--- linux-2.6.24.orig/drivers/pnp/pnpacpi/rsparser.c +++ linux-2.6.24/drivers/pnp/pnpacpi/rsparser.c @@ -85,7 +85,7 @@ i < PNP_MAX_IRQ) i++; if (i >= PNP_MAX_IRQ && !warned) { - printk(KERN_ERR "pnpacpi: exceeded the max number of IRQ " + printk(KERN_WARNING "pnpacpi: exceeded the max number of IRQ " "resources: %d \n", PNP_MAX_IRQ); warned = 1; return; @@ -187,7 +187,7 @@ res->dma_resource[i].start = dma; res->dma_resource[i].end = dma; } else if (!warned) { - printk(KERN_ERR "pnpacpi: exceeded the max number of DMA " + printk(KERN_WARNING "pnpacpi: exceeded the max number of DMA " "resources: %d \n", PNP_MAX_DMA); warned = 1; } @@ -213,7 +213,7 @@ res->port_resource[i].start = io; res->port_resource[i].end = io + len - 1; } else if (!warned) { - printk(KERN_ERR "pnpacpi: exceeded the max number of IO " + printk(KERN_WARNING "pnpacpi: exceeded the max number of IO " "resources: %d \n", PNP_MAX_PORT); warned = 1; } @@ -241,7 +241,7 @@ res->mem_resource[i].start = mem; res->mem_resource[i].end = mem + len - 1; } else if (!warned) { - printk(KERN_ERR "pnpacpi: exceeded the max number of mem " + printk(KERN_WARNING "pnpacpi: exceeded the max number of mem " "resources: %d\n", PNP_MAX_MEM); warned = 1; } @@ -752,6 +752,12 @@ if (pnpacpi_supported_resource(res)) { (*resource)->type = res->type; (*resource)->length = sizeof(struct acpi_resource); + if (res->type == ACPI_RESOURCE_TYPE_IRQ) + (*resource)->data.irq.descriptor_length = + res->data.irq.descriptor_length; + if (res->type == ACPI_RESOURCE_TYPE_START_DEPENDENT) + (*resource)->data.start_dpf.descriptor_length = + res->data.start_dpf.descriptor_length; (*resource)++; } --- linux-2.6.24.orig/drivers/s390/char/defkeymap.c +++ linux-2.6.24/drivers/s390/char/defkeymap.c @@ -151,8 +151,8 @@ }; struct kbdiacruc accent_table[MAX_DIACR] = { - {'^', 'c', '\003'}, {'^', 'd', '\004'}, - {'^', 'z', '\032'}, {'^', '\012', '\000'}, + {'^', 'c', 0003}, {'^', 'd', 0004}, + {'^', 'z', 0032}, {'^', 0012, 0000}, }; unsigned int accent_table_size = 4; --- linux-2.6.24.orig/drivers/ide/ide-cd.h +++ linux-2.6.24/drivers/ide/ide-cd.h @@ -15,7 +15,7 @@ memory, though. */ #ifndef VERBOSE_IDE_CD_ERRORS -#define VERBOSE_IDE_CD_ERRORS 1 +#define VERBOSE_IDE_CD_ERRORS 0 #endif --- linux-2.6.24.orig/drivers/ide/ide-cd.c +++ linux-2.6.24/drivers/ide/ide-cd.c @@ -2988,7 +2988,8 @@ if (strcmp(drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 || strcmp(drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 || strcmp(drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 || - strcmp(drive->id->model, "MATSHITADVD-ROM SR-8174") == 0) + strcmp(drive->id->model, "MATSHITADVD-ROM SR-8174") == 0 || + strcmp(drive->id->model, "Optiarc DVD RW AD-5200A") == 0) CDROM_CONFIG_FLAGS(drive)->audio_play = 1; #if ! STANDARD_ATAPI --- linux-2.6.24.orig/drivers/ide/ppc/pmac.c +++ linux-2.6.24/drivers/ide/ppc/pmac.c @@ -1269,7 +1269,7 @@ int rc = 0; if (mesg.event != mdev->ofdev.dev.power.power_state.event - && mesg.event == PM_EVENT_SUSPEND) { + && (mesg.event & PM_EVENT_SLEEP)) { rc = pmac_ide_do_suspend(hwif); if (rc == 0) mdev->ofdev.dev.power.power_state = mesg; @@ -1374,7 +1374,7 @@ int rc = 0; if (mesg.event != pdev->dev.power.power_state.event - && mesg.event == PM_EVENT_SUSPEND) { + && (mesg.event & PM_EVENT_SLEEP)) { rc = pmac_ide_do_suspend(hwif); if (rc == 0) pdev->dev.power.power_state = mesg; --- linux-2.6.24.orig/drivers/serial/8250.c +++ linux-2.6.24/drivers/serial/8250.c @@ -1822,6 +1822,8 @@ * allow register changes to become visible. */ spin_lock_irqsave(&up->port.lock, flags); + if (up->port.flags & UPF_SHARE_IRQ) + disable_irq_nosync(up->port.irq); wait_for_xmitr(up, UART_LSR_THRE); serial_out_sync(up, UART_IER, UART_IER_THRI); @@ -1833,6 +1835,8 @@ iir = serial_in(up, UART_IIR); serial_out(up, UART_IER, 0); + if (up->port.flags & UPF_SHARE_IRQ) + enable_irq(up->port.irq); spin_unlock_irqrestore(&up->port.lock, flags); /* --- linux-2.6.24.orig/drivers/firmware/dell_rbu.c +++ linux-2.6.24/drivers/firmware/dell_rbu.c @@ -598,7 +598,7 @@ { int size = 0; if (!pos) - size = sprintf(buffer, "%s\n", image_type); + size = scnprintf(buffer, count, "%s\n", image_type); return size; } @@ -670,7 +670,7 @@ int size = 0; if (!pos) { spin_lock(&rbu_data.lock); - size = sprintf(buffer, "%lu\n", rbu_data.packetsize); + size = scnprintf(buffer, count, "%lu\n", rbu_data.packetsize); spin_unlock(&rbu_data.lock); } return size; --- linux-2.6.24.orig/drivers/firmware/dmi_scan.c +++ linux-2.6.24/drivers/firmware/dmi_scan.c @@ -219,7 +219,7 @@ dev->name = "IPMI controller"; dev->device_data = data; - list_add(&dev->list, &dmi_devices); + list_add_tail(&dev->list, &dmi_devices); } /* @@ -389,6 +389,17 @@ } EXPORT_SYMBOL(dmi_get_system_info); +/** + * dmi_name_in_serial - Check if string is in the DMI product serial + * information. + */ +int dmi_name_in_serial(const char *str) +{ + int f = DMI_PRODUCT_SERIAL; + if (dmi_ident[f] && strstr(dmi_ident[f], str)) + return 1; + return 0; +} /** * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. --- linux-2.6.24.orig/drivers/firmware/dcdbas.c +++ linux-2.6.24/drivers/firmware/dcdbas.c @@ -658,4 +658,5 @@ MODULE_VERSION(DRIVER_VERSION); MODULE_AUTHOR("Dell Inc."); MODULE_LICENSE("GPL"); - +/* Any System or BIOS claiming to be by Dell */ +MODULE_ALIAS("dmi:*:[bs]vnD[Ee][Ll][Ll]*:*"); --- linux-2.6.24.orig/drivers/firmware/Kconfig +++ linux-2.6.24/drivers/firmware/Kconfig @@ -17,6 +17,15 @@ obscure configurations. Most disk controller BIOS vendors do not yet implement this feature. +config EDD_OFF + bool "Sets default behavior for EDD detection to off" + depends on EDD + default n + help + Say Y if you want EDD disabled by default, even though it is compiled into the + kernel. Say N if you want EDD enabled by default. EDD can be dynamically set + using the kernel parameter 'edd={on|off}'. + config EFI_VARS tristate "EFI Variable Support via sysfs" depends on EFI --- linux-2.6.24.orig/drivers/block/ub.c +++ linux-2.6.24/drivers/block/ub.c @@ -657,7 +657,6 @@ if ((cmd = ub_get_cmd(lun)) == NULL) return -1; memset(cmd, 0, sizeof(struct ub_scsi_cmd)); - sg_init_table(cmd->sgv, UB_MAX_REQ_SG); blkdev_dequeue_request(rq); @@ -668,6 +667,7 @@ /* * get scatterlist from block layer */ + sg_init_table(&urq->sgv[0], UB_MAX_REQ_SG); n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]); if (n_elem < 0) { /* Impossible, because blk_rq_map_sg should not hit ENOMEM. */ --- linux-2.6.24.orig/drivers/block/Kconfig +++ linux-2.6.24/drivers/block/Kconfig @@ -429,6 +429,7 @@ tristate "Virtio block driver (EXPERIMENTAL)" depends on EXPERIMENTAL && VIRTIO ---help--- - This is the virtual block driver for lguest. Say Y or M. + This is the virtual block driver for virtio. It can be used with + lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. endif # BLK_DEV --- linux-2.6.24.orig/drivers/block/virtio_blk.c +++ linux-2.6.24/drivers/block/virtio_blk.c @@ -7,8 +7,10 @@ #include #define VIRTIO_MAX_SG (3+MAX_PHYS_SEGMENTS) +#define PART_BITS 4 + +static int major, index; -static unsigned char virtblk_index = 'a'; struct virtio_blk { spinlock_t lock; @@ -36,7 +38,7 @@ struct virtio_blk_inhdr in_hdr; }; -static bool blk_done(struct virtqueue *vq) +static void blk_done(struct virtqueue *vq) { struct virtio_blk *vblk = vq->vdev->priv; struct virtblk_req *vbr; @@ -65,7 +67,6 @@ /* In case queue is stopped waiting for more buffers. */ blk_start_queue(vblk->disk->queue); spin_unlock_irqrestore(&vblk->lock, flags); - return true; } static bool do_req(struct request_queue *q, struct virtio_blk *vblk, @@ -153,20 +154,37 @@ (void __user *)data); } +/* We provide getgeo only to please some old bootloader/partitioning tools */ +static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) +{ + /* some standard values, similar to sd */ + geo->heads = 1 << 6; + geo->sectors = 1 << 5; + geo->cylinders = get_capacity(bd->bd_disk) >> 11; + return 0; +} + static struct block_device_operations virtblk_fops = { - .ioctl = virtblk_ioctl, - .owner = THIS_MODULE, + .ioctl = virtblk_ioctl, + .owner = THIS_MODULE, + .getgeo = virtblk_getgeo, }; +static int index_to_minor(int index) +{ + return index << PART_BITS; +} + static int virtblk_probe(struct virtio_device *vdev) { struct virtio_blk *vblk; - int err, major; - void *token; - unsigned int len; + int err; u64 cap; u32 v; + if (index_to_minor(index) >= 1 << MINORBITS) + return -ENOSPC; + vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL); if (!vblk) { err = -ENOMEM; @@ -178,7 +196,7 @@ vblk->vdev = vdev; /* We expect one virtqueue, for output. */ - vblk->vq = vdev->config->find_vq(vdev, blk_done); + vblk->vq = vdev->config->find_vq(vdev, 0, blk_done); if (IS_ERR(vblk->vq)) { err = PTR_ERR(vblk->vq); goto out_free_vblk; @@ -190,17 +208,11 @@ goto out_free_vq; } - major = register_blkdev(0, "virtblk"); - if (major < 0) { - err = major; - goto out_mempool; - } - /* FIXME: How many partitions? How long is a piece of string? */ - vblk->disk = alloc_disk(1 << 4); + vblk->disk = alloc_disk(1 << PART_BITS); if (!vblk->disk) { err = -ENOMEM; - goto out_unregister_blkdev; + goto out_mempool; } vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock); @@ -209,22 +221,33 @@ goto out_put_disk; } - sprintf(vblk->disk->disk_name, "vd%c", virtblk_index++); + if (index < 26) { + sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26); + } else if (index < (26 + 1) * 26) { + sprintf(vblk->disk->disk_name, "vd%c%c", + 'a' + index / 26 - 1, 'a' + index % 26); + } else { + const unsigned int m1 = (index / 26 - 1) / 26 - 1; + const unsigned int m2 = (index / 26 - 1) % 26; + const unsigned int m3 = index % 26; + sprintf(vblk->disk->disk_name, "vd%c%c%c", + 'a' + m1, 'a' + m2, 'a' + m3); + } + vblk->disk->major = major; - vblk->disk->first_minor = 0; + vblk->disk->first_minor = index_to_minor(index); vblk->disk->private_data = vblk; vblk->disk->fops = &virtblk_fops; + vblk->disk->driverfs_dev = &vdev->dev; + index++; /* If barriers are supported, tell block layer that queue is ordered */ - token = vdev->config->find(vdev, VIRTIO_CONFIG_BLK_F, &len); - if (virtio_use_bit(vdev, token, len, VIRTIO_BLK_F_BARRIER)) + if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER)) blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL); - err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_CAPACITY, &cap); - if (err) { - dev_err(&vdev->dev, "Bad/missing capacity in config\n"); - goto out_cleanup_queue; - } + /* Host must always specify the capacity. */ + __virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity), + &cap); /* If capacity is too big, truncate with warning. */ if ((sector_t)cap != cap) { @@ -234,31 +257,25 @@ } set_capacity(vblk->disk, cap); - err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SIZE_MAX, &v); + /* Host can optionally specify maximum segment size and number of + * segments. */ + err = virtio_config_val(vdev, VIRTIO_BLK_F_SIZE_MAX, + offsetof(struct virtio_blk_config, size_max), + &v); if (!err) blk_queue_max_segment_size(vblk->disk->queue, v); - else if (err != -ENOENT) { - dev_err(&vdev->dev, "Bad SIZE_MAX in config\n"); - goto out_cleanup_queue; - } - err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SEG_MAX, &v); + err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX, + offsetof(struct virtio_blk_config, seg_max), + &v); if (!err) blk_queue_max_hw_segments(vblk->disk->queue, v); - else if (err != -ENOENT) { - dev_err(&vdev->dev, "Bad SEG_MAX in config\n"); - goto out_cleanup_queue; - } add_disk(vblk->disk); return 0; -out_cleanup_queue: - blk_cleanup_queue(vblk->disk->queue); out_put_disk: put_disk(vblk->disk); -out_unregister_blkdev: - unregister_blkdev(major, "virtblk"); out_mempool: mempool_destroy(vblk->pool); out_free_vq: @@ -274,12 +291,16 @@ struct virtio_blk *vblk = vdev->priv; int major = vblk->disk->major; + /* Nothing should be pending. */ BUG_ON(!list_empty(&vblk->reqs)); + + /* Stop all the virtqueues. */ + vdev->config->reset(vdev); + blk_cleanup_queue(vblk->disk->queue); put_disk(vblk->disk); unregister_blkdev(major, "virtblk"); mempool_destroy(vblk->pool); - /* There should be nothing in the queue now, so no need to shutdown */ vdev->config->del_vq(vblk->vq); kfree(vblk); } @@ -299,11 +320,15 @@ static int __init init(void) { + major = register_blkdev(0, "virtblk"); + if (major < 0) + return major; return register_virtio_driver(&virtio_blk); } static void __exit fini(void) { + unregister_blkdev(major, "virtblk"); unregister_virtio_driver(&virtio_blk); } module_init(init); --- linux-2.6.24.orig/drivers/isdn/capi/capidrv.c +++ linux-2.6.24/drivers/isdn/capi/capidrv.c @@ -2332,13 +2332,14 @@ static void __exit capidrv_exit(void) { - char rev[10]; + char rev[32]; char *p; if ((p = strchr(revision, ':')) != 0) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); - *p = 0; + strncpy(rev, p + 1, sizeof(rev)); + rev[sizeof(rev)-1] = 0; + if ((p = strchr(rev, '$')) != 0) + *p = 0; } else { strcpy(rev, " ??? "); } --- linux-2.6.24.orig/drivers/isdn/hisax/hfc_usb.c +++ linux-2.6.24/drivers/isdn/hisax/hfc_usb.c @@ -818,8 +818,8 @@ } /* we have a complete hdlc packet */ if (finish) { - if ((!fifo->skbuff->data[fifo->skbuff->len - 1]) - && (fifo->skbuff->len > 3)) { + if (fifo->skbuff->len > 3 && + !fifo->skbuff->data[fifo->skbuff->len - 1]) { if (fifon == HFCUSB_D_RX) { DBG(HFCUSB_DBG_DCHANNEL, --- linux-2.6.24.orig/drivers/isdn/i4l/isdn_net.c +++ linux-2.6.24/drivers/isdn/i4l/isdn_net.c @@ -2010,6 +2010,7 @@ ndev->flags = IFF_NOARP|IFF_POINTOPOINT; ndev->type = ARPHRD_ETHER; ndev->addr_len = ETH_ALEN; + ndev->validate_addr = NULL; /* for clients with MPPP maybe higher values better */ ndev->tx_queue_len = 30; --- linux-2.6.24.orig/drivers/ata/sata_nv.c +++ linux-2.6.24/drivers/ata/sata_nv.c @@ -1011,14 +1011,20 @@ } if (status & (NV_ADMA_STAT_DONE | - NV_ADMA_STAT_CPBERR)) { - u32 check_commands; + NV_ADMA_STAT_CPBERR | + NV_ADMA_STAT_CMD_COMPLETE)) { + u32 check_commands = notifier_clears[i]; int pos, error = 0; - if (ata_tag_valid(ap->link.active_tag)) - check_commands = 1 << ap->link.active_tag; - else - check_commands = ap->link.sactive; + if (status & NV_ADMA_STAT_CPBERR) { + /* Check all active commands */ + if (ata_tag_valid(ap->link.active_tag)) + check_commands = 1 << + ap->link.active_tag; + else + check_commands = ap-> + link.sactive; + } /** Check CPBs for completed commands */ while ((pos = ffs(check_commands)) && !error) { --- linux-2.6.24.orig/drivers/ata/pata_hpt37x.c +++ linux-2.6.24/drivers/ata/pata_hpt37x.c @@ -24,7 +24,7 @@ #include #define DRV_NAME "pata_hpt37x" -#define DRV_VERSION "0.6.9" +#define DRV_VERSION "0.6.11" struct hpt_clock { u8 xfer_speed; @@ -281,7 +281,7 @@ if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33)) mask &= ~ATA_MASK_UDMA; if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5)) - mask &= ~(0x1F << ATA_SHIFT_UDMA); + mask &= ~(0xE0 << ATA_SHIFT_UDMA); } return ata_pci_default_filter(adev, mask); } @@ -297,7 +297,7 @@ { if (adev->class == ATA_DEV_ATA) { if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5)) - mask &= ~ (0x1F << ATA_SHIFT_UDMA); + mask &= ~(0xE0 << ATA_SHIFT_UDMA); } return ata_pci_default_filter(adev, mask); } --- linux-2.6.24.orig/drivers/ata/ahci.c +++ linux-2.6.24/drivers/ata/ahci.c @@ -85,6 +85,7 @@ board_ahci_ign_iferr = 2, board_ahci_sb600 = 3, board_ahci_mv = 4, + board_ahci_sb700 = 5, /* global controller registers */ HOST_CAP = 0x00, /* host capabilities */ @@ -442,6 +443,16 @@ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + /* board_ahci_sb700 */ + { + AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | + AHCI_HFLAG_NO_PMP), + .flags = AHCI_FLAG_COMMON, + .link_flags = AHCI_LFLAG_COMMON, + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, }; static const struct pci_device_id ahci_pci_tbl[] = { @@ -482,12 +493,12 @@ /* ATI */ { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ - { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700/800 */ - { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700/800 */ - { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700/800 */ - { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700/800 */ - { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb600 }, /* ATI SB700/800 */ - { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb600 }, /* ATI SB700/800 */ + { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */ + { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */ + { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */ + { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */ + { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */ + { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */ /* VIA */ { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ @@ -579,6 +590,11 @@ }; +static inline int ahci_zero_nr_ports(u32 cap) +{ + return cap & ~0x1f; +} + static inline int ahci_nr_ports(u32 cap) { return (cap & 0x1f) + 1; @@ -644,6 +660,15 @@ cap &= ~HOST_CAP_PMP; } + if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 && + port_map != 1) { + dev_printk(KERN_INFO, &pdev->dev, + "JMB361 has only one port, port_map 0x%x -> 0x%x\n", + port_map, 1); + port_map = 1; + cap = ahci_zero_nr_ports(cap); + } + /* * Temporary Marvell 6145 hack: PATA port presence * is asserted through the standard AHCI port @@ -1922,7 +1947,7 @@ void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; u32 ctl; - if (mesg.event == PM_EVENT_SUSPEND) { + if (mesg.event & PM_EVENT_SLEEP) { /* AHCI spec rev1.1 section 8.3.3: * Software must disable interrupts prior to requesting a * transition of the HBA to D3 state. --- linux-2.6.24.orig/drivers/ata/libata-core.c +++ linux-2.6.24/drivers/ata/libata-core.c @@ -103,9 +103,9 @@ module_param_named(fua, libata_fua, int, 0444); MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); -static int ata_ignore_hpa; +static int ata_ignore_hpa = 1; module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644); -MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)"); +MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk, default)"); static int libata_dma_mask = ATA_DMA_MASK_ATA|ATA_DMA_MASK_ATAPI|ATA_DMA_MASK_CFA; module_param_named(dma, libata_dma_mask, int, 0444); @@ -947,8 +947,8 @@ if (r_err) *r_err = err; - /* see if device passed diags: if master then continue and warn later */ - if (err == 0 && dev->devno == 0) + /* see if device passed diags: continue and warn later */ + if (err == 0) /* diagnostic fail : do nothing _YET_ */ dev->horkage |= ATA_HORKAGE_DIAGNOSTIC; else if (err == 1) @@ -1936,24 +1936,34 @@ id, sizeof(id[0]) * ATA_ID_WORDS, 0); if (err_mask) { if (err_mask & AC_ERR_NODEV_HINT) { - DPRINTK("ata%u.%d: NODEV after polling detection\n", - ap->print_id, dev->devno); + ata_dev_printk(dev, KERN_DEBUG, + "NODEV after polling detection\n"); return -ENOENT; } - /* Device or controller might have reported the wrong - * device class. Give a shot at the other IDENTIFY if - * the current one is aborted by the device. - */ - if (may_fallback && - (err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { - may_fallback = 0; + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; - if (class == ATA_DEV_ATA) - class = ATA_DEV_ATAPI; - else - class = ATA_DEV_ATA; - goto retry; + if (class == ATA_DEV_ATA) + class = ATA_DEV_ATAPI; + else + class = ATA_DEV_ATA; + goto retry; + } + + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + ata_dev_printk(dev, KERN_DEBUG, + "both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; } rc = -EIO; @@ -2295,19 +2305,8 @@ dev->flags |= ATA_DFLAG_DIPM; } - if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { - /* Let the user know. We don't want to disallow opens for - rescue purposes, or in case the vendor is just a blithering - idiot */ - if (print_info) { - ata_dev_printk(dev, KERN_WARNING, -"Drive reports diagnostics failure. This may indicate a drive\n"); - ata_dev_printk(dev, KERN_WARNING, -"fault or invalid emulation. Contact drive vendor for information.\n"); - } - } - - /* limit bridge transfers to udma5, 200 sectors */ + /* Limit PATA drive on SATA cable bridge transfers to udma5, + 200 sectors */ if (ata_dev_knobble(dev)) { if (ata_msg_drv(ap) && print_info) ata_dev_printk(dev, KERN_INFO, @@ -2336,6 +2335,21 @@ if (ap->ops->dev_config) ap->ops->dev_config(dev); + if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { + /* Let the user know. We don't want to disallow opens for + rescue purposes, or in case the vendor is just a blithering + idiot. Do this after the dev_config call as some controllers + with buggy firmware may want to avoid reporting false device + bugs */ + + if (print_info) { + ata_dev_printk(dev, KERN_WARNING, +"Drive reports diagnostics failure. This may indicate a drive\n"); + ata_dev_printk(dev, KERN_WARNING, +"fault or invalid emulation. Contact drive vendor for information.\n"); + } + } + if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n", __FUNCTION__, ata_chk_status(ap)); @@ -3039,7 +3053,7 @@ /* Early MWDMA devices do DMA but don't allow DMA mode setting. Don't fail an MWDMA0 set IFF the device indicates it is in MWDMA0 */ - if (dev->xfer_shift == ATA_SHIFT_MWDMA && + if (dev->xfer_shift == ATA_SHIFT_MWDMA && dev->dma_mode == XFER_MW_DMA_0 && (dev->id[63] >> 8) & 1) err_mask &= ~AC_ERR_DEV; @@ -4144,6 +4158,9 @@ /* NCQ is slow */ { "WDC WD740ADFD-00", NULL, ATA_HORKAGE_NONCQ }, { "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, }, + /* See also: http://lkml.org/lkml/2007/10/17/380 */ + { "WDC WD1500ADFD-0*", NULL, ATA_HORKAGE_NONCQ }, + { "WDC WD5000AAKS-0*", NULL, ATA_HORKAGE_NONCQ }, /* http://thread.gmane.org/gmane.linux.ide/14907 */ { "FUJITSU MHT2060BH", NULL, ATA_HORKAGE_NONCQ }, /* NCQ is broken */ @@ -4159,6 +4176,25 @@ { "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ, }, { "HTS541080G9SA00", "MB4OC60D", ATA_HORKAGE_NONCQ, }, { "HTS541010G9SA00", "MBZOC60D", ATA_HORKAGE_NONCQ, }, + /* Drives which do spurious command completion */ + { "HTS541680J9SA00", "SB2IC7EP", ATA_HORKAGE_NONCQ, }, + { "HTS541612J9SA00", "SBDIC7JP", ATA_HORKAGE_NONCQ, }, + { "HDT722516DLA380", "V43OA96A", ATA_HORKAGE_NONCQ, }, + { "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, }, + { "Hitachi HTS542525K9SA00", "BBFOC31P", ATA_HORKAGE_NONCQ, }, + { "HTS722012K9A300", "DCCOC54P", ATA_HORKAGE_NONCQ, }, + { "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, }, + { "WDC WD3200AAJS-00RYA0", "12.01B01", ATA_HORKAGE_NONCQ, }, + { "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, }, + { "ST9120822AS", "3.CLF", ATA_HORKAGE_NONCQ, }, + { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, }, + { "ST9160821AS", "3.ALD", ATA_HORKAGE_NONCQ, }, + { "ST9160821AS", "3.CCD", ATA_HORKAGE_NONCQ, }, + { "ST3160812AS", "3.ADJ", ATA_HORKAGE_NONCQ, }, + { "ST980813AS", "3.ADB", ATA_HORKAGE_NONCQ, }, + { "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, }, + { "Maxtor 7V300F0", "VA111900", ATA_HORKAGE_NONCQ, }, + { "FUJITSU MHW2160BH PL", "0084001E", ATA_HORKAGE_NONCQ, }, /* devices which puke on READ_NATIVE_MAX */ { "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA, }, @@ -7388,7 +7424,7 @@ pci_save_state(pdev); pci_disable_device(pdev); - if (mesg.event == PM_EVENT_SUSPEND) + if (mesg.event & PM_EVENT_SLEEP) pci_set_power_state(pdev, PCI_D3hot); } --- linux-2.6.24.orig/drivers/ata/pata_it821x.c +++ linux-2.6.24/drivers/ata/pata_it821x.c @@ -430,7 +430,7 @@ return ata_qc_issue_prot(qc); } printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command); - return AC_ERR_INVALID; + return AC_ERR_DEV; } /** @@ -516,6 +516,37 @@ printk("(%dK stripe)", adev->id[146]); printk(".\n"); } + /* This is a controller firmware triggered funny, don't + report the drive faulty! */ + adev->horkage &= ~ATA_HORKAGE_DIAGNOSTIC; +} + +/** + * it821x_ident_hack - Hack identify data up + * @ap: Port + * + * Walk the devices on this firmware driven port and slightly + * mash the identify data to stop us and common tools trying to + * use features not firmware supported. The firmware itself does + * some masking (eg SMART) but not enough. + * + * This is a bit of an abuse of the cable method, but it is the + * only method called at the right time. We could modify the libata + * core specifically for ident hacking but while we have one offender + * it seems better to keep the fallout localised. + */ + +static int it821x_ident_hack(struct ata_port *ap) +{ + struct ata_device *adev; + ata_link_for_each_dev(adev, &ap->link) { + if (ata_dev_enabled(adev)) { + adev->id[84] &= ~(1 << 6); /* No FUA */ + adev->id[85] &= ~(1 << 10); /* No HPA */ + adev->id[76] = 0; /* No NCQ/AN etc */ + } + } + return ata_cable_unknown(ap); } @@ -634,7 +665,7 @@ .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, + .cable_detect = it821x_ident_hack, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, --- linux-2.6.24.orig/drivers/ata/ata_piix.c +++ linux-2.6.24/drivers/ata/ata_piix.c @@ -700,6 +700,8 @@ { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */ + { 0x24CA, 0x1025, 0x003d }, /* ICH4 on Acer TM290 */ + { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ /* end marker */ { 0, } }; @@ -1129,7 +1131,7 @@ * cycles and power trying to do something to the sleeping * beauty. */ - if (piix_broken_suspend() && mesg.event == PM_EVENT_SUSPEND) { + if (piix_broken_suspend() && (mesg.event & PM_EVENT_SLEEP)) { pci_save_state(pdev); /* mark its power state as "unknown", since we don't --- linux-2.6.24.orig/drivers/ata/pata_sis.c +++ linux-2.6.24/drivers/ata/pata_sis.c @@ -1006,6 +1006,7 @@ { PCI_VDEVICE(SI, 0x5513), }, /* SiS 5513 */ { PCI_VDEVICE(SI, 0x5518), }, /* SiS 5518 */ { PCI_VDEVICE(SI, 0x1180), }, /* SiS 1180 */ + { PCI_VDEVICE(SI, 0x1180), }, /* SiS 1180 */ { } }; --- linux-2.6.24.orig/drivers/ata/pata_hpt366.c +++ linux-2.6.24/drivers/ata/pata_hpt366.c @@ -27,7 +27,7 @@ #include #define DRV_NAME "pata_hpt366" -#define DRV_VERSION "0.6.1" +#define DRV_VERSION "0.6.2" struct hpt_clock { u8 xfer_speed; @@ -180,9 +180,9 @@ if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33)) mask &= ~ATA_MASK_UDMA; if (hpt_dma_blacklisted(adev, "UDMA3", bad_ata66_3)) - mask &= ~(0x07 << ATA_SHIFT_UDMA); + mask &= ~(0xF8 << ATA_SHIFT_UDMA); if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4)) - mask &= ~(0x0F << ATA_SHIFT_UDMA); + mask &= ~(0xF0 << ATA_SHIFT_UDMA); } return ata_pci_default_filter(adev, mask); } --- linux-2.6.24.orig/drivers/ata/libata-acpi.c +++ linux-2.6.24/drivers/ata/libata-acpi.c @@ -760,7 +760,8 @@ */ ata_link_for_each_dev(dev, &ap->link) { ata_acpi_clear_gtf(dev); - if (ata_dev_get_GTF(dev, NULL) >= 0) + if (ata_dev_enabled(dev) && + ata_dev_get_GTF(dev, NULL) >= 0) dev->flags |= ATA_DFLAG_ACPI_PENDING; } } else { @@ -770,7 +771,8 @@ */ ata_link_for_each_dev(dev, &ap->link) { ata_acpi_clear_gtf(dev); - dev->flags |= ATA_DFLAG_ACPI_PENDING; + if (ata_dev_enabled(dev)) + dev->flags |= ATA_DFLAG_ACPI_PENDING; } } } --- linux-2.6.24.orig/drivers/ata/pata_serverworks.c +++ linux-2.6.24/drivers/ata/pata_serverworks.c @@ -226,7 +226,7 @@ for (i = 0; (p = csb_bad_ata100[i]) != NULL; i++) { if (!strcmp(p, model_num)) - mask &= ~(0x1F << ATA_SHIFT_UDMA); + mask &= ~(0xE0 << ATA_SHIFT_UDMA); } return ata_pci_default_filter(adev, mask); } --- linux-2.6.24.orig/drivers/message/fusion/mptsas.c +++ linux-2.6.24/drivers/message/fusion/mptsas.c @@ -1699,6 +1699,11 @@ if (error) goto out_free_consistent; + if (!buffer->NumPhys) { + error = -ENODEV; + goto out_free_consistent; + } + /* save config data */ port_info->num_phys = buffer->NumPhys; port_info->phy_info = kcalloc(port_info->num_phys, --- linux-2.6.24.orig/drivers/message/fusion/mptbase.c +++ linux-2.6.24/drivers/message/fusion/mptbase.c @@ -2844,6 +2844,16 @@ pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus); pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo); pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices); + /* + * VMware emulation is broken, its PortFact's MaxDevices reports value + * programmed by IOC Init, so if you program IOC Init to 256 (which is 0, + * as that field is only 8 bit), it reports back 0 in port facts, instead + * of 256... And unfortunately using 256 triggers another bug in the + * code (parallel SCSI can have only 16 devices). + */ + if (pfacts->MaxDevices == 0) { + pfacts->MaxDevices = 16; + } pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID); pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags); pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers); --- linux-2.6.24.orig/drivers/spi/atmel_spi.c +++ linux-2.6.24/drivers/spi/atmel_spi.c @@ -85,6 +85,16 @@ unsigned gpio = (unsigned) spi->controller_data; unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; + int i; + u32 csr; + u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; + + /* Make sure clock polarity is correct */ + for (i = 0; i < spi->master->num_chipselect; i++) { + csr = spi_readl(as, CSR0 + 4 * i); + if ((csr ^ cpol) & SPI_BIT(CPOL)) + spi_writel(as, CSR0 + 4 * i, csr ^ SPI_BIT(CPOL)); + } mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); --- linux-2.6.24.orig/drivers/spi/pxa2xx_spi.c +++ linux-2.6.24/drivers/spi/pxa2xx_spi.c @@ -48,13 +48,19 @@ #define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK) #define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0) -/* for testing SSCR1 changes that require SSP restart, basically - * everything except the service and interrupt enables */ -#define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_EBCEI | SSCR1_SCFR \ +/* + * for testing SSCR1 changes that require SSP restart, basically + * everything except the service and interrupt enables, the pxa270 developer + * manual says only SSCR1_SCFR, SSCR1_SPH, SSCR1_SPO need to be in this + * list, but the PXA255 dev man says all bits without really meaning the + * service and interrupt enables + */ +#define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \ | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \ - | SSCR1_RWOT | SSCR1_TRAIL | SSCR1_PINTE \ - | SSCR1_STRF | SSCR1_EFWR |SSCR1_RFT \ - | SSCR1_TFT | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) + | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \ + | SSCR1_IFS | SSCR1_STRF | SSCR1_EFWR \ + | SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \ + | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) #define DEFINE_SSP_REG(reg, off) \ static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \ @@ -961,9 +967,6 @@ if (drv_data->ssp_type == PXA25x_SSP) DCMD(drv_data->tx_channel) |= DCMD_ENDIRQEN; - /* Fix me, need to handle cs polarity */ - drv_data->cs_control(PXA2XX_CS_ASSERT); - /* Clear status and start DMA engine */ cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1; write_SSSR(drv_data->clear_sr, reg); @@ -973,9 +976,6 @@ /* Ensure we have the correct interrupt handler */ drv_data->transfer_handler = interrupt_transfer; - /* Fix me, need to handle cs polarity */ - drv_data->cs_control(PXA2XX_CS_ASSERT); - /* Clear status */ cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1; write_SSSR(drv_data->clear_sr, reg); @@ -986,16 +986,29 @@ || (read_SSCR1(reg) & SSCR1_CHANGE_MASK) != (cr1 & SSCR1_CHANGE_MASK)) { + /* stop the SSP, and update the other bits */ write_SSCR0(cr0 & ~SSCR0_SSE, reg); if (drv_data->ssp_type != PXA25x_SSP) write_SSTO(chip->timeout, reg); - write_SSCR1(cr1, reg); + /* first set CR1 without interrupt and service enables */ + write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg); + /* restart the SSP */ write_SSCR0(cr0, reg); + } else { if (drv_data->ssp_type != PXA25x_SSP) write_SSTO(chip->timeout, reg); - write_SSCR1(cr1, reg); } + + /* FIXME, need to handle cs polarity, + * this driver uses struct pxa2xx_spi_chip.cs_control to + * specify a CS handling function, and it ignores most + * struct spi_device.mode[s], including SPI_CS_HIGH */ + drv_data->cs_control(PXA2XX_CS_ASSERT); + + /* after chip select, release the data by enabling service + * requests and interrupts, without changing any mode bits */ + write_SSCR1(cr1, reg); } static void pump_messages(struct work_struct *work) --- linux-2.6.24.orig/drivers/media/video/vivi.c +++ linux-2.6.24/drivers/media/video/vivi.c @@ -170,7 +170,7 @@ int users; /* various device info */ - struct video_device vfd; + struct video_device *vfd; struct vivi_dmaqueue vidq; @@ -986,7 +986,7 @@ printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor); list_for_each_entry(dev, &vivi_devlist, vivi_devlist) - if (dev->vfd.minor == minor) + if (dev->vfd->minor == minor) goto found; return -ENODEV; found: @@ -1067,7 +1067,7 @@ return videobuf_poll_stream(file, q, wait); } -static int vivi_release(struct inode *inode, struct file *file) +static int vivi_close(struct inode *inode, struct file *file) { struct vivi_fh *fh = file->private_data; struct vivi_dev *dev = fh->dev; @@ -1088,6 +1088,18 @@ return 0; } +static int vivi_release(struct vivi_dev *dev) +{ + if (-1 != dev->vfd->minor) + video_unregister_device(dev->vfd); + else + video_device_release(dev->vfd); + + dev->vfd = NULL; + + return 0; +} + static int vivi_mmap(struct file *file, struct vm_area_struct * vma) { @@ -1109,7 +1121,7 @@ static const struct file_operations vivi_fops = { .owner = THIS_MODULE, .open = vivi_open, - .release = vivi_release, + .release = vivi_close, .read = vivi_read, .poll = vivi_poll, .ioctl = video_ioctl2, /* V4L2 ioctl handler */ @@ -1117,12 +1129,12 @@ .llseek = no_llseek, }; -static struct video_device vivi = { +static struct video_device vivi_template = { .name = "vivi", .type = VID_TYPE_CAPTURE, .fops = &vivi_fops, .minor = -1, -// .release = video_device_release, + .release = video_device_release, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, @@ -1156,6 +1168,7 @@ { int ret; struct vivi_dev *dev; + struct video_device *vfd; dev = kzalloc(sizeof(*dev),GFP_KERNEL); if (NULL == dev) @@ -1174,7 +1187,18 @@ dev->vidq.timeout.data = (unsigned long)dev; init_timer(&dev->vidq.timeout); - ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr); + vfd = video_device_alloc(); + if (NULL == vfd) + return -ENOMEM; + + *vfd = vivi_template; + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); + snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", + vivi_template.name, vfd->minor); + + dev->vfd = vfd; + printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret); return ret; } @@ -1188,9 +1212,9 @@ list = vivi_devlist.next; list_del(list); h = list_entry(list, struct vivi_dev, vivi_devlist); + vivi_release(h); kfree (h); } - video_unregister_device(&vivi); } module_init(vivi_init); --- linux-2.6.24.orig/drivers/media/video/tvaudio.c +++ linux-2.6.24/drivers/media/video/tvaudio.c @@ -156,7 +156,7 @@ { unsigned char buffer[2]; - if (-1 == subaddr) { + if (subaddr < 0) { v4l_dbg(1, debug, &chip->c, "%s: chip_write: 0x%x\n", chip->c.name, val); chip->shadow.bytes[1] = val; @@ -167,6 +167,13 @@ return -1; } } else { + if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) { + v4l_info(&chip->c, + "Tried to access a non-existent register: %d\n", + subaddr); + return -EINVAL; + } + v4l_dbg(1, debug, &chip->c, "%s: chip_write: reg%d=0x%x\n", chip->c.name, subaddr, val); chip->shadow.bytes[subaddr+1] = val; @@ -181,12 +188,20 @@ return 0; } -static int chip_write_masked(struct CHIPSTATE *chip, int subaddr, int val, int mask) +static int chip_write_masked(struct CHIPSTATE *chip, + int subaddr, int val, int mask) { if (mask != 0) { - if (-1 == subaddr) { + if (subaddr < 0) { val = (chip->shadow.bytes[1] & ~mask) | (val & mask); } else { + if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) { + v4l_info(&chip->c, + "Tried to access a non-existent register: %d\n", + subaddr); + return -EINVAL; + } + val = (chip->shadow.bytes[subaddr+1] & ~mask) | (val & mask); } } @@ -232,6 +247,15 @@ if (0 == cmd->count) return 0; + if (cmd->count + cmd->bytes[0] - 1 >= ARRAY_SIZE(chip->shadow.bytes)) { + v4l_info(&chip->c, + "Tried to access a non-existent register range: %d to %d\n", + cmd->bytes[0] + 1, cmd->bytes[0] + cmd->count - 1); + return -EINVAL; + } + + /* FIXME: it seems that the shadow bytes are wrong bellow !*/ + /* update our shadow register set; print bytes if (debug > 0) */ v4l_dbg(1, debug, &chip->c, "%s: chip_cmd(%s): reg=%d, data:", chip->c.name, name,cmd->bytes[0]); @@ -1765,7 +1789,7 @@ case VIDIOCSFREQ: case VIDIOC_S_FREQUENCY: chip->mode = 0; /* automatic */ - if (desc->checkmode) { + if (desc->checkmode && desc->setmode) { desc->setmode(chip,VIDEO_SOUND_MONO); if (chip->prevmode != VIDEO_SOUND_MONO) chip->prevmode = -1; /* reset previous mode */ --- linux-2.6.24.orig/drivers/media/video/cx88/cx88-cards.c +++ linux-2.6.24/drivers/media/video/cx88/cx88-cards.c @@ -1349,6 +1349,10 @@ }}, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xe780, + }, }, [CX88_BOARD_ADSTECH_PTV_390] = { .name = "ADS Tech Instant Video PCI", --- linux-2.6.24.orig/drivers/media/video/saa7134/saa7134-dvb.c +++ linux-2.6.24/drivers/media/video/saa7134/saa7134-dvb.c @@ -826,6 +826,7 @@ static struct tda10086_config flydvbs = { .demod_address = 0x0e, .invert = 0, + .diseqc_tone = 0, }; /* ================================================================== --- linux-2.6.24.orig/drivers/media/video/ivtv/ivtv-ioctl.c +++ linux-2.6.24/drivers/media/video/ivtv/ivtv-ioctl.c @@ -727,7 +727,8 @@ memset(vcap, 0, sizeof(*vcap)); strcpy(vcap->driver, IVTV_DRIVER_NAME); /* driver name */ - strcpy(vcap->card, itv->card_name); /* card type */ + strncpy(vcap->card, itv->card_name, + sizeof(vcap->card)-1); /* card type */ strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */ vcap->version = IVTV_DRIVER_VERSION; /* version */ vcap->capabilities = itv->v4l2_cap; /* capabilities */ --- linux-2.6.24.orig/drivers/media/video/ivtv/ivtv-driver.c +++ linux-2.6.24/drivers/media/video/ivtv/ivtv-driver.c @@ -687,6 +687,9 @@ itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; itv->vbi.sliced_in = &itv->vbi.in.fmt.sliced; + /* Init the sg table for osd/yuv output */ + sg_init_table(itv->udma.SGlist, IVTV_DMA_SG_OSD_ENT); + /* OSD */ itv->osd_global_alpha_state = 1; itv->osd_global_alpha = 255; --- linux-2.6.24.orig/drivers/media/video/em28xx/em28xx-cards.c +++ linux-2.6.24/drivers/media/video/em28xx/em28xx-cards.c @@ -274,6 +274,7 @@ { USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x2040, 0x6502), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, { }, }; --- linux-2.6.24.orig/drivers/media/dvb/frontends/tda10086.h +++ linux-2.6.24/drivers/media/dvb/frontends/tda10086.h @@ -33,6 +33,9 @@ /* does the "inversion" need inverted? */ u8 invert; + + /* do we need the diseqc signal with carrier? */ + u8 diseqc_tone; }; #if defined(CONFIG_DVB_TDA10086) || (defined(CONFIG_DVB_TDA10086_MODULE) && defined(MODULE)) --- linux-2.6.24.orig/drivers/media/dvb/frontends/tda10086.c +++ linux-2.6.24/drivers/media/dvb/frontends/tda10086.c @@ -106,9 +106,12 @@ static int tda10086_init(struct dvb_frontend* fe) { struct tda10086_state* state = fe->demodulator_priv; + u8 t22k_off = 0x80; dprintk ("%s\n", __FUNCTION__); + if (state->config->diseqc_tone) + t22k_off = 0; // reset tda10086_write_byte(state, 0x00, 0x00); msleep(10); @@ -158,7 +161,7 @@ tda10086_write_byte(state, 0x3d, 0x80); // setup SEC - tda10086_write_byte(state, 0x36, 0x80); // all SEC off, no 22k tone + tda10086_write_byte(state, 0x36, t22k_off); // all SEC off, 22k tone tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000))); // } tone frequency tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8); // } @@ -180,16 +183,20 @@ static int tda10086_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { struct tda10086_state* state = fe->demodulator_priv; + u8 t22k_off = 0x80; dprintk ("%s\n", __FUNCTION__); + if (state->config->diseqc_tone) + t22k_off = 0; + switch (tone) { case SEC_TONE_OFF: - tda10086_write_byte(state, 0x36, 0x80); + tda10086_write_byte(state, 0x36, t22k_off); break; case SEC_TONE_ON: - tda10086_write_byte(state, 0x36, 0x81); + tda10086_write_byte(state, 0x36, 0x01 + t22k_off); break; } @@ -202,9 +209,13 @@ struct tda10086_state* state = fe->demodulator_priv; int i; u8 oldval; + u8 t22k_off = 0x80; dprintk ("%s\n", __FUNCTION__); + if (state->config->diseqc_tone) + t22k_off = 0; + if (cmd->msg_len > 6) return -EINVAL; oldval = tda10086_read_byte(state, 0x36); @@ -212,7 +223,8 @@ for(i=0; i< cmd->msg_len; i++) { tda10086_write_byte(state, 0x48+i, cmd->msg[i]); } - tda10086_write_byte(state, 0x36, 0x88 | ((cmd->msg_len - 1) << 4)); + tda10086_write_byte(state, 0x36, (0x08 + t22k_off) + | ((cmd->msg_len - 1) << 4)); tda10086_diseqc_wait(state); @@ -225,16 +237,20 @@ { struct tda10086_state* state = fe->demodulator_priv; u8 oldval = tda10086_read_byte(state, 0x36); + u8 t22k_off = 0x80; dprintk ("%s\n", __FUNCTION__); + if (state->config->diseqc_tone) + t22k_off = 0; + switch(minicmd) { case SEC_MINI_A: - tda10086_write_byte(state, 0x36, 0x84); + tda10086_write_byte(state, 0x36, 0x04 + t22k_off); break; case SEC_MINI_B: - tda10086_write_byte(state, 0x36, 0x86); + tda10086_write_byte(state, 0x36, 0x06 + t22k_off); break; } --- linux-2.6.24.orig/drivers/media/dvb/ttpci/budget.c +++ linux-2.6.24/drivers/media/dvb/ttpci/budget.c @@ -351,6 +351,7 @@ static struct tda10086_config tda10086_config = { .demod_address = 0x0e, .invert = 0, + .diseqc_tone = 1, }; static u8 read_pwm(struct budget* budget) --- linux-2.6.24.orig/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ linux-2.6.24/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -16,6 +16,7 @@ #define USB_VID_ALINK 0x05e3 #define USB_VID_ANCHOR 0x0547 #define USB_VID_ANUBIS_ELECTRONIC 0x10fd +#define USB_VID_ASUS 0x0b05 #define USB_VID_AVERMEDIA 0x07ca #define USB_VID_COMPRO 0x185b #define USB_VID_COMPRO_UNK 0x145f @@ -44,6 +45,7 @@ #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 #define USB_VID_UNIWILL 0x1584 #define USB_VID_WIDEVIEW 0x14aa +#define USB_VID_GIGABYTE 0x1044 /* Product IDs */ #define USB_PID_ADSTECH_USB2_COLD 0xa333 @@ -99,6 +101,7 @@ #define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a #define USB_PID_ARTEC_T14_COLD 0x810b #define USB_PID_ARTEC_T14_WARM 0x810c +#define USB_PID_ARTEC_T14BR 0x810f #define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613 #define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002 #define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e @@ -120,6 +123,7 @@ #define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 +#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 #define USB_PID_AVERMEDIA_EXPRESS 0xb568 #define USB_PID_AVERMEDIA_VOLAR 0xa807 @@ -170,6 +174,9 @@ #define USB_PID_OPERA1_WARM 0x3829 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513 - +/* dom pour gigabyte u7000 */ +#define USB_PID_GIGABYTE_U7000 0x7001 +#define USB_PID_ASUS_U3000 0x171f +#define USB_PID_ASUS_U3100 0x173f #endif --- linux-2.6.24.orig/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ linux-2.6.24/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -230,6 +230,27 @@ } }; +static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib7000p_i2c_enumeration(&adap->dev->i2c_adap,1,18,stk7700d_dib7000p_mt2266_config); + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); + + return adap->fe == NULL ? -ENODEV : 0; +} + static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) { if (adap->id == 0) { @@ -821,6 +842,11 @@ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, + { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, + { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) }, +/* 25 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -891,6 +917,10 @@ { "AVerMedia AVerTV DVB-T Express", { &dib0700_usb_id_table[20] }, { NULL }, + }, + { "Gigabyte U7000", + { &dib0700_usb_id_table[21], NULL }, + { NULL }, } }, @@ -974,6 +1004,25 @@ .num_adapters = 1, .adapter = { { + .frontend_attach = stk7700P2_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, + }, + + .num_device_descs = 1, + .devices = { + { "ASUS My Cinema U3000 Mini DVBT Tuner", + { &dib0700_usb_id_table[23], NULL }, + { NULL }, + }, + } + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { .frontend_attach = stk7070p_frontend_attach, .tuner_attach = dib7070p_tuner_attach, @@ -983,7 +1032,7 @@ }, }, - .num_device_descs = 2, + .num_device_descs = 5, .devices = { { "DiBcom STK7070P reference design", { &dib0700_usb_id_table[15], NULL }, @@ -993,7 +1042,25 @@ { &dib0700_usb_id_table[16], NULL }, { NULL }, }, - } + { "Artec T14BR DVB-T", + { &dib0700_usb_id_table[22], NULL }, + { NULL }, + }, + { "ASUS My Cinema U3100 Mini DVBT Tuner", + { &dib0700_usb_id_table[24], NULL }, + { NULL }, + }, + { "Hauppauge Nova-T Stick", + { &dib0700_usb_id_table[25], NULL }, + { NULL }, + }, + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 2, --- linux-2.6.24.orig/drivers/media/dvb/dvb-usb/umt-010.c +++ linux-2.6.24/drivers/media/dvb/dvb-usb/umt-010.c @@ -104,7 +104,7 @@ /* parameter for the MPEG2-data transfer */ .stream = { .type = USB_BULK, - .count = 20, + .count = MAX_NO_URBS_FOR_DATA_STREAM, .endpoint = 0x06, .u = { .bulk = { --- linux-2.6.24.orig/drivers/media/dvb/dvb-usb/ttusb2.c +++ linux-2.6.24/drivers/media/dvb/dvb-usb/ttusb2.c @@ -144,6 +144,7 @@ static struct tda10086_config tda10086_config = { .demod_address = 0x0e, .invert = 0, + .diseqc_tone = 1, }; static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap) --- linux-2.6.24.orig/drivers/char/selection.c +++ linux-2.6.24/drivers/char/selection.c @@ -268,7 +268,7 @@ /* Allocate a new buffer before freeing the old one ... */ multiplier = use_unicode ? 3 : 1; /* chars can take up to 3 bytes */ - bp = kmalloc((sel_end-sel_start)/2*multiplier+1, GFP_KERNEL); + bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL); if (!bp) { printk(KERN_WARNING "selection: kmalloc() failed\n"); clear_selection(); --- linux-2.6.24.orig/drivers/char/vt_ioctl.c +++ linux-2.6.24/drivers/char/vt_ioctl.c @@ -35,6 +35,8 @@ #include #include +#define max_font_size 65536 + char vt_dont_switch; extern struct tty_driver *console_driver; @@ -1166,6 +1168,7 @@ static void complete_change_console(struct vc_data *vc) { unsigned char old_vc_mode; + struct vc_data *oldvc = vc_cons[fg_console].d; last_console = fg_console; @@ -1174,9 +1177,31 @@ * KD_TEXT mode or vice versa, which means we need to blank or * unblank the screen later. */ - old_vc_mode = vc_cons[fg_console].d->vc_mode; + old_vc_mode = oldvc->vc_mode; + +#if defined(CONFIG_VGA_CONSOLE) + if (old_vc_mode == KD_TEXT && oldvc->vc_sw == &vga_con && + oldvc->vc_sw->con_font_get) { + if (!oldvc->vc_font.data) + oldvc->vc_font.data = kmalloc(max_font_size, + GFP_KERNEL); + lock_kernel(); + oldvc->vc_sw->con_font_get(oldvc, &oldvc->vc_font); + unlock_kernel(); + } +#endif switch_screen(vc); +#if defined(CONFIG_VGA_CONSOLE) + if (vc->vc_mode == KD_TEXT && vc->vc_sw == &vga_con && + vc->vc_sw->con_font_set) { + if (vc->vc_font.data) { + lock_kernel(); + vc->vc_sw->con_font_set(vc, &vc->vc_font, 0); + unlock_kernel(); + } + } +#endif /* * This can't appear below a successful kill_pid(). If it did, * then the *blank_screen operation could occur while X, having --- linux-2.6.24.orig/drivers/char/agp/ati-agp.c +++ linux-2.6.24/drivers/char/agp/ati-agp.c @@ -468,6 +468,10 @@ .chipset_name = "IGP9100/M", }, { + .device_id = PCI_DEVICE_ID_ATI_RS350_133, + .chipset_name = "IGP9000/M", + }, + { .device_id = PCI_DEVICE_ID_ATI_RS350_200, .chipset_name = "IGP9100/M", }, --- linux-2.6.24.orig/drivers/char/agp/generic.c +++ linux-2.6.24/drivers/char/agp/generic.c @@ -1166,7 +1166,7 @@ { struct page * page; - page = alloc_page(GFP_KERNEL | GFP_DMA32); + page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO ); if (page == NULL) return NULL; --- linux-2.6.24.orig/drivers/char/agp/via-agp.c +++ linux-2.6.24/drivers/char/agp/via-agp.c @@ -548,6 +548,7 @@ ID(PCI_DEVICE_ID_VIA_VT3324), ID(PCI_DEVICE_ID_VIA_VT3336), ID(PCI_DEVICE_ID_VIA_P4M890), + ID(PCI_DEVICE_ID_VIA_VT3364), { } }; --- linux-2.6.24.orig/drivers/char/virtio_console.c +++ linux-2.6.24/drivers/char/virtio_console.c @@ -158,13 +158,13 @@ /* Find the input queue. */ /* FIXME: This is why we want to wean off hvc: we do nothing * when input comes in. */ - in_vq = vdev->config->find_vq(vdev, NULL); + in_vq = vdev->config->find_vq(vdev, 0, NULL); if (IS_ERR(in_vq)) { err = PTR_ERR(in_vq); goto free; } - out_vq = vdev->config->find_vq(vdev, NULL); + out_vq = vdev->config->find_vq(vdev, 1, NULL); if (IS_ERR(out_vq)) { err = PTR_ERR(out_vq); goto free_in_vq; --- linux-2.6.24.orig/drivers/char/vt.c +++ linux-2.6.24/drivers/char/vt.c @@ -264,6 +264,10 @@ #define DO_UPDATE(vc) CON_IS_VISIBLE(vc) #endif +#ifdef CONFIG_PROM_CONSOLE +static int force_prom_console; +#endif + static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) { unsigned short *p; @@ -702,6 +706,7 @@ if (is_switch) { set_leds(); compute_shiftstate(); + notify_update(vc); } } @@ -2882,6 +2887,17 @@ .unthrottle = con_unthrottle, }; +#ifdef CONFIG_PROM_CONSOLE +static int __init check_prom_console(char *str) +{ + force_prom_console = 1; + printk ("PROM console forced!\n"); + return 1; +} + +__setup("forcepromconsole", check_prom_console); +#endif + int __init vty_init(void) { vcs_init(); @@ -2904,7 +2920,8 @@ kbd_init(); console_map_init(); #ifdef CONFIG_PROM_CONSOLE - prom_con_init(); + if (force_prom_console) + prom_con_init(); #endif #ifdef CONFIG_MDA_CONSOLE mda_console_init(); --- linux-2.6.24.orig/drivers/char/Kconfig +++ linux-2.6.24/drivers/char/Kconfig @@ -80,6 +80,14 @@ information. For framebuffer console users, please refer to . +config DEV_KMEM + bool "/dev/kmem virtual device support" + help + Say Y here if you want to support the /dev/kmem device. The + /dev/kmem device is rarely used, but can be used for certain + kind of kernel debugging operations. + When in doubt, say "N". + config SERIAL_NONSTANDARD bool "Non-standard serial port support" depends on HAS_IOMEM --- linux-2.6.24.orig/drivers/char/drm/via_chrome9_3d_reg.h +++ linux-2.6.24/drivers/char/drm/via_chrome9_3d_reg.h @@ -0,0 +1,401 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VIA_CHROME9_3D_REG_H +#define VIA_CHROME9_3D_REG_H + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#define GetMMIORegister(base, offset) \ + (*(volatile unsigned int *)(void *)(((unsigned char *)(base)) + \ + (offset))) +#define SetMMIORegister(base, offset, val) \ + (*(volatile unsigned int *)(void *)(((unsigned char *)(base)) + \ + (offset)) = (val)) + +#define GetMMIORegisterU8(base, offset) \ + (*(volatile unsigned char *)(void *)(((unsigned char *)(base)) + \ + (offset))) +#define SetMMIORegisterU8(base, offset, val) \ + (*(volatile unsigned char *)(void *)(((unsigned char *)(base)) + \ + (offset)) = (val)) + +#define BCI_SEND(bci, value) (*(bci)++ = (unsigned long)(value)) +#define BCI_SET_STREAM_REGISTER(bci_base, bci_index, reg_value) \ +do { \ + unsigned long cmd; \ + \ + cmd = (0x90000000 \ + | (1<<16) /* stream processor register */ \ + | (bci_index & 0x3FFC)); /* MMIO register address */ \ + BCI_SEND(bci_base, cmd); \ + BCI_SEND(bci_base, reg_value); \ + } while (0) + +/* Command Header Type */ + +#define INV_AGPHeader0 0xFE000000 +#define INV_AGPHeader1 0xFE010000 +#define INV_AGPHeader2 0xFE020000 +#define INV_AGPHeader3 0xFE030000 +#define INV_AGPHeader4 0xFE040000 +#define INV_AGPHeader5 0xFE050000 +#define INV_AGPHeader6 0xFE060000 +#define INV_AGPHeader7 0xFE070000 +#define INV_AGPHeader82 0xFE820000 +#define INV_AGPHeader_MASK 0xFFFF0000 + +/*send pause address of AGP ring command buffer via_chrome9 this IO port*/ +#define INV_REG_PCIPAUSE 0x294 +#define INV_REG_PCIPAUSE_ENABLE 0x4 + +#define INV_CMDBUF_THRESHOLD (8) +#define INV_QW_PAUSE_ALIGN 0x40 + +/* Transmission IO Space*/ +#define INV_REG_CR_TRANS 0x041C +#define INV_REG_CR_BEGIN 0x0420 +#define INV_REG_CR_END 0x0438 + +#define INV_REG_3D_TRANS 0x043C +#define INV_REG_3D_BEGIN 0x0440 +#define INV_REG_3D_END 0x06FC +#define INV_REG_23D_WAIT 0x326C +/*3D / 2D ID Control (Only For Group A)*/ +#define INV_REG_2D3D_ID_CTRL 0x060 + + +/* Engine Status */ + +#define INV_RB_ENG_STATUS 0x0400 +#define INV_ENG_BUSY_HQV0 0x00040000 +#define INV_ENG_BUSY_HQV1 0x00020000 +#define INV_ENG_BUSY_CR 0x00000010 +#define INV_ENG_BUSY_MPEG 0x00000008 +#define INV_ENG_BUSY_VQ 0x00000004 +#define INV_ENG_BUSY_2D 0x00000002 +#define INV_ENG_BUSY_3D 0x00001FE1 +#define INV_ENG_BUSY_ALL \ + (INV_ENG_BUSY_2D | INV_ENG_BUSY_3D | INV_ENG_BUSY_CR) + +/* Command Queue Status*/ +#define INV_RB_VQ_STATUS 0x0448 +#define INV_VQ_FULL 0x40000000 + +/* AGP command buffer pointer current position*/ +#define INV_RB_AGPCMD_CURRADDR 0x043C + +/* AGP command buffer status*/ +#define INV_RB_AGPCMD_STATUS 0x0444 +#define INV_AGPCMD_InPause 0x80000000 + +/*AGP command buffer pause address*/ +#define INV_RB_AGPCMD_PAUSEADDR 0x045C + +/*AGP command buffer jump address*/ +#define INV_RB_AGPCMD_JUMPADDR 0x0460 + +/*AGP command buffer start address*/ +#define INV_RB_AGPCMD_STARTADDR 0x0464 + + +/* Constants */ +#define NUMBER_OF_EVENT_TAGS 1024 +#define NUMBER_OF_APERTURES_CLB 16 + +/* Register definition */ +#define HW_SHADOW_ADDR 0x8520 +#define HW_GARTTABLE_ADDR 0x8540 + +#define INV_HSWFlag_DBGMASK 0x00000FFF +#define INV_HSWFlag_ENCODEMASK 0x007FFFF0 +#define INV_HSWFlag_ADDRSHFT 8 +#define INV_HSWFlag_DECODEMASK \ + (INV_HSWFlag_ENCODEMASK << INV_HSWFlag_ADDRSHFT) +#define INV_HSWFlag_ADDR_ENCODE(x) 0xCC000000 +#define INV_HSWFlag_ADDR_DECODE(x) \ + (((unsigned int)x & INV_HSWFlag_DECODEMASK) >> INV_HSWFlag_ADDRSHFT) + + +#define INV_SubA_HAGPBstL 0x60000000 +#define INV_SubA_HAGPBstH 0x61000000 +#define INV_SubA_HAGPBendL 0x62000000 +#define INV_SubA_HAGPBendH 0x63000000 +#define INV_SubA_HAGPBpL 0x64000000 +#define INV_SubA_HAGPBpID 0x65000000 +#define INV_HAGPBpID_PAUSE 0x00000000 +#define INV_HAGPBpID_JUMP 0x00000100 +#define INV_HAGPBpID_STOP 0x00000200 + +#define INV_HAGPBpH_MASK 0x000000FF +#define INV_HAGPBpH_SHFT 0 + +#define INV_SubA_HAGPBjumpL 0x66000000 +#define INV_SubA_HAGPBjumpH 0x67000000 +#define INV_HAGPBjumpH_MASK 0x000000FF +#define INV_HAGPBjumpH_SHFT 0 + +#define INV_SubA_HFthRCM 0x68000000 +#define INV_HFthRCM_MASK 0x003F0000 +#define INV_HFthRCM_SHFT 16 +#define INV_HFthRCM_8 0x00080000 +#define INV_HFthRCM_10 0x000A0000 +#define INV_HFthRCM_18 0x00120000 +#define INV_HFthRCM_24 0x00180000 +#define INV_HFthRCM_32 0x00200000 + +#define INV_HAGPBClear 0x00000008 + +#define INV_HRSTTrig_RestoreAGP 0x00000004 +#define INV_HRSTTrig_RestoreAll 0x00000002 +#define INV_HAGPBTrig 0x00000001 + +#define INV_ParaSubType_MASK 0xff000000 +#define INV_ParaType_MASK 0x00ff0000 +#define INV_ParaOS_MASK 0x0000ff00 +#define INV_ParaAdr_MASK 0x000000ff +#define INV_ParaSubType_SHIFT 24 +#define INV_ParaType_SHIFT 16 +#define INV_ParaOS_SHIFT 8 +#define INV_ParaAdr_SHIFT 0 + +#define INV_ParaType_Vdata 0x00000000 +#define INV_ParaType_Attr 0x00010000 +#define INV_ParaType_Tex 0x00020000 +#define INV_ParaType_Pal 0x00030000 +#define INV_ParaType_FVF 0x00040000 +#define INV_ParaType_PreCR 0x00100000 +#define INV_ParaType_CR 0x00110000 +#define INV_ParaType_Cfg 0x00fe0000 +#define INV_ParaType_Dummy 0x00300000 + +#define INV_HWBasL_MASK 0x00FFFFFF +#define INV_HWBasH_MASK 0xFF000000 +#define INV_HWBasH_SHFT 24 +#define INV_HWBasL(x) ((unsigned int)(x) & INV_HWBasL_MASK) +#define INV_HWBasH(x) ((unsigned int)(x) >> INV_HWBasH_SHFT) +#define INV_HWBas256(x) ((unsigned int)(x) >> 8) +#define INV_HWPit32(x) ((unsigned int)(x) >> 5) + +/* Read Back Register Setting */ +#define INV_SubA_HSetRBGID 0x02000000 +#define INV_HSetRBGID_CR 0x00000000 +#define INV_HSetRBGID_FE 0x00000001 +#define INV_HSetRBGID_PE 0x00000002 +#define INV_HSetRBGID_RC 0x00000003 +#define INV_HSetRBGID_PS 0x00000004 +#define INV_HSetRBGID_XE 0x00000005 +#define INV_HSetRBGID_BE 0x00000006 + + +struct drm_clb_event_tag_info { + unsigned int *linear_address; + unsigned int *event_tag_linear_address; + int usage[NUMBER_OF_EVENT_TAGS]; + unsigned int pid[NUMBER_OF_EVENT_TAGS]; +}; + +static inline int IS_AGPHEADER_INV(unsigned int data) +{ + switch (data & INV_AGPHeader_MASK) { + case INV_AGPHeader0: + case INV_AGPHeader1: + case INV_AGPHeader2: + case INV_AGPHeader3: + case INV_AGPHeader4: + case INV_AGPHeader5: + case INV_AGPHeader6: + case INV_AGPHeader7: + return TRUE; + default: + return FALSE; + } +} + +/* Header0: 2D */ +#define ADDCmdHeader0_INVI(pCmd, dwCount) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader0; \ + *(pCmd)++ = (dwCount); \ + *(pCmd)++ = 0; \ + *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \ +} + +/* Header1: 2D */ +#define ADDCmdHeader1_INVI(pCmd, dwAddr, dwCount) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader1 | (dwAddr); \ + *(pCmd)++ = (dwCount); \ + *(pCmd)++ = 0; \ + *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \ +} + +/* Header2: CR/3D */ +#define ADDCmdHeader2_INVI(pCmd, dwAddr, dwType) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned int)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader2 | ((dwAddr)+4); \ + *(pCmd)++ = (dwAddr); \ + *(pCmd)++ = (dwType); \ + *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \ +} + +/* Header2: CR/3D with SW Flag */ +#define ADDCmdHeader2_SWFlag_INVI(pCmd, dwAddr, dwType, dwSWFlag) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader2 | ((dwAddr)+4); \ + *(pCmd)++ = (dwAddr); \ + *(pCmd)++ = (dwType); \ + *(pCmd)++ = (dwSWFlag); \ +} + + +/* Header3: 3D */ +#define ADDCmdHeader3_INVI(pCmd, dwType, dwStart, dwCount) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader3 | INV_REG_3D_TRANS; \ + *(pCmd)++ = (dwCount); \ + *(pCmd)++ = (dwType) | ((dwStart) & 0xFFFF); \ + *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \ +} + +/* Header3: 3D with SW Flag */ +#define ADDCmdHeader3_SWFlag_INVI(pCmd, dwType, dwStart, dwSWFlag, dwCount) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader3 | INV_REG_3D_TRANS; \ + *(pCmd)++ = (dwCount); \ + *(pCmd)++ = (dwType) | ((dwStart) & 0xFFFF); \ + *(pCmd)++ = (dwSWFlag); \ +} + +/* Header4: DVD */ +#define ADDCmdHeader4_INVI(pCmd, dwAddr, dwCount, id) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader4 | (dwAddr); \ + *(pCmd)++ = (dwCount); \ + *(pCmd)++ = (id); \ + *(pCmd)++ = 0; \ +} + +/* Header5: DVD */ +#define ADDCmdHeader5_INVI(pCmd, dwQWcount, id) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader5; \ + *(pCmd)++ = (dwQWcount); \ + *(pCmd)++ = (id); \ + *(pCmd)++ = 0; \ +} + +/* Header6: DEBUG */ +#define ADDCmdHeader6_INVI(pCmd) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader6; \ + *(pCmd)++ = 0; \ + *(pCmd)++ = 0; \ + *(pCmd)++ = 0; \ +} + +/* Header7: DMA */ +#define ADDCmdHeader7_INVI(pCmd, dwQWcount, id) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader7; \ + *(pCmd)++ = (dwQWcount); \ + *(pCmd)++ = (id); \ + *(pCmd)++ = 0; \ +} + +/* Header82: Branch buffer */ +#define ADDCmdHeader82_INVI(pCmd, dwAddr, dwType); \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader82 | ((dwAddr)+4); \ + *(pCmd)++ = (dwAddr); \ + *(pCmd)++ = (dwType); \ + *(pCmd)++ = 0xCC000000; \ +} + + +#define ADD2DCmd_INVI(pCmd, dwAddr, dwCmd) \ +{ \ + *(pCmd)++ = (dwAddr); \ + *(pCmd)++ = (dwCmd); \ +} + +#define ADDCmdData_INVI(pCmd, dwCmd) *(pCmd)++ = (dwCmd) + +#define ADDCmdDataStream_INVI(pCmdBuf, pCmd, dwCount) \ +{ \ + memcpy((pCmdBuf), (pCmd), ((dwCount)<<2)); \ + (pCmdBuf) += (dwCount); \ +} + +#endif --- linux-2.6.24.orig/drivers/char/drm/drm_drv.c +++ linux-2.6.24/drivers/char/drm/drm_drv.c @@ -386,19 +386,19 @@ DRM_INFO("Initialized %s %d.%d.%d %s\n", CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); return 0; - err_p3: - drm_sysfs_destroy(drm_class); - err_p2: +err_p3: + drm_sysfs_destroy(); +err_p2: unregister_chrdev(DRM_MAJOR, "drm"); drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); - err_p1: +err_p1: return ret; } static void __exit drm_core_exit(void) { remove_proc_entry("dri", NULL); - drm_sysfs_destroy(drm_class); + drm_sysfs_destroy(); unregister_chrdev(DRM_MAJOR, "drm"); --- linux-2.6.24.orig/drivers/char/drm/via_chrome9_dma.c +++ linux-2.6.24/drivers/char/drm/via_chrome9_dma.c @@ -0,0 +1,1147 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "drmP.h" +#include "drm.h" +#include "via_chrome9_drm.h" +#include "via_chrome9_drv.h" +#include "via_chrome9_3d_reg.h" +#include "via_chrome9_dma.h" + +#define NULLCOMMANDNUMBER 256 +unsigned int NULL_COMMAND_INV[4] = + { 0xCC000000, 0xCD000000, 0xCE000000, 0xCF000000 }; + +void +via_chrome9ke_assert(int a) +{ +} + +unsigned int +ProtectSizeValue(unsigned int size) +{ + unsigned int i; + for (i = 0; i < 8; i++) + if ((size > (1 << (i + 12))) + && (size <= (1 << (i + 13)))) + return (i + 1); + return 0; +} + +static unsigned int +InitPCIEGART(struct drm_via_chrome9_private *dev_priv) +{ + unsigned int *pGARTTable; + unsigned int i, entries, GARTOffset; + unsigned char sr6a, sr6b, sr6c, sr6f, sr7b; + + if (!dev_priv->pagetable_map.pagetable_size) + return 0; + + entries = dev_priv->pagetable_map.pagetable_size / sizeof(unsigned int); + + pGARTTable = + ioremap_nocache(dev_priv->fb_base_address + + dev_priv->pagetable_map.pagetable_offset, + dev_priv->pagetable_map.pagetable_size); + if (pGARTTable) + dev_priv->pagetable_map.pagetable_handle = pGARTTable; + else + return 0; + + /*set gart table base */ + GARTOffset = dev_priv->pagetable_map.pagetable_offset; + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c &= (~0x80); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + sr6a = (unsigned char) ((GARTOffset & 0xff000) >> 12); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6a); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6a); + + sr6b = (unsigned char) ((GARTOffset & 0xff00000) >> 20); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6b); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6b); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c |= ((unsigned char) ((GARTOffset >> 28) & 0x01)); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x7b); + sr7b = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr7b &= (~0x0f); + sr7b |= ProtectSizeValue(dev_priv->pagetable_map.pagetable_size); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr7b); + + for (i = 0; i < entries; i++) + writel(0x80000000, pGARTTable + i); + /*flush */ + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f); + do { + sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + } + while (sr6f & 0x80) + ; + + sr6f |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + return 1; +} + + +static unsigned int * +AllocAndBindPCIEMemory(struct drm_via_chrome9_private *dev_priv, + unsigned int size, unsigned int offset) +{ + unsigned int *addrlinear; + unsigned int *pGARTTable; + unsigned int entries, alignedoffset, i; + unsigned char sr6c, sr6f; + + if (!size) + return NULL; + + entries = (size + PAGE_SIZE - 1) / PAGE_SIZE; + alignedoffset = (offset + PAGE_SIZE - 1) / PAGE_SIZE; + + if ((entries + alignedoffset) > + (dev_priv->pagetable_map.pagetable_size / sizeof(unsigned int))) + return NULL; + + addrlinear = + __vmalloc(entries * PAGE_SIZE, GFP_KERNEL | __GFP_HIGHMEM, + PAGE_KERNEL_NOCACHE); + + if (!addrlinear) + return NULL; + + pGARTTable = dev_priv->pagetable_map.pagetable_handle; + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c &= (~0x80); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f); + do { + sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + } + while (sr6f & 0x80) + ; + + for (i = 0; i < entries; i++) + writel(page_to_pfn + (vmalloc_to_page((void *) addrlinear + PAGE_SIZE * i)) & + 0x3fffffff, pGARTTable + i + alignedoffset); + + sr6f |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + return addrlinear; + +} + +void +SetAGPDoubleCmd_inv(struct drm_device *dev) +{ + /* we now don't use double buffer */ + return; +} + +void +SetAGPRingCmdRegs_inv(struct drm_device *dev) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + (struct drm_via_chrome9_DMA_manager *) dev_priv->dma_manager; + unsigned int AGPBufLinearBase = 0, AGPBufPhysicalBase = 0; + unsigned long *pFree; + unsigned int dwStart, dwEnd, dwPause, AGPCurrAddr, AGPCurStat, CurrAGP; + unsigned int dwReg60, dwReg61, dwReg62, dwReg63, + dwReg64, dwReg65, dwJump; + + lpcmDMAManager->pFree = lpcmDMAManager->pBeg; + + AGPBufLinearBase = (unsigned int) lpcmDMAManager->addr_linear; + AGPBufPhysicalBase = + (dev_priv->chip_agp == + CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base + + lpcmDMAManager->pPhysical; + /*add shadow offset */ + + CurrAGP = + GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_CURRADDR); + AGPCurStat = + GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_STATUS); + + if (AGPCurStat & INV_AGPCMD_InPause) { + AGPCurrAddr = + GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + pFree = (unsigned long *) (AGPBufLinearBase + AGPCurrAddr - + AGPBufPhysicalBase); + ADDCmdHeader2_INVI(pFree, INV_REG_CR_TRANS, INV_ParaType_Dummy); + if (dev_priv->chip_sub_index == CHIP_H6S2) + do { + ADDCmdData_INVI(pFree, 0xCCCCCCC0); + ADDCmdData_INVI(pFree, 0xDDD00000); + } + while ((u32)((unsigned int) pFree) & 0x7f) + ; + /*for 8*128bit aligned */ + else + do { + ADDCmdData_INVI(pFree, 0xCCCCCCC0); + ADDCmdData_INVI(pFree, 0xDDD00000); + } + while ((u32) ((unsigned int) pFree) & 0x1f) + ; + /*for 256bit aligned */ + dwPause = + (u32) (((unsigned int) pFree) - AGPBufLinearBase + + AGPBufPhysicalBase - 16); + + dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); + dwReg65 = + INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | + INV_HAGPBpID_STOP; + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + dwReg64); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + dwReg65); + + while ((GetMMIORegister + (dev_priv->mmio->handle, + INV_RB_ENG_STATUS) & INV_ENG_BUSY_ALL)); + } + dwStart = + (u32) ((unsigned int) lpcmDMAManager->pBeg - AGPBufLinearBase + + AGPBufPhysicalBase); + dwEnd = (u32) ((unsigned int) lpcmDMAManager->pEnd - AGPBufLinearBase + + AGPBufPhysicalBase); + + lpcmDMAManager->pFree = lpcmDMAManager->pBeg; + if (dev_priv->chip_sub_index == CHIP_H6S2) { + ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS, + INV_ParaType_Dummy); + do { + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC0); + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xDDD00000); + } + while ((u32)((unsigned long *) lpcmDMAManager->pFree) & 0x7f) + ; + } + dwJump = 0xFFFFFFF0; + dwPause = + (u32)(((unsigned int) lpcmDMAManager->pFree) - + 16 - AGPBufLinearBase + AGPBufPhysicalBase); + + DRM_DEBUG("dwStart = %08x, dwEnd = %08x, dwPause = %08x\n", dwStart, + dwEnd, dwPause); + + dwReg60 = INV_SubA_HAGPBstL | INV_HWBasL(dwStart); + dwReg61 = INV_SubA_HAGPBstH | INV_HWBasH(dwStart); + dwReg62 = INV_SubA_HAGPBendL | INV_HWBasL(dwEnd); + dwReg63 = INV_SubA_HAGPBendH | INV_HWBasH(dwEnd); + dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); + dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_PAUSE; + + if (dev_priv->chip_sub_index == CHIP_H6S2) + dwReg60 |= 0x01; + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg60); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg61); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg62); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg63); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + INV_SubA_HAGPBjumpL | INV_HWBasL(dwJump)); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + INV_SubA_HAGPBjumpH | INV_HWBasH(dwJump)); + + /* Trigger AGP cycle */ + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + INV_SubA_HFthRCM | INV_HFthRCM_10 | INV_HAGPBTrig); + + /*for debug */ + CurrAGP = + GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_CURRADDR); + + lpcmDMAManager->pInUseBySW = lpcmDMAManager->pFree; +} + +/* Do hw intialization and determine whether to use dma or mmio to +talk with hw */ +int +via_chrome9_hw_init(struct drm_device *dev, + struct drm_via_chrome9_init *init) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + unsigned retval = 0; + unsigned int *pGARTTable, *addrlinear = NULL; + int pages; + struct drm_clb_event_tag_info *event_tag_info; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = NULL; + + if (init->chip_agp == CHIP_PCIE) { + dev_priv->pagetable_map.pagetable_offset = + init->garttable_offset; + dev_priv->pagetable_map.pagetable_size = init->garttable_size; + dev_priv->agp_size = init->agp_tex_size; + /*Henry :prepare for PCIE texture buffer */ + } else { + dev_priv->pagetable_map.pagetable_offset = 0; + dev_priv->pagetable_map.pagetable_size = 0; + } + + dev_priv->dma_manager = + kmalloc(sizeof(struct drm_via_chrome9_DMA_manager), GFP_KERNEL); + if (!dev_priv->dma_manager) { + DRM_ERROR("could not allocate system for dma_manager!\n"); + return -ENOMEM; + } + + lpcmDMAManager = + (struct drm_via_chrome9_DMA_manager *) dev_priv->dma_manager; + ((struct drm_via_chrome9_DMA_manager *) + dev_priv->dma_manager)->DMASize = init->DMA_size; + ((struct drm_via_chrome9_DMA_manager *) + dev_priv->dma_manager)->pPhysical = init->DMA_phys_address; + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, 0x00110000); + if (dev_priv->chip_sub_index == CHIP_H6S2) { + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x06000000); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x07100000); + } else { + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x02000000); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x03100000); + } + + /* Specify fence command read back ID */ + /* Default the read back ID is CR */ + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + INV_SubA_HSetRBGID | INV_HSetRBGID_CR); + + DRM_DEBUG("begin to init\n"); + + if (dev_priv->chip_sub_index == CHIP_H6S2) { + dev_priv->pcie_vmalloc_nocache = 0; + if (dev_priv->pagetable_map.pagetable_size) + retval = InitPCIEGART(dev_priv); + + if (retval && dev_priv->drm_agp_type != DRM_AGP_DISABLED) { + addrlinear = + AllocAndBindPCIEMemory(dev_priv, + lpcmDMAManager->DMASize + + dev_priv->agp_size, 0); + if (addrlinear) { + dev_priv->pcie_vmalloc_nocache = (unsigned long) + addrlinear; + } else { + dev_priv->bci_buffer = + vmalloc(MAX_BCI_BUFFER_SIZE); + dev_priv->drm_agp_type = DRM_AGP_DISABLED; + } + } else { + dev_priv->bci_buffer = vmalloc(MAX_BCI_BUFFER_SIZE); + dev_priv->drm_agp_type = DRM_AGP_DISABLED; + } + } else { + if (dev_priv->drm_agp_type != DRM_AGP_DISABLED) { + pGARTTable = NULL; + addrlinear = (unsigned int *) + ioremap(dev->agp->base + + lpcmDMAManager->pPhysical, + lpcmDMAManager->DMASize); + dev_priv->bci_buffer = NULL; + } else { + dev_priv->bci_buffer = vmalloc(MAX_BCI_BUFFER_SIZE); + /*Homer, BCI path always use this block of memory8 */ + } + } + + /*till here we have known whether support dma or not */ + pages = dev->sg->pages; + event_tag_info = vmalloc(sizeof(struct drm_clb_event_tag_info)); + memset(event_tag_info, 0, sizeof(struct drm_clb_event_tag_info)); + if (!event_tag_info) + return DRM_ERROR(" event_tag_info allocate error!"); + + /* aligned to 16k alignment */ + event_tag_info->linear_address = + (int + *) (((unsigned int) dev_priv->shadow_map.shadow_handle + + 0x3fff) & 0xffffc000); + event_tag_info->event_tag_linear_address = + event_tag_info->linear_address + 3; + dev_priv->event_tag_info = (void *) event_tag_info; + dev_priv->max_apertures = NUMBER_OF_APERTURES_CLB; + + /* Initialize DMA data structure */ + lpcmDMAManager->DMASize /= sizeof(unsigned int); + lpcmDMAManager->pBeg = addrlinear; + lpcmDMAManager->pFree = lpcmDMAManager->pBeg; + lpcmDMAManager->pInUseBySW = lpcmDMAManager->pBeg; + lpcmDMAManager->pInUseByHW = lpcmDMAManager->pBeg; + lpcmDMAManager->LastIssuedEventTag = (unsigned int) (unsigned long *) + lpcmDMAManager->pBeg; + lpcmDMAManager->ppInUseByHW = + (unsigned int **) ((char *) (dev_priv->mmio->handle) + + INV_RB_AGPCMD_CURRADDR); + lpcmDMAManager->bDMAAgp = dev_priv->chip_agp; + lpcmDMAManager->addr_linear = (unsigned int *) addrlinear; + + if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) { + lpcmDMAManager->MaxKickoffSize = lpcmDMAManager->DMASize >> 1; + lpcmDMAManager->pEnd = + lpcmDMAManager->addr_linear + + (lpcmDMAManager->DMASize >> 1) - 1; + SetAGPDoubleCmd_inv(dev); + if (dev_priv->chip_sub_index == CHIP_H6S2) { + DRM_INFO("DMA buffer initialized finished. "); + DRM_INFO("Use PCIE Double Buffer type!\n"); + DRM_INFO("Total PCIE DMA buffer size = %8d bytes. \n", + lpcmDMAManager->DMASize << 2); + } else { + DRM_INFO("DMA buffer initialized finished. "); + DRM_INFO("Use AGP Double Buffer type!\n"); + DRM_INFO("Total AGP DMA buffer size = %8d bytes. \n", + lpcmDMAManager->DMASize << 2); + } + } else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) { + lpcmDMAManager->MaxKickoffSize = lpcmDMAManager->DMASize; + lpcmDMAManager->pEnd = + lpcmDMAManager->addr_linear + lpcmDMAManager->DMASize; + SetAGPRingCmdRegs_inv(dev); + if (dev_priv->chip_sub_index == CHIP_H6S2) { + DRM_INFO("DMA buffer initialized finished. \n"); + DRM_INFO("Use PCIE Ring Buffer type!"); + DRM_INFO("Total PCIE DMA buffer size = %8d bytes. \n", + lpcmDMAManager->DMASize << 2); + } else { + DRM_INFO("DMA buffer initialized finished. "); + DRM_INFO("Use AGP Ring Buffer type!\n"); + DRM_INFO("Total AGP DMA buffer size = %8d bytes. \n", + lpcmDMAManager->DMASize << 2); + } + } else if (dev_priv->drm_agp_type == DRM_AGP_DISABLED) { + lpcmDMAManager->MaxKickoffSize = 0x0; + if (dev_priv->chip_sub_index == CHIP_H6S2) + DRM_INFO("PCIE init failed! Use PCI\n"); + else + DRM_INFO("AGP init failed! Use PCI\n"); + } + return 0; +} + +static void +kickoff_bci_inv(struct drm_via_chrome9_private *dev_priv, + struct drm_via_chrome9_flush *dma_info) +{ + u32 HdType, dwQWCount, i, dwCount, Addr1, Addr2, SWPointer, + SWPointerEnd; + unsigned long *pCmdData; + int result; + + /*pCmdData = __s3gke_vmalloc(dma_info->cmd_size<<2); */ + pCmdData = dev_priv->bci_buffer; + + if (!pCmdData) + return; + + result = copy_from_user((int *) pCmdData, dma_info->usermode_dma_buf, + dma_info->cmd_size << 2); + + SWPointer = 0; + SWPointerEnd = (u32) dma_info->cmd_size; + while (SWPointer < SWPointerEnd) { + HdType = pCmdData[SWPointer] & INV_AGPHeader_MASK; + switch (HdType) { + case INV_AGPHeader0: + case INV_AGPHeader5: + dwQWCount = pCmdData[SWPointer + 1]; + SWPointer += 4; + + for (i = 0; i < dwQWCount; i++) { + SetMMIORegister(dev_priv->mmio->handle, + pCmdData[SWPointer], + pCmdData[SWPointer + 1]); + SWPointer += 2; + } + break; + + case INV_AGPHeader1: + dwCount = pCmdData[SWPointer + 1]; + Addr1 = 0x0; + SWPointer += 4; /* skip 128-bit. */ + + for (; dwCount > 0; dwCount--, SWPointer++, + Addr1 += 4) { + SetMMIORegister(dev_priv->hostBlt->handle, + Addr1, pCmdData[SWPointer]); + } + break; + + case INV_AGPHeader4: + dwCount = pCmdData[SWPointer + 1]; + Addr1 = pCmdData[SWPointer] & 0x0000FFFF; + SWPointer += 4; /* skip 128-bit. */ + + for (; dwCount > 0; dwCount--, SWPointer++) + SetMMIORegister(dev_priv->mmio->handle, Addr1, + pCmdData[SWPointer]); + break; + + case INV_AGPHeader2: + Addr1 = pCmdData[SWPointer + 1] & 0xFFFF; + Addr2 = pCmdData[SWPointer] & 0xFFFF; + + /* Write first data (either ParaType or whatever) to + Addr1 */ + SetMMIORegister(dev_priv->mmio->handle, Addr1, + pCmdData[SWPointer + 2]); + SWPointer += 4; + + /* The following data are all written to Addr2, + until another header is met */ + while (!IS_AGPHEADER_INV(pCmdData[SWPointer]) + && (SWPointer < SWPointerEnd)) { + SetMMIORegister(dev_priv->mmio->handle, Addr2, + pCmdData[SWPointer]); + SWPointer++; + } + break; + + case INV_AGPHeader3: + Addr1 = pCmdData[SWPointer] & 0xFFFF; + Addr2 = Addr1 + 4; + dwCount = pCmdData[SWPointer + 1]; + + /* Write first data (either ParaType or whatever) to + Addr1 */ + SetMMIORegister(dev_priv->mmio->handle, Addr1, + pCmdData[SWPointer + 2]); + SWPointer += 4; + + for (i = 0; i < dwCount; i++) { + SetMMIORegister(dev_priv->mmio->handle, Addr2, + pCmdData[SWPointer]); + SWPointer++; + } + break; + + case INV_AGPHeader6: + break; + + case INV_AGPHeader7: + break; + + default: + SWPointer += 4; /* Advance to next header */ + } + + SWPointer = (SWPointer + 3) & ~3; + } +} + +void +kickoff_dma_db_inv(struct drm_device *dev) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + + u32 BufferSize = (u32) (lpcmDMAManager->pFree - lpcmDMAManager->pBeg); + + unsigned int AGPBufLinearBase = + (unsigned int) lpcmDMAManager->addr_linear; + unsigned int AGPBufPhysicalBase = + (unsigned int) dev->agp->base + lpcmDMAManager->pPhysical; + /*add shadow offset */ + + unsigned int dwStart, dwEnd, dwPause; + unsigned int dwReg60, dwReg61, dwReg62, dwReg63, dwReg64, dwReg65; + unsigned int CR_Status; + + if (BufferSize == 0) + return; + + /* 256-bit alignment of AGP pause address */ + if ((u32) ((unsigned long *) lpcmDMAManager->pFree) & 0x1f) { + ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS, + INV_ParaType_Dummy); + do { + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC0); + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xDDD00000); + } + while (((unsigned int) lpcmDMAManager->pFree) & 0x1f) + ; + } + + dwStart = + (u32) (unsigned long *)lpcmDMAManager->pBeg - + AGPBufLinearBase + AGPBufPhysicalBase; + dwEnd = (u32) (unsigned long *)lpcmDMAManager->pEnd - + AGPBufLinearBase + AGPBufPhysicalBase; + dwPause = + (u32)(unsigned long *)lpcmDMAManager->pFree - + AGPBufLinearBase + AGPBufPhysicalBase - 4; + + dwReg60 = INV_SubA_HAGPBstL | INV_HWBasL(dwStart); + dwReg61 = INV_SubA_HAGPBstH | INV_HWBasH(dwStart); + dwReg62 = INV_SubA_HAGPBendL | INV_HWBasL(dwEnd); + dwReg63 = INV_SubA_HAGPBendH | INV_HWBasH(dwEnd); + dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); + dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_STOP; + + /* wait CR idle */ + CR_Status = GetMMIORegister(dev_priv->mmio->handle, INV_RB_ENG_STATUS); + while (CR_Status & INV_ENG_BUSY_CR) + CR_Status = + GetMMIORegister(dev_priv->mmio->handle, + INV_RB_ENG_STATUS); + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg60); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg61); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg62); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg63); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65); + + /* Trigger AGP cycle */ + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + INV_SubA_HFthRCM | INV_HFthRCM_10 | INV_HAGPBTrig); + + if (lpcmDMAManager->pBeg == lpcmDMAManager->addr_linear) { + /* The second AGP command buffer */ + lpcmDMAManager->pBeg = + lpcmDMAManager->addr_linear + + (lpcmDMAManager->DMASize >> 2); + lpcmDMAManager->pEnd = + lpcmDMAManager->addr_linear + lpcmDMAManager->DMASize; + lpcmDMAManager->pFree = lpcmDMAManager->pBeg; + } else { + /* The first AGP command buffer */ + lpcmDMAManager->pBeg = lpcmDMAManager->addr_linear; + lpcmDMAManager->pEnd = + lpcmDMAManager->addr_linear + + (lpcmDMAManager->DMASize / 2) - 1; + lpcmDMAManager->pFree = lpcmDMAManager->pBeg; + } + CR_Status = GetMMIORegister(dev_priv->mmio->handle, INV_RB_ENG_STATUS); +} + + +void +kickoff_dma_ring_inv(struct drm_device *dev) +{ + unsigned int dwPause, dwReg64, dwReg65; + + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + + unsigned int AGPBufLinearBase = + (unsigned int) lpcmDMAManager->addr_linear; + unsigned int AGPBufPhysicalBase = + (dev_priv->chip_agp == + CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base + + lpcmDMAManager->pPhysical; + /*add shadow offset */ + + /* 256-bit alignment of AGP pause address */ + if (dev_priv->chip_sub_index == CHIP_H6S2) { + if ((u32) + ((unsigned long *) lpcmDMAManager->pFree) & 0x7f) { + ADDCmdHeader2_INVI(lpcmDMAManager->pFree, + INV_REG_CR_TRANS, + INV_ParaType_Dummy); + do { + ADDCmdData_INVI(lpcmDMAManager->pFree, + 0xCCCCCCC0); + ADDCmdData_INVI(lpcmDMAManager->pFree, + 0xDDD00000); + } + while ((u32)((unsigned long *) lpcmDMAManager->pFree) & + 0x7f) + ; + } + } else { + if ((u32) + ((unsigned long *) lpcmDMAManager->pFree) & 0x1f) { + ADDCmdHeader2_INVI(lpcmDMAManager->pFree, + INV_REG_CR_TRANS, + INV_ParaType_Dummy); + do { + ADDCmdData_INVI(lpcmDMAManager->pFree, + 0xCCCCCCC0); + ADDCmdData_INVI(lpcmDMAManager->pFree, + 0xDDD00000); + } + while ((u32)((unsigned long *) lpcmDMAManager->pFree) & + 0x1f) + ; + } + } + + + dwPause = (u32) ((unsigned long *) lpcmDMAManager->pFree) + - AGPBufLinearBase + AGPBufPhysicalBase - 16; + + dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); + dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_PAUSE; + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65); + + lpcmDMAManager->pInUseBySW = lpcmDMAManager->pFree; +} + +static int +waitchipidle_inv(struct drm_via_chrome9_private *dev_priv) +{ + unsigned int count = 50000; + unsigned int eng_status; + unsigned int engine_busy; + + do { + eng_status = + GetMMIORegister(dev_priv->mmio->handle, + INV_RB_ENG_STATUS); + engine_busy = eng_status & INV_ENG_BUSY_ALL; + count--; + } + while (engine_busy && count) + ; + if (count && engine_busy == 0) + return 0; + return -1; +} + +void +get_space_db_inv(struct drm_device *dev, + struct cmd_get_space *lpcmGetSpaceData) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + + unsigned int dwRequestSize = lpcmGetSpaceData->dwRequestSize; + if (dwRequestSize > lpcmDMAManager->MaxKickoffSize) { + DRM_INFO("too big DMA buffer request!!!\n"); + via_chrome9ke_assert(0); + *lpcmGetSpaceData->pCmdData = (unsigned int) NULL; + return; + } + + if ((lpcmDMAManager->pFree + dwRequestSize) > + (lpcmDMAManager->pEnd - INV_CMDBUF_THRESHOLD * 2)) + kickoff_dma_db_inv(dev); + + *lpcmGetSpaceData->pCmdData = (unsigned int) lpcmDMAManager->pFree; +} + +void +RewindRingAGP_inv(struct drm_device *dev) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + + unsigned int AGPBufLinearBase = + (unsigned int) lpcmDMAManager->addr_linear; + unsigned int AGPBufPhysicalBase = + (dev_priv->chip_agp == + CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base + + lpcmDMAManager->pPhysical; + /*add shadow offset */ + + unsigned int dwPause, dwJump; + unsigned int dwReg66, dwReg67; + unsigned int dwReg64, dwReg65; + + ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS, + INV_ParaType_Dummy); + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC7); + if (dev_priv->chip_sub_index == CHIP_H6S2) + while ((unsigned int) lpcmDMAManager->pFree & 0x7F) + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC7); + else + while ((unsigned int) lpcmDMAManager->pFree & 0x1F) + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC7); + dwJump = ((u32) ((unsigned long *) lpcmDMAManager->pFree)) + - AGPBufLinearBase + AGPBufPhysicalBase - 16; + + lpcmDMAManager->pFree = lpcmDMAManager->pBeg; + + dwPause = ((u32) ((unsigned long *) lpcmDMAManager->pFree)) + - AGPBufLinearBase + AGPBufPhysicalBase - 16; + + dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); + dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_PAUSE; + + dwReg66 = INV_SubA_HAGPBjumpL | INV_HWBasL(dwJump); + dwReg67 = INV_SubA_HAGPBjumpH | INV_HWBasH(dwJump); + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg66); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg67); + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65); + lpcmDMAManager->pInUseBySW = lpcmDMAManager->pFree; +} + + +void +get_space_ring_inv(struct drm_device *dev, + struct cmd_get_space *lpcmGetSpaceData) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + unsigned int dwUnFlushed; + unsigned int dwRequestSize = lpcmGetSpaceData->dwRequestSize; + + unsigned int AGPBufLinearBase = + (unsigned int) lpcmDMAManager->addr_linear; + unsigned int AGPBufPhysicalBase = + (dev_priv->chip_agp == + CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base + + lpcmDMAManager->pPhysical; + /*add shadow offset */ + u32 BufStart, BufEnd, CurSW, CurHW, NextSW, BoundaryCheck; + + dwUnFlushed = + (unsigned int) (lpcmDMAManager->pFree - lpcmDMAManager->pBeg); + /*default bEnableModuleSwitch is on for metro,is off for rest */ + /*cmHW_Module_Switch is context-wide variable which is enough for 2d/3d + switch in a context. */ + /*But we must keep the dma buffer being wrapped head and tail by 3d cmds + when it is kicked off to kernel mode. */ + /*Get DMA Space (If requested, or no BCI space and BCI not forced. */ + + if (dwRequestSize > lpcmDMAManager->MaxKickoffSize) { + DRM_INFO("too big DMA buffer request!!!\n"); + via_chrome9ke_assert(0); + *lpcmGetSpaceData->pCmdData = 0; + return; + } + + if (dwUnFlushed + dwRequestSize > lpcmDMAManager->MaxKickoffSize) + kickoff_dma_ring_inv(dev); + + BufStart = + (u32)((unsigned int) lpcmDMAManager->pBeg) - AGPBufLinearBase + + AGPBufPhysicalBase; + BufEnd = (u32)((unsigned int) lpcmDMAManager->pEnd) - AGPBufLinearBase + + AGPBufPhysicalBase; + dwRequestSize = lpcmGetSpaceData->dwRequestSize << 2; + NextSW = (u32) ((unsigned int) lpcmDMAManager->pFree) + dwRequestSize + + INV_CMDBUF_THRESHOLD * 8 - AGPBufLinearBase + + AGPBufPhysicalBase; + + CurSW = (u32)((unsigned int) lpcmDMAManager->pFree) - AGPBufLinearBase + + AGPBufPhysicalBase; + CurHW = GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_CURRADDR); + + if (NextSW >= BufEnd) { + kickoff_dma_ring_inv(dev); + CurSW = (u32) ((unsigned int) lpcmDMAManager->pFree) - + AGPBufLinearBase + AGPBufPhysicalBase; + /* make sure the last rewind is completed */ + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + while (CurHW > CurSW) + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + /* Sometime the value read from HW is unreliable, + so need double confirm. */ + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + while (CurHW > CurSW) + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + BoundaryCheck = + BufStart + dwRequestSize + INV_QW_PAUSE_ALIGN * 16; + if (BoundaryCheck >= BufEnd) + /* If an empty command buffer can't hold + the request data. */ + via_chrome9ke_assert(0); + else { + /* We need to guarntee the new commands have no chance + to override the unexected commands or wait until there + is no unexecuted commands in agp buffer */ + if (CurSW <= BoundaryCheck) { + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + while (CurHW < CurSW) + CurHW = GetMMIORegister( + dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + /*Sometime the value read from HW is unreliable, + so need double confirm. */ + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + while (CurHW < CurSW) { + CurHW = GetMMIORegister( + dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + } + RewindRingAGP_inv(dev); + CurSW = (u32) ((unsigned long *) + lpcmDMAManager->pFree) - + AGPBufLinearBase + AGPBufPhysicalBase; + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + /* Waiting until hw pointer jump to start + and hw pointer will */ + /* equal to sw pointer */ + while (CurHW != CurSW) { + CurHW = GetMMIORegister( + dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + } + } else { + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + + while (CurHW <= BoundaryCheck) { + CurHW = GetMMIORegister( + dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + } + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + /* Sometime the value read from HW is + unreliable, so need double confirm. */ + while (CurHW <= BoundaryCheck) { + CurHW = GetMMIORegister( + dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + } + RewindRingAGP_inv(dev); + } + } + } else { + /* no need to rewind Ensure unexecuted agp commands will + not be override by new + agp commands */ + CurSW = (u32) ((unsigned int) lpcmDMAManager->pFree) - + AGPBufLinearBase + AGPBufPhysicalBase; + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + + while ((CurHW > CurSW) && (CurHW <= NextSW)) + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + + /* Sometime the value read from HW is unreliable, + so need double confirm. */ + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + while ((CurHW > CurSW) && (CurHW <= NextSW)) + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + } + /*return the space handle */ + *lpcmGetSpaceData->pCmdData = (unsigned int) lpcmDMAManager->pFree; +} + +void +release_space_inv(struct drm_device *dev, + struct cmd_release_space *lpcmReleaseSpaceData) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + unsigned int dwReleaseSize = lpcmReleaseSpaceData->dwReleaseSize; + int i = 0; + + lpcmDMAManager->pFree += dwReleaseSize; + + /* aligned address */ + while (((unsigned int) lpcmDMAManager->pFree) & 0xF) { + /* not in 4 unsigned ints (16 Bytes) align address, + insert NULL Commands */ + *lpcmDMAManager->pFree++ = NULL_COMMAND_INV[i & 0x3]; + i++; + } + + if ((dev_priv->chip_sub_index == CHIP_H5) + && (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER)) { + ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS, + INV_ParaType_Dummy); + for (i = 0; i < NULLCOMMANDNUMBER; i++) + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCC000000); + } +} + +int +via_chrome9_ioctl_flush(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_via_chrome9_flush *dma_info = data; + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + int ret = 0; + int result = 0; + struct cmd_get_space getspace; + struct cmd_release_space releasespace; + volatile unsigned long *pCmdData = NULL; + + switch (dma_info->dma_cmd_type) { + /* Copy DMA buffer to BCI command buffer */ + case flush_bci: + case flush_bci_and_wait: + if (dma_info->cmd_size <= 0) + return 0; + if (dma_info->cmd_size > MAX_BCI_BUFFER_SIZE) { + DRM_INFO("too big BCI space request!!!\n"); + return 0; + } + + kickoff_bci_inv(dev_priv, dma_info); + waitchipidle_inv(dev_priv); + break; + /* Use DRM DMA buffer manager to kick off DMA directly */ + case dma_kickoff: + break; + + /* Copy user mode DMA buffer to kernel DMA buffer, + then kick off DMA */ + case flush_dma_buffer: + case flush_dma_and_wait: + if (dma_info->cmd_size <= 0) + return 0; + + getspace.dwRequestSize = dma_info->cmd_size; + if ((dev_priv->chip_sub_index == CHIP_H5) + && (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER)) + getspace.dwRequestSize += (NULLCOMMANDNUMBER + 4); + /*henry:Patch for VT3293 agp ring buffer stability */ + getspace.pCmdData = (unsigned int *) &pCmdData; + + if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) + get_space_db_inv(dev, &getspace); + else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) + get_space_ring_inv(dev, &getspace); + + if (pCmdData) { + /*copy data from userspace to kernel-dma-agp buffer */ + result = copy_from_user((int *) + pCmdData, + dma_info->usermode_dma_buf, + dma_info->cmd_size << 2); + releasespace.dwReleaseSize = dma_info->cmd_size; + release_space_inv(dev, &releasespace); + + if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) + kickoff_dma_db_inv(dev); + else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) + kickoff_dma_ring_inv(dev); + + if (dma_info->dma_cmd_type == flush_dma_and_wait) + waitchipidle_inv(dev_priv); + } else { + DRM_INFO("No enough DMA space"); + ret = -ENOMEM; + } + break; + + default: + DRM_INFO("Invalid DMA buffer type"); + ret = -EINVAL; + break; + } + return ret; +} + +int +via_chrome9_ioctl_free(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} + +int +via_chrome9_ioctl_wait_chip_idle(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + + waitchipidle_inv(dev_priv); + /* maybe_bug here, do we always return 0 */ + return 0; +} + +int +via_chrome9_ioctl_flush_cache(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} --- linux-2.6.24.orig/drivers/char/drm/via_chrome9_drm.h +++ linux-2.6.24/drivers/char/drm/via_chrome9_drm.h @@ -0,0 +1,423 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _VIA_CHROME9_DRM_H_ +#define _VIA_CHROME9_DRM_H_ + +/* WARNING: These defines must be the same as what the Xserver uses. + * if you change them, you must change the defines in the Xserver. + */ + +#ifndef _VIA_CHROME9_DEFINES_ +#define _VIA_CHROME9_DEFINES_ + +#ifndef __KERNEL__ +#include "via_drmclient.h" +#endif + +#define VIA_CHROME9_NR_SAREA_CLIPRECTS 8 +#define VIA_CHROME9_NR_XVMC_PORTS 10 +#define VIA_CHROME9_NR_XVMC_LOCKS 5 +#define VIA_CHROME9_MAX_CACHELINE_SIZE 64 +#define XVMCLOCKPTR(saPriv,lockNo) \ + ((volatile struct drm_hw_lock *) \ + (((((unsigned long) (saPriv)->XvMCLockArea) + \ + (VIA_CHROME9_MAX_CACHELINE_SIZE - 1)) & \ + ~(VIA_CHROME9_MAX_CACHELINE_SIZE - 1)) + \ + VIA_CHROME9_MAX_CACHELINE_SIZE*(lockNo))) + +/* Each region is a minimum of 64k, and there are at most 64 of them. + */ +#define VIA_CHROME9_NR_TEX_REGIONS 64 +#define VIA_CHROME9_LOG_MIN_TEX_REGION_SIZE 16 +#endif + +#define VIA_CHROME9_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */ +#define VIA_CHROME9_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */ +#define VIA_CHROME9_UPLOAD_CTX 0x4 +#define VIA_CHROME9_UPLOAD_BUFFERS 0x8 +#define VIA_CHROME9_UPLOAD_TEX0 0x10 +#define VIA_CHROME9_UPLOAD_TEX1 0x20 +#define VIA_CHROME9_UPLOAD_CLIPRECTS 0x40 +#define VIA_CHROME9_UPLOAD_ALL 0xff + +/* VIA_CHROME9 specific ioctls */ +#define DRM_VIA_CHROME9_ALLOCMEM 0x00 +#define DRM_VIA_CHROME9_FREEMEM 0x01 +#define DRM_VIA_CHROME9_FREE 0x02 +#define DRM_VIA_CHROME9_ALLOCATE_EVENT_TAG 0x03 +#define DRM_VIA_CHROME9_FREE_EVENT_TAG 0x04 +#define DRM_VIA_CHROME9_ALLOCATE_APERTURE 0x05 +#define DRM_VIA_CHROME9_FREE_APERTURE 0x06 +#define DRM_VIA_CHROME9_ALLOCATE_VIDEO_MEM 0x07 +#define DRM_VIA_CHROME9_FREE_VIDEO_MEM 0x08 +#define DRM_VIA_CHROME9_WAIT_CHIP_IDLE 0x09 +#define DRM_VIA_CHROME9_PROCESS_EXIT 0x0A +#define DRM_VIA_CHROME9_RESTORE_PRIMARY 0x0B +#define DRM_VIA_CHROME9_FLUSH_CACHE 0x0C +#define DRM_VIA_CHROME9_INIT 0x0D +#define DRM_VIA_CHROME9_FLUSH 0x0E +#define DRM_VIA_CHROME9_CHECKVIDMEMSIZE 0x0F +#define DRM_VIA_CHROME9_PCIEMEMCTRL 0x10 +#define DRM_VIA_CHROME9_AUTH_MAGIC 0x11 + +#define DRM_IOCTL_VIA_CHROME9_INIT \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_INIT, \ + struct drm_via_chrome9_init) +#define DRM_IOCTL_VIA_CHROME9_FLUSH \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FLUSH, \ + struct drm_via_chrome9_flush) +#define DRM_IOCTL_VIA_CHROME9_FREE \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREE, int) +#define DRM_IOCTL_VIA_CHROME9_ALLOCATE_EVENT_TAG \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_ALLOCATE_EVENT_TAG, \ + struct drm_event_via_chrome9_tag) +#define DRM_IOCTL_VIA_CHROME9_FREE_EVENT_TAG \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREE_EVENT_TAG, \ + struct drm_event_via_chrome9_tag) +#define DRM_IOCTL_VIA_CHROME9_ALLOCATE_APERTURE \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_ALLOCATE_APERTURE, \ + struct drm_via_chrome9_aperture) +#define DRM_IOCTL_VIA_CHROME9_FREE_APERTURE \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREE_APERTURE, \ + struct drm_via_chrome9_aperture) +#define DRM_IOCTL_VIA_CHROME9_ALLOCATE_VIDEO_MEM \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_ALLOCATE_VIDEO_MEM, \ + struct drm_via_chrome9_memory_alloc) +#define DRM_IOCTL_VIA_CHROME9_FREE_VIDEO_MEM \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREE_VIDEO_MEM, \ + struct drm_via_chrome9_memory_alloc) +#define DRM_IOCTL_VIA_CHROME9_WAIT_CHIP_IDLE \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_WAIT_CHIP_IDLE, int) +#define DRM_IOCTL_VIA_CHROME9_PROCESS_EXIT \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_PROCESS_EXIT, int) +#define DRM_IOCTL_VIA_CHROME9_RESTORE_PRIMARY \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_RESTORE_PRIMARY, int) +#define DRM_IOCTL_VIA_CHROME9_FLUSH_CACHE \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FLUSH_CACHE, int) +#define DRM_IOCTL_VIA_CHROME9_ALLOCMEM \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_ALLOCMEM, int) +#define DRM_IOCTL_VIA_CHROME9_FREEMEM \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREEMEM, int) +#define DRM_IOCTL_VIA_CHROME9_CHECK_VIDMEM_SIZE \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_CHECKVIDMEMSIZE, \ + struct drm_via_chrome9_memory_alloc) +#define DRM_IOCTL_VIA_CHROME9_PCIEMEMCTRL \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_PCIEMEMCTRL,\ + drm_via_chrome9_pciemem_ctrl_t) +#define DRM_IOCTL_VIA_CHROME9_AUTH_MAGIC \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_AUTH_MAGIC, drm_auth_t) + +enum S3GCHIPIDS { + CHIP_UNKNOWN = -1, + CHIP_CMODEL, /*Model for any chip. */ + CHIP_CLB, /*Columbia */ + CHIP_DST, /*Destination */ + CHIP_CSR, /*Castlerock */ + CHIP_INV, /*Innovation (H3) */ + CHIP_H5, /*Innovation (H5) */ + CHIP_H5S1, /*Innovation (H5S1) */ + CHIP_H6S2, /*Innovation (H6S2) */ + CHIP_CMS, /*Columbia MS */ + CHIP_METRO, /*Metropolis */ + CHIP_MANHATTAN, /*manhattan */ + CHIP_MATRIX, /*matrix */ + CHIP_EVO, /*change for GCC 4.1 -add- 07.02.12*/ + CHIP_H6S1, /*Innovation (H6S1)*/ + CHIP_DST2, /*Destination-2 */ + CHIP_LAST /*Maximum number of chips supported. */ +}; + +enum VIA_CHROME9CHIPBUS { + CHIP_PCI, + CHIP_AGP, + CHIP_PCIE +}; + +struct drm_via_chrome9_init { + enum { + VIA_CHROME9_INIT = 0x01, + VIA_CHROME9_CLEANUP = 0x02 + } func; + int chip_agp; + int chip_index; + int chip_sub_index; + int usec_timeout; + unsigned int sarea_priv_offset; + unsigned int fb_cpp; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int mmio_handle; + unsigned int dma_handle; + unsigned int fb_handle; + unsigned int front_handle; + unsigned int back_handle; + unsigned int depth_handle; + + unsigned int fb_tex_offset; + unsigned int fb_tex_size; + + unsigned int agp_tex_size; + unsigned int agp_tex_handle; + unsigned int shadow_size; + unsigned int shadow_handle; + unsigned int garttable_size; + unsigned int garttable_offset; + unsigned long available_fb_size; + unsigned long fb_base_address; + unsigned int DMA_size; + unsigned long DMA_phys_address; + enum { + AGP_RING_BUFFER, + AGP_DOUBLE_BUFFER, + AGP_DISABLED + } agp_type; + unsigned int hostBlt_handle; +}; + +enum dma_cmd_type { + flush_bci = 0, + flush_bci_and_wait, + dma_kickoff, + flush_dma_buffer, + flush_dma_and_wait +}; + +struct drm_via_chrome9_flush { + enum dma_cmd_type dma_cmd_type; + /* command buffer index */ + int cmd_idx; + /* command buffer offset */ + int cmd_offset; + /* command dword size,command always from beginning */ + int cmd_size; + /* if use dma kick off,it is dma kick off command */ + unsigned long dma_kickoff[2]; + /* user mode DMA buffer pointer */ + unsigned int *usermode_dma_buf; +}; + +struct event_value { + int event_low; + int event_high; +}; + +struct drm_via_chrome9_event_tag { + unsigned int event_size; /* event tag size */ + int event_offset; /* event tag id */ + struct event_value last_sent_event_value; + struct event_value current_event_value; + int query_mask0; + int query_mask1; + int query_Id1; +}; + +/* Indices into buf.Setup where various bits of state are mirrored per + * context and per buffer. These can be fired at the card as a unit, + * or in a piecewise fashion as required. + */ + +#define VIA_CHROME9_TEX_SETUP_SIZE 8 + +/* Flags for clear ioctl + */ +#define VIA_CHROME9_FRONT 0x1 +#define VIA_CHROME9_BACK 0x2 +#define VIA_CHROME9_DEPTH 0x4 +#define VIA_CHROME9_STENCIL 0x8 +#define VIA_CHROME9_MEM_VIDEO 0 /* matches drm constant */ +#define VIA_CHROME9_MEM_AGP 1 /* matches drm constant */ +#define VIA_CHROME9_MEM_SYSTEM 2 +#define VIA_CHROME9_MEM_MIXED 3 +#define VIA_CHROME9_MEM_UNKNOWN 4 + +struct drm_via_chrome9_agp { + uint32_t offset; + uint32_t size; +}; + +struct drm_via_chrome9_fb { + uint32_t offset; + uint32_t size; +}; + +struct drm_via_chrome9_mem { + uint32_t context; + uint32_t type; + uint32_t size; + unsigned long index; + unsigned long offset; +}; + +struct drm_via_chrome9_aperture { + /*IN: The frame buffer offset of the surface. */ + int surface_offset; + /*IN: Surface pitch in byte, */ + int pitch; + /*IN: Surface width in pixel */ + int width; + /*IN: Surface height in pixel */ + int height; + /*IN: Surface color format, Columbia has more color formats */ + int color_format; + /*IN: Rotation degrees, only for Columbia */ + int rotation_degree; + /*IN Is the PCIE Video, for MATRIX support NONLOCAL Aperture */ + int isPCIEVIDEO; + /*IN: Is the surface tilled, only for Columbia */ + int is_tiled; + /*IN: Only allocate apertur, not hardware setup. */ + int allocate_only; + /* OUT: linear address for aperture */ + unsigned int *aperture_linear_address; + /*OUT: The pitch of the aperture,for CPU write not for GE */ + int aperture_pitch; + /*OUT: The index of the aperture */ + int aperture_handle; + int apertureID; + /* always =0xAAAAAAAA */ + /* Aligned surface's width(in pixel) */ + int width_aligned; + /* Aligned surface's height(in pixel) */ + int height_aligned; +}; + +/* + Some fileds of this data structure has no meaning now since + we have managed heap based on mechanism provided by DRM + Remain what it was to keep consistent with 3D driver interface. +*/ +struct drm_via_chrome9_memory_alloc { + enum { + memory_heap_video = 0, + memory_heap_agp, + memory_heap_pcie_video, + memory_heap_pcie, + max_memory_heaps + } heap_type; + struct { + void *lpL1Node; + unsigned int alcL1Tag; + unsigned int usageCount; + unsigned int dwVersion; + unsigned int dwResHandle; + unsigned int dwProcessID; + } heap_info; + unsigned int flags; + unsigned int size; + unsigned int physaddress; + unsigned int offset; + unsigned int align; + void *linearaddress; +}; + +struct drm_via_chrome9_dma_init { + enum { + VIA_CHROME9_INIT_DMA = 0x01, + VIA_CHROME9_CLEANUP_DMA = 0x02, + VIA_CHROME9_DMA_INITIALIZED = 0x03 + } func; + + unsigned long offset; + unsigned long size; + unsigned long reg_pause_addr; +}; + +struct drm_via_chrome9_cmdbuffer { + char __user *buf; + unsigned long size; +}; + +/* Warning: If you change the SAREA structure you must change the Xserver + * structure as well */ + +struct drm_via_chrome9_tex_region { + unsigned char next, prev; /* indices to form a circular LRU */ + unsigned char inUse; /* owned by a client, or free? */ + int age; /* tracked by clients to update local LRU's */ +}; + +struct drm_via_chrome9_sarea { + int page_flip; + int current_page; + unsigned int req_drawable;/* the X drawable id */ + unsigned int req_draw_buffer;/* VIA_CHROME9_FRONT or VIA_CHROME9_BACK */ + /* Last context that uploaded state */ + int ctx_owner; +}; + +struct drm_via_chrome9_cmdbuf_size { + enum { + VIA_CHROME9_CMDBUF_SPACE = 0x01, + VIA_CHROME9_CMDBUF_LAG = 0x02 + } func; + int wait; + uint32_t size; +}; + +struct drm_via_chrome9_DMA_manager { + unsigned int *addr_linear; + unsigned int DMASize; + unsigned int bDMAAgp; + unsigned int LastIssuedEventTag; + unsigned int *pBeg; + unsigned int *pInUseByHW; + unsigned int **ppInUseByHW; + unsigned int *pInUseBySW; + unsigned int *pFree; + unsigned int *pEnd; + + unsigned long pPhysical; + unsigned int MaxKickoffSize; +}; + +extern int via_chrome9_ioctl_wait_chip_idle(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_init(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_allocate_event_tag(struct drm_device + *dev, void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_free_event_tag(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_driver_load(struct drm_device *dev, + unsigned long chipset); +extern int via_chrome9_driver_unload(struct drm_device *dev); +extern int via_chrome9_ioctl_process_exit(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_restore_primary(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_drm_resume(struct pci_dev *dev); +extern int via_chrome9_drm_suspend(struct pci_dev *dev, + pm_message_t state); +extern void __via_chrome9ke_udelay(unsigned long usecs); +extern void via_chrome9_lastclose(struct drm_device *dev); +extern void via_chrome9_preclose(struct drm_device *dev, + struct drm_file *file_priv); +extern int via_chrome9_is_agp(struct drm_device *dev); + + +#endif /* _VIA_CHROME9_DRM_H_ */ --- linux-2.6.24.orig/drivers/char/drm/drm_bufs.c +++ linux-2.6.24/drivers/char/drm/drm_bufs.c @@ -429,6 +429,7 @@ return ret; } +EXPORT_SYMBOL(drm_rmmap); /* The rmmap ioctl appears to be unnecessary. All mappings are torn down on * the last close of the device, and this is necessary for cleanup when things --- linux-2.6.24.orig/drivers/char/drm/drm_fops.c +++ linux-2.6.24/drivers/char/drm/drm_fops.c @@ -326,6 +326,7 @@ struct drm_file *file_priv = filp->private_data; struct drm_device *dev = file_priv->head->dev; int retcode = 0; + unsigned long irqflags; lock_kernel(); @@ -357,9 +358,11 @@ */ do{ - spin_lock(&dev->lock.spinlock); + spin_lock_irqsave(&dev->lock.spinlock, + irqflags); locked = dev->lock.idle_has_lock; - spin_unlock(&dev->lock.spinlock); + spin_unlock_irqrestore(&dev->lock.spinlock, + irqflags); if (locked) break; schedule(); --- linux-2.6.24.orig/drivers/char/drm/i915_drv.c +++ linux-2.6.24/drivers/char/drm/i915_drv.c @@ -38,6 +38,495 @@ i915_PCI_IDS }; +enum pipe { + PIPE_A = 0, + PIPE_B, +}; + +static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (pipe == PIPE_A) + return (I915_READ(DPLL_A) & DPLL_VCO_ENABLE); + else + return (I915_READ(DPLL_B) & DPLL_VCO_ENABLE); +} + +static void i915_save_palette(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B); + u32 *array; + int i; + + if (!i915_pipe_enabled(dev, pipe)) + return; + + if (pipe == PIPE_A) + array = dev_priv->save_palette_a; + else + array = dev_priv->save_palette_b; + + for(i = 0; i < 256; i++) + array[i] = I915_READ(reg + (i << 2)); +} + +static void i915_restore_palette(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B); + u32 *array; + int i; + + if (!i915_pipe_enabled(dev, pipe)) + return; + + if (pipe == PIPE_A) + array = dev_priv->save_palette_a; + else + array = dev_priv->save_palette_b; + + for(i = 0; i < 256; i++) + I915_WRITE(reg + (i << 2), array[i]); +} + +static u8 i915_read_indexed(u16 index_port, u16 data_port, u8 reg) +{ + outb(reg, index_port); + return inb(data_port); +} + +static u8 i915_read_ar(u16 st01, u8 reg, u16 palette_enable) +{ + inb(st01); + outb(palette_enable | reg, VGA_AR_INDEX); + return inb(VGA_AR_DATA_READ); +} + +static void i915_write_ar(u8 st01, u8 reg, u8 val, u16 palette_enable) +{ + inb(st01); + outb(palette_enable | reg, VGA_AR_INDEX); + outb(val, VGA_AR_DATA_WRITE); +} + +static void i915_write_indexed(u16 index_port, u16 data_port, u8 reg, u8 val) +{ + outb(reg, index_port); + outb(val, data_port); +} + +static void i915_save_vga(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + u16 cr_index, cr_data, st01; + + /* VGA color palette registers */ + dev_priv->saveDACMASK = inb(VGA_DACMASK); + /* DACCRX automatically increments during read */ + outb(0, VGA_DACRX); + /* Read 3 bytes of color data from each index */ + for (i = 0; i < 256 * 3; i++) + dev_priv->saveDACDATA[i] = inb(VGA_DACDATA); + + /* MSR bits */ + dev_priv->saveMSR = inb(VGA_MSR_READ); + if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) { + cr_index = VGA_CR_INDEX_CGA; + cr_data = VGA_CR_DATA_CGA; + st01 = VGA_ST01_CGA; + } else { + cr_index = VGA_CR_INDEX_MDA; + cr_data = VGA_CR_DATA_MDA; + st01 = VGA_ST01_MDA; + } + + /* CRT controller regs */ + i915_write_indexed(cr_index, cr_data, 0x11, + i915_read_indexed(cr_index, cr_data, 0x11) & + (~0x80)); + for (i = 0; i <= 0x24; i++) + dev_priv->saveCR[i] = + i915_read_indexed(cr_index, cr_data, i); + /* Make sure we don't turn off CR group 0 writes */ + dev_priv->saveCR[0x11] &= ~0x80; + + /* Attribute controller registers */ + inb(st01); + dev_priv->saveAR_INDEX = inb(VGA_AR_INDEX); + for (i = 0; i <= 0x14; i++) + dev_priv->saveAR[i] = i915_read_ar(st01, i, 0); + inb(st01); + outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX); + inb(st01); + + /* Graphics controller registers */ + for (i = 0; i < 9; i++) + dev_priv->saveGR[i] = + i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, i); + + dev_priv->saveGR[0x10] = + i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10); + dev_priv->saveGR[0x11] = + i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11); + dev_priv->saveGR[0x18] = + i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18); + + /* Sequencer registers */ + for (i = 0; i < 8; i++) + dev_priv->saveSR[i] = + i915_read_indexed(VGA_SR_INDEX, VGA_SR_DATA, i); +} + +static void i915_restore_vga(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + u16 cr_index, cr_data, st01; + + /* MSR bits */ + outb(dev_priv->saveMSR, VGA_MSR_WRITE); + if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) { + cr_index = VGA_CR_INDEX_CGA; + cr_data = VGA_CR_DATA_CGA; + st01 = VGA_ST01_CGA; + } else { + cr_index = VGA_CR_INDEX_MDA; + cr_data = VGA_CR_DATA_MDA; + st01 = VGA_ST01_MDA; + } + + /* Sequencer registers, don't write SR07 */ + for (i = 0; i < 7; i++) + i915_write_indexed(VGA_SR_INDEX, VGA_SR_DATA, i, + dev_priv->saveSR[i]); + + /* CRT controller regs */ + /* Enable CR group 0 writes */ + i915_write_indexed(cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]); + for (i = 0; i <= 0x24; i++) + i915_write_indexed(cr_index, cr_data, i, dev_priv->saveCR[i]); + + /* Graphics controller regs */ + for (i = 0; i < 9; i++) + i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, i, + dev_priv->saveGR[i]); + + i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10, + dev_priv->saveGR[0x10]); + i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11, + dev_priv->saveGR[0x11]); + i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18, + dev_priv->saveGR[0x18]); + + /* Attribute controller registers */ + inb(st01); + for (i = 0; i <= 0x14; i++) + i915_write_ar(st01, i, dev_priv->saveAR[i], 0); + inb(st01); /* switch back to index mode */ + outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX); + inb(st01); + + /* VGA color palette registers */ + outb(dev_priv->saveDACMASK, VGA_DACMASK); + /* DACCRX automatically increments during read */ + outb(0, VGA_DACWX); + /* Read 3 bytes of color data from each index */ + for (i = 0; i < 256 * 3; i++) + outb(dev_priv->saveDACDATA[i], VGA_DACDATA); + +} + +static int i915_suspend(struct drm_device *dev, pm_message_t state) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + if (!dev || !dev_priv) { + printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv); + printk(KERN_ERR "DRM not initialized, aborting suspend.\n"); + return -ENODEV; + } + + if (state.event == PM_EVENT_PRETHAW) + return 0; + + pci_save_state(dev->pdev); + pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); + + /* Pipe & plane A info */ + dev_priv->savePIPEACONF = I915_READ(PIPEACONF); + dev_priv->savePIPEASRC = I915_READ(PIPEASRC); + dev_priv->saveFPA0 = I915_READ(FPA0); + dev_priv->saveFPA1 = I915_READ(FPA1); + dev_priv->saveDPLL_A = I915_READ(DPLL_A); + if (IS_I965G(dev)) + dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD); + dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A); + dev_priv->saveHBLANK_A = I915_READ(HBLANK_A); + dev_priv->saveHSYNC_A = I915_READ(HSYNC_A); + dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A); + dev_priv->saveVBLANK_A = I915_READ(VBLANK_A); + dev_priv->saveVSYNC_A = I915_READ(VSYNC_A); + dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A); + + dev_priv->saveDSPACNTR = I915_READ(DSPACNTR); + dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE); + dev_priv->saveDSPASIZE = I915_READ(DSPASIZE); + dev_priv->saveDSPAPOS = I915_READ(DSPAPOS); + dev_priv->saveDSPABASE = I915_READ(DSPABASE); + if (IS_I965G(dev)) { + dev_priv->saveDSPASURF = I915_READ(DSPASURF); + dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF); + } + i915_save_palette(dev, PIPE_A); + dev_priv->savePIPEASTAT = I915_READ(I915REG_PIPEASTAT); + + /* Pipe & plane B info */ + dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); + dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC); + dev_priv->saveFPB0 = I915_READ(FPB0); + dev_priv->saveFPB1 = I915_READ(FPB1); + dev_priv->saveDPLL_B = I915_READ(DPLL_B); + if (IS_I965G(dev)) + dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD); + dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B); + dev_priv->saveHBLANK_B = I915_READ(HBLANK_B); + dev_priv->saveHSYNC_B = I915_READ(HSYNC_B); + dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B); + dev_priv->saveVBLANK_B = I915_READ(VBLANK_B); + dev_priv->saveVSYNC_B = I915_READ(VSYNC_B); + dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A); + + dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR); + dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE); + dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE); + dev_priv->saveDSPBPOS = I915_READ(DSPBPOS); + dev_priv->saveDSPBBASE = I915_READ(DSPBBASE); + if (IS_I965GM(dev) || IS_IGD_GM(dev)) { + dev_priv->saveDSPBSURF = I915_READ(DSPBSURF); + dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); + } + i915_save_palette(dev, PIPE_B); + dev_priv->savePIPEBSTAT = I915_READ(I915REG_PIPEBSTAT); + + /* CRT state */ + dev_priv->saveADPA = I915_READ(ADPA); + + /* LVDS state */ + dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); + dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); + dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); + if (IS_I965G(dev)) + dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); + if (IS_MOBILE(dev) && !IS_I830(dev)) + dev_priv->saveLVDS = I915_READ(LVDS); + if (!IS_I830(dev) && !IS_845G(dev)) + dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL); + dev_priv->saveLVDSPP_ON = I915_READ(LVDSPP_ON); + dev_priv->saveLVDSPP_OFF = I915_READ(LVDSPP_OFF); + dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE); + + /* FIXME: save TV & SDVO state */ + + /* FBC state */ + dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE); + dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE); + dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2); + dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL); + + /* Interrupt state */ + dev_priv->saveIIR = I915_READ(I915REG_INT_IDENTITY_R); + dev_priv->saveIER = I915_READ(I915REG_INT_ENABLE_R); + dev_priv->saveIMR = I915_READ(I915REG_INT_MASK_R); + + /* VGA state */ + dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0); + dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1); + dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV); + dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); + + /* Clock gating state */ + dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D); + + /* Cache mode state */ + dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); + + /* Memory Arbitration state */ + dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); + + /* Scratch space */ + for (i = 0; i < 16; i++) { + dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2)); + dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2)); + } + for (i = 0; i < 3; i++) + dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2)); + + i915_save_vga(dev); + + if (state.event == PM_EVENT_SUSPEND) { + /* Shut down the device */ + pci_disable_device(dev->pdev); + pci_set_power_state(dev->pdev, PCI_D3hot); + } + + return 0; +} + +static int i915_resume(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + pci_set_power_state(dev->pdev, PCI_D0); + pci_restore_state(dev->pdev); + if (pci_enable_device(dev->pdev)) + return -1; + + pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); + + /* Pipe & plane A info */ + /* Prime the clock */ + if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { + I915_WRITE(DPLL_A, dev_priv->saveDPLL_A & + ~DPLL_VCO_ENABLE); + udelay(150); + } + I915_WRITE(FPA0, dev_priv->saveFPA0); + I915_WRITE(FPA1, dev_priv->saveFPA1); + /* Actually enable it */ + I915_WRITE(DPLL_A, dev_priv->saveDPLL_A); + udelay(150); + if (IS_I965G(dev)) + I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); + udelay(150); + + /* Restore mode */ + I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A); + I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A); + I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A); + I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A); + I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A); + I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A); + I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A); + + /* Restore plane info */ + I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE); + I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS); + I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC); + I915_WRITE(DSPABASE, dev_priv->saveDSPABASE); + I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE); + if (IS_I965G(dev)) { + I915_WRITE(DSPASURF, dev_priv->saveDSPASURF); + I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF); + } + + I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); + + i915_restore_palette(dev, PIPE_A); + /* Enable the plane */ + I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR); + I915_WRITE(DSPABASE, I915_READ(DSPABASE)); + + /* Pipe & plane B info */ + if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { + I915_WRITE(DPLL_B, dev_priv->saveDPLL_B & + ~DPLL_VCO_ENABLE); + udelay(150); + } + I915_WRITE(FPB0, dev_priv->saveFPB0); + I915_WRITE(FPB1, dev_priv->saveFPB1); + /* Actually enable it */ + I915_WRITE(DPLL_B, dev_priv->saveDPLL_B); + udelay(150); + if (IS_I965G(dev)) + I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); + udelay(150); + + /* Restore mode */ + I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B); + I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B); + I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B); + I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B); + I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B); + I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B); + I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B); + + /* Restore plane info */ + I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE); + I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS); + I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC); + I915_WRITE(DSPBBASE, dev_priv->saveDSPBBASE); + I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); + if (IS_I965G(dev)) { + I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF); + I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); + } + + I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); + + i915_restore_palette(dev, PIPE_B); + /* Enable the plane */ + I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); + I915_WRITE(DSPBBASE, I915_READ(DSPBBASE)); + + /* CRT state */ + I915_WRITE(ADPA, dev_priv->saveADPA); + + /* LVDS state */ + if (IS_I965G(dev)) + I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2); + if (IS_MOBILE(dev) && !IS_I830(dev)) + I915_WRITE(LVDS, dev_priv->saveLVDS); + if (!IS_I830(dev) && !IS_845G(dev)) + I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL); + + I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS); + I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); + I915_WRITE(LVDSPP_ON, dev_priv->saveLVDSPP_ON); + I915_WRITE(LVDSPP_OFF, dev_priv->saveLVDSPP_OFF); + I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE); + I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); + + /* FIXME: restore TV & SDVO state */ + + /* FBC info */ + I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE); + I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE); + I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2); + I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL); + + /* VGA state */ + I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); + I915_WRITE(VCLK_DIVISOR_VGA0, dev_priv->saveVCLK_DIVISOR_VGA0); + I915_WRITE(VCLK_DIVISOR_VGA1, dev_priv->saveVCLK_DIVISOR_VGA1); + I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV); + udelay(150); + + /* Clock gating state */ + I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D); + + /* Cache mode state */ + I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); + + /* Memory arbitration state */ + I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000); + + for (i = 0; i < 16; i++) { + I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]); + I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]); + } + for (i = 0; i < 3; i++) + I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]); + + i915_restore_vga(dev); + + return 0; +} + static struct drm_driver driver = { /* don't use mtrr's here, the Xserver or user space app should * deal with them for intel hardware. @@ -47,8 +536,11 @@ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2, .load = i915_driver_load, + .unload = i915_driver_unload, .lastclose = i915_driver_lastclose, .preclose = i915_driver_preclose, + .suspend = i915_suspend, + .resume = i915_resume, .device_is_agp = i915_driver_device_is_agp, .vblank_wait = i915_driver_vblank_wait, .vblank_wait2 = i915_driver_vblank_wait2, --- linux-2.6.24.orig/drivers/char/drm/drm_stub.c +++ linux-2.6.24/drivers/char/drm/drm_stub.c @@ -168,11 +168,10 @@ goto err_g1; } - head->dev_class = drm_sysfs_device_add(drm_class, head); - if (IS_ERR(head->dev_class)) { + ret = drm_sysfs_device_add(dev, head); + if (ret) { printk(KERN_ERR "DRM: Error sysfs_device_add.\n"); - ret = PTR_ERR(head->dev_class); goto err_g2; } *heads = head; @@ -284,7 +283,7 @@ DRM_DEBUG("release secondary minor %d\n", minor); drm_proc_cleanup(minor, drm_proc_root, head->dev_root); - drm_sysfs_device_remove(head->dev_class); + drm_sysfs_device_remove(head->dev); *head = (struct drm_head) {.dev = NULL}; --- linux-2.6.24.orig/drivers/char/drm/i915_dma.c +++ linux-2.6.24/drivers/char/drm/i915_dma.c @@ -31,17 +31,6 @@ #include "i915_drm.h" #include "i915_drv.h" -#define IS_I965G(dev) (dev->pci_device == 0x2972 || \ - dev->pci_device == 0x2982 || \ - dev->pci_device == 0x2992 || \ - dev->pci_device == 0x29A2 || \ - dev->pci_device == 0x2A02 || \ - dev->pci_device == 0x2A12) - -#define IS_G33(dev) (dev->pci_device == 0x29b2 || \ - dev->pci_device == 0x29c2 || \ - dev->pci_device == 0x29d2) - /* Really want an OS-independent resettable timer. Would like to have * this loop run for (eg) 3 sec, but have the timer reset every time * the head pointer changes, so that EBUSY only happens if the ring @@ -90,6 +79,7 @@ static int i915_dma_cleanup(struct drm_device * dev) { + drm_i915_private_t *dev_priv = dev->dev_private; /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. @@ -97,52 +87,42 @@ if (dev->irq) drm_irq_uninstall(dev); - if (dev->dev_private) { - drm_i915_private_t *dev_priv = - (drm_i915_private_t *) dev->dev_private; - - if (dev_priv->ring.virtual_start) { - drm_core_ioremapfree(&dev_priv->ring.map, dev); - } - - if (dev_priv->status_page_dmah) { - drm_pci_free(dev, dev_priv->status_page_dmah); - /* Need to rewrite hardware status page */ - I915_WRITE(0x02080, 0x1ffff000); - } - - if (dev_priv->status_gfx_addr) { - dev_priv->status_gfx_addr = 0; - drm_core_ioremapfree(&dev_priv->hws_map, dev); - I915_WRITE(0x2080, 0x1ffff000); - } + if (dev_priv->ring.virtual_start) { + drm_core_ioremapfree(&dev_priv->ring.map, dev); + dev_priv->ring.virtual_start = 0; + dev_priv->ring.map.handle = 0; + dev_priv->ring.map.size = 0; + } - drm_free(dev->dev_private, sizeof(drm_i915_private_t), - DRM_MEM_DRIVER); + if (dev_priv->status_page_dmah) { + drm_pci_free(dev, dev_priv->status_page_dmah); + dev_priv->status_page_dmah = NULL; + /* Need to rewrite hardware status page */ + I915_WRITE(0x02080, 0x1ffff000); + } - dev->dev_private = NULL; + if (dev_priv->status_gfx_addr) { + dev_priv->status_gfx_addr = 0; + drm_core_ioremapfree(&dev_priv->hws_map, dev); + I915_WRITE(0x2080, 0x1ffff000); } return 0; } -static int i915_initialize(struct drm_device * dev, - drm_i915_private_t * dev_priv, - drm_i915_init_t * init) +static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) { - memset(dev_priv, 0, sizeof(drm_i915_private_t)); + drm_i915_private_t *dev_priv = dev->dev_private; dev_priv->sarea = drm_getsarea(dev); if (!dev_priv->sarea) { DRM_ERROR("can not find sarea!\n"); - dev->dev_private = (void *)dev_priv; i915_dma_cleanup(dev); return -EINVAL; } dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); if (!dev_priv->mmio_map) { - dev->dev_private = (void *)dev_priv; i915_dma_cleanup(dev); DRM_ERROR("can not find mmio map!\n"); return -EINVAL; @@ -165,7 +145,6 @@ drm_core_ioremap(&dev_priv->ring.map, dev); if (dev_priv->ring.map.handle == NULL) { - dev->dev_private = (void *)dev_priv; i915_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); @@ -192,12 +171,11 @@ dev_priv->allow_batchbuffer = 1; /* Program Hardware Status Page */ - if (!IS_G33(dev)) { + if (!I915_NEED_GFX_HWS(dev)) { dev_priv->status_page_dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); if (!dev_priv->status_page_dmah) { - dev->dev_private = (void *)dev_priv; i915_dma_cleanup(dev); DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; @@ -209,7 +187,6 @@ I915_WRITE(0x02080, dev_priv->dma_status_page); } DRM_DEBUG("Enabled hardware status page\n"); - dev->dev_private = (void *)dev_priv; return 0; } @@ -254,17 +231,12 @@ static int i915_dma_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv; drm_i915_init_t *init = data; int retcode = 0; switch (init->func) { case I915_INIT_DMA: - dev_priv = drm_alloc(sizeof(drm_i915_private_t), - DRM_MEM_DRIVER); - if (dev_priv == NULL) - return -ENOMEM; - retcode = i915_initialize(dev, dev_priv, init); + retcode = i915_initialize(dev, init); break; case I915_CLEANUP_DMA: retcode = i915_dma_cleanup(dev); @@ -748,6 +720,9 @@ drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_hws_addr_t *hws = data; + if (!I915_NEED_GFX_HWS(dev)) + return -EINVAL; + if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); return -EINVAL; @@ -765,7 +740,6 @@ drm_core_ioremap(&dev_priv->hws_map, dev); if (dev_priv->hws_map.handle == NULL) { - dev->dev_private = (void *)dev_priv; i915_dma_cleanup(dev); dev_priv->status_gfx_addr = 0; DRM_ERROR("can not ioremap virtual address for" @@ -784,6 +758,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) { + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long base, size; + int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1; + + if (!IS_I9XX(dev)) { + dev->driver->suspend = NULL; + dev->driver->resume = NULL; + } + /* i915 has 4 more counters */ dev->counters += 4; dev->types[6] = _DRM_STAT_IRQ; @@ -791,24 +774,50 @@ dev->types[8] = _DRM_STAT_SECONDARY; dev->types[9] = _DRM_STAT_DMA; + dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); + if (dev_priv == NULL) + return -ENOMEM; + + memset(dev_priv, 0, sizeof(drm_i915_private_t)); + + dev->dev_private = (void *)dev_priv; + + /* Add register map (needed for suspend/resume) */ + base = drm_get_resource_start(dev, mmio_bar); + size = drm_get_resource_len(dev, mmio_bar); + + ret = drm_addmap(dev, base, size, _DRM_REGISTERS, _DRM_KERNEL, + &dev_priv->mmio_map); + return ret; +} + +int i915_driver_unload(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->mmio_map) + drm_rmmap(dev, dev_priv->mmio_map); + + drm_free(dev->dev_private, sizeof(drm_i915_private_t), + DRM_MEM_DRIVER); + return 0; } void i915_driver_lastclose(struct drm_device * dev) { - if (dev->dev_private) { - drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_private_t *dev_priv = dev->dev_private; + + if (dev_priv->agp_heap) i915_mem_takedown(&(dev_priv->agp_heap)); - } + i915_dma_cleanup(dev); } void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) { - if (dev->dev_private) { - drm_i915_private_t *dev_priv = dev->dev_private; - i915_mem_release(dev, file_priv, dev_priv->agp_heap); - } + drm_i915_private_t *dev_priv = dev->dev_private; + i915_mem_release(dev, file_priv, dev_priv->agp_heap); } struct drm_ioctl_desc i915_ioctls[] = { @@ -828,7 +837,7 @@ DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ), DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); --- linux-2.6.24.orig/drivers/char/drm/r128_drv.h +++ linux-2.6.24/drivers/char/drm/r128_drv.h @@ -418,6 +418,14 @@ * Misc helper macros */ +#define DEV_INIT_TEST_WITH_RETURN(_dev_priv) \ +do { \ + if (!_dev_priv) { \ + DRM_ERROR("called with no initialization\n"); \ + return -EINVAL; \ + } \ +} while (0) + #define RING_SPACE_TEST_WITH_RETURN( dev_priv ) \ do { \ drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i; \ --- linux-2.6.24.orig/drivers/char/drm/via_chrome9_drv.h +++ linux-2.6.24/drivers/char/drm/via_chrome9_drv.h @@ -0,0 +1,145 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _VIA_CHROME9_DRV_H_ +#define _VIA_CHROME9_DRV_H_ + +#include "drm_sman.h" +#define DRIVER_AUTHOR "Various" + +#define DRIVER_NAME "via_chrome9_chrome9" +#define DRIVER_DESC "VIA_CHROME9 Unichrome / Pro" +#define DRIVER_DATE "20080415" + +#define DRIVER_MAJOR 2 +#define DRIVER_MINOR 11 +#define DRIVER_PATCHLEVEL 1 + +#define via_chrome9_PCI_BUF_SIZE 60000 +#define via_chrome9_FIRE_BUF_SIZE 1024 +#define via_chrome9_NUM_IRQS 4 + +#define MAX_MEMORY_HEAPS 4 +#define NUMBER_OF_APERTURES 32 + +/*typedef struct drm_via_chrome9_shadow_map drm_via_chrome9_shadow_map_t;*/ +struct drm_via_chrome9_shadow_map { + struct drm_map *shadow; + unsigned int shadow_size; + unsigned int *shadow_handle; +}; + +/*typedef struct drm_via_chrome9_pagetable_map + *drm_via_chrome9_pagetable_map_t; + */ +struct drm_via_chrome9_pagetable_map { + unsigned int pagetable_offset; + unsigned int pagetable_size; + unsigned int *pagetable_handle; + unsigned int mmt_register; +}; + +/*typedef struct drm_via_chrome9_private drm_via_chrome9_private_t;*/ +struct drm_via_chrome9_private { + int chip_agp; + int chip_index; + int chip_sub_index; + + unsigned long front_offset; + unsigned long back_offset; + unsigned long depth_offset; + unsigned long fb_base_address; + unsigned long available_fb_size; + int usec_timeout; + int max_apertures; + struct drm_sman sman; + unsigned int alignment; + /* bit[31]:0:indicate no alignment needed,1:indicate + alignment needed and size is bit[0:30]*/ + + struct drm_map *sarea; + struct drm_via_chrome9_sarea *sarea_priv; + + struct drm_map *mmio; + struct drm_map *hostBlt; + struct drm_map *fb; + struct drm_map *front; + struct drm_map *back; + struct drm_map *depth; + struct drm_map *agp_tex; + unsigned int agp_size; + unsigned int agp_offset; + + struct semaphore *drm_s3g_sem; + + struct drm_via_chrome9_shadow_map shadow_map; + struct drm_via_chrome9_pagetable_map pagetable_map; + + char *bci; + + int aperture_usage[NUMBER_OF_APERTURES]; + void *event_tag_info; + + /* DMA buffer manager */ + void *dma_manager; + /* Indicate agp/pcie heap initialization flag */ + int agp_initialized; + /* Indicate video heap initialization flag */ + int vram_initialized; + + unsigned long pcie_vmalloc_addr; + + /* pointer to device information */ + void *dev; + /* if agp init fail, go ahead and force dri use PCI*/ + enum { + DRM_AGP_RING_BUFFER, + DRM_AGP_DOUBLE_BUFFER, + DRM_AGP_DISABLED + } drm_agp_type; + /*end*/ + + unsigned long *bci_buffer; + unsigned long pcie_vmalloc_nocache; +}; + + +enum via_chrome9_family { + VIA_CHROME9_OTHER = 0, /* Baseline */ + VIA_CHROME9_PRO_GROUP_A,/* Another video engine and DMA commands */ + VIA_CHROME9_DX9_0, + VIA_CHROME9_PCIE_GROUP +}; + +/* VIA_CHROME9 MMIO register access */ +#define VIA_CHROME9_BASE ((dev_priv->mmio)) + +#define VIA_CHROME9_READ(reg) DRM_READ32(VIA_CHROME9_BASE, reg) +#define VIA_CHROME9_WRITE(reg, val) DRM_WRITE32(VIA_CHROME9_BASE, reg, val) +#define VIA_CHROME9_READ8(reg) DRM_READ8(VIA_CHROME9_BASE, reg) +#define VIA_CHROME9_WRITE8(reg, val) DRM_WRITE8(VIA_CHROME9_BASE, reg, val) + +#endif --- linux-2.6.24.orig/drivers/char/drm/via_chrome9_drm.c +++ linux-2.6.24/drivers/char/drm/via_chrome9_drm.c @@ -0,0 +1,993 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "drmP.h" +#include "via_chrome9_drm.h" +#include "via_chrome9_drv.h" +#include "via_chrome9_mm.h" +#include "via_chrome9_dma.h" +#include "via_chrome9_3d_reg.h" + +#define VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT 10 + + +void __via_chrome9ke_udelay(unsigned long usecs) +{ + unsigned long start; + unsigned long stop; + unsigned long period; + unsigned long wait_period; + struct timespec tval; + +#ifdef NDELAY_LIMIT +#define UDELAY_LIMIT (NDELAY_LIMIT/1000) /* supposed to be 10 msec */ +#else +#define UDELAY_LIMIT (10000) /* 10 msec */ +#endif + + if (usecs > UDELAY_LIMIT) { + start = jiffies; + tval.tv_sec = usecs / 1000000; + tval.tv_nsec = (usecs - tval.tv_sec * 1000000) * 1000; + wait_period = timespec_to_jiffies(&tval); + do { + stop = jiffies; + + if (stop < start) + period = ((unsigned long)-1 - start) + stop + 1; + else + period = stop - start; + + } while (period < wait_period); + } else + udelay(usecs); /* delay value might get checked once again */ +} + +int via_chrome9_ioctl_process_exit(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} + +int via_chrome9_ioctl_restore_primary(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + return 0; +} + +void Initialize3DEngine(struct drm_via_chrome9_private *dev_priv) +{ + int i; + unsigned int StageOfTexture; + + if (dev_priv->chip_sub_index == CHIP_H5 || + dev_priv->chip_sub_index == CHIP_H5S1) { + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + 0x00010000); + + for (i = 0; i <= 0x8A; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (unsigned int) i << 24); + } + + /* Initial Texture Stage Setting*/ + for (StageOfTexture = 0; StageOfTexture < 0xf; + StageOfTexture++) { + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00020000 | 0x00000000 | + (StageOfTexture & 0xf)<<24)); + /* *((unsigned int volatile*)(pMapIOPort+HC_REG_TRANS_SET)) = + (0x00020000 | HC_ParaSubType_Tex0 | (StageOfTexture & + 0xf)<<24);*/ + for (i = 0 ; i <= 0x30 ; i++) { + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_Hpara0)) = ((unsigned int) i << 24);*/ + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (unsigned int) i << 24); + } + } + + /* Initial Texture Sampler Setting*/ + for (StageOfTexture = 0; StageOfTexture < 0xf; + StageOfTexture++) { + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00020000 | 0x00020000 | + (StageOfTexture & 0xf)<<24)); + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_TRANS_SET)) = (0x00020000 | 0x00020000 | + ( StageOfTexture & 0xf)<<24);*/ + for (i = 0 ; i <= 0x30 ; i++) { + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_Hpara0)) = ((unsigned int) i << 24);*/ + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (unsigned int) i << 24); + } + } + + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00020000 | 0xfe000000)); + /* *((unsigned int volatile*)(pMapIOPort+HC_REG_TRANS_SET)) = + (0x00020000 | HC_ParaSubType_TexGen);*/ + for (i = 0 ; i <= 0x13 ; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (unsigned int) i << 24); + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_Hpara0)) = ((unsigned int) i << 24);*/ + } + + /* Initial Gamma Table Setting*/ + /* Initial Gamma Table Setting*/ + /* 5 + 4 = 9 (12) dwords*/ + /* sRGB texture is not directly support by H3 hardware. + We have to set the deGamma table for texture sampling.*/ + + /* degamma table*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x15000000)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (30 << 20) | (15 << 10) | (5))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((119 << 20) | (81 << 10) | (52))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((283 << 20) | (219 << 10) | (165))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((535 << 20) | (441 << 10) | (357))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((119 << 20) | (884 << 20) | (757 << 10) | + (640))); + + /* gamma table*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x17000000)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (13 << 20) | (13 << 10) | (13))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (26 << 20) | (26 << 10) | (26))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (39 << 20) | (39 << 10) | (39))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((51 << 20) | (51 << 10) | (51))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((71 << 20) | (71 << 10) | (71))); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (87 << 20) | (87 << 10) | (87)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (113 << 20) | (113 << 10) | (113)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (135 << 20) | (135 << 10) | (135)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (170 << 20) | (170 << 10) | (170)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (199 << 20) | (199 << 10) | (199)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (246 << 20) | (246 << 10) | (246)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (284 << 20) | (284 << 10) | (284)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (317 << 20) | (317 << 10) | (317)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (347 << 20) | (347 << 10) | (347)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (373 << 20) | (373 << 10) | (373)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (398 << 20) | (398 << 10) | (398)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (442 << 20) | (442 << 10) | (442)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (481 << 20) | (481 << 10) | (481)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (517 << 20) | (517 << 10) | (517)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (550 << 20) | (550 << 10) | (550)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (609 << 20) | (609 << 10) | (609)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (662 << 20) | (662 << 10) | (662)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (709 << 20) | (709 << 10) | (709)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (753 << 20) | (753 << 10) | (753)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (794 << 20) | (794 << 10) | (794)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (832 << 20) | (832 << 10) | (832)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (868 << 20) | (868 << 10) | (868)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (902 << 20) | (902 << 10) | (902)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (934 << 20) | (934 << 10) | (934)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (966 << 20) | (966 << 10) | (966)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (996 << 20) | (996 << 10) | (996)); + + + /* + For Interrupt Restore only All types of write through + regsiters should be write header data to hardware at + least before it can restore. H/W will automatically + record the header to write through state buffer for + resture usage. + By Jaren: + HParaType = 8'h03, HParaSubType = 8'h00 + 8'h11 + 8'h12 + 8'h14 + 8'h15 + 8'h17 + HParaSubType 8'h12, 8'h15 is initialized. + [HWLimit] + 1. All these write through registers can't be partial + update. + 2. All these write through must be AGP command + 16 entries : 4 128-bit data */ + + /* Initialize INV_ParaSubType_TexPal */ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x00000000)); + for (i = 0; i < 16; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00000000); + } + + /* Initialize INV_ParaSubType_4X4Cof */ + /* 32 entries : 8 128-bit data */ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x11000000)); + for (i = 0; i < 32; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00000000); + } + + /* Initialize INV_ParaSubType_StipPal */ + /* 5 entries : 2 128-bit data */ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x14000000)); + for (i = 0; i < (5+3); i++) { + SetMMIORegister(dev_priv->mmio->handle, + 0x440, 0x00000000); + } + + /* primitive setting & vertex format*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00040000 | 0x14000000)); + for (i = 0; i < 52; i++) { + SetMMIORegister(dev_priv->mmio->handle, + 0x440, ((unsigned int) i << 24)); + } + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + 0x00fe0000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x4000840f); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x47000400); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x44000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x46000000); + + /* setting Misconfig*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + 0x00fe0000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00001004); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0800004b); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0a000049); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0b0000fb); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0c000001); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0d0000cb); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0e000009); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x10000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x110000ff); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x12000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x130000db); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x14000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x15000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x16000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x17000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x18000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x19000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x20000000); + } else if (dev_priv->chip_sub_index == CHIP_H6S2) { + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + 0x00010000); + for (i = 0; i <= 0x9A; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (unsigned int) i << 24); + } + + /* Initial Texture Stage Setting*/ + for (StageOfTexture = 0; StageOfTexture <= 0xf; + StageOfTexture++) { + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00020000 | 0x00000000 | + (StageOfTexture & 0xf)<<24)); + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_TRANS_SET)) = + (0x00020000 | HC_ParaSubType_Tex0 | + (StageOfTexture & 0xf)<<24);*/ + for (i = 0 ; i <= 0x30 ; i++) { + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_Hpara0)) =((unsigned int) i << 24);*/ + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (unsigned int) i << 24); + } + } + + /* Initial Texture Sampler Setting*/ + for (StageOfTexture = 0; StageOfTexture <= 0xf; + StageOfTexture++) { + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00020000 | 0x20000000 | + (StageOfTexture & 0xf)<<24)); + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_TRANS_SET)) =(0x00020000 | 0x00020000 | + ( StageOfTexture & 0xf)<<24);*/ + for (i = 0 ; i <= 0x36 ; i++) { + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_Hpara0)) =((unsigned int) i << 24);*/ + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (unsigned int) i << 24); + } + } + + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00020000 | 0xfe000000)); + for (i = 0 ; i <= 0x13 ; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (unsigned int) i << 24); + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_Hpara0)) =((unsigned int) i << 24);*/ + } + + /* Initial Gamma Table Setting*/ + /* Initial Gamma Table Setting*/ + /* 5 + 4 = 9 (12) dwords*/ + /* sRGB texture is not directly support by + H3 hardware.*/ + /* We have to set the deGamma table for texture + sampling.*/ + + /* degamma table*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x15000000)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (30 << 20) | (15 << 10) | (5))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((119 << 20) | (81 << 10) | (52))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((283 << 20) | (219 << 10) | (165))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((535 << 20) | (441 << 10) | (357))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((119 << 20) | (884 << 20) | (757 << 10) + | (640))); + + /* gamma table*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x17000000)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (13 << 20) | (13 << 10) | (13))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (26 << 20) | (26 << 10) | (26))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (39 << 20) | (39 << 10) | (39))); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, ((51 << 20) | (51 << 10) | (51))); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, ((71 << 20) | (71 << 10) | (71))); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (87 << 20) | (87 << 10) | (87)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (113 << 20) | (113 << 10) | (113)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (135 << 20) | (135 << 10) | (135)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (170 << 20) | (170 << 10) | (170)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (199 << 20) | (199 << 10) | (199)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (246 << 20) | (246 << 10) | (246)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (284 << 20) | (284 << 10) | (284)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (317 << 20) | (317 << 10) | (317)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (347 << 20) | (347 << 10) | (347)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (373 << 20) | (373 << 10) | (373)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (398 << 20) | (398 << 10) | (398)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (442 << 20) | (442 << 10) | (442)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (481 << 20) | (481 << 10) | (481)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (517 << 20) | (517 << 10) | (517)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (550 << 20) | (550 << 10) | (550)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (609 << 20) | (609 << 10) | (609)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (662 << 20) | (662 << 10) | (662)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (709 << 20) | (709 << 10) | (709)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (753 << 20) | (753 << 10) | (753)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (794 << 20) | (794 << 10) | (794)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (832 << 20) | (832 << 10) | (832)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (868 << 20) | (868 << 10) | (868)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (902 << 20) | (902 << 10) | (902)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (934 << 20) | (934 << 10) | (934)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (966 << 20) | (966 << 10) | (966)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (996 << 20) | (996 << 10) | (996)); + + + /* For Interrupt Restore only + All types of write through regsiters should be write + header data to hardware at least before it can restore. + H/W will automatically record the header to write + through state buffer for restureusage. + By Jaren: + HParaType = 8'h03, HParaSubType = 8'h00 + 8'h11 + 8'h12 + 8'h14 + 8'h15 + 8'h17 + HParaSubType 8'h12, 8'h15 is initialized. + [HWLimit] + 1. All these write through registers can't be partial + update. + 2. All these write through must be AGP command + 16 entries : 4 128-bit data */ + + /* Initialize INV_ParaSubType_TexPal */ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x00000000)); + for (i = 0; i < 16; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00000000); + } + + /* Initialize INV_ParaSubType_4X4Cof */ + /* 32 entries : 8 128-bit data */ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x11000000)); + for (i = 0; i < 32; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00000000); + } + + /* Initialize INV_ParaSubType_StipPal */ + /* 5 entries : 2 128-bit data */ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x14000000)); + for (i = 0; i < (5+3); i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00000000); + } + + /* primitive setting & vertex format*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00040000)); + for (i = 0; i <= 0x62; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((unsigned int) i << 24)); + } + + /*ParaType 0xFE - Configure and Misc Setting*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00fe0000)); + for (i = 0; i <= 0x47; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((unsigned int) i << 24)); + } + /*ParaType 0x11 - Frame Buffer Auto-Swapping and + Command Regulator Misc*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00110000)); + for (i = 0; i <= 0x20; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((unsigned int) i << 24)); + } + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + 0x00fe0000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x4000840f); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x47000404); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x44000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x46000005); + + /* setting Misconfig*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + 0x00fe0000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00001004); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x08000249); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0a0002c9); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0b0002fb); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0c000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0d0002cb); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0e000009); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x10000049); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x110002ff); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x12000008); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x130002db); + } +} + +int via_chrome9_drm_resume(struct pci_dev *pci) +{ + struct drm_device *dev = (struct drm_device *)pci_get_drvdata(pci); + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *)dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + + Initialize3DEngine(dev_priv); + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, 0x00110000); + if (dev_priv->chip_sub_index == CHIP_H6S2) { + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x06000000); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x07100000); + } else{ + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x02000000); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x03100000); + } + + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + INV_SubA_HSetRBGID | INV_HSetRBGID_CR); + + if (dev_priv->chip_sub_index == CHIP_H6S2) { + unsigned int *pGARTTable; + unsigned int i, entries, GARTOffset; + unsigned char sr6a, sr6b, sr6c, sr6f, sr7b; + unsigned int *addrlinear; + unsigned int size, alignedoffset; + + entries = dev_priv->pagetable_map.pagetable_size / + sizeof(unsigned int); + pGARTTable = dev_priv->pagetable_map.pagetable_handle; + + GARTOffset = dev_priv->pagetable_map.pagetable_offset; + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c &= (~0x80); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + sr6a = (unsigned char)((GARTOffset & 0xff000) >> 12); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6a); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6a); + + sr6b = (unsigned char)((GARTOffset & 0xff00000) >> 20); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6b); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6b); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c |= ((unsigned char)((GARTOffset >> 28) & 0x01)); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x7b); + sr7b = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr7b &= (~0x0f); + sr7b |= ProtectSizeValue(dev_priv-> + pagetable_map.pagetable_size); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr7b); + + for (i = 0; i < entries; i++) + writel(0x80000000, pGARTTable+i); + + /*flush*/ + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f); + do { + sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, + 0x83c5); + } while (sr6f & 0x80); + + sr6f |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + size = lpcmDMAManager->DMASize * sizeof(unsigned int) + + dev_priv->agp_size; + alignedoffset = 0; + entries = (size + PAGE_SIZE - 1) / PAGE_SIZE; + addrlinear = (unsigned int *)dev_priv->pcie_vmalloc_nocache; + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c &= (~0x80); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f); + do { + sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, + 0x83c5); + } while (sr6f & 0x80); + + for (i = 0; i < entries; i++) + writel(page_to_pfn(vmalloc_to_page((void *)addrlinear + + PAGE_SIZE * i)) & 0x3fffffff, pGARTTable+ + i+alignedoffset); + + sr6f |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + } + + if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) + SetAGPDoubleCmd_inv(dev); + else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) + SetAGPRingCmdRegs_inv(dev); + return 0; +} + +int via_chrome9_drm_suspend(struct pci_dev *dev, + pm_message_t state) +{ + return 0; +} + +int via_chrome9_driver_load(struct drm_device *dev, + unsigned long chipset) +{ + struct drm_via_chrome9_private *dev_priv; + int ret = 0; + static int associate; + + if (!associate) { + pci_set_drvdata(dev->pdev, dev); + dev->pdev->driver = &dev->driver->pci_driver; + associate = 1; + } + + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; + + dev_priv = drm_calloc(1, sizeof(struct drm_via_chrome9_private), + DRM_MEM_DRIVER); + if (dev_priv == NULL) + return -ENOMEM; + + /* Clear */ + memset(dev_priv, 0, sizeof(struct drm_via_chrome9_private)); + + dev_priv->dev = dev; + dev->dev_private = (void *)dev_priv; + + dev_priv->chip_index = chipset; + + ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); + if (ret) + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + return ret; +} + +int via_chrome9_driver_unload(struct drm_device *dev) +{ + struct drm_via_chrome9_private *dev_priv = dev->dev_private; + + drm_sman_takedown(&dev_priv->sman); + + drm_free(dev_priv, sizeof(struct drm_via_chrome9_private), + DRM_MEM_DRIVER); + + return 0; +} + +static int via_chrome9_initialize(struct drm_device *dev, + struct drm_via_chrome9_init *init) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *)dev->dev_private; + + dev_priv->chip_agp = init->chip_agp; + dev_priv->chip_index = init->chip_index; + dev_priv->chip_sub_index = init->chip_sub_index; + + dev_priv->usec_timeout = init->usec_timeout; + dev_priv->front_offset = init->front_offset; + dev_priv->back_offset = init->back_offset >> + VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT << + VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT; + dev_priv->available_fb_size = init->available_fb_size - + (init->available_fb_size % + (1 << VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT)); + dev_priv->depth_offset = init->depth_offset; + + /* Find all the map added first, doing this is necessary to + intialize hw */ + if (via_chrome9_map_init(dev, init)) { + DRM_ERROR("function via_chrome9_map_init ERROR !\n"); + goto error; + } + + /* Necessary information has been gathered for initialize hw */ + if (via_chrome9_hw_init(dev, init)) { + DRM_ERROR("function via_chrome9_hw_init ERROR !\n"); + goto error; + } + + /* After hw intialization, we have kown whether to use agp + or to use pcie for texture */ + if (via_chrome9_heap_management_init(dev, init)) { + DRM_ERROR("function \ + via_chrome9_heap_management_init ERROR !\n"); + goto error; + } + + return 0; + +error: + /* all the error recover has been processed in relevant function, + so here just return error */ + return -EINVAL; +} + +static void via_chrome9_cleanup(struct drm_device *dev, + struct drm_via_chrome9_init *init) +{ + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = NULL; + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *)dev->dev_private; + DRM_DEBUG("function via_chrome9_cleanup run!\n"); + + if (!dev_priv) + return ; + + lpcmDMAManager = + (struct drm_via_chrome9_DMA_manager *)dev_priv->dma_manager; + if (dev_priv->pcie_vmalloc_nocache) { + vfree((void *)dev_priv->pcie_vmalloc_nocache); + dev_priv->pcie_vmalloc_nocache = 0; + if (lpcmDMAManager) + lpcmDMAManager->addr_linear = NULL; + } + + if (dev_priv->pagetable_map.pagetable_handle) { + iounmap(dev_priv->pagetable_map.pagetable_handle); + dev_priv->pagetable_map.pagetable_handle = NULL; + } + + if (lpcmDMAManager && lpcmDMAManager->addr_linear) { + iounmap(lpcmDMAManager->addr_linear); + lpcmDMAManager->addr_linear = NULL; + } + + kfree(lpcmDMAManager); + dev_priv->dma_manager = NULL; + + if (dev_priv->event_tag_info) { + vfree(dev_priv->event_tag_info); + dev_priv->event_tag_info = NULL; + } + + if (dev_priv->bci_buffer) { + vfree(dev_priv->bci_buffer); + dev_priv->bci_buffer = NULL; + } + + via_chrome9_memory_destroy_heap(dev, dev_priv); +} + +/* +Do almost everything intialize here,include: +1.intialize all addmaps in private data structure +2.intialize memory heap management for video agp/pcie +3.intialize hw for dma(pcie/agp) function + +Note:all this function will dispatch into relevant function +*/ +int via_chrome9_ioctl_init(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_via_chrome9_init *init = (struct drm_via_chrome9_init *)data; + + switch (init->func) { + case VIA_CHROME9_INIT: + if (via_chrome9_initialize(dev, init)) { + DRM_ERROR("function via_chrome9_initialize error\n"); + return -1; + } + break; + + case VIA_CHROME9_CLEANUP: + via_chrome9_cleanup(dev, init); + break; + + default: + return -1; + } + + return 0; +} + +int via_chrome9_ioctl_allocate_event_tag(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_via_chrome9_event_tag *event_tag = data; + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *)dev->dev_private; + struct drm_clb_event_tag_info *event_tag_info = + dev_priv->event_tag_info; + unsigned int *event_addr = 0, i = 0; + + for (i = 0; i < NUMBER_OF_EVENT_TAGS; i++) { + if (!event_tag_info->usage[i]) + break; + } + + if (i < NUMBER_OF_EVENT_TAGS) { + event_tag_info->usage[i] = 1; + event_tag->event_offset = i; + event_tag->last_sent_event_value.event_low = 0; + event_tag->current_event_value.event_low = 0; + event_addr = event_tag_info->linear_address + + event_tag->event_offset * 4; + *event_addr = 0; + return 0; + } else { + return -7; + } + + return 0; +} + +int via_chrome9_ioctl_free_event_tag(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *)dev->dev_private; + struct drm_clb_event_tag_info *event_tag_info = + dev_priv->event_tag_info; + struct drm_via_chrome9_event_tag *event_tag = data; + + event_tag_info->usage[event_tag->event_offset] = 0; + return 0; +} + +void via_chrome9_lastclose(struct drm_device *dev) +{ + via_chrome9_cleanup(dev, 0); + return ; +} + +static int via_chrome9_do_wait_vblank(struct drm_via_chrome9_private + *dev_priv) +{ + int i; + + for (i = 0; i < dev_priv->usec_timeout; i++) { + VIA_CHROME9_WRITE8(0x83d4, 0x34); + if ((VIA_CHROME9_READ8(0x83d5)) & 0x8) + return 0; + __via_chrome9ke_udelay(1); + } + + return (-1); +} + +void via_chrome9_preclose(struct drm_device *dev, struct drm_file *file_priv) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_sarea *sarea_priv = NULL; + + if (!dev_priv) + return ; + + sarea_priv = dev_priv->sarea_priv; + if (!sarea_priv) + return ; + + if ((sarea_priv->page_flip == 1) && + (sarea_priv->current_page != VIA_CHROME9_FRONT)) { + volatile unsigned long *bci_base; + if (via_chrome9_do_wait_vblank(dev_priv)) + return; + + bci_base = (volatile unsigned long *)(dev_priv->bci); + + BCI_SET_STREAM_REGISTER(bci_base, 0x81c4, 0xc0000000); + BCI_SET_STREAM_REGISTER(bci_base, 0x81c0, + dev_priv->front_offset); + BCI_SEND(bci_base, 0x64000000);/* wait vsync */ + + sarea_priv->current_page = VIA_CHROME9_FRONT; + } +} + +int via_chrome9_is_agp(struct drm_device *dev) +{ + /* filter out pcie group which has no AGP device */ + if (dev->pci_device == 0x1122) { + dev->driver->driver_features &= + ~(DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_REQUIRE_AGP); + return 0; + } + return 1; +} + --- linux-2.6.24.orig/drivers/char/drm/Kconfig +++ linux-2.6.24/drivers/char/drm/Kconfig @@ -38,7 +38,7 @@ Choose this option if you have an ATI Radeon graphics card. There are both PCI and AGP versions. You don't need to choose this to run the Radeon in plain VGA mode. - + If M is selected, the module will be called radeon. config DRM_I810 @@ -71,9 +71,9 @@ 852GM, 855GM 865G or 915G integrated graphics. If M is selected, the module will be called i915. AGP support is required for this driver to work. This driver is used by the Intel driver in X.org 6.8 and - XFree86 4.4 and above. If unsure, build this and i830 as modules and + XFree86 4.4 and above. If unsure, build this and i830 as modules and the X server will load the correct one. - + endchoice config DRM_MGA @@ -88,7 +88,7 @@ tristate "SiS video cards" depends on DRM && AGP help - Choose this option if you have a SiS 630 or compatible video + Choose this option if you have a SiS 630 or compatible video chipset. If M is selected the module will be called sis. AGP support is required for this driver to work. @@ -98,6 +98,13 @@ help Choose this option if you have a Via unichrome or compatible video chipset. If M is selected the module will be called via. + +config DRM_VIA_CHROME9 + tristate "Via unichrome9 video cards" + depends on DRM + help + Choose this option if you have a Via unichrome9 or compatible video + chipset. If M is selected the module will be called via_chrome9. config DRM_SAVAGE tristate "Savage video cards" @@ -105,4 +112,3 @@ help Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister chipset. If M is selected the module will be called savage. - --- linux-2.6.24.orig/drivers/char/drm/via_chrome9_drv.c +++ linux-2.6.24/drivers/char/drm/via_chrome9_drv.c @@ -0,0 +1,153 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "drmP.h" +#include "via_chrome9_drm.h" +#include "via_chrome9_drv.h" +#include "via_chrome9_dma.h" +#include "via_chrome9_mm.h" + +#include "drm_pciids.h" + +static int dri_library_name(struct drm_device *dev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "via_chrome9"); +} + +int via_chrome9_drm_authmagic(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} + +struct drm_ioctl_desc via_chrome9_ioctls[] = { + DRM_IOCTL_DEF(DRM_VIA_CHROME9_INIT, via_chrome9_ioctl_init, + DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),/* via_chrome9_map.c*/ + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FLUSH, via_chrome9_ioctl_flush, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREE, via_chrome9_ioctl_free, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_ALLOCATE_EVENT_TAG, + via_chrome9_ioctl_allocate_event_tag, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREE_EVENT_TAG, + via_chrome9_ioctl_free_event_tag, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_ALLOCATE_APERTURE, + via_chrome9_ioctl_allocate_aperture, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREE_APERTURE, + via_chrome9_ioctl_free_aperture, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_ALLOCATE_VIDEO_MEM, + via_chrome9_ioctl_allocate_mem_wrapper, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREE_VIDEO_MEM, + via_chrome9_ioctl_free_mem_wrapper, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_WAIT_CHIP_IDLE, + via_chrome9_ioctl_wait_chip_idle, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_PROCESS_EXIT, + via_chrome9_ioctl_process_exit, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_RESTORE_PRIMARY, + via_chrome9_ioctl_restore_primary, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FLUSH_CACHE, + via_chrome9_ioctl_flush_cache, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_ALLOCMEM, + via_chrome9_ioctl_allocate_mem_base, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREEMEM, + via_chrome9_ioctl_freemem_base, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_CHECKVIDMEMSIZE, + via_chrome9_ioctl_check_vidmem_size, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_PCIEMEMCTRL, + via_chrome9_ioctl_pciemem_ctrl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_AUTH_MAGIC, via_chrome9_drm_authmagic, 0) +}; + +int via_chrome9_max_ioctl = DRM_ARRAY_SIZE(via_chrome9_ioctls); + +static struct pci_device_id pciidlist[] = { + via_chrome9DRV_PCI_IDS +}; + +int via_chrome9_driver_open(struct drm_device *dev, + struct drm_file *priv) +{ + priv->authenticated = 1; + return 0; +} + +static struct drm_driver driver = { + .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | + DRIVER_HAVE_DMA | DRIVER_FB_DMA | DRIVER_USE_MTRR, + .open = via_chrome9_driver_open, + .load = via_chrome9_driver_load, + .unload = via_chrome9_driver_unload, + .device_is_agp = via_chrome9_is_agp, + .dri_library_name = dri_library_name, + .reclaim_buffers = drm_core_reclaim_buffers, + .reclaim_buffers_locked = NULL, + .reclaim_buffers_idlelocked = via_chrome9_reclaim_buffers_locked, + .lastclose = via_chrome9_lastclose, + .preclose = via_chrome9_preclose, + .get_map_ofs = drm_core_get_map_ofs, + .get_reg_ofs = drm_core_get_reg_ofs, + .ioctls = via_chrome9_ioctls, + .fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .ioctl = drm_ioctl, + .mmap = drm_mmap, + .poll = drm_poll, + .fasync = drm_fasync, + }, + .pci_driver = { + .name = DRIVER_NAME, + .id_table = pciidlist, + .resume = via_chrome9_drm_resume, + .suspend = via_chrome9_drm_suspend, + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, +}; + +static int __init via_chrome9_init(void) +{ + driver.num_ioctls = via_chrome9_max_ioctl; + driver.dev_priv_size = sizeof(struct drm_via_chrome9_private); + return drm_init(&driver); +} + +static void __exit via_chrome9_exit(void) +{ + drm_exit(&driver); +} + +module_init(via_chrome9_init); +module_exit(via_chrome9_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL and additional rights"); --- linux-2.6.24.orig/drivers/char/drm/drm_pciids.h +++ linux-2.6.24/drivers/char/drm/drm_pciids.h @@ -240,10 +240,17 @@ {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \ {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \ {0, 0, 0} + +#define via_chrome9DRV_PCI_IDS \ + {0x1106, 0x3225, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_CHROME9_DX9_0}, \ + {0x1106, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x1122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_CHROME9_PCIE_GROUP},\ + {0, 0, 0} + #define i810_PCI_IDS \ {0x8086, 0x7121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x7123, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ @@ -311,5 +318,6 @@ {0x8086, 0x29d2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2a02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2a12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0, 0, 0} --- linux-2.6.24.orig/drivers/char/drm/drm_sysfs.c +++ linux-2.6.24/drivers/char/drm/drm_sysfs.c @@ -19,6 +19,43 @@ #include "drm_core.h" #include "drmP.h" +#define to_drm_device(d) container_of(d, struct drm_device, dev) + +/** + * drm_sysfs_suspend - DRM class suspend hook + * @dev: Linux device to suspend + * @state: power state to enter + * + * Just figures out what the actual struct drm_device associated with + * @dev is and calls its suspend hook, if present. + */ +static int drm_sysfs_suspend(struct device *dev, pm_message_t state) +{ + struct drm_device *drm_dev = to_drm_device(dev); + + if (drm_dev->driver->suspend) + return drm_dev->driver->suspend(drm_dev, state); + + return 0; +} + +/** + * drm_sysfs_resume - DRM class resume hook + * @dev: Linux device to resume + * + * Just figures out what the actual struct drm_device associated with + * @dev is and calls its resume hook, if present. + */ +static int drm_sysfs_resume(struct device *dev) +{ + struct drm_device *drm_dev = to_drm_device(dev); + + if (drm_dev->driver->resume) + return drm_dev->driver->resume(drm_dev); + + return 0; +} + /* Display the version of drm_core. This doesn't work right in current design */ static ssize_t version_show(struct class *dev, char *buf) { @@ -33,7 +70,7 @@ * @owner: pointer to the module that is to "own" this struct drm_sysfs_class * @name: pointer to a string for the name of this class. * - * This is used to create a struct drm_sysfs_class pointer that can then be used + * This is used to create DRM class pointer that can then be used * in calls to drm_sysfs_device_add(). * * Note, the pointer created here is to be destroyed when finished by making a @@ -50,6 +87,9 @@ goto err_out; } + class->suspend = drm_sysfs_suspend; + class->resume = drm_sysfs_resume; + err = class_create_file(class, &class_attr_version); if (err) goto err_out_class; @@ -63,94 +103,105 @@ } /** - * drm_sysfs_destroy - destroys a struct drm_sysfs_class structure - * @cs: pointer to the struct drm_sysfs_class that is to be destroyed + * drm_sysfs_destroy - destroys DRM class * - * Note, the pointer to be destroyed must have been created with a call to - * drm_sysfs_create(). + * Destroy the DRM device class. */ -void drm_sysfs_destroy(struct class *class) +void drm_sysfs_destroy(void) { - if ((class == NULL) || (IS_ERR(class))) + if ((drm_class == NULL) || (IS_ERR(drm_class))) return; - - class_remove_file(class, &class_attr_version); - class_destroy(class); + class_remove_file(drm_class, &class_attr_version); + class_destroy(drm_class); } -static ssize_t show_dri(struct class_device *class_device, char *buf) +static ssize_t show_dri(struct device *device, struct device_attribute *attr, + char *buf) { - struct drm_device * dev = ((struct drm_head *)class_get_devdata(class_device))->dev; + struct drm_device *dev = to_drm_device(device); if (dev->driver->dri_library_name) return dev->driver->dri_library_name(dev, buf); return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name); } -static struct class_device_attribute class_device_attrs[] = { +static struct device_attribute device_attrs[] = { __ATTR(dri_library_name, S_IRUGO, show_dri, NULL), }; /** + * drm_sysfs_device_release - do nothing + * @dev: Linux device + * + * Normally, this would free the DRM device associated with @dev, along + * with cleaning up any other stuff. But we do that in the DRM core, so + * this function can just return and hope that the core does its job. + */ +static void drm_sysfs_device_release(struct device *dev) +{ + return; +} + +/** * drm_sysfs_device_add - adds a class device to sysfs for a character driver - * @cs: pointer to the struct class that this device should be registered to. - * @dev: the dev_t for the device to be added. - * @device: a pointer to a struct device that is assiociated with this class device. - * @fmt: string for the class device's name - * - * A struct class_device will be created in sysfs, registered to the specified - * class. A "dev" file will be created, showing the dev_t for the device. The - * pointer to the struct class_device will be returned from the call. Any further - * sysfs files that might be required can be created using this pointer. - * Note: the struct class passed to this function must have previously been - * created with a call to drm_sysfs_create(). - */ -struct class_device *drm_sysfs_device_add(struct class *cs, struct drm_head *head) -{ - struct class_device *class_dev; - int i, j, err; - - class_dev = class_device_create(cs, NULL, - MKDEV(DRM_MAJOR, head->minor), - &(head->dev->pdev)->dev, - "card%d", head->minor); - if (IS_ERR(class_dev)) { - err = PTR_ERR(class_dev); + * @dev: DRM device to be added + * @head: DRM head in question + * + * Add a DRM device to the DRM's device model class. We use @dev's PCI device + * as the parent for the Linux device, and make sure it has a file containing + * the driver we're using (for userspace compatibility). + */ +int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) +{ + int err; + int i, j; + + dev->dev.parent = &dev->pdev->dev; + dev->dev.class = drm_class; + dev->dev.release = drm_sysfs_device_release; + /* + * This will actually add the major:minor file so that udev + * will create the device node. We don't want to do that just + * yet... + */ + /* dev->dev.devt = head->device; */ + snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", head->minor); + + err = device_register(&dev->dev); + if (err) { + DRM_ERROR("device add failed: %d\n", err); goto err_out; } - class_set_devdata(class_dev, head); - - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { - err = class_device_create_file(class_dev, - &class_device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { + err = device_create_file(&dev->dev, &device_attrs[i]); if (err) goto err_out_files; } - return class_dev; + return 0; err_out_files: if (i > 0) for (j = 0; j < i; j++) - class_device_remove_file(class_dev, - &class_device_attrs[i]); - class_device_unregister(class_dev); + device_remove_file(&dev->dev, &device_attrs[i]); + device_unregister(&dev->dev); err_out: - return ERR_PTR(err); + + return err; } /** - * drm_sysfs_device_remove - removes a class device that was created with drm_sysfs_device_add() - * @dev: the dev_t of the device that was previously registered. + * drm_sysfs_device_remove - remove DRM device + * @dev: DRM device to remove * * This call unregisters and cleans up a class device that was created with a * call to drm_sysfs_device_add() */ -void drm_sysfs_device_remove(struct class_device *class_dev) +void drm_sysfs_device_remove(struct drm_device *dev) { int i; - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) - class_device_remove_file(class_dev, &class_device_attrs[i]); - class_device_unregister(class_dev); + for (i = 0; i < ARRAY_SIZE(device_attrs); i++) + device_remove_file(&dev->dev, &device_attrs[i]); + device_unregister(&dev->dev); } --- linux-2.6.24.orig/drivers/char/drm/r128_state.c +++ linux-2.6.24/drivers/char/drm/r128_state.c @@ -1245,14 +1245,18 @@ static int r128_cce_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_r128_private_t *dev_priv = dev->dev_private; - drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_r128_sarea_t *sarea_priv; drm_r128_clear_t *clear = data; DRM_DEBUG("\n"); LOCK_TEST_WITH_RETURN(dev, file_priv); + DEV_INIT_TEST_WITH_RETURN(dev_priv); + RING_SPACE_TEST_WITH_RETURN(dev_priv); + sarea_priv = dev_priv->sarea_priv; + if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS) sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS; @@ -1313,6 +1317,8 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); + DEV_INIT_TEST_WITH_RETURN(dev_priv); + RING_SPACE_TEST_WITH_RETURN(dev_priv); if (!dev_priv->page_flipping) @@ -1332,6 +1338,8 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); + DEV_INIT_TEST_WITH_RETURN(dev_priv); + RING_SPACE_TEST_WITH_RETURN(dev_priv); if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS) @@ -1355,10 +1363,7 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return -EINVAL; - } + DEV_INIT_TEST_WITH_RETURN(dev_priv); DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n", DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard); @@ -1411,10 +1416,7 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return -EINVAL; - } + DEV_INIT_TEST_WITH_RETURN(dev_priv); DRM_DEBUG("pid=%d buf=%d s=%d e=%d d=%d\n", DRM_CURRENTPID, elts->idx, elts->start, elts->end, elts->discard); @@ -1477,6 +1479,8 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); + DEV_INIT_TEST_WITH_RETURN(dev_priv); + DRM_DEBUG("pid=%d index=%d\n", DRM_CURRENTPID, blit->idx); if (blit->idx < 0 || blit->idx >= dma->buf_count) { @@ -1502,6 +1506,8 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); + DEV_INIT_TEST_WITH_RETURN(dev_priv); + RING_SPACE_TEST_WITH_RETURN(dev_priv); ret = -EINVAL; @@ -1532,6 +1538,8 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); + DEV_INIT_TEST_WITH_RETURN(dev_priv); + if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32))) return -EFAULT; @@ -1556,10 +1564,7 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return -EINVAL; - } + DEV_INIT_TEST_WITH_RETURN(dev_priv); DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n", indirect->idx, indirect->start, indirect->end, @@ -1621,10 +1626,7 @@ drm_r128_getparam_t *param = data; int value; - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return -EINVAL; - } + DEV_INIT_TEST_WITH_RETURN(dev_priv); DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); --- linux-2.6.24.orig/drivers/char/drm/via_chrome9_mm.c +++ linux-2.6.24/drivers/char/drm/via_chrome9_mm.c @@ -0,0 +1,388 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "drmP.h" +#include "via_chrome9_drm.h" +#include "via_chrome9_drv.h" +#include "drm_sman.h" +#include "via_chrome9_mm.h" + +#define VIA_CHROME9_MM_GRANULARITY 4 +#define VIA_CHROME9_MM_GRANULARITY_MASK ((1 << VIA_CHROME9_MM_GRANULARITY) - 1) + + +int via_chrome9_map_init(struct drm_device *dev, + struct drm_via_chrome9_init *init) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *)dev->dev_private; + + dev_priv->sarea = drm_getsarea(dev); + if (!dev_priv->sarea) { + DRM_ERROR("could not find sarea!\n"); + goto error; + } + dev_priv->sarea_priv = + (struct drm_via_chrome9_sarea *)((unsigned char *)dev_priv-> + sarea->handle + init->sarea_priv_offset); + + dev_priv->fb = drm_core_findmap(dev, init->fb_handle); + if (!dev_priv->fb) { + DRM_ERROR("could not find framebuffer!\n"); + goto error; + } + /* Frame buffer physical base address */ + dev_priv->fb_base_address = init->fb_base_address; + + if (init->shadow_size) { + /* find apg shadow region mappings */ + dev_priv->shadow_map.shadow = drm_core_findmap(dev, init-> + shadow_handle); + if (!dev_priv->shadow_map.shadow) { + DRM_ERROR("could not shadow map!\n"); + goto error; + } + dev_priv->shadow_map.shadow_size = init->shadow_size; + dev_priv->shadow_map.shadow_handle = (unsigned int *)dev_priv-> + shadow_map.shadow->handle; + init->shadow_handle = dev_priv->shadow_map.shadow->offset; + } + if (init->agp_tex_size && init->chip_agp != CHIP_PCIE) { + /* find apg texture buffer mappings */ + dev_priv->agp_tex = drm_core_findmap(dev, init->agp_tex_handle); + dev_priv->agp_size = init->agp_tex_size; + dev_priv->agp_offset = init->agp_tex_handle; + if (!dev_priv->agp_tex) { + DRM_ERROR("could not find agp texture map !\n"); + goto error; + } + } + /* find mmio/dma mappings */ + dev_priv->mmio = drm_core_findmap(dev, init->mmio_handle); + if (!dev_priv->mmio) { + DRM_ERROR("failed to find mmio region!\n"); + goto error; + } + + dev_priv->hostBlt = drm_core_findmap(dev, init->hostBlt_handle); + if (!dev_priv->hostBlt) { + DRM_ERROR("failed to find host bitblt region!\n"); + goto error; + } + + dev_priv->drm_agp_type = init->agp_type; + if (init->agp_type != AGP_DISABLED && init->chip_agp != CHIP_PCIE) { + dev->agp_buffer_map = drm_core_findmap(dev, init->dma_handle); + if (!dev->agp_buffer_map) { + DRM_ERROR("failed to find dma buffer region!\n"); + goto error; + } + } + + dev_priv->bci = (char *)dev_priv->mmio->handle + 0x10000; + + return 0; + +error: + /* do cleanup here, refine_later */ + return (-EINVAL); +} + +int via_chrome9_heap_management_init(struct drm_device *dev, + struct drm_via_chrome9_init *init) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + int ret = 0; + + /* video memory management. range: 0 ---- video_whole_size */ + mutex_lock(&dev->struct_mutex); + ret = drm_sman_set_range(&dev_priv->sman, VIA_CHROME9_MEM_VIDEO, + 0, dev_priv->available_fb_size >> VIA_CHROME9_MM_GRANULARITY); + if (ret) { + DRM_ERROR("VRAM memory manager initialization ******ERROR\ + !******\n"); + mutex_unlock(&dev->struct_mutex); + goto error; + } + dev_priv->vram_initialized = 1; + /* agp/pcie heap management. + note:because agp is contradict with pcie, so only one is enough + for managing both of them.*/ + init->agp_type = dev_priv->drm_agp_type; + if (init->agp_type != AGP_DISABLED && dev_priv->agp_size) { + ret = drm_sman_set_range(&dev_priv->sman, VIA_CHROME9_MEM_AGP, + 0, dev_priv->agp_size >> VIA_CHROME9_MM_GRANULARITY); + if (ret) { + DRM_ERROR("AGP/PCIE memory manager initialization ******ERROR\ + !******\n"); + mutex_unlock(&dev->struct_mutex); + goto error; + } + dev_priv->agp_initialized = 1; + } + mutex_unlock(&dev->struct_mutex); + return 0; + +error: + /* Do error recover here, refine_later */ + return -EINVAL; +} + + +void via_chrome9_memory_destroy_heap(struct drm_device *dev, + struct drm_via_chrome9_private *dev_priv) +{ + mutex_lock(&dev->struct_mutex); + drm_sman_cleanup(&dev_priv->sman); + dev_priv->vram_initialized = 0; + dev_priv->agp_initialized = 0; + mutex_unlock(&dev->struct_mutex); +} + +void via_chrome9_reclaim_buffers_locked(struct drm_device *dev, + struct drm_file *file_priv) +{ + return; +} + +int via_chrome9_ioctl_allocate_aperture(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + return 0; +} + +int via_chrome9_ioctl_free_aperture(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + return 0; +} + + +/* Allocate memory from DRM module for video playing */ +int via_chrome9_ioctl_allocate_mem_base(struct drm_device *dev, +void *data, struct drm_file *file_priv) +{ + struct drm_via_chrome9_mem *mem = data; + struct drm_memblock_item *item; + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + unsigned long tmpSize = 0, offset = 0, alignment = 0; + /* modify heap_type to agp for pcie, since we treat pcie/agp heap + no difference in heap management */ + if (mem->type == memory_heap_pcie) { + if (dev_priv->chip_agp != CHIP_PCIE) { + DRM_ERROR( + "User want to alloc memory from pcie heap but via_chrome9.ko\ + has no this heap exist.******ERROR******\n"); + return -EINVAL; + } + mem->type = memory_heap_agp; + } + + if (mem->type > VIA_CHROME9_MEM_AGP) { + DRM_ERROR("Unknown memory type allocation\n"); + return -EINVAL; + } + mutex_lock(&dev->struct_mutex); + if (0 == ((mem->type == VIA_CHROME9_MEM_VIDEO) ? + dev_priv->vram_initialized : dev_priv->agp_initialized)) { + DRM_ERROR("Attempt to allocate from uninitialized\ + memory manager.\n"); + mutex_unlock(&dev->struct_mutex); + return -EINVAL; + } + tmpSize = (mem->size + VIA_CHROME9_MM_GRANULARITY_MASK) >> + VIA_CHROME9_MM_GRANULARITY; + mem->size = tmpSize << VIA_CHROME9_MM_GRANULARITY; + alignment = (dev_priv->alignment & 0x80000000) ? dev_priv-> + alignment & 0x7FFFFFFF:0; + alignment /= (1 << VIA_CHROME9_MM_GRANULARITY); + item = drm_sman_alloc(&dev_priv->sman, mem->type, tmpSize, alignment, + (unsigned long)file_priv); + mutex_unlock(&dev->struct_mutex); + /* alloc failed */ + if (!item) { + DRM_ERROR("Allocate memory failed ******ERROR******.\n"); + return -ENOMEM; + } + /* Till here every thing is ok, we check the memory type allocated + and return appropriate value to user mode Here the value return to + user is very difficult to operate. BE CAREFULLY!!! */ + /* offset is used by user mode ap to calculate the virtual address + which is used to access the memory allocated */ + mem->index = item->user_hash.key; + offset = item->mm->offset(item->mm, item->mm_info) << + VIA_CHROME9_MM_GRANULARITY; + switch (mem->type) { + case VIA_CHROME9_MEM_VIDEO: + mem->offset = offset + dev_priv->back_offset; + break; + case VIA_CHROME9_MEM_AGP: + /* return different value to user according to the chip type */ + if (dev_priv->chip_agp == CHIP_PCIE) { + mem->offset = offset + + ((struct drm_via_chrome9_DMA_manager *)dev_priv-> + dma_manager)->DMASize * sizeof(unsigned long); + } else { + mem->offset = offset; + } + break; + default: + /* Strange thing happen! Faint. Code bug! */ + DRM_ERROR("Enter here is impossible ******\ + ERROR******.\n"); + return -EINVAL; + } + /*DONE. Need we call function copy_to_user ?NO. We can't even + touch user's space.But we are lucky, since kernel drm:drm_ioctl + will to the job for us. */ + return 0; +} + +/* Allocate video/AGP/PCIE memory from heap management */ +int via_chrome9_ioctl_allocate_mem_wrapper(struct drm_device + *dev, void *data, struct drm_file *file_priv) +{ + struct drm_via_chrome9_memory_alloc *memory_alloc = + (struct drm_via_chrome9_memory_alloc *)data; + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_mem mem; + + mem.size = memory_alloc->size; + mem.type = memory_alloc->heap_type; + dev_priv->alignment = memory_alloc->align | 0x80000000; + if (via_chrome9_ioctl_allocate_mem_base(dev, &mem, file_priv)) { + DRM_ERROR("Allocate memory error!.\n"); + return -ENOMEM; + } + dev_priv->alignment = 0; + /* Till here every thing is ok, we check the memory type allocated and + return appropriate value to user mode Here the value return to user is + very difficult to operate. BE CAREFULLY!!!*/ + /* offset is used by user mode ap to calculate the virtual address + which is used to access the memory allocated */ + memory_alloc->offset = mem.offset; + memory_alloc->heap_info.lpL1Node = (void *)mem.index; + memory_alloc->size = mem.size; + switch (memory_alloc->heap_type) { + case VIA_CHROME9_MEM_VIDEO: + memory_alloc->physaddress = memory_alloc->offset + + dev_priv->fb_base_address; + memory_alloc->linearaddress = (void *)memory_alloc->physaddress; + break; + case VIA_CHROME9_MEM_AGP: + /* return different value to user according to the chip type */ + if (dev_priv->chip_agp == CHIP_PCIE) { + memory_alloc->physaddress = memory_alloc->offset; + memory_alloc->linearaddress = (void *)memory_alloc-> + physaddress; + } else { + memory_alloc->physaddress = dev->agp->base + + memory_alloc->offset + + ((struct drm_via_chrome9_DMA_manager *) + dev_priv->dma_manager)->DMASize * sizeof(unsigned long); + memory_alloc->linearaddress = + (void *)memory_alloc->physaddress; + } + break; + default: + /* Strange thing happen! Faint. Code bug! */ + DRM_ERROR("Enter here is impossible ******ERROR******.\n"); + return -EINVAL; + } + return 0; +} + +int via_chrome9_ioctl_free_mem_wrapper(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_via_chrome9_memory_alloc *memory_alloc = data; + struct drm_via_chrome9_mem mem; + + mem.index = (unsigned long)memory_alloc->heap_info.lpL1Node; + if (via_chrome9_ioctl_freemem_base(dev, &mem, file_priv)) { + DRM_ERROR("function free_mem_wrapper error.\n"); + return -EINVAL; + } + + return 0; +} + +int via_chrome9_ioctl_freemem_base(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_via_chrome9_private *dev_priv = dev->dev_private; + struct drm_via_chrome9_mem *mem = data; + int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm_sman_free_key(&dev_priv->sman, mem->index); + mutex_unlock(&dev->struct_mutex); + DRM_DEBUG("free = 0x%lx\n", mem->index); + + return ret; +} + +int via_chrome9_ioctl_check_vidmem_size(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + return 0; +} + +int via_chrome9_ioctl_pciemem_ctrl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + int result = 0; + struct drm_via_chrome9_private *dev_priv = dev->dev_private; + struct drm_via_chrome9_pciemem_ctrl *pcie_memory_ctrl = data; + switch (pcie_memory_ctrl->ctrl_type) { + case pciemem_copy_from_user: + result = copy_from_user((void *)( + dev_priv->pcie_vmalloc_nocache+ + pcie_memory_ctrl->pcieoffset), + pcie_memory_ctrl->usermode_data, + pcie_memory_ctrl->size); + break; + case pciemem_copy_to_user: + result = copy_to_user(pcie_memory_ctrl->usermode_data, + (void *)(dev_priv->pcie_vmalloc_nocache+ + pcie_memory_ctrl->pcieoffset), + pcie_memory_ctrl->size); + break; + case pciemem_memset: + memset((void *)(dev_priv->pcie_vmalloc_nocache + + pcie_memory_ctrl->pcieoffset), + pcie_memory_ctrl->memsetdata, + pcie_memory_ctrl->size); + break; + default: + break; + } + return 0; +} --- linux-2.6.24.orig/drivers/char/drm/i915_drv.h +++ linux-2.6.24/drivers/char/drm/i915_drv.h @@ -114,6 +114,93 @@ spinlock_t swaps_lock; drm_i915_vbl_swap_t vbl_swaps; unsigned int swaps_pending; + + /* Register state */ + u8 saveLBB; + u32 saveDSPACNTR; + u32 saveDSPBCNTR; + u32 savePIPEACONF; + u32 savePIPEBCONF; + u32 savePIPEASRC; + u32 savePIPEBSRC; + u32 saveFPA0; + u32 saveFPA1; + u32 saveDPLL_A; + u32 saveDPLL_A_MD; + u32 saveHTOTAL_A; + u32 saveHBLANK_A; + u32 saveHSYNC_A; + u32 saveVTOTAL_A; + u32 saveVBLANK_A; + u32 saveVSYNC_A; + u32 saveBCLRPAT_A; + u32 savePIPEASTAT; + u32 saveDSPASTRIDE; + u32 saveDSPASIZE; + u32 saveDSPAPOS; + u32 saveDSPABASE; + u32 saveDSPASURF; + u32 saveDSPATILEOFF; + u32 savePFIT_PGM_RATIOS; + u32 saveBLC_PWM_CTL; + u32 saveBLC_PWM_CTL2; + u32 saveFPB0; + u32 saveFPB1; + u32 saveDPLL_B; + u32 saveDPLL_B_MD; + u32 saveHTOTAL_B; + u32 saveHBLANK_B; + u32 saveHSYNC_B; + u32 saveVTOTAL_B; + u32 saveVBLANK_B; + u32 saveVSYNC_B; + u32 saveBCLRPAT_B; + u32 savePIPEBSTAT; + u32 saveDSPBSTRIDE; + u32 saveDSPBSIZE; + u32 saveDSPBPOS; + u32 saveDSPBBASE; + u32 saveDSPBSURF; + u32 saveDSPBTILEOFF; + u32 saveVCLK_DIVISOR_VGA0; + u32 saveVCLK_DIVISOR_VGA1; + u32 saveVCLK_POST_DIV; + u32 saveVGACNTRL; + u32 saveADPA; + u32 saveLVDS; + u32 saveLVDSPP_ON; + u32 saveLVDSPP_OFF; + u32 saveDVOA; + u32 saveDVOB; + u32 saveDVOC; + u32 savePP_ON; + u32 savePP_OFF; + u32 savePP_CONTROL; + u32 savePP_CYCLE; + u32 savePFIT_CONTROL; + u32 save_palette_a[256]; + u32 save_palette_b[256]; + u32 saveFBC_CFB_BASE; + u32 saveFBC_LL_BASE; + u32 saveFBC_CONTROL; + u32 saveFBC_CONTROL2; + u32 saveIER; + u32 saveIIR; + u32 saveIMR; + u32 saveCACHE_MODE_0; + u32 saveDSPCLK_GATE_D; + u32 saveMI_ARB_STATE; + u32 saveSWF0[16]; + u32 saveSWF1[16]; + u32 saveSWF2[3]; + u8 saveMSR; + u8 saveSR[8]; + u8 saveGR[25]; + u8 saveAR_INDEX; + u8 saveAR[21]; + u8 saveDACMASK; + u8 saveDACDATA[256*3]; /* 256 3-byte colors */ + u8 saveCR[37]; } drm_i915_private_t; extern struct drm_ioctl_desc i915_ioctls[]; @@ -122,6 +209,7 @@ /* i915_dma.c */ extern void i915_kernel_lost_context(struct drm_device * dev); extern int i915_driver_load(struct drm_device *, unsigned long flags); +extern int i915_driver_unload(struct drm_device *); extern void i915_driver_lastclose(struct drm_device * dev); extern void i915_driver_preclose(struct drm_device *dev, struct drm_file *file_priv); @@ -200,7 +288,51 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); -#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) +/* Extended config space */ +#define LBB 0xf4 + +/* VGA stuff */ + +#define VGA_ST01_MDA 0x3ba +#define VGA_ST01_CGA 0x3da + +#define VGA_MSR_WRITE 0x3c2 +#define VGA_MSR_READ 0x3cc +#define VGA_MSR_MEM_EN (1<<1) +#define VGA_MSR_CGA_MODE (1<<0) + +#define VGA_SR_INDEX 0x3c4 +#define VGA_SR_DATA 0x3c5 + +#define VGA_AR_INDEX 0x3c0 +#define VGA_AR_VID_EN (1<<5) +#define VGA_AR_DATA_WRITE 0x3c0 +#define VGA_AR_DATA_READ 0x3c1 + +#define VGA_GR_INDEX 0x3ce +#define VGA_GR_DATA 0x3cf +/* GR05 */ +#define VGA_GR_MEM_READ_MODE_SHIFT 3 +#define VGA_GR_MEM_READ_MODE_PLANE 1 +/* GR06 */ +#define VGA_GR_MEM_MODE_MASK 0xc +#define VGA_GR_MEM_MODE_SHIFT 2 +#define VGA_GR_MEM_A0000_AFFFF 0 +#define VGA_GR_MEM_A0000_BFFFF 1 +#define VGA_GR_MEM_B0000_B7FFF 2 +#define VGA_GR_MEM_B0000_BFFFF 3 + +#define VGA_DACMASK 0x3c6 +#define VGA_DACRX 0x3c7 +#define VGA_DACWX 0x3c8 +#define VGA_DACDATA 0x3c9 + +#define VGA_CR_INDEX_MDA 0x3b4 +#define VGA_CR_DATA_MDA 0x3b5 +#define VGA_CR_INDEX_CGA 0x3d4 +#define VGA_CR_DATA_CGA 0x3d5 + +#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) #define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) #define CMD_REPORT_HEAD (7<<23) #define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) @@ -215,6 +347,44 @@ #define BB1_UNPROTECTED (0<<0) #define BB2_END_ADDR_MASK (~0x7) +/* Framebuffer compression */ +#define FBC_CFB_BASE 0x03200 /* 4k page aligned */ +#define FBC_LL_BASE 0x03204 /* 4k page aligned */ +#define FBC_CONTROL 0x03208 +#define FBC_CTL_EN (1<<31) +#define FBC_CTL_PERIODIC (1<<30) +#define FBC_CTL_INTERVAL_SHIFT (16) +#define FBC_CTL_UNCOMPRESSIBLE (1<<14) +#define FBC_CTL_STRIDE_SHIFT (5) +#define FBC_CTL_FENCENO (1<<0) +#define FBC_COMMAND 0x0320c +#define FBC_CMD_COMPRESS (1<<0) +#define FBC_STATUS 0x03210 +#define FBC_STAT_COMPRESSING (1<<31) +#define FBC_STAT_COMPRESSED (1<<30) +#define FBC_STAT_MODIFIED (1<<29) +#define FBC_STAT_CURRENT_LINE (1<<0) +#define FBC_CONTROL2 0x03214 +#define FBC_CTL_FENCE_DBL (0<<4) +#define FBC_CTL_IDLE_IMM (0<<2) +#define FBC_CTL_IDLE_FULL (1<<2) +#define FBC_CTL_IDLE_LINE (2<<2) +#define FBC_CTL_IDLE_DEBUG (3<<2) +#define FBC_CTL_CPU_FENCE (1<<1) +#define FBC_CTL_PLANEA (0<<0) +#define FBC_CTL_PLANEB (1<<0) +#define FBC_FENCE_OFF 0x0321b + +#define FBC_LL_SIZE (1536) +#define FBC_LL_PAD (32) + +/* Interrupt bits: + */ +#define USER_INT_FLAG (1<<1) +#define VSYNC_PIPEB_FLAG (1<<5) +#define VSYNC_PIPEA_FLAG (1<<7) +#define HWB_OOM_FLAG (1<<13) /* binner out of memory */ + #define I915REG_HWSTAM 0x02098 #define I915REG_INT_IDENTITY_R 0x020a4 #define I915REG_INT_MASK_R 0x020a8 @@ -252,6 +422,11 @@ #define LP_RING 0x2030 #define HP_RING 0x2040 #define RING_TAIL 0x00 +/* The binner has its own ring buffer: + */ +#define HWB_RING 0x2400 + +#define RING_TAIL 0x00 #define TAIL_ADDR 0x001FFFF8 #define RING_HEAD 0x04 #define HEAD_WRAP_COUNT 0xFFE00000 @@ -269,11 +444,110 @@ #define RING_VALID 0x00000001 #define RING_INVALID 0x00000000 +/* Instruction parser error reg: + */ +#define IPEIR 0x2088 + +/* Scratch pad debug 0 reg: + */ +#define SCPD0 0x209c + +/* Error status reg: + */ +#define ESR 0x20b8 + +/* Secondary DMA fetch address debug reg: + */ +#define DMA_FADD_S 0x20d4 + +/* Memory Interface Arbitration State + */ +#define MI_ARB_STATE 0x20e4 + +/* Cache mode 0 reg. + * - Manipulating render cache behaviour is central + * to the concept of zone rendering, tuning this reg can help avoid + * unnecessary render cache reads and even writes (for z/stencil) + * at beginning and end of scene. + * + * - To change a bit, write to this reg with a mask bit set and the + * bit of interest either set or cleared. EG: (BIT<<16) | BIT to set. + */ +#define Cache_Mode_0 0x2120 +#define CACHE_MODE_0 0x2120 +#define CM0_MASK_SHIFT 16 +#define CM0_IZ_OPT_DISABLE (1<<6) +#define CM0_ZR_OPT_DISABLE (1<<5) +#define CM0_DEPTH_EVICT_DISABLE (1<<4) +#define CM0_COLOR_EVICT_DISABLE (1<<3) +#define CM0_DEPTH_WRITE_DISABLE (1<<1) +#define CM0_RC_OP_FLUSH_DISABLE (1<<0) + + +/* Graphics flush control. A CPU write flushes the GWB of all writes. + * The data is discarded. + */ +#define GFX_FLSH_CNTL 0x2170 + +/* Binner control. Defines the location of the bin pointer list: + */ +#define BINCTL 0x2420 +#define BC_MASK (1 << 9) + +/* Binned scene info. + */ +#define BINSCENE 0x2428 +#define BS_OP_LOAD (1 << 8) +#define BS_MASK (1 << 22) + +/* Bin command parser debug reg: + */ +#define BCPD 0x2480 + +/* Bin memory control debug reg: + */ +#define BMCD 0x2484 + +/* Bin data cache debug reg: + */ +#define BDCD 0x2488 + +/* Binner pointer cache debug reg: + */ +#define BPCD 0x248c + +/* Binner scratch pad debug reg: + */ +#define BINSKPD 0x24f0 + +/* HWB scratch pad debug reg: + */ +#define HWBSKPD 0x24f4 + +/* Binner memory pool reg: + */ +#define BMP_BUFFER 0x2430 +#define BMP_PAGE_SIZE_4K (0 << 10) +#define BMP_BUFFER_SIZE_SHIFT 1 +#define BMP_ENABLE (1 << 0) + +/* Get/put memory from the binner memory pool: + */ +#define BMP_GET 0x2438 +#define BMP_PUT 0x2440 +#define BMP_OFFSET_SHIFT 5 + +/* 3D state packets: + */ +#define GFX_OP_RASTER_RULES ((0x3<<29)|(0x7<<24)) + #define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) #define SC_UPDATE_SCISSOR (0x1<<1) #define SC_ENABLE_MASK (0x1<<0) #define SC_ENABLE (0x1<<0) +#define GFX_OP_LOAD_INDIRECT ((0x3<<29)|(0x1d<<24)|(0x7<<16)) + #define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) #define SCI_YMIN_MASK (0xffff<<16) #define SCI_XMIN_MASK (0xffff<<0) @@ -290,6 +564,7 @@ #define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) +#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4) #define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) #define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) #define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) @@ -301,6 +576,7 @@ #define MI_BATCH_NON_SECURE_I965 (1<<8) #define MI_WAIT_FOR_EVENT ((0x3<<23)) +#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6) #define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) #define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) @@ -308,9 +584,542 @@ #define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) #define ASYNC_FLIP (1<<22) +#define DISPLAY_PLANE_A (0<<20) +#define DISPLAY_PLANE_B (1<<20) + +/* Display regs */ +#define DSPACNTR 0x70180 +#define DSPBCNTR 0x71180 +#define DISPPLANE_SEL_PIPE_MASK (1<<24) + +/* Define the region of interest for the binner: + */ +#define CMD_OP_BIN_CONTROL ((0x3<<29)|(0x1d<<24)|(0x84<<16)|4) #define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) -#define READ_BREADCRUMB(dev_priv) (((u32 *)(dev_priv->hw_status_page))[5]) +#define CMD_MI_FLUSH (0x04 << 23) +#define MI_NO_WRITE_FLUSH (1 << 2) +#define MI_READ_FLUSH (1 << 0) +#define MI_EXE_FLUSH (1 << 1) +#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ +#define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ + +#define BREADCRUMB_BITS 31 +#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1) + +#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) +#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) + +#define BLC_PWM_CTL 0x61254 +#define BACKLIGHT_MODULATION_FREQ_SHIFT (17) + +#define BLC_PWM_CTL2 0x61250 +/** + * This is the most significant 15 bits of the number of backlight cycles in a + * complete cycle of the modulated backlight control. + * + * The actual value is this field multiplied by two. + */ +#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) +#define BLM_LEGACY_MODE (1 << 16) +/** + * This is the number of cycles out of the backlight modulation cycle for which + * the backlight is on. + * + * This field must be no greater than the number of cycles in the complete + * backlight modulation cycle. + */ +#define BACKLIGHT_DUTY_CYCLE_SHIFT (0) +#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) + +#define I915_GCFGC 0xf0 +#define I915_LOW_FREQUENCY_ENABLE (1 << 7) +#define I915_DISPLAY_CLOCK_190_200_MHZ (0 << 4) +#define I915_DISPLAY_CLOCK_333_MHZ (4 << 4) +#define I915_DISPLAY_CLOCK_MASK (7 << 4) + +#define I855_HPLLCC 0xc0 +#define I855_CLOCK_CONTROL_MASK (3 << 0) +#define I855_CLOCK_133_200 (0 << 0) +#define I855_CLOCK_100_200 (1 << 0) +#define I855_CLOCK_100_133 (2 << 0) +#define I855_CLOCK_166_250 (3 << 0) + +/* p317, 319 + */ +#define VCLK2_VCO_M 0x6008 /* treat as 16 bit? (includes msbs) */ +#define VCLK2_VCO_N 0x600a +#define VCLK2_VCO_DIV_SEL 0x6012 + +#define VCLK_DIVISOR_VGA0 0x6000 +#define VCLK_DIVISOR_VGA1 0x6004 +#define VCLK_POST_DIV 0x6010 +/** Selects a post divisor of 4 instead of 2. */ +# define VGA1_PD_P2_DIV_4 (1 << 15) +/** Overrides the p2 post divisor field */ +# define VGA1_PD_P1_DIV_2 (1 << 13) +# define VGA1_PD_P1_SHIFT 8 +/** P1 value is 2 greater than this field */ +# define VGA1_PD_P1_MASK (0x1f << 8) +/** Selects a post divisor of 4 instead of 2. */ +# define VGA0_PD_P2_DIV_4 (1 << 7) +/** Overrides the p2 post divisor field */ +# define VGA0_PD_P1_DIV_2 (1 << 5) +# define VGA0_PD_P1_SHIFT 0 +/** P1 value is 2 greater than this field */ +# define VGA0_PD_P1_MASK (0x1f << 0) + +#define DSPCLK_GATE_D 0x6200 + +/* I830 CRTC registers */ +#define HTOTAL_A 0x60000 +#define HBLANK_A 0x60004 +#define HSYNC_A 0x60008 +#define VTOTAL_A 0x6000c +#define VBLANK_A 0x60010 +#define VSYNC_A 0x60014 +#define PIPEASRC 0x6001c +#define BCLRPAT_A 0x60020 +#define VSYNCSHIFT_A 0x60028 + +#define HTOTAL_B 0x61000 +#define HBLANK_B 0x61004 +#define HSYNC_B 0x61008 +#define VTOTAL_B 0x6100c +#define VBLANK_B 0x61010 +#define VSYNC_B 0x61014 +#define PIPEBSRC 0x6101c +#define BCLRPAT_B 0x61020 +#define VSYNCSHIFT_B 0x61028 + +#define PP_STATUS 0x61200 +# define PP_ON (1 << 31) +/** + * Indicates that all dependencies of the panel are on: + * + * - PLL enabled + * - pipe enabled + * - LVDS/DVOB/DVOC on + */ +# define PP_READY (1 << 30) +# define PP_SEQUENCE_NONE (0 << 28) +# define PP_SEQUENCE_ON (1 << 28) +# define PP_SEQUENCE_OFF (2 << 28) +# define PP_SEQUENCE_MASK 0x30000000 +#define PP_CONTROL 0x61204 +# define POWER_TARGET_ON (1 << 0) + +#define LVDSPP_ON 0x61208 +#define LVDSPP_OFF 0x6120c +#define PP_CYCLE 0x61210 + +#define PFIT_CONTROL 0x61230 +# define PFIT_ENABLE (1 << 31) +# define PFIT_PIPE_MASK (3 << 29) +# define PFIT_PIPE_SHIFT 29 +# define VERT_INTERP_DISABLE (0 << 10) +# define VERT_INTERP_BILINEAR (1 << 10) +# define VERT_INTERP_MASK (3 << 10) +# define VERT_AUTO_SCALE (1 << 9) +# define HORIZ_INTERP_DISABLE (0 << 6) +# define HORIZ_INTERP_BILINEAR (1 << 6) +# define HORIZ_INTERP_MASK (3 << 6) +# define HORIZ_AUTO_SCALE (1 << 5) +# define PANEL_8TO6_DITHER_ENABLE (1 << 3) + +#define PFIT_PGM_RATIOS 0x61234 +# define PFIT_VERT_SCALE_MASK 0xfff00000 +# define PFIT_HORIZ_SCALE_MASK 0x0000fff0 + +#define PFIT_AUTO_RATIOS 0x61238 + + +#define DPLL_A 0x06014 +#define DPLL_B 0x06018 +# define DPLL_VCO_ENABLE (1 << 31) +# define DPLL_DVO_HIGH_SPEED (1 << 30) +# define DPLL_SYNCLOCK_ENABLE (1 << 29) +# define DPLL_VGA_MODE_DIS (1 << 28) +# define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ +# define DPLLB_MODE_LVDS (2 << 26) /* i915 */ +# define DPLL_MODE_MASK (3 << 26) +# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ +# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ +# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ +# define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */ +# define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ +# define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ +/** + * The i830 generation, in DAC/serial mode, defines p1 as two plus this + * bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set. + */ +# define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 +/** + * The i830 generation, in LVDS mode, defines P1 as the bit number set within + * this field (only one bit may be set). + */ +# define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000 +# define DPLL_FPA01_P1_POST_DIV_SHIFT 16 +# define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required in DVO non-gang */ +# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ +# define PLL_REF_INPUT_DREFCLK (0 << 13) +# define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ +# define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */ +# define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) +# define PLL_REF_INPUT_MASK (3 << 13) +# define PLL_LOAD_PULSE_PHASE_SHIFT 9 +/* + * Parallel to Serial Load Pulse phase selection. + * Selects the phase for the 10X DPLL clock for the PCIe + * digital display port. The range is 4 to 13; 10 or more + * is just a flip delay. The default is 6 + */ +# define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) +# define DISPLAY_RATE_SELECT_FPA1 (1 << 8) + +/** + * SDVO multiplier for 945G/GM. Not used on 965. + * + * \sa DPLL_MD_UDI_MULTIPLIER_MASK + */ +# define SDVO_MULTIPLIER_MASK 0x000000ff +# define SDVO_MULTIPLIER_SHIFT_HIRES 4 +# define SDVO_MULTIPLIER_SHIFT_VGA 0 + +/** @defgroup DPLL_MD + * @{ + */ +/** Pipe A SDVO/UDI clock multiplier/divider register for G965. */ +#define DPLL_A_MD 0x0601c +/** Pipe B SDVO/UDI clock multiplier/divider register for G965. */ +#define DPLL_B_MD 0x06020 +/** + * UDI pixel divider, controlling how many pixels are stuffed into a packet. + * + * Value is pixels minus 1. Must be set to 1 pixel for SDVO. + */ +# define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 +# define DPLL_MD_UDI_DIVIDER_SHIFT 24 +/** UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */ +# define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 +# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 +/** + * SDVO/UDI pixel multiplier. + * + * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus + * clock rate is 10 times the DPLL clock. At low resolution/refresh rate + * modes, the bus rate would be below the limits, so SDVO allows for stuffing + * dummy bytes in the datastream at an increased clock rate, with both sides of + * the link knowing how many bytes are fill. + * + * So, for a mode with a dotclock of 65Mhz, we would want to double the clock + * rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be + * set to 130Mhz, and the SDVO multiplier set to 2x in this register and + * through an SDVO command. + * + * This register field has values of multiplication factor minus 1, with + * a maximum multiplier of 5 for SDVO. + */ +# define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 +# define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 +/** SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK. + * This best be set to the default value (3) or the CRT won't work. No, + * I don't entirely understand what this does... + */ +# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f +# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 +/** @} */ + +#define DPLL_TEST 0x606c +# define DPLLB_TEST_SDVO_DIV_1 (0 << 22) +# define DPLLB_TEST_SDVO_DIV_2 (1 << 22) +# define DPLLB_TEST_SDVO_DIV_4 (2 << 22) +# define DPLLB_TEST_SDVO_DIV_MASK (3 << 22) +# define DPLLB_TEST_N_BYPASS (1 << 19) +# define DPLLB_TEST_M_BYPASS (1 << 18) +# define DPLLB_INPUT_BUFFER_ENABLE (1 << 16) +# define DPLLA_TEST_N_BYPASS (1 << 3) +# define DPLLA_TEST_M_BYPASS (1 << 2) +# define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) + +#define ADPA 0x61100 +#define ADPA_DAC_ENABLE (1<<31) +#define ADPA_DAC_DISABLE 0 +#define ADPA_PIPE_SELECT_MASK (1<<30) +#define ADPA_PIPE_A_SELECT 0 +#define ADPA_PIPE_B_SELECT (1<<30) +#define ADPA_USE_VGA_HVPOLARITY (1<<15) +#define ADPA_SETS_HVPOLARITY 0 +#define ADPA_VSYNC_CNTL_DISABLE (1<<11) +#define ADPA_VSYNC_CNTL_ENABLE 0 +#define ADPA_HSYNC_CNTL_DISABLE (1<<10) +#define ADPA_HSYNC_CNTL_ENABLE 0 +#define ADPA_VSYNC_ACTIVE_HIGH (1<<4) +#define ADPA_VSYNC_ACTIVE_LOW 0 +#define ADPA_HSYNC_ACTIVE_HIGH (1<<3) +#define ADPA_HSYNC_ACTIVE_LOW 0 + +#define FPA0 0x06040 +#define FPA1 0x06044 +#define FPB0 0x06048 +#define FPB1 0x0604c +# define FP_N_DIV_MASK 0x003f0000 +# define FP_N_DIV_SHIFT 16 +# define FP_M1_DIV_MASK 0x00003f00 +# define FP_M1_DIV_SHIFT 8 +# define FP_M2_DIV_MASK 0x0000003f +# define FP_M2_DIV_SHIFT 0 + + +#define PORT_HOTPLUG_EN 0x61110 +# define SDVOB_HOTPLUG_INT_EN (1 << 26) +# define SDVOC_HOTPLUG_INT_EN (1 << 25) +# define TV_HOTPLUG_INT_EN (1 << 18) +# define CRT_HOTPLUG_INT_EN (1 << 9) +# define CRT_HOTPLUG_FORCE_DETECT (1 << 3) + +#define PORT_HOTPLUG_STAT 0x61114 +# define CRT_HOTPLUG_INT_STATUS (1 << 11) +# define TV_HOTPLUG_INT_STATUS (1 << 10) +# define CRT_HOTPLUG_MONITOR_MASK (3 << 8) +# define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) +# define CRT_HOTPLUG_MONITOR_MONO (2 << 8) +# define CRT_HOTPLUG_MONITOR_NONE (0 << 8) +# define SDVOC_HOTPLUG_INT_STATUS (1 << 7) +# define SDVOB_HOTPLUG_INT_STATUS (1 << 6) + +#define SDVOB 0x61140 +#define SDVOC 0x61160 +#define SDVO_ENABLE (1 << 31) +#define SDVO_PIPE_B_SELECT (1 << 30) +#define SDVO_STALL_SELECT (1 << 29) +#define SDVO_INTERRUPT_ENABLE (1 << 26) +/** + * 915G/GM SDVO pixel multiplier. + * + * Programmed value is multiplier - 1, up to 5x. + * + * \sa DPLL_MD_UDI_MULTIPLIER_MASK + */ +#define SDVO_PORT_MULTIPLY_MASK (7 << 23) +#define SDVO_PORT_MULTIPLY_SHIFT 23 +#define SDVO_PHASE_SELECT_MASK (15 << 19) +#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) +#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) +#define SDVOC_GANG_MODE (1 << 16) +#define SDVO_BORDER_ENABLE (1 << 7) +#define SDVOB_PCIE_CONCURRENCY (1 << 3) +#define SDVO_DETECTED (1 << 2) +/* Bits to be preserved when writing */ +#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14)) +#define SDVOC_PRESERVE_MASK (1 << 17) + +/** @defgroup LVDS + * @{ + */ +/** + * This register controls the LVDS output enable, pipe selection, and data + * format selection. + * + * All of the clock/data pairs are force powered down by power sequencing. + */ +#define LVDS 0x61180 +/** + * Enables the LVDS port. This bit must be set before DPLLs are enabled, as + * the DPLL semantics change when the LVDS is assigned to that pipe. + */ +# define LVDS_PORT_EN (1 << 31) +/** Selects pipe B for LVDS data. Must be set on pre-965. */ +# define LVDS_PIPEB_SELECT (1 << 30) + +/** + * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per + * pixel. + */ +# define LVDS_A0A2_CLKA_POWER_MASK (3 << 8) +# define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8) +# define LVDS_A0A2_CLKA_POWER_UP (3 << 8) +/** + * Controls the A3 data pair, which contains the additional LSBs for 24 bit + * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be + * on. + */ +# define LVDS_A3_POWER_MASK (3 << 6) +# define LVDS_A3_POWER_DOWN (0 << 6) +# define LVDS_A3_POWER_UP (3 << 6) +/** + * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP + * is set. + */ +# define LVDS_CLKB_POWER_MASK (3 << 4) +# define LVDS_CLKB_POWER_DOWN (0 << 4) +# define LVDS_CLKB_POWER_UP (3 << 4) + +/** + * Controls the B0-B3 data pairs. This must be set to match the DPLL p2 + * setting for whether we are in dual-channel mode. The B3 pair will + * additionally only be powered up when LVDS_A3_POWER_UP is set. + */ +# define LVDS_B0B3_POWER_MASK (3 << 2) +# define LVDS_B0B3_POWER_DOWN (0 << 2) +# define LVDS_B0B3_POWER_UP (3 << 2) + +#define PIPEACONF 0x70008 +#define PIPEACONF_ENABLE (1<<31) +#define PIPEACONF_DISABLE 0 +#define PIPEACONF_DOUBLE_WIDE (1<<30) +#define I965_PIPECONF_ACTIVE (1<<30) +#define PIPEACONF_SINGLE_WIDE 0 +#define PIPEACONF_PIPE_UNLOCKED 0 +#define PIPEACONF_PIPE_LOCKED (1<<25) +#define PIPEACONF_PALETTE 0 +#define PIPEACONF_GAMMA (1<<24) +#define PIPECONF_FORCE_BORDER (1<<25) +#define PIPECONF_PROGRESSIVE (0 << 21) +#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) +#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) + +#define PIPEBCONF 0x71008 +#define PIPEBCONF_ENABLE (1<<31) +#define PIPEBCONF_DISABLE 0 +#define PIPEBCONF_DOUBLE_WIDE (1<<30) +#define PIPEBCONF_DISABLE 0 +#define PIPEBCONF_GAMMA (1<<24) +#define PIPEBCONF_PALETTE 0 + +#define PIPEBGCMAXRED 0x71010 +#define PIPEBGCMAXGREEN 0x71014 +#define PIPEBGCMAXBLUE 0x71018 +#define PIPEBSTAT 0x71024 +#define PIPEBFRAMEHIGH 0x71040 +#define PIPEBFRAMEPIXEL 0x71044 + +#define DSPACNTR 0x70180 +#define DSPBCNTR 0x71180 +#define DISPLAY_PLANE_ENABLE (1<<31) +#define DISPLAY_PLANE_DISABLE 0 +#define DISPPLANE_GAMMA_ENABLE (1<<30) +#define DISPPLANE_GAMMA_DISABLE 0 +#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) +#define DISPPLANE_8BPP (0x2<<26) +#define DISPPLANE_15_16BPP (0x4<<26) +#define DISPPLANE_16BPP (0x5<<26) +#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) +#define DISPPLANE_32BPP (0x7<<26) +#define DISPPLANE_STEREO_ENABLE (1<<25) +#define DISPPLANE_STEREO_DISABLE 0 +#define DISPPLANE_SEL_PIPE_MASK (1<<24) +#define DISPPLANE_SEL_PIPE_A 0 +#define DISPPLANE_SEL_PIPE_B (1<<24) +#define DISPPLANE_SRC_KEY_ENABLE (1<<22) +#define DISPPLANE_SRC_KEY_DISABLE 0 +#define DISPPLANE_LINE_DOUBLE (1<<20) +#define DISPPLANE_NO_LINE_DOUBLE 0 +#define DISPPLANE_STEREO_POLARITY_FIRST 0 +#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) +/* plane B only */ +#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) +#define DISPPLANE_ALPHA_TRANS_DISABLE 0 +#define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0 +#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) + +#define DSPABASE 0x70184 +#define DSPASTRIDE 0x70188 + +#define DSPBBASE 0x71184 +#define DSPBADDR DSPBBASE +#define DSPBSTRIDE 0x71188 + +#define DSPAKEYVAL 0x70194 +#define DSPAKEYMASK 0x70198 + +#define DSPAPOS 0x7018C /* reserved */ +#define DSPASIZE 0x70190 +#define DSPBPOS 0x7118C +#define DSPBSIZE 0x71190 + +#define DSPASURF 0x7019C +#define DSPATILEOFF 0x701A4 + +#define DSPBSURF 0x7119C +#define DSPBTILEOFF 0x711A4 + +#define VGACNTRL 0x71400 +# define VGA_DISP_DISABLE (1 << 31) +# define VGA_2X_MODE (1 << 30) +# define VGA_PIPE_B_SELECT (1 << 29) + +/* + * Some BIOS scratch area registers. The 845 (and 830?) store the amount + * of video memory available to the BIOS in SWF1. + */ + +#define SWF0 0x71410 + +/* + * 855 scratch registers. + */ +#define SWF10 0x70410 + +#define SWF30 0x72414 + +/* + * Overlay registers. These are overlay registers accessed via MMIO. + * Those loaded via the overlay register page are defined in i830_video.c. + */ +#define OVADD 0x30000 + +#define DOVSTA 0x30008 +#define OC_BUF (0x3<<20) + +#define OGAMC5 0x30010 +#define OGAMC4 0x30014 +#define OGAMC3 0x30018 +#define OGAMC2 0x3001c +#define OGAMC1 0x30020 +#define OGAMC0 0x30024 +/* + * Palette registers + */ +#define PALETTE_A 0x0a000 +#define PALETTE_B 0x0a800 + +#define IS_I830(dev) ((dev)->pci_device == 0x3577) +#define IS_845G(dev) ((dev)->pci_device == 0x2562) +#define IS_I85X(dev) ((dev)->pci_device == 0x3582) +#define IS_I855(dev) ((dev)->pci_device == 0x3582) +#define IS_I865G(dev) ((dev)->pci_device == 0x2572) + +#define IS_I915G(dev) ((dev)->pci_device == 0x2582 || (dev)->pci_device == 0x258a) +#define IS_I915GM(dev) ((dev)->pci_device == 0x2592) +#define IS_I945G(dev) ((dev)->pci_device == 0x2772) +#define IS_I945GM(dev) ((dev)->pci_device == 0x27A2 ||\ + (dev)->pci_device == 0x27AE) +#define IS_I965G(dev) ((dev)->pci_device == 0x2972 || \ + (dev)->pci_device == 0x2982 || \ + (dev)->pci_device == 0x2992 || \ + (dev)->pci_device == 0x29A2 || \ + (dev)->pci_device == 0x2A02 || \ + (dev)->pci_device == 0x2A12 || \ + (dev)->pci_device == 0x2A42) + +#define IS_I965GM(dev) ((dev)->pci_device == 0x2A02) + +#define IS_IGD_GM(dev) ((dev)->pci_device == 0x2A42) + +#define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \ + (dev)->pci_device == 0x29B2 || \ + (dev)->pci_device == 0x29D2) + +#define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \ + IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev)) + +#define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \ + IS_I945GM(dev) || IS_I965GM(dev) || IS_IGD_GM(dev)) + +#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev)) + +#define PRIMARY_RINGBUFFER_SIZE (128*1024) #endif --- linux-2.6.24.orig/drivers/char/drm/drm_lock.c +++ linux-2.6.24/drivers/char/drm/drm_lock.c @@ -53,6 +53,7 @@ DECLARE_WAITQUEUE(entry, current); struct drm_lock *lock = data; int ret = 0; + unsigned long irqflags; ++file_priv->lock_count; @@ -71,9 +72,9 @@ return -EINVAL; add_wait_queue(&dev->lock.lock_queue, &entry); - spin_lock(&dev->lock.spinlock); + spin_lock_irqsave(&dev->lock.spinlock, irqflags); dev->lock.user_waiters++; - spin_unlock(&dev->lock.spinlock); + spin_unlock_irqrestore(&dev->lock.spinlock, irqflags); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); if (!dev->lock.hw_lock) { @@ -95,9 +96,9 @@ break; } } - spin_lock(&dev->lock.spinlock); + spin_lock_irqsave(&dev->lock.spinlock, irqflags); dev->lock.user_waiters--; - spin_unlock(&dev->lock.spinlock); + spin_unlock_irqrestore(&dev->lock.spinlock, irqflags); __set_current_state(TASK_RUNNING); remove_wait_queue(&dev->lock.lock_queue, &entry); @@ -198,8 +199,9 @@ { unsigned int old, new, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; + unsigned long irqflags; - spin_lock(&lock_data->spinlock); + spin_lock_irqsave(&lock_data->spinlock, irqflags); do { old = *lock; if (old & _DRM_LOCK_HELD) @@ -211,7 +213,7 @@ } prev = cmpxchg(lock, old, new); } while (prev != old); - spin_unlock(&lock_data->spinlock); + spin_unlock_irqrestore(&lock_data->spinlock, irqflags); if (_DRM_LOCKING_CONTEXT(old) == context) { if (old & _DRM_LOCK_HELD) { @@ -272,15 +274,16 @@ { unsigned int old, new, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; + unsigned long irqflags; - spin_lock(&lock_data->spinlock); + spin_lock_irqsave(&lock_data->spinlock, irqflags); if (lock_data->kernel_waiters != 0) { drm_lock_transfer(lock_data, 0); lock_data->idle_has_lock = 1; - spin_unlock(&lock_data->spinlock); + spin_unlock_irqrestore(&lock_data->spinlock, irqflags); return 1; } - spin_unlock(&lock_data->spinlock); + spin_unlock_irqrestore(&lock_data->spinlock, irqflags); do { old = *lock; @@ -344,19 +347,20 @@ void drm_idlelock_take(struct drm_lock_data *lock_data) { int ret = 0; + unsigned long irqflags; - spin_lock(&lock_data->spinlock); + spin_lock_irqsave(&lock_data->spinlock, irqflags); lock_data->kernel_waiters++; if (!lock_data->idle_has_lock) { - spin_unlock(&lock_data->spinlock); + spin_unlock_irqrestore(&lock_data->spinlock, irqflags); ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT); - spin_lock(&lock_data->spinlock); + spin_lock_irqsave(&lock_data->spinlock, irqflags); if (ret == 1) lock_data->idle_has_lock = 1; } - spin_unlock(&lock_data->spinlock); + spin_unlock_irqrestore(&lock_data->spinlock, irqflags); } EXPORT_SYMBOL(drm_idlelock_take); @@ -364,8 +368,9 @@ { unsigned int old, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; + unsigned long irqflags; - spin_lock(&lock_data->spinlock); + spin_lock_irqsave(&lock_data->spinlock, irqflags); if (--lock_data->kernel_waiters == 0) { if (lock_data->idle_has_lock) { do { @@ -376,7 +381,7 @@ lock_data->idle_has_lock = 0; } } - spin_unlock(&lock_data->spinlock); + spin_unlock_irqrestore(&lock_data->spinlock, irqflags); } EXPORT_SYMBOL(drm_idlelock_release); --- linux-2.6.24.orig/drivers/char/drm/drmP.h +++ linux-2.6.24/drivers/char/drm/drmP.h @@ -567,6 +567,8 @@ void (*postclose) (struct drm_device *, struct drm_file *); void (*lastclose) (struct drm_device *); int (*unload) (struct drm_device *); + int (*suspend) (struct drm_device *, pm_message_t state); + int (*resume) (struct drm_device *); int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); void (*dma_ready) (struct drm_device *); int (*dma_quiescent) (struct drm_device *); @@ -642,6 +644,7 @@ * may contain multiple heads. */ struct drm_device { + struct device dev; /**< Linux device */ char *unique; /**< Unique identifier: e.g., busid */ int unique_len; /**< Length of unique field */ char *devname; /**< For /proc/interrupts */ @@ -1061,11 +1064,11 @@ extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); /* sysfs support (drm_sysfs.c) */ +struct drm_sysfs_class; extern struct class *drm_sysfs_create(struct module *owner, char *name); -extern void drm_sysfs_destroy(struct class *cs); -extern struct class_device *drm_sysfs_device_add(struct class *cs, - struct drm_head *head); -extern void drm_sysfs_device_remove(struct class_device *class_dev); +extern void drm_sysfs_destroy(void); +extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head); +extern void drm_sysfs_device_remove(struct drm_device *dev); /* * Basic memory manager support (drm_mm.c) --- linux-2.6.24.orig/drivers/char/drm/via_chrome9_mm.h +++ linux-2.6.24/drivers/char/drm/via_chrome9_mm.h @@ -0,0 +1,67 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _VIA_CHROME9_MM_H_ +#define _VIA_CHROME9_MM_H_ +struct drm_via_chrome9_pciemem_ctrl { + enum { + pciemem_copy_from_user = 0, + pciemem_copy_to_user, + pciemem_memset, + } ctrl_type; + unsigned int pcieoffset; + unsigned int size;/*in Byte*/ + unsigned char memsetdata;/*for memset*/ + void *usermode_data;/*user mode data pointer*/ +}; + +extern int via_chrome9_map_init(struct drm_device *dev, + struct drm_via_chrome9_init *init); +extern int via_chrome9_heap_management_init(struct drm_device + *dev, struct drm_via_chrome9_init *init); +extern void via_chrome9_memory_destroy_heap(struct drm_device + *dev, struct drm_via_chrome9_private *dev_priv); +extern int via_chrome9_ioctl_check_vidmem_size(struct drm_device + *dev, void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_pciemem_ctrl(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_allocate_aperture(struct drm_device + *dev, void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_free_aperture(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_allocate_mem_base(struct drm_device + *dev, void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_allocate_mem_wrapper( + struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_freemem_base(struct drm_device + *dev, void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_free_mem_wrapper(struct drm_device + *dev, void *data, struct drm_file *file_priv); +extern void via_chrome9_reclaim_buffers_locked(struct drm_device + *dev, struct drm_file *file_priv); + +#endif + --- linux-2.6.24.orig/drivers/char/drm/r128_cce.c +++ linux-2.6.24/drivers/char/drm/r128_cce.c @@ -353,6 +353,11 @@ DRM_DEBUG("\n"); + if (dev->dev_private) { + DRM_DEBUG("called when already initialized\n"); + return -EINVAL; + } + dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) return -ENOMEM; @@ -650,6 +655,8 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); + DEV_INIT_TEST_WITH_RETURN(dev_priv); + if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) { DRM_DEBUG("%s while CCE running\n", __FUNCTION__); return 0; @@ -672,6 +679,8 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); + DEV_INIT_TEST_WITH_RETURN(dev_priv); + /* Flush any pending CCE commands. This ensures any outstanding * commands are exectuted by the engine before we turn it off. */ @@ -709,10 +718,7 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); - if (!dev_priv) { - DRM_DEBUG("%s called before init done\n", __FUNCTION__); - return -EINVAL; - } + DEV_INIT_TEST_WITH_RETURN(dev_priv); r128_do_cce_reset(dev_priv); @@ -729,6 +735,8 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); + DEV_INIT_TEST_WITH_RETURN(dev_priv); + if (dev_priv->cce_running) { r128_do_cce_flush(dev_priv); } @@ -742,6 +750,8 @@ LOCK_TEST_WITH_RETURN(dev, file_priv); + DEV_INIT_TEST_WITH_RETURN(dev->dev_private); + return r128_do_engine_reset(dev); } --- linux-2.6.24.orig/drivers/char/drm/via_chrome9_dma.h +++ linux-2.6.24/drivers/char/drm/via_chrome9_dma.h @@ -0,0 +1,68 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _VIA_CHROME9_DMA_H_ +#define _VIA_CHROME9_DMA_H_ + +#define MAX_BCI_BUFFER_SIZE 16*1024*1024 + +enum cmd_request_type { + CM_REQUEST_BCI, + CM_REQUEST_DMA, + CM_REQUEST_RB, + CM_REQUEST_RB_FORCED_DMA, + CM_REQUEST_NOTAVAILABLE +}; + +struct cmd_get_space { + unsigned int dwRequestSize; + enum cmd_request_type hint; + volatile unsigned int *pCmdData; +}; + +struct cmd_release_space { + unsigned int dwReleaseSize; +}; + +extern int via_chrome9_hw_init(struct drm_device *dev, + struct drm_via_chrome9_init *init); +extern int via_chrome9_ioctl_flush(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int via_chrome9_ioctl_free(struct drm_device *dev, void *data, + struct drm_file *file_prev); +extern int via_chrome9_ioctl_wait_chip_idle(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_flush_cache(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_flush(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int via_chrome9_ioctl_free(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern unsigned int ProtectSizeValue(unsigned int size); +extern void SetAGPDoubleCmd_inv(struct drm_device *dev); +extern void SetAGPRingCmdRegs_inv(struct drm_device *dev); + +#endif --- linux-2.6.24.orig/drivers/char/drm/Makefile +++ linux-2.6.24/drivers/char/drm/Makefile @@ -18,6 +18,7 @@ sis-objs := sis_drv.o sis_mm.o savage-objs := savage_drv.o savage_bci.o savage_state.o via-objs := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o +via_chrome9-objs := via_chrome9_drv.o via_chrome9_drm.o via_chrome9_mm.o via_chrome9_dma.o ifeq ($(CONFIG_COMPAT),y) drm-objs += drm_ioc32.o @@ -38,5 +39,4 @@ obj-$(CONFIG_DRM_SIS) += sis.o obj-$(CONFIG_DRM_SAVAGE)+= savage.o obj-$(CONFIG_DRM_VIA) +=via.o - - +obj-$(CONFIG_DRM_VIA_CHROME9) += via_chrome9.o --- linux-2.6.24.orig/drivers/char/keyboard.c +++ linux-2.6.24/drivers/char/keyboard.c @@ -1067,6 +1067,8 @@ int code; switch (keycode) { + case KEY_RESERVED: + break; case KEY_PAUSE: put_queue(vc, 0xe1); put_queue(vc, 0x1d | up_flag); @@ -1126,6 +1128,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) { + if (keycode == KEY_RESERVED) + return 0; if (keycode > 127) return -1; --- linux-2.6.24.orig/drivers/char/mem.c +++ linux-2.6.24/drivers/char/mem.c @@ -108,6 +108,30 @@ } #endif +#ifdef CONFIG_NONPROMISC_DEVMEM +static inline int range_is_allowed(unsigned long from, unsigned long to) +{ + unsigned long cursor; + + cursor = from >> PAGE_SHIFT; + while ((cursor << PAGE_SHIFT) < to) { + if (!devmem_is_allowed(cursor)) { + printk(KERN_INFO "Program %s tried to read /dev/mem " + "between %lx->%lx.\n", + current->comm, from, to); + return 0; + } + cursor++; + } + return 1; +} +#else +static inline int range_is_allowed(unsigned long from, unsigned long to) +{ + return 1; +} +#endif + /* * This funcion reads the *physical* memory. The f_pos points directly to the * memory location. @@ -157,6 +181,8 @@ */ ptr = xlate_dev_mem_ptr(p); + if (!range_is_allowed(p, p+count)) + return -EPERM; if (copy_to_user(buf, ptr, sz)) return -EFAULT; buf += sz; @@ -214,6 +240,8 @@ */ ptr = xlate_dev_mem_ptr(p); + if (!range_is_allowed(p, p+sz)) + return -EPERM; copied = copy_from_user(ptr, buf, sz); if (copied) { written += sz - copied; @@ -295,6 +323,7 @@ return 0; } +#ifdef CONFIG_DEVKMEM static int mmap_kmem(struct file * file, struct vm_area_struct * vma) { unsigned long pfn; @@ -315,6 +344,7 @@ vma->vm_pgoff = pfn; return mmap_mem(file, vma); } +#endif #ifdef CONFIG_CRASH_DUMP /* @@ -353,6 +383,7 @@ extern long vread(char *buf, char *addr, unsigned long count); extern long vwrite(char *buf, char *addr, unsigned long count); +#ifdef CONFIG_DEVKMEM /* * This function reads the *virtual* memory as seen by the kernel. */ @@ -557,6 +588,7 @@ *ppos = p; return virtr + wrote; } +#endif #ifdef CONFIG_DEVPORT static ssize_t read_port(struct file * file, char __user * buf, @@ -734,6 +766,7 @@ .get_unmapped_area = get_unmapped_area_mem, }; +#ifdef CONFIG_DEVKMEM static const struct file_operations kmem_fops = { .llseek = memory_lseek, .read = read_kmem, @@ -742,6 +775,7 @@ .open = open_kmem, .get_unmapped_area = get_unmapped_area_mem, }; +#endif static const struct file_operations null_fops = { .llseek = null_lseek, @@ -820,11 +854,13 @@ filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi; break; +#ifdef CONFIG_DEVKMEM case 2: filp->f_op = &kmem_fops; filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi; break; +#endif case 3: filp->f_op = &null_fops; break; @@ -873,7 +909,9 @@ const struct file_operations *fops; } devlist[] = { /* list of minor devices */ {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, +#ifdef CONFIG_DEVKMEM {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, +#endif {3, "null", S_IRUGO | S_IWUGO, &null_fops}, #ifdef CONFIG_DEVPORT {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, --- linux-2.6.24.orig/drivers/char/random.c +++ linux-2.6.24/drivers/char/random.c @@ -1637,15 +1637,20 @@ * value is not cryptographically secure but for several uses the cost of * depleting entropy is too high */ +DEFINE_PER_CPU(__u32 [4], get_random_int_hash); unsigned int get_random_int(void) { - /* - * Use IP's RNG. It suits our purpose perfectly: it re-keys itself - * every second, from the entropy pool (and thus creates a limited - * drain on it), and uses halfMD4Transform within the second. We - * also mix it with jiffies and the PID: - */ - return secure_ip_id((__force __be32)(current->pid + jiffies)); + struct keydata *keyptr; + __u32 *hash = get_cpu_var(get_random_int_hash); + int ret; + + keyptr = get_keyptr(); + hash[0] += current->pid + jiffies + get_cycles() + (int)(long)&ret; + + ret = half_md4_transform(hash, keyptr->secret); + put_cpu_var(get_random_int_hash); + + return ret; } /* --- linux-2.6.24.orig/drivers/char/defkeymap.c_shipped +++ linux-2.6.24/drivers/char/defkeymap.c_shipped @@ -223,40 +223,40 @@ }; struct kbdiacruc accent_table[MAX_DIACR] = { - {'`', 'A', '\300'}, {'`', 'a', '\340'}, - {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, - {'^', 'A', '\302'}, {'^', 'a', '\342'}, - {'~', 'A', '\303'}, {'~', 'a', '\343'}, - {'"', 'A', '\304'}, {'"', 'a', '\344'}, - {'O', 'A', '\305'}, {'o', 'a', '\345'}, - {'0', 'A', '\305'}, {'0', 'a', '\345'}, - {'A', 'A', '\305'}, {'a', 'a', '\345'}, - {'A', 'E', '\306'}, {'a', 'e', '\346'}, - {',', 'C', '\307'}, {',', 'c', '\347'}, - {'`', 'E', '\310'}, {'`', 'e', '\350'}, - {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, - {'^', 'E', '\312'}, {'^', 'e', '\352'}, - {'"', 'E', '\313'}, {'"', 'e', '\353'}, - {'`', 'I', '\314'}, {'`', 'i', '\354'}, - {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, - {'^', 'I', '\316'}, {'^', 'i', '\356'}, - {'"', 'I', '\317'}, {'"', 'i', '\357'}, - {'-', 'D', '\320'}, {'-', 'd', '\360'}, - {'~', 'N', '\321'}, {'~', 'n', '\361'}, - {'`', 'O', '\322'}, {'`', 'o', '\362'}, - {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, - {'^', 'O', '\324'}, {'^', 'o', '\364'}, - {'~', 'O', '\325'}, {'~', 'o', '\365'}, - {'"', 'O', '\326'}, {'"', 'o', '\366'}, - {'/', 'O', '\330'}, {'/', 'o', '\370'}, - {'`', 'U', '\331'}, {'`', 'u', '\371'}, - {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, - {'^', 'U', '\333'}, {'^', 'u', '\373'}, - {'"', 'U', '\334'}, {'"', 'u', '\374'}, - {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, - {'T', 'H', '\336'}, {'t', 'h', '\376'}, - {'s', 's', '\337'}, {'"', 'y', '\377'}, - {'s', 'z', '\337'}, {'i', 'j', '\377'}, + {'`', 'A', 0300}, {'`', 'a', 0340}, + {'\'', 'A', 0301}, {'\'', 'a', 0341}, + {'^', 'A', 0302}, {'^', 'a', 0342}, + {'~', 'A', 0303}, {'~', 'a', 0343}, + {'"', 'A', 0304}, {'"', 'a', 0344}, + {'O', 'A', 0305}, {'o', 'a', 0345}, + {'0', 'A', 0305}, {'0', 'a', 0345}, + {'A', 'A', 0305}, {'a', 'a', 0345}, + {'A', 'E', 0306}, {'a', 'e', 0346}, + {',', 'C', 0307}, {',', 'c', 0347}, + {'`', 'E', 0310}, {'`', 'e', 0350}, + {'\'', 'E', 0311}, {'\'', 'e', 0351}, + {'^', 'E', 0312}, {'^', 'e', 0352}, + {'"', 'E', 0313}, {'"', 'e', 0353}, + {'`', 'I', 0314}, {'`', 'i', 0354}, + {'\'', 'I', 0315}, {'\'', 'i', 0355}, + {'^', 'I', 0316}, {'^', 'i', 0356}, + {'"', 'I', 0317}, {'"', 'i', 0357}, + {'-', 'D', 0320}, {'-', 'd', 0360}, + {'~', 'N', 0321}, {'~', 'n', 0361}, + {'`', 'O', 0322}, {'`', 'o', 0362}, + {'\'', 'O', 0323}, {'\'', 'o', 0363}, + {'^', 'O', 0324}, {'^', 'o', 0364}, + {'~', 'O', 0325}, {'~', 'o', 0365}, + {'"', 'O', 0326}, {'"', 'o', 0366}, + {'/', 'O', 0330}, {'/', 'o', 0370}, + {'`', 'U', 0331}, {'`', 'u', 0371}, + {'\'', 'U', 0332}, {'\'', 'u', 0372}, + {'^', 'U', 0333}, {'^', 'u', 0373}, + {'"', 'U', 0334}, {'"', 'u', 0374}, + {'\'', 'Y', 0335}, {'\'', 'y', 0375}, + {'T', 'H', 0336}, {'t', 'h', 0376}, + {'s', 's', 0337}, {'"', 'y', 0377}, + {'s', 'z', 0337}, {'i', 'j', 0377}, }; unsigned int accent_table_size = 68; --- linux-2.6.24.orig/drivers/bluetooth/hci_usb.c +++ linux-2.6.24/drivers/bluetooth/hci_usb.c @@ -132,6 +132,13 @@ /* Dell laptop with Broadcom chip */ { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, + /* Dell Wireless 370 */ + { USB_DEVICE(0x413c, 0x8156), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, + /* Dell Wireless 410 */ + { USB_DEVICE(0x413c, 0x8152), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, + + /* Broadcom 2046 */ + { USB_DEVICE(0x0a5c, 0x2151), .driver_info = HCI_RESET }, /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET }, @@ -144,6 +151,7 @@ { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, /* RTX Telecom based adapters with buggy SCO support */ + { USB_DEVICE(0x0e5e, 0x6622), .driver_info = HCI_BROKEN_ISOC }, { USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC }, { USB_DEVICE(0x0400, 0x080a), .driver_info = HCI_BROKEN_ISOC }, @@ -1019,8 +1027,10 @@ while ((_urb = _urb_dequeue(q))) { /* reset queue since _urb_dequeue sets it to NULL */ _urb->queue = q; - usb_kill_urb(&_urb->urb); + spin_lock_irqsave(&q->lock, flags); list_add(&_urb->list, &killed); + spin_unlock_irqrestore(&q->lock, flags); + usb_kill_urb(&_urb->urb); } spin_lock_irqsave(&q->lock, flags); --- linux-2.6.24.orig/drivers/bluetooth/dtl1_cs.c +++ linux-2.6.24/drivers/bluetooth/dtl1_cs.c @@ -298,7 +298,10 @@ int boguscount = 0; int iir, lsr; - BUG_ON(!info->hdev); + if (!info || !info->hdev) { + BT_ERR("Call of irq %d for unknown device", irq); + return IRQ_NONE; + } iobase = info->p_dev->io.BasePort1; --- linux-2.6.24.orig/drivers/bluetooth/bluecard_cs.c +++ linux-2.6.24/drivers/bluetooth/bluecard_cs.c @@ -503,7 +503,10 @@ unsigned int iobase; unsigned char reg; - BUG_ON(!info->hdev); + if (!info || !info->hdev) { + BT_ERR("Call of irq %d for unknown device", irq); + return IRQ_NONE; + } if (!test_bit(CARD_READY, &(info->hw_state))) return IRQ_HANDLED; --- linux-2.6.24.orig/drivers/bluetooth/btuart_cs.c +++ linux-2.6.24/drivers/bluetooth/btuart_cs.c @@ -294,7 +294,10 @@ int boguscount = 0; int iir, lsr; - BUG_ON(!info->hdev); + if (!info || !info->hdev) { + BT_ERR("Call of irq %d for unknown device", irq); + return IRQ_NONE; + } iobase = info->p_dev->io.BasePort1; --- linux-2.6.24.orig/drivers/bluetooth/bt3c_cs.c +++ linux-2.6.24/drivers/bluetooth/bt3c_cs.c @@ -344,7 +344,10 @@ unsigned int iobase; int iir; - BUG_ON(!info->hdev); + if (!info || !info->hdev) { + BT_ERR("Call of irq %d for unknown device", irq); + return IRQ_NONE; + } iobase = info->p_dev->io.BasePort1; --- linux-2.6.24.orig/drivers/bluetooth/bcm203x.c +++ linux-2.6.24/drivers/bluetooth/bcm203x.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -42,7 +43,7 @@ #define BT_DBG(D...) #endif -#define VERSION "1.1" +#define VERSION "1.0" static int ignore = 0; @@ -71,7 +72,7 @@ unsigned long state; - struct work_struct work; + struct timer_list timer; struct urb *urb; unsigned char *buffer; @@ -104,7 +105,7 @@ data->state = BCM203X_SELECT_MEMORY; - schedule_work(&data->work); + mod_timer(&data->timer, jiffies + (HZ / 10)); break; case BCM203X_SELECT_MEMORY: @@ -157,10 +158,9 @@ } } -static void bcm203x_work(struct work_struct *work) +static void bcm203x_timer(unsigned long user_data) { - struct bcm203x_data *data = - container_of(work, struct bcm203x_data, work); + struct bcm203x_data *data = (struct bcm203x_data *) user_data; if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) BT_ERR("Can't submit URB"); @@ -247,11 +247,13 @@ release_firmware(firmware); - INIT_WORK(&data->work, bcm203x_work); + init_timer(&data->timer); + data->timer.function = bcm203x_timer; + data->timer.data = (unsigned long) data; usb_set_intfdata(intf, data); - schedule_work(&data->work); + mod_timer(&data->timer, jiffies + HZ); return 0; } --- linux-2.6.24.orig/drivers/dma/ioat_dma.c +++ linux-2.6.24/drivers/dma/ioat_dma.c @@ -726,6 +726,7 @@ if (new) { new->len = len; + new->async_tx.ack = 0; return &new->async_tx; } else return NULL; @@ -749,6 +750,7 @@ if (new) { new->len = len; + new->async_tx.ack = 0; return &new->async_tx; } else return NULL; --- linux-2.6.24.orig/drivers/watchdog/ib700wdt.c +++ linux-2.6.24/drivers/watchdog/ib700wdt.c @@ -155,7 +155,7 @@ return -EINVAL; for (i = 0x0F; i > -1; i--) - if (wd_times[i] > t) + if (wd_times[i] >= t) break; wd_margin = i; return 0; --- linux-2.6.24.orig/drivers/pci/pci.c +++ linux-2.6.24/drivers/pci/pci.c @@ -536,6 +536,7 @@ case PM_EVENT_PRETHAW: /* REVISIT both freeze and pre-thaw "should" use D0 */ case PM_EVENT_SUSPEND: + case PM_EVENT_HIBERNATE: return PCI_D3hot; default: printk("Unrecognized suspend event %d\n", state.event); --- linux-2.6.24.orig/drivers/pci/quirks.c +++ linux-2.6.24/drivers/pci/quirks.c @@ -187,10 +187,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency ); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency ); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C691_0, quirk_vialatency ); /* Must restore this on a resume from RAM */ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency ); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency ); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C691_0, quirk_vialatency ); /* * VIA Apollo VP3 needs ETBF on BT848/878 @@ -869,13 +871,13 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb ); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb ); - -static void __devinit quirk_sb600_sata(struct pci_dev *pdev) +static void __devinit quirk_amd_ide_mode(struct pci_dev *pdev) { - /* set sb600 sata to ahci mode */ - if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - u8 tmp; + /* set sb600/sb700/sb800 sata to ahci mode */ + u8 tmp; + pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &tmp); + if (tmp == 0x01) { pci_read_config_byte(pdev, 0x40, &tmp); pci_write_config_byte(pdev, 0x40, tmp|1); pci_write_config_byte(pdev, 0x9, 1); @@ -883,10 +885,13 @@ pci_write_config_byte(pdev, 0x40, tmp); pdev->class = PCI_CLASS_STORAGE_SATA_AHCI; + dev_info(&pdev->dev, "set SATA to AHCI mode\n"); } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_sb600_sata); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_sb600_sata); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode); /* * Serverworks CSB5 IDE does not fully support native mode @@ -950,6 +955,12 @@ * accesses to the SMBus registers, with potentially bad effects. Thus you * should be very careful when adding new entries: if SMM is accessing the * Intel SMBus, this is a very good reason to leave it hidden. + * + * Likewise, many recent laptops use ACPI for thermal management. If the + * ACPI DSDT code accesses the SMBus, then Linux should not access it + * natively, and keeping the SMBus hidden is the right thing to do. If you + * are about to add an entry in the table below, please first disassemble + * the DSDT and double-check that there is no code accessing the SMBus. */ static int asus_hides_smbus; @@ -1022,11 +1033,6 @@ case 0x12bd: /* HP D530 */ asus_hides_smbus = 1; } - else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) - switch (dev->subsystem_device) { - case 0x099c: /* HP Compaq nx6110 */ - asus_hides_smbus = 1; - } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG)) { if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) switch(dev->subsystem_device) { @@ -1711,10 +1717,89 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, quirk_nvidia_ck804_msi_ht_cap); +/* + * Force enable MSI mapping capability on HT bridges */ +static inline void ht_enable_msi_mapping(struct pci_dev *dev) +{ + int pos, ttl = 48; + + pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); + while (pos && ttl--) { + u8 flags; + + if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, + &flags) == 0) { + dev_info(&dev->dev, "Enabling HT MSI Mapping\n"); + + pci_write_config_byte(dev, pos + HT_MSI_FLAGS, + flags | HT_MSI_FLAGS_ENABLE); + } + pos = pci_find_next_ht_capability(dev, pos, + HT_CAPTYPE_MSI_MAPPING); + } +} + +static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) +{ + struct pci_dev *host_bridge; + int pos, ttl = 48; + + /* + * HT MSI mapping should be disabled on devices that are below + * a non-Hypertransport host bridge. Locate the host bridge... + */ + host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)); + if (host_bridge == NULL) { + dev_warn(&dev->dev, + "nv_msi_ht_cap_quirk didn't locate host bridge\n"); + return; + } + + pos = pci_find_ht_capability(host_bridge, HT_CAPTYPE_SLAVE); + if (pos != 0) { + /* Host bridge is to HT */ + ht_enable_msi_mapping(dev); + return; + } + + /* Host bridge is not to HT, disable HT MSI mapping on this device */ + pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); + while (pos && ttl--) { + u8 flags; + + if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, + &flags) == 0) { + dev_info(&dev->dev, "Quirk disabling HT MSI mapping"); + pci_write_config_byte(dev, pos + HT_MSI_FLAGS, + flags & ~HT_MSI_FLAGS_ENABLE); + } + pos = pci_find_next_ht_capability(dev, pos, + HT_CAPTYPE_MSI_MAPPING); + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk); + static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev) { dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG; } +static void __devinit quirk_msi_intx_disable_ati_bug(struct pci_dev *dev) +{ + struct pci_dev *p; + + /* SB700 MSI issue will be fixed at HW level from revision A21, + * we need check PCI REVISION ID of SMBus controller to get SB700 + * revision. + */ + p = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, + NULL); + if (!p) + return; + + if ((p->revision < 0x3B) && (p->revision >= 0x30)) + dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG; + pci_dev_put(p); +} DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780, quirk_msi_intx_disable_bug); @@ -1735,17 +1820,15 @@ quirk_msi_intx_disable_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4390, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4391, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4392, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4393, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4394, - quirk_msi_intx_disable_bug); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4395, - quirk_msi_intx_disable_bug); + quirk_msi_intx_disable_ati_bug); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4373, quirk_msi_intx_disable_bug); --- linux-2.6.24.orig/drivers/pci/setup-res.c +++ linux-2.6.24/drivers/pci/setup-res.c @@ -158,7 +158,7 @@ } if (ret) { - printk(KERN_ERR "PCI: Failed to allocate %s resource " + printk(KERN_WARNING "PCI: Failed to allocate %s resource " "#%d:%llx@%llx for %s\n", res->flags & IORESOURCE_IO ? "I/O" : "mem", resno, (unsigned long long)size, @@ -196,7 +196,7 @@ } if (ret) { - printk(KERN_ERR "PCI: Failed to allocate %s resource " + printk(KERN_WARNING "PCI: Failed to allocate %s resource " "#%d:%llx@%llx for %s\n", res->flags & IORESOURCE_IO ? "I/O" : "mem", resno, (unsigned long long)(res->end - res->start + 1), --- linux-2.6.24.orig/drivers/pci/pci.h +++ linux-2.6.24/drivers/pci/pci.h @@ -39,9 +39,11 @@ #ifdef CONFIG_PCI_MSI void pci_no_msi(void); +void pci_yes_msi(void); extern void pci_msi_init_pci_dev(struct pci_dev *dev); #else static inline void pci_no_msi(void) { } +static inline void pci_yes_msi(void) { } static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } #endif --- linux-2.6.24.orig/drivers/base/platform.c +++ linux-2.6.24/drivers/base/platform.c @@ -647,7 +647,7 @@ high_totalram += high_totalram - 1; mask = (((u64)high_totalram) << 32) + 0xffffffff; } - return mask & *dev->dma_mask; + return mask; } EXPORT_SYMBOL_GPL(dma_get_required_mask); #endif --- linux-2.6.24.orig/drivers/md/raid5.c +++ linux-2.6.24/drivers/md/raid5.c @@ -2348,25 +2348,15 @@ static void handle_parity_checks5(raid5_conf_t *conf, struct stripe_head *sh, struct stripe_head_state *s, int disks) { + int canceled_check = 0; + set_bit(STRIPE_HANDLE, &sh->state); - /* Take one of the following actions: - * 1/ start a check parity operation if (uptodate == disks) - * 2/ finish a check parity operation and act on the result - * 3/ skip to the writeback section if we previously - * initiated a recovery operation - */ - if (s->failed == 0 && - !test_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending)) { - if (!test_and_set_bit(STRIPE_OP_CHECK, &sh->ops.pending)) { - BUG_ON(s->uptodate != disks); - clear_bit(R5_UPTODATE, &sh->dev[sh->pd_idx].flags); - sh->ops.count++; - s->uptodate--; - } else if ( - test_and_clear_bit(STRIPE_OP_CHECK, &sh->ops.complete)) { - clear_bit(STRIPE_OP_CHECK, &sh->ops.ack); - clear_bit(STRIPE_OP_CHECK, &sh->ops.pending); + /* complete a check operation */ + if (test_and_clear_bit(STRIPE_OP_CHECK, &sh->ops.complete)) { + clear_bit(STRIPE_OP_CHECK, &sh->ops.ack); + clear_bit(STRIPE_OP_CHECK, &sh->ops.pending); + if (s->failed == 0) { if (sh->ops.zero_sum_result == 0) /* parity is correct (on disc, * not in buffer any more) @@ -2391,7 +2381,8 @@ s->uptodate++; } } - } + } else + canceled_check = 1; /* STRIPE_INSYNC is not set */ } /* check if we can clear a parity disk reconstruct */ @@ -2404,12 +2395,28 @@ clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending); } - /* Wait for check parity and compute block operations to complete - * before write-back + /* start a new check operation if there are no failures, the stripe is + * not insync, and a repair is not in flight */ - if (!test_bit(STRIPE_INSYNC, &sh->state) && - !test_bit(STRIPE_OP_CHECK, &sh->ops.pending) && - !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending)) { + if (s->failed == 0 && + !test_bit(STRIPE_INSYNC, &sh->state) && + !test_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending)) { + if (!test_and_set_bit(STRIPE_OP_CHECK, &sh->ops.pending)) { + BUG_ON(s->uptodate != disks); + clear_bit(R5_UPTODATE, &sh->dev[sh->pd_idx].flags); + sh->ops.count++; + s->uptodate--; + } + } + + /* Wait for check parity and compute block operations to complete + * before write-back. If a failure occurred while the check operation + * was in flight we need to cycle this stripe through handle_stripe + * since the parity block may not be uptodate + */ + if (!canceled_check && !test_bit(STRIPE_INSYNC, &sh->state) && + !test_bit(STRIPE_OP_CHECK, &sh->ops.pending) && + !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending)) { struct r5dev *dev; /* either failed parity check, or recovery is happening */ if (s->failed == 0) @@ -3159,7 +3166,8 @@ atomic_inc(&conf->preread_active_stripes); list_add_tail(&sh->lru, &conf->handle_list); } - } + } else + blk_plug_device(conf->mddev->queue); } static void activate_bit_delay(raid5_conf_t *conf) @@ -3549,7 +3557,8 @@ goto retry; } finish_wait(&conf->wait_for_overlap, &w); - handle_stripe(sh, NULL); + set_bit(STRIPE_HANDLE, &sh->state); + clear_bit(STRIPE_DELAYED, &sh->state); release_stripe(sh); } else { /* cannot get stripe for read-ahead, just give-up */ @@ -3864,7 +3873,7 @@ * During the scan, completed stripes are saved for us by the interrupt * handler, so that they will not have to wait for our next wakeup. */ -static void raid5d (mddev_t *mddev) +static void raid5d(mddev_t *mddev) { struct stripe_head *sh; raid5_conf_t *conf = mddev_to_conf(mddev); @@ -3889,12 +3898,6 @@ activate_bit_delay(conf); } - if (list_empty(&conf->handle_list) && - atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD && - !blk_queue_plugged(mddev->queue) && - !list_empty(&conf->delayed_list)) - raid5_activate_delayed(conf); - while ((bio = remove_bio_from_retry(conf))) { int ok; spin_unlock_irq(&conf->device_lock); --- linux-2.6.24.orig/drivers/md/dm.c +++ linux-2.6.24/drivers/md/dm.c @@ -1566,6 +1566,7 @@ { return md->disk; } +EXPORT_SYMBOL_GPL(dm_disk); int dm_suspended(struct mapped_device *md) { --- linux-2.6.24.orig/drivers/md/md.c +++ linux-2.6.24/drivers/md/md.c @@ -1847,17 +1847,6 @@ __ATTR(state, S_IRUGO|S_IWUSR, state_show, state_store); static ssize_t -super_show(mdk_rdev_t *rdev, char *page) -{ - if (rdev->sb_loaded && rdev->sb_size) { - memcpy(page, page_address(rdev->sb_page), rdev->sb_size); - return rdev->sb_size; - } else - return 0; -} -static struct rdev_sysfs_entry rdev_super = __ATTR_RO(super); - -static ssize_t errors_show(mdk_rdev_t *rdev, char *page) { return sprintf(page, "%d\n", atomic_read(&rdev->corrected_errors)); @@ -1959,7 +1948,6 @@ static struct attribute *rdev_default_attrs[] = { &rdev_state.attr, - &rdev_super.attr, &rdev_errors.attr, &rdev_slot.attr, &rdev_offset.attr, @@ -2881,7 +2869,8 @@ char *e; unsigned long long new = simple_strtoull(buf, &e, 10); - if (mddev->pers->quiesce == NULL) + if (mddev->pers == NULL || + mddev->pers->quiesce == NULL) return -EINVAL; if (buf == e || (*e && *e != '\n')) return -EINVAL; @@ -2909,7 +2898,8 @@ char *e; unsigned long long new = simple_strtoull(buf, &e, 10); - if (mddev->pers->quiesce == NULL) + if (mddev->pers == NULL || + mddev->pers->quiesce == NULL) return -EINVAL; if (buf == e || (*e && *e != '\n')) return -EINVAL; --- linux-2.6.24.orig/drivers/cpuidle/cpuidle.c +++ linux-2.6.24/drivers/cpuidle/cpuidle.c @@ -26,6 +26,8 @@ static int enabled_devices; +static int __cpuidle_register_device(struct cpuidle_device *dev); + /** * cpuidle_idle_call - the main idle loop * @@ -126,6 +128,12 @@ if (!dev->state_count) return -EINVAL; + if (dev->registered == 0) { + ret = __cpuidle_register_device(dev); + if (ret) + return ret; + } + if ((ret = cpuidle_add_state_sysfs(dev))) return ret; @@ -181,10 +189,13 @@ EXPORT_SYMBOL_GPL(cpuidle_disable_device); /** - * cpuidle_register_device - registers a CPU's idle PM feature + * __cpuidle_register_device - internal register function called before register + * and enable routines * @dev: the cpu + * + * cpuidle_lock mutex must be held before this is called */ -int cpuidle_register_device(struct cpuidle_device *dev) +static int __cpuidle_register_device(struct cpuidle_device *dev) { int ret; struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); @@ -196,23 +207,38 @@ init_completion(&dev->kobj_unregister); - mutex_lock(&cpuidle_lock); - per_cpu(cpuidle_devices, dev->cpu) = dev; list_add(&dev->device_list, &cpuidle_detected_devices); if ((ret = cpuidle_add_sysfs(sys_dev))) { - mutex_unlock(&cpuidle_lock); module_put(cpuidle_curr_driver->owner); return ret; } + dev->registered = 1; + return 0; +} + +/** + * cpuidle_register_device - registers a CPU's idle PM feature + * @dev: the cpu + */ +int cpuidle_register_device(struct cpuidle_device *dev) +{ + int ret; + + mutex_lock(&cpuidle_lock); + + if ((ret = __cpuidle_register_device(dev))) { + mutex_unlock(&cpuidle_lock); + return ret; + } + cpuidle_enable_device(dev); cpuidle_install_idle_handler(); mutex_unlock(&cpuidle_lock); return 0; - } EXPORT_SYMBOL_GPL(cpuidle_register_device); @@ -225,6 +251,9 @@ { struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); + if (dev->registered == 0) + return; + cpuidle_pause_and_lock(); cpuidle_disable_device(dev); --- linux-2.6.24.orig/drivers/virtio/virtio.c +++ linux-2.6.24/drivers/virtio/virtio.c @@ -102,9 +102,13 @@ struct virtio_driver *drv = container_of(dev->dev.driver, struct virtio_driver, driver); - dev->config->set_status(dev, dev->config->get_status(dev) - & ~VIRTIO_CONFIG_S_DRIVER); drv->remove(dev); + + /* Driver should have reset device. */ + BUG_ON(dev->config->get_status(dev)); + + /* Acknowledge the device's existence again. */ + add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); return 0; } @@ -130,6 +134,10 @@ dev->dev.bus = &virtio_bus; sprintf(dev->dev.bus_id, "%u", dev->index); + /* We always start by resetting the device, in case a previous + * driver messed it up. This also tests that code path a little. */ + dev->config->reset(dev); + /* Acknowledge that we've seen the device. */ add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); @@ -148,55 +156,18 @@ } EXPORT_SYMBOL_GPL(unregister_virtio_device); -int __virtio_config_val(struct virtio_device *vdev, - u8 type, void *val, size_t size) -{ - void *token; - unsigned int len; - - token = vdev->config->find(vdev, type, &len); - if (!token) - return -ENOENT; - - if (len != size) - return -EIO; - - vdev->config->get(vdev, token, val, size); - return 0; -} -EXPORT_SYMBOL_GPL(__virtio_config_val); - -int virtio_use_bit(struct virtio_device *vdev, - void *token, unsigned int len, unsigned int bitnum) -{ - unsigned long bits[16]; - - /* This makes it convenient to pass-through find() results. */ - if (!token) - return 0; - - /* bit not in range of this bitfield? */ - if (bitnum * 8 >= len / 2) - return 0; - - /* Giant feature bitfields are silly. */ - BUG_ON(len > sizeof(bits)); - vdev->config->get(vdev, token, bits, len); - - if (!test_bit(bitnum, bits)) - return 0; - - /* Set acknowledge bit, and write it back. */ - set_bit(bitnum + len * 8 / 2, bits); - vdev->config->set(vdev, token, bits, len); - return 1; -} -EXPORT_SYMBOL_GPL(virtio_use_bit); - static int virtio_init(void) { if (bus_register(&virtio_bus) != 0) panic("virtio bus registration failed"); return 0; } + +static void __exit virtio_exit(void) +{ + bus_unregister(&virtio_bus); +} core_initcall(virtio_init); +module_exit(virtio_exit); + +MODULE_LICENSE("GPL"); --- linux-2.6.24.orig/drivers/virtio/Kconfig +++ linux-2.6.24/drivers/virtio/Kconfig @@ -1,8 +1,35 @@ # Virtio always gets selected by whoever wants it. config VIRTIO - bool + tristate # Similarly the virtio ring implementation. config VIRTIO_RING - bool + tristate depends on VIRTIO + +config VIRTIO_PCI + tristate "PCI driver for virtio devices (EXPERIMENTAL)" + depends on PCI && EXPERIMENTAL + select VIRTIO + select VIRTIO_RING + ---help--- + This drivers provides support for virtio based paravirtual device + drivers over PCI. This requires that your VMM has appropriate PCI + virtio backends. Most QEMU based VMMs should support these devices + (like KVM or Xen). + + Currently, the ABI is not considered stable so there is no guarantee + that this version of the driver will work with your VMM. + + If unsure, say M. + +config VIRTIO_BALLOON + tristate "Virtio balloon driver (EXPERIMENTAL)" + select VIRTIO + select VIRTIO_RING + ---help--- + This driver supports increasing and decreasing the amount + of memory within a KVM guest. + + If unsure, say M. + --- linux-2.6.24.orig/drivers/virtio/virtio_balloon.c +++ linux-2.6.24/drivers/virtio/virtio_balloon.c @@ -0,0 +1,285 @@ +/* Virtio balloon implementation, inspired by Dor Loar and Marcelo + * Tosatti's implementations. + * + * Copyright 2008 Rusty Russell IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +//#define DEBUG +#include +#include +#include +#include +#include +#include + +struct virtio_balloon +{ + struct virtio_device *vdev; + struct virtqueue *inflate_vq, *deflate_vq; + + /* Where the ballooning thread waits for config to change. */ + wait_queue_head_t config_change; + + /* The thread servicing the balloon. */ + struct task_struct *thread; + + /* Waiting for host to ack the pages we released. */ + struct completion acked; + + /* Do we have to tell Host *before* we reuse pages? */ + bool tell_host_first; + + /* The pages we've told the Host we're not using. */ + unsigned int num_pages; + struct list_head pages; + + /* The array of pfns we tell the Host about. */ + unsigned int num_pfns; + u32 pfns[256]; +}; + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_BALLOON, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static void balloon_ack(struct virtqueue *vq) +{ + struct virtio_balloon *vb; + unsigned int len; + + vb = vq->vq_ops->get_buf(vq, &len); + if (vb) + complete(&vb->acked); +} + +static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq) +{ + struct scatterlist sg; + + sg_init_one(&sg, vb->pfns, sizeof(vb->pfns[0]) * vb->num_pfns); + + init_completion(&vb->acked); + + /* We should always be able to add one buffer to an empty queue. */ + if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) != 0) + BUG(); + vq->vq_ops->kick(vq); + + /* When host has read buffer, this completes via balloon_ack */ + wait_for_completion(&vb->acked); +} + +static void fill_balloon(struct virtio_balloon *vb, size_t num) +{ + /* We can only do one array worth at a time. */ + num = min(num, ARRAY_SIZE(vb->pfns)); + + for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) { + struct page *page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY); + if (!page) { + if (printk_ratelimit()) + dev_printk(KERN_INFO, &vb->vdev->dev, + "Out of puff! Can't get %zu pages\n", + num); + /* Sleep for at least 1/5 of a second before retry. */ + msleep(200); + break; + } + vb->pfns[vb->num_pfns] = page_to_pfn(page); + totalram_pages--; + vb->num_pages++; + list_add(&page->lru, &vb->pages); + } + + /* Didn't get any? Oh well. */ + if (vb->num_pfns == 0) + return; + + tell_host(vb, vb->inflate_vq); +} + +static void release_pages_by_pfn(const u32 pfns[], unsigned int num) +{ + unsigned int i; + + for (i = 0; i < num; i++) { + __free_page(pfn_to_page(pfns[i])); + totalram_pages++; + } +} + +static void leak_balloon(struct virtio_balloon *vb, size_t num) +{ + struct page *page; + + /* We can only do one array worth at a time. */ + num = min(num, ARRAY_SIZE(vb->pfns)); + + for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) { + page = list_first_entry(&vb->pages, struct page, lru); + list_del(&page->lru); + vb->pfns[vb->num_pfns] = page_to_pfn(page); + vb->num_pages--; + } + + if (vb->tell_host_first) { + tell_host(vb, vb->deflate_vq); + release_pages_by_pfn(vb->pfns, vb->num_pfns); + } else { + release_pages_by_pfn(vb->pfns, vb->num_pfns); + tell_host(vb, vb->deflate_vq); + } +} + +static void virtballoon_changed(struct virtio_device *vdev) +{ + struct virtio_balloon *vb = vdev->priv; + + wake_up(&vb->config_change); +} + +static inline s64 towards_target(struct virtio_balloon *vb) +{ + u32 v; + __virtio_config_val(vb->vdev, + offsetof(struct virtio_balloon_config, num_pages), + &v); + return v - vb->num_pages; +} + +static void update_balloon_size(struct virtio_balloon *vb) +{ + __le32 actual = cpu_to_le32(vb->num_pages); + + vb->vdev->config->set(vb->vdev, + offsetof(struct virtio_balloon_config, actual), + &actual, sizeof(actual)); +} + +static int balloon(void *_vballoon) +{ + struct virtio_balloon *vb = _vballoon; + + set_freezable(); + while (!kthread_should_stop()) { + s64 diff; + + try_to_freeze(); + wait_event_interruptible(vb->config_change, + (diff = towards_target(vb)) != 0 + || kthread_should_stop()); + if (diff > 0) + fill_balloon(vb, diff); + else if (diff < 0) + leak_balloon(vb, -diff); + update_balloon_size(vb); + } + return 0; +} + +static int virtballoon_probe(struct virtio_device *vdev) +{ + struct virtio_balloon *vb; + int err; + + vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL); + if (!vb) { + err = -ENOMEM; + goto out; + } + + INIT_LIST_HEAD(&vb->pages); + vb->num_pages = 0; + init_waitqueue_head(&vb->config_change); + vb->vdev = vdev; + + /* We expect two virtqueues. */ + vb->inflate_vq = vdev->config->find_vq(vdev, 0, balloon_ack); + if (IS_ERR(vb->inflate_vq)) { + err = PTR_ERR(vb->inflate_vq); + goto out_free_vb; + } + + vb->deflate_vq = vdev->config->find_vq(vdev, 1, balloon_ack); + if (IS_ERR(vb->deflate_vq)) { + err = PTR_ERR(vb->deflate_vq); + goto out_del_inflate_vq; + } + + vb->thread = kthread_run(balloon, vb, "vballoon"); + if (IS_ERR(vb->thread)) { + err = PTR_ERR(vb->thread); + goto out_del_deflate_vq; + } + + vb->tell_host_first + = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST); + + return 0; + +out_del_deflate_vq: + vdev->config->del_vq(vb->deflate_vq); +out_del_inflate_vq: + vdev->config->del_vq(vb->inflate_vq); +out_free_vb: + kfree(vb); +out: + return err; +} + +static void virtballoon_remove(struct virtio_device *vdev) +{ + struct virtio_balloon *vb = vdev->priv; + + kthread_stop(vb->thread); + + /* There might be pages left in the balloon: free them. */ + while (vb->num_pages) + leak_balloon(vb, vb->num_pages); + + /* Now we reset the device so we can clean up the queues. */ + vdev->config->reset(vdev); + + vdev->config->del_vq(vb->deflate_vq); + vdev->config->del_vq(vb->inflate_vq); + kfree(vb); +} + +static struct virtio_driver virtio_balloon = { + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtballoon_probe, + .remove = __devexit_p(virtballoon_remove), + .config_changed = virtballoon_changed, +}; + +static int __init init(void) +{ + return register_virtio_driver(&virtio_balloon); +} + +static void __exit fini(void) +{ + unregister_virtio_driver(&virtio_balloon); +} +module_init(init); +module_exit(fini); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio balloon driver"); +MODULE_LICENSE("GPL"); --- linux-2.6.24.orig/drivers/virtio/virtio_pci.c +++ linux-2.6.24/drivers/virtio/virtio_pci.c @@ -0,0 +1,450 @@ +/* + * Virtio PCI driver + * + * This module allows virtio devices to be used over a virtual PCI device. + * This can be used with QEMU based VMMs like KVM or Xen. + * + * Copyright IBM Corp. 2007 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Anthony Liguori "); +MODULE_DESCRIPTION("virtio-pci"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1"); + +/* Our device structure */ +struct virtio_pci_device +{ + struct virtio_device vdev; + struct pci_dev *pci_dev; + + /* the IO mapping for the PCI config space */ + void __iomem *ioaddr; + + /* a list of queues so we can dispatch IRQs */ + spinlock_t lock; + struct list_head virtqueues; +}; + +struct virtio_pci_vq_info +{ + /* the actual virtqueue */ + struct virtqueue *vq; + + /* the number of entries in the queue */ + int num; + + /* the index of the queue */ + int queue_index; + + /* the virtual address of the ring queue */ + void *queue; + + /* the list node for the virtqueues list */ + struct list_head node; +}; + +/* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */ +static struct pci_device_id virtio_pci_id_table[] = { + { 0x1af4, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 }, +}; + +MODULE_DEVICE_TABLE(pci, virtio_pci_id_table); + +/* A PCI device has it's own struct device and so does a virtio device so + * we create a place for the virtio devices to show up in sysfs. I think it + * would make more sense for virtio to not insist on having it's own device. */ +static struct device virtio_pci_root = { + .parent = NULL, + .bus_id = "virtio-pci", +}; + +/* Unique numbering for devices under the kvm root */ +static unsigned int dev_index; + +/* Convert a generic virtio device to our structure */ +static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev) +{ + return container_of(vdev, struct virtio_pci_device, vdev); +} + +/* virtio config->feature() implementation */ +static bool vp_feature(struct virtio_device *vdev, unsigned bit) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + u32 mask; + + /* Since this function is supposed to have the side effect of + * enabling a queried feature, we simulate that by doing a read + * from the host feature bitmask and then writing to the guest + * feature bitmask */ + mask = ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES); + if (mask & (1 << bit)) { + mask |= (1 << bit); + iowrite32(mask, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES); + } + + return !!(mask & (1 << bit)); +} + +/* virtio config->get() implementation */ +static void vp_get(struct virtio_device *vdev, unsigned offset, + void *buf, unsigned len) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + void __iomem *ioaddr = vp_dev->ioaddr + VIRTIO_PCI_CONFIG + offset; + u8 *ptr = buf; + int i; + + for (i = 0; i < len; i++) + ptr[i] = ioread8(ioaddr + i); +} + +/* the config->set() implementation. it's symmetric to the config->get() + * implementation */ +static void vp_set(struct virtio_device *vdev, unsigned offset, + const void *buf, unsigned len) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + void __iomem *ioaddr = vp_dev->ioaddr + VIRTIO_PCI_CONFIG + offset; + const u8 *ptr = buf; + int i; + + for (i = 0; i < len; i++) + iowrite8(ptr[i], ioaddr + i); +} + +/* config->{get,set}_status() implementations */ +static u8 vp_get_status(struct virtio_device *vdev) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + return ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS); +} + +static void vp_set_status(struct virtio_device *vdev, u8 status) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + /* We should never be setting status to 0. */ + BUG_ON(status == 0); + return iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS); +} + +static void vp_reset(struct virtio_device *vdev) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + /* 0 status means a reset. */ + return iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS); +} + +/* the notify function used when creating a virt queue */ +static void vp_notify(struct virtqueue *vq) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev); + struct virtio_pci_vq_info *info = vq->priv; + + /* we write the queue's selector into the notification register to + * signal the other end */ + iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY); +} + +/* A small wrapper to also acknowledge the interrupt when it's handled. + * I really need an EIO hook for the vring so I can ack the interrupt once we + * know that we'll be handling the IRQ but before we invoke the callback since + * the callback may notify the host which results in the host attempting to + * raise an interrupt that we would then mask once we acknowledged the + * interrupt. */ +static irqreturn_t vp_interrupt(int irq, void *opaque) +{ + struct virtio_pci_device *vp_dev = opaque; + struct virtio_pci_vq_info *info; + irqreturn_t ret = IRQ_NONE; + unsigned long flags; + u8 isr; + + /* reading the ISR has the effect of also clearing it so it's very + * important to save off the value. */ + isr = ioread8(vp_dev->ioaddr + VIRTIO_PCI_ISR); + + /* It's definitely not us if the ISR was not high */ + if (!isr) + return IRQ_NONE; + + /* Configuration change? Tell driver if it wants to know. */ + if (isr & VIRTIO_PCI_ISR_CONFIG) { + struct virtio_driver *drv; + drv = container_of(vp_dev->vdev.dev.driver, + struct virtio_driver, driver); + + if (drv->config_changed) + drv->config_changed(&vp_dev->vdev); + } + + spin_lock_irqsave(&vp_dev->lock, flags); + list_for_each_entry(info, &vp_dev->virtqueues, node) { + if (vring_interrupt(irq, info->vq) == IRQ_HANDLED) + ret = IRQ_HANDLED; + } + spin_unlock_irqrestore(&vp_dev->lock, flags); + + return ret; +} + +/* the config->find_vq() implementation */ +static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index, + void (*callback)(struct virtqueue *vq)) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + struct virtio_pci_vq_info *info; + struct virtqueue *vq; + unsigned long flags; + u16 num; + int err; + + /* Select the queue we're interested in */ + iowrite16(index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL); + + /* Check if queue is either not available or already active. */ + num = ioread16(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NUM); + if (!num || ioread32(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN)) + return ERR_PTR(-ENOENT); + + /* allocate and fill out our structure the represents an active + * queue */ + info = kmalloc(sizeof(struct virtio_pci_vq_info), GFP_KERNEL); + if (!info) + return ERR_PTR(-ENOMEM); + + info->queue_index = index; + info->num = num; + + info->queue = kzalloc(PAGE_ALIGN(vring_size(num,PAGE_SIZE)), GFP_KERNEL); + if (info->queue == NULL) { + err = -ENOMEM; + goto out_info; + } + + /* activate the queue */ + iowrite32(virt_to_phys(info->queue) >> PAGE_SHIFT, + vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); + + /* create the vring */ + vq = vring_new_virtqueue(info->num, vdev, info->queue, + vp_notify, callback); + if (!vq) { + err = -ENOMEM; + goto out_activate_queue; + } + + vq->priv = info; + info->vq = vq; + + spin_lock_irqsave(&vp_dev->lock, flags); + list_add(&info->node, &vp_dev->virtqueues); + spin_unlock_irqrestore(&vp_dev->lock, flags); + + return vq; + +out_activate_queue: + iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); + kfree(info->queue); +out_info: + kfree(info); + return ERR_PTR(err); +} + +/* the config->del_vq() implementation */ +static void vp_del_vq(struct virtqueue *vq) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev); + struct virtio_pci_vq_info *info = vq->priv; + unsigned long flags; + + spin_lock_irqsave(&vp_dev->lock, flags); + list_del(&info->node); + spin_unlock_irqrestore(&vp_dev->lock, flags); + + vring_del_virtqueue(vq); + + /* Select and deactivate the queue */ + iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL); + iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); + + kfree(info->queue); + kfree(info); +} + +static struct virtio_config_ops virtio_pci_config_ops = { + .feature = vp_feature, + .get = vp_get, + .set = vp_set, + .get_status = vp_get_status, + .set_status = vp_set_status, + .reset = vp_reset, + .find_vq = vp_find_vq, + .del_vq = vp_del_vq, +}; + +/* the PCI probing function */ +static int __devinit virtio_pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id) +{ + struct virtio_pci_device *vp_dev; + int err; + + /* We only own devices >= 0x1000 and <= 0x103f: leave the rest. */ + if (pci_dev->device < 0x1000 || pci_dev->device > 0x103f) + return -ENODEV; + + if (pci_dev->revision != VIRTIO_PCI_ABI_VERSION) { + printk(KERN_ERR "virtio_pci: expected ABI version %d, got %d\n", + VIRTIO_PCI_ABI_VERSION, pci_dev->revision); + return -ENODEV; + } + + /* allocate our structure and fill it out */ + vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL); + if (vp_dev == NULL) + return -ENOMEM; + + snprintf(vp_dev->vdev.dev.bus_id, BUS_ID_SIZE, "virtio%d", dev_index); + vp_dev->vdev.index = dev_index; + dev_index++; + + vp_dev->vdev.dev.parent = &virtio_pci_root; + vp_dev->vdev.config = &virtio_pci_config_ops; + vp_dev->pci_dev = pci_dev; + INIT_LIST_HEAD(&vp_dev->virtqueues); + spin_lock_init(&vp_dev->lock); + + /* enable the device */ + err = pci_enable_device(pci_dev); + if (err) + goto out; + + err = pci_request_regions(pci_dev, "virtio-pci"); + if (err) + goto out_enable_device; + + vp_dev->ioaddr = pci_iomap(pci_dev, 0, 0); + if (vp_dev->ioaddr == NULL) + goto out_req_regions; + + pci_set_drvdata(pci_dev, vp_dev); + + /* we use the subsystem vendor/device id as the virtio vendor/device + * id. this allows us to use the same PCI vendor/device id for all + * virtio devices and to identify the particular virtio driver by + * the subsytem ids */ + vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor; + vp_dev->vdev.id.device = pci_dev->subsystem_device; + + /* register a handler for the queue with the PCI device's interrupt */ + err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED, + vp_dev->vdev.dev.bus_id, vp_dev); + if (err) + goto out_set_drvdata; + + /* finally register the virtio device */ + err = register_virtio_device(&vp_dev->vdev); + if (err) + goto out_req_irq; + + return 0; + +out_req_irq: + free_irq(pci_dev->irq, vp_dev); +out_set_drvdata: + pci_set_drvdata(pci_dev, NULL); + pci_iounmap(pci_dev, vp_dev->ioaddr); +out_req_regions: + pci_release_regions(pci_dev); +out_enable_device: + pci_disable_device(pci_dev); +out: + kfree(vp_dev); + return err; +} + +static void __devexit virtio_pci_remove(struct pci_dev *pci_dev) +{ + struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); + + unregister_virtio_device(&vp_dev->vdev); + free_irq(pci_dev->irq, vp_dev); + pci_set_drvdata(pci_dev, NULL); + pci_iounmap(pci_dev, vp_dev->ioaddr); + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); + kfree(vp_dev); +} + +#ifdef CONFIG_PM +static int virtio_pci_suspend(struct pci_dev *pci_dev, pm_message_t state) +{ + pci_save_state(pci_dev); + pci_set_power_state(pci_dev, PCI_D3hot); + return 0; +} + +static int virtio_pci_resume(struct pci_dev *pci_dev) +{ + pci_restore_state(pci_dev); + pci_set_power_state(pci_dev, PCI_D0); + return 0; +} +#endif + +static struct pci_driver virtio_pci_driver = { + .name = "virtio-pci", + .id_table = virtio_pci_id_table, + .probe = virtio_pci_probe, + .remove = virtio_pci_remove, +#ifdef CONFIG_PM + .suspend = virtio_pci_suspend, + .resume = virtio_pci_resume, +#endif +}; + +static int __init virtio_pci_init(void) +{ + int err; + + err = device_register(&virtio_pci_root); + if (err) + return err; + + err = pci_register_driver(&virtio_pci_driver); + if (err) + device_unregister(&virtio_pci_root); + + return err; +} + +module_init(virtio_pci_init); + +static void __exit virtio_pci_exit(void) +{ + device_unregister(&virtio_pci_root); + pci_unregister_driver(&virtio_pci_driver); +} + +module_exit(virtio_pci_exit); --- linux-2.6.24.orig/drivers/virtio/virtio_ring.c +++ linux-2.6.24/drivers/virtio/virtio_ring.c @@ -87,6 +87,8 @@ if (vq->num_free < out + in) { pr_debug("Can't add buf len %i - avail = %i\n", out + in, vq->num_free); + /* We notify *even if* VRING_USED_F_NO_NOTIFY is set here. */ + vq->notify(&vq->vq); END_USE(vq); return -ENOSPC; } @@ -97,16 +99,14 @@ head = vq->free_head; for (i = vq->free_head; out; i = vq->vring.desc[i].next, out--) { vq->vring.desc[i].flags = VRING_DESC_F_NEXT; - vq->vring.desc[i].addr = (page_to_pfn(sg_page(sg))<offset; + vq->vring.desc[i].addr = sg_phys(sg); vq->vring.desc[i].len = sg->length; prev = i; sg++; } for (; in; i = vq->vring.desc[i].next, in--) { vq->vring.desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE; - vq->vring.desc[i].addr = (page_to_pfn(sg_page(sg))<offset; + vq->vring.desc[i].addr = sg_phys(sg); vq->vring.desc[i].len = sg->length; prev = i; sg++; @@ -171,16 +171,6 @@ vq->num_free++; } -/* FIXME: We need to tell other side about removal, to synchronize. */ -static void vring_shutdown(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - unsigned int i; - - for (i = 0; i < vq->vring.num; i++) - detach_buf(vq, i); -} - static inline bool more_used(const struct vring_virtqueue *vq) { return vq->last_used_idx != vq->vring.used->idx; @@ -220,7 +210,14 @@ return ret; } -static bool vring_restart(struct virtqueue *_vq) +static void vring_disable_cb(struct virtqueue *_vq) +{ + struct vring_virtqueue *vq = to_vvq(_vq); + + vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; +} + +static bool vring_enable_cb(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); @@ -232,7 +229,6 @@ vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; mb(); if (unlikely(more_used(vq))) { - vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; END_USE(vq); return false; } @@ -253,26 +249,34 @@ if (unlikely(vq->broken)) return IRQ_HANDLED; + /* Other side may have missed us turning off the interrupt, + * but we should preserve disable semantic for virtio users. */ + if (unlikely(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) { + pr_debug("virtqueue interrupt after disable for %p\n", vq); + return IRQ_HANDLED; + } + pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback); - if (vq->vq.callback && !vq->vq.callback(&vq->vq)) - vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; + if (vq->vq.callback) + vq->vq.callback(&vq->vq); return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(vring_interrupt); static struct virtqueue_ops vring_vq_ops = { .add_buf = vring_add_buf, .get_buf = vring_get_buf, .kick = vring_kick, - .restart = vring_restart, - .shutdown = vring_shutdown, + .disable_cb = vring_disable_cb, + .enable_cb = vring_enable_cb, }; struct virtqueue *vring_new_virtqueue(unsigned int num, struct virtio_device *vdev, void *pages, void (*notify)(struct virtqueue *), - bool (*callback)(struct virtqueue *)) + void (*callback)(struct virtqueue *)) { struct vring_virtqueue *vq; unsigned int i; @@ -311,9 +315,12 @@ return &vq->vq; } +EXPORT_SYMBOL_GPL(vring_new_virtqueue); void vring_del_virtqueue(struct virtqueue *vq) { kfree(to_vvq(vq)); } +EXPORT_SYMBOL_GPL(vring_del_virtqueue); +MODULE_LICENSE("GPL"); --- linux-2.6.24.orig/drivers/virtio/Makefile +++ linux-2.6.24/drivers/virtio/Makefile @@ -1,2 +1,4 @@ obj-$(CONFIG_VIRTIO) += virtio.o obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o +obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o +obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o --- linux-2.6.24.orig/drivers/mmc/card/block.c +++ linux-2.6.24/drivers/mmc/card/block.c @@ -46,7 +46,7 @@ #define MMC_SHIFT 3 #define MMC_NUM_MINORS (256 >> MMC_SHIFT) -static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; +static DECLARE_BITMAP(dev_use,MMC_NUM_MINORS); /* * There is one mmc_blk_data per slot. --- linux-2.6.24.orig/drivers/mmc/core/core.c +++ linux-2.6.24/drivers/mmc/core/core.c @@ -496,7 +496,7 @@ * This delay must be at least 74 clock sizes, or 1 ms, or the * time required to reach a stable voltage. */ - mmc_delay(2); + mmc_delay(10); } static void mmc_power_off(struct mmc_host *host) --- linux-2.6.24.orig/drivers/mmc/Kconfig +++ linux-2.6.24/drivers/mmc/Kconfig @@ -2,6 +2,8 @@ # MMC subsystem configuration # +menu "MMC/SD/SDIO support, can only select one arch from MMC and MSS" + menuconfig MMC tristate "MMC/SD card support" depends on HAS_IOMEM @@ -17,7 +19,6 @@ help This is an option for use by developers; most people should say N here. This enables MMC core and driver debugging. - if MMC source "drivers/mmc/core/Kconfig" @@ -27,3 +28,22 @@ source "drivers/mmc/host/Kconfig" endif # MMC + +config MSS + tristate "MSS architecture MMC/SD/SDIO Interface support" + help + MSS is an advanced version of the MMC protocol drivers + which abstracts the control layer to encompass multiple + media card formats. Simply define the protocols you + wish to use (one is MMC for instance, another is SD). + + If you want MSS support, you should say M here and also + to the specific drivers for your MSS interface. + +if MSS + +source "drivers/mmc/mss/Kconfig" + +endif + +endmenu --- linux-2.6.24.orig/drivers/mmc/mss/sd_protocol.c +++ linux-2.6.24/drivers/mmc/mss/sd_protocol.c @@ -0,0 +1,1100 @@ +/* + * sd_protocol.c - SD protocol driver + * + * Copyright (C) 2007 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 only + * for now as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * derived from previous mmc code in Linux kernel + * Copyright (c) 2002 Hewlett-Packard Company + * Copyright (c) 2002 Andrew Christian + * Copyright (c) 2006 Bridge Wu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define KBPS 1 +#define MBPS 1000 + +static u32 ts_exp[] = { 100*KBPS, 1*MBPS, 10*MBPS, 100*MBPS, 0, 0, 0, 0 }; +static u32 ts_mul[] = { 0, 1000, 1200, 1300, 1500, 2000, 2500, 3000, + 3500, 4000, 4500, 5000, 5500, 6000, 7000, 8000 }; + +static u32 sd_tran_speed(u8 ts) +{ + u32 clock = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3]; + + dbg5("clock :%d", clock); + return clock; +} + + +static int sd_unpack_r1(struct mss_cmd *cmd, struct sd_response_r1 *r1, struct sd_card *sd_card) +{ + u8 *buf = cmd->response; + + //debug(" result in r1: %d\n", request->result); + //if ( request->result ) return request->result; + + sd_card->errno = SD_ERROR_NONE; + r1->cmd = unstuff_bits(buf, 40, 8, 6); + r1->status = unstuff_bits(buf, 8, 32, 6); + + dbg5("status 0x%x", r1->status); + if (R1_STATUS(r1->status)) { + if (r1->status & R1_OUT_OF_RANGE) + sd_card->errno = SD_ERROR_OUT_OF_RANGE; + if (r1->status & R1_ADDRESS_ERROR) + sd_card->errno = SD_ERROR_ADDRESS; + if (r1->status & R1_BLOCK_LEN_ERROR) + sd_card->errno = SD_ERROR_BLOCK_LEN; + if (r1->status & R1_ERASE_SEQ_ERROR) + sd_card->errno = SD_ERROR_ERASE_SEQ; + if (r1->status & R1_ERASE_PARAM) + sd_card->errno = SD_ERROR_ERASE_PARAM; + if (r1->status & R1_WP_VIOLATION) + sd_card->errno = SD_ERROR_WP_VIOLATION; + if (r1->status & R1_LOCK_UNLOCK_FAILED) + sd_card->errno = SD_ERROR_LOCK_UNLOCK_FAILED; + if (r1->status & R1_COM_CRC_ERROR) + sd_card->errno = SD_ERROR_COM_CRC; + if (r1->status & R1_ILLEGAL_COMMAND) + sd_card->errno = SD_ERROR_ILLEGAL_COMMAND; + if (r1->status & R1_CARD_ECC_FAILED) + sd_card->errno = SD_ERROR_CARD_ECC_FAILED; + if (r1->status & R1_CC_ERROR) + sd_card->errno = SD_ERROR_CC; + if (r1->status & R1_ERROR) + sd_card->errno = SD_ERROR_GENERAL; + if (r1->status & R1_CID_CSD_OVERWRITE) + sd_card->errno = SD_ERROR_CID_CSD_OVERWRITE; + } + if (r1->status & R1_AKE_SEQ_ERROR) + sd_card->errno = SD_ERROR_CID_CSD_OVERWRITE; + + if (r1->cmd != cmd->opcode) + sd_card->errno = SD_ERROR_HEADER_MISMATCH; + dbg5("command:0x%x", r1->cmd); + /* This should be last - it's the least dangerous error */ + if (R1_CURRENT_STATE(r1->status) != sd_card->state ) { + dbg5("state dismatch:r1->status:%x,state:%x\n",R1_CURRENT_STATE(r1->status),sd_card->state); + sd_card->errno = SD_ERROR_STATE_MISMATCH; + } + dbg5("sd card error %d", sd_card->errno); + if (sd_card->errno) + return MSS_ERROR_RESP_UNPACK; + return 0; +} + +static int sd_unpack_r3(struct mss_cmd *cmd, struct sd_response_r3 *r3, struct sd_card *sd_card) +{ + u8 *buf = cmd->response; + + sd_card->errno = SD_ERROR_NONE; + r3->cmd = unstuff_bits(buf, 40, 8, 6); + r3->ocr = unstuff_bits(buf, 8, 32, 6); + dbg5("ocr=0x%x", r3->ocr); + + if (r3->cmd != 0x3f) { + sd_card->errno = SD_ERROR_HEADER_MISMATCH; + return MSS_ERROR_RESP_UNPACK; + } + return 0; +} + +static int sd_unpack_r6(struct mss_cmd *cmd, struct sd_response_r6 *r6, struct sd_card *sd_card) +{ + u8 *buf = cmd->response; + int errno = SD_ERROR_NONE; + + r6->cmd = unstuff_bits(buf, 40, 8, 6); + r6->rca = unstuff_bits(buf, 24, 16, 6); + r6->status = unstuff_bits(buf, 8, 16, 6); + if (R6_STATUS(r6->status)) { + if (r6->status & R6_COM_CRC_ERROR) + errno = SD_ERROR_COM_CRC; + if (r6->status & R6_ILLEGAL_COMMAND) + errno = SD_ERROR_ILLEGAL_COMMAND; + if (r6->status & R6_ERROR) + errno = SD_ERROR_CC; + } + if (r6->cmd != cmd->opcode) + errno = SD_ERROR_HEADER_MISMATCH; + /* This should be last - it's the least dangerous error */ + if (R1_CURRENT_STATE(r6->status) != sd_card->state) + errno = SD_ERROR_STATE_MISMATCH; + sd_card->errno = errno; + if (errno) + return MSS_ERROR_RESP_UNPACK; + return 0 ; +} + +static int sd_unpack_cid(struct mss_cmd *cmd, struct sd_cid *cid, struct sd_card *sd_card) +{ + u8 *buf = cmd->response; + + sd_card->errno = SD_ERROR_NONE; + if (buf[0] != 0x3f) { + sd_card->errno = SD_ERROR_HEADER_MISMATCH; + return MSS_ERROR_RESP_UNPACK; + } + buf = buf + 1; + + cid->mid = unstuff_bits(buf, 120, 8, 16); + cid->oid = unstuff_bits(buf, 104, 16, 16); + cid->pnm[0] = unstuff_bits(buf, 96, 8, 16); + cid->pnm[1] = unstuff_bits(buf, 88, 8, 16); + cid->pnm[2] = unstuff_bits(buf, 80, 8, 16); + cid->pnm[3] = unstuff_bits(buf, 72, 8, 16); + cid->pnm[4] = unstuff_bits(buf, 64, 8, 16); + cid->pnm[5] = 0; + cid->prv = unstuff_bits(buf, 56, 8, 16); + cid->psn = unstuff_bits(buf, 24, 32, 16); + cid->mdt = unstuff_bits(buf, 8, 12, 16); +/* + DEBUG(" mid=%d oid=%d pnm=%s prv=%d.%d psn=%08x mdt=%d/%d\n", + cid->mid, cid->oid, cid->pnm, + (cid->prv>>4), (cid->prv&0xf), + cid->psn, cid->mdt&&0xf, ((cid->mdt>>4)&0xff)+2000); +*/ + + return 0; +} + +static int sd_unpack_csd(struct mss_cmd *cmd, struct sd_csd *csd, struct sd_card *sd_card) +{ + u8 *buf = cmd->response; + + sd_card->errno = SD_ERROR_NONE; + if (buf[0] != 0x3f) { + sd_card->errno = SD_ERROR_HEADER_MISMATCH; + return MSS_ERROR_RESP_UNPACK; + } + buf = buf + 1; + + csd->csd_structure = unstuff_bits(buf, 126, 2, 16); + csd->taac = unstuff_bits(buf, 112, 8, 16); + csd->nsac = unstuff_bits(buf, 104, 8, 16); + csd->tran_speed = unstuff_bits(buf, 96, 8, 16); + csd->ccc = unstuff_bits(buf, 84, 12, 16); + csd->read_bl_len = unstuff_bits(buf, 80, 4, 16); + csd->read_bl_partial = unstuff_bits(buf, 79, 1, 16); + csd->write_blk_misalign = unstuff_bits(buf, 78, 1, 16); + csd->read_blk_misalign = unstuff_bits(buf, 77, 1, 16); + csd->dsr_imp = unstuff_bits(buf, 76, 1, 16); + if (csd->csd_structure == 0) { + csd->csd.csd1.c_size = unstuff_bits(buf, 62, 12, 16); + csd->csd.csd1.vdd_r_curr_min = unstuff_bits(buf, 59, 3, 16); + csd->csd.csd1.vdd_r_curr_max = unstuff_bits(buf, 56, 3, 16); + csd->csd.csd1.vdd_w_curr_min = unstuff_bits(buf, 53, 3, 16); + csd->csd.csd1.vdd_w_curr_max = unstuff_bits(buf, 50, 3, 16); + csd->csd.csd1.c_size_mult = unstuff_bits(buf, 47, 3, 16); + } + else if (csd->csd_structure == 1) { + csd->csd.csd2.c_size = unstuff_bits(buf, 48, 22, 16); + } + csd->erase_blk_en = unstuff_bits(buf, 46, 1, 16); + csd->sector_size = unstuff_bits(buf, 39, 7, 16); + csd->wp_grp_size = unstuff_bits(buf, 32, 7, 16); + csd->wp_grp_enable = unstuff_bits(buf, 31, 1, 16); + csd->r2w_factor = unstuff_bits(buf, 26, 3, 16); + csd->write_bl_len = unstuff_bits(buf, 22, 4, 16); + csd->write_bl_partial = unstuff_bits(buf, 21, 1, 16); + csd->file_format_grp = unstuff_bits(buf, 15, 1, 16); + csd->copy = unstuff_bits(buf, 14, 1, 16); + csd->perm_write_protect = unstuff_bits(buf, 13, 1, 16); + csd->tmp_write_protect = unstuff_bits(buf, 12, 1, 16); + csd->file_format = unstuff_bits(buf, 10, 2, 16); + + if (csd->csd_structure == 0) { + dbg5(" csd_structure=%d taac=%02x nsac=%02x tran_speed=%02x\n" + " ccc=%04x read_bl_len=%d read_bl_partial=%d write_blk_misalign=%d\n" + " read_blk_misalign=%d dsr_imp=%d c_size=%d vdd_r_curr_min=%d\n" + " vdd_r_curr_max=%d vdd_w_curr_min=%d vdd_w_curr_max=%d c_size_mult=%d\n" + " erase_blk_en=%d sector_size=%d wp_grp_size=%d wp_grp_enable=%d r2w_factor=%d\n" + " write_bl_len=%d write_bl_partial=%d file_format_grp=%d copy=%d\n" + " perm_write_protect=%d tmp_write_protect=%d file_format=%d\n", + csd->csd_structure,csd->taac, csd->nsac, csd->tran_speed, + csd->ccc, csd->read_bl_len, + csd->read_bl_partial, csd->write_blk_misalign, + csd->read_blk_misalign, csd->dsr_imp, + csd->csd.csd1.c_size, csd->csd.csd1.vdd_r_curr_min, + csd->csd.csd1.vdd_r_curr_max, csd->csd.csd1.vdd_w_curr_min, + csd->csd.csd1.vdd_w_curr_max, csd->csd.csd1.c_size_mult, + csd->erase_blk_en,csd->sector_size, + csd->wp_grp_size, csd->wp_grp_enable, + csd->r2w_factor, + csd->write_bl_len, csd->write_bl_partial, + csd->file_format_grp, csd->copy, + csd->perm_write_protect, csd->tmp_write_protect, + csd->file_format); + } + else if (csd->csd_structure == 1) { + dbg5(" csd_structure=%d taac=%02x nsac=%02x tran_speed=%02x\n" + " ccc=%04x read_bl_len=%d read_bl_partial=%d write_blk_misalign=%d\n" + " read_blk_misalign=%d dsr_imp=%d c_size=%d\n" + " erase_blk_en=%d sector_size=%d wp_grp_size=%d wp_grp_enable=%d r2w_factor=%d\n" + " write_bl_len=%d write_bl_partial=%d file_format_grp=%d copy=%d\n" + " perm_write_protect=%d tmp_write_protect=%d file_format=%d\n", + csd->csd_structure,csd->taac, csd->nsac, csd->tran_speed, + csd->ccc, csd->read_bl_len, + csd->read_bl_partial, csd->write_blk_misalign, + csd->read_blk_misalign, csd->dsr_imp, + csd->csd.csd2.c_size, + csd->erase_blk_en,csd->sector_size, + csd->wp_grp_size, csd->wp_grp_enable, + csd->r2w_factor, + csd->write_bl_len, csd->write_bl_partial, + csd->file_format_grp, csd->copy, + csd->perm_write_protect, csd->tmp_write_protect, + csd->file_format); + } + + return 0; +} + +static int sd_unpack_swfuncstatus(char *buf, struct sw_func_status *status) +{ + int i; + + buf += 34; + for (i = 0; i < 5; i++) { + status->func_busy[i] = buf[0] << 8 | buf[1]; + buf += 2; + } + buf += 1; + for (i = 0; i <= 5; i = i + 2) { + status->group_status[i] = buf[0] & 0xFF; + status->group_status[(i + 1)] = (buf[0] >> 4) & 0xFF; + buf += 1; + } + + for (i = 0; i <= 5; i++) { + status->func_support[i] = buf[0] << 8 | buf[1]; + buf += 2; + } + + status->current_consumption = buf[0] << 8 | buf[1]; + + return 0; +} + +static int sd_unpack_r7(struct mss_cmd *cmd, struct sd_response_r7 *r7, u16 arg, struct sd_card *sd_card) +{ + u8 *buf = cmd->response; + + r7->cmd = unstuff_bits(buf, 40, 8, 6); + r7->ver = unstuff_bits(buf, 20, 20, 6); + r7->vca = unstuff_bits(buf, 16, 4, 6); + r7->pattern = unstuff_bits(buf, 8, 8, 6); + +/* if ((r7->cmd | r7->ver | r7->vca | r7->pattern) == 0) + return MSS_NO_RESPONSE;*/ + if (r7->cmd != SD_SEND_IF_COND || r7->ver != 0 + || (r7->vca | r7->pattern) != arg) { + sd_card->errno = SD_ERROR_HEADER_MISMATCH; + return MSS_ERROR_RESP_UNPACK; + } + return 0; +} + +static int sd_unpack_scr(u8 *buf, struct sd_scr *scr) +{ + scr->scr_structure = unstuff_bits(buf, 60, 4, 8); + scr->sd_spec = unstuff_bits(buf, 56, 4, 8); + scr->data_stat_after_erase = unstuff_bits(buf, 55, 1, 8); + scr->sd_security = unstuff_bits(buf, 52, 3, 8); + scr->sd_bus_width = unstuff_bits(buf, 48, 4, 8); + scr->init = 1; + + dbg5("scr_stru:%d, spec:%d, sata:%d, security:%d, bus:%d", scr->scr_structure, scr->sd_spec, scr->data_stat_after_erase, scr->sd_security, scr->sd_bus_width); + return 0; +} + +static int sd_get_status(struct mss_card *card, int *status) +{ + struct sd_response_r1 r1; + struct sd_card *sd_card = card->prot_card; + struct mss_host *host = card->slot->host; + int clock, ret, retries = 4; + + clock = sd_tran_speed(sd_card->csd.tran_speed); + mss_set_clock(card->slot->host, clock); + while (retries--) { + dbg5("rety"); + ret = mss_send_simple_ll_req(host, &sd_card->llreq, + &sd_card->cmd, SD_SEND_STATUS, + sd_card->rca << 16, MSS_RESPONSE_R1, 0); + dbg5("retry ret :%d", ret); + if (ret && !retries) + return ret; + else if (!ret) { + ret = sd_unpack_r1(&sd_card->cmd, &r1, sd_card); + if (ret) { + if (sd_card->errno == SD_ERROR_STATE_MISMATCH) { + sd_card->state = R1_CURRENT_STATE(r1.status); + sd_card->errno = SD_ERROR_NONE; + } + else + return ret; + } + else + break; + } + + clock = host->ios.clock; + clock = clock >> 1; + if (clock < SD_CARD_CLOCK_SLOW || retries == 1) + clock = SD_CARD_CLOCK_SLOW; + mss_set_clock(host, clock); + } + + *status = r1.status; + + return MSS_ERROR_NONE; +} + +/** + * The blocks requested by the kernel may or may not match what we can do. + * Unfortunately, filesystems play fast and loose with block sizes, so we're + * stuck with this. + */ +static void sd_fix_request_block_len(struct mss_card *card, int action, struct mss_rw_arg *arg) +{ + u16 block_len = 0; + struct sd_card *sd_card = card->prot_card; + struct mss_host *host = card->slot->host; + + switch(action) { + case MSS_DATA_READ: + block_len = 1 << sd_card->csd.read_bl_len; + break; + case MSS_DATA_WRITE: + block_len = 1 << sd_card->csd.write_bl_len; + break; + default: + return; + } + if (host->high_capacity && (sd_card->ocr & SD_OCR_CCS)) + block_len = 512; + if (block_len < arg->block_len) { + int scale = arg->block_len / block_len; + arg->block_len = block_len; + arg->block *= scale; + arg->nob *= scale; + } +} + +static int sd_send_cmd6(struct mss_card *card, struct sw_func_status *status, int mode, u32 funcs) +{ + struct sd_response_r1 r1; + struct sd_card *sd_card = card->prot_card; + struct mss_ll_request *llreq = &sd_card->llreq; + struct mss_cmd *cmd = &sd_card->cmd; + struct mss_data *data = &sd_card->data; + struct mss_host *host= card->slot->host; + struct scatterlist sg; + char *g_buffer = sd_card->buf; + int ret; + /* Set the argumens for CMD6. */ + /* [31]: Mode + * [30:24]: reserved (all 0s) + * [23:20]: group 6 + * [19:16]: group 5 + * [15:12]: group 4 + * [11:8]: group 3 + * [7:4]: group 2 + * [3:0]: group 1 + */ + sg.page = virt_to_page(g_buffer); + sg.offset = offset_in_page(g_buffer); + sg.length = 8; + + memset(llreq, 0x0, sizeof(struct mss_ll_request)); + memset(cmd, 0x0, sizeof(struct mss_cmd)); + memset(data, 0x0, sizeof(struct mss_data)); + MSS_INIT_CMD(cmd, SD_SW_FUNC, (funcs | ((mode & 0x1) << 31)), 0, + MSS_RESPONSE_R1); + MSS_INIT_DATA(data, 1, 32, MSS_DATA_READ, 1, &sg, 0); + llreq->cmd = cmd; + llreq->data = data; + + ret = mss_send_ll_req(host, llreq); + if (ret) + return ret; + ret = sd_unpack_r1(cmd, &r1, sd_card); + if (ret) + return ret; + sd_unpack_swfuncstatus(g_buffer, status); + + return 0; +} + +/***************************************************************************** + * + * protocol entry functions + * + ****************************************************************************/ + +static int sd_recognize_card(struct mss_card *card) +{ + struct sd_response_r1 r1; + struct sd_response_r3 r3; + struct sd_response_r7 r7; + int ret; + struct sd_card *sd_card = (struct sd_card *)card->prot_card; + struct mss_ios ios; + struct mss_host *host = card->slot->host; + struct mss_ll_request *llreq = &sd_card->llreq; + struct mss_cmd *cmd = &sd_card->cmd; + + card->state = CARD_STATE_IDLE; + card->bus_width = MSS_BUSWIDTH_1BIT; + + memcpy(&ios, &host->ios, sizeof(struct mss_ios)); + ios.bus_mode = MSS_BUSMODE_OPENDRAIN; + ios.clock = host->f_min; + ios.bus_width = MSS_BUSWIDTH_1BIT; + host->ops->set_ios(host, &ios); + + card->card_type = MSS_UNKNOWN_CARD; + + ret = mss_send_simple_ll_req(host, llreq, cmd, + SD_GO_IDLE_STATE, 0, MSS_RESPONSE_NONE, MSS_CMD_INIT); + if (ret) + return ret; + if (host->sd_spec == MSS_SD_SPEC_20) { + if (!(host->vdd & MSS_VDD_27_36)) + return MSS_ERROR_NO_PROTOCOL; + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SEND_IF_COND, + 0x1AA, MSS_RESPONSE_R7, 0); + if (ret == MSS_ERROR_TIMEOUT) + goto next; + else if (ret) + return ret; + ret = sd_unpack_r7(cmd, &r7, 0x1AA, sd_card); + if (!ret) { + sd_card->ver = MSS_SD_SPEC_20; + goto next; + } + else + return ret; + } +next: + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_APP_CMD, 0, + MSS_RESPONSE_R1, 0); + if (ret) + return ret; + ret = sd_unpack_r1(cmd, &r1, sd_card); + if (ret) + return ret; + + + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SD_SEND_OP_COND, 0, + MSS_RESPONSE_R3, 0); + if (ret) + return ret; + ret = sd_unpack_r3(cmd, &r3, sd_card); + if (ret) + return ret; + + if (r3.ocr & host->vdd) { + card->card_type = MSS_SD_CARD; + sd_card->ver = MSS_SD_SPEC_20; + } + else + card->card_type = MSS_UNCOMPATIBLE_CARD; + + return MSS_ERROR_NONE; +} + + +/** + * sd_card_init + * @dev: mss_card_device + * + * return value: 0: success, -1: failed + */ +static int sd_card_init(struct mss_card *card) +{ + struct sd_response_r1 r1; + struct sd_response_r3 r3; + struct sd_response_r6 r6; + struct sd_response_r7 r7; + struct sd_cid cid; + int ret; + struct sd_card * sd_card= (struct sd_card *)card->prot_card; + struct mss_ios ios; + struct mss_host *host = card->slot->host; + struct mss_ll_request *llreq = &sd_card->llreq; + struct mss_cmd *cmd = &sd_card->cmd; + int hcs = 0; + + sd_card->state = CARD_STATE_IDLE; + card->bus_width = MSS_BUSWIDTH_1BIT; + sd_card->rca = 0; + + memcpy(&ios, &host->ios, sizeof(struct mss_ios)); + ios.bus_mode = MSS_BUSMODE_OPENDRAIN; + ios.bus_width = MSS_BUSWIDTH_1BIT; + ios.clock = host->f_min; + host->ops->set_ios(host, &ios); + + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_GO_IDLE_STATE, 0, + MSS_RESPONSE_NONE, MSS_CMD_INIT); + if (ret) + return ret; + /* + * We have to send cmd 8 to 2.0 card. It will tell the card that the + * host support 2.0 spec. + */ + if (sd_card->ver == MSS_SD_SPEC_20 && host->sd_spec == MSS_SD_SPEC_20) { + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SEND_IF_COND, + 0x1AA, MSS_RESPONSE_R7, 0); + if (ret) + return ret; + ret = sd_unpack_r7(cmd, &r7, 0x1AA, sd_card); + if (ret) + return ret; + if (host->high_capacity) + hcs = 1; + } + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_APP_CMD, 0, + MSS_RESPONSE_R1, 0); + if (ret) + return ret; + ret = sd_unpack_r1(cmd, &r1, sd_card); + if (ret) + return ret; + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SD_SEND_OP_COND, + hcs << 30 | host->vdd, MSS_RESPONSE_R3, 0); + if (ret) + return ret; + ret = sd_unpack_r3(cmd, &r3, sd_card); + if (ret) + return ret; + while (!(r3.ocr & SD_OCR_CARD_BUSY)) { + //mdelay(20); + msleep(15); + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_APP_CMD, 0, + MSS_RESPONSE_R1, 0); + if (ret) + return ret; + ret = sd_unpack_r1(cmd, &r1, sd_card); + if (ret) + return ret; + + ret = mss_send_simple_ll_req(host, llreq, cmd, + SD_SD_SEND_OP_COND, hcs << 30 | host->vdd, + MSS_RESPONSE_R3, 0); + if (ret) + return ret; + ret = sd_unpack_r3(cmd, &r3, sd_card); + if (ret) + return ret; + } + memcpy(&sd_card->ocr, &r3.ocr, sizeof(r3.ocr)); + sd_card->state = CARD_STATE_READY; + + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_ALL_SEND_CID, 0, + MSS_RESPONSE_R2_CID, 0); + if (ret) + return ret; + + memset(&cid, 0x0, sizeof(struct sd_cid)); + ret = sd_unpack_cid(cmd, &cid, sd_card); + if (ret) + return ret; + + if (sd_card->cid.mid != 0) { + if (sd_card->cid.mid != cid.mid || sd_card->cid.oid != cid.oid + || sd_card->cid.prv != cid.prv + || sd_card->cid.psn != cid.psn + || sd_card->cid.mdt != cid.mdt + || memcmp(sd_card->cid.pnm, cid.pnm, 6)) + return MSS_ERROR_MISMATCH_CARD; + + if (memcmp(&cid, &sd_card->cid, sizeof(struct sd_cid))) + return MSS_ERROR_MISMATCH_CARD; + } + else + memcpy(&sd_card->cid, &cid, sizeof(struct sd_cid)); + + sd_card->state = CARD_STATE_IDENT; + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SEND_RELATIVE_ADDR, + 0, MSS_RESPONSE_R6, 0); + if (ret) + return ret; + ret = sd_unpack_r6(cmd, &r6, sd_card); + if (ret) + return ret; + sd_card->state = CARD_STATE_STBY; + sd_card->rca = r6.rca; + + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SEND_CSD, + sd_card->rca << 16, MSS_RESPONSE_R2_CSD, 0); + if (ret) + return ret; + ret = sd_unpack_csd(cmd, &sd_card->csd, sd_card); + if (ret) + return ret; + + if (host->ops->is_slot_wp && host->ops->is_slot_wp(card->slot)) + card->state |= MSS_CARD_WP; + + return MSS_ERROR_NONE; +} + +static int sd_read_write_entry(struct mss_card *card, int action, struct mss_rw_arg *arg, struct mss_rw_result *result) +{ + struct sd_response_r1 r1; + struct mss_host *host = card->slot->host; + struct mss_ios ios; + int ret, retries = 4; + struct sd_card *sd_card = (struct sd_card *)card->prot_card; + struct mss_ll_request *llreq = &sd_card->llreq; + struct mss_cmd *cmd = &sd_card->cmd; + struct mss_data *data = &sd_card->data; + struct scatterlist sg; + char *g_buffer = sd_card->buf; + int status; + u32 clock; + u32 cmdarg, blklen, opcode, flags; + + dbg5("block:%d, nob:%d, blok_len:%d", arg->block, arg->nob, arg->block_len); + ret = sd_get_status(card, &status); + if (ret) + return ret; + + if (status & R1_CARD_IS_LOCKED) + return MSS_ERROR_LOCKED; + + if (action == MSS_WRITE_MEM && host->ops->is_slot_wp && + host->ops->is_slot_wp(card->slot)) + return MSS_ERROR_WP; + + if (sd_card->state == CARD_STATE_STBY) { + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SELECT_CARD, + sd_card->rca << 16, MSS_RESPONSE_R1B, 0); + if (ret) + return ret; + ret = sd_unpack_r1(cmd, &r1, sd_card); + if (ret) + return ret; + } + sd_card->state = CARD_STATE_TRAN; + + sd_fix_request_block_len(card, action, arg); + + + if (!sd_card->scr.init) { + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_APP_CMD, + sd_card->rca << 16, MSS_RESPONSE_R1, 0); + if (ret) + return ret; + + sg.page = virt_to_page(g_buffer); + sg.offset = offset_in_page(g_buffer); + sg.length = 8; + + memset(llreq, 0x0, sizeof(struct mss_ll_request)); + memset(cmd, 0x0, sizeof(struct mss_cmd)); + memset(data, 0x0, sizeof(struct mss_data)); + MSS_INIT_CMD(cmd, SD_SEND_SCR, 0, 0, MSS_RESPONSE_R1); + MSS_INIT_DATA(data, 1, 8, MSS_DATA_READ, 1, &sg, 0); + llreq->cmd = cmd; + llreq->data = data; + + ret = mss_send_ll_req(host, llreq); + if (ret) + return ret; + ret = sd_unpack_scr(g_buffer, &sd_card->scr); + if (ret) + return ret; + } + if (sd_card->scr.sd_bus_width == SCR_BUSWIDTH_1BIT) { + mss_set_buswidth(host, MSS_BUSWIDTH_1BIT); + card->bus_width = MSS_BUSWIDTH_1BIT; + } + else { + if (card->bus_width == MSS_BUSWIDTH_1BIT + && host->bus_width == MSS_BUSWIDTH_4BIT) { + mss_set_buswidth(host, MSS_BUSWIDTH_4BIT); + card->bus_width = MSS_BUSWIDTH_4BIT; + ret = mss_send_simple_ll_req(host, llreq, cmd, + SD_APP_CMD, sd_card->rca << 16, + MSS_RESPONSE_R1, 0); + if (ret) + return ret; + ret = sd_unpack_r1(cmd, &r1, sd_card); + if (ret) + return ret; + ret = mss_send_simple_ll_req(host, llreq, cmd, + SD_SET_BUS_WIDTH, 0x2, MSS_RESPONSE_R1, + 0); + if (ret) + return ret; + ret = sd_unpack_r1(cmd, &r1, sd_card); + if (ret) + return ret; + card->bus_width = MSS_BUSWIDTH_4BIT; + } + } + memset(llreq, 0x0, sizeof(struct mss_ll_request)); + memset(cmd, 0x0, sizeof(struct mss_cmd)); + memset(data, 0x0, sizeof(struct mss_data)); + + memcpy(&ios, &host->ios, sizeof(struct mss_ios)); + if ((sd_card->ocr & SD_OCR_CCS) && host->high_capacity) { + ios.access_mode = MSS_ACCESS_MODE_SECTOR; + cmdarg = arg->block; + blklen = 512; + } + else { + if (arg->block_len != sd_card->block_len) { + ret = mss_send_simple_ll_req(host, llreq, cmd, + SD_SET_BLOCKLEN, arg->block_len, + MSS_RESPONSE_R1, 0); + if (ret) + return ret; + ret = sd_unpack_r1(cmd, &r1, sd_card); + if (ret) + return ret; + sd_card->block_len = arg->block_len; + } + cmdarg = arg->block * arg->block_len; + blklen = arg->block_len; + } + ios.clock = sd_tran_speed(sd_card->csd.tran_speed); + host->ops->set_ios(host, &ios); + + llreq->cmd = cmd; + llreq->data = data; + +read_write_entry: + + if (arg->nob > 1) { + if (action == MSS_READ_MEM) { + opcode = SD_READ_MULTIPLE_BLOCK; + flags = MSS_DATA_READ | MSS_DATA_MULTI; + } + else { + opcode = SD_WRITE_MULTIPLE_BLOCK; + flags = MSS_DATA_WRITE | MSS_DATA_MULTI; + } + + MSS_INIT_CMD(cmd, opcode, cmdarg, 0, MSS_RESPONSE_R1); + MSS_INIT_DATA(data, arg->nob, blklen, flags, arg->sg_len, + arg->sg, 0); + + ret = mss_send_ll_req(host, llreq); + if (!ret) + ret = sd_unpack_r1(cmd, &r1, sd_card); + sd_card->state = (action == MSS_WRITE_MEM) ? CARD_STATE_RCV : CARD_STATE_DATA; + if (ret) { + mss_send_simple_ll_req(host, llreq, cmd, + SD_STOP_TRANSMISSION, 0, + (action == MSS_WRITE_MEM) ? + MSS_RESPONSE_R1B : MSS_RESPONSE_R1, 0); + sd_card->state = CARD_STATE_TRAN; + if (--retries) { + clock = host->ios.clock; + clock = clock >> 1; + if (clock < SD_CARD_CLOCK_SLOW && retries == 1) + clock = SD_CARD_CLOCK_SLOW; + mss_set_clock(host, clock); + goto read_write_entry; + } + return ret; + } + ret = mss_send_simple_ll_req(host, llreq, cmd, + SD_STOP_TRANSMISSION, 0, + (action == MSS_WRITE_MEM) ? + MSS_RESPONSE_R1B : MSS_RESPONSE_R1, 0); + if (ret) + return ret; + ret = sd_unpack_r1(cmd, &r1, sd_card); + sd_card->state = CARD_STATE_TRAN; + if (ret && (sd_card->errno != SD_ERROR_OUT_OF_RANGE)) + return ret; + } else { + if (action == MSS_READ_MEM) { + opcode = SD_READ_SINGLE_BLOCK; + flags = MSS_DATA_READ; + } + else { + opcode = SD_WRITE_BLOCK; + flags = MSS_DATA_WRITE; + } + MSS_INIT_CMD(cmd, opcode, cmdarg, 0, MSS_RESPONSE_R1); + MSS_INIT_DATA(data, arg->nob, blklen, flags, arg->sg_len, + arg->sg, 0); + + ret = mss_send_ll_req(host, llreq); + if (!ret) + ret = sd_unpack_r1(cmd, &r1, sd_card); + if (ret) { + if (--retries) { + clock = host->ios.clock; + clock = clock >> 1; + if (clock < SD_CARD_CLOCK_SLOW && retries == 1) + clock = SD_CARD_CLOCK_SLOW; + mss_set_clock(host, clock); + goto read_write_entry; + } + return ret; + } + } + /* Deselect the card */ + /*mmc_simple_ll_req(host, mmc_card, MMC_SELECT_CARD, + 0, MSS_RESPONSE_NONE, 0); + if (ret) + return ret; + ret = mmc_unpack_r1(&mmc_card->cmd, &r1, mmc_card); + mmc_card->state = CARD_STATE_STBY;*/ + if (ret) + return ret; + result->bytes_xfered = data->bytes_xfered; + + return MSS_ERROR_NONE; +} + +static int sd_query_function(struct mss_card *card, struct io_swfunc_request *r, struct sw_func_status *status) +{ + struct sd_card *sd_card = card->prot_card; + int i; + u32 arg = 0; + + if (card->slot->host->sd_spec != MSS_SD_SPEC_20 + || sd_card->ver != MSS_SD_SPEC_20) + return MSS_ERROR_ACTION_UNSUPPORTED; + for (i = 5; i > 0; i--) { + arg |= ((r->args[i] & 0xF) << (i << 2)); + } + return sd_send_cmd6(card, status, 0, arg); +} + +static int sd_sw_function(struct mss_card *card, struct io_swfunc_request *r) +{ + int ret, i; + u32 arg = 0; + struct sw_func_status status; + struct sd_card *sd_card = card->prot_card; + + if (card->slot->host->sd_spec != MSS_SD_SPEC_20 + || sd_card->ver != MSS_SD_SPEC_20) + return MSS_ERROR_ACTION_UNSUPPORTED; + for (i = 0; i < 6; i++) { + if (r->args[i] >= 0xF) { + goto switch_err; + } + } + /* Step 1: CMD6(mode = 0, func = 0xF(Don't Care) */ + ret = sd_send_cmd6(card, &status, 0, 0xFFFFFF); + if (ret) + goto switch_err; + + /* Step 2: Any Switch ? */ + for (i = 0; i < 6; i++) { + if (!((status.func_support[i]) & (0x1 << (r->args[i])))) + goto switch_err; + } + + for (i = 0; i < 6; i++) { + if (status.group_status[i] != r->args[i]) { + break; + } + } + if (i == 6) + return 0; + + /* Step 3: CMD6(mode = 0, func= funcX */ + for (i = 5; i > 0; i--) { + arg |= ((r->args[i]) << (i << 2)); + } + ret = sd_send_cmd6(card, &status, 0, arg); + if (ret) + goto switch_err; + if (status.current_consumption > r->current_acceptable) { + goto switch_err; + } + for (i = 0; i < 6; i++) { + if (status.group_status[i] != r->args[i]) { + goto switch_err; + } + } + ret = sd_send_cmd6(card, &status, 1, arg); + if (ret) + goto switch_err; + for (i = 0; i < 6; i++) { + if (status.group_status[i] != r->args[i]) { + goto switch_err; + } + } + return 0; +switch_err: + sd_card->errno = SD_ERROR_SWFUNC; + return MSS_ERROR_ACTION_UNSUPPORTED; +} +/* count by 512 bytes */ +static int sd_get_capacity(struct mss_card *card, u32 *size) +{ + struct sd_card *sd_card = card->prot_card; + int c_size = 0; + int c_size_mult = 0; + int blk_len = 0; + + if (sd_card->csd.csd_structure == 0) { + c_size = sd_card->csd.csd.csd1.c_size; + c_size_mult = sd_card->csd.csd.csd1.c_size_mult; + blk_len = sd_card->csd.read_bl_len - 9; + } + /* (csize + 1) * 512 * 1024 bytes */ + else if (sd_card->csd.csd_structure == 1) { + c_size = sd_card->csd.csd.csd2.c_size; + c_size_mult = 7; + blk_len = 2; + } + *size = (c_size + 1) << (2 + c_size_mult + blk_len); + return MSS_ERROR_NONE; +} + + + +/***************************************************************************** + * + * protocol driver interface functions + * + ****************************************************************************/ +static int sd_prot_entry(struct mss_card *card, unsigned int action, void *arg, void *result) +{ + int ret; + u32 status; + + if (action != MSS_RECOGNIZE_CARD && card->card_type != MSS_SD_CARD) + return MSS_ERROR_WRONG_CARD_TYPE; + switch (action) { + case MSS_RECOGNIZE_CARD: + ret = sd_recognize_card(card); + break; + case MSS_INIT_CARD: + ret = sd_card_init(card); + break; + case MSS_READ_MEM: + case MSS_WRITE_MEM: + if (!arg || !result) + return -EINVAL; + ret = sd_read_write_entry(card, action, arg, result); + break; + /* + case MSS_LOCK_UNLOCK: + ret = sd_lock_unlock_entry(dev); + break; + */ + case MSS_SD_QUERY_FUNC: + if (!arg || !result) + return -EINVAL; + ret = sd_query_function(card, arg, result); + break; + case MSS_SD_SW_FUNC: + if (!arg) + return -EINVAL; + ret = sd_sw_function(card, arg); + break; + case MSS_QUERY_CARD: + ret = sd_get_status(card, &status); + break; + case MSS_GET_CAPACITY: + ret = sd_get_capacity(card, result); + break; + default: + ret = MSS_ERROR_ACTION_UNSUPPORTED; + break; + } + return ret; +} + +static int sd_prot_attach_card(struct mss_card *card) +{ + struct sd_card *sd_card; + +#define ALIGN32(x) (((x) + 31) & (~31)) + sd_card = kzalloc(ALIGN32(ALIGN32(sizeof(struct sd_card))) + 512, + GFP_KERNEL); + card->prot_card = sd_card; + if (sd_card) { + sd_card->buf = (char *)ALIGN32((unsigned int)&sd_card[1]); + return 0; + } + return -ENOMEM; +} + +static void sd_prot_detach_card(struct mss_card *card) +{ + kfree(card->prot_card); +} + +static int sd_prot_get_errno(struct mss_card *card) +{ + struct sd_card *sd_card = card->prot_card; + + return sd_card->errno; +} + +static struct mss_prot_driver sd_protocol = { + .name = SD_PROTOCOL, + .prot_entry = sd_prot_entry, + .attach_card = sd_prot_attach_card, + .detach_card = sd_prot_detach_card, + .get_errno = sd_prot_get_errno, +}; + +/***************************************************************************** + * + * module init and exit functions + * + ****************************************************************************/ +static int sd_protocol_init(void) +{ + register_mss_prot_driver(&sd_protocol); + return 0; +} + +static void sd_protocol_exit(void) +{ + unregister_mss_prot_driver(&sd_protocol); +} + + +module_init(sd_protocol_init); +module_exit(sd_protocol_exit); + +MODULE_AUTHOR("Bridge Wu"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SD protocol driver"); --- linux-2.6.24.orig/drivers/mmc/mss/mss_block.c +++ linux-2.6.24/drivers/mmc/mss/mss_block.c @@ -0,0 +1,555 @@ +/* + * mss_block.c - MMC/SD Card driver (block device driver) + * + * Copyright (C) 2007 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 only + * for now as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * derived from previous mmc code in Linux kernel + * Copyright (c) 2002 Hewlett-Packard Company + * Copyright (c) 2002 Andrew Christian + * Copyright (c) 2006 Bridge Wu + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include + +#include + +#define MSS_SHIFT 3 +#define MSS_SECTOR_SIZE (512) + +static int major; + +struct mss_disk { + struct request_queue *queue; + struct gendisk *disk; + struct mss_card *card; + struct class_device cdev; + + u32 flags; /* for suspend/resume */ +#define MSS_QUEUE_SUSPENDED (1 << 1) +#define MSS_QUEUE_EXIT (1 << 0) + struct completion thread_complete; + struct semaphore thread_sem; + wait_queue_head_t thread_wq; + spinlock_t request_lock; + struct scatterlist *sg; + struct request *req; +}; + +#define MSS_NUM_MINORS (256 << MSS_SHIFT) + +static unsigned long dev_use[MSS_NUM_MINORS/8*sizeof(unsigned long)]; + +static DECLARE_MUTEX(md_ref_mutex); + +static struct mss_disk *mss_disk_get(struct gendisk *disk) +{ + struct mss_disk *md; + + down(&md_ref_mutex); + md = disk->private_data; + if (md) { + if (mss_card_get(md->card) == 0) + class_device_get(&md->cdev); + else + md = NULL; + } + up(&md_ref_mutex); + + return md; +} + +static void mss_disk_put(struct mss_disk *md) +{ + struct mss_card *card = md->card; + + down(&md_ref_mutex); + class_device_put(&md->cdev); + mss_card_put(card); + up(&md_ref_mutex); +} + +static void mss_disk_release(struct class_device *cdev) +{ + struct mss_disk *md = container_of(cdev, struct mss_disk, cdev); + struct gendisk *disk = md->disk; + + /* Release the minor number */ + __clear_bit(disk->first_minor >> MSS_SHIFT, dev_use); + + put_disk(md->disk); + + /* Terminate the request handler thread */ + md->flags |= MSS_QUEUE_EXIT; + wake_up(&md->thread_wq); + wait_for_completion(&md->thread_complete); + + kfree(md->sg); + md->sg = NULL; + + blk_cleanup_queue(md->queue); + + put_device(&md->card->dev); + md->card = NULL; + kfree(md); +} + +static struct class mss_disk_class = { + .name = "mss disk", + .owner = THIS_MODULE, + .release = mss_disk_release, + //.class_dev_attrs = mss_disk_attrs, +}; + +static int mss_media_transfer(struct mss_disk *md, struct request *req) +{ + struct mss_request mreq; + struct mss_rw_arg marg; + struct mss_rw_result mres; + int ret; + + memset(&mreq, 0x0, sizeof(mreq)); + memset(&marg, 0x0, sizeof(marg)); + memset(&mres, 0x0, sizeof(marg)); + + mreq.arg = &marg; + mreq.result = &mres; + mreq.card = md->card; + do { + if (rq_data_dir(req) == READ) + mreq.action = MSS_READ_MEM; + else + mreq.action = MSS_WRITE_MEM; + + marg.nob = req->nr_sectors; + /* FIXME */ + marg.block_len = MSS_SECTOR_SIZE; + marg.block = req->sector; + marg.sg = md->sg; + marg.sg_len = blk_rq_map_sg(req->q, req, marg.sg); + + ret = mss_send_request(&mreq); + if (ret) + goto err; + dbg5("successful, bytes transfer :%x\n", mres.bytes_xfered); + ret = end_that_request_chunk(req, 1, mres.bytes_xfered); + if (!ret) { + add_disk_randomness(md->disk); + blkdev_dequeue_request(req); + end_that_request_last(req, 0); + } + } while (ret); + + return 1; +err: + dbg5("error, bytes transfer :%x\n", mres.bytes_xfered); + do { + ret = end_that_request_chunk(req, 0, + req->current_nr_sectors << 9); + } while (ret); + + add_disk_randomness(md->disk); + blkdev_dequeue_request(req); + end_that_request_last(req, 0); + + return 0; +} + +static int mss_queue_thread(void *d) +{ + struct mss_disk *md = d; + DECLARE_WAITQUEUE(wait, current); + + current->flags |= PF_MEMALLOC; + + daemonize("mmcqd%d", md->disk->first_minor >> MSS_SHIFT); + + complete(&md->thread_complete); + + down(&md->thread_sem); + add_wait_queue(&md->thread_wq, &wait); + do { + struct request *req = NULL; + + + /* masked by Feng */ + /* try_to_freeze(); */ + spin_lock_irq(&md->request_lock); + set_current_state(TASK_INTERRUPTIBLE); + if (!blk_queue_plugged(md->queue)) + md->req = req = elv_next_request(md->queue); + spin_unlock_irq(&md->request_lock); + + if (!req) { + if (md->flags & MSS_QUEUE_EXIT) + break; + up(&md->thread_sem); + schedule(); + down(&md->thread_sem); + continue; + } + set_current_state(TASK_RUNNING); + + mss_media_transfer(md, req); + } while (1); + remove_wait_queue(&md->thread_wq, &wait); + up(&md->thread_sem); + + complete_and_exit(&md->thread_complete, 0); + return 0; +} + +static int mss_media_preq(struct request_queue *q, struct request *req) +{ + struct mss_disk *md = q->queuedata; + if (!md || !md->card || + (md->card->state & (MSS_CARD_REMOVING | MSS_CARD_INVALID))) { + return BLKPREP_KILL; + } + return BLKPREP_OK; +} + + +/** + * mss_media_request + * @q: request queue + * + * entry function to request handling of MMC/SD block device driver. + * handle a request from request queue generated by upper layer. + */ +static void mss_media_request(request_queue_t *q) +{ + struct mss_disk *md = q->queuedata; + + if (md && !md->req) + wake_up(&md->thread_wq); +} + + +static int mss_blk_open(struct inode *inode, struct file *filp) +{ + struct gendisk *disk = inode->i_bdev->bd_disk; + struct mss_disk *md; + + md = mss_disk_get(disk); + if (!md) + return -ENXIO; + + if ((filp->f_mode & FMODE_WRITE) && (md->card->state & MSS_CARD_WP)) + return -EROFS; + /* FIXME check media change */ + check_disk_change(inode->i_bdev); + return 0; +} + +static int mss_blk_release(struct inode *inode, struct file *filep) +{ + struct gendisk *disk = inode->i_bdev->bd_disk; + struct mss_disk *md = disk->private_data; + + mss_disk_put(md); + return 0; +} + +static struct block_device_operations mss_bdops = { + .open = mss_blk_open, + .release = mss_blk_release, + //.media_changed = mss_media_changed, + //.revalidate_disk = mss_media_revalidate_disk, + .owner = THIS_MODULE, +}; + +/***************************************************************************** + * + * device driver functions + * + ****************************************************************************/ + +/** + * mss_card_probe + * @dev: device + * + * probe method to initialize block device. + * initialize mss_block_device, set capacity, load block driver(add_disk). + * + * invoked by bus_match (invoked by device_register or driver_register) + * must have device and driver, or this function cannot be invoked. + */ +static int mss_blk_probe(struct device *dev) +{ + struct mss_disk *md; + struct mss_card *card; + struct mss_host *host; + int devidx, ret = 0; + u64 limit = BLK_BOUNCE_HIGH; + + dbg5("read to probe card"); + devidx = find_first_zero_bit(dev_use, MSS_NUM_MINORS); + if (devidx >= MSS_NUM_MINORS) { + printk(KERN_ERR "can not find available minors"); + return -ENOSPC; + } + __set_bit(devidx, dev_use); + + card = container_of(dev, struct mss_card, dev); + + host = card->slot->host; + if (card->card_type != MSS_MMC_CARD && card->card_type != MSS_SD_CARD) { + printk(KERN_ERR "card(slot%d, host%d) is not memory card\n", + card->slot->id, host->id); + ret = -ENOTBLK; + goto clear_bit; + } + + md = kzalloc(sizeof(*md), GFP_KERNEL); + if (!md) { + printk(KERN_ERR "card(slot%d, host%d) alloc block_dev failed!" + "\n", card->slot->id, host->id); + ret = -ENOMEM; + goto clear_bit; + } + md->card = card; + md->disk = alloc_disk(1 << MSS_SHIFT); + if (md->disk == NULL) { + printk(KERN_ERR "card(slot%d, host%d) alloc disk failed!\n", + card->slot->id, host->id); + ret = -ENOMEM; + goto free_data; + } + md->disk->major = major; + md->disk->first_minor = devidx << MSS_SHIFT; + md->disk->fops = &mss_bdops; + md->disk->driverfs_dev = &card->dev; + md->disk->private_data = md; +// sprintf(md->disk->devfs_name, "mssblk%d", devidx); + sprintf(md->disk->disk_name, "mss/blk%d", devidx); + + class_device_initialize(&md->cdev); + md->cdev.dev = &card->dev; + md->cdev.class = &mss_disk_class; + strncpy(md->cdev.class_id, card->dev.bus_id, BUS_ID_SIZE); + ret = class_device_add(&md->cdev); + if (ret) { + goto free_disk; + } + get_device(&card->dev); + + spin_lock_init(&md->request_lock); + md->queue = blk_init_queue(mss_media_request, &md->request_lock); + if (!md->queue) { + ret = -ENOMEM; + goto remove_cdev; + } + if (host->dev->dma_mask && *host->dev->dma_mask) + limit = *host->dev->dma_mask; + + blk_queue_prep_rq(md->queue, mss_media_preq); + blk_queue_bounce_limit(md->queue, limit); + blk_queue_max_sectors(md->queue, host->max_sectors); + blk_queue_max_phys_segments(md->queue, host->max_phys_segs); + blk_queue_max_hw_segments(md->queue, host->max_hw_segs); + blk_queue_max_segment_size(md->queue, host->max_seg_size); + + md->queue->queuedata = md; + + md->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs, + GFP_KERNEL); + if (!md->sg) { + ret = -ENOMEM; + goto clean_queue; + } + + init_completion(&md->thread_complete); + init_waitqueue_head(&md->thread_wq); + init_MUTEX(&md->thread_sem); + + ret = kernel_thread(mss_queue_thread, md, CLONE_KERNEL); + if (ret < 0) { + goto free_sg; + } + wait_for_completion(&md->thread_complete); + init_completion(&md->thread_complete); + + md->disk->queue = md->queue; + dev_set_drvdata(dev, md); + blk_queue_hardsect_size(md->queue, MSS_SECTOR_SIZE); + set_capacity(md->disk, mss_get_capacity(card)/(MSS_SECTOR_SIZE/512) - 4); + add_disk(md->disk); + return 0; + +free_sg: + kfree(md->sg); +clean_queue: + blk_cleanup_queue(md->queue); +remove_cdev: + class_device_del(&md->cdev); + put_device(&card->dev); +free_disk: + put_disk(md->disk); +free_data: + kfree(md); +clear_bit: + __clear_bit(devidx, dev_use); + + return ret; +} + +/** + * mss_card_remove + * @dev: device + * + * remove method to remove block device. + * invoked by device_unregister or driver_unregister. + */ +static int mss_blk_remove(struct device *dev) +{ + struct mss_disk *md; + struct mss_card *card; + + card = container_of(dev, struct mss_card, dev); + md = dev_get_drvdata(dev); + + class_device_del(&md->cdev); + del_gendisk(md->disk); + md->disk->queue = NULL; + + down(&md_ref_mutex); + dev_set_drvdata(dev, NULL); + class_device_put(&md->cdev); + up(&md_ref_mutex); + + return 0; +} + +/** + * mss_card_suspend + * @dev: device + * @state: suspend state + * @level: suspend level + * + * card specific suspend. + * invoke blk_stop_queue to suspend request queue. + */ +static int mss_blk_suspend(struct device *dev, pm_message_t state)//, u32 level) +{ + struct mss_disk *md; + struct mss_card *card; + unsigned long flags; + + card = container_of(dev, struct mss_card, dev); + md = dev_get_drvdata(dev); + + if (!(md->flags & MSS_QUEUE_SUSPENDED)) { + md->flags |= MSS_QUEUE_SUSPENDED; + spin_lock_irqsave(&md->request_lock, flags); + blk_stop_queue(md->queue); + spin_unlock_irqrestore(&md->request_lock, flags); + } + + return 0; +} + +/** + * mss_card_resume + * @dev: device + * @level: suspend level + * + * card specific resume. + * invoke blk_start_queue to resume request queue. + */ +static int mss_blk_resume(struct device *dev)//, u32 level) +{ + struct mss_disk *md; + struct mss_card *card; + unsigned long flags; + + card = container_of(dev, struct mss_card, dev); + md = dev_get_drvdata(dev); + + if (md->flags & MSS_QUEUE_SUSPENDED) { + md->flags &= ~MSS_QUEUE_SUSPENDED; + spin_lock_irqsave(&md->request_lock, flags); + blk_start_queue(md->queue); + spin_unlock_irqrestore(&md->request_lock, flags); + } + + return 0; +} + +static struct mss_driver mss_block_driver = { + .driver = { + .name = "MMC_SD Block Driver", + .probe = mss_blk_probe, + .remove = mss_blk_remove, + .suspend = mss_blk_suspend, + .resume = mss_blk_resume, + }, +}; + +/***************************************************************************** + * + * module init and exit functions + * + ****************************************************************************/ +static int mss_card_driver_init(void) +{ + int ret = -ENOMEM; + + ret = register_blkdev(major, "mmc"); + if (ret < 0) { + printk(KERN_ERR "Unable to get major %d for MMC media: %d\n", + major, ret); + return ret; + } + if (major == 0) + major = ret; + + dbg5("Get major number :%d\n", major); +// devfs_mk_dir("mmc"); + + class_register(&mss_disk_class); + return register_mss_driver(&mss_block_driver); +} + +static void mss_card_driver_exit(void) +{ + unregister_mss_driver(&mss_block_driver); +// devfs_remove("mmc"); + unregister_blkdev(major, "mmc"); + class_unregister(&mss_disk_class); +} + + +module_init(mss_card_driver_init); +module_exit(mss_card_driver_exit); + +MODULE_AUTHOR("Bridge Wu"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Block device driver for MMC/SD card"); --- linux-2.6.24.orig/drivers/mmc/mss/mss_core.c +++ linux-2.6.24/drivers/mmc/mss/mss_core.c @@ -0,0 +1,918 @@ +/* + * mss_core.c - MMC/SD/SDIO Core driver + * + * Copyright (C) 2007 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 only + * for now as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * derived from previous mmc code in Linux kernel + * Copyright (c) 2002 Hewlett-Packard Company + * Copyright (c) 2002 Andrew Christian + * Copyright (c) 2006 Bridge Wu + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +static LIST_HEAD(mss_protocol_list); +static LIST_HEAD(mss_host_list); + +static void mss_power_up(struct mss_host *host) +{ + struct mss_ios ios; + + memcpy(&ios, &host->ios, sizeof(ios)); + ios.vdd = host->vdd; + ios.chip_select = MSS_CS_NO_CARE; + ios.power_mode = MSS_POWER_UP; + host->ops->set_ios(host, &ios); + + msleep(1); + + ios.clock = host->f_min; + ios.power_mode = MSS_POWER_ON; + host->ops->set_ios(host, &ios); + + msleep(2); +} + +static void mss_power_off(struct mss_host *host) +{ + struct mss_ios ios; + + memcpy(&ios, &host->ios, sizeof(ios)); + ios.clock = 0; + ios.chip_select = MSS_CS_NO_CARE; + ios.power_mode = MSS_POWER_OFF; + host->ops->set_ios(host, &ios); +} + +static void mss_idle_cards(struct mss_host *host) +{ + struct mss_ios ios; + + memcpy(&ios, &host->ios, sizeof(ios)); + ios.chip_select = MSS_CS_HIGH; + host->ops->set_ios(host, &ios); + msleep(1); + ios.chip_select = MSS_CS_NO_CARE; + host->ops->set_ios(host, &ios); + msleep(1); +} + +/* + * Only after card is initialized by protocol and be registed to mmc_bus, the + * state is changed to MSS_CARD_REGISTERED. + */ +static int mmc_bus_match(struct device *dev, struct device_driver *drv) +{ + struct mss_card *card; + + card = container_of(dev, struct mss_card, dev); + + dbg(card->slot, "bus match driver %s", drv->name); + /* when card->state is MSS_CARD_REGISTERED,it is accepted by protocol */ + if (card->prot_driver && (card->state & MSS_CARD_REGISTERED)) + return 1; + dbg(card->slot, "bus match driver %s fail", drv->name); + return 0; +} + +//static int mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) +//{ +// printk(KERN_INFO "*** HOT PLUG ***\n"); +// return 0; +//} + +static int mmc_bus_suspend(struct device * dev, pm_message_t state) +{ + int ret = 0; + struct mss_card *card; + + card = container_of(dev, struct mss_card, dev); + + if (card->state & MSS_CARD_HANDLEIO) + return -EAGAIN; + if (card->state & MSS_CARD_SUSPENDED) + return 0; + + if (dev->driver && dev->driver->suspend) { + ret = dev->driver->suspend(dev, state);//, SUSPEND_DISABLE); + if (ret == 0) + ret = dev->driver->suspend(dev, state);//, SUSPEND_SAVE_STATE); + if (ret == 0) + ret = dev->driver->suspend(dev, state);//, SUSPEND_POWER_DOWN); + } + /* mark MSS_CARD_SUSPEND here */ + card->state |= MSS_CARD_SUSPENDED; + return ret; +} +/* + * card may be removed or replaced by another card from the mmc_bus when it is + * sleeping, and the slot may be inserted a card when it is sleeping. + * The controller resume function need to take care about it. + */ +static int mmc_bus_resume(struct device * dev) +{ + int ret = 0; + struct mss_card *card; + + card = container_of(dev, struct mss_card, dev); + + /* it is new instered card or replaced card */ + if (!(card->state & MSS_CARD_SUSPENDED)) + return 0; + + card->state &= ~MSS_CARD_SUSPENDED; + if (dev->driver && dev->driver->resume) { + ret = dev->driver->resume(dev);//, RESUME_POWER_ON); + if (ret == 0) + ret = dev->driver->resume(dev);//, RESUME_RESTORE_STATE); + if (ret == 0) + ret = dev->driver->resume(dev);//, RESUME_ENABLE); + } + + return ret; +} + +static struct bus_type mmc_bus_type = { + .name = "mmc_bus", + .match = mmc_bus_match, +// .hotplug = mmc_bus_hotplug, + .suspend = mmc_bus_suspend, + .resume = mmc_bus_resume, +}; + +static void mss_card_device_release(struct device *dev) +{ + struct mss_card *card = container_of(dev, struct mss_card, dev); + + kfree(card); +} + +static void mss_claim_host(struct mss_host *host, struct mss_card *card) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + + /* + spin_lock_irqsave(&host->lock, flags); + while (host->active_card != NULL) { + spin_unlock_irqrestore(&host->lock, flags); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&host->wq, &wait); + schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&host->wq, &wait); + spin_lock_irqsave(&host->lock, flags); + } + */ + + spin_lock_irqsave(&host->lock, flags); + while (host->active_card != NULL) { + set_current_state(TASK_UNINTERRUPTIBLE); + spin_unlock_irqrestore(&host->lock, flags); + add_wait_queue(&host->wq, &wait); + schedule(); + remove_wait_queue(&host->wq, &wait); + spin_lock_irqsave(&host->lock, flags); + } + set_current_state(TASK_RUNNING); + host->active_card = card; + spin_unlock_irqrestore(&host->lock, flags); +} + +static void mss_release_host(struct mss_host* host) +{ + unsigned long flags; + + BUG_ON(host->active_card == NULL); + + spin_lock_irqsave(&host->lock, flags); + host->active_card = NULL; + spin_unlock_irqrestore(&host->lock, flags); + + wake_up(&host->wq); + +} + +int mss_card_get(struct mss_card *card) +{ + if ((card->state & MSS_CARD_REMOVING) + || !(card->state & MSS_CARD_REGISTERED)) + return -ENXIO; + if (!get_device(&card->dev)) + return -ENXIO; + return 0; +} + +void mss_card_put(struct mss_card *card) +{ + put_device(&card->dev); +} + +/* + * finish handling a request. + */ +static void mss_finish_request(struct mss_request *req) +{ + struct mss_driver *drv; + struct mss_card *card = req->card; + + drv = container_of(card->dev.driver, struct mss_driver, driver); + if (drv && drv->request_done) + drv->request_done(req); +} + +/* + * Loop all the protocol in the mss_protocol_list, and find one protocol that + * can successful recognize and init the card. + */ +static int mss_attach_protocol(struct mss_card *card) +{ + struct list_head *item; + struct mss_prot_driver *pdrv = NULL; + struct mss_host *host = card->slot->host; + int ret; + + /* loop all the protocol, and find one that match the card */ + list_for_each(item, &mss_protocol_list) { + pdrv = list_entry(item, struct mss_prot_driver, node); + dbg(card->slot, "try protocol:%s", pdrv->name); + + ret = pdrv->attach_card(card); + if (ret) + continue; + dbg(card->slot, "protocol:%s allocate spec card", pdrv->name); + + mss_claim_host(host, card); + ret = pdrv->prot_entry(card, MSS_RECOGNIZE_CARD, NULL, NULL); + mss_release_host(host); + dbg(card->slot, "protocol:%s identy ret:%d, card type:%d\n", pdrv->name, ret, card->card_type); + if (ret) + continue; + switch (card->card_type) { + case MSS_MMC_CARD: + //case MSS_CE_ATA: + case MSS_SD_CARD: + case MSS_SDIO_CARD: + case MSS_COMBO_CARD: + //dbg("identified card type: %d", card_type); + goto identified; + /* + * The card can be recognized, but it deos not fit the + * controller. + */ + case MSS_UNCOMPATIBLE_CARD: + pdrv->detach_card(card); + return MSS_ERROR_NO_PROTOCOL; + /* The card can not be recognized by the protocl */ + case MSS_UNKNOWN_CARD: + pdrv->detach_card(card); + break; + default: + pdrv->detach_card(card); + printk(KERN_WARNING "protocol driver :%s return unknown value when recognize the card\n", pdrv->name); + break; + } + } + + return MSS_ERROR_NO_PROTOCOL; +identified: + card->prot_driver = pdrv; + return 0; +} + +/* Initialize card by the protocol */ +int mss_init_card(struct mss_card *card) +{ + int ret; + struct mss_host *host = card->slot->host; + + if (!card || !card->prot_driver) + return -EINVAL; + mss_claim_host(host, card); + ret = card->prot_driver->prot_entry(card, MSS_INIT_CARD, NULL, NULL); + mss_release_host(host); + + dbg5("return :%d", ret); + return ret; +} + +int mss_query_card(struct mss_card *card) +{ + int ret; + struct mss_host *host = card->slot->host; + + if (!card || !card->prot_driver) + return -EINVAL; + mss_claim_host(host, card); + ret = card->prot_driver->prot_entry(card, MSS_QUERY_CARD, NULL, NULL); + mss_release_host(host); + + return ret; +} + +static int __mss_insert_card(struct mss_card *card) +{ + int ret; + + dbg(card->slot, "attaching protocol"); + /* Step 1: Recognize the card */ + ret = mss_attach_protocol(card); + if (ret) + return ret; + + dbg(card->slot, "protocol%s attached", card->prot_driver->name); + /* Step 2, initialize the card */ + ret = mss_init_card(card); + if (ret) { + goto detach_prot; + } + + dbg(card->slot, "protocol%s inited", card->prot_driver->name); + /* Step 3, register the card to mmc bus */ + card->dev.release = mss_card_device_release; + card->dev.parent = card->slot->host->dev; + /* set bus_id and name */ + snprintf(&card->dev.bus_id[0], sizeof(card->dev.bus_id), "mmc%d%d", + card->slot->host->id, card->slot->id); + card->dev.bus = &mmc_bus_type; + + card->state |= MSS_CARD_REGISTERED; + ret = device_register(&card->dev); /* will call mss_card_probe */ + if (ret) { + ret = MSS_ERROR_REGISTER_CARD; + card->state &= ~MSS_CARD_REGISTERED; + goto detach_prot; + } + dbg(card->slot, "protocol%s registered\n", card->prot_driver->name); + return MSS_ERROR_NONE; + +detach_prot: + card->prot_driver->detach_card(card); + card->prot_driver = NULL; + return ret; +} + +/* + * After knowing a card has been inserted into the slot, this function should + * be invoked. At last, load card driver in card (done by card_driver->probe). + */ +static int mss_insert_card(struct mss_slot *slot) +{ + struct mss_card * card; + int ret; + + BUG_ON(slot->card); + dbg(slot, "card is inserting"); + card = kzalloc(sizeof(struct mss_card), GFP_KERNEL); + if (!card) + return -ENOMEM; + card->slot = slot; + slot->card = card; + + dbg(slot, "allocate card :0x%p", card); + ret = __mss_insert_card(card); + dbg(slot, "insert ret :%d", ret); + if (ret) { + dbg(slot, "free card"); + slot->card = NULL; + kfree(card); + } + return ret; +} + +static int __mss_eject_card(struct mss_card *card) +{ + card->state |= MSS_CARD_REMOVING; + + dbg(card->slot, "card state 0x%x", card->state); + + if (card->prot_driver) { + card->prot_driver->detach_card(card); + card->prot_driver = NULL; + } + if (card->state & MSS_CARD_REGISTERED) { + device_unregister(&(card->dev)); + //card->state &= ~MSS_CARD_REGISTERED; + } + + return 0; +} + +/* + * After knowing a card has been ejected from the slot, this function should + * be invoked. At last, unload card driver in card(done by card_driver->remove). + */ +static int mss_eject_card(struct mss_card *card) +{ + BUG_ON(!card); + + dbg(card->slot, "eject card 0x%x", card); + __mss_eject_card(card); + + card->slot->card = NULL; + card->slot = NULL; + //kfree(card); + + return 0; +} + +unsigned int mss_get_capacity(struct mss_card *card) +{ + int ret; + u32 cap; + + mss_claim_host(card->slot->host, card); + ret = card->prot_driver->prot_entry(card, MSS_GET_CAPACITY, NULL, &cap); + mss_release_host(card->slot->host); + dbg5("get capcacity:0x%x, ret:%d",cap, ret); + if (ret) + cap = 0; + return cap; +} + +int mss_scan_slot(struct work_struct *work) +{ + struct mss_card *card; + struct mss_host *host; + struct mss_slot *slot; + int ret = 0; + + slot = container_of(work, struct mss_slot, card_detect.work); + + card = slot->card; + host = slot->host; + + + printk("begin scan slot, id = %d card_type = %d\n", slot->id, + (card)?(card->card_type):0); + + /* slot has card in it before, and the card is resuming back */ + if (card && (card->state & MSS_CARD_SUSPENDED)) { + dbg(slot, "suspend, card state is 0x%x", card->state); + printk("suspend, card state is 0x%x", card->state); + /* card was ejected when it is suspended */ + if (host->ops->is_slot_empty + && host->ops->is_slot_empty(slot)) { + card->state |= MSS_CARD_REMOVING; + ret = MSS_ERROR_CARD_REMOVING; + } + else { + /* + * if host provides is_slot_empty, and it + * indicates that the card is in slot, then + * we try to init it. + * else, we try to init it directly. Obvisouly + * that if there is no card in the slot, the + * init will fail + */ + dbg(slot, "no is_slot_empty"); + ret = mss_init_card(card); + if (ret) + card->state |= MSS_CARD_INVALID; + } + } + else if (card && (card->state & MSS_CARD_INVALID)) { + + dbg(slot, "2222222222222"); + + card->state &= ~MSS_CARD_INVALID; + ret = mss_eject_card(card); + + if (!host->ops->is_slot_empty + || (host->ops->is_slot_empty && + !host->ops->is_slot_empty(slot))) { + ret = mss_insert_card(slot); + } + + } + /* slot has card in it before, and no suspend happens */ + else if (card && (card->state & MSS_CARD_REGISTERED)) { + dbg(slot, "33333333333"); + + dbg(slot, "register, card state is %d", card->state); + //printk("register, card state is %d", card->state); + if (host->ops->is_slot_empty) { + dbg(slot, "has is_slot_empty"); + /* card has been ejected */ + if (host->ops->is_slot_empty(slot)) + ret = mss_eject_card(card); + } + else { + /* + * We try to send the status query command. + * If card->state has set MSS_CARD_REGISRTEED, + * it indicates that the card has finished + * identification process, and it will response + * the SEND_STATUS command. + */ + dbg(slot, "no is_slot_empty"); + if (mss_query_card(card)) + /* Card has been ejected */ + ret = mss_eject_card(card); + } + } + /* slot has card in it, but the card is not registered */ + else if (card) { + /* This should never be happens, because when insert fail, we will delete the card */ + BUG(); + } + /* slot has no card in it before */ + else if (!card) { + dbg(slot, "no card in it before"); + + mss_power_off(host); + mss_power_up(host); + mss_idle_cards(host); + if (host->ops->is_slot_empty) { + /* slot is not empty */ + if (!host->ops->is_slot_empty(slot)) + ret = mss_insert_card(slot); + } + else { + /* try to insert a card */ + ret = mss_insert_card(slot); + } + } + else { + printk(KERN_ERR "Unexpected situation when scan host:%d" + ", slot:%d, card state:0x%x\n", host->id, + slot->id, card ? card->state : 0x0); + BUG(); + } + + return ret; +} + +void mss_detect_change(struct mss_host *host, unsigned long delay, unsigned int id) +{ + struct mss_slot *slot; + + slot = &host->slots[id]; + + //printk(" enter mss_detect_change(): delay = %d, id = %d, slot = 0x%xi\n", + // delay, id, slot); + + if (delay) + schedule_delayed_work(&slot->card_detect, delay); + else + schedule_work(&slot->card_detect); + + //printk("%s(): done and exit\n", __FUNCTION__); +} + +void mss_scan_host(struct mss_host *host) +{ + struct mss_slot *slot; + int i; + + for (i = 0; i < host->slot_num; i++) { + slot = &host->slots[i]; + mss_scan_slot(&slot->card_detect.work); + } +} + +void mss_force_card_remove(struct mss_card *card) +{ + mss_eject_card(card); +} + +static void mss_wait_done(struct mss_ll_request *llreq) +{ + complete(llreq->done_data); +} + +int mss_send_ll_req(struct mss_host *host, struct mss_ll_request *llreq) +{ + DECLARE_COMPLETION(complete); + + llreq->done = mss_wait_done; + llreq->done_data = &complete; + + llreq->cmd->llreq = llreq; + llreq->cmd->error = MSS_ERROR_NONE; + if (llreq->data) + llreq->cmd->data = llreq->data; +/* if (llreq->data && llreq->stop) { + llreq->stop->llreq = llreq; + llreq->stop->error = 0; + }*/ + host->ops->request(host, llreq); + wait_for_completion(&complete); +/* if (llreq->cmd->error || (llreq->stop && llreq->stop-error))*/ + + return llreq->cmd->error; +} + +int mss_send_simple_ll_req(struct mss_host *host, struct mss_ll_request *llreq, struct mss_cmd *cmd, u32 opcode, u32 arg, u32 rtype, u32 flags) +{ + memset(llreq, 0x0, sizeof(struct mss_ll_request)); + memset(cmd, 0x0, sizeof(struct mss_cmd)); + + cmd->opcode = opcode; + cmd->arg = arg; + cmd->rtype = rtype; + cmd->flags = flags; + + llreq->cmd = cmd; + + return mss_send_ll_req(host, llreq); +} + + +/* + * add controller into mss_host_list + */ +int register_mss_host(struct mss_host *host) +{ + list_add_tail(&host->node, &mss_host_list); + return 0; +} + +/* + * delete controller from mss_controller_list + */ +void unregister_mss_host(struct mss_host *host) +{ + + list_del(&host->node); +} + +/***************************************************************************** + * + * functions for protocol driver + * + ****************************************************************************/ + +/* + * add protocol driver into mss_protocol_list + */ +int register_mss_prot_driver(struct mss_prot_driver *drv) +{ + struct list_head *item; + struct mss_host *host; + struct mss_slot *slot; + int i; + + list_add(&drv->node, &mss_protocol_list); + + list_for_each(item, &mss_host_list) { + host = list_entry(item, struct mss_host, node); + for (i = 0; i < host->slot_num; i++) { + slot = &host->slots[i]; + if (!slot->card) + mss_scan_slot(&slot->card_detect.work); + } + } + return 0; +} + +/* + * delete protocol driver from mss_protocol_list + */ +void unregister_mss_prot_driver(struct mss_prot_driver *drv) +{ + struct mss_slot *slot; + struct list_head *item; + struct mss_host *host; + int i; + + list_del(&drv->node); + + list_for_each(item, &mss_host_list) { + host = list_entry(item, struct mss_host, node); + for (i = 0; i < host->slot_num; i++) { + slot = &host->slots[i]; + if (slot->card && slot->card->prot_driver == drv) + mss_eject_card(slot->card); + } + } + +} + +/***************************************************************************** + * + * interfaces for card driver + * + ****************************************************************************/ + +/* + * register card driver onto MMC bus + */ +int register_mss_driver (struct mss_driver *drv) +{ + drv->driver.bus = &mmc_bus_type; + return driver_register(&drv->driver); /* will call card_driver->probe */ +} + +/* + * unregister card driver from MMC bus + */ +void unregister_mss_driver (struct mss_driver *drv) +{ + driver_unregister(&drv->driver); +} + +/* + * enable SDIO interrupt, used by SDIO application driver + */ +void mss_set_sdio_int(struct mss_host *host, int sdio_en) +{ + struct mss_ios ios; + + dbg5("mss_set_sdio_int = %s", (sdio_en)?"ENABLE":"DISABLE"); + memcpy(&ios, &host->ios, sizeof(ios)); + ios.sdio_int = sdio_en; + host->ops->set_ios(host, &ios); +} + +void mss_set_clock(struct mss_host *host, int clock) +{ + struct mss_ios ios; + + memcpy(&ios, &host->ios, sizeof(ios)); + if (clock > host->f_max) + clock = host->f_max; + else if (clock < host->f_min) + clock = host->f_min; + ios.clock = clock; + host->ops->set_ios(host, &ios); +} + +void mss_set_buswidth(struct mss_host *host, int buswidth) +{ + struct mss_ios ios; + + memcpy(&ios, &host->ios, sizeof(ios)); + ios.bus_width = buswidth; + host->ops->set_ios(host, &ios); +} + +void mss_set_busmode(struct mss_host *host, int busmode) +{ + struct mss_ios ios; + + memcpy(&ios, &host->ios, sizeof(ios)); + ios.bus_mode = busmode; + host->ops->set_ios(host, &ios); +} + +int mss_send_request(struct mss_request *req) +{ + struct mss_host *host; + struct mss_card *card; +// unsigned long flags; + int ret; + + if (!req->card || !req->card->slot) + return -ENODEV; + card = req->card; + host = card->slot->host; + if (req->card->state & MSS_CARD_REMOVING) + return MSS_ERROR_CARD_REMOVING; + card->state |= MSS_CARD_HANDLEIO; + dbg5("claim host"); + mss_claim_host(host, card); + ret = card->prot_driver->prot_entry(card, req->action, req->arg, + req->result); + mss_release_host(host); + dbg5("release host"); + card->state &= ~MSS_CARD_HANDLEIO; + + if (ret) + req->errno = card->prot_driver->get_errno(card); + + return ret; +} + +struct mss_host * mss_alloc_host(unsigned int slot_num, unsigned int id, unsigned int private_size) +{ + struct mss_host *host; + struct mss_slot *slot; + int i = 0, size; + + printk("%s(): enter\n", __FUNCTION__); + + size = sizeof(struct mss_host) + sizeof(struct mss_slot) * slot_num + + private_size; + host = (struct mss_host *)kzalloc(size, GFP_KERNEL); + if (!host) + return NULL; + memset(host, 0x0, size); + host->id = id; + host->slot_num = slot_num; + while(i < slot_num) { + slot = &host->slots[i]; + slot->id = i; + slot->host = host; + INIT_DELAYED_WORK(&slot->card_detect, (void (*)(void *))mss_scan_slot); + i++; + } + host->private = (void *)&host->slots[slot_num]; + host->active_card = NULL; + init_waitqueue_head(&host->wq); + spin_lock_init(&host->lock); + + return host; +} + +void mss_free_host(struct mss_host *host) +{ + kfree(host); +} + +struct mss_host *mss_find_host(int id) +{ + struct list_head *pos; + struct mss_host *host; + + list_for_each(pos, &mss_host_list) { + host = list_entry(pos, struct mss_host, node); + if (host->id == id) + return host; + } + return NULL; +} + +/***************************************************************************** + * + * module init and exit functions + * + ****************************************************************************/ + +static int mss_core_driver_init(void) +{ + return bus_register(&mmc_bus_type); +} + +static void mss_core_driver_exit(void) +{ + bus_unregister(&mmc_bus_type); +} + + +EXPORT_SYMBOL_GPL(mss_detect_change); +EXPORT_SYMBOL_GPL(mss_scan_slot); +EXPORT_SYMBOL_GPL(mss_scan_host); +EXPORT_SYMBOL_GPL(mss_alloc_host); +EXPORT_SYMBOL_GPL(mss_free_host); +EXPORT_SYMBOL_GPL(mss_find_host); +EXPORT_SYMBOL_GPL(mss_force_card_remove); +EXPORT_SYMBOL_GPL(register_mss_host); +EXPORT_SYMBOL_GPL(unregister_mss_host); + +EXPORT_SYMBOL_GPL(register_mss_driver); +EXPORT_SYMBOL_GPL(unregister_mss_driver); +EXPORT_SYMBOL_GPL(mss_send_request); +EXPORT_SYMBOL_GPL(mss_get_capacity); + +EXPORT_SYMBOL_GPL(register_mss_prot_driver); +EXPORT_SYMBOL_GPL(unregister_mss_prot_driver); +EXPORT_SYMBOL_GPL(mss_send_ll_req); +EXPORT_SYMBOL_GPL(mss_send_simple_ll_req); +EXPORT_SYMBOL_GPL(mss_set_sdio_int); +EXPORT_SYMBOL_GPL(mss_set_buswidth); +EXPORT_SYMBOL_GPL(mss_set_clock); +EXPORT_SYMBOL_GPL(mss_set_busmode); +EXPORT_SYMBOL_GPL(mss_card_get); +EXPORT_SYMBOL_GPL(mss_card_put); + +module_init(mss_core_driver_init); +module_exit(mss_core_driver_exit); + +MODULE_AUTHOR("Bridge Wu"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Core driver for MMC/SD/SDIO card"); --- linux-2.6.24.orig/drivers/mmc/mss/mmc_protocol.c +++ linux-2.6.24/drivers/mmc/mss/mmc_protocol.c @@ -0,0 +1,1049 @@ +/* + * mmc_protocol.c - MMC protocol driver + * + * Copyright (C) 2007 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 only + * for now as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * derived from previous mmc code in Linux kernel + * Copyright (c) 2002 Hewlett-Packard Company + * Copyright (c) 2002 Andrew Christian + * Copyright (c) 2006 Bridge Wu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* internal functions */ + +#define KBPS 1 +#define MBPS 1000 + +static u32 ts_exp[] = { 100*KBPS, 1*MBPS, 10*MBPS, 100*MBPS, 0, 0, 0, 0 }; +static u32 ts_mul[] = { 0, 1000, 1200, 1300, 1500, 2000, 2500, 3000, + 3500, 4000, 4500, 5000, 5500, 6000, 7000, 8000 }; + +static u32 mmc_tran_speed(u8 ts) +{ + u32 clock = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3]; + + return clock; +} + +static int mmc_unpack_r1(struct mss_cmd *cmd, struct mmc_response_r1 *r1, struct mmc_card *mmc_card) +{ + u8 *buf = cmd->response; + + mmc_card->errno = MMC_ERROR_NONE; + r1->cmd = unstuff_bits(buf, 40, 8, 6); + r1->status = unstuff_bits(buf, 8, 32, 6); + + if (R1_STATUS(r1->status)) { + if (r1->status & R1_OUT_OF_RANGE) + mmc_card->errno = MMC_ERROR_OUT_OF_RANGE; + if (r1->status & R1_ADDRESS_ERROR) + mmc_card->errno = MMC_ERROR_ADDRESS; + if (r1->status & R1_BLOCK_LEN_ERROR) + mmc_card->errno = MMC_ERROR_BLOCK_LEN; + if (r1->status & R1_ERASE_SEQ_ERROR) + mmc_card->errno = MMC_ERROR_ERASE_SEQ; + if (r1->status & R1_ERASE_PARAM) + mmc_card->errno = MMC_ERROR_ERASE_PARAM; + if (r1->status & R1_WP_VIOLATION) + mmc_card->errno = MMC_ERROR_WP_VIOLATION; + if (r1->status & R1_LOCK_UNLOCK_FAILED) + mmc_card->errno = MMC_ERROR_LOCK_UNLOCK_FAILED; + if (r1->status & R1_COM_CRC_ERROR) + mmc_card->errno = MMC_ERROR_COM_CRC; + if (r1->status & R1_ILLEGAL_COMMAND) + mmc_card->errno = MMC_ERROR_ILLEGAL_COMMAND; + if (r1->status & R1_CARD_ECC_FAILED) + mmc_card->errno = MMC_ERROR_CARD_ECC_FAILED; + if (r1->status & R1_CC_ERROR) + mmc_card->errno = MMC_ERROR_CC; + if (r1->status & R1_ERROR) + mmc_card->errno = MMC_ERROR_GENERAL; + if (r1->status & R1_UNDERRUN) + mmc_card->errno = MMC_ERROR_UNDERRUN; + if (r1->status & R1_OVERRUN) + mmc_card->errno = MMC_ERROR_OVERRUN; + if (r1->status & R1_CID_CSD_OVERWRITE) + mmc_card->errno = MMC_ERROR_CID_CSD_OVERWRITE; + } + + if (buf[0] != cmd->opcode) + mmc_card->errno = MMC_ERROR_HEADER_MISMATCH; + /* This should be last - it's the least dangerous error */ + if (R1_CURRENT_STATE(r1->status) != mmc_card->state ) { + dbg5("state dismatch:r1->status:%x,state:%x\n",R1_CURRENT_STATE(r1->status),mmc_card->state); + mmc_card->errno = MMC_ERROR_STATE_MISMATCH; + } + dbg5("mmc card error %d", mmc_card->errno); + if (mmc_card->errno) + return MSS_ERROR_RESP_UNPACK; + return 0; +} + +static int mmc_unpack_r3(struct mss_cmd *cmd, struct mmc_response_r3 *r3, struct mmc_card *mmc_card) +{ + u8 *buf = cmd->response; + + mmc_card->errno = MMC_ERROR_NONE; + r3->cmd = unstuff_bits(buf, 40, 8, 6); + r3->ocr = unstuff_bits(buf, 8, 32, 6); + + if (r3->cmd != 0x3f) { + mmc_card->errno = MMC_ERROR_HEADER_MISMATCH; + return MSS_ERROR_RESP_UNPACK; + } + return 0; +} + +/** + * Fast I/O, support for CEATA devices. + */ +static int mmc_unpack_r4( struct mss_cmd *cmd, struct mmc_response_r4 *r4, struct mmc_card *mmc_card) +{ + u8 *buf = cmd->response; + + mmc_card->errno = MMC_ERROR_NONE; + + r4->cmd = unstuff_bits(buf, 40, 8, 6); + r4->rca = unstuff_bits(buf, 24, 16, 6); + r4->status = unstuff_bits(buf, 23, 1, 6); + r4->reg_addr = unstuff_bits(buf, 16, 7, 6); + r4->read_reg_contents = unstuff_bits(buf, 8, 8, 6); + + if (r4->cmd != 0x27) { + mmc_card->errno = MMC_ERROR_HEADER_MISMATCH; + return MSS_ERROR_RESP_UNPACK; + } + return 0 ; +} + +/** + * Interrupt request. not supported temporarily. + */ +static int mmc_unpack_r5(struct mss_cmd *cmd, struct mmc_response_r5 *r5, struct mmc_card *mmc_card) +{ + u8 *buf = cmd->response; + + mmc_card->errno = MMC_ERROR_NONE; + + r5->cmd = unstuff_bits(buf, 40, 8, 6); + r5->rca = unstuff_bits(buf, 24, 16, 6); + r5->irq_data = unstuff_bits(buf, 8, 16, 6); + + if (r5->cmd != 0x28) { + mmc_card->errno = MMC_ERROR_HEADER_MISMATCH; + return MSS_ERROR_RESP_UNPACK; + } + return 0 ; +} + +static int mmc_unpack_cid(struct mss_cmd *cmd, struct mmc_cid *cid, struct mmc_card *mmc_card) +{ + u8 *buf = cmd->response; + + mmc_card->errno = MMC_ERROR_NONE; + if (buf[0] != 0x3f) { + mmc_card->errno = MMC_ERROR_HEADER_MISMATCH; + return MSS_ERROR_RESP_UNPACK; + } + buf = buf + 1; + + cid->mid = unstuff_bits(buf, 120, 8, 16); + cid->oid = unstuff_bits(buf, 104, 16, 16); + cid->pnm[0] = unstuff_bits(buf, 96, 8, 16); + cid->pnm[1] = unstuff_bits(buf, 88, 8, 16); + cid->pnm[2] = unstuff_bits(buf, 80, 8, 16); + cid->pnm[3] = unstuff_bits(buf, 72, 8, 16); + cid->pnm[4] = unstuff_bits(buf, 64, 8, 16); + cid->pnm[5] = unstuff_bits(buf, 56, 8, 16); + cid->pnm[6] = 0; + cid->prv = unstuff_bits(buf, 48, 8, 16); + cid->psn = unstuff_bits(buf, 16, 32, 16); + cid->mdt = unstuff_bits(buf, 8, 8, 16); + + return 0; +} + +static int mmc_unpack_csd(struct mss_cmd *cmd, struct mmc_csd *csd, struct mmc_card *mmc_card) +{ + u8 *buf = cmd->response; + + mmc_card->errno = MMC_ERROR_NONE; + if (buf[0] != 0x3f) { + mmc_card->errno = MMC_ERROR_HEADER_MISMATCH; + return MSS_ERROR_RESP_UNPACK; + } + buf = buf + 1; + + csd->csd_structure = unstuff_bits(buf, 126, 2, 16); + csd->spec_vers = unstuff_bits(buf, 122, 4, 16); + csd->taac = unstuff_bits(buf, 112, 8, 16); + csd->nsac = unstuff_bits(buf, 104, 8, 16); + csd->tran_speed = unstuff_bits(buf, 96, 8, 16); + csd->ccc = unstuff_bits(buf, 84, 12, 16);; + csd->read_bl_len = unstuff_bits(buf, 80, 4, 16); + csd->read_bl_partial = unstuff_bits(buf, 79, 1, 16); + csd->write_blk_misalign = unstuff_bits(buf, 78, 1, 16); + csd->read_blk_misalign = unstuff_bits(buf, 77, 1, 16); + csd->dsr_imp = unstuff_bits(buf, 76, 1, 16); + csd->c_size = unstuff_bits(buf, 62, 12, 16); + csd->vdd_r_curr_min = unstuff_bits(buf, 59, 3, 16); + csd->vdd_r_curr_max = unstuff_bits(buf, 56, 3, 16); + csd->vdd_w_curr_min = unstuff_bits(buf, 53, 3, 16); + csd->vdd_w_curr_max = unstuff_bits(buf, 50, 3, 16); + csd->c_size_mult = unstuff_bits(buf, 47, 3, 16); + switch (csd->csd_structure ) { + case CSD_STRUCT_1_0: + case CSD_STRUCT_1_1: + csd->erase.v22.sector_size = + unstuff_bits(buf, 42, 5, 16); + csd->erase.v22.erase_grp_size = + unstuff_bits(buf, 37, 5, 6); + break; + case CSD_STRUCT_1_2: + default: + csd->erase.v31.erase_grp_size = + unstuff_bits(buf, 42, 5, 16); + csd->erase.v31.erase_grp_mult = + unstuff_bits(buf, 37, 5, 16);; + break; + } + csd->wp_grp_size = unstuff_bits(buf, 32, 5, 16); + csd->wp_grp_enable = unstuff_bits(buf, 31, 1, 16); + csd->default_ecc = unstuff_bits(buf, 29, 2, 16); + csd->r2w_factor = unstuff_bits(buf, 26, 3, 16); + csd->write_bl_len = unstuff_bits(buf, 22, 4, 16); + csd->write_bl_partial = unstuff_bits(buf, 21, 1, 16); + csd->file_format_grp = unstuff_bits(buf, 16, 1, 16); + csd->copy = unstuff_bits(buf, 14, 1, 16); + csd->perm_write_protect = unstuff_bits(buf, 13, 1, 16); + csd->tmp_write_protect = unstuff_bits(buf, 12, 1, 16); + csd->file_format = unstuff_bits(buf, 10, 2, 16); + csd->ecc = unstuff_bits(buf, 8, 2, 16); + + printk(" csd_structure=%d spec_vers=%d taac=%02x nsac=%02x tran_speed=%02x\n" + " ccc=%04x read_bl_len=%d read_bl_partial=%d write_blk_misalign=%d\n" + " read_blk_misalign=%d dsr_imp=%d c_size=%d vdd_r_curr_min=%d\n" + " vdd_r_curr_max=%d vdd_w_curr_min=%d vdd_w_curr_max=%d c_size_mult=%d\n" + " wp_grp_size=%d wp_grp_enable=%d default_ecc=%d r2w_factor=%d\n" + " write_bl_len=%d write_bl_partial=%d file_format_grp=%d copy=%d\n" + " perm_write_protect=%d tmp_write_protect=%d file_format=%d ecc=%d\n", + csd->csd_structure, csd->spec_vers, + csd->taac, csd->nsac, csd->tran_speed, + csd->ccc, csd->read_bl_len, + csd->read_bl_partial, csd->write_blk_misalign, + csd->read_blk_misalign, csd->dsr_imp, + csd->c_size, csd->vdd_r_curr_min, + csd->vdd_r_curr_max, csd->vdd_w_curr_min, + csd->vdd_w_curr_max, csd->c_size_mult, + csd->wp_grp_size, csd->wp_grp_enable, + csd->default_ecc, csd->r2w_factor, + csd->write_bl_len, csd->write_bl_partial, + csd->file_format_grp, csd->copy, + csd->perm_write_protect, csd->tmp_write_protect, + csd->file_format, csd->ecc); + switch ( csd->csd_structure ) { + case CSD_STRUCT_1_0: + case CSD_STRUCT_1_1: + printk(" V22 sector_size=%d erase_grp_size=%d\n", + csd->erase.v22.sector_size, + csd->erase.v22.erase_grp_size); + break; + case CSD_STRUCT_1_2: + default: + printk(" V31 erase_grp_size=%d erase_grp_mult=%d\n", + csd->erase.v31.erase_grp_size, + csd->erase.v31.erase_grp_mult); + break; + + } + + return MSS_ERROR_NONE; +} + +static int mmc_unpack_ext_csd(u8 *buf, struct mmc_ext_csd *ext_csd) +{ + ext_csd->s_cmd_set = buf[504]; + ext_csd->sec_count = ((u32)buf[212]) << 24 | ((u32)buf[213]) << 16 | ((u32)buf[214]) << 8 | ((u32)buf[215]) ; + ext_csd->min_perf_w_8_52 = buf[210]; + ext_csd->min_perf_r_8_52 = buf[209]; + ext_csd->min_perf_w_26_4_52 = buf[208]; + ext_csd->min_perf_r_26_4_52 = buf[207]; + ext_csd->min_perf_w_4_26 = buf[206]; + ext_csd->min_perf_r_4_26 = buf[205]; + ext_csd->pwr_cl_26_360 = buf[203]; + ext_csd->pwr_cl_52_360 = buf[202]; + ext_csd->pwr_cl_26_195 = buf[201]; + ext_csd->pwr_cl_52_195 = buf[200]; + ext_csd->card_type = buf[196]; + ext_csd->csd_structure = buf[194]; + ext_csd->ext_csd_rev = buf[192]; + ext_csd->cmd_set = buf[191]; + ext_csd->cmd_set_rev = buf[189]; + ext_csd->power_class = buf[187]; + ext_csd->hs_timing = buf[185]; + ext_csd->erased_mem_cont = buf[183]; + + return 0; +} + +/** + * The blocks requested by the kernel may or may not match what we can do. + * Unfortunately, filesystems play fast and loose with block sizes, so we're + * stuck with this . + */ +static void mmc_fix_request_block_len(struct mss_card *card, int action, struct mss_rw_arg *arg) +{ + u16 block_len = 0; + struct mmc_card *mmc_card = card->prot_card; + struct mss_host *host = card->slot->host; + + switch(action) { + case MSS_DATA_READ: + block_len = 1 << mmc_card->csd.read_bl_len; + break; + case MSS_DATA_WRITE: + block_len = 1 << mmc_card->csd.write_bl_len; + break; + default: + return; + } + if (host->high_capacity && mmc_card->access_mode == MMC_ACCESS_MODE_SECTOR) + block_len = 512; + if (block_len < arg->block_len) { + int scale = arg->block_len / block_len; + arg->block_len = block_len; + arg->block *= scale; + arg->nob *= scale; + } +} + + +/***************************************************************************** + * + * protocol entry functions + * + ****************************************************************************/ + +static u32 mmc_make_cmd6_arg(u8 access, u8 index, u8 value, u8 cmdset) +{ + u32 ret; + ret = (access << 24) | (index << 16) | (value << 8) | cmdset; + return ret; +} + +static int mmc_get_status(struct mss_card *card, u32 *status) +{ + struct mmc_response_r1 r1; + struct mmc_card *mmc_card = card->prot_card; + struct mss_host *host = card->slot->host; + struct mss_ll_request *llreq = &mmc_card->llreq; + struct mss_cmd *cmd = &mmc_card->cmd; + int clock, ret, retries = 4; + + clock = mmc_tran_speed(mmc_card->csd.tran_speed); + mss_set_clock(card->slot->host, clock); + while (retries--) { + dbg5("rety"); + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SEND_STATUS, + mmc_card->rca << 16, MSS_RESPONSE_R1, 0); + dbg5("retry ret :%d", ret); + if (ret && !retries) + return ret; + else if (!ret) { + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + if (ret) { + if (mmc_card->errno==MMC_ERROR_STATE_MISMATCH) { + mmc_card->state = + R1_CURRENT_STATE(r1.status); + mmc_card->errno = MMC_ERROR_NONE; + } + else + return ret; + } + else + break; + } + + clock = host->ios.clock; + clock = clock >> 1; + if (clock < MMC_CARD_CLOCK_SLOW || retries == 1) + clock = MMC_CARD_CLOCK_SLOW; + mss_set_clock(host, clock); + } + + *status = r1.status; + + return MSS_ERROR_NONE; +} + +static int mmc_recognize_card(struct mss_card *card) +{ + struct mmc_response_r3 r3; + struct mmc_card *mmc_card = card->prot_card; + struct mss_ios ios; + struct mss_host *host = card->slot->host; + struct mss_ll_request *llreq = &mmc_card->llreq; + struct mss_cmd *cmd = &mmc_card->cmd; + int ret; + u32 ocr = host->vdd; + + mmc_card->state = CARD_STATE_IDLE; + card->bus_width = MSS_BUSWIDTH_1BIT; + card->card_type = MSS_UNKNOWN_CARD; + + memcpy(&ios, &host->ios, sizeof(struct mss_ios)); + ios.bus_mode = MSS_BUSMODE_OPENDRAIN; + ios.clock = host->f_min; + ios.bus_width = MSS_BUSWIDTH_1BIT; + host->ops->set_ios(host, &ios); + + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_GO_IDLE_STATE, 0, + MSS_RESPONSE_NONE, MSS_CMD_INIT); + dbg2(card->slot, card->prot_driver, "Sending GO_IDLE cmd, ret:%d\n", ret); + if (ret) + return ret; + if (host->high_capacity) + ocr |= MMC_ACCESS_MODE_SECTOR; + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SEND_OP_COND, ocr, + MSS_RESPONSE_R3, 0); + dbg2(card->slot, card->prot_driver, "Sending SEND_OP_COND cmd, arg:0x%x\n, ret:%d", ocr, ret); + if (ret) + return ret; + + ret = mmc_unpack_r3(cmd, &r3, mmc_card); + dbg2(card->slot, card->prot_driver, "unapck ret %d, SEND_OP_COND ocr:0x%x", ret, r3.ocr); + if (!ret) { + if (r3.ocr & host->vdd) { + card->card_type = MSS_MMC_CARD; + } else { + printk(KERN_WARNING "uncompatible card\n"); + card->card_type = MSS_UNCOMPATIBLE_CARD; + } + return ret; + } + card->card_type = MSS_UNKNOWN_CARD; + + return MSS_ERROR_NONE; +} + +static int mmc_card_init(struct mss_card *card) +{ + struct mmc_response_r3 r3; + struct mmc_response_r1 r1; + struct mmc_cid cid; + struct mmc_card *mmc_card = card->prot_card; + struct mss_ios ios; + struct mss_host *host; + struct mss_ll_request *llreq = &mmc_card->llreq; + struct mss_cmd *cmd = &mmc_card->cmd; + struct mss_data *data = &mmc_card->data; + int ret; + u8 *g_buffer; + u32 ocr, arg, bus_width; + struct scatterlist sg; + + host = card->slot->host; + ocr = host->vdd; + + mmc_card->state = CARD_STATE_IDLE; + card->bus_width = MSS_BUSWIDTH_1BIT; + + memcpy(&ios, &host->ios, sizeof(struct mss_ios)); + ios.bus_mode = MSS_BUSMODE_OPENDRAIN; + ios.bus_width = MSS_BUSWIDTH_1BIT; + ios.clock = host->f_min; + host->ops->set_ios(host, &ios); + + dbg2(card->slot, card->prot_driver, "Sending GO_IDLE cmd, ret:%d\n", ret); + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_GO_IDLE_STATE, 0, + MSS_RESPONSE_NONE, MSS_CMD_INIT); + if (ret) + return ret; + + if (host->high_capacity) + ocr |= MMC_ACCESS_MODE_SECTOR; + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SEND_OP_COND, ocr, + MSS_RESPONSE_R3, 0); + dbg2(card->slot, card->prot_driver, "Sending SEND_OP_COND cmd, arg:0x%x\n, ret:%d", ocr, ret); + if (ret) + return ret; + + ret = mmc_unpack_r3(cmd, &r3, mmc_card); + dbg2(card->slot, card->prot_driver, "unapck ret %d, SEND_OP_COND ocr:0x%x", ret, r3.ocr); + if (ret) { + //printk(KERN_ERR "failed SEND_OP_COND error=%d (%s) \n", ret, mmc_result_to_string(ret)); + return ret; + } + + while (!(r3.ocr & MMC_CARD_BUSY)) { + //mdelay(20); + msleep(15); + dbg2(card->slot, card->prot_driver, "card is busy after SNED_OP_COND"); + ret = mss_send_simple_ll_req(host, llreq, cmd, + MMC_SEND_OP_COND, ocr, MSS_RESPONSE_R3, 0); + dbg2(card->slot, card->prot_driver, "Sending SEND_OP_COND cmd, arg:0x%x\n, ret:%d", ocr, ret); + if (ret) + return ret; + ret = mmc_unpack_r3(cmd, &r3, mmc_card); + dbg2(card->slot, card->prot_driver, "unapck ret %d, SEND_OP_COND ocr:0x%x", ret, r3.ocr); + if (ret) { + //printk(KERN_ERR ": failed SEND_OP_COND error=%d (%s) \n", retval, mmc_result_to_string(retval) ); + return ret; + } + } + + mmc_card->vdd = r3.ocr & MMC_VDD_MASK; + mmc_card->access_mode = r3.ocr & MMC_ACCESS_MODE_MASK; + mmc_card->state = CARD_STATE_READY; + + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_ALL_SEND_CID, 0, + MSS_RESPONSE_R2_CID, 0); + dbg2(card->slot, card->prot_driver, "Sending MMC_ALL_SEND_CID cmd, arg:0x%x\n, ret:%d", 0, ret); + if (ret) + return ret; + + memset(&cid, 0x0, sizeof(struct mmc_cid)); + ret = mmc_unpack_cid(cmd, &cid, mmc_card); + if (ret) + return ret; + + /* Not first init */ + if (mmc_card->cid.mid != 0) { + /* Card is changed */ + if (mmc_card->cid.mid != cid.mid || mmc_card->cid.oid != cid.oid + || mmc_card->cid.prv != cid.prv + || mmc_card->cid.psn != cid.psn + || mmc_card->cid.mdt != cid.mdt + || memcmp(mmc_card->cid.pnm, cid.pnm, 6)) + return MSS_ERROR_MISMATCH_CARD; + } + else + memcpy(&mmc_card->cid, &cid, sizeof(struct mmc_cid)); + + mmc_card->state = CARD_STATE_IDENT; + + mss_set_busmode(host, MSS_BUSMODE_PUSHPULL); + + mmc_card->rca = MMC_SLOT_RCA(card->slot); + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SET_RELATIVE_ADDR, + mmc_card->rca << 16, MSS_RESPONSE_R1, 0); + dbg2(card->slot, card->prot_driver, "Sending SET_REL_ADDR cmd, arg:0x%x\n, ret:%d", mmc_card->rca << 16, ret); + if (ret) + return ret; + + //mss_simple_cmd(dev, MMC_SET_RELATIVE_ADDR, (dev->slot->rca) << 16, RESPONSE_R1, buffer); + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + if (ret) { + //printk(KERN_INFO "MMC: unable to SET_RELATIVE_ADDR error=%d (%s)\n", retval, mmc_result_to_string(retval) ); + return ret; + } + mmc_card->state = CARD_STATE_STBY; + + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SEND_CSD, + mmc_card->rca << 16, MSS_RESPONSE_R2_CSD, 0); + dbg2(card->slot, card->prot_driver, "Sending MMC_SEND_CSD cmd, arg:0x%x\n, ret:%d", mmc_card->rca << 16, ret); + if (ret) + return ret; + ret = mmc_unpack_csd(cmd, &mmc_card->csd, mmc_card); + if (ret) { + //printk(KERN_INFO "MMC: unable to SEND_CSD error=%d (%s)\n", retval, mmc_result_to_string(retval) ); + return ret; + } + + /* + * if it is MMC4.x-compatible card and how many bits are working. + */ + if (mmc_card->csd.spec_vers != CSD_SPEC_VERS_4 + || host->mmc_spec != MSS_MMC_SPEC_40_42) + goto exit; + + g_buffer = mmc_card->buf;//kmalloc(512, GFP_KERNEL); + /*if (!g_buffer) + return -ENOMEM; */ + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SELECT_CARD, + mmc_card->rca << 16, MSS_RESPONSE_R1B, 0); + if (ret) + return ret; + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + if (ret) + return ret; + mmc_card->state = CARD_STATE_TRAN; + + /* + * set 1-bus mode in init. arg:access=0b11, arg:index=0xb7, arg:value=0 + * or CMD8 will not be responded with 1-bit/controller and 4-bit/card + * dev->bus_mode should be MSS_1_BIT before next command + * buffer = NULL; + */ + arg = mmc_make_cmd6_arg(0x3, 0xb7, 0, 0); + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SWITCH, arg, + MSS_RESPONSE_R1B, 0); + if (ret) + return ret; + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + if (ret) + return ret; + + card->bus_width = MSS_BUSWIDTH_1BIT; + mss_set_buswidth(host, MSS_BUSWIDTH_1BIT); + + sg.page = virt_to_page(g_buffer); + sg.offset = offset_in_page(g_buffer); + sg.length = 512; + + memset(llreq, 0x0, sizeof(struct mss_ll_request)); + memset(cmd, 0x0, sizeof(struct mss_cmd)); + memset(data, 0x0, sizeof(struct mss_data)); + MSS_INIT_CMD(cmd, MMC_SEND_EXT_CSD, 0, 0, MSS_RESPONSE_R1); + MSS_INIT_DATA(data, 1, 512, MSS_DATA_READ, 1, &sg, 0); + llreq->cmd = cmd; + llreq->data = data; + + ret = mss_send_ll_req(host, &mmc_card->llreq); + if (ret) + return ret; + ret = mmc_unpack_ext_csd(g_buffer, &mmc_card->ext_csd); + if (ret) + return ret; + + /* + * use CMD19/CMD14 (BUSTEST_W/BUSTEST_R) to test supported bus mode. + */ + memset(g_buffer, 0xFF, 512); + bus_width = host->bus_width; + if (bus_width == MSS_BUSWIDTH_1BIT) + goto exit; + else if (bus_width == MSS_BUSWIDTH_4BIT) { + card->bus_width = MSS_BUSWIDTH_4BIT; + g_buffer[0] = 0xa5; /* 0b10100101 */ + g_buffer[1] = 0xFF; /* 0b11111111 */ + } + else if (bus_width == MSS_BUSWIDTH_8BIT) { + card->bus_width = MSS_BUSWIDTH_8BIT; + g_buffer[0] = 0xaa; /* 0b10101010 */ + g_buffer[1] = 0x55; /* 0b01010101 */ + } + else + goto exit; + + mss_set_buswidth(host, bus_width); + + memset(llreq, 0x0, sizeof(struct mss_ll_request)); + memset(cmd, 0x0, sizeof(struct mss_cmd)); + memset(data, 0x0, sizeof(struct mss_data)); + MSS_INIT_CMD(cmd, MMC_BUSTEST_W, 0, 0, MSS_RESPONSE_R1); + MSS_INIT_DATA(data, 1, 512, MSS_DATA_WRITE, 1, &sg, 0); + llreq->cmd = cmd; + llreq->data = data; + + ret = mss_send_ll_req(host, &mmc_card->llreq); + if (ret) + return ret; + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + if (ret) + return ret; + + mmc_card->state = CARD_STATE_BTST; + memset(g_buffer, 0xFF, 512); + + memset(llreq, 0x0, sizeof(struct mss_ll_request)); + memset(cmd, 0x0, sizeof(struct mss_cmd)); + memset(data, 0x0, sizeof(struct mss_data)); + MSS_INIT_CMD(cmd, MMC_BUSTEST_R, 0, 0, MSS_RESPONSE_R1); + MSS_INIT_DATA(data, 1, 512, MSS_DATA_READ, 1, &sg, 0); + llreq->cmd = cmd; + llreq->data = data; + + ret = mss_send_ll_req(host, &mmc_card->llreq); + if (ret) + return ret; + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + if (ret) + return ret; + + if ((g_buffer[0] == 0x55/*0b01010101*/) && + (g_buffer[1] == 0xaa/*0b10101010*/)) { + mmc_card->bus_width = MSS_BUSWIDTH_8BIT; + } + else if (g_buffer[0] == 0x5a /*0b01011010*/) { + mmc_card->bus_width = MSS_BUSWIDTH_4BIT; + } + else { + mmc_card->bus_width = MSS_BUSWIDTH_1BIT; + } + + mmc_card->state = CARD_STATE_TRAN; + + arg = mmc_make_cmd6_arg(0x3, 0xb7, mmc_card->bus_width, 0); + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SWITCH, arg, + MSS_RESPONSE_R1B, 0); + if (ret) + return ret; + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + if (ret) + return ret; + + card->bus_width = mmc_card->bus_width; + /** + * use CMD6 to set high speed mode. arg:access=0b11, arg:index=0xb9, + * arg:value=1 according to card/controller high speed timing + * high speed mode for MMC-4.x compatible card. + */ + if (host->high_speed == MSS_HIGH_SPEED) { + mmc_make_cmd6_arg(0x3, 0xb9, 1, 0); + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SWITCH, arg, + MSS_RESPONSE_R1B, 0); + if (ret) + return ret; + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + if (ret) + return ret; + memcpy(&ios, &host->ios, sizeof(struct mss_ios)); + ios.high_speed = MSS_HIGH_SPEED; + ios.clock = MMC_CARD_CLOCK_FAST; + host->ops->set_ios(host, &ios); + if (host->ios.high_speed != MSS_HIGH_SPEED) { + u32 clock = mmc_tran_speed(mmc_card->csd.tran_speed); + mss_set_clock(host, clock); + } + } + else { + /* change to the highest speed in normal mode */ + u32 clock = mmc_tran_speed(mmc_card->csd.tran_speed); + mss_set_clock(host, clock); + } + + /** + * use CMD6 to set power class. arg:access=0b11, arg:index=0xbb, + * arg:value=card power class code according to card/controller supported + * power class. We read value from PWL_CL_ff_vvv and set it to POWER_CLASS + * according to supported voltage and clock rate. + */ + + /* Deselect the card */ + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SELECT_CARD, 0, + MSS_RESPONSE_R1B, 0); + if (ret) + return ret; + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + if (ret) + return ret; + mmc_card->state = CARD_STATE_STBY; + +exit: + return MSS_ERROR_NONE; +} + +static int mmc_read_write_entry(struct mss_card *card, int action, struct mss_rw_arg *arg, struct mss_rw_result *result) +{ + struct mmc_card *mmc_card = card->prot_card; + struct mss_host *host; + struct mss_ios ios; + struct mmc_response_r1 r1; + struct mss_ll_request *llreq = &mmc_card->llreq; + struct mss_cmd *cmd = &mmc_card->cmd; + struct mss_data *data = &mmc_card->data; + int ret, retries = 4, clock; + u32 status = 0; + int access_mode_sector = 0; + u32 cmdarg, blklen, opcode, flags; + + host = card->slot->host; + + ret = mmc_get_status(card, &status); + if (ret) + return ret; + + if (status & R1_CARD_IS_LOCKED) + return MSS_ERROR_LOCKED; + + if (action == MSS_WRITE_MEM && host->ops->is_slot_wp && + host->ops->is_slot_wp(card->slot)) + return MSS_ERROR_WP; + + if (mmc_card->state == CARD_STATE_STBY) { + ret = mss_send_simple_ll_req(host, llreq, cmd, MMC_SELECT_CARD, + mmc_card->rca << 16, MSS_RESPONSE_R1, 0); + if (ret) + return ret; + dbg5("select card cmd return ret:%d\n", ret); + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + if (ret) + return ret; + } + mmc_card->state = CARD_STATE_TRAN; + + mmc_fix_request_block_len(card, action, arg); + access_mode_sector = (mmc_card->access_mode == MMC_ACCESS_MODE_SECTOR) + && host->high_capacity; + memcpy(&ios, &host->ios, sizeof(struct mss_ios)); + if (access_mode_sector) { + ios.access_mode = MSS_ACCESS_MODE_SECTOR; + cmdarg = arg->block; + blklen = 512; + } + else { + if (arg->block_len != mmc_card->block_len) { + ret = mss_send_simple_ll_req(host, llreq, cmd, + MMC_SET_BLOCKLEN, arg->block_len, + MSS_RESPONSE_R1, 0); + if (ret) + return ret; + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + if (ret) + return ret; + mmc_card->block_len = arg->block_len; + } + cmdarg = arg->block * arg->block_len; + blklen = arg->block_len; + } + + if (mmc_card->csd.spec_vers == CSD_SPEC_VERS_4 && host->high_speed) { + ios.high_speed = MSS_HIGH_SPEED; + ios.clock = MMC_CARD_CLOCK_FAST; + } + else { + ios.clock = mmc_tran_speed(mmc_card->csd.tran_speed); + } + host->ops->set_ios(host, &ios); + + memset(llreq, 0x0, sizeof(struct mss_ll_request)); + memset(cmd, 0x0, sizeof(struct mss_cmd)); + memset(data, 0x0, sizeof(struct mss_data)); + llreq->cmd = cmd; + llreq->data = data; + +read_write_entry: + if (arg->nob > 1) { + if (action == MSS_READ_MEM) { + opcode = MMC_READ_MULTIPLE_BLOCK; + flags = MSS_DATA_READ | MSS_DATA_MULTI; + } + else { + opcode = MMC_WRITE_MULTIPLE_BLOCK; + flags = MSS_DATA_WRITE | MSS_DATA_MULTI; + } + + MSS_INIT_CMD(cmd, opcode, cmdarg, 0, MSS_RESPONSE_R1); + MSS_INIT_DATA(data, arg->nob, blklen, flags, arg->sg_len, + arg->sg, 0); + + ret = mss_send_ll_req(host, &mmc_card->llreq); + if (!ret) + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + + mmc_card->state = (action == MSS_WRITE_MEM) ? CARD_STATE_RCV + : CARD_STATE_DATA; + + if (ret) { + mss_send_simple_ll_req(host, llreq, cmd, + MMC_STOP_TRANSMISSION, 0, + (action == MSS_WRITE_MEM) ? + MSS_RESPONSE_R1B : MSS_RESPONSE_R1, 0); + mmc_card->state = CARD_STATE_TRAN; + + if (--retries) { + clock = host->ios.clock; + clock = clock >> 1; + if (clock < MMC_CARD_CLOCK_SLOW && retries == 1) + clock = MMC_CARD_CLOCK_SLOW; + mss_set_clock(host, clock); + goto read_write_entry; + } + return ret; + } + ret = mss_send_simple_ll_req(host, llreq, cmd, + MMC_STOP_TRANSMISSION, 0, + (action == MSS_WRITE_MEM) ? + MSS_RESPONSE_R1B : MSS_RESPONSE_R1, 0); + if (ret) + return ret; + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + mmc_card->state = CARD_STATE_TRAN; + + if (ret && (mmc_card->errno != MMC_ERROR_OUT_OF_RANGE)) + return ret; + } else { + if (action == MSS_READ_MEM) { + opcode = MMC_READ_SINGLE_BLOCK; + flags = MSS_DATA_READ; + } + else { + opcode = MMC_WRITE_BLOCK; + flags = MSS_DATA_WRITE; + } + MSS_INIT_CMD(cmd, opcode, cmdarg, 0, MSS_RESPONSE_R1); + MSS_INIT_DATA(data, arg->nob, blklen, flags, arg->sg_len, + arg->sg, 0); + + ret = mss_send_ll_req(host, &mmc_card->llreq); + if (!ret) + ret = mmc_unpack_r1(cmd, &r1, mmc_card); + if (ret) { + if (--retries) { + clock = host->ios.clock; + clock = clock >> 1; + if (clock < MMC_CARD_CLOCK_SLOW && retries == 1) + clock = MMC_CARD_CLOCK_SLOW; + mss_set_clock(host, clock); + goto read_write_entry; + } + return ret; + } + } + /* Deselect the card */ + /*mmc_simple_ll_req(host, mmc_card, MMC_SELECT_CARD, + 0, MSS_RESPONSE_NONE, 0); + if (ret) + return ret; + ret = mmc_unpack_r1(&mmc_card->cmd, &r1, mmc_card); + mmc_card->state = CARD_STATE_STBY;*/ + if (ret) + return ret; + result->bytes_xfered = data->bytes_xfered; + + return MSS_ERROR_NONE; +} + +/* count by 512 bytes */ +static int mmc_get_capacity(struct mss_card *card, u32 *size) +{ + int c_size = 0; + int c_size_mult = 0; + struct mmc_card *mmc_card = card->prot_card; + struct mss_host *host = card->slot->host; + + if (mmc_card->access_mode == MMC_ACCESS_MODE_SECTOR && host->high_capacity) + *size = mmc_card->ext_csd.sec_count; + else { + c_size = mmc_card->csd.c_size; + c_size_mult = mmc_card->csd.c_size_mult; + *size = (c_size + 1) + << (2 + c_size_mult + mmc_card->csd.read_bl_len - 9); + } + dbg5("the capacity :0x%x", *size); + return MSS_ERROR_NONE; +} + + +/***************************************************************************** + * + * protocol driver interface functions + * + ****************************************************************************/ + +static int mmc_prot_entry(struct mss_card *card, unsigned int action, void *arg, void *result) +{ + u32 status; + int ret; + + if (action != MSS_RECOGNIZE_CARD && card->card_type != MSS_MMC_CARD) + return MSS_ERROR_WRONG_CARD_TYPE; + switch (action) { + case MSS_RECOGNIZE_CARD: + ret = mmc_recognize_card(card); + break; + case MSS_INIT_CARD: + ret = mmc_card_init(card); + break; + case MSS_READ_MEM: + case MSS_WRITE_MEM: + if (!arg) + return -EINVAL; + ret = mmc_read_write_entry(card, action, arg, result); + break; + case MSS_QUERY_CARD: + ret = mmc_get_status(card, &status); + break; + case MSS_GET_CAPACITY: + ret = mmc_get_capacity(card, result); + break; + default: + ret = MSS_ERROR_ACTION_UNSUPPORTED; + break; + } + //dbg("mmc protocol entry exit, ret: %d, action: %d\n", ret, action); + return ret; +} + +static int mmc_prot_attach_card(struct mss_card *card) +{ + struct mmc_card *mmc_card; + +#define ALIGN32(x) (((x) + 31) & (~31)) + mmc_card = kzalloc(ALIGN32(ALIGN32(sizeof(struct mmc_card))) + 512, + GFP_KERNEL); + card->prot_card = mmc_card; + if (mmc_card) { + mmc_card->buf = (char *)ALIGN32((unsigned int)&mmc_card[1]); + return 0; + } + return -ENOMEM; +} + +static void mmc_prot_detach_card(struct mss_card *card) +{ + kfree(card->prot_card); +} + +static int mmc_prot_get_errno(struct mss_card *card) +{ + struct mmc_card *mmc_card = card->prot_card; + return mmc_card->errno; +} + +static struct mss_prot_driver mmc_protocol = { + .name = MMC_PROTOCOL, + .prot_entry = mmc_prot_entry, + .attach_card = mmc_prot_attach_card, + .detach_card = mmc_prot_detach_card, + .get_errno = mmc_prot_get_errno, +}; + +static int mmc_protocol_init(void) +{ + register_mss_prot_driver(&mmc_protocol); + return 0; +} + +static void mmc_protocol_exit(void) +{ + unregister_mss_prot_driver(&mmc_protocol); +} + + +module_init(mmc_protocol_init); +module_exit(mmc_protocol_exit); + +MODULE_AUTHOR("Bridge Wu"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MMC protocol driver"); --- linux-2.6.24.orig/drivers/mmc/mss/Kconfig +++ linux-2.6.24/drivers/mmc/mss/Kconfig @@ -0,0 +1,28 @@ +# +# MMC subsystem configuration +# + +comment "MSS structure support" + + +config MSS_BLOCK + tristate "MSS block device driver" + depends on MSS && BLOCK + default y + help + Say Y here to enable the MMC block device driver support. + This provides a block device driver, which you can use to + mount the filesystem. Almost everyone wishing MMC support + should say Y or M here. + +config MSS_SDHCI + tristate "MSS host controller driver" + depends on PCI && MSS + help + This select the generic Secure Digital Host Controller Interface. + It is used by manufacturers such as Texas Instruments(R), Ricoh(R) + and Toshiba(R). Most controllers found in laptops are of this type. + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + --- linux-2.6.24.orig/drivers/mmc/mss/mss_sdhci.h +++ linux-2.6.24/drivers/mmc/mss/mss_sdhci.h @@ -0,0 +1,248 @@ +/* + * mss_sdhci.h - SD Host Controller interface driver + * + * Copyright (C) 2007 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 only + * for now as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * derived from linux/drivers/mmc/sdhci.h + * Copyright (c) 2005 Pierre Ossman + */ + + +/* + * PCI registers + */ +#define MSS_VDD_150 0 +#define MSS_VDD_155 1 +#define MSS_VDD_160 2 +#define MSS_VDD_165 3 +#define MSS_VDD_170 4 +#define MSS_VDD_180 5 +#define MSS_VDD_190 6 +#define MSS_VDD_200 7 +#define MSS_VDD_210 8 +#define MSS_VDD_220 9 +#define MSS_VDD_230 10 +#define MSS_VDD_240 11 +#define MSS_VDD_250 12 +#define MSS_VDD_260 13 +#define MSS_VDD_270 14 +#define MSS_VDD_280 15 +#define MSS_VDD_290 16 +#define MSS_VDD_300 17 +#define MSS_VDD_310 18 +#define MSS_VDD_320 19 +#define MSS_VDD_330 20 +#define MSS_VDD_340 21 +#define MSS_VDD_350 22 +#define MSS_VDD_360 23 + +#define PCI_SDHCI_IFPIO 0x00 +#define PCI_SDHCI_IFDMA 0x01 +#define PCI_SDHCI_IFVENDOR 0x02 + +#define PCI_SLOT_INFO 0x40 /* 8 bits */ +#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7) +#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07 + +/* + * Controller registers + */ +#define SDHCI_DMA_ADDRESS 0x00 +#define SDHCI_BLOCK_SIZE 0x04 +#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) + +#define SDHCI_BLOCK_COUNT 0x06 +#define SDHCI_ARGUMENT 0x08 + +#define SDHCI_TRANSFER_MODE 0x0C +#define SDHCI_TRNS_DMA 0x01 +#define SDHCI_TRNS_BLK_CNT_EN 0x02 +#define SDHCI_TRNS_ACMD12 0x04 +#define SDHCI_TRNS_READ 0x10 +#define SDHCI_TRNS_MULTI 0x20 + +#define SDHCI_COMMAND 0x0E +#define SDHCI_CMD_RESP_MASK 0x03 +#define SDHCI_CMD_CRC 0x08 +#define SDHCI_CMD_INDEX 0x10 +#define SDHCI_CMD_DATA 0x20 + +#define SDHCI_CMD_RESP_NONE 0x00 +#define SDHCI_CMD_RESP_LONG 0x01 +#define SDHCI_CMD_RESP_SHORT 0x02 +#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 + +#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff)) + +#define SDHCI_RESPONSE 0x10 +#define SDHCI_BUFFER 0x20 +#define SDHCI_PRESENT_STATE 0x24 + +#define SDHCI_CMD_INHIBIT 0x00000001 +#define SDHCI_DATA_INHIBIT 0x00000002 +#define SDHCI_DOING_WRITE 0x00000100 +#define SDHCI_DOING_READ 0x00000200 +#define SDHCI_SPACE_AVAILABLE 0x00000400 +#define SDHCI_DATA_AVAILABLE 0x00000800 +#define SDHCI_CARD_PRESENT 0x00010000 +#define SDHCI_WRITE_PROTECT 0x00080000 + +#define SDHCI_HOST_CONTROL 0x28 +#define SDHCI_CTRL_LED 0x01 +#define SDHCI_CTRL_4BITBUS 0x02 +#define SDHCI_CTRL_HISPD 0x04 + +#define SDHCI_POWER_CONTROL 0x29 +#define SDHCI_POWER_ON 0x01 +#define SDHCI_POWER_180 0x0A +#define SDHCI_POWER_300 0x0C +#define SDHCI_POWER_330 0x0E + +#define SDHCI_BLOCK_GAP_CONTROL 0x2A + +#define SDHCI_WALK_UP_CONTROL 0x2B + +#define SDHCI_CLOCK_CONTROL 0x2C +#define SDHCI_DIVIDER_SHIFT 8 +#define SDHCI_CLOCK_CARD_EN 0x0004 +#define SDHCI_CLOCK_INT_STABLE 0x0002 +#define SDHCI_CLOCK_INT_EN 0x0001 + +#define SDHCI_TIMEOUT_CONTROL 0x2E + +#define SDHCI_SOFTWARE_RESET 0x2F +#define SDHCI_RESET_ALL 0x01 +#define SDHCI_RESET_CMD 0x02 +#define SDHCI_RESET_DATA 0x04 + +#define SDHCI_INT_STATUS 0x30 +#define SDHCI_INT_ENABLE 0x34 +#define SDHCI_SIGNAL_ENABLE 0x38 +#define SDHCI_INT_RESPONSE 0x00000001 +#define SDHCI_INT_DATA_END 0x00000002 +#define SDHCI_INT_BLK_GAP 0x00000004 +#define SDHCI_INT_DMA_END 0x00000008 +#define SDHCI_INT_SPACE_AVAIL 0x00000010 +#define SDHCI_INT_DATA_AVAIL 0x00000020 +#define SDHCI_INT_CARD_INSERT 0x00000040 +#define SDHCI_INT_CARD_REMOVE 0x00000080 +#define SDHCI_INT_CARD_INT 0x00000100 +#define SDHCI_INT_ERROR 0x00008000 +#define SDHCI_INT_TIMEOUT 0x00010000 +#define SDHCI_INT_CRC 0x00020000 +#define SDHCI_INT_END_BIT 0x00040000 +#define SDHCI_INT_INDEX 0x00080000 +#define SDHCI_INT_DATA_TIMEOUT 0x00100000 +#define SDHCI_INT_DATA_CRC 0x00200000 +#define SDHCI_INT_DATA_END_BIT 0x00400000 +#define SDHCI_INT_BUS_POWER 0x00800000 +#define SDHCI_INT_ACMD12ERR 0x01000000 + +#define SDHCI_INT_NORMAL_MASK 0x00007FFF +#define SDHCI_INT_ERROR_MASK 0xFFFF8000 + +#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \ + SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX) +#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ + SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ + SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ + SDHCI_INT_DATA_END_BIT) + +#define SDHCI_ACMD12_ERR 0x3C + +/* 3E-3F reserved */ + +#define SDHCI_CAPABILITIES 0x40 +#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F +#define SDHCI_TIMEOUT_CLK_SHIFT 0 +#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 +#define SDHCI_CLOCK_BASE_MASK 0x00003F00 +#define SDHCI_CLOCK_BASE_SHIFT 8 +#define SDHCI_MAX_BLOCK_MASK 0x00030000 +#define SDHCI_MAX_BLOCK_SHIFT 16 +#define SDHCI_CAN_DO_HISPD 0x00200000 +#define SDHCI_CAN_DO_DMA 0x00400000 +#define SDHCI_CAN_VDD_330 0x01000000 +#define SDHCI_CAN_VDD_300 0x02000000 +#define SDHCI_CAN_VDD_180 0x04000000 + +/* 44-47 reserved for more caps */ + +#define SDHCI_MAX_CURRENT 0x48 + +/* 4C-4F reserved for more max current */ +/* 50-FB reserved */ + +#define SDHCI_SLOT_INT_STATUS 0xFC + +#define SDHCI_HOST_VERSION 0xFE +#define SDHCI_VENDOR_VER_MASK 0xFF00 +#define SDHCI_VENDOR_VER_SHIFT 8 +#define SDHCI_SPEC_VER_MASK 0x00FF +#define SDHCI_SPEC_VER_SHIFT 0 + +#define SDHCI_USE_DMA (1<<0) + +struct sdhci_chip; + +struct sdhci_host { + struct sdhci_chip *chip; + struct mss_host *mmc; /* MMC structure */ + + spinlock_t lock; /* Mutex */ + int flags; /* Host attributes */ + + + unsigned int max_clk; /* Max possible freq (MHz) */ + unsigned int timeout_clk; /* Timeout freq (KHz) */ + unsigned int max_block; /* Max block size (bytes) */ + + unsigned int clock; /* Current clock (MHz) */ + unsigned short power; /* Current voltage */ + + struct mss_ll_request *mrq; /* Current request */ + struct mss_cmd *cmd; /* Current command */ + struct mss_data *data; /* Current data request */ + struct mss_card *card; + + struct scatterlist *cur_sg; /* We're working on this */ + char *mapped_sg; /* This is where it's mapped */ + int num_sg; /* Entries left */ + int offset; /* Offset into current sg */ + int remain; /* Bytes left in current */ + int size; /* Remaining bytes in transfer */ + + char slot_descr[20]; /* Name for reservations */ + int irq; /* Device IRQ */ + int bar; /* PCI BAR index */ + unsigned long addr; /* Bus address */ + void __iomem * ioaddr; /* Mapped address */ + + struct tasklet_struct card_tasklet; /* Tasklet structures */ + struct tasklet_struct finish_tasklet; + + struct timer_list timer; /* Timer for timeouts */ +}; + +struct sdhci_chip { + struct pci_dev *pdev; + unsigned long quirks; + int num_slots; /* Slots on controller */ + struct sdhci_host *hosts[0]; /* Pointers to hosts */ +}; --- linux-2.6.24.orig/drivers/mmc/mss/sdio_protocol.c +++ linux-2.6.24/drivers/mmc/mss/sdio_protocol.c @@ -0,0 +1,1094 @@ +/* + * sdio_protocol.c - SDIO protocol driver + * + * Copyright (C) 2007 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 only + * for now as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * derived from previous mmc code in Linux kernel + * Copyright (c) 2002 Hewlett-Packard Company + * Copyright (c) 2002 Andrew Christian + * Copyright (c) 2006 Bridge Wu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/***************************************************************************** + * + * internal functions + * + ****************************************************************************/ + +#define KBPS 1 +#define MBPS 1000 + +static u32 ts_exp[] = { 100*KBPS, 1*MBPS, 10*MBPS, 100*MBPS, 0, 0, 0, 0 }; +static u32 ts_mul[] = { 0, 1000, 1200, 1300, 1500, 2000, 2500, 3000, + 3500, 4000, 4500, 5000, 5500, 6000, 7000, 8000 }; + +static u32 sdio_tran_speed( u8 ts ) +{ + u32 clock = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3]; + + dbg5("clock :%d", clock); + return clock; +} + +static int sdio_unpack_r1(struct mss_cmd *cmd, struct sdio_response_r1 *r1, struct sdio_card *sdio_card) +{ + u8 *buf = cmd->response; + + //debug(" result in r1: %d\n", request->result); + //if ( request->result ) return request->result; + + sdio_card->errno = SDIO_ERROR_NONE; + r1->cmd = unstuff_bits(buf, 40, 8, 6); + r1->status = unstuff_bits(buf, 8, 32, 6); + + dbg5("status 0x%x", r1->status); + if (R1_STATUS(r1->status)) { + if (r1->status & R1_OUT_OF_RANGE) + sdio_card->errno = SDIO_ERROR_OUT_OF_RANGE; + if (r1->status & R1_COM_CRC_ERROR) + sdio_card->errno = SDIO_ERROR_COM_CRC; + if (r1->status & R1_ILLEGAL_COMMAND) + sdio_card->errno = SDIO_ERROR_ILLEGAL_COMMAND; + if (r1->status & R1_ERROR) + sdio_card->errno = SDIO_ERROR_GENERAL; + } + + if (r1->cmd != cmd->opcode) + sdio_card->errno = SDIO_ERROR_HEADER_MISMATCH; + dbg5("command:0x%x", r1->cmd); + /* This should be last - it's the least dangerous error */ + if (sdio_card->errno != SDIO_ERROR_NONE) + return MSS_ERROR_RESP_UNPACK; + return MSS_ERROR_NONE; +} + + +static int sdio_unpack_r4(struct mss_cmd *cmd, struct sdio_response_r4 *r4, struct sdio_card *sdio_card) +{ + u8 *buf = cmd->response; + + r4->ocr = unstuff_bits(buf, 8, 24, 6); + r4->ready = unstuff_bits(buf, 39, 1, 6); + r4->mem_present = unstuff_bits(buf, 35, 1, 6); + r4->func_num = unstuff_bits(buf, 36, 3, 6); + dbg5("ocr=%08x,ready=%d,mp=%d,fun_num:%d\n", r4->ocr, r4->ready, +r4->mem_present, r4->func_num); + return 0; +} + + +static int sdio_unpack_r5(struct mss_cmd *cmd, struct sdio_response_r5 *r5, struct sdio_card *sdio_card) +{ + u8 *buf = cmd->response; + + sdio_card->errno = SDIO_ERROR_NONE; + r5->cmd = unstuff_bits(buf, 40, 8, 6); + r5->status = unstuff_bits(buf, 16, 8, 6); + r5->data = unstuff_bits(buf, 8, 8, 6); + dbg5("cmd=%d status=%02x,data:%02x", r5->cmd, r5->status, r5->data); + + if (r5->status) { + if (r5->status & R5_OUT_OF_RANGE) + return SDIO_ERROR_OUT_OF_RANGE; + if (r5->status & R5_COM_CRC_ERROR) + return SDIO_ERROR_COM_CRC; + if (r5->status & R5_ILLEGAL_COMMAND) + return SDIO_ERROR_ILLEGAL_COMMAND; + if (r5->status & R5_ERROR) + return SDIO_ERROR_GENERAL; + if (r5->status & R5_FUNCTION_NUMBER) + return SDIO_ERROR_FUNC_NUM; + } + + if (r5->cmd != cmd->opcode) { + return SDIO_ERROR_HEADER_MISMATCH; + } + + return 0; +} + +static u16 sdio_unpack_r6(struct mss_cmd *cmd, struct sdio_response_r6 *r6, struct sdio_card *sdio_card) +{ + u8 *buf = cmd->response; + int errno = SDIO_ERROR_NONE; + + r6->cmd = unstuff_bits(buf, 40, 8, 6); + r6->rca = unstuff_bits(buf, 24, 16, 6); + r6->status = unstuff_bits(buf, 8, 16, 6); + if (R6_STATUS(r6->status)) { + if (r6->status & R6_COM_CRC_ERROR) + errno = SDIO_ERROR_COM_CRC; + if (r6->status & R6_ILLEGAL_COMMAND) + errno = SDIO_ERROR_ILLEGAL_COMMAND; + if (r6->status & R6_ERROR) + errno = SDIO_ERROR_GENERAL; + } + if (r6->cmd != cmd->opcode) + errno = SDIO_ERROR_HEADER_MISMATCH; + sdio_card->errno = errno; + if (errno) + return MSS_ERROR_RESP_UNPACK; + return 0 ; + +} + + +/***************************************************************************** + * + * internal functions + * + ****************************************************************************/ + +/* sdio related function */ +static u32 sdio_make_cmd52_arg(int rw, int fun_num, int raw, int address, int write_data) +{ + u32 ret; + dbg5("rw:%d,fun:%d,raw:%d,address:%d,write_data:%d\n", + rw, fun_num, raw, address, write_data); + ret = (rw << 31) | (fun_num << 28) | (raw << 27) | (address << 9) | write_data; + return ret; +} + +static u32 sdio_make_cmd53_arg(int rw, int fun_num, int block_mode, int op_code, int address, int count) +{ + u32 ret; + dbg5("rw:%d,fun:%d,block_mode:%d,op_code:%d,address:%d,count:%d\n", + rw, fun_num, block_mode, op_code, address, count); + ret = (rw << 31) | (fun_num << 28) | (block_mode << 27) | (op_code << 26) | (address << 9) | count; + return ret; +} + +#define SDIO_FN0_READ_REG(addr) \ + do { \ + arg = sdio_make_cmd52_arg(SDIO_R, 0, 0, addr, 0); \ + ret = mss_send_simple_ll_req(host, llreq, cmd, \ + IO_RW_DIRECT, arg, MSS_RESPONSE_R5, \ + MSS_CMD_SDIO_EN); \ + if (ret) { \ + dbg5("CMD ERROR: ret = %d\n", ret); \ + return ret; \ + } \ + ret = sdio_unpack_r5(cmd, &r5, sdio_card); \ + if (ret) { \ + dbg5("UNPACK ERROR: ret = %d\n", ret); \ + return ret; \ + } \ + } while(0) + +#define SDIO_FN0_WRITE_REG(addr, val) \ + do { \ + arg = sdio_make_cmd52_arg(SDIO_W, 0, 0, addr, val); \ + ret = mss_send_simple_ll_req(host, llreq, cmd, \ + IO_RW_DIRECT, arg, MSS_RESPONSE_R5, \ + MSS_CMD_SDIO_EN); \ + if (ret) { \ + dbg5("CMD ERROR: ret = %d\n", ret); \ + return ret; \ + } \ + ret = sdio_unpack_r5(cmd, &r5, sdio_card); \ + if (ret) { \ + dbg5("UNPACK ERROR: ret = %d\n", ret); \ + return ret; \ + } \ + } while(0) + + +static int sdio_set_bus_width(struct mss_card *card, u8 buswidth) +{ + struct mss_host *host = card->slot->host; + struct sdio_card *sdio_card = card->prot_card; + struct mss_cmd *cmd = &sdio_card->cmd; + struct mss_ll_request *llreq = &sdio_card->llreq; + struct sdio_response_r5 r5; + int ret,arg; + + SDIO_FN0_WRITE_REG(BUS_IF_CTRL, buswidth); + card->bus_width = MSS_BUSWIDTH_4BIT; + + return 0; +} + +static int sdio_set_block_size(struct mss_card *card, u16 size, int func) +{ + struct mss_host *host = card->slot->host; + struct sdio_card *sdio_card = card->prot_card; + struct mss_cmd *cmd = &sdio_card->cmd; + struct mss_ll_request *llreq = &sdio_card->llreq; + struct sdio_response_r5 r5; + int ret,arg; + u8 tmp; + + if (func == 0) { + tmp = size & 0xff; + SDIO_FN0_WRITE_REG(FN0_BLKSZ_1, tmp); + + tmp = (size & 0xff00) >> 8; + SDIO_FN0_WRITE_REG(FN0_BLKSZ_2, tmp); + + sdio_card->cccr.fn0_blksz = size; + } else { + tmp = size & 0xff; + SDIO_FN0_WRITE_REG(FNn_BLKSZ_1(func), tmp); + + tmp = (size & 0xff00) >> 8; + SDIO_FN0_WRITE_REG(FNn_BLKSZ_2(func), tmp); + + sdio_card->fbr[func].fn_blksz = size; + } + + return 0; +} + +static int sdio_io_enable(struct mss_card *card, u8 set_mask) +{ + struct mss_host *host = card->slot->host; + struct sdio_card *sdio_card = card->prot_card; + struct mss_cmd *cmd = &sdio_card->cmd; + struct mss_ll_request *llreq = &sdio_card->llreq; + struct sdio_response_r5 r5; + int ret, arg; + + SDIO_FN0_WRITE_REG(IO_ENABLE, set_mask); + + return 0; +} + +static int sdio_interrupt_enable(struct mss_card *card, u8 set_mask) +{ + struct mss_host *host = card->slot->host; + struct sdio_card *sdio_card = card->prot_card; + struct mss_cmd *cmd = &sdio_card->cmd; + struct mss_ll_request *llreq = &sdio_card->llreq; + struct sdio_response_r5 r5; + int ret, arg; + + SDIO_FN0_WRITE_REG(INT_ENABLE, set_mask); + + return 0; +} + +static int sdio_csa_enable(struct mss_card *card, int func) +{ + struct mss_host *host = card->slot->host; + struct sdio_card *sdio_card = card->prot_card; + struct mss_cmd *cmd = &sdio_card->cmd; + struct mss_ll_request *llreq = &sdio_card->llreq; + struct sdio_response_r5 r5; + int arg; + int ret = 0; + + if(sdio_card->fbr[func].fun_support_csa == 0) + return ret; + + SDIO_FN0_WRITE_REG(FNn_IF_CODE(func), 0x80); + + return 0; +} + + +static int get_sdio_fbr_info(struct mss_card *card, int func) +{ + struct mss_host *host = card->slot->host; + struct sdio_card *sdio_card = card->prot_card; + struct mss_cmd *cmd = &sdio_card->cmd; + struct mss_ll_request *llreq = &sdio_card->llreq; + struct sdio_response_r5 r5; + int ret,arg; + u32 tmp; + + dbg5("get_sdio_fbr_info"); + SDIO_FN0_READ_REG(FNn_IF_CODE(func)); + sdio_card->fbr[func].fun_if_code = r5.data & 0xF; + sdio_card->fbr[func].fun_support_csa = (r5.data >> 6) & 0x1; + sdio_card->fbr[func].fun_csa_enable = (r5.data >> 7) & 0x1; + + SDIO_FN0_READ_REG(FNn_EXT_IF_CODE(func)); + sdio_card->fbr[func].fun_ext_if_code = r5.data; + + SDIO_FN0_READ_REG(FNn_CIS_POINTER_1(func)); + tmp = r5.data; + SDIO_FN0_READ_REG(FNn_CIS_POINTER_2(func)); + tmp |= r5.data << 8; + SDIO_FN0_READ_REG(FNn_CIS_POINTER_3(func)); + tmp |= r5.data << 16; + sdio_card->fbr[func].pfcis = tmp; + + SDIO_FN0_READ_REG(FNn_CSA_POINTER_1(func)); + tmp = r5.data; + SDIO_FN0_READ_REG(FNn_CSA_POINTER_2(func)); + tmp |= r5.data << 8; + SDIO_FN0_READ_REG(FNn_CSA_POINTER_3(func)); + tmp |= r5.data << 16; + sdio_card->fbr[func].pcsa = tmp; + + SDIO_FN0_READ_REG(FNn_BLKSZ_1(func)); + tmp = r5.data; + SDIO_FN0_READ_REG(FNn_BLKSZ_2(func)); + tmp |= r5.data << 8; + sdio_card->fbr[func].fn_blksz = tmp; + + dbg5("func:%d, csa:0x%x, cis:0x%x, blksz:0x%x", func, sdio_card->fbr[func].pcsa, sdio_card->fbr[func].pfcis, sdio_card->fbr[func].fn_blksz); + + return 0; +} + +static int get_sdio_cccr_info(struct mss_card *card) +{ + struct mss_host *host = card->slot->host; + struct sdio_card *sdio_card = card->prot_card; + struct mss_cmd *cmd = &sdio_card->cmd; + struct mss_ll_request *llreq = &sdio_card->llreq; + struct sdio_response_r5 r5; + int ret, arg; + u32 tmp; + + dbg5("get_sdio_cccr_info"); + SDIO_FN0_READ_REG(CCCR_SDIO_REVISION); + sdio_card->cccr.sdiox = (r5.data >> 4) & 0xf; + sdio_card->cccr.cccrx = r5.data & 0xf; + + SDIO_FN0_READ_REG(SD_SPEC_REVISION); + sdio_card->cccr.sdx = r5.data & 0xf; + + SDIO_FN0_READ_REG(IO_ENABLE); + sdio_card->cccr.ioex = r5.data; + + SDIO_FN0_READ_REG(IO_READY); + sdio_card->cccr.iorx = r5.data; + + SDIO_FN0_READ_REG(INT_ENABLE); + sdio_card->cccr.intex = r5.data; + + SDIO_FN0_READ_REG(INT_PENDING); + sdio_card->cccr.intx = r5.data; + + SDIO_FN0_READ_REG(BUS_IF_CTRL); + sdio_card->cccr.buswidth = r5.data & 0x3; + sdio_card->cccr.cd = (r5.data >> 7) & 0x1; + + SDIO_FN0_READ_REG(CARD_CAPABILITY); + sdio_card->cccr.sdc = r5.data & 0x1; + sdio_card->cccr.smb = (r5.data >> 1) & 0x1; + sdio_card->cccr.srw = (r5.data >> 2) & 0x1; + sdio_card->cccr.sbs = (r5.data >> 3) & 0x1; + sdio_card->cccr.s4mi = (r5.data >> 4) & 0x1; + sdio_card->cccr.e4mi = (r5.data >> 5) & 0x1; + sdio_card->cccr.lsc = (r5.data >> 6) & 0x1; + sdio_card->cccr.ls4b = (r5.data >> 7) & 0x1; + + SDIO_FN0_READ_REG(COMMON_CIS_POINTER_1); + tmp = r5.data; + SDIO_FN0_READ_REG(COMMON_CIS_POINTER_2); + tmp |= r5.data << 8; + SDIO_FN0_READ_REG(COMMON_CIS_POINTER_3); + tmp |= r5.data << 16; + sdio_card->cccr.pccis = tmp; + + SDIO_FN0_READ_REG(BUS_SUSPEND); + sdio_card->cccr.bs = r5.data & 0x1; + sdio_card->cccr.br = (r5.data >> 1) & 0x1; + + SDIO_FN0_READ_REG(FUNCTION_SELECT); + sdio_card->cccr.fsx = r5.data & 0xf; + sdio_card->cccr.df = (r5.data >> 7) & 0x1; + + SDIO_FN0_READ_REG(EXEC_FLAGS); + sdio_card->cccr.exx = r5.data; + + SDIO_FN0_READ_REG(READY_FLAGS); + sdio_card->cccr.rfx = r5.data; + + SDIO_FN0_READ_REG(FN0_BLKSZ_1); + tmp = r5.data; + SDIO_FN0_READ_REG(FN0_BLKSZ_2); + tmp |= r5.data << 8; + sdio_card->cccr.fn0_blksz = tmp; + + SDIO_FN0_READ_REG(POWER_CTRL); + sdio_card->cccr.smpc = r5.data & 0x1; + sdio_card->cccr.empc = (r5.data >> 1) & 0x1; + + dbg5("cccr, card capability: low_speed_card:%d" + " low_speed_card_4bit:%d int_bw_block:%d\n" + " suspend/resume:%d read/wait:%d multiblcok:%d direct_cmd:%d\n", + sdio_card->cccr.lsc, sdio_card->cccr.ls4b, + sdio_card->cccr.s4mi, sdio_card->cccr.sbs, + sdio_card->cccr.srw, sdio_card->cccr.smb, sdio_card->cccr.sdc); + dbg5("sdio:%d, sd:%d, cccr:%d, common cis:0x%x\n", sdio_card->cccr.sdiox, sdio_card->cccr.sdx, sdio_card->cccr.cccrx, sdio_card->cccr.pccis); + dbg5("spmc:%d\n", sdio_card->cccr.smpc); + dbg5("ioe:0x%x, ior:0x%x\n", sdio_card->cccr.ioex, sdio_card->cccr.iorx); + return 0; +} + +static int get_sdio_fcis_info(struct mss_card *card, int func) +{ + struct mss_host *host= card->slot->host; + struct sdio_card *sdio_card = card->prot_card; + struct mss_cmd *cmd = &sdio_card->cmd; + struct mss_ll_request *llreq = &sdio_card->llreq; + int ret, arg, tuple_body_len, tuple_type; + struct sdio_response_r5 r5; + u32 addr, next_addr; + u32 tmp; + u16 tmp16; + + dbg5("get_sdio_fcis_info"); + addr = sdio_card->fbr[func].pfcis; + + while(1) { + SDIO_FN0_READ_REG(addr); + tuple_type = r5.data; + + SDIO_FN0_READ_REG(addr + 1); + tuple_body_len = r5.data; + + next_addr = addr + 2 + r5.data; + switch (tuple_type) { + case CISTPL_NULL: + case CISTPL_END: + dbg5("cistpl null/end\n"); + goto finish; + case CISTPL_CHECKSUM: + dbg5("cistpl checksum\n"); + break; + case CISTPL_VERS_1: + dbg5("cistpl vers level 1\n"); + break; + case CISTPL_ALTSTR: + dbg5("cistpl altstr\n"); + break; + case CISTPL_MANFID: + dbg5("cistpl manfid\n"); + break; + case CISTPL_FUNCID: + dbg5("cistpl funcid\n"); + SDIO_FN0_READ_REG(addr + 2); + + if (r5.data != 0x0c) + dbg5("not a sdio card\n"); + else + dbg5(" a sdio card\n"); + + break; + case CISTPL_FUNCE: + /* Type of extended data, should be 1 */ + SDIO_FN0_READ_REG(addr + 2); + if (r5.data == 0x01) + dbg5("1 type extended tuple\n"); + + /* FUNCTION_INFO */ + SDIO_FN0_READ_REG(addr + 3); + sdio_card->fcis[func].func_info = r5.data; + + /* STD_IO_REV */ + SDIO_FN0_READ_REG(addr + 4); + sdio_card->fcis[func].std_io_rev = r5.data; + + /* card psn */ + SDIO_FN0_READ_REG(addr + 5); + tmp = r5.data; + SDIO_FN0_READ_REG(addr + 6); + tmp |= r5.data << 8; + SDIO_FN0_READ_REG(addr + 7); + tmp |= r5.data << 16; + SDIO_FN0_READ_REG(addr + 8); + tmp |= r5.data << 24; + sdio_card->fcis[func].card_psn = tmp; + + /* card csa size */ + SDIO_FN0_READ_REG(addr + 9); + tmp = r5.data; + SDIO_FN0_READ_REG(addr + 10); + tmp |= r5.data << 8; + SDIO_FN0_READ_REG(addr + 11); + tmp |= r5.data << 16; + SDIO_FN0_READ_REG(addr + 12); + tmp |= r5.data << 24; + sdio_card->fcis[func].csa_size = tmp; + + /* csa property */ + SDIO_FN0_READ_REG(addr + 13); + sdio_card->fcis[func].csa_property = r5.data; + + /* max_blk_size */ + SDIO_FN0_READ_REG(addr + 14); + tmp16 = r5.data; + SDIO_FN0_READ_REG(addr + 15); + tmp16 |= r5.data << 8; + sdio_card->fcis[func].max_blk_size = tmp16; + + /* ocr */ + SDIO_FN0_READ_REG(addr + 16); + tmp = r5.data; + SDIO_FN0_READ_REG(addr + 17); + tmp |= r5.data << 8; + SDIO_FN0_READ_REG(addr + 18); + tmp |= r5.data << 16; + SDIO_FN0_READ_REG(addr + 19); + tmp |= r5.data << 24; + sdio_card->fcis[func].ocr = tmp; + + /* pwr */ + SDIO_FN0_READ_REG(addr + 20); + sdio_card->fcis[func].op_min_pwr = r5.data; + + SDIO_FN0_READ_REG(addr + 21); + sdio_card->fcis[func].op_avg_pwr = r5.data; + + SDIO_FN0_READ_REG(addr + 22); + sdio_card->fcis[func].op_max_pwr = r5.data; + + SDIO_FN0_READ_REG(addr + 23); + sdio_card->fcis[func].sb_min_pwr = r5.data; + + SDIO_FN0_READ_REG(addr + 24); + sdio_card->fcis[func].sb_avg_pwr = r5.data; + + SDIO_FN0_READ_REG(addr + 25); + sdio_card->fcis[func].sb_max_pwr = r5.data; + + SDIO_FN0_READ_REG(addr + 26); + tmp16 = r5.data; + SDIO_FN0_READ_REG(addr + 27); + tmp16 |= r5.data << 8; + sdio_card->fcis[func].min_bw = tmp16; + + SDIO_FN0_READ_REG(addr + 28); + tmp16 = r5.data; + SDIO_FN0_READ_REG(addr + 29); + tmp16 |= r5.data << 8; + sdio_card->fcis[func].opt_bw = tmp16; + + // SDIO1.0 is 28, and 1.1 is 36 + if (sdio_card->cccr.sdiox == 0) + break; + SDIO_FN0_READ_REG(addr + 30); + tmp16 = r5.data; + SDIO_FN0_READ_REG(addr + 31); + tmp16 |= r5.data << 8; + sdio_card->fcis[func].enable_timeout_val= tmp16; + break; + case CISTPL_SDIO_STD: + dbg5("sdio std\n"); + break; + case CISTPL_SDIO_EXT: + dbg5("sdio std ext\n"); + break; + default : + dbg5("not supported cis\n"); + } + addr = next_addr; + } +finish: + dbg5("fcis %d\nfunction_info:0x%x std_io_rev:0x%x card_psn:0x%x\n" + "csa_size:0x%x csa_property:0x%x max_blk_size:0x%x\n" + "ocr:0x%x op_min_pwr:0x%x op_avg_pwr:0x%x op_max_pwr:0x%x" + "sb_min_pwr:0x%x sb_avg_pwr:0x%x sb_max_pwr:0x%x" + "min_bw:0x%x opt_bw:0x%x time out:%x\n",func, + sdio_card->fcis[func].func_info, sdio_card->fcis[func].std_io_rev, sdio_card->fcis[func].card_psn, + sdio_card->fcis[func].csa_size, sdio_card->fcis[func].csa_property, sdio_card->fcis[func].max_blk_size, + sdio_card->fcis[func].ocr, sdio_card->fcis[func].op_min_pwr, sdio_card->fcis[func].op_avg_pwr, sdio_card->fcis[func].op_max_pwr, + sdio_card->fcis[func].sb_min_pwr, sdio_card->fcis[func].sb_avg_pwr, sdio_card->fcis[func].sb_max_pwr, + sdio_card->fcis[func].min_bw, sdio_card->fcis[func].opt_bw, sdio_card->fcis[func].enable_timeout_val); + return 0; +} + +static int get_sdio_ccis_info(struct mss_card *card) +{ + struct mss_host *host= card->slot->host; + struct sdio_card *sdio_card = card->prot_card; + struct mss_cmd *cmd = &sdio_card->cmd; + struct mss_ll_request *llreq = &sdio_card->llreq; + int ret, arg, tuple_body_len, tuple_type; + struct sdio_response_r5 r5; + u32 addr, next_addr; + u16 tmp16; + + dbg5("get_sdio_ccis_info"); + addr = sdio_card->cccr.pccis; + while (1) { + SDIO_FN0_READ_REG(addr); + tuple_type = r5.data; + + SDIO_FN0_READ_REG(addr + 1); + tuple_body_len = r5.data; + next_addr = addr + 2 + r5.data; + + switch (tuple_type) { + case CISTPL_NULL: + case CISTPL_END: + dbg5("cistpl null/end\n"); + goto finish; + case CISTPL_CHECKSUM: + dbg5("cistpl checksum\n"); + break; + case CISTPL_VERS_1: + dbg5("cistpl vers level 1\n"); + break; + case CISTPL_ALTSTR: + dbg5("cistpl altstr\n"); + break; + case CISTPL_MANFID: + dbg5("cistpl manfid\n"); + SDIO_FN0_READ_REG(addr + 2); + tmp16 = r5.data; + SDIO_FN0_READ_REG(addr + 3); + tmp16 |= r5.data << 8; + sdio_card->ccis.manufacturer = tmp16; + + SDIO_FN0_READ_REG(addr + 4); + tmp16 = r5.data; + SDIO_FN0_READ_REG(addr + 5); + tmp16 |= r5.data << 8; + sdio_card->ccis.card_id = tmp16; + + break; + case CISTPL_FUNCID: + dbg5("cistpl funcid\n"); + SDIO_FN0_READ_REG(addr + 2); + if (r5.data != 0x0c) + dbg5("not a sdio card\n"); + else + dbg5(" a sdio card\n"); + + break; + case CISTPL_FUNCE: + dbg5("cistpl funce\n"); + SDIO_FN0_READ_REG(addr + 2); + if (r5.data == 0x00) + dbg5("0 type extended tuple\n"); + + SDIO_FN0_READ_REG(addr + 3); + tmp16 = r5.data; + SDIO_FN0_READ_REG(addr + 4); + tmp16 = r5.data << 8; + sdio_card->ccis.fn0_block_size = tmp16; + + SDIO_FN0_READ_REG(addr + 5); + sdio_card->ccis.max_tran_speed = r5.data; + //slot->tran_speed = card->ccis.max_tran_speed; + break; + case CISTPL_SDIO_STD: + dbg5("sdio std\n"); + break; + case CISTPL_SDIO_EXT: + dbg5("sdio std ext\n"); + break; + default: + dbg5("not supported cis\n"); + } + addr = next_addr; + } +finish: + dbg5("ccis:\nmanf:0x%x card_id:0x%x block_size:0x%x\nmax_tran_speed:0x%x\n",sdio_card->ccis.manufacturer, sdio_card->ccis.card_id, sdio_card->ccis.fn0_block_size, sdio_card->ccis.max_tran_speed); + return 0; +} + +/***************************************************************************** + * + * protocol entry functions + * + ****************************************************************************/ + +static int sdio_recognize_card(struct mss_card *card) +{ + struct mss_host *host = card->slot->host; + struct sdio_card *sdio_card = card->prot_card; + struct mss_cmd *cmd = &sdio_card->cmd; + struct mss_ll_request *llreq = &sdio_card->llreq; + struct mss_ios ios; + struct sdio_response_r4 r4; + int ret; + + card->card_type = MSS_UNKNOWN_CARD; + card->state = CARD_STATE_INIT; + card->bus_width = MSS_BUSWIDTH_1BIT; + + memcpy(&ios, &host->ios, sizeof(struct mss_ios)); + ios.clock = host->f_min; + ios.bus_width = MSS_BUSWIDTH_1BIT; + host->ops->set_ios(host, &ios); + + /* check if a sdio card, need not send CMD0 to reset for SDIO card */ + ret = mss_send_simple_ll_req(host, llreq, cmd, IO_SEND_OP_COND, + 0, MSS_RESPONSE_R4, 0); + if (ret) + return ret; + ret = sdio_unpack_r4(cmd, &r4, sdio_card); + if (ret) + return ret; + sdio_card->func_num = r4.func_num; + sdio_card->mem_present = r4.mem_present; + if (!r4.func_num) + return MSS_ERROR_NONE; + /* maybe COMBO_CARD. but we can return SDIO_CARD first, + * in sdio_card_init, we will judge further. + */ + if(r4.ocr & host->vdd) { + card->card_type = MSS_SDIO_CARD; + } else { + printk(KERN_WARNING "uncompatible card\n"); + card->card_type = MSS_UNCOMPATIBLE_CARD; + } + + return MSS_ERROR_NONE; +} + +static int sdio_card_init(struct mss_card *card) +{ + struct mss_host *host = card->slot->host; + struct sdio_card *sdio_card = card->prot_card; + struct mss_cmd *cmd = &sdio_card->cmd; + struct mss_ll_request *llreq = &sdio_card->llreq; + struct sdio_response_r1 r1; + struct sdio_response_r4 r4; + struct sdio_response_r6 r6; + struct mss_ios ios; + int ret, tmp, i; + u8 funcs; + + dbg5("card = %08X\n", (u32)card); + card->state = CARD_STATE_INIT; + card->bus_width = MSS_BUSWIDTH_1BIT; + + memcpy(&ios, &host->ios, sizeof(struct mss_ios)); + ios.clock = host->f_min; + ios.bus_width = MSS_BUSWIDTH_1BIT; + host->ops->set_ios(host, &ios); + + ret = mss_send_simple_ll_req(host, llreq, cmd, IO_SEND_OP_COND, + host->vdd, MSS_RESPONSE_R4, 0); + if (ret) + return ret; + ret = sdio_unpack_r4(cmd, &r4, sdio_card); + if (ret) + return ret; + + while (!r4.ready) { + //mdelay(20); + msleep(15); + ret = mss_send_simple_ll_req(host, llreq, cmd, IO_SEND_OP_COND, + host->vdd, MSS_RESPONSE_R4, 0); + if (ret) + return ret; + ret = sdio_unpack_r4(cmd, &r4, sdio_card); + if (ret) + return ret; + } + + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SET_RELATIVE_ADDR, + 0, MSS_RESPONSE_R6, 0); + if (ret) + return ret; + ret = sdio_unpack_r6(cmd, &r6, sdio_card); + if (ret) + return ret; + sdio_card->state = CARD_STATE_STBY; + sdio_card->rca = r6.rca; + + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SELECT_CARD, + (sdio_card->rca) << 16, MSS_RESPONSE_R1B, 0); + if (ret) + return ret; + ret = sdio_unpack_r1(cmd, &r1, sdio_card); + if (ret) + return ret; + + /** CARD_STATE_CMD */ + //slot->state = CARD_STATE_CMD; + //send CMD53 to let DATA BUS FREE, since bus_suspend not supported, need not to do this + //arg = sdio_make_cmd53_arg(SDIO_READ, 0, 0, 0, 0, 1); + //mss_simple_cmd( dev, IO_RW_EXTENDED, arg, RESPONSE_R5); + + + /** CARD_STATE_TRAN */ + sdio_card->state = CARD_STATE_CMD; + + + ret = get_sdio_cccr_info(card); + if (ret) + return ret; + funcs = sdio_card->func_num; + for(i = 1; i <= funcs; i++) { + ret = get_sdio_fbr_info(card, i); + if (ret) + return ret; + } + + ret = get_sdio_ccis_info(card); + if (ret) + return ret; + for(i = 1; i <= funcs; i++) { + ret = get_sdio_fcis_info(card, i); + if (ret) + return ret; + } + if(host->bus_width == MSS_BUSWIDTH_4BIT + && (!sdio_card->cccr.lsc || sdio_card->cccr.ls4b)) { + host->ios.bus_width = MSS_BUSWIDTH_4BIT; + sdio_set_bus_width(card, 2); + } + + /* enable function */ + tmp = 0; + for(i = 1; i <= funcs; i++) { + tmp |= (1 << i); + } + ret = sdio_io_enable(card, tmp); + if (ret) + return ret; + + /* enable interrupt */ + tmp = 1; + for(i = 1; i <= funcs; i++) { + tmp |= (1 << i); + } + ret = sdio_interrupt_enable(card, tmp); + if (ret) + return ret; + + /* enable card capabilites */ + for (i=1; i <= funcs; i++) { + sdio_csa_enable(card, i); + } + + mss_set_sdio_int(card->slot->host, 1); + + return MSS_ERROR_NONE; +} + +static int sdio_read_write_entry(struct mss_card *card, int action, struct mss_rw_arg *arg, struct mss_rw_result *result) +{ + struct mss_host *host = card->slot->host; + struct sdio_card *sdio_card = card->prot_card; + struct mss_cmd *cmd = &sdio_card->cmd; + struct mss_data *data = &sdio_card->data; + struct mss_ll_request *llreq = &sdio_card->llreq; + struct sdio_response_r5 r5; + struct sdio_response_r1 r1; + int ret; + u32 addr, blkmode, func, rw, rw_count, opcode, clock, cmdarg; + int retries = 4; + + if (sdio_card->state == CARD_STATE_STBY) { + ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SELECT_CARD, + sdio_card->rca << 16, MSS_RESPONSE_R1B, 0); + if (ret) + return ret; + ret = sdio_unpack_r1(cmd, &r1, sdio_card); + if (ret) + return ret; + } + + mss_set_clock(host, sdio_tran_speed(sdio_card->ccis.max_tran_speed)); + func = arg->func; + if (func > sdio_card->func_num) + return MSS_ERROR_WRONG_ARG; + + if (arg->block_len == 0) { + blkmode = 0; + } + else { + if (!sdio_card->cccr.smb) + return MSS_ERROR_WRONG_ARG; + dbg5("blkzs:%d, %d\n", arg->block_len, sdio_card->fbr[func].fn_blksz); + if (arg->block_len != sdio_card->fbr[func].fn_blksz) { + ret = sdio_set_block_size(card, arg->block_len, func); + if (ret) + return ret; + } + blkmode = 1; + } + + rw = (action == MSS_READ_MEM) ? 0 : 1; + addr = arg->block; + opcode = (arg->opcode) ? 1 : 0; + rw_count = arg->nob; + + memset(llreq, 0x0, sizeof(struct mss_ll_request)); + memset(cmd, 0x0, sizeof(struct mss_cmd)); + memset(data, 0x0, sizeof(struct mss_data)); + +read_write_entry: + /* deal with request */ + /* if only one byte, then use CMD52 to read*/ + if (!blkmode && rw_count == 1) { + u8 val = (rw) ? arg->val : 0; + dbg5("use CMD52 to transfer data. rw direction: %d", rw); + cmdarg = sdio_make_cmd52_arg(rw, func, opcode, addr, val); + + dbg5("cmdarg :0x%x\n", cmdarg); + ret = mss_send_simple_ll_req(host, llreq, cmd, IO_RW_DIRECT, + cmdarg, MSS_RESPONSE_R5, + MSS_CMD_SDIO_EN); + if (!ret) + ret = sdio_unpack_r5(cmd, &r5, sdio_card); + if (!ret) + result->bytes_xfered = r5.data; + else if (ret && --retries) { + clock = host->ios.clock; + clock = clock >> 1; + if (clock < SDIO_CARD_CLOCK_SLOW && retries == 1) { + clock = SDIO_CARD_CLOCK_SLOW; + mss_set_clock(host, clock); + goto read_write_entry; + } + return ret; + } + dbg5("r5.data:0x%x\n",r5.data); + } + else { + cmdarg= sdio_make_cmd53_arg(rw, func, blkmode, opcode, addr, + rw_count); + MSS_INIT_CMD(cmd, IO_RW_EXTENDED, cmdarg, MSS_CMD_SDIO_EN, + MSS_RESPONSE_R5); + MSS_INIT_DATA(data, rw_count, arg->block_len, + ((rw) ? MSS_DATA_WRITE : MSS_DATA_READ), + arg->sg_len, arg->sg, 0); + llreq->cmd = cmd; + llreq->data = data; + + ret = mss_send_ll_req(host, llreq); + if (!ret) + ret = sdio_unpack_r5(cmd, &r5, sdio_card); + if (ret) { + if (--retries) { + clock = host->ios.clock; + clock = clock >> 1; + if (clock < SDIO_CARD_CLOCK_SLOW + && retries == 1) + clock = SDIO_CARD_CLOCK_SLOW; + mss_set_clock(host, clock); + goto read_write_entry; + } + return ret; + } + + } + return MSS_ERROR_NONE; +} + +/***************************************************************************** + * + * protocol driver interface functions + * + ****************************************************************************/ + +static int sdio_prot_entry(struct mss_card *card, unsigned int action, void *arg, void *result) +{ + int ret; + + dbg5("action = %d\n", action); + if (action != MSS_RECOGNIZE_CARD && card->card_type != MSS_SDIO_CARD) + return MSS_ERROR_WRONG_CARD_TYPE; + switch (action) { + case MSS_RECOGNIZE_CARD: + ret = sdio_recognize_card(card); + break; + case MSS_INIT_CARD: + ret = sdio_card_init(card); + break; + case MSS_READ_MEM: + case MSS_WRITE_MEM: + if (!arg || !result) + return -EINVAL; + ret = sdio_read_write_entry(card, action, arg, result); + break; + case MSS_QUERY_CARD: + ret = MSS_ERROR_NONE; + break; + default: + ret = MSS_ERROR_ACTION_UNSUPPORTED; + break; + } + + return ret; +} + +static int sdio_prot_attach_card(struct mss_card *card) +{ + struct sdio_card *sdio_card; + +#define ALIGN32(x) (((x) + 31) & (~31)) + sdio_card = kzalloc(ALIGN32(sizeof(struct sdio_card)), GFP_KERNEL); + card->prot_card = sdio_card; + if (sdio_card) { + return 0; + } + return -ENOMEM; +} + +static void sdio_prot_detach_card(struct mss_card *card) +{ + kfree(card->prot_card); +} + +static int sdio_prot_get_errno(struct mss_card *card) +{ + struct sdio_card *sdio_card = card->prot_card; + + return sdio_card->errno; +} + +static struct mss_prot_driver sdio_protocol = { + .name = SDIO_PROTOCOL, + .prot_entry = sdio_prot_entry, + .attach_card = sdio_prot_attach_card, + .detach_card = sdio_prot_detach_card, + .get_errno = sdio_prot_get_errno, +}; + +/***************************************************************************** + * + * module init and exit functions + * + ****************************************************************************/ +static int sdio_protocol_init(void) +{ + register_mss_prot_driver(&sdio_protocol); + return 0; +} + +static void sdio_protocol_exit(void) +{ + unregister_mss_prot_driver(&sdio_protocol); +} + + +module_init(sdio_protocol_init); +module_exit(sdio_protocol_exit); + +MODULE_AUTHOR("Bridge Wu"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SDIO protocol driver"); --- linux-2.6.24.orig/drivers/mmc/mss/Makefile +++ linux-2.6.24/drivers/mmc/mss/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for the kernel MSS(mmc/sd/sdio) device drivers. +# + +# Core +obj-$(CONFIG_MSS) += mss_core.o mmc_protocol.o sdio_protocol.o sd_protocol.o + +# Media drivers +obj-$(CONFIG_MSS_BLOCK) += mss_block.o + +# Host drivers +obj-$(CONFIG_MSS_SDHCI) += mss_sdhci.o + --- linux-2.6.24.orig/drivers/mmc/mss/mss_sdhci.c +++ linux-2.6.24/drivers/mmc/mss/mss_sdhci.c @@ -0,0 +1,1778 @@ +/* + * mss_sdhci.c - SD Host Controller interface driver + * + * Copyright (C) 2007 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 only + * for now as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * derived from linux/drivers/mmc/sdhci.c + * Copyright (c) 2005 Pierre Ossman + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "mss_sdhci.h" + + +#define DRIVER_NAME "sdhci" +#define BUGMAIL " " + +#define DBG(f, x...) \ + pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x) + +static unsigned int debug_nodma = 0; +static unsigned int debug_forcedma = 0; +static unsigned int debug_quirks = 0; + +#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) +#define SDHCI_QUIRK_FORCE_DMA (1<<1) +/* Controller doesn't like some resets when there is no card inserted. */ +#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) +#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) + +static const struct pci_device_id pci_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_RICOH, + .device = PCI_DEVICE_ID_RICOH_R5C822, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = PCI_ANY_ID, + .driver_data = SDHCI_QUIRK_CLOCK_BEFORE_RESET | + SDHCI_QUIRK_FORCE_DMA, + }, + + { + .vendor = PCI_VENDOR_ID_RICOH, + .device = PCI_DEVICE_ID_RICOH_R5C822, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SDHCI_QUIRK_FORCE_DMA | + SDHCI_QUIRK_NO_CARD_NO_RESET, + }, + + { + .vendor = PCI_VENDOR_ID_TI, + .device = PCI_DEVICE_ID_TI_XX21_XX11_SD, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SDHCI_QUIRK_FORCE_DMA, + }, + + { + .vendor = PCI_VENDOR_ID_ENE, + .device = PCI_DEVICE_ID_ENE_CB712_SD, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE, + }, + + { /* Generic SD host controller */ + PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) + }, + + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(pci, pci_ids); + +static void sdhci_prepare_data(struct sdhci_host *, struct mss_data *); +static void sdhci_finish_data(struct sdhci_host *); + +static void sdhci_send_command(struct sdhci_host *, struct mss_cmd *); +static void sdhci_finish_command(struct sdhci_host *); + +struct proc_dir_entry *dir_sdhci = NULL; + +static inline struct sdhci_host* slot_to_host(struct mss_slot *slot) +{ + return (struct sdhci_host*)(slot->private); +} + +static inline struct sdhci_host* mss_to_host(struct mss_host *mss) +{ + return (struct sdhci_host*)(mss->private); +} + +static void sdhci_dumpregs(struct sdhci_host *host) +{ + printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n"); + + printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", + readl(host->ioaddr + SDHCI_DMA_ADDRESS), + readw(host->ioaddr + SDHCI_HOST_VERSION)); + printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", + readw(host->ioaddr + SDHCI_BLOCK_SIZE), + readw(host->ioaddr + SDHCI_BLOCK_COUNT)); + printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", + readl(host->ioaddr + SDHCI_ARGUMENT), + readw(host->ioaddr + SDHCI_TRANSFER_MODE)); + printk(KERN_DEBUG DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", + readl(host->ioaddr + SDHCI_PRESENT_STATE), + readb(host->ioaddr + SDHCI_HOST_CONTROL)); + printk(KERN_DEBUG DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", + readb(host->ioaddr + SDHCI_POWER_CONTROL), + readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL)); + printk(KERN_DEBUG DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", + readb(host->ioaddr + SDHCI_WALK_UP_CONTROL), + readw(host->ioaddr + SDHCI_CLOCK_CONTROL)); + printk(KERN_DEBUG DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", + readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL), + readl(host->ioaddr + SDHCI_INT_STATUS)); + printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", + readl(host->ioaddr + SDHCI_INT_ENABLE), + readl(host->ioaddr + SDHCI_SIGNAL_ENABLE)); + printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", + readw(host->ioaddr + SDHCI_ACMD12_ERR), + readw(host->ioaddr + SDHCI_SLOT_INT_STATUS)); + printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x | Max curr: 0x%08x\n", + readl(host->ioaddr + SDHCI_CAPABILITIES), + readl(host->ioaddr + SDHCI_MAX_CURRENT)); + + printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n"); +} + +#ifdef CONFIG_PROC_FS +static int sdhci_read_proc(char* page, char** start, off_t off, int count, int* eof, void* data) { +int len = 0; +struct sdhci_host *host=(struct sdhci_host *)data; + + if (host == NULL) goto done; + + len += sprintf(page+len, DRIVER_NAME ": ============== REGISTER DUMP ==============\n"); + + len += sprintf(page+len, DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", + readl(host->ioaddr + SDHCI_DMA_ADDRESS), + readw(host->ioaddr + SDHCI_HOST_VERSION)); + len += sprintf(page+len, DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", + readw(host->ioaddr + SDHCI_BLOCK_SIZE), + readw(host->ioaddr + SDHCI_BLOCK_COUNT)); + len += sprintf(page+len, DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", + readl(host->ioaddr + SDHCI_ARGUMENT), + readw(host->ioaddr + SDHCI_TRANSFER_MODE)); + len += sprintf(page+len, DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", + readl(host->ioaddr + SDHCI_PRESENT_STATE), + readb(host->ioaddr + SDHCI_HOST_CONTROL)); + len += sprintf(page+len, DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", + readb(host->ioaddr + SDHCI_POWER_CONTROL), + readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL)); + len += sprintf(page+len, DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", + readb(host->ioaddr + SDHCI_WALK_UP_CONTROL), + readw(host->ioaddr + SDHCI_CLOCK_CONTROL)); + len += sprintf(page+len, DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", + readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL), + readl(host->ioaddr + SDHCI_INT_STATUS)); + len += sprintf(page+len, DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", + readl(host->ioaddr + SDHCI_INT_ENABLE), + readl(host->ioaddr + SDHCI_SIGNAL_ENABLE)); + len += sprintf(page+len, DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", + readw(host->ioaddr + SDHCI_ACMD12_ERR), + readw(host->ioaddr + SDHCI_SLOT_INT_STATUS)); + len += sprintf(page+len, DRIVER_NAME ": Caps: 0x%08x | Max curr: 0x%08x\n", + readl(host->ioaddr + SDHCI_CAPABILITIES), + readl(host->ioaddr + SDHCI_MAX_CURRENT)); + + len += sprintf(page+len, DRIVER_NAME ": ===========================================\n"); + +done: + *eof = 1; + return len; +} +#endif + +/*****************************************************************************\ + * * + * Low level functions * + * * +\*****************************************************************************/ + +static void sdhci_reset(struct sdhci_host *host, u8 mask) +{ + unsigned long timeout; + + if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { + if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & + SDHCI_CARD_PRESENT)) + return; + } + + writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET); + + if (mask & SDHCI_RESET_ALL) + host->clock = 0; + + /* Wait max 100 ms */ + timeout = 100; + + /* hw clears the bit when it's done */ + while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) { + if (timeout == 0) { + printk(KERN_ERR "mmchost: Reset 0x%x never completed.\n", (int)mask); + sdhci_dumpregs(host); + return; + } + timeout--; + mdelay(1); + } +} + +static void sdhci_init(struct sdhci_host *host) +{ + u32 intmask; + + sdhci_reset(host, SDHCI_RESET_ALL); + + intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | + SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | + SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | + SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT | + SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | + SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE; + + writel(intmask, host->ioaddr + SDHCI_INT_ENABLE); + writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE); +} + +static void sdhci_activate_led(struct sdhci_host *host) +{ + u8 ctrl; + + ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); + ctrl |= SDHCI_CTRL_LED; + writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); +} + +static void sdhci_deactivate_led(struct sdhci_host *host) +{ + u8 ctrl; + + ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); + ctrl &= ~SDHCI_CTRL_LED; + writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); +} + +/*****************************************************************************\ + * * + * Core functions * + * * +\*****************************************************************************/ + +static inline char* sdhci_sg_to_buffer(struct sdhci_host* host) +{ + return page_address(host->cur_sg->page) + host->cur_sg->offset; +} + +static inline int sdhci_next_sg(struct sdhci_host* host) +{ + /* Skip to next SG entry. */ + host->cur_sg++; + host->num_sg--; + + /* Any entries left? */ + if (host->num_sg > 0) { + host->offset = 0; + host->remain = host->cur_sg->length; + } + + return host->num_sg; +} + +static void sdhci_read_block_pio(struct sdhci_host *host) +{ + int blksize, chunk_remain; + u32 data; + char *buffer; + int size; + + + blksize = host->data->blksz; + chunk_remain = 0; + data = 0; + + buffer = sdhci_sg_to_buffer(host) + host->offset; + + while (blksize) { + if (chunk_remain == 0) { + data = readl(host->ioaddr + SDHCI_BUFFER); + chunk_remain = min(blksize, 4); + } + + size = min(host->size, host->remain); + size = min(size, chunk_remain); + + chunk_remain -= size; + blksize -= size; + host->offset += size; + host->remain -= size; + host->size -= size; + while (size) { + *buffer = data & 0xFF; + buffer++; + data >>= 8; + size--; + } + + if (host->remain == 0) { + if (sdhci_next_sg(host) == 0) { + BUG_ON(blksize != 0); + return; + } + buffer = sdhci_sg_to_buffer(host); + } + } +} + +static void sdhci_write_block_pio(struct sdhci_host *host) +{ + int blksize, chunk_remain; + u32 data; + char *buffer; + int bytes, size; + + + blksize = host->data->blksz; + chunk_remain = 4; + data = 0; + + bytes = 0; + buffer = sdhci_sg_to_buffer(host) + host->offset; + + while (blksize) { + size = min(host->size, host->remain); + size = min(size, chunk_remain); + + chunk_remain -= size; + blksize -= size; + host->offset += size; + host->remain -= size; + host->size -= size; + while (size) { + data >>= 8; + data |= (u32)*buffer << 24; + buffer++; + size--; + } + + if (chunk_remain == 0) { + writel(data, host->ioaddr + SDHCI_BUFFER); + chunk_remain = min(blksize, 4); + } + + if (host->remain == 0) { + if (sdhci_next_sg(host) == 0) { + BUG_ON(blksize != 0); + return; + } + buffer = sdhci_sg_to_buffer(host); + } + } +} + +static void sdhci_transfer_pio(struct sdhci_host *host) +{ + u32 mask; + + BUG_ON(!host->data); + + if (host->size == 0) + return; + + if (host->data->flags & MSS_DATA_READ) + mask = SDHCI_DATA_AVAILABLE; + else + mask = SDHCI_SPACE_AVAILABLE; + + while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) { + if (host->data->flags & MSS_DATA_READ) + sdhci_read_block_pio(host); + else + sdhci_write_block_pio(host); + + if (host->size == 0) + break; + + BUG_ON(host->num_sg == 0); + } + + DBG("PIO transfer complete.\n"); +} + + +static void sdhci_prepare_data(struct sdhci_host *host, struct mss_data *data) +{ + u8 count; + unsigned target_timeout, current_timeout; + + WARN_ON(host->data); + + if (data == NULL) + return; + + DBG("blksz %04x blks %04x flags %08x\n", + data->blksz, data->blocks, data->flags); + DBG("tsac %d ms\n", data->timeout_ns / 1000000); + + /* Sanity checks */ + BUG_ON(data->blksz * data->blocks > 524288); + //BUG_ON(data->blksz > host->mmc->max_blk_size); + BUG_ON(data->blocks > 65535); + + /* timeout in us */ + target_timeout = data->timeout_ns / 1000; + + /* + * Figure out needed cycles. + * We do this in steps in order to fit inside a 32 bit int. + * The first step is the minimum timeout, which will have a + * minimum resolution of 6 bits: + * (1) 2^13*1000 > 2^22, + * (2) host->timeout_clk < 2^16 + * => + * (1) / (2) > 2^6 + */ + count = 0; + current_timeout = (1 << 13) * 1000 / host->timeout_clk; + while (current_timeout < target_timeout) { + count++; + current_timeout <<= 1; + if (count >= 0xF) + break; + } + + if (count >= 0xF) { + printk(KERN_WARNING "mmchost: Too large timeout requested!\n"); + count = 0xE; + } + + if (count == 0) count = 0x8; /* add by feng for SD memory timeout issue */ + writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL); + + if (host->flags & SDHCI_USE_DMA) { + int count; + + count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len, + (data->flags & MSS_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE); + BUG_ON(count != 1); + + writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS); + } else { + host->size = data->blksz * data->blocks; + + host->cur_sg = data->sg; + host->num_sg = data->sg_len; + + host->offset = 0; + host->remain = host->cur_sg->length; + } + + + /* We do not handle DMA boundaries, so set it to max (512 KiB) */ + writew(SDHCI_MAKE_BLKSZ(7, data->blksz), + host->ioaddr + SDHCI_BLOCK_SIZE); + writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT); +} + +static void sdhci_set_transfer_mode(struct sdhci_host *host, + struct mss_data *data) +{ + u16 mode; + + WARN_ON(host->data); + + if (data == NULL) + return; + + mode = SDHCI_TRNS_BLK_CNT_EN; + if (data->blocks > 1) + mode |= SDHCI_TRNS_MULTI; + if (data->flags & MSS_DATA_READ) + mode |= SDHCI_TRNS_READ; + if (host->flags & SDHCI_USE_DMA) + mode |= SDHCI_TRNS_DMA; + + writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE); +} + +static void sdhci_finish_data(struct sdhci_host *host) +{ + struct mss_data *data; + struct mss_cmd *cmd; + u16 blocks; + + BUG_ON(!host->data); + BUG_ON(!host->mrq->cmd); + + data = host->data; + cmd = host->mrq->cmd; + host->data = NULL; + + if (host->flags & SDHCI_USE_DMA) { + pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len, + (data->flags & MSS_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE); + } + + /* + * Controller doesn't count down when in single block mode. + */ + if ((data->blocks == 1) && (cmd->error == MSS_ERROR_NONE)) + blocks = 0; + else + blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT); + data->bytes_xfered = data->blksz * (data->blocks - blocks); + + if ((cmd->error == MSS_ERROR_NONE) && blocks) { + printk(KERN_ERR "mmchost: Controller signalled completion even " + "though there were blocks left. Please report this " + "to " BUGMAIL ".\n"); + cmd->error = MSS_ERROR_CRC; + } else if (host->size != 0) { + printk(KERN_ERR "mmchost: %d bytes were left untransferred. " + "Please report this to " BUGMAIL ".\n", host->size); + cmd->error = MSS_ERROR_CRC; + } + + DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered); + + tasklet_schedule(&host->finish_tasklet); +} + +static void sdhci_send_command(struct sdhci_host *host, struct mss_cmd *cmd) +{ + unsigned long flags; + u32 mask; + unsigned long timeout; + + WARN_ON(host->cmd); + + DBG("Sending cmd (%x)\n", cmd->opcode); + + /* Wait max 10 ms */ + timeout = 10; + + mask = SDHCI_CMD_INHIBIT; + + if ((cmd->data != NULL) || (cmd->rtype == MSS_RESPONSE_R1B)) + mask |= SDHCI_DATA_INHIBIT; + + while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) { + if (timeout == 0) { + printk(KERN_ERR "mmchost: Controller never released " + "inhibit bit(s).\n"); + sdhci_dumpregs(host); + cmd->error = MSS_ERROR_CRC; + tasklet_schedule(&host->finish_tasklet); + return; + } + timeout--; + mdelay(1); + } + + mod_timer(&host->timer, jiffies + 10 * HZ); + + host->cmd = cmd; + + sdhci_prepare_data(host, cmd->data); + + writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT); + + sdhci_set_transfer_mode(host, cmd->data); + + + switch (cmd->rtype) { + case MSS_RESPONSE_NONE: + flags = SDHCI_CMD_RESP_NONE; + break; + case MSS_RESPONSE_R1: + flags = SDHCI_CMD_RESP_SHORT | SDHCI_CMD_CRC | SDHCI_CMD_INDEX; + break; + case MSS_RESPONSE_R1B: + flags = SDHCI_CMD_RESP_SHORT_BUSY | SDHCI_CMD_CRC | SDHCI_CMD_INDEX; + break; + case MSS_RESPONSE_R2_CID: + case MSS_RESPONSE_R2_CSD: + flags = SDHCI_CMD_RESP_LONG | SDHCI_CMD_CRC; + break; + case MSS_RESPONSE_R3: + flags = SDHCI_CMD_RESP_SHORT; + break; + case MSS_RESPONSE_R6: + flags = SDHCI_CMD_RESP_SHORT | SDHCI_CMD_CRC; + break; + default: + flags = SDHCI_CMD_RESP_SHORT; + } + + if (cmd->data) + flags |= SDHCI_CMD_DATA; + DBG("SEND CMD=%08X, ARG=%08X\n", + SDHCI_MAKE_CMD(cmd->opcode, flags), cmd->arg); + writew(SDHCI_MAKE_CMD(cmd->opcode, flags), + host->ioaddr + SDHCI_COMMAND); +} + +static void sdhci_finish_command(struct sdhci_host *host) +{ + int i; + u32 *rp; + + BUG_ON(host->cmd == NULL); + + if (host->cmd->rtype != MSS_RESPONSE_NONE) { + switch (host->cmd->rtype) { + case MSS_RESPONSE_R2_CID: + case MSS_RESPONSE_R2_CSD: + case MSS_RESPONSE_R3: + host->cmd->response[0] = 0x3f; + break; + case MSS_RESPONSE_R6: + case MSS_RESPONSE_R1: + case MSS_RESPONSE_R1B: + default: + host->cmd->response[0] = host->cmd->opcode; + } + rp = (u32 *)&host->cmd->response[1]; + if ((host->cmd->rtype == MSS_RESPONSE_R2_CID)|| + (host->cmd->rtype == MSS_RESPONSE_R2_CSD)) { + /* CRC is stripped so we need to do some shifting. */ + for (i = 0; i < 4; i++, rp++) { + *rp = readl(host->ioaddr + + SDHCI_RESPONSE + (3-i)*4) << 8; + if (i != 3) + *rp |= readb(host->ioaddr + + SDHCI_RESPONSE + (3-i)*4-1); + //*rp = BYTE_REVERSE(*rp); + *rp = ___arch__swab32(*rp); + } + } else { + *rp = readl(host->ioaddr + SDHCI_RESPONSE); + //*rp = BYTE_REVERSE(*rp); + *rp = ___arch__swab32(*rp); + } + } + + host->cmd->error = MSS_ERROR_NONE; + + DBG("Ending cmd (%x)\n", host->cmd->opcode); + + if (host->cmd->data) + host->data = host->cmd->data; + else + tasklet_schedule(&host->finish_tasklet); + + host->cmd = NULL; +} + +static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) +{ + int div; + //u8 ctrl; + u16 clk; + unsigned long timeout; + + if (clock == host->clock) + return; + + writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); + + + /* + ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); + if (clock > 25000000) + ctrl |= SDHCI_CTRL_HISPD; + else + ctrl &= ~SDHCI_CTRL_HISPD; + writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); + */ + + if (clock == 0) + goto out; + + for (div = 1;div < 256;div *= 2) { + if ((host->max_clk / div) <= clock) + break; + } + div >>= 1; + + clk = div << SDHCI_DIVIDER_SHIFT; + clk |= SDHCI_CLOCK_INT_EN; + writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); + + /* Wait max 10 ms */ + timeout = 10; + while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL)) + & SDHCI_CLOCK_INT_STABLE)) { + if (timeout == 0) { + printk(KERN_ERR "mmchost: Internal clock never estabilised.\n"); + sdhci_dumpregs(host); + return; + } + timeout--; + mdelay(1); + } + + clk |= SDHCI_CLOCK_CARD_EN; + writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); + +out: + host->clock = clock; +} + +static void sdhci_set_power(struct sdhci_host *host, unsigned short power) +{ + u8 pwr; + int i; + + /* feng: modify ulong to ushort for 2.6.21 porting */ + if (power != (unsigned short)-1) { + for(i = 0; (i < 16)&&!(power&1); i++) power >>= 1; + power = i; + } + DBG("set power to %d\n", power); + + + if (host->power == power) + return; + + if (power == (unsigned short)-1) { + writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); + goto out; + } + + /* + * Spec says that we should clear the power reg before setting + * a new value. Some controllers don't seem to like this though. + */ + if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) + writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); + + pwr = SDHCI_POWER_ON; + + /* + switch (power) { + case MSS_VDD_170: + case MSS_VDD_180: + case MSS_VDD_190: + pwr |= SDHCI_POWER_180; + break; + case MSS_VDD_290: + case MSS_VDD_300: + case MSS_VDD_310: + pwr |= SDHCI_POWER_300; + break; + case MSS_VDD_320: + case MSS_VDD_330: + case MSS_VDD_340: + pwr |= SDHCI_POWER_330; + break; + default: + // mask by feng, temply masked it for debug + //BUG(); + } + */ + + /* added for temp use */ + pwr |= SDHCI_POWER_330; + + writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL); + +out: + host->power = power; + +} + +/*****************************************************************************\ + * * + * MMC callbacks * + * * +\*****************************************************************************/ + +static void sdhci_request(struct mss_host *mmc, struct mss_ll_request *mrq) +{ + struct sdhci_host *host; + unsigned long flags; + + host = mss_to_host(mmc); + if (mmc->active_card != NULL) + host->card = mmc->active_card; + + spin_lock_irqsave(&host->lock, flags); + + WARN_ON(host->mrq != NULL); + + sdhci_activate_led(host); + + host->mrq = mrq; + + if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { + host->mrq->cmd->error = MSS_ERROR_TIMEOUT; + tasklet_schedule(&host->finish_tasklet); + } else + sdhci_send_command(host, mrq->cmd); + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); +} + +static void sdhci_set_ios(struct mss_host *mmc, struct mss_ios *ios) +{ + struct sdhci_host *host; + unsigned long flags; + u8 ctrl; + u32 intmask; + host = mss_to_host(mmc); + + DBG("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", + ios->clock, ios->bus_mode, ios->power_mode, + ios->chip_select, ios->vdd, ios->bus_width); + + spin_lock_irqsave(&host->lock, flags); + + /* + * Reset the chip on each power off. + * Should clear out any weird states. + */ + if (ios->power_mode == MSS_POWER_OFF) { + writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE); + sdhci_init(host); + } + + sdhci_set_clock(host, ios->clock); + + if (ios->power_mode == MSS_POWER_OFF) + sdhci_set_power(host, -1); + else + sdhci_set_power(host, ios->vdd); + + ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); + if (ios->bus_width == MSS_BUSWIDTH_4BIT) + ctrl |= SDHCI_CTRL_4BITBUS; + else + ctrl &= ~SDHCI_CTRL_4BITBUS; + + /* temply masked by feng + if (ios->timing == MMC_TIMING_SD_HS) + ctrl |= SDHCI_CTRL_HISPD; + else + ctrl &= ~SDHCI_CTRL_HISPD; + */ + + writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); + mmiowb(); + + + if (ios->sdio_int == MSS_SDIO_INT_EN) { + intmask = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE); + intmask |= SDHCI_INT_CARD_INT; + writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE); + + intmask = readl(host->ioaddr + SDHCI_INT_ENABLE); + intmask |= SDHCI_INT_CARD_INT; + writel(intmask, host->ioaddr + SDHCI_INT_ENABLE); + } else { + intmask = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE); + intmask &= ~(SDHCI_INT_CARD_INT); + writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE); + + intmask = readl(host->ioaddr + SDHCI_INT_ENABLE); + intmask &= ~(SDHCI_INT_CARD_INT); + writel(intmask, host->ioaddr + SDHCI_INT_ENABLE); + } + + + memcpy(&host->mmc->ios, ios, sizeof(struct mss_ios)); + spin_unlock_irqrestore(&host->lock, flags); +} + +/* +static int sdhci_slot_is_wp(struct mss_slot *slot) +{ + struct sdhci_host *host; + int present; + + host = slot_to_host(slot); + present = readl(host->ioaddr + SDHCI_PRESENT_STATE); + return !(present & SDHCI_WRITE_PROTECT); +} + +static int sdhci_slot_is_empty(struct mss_slot *slot) +{ + struct sdhci_host *host; + int present; + + host = slot_to_host(slot); + present = readl(host->ioaddr + SDHCI_PRESENT_STATE); + return !(present & SDHCI_CARD_PRESENT); +} + +static int sdhci_mss_slot_is_wp(struct mss_slot *slot) +{ + struct sdhci_host *host; + int result; + unsigned long flags; + + host = slot_to_host(slot); + spin_lock_irqsave(&host->lock, flags); + result = sdhci_slot_is_wp(slot); + spin_unlock_irqrestore(&host->lock, flags); + return result; +} + +static int sdhci_mss_slot_is_empty(struct mss_slot *slot) +{ + struct sdhci_host *host; + int result; + unsigned long flags; + + host = slot_to_host(slot); + spin_lock_irqsave(&host->lock, flags); + result = sdhci_slot_is_empty(slot); + spin_unlock_irqrestore(&host->lock, flags); + return result; +} +*/ + +static u32 sdhci_get_cur_state(struct mss_slot *slot) +{ + struct sdhci_host *host; + u32 state; + unsigned long flags; + + host = slot_to_host(slot); + spin_lock_irqsave(&host->lock, flags); + state = readl(host->ioaddr + SDHCI_PRESENT_STATE); + spin_unlock_irqrestore(&host->lock, flags); + return state; +} + +static int sdhci_mss_slot_is_wp(struct mss_slot *slot) +{ + return !( sdhci_get_cur_state(slot) & SDHCI_WRITE_PROTECT); +} + +static int sdhci_mss_slot_is_empty(struct mss_slot *slot) +{ + return !( sdhci_get_cur_state(slot) & SDHCI_CARD_PRESENT); +} + + +static struct mss_host_ops sdhci_ops = { + .request = sdhci_request, + .set_ios = sdhci_set_ios, + .is_slot_empty = sdhci_mss_slot_is_empty, + .is_slot_wp = sdhci_mss_slot_is_wp, +}; + +/*****************************************************************************\ + * * + * Tasklets * + * * +\*****************************************************************************/ + +static void sdhci_tasklet_card(unsigned long param) +{ + struct sdhci_host *host; + unsigned long flags; + + host = (struct sdhci_host*)param; + + spin_lock_irqsave(&host->lock, flags); + + if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { + if (host->mrq) { + printk(KERN_ERR "mmchost: Card removed during transfer!\n"); + printk(KERN_ERR "mmchost: Resetting controller.\n"); + + sdhci_reset(host, SDHCI_RESET_CMD); + sdhci_reset(host, SDHCI_RESET_DATA); + + host->mrq->cmd->error = MSS_ERROR_CRC; + tasklet_schedule(&host->finish_tasklet); + } + } + + spin_unlock_irqrestore(&host->lock, flags); + + + mss_detect_change(host->mmc, msecs_to_jiffies(500), 0); + //mmc_detect_change(host->mmc, msecs_to_jiffies(500)); + +} + +static void sdhci_tasklet_finish(unsigned long param) +{ + struct sdhci_host *host; + unsigned long flags; + struct mss_ll_request *mrq; + host = (struct sdhci_host*)param; + + spin_lock_irqsave(&host->lock, flags); + + del_timer(&host->timer); + + mrq = host->mrq; + + DBG("Ending request, cmd (%x)\n", mrq->cmd->opcode); + + /* + * The controller needs a reset of internal state machines + * upon error conditions. + */ + + if (mrq->cmd->error != MSS_ERROR_NONE) { + //if ((mrq->cmd->error != MSS_ERROR_NONE) || + // (mrq->data && ((mrq->data->error != MSS_ERROR_NONE) || + // (mrq->data->stop && (mrq->data->stop->error != MSS_ERROR_NONE))))) { + + /* Some controllers need this kick or reset won't work here */ + if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) { + unsigned int clock; + + /* This is to force an update */ + clock = host->clock; + host->clock = 0; + sdhci_set_clock(host, clock); + } + + /* Spec says we should do both at the same time, but Ricoh + controllers do not like that. */ + sdhci_reset(host, SDHCI_RESET_CMD); + sdhci_reset(host, SDHCI_RESET_DATA); + } + + +// printk(KERN_EMERG "%%%%%%%%%%%%%host->cmd = NULL; host->data = NULL %%%%%%%%%%%%%%%%%%%%\n"); + host->cmd = NULL; + host->data = NULL; + + sdhci_deactivate_led(host); + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); + + host->mrq->done(host->mrq); + host->mrq = NULL; +} + +static void sdhci_timeout_timer(unsigned long data) +{ + struct sdhci_host *host; + unsigned long flags; + + host = (struct sdhci_host*)data; + + spin_lock_irqsave(&host->lock, flags); + + + + if (host->data) { + host->mrq->cmd->error = MSS_ERROR_TIMEOUT; + sdhci_finish_data(host); + } else { + if (host->cmd) + host->cmd->error = MSS_ERROR_TIMEOUT; + else + host->mrq->cmd->error = MSS_ERROR_TIMEOUT; + + tasklet_schedule(&host->finish_tasklet); + } + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); +} + +/*****************************************************************************\ + * * + * Interrupt handling * + * * +\*****************************************************************************/ + +static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) +{ + BUG_ON(intmask == 0); + + if (!host->cmd) { + printk(KERN_ERR "mmchost: Got command interrupt even though no " + "command operation was in progress.\n"); + sdhci_dumpregs(host); + return; + } + + if (intmask & SDHCI_INT_RESPONSE) + sdhci_finish_command(host); + else { + if (intmask & SDHCI_INT_TIMEOUT) + host->cmd->error = MSS_ERROR_TIMEOUT; + else if (intmask & SDHCI_INT_CRC) + host->cmd->error = MSS_ERROR_CRC; + else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) + host->cmd->error = MSS_ERROR_CRC; + else + host->cmd->error = MSS_ERROR_CRC; + + tasklet_schedule(&host->finish_tasklet); + } +} + +static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) +{ + BUG_ON(intmask == 0); + + if (!host->data) { + /* + * A data end interrupt is sent together with the response + * for the stop command. + */ + if (intmask & SDHCI_INT_DATA_END) + return; + + printk(KERN_ERR "mmchost: Got data interrupt even though no " + "data operation was in progress.\n"); + sdhci_dumpregs(host); + + return; + } + + if (intmask & SDHCI_INT_DATA_TIMEOUT) + host->mrq->cmd->error = MSS_ERROR_TIMEOUT; + else if (intmask & SDHCI_INT_DATA_CRC) + host->mrq->cmd->error = MSS_ERROR_CRC; + else if (intmask & SDHCI_INT_DATA_END_BIT) + host->mrq->cmd->error = MSS_ERROR_CRC; + + if (host->mrq->cmd->error != MSS_ERROR_NONE) + sdhci_finish_data(host); + else { + if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) + sdhci_transfer_pio(host); + + if (intmask & SDHCI_INT_DATA_END) + sdhci_finish_data(host); + } +} + +/* static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs) */ +static irqreturn_t sdhci_irq(int irq, void *dev_id) +{ + irqreturn_t result; + struct sdhci_host* host = dev_id; + u32 intmask; + struct mss_driver *drv; + struct mss_card *card; + u32 imask; + + spin_lock(&host->lock); + + intmask = readl(host->ioaddr + SDHCI_INT_STATUS); + + if (!intmask || intmask == 0xffffffff) { + result = IRQ_NONE; + goto out; + } + + DBG("*** %s got interrupt: 0x%08x\n", host->slot_descr, intmask); + + if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { + writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE), + host->ioaddr + SDHCI_INT_STATUS); + tasklet_schedule(&host->card_tasklet); + } + + intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); + + if (intmask & SDHCI_INT_CMD_MASK) { + writel(intmask & SDHCI_INT_CMD_MASK, + host->ioaddr + SDHCI_INT_STATUS); + sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); + } + + if (intmask & SDHCI_INT_DATA_MASK) { + writel(intmask & SDHCI_INT_DATA_MASK, + host->ioaddr + SDHCI_INT_STATUS); + sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); + } + + /* previous sdhci.c has no code for card interrupt handling */ + if (intmask & SDHCI_INT_CARD_INT) { + /* disable the card interrupt */ + imask = readl(host->ioaddr + SDHCI_INT_ENABLE); + imask &= ~(SDHCI_INT_CARD_INT); + writel(imask, host->ioaddr + SDHCI_INT_ENABLE); + + /* send the card interrupt to the SDIO app driver */ + card = host->card; + if (card) + drv = container_of(card->dev.driver, struct mss_driver, driver); + if (card && drv && (drv->sdio_int_handler != NULL)) + drv->sdio_int_handler(card); + } + + + intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); + + if (intmask & SDHCI_INT_BUS_POWER) { + printk(KERN_ERR "mmchost: Card is consuming too much power!\n"); + writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS); + } + + intmask &= SDHCI_INT_BUS_POWER; + + if (intmask) { + printk(KERN_ERR "mmchost: Unexpected interrupt 0x%08x.\n", intmask); + sdhci_dumpregs(host); + + writel(intmask, host->ioaddr + SDHCI_INT_STATUS); + } + + result = IRQ_HANDLED; + + + mmiowb(); +out: + spin_unlock(&host->lock); + + return result; +} + +/*****************************************************************************\ + * * + * Suspend/resume * + * * +\*****************************************************************************/ + +#ifdef CONFIG_PM + +static int sdhci_suspend (struct pci_dev *pdev, pm_message_t state) +{ + struct sdhci_chip *chip; + int i, ret; + + chip = pci_get_drvdata(pdev); + if (!chip) + return 0; + + DBG("Suspending...\n"); + + pci_save_state(pdev); + pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); + + for (i = 0;i < chip->num_slots;i++) { + if (!chip->hosts[i]) + continue; + free_irq(chip->hosts[i]->irq, chip->hosts[i]); + } + + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int sdhci_resume (struct pci_dev *pdev) +{ + struct sdhci_chip *chip; + int i, ret; + + chip = pci_get_drvdata(pdev); + if (!chip) + return 0; + + DBG("Resuming...\n"); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + if (ret) + return ret; + + for (i = 0;i < chip->num_slots;i++) { + if (!chip->hosts[i]) + continue; + if (chip->hosts[i]->flags & SDHCI_USE_DMA) + pci_set_master(pdev); + ret = request_irq(chip->hosts[i]->irq, sdhci_irq, + IRQF_SHARED, chip->hosts[i]->slot_descr, + chip->hosts[i]); + if (ret) + return ret; + sdhci_init(chip->hosts[i]); + mmiowb(); + } + + return 0; +} + +#else /* CONFIG_PM */ + +#define sdhci_suspend NULL +#define sdhci_resume NULL + +#endif /* CONFIG_PM */ + +/*****************************************************************************\ + * * + * Device probing/removal * + * * +\*****************************************************************************/ + +static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) +{ + int ret; + unsigned int version; + struct sdhci_chip *chip; + struct mss_host *mmc; + struct sdhci_host *host; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc_sdhci = NULL; + char pbuf[50]; +#endif + u8 first_bar; + unsigned int caps; + + u32 tmpval; + + + chip = pci_get_drvdata(pdev); + BUG_ON(!chip); + + ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar); + if (ret) + return ret; + first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK; + + if (first_bar > 5) { + printk(KERN_ERR DRIVER_NAME ": Invalid first BAR. Aborting.\n"); + return -ENODEV; + } + + if (!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)) { + printk(KERN_ERR DRIVER_NAME ": BAR is not iomem. Aborting.\n"); + return -ENODEV; + } + + tmpval = pci_resource_len(pdev, first_bar + slot); + + if (pci_resource_len(pdev, first_bar + slot) != 0x100) { + printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. " + "You may experience problems.\n"); + } + + if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) { + printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n"); + return -ENODEV; + } + + if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) { + printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n"); + return -ENODEV; + } + + //DBG("starting mss alloc process\n"); + + mmc = mss_alloc_host(1, 0, sizeof(struct sdhci_host)); + if (!mmc) + return -ENOMEM; + + host = mss_to_host(mmc); + host->mmc = mmc; + + host->chip = chip; + chip->hosts[slot] = host; + + mmc->slots->private = host; + host->card = NULL; + host->bar = first_bar + slot; + + host->addr = pci_resource_start(pdev, host->bar); + host->irq = pdev->irq; + + + snprintf(host->slot_descr, 20, "sdhci:slot%d", slot); + ret = pci_request_region(pdev, host->bar, host->slot_descr); + if (ret) + goto free; + + host->ioaddr = ioremap_nocache(host->addr, + pci_resource_len(pdev, host->bar)); + if (!host->ioaddr) { + ret = -ENOMEM; + goto release; + } + + sdhci_reset(host, SDHCI_RESET_ALL); + + version = readw(host->ioaddr + SDHCI_HOST_VERSION); + version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; + if (version != 0) { + printk(KERN_ERR "%s: Unknown controller version (%d). " + "You may experience problems.\n", host->slot_descr, + version); + } + + caps = readl(host->ioaddr + SDHCI_CAPABILITIES); + + /*on R5C832 controller we just assume the DMA is supported. It is a work round to fix the silicon bug*/ + // caps &= ~SDHCI_CAN_DO_DMA; + + if (debug_nodma) + DBG("DMA forced off\n"); + else if (debug_forcedma) { + DBG("DMA forced on\n"); + host->flags |= SDHCI_USE_DMA; + } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA) + host->flags |= SDHCI_USE_DMA; + /* mask the check point for some DMA capable SDIO controller + reporting wrong information to PCI, and "caps" should be + enough for judging DMA capability */ + /* else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) + DBG("Controller doesn't have DMA interface\n"); */ + else if (!(caps & SDHCI_CAN_DO_DMA)) + DBG("Controller doesn't have DMA capability\n"); + else + host->flags |= SDHCI_USE_DMA; + + if (host->flags & SDHCI_USE_DMA) { + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_WARNING "%s: No suitable DMA available. " + "Falling back to PIO.\n", host->slot_descr); + host->flags &= ~SDHCI_USE_DMA; + } + } + + if (host->flags & SDHCI_USE_DMA) + pci_set_master(pdev); + else /* XXX: Hack to get MMC layer to avoid highmem */ + pdev->dma_mask = 0; + + host->max_clk = + (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; + if (host->max_clk == 0) { + printk(KERN_ERR "%s: Hardware doesn't specify base clock " + "frequency.\n", host->slot_descr); + ret = -ENODEV; + goto unmap; + } + host->max_clk *= 1000000; + + host->timeout_clk = + (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; + if (host->timeout_clk == 0) { + printk(KERN_ERR "%s: Hardware doesn't specify timeout clock " + "frequency.\n", host->slot_descr); + ret = -ENODEV; + goto unmap; + } + if (caps & SDHCI_TIMEOUT_CLK_UNIT) + host->timeout_clk *= 1000; + + host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; + if (host->max_block >= 3) { + printk(KERN_ERR "%s: Invalid maximum block size.\n", + host->slot_descr); + ret = -ENODEV; + goto unmap; + } + host->max_block = 512 << host->max_block; + + + /* Set host parameters. */ + mmc->ops = &sdhci_ops; + mmc->f_min = host->max_clk / 256; + mmc->f_max = host->max_clk; + mmc->dev = &pdev->dev; + mmc->vdd = 0; + + if (caps & SDHCI_CAN_VDD_330) { + mmc->vdd |= MSS_VDD_32_33|MSS_VDD_33_34; + } else if (caps & SDHCI_CAN_VDD_300) { + mmc->vdd |= MSS_VDD_29_30|MSS_VDD_30_31; + } else if (caps & SDHCI_CAN_VDD_180) { + mmc->vdd |= MSS_VDD_170_195; + } + mmc->ios.vdd = mmc->vdd; + + if (mmc->vdd == 0) { + printk(KERN_ERR "%s: Hardware doesn't report any " + "support voltages.\n", host->slot_descr); + ret = -ENODEV; + goto unmap; + } + mmc->bus_width = MSS_BUSWIDTH_4BIT; + + spin_lock_init(&host->lock); + + /* + * Maximum number of segments. Hardware cannot do scatter lists. + */ + if (host->flags & SDHCI_USE_DMA) + mmc->max_hw_segs = 1; + else + mmc->max_hw_segs = 16; + mmc->max_phys_segs = 16; + + /* + * Maximum number of sectors in one transfer. Limited by DMA boundary + * size (512KiB), which means (512 KiB/512=) 1024 entries. + */ + mmc->max_sectors = 1024; + + /* + * Maximum segment size. Could be one segment with the maximum number + * of sectors. + */ + mmc->max_seg_size = mmc->max_sectors * 512; + + /* + * Init tasklets. + */ + tasklet_init(&host->card_tasklet, + sdhci_tasklet_card, (unsigned long)host); + tasklet_init(&host->finish_tasklet, + sdhci_tasklet_finish, (unsigned long)host); + + setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); + + ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, + host->slot_descr, host); + if (ret) + goto untasklet; + + sdhci_init(host); + mmiowb(); + + register_mss_host(mmc); + + printk(KERN_INFO "mmchost: SDHCI at 0x%08lx irq %d %s\n", + host->addr, host->irq, + (host->flags & SDHCI_USE_DMA)?"DMA":"PIO"); + + + mss_detect_change(host->mmc, msecs_to_jiffies(500), 0); + + +#ifdef CONFIG_PROC_FS + if (dir_sdhci) { + sprintf(pbuf, "%s.%d", pci_name(pdev), slot); + if ((proc_sdhci = create_proc_entry(pbuf, S_IRUSR | S_IRGRP | S_IROTH, dir_sdhci)) != NULL) + { + proc_sdhci->read_proc = sdhci_read_proc; + proc_sdhci->data = host; + } + } +#endif + return 0; + +untasklet: + tasklet_kill(&host->card_tasklet); + tasklet_kill(&host->finish_tasklet); +unmap: + iounmap(host->ioaddr); +release: + pci_release_region(pdev, host->bar); +free: + mss_free_host(mmc); + return ret; +} + +static void sdhci_remove_slot(struct pci_dev *pdev, int slot) +{ + struct sdhci_chip *chip; + struct mss_host *mmc; + struct sdhci_host *host; + struct mss_slot *mslot; + +#ifdef CONFIG_PROC_FS + char pbuf[50]; +#endif + + chip = pci_get_drvdata(pdev); + host = chip->hosts[slot]; + mmc = host->mmc; + + mslot = &mmc->slots[slot]; + if (mslot->card) + mss_force_card_remove(mslot->card); + + unregister_mss_host(mmc); + chip->hosts[slot] = NULL; + + sdhci_reset(host, SDHCI_RESET_ALL); + + free_irq(host->irq, host); + + del_timer_sync(&host->timer); + + tasklet_kill(&host->card_tasklet); + tasklet_kill(&host->finish_tasklet); + + iounmap(host->ioaddr); + + pci_release_region(pdev, host->bar); + +#ifdef CONFIG_PROC_FS + if (dir_sdhci) { + sprintf(pbuf, "%s.%d", pci_name(pdev), slot); + remove_proc_entry(pbuf, dir_sdhci); + } +#endif + mss_free_host(mmc); +} + +static int __devinit sdhci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int ret, i; + u8 slots, rev; + struct sdhci_chip *chip; + + + BUG_ON(pdev == NULL); + BUG_ON(ent == NULL); + + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev); + + printk(KERN_INFO DRIVER_NAME + ": SDHCI controller found at %s [%04x:%04x] (rev %x)\n", + pci_name(pdev), (int)pdev->vendor, (int)pdev->device, + (int)rev); + + ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots); + if (ret) + return ret; + + slots = PCI_SLOT_INFO_SLOTS(slots) + 1; + if (slots == 0) + return -ENODEV; + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + chip = kzalloc(sizeof(struct sdhci_chip) + + sizeof(struct sdhci_host*) * slots, GFP_KERNEL); + if (!chip) { + ret = -ENOMEM; + goto err; + } + + chip->pdev = pdev; + chip->quirks = ent->driver_data; + + if (debug_quirks) + chip->quirks = debug_quirks; + + chip->num_slots = slots; + pci_set_drvdata(pdev, chip); + + for (i = 0;i < slots;i++) { + ret = sdhci_probe_slot(pdev, i); + if (ret) { + for (i--;i >= 0;i--) + sdhci_remove_slot(pdev, i); + goto free; + } + } + + return 0; + +free: + pci_set_drvdata(pdev, NULL); + kfree(chip); +err: + pci_disable_device(pdev); + return ret; +} + +static void __devexit sdhci_remove(struct pci_dev *pdev) +{ + int i; + struct sdhci_chip *chip; + + chip = pci_get_drvdata(pdev); + + if (chip) { + for (i = 0;i < chip->num_slots;i++) + sdhci_remove_slot(pdev, i); + + pci_set_drvdata(pdev, NULL); + + kfree(chip); + } + + pci_disable_device(pdev); +} + +static struct pci_driver sdhci_driver = { + .name = DRIVER_NAME, + .id_table = pci_ids, + .probe = sdhci_probe, + .remove = __devexit_p(sdhci_remove), + .suspend = sdhci_suspend, + .resume = sdhci_resume, +}; + +/*****************************************************************************\ + * * + * Driver init/exit * + * * +\*****************************************************************************/ + +static int __init sdhci_drv_init(void) +{ + printk(KERN_INFO DRIVER_NAME + ": Secure Digital Host Controller Interface driver\n"); + printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); + + + +#ifdef CONFIG_PROC_FS + if ((dir_sdhci = proc_mkdir("sdhci", NULL)) == NULL) + printk(KERN_WARNING "SDHCI failed to create proc interface\n"); +#endif + return pci_register_driver(&sdhci_driver); +} + +static void __exit sdhci_drv_exit(void) +{ + pci_unregister_driver(&sdhci_driver); +#ifdef CONFIG_PROC_FS + if (dir_sdhci) { + remove_proc_entry("sdhci", NULL); + dir_sdhci = NULL; + } +#endif +} + +module_init(sdhci_drv_init); +module_exit(sdhci_drv_exit); + +module_param(debug_nodma, uint, 0444); +module_param(debug_forcedma, uint, 0444); +module_param(debug_quirks, uint, 0444); + +MODULE_AUTHOR("Pierre Ossman "); +MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver"); +MODULE_LICENSE("GPL"); + +MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)"); +MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)"); +MODULE_PARM_DESC(debug_quirks, "Force certain quirks."); --- linux-2.6.24.orig/drivers/mmc/Makefile +++ linux-2.6.24/drivers/mmc/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_MMC) += core/ obj-$(CONFIG_MMC) += card/ obj-$(CONFIG_MMC) += host/ +obj-$(CONFIG_MSS) += mss/ --- linux-2.6.24.orig/drivers/video/vesafb.c +++ linux-2.6.24/drivers/video/vesafb.c @@ -28,6 +28,12 @@ #define dac_reg (0x3c8) #define dac_val (0x3c9) +struct vesafb_info +{ + u32 pseudo_palette[256]; + int mtrr_hdl; +}; + /* --------------------------------------------------------------------- */ static struct fb_var_screeninfo vesafb_defined __initdata = { @@ -47,16 +53,37 @@ .accel = FB_ACCEL_NONE, }; +#ifndef MODULE static int inverse __read_mostly; +#endif static int mtrr __read_mostly; /* disable mtrr */ static int vram_remap __initdata; /* Set amount of memory to be used */ static int vram_total __initdata; /* Set total amount of memory */ static int pmi_setpal __read_mostly = 1; /* pmi for palette changes ??? */ +static int redraw __read_mostly; static int ypan __read_mostly; /* 0..nothing, 1..ypan, 2..ywrap */ +static int ywrap __read_mostly; static void (*pmi_start)(void) __read_mostly; static void (*pmi_pal) (void) __read_mostly; static int depth __read_mostly; static int vga_compat __read_mostly; + +module_param(redraw, bool, 0); +module_param(ypan, bool, 0); +module_param(ywrap, bool, 0); +module_param_named(vgapal, pmi_setpal, invbool, 0); +MODULE_PARM_DESC(vgapal, "Use VGA for setting palette (default)"); +module_param_named(pmipal, pmi_setpal, bool, 0); +MODULE_PARM_DESC(pmipal, "Use PMI for setting palette"); +module_param(mtrr, bool, 0); +MODULE_PARM_DESC(mtrr, "Enable MTRR support (default)"); +module_param_named(nomtrr, mtrr, invbool, 0); +MODULE_PARM_DESC(nomtrr, "Disable MTRR support"); +module_param(vram_remap, int, 0); +MODULE_PARM_DESC(vram_remap, "Set total amount of memory to be used"); +module_param(vram_total, int, 0); +MODULE_PARM_DESC(vram_total, "Total amount of memory"); + /* --------------------------------------------------------------------- */ static int vesafb_pan_display(struct fb_var_screeninfo *var, @@ -183,6 +210,7 @@ .fb_imageblit = cfb_imageblit, }; +#ifndef MODULE static int __init vesafb_setup(char *options) { char *this_opt; @@ -216,6 +244,7 @@ } return 0; } +#endif static int __init vesafb_probe(struct platform_device *dev) { @@ -463,8 +492,28 @@ return err; } +static int __exit vesafb_remove(struct platform_device *device) +{ + struct fb_info *info = dev_get_drvdata(&device->dev); + + unregister_framebuffer(info); +#ifdef CONFIG_MTRR + { + struct vesafb_info *vfb_info = (struct vesafb_info *) info->par; + if (vfb_info->mtrr_hdl >= 0) + mtrr_del(vfb_info->mtrr_hdl, 0, 0); + } +#endif + iounmap(info->screen_base); + framebuffer_release(info); + release_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len); + + return 0; +} + static struct platform_driver vesafb_driver = { .probe = vesafb_probe, + .remove = vesafb_remove, .driver = { .name = "vesafb", }, @@ -475,11 +524,18 @@ static int __init vesafb_init(void) { int ret; +#ifndef MODULE char *option = NULL; /* ignore error return of fb_get_options */ fb_get_options("vesafb", &option); vesafb_setup(option); +#else + if (redraw) + ypan = 0; + if (ywrap) + ypan = 2; +#endif ret = platform_driver_register(&vesafb_driver); if (!ret) { @@ -498,6 +554,14 @@ return ret; } + +static void __exit vesafb_exit(void) +{ + platform_device_unregister(vesafb_device); + platform_driver_unregister(&vesafb_driver); +} + module_init(vesafb_init); +module_exit(vesafb_exit); MODULE_LICENSE("GPL"); --- linux-2.6.24.orig/drivers/video/Kconfig +++ linux-2.6.24/drivers/video/Kconfig @@ -629,8 +629,8 @@ If unsure, say N. config FB_VESA - bool "VESA VGA graphics support" - depends on (FB = y) && X86 + tristate "VESA VGA graphics support" + depends on FB && X86 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT --- linux-2.6.24.orig/drivers/video/uvesafb.c +++ linux-2.6.24/drivers/video/uvesafb.c @@ -66,12 +66,14 @@ * find the kernel part of the task struct, copy the registers and * the buffer contents and then complete the task. */ -static void uvesafb_cn_callback(void *data) +static void uvesafb_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { - struct cn_msg *msg = data; struct uvesafb_task *utask; struct uvesafb_ktask *task; + if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) + return; + if (msg->seq >= UVESAFB_TASKS_MAX) return; --- linux-2.6.24.orig/drivers/video/nvidia/nvidia.c +++ linux-2.6.24/drivers/video/nvidia/nvidia.c @@ -1048,7 +1048,7 @@ acquire_console_sem(); par->pm_state = mesg.event; - if (mesg.event == PM_EVENT_SUSPEND) { + if (mesg.event & PM_EVENT_SLEEP) { fb_set_suspend(info, 1); nvidiafb_blank(FB_BLANK_POWERDOWN, info); nvidia_write_regs(par, &par->SavedReg); --- linux-2.6.24.orig/drivers/video/console/vgacon.c +++ linux-2.6.24/drivers/video/console/vgacon.c @@ -1268,7 +1268,7 @@ font->charcount = vga_512_chars ? 512 : 256; if (!font->data) return 0; - return vgacon_do_font_op(&state, font->data, 0, 0); + return vgacon_do_font_op(&state, font->data, 0, vga_512_chars); } #else --- linux-2.6.24.orig/drivers/video/fb_defio.c +++ linux-2.6.24/drivers/video/fb_defio.c @@ -88,6 +88,17 @@ .page_mkwrite = fb_deferred_io_mkwrite, }; +static int fb_deferred_io_set_page_dirty(struct page *page) +{ + if (!PageDirty(page)) + SetPageDirty(page); + return 0; +} + +static const struct address_space_operations fb_deferred_io_aops = { + .set_page_dirty = fb_deferred_io_set_page_dirty, +}; + static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma) { vma->vm_ops = &fb_deferred_io_vm_ops; @@ -137,6 +148,14 @@ } EXPORT_SYMBOL_GPL(fb_deferred_io_init); +void fb_deferred_io_open(struct fb_info *info, + struct inode *inode, + struct file *file) +{ + file->f_mapping->a_ops = &fb_deferred_io_aops; +} +EXPORT_SYMBOL_GPL(fb_deferred_io_open); + void fb_deferred_io_cleanup(struct fb_info *info) { struct fb_deferred_io *fbdefio = info->fbdefio; --- linux-2.6.24.orig/drivers/video/chipsfb.c +++ linux-2.6.24/drivers/video/chipsfb.c @@ -459,7 +459,7 @@ if (state.event == pdev->dev.power.power_state.event) return 0; - if (state.event != PM_EVENT_SUSPEND) + if (!(state.event & PM_EVENT_SLEEP)) goto done; acquire_console_sem(); --- linux-2.6.24.orig/drivers/video/fbmem.c +++ linux-2.6.24/drivers/video/fbmem.c @@ -1315,6 +1315,10 @@ if (res) module_put(info->fbops->owner); } +#ifdef CONFIG_FB_DEFERRED_IO + if (info->fbdefio) + fb_deferred_io_open(info, inode, file); +#endif return res; } @@ -1521,6 +1525,7 @@ static void __exit fbmem_exit(void) { + remove_proc_entry("fb", NULL); class_destroy(fb_class); unregister_chrdev(FB_MAJOR, "fb"); } --- linux-2.6.24.orig/drivers/ssb/pci.c +++ linux-2.6.24/drivers/ssb/pci.c @@ -426,6 +426,7 @@ SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC, SSB_SPROM_REVISION_CRC_SHIFT); + if ((bus->chip_id & 0xFF00) == 0x4400) { /* Workaround: The BCM44XX chip has a stupid revision * number stored in the SPROM. @@ -443,6 +444,10 @@ if (out->revision >= 4) goto unsupported; } + if (out->r1.boardflags_lo == 0xFFFF) + out->r1.boardflags_lo = 0; /* per specs */ + if (out->r2.boardflags_hi == 0xFFFF) + out->r2.boardflags_hi = 0; /* per specs */ return 0; unsupported: --- linux-2.6.24.orig/drivers/ssb/driver_pcicore.c +++ linux-2.6.24/drivers/ssb/driver_pcicore.c @@ -517,7 +517,7 @@ } else { tmp = ssb_read32(dev, SSB_TPSFLAG); tmp &= SSB_TPSFLAG_BPFLAG; - intvec |= tmp; + intvec |= (1 << tmp); } ssb_write32(pdev, SSB_INTVEC, intvec); } --- linux-2.6.24.orig/drivers/ssb/main.c +++ linux-2.6.24/drivers/ssb/main.c @@ -879,6 +879,11 @@ return SSB_TMSLOW_REJECT_22; case SSB_IDLOW_SSBREV_23: return SSB_TMSLOW_REJECT_23; + case SSB_IDLOW_SSBREV_24: /* TODO - find the proper REJECT bits */ + case SSB_IDLOW_SSBREV_25: /* same here */ + case SSB_IDLOW_SSBREV_26: /* same here */ + case SSB_IDLOW_SSBREV_27: /* same here */ + return SSB_TMSLOW_REJECT_23; /* this is a guess */ default: WARN_ON(1); } @@ -1032,6 +1037,12 @@ goto out; cc = &bus->chipco; + + if (!cc->dev) + goto out; + if (cc->dev->id.revision < 5) + goto out; + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW); err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); if (err) --- linux-2.6.24.orig/drivers/uio/uio.c +++ linux-2.6.24/drivers/uio/uio.c @@ -447,6 +447,8 @@ vma->vm_flags |= VM_IO | VM_RESERVED; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + return remap_pfn_range(vma, vma->vm_start, idev->info->mem[mi].addr >> PAGE_SHIFT, --- linux-2.6.24.orig/drivers/acpi/resources/rscalc.c +++ linux-2.6.24/drivers/acpi/resources/rscalc.c @@ -211,6 +211,13 @@ * variable-length fields */ switch (resource->type) { + case ACPI_RESOURCE_TYPE_IRQ: + + if (resource->data.irq.descriptor_length == 2) { + total_size--; + } + break; + case ACPI_RESOURCE_TYPE_VENDOR: /* * Vendor Defined Resource: --- linux-2.6.24.orig/drivers/acpi/resources/rsirq.c +++ linux-2.6.24/drivers/acpi/resources/rsirq.c @@ -52,7 +52,7 @@ * acpi_rs_get_irq * ******************************************************************************/ -struct acpi_rsconvert_info acpi_rs_get_irq[7] = { +struct acpi_rsconvert_info acpi_rs_get_irq[8] = { {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_IRQ, ACPI_RS_SIZE(struct acpi_resource_irq), ACPI_RSC_TABLE_SIZE(acpi_rs_get_irq)}, @@ -69,6 +69,12 @@ ACPI_EDGE_SENSITIVE, 1}, + /* Get the descriptor length (2 or 3 for IRQ descriptor) */ + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.irq.descriptor_length), + AML_OFFSET(irq.descriptor_type), + 0}, + /* All done if no flag byte present in descriptor */ {ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 3}, @@ -94,7 +100,9 @@ * ******************************************************************************/ -struct acpi_rsconvert_info acpi_rs_set_irq[9] = { +struct acpi_rsconvert_info acpi_rs_set_irq[13] = { + /* Start with a default descriptor of length 3 */ + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_IRQ, sizeof(struct aml_resource_irq), ACPI_RSC_TABLE_SIZE(acpi_rs_set_irq)}, @@ -105,7 +113,7 @@ AML_OFFSET(irq.irq_mask), ACPI_RS_OFFSET(data.irq.interrupt_count)}, - /* Set the flags byte by default */ + /* Set the flags byte */ {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.triggering), AML_OFFSET(irq.flags), @@ -118,6 +126,33 @@ {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.sharable), AML_OFFSET(irq.flags), 4}, + + /* + * All done if the output descriptor length is required to be 3 + * (i.e., optimization to 2 bytes cannot be attempted) + */ + {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET(data.irq.descriptor_length), + 3}, + + /* Set length to 2 bytes (no flags byte) */ + + {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq_noflags)}, + + /* + * All done if the output descriptor length is required to be 2. + * + * TBD: Perhaps we should check for error if input flags are not + * compatible with a 2-byte descriptor. + */ + {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET(data.irq.descriptor_length), + 2}, + + /* Reset length to 3 bytes (descriptor with flags byte) */ + + {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq)}, + /* * Check if the flags byte is necessary. Not needed if the flags are: * ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH, ACPI_EXCLUSIVE @@ -134,7 +169,7 @@ ACPI_RS_OFFSET(data.irq.sharable), ACPI_EXCLUSIVE}, - /* irq_no_flags() descriptor can be used */ + /* We can optimize to a 2-byte irq_no_flags() descriptor */ {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq_noflags)} }; --- linux-2.6.24.orig/drivers/acpi/resources/rsdump.c +++ linux-2.6.24/drivers/acpi/resources/rsdump.c @@ -87,8 +87,10 @@ * ******************************************************************************/ -struct acpi_rsdump_info acpi_rs_dump_irq[6] = { +struct acpi_rsdump_info acpi_rs_dump_irq[7] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_irq), "IRQ", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.descriptor_length), + "Descriptor Length", NULL}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.triggering), "Triggering", acpi_gbl_he_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.polarity), "Polarity", @@ -115,9 +117,11 @@ NULL} }; -struct acpi_rsdump_info acpi_rs_dump_start_dpf[3] = { +struct acpi_rsdump_info acpi_rs_dump_start_dpf[4] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_start_dpf), "Start-Dependent-Functions", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(start_dpf.descriptor_length), + "Descriptor Length", NULL}, {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.compatibility_priority), "Compatibility Priority", acpi_gbl_config_decode}, {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.performance_robustness), --- linux-2.6.24.orig/drivers/acpi/resources/rsmisc.c +++ linux-2.6.24/drivers/acpi/resources/rsmisc.c @@ -497,6 +497,17 @@ } break; + case ACPI_RSC_EXIT_EQ: + /* + * Control - Exit conversion if equal + */ + if (*ACPI_ADD_PTR(u8, resource, + COMPARE_TARGET(info)) == + COMPARE_VALUE(info)) { + goto exit; + } + break; + default: ACPI_ERROR((AE_INFO, "Invalid conversion opcode")); --- linux-2.6.24.orig/drivers/acpi/resources/rsio.c +++ linux-2.6.24/drivers/acpi/resources/rsio.c @@ -185,7 +185,7 @@ * ******************************************************************************/ -struct acpi_rsconvert_info acpi_rs_get_start_dpf[5] = { +struct acpi_rsconvert_info acpi_rs_get_start_dpf[6] = { {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_START_DEPENDENT, ACPI_RS_SIZE(struct acpi_resource_start_dependent), ACPI_RSC_TABLE_SIZE(acpi_rs_get_start_dpf)}, @@ -196,6 +196,12 @@ ACPI_ACCEPTABLE_CONFIGURATION, 2}, + /* Get the descriptor length (0 or 1 for Start Dpf descriptor) */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.start_dpf.descriptor_length), + AML_OFFSET(start_dpf.descriptor_type), + 0}, + /* All done if there is no flag byte present in the descriptor */ {ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 1}, @@ -219,7 +225,9 @@ * ******************************************************************************/ -struct acpi_rsconvert_info acpi_rs_set_start_dpf[6] = { +struct acpi_rsconvert_info acpi_rs_set_start_dpf[10] = { + /* Start with a default descriptor of length 1 */ + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_START_DEPENDENT, sizeof(struct aml_resource_start_dependent), ACPI_RSC_TABLE_SIZE(acpi_rs_set_start_dpf)}, @@ -236,6 +244,33 @@ AML_OFFSET(start_dpf.flags), 2}, /* + * All done if the output descriptor length is required to be 1 + * (i.e., optimization to 0 bytes cannot be attempted) + */ + {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET(data.start_dpf.descriptor_length), + 1}, + + /* Set length to 0 bytes (no flags byte) */ + + {ACPI_RSC_LENGTH, 0, 0, + sizeof(struct aml_resource_start_dependent_noprio)}, + + /* + * All done if the output descriptor length is required to be 0. + * + * TBD: Perhaps we should check for error if input flags are not + * compatible with a 0-byte descriptor. + */ + {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET(data.start_dpf.descriptor_length), + 0}, + + /* Reset length to 1 byte (descriptor with flags byte) */ + + {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq)}, + + /* * All done if flags byte is necessary -- if either priority value * is not ACPI_ACCEPTABLE_CONFIGURATION */ --- linux-2.6.24.orig/drivers/acpi/video.c +++ linux-2.6.24/drivers/acpi/video.c @@ -72,6 +72,10 @@ MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_LICENSE("GPL"); +static int no_automatic_changes = 1; + +module_param(no_automatic_changes, uint, 0600); + static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device, int type); @@ -292,18 +296,26 @@ static int acpi_video_get_brightness(struct backlight_device *bd) { unsigned long cur_level; + int i; struct acpi_video_device *vd = (struct acpi_video_device *)bl_get_data(bd); acpi_video_device_lcd_get_level_current(vd, &cur_level); - return (int) cur_level; + for (i = 2; i < vd->brightness->count; i++) { + if (vd->brightness->levels[i] == cur_level) + /* The first two entries are special - see page 575 + of the ACPI spec 3.0 */ + return i-2; + } + return 0; } static int acpi_video_set_brightness(struct backlight_device *bd) { - int request_level = bd->props.brightness; + int request_level = bd->props.brightness+2; struct acpi_video_device *vd = (struct acpi_video_device *)bl_get_data(bd); - acpi_video_device_lcd_set_level(vd, request_level); + acpi_video_device_lcd_set_level(vd, + vd->brightness->levels[request_level]); return 0; } @@ -652,7 +664,6 @@ kfree(obj); if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){ - unsigned long tmp; static int count = 0; char *name; name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); @@ -660,11 +671,10 @@ return; sprintf(name, "acpi_video%d", count++); - acpi_video_device_lcd_get_level_current(device, &tmp); device->backlight = backlight_device_register(name, NULL, device, &acpi_backlight_ops); - device->backlight->props.max_brightness = max_level; - device->backlight->props.brightness = (int)tmp; + device->backlight->props.max_brightness = device->brightness->count-3; + device->backlight->props.brightness = acpi_video_get_brightness(device->backlight); backlight_update_status(device->backlight); kfree(name); @@ -1850,27 +1860,32 @@ switch (event) { case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ - acpi_video_switch_brightness(video_device, event); + if (!no_automatic_changes) + acpi_video_switch_brightness(video_device, event); acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESS_CYCLE; break; case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ - acpi_video_switch_brightness(video_device, event); + if (!no_automatic_changes) + acpi_video_switch_brightness(video_device, event); acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESSUP; break; case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ - acpi_video_switch_brightness(video_device, event); + if (!no_automatic_changes) + acpi_video_switch_brightness(video_device, event); acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESSDOWN; break; case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */ - acpi_video_switch_brightness(video_device, event); + if (!no_automatic_changes) + acpi_video_switch_brightness(video_device, event); acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESS_ZERO; break; case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ - acpi_video_switch_brightness(video_device, event); + if (!no_automatic_changes) + acpi_video_switch_brightness(video_device, event); acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_DISPLAY_OFF; break; --- linux-2.6.24.orig/drivers/acpi/executer/exconfig.c +++ linux-2.6.24/drivers/acpi/executer/exconfig.c @@ -268,6 +268,8 @@ struct acpi_table_desc table_desc; acpi_native_uint table_index; acpi_status status; + u32 length; + void *maddr; ACPI_FUNCTION_TRACE(ex_load_op); @@ -299,9 +301,24 @@ } } + length = obj_desc->region.length; + table_desc.pointer = ACPI_ALLOCATE(length); + if (!table_desc.pointer) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + maddr = acpi_os_map_memory(obj_desc->region.address, length); + if (!maddr) { + ACPI_FREE(table_desc.pointer); + return_ACPI_STATUS(AE_NO_MEMORY); + } + ACPI_MEMCPY(table_desc.pointer, maddr, length); + acpi_os_unmap_memory(maddr, length); + + /* Keep the address for the pretty table info print */ table_desc.address = obj_desc->region.address; table_desc.length = obj_desc->region.length; - table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED; + table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED; break; case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */ --- linux-2.6.24.orig/drivers/acpi/osl.c +++ linux-2.6.24/drivers/acpi/osl.c @@ -312,6 +312,67 @@ return AE_OK; } +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD +struct acpi_table_header * acpi_find_dsdt_initrd(void) +{ + struct file *firmware_file; + mm_segment_t oldfs; + unsigned long len, len2; + struct acpi_table_header *dsdt_buffer, *ret = NULL; + struct kstat stat; + /* maybe this could be an argument on the cmd line, but let's keep it simple for now */ + char *ramfs_dsdt_name = "/DSDT.aml"; + + printk(KERN_INFO PREFIX "Looking for DSDT in initramfs... "); + + /* + * Never do this at home, only the user-space is allowed to open a file. + * The clean way would be to use the firmware loader. But this code must be run + * before there is any userspace available. So we need a static/init firmware + * infrastructure, which doesn't exist yet... + */ + if (vfs_stat(ramfs_dsdt_name, &stat) < 0) { + printk("error, file %s not found.\n", ramfs_dsdt_name); + return ret; + } + + len = stat.size; + /* check especially against empty files */ + if (len <= 4) { + printk("error file is too small, only %lu bytes.\n", len); + return ret; + } + + firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0); + if (IS_ERR(firmware_file)) { + printk("error, could not open file %s.\n", ramfs_dsdt_name); + return ret; + } + + dsdt_buffer = ACPI_ALLOCATE(len); + if (!dsdt_buffer) { + printk("error when allocating %lu bytes of memory.\n", len); + goto err; + } + + oldfs = get_fs(); + set_fs(KERNEL_DS); + len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len, &firmware_file->f_pos); + set_fs(oldfs); + if (len2 < len) { + printk("error trying to read %lu bytes from %s.\n", len, ramfs_dsdt_name); + ACPI_FREE(dsdt_buffer); + goto err; + } + + printk("successfully read %lu bytes from %s.\n", len, ramfs_dsdt_name); + ret = dsdt_buffer; +err: + filp_close(firmware_file, NULL); + return ret; +} +#endif + acpi_status acpi_os_table_override(struct acpi_table_header * existing_table, struct acpi_table_header ** new_table) @@ -319,13 +380,18 @@ if (!existing_table || !new_table) return AE_BAD_PARAMETER; + *new_table = NULL; + #ifdef CONFIG_ACPI_CUSTOM_DSDT if (strncmp(existing_table->signature, "DSDT", 4) == 0) *new_table = (struct acpi_table_header *)AmlCode; - else - *new_table = NULL; -#else - *new_table = NULL; +#endif +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD + if (strncmp(existing_table->signature, "DSDT", 4) == 0) { + struct acpi_table_header* initrd_table = acpi_find_dsdt_initrd(); + if (initrd_table) + *new_table = initrd_table; + } #endif return AE_OK; } @@ -750,6 +816,7 @@ void acpi_os_wait_events_complete(void *context) { flush_workqueue(kacpid_wq); + flush_workqueue(kacpi_notify_wq); } EXPORT_SYMBOL(acpi_os_wait_events_complete); --- linux-2.6.24.orig/drivers/acpi/scan.c +++ linux-2.6.24/drivers/acpi/scan.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include /* for acpi_ex_eisa_id_to_string() */ @@ -86,17 +87,37 @@ } static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); -static int acpi_eject_operation(acpi_handle handle, int lockable) +static int acpi_bus_hot_remove_device(void *context) { + struct acpi_device *device; + acpi_handle handle = context; struct acpi_object_list arg_list; union acpi_object arg; acpi_status status = AE_OK; - /* - * TBD: evaluate _PS3? - */ + if (acpi_bus_get_device(handle, &device)) + return 0; + + if (!device) + return 0; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Hot-removing device %s...\n", device->dev.bus_id)); - if (lockable) { + + if (acpi_bus_trim(device, 1)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Removing device failed\n")); + return -1; + } + + /* power off device */ + status = acpi_evaluate_object(handle, "_PS3", NULL, NULL); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Power-off device failed\n")); + + if (device->flags.lockable) { arg_list.count = 1; arg_list.pointer = &arg; arg.type = ACPI_TYPE_INTEGER; @@ -112,24 +133,19 @@ /* * TBD: _EJD support. */ - status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - return (-ENODEV); - } + if (ACPI_FAILURE(status)) + return -ENODEV; - return (0); + return 0; } static ssize_t acpi_eject_store(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - int result; int ret = count; - int islockable; acpi_status status; - acpi_handle handle; acpi_object_type type = 0; struct acpi_device *acpi_device = to_acpi_device(d); @@ -148,17 +164,9 @@ goto err; } - islockable = acpi_device->flags.lockable; - handle = acpi_device->handle; - - result = acpi_bus_trim(acpi_device, 1); - - if (!result) - result = acpi_eject_operation(handle, islockable); - - if (result) { - ret = -EBUSY; - } + /* remove the device in another thread to fix the deadlock issue */ + ret = kernel_thread(acpi_bus_hot_remove_device, + acpi_device->handle, SIGCHLD); err: return ret; } @@ -1156,6 +1164,16 @@ acpi_device_set_id(device, parent, handle, type); /* + * The ACPI device is attached to acpi handle before getting + * the power/wakeup/peformance flags. Otherwise OS can't get + * the corresponding ACPI device by the acpi handle in the course + * of getting the power/wakeup/performance flags. + */ + result = acpi_device_set_context(device, type); + if (result) + goto end; + + /* * Power Management * ---------------- */ @@ -1185,8 +1203,6 @@ goto end; } - if ((result = acpi_device_set_context(device, type))) - goto end; result = acpi_device_register(device, parent); --- linux-2.6.24.orig/drivers/acpi/toshiba_acpi.c +++ linux-2.6.24/drivers/acpi/toshiba_acpi.c @@ -27,13 +27,28 @@ * engineering the Windows drivers * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5 * Rob Miller - TV out and hotkeys help + * Daniel Silverstone - Punting of hotkeys via acpi using a thread * + * PLEASE NOTE + * + * This is an experimental version of toshiba_acpi which includes emulation + * of the original toshiba driver's /proc/toshiba and /dev/toshiba, + * allowing Toshiba userspace utilities to work. The relevant code was + * based on toshiba.c (copyright 1996-2001 Jonathan A. Buzzard) and + * incorporated into this driver with help from Gintautas Miliauskas, + * Charles Schwieters, and Christoph Burger-Scheidlin. + * + * Caveats: + * * hotkey status in /proc/toshiba is not implemented + * * to make accesses to /dev/toshiba load this driver instead of + * the original driver, you will have to modify your module + * auto-loading configuration * * TODO * */ -#define TOSHIBA_ACPI_VERSION "0.18" +#define TOSHIBA_ACPI_VERSION "0.19a-dev" #define PROC_INTERFACE_VERSION 1 #include @@ -41,12 +56,32 @@ #include #include #include +#include +#include +#include +#include +#include #include - +#include #include #include +/* Some compatibility for isa legacy interface */ +#ifndef isa_readb + +#define isa_readb(a) readb(__ISA_IO_base + (a)) +#define isa_readw(a) readw(__ISA_IO_base + (a)) +#define isa_readl(a) readl(__ISA_IO_base + (a)) +#define isa_writeb(b,a) writeb(b,__ISA_IO_base + (a)) +#define isa_writew(w,a) writew(w,__ISA_IO_base + (a)) +#define isa_writel(l,a) writel(l,__ISA_IO_base + (a)) +#define isa_memset_io(a,b,c) memset_io(__ISA_IO_base + (a),(b),(c)) +#define isa_memcpy_fromio(a,b,c) memcpy_fromio((a),__ISA_IO_base + (b),(c)) +#define isa_memcpy_toio(a,b,c) memcpy_toio(__ISA_IO_base + (a),(b),(c)) + +#endif + MODULE_AUTHOR("John Belmonte"); MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); MODULE_LICENSE("GPL"); @@ -216,6 +251,11 @@ static int force_fan; static int last_key_event; static int key_event_valid; +static int hotkeys_over_acpi = 1; +static int hotkeys_check_per_sec = 2; + +module_param(hotkeys_over_acpi, uint, 0400); +module_param(hotkeys_check_per_sec, uint, 0400); typedef struct _ProcItem { const char *name; @@ -443,27 +483,34 @@ u32 hci_result; u32 value; - if (!key_event_valid) { - hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result); - if (hci_result == HCI_SUCCESS) { - key_event_valid = 1; - last_key_event = value; - } else if (hci_result == HCI_EMPTY) { - /* better luck next time */ - } else if (hci_result == HCI_NOT_SUPPORTED) { - /* This is a workaround for an unresolved issue on - * some machines where system events sporadically - * become disabled. */ - hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); - printk(MY_NOTICE "Re-enabled hotkeys\n"); - } else { - printk(MY_ERR "Error reading hotkey status\n"); - goto end; + if (!hotkeys_over_acpi) { + if (!key_event_valid) { + hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result); + if (hci_result == HCI_SUCCESS) { + key_event_valid = 1; + last_key_event = value; + } else if (hci_result == HCI_EMPTY) { + /* better luck next time */ + } else if (hci_result == HCI_NOT_SUPPORTED) { + /* This is a workaround for an + * unresolved issue on some machines + * where system events sporadically + * become disabled. */ + hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); + printk(MY_NOTICE "Re-enabled hotkeys\n"); + } else { + printk(MY_ERR "Error reading hotkey status\n"); + goto end; + } } + } else { + key_event_valid = 0; + last_key_event = 0; } p += sprintf(p, "hotkey_ready: %d\n", key_event_valid); p += sprintf(p, "hotkey: 0x%04x\n", last_key_event); + p += sprintf(p, "hotkeys_via_acpi: %d\n", hotkeys_over_acpi); end: return p; @@ -490,6 +537,179 @@ return p; } +/* /dev/toshiba and /proc/toshiba handlers {{{ + * + * ISSUE: lots of magic numbers and mysterious code + */ + +#define TOSH_MINOR_DEV 181 +#define OLD_PROC_TOSHIBA "toshiba" + +static int +tosh_acpi_bridge(SMMRegisters* regs) +{ + acpi_status status; + + /* assert(sizeof(SMMRegisters) == sizeof(u32)*HCI_WORDS); */ + status = hci_raw((u32*)regs, (u32*)regs); + if (status == AE_OK && (regs->eax & 0xff00) == HCI_SUCCESS) + return 0; + + return -EINVAL; +} + +static int +tosh_ioctl(struct inode* ip, struct file* fp, unsigned int cmd, + unsigned long arg) +{ + SMMRegisters regs; + unsigned short ax,bx; + int err; + + if ((!arg) || (cmd != TOSH_SMM)) + return -EINVAL; + + if (copy_from_user(®s, (SMMRegisters*)arg, sizeof(SMMRegisters))) + return -EFAULT; + + ax = regs.eax & 0xff00; + bx = regs.ebx & 0xffff; + + /* block HCI calls to read/write memory & PCI devices */ + if (((ax==HCI_SET) || (ax==HCI_GET)) && (bx>0x0069)) + return -EINVAL; + + err = tosh_acpi_bridge(®s); + + if (copy_to_user((SMMRegisters*)arg, ®s, sizeof(SMMRegisters))) + return -EFAULT; + + return err; +} + +static int +tosh_get_machine_id(void) +{ + int id; + unsigned short bx,cx; + unsigned long address; + + id = (0x100*(int)isa_readb(0xffffe))+((int)isa_readb(0xffffa)); + + /* do we have a SCTTable machine identication number on our hands */ + if (id==0xfc2f) { + bx = 0xe6f5; /* cheat */ + /* now twiddle with our pointer a bit */ + address = 0x000f0000+bx; + cx = isa_readw(address); + address = 0x000f0009+bx+cx; + cx = isa_readw(address); + address = 0x000f000a+cx; + cx = isa_readw(address); + /* now construct our machine identification number */ + id = ((cx & 0xff)<<8)+((cx & 0xff00)>>8); + } + + return id; +} + +static int tosh_id; +static int tosh_bios; +static int tosh_date; +static int tosh_sci; + +static struct file_operations tosh_fops = { + .owner = THIS_MODULE, + .ioctl = tosh_ioctl +}; + +static struct miscdevice tosh_device = { + TOSH_MINOR_DEV, + "toshiba", + &tosh_fops +}; + +static void +setup_tosh_info(void __iomem *bios) +{ + int major, minor; + int day, month, year; + + tosh_id = tosh_get_machine_id(); + + /* get the BIOS version */ + major = isa_readb(0xfe009)-'0'; + minor = ((isa_readb(0xfe00b)-'0')*10)+(isa_readb(0xfe00c)-'0'); + tosh_bios = (major*0x100)+minor; + + /* get the BIOS date */ + day = ((isa_readb(0xffff5)-'0')*10)+(isa_readb(0xffff6)-'0'); + month = ((isa_readb(0xffff8)-'0')*10)+(isa_readb(0xffff9)-'0'); + year = ((isa_readb(0xffffb)-'0')*10)+(isa_readb(0xffffc)-'0'); + tosh_date = (((year-90) & 0x1f)<<10) | ((month & 0xf)<<6) + | ((day & 0x1f)<<1); +} + +/* /proc/toshiba read handler */ +static int +tosh_get_info(char* buffer, char** start, off_t fpos, int length) +{ + char* temp = buffer; + /* TODO: tosh_fn_status() */ + int key = 0; + + /* Format: + * 0) Linux driver version (this will change if format changes) + * 1) Machine ID + * 2) SCI version + * 3) BIOS version (major, minor) + * 4) BIOS date (in SCI date format) + * 5) Fn Key status + */ + + temp += sprintf(temp, "1.1 0x%04x %d.%d %d.%d 0x%04x 0x%02x\n", + tosh_id, + (tosh_sci & 0xff00)>>8, + tosh_sci & 0xff, + (tosh_bios & 0xff00)>>8, + tosh_bios & 0xff, + tosh_date, + key); + + return temp-buffer; +} + +static int __init +old_driver_emulation_init(void) +{ + int status; + void __iomem *bios = ioremap(0xf0000, 0x10000); + if (!bios) + return -ENOMEM; + + if ((status = misc_register(&tosh_device))) { + printk(MY_ERR "failed to register misc device %d (\"%s\")\n", + tosh_device.minor, tosh_device.name); + return status; + } + + setup_tosh_info(bios); + create_proc_info_entry(OLD_PROC_TOSHIBA, 0, NULL, tosh_get_info); + + iounmap(bios); + + return 0; +} + +static void __exit +old_driver_emulation_exit(void) +{ + remove_proc_entry(OLD_PROC_TOSHIBA, NULL); + misc_deregister(&tosh_device); +} + +/* }}} end of /dev/toshiba and /proc/toshiba handlers */ + /* proc and module init */ @@ -538,16 +758,151 @@ .update_status = set_lcd_status, }; +static struct semaphore thread_sem; +static int thread_should_die; + +static struct acpi_device *threaded_device = 0; + +static void thread_deliver_button_event(u32 value) +{ + if (!threaded_device) return; + if( value == 0x0100 ) { + /* Ignore FN on its own */ + } else if( value & 0x80 ) { + acpi_bus_generate_proc_event( threaded_device, 1, value & ~0x80 ); + } else { + acpi_bus_generate_proc_event( threaded_device, 0, value ); + } +} + +static int toshiba_acpi_thread(void *data) +{ + int dropped = 0; + u32 hci_result, value; + + daemonize("ktoshkeyd"); + set_user_nice(current, 4); + thread_should_die = 0; + + up(&thread_sem); + + do { + /* In case we get stuck; we can rmmod the module here */ + if (thread_should_die) + break; + + hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result); + if (hci_result == HCI_SUCCESS) { + dropped++; + } else if (hci_result == HCI_EMPTY) { + /* better luck next time */ + } else if (hci_result == HCI_NOT_SUPPORTED) { + /* This is a workaround for an unresolved issue on + * some machines where system events sporadically + * become disabled. */ + hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); + printk(MY_NOTICE "Re-enabled hotkeys\n"); + } + } while (hci_result != HCI_EMPTY); + + printk(MY_INFO "Dropped %d keys from the queue on startup\n", dropped); + + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / hotkeys_check_per_sec); + + if (thread_should_die) + break; + + if (try_to_freeze()) + continue; + + do { + hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result); + if (hci_result == HCI_SUCCESS) { + thread_deliver_button_event(value); + } else if (hci_result == HCI_EMPTY) { + /* better luck next time */ + } else if (hci_result == HCI_NOT_SUPPORTED) { + /* This is a workaround for an + * unresolved issue on some machines + * where system events sporadically + * become disabled. */ + hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); + printk(MY_NOTICE "Re-enabled hotkeys\n"); + } + } while (hci_result == HCI_SUCCESS); + } + set_user_nice(current, -20); /* Become nasty so we are cleaned up + * before the module exits making us oops */ + up(&thread_sem); + return 0; +} + +static int acpi_toshkeys_add (struct acpi_device *device) +{ + threaded_device = device; + strcpy(acpi_device_name(device), "Toshiba laptop hotkeys"); + strcpy(acpi_device_class(device), "hkey"); + return 0; +} + +static int acpi_toshkeys_remove (struct acpi_device *device, int type) +{ + if (threaded_device == device) + threaded_device = 0; + return 0; +} + +static const struct acpi_device_id acpi_toshkeys_ids[] = { + { "TOS6200", 0 }, + { "TOS6207", 0 }, + { "TOS6208", 0 }, + {"", 0} +}; + +static struct acpi_driver acpi_threaded_toshkeys = { + .name = "Toshiba laptop hotkeys driver", + .class = "hkey", + .ids = acpi_toshkeys_ids, + .ops = { + .add = acpi_toshkeys_add, + .remove = acpi_toshkeys_remove, + }, +}; + +static int __init init_threaded_acpi(void) +{ + acpi_status result = AE_OK; + result = acpi_bus_register_driver(&acpi_threaded_toshkeys); + if( result < 0 ) + printk(MY_ERR "Registration of toshkeys acpi device failed\n"); + return result; +} + +static void kill_threaded_acpi(void) +{ + acpi_bus_unregister_driver(&acpi_threaded_toshkeys); +} + static void toshiba_acpi_exit(void) { if (toshiba_backlight_device) backlight_device_unregister(toshiba_backlight_device); + if (hotkeys_over_acpi) { + thread_should_die = 1; + down(&thread_sem); + kill_threaded_acpi(); + } + remove_device(); if (toshiba_proc_dir) remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); + old_driver_emulation_exit(); + return; } @@ -555,6 +910,7 @@ { acpi_status status = AE_OK; u32 hci_result; + int status2; if (acpi_disabled) return -ENODEV; @@ -571,6 +927,9 @@ TOSHIBA_ACPI_VERSION); printk(MY_INFO " HCI method: %s\n", method_hci); + if ((status2 = old_driver_emulation_init())) + return status2; + force_fan = 0; key_event_valid = 0; @@ -598,7 +957,27 @@ toshiba_acpi_exit(); return ret; } - toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; + toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; + + if (hotkeys_over_acpi && ACPI_SUCCESS(status)) { + printk(MY_INFO "Toshiba hotkeys are sent as ACPI events\n"); + if (hotkeys_check_per_sec < 1) + hotkeys_check_per_sec = 1; + if (hotkeys_check_per_sec > 10) + hotkeys_check_per_sec = 10; + printk(MY_INFO "ktoshkeyd will check %d time%s per second\n", + hotkeys_check_per_sec, hotkeys_check_per_sec==1?"":"s"); + if (init_threaded_acpi() >= 0) { + init_MUTEX_LOCKED(&thread_sem); + kernel_thread(toshiba_acpi_thread, NULL, CLONE_KERNEL); + down(&thread_sem); + } else { + remove_device(); + remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); + status = AE_ERROR; + printk(MY_INFO "ktoshkeyd initialisation failed. Refusing to load module\n"); + } + } return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; } --- linux-2.6.24.orig/drivers/acpi/utilities/utobject.c +++ linux-2.6.24/drivers/acpi/utilities/utobject.c @@ -432,7 +432,7 @@ * element -- which is legal) */ if (!internal_object) { - *obj_length = 0; + *obj_length = sizeof(union acpi_object); return_ACPI_STATUS(AE_OK); } --- linux-2.6.24.orig/drivers/acpi/Kconfig +++ linux-2.6.24/drivers/acpi/Kconfig @@ -274,6 +274,23 @@ Enter the full path name to the file which includes the AmlCode declaration. +config ACPI_CUSTOM_DSDT_INITRD + bool "Read Custom DSDT from initramfs" + depends on BLK_DEV_INITRD + default y + help + The DSDT (Differentiated System Description Table) often needs to be + overridden because of broken BIOS implementations. If this feature is + activated you will be able to provide a customized DSDT by adding it + to your initramfs. For now you need to use a special mkinitrd tool. + For more details see or + . If there is no table found, it + will fallback to the custom DSDT in-kernel (if activated) or to the + DSDT from the BIOS. + + Even if you do not need a new one at the moment, you may want to use a + better implemented DSDT later. It is safe to say Y here. + config ACPI_BLACKLIST_YEAR int "Disable ACPI for systems before Jan 1st this year" if X86_32 default 0 --- linux-2.6.24.orig/drivers/acpi/processor_core.c +++ linux-2.6.24/drivers/acpi/processor_core.c @@ -622,7 +622,7 @@ int result = 0; acpi_status status = AE_OK; struct acpi_processor *pr; - + struct sys_device *sysdev; pr = acpi_driver_data(device); @@ -653,6 +653,11 @@ if (result) goto end; + sysdev = get_cpu_sysdev(pr->id); + if (sysdev && + sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) + return -EFAULT; + status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, acpi_processor_notify, pr); @@ -789,10 +794,13 @@ status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, acpi_processor_notify); + if (get_cpu_sysdev(pr->id)) + sysfs_remove_link(&device->dev.kobj, "sysdev"); + acpi_processor_remove_fs(device); processors[pr->id] = NULL; - + processor_device_array[pr->id] = NULL; kfree(pr); return 0; @@ -978,9 +986,9 @@ static int acpi_processor_handle_eject(struct acpi_processor *pr) { - if (cpu_online(pr->id)) { - return (-EINVAL); - } + if (cpu_online(pr->id)) + cpu_down(pr->id); + arch_unregister_cpu(pr->id); acpi_unmap_lsapic(pr->id); return (0); --- linux-2.6.24.orig/drivers/acpi/bus.c +++ linux-2.6.24/drivers/acpi/bus.c @@ -49,6 +49,23 @@ #define STRUCT_TO_INT(s) (*((int*)&s)) +static int set_power_nocheck(const struct dmi_system_id *id) +{ + printk(KERN_NOTICE PREFIX "%s detected - " + "disable power check in power transistion\n", id->ident); + acpi_power_nocheck = 1; + return 0; +} +static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = { + { + set_power_nocheck, "HP Pavilion 05", { + DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), + DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"), + DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL}, + {}, +}; + + /* -------------------------------------------------------------------------- Device Management -------------------------------------------------------------------------- */ @@ -199,7 +216,19 @@ /* * Get device's current power state */ - acpi_bus_get_power(device->handle, &device->power.state); + if (!acpi_power_nocheck) { + /* + * Maybe the incorrect power state is returned on the bogus + * bios, which is different with the real power state. + * For example: the bios returns D0 state and the real power + * state is D3. OS expects to set the device to D0 state. In + * such case if OS uses the power state returned by the BIOS, + * the device can't be transisted to the correct power state. + * So if the acpi_power_nocheck is set, it is unnecessary to + * get the power state by calling acpi_bus_get_power. + */ + acpi_bus_get_power(device->handle, &device->power.state); + } if ((state == device->power.state) && !device->flags.force_power_state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state)); @@ -350,10 +379,11 @@ } spin_lock_irqsave(&acpi_bus_event_lock, flags); - entry = - list_entry(acpi_bus_event_list.next, struct acpi_bus_event, node); - if (entry) + if (!list_empty(&acpi_bus_event_list)) { + entry = list_entry(acpi_bus_event_list.next, + struct acpi_bus_event, node); list_del(&entry->node); + } spin_unlock_irqrestore(&acpi_bus_event_lock, flags); if (!entry) @@ -773,7 +803,11 @@ } } else disable_acpi(); - + /* + * If the laptop falls into the DMI check table, the power state check + * will be disabled in the course of device power transistion. + */ + dmi_check_system(power_nocheck_dmi_table); return result; } --- linux-2.6.24.orig/drivers/acpi/hardware/hwsleep.c +++ linux-2.6.24/drivers/acpi/hardware/hwsleep.c @@ -587,6 +587,13 @@ } /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */ + /* + * Some BIOSes assume that WAK_STS will be cleared on resume and use + * it to determine whether the system is rebooting or resuming. Clear + * it for compatibility. + */ + acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1); + acpi_gbl_system_awake_and_running = TRUE; /* Enable power button */ --- linux-2.6.24.orig/drivers/acpi/processor_idle.c +++ linux-2.6.24/drivers/acpi/processor_idle.c @@ -125,52 +125,7 @@ static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = { { set_max_cstate, "IBM ThinkPad R40e", { DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET70WW")}, (void *)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW")}, (void *)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET43WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET45WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET47WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET50WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET52WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET55WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET56WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET59WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET61WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET62WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET64WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET65WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET68WW") }, (void*)1}, + DMI_MATCH(DMI_BIOS_VERSION,"1SET")}, (void *)1}, { set_max_cstate, "Medion 41700", { DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), DMI_MATCH(DMI_BIOS_VERSION,"R01-A1J")}, (void *)1}, @@ -1249,6 +1204,8 @@ { int result = 0; + if (boot_option_idle_override) + return 0; if (!pr) return -EINVAL; @@ -1593,6 +1550,7 @@ return -EINVAL; } + dev->cpu = pr->id; for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { cx = &pr->power.states[i]; state = &dev->states[count]; @@ -1651,7 +1609,10 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) { - int ret; + int ret = 0; + + if (boot_option_idle_override) + return 0; if (!pr) return -EINVAL; @@ -1666,8 +1627,11 @@ cpuidle_pause_and_lock(); cpuidle_disable_device(&pr->power.dev); acpi_processor_get_power_info(pr); - acpi_processor_setup_cpuidle(pr); - ret = cpuidle_enable_device(&pr->power.dev); + if (pr->flags.power) { + acpi_processor_setup_cpuidle(pr); + ret = cpuidle_enable_device(&pr->power.dev); + } + cpuidle_resume_and_unlock(); return ret; @@ -1683,6 +1647,8 @@ struct proc_dir_entry *entry = NULL; unsigned int i; + if (boot_option_idle_override) + return 0; if (!first_run) { dmi_check_system(processor_power_dmi_table); @@ -1717,10 +1683,9 @@ * Note that we use previously set idle handler will be used on * platforms that only support C1. */ - if ((pr->flags.power) && (!boot_option_idle_override)) { + if (pr->flags.power) { #ifdef CONFIG_CPU_IDLE acpi_processor_setup_cpuidle(pr); - pr->power.dev.cpu = pr->id; if (cpuidle_register_device(&pr->power.dev)) return -EIO; #endif @@ -1757,9 +1722,11 @@ int acpi_processor_power_exit(struct acpi_processor *pr, struct acpi_device *device) { + if (boot_option_idle_override) + return 0; + #ifdef CONFIG_CPU_IDLE - if ((pr->flags.power) && (!boot_option_idle_override)) - cpuidle_unregister_device(&pr->power.dev); + cpuidle_unregister_device(&pr->power.dev); #endif pr->flags.power_setup_done = 0; --- linux-2.6.24.orig/drivers/acpi/power.c +++ linux-2.6.24/drivers/acpi/power.c @@ -54,6 +54,14 @@ #define ACPI_POWER_RESOURCE_STATE_OFF 0x00 #define ACPI_POWER_RESOURCE_STATE_ON 0x01 #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF + +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "acpi." +int acpi_power_nocheck; +module_param_named(power_nocheck, acpi_power_nocheck, bool, 000); + static int acpi_power_add(struct acpi_device *device); static int acpi_power_remove(struct acpi_device *device, int type); static int acpi_power_resume(struct acpi_device *device); @@ -225,11 +233,17 @@ if (ACPI_FAILURE(status)) return -ENODEV; - result = acpi_power_get_state(resource, &state); - if (result) - return result; - if (state != ACPI_POWER_RESOURCE_STATE_ON) - return -ENOEXEC; + if (!acpi_power_nocheck) { + /* + * If acpi_power_nocheck is set, it is unnecessary to check + * the power state after power transition. + */ + result = acpi_power_get_state(resource, &state); + if (result) + return result; + if (state != ACPI_POWER_RESOURCE_STATE_ON) + return -ENOEXEC; + } /* Update the power resource's _device_ power state */ resource->device->power.state = ACPI_STATE_D0; @@ -276,11 +290,17 @@ if (ACPI_FAILURE(status)) return -ENODEV; - result = acpi_power_get_state(resource, &state); - if (result) - return result; - if (state != ACPI_POWER_RESOURCE_STATE_OFF) - return -ENOEXEC; + if (!acpi_power_nocheck) { + /* + * If acpi_power_nocheck is set, it is unnecessary to check + * the power state after power transition. + */ + result = acpi_power_get_state(resource, &state); + if (result) + return result; + if (state != ACPI_POWER_RESOURCE_STATE_OFF) + return -ENOEXEC; + } /* Update the power resource's _device_ power state */ resource->device->power.state = ACPI_STATE_D3; --- linux-2.6.24.orig/drivers/acpi/reboot.c +++ linux-2.6.24/drivers/acpi/reboot.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +/* + * Some systems the have been proved to be able to reboot this way (even if + * some fail to claim this in the FADT). + */ +static struct dmi_system_id reboot_dmi_whitelist[] = { + { + .ident = "ASUS M6NE", + .matches = { + DMI_MATCH(DMI_BIOS_VERSION,"0208"), + DMI_MATCH(DMI_PRODUCT_NAME,"M6Ne"), + }, + }, + { + .ident = "Intel powered classmate PC", + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, + "Intel powered classmate PC"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Gen 1.5"), + }, + }, + {} +}; + +void acpi_reboot(void) +{ + struct acpi_generic_address *rr; + struct pci_bus *bus0; + u8 reset_value; + unsigned int devfn; + + if (acpi_disabled) + return; + + rr = &acpi_gbl_FADT.reset_register; + + /* + * For those systems that have not been whitelisted, check the ACPI + * flags and the register layout. + */ + if (!dmi_check_system(reboot_dmi_whitelist)) { + /* Is the reset register supported? */ + if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER)) + return; + /* Is the width and ofset as specified? */ + if (rr->bit_width != 8 || rr->bit_offset != 0) + return; + } + + reset_value = acpi_gbl_FADT.reset_value; + + /* The reset register can only exist in I/O, Memory or PCI config space + * on a device on bus 0. */ + switch (rr->space_id) { + case ACPI_ADR_SPACE_PCI_CONFIG: + /* The reset register can only live on bus 0. */ + bus0 = pci_find_bus(0, 0); + if (!bus0) + return; + /* Form PCI device/function pair. */ + devfn = PCI_DEVFN((rr->address >> 32) & 0xffff, + (rr->address >> 16) & 0xffff); + printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG."); + /* Write the value that resets us. */ + pci_bus_write_config_byte(bus0, devfn, + (rr->address & 0xffff), reset_value); + break; + + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + case ACPI_ADR_SPACE_SYSTEM_IO: + printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n"); + acpi_hw_low_level_write(8, reset_value, rr); + break; + } + /* Wait ten seconds */ + acpi_os_stall(10000000); +} --- linux-2.6.24.orig/drivers/acpi/ec.c +++ linux-2.6.24/drivers/acpi/ec.c @@ -573,7 +573,7 @@ void *handler_context, void *region_context) { struct acpi_ec *ec = handler_context; - int result = 0, i = 0; + int result = 0, i; u8 temp = 0; if ((address > 0xFF) || !value || !handler_context) @@ -585,7 +585,18 @@ if (bits != 8 && acpi_strict) return AE_BAD_PARAMETER; - while (bits - i > 0) { + acpi_ec_burst_enable(ec); + + if (function == ACPI_READ) { + result = acpi_ec_read(ec, address, &temp); + *value = temp; + } else { + temp = 0xff & (*value); + result = acpi_ec_write(ec, address, temp); + } + + for (i = 8; unlikely(bits - i > 0); i += 8) { + ++address; if (function == ACPI_READ) { result = acpi_ec_read(ec, address, &temp); (*value) |= ((acpi_integer)temp) << i; @@ -593,10 +604,10 @@ temp = 0xff & ((*value) >> i); result = acpi_ec_write(ec, address, temp); } - i += 8; - ++address; } + acpi_ec_burst_disable(ec); + switch (result) { case -EINVAL: return AE_BAD_PARAMETER; --- linux-2.6.24.orig/drivers/acpi/Makefile +++ linux-2.6.24/drivers/acpi/Makefile @@ -21,7 +21,7 @@ # # ACPI Core Subsystem (Interpreter) # -obj-y += osl.o utils.o \ +obj-y += osl.o utils.o reboot.o\ dispatcher/ events/ executer/ hardware/ \ namespace/ parser/ resources/ tables/ \ utilities/ --- linux-2.6.24.orig/drivers/Kconfig +++ linux-2.6.24/drivers/Kconfig @@ -90,9 +90,5 @@ source "drivers/auxdisplay/Kconfig" -source "drivers/kvm/Kconfig" - source "drivers/uio/Kconfig" - -source "drivers/virtio/Kconfig" endmenu --- linux-2.6.24.orig/drivers/macintosh/mediabay.c +++ linux-2.6.24/drivers/macintosh/mediabay.c @@ -447,6 +447,7 @@ return -ENODEV; } +EXPORT_SYMBOL(check_media_bay_by_base); int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, int irq, int index) @@ -487,6 +488,7 @@ return -ENODEV; } +EXPORT_SYMBOL(media_bay_set_ide_infos); static void media_bay_step(int i) { @@ -709,7 +711,8 @@ { struct media_bay_info *bay = macio_get_drvdata(mdev); - if (state.event != mdev->ofdev.dev.power.power_state.event && state.event == PM_EVENT_SUSPEND) { + if (state.event != mdev->ofdev.dev.power.power_state.event + && (state.event & PM_EVENT_SLEEP)) { down(&bay->lock); bay->sleeping = 1; set_mb_power(bay, 0); --- linux-2.6.24.orig/drivers/macintosh/smu.c +++ linux-2.6.24/drivers/macintosh/smu.c @@ -85,6 +85,7 @@ u32 cmd_buf_abs; /* command buffer absolute */ struct list_head cmd_list; struct smu_cmd *cmd_cur; /* pending command */ + int broken_nap; struct list_head cmd_i2c_list; struct smu_i2c_cmd *cmd_i2c_cur; /* pending i2c command */ struct timer_list i2c_timer; @@ -135,6 +136,19 @@ fend = faddr + smu->cmd_buf->length + 2; flush_inval_dcache_range(faddr, fend); + + /* We also disable NAP mode for the duration of the command + * on U3 based machines. + * This is slightly racy as it can be written back to 1 by a sysctl + * but that never happens in practice. There seem to be an issue with + * U3 based machines such as the iMac G5 where napping for the + * whole duration of the command prevents the SMU from fetching it + * from memory. This might be related to the strange i2c based + * mechanism the SMU uses to access memory. + */ + if (smu->broken_nap) + powersave_nap = 0; + /* This isn't exactly a DMA mapping here, I suspect * the SMU is actually communicating with us via i2c to the * northbridge or the CPU to access RAM. @@ -211,6 +225,10 @@ misc = cmd->misc; mb(); cmd->status = rc; + + /* Re-enable NAP mode */ + if (smu->broken_nap) + powersave_nap = 1; bail: /* Start next command if any */ smu_start_cmd(); @@ -461,7 +479,7 @@ if (np == NULL) return -ENODEV; - printk(KERN_INFO "SMU driver %s %s\n", VERSION, AUTHOR); + printk(KERN_INFO "SMU: Driver %s %s\n", VERSION, AUTHOR); if (smu_cmdbuf_abs == 0) { printk(KERN_ERR "SMU: Command buffer not allocated !\n"); @@ -533,6 +551,11 @@ goto fail; } + /* U3 has an issue with NAP mode when issuing SMU commands */ + smu->broken_nap = pmac_get_uninorth_variant() < 4; + if (smu->broken_nap) + printk(KERN_INFO "SMU: using NAP mode workaround\n"); + sys_ctrler = SYS_CTRLER_SMU; return 0; --- linux-2.6.24.orig/drivers/macintosh/via-pmu.c +++ linux-2.6.24/drivers/macintosh/via-pmu.c @@ -2842,7 +2842,7 @@ EXPORT_SYMBOL(pmu_suspend); EXPORT_SYMBOL(pmu_resume); EXPORT_SYMBOL(pmu_unlock); -#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) +#if defined(CONFIG_PPC32) EXPORT_SYMBOL(pmu_enable_irled); EXPORT_SYMBOL(pmu_battery_count); EXPORT_SYMBOL(pmu_batteries); --- linux-2.6.24.orig/drivers/usb/gadget/ether.c +++ linux-2.6.24/drivers/usb/gadget/ether.c @@ -1561,6 +1561,7 @@ memcpy(req->buf, buf, n); req->complete = rndis_response_complete; rndis_free_response(dev->rndis_config, buf); + value = n; } /* else stalls ... spec says to avoid that */ } --- linux-2.6.24.orig/drivers/usb/host/ohci-hcd.c +++ linux-2.6.24/drivers/usb/host/ohci-hcd.c @@ -85,6 +85,21 @@ static int ohci_restart (struct ohci_hcd *ohci); #endif +#ifdef CONFIG_PCI +static void quirk_amd_pll(int state); +static void amd_iso_dev_put(void); +#else +static inline void quirk_amd_pll(int state) +{ + return; +} +static inline void amd_iso_dev_put(void) +{ + return; +} +#endif + + #include "ohci-hub.c" #include "ohci-dbg.c" #include "ohci-mem.c" @@ -885,6 +900,8 @@ if (quirk_zfmicro(ohci)) del_timer(&ohci->unlink_watchdog); + if (quirk_amdiso(ohci)) + amd_iso_dev_put(); remove_debug_files (ohci); ohci_mem_cleanup (ohci); --- linux-2.6.24.orig/drivers/usb/host/ehci-dbg.c +++ linux-2.6.24/drivers/usb/host/ehci-dbg.c @@ -763,9 +763,7 @@ } if (ehci->reclaim) { - temp = scnprintf (next, size, "reclaim qh %p%s\n", - ehci->reclaim, - ehci->reclaim_ready ? " ready" : ""); + temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim); size -= temp; next += temp; } --- linux-2.6.24.orig/drivers/usb/host/ohci-pci.c +++ linux-2.6.24/drivers/usb/host/ohci-pci.c @@ -18,6 +18,28 @@ #error "This file is PCI bus glue. CONFIG_PCI must be defined." #endif +#include +#include + + +/* constants used to work around PM-related transfer + * glitches in some AMD 700 series southbridges + */ +#define AB_REG_BAR 0xf0 +#define AB_INDX(addr) ((addr) + 0x00) +#define AB_DATA(addr) ((addr) + 0x04) +#define AX_INDXC 0X30 +#define AX_DATAC 0x34 + +#define NB_PCIE_INDX_ADDR 0xe0 +#define NB_PCIE_INDX_DATA 0xe4 +#define PCIE_P_CNTL 0x10040 +#define BIF_NB 0x10002 + +static struct pci_dev *amd_smbus_dev; +static struct pci_dev *amd_hb_dev; +static int amd_ohci_iso_count; + /*-------------------------------------------------------------------------*/ static int broken_suspend(struct usb_hcd *hcd) @@ -143,6 +165,103 @@ return 0; } +static int ohci_quirk_amd700(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + u8 rev = 0; + + if (!amd_smbus_dev) + amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, + PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); + if (!amd_smbus_dev) + return 0; + + pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev); + if ((rev > 0x3b) || (rev < 0x30)) { + pci_dev_put(amd_smbus_dev); + amd_smbus_dev = NULL; + return 0; + } + + amd_ohci_iso_count++; + + if (!amd_hb_dev) + amd_hb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9600, NULL); + + ohci->flags |= OHCI_QUIRK_AMD_ISO; + ohci_dbg(ohci, "enabled AMD ISO transfers quirk\n"); + + return 0; +} + +/* + * The hardware normally enables the A-link power management feature, which + * lets the system lower the power consumption in idle states. + * + * Assume the system is configured to have USB 1.1 ISO transfers going + * to or from a USB device. Without this quirk, that stream may stutter + * or have breaks occasionally. For transfers going to speakers, this + * makes a very audible mess... + * + * That audio playback corruption is due to the audio stream getting + * interrupted occasionally when the link goes in lower power state + * This USB quirk prevents the link going into that lower power state + * during audio playback or other ISO operations. + */ +static void quirk_amd_pll(int on) +{ + u32 addr; + u32 val; + u32 bit = (on > 0) ? 1 : 0; + + pci_read_config_dword(amd_smbus_dev, AB_REG_BAR, &addr); + + /* BIT names/meanings are NDA-protected, sorry ... */ + + outl(AX_INDXC, AB_INDX(addr)); + outl(0x40, AB_DATA(addr)); + outl(AX_DATAC, AB_INDX(addr)); + val = inl(AB_DATA(addr)); + val &= ~((1 << 3) | (1 << 4) | (1 << 9)); + val |= (bit << 3) | ((!bit) << 4) | ((!bit) << 9); + outl(val, AB_DATA(addr)); + + if (amd_hb_dev) { + addr = PCIE_P_CNTL; + pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_ADDR, addr); + + pci_read_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, &val); + val &= ~(1 | (1 << 3) | (1 << 4) | (1 << 9) | (1 << 12)); + val |= bit | (bit << 3) | (bit << 12); + val |= ((!bit) << 4) | ((!bit) << 9); + pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, val); + + addr = BIF_NB; + pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_ADDR, addr); + + pci_read_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, &val); + val &= ~(1 << 8); + val |= bit << 8; + pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, val); + } +} + +static void amd_iso_dev_put(void) +{ + amd_ohci_iso_count--; + if (amd_ohci_iso_count == 0) { + if (amd_smbus_dev) { + pci_dev_put(amd_smbus_dev); + amd_smbus_dev = NULL; + } + if (amd_hb_dev) { + pci_dev_put(amd_hb_dev); + amd_hb_dev = NULL; + } + } + +} + /* List of quirks for OHCI */ static const struct pci_device_id ohci_pci_quirks[] = { { @@ -181,6 +300,19 @@ PCI_DEVICE(PCI_VENDOR_ID_ITE, 0x8152), .driver_data = (unsigned long) broken_suspend, }, + { + PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4397), + .driver_data = (unsigned long)ohci_quirk_amd700, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4398), + .driver_data = (unsigned long)ohci_quirk_amd700, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), + .driver_data = (unsigned long)ohci_quirk_amd700, + }, + /* FIXME for some of the early AMD 760 southbridges, OHCI * won't work at all. blacklist them. */ --- linux-2.6.24.orig/drivers/usb/host/ohci-q.c +++ linux-2.6.24/drivers/usb/host/ohci-q.c @@ -49,6 +49,9 @@ switch (usb_pipetype (urb->pipe)) { case PIPE_ISOCHRONOUS: ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--; + if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0 + && quirk_amdiso(ohci)) + quirk_amd_pll(1); break; case PIPE_INTERRUPT: ohci_to_hcd(ohci)->self.bandwidth_int_reqs--; @@ -680,6 +683,9 @@ data + urb->iso_frame_desc [cnt].offset, urb->iso_frame_desc [cnt].length, urb, cnt); } + if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0 + && quirk_amdiso(ohci)) + quirk_amd_pll(0); periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0 && ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0; break; --- linux-2.6.24.orig/drivers/usb/host/ehci-pci.c +++ linux-2.6.24/drivers/usb/host/ehci-pci.c @@ -305,7 +305,7 @@ /* emptying the schedule aborts any urbs */ spin_lock_irq(&ehci->lock); if (ehci->reclaim) - ehci->reclaim_ready = 1; + end_unlink_async(ehci); ehci_work(ehci); spin_unlock_irq(&ehci->lock); --- linux-2.6.24.orig/drivers/usb/host/sl811-hcd.c +++ linux-2.6.24/drivers/usb/host/sl811-hcd.c @@ -1766,6 +1766,7 @@ retval = sl811h_bus_suspend(hcd); break; case PM_EVENT_SUSPEND: + case PM_EVENT_HIBERNATE: case PM_EVENT_PRETHAW: /* explicitly discard hw state */ port_power(sl811, 0); break; --- linux-2.6.24.orig/drivers/usb/host/ehci-q.c +++ linux-2.6.24/drivers/usb/host/ehci-q.c @@ -315,10 +315,10 @@ if (likely (last->urb != urb)) { ehci_urb_done(ehci, last->urb, last_status); count++; + last_status = -EINPROGRESS; } ehci_qtd_free (ehci, last); last = NULL; - last_status = -EINPROGRESS; } /* ignore urbs submitted during completions we reported */ @@ -973,7 +973,7 @@ struct ehci_qh *qh = ehci->reclaim; struct ehci_qh *next; - timer_action_done (ehci, TIMER_IAA_WATCHDOG); + iaa_watchdog_done(ehci); // qh->hw_next = cpu_to_hc32(qh->qh_dma); qh->qh_state = QH_STATE_IDLE; @@ -983,7 +983,6 @@ /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ next = qh->reclaim; ehci->reclaim = next; - ehci->reclaim_ready = 0; qh->reclaim = NULL; qh_completions (ehci, qh); @@ -1059,11 +1058,10 @@ return; } - ehci->reclaim_ready = 0; cmd |= CMD_IAAD; ehci_writel(ehci, cmd, &ehci->regs->command); (void)ehci_readl(ehci, &ehci->regs->command); - timer_action (ehci, TIMER_IAA_WATCHDOG); + iaa_watchdog_start(ehci); } /*-------------------------------------------------------------------------*/ --- linux-2.6.24.orig/drivers/usb/host/u132-hcd.c +++ linux-2.6.24/drivers/usb/host/u132-hcd.c @@ -3213,15 +3213,20 @@ dev_err(&u132->platform_dev->dev, "device is being removed\n"); return -ESHUTDOWN; } else { - int retval = 0; - if (state.event == PM_EVENT_FREEZE) { + int retval = 0, ports; + + switch (state.event) { + case PM_EVENT_FREEZE: retval = u132_bus_suspend(hcd); - } else if (state.event == PM_EVENT_SUSPEND) { - int ports = MAX_U132_PORTS; + break; + case PM_EVENT_SUSPEND: + case PM_EVENT_HIBERNATE: + ports = MAX_U132_PORTS; while (ports-- > 0) { port_power(u132, ports, 0); } - } + break; + } if (retval == 0) pdev->dev.power.power_state = state; return retval; --- linux-2.6.24.orig/drivers/usb/host/ehci-hub.c +++ linux-2.6.24/drivers/usb/host/ehci-hub.c @@ -123,6 +123,8 @@ if (time_before (jiffies, ehci->next_statechange)) msleep(5); + del_timer_sync(&ehci->watchdog); + del_timer_sync(&ehci->iaa_watchdog); port = HCS_N_PORTS (ehci->hcs_params); spin_lock_irq (&ehci->lock); @@ -134,7 +136,7 @@ } ehci->command = ehci_readl(ehci, &ehci->regs->command); if (ehci->reclaim) - ehci->reclaim_ready = 1; + end_unlink_async(ehci); ehci_work(ehci); /* Unlike other USB host controller types, EHCI doesn't have @@ -171,7 +173,6 @@ } /* turn off now-idle HC */ - del_timer_sync (&ehci->watchdog); ehci_halt (ehci); hcd->state = HC_STATE_SUSPENDED; @@ -606,7 +607,7 @@ } break; case USB_PORT_FEAT_C_SUSPEND: - /* we auto-clear this feature */ + clear_bit(wIndex, &ehci->port_c_suspend); break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) @@ -685,7 +686,7 @@ /* resume completed? */ else if (time_after_eq(jiffies, ehci->reset_done[wIndex])) { - status |= 1 << USB_PORT_FEAT_C_SUSPEND; + set_bit(wIndex, &ehci->port_c_suspend); ehci->reset_done[wIndex] = 0; /* stop resume signaling */ @@ -762,6 +763,8 @@ status |= 1 << USB_PORT_FEAT_RESET; if (temp & PORT_POWER) status |= 1 << USB_PORT_FEAT_POWER; + if (test_bit(wIndex, &ehci->port_c_suspend)) + status |= 1 << USB_PORT_FEAT_C_SUSPEND; #ifndef EHCI_VERBOSE_DEBUG if (status & ~0xffff) /* only if wPortChange is interesting */ --- linux-2.6.24.orig/drivers/usb/host/ehci.h +++ linux-2.6.24/drivers/usb/host/ehci.h @@ -74,7 +74,6 @@ /* async schedule support */ struct ehci_qh *async; struct ehci_qh *reclaim; - unsigned reclaim_ready : 1; unsigned scanning : 1; /* periodic schedule support */ @@ -98,6 +97,8 @@ dedicated to the companion controller */ unsigned long owned_ports; /* which ports are owned by the companion during a bus suspend */ + unsigned long port_c_suspend; /* which ports have + the change-suspend feature turned on */ /* per-HC memory pools (could be per-bus, but ...) */ struct dma_pool *qh_pool; /* qh per active urb */ @@ -105,6 +106,7 @@ struct dma_pool *itd_pool; /* itd per iso urb */ struct dma_pool *sitd_pool; /* sitd per split iso urb */ + struct timer_list iaa_watchdog; struct timer_list watchdog; unsigned long actions; unsigned stamp; @@ -140,9 +142,21 @@ } +static inline void +iaa_watchdog_start(struct ehci_hcd *ehci) +{ + WARN_ON(timer_pending(&ehci->iaa_watchdog)); + mod_timer(&ehci->iaa_watchdog, + jiffies + msecs_to_jiffies(EHCI_IAA_MSECS)); +} + +static inline void iaa_watchdog_done(struct ehci_hcd *ehci) +{ + del_timer(&ehci->iaa_watchdog); +} + enum ehci_timer_action { TIMER_IO_WATCHDOG, - TIMER_IAA_WATCHDOG, TIMER_ASYNC_SHRINK, TIMER_ASYNC_OFF, }; @@ -160,9 +174,6 @@ unsigned long t; switch (action) { - case TIMER_IAA_WATCHDOG: - t = EHCI_IAA_JIFFIES; - break; case TIMER_IO_WATCHDOG: t = EHCI_IO_JIFFIES; break; @@ -179,8 +190,7 @@ // async queue SHRINK often precedes IAA. while it's ready // to go OFF neither can matter, and afterwards the IO // watchdog stops unless there's still periodic traffic. - if (action != TIMER_IAA_WATCHDOG - && t > ehci->watchdog.expires + if (time_before_eq(t, ehci->watchdog.expires) && timer_pending (&ehci->watchdog)) return; mod_timer (&ehci->watchdog, t); --- linux-2.6.24.orig/drivers/usb/host/ohci.h +++ linux-2.6.24/drivers/usb/host/ohci.h @@ -399,6 +399,8 @@ #define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ #define OHCI_QUIRK_NEC 0x40 /* lost interrupts */ #define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */ +#define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ +#define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/ // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ @@ -419,6 +421,10 @@ { return ohci->flags & OHCI_QUIRK_ZFMICRO; } +static inline int quirk_amdiso(struct ohci_hcd *ohci) +{ + return ohci->flags & OHCI_QUIRK_AMD_ISO; +} #else static inline int quirk_nec(struct ohci_hcd *ohci) { @@ -428,6 +434,10 @@ { return 0; } +static inline int quirk_amdiso(struct ohci_hcd *ohci) +{ + return 0; +} #endif /* convert between an hcd pointer and the corresponding ohci_hcd */ --- linux-2.6.24.orig/drivers/usb/host/ehci-hcd.c +++ linux-2.6.24/drivers/usb/host/ehci-hcd.c @@ -109,7 +109,7 @@ #define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ -#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ +#define EHCI_IAA_MSECS 10 /* arbitrary */ #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ @@ -266,6 +266,7 @@ /*-------------------------------------------------------------------------*/ +static void end_unlink_async(struct ehci_hcd *ehci); static void ehci_work(struct ehci_hcd *ehci); #include "ehci-hub.c" @@ -275,25 +276,62 @@ /*-------------------------------------------------------------------------*/ -static void ehci_watchdog (unsigned long param) +static void ehci_iaa_watchdog(unsigned long param) { struct ehci_hcd *ehci = (struct ehci_hcd *) param; unsigned long flags; spin_lock_irqsave (&ehci->lock, flags); - /* lost IAA irqs wedge things badly; seen with a vt8235 */ - if (ehci->reclaim) { - u32 status = ehci_readl(ehci, &ehci->regs->status); - if (status & STS_IAA) { - ehci_vdbg (ehci, "lost IAA\n"); + /* Lost IAA irqs wedge things badly; seen first with a vt8235. + * So we need this watchdog, but must protect it against both + * (a) SMP races against real IAA firing and retriggering, and + * (b) clean HC shutdown, when IAA watchdog was pending. + */ + if (ehci->reclaim + && !timer_pending(&ehci->iaa_watchdog) + && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) { + u32 cmd, status; + + /* If we get here, IAA is *REALLY* late. It's barely + * conceivable that the system is so busy that CMD_IAAD + * is still legitimately set, so let's be sure it's + * clear before we read STS_IAA. (The HC should clear + * CMD_IAAD when it sets STS_IAA.) + */ + cmd = ehci_readl(ehci, &ehci->regs->command); + if (cmd & CMD_IAAD) + ehci_writel(ehci, cmd & ~CMD_IAAD, + &ehci->regs->command); + + /* If IAA is set here it either legitimately triggered + * before we cleared IAAD above (but _way_ late, so we'll + * still count it as lost) ... or a silicon erratum: + * - VIA seems to set IAA without triggering the IRQ; + * - IAAD potentially cleared without setting IAA. + */ + status = ehci_readl(ehci, &ehci->regs->status); + if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { COUNT (ehci->stats.lost_iaa); ehci_writel(ehci, STS_IAA, &ehci->regs->status); - ehci->reclaim_ready = 1; } + + ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", + status, cmd); + end_unlink_async(ehci); } - /* stop async processing after it's idled a bit */ + spin_unlock_irqrestore(&ehci->lock, flags); +} + +static void ehci_watchdog(unsigned long param) +{ + struct ehci_hcd *ehci = (struct ehci_hcd *) param; + unsigned long flags; + + spin_lock_irqsave(&ehci->lock, flags); + + /* stop async processing after it's idled a bit */ if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) start_unlink_async (ehci, ehci->async); @@ -363,8 +401,6 @@ static void ehci_work (struct ehci_hcd *ehci) { timer_action_done (ehci, TIMER_IO_WATCHDOG); - if (ehci->reclaim_ready) - end_unlink_async (ehci); /* another CPU may drop ehci->lock during a schedule scan while * it reports urb completions. this flag guards against bogus @@ -399,6 +435,7 @@ /* no more interrupts ... */ del_timer_sync (&ehci->watchdog); + del_timer_sync(&ehci->iaa_watchdog); spin_lock_irq(&ehci->lock); if (HC_IS_RUNNING (hcd->state)) @@ -447,6 +484,10 @@ ehci->watchdog.function = ehci_watchdog; ehci->watchdog.data = (unsigned long) ehci; + init_timer(&ehci->iaa_watchdog); + ehci->iaa_watchdog.function = ehci_iaa_watchdog; + ehci->iaa_watchdog.data = (unsigned long) ehci; + /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -463,7 +504,6 @@ ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); ehci->reclaim = NULL; - ehci->reclaim_ready = 0; ehci->next_uframe = -1; /* @@ -611,7 +651,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 status, pcd_status = 0; + u32 status, pcd_status = 0, cmd; int bh; spin_lock (&ehci->lock); @@ -632,7 +672,7 @@ /* clear (just) interrupts */ ehci_writel(ehci, status, &ehci->regs->status); - ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */ + cmd = ehci_readl(ehci, &ehci->regs->command); bh = 0; #ifdef EHCI_VERBOSE_DEBUG @@ -653,9 +693,17 @@ /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { - COUNT (ehci->stats.reclaim); - ehci->reclaim_ready = 1; - bh = 1; + /* guard against (alleged) silicon errata */ + if (cmd & CMD_IAAD) { + ehci_writel(ehci, cmd & ~CMD_IAAD, + &ehci->regs->command); + ehci_dbg(ehci, "IAA with IAAD still set?\n"); + } + if (ehci->reclaim) { + COUNT(ehci->stats.reclaim); + end_unlink_async(ehci); + } else + ehci_dbg(ehci, "IAA with nothing to reclaim?\n"); } /* remote wakeup [4.3.1] */ @@ -761,10 +809,16 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - /* if we need to use IAA and it's busy, defer */ - if (qh->qh_state == QH_STATE_LINKED - && ehci->reclaim - && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) { + /* failfast */ + if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim) + end_unlink_async(ehci); + + /* if it's not linked then there's nothing to do */ + if (qh->qh_state != QH_STATE_LINKED) + ; + + /* defer till later if busy */ + else if (ehci->reclaim) { struct ehci_qh *last; for (last = ehci->reclaim; @@ -774,12 +828,8 @@ qh->qh_state = QH_STATE_UNLINK_WAIT; last->reclaim = qh; - /* bypass IAA if the hc can't care */ - } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim) - end_unlink_async (ehci); - - /* something else might have unlinked the qh by now */ - if (qh->qh_state == QH_STATE_LINKED) + /* start IAA cycle */ + } else start_unlink_async (ehci, qh); } @@ -806,7 +856,19 @@ qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; - unlink_async (ehci, qh); + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + unlink_async(ehci, qh); + break; + case QH_STATE_UNLINK: + case QH_STATE_UNLINK_WAIT: + /* already started */ + break; + case QH_STATE_IDLE: + WARN_ON(1); + break; + } break; case PIPE_INTERRUPT: @@ -898,6 +960,7 @@ unlink_async (ehci, qh); /* FALL THROUGH */ case QH_STATE_UNLINK: /* wait for hw to finish? */ + case QH_STATE_UNLINK_WAIT: idle_timeout: spin_unlock_irqrestore (&ehci->lock, flags); schedule_timeout_uninterruptible(1); --- linux-2.6.24.orig/drivers/usb/serial/option.c +++ linux-2.6.24/drivers/usb/serial/option.c @@ -180,6 +180,7 @@ { USB_DEVICE(DELL_VENDOR_ID, 0x8117) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */ { USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */ { USB_DEVICE(DELL_VENDOR_ID, 0x8128) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */ + { USB_DEVICE(DELL_VENDOR_ID, 0x8133) }, /* Dell Wireless 5720 == Novatel EV620 CDMA/EV-DO */ { USB_DEVICE(DELL_VENDOR_ID, 0x8136) }, /* Dell Wireless HSDPA 5520 == Novatel Expedite EU860D */ { USB_DEVICE(DELL_VENDOR_ID, 0x8137) }, /* Dell Wireless HSDPA 5520 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, --- linux-2.6.24.orig/drivers/usb/serial/visor.c +++ linux-2.6.24/drivers/usb/serial/visor.c @@ -191,7 +191,7 @@ .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, - .num_bulk_out = 2, + .num_bulk_out = NUM_DONT_CARE, .num_ports = 2, .open = visor_open, .close = visor_close, --- linux-2.6.24.orig/drivers/usb/serial/airprime.c +++ linux-2.6.24/drivers/usb/serial/airprime.c @@ -18,6 +18,16 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ + { USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */ + { USB_DEVICE(0x0930, 0x1303) }, /* Toshiba (Novatel Wireless) HSDPA for M400 */ + { USB_DEVICE(0x106c, 0x3701) }, /* Audiovox PC5740 */ + { USB_DEVICE(0x106c, 0x3702) }, /* Sprint Pantech PX-500 DGE */ + { USB_DEVICE(0x1410, 0x4100) }, /* Novatel Wireless U727 */ + { USB_DEVICE(0x1410, 0x5100) }, /* Novatel Wireless U727 newer */ + { USB_DEVICE(0x1410, 0x6000) }, /* Novatel Wireless U760 */ + { USB_DEVICE(0x12d1, 0x1003) }, /* Huawei E220 */ + { USB_DEVICE(0x05c6, 0x6000) }, /* Momo design */ + { USB_DEVICE(0xf3d0, 0x0112) }, /* AirPrime 5220 */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); --- linux-2.6.24.orig/drivers/usb/serial/ch341.c +++ linux-2.6.24/drivers/usb/serial/ch341.c @@ -28,6 +28,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x4348, 0x5523) }, + { USB_DEVICE(0x1a86, 0x7523) }, { }, }; MODULE_DEVICE_TABLE(usb, id_table); --- linux-2.6.24.orig/drivers/usb/serial/pl2303.c +++ linux-2.6.24/drivers/usb/serial/pl2303.c @@ -89,6 +89,7 @@ { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, { USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) }, { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, + { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, { } /* Terminating entry */ }; --- linux-2.6.24.orig/drivers/usb/serial/usb-serial.c +++ linux-2.6.24/drivers/usb/serial/usb-serial.c @@ -844,6 +844,7 @@ serial->num_interrupt_in = num_interrupt_in; serial->num_interrupt_out = num_interrupt_out; +#if 0 /* check that the device meets the driver's requirements */ if ((type->num_interrupt_in != NUM_DONT_CARE && type->num_interrupt_in != num_interrupt_in) @@ -857,6 +858,7 @@ kfree(serial); return -EIO; } +#endif /* found all that we need */ dev_info(&interface->dev, "%s converter detected\n", --- linux-2.6.24.orig/drivers/usb/serial/ftdi_sio.c +++ linux-2.6.24/drivers/usb/serial/ftdi_sio.c @@ -310,6 +310,7 @@ }; static int ftdi_olimex_probe (struct usb_serial *serial); +static int ftdi_mtxorb_hack_setup (struct usb_serial *serial); static void ftdi_USB_UIRT_setup (struct ftdi_private *priv); static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv); @@ -317,6 +318,10 @@ .probe = ftdi_olimex_probe, }; +static struct ftdi_sio_quirk ftdi_mtxorb_hack_quirk = { + .probe = ftdi_mtxorb_hack_setup, +}; + static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { .port_probe = ftdi_USB_UIRT_setup, }; @@ -379,6 +384,8 @@ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, + { USB_DEVICE(MTXORB_VK_VID, MTXORB_VK_PID), + .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, @@ -492,6 +499,7 @@ { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, @@ -1301,6 +1309,23 @@ return 0; } +/* + * The Matrix Orbital VK204-25-USB has an invalid IN endpoint. + * We have to correct it if we want to read from it. + */ +static int ftdi_mtxorb_hack_setup(struct usb_serial *serial) +{ + struct usb_host_endpoint *ep = serial->dev->ep_in[1]; + struct usb_endpoint_descriptor *ep_desc = &ep->desc; + + if (ep->enabled && ep_desc->wMaxPacketSize == 0) { + ep_desc->wMaxPacketSize = 0x40; + info("Fixing invalid wMaxPacketSize on read pipe"); + } + + return 0; +} + /* ftdi_shutdown is called from usbserial:usb_serial_disconnect * it is called when the usb device is disconnected * --- linux-2.6.24.orig/drivers/usb/serial/keyspan.h +++ linux-2.6.24/drivers/usb/serial/keyspan.h @@ -637,6 +637,7 @@ .description = "Keyspan - (without firmware)", .id_table = keyspan_pre_ids, .num_interrupt_in = NUM_DONT_CARE, + .num_interrupt_out = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, @@ -651,6 +652,7 @@ .description = "Keyspan 1 port adapter", .id_table = keyspan_1port_ids, .num_interrupt_in = NUM_DONT_CARE, + .num_interrupt_out = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, @@ -678,6 +680,7 @@ .description = "Keyspan 2 port adapter", .id_table = keyspan_2port_ids, .num_interrupt_in = NUM_DONT_CARE, + .num_interrupt_out = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 2, @@ -705,6 +708,7 @@ .description = "Keyspan 4 port adapter", .id_table = keyspan_4port_ids, .num_interrupt_in = NUM_DONT_CARE, + .num_interrupt_out = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 4, --- linux-2.6.24.orig/drivers/usb/serial/pl2303.h +++ linux-2.6.24/drivers/usb/serial/pl2303.h @@ -112,3 +112,7 @@ /* Y.C. Cable U.S.A., Inc - USB to RS-232 */ #define YCCABLE_VENDOR_ID 0x05ad #define YCCABLE_PRODUCT_ID 0x0fba + +/* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */ +#define SANWA_VENDOR_ID 0x11ad +#define SANWA_PRODUCT_ID 0x0001 --- linux-2.6.24.orig/drivers/usb/serial/ftdi_sio.h +++ linux-2.6.24/drivers/usb/serial/ftdi_sio.h @@ -98,6 +98,13 @@ #define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */ #define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */ +/* + * The following are the values for the Matrix Orbital VK204-25-USB + * display, which use the FT232RL. + */ +#define MTXORB_VK_VID 0x1b3d +#define MTXORB_VK_PID 0x0158 + /* Interbiometrics USB I/O Board */ /* Developed for Interbiometrics by Rudolf Gugler */ #define INTERBIOMETRICS_VID 0x1209 --- linux-2.6.24.orig/drivers/usb/serial/ti_usb_3410_5052.c +++ linux-2.6.24/drivers/usb/serial/ti_usb_3410_5052.c @@ -264,8 +264,8 @@ .description = "TI USB 3410 1 port adapter", .usb_driver = &ti_usb_driver, .id_table = ti_id_table_3410, - .num_interrupt_in = 1, - .num_bulk_in = 1, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = 1, .num_ports = 1, .attach = ti_startup, --- linux-2.6.24.orig/drivers/usb/core/quirks.c +++ linux-2.6.24/drivers/usb/core/quirks.c @@ -28,6 +28,9 @@ * devices is broken... */ static const struct usb_device_id usb_quirk_list[] = { + /* Action Semiconductor flash disk */ + { USB_DEVICE(0x10d6, 0x2200), .driver_info = USB_QUIRK_STRING_FETCH_255}, + /* CBM - Flash disk */ { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, /* HP 5300/5370C scanner */ @@ -39,6 +42,9 @@ /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, + /* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */ + { USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF }, + /* Philips PSC805 audio device */ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, --- linux-2.6.24.orig/drivers/usb/core/hub.c +++ linux-2.6.24/drivers/usb/core/hub.c @@ -327,6 +327,9 @@ return status; } +static int hub_port_status(struct usb_hub *hub, int port1, + u16 *status, u16 *change); + static void kick_khubd(struct usb_hub *hub) { unsigned long flags; @@ -602,6 +605,81 @@ kick_khubd(hub); } +#define HUB_RESET 1 +#define HUB_RESUME 2 +#define HUB_RESET_RESUME 3 + +#ifdef CONFIG_PM + +static void hub_restart(struct usb_hub *hub, int type) +{ + struct usb_device *hdev = hub->hdev; + int port1; + + /* Check each of the children to see if they require + * USB-PERSIST handling or disconnection. Also check + * each unoccupied port to make sure it is still disabled. + */ + for (port1 = 1; port1 <= hdev->maxchild; ++port1) { + struct usb_device *udev = hdev->children[port1-1]; + int status = 0; + u16 portstatus, portchange; + + if (!udev || udev->state == USB_STATE_NOTATTACHED) { + if (type != HUB_RESET) { + status = hub_port_status(hub, port1, + &portstatus, &portchange); + if (status == 0 && (portstatus & + USB_PORT_STAT_ENABLE)) + clear_port_feature(hdev, port1, + USB_PORT_FEAT_ENABLE); + } + continue; + } + + /* Was the power session lost while we were suspended? */ + switch (type) { + case HUB_RESET_RESUME: + portstatus = 0; + portchange = USB_PORT_STAT_C_CONNECTION; + break; + + case HUB_RESET: + case HUB_RESUME: + status = hub_port_status(hub, port1, + &portstatus, &portchange); + break; + } + + /* For "USB_PERSIST"-enabled children we must + * mark the child device for reset-resume and + * turn off the various status changes to prevent + * khubd from disconnecting it later. + */ + if (USB_PERSIST && udev->persist_enabled && status == 0 && + !(portstatus & USB_PORT_STAT_ENABLE)) { + if (portchange & USB_PORT_STAT_C_ENABLE) + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_ENABLE); + if (portchange & USB_PORT_STAT_C_CONNECTION) + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_CONNECTION); + udev->reset_resume = 1; + } + + /* Otherwise for a reset_resume we must disconnect the child, + * but as we may not lock the child device here + * we have to do a "logical" disconnect. + */ + else if (type == HUB_RESET_RESUME) + hub_port_logical_disconnect(hub, port1); + } + + hub_activate(hub); +} + +#endif /* CONFIG_PM */ + /* caller has locked the hub device */ static int hub_pre_reset(struct usb_interface *intf) { @@ -1989,49 +2067,20 @@ static int hub_resume(struct usb_interface *intf) { - struct usb_hub *hub = usb_get_intfdata (intf); - - dev_dbg(&intf->dev, "%s\n", __FUNCTION__); + struct usb_hub *hub = usb_get_intfdata(intf); - /* tell khubd to look for changes on this hub */ - hub_activate(hub); + dev_dbg(&intf->dev, "%s\n", __func__); + hub_restart(hub, HUB_RESUME); return 0; } static int hub_reset_resume(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); - struct usb_device *hdev = hub->hdev; - int port1; + dev_dbg(&intf->dev, "%s\n", __func__); hub_power_on(hub); - - for (port1 = 1; port1 <= hdev->maxchild; ++port1) { - struct usb_device *child = hdev->children[port1-1]; - - if (child) { - - /* For "USB_PERSIST"-enabled children we must - * mark the child device for reset-resume and - * turn off the connect-change status to prevent - * khubd from disconnecting it later. - */ - if (USB_PERSIST && child->persist_enabled) { - child->reset_resume = 1; - clear_port_feature(hdev, port1, - USB_PORT_FEAT_C_CONNECTION); - - /* Otherwise we must disconnect the child, - * but as we may not lock the child device here - * we have to do a "logical" disconnect. - */ - } else { - hub_port_logical_disconnect(hub, port1); - } - } - } - - hub_activate(hub); + hub_restart(hub, HUB_RESET_RESUME); return 0; } --- linux-2.6.24.orig/drivers/usb/core/message.c +++ linux-2.6.24/drivers/usb/core/message.c @@ -1189,7 +1189,10 @@ return -EINVAL; } - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + if (dev->quirks & USB_QUIRK_NO_SET_INTF) + ret = -EPIPE; + else + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate, interface, NULL, 0, 5000); --- linux-2.6.24.orig/drivers/usb/class/cdc-acm.c +++ linux-2.6.24/drivers/usb/class/cdc-acm.c @@ -1183,6 +1183,9 @@ { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, + { USB_DEVICE(0x0e8d,0x0003), /* MediaTek Inc MT6227 */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, /* control interfaces with various AT-command sets */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, --- linux-2.6.24.orig/drivers/usb/class/usblp.c +++ linux-2.6.24/drivers/usb/class/usblp.c @@ -428,6 +428,7 @@ usblp->rcomplete = 0; if (handle_bidir(usblp) < 0) { + usb_autopm_put_interface(intf); usblp->used = 0; file->private_data = NULL; retval = -EIO; --- linux-2.6.24.orig/drivers/usb/storage/protocol.c +++ linux-2.6.24/drivers/usb/storage/protocol.c @@ -194,7 +194,7 @@ * and the starting offset within the page, and update * the *offset and *index values for the next loop. */ cnt = 0; - while (cnt < buflen) { + while (cnt < buflen && sg) { struct page *page = sg_page(sg) + ((sg->offset + *offset) >> PAGE_SHIFT); unsigned int poff = @@ -249,7 +249,8 @@ unsigned int offset = 0; struct scatterlist *sg = NULL; - usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset, + buflen = min(buflen, srb->request_bufflen); + buflen = usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset, TO_XFER_BUF); if (buflen < srb->request_bufflen) srb->resid = srb->request_bufflen - buflen; --- linux-2.6.24.orig/drivers/usb/storage/transport.c +++ linux-2.6.24/drivers/usb/storage/transport.c @@ -1010,7 +1010,8 @@ US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n", le32_to_cpu(bcs->Signature), bcs->Tag, residue, bcs->Status); - if (bcs->Tag != us->tag || bcs->Status > US_BULK_STAT_PHASE) { + if (!(bcs->Tag == us->tag || (us->flags & US_FL_BULK_IGNORE_TAG)) || + bcs->Status > US_BULK_STAT_PHASE) { US_DEBUGP("Bulk logical error\n"); return USB_STOR_TRANSPORT_ERROR; } --- linux-2.6.24.orig/drivers/usb/storage/unusual_devs.h +++ linux-2.6.24/drivers/usb/storage/unusual_devs.h @@ -161,6 +161,27 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_MAX_SECTORS_64 ), +/* Reported by Filip Joelsson */ +UNUSUAL_DEV( 0x0421, 0x005d, 0x0001, 0x0600, + "Nokia", + "Nokia 3110c", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + +/* Reported by CSECSY Laszlo */ +UNUSUAL_DEV( 0x0421, 0x0063, 0x0001, 0x0601, + "Nokia", + "Nokia 3109c", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + +/* Patch for Nokia 5310 capacity */ +UNUSUAL_DEV( 0x0421, 0x006a, 0x0000, 0x0591, + "Nokia", + "5310", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* Reported by Mario Rettig */ UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100, "Nokia", @@ -226,6 +247,35 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_MAX_SECTORS_64 ), +/* Reported by Cedric Godin */ +UNUSUAL_DEV( 0x0421, 0x04b9, 0x0500, 0x0551, + "Nokia", + "5300", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + +/* Reported by Richard Nauber */ +UNUSUAL_DEV( 0x0421, 0x04fa, 0x0550, 0x0660, + "Nokia", + "6300", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + +/* Patch for Nokia 5310 capacity */ +UNUSUAL_DEV( 0x0421, 0x006a, 0x0000, 0x0591, + "Nokia", + "5310", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + +/* Submitted by Ricky Wong Yung Fei */ +/* Nokia 7610 Supernova - Too many sectors reported in usb storage mode */ +UNUSUAL_DEV( 0x0421, 0x00f5, 0x0000, 0x0470, + "Nokia", + "7610 Supernova", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* Reported by Olaf Hering from novell bug #105878 */ UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, "SMSC", @@ -276,6 +326,18 @@ US_SC_SCSI, US_PR_KARMA, rio_karma_init, 0), #endif +/* Reported by Tamas Kerecsen + * Obviously the PROM has not been customized by the VAR; + * the Vendor and Product string descriptors are: + * Generic Mass Storage (PROTOTYPE--Remember to change idVendor) + * Generic Manufacturer (PROTOTYPE--Remember to change idVendor) + */ +UNUSUAL_DEV( 0x045e, 0xffff, 0x0000, 0x0000, + "Mitac", + "GPS", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + /* * This virtual floppy is found in Sun equipment (x4600, x4200m2, etc.) * Reported by Pete Zaitcev @@ -306,6 +368,13 @@ "Finecam S5", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), +/* Patch submitted by Jens Taprogge */ +UNUSUAL_DEV( 0x0482, 0x0107, 0x0100, 0x0100, + "Kyocera", + "CONTAX SL300R T*", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE), + /* Reported by Paul Stewart * This entry is needed because the device reports Sub=ff */ UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001, @@ -328,6 +397,13 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Tobias Kunze Briseno */ +UNUSUAL_DEV( 0x04b0, 0x0403, 0x0200, 0x0200, + "NIKON", + "NIKON DSC D2H", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* Reported by Milinevsky Dmitry */ UNUSUAL_DEV( 0x04b0, 0x0409, 0x0100, 0x0100, "NIKON", @@ -357,14 +433,14 @@ US_FL_FIX_CAPACITY), /* Reported by Emil Larsson */ -UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0101, +UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0111, "NIKON", "NIKON DSC D80", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), /* Reported by Ortwin Glueck */ -UNUSUAL_DEV( 0x04b0, 0x0413, 0x0110, 0x0110, +UNUSUAL_DEV( 0x04b0, 0x0413, 0x0110, 0x0111, "NIKON", "NIKON DSC D40", US_SC_DEVICE, US_PR_DEVICE, NULL, @@ -384,6 +460,13 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by paul ready */ +UNUSUAL_DEV( 0x04b0, 0x0419, 0x0100, 0x0200, + "NIKON", + "NIKON DSC D300", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* Reported by Doug Maxey (dwm@austin.ibm.com) */ UNUSUAL_DEV( 0x04b3, 0x4001, 0x0110, 0x0110, "IBM", @@ -557,6 +640,13 @@ US_FL_SINGLE_LUN), #endif +/* Reported by Dmitry Khlystov */ +UNUSUAL_DEV( 0x04e8, 0x507c, 0x0220, 0x0220, + "Samsung", + "YP-U3", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64), + /* Reported by Bob Sass -- only rev 1.33 tested */ UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133, "Belkin", @@ -947,6 +1037,13 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* Reported by Adrian Pilchowiec */ +UNUSUAL_DEV( 0x071b, 0x3203, 0x0000, 0x0000, + "RockChip", + "MP3", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_NO_WP_DETECT | US_FL_MAX_SECTORS_64), + /* Reported by Massimiliano Ghilardi * This USB MP3/AVI player device fails and disconnects if more than 128 * sectors (64kB) are read/written in a single command, and may be present @@ -1176,6 +1273,13 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), +/* Reported by Luciano Rocha */ +UNUSUAL_DEV( 0x0840, 0x0082, 0x0001, 0x0001, + "Argosy", + "Storage", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* Entry and supporting patch by Theodore Kilgore . * Flag will support Bulk devices which use a standards-violating 32-byte * Command Block Wrapper. Here, the "DC2MEGA" cameras (several brands) with @@ -1330,6 +1434,13 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), +/* Reported by Rohan Hart */ +UNUSUAL_DEV( 0x2770, 0x915d, 0x0010, 0x0010, + "INTOVA", + "Pixtreme", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* * Entry for Jenoptik JD 5200z3 * @@ -1412,6 +1523,17 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_GO_SLOW | US_FL_MAX_SECTORS_64), +/* Patch by Leonid Petrov mail at lpetrov.net + * Reported by Robert Spitzenpfeil + * http://www.qbik.ch/usb/devices/showdev.php?id=1705 + * Updated to 103 device by MJ Ray mjr at phonecoop.coop + */ +UNUSUAL_DEV( 0x0f19, 0x0103, 0x0100, 0x0100, + "Oracom Co., Ltd", + "ORC-200M", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + /* David Kuehling : * for MP3-Player AVOX WSX-300ER (bought in Japan). Reports lots of SCSI * errors when trying to write. @@ -1463,7 +1585,7 @@ "Sony Ericsson", "M600i", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), + US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), /* Reported by Kevin Cernekee * Tested on hardware version 1.10. @@ -1477,6 +1599,15 @@ US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init, 0 ), +/* Reported by Fabio Venturi + * The device reports a vendor-specific bDeviceClass. + */ +UNUSUAL_DEV( 0x10d6, 0x2200, 0x0100, 0x0100, + "Actions Semiconductor", + "Mtp device", + US_SC_DEVICE, US_PR_DEVICE, NULL, + 0), + /* Reported by Kevin Lloyd * Entry is needed for the initializer function override, * which instructs the device to load as a modem @@ -1550,13 +1681,35 @@ /* * Patch by Pete Zaitcev * Report by Mark Patton. Red Hat bz#208928. + * Added support for rev 0x0002 (Motorola ROKR W5) + * by Javier Smaldone */ -UNUSUAL_DEV( 0x22b8, 0x4810, 0x0001, 0x0001, +UNUSUAL_DEV( 0x22b8, 0x4810, 0x0001, 0x0002, "Motorola", - "RAZR V3i", + "RAZR V3i/ROKR W5", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* + * Patch by Jost Diederichs + */ +UNUSUAL_DEV(0x22b8, 0x6410, 0x0001, 0x9999, + "Motorola Inc.", + "Motorola Phone (RAZRV3xx)", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + +/* + * Patch by Constantin Baranov + * Report by Andreas Koenecke. + * Motorola ROKR Z6. + */ +UNUSUAL_DEV( 0x22b8, 0x6426, 0x0101, 0x0101, + "Motorola", + "MSnc.", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_INQUIRY | US_FL_FIX_CAPACITY | US_FL_BULK_IGNORE_TAG), + /* Reported by Radovan Garabik */ UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999, "MPIO", @@ -1588,6 +1741,11 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_CAPACITY_HEURISTICS), +UNUSUAL_DEV( 0Xed10, 0x7636, 0x0001, 0x0001, + "TGE", + "Digital MP3 Audio Player", + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), + /* Control/Bulk transport for all SubClass values */ USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR), USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR), --- linux-2.6.24.orig/drivers/mtd/devices/block2mtd.c +++ linux-2.6.24/drivers/mtd/devices/block2mtd.c @@ -408,7 +408,6 @@ if (token[1]) { ret = parse_num(&erase_size, token[1]); if (ret) { - kfree(name); parse_err("illegal erase size"); } } --- linux-2.6.24.orig/drivers/mtd/chips/cfi_cmdset_0001.c +++ linux-2.6.24/drivers/mtd/chips/cfi_cmdset_0001.c @@ -669,7 +669,7 @@ /* Someone else might have been playing with it. */ return -EAGAIN; } - + /* Fall through */ case FL_READY: case FL_CFI_QUERY: case FL_JEDEC_QUERY: @@ -729,14 +729,14 @@ chip->state = FL_READY; return 0; + case FL_SHUTDOWN: + /* The machine is rebooting now,so no one can get chip anymore */ + return -EIO; case FL_POINT: /* Only if there's no operation suspended... */ if (mode == FL_READY && chip->oldstate == FL_READY) return 0; - - case FL_SHUTDOWN: - /* The machine is rebooting now,so no one can get chip anymore */ - return -EIO; + /* Fall through */ default: sleep: set_current_state(TASK_UNINTERRUPTIBLE); --- linux-2.6.24.orig/drivers/scsi/advansys.c +++ linux-2.6.24/drivers/scsi/advansys.c @@ -566,7 +566,7 @@ ASC_SCSI_BIT_ID_TYPE unit_not_ready; ASC_SCSI_BIT_ID_TYPE queue_full_or_busy; ASC_SCSI_BIT_ID_TYPE start_motor; - uchar overrun_buf[ASC_OVERRUN_BSIZE] __aligned(8); + uchar *overrun_buf; dma_addr_t overrun_dma; uchar scsi_reset_wait; uchar chip_no; @@ -6439,7 +6439,7 @@ i += 2; len += 2; } else { - unsigned char off = buf[i] * 2; + unsigned int off = buf[i] * 2; unsigned short word = (buf[off + 1] << 8) | buf[off]; AdvWriteWordAutoIncLram(iop_base, word); len += 2; @@ -13833,6 +13833,12 @@ */ if (ASC_NARROW_BOARD(boardp)) { ASC_DBG(2, "AscInitAsc1000Driver()\n"); + + asc_dvc_varp->overrun_buf = kzalloc(ASC_OVERRUN_BSIZE, GFP_KERNEL); + if (!asc_dvc_varp->overrun_buf) { + ret = -ENOMEM; + goto err_free_wide_mem; + } warn_code = AscInitAsc1000Driver(asc_dvc_varp); if (warn_code || asc_dvc_varp->err_code) { @@ -13840,8 +13846,10 @@ "warn 0x%x, error 0x%x\n", asc_dvc_varp->init_state, warn_code, asc_dvc_varp->err_code); - if (asc_dvc_varp->err_code) + if (asc_dvc_varp->err_code) { ret = -ENODEV; + kfree(asc_dvc_varp->overrun_buf); + } } } else { if (advansys_wide_init_chip(shost)) @@ -13894,6 +13902,7 @@ dma_unmap_single(board->dev, board->dvc_var.asc_dvc_var.overrun_dma, ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE); + kfree(board->dvc_var.asc_dvc_var.overrun_buf); } else { iounmap(board->ioremap_addr); advansys_wide_free_mem(board); --- linux-2.6.24.orig/drivers/scsi/gdth.c +++ linux-2.6.24/drivers/scsi/gdth.c @@ -160,7 +160,7 @@ static void gdth_clear_events(void); static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, - char *buffer, ushort count, int to_buffer); + char *buffer, ushort count); static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp); static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive); @@ -183,7 +183,6 @@ unsigned int cmd, unsigned long arg); static void gdth_flush(gdth_ha_str *ha); -static int gdth_halt(struct notifier_block *nb, ulong event, void *buf); static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *)); static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, struct gdth_cmndinfo *cmndinfo); @@ -418,12 +417,6 @@ #include "gdth_proc.h" #include "gdth_proc.c" -/* notifier block to get a notify on system shutdown/halt/reboot */ -static struct notifier_block gdth_notifier = { - gdth_halt, NULL, 0 -}; -static int notifier_disabled = 0; - static gdth_ha_str *gdth_find_ha(int hanum) { gdth_ha_str *ha; @@ -446,8 +439,8 @@ for (i=0; icmndinfo[i].index == 0) { priv = &ha->cmndinfo[i]; - priv->index = i+1; memset(priv, 0, sizeof(*priv)); + priv->index = i+1; break; } } @@ -494,7 +487,6 @@ gdth_ha_str *ha = shost_priv(sdev->host); Scsi_Cmnd *scp; struct gdth_cmndinfo cmndinfo; - struct scatterlist one_sg; DECLARE_COMPLETION_ONSTACK(wait); int rval; @@ -508,13 +500,10 @@ /* use request field to save the ptr. to completion struct. */ scp->request = (struct request *)&wait; scp->timeout_per_command = timeout*HZ; - sg_init_one(&one_sg, gdtcmd, sizeof(*gdtcmd)); - gdth_set_sglist(scp, &one_sg); - gdth_set_sg_count(scp, 1); - gdth_set_bufflen(scp, sizeof(*gdtcmd)); scp->cmd_len = 12; memcpy(scp->cmnd, cmnd, 12); cmndinfo.priority = IOCTL_PRI; + cmndinfo.internal_cmd_str = gdtcmd; cmndinfo.internal_command = 1; TRACE(("__gdth_execute() cmd 0x%x\n", scp->cmnd[0])); @@ -2355,7 +2344,7 @@ * buffers, kmap_atomic() as needed. */ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, - char *buffer, ushort count, int to_buffer) + char *buffer, ushort count) { ushort cpcount,i, max_sg = gdth_sg_count(scp); ushort cpsum,cpnow; @@ -2381,10 +2370,7 @@ } local_irq_save(flags); address = kmap_atomic(sg_page(sl), KM_BIO_SRC_IRQ) + sl->offset; - if (to_buffer) - memcpy(buffer, address, cpnow); - else - memcpy(address, buffer, cpnow); + memcpy(address, buffer, cpnow); flush_dcache_page(sg_page(sl)); kunmap_atomic(address, KM_BIO_SRC_IRQ); local_irq_restore(flags); @@ -2438,7 +2424,7 @@ strcpy(inq.vendor,ha->oem_name); sprintf(inq.product,"Host Drive #%02d",t); strcpy(inq.revision," "); - gdth_copy_internal_data(ha, scp, (char*)&inq, sizeof(gdth_inq_data), 0); + gdth_copy_internal_data(ha, scp, (char*)&inq, sizeof(gdth_inq_data)); break; case REQUEST_SENSE: @@ -2448,7 +2434,7 @@ sd.key = NO_SENSE; sd.info = 0; sd.add_length= 0; - gdth_copy_internal_data(ha, scp, (char*)&sd, sizeof(gdth_sense_data), 0); + gdth_copy_internal_data(ha, scp, (char*)&sd, sizeof(gdth_sense_data)); break; case MODE_SENSE: @@ -2460,7 +2446,7 @@ mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16; mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8; mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff); - gdth_copy_internal_data(ha, scp, (char*)&mpd, sizeof(gdth_modep_data), 0); + gdth_copy_internal_data(ha, scp, (char*)&mpd, sizeof(gdth_modep_data)); break; case READ_CAPACITY: @@ -2470,7 +2456,7 @@ else rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1); rdc.block_length = cpu_to_be32(SECTOR_SIZE); - gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data), 0); + gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data)); break; case SERVICE_ACTION_IN: @@ -2482,7 +2468,7 @@ rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1); rdc16.block_length = cpu_to_be32(SECTOR_SIZE); gdth_copy_internal_data(ha, scp, (char*)&rdc16, - sizeof(gdth_rdcap16_data), 0); + sizeof(gdth_rdcap16_data)); } else { scp->result = DID_ABORT << 16; } @@ -2852,6 +2838,7 @@ static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) { register gdth_cmd_str *cmdp; + struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); int cmd_index; cmdp= ha->pccb; @@ -2860,7 +2847,7 @@ if (ha->type==GDT_EISA && ha->cmd_cnt>0) return 0; - gdth_copy_internal_data(ha, scp, (char *)cmdp, sizeof(gdth_cmd_str), 1); + *cmdp = *cmndinfo->internal_cmd_str; cmdp->RequestBuffer = scp; /* search free command index */ @@ -2975,7 +2962,7 @@ eindex = handle; estr->event_source = 0; - if (eindex >= MAX_EVENTS) { + if (eindex < 0 || eindex >= MAX_EVENTS) { spin_unlock_irqrestore(&ha->smp_lock, flags); return eindex; } @@ -3793,6 +3780,8 @@ gdth_ha_str *ha; ulong flags; + BUG_ON(list_empty(&gdth_instances)); + ha = list_first_entry(&gdth_instances, gdth_ha_str, list); spin_lock_irqsave(&ha->smp_lock, flags); @@ -4668,45 +4657,6 @@ } } -/* shutdown routine */ -static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) -{ - gdth_ha_str *ha; -#ifndef __alpha__ - gdth_cmd_str gdtcmd; - char cmnd[MAX_COMMAND_SIZE]; -#endif - - if (notifier_disabled) - return NOTIFY_OK; - - TRACE2(("gdth_halt() event %d\n",(int)event)); - if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) - return NOTIFY_DONE; - - notifier_disabled = 1; - printk("GDT-HA: Flushing all host drives .. "); - list_for_each_entry(ha, &gdth_instances, list) { - gdth_flush(ha); - -#ifndef __alpha__ - /* controller reset */ - memset(cmnd, 0xff, MAX_COMMAND_SIZE); - gdtcmd.BoardNode = LOCALBOARD; - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_RESET; - TRACE2(("gdth_halt(): reset controller %d\n", ha->hanum)); - gdth_execute(ha->shost, &gdtcmd, cmnd, 10, NULL); -#endif - } - printk("Done.\n"); - -#ifdef GDTH_STATISTICS - del_timer(&gdth_timer); -#endif - return NOTIFY_OK; -} - /* configure lun */ static int gdth_slave_configure(struct scsi_device *sdev) { @@ -4838,6 +4788,9 @@ if (error) goto out_free_coal_stat; list_add_tail(&ha->list, &gdth_instances); + + scsi_scan_host(shp); + return 0; out_free_coal_stat: @@ -4965,6 +4918,9 @@ if (error) goto out_free_coal_stat; list_add_tail(&ha->list, &gdth_instances); + + scsi_scan_host(shp); + return 0; out_free_ccb_phys: @@ -5102,6 +5058,9 @@ if (error) goto out_free_coal_stat; list_add_tail(&ha->list, &gdth_instances); + + scsi_scan_host(shp); + return 0; out_free_coal_stat: @@ -5132,13 +5091,13 @@ scsi_remove_host(shp); + gdth_flush(ha); + if (ha->sdev) { scsi_free_host_dev(ha->sdev); ha->sdev = NULL; } - gdth_flush(ha); - if (shp->irq) free_irq(shp->irq,ha); @@ -5164,6 +5123,24 @@ scsi_host_put(shp); } +static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) +{ + gdth_ha_str *ha; + + TRACE2(("gdth_halt() event %d\n", (int)event)); + if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) + return NOTIFY_DONE; + + list_for_each_entry(ha, &gdth_instances, list) + gdth_flush(ha); + + return NOTIFY_OK; +} + +static struct notifier_block gdth_notifier = { + gdth_halt, NULL, 0 +}; + static int __init gdth_init(void) { if (disable) { @@ -5226,7 +5203,6 @@ add_timer(&gdth_timer); #endif major = register_chrdev(0,"gdth", &gdth_fops); - notifier_disabled = 0; register_reboot_notifier(&gdth_notifier); gdth_polling = FALSE; return 0; @@ -5236,14 +5212,15 @@ { gdth_ha_str *ha; - list_for_each_entry(ha, &gdth_instances, list) - gdth_remove_one(ha); + unregister_chrdev(major, "gdth"); + unregister_reboot_notifier(&gdth_notifier); #ifdef GDTH_STATISTICS - del_timer(&gdth_timer); + del_timer_sync(&gdth_timer); #endif - unregister_chrdev(major,"gdth"); - unregister_reboot_notifier(&gdth_notifier); + + list_for_each_entry(ha, &gdth_instances, list) + gdth_remove_one(ha); } module_init(gdth_init); --- linux-2.6.24.orig/drivers/scsi/scsi_lib.c +++ linux-2.6.24/drivers/scsi/scsi_lib.c @@ -298,7 +298,6 @@ page = sg_page(sg); off = sg->offset; len = sg->length; - data_len += len; while (len > 0 && data_len > 0) { /* --- linux-2.6.24.orig/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ linux-2.6.24/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -155,7 +155,7 @@ pci_save_state(pdev); pci_disable_device(pdev); - if (mesg.event == PM_EVENT_SUSPEND) + if (mesg.event & PM_EVENT_SLEEP) pci_set_power_state(pdev, PCI_D3hot); return rc; --- linux-2.6.24.orig/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ linux-2.6.24/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -110,7 +110,7 @@ pci_save_state(pdev); pci_disable_device(pdev); - if (mesg.event == PM_EVENT_SUSPEND) + if (mesg.event & PM_EVENT_SLEEP) pci_set_power_state(pdev, PCI_D3hot); return rc; --- linux-2.6.24.orig/drivers/scsi/aic94xx/aic94xx_scb.c +++ linux-2.6.24/drivers/scsi/aic94xx/aic94xx_scb.c @@ -458,13 +458,19 @@ tc_abort = le16_to_cpu(tc_abort); list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) { - struct sas_task *task = ascb->uldd_task; + struct sas_task *task = a->uldd_task; + + if (a->tc_index != tc_abort) + continue; - if (task && a->tc_index == tc_abort) { + if (task) { failed_dev = task->dev; sas_task_abort(task); - break; + } else { + ASD_DPRINTK("R_T_A for non TASK scb 0x%x\n", + a->scb->header.opcode); } + break; } if (!failed_dev) { @@ -478,7 +484,7 @@ * that the EH will wake up and do something. */ list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) { - struct sas_task *task = ascb->uldd_task; + struct sas_task *task = a->uldd_task; if (task && task->dev == failed_dev && --- linux-2.6.24.orig/drivers/scsi/scsi_transport_fc.c +++ linux-2.6.24/drivers/scsi/scsi_transport_fc.c @@ -478,9 +478,29 @@ MODULE_PARM_DESC(dev_loss_tmo, "Maximum number of seconds that the FC transport should" " insulate the loss of a remote port. Once this value is" - " exceeded, the scsi target is removed. Value should be" + " exceeded, the scsi target may be removed. Reference the" + " remove_on_dev_loss module parameter. Value should be" " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT."); +/* + * remove_on_dev_loss: controls whether the transport will + * remove a scsi target after the device loss timer expires. + * Removal on disconnect is modeled after the USB subsystem + * and expects subsystems layered on SCSI to be aware of + * potential device loss and handle it appropriately. However, + * many subsystems do not support device removal, leaving situations + * where structure references may remain, causing new device + * name assignments, etc., if the target returns. + */ +static unsigned int fc_remove_on_dev_loss = 0; +module_param_named(remove_on_dev_loss, fc_remove_on_dev_loss, + int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(remove_on_dev_loss, + "Boolean. When the device loss timer fires, this variable" + " controls whether the scsi infrastructure for the target" + " device is removed. Values: zero means do not remove," + " non-zero means remove. Default is zero."); + /** * Netlink Infrastructure **/ @@ -2297,7 +2317,8 @@ if (i->f->terminate_rport_io) i->f->terminate_rport_io(rport); - scsi_remove_target(&rport->dev); + if (fc_remove_on_dev_loss) + scsi_remove_target(&rport->dev); } @@ -2934,9 +2955,13 @@ return; } - dev_printk(KERN_ERR, &rport->dev, - "blocked FC remote port time out: removing target and " - "saving binding\n"); + if (fc_remove_on_dev_loss) + dev_printk(KERN_ERR, &rport->dev, + "blocked FC remote port time out: removing target and " + "saving binding\n"); + else + dev_printk(KERN_ERR, &rport->dev, + "blocked FC remote port time out: saving binding\n"); list_move_tail(&rport->peers, &fc_host->rport_bindings); --- linux-2.6.24.orig/drivers/scsi/arcmsr/arcmsr_hba.c +++ linux-2.6.24/drivers/scsi/arcmsr/arcmsr_hba.c @@ -1380,17 +1380,16 @@ switch(controlcode) { case ARCMSR_MESSAGE_READ_RQBUFFER: { - unsigned long *ver_addr; - dma_addr_t buf_handle; + unsigned char *ver_addr; uint8_t *pQbuffer, *ptmpQbuffer; int32_t allxfer_len = 0; - ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); + ver_addr = kmalloc(1032, GFP_ATOMIC); if (!ver_addr) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } - ptmpQbuffer = (uint8_t *) ver_addr; + ptmpQbuffer = ver_addr; while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) && (allxfer_len < 1031)) { pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; @@ -1419,25 +1418,24 @@ } arcmsr_iop_message_read(acb); } - memcpy(pcmdmessagefld->messagedatabuffer, (uint8_t *)ver_addr, allxfer_len); + memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len); pcmdmessagefld->cmdmessage.Length = allxfer_len; pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; - pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); + kfree(ver_addr); } break; case ARCMSR_MESSAGE_WRITE_WQBUFFER: { - unsigned long *ver_addr; - dma_addr_t buf_handle; + unsigned char *ver_addr; int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; uint8_t *pQbuffer, *ptmpuserbuffer; - ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); + ver_addr = kmalloc(1032, GFP_ATOMIC); if (!ver_addr) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } - ptmpuserbuffer = (uint8_t *)ver_addr; + ptmpuserbuffer = ver_addr; user_len = pcmdmessagefld->cmdmessage.Length; memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len); wqbuf_lastindex = acb->wqbuf_lastindex; @@ -1483,7 +1481,7 @@ retvalue = ARCMSR_MESSAGE_FAIL; } } - pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); + kfree(ver_addr); } break; --- linux-2.6.24.orig/drivers/scsi/ips.c +++ linux-2.6.24/drivers/scsi/ips.c @@ -1580,7 +1580,7 @@ METHOD_TRACE("ips_make_passthru", 1); scsi_for_each_sg(SC, sg, scsi_sg_count(SC), i) - length += sg[i].length; + length += sg->length; if (length < sizeof (ips_passthru_t)) { /* wrong size */ @@ -6842,13 +6842,10 @@ if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to install interrupt handler\n"); - scsi_host_put(sh); - return -1; + goto err_out_sh; } kfree(oldha); - ips_sh[index] = sh; - ips_ha[index] = ha; /* Store away needed values for later use */ sh->io_port = ha->io_addr; @@ -6867,10 +6864,21 @@ sh->max_channel = ha->nbus - 1; sh->can_queue = ha->max_cmds - 1; - scsi_add_host(sh, NULL); + if (scsi_add_host(sh, &ha->pcidev->dev)) + goto err_out; + + ips_sh[index] = sh; + ips_ha[index] = ha; + scsi_scan_host(sh); return 0; + +err_out: + free_irq(ha->pcidev->irq, ha); +err_out_sh: + scsi_host_put(sh); + return -1; } /*---------------------------------------------------------------------------*/ --- linux-2.6.24.orig/drivers/scsi/mesh.c +++ linux-2.6.24/drivers/scsi/mesh.c @@ -1759,6 +1759,7 @@ switch (mesg.event) { case PM_EVENT_SUSPEND: + case PM_EVENT_HIBERNATE: case PM_EVENT_FREEZE: break; default: --- linux-2.6.24.orig/drivers/scsi/sd.c +++ linux-2.6.24/drivers/scsi/sd.c @@ -907,6 +907,7 @@ unsigned int xfer_size = SCpnt->request_bufflen; unsigned int good_bytes = result ? 0 : xfer_size; u64 start_lba = SCpnt->request->sector; + u64 end_lba = SCpnt->request->sector + (xfer_size / 512); u64 bad_lba; struct scsi_sense_hdr sshdr; int sense_valid = 0; @@ -945,26 +946,23 @@ goto out; if (xfer_size <= SCpnt->device->sector_size) goto out; - switch (SCpnt->device->sector_size) { - case 256: + if (SCpnt->device->sector_size < 512) { + /* only legitimate sector_size here is 256 */ start_lba <<= 1; - break; - case 512: - break; - case 1024: - start_lba >>= 1; - break; - case 2048: - start_lba >>= 2; - break; - case 4096: - start_lba >>= 3; - break; - default: - /* Print something here with limiting frequency. */ - goto out; - break; + end_lba <<= 1; + } else { + /* be careful ... don't want any overflows */ + u64 factor = SCpnt->device->sector_size / 512; + do_div(start_lba, factor); + do_div(end_lba, factor); } + + if (bad_lba < start_lba || bad_lba >= end_lba) + /* the bad lba was reported incorrectly, we have + * no idea where the error is + */ + goto out; + /* This computation should always be done in terms of * the resolution of the device's medium. */ @@ -1815,8 +1813,7 @@ goto done; } - if (mesg.event == PM_EVENT_SUSPEND && - sdkp->device->manage_start_stop) { + if ((mesg.event & PM_EVENT_SLEEP) && sdkp->device->manage_start_stop) { sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); ret = sd_start_stop_device(sdkp, 0); } --- linux-2.6.24.orig/drivers/scsi/gdth_proc.c +++ linux-2.6.24/drivers/scsi/gdth_proc.c @@ -694,15 +694,13 @@ { ulong flags; - spin_lock_irqsave(&ha->smp_lock, flags); - if (buf == ha->pscratch) { + spin_lock_irqsave(&ha->smp_lock, flags); ha->scratch_busy = FALSE; + spin_unlock_irqrestore(&ha->smp_lock, flags); } else { pci_free_consistent(ha->pdev, size, buf, paddr); } - - spin_unlock_irqrestore(&ha->smp_lock, flags); } #ifdef GDTH_IOCTL_PROC --- linux-2.6.24.orig/drivers/scsi/megaraid/megaraid_sas.c +++ linux-2.6.24/drivers/scsi/megaraid/megaraid_sas.c @@ -3018,7 +3018,7 @@ return retval; } -static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl, +static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUSR, megasas_sysfs_show_dbg_lvl, megasas_sysfs_set_dbg_lvl); /** --- linux-2.6.24.orig/drivers/scsi/gdth.h +++ linux-2.6.24/drivers/scsi/gdth.h @@ -915,6 +915,7 @@ struct gdth_cmndinfo { /* per-command private info */ int index; int internal_command; /* don't call scsi_done */ + gdth_cmd_str *internal_cmd_str; /* crier for internal messages*/ dma_addr_t sense_paddr; /* sense dma-addr */ unchar priority; int timeout; --- linux-2.6.24.orig/drivers/net/hamradio/mkiss.c +++ linux-2.6.24/drivers/net/hamradio/mkiss.c @@ -530,6 +530,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) { struct mkiss *ax = netdev_priv(dev); + int cib = 0; if (!netif_running(dev)) { printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); @@ -545,10 +546,11 @@ /* 20 sec timeout not reached */ return 1; } + if (ax->tty->driver->chars_in_buffer) + cib = ax->tty->driver->chars_in_buffer(ax->tty); printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name, - (ax->tty->driver->chars_in_buffer(ax->tty) || ax->xleft) ? - "bad line quality" : "driver error"); + cib || ax->xleft ? "bad line quality" : "driver error"); ax->xleft = 0; clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); @@ -737,6 +739,8 @@ if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (!tty->driver->write) + return -EOPNOTSUPP; dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup); if (!dev) { --- linux-2.6.24.orig/drivers/net/hamradio/6pack.c +++ linux-2.6.24/drivers/net/hamradio/6pack.c @@ -601,6 +601,8 @@ if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (!tty->driver->write) + return -EOPNOTSUPP; dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup); if (!dev) { --- linux-2.6.24.orig/drivers/net/wireless/orinoco_cs.c +++ linux-2.6.24/drivers/net/wireless/orinoco_cs.c @@ -11,6 +11,7 @@ */ #define DRIVER_NAME "orinoco_cs" +#define OVERLAP_DRIVER_NAME "orinoco_cs_overlap" #define PFX DRIVER_NAME ": " #include @@ -440,66 +441,93 @@ " (David Gibson , " "Pavel Roskin , et al)"; -static struct pcmcia_device_id orinoco_cs_ids[] = { +/* + * PCMCIA IDs that are also defined in hostap_cs. + */ +static struct pcmcia_device_id orinoco_overlap_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */ PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */ - PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */ PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */ PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */ PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */ + PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */ + PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */ + PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */ + PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */ + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */ + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */ + + PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18), + PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf), + + PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2), + + PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2), + PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac), + PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab), + PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), + PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757), + PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a), + PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3), + PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18), + PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b), + PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77), + PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395), + PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), + PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f), + + PCMCIA_DEVICE_NULL, +}; + +static struct pcmcia_driver orinoco_overlap_driver = { + .owner = THIS_MODULE, + .drv = { + .name = OVERLAP_DRIVER_NAME, + }, + .probe = orinoco_cs_probe, + .remove = orinoco_cs_detach, + .id_table = orinoco_overlap_cs_ids, + .suspend = orinoco_cs_suspend, + .resume = orinoco_cs_resume, +}; + +static struct pcmcia_device_id orinoco_cs_ids[] = { + PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */ PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */ PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */ PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */ PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */ - PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */ PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */ PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */ - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */ - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */ - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */ PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */ - PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */ PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */ PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */ - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */ PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */ PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */ PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */ - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */ - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */ + PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9), PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3), PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5), - PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2), PCMCIA_DEVICE_PROD_ID123("AIRVAST", "IEEE 802.11b Wireless PCMCIA Card", "HFA3863", 0xea569531, 0x4bcb9645, 0x355cb092), - PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f), PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842), PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e), PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169), PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18), PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90), - PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b), PCMCIA_DEVICE_PROD_ID123("corega", "WL PCCL-11", "ISL37300P", 0x0a21501a, 0x59868926, 0xc9049a39), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9), PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae), - PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac), - PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab), PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916), PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146), PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3), PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c), - PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77), - PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf), - PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2), PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92), - PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395), PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a), PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410), PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3), @@ -516,11 +544,8 @@ PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9), PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26), PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b), - PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757), - PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a), PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e), PCMCIA_DEVICE_PROD_ID123("The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", 0xa5f472c2, 0x590eb502, 0xc9049a39), - PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids); @@ -537,18 +562,39 @@ .resume = orinoco_cs_resume, }; +static int orinoco_driver_registered = 0; +static int orinoco_overlap_driver_registered = 0; + static int __init init_orinoco_cs(void) { + int status; + printk(KERN_DEBUG "%s\n", version); - return pcmcia_register_driver(&orinoco_driver); + status = pcmcia_register_driver(&orinoco_driver); + if (status >= 0) + orinoco_driver_registered = 1; + + status = pcmcia_register_driver(&orinoco_overlap_driver); + if (status >= 0) + orinoco_overlap_driver_registered = 1; + + return status; } static void __exit exit_orinoco_cs(void) { - pcmcia_unregister_driver(&orinoco_driver); + if (orinoco_overlap_driver_registered) { + pcmcia_unregister_driver(&orinoco_overlap_driver); + orinoco_overlap_driver_registered = 0; + } + + if (orinoco_driver_registered) { + pcmcia_unregister_driver(&orinoco_driver); + orinoco_driver_registered = 0; + } } module_init(init_orinoco_cs); --- linux-2.6.24.orig/drivers/net/wireless/hostap/hostap_main.c +++ linux-2.6.24/drivers/net/wireless/hostap/hostap_main.c @@ -1106,6 +1106,7 @@ (u8 *) &reason, 2); memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); + wireless_send_event(local->ddev, SIOCGIWAP, &wrqu, NULL); return ret; } --- linux-2.6.24.orig/drivers/net/wireless/hostap/hostap_ioctl.c +++ linux-2.6.24/drivers/net/wireless/hostap/hostap_ioctl.c @@ -1089,6 +1089,9 @@ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) + range->scan_capa = IW_SCAN_CAPA_ESSID; + return 0; } --- linux-2.6.24.orig/drivers/net/wireless/hostap/hostap_hw.c +++ linux-2.6.24/drivers/net/wireless/hostap/hostap_hw.c @@ -3434,6 +3434,7 @@ memset(&wrqu, 0, sizeof(wrqu)); wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); + wireless_send_event(local->ddev, SIOCGIWAP, &wrqu, NULL); /* Disable hardware and firmware */ prism2_hw_shutdown(dev, 0); --- linux-2.6.24.orig/drivers/net/wireless/hostap/hostap_info.c +++ linux-2.6.24/drivers/net/wireless/hostap/hostap_info.c @@ -238,6 +238,7 @@ wrqu.data.length = 0; wrqu.data.flags = 0; wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL); + wireless_send_event(local->ddev, SIOCGIWSCAN, &wrqu, NULL); /* Allow SIOCGIWSCAN handling to occur since we have received * scanning result */ @@ -450,8 +451,10 @@ * frames and can confuse wpa_supplicant about the current association * status. */ - if (connected || local->prev_linkstatus_connected) + if (connected || local->prev_linkstatus_connected) { wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); + wireless_send_event(local->ddev, SIOCGIWAP, &wrqu, NULL); + } local->prev_linkstatus_connected = connected; } --- linux-2.6.24.orig/drivers/net/wireless/libertas/scan.c +++ linux-2.6.24/drivers/net/wireless/libertas/scan.c @@ -1022,8 +1022,8 @@ switch (elem->id) { case MFIE_TYPE_SSID: - bss->ssid_len = elem->len; - memcpy(bss->ssid, elem->data, elem->len); + bss->ssid_len = min_t(int, 32, elem->len); + memcpy(bss->ssid, elem->data, bss->ssid_len); lbs_deb_scan("ssid '%s', ssid length %u\n", escape_essid(bss->ssid, bss->ssid_len), bss->ssid_len); --- linux-2.6.24.orig/drivers/net/wireless/b43/dma.c +++ linux-2.6.24/drivers/net/wireless/b43/dma.c @@ -165,7 +165,7 @@ addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK); addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK) >> SSB_DMA_TRANSLATION_SHIFT; - addrhi |= ssb_dma_translation(ring->dev->dev); + addrhi |= (ssb_dma_translation(ring->dev->dev) << 1); if (slot == ring->nr_slots - 1) ctl0 |= B43_DMA64_DCTL0_DTABLEEND; if (start) @@ -426,9 +426,21 @@ static int alloc_ringmemory(struct b43_dmaring *ring) { struct device *dev = ring->dev->dev->dev; + gfp_t flags = GFP_KERNEL; + /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K + * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing + * has shown that 4K is sufficient for the latter as long as the buffer + * does not cross an 8K boundary. + * + * For unknown reasons - possibly a hardware error - the BCM4311 rev + * 02, which uses 64-bit DMA, needs the ring buffer in very low memory, + * which accounts for the GFP_DMA flag below. + */ + if (ring->dma64) + flags |= GFP_DMA; ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE, - &(ring->dmabase), GFP_KERNEL); + &(ring->dmabase), flags); if (!ring->descbase) { b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); return -ENOMEM; @@ -483,7 +495,7 @@ return 0; } -/* Reset the RX DMA channel */ +/* Reset the TX DMA channel */ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) { int i; @@ -647,7 +659,7 @@ b43_dma_write(ring, B43_DMA64_TXRINGHI, ((ringbase >> 32) & ~SSB_DMA_TRANSLATION_MASK) - | trans); + | (trans << 1)); } else { u32 ringbase = (u32) (ring->dmabase); @@ -680,8 +692,9 @@ b43_dma_write(ring, B43_DMA64_RXRINGHI, ((ringbase >> 32) & ~SSB_DMA_TRANSLATION_MASK) - | trans); - b43_dma_write(ring, B43_DMA64_RXINDEX, 200); + | (trans << 1)); + b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots * + sizeof(struct b43_dmadesc64)); } else { u32 ringbase = (u32) (ring->dmabase); @@ -695,11 +708,12 @@ b43_dma_write(ring, B43_DMA32_RXRING, (ringbase & ~SSB_DMA_TRANSLATION_MASK) | trans); - b43_dma_write(ring, B43_DMA32_RXINDEX, 200); + b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots * + sizeof(struct b43_dmadesc32)); } } - out: +out: return err; } --- linux-2.6.24.orig/drivers/net/wireless/b43/phy.c +++ linux-2.6.24/drivers/net/wireless/b43/phy.c @@ -933,7 +933,7 @@ for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) b43_ofdmtab_write16(dev, 0x5000, i, b43_tab_sigmasqr1[i]); - else if ((phy->rev > 2) && (phy->rev <= 8)) + else if ((phy->rev > 2) && (phy->rev <= 9)) for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) b43_ofdmtab_write16(dev, 0x5000, i, b43_tab_sigmasqr2[i]); --- linux-2.6.24.orig/drivers/net/wireless/b43/main.c +++ linux-2.6.24/drivers/net/wireless/b43/main.c @@ -101,6 +101,9 @@ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15), SSB_DEVTABLE_END }; @@ -3079,7 +3082,7 @@ unsupported = 1; break; case B43_PHYTYPE_G: - if (phy_rev > 8) + if (phy_rev > 9) unsupported = 1; break; default: @@ -3739,7 +3742,7 @@ have_gphy = 0; switch (dev->phy.type) { case B43_PHYTYPE_A: - have_aphy = 1; + have_aphy = 0; break; case B43_PHYTYPE_B: have_bphy = 1; @@ -3850,8 +3853,16 @@ return err; } +#define IS_PDEV(pdev, _vendor, _device, _subvendor, _subdevice) ( \ + (pdev->vendor == PCI_VENDOR_ID_##_vendor) && \ + (pdev->device == _device) && \ + (pdev->subsystem_vendor == PCI_VENDOR_ID_##_subvendor) && \ + (pdev->subsystem_device == _subdevice) ) + static void b43_sprom_fixup(struct ssb_bus *bus) { + struct pci_dev *pdev; + /* boardflags workarounds */ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL && bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74) @@ -3859,6 +3870,15 @@ if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40) bus->sprom.r1.boardflags_lo |= B43_BFL_PACTRL; + if (bus->bustype == SSB_BUSTYPE_PCI) { + pdev = bus->host_pci; + if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) || + IS_PDEV(pdev, BROADCOM, 0x4320, DELL, 0x0003) || + IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) || + IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0014) || + IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013)) + bus->sprom.r1.boardflags_lo &= ~B43_BFL_BTCOEXIST; + } /* Handle case when gain is not set in sprom */ if (bus->sprom.r1.antenna_gain_a == 0xFF) --- linux-2.6.24.orig/drivers/net/wireless/ipw2200.c +++ linux-2.6.24/drivers/net/wireless/ipw2200.c @@ -8912,6 +8912,8 @@ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE; + IPW_DEBUG_WX("GET Range\n"); return 0; } --- linux-2.6.24.orig/drivers/net/wireless/b43legacy/xmit.c +++ linux-2.6.24/drivers/net/wireless/b43legacy/xmit.c @@ -606,7 +606,7 @@ tmp = hw->count; status.frame_count = (tmp >> 4); status.rts_count = (tmp & 0x0F); - tmp = hw->flags; + tmp = hw->flags << 1; status.supp_reason = ((tmp & 0x1C) >> 2); status.pm_indicated = !!(tmp & 0x80); status.intermediate = !!(tmp & 0x40); --- linux-2.6.24.orig/drivers/net/wireless/b43legacy/leds.c +++ linux-2.6.24/drivers/net/wireless/b43legacy/leds.c @@ -256,7 +256,7 @@ continue; #endif /* CONFIG_B43LEGACY_DEBUG */ default: - B43legacy_BUG_ON(1); + break; }; if (led->activelow) --- linux-2.6.24.orig/drivers/net/wireless/b43legacy/main.c +++ linux-2.6.24/drivers/net/wireless/b43legacy/main.c @@ -1500,6 +1500,7 @@ } if (!fw->initvals) { switch (dev->phy.type) { + case B43legacy_PHYTYPE_B: case B43legacy_PHYTYPE_G: if ((rev >= 5) && (rev <= 10)) filename = "b0g0initvals5"; @@ -1517,6 +1518,7 @@ } if (!fw->initvals_band) { switch (dev->phy.type) { + case B43legacy_PHYTYPE_B: case B43legacy_PHYTYPE_G: if ((rev >= 5) && (rev <= 10)) filename = "b0g0bsinitvals5"; --- linux-2.6.24.orig/drivers/net/wireless/strip.c +++ linux-2.6.24/drivers/net/wireless/strip.c @@ -802,7 +802,8 @@ struct ktermios old_termios = *(tty->termios); tty->termios->c_cflag &= ~CBAUD; /* Clear the old baud setting */ tty->termios->c_cflag |= baudcode; /* Set the new baud setting */ - tty->driver->set_termios(tty, &old_termios); + if (tty->driver->set_termios) + tty->driver->set_termios(tty, &old_termios); } /* --- linux-2.6.24.orig/drivers/net/tehuti.c +++ linux-2.6.24/drivers/net/tehuti.c @@ -625,6 +625,12 @@ s_firmLoad[i] = CPU_CHIP_SWAP32(s_firmLoad[i]); } +static int bdx_range_check(struct bdx_priv *priv, u32 offset) +{ + return (offset > (u32) (BDX_REGS_SIZE / priv->nic->port_num)) ? + -EINVAL : 0; +} + static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) { struct bdx_priv *priv = ndev->priv; @@ -643,9 +649,15 @@ DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]); } + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + switch (data[0]) { case BDX_OP_READ: + error = bdx_range_check(priv, data[1]); + if (error < 0) + return error; data[2] = READ_REG(priv, data[1]); DBG("read_reg(0x%x)=0x%x (dec %d)\n", data[1], data[2], data[2]); @@ -655,6 +667,9 @@ break; case BDX_OP_WRITE: + error = bdx_range_check(priv, data[1]); + if (error < 0) + return error; WRITE_REG(priv, data[1], data[2]); DBG("write_reg(0x%x, 0x%x)\n", data[1], data[2]); break; --- linux-2.6.24.orig/drivers/net/irda/nsc-ircc.c +++ linux-2.6.24/drivers/net/irda/nsc-ircc.c @@ -149,7 +149,7 @@ static chipio_t pnp_info; static const struct pnp_device_id nsc_ircc_pnp_table[] = { { .id = "NSC6001", .driver_data = 0 }, - { .id = "IBM0071", .driver_data = 0 }, + { .id = "IBM0071", .driver_data = 1 }, { } }; @@ -928,6 +928,9 @@ * On my box, cfg_base is in the PnP descriptor of the * motherboard. Oh well... Jean II */ + if (id->driver_data == 1) + dongle_id = 0x9; + if (pnp_port_valid(dev, 0) && !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) pnp_info.fir_base = pnp_port_start(dev, 0); --- linux-2.6.24.orig/drivers/net/irda/irtty-sir.c +++ linux-2.6.24/drivers/net/irda/irtty-sir.c @@ -64,7 +64,9 @@ IRDA_ASSERT(priv != NULL, return -1;); IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); - return priv->tty->driver->chars_in_buffer(priv->tty); + if (priv->tty->driver->chars_in_buffer) + return priv->tty->driver->chars_in_buffer(priv->tty); + return 0; } /* Wait (sleep) until underlaying hardware finished transmission --- linux-2.6.24.orig/drivers/net/skfp/skfddi.c +++ linux-2.6.24/drivers/net/skfp/skfddi.c @@ -998,9 +998,9 @@ break; case SKFP_CLR_STATS: /* Zero out the driver statistics */ if (!capable(CAP_NET_ADMIN)) { - memset(&lp->MacStat, 0, sizeof(lp->MacStat)); - } else { status = -EPERM; + } else { + memset(&lp->MacStat, 0, sizeof(lp->MacStat)); } break; default: --- linux-2.6.24.orig/drivers/net/ppp_async.c +++ linux-2.6.24/drivers/net/ppp_async.c @@ -158,6 +158,9 @@ struct asyncppp *ap; int err; + if (!tty->driver->write) + return -EOPNOTSUPP; + err = -ENOMEM; ap = kzalloc(sizeof(*ap), GFP_KERNEL); if (!ap) --- linux-2.6.24.orig/drivers/net/slip.c +++ linux-2.6.24/drivers/net/slip.c @@ -463,9 +463,14 @@ /* 20 sec timeout not reached */ goto out; } - printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, - (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ? - "bad line quality" : "driver error"); + { + int cib = 0; + if (sl->tty->driver->chars_in_buffer) + cib = sl->tty->driver->chars_in_buffer(sl->tty); + printk(KERN_WARNING "%s: transmit timed out, %s?\n", + dev->name, (cib || sl->xleft) ? + "bad line quality" : "driver error"); + } sl->xleft = 0; sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); sl_unlock(sl); @@ -834,6 +839,8 @@ if(!capable(CAP_NET_ADMIN)) return -EPERM; + if (!tty->driver->write) + return -EOPNOTSUPP; /* RTnetlink lock is misused here to serialize concurrent opens of slip channels. There are better ways, but it is --- linux-2.6.24.orig/drivers/net/tulip/tulip.h +++ linux-2.6.24/drivers/net/tulip/tulip.h @@ -37,7 +37,10 @@ #define TULIP_BAR 0 /* CBIO */ #endif - +#ifndef PCI_ULI5261_ID +#define PCI_ULI5261_ID 0x526110B9 /* ULi M5261 ID*/ +#define PCI_ULI5263_ID 0x526310B9 /* ULi M5263 ID*/ +#endif struct tulip_chip_table { char *chip_name; --- linux-2.6.24.orig/drivers/net/tulip/tulip_core.c +++ linux-2.6.24/drivers/net/tulip/tulip_core.c @@ -230,8 +230,12 @@ { 0x1259, 0xa120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, + /* Ubuntu: On non-sparc, this seems to be handled better by the + * dmfe driver. */ +#ifdef __sparc__ { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, +#endif { 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, { 0x1113, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, @@ -394,6 +398,11 @@ goto media_picked; } } + if (tp->chip_id == PCI_ULI5261_ID || tp->chip_id == PCI_ULI5263_ID) { + for (i = tp->mtable->leafcount - 1; i >= 0; i--) + if (tulip_media_cap[tp->mtable->mleaf[i].media] & MediaIsMII) + goto media_picked; + } /* Start sensing first non-full-duplex media. */ for (i = tp->mtable->leafcount - 1; (tulip_media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--) --- linux-2.6.24.orig/drivers/net/tulip/media.c +++ linux-2.6.24/drivers/net/tulip/media.c @@ -519,10 +519,11 @@ /* Enable autonegotiation: some boards default to off. */ if (tp->default_port == 0) { new_bmcr = mii_reg0 | BMCR_ANENABLE; - if (new_bmcr != mii_reg0) { - new_bmcr |= BMCR_ANRESTART; - ane_switch = 1; - } + /* DM9161E PHY seems to need to restart + * autonegotiation even if it defaults to enabled. + */ + new_bmcr |= BMCR_ANRESTART; + ane_switch = 1; } /* ...or disable nway, if forcing media */ else { --- linux-2.6.24.orig/drivers/net/pppol2tp.c +++ linux-2.6.24/drivers/net/pppol2tp.c @@ -302,14 +302,14 @@ struct pppol2tp_session *session; struct hlist_node *walk; - read_lock(&tunnel->hlist_lock); + read_lock_bh(&tunnel->hlist_lock); hlist_for_each_entry(session, walk, session_list, hlist) { if (session->tunnel_addr.s_session == session_id) { - read_unlock(&tunnel->hlist_lock); + read_unlock_bh(&tunnel->hlist_lock); return session; } } - read_unlock(&tunnel->hlist_lock); + read_unlock_bh(&tunnel->hlist_lock); return NULL; } @@ -320,14 +320,14 @@ { struct pppol2tp_tunnel *tunnel = NULL; - read_lock(&pppol2tp_tunnel_list_lock); + read_lock_bh(&pppol2tp_tunnel_list_lock); list_for_each_entry(tunnel, &pppol2tp_tunnel_list, list) { if (tunnel->stats.tunnel_id == tunnel_id) { - read_unlock(&pppol2tp_tunnel_list_lock); + read_unlock_bh(&pppol2tp_tunnel_list_lock); return tunnel; } } - read_unlock(&pppol2tp_tunnel_list_lock); + read_unlock_bh(&pppol2tp_tunnel_list_lock); return NULL; } @@ -342,10 +342,11 @@ static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_buff *skb) { struct sk_buff *skbp; + struct sk_buff *tmp; u16 ns = PPPOL2TP_SKB_CB(skb)->ns; - spin_lock(&session->reorder_q.lock); - skb_queue_walk(&session->reorder_q, skbp) { + spin_lock_bh(&session->reorder_q.lock); + skb_queue_walk_safe(&session->reorder_q, skbp, tmp) { if (PPPOL2TP_SKB_CB(skbp)->ns > ns) { __skb_insert(skb, skbp->prev, skbp, &session->reorder_q); PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, @@ -360,7 +361,7 @@ __skb_queue_tail(&session->reorder_q, skb); out: - spin_unlock(&session->reorder_q.lock); + spin_unlock_bh(&session->reorder_q.lock); } /* Dequeue a single skb. @@ -371,10 +372,9 @@ int length = PPPOL2TP_SKB_CB(skb)->length; struct sock *session_sock = NULL; - /* We're about to requeue the skb, so unlink it and return resources + /* We're about to requeue the skb, so return resources * to its current owner (a socket receive buffer). */ - skb_unlink(skb, &session->reorder_q); skb_orphan(skb); tunnel->stats.rx_packets++; @@ -442,7 +442,7 @@ * expect to send up next, dequeue it and any other * in-sequence packets behind it. */ - spin_lock(&session->reorder_q.lock); + spin_lock_bh(&session->reorder_q.lock); skb_queue_walk_safe(&session->reorder_q, skb, tmp) { if (time_after(jiffies, PPPOL2TP_SKB_CB(skb)->expires)) { session->stats.rx_seq_discards++; @@ -469,13 +469,18 @@ goto out; } } - spin_unlock(&session->reorder_q.lock); + __skb_unlink(skb, &session->reorder_q); + + /* Process the skb. We release the queue lock while we + * do so to let other contexts process the queue. + */ + spin_unlock_bh(&session->reorder_q.lock); pppol2tp_recv_dequeue_skb(session, skb); - spin_lock(&session->reorder_q.lock); + spin_lock_bh(&session->reorder_q.lock); } out: - spin_unlock(&session->reorder_q.lock); + spin_unlock_bh(&session->reorder_q.lock); } /* Internal receive frame. Do the real work of receiving an L2TP data frame @@ -766,14 +771,18 @@ err = 0; skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &err); - if (skb) { - err = memcpy_toiovec(msg->msg_iov, (unsigned char *) skb->data, - skb->len); - if (err < 0) - goto do_skb_free; - err = skb->len; - } -do_skb_free: + if (!skb) + goto end; + + if (len > skb->len) + len = skb->len; + else if (len < skb->len) + msg->msg_flags |= MSG_TRUNC; + + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len); + if (likely(err == 0)) + err = len; + kfree_skb(skb); end: return err; @@ -1058,7 +1067,7 @@ /* Get routing info from the tunnel socket */ dst_release(skb->dst); - skb->dst = sk_dst_get(sk_tun); + skb->dst = dst_clone(__sk_dst_get(sk_tun)); skb_orphan(skb); skb->sk = sk_tun; @@ -1106,7 +1115,7 @@ PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, "%s: closing all sessions...\n", tunnel->name); - write_lock(&tunnel->hlist_lock); + write_lock_bh(&tunnel->hlist_lock); for (hash = 0; hash < PPPOL2TP_HASH_SIZE; hash++) { again: hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) { @@ -1126,7 +1135,7 @@ * disappear as we're jumping between locks. */ sock_hold(sk); - write_unlock(&tunnel->hlist_lock); + write_unlock_bh(&tunnel->hlist_lock); lock_sock(sk); if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { @@ -1148,11 +1157,11 @@ * list so we are guaranteed to make forward * progress. */ - write_lock(&tunnel->hlist_lock); + write_lock_bh(&tunnel->hlist_lock); goto again; } } - write_unlock(&tunnel->hlist_lock); + write_unlock_bh(&tunnel->hlist_lock); } /* Really kill the tunnel. @@ -1161,9 +1170,9 @@ static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel) { /* Remove from socket list */ - write_lock(&pppol2tp_tunnel_list_lock); + write_lock_bh(&pppol2tp_tunnel_list_lock); list_del_init(&tunnel->list); - write_unlock(&pppol2tp_tunnel_list_lock); + write_unlock_bh(&pppol2tp_tunnel_list_lock); atomic_dec(&pppol2tp_tunnel_count); kfree(tunnel); @@ -1239,9 +1248,9 @@ /* Delete the session socket from the * hash */ - write_lock(&tunnel->hlist_lock); + write_lock_bh(&tunnel->hlist_lock); hlist_del_init(&session->hlist); - write_unlock(&tunnel->hlist_lock); + write_unlock_bh(&tunnel->hlist_lock); atomic_dec(&pppol2tp_session_count); } @@ -1386,9 +1395,9 @@ /* Add tunnel to our list */ INIT_LIST_HEAD(&tunnel->list); - write_lock(&pppol2tp_tunnel_list_lock); + write_lock_bh(&pppol2tp_tunnel_list_lock); list_add(&tunnel->list, &pppol2tp_tunnel_list); - write_unlock(&pppol2tp_tunnel_list_lock); + write_unlock_bh(&pppol2tp_tunnel_list_lock); atomic_inc(&pppol2tp_tunnel_count); /* Bump the reference count. The tunnel context is deleted @@ -1593,11 +1602,11 @@ sk->sk_user_data = session; /* Add session to the tunnel's hash list */ - write_lock(&tunnel->hlist_lock); + write_lock_bh(&tunnel->hlist_lock); hlist_add_head(&session->hlist, pppol2tp_session_id_hash(tunnel, session->tunnel_addr.s_session)); - write_unlock(&tunnel->hlist_lock); + write_unlock_bh(&tunnel->hlist_lock); atomic_inc(&pppol2tp_session_count); @@ -2199,7 +2208,7 @@ int next = 0; int i; - read_lock(&tunnel->hlist_lock); + read_lock_bh(&tunnel->hlist_lock); for (i = 0; i < PPPOL2TP_HASH_SIZE; i++) { hlist_for_each_entry(session, walk, &tunnel->session_hlist[i], hlist) { if (curr == NULL) { @@ -2217,7 +2226,7 @@ } } out: - read_unlock(&tunnel->hlist_lock); + read_unlock_bh(&tunnel->hlist_lock); if (!found) session = NULL; @@ -2228,13 +2237,13 @@ { struct pppol2tp_tunnel *tunnel = NULL; - read_lock(&pppol2tp_tunnel_list_lock); + read_lock_bh(&pppol2tp_tunnel_list_lock); if (list_is_last(&curr->list, &pppol2tp_tunnel_list)) { goto out; } tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list); out: - read_unlock(&pppol2tp_tunnel_list_lock); + read_unlock_bh(&pppol2tp_tunnel_list_lock); return tunnel; } --- linux-2.6.24.orig/drivers/net/e1000e/netdev.c +++ linux-2.6.24/drivers/net/e1000e/netdev.c @@ -390,13 +390,22 @@ length = le16_to_cpu(rx_desc->length); /* !EOP means multiple descriptors were used to store a single - * packet, also make sure the frame isn't just CRC only */ - if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) { + * packet, if thats the case we need to toss it. In fact, we + * to toss every packet with the EOP bit clear and the next + * frame that _does_ have the EOP bit set, as it is by + * definition only a frame fragment + */ + if (unlikely(!(status & E1000_RXD_STAT_EOP))) + set_bit(__E1000_DISCARDING, &adapter->flags); + + if (test_bit(__E1000_DISCARDING, &adapter->flags)) { /* All receives must fit into a single buffer */ ndev_dbg(netdev, "%s: Receive packet consumed " "multiple buffers\n", netdev->name); /* recycle */ buffer_info->skb = skb; + if (status & E1000_RXD_STAT_EOP) + clear_bit(__E1000_DISCARDING, &adapter->flags); goto next_desc; } @@ -1686,6 +1695,9 @@ else rctl |= E1000_RCTL_LPE; + /* Enable hardware CRC frame stripping */ + rctl |= E1000_RCTL_SECRC; + /* Setup buffer sizes */ rctl &= ~E1000_RCTL_SZ_4096; rctl |= E1000_RCTL_BSEX; @@ -1751,9 +1763,6 @@ /* Enable Packet split descriptors */ rctl |= E1000_RCTL_DTYP_PS; - - /* Enable hardware CRC frame stripping */ - rctl |= E1000_RCTL_SECRC; psrctl |= adapter->rx_ps_bsize0 >> E1000_PSRCTL_BSIZE0_SHIFT; --- linux-2.6.24.orig/drivers/net/e1000e/e1000.h +++ linux-2.6.24/drivers/net/e1000e/e1000.h @@ -321,7 +321,8 @@ enum e1000_state_t { __E1000_TESTING, __E1000_RESETTING, - __E1000_DOWN + __E1000_DOWN, + __E1000_DISCARDING }; enum latency_range { --- linux-2.6.24.orig/drivers/net/niu.c +++ linux-2.6.24/drivers/net/niu.c @@ -33,8 +33,8 @@ #define DRV_MODULE_NAME "niu" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "0.6" -#define DRV_MODULE_RELDATE "January 5, 2008" +#define DRV_MODULE_VERSION "0.7" +#define DRV_MODULE_RELDATE "February 18, 2008" static char version[] __devinitdata = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; @@ -1616,12 +1616,13 @@ if (index >= niu_num_alt_addr(np)) return -EINVAL; - if (np->flags & NIU_FLAGS_XMAC) + if (np->flags & NIU_FLAGS_XMAC) { reg = XMAC_ADDR_CMPEN; - else + mask = 1 << index; + } else { reg = BMAC_ADDR_CMPEN; - - mask = 1 << index; + mask = 1 << (index + 1); + } val = nr64_mac(reg); if (on) @@ -5147,7 +5148,12 @@ index++; } } else { - for (i = 0; i < niu_num_alt_addr(np); i++) { + int alt_start; + if (np->flags & NIU_FLAGS_XMAC) + alt_start = 0; + else + alt_start = 1; + for (i = alt_start; i < niu_num_alt_addr(np); i++) { err = niu_enable_alt_mac(np, i, 0); if (err) printk(KERN_WARNING PFX "%s: Error %d " --- linux-2.6.24.orig/drivers/net/ppp_synctty.c +++ linux-2.6.24/drivers/net/ppp_synctty.c @@ -207,6 +207,9 @@ struct syncppp *ap; int err; + if (!tty->driver->write) + return -EOPNOTSUPP; + ap = kzalloc(sizeof(*ap), GFP_KERNEL); err = -ENOMEM; if (!ap) --- linux-2.6.24.orig/drivers/net/forcedeth.c +++ linux-2.6.24/drivers/net/forcedeth.c @@ -5666,3 +5666,5 @@ module_init(init_nic); module_exit(exit_nic); + + --- linux-2.6.24.orig/drivers/net/dl2k.h +++ linux-2.6.24/drivers/net/dl2k.h @@ -388,8 +388,8 @@ MII_MSSR_CFG_RES = 0x4000, MII_MSSR_LOCAL_RCV_STATUS = 0x2000, MII_MSSR_REMOTE_RCVR = 0x1000, - MII_MSSR_LP_1000BT_HD = 0x0800, - MII_MSSR_LP_1000BT_FD = 0x0400, + MII_MSSR_LP_1000BT_FD = 0x0800, + MII_MSSR_LP_1000BT_HD = 0x0400, MII_MSSR_IDLE_ERR_COUNT = 0x00ff, }; --- linux-2.6.24.orig/drivers/net/appletalk/ipddp.c +++ linux-2.6.24/drivers/net/appletalk/ipddp.c @@ -173,8 +173,7 @@ ((struct net_device_stats *) dev->priv)->tx_packets++; ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len; - if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) - dev_kfree_skb(skb); + aarp_send_ddp(rt->dev, skb, &rt->at, NULL); return 0; } --- linux-2.6.24.orig/drivers/net/cxgb3/t3_hw.c +++ linux-2.6.24/drivers/net/cxgb3/t3_hw.c @@ -1730,7 +1730,6 @@ MC7_INTR_MASK}, {A_MC5_DB_INT_ENABLE, MC5_INTR_MASK}, {A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK}, - {A_TP_INT_ENABLE, 0x3bfffff}, {A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK}, {A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK}, {A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK}, @@ -1740,6 +1739,8 @@ adapter->slow_intr_mask = PL_INTR_MASK; t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0); + t3_write_reg(adapter, A_TP_INT_ENABLE, + adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff); if (adapter->params.rev > 0) { t3_write_reg(adapter, A_CPL_INTR_ENABLE, --- linux-2.6.24.orig/drivers/net/sungem.c +++ linux-2.6.24/drivers/net/sungem.c @@ -910,7 +910,7 @@ * rx ring - must call napi_disable(), which * schedule_timeout()'s if polling is already disabled. */ - work_done += gem_rx(gp, budget); + work_done += gem_rx(gp, budget - work_done); if (work_done >= budget) return work_done; --- linux-2.6.24.orig/drivers/net/Kconfig +++ linux-2.6.24/drivers/net/Kconfig @@ -3064,6 +3064,7 @@ tristate "Virtio network driver (EXPERIMENTAL)" depends on EXPERIMENTAL && VIRTIO ---help--- - This is the virtual network driver for lguest. Say Y or M. + This is the virtual network driver for virtio. It can be used with + lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. endif # NETDEVICES --- linux-2.6.24.orig/drivers/net/macb.c +++ linux-2.6.24/drivers/net/macb.c @@ -148,7 +148,7 @@ if (phydev->duplex) reg |= MACB_BIT(FD); - if (phydev->speed) + if (phydev->speed == SPEED_100) reg |= MACB_BIT(SPD); macb_writel(bp, NCFGR, reg); @@ -1257,6 +1257,8 @@ if (dev) { bp = netdev_priv(dev); + if (bp->phy_dev) + phy_disconnect(bp->phy_dev); mdiobus_unregister(&bp->mii_bus); kfree(bp->mii_bus.irq); unregister_netdev(dev); --- linux-2.6.24.orig/drivers/net/bonding/bond_main.c +++ linux-2.6.24/drivers/net/bonding/bond_main.c @@ -4883,14 +4883,16 @@ down_write(&bonding_rwsem); /* Check to see if the bond already exists. */ - list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) - if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) { - printk(KERN_ERR DRV_NAME + if (name) { + list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) + if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) { + printk(KERN_ERR DRV_NAME ": cannot add bond %s; it already exists\n", - name); - res = -EPERM; - goto out_rtnl; - } + name); + res = -EPERM; + goto out_rtnl; + } + } bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", ether_setup); --- linux-2.6.24.orig/drivers/net/usb/asix.c +++ linux-2.6.24/drivers/net/usb/asix.c @@ -1437,6 +1437,10 @@ // Belkin F5D5055 USB_DEVICE(0x050d, 0x5055), .driver_info = (unsigned long) &ax88178_info, +}, { + // Apple USB Ethernet Adapter + USB_DEVICE(0x05ac, 0x1402), + .driver_info = (unsigned long) &ax88772_info, }, { }, // END }; --- linux-2.6.24.orig/drivers/net/usb/pegasus.c +++ linux-2.6.24/drivers/net/usb/pegasus.c @@ -1289,6 +1289,24 @@ } } +static int pegasus_blacklisted(struct usb_device *udev) +{ + struct usb_device_descriptor *udd = &udev->descriptor; + + /* Special quirk to keep the driver from handling the Belkin Bluetooth + * dongle which happens to have the same ID. + */ + if (udd->idVendor == VENDOR_BELKIN && udd->idProduct == 0x0121) { + if (udd->bDeviceClass == USB_CLASS_WIRELESS_CONTROLLER) { + if (udd->bDeviceProtocol == 1) { + return 1; + } + } + } + + return 0; +} + static int pegasus_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1300,6 +1318,12 @@ DECLARE_MAC_BUF(mac); usb_get_dev(dev); + + if (pegasus_blacklisted(dev)) { + res = -ENODEV; + goto out; + } + net = alloc_etherdev(sizeof(struct pegasus)); if (!net) { dev_err(&intf->dev, "can't allocate %s\n", "device"); --- linux-2.6.24.orig/drivers/net/usb/rndis_host.c +++ linux-2.6.24/drivers/net/usb/rndis_host.c @@ -499,6 +499,14 @@ net->hard_header_len += sizeof (struct rndis_data_hdr); dev->hard_mtu = net->mtu + net->hard_header_len; + dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1); + if (dev->maxpacket == 0) { + if (netif_msg_probe(dev)) + dev_dbg(&intf->dev, "dev->maxpacket can't be 0\n"); + retval = -EINVAL; + goto fail_and_release; + } + dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1); dev->rx_urb_size &= ~(dev->maxpacket - 1); u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size); --- linux-2.6.24.orig/drivers/net/sis190.c +++ linux-2.6.24/drivers/net/sis190.c @@ -311,6 +311,7 @@ unsigned int type; u32 feature; } mii_chip_table[] = { + { "Atheros PHY AR8012", { 0x004d, 0xd020 }, LAN, 0 }, { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 }, { "Broadcom PHY AC131", { 0x0143, 0xbc70 }, LAN, 0 }, { "Agere PHY ET1101B", { 0x0282, 0xf010 }, LAN, 0 }, @@ -1632,13 +1633,18 @@ static int sis190_get_mac_addr(struct pci_dev *pdev, struct net_device *dev) { - u8 from; + int rc; + + rc = sis190_get_mac_addr_from_eeprom(pdev, dev); + if (rc < 0) { + u8 reg; - pci_read_config_byte(pdev, 0x73, &from); + pci_read_config_byte(pdev, 0x73, ®); - return (from & 0x00000001) ? - sis190_get_mac_addr_from_apc(pdev, dev) : - sis190_get_mac_addr_from_eeprom(pdev, dev); + if (reg & 0x00000001) + rc = sis190_get_mac_addr_from_apc(pdev, dev); + } + return rc; } static void sis190_set_speed_auto(struct net_device *dev) --- linux-2.6.24.orig/drivers/net/sky2.c +++ linux-2.6.24/drivers/net/sky2.c @@ -119,6 +119,7 @@ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) }, /* 88E8038 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, /* 88E8039 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4354) }, /* 88E8040 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4355) }, /* 88E8040T */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4356) }, /* 88EC033 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4357) }, /* 88E8042 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x435A) }, /* 88E8048 */ @@ -3324,7 +3325,7 @@ default: gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); - gm_phy_write(hw, port, PHY_MARV_LED_OVER, + gm_phy_write(hw, port, PHY_MARV_LED_OVER, on ? PHY_M_LED_ALL : 0); } } @@ -4312,10 +4313,14 @@ if (!hw) return 0; + del_timer_sync(&hw->watchdog_timer); + cancel_work_sync(&hw->restart_work); + for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; struct sky2_port *sky2 = netdev_priv(dev); + netif_device_detach(dev); if (netif_running(dev)) sky2_down(dev); @@ -4366,6 +4371,8 @@ for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; + + netif_device_attach(dev); if (netif_running(dev)) { err = sky2_up(dev); if (err) { --- linux-2.6.24.orig/drivers/net/virtio_net.c +++ linux-2.6.24/drivers/net/virtio_net.c @@ -24,6 +24,13 @@ #include #include +static int napi_weight = 128; +module_param(napi_weight, int, 0444); + +static int csum = 1, gso = 1; +module_param(csum, bool, 0444); +module_param(gso, bool, 0444); + /* FIXME: MTU in config. */ #define MAX_PACKET_LEN (ETH_HLEN+ETH_DATA_LEN) @@ -52,13 +59,14 @@ sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr)); } -static bool skb_xmit_done(struct virtqueue *rvq) +static void skb_xmit_done(struct virtqueue *svq) { - struct virtnet_info *vi = rvq->vdev->priv; + struct virtnet_info *vi = svq->vdev->priv; - /* In case we were waiting for output buffers. */ + /* Suppress further interrupts. */ + svq->vq_ops->disable_cb(svq); + /* We were waiting for more output buffers. */ netif_wake_queue(vi->dev); - return true; } static void receive_skb(struct net_device *dev, struct sk_buff *skb, @@ -83,28 +91,16 @@ if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { pr_debug("Needs csum!\n"); - skb->ip_summed = CHECKSUM_PARTIAL; - skb->csum_start = hdr->csum_start; - skb->csum_offset = hdr->csum_offset; - if (skb->csum_start > skb->len - 2 - || skb->csum_offset > skb->len - 2) { - if (net_ratelimit()) - printk(KERN_WARNING "%s: csum=%u/%u len=%u\n", - dev->name, skb->csum_start, - skb->csum_offset, skb->len); + if (!skb_partial_csum_set(skb,hdr->csum_start,hdr->csum_offset)) goto frame_err; - } } if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { pr_debug("GSO!\n"); - switch (hdr->gso_type) { + switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { case VIRTIO_NET_HDR_GSO_TCPV4: skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; break; - case VIRTIO_NET_HDR_GSO_TCPV4_ECN: - skb_shinfo(skb)->gso_type = SKB_GSO_TCP_ECN; - break; case VIRTIO_NET_HDR_GSO_UDP: skb_shinfo(skb)->gso_type = SKB_GSO_UDP; break; @@ -118,6 +114,9 @@ goto frame_err; } + if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN) + skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; + skb_shinfo(skb)->gso_size = hdr->gso_size; if (skb_shinfo(skb)->gso_size == 0) { if (net_ratelimit()) @@ -170,12 +169,14 @@ vi->rvq->vq_ops->kick(vi->rvq); } -static bool skb_recv_done(struct virtqueue *rvq) +static void skb_recv_done(struct virtqueue *rvq) { struct virtnet_info *vi = rvq->vdev->priv; - netif_rx_schedule(vi->dev, &vi->napi); - /* Suppress further interrupts. */ - return false; + /* Schedule NAPI, Suppress further interrupts if successful. */ + if (netif_rx_schedule_prep(vi->dev, &vi->napi)) { + rvq->vq_ops->disable_cb(rvq); + __netif_rx_schedule(vi->dev, &vi->napi); + } } static int virtnet_poll(struct napi_struct *napi, int budget) @@ -201,9 +202,12 @@ /* Out of packets? */ if (received < budget) { netif_rx_complete(vi->dev, napi); - if (unlikely(!vi->rvq->vq_ops->restart(vi->rvq)) - && netif_rx_reschedule(vi->dev, napi)) + if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq)) + && napi_schedule_prep(napi)) { + vi->rvq->vq_ops->disable_cb(vi->rvq); + __netif_rx_schedule(vi->dev, napi); goto again; + } } return received; @@ -236,8 +240,6 @@ pr_debug("%s: xmit %p %s\n", dev->name, skb, print_mac(mac, dest)); - free_old_xmit_skbs(vi); - /* Encode metadata header at front. */ hdr = skb_vnet_hdr(skb); if (skb->ip_summed == CHECKSUM_PARTIAL) { @@ -250,10 +252,9 @@ } if (skb_is_gso(skb)) { + hdr->hdr_len = skb_transport_header(skb) - skb->data; hdr->gso_size = skb_shinfo(skb)->gso_size; - if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN) - hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4_ECN; - else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) + if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; @@ -261,19 +262,34 @@ hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP; else BUG(); + if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN) + hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN; } else { hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE; - hdr->gso_size = 0; + hdr->gso_size = hdr->hdr_len = 0; } vnet_hdr_to_sg(sg, skb); num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; __skb_queue_head(&vi->send, skb); + +again: + /* Free up any pending old buffers before queueing new ones. */ + free_old_xmit_skbs(vi); err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); if (err) { pr_debug("%s: virtio not prepared to send\n", dev->name); - skb_unlink(skb, &vi->send); netif_stop_queue(dev); + + /* Activate callback for using skbs: if this returns false it + * means some were used in the meantime. */ + if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) { + vi->svq->vq_ops->disable_cb(vi->svq); + netif_start_queue(dev); + goto again; + } + __skb_unlink(skb, &vi->send); + return NETDEV_TX_BUSY; } vi->svq->vq_ops->kick(vi->svq); @@ -281,49 +297,46 @@ return 0; } -static int virtnet_open(struct net_device *dev) +#ifdef CONFIG_NET_POLL_CONTROLLER +static void virtnet_netpoll(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); - try_fill_recv(vi); + napi_schedule(&vi->napi); +} +#endif - /* If we didn't even get one input buffer, we're useless. */ - if (vi->num == 0) - return -ENOMEM; +static int virtnet_open(struct net_device *dev) +{ + struct virtnet_info *vi = netdev_priv(dev); napi_enable(&vi->napi); + + /* If all buffers were filled by other side before we napi_enabled, we + * won't get another interrupt, so process any outstanding packets + * now. virtnet_poll wants re-enable the queue, so we disable here. + * We synchronize against interrupts via NAPI_STATE_SCHED */ + if (netif_rx_schedule_prep(dev, &vi->napi)) { + vi->rvq->vq_ops->disable_cb(vi->rvq); + __netif_rx_schedule(dev, &vi->napi); + } return 0; } static int virtnet_close(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); - struct sk_buff *skb; napi_disable(&vi->napi); - /* networking core has neutered skb_xmit_done/skb_recv_done, so don't - * worry about races vs. get(). */ - vi->rvq->vq_ops->shutdown(vi->rvq); - while ((skb = __skb_dequeue(&vi->recv)) != NULL) { - kfree_skb(skb); - vi->num--; - } - vi->svq->vq_ops->shutdown(vi->svq); - while ((skb = __skb_dequeue(&vi->send)) != NULL) - kfree_skb(skb); - - BUG_ON(vi->num != 0); return 0; } static int virtnet_probe(struct virtio_device *vdev) { int err; - unsigned int len; struct net_device *dev; struct virtnet_info *vi; - void *token; /* Allocate ourselves a network device with room for our info */ dev = alloc_etherdev(sizeof(struct virtnet_info)); @@ -331,50 +344,48 @@ return -ENOMEM; /* Set up network device as normal. */ - ether_setup(dev); dev->open = virtnet_open; dev->stop = virtnet_close; dev->hard_start_xmit = start_xmit; dev->features = NETIF_F_HIGHDMA; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = virtnet_netpoll; +#endif SET_NETDEV_DEV(dev, &vdev->dev); /* Do we support "hardware" checksums? */ - token = vdev->config->find(vdev, VIRTIO_CONFIG_NET_F, &len); - if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_NO_CSUM)) { + if (csum && vdev->config->feature(vdev, VIRTIO_NET_F_CSUM)) { /* This opens up the world of extra features. */ dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; - if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO4)) - dev->features |= NETIF_F_TSO; - if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_UFO)) - dev->features |= NETIF_F_UFO; - if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO4_ECN)) - dev->features |= NETIF_F_TSO_ECN; - if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO6)) - dev->features |= NETIF_F_TSO6; + if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_GSO)) { + dev->features |= NETIF_F_TSO | NETIF_F_UFO + | NETIF_F_TSO_ECN | NETIF_F_TSO6; + } } /* Configuration may specify what MAC to use. Otherwise random. */ - token = vdev->config->find(vdev, VIRTIO_CONFIG_NET_MAC_F, &len); - if (token) { - dev->addr_len = len; - vdev->config->get(vdev, token, dev->dev_addr, len); + if (vdev->config->feature(vdev, VIRTIO_NET_F_MAC)) { + vdev->config->get(vdev, + offsetof(struct virtio_net_config, mac), + dev->dev_addr, dev->addr_len); } else random_ether_addr(dev->dev_addr); /* Set up our device-specific information */ vi = netdev_priv(dev); - netif_napi_add(dev, &vi->napi, virtnet_poll, 16); + netif_napi_add(dev, &vi->napi, virtnet_poll, napi_weight); vi->dev = dev; vi->vdev = vdev; + vdev->priv = vi; /* We expect two virtqueues, receive then send. */ - vi->rvq = vdev->config->find_vq(vdev, skb_recv_done); + vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done); if (IS_ERR(vi->rvq)) { err = PTR_ERR(vi->rvq); goto free; } - vi->svq = vdev->config->find_vq(vdev, skb_xmit_done); + vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done); if (IS_ERR(vi->svq)) { err = PTR_ERR(vi->svq); goto free_recv; @@ -389,10 +400,21 @@ pr_debug("virtio_net: registering device failed\n"); goto free_send; } + + /* Last of all, set up some receive buffers. */ + try_fill_recv(vi); + + /* If we didn't even get one input buffer, we're useless. */ + if (vi->num == 0) { + err = -ENOMEM; + goto unregister; + } + pr_debug("virtnet: registered device %s\n", dev->name); - vdev->priv = vi; return 0; +unregister: + unregister_netdev(dev); free_send: vdev->config->del_vq(vi->svq); free_recv: @@ -405,6 +427,20 @@ static void virtnet_remove(struct virtio_device *vdev) { struct virtnet_info *vi = vdev->priv; + struct sk_buff *skb; + + /* Stop all the virtqueues. */ + vdev->config->reset(vdev); + + /* Free our skbs in send and recv queues, if any. */ + while ((skb = __skb_dequeue(&vi->recv)) != NULL) { + kfree_skb(skb); + vi->num--; + } + while ((skb = __skb_dequeue(&vi->send)) != NULL) + kfree_skb(skb); + + BUG_ON(vi->num != 0); vdev->config->del_vq(vi->svq); vdev->config->del_vq(vi->rvq); --- linux-2.6.24.orig/drivers/net/niu.h +++ linux-2.6.24/drivers/net/niu.h @@ -499,7 +499,7 @@ #define BMAC_ADDR2 0x00110UL #define BMAC_ADDR2_ADDR2 0x000000000000ffffULL -#define BMAC_NUM_ALT_ADDR 7 +#define BMAC_NUM_ALT_ADDR 6 #define BMAC_ALT_ADDR0(NUM) (0x00118UL + (NUM)*0x18UL) #define BMAC_ALT_ADDR0_ADDR0 0x000000000000ffffULL --- linux-2.6.24.orig/drivers/net/wan/sbni.c +++ linux-2.6.24/drivers/net/wan/sbni.c @@ -1317,7 +1317,7 @@ break; case SIOCDEVRESINSTATS : - if( current->euid != 0 ) /* root only */ + if (!capable(CAP_NET_ADMIN)) return -EPERM; memset( &nl->in_stats, 0, sizeof(struct sbni_in_stats) ); break; @@ -1334,7 +1334,7 @@ break; case SIOCDEVSHWSTATE : - if( current->euid != 0 ) /* root only */ + if (!capable(CAP_NET_ADMIN)) return -EPERM; spin_lock( &nl->lock ); @@ -1355,7 +1355,7 @@ #ifdef CONFIG_SBNI_MULTILINE case SIOCDEVENSLAVE : - if( current->euid != 0 ) /* root only */ + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user( slave_name, ifr->ifr_data, sizeof slave_name )) @@ -1370,7 +1370,7 @@ return enslave( dev, slave_dev ); case SIOCDEVEMANSIPATE : - if( current->euid != 0 ) /* root only */ + if (!capable(CAP_NET_ADMIN)) return -EPERM; return emancipate( dev ); --- linux-2.6.24.orig/drivers/net/wan/x25_asy.c +++ linux-2.6.24/drivers/net/wan/x25_asy.c @@ -283,6 +283,10 @@ static void x25_asy_timeout(struct net_device *dev) { struct x25_asy *sl = (struct x25_asy*)(dev->priv); + int cib = 0; + + if (sl->tty->driver->chars_in_buffer) + cib = sl->tty->driver->chars_in_buffer(sl->tty); spin_lock(&sl->lock); if (netif_queue_stopped(dev)) { @@ -290,8 +294,7 @@ * 14 Oct 1994 Dmitry Gorodchanin. */ printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, - (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ? - "bad line quality" : "driver error"); + (cib || sl->xleft) ? "bad line quality" : "driver error"); sl->xleft = 0; sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); x25_asy_unlock(sl); @@ -561,6 +564,9 @@ return -EEXIST; } + if (!tty->driver->write) + return -EOPNOTSUPP; + /* OK. Find a free X.25 channel to use. */ if ((sl = x25_asy_alloc()) == NULL) { return -ENFILE; --- linux-2.6.24.orig/drivers/net/plip.c +++ linux-2.6.24/drivers/net/plip.c @@ -903,17 +903,18 @@ struct net_local *nl; struct plip_local *rcv; unsigned char c0; + unsigned long flags; nl = netdev_priv(dev); rcv = &nl->rcv_data; - spin_lock_irq (&nl->lock); + spin_lock_irqsave (&nl->lock, flags); c0 = read_status(dev); if ((c0 & 0xf8) != 0xc0) { if ((dev->irq != -1) && (net_debug > 1)) printk(KERN_DEBUG "%s: spurious interrupt\n", dev->name); - spin_unlock_irq (&nl->lock); + spin_unlock_irqrestore (&nl->lock, flags); return; } @@ -942,7 +943,7 @@ break; } - spin_unlock_irq(&nl->lock); + spin_unlock_irqrestore(&nl->lock, flags); } static int --- linux-2.6.24.orig/drivers/net/pcmcia/smc91c92_cs.c +++ linux-2.6.24/drivers/net/pcmcia/smc91c92_cs.c @@ -559,8 +559,16 @@ /* Read the station address from the CIS. It is stored as the last (fourth) string in the Version 1 Version/ID tuple. */ - if (link->prod_id[3]) { - station_addr = link->prod_id[3]; + tuple->DesiredTuple = CISTPL_VERS_1; + if (first_tuple(link, tuple, parse) != CS_SUCCESS) { + rc = -1; + goto free_cfg_mem; + } + /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ + if (next_tuple(link, tuple, parse) != CS_SUCCESS) + first_tuple(link, tuple, parse); + if (parse->version_1.ns > 3) { + station_addr = parse->version_1.str + parse->version_1.ofs[3]; if (cvt_ascii_address(dev, station_addr) == 0) { rc = 0; goto free_cfg_mem; --- linux-2.6.24.orig/drivers/net/sunvnet.c +++ linux-2.6.24/drivers/net/sunvnet.c @@ -201,15 +201,9 @@ struct sk_buff *skb; int err; - err = -EMSGSIZE; - if (unlikely(len < ETH_ZLEN || len > ETH_FRAME_LEN)) { - dev->stats.rx_length_errors++; - goto out_dropped; - } - skb = alloc_and_align_skb(dev, len); err = -ENOMEM; - if (unlikely(!skb)) { + if (!skb) { dev->stats.rx_missed_errors++; goto out_dropped; } @@ -219,7 +213,7 @@ err = ldc_copy(port->vio.lp, LDC_COPY_IN, skb->data, copy_len, 0, cookies, ncookies); - if (unlikely(err < 0)) { + if (err < 0) { dev->stats.rx_frame_errors++; goto out_free_skb; } --- linux-2.6.24.orig/drivers/net/r8169.c +++ linux-2.6.24/drivers/net/r8169.c @@ -77,11 +77,11 @@ /* MAC address length */ #define MAC_ADDR_LEN 6 +#define MAX_READ_REQUEST_SHIFT 12 #define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */ #define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ #define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ #define EarlyTxThld 0x3F /* 0x3F means NO early transmit */ -#define RxPacketMaxSize 0x3FE8 /* 16K - 1 - ETH_HLEN - VLAN - CRC... */ #define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */ #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ @@ -111,6 +111,10 @@ RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe + RTL_GIGA_MAC_VER_07 = 0x07, // 8102e + RTL_GIGA_MAC_VER_08 = 0x08, // 8102e + RTL_GIGA_MAC_VER_09 = 0x09, // 8102e + RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb @@ -137,6 +141,10 @@ _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe + _R("RTL8102e", RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E + _R("RTL8102e", RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E + _R("RTL8102e", RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139 @@ -212,9 +220,6 @@ Config5 = 0x56, MultiIntr = 0x5c, PHYAR = 0x60, - TBICSR = 0x64, - TBI_ANAR = 0x68, - TBI_LPAR = 0x6a, PHYstatus = 0x6c, RxMaxSize = 0xda, CPlusCmd = 0xe0, @@ -228,6 +233,32 @@ FuncForceEvent = 0xfc, }; +enum rtl8110_registers { + TBICSR = 0x64, + TBI_ANAR = 0x68, + TBI_LPAR = 0x6a, +}; + +enum rtl8168_8101_registers { + CSIDR = 0x64, + CSIAR = 0x68, +#define CSIAR_FLAG 0x80000000 +#define CSIAR_WRITE_CMD 0x80000000 +#define CSIAR_BYTE_ENABLE 0x0f +#define CSIAR_BYTE_ENABLE_SHIFT 12 +#define CSIAR_ADDR_MASK 0x0fff + + EPHYAR = 0x80, +#define EPHYAR_FLAG 0x80000000 +#define EPHYAR_WRITE_CMD 0x80000000 +#define EPHYAR_REG_MASK 0x1f +#define EPHYAR_REG_SHIFT 16 +#define EPHYAR_DATA_MASK 0xffff + DBG_REG = 0xd1, +#define FIX_NAK_1 (1 << 4) +#define FIX_NAK_2 (1 << 3) +}; + enum rtl_register_content { /* InterruptStatusBits */ SYSErr = 0x8000, @@ -281,7 +312,13 @@ TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ /* Config1 register p.24 */ + LEDS1 = (1 << 7), + LEDS0 = (1 << 6), MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */ + Speed_down = (1 << 4), + MEMMAP = (1 << 3), + IOMAP = (1 << 2), + VPD = (1 << 1), PMEnable = (1 << 0), /* Power Management Enable */ /* Config2 register p. 25 */ @@ -291,6 +328,7 @@ /* Config3 register p.25 */ MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */ LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */ + Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */ /* Config5 register p.27 */ BWF = (1 << 6), /* Accept Broadcast wakeup frame */ @@ -308,7 +346,16 @@ TBINwComplete = 0x01000000, /* CPlusCmd p.31 */ - PktCntrDisable = (1 << 7), // 8168 + EnableBist = (1 << 15), // 8168 8101 + Mac_dbgo_oe = (1 << 14), // 8168 8101 + Normal_mode = (1 << 13), // unused + Force_half_dup = (1 << 12), // 8168 8101 + Force_rxflow_en = (1 << 11), // 8168 8101 + Force_txflow_en = (1 << 10), // 8168 8101 + Cxpl_dbg_sel = (1 << 9), // 8168 8101 + ASF = (1 << 8), // 8168 8101 + PktCntrDisable = (1 << 7), // 8168 8101 + Mac_dbgo_sel = 0x001c, // 8168 RxVlan = (1 << 6), RxChkSum = (1 << 5), PCIDAC = (1 << 4), @@ -429,6 +476,7 @@ void (*hw_start)(struct net_device *); unsigned int (*phy_reset_pending)(void __iomem *); unsigned int (*link_ok)(void __iomem *); + int pcie_cap; struct delayed_work task; unsigned features; }; @@ -503,6 +551,77 @@ return value; } +static void mdio_patch(void __iomem *ioaddr, int reg_addr, int value) +{ + mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value); +} + +static void rtl_ephy_write(void __iomem *ioaddr, int reg_addr, int value) +{ + unsigned int i; + + RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) | + (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); + + for (i = 0; i < 100; i++) { + if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG)) + break; + udelay(10); + } +} + +static u16 rtl_ephy_read(void __iomem *ioaddr, int reg_addr) +{ + u16 value = 0xffff; + unsigned int i; + + RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); + + for (i = 0; i < 100; i++) { + if (RTL_R32(EPHYAR) & EPHYAR_FLAG) { + value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK; + break; + } + udelay(10); + } + + return value; +} + +static void rtl_csi_write(void __iomem *ioaddr, int addr, int value) +{ + unsigned int i; + + RTL_W32(CSIDR, value); + RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); + + for (i = 0; i < 100; i++) { + if (!(RTL_R32(CSIAR) & CSIAR_FLAG)) + break; + udelay(10); + } +} + +static u32 rtl_csi_read(void __iomem *ioaddr, int addr) +{ + u32 value = ~0x00; + unsigned int i; + + RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); + + for (i = 0; i < 100; i++) { + if (RTL_R32(CSIAR) & CSIAR_FLAG) { + value = RTL_R32(CSIDR); + break; + } + udelay(10); + } + + return value; +} + static void rtl8169_irq_mask_and_ack(void __iomem *ioaddr) { RTL_W16(IntrMask, 0x0000); @@ -726,8 +845,12 @@ } } - /* The 8100e/8101e do Fast Ethernet only. */ - if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || + /* The 8100e/8101e/8102e do Fast Ethernet only. */ + if ((tp->mac_version == RTL_GIGA_MAC_VER_07) || + (tp->mac_version == RTL_GIGA_MAC_VER_08) || + (tp->mac_version == RTL_GIGA_MAC_VER_09) || + (tp->mac_version == RTL_GIGA_MAC_VER_10) || + (tp->mac_version == RTL_GIGA_MAC_VER_13) || (tp->mac_version == RTL_GIGA_MAC_VER_14) || (tp->mac_version == RTL_GIGA_MAC_VER_15) || (tp->mac_version == RTL_GIGA_MAC_VER_16)) { @@ -1136,9 +1259,22 @@ { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, /* 8101 family. */ + { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 }, + { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 }, + { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 }, + { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 }, + { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 }, + { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 }, { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 }, + { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 }, { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 }, + { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 }, + { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 }, { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 }, + /* 8102EL */ + { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_16 }, + /* 8102E */ + { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_16 }, /* FIXME: where did these entries come from ? -- FR */ { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 }, { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 }, @@ -1299,6 +1435,37 @@ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } +static void rtl8101_hw_phy_config(void __iomem *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0000 }, + { 0x11, mdio_read(ioaddr,0x11) | 0x1000 }, + { 0x19, mdio_read(ioaddr,0x19) | 0x2000 }, + { 0x1f, 0x0003 }, + { 0x08, 0x441D }, + { 0x01, 0x9100 }, + { 0x1f, 0x0000 } + }; + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); +} + +static void rtl8102e_hw_phy_config(void __iomem *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0003 }, + { 0x08, 0x441d }, + { 0x01, 0x9100 }, + { 0x1f, 0x0000 } + }; + + mdio_write(ioaddr, 0x1f, 0x0000); + mdio_patch(ioaddr, 0x11, 1 << 12); + mdio_patch(ioaddr, 0x19, 1 << 13); + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); +} + static void rtl_hw_phy_config(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -1316,6 +1483,14 @@ case RTL_GIGA_MAC_VER_04: rtl8169sb_hw_phy_config(ioaddr); break; + case RTL_GIGA_MAC_VER_07: + case RTL_GIGA_MAC_VER_08: + case RTL_GIGA_MAC_VER_09: + rtl8102e_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_13: + case RTL_GIGA_MAC_VER_16: + rtl8101_hw_phy_config(ioaddr); case RTL_GIGA_MAC_VER_18: rtl8168cp_hw_phy_config(ioaddr); break; @@ -1438,8 +1613,10 @@ rtl_hw_phy_config(dev); - dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); - RTL_W8(0x82, 0x01); + if (tp->mac_version <= RTL_GIGA_MAC_VER_06) { + dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + RTL_W8(0x82, 0x01); + } pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40); @@ -1617,6 +1794,7 @@ SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); tp->dev = dev; + tp->pci_dev = pdev; tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT); /* enable device (incl. PCI PM wakeup and hotplug setup) */ @@ -1687,6 +1865,10 @@ goto err_out_free_res_4; } + tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (!tp->pcie_cap && netif_msg_probe(tp)) + dev_info(&pdev->dev, "no PCI Express capability\n"); + /* Unneeded ? Don't mess with Mrs. Murphy. */ rtl8169_irq_mask_and_ack(ioaddr); @@ -1776,8 +1958,14 @@ dev->poll_controller = rtl8169_netpoll; #endif + /* Ubuntu temporary workaround for bug #76489, disable + * NETIF_F_TSO by default for RTL8111/8168B chipsets. + * People can re-enable if required */ + if (tp->mac_version == RTL_GIGA_MAC_VER_11 + || tp->mac_version == RTL_GIGA_MAC_VER_12) + dev->features &= ~NETIF_F_TSO; + tp->intr_mask = 0xffff; - tp->pci_dev = pdev; tp->mmio_addr = ioaddr; tp->align = cfg->align; tp->hw_start = cfg->hw_start; @@ -1980,10 +2168,10 @@ return cmd; } -static void rtl_set_rx_max_size(void __iomem *ioaddr) +static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz) { /* Low hurts. Let's disable the filtering. */ - RTL_W16(RxMaxSize, 16383); + RTL_W16(RxMaxSize, rx_buf_sz); } static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version) @@ -2030,7 +2218,7 @@ RTL_W8(EarlyTxThres, EarlyTxThld); - rtl_set_rx_max_size(ioaddr); + rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz); if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || (tp->mac_version == RTL_GIGA_MAC_VER_02) || @@ -2083,18 +2271,57 @@ RTL_W16(IntrMask, tp->intr_event); } +static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rtl8169_private *tp = netdev_priv(dev); + int cap = tp->pcie_cap; + + if (cap) { + u16 ctl; + + pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl); + ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force; + pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl); + } +} + +static void rtl_csi_access_enable(void __iomem *ioaddr) +{ + u32 csi; + + csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff; + rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000); +} + +struct ephy_info { + unsigned int offset; + u16 mask; + u16 bits; +}; + +static void rtl_ephy_init(void __iomem *ioaddr, struct ephy_info *e, int len) +{ + u16 w; + + while (len-- > 0) { + w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits; + rtl_ephy_write(ioaddr, e->offset, w); + e++; + } +} + static void rtl_hw_start_8168(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; struct pci_dev *pdev = tp->pci_dev; - u8 ctl; RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(EarlyTxThres, EarlyTxThld); - rtl_set_rx_max_size(ioaddr); + rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz); rtl_set_rx_tx_config_registers(tp); @@ -2102,10 +2329,7 @@ RTL_W16(CPlusCmd, tp->cp_cmd); - /* Tx performance tweak. */ - pci_read_config_byte(pdev, 0x69, &ctl); - ctl = (ctl & ~0x70) | 0x50; - pci_write_config_byte(pdev, 0x69, ctl); + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); RTL_W16(IntrMitigate, 0x5151); @@ -2121,8 +2345,6 @@ RTL_R8(IntrMask); - RTL_W32(RxMissed, 0); - rtl_set_rx_mode(dev); RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); @@ -2132,6 +2354,70 @@ RTL_W16(IntrMask, tp->intr_event); } +#define R810X_CPCMD_QUIRK_MASK (\ + EnableBist | \ + Mac_dbgo_oe | \ + Force_half_dup | \ + Force_half_dup | \ + Force_txflow_en | \ + Cxpl_dbg_sel | \ + ASF | \ + PktCntrDisable | \ + PCIDAC | \ + PCIMulRW) + +static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev) +{ + static struct ephy_info e_info_8102e_1[] = { + { 0x01, 0, 0x6e65 }, + { 0x02, 0, 0x091f }, + { 0x03, 0, 0xc2f9 }, + { 0x06, 0, 0xafb5 }, + { 0x07, 0, 0x0e00 }, + { 0x19, 0, 0xec80 }, + { 0x01, 0, 0x2e65 }, + { 0x01, 0, 0x6e65 } + }; + u8 cfg1; + + rtl_csi_access_enable(ioaddr); + + RTL_W8(DBG_REG, FIX_NAK_1); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(Config1, + LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable); + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + cfg1 = RTL_R8(Config1); + if ((cfg1 & LEDS0) && (cfg1 & LEDS1)) + RTL_W8(Config1, cfg1 & ~LEDS0); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK); + + rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1)); +} + +static void rtl_hw_start_8102e_2(void __iomem *ioaddr, struct pci_dev *pdev) +{ + rtl_csi_access_enable(ioaddr); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable); + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8102e_3(void __iomem *ioaddr, struct pci_dev *pdev) +{ + rtl_hw_start_8102e_2(ioaddr, pdev); + + rtl_ephy_write(ioaddr, 0x03, 0xc2f9); +} + static void rtl_hw_start_8101(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -2140,15 +2426,33 @@ if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || (tp->mac_version == RTL_GIGA_MAC_VER_16)) { - pci_write_config_word(pdev, 0x68, 0x00); - pci_write_config_word(pdev, 0x69, 0x08); + int cap = tp->pcie_cap; + + if (cap) { + pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_NOSNOOP_EN); + } + } + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_07: + rtl_hw_start_8102e_1(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_08: + rtl_hw_start_8102e_3(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_09: + rtl_hw_start_8102e_2(ioaddr, pdev); + break; } RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(EarlyTxThres, EarlyTxThld); - rtl_set_rx_max_size(ioaddr); + rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz); tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; @@ -2165,8 +2469,6 @@ RTL_R8(IntrMask); - RTL_W32(RxMissed, 0); - rtl_set_rx_mode(dev); RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); @@ -2564,13 +2866,6 @@ opts1 |= FirstFrag; } else { len = skb->len; - - if (unlikely(len < ETH_ZLEN)) { - if (skb_padto(skb, ETH_ZLEN)) - goto err_update_stats; - len = ETH_ZLEN; - } - opts1 |= FirstFrag | LastFrag; tp->tx_skb[entry].skb = skb; } @@ -2608,7 +2903,6 @@ err_stop: netif_stop_queue(dev); ret = NETDEV_TX_BUSY; -err_update_stats: dev->stats.tx_dropped++; goto out; } @@ -2820,7 +3114,7 @@ pkt_size, PCI_DMA_FROMDEVICE); rtl8169_mark_to_asic(desc, tp->rx_buf_sz); } else { - pci_unmap_single(pdev, addr, pkt_size, + pci_unmap_single(pdev, addr, tp->rx_buf_sz, PCI_DMA_FROMDEVICE); tp->Rx_skbuff[entry] = NULL; } @@ -2977,6 +3271,17 @@ } #endif +static void rtl8169_rx_missed(struct net_device *dev, void __iomem *ioaddr) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + if (tp->mac_version > RTL_GIGA_MAC_VER_06) + return; + + dev->stats.rx_missed_errors += (RTL_R32(RxMissed) & 0xffffff); + RTL_W32(RxMissed, 0); +} + static void rtl8169_down(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -2996,9 +3301,7 @@ rtl8169_asic_down(ioaddr); - /* Update the error counts. */ - dev->stats.rx_missed_errors += RTL_R32(RxMissed); - RTL_W32(RxMissed, 0); + rtl8169_rx_missed(dev, ioaddr); spin_unlock_irq(&tp->lock); @@ -3124,8 +3427,7 @@ if (netif_running(dev)) { spin_lock_irqsave(&tp->lock, flags); - dev->stats.rx_missed_errors += RTL_R32(RxMissed); - RTL_W32(RxMissed, 0); + rtl8169_rx_missed(dev, ioaddr); spin_unlock_irqrestore(&tp->lock, flags); } @@ -3150,8 +3452,7 @@ rtl8169_asic_down(ioaddr); - dev->stats.rx_missed_errors += RTL_R32(RxMissed); - RTL_W32(RxMissed, 0); + rtl8169_rx_missed(dev, ioaddr); spin_unlock_irq(&tp->lock); --- linux-2.6.24.orig/drivers/net/e1000/e1000.h +++ linux-2.6.24/drivers/net/e1000/e1000.h @@ -348,7 +348,8 @@ enum e1000_state_t { __E1000_TESTING, __E1000_RESETTING, - __E1000_DOWN + __E1000_DOWN, + __E1000_DISCARDING }; extern char e1000_driver_name[]; --- linux-2.6.24.orig/drivers/net/e1000/e1000_main.c +++ linux-2.6.24/drivers/net/e1000/e1000_main.c @@ -218,6 +218,10 @@ MODULE_PARM_DESC(copybreak, "Maximum size of packet that is copied to a new buffer on receive"); +static int eeprom_bad_csum_allow __read_mostly = 0; +module_param(eeprom_bad_csum_allow, int, 0); +MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad EEPROM checksums"); + static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state); static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev); @@ -1001,16 +1005,19 @@ goto err_eeprom; } - /* before reading the EEPROM, reset the controller to - * put the device in a known good starting state */ + if (e1000_validate_eeprom_checksum(&adapter->hw) < 0) { + /* before reading the EEPROM, reset the controller to + * put the device in a known good starting state */ - e1000_reset_hw(&adapter->hw); + e1000_reset_hw(&adapter->hw); - /* make sure the EEPROM is good */ + /* make sure the EEPROM is good */ - if (e1000_validate_eeprom_checksum(&adapter->hw) < 0) { - DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n"); - goto err_eeprom; + if (e1000_validate_eeprom_checksum(&adapter->hw) < 0) { + DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n"); + if (!eeprom_bad_csum_allow) + goto err_eeprom; + } } /* copy the MAC address out of the EEPROM */ @@ -4173,13 +4180,23 @@ PCI_DMA_FROMDEVICE); length = le16_to_cpu(rx_desc->length); + /* !EOP means multiple descriptors were used to store a single + * packet, if thats the case we need to toss it. In fact, we + * to toss every packet with the EOP bit clear and the next + * frame that _does_ have the EOP bit set, as it is by + * definition only a frame fragment + */ + if (unlikely(!(status & E1000_RXD_STAT_EOP))) + set_bit(__E1000_DISCARDING, &adapter->flags); - if (unlikely(!(status & E1000_RXD_STAT_EOP))) { + if (test_bit(__E1000_DISCARDING, &adapter->flags)) { /* All receives must fit into a single buffer */ E1000_DBG("%s: Receive packet consumed multiple" " buffers\n", netdev->name); /* recycle */ buffer_info->skb = skb; + if (status & E1000_RXD_STAT_EOP) + clear_bit(__E1000_DISCARDING, &adapter->flags); goto next_desc; } --- linux-2.6.24.orig/drivers/lguest/page_tables.c +++ linux-2.6.24/drivers/lguest/page_tables.c @@ -94,10 +94,10 @@ /* These two functions just like the above two, except they access the Guest * page tables. Hence they return a Guest address. */ -static unsigned long gpgd_addr(struct lguest *lg, unsigned long vaddr) +static unsigned long gpgd_addr(struct lg_cpu *cpu, unsigned long vaddr) { unsigned int index = vaddr >> (PGDIR_SHIFT); - return lg->pgdirs[lg->pgdidx].gpgdir + index * sizeof(pgd_t); + return cpu->lg->pgdirs[cpu->cpu_pgd].gpgdir + index * sizeof(pgd_t); } static unsigned long gpte_addr(struct lguest *lg, @@ -200,22 +200,23 @@ * * If we fixed up the fault (ie. we mapped the address), this routine returns * true. Otherwise, it was a real fault and we need to tell the Guest. */ -int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) +int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode) { pgd_t gpgd; pgd_t *spgd; unsigned long gpte_ptr; pte_t gpte; pte_t *spte; + struct lguest *lg = cpu->lg; /* First step: get the top-level Guest page table entry. */ - gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t); + gpgd = lgread(lg, gpgd_addr(cpu, vaddr), pgd_t); /* Toplevel not present? We can't map it in. */ if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) return 0; /* Now look at the matching shadow entry. */ - spgd = spgd_addr(lg, lg->pgdidx, vaddr); + spgd = spgd_addr(lg, cpu->cpu_pgd, vaddr); if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) { /* No shadow entry: allocate a new shadow PTE page. */ unsigned long ptepage = get_zeroed_page(GFP_KERNEL); @@ -297,19 +298,19 @@ * * This is a quick version which answers the question: is this virtual address * mapped by the shadow page tables, and is it writable? */ -static int page_writable(struct lguest *lg, unsigned long vaddr) +static int page_writable(struct lg_cpu *cpu, unsigned long vaddr) { pgd_t *spgd; unsigned long flags; /* Look at the current top level entry: is it present? */ - spgd = spgd_addr(lg, lg->pgdidx, vaddr); + spgd = spgd_addr(cpu->lg, cpu->cpu_pgd, vaddr); if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) return 0; /* Check the flags on the pte entry itself: it must be present and * writable. */ - flags = pte_flags(*(spte_addr(lg, *spgd, vaddr))); + flags = pte_flags(*(spte_addr(cpu->lg, *spgd, vaddr))); return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW); } @@ -317,10 +318,10 @@ /* So, when pin_stack_pages() asks us to pin a page, we check if it's already * in the page tables, and if not, we call demand_page() with error code 2 * (meaning "write"). */ -void pin_page(struct lguest *lg, unsigned long vaddr) +void pin_page(struct lg_cpu *cpu, unsigned long vaddr) { - if (!page_writable(lg, vaddr) && !demand_page(lg, vaddr, 2)) - kill_guest(lg, "bad stack page %#lx", vaddr); + if (!page_writable(cpu, vaddr) && !demand_page(cpu, vaddr, 2)) + kill_guest(cpu->lg, "bad stack page %#lx", vaddr); } /*H:450 If we chase down the release_pgd() code, it looks like this: */ @@ -358,28 +359,28 @@ * * The Guest has a hypercall to throw away the page tables: it's used when a * large number of mappings have been changed. */ -void guest_pagetable_flush_user(struct lguest *lg) +void guest_pagetable_flush_user(struct lg_cpu *cpu) { /* Drop the userspace part of the current page table. */ - flush_user_mappings(lg, lg->pgdidx); + flush_user_mappings(cpu->lg, cpu->cpu_pgd); } /*:*/ /* We walk down the guest page tables to get a guest-physical address */ -unsigned long guest_pa(struct lguest *lg, unsigned long vaddr) +unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr) { pgd_t gpgd; pte_t gpte; /* First step: get the top-level Guest page table entry. */ - gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t); + gpgd = lgread(cpu->lg, gpgd_addr(cpu, vaddr), pgd_t); /* Toplevel not present? We can't map it in. */ if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) - kill_guest(lg, "Bad address %#lx", vaddr); + kill_guest(cpu->lg, "Bad address %#lx", vaddr); - gpte = lgread(lg, gpte_addr(lg, gpgd, vaddr), pte_t); + gpte = lgread(cpu->lg, gpte_addr(cpu->lg, gpgd, vaddr), pte_t); if (!(pte_flags(gpte) & _PAGE_PRESENT)) - kill_guest(lg, "Bad address %#lx", vaddr); + kill_guest(cpu->lg, "Bad address %#lx", vaddr); return pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK); } @@ -399,11 +400,12 @@ /*H:435 And this is us, creating the new page directory. If we really do * allocate a new one (and so the kernel parts are not there), we set * blank_pgdir. */ -static unsigned int new_pgdir(struct lguest *lg, +static unsigned int new_pgdir(struct lg_cpu *cpu, unsigned long gpgdir, int *blank_pgdir) { unsigned int next; + struct lguest *lg = cpu->lg; /* We pick one entry at random to throw out. Choosing the Least * Recently Used might be better, but this is easy. */ @@ -413,7 +415,7 @@ lg->pgdirs[next].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL); /* If the allocation fails, just keep using the one we have */ if (!lg->pgdirs[next].pgdir) - next = lg->pgdidx; + next = cpu->cpu_pgd; else /* This is a blank page, so there are no kernel * mappings: caller must map the stack! */ @@ -432,21 +434,22 @@ * Now we've seen all the page table setting and manipulation, let's see what * what happens when the Guest changes page tables (ie. changes the top-level * pgdir). This occurs on almost every context switch. */ -void guest_new_pagetable(struct lguest *lg, unsigned long pgtable) +void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable) { int newpgdir, repin = 0; + struct lguest *lg = cpu->lg; /* Look to see if we have this one already. */ newpgdir = find_pgdir(lg, pgtable); /* If not, we allocate or mug an existing one: if it's a fresh one, * repin gets set to 1. */ if (newpgdir == ARRAY_SIZE(lg->pgdirs)) - newpgdir = new_pgdir(lg, pgtable, &repin); + newpgdir = new_pgdir(cpu, pgtable, &repin); /* Change the current pgd index to the new one. */ - lg->pgdidx = newpgdir; + cpu->cpu_pgd = newpgdir; /* If it was completely blank, we map in the Guest kernel stack */ if (repin) - pin_stack_pages(lg); + pin_stack_pages(cpu); } /*H:470 Finally, a routine which throws away everything: all PGD entries in all @@ -468,11 +471,11 @@ * mapping. Since kernel mappings are in every page table, it's easiest to * throw them all away. This traps the Guest in amber for a while as * everything faults back in, but it's rare. */ -void guest_pagetable_clear_all(struct lguest *lg) +void guest_pagetable_clear_all(struct lg_cpu *cpu) { - release_all_pagetables(lg); + release_all_pagetables(cpu->lg); /* We need the Guest kernel stack mapped again. */ - pin_stack_pages(lg); + pin_stack_pages(cpu); } /*:*/ /*M:009 Since we throw away all mappings when a kernel mapping changes, our @@ -590,11 +593,11 @@ { /* We start on the first shadow page table, and give it a blank PGD * page. */ - lg->pgdidx = 0; - lg->pgdirs[lg->pgdidx].gpgdir = pgtable; - lg->pgdirs[lg->pgdidx].pgdir = (pgd_t*)get_zeroed_page(GFP_KERNEL); - if (!lg->pgdirs[lg->pgdidx].pgdir) + lg->pgdirs[0].gpgdir = pgtable; + lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL); + if (!lg->pgdirs[0].pgdir) return -ENOMEM; + lg->cpus[0].cpu_pgd = 0; return 0; } @@ -606,7 +609,7 @@ /* We tell the Guest that it can't use the top 4MB of virtual * addresses used by the Switcher. */ || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem) - || put_user(lg->pgdirs[lg->pgdidx].gpgdir,&lg->lguest_data->pgdir)) + || put_user(lg->pgdirs[0].gpgdir, &lg->lguest_data->pgdir)) kill_guest(lg, "bad guest page %p", lg->lguest_data); /* In flush_user_mappings() we loop from 0 to @@ -634,17 +637,18 @@ * Guest (and not the pages for other CPUs). We have the appropriate PTE pages * for each CPU already set up, we just need to hook them in now we know which * Guest is about to run on this CPU. */ -void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages) +void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages) { pte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages); pgd_t switcher_pgd; pte_t regs_pte; + unsigned long pfn; /* Make the last PGD entry for this Guest point to the Switcher's PTE * page for this CPU (with appropriate flags). */ switcher_pgd = __pgd(__pa(switcher_pte_page) | _PAGE_KERNEL); - lg->pgdirs[lg->pgdidx].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd; + cpu->lg->pgdirs[cpu->cpu_pgd].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd; /* We also change the Switcher PTE page. When we're running the Guest, * we want the Guest's "regs" page to appear where the first Switcher @@ -653,7 +657,8 @@ * CPU's "struct lguest_pages": if we make sure the Guest's register * page is already mapped there, we don't have to copy them out * again. */ - regs_pte = pfn_pte (__pa(lg->regs_page) >> PAGE_SHIFT, __pgprot(_PAGE_KERNEL)); + pfn = __pa(cpu->regs_page) >> PAGE_SHIFT; + regs_pte = pfn_pte(pfn, __pgprot(_PAGE_KERNEL)); switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTRS_PER_PTE] = regs_pte; } /*:*/ --- linux-2.6.24.orig/drivers/lguest/hypercalls.c +++ linux-2.6.24/drivers/lguest/hypercalls.c @@ -29,8 +29,10 @@ /*H:120 This is the core hypercall routine: where the Guest gets what it wants. * Or gets killed. Or, in the case of LHCALL_CRASH, both. */ -static void do_hcall(struct lguest *lg, struct hcall_args *args) +static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args) { + struct lguest *lg = cpu->lg; + switch (args->arg0) { case LHCALL_FLUSH_ASYNC: /* This call does nothing, except by breaking out of the Guest @@ -41,8 +43,8 @@ * do that. */ kill_guest(lg, "already have lguest_data"); break; - case LHCALL_CRASH: { - /* Crash is such a trivial hypercall that we do it in four + case LHCALL_SHUTDOWN: { + /* Shutdown is such a trivial hypercall that we do it in four * lines right here. */ char msg[128]; /* If the lgread fails, it will call kill_guest() itself; the @@ -50,24 +52,26 @@ __lgread(lg, msg, args->arg1, sizeof(msg)); msg[sizeof(msg)-1] = '\0'; kill_guest(lg, "CRASH: %s", msg); + if (args->arg2 == LGUEST_SHUTDOWN_RESTART) + lg->dead = ERR_PTR(-ERESTART); break; } case LHCALL_FLUSH_TLB: /* FLUSH_TLB comes in two flavors, depending on the * argument: */ if (args->arg1) - guest_pagetable_clear_all(lg); + guest_pagetable_clear_all(cpu); else - guest_pagetable_flush_user(lg); + guest_pagetable_flush_user(cpu); break; /* All these calls simply pass the arguments through to the right * routines. */ case LHCALL_NEW_PGTABLE: - guest_new_pagetable(lg, args->arg1); + guest_new_pagetable(cpu, args->arg1); break; case LHCALL_SET_STACK: - guest_set_stack(lg, args->arg1, args->arg2, args->arg3); + guest_set_stack(cpu, args->arg1, args->arg2, args->arg3); break; case LHCALL_SET_PTE: guest_set_pte(lg, args->arg1, args->arg2, __pte(args->arg3)); @@ -76,22 +80,22 @@ guest_set_pmd(lg, args->arg1, args->arg2); break; case LHCALL_SET_CLOCKEVENT: - guest_set_clockevent(lg, args->arg1); + guest_set_clockevent(cpu, args->arg1); break; case LHCALL_TS: /* This sets the TS flag, as we saw used in run_guest(). */ - lg->ts = args->arg1; + cpu->ts = args->arg1; break; case LHCALL_HALT: /* Similarly, this sets the halted flag for run_guest(). */ - lg->halted = 1; + cpu->halted = 1; break; case LHCALL_NOTIFY: - lg->pending_notify = args->arg1; + cpu->pending_notify = args->arg1; break; default: /* It should be an architecture-specific hypercall. */ - if (lguest_arch_do_hcall(lg, args)) + if (lguest_arch_do_hcall(cpu, args)) kill_guest(lg, "Bad hypercall %li\n", args->arg0); } } @@ -104,10 +108,11 @@ * Guest put them in the ring, but we also promise the Guest that they will * happen before any normal hypercall (which is why we check this before * checking for a normal hcall). */ -static void do_async_hcalls(struct lguest *lg) +static void do_async_hcalls(struct lg_cpu *cpu) { unsigned int i; u8 st[LHCALL_RING_SIZE]; + struct lguest *lg = cpu->lg; /* For simplicity, we copy the entire call status array in at once. */ if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st))) @@ -119,7 +124,7 @@ /* We remember where we were up to from last time. This makes * sure that the hypercalls are done in the order the Guest * places them in the ring. */ - unsigned int n = lg->next_hcall; + unsigned int n = cpu->next_hcall; /* 0xFF means there's no call here (yet). */ if (st[n] == 0xFF) @@ -127,8 +132,8 @@ /* OK, we have hypercall. Increment the "next_hcall" cursor, * and wrap back to 0 if we reach the end. */ - if (++lg->next_hcall == LHCALL_RING_SIZE) - lg->next_hcall = 0; + if (++cpu->next_hcall == LHCALL_RING_SIZE) + cpu->next_hcall = 0; /* Copy the hypercall arguments into a local copy of * the hcall_args struct. */ @@ -139,7 +144,7 @@ } /* Do the hypercall, same as a normal one. */ - do_hcall(lg, &args); + do_hcall(cpu, &args); /* Mark the hypercall done. */ if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) { @@ -149,23 +154,24 @@ /* Stop doing hypercalls if they want to notify the Launcher: * it needs to service this first. */ - if (lg->pending_notify) + if (cpu->pending_notify) break; } } /* Last of all, we look at what happens first of all. The very first time the * Guest makes a hypercall, we end up here to set things up: */ -static void initialize(struct lguest *lg) +static void initialize(struct lg_cpu *cpu) { + struct lguest *lg = cpu->lg; /* You can't do anything until you're initialized. The Guest knows the * rules, so we're unforgiving here. */ - if (lg->hcall->arg0 != LHCALL_LGUEST_INIT) { - kill_guest(lg, "hypercall %li before INIT", lg->hcall->arg0); + if (cpu->hcall->arg0 != LHCALL_LGUEST_INIT) { + kill_guest(lg, "hypercall %li before INIT", cpu->hcall->arg0); return; } - if (lguest_arch_init_hypercalls(lg)) + if (lguest_arch_init_hypercalls(cpu)) kill_guest(lg, "bad guest page %p", lg->lguest_data); /* The Guest tells us where we're not to deliver interrupts by putting @@ -185,7 +191,7 @@ * first write to a Guest page. This may have caused a copy-on-write * fault, but the old page might be (read-only) in the Guest * pagetable. */ - guest_pagetable_clear_all(lg); + guest_pagetable_clear_all(cpu); } /*H:100 @@ -194,27 +200,27 @@ * Remember from the Guest, hypercalls come in two flavors: normal and * asynchronous. This file handles both of types. */ -void do_hypercalls(struct lguest *lg) +void do_hypercalls(struct lg_cpu *cpu) { /* Not initialized yet? This hypercall must do it. */ - if (unlikely(!lg->lguest_data)) { + if (unlikely(!cpu->lg->lguest_data)) { /* Set up the "struct lguest_data" */ - initialize(lg); + initialize(cpu); /* Hcall is done. */ - lg->hcall = NULL; + cpu->hcall = NULL; return; } /* The Guest has initialized. * * Look in the hypercall ring for the async hypercalls: */ - do_async_hcalls(lg); + do_async_hcalls(cpu); /* If we stopped reading the hypercall ring because the Guest did a * NOTIFY to the Launcher, we want to return now. Otherwise we do * the hypercall. */ - if (!lg->pending_notify) { - do_hcall(lg, lg->hcall); + if (!cpu->pending_notify) { + do_hcall(cpu, cpu->hcall); /* Tricky point: we reset the hcall pointer to mark the * hypercall as "done". We use the hcall pointer rather than * the trap number to indicate a hypercall is pending. @@ -225,7 +231,7 @@ * Launcher, the run_guest() loop will exit without running the * Guest. When it comes back it would try to re-run the * hypercall. */ - lg->hcall = NULL; + cpu->hcall = NULL; } } --- linux-2.6.24.orig/drivers/lguest/lguest_device.c +++ linux-2.6.24/drivers/lguest/lguest_device.c @@ -52,57 +52,82 @@ /*D:130 * Device configurations * - * The configuration information for a device consists of a series of fields. - * We don't really care what they are: the Launcher set them up, and the driver - * will look at them during setup. - * - * For us these fields come immediately after that device's descriptor in the - * lguest_devices page. - * - * Each field starts with a "type" byte, a "length" byte, then that number of - * bytes of configuration information. The device descriptor tells us the - * total configuration length so we know when we've reached the last field. */ + * The configuration information for a device consists of one or more + * virtqueues, a feature bitmaks, and some configuration bytes. The + * configuration bytes don't really matter to us: the Launcher sets them up, and + * the driver will look at them during setup. + * + * A convenient routine to return the device's virtqueue config array: + * immediately after the descriptor. */ +static struct lguest_vqconfig *lg_vq(const struct lguest_device_desc *desc) +{ + return (void *)(desc + 1); +} -/* type + length bytes */ -#define FHDR_LEN 2 +/* The features come immediately after the virtqueues. */ +static u8 *lg_features(const struct lguest_device_desc *desc) +{ + return (void *)(lg_vq(desc) + desc->num_vq); +} -/* This finds the first field of a given type for a device's configuration. */ -static void *lg_find(struct virtio_device *vdev, u8 type, unsigned int *len) +/* The config space comes after the two feature bitmasks. */ +static u8 *lg_config(const struct lguest_device_desc *desc) { - struct lguest_device_desc *desc = to_lgdev(vdev)->desc; - int i; + return lg_features(desc) + desc->feature_len * 2; +} - for (i = 0; i < desc->config_len; i += FHDR_LEN + desc->config[i+1]) { - if (desc->config[i] == type) { - /* Mark it used, so Host can know we looked at it, and - * also so we won't find the same one twice. */ - desc->config[i] |= 0x80; - /* Remember, the second byte is the length. */ - *len = desc->config[i+1]; - /* We return a pointer to the field header. */ - return desc->config + i; - } - } +/* The total size of the config page used by this device (incl. desc) */ +static unsigned desc_size(const struct lguest_device_desc *desc) +{ + return sizeof(*desc) + + desc->num_vq * sizeof(struct lguest_vqconfig) + + desc->feature_len * 2 + + desc->config_len; +} - /* Not found: return NULL for failure. */ - return NULL; +/* This tests (and acknowleges) a feature bit. */ +static bool lg_feature(struct virtio_device *vdev, unsigned fbit) +{ + struct lguest_device_desc *desc = to_lgdev(vdev)->desc; + u8 *features; + + /* Obviously if they ask for a feature off the end of our feature + * bitmap, it's not set. */ + if (fbit / 8 > desc->feature_len) + return false; + + /* The feature bitmap comes after the virtqueues. */ + features = lg_features(desc); + if (!(features[fbit / 8] & (1 << (fbit % 8)))) + return false; + + /* We set the matching bit in the other half of the bitmap to tell the + * Host we want to use this feature. We don't use this yet, but we + * could in future. */ + features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8)); + return true; } /* Once they've found a field, getting a copy of it is easy. */ -static void lg_get(struct virtio_device *vdev, void *token, +static void lg_get(struct virtio_device *vdev, unsigned int offset, void *buf, unsigned len) { - /* Check they didn't ask for more than the length of the field! */ - BUG_ON(len > ((u8 *)token)[1]); - memcpy(buf, token + FHDR_LEN, len); + struct lguest_device_desc *desc = to_lgdev(vdev)->desc; + + /* Check they didn't ask for more than the length of the config! */ + BUG_ON(offset + len > desc->config_len); + memcpy(buf, lg_config(desc) + offset, len); } /* Setting the contents is also trivial. */ -static void lg_set(struct virtio_device *vdev, void *token, +static void lg_set(struct virtio_device *vdev, unsigned int offset, const void *buf, unsigned len) { - BUG_ON(len > ((u8 *)token)[1]); - memcpy(token + FHDR_LEN, buf, len); + struct lguest_device_desc *desc = to_lgdev(vdev)->desc; + + /* Check they didn't ask for more than the length of the config! */ + BUG_ON(offset + len > desc->config_len); + memcpy(lg_config(desc) + offset, buf, len); } /* The operations to get and set the status word just access the status field @@ -114,9 +139,20 @@ static void lg_set_status(struct virtio_device *vdev, u8 status) { + BUG_ON(!status); to_lgdev(vdev)->desc->status = status; } +/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor + * address of the device. The Host will zero the status and all the + * features. */ +static void lg_reset(struct virtio_device *vdev) +{ + unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; + + hcall(LHCALL_NOTIFY, (max_pfn<config->find(vdev, VIRTIO_CONFIG_F_VIRTQUEUE, &len); - if (!token) + /* We must have this many virtqueues. */ + if (index >= ldev->desc->num_vq) return ERR_PTR(-ENOENT); lvq = kmalloc(sizeof(*lvq), GFP_KERNEL); if (!lvq) return ERR_PTR(-ENOMEM); - /* Note: we could use a configuration space inside here, just like we - * do for the device. This would allow expansion in future, because - * our configuration system is designed to be expansible. But this is - * way easier. */ - if (len != sizeof(lvq->config)) { - dev_err(&vdev->dev, "Unexpected virtio config len %u\n", len); - err = -EIO; - goto free_lvq; - } - /* Make a copy of the "struct lguest_vqconfig" field. We need a copy - * because the config space might not be aligned correctly. */ - vdev->config->get(vdev, token, &lvq->config, sizeof(lvq->config)); + /* Make a copy of the "struct lguest_vqconfig" entry, which sits after + * the descriptor. We need a copy because the config space might not + * be aligned correctly. */ + memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config)); + printk("Mapping virtqueue %i addr %lx\n", index, + (unsigned long)lvq->config.pfn << PAGE_SHIFT); /* Figure out how many pages the ring will take, and map that memory */ lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT, DIV_ROUND_UP(vring_size(lvq->config.num, @@ -259,11 +285,12 @@ /* The ops structure which hooks everything together. */ static struct virtio_config_ops lguest_config_ops = { - .find = lg_find, + .feature = lg_feature, .get = lg_get, .set = lg_set, .get_status = lg_get_status, .set_status = lg_set_status, + .reset = lg_reset, .find_vq = lg_find_vq, .del_vq = lg_del_vq, }; @@ -329,13 +356,14 @@ struct lguest_device_desc *d; /* We start at the page beginning, and skip over each entry. */ - for (i = 0; i < PAGE_SIZE; i += sizeof(*d) + d->config_len) { + for (i = 0; i < PAGE_SIZE; i += desc_size(d)) { d = lguest_devices + i; /* Once we hit a zero, stop. */ if (d->type == 0) break; + printk("Device at %i has size %u\n", i, desc_size(d)); add_lguest_device(d); } } --- linux-2.6.24.orig/drivers/lguest/segments.c +++ linux-2.6.24/drivers/lguest/segments.c @@ -58,7 +58,7 @@ * Protection Fault in the Switcher when it restores a Guest segment register * which tries to use that entry. Then we kill the Guest for causing such a * mess: the message will be "unhandled trap 256". */ -static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end) +static void fixup_gdt_table(struct lg_cpu *cpu, unsigned start, unsigned end) { unsigned int i; @@ -71,14 +71,14 @@ /* Segment descriptors contain a privilege level: the Guest is * sometimes careless and leaves this as 0, even though it's * running at privilege level 1. If so, we fix it here. */ - if ((lg->arch.gdt[i].b & 0x00006000) == 0) - lg->arch.gdt[i].b |= (GUEST_PL << 13); + if ((cpu->arch.gdt[i].b & 0x00006000) == 0) + cpu->arch.gdt[i].b |= (GUEST_PL << 13); /* Each descriptor has an "accessed" bit. If we don't set it * now, the CPU will try to set it when the Guest first loads * that entry into a segment register. But the GDT isn't * writable by the Guest, so bad things can happen. */ - lg->arch.gdt[i].b |= 0x00000100; + cpu->arch.gdt[i].b |= 0x00000100; } } @@ -109,31 +109,31 @@ /* This routine sets up the initial Guest GDT for booting. All entries start * as 0 (unusable). */ -void setup_guest_gdt(struct lguest *lg) +void setup_guest_gdt(struct lg_cpu *cpu) { /* Start with full 0-4G segments... */ - lg->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT; - lg->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT; + cpu->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT; + cpu->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT; /* ...except the Guest is allowed to use them, so set the privilege * level appropriately in the flags. */ - lg->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13); - lg->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13); + cpu->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13); + cpu->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13); } /*H:650 An optimization of copy_gdt(), for just the three "thead-local storage" * entries. */ -void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt) +void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt) { unsigned int i; for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++) - gdt[i] = lg->arch.gdt[i]; + gdt[i] = cpu->arch.gdt[i]; } /*H:640 When the Guest is run on a different CPU, or the GDT entries have * changed, copy_gdt() is called to copy the Guest's GDT entries across to this * CPU's GDT. */ -void copy_gdt(const struct lguest *lg, struct desc_struct *gdt) +void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt) { unsigned int i; @@ -141,21 +141,22 @@ * replaced. See ignored_gdt() above. */ for (i = 0; i < GDT_ENTRIES; i++) if (!ignored_gdt(i)) - gdt[i] = lg->arch.gdt[i]; + gdt[i] = cpu->arch.gdt[i]; } /*H:620 This is where the Guest asks us to load a new GDT (LHCALL_LOAD_GDT). * We copy it from the Guest and tweak the entries. */ -void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num) +void load_guest_gdt(struct lg_cpu *cpu, unsigned long table, u32 num) { + struct lguest *lg = cpu->lg; /* We assume the Guest has the same number of GDT entries as the * Host, otherwise we'd have to dynamically allocate the Guest GDT. */ - if (num > ARRAY_SIZE(lg->arch.gdt)) + if (num > ARRAY_SIZE(cpu->arch.gdt)) kill_guest(lg, "too many gdt entries %i", num); /* We read the whole thing in, then fix it up. */ - __lgread(lg, lg->arch.gdt, table, num * sizeof(lg->arch.gdt[0])); - fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->arch.gdt)); + __lgread(lg, cpu->arch.gdt, table, num * sizeof(cpu->arch.gdt[0])); + fixup_gdt_table(cpu, 0, ARRAY_SIZE(cpu->arch.gdt)); /* Mark that the GDT changed so the core knows it has to copy it again, * even if the Guest is run on the same CPU. */ lg->changed |= CHANGED_GDT; @@ -165,12 +166,13 @@ * Remember that this happens on every context switch, so it's worth * optimizing. But wouldn't it be neater to have a single hypercall to cover * both cases? */ -void guest_load_tls(struct lguest *lg, unsigned long gtls) +void guest_load_tls(struct lg_cpu *cpu, unsigned long gtls) { - struct desc_struct *tls = &lg->arch.gdt[GDT_ENTRY_TLS_MIN]; + struct desc_struct *tls = &cpu->arch.gdt[GDT_ENTRY_TLS_MIN]; + struct lguest *lg = cpu->lg; __lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES); - fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1); + fixup_gdt_table(cpu, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1); /* Note that just the TLS entries have changed. */ lg->changed |= CHANGED_GDT_TLS; } --- linux-2.6.24.orig/drivers/lguest/x86/core.c +++ linux-2.6.24/drivers/lguest/x86/core.c @@ -73,8 +73,9 @@ * since it last ran. We saw this set in interrupts_and_traps.c and * segments.c. */ -static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages) +static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages) { + struct lguest *lg = cpu->lg; /* Copying all this data can be quite expensive. We usually run the * same Guest we ran last time (and that Guest hasn't run anywhere else * meanwhile). If that's not the case, we pretend everything in the @@ -90,42 +91,43 @@ pages->state.host_cr3 = __pa(current->mm->pgd); /* Set up the Guest's page tables to see this CPU's pages (and no * other CPU's pages). */ - map_switcher_in_guest(lg, pages); + map_switcher_in_guest(cpu, pages); /* Set up the two "TSS" members which tell the CPU what stack to use * for traps which do directly into the Guest (ie. traps at privilege * level 1). */ - pages->state.guest_tss.esp1 = lg->esp1; - pages->state.guest_tss.ss1 = lg->ss1; + pages->state.guest_tss.esp1 = cpu->esp1; + pages->state.guest_tss.ss1 = cpu->ss1; /* Copy direct-to-Guest trap entries. */ if (lg->changed & CHANGED_IDT) - copy_traps(lg, pages->state.guest_idt, default_idt_entries); + copy_traps(cpu, pages->state.guest_idt, default_idt_entries); /* Copy all GDT entries which the Guest can change. */ if (lg->changed & CHANGED_GDT) - copy_gdt(lg, pages->state.guest_gdt); + copy_gdt(cpu, pages->state.guest_gdt); /* If only the TLS entries have changed, copy them. */ else if (lg->changed & CHANGED_GDT_TLS) - copy_gdt_tls(lg, pages->state.guest_gdt); + copy_gdt_tls(cpu, pages->state.guest_gdt); /* Mark the Guest as unchanged for next time. */ lg->changed = 0; } /* Finally: the code to actually call into the Switcher to run the Guest. */ -static void run_guest_once(struct lguest *lg, struct lguest_pages *pages) +static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages) { /* This is a dummy value we need for GCC's sake. */ unsigned int clobber; + struct lguest *lg = cpu->lg; /* Copy the guest-specific information into this CPU's "struct * lguest_pages". */ - copy_in_guest_info(lg, pages); + copy_in_guest_info(cpu, pages); /* Set the trap number to 256 (impossible value). If we fault while * switching to the Guest (bad segment registers or bug), this will * cause us to abort the Guest. */ - lg->regs->trapnum = 256; + cpu->regs->trapnum = 256; /* Now: we push the "eflags" register on the stack, then do an "lcall". * This is how we change from using the kernel code segment to using @@ -143,7 +145,7 @@ * 0-th argument above, ie "a"). %ebx contains the * physical address of the Guest's top-level page * directory. */ - : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir)) + : "0"(pages), "1"(__pa(lg->pgdirs[cpu->cpu_pgd].pgdir)) /* We tell gcc that all these registers could change, * which means we don't have to save and restore them in * the Switcher. */ @@ -161,12 +163,12 @@ /*H:040 This is the i386-specific code to setup and run the Guest. Interrupts * are disabled: we own the CPU. */ -void lguest_arch_run_guest(struct lguest *lg) +void lguest_arch_run_guest(struct lg_cpu *cpu) { /* Remember the awfully-named TS bit? If the Guest has asked to set it * we set it now, so we can trap and pass that trap to the Guest if it * uses the FPU. */ - if (lg->ts) + if (cpu->ts) lguest_set_ts(); /* SYSENTER is an optimized way of doing system calls. We can't allow @@ -180,7 +182,7 @@ /* Now we actually run the Guest. It will return when something * interesting happens, and we can examine its registers to see what it * was doing. */ - run_guest_once(lg, lguest_pages(raw_smp_processor_id())); + run_guest_once(cpu, lguest_pages(raw_smp_processor_id())); /* Note that the "regs" pointer contains two extra entries which are * not really registers: a trap number which says what interrupt or @@ -191,11 +193,11 @@ * bad virtual address. We have to grab this now, because once we * re-enable interrupts an interrupt could fault and thus overwrite * cr2, or we could even move off to a different CPU. */ - if (lg->regs->trapnum == 14) - lg->arch.last_pagefault = read_cr2(); + if (cpu->regs->trapnum == 14) + cpu->arch.last_pagefault = read_cr2(); /* Similarly, if we took a trap because the Guest used the FPU, * we have to restore the FPU it expects to see. */ - else if (lg->regs->trapnum == 7) + else if (cpu->regs->trapnum == 7) math_state_restore(); /* Restore SYSENTER if it's supposed to be on. */ @@ -214,18 +216,19 @@ * When the Guest uses one of these instructions, we get a trap (General * Protection Fault) and come here. We see if it's one of those troublesome * instructions and skip over it. We return true if we did. */ -static int emulate_insn(struct lguest *lg) +static int emulate_insn(struct lg_cpu *cpu) { + struct lguest *lg = cpu->lg; u8 insn; unsigned int insnlen = 0, in = 0, shift = 0; /* The eip contains the *virtual* address of the Guest's instruction: * guest_pa just subtracts the Guest's page_offset. */ - unsigned long physaddr = guest_pa(lg, lg->regs->eip); + unsigned long physaddr = guest_pa(cpu, cpu->regs->eip); /* This must be the Guest kernel trying to do something, not userspace! * The bottom two bits of the CS segment register are the privilege * level. */ - if ((lg->regs->cs & 3) != GUEST_PL) + if ((cpu->regs->cs & 3) != GUEST_PL) return 0; /* Decoding x86 instructions is icky. */ @@ -268,26 +271,27 @@ if (in) { /* Lower bit tells is whether it's a 16 or 32 bit access */ if (insn & 0x1) - lg->regs->eax = 0xFFFFFFFF; + cpu->regs->eax = 0xFFFFFFFF; else - lg->regs->eax |= (0xFFFF << shift); + cpu->regs->eax |= (0xFFFF << shift); } /* Finally, we've "done" the instruction, so move past it. */ - lg->regs->eip += insnlen; + cpu->regs->eip += insnlen; /* Success! */ return 1; } /*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */ -void lguest_arch_handle_trap(struct lguest *lg) +void lguest_arch_handle_trap(struct lg_cpu *cpu) { - switch (lg->regs->trapnum) { + struct lguest *lg = cpu->lg; + switch (cpu->regs->trapnum) { case 13: /* We've intercepted a General Protection Fault. */ /* Check if this was one of those annoying IN or OUT * instructions which we need to emulate. If so, we just go * back into the Guest after we've done it. */ - if (lg->regs->errcode == 0) { - if (emulate_insn(lg)) + if (cpu->regs->errcode == 0) { + if (emulate_insn(cpu)) return; } break; @@ -301,7 +305,8 @@ * * The errcode tells whether this was a read or a write, and * whether kernel or userspace code. */ - if (demand_page(lg, lg->arch.last_pagefault, lg->regs->errcode)) + if (demand_page(cpu, cpu->arch.last_pagefault, + cpu->regs->errcode)) return; /* OK, it's really not there (or not OK): the Guest needs to @@ -312,14 +317,14 @@ * happen before it's done the LHCALL_LGUEST_INIT hypercall, so * lg->lguest_data could be NULL */ if (lg->lguest_data && - put_user(lg->arch.last_pagefault, &lg->lguest_data->cr2)) + put_user(cpu->arch.last_pagefault, &lg->lguest_data->cr2)) kill_guest(lg, "Writing cr2"); break; case 7: /* We've intercepted a Device Not Available fault. */ /* If the Guest doesn't want to know, we already restored the * Floating Point Unit, so we just continue without telling * it. */ - if (!lg->ts) + if (!cpu->ts) return; break; case 32 ... 255: @@ -332,19 +337,19 @@ case LGUEST_TRAP_ENTRY: /* Our 'struct hcall_args' maps directly over our regs: we set * up the pointer now to indicate a hypercall is pending. */ - lg->hcall = (struct hcall_args *)lg->regs; + cpu->hcall = (struct hcall_args *)cpu->regs; return; } /* We didn't handle the trap, so it needs to go to the Guest. */ - if (!deliver_trap(lg, lg->regs->trapnum)) + if (!deliver_trap(cpu, cpu->regs->trapnum)) /* If the Guest doesn't have a handler (either it hasn't * registered any yet, or it's one of the faults we don't let * it handle), it dies with a cryptic error message. */ kill_guest(lg, "unhandled trap %li at %#lx (%#lx)", - lg->regs->trapnum, lg->regs->eip, - lg->regs->trapnum == 14 ? lg->arch.last_pagefault - : lg->regs->errcode); + cpu->regs->trapnum, cpu->regs->eip, + cpu->regs->trapnum == 14 ? cpu->arch.last_pagefault + : cpu->regs->errcode); } /* Now we can look at each of the routines this calls, in increasing order of @@ -487,17 +492,17 @@ /*H:122 The i386-specific hypercalls simply farm out to the right functions. */ -int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args) +int lguest_arch_do_hcall(struct lg_cpu *cpu, struct hcall_args *args) { switch (args->arg0) { case LHCALL_LOAD_GDT: - load_guest_gdt(lg, args->arg1, args->arg2); + load_guest_gdt(cpu, args->arg1, args->arg2); break; case LHCALL_LOAD_IDT_ENTRY: - load_guest_idt_entry(lg, args->arg1, args->arg2, args->arg3); + load_guest_idt_entry(cpu, args->arg1, args->arg2, args->arg3); break; case LHCALL_LOAD_TLS: - guest_load_tls(lg, args->arg1); + guest_load_tls(cpu, args->arg1); break; default: /* Bad Guest. Bad! */ @@ -507,13 +512,14 @@ } /*H:126 i386-specific hypercall initialization: */ -int lguest_arch_init_hypercalls(struct lguest *lg) +int lguest_arch_init_hypercalls(struct lg_cpu *cpu) { u32 tsc_speed; + struct lguest *lg = cpu->lg; /* The pointer to the Guest's "struct lguest_data" is the only * argument. We check that address now. */ - if (!lguest_address_ok(lg, lg->hcall->arg1, sizeof(*lg->lguest_data))) + if (!lguest_address_ok(lg, cpu->hcall->arg1, sizeof(*lg->lguest_data))) return -EFAULT; /* Having checked it, we simply set lg->lguest_data to point straight @@ -521,7 +527,7 @@ * copy_to_user/from_user from now on, instead of lgread/write. I put * this in to show that I'm not immune to writing stupid * optimizations. */ - lg->lguest_data = lg->mem_base + lg->hcall->arg1; + lg->lguest_data = lg->mem_base + cpu->hcall->arg1; /* We insist that the Time Stamp Counter exist and doesn't change with * cpu frequency. Some devious chip manufacturers decided that TSC @@ -548,9 +554,9 @@ * * Most of the Guest's registers are left alone: we used get_zeroed_page() to * allocate the structure, so they will be 0. */ -void lguest_arch_setup_regs(struct lguest *lg, unsigned long start) +void lguest_arch_setup_regs(struct lg_cpu *cpu, unsigned long start) { - struct lguest_regs *regs = lg->regs; + struct lguest_regs *regs = cpu->regs; /* There are four "segment" registers which the Guest needs to boot: * The "code segment" register (cs) refers to the kernel code segment @@ -577,5 +583,5 @@ /* There are a couple of GDT entries the Guest expects when first * booting. */ - setup_guest_gdt(lg); + setup_guest_gdt(cpu); } --- linux-2.6.24.orig/drivers/lguest/core.c +++ linux-2.6.24/drivers/lguest/core.c @@ -174,20 +174,22 @@ /*H:030 Let's jump straight to the the main loop which runs the Guest. * Remember, this is called by the Launcher reading /dev/lguest, and we keep * going around and around until something interesting happens. */ -int run_guest(struct lguest *lg, unsigned long __user *user) +int run_guest(struct lg_cpu *cpu, unsigned long __user *user) { + struct lguest *lg = cpu->lg; + /* We stop running once the Guest is dead. */ while (!lg->dead) { /* First we run any hypercalls the Guest wants done. */ - if (lg->hcall) - do_hypercalls(lg); + if (cpu->hcall) + do_hypercalls(cpu); /* It's possible the Guest did a NOTIFY hypercall to the * Launcher, in which case we return from the read() now. */ - if (lg->pending_notify) { - if (put_user(lg->pending_notify, user)) + if (cpu->pending_notify) { + if (put_user(cpu->pending_notify, user)) return -EFAULT; - return sizeof(lg->pending_notify); + return sizeof(cpu->pending_notify); } /* Check for signals */ @@ -195,13 +197,13 @@ return -ERESTARTSYS; /* If Waker set break_out, return to Launcher. */ - if (lg->break_out) + if (cpu->break_out) return -EAGAIN; /* Check if there are any interrupts which can be delivered * now: if so, this sets up the hander to be executed when we * next run the Guest. */ - maybe_do_interrupt(lg); + maybe_do_interrupt(cpu); /* All long-lived kernel loops need to check with this horrible * thing called the freezer. If the Host is trying to suspend, @@ -215,7 +217,7 @@ /* If the Guest asked to be stopped, we sleep. The Guest's * clock timer or LHCALL_BREAK from the Waker will wake us. */ - if (lg->halted) { + if (cpu->halted) { set_current_state(TASK_INTERRUPTIBLE); schedule(); continue; @@ -226,15 +228,17 @@ local_irq_disable(); /* Actually run the Guest until something happens. */ - lguest_arch_run_guest(lg); + lguest_arch_run_guest(cpu); /* Now we're ready to be interrupted or moved to other CPUs */ local_irq_enable(); /* Now we deal with whatever happened to the Guest. */ - lguest_arch_handle_trap(lg); + lguest_arch_handle_trap(cpu); } + if (lg->dead == ERR_PTR(-ERESTART)) + return -ERESTART; /* The Guest is dead => "No such file or directory" */ return -ENOENT; } --- linux-2.6.24.orig/drivers/lguest/lg.h +++ linux-2.6.24/drivers/lguest/lg.h @@ -38,58 +38,71 @@ #define CHANGED_GDT_TLS 4 /* Actually a subset of CHANGED_GDT */ #define CHANGED_ALL 3 -/* The private info the thread maintains about the guest. */ -struct lguest -{ - /* At end of a page shared mapped over lguest_pages in guest. */ - unsigned long regs_page; - struct lguest_regs *regs; - struct lguest_data __user *lguest_data; +struct lguest; + +struct lg_cpu { + unsigned int id; + struct lguest *lg; struct task_struct *tsk; struct mm_struct *mm; /* == tsk->mm, but that becomes NULL on exit */ - u32 pfn_limit; - /* This provides the offset to the base of guest-physical - * memory in the Launcher. */ - void __user *mem_base; - unsigned long kernel_address; + u32 cr2; - int halted; int ts; - u32 next_hcall; u32 esp1; u8 ss1; + unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */ + + /* At end of a page shared mapped over lguest_pages in guest. */ + unsigned long regs_page; + struct lguest_regs *regs; + + int cpu_pgd; /* which pgd this cpu is currently using */ + /* If a hypercall was asked for, this points to the arguments. */ struct hcall_args *hcall; + u32 next_hcall; + + /* Virtual clock device */ + struct hrtimer hrt; /* Do we need to stop what we're doing and return to userspace? */ int break_out; wait_queue_head_t break_wq; + int halted; + + /* Pending virtual interrupts */ + DECLARE_BITMAP(irqs_pending, LGUEST_IRQS); + + struct lg_cpu_arch arch; +}; + +/* The private info the thread maintains about the guest. */ +struct lguest +{ + struct lguest_data __user *lguest_data; + struct lg_cpu cpus[NR_CPUS]; + unsigned int nr_cpus; + + u32 pfn_limit; + /* This provides the offset to the base of guest-physical + * memory in the Launcher. */ + void __user *mem_base; + unsigned long kernel_address; /* Bitmap of what has changed: see CHANGED_* above. */ int changed; struct lguest_pages *last_pages; - /* We keep a small number of these. */ - u32 pgdidx; struct pgdir pgdirs[4]; unsigned long noirq_start, noirq_end; - unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */ unsigned int stack_pages; u32 tsc_khz; /* Dead? */ const char *dead; - - struct lguest_arch arch; - - /* Virtual clock device */ - struct hrtimer hrt; - - /* Pending virtual interrupts */ - DECLARE_BITMAP(irqs_pending, LGUEST_IRQS); }; extern struct mutex lguest_lock; @@ -116,7 +129,7 @@ } while(0) /* (end of memory access helper routines) :*/ -int run_guest(struct lguest *lg, unsigned long __user *user); +int run_guest(struct lg_cpu *cpu, unsigned long __user *user); /* Helper macros to obtain the first 12 or the last 20 bits, this is only the * first step in the migration to the kernel types. pte_pfn is already defined @@ -126,52 +139,53 @@ #define pgd_pfn(x) (pgd_val(x) >> PAGE_SHIFT) /* interrupts_and_traps.c: */ -void maybe_do_interrupt(struct lguest *lg); -int deliver_trap(struct lguest *lg, unsigned int num); -void load_guest_idt_entry(struct lguest *lg, unsigned int i, u32 low, u32 hi); -void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages); -void pin_stack_pages(struct lguest *lg); +void maybe_do_interrupt(struct lg_cpu *cpu); +int deliver_trap(struct lg_cpu *cpu, unsigned int num); +void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int i, + u32 low, u32 hi); +void guest_set_stack(struct lg_cpu *cpu, u32 seg, u32 esp, unsigned int pages); +void pin_stack_pages(struct lg_cpu *cpu); void setup_default_idt_entries(struct lguest_ro_state *state, const unsigned long *def); -void copy_traps(const struct lguest *lg, struct desc_struct *idt, +void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt, const unsigned long *def); -void guest_set_clockevent(struct lguest *lg, unsigned long delta); -void init_clockdev(struct lguest *lg); +void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta); +void init_clockdev(struct lg_cpu *cpu); bool check_syscall_vector(struct lguest *lg); int init_interrupts(void); void free_interrupts(void); /* segments.c: */ void setup_default_gdt_entries(struct lguest_ro_state *state); -void setup_guest_gdt(struct lguest *lg); -void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num); -void guest_load_tls(struct lguest *lg, unsigned long tls_array); -void copy_gdt(const struct lguest *lg, struct desc_struct *gdt); -void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt); +void setup_guest_gdt(struct lg_cpu *cpu); +void load_guest_gdt(struct lg_cpu *cpu, unsigned long table, u32 num); +void guest_load_tls(struct lg_cpu *cpu, unsigned long tls_array); +void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt); +void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt); /* page_tables.c: */ int init_guest_pagetable(struct lguest *lg, unsigned long pgtable); void free_guest_pagetable(struct lguest *lg); -void guest_new_pagetable(struct lguest *lg, unsigned long pgtable); +void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable); void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i); -void guest_pagetable_clear_all(struct lguest *lg); -void guest_pagetable_flush_user(struct lguest *lg); +void guest_pagetable_clear_all(struct lg_cpu *cpu); +void guest_pagetable_flush_user(struct lg_cpu *cpu); void guest_set_pte(struct lguest *lg, unsigned long gpgdir, unsigned long vaddr, pte_t val); -void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages); -int demand_page(struct lguest *info, unsigned long cr2, int errcode); -void pin_page(struct lguest *lg, unsigned long vaddr); -unsigned long guest_pa(struct lguest *lg, unsigned long vaddr); +void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages); +int demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode); +void pin_page(struct lg_cpu *cpu, unsigned long vaddr); +unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr); void page_table_guest_data_init(struct lguest *lg); /* /core.c: */ void lguest_arch_host_init(void); void lguest_arch_host_fini(void); -void lguest_arch_run_guest(struct lguest *lg); -void lguest_arch_handle_trap(struct lguest *lg); -int lguest_arch_init_hypercalls(struct lguest *lg); -int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args); -void lguest_arch_setup_regs(struct lguest *lg, unsigned long start); +void lguest_arch_run_guest(struct lg_cpu *cpu); +void lguest_arch_handle_trap(struct lg_cpu *cpu); +int lguest_arch_init_hypercalls(struct lg_cpu *cpu); +int lguest_arch_do_hcall(struct lg_cpu *cpu, struct hcall_args *args); +void lguest_arch_setup_regs(struct lg_cpu *cpu, unsigned long start); /* /switcher.S: */ extern char start_switcher_text[], end_switcher_text[], switch_to_guest[]; @@ -181,7 +195,7 @@ void lguest_device_remove(void); /* hypercalls.c: */ -void do_hypercalls(struct lguest *lg); +void do_hypercalls(struct lg_cpu *cpu); void write_timestamp(struct lguest *lg); /*L:035 --- linux-2.6.24.orig/drivers/lguest/Makefile +++ linux-2.6.24/drivers/lguest/Makefile @@ -19,3 +19,11 @@ @for f in Preparation Guest Drivers Launcher Host Switcher Mastery; do echo "{==- $$f -==}"; make -s $$f; done; echo "{==-==}" Preparation Preparation! Guest Drivers Launcher Host Switcher Mastery: @sh ../../Documentation/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'` +Puppy: + @clear + @printf " __ \n (___()'\`;\n /, /\`\n \\\\\\\"--\\\\\\ \n" + @sleep 2; clear; printf "\n\n Sit!\n\n"; sleep 1; clear + @printf " __ \n ()'\`; \n /\\|\` \n / | \n(/_)_|_ \n" + @sleep 2; clear; printf "\n\n Stand!\n\n"; sleep 1; clear + @printf " __ \n ()'\`; \n /\\|\` \n /._.= \n /| / \n(_\_)_ \n" + @sleep 2; clear; printf "\n\n Good puppy!\n\n"; sleep 1; clear --- linux-2.6.24.orig/drivers/lguest/lguest_user.c +++ linux-2.6.24/drivers/lguest/lguest_user.c @@ -13,7 +13,7 @@ * LHREQ_BREAK and the value "1" to /dev/lguest to do this. Once the Launcher * has done whatever needs attention, it writes LHREQ_BREAK and "0" to release * the Waker. */ -static int break_guest_out(struct lguest *lg, const unsigned long __user *input) +static int break_guest_out(struct lg_cpu *cpu, const unsigned long __user*input) { unsigned long on; @@ -22,21 +22,21 @@ return -EFAULT; if (on) { - lg->break_out = 1; + cpu->break_out = 1; /* Pop it out of the Guest (may be running on different CPU) */ - wake_up_process(lg->tsk); + wake_up_process(cpu->tsk); /* Wait for them to reset it */ - return wait_event_interruptible(lg->break_wq, !lg->break_out); + return wait_event_interruptible(cpu->break_wq, !cpu->break_out); } else { - lg->break_out = 0; - wake_up(&lg->break_wq); + cpu->break_out = 0; + wake_up(&cpu->break_wq); return 0; } } /*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt * number to /dev/lguest. */ -static int user_send_irq(struct lguest *lg, const unsigned long __user *input) +static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input) { unsigned long irq; @@ -46,7 +46,7 @@ return -EINVAL; /* Next time the Guest runs, the core code will see if it can deliver * this interrupt. */ - set_bit(irq, lg->irqs_pending); + set_bit(irq, cpu->irqs_pending); return 0; } @@ -55,13 +55,21 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o) { struct lguest *lg = file->private_data; + struct lg_cpu *cpu; + unsigned int cpu_id = *o; /* You must write LHREQ_INITIALIZE first! */ if (!lg) return -EINVAL; + /* Watch out for arbitrary vcpu indexes! */ + if (cpu_id >= lg->nr_cpus) + return -EINVAL; + + cpu = &lg->cpus[cpu_id]; + /* If you're not the task which owns the Guest, go away. */ - if (current != lg->tsk) + if (current != cpu->tsk) return -EPERM; /* If the guest is already dead, we indicate why */ @@ -81,11 +89,49 @@ /* If we returned from read() last time because the Guest notified, * clear the flag. */ - if (lg->pending_notify) - lg->pending_notify = 0; + if (cpu->pending_notify) + cpu->pending_notify = 0; /* Run the Guest until something interesting happens. */ - return run_guest(lg, (unsigned long __user *)user); + return run_guest(cpu, (unsigned long __user *)user); +} + +static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip) +{ + if (id >= NR_CPUS) + return -EINVAL; + + cpu->id = id; + cpu->lg = container_of((cpu - id), struct lguest, cpus[0]); + cpu->lg->nr_cpus++; + init_clockdev(cpu); + + /* We need a complete page for the Guest registers: they are accessible + * to the Guest and we can only grant it access to whole pages. */ + cpu->regs_page = get_zeroed_page(GFP_KERNEL); + if (!cpu->regs_page) + return -ENOMEM; + + /* We actually put the registers at the bottom of the page. */ + cpu->regs = (void *)cpu->regs_page + PAGE_SIZE - sizeof(*cpu->regs); + + /* Now we initialize the Guest's registers, handing it the start + * address. */ + lguest_arch_setup_regs(cpu, start_ip); + + /* Initialize the queue for the waker to wait on */ + init_waitqueue_head(&cpu->break_wq); + + /* We keep a pointer to the Launcher task (ie. current task) for when + * other Guests want to wake this one (inter-Guest I/O). */ + cpu->tsk = current; + + /* We need to keep a pointer to the Launcher's memory map, because if + * the Launcher dies we need to clean it up. If we don't keep a + * reference, it is destroyed before close() is called. */ + cpu->mm = get_task_mm(cpu->tsk); + + return 0; } /*L:020 The initialization write supplies 4 pointer sized (32 or 64 bit) @@ -134,15 +180,10 @@ lg->mem_base = (void __user *)(long)args[0]; lg->pfn_limit = args[1]; - /* We need a complete page for the Guest registers: they are accessible - * to the Guest and we can only grant it access to whole pages. */ - lg->regs_page = get_zeroed_page(GFP_KERNEL); - if (!lg->regs_page) { - err = -ENOMEM; + /* This is the first cpu */ + err = lg_cpu_start(&lg->cpus[0], 0, args[3]); + if (err) goto release_guest; - } - /* We actually put the registers at the bottom of the page. */ - lg->regs = (void *)lg->regs_page + PAGE_SIZE - sizeof(*lg->regs); /* Initialize the Guest's shadow page tables, using the toplevel * address the Launcher gave us. This allocates memory, so can @@ -151,24 +192,6 @@ if (err) goto free_regs; - /* Now we initialize the Guest's registers, handing it the start - * address. */ - lguest_arch_setup_regs(lg, args[3]); - - /* The timer for lguest's clock needs initialization. */ - init_clockdev(lg); - - /* We keep a pointer to the Launcher task (ie. current task) for when - * other Guests want to wake this one (inter-Guest I/O). */ - lg->tsk = current; - /* We need to keep a pointer to the Launcher's memory map, because if - * the Launcher dies we need to clean it up. If we don't keep a - * reference, it is destroyed before close() is called. */ - lg->mm = get_task_mm(lg->tsk); - - /* Initialize the queue for the waker to wait on */ - init_waitqueue_head(&lg->break_wq); - /* We remember which CPU's pages this Guest used last, for optimization * when the same Guest runs on the same CPU twice. */ lg->last_pages = NULL; @@ -182,7 +205,8 @@ return sizeof(args); free_regs: - free_page(lg->regs_page); + /* FIXME: This should be in free_vcpu */ + free_page(lg->cpus[0].regs_page); release_guest: kfree(lg); unlock: @@ -202,30 +226,37 @@ struct lguest *lg = file->private_data; const unsigned long __user *input = (const unsigned long __user *)in; unsigned long req; + struct lg_cpu *uninitialized_var(cpu); + unsigned int cpu_id = *off; if (get_user(req, input) != 0) return -EFAULT; input++; /* If you haven't initialized, you must do that first. */ - if (req != LHREQ_INITIALIZE && !lg) - return -EINVAL; + if (req != LHREQ_INITIALIZE) { + if (!lg || (cpu_id >= lg->nr_cpus)) + return -EINVAL; + cpu = &lg->cpus[cpu_id]; + if (!cpu) + return -EINVAL; + } /* Once the Guest is dead, all you can do is read() why it died. */ if (lg && lg->dead) return -ENOENT; /* If you're not the task which owns the Guest, you can only break */ - if (lg && current != lg->tsk && req != LHREQ_BREAK) + if (lg && current != cpu->tsk && req != LHREQ_BREAK) return -EPERM; switch (req) { case LHREQ_INITIALIZE: return initialize(file, input); case LHREQ_IRQ: - return user_send_irq(lg, input); + return user_send_irq(cpu, input); case LHREQ_BREAK: - return break_guest_out(lg, input); + return break_guest_out(cpu, input); default: return -EINVAL; } @@ -241,6 +272,7 @@ static int close(struct inode *inode, struct file *file) { struct lguest *lg = file->private_data; + unsigned int i; /* If we never successfully initialized, there's nothing to clean up */ if (!lg) @@ -249,19 +281,23 @@ /* We need the big lock, to protect from inter-guest I/O and other * Launchers initializing guests. */ mutex_lock(&lguest_lock); - /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */ - hrtimer_cancel(&lg->hrt); + /* Free up the shadow page tables for the Guest. */ free_guest_pagetable(lg); - /* Now all the memory cleanups are done, it's safe to release the - * Launcher's memory management structure. */ - mmput(lg->mm); + + for (i = 0; i < lg->nr_cpus; i++) { + /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */ + hrtimer_cancel(&lg->cpus[i].hrt); + /* We can free up the register page we allocated. */ + free_page(lg->cpus[i].regs_page); + /* Now all the memory cleanups are done, it's safe to release + * the Launcher's memory management structure. */ + mmput(lg->cpus[i].mm); + } /* If lg->dead doesn't contain an error code it will be NULL or a * kmalloc()ed string, either of which is ok to hand to kfree(). */ if (!IS_ERR(lg->dead)) kfree(lg->dead); - /* We can free up the register page we allocated. */ - free_page(lg->regs_page); /* We clear the entire structure, which also marks it as free for the * next user. */ memset(lg, 0, sizeof(*lg)); --- linux-2.6.24.orig/drivers/lguest/interrupts_and_traps.c +++ linux-2.6.24/drivers/lguest/interrupts_and_traps.c @@ -60,41 +60,42 @@ * We set up the stack just like the CPU does for a real interrupt, so it's * identical for the Guest (and the standard "iret" instruction will undo * it). */ -static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) +static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi, int has_err) { unsigned long gstack, origstack; u32 eflags, ss, irq_enable; unsigned long virtstack; + struct lguest *lg = cpu->lg; /* There are two cases for interrupts: one where the Guest is already * in the kernel, and a more complex one where the Guest is in * userspace. We check the privilege level to find out. */ - if ((lg->regs->ss&0x3) != GUEST_PL) { + if ((cpu->regs->ss&0x3) != GUEST_PL) { /* The Guest told us their kernel stack with the SET_STACK * hypercall: both the virtual address and the segment */ - virtstack = lg->esp1; - ss = lg->ss1; + virtstack = cpu->esp1; + ss = cpu->ss1; - origstack = gstack = guest_pa(lg, virtstack); + origstack = gstack = guest_pa(cpu, virtstack); /* We push the old stack segment and pointer onto the new * stack: when the Guest does an "iret" back from the interrupt * handler the CPU will notice they're dropping privilege * levels and expect these here. */ - push_guest_stack(lg, &gstack, lg->regs->ss); - push_guest_stack(lg, &gstack, lg->regs->esp); + push_guest_stack(lg, &gstack, cpu->regs->ss); + push_guest_stack(lg, &gstack, cpu->regs->esp); } else { /* We're staying on the same Guest (kernel) stack. */ - virtstack = lg->regs->esp; - ss = lg->regs->ss; + virtstack = cpu->regs->esp; + ss = cpu->regs->ss; - origstack = gstack = guest_pa(lg, virtstack); + origstack = gstack = guest_pa(cpu, virtstack); } /* Remember that we never let the Guest actually disable interrupts, so * the "Interrupt Flag" bit is always set. We copy that bit from the * Guest's "irq_enabled" field into the eflags word: we saw the Guest * copy it back in "lguest_iret". */ - eflags = lg->regs->eflags; + eflags = cpu->regs->eflags; if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0 && !(irq_enable & X86_EFLAGS_IF)) eflags &= ~X86_EFLAGS_IF; @@ -103,19 +104,19 @@ * "eflags" word, the old code segment, and the old instruction * pointer. */ push_guest_stack(lg, &gstack, eflags); - push_guest_stack(lg, &gstack, lg->regs->cs); - push_guest_stack(lg, &gstack, lg->regs->eip); + push_guest_stack(lg, &gstack, cpu->regs->cs); + push_guest_stack(lg, &gstack, cpu->regs->eip); /* For the six traps which supply an error code, we push that, too. */ if (has_err) - push_guest_stack(lg, &gstack, lg->regs->errcode); + push_guest_stack(lg, &gstack, cpu->regs->errcode); /* Now we've pushed all the old state, we change the stack, the code * segment and the address to execute. */ - lg->regs->ss = ss; - lg->regs->esp = virtstack + (gstack - origstack); - lg->regs->cs = (__KERNEL_CS|GUEST_PL); - lg->regs->eip = idt_address(lo, hi); + cpu->regs->ss = ss; + cpu->regs->esp = virtstack + (gstack - origstack); + cpu->regs->cs = (__KERNEL_CS|GUEST_PL); + cpu->regs->eip = idt_address(lo, hi); /* There are two kinds of interrupt handlers: 0xE is an "interrupt * gate" which expects interrupts to be disabled on entry. */ @@ -129,9 +130,10 @@ * * maybe_do_interrupt() gets called before every entry to the Guest, to see if * we should divert the Guest to running an interrupt handler. */ -void maybe_do_interrupt(struct lguest *lg) +void maybe_do_interrupt(struct lg_cpu *cpu) { unsigned int irq; + struct lguest *lg = cpu->lg; DECLARE_BITMAP(blk, LGUEST_IRQS); struct desc_struct *idt; @@ -145,7 +147,7 @@ sizeof(blk))) return; - bitmap_andnot(blk, lg->irqs_pending, blk, LGUEST_IRQS); + bitmap_andnot(blk, cpu->irqs_pending, blk, LGUEST_IRQS); /* Find the first interrupt. */ irq = find_first_bit(blk, LGUEST_IRQS); @@ -155,15 +157,15 @@ /* They may be in the middle of an iret, where they asked us never to * deliver interrupts. */ - if (lg->regs->eip >= lg->noirq_start && lg->regs->eip < lg->noirq_end) + if (cpu->regs->eip >= lg->noirq_start && cpu->regs->eip < lg->noirq_end) return; /* If they're halted, interrupts restart them. */ - if (lg->halted) { + if (cpu->halted) { /* Re-enable interrupts. */ if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled)) kill_guest(lg, "Re-enabling interrupts"); - lg->halted = 0; + cpu->halted = 0; } else { /* Otherwise we check if they have interrupts disabled. */ u32 irq_enabled; @@ -176,15 +178,15 @@ /* Look at the IDT entry the Guest gave us for this interrupt. The * first 32 (FIRST_EXTERNAL_VECTOR) entries are for traps, so we skip * over them. */ - idt = &lg->arch.idt[FIRST_EXTERNAL_VECTOR+irq]; + idt = &cpu->arch.idt[FIRST_EXTERNAL_VECTOR+irq]; /* If they don't have a handler (yet?), we just ignore it */ if (idt_present(idt->a, idt->b)) { /* OK, mark it no longer pending and deliver it. */ - clear_bit(irq, lg->irqs_pending); + clear_bit(irq, cpu->irqs_pending); /* set_guest_interrupt() takes the interrupt descriptor and a * flag to say whether this interrupt pushes an error code onto * the stack as well: virtual interrupts never do. */ - set_guest_interrupt(lg, idt->a, idt->b, 0); + set_guest_interrupt(cpu, idt->a, idt->b, 0); } /* Every time we deliver an interrupt, we update the timestamp in the @@ -245,19 +247,19 @@ } /* deliver_trap() returns true if it could deliver the trap. */ -int deliver_trap(struct lguest *lg, unsigned int num) +int deliver_trap(struct lg_cpu *cpu, unsigned int num) { /* Trap numbers are always 8 bit, but we set an impossible trap number * for traps inside the Switcher, so check that here. */ - if (num >= ARRAY_SIZE(lg->arch.idt)) + if (num >= ARRAY_SIZE(cpu->arch.idt)) return 0; /* Early on the Guest hasn't set the IDT entries (or maybe it put a * bogus one in): if we fail here, the Guest will be killed. */ - if (!idt_present(lg->arch.idt[num].a, lg->arch.idt[num].b)) + if (!idt_present(cpu->arch.idt[num].a, cpu->arch.idt[num].b)) return 0; - set_guest_interrupt(lg, lg->arch.idt[num].a, lg->arch.idt[num].b, - has_err(num)); + set_guest_interrupt(cpu, cpu->arch.idt[num].a, + cpu->arch.idt[num].b, has_err(num)); return 1; } @@ -309,10 +311,11 @@ * the Guest. * * Which is deeply unfair, because (literally!) it wasn't the Guests' fault. */ -void pin_stack_pages(struct lguest *lg) +void pin_stack_pages(struct lg_cpu *cpu) { unsigned int i; + struct lguest *lg = cpu->lg; /* Depending on the CONFIG_4KSTACKS option, the Guest can have one or * two pages of stack space. */ for (i = 0; i < lg->stack_pages; i++) @@ -320,7 +323,7 @@ * start of the page after the kernel stack. Subtract one to * get back onto the first stack page, and keep subtracting to * get to the rest of the stack pages. */ - pin_page(lg, lg->esp1 - 1 - i * PAGE_SIZE); + pin_page(cpu, cpu->esp1 - 1 - i * PAGE_SIZE); } /* Direct traps also mean that we need to know whenever the Guest wants to use @@ -331,21 +334,21 @@ * * In Linux each process has its own kernel stack, so this happens a lot: we * change stacks on each context switch. */ -void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages) +void guest_set_stack(struct lg_cpu *cpu, u32 seg, u32 esp, unsigned int pages) { /* You are not allowed have a stack segment with privilege level 0: bad * Guest! */ if ((seg & 0x3) != GUEST_PL) - kill_guest(lg, "bad stack segment %i", seg); + kill_guest(cpu->lg, "bad stack segment %i", seg); /* We only expect one or two stack pages. */ if (pages > 2) - kill_guest(lg, "bad stack pages %u", pages); + kill_guest(cpu->lg, "bad stack pages %u", pages); /* Save where the stack is, and how many pages */ - lg->ss1 = seg; - lg->esp1 = esp; - lg->stack_pages = pages; + cpu->ss1 = seg; + cpu->esp1 = esp; + cpu->lg->stack_pages = pages; /* Make sure the new stack pages are mapped */ - pin_stack_pages(lg); + pin_stack_pages(cpu); } /* All this reference to mapping stacks leads us neatly into the other complex @@ -383,7 +386,7 @@ * * We saw the Guest setting Interrupt Descriptor Table (IDT) entries with the * LHCALL_LOAD_IDT_ENTRY hypercall before: that comes here. */ -void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi) +void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int num, u32 lo, u32 hi) { /* Guest never handles: NMI, doublefault, spurious interrupt or * hypercall. We ignore when it tries to set them. */ @@ -392,13 +395,13 @@ /* Mark the IDT as changed: next time the Guest runs we'll know we have * to copy this again. */ - lg->changed |= CHANGED_IDT; + cpu->lg->changed |= CHANGED_IDT; /* Check that the Guest doesn't try to step outside the bounds. */ - if (num >= ARRAY_SIZE(lg->arch.idt)) - kill_guest(lg, "Setting idt entry %u", num); + if (num >= ARRAY_SIZE(cpu->arch.idt)) + kill_guest(cpu->lg, "Setting idt entry %u", num); else - set_trap(lg, &lg->arch.idt[num], num, lo, hi); + set_trap(cpu->lg, &cpu->arch.idt[num], num, lo, hi); } /* The default entry for each interrupt points into the Switcher routines which @@ -434,14 +437,14 @@ /*H:240 We don't use the IDT entries in the "struct lguest" directly, instead * we copy them into the IDT which we've set up for Guests on this CPU, just * before we run the Guest. This routine does that copy. */ -void copy_traps(const struct lguest *lg, struct desc_struct *idt, +void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt, const unsigned long *def) { unsigned int i; /* We can simply copy the direct traps, otherwise we use the default * ones in the Switcher: they will return to the Host. */ - for (i = 0; i < ARRAY_SIZE(lg->arch.idt); i++) { + for (i = 0; i < ARRAY_SIZE(cpu->arch.idt); i++) { /* If no Guest can ever override this trap, leave it alone. */ if (!direct_trap(i)) continue; @@ -450,8 +453,8 @@ * Interrupt gates (type 14) disable interrupts as they are * entered, which we never let the Guest do. Not present * entries (type 0x0) also can't go direct, of course. */ - if (idt_type(lg->arch.idt[i].a, lg->arch.idt[i].b) == 0xF) - idt[i] = lg->arch.idt[i]; + if (idt_type(cpu->arch.idt[i].a, cpu->arch.idt[i].b) == 0xF) + idt[i] = cpu->arch.idt[i]; else /* Reset it to the default. */ default_idt_entry(&idt[i], i, def[i]); @@ -470,13 +473,13 @@ * infrastructure to set a callback at that time. * * 0 means "turn off the clock". */ -void guest_set_clockevent(struct lguest *lg, unsigned long delta) +void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta) { ktime_t expires; if (unlikely(delta == 0)) { /* Clock event device is shutting down. */ - hrtimer_cancel(&lg->hrt); + hrtimer_cancel(&cpu->hrt); return; } @@ -484,25 +487,25 @@ * all the time between now and the timer interrupt it asked for. This * is almost always the right thing to do. */ expires = ktime_add_ns(ktime_get_real(), delta); - hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS); + hrtimer_start(&cpu->hrt, expires, HRTIMER_MODE_ABS); } /* This is the function called when the Guest's timer expires. */ static enum hrtimer_restart clockdev_fn(struct hrtimer *timer) { - struct lguest *lg = container_of(timer, struct lguest, hrt); + struct lg_cpu *cpu = container_of(timer, struct lg_cpu, hrt); /* Remember the first interrupt is the timer interrupt. */ - set_bit(0, lg->irqs_pending); + set_bit(0, cpu->irqs_pending); /* If the Guest is actually stopped, we need to wake it up. */ - if (lg->halted) - wake_up_process(lg->tsk); + if (cpu->halted) + wake_up_process(cpu->tsk); return HRTIMER_NORESTART; } /* This sets up the timer for this Guest. */ -void init_clockdev(struct lguest *lg) +void init_clockdev(struct lg_cpu *cpu) { - hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS); - lg->hrt.function = clockdev_fn; + hrtimer_init(&cpu->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS); + cpu->hrt.function = clockdev_fn; } --- linux-2.6.24.orig/drivers/w1/w1_netlink.c +++ linux-2.6.24/drivers/w1/w1_netlink.c @@ -128,9 +128,8 @@ return err; } -static void w1_cn_callback(void *data) +static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { - struct cn_msg *msg = data; struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); struct w1_netlink_cmd *cmd; struct w1_slave *sl; --- linux-2.6.24.orig/drivers/firewire/fw-ohci.c +++ linux-2.6.24/drivers/firewire/fw-ohci.c @@ -1803,6 +1803,13 @@ page = payload >> PAGE_SHIFT; offset = payload & ~PAGE_MASK; rest = p->payload_length; + /* + * The controllers I've tested have not worked correctly when + * second_req_count is zero. Rather than do something we know won't + * work, return an error + */ + if (rest == 0) + return -EINVAL; /* FIXME: make packet-per-buffer/dual-buffer a context option */ while (rest > 0) { --- linux-2.6.24.orig/drivers/parisc/eisa_eeprom.c +++ linux-2.6.24/drivers/parisc/eisa_eeprom.c @@ -54,7 +54,7 @@ ssize_t ret; int i; - if (*ppos >= HPEE_MAX_LENGTH) + if (*ppos < 0 || *ppos >= HPEE_MAX_LENGTH) return 0; count = *ppos + count < HPEE_MAX_LENGTH ? count : HPEE_MAX_LENGTH - *ppos; --- linux-2.6.24.orig/drivers/infiniband/ulp/srp/ib_srp.c +++ linux-2.6.24/drivers/infiniband/ulp/srp/ib_srp.c @@ -2055,6 +2055,7 @@ &host->target_list, list) { srp_remove_host(target->scsi_host); scsi_remove_host(target->scsi_host); + srp_remove_host(target->scsi_host); srp_disconnect_target(target); ib_destroy_cm_id(target->cm_id); srp_free_target_ib(target); --- linux-2.6.24.orig/drivers/input/joystick/xpad.c +++ linux-2.6.24/drivers/input/joystick/xpad.c @@ -136,6 +136,7 @@ { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, + { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, @@ -180,6 +181,7 @@ static struct usb_device_id xpad_table [] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ { USB_DEVICE_INTERFACE_PROTOCOL(0x045e, 0x028e, 1) }, /* X-Box 360 controller */ + { USB_DEVICE_INTERFACE_PROTOCOL(0x1430, 0x4748, 1) }, /* RedOctane Guitar Hero X-plorer */ { } }; --- linux-2.6.24.orig/drivers/input/serio/i8042-x86ia64io.h +++ linux-2.6.24/drivers/input/serio/i8042-x86ia64io.h @@ -270,6 +270,13 @@ DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"), }, }, + { + .ident = "IBM 2656", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "2656"), + }, + }, { } }; --- linux-2.6.24.orig/drivers/input/keyboard/atkbd.c +++ linux-2.6.24/drivers/input/keyboard/atkbd.c @@ -809,6 +809,8 @@ static void atkbd_cleanup(struct serio *serio) { struct atkbd *atkbd = serio_get_drvdata(serio); + + atkbd_disable(atkbd); ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT); } --- linux-2.6.24.orig/drivers/input/mouse/appletouch.c +++ linux-2.6.24/drivers/input/mouse/appletouch.c @@ -62,6 +62,11 @@ #define GEYSER4_ISO_PRODUCT_ID 0x021B #define GEYSER4_JIS_PRODUCT_ID 0x021C +/* Updated codes for MacBook3,1 support */ +#define GEYSER4_HF_ANSI_PRODUCT_ID 0x0229 +#define GEYSER4_HF_ISO_PRODUCT_ID 0x022A +#define GEYSER4_HF_JIS_PRODUCT_ID 0x021B + #define ATP_DEVICE(prod) \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ USB_DEVICE_ID_MATCH_INT_CLASS | \ @@ -93,6 +98,11 @@ { ATP_DEVICE(GEYSER4_ISO_PRODUCT_ID) }, { ATP_DEVICE(GEYSER4_JIS_PRODUCT_ID) }, + /* Core2 Duo MacBook3,1 */ + { ATP_DEVICE(GEYSER4_HF_ANSI_PRODUCT_ID) }, + { ATP_DEVICE(GEYSER4_HF_ISO_PRODUCT_ID) }, + { ATP_DEVICE(GEYSER4_HF_JIS_PRODUCT_ID) }, + /* Terminating entry */ { } }; @@ -217,7 +227,10 @@ (productId == GEYSER3_JIS_PRODUCT_ID) || (productId == GEYSER4_ANSI_PRODUCT_ID) || (productId == GEYSER4_ISO_PRODUCT_ID) || - (productId == GEYSER4_JIS_PRODUCT_ID); + (productId == GEYSER4_JIS_PRODUCT_ID) || + (productId == GEYSER4_HF_ANSI_PRODUCT_ID) || + (productId == GEYSER4_HF_ISO_PRODUCT_ID) || + (productId == GEYSER4_HF_JIS_PRODUCT_ID); } /* --- linux-2.6.24.orig/drivers/input/mouse/alps.c +++ linux-2.6.24/drivers/input/mouse/alps.c @@ -37,6 +37,7 @@ #define ALPS_FW_BK_2 0x40 static const struct alps_model_info alps_model_data[] = { + { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, @@ -54,6 +55,7 @@ { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ + { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 } /* Dell Vostro 1400 */ }; @@ -421,7 +423,8 @@ static int alps_reconnect(struct psmouse *psmouse) { - psmouse_reset(psmouse); + /* UBUNTU: Causes lockups on resume */ + /* psmouse_reset(psmouse); */ if (alps_hw_init(psmouse, NULL)) return -1; --- linux-2.6.24.orig/drivers/acorn/char/defkeymap-l7200.c +++ linux-2.6.24/drivers/acorn/char/defkeymap-l7200.c @@ -347,40 +347,40 @@ }; struct kbdiacruc accent_table[MAX_DIACR] = { - {'`', 'A', '\300'}, {'`', 'a', '\340'}, - {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, - {'^', 'A', '\302'}, {'^', 'a', '\342'}, - {'~', 'A', '\303'}, {'~', 'a', '\343'}, - {'"', 'A', '\304'}, {'"', 'a', '\344'}, - {'O', 'A', '\305'}, {'o', 'a', '\345'}, - {'0', 'A', '\305'}, {'0', 'a', '\345'}, - {'A', 'A', '\305'}, {'a', 'a', '\345'}, - {'A', 'E', '\306'}, {'a', 'e', '\346'}, - {',', 'C', '\307'}, {',', 'c', '\347'}, - {'`', 'E', '\310'}, {'`', 'e', '\350'}, - {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, - {'^', 'E', '\312'}, {'^', 'e', '\352'}, - {'"', 'E', '\313'}, {'"', 'e', '\353'}, - {'`', 'I', '\314'}, {'`', 'i', '\354'}, - {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, - {'^', 'I', '\316'}, {'^', 'i', '\356'}, - {'"', 'I', '\317'}, {'"', 'i', '\357'}, - {'-', 'D', '\320'}, {'-', 'd', '\360'}, - {'~', 'N', '\321'}, {'~', 'n', '\361'}, - {'`', 'O', '\322'}, {'`', 'o', '\362'}, - {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, - {'^', 'O', '\324'}, {'^', 'o', '\364'}, - {'~', 'O', '\325'}, {'~', 'o', '\365'}, - {'"', 'O', '\326'}, {'"', 'o', '\366'}, - {'/', 'O', '\330'}, {'/', 'o', '\370'}, - {'`', 'U', '\331'}, {'`', 'u', '\371'}, - {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, - {'^', 'U', '\333'}, {'^', 'u', '\373'}, - {'"', 'U', '\334'}, {'"', 'u', '\374'}, - {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, - {'T', 'H', '\336'}, {'t', 'h', '\376'}, - {'s', 's', '\337'}, {'"', 'y', '\377'}, - {'s', 'z', '\337'}, {'i', 'j', '\377'}, + {'`', 'A', 0300}, {'`', 'a', 0340}, + {'\'', 'A', 0301}, {'\'', 'a', 0341}, + {'^', 'A', 0302}, {'^', 'a', 0342}, + {'~', 'A', 0303}, {'~', 'a', 0343}, + {'"', 'A', 0304}, {'"', 'a', 0344}, + {'O', 'A', 0305}, {'o', 'a', 0345}, + {'0', 'A', 0305}, {'0', 'a', 0345}, + {'A', 'A', 0305}, {'a', 'a', 0345}, + {'A', 'E', 0306}, {'a', 'e', 0346}, + {',', 'C', 0307}, {',', 'c', 0347}, + {'`', 'E', 0310}, {'`', 'e', 0350}, + {'\'', 'E', 0311}, {'\'', 'e', 0351}, + {'^', 'E', 0312}, {'^', 'e', 0352}, + {'"', 'E', 0313}, {'"', 'e', 0353}, + {'`', 'I', 0314}, {'`', 'i', 0354}, + {'\'', 'I', 0315}, {'\'', 'i', 0355}, + {'^', 'I', 0316}, {'^', 'i', 0356}, + {'"', 'I', 0317}, {'"', 'i', 0357}, + {'-', 'D', 0320}, {'-', 'd', 0360}, + {'~', 'N', 0321}, {'~', 'n', 0361}, + {'`', 'O', 0322}, {'`', 'o', 0362}, + {'\'', 'O', 0323}, {'\'', 'o', 0363}, + {'^', 'O', 0324}, {'^', 'o', 0364}, + {'~', 'O', 0325}, {'~', 'o', 0365}, + {'"', 'O', 0326}, {'"', 'o', 0366}, + {'/', 'O', 0330}, {'/', 'o', 0370}, + {'`', 'U', 0331}, {'`', 'u', 0371}, + {'\'', 'U', 0332}, {'\'', 'u', 0372}, + {'^', 'U', 0333}, {'^', 'u', 0373}, + {'"', 'U', 0334}, {'"', 'u', 0374}, + {'\'', 'Y', 0335}, {'\'', 'y', 0375}, + {'T', 'H', 0336}, {'t', 'h', 0376}, + {'s', 's', 0337}, {'"', 'y', 0377}, + {'s', 'z', 0337}, {'i', 'j', 0377}, }; unsigned int accent_table_size = 68; --- linux-2.6.24.orig/drivers/pcmcia/cs.c +++ linux-2.6.24/drivers/pcmcia/cs.c @@ -565,7 +565,10 @@ if (!(skt->state & SOCKET_PRESENT)) { skt->state &= ~SOCKET_SUSPEND; - return socket_insert(skt); + /* UBUNTU: This causes problems on resume. Userspace + * scripts take care of this. */ + /* return socket_insert(skt); */ + return 0; } ret = socket_setup(skt, resume_delay); --- linux-2.6.24.orig/drivers/connector/connector.c +++ linux-2.6.24/drivers/connector/connector.c @@ -126,10 +126,11 @@ /* * Callback helper - queues work and setup destructor for given data. */ -static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), void *data) +static int cn_call_callback(struct sk_buff *skb, void (*destruct_data)(void *), void *data) { struct cn_callback_entry *__cbq, *__new_cbq; struct cn_dev *dev = &cdev; + struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(skb)); int err = -ENODEV; spin_lock_bh(&dev->cbdev->queue_lock); @@ -137,7 +138,7 @@ if (cn_cb_equal(&__cbq->id.id, &msg->id)) { if (likely(!work_pending(&__cbq->work) && __cbq->data.ddata == NULL)) { - __cbq->data.callback_priv = msg; + __cbq->data.skb = skb; __cbq->data.ddata = data; __cbq->data.destruct_data = destruct_data; @@ -154,7 +155,7 @@ __new_cbq = kzalloc(sizeof(struct cn_callback_entry), GFP_ATOMIC); if (__new_cbq) { d = &__new_cbq->data; - d->callback_priv = msg; + d->skb = skb; d->callback = __cbq->data.callback; d->ddata = data; d->destruct_data = destruct_data; @@ -195,7 +196,7 @@ group = NETLINK_CB((skb)).dst_group; msg = NLMSG_DATA(nlh); - return cn_call_callback(msg, (void (*)(void *))kfree_skb, skb); + return cn_call_callback(skb, (void (*)(void *))kfree_skb, skb); } /* @@ -287,7 +288,8 @@ * * May sleep. */ -int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *)) +int cn_add_callback(struct cb_id *id, char *name, + void (*callback)(struct cn_msg *, struct netlink_skb_parms *)) { int err; struct cn_dev *dev = &cdev; @@ -369,9 +371,8 @@ * * Used for notification of a request's processing. */ -static void cn_callback(void *data) +static void cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { - struct cn_msg *msg = data; struct cn_ctl_msg *ctl; struct cn_ctl_entry *ent; u32 size; --- linux-2.6.24.orig/drivers/connector/cn_queue.c +++ linux-2.6.24/drivers/connector/cn_queue.c @@ -36,8 +36,10 @@ struct cn_callback_entry *cbq = container_of(work, struct cn_callback_entry, work); struct cn_callback_data *d = &cbq->data; + struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(d->skb)); + struct netlink_skb_parms *nsp = &NETLINK_CB(d->skb); - d->callback(d->callback_priv); + d->callback(msg, nsp); d->destruct_data(d->ddata); d->ddata = NULL; @@ -45,7 +47,9 @@ kfree(d->free); } -static struct cn_callback_entry *cn_queue_alloc_callback_entry(char *name, struct cb_id *id, void (*callback)(void *)) +static struct cn_callback_entry * +cn_queue_alloc_callback_entry(char *name, struct cb_id *id, + void (*callback)(struct cn_msg *, struct netlink_skb_parms *)) { struct cn_callback_entry *cbq; @@ -75,7 +79,8 @@ return ((i1->idx == i2->idx) && (i1->val == i2->val)); } -int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *)) +int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, + void (*callback)(struct cn_msg *, struct netlink_skb_parms *)) { struct cn_callback_entry *cbq, *__cbq; int found = 0; --- linux-2.6.24.orig/drivers/connector/cn_proc.c +++ linux-2.6.24/drivers/connector/cn_proc.c @@ -196,9 +196,9 @@ * cn_proc_mcast_ctl * @data: message sent from userspace via the connector */ -static void cn_proc_mcast_ctl(void *data) +static void cn_proc_mcast_ctl(struct cn_msg *msg, + struct netlink_skb_parms *nsp) { - struct cn_msg *msg = data; enum proc_cn_mcast_op *mc_op = NULL; int err = 0; --- linux-2.6.24.orig/drivers/hwmon/hdaps.c +++ linux-2.6.24/drivers/hwmon/hdaps.c @@ -521,10 +521,16 @@ HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"), HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"), HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60"), + HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61"), HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"), HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X41"), HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60"), + HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61"), + HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61 Tablet"), HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"), + HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T61P"), + HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R61"), + HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T61"), { .ident = NULL } }; --- linux-2.6.24.orig/drivers/hwmon/w83781d.c +++ linux-2.6.24/drivers/hwmon/w83781d.c @@ -1380,7 +1380,8 @@ /* Reserve the ISA region */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!request_region(res->start, W83781D_EXTENT, "w83781d")) { + if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2, + "w83781d")) { err = -EBUSY; goto exit; } @@ -1432,7 +1433,7 @@ device_remove_file(&pdev->dev, &dev_attr_name); kfree(data); exit_release_region: - release_region(res->start, W83781D_EXTENT); + release_region(res->start + W83781D_ADDR_REG_OFFSET, 2); exit: return err; } @@ -1446,7 +1447,7 @@ sysfs_remove_group(&pdev->dev.kobj, &w83781d_group); sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt); device_remove_file(&pdev->dev, &dev_attr_name); - release_region(data->client.addr, W83781D_EXTENT); + release_region(data->client.addr + W83781D_ADDR_REG_OFFSET, 2); kfree(data); return 0; @@ -1820,8 +1821,17 @@ { int val, save, found = 0; - if (!request_region(address, W83781D_EXTENT, "w83781d")) + /* We have to request the region in two parts because some + boards declare base+4 to base+7 as a PNP device */ + if (!request_region(address, 4, "w83781d")) { + pr_debug("w83781d: Failed to request low part of region\n"); return 0; + } + if (!request_region(address + 4, 4, "w83781d")) { + pr_debug("w83781d: Failed to request high part of region\n"); + release_region(address, 4); + return 0; + } #define REALLY_SLOW_IO /* We need the timeouts for at least some W83781D-like @@ -1896,7 +1906,8 @@ val == 0x30 ? "W83782D" : "W83781D", (int)address); release: - release_region(address, W83781D_EXTENT); + release_region(address + 4, 4); + release_region(address, 4); return found; } --- linux-2.6.24.orig/drivers/hwmon/coretemp.c +++ linux-2.6.24/drivers/hwmon/coretemp.c @@ -368,10 +368,10 @@ for_each_online_cpu(i) { struct cpuinfo_x86 *c = &cpu_data(i); - /* check if family 6, models e, f, 16 */ + /* check if family 6, models 0xe, 0xf, 0x16, 0x17 */ if ((c->cpuid_level < 0) || (c->x86 != 0x6) || !((c->x86_model == 0xe) || (c->x86_model == 0xf) || - (c->x86_model == 0x16))) { + (c->x86_model == 0x16) || (c->x86_model == 0x17))) { /* supported CPU not found, but report the unknown family 6 CPU */ --- linux-2.6.24.orig/drivers/Makefile +++ linux-2.6.24/drivers/Makefile @@ -47,7 +47,6 @@ obj-$(CONFIG_PCCARD) += pcmcia/ obj-$(CONFIG_DIO) += dio/ obj-$(CONFIG_SBUS) += sbus/ -obj-$(CONFIG_KVM) += kvm/ obj-$(CONFIG_ZORRO) += zorro/ obj-$(CONFIG_MAC) += macintosh/ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/ @@ -77,6 +76,7 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_CPU_IDLE) += cpuidle/ obj-$(CONFIG_MMC) += mmc/ +obj-$(CONFIG_MSS) += mmc/ obj-$(CONFIG_NEW_LEDS) += leds/ obj-$(CONFIG_INFINIBAND) += infiniband/ obj-$(CONFIG_SGI_SN) += sn/ --- linux-2.6.24.orig/drivers/hid/usbhid/hid-quirks.c +++ linux-2.6.24/drivers/hid/usbhid/hid-quirks.c @@ -19,6 +19,7 @@ #define USB_VENDOR_ID_A4TECH 0x09da #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 +#define USB_DEVICE_ID_A4TECH_X5_005D 0x000a #define USB_VENDOR_ID_AASHIMA 0x06d6 #define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025 @@ -59,6 +60,21 @@ #define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a #define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b #define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c +#define USB_DEVICE_ID_APPLE_ALU_ANSI 0x0220 +#define USB_DEVICE_ID_APPLE_ALU_ISO 0x0221 +#define USB_DEVICE_ID_APPLE_ALU_JIS 0x0222 +#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229 +#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a +#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b +#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c +#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d +#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e +#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223 +#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224 +#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225 +#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 +#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 +#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 @@ -66,6 +82,9 @@ #define USB_VENDOR_ID_ASUS 0x0b05 #define USB_DEVICE_ID_ASUS_LCM 0x1726 +#define USB_VENDOR_ID_ASUS 0x0b05 +#define USB_DEVICE_ID_ASUS_LCM 0x1726 + #define USB_VENDOR_ID_ATEN 0x0557 #define USB_DEVICE_ID_ATEN_UC100KM 0x2004 #define USB_DEVICE_ID_ATEN_CS124U 0x2202 @@ -116,6 +135,7 @@ #define USB_VENDOR_ID_GAMERON 0x0810 #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001 +#define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002 #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc @@ -368,6 +388,7 @@ } hid_blacklist[] = { { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, + { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D, HID_QUIRK_2WHEEL_MOUSE_HACK_B8 }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, @@ -377,6 +398,7 @@ { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, @@ -540,19 +562,34 @@ { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI, HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS, HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS }, @@ -645,6 +682,8 @@ { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, + { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE}, + { 0, 0 } }; @@ -751,6 +790,7 @@ return 0; } +EXPORT_SYMBOL(usbhid_modify_dquirk); /** * usbhid_remove_all_dquirks: remove all runtime HID quirks from memory --- linux-2.6.24.orig/drivers/hid/usbhid/Kconfig +++ linux-2.6.24/drivers/hid/usbhid/Kconfig @@ -25,12 +25,13 @@ depends on USB_HID && INPUT=n config USB_HIDINPUT_POWERBOOK - bool "Enable support for iBook/PowerBook/MacBook/MacBookPro special keys" + bool "Enable support for Apple laptop/aluminum USB special keys" default n depends on USB_HID help Say Y here if you want support for the special keys (Fn, Numlock) on - Apple iBooks, PowerBooks, MacBooks and MacBook Pros. + Apple iBooks, PowerBooks, MacBooks, MacBook Pros and aluminum USB + keyboards. If unsure, say N. --- linux-2.6.24.orig/drivers/hid/hid-input.c +++ linux-2.6.24/drivers/hid/hid-input.c @@ -34,10 +34,10 @@ #include #include -static int hid_pb_fnmode = 1; -module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644); +static int hid_apple_fnmode = 1; +module_param_named(pb_fnmode, hid_apple_fnmode, int, 0644); MODULE_PARM_DESC(pb_fnmode, - "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); + "Mode of fn key on Apple keyboards (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); #define unk KEY_UNKNOWN @@ -98,20 +98,41 @@ u8 flags; }; -#define POWERBOOK_FLAG_FKEY 0x01 +#define APPLE_FLAG_FKEY 0x01 + +static struct hidinput_key_translation apple_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_CYCLEWINDOWS, APPLE_FLAG_FKEY }, /* Exposé */ + { KEY_F4, KEY_FN_F4, APPLE_FLAG_FKEY }, /* Dashboard */ + { KEY_F5, KEY_FN_F5 }, + { KEY_F6, KEY_FN_F6 }, + { KEY_F7, KEY_BACK, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_FORWARD, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, + { } +}; static struct hidinput_key_translation powerbook_fn_keys[] = { { KEY_BACKSPACE, KEY_DELETE }, - { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY }, - { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY }, - { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY }, - { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY }, - { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY }, - { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY }, - { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F4, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F5, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_F6, KEY_NUMLOCK, APPLE_FLAG_FKEY }, + { KEY_F7, KEY_SWITCHVIDEOMODE, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_KBDILLUMTOGGLE, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_KBDILLUMUP, APPLE_FLAG_FKEY }, { KEY_UP, KEY_PAGEUP }, { KEY_DOWN, KEY_PAGEDOWN }, { KEY_LEFT, KEY_HOME }, @@ -142,7 +163,7 @@ { } }; -static struct hidinput_key_translation powerbook_iso_keyboard[] = { +static struct hidinput_key_translation apple_iso_keyboard[] = { { KEY_GRAVE, KEY_102ND }, { KEY_102ND, KEY_GRAVE }, { } @@ -160,39 +181,42 @@ return NULL; } -static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, +static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, struct hid_usage *usage, __s32 value) { struct hidinput_key_translation *trans; if (usage->code == KEY_FN) { - if (value) hid->quirks |= HID_QUIRK_POWERBOOK_FN_ON; - else hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON; + if (value) hid->quirks |= HID_QUIRK_APPLE_FN_ON; + else hid->quirks &= ~HID_QUIRK_APPLE_FN_ON; input_event(input, usage->type, usage->code, value); return 1; } - if (hid_pb_fnmode) { + if (hid_apple_fnmode) { int do_translate; - trans = find_translation(powerbook_fn_keys, usage->code); + trans = find_translation((hid->product < 0x220 || + hid->product >= 0x300) ? + powerbook_fn_keys : apple_fn_keys, + usage->code); if (trans) { - if (test_bit(usage->code, hid->pb_pressed_fn)) + if (test_bit(usage->code, hid->apple_pressed_fn)) do_translate = 1; - else if (trans->flags & POWERBOOK_FLAG_FKEY) + else if (trans->flags & APPLE_FLAG_FKEY) do_translate = - (hid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) || - (hid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)); + (hid_apple_fnmode == 2 && (hid->quirks & HID_QUIRK_APPLE_FN_ON)) || + (hid_apple_fnmode == 1 && !(hid->quirks & HID_QUIRK_APPLE_FN_ON)); else - do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON); + do_translate = (hid->quirks & HID_QUIRK_APPLE_FN_ON); if (do_translate) { if (value) - set_bit(usage->code, hid->pb_pressed_fn); + set_bit(usage->code, hid->apple_pressed_fn); else - clear_bit(usage->code, hid->pb_pressed_fn); + clear_bit(usage->code, hid->apple_pressed_fn); input_event(input, usage->type, trans->to, value); @@ -200,8 +224,9 @@ } } - if (test_bit(usage->code, hid->pb_pressed_numlock) || - test_bit(LED_NUML, input->led)) { + if (hid->quirks & HID_QUIRK_APPLE_NUMLOCK_EMULATION && ( + test_bit(usage->code, hid->pb_pressed_numlock) || + test_bit(LED_NUML, input->led))) { trans = find_translation(powerbook_numlock_keys, usage->code); if (trans) { @@ -217,8 +242,8 @@ } } - if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) { - trans = find_translation(powerbook_iso_keyboard, usage->code); + if (hid->quirks & HID_QUIRK_APPLE_ISO_KEYBOARD) { + trans = find_translation(apple_iso_keyboard, usage->code); if (trans) { input_event(input, usage->type, trans->to, value); return 1; @@ -228,31 +253,35 @@ return 0; } -static void hidinput_pb_setup(struct input_dev *input) +static void hidinput_apple_setup(struct input_dev *input) { struct hidinput_key_translation *trans; set_bit(KEY_NUMLOCK, input->keybit); /* Enable all needed keys */ + for (trans = apple_fn_keys; trans->from; trans++) + set_bit(trans->to, input->keybit); + for (trans = powerbook_fn_keys; trans->from; trans++) set_bit(trans->to, input->keybit); for (trans = powerbook_numlock_keys; trans->from; trans++) set_bit(trans->to, input->keybit); - for (trans = powerbook_iso_keyboard; trans->from; trans++) + for (trans = apple_iso_keyboard; trans->from; trans++) set_bit(trans->to, input->keybit); } #else -static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, - struct hid_usage *usage, __s32 value) +static inline int hidinput_apple_event(struct hid_device *hid, + struct input_dev *input, + struct hid_usage *usage, __s32 value) { return 0; } -static inline void hidinput_pb_setup(struct input_dev *input) +static inline void hidinput_apple_setup(struct input_dev *input) { } #endif @@ -785,14 +814,14 @@ } break; - case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */ + case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */ set_bit(EV_REP, input->evbit); switch(usage->hid & HID_USAGE) { case 0x003: - /* The fn key on Apple PowerBooks */ + /* The fn key on Apple USB keyboards */ map_key_clear(KEY_FN); - hidinput_pb_setup(input); + hidinput_apple_setup(input); break; default: goto ignore; @@ -867,9 +896,10 @@ map_key(BTN_1); } - if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) && - (usage->type == EV_REL) && (usage->code == REL_WHEEL)) - set_bit(REL_HWHEEL, bit); + if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5 | + HID_QUIRK_2WHEEL_MOUSE_HACK_B8)) && (usage->type == EV_REL) && + (usage->code == REL_WHEEL)) + set_bit(REL_HWHEEL, bit); if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) @@ -967,6 +997,19 @@ return; } + if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) && + (usage->type == EV_REL) && + (usage->code == REL_WHEEL)) { + hid->delayed_value = value; + return; + } + + if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) && + (usage->hid == 0x000100b8)) { + input_event(input, EV_REL, value ? REL_HWHEEL : REL_WHEEL, hid->delayed_value); + return; + } + if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) { input_event(input, usage->type, usage->code, -value); return; @@ -977,7 +1020,7 @@ return; } - if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value)) + if ((hid->quirks & HID_QUIRK_APPLE_HAS_FN) && hidinput_apple_event(hid, input, usage, value)) return; if (usage->hat_min < usage->hat_max || usage->hat_dir) { --- linux-2.6.24.orig/kernel/time/timekeeping.c +++ linux-2.6.24/kernel/time/timekeeping.c @@ -189,6 +189,7 @@ if (clock == new) return; + new->cycle_last = 0; now = clocksource_read(new); nsec = __get_nsec_offset(); timespec_add_ns(&xtime, nsec); @@ -301,6 +302,7 @@ /* Make sure that we have the correct xtime reference */ timespec_add_ns(&xtime, timekeeping_suspend_nsecs); /* re-base the last cycle value */ + clock->cycle_last = 0; clock->cycle_last = clocksource_read(clock); clock->error = 0; timekeeping_suspended = 0; --- linux-2.6.24.orig/kernel/sched_fair.c +++ linux-2.6.24/kernel/sched_fair.c @@ -20,6 +20,8 @@ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra */ +#include + /* * Targeted preemption latency for CPU-bound tasks: * (default: 20ms * (1 + ilog(ncpus)), units: nanoseconds) @@ -434,6 +436,7 @@ #ifdef CONFIG_SCHEDSTATS if (se->sleep_start) { u64 delta = rq_of(cfs_rq)->clock - se->sleep_start; + struct task_struct *tsk = task_of(se); if ((s64)delta < 0) delta = 0; @@ -443,9 +446,12 @@ se->sleep_start = 0; se->sum_sleep_runtime += delta; + + account_scheduler_latency(tsk, delta >> 10, 1); } if (se->block_start) { u64 delta = rq_of(cfs_rq)->clock - se->block_start; + struct task_struct *tsk = task_of(se); if ((s64)delta < 0) delta = 0; @@ -462,11 +468,11 @@ * time that the task spent sleeping: */ if (unlikely(prof_on == SLEEP_PROFILING)) { - struct task_struct *tsk = task_of(se); profile_hits(SLEEP_PROFILING, (void *)get_wchan(tsk), delta >> 20); } + account_scheduler_latency(tsk, delta >> 10, 0); } #endif } @@ -1104,6 +1110,16 @@ set_next_entity(cfs_rq_of(se), se); } +#ifdef CONFIG_FAIR_GROUP_SCHED +static void moved_group_fair(struct task_struct *p) +{ + struct cfs_rq *cfs_rq = task_cfs_rq(p); + + update_curr(cfs_rq); + place_entity(cfs_rq, &p->se, 1); +} +#endif + /* * All the scheduling class methods: */ @@ -1126,6 +1142,10 @@ .set_curr_task = set_curr_task_fair, .task_tick = task_tick_fair, .task_new = task_new_fair, + +#ifdef CONFIG_FAIR_GROUP_SCHED + .moved_group = moved_group_fair, +#endif }; #ifdef CONFIG_SCHED_DEBUG --- linux-2.6.24.orig/kernel/sysctl.c +++ linux-2.6.24/kernel/sysctl.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ #ifdef CONFIG_X86 #include #include +#include #endif static int deprecated_sysctl_warning(struct __sysctl_args *args); @@ -81,6 +83,7 @@ extern int maps_protect; extern int sysctl_stat_interval; extern int audit_argv_kb; +extern int latencytop_enabled; /* Constants used for minimum and maximum */ #ifdef CONFIG_DETECT_SOFTLOCKUP @@ -306,7 +309,7 @@ .procname = "sched_nr_migrate", .data = &sysctl_sched_nr_migrate, .maxlen = sizeof(unsigned int), - .mode = 644, + .mode = 0644, .proc_handler = &proc_dointvec, }, #endif @@ -382,6 +385,15 @@ .proc_handler = &proc_dointvec_taint, }, #endif +#ifdef CONFIG_LATENCYTOP + { + .procname = "latencytop", + .data = &latencytop_enabled, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif #ifdef CONFIG_SECURITY_CAPABILITIES { .procname = "cap-bound", @@ -683,6 +695,14 @@ .mode = 0644, .proc_handler = &proc_dointvec, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "io_delay_type", + .data = &io_delay_type, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #endif #if defined(CONFIG_MMU) { @@ -910,7 +930,7 @@ .data = &nr_overcommit_huge_pages, .maxlen = sizeof(nr_overcommit_huge_pages), .mode = 0644, - .proc_handler = &proc_doulongvec_minmax, + .proc_handler = &hugetlb_overcommit_handler, }, #endif { @@ -1217,6 +1237,22 @@ .mode = 0644, .proc_handler = &proc_dointvec, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "default_relatime", + .data = &default_relatime, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "relatime_interval", + .data = &relatime_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) { .ctl_name = CTL_UNNUMBERED, @@ -1327,6 +1363,33 @@ return NULL; } +char *sysctl_pathname(ctl_table *table, char *buffer, int buflen) +{ + if (buflen < 1) + return NULL; + buffer += --buflen; + *buffer = '\0'; + + while (table) { + int namelen = strlen(table->procname); + + if (buflen < namelen + 1) + return NULL; + buflen -= namelen + 1; + buffer -= namelen; + memcpy(buffer, table->procname, namelen); + *--buffer = '/'; + table = table->parent; + } + if (buflen < 4) + return NULL; + buffer -= 4; + memcpy(buffer, "/sys", 4); + + return buffer; +} +EXPORT_SYMBOL(sysctl_pathname); + #ifdef CONFIG_SYSCTL_SYSCALL int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen) --- linux-2.6.24.orig/kernel/signal.c +++ linux-2.6.24/kernel/signal.c @@ -739,7 +739,8 @@ for (i = 0; i < 16; i++) { unsigned char insn; - __get_user(insn, (unsigned char *)(regs->eip + i)); + if (get_user(insn, (unsigned char *)(regs->eip + i))) + break; printk("%02x ", insn); } } @@ -1150,7 +1151,8 @@ read_lock(&tasklist_lock); for_each_process(p) { - if (p->pid > 1 && !same_thread_group(p, current)) { + if (task_pid_vnr(p) > 1 && + !same_thread_group(p, current)) { int err = group_send_sig_info(sig, info, p); ++count; if (err != -EPERM) @@ -2358,11 +2360,9 @@ stack_t oss; int error; - if (uoss) { - oss.ss_sp = (void __user *) current->sas_ss_sp; - oss.ss_size = current->sas_ss_size; - oss.ss_flags = sas_ss_flags(sp); - } + oss.ss_sp = (void __user *) current->sas_ss_sp; + oss.ss_size = current->sas_ss_size; + oss.ss_flags = sas_ss_flags(sp); if (uss) { void __user *ss_sp; @@ -2405,13 +2405,16 @@ current->sas_ss_size = ss_size; } + error = 0; if (uoss) { error = -EFAULT; - if (copy_to_user(uoss, &oss, sizeof(oss))) + if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) goto out; + error = __put_user(oss.ss_sp, &uoss->ss_sp) | + __put_user(oss.ss_size, &uoss->ss_size) | + __put_user(oss.ss_flags, &uoss->ss_flags); } - error = 0; out: return error; } --- linux-2.6.24.orig/kernel/exit.c +++ linux-2.6.24/kernel/exit.c @@ -813,8 +813,7 @@ */ if (tsk->exit_signal != SIGCHLD && tsk->exit_signal != -1 && ( tsk->parent_exec_id != t->self_exec_id || - tsk->self_exec_id != tsk->parent_exec_id) - && !capable(CAP_KILL)) + tsk->self_exec_id != tsk->parent_exec_id)) tsk->exit_signal = SIGCHLD; --- linux-2.6.24.orig/kernel/auditfilter.c +++ linux-2.6.24/kernel/auditfilter.c @@ -1076,8 +1076,8 @@ list_for_each_entry_safe(p, n, in_list, ilist) { list_del(&p->ilist); inotify_rm_watch(audit_ih, &p->wdata); - /* the put matching the get in audit_do_del_rule() */ - put_inotify_watch(&p->wdata); + /* the unpin matching the pin in audit_do_del_rule() */ + unpin_inotify_watch(&p->wdata); } } @@ -1370,9 +1370,13 @@ /* Put parent on the inotify un-registration * list. Grab a reference before releasing * audit_filter_mutex, to be released in - * audit_inotify_unregister(). */ - list_add(&parent->ilist, &inotify_list); - get_inotify_watch(&parent->wdata); + * audit_inotify_unregister(). + * If filesystem is going away, just leave + * the sucker alone, eviction will take + * care of it. + */ + if (pin_inotify_watch(&parent->wdata)) + list_add(&parent->ilist, &inotify_list); } } } --- linux-2.6.24.orig/kernel/cgroup.c +++ linux-2.6.24/kernel/cgroup.c @@ -2611,7 +2611,7 @@ } /* Create the cgroup directory, which also creates the cgroup */ - ret = vfs_mkdir(inode, dentry, S_IFDIR | 0755); + ret = vfs_mkdir(inode, dentry, NULL, S_IFDIR | 0755); child = __d_cgrp(dentry); dput(dentry); if (ret) { --- linux-2.6.24.orig/kernel/audit_tree.c +++ linux-2.6.24/kernel/audit_tree.c @@ -24,6 +24,7 @@ struct list_head trees; /* with root here */ int dead; int count; + atomic_long_t refs; struct rcu_head head; struct node { struct list_head list; @@ -56,7 +57,8 @@ * tree is refcounted; one reference for "some rules on rules_list refer to * it", one for each chunk with pointer to it. * - * chunk is refcounted by embedded inotify_watch. + * chunk is refcounted by embedded inotify_watch + .refs (non-zero refcount + * of watch contributes 1 to .refs). * * node.index allows to get from node.list to containing chunk. * MSB of that sucker is stolen to mark taggings that we might have to @@ -121,6 +123,7 @@ INIT_LIST_HEAD(&chunk->hash); INIT_LIST_HEAD(&chunk->trees); chunk->count = count; + atomic_long_set(&chunk->refs, 1); for (i = 0; i < count; i++) { INIT_LIST_HEAD(&chunk->owners[i].list); chunk->owners[i].index = i; @@ -129,9 +132,8 @@ return chunk; } -static void __free_chunk(struct rcu_head *rcu) +static void free_chunk(struct audit_chunk *chunk) { - struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head); int i; for (i = 0; i < chunk->count; i++) { @@ -141,14 +143,16 @@ kfree(chunk); } -static inline void free_chunk(struct audit_chunk *chunk) +void audit_put_chunk(struct audit_chunk *chunk) { - call_rcu(&chunk->head, __free_chunk); + if (atomic_long_dec_and_test(&chunk->refs)) + free_chunk(chunk); } -void audit_put_chunk(struct audit_chunk *chunk) +static void __put_chunk(struct rcu_head *rcu) { - put_inotify_watch(&chunk->watch); + struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head); + audit_put_chunk(chunk); } enum {HASH_SIZE = 128}; @@ -177,7 +181,7 @@ list_for_each_rcu(pos, list) { struct audit_chunk *p = container_of(pos, struct audit_chunk, hash); if (p->watch.inode == inode) { - get_inotify_watch(&p->watch); + atomic_long_inc(&p->refs); return p; } } @@ -195,17 +199,49 @@ /* tagging and untagging inodes with trees */ -static void untag_chunk(struct audit_chunk *chunk, struct node *p) +static struct audit_chunk *find_chunk(struct node *p) +{ + int index = p->index & ~(1U<<31); + p -= index; + return container_of(p, struct audit_chunk, owners[0]); +} + +static void untag_chunk(struct node *p) { + struct audit_chunk *chunk = find_chunk(p); struct audit_chunk *new; struct audit_tree *owner; int size = chunk->count - 1; int i, j; + if (!pin_inotify_watch(&chunk->watch)) { + /* + * Filesystem is shutting down; all watches are getting + * evicted, just take it off the node list for this + * tree and let the eviction logics take care of the + * rest. + */ + owner = p->owner; + if (owner->root == chunk) { + list_del_init(&owner->same_root); + owner->root = NULL; + } + list_del_init(&p->list); + p->owner = NULL; + put_tree(owner); + return; + } + + spin_unlock(&hash_lock); + + /* + * pin_inotify_watch() succeeded, so the watch won't go away + * from under us. + */ mutex_lock(&chunk->watch.inode->inotify_mutex); if (chunk->dead) { mutex_unlock(&chunk->watch.inode->inotify_mutex); - return; + goto out; } owner = p->owner; @@ -222,7 +258,7 @@ inotify_evict_watch(&chunk->watch); mutex_unlock(&chunk->watch.inode->inotify_mutex); put_inotify_watch(&chunk->watch); - return; + goto out; } new = alloc_chunk(size); @@ -264,7 +300,7 @@ inotify_evict_watch(&chunk->watch); mutex_unlock(&chunk->watch.inode->inotify_mutex); put_inotify_watch(&chunk->watch); - return; + goto out; Fallback: // do the best we can @@ -278,6 +314,9 @@ put_tree(owner); spin_unlock(&hash_lock); mutex_unlock(&chunk->watch.inode->inotify_mutex); +out: + unpin_inotify_watch(&chunk->watch); + spin_lock(&hash_lock); } static int create_chunk(struct inode *inode, struct audit_tree *tree) @@ -388,13 +427,6 @@ return 0; } -static struct audit_chunk *find_chunk(struct node *p) -{ - int index = p->index & ~(1U<<31); - p -= index; - return container_of(p, struct audit_chunk, owners[0]); -} - static void kill_rules(struct audit_tree *tree) { struct audit_krule *rule, *next; @@ -432,17 +464,10 @@ spin_lock(&hash_lock); while (!list_empty(&victim->chunks)) { struct node *p; - struct audit_chunk *chunk; p = list_entry(victim->chunks.next, struct node, list); - chunk = find_chunk(p); - get_inotify_watch(&chunk->watch); - spin_unlock(&hash_lock); - - untag_chunk(chunk, p); - put_inotify_watch(&chunk->watch); - spin_lock(&hash_lock); + untag_chunk(p); } spin_unlock(&hash_lock); put_tree(victim); @@ -470,7 +495,6 @@ while (!list_empty(&tree->chunks)) { struct node *node; - struct audit_chunk *chunk; node = list_entry(tree->chunks.next, struct node, list); @@ -478,14 +502,7 @@ if (!(node->index & (1U<<31))) break; - chunk = find_chunk(node); - get_inotify_watch(&chunk->watch); - spin_unlock(&hash_lock); - - untag_chunk(chunk, node); - - put_inotify_watch(&chunk->watch); - spin_lock(&hash_lock); + untag_chunk(node); } if (!tree->root && !tree->goner) { tree->goner = 1; @@ -879,7 +896,7 @@ static void destroy_watch(struct inotify_watch *watch) { struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch); - free_chunk(chunk); + call_rcu(&chunk->head, __put_chunk); } static const struct inotify_operations rtree_inotify_ops = { --- linux-2.6.24.orig/kernel/fork.c +++ linux-2.6.24/kernel/fork.c @@ -392,6 +392,7 @@ destroy_context(mm); free_mm(mm); } +EXPORT_SYMBOL_GPL(__mmdrop); /* * Decrement the use count and release all resources for an mm. @@ -472,18 +473,18 @@ * the value intact in a core dump, and to save the unnecessary * trouble otherwise. Userland only wants this done for a sys_exit. */ - if (tsk->clear_child_tid - && !(tsk->flags & PF_SIGNALED) - && atomic_read(&mm->mm_users) > 1) { - u32 __user * tidptr = tsk->clear_child_tid; + if (tsk->clear_child_tid) { + if (!(tsk->flags & PF_SIGNALED) && + atomic_read(&mm->mm_users) > 1) { + /* + * We don't check the error code - if userspace has + * not set up a proper pointer then tough luck. + */ + put_user(0, tsk->clear_child_tid); + sys_futex(tsk->clear_child_tid, FUTEX_WAKE, + 1, NULL, NULL, 0); + } tsk->clear_child_tid = NULL; - - /* - * We don't check the error code - if userspace has - * not set up a proper pointer then tough luck. - */ - put_user(0, tidptr); - sys_futex(tidptr, FUTEX_WAKE, 1, NULL, NULL, 0); } } @@ -1196,10 +1197,7 @@ #ifdef TIF_SYSCALL_EMU clear_tsk_thread_flag(p, TIF_SYSCALL_EMU); #endif - - /* Our parent execution domain becomes current domain - These must match for thread signalling to apply */ - p->parent_exec_id = p->self_exec_id; + clear_all_latency_tracing(p); /* ok, now we should be set up.. */ p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL); @@ -1242,10 +1240,13 @@ set_task_cpu(p, smp_processor_id()); /* CLONE_PARENT re-uses the old parent */ - if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) + if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) { p->real_parent = current->real_parent; - else + p->parent_exec_id = current->parent_exec_id; + } else { p->real_parent = current; + p->parent_exec_id = current->self_exec_id; + } p->parent = p->real_parent; spin_lock(¤t->sighand->siglock); --- linux-2.6.24.orig/kernel/hrtimer.c +++ linux-2.6.24/kernel/hrtimer.c @@ -325,6 +325,24 @@ } #endif /* BITS_PER_LONG >= 64 */ +/* + * Add two ktime values and do a safety check for overflow: + */ + +ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs) +{ + ktime_t res = ktime_add(lhs, rhs); + + /* + * We use KTIME_SEC_MAX here, the maximum timeout which we can + * return to user space in a timespec: + */ + if (res.tv64 < 0 || res.tv64 < lhs.tv64 || res.tv64 < rhs.tv64) + res = ktime_set(KTIME_SEC_MAX, 0); + + return res; +} + /* High resolution timer related functions */ #ifdef CONFIG_HIGH_RES_TIMERS @@ -409,6 +427,8 @@ ktime_t expires = ktime_sub(timer->expires, base->offset); int res; + WARN_ON_ONCE(timer->expires.tv64 < 0); + /* * When the callback is running, we do not reprogram the clock event * device. The timer callback is either running on a different CPU or @@ -419,6 +439,15 @@ if (hrtimer_callback_running(timer)) return 0; + /* + * CLOCK_REALTIME timer might be requested with an absolute + * expiry time which is less than base->offset. Nothing wrong + * about that, just avoid to call into the tick code, which + * has now objections against negative expiry values. + */ + if (expires.tv64 < 0) + return -ETIME; + if (expires.tv64 >= expires_next->tv64) return 0; @@ -682,13 +711,7 @@ */ orun++; } - timer->expires = ktime_add(timer->expires, interval); - /* - * Make sure, that the result did not wrap with a very large - * interval. - */ - if (timer->expires.tv64 < 0) - timer->expires = ktime_set(KTIME_SEC_MAX, 0); + timer->expires = ktime_add_safe(timer->expires, interval); return orun; } @@ -839,7 +862,7 @@ new_base = switch_hrtimer_base(timer, base); if (mode == HRTIMER_MODE_REL) { - tim = ktime_add(tim, new_base->get_time()); + tim = ktime_add_safe(tim, new_base->get_time()); /* * CONFIG_TIME_LOW_RES is a temporary way for architectures * to signal that they simply return xtime in @@ -848,16 +871,8 @@ * timeouts. This will go away with the GTOD framework. */ #ifdef CONFIG_TIME_LOW_RES - tim = ktime_add(tim, base->resolution); + tim = ktime_add_safe(tim, base->resolution); #endif - /* - * Careful here: User space might have asked for a - * very long sleep, so the add above might result in a - * negative number, which enqueues the timer in front - * of the queue. - */ - if (tim.tv64 < 0) - tim.tv64 = KTIME_MAX; } timer->expires = tim; @@ -1291,11 +1306,26 @@ return t->task == NULL; } +static int update_rmtp(struct hrtimer *timer, struct timespec __user *rmtp) +{ + struct timespec rmt; + ktime_t rem; + + rem = ktime_sub(timer->expires, timer->base->get_time()); + if (rem.tv64 <= 0) + return 0; + rmt = ktime_to_timespec(rem); + + if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) + return -EFAULT; + + return 1; +} + long __sched hrtimer_nanosleep_restart(struct restart_block *restart) { struct hrtimer_sleeper t; - struct timespec *rmtp; - ktime_t time; + struct timespec __user *rmtp; restart->fn = do_no_restart_syscall; @@ -1305,12 +1335,11 @@ if (do_nanosleep(&t, HRTIMER_MODE_ABS)) return 0; - rmtp = (struct timespec *)restart->arg1; + rmtp = (struct timespec __user *)restart->arg1; if (rmtp) { - time = ktime_sub(t.timer.expires, t.timer.base->get_time()); - if (time.tv64 <= 0) - return 0; - *rmtp = ktime_to_timespec(time); + int ret = update_rmtp(&t.timer, rmtp); + if (ret <= 0) + return ret; } restart->fn = hrtimer_nanosleep_restart; @@ -1319,12 +1348,11 @@ return -ERESTART_RESTARTBLOCK; } -long hrtimer_nanosleep(struct timespec *rqtp, struct timespec *rmtp, +long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, const enum hrtimer_mode mode, const clockid_t clockid) { struct restart_block *restart; struct hrtimer_sleeper t; - ktime_t rem; hrtimer_init(&t.timer, clockid, mode); t.timer.expires = timespec_to_ktime(*rqtp); @@ -1336,10 +1364,9 @@ return -ERESTARTNOHAND; if (rmtp) { - rem = ktime_sub(t.timer.expires, t.timer.base->get_time()); - if (rem.tv64 <= 0) - return 0; - *rmtp = ktime_to_timespec(rem); + int ret = update_rmtp(&t.timer, rmtp); + if (ret <= 0) + return ret; } restart = ¤t_thread_info()->restart_block; @@ -1355,8 +1382,7 @@ asmlinkage long sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp) { - struct timespec tu, rmt; - int ret; + struct timespec tu; if (copy_from_user(&tu, rqtp, sizeof(tu))) return -EFAULT; @@ -1364,15 +1390,7 @@ if (!timespec_valid(&tu)) return -EINVAL; - ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, HRTIMER_MODE_REL, - CLOCK_MONOTONIC); - - if (ret && rmtp) { - if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) - return -EFAULT; - } - - return ret; + return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC); } /* --- linux-2.6.24.orig/kernel/audit.c +++ linux-2.6.24/kernel/audit.c @@ -1200,13 +1200,17 @@ static inline int audit_expand(struct audit_buffer *ab, int extra) { struct sk_buff *skb = ab->skb; - int ret = pskb_expand_head(skb, skb_headroom(skb), extra, - ab->gfp_mask); + int oldtail = skb_tailroom(skb); + int ret = pskb_expand_head(skb, 0, extra, ab->gfp_mask); + int newtail = skb_tailroom(skb); + if (ret < 0) { audit_log_lost("out of memory in audit_expand"); return 0; } - return skb_tailroom(skb); + + skb->truesize += newtail - oldtail; + return newtail; } /* @@ -1215,8 +1219,7 @@ * will be called a second time. Currently, we assume that a printk * can't format message larger than 1024 bytes, so we don't either. */ -static void audit_log_vformat(struct audit_buffer *ab, const char *fmt, - va_list args) +void audit_log_vformat(struct audit_buffer *ab, const char *fmt, va_list args) { int len, avail; struct sk_buff *skb; @@ -1471,3 +1474,6 @@ EXPORT_SYMBOL(audit_log_end); EXPORT_SYMBOL(audit_log_format); EXPORT_SYMBOL(audit_log); +EXPORT_SYMBOL_GPL(audit_log_vformat); +EXPORT_SYMBOL_GPL(audit_log_untrustedstring); +EXPORT_SYMBOL_GPL(audit_log_d_path); --- linux-2.6.24.orig/kernel/posix-timers.c +++ linux-2.6.24/kernel/posix-timers.c @@ -766,9 +766,11 @@ /* SIGEV_NONE timers are not queued ! See common_timer_get */ if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) { /* Setup correct expiry time for relative timers */ - if (mode == HRTIMER_MODE_REL) - timer->expires = ktime_add(timer->expires, - timer->base->get_time()); + if (mode == HRTIMER_MODE_REL) { + timer->expires = + ktime_add_safe(timer->expires, + timer->base->get_time()); + } return 0; } @@ -981,20 +983,9 @@ static int common_nsleep(const clockid_t which_clock, int flags, struct timespec *tsave, struct timespec __user *rmtp) { - struct timespec rmt; - int ret; - - ret = hrtimer_nanosleep(tsave, rmtp ? &rmt : NULL, - flags & TIMER_ABSTIME ? - HRTIMER_MODE_ABS : HRTIMER_MODE_REL, - which_clock); - - if (ret && rmtp) { - if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) - return -EFAULT; - } - - return ret; + return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ? + HRTIMER_MODE_ABS : HRTIMER_MODE_REL, + which_clock); } asmlinkage long --- linux-2.6.24.orig/kernel/compat.c +++ linux-2.6.24/kernel/compat.c @@ -40,10 +40,36 @@ __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; } +static long compat_nanosleep_restart(struct restart_block *restart) +{ + struct compat_timespec __user *rmtp; + struct timespec rmt; + mm_segment_t oldfs; + long ret; + + rmtp = (struct compat_timespec __user *)(restart->arg1); + restart->arg1 = (unsigned long)&rmt; + oldfs = get_fs(); + set_fs(KERNEL_DS); + ret = hrtimer_nanosleep_restart(restart); + set_fs(oldfs); + + if (ret) { + restart->fn = compat_nanosleep_restart; + restart->arg1 = (unsigned long)rmtp; + + if (rmtp && put_compat_timespec(&rmt, rmtp)) + return -EFAULT; + } + + return ret; +} + asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, struct compat_timespec __user *rmtp) { struct timespec tu, rmt; + mm_segment_t oldfs; long ret; if (get_compat_timespec(&tu, rqtp)) @@ -52,11 +78,21 @@ if (!timespec_valid(&tu)) return -EINVAL; - ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, HRTIMER_MODE_REL, - CLOCK_MONOTONIC); + oldfs = get_fs(); + set_fs(KERNEL_DS); + ret = hrtimer_nanosleep(&tu, + rmtp ? (struct timespec __user *)&rmt : NULL, + HRTIMER_MODE_REL, CLOCK_MONOTONIC); + set_fs(oldfs); + + if (ret) { + struct restart_block *restart + = ¤t_thread_info()->restart_block; + + restart->fn = compat_nanosleep_restart; + restart->arg1 = (unsigned long)rmtp; - if (ret && rmtp) { - if (put_compat_timespec(&rmt, rmtp)) + if (rmtp && put_compat_timespec(&rmt, rmtp)) return -EFAULT; } --- linux-2.6.24.orig/kernel/futex.c +++ linux-2.6.24/kernel/futex.c @@ -60,6 +60,8 @@ #include "rtmutex_common.h" +int __read_mostly futex_cmpxchg_enabled; + #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8) /* @@ -466,6 +468,8 @@ struct futex_hash_bucket *hb; union futex_key key; + if (!futex_cmpxchg_enabled) + return; /* * We are a ZOMBIE and nobody can enqueue itself on * pi_state_list anymore, but we have to be careful @@ -1854,6 +1858,8 @@ sys_set_robust_list(struct robust_list_head __user *head, size_t len) { + if (!futex_cmpxchg_enabled) + return -ENOSYS; /* * The kernel knows only one size for now: */ @@ -1878,6 +1884,9 @@ struct robust_list_head __user *head; unsigned long ret; + if (!futex_cmpxchg_enabled) + return -ENOSYS; + if (!pid) head = current->robust_list; else { @@ -1980,6 +1989,9 @@ unsigned long futex_offset; int rc; + if (!futex_cmpxchg_enabled) + return; + /* * Fetch the list head (which was registered earlier, via * sys_set_robust_list()): @@ -2034,7 +2046,7 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, u32 __user *uaddr2, u32 val2, u32 val3) { - int ret; + int ret = -ENOSYS; int cmd = op & FUTEX_CMD_MASK; struct rw_semaphore *fshared = NULL; @@ -2062,13 +2074,16 @@ ret = futex_wake_op(uaddr, fshared, uaddr2, val, val2, val3); break; case FUTEX_LOCK_PI: - ret = futex_lock_pi(uaddr, fshared, val, timeout, 0); + if (futex_cmpxchg_enabled) + ret = futex_lock_pi(uaddr, fshared, val, timeout, 0); break; case FUTEX_UNLOCK_PI: - ret = futex_unlock_pi(uaddr, fshared); + if (futex_cmpxchg_enabled) + ret = futex_unlock_pi(uaddr, fshared); break; case FUTEX_TRYLOCK_PI: - ret = futex_lock_pi(uaddr, fshared, 0, timeout, 1); + if (futex_cmpxchg_enabled) + ret = futex_lock_pi(uaddr, fshared, 0, timeout, 1); break; default: ret = -ENOSYS; @@ -2094,7 +2109,7 @@ t = timespec_to_ktime(ts); if (cmd == FUTEX_WAIT) - t = ktime_add(ktime_get(), t); + t = ktime_add_safe(ktime_get(), t); tp = &t; } /* @@ -2123,8 +2138,29 @@ static int __init init(void) { - int i = register_filesystem(&futex_fs_type); + u32 curval; + int i; + + /* + * This will fail and we want it. Some arch implementations do + * runtime detection of the futex_atomic_cmpxchg_inatomic() + * functionality. We want to know that before we call in any + * of the complex code paths. Also we want to prevent + * registration of robust lists in that case. NULL is + * guaranteed to fault and we get -EFAULT on functional + * implementation, the non functional ones will return + * -ENOSYS. + */ + curval = cmpxchg_futex_value_locked(NULL, 0, 0); + if (curval == -EFAULT) + futex_cmpxchg_enabled = 1; + for (i = 0; i < ARRAY_SIZE(futex_queues); i++) { + plist_head_init(&futex_queues[i].chain, &futex_queues[i].lock); + spin_lock_init(&futex_queues[i].lock); + } + + i = register_filesystem(&futex_fs_type); if (i) return i; @@ -2134,10 +2170,6 @@ return PTR_ERR(futex_mnt); } - for (i = 0; i < ARRAY_SIZE(futex_queues); i++) { - plist_head_init(&futex_queues[i].chain, &futex_queues[i].lock); - spin_lock_init(&futex_queues[i].lock); - } return 0; } __initcall(init); --- linux-2.6.24.orig/kernel/relay.c +++ linux-2.6.24/kernel/relay.c @@ -1072,7 +1072,7 @@ unsigned int flags, int *nonpad_ret) { - unsigned int pidx, poff, total_len, subbuf_pages, ret; + unsigned int pidx, poff, total_len, subbuf_pages, nr_pages, ret; struct rchan_buf *rbuf = in->private_data; unsigned int subbuf_size = rbuf->chan->subbuf_size; uint64_t pos = (uint64_t) *ppos; @@ -1103,8 +1103,9 @@ subbuf_pages = rbuf->chan->alloc_size >> PAGE_SHIFT; pidx = (read_start / PAGE_SIZE) % subbuf_pages; poff = read_start & ~PAGE_MASK; + nr_pages = min_t(unsigned int, subbuf_pages, PIPE_BUFFERS); - for (total_len = 0; spd.nr_pages < subbuf_pages; spd.nr_pages++) { + for (total_len = 0; spd.nr_pages < nr_pages; spd.nr_pages++) { unsigned int this_len, this_end, private; unsigned int cur_pos = read_start + total_len; --- linux-2.6.24.orig/kernel/seccomp.c +++ linux-2.6.24/kernel/seccomp.c @@ -8,6 +8,7 @@ #include #include +#include /* #define SECCOMP_DEBUG 1 */ #define NR_SECCOMP_MODES 1 @@ -22,7 +23,7 @@ 0, /* null terminated */ }; -#ifdef TIF_32BIT +#ifdef CONFIG_COMPAT static int mode1_syscalls_32[] = { __NR_seccomp_read_32, __NR_seccomp_write_32, __NR_seccomp_exit_32, __NR_seccomp_sigreturn_32, 0, /* null terminated */ @@ -37,8 +38,8 @@ switch (mode) { case 1: syscall = mode1_syscalls; -#ifdef TIF_32BIT - if (test_thread_flag(TIF_32BIT)) +#ifdef CONFIG_COMPAT + if (is_compat_task()) syscall = mode1_syscalls_32; #endif do { --- linux-2.6.24.orig/kernel/irq/chip.c +++ linux-2.6.24/kernel/irq/chip.c @@ -246,6 +246,17 @@ } /* + * default shutdown function + */ +static void default_shutdown(unsigned int irq) +{ + struct irq_desc *desc = irq_desc + irq; + + desc->chip->mask(irq); + desc->status |= IRQ_MASKED; +} + +/* * Fixup enable/disable function pointers */ void irq_chip_set_defaults(struct irq_chip *chip) @@ -256,8 +267,15 @@ chip->disable = default_disable; if (!chip->startup) chip->startup = default_startup; + /* + * We use chip->disable, when the user provided its own. When + * we have default_disable set for chip->disable, then we need + * to use default_shutdown, otherwise the irq line is not + * disabled on free_irq(): + */ if (!chip->shutdown) - chip->shutdown = chip->disable; + chip->shutdown = chip->disable != default_disable ? + chip->disable : default_shutdown; if (!chip->name) chip->name = chip->typename; if (!chip->end) @@ -589,3 +607,39 @@ set_irq_chip(irq, chip); __set_irq_handler(irq, handle, 0, name); } + +void __init set_irq_noprobe(unsigned int irq) +{ + struct irq_desc *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to mark IRQ%d non-probeable\n", irq); + + return; + } + + desc = irq_desc + irq; + + spin_lock_irqsave(&desc->lock, flags); + desc->status |= IRQ_NOPROBE; + spin_unlock_irqrestore(&desc->lock, flags); +} + +void __init set_irq_probe(unsigned int irq) +{ + struct irq_desc *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to mark IRQ%d probeable\n", irq); + + return; + } + + desc = irq_desc + irq; + + spin_lock_irqsave(&desc->lock, flags); + desc->status &= ~IRQ_NOPROBE; + spin_unlock_irqrestore(&desc->lock, flags); +} --- linux-2.6.24.orig/kernel/cpu.c +++ linux-2.6.24/kernel/cpu.c @@ -219,6 +219,7 @@ mutex_unlock(&cpu_add_remove_lock); return err; } +EXPORT_SYMBOL(cpu_down); #endif /*CONFIG_HOTPLUG_CPU*/ /* Requires cpu_add_remove_lock to be held */ --- linux-2.6.24.orig/kernel/sched.c +++ linux-2.6.24/kernel/sched.c @@ -727,6 +727,49 @@ resched_task(cpu_curr(cpu)); spin_unlock_irqrestore(&rq->lock, flags); } + +#ifdef CONFIG_NO_HZ +/* + * When add_timer_on() enqueues a timer into the timer wheel of an + * idle CPU then this timer might expire before the next timer event + * which is scheduled to wake up that CPU. In case of a completely + * idle system the next event might even be infinite time into the + * future. wake_up_idle_cpu() ensures that the CPU is woken up and + * leaves the inner idle loop so the newly added timer is taken into + * account when the CPU goes back to idle and evaluates the timer + * wheel for the next timer event. + */ +void wake_up_idle_cpu(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + + if (cpu == smp_processor_id()) + return; + + /* + * This is safe, as this function is called with the timer + * wheel base lock of (cpu) held. When the CPU is on the way + * to idle and has not yet set rq->curr to idle then it will + * be serialized on the timer wheel base lock and take the new + * timer into account automatically. + */ + if (rq->curr != rq->idle) + return; + + /* + * We can set TIF_RESCHED on the idle task of the other CPU + * lockless. The worst case is that the other CPU runs the + * idle task through an additional NOOP schedule() + */ + set_tsk_thread_flag(rq->idle, TIF_NEED_RESCHED); + + /* NEED_RESCHED must be visible before we test polling */ + smp_mb(); + if (!tsk_is_polling(rq->idle)) + smp_send_reschedule(cpu); +} +#endif + #else static inline void resched_task(struct task_struct *p) { @@ -4028,11 +4071,10 @@ oldprio = p->prio; on_rq = p->se.on_rq; running = task_current(rq, p); - if (on_rq) { + if (on_rq) dequeue_task(rq, p, 0); - if (running) - p->sched_class->put_prev_task(rq, p); - } + if (running) + p->sched_class->put_prev_task(rq, p); if (rt_prio(prio)) p->sched_class = &rt_sched_class; @@ -4041,9 +4083,9 @@ p->prio = prio; + if (running) + p->sched_class->set_curr_task(rq); if (on_rq) { - if (running) - p->sched_class->set_curr_task(rq); enqueue_task(rq, p, 0); /* * Reschedule if we are currently running on this runqueue and @@ -4339,18 +4381,17 @@ update_rq_clock(rq); on_rq = p->se.on_rq; running = task_current(rq, p); - if (on_rq) { + if (on_rq) deactivate_task(rq, p, 0); - if (running) - p->sched_class->put_prev_task(rq, p); - } + if (running) + p->sched_class->put_prev_task(rq, p); oldprio = p->prio; __setscheduler(rq, p, policy, param->sched_priority); + if (running) + p->sched_class->set_curr_task(rq); if (on_rq) { - if (running) - p->sched_class->set_curr_task(rq); activate_task(rq, p, 0); /* * Reschedule if we are currently running on this runqueue and @@ -7110,19 +7151,22 @@ running = task_current(rq, tsk); on_rq = tsk->se.on_rq; - if (on_rq) { + if (on_rq) dequeue_task(rq, tsk, 0); - if (unlikely(running)) - tsk->sched_class->put_prev_task(rq, tsk); - } + if (unlikely(running)) + tsk->sched_class->put_prev_task(rq, tsk); set_task_cfs_rq(tsk, task_cpu(tsk)); - if (on_rq) { - if (unlikely(running)) - tsk->sched_class->set_curr_task(rq); +#ifdef CONFIG_FAIR_GROUP_SCHED + if (tsk->sched_class->moved_group) + tsk->sched_class->moved_group(tsk); +#endif + + if (unlikely(running)) + tsk->sched_class->set_curr_task(rq); + if (on_rq) enqueue_task(rq, tsk, 0); - } done: task_rq_unlock(rq, &flags); --- linux-2.6.24.orig/kernel/power/Kconfig +++ linux-2.6.24/kernel/power/Kconfig @@ -97,6 +97,21 @@ powered and thus its contents are preserved, such as the suspend-to-RAM state (i.e. the ACPI S3 state). +config PM_DISABLE_CONSOLE + bool "Disable Power Management messing with the active console" + depends on PM + default n + ---help--- + By defauly, PM will take over the active console (generally, this means + switching to the console when suspending from X). This can at times cause + problems, especially if userspace suspend scripts try to do things with the + console before or after suspending (e.g. calling vbestate). + + To work around this, enable this option so that PM will not handle the + console. + + If unsure, say N. + config HIBERNATION_UP_POSSIBLE bool depends on X86 || PPC64_SWSUSP || PPC32 --- linux-2.6.24.orig/kernel/power/console.c +++ linux-2.6.24/kernel/power/console.c @@ -16,6 +16,7 @@ int pm_prepare_console(void) { +#ifndef CONFIG_PM_DISABLE_CONSOLE acquire_console_sem(); orig_fgconsole = fg_console; @@ -44,15 +45,18 @@ } orig_kmsg = kmsg_redirect; kmsg_redirect = SUSPEND_CONSOLE; +#endif return 0; } void pm_restore_console(void) { +#ifndef CONFIG_PM_DISABLE_CONSOLE acquire_console_sem(); set_console(orig_fgconsole); release_console_sem(); kmsg_redirect = orig_kmsg; +#endif return; } #endif --- linux-2.6.24.orig/kernel/power/disk.c +++ linux-2.6.24/kernel/power/disk.c @@ -291,7 +291,7 @@ return error; suspend_console(); - error = device_suspend(PMSG_SUSPEND); + error = device_suspend(PMSG_HIBERNATE); if (error) goto Resume_console; @@ -304,7 +304,7 @@ goto Finish; local_irq_disable(); - error = device_power_down(PMSG_SUSPEND); + error = device_power_down(PMSG_HIBERNATE); if (!error) { hibernation_ops->enter(); /* We should never get here */ --- linux-2.6.24.orig/kernel/timer.c +++ linux-2.6.24/kernel/timer.c @@ -453,10 +453,18 @@ spin_lock_irqsave(&base->lock, flags); timer_set_base(timer, base); internal_add_timer(base, timer); + /* + * Check whether the other CPU is idle and needs to be + * triggered to reevaluate the timer wheel when nohz is + * active. We are protected against the other CPU fiddling + * with the timer by holding the timer base lock. This also + * makes sure that a CPU on the way to idle can not evaluate + * the timer wheel. + */ + wake_up_idle_cpu(cpu); spin_unlock_irqrestore(&base->lock, flags); } - /** * mod_timer - modify a timer's timeout * @timer: the timer to be modified --- linux-2.6.24.orig/kernel/Makefile +++ linux-2.6.24/kernel/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o obj-$(CONFIG_MARKERS) += marker.o +obj-$(CONFIG_LATENCYTOP) += latencytop.o ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) # According to Alan Modra , the -fno-omit-frame-pointer is --- linux-2.6.24.orig/kernel/latencytop.c +++ linux-2.6.24/kernel/latencytop.c @@ -0,0 +1,241 @@ +/* + * latencytop.c: Latency display infrastructure + * + * (C) Copyright 2008 Intel Corporation + * Author: Arjan van de Ven + * + * 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; version 2 + * of the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_SPINLOCK(latency_lock); + +#define MAXLR 128 +static struct latency_record latency_record[MAXLR]; + +int latencytop_enabled; + +void clear_all_latency_tracing(struct task_struct *p) +{ + unsigned long flags; + + if (!latencytop_enabled) + return; + + spin_lock_irqsave(&latency_lock, flags); + memset(&p->latency_record, 0, sizeof(p->latency_record)); + p->latency_record_count = 0; + spin_unlock_irqrestore(&latency_lock, flags); +} + +static void clear_global_latency_tracing(void) +{ + unsigned long flags; + + spin_lock_irqsave(&latency_lock, flags); + memset(&latency_record, 0, sizeof(latency_record)); + spin_unlock_irqrestore(&latency_lock, flags); +} + +static void __sched account_global_scheduler_latency(struct task_struct *tsk, + struct latency_record *lat) +{ + int firstnonnull = MAXLR + 1; + int i; + + if (!latencytop_enabled) + return; + + /* skip kernel threads for now */ + if (!tsk->mm) + return; + + for (i = 0; i < MAXLR; i++) { + int q; + int same = 1; + /* Nothing stored: */ + if (!latency_record[i].backtrace[0]) { + if (firstnonnull > i) + firstnonnull = i; + continue; + } + for (q = 0 ; q < LT_BACKTRACEDEPTH ; q++) { + if (latency_record[i].backtrace[q] != + lat->backtrace[q]) + same = 0; + if (same && lat->backtrace[q] == 0) + break; + if (same && lat->backtrace[q] == ULONG_MAX) + break; + } + if (same) { + latency_record[i].count++; + latency_record[i].time += lat->time; + if (lat->time > latency_record[i].max) + latency_record[i].max = lat->time; + return; + } + } + + i = firstnonnull; + if (i >= MAXLR - 1) + return; + + /* Allocted a new one: */ + memcpy(&latency_record[i], lat, sizeof(struct latency_record)); +} + +static inline void +store_stacktrace(struct task_struct *tsk, struct latency_record *lat) +{ + struct stack_trace trace; + + memset(&trace, 0, sizeof(trace)); + trace.max_entries = LT_BACKTRACEDEPTH; + trace.entries = &lat->backtrace[0]; + trace.skip = 0; + save_stack_trace_tsk(tsk, &trace); +} + +void __sched +account_scheduler_latency(struct task_struct *tsk, int usecs, int inter) +{ + unsigned long flags; + int i, q; + struct latency_record lat; + + if (!latencytop_enabled) + return; + + /* Long interruptible waits are generally user requested... */ + if (inter && usecs > 5000) + return; + + memset(&lat, 0, sizeof(lat)); + lat.count = 1; + lat.time = usecs; + lat.max = usecs; + store_stacktrace(tsk, &lat); + + spin_lock_irqsave(&latency_lock, flags); + + account_global_scheduler_latency(tsk, &lat); + + /* + * short term hack; if we're > 32 we stop; future we recycle: + */ + tsk->latency_record_count++; + if (tsk->latency_record_count >= LT_SAVECOUNT) + goto out_unlock; + + for (i = 0; i < LT_SAVECOUNT ; i++) { + struct latency_record *mylat; + int same = 1; + mylat = &tsk->latency_record[i]; + for (q = 0 ; q < LT_BACKTRACEDEPTH ; q++) { + if (mylat->backtrace[q] != + lat.backtrace[q]) + same = 0; + if (same && lat.backtrace[q] == 0) + break; + if (same && lat.backtrace[q] == ULONG_MAX) + break; + } + if (same) { + mylat->count++; + mylat->time += lat.time; + if (lat.time > mylat->max) + mylat->max = lat.time; + goto out_unlock; + } + } + + /* Allocated a new one: */ + i = tsk->latency_record_count; + memcpy(&tsk->latency_record[i], &lat, sizeof(struct latency_record)); + +out_unlock: + spin_unlock_irqrestore(&latency_lock, flags); +} + +static int lstats_show(struct seq_file *m, void *v) +{ + int i; + + seq_puts(m, "Latency Top version : v0.1\n"); + + for (i = 0; i < MAXLR; i++) { + if (latency_record[i].backtrace[0]) { + int q; + seq_printf(m, "%i %li %li ", + latency_record[i].count, + latency_record[i].time, + latency_record[i].max); + for (q = 0; q < LT_BACKTRACEDEPTH; q++) { + char sym[KSYM_NAME_LEN]; + char *c; + if (!latency_record[i].backtrace[q]) + break; + if (latency_record[i].backtrace[q] == ULONG_MAX) + break; + sprint_symbol(sym, + latency_record[i].backtrace[q]); + c = strchr(sym, '+'); + if (c) + *c = 0; + seq_printf(m, "%s ", sym); + } + seq_printf(m, "\n"); + } + } + return 0; +} + +static ssize_t +lstats_write(struct file *file, const char __user *buf, size_t count, + loff_t *offs) +{ + clear_global_latency_tracing(); + + return count; +} + +static int lstats_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, lstats_show, NULL); +} + +static struct file_operations lstats_fops = { + .open = lstats_open, + .read = seq_read, + .write = lstats_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init init_lstats_procfs(void) +{ + struct proc_dir_entry *pe; + + pe = create_proc_entry("latency_stats", 0644, NULL); + if (!pe) + return -ENOMEM; + + pe->proc_fops = &lstats_fops; + + return 0; +} +__initcall(init_lstats_procfs); --- linux-2.6.24.orig/kernel/futex_compat.c +++ linux-2.6.24/kernel/futex_compat.c @@ -54,6 +54,9 @@ compat_long_t futex_offset; int rc; + if (!futex_cmpxchg_enabled) + return; + /* * Fetch the list head (which was registered earlier, via * sys_set_robust_list()): @@ -115,6 +118,9 @@ compat_sys_set_robust_list(struct compat_robust_list_head __user *head, compat_size_t len) { + if (!futex_cmpxchg_enabled) + return -ENOSYS; + if (unlikely(len != sizeof(*head))) return -EINVAL; @@ -130,6 +136,9 @@ struct compat_robust_list_head __user *head; unsigned long ret; + if (!futex_cmpxchg_enabled) + return -ENOSYS; + if (!pid) head = current->compat_robust_list; else { @@ -175,7 +184,7 @@ t = timespec_to_ktime(ts); if (cmd == FUTEX_WAIT) - t = ktime_add(ktime_get(), t); + t = ktime_add_safe(ktime_get(), t); tp = &t; } if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE) --- linux-2.6.24.orig/block/scsi_ioctl.c +++ linux-2.6.24/block/scsi_ioctl.c @@ -235,6 +235,8 @@ rq->timeout = q->sg_timeout; if (!rq->timeout) rq->timeout = BLK_DEFAULT_SG_TIMEOUT; + if (rq->timeout < BLK_MIN_SG_TIMEOUT) + rq->timeout = BLK_MIN_SG_TIMEOUT; return 0; } @@ -546,8 +548,14 @@ return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data); } -int scsi_cmd_ioctl(struct file *file, struct request_queue *q, - struct gendisk *bd_disk, unsigned int cmd, void __user *arg) +static inline int blk_send_allow_medium_removal(struct request_queue *q, + struct gendisk *bd_disk) +{ + return __blk_send_generic(q, bd_disk, + GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, 0); +} + +int scsi_cmd_ioctl(struct file *file, struct request_queue *q, struct gendisk *bd_disk, unsigned int cmd, void __user *arg) { int err; @@ -666,7 +674,11 @@ err = blk_send_start_stop(q, bd_disk, 0x03); break; case CDROMEJECT: - err = blk_send_start_stop(q, bd_disk, 0x02); + err = 0; + + err |= blk_send_allow_medium_removal(q, bd_disk); + err |= blk_send_start_stop(q, bd_disk, 0x01); + err |= blk_send_start_stop(q, bd_disk, 0x02); break; default: err = -ENOTTY; --- linux-2.6.24.orig/block/ll_rw_blk.c +++ linux-2.6.24/block/ll_rw_blk.c @@ -2667,8 +2667,10 @@ static void bio_end_empty_barrier(struct bio *bio, int err) { - if (err) + if (err) { + set_bit(BIO_EOPNOTSUPP, &bio->bi_flags); clear_bit(BIO_UPTODATE, &bio->bi_flags); + } complete(bio->bi_private); } @@ -2717,7 +2719,9 @@ *error_sector = bio->bi_sector; ret = 0; - if (!bio_flagged(bio, BIO_UPTODATE)) + if (bio_flagged(bio, BIO_EOPNOTSUPP)) + ret = -EOPNOTSUPP; + else if (!bio_flagged(bio, BIO_UPTODATE)) ret = -EIO; bio_put(bio); --- linux-2.6.24.orig/block/bsg.c +++ linux-2.6.24/block/bsg.c @@ -198,6 +198,8 @@ rq->timeout = q->sg_timeout; if (!rq->timeout) rq->timeout = BLK_DEFAULT_SG_TIMEOUT; + if (rq->timeout < BLK_MIN_SG_TIMEOUT) + rq->timeout = BLK_MIN_SG_TIMEOUT; return 0; } --- linux-2.6.24.orig/include/asm-parisc/pdc.h +++ linux-2.6.24/include/asm-parisc/pdc.h @@ -645,8 +645,7 @@ void pdc_io_reset(void); void pdc_io_reset_devices(void); int pdc_iodc_getc(void); -int pdc_iodc_print(unsigned char *str, unsigned count); -void pdc_printf(const char *fmt, ...); +int pdc_iodc_print(const unsigned char *str, unsigned count); void pdc_emergency_unlock(void); int pdc_sti_call(unsigned long func, unsigned long flags, --- linux-2.6.24.orig/include/asm-parisc/futex.h +++ linux-2.6.24/include/asm-parisc/futex.h @@ -56,6 +56,12 @@ int err = 0; int uval; + /* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is + * our gateway page, and causes no end of trouble... + */ + if (segment_eq(KERNEL_DS, get_fs()) && !uaddr) + return -EFAULT; + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) return -EFAULT; @@ -67,5 +73,5 @@ return uval; } -#endif -#endif +#endif /*__KERNEL__*/ +#endif /*_ASM_PARISC_FUTEX_H*/ --- linux-2.6.24.orig/include/asm-sparc/mman.h +++ linux-2.6.24/include/asm-sparc/mman.h @@ -37,9 +37,8 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ -#define arch_mmap_check sparc_mmap_check -int sparc_mmap_check(unsigned long addr, unsigned long len, - unsigned long flags); +#define arch_mmap_check(addr,len,flags) sparc_mmap_check(addr,len) +int sparc_mmap_check(unsigned long addr, unsigned long len); #endif #endif --- linux-2.6.24.orig/include/asm-arm/arch-pxa/pxa-regs.h +++ linux-2.6.24/include/asm-arm/arch-pxa/pxa-regs.h @@ -1669,6 +1669,7 @@ #define SSCR1_RSRE (1 << 20) /* Receive Service Request Enable */ #define SSCR1_TINTE (1 << 19) /* Receiver Time-out Interrupt enable */ #define SSCR1_PINTE (1 << 18) /* Peripheral Trailing Byte Interupt Enable */ +#define SSCR1_IFS (1 << 16) /* Invert Frame Signal */ #define SSCR1_STRF (1 << 15) /* Select FIFO or EFWR */ #define SSCR1_EFWR (1 << 14) /* Enable FIFO Write/Read */ --- linux-2.6.24.orig/include/asm-sparc64/seccomp.h +++ linux-2.6.24/include/asm-sparc64/seccomp.h @@ -1,11 +1,5 @@ #ifndef _ASM_SECCOMP_H -#include /* already defines TIF_32BIT */ - -#ifndef TIF_32BIT -#error "unexpected TIF_32BIT on sparc64" -#endif - #include #define __NR_seccomp_read __NR_read --- linux-2.6.24.orig/include/asm-sparc64/compat.h +++ linux-2.6.24/include/asm-sparc64/compat.h @@ -240,4 +240,9 @@ unsigned int __unused2; }; +static inline int is_compat_task(void) +{ + return test_thread_flag(TIF_32BIT); +} + #endif /* _ASM_SPARC64_COMPAT_H */ --- linux-2.6.24.orig/include/asm-sparc64/backoff.h +++ linux-2.6.24/include/asm-sparc64/backoff.h @@ -12,7 +12,8 @@ mov reg, tmp; \ 88: brnz,pt tmp, 88b; \ sub tmp, 1, tmp; \ - cmp reg, BACKOFF_LIMIT; \ + set BACKOFF_LIMIT, tmp; \ + cmp reg, tmp; \ bg,pn %xcc, label; \ nop; \ ba,pt %xcc, label; \ --- linux-2.6.24.orig/include/asm-sparc64/mman.h +++ linux-2.6.24/include/asm-sparc64/mman.h @@ -37,9 +37,8 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ -#define arch_mmap_check sparc64_mmap_check -int sparc64_mmap_check(unsigned long addr, unsigned long len, - unsigned long flags); +#define arch_mmap_check(addr,len,flags) sparc64_mmap_check(addr,len) +int sparc64_mmap_check(unsigned long addr, unsigned long len); #endif #endif --- linux-2.6.24.orig/include/linux/hugetlb.h +++ linux-2.6.24/include/linux/hugetlb.h @@ -8,6 +8,7 @@ #include #include #include +#include struct ctl_table; @@ -17,6 +18,7 @@ } int hugetlb_sysctl_handler(struct ctl_table *, int, struct file *, void __user *, size_t *, loff_t *); +int hugetlb_overcommit_handler(struct ctl_table *, int, struct file *, void __user *, size_t *, loff_t *); int hugetlb_treat_movable_handler(struct ctl_table *, int, struct file *, void __user *, size_t *, loff_t *); int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *); int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, struct page **, struct vm_area_struct **, unsigned long *, int *, int, int); --- linux-2.6.24.orig/include/linux/security.h +++ linux-2.6.24/include/linux/security.h @@ -28,6 +28,7 @@ #include #include #include +#include /* PAGE_ALIGN */ #include #include #include @@ -56,13 +57,15 @@ extern int cap_bprm_set_security (struct linux_binprm *bprm); extern void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe); extern int cap_bprm_secureexec(struct linux_binprm *bprm); -extern int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags); -extern int cap_inode_removexattr(struct dentry *dentry, char *name); +extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name, void *value, size_t size, int flags, struct file *file); +extern int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, char *name, struct file *file); extern int cap_inode_need_killpriv(struct dentry *dentry); extern int cap_inode_killpriv(struct dentry *dentry); +extern int cap_file_mmap(struct file *file, unsigned long reqprot, + unsigned long prot, unsigned long flags, + unsigned long addr, unsigned long addr_only); extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags); extern void cap_task_reparent_to_init (struct task_struct *p); -extern int cap_task_kill(struct task_struct *p, struct siginfo *info, int sig, u32 secid); extern int cap_task_setscheduler (struct task_struct *p, int policy, struct sched_param *lp); extern int cap_task_setioprio (struct task_struct *p, int ioprio); extern int cap_task_setnice (struct task_struct *p, int nice); @@ -85,6 +88,7 @@ extern int cap_netlink_recv(struct sk_buff *skb, int cap); extern unsigned long mmap_min_addr; +extern unsigned long dac_mmap_min_addr; /* * Values used in the task_security_ops calls */ @@ -111,6 +115,22 @@ #define LSM_UNSAFE_PTRACE 2 #define LSM_UNSAFE_PTRACE_CAP 4 +/* + * If a hint addr is less than mmap_min_addr change hint to be as + * low as possible but still greater than mmap_min_addr + */ +static inline unsigned long round_hint_to_min(unsigned long hint) +{ + hint &= PAGE_MASK; + if (((void *)hint != NULL) && + (hint < mmap_min_addr)) + return PAGE_ALIGN(mmap_min_addr); + return hint; +} + +extern int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos); + #ifdef CONFIG_SECURITY /** @@ -297,23 +317,28 @@ * Check permission to create a regular file. * @dir contains inode structure of the parent of the new file. * @dentry contains the dentry structure for the file to be created. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * @mode contains the file mode of the file to be created. * Return 0 if permission is granted. * @inode_link: * Check permission before creating a new hard link to a file. * @old_dentry contains the dentry structure for an existing link to the file. + * @old_mnt is the vfsmount corresponding to @old_dentry (may be NULL). * @dir contains the inode structure of the parent directory of the new link. * @new_dentry contains the dentry structure for the new link. + * @new_mnt is the vfsmount corresponding to @new_dentry (may be NULL). * Return 0 if permission is granted. * @inode_unlink: * Check the permission to remove a hard link to a file. * @dir contains the inode structure of parent directory of the file. * @dentry contains the dentry structure for file to be unlinked. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * Return 0 if permission is granted. * @inode_symlink: * Check the permission to create a symbolic link to a file. * @dir contains the inode structure of parent directory of the symbolic link. * @dentry contains the dentry structure of the symbolic link. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * @old_name contains the pathname of file. * Return 0 if permission is granted. * @inode_mkdir: @@ -321,12 +346,14 @@ * associated with inode strcture @dir. * @dir containst the inode structure of parent of the directory to be created. * @dentry contains the dentry structure of new directory. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * @mode contains the mode of new directory. * Return 0 if permission is granted. * @inode_rmdir: * Check the permission to remove a directory. * @dir contains the inode structure of parent of the directory to be removed. * @dentry contains the dentry structure of directory to be removed. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * Return 0 if permission is granted. * @inode_mknod: * Check permissions when creating a special file (or a socket or a fifo @@ -335,6 +362,7 @@ * and not this hook. * @dir contains the inode structure of parent of the new file. * @dentry contains the dentry structure of the new file. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * @mode contains the mode of the new file. * @dev contains the device number. * Return 0 if permission is granted. @@ -342,12 +370,15 @@ * Check for permission to rename a file or directory. * @old_dir contains the inode structure for parent of the old link. * @old_dentry contains the dentry structure of the old link. + * @old_mnt is the vfsmount corresponding to @old_dentry (may be NULL). * @new_dir contains the inode structure for parent of the new link. * @new_dentry contains the dentry structure of the new link. + * @new_mnt is the vfsmount corresponding to @new_dentry (may be NULL). * Return 0 if permission is granted. * @inode_readlink: * Check the permission to read the symbolic link. * @dentry contains the dentry structure for the file link. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * Return 0 if permission is granted. * @inode_follow_link: * Check permission to follow a symbolic link when looking up a pathname. @@ -371,6 +402,7 @@ * file attributes change (such as when a file is truncated, chown/chmod * operations, transferring disk quotas, etc). * @dentry contains the dentry structure for the file. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * @attr is the iattr structure containing the new file attributes. * Return 0 if permission is granted. * @inode_getattr: @@ -386,18 +418,18 @@ * inode. * @inode_setxattr: * Check permission before setting the extended attributes - * @value identified by @name for @dentry. + * @value identified by @name for @dentry and @mnt. * Return 0 if permission is granted. * @inode_post_setxattr: * Update inode security field after successful setxattr operation. - * @value identified by @name for @dentry. + * @value identified by @name for @dentry and @mnt. * @inode_getxattr: * Check permission before obtaining the extended attributes - * identified by @name for @dentry. + * identified by @name for @dentry and @mnt. * Return 0 if permission is granted. * @inode_listxattr: * Check permission before obtaining the list of extended attribute - * names for @dentry. + * names for @dentry and @mnt. * Return 0 if permission is granted. * @inode_removexattr: * Check permission before removing the extended attribute @@ -1247,32 +1279,45 @@ void (*inode_free_security) (struct inode *inode); int (*inode_init_security) (struct inode *inode, struct inode *dir, char **name, void **value, size_t *len); - int (*inode_create) (struct inode *dir, - struct dentry *dentry, int mode); - int (*inode_link) (struct dentry *old_dentry, - struct inode *dir, struct dentry *new_dentry); - int (*inode_unlink) (struct inode *dir, struct dentry *dentry); - int (*inode_symlink) (struct inode *dir, - struct dentry *dentry, const char *old_name); - int (*inode_mkdir) (struct inode *dir, struct dentry *dentry, int mode); - int (*inode_rmdir) (struct inode *dir, struct dentry *dentry); + int (*inode_create) (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode); + int (*inode_link) (struct dentry *old_dentry, struct vfsmount *old_mnt, + struct inode *dir, struct dentry *new_dentry, + struct vfsmount *new_mnt); + int (*inode_unlink) (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt); + int (*inode_symlink) (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, const char *old_name); + int (*inode_mkdir) (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode); + int (*inode_rmdir) (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt); int (*inode_mknod) (struct inode *dir, struct dentry *dentry, - int mode, dev_t dev); + struct vfsmount *mnt, int mode, dev_t dev); int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry); - int (*inode_readlink) (struct dentry *dentry); + struct vfsmount *old_mnt, + struct inode *new_dir, struct dentry *new_dentry, + struct vfsmount *new_mnt); + int (*inode_readlink) (struct dentry *dentry, struct vfsmount *mnt); int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd); int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd); - int (*inode_setattr) (struct dentry *dentry, struct iattr *attr); + int (*inode_setattr) (struct dentry *dentry, struct vfsmount *mnt, + struct iattr *attr); int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry); void (*inode_delete) (struct inode *inode); - int (*inode_setxattr) (struct dentry *dentry, char *name, void *value, - size_t size, int flags); - void (*inode_post_setxattr) (struct dentry *dentry, char *name, void *value, + int (*inode_setxattr) (struct dentry *dentry, struct vfsmount *mnt, + char *name, void *value, size_t size, int flags, + struct file *file); + void (*inode_post_setxattr) (struct dentry *dentry, + struct vfsmount *mnt, + char *name, void *value, size_t size, int flags); - int (*inode_getxattr) (struct dentry *dentry, char *name); - int (*inode_listxattr) (struct dentry *dentry); - int (*inode_removexattr) (struct dentry *dentry, char *name); + int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt, + char *name, struct file *file); + int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt, + struct file *file); + int (*inode_removexattr) (struct dentry *dentry, struct vfsmount *mnt, + char *name, struct file *file); int (*inode_need_killpriv) (struct dentry *dentry); int (*inode_killpriv) (struct dentry *dentry); int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err); @@ -1503,30 +1548,43 @@ void security_inode_free(struct inode *inode); int security_inode_init_security(struct inode *inode, struct inode *dir, char **name, void **value, size_t *len); -int security_inode_create(struct inode *dir, struct dentry *dentry, int mode); -int security_inode_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *new_dentry); -int security_inode_unlink(struct inode *dir, struct dentry *dentry); +int security_inode_create(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode); +int security_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt, + struct inode *dir, struct dentry *new_dentry, + struct vfsmount *new_mnt); +int security_inode_unlink(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt); int security_inode_symlink(struct inode *dir, struct dentry *dentry, - const char *old_name); -int security_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode); -int security_inode_rmdir(struct inode *dir, struct dentry *dentry); -int security_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev); + struct vfsmount *mnt, const char *old_name); +int security_inode_mkdir(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode); +int security_inode_rmdir(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt); +int security_inode_mknod(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode, dev_t dev); int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry); -int security_inode_readlink(struct dentry *dentry); + struct vfsmount *old_mnt, struct inode *new_dir, + struct dentry *new_dentry, struct vfsmount *new_mnt); +int security_inode_readlink(struct dentry *dentry, struct vfsmount *mnt); int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd); int security_inode_permission(struct inode *inode, int mask, struct nameidata *nd); -int security_inode_setattr(struct dentry *dentry, struct iattr *attr); +int security_inode_setattr(struct dentry *dentry, struct vfsmount *mnt, + struct iattr *attr); int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry); void security_inode_delete(struct inode *inode); -int security_inode_setxattr(struct dentry *dentry, char *name, - void *value, size_t size, int flags); -void security_inode_post_setxattr(struct dentry *dentry, char *name, - void *value, size_t size, int flags); -int security_inode_getxattr(struct dentry *dentry, char *name); -int security_inode_listxattr(struct dentry *dentry); -int security_inode_removexattr(struct dentry *dentry, char *name); +int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, + char *name, void *value, size_t size, int flags, + struct file *file); +void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt, + char *name, void *value, size_t size, + int flags); +int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt, + char *name, struct file *file); +int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt, + struct file *file); +int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, + char *name, struct file *file); int security_inode_need_killpriv(struct dentry *dentry); int security_inode_killpriv(struct dentry *dentry); int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err); @@ -1813,26 +1871,31 @@ static inline int security_inode_create (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode) { return 0; } static inline int security_inode_link (struct dentry *old_dentry, + struct vfsmount *old_mnt, struct inode *dir, - struct dentry *new_dentry) + struct dentry *new_dentry, + struct vfsmount *new_mnt) { return 0; } static inline int security_inode_unlink (struct inode *dir, - struct dentry *dentry) + struct dentry *dentry, + struct vfsmount *mnt) { return 0; } static inline int security_inode_symlink (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, const char *old_name) { return 0; @@ -1840,19 +1903,22 @@ static inline int security_inode_mkdir (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode) { return 0; } static inline int security_inode_rmdir (struct inode *dir, - struct dentry *dentry) + struct dentry *dentry, + struct vfsmount *mnt) { return 0; } static inline int security_inode_mknod (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode, dev_t dev) { return 0; @@ -1860,13 +1926,16 @@ static inline int security_inode_rename (struct inode *old_dir, struct dentry *old_dentry, + struct vfsmount *old_mnt, struct inode *new_dir, - struct dentry *new_dentry) + struct dentry *new_dentry, + struct vfsmount *new_mnt) { return 0; } -static inline int security_inode_readlink (struct dentry *dentry) +static inline int security_inode_readlink(struct dentry *dentry, + struct vfsmount *mnt) { return 0; } @@ -1884,6 +1953,7 @@ } static inline int security_inode_setattr (struct dentry *dentry, + struct vfsmount *mnt, struct iattr *attr) { return 0; @@ -1898,29 +1968,40 @@ static inline void security_inode_delete (struct inode *inode) { } -static inline int security_inode_setxattr (struct dentry *dentry, char *name, - void *value, size_t size, int flags) -{ - return cap_inode_setxattr(dentry, name, value, size, flags); +static inline int security_inode_setxattr (struct dentry *dentry, + struct vfsmount *mnt, char *name, + void *value, size_t size, int flags, + struct file *file) +{ + return cap_inode_setxattr(dentry, mnt, name, value, size, flags, file); } -static inline void security_inode_post_setxattr (struct dentry *dentry, char *name, - void *value, size_t size, int flags) +static inline void security_inode_post_setxattr (struct dentry *dentry, + struct vfsmount *mnt, + char *name, + void *value, size_t size, + int flags) { } -static inline int security_inode_getxattr (struct dentry *dentry, char *name) +static inline int security_inode_getxattr (struct dentry *dentry, + struct vfsmount *mnt, char *name, + struct file *file) { return 0; } -static inline int security_inode_listxattr (struct dentry *dentry) +static inline int security_inode_listxattr (struct dentry *dentry, + struct vfsmount *mnt, + struct file *file) { return 0; } -static inline int security_inode_removexattr (struct dentry *dentry, char *name) +static inline int security_inode_removexattr (struct dentry *dentry, + struct vfsmount *mnt, char *name, + struct file *file) { - return cap_inode_removexattr(dentry, name); + return cap_inode_removexattr(dentry, mnt, name, file); } static inline int security_inode_need_killpriv(struct dentry *dentry) @@ -2112,7 +2193,7 @@ struct siginfo *info, int sig, u32 secid) { - return cap_task_kill(p, info, sig, secid); + return 0; } static inline int security_task_wait (struct task_struct *p) --- linux-2.6.24.orig/include/linux/connector.h +++ linux-2.6.24/include/linux/connector.h @@ -124,9 +124,9 @@ struct cn_callback_data { void (*destruct_data) (void *); void *ddata; - - void *callback_priv; - void (*callback) (void *); + + struct sk_buff *skb; + void (*callback) (struct cn_msg *, struct netlink_skb_parms *); void *free; }; @@ -159,11 +159,11 @@ struct cn_queue_dev *cbdev; }; -int cn_add_callback(struct cb_id *, char *, void (*callback) (void *)); +int cn_add_callback(struct cb_id *, char *, void (*callback) (struct cn_msg *, struct netlink_skb_parms *)); void cn_del_callback(struct cb_id *); int cn_netlink_send(struct cn_msg *, u32, gfp_t); -int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *)); +int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(struct cn_msg *, struct netlink_skb_parms *)); void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id); struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *); --- linux-2.6.24.orig/include/linux/audit.h +++ linux-2.6.24/include/linux/audit.h @@ -33,7 +33,7 @@ * 1200 - 1299 messages internal to the audit daemon * 1300 - 1399 audit event messages * 1400 - 1499 SE Linux use - * 1500 - 1599 kernel LSPP events + * 1500 - 1599 AppArmor use * 1600 - 1699 kernel crypto events * 1700 - 1799 kernel anomaly records * 1800 - 1999 future kernel use (maybe integrity labels and related events) @@ -116,11 +116,20 @@ #define AUDIT_MAC_IPSEC_DELSPD 1414 /* Not used */ #define AUDIT_MAC_IPSEC_EVENT 1415 /* Audit an IPSec event */ +#define AUDIT_APPARMOR_AUDIT 1501 /* AppArmor audited grants */ +#define AUDIT_APPARMOR_ALLOWED 1502 /* Allowed Access for learning */ +#define AUDIT_APPARMOR_DENIED 1503 +#define AUDIT_APPARMOR_HINT 1504 /* Process Tracking information */ +#define AUDIT_APPARMOR_STATUS 1505 /* Changes in config */ +#define AUDIT_APPARMOR_ERROR 1506 /* Internal AppArmor Errors */ + #define AUDIT_FIRST_KERN_ANOM_MSG 1700 #define AUDIT_LAST_KERN_ANOM_MSG 1799 #define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */ #define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */ +#define AUDIT_SD 1500 /* AppArmor (SubDomain) audit */ + #define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ /* Rule flags */ @@ -513,6 +522,9 @@ __attribute__((format(printf,4,5))); extern struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type); +extern void audit_log_vformat(struct audit_buffer *ab, + const char *fmt, va_list args) + __attribute__((format(printf,2,0))); extern void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) __attribute__((format(printf,2,3))); --- linux-2.6.24.orig/include/linux/hrtimer.h +++ linux-2.6.24/include/linux/hrtimer.h @@ -300,7 +300,7 @@ /* Precise sleep: */ extern long hrtimer_nanosleep(struct timespec *rqtp, - struct timespec *rmtp, + struct timespec __user *rmtp, const enum hrtimer_mode mode, const clockid_t clockid); extern long hrtimer_nanosleep_restart(struct restart_block *restart_block); --- linux-2.6.24.orig/include/linux/latencytop.h +++ linux-2.6.24/include/linux/latencytop.h @@ -0,0 +1,44 @@ +/* + * latencytop.h: Infrastructure for displaying latency + * + * (C) Copyright 2008 Intel Corporation + * Author: Arjan van de Ven + * + */ + +#ifndef _INCLUDE_GUARD_LATENCYTOP_H_ +#define _INCLUDE_GUARD_LATENCYTOP_H_ + +#ifdef CONFIG_LATENCYTOP + +#define LT_SAVECOUNT 32 +#define LT_BACKTRACEDEPTH 12 + +struct latency_record { + unsigned long backtrace[LT_BACKTRACEDEPTH]; + unsigned int count; + unsigned long time; + unsigned long max; +}; + + +struct task_struct; + +void account_scheduler_latency(struct task_struct *task, int usecs, int inter); + +void clear_all_latency_tracing(struct task_struct *p); + +#else + +static inline void +account_scheduler_latency(struct task_struct *task, int usecs, int inter) +{ +} + +static inline void clear_all_latency_tracing(struct task_struct *p) +{ +} + +#endif + +#endif --- linux-2.6.24.orig/include/linux/nfsd/xdr4.h +++ linux-2.6.24/include/linux/nfsd/xdr4.h @@ -207,10 +207,8 @@ u32 op_create; /* request */ u32 op_createmode; /* request */ u32 op_bmval[2]; /* request */ - union { /* request */ - struct iattr iattr; /* UNCHECKED4,GUARDED4 */ - nfs4_verifier verf; /* EXCLUSIVE4 */ - } u; + struct iattr iattr; /* UNCHECKED4, GUARDED4, EXCLUSIVE4_1 */ + nfs4_verifier verf; /* EXCLUSIVE4 */ clientid_t op_clientid; /* request */ struct xdr_netobj op_owner; /* request */ u32 op_seqid; /* request */ @@ -224,8 +222,8 @@ struct nfs4_stateowner *op_stateowner; /* used during processing */ struct nfs4_acl *op_acl; }; -#define op_iattr u.iattr -#define op_verf u.verf +#define op_iattr iattr +#define op_verf verf struct nfsd4_open_confirm { stateid_t oc_req_stateid /* request */; --- linux-2.6.24.orig/include/linux/nfsd/nfsd.h +++ linux-2.6.24/include/linux/nfsd/nfsd.h @@ -79,7 +79,8 @@ #ifdef CONFIG_NFSD_V4 __be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, struct nfs4_acl *); -int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); +int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, + struct vfsmount *mnt, struct nfs4_acl **); #endif /* CONFIG_NFSD_V4 */ __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, --- linux-2.6.24.orig/include/linux/kvm_types.h +++ linux-2.6.24/include/linux/kvm_types.h @@ -0,0 +1,54 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef __KVM_TYPES_H__ +#define __KVM_TYPES_H__ + +#include + +/* + * Address types: + * + * gva - guest virtual address + * gpa - guest physical address + * gfn - guest frame number + * hva - host virtual address + * hpa - host physical address + * hfn - host frame number + */ + +typedef unsigned long gva_t; +typedef u64 gpa_t; +typedef unsigned long gfn_t; + +typedef unsigned long hva_t; +typedef u64 hpa_t; +typedef unsigned long hfn_t; + +struct kvm_pio_request { + unsigned long count; + int cur_count; + struct page *guest_pages[2]; + unsigned guest_page_offset; + int in; + int port; + int size; + int string; + int down; + int rep; +}; + +#endif /* __KVM_TYPES_H__ */ --- linux-2.6.24.orig/include/linux/if_arp.h +++ linux-2.6.24/include/linux/if_arp.h @@ -52,6 +52,8 @@ #define ARPHRD_ROSE 270 #define ARPHRD_X25 271 /* CCITT X.25 */ #define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */ +#define ARPHRD_WIMAX 273 /* WiMAX pseudo-header */ + #define ARPHRD_PPP 512 #define ARPHRD_CISCO 513 /* Cisco HDLC */ #define ARPHRD_HDLC ARPHRD_CISCO --- linux-2.6.24.orig/include/linux/hid.h +++ linux-2.6.24/include/linux/hid.h @@ -267,10 +267,10 @@ #define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100 #define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200 #define HID_QUIRK_MIGHTYMOUSE 0x00000400 -#define HID_QUIRK_POWERBOOK_HAS_FN 0x00000800 -#define HID_QUIRK_POWERBOOK_FN_ON 0x00001000 +#define HID_QUIRK_APPLE_HAS_FN 0x00000800 +#define HID_QUIRK_APPLE_FN_ON 0x00001000 #define HID_QUIRK_INVERT_HWHEEL 0x00002000 -#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00004000 +#define HID_QUIRK_APPLE_ISO_KEYBOARD 0x00004000 #define HID_QUIRK_BAD_RELATIVE_KEYS 0x00008000 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 #define HID_QUIRK_IGNORE_MOUSE 0x00020000 @@ -281,6 +281,8 @@ #define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL 0x00400000 #define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP 0x00800000 #define HID_QUIRK_IGNORE_HIDINPUT 0x01000000 +#define HID_QUIRK_2WHEEL_MOUSE_HACK_B8 0x02000000 +#define HID_QUIRK_APPLE_NUMLOCK_EMULATION 0x20000000 /* * Separate quirks for runtime report descriptor fixup @@ -456,6 +458,8 @@ void *driver_data; + __s32 delayed_value; /* For A4 Tech mice hwheel quirk */ + /* device-specific function pointers */ int (*hidinput_input_event) (struct input_dev *, unsigned int, unsigned int, int); int (*hid_open) (struct hid_device *); @@ -469,7 +473,7 @@ /* handler for raw output data, used by hidraw */ int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t); #ifdef CONFIG_USB_HIDINPUT_POWERBOOK - unsigned long pb_pressed_fn[BITS_TO_LONGS(KEY_CNT)]; + unsigned long apple_pressed_fn[BITS_TO_LONGS(KEY_CNT)]; unsigned long pb_pressed_numlock[BITS_TO_LONGS(KEY_CNT)]; #endif }; --- linux-2.6.24.orig/include/linux/lguest_launcher.h +++ linux-2.6.24/include/linux/lguest_launcher.h @@ -23,7 +23,12 @@ struct lguest_device_desc { /* The device type: console, network, disk etc. Type 0 terminates. */ __u8 type; - /* The number of bytes of the config array. */ + /* The number of virtqueues (first in config array) */ + __u8 num_vq; + /* The number of bytes of feature bits. Multiply by 2: one for host + * features and one for guest acknowledgements. */ + __u8 feature_len; + /* The number of bytes of the config array after virtqueues. */ __u8 config_len; /* A status byte, written by the Guest. */ __u8 status; @@ -31,7 +36,7 @@ }; /*D:135 This is how we expect the device configuration field for a virtqueue - * (type VIRTIO_CONFIG_F_VIRTQUEUE) to be laid out: */ + * to be laid out in config space. */ struct lguest_vqconfig { /* The number of entries in the virtio_ring */ __u16 num; --- linux-2.6.24.orig/include/linux/inotify.h +++ linux-2.6.24/include/linux/inotify.h @@ -128,6 +128,8 @@ struct inotify_watch *); extern void get_inotify_watch(struct inotify_watch *); extern void put_inotify_watch(struct inotify_watch *); +extern int pin_inotify_watch(struct inotify_watch *); +extern void unpin_inotify_watch(struct inotify_watch *); #else @@ -222,6 +224,15 @@ { } +extern inline int pin_inotify_watch(struct inotify_watch *watch) +{ + return 0; +} + +extern inline void unpin_inotify_watch(struct inotify_watch *watch) +{ +} + #endif /* CONFIG_INOTIFY */ #endif /* __KERNEL __ */ --- linux-2.6.24.orig/include/linux/virtio_balloon.h +++ linux-2.6.24/include/linux/virtio_balloon.h @@ -0,0 +1,18 @@ +#ifndef _LINUX_VIRTIO_BALLOON_H +#define _LINUX_VIRTIO_BALLOON_H +#include + +/* The ID for virtio_balloon */ +#define VIRTIO_ID_BALLOON 5 + +/* The feature bitmap for virtio balloon */ +#define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */ + +struct virtio_balloon_config +{ + /* Number of pages host wants Guest to give up. */ + __le32 num_pages; + /* Number of pages we've actually got in balloon. */ + __le32 actual; +}; +#endif /* _LINUX_VIRTIO_BALLOON_H */ --- linux-2.6.24.orig/include/linux/stacktrace.h +++ linux-2.6.24/include/linux/stacktrace.h @@ -9,10 +9,13 @@ }; extern void save_stack_trace(struct stack_trace *trace); +extern void save_stack_trace_tsk(struct task_struct *tsk, + struct stack_trace *trace); extern void print_stack_trace(struct stack_trace *trace, int spaces); #else # define save_stack_trace(trace) do { } while (0) +# define save_stack_trace_tsk(tsk, trace) do { } while (0) # define print_stack_trace(trace, spaces) do { } while (0) #endif --- linux-2.6.24.orig/include/linux/namei.h +++ linux-2.6.24/include/linux/namei.h @@ -81,6 +81,7 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags); extern void release_open_intent(struct nameidata *); +struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd); extern struct dentry *lookup_one_len(const char *, struct dentry *, int); extern struct dentry *lookup_one_noperm(const char *, struct dentry *); --- linux-2.6.24.orig/include/linux/kvm.h +++ linux-2.6.24/include/linux/kvm.h @@ -9,12 +9,10 @@ #include #include +#include #define KVM_API_VERSION 12 -/* Architectural interrupt line count. */ -#define KVM_NR_INTERRUPTS 256 - /* for KVM_CREATE_MEMORY_REGION */ struct kvm_memory_region { __u32 slot; @@ -23,17 +21,19 @@ __u64 memory_size; /* bytes */ }; -/* for kvm_memory_region::flags */ -#define KVM_MEM_LOG_DIRTY_PAGES 1UL - -struct kvm_memory_alias { - __u32 slot; /* this has a different namespace than memory slots */ +/* for KVM_SET_USER_MEMORY_REGION */ +struct kvm_userspace_memory_region { + __u32 slot; __u32 flags; __u64 guest_phys_addr; - __u64 memory_size; - __u64 target_phys_addr; + __u64 memory_size; /* bytes */ + __u64 userspace_addr; /* start of the userspace allocated memory */ }; +/* for kvm_memory_region::flags */ +#define KVM_MEM_LOG_DIRTY_PAGES 1UL + + /* for KVM_IRQ_LINE */ struct kvm_irq_level { /* @@ -45,62 +45,18 @@ __u32 level; }; -/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */ -struct kvm_pic_state { - __u8 last_irr; /* edge detection */ - __u8 irr; /* interrupt request register */ - __u8 imr; /* interrupt mask register */ - __u8 isr; /* interrupt service register */ - __u8 priority_add; /* highest irq priority */ - __u8 irq_base; - __u8 read_reg_select; - __u8 poll; - __u8 special_mask; - __u8 init_state; - __u8 auto_eoi; - __u8 rotate_on_auto_eoi; - __u8 special_fully_nested_mode; - __u8 init4; /* true if 4 byte init */ - __u8 elcr; /* PIIX edge/trigger selection */ - __u8 elcr_mask; -}; - -#define KVM_IOAPIC_NUM_PINS 24 -struct kvm_ioapic_state { - __u64 base_address; - __u32 ioregsel; - __u32 id; - __u32 irr; - __u32 pad; - union { - __u64 bits; - struct { - __u8 vector; - __u8 delivery_mode:3; - __u8 dest_mode:1; - __u8 delivery_status:1; - __u8 polarity:1; - __u8 remote_irr:1; - __u8 trig_mode:1; - __u8 mask:1; - __u8 reserve:7; - __u8 reserved[4]; - __u8 dest_id; - } fields; - } redirtbl[KVM_IOAPIC_NUM_PINS]; -}; - -#define KVM_IRQCHIP_PIC_MASTER 0 -#define KVM_IRQCHIP_PIC_SLAVE 1 -#define KVM_IRQCHIP_IOAPIC 2 struct kvm_irqchip { __u32 chip_id; __u32 pad; union { char dummy[512]; /* reserving space */ +#ifdef CONFIG_X86 struct kvm_pic_state pic; +#endif +#if defined(CONFIG_X86) || defined(CONFIG_IA64) struct kvm_ioapic_state ioapic; +#endif } chip; }; @@ -116,6 +72,7 @@ #define KVM_EXIT_FAIL_ENTRY 9 #define KVM_EXIT_INTR 10 #define KVM_EXIT_SET_TPR 11 +#define KVM_EXIT_TPR_ACCESS 12 /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */ struct kvm_run { @@ -174,90 +131,17 @@ __u32 longmode; __u32 pad; } hypercall; + /* KVM_EXIT_TPR_ACCESS */ + struct { + __u64 rip; + __u32 is_write; + __u32 pad; + } tpr_access; /* Fix the size of the union. */ char padding[256]; }; }; -/* for KVM_GET_REGS and KVM_SET_REGS */ -struct kvm_regs { - /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ - __u64 rax, rbx, rcx, rdx; - __u64 rsi, rdi, rsp, rbp; - __u64 r8, r9, r10, r11; - __u64 r12, r13, r14, r15; - __u64 rip, rflags; -}; - -/* for KVM_GET_FPU and KVM_SET_FPU */ -struct kvm_fpu { - __u8 fpr[8][16]; - __u16 fcw; - __u16 fsw; - __u8 ftwx; /* in fxsave format */ - __u8 pad1; - __u16 last_opcode; - __u64 last_ip; - __u64 last_dp; - __u8 xmm[16][16]; - __u32 mxcsr; - __u32 pad2; -}; - -/* for KVM_GET_LAPIC and KVM_SET_LAPIC */ -#define KVM_APIC_REG_SIZE 0x400 -struct kvm_lapic_state { - char regs[KVM_APIC_REG_SIZE]; -}; - -struct kvm_segment { - __u64 base; - __u32 limit; - __u16 selector; - __u8 type; - __u8 present, dpl, db, s, l, g, avl; - __u8 unusable; - __u8 padding; -}; - -struct kvm_dtable { - __u64 base; - __u16 limit; - __u16 padding[3]; -}; - -/* for KVM_GET_SREGS and KVM_SET_SREGS */ -struct kvm_sregs { - /* out (KVM_GET_SREGS) / in (KVM_SET_SREGS) */ - struct kvm_segment cs, ds, es, fs, gs, ss; - struct kvm_segment tr, ldt; - struct kvm_dtable gdt, idt; - __u64 cr0, cr2, cr3, cr4, cr8; - __u64 efer; - __u64 apic_base; - __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64]; -}; - -struct kvm_msr_entry { - __u32 index; - __u32 reserved; - __u64 data; -}; - -/* for KVM_GET_MSRS and KVM_SET_MSRS */ -struct kvm_msrs { - __u32 nmsrs; /* number of msrs in entries */ - __u32 pad; - - struct kvm_msr_entry entries[0]; -}; - -/* for KVM_GET_MSR_INDEX_LIST */ -struct kvm_msr_list { - __u32 nmsrs; /* number of msrs in entries */ - __u32 indices[0]; -}; - /* for KVM_TRANSLATE */ struct kvm_translation { /* in */ @@ -302,28 +186,24 @@ }; }; -struct kvm_cpuid_entry { - __u32 function; - __u32 eax; - __u32 ebx; - __u32 ecx; - __u32 edx; - __u32 padding; -}; - -/* for KVM_SET_CPUID */ -struct kvm_cpuid { - __u32 nent; - __u32 padding; - struct kvm_cpuid_entry entries[0]; -}; - /* for KVM_SET_SIGNAL_MASK */ struct kvm_signal_mask { __u32 len; __u8 sigset[0]; }; +/* for KVM_TPR_ACCESS_REPORTING */ +struct kvm_tpr_access_ctl { + __u32 enabled; + __u32 flags; + __u32 reserved[8]; +}; + +/* for KVM_SET_VAPIC_ADDR */ +struct kvm_vapic_addr { + __u64 vapic_addr; +}; + #define KVMIO 0xAE /* @@ -341,17 +221,31 @@ * Get size for mmap(vcpu_fd) */ #define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */ +#define KVM_GET_SUPPORTED_CPUID _IOWR(KVMIO, 0x05, struct kvm_cpuid2) /* * Extension capability list. */ #define KVM_CAP_IRQCHIP 0 #define KVM_CAP_HLT 1 +#define KVM_CAP_MMU_SHADOW_CACHE_CONTROL 2 +#define KVM_CAP_USER_MEMORY 3 +#define KVM_CAP_SET_TSS_ADDR 4 +#define KVM_CAP_VAPIC 6 +#define KVM_CAP_EXT_CPUID 7 +#define KVM_CAP_CLOCKSOURCE 8 +#define KVM_CAP_NR_VCPUS 9 /* returns max vcpus per vm */ +#define KVM_CAP_NR_MEMSLOTS 10 /* returns max memory slots per vm */ /* * ioctls for VM fds */ #define KVM_SET_MEMORY_REGION _IOW(KVMIO, 0x40, struct kvm_memory_region) +#define KVM_SET_NR_MMU_PAGES _IO(KVMIO, 0x44) +#define KVM_GET_NR_MMU_PAGES _IO(KVMIO, 0x45) +#define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46,\ + struct kvm_userspace_memory_region) +#define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47) /* * KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns * a vcpu fd. @@ -384,5 +278,11 @@ #define KVM_SET_FPU _IOW(KVMIO, 0x8d, struct kvm_fpu) #define KVM_GET_LAPIC _IOR(KVMIO, 0x8e, struct kvm_lapic_state) #define KVM_SET_LAPIC _IOW(KVMIO, 0x8f, struct kvm_lapic_state) +#define KVM_SET_CPUID2 _IOW(KVMIO, 0x90, struct kvm_cpuid2) +#define KVM_GET_CPUID2 _IOWR(KVMIO, 0x91, struct kvm_cpuid2) +/* Available with KVM_CAP_VAPIC */ +#define KVM_TPR_ACCESS_REPORTING _IOWR(KVMIO, 0x92, struct kvm_tpr_access_ctl) +/* Available with KVM_CAP_VAPIC */ +#define KVM_SET_VAPIC_ADDR _IOW(KVMIO, 0x93, struct kvm_vapic_addr) #endif --- linux-2.6.24.orig/include/linux/cpuidle.h +++ linux-2.6.24/include/linux/cpuidle.h @@ -79,6 +79,7 @@ }; struct cpuidle_device { + unsigned int registered:1; int enabled:1; unsigned int cpu; --- linux-2.6.24.orig/include/linux/syscalls.h +++ linux-2.6.24/include/linux/syscalls.h @@ -66,6 +66,22 @@ #include #include +#define __SC_DECL1(t1, a1) t1 a1 +#define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__) +#define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__) +#define __SC_DECL4(t4, a4, ...) t4 a4, __SC_DECL3(__VA_ARGS__) +#define __SC_DECL5(t5, a5, ...) t5 a5, __SC_DECL4(__VA_ARGS__) +#define __SC_DECL6(t6, a6, ...) t6 a6, __SC_DECL5(__VA_ARGS__) + +#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) + +#define SYSCALL_DEFINEx(x, sname, ...) \ + __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) + +#define SYSCALL_DEFINE(name) asmlinkage long sys_##name +#define __SYSCALL_DEFINEx(x, name, ...) \ + asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)) + asmlinkage long sys_time(time_t __user *tloc); asmlinkage long sys_stime(time_t __user *tptr); asmlinkage long sys_gettimeofday(struct timeval __user *tv, @@ -614,4 +630,7 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[]); +asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff); #endif --- linux-2.6.24.orig/include/linux/Kbuild +++ linux-2.6.24/include/linux/Kbuild @@ -98,7 +98,6 @@ header-y += ixjuser.h header-y += jffs2.h header-y += keyctl.h -header-y += kvm.h header-y += limits.h header-y += lock_dlm_plock.h header-y += magic.h @@ -255,6 +254,7 @@ unifdef-y += kernelcapi.h unifdef-y += kernel.h unifdef-y += keyboard.h +unifdef-$(CONFIG_HAVE_KVM) += kvm.h unifdef-y += llc.h unifdef-y += loop.h unifdef-y += lp.h --- linux-2.6.24.orig/include/linux/irq.h +++ linux-2.6.24/include/linux/irq.h @@ -367,6 +367,9 @@ __set_irq_handler(irq, handle, 1, NULL); } +extern void set_irq_noprobe(unsigned int irq); +extern void set_irq_probe(unsigned int irq); + /* Handle dynamic irq creation and destruction */ extern int create_irq(void); extern void destroy_irq(unsigned int irq); --- linux-2.6.24.orig/include/linux/sysctl.h +++ linux-2.6.24/include/linux/sysctl.h @@ -977,6 +977,8 @@ extern int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int, struct file *, void __user *, size_t *, loff_t *); +extern char *sysctl_pathname(ctl_table *, char *, int); + extern int do_sysctl (int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen); --- linux-2.6.24.orig/include/linux/fb.h +++ linux-2.6.24/include/linux/fb.h @@ -966,6 +966,9 @@ /* drivers/video/fb_defio.c */ extern void fb_deferred_io_init(struct fb_info *info); +extern void fb_deferred_io_open(struct fb_info *info, + struct inode *inode, + struct file *file); extern void fb_deferred_io_cleanup(struct fb_info *info); extern int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync); --- linux-2.6.24.orig/include/linux/futex.h +++ linux-2.6.24/include/linux/futex.h @@ -153,6 +153,7 @@ #ifdef CONFIG_FUTEX extern void exit_robust_list(struct task_struct *curr); extern void exit_pi_state_list(struct task_struct *curr); +extern int futex_cmpxchg_enabled; #else static inline void exit_robust_list(struct task_struct *curr) { --- linux-2.6.24.orig/include/linux/virtio_blk.h +++ linux-2.6.24/include/linux/virtio_blk.h @@ -6,15 +6,19 @@ #define VIRTIO_ID_BLOCK 2 /* Feature bits */ -#define VIRTIO_CONFIG_BLK_F 0x40 -#define VIRTIO_BLK_F_BARRIER 1 /* Does host support barriers? */ +#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */ +#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */ +#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */ -/* The capacity (in 512-byte sectors). */ -#define VIRTIO_CONFIG_BLK_F_CAPACITY 0x41 -/* The maximum segment size. */ -#define VIRTIO_CONFIG_BLK_F_SIZE_MAX 0x42 -/* The maximum number of segments. */ -#define VIRTIO_CONFIG_BLK_F_SEG_MAX 0x43 +struct virtio_blk_config +{ + /* The capacity (in 512-byte sectors). */ + __le64 capacity; + /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */ + __le32 size_max; + /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */ + __le32 seg_max; +} __attribute__((packed)); /* These two define direction. */ #define VIRTIO_BLK_T_IN 0 @@ -35,8 +39,6 @@ __u32 ioprio; /* Sector (ie. 512 byte offset) */ __u64 sector; - /* Where to put reply. */ - __u64 id; }; #define VIRTIO_BLK_S_OK 0 --- linux-2.6.24.orig/include/linux/dmi.h +++ linux-2.6.24/include/linux/dmi.h @@ -78,6 +78,7 @@ extern void dmi_scan_machine(void); extern int dmi_get_year(int field); extern int dmi_name_in_vendors(const char *str); +extern int dmi_name_in_serial(const char *str); extern int dmi_available; #else @@ -88,6 +89,7 @@ const struct dmi_device *from) { return NULL; } static inline int dmi_get_year(int year) { return 0; } static inline int dmi_name_in_vendors(const char *s) { return 0; } +static inline int dmi_name_in_serial(const char *s) { return 0; } #define dmi_available 0 #endif --- linux-2.6.24.orig/include/linux/kvm_host.h +++ linux-2.6.24/include/linux/kvm_host.h @@ -0,0 +1,310 @@ +#ifndef __KVM_HOST_H +#define __KVM_HOST_H + +/* + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#define KVM_MAX_VCPUS 16 +#define KVM_MEMORY_SLOTS 32 +/* memory slots that does not exposed to userspace */ +#define KVM_PRIVATE_MEM_SLOTS 4 + +#define KVM_PIO_PAGE_OFFSET 1 + +/* + * vcpu->requests bit members + */ +#define KVM_REQ_TLB_FLUSH 0 +#define KVM_REQ_MIGRATE_TIMER 1 +#define KVM_REQ_REPORT_TPR_ACCESS 2 +#define KVM_REQ_MMU_RELOAD 3 +#define KVM_REQ_TRIPLE_FAULT 4 + +struct kvm_vcpu; +extern struct kmem_cache *kvm_vcpu_cache; + +struct kvm_guest_debug { + int enabled; + unsigned long bp[4]; + int singlestep; +}; + +/* + * It would be nice to use something smarter than a linear search, TBD... + * Thankfully we dont expect many devices to register (famous last words :), + * so until then it will suffice. At least its abstracted so we can change + * in one place. + */ +struct kvm_io_bus { + int dev_count; +#define NR_IOBUS_DEVS 6 + struct kvm_io_device *devs[NR_IOBUS_DEVS]; +}; + +void kvm_io_bus_init(struct kvm_io_bus *bus); +void kvm_io_bus_destroy(struct kvm_io_bus *bus); +struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr); +void kvm_io_bus_register_dev(struct kvm_io_bus *bus, + struct kvm_io_device *dev); + +struct kvm_vcpu { + struct kvm *kvm; +#ifdef CONFIG_PREEMPT_NOTIFIERS + struct preempt_notifier preempt_notifier; +#endif + int vcpu_id; + struct mutex mutex; + int cpu; + struct kvm_run *run; + int guest_mode; + unsigned long requests; + struct kvm_guest_debug guest_debug; + int fpu_active; + int guest_fpu_loaded; + wait_queue_head_t wq; + int sigset_active; + sigset_t sigset; + struct kvm_vcpu_stat stat; + +#ifdef CONFIG_HAS_IOMEM + int mmio_needed; + int mmio_read_completed; + int mmio_is_write; + int mmio_size; + unsigned char mmio_data[8]; + gpa_t mmio_phys_addr; +#endif + + struct kvm_vcpu_arch arch; +}; + +struct kvm_memory_slot { + gfn_t base_gfn; + unsigned long npages; + unsigned long flags; + unsigned long *rmap; + unsigned long *dirty_bitmap; + struct { + unsigned long rmap_pde; + int write_count; + } *lpage_info; + unsigned long userspace_addr; + int user_alloc; +}; + +struct kvm { + struct mutex lock; /* protects the vcpus array and APIC accesses */ + spinlock_t mmu_lock; + struct rw_semaphore slots_lock; + struct mm_struct *mm; /* userspace tied to this vm */ + int nmemslots; + struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS + + KVM_PRIVATE_MEM_SLOTS]; + struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; + struct list_head vm_list; + struct file *filp; + struct kvm_io_bus mmio_bus; + struct kvm_io_bus pio_bus; + struct kvm_vm_stat stat; + struct kvm_arch arch; +}; + +/* The guest did something we don't support. */ +#define pr_unimpl(vcpu, fmt, ...) \ + do { \ + if (printk_ratelimit()) \ + printk(KERN_ERR "kvm: %i: cpu%i " fmt, \ + current->tgid, (vcpu)->vcpu_id , ## __VA_ARGS__); \ + } while (0) + +#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt) +#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt) + +int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id); +void kvm_vcpu_uninit(struct kvm_vcpu *vcpu); + +void vcpu_load(struct kvm_vcpu *vcpu); +void vcpu_put(struct kvm_vcpu *vcpu); + +void decache_vcpus_on_cpu(int cpu); + + +int kvm_init(void *opaque, unsigned int vcpu_size, + struct module *module); +void kvm_exit(void); + +#define HPA_MSB ((sizeof(hpa_t) * 8) - 1) +#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB) +static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } +struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva); + +extern struct page *bad_page; + +int is_error_page(struct page *page); +int kvm_is_error_hva(unsigned long addr); +int kvm_set_memory_region(struct kvm *kvm, + struct kvm_userspace_memory_region *mem, + int user_alloc); +int __kvm_set_memory_region(struct kvm *kvm, + struct kvm_userspace_memory_region *mem, + int user_alloc); +int kvm_arch_set_memory_region(struct kvm *kvm, + struct kvm_userspace_memory_region *mem, + struct kvm_memory_slot old, + int user_alloc); +gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn); +struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); +unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn); +void kvm_release_page_clean(struct page *page); +void kvm_release_page_dirty(struct page *page); +int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset, + int len); +int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data, + unsigned long len); +int kvm_read_guest(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len); +int kvm_write_guest_page(struct kvm *kvm, gfn_t gfn, const void *data, + int offset, int len); +int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data, + unsigned long len); +int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len); +int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len); +struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn); +int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn); +void mark_page_dirty(struct kvm *kvm, gfn_t gfn); + +void kvm_vcpu_block(struct kvm_vcpu *vcpu); +void kvm_resched(struct kvm_vcpu *vcpu); +void kvm_load_guest_fpu(struct kvm_vcpu *vcpu); +void kvm_put_guest_fpu(struct kvm_vcpu *vcpu); +void kvm_flush_remote_tlbs(struct kvm *kvm); +void kvm_reload_remote_mmus(struct kvm *kvm); + +long kvm_arch_dev_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg); +long kvm_arch_vcpu_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg); +void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu); +void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu); + +int kvm_dev_ioctl_check_extension(long ext); + +int kvm_get_dirty_log(struct kvm *kvm, + struct kvm_dirty_log *log, int *is_dirty); +int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, + struct kvm_dirty_log *log); + +int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, + struct + kvm_userspace_memory_region *mem, + int user_alloc); +long kvm_arch_vm_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg); +void kvm_arch_destroy_vm(struct kvm *kvm); + +int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu); +int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu); + +int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, + struct kvm_translation *tr); + +int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs); +int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs); +int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, + struct kvm_sregs *sregs); +int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, + struct kvm_sregs *sregs); +int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, + struct kvm_debug_guest *dbg); +int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run); + +int kvm_arch_init(void *opaque); +void kvm_arch_exit(void); + +int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu); +void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu); + +void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu); +void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu); +void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu); +struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id); +int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu); +void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu); + +int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu); +void kvm_arch_hardware_enable(void *garbage); +void kvm_arch_hardware_disable(void *garbage); +int kvm_arch_hardware_setup(void); +void kvm_arch_hardware_unsetup(void); +void kvm_arch_check_processor_compat(void *rtn); +int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu); + +void kvm_free_physmem(struct kvm *kvm); + +struct kvm *kvm_arch_create_vm(void); +void kvm_arch_destroy_vm(struct kvm *kvm); + +int kvm_cpu_get_interrupt(struct kvm_vcpu *v); +int kvm_cpu_has_interrupt(struct kvm_vcpu *v); +void kvm_vcpu_kick(struct kvm_vcpu *vcpu); + +static inline void kvm_guest_enter(void) +{ + account_system_vtime(current); + current->flags |= PF_VCPU; +} + +static inline void kvm_guest_exit(void) +{ + account_system_vtime(current); + current->flags &= ~PF_VCPU; +} + +static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot) +{ + return slot - kvm->memslots; +} + +static inline gpa_t gfn_to_gpa(gfn_t gfn) +{ + return (gpa_t)gfn << PAGE_SHIFT; +} + +static inline void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) +{ + set_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests); +} + +enum kvm_stat_kind { + KVM_STAT_VM, + KVM_STAT_VCPU, +}; + +struct kvm_stats_debugfs_item { + const char *name; + int offset; + enum kvm_stat_kind kind; + struct dentry *dentry; +}; +extern struct kvm_stats_debugfs_item debugfs_entries[]; + +#endif --- linux-2.6.24.orig/include/linux/percpu.h +++ linux-2.6.24/include/linux/percpu.h @@ -34,7 +34,7 @@ #ifdef CONFIG_SMP struct percpu_data { - void *ptrs[NR_CPUS]; + void *ptrs[1]; }; #define __percpu_disguise(pdata) (struct percpu_data *)~(unsigned long)(pdata) --- linux-2.6.24.orig/include/linux/mmc/sd_protocol.h +++ linux-2.6.24/include/linux/mmc/sd_protocol.h @@ -0,0 +1,314 @@ +/* + * sd_protocol.h - SD Protocol driver header file + * + * Copyright (C) 2007 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 only + * for now as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * derived from previous mmc code in Linux kernel + * Copyright (c) 2002 Hewlett-Packard Company + * Copyright (c) 2002 Andrew Christian + * Copyright (c) 2006 Bridge Wu + */ + + + +#ifndef __SD_PROTOCOL_H__ +#define __SD_PROTOCOL_H__ + +#include + +#define SD_PROTOCOL "sd" + +#define MSS_SD_QUERY_FUNC 0x100 +#define MSS_SD_SW_FUNC 0x101 + +/* Standard SD clock speeds */ +#define SD_CARD_CLOCK_SLOW 0 +#define SD_CARD_CLOCK_FAST 50000000 + +/* command type: ac(addressed command), bcr(broadcase command with response), + * adtc(addressed data transfer command), bc(broadcase command) + */ + +/* Standard SD commands (1.01) type argument response */ + /* class 0, basic: 0, 2-4, 7, 9, 10, 12, 13, 15 */ +#define SD_GO_IDLE_STATE 0 /* bc */ +#define SD_ALL_SEND_CID 2 /* bcr R2 */ +#define SD_SEND_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ +#define SD_SET_DSR 4 /* bc [31:16] RCA */ +#define SD_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define SD_SEND_CSD 9 /* ac [31:16] RCA R2 */ +#define SD_SEND_CID 10 /* ac [31:16] RCA R2 */ +#define SD_STOP_TRANSMISSION 12 /* ac R1b */ +#define SD_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define SD_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ +#define SD_SW_FUNC 6 +#define SD_SEND_IF_COND 8 + + /* class 1: reserved */ + /* class 3: reserved */ + + /* class 2, block read: 16-18 */ +#define SD_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ +#define SD_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ +#define SD_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ + + /* class 4, block write: 16, 24, 25, 27 */ +#define SD_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ +#define SD_WRITE_MULTIPLE_BLOCK 25 /* adtc [31:0] data addr R1 */ +#define SD_PROGRAM_CID 26 /* adtc R1 */ +#define SD_PROGRAM_CSD 27 /* adtc R1 */ +/* CMD26 appeared in SDMC state diagram(data transfer mode) */ + + /* class 6, write-protection: 28, 29, 30 */ +#define SD_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ +#define SD_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ +#define SD_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ + + /* class 5, erase: 32, 33, 38 */ +#define SD_ERASE_WR_BLOCK_START 32 /* ac [31:0] data addr R1 */ +#define SD_ERASE_WR_BLOCK_END 33 /* ac [31:0] data addr R1 */ +#define SD_ERASE 38 /* ac R1b */ + + /* class 7, lock card: 42 */ +#define SD_LOCK_UNLOCK 42 /* adtc R1b */ + + /* class 8, application specific: 55, 56 */ +#define SD_APP_CMD 55 /* ac [31:16] RCA R1 */ +#define SD_GEN_CMD 56 /* adtc [0] RD/WR R1b */ + + /* class 8, application specific: ACMD6,13,22,23,41,42,51 */ +#define SD_SET_BUS_WIDTH 6 /* ac [1:0] BUS WIDTH R1 */ +#define SD_SD_STATUS 13 /* adtc R1 */ +#define SD_SEND_NUM_WR_BLOCKS 22 /* adtc R1 */ +#define SD_SET_WR_BLK_ERASE_COUNT 23 /* ac [22:0] No.Blocks R1 */ +#define SD_SD_SEND_OP_COND 41 /* bcr [31:0] OCR R3 */ +#define SD_SET_CLR_CARD_DETECT 42 /* ac [0] set_cd R1 */ +#define SD_SEND_SCR 51 /* adtc R1 */ + +/* + SD card status in R1: compatible to the MMC protocol + (SD status: extended status field of 512b, ACMD13 require card to send this) + Type + e : error bit + s : status bit + r : detected and set for the actual command response + x : detected and set during command execution. the host must poll + the card by sending status command in order to read these bits. + Clear condition + a : according to the card state + b : always related to the previous command. Reception of + a valid command will clear it (with a delay of one command) + c : clear by read + */ + +#define R1_OUT_OF_RANGE (1 << 31) /* er, c */ +#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */ +#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */ +#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ +#define R1_ERASE_PARAM (1 << 27) /* ex, c */ +#define R1_WP_VIOLATION (1 << 26) /* erx, c */ +#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ +#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ +#define R1_COM_CRC_ERROR (1 << 23) /* er, b */ +#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ +#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */ +#define R1_CC_ERROR (1 << 20) /* erx, c */ +#define R1_ERROR (1 << 19) /* erx, c */ +#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */ +#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ +#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ +#define R1_ERASE_RESET (1 << 13) /* sr, c */ +#define R1_STATUS(x) ((x) & 0xFFFFE000) + +#define R1_CURRENT_STATE(x) (((x) & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_READY_FOR_DATA (1 << 8) /* sx, a */ +#define R1_APP_CMD (1 << 5) /* sr, c */ +#define R1_AKE_SEQ_ERROR (1 << 3) /* er, c */ + + +#define R6_COM_CRC_ERROR (1 << 15) /* er, b */ +#define R6_ILLEGAL_COMMAND (1 << 14) /* er, b */ +#define R6_ERROR (1 << 13) /* erx, c */ +#define R6_STATUS(x) ((x) & 0xFFFFE000) +#define R6_CURRENT_STATE(x) (((x) & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R6_READY_FOR_DATA (1 << 8) /* sx, a */ +#define R6_APP_CMD (1 << 5) /* sr, c */ + +/** + * SD status: extended status field of 512b, ACMD13 require card to send this. + * [511:510] DAT_BUS_WIDTH SR A + * [509] SECURE_MODE SR A + * [495:480] SD_CARD_TYPE SR A + * [479:448] SIZE_OF_PROTECTED_AREA SR A + */ +enum sd_status_error { + SD_ERROR_NONE = 0, + SD_ERROR_OUT_OF_RANGE, + SD_ERROR_ADDRESS, + SD_ERROR_BLOCK_LEN, + SD_ERROR_ERASE_SEQ, + SD_ERROR_ERASE_PARAM, + SD_ERROR_WP_VIOLATION, + SD_ERROR_CARD_IS_LOCKED, + SD_ERROR_LOCK_UNLOCK_FAILED, + SD_ERROR_COM_CRC, + SD_ERROR_ILLEGAL_COMMAND, /* 10 */ + SD_ERROR_CARD_ECC_FAILED, + SD_ERROR_CC, + SD_ERROR_GENERAL, + SD_ERROR_CID_CSD_OVERWRITE, + SD_ERROR_AKE_SEQ, + SD_ERROR_SWFUNC, + SD_ERROR_STATE_MISMATCH, + SD_ERROR_HEADER_MISMATCH, +}; + + + +enum card_state { + CARD_STATE_EMPTY = -1, + CARD_STATE_IDLE = 0, + CARD_STATE_READY = 1, + CARD_STATE_IDENT = 2, + CARD_STATE_STBY = 3, + CARD_STATE_TRAN = 4, + CARD_STATE_DATA = 5, + CARD_STATE_RCV = 6, + CARD_STATE_PRG = 7, + CARD_STATE_DIS = 8, + CARD_STATE_CMD = 9 +}; + +struct sd_cid { + u8 mid; + u16 oid; + u8 pnm[6]; // Product name (we null-terminate) + u8 prv; + u32 psn; + u16 mdt; +}; + +struct sd_csd { + u8 csd_structure; +#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ +#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ +#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */ + u8 taac; + u8 nsac; + u8 tran_speed; + u16 ccc; + u8 read_bl_len; + u8 read_bl_partial; + u8 write_blk_misalign; + u8 read_blk_misalign; + u8 dsr_imp; + union { + struct { + u16 c_size; + u8 vdd_r_curr_min; + u8 vdd_r_curr_max; + u8 vdd_w_curr_min; + u8 vdd_w_curr_max; + u8 c_size_mult; + } csd1; + struct { + u32 c_size; + } csd2; + }csd; + u8 erase_blk_en; + u8 sector_size; + u8 wp_grp_size; + u8 wp_grp_enable; + u8 r2w_factor; + u8 write_bl_len; + u8 write_bl_partial; + u8 file_format_grp; + u8 copy; + u8 perm_write_protect; + u8 tmp_write_protect; + u8 file_format; +}; + +struct sd_scr { + u8 scr_structure; + u8 sd_spec; + u8 data_stat_after_erase; + u8 sd_security; + u8 sd_bus_width; +#define SCR_BUSWIDTH_1BIT 0 +#define SCR_BUSWIDTH_4BIT (1 << 2) + u8 init; +}; + +/* These are unpacked versions of the actual responses */ + +struct sd_response_r1 { + u8 cmd; + u32 status; +}; + +struct sd_response_r3 { + u8 cmd; + u32 ocr; +#define SD_OCR_CARD_BUSY (1 << 31) /* Card Power up status bit */ +#define SD_OCR_CCS (1 << 30) +}; + +struct sd_response_r6 { + u8 cmd; + u16 rca; + u16 status; +}; + +struct sd_response_r7 { + u8 cmd; + u8 ver; + u8 vca; + u8 pattern; +}; + +struct sw_func_status { + u16 current_consumption; + u16 func_support[6]; + u8 group_status[6]; + u16 func_busy[6]; +}; + +struct sd_card { + struct sd_cid cid; + struct sd_csd csd; + struct sd_scr scr; + u32 ocr; + u32 rca:16, + ver:8, + high_speed:2; + char *buf; + struct mss_ll_request llreq; + struct mss_cmd cmd; + struct mss_data data; + enum sd_status_error errno; + enum card_state state; + u32 block_len; +}; + +struct io_swfunc_request { + u16 current_acceptable; + u8 args[6]; +}; + +#endif --- linux-2.6.24.orig/include/linux/mmc/sdio_protocol.h +++ linux-2.6.24/include/linux/mmc/sdio_protocol.h @@ -0,0 +1,374 @@ +/* + * sdio_protocol.h - SDIO Protocol driver header file + * + * Copyright (C) 2007 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 only + * for now as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * derived from previous mmc code in Linux kernel + * Copyright (c) 2002 Hewlett-Packard Company + * Copyright (c) 2002 Andrew Christian + * Copyright (c) 2006 Bridge Wu + */ + + +#ifndef __SDIO_PROTOCOL_H__ +#define __SDIO_PROTOCOL_H__ + +#define SDIO_PROTOCOL "sdio" + +#define SDIO_READ 0 +#define SDIO_WRITE 1 + +#define CMD53_OP_FIXED 0 +#define CMD53_OP_INC 1 + +/* Standard SD clock speeds */ +#define SDIO_CARD_CLOCK_SLOW 0 /* 0/100KHz -- 400 kHz for initial setup */ +#define SDIO_CARD_CLOCK_FAST 25000000 /* 25 MHz for maximum for normal operation */ + +/* command type: ac(addressed command), bcr(broadcase command with response), + * adtc(addressed data transfer command), bc(broadcase command) + */ + +/* Standard SD commands (1.01) type argument response */ + /* class 0, basic: 0, 2-4, 7, 9, 10, 12, 13, 15 */ +#define SD_GO_IDLE_STATE 0 /* bc */ +#define SD_ALL_SEND_CID 2 /* bcr R2 */ +#define SD_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ +#define SD_SET_DSR 4 /* bc [31:16] RCA */ +#define SD_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define SD_SEND_CSD 9 /* ac [31:16] RCA R2 */ +#define SD_SEND_CID 10 /* ac [31:16] RCA R2 */ +#define SD_STOP_TRANSMISSION 12 /* ac R1b */ +#define SD_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define SD_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ + + /* class 1: reserved */ + /* class 3: reserved */ + + /* class 2, block read: 16-18 */ +#define SD_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ +#define SD_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ +#define SD_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ + + /* class 4, block write: 16, 24, 25, 27 */ +#define SD_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ +#define SD_WRITE_MULTIPLE_BLOCK 25 /* adtc [31:0] data addr R1 */ +#define SD_PROGRAM_CID 26 /* adtc R1 */ +#define SD_PROGRAM_CSD 27 /* adtc R1 */ +/* CMD26 appeared in SDMC state diagram(data transfer mode) */ + + /* class 6, write-protection: 28, 29, 30 */ +#define SD_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ +#define SD_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ +#define SD_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ + + /* class 5, erase: 32, 33, 38 */ +#define SD_ERASE_WR_BLOCK_START 32 /* ac [31:0] data addr R1 */ +#define SD_ERASE_WR_BLOCK_END 33 /* ac [31:0] data addr R1 */ +#define SD_ERASE 38 /* ac R1b */ + + /* class 7, lock card: 42 */ +#define SD_LOCK_UNLOCK 42 /* adtc R1b */ + + /* class 8, application specific: 55, 56 */ +#define SD_APP_CMD 55 /* ac [31:16] RCA R1 */ +#define SD_GEN_CMD 56 /* adtc [0] RD/WR R1b */ + + /* class 8, application specific: ACMD6,13,22,23,41,42,51 */ +#define SD_SET_BUS_WIDTH 6 /* ac [1:0] BUS WIDTH R1 */ +#define SD_SD_STATUS 13 /* adtc R1 */ +#define SD_SEND_NUM_WR_BLOCKS 22 /* adtc R1 */ +#define SD_SET_WR_BLK_ERASE_COUNT 23 /* ac [22:0] No.Blocks R1 */ +#define SD_SD_SEND_OP_COND 41 /* bcr [31:0] OCR R3 */ +#define SD_SET_CLR_CARD_DETECT 42 /* ac [0] set_cd R1 */ +#define SD_SEND_SCR 51 /* adtc R1 */ + + + +/* SDIO cmd */ +#define IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */ +#define IO_RW_DIRECT 52 /* R5 */ +#define IO_RW_EXTENDED 53 /* R5 */ + +/* + SD card status in R1: compatible to the MMC protocol + (SD status: extended status field of 512b, ACMD13 require card to send this) + Type + e : error bit + s : status bit + r : detected and set for the actual command response + x : detected and set during command execution. the host must poll + the card by sending status command in order to read these bits. + Clear condition + a : according to the card state + b : always related to the previous command. Reception of + a valid command will clear it (with a delay of one command) + c : clear by read + */ + +#define R1_OUT_OF_RANGE (1 << 31) /* er, c */ +#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */ +#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */ +#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ +#define R1_ERASE_PARAM (1 << 27) /* ex, c */ +#define R1_WP_VIOLATION (1 << 26) /* erx, c */ +#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ +#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ +#define R1_COM_CRC_ERROR (1 << 23) /* er, b */ +#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ +#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */ +#define R1_CC_ERROR (1 << 20) /* erx, c */ +#define R1_ERROR (1 << 19) /* erx, c */ +#define R1_UNDERRUN (1 << 18) /* ex, c */ +#define R1_OVERRUN (1 << 17) /* ex, c */ +#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */ +#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ +#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ +#define R1_ERASE_RESET (1 << 13) /* sr, c */ +#define R1_STATUS(x) (x & 0xFFFFE000) + +#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_READY_FOR_DATA (1 << 8) /* sx, a */ +#define R1_APP_CMD (1 << 5) /* sr, c */ +#define R1_AKE_SEQ_ERROR (1 << 3) /* er, c */ + + +/** + * SD status: extended status field of 512b, ACMD13 require card to send this. + * [511:510] DAT_BUS_WIDTH SR A + * [509] SECURE_MODE SR A + * [495:480] SD_CARD_TYPE SR A + * [479:448] SIZE_OF_PROTECTED_AREA SR A + */ + +/* for SDIO response r5 r6*/ +#define R5_COM_CRC_ERROR (1 << 7) /* er, b */ +#define R5_ILLEGAL_COMMAND (1 << 6) /* er, b */ +#define R5_ERROR (1 << 3) /* er, c */ +#define R5_FUNCTION_NUMBER (1 << 1) /* er, c */ +#define R5_OUT_OF_RANGE (1 << 0) /* er, c */ +#define R5_CURRENT_STATE(x) ((x & 0x30) >> 4) /* sx, b (4 bits) */ + +#define R6_COM_CRC_ERROR (1 << 15) /* er, b */ +#define R6_ILLEGAL_COMMAND (1 << 14) /* er, b */ +#define R6_ERROR (1 << 13) /* erx, c */ +#define R6_STATUS(x) (x & 0xFFFFE000) +#define R6_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R6_READY_FOR_DATA (1 << 8) /* sx, a */ +#define R6_APP_CMD (1 << 5) /* sr, c */ + + +#define MAX_FUNC_NUMBER 8 + +/* cccr register */ +#define CCCR_SDIO_REVISION (0x00) +#define SD_SPEC_REVISION (0x01) +#define IO_ENABLE (0x02) +#define IO_READY (0x03) +#define INT_ENABLE (0x04) +#define INT_PENDING (0x05) +#define IO_ABORT (0x06) +#define BUS_IF_CTRL (0x07) +#define CARD_CAPABILITY (0x08) +#define COMMON_CIS_POINTER_1 (0x09) +#define COMMON_CIS_POINTER_2 (0x0a) +#define COMMON_CIS_POINTER_3 (0x0b) +#define BUS_SUSPEND (0x0c) +#define FUNCTION_SELECT (0x0d) +#define EXEC_FLAGS (0x0e) +#define READY_FLAGS (0x0f) +#define FN0_BLKSZ_1 (0x10) +#define FN0_BLKSZ_2 (0x11) +#define POWER_CTRL (0x12) + +/* fbr register */ +#define FNn_IF_CODE(n) ((n << 8) | 0x00) +#define FNn_EXT_IF_CODE(n) ((n << 8) | 0x01) +#define FNn_SPS(n) ((n << 8) | 0x02) +#define FNn_CIS_POINTER_1(n) ((n << 8) | 0x09) +#define FNn_CIS_POINTER_2(n) ((n << 8) | 0x0a) +#define FNn_CIS_POINTER_3(n) ((n << 8) | 0x0b) +#define FNn_CSA_POINTER_1(n) ((n << 8) | 0x0c) +#define FNn_CSA_POINTER_2(n) ((n << 8) | 0x0d) +#define FNn_CSA_POINTER_3(n) ((n << 8) | 0x0e) +#define FNn_CSA_ACCESS_WIN(n) ((n << 8) | 0x0f) +#define FNn_BLKSZ_1(n) ((n << 8) | 0x10) +#define FNn_BLKSZ_2(n) ((n << 8) | 0x11) + +/* CIS tuple codes supported by SDIO device */ +#define CISTPL_NULL (0x00) +#define CISTPL_CHECKSUM (0x10) +#define CISTPL_VERS_1 (0x15) +#define CISTPL_ALTSTR (0x16) +#define CISTPL_MANFID (0x20) +#define CISTPL_FUNCID (0x21) +#define CISTPL_FUNCE (0x22) +#define CISTPL_SDIO_STD (0x91) +#define CISTPL_SDIO_EXT (0x92) +#define CISTPL_END (0xff) + +#define SDIO_R (0) +#define SDIO_W (1) + +enum sdio_status_error { + SDIO_ERROR_NONE = 0, + SDIO_ERROR_COM_CRC, + SDIO_ERROR_ILLEGAL_COMMAND, /* 10 */ + SDIO_ERROR_GENERAL, + SDIO_ERROR_OUT_OF_RANGE, + SDIO_ERROR_FUNC_NUM, + SDIO_ERROR_STATE_MISMATCH, + SDIO_ERROR_HEADER_MISMATCH, +}; + + + +enum card_state { + CARD_STATE_EMPTY = -1, + CARD_STATE_INIT = 0, + CARD_STATE_STBY = 3, + CARD_STATE_TRAN = 4, + CARD_STATE_CMD = 9 +}; + + +struct sdio_response_r1 { + u8 cmd; + u32 status; +}; + +struct sdio_response_r4 { + u32 ocr; + u8 ready; + u8 mem_present; + u8 func_num; +}; + +struct sdio_response_r5 { + u8 cmd; + u8 status; + u8 data; +}; + +struct sdio_response_r6 { + u8 cmd; + u16 rca; + int status; +}; + +struct sdio_cccr { + u8 cccrx:4, + sdiox:4; + u8 sdx; + u8 ioex; + u8 iorx; + u8 intex; + u8 intx; + u8 buswidth:2, + cd:1; + /* card capability */ + u8 sdc:1, + smb:1, + srw:1, + sbs:1, + s4mi:1, + e4mi:1, + lsc:1, + ls4b:1; + /* pointer to common CIS */ + u32 pccis; + u8 br:1, + bs:1; + u8 fsx:4, + df:1; + u8 exx; + u8 rfx; + u16 fn0_blksz; + u8 smpc:1, + empc:1; +}; + +struct sdio_fbr { + u8 fun_if_code:4, + fun_support_csa:1, + fun_csa_enable:1; + u8 fun_ext_if_code; + u32 pfcis; + u32 pcsa; + u16 fn_blksz; +}; + +struct sdio_ccis { + u16 manufacturer; /* CISTPL_MANFID */ + u16 card_id; +#if 1 + /* it seems this is n/a for type common according to SDIO spec 1.1 */ + u8 device_class; /* CISTPL_FUNCID, should be 0x0c */ + + /* CISTPL_FUNCE tuple for function 0 */ + u16 fn0_block_size; + u8 max_tran_speed; +#endif +}; + +struct sdio_fcis { + u8 device_class; /* CISTPL_FUNCID, should be 0x0c */ + + /* CISTPL_FUNCE for function 1 - 7 */ + u8 func_info; + u8 std_io_rev; + u32 card_psn; + u32 csa_size; + u8 csa_property; + u16 max_blk_size; + u32 ocr; + u8 op_min_pwr; /* op:operating pwr: current in mA */ + u8 op_avg_pwr; + u8 op_max_pwr; + u8 sb_min_pwr; /* sb:standby */ + u8 sb_avg_pwr; + u8 sb_max_pwr; + u16 min_bw; /* min data transfer bandwidth */ + u16 opt_bw; /* optimum data transfer bandwidth */ + /* SDIO 1.0 not support and 1.1 suport */ + u16 enable_timeout_val; + /* added for 1.1 on 7.13 */ + u16 sp_avg_pwr; + u16 sp_max_pwr; + u16 hp_avg_pwr; + u16 hp_max_pwr; + u16 lp_avg_pwr; + u16 lp_max_pwr; +}; + +struct sdio_card { + u8 func_num; + u8 mem_present; + u16 rca; + struct sdio_cccr cccr; + struct sdio_fbr fbr[MAX_FUNC_NUMBER]; + struct sdio_ccis ccis; + struct sdio_fcis fcis[MAX_FUNC_NUMBER]; + struct mss_ll_request llreq; + struct mss_cmd cmd; + struct mss_data data; + enum sdio_status_error errno; + enum card_state state; +}; + +#endif --- linux-2.6.24.orig/include/linux/mmc/mmc_protocol.h +++ linux-2.6.24/include/linux/mmc/mmc_protocol.h @@ -0,0 +1,366 @@ +/* + * mmc_protocol.h - MMC Protocol driver header file + * + * Copyright (C) 2007 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 only + * for now as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * derived from previous mmc code in Linux kernel + * Copyright (c) 2002 Hewlett-Packard Company + * Copyright (c) 2002 Andrew Christian + * Copyright (c) 2006 Bridge Wu + */ + + +#ifndef __MMC_PROTOCOL_H__ +#define __MMC_PROTOCOL_H__ + + +#include + +#define MMC_PROTOCOL "mmc" + +/*card status*/ + +#define PARSE_U32(_buf) \ + (((u32)(_buf)[0]) << 24) | (((u32)(_buf)[1]) << 16) | \ + (((u32)(_buf)[2]) << 8) | ((u32)(_buf)[3]); + +#define PARSE_U16(_buf) \ + (((u16)(_buf)[0]) << 8) | ((u16)(_buf)[1]); + + +/* Standard MMC clock speeds */ +#define MMC_CARD_CLOCK_SLOW 0 /* The LOWEST clock for mmc */ +#define MMC_CARD_CLOCK_FAST 52000000 /* The HIGHEST clock for mmc */ + +/* command type: ac(addressed command), bcr(broadcase command with response), + * adtc(addressed data transfer command), bc(broadcase command) + */ + +/* Standard MMC commands (4.0) type argument response */ + + /* class 0, basic: 0-10, 12-15, 19 */ +#define MMC_GO_IDLE_STATE 0 /* bc */ +#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ +#define MMC_ALL_SEND_CID 2 /* bcr R2 */ +#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ +#define MMC_SET_DSR 4 /* bc [31:16] DSR */ +#define MMC_RSVD5 5 +#define MMC_SWITCH 6 /* ac see comments below R1b */ +#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ +#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ +#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ +#define MMC_STOP_TRANSMISSION 12 /* ac R1b */ +#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_BUSTEST_R 14 /* adtc R1 */ +#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ +#define MMC_BUSTEST_W 19 /* adtc R1 */ +/* CMD6: [25:24access,23:16index,15:8value,2:0cmd set] */ + + /* class 1, stream read: 11 */ +#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ + + /* class 2, block read: 16-18, 23 */ +#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ +#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ +#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ + + /* class 3, stream write: 20 */ +#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ + + /* class 4, block write: 16, 23-27 */ +#define MMC_SET_BLOCK_COUNT 23 /* ad [15:0] nob R1 */ +#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ +#define MMC_PROGRAM_CID 26 /* adtc R1 */ +#define MMC_PROGRAM_CSD 27 /* adtc R1 */ + + /* class 6, write protection: 28-30 */ +#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ +#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ +#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ + + /* class 5, erase: 35, 36, 38 */ +#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ +#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ +#define MMC_ERASE 37 /* ac R1b */ + + /* class 9, I/O mode: 39, 40 */ +#define MMC_FAST_IO 39 /* ac see comments below R4 */ +#define MMC_GO_IRQ_STATE 40 /* bcr R5 */ +/* [31:16RCA, 15:15reg write flag, 14:8reg address, 7:0reg data] */ + + /* class 7, lock card: 42 */ +#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ + + /* class 8, application specific: 55, 56 */ +#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */ +#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1b */ + +#if 0 +#ifdef CONFIG_CEATA + + // CEATA command +#define CEATA_RW_MULTIPLE_REGISTER 60 /* R1B*/ +#define CEATA_RW_MULTIPLE_BLOCK 61 /* R1B*/ + + +//CEATA taskfile related +#define CEATA_FEATURES_EXP 0x01 +#define CEATA_SECTOR_COUNT_EXP 0x02 +#define CEATA_LBA_LOW_EXP 0x03 +#define CEATA_LBA_MID_EXP 0x04 +#define CEATA_LBA_HIGH_EXP 0x05 +#define CEATA_CONTROL 0x06 +#define CEATA_FEATURES_ERROR 0x09 +#define CEATA_SECTOR_COUNT 0x0A +#define CEATA_LBA_LOW 0x0B +#define CEATA_LBA_MID 0x0C +#define CEATA_LBA_HIGH 0x0D +#define CEATA_DEVICE_HEAD 0x0E +#define CEATA_COMMAND_STATUS 0x0F + +//CEATA command arguments to write to taskfile at COMMAND_STATUS(0x0F) +#define CEATA_READ_DMA_EXT 0x25 +#define CEATA_WRITE_DMA_EXT 0x35 +#define CEATA_STAND_BY_IMMEDIATE 0xE0 +#define CEATA_FLUSH_CACHE_EXT 0xEA +#define CEATA_IDENTIFY_DATA 0xEC + + +//CEATA taskfile file value at the status field(0x0F) +#define BSY 0x80 +#define ATA_ERROR 0x01 + +#endif +#endif + +/* + MMC status in R1 + Type + e : error bit + s : status bit + r : detected and set for the actual command response + x : detected and set during command execution. the host must poll + the card by sending status command in order to read these bits. + Clear condition + a : according to the card state + b : always related to the previous command. Reception of + a valid command will clear it (with a delay of one command) + c : clear by read + */ + +#define R1_OUT_OF_RANGE (1 << 31) /* er, c */ +#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */ +#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */ +#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ +#define R1_ERASE_PARAM (1 << 27) /* ex, c */ +#define R1_WP_VIOLATION (1 << 26) /* erx, c */ +#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ +#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ +#define R1_COM_CRC_ERROR (1 << 23) /* er, b */ +#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ +#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */ +#define R1_CC_ERROR (1 << 20) /* erx, c */ +#define R1_ERROR (1 << 19) /* erx, c */ +#define R1_UNDERRUN (1 << 18) /* ex, c */ +#define R1_OVERRUN (1 << 17) /* ex, c */ +#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */ +#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ +#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a, must be set 0 to MMC4.0 */ +#define R1_ERASE_RESET (1 << 13) /* sr, c */ + +#define R1_STATUS(x) (x & 0xFFFFE000) + +#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_READY_FOR_DATA (1 << 8) /* sx, a */ +#define R1_SWITCH_ERROR (1 << 7) /* E, X */ +#define R1_APP_CMD (1 << 5) /* sr, c */ + +#define MMC_SLOT_RCA(slot) (slot->id + 1) /* map the slot id to rca */ +enum mmc_status_error { + MMC_ERROR_NONE = 0, + MMC_ERROR_OUT_OF_RANGE, + MMC_ERROR_ADDRESS, + MMC_ERROR_BLOCK_LEN, + MMC_ERROR_ERASE_SEQ, + MMC_ERROR_ERASE_PARAM, + MMC_ERROR_WP_VIOLATION, + MMC_ERROR_CARD_IS_LOCKED, + MMC_ERROR_LOCK_UNLOCK_FAILED, + MMC_ERROR_COM_CRC, + MMC_ERROR_ILLEGAL_COMMAND, /* 10 */ + MMC_ERROR_CARD_ECC_FAILED, + MMC_ERROR_CC, + MMC_ERROR_GENERAL, + MMC_ERROR_UNDERRUN, + MMC_ERROR_OVERRUN, + MMC_ERROR_CID_CSD_OVERWRITE, + MMC_ERROR_STATE_MISMATCH, + MMC_ERROR_HEADER_MISMATCH, +}; + +enum card_state { + CARD_STATE_EMPTY = -1, + CARD_STATE_IDLE = 0, + CARD_STATE_READY = 1, + CARD_STATE_IDENT = 2, + CARD_STATE_STBY = 3, + CARD_STATE_TRAN = 4, + CARD_STATE_DATA = 5, + CARD_STATE_RCV = 6, + CARD_STATE_PRG = 7, + CARD_STATE_DIS = 8, + CARD_STATE_BTST = 9 +}; + +/* These are unpacked versions of the actual responses */ + +struct mmc_response_r1 { + u8 cmd; + u32 status; +}; + +struct mmc_cid { + u8 mid; + u16 oid; + u8 pnm[7]; /* Product name (we null-terminate) */ + u8 prv; + u32 psn; + u8 mdt; +}; + +struct mmc_csd { + u8 csd_structure; +#define CSD_STRUCT_1_0 0 /* Valid for system specification 1.0 - 1.2 */ +#define CSD_STRUCT_1_1 1 /* Valid for system specification 1.4 - 2.2 */ +#define CSD_STRUCT_1_2 2 /* Valid for system specification 3.1 */ + + u8 spec_vers; +#define CSD_SPEC_VERS_0 0 /* Implements system specification 1.0 - 1.2 */ +#define CSD_SPEC_VERS_1 1 /* Implements system specification 1.4 */ +#define CSD_SPEC_VERS_2 2 /* Implements system specification 2.0 - 2.2 */ +#define CSD_SPEC_VERS_3 3 /* Implements system specification 3.1 */ +#define CSD_SPEC_VERS_4 4 /* Implements system specification 4.0 - 4.2 */ + + u8 taac; + u8 nsac; + u8 tran_speed; + u16 ccc; + u8 read_bl_len; + u8 read_bl_partial; + u8 write_blk_misalign; + u8 read_blk_misalign; + u8 dsr_imp; + u16 c_size; + u8 vdd_r_curr_min; + u8 vdd_r_curr_max; + u8 vdd_w_curr_min; + u8 vdd_w_curr_max; + u8 c_size_mult; + union { + struct { /* MMC system specification version 3.1 */ + u8 erase_grp_size; + u8 erase_grp_mult; + } v31; + struct { /* MMC system specification version 2.2 */ + u8 sector_size; + u8 erase_grp_size; + } v22; + } erase; + u8 wp_grp_size; + u8 wp_grp_enable; + u8 default_ecc; + u8 r2w_factor; + u8 write_bl_len; + u8 write_bl_partial; + u8 file_format_grp; + u8 copy; + u8 perm_write_protect; + u8 tmp_write_protect; + u8 file_format; + u8 ecc; +}; + +struct mmc_ext_csd { + u8 s_cmd_set; + u8 sec_count; + u8 min_perf_w_8_52; + u8 min_perf_r_8_52; + u8 min_perf_w_26_4_52; + u8 min_perf_r_26_4_52; + u8 min_perf_w_4_26; + u8 min_perf_r_4_26; + u8 pwr_cl_26_360; + u8 pwr_cl_52_360; + u8 pwr_cl_26_195; + u8 pwr_cl_52_195; + u8 card_type; + u8 csd_structure; + u8 ext_csd_rev; + u8 cmd_set; + u8 cmd_set_rev; + u8 power_class; + u8 hs_timing; + u8 erased_mem_cont; +}; + +struct mmc_response_r3 { + u8 cmd; + u32 ocr; +#define MMC_ACCESS_MODE_MASK (0x3 << 29) /* mask to acess mode */ +#define MMC_ACCESS_MODE_SECTOR (0x2 << 29) /* sector access mode */ +#define MMC_ACCESS_MODE_BYTE (0x0 << 29) /* byte access mode */ +#define MMC_CARD_BUSY (1 << 31) /* Card Power up status bit */ +#define MMC_VDD_MASK (0xffff1 << 7) +}; + +struct mmc_response_r4 { /*Fast I/O */ + u8 cmd; + u16 rca; + u8 status; + u8 reg_addr; + u8 read_reg_contents; +}; + +struct mmc_response_r5 { /*Interrupt request */ + u8 cmd; + u16 rca; + u16 irq_data; +}; + +struct mmc_card { + struct mmc_cid cid; + struct mmc_csd csd; + struct mmc_ext_csd ext_csd; + /* The mmc card property */ + u32 vdd:24, + high_speed:2, + access_mode:2, + bus_width:4; + char *buf; + struct mss_ll_request llreq; + struct mss_cmd cmd; + struct mss_data data; + enum mmc_status_error errno; + enum card_state state; /* empty, ident, ready, whatever */ + u32 block_len; + u16 rca; +}; + +#endif /* end __MMC_PROTOCOL_H__ */ --- linux-2.6.24.orig/include/linux/mmc/mss_core.h +++ linux-2.6.24/include/linux/mmc/mss_core.h @@ -0,0 +1,437 @@ +/* + * mss_core.h - MMC/SD/SDIO Core driver header file + * + * Copyright (C) 2007 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 only + * for now as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * derived from previous mmc code in Linux kernel + * Copyright (c) 2002 Hewlett-Packard Company + * Copyright (c) 2002 Andrew Christian + * Copyright (c) 2006 Bridge Wu + */ + + +#ifndef __MSS_CORE_H__ +#define __MSS_CORE_H__ + +#include +#include + +/* MSS Core general results */ +enum mss_result { + MSS_ERROR_NONE = 0, + MSS_ERROR_NO_PROTOCOL = 1, + MSS_ERROR_REGISTER_CARD, + MSS_ERROR_MISMATCH_CARD, + MSS_ERROR_WRONG_CARD_TYPE, + MSS_ERROR_CARD_REMOVING, + MSS_ERROR_RESP_UNPACK, + MSS_ERROR_CRC, + MSS_ERROR_FLASH, + MSS_ERROR_TIMEOUT, + MSS_ERROR_LOCKED, + MSS_ERROR_WP, + MSS_ERROR_ACTION_UNSUPPORTED, + MSS_ERROR_DMA, + MSS_ERROR_WRONG_ARG, +}; + +#define MSS_MAX_RESPONSE_SIZE 18 +//#define MSS_SECTOR_SIZE 512 + +/** + * enum mss_rsp_type: MMC/SD/SDIO command response type. + * + * This is used by both protocol and controller to set MMC/SD/SDIO controller + * according to command response type. This is related to MMC/SD/SDIO + * protocol, also to MMC/SD/SDIO controller. So it is placed in core layer, + * rather than in protocol layer or controller layer. + */ +enum mss_rsp_type { + MSS_RESPONSE_NONE = 0, + MSS_RESPONSE_R1 = 1, + MSS_RESPONSE_R1B = 10, + MSS_RESPONSE_R2_CID = 2, + MSS_RESPONSE_R2_CSD = 20, + MSS_RESPONSE_R3 = 3, + MSS_RESPONSE_R4 = 4, + MSS_RESPONSE_R5 = 5, + MSS_RESPONSE_R6 = 6, + MSS_RESPONSE_R7 = 7, +}; + +enum mss_card_type { + MSS_UNKNOWN_CARD = 0, + MSS_MMC_CARD = 1, + MSS_CEATA, + MSS_SD_CARD , + MSS_SDIO_CARD , + MSS_COMBO_CARD , + MSS_UNCOMPATIBLE_CARD, +}; + +struct mss_request { + struct mss_card *card; /* Card */ + int action; /* what kind of request */ +/* MSS general action in prot_entry() */ +#define MSS_ACTION_BASE 0x80 +#define MSS_ACTION_PRIVATE 0x100 + +#define MSS_RECOGNIZE_CARD (MSS_ACTION_BASE + 1) +#define MSS_INIT_CARD (MSS_ACTION_BASE + 2) +#define MSS_READ_MEM (MSS_ACTION_BASE + 3) +#define MSS_WRITE_MEM (MSS_ACTION_BASE + 4) +#define MSS_LOCK_CARD (MSS_ACTION_BASE + 5) +#define MSS_UNLOCK_CARD (MSS_ACTION_BASE + 6) +#define MSS_QUERY_CARD (MSS_ACTION_BASE + 7) +#define MSS_GET_CAPACITY (MSS_ACTION_BASE + 8) + + int errno; /* protocl specific error */ + void *arg; /* argumnets for request */ + void *result; /* the request results */ +}; + +struct mss_rw_arg { + u32 block; /* Start block address, for sdio, reg addr */ + u32 nob; /* Length of block for read/write */ + u32 block_len; /* Size of block (sanity check) */ + unsigned int sg_len; + struct scatterlist *sg; + u8 func; /* for sdio */ + u8 opcode; /* for sdio */ + u8 val; /* for sdio */ +}; + +struct mss_rw_result { + u32 bytes_xfered; +}; + +struct mss_cmd { + u32 opcode; /* command opcode */ + u32 arg; /* arguments */ + u8 response[MSS_MAX_RESPONSE_SIZE]; /* Response of the command */ + u32 flags; /* Specail flags for command */ +/* + * Some controller needs know some special command. + * MSS_CMD_INIT: It is the first command after card is reset, and controller + * may need precede command with some MMC CLKs + * MSS_CMD_STOP: It is the command that need stop the cuurent data transmission. + * MSS_CMD_SDIO_EN: The command is sent with the effect that sdio interrupt is + * enabled in the controller. + */ +#define MSS_CMD_INIT (1 << 0) +#define MSS_CMD_STOP (1 << 1) +#define MSS_CMD_SDIO_EN (1 << 2) + + u32 rtype; /* response type */ + u32 error; + struct mss_ll_request *llreq; + struct mss_data *data; +}; + +#define MSS_INIT_CMD(cmd, c_opcode, c_arg, c_flags, c_rtype) \ + do { \ + (cmd)->opcode = c_opcode; \ + (cmd)->arg = c_arg; \ + (cmd)->flags = c_flags; \ + (cmd)->rtype = c_rtype; \ + } while (0) + +struct mss_data { + u32 timeout_ns; /* data time out in ns */ + u32 blocks; /* number of block */ + u32 blksz; /* block lenght */ + u32 flags; +#define MSS_DATA_WRITE (1 << 0) +#define MSS_DATA_READ (1 << 1) +#define MSS_DATA_STREAM (1 << 2) +#define MSS_DATA_MULTI (1 << 3) + + unsigned int sg_len; + struct scatterlist *sg; + unsigned int bytes_xfered; +}; + +#define MSS_INIT_DATA(data, d_nob, d_block_len, d_flags, d_sg_len, d_sg, \ + d_timeout_ns) \ + do { \ + (data)->timeout_ns = d_timeout_ns; \ + (data)->blocks = d_nob; \ + (data)->blksz = d_block_len; \ + (data)->flags = d_flags; \ + (data)->sg_len = d_sg_len; \ + (data)->sg = d_sg; \ + } while(0) + +struct mss_ll_request { + struct mss_cmd *cmd; + struct mss_data *data; + + void *done_data; + void (*done)(struct mss_ll_request *); +}; + +struct mss_card { + u32 card_type; /* MMC or SD or SDIO */ + u32 state; /* card states */ +/* + * Card can be in several states, such as when card is suspended, the states + * may be MSS_CARD_IDENTIFIED | MSS_CARD_SUSPEND. + * The states is from the top view, it is diffrent with the states defined in + * the protocol. + */ +#define MSS_CARD_REGISTERED (0x1 << 1) +#define MSS_CARD_REMOVING (0x1 << 2) +#define MSS_CARD_HANDLEIO (0x1 << 3) +#define MSS_CARD_SUSPENDED (0x1 << 4) +#define MSS_CARD_WP (0x1 << 5) +#define MSS_CARD_INVALID (0x1 << 6) + + void *prot_card; /* point to specific protocl card structure */ + struct mss_prot_driver *prot_driver; /* protocol driver */ + + u32 usage; + u32 bus_width; /* 1-bit or 4-bit or 8-bit bus width */ + + struct mss_slot *slot; /* in which slot ? */ + struct device dev; /* device on mmc_bus */ +}; + +struct mss_driver { + struct device_driver driver; /* driver on mmc_bus */ + void (*sdio_int_handler)(struct mss_card *); + void (*request_done)(struct mss_request *); +}; + +struct mss_slot { + /* point to real card if inserted, else NULL */ + struct mss_card *card; + struct mss_host *host; /* point to controller */ + u32 id; /* slot is, start from 0 */ + + struct delayed_work card_detect; + void *private; +}; + +struct mss_ios { + u32 clock; /* current controller clock */ + u32 bus_width:4, /* current bus width */ +#define MSS_BUSWIDTH_1BIT 0 +#define MSS_BUSWIDTH_4BIT 1 +#define MSS_BUSWIDTH_8BIT 2 + access_mode:2, +#define MSS_ACCESS_MODE_BYTE 0 +#define MSS_ACCESS_MODE_SECTOR 2 + + high_speed:2, +#define MSS_HIGH_SPEED 1 + + bus_mode:2, /* current bus mode */ +#define MSS_BUSMODE_OPENDRAIN 1 +#define MSS_BUSMODE_PUSHPULL 2 + + chip_select:2, +#define MSS_CS_NO_CARE 0 +#define MSS_CS_HIGH 1 +#define MSS_CS_LOW 2 + + power_mode:2, +#define MSS_POWER_OFF 1 +#define MSS_POWER_UP 2 +#define MSS_POWER_ON 3 + sdio_int:2; +#define MSS_SDIO_INT_DIS 0 +#define MSS_SDIO_INT_EN 1 + + u32 vdd; +}; + +/* Host operations */ +struct mss_host_ops { + void (*request)(struct mss_host *, struct mss_ll_request *); + void (*set_ios)(struct mss_host *, struct mss_ios *); + /* optioanl operations */ + int (*is_slot_empty)(struct mss_slot *); /* slot empty? */ + int (*is_slot_wp)(struct mss_slot *); /* write-protected ? */ +}; + +struct mss_host { + struct list_head node; /* list all controllers */ + struct mss_card *active_card; /* pointer to active slot */ + unsigned int slot_num; /* slots number of controller */ + unsigned int id; /* controller id */ + wait_queue_head_t wq; /* wait queue for host claim */ + unsigned int max_seg_size; + unsigned int max_hw_segs; + unsigned int max_phys_segs; + unsigned int max_sectors; + spinlock_t lock; + void *private; + struct device *dev; + + u32 f_min; /* min clock supported */ + u32 f_max; /* max clock supported */ + u32 vdd: 24, /* support VDD */ +#define MSS_VDD_170_195 (1 << 7) /* VDD voltage 1.45 - 1.50 */ +#define MSS_VDD_20_21 (1 << 8) /* VDD voltage 2.0 ~ 2.1 */ +#define MSS_VDD_21_22 (1 << 9) /* VDD voltage 2.1 ~ 2.2 */ +#define MSS_VDD_22_23 (1 << 10) /* VDD voltage 2.2 ~ 2.3 */ +#define MSS_VDD_23_24 (1 << 11) /* VDD voltage 2.3 ~ 2.4 */ +#define MSS_VDD_24_25 (1 << 12) /* VDD voltage 2.4 ~ 2.5 */ +#define MSS_VDD_25_26 (1 << 13) /* VDD voltage 2.5 ~ 2.6 */ +#define MSS_VDD_26_27 (1 << 14) /* VDD voltage 2.6 ~ 2.7 */ +#define MSS_VDD_27_28 (1 << 15) /* VDD voltage 2.7 ~ 2.8 */ +#define MSS_VDD_28_29 (1 << 16) /* VDD voltage 2.8 ~ 2.9 */ +#define MSS_VDD_29_30 (1 << 17) /* VDD voltage 2.9 ~ 3.0 */ +#define MSS_VDD_30_31 (1 << 18) /* VDD voltage 3.0 ~ 3.1 */ +#define MSS_VDD_31_32 (1 << 19) /* VDD voltage 3.1 ~ 3.2 */ +#define MSS_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */ +#define MSS_VDD_33_34 (1 << 21) /* VDD voltage 3.3 ~ 3.4 */ +#define MSS_VDD_34_35 (1 << 22) /* VDD voltage 3.4 ~ 3.5 */ +#define MSS_VDD_35_36 (1 << 23) /* VDD voltage 3.5 ~ 3.6 */ + +#define MSS_VDD_20_26 (0x3f << 8) /* VDD voltage 2.0 to 2.6 */ +#define MSS_VDD_27_36 (0x1ff << 15) /* VDD voltage 2.7 to 3.6 */ +#define MSS_VDD_MASK (0xffff1 << 7) + + bus_width:4; /* Support max bus width */ + u32 sd_spec:8, + mmc_spec:8, + sdio_spec:8, + high_capacity:1, + high_speed:1; +#define MSS_SD_SPEC_NONE 0 +#define MSS_SD_SPEC_10 1 +#define MSS_SD_SPEC_11 2 +#define MSS_SD_SPEC_20 3 +#define MSS_MMC_SPEC_NONE 0 /* Do not support */ +#define MSS_MMC_SPEC_11_12 1 /* MMC specification 1.1 - 1.2 */ +#define MSS_MMC_SPEC_14 2 /* MMC specification 1.4 */ +#define MSS_MMC_SPEC_20_22 3 /* MMC specification 2.0 - 2.2 */ +#define MSS_MMC_SPEC_31 4 /* MMC specification 3.1 */ +#define MSS_MMC_SPEC_40_42 5 /* MMC specification 4.0 - 4.2 */ +#define MSS_SDIO_SPEC_NONE 0 +#define MSS_SDIO_SPEC_10 1 +#define MSS_SDIO_SPEC_11 2 + + struct mss_ios ios; + struct mss_host_ops *ops; + struct mss_slot slots[0]; +}; + +struct mss_prot_driver { + char *name; /* protocol name */ + struct list_head node; + + int (*prot_entry)(struct mss_card *, unsigned int, void *, void *); + int (*attach_card) (struct mss_card *); + void (*detach_card) (struct mss_card *); + int (*get_errno) (struct mss_card *); +}; + +static inline u32 unstuff_bits(u8 *resp, u32 start, u32 size, u32 bytes) +{ + u32 _end = bytes - (start / 8) - 1; + u32 _start = bytes - ((start + size - 1) / 8) - 1; + u8 shft = start % 8; + u32 mask = (1 << (((start + size) % 8) ? ((start + size) % 8) : 8)) - 1; + u32 res = 0; + + while (1) { + res = res << 8; + res |= resp[_start]; + if (_end != _start) + _start++; + else + break; + mask = mask << 8 | 0xFF; + } + res = (res & mask) >> shft; + + return res; +} + +/* to controller driver */ +void mss_detect_change(struct mss_host *, unsigned long delay, unsigned int); +int mss_scan_slot(struct work_struct *work); +void mss_scan_host(struct mss_host *); +struct mss_host * mss_alloc_host(unsigned int , unsigned int , unsigned int ); +void mss_free_host(struct mss_host *); +struct mss_host *mss_find_host(int ); +void mss_force_card_remove(struct mss_card *); +int register_mss_host(struct mss_host *); +void unregister_mss_host(struct mss_host *); + +/* to card driver */ +int register_mss_driver (struct mss_driver *); +void unregister_mss_driver (struct mss_driver *); +int mss_send_request(struct mss_request *); +unsigned int mss_get_capacity(struct mss_card *); +int mss_card_get(struct mss_card *); +void mss_card_put(struct mss_card *); + +/* to protocol driver */ +int register_mss_prot_driver(struct mss_prot_driver *); +void unregister_mss_prot_driver(struct mss_prot_driver *); +int mss_send_ll_req(struct mss_host *, struct mss_ll_request *); +int mss_send_simple_ll_req(struct mss_host *, struct mss_ll_request *, struct mss_cmd *, u32 , u32 , u32 , u32 ); +void mss_set_sdio_int(struct mss_host *, int ); +void mss_set_buswidth(struct mss_host *, int ); +void mss_set_busmode(struct mss_host *, int ); +void mss_set_clock(struct mss_host *, int ); + +#ifdef CONFIG_MMC_DEBUG +/* debug for mss_core */ +#define dbg(slot, format, arg...) \ + do { \ + printk(KERN_INFO "%s(): host%u slot%u, " \ + format "\n", __func__, \ + (slot)->host->id, (slot)->id, ##arg); \ + } while(0) + +/* +#define dbg(format, arg...) \ + do { \ + printk(KERN_INFO "%s(): " format "\n", \ + __func__, ##arg); \ + } while(0) + +*/ +/* debug for protocol */ +#define dbg2(slot, prot, format, arg...) printk(KERN_INFO "%s(): " \ + "host%u slot%u prot%s, " format "\n", __func__, \ + slot?slot->host->id:-1, slot?slot->id:-1, \ + prot?prot->name:"NULL", ##arg) + +/* debug for hw */ +#define dbg4(slot, format, arg...) do { \ + printk(KERN_INFO "%s(): ", __func__); \ + if (slot) \ + printk(KERN_INFO "host%u slot%u , ", slot->host->id, \ + slot->id); \ + printk(KERN_INFO format "\n", ##arg); \ + } while(0) + +#define dbg5(format, arg...) printk(KERN_INFO "%s(): " format "\n", __func__, ##arg) + +#else +#define dbg(slot, format, arg...) +#define dbg2(slot, prot, format, arg...) +#define dbg4(slot, format, arg...) +#define dbg5(format, arg...) +#endif +#endif --- linux-2.6.24.orig/include/linux/virtio_net.h +++ linux-2.6.24/include/linux/virtio_net.h @@ -5,32 +5,32 @@ /* The ID for virtio_net */ #define VIRTIO_ID_NET 1 -/* The bitmap of config for virtio net */ -#define VIRTIO_CONFIG_NET_F 0x40 -#define VIRTIO_NET_F_NO_CSUM 0 -#define VIRTIO_NET_F_TSO4 1 -#define VIRTIO_NET_F_UFO 2 -#define VIRTIO_NET_F_TSO4_ECN 3 -#define VIRTIO_NET_F_TSO6 4 +/* The feature bitmap for virtio net */ +#define VIRTIO_NET_F_CSUM 0 /* Can handle pkts w/ partial csum */ +#define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */ +#define VIRTIO_NET_F_GSO 6 /* Can handle pkts w/ any GSO type */ -/* The config defining mac address. */ -#define VIRTIO_CONFIG_NET_MAC_F 0x41 +struct virtio_net_config +{ + /* The config defining mac address (if VIRTIO_NET_F_MAC) */ + __u8 mac[6]; +} __attribute__((packed)); /* This is the first element of the scatter-gather list. If you don't * specify GSO or CSUM features, you can simply ignore the header. */ struct virtio_net_hdr { #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset - __u8 flags; + __u8 flags; #define VIRTIO_NET_HDR_GSO_NONE 0 // Not a GSO frame #define VIRTIO_NET_HDR_GSO_TCPV4 1 // GSO frame, IPv4 TCP (TSO) -/* FIXME: Do we need this? If they said they can handle ECN, do they care? */ -#define VIRTIO_NET_HDR_GSO_TCPV4_ECN 2 // GSO frame, IPv4 TCP w/ ECN #define VIRTIO_NET_HDR_GSO_UDP 3 // GSO frame, IPv4 UDP (UFO) #define VIRTIO_NET_HDR_GSO_TCPV6 4 // GSO frame, IPv6 TCP - __u8 gso_type; - __u16 gso_size; - __u16 csum_start; - __u16 csum_offset; +#define VIRTIO_NET_HDR_GSO_ECN 0x80 // TCP has ECN set + __u8 gso_type; + __u16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */ + __u16 gso_size; /* Bytes to append to gso_hdr_len per frame */ + __u16 csum_start; /* Position to start checksumming from */ + __u16 csum_offset; /* Offset after that to place checksum */ }; #endif /* _LINUX_VIRTIO_NET_H */ --- linux-2.6.24.orig/include/linux/mount.h +++ linux-2.6.24/include/linux/mount.h @@ -103,5 +103,10 @@ extern spinlock_t vfsmount_lock; extern dev_t name_to_dev_t(char *name); +extern char *d_namespace_path(struct dentry *, struct vfsmount *, char *, int); + +extern int default_relatime; +extern int relatime_interval; + #endif #endif /* _LINUX_MOUNT_H */ --- linux-2.6.24.orig/include/linux/netfilter_ipv6/Kbuild +++ linux-2.6.24/include/linux/netfilter_ipv6/Kbuild @@ -11,6 +11,7 @@ header-y += ip6t_limit.h header-y += ip6t_mac.h header-y += ip6t_mark.h +header-y += ip6t_mh.h header-y += ip6t_multiport.h header-y += ip6t_opts.h header-y += ip6t_owner.h --- linux-2.6.24.orig/include/linux/ssb/ssb_regs.h +++ linux-2.6.24/include/linux/ssb/ssb_regs.h @@ -147,6 +147,10 @@ #define SSB_IDLOW_SSBREV 0xF0000000 /* Sonics Backplane Revision code */ #define SSB_IDLOW_SSBREV_22 0x00000000 /* <= 2.2 */ #define SSB_IDLOW_SSBREV_23 0x10000000 /* 2.3 */ +#define SSB_IDLOW_SSBREV_24 0x40000000 /* ?? Found in BCM4328 */ +#define SSB_IDLOW_SSBREV_25 0x50000000 /* ?? Not Found yet */ +#define SSB_IDLOW_SSBREV_26 0x60000000 /* ?? Found in some BCM4311/2 */ +#define SSB_IDLOW_SSBREV_27 0x70000000 /* ?? Found in some BCM4311/2 */ #define SSB_IDHIGH 0x0FFC /* SB Identification High */ #define SSB_IDHIGH_RCLO 0x0000000F /* Revision Code (low part) */ #define SSB_IDHIGH_CC 0x00008FF0 /* Core Code */ --- linux-2.6.24.orig/include/linux/dcache.h +++ linux-2.6.24/include/linux/dcache.h @@ -300,6 +300,8 @@ */ extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); +extern char *__d_path(struct dentry *, struct vfsmount *, struct dentry *, + struct vfsmount *, char *, int, int); extern char * d_path(struct dentry *, struct vfsmount *, char *, int); /* Allocation counts.. */ --- linux-2.6.24.orig/include/linux/usb/quirks.h +++ linux-2.6.24/include/linux/usb/quirks.h @@ -9,3 +9,6 @@ /* device can't resume correctly so reset it instead */ #define USB_QUIRK_RESET_RESUME 0x00000002 + +/* device can't handle Set-Interface requests */ +#define USB_QUIRK_NO_SET_INTF 0x00000004 --- linux-2.6.24.orig/include/linux/ethtool.h +++ linux-2.6.24/include/linux/ethtool.h @@ -12,6 +12,7 @@ #ifndef _LINUX_ETHTOOL_H #define _LINUX_ETHTOOL_H +#include /* This should work for both 32 and 64 bit userland. */ struct ethtool_cmd { --- linux-2.6.24.orig/include/linux/wireless.h +++ linux-2.6.24/include/linux/wireless.h @@ -541,6 +541,16 @@ /* Maximum size of returned data */ #define IW_SCAN_MAX_DATA 4096 /* In bytes */ +/* Scan capability flags - in (struct iw_range *)->scan_capa */ +#define IW_SCAN_CAPA_NONE 0x00 +#define IW_SCAN_CAPA_ESSID 0x01 +#define IW_SCAN_CAPA_BSSID 0x02 +#define IW_SCAN_CAPA_CHANNEL 0x04 +#define IW_SCAN_CAPA_MODE 0x08 +#define IW_SCAN_CAPA_RATE 0x10 +#define IW_SCAN_CAPA_TYPE 0x20 +#define IW_SCAN_CAPA_TIME 0x40 + /* Max number of char in custom event - use multiple of them if needed */ #define IW_CUSTOM_MAX 256 /* In bytes */ @@ -963,6 +973,9 @@ __u16 old_num_channels; __u8 old_num_frequency; + /* Scan capabilities */ + __u8 scan_capa; /* IW_SCAN_CAPA_* bit field */ + /* Wireless event capability bitmasks */ __u32 event_capa[6]; --- linux-2.6.24.orig/include/linux/ktime.h +++ linux-2.6.24/include/linux/ktime.h @@ -310,6 +310,8 @@ return ktime_sub_ns(kt, usec * 1000); } +extern ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs); + /* * The resolution of the clocks. The resolution value is returned in * the clock_getres() system call to give application programmers an --- linux-2.6.24.orig/include/linux/delay.h +++ linux-2.6.24/include/linux/delay.h @@ -35,6 +35,7 @@ #define ndelay(x) udelay(((x)+999)/1000) #endif +extern unsigned long lpj_tsc; void calibrate_delay(void); void msleep(unsigned int msecs); unsigned long msleep_interruptible(unsigned int msecs); --- linux-2.6.24.orig/include/linux/netfilter/Kbuild +++ linux-2.6.24/include/linux/netfilter/Kbuild @@ -28,6 +28,7 @@ header-y += xt_multiport.h header-y += xt_pkttype.h header-y += xt_policy.h +header-y += xt_quota.h header-y += xt_realm.h header-y += xt_sctp.h header-y += xt_state.h --- linux-2.6.24.orig/include/linux/pm.h +++ linux-2.6.24/include/linux/pm.h @@ -143,6 +143,9 @@ * the upcoming system state (such as PCI_D3hot), and enable * wakeup events as appropriate. * + * HIBERNATE Enter a low power device state appropriate for the hibernation + * state (eg. ACPI S4) and enable wakeup events as appropriate. + * * FREEZE Quiesce operations so that a consistent image can be saved; * but do NOT otherwise enter a low power device state, and do * NOT emit system wakeup events. @@ -166,11 +169,15 @@ #define PM_EVENT_ON 0 #define PM_EVENT_FREEZE 1 #define PM_EVENT_SUSPEND 2 -#define PM_EVENT_PRETHAW 3 +#define PM_EVENT_HIBERNATE 4 +#define PM_EVENT_PRETHAW 8 + +#define PM_EVENT_SLEEP (PM_EVENT_SUSPEND | PM_EVENT_HIBERNATE) #define PMSG_FREEZE ((struct pm_message){ .event = PM_EVENT_FREEZE, }) #define PMSG_PRETHAW ((struct pm_message){ .event = PM_EVENT_PRETHAW, }) #define PMSG_SUSPEND ((struct pm_message){ .event = PM_EVENT_SUSPEND, }) +#define PMSG_HIBERNATE ((struct pm_message){ .event = PM_EVENT_HIBERNATE, }) #define PMSG_ON ((struct pm_message){ .event = PM_EVENT_ON, }) struct dev_pm_info { --- linux-2.6.24.orig/include/linux/xattr.h +++ linux-2.6.24/include/linux/xattr.h @@ -46,10 +46,13 @@ size_t size, int flags); }; -ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t); -ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size); -int vfs_setxattr(struct dentry *, char *, void *, size_t, int); -int vfs_removexattr(struct dentry *, char *); +ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, char *, void *, + size_t, struct file *); +ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list, + size_t size, struct file *); +int vfs_setxattr(struct dentry *, struct vfsmount *, char *, void *, size_t, + int, struct file *); +int vfs_removexattr(struct dentry *, struct vfsmount *, char *, struct file *); ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size); ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); --- linux-2.6.24.orig/include/linux/splice.h +++ linux-2.6.24/include/linux/splice.h @@ -70,4 +70,10 @@ extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, splice_direct_actor *); +extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags); +extern long do_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags); + #endif --- linux-2.6.24.orig/include/linux/virtio_pci.h +++ linux-2.6.24/include/linux/virtio_pci.h @@ -0,0 +1,57 @@ +/* + * Virtio PCI driver + * + * This module allows virtio devices to be used over a virtual PCI device. + * This can be used with QEMU based VMMs like KVM or Xen. + * + * Copyright IBM Corp. 2007 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef _LINUX_VIRTIO_PCI_H +#define _LINUX_VIRTIO_PCI_H + +#include + +/* A 32-bit r/o bitmask of the features supported by the host */ +#define VIRTIO_PCI_HOST_FEATURES 0 + +/* A 32-bit r/w bitmask of features activated by the guest */ +#define VIRTIO_PCI_GUEST_FEATURES 4 + +/* A 32-bit r/w PFN for the currently selected queue */ +#define VIRTIO_PCI_QUEUE_PFN 8 + +/* A 16-bit r/o queue size for the currently selected queue */ +#define VIRTIO_PCI_QUEUE_NUM 12 + +/* A 16-bit r/w queue selector */ +#define VIRTIO_PCI_QUEUE_SEL 14 + +/* A 16-bit r/w queue notifier */ +#define VIRTIO_PCI_QUEUE_NOTIFY 16 + +/* An 8-bit device status register. */ +#define VIRTIO_PCI_STATUS 18 + +/* An 8-bit r/o interrupt status register. Reading the value will return the + * current contents of the ISR and will also clear it. This is effectively + * a read-and-acknowledge. */ +#define VIRTIO_PCI_ISR 19 + +/* The bit of the ISR which indicates a device configuration change. */ +#define VIRTIO_PCI_ISR_CONFIG 0x2 + +/* The remaining space is defined by each driver as the per-driver + * configuration space */ +#define VIRTIO_PCI_CONFIG 20 + +/* Virtio ABI version, this must match exactly */ +#define VIRTIO_PCI_ABI_VERSION 0 +#endif --- linux-2.6.24.orig/include/linux/input.h +++ linux-2.6.24/include/linux/input.h @@ -371,6 +371,8 @@ #define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */ #define KEY_DISPLAY_OFF 245 /* display device to off state */ +#define KEY_WIMAX 246 + #define BTN_MISC 0x100 #define BTN_0 0x100 #define BTN_1 0x101 --- linux-2.6.24.orig/include/linux/kvm_para.h +++ linux-2.6.24/include/linux/kvm_para.h @@ -2,72 +2,31 @@ #define __LINUX_KVM_PARA_H /* - * Guest OS interface for KVM paravirtualization - * - * Note: this interface is totally experimental, and is certain to change - * as we make progress. + * This header file provides a method for making a hypercall to the host + * Architectures should define: + * - kvm_hypercall0, kvm_hypercall1... + * - kvm_arch_para_features + * - kvm_para_available */ -/* - * Per-VCPU descriptor area shared between guest and host. Writable to - * both guest and host. Registered with the host by the guest when - * a guest acknowledges paravirtual mode. - * - * NOTE: all addresses are guest-physical addresses (gpa), to make it - * easier for the hypervisor to map between the various addresses. - */ -struct kvm_vcpu_para_state { - /* - * API version information for compatibility. If there's any support - * mismatch (too old host trying to execute too new guest) then - * the host will deny entry into paravirtual mode. Any other - * combination (new host + old guest and new host + new guest) - * is supposed to work - new host versions will support all old - * guest API versions. - */ - u32 guest_version; - u32 host_version; - u32 size; - u32 ret; - - /* - * The address of the vm exit instruction (VMCALL or VMMCALL), - * which the host will patch according to the CPU model the - * VM runs on: - */ - u64 hypercall_gpa; - -} __attribute__ ((aligned(PAGE_SIZE))); +/* Return values for hypercalls */ +#define KVM_ENOSYS 1000 +#define KVM_EPERM EPERM -#define KVM_PARA_API_VERSION 1 +#define KVM_HC_VAPIC_POLL_IRQ 1 /* - * This is used for an RDMSR's ECX parameter to probe for a KVM host. - * Hopefully no CPU vendor will use up this number. This is placed well - * out of way of the typical space occupied by CPU vendors' MSR indices, - * and we think (or at least hope) it wont be occupied in the future - * either. + * hypercalls use architecture specific */ -#define MSR_KVM_API_MAGIC 0x87655678 +#include -#define KVM_EINVAL 1 - -/* - * Hypercall calling convention: - * - * Each hypercall may have 0-6 parameters. - * - * 64-bit hypercall index is in RAX, goes from 0 to __NR_hypercalls-1 - * - * 64-bit parameters 1-6 are in the standard gcc x86_64 calling convention - * order: RDI, RSI, RDX, RCX, R8, R9. - * - * 32-bit index is EBX, parameters are: EAX, ECX, EDX, ESI, EDI, EBP. - * (the first 3 are according to the gcc regparm calling convention) - * - * No registers are clobbered by the hypercall, except that the - * return value is in RAX. - */ -#define __NR_hypercalls 0 +#ifdef __KERNEL__ +static inline int kvm_para_has_feature(unsigned int feature) +{ + if (kvm_arch_para_features() & (1UL << feature)) + return 1; + return 0; +} +#endif /* __KERNEL__ */ +#endif /* __LINUX_KVM_PARA_H */ -#endif --- linux-2.6.24.orig/include/linux/virtio.h +++ linux-2.6.24/include/linux/virtio.h @@ -11,15 +11,13 @@ /** * virtqueue - a queue to register buffers for sending or receiving. * @callback: the function to call when buffers are consumed (can be NULL). - * If this returns false, callbacks are suppressed until vq_ops->restart - * is called. * @vdev: the virtio device this queue was created for. * @vq_ops: the operations for this virtqueue (see below). * @priv: a pointer for the virtqueue implementation to use. */ struct virtqueue { - bool (*callback)(struct virtqueue *vq); + void (*callback)(struct virtqueue *vq); struct virtio_device *vdev; struct virtqueue_ops *vq_ops; void *priv; @@ -41,16 +39,19 @@ * vq: the struct virtqueue we're talking about. * len: the length written into the buffer * Returns NULL or the "data" token handed to add_buf. - * @restart: restart callbacks after callback returned false. + * @disable_cb: disable callbacks * vq: the struct virtqueue we're talking about. - * This returns "false" (and doesn't re-enable) if there are pending - * buffers in the queue, to avoid a race. - * @shutdown: "unadd" all buffers. + * Note that this is not necessarily synchronous, hence unreliable and only + * useful as an optimization. + * @enable_cb: restart callbacks after disable_cb. * vq: the struct virtqueue we're talking about. - * Remove everything from the queue. + * This re-enables callbacks; it returns "false" if there are pending + * buffers in the queue, to detect a possible race between the driver + * checking for more work, and enabling callbacks. * * Locking rules are straightforward: the driver is responsible for - * locking. No two operations may be invoked simultaneously. + * locking. No two operations may be invoked simultaneously, with the exception + * of @disable_cb. * * All operations can be called in any context. */ @@ -65,9 +66,8 @@ void *(*get_buf)(struct virtqueue *vq, unsigned int *len); - bool (*restart)(struct virtqueue *vq); - - void (*shutdown)(struct virtqueue *vq); + void (*disable_cb)(struct virtqueue *vq); + bool (*enable_cb)(struct virtqueue *vq); }; /** @@ -97,12 +97,15 @@ * @probe: the function to call when a device is found. Returns a token for * remove, or PTR_ERR(). * @remove: the function when a device is removed. + * @config_changed: optional function to call when the device configuration + * changes; may be called in interrupt context. */ struct virtio_driver { struct device_driver driver; const struct virtio_device_id *id_table; int (*probe)(struct virtio_device *dev); void (*remove)(struct virtio_device *dev); + void (*config_changed)(struct virtio_device *dev); }; int register_virtio_driver(struct virtio_driver *drv); --- linux-2.6.24.orig/include/linux/fs.h +++ linux-2.6.24/include/linux/fs.h @@ -351,13 +351,6 @@ struct timespec ia_atime; struct timespec ia_mtime; struct timespec ia_ctime; - - /* - * Not an attribute, but an auxilary info for filesystems wanting to - * implement an ftruncate() like method. NOTE: filesystem should - * check for (ia_valid & ATTR_FILE), and not for (ia_file != NULL). - */ - struct file *ia_file; }; /* @@ -1068,13 +1061,13 @@ */ extern int vfs_permission(struct nameidata *, int); extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *); -extern int vfs_mkdir(struct inode *, struct dentry *, int); -extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t); -extern int vfs_symlink(struct inode *, struct dentry *, const char *, int); -extern int vfs_link(struct dentry *, struct inode *, struct dentry *); -extern int vfs_rmdir(struct inode *, struct dentry *); -extern int vfs_unlink(struct inode *, struct dentry *); -extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); +extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int); +extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t); +extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *, int); +extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *); +extern int vfs_rmdir(struct inode *, struct dentry *, struct vfsmount *); +extern int vfs_unlink(struct inode *, struct dentry *, struct vfsmount *); +extern int vfs_rename(struct inode *, struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *); /* * VFS dentry helper functions. @@ -1188,6 +1181,8 @@ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **); + int (*fgetattr)(struct file *, struct kstat *); + int (*fsetattr)(struct file *, struct iattr *); }; struct inode_operations { @@ -1536,8 +1531,8 @@ /* fs/open.c */ -extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, - struct file *filp); +extern int do_truncate(struct dentry *, struct vfsmount *, loff_t start, + unsigned int time_attrs, struct file *filp); extern long do_sys_open(int dfd, const char __user *filename, int flags, int mode); extern struct file *filp_open(const char *, int, int); @@ -1693,7 +1688,8 @@ #ifdef CONFIG_BLOCK extern sector_t bmap(struct inode *, sector_t); #endif -extern int notify_change(struct dentry *, struct iattr *); +extern int notify_change(struct dentry *, struct vfsmount *, struct iattr *); +extern int fnotify_change(struct dentry *, struct vfsmount *, struct iattr *, struct file *); extern int permission(struct inode *, int, struct nameidata *); extern int generic_permission(struct inode *, int, int (*check_acl)(struct inode *, int)); @@ -1766,9 +1762,9 @@ extern void clear_inode(struct inode *); extern void destroy_inode(struct inode *); extern struct inode *new_inode(struct super_block *); -extern int __remove_suid(struct dentry *, int); +extern int __remove_suid(struct path *, int); extern int should_remove_suid(struct dentry *); -extern int remove_suid(struct dentry *); +extern int remove_suid(struct path *); extern void __insert_inode_hash(struct inode *, unsigned long hashval); extern void remove_inode_hash(struct inode *); --- linux-2.6.24.orig/include/linux/blkdev.h +++ linux-2.6.24/include/linux/blkdev.h @@ -607,6 +607,7 @@ * default timeout for SG_IO if none specified */ #define BLK_DEFAULT_SG_TIMEOUT (60 * HZ) +#define BLK_MIN_SG_TIMEOUT (7 * HZ) #ifdef CONFIG_BOUNCE extern int init_emergency_isa_pool(void); --- linux-2.6.24.orig/include/linux/skbuff.h +++ linux-2.6.24/include/linux/skbuff.h @@ -1804,5 +1804,6 @@ skb->ip_summed = CHECKSUM_NONE; } +bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off); #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ --- linux-2.6.24.orig/include/linux/capability.h +++ linux-2.6.24/include/linux/capability.h @@ -121,7 +121,12 @@ /* Used to decide between falling back on the old suser() or fsuser(). */ -#define CAP_FS_MASK 0x1f +#define CAP_FS_MASK (CAP_TO_MASK(CAP_CHOWN) \ + | CAP_TO_MASK(CAP_MKNOD) \ + | CAP_TO_MASK(CAP_DAC_OVERRIDE) \ + | CAP_TO_MASK(CAP_DAC_READ_SEARCH) \ + | CAP_TO_MASK(CAP_FOWNER) \ + | CAP_TO_MASK(CAP_FSETID)) /* Overrides the restriction that the real or effective user ID of a process sending a signal must match the real or effective user ID --- linux-2.6.24.orig/include/linux/virtio_ring.h +++ linux-2.6.24/include/linux/virtio_ring.h @@ -15,9 +15,13 @@ /* This marks a buffer as write-only (otherwise read-only). */ #define VRING_DESC_F_WRITE 2 -/* This means don't notify other side when buffer added. */ +/* The Host uses this in used->flags to advise the Guest: don't kick me when + * you add a buffer. It's unreliable, so it's simply an optimization. Guest + * will still kick if it's out of buffers. */ #define VRING_USED_F_NO_NOTIFY 1 -/* This means don't interrupt guest when buffer consumed. */ +/* The Guest uses this in avail->flags to advise the Host: don't interrupt me + * when you consume a buffer. It's unreliable, so it's simply an + * optimization. */ #define VRING_AVAIL_F_NO_INTERRUPT 1 /* Virtio ring descriptors: 16 bytes. These can chain together via "next". */ @@ -89,7 +93,7 @@ * }; */ static inline void vring_init(struct vring *vr, unsigned int num, void *p, - unsigned int pagesize) + unsigned long pagesize) { vr->num = num; vr->desc = p; @@ -98,7 +102,7 @@ & ~(pagesize - 1)); } -static inline unsigned vring_size(unsigned int num, unsigned int pagesize) +static inline unsigned vring_size(unsigned int num, unsigned long pagesize) { return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num) + pagesize - 1) & ~(pagesize - 1)) @@ -114,7 +118,7 @@ struct virtio_device *vdev, void *pages, void (*notify)(struct virtqueue *vq), - bool (*callback)(struct virtqueue *vq)); + void (*callback)(struct virtqueue *vq)); void vring_del_virtqueue(struct virtqueue *vq); irqreturn_t vring_interrupt(int irq, void *_vq); --- linux-2.6.24.orig/include/linux/mm.h +++ linux-2.6.24/include/linux/mm.h @@ -514,21 +514,6 @@ } /* - * If a hint addr is less than mmap_min_addr change hint to be as - * low as possible but still greater than mmap_min_addr - */ -static inline unsigned long round_hint_to_min(unsigned long hint) -{ -#ifdef CONFIG_SECURITY - hint &= PAGE_MASK; - if (((void *)hint != NULL) && - (hint < mmap_min_addr)) - return PAGE_ALIGN(mmap_min_addr); -#endif - return hint; -} - -/* * Some inline functions in vmstat.h depend on page_zone() */ #include --- linux-2.6.24.orig/include/linux/time.h +++ linux-2.6.24/include/linux/time.h @@ -173,6 +173,10 @@ { ns += a->tv_nsec; while(unlikely(ns >= NSEC_PER_SEC)) { + /* The following asm() prevents the compiler from + * optimising this loop into a modulo operation. */ + asm("" : "+r"(ns)); + ns -= NSEC_PER_SEC; a->tv_sec++; } --- linux-2.6.24.orig/include/linux/personality.h +++ linux-2.6.24/include/linux/personality.h @@ -40,7 +40,10 @@ * Security-relevant compatibility flags that must be * cleared upon setuid or setgid exec: */ -#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC|ADDR_NO_RANDOMIZE) +#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC | \ + ADDR_NO_RANDOMIZE | \ + ADDR_COMPAT_LAYOUT | \ + MMAP_PAGE_ZERO) /* * Personality types. --- linux-2.6.24.orig/include/linux/usb_usual.h +++ linux-2.6.24/include/linux/usb_usual.h @@ -50,7 +50,9 @@ US_FLAG(CAPACITY_HEURISTICS, 0x00001000) \ /* sometimes sizes is too big */ \ US_FLAG(MAX_SECTORS_MIN,0x00002000) \ - /* Sets max_sectors to arch min */ + /* Sets max_sectors to arch min */ \ + US_FLAG(BULK_IGNORE_TAG,0x00004000) \ + /* Ignore tag mismatch in bulk operations */ #define US_FLAG(name, value) US_FL_##name = value , --- linux-2.6.24.orig/include/linux/sched.h +++ linux-2.6.24/include/linux/sched.h @@ -88,6 +88,7 @@ #include #include #include +#include #include @@ -847,6 +848,10 @@ void (*set_curr_task) (struct rq *rq); void (*task_tick) (struct rq *rq, struct task_struct *p); void (*task_new) (struct rq *rq, struct task_struct *p); + +#ifdef CONFIG_FAIR_GROUP_SCHED + void (*moved_group) (struct task_struct *p); +#endif }; struct load_weight { @@ -1178,6 +1183,11 @@ int make_it_fail; #endif struct prop_local_single dirties; +#ifdef CONFIG_LATENCYTOP + int latency_record_count; + struct latency_record latency_record[LT_SAVECOUNT]; +#endif + struct list_head *scm_work_list; }; /* @@ -1449,6 +1459,12 @@ extern void sched_idle_next(void); +#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) +extern void wake_up_idle_cpu(int cpu); +#else +static inline void wake_up_idle_cpu(int cpu) { } +#endif + #ifdef CONFIG_SCHED_DEBUG extern unsigned int sysctl_sched_latency; extern unsigned int sysctl_sched_min_granularity; --- linux-2.6.24.orig/include/linux/rfkill.h +++ linux-2.6.24/include/linux/rfkill.h @@ -33,11 +33,13 @@ * RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device. * RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device. * RFKILL_TYPE_UWB: switch is on a ultra wideband device. + * RFKILL_TYPE_WIMAX: switch is on a WiMAX device. */ enum rfkill_type { RFKILL_TYPE_WLAN , RFKILL_TYPE_BLUETOOTH, RFKILL_TYPE_UWB, + RFKILL_TYPE_WIMAX, RFKILL_TYPE_MAX, }; --- linux-2.6.24.orig/include/linux/virtio_config.h +++ linux-2.6.24/include/linux/virtio_config.h @@ -5,7 +5,7 @@ * store and access that space differently. */ #include -/* Status byte for guest to report progress, and synchronize config. */ +/* Status byte for guest to report progress, and synchronize features. */ /* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ #define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 /* We have found a driver for the device. */ @@ -15,34 +15,27 @@ /* We've given up on this device. */ #define VIRTIO_CONFIG_S_FAILED 0x80 -/* Feature byte (actually 7 bits availabe): */ -/* Requirements/features of the virtio implementation. */ -#define VIRTIO_CONFIG_F_VIRTIO 1 -/* Requirements/features of the virtqueue (may have more than one). */ -#define VIRTIO_CONFIG_F_VIRTQUEUE 2 - #ifdef __KERNEL__ struct virtio_device; /** * virtio_config_ops - operations for configuring a virtio device - * @find: search for the next configuration field of the given type. + * @feature: search for a feature in this config * vdev: the virtio_device - * type: the feature type - * len: the (returned) length of the field if found. - * Returns a token if found, or NULL. Never returnes the same field twice - * (ie. it's used up). - * @get: read the value of a configuration field after find(). + * bit: the feature bit + * Returns true if the feature is supported. Acknowledges the feature + * so the host can see it. + * @get: read the value of a configuration field * vdev: the virtio_device - * token: the token returned from find(). + * offset: the offset of the configuration field * buf: the buffer to write the field value into. - * len: the length of the buffer (given by find()). + * len: the length of the buffer * Note that contents are conventionally little-endian. - * @set: write the value of a configuration field after find(). + * @set: write the value of a configuration field * vdev: the virtio_device - * token: the token returned from find(). + * offset: the offset of the configuration field * buf: the buffer to read the field value from. - * len: the length of the buffer (given by find()). + * len: the length of the buffer * Note that contents are conventionally little-endian. * @get_status: read the status byte * vdev: the virtio_device @@ -50,62 +43,67 @@ * @set_status: write the status byte * vdev: the virtio_device * status: the new status byte - * @find_vq: find the first VIRTIO_CONFIG_F_VIRTQUEUE and create a virtqueue. + * @reset: reset the device + * vdev: the virtio device + * After this, status and feature negotiation must be done again + * @find_vq: find a virtqueue and instantiate it. * vdev: the virtio_device + * index: the 0-based virtqueue number in case there's more than one. * callback: the virqtueue callback - * Returns the new virtqueue or ERR_PTR(). + * Returns the new virtqueue or ERR_PTR() (eg. -ENOENT). * @del_vq: free a virtqueue found by find_vq(). */ struct virtio_config_ops { - void *(*find)(struct virtio_device *vdev, u8 type, unsigned *len); - void (*get)(struct virtio_device *vdev, void *token, + bool (*feature)(struct virtio_device *vdev, unsigned bit); + void (*get)(struct virtio_device *vdev, unsigned offset, void *buf, unsigned len); - void (*set)(struct virtio_device *vdev, void *token, + void (*set)(struct virtio_device *vdev, unsigned offset, const void *buf, unsigned len); u8 (*get_status)(struct virtio_device *vdev); void (*set_status)(struct virtio_device *vdev, u8 status); + void (*reset)(struct virtio_device *vdev); struct virtqueue *(*find_vq)(struct virtio_device *vdev, - bool (*callback)(struct virtqueue *)); + unsigned index, + void (*callback)(struct virtqueue *)); void (*del_vq)(struct virtqueue *vq); }; /** - * virtio_config_val - get a single virtio config and mark it used. - * @config: the virtio config space - * @type: the type to search for. + * virtio_config_val - look for a feature and get a single virtio config. + * @vdev: the virtio device + * @fbit: the feature bit + * @offset: the type to search for. * @val: a pointer to the value to fill in. * - * Once used, the config type is marked with VIRTIO_CONFIG_F_USED so it can't - * be found again. This version does endian conversion. */ -#define virtio_config_val(vdev, type, v) ({ \ - int _err = __virtio_config_val((vdev),(type),(v),sizeof(*(v))); \ - \ - BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2 \ - && sizeof(*(v)) != 4 && sizeof(*(v)) != 8); \ - if (!_err) { \ - switch (sizeof(*(v))) { \ - case 2: le16_to_cpus((__u16 *) v); break; \ - case 4: le32_to_cpus((__u32 *) v); break; \ - case 8: le64_to_cpus((__u64 *) v); break; \ - } \ - } \ + * The return value is -ENOENT if the feature doesn't exist. Otherwise + * the value is endian-corrected and returned in v. */ +#define virtio_config_val(vdev, fbit, offset, v) ({ \ + int _err; \ + if ((vdev)->config->feature((vdev), (fbit))) { \ + __virtio_config_val((vdev), (offset), (v)); \ + _err = 0; \ + } else \ + _err = -ENOENT; \ _err; \ }) -int __virtio_config_val(struct virtio_device *dev, - u8 type, void *val, size_t size); - /** - * virtio_use_bit - helper to use a feature bit in a bitfield value. - * @dev: the virtio device - * @token: the token as returned from vdev->config->find(). - * @len: the length of the field. - * @bitnum: the bit to test. + * __virtio_config_val - get a single virtio config without feature check. + * @vdev: the virtio device + * @offset: the type to search for. + * @val: a pointer to the value to fill in. * - * If handed a NULL token, it returns false, otherwise returns bit status. - * If it's one, it sets the mirroring acknowledgement bit. */ -int virtio_use_bit(struct virtio_device *vdev, - void *token, unsigned int len, unsigned int bitnum); + * The value is endian-corrected and returned in v. */ +#define __virtio_config_val(vdev, offset, v) do { \ + BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2 \ + && sizeof(*(v)) != 4 && sizeof(*(v)) != 8); \ + (vdev)->config->get((vdev), (offset), (v), sizeof(*(v))); \ + switch (sizeof(*(v))) { \ + case 2: le16_to_cpus((__u16 *) v); break; \ + case 4: le32_to_cpus((__u32 *) v); break; \ + case 8: le64_to_cpus((__u64 *) v); break; \ + } \ +} while(0) #endif /* __KERNEL__ */ #endif /* _LINUX_VIRTIO_CONFIG_H */ --- linux-2.6.24.orig/include/linux/moduleparam.h +++ linux-2.6.24/include/linux/moduleparam.h @@ -62,6 +62,16 @@ void *elem; }; +/* On alpha, ia64 and ppc64 relocations to global data cannot go into + read-only sections (which is part of respective UNIX ABI on these + platforms). So 'const' makes no sense and even causes compile failures + with some compilers. */ +#if defined(CONFIG_ALPHA) || defined(CONFIG_IA64) || defined(CONFIG_PPC64) +#define __moduleparam_const +#else +#define __moduleparam_const const +#endif + /* This is the fundamental function for registering boot/module parameters. perm sets the visibility in sysfs: 000 means it's not there, read bits mean it's readable, write bits mean it's @@ -71,7 +81,7 @@ static int __param_perm_check_##name __attribute__((unused)) = \ BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)); \ static const char __param_str_##name[] = prefix #name; \ - static struct kernel_param const __param_##name \ + static struct kernel_param __moduleparam_const __param_##name \ __attribute_used__ \ __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ = { __param_str_##name, perm, set, get, { arg } } --- linux-2.6.24.orig/include/acpi/reboot.h +++ linux-2.6.24/include/acpi/reboot.h @@ -0,0 +1,10 @@ +#ifndef __ACPI_REBOOT_H +#define __ACPI_REBOOT_H + +#ifdef CONFIG_ACPI +extern void acpi_reboot(void); +#else +static inline void acpi_reboot(void) { } +#endif + +#endif --- linux-2.6.24.orig/include/acpi/acpi_drivers.h +++ linux-2.6.24/include/acpi/acpi_drivers.h @@ -91,6 +91,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev); int acpi_power_get_inferred_state(struct acpi_device *device); int acpi_power_transition(struct acpi_device *device, int state); +extern int acpi_power_nocheck; #endif /* -------------------------------------------------------------------------- --- linux-2.6.24.orig/include/acpi/acresrc.h +++ linux-2.6.24/include/acpi/acresrc.h @@ -94,6 +94,7 @@ #define ACPI_RSC_BITMASK16 18 #define ACPI_RSC_EXIT_NE 19 #define ACPI_RSC_EXIT_LE 20 +#define ACPI_RSC_EXIT_EQ 21 /* Resource Conversion sub-opcodes */ --- linux-2.6.24.orig/include/acpi/actypes.h +++ linux-2.6.24/include/acpi/actypes.h @@ -990,6 +990,7 @@ * Structures used to describe device resources */ struct acpi_resource_irq { + u8 descriptor_length; u8 triggering; u8 polarity; u8 sharable; @@ -1006,6 +1007,7 @@ }; struct acpi_resource_start_dependent { + u8 descriptor_length; u8 compatibility_priority; u8 performance_robustness; }; --- linux-2.6.24.orig/include/net/scm.h +++ linux-2.6.24/include/net/scm.h @@ -14,8 +14,9 @@ struct scm_fp_list { - int count; - struct file *fp[SCM_MAX_FD]; + struct list_head list; + int count; + struct file *fp[SCM_MAX_FD]; }; struct scm_cookie --- linux-2.6.24.orig/include/net/inet_sock.h +++ linux-2.6.24/include/net/inet_sock.h @@ -175,7 +175,8 @@ static inline unsigned int inet_ehashfn(const __be32 laddr, const __u16 lport, const __be32 faddr, const __be16 fport) { - return jhash_2words((__force __u32) laddr ^ (__force __u32) faddr, + return jhash_3words((__force __u32) laddr, + (__force __u32) faddr, ((__u32) lport) << 16 | (__force __u32)fport, inet_ehash_secret); } --- linux-2.6.24.orig/include/net/sctp/sm.h +++ linux-2.6.24/include/net/sctp/sm.h @@ -227,6 +227,9 @@ const struct sctp_chunk *, const __u8 *, const size_t ); +struct sctp_chunk *sctp_make_violation_paramlen(const struct sctp_association *, + const struct sctp_chunk *, + struct sctp_paramhdr *); struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *, const struct sctp_transport *, const void *payload, --- linux-2.6.24.orig/include/net/bluetooth/hci_core.h +++ linux-2.6.24/include/net/bluetooth/hci_core.h @@ -25,6 +25,8 @@ #ifndef __HCI_CORE_H #define __HCI_CORE_H +#include + #include /* HCI upper protocols */ @@ -93,7 +95,7 @@ atomic_t cmd_cnt; unsigned int acl_cnt; - unsigned int sco_cnt; + atomic_t sco_cnt; unsigned int acl_mtu; unsigned int sco_mtu; @@ -150,7 +152,6 @@ struct list_head list; atomic_t refcnt; - spinlock_t lock; bdaddr_t dst; __u16 handle; @@ -167,10 +168,11 @@ __u8 power_save; unsigned long pend; - unsigned int sent; + atomic_t sent; struct sk_buff_head data_q; + struct hrtimer tx_timer; struct timer_list disc_timer; struct timer_list idle_timer; --- linux-2.6.24.orig/include/net/bluetooth/sco.h +++ linux-2.6.24/include/net/bluetooth/sco.h @@ -26,12 +26,7 @@ #define __SCO_H /* SCO defaults */ -#define SCO_DEFAULT_MTU 500 -#define SCO_DEFAULT_FLUSH_TO 0xFFFF - #define SCO_CONN_TIMEOUT (HZ * 40) -#define SCO_DISCONN_TIMEOUT (HZ * 2) -#define SCO_CONN_IDLE_TIMEOUT (HZ * 60) /* SCO socket address */ struct sockaddr_sco { --- linux-2.6.24.orig/include/net/af_unix.h +++ linux-2.6.24/include/net/af_unix.h @@ -9,6 +9,7 @@ extern void unix_inflight(struct file *fp); extern void unix_notinflight(struct file *fp); extern void unix_gc(void); +extern void wait_for_unix_gc(void); #define UNIX_HASH_SIZE 256 @@ -54,6 +55,7 @@ atomic_t inflight; spinlock_t lock; unsigned int gc_candidate : 1; + unsigned int gc_maybe_cycle : 1; wait_queue_head_t peer_wait; }; #define unix_sk(__sk) ((struct unix_sock *)__sk) --- linux-2.6.24.orig/include/net/tcp.h +++ linux-2.6.24/include/net/tcp.h @@ -775,11 +775,14 @@ extern __u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst); /* Slow start with delack produces 3 packets of burst, so that - * it is safe "de facto". + * it is safe "de facto". This will be the default - same as + * the default reordering threshold - but if reordering increases, + * we must be able to allow cwnd to burst at least this much in order + * to not pull it back when holes are filled. */ static __inline__ __u32 tcp_max_burst(const struct tcp_sock *tp) { - return 3; + return tp->reordering; } /* RFC2861 Check whether we are limited by application or congestion window --- linux-2.6.24.orig/include/asm-x86/kvm_x86_emulate.h +++ linux-2.6.24/include/asm-x86/kvm_x86_emulate.h @@ -0,0 +1,186 @@ +/****************************************************************************** + * x86_emulate.h + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. + * + * Copyright (c) 2005 Keir Fraser + * + * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4 + */ + +#ifndef __X86_EMULATE_H__ +#define __X86_EMULATE_H__ + +struct x86_emulate_ctxt; + +/* + * x86_emulate_ops: + * + * These operations represent the instruction emulator's interface to memory. + * There are two categories of operation: those that act on ordinary memory + * regions (*_std), and those that act on memory regions known to require + * special treatment or emulation (*_emulated). + * + * The emulator assumes that an instruction accesses only one 'emulated memory' + * location, that this location is the given linear faulting address (cr2), and + * that this is one of the instruction's data operands. Instruction fetches and + * stack operations are assumed never to access emulated memory. The emulator + * automatically deduces which operand of a string-move operation is accessing + * emulated memory, and assumes that the other operand accesses normal memory. + * + * NOTES: + * 1. The emulator isn't very smart about emulated vs. standard memory. + * 'Emulated memory' access addresses should be checked for sanity. + * 'Normal memory' accesses may fault, and the caller must arrange to + * detect and handle reentrancy into the emulator via recursive faults. + * Accesses may be unaligned and may cross page boundaries. + * 2. If the access fails (cannot emulate, or a standard access faults) then + * it is up to the memop to propagate the fault to the guest VM via + * some out-of-band mechanism, unknown to the emulator. The memop signals + * failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will + * then immediately bail. + * 3. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only + * cmpxchg8b_emulated need support 8-byte accesses. + * 4. The emulator cannot handle 64-bit mode emulation on an x86/32 system. + */ +/* Access completed successfully: continue emulation as normal. */ +#define X86EMUL_CONTINUE 0 +/* Access is unhandleable: bail from emulation and return error to caller. */ +#define X86EMUL_UNHANDLEABLE 1 +/* Terminate emulation but return success to the caller. */ +#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */ +#define X86EMUL_RETRY_INSTR 2 /* retry the instruction for some reason */ +#define X86EMUL_CMPXCHG_FAILED 2 /* cmpxchg did not see expected value */ +struct x86_emulate_ops { + /* + * read_std: Read bytes of standard (non-emulated/special) memory. + * Used for instruction fetch, stack operations, and others. + * @addr: [IN ] Linear address from which to read. + * @val: [OUT] Value read from memory, zero-extended to 'u_long'. + * @bytes: [IN ] Number of bytes to read from memory. + */ + int (*read_std)(unsigned long addr, void *val, + unsigned int bytes, struct kvm_vcpu *vcpu); + + /* + * read_emulated: Read bytes from emulated/special memory area. + * @addr: [IN ] Linear address from which to read. + * @val: [OUT] Value read from memory, zero-extended to 'u_long'. + * @bytes: [IN ] Number of bytes to read from memory. + */ + int (*read_emulated) (unsigned long addr, + void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu); + + /* + * write_emulated: Read bytes from emulated/special memory area. + * @addr: [IN ] Linear address to which to write. + * @val: [IN ] Value to write to memory (low-order bytes used as + * required). + * @bytes: [IN ] Number of bytes to write to memory. + */ + int (*write_emulated) (unsigned long addr, + const void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu); + + /* + * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an + * emulated/special memory area. + * @addr: [IN ] Linear address to access. + * @old: [IN ] Value expected to be current at @addr. + * @new: [IN ] Value to write to @addr. + * @bytes: [IN ] Number of bytes to access using CMPXCHG. + */ + int (*cmpxchg_emulated) (unsigned long addr, + const void *old, + const void *new, + unsigned int bytes, + struct kvm_vcpu *vcpu); + +}; + +/* Type, address-of, and value of an instruction's operand. */ +struct operand { + enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type; + unsigned int bytes; + unsigned long val, orig_val, *ptr; +}; + +struct fetch_cache { + u8 data[15]; + unsigned long start; + unsigned long end; +}; + +struct decode_cache { + u8 twobyte; + u8 b; + u8 lock_prefix; + u8 rep_prefix; + u8 op_bytes; + u8 ad_bytes; + u8 rex_prefix; + struct operand src; + struct operand dst; + unsigned long *override_base; + unsigned int d; + unsigned long regs[NR_VCPU_REGS]; + unsigned long eip, eip_orig; + /* modrm */ + u8 modrm; + u8 modrm_mod; + u8 modrm_reg; + u8 modrm_rm; + u8 use_modrm_ea; + unsigned long modrm_ea; + unsigned long modrm_val; + struct fetch_cache fetch; +}; + +struct x86_emulate_ctxt { + /* Register state before/after emulation. */ + struct kvm_vcpu *vcpu; + + /* Linear faulting address (if emulating a page-faulting instruction). */ + unsigned long eflags; + + /* Emulated execution mode, represented by an X86EMUL_MODE value. */ + int mode; + + unsigned long cs_base; + unsigned long ds_base; + unsigned long es_base; + unsigned long ss_base; + unsigned long gs_base; + unsigned long fs_base; + + /* decode cache */ + + struct decode_cache decode; +}; + +/* Repeat String Operation Prefix */ +#define REPE_PREFIX 1 +#define REPNE_PREFIX 2 + +/* Execution mode, passed to the emulator. */ +#define X86EMUL_MODE_REAL 0 /* Real mode. */ +#define X86EMUL_MODE_PROT16 2 /* 16-bit protected mode. */ +#define X86EMUL_MODE_PROT32 4 /* 32-bit protected mode. */ +#define X86EMUL_MODE_PROT64 8 /* 64-bit (long) mode. */ + +/* Host execution mode. */ +#if defined(__i386__) +#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32 +#elif defined(CONFIG_X86_64) +#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64 +#endif + +int x86_decode_insn(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops); +int x86_emulate_insn(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops); + +#endif /* __X86_EMULATE_H__ */ --- linux-2.6.24.orig/include/asm-x86/nops_64.h +++ linux-2.6.24/include/asm-x86/nops_64.h @@ -0,0 +1,49 @@ +#ifndef _ASM_NOPS_H +#define _ASM_NOPS_H + +/* Define nops for use with alternative() */ + +#if defined(CONFIG_MPSC) || defined(CONFIG_MCORE2) +#define ASM_NOP1 P6_NOP1 +#define ASM_NOP2 P6_NOP2 +#define ASM_NOP3 P6_NOP3 +#define ASM_NOP4 P6_NOP4 +#define ASM_NOP5 P6_NOP5 +#define ASM_NOP6 P6_NOP6 +#define ASM_NOP7 P6_NOP7 +#define ASM_NOP8 P6_NOP8 +#else +#define ASM_NOP1 K8_NOP1 +#define ASM_NOP2 K8_NOP2 +#define ASM_NOP3 K8_NOP3 +#define ASM_NOP4 K8_NOP4 +#define ASM_NOP5 K8_NOP5 +#define ASM_NOP6 K8_NOP6 +#define ASM_NOP7 K8_NOP7 +#define ASM_NOP8 K8_NOP8 +#endif + +/* Opteron nops */ +#define K8_NOP1 ".byte 0x90\n" +#define K8_NOP2 ".byte 0x66,0x90\n" +#define K8_NOP3 ".byte 0x66,0x66,0x90\n" +#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n" +#define K8_NOP5 K8_NOP3 K8_NOP2 +#define K8_NOP6 K8_NOP3 K8_NOP3 +#define K8_NOP7 K8_NOP4 K8_NOP3 +#define K8_NOP8 K8_NOP4 K8_NOP4 + +/* P6 nops */ +/* uses eax dependencies (Intel-recommended choice) */ +#define P6_NOP1 ".byte 0x90\n" +#define P6_NOP2 ".byte 0x66,0x90\n" +#define P6_NOP3 ".byte 0x0f,0x1f,0x00\n" +#define P6_NOP4 ".byte 0x0f,0x1f,0x40,0\n" +#define P6_NOP5 ".byte 0x0f,0x1f,0x44,0x00,0\n" +#define P6_NOP6 ".byte 0x66,0x0f,0x1f,0x44,0x00,0\n" +#define P6_NOP7 ".byte 0x0f,0x1f,0x80,0,0,0,0\n" +#define P6_NOP8 ".byte 0x0f,0x1f,0x84,0x00,0,0,0,0\n" + +#define ASM_NOP_MAX 8 + +#endif --- linux-2.6.24.orig/include/asm-x86/futex_32.h +++ linux-2.6.24/include/asm-x86/futex_32.h @@ -28,7 +28,7 @@ "1: movl %2, %0\n\ movl %0, %3\n" \ insn "\n" \ -"2: " LOCK_PREFIX "cmpxchgl %3, %2\n\ +"2: lock ; cmpxchgl %3, %2\n\ jnz 1b\n\ 3: .section .fixup,\"ax\"\n\ 4: mov %5, %1\n\ @@ -68,7 +68,7 @@ #endif switch (op) { case FUTEX_OP_ADD: - __futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, + __futex_atomic_op1("lock ; xaddl %0, %2", ret, oldval, uaddr, oparg); break; case FUTEX_OP_OR: @@ -111,7 +111,7 @@ return -EFAULT; __asm__ __volatile__( - "1: " LOCK_PREFIX "cmpxchgl %3, %1 \n" + "1: lock ; cmpxchgl %3, %1 \n" "2: .section .fixup, \"ax\" \n" "3: mov %2, %0 \n" --- linux-2.6.24.orig/include/asm-x86/tsc.h +++ linux-2.6.24/include/asm-x86/tsc.h @@ -32,32 +32,17 @@ return ret; } -/* Like get_cycles, but make sure the CPU is synchronized. */ -static __always_inline cycles_t get_cycles_sync(void) +static inline cycles_t vget_cycles(void) { - unsigned long long ret; - unsigned eax, edx; - - /* - * Use RDTSCP if possible; it is guaranteed to be synchronous - * and doesn't cause a VMEXIT on Hypervisors - */ - alternative_io(ASM_NOP3, ".byte 0x0f,0x01,0xf9", X86_FEATURE_RDTSCP, - ASM_OUTPUT2("=a" (eax), "=d" (edx)), - "a" (0U), "d" (0U) : "ecx", "memory"); - ret = (((unsigned long long)edx) << 32) | ((unsigned long long)eax); - if (ret) - return ret; - /* - * Don't do an additional sync on CPUs where we know - * RDTSC is already synchronous: + * We only do VDSOs on TSC capable CPUs, so this shouldnt + * access boot_cpu_data (which is not VDSO-safe): */ - alternative_io("cpuid", ASM_NOP2, X86_FEATURE_SYNC_RDTSC, - "=a" (eax), "0" (1) : "ebx","ecx","edx","memory"); - rdtscll(ret); - - return ret; +#ifndef CONFIG_X86_TSC + if (!cpu_has_tsc) + return 0; +#endif + return (cycles_t) native_read_tsc(); } extern void tsc_init(void); --- linux-2.6.24.orig/include/asm-x86/seccomp_32.h +++ linux-2.6.24/include/asm-x86/seccomp_32.h @@ -1,11 +1,5 @@ #ifndef _ASM_SECCOMP_H -#include - -#ifdef TIF_32BIT -#error "unexpected TIF_32BIT on i386" -#endif - #include #define __NR_seccomp_read __NR_read --- linux-2.6.24.orig/include/asm-x86/signal.h +++ linux-2.6.24/include/asm-x86/signal.h @@ -181,14 +181,14 @@ #ifdef __KERNEL__ #include -#ifdef __386__ +#ifdef __i386__ #define __HAVE_ARCH_SIG_BITOPS -#define sigaddset(set,sig) \ - (__builtin_constantp(sig) ? \ - __const_sigaddset((set),(sig)) : \ - __gen_sigaddset((set),(sig))) +#define sigaddset(set,sig) \ + (__builtin_constant_p(sig) \ + ? __const_sigaddset((set), (sig)) \ + : __gen_sigaddset((set), (sig))) static __inline__ void __gen_sigaddset(sigset_t *set, int _sig) { --- linux-2.6.24.orig/include/asm-x86/vmware.h +++ linux-2.6.24/include/asm-x86/vmware.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2008, VMware, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef ASM_X86__VMWARE_H +#define ASM_X86__VMWARE_H + +extern unsigned long vmware_get_tsc_khz(void); +extern int vmware_platform(void); +extern void vmware_set_feature_bits(struct cpuinfo_x86 *c); + +#endif --- linux-2.6.24.orig/include/asm-x86/kvm.h +++ linux-2.6.24/include/asm-x86/kvm.h @@ -0,0 +1,191 @@ +#ifndef __LINUX_KVM_X86_H +#define __LINUX_KVM_X86_H + +/* + * KVM x86 specific structures and definitions + * + */ + +#include +#include + +/* Architectural interrupt line count. */ +#define KVM_NR_INTERRUPTS 256 + +struct kvm_memory_alias { + __u32 slot; /* this has a different namespace than memory slots */ + __u32 flags; + __u64 guest_phys_addr; + __u64 memory_size; + __u64 target_phys_addr; +}; + +/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */ +struct kvm_pic_state { + __u8 last_irr; /* edge detection */ + __u8 irr; /* interrupt request register */ + __u8 imr; /* interrupt mask register */ + __u8 isr; /* interrupt service register */ + __u8 priority_add; /* highest irq priority */ + __u8 irq_base; + __u8 read_reg_select; + __u8 poll; + __u8 special_mask; + __u8 init_state; + __u8 auto_eoi; + __u8 rotate_on_auto_eoi; + __u8 special_fully_nested_mode; + __u8 init4; /* true if 4 byte init */ + __u8 elcr; /* PIIX edge/trigger selection */ + __u8 elcr_mask; +}; + +#define KVM_IOAPIC_NUM_PINS 24 +struct kvm_ioapic_state { + __u64 base_address; + __u32 ioregsel; + __u32 id; + __u32 irr; + __u32 pad; + union { + __u64 bits; + struct { + __u8 vector; + __u8 delivery_mode:3; + __u8 dest_mode:1; + __u8 delivery_status:1; + __u8 polarity:1; + __u8 remote_irr:1; + __u8 trig_mode:1; + __u8 mask:1; + __u8 reserve:7; + __u8 reserved[4]; + __u8 dest_id; + } fields; + } redirtbl[KVM_IOAPIC_NUM_PINS]; +}; + +#define KVM_IRQCHIP_PIC_MASTER 0 +#define KVM_IRQCHIP_PIC_SLAVE 1 +#define KVM_IRQCHIP_IOAPIC 2 + +/* for KVM_GET_REGS and KVM_SET_REGS */ +struct kvm_regs { + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ + __u64 rax, rbx, rcx, rdx; + __u64 rsi, rdi, rsp, rbp; + __u64 r8, r9, r10, r11; + __u64 r12, r13, r14, r15; + __u64 rip, rflags; +}; + +/* for KVM_GET_LAPIC and KVM_SET_LAPIC */ +#define KVM_APIC_REG_SIZE 0x400 +struct kvm_lapic_state { + char regs[KVM_APIC_REG_SIZE]; +}; + +struct kvm_segment { + __u64 base; + __u32 limit; + __u16 selector; + __u8 type; + __u8 present, dpl, db, s, l, g, avl; + __u8 unusable; + __u8 padding; +}; + +struct kvm_dtable { + __u64 base; + __u16 limit; + __u16 padding[3]; +}; + + +/* for KVM_GET_SREGS and KVM_SET_SREGS */ +struct kvm_sregs { + /* out (KVM_GET_SREGS) / in (KVM_SET_SREGS) */ + struct kvm_segment cs, ds, es, fs, gs, ss; + struct kvm_segment tr, ldt; + struct kvm_dtable gdt, idt; + __u64 cr0, cr2, cr3, cr4, cr8; + __u64 efer; + __u64 apic_base; + __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64]; +}; + +/* for KVM_GET_FPU and KVM_SET_FPU */ +struct kvm_fpu { + __u8 fpr[8][16]; + __u16 fcw; + __u16 fsw; + __u8 ftwx; /* in fxsave format */ + __u8 pad1; + __u16 last_opcode; + __u64 last_ip; + __u64 last_dp; + __u8 xmm[16][16]; + __u32 mxcsr; + __u32 pad2; +}; + +struct kvm_msr_entry { + __u32 index; + __u32 reserved; + __u64 data; +}; + +/* for KVM_GET_MSRS and KVM_SET_MSRS */ +struct kvm_msrs { + __u32 nmsrs; /* number of msrs in entries */ + __u32 pad; + + struct kvm_msr_entry entries[0]; +}; + +/* for KVM_GET_MSR_INDEX_LIST */ +struct kvm_msr_list { + __u32 nmsrs; /* number of msrs in entries */ + __u32 indices[0]; +}; + + +struct kvm_cpuid_entry { + __u32 function; + __u32 eax; + __u32 ebx; + __u32 ecx; + __u32 edx; + __u32 padding; +}; + +/* for KVM_SET_CPUID */ +struct kvm_cpuid { + __u32 nent; + __u32 padding; + struct kvm_cpuid_entry entries[0]; +}; + +struct kvm_cpuid_entry2 { + __u32 function; + __u32 index; + __u32 flags; + __u32 eax; + __u32 ebx; + __u32 ecx; + __u32 edx; + __u32 padding[3]; +}; + +#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX 1 +#define KVM_CPUID_FLAG_STATEFUL_FUNC 2 +#define KVM_CPUID_FLAG_STATE_READ_NEXT 4 + +/* for KVM_SET_CPUID2 */ +struct kvm_cpuid2 { + __u32 nent; + __u32 padding; + struct kvm_cpuid_entry2 entries[0]; +}; + +#endif --- linux-2.6.24.orig/include/asm-x86/Kbuild +++ linux-2.6.24/include/asm-x86/Kbuild @@ -3,6 +3,7 @@ header-y += boot.h header-y += bootparam.h header-y += debugreg.h +header-y += kvm.h header-y += ldt.h header-y += msr-index.h header-y += prctl.h --- linux-2.6.24.orig/include/asm-x86/io_apic_64.h +++ linux-2.6.24/include/asm-x86/io_apic_64.h @@ -129,7 +129,7 @@ extern int sis_apic_bug; /* dummy */ -void enable_NMI_through_LVT0 (void * dummy); +void enable_NMI_through_LVT0(void); extern spinlock_t i8259A_lock; --- linux-2.6.24.orig/include/asm-x86/page_64.h +++ linux-2.6.24/include/asm-x86/page_64.h @@ -45,6 +45,9 @@ void clear_page(void *); void copy_page(void *, void *); +extern int page_is_ram(unsigned long pagenr); +extern int devmem_is_allowed(unsigned long pagenr); + #define clear_user_page(page, vaddr, pg) clear_page(page) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) --- linux-2.6.24.orig/include/asm-x86/page_32.h +++ linux-2.6.24/include/asm-x86/page_32.h @@ -166,6 +166,7 @@ extern int sysctl_legacy_va_layout; extern int page_is_ram(unsigned long pagenr); +extern int devmem_is_allowed(unsigned long pagenr); #endif /* __ASSEMBLY__ */ --- linux-2.6.24.orig/include/asm-x86/processor_32.h +++ linux-2.6.24/include/asm-x86/processor_32.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -81,6 +82,7 @@ __u8 cpu_core_id; /* Core id */ __u8 cpu_index; /* index into per_cpu list */ #endif + unsigned int x86_hyper_vendor; } __attribute__((__aligned__(SMP_CACHE_BYTES))); #define X86_VENDOR_INTEL 0 @@ -94,6 +96,9 @@ #define X86_VENDOR_NUM 9 #define X86_VENDOR_UNKNOWN 0xff +#define X86_HYPER_VENDOR_NONE 0 +#define X86_HYPER_VENDOR_VMWARE 1 + /* * capabilities of CPUs */ @@ -652,90 +657,6 @@ return edx; } -/* generic versions from gas */ -#define GENERIC_NOP1 ".byte 0x90\n" -#define GENERIC_NOP2 ".byte 0x89,0xf6\n" -#define GENERIC_NOP3 ".byte 0x8d,0x76,0x00\n" -#define GENERIC_NOP4 ".byte 0x8d,0x74,0x26,0x00\n" -#define GENERIC_NOP5 GENERIC_NOP1 GENERIC_NOP4 -#define GENERIC_NOP6 ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n" -#define GENERIC_NOP7 ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n" -#define GENERIC_NOP8 GENERIC_NOP1 GENERIC_NOP7 - -/* Opteron nops */ -#define K8_NOP1 GENERIC_NOP1 -#define K8_NOP2 ".byte 0x66,0x90\n" -#define K8_NOP3 ".byte 0x66,0x66,0x90\n" -#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n" -#define K8_NOP5 K8_NOP3 K8_NOP2 -#define K8_NOP6 K8_NOP3 K8_NOP3 -#define K8_NOP7 K8_NOP4 K8_NOP3 -#define K8_NOP8 K8_NOP4 K8_NOP4 - -/* K7 nops */ -/* uses eax dependencies (arbitary choice) */ -#define K7_NOP1 GENERIC_NOP1 -#define K7_NOP2 ".byte 0x8b,0xc0\n" -#define K7_NOP3 ".byte 0x8d,0x04,0x20\n" -#define K7_NOP4 ".byte 0x8d,0x44,0x20,0x00\n" -#define K7_NOP5 K7_NOP4 ASM_NOP1 -#define K7_NOP6 ".byte 0x8d,0x80,0,0,0,0\n" -#define K7_NOP7 ".byte 0x8D,0x04,0x05,0,0,0,0\n" -#define K7_NOP8 K7_NOP7 ASM_NOP1 - -/* P6 nops */ -/* uses eax dependencies (Intel-recommended choice) */ -#define P6_NOP1 GENERIC_NOP1 -#define P6_NOP2 ".byte 0x66,0x90\n" -#define P6_NOP3 ".byte 0x0f,0x1f,0x00\n" -#define P6_NOP4 ".byte 0x0f,0x1f,0x40,0\n" -#define P6_NOP5 ".byte 0x0f,0x1f,0x44,0x00,0\n" -#define P6_NOP6 ".byte 0x66,0x0f,0x1f,0x44,0x00,0\n" -#define P6_NOP7 ".byte 0x0f,0x1f,0x80,0,0,0,0\n" -#define P6_NOP8 ".byte 0x0f,0x1f,0x84,0x00,0,0,0,0\n" - -#ifdef CONFIG_MK8 -#define ASM_NOP1 K8_NOP1 -#define ASM_NOP2 K8_NOP2 -#define ASM_NOP3 K8_NOP3 -#define ASM_NOP4 K8_NOP4 -#define ASM_NOP5 K8_NOP5 -#define ASM_NOP6 K8_NOP6 -#define ASM_NOP7 K8_NOP7 -#define ASM_NOP8 K8_NOP8 -#elif defined(CONFIG_MK7) -#define ASM_NOP1 K7_NOP1 -#define ASM_NOP2 K7_NOP2 -#define ASM_NOP3 K7_NOP3 -#define ASM_NOP4 K7_NOP4 -#define ASM_NOP5 K7_NOP5 -#define ASM_NOP6 K7_NOP6 -#define ASM_NOP7 K7_NOP7 -#define ASM_NOP8 K7_NOP8 -#elif defined(CONFIG_M686) || defined(CONFIG_MPENTIUMII) || \ - defined(CONFIG_MPENTIUMIII) || defined(CONFIG_MPENTIUMM) || \ - defined(CONFIG_MCORE2) || defined(CONFIG_PENTIUM4) -#define ASM_NOP1 P6_NOP1 -#define ASM_NOP2 P6_NOP2 -#define ASM_NOP3 P6_NOP3 -#define ASM_NOP4 P6_NOP4 -#define ASM_NOP5 P6_NOP5 -#define ASM_NOP6 P6_NOP6 -#define ASM_NOP7 P6_NOP7 -#define ASM_NOP8 P6_NOP8 -#else -#define ASM_NOP1 GENERIC_NOP1 -#define ASM_NOP2 GENERIC_NOP2 -#define ASM_NOP3 GENERIC_NOP3 -#define ASM_NOP4 GENERIC_NOP4 -#define ASM_NOP5 GENERIC_NOP5 -#define ASM_NOP6 GENERIC_NOP6 -#define ASM_NOP7 GENERIC_NOP7 -#define ASM_NOP8 GENERIC_NOP8 -#endif - -#define ASM_NOP_MAX 8 - /* Prefetch instructions for Pentium III and AMD Athlon */ /* It's not worth to care about 3dnow! prefetches for the K6 because they are microcoded there and very slow. --- linux-2.6.24.orig/include/asm-x86/kvm_host.h +++ linux-2.6.24/include/asm-x86/kvm_host.h @@ -0,0 +1,638 @@ +#/* + * Kernel-based Virtual Machine driver for Linux + * + * This header defines architecture specific interfaces, x86 version + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef ASM_KVM_HOST_H +#define ASM_KVM_HOST_H + +#include +#include + +#include +#include +#include + +#include + +#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1) +#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD)) +#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS|0xFFFFFF0000000000ULL) + +#define KVM_GUEST_CR0_MASK \ + (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE \ + | X86_CR0_NW | X86_CR0_CD) +#define KVM_VM_CR0_ALWAYS_ON \ + (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE | X86_CR0_TS \ + | X86_CR0_MP) +#define KVM_GUEST_CR4_MASK \ + (X86_CR4_VME | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_VMXE) +#define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE) +#define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE) + +#define INVALID_PAGE (~(hpa_t)0) +#define UNMAPPED_GVA (~(gpa_t)0) + +/* shadow tables are PAE even on non-PAE hosts */ +#define KVM_HPAGE_SHIFT 21 +#define KVM_HPAGE_SIZE (1UL << KVM_HPAGE_SHIFT) +#define KVM_HPAGE_MASK (~(KVM_HPAGE_SIZE - 1)) + +#define KVM_PAGES_PER_HPAGE (KVM_HPAGE_SIZE / PAGE_SIZE) + +#define DE_VECTOR 0 +#define UD_VECTOR 6 +#define NM_VECTOR 7 +#define DF_VECTOR 8 +#define TS_VECTOR 10 +#define NP_VECTOR 11 +#define SS_VECTOR 12 +#define GP_VECTOR 13 +#define PF_VECTOR 14 + +#define SELECTOR_TI_MASK (1 << 2) +#define SELECTOR_RPL_MASK 0x03 + +#define IOPL_SHIFT 12 + +#define KVM_ALIAS_SLOTS 4 + +#define KVM_PERMILLE_MMU_PAGES 20 +#define KVM_MIN_ALLOC_MMU_PAGES 64 +#define KVM_MMU_HASH_SHIFT 10 +#define KVM_NUM_MMU_PAGES (1 << KVM_MMU_HASH_SHIFT) +#define KVM_MIN_FREE_MMU_PAGES 5 +#define KVM_REFILL_PAGES 25 +#define KVM_MAX_CPUID_ENTRIES 40 + +extern spinlock_t kvm_lock; +extern struct list_head vm_list; + +struct kvm_vcpu; +struct kvm; + +enum { + VCPU_REGS_RAX = 0, + VCPU_REGS_RCX = 1, + VCPU_REGS_RDX = 2, + VCPU_REGS_RBX = 3, + VCPU_REGS_RSP = 4, + VCPU_REGS_RBP = 5, + VCPU_REGS_RSI = 6, + VCPU_REGS_RDI = 7, +#ifdef CONFIG_X86_64 + VCPU_REGS_R8 = 8, + VCPU_REGS_R9 = 9, + VCPU_REGS_R10 = 10, + VCPU_REGS_R11 = 11, + VCPU_REGS_R12 = 12, + VCPU_REGS_R13 = 13, + VCPU_REGS_R14 = 14, + VCPU_REGS_R15 = 15, +#endif + NR_VCPU_REGS +}; + +enum { + VCPU_SREG_CS, + VCPU_SREG_DS, + VCPU_SREG_ES, + VCPU_SREG_FS, + VCPU_SREG_GS, + VCPU_SREG_SS, + VCPU_SREG_TR, + VCPU_SREG_LDTR, +}; + +#include + +#define KVM_NR_MEM_OBJS 40 + +/* + * We don't want allocation failures within the mmu code, so we preallocate + * enough memory for a single page fault in a cache. + */ +struct kvm_mmu_memory_cache { + int nobjs; + void *objects[KVM_NR_MEM_OBJS]; +}; + +#define NR_PTE_CHAIN_ENTRIES 5 + +struct kvm_pte_chain { + u64 *parent_ptes[NR_PTE_CHAIN_ENTRIES]; + struct hlist_node link; +}; + +/* + * kvm_mmu_page_role, below, is defined as: + * + * bits 0:3 - total guest paging levels (2-4, or zero for real mode) + * bits 4:7 - page table level for this shadow (1-4) + * bits 8:9 - page table quadrant for 2-level guests + * bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode) + * bits 17:19 - common access permissions for all ptes in this shadow page + */ +union kvm_mmu_page_role { + unsigned word; + struct { + unsigned glevels : 4; + unsigned level : 4; + unsigned quadrant : 2; + unsigned pad_for_nice_hex_output : 6; + unsigned metaphysical : 1; + unsigned access : 3; + unsigned invalid : 1; + }; +}; + +struct kvm_mmu_page { + struct list_head link; + struct hlist_node hash_link; + + /* + * The following two entries are used to key the shadow page in the + * hash table. + */ + gfn_t gfn; + union kvm_mmu_page_role role; + + u64 *spt; + /* hold the gfn of each spte inside spt */ + gfn_t *gfns; + unsigned long slot_bitmap; /* One bit set per slot which has memory + * in this shadow page. + */ + int multimapped; /* More than one parent_pte? */ + int root_count; /* Currently serving as active root */ + union { + u64 *parent_pte; /* !multimapped */ + struct hlist_head parent_ptes; /* multimapped, kvm_pte_chain */ + }; +}; + +/* + * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level + * 32-bit). The kvm_mmu structure abstracts the details of the current mmu + * mode. + */ +struct kvm_mmu { + void (*new_cr3)(struct kvm_vcpu *vcpu); + int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err); + void (*free)(struct kvm_vcpu *vcpu); + gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva); + void (*prefetch_page)(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *page); + hpa_t root_hpa; + int root_level; + int shadow_root_level; + + u64 *pae_root; +}; + +struct kvm_vcpu_arch { + u64 host_tsc; + int interrupt_window_open; + unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ + DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS); + unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */ + unsigned long rip; /* needs vcpu_load_rsp_rip() */ + + unsigned long cr0; + unsigned long cr2; + unsigned long cr3; + unsigned long cr4; + unsigned long cr8; + u64 pdptrs[4]; /* pae */ + u64 shadow_efer; + u64 apic_base; + struct kvm_lapic *apic; /* kernel irqchip context */ +#define VCPU_MP_STATE_RUNNABLE 0 +#define VCPU_MP_STATE_UNINITIALIZED 1 +#define VCPU_MP_STATE_INIT_RECEIVED 2 +#define VCPU_MP_STATE_SIPI_RECEIVED 3 +#define VCPU_MP_STATE_HALTED 4 + int mp_state; + int sipi_vector; + u64 ia32_misc_enable_msr; + bool tpr_access_reporting; + + struct kvm_mmu mmu; + + struct kvm_mmu_memory_cache mmu_pte_chain_cache; + struct kvm_mmu_memory_cache mmu_rmap_desc_cache; + struct kvm_mmu_memory_cache mmu_page_cache; + struct kvm_mmu_memory_cache mmu_page_header_cache; + + gfn_t last_pt_write_gfn; + int last_pt_write_count; + u64 *last_pte_updated; + + struct { + gfn_t gfn; /* presumed gfn during guest pte update */ + struct page *page; /* page corresponding to that gfn */ + int largepage; + } update_pte; + + struct i387_fxsave_struct host_fx_image; + struct i387_fxsave_struct guest_fx_image; + + gva_t mmio_fault_cr2; + struct kvm_pio_request pio; + void *pio_data; + + struct kvm_queued_exception { + bool pending; + bool has_error_code; + u8 nr; + u32 error_code; + } exception; + + struct { + int active; + u8 save_iopl; + struct kvm_save_segment { + u16 selector; + unsigned long base; + u32 limit; + u32 ar; + } tr, es, ds, fs, gs; + } rmode; + int halt_request; /* real mode on Intel only */ + + int cpuid_nent; + struct kvm_cpuid_entry2 cpuid_entries[KVM_MAX_CPUID_ENTRIES]; + /* emulate context */ + + struct x86_emulate_ctxt emulate_ctxt; + + gpa_t time; + struct kvm_vcpu_time_info hv_clock; + unsigned int time_offset; + struct page *time_page; +}; + +struct kvm_mem_alias { + gfn_t base_gfn; + unsigned long npages; + gfn_t target_gfn; +}; + +struct kvm_arch{ + int naliases; + struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS]; + + unsigned int n_free_mmu_pages; + unsigned int n_requested_mmu_pages; + unsigned int n_alloc_mmu_pages; + struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES]; + /* + * Hash table of struct kvm_mmu_page. + */ + struct list_head active_mmu_pages; + struct kvm_pic *vpic; + struct kvm_ioapic *vioapic; + + int round_robin_prev_vcpu; + unsigned int tss_addr; + struct page *apic_access_page; + + gpa_t wall_clock; +}; + +struct kvm_vm_stat { + u32 mmu_shadow_zapped; + u32 mmu_pte_write; + u32 mmu_pte_updated; + u32 mmu_pde_zapped; + u32 mmu_flooded; + u32 mmu_recycled; + u32 mmu_cache_miss; + u32 remote_tlb_flush; + u32 lpages; +}; + +struct kvm_vcpu_stat { + u32 pf_fixed; + u32 pf_guest; + u32 tlb_flush; + u32 invlpg; + + u32 exits; + u32 io_exits; + u32 mmio_exits; + u32 signal_exits; + u32 irq_window_exits; + u32 halt_exits; + u32 halt_wakeup; + u32 request_irq_exits; + u32 irq_exits; + u32 host_state_reload; + u32 efer_reload; + u32 fpu_reload; + u32 insn_emulation; + u32 insn_emulation_fail; + u32 hypercalls; +}; + +struct descriptor_table { + u16 limit; + unsigned long base; +} __attribute__((packed)); + +struct kvm_x86_ops { + int (*cpu_has_kvm_support)(void); /* __init */ + int (*disabled_by_bios)(void); /* __init */ + void (*hardware_enable)(void *dummy); /* __init */ + void (*hardware_disable)(void *dummy); + void (*check_processor_compatibility)(void *rtn); + int (*hardware_setup)(void); /* __init */ + void (*hardware_unsetup)(void); /* __exit */ + bool (*cpu_has_accelerated_tpr)(void); + + /* Create, but do not attach this VCPU */ + struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id); + void (*vcpu_free)(struct kvm_vcpu *vcpu); + int (*vcpu_reset)(struct kvm_vcpu *vcpu); + + void (*prepare_guest_switch)(struct kvm_vcpu *vcpu); + void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu); + void (*vcpu_put)(struct kvm_vcpu *vcpu); + void (*vcpu_decache)(struct kvm_vcpu *vcpu); + + int (*set_guest_debug)(struct kvm_vcpu *vcpu, + struct kvm_debug_guest *dbg); + void (*guest_debug_pre)(struct kvm_vcpu *vcpu); + int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata); + int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); + u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg); + void (*get_segment)(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg); + int (*get_cpl)(struct kvm_vcpu *vcpu); + void (*set_segment)(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg); + void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l); + void (*decache_cr4_guest_bits)(struct kvm_vcpu *vcpu); + void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0); + void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3); + void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4); + void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer); + void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); + void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); + void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); + void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); + unsigned long (*get_dr)(struct kvm_vcpu *vcpu, int dr); + void (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value, + int *exception); + void (*cache_regs)(struct kvm_vcpu *vcpu); + void (*decache_regs)(struct kvm_vcpu *vcpu); + unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); + void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags); + + void (*tlb_flush)(struct kvm_vcpu *vcpu); + + void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run); + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu); + void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); + void (*patch_hypercall)(struct kvm_vcpu *vcpu, + unsigned char *hypercall_addr); + int (*get_irq)(struct kvm_vcpu *vcpu); + void (*set_irq)(struct kvm_vcpu *vcpu, int vec); + void (*queue_exception)(struct kvm_vcpu *vcpu, unsigned nr, + bool has_error_code, u32 error_code); + bool (*exception_injected)(struct kvm_vcpu *vcpu); + void (*inject_pending_irq)(struct kvm_vcpu *vcpu); + void (*inject_pending_vectors)(struct kvm_vcpu *vcpu, + struct kvm_run *run); + + int (*set_tss_addr)(struct kvm *kvm, unsigned int addr); +}; + +extern struct kvm_x86_ops *kvm_x86_ops; + +int kvm_mmu_module_init(void); +void kvm_mmu_module_exit(void); + +void kvm_mmu_destroy(struct kvm_vcpu *vcpu); +int kvm_mmu_create(struct kvm_vcpu *vcpu); +int kvm_mmu_setup(struct kvm_vcpu *vcpu); +void kvm_mmu_set_nonpresent_ptes(u64 trap_pte, u64 notrap_pte); + +int kvm_mmu_reset_context(struct kvm_vcpu *vcpu); +void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot); +void kvm_mmu_zap_all(struct kvm *kvm); +unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm); +void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages); + +int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3); + +enum emulation_result { + EMULATE_DONE, /* no further processing */ + EMULATE_DO_MMIO, /* kvm_run filled with mmio request */ + EMULATE_FAIL, /* can't emulate this instruction */ +}; + +#define EMULTYPE_NO_DECODE (1 << 0) +#define EMULTYPE_TRAP_UD (1 << 1) +int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run, + unsigned long cr2, u16 error_code, int emulation_type); +void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context); +void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); +void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); +void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, + unsigned long *rflags); + +unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr); +void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value, + unsigned long *rflags); +void kvm_enable_efer_bits(u64); +int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data); +int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); + +struct x86_emulate_ctxt; + +int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned port); +int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned long count, int down, + gva_t address, int rep, unsigned port); +void kvm_emulate_cpuid(struct kvm_vcpu *vcpu); +int kvm_emulate_halt(struct kvm_vcpu *vcpu); +int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); +int emulate_clts(struct kvm_vcpu *vcpu); +int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, + unsigned long *dest); +int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, + unsigned long value); + +void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); +void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0); +void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0); +void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0); +unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu); +void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw); +void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l); + +int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); +int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data); + +void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr); +void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code); +void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2, + u32 error_code); +bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl); + +void fx_init(struct kvm_vcpu *vcpu); + +int emulator_read_std(unsigned long addr, + void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu); +int emulator_write_emulated(unsigned long addr, + const void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu); + +unsigned long segment_base(u16 selector); + +void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu); +void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, + const u8 *new, int bytes); +int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva); +void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); +int kvm_mmu_load(struct kvm_vcpu *vcpu); +void kvm_mmu_unload(struct kvm_vcpu *vcpu); + +int kvm_emulate_hypercall(struct kvm_vcpu *vcpu); + +int kvm_fix_hypercall(struct kvm_vcpu *vcpu); + +int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code); + +void kvm_enable_tdp(void); + +int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3); +int complete_pio(struct kvm_vcpu *vcpu); + +static inline struct kvm_mmu_page *page_header(hpa_t shadow_page) +{ + struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT); + + return (struct kvm_mmu_page *)page_private(page); +} + +static inline u16 read_fs(void) +{ + u16 seg; + asm("mov %%fs, %0" : "=g"(seg)); + return seg; +} + +static inline u16 read_gs(void) +{ + u16 seg; + asm("mov %%gs, %0" : "=g"(seg)); + return seg; +} + +static inline u16 read_ldt(void) +{ + u16 ldt; + asm("sldt %0" : "=g"(ldt)); + return ldt; +} + +static inline void load_fs(u16 sel) +{ + asm("mov %0, %%fs" : : "rm"(sel)); +} + +static inline void load_gs(u16 sel) +{ + asm("mov %0, %%gs" : : "rm"(sel)); +} + +#ifndef load_ldt +static inline void load_ldt(u16 sel) +{ + asm("lldt %0" : : "rm"(sel)); +} +#endif + +static inline void get_idt(struct descriptor_table *table) +{ + asm("sidt %0" : "=m"(*table)); +} + +static inline void get_gdt(struct descriptor_table *table) +{ + asm("sgdt %0" : "=m"(*table)); +} + +static inline unsigned long read_tr_base(void) +{ + u16 tr; + asm("str %0" : "=g"(tr)); + return segment_base(tr); +} + +#ifdef CONFIG_X86_64 +static inline unsigned long read_msr(unsigned long msr) +{ + u64 value; + + rdmsrl(msr, value); + return value; +} +#endif + +static inline void fx_save(struct i387_fxsave_struct *image) +{ + asm("fxsave (%0)":: "r" (image)); +} + +static inline void fx_restore(struct i387_fxsave_struct *image) +{ + asm("fxrstor (%0)":: "r" (image)); +} + +static inline void fpu_init(void) +{ + asm("finit"); +} + +static inline u32 get_rdx_init_val(void) +{ + return 0x600; /* P6 family */ +} + +static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code) +{ + kvm_queue_exception_e(vcpu, GP_VECTOR, error_code); +} + +#define ASM_VMX_VMCLEAR_RAX ".byte 0x66, 0x0f, 0xc7, 0x30" +#define ASM_VMX_VMLAUNCH ".byte 0x0f, 0x01, 0xc2" +#define ASM_VMX_VMRESUME ".byte 0x0f, 0x01, 0xc3" +#define ASM_VMX_VMPTRLD_RAX ".byte 0x0f, 0xc7, 0x30" +#define ASM_VMX_VMREAD_RDX_RAX ".byte 0x0f, 0x78, 0xd0" +#define ASM_VMX_VMWRITE_RAX_RDX ".byte 0x0f, 0x79, 0xd0" +#define ASM_VMX_VMWRITE_RSP_RDX ".byte 0x0f, 0x79, 0xd4" +#define ASM_VMX_VMXOFF ".byte 0x0f, 0x01, 0xc4" +#define ASM_VMX_VMXON_RAX ".byte 0xf3, 0x0f, 0xc7, 0x30" +#define ASM_VMX_INVVPID ".byte 0x66, 0x0f, 0x38, 0x81, 0x08" + +#define MSR_IA32_TIME_STAMP_COUNTER 0x010 + +#define TSS_IOPB_BASE_OFFSET 0x66 +#define TSS_BASE_SIZE 0x68 +#define TSS_IOPB_SIZE (65536 / 8) +#define TSS_REDIRECTION_SIZE (256 / 8) +#define RMODE_TSS_SIZE (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1) + +#endif --- linux-2.6.24.orig/include/asm-x86/seccomp_64.h +++ linux-2.6.24/include/asm-x86/seccomp_64.h @@ -1,13 +1,5 @@ #ifndef _ASM_SECCOMP_H -#include - -#ifdef TIF_32BIT -#error "unexpected TIF_32BIT on x86_64" -#else -#define TIF_32BIT TIF_IA32 -#endif - #include #include --- linux-2.6.24.orig/include/asm-x86/futex_64.h +++ linux-2.6.24/include/asm-x86/futex_64.h @@ -27,7 +27,7 @@ "1: movl %2, %0\n\ movl %0, %3\n" \ insn "\n" \ -"2: " LOCK_PREFIX "cmpxchgl %3, %2\n\ +"2: lock ; cmpxchgl %3, %2\n\ jnz 1b\n\ 3: .section .fixup,\"ax\"\n\ 4: mov %5, %1\n\ @@ -62,7 +62,7 @@ __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ADD: - __futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, oldval, + __futex_atomic_op1("lock ; xaddl %0, %2", ret, oldval, uaddr, oparg); break; case FUTEX_OP_OR: @@ -101,7 +101,7 @@ return -EFAULT; __asm__ __volatile__( - "1: " LOCK_PREFIX "cmpxchgl %3, %1 \n" + "1: lock ; cmpxchgl %3, %1 \n" "2: .section .fixup, \"ax\" \n" "3: mov %2, %0 \n" --- linux-2.6.24.orig/include/asm-x86/lguest_hcall.h +++ linux-2.6.24/include/asm-x86/lguest_hcall.h @@ -4,7 +4,7 @@ #define LHCALL_FLUSH_ASYNC 0 #define LHCALL_LGUEST_INIT 1 -#define LHCALL_CRASH 2 +#define LHCALL_SHUTDOWN 2 #define LHCALL_LOAD_GDT 3 #define LHCALL_NEW_PGTABLE 4 #define LHCALL_FLUSH_TLB 5 @@ -20,6 +20,10 @@ #define LGUEST_TRAP_ENTRY 0x1F +/* Argument number 3 to LHCALL_LGUEST_SHUTDOWN */ +#define LGUEST_SHUTDOWN_POWEROFF 1 +#define LGUEST_SHUTDOWN_RESTART 2 + #ifndef __ASSEMBLY__ #include --- linux-2.6.24.orig/include/asm-x86/io_32.h +++ linux-2.6.24/include/asm-x86/io_32.h @@ -250,10 +250,10 @@ #endif /* __KERNEL__ */ -static inline void native_io_delay(void) -{ - asm volatile("outb %%al,$0x80" : : : "memory"); -} +extern void native_io_delay(void); + +extern int io_delay_type; +extern void io_delay_init(void); #if defined(CONFIG_PARAVIRT) #include --- linux-2.6.24.orig/include/asm-x86/io_64.h +++ linux-2.6.24/include/asm-x86/io_64.h @@ -35,13 +35,20 @@ * - Arnaldo Carvalho de Melo */ -#define __SLOW_DOWN_IO "\noutb %%al,$0x80" +extern void native_io_delay(void); +extern int io_delay_type; +extern void io_delay_init(void); + +static inline void slow_down_io(void) +{ + native_io_delay(); #ifdef REALLY_SLOW_IO -#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO -#else -#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO + native_io_delay(); + native_io_delay(); + native_io_delay(); #endif +} /* * Talk about misusing macros.. @@ -50,21 +57,21 @@ static inline void out##s(unsigned x value, unsigned short port) { #define __OUT2(s,s1,s2) \ -__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" +__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" : : "a" (value), "Nd" (port)) #define __OUT(s,s1,x) \ -__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \ -__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \ +__OUT1(s,x) __OUT2(s,s1,"w"); } \ +__OUT1(s##_p,x) __OUT2(s,s1,"w"); slow_down_io(); } #define __IN1(s) \ static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v; #define __IN2(s,s1,s2) \ -__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" +__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" : "=a" (_v) : "Nd" (port)) -#define __IN(s,s1,i...) \ -__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ -__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ +#define __IN(s,s1) \ +__IN1(s) __IN2(s,s1,"w"); return _v; } \ +__IN1(s##_p) __IN2(s,s1,"w"); slow_down_io(); return _v; } #define __INS(s) \ static inline void ins##s(unsigned short port, void * addr, unsigned long count) \ --- linux-2.6.24.orig/include/asm-x86/processor_64.h +++ linux-2.6.24/include/asm-x86/processor_64.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -76,6 +77,7 @@ __u8 cpu_core_id; /* Core id. */ __u8 cpu_index; /* index into per_cpu list */ #endif + unsigned int x86_hyper_vendor; } ____cacheline_aligned; #define X86_VENDOR_INTEL 0 @@ -88,6 +90,9 @@ #define X86_VENDOR_NUM 8 #define X86_VENDOR_UNKNOWN 0xff +#define X86_HYPER_VENDOR_NONE 0 +#define X86_HYPER_VENDOR_VMWARE 1 + #ifdef CONFIG_SMP DECLARE_PER_CPU(struct cpuinfo_x86, cpu_info); #define cpu_data(cpu) per_cpu(cpu_info, cpu) @@ -335,50 +340,6 @@ struct extended_signature sigs[0]; }; - -#if defined(CONFIG_MPSC) || defined(CONFIG_MCORE2) -#define ASM_NOP1 P6_NOP1 -#define ASM_NOP2 P6_NOP2 -#define ASM_NOP3 P6_NOP3 -#define ASM_NOP4 P6_NOP4 -#define ASM_NOP5 P6_NOP5 -#define ASM_NOP6 P6_NOP6 -#define ASM_NOP7 P6_NOP7 -#define ASM_NOP8 P6_NOP8 -#else -#define ASM_NOP1 K8_NOP1 -#define ASM_NOP2 K8_NOP2 -#define ASM_NOP3 K8_NOP3 -#define ASM_NOP4 K8_NOP4 -#define ASM_NOP5 K8_NOP5 -#define ASM_NOP6 K8_NOP6 -#define ASM_NOP7 K8_NOP7 -#define ASM_NOP8 K8_NOP8 -#endif - -/* Opteron nops */ -#define K8_NOP1 ".byte 0x90\n" -#define K8_NOP2 ".byte 0x66,0x90\n" -#define K8_NOP3 ".byte 0x66,0x66,0x90\n" -#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n" -#define K8_NOP5 K8_NOP3 K8_NOP2 -#define K8_NOP6 K8_NOP3 K8_NOP3 -#define K8_NOP7 K8_NOP4 K8_NOP3 -#define K8_NOP8 K8_NOP4 K8_NOP4 - -/* P6 nops */ -/* uses eax dependencies (Intel-recommended choice) */ -#define P6_NOP1 ".byte 0x90\n" -#define P6_NOP2 ".byte 0x66,0x90\n" -#define P6_NOP3 ".byte 0x0f,0x1f,0x00\n" -#define P6_NOP4 ".byte 0x0f,0x1f,0x40,0\n" -#define P6_NOP5 ".byte 0x0f,0x1f,0x44,0x00,0\n" -#define P6_NOP6 ".byte 0x66,0x0f,0x1f,0x44,0x00,0\n" -#define P6_NOP7 ".byte 0x0f,0x1f,0x80,0,0,0,0\n" -#define P6_NOP8 ".byte 0x0f,0x1f,0x84,0x00,0,0,0,0\n" - -#define ASM_NOP_MAX 8 - /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ static inline void rep_nop(void) { --- linux-2.6.24.orig/include/asm-x86/gart.h +++ linux-2.6.24/include/asm-x86/gart.h @@ -10,6 +10,7 @@ extern void gart_iommu_shutdown(void); extern void __init gart_parse_options(char *); extern void gart_iommu_hole_init(void); +extern void set_up_gart_resume(u32, u32); extern int fallback_aper_order; extern int fallback_aper_force; extern int gart_iommu_aperture; --- linux-2.6.24.orig/include/asm-x86/cpufeature_32.h +++ linux-2.6.24/include/asm-x86/cpufeature_32.h @@ -82,6 +82,9 @@ /* 14 free */ #define X86_FEATURE_SYNC_RDTSC (3*32+15) /* RDTSC synchronizes the CPU */ #define X86_FEATURE_REP_GOOD (3*32+16) /* rep microcode works well on this CPU */ +#define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */ +#define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */ +#define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ #define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ @@ -93,6 +96,7 @@ #define X86_FEATURE_CX16 (4*32+13) /* CMPXCHG16B */ #define X86_FEATURE_XTPR (4*32+14) /* Send Task Priority Messages */ #define X86_FEATURE_DCA (4*32+18) /* Direct Cache Access */ +#define X86_FEATURE_HYPERVISOR (4*32+31) /* Running on a hypervisor */ /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ #define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */ @@ -165,6 +169,7 @@ #define cpu_has_pebs boot_cpu_has(X86_FEATURE_PEBS) #define cpu_has_clflush boot_cpu_has(X86_FEATURE_CLFLSH) #define cpu_has_bts boot_cpu_has(X86_FEATURE_BTS) +#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR) #endif /* __ASM_I386_CPUFEATURE_H */ --- linux-2.6.24.orig/include/asm-x86/kvm_para.h +++ linux-2.6.24/include/asm-x86/kvm_para.h @@ -0,0 +1,130 @@ +#ifndef __X86_KVM_PARA_H +#define __X86_KVM_PARA_H + +/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It + * should be used to determine that a VM is running under KVM. + */ +#define KVM_CPUID_SIGNATURE 0x40000000 + +/* This CPUID returns a feature bitmap in eax. Before enabling a particular + * paravirtualization, the appropriate feature bit should be checked. + */ +#define KVM_CPUID_FEATURES 0x40000001 +#define KVM_FEATURE_CLOCKSOURCE 0 + +#define MSR_KVM_WALL_CLOCK 0x11 +#define MSR_KVM_SYSTEM_TIME 0x12 + +#ifdef __KERNEL__ +#include + +/* xen binary-compatible interface. See xen headers for details */ +struct kvm_vcpu_time_info { + uint32_t version; + uint32_t pad0; + uint64_t tsc_timestamp; + uint64_t system_time; + uint32_t tsc_to_system_mul; + int8_t tsc_shift; + int8_t pad[3]; +} __attribute__((__packed__)); /* 32 bytes */ + +struct kvm_wall_clock { + uint32_t wc_version; + uint32_t wc_sec; + uint32_t wc_nsec; +} __attribute__((__packed__)); + + +extern void kvmclock_init(void); + + +/* This instruction is vmcall. On non-VT architectures, it will generate a + * trap that we will then rewrite to the appropriate instruction. + */ +#define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1" + +/* For KVM hypercalls, a three-byte sequence of either the vmrun or the vmmrun + * instruction. The hypervisor may replace it with something else but only the + * instructions are guaranteed to be supported. + * + * Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively. + * The hypercall number should be placed in rax and the return value will be + * placed in rax. No other registers will be clobbered unless explicited + * noted by the particular hypercall. + */ + +static inline long kvm_hypercall0(unsigned int nr) +{ + long ret; + asm volatile(KVM_HYPERCALL + : "=a"(ret) + : "a"(nr)); + return ret; +} + +static inline long kvm_hypercall1(unsigned int nr, unsigned long p1) +{ + long ret; + asm volatile(KVM_HYPERCALL + : "=a"(ret) + : "a"(nr), "b"(p1)); + return ret; +} + +static inline long kvm_hypercall2(unsigned int nr, unsigned long p1, + unsigned long p2) +{ + long ret; + asm volatile(KVM_HYPERCALL + : "=a"(ret) + : "a"(nr), "b"(p1), "c"(p2)); + return ret; +} + +static inline long kvm_hypercall3(unsigned int nr, unsigned long p1, + unsigned long p2, unsigned long p3) +{ + long ret; + asm volatile(KVM_HYPERCALL + : "=a"(ret) + : "a"(nr), "b"(p1), "c"(p2), "d"(p3)); + return ret; +} + +static inline long kvm_hypercall4(unsigned int nr, unsigned long p1, + unsigned long p2, unsigned long p3, + unsigned long p4) +{ + long ret; + asm volatile(KVM_HYPERCALL + : "=a"(ret) + : "a"(nr), "b"(p1), "c"(p2), "d"(p3), "S"(p4)); + return ret; +} + +static inline int kvm_para_available(void) +{ + unsigned int eax, ebx, ecx, edx; + char signature[13]; + + cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx); + memcpy(signature + 0, &ebx, 4); + memcpy(signature + 4, &ecx, 4); + memcpy(signature + 8, &edx, 4); + signature[12] = 0; + + if (strcmp(signature, "KVMKVMKVM") == 0) + return 1; + + return 0; +} + +static inline unsigned int kvm_arch_para_features(void) +{ + return cpuid_eax(KVM_CPUID_FEATURES); +} + +#endif + +#endif --- linux-2.6.24.orig/include/asm-x86/msr.h +++ linux-2.6.24/include/asm-x86/msr.h @@ -13,6 +13,7 @@ #ifndef __ASSEMBLY__ #include +#include static inline unsigned long long native_read_msr(unsigned int msr) { @@ -69,7 +70,11 @@ static inline unsigned long long native_read_tsc(void) { unsigned long long val; + + rdtsc_barrier(); asm volatile("rdtsc" : "=A" (val)); + rdtsc_barrier(); + return val; } @@ -169,6 +174,7 @@ #ifndef __ASSEMBLY__ #include +#include /* * Access to machine-specific registers (available on 586 and better only) * Note: the rd* operations modify the parameters directly (without using @@ -220,6 +226,17 @@ #define write_rdtscp_aux(val) wrmsr(0xc0000103, val, 0) +static inline unsigned long long native_read_tsc(void) +{ + unsigned long long val; + + rdtsc_barrier(); + rdtscll(val); + rdtsc_barrier(); + + return val; +} + #define rdpmc(counter,low,high) \ __asm__ __volatile__("rdpmc" \ : "=a" (low), "=d" (high) \ --- linux-2.6.24.orig/include/asm-x86/lguest.h +++ linux-2.6.24/include/asm-x86/lguest.h @@ -56,7 +56,7 @@ struct desc_struct guest_gdt[GDT_ENTRIES]; }; -struct lguest_arch +struct lg_cpu_arch { /* The GDT entries copied into lguest_ro_state when running. */ struct desc_struct gdt[GDT_ENTRIES]; --- linux-2.6.24.orig/include/asm-x86/apic_32.h +++ linux-2.6.24/include/asm-x86/apic_32.h @@ -109,7 +109,7 @@ extern void setup_secondary_APIC_clock (void); extern int APIC_init_uniprocessor (void); -extern void enable_NMI_through_LVT0 (void * dummy); +extern void enable_NMI_through_LVT0(void); #define ARCH_APICTIMER_STOPS_ON_C3 1 --- linux-2.6.24.orig/include/asm-x86/system_32.h +++ linux-2.6.24/include/asm-x86/system_32.h @@ -5,6 +5,7 @@ #include #include #include +#include #ifdef __KERNEL__ #define AT_VECTOR_SIZE_ARCH 2 /* entries in ARCH_DLINFO */ @@ -299,6 +300,19 @@ #define set_mb(var, value) do { var = value; barrier(); } while (0) #endif +/* + * Stop RDTSC speculation. This is needed when you need to use RDTSC + * (or get_cycles or vread that possibly accesses the TSC) in a defined + * code region. + * + * (Could use an alternative three way for this if there was one.) + */ +static inline void rdtsc_barrier(void) +{ + alternative(ASM_NOP3, "mfence", X86_FEATURE_MFENCE_RDTSC); + alternative(ASM_NOP3, "lfence", X86_FEATURE_LFENCE_RDTSC); +} + #include /* --- linux-2.6.24.orig/include/asm-x86/pgtable_64.h +++ linux-2.6.24/include/asm-x86/pgtable_64.h @@ -410,6 +410,7 @@ remap_pfn_range(vma, vaddr, pfn, size, prot) #define HAVE_ARCH_UNMAPPED_AREA +#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN #define pgtable_cache_init() do { } while (0) #define check_pgt_cache() do { } while (0) --- linux-2.6.24.orig/include/asm-x86/nops_32.h +++ linux-2.6.24/include/asm-x86/nops_32.h @@ -0,0 +1,91 @@ +#ifndef _ASM_NOPS_H +#define _ASM_NOPS_H + +/* Define nops for use with alternative() */ + +/* generic versions from gas */ +#define GENERIC_NOP1 ".byte 0x90\n" +#define GENERIC_NOP2 ".byte 0x89,0xf6\n" +#define GENERIC_NOP3 ".byte 0x8d,0x76,0x00\n" +#define GENERIC_NOP4 ".byte 0x8d,0x74,0x26,0x00\n" +#define GENERIC_NOP5 GENERIC_NOP1 GENERIC_NOP4 +#define GENERIC_NOP6 ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n" +#define GENERIC_NOP7 ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n" +#define GENERIC_NOP8 GENERIC_NOP1 GENERIC_NOP7 + +/* Opteron nops */ +#define K8_NOP1 GENERIC_NOP1 +#define K8_NOP2 ".byte 0x66,0x90\n" +#define K8_NOP3 ".byte 0x66,0x66,0x90\n" +#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n" +#define K8_NOP5 K8_NOP3 K8_NOP2 +#define K8_NOP6 K8_NOP3 K8_NOP3 +#define K8_NOP7 K8_NOP4 K8_NOP3 +#define K8_NOP8 K8_NOP4 K8_NOP4 + +/* K7 nops */ +/* uses eax dependencies (arbitary choice) */ +#define K7_NOP1 GENERIC_NOP1 +#define K7_NOP2 ".byte 0x8b,0xc0\n" +#define K7_NOP3 ".byte 0x8d,0x04,0x20\n" +#define K7_NOP4 ".byte 0x8d,0x44,0x20,0x00\n" +#define K7_NOP5 K7_NOP4 ASM_NOP1 +#define K7_NOP6 ".byte 0x8d,0x80,0,0,0,0\n" +#define K7_NOP7 ".byte 0x8D,0x04,0x05,0,0,0,0\n" +#define K7_NOP8 K7_NOP7 ASM_NOP1 + +/* P6 nops */ +/* uses eax dependencies (Intel-recommended choice) */ +#define P6_NOP1 GENERIC_NOP1 +#define P6_NOP2 ".byte 0x66,0x90\n" +#define P6_NOP3 ".byte 0x0f,0x1f,0x00\n" +#define P6_NOP4 ".byte 0x0f,0x1f,0x40,0\n" +#define P6_NOP5 ".byte 0x0f,0x1f,0x44,0x00,0\n" +#define P6_NOP6 ".byte 0x66,0x0f,0x1f,0x44,0x00,0\n" +#define P6_NOP7 ".byte 0x0f,0x1f,0x80,0,0,0,0\n" +#define P6_NOP8 ".byte 0x0f,0x1f,0x84,0x00,0,0,0,0\n" + +#ifdef CONFIG_MK8 +#define ASM_NOP1 K8_NOP1 +#define ASM_NOP2 K8_NOP2 +#define ASM_NOP3 K8_NOP3 +#define ASM_NOP4 K8_NOP4 +#define ASM_NOP5 K8_NOP5 +#define ASM_NOP6 K8_NOP6 +#define ASM_NOP7 K8_NOP7 +#define ASM_NOP8 K8_NOP8 +#elif defined(CONFIG_MK7) +#define ASM_NOP1 K7_NOP1 +#define ASM_NOP2 K7_NOP2 +#define ASM_NOP3 K7_NOP3 +#define ASM_NOP4 K7_NOP4 +#define ASM_NOP5 K7_NOP5 +#define ASM_NOP6 K7_NOP6 +#define ASM_NOP7 K7_NOP7 +#define ASM_NOP8 K7_NOP8 +#elif (defined(CONFIG_M686) || defined(CONFIG_MPENTIUMII) || \ + defined(CONFIG_MPENTIUMIII) || defined(CONFIG_MPENTIUMM) || \ + defined(CONFIG_MCORE2) || defined(CONFIG_PENTIUM4)) && \ + !defined(CONFIG_X86_GENERIC) +#define ASM_NOP1 P6_NOP1 +#define ASM_NOP2 P6_NOP2 +#define ASM_NOP3 P6_NOP3 +#define ASM_NOP4 P6_NOP4 +#define ASM_NOP5 P6_NOP5 +#define ASM_NOP6 P6_NOP6 +#define ASM_NOP7 P6_NOP7 +#define ASM_NOP8 P6_NOP8 +#else +#define ASM_NOP1 GENERIC_NOP1 +#define ASM_NOP2 GENERIC_NOP2 +#define ASM_NOP3 GENERIC_NOP3 +#define ASM_NOP4 GENERIC_NOP4 +#define ASM_NOP5 GENERIC_NOP5 +#define ASM_NOP6 GENERIC_NOP6 +#define ASM_NOP7 GENERIC_NOP7 +#define ASM_NOP8 GENERIC_NOP8 +#endif + +#define ASM_NOP_MAX 8 + +#endif --- linux-2.6.24.orig/include/asm-x86/hypervisor.h +++ linux-2.6.24/include/asm-x86/hypervisor.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2008, VMware, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef ASM_X86__HYPERVISOR_H +#define ASM_X86__HYPERVISOR_H + +extern unsigned long get_hypervisor_tsc_freq(void); +extern void init_hypervisor(struct cpuinfo_x86 *c); + +#endif --- linux-2.6.24.orig/include/asm-x86/system_64.h +++ linux-2.6.24/include/asm-x86/system_64.h @@ -4,6 +4,7 @@ #include #include #include +#include #ifdef __KERNEL__ @@ -173,6 +174,19 @@ #define read_barrier_depends() do {} while(0) #define set_mb(var, value) do { (void) xchg(&var, value); } while (0) +/* + * Stop RDTSC speculation. This is needed when you need to use RDTSC + * (or get_cycles or vread that possibly accesses the TSC) in a defined + * code region. + * + * (Could use an alternative three way for this if there was one.) + */ +static inline void rdtsc_barrier(void) +{ + alternative(ASM_NOP3, "mfence", X86_FEATURE_MFENCE_RDTSC); + alternative(ASM_NOP3, "lfence", X86_FEATURE_LFENCE_RDTSC); +} + #define warn_if_not_ulong(x) do { unsigned long foo; (void) (&(x) == &foo); } while (0) #include --- linux-2.6.24.orig/include/asm-x86/e820.h +++ linux-2.6.24/include/asm-x86/e820.h @@ -22,6 +22,9 @@ }; #endif /* __ASSEMBLY__ */ +#define BIOS_BEGIN 0x000a0000 +#define BIOS_END 0x00100000 + #ifdef __KERNEL__ #ifdef CONFIG_X86_32 # include "e820_32.h" --- linux-2.6.24.orig/include/asm-x86/nops.h +++ linux-2.6.24/include/asm-x86/nops.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "nops_32.h" +#else +# include "nops_64.h" +#endif --- linux-2.6.24.orig/include/asm-powerpc/seccomp.h +++ linux-2.6.24/include/asm-powerpc/seccomp.h @@ -1,10 +1,6 @@ #ifndef _ASM_POWERPC_SECCOMP_H #define _ASM_POWERPC_SECCOMP_H -#ifdef __KERNEL__ -#include -#endif - #include #define __NR_seccomp_read __NR_read --- linux-2.6.24.orig/include/asm-powerpc/compat.h +++ linux-2.6.24/include/asm-powerpc/compat.h @@ -210,5 +210,10 @@ compat_ulong_t __unused6; }; +static inline int is_compat_task(void) +{ + return test_thread_flag(TIF_32BIT); +} + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_COMPAT_H */ --- linux-2.6.24.orig/include/asm-powerpc/pmac_feature.h +++ linux-2.6.24/include/asm-powerpc/pmac_feature.h @@ -392,6 +392,14 @@ #define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) #define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) +/* Uninorth variant: + * + * 0 = not uninorth + * 1 = U1.x or U2.x + * 3 = U3 + * 4 = U4 + */ +extern int pmac_get_uninorth_variant(void); #endif /* __ASM_POWERPC_PMAC_FEATURE_H */ #endif /* __KERNEL__ */ --- linux-2.6.24.orig/include/asm-mips/seccomp.h +++ linux-2.6.24/include/asm-mips/seccomp.h @@ -1,6 +1,5 @@ #ifndef __ASM_SECCOMP_H -#include #include #define __NR_seccomp_read __NR_read --- linux-2.6.24.orig/lib/Kconfig.debug +++ linux-2.6.24/lib/Kconfig.debug @@ -517,4 +517,16 @@ help Provide stacktrace filter for fault-injection capabilities +config LATENCYTOP + bool "Latency measuring infrastructure" + select FRAME_POINTER if !MIPS + select KALLSYMS + select KALLSYMS_ALL + select STACKTRACE + depends on SCHEDSTATS + help + Enable this option if you want to use the LatencyTOP tool + to find out which userspace is blocking on what kernel operations. + + source "samples/Kconfig" --- linux-2.6.24.orig/arch/s390/kernel/compat_linux.c +++ linux-2.6.24/arch/s390/kernel/compat_linux.c @@ -844,38 +844,6 @@ u32 offset; }; -/* common code for old and new mmaps */ -static inline long do_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - struct file * file = NULL; - unsigned long error = -EBADF; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) { - /* Result is out of bounds. */ - do_munmap(current->mm, addr, len); - error = -ENOMEM; - } - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - - asmlinkage unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg) { @@ -889,7 +857,8 @@ if (a.offset & ~PAGE_MASK) goto out; - error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); + error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, + a.offset >> PAGE_SHIFT); out: return error; } @@ -902,7 +871,7 @@ if (copy_from_user(&a, arg, sizeof(a))) goto out; - error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); + error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); out: return error; } --- linux-2.6.24.orig/arch/s390/kernel/sys_s390.c +++ linux-2.6.24/arch/s390/kernel/sys_s390.c @@ -49,32 +49,6 @@ return error; } -/* common code for old and new mmaps */ -static inline long do_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - long error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - /* * Perform the select(nd, in, out, ex, tv) and mmap() system * calls. Linux for S/390 isn't able to handle more than 5 @@ -98,7 +72,7 @@ if (copy_from_user(&a, arg, sizeof(a))) goto out; - error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); + error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); out: return error; } @@ -115,7 +89,7 @@ if (a.offset & ~PAGE_MASK) goto out; - error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); + error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); out: return error; } --- linux-2.6.24.orig/arch/s390/lib/uaccess_std.c +++ linux-2.6.24/arch/s390/lib/uaccess_std.c @@ -293,10 +293,10 @@ asm volatile( " sacf 256\n" - " cs %1,%4,0(%5)\n" - "0: lr %0,%1\n" - "1: sacf 0\n" - EX_TABLE(0b,1b) + "0: cs %1,%4,0(%5)\n" + "1: lr %0,%1\n" + "2: sacf 0\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) : "=d" (ret), "+d" (oldval), "=m" (*uaddr) : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr) : "cc", "memory" ); --- linux-2.6.24.orig/arch/s390/lib/uaccess_pt.c +++ linux-2.6.24/arch/s390/lib/uaccess_pt.c @@ -406,6 +406,8 @@ { int ret; + if (!current->mm) + return -EFAULT; spin_lock(¤t->mm->page_table_lock); uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); if (!uaddr) { --- linux-2.6.24.orig/arch/m32r/kernel/sys_m32r.c +++ linux-2.6.24/arch/m32r/kernel/sys_m32r.c @@ -96,30 +96,6 @@ return error; } -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - int error = -EBADF; - struct file *file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - /* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. * --- linux-2.6.24.orig/arch/m32r/kernel/syscall_table.S +++ linux-2.6.24/arch/m32r/kernel/syscall_table.S @@ -191,7 +191,7 @@ .long sys_ni_syscall /* streams2 */ .long sys_vfork /* 190 */ .long sys_getrlimit - .long sys_mmap2 + .long sys_mmap_pgoff .long sys_truncate64 .long sys_ftruncate64 .long sys_stat64 /* 195 */ --- linux-2.6.24.orig/arch/mips/kernel/syscall.c +++ linux-2.6.24/arch/mips/kernel/syscall.c @@ -85,7 +85,8 @@ * We do not accept a shared mapping if it would violate * cache aliasing constraints. */ - if ((flags & MAP_SHARED) && (addr & shm_align_mask)) + if ((flags & MAP_SHARED) && + ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) return -EINVAL; return addr; } @@ -121,31 +122,6 @@ } } -/* common code for old and new mmaps */ -static inline unsigned long -do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flags, unsigned long fd, unsigned long pgoff) -{ - unsigned long error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - asmlinkage unsigned long old_mmap(unsigned long addr, unsigned long len, int prot, int flags, int fd, off_t offset) @@ -156,7 +132,7 @@ if (offset & ~PAGE_MASK) goto out; - result = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + result = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); out: return result; @@ -169,7 +145,7 @@ if (pgoff & (~PAGE_MASK >> 12)) return -EINVAL; - return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12)); + return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12)); } save_static_function(sys_fork); --- linux-2.6.24.orig/arch/mips/kernel/i8259.c +++ linux-2.6.24/arch/mips/kernel/i8259.c @@ -338,8 +338,10 @@ init_8259A(0); - for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++) + for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++) { set_irq_chip_and_handler(i, &i8259A_chip, handle_level_irq); + set_irq_probe(i); + } setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); } --- linux-2.6.24.orig/arch/mips/kernel/irq.c +++ linux-2.6.24/arch/mips/kernel/irq.c @@ -145,6 +145,11 @@ void __init init_IRQ(void) { + int i; + + for (i = 0; i < NR_IRQS; i++) + set_irq_noprobe(i); + arch_init_irq(); #ifdef CONFIG_KGDB --- linux-2.6.24.orig/arch/mips/kernel/linux32.c +++ linux-2.6.24/arch/mips/kernel/linux32.c @@ -103,28 +103,13 @@ sys32_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) { - struct file * file = NULL; unsigned long error; error = -EINVAL; if (pgoff & (~PAGE_MASK >> 12)) goto out; - pgoff >>= PAGE_SHIFT-12; - - if (!(flags & MAP_ANONYMOUS)) { - error = -EBADF; - file = fget(fd); - if (!file) - goto out; - } - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - if (file) - fput(file); - + error = sys_mmap_pgoff(addr, len, prot, flags, fd, + pgoff >> (PAGE_SHIFT-12)); out: return error; } --- linux-2.6.24.orig/arch/avr32/kernel/sys_avr32.c +++ linux-2.6.24/arch/avr32/kernel/sys_avr32.c @@ -5,15 +5,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include -#include -#include -#include #include -#include -#include - asmlinkage int sys_pipe(unsigned long __user *filedes) { int fd[2]; @@ -27,29 +20,6 @@ return error; } -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t offset) -{ - int error = -EBADF; - struct file *file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - return error; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, offset); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); - return error; -} - int kernel_execve(const char *file, char **argv, char **envp) { register long scno asm("r8") = __NR_execve; --- linux-2.6.24.orig/arch/avr32/kernel/syscall-stubs.S +++ linux-2.6.24/arch/avr32/kernel/syscall-stubs.S @@ -61,7 +61,7 @@ __sys_mmap2: pushm lr st.w --sp, ARG6 - rcall sys_mmap2 + rcall sys_mmap_pgoff sub sp, -4 popm pc --- linux-2.6.24.orig/arch/sparc64/kernel/signal.c +++ linux-2.6.24/arch/sparc64/kernel/signal.c @@ -354,7 +354,7 @@ static inline int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) { - unsigned long *fpregs = (unsigned long *)(regs+1); + unsigned long *fpregs = current_thread_info()->fpregs; unsigned long fprs; int err = 0; --- linux-2.6.24.orig/arch/sparc64/kernel/sys_sparc.c +++ linux-2.6.24/arch/sparc64/kernel/sys_sparc.c @@ -540,20 +540,19 @@ return ret; } -int sparc64_mmap_check(unsigned long addr, unsigned long len, - unsigned long flags) +int sparc64_mmap_check(unsigned long addr, unsigned long len) { if (test_thread_flag(TIF_32BIT)) { if (len >= STACK_TOP32) return -EINVAL; - if ((flags & MAP_FIXED) && addr > STACK_TOP32 - len) + if (addr > STACK_TOP32 - len) return -EINVAL; } else { if (len >= VA_EXCLUDE_START) return -EINVAL; - if ((flags & MAP_FIXED) && invalid_64bit_range(addr, len)) + if (invalid_64bit_range(addr, len)) return -EINVAL; } @@ -607,46 +606,19 @@ unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) { - struct vm_area_struct *vma; unsigned long ret = -EINVAL; if (test_thread_flag(TIF_32BIT)) goto out; if (unlikely(new_len >= VA_EXCLUDE_START)) goto out; - if (unlikely(invalid_64bit_range(addr, old_len))) + if (unlikely(sparc64_mmap_check(addr, old_len))) + goto out; + if (unlikely(sparc64_mmap_check(new_addr, new_len))) goto out; down_write(¤t->mm->mmap_sem); - if (flags & MREMAP_FIXED) { - if (invalid_64bit_range(new_addr, new_len)) - goto out_sem; - } else if (invalid_64bit_range(addr, new_len)) { - unsigned long map_flags = 0; - struct file *file = NULL; - - ret = -ENOMEM; - if (!(flags & MREMAP_MAYMOVE)) - goto out_sem; - - vma = find_vma(current->mm, addr); - if (vma) { - if (vma->vm_flags & VM_SHARED) - map_flags |= MAP_SHARED; - file = vma->vm_file; - } - - /* MREMAP_FIXED checked above. */ - new_addr = get_unmapped_area(file, addr, new_len, - vma ? vma->vm_pgoff : 0, - map_flags); - ret = new_addr; - if (new_addr & ~PAGE_MASK) - goto out_sem; - flags |= MREMAP_FIXED; - } ret = do_mremap(addr, old_len, new_len, flags, new_addr); -out_sem: up_write(¤t->mm->mmap_sem); out: return ret; --- linux-2.6.24.orig/arch/sparc64/kernel/ldc.c +++ linux-2.6.24/arch/sparc64/kernel/ldc.c @@ -290,7 +290,8 @@ return p + (lp->tx_tail / LDC_PACKET_SIZE); } -static int set_tx_tail(struct ldc_channel *lp, unsigned long tail) +static int set_tx_tail(struct ldc_channel *lp, + unsigned long tail) { unsigned long orig_tail = lp->tx_tail; int limit = 1000; @@ -314,30 +315,6 @@ return -EBUSY; } -/* This just updates the head value in the hypervisor using - * a polling loop with a timeout. The caller takes care of - * upating software state representing the head change, if any. - */ -static int __set_rx_head(struct ldc_channel *lp, unsigned long head) -{ - int limit = 1000; - - while (limit-- > 0) { - unsigned long err; - - err = sun4v_ldc_rx_set_qhead(lp->id, head); - if (!err) - return 0; - - if (err != HV_EWOULDBLOCK) - return -EINVAL; - - udelay(1); - } - - return -EBUSY; -} - static int send_tx_packet(struct ldc_channel *lp, struct ldc_packet *p, unsigned long new_tail) @@ -818,7 +795,7 @@ * everything. */ if (lp->flags & LDC_FLAG_RESET) { - (void) __set_rx_head(lp, lp->rx_tail); + (void) sun4v_ldc_rx_set_qhead(lp->id, lp->rx_tail); goto out; } @@ -847,7 +824,7 @@ while (lp->rx_head != lp->rx_tail) { struct ldc_packet *p; - unsigned long new; + unsigned long new, hv_err; int err; p = lp->rx_base + (lp->rx_head / LDC_PACKET_SIZE); @@ -882,8 +859,8 @@ new = 0; lp->rx_head = new; - err = __set_rx_head(lp, new); - if (err < 0) { + hv_err = sun4v_ldc_rx_set_qhead(lp->id, new); + if (hv_err) { (void) ldc_abort(lp); break; } @@ -1452,8 +1429,8 @@ new = rx_advance(lp, lp->rx_head); lp->rx_head = new; - err = __set_rx_head(lp, new); - if (err < 0) + hv_err = sun4v_ldc_rx_set_qhead(lp->id, new); + if (hv_err) err = -ECONNRESET; else err = LDC_PACKET_SIZE; @@ -1537,6 +1514,7 @@ static int rx_bad_seq(struct ldc_channel *lp, struct ldc_packet *p, struct ldc_packet *first_frag) { + unsigned long hv_err; int err; if (first_frag) @@ -1546,8 +1524,8 @@ if (err) return err; - err = __set_rx_head(lp, lp->rx_tail); - if (err < 0) + hv_err = sun4v_ldc_rx_set_qhead(lp->id, lp->rx_tail); + if (hv_err) return ldc_abort(lp); return 0; @@ -1601,9 +1579,10 @@ static int rx_set_head(struct ldc_channel *lp, unsigned long head) { - int err = __set_rx_head(lp, head); + unsigned long hv_err; - if (err < 0) + hv_err = sun4v_ldc_rx_set_qhead(lp->id, head); + if (hv_err) return ldc_abort(lp); lp->rx_head = head; --- linux-2.6.24.orig/arch/sparc64/kernel/sys_sparc32.c +++ linux-2.6.24/arch/sparc64/kernel/sys_sparc32.c @@ -910,44 +910,15 @@ unsigned long old_len, unsigned long new_len, unsigned long flags, u32 __new_addr) { - struct vm_area_struct *vma; unsigned long ret = -EINVAL; unsigned long new_addr = __new_addr; - if (old_len > STACK_TOP32 || new_len > STACK_TOP32) + if (unlikely(sparc64_mmap_check(addr, old_len))) goto out; - if (addr > STACK_TOP32 - old_len) + if (unlikely(sparc64_mmap_check(new_addr, new_len))) goto out; down_write(¤t->mm->mmap_sem); - if (flags & MREMAP_FIXED) { - if (new_addr > STACK_TOP32 - new_len) - goto out_sem; - } else if (addr > STACK_TOP32 - new_len) { - unsigned long map_flags = 0; - struct file *file = NULL; - - ret = -ENOMEM; - if (!(flags & MREMAP_MAYMOVE)) - goto out_sem; - - vma = find_vma(current->mm, addr); - if (vma) { - if (vma->vm_flags & VM_SHARED) - map_flags |= MAP_SHARED; - file = vma->vm_file; - } - - /* MREMAP_FIXED checked above. */ - new_addr = get_unmapped_area(file, addr, new_len, - vma ? vma->vm_pgoff : 0, - map_flags); - ret = new_addr; - if (new_addr & ~PAGE_MASK) - goto out_sem; - flags |= MREMAP_FIXED; - } ret = do_mremap(addr, old_len, new_len, flags, new_addr); -out_sem: up_write(¤t->mm->mmap_sem); out: return ret; --- linux-2.6.24.orig/arch/sparc64/kernel/pci_common.c +++ linux-2.6.24/arch/sparc64/kernel/pci_common.c @@ -374,7 +374,7 @@ const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL); if (vdma) { - struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL); + struct resource *rp = kzalloc(sizeof(*rp), GFP_KERNEL); if (!rp) { prom_printf("Cannot allocate IOMMU resource.\n"); --- linux-2.6.24.orig/arch/sparc64/kernel/ptrace.c +++ linux-2.6.24/arch/sparc64/kernel/ptrace.c @@ -127,6 +127,8 @@ if (tlb_type == hypervisor) return; + preempt_disable(); + #ifdef DCACHE_ALIASING_POSSIBLE /* If bit 13 of the kernel address we used to access the * user page is the same as the virtual address that page @@ -165,6 +167,8 @@ for (; start < end; start += icache_line_size) flushi(start); } + + preempt_enable(); } asmlinkage void do_ptrace(struct pt_regs *regs) --- linux-2.6.24.orig/arch/sparc64/lib/rwsem.S +++ linux-2.6.24/arch/sparc64/lib/rwsem.S @@ -6,7 +6,7 @@ #include - .section .sched.text + .section .sched.text, "ax" .globl __down_read __down_read: --- linux-2.6.24.orig/arch/sparc64/mm/tlb.c +++ linux-2.6.24/arch/sparc64/mm/tlb.c @@ -23,10 +23,11 @@ void flush_tlb_pending(void) { - struct mmu_gather *mp = &__get_cpu_var(mmu_gathers); + struct mmu_gather *mp; preempt_disable(); + mp = &__get_cpu_var(mmu_gathers); if (mp->tlb_nr) { flush_tsb_user(mp); --- linux-2.6.24.orig/arch/sparc64/mm/fault.c +++ linux-2.6.24/arch/sparc64/mm/fault.c @@ -244,16 +244,8 @@ if (regs->tstate & TSTATE_PRIV) { const struct exception_table_entry *entry; - if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) { - if (insn & 0x2000) - asi = (regs->tstate >> 24); - else - asi = (insn >> 5); - } - - /* Look in asi.h: All _S asis have LS bit set */ - if ((asi & 0x1) && - (entry = search_exception_tables(regs->tpc))) { + entry = search_exception_tables(regs->tpc); + if (entry) { regs->tpc = entry->fixup; regs->tnpc = regs->tpc + 4; return; @@ -294,7 +286,7 @@ unsigned long tpc = regs->tpc; /* Sanity check the PC. */ - if ((tpc >= KERNBASE && tpc < (unsigned long) _etext) || + if ((tpc >= KERNBASE && tpc < (unsigned long) __init_end) || (tpc >= MODULES_VADDR && tpc < MODULES_END)) { /* Valid, no problems... */ } else { --- linux-2.6.24.orig/arch/frv/kernel/sys_frv.c +++ linux-2.6.24/arch/frv/kernel/sys_frv.c @@ -49,9 +49,6 @@ unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) { - int error = -EBADF; - struct file * file = NULL; - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); @@ -67,62 +64,9 @@ if (pgoff & ((1<<(PAGE_SHIFT-12))-1)) return -EINVAL; - pgoff >>= (PAGE_SHIFT - 12); - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - -#if 0 /* DAVIDM - do we want this */ -struct mmap_arg_struct64 { - __u32 addr; - __u32 len; - __u32 prot; - __u32 flags; - __u64 offset; /* 64 bits */ - __u32 fd; -}; - -asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg) -{ - int error = -EFAULT; - struct file * file = NULL; - struct mmap_arg_struct64 a; - unsigned long pgoff; - - if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; - - if ((long)a.offset & ~PAGE_MASK) - return -EINVAL; - - pgoff = a.offset >> PAGE_SHIFT; - if ((a.offset >> PAGE_SHIFT) != pgoff) - return -EINVAL; - - if (!(a.flags & MAP_ANONYMOUS)) { - error = -EBADF; - file = fget(a.fd); - if (!file) - goto out; - } - a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); - up_write(¤t->mm->mmap_sem); - if (file) - fput(file); -out: - return error; + return sys_mmap_pgoff(addr, len, prot, flags, fd, + pgoff >> (PAGE_SHIFT - 12)); } -#endif /* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. --- linux-2.6.24.orig/arch/arm/mach-pxa/clock.c +++ linux-2.6.24/arch/arm/mach-pxa/clock.c @@ -23,18 +23,27 @@ static DEFINE_MUTEX(clocks_mutex); static DEFINE_SPINLOCK(clocks_lock); +static struct clk *clk_lookup(struct device *dev, const char *id) +{ + struct clk *p; + + list_for_each_entry(p, &clocks, node) + if (strcmp(id, p->name) == 0 && p->dev == dev) + return p; + + return NULL; +} + struct clk *clk_get(struct device *dev, const char *id) { struct clk *p, *clk = ERR_PTR(-ENOENT); mutex_lock(&clocks_mutex); - list_for_each_entry(p, &clocks, node) { - if (strcmp(id, p->name) == 0 && - (p->dev == NULL || p->dev == dev)) { - clk = p; - break; - } - } + p = clk_lookup(dev, id); + if (!p) + p = clk_lookup(NULL, id); + if (p) + clk = p; mutex_unlock(&clocks_mutex); return clk; --- linux-2.6.24.orig/arch/arm/kernel/entry-common.S +++ linux-2.6.24/arch/arm/kernel/entry-common.S @@ -344,12 +344,12 @@ tst r5, #PGOFF_MASK moveq r5, r5, lsr #PAGE_SHIFT - 12 streq r5, [sp, #4] - beq do_mmap2 + beq sys_mmap_pgoff mov r0, #-EINVAL mov pc, lr #else str r5, [sp, #4] - b do_mmap2 + b sys_mmap_pgoff #endif #ifdef CONFIG_OABI_COMPAT --- linux-2.6.24.orig/arch/arm/kernel/sys_arm.c +++ linux-2.6.24/arch/arm/kernel/sys_arm.c @@ -30,10 +30,6 @@ #include -extern unsigned long do_mremap(unsigned long addr, unsigned long old_len, - unsigned long new_len, unsigned long flags, - unsigned long new_addr); - /* * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. @@ -51,37 +47,6 @@ return error; } -/* common code for old and new mmaps */ -inline long do_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - int error = -EINVAL; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - if (flags & MAP_FIXED && addr < FIRST_USER_ADDRESS) - goto out; - - error = -EBADF; - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - struct mmap_arg_struct { unsigned long addr; unsigned long len; @@ -103,29 +68,11 @@ if (a.offset & ~PAGE_MASK) goto out; - error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); + error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); out: return error; } -asmlinkage unsigned long -sys_arm_mremap(unsigned long addr, unsigned long old_len, - unsigned long new_len, unsigned long flags, - unsigned long new_addr) -{ - unsigned long ret = -EINVAL; - - if (flags & MREMAP_FIXED && new_addr < FIRST_USER_ADDRESS) - goto out; - - down_write(¤t->mm->mmap_sem); - ret = do_mremap(addr, old_len, new_len, flags, new_addr); - up_write(¤t->mm->mmap_sem); - -out: - return ret; -} - /* * Perform the select(nd, in, out, ex, tv) and mmap() system * calls. --- linux-2.6.24.orig/arch/arm/kernel/calls.S +++ linux-2.6.24/arch/arm/kernel/calls.S @@ -172,7 +172,7 @@ /* 160 */ CALL(sys_sched_get_priority_min) CALL(sys_sched_rr_get_interval) CALL(sys_nanosleep) - CALL(sys_arm_mremap) + CALL(sys_mremap) CALL(sys_setresuid16) /* 165 */ CALL(sys_getresuid16) CALL(sys_ni_syscall) /* vm86 */ --- linux-2.6.24.orig/arch/arm/mm/mmap.c +++ linux-2.6.24/arch/arm/mm/mmap.c @@ -52,7 +52,8 @@ * We enforce the MAP_FIXED case. */ if (flags & MAP_FIXED) { - if (aliasing && flags & MAP_SHARED && addr & (SHMLBA - 1)) + if (aliasing && flags & MAP_SHARED && + (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)) return -EINVAL; return addr; } --- linux-2.6.24.orig/arch/ia64/kernel/sys_ia64.c +++ linux-2.6.24/arch/ia64/kernel/sys_ia64.c @@ -100,51 +100,7 @@ asmlinkage unsigned long ia64_brk (unsigned long brk) { - unsigned long rlim, retval, newbrk, oldbrk; - struct mm_struct *mm = current->mm; - - /* - * Most of this replicates the code in sys_brk() except for an additional safety - * check and the clearing of r8. However, we can't call sys_brk() because we need - * to acquire the mmap_sem before we can do the test... - */ - down_write(&mm->mmap_sem); - - if (brk < mm->end_code) - goto out; - newbrk = PAGE_ALIGN(brk); - oldbrk = PAGE_ALIGN(mm->brk); - if (oldbrk == newbrk) - goto set_brk; - - /* Always allow shrinking brk. */ - if (brk <= mm->brk) { - if (!do_munmap(mm, newbrk, oldbrk-newbrk)) - goto set_brk; - goto out; - } - - /* Check against unimplemented/unmapped addresses: */ - if ((newbrk - oldbrk) > RGN_MAP_LIMIT || REGION_OFFSET(newbrk) > RGN_MAP_LIMIT) - goto out; - - /* Check against rlimit.. */ - rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur; - if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim) - goto out; - - /* Check against existing mmap mappings. */ - if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) - goto out; - - /* Ok, looks good - let it rip. */ - if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk) - goto out; -set_brk: - mm->brk = brk; -out: - retval = mm->brk; - up_write(&mm->mmap_sem); + unsigned long retval = sys_brk(brk); force_successful_syscall_return(); return retval; } @@ -185,39 +141,6 @@ return 0; } -static inline unsigned long -do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff) -{ - struct file *file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - return -EBADF; - - if (!file->f_op || !file->f_op->mmap) { - addr = -ENODEV; - goto out; - } - } - - /* Careful about overflows.. */ - len = PAGE_ALIGN(len); - if (!len || len > TASK_SIZE) { - addr = -EINVAL; - goto out; - } - - down_write(¤t->mm->mmap_sem); - addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - -out: if (file) - fput(file); - return addr; -} - /* * mmap2() is like mmap() except that the offset is expressed in units * of PAGE_SIZE (instead of bytes). This allows to mmap2() (pieces @@ -226,7 +149,7 @@ asmlinkage unsigned long sys_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, long pgoff) { - addr = do_mmap2(addr, len, prot, flags, fd, pgoff); + addr = sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); if (!IS_ERR((void *) addr)) force_successful_syscall_return(); return addr; @@ -238,7 +161,7 @@ if (offset_in_page(off) != 0) return -EINVAL; - addr = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); + addr = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); if (!IS_ERR((void *) addr)) force_successful_syscall_return(); return addr; --- linux-2.6.24.orig/arch/ia64/pci/pci.c +++ linux-2.6.24/arch/ia64/pci/pci.c @@ -371,7 +371,12 @@ info.name = name; acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window, &info); - + /* + * See arch/x86/pci/acpi.c. + * The desired pci bus might already be scanned in a quirk. We + * should handle the case here, but it appears that IA64 hasn't + * such quirk. So we just ignore the case now. + */ pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller); if (pbus) pcibios_setup_root_windows(pbus, controller); --- linux-2.6.24.orig/arch/ia64/ia32/binfmt_elf32.c +++ linux-2.6.24/arch/ia64/ia32/binfmt_elf32.c @@ -222,7 +222,7 @@ } static unsigned long -elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) +elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type, unsigned long unused) { unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK; --- linux-2.6.24.orig/arch/sparc/kernel/sys_sparc.c +++ linux-2.6.24/arch/sparc/kernel/sys_sparc.c @@ -46,7 +46,8 @@ /* We do not accept a shared mapping if it would violate * cache aliasing constraints. */ - if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1))) + if ((flags & MAP_SHARED) && + ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) return -EINVAL; return addr; } @@ -80,15 +81,6 @@ } } -asmlinkage unsigned long sparc_brk(unsigned long brk) -{ - if(ARCH_SUN4C_SUN4) { - if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000)) - return current->mm->brk; - } - return sys_brk(brk); -} - /* * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. @@ -220,12 +212,11 @@ return err; } -int sparc_mmap_check(unsigned long addr, unsigned long len, unsigned long flags) +int sparc_mmap_check(unsigned long addr, unsigned long len) { if (ARCH_SUN4C_SUN4 && (len > 0x20000000 || - ((flags & MAP_FIXED) && - addr < 0xe0000000 && addr + len > 0x20000000))) + (addr < 0xe0000000 && addr + len > 0x20000000))) return -EINVAL; /* See asm-sparc/uaccess.h */ @@ -236,31 +227,6 @@ } /* Linux version of mmap */ -static unsigned long do_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, unsigned long fd, - unsigned long pgoff) -{ - struct file * file = NULL; - unsigned long retval = -EBADF; - - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - len = PAGE_ALIGN(len); - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - down_write(¤t->mm->mmap_sem); - retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return retval; -} asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, @@ -268,14 +234,16 @@ { /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE we have. */ - return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12)); + return sys_mmap_pgoff(addr, len, prot, flags, fd, + pgoff >> (PAGE_SHIFT - 12)); } asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off) { - return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); + /* no alignment check? */ + return sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); } long sparc_remap_file_pages(unsigned long start, unsigned long size, @@ -289,65 +257,6 @@ (pgoff >> (PAGE_SHIFT - 12)), flags); } -extern unsigned long do_mremap(unsigned long addr, - unsigned long old_len, unsigned long new_len, - unsigned long flags, unsigned long new_addr); - -asmlinkage unsigned long sparc_mremap(unsigned long addr, - unsigned long old_len, unsigned long new_len, - unsigned long flags, unsigned long new_addr) -{ - struct vm_area_struct *vma; - unsigned long ret = -EINVAL; - if (ARCH_SUN4C_SUN4) { - if (old_len > 0x20000000 || new_len > 0x20000000) - goto out; - if (addr < 0xe0000000 && addr + old_len > 0x20000000) - goto out; - } - if (old_len > TASK_SIZE - PAGE_SIZE || - new_len > TASK_SIZE - PAGE_SIZE) - goto out; - down_write(¤t->mm->mmap_sem); - if (flags & MREMAP_FIXED) { - if (ARCH_SUN4C_SUN4 && - new_addr < 0xe0000000 && - new_addr + new_len > 0x20000000) - goto out_sem; - if (new_addr + new_len > TASK_SIZE - PAGE_SIZE) - goto out_sem; - } else if ((ARCH_SUN4C_SUN4 && addr < 0xe0000000 && - addr + new_len > 0x20000000) || - addr + new_len > TASK_SIZE - PAGE_SIZE) { - unsigned long map_flags = 0; - struct file *file = NULL; - - ret = -ENOMEM; - if (!(flags & MREMAP_MAYMOVE)) - goto out_sem; - - vma = find_vma(current->mm, addr); - if (vma) { - if (vma->vm_flags & VM_SHARED) - map_flags |= MAP_SHARED; - file = vma->vm_file; - } - - new_addr = get_unmapped_area(file, addr, new_len, - vma ? vma->vm_pgoff : 0, - map_flags); - ret = new_addr; - if (new_addr & ~PAGE_MASK) - goto out_sem; - flags |= MREMAP_FIXED; - } - ret = do_mremap(addr, old_len, new_len, flags, new_addr); -out_sem: - up_write(¤t->mm->mmap_sem); -out: - return ret; -} - /* we come to here via sys_nis_syscall so it can setup the regs argument */ asmlinkage unsigned long c_sys_nis_syscall (struct pt_regs *regs) --- linux-2.6.24.orig/arch/sparc/kernel/una_asm.S +++ linux-2.6.24/arch/sparc/kernel/una_asm.S @@ -0,0 +1,153 @@ +/* una_asm.S: Kernel unaligned trap assembler helpers. + * + * Copyright (C) 1996,2005,2008 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include + + .text + +retl_efault: + retl + mov -EFAULT, %o0 + + /* int __do_int_store(unsigned long *dst_addr, int size, + * unsigned long *src_val) + * + * %o0 = dest_addr + * %o1 = size + * %o2 = src_val + * + * Return '0' on success, -EFAULT on failure. + */ + .globl __do_int_store +__do_int_store: + ld [%o2], %g1 + cmp %1, 2 + be 2f + cmp %1, 4 + be 1f + srl %g1, 24, %g2 + srl %g1, 16, %g7 +4: stb %g2, [%o0] + srl %g1, 8, %g2 +5: stb %g7, [%o0 + 1] + ld [%o2 + 4], %g7 +6: stb %g2, [%o0 + 2] + srl %g7, 24, %g2 +7: stb %g1, [%o0 + 3] + srl %g7, 16, %g1 +8: stb %g2, [%o0 + 4] + srl %g7, 8, %g2 +9: stb %g1, [%o0 + 5] +10: stb %g2, [%o0 + 6] + b 0f +11: stb %g7, [%o0 + 7] +1: srl %g1, 16, %g7 +12: stb %g2, [%o0] + srl %g1, 8, %g2 +13: stb %g7, [%o0 + 1] +14: stb %g2, [%o0 + 2] + b 0f +15: stb %g1, [%o0 + 3] +2: srl %g1, 8, %g2 +16: stb %g2, [%o0] +17: stb %g1, [%o0 + 1] +0: retl + mov 0, %o0 + + .section __ex_table,#alloc + .word 4b, retl_efault + .word 5b, retl_efault + .word 6b, retl_efault + .word 7b, retl_efault + .word 8b, retl_efault + .word 9b, retl_efault + .word 10b, retl_efault + .word 11b, retl_efault + .word 12b, retl_efault + .word 13b, retl_efault + .word 14b, retl_efault + .word 15b, retl_efault + .word 16b, retl_efault + .word 17b, retl_efault + .previous + + /* int do_int_load(unsigned long *dest_reg, int size, + * unsigned long *saddr, int is_signed) + * + * %o0 = dest_reg + * %o1 = size + * %o2 = saddr + * %o3 = is_signed + * + * Return '0' on success, -EFAULT on failure. + */ + .globl do_int_load +do_int_load: + cmp %o1, 8 + be 9f + cmp %o1, 4 + be 6f +4: ldub [%o2], %g1 +5: ldub [%o2 + 1], %g2 + sll %g1, 8, %g1 + tst %o3 + be 3f + or %g1, %g2, %g1 + sll %g1, 16, %g1 + sra %g1, 16, %g1 +3: b 0f + st %g1, [%o0] +6: ldub [%o2 + 1], %g2 + sll %g1, 24, %g1 +7: ldub [%o2 + 2], %g7 + sll %g2, 16, %g2 +8: ldub [%o2 + 3], %g3 + sll %g7, 8, %g7 + or %g3, %g2, %g3 + or %g7, %g3, %g7 + or %g1, %g7, %g1 + b 0f + st %g1, [%o0] +9: ldub [%o2], %g1 +10: ldub [%o2 + 1], %g2 + sll %g1, 24, %g1 +11: ldub [%o2 + 2], %g7 + sll %g2, 16, %g2 +12: ldub [%o2 + 3], %g3 + sll %g7, 8, %g7 + or %g1, %g2, %g1 + or %g7, %g3, %g7 + or %g1, %g7, %g7 +13: ldub [%o2 + 4], %g1 + st %g7, [%o0] +14: ldub [%o2 + 5], %g2 + sll %g1, 24, %g1 +15: ldub [%o2 + 6], %g7 + sll %g2, 16, %g2 +16: ldub [%o2 + 7], %g3 + sll %g7, 8, %g7 + or %g1, %g2, %g1 + or %g7, %g3, %g7 + or %g1, %g7, %g7 + st %g7, [%o0 + 4] +0: retl + mov 0, %o0 + + .section __ex_table,#alloc + .word 4b, retl_efault + .word 5b, retl_efault + .word 6b, retl_efault + .word 7b, retl_efault + .word 8b, retl_efault + .word 9b, retl_efault + .word 10b, retl_efault + .word 11b, retl_efault + .word 12b, retl_efault + .word 13b, retl_efault + .word 14b, retl_efault + .word 15b, retl_efault + .word 16b, retl_efault + .previous --- linux-2.6.24.orig/arch/sparc/kernel/unaligned.c +++ linux-2.6.24/arch/sparc/kernel/unaligned.c @@ -175,157 +175,31 @@ panic(str); } -#define do_integer_load(dest_reg, size, saddr, is_signed, errh) ({ \ -__asm__ __volatile__ ( \ - "cmp %1, 8\n\t" \ - "be 9f\n\t" \ - " cmp %1, 4\n\t" \ - "be 6f\n" \ -"4:\t" " ldub [%2], %%l1\n" \ -"5:\t" "ldub [%2 + 1], %%l2\n\t" \ - "sll %%l1, 8, %%l1\n\t" \ - "tst %3\n\t" \ - "be 3f\n\t" \ - " add %%l1, %%l2, %%l1\n\t" \ - "sll %%l1, 16, %%l1\n\t" \ - "sra %%l1, 16, %%l1\n" \ -"3:\t" "b 0f\n\t" \ - " st %%l1, [%0]\n" \ -"6:\t" "ldub [%2 + 1], %%l2\n\t" \ - "sll %%l1, 24, %%l1\n" \ -"7:\t" "ldub [%2 + 2], %%g7\n\t" \ - "sll %%l2, 16, %%l2\n" \ -"8:\t" "ldub [%2 + 3], %%g1\n\t" \ - "sll %%g7, 8, %%g7\n\t" \ - "or %%l1, %%l2, %%l1\n\t" \ - "or %%g7, %%g1, %%g7\n\t" \ - "or %%l1, %%g7, %%l1\n\t" \ - "b 0f\n\t" \ - " st %%l1, [%0]\n" \ -"9:\t" "ldub [%2], %%l1\n" \ -"10:\t" "ldub [%2 + 1], %%l2\n\t" \ - "sll %%l1, 24, %%l1\n" \ -"11:\t" "ldub [%2 + 2], %%g7\n\t" \ - "sll %%l2, 16, %%l2\n" \ -"12:\t" "ldub [%2 + 3], %%g1\n\t" \ - "sll %%g7, 8, %%g7\n\t" \ - "or %%l1, %%l2, %%l1\n\t" \ - "or %%g7, %%g1, %%g7\n\t" \ - "or %%l1, %%g7, %%g7\n" \ -"13:\t" "ldub [%2 + 4], %%l1\n\t" \ - "st %%g7, [%0]\n" \ -"14:\t" "ldub [%2 + 5], %%l2\n\t" \ - "sll %%l1, 24, %%l1\n" \ -"15:\t" "ldub [%2 + 6], %%g7\n\t" \ - "sll %%l2, 16, %%l2\n" \ -"16:\t" "ldub [%2 + 7], %%g1\n\t" \ - "sll %%g7, 8, %%g7\n\t" \ - "or %%l1, %%l2, %%l1\n\t" \ - "or %%g7, %%g1, %%g7\n\t" \ - "or %%l1, %%g7, %%g7\n\t" \ - "st %%g7, [%0 + 4]\n" \ -"0:\n\n\t" \ - ".section __ex_table,#alloc\n\t" \ - ".word 4b, " #errh "\n\t" \ - ".word 5b, " #errh "\n\t" \ - ".word 6b, " #errh "\n\t" \ - ".word 7b, " #errh "\n\t" \ - ".word 8b, " #errh "\n\t" \ - ".word 9b, " #errh "\n\t" \ - ".word 10b, " #errh "\n\t" \ - ".word 11b, " #errh "\n\t" \ - ".word 12b, " #errh "\n\t" \ - ".word 13b, " #errh "\n\t" \ - ".word 14b, " #errh "\n\t" \ - ".word 15b, " #errh "\n\t" \ - ".word 16b, " #errh "\n\n\t" \ - ".previous\n\t" \ - : : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed) \ - : "l1", "l2", "g7", "g1", "cc"); \ -}) - -#define store_common(dst_addr, size, src_val, errh) ({ \ -__asm__ __volatile__ ( \ - "ld [%2], %%l1\n" \ - "cmp %1, 2\n\t" \ - "be 2f\n\t" \ - " cmp %1, 4\n\t" \ - "be 1f\n\t" \ - " srl %%l1, 24, %%l2\n\t" \ - "srl %%l1, 16, %%g7\n" \ -"4:\t" "stb %%l2, [%0]\n\t" \ - "srl %%l1, 8, %%l2\n" \ -"5:\t" "stb %%g7, [%0 + 1]\n\t" \ - "ld [%2 + 4], %%g7\n" \ -"6:\t" "stb %%l2, [%0 + 2]\n\t" \ - "srl %%g7, 24, %%l2\n" \ -"7:\t" "stb %%l1, [%0 + 3]\n\t" \ - "srl %%g7, 16, %%l1\n" \ -"8:\t" "stb %%l2, [%0 + 4]\n\t" \ - "srl %%g7, 8, %%l2\n" \ -"9:\t" "stb %%l1, [%0 + 5]\n" \ -"10:\t" "stb %%l2, [%0 + 6]\n\t" \ - "b 0f\n" \ -"11:\t" " stb %%g7, [%0 + 7]\n" \ -"1:\t" "srl %%l1, 16, %%g7\n" \ -"12:\t" "stb %%l2, [%0]\n\t" \ - "srl %%l1, 8, %%l2\n" \ -"13:\t" "stb %%g7, [%0 + 1]\n" \ -"14:\t" "stb %%l2, [%0 + 2]\n\t" \ - "b 0f\n" \ -"15:\t" " stb %%l1, [%0 + 3]\n" \ -"2:\t" "srl %%l1, 8, %%l2\n" \ -"16:\t" "stb %%l2, [%0]\n" \ -"17:\t" "stb %%l1, [%0 + 1]\n" \ -"0:\n\n\t" \ - ".section __ex_table,#alloc\n\t" \ - ".word 4b, " #errh "\n\t" \ - ".word 5b, " #errh "\n\t" \ - ".word 6b, " #errh "\n\t" \ - ".word 7b, " #errh "\n\t" \ - ".word 8b, " #errh "\n\t" \ - ".word 9b, " #errh "\n\t" \ - ".word 10b, " #errh "\n\t" \ - ".word 11b, " #errh "\n\t" \ - ".word 12b, " #errh "\n\t" \ - ".word 13b, " #errh "\n\t" \ - ".word 14b, " #errh "\n\t" \ - ".word 15b, " #errh "\n\t" \ - ".word 16b, " #errh "\n\t" \ - ".word 17b, " #errh "\n\n\t" \ - ".previous\n\t" \ - : : "r" (dst_addr), "r" (size), "r" (src_val) \ - : "l1", "l2", "g7", "g1", "cc"); \ -}) - -#define do_integer_store(reg_num, size, dst_addr, regs, errh) ({ \ - unsigned long *src_val; \ - static unsigned long zero[2] = { 0, }; \ - \ - if (reg_num) src_val = fetch_reg_addr(reg_num, regs); \ - else { \ - src_val = &zero[0]; \ - if (size == 8) \ - zero[1] = fetch_reg(1, regs); \ - } \ - store_common(dst_addr, size, src_val, errh); \ -}) +/* una_asm.S */ +extern int do_int_load(unsigned long *dest_reg, int size, + unsigned long *saddr, int is_signed); +extern int __do_int_store(unsigned long *dst_addr, int size, + unsigned long *src_val); + +static int do_int_store(int reg_num, int size, unsigned long *dst_addr, + struct pt_regs *regs) +{ + unsigned long zero[2] = { 0, 0 }; + unsigned long *src_val; + + if (reg_num) + src_val = fetch_reg_addr(reg_num, regs); + else { + src_val = &zero[0]; + if (size == 8) + zero[1] = fetch_reg(1, regs); + } + return __do_int_store(dst_addr, size, src_val); +} extern void smp_capture(void); extern void smp_release(void); -#define do_atomic(srcdest_reg, mem, errh) ({ \ - unsigned long flags, tmp; \ - \ - smp_capture(); \ - local_irq_save(flags); \ - tmp = *srcdest_reg; \ - do_integer_load(srcdest_reg, 4, mem, 0, errh); \ - store_common(mem, 4, &tmp, errh); \ - local_irq_restore(flags); \ - smp_release(); \ -}) - static inline void advance(struct pt_regs *regs) { regs->pc = regs->npc; @@ -342,9 +216,7 @@ return !floating_point_load_or_store_p(insn); } -void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("kernel_mna_trap_fault"); - -void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) +static void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) { unsigned long g2 = regs->u_regs [UREG_G2]; unsigned long fixup = search_extables_range(regs->pc, &g2); @@ -379,48 +251,34 @@ printk("Unsupported unaligned load/store trap for kernel at <%08lx>.\n", regs->pc); unaligned_panic("Wheee. Kernel does fpu/atomic unaligned load/store."); - - __asm__ __volatile__ ("\n" -"kernel_unaligned_trap_fault:\n\t" - "mov %0, %%o0\n\t" - "call kernel_mna_trap_fault\n\t" - " mov %1, %%o1\n\t" - : - : "r" (regs), "r" (insn) - : "o0", "o1", "o2", "o3", "o4", "o5", "o7", - "g1", "g2", "g3", "g4", "g5", "g7", "cc"); } else { unsigned long addr = compute_effective_address(regs, insn); + int err; #ifdef DEBUG_MNA printk("KMNA: pc=%08lx [dir=%s addr=%08lx size=%d] retpc[%08lx]\n", regs->pc, dirstrings[dir], addr, size, regs->u_regs[UREG_RETPC]); #endif - switch(dir) { + switch (dir) { case load: - do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs), - size, (unsigned long *) addr, - decode_signedness(insn), - kernel_unaligned_trap_fault); + err = do_int_load(fetch_reg_addr(((insn>>25)&0x1f), + regs), + size, (unsigned long *) addr, + decode_signedness(insn)); break; case store: - do_integer_store(((insn>>25)&0x1f), size, - (unsigned long *) addr, regs, - kernel_unaligned_trap_fault); - break; -#if 0 /* unsupported */ - case both: - do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs), - (unsigned long *) addr, - kernel_unaligned_trap_fault); + err = do_int_store(((insn>>25)&0x1f), size, + (unsigned long *) addr, regs); break; -#endif default: panic("Impossible kernel unaligned trap."); /* Not reached... */ } - advance(regs); + if (err) + kernel_mna_trap_fault(regs, insn); + else + advance(regs); } } @@ -459,9 +317,7 @@ return 0; } -void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("user_mna_trap_fault"); - -void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) +static void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) { siginfo_t info; @@ -485,7 +341,7 @@ if(!ok_for_user(regs, insn, dir)) { goto kill_user; } else { - int size = decode_access_size(insn); + int err, size = decode_access_size(insn); unsigned long addr; if(floating_point_load_or_store_p(insn)) { @@ -496,48 +352,34 @@ addr = compute_effective_address(regs, insn); switch(dir) { case load: - do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs), - size, (unsigned long *) addr, - decode_signedness(insn), - user_unaligned_trap_fault); + err = do_int_load(fetch_reg_addr(((insn>>25)&0x1f), + regs), + size, (unsigned long *) addr, + decode_signedness(insn)); break; case store: - do_integer_store(((insn>>25)&0x1f), size, - (unsigned long *) addr, regs, - user_unaligned_trap_fault); + err = do_int_store(((insn>>25)&0x1f), size, + (unsigned long *) addr, regs); break; case both: -#if 0 /* unsupported */ - do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs), - (unsigned long *) addr, - user_unaligned_trap_fault); -#else /* * This was supported in 2.4. However, we question * the value of SWAP instruction across word boundaries. */ printk("Unaligned SWAP unsupported.\n"); - goto kill_user; -#endif + err = -EFAULT; break; default: unaligned_panic("Impossible user unaligned trap."); - - __asm__ __volatile__ ("\n" -"user_unaligned_trap_fault:\n\t" - "mov %0, %%o0\n\t" - "call user_mna_trap_fault\n\t" - " mov %1, %%o1\n\t" - : - : "r" (regs), "r" (insn) - : "o0", "o1", "o2", "o3", "o4", "o5", "o7", - "g1", "g2", "g3", "g4", "g5", "g7", "cc"); goto out; } - advance(regs); + if (err) + goto kill_user; + else + advance(regs); goto out; } --- linux-2.6.24.orig/arch/sparc/kernel/systbls.S +++ linux-2.6.24/arch/sparc/kernel/systbls.S @@ -19,7 +19,7 @@ /*0*/ .long sys_restart_syscall, sys_exit, sys_fork, sys_read, sys_write /*5*/ .long sys_open, sys_close, sys_wait4, sys_creat, sys_link /*10*/ .long sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys_mknod -/*15*/ .long sys_chmod, sys_lchown16, sparc_brk, sys_nis_syscall, sys_lseek +/*15*/ .long sys_chmod, sys_lchown16, sys_brk, sys_nis_syscall, sys_lseek /*20*/ .long sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16 /*25*/ .long sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause /*30*/ .long sys_utime, sys_lchown, sys_fchown, sys_access, sys_nice @@ -67,7 +67,7 @@ /*235*/ .long sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler /*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep -/*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl +/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl /*255*/ .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep /*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun /*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy --- linux-2.6.24.orig/arch/sparc/kernel/Makefile +++ linux-2.6.24/arch/sparc/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.62 2000/12/15 00:41:17 davem Exp $ +# # Makefile for the linux kernel. # @@ -12,7 +12,8 @@ sys_sparc.o sunos_asm.o systbls.o \ time.o windows.o cpu.o devices.o sclow.o \ tadpole.o tick14.o ptrace.o sys_solaris.o \ - unaligned.o muldiv.o semaphore.o prom.o of_device.o devres.o + unaligned.o una_asm.o muldiv.o semaphore.o \ + prom.o of_device.o devres.o devres-y = ../../../kernel/irq/devres.o --- linux-2.6.24.orig/arch/sparc/lib/rwsem.S +++ linux-2.6.24/arch/sparc/lib/rwsem.S @@ -7,7 +7,7 @@ #include #include - .section .sched.text + .section .sched.text, "ax" .align 4 .globl ___down_read --- linux-2.6.24.orig/arch/um/kernel/syscall.c +++ linux-2.6.24/arch/um/kernel/syscall.c @@ -8,6 +8,7 @@ #include "linux/mm.h" #include "linux/sched.h" #include "linux/utsname.h" +#include "linux/syscalls.h" #include "asm/current.h" #include "asm/mman.h" #include "asm/uaccess.h" @@ -39,31 +40,6 @@ return ret; } -/* common code for old and new mmaps */ -long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - long error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); - out: - return error; -} - long old_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long offset) @@ -72,7 +48,7 @@ if (offset & ~PAGE_MASK) goto out; - err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + err = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); out: return err; } --- linux-2.6.24.orig/arch/um/include/sysdep-i386/syscalls.h +++ linux-2.6.24/arch/um/include/sysdep-i386/syscalls.h @@ -19,7 +19,3 @@ #define EXECUTE_SYSCALL(syscall, regs) \ ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) - -extern long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); --- linux-2.6.24.orig/arch/x86/kernel/signal_64.c +++ linux-2.6.24/arch/x86/kernel/signal_64.c @@ -295,7 +295,7 @@ see include/asm-x86_64/uaccess.h for details. */ set_fs(USER_DS); - regs->eflags &= ~TF_MASK; + regs->eflags &= ~(TF_MASK | X86_EFLAGS_DF); if (test_thread_flag(TIF_SINGLESTEP)) ptrace_notify(SIGTRAP); #ifdef DEBUG_SIG --- linux-2.6.24.orig/arch/x86/kernel/process_64.c +++ linux-2.6.24/arch/x86/kernel/process_64.c @@ -212,14 +212,13 @@ current_thread_info()->status |= TS_POLLING; /* endless idle loop with no priority at all */ while (1) { + tick_nohz_stop_sched_tick(); while (!need_resched()) { void (*idle)(void); if (__get_cpu_var(cpu_idle_state)) __get_cpu_var(cpu_idle_state) = 0; - tick_nohz_stop_sched_tick(); - rmb(); idle = pm_idle; if (!idle) --- linux-2.6.24.orig/arch/x86/kernel/Makefile_64 +++ linux-2.6.24/arch/x86/kernel/Makefile_64 @@ -11,7 +11,7 @@ x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \ - i8253.o + i8253.o io_delay.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ --- linux-2.6.24.orig/arch/x86/kernel/time_64.c +++ linux-2.6.24/arch/x86/kernel/time_64.c @@ -241,7 +241,7 @@ rdtscl(tsc_start); do { rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now); - tsc_now = get_cycles_sync(); + tsc_now = get_cycles(); } while ((tsc_now - tsc_start) < TICK_COUNT); local_irq_restore(flags); @@ -279,6 +279,8 @@ boot_cpu_data.x86 == 16) cpu_khz = tsc_calibrate_cpu_khz(); + lpj_tsc = ((unsigned long)tsc_khz * 1000)/HZ; + if (unsynchronized_tsc()) mark_tsc_unstable("TSCs unsynchronized"); --- linux-2.6.24.orig/arch/x86/kernel/pci-gart_64.c +++ linux-2.6.24/arch/x86/kernel/pci-gart_64.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -492,6 +493,83 @@ return aper_base; } +static void enable_gart_translations(void) +{ + int i; + + for (i = 0; i < num_k8_northbridges; i++) { + struct pci_dev *dev = k8_northbridges[i]; + u32 ctl; + u32 gatt_reg; + + gatt_reg = __pa(agp_gatt_table) >> 12; + gatt_reg <<= 4; + pci_write_config_dword(dev, 0x98, gatt_reg); + pci_read_config_dword(dev, 0x90, &ctl); + + ctl |= 1; + ctl &= ~((1<<4) | (1<<5)); + + pci_write_config_dword(dev, 0x90, ctl); + } +} + +/* + * If fix_up_north_bridges is set, the north bridges have to be fixed up on + * resume in the same way as they are handled in gart_iommu_hole_init(). + */ +static bool fix_up_north_bridges; +static u32 aperture_order; +static u32 aperture_alloc; + +void set_up_gart_resume(u32 aper_order, u32 aper_alloc) +{ + fix_up_north_bridges = true; + aperture_order = aper_order; + aperture_alloc = aper_alloc; +} + +static int gart_resume(struct sys_device *dev) +{ + printk(KERN_INFO "PCI-DMA: Resuming GART IOMMU\n"); + + if (fix_up_north_bridges) { + int i; + + printk(KERN_INFO "PCI-DMA: Restoring GART aperture settings\n"); + + for (i = 0; i < num_k8_northbridges; i++) { + struct pci_dev *dev = k8_northbridges[i]; + + /* + * Don't enable translations just yet. That is the next + * step. Restore the pre-suspend aperture settings. + */ + pci_write_config_dword(dev, 0x90, aperture_order << 1); + pci_write_config_dword(dev, 0x94, aperture_alloc >> 25); + } + } + + enable_gart_translations(); + + return 0; +} + +static int gart_suspend(struct sys_device *dev, pm_message_t state) +{ + return 0; +} + +static struct sysdev_class gart_sysdev_class = { + .suspend = gart_suspend, + .resume = gart_resume, +}; + +static struct sys_device device_gart = { + .id = 0, + .cls = &gart_sysdev_class, +}; + /* * Private Northbridge GATT initialization in case we cannot use the * AGP driver for some reason. @@ -502,7 +580,7 @@ void *gatt; unsigned aper_base, new_aper_base; unsigned aper_size, gatt_size, new_aper_size; - int i; + int i, error; printk(KERN_INFO "PCI-DMA: Disabling AGP.\n"); aper_size = aper_base = info->aper_size = 0; @@ -536,21 +614,14 @@ memset(gatt, 0, gatt_size); agp_gatt_table = gatt; - for (i = 0; i < num_k8_northbridges; i++) { - u32 ctl; - u32 gatt_reg; - - dev = k8_northbridges[i]; - gatt_reg = __pa(gatt) >> 12; - gatt_reg <<= 4; - pci_write_config_dword(dev, 0x98, gatt_reg); - pci_read_config_dword(dev, 0x90, &ctl); - - ctl |= 1; - ctl &= ~((1<<4) | (1<<5)); + enable_gart_translations(); - pci_write_config_dword(dev, 0x90, ctl); - } + error = sysdev_class_register(&gart_sysdev_class); + if (!error) + error = sysdev_register(&device_gart); + if (error) + panic("Could not register gart_sysdev -- " \ + "would corrupt data on next suspend"); flush_gart(); printk("PCI-DMA: aperture base @ %x size %u KB\n",aper_base, aper_size>>10); --- linux-2.6.24.orig/arch/x86/kernel/aperture_64.c +++ linux-2.6.24/arch/x86/kernel/aperture_64.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,8 @@ printk("Mapping aperture over %d KB of RAM @ %lx\n", aper_size >> 10, __pa(p)); insert_aperture_resource((u32)__pa(p), aper_size); + register_nosave_region((u32)__pa(p) >> PAGE_SHIFT, + (u32)__pa(p+aper_size) >> PAGE_SHIFT); return (u32)__pa(p); } @@ -296,4 +299,6 @@ write_pci_config(0, num, 3, 0x90, aper_order<<1); write_pci_config(0, num, 3, 0x94, aper_alloc>>25); } + + set_up_gart_resume(aper_order, aper_alloc); } --- linux-2.6.24.orig/arch/x86/kernel/smpboot_32.c +++ linux-2.6.24/arch/x86/kernel/smpboot_32.c @@ -405,7 +405,7 @@ setup_secondary_clock(); if (nmi_watchdog == NMI_IO_APIC) { disable_8259A_irq(0); - enable_NMI_through_LVT0(NULL); + enable_NMI_through_LVT0(); enable_8259A_irq(0); } /* @@ -882,6 +882,11 @@ /* mark "stuck" area as not stuck */ *((volatile unsigned long *)trampoline_base) = 0; + /* + * Cleanup possible dangling ends... + */ + smpboot_restore_warm_reset_vector(); + return boot_error; } @@ -1083,11 +1088,6 @@ } /* - * Cleanup possible dangling ends... - */ - smpboot_restore_warm_reset_vector(); - - /* * Allow the user to impress friends. */ Dprintk("Before bogomips.\n"); --- linux-2.6.24.orig/arch/x86/kernel/tsc_32.c +++ linux-2.6.24/arch/x86/kernel/tsc_32.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -10,6 +11,7 @@ #include #include #include +#include #include "mach_timer.h" @@ -130,11 +132,17 @@ unsigned long native_calculate_cpu_khz(void) { unsigned long long start, end; - unsigned long count; + unsigned long count, hypervisor_tsc_khz; u64 delta64 = (u64)ULLONG_MAX; int i; unsigned long flags; + hypervisor_tsc_khz = get_hypervisor_tsc_freq(); + if (hypervisor_tsc_khz) { + printk(KERN_INFO "TSC: Frequency read from the hypervisor\n"); + return hypervisor_tsc_khz; + } + local_irq_save(flags); /* run 3 times to ensure the cache is warm and to get an accurate reading */ @@ -267,15 +275,28 @@ /* clock source code */ -static unsigned long current_tsc_khz = 0; +static unsigned long current_tsc_khz; +static struct clocksource clocksource_tsc; +/* + * We compare the TSC to the cycle_last value in the clocksource + * structure to avoid a nasty time-warp issue. This can be observed in + * a very small window right after one CPU updated cycle_last under + * xtime lock and the other CPU reads a TSC value which is smaller + * than the cycle_last reference value due to a TSC which is slighty + * behind. This delta is nowhere else observable, but in that case it + * results in a forward time jump in the range of hours due to the + * unsigned delta calculation of the time keeping core code, which is + * necessary to support wrapping clocksources like pm timer. + */ static cycle_t read_tsc(void) { cycle_t ret; rdtscll(ret); - return ret; + return ret >= clocksource_tsc.cycle_last ? + ret : clocksource_tsc.cycle_last; } static struct clocksource clocksource_tsc = { @@ -333,6 +354,9 @@ { if (!cpu_has_tsc || tsc_unstable) return 1; + + if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) + return 0; /* * Intel systems are normally all synchronized. * Exceptions must mark TSC as unstable: @@ -367,6 +391,8 @@ void __init tsc_init(void) { + u64 lpj; + if (!cpu_has_tsc || tsc_disable) goto out_no_tsc; @@ -376,6 +402,10 @@ if (!cpu_khz) goto out_no_tsc; + lpj = ((u64)tsc_khz * 1000); + do_div(lpj, HZ); + lpj_tsc = lpj; + printk("Detected %lu.%03lu MHz processor.\n", (unsigned long)cpu_khz / 1000, (unsigned long)cpu_khz % 1000); @@ -388,6 +418,9 @@ unsynchronized_tsc(); check_geode_tsc_reliable(); + if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) + clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; + current_tsc_khz = tsc_khz; clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz, clocksource_tsc.shift); --- linux-2.6.24.orig/arch/x86/kernel/tsc_64.c +++ linux-2.6.24/arch/x86/kernel/tsc_64.c @@ -10,6 +10,8 @@ #include #include +#include +#include static int notsc __initdata = 0; @@ -133,12 +135,12 @@ int i; for (i = 0; i < MAX_RETRIES; i++) { - t1 = get_cycles_sync(); + t1 = get_cycles(); if (hpet) *hpet = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF; else *pm = acpi_pm_read_early(); - t2 = get_cycles_sync(); + t2 = get_cycles(); if ((t2 - t1) < SMI_TRESHOLD) return t2; } @@ -151,8 +153,18 @@ void __init tsc_calibrate(void) { unsigned long flags, tsc1, tsc2, tr1, tr2, pm1, pm2, hpet1, hpet2; + unsigned long hypervisor_tsc_khz; int hpet = is_hpet_enabled(); + hypervisor_tsc_khz = get_hypervisor_tsc_freq(); + if (hypervisor_tsc_khz) { + tsc_khz = hypervisor_tsc_khz; + set_cyc2ns_scale(tsc_khz); + printk(KERN_INFO "TSC: Frequency read from the hypervisor is " + "%d.%03d MHz\n", tsc_khz / 1000, tsc_khz % 1000); + return; + } + local_irq_save(flags); tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); @@ -162,9 +174,9 @@ outb(0xb0, 0x43); outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42); outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42); - tr1 = get_cycles_sync(); + tr1 = get_cycles(); while ((inb(0x61) & 0x20) == 0); - tr2 = get_cycles_sync(); + tr2 = get_cycles(); tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); @@ -222,6 +234,9 @@ if (apic_is_clustered_box()) return 1; #endif + if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) + return 0; + /* Most intel systems have synchronized TSCs except for multi node systems */ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) { @@ -246,18 +261,34 @@ __setup("notsc", notsc_setup); +static struct clocksource clocksource_tsc; -/* clock source code: */ +/* + * We compare the TSC to the cycle_last value in the clocksource + * structure to avoid a nasty time-warp. This can be observed in a + * very small window right after one CPU updated cycle_last under + * xtime/vsyscall_gtod lock and the other CPU reads a TSC value which + * is smaller than the cycle_last reference value due to a TSC which + * is slighty behind. This delta is nowhere else observable, but in + * that case it results in a forward time jump in the range of hours + * due to the unsigned delta calculation of the time keeping core + * code, which is necessary to support wrapping clocksources like pm + * timer. + */ static cycle_t read_tsc(void) { - cycle_t ret = (cycle_t)get_cycles_sync(); - return ret; + cycle_t ret = (cycle_t)get_cycles(); + + return ret >= clocksource_tsc.cycle_last ? + ret : clocksource_tsc.cycle_last; } static cycle_t __vsyscall_fn vread_tsc(void) { - cycle_t ret = (cycle_t)get_cycles_sync(); - return ret; + cycle_t ret = (cycle_t)vget_cycles(); + + return ret >= __vsyscall_gtod_data.clock.cycle_last ? + ret : __vsyscall_gtod_data.clock.cycle_last; } static struct clocksource clocksource_tsc = { @@ -288,6 +319,9 @@ void __init init_tsc_clocksource(void) { if (!notsc) { + if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) + clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; + clocksource_tsc.mult = clocksource_khz2mult(tsc_khz, clocksource_tsc.shift); if (check_tsc_unstable()) --- linux-2.6.24.orig/arch/x86/kernel/apic_32.c +++ linux-2.6.24/arch/x86/kernel/apic_32.c @@ -154,7 +154,7 @@ /** * enable_NMI_through_LVT0 - enable NMI through local vector table 0 */ -void enable_NMI_through_LVT0 (void * dummy) +void __cpuinit enable_NMI_through_LVT0(void) { unsigned int v = APIC_DM_NMI; --- linux-2.6.24.orig/arch/x86/kernel/syscall_table_32.S +++ linux-2.6.24/arch/x86/kernel/syscall_table_32.S @@ -191,7 +191,7 @@ .long sys_ni_syscall /* reserved for streams2 */ .long sys_vfork /* 190 */ .long sys_getrlimit - .long sys_mmap2 + .long sys_mmap_pgoff .long sys_truncate64 .long sys_ftruncate64 .long sys_stat64 /* 195 */ --- linux-2.6.24.orig/arch/x86/kernel/setup_32.c +++ linux-2.6.24/arch/x86/kernel/setup_32.c @@ -61,6 +61,7 @@ #include #include #include +#include /* This value is set up by the early boot code to point to the value immediately after the boot time page tables. It contains a *physical* @@ -648,6 +649,14 @@ dmi_scan_machine(); + /* + * VMware detection requires dmi to be available, so this + * needs to be done after dmi_scan_machine, for the BP. + */ + init_hypervisor(&boot_cpu_data); + + io_delay_init();; + #ifdef CONFIG_X86_GENERICARCH generic_apic_probe(); #endif --- linux-2.6.24.orig/arch/x86/kernel/machine_kexec_64.c +++ linux-2.6.24/arch/x86/kernel/machine_kexec_64.c @@ -233,6 +233,7 @@ void arch_crash_save_vmcoreinfo(void) { + VMCOREINFO_SYMBOL(phys_base); VMCOREINFO_SYMBOL(init_level4_pgt); #ifdef CONFIG_ARCH_DISCONTIGMEM_ENABLE --- linux-2.6.24.orig/arch/x86/kernel/signal_32.c +++ linux-2.6.24/arch/x86/kernel/signal_32.c @@ -396,7 +396,7 @@ * The tracer may want to single-step inside the * handler too. */ - regs->eflags &= ~TF_MASK; + regs->eflags &= ~(TF_MASK | X86_EFLAGS_DF); if (test_thread_flag(TIF_SINGLESTEP)) ptrace_notify(SIGTRAP); @@ -489,7 +489,7 @@ * The tracer may want to single-step inside the * handler too. */ - regs->eflags &= ~TF_MASK; + regs->eflags &= ~(TF_MASK | X86_EFLAGS_DF); if (test_thread_flag(TIF_SINGLESTEP)) ptrace_notify(SIGTRAP); --- linux-2.6.24.orig/arch/x86/kernel/io_apic_32.c +++ linux-2.6.24/arch/x86/kernel/io_apic_32.c @@ -2080,7 +2080,7 @@ .eoi = ack_apic, }; -static void setup_nmi (void) +static void __init setup_nmi(void) { /* * Dirty trick to enable the NMI watchdog ... @@ -2093,7 +2093,7 @@ */ apic_printk(APIC_VERBOSE, KERN_INFO "activating NMI Watchdog ..."); - on_each_cpu(enable_NMI_through_LVT0, NULL, 1, 1); + enable_NMI_through_LVT0(); apic_printk(APIC_VERBOSE, " done.\n"); } @@ -2306,6 +2306,9 @@ for (i = FIRST_SYSTEM_VECTOR; i < NR_VECTORS; i++) set_bit(i, used_vectors); + /* Mark FIRST_DEVICE_VECTOR which is assigned to IRQ0 as used. */ + set_bit(FIRST_DEVICE_VECTOR, used_vectors); + enable_IO_APIC(); if (acpi_ioapic) @@ -2478,6 +2481,7 @@ dynamic_irq_cleanup(irq); spin_lock_irqsave(&vector_lock, flags); + clear_bit(irq_vector[irq], used_vectors); irq_vector[irq] = 0; spin_unlock_irqrestore(&vector_lock, flags); } --- linux-2.6.24.orig/arch/x86/kernel/acpi/boot.c +++ linux-2.6.24/arch/x86/kernel/acpi/boot.c @@ -592,9 +592,25 @@ * RSDP signature. */ for (offset = 0; offset < length; offset += 16) { - if (strncmp((char *)(phys_to_virt(start) + offset), "RSD PTR ", sig_len)) - continue; - return (start + offset); + if (strncmp((char *)(phys_to_virt(start) + offset), "RSD PTR ", sig_len) == 0) { + /* 2007-09-24 TJ + * The ACPI specification states the first 20 bytes of the RSDP table + * must have a checksum of 0 (ACPI 1.0b RSDP table is 20 bytes long). + * The signature can appear in multiple memory locations so don't rely + * on it as the sole proof of a valid table. + * This fixes broken/disabled ACPI problems with Acer Travelmate C100 + * (and others) where the first signature match is accepted without + * confirming the checksum. + */ + unsigned int i; + unsigned char checksum; + unsigned char *table = (unsigned char *)(phys_to_virt(start) + offset); + for (checksum = 0, i = 0; i < 20; i++) + checksum += table[i]; + + printk(KERN_WARNING PREFIX "RSDP signature @ 0x%0.8lX checksum %d\n", table, checksum); + if (checksum == 0) return (start + offset); + } } return 0; --- linux-2.6.24.orig/arch/x86/kernel/io_delay.c +++ linux-2.6.24/arch/x86/kernel/io_delay.c @@ -0,0 +1,121 @@ +/* + * I/O delay strategies for inb_p/outb_p + * + * Allow for a DMI based override of port 0x80, needed for certain HP laptops + * and possibly other systems. Also allow for the gradual elimination of + * outb_p/inb_p API uses. + */ +#include +#include +#include +#include +#include +#include + +int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE; + +static int __initdata io_delay_override; + +/* + * Paravirt wants native_io_delay to be a constant. + */ +void native_io_delay(void) +{ + switch (io_delay_type) { + default: + case CONFIG_IO_DELAY_TYPE_0X80: + asm volatile ("outb %al, $0x80"); + break; + case CONFIG_IO_DELAY_TYPE_0XED: + asm volatile ("outb %al, $0xed"); + break; + case CONFIG_IO_DELAY_TYPE_UDELAY: + /* + * 2 usecs is an upper-bound for the outb delay but + * note that udelay doesn't have the bus-level + * side-effects that outb does, nor does udelay() have + * precise timings during very early bootup (the delays + * are shorter until calibrated): + */ + udelay(2); + case CONFIG_IO_DELAY_TYPE_NONE: + break; + } +} +EXPORT_SYMBOL(native_io_delay); + +static int __init dmi_io_delay_0xed_port(const struct dmi_system_id *id) +{ + if (io_delay_type == CONFIG_IO_DELAY_TYPE_0X80) { + printk(KERN_NOTICE "%s: using 0xed I/O delay port\n", + id->ident); + io_delay_type = CONFIG_IO_DELAY_TYPE_0XED; + } + + return 0; +} + +/* + * Quirk table for systems that misbehave (lock up, etc.) if port + * 0x80 is used: + */ +static struct dmi_system_id __initdata io_delay_0xed_port_dmi_table[] = { + { + .callback = dmi_io_delay_0xed_port, + .ident = "Compaq Presario V6000", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), + DMI_MATCH(DMI_BOARD_NAME, "30B7") + } + }, + { + .callback = dmi_io_delay_0xed_port, + .ident = "HP Pavilion dv9000z", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), + DMI_MATCH(DMI_BOARD_NAME, "30B9") + } + }, + { + .callback = dmi_io_delay_0xed_port, + .ident = "HP Pavilion dv6000", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), + DMI_MATCH(DMI_BOARD_NAME, "30B8") + } + }, + { + .callback = dmi_io_delay_0xed_port, + .ident = "HP Pavilion tx1000", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), + DMI_MATCH(DMI_BOARD_NAME, "30BF") + } + }, + { } +}; + +void __init io_delay_init(void) +{ + if (!io_delay_override) + dmi_check_system(io_delay_0xed_port_dmi_table); +} + +static int __init io_delay_param(char *s) +{ + if (!strcmp(s, "0x80")) + io_delay_type = CONFIG_IO_DELAY_TYPE_0X80; + else if (!strcmp(s, "0xed")) + io_delay_type = CONFIG_IO_DELAY_TYPE_0XED; + else if (!strcmp(s, "udelay")) + io_delay_type = CONFIG_IO_DELAY_TYPE_UDELAY; + else if (!strcmp(s, "none")) + io_delay_type = CONFIG_IO_DELAY_TYPE_NONE; + else + return -EINVAL; + + io_delay_override = 1; + return 0; +} + +early_param("io_delay", io_delay_param); --- linux-2.6.24.orig/arch/x86/kernel/sys_x86_64.c +++ linux-2.6.24/arch/x86/kernel/sys_x86_64.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -37,26 +38,12 @@ unsigned long fd, unsigned long off) { long error; - struct file * file; error = -EINVAL; if (off & ~PAGE_MASK) goto out; - error = -EBADF; - file = NULL; - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); + error = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); out: return error; } @@ -65,6 +52,7 @@ unsigned long *end) { if (!test_thread_flag(TIF_IA32) && (flags & MAP_32BIT)) { + unsigned long new_begin; /* This is usually used needed to map code in small model, so it needs to be in the first 31bit. Limit it to that. This means we need to move the @@ -74,6 +62,11 @@ of playground for now. -AK */ *begin = 0x40000000; *end = 0x80000000; + if (current->flags & PF_RANDOMIZE) { + new_begin = randomize_range(*begin, *begin + 0x02000000, 0); + if (new_begin) + *begin = new_begin; + } } else { *begin = TASK_UNMAPPED_BASE; *end = TASK_SIZE; @@ -143,6 +136,97 @@ } } + +unsigned long +arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, + const unsigned long len, const unsigned long pgoff, + const unsigned long flags) +{ + struct vm_area_struct *vma; + struct mm_struct *mm = current->mm; + unsigned long addr = addr0; + + /* requested length too big for entire address space */ + if (len > TASK_SIZE) + return -ENOMEM; + + if (flags & MAP_FIXED) + return addr; + + /* for MAP_32BIT mappings we force the legact mmap base */ + if (!test_thread_flag(TIF_IA32) && (flags & MAP_32BIT)) + goto bottomup; + + /* requesting a specific address */ + if (addr) { + addr = PAGE_ALIGN(addr); + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && + (!vma || addr + len <= vma->vm_start)) + return addr; + } + + /* check if free_area_cache is useful for us */ + if (len <= mm->cached_hole_size) { + mm->cached_hole_size = 0; + mm->free_area_cache = mm->mmap_base; + } + + /* either no address requested or can't fit in requested address hole */ + addr = mm->free_area_cache; + + /* make sure it can fit in the remaining address space */ + if (addr > len) { + vma = find_vma(mm, addr-len); + if (!vma || addr <= vma->vm_start) + /* remember the address as a hint for next time */ + return (mm->free_area_cache = addr-len); + } + + if (mm->mmap_base < len) + goto bottomup; + + addr = mm->mmap_base-len; + + do { + /* + * Lookup failure means no vma is above this address, + * else if new region fits below vma->vm_start, + * return with success: + */ + vma = find_vma(mm, addr); + if (!vma || addr+len <= vma->vm_start) + /* remember the address as a hint for next time */ + return (mm->free_area_cache = addr); + + /* remember the largest hole we saw so far */ + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; + + /* try just below the current vma->vm_start */ + addr = vma->vm_start-len; + } while (len < vma->vm_start); + +bottomup: + /* + * A failed mmap() very likely causes application failure, + * so fall back to the bottom-up function here. This scenario + * can happen with large stack limits and large mmap() + * allocations. + */ + mm->cached_hole_size = ~0UL; + mm->free_area_cache = TASK_UNMAPPED_BASE; + addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); + /* + * Restore the topdown base: + */ + mm->free_area_cache = mm->mmap_base; + mm->cached_hole_size = ~0UL; + + return addr; +} + + asmlinkage long sys_uname(struct new_utsname __user * name) { int err; --- linux-2.6.24.orig/arch/x86/kernel/Makefile_32 +++ linux-2.6.24/arch/x86/kernel/Makefile_32 @@ -8,7 +8,7 @@ obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ - quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o + quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ --- linux-2.6.24.orig/arch/x86/kernel/sys_i386_32.c +++ linux-2.6.24/arch/x86/kernel/sys_i386_32.c @@ -39,31 +39,6 @@ return error; } -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - int error = -EBADF; - struct file *file = NULL; - struct mm_struct *mm = current->mm; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(&mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(&mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - /* * Perform the select(nd, in, out, ex, tv) and mmap() system * calls. Linux/i386 didn't use to be able to handle more than @@ -92,7 +67,7 @@ if (a.offset & ~PAGE_MASK) goto out; - err = sys_mmap2(a.addr, a.len, a.prot, a.flags, + err = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); out: return err; --- linux-2.6.24.orig/arch/x86/kernel/apic_64.c +++ linux-2.6.24/arch/x86/kernel/apic_64.c @@ -151,7 +151,7 @@ return send_status; } -void enable_NMI_through_LVT0 (void * dummy) +void enable_NMI_through_LVT0(void) { unsigned int v; --- linux-2.6.24.orig/arch/x86/kernel/reboot_64.c +++ linux-2.6.24/arch/x86/kernel/reboot_64.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ static long no_idt[3]; static enum { + BOOT_ACPI = 'a', BOOT_TRIPLE = 't', BOOT_KBD = 'k' } reboot_type = BOOT_KBD; @@ -56,6 +58,7 @@ case 't': case 'b': case 'k': + case 'a': reboot_type = *str; break; case 'f': @@ -146,7 +149,11 @@ reboot_type = BOOT_KBD; break; - } + case BOOT_ACPI: + acpi_reboot(); + reboot_type = BOOT_KBD; + break; + } } } --- linux-2.6.24.orig/arch/x86/kernel/setup_64.c +++ linux-2.6.24/arch/x86/kernel/setup_64.c @@ -59,6 +59,7 @@ #include #include #include +#include /* * Machine setup.. @@ -311,6 +312,14 @@ dmi_scan_machine(); + /* + * VMware detection requires dmi to be available, so this + * needs to be done after dmi_scan_machine, for the BP. + */ + init_hypervisor(&boot_cpu_data); + + io_delay_init(); + #ifdef CONFIG_SMP /* setup to use the static apicid table during kernel startup */ x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init; @@ -679,8 +688,8 @@ if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x11) set_bit(X86_FEATURE_K8, &c->x86_capability); - /* RDTSC can be speculated around */ - clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); + /* MFENCE stops RDTSC speculation */ + set_bit(X86_FEATURE_MFENCE_RDTSC, &c->x86_capability); /* Family 10 doesn't support C states in MWAIT so don't use it */ if (c->x86 == 0x10 && !force_mwait) @@ -814,10 +823,7 @@ set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability); if (c->x86 == 6) set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability); - if (c->x86 == 15) - set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); - else - clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); + set_bit(X86_FEATURE_LFENCE_RDTSC, &c->x86_capability); c->x86_max_cores = intel_num_cpu_cores(c); srat_detect_node(); @@ -957,6 +963,8 @@ select_idle_routine(c); detect_ht(c); + init_hypervisor(c); + /* * On SMP, boot_cpu_data holds the common feature set between * all CPUs; so make sure that we indicate which features are --- linux-2.6.24.orig/arch/x86/kernel/tsc_sync.c +++ linux-2.6.24/arch/x86/kernel/tsc_sync.c @@ -46,7 +46,7 @@ cycles_t start, now, prev, end; int i; - start = get_cycles_sync(); + start = get_cycles(); /* * The measurement runs for 20 msecs: */ @@ -61,7 +61,7 @@ */ __raw_spin_lock(&sync_lock); prev = last_tsc; - now = get_cycles_sync(); + now = get_cycles(); last_tsc = now; __raw_spin_unlock(&sync_lock); @@ -106,6 +106,12 @@ if (unsynchronized_tsc()) return; + if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) { + printk(KERN_INFO + "Skipping synchronization checks as TSC is reliable.\n"); + return; + } + printk(KERN_INFO "checking TSC synchronization [CPU#%d -> CPU#%d]:", smp_processor_id(), cpu); @@ -159,7 +165,7 @@ { int cpus = 2; - if (unsynchronized_tsc()) + if (unsynchronized_tsc() || boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) return; /* --- linux-2.6.24.orig/arch/x86/kernel/io_apic_64.c +++ linux-2.6.24/arch/x86/kernel/io_apic_64.c @@ -1565,7 +1565,7 @@ .end = end_lapic_irq, }; -static void setup_nmi (void) +static void __init setup_nmi(void) { /* * Dirty trick to enable the NMI watchdog ... @@ -1578,7 +1578,7 @@ */ printk(KERN_INFO "activating NMI Watchdog ..."); - enable_NMI_through_LVT0(NULL); + enable_NMI_through_LVT0(); printk(" done.\n"); } @@ -1654,7 +1654,7 @@ * * FIXME: really need to revamp this for modern platforms only. */ -static inline void check_timer(void) +static inline void __init check_timer(void) { struct irq_cfg *cfg = irq_cfg + 0; int apic1, pin1, apic2, pin2; --- linux-2.6.24.orig/arch/x86/kernel/smpboot_64.c +++ linux-2.6.24/arch/x86/kernel/smpboot_64.c @@ -338,7 +338,7 @@ if (nmi_watchdog == NMI_IO_APIC) { disable_8259A_irq(0); - enable_NMI_through_LVT0(NULL); + enable_NMI_through_LVT0(); enable_8259A_irq(0); } --- linux-2.6.24.orig/arch/x86/kernel/cpu/vmware.c +++ linux-2.6.24/arch/x86/kernel/cpu/vmware.c @@ -0,0 +1,114 @@ +/* + * VMware Detection code. + * + * Copyright (C) 2008, VMware, Inc. + * Author : Alok N Kataria + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include + +#include +#include + +#define CPUID_VMWARE_INFO_LEAF 0x40000000 +#define VMWARE_HYPERVISOR_MAGIC 0x564D5868 +#define VMWARE_HYPERVISOR_PORT 0x5658 + +#define VMWARE_PORT_CMD_GETVERSION 10 +#define VMWARE_PORT_CMD_GETHZ 45 + +#define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \ + __asm__("inl (%%dx)" : \ + "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \ + "0"(VMWARE_HYPERVISOR_MAGIC), \ + "1"(VMWARE_PORT_CMD_##cmd), \ + "2"(VMWARE_HYPERVISOR_PORT), "3"(UINT_MAX) : \ + "memory"); + +static inline int __vmware_platform(void) +{ + uint32_t eax, ebx, ecx, edx; + VMWARE_PORT(GETVERSION, eax, ebx, ecx, edx); + return eax != (uint32_t)-1 && ebx == VMWARE_HYPERVISOR_MAGIC; +} + +static unsigned long __vmware_get_tsc_khz(void) +{ + uint64_t tsc_hz; + uint32_t eax, ebx, ecx, edx; + + VMWARE_PORT(GETHZ, eax, ebx, ecx, edx); + + if (ebx == UINT_MAX) + return 0; + tsc_hz = eax | (((uint64_t)ebx) << 32); + do_div(tsc_hz, 1000); + BUG_ON(tsc_hz >> 32); + return tsc_hz; +} + +/* + * While checking the dmi string infomation, just checking the product + * serial key should be enough, as this will always have a VMware + * specific string when running under VMware hypervisor. + */ +int vmware_platform(void) +{ + if (cpu_has_hypervisor) { + unsigned int eax, ebx, ecx, edx; + char hyper_vendor_id[13]; + + cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &ebx, &ecx, &edx); + memcpy(hyper_vendor_id + 0, &ebx, 4); + memcpy(hyper_vendor_id + 4, &ecx, 4); + memcpy(hyper_vendor_id + 8, &edx, 4); + hyper_vendor_id[12] = '\0'; + if (!strcmp(hyper_vendor_id, "VMwareVMware")) + return 1; + } else if (dmi_available && dmi_name_in_serial("VMware") && + __vmware_platform()) + return 1; + + return 0; +} + +unsigned long vmware_get_tsc_khz(void) +{ + BUG_ON(!vmware_platform()); + return __vmware_get_tsc_khz(); +} + +/* + * VMware hypervisor takes care of exporting a reliable TSC to the guest. + * Still, due to timing difference when running on virtual cpus, the TSC can + * be marked as unstable in some cases. For example, the TSC sync check at + * bootup can fail due to a marginal offset between vcpus' TSCs (though the + * TSCs do not drift from each other). Also, the ACPI PM timer clocksource + * is not suitable as a watchdog when running on a hypervisor because the + * kernel may miss a wrap of the counter if the vcpu is descheduled for a + * long time. To skip these checks at runtime we set these capability bits, + * so that the kernel could just trust the hypervisor with providing a + * reliable virtual TSC that is suitable for timekeeping. + */ +void __cpuinit vmware_set_feature_bits(struct cpuinfo_x86 *c) +{ + set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability); + set_bit(X86_FEATURE_TSC_RELIABLE, c->x86_capability); +} --- linux-2.6.24.orig/arch/x86/kernel/cpu/intel.c +++ linux-2.6.24/arch/x86/kernel/cpu/intel.c @@ -201,9 +201,10 @@ } #endif + if (cpu_has_xmm2) + set_bit(X86_FEATURE_LFENCE_RDTSC, c->x86_capability); if (c->x86 == 15) { set_bit(X86_FEATURE_P4, c->x86_capability); - set_bit(X86_FEATURE_SYNC_RDTSC, c->x86_capability); } if (c->x86 == 6) set_bit(X86_FEATURE_P3, c->x86_capability); --- linux-2.6.24.orig/arch/x86/kernel/cpu/mcheck/mce_64.c +++ linux-2.6.24/arch/x86/kernel/cpu/mcheck/mce_64.c @@ -31,7 +31,7 @@ #include #define MISC_MCELOG_MINOR 227 -#define NR_BANKS 6 +#define NR_SYSFS_BANKS 6 atomic_t mce_entry; @@ -46,7 +46,7 @@ */ static int tolerant = 1; static int banks; -static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL }; +static unsigned long bank[NR_SYSFS_BANKS] = { [0 ... NR_SYSFS_BANKS-1] = ~0UL }; static unsigned long notify_user; static int rip_msr; static int mce_bootlog = 1; @@ -209,7 +209,7 @@ barrier(); for (i = 0; i < banks; i++) { - if (!bank[i]) + if (i < NR_SYSFS_BANKS && !bank[i]) continue; m.misc = 0; @@ -444,9 +444,10 @@ rdmsrl(MSR_IA32_MCG_CAP, cap); banks = cap & 0xff; - if (banks > NR_BANKS) { - printk(KERN_INFO "MCE: warning: using only %d banks\n", banks); - banks = NR_BANKS; + if (banks > MCE_EXTENDED_BANK) { + printk(KERN_INFO "MCE: warning: using only %d banks\n", + MCE_EXTENDED_BANK); + banks = MCE_EXTENDED_BANK; } /* Use accurate RIP reporting if available. */ if ((cap & (1<<9)) && ((cap >> 16) & 0xff) >= 9) @@ -462,7 +463,7 @@ wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); for (i = 0; i < banks; i++) { - wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]); + wrmsrl(MSR_IA32_MC0_CTL+4*i, ~0UL); wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0); } } @@ -765,7 +766,10 @@ } \ static SYSDEV_ATTR(name, 0644, show_ ## name, set_ ## name); -/* TBD should generate these dynamically based on number of available banks */ +/* + * TBD should generate these dynamically based on number of available banks. + * Have only 6 contol banks in /sysfs until then. + */ ACCESSOR(bank0ctl,bank[0],mce_restart()) ACCESSOR(bank1ctl,bank[1],mce_restart()) ACCESSOR(bank2ctl,bank[2],mce_restart()) --- linux-2.6.24.orig/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c +++ linux-2.6.24/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c @@ -44,6 +44,7 @@ CPU_DOTHAN_A1, CPU_DOTHAN_A2, CPU_DOTHAN_B0, + CPU_DOTHAN_C0, CPU_MP4HT_D0, CPU_MP4HT_E0, }; @@ -53,6 +54,7 @@ [CPU_DOTHAN_A1] = { 6, 13, 1 }, [CPU_DOTHAN_A2] = { 6, 13, 2 }, [CPU_DOTHAN_B0] = { 6, 13, 6 }, + [CPU_DOTHAN_C0] = { 6, 13, 8 }, [CPU_MP4HT_D0] = {15, 3, 4 }, [CPU_MP4HT_E0] = {15, 4, 1 }, }; @@ -194,6 +196,88 @@ }; #undef OP + +#define OPEX(mhz, base, mva, mvb, mvc, mvd) \ +{ \ + .frequency = (mhz) * 1000, \ + .index = (((mhz)/(base)) << 8) | ((mva - 700) / 16) \ +} + +/* Intel Pentium M processor 730 / 1.60 GHz (Sonoma) */ +static struct cpufreq_frequency_table sonoma_1596[] = +{ + OPEX( 798, 133, 988, 988, 988, 988), + OPEX(1064, 133, 1116, 1111, 1084, 1079), + OPEX(1330, 133, 1244, 1233, 1180, 1169), + OPEX(1596, 133, 1356, 1356, 1260, 1260), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 740 / 1.73 GHz (Sonoma) */ +static struct cpufreq_frequency_table sonoma_1729[] = +{ + OPEX( 798, 133, 988, 988, 988, 988), + OPEX(1064, 133, 1100, 1093, 1068, 1066), + OPEX(1330, 133, 1212, 1198, 1148, 1143), + OPEX(1729, 133, 1356, 1356, 1260, 1260), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 750 / 1.86 GHz (Sonoma) */ +static struct cpufreq_frequency_table sonoma_1862[] = +{ + OPEX( 798, 133, 988, 988, 988, 988), + OPEX(1064, 133, 1084, 1080, 1068, 1056), + OPEX(1330, 133, 1180, 1172, 1132, 1124), + OPEX(1596, 133, 1276, 1264, 1196, 1192), + OPEX(1862, 133, 1356, 1356, 1260, 1260), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 760 / 2.00 GHz (Sonoma) */ +static struct cpufreq_frequency_table sonoma_1995[] = +{ + OPEX( 798, 133, 988, 988, 988, 988), + OPEX(1064, 133, 1084, 1070, 1052, 1048), + OPEX(1330, 133, 1164, 1152, 1116, 1109), + OPEX(1596, 133, 1244, 1233, 1180, 1169), + OPEX(1995, 133, 1356, 1356, 1260, 1260), + { .frequency = CPUFREQ_TABLE_END } +}; +/* Intel Pentium M processor 770 / 2.13 GHz (Sonoma) */ +static struct cpufreq_frequency_table sonoma_2128[] = +{ + OPEX( 798, 133, 988, 988, 988, 988), + OPEX(1064, 133, 1068, 1065, 1052, 1042), + OPEX(1330, 133, 1148, 1142, 1100, 1097), + OPEX(1596, 133, 1228, 1218, 1164, 1151), + OPEX(1862, 133, 1308, 1295, 1212, 1206), + OPEX(2128, 133, 1372, 1372, 1260, 1260), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 780 / 2.26 GHz (Sonoma) */ +static struct cpufreq_frequency_table sonoma_2261[] = +{ + OPEX( 798, 133, 988, 988, 988, 988), + OPEX(1064, 133, 1068, 1064, 1052, 1037), + OPEX(1330, 133, 1148, 1139, 1100, 1087), + OPEX(1596, 133, 1228, 1215, 1148, 1136), + OPEX(1862, 133, 1292, 1291, 1196, 1186), + OPEX(2261, 133, 1404, 1404, 1260, 1260), + { .frequency = CPUFREQ_TABLE_END } +}; + +#undef OPEX + +#define SONOMA(cpuid, max, base, name) \ +{ .cpu_id = cpuid, \ + .model_name = "Intel(R) Pentium(R) M processor " name "GHz", \ + .max_freq = (max)*1000, \ + .op_points = sonoma_##max, \ +} + + #define _BANIAS(cpuid, max, name) \ { .cpu_id = cpuid, \ .model_name = "Intel(R) Pentium(R) M processor " name "MHz", \ @@ -216,6 +300,15 @@ BANIAS(1600), BANIAS(1700), + /* Builtin tables for Dothan C0 CPUs, a.k.a Sonoma */ + SONOMA(&cpu_ids[CPU_DOTHAN_C0], 1596, 133, "1.60"), + SONOMA(&cpu_ids[CPU_DOTHAN_C0], 1729, 133, "1.73"), + SONOMA(&cpu_ids[CPU_DOTHAN_C0], 1862, 133, "1.86"), + SONOMA(&cpu_ids[CPU_DOTHAN_C0], 1995, 133, "2.00"), + SONOMA(&cpu_ids[CPU_DOTHAN_C0], 2128, 133, "2.13"), + SONOMA(&cpu_ids[CPU_DOTHAN_C0], 2261, 133, "2.26"), + + /* NULL model_name is a wildcard */ { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL }, { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL }, --- linux-2.6.24.orig/arch/x86/kernel/cpu/mtrr/generic.c +++ linux-2.6.24/arch/x86/kernel/cpu/mtrr/generic.c @@ -35,6 +35,33 @@ static unsigned long smp_changes_mask; static struct mtrr_state mtrr_state = {}; +/** + * BIOS is expected to clear MtrrFixDramModEn bit, see for example + * "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD + * Opteron Processors" (26094 Rev. 3.30 February 2006), section + * "13.2.1.2 SYSCFG Register": "The MtrrFixDramModEn bit should be set + * to 1 during BIOS initalization of the fixed MTRRs, then cleared to + * 0 for operation." + */ +#define FW_WARN "[Firmware Warn]: " +static inline void k8_check_syscfg_dram_mod_en(void) +{ + u32 lo, hi; + + if (!((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && + (boot_cpu_data.x86 >= 0x0f))) + return; + + rdmsr(MSR_K8_SYSCFG, lo, hi); + if (lo & K8_MTRRFIXRANGE_DRAM_MODIFY) { + printk(KERN_ERR FW_WARN "MTRR: CPU %u: SYSCFG[MtrrFixDramModEn]" + " not cleared by BIOS, clearing this bit\n", + smp_processor_id()); + lo &= ~K8_MTRRFIXRANGE_DRAM_MODIFY; + mtrr_wrmsr(MSR_K8_SYSCFG, lo, hi); + } +} + #undef MODULE_PARAM_PREFIX #define MODULE_PARAM_PREFIX "mtrr." @@ -55,6 +82,8 @@ unsigned int *p = (unsigned int *) frs; int i; + k8_check_syscfg_dram_mod_en(); + rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]); for (i = 0; i < 2; i++) @@ -167,23 +196,8 @@ } /** - * Enable and allow read/write of extended fixed-range MTRR bits on K8 CPUs - * see AMD publication no. 24593, chapter 3.2.1 for more information - */ -static inline void k8_enable_fixed_iorrs(void) -{ - unsigned lo, hi; - - rdmsr(MSR_K8_SYSCFG, lo, hi); - mtrr_wrmsr(MSR_K8_SYSCFG, lo - | K8_MTRRFIXRANGE_DRAM_ENABLE - | K8_MTRRFIXRANGE_DRAM_MODIFY, hi); -} - -/** * Checks and updates an fixed-range MTRR if it differs from the value it - * should have. If K8 extentions are wanted, update the K8 SYSCFG MSR also. - * see AMD publication no. 24593, chapter 7.8.1, page 233 for more information + * should have. * \param msr MSR address of the MTTR which should be checked and updated * \param changed pointer which indicates whether the MTRR needed to be changed * \param msrwords pointer to the MSR values which the MSR should have @@ -195,10 +209,6 @@ rdmsr(msr, lo, hi); if (lo != msrwords[0] || hi != msrwords[1]) { - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && - boot_cpu_data.x86 == 15 && - ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK)) - k8_enable_fixed_iorrs(); mtrr_wrmsr(msr, msrwords[0], msrwords[1]); *changed = TRUE; } @@ -263,6 +273,8 @@ int changed = FALSE; int block=-1, range; + k8_check_syscfg_dram_mod_en(); + while (fixed_range_blocks[++block].ranges) for (range=0; range < fixed_range_blocks[block].ranges; range++) set_fixed_range(fixed_range_blocks[block].base_msr + range, --- linux-2.6.24.orig/arch/x86/kernel/cpu/Makefile +++ linux-2.6.24/arch/x86/kernel/cpu/Makefile @@ -3,6 +3,7 @@ # obj-y := intel_cacheinfo.o addon_cpuid_features.o +obj-y += vmware.o hypervisor.o obj-$(CONFIG_X86_32) += common.o proc.o bugs.o obj-$(CONFIG_X86_32) += amd.o --- linux-2.6.24.orig/arch/x86/kernel/cpu/amd.c +++ linux-2.6.24/arch/x86/kernel/cpu/amd.c @@ -301,6 +301,9 @@ /* K6s reports MCEs but don't actually have all the MSRs */ if (c->x86 < 6) clear_bit(X86_FEATURE_MCE, c->x86_capability); + + if (cpu_has_xmm2) + set_bit(X86_FEATURE_MFENCE_RDTSC, c->x86_capability); } static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 * c, unsigned int size) --- linux-2.6.24.orig/arch/x86/kernel/cpu/hypervisor.c +++ linux-2.6.24/arch/x86/kernel/cpu/hypervisor.c @@ -0,0 +1,60 @@ +/* + * Common hypervisor code + * + * Copyright (C) 2008, VMware, Inc. + * Author : Alok N Kataria + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include + +#include +#include +#include + +static inline void __cpuinit +detect_hypervisor_vendor(struct cpuinfo_x86 *c) +{ + if (vmware_platform()) { + c->x86_hyper_vendor = X86_HYPER_VENDOR_VMWARE; + } else { + c->x86_hyper_vendor = X86_HYPER_VENDOR_NONE; + } +} + +unsigned long get_hypervisor_tsc_freq(void) +{ + if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) + return vmware_get_tsc_khz(); + return 0; +} + +static inline void __cpuinit +hypervisor_set_feature_bits(struct cpuinfo_x86 *c) +{ + if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) { + vmware_set_feature_bits(c); + return; + } +} + +void __cpuinit init_hypervisor(struct cpuinfo_x86 *c) +{ + detect_hypervisor_vendor(c); + hypervisor_set_feature_bits(c); +} --- linux-2.6.24.orig/arch/x86/kernel/cpu/common.c +++ linux-2.6.24/arch/x86/kernel/cpu/common.c @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef CONFIG_X86_LOCAL_APIC #include #include @@ -482,6 +483,8 @@ c->x86, c->x86_model); } + init_hypervisor(c); + /* Now the feature flags better reflect actual CPU features! */ printk(KERN_DEBUG "CPU: After all inits, caps:"); --- linux-2.6.24.orig/arch/x86/kernel/reboot_32.c +++ linux-2.6.24/arch/x86/kernel/reboot_32.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,9 @@ case 'c': /* "cold" reboot (with memory testing etc) */ reboot_mode = 0x0; break; + case 'a': /* reboot through ACPI BIOS. */ + reboot_thru_bios = 2; + break; case 'b': /* "bios" reboot by jumping through the BIOS */ reboot_thru_bios = 1; break; @@ -74,6 +78,20 @@ */ /* + * Some machines require the "reboot=a" commandline option, this quirk makes + * that automatic. + */ +static int __init set_acpi_reboot(const struct dmi_system_id *d) +{ + if (!reboot_thru_bios) { + printk(KERN_INFO "%s detected. Using ACPI for reboots.\n", + d->ident); + reboot_thru_bios = 2; + } + return 0; +} + +/* * Some machines require the "reboot=b" commandline option, this quirk makes that automatic. */ static int __init set_bios_reboot(const struct dmi_system_id *d) @@ -135,6 +153,15 @@ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), }, }, + { /* Handle problems with rebooting classmate PC after suspend */ + .callback = set_acpi_reboot, + .ident = "Intel powered classmate PC", + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, + "Intel powered classmate PC"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Gen 1.5"), + }, + }, { } }; @@ -357,6 +384,9 @@ if (efi_enabled) efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL); + if (reboot_thru_bios == 2) + acpi_reboot(); + machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); } --- linux-2.6.24.orig/arch/x86/kernel/stacktrace.c +++ linux-2.6.24/arch/x86/kernel/stacktrace.c @@ -33,6 +33,19 @@ trace->entries[trace->nr_entries++] = addr; } +static void save_stack_address_nosched(void *data, unsigned long addr) +{ + struct stack_trace *trace = (struct stack_trace *)data; + if (in_sched_functions(addr)) + return; + if (trace->skip > 0) { + trace->skip--; + return; + } + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = addr; +} + static const struct stacktrace_ops save_stack_ops = { .warning = save_stack_warning, .warning_symbol = save_stack_warning_symbol, @@ -40,6 +53,13 @@ .address = save_stack_address, }; +static const struct stacktrace_ops save_stack_ops_nosched = { + .warning = save_stack_warning, + .warning_symbol = save_stack_warning_symbol, + .stack = save_stack_stack, + .address = save_stack_address_nosched, +}; + /* * Save stack-backtrace addresses into a stack_trace buffer. */ @@ -50,3 +70,10 @@ trace->entries[trace->nr_entries++] = ULONG_MAX; } EXPORT_SYMBOL(save_stack_trace); + +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + dump_trace(tsk, NULL, NULL, &save_stack_ops_nosched, trace); + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = ULONG_MAX; +} --- linux-2.6.24.orig/arch/x86/kernel/entry_64.S +++ linux-2.6.24/arch/x86/kernel/entry_64.S @@ -779,7 +779,7 @@ swapgs paranoid_restore\trace: RESTORE_ALL 8 - iretq + jmp iret_label paranoid_userspace\trace: GET_THREAD_INFO(%rcx) movl threadinfo_flags(%rcx),%ebx --- linux-2.6.24.orig/arch/x86/kernel/ptrace_64.c +++ linux-2.6.24/arch/x86/kernel/ptrace_64.c @@ -585,6 +585,12 @@ } } +#if defined CONFIG_IA32_EMULATION +# define IS_IA32 is_compat_task() +#else +# define IS_IA32 0 +#endif + asmlinkage void syscall_trace_enter(struct pt_regs *regs) { /* do the secure computing check first */ @@ -595,7 +601,7 @@ syscall_trace(regs); if (unlikely(current->audit_context)) { - if (test_thread_flag(TIF_IA32)) { + if (IS_IA32) { audit_syscall_entry(AUDIT_ARCH_I386, regs->orig_rax, regs->rbx, regs->rcx, --- linux-2.6.24.orig/arch/x86/boot/compressed/misc_64.c +++ linux-2.6.24/arch/x86/boot/compressed/misc_64.c @@ -184,8 +184,6 @@ static void *memset(void *s, int c, unsigned n); static void *memcpy(void *dest, const void *src, unsigned n); -static void putstr(const char *); - static long free_mem_ptr; static long free_mem_end_ptr; @@ -228,7 +226,8 @@ { free_mem_ptr = (long) *ptr; } - + +#ifdef CONFIG_WRAPPER_PRINT static void scroll(void) { int i; @@ -269,11 +268,14 @@ RM_SCREEN_INFO.orig_y = y; pos = (x + cols * y) * 2; /* Update cursor position */ - outb_p(14, vidport); - outb_p(0xff & (pos >> 9), vidport+1); - outb_p(15, vidport); - outb_p(0xff & (pos >> 1), vidport+1); -} + outb(14, vidport); + outb(0xff & (pos >> 9), vidport+1); + outb(15, vidport); + outb(0xff & (pos >> 1), vidport+1); +} +#else +#define putstr(__x) do{}while(0) +#endif /* CONFIG_WRAPPER_PRINT */ static void* memset(void* s, int c, unsigned n) { --- linux-2.6.24.orig/arch/x86/boot/compressed/misc_32.c +++ linux-2.6.24/arch/x86/boot/compressed/misc_32.c @@ -184,8 +184,6 @@ static void *memset(void *s, int c, unsigned n); static void *memcpy(void *dest, const void *src, unsigned n); -static void putstr(const char *); - static unsigned long free_mem_ptr; static unsigned long free_mem_end_ptr; @@ -232,7 +230,8 @@ { free_mem_ptr = (unsigned long) *ptr; } - + +#ifdef CONFIG_WRAPPER_PRINT static void scroll(void) { int i; @@ -276,11 +275,14 @@ RM_SCREEN_INFO.orig_y = y; pos = (x + cols * y) * 2; /* Update cursor position */ - outb_p(14, vidport); - outb_p(0xff & (pos >> 9), vidport+1); - outb_p(15, vidport); - outb_p(0xff & (pos >> 1), vidport+1); -} + outb(14, vidport); + outb(0xff & (pos >> 9), vidport+1); + outb(15, vidport); + outb(0xff & (pos >> 1), vidport+1); +} +#else +#define putstr(__x) do{}while(0) +#endif /* CONFIG_WRAPPER_PRINT */ static void* memset(void* s, int c, unsigned n) { --- linux-2.6.24.orig/arch/x86/boot/edd.c +++ linux-2.6.24/arch/x86/boot/edd.c @@ -128,16 +128,24 @@ { char eddarg[8]; int do_mbr = 1; +#ifdef CONFIG_EDD_OFF + int do_edd = 0; +#else int do_edd = 1; +#endif int devno; struct edd_info ei, *edp; u32 *mbrptr; if (cmdline_find_option("edd", eddarg, sizeof eddarg) > 0) { - if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip")) + if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip")) { + do_edd = 1; do_mbr = 0; + } else if (!strcmp(eddarg, "off")) do_edd = 0; + else if (!strcmp(eddarg, "on")) + do_edd = 1; } edp = boot_params.eddbuf; --- linux-2.6.24.orig/arch/x86/lib/copy_user_64.S +++ linux-2.6.24/arch/x86/lib/copy_user_64.S @@ -217,19 +217,19 @@ /* table sorted by exception address */ .section __ex_table,"a" .align 8 - .quad .Ls1,.Ls1e - .quad .Ls2,.Ls2e - .quad .Ls3,.Ls3e - .quad .Ls4,.Ls4e - .quad .Ld1,.Ls1e + .quad .Ls1,.Ls1e /* Ls1-Ls4 have copied zero bytes */ + .quad .Ls2,.Ls1e + .quad .Ls3,.Ls1e + .quad .Ls4,.Ls1e + .quad .Ld1,.Ls1e /* Ld1-Ld4 have copied 0-24 bytes */ .quad .Ld2,.Ls2e .quad .Ld3,.Ls3e .quad .Ld4,.Ls4e - .quad .Ls5,.Ls5e - .quad .Ls6,.Ls6e - .quad .Ls7,.Ls7e - .quad .Ls8,.Ls8e - .quad .Ld5,.Ls5e + .quad .Ls5,.Ls5e /* Ls5-Ls8 have copied 32 bytes */ + .quad .Ls6,.Ls5e + .quad .Ls7,.Ls5e + .quad .Ls8,.Ls5e + .quad .Ld5,.Ls5e /* Ld5-Ld8 have copied 32-56 bytes */ .quad .Ld6,.Ls6e .quad .Ld7,.Ls7e .quad .Ld8,.Ls8e @@ -244,11 +244,8 @@ .quad .Le5,.Le_zero .previous - /* compute 64-offset for main loop. 8 bytes accuracy with error on the - pessimistic side. this is gross. it would be better to fix the - interface. */ /* eax: zero, ebx: 64 */ -.Ls1e: addl $8,%eax +.Ls1e: addl $8,%eax /* eax is bytes left uncopied within the loop (Ls1e: 64 .. Ls8e: 8) */ .Ls2e: addl $8,%eax .Ls3e: addl $8,%eax .Ls4e: addl $8,%eax --- linux-2.6.24.orig/arch/x86/lib/copy_user_nocache_64.S +++ linux-2.6.24/arch/x86/lib/copy_user_nocache_64.S @@ -145,19 +145,19 @@ /* table sorted by exception address */ .section __ex_table,"a" .align 8 - .quad .Ls1,.Ls1e - .quad .Ls2,.Ls2e - .quad .Ls3,.Ls3e - .quad .Ls4,.Ls4e - .quad .Ld1,.Ls1e + .quad .Ls1,.Ls1e /* .Ls[1-4] - 0 bytes copied */ + .quad .Ls2,.Ls1e + .quad .Ls3,.Ls1e + .quad .Ls4,.Ls1e + .quad .Ld1,.Ls1e /* .Ld[1-4] - 0..24 bytes coped */ .quad .Ld2,.Ls2e .quad .Ld3,.Ls3e .quad .Ld4,.Ls4e - .quad .Ls5,.Ls5e - .quad .Ls6,.Ls6e - .quad .Ls7,.Ls7e - .quad .Ls8,.Ls8e - .quad .Ld5,.Ls5e + .quad .Ls5,.Ls5e /* .Ls[5-8] - 32 bytes copied */ + .quad .Ls6,.Ls5e + .quad .Ls7,.Ls5e + .quad .Ls8,.Ls5e + .quad .Ld5,.Ls5e /* .Ld[5-8] - 32..56 bytes copied */ .quad .Ld6,.Ls6e .quad .Ld7,.Ls7e .quad .Ld8,.Ls8e @@ -172,11 +172,8 @@ .quad .Le5,.Le_zero .previous - /* compute 64-offset for main loop. 8 bytes accuracy with error on the - pessimistic side. this is gross. it would be better to fix the - interface. */ /* eax: zero, ebx: 64 */ -.Ls1e: addl $8,%eax +.Ls1e: addl $8,%eax /* eax: bytes left uncopied: Ls1e: 64 .. Ls8e: 8 */ .Ls2e: addl $8,%eax .Ls3e: addl $8,%eax .Ls4e: addl $8,%eax --- linux-2.6.24.orig/arch/x86/pci/mmconfig_32.c +++ linux-2.6.24/arch/x86/pci/mmconfig_32.c @@ -30,10 +30,6 @@ struct acpi_mcfg_allocation *cfg; int cfg_num; - if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS && - test_bit(PCI_SLOT(devfn) + 32*bus, pci_mmcfg_fallback_slots)) - return 0; - for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { cfg = &pci_mmcfg_config[cfg_num]; if (cfg->pci_segment == seg && @@ -68,13 +64,16 @@ u32 base; if ((bus > 255) || (devfn > 255) || (reg > 4095)) { - *value = -1; +err: *value = -1; return -EINVAL; } + if (reg < 256) + return pci_conf1_read(seg,bus,devfn,reg,len,value); + base = get_base_addr(seg, bus, devfn); if (!base) - return pci_conf1_read(seg,bus,devfn,reg,len,value); + goto err; spin_lock_irqsave(&pci_config_lock, flags); @@ -105,9 +104,12 @@ if ((bus > 255) || (devfn > 255) || (reg > 4095)) return -EINVAL; + if (reg < 256) + return pci_conf1_write(seg,bus,devfn,reg,len,value); + base = get_base_addr(seg, bus, devfn); if (!base) - return pci_conf1_write(seg,bus,devfn,reg,len,value); + return -EINVAL; spin_lock_irqsave(&pci_config_lock, flags); @@ -134,12 +136,6 @@ .write = pci_mmcfg_write, }; -int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, - unsigned int devfn) -{ - return get_base_addr(seg, bus, devfn) != 0; -} - int __init pci_mmcfg_arch_init(void) { printk(KERN_INFO "PCI: Using MMCONFIG\n"); --- linux-2.6.24.orig/arch/x86/pci/mmconfig-shared.c +++ linux-2.6.24/arch/x86/pci/mmconfig-shared.c @@ -22,42 +22,9 @@ #define MMCONFIG_APER_MIN (2 * 1024*1024) #define MMCONFIG_APER_MAX (256 * 1024*1024) -DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); - /* Indicate if the mmcfg resources have been placed into the resource table. */ static int __initdata pci_mmcfg_resources_inserted; -/* K8 systems have some devices (typically in the builtin northbridge) - that are only accessible using type1 - Normally this can be expressed in the MCFG by not listing them - and assigning suitable _SEGs, but this isn't implemented in some BIOS. - Instead try to discover all devices on bus 0 that are unreachable using MM - and fallback for them. */ -static void __init unreachable_devices(void) -{ - int i, bus; - /* Use the max bus number from ACPI here? */ - for (bus = 0; bus < PCI_MMCFG_MAX_CHECK_BUS; bus++) { - for (i = 0; i < 32; i++) { - unsigned int devfn = PCI_DEVFN(i, 0); - u32 val1, val2; - - pci_conf1_read(0, bus, devfn, 0, 4, &val1); - if (val1 == 0xffffffff) - continue; - - if (pci_mmcfg_arch_reachable(0, bus, devfn)) { - raw_pci_ops->read(0, bus, devfn, 0, 4, &val2); - if (val1 == val2) - continue; - } - set_bit(i + 32 * bus, pci_mmcfg_fallback_slots); - printk(KERN_NOTICE "PCI: No mmconfig possible on device" - " %02x:%02x\n", bus, i); - } - } -} - static const char __init *pci_mmcfg_e7520(void) { u32 win; @@ -270,8 +237,6 @@ return; if (pci_mmcfg_arch_init()) { - if (type == 1) - unreachable_devices(); if (known_bridge) pci_mmcfg_insert_resources(IORESOURCE_BUSY); pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; --- linux-2.6.24.orig/arch/x86/pci/pci.h +++ linux-2.6.24/arch/x86/pci/pci.h @@ -39,6 +39,8 @@ pci_dmi_bf, }; +extern void __init dmi_check_pciprobe(void); + /* pci-i386.c */ extern unsigned int pcibios_max_latency; @@ -98,13 +100,6 @@ /* pci-mmconfig.c */ -/* Verify the first 16 busses. We assume that systems with more busses - get MCFG right. */ -#define PCI_MMCFG_MAX_CHECK_BUS 16 -extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); - -extern int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, - unsigned int devfn); extern int __init pci_mmcfg_arch_init(void); /* --- linux-2.6.24.orig/arch/x86/pci/i386.c +++ linux-2.6.24/arch/x86/pci/i386.c @@ -125,7 +125,8 @@ pr = pci_find_parent_resource(dev, r); if (!r->start || !pr || request_resource(pr, r) < 0) { - printk(KERN_ERR "PCI: Cannot allocate " + printk(KERN_WARNING + "PCI: Cannot allocate " "resource region %d " "of bridge %s\n", idx, pci_name(dev)); @@ -168,7 +169,8 @@ r->start, r->end, r->flags, disabled, pass); pr = pci_find_parent_resource(dev, r); if (!pr || request_resource(pr, r) < 0) { - printk(KERN_ERR "PCI: Cannot allocate " + printk(KERN_WARNING + "PCI: Cannot allocate " "resource region %d " "of device %s\n", idx, pci_name(dev)); --- linux-2.6.24.orig/arch/x86/pci/mmconfig_64.c +++ linux-2.6.24/arch/x86/pci/mmconfig_64.c @@ -40,9 +40,7 @@ static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) { char __iomem *addr; - if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS && - test_bit(32*bus + PCI_SLOT(devfn), pci_mmcfg_fallback_slots)) - return NULL; + addr = get_virt(seg, bus); if (!addr) return NULL; @@ -56,13 +54,16 @@ /* Why do we have this when nobody checks it. How about a BUG()!? -AK */ if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) { - *value = -1; +err: *value = -1; return -EINVAL; } + if (reg < 256) + return pci_conf1_read(seg,bus,devfn,reg,len,value); + addr = pci_dev_base(seg, bus, devfn); if (!addr) - return pci_conf1_read(seg,bus,devfn,reg,len,value); + goto err; switch (len) { case 1: @@ -88,9 +89,12 @@ if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) return -EINVAL; + if (reg < 256) + return pci_conf1_write(seg,bus,devfn,reg,len,value); + addr = pci_dev_base(seg, bus, devfn); if (!addr) - return pci_conf1_write(seg,bus,devfn,reg,len,value); + return -EINVAL; switch (len) { case 1: @@ -126,12 +130,6 @@ return addr; } -int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, - unsigned int devfn) -{ - return pci_dev_base(seg, bus, devfn) != NULL; -} - int __init pci_mmcfg_arch_init(void) { int i; --- linux-2.6.24.orig/arch/x86/pci/init.c +++ linux-2.6.24/arch/x86/pci/init.c @@ -32,6 +32,8 @@ printk(KERN_ERR "PCI: Fatal: No config space access function found\n"); + dmi_check_pciprobe(); + return 0; } arch_initcall(pci_access_init); --- linux-2.6.24.orig/arch/x86/pci/acpi.c +++ linux-2.6.24/arch/x86/pci/acpi.c @@ -219,8 +219,21 @@ if (pxm >= 0) sd->node = pxm_to_node(pxm); #endif + /* + * Maybe the desired pci bus has been already scanned. In such case + * it is unnecessary to scan the pci bus with the given domain,busnum. + */ + bus = pci_find_bus(domain, busnum); + if (bus) { + /* + * If the desired bus exits, the content of bus->sysdata will + * be replaced by sd. + */ + memcpy(bus->sysdata, sd, sizeof(*sd)); + kfree(sd); + } else + bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); - bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); if (!bus) kfree(sd); @@ -228,7 +241,7 @@ if (bus != NULL) { if (pxm >= 0) { printk("bus %d -> pxm %d -> node %d\n", - busnum, pxm, sd->node); + busnum, pxm, pxm_to_node(pxm)); } } #endif --- linux-2.6.24.orig/arch/x86/pci/common.c +++ linux-2.6.24/arch/x86/pci/common.c @@ -17,8 +17,7 @@ #include "pci.h" -unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | - PCI_PROBE_MMCONF; +unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; static int pci_bf_sort; int pci_routeirq; @@ -147,6 +146,22 @@ } #endif +#ifdef CONFIG_PCI_MMCONFIG +static int __devinit working_mmconfig(struct dmi_system_id *d) +{ + pci_probe |= PCI_PROBE_MMCONF; + return 0; +} + +static int __devinit blacklist_mmconfig(struct dmi_system_id *d) +{ + pci_probe &= ~PCI_PROBE_MMCONF; + printk(KERN_INFO "%s detected: disabling MMCONFIG PCI access", + d->ident); + return 0; +} +#endif /*CONFIG_PCI_MMCONFIG*/ + static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { #ifdef __i386__ /* @@ -334,13 +349,16 @@ {} }; +void __init dmi_check_pciprobe(void) +{ + dmi_check_system(pciprobe_dmi_table); +} + struct pci_bus * __devinit pcibios_scan_root(int busnum) { struct pci_bus *bus = NULL; struct pci_sysdata *sd; - dmi_check_system(pciprobe_dmi_table); - while ((bus = pci_find_next_bus(bus)) != NULL) { if (bus->number == busnum) { /* Already scanned */ @@ -443,6 +461,10 @@ pci_probe &= ~PCI_PROBE_MMCONF; return NULL; } + else if (!strcmp(str, "mmconf")) { + pci_probe |= PCI_PROBE_MMCONF; + return NULL; + } #endif else if (!strcmp(str, "noacpi")) { acpi_noirq_set(); --- linux-2.6.24.orig/arch/x86/Kconfig +++ linux-2.6.24/arch/x86/Kconfig @@ -116,6 +116,7 @@ bool default y +select HAVE_KVM config ZONE_DMA32 bool @@ -1619,4 +1620,6 @@ source "crypto/Kconfig" +source "arch/x86/kvm/Kconfig" + source "lib/Kconfig" --- linux-2.6.24.orig/arch/x86/mm/init_64.c +++ linux-2.6.24/arch/x86/mm/init_64.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -512,6 +513,71 @@ } #endif +int page_is_ram(unsigned long pagenr) +{ + int i; + unsigned long addr, end; + + if (efi_enabled) { + efi_memory_desc_t *md; + void *p; + + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { + md = p; + if (!is_available_memory(md)) + continue; + addr = (md->phys_addr+PAGE_SIZE-1) >> PAGE_SHIFT; + end = (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >> PAGE_SHIFT; + + if ((pagenr >= addr) && (pagenr < end)) + return 1; + } + return 0; + } + + for (i = 0; i < e820.nr_map; i++) { + /* + * Not usable memory: + */ + if (e820.map[i].type != E820_RAM) + continue; + addr = (e820.map[i].addr + PAGE_SIZE-1) >> PAGE_SHIFT; + end = (e820.map[i].addr + e820.map[i].size) >> PAGE_SHIFT; + + /* + * Sanity check: Some BIOSen report areas as RAM that + * are not. Notably the 640->1Mb area, which is the + * PCI BIOS area. + */ + if (addr >= (BIOS_BEGIN >> PAGE_SHIFT) && + end < (BIOS_END >> PAGE_SHIFT)) + continue; + + if ((pagenr >= addr) && (pagenr < end)) + return 1; + } + return 0; +} + +/* + * devmem_is_allowed() checks to see if /dev/mem access to a certain address + * is valid. The argument is a physical page number. + * + * + * On x86, access has to be given to the first megabyte of ram because that area + * contains bios code and data regions used by X and dosemu and similar apps. + * Access has to be given to non-kernel-ram areas as well, these contain the PCI + * mmio resources as well as potential bios/acpi data regions. + */ +int devmem_is_allowed(unsigned long pagenr) +{ + if (pagenr <= 256) + return 1; + if (!page_is_ram(pagenr)) + return 1; + return 0; +} + static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules, kcore_vsyscall; --- linux-2.6.24.orig/arch/x86/mm/init_32.c +++ linux-2.6.24/arch/x86/mm/init_32.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -223,22 +225,48 @@ } for (i = 0; i < e820.nr_map; i++) { - - if (e820.map[i].type != E820_RAM) /* not usable memory */ + /* + * Not usable memory: + */ + if (e820.map[i].type != E820_RAM) continue; + addr = (e820.map[i].addr + PAGE_SIZE-1) >> PAGE_SHIFT; + end = (e820.map[i].addr + e820.map[i].size) >> PAGE_SHIFT; + /* - * !!!FIXME!!! Some BIOSen report areas as RAM that - * are not. Notably the 640->1Mb area. We need a sanity - * check here. + * Sanity check: Some BIOSen report areas as RAM that + * are not. Notably the 640->1Mb area, which is the + * PCI BIOS area. */ - addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT; - end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT; - if ((pagenr >= addr) && (pagenr < end)) + if (addr >= (BIOS_BEGIN >> PAGE_SHIFT) && + end < (BIOS_END >> PAGE_SHIFT)) + continue; + + if ((pagenr >= addr) && (pagenr < end)) return 1; } return 0; } +/* + * devmem_is_allowed() checks to see if /dev/mem access to a certain address + * is valid. The argument is a physical page number. + * + * + * On x86, access has to be given to the first megabyte of ram because that area + * contains bios code and data regions used by X and dosemu and similar apps. + * Access has to be given to non-kernel-ram areas as well, these contain the PCI + * mmio resources as well as potential bios/acpi data regions. + */ +int devmem_is_allowed(unsigned long pagenr) +{ + if (pagenr <= 256) + return 1; + if (!page_is_ram(pagenr)) + return 1; + return 0; +} + #ifdef CONFIG_HIGHMEM pte_t *kmap_pte; pgprot_t kmap_prot; @@ -790,6 +818,22 @@ #ifdef CONFIG_DEBUG_RODATA +static int mark_rodata_ro_stop_work(void *data) +{ + return 0; +} + +static struct dmi_system_id mark_rodata_ro_table[] = { + { /* Handle boot Oops on Acer Aspire One */ + .ident = "Acer Aspire One", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "AOA"), + }, + }, + { } +}; + void mark_rodata_ro(void) { unsigned long start = PFN_ALIGN(_text); @@ -818,7 +862,21 @@ * We do this after the printk so that if something went wrong in the * change, the printk gets out at least to give a better debug hint * of who is the culprit. + * + * https://bugs.launchpad.net/ubuntu/+bug/322867 + * + * Calling global_flush_tlb() at this point on Acer Aspire One seems + * to trigger a panic if the timing is right. Delays caused by printk + * statements made the panic less likely. The panic itself looks like + * some other function is running in parallel at that time and seems + * to be loosing the stack. There is no final explanation to this but + * it looks like forcing the other CPUs/HTs out of work fixes the + * problem without much risk for regression. */ + if (dmi_check_system(mark_rodata_ro_table)) { + printk(KERN_INFO "Adding stop_machine_run call\n"); + stop_machine_run(mark_rodata_ro_stop_work, NULL, NR_CPUS); + } global_flush_tlb(); } #endif --- linux-2.6.24.orig/arch/x86/mm/pageattr_64.c +++ linux-2.6.24/arch/x86/mm/pageattr_64.c @@ -207,7 +207,7 @@ if (__pa(address) < KERNEL_TEXT_SIZE) { unsigned long addr2; pgprot_t prot2; - addr2 = __START_KERNEL_map + __pa(address); + addr2 = __START_KERNEL_map + __pa(address) - phys_base; /* Make sure the kernel mappings stay executable */ prot2 = pte_pgprot(pte_mkexec(pfn_pte(0, prot))); err = __change_page_attr(addr2, pfn, prot2, --- linux-2.6.24.orig/arch/x86/mm/mmap_64.c +++ linux-2.6.24/arch/x86/mm/mmap_64.c @@ -1,29 +1,117 @@ -/* Copyright 2005 Andi Kleen, SuSE Labs. - * Licensed under GPL, v.2 +/* + * linux/arch/x86-64/mm/mmap.c + * + * flexible mmap layout support + * + * Based on code by Ingo Molnar and Andi Kleen, copyrighted + * as follows: + * + * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. + * All Rights Reserved. + * Copyright 2005 Andi Kleen, SUSE Labs. + * Copyright 2007 Jiri Kosina, SUSE Labs. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * */ + +#include #include -#include #include +#include +#include #include -/* Notebook: move the mmap code from sys_x86_64.c over here. */ +/* + * Top of mmap area (just below the process stack). + * + * Leave an at least ~128 MB hole. + */ +#define MIN_GAP (128*1024*1024) +#define MAX_GAP (TASK_SIZE/6*5) + +static inline unsigned long mmap_base(void) +{ + unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur; + + if (gap < MIN_GAP) + gap = MIN_GAP; + else if (gap > MAX_GAP) + gap = MAX_GAP; + return TASK_SIZE - (gap & PAGE_MASK); +} + +static inline int mmap_is_32(void) +{ +#ifdef CONFIG_IA32_EMULATION + if (test_thread_flag(TIF_IA32)) + return 1; +#endif + return 0; +} + +static inline int mmap_is_legacy(void) +{ + if (current->personality & ADDR_COMPAT_LAYOUT) + return 1; + + if (current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY) + return 1; + + return sysctl_legacy_va_layout; +} + +/* + * This function, called very early during the creation of a new + * process VM image, sets up which VM layout function to use: + */ void arch_pick_mmap_layout(struct mm_struct *mm) { + int rnd = 0; + if (current->flags & PF_RANDOMIZE) { + /* + * Add 28bit randomness which is about 40bits of address space + * because mmap base has to be page aligned. + * or ~1/128 of the total user VM + * (total user address space is 47bits) + */ + rnd = get_random_int() & 0xfffffff; + } + + /* + * Fall back to the standard layout if the personality + * bit is set, or if the expected stack growth is unlimited: + */ + if (mmap_is_32()) { #ifdef CONFIG_IA32_EMULATION - if (current_thread_info()->flags & _TIF_IA32) + /* ia32_pick_mmap_layout has its own. */ return ia32_pick_mmap_layout(mm); #endif - mm->mmap_base = TASK_UNMAPPED_BASE; + } else if(mmap_is_legacy()) { + mm->mmap_base = TASK_UNMAPPED_BASE; + mm->get_unmapped_area = arch_get_unmapped_area; + mm->unmap_area = arch_unmap_area; + } else { + mm->mmap_base = mmap_base(); + mm->get_unmapped_area = arch_get_unmapped_area_topdown; + mm->unmap_area = arch_unmap_area_topdown; + if (current->flags & PF_RANDOMIZE) + rnd = -rnd; + } if (current->flags & PF_RANDOMIZE) { - /* Add 28bit randomness which is about 40bits of address space - because mmap base has to be page aligned. - or ~1/128 of the total user VM - (total user address space is 47bits) */ - unsigned rnd = get_random_int() & 0xfffffff; - mm->mmap_base += ((unsigned long)rnd) << PAGE_SHIFT; + mm->mmap_base += ((long)rnd) << PAGE_SHIFT; } - mm->get_unmapped_area = arch_get_unmapped_area; - mm->unmap_area = arch_unmap_area; } - --- linux-2.6.24.orig/arch/x86/lguest/boot.c +++ linux-2.6.24/arch/x86/lguest/boot.c @@ -67,6 +67,7 @@ #include #include #include +#include /* for struct machine_ops */ /*G:010 Welcome to the Guest! * @@ -812,7 +813,7 @@ * rather than virtual addresses, so we use __pa() here. */ static void lguest_power_off(void) { - hcall(LHCALL_CRASH, __pa("Power down"), 0, 0); + hcall(LHCALL_SHUTDOWN, __pa("Power down"), LGUEST_SHUTDOWN_POWEROFF, 0); } /* @@ -822,7 +823,7 @@ */ static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p) { - hcall(LHCALL_CRASH, __pa(p), 0, 0); + hcall(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF, 0); /* The hcall won't return, but to keep gcc happy, we're "done". */ return NOTIFY_DONE; } @@ -926,6 +927,11 @@ return insn_len; } +static void lguest_restart(char *reason) +{ + hcall(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART, 0); +} + /*G:030 Once we get to lguest_init(), we know we're a Guest. The pv_ops * structures in the kernel provide points for (almost) every routine we have * to override to avoid privileged instructions. */ @@ -1059,6 +1065,7 @@ * the Guest routine to power off. */ pm_power_off = lguest_power_off; + machine_ops.restart = lguest_restart; /* Now we're set up, call start_kernel() in init/main.c and we proceed * to boot as normal. It never returns. */ start_kernel(); --- linux-2.6.24.orig/arch/x86/xen/enlighten.c +++ linux-2.6.24/arch/x86/xen/enlighten.c @@ -95,7 +95,7 @@ * * 0: not available, 1: available */ -static int have_vcpu_info_placement = 0; +static int have_vcpu_info_placement = 1; static void __init xen_vcpu_setup(int cpu) { @@ -103,6 +103,7 @@ int err; struct vcpu_info *vcpup; + BUG_ON(HYPERVISOR_shared_info == &dummy_shared_info); per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; if (!have_vcpu_info_placement) @@ -153,6 +154,7 @@ if (*eax == 1) maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */ (1 << X86_FEATURE_ACPI) | /* disable ACPI */ + (1 << X86_FEATURE_SEP) | /* disable SEP */ (1 << X86_FEATURE_ACC)); /* thermal monitoring */ asm(XEN_EMULATE_PREFIX "cpuid" @@ -791,30 +793,40 @@ xen_write_cr3(__pa(base)); } -static __init void xen_pagetable_setup_done(pgd_t *base) +static __init void setup_shared_info(void) { - /* This will work as long as patching hasn't happened yet - (which it hasn't) */ - pv_mmu_ops.alloc_pt = xen_alloc_pt; - pv_mmu_ops.set_pte = xen_set_pte; - if (!xen_feature(XENFEAT_auto_translated_physmap)) { + unsigned long addr = fix_to_virt(FIX_PARAVIRT_BOOTMAP); + /* * Create a mapping for the shared info page. * Should be set_fixmap(), but shared_info is a machine * address with no corresponding pseudo-phys address. */ - set_pte_mfn(fix_to_virt(FIX_PARAVIRT_BOOTMAP), + set_pte_mfn(addr, PFN_DOWN(xen_start_info->shared_info), PAGE_KERNEL); - HYPERVISOR_shared_info = - (struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP); - + HYPERVISOR_shared_info = (struct shared_info *)addr; } else HYPERVISOR_shared_info = (struct shared_info *)__va(xen_start_info->shared_info); +#ifndef CONFIG_SMP + /* In UP this is as good a place as any to set up shared info */ + xen_setup_vcpu_info_placement(); +#endif +} + +static __init void xen_pagetable_setup_done(pgd_t *base) +{ + /* This will work as long as patching hasn't happened yet + (which it hasn't) */ + pv_mmu_ops.alloc_pt = xen_alloc_pt; + pv_mmu_ops.set_pte = xen_set_pte; + + setup_shared_info(); + /* Actually pin the pagetable down, but we can't set PG_pinned yet because the page structures don't exist yet. */ { @@ -1165,15 +1177,9 @@ x86_write_percpu(xen_cr3, __pa(pgd)); x86_write_percpu(xen_current_cr3, __pa(pgd)); -#ifdef CONFIG_SMP /* Don't do the full vcpu_info placement stuff until we have a - possible map. */ + possible map and a non-dummy shared_info. */ per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; -#else - /* May as well do it now, since there's no good time to call - it later on UP. */ - xen_setup_vcpu_info_placement(); -#endif pv_info.kernel_rpl = 1; if (xen_feature(XENFEAT_supervisor_mode_kernel)) --- linux-2.6.24.orig/arch/x86/xen/xen-asm.S +++ linux-2.6.24/arch/x86/xen/xen-asm.S @@ -33,12 +33,17 @@ events, then enter the hypervisor to get them handled. */ ENTRY(xen_irq_enable_direct) - /* Clear mask and test pending */ - andw $0x00ff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending + /* Unmask events */ + movb $0, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask + /* Preempt here doesn't matter because that will deal with any pending interrupts. The pending check may end up being run on the wrong CPU, but that doesn't hurt. */ + + /* Test for pending */ + testb $0xff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending jz 1f + 2: call check_events 1: ENDPATCH(xen_irq_enable_direct) --- linux-2.6.24.orig/arch/x86/Kconfig.debug +++ linux-2.6.24/arch/x86/Kconfig.debug @@ -5,6 +5,18 @@ source "lib/Kconfig.debug" +config NONPROMISC_DEVMEM + bool "Disable promiscuous /dev/mem" + default y + help + The /dev/mem file by default only allows userspace access to PCI + space and the BIOS code and data regions. This is sufficient for + dosemu and X and all common users of /dev/mem. With this config + option, you allow userspace access to all of memory, including + kernel and userspace memory. Accidental access to this is + obviously disasterous, but specific access can be used by people + debugging the kernel. + config EARLY_PRINTK bool "Early printk" if EMBEDDED && DEBUG_KERNEL && X86_32 default y @@ -18,6 +30,12 @@ with klogd/syslogd or the X server. You should normally N here, unless you want to debug such a crash. +config WRAPPER_PRINT + bool "Boot wrapper print" if EMBEDDED + default y + help + Enable informational output from the bootwrapper (bzImage and zImage). + config DEBUG_STACKOVERFLOW bool "Check for stack overflows" depends on DEBUG_KERNEL @@ -112,4 +130,78 @@ Add a simple leak tracer to the IOMMU code. This is useful when you are debugging a buggy device driver that leaks IOMMU mappings. +# +# IO delay types: +# + +config IO_DELAY_TYPE_0X80 + int + default "0" + +config IO_DELAY_TYPE_0XED + int + default "1" + +config IO_DELAY_TYPE_UDELAY + int + default "2" + +config IO_DELAY_TYPE_NONE + int + default "3" + +choice + prompt "IO delay type" + default IO_DELAY_0XED + +config IO_DELAY_0X80 + bool "port 0x80 based port-IO delay [recommended]" + help + This is the traditional Linux IO delay used for in/out_p. + It is the most tested hence safest selection here. + +config IO_DELAY_0XED + bool "port 0xed based port-IO delay" + help + Use port 0xed as the IO delay. This frees up port 0x80 which is + often used as a hardware-debug port. + +config IO_DELAY_UDELAY + bool "udelay based port-IO delay" + help + Use udelay(2) as the IO delay method. This provides the delay + while not having any side-effect on the IO port space. + +config IO_DELAY_NONE + bool "no port-IO delay" + help + No port-IO delay. Will break on old boxes that require port-IO + delay for certain operations. Should work on most new machines. + +endchoice + +if IO_DELAY_0X80 +config DEFAULT_IO_DELAY_TYPE + int + default IO_DELAY_TYPE_0X80 +endif + +if IO_DELAY_0XED +config DEFAULT_IO_DELAY_TYPE + int + default IO_DELAY_TYPE_0XED +endif + +if IO_DELAY_UDELAY +config DEFAULT_IO_DELAY_TYPE + int + default IO_DELAY_TYPE_UDELAY +endif + +if IO_DELAY_NONE +config DEFAULT_IO_DELAY_TYPE + int + default IO_DELAY_TYPE_NONE +endif + endmenu --- linux-2.6.24.orig/arch/x86/Makefile +++ linux-2.6.24/arch/x86/Makefile @@ -17,3 +17,5 @@ UTS_MACHINE := x86_64 include $(srctree)/arch/x86/Makefile_64 endif + +core-$(CONFIG_KVM) += arch/x86/kvm/ --- linux-2.6.24.orig/arch/x86/kvm/x86.c +++ linux-2.6.24/arch/x86/kvm/x86.c @@ -0,0 +1,3468 @@ +/* + * Kernel-based Virtual Machine driver for Linux + * + * derived from drivers/kvm/kvm_main.c + * + * Copyright (C) 2006 Qumranet, Inc. + * + * Authors: + * Avi Kivity + * Yaniv Kamay + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include +#include "segment_descriptor.h" +#include "irq.h" +#include "mmu.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_IO_MSRS 256 +#define CR0_RESERVED_BITS \ + (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \ + | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \ + | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG)) +#define CR4_RESERVED_BITS \ + (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\ + | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \ + | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR \ + | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE)) + +#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR) +/* EFER defaults: + * - enable syscall per default because its emulated by KVM + * - enable LME and LMA per default on 64 bit KVM + */ +#ifdef CONFIG_X86_64 +static u64 __read_mostly efer_reserved_bits = 0xfffffffffffffafeULL; +#else +static u64 __read_mostly efer_reserved_bits = 0xfffffffffffffffeULL; +#endif + +#define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM +#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU + +static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid, + struct kvm_cpuid_entry2 __user *entries); + +struct kvm_x86_ops *kvm_x86_ops; + +struct kvm_stats_debugfs_item debugfs_entries[] = { + { "pf_fixed", VCPU_STAT(pf_fixed) }, + { "pf_guest", VCPU_STAT(pf_guest) }, + { "tlb_flush", VCPU_STAT(tlb_flush) }, + { "invlpg", VCPU_STAT(invlpg) }, + { "exits", VCPU_STAT(exits) }, + { "io_exits", VCPU_STAT(io_exits) }, + { "mmio_exits", VCPU_STAT(mmio_exits) }, + { "signal_exits", VCPU_STAT(signal_exits) }, + { "irq_window", VCPU_STAT(irq_window_exits) }, + { "halt_exits", VCPU_STAT(halt_exits) }, + { "halt_wakeup", VCPU_STAT(halt_wakeup) }, + { "hypercalls", VCPU_STAT(hypercalls) }, + { "request_irq", VCPU_STAT(request_irq_exits) }, + { "irq_exits", VCPU_STAT(irq_exits) }, + { "host_state_reload", VCPU_STAT(host_state_reload) }, + { "efer_reload", VCPU_STAT(efer_reload) }, + { "fpu_reload", VCPU_STAT(fpu_reload) }, + { "insn_emulation", VCPU_STAT(insn_emulation) }, + { "insn_emulation_fail", VCPU_STAT(insn_emulation_fail) }, + { "mmu_shadow_zapped", VM_STAT(mmu_shadow_zapped) }, + { "mmu_pte_write", VM_STAT(mmu_pte_write) }, + { "mmu_pte_updated", VM_STAT(mmu_pte_updated) }, + { "mmu_pde_zapped", VM_STAT(mmu_pde_zapped) }, + { "mmu_flooded", VM_STAT(mmu_flooded) }, + { "mmu_recycled", VM_STAT(mmu_recycled) }, + { "mmu_cache_miss", VM_STAT(mmu_cache_miss) }, + { "remote_tlb_flush", VM_STAT(remote_tlb_flush) }, + { "largepages", VM_STAT(lpages) }, + { NULL } +}; + + +unsigned long segment_base(u16 selector) +{ + struct descriptor_table gdt; + struct segment_descriptor *d; + unsigned long table_base; + unsigned long v; + + if (selector == 0) + return 0; + + asm("sgdt %0" : "=m"(gdt)); + table_base = gdt.base; + + if (selector & 4) { /* from ldt */ + u16 ldt_selector; + + asm("sldt %0" : "=g"(ldt_selector)); + table_base = segment_base(ldt_selector); + } + d = (struct segment_descriptor *)(table_base + (selector & ~7)); + v = d->base_low | ((unsigned long)d->base_mid << 16) | + ((unsigned long)d->base_high << 24); +#ifdef CONFIG_X86_64 + if (d->system == 0 && (d->type == 2 || d->type == 9 || d->type == 11)) + v |= ((unsigned long) \ + ((struct segment_descriptor_64 *)d)->base_higher) << 32; +#endif + return v; +} +EXPORT_SYMBOL_GPL(segment_base); + +u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) +{ + if (irqchip_in_kernel(vcpu->kvm)) + return vcpu->arch.apic_base; + else + return vcpu->arch.apic_base; +} +EXPORT_SYMBOL_GPL(kvm_get_apic_base); + +void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) +{ + /* TODO: reserve bits check */ + if (irqchip_in_kernel(vcpu->kvm)) + kvm_lapic_set_base(vcpu, data); + else + vcpu->arch.apic_base = data; +} +EXPORT_SYMBOL_GPL(kvm_set_apic_base); + +void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr) +{ + WARN_ON(vcpu->arch.exception.pending); + vcpu->arch.exception.pending = true; + vcpu->arch.exception.has_error_code = false; + vcpu->arch.exception.nr = nr; +} +EXPORT_SYMBOL_GPL(kvm_queue_exception); + +void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr, + u32 error_code) +{ + ++vcpu->stat.pf_guest; + if (vcpu->arch.exception.pending) { + if (vcpu->arch.exception.nr == PF_VECTOR) { + printk(KERN_DEBUG "kvm: inject_page_fault:" + " double fault 0x%lx\n", addr); + vcpu->arch.exception.nr = DF_VECTOR; + vcpu->arch.exception.error_code = 0; + } else if (vcpu->arch.exception.nr == DF_VECTOR) { + /* triple fault -> shutdown */ + set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests); + } + return; + } + vcpu->arch.cr2 = addr; + kvm_queue_exception_e(vcpu, PF_VECTOR, error_code); +} + +void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code) +{ + WARN_ON(vcpu->arch.exception.pending); + vcpu->arch.exception.pending = true; + vcpu->arch.exception.has_error_code = true; + vcpu->arch.exception.nr = nr; + vcpu->arch.exception.error_code = error_code; +} +EXPORT_SYMBOL_GPL(kvm_queue_exception_e); + +static void __queue_exception(struct kvm_vcpu *vcpu) +{ + kvm_x86_ops->queue_exception(vcpu, vcpu->arch.exception.nr, + vcpu->arch.exception.has_error_code, + vcpu->arch.exception.error_code); +} + /* + * Checks if cpl <= required_cpl; if true, return true. Otherwise queue + * a #GP and return false. + */ +bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl) +{ + if (kvm_x86_ops->get_cpl(vcpu) <= required_cpl) + return true; + kvm_queue_exception_e(vcpu, GP_VECTOR, 0); + return false; +} +EXPORT_SYMBOL_GPL(kvm_require_cpl); + +/* + * Load the pae pdptrs. Return true is they are all valid. + */ +int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) +{ + gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT; + unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2; + int i; + int ret; + u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)]; + + down_read(&vcpu->kvm->slots_lock); + ret = kvm_read_guest_page(vcpu->kvm, pdpt_gfn, pdpte, + offset * sizeof(u64), sizeof(pdpte)); + if (ret < 0) { + ret = 0; + goto out; + } + for (i = 0; i < ARRAY_SIZE(pdpte); ++i) { + if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) { + ret = 0; + goto out; + } + } + ret = 1; + + memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs)); +out: + up_read(&vcpu->kvm->slots_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(load_pdptrs); + +static bool pdptrs_changed(struct kvm_vcpu *vcpu) +{ + u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)]; + bool changed = true; + int r; + + if (is_long_mode(vcpu) || !is_pae(vcpu)) + return false; + + down_read(&vcpu->kvm->slots_lock); + r = kvm_read_guest(vcpu->kvm, vcpu->arch.cr3 & ~31u, pdpte, sizeof(pdpte)); + if (r < 0) + goto out; + changed = memcmp(pdpte, vcpu->arch.pdptrs, sizeof(pdpte)) != 0; +out: + up_read(&vcpu->kvm->slots_lock); + + return changed; +} + +void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) +{ + if (cr0 & CR0_RESERVED_BITS) { + printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n", + cr0, vcpu->arch.cr0); + kvm_inject_gp(vcpu, 0); + return; + } + + if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) { + printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n"); + kvm_inject_gp(vcpu, 0); + return; + } + + if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) { + printk(KERN_DEBUG "set_cr0: #GP, set PG flag " + "and a clear PE flag\n"); + kvm_inject_gp(vcpu, 0); + return; + } + + if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) { +#ifdef CONFIG_X86_64 + if ((vcpu->arch.shadow_efer & EFER_LME)) { + int cs_db, cs_l; + + if (!is_pae(vcpu)) { + printk(KERN_DEBUG "set_cr0: #GP, start paging " + "in long mode while PAE is disabled\n"); + kvm_inject_gp(vcpu, 0); + return; + } + kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); + if (cs_l) { + printk(KERN_DEBUG "set_cr0: #GP, start paging " + "in long mode while CS.L == 1\n"); + kvm_inject_gp(vcpu, 0); + return; + + } + } else +#endif + if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.cr3)) { + printk(KERN_DEBUG "set_cr0: #GP, pdptrs " + "reserved bits\n"); + kvm_inject_gp(vcpu, 0); + return; + } + + } + + kvm_x86_ops->set_cr0(vcpu, cr0); + vcpu->arch.cr0 = cr0; + + kvm_mmu_reset_context(vcpu); + return; +} +EXPORT_SYMBOL_GPL(kvm_set_cr0); + +void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw) +{ + kvm_set_cr0(vcpu, (vcpu->arch.cr0 & ~0x0ful) | (msw & 0x0f)); +} +EXPORT_SYMBOL_GPL(kvm_lmsw); + +void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) +{ + if (cr4 & CR4_RESERVED_BITS) { + printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n"); + kvm_inject_gp(vcpu, 0); + return; + } + + if (is_long_mode(vcpu)) { + if (!(cr4 & X86_CR4_PAE)) { + printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while " + "in long mode\n"); + kvm_inject_gp(vcpu, 0); + return; + } + } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & X86_CR4_PAE) + && !load_pdptrs(vcpu, vcpu->arch.cr3)) { + printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n"); + kvm_inject_gp(vcpu, 0); + return; + } + + if (cr4 & X86_CR4_VMXE) { + printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n"); + kvm_inject_gp(vcpu, 0); + return; + } + kvm_x86_ops->set_cr4(vcpu, cr4); + vcpu->arch.cr4 = cr4; + kvm_mmu_reset_context(vcpu); +} +EXPORT_SYMBOL_GPL(kvm_set_cr4); + +void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) +{ + if (cr3 == vcpu->arch.cr3 && !pdptrs_changed(vcpu)) { + kvm_mmu_flush_tlb(vcpu); + return; + } + + if (is_long_mode(vcpu)) { + if (cr3 & CR3_L_MODE_RESERVED_BITS) { + printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n"); + kvm_inject_gp(vcpu, 0); + return; + } + } else { + if (is_pae(vcpu)) { + if (cr3 & CR3_PAE_RESERVED_BITS) { + printk(KERN_DEBUG + "set_cr3: #GP, reserved bits\n"); + kvm_inject_gp(vcpu, 0); + return; + } + if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) { + printk(KERN_DEBUG "set_cr3: #GP, pdptrs " + "reserved bits\n"); + kvm_inject_gp(vcpu, 0); + return; + } + } + /* + * We don't check reserved bits in nonpae mode, because + * this isn't enforced, and VMware depends on this. + */ + } + + down_read(&vcpu->kvm->slots_lock); + /* + * Does the new cr3 value map to physical memory? (Note, we + * catch an invalid cr3 even in real-mode, because it would + * cause trouble later on when we turn on paging anyway.) + * + * A real CPU would silently accept an invalid cr3 and would + * attempt to use it - with largely undefined (and often hard + * to debug) behavior on the guest side. + */ + if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT))) + kvm_inject_gp(vcpu, 0); + else { + vcpu->arch.cr3 = cr3; + vcpu->arch.mmu.new_cr3(vcpu); + } + up_read(&vcpu->kvm->slots_lock); +} +EXPORT_SYMBOL_GPL(kvm_set_cr3); + +void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) +{ + if (cr8 & CR8_RESERVED_BITS) { + printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8); + kvm_inject_gp(vcpu, 0); + return; + } + if (irqchip_in_kernel(vcpu->kvm)) + kvm_lapic_set_tpr(vcpu, cr8); + else + vcpu->arch.cr8 = cr8; +} +EXPORT_SYMBOL_GPL(kvm_set_cr8); + +unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu) +{ + if (irqchip_in_kernel(vcpu->kvm)) + return kvm_lapic_get_cr8(vcpu); + else + return vcpu->arch.cr8; +} +EXPORT_SYMBOL_GPL(kvm_get_cr8); + +/* + * List of msr numbers which we expose to userspace through KVM_GET_MSRS + * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST. + * + * This list is modified at module load time to reflect the + * capabilities of the host cpu. + */ +static u32 msrs_to_save[] = { + MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, + MSR_K6_STAR, +#ifdef CONFIG_X86_64 + MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR, +#endif + MSR_IA32_TIME_STAMP_COUNTER, MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, + MSR_IA32_PERF_STATUS, +}; + +static unsigned num_msrs_to_save; + +static u32 emulated_msrs[] = { + MSR_IA32_MISC_ENABLE, +}; + +static void set_efer(struct kvm_vcpu *vcpu, u64 efer) +{ + if (efer & efer_reserved_bits) { + printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n", + efer); + kvm_inject_gp(vcpu, 0); + return; + } + + if (is_paging(vcpu) + && (vcpu->arch.shadow_efer & EFER_LME) != (efer & EFER_LME)) { + printk(KERN_DEBUG "set_efer: #GP, change LME while paging\n"); + kvm_inject_gp(vcpu, 0); + return; + } + + kvm_x86_ops->set_efer(vcpu, efer); + + efer &= ~EFER_LMA; + efer |= vcpu->arch.shadow_efer & EFER_LMA; + + vcpu->arch.shadow_efer = efer; +} + +void kvm_enable_efer_bits(u64 mask) +{ + efer_reserved_bits &= ~mask; +} +EXPORT_SYMBOL_GPL(kvm_enable_efer_bits); + + +/* + * Writes msr value into into the appropriate "register". + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. + */ +int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) +{ + return kvm_x86_ops->set_msr(vcpu, msr_index, data); +} + +/* + * Adapt set_msr() to msr_io()'s calling convention + */ +static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) +{ + return kvm_set_msr(vcpu, index, *data); +} + +static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock) +{ + static int version; + struct kvm_wall_clock wc; + struct timespec wc_ts; + + if (!wall_clock) + return; + + mutex_lock(&kvm->lock); + + version++; + kvm_write_guest(kvm, wall_clock, &version, sizeof(version)); + + wc_ts = current_kernel_time(); + wc.wc_sec = wc_ts.tv_sec; + wc.wc_nsec = wc_ts.tv_nsec; + wc.wc_version = version; + kvm_write_guest(kvm, wall_clock, &wc, sizeof(wc)); + + version++; + kvm_write_guest(kvm, wall_clock, &version, sizeof(version)); + + mutex_unlock(&kvm->lock); +} + +static void kvm_write_guest_time(struct kvm_vcpu *v) +{ + struct timespec ts; + unsigned long flags; + struct kvm_vcpu_arch *vcpu = &v->arch; + void *shared_kaddr; + + if ((!vcpu->time_page)) + return; + + /* Keep irq disabled to prevent changes to the clock */ + local_irq_save(flags); + kvm_get_msr(v, MSR_IA32_TIME_STAMP_COUNTER, + &vcpu->hv_clock.tsc_timestamp); + ktime_get_ts(&ts); + local_irq_restore(flags); + + /* With all the info we got, fill in the values */ + + vcpu->hv_clock.system_time = ts.tv_nsec + + (NSEC_PER_SEC * (u64)ts.tv_sec); + /* + * The interface expects us to write an even number signaling that the + * update is finished. Since the guest won't see the intermediate + * state, we just write "2" at the end + */ + vcpu->hv_clock.version = 2; + + shared_kaddr = kmap_atomic(vcpu->time_page, KM_USER0); + + memcpy(shared_kaddr + vcpu->time_offset, &vcpu->hv_clock, + sizeof(vcpu->hv_clock)); + + kunmap_atomic(shared_kaddr, KM_USER0); + + mark_page_dirty(v->kvm, vcpu->time >> PAGE_SHIFT); +} + + +int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) +{ + switch (msr) { + case MSR_EFER: + set_efer(vcpu, data); + break; + case MSR_IA32_MC0_STATUS: + pr_unimpl(vcpu, "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n", + __FUNCTION__, data); + break; + case MSR_IA32_MCG_STATUS: + pr_unimpl(vcpu, "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n", + __FUNCTION__, data); + break; + case MSR_IA32_MCG_CTL: + pr_unimpl(vcpu, "%s: MSR_IA32_MCG_CTL 0x%llx, nop\n", + __FUNCTION__, data); + break; + case MSR_IA32_UCODE_REV: + case MSR_IA32_UCODE_WRITE: + case 0x200 ... 0x2ff: /* MTRRs */ + break; + case MSR_IA32_APICBASE: + kvm_set_apic_base(vcpu, data); + break; + case MSR_IA32_MISC_ENABLE: + vcpu->arch.ia32_misc_enable_msr = data; + break; + case MSR_KVM_WALL_CLOCK: + vcpu->kvm->arch.wall_clock = data; + kvm_write_wall_clock(vcpu->kvm, data); + break; + case MSR_KVM_SYSTEM_TIME: { + vcpu->arch.time = data & PAGE_MASK; + vcpu->arch.time_offset = data & ~PAGE_MASK; + + vcpu->arch.hv_clock.tsc_to_system_mul = + clocksource_khz2mult(tsc_khz, 22); + vcpu->arch.hv_clock.tsc_shift = 22; + + down_read(¤t->mm->mmap_sem); + vcpu->arch.time_page = + gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT); + up_read(¤t->mm->mmap_sem); + + if (is_error_page(vcpu->arch.time_page)) + vcpu->arch.time_page = NULL; + + kvm_write_guest_time(vcpu); + break; + } + default: + pr_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n", msr, data); + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(kvm_set_msr_common); + + +/* + * Reads an msr value (of 'msr_index') into 'pdata'. + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. + */ +int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) +{ + return kvm_x86_ops->get_msr(vcpu, msr_index, pdata); +} + +int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) +{ + u64 data; + + switch (msr) { + case 0xc0010010: /* SYSCFG */ + case 0xc0010015: /* HWCR */ + case MSR_IA32_PLATFORM_ID: + case MSR_IA32_P5_MC_ADDR: + case MSR_IA32_P5_MC_TYPE: + case MSR_IA32_MC0_CTL: + case MSR_IA32_MCG_STATUS: + case MSR_IA32_MCG_CAP: + case MSR_IA32_MCG_CTL: + case MSR_IA32_MC0_MISC: + case MSR_IA32_MC0_MISC+4: + case MSR_IA32_MC0_MISC+8: + case MSR_IA32_MC0_MISC+12: + case MSR_IA32_MC0_MISC+16: + case MSR_IA32_UCODE_REV: + case MSR_IA32_EBL_CR_POWERON: + /* MTRR registers */ + case 0xfe: + case 0x200 ... 0x2ff: + data = 0; + break; + case 0xcd: /* fsb frequency */ + data = 3; + break; + case MSR_IA32_APICBASE: + data = kvm_get_apic_base(vcpu); + break; + case MSR_IA32_MISC_ENABLE: + data = vcpu->arch.ia32_misc_enable_msr; + break; + case MSR_IA32_PERF_STATUS: + /* TSC increment by tick */ + data = 1000ULL; + /* CPU multiplier */ + data |= (((uint64_t)4ULL) << 40); + break; + case MSR_EFER: + data = vcpu->arch.shadow_efer; + break; + case MSR_KVM_WALL_CLOCK: + data = vcpu->kvm->arch.wall_clock; + break; + case MSR_KVM_SYSTEM_TIME: + data = vcpu->arch.time; + break; + default: + pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr); + return 1; + } + *pdata = data; + return 0; +} +EXPORT_SYMBOL_GPL(kvm_get_msr_common); + +/* + * Read or write a bunch of msrs. All parameters are kernel addresses. + * + * @return number of msrs set successfully. + */ +static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs, + struct kvm_msr_entry *entries, + int (*do_msr)(struct kvm_vcpu *vcpu, + unsigned index, u64 *data)) +{ + int i; + + vcpu_load(vcpu); + + for (i = 0; i < msrs->nmsrs; ++i) + if (do_msr(vcpu, entries[i].index, &entries[i].data)) + break; + + vcpu_put(vcpu); + + return i; +} + +/* + * Read or write a bunch of msrs. Parameters are user addresses. + * + * @return number of msrs set successfully. + */ +static int msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs __user *user_msrs, + int (*do_msr)(struct kvm_vcpu *vcpu, + unsigned index, u64 *data), + int writeback) +{ + struct kvm_msrs msrs; + struct kvm_msr_entry *entries; + int r, n; + unsigned size; + + r = -EFAULT; + if (copy_from_user(&msrs, user_msrs, sizeof msrs)) + goto out; + + r = -E2BIG; + if (msrs.nmsrs >= MAX_IO_MSRS) + goto out; + + r = -ENOMEM; + size = sizeof(struct kvm_msr_entry) * msrs.nmsrs; + entries = vmalloc(size); + if (!entries) + goto out; + + r = -EFAULT; + if (copy_from_user(entries, user_msrs->entries, size)) + goto out_free; + + r = n = __msr_io(vcpu, &msrs, entries, do_msr); + if (r < 0) + goto out_free; + + r = -EFAULT; + if (writeback && copy_to_user(user_msrs->entries, entries, size)) + goto out_free; + + r = n; + +out_free: + vfree(entries); +out: + return r; +} + +/* + * Make sure that a cpu that is being hot-unplugged does not have any vcpus + * cached on it. + */ +void decache_vcpus_on_cpu(int cpu) +{ + struct kvm *vm; + struct kvm_vcpu *vcpu; + int i; + + spin_lock(&kvm_lock); + list_for_each_entry(vm, &vm_list, vm_list) + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = vm->vcpus[i]; + if (!vcpu) + continue; + /* + * If the vcpu is locked, then it is running on some + * other cpu and therefore it is not cached on the + * cpu in question. + * + * If it's not locked, check the last cpu it executed + * on. + */ + if (mutex_trylock(&vcpu->mutex)) { + if (vcpu->cpu == cpu) { + kvm_x86_ops->vcpu_decache(vcpu); + vcpu->cpu = -1; + } + mutex_unlock(&vcpu->mutex); + } + } + spin_unlock(&kvm_lock); +} + +int kvm_dev_ioctl_check_extension(long ext) +{ + int r; + + switch (ext) { + case KVM_CAP_IRQCHIP: + case KVM_CAP_HLT: + case KVM_CAP_MMU_SHADOW_CACHE_CONTROL: + case KVM_CAP_USER_MEMORY: + case KVM_CAP_SET_TSS_ADDR: + case KVM_CAP_EXT_CPUID: + case KVM_CAP_CLOCKSOURCE: + r = 1; + break; + case KVM_CAP_VAPIC: + r = !kvm_x86_ops->cpu_has_accelerated_tpr(); + break; + case KVM_CAP_NR_VCPUS: + r = KVM_MAX_VCPUS; + break; + case KVM_CAP_NR_MEMSLOTS: + r = KVM_MEMORY_SLOTS; + break; + default: + r = 0; + break; + } + return r; + +} + +long kvm_arch_dev_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + long r; + + switch (ioctl) { + case KVM_GET_MSR_INDEX_LIST: { + struct kvm_msr_list __user *user_msr_list = argp; + struct kvm_msr_list msr_list; + unsigned n; + + r = -EFAULT; + if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list)) + goto out; + n = msr_list.nmsrs; + msr_list.nmsrs = num_msrs_to_save + ARRAY_SIZE(emulated_msrs); + if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list)) + goto out; + r = -E2BIG; + if (n < num_msrs_to_save) + goto out; + r = -EFAULT; + if (copy_to_user(user_msr_list->indices, &msrs_to_save, + num_msrs_to_save * sizeof(u32))) + goto out; + if (copy_to_user(user_msr_list->indices + + num_msrs_to_save * sizeof(u32), + &emulated_msrs, + ARRAY_SIZE(emulated_msrs) * sizeof(u32))) + goto out; + r = 0; + break; + } + case KVM_GET_SUPPORTED_CPUID: { + struct kvm_cpuid2 __user *cpuid_arg = argp; + struct kvm_cpuid2 cpuid; + + r = -EFAULT; + if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) + goto out; + r = kvm_dev_ioctl_get_supported_cpuid(&cpuid, + cpuid_arg->entries); + if (r) + goto out; + + r = -EFAULT; + if (copy_to_user(cpuid_arg, &cpuid, sizeof cpuid)) + goto out; + r = 0; + break; + } + default: + r = -EINVAL; + } +out: + return r; +} + +void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) +{ + kvm_x86_ops->vcpu_load(vcpu, cpu); + kvm_write_guest_time(vcpu); +} + +void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) +{ + kvm_x86_ops->vcpu_put(vcpu); + kvm_put_guest_fpu(vcpu); +} + +static int is_efer_nx(void) +{ + u64 efer; + + rdmsrl(MSR_EFER, efer); + return efer & EFER_NX; +} + +static void cpuid_fix_nx_cap(struct kvm_vcpu *vcpu) +{ + int i; + struct kvm_cpuid_entry2 *e, *entry; + + entry = NULL; + for (i = 0; i < vcpu->arch.cpuid_nent; ++i) { + e = &vcpu->arch.cpuid_entries[i]; + if (e->function == 0x80000001) { + entry = e; + break; + } + } + if (entry && (entry->edx & (1 << 20)) && !is_efer_nx()) { + entry->edx &= ~(1 << 20); + printk(KERN_INFO "kvm: guest NX capability removed\n"); + } +} + +/* when an old userspace process fills a new kernel module */ +static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu, + struct kvm_cpuid *cpuid, + struct kvm_cpuid_entry __user *entries) +{ + int r, i; + struct kvm_cpuid_entry *cpuid_entries; + + r = -E2BIG; + if (cpuid->nent > KVM_MAX_CPUID_ENTRIES) + goto out; + r = -ENOMEM; + cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry) * cpuid->nent); + if (!cpuid_entries) + goto out; + r = -EFAULT; + if (copy_from_user(cpuid_entries, entries, + cpuid->nent * sizeof(struct kvm_cpuid_entry))) + goto out_free; + for (i = 0; i < cpuid->nent; i++) { + vcpu->arch.cpuid_entries[i].function = cpuid_entries[i].function; + vcpu->arch.cpuid_entries[i].eax = cpuid_entries[i].eax; + vcpu->arch.cpuid_entries[i].ebx = cpuid_entries[i].ebx; + vcpu->arch.cpuid_entries[i].ecx = cpuid_entries[i].ecx; + vcpu->arch.cpuid_entries[i].edx = cpuid_entries[i].edx; + vcpu->arch.cpuid_entries[i].index = 0; + vcpu->arch.cpuid_entries[i].flags = 0; + vcpu->arch.cpuid_entries[i].padding[0] = 0; + vcpu->arch.cpuid_entries[i].padding[1] = 0; + vcpu->arch.cpuid_entries[i].padding[2] = 0; + } + vcpu->arch.cpuid_nent = cpuid->nent; + cpuid_fix_nx_cap(vcpu); + r = 0; + +out_free: + vfree(cpuid_entries); +out: + return r; +} + +static int kvm_vcpu_ioctl_set_cpuid2(struct kvm_vcpu *vcpu, + struct kvm_cpuid2 *cpuid, + struct kvm_cpuid_entry2 __user *entries) +{ + int r; + + r = -E2BIG; + if (cpuid->nent > KVM_MAX_CPUID_ENTRIES) + goto out; + r = -EFAULT; + if (copy_from_user(&vcpu->arch.cpuid_entries, entries, + cpuid->nent * sizeof(struct kvm_cpuid_entry2))) + goto out; + vcpu->arch.cpuid_nent = cpuid->nent; + return 0; + +out: + return r; +} + +static int kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu, + struct kvm_cpuid2 *cpuid, + struct kvm_cpuid_entry2 __user *entries) +{ + int r; + + r = -E2BIG; + if (cpuid->nent < vcpu->arch.cpuid_nent) + goto out; + r = -EFAULT; + if (copy_to_user(entries, &vcpu->arch.cpuid_entries, + vcpu->arch.cpuid_nent * sizeof(struct kvm_cpuid_entry2))) + goto out; + return 0; + +out: + cpuid->nent = vcpu->arch.cpuid_nent; + return r; +} + +static inline u32 bit(int bitno) +{ + return 1 << (bitno & 31); +} + +static void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function, + u32 index) +{ + entry->function = function; + entry->index = index; + cpuid_count(entry->function, entry->index, + &entry->eax, &entry->ebx, &entry->ecx, &entry->edx); + entry->flags = 0; +} + +static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, + u32 index, int *nent, int maxnent) +{ + const u32 kvm_supported_word0_x86_features = bit(X86_FEATURE_FPU) | + bit(X86_FEATURE_VME) | bit(X86_FEATURE_DE) | + bit(X86_FEATURE_PSE) | bit(X86_FEATURE_TSC) | + bit(X86_FEATURE_MSR) | bit(X86_FEATURE_PAE) | + bit(X86_FEATURE_CX8) | bit(X86_FEATURE_APIC) | + bit(X86_FEATURE_SEP) | bit(X86_FEATURE_PGE) | + bit(X86_FEATURE_CMOV) | bit(X86_FEATURE_PSE36) | + bit(X86_FEATURE_CLFLSH) | bit(X86_FEATURE_MMX) | + bit(X86_FEATURE_FXSR) | bit(X86_FEATURE_XMM) | + bit(X86_FEATURE_XMM2) | bit(X86_FEATURE_SELFSNOOP); + const u32 kvm_supported_word1_x86_features = bit(X86_FEATURE_FPU) | + bit(X86_FEATURE_VME) | bit(X86_FEATURE_DE) | + bit(X86_FEATURE_PSE) | bit(X86_FEATURE_TSC) | + bit(X86_FEATURE_MSR) | bit(X86_FEATURE_PAE) | + bit(X86_FEATURE_CX8) | bit(X86_FEATURE_APIC) | + bit(X86_FEATURE_PGE) | + bit(X86_FEATURE_CMOV) | bit(X86_FEATURE_PSE36) | + bit(X86_FEATURE_MMX) | bit(X86_FEATURE_FXSR) | + bit(X86_FEATURE_SYSCALL) | + (bit(X86_FEATURE_NX) && is_efer_nx()) | +#ifdef CONFIG_X86_64 + bit(X86_FEATURE_LM) | +#endif + bit(X86_FEATURE_MMXEXT) | + bit(X86_FEATURE_3DNOWEXT) | + bit(X86_FEATURE_3DNOW); + const u32 kvm_supported_word3_x86_features = + bit(X86_FEATURE_XMM3) | bit(X86_FEATURE_CX16); + const u32 kvm_supported_word6_x86_features = + bit(X86_FEATURE_LAHF_LM) | bit(X86_FEATURE_CMP_LEGACY); + + /* all func 2 cpuid_count() should be called on the same cpu */ + get_cpu(); + do_cpuid_1_ent(entry, function, index); + ++*nent; + + switch (function) { + case 0: + entry->eax = min(entry->eax, (u32)0xb); + break; + case 1: + entry->edx &= kvm_supported_word0_x86_features; + entry->ecx &= kvm_supported_word3_x86_features; + break; + /* function 2 entries are STATEFUL. That is, repeated cpuid commands + * may return different values. This forces us to get_cpu() before + * issuing the first command, and also to emulate this annoying behavior + * in kvm_emulate_cpuid() using KVM_CPUID_FLAG_STATE_READ_NEXT */ + case 2: { + int t, times = entry->eax & 0xff; + + entry->flags |= KVM_CPUID_FLAG_STATEFUL_FUNC; + for (t = 1; t < times && *nent < maxnent; ++t) { + do_cpuid_1_ent(&entry[t], function, 0); + entry[t].flags |= KVM_CPUID_FLAG_STATEFUL_FUNC; + ++*nent; + } + break; + } + /* function 4 and 0xb have additional index. */ + case 4: { + int i, cache_type; + + entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; + /* read more entries until cache_type is zero */ + for (i = 1; *nent < maxnent; ++i) { + cache_type = entry[i - 1].eax & 0x1f; + if (!cache_type) + break; + do_cpuid_1_ent(&entry[i], function, i); + entry[i].flags |= + KVM_CPUID_FLAG_SIGNIFCANT_INDEX; + ++*nent; + } + break; + } + case 0xb: { + int i, level_type; + + entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; + /* read more entries until level_type is zero */ + for (i = 1; *nent < maxnent; ++i) { + level_type = entry[i - 1].ecx & 0xff; + if (!level_type) + break; + do_cpuid_1_ent(&entry[i], function, i); + entry[i].flags |= + KVM_CPUID_FLAG_SIGNIFCANT_INDEX; + ++*nent; + } + break; + } + case 0x80000000: + entry->eax = min(entry->eax, 0x8000001a); + break; + case 0x80000001: + entry->edx &= kvm_supported_word1_x86_features; + entry->ecx &= kvm_supported_word6_x86_features; + break; + } + put_cpu(); +} + +static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid, + struct kvm_cpuid_entry2 __user *entries) +{ + struct kvm_cpuid_entry2 *cpuid_entries; + int limit, nent = 0, r = -E2BIG; + u32 func; + + if (cpuid->nent < 1) + goto out; + if (cpuid->nent > KVM_MAX_CPUID_ENTRIES) + cpuid->nent = KVM_MAX_CPUID_ENTRIES; + r = -ENOMEM; + cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry2) * cpuid->nent); + if (!cpuid_entries) + goto out; + + do_cpuid_ent(&cpuid_entries[0], 0, 0, &nent, cpuid->nent); + limit = cpuid_entries[0].eax; + for (func = 1; func <= limit && nent < cpuid->nent; ++func) + do_cpuid_ent(&cpuid_entries[nent], func, 0, + &nent, cpuid->nent); + r = -E2BIG; + if (nent >= cpuid->nent) + goto out_free; + + do_cpuid_ent(&cpuid_entries[nent], 0x80000000, 0, &nent, cpuid->nent); + limit = cpuid_entries[nent - 1].eax; + for (func = 0x80000001; func <= limit && nent < cpuid->nent; ++func) + do_cpuid_ent(&cpuid_entries[nent], func, 0, + &nent, cpuid->nent); + r = -EFAULT; + if (copy_to_user(entries, cpuid_entries, + nent * sizeof(struct kvm_cpuid_entry2))) + goto out_free; + cpuid->nent = nent; + r = 0; + +out_free: + vfree(cpuid_entries); +out: + return r; +} + +static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu, + struct kvm_lapic_state *s) +{ + vcpu_load(vcpu); + memcpy(s->regs, vcpu->arch.apic->regs, sizeof *s); + vcpu_put(vcpu); + + return 0; +} + +static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu, + struct kvm_lapic_state *s) +{ + vcpu_load(vcpu); + memcpy(vcpu->arch.apic->regs, s->regs, sizeof *s); + kvm_apic_post_state_restore(vcpu); + vcpu_put(vcpu); + + return 0; +} + +static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, + struct kvm_interrupt *irq) +{ + if (irq->irq < 0 || irq->irq >= 256) + return -EINVAL; + if (irqchip_in_kernel(vcpu->kvm)) + return -ENXIO; + vcpu_load(vcpu); + + set_bit(irq->irq, vcpu->arch.irq_pending); + set_bit(irq->irq / BITS_PER_LONG, &vcpu->arch.irq_summary); + + vcpu_put(vcpu); + + return 0; +} + +static int vcpu_ioctl_tpr_access_reporting(struct kvm_vcpu *vcpu, + struct kvm_tpr_access_ctl *tac) +{ + if (tac->flags) + return -EINVAL; + vcpu->arch.tpr_access_reporting = !!tac->enabled; + return 0; +} + +long kvm_arch_vcpu_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + struct kvm_vcpu *vcpu = filp->private_data; + void __user *argp = (void __user *)arg; + int r; + + switch (ioctl) { + case KVM_GET_LAPIC: { + struct kvm_lapic_state lapic; + + memset(&lapic, 0, sizeof lapic); + r = kvm_vcpu_ioctl_get_lapic(vcpu, &lapic); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &lapic, sizeof lapic)) + goto out; + r = 0; + break; + } + case KVM_SET_LAPIC: { + struct kvm_lapic_state lapic; + + r = -EFAULT; + if (copy_from_user(&lapic, argp, sizeof lapic)) + goto out; + r = kvm_vcpu_ioctl_set_lapic(vcpu, &lapic);; + if (r) + goto out; + r = 0; + break; + } + case KVM_INTERRUPT: { + struct kvm_interrupt irq; + + r = -EFAULT; + if (copy_from_user(&irq, argp, sizeof irq)) + goto out; + r = kvm_vcpu_ioctl_interrupt(vcpu, &irq); + if (r) + goto out; + r = 0; + break; + } + case KVM_SET_CPUID: { + struct kvm_cpuid __user *cpuid_arg = argp; + struct kvm_cpuid cpuid; + + r = -EFAULT; + if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) + goto out; + r = kvm_vcpu_ioctl_set_cpuid(vcpu, &cpuid, cpuid_arg->entries); + if (r) + goto out; + break; + } + case KVM_SET_CPUID2: { + struct kvm_cpuid2 __user *cpuid_arg = argp; + struct kvm_cpuid2 cpuid; + + r = -EFAULT; + if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) + goto out; + r = kvm_vcpu_ioctl_set_cpuid2(vcpu, &cpuid, + cpuid_arg->entries); + if (r) + goto out; + break; + } + case KVM_GET_CPUID2: { + struct kvm_cpuid2 __user *cpuid_arg = argp; + struct kvm_cpuid2 cpuid; + + r = -EFAULT; + if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) + goto out; + r = kvm_vcpu_ioctl_get_cpuid2(vcpu, &cpuid, + cpuid_arg->entries); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(cpuid_arg, &cpuid, sizeof cpuid)) + goto out; + r = 0; + break; + } + case KVM_GET_MSRS: + r = msr_io(vcpu, argp, kvm_get_msr, 1); + break; + case KVM_SET_MSRS: + r = msr_io(vcpu, argp, do_set_msr, 0); + break; + case KVM_TPR_ACCESS_REPORTING: { + struct kvm_tpr_access_ctl tac; + + r = -EFAULT; + if (copy_from_user(&tac, argp, sizeof tac)) + goto out; + r = vcpu_ioctl_tpr_access_reporting(vcpu, &tac); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &tac, sizeof tac)) + goto out; + r = 0; + break; + }; + case KVM_SET_VAPIC_ADDR: { + struct kvm_vapic_addr va; + + r = -EINVAL; + if (!irqchip_in_kernel(vcpu->kvm)) + goto out; + r = -EFAULT; + if (copy_from_user(&va, argp, sizeof va)) + goto out; + r = 0; + kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr); + break; + } + default: + r = -EINVAL; + } +out: + return r; +} + +static int kvm_vm_ioctl_set_tss_addr(struct kvm *kvm, unsigned long addr) +{ + int ret; + + if (addr > (unsigned int)(-3 * PAGE_SIZE)) + return -1; + ret = kvm_x86_ops->set_tss_addr(kvm, addr); + return ret; +} + +static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm, + u32 kvm_nr_mmu_pages) +{ + if (kvm_nr_mmu_pages < KVM_MIN_ALLOC_MMU_PAGES) + return -EINVAL; + + down_write(&kvm->slots_lock); + + kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages); + kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages; + + up_write(&kvm->slots_lock); + return 0; +} + +static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm) +{ + return kvm->arch.n_alloc_mmu_pages; +} + +gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) +{ + int i; + struct kvm_mem_alias *alias; + + for (i = 0; i < kvm->arch.naliases; ++i) { + alias = &kvm->arch.aliases[i]; + if (gfn >= alias->base_gfn + && gfn < alias->base_gfn + alias->npages) + return alias->target_gfn + gfn - alias->base_gfn; + } + return gfn; +} + +/* + * Set a new alias region. Aliases map a portion of physical memory into + * another portion. This is useful for memory windows, for example the PC + * VGA region. + */ +static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, + struct kvm_memory_alias *alias) +{ + int r, n; + struct kvm_mem_alias *p; + + r = -EINVAL; + /* General sanity checks */ + if (alias->memory_size & (PAGE_SIZE - 1)) + goto out; + if (alias->guest_phys_addr & (PAGE_SIZE - 1)) + goto out; + if (alias->slot >= KVM_ALIAS_SLOTS) + goto out; + if (alias->guest_phys_addr + alias->memory_size + < alias->guest_phys_addr) + goto out; + if (alias->target_phys_addr + alias->memory_size + < alias->target_phys_addr) + goto out; + + down_write(&kvm->slots_lock); + + p = &kvm->arch.aliases[alias->slot]; + p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; + p->npages = alias->memory_size >> PAGE_SHIFT; + p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT; + + for (n = KVM_ALIAS_SLOTS; n > 0; --n) + if (kvm->arch.aliases[n - 1].npages) + break; + kvm->arch.naliases = n; + + kvm_mmu_zap_all(kvm); + + up_write(&kvm->slots_lock); + + return 0; + +out: + return r; +} + +static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) +{ + int r; + + r = 0; + switch (chip->chip_id) { + case KVM_IRQCHIP_PIC_MASTER: + memcpy(&chip->chip.pic, + &pic_irqchip(kvm)->pics[0], + sizeof(struct kvm_pic_state)); + break; + case KVM_IRQCHIP_PIC_SLAVE: + memcpy(&chip->chip.pic, + &pic_irqchip(kvm)->pics[1], + sizeof(struct kvm_pic_state)); + break; + case KVM_IRQCHIP_IOAPIC: + memcpy(&chip->chip.ioapic, + ioapic_irqchip(kvm), + sizeof(struct kvm_ioapic_state)); + break; + default: + r = -EINVAL; + break; + } + return r; +} + +static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) +{ + int r; + + r = 0; + switch (chip->chip_id) { + case KVM_IRQCHIP_PIC_MASTER: + memcpy(&pic_irqchip(kvm)->pics[0], + &chip->chip.pic, + sizeof(struct kvm_pic_state)); + break; + case KVM_IRQCHIP_PIC_SLAVE: + memcpy(&pic_irqchip(kvm)->pics[1], + &chip->chip.pic, + sizeof(struct kvm_pic_state)); + break; + case KVM_IRQCHIP_IOAPIC: + memcpy(ioapic_irqchip(kvm), + &chip->chip.ioapic, + sizeof(struct kvm_ioapic_state)); + break; + default: + r = -EINVAL; + break; + } + kvm_pic_update_irq(pic_irqchip(kvm)); + return r; +} + +/* + * Get (and clear) the dirty memory log for a memory slot. + */ +int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, + struct kvm_dirty_log *log) +{ + int r; + int n; + struct kvm_memory_slot *memslot; + int is_dirty = 0; + + down_write(&kvm->slots_lock); + + r = kvm_get_dirty_log(kvm, log, &is_dirty); + if (r) + goto out; + + /* If nothing is dirty, don't bother messing with page tables. */ + if (is_dirty) { + kvm_mmu_slot_remove_write_access(kvm, log->slot); + kvm_flush_remote_tlbs(kvm); + memslot = &kvm->memslots[log->slot]; + n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; + memset(memslot->dirty_bitmap, 0, n); + } + r = 0; +out: + up_write(&kvm->slots_lock); + return r; +} + +long kvm_arch_vm_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + struct kvm *kvm = filp->private_data; + void __user *argp = (void __user *)arg; + int r = -EINVAL; + + switch (ioctl) { + case KVM_SET_TSS_ADDR: + r = kvm_vm_ioctl_set_tss_addr(kvm, arg); + if (r < 0) + goto out; + break; + case KVM_SET_MEMORY_REGION: { + struct kvm_memory_region kvm_mem; + struct kvm_userspace_memory_region kvm_userspace_mem; + + r = -EFAULT; + if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem)) + goto out; + kvm_userspace_mem.slot = kvm_mem.slot; + kvm_userspace_mem.flags = kvm_mem.flags; + kvm_userspace_mem.guest_phys_addr = kvm_mem.guest_phys_addr; + kvm_userspace_mem.memory_size = kvm_mem.memory_size; + r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0); + if (r) + goto out; + break; + } + case KVM_SET_NR_MMU_PAGES: + r = kvm_vm_ioctl_set_nr_mmu_pages(kvm, arg); + if (r) + goto out; + break; + case KVM_GET_NR_MMU_PAGES: + r = kvm_vm_ioctl_get_nr_mmu_pages(kvm); + break; + case KVM_SET_MEMORY_ALIAS: { + struct kvm_memory_alias alias; + + r = -EFAULT; + if (copy_from_user(&alias, argp, sizeof alias)) + goto out; + r = kvm_vm_ioctl_set_memory_alias(kvm, &alias); + if (r) + goto out; + break; + } + case KVM_CREATE_IRQCHIP: + r = -ENOMEM; + kvm->arch.vpic = kvm_create_pic(kvm); + if (kvm->arch.vpic) { + r = kvm_ioapic_init(kvm); + if (r) { + kfree(kvm->arch.vpic); + kvm->arch.vpic = NULL; + goto out; + } + } else + goto out; + break; + case KVM_IRQ_LINE: { + struct kvm_irq_level irq_event; + + r = -EFAULT; + if (copy_from_user(&irq_event, argp, sizeof irq_event)) + goto out; + if (irqchip_in_kernel(kvm)) { + mutex_lock(&kvm->lock); + if (irq_event.irq < 16) + kvm_pic_set_irq(pic_irqchip(kvm), + irq_event.irq, + irq_event.level); + kvm_ioapic_set_irq(kvm->arch.vioapic, + irq_event.irq, + irq_event.level); + mutex_unlock(&kvm->lock); + r = 0; + } + break; + } + case KVM_GET_IRQCHIP: { + /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ + struct kvm_irqchip chip; + + r = -EFAULT; + if (copy_from_user(&chip, argp, sizeof chip)) + goto out; + r = -ENXIO; + if (!irqchip_in_kernel(kvm)) + goto out; + r = kvm_vm_ioctl_get_irqchip(kvm, &chip); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &chip, sizeof chip)) + goto out; + r = 0; + break; + } + case KVM_SET_IRQCHIP: { + /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ + struct kvm_irqchip chip; + + r = -EFAULT; + if (copy_from_user(&chip, argp, sizeof chip)) + goto out; + r = -ENXIO; + if (!irqchip_in_kernel(kvm)) + goto out; + r = kvm_vm_ioctl_set_irqchip(kvm, &chip); + if (r) + goto out; + r = 0; + break; + } + default: + ; + } +out: + return r; +} + +static void kvm_init_msr_list(void) +{ + u32 dummy[2]; + unsigned i, j; + + for (i = j = 0; i < ARRAY_SIZE(msrs_to_save); i++) { + if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0) + continue; + if (j < i) + msrs_to_save[j] = msrs_to_save[i]; + j++; + } + num_msrs_to_save = j; +} + +/* + * Only apic need an MMIO device hook, so shortcut now.. + */ +static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu, + gpa_t addr) +{ + struct kvm_io_device *dev; + + if (vcpu->arch.apic) { + dev = &vcpu->arch.apic->dev; + if (dev->in_range(dev, addr)) + return dev; + } + return NULL; +} + + +static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, + gpa_t addr) +{ + struct kvm_io_device *dev; + + dev = vcpu_find_pervcpu_dev(vcpu, addr); + if (dev == NULL) + dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); + return dev; +} + +int emulator_read_std(unsigned long addr, + void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu) +{ + void *data = val; + int r = X86EMUL_CONTINUE; + + down_read(&vcpu->kvm->slots_lock); + while (bytes) { + gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); + unsigned offset = addr & (PAGE_SIZE-1); + unsigned tocopy = min(bytes, (unsigned)PAGE_SIZE - offset); + int ret; + + if (gpa == UNMAPPED_GVA) { + r = X86EMUL_PROPAGATE_FAULT; + goto out; + } + ret = kvm_read_guest(vcpu->kvm, gpa, data, tocopy); + if (ret < 0) { + r = X86EMUL_UNHANDLEABLE; + goto out; + } + + bytes -= tocopy; + data += tocopy; + addr += tocopy; + } +out: + up_read(&vcpu->kvm->slots_lock); + return r; +} +EXPORT_SYMBOL_GPL(emulator_read_std); + +static int emulator_read_emulated(unsigned long addr, + void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu) +{ + struct kvm_io_device *mmio_dev; + gpa_t gpa; + + if (vcpu->mmio_read_completed) { + memcpy(val, vcpu->mmio_data, bytes); + vcpu->mmio_read_completed = 0; + return X86EMUL_CONTINUE; + } + + down_read(&vcpu->kvm->slots_lock); + gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); + up_read(&vcpu->kvm->slots_lock); + + /* For APIC access vmexit */ + if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) + goto mmio; + + if (emulator_read_std(addr, val, bytes, vcpu) + == X86EMUL_CONTINUE) + return X86EMUL_CONTINUE; + if (gpa == UNMAPPED_GVA) + return X86EMUL_PROPAGATE_FAULT; + +mmio: + /* + * Is this MMIO handled locally? + */ + mutex_lock(&vcpu->kvm->lock); + mmio_dev = vcpu_find_mmio_dev(vcpu, gpa); + if (mmio_dev) { + kvm_iodevice_read(mmio_dev, gpa, bytes, val); + mutex_unlock(&vcpu->kvm->lock); + return X86EMUL_CONTINUE; + } + mutex_unlock(&vcpu->kvm->lock); + + vcpu->mmio_needed = 1; + vcpu->mmio_phys_addr = gpa; + vcpu->mmio_size = bytes; + vcpu->mmio_is_write = 0; + + return X86EMUL_UNHANDLEABLE; +} + +static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, + const void *val, int bytes) +{ + int ret; + + down_read(&vcpu->kvm->slots_lock); + ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes); + if (ret < 0) { + up_read(&vcpu->kvm->slots_lock); + return 0; + } + kvm_mmu_pte_write(vcpu, gpa, val, bytes); + up_read(&vcpu->kvm->slots_lock); + return 1; +} + +static int emulator_write_emulated_onepage(unsigned long addr, + const void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu) +{ + struct kvm_io_device *mmio_dev; + gpa_t gpa; + + down_read(&vcpu->kvm->slots_lock); + gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); + up_read(&vcpu->kvm->slots_lock); + + if (gpa == UNMAPPED_GVA) { + kvm_inject_page_fault(vcpu, addr, 2); + return X86EMUL_PROPAGATE_FAULT; + } + + /* For APIC access vmexit */ + if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) + goto mmio; + + if (emulator_write_phys(vcpu, gpa, val, bytes)) + return X86EMUL_CONTINUE; + +mmio: + /* + * Is this MMIO handled locally? + */ + mutex_lock(&vcpu->kvm->lock); + mmio_dev = vcpu_find_mmio_dev(vcpu, gpa); + if (mmio_dev) { + kvm_iodevice_write(mmio_dev, gpa, bytes, val); + mutex_unlock(&vcpu->kvm->lock); + return X86EMUL_CONTINUE; + } + mutex_unlock(&vcpu->kvm->lock); + + vcpu->mmio_needed = 1; + vcpu->mmio_phys_addr = gpa; + vcpu->mmio_size = bytes; + vcpu->mmio_is_write = 1; + memcpy(vcpu->mmio_data, val, bytes); + + return X86EMUL_CONTINUE; +} + +int emulator_write_emulated(unsigned long addr, + const void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu) +{ + /* Crossing a page boundary? */ + if (((addr + bytes - 1) ^ addr) & PAGE_MASK) { + int rc, now; + + now = -addr & ~PAGE_MASK; + rc = emulator_write_emulated_onepage(addr, val, now, vcpu); + if (rc != X86EMUL_CONTINUE) + return rc; + addr += now; + val += now; + bytes -= now; + } + return emulator_write_emulated_onepage(addr, val, bytes, vcpu); +} +EXPORT_SYMBOL_GPL(emulator_write_emulated); + +static int emulator_cmpxchg_emulated(unsigned long addr, + const void *old, + const void *new, + unsigned int bytes, + struct kvm_vcpu *vcpu) +{ + static int reported; + + if (!reported) { + reported = 1; + printk(KERN_WARNING "kvm: emulating exchange as write\n"); + } +#ifndef CONFIG_X86_64 + /* guests cmpxchg8b have to be emulated atomically */ + if (bytes == 8) { + gpa_t gpa; + struct page *page; + char *kaddr; + u64 val; + + down_read(&vcpu->kvm->slots_lock); + gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); + + if (gpa == UNMAPPED_GVA || + (gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) + goto emul_write; + + if (((gpa + bytes - 1) & PAGE_MASK) != (gpa & PAGE_MASK)) + goto emul_write; + + val = *(u64 *)new; + + down_read(¤t->mm->mmap_sem); + page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); + up_read(¤t->mm->mmap_sem); + + kaddr = kmap_atomic(page, KM_USER0); + set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val); + kunmap_atomic(kaddr, KM_USER0); + kvm_release_page_dirty(page); + emul_write: + up_read(&vcpu->kvm->slots_lock); + } +#endif + + return emulator_write_emulated(addr, new, bytes, vcpu); +} + +static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) +{ + return kvm_x86_ops->get_segment_base(vcpu, seg); +} + +int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address) +{ + return X86EMUL_CONTINUE; +} + +int emulate_clts(struct kvm_vcpu *vcpu) +{ + kvm_x86_ops->set_cr0(vcpu, vcpu->arch.cr0 & ~X86_CR0_TS); + return X86EMUL_CONTINUE; +} + +int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest) +{ + struct kvm_vcpu *vcpu = ctxt->vcpu; + + switch (dr) { + case 0 ... 3: + *dest = kvm_x86_ops->get_dr(vcpu, dr); + return X86EMUL_CONTINUE; + default: + pr_unimpl(vcpu, "%s: unexpected dr %u\n", __FUNCTION__, dr); + return X86EMUL_UNHANDLEABLE; + } +} + +int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value) +{ + unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U; + int exception; + + kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception); + if (exception) { + /* FIXME: better handling */ + return X86EMUL_UNHANDLEABLE; + } + return X86EMUL_CONTINUE; +} + +void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context) +{ + static int reported; + u8 opcodes[4]; + unsigned long rip = vcpu->arch.rip; + unsigned long rip_linear; + + rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS); + + if (reported) + return; + + emulator_read_std(rip_linear, (void *)opcodes, 4, vcpu); + + printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n", + context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]); + reported = 1; +} +EXPORT_SYMBOL_GPL(kvm_report_emulation_failure); + +static struct x86_emulate_ops emulate_ops = { + .read_std = emulator_read_std, + .read_emulated = emulator_read_emulated, + .write_emulated = emulator_write_emulated, + .cmpxchg_emulated = emulator_cmpxchg_emulated, +}; + +int emulate_instruction(struct kvm_vcpu *vcpu, + struct kvm_run *run, + unsigned long cr2, + u16 error_code, + int emulation_type) +{ + int r; + struct decode_cache *c; + + vcpu->arch.mmio_fault_cr2 = cr2; + kvm_x86_ops->cache_regs(vcpu); + + vcpu->mmio_is_write = 0; + vcpu->arch.pio.string = 0; + + if (!(emulation_type & EMULTYPE_NO_DECODE)) { + int cs_db, cs_l; + kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); + + vcpu->arch.emulate_ctxt.vcpu = vcpu; + vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu); + vcpu->arch.emulate_ctxt.mode = + (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM) + ? X86EMUL_MODE_REAL : cs_l + ? X86EMUL_MODE_PROT64 : cs_db + ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; + + if (vcpu->arch.emulate_ctxt.mode == X86EMUL_MODE_PROT64) { + vcpu->arch.emulate_ctxt.cs_base = 0; + vcpu->arch.emulate_ctxt.ds_base = 0; + vcpu->arch.emulate_ctxt.es_base = 0; + vcpu->arch.emulate_ctxt.ss_base = 0; + } else { + vcpu->arch.emulate_ctxt.cs_base = + get_segment_base(vcpu, VCPU_SREG_CS); + vcpu->arch.emulate_ctxt.ds_base = + get_segment_base(vcpu, VCPU_SREG_DS); + vcpu->arch.emulate_ctxt.es_base = + get_segment_base(vcpu, VCPU_SREG_ES); + vcpu->arch.emulate_ctxt.ss_base = + get_segment_base(vcpu, VCPU_SREG_SS); + } + + vcpu->arch.emulate_ctxt.gs_base = + get_segment_base(vcpu, VCPU_SREG_GS); + vcpu->arch.emulate_ctxt.fs_base = + get_segment_base(vcpu, VCPU_SREG_FS); + + r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops); + + /* Reject the instructions other than VMCALL/VMMCALL when + * try to emulate invalid opcode */ + c = &vcpu->arch.emulate_ctxt.decode; + if ((emulation_type & EMULTYPE_TRAP_UD) && + (!(c->twobyte && c->b == 0x01 && + (c->modrm_reg == 0 || c->modrm_reg == 3) && + c->modrm_mod == 3 && c->modrm_rm == 1))) + return EMULATE_FAIL; + + ++vcpu->stat.insn_emulation; + if (r) { + ++vcpu->stat.insn_emulation_fail; + if (kvm_mmu_unprotect_page_virt(vcpu, cr2)) + return EMULATE_DONE; + return EMULATE_FAIL; + } + } + + r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops); + + if (vcpu->arch.pio.string) + return EMULATE_DO_MMIO; + + if ((r || vcpu->mmio_is_write) && run) { + run->exit_reason = KVM_EXIT_MMIO; + run->mmio.phys_addr = vcpu->mmio_phys_addr; + memcpy(run->mmio.data, vcpu->mmio_data, 8); + run->mmio.len = vcpu->mmio_size; + run->mmio.is_write = vcpu->mmio_is_write; + } + + if (r) { + if (kvm_mmu_unprotect_page_virt(vcpu, cr2)) + return EMULATE_DONE; + if (!vcpu->mmio_needed) { + kvm_report_emulation_failure(vcpu, "mmio"); + return EMULATE_FAIL; + } + return EMULATE_DO_MMIO; + } + + kvm_x86_ops->decache_regs(vcpu); + kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags); + + if (vcpu->mmio_is_write) { + vcpu->mmio_needed = 0; + return EMULATE_DO_MMIO; + } + + return EMULATE_DONE; +} +EXPORT_SYMBOL_GPL(emulate_instruction); + +static void free_pio_guest_pages(struct kvm_vcpu *vcpu) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vcpu->arch.pio.guest_pages); ++i) + if (vcpu->arch.pio.guest_pages[i]) { + kvm_release_page_dirty(vcpu->arch.pio.guest_pages[i]); + vcpu->arch.pio.guest_pages[i] = NULL; + } +} + +static int pio_copy_data(struct kvm_vcpu *vcpu) +{ + void *p = vcpu->arch.pio_data; + void *q; + unsigned bytes; + int nr_pages = vcpu->arch.pio.guest_pages[1] ? 2 : 1; + + q = vmap(vcpu->arch.pio.guest_pages, nr_pages, VM_READ|VM_WRITE, + PAGE_KERNEL); + if (!q) { + free_pio_guest_pages(vcpu); + return -ENOMEM; + } + q += vcpu->arch.pio.guest_page_offset; + bytes = vcpu->arch.pio.size * vcpu->arch.pio.cur_count; + if (vcpu->arch.pio.in) + memcpy(q, p, bytes); + else + memcpy(p, q, bytes); + q -= vcpu->arch.pio.guest_page_offset; + vunmap(q); + free_pio_guest_pages(vcpu); + return 0; +} + +int complete_pio(struct kvm_vcpu *vcpu) +{ + struct kvm_pio_request *io = &vcpu->arch.pio; + long delta; + int r; + + kvm_x86_ops->cache_regs(vcpu); + + if (!io->string) { + if (io->in) + memcpy(&vcpu->arch.regs[VCPU_REGS_RAX], vcpu->arch.pio_data, + io->size); + } else { + if (io->in) { + r = pio_copy_data(vcpu); + if (r) { + kvm_x86_ops->cache_regs(vcpu); + return r; + } + } + + delta = 1; + if (io->rep) { + delta *= io->cur_count; + /* + * The size of the register should really depend on + * current address size. + */ + vcpu->arch.regs[VCPU_REGS_RCX] -= delta; + } + if (io->down) + delta = -delta; + delta *= io->size; + if (io->in) + vcpu->arch.regs[VCPU_REGS_RDI] += delta; + else + vcpu->arch.regs[VCPU_REGS_RSI] += delta; + } + + kvm_x86_ops->decache_regs(vcpu); + + io->count -= io->cur_count; + io->cur_count = 0; + + return 0; +} + +static void kernel_pio(struct kvm_io_device *pio_dev, + struct kvm_vcpu *vcpu, + void *pd) +{ + /* TODO: String I/O for in kernel device */ + + mutex_lock(&vcpu->kvm->lock); + if (vcpu->arch.pio.in) + kvm_iodevice_read(pio_dev, vcpu->arch.pio.port, + vcpu->arch.pio.size, + pd); + else + kvm_iodevice_write(pio_dev, vcpu->arch.pio.port, + vcpu->arch.pio.size, + pd); + mutex_unlock(&vcpu->kvm->lock); +} + +static void pio_string_write(struct kvm_io_device *pio_dev, + struct kvm_vcpu *vcpu) +{ + struct kvm_pio_request *io = &vcpu->arch.pio; + void *pd = vcpu->arch.pio_data; + int i; + + mutex_lock(&vcpu->kvm->lock); + for (i = 0; i < io->cur_count; i++) { + kvm_iodevice_write(pio_dev, io->port, + io->size, + pd); + pd += io->size; + } + mutex_unlock(&vcpu->kvm->lock); +} + +static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, + gpa_t addr) +{ + return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr); +} + +int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned port) +{ + struct kvm_io_device *pio_dev; + + vcpu->run->exit_reason = KVM_EXIT_IO; + vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; + vcpu->run->io.size = vcpu->arch.pio.size = size; + vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; + vcpu->run->io.count = vcpu->arch.pio.count = vcpu->arch.pio.cur_count = 1; + vcpu->run->io.port = vcpu->arch.pio.port = port; + vcpu->arch.pio.in = in; + vcpu->arch.pio.string = 0; + vcpu->arch.pio.down = 0; + vcpu->arch.pio.guest_page_offset = 0; + vcpu->arch.pio.rep = 0; + + kvm_x86_ops->cache_regs(vcpu); + memcpy(vcpu->arch.pio_data, &vcpu->arch.regs[VCPU_REGS_RAX], 4); + kvm_x86_ops->decache_regs(vcpu); + + kvm_x86_ops->skip_emulated_instruction(vcpu); + + pio_dev = vcpu_find_pio_dev(vcpu, port); + if (pio_dev) { + kernel_pio(pio_dev, vcpu, vcpu->arch.pio_data); + complete_pio(vcpu); + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(kvm_emulate_pio); + +int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned long count, int down, + gva_t address, int rep, unsigned port) +{ + unsigned now, in_page; + int i, ret = 0; + int nr_pages = 1; + struct page *page; + struct kvm_io_device *pio_dev; + + vcpu->run->exit_reason = KVM_EXIT_IO; + vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; + vcpu->run->io.size = vcpu->arch.pio.size = size; + vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; + vcpu->run->io.count = vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count; + vcpu->run->io.port = vcpu->arch.pio.port = port; + vcpu->arch.pio.in = in; + vcpu->arch.pio.string = 1; + vcpu->arch.pio.down = down; + vcpu->arch.pio.guest_page_offset = offset_in_page(address); + vcpu->arch.pio.rep = rep; + + if (!count) { + kvm_x86_ops->skip_emulated_instruction(vcpu); + return 1; + } + + if (!down) + in_page = PAGE_SIZE - offset_in_page(address); + else + in_page = offset_in_page(address) + size; + now = min(count, (unsigned long)in_page / size); + if (!now) { + /* + * String I/O straddles page boundary. Pin two guest pages + * so that we satisfy atomicity constraints. Do just one + * transaction to avoid complexity. + */ + nr_pages = 2; + now = 1; + } + if (down) { + /* + * String I/O in reverse. Yuck. Kill the guest, fix later. + */ + pr_unimpl(vcpu, "guest string pio down\n"); + kvm_inject_gp(vcpu, 0); + return 1; + } + vcpu->run->io.count = now; + vcpu->arch.pio.cur_count = now; + + if (vcpu->arch.pio.cur_count == vcpu->arch.pio.count) + kvm_x86_ops->skip_emulated_instruction(vcpu); + + for (i = 0; i < nr_pages; ++i) { + down_read(&vcpu->kvm->slots_lock); + page = gva_to_page(vcpu, address + i * PAGE_SIZE); + vcpu->arch.pio.guest_pages[i] = page; + up_read(&vcpu->kvm->slots_lock); + if (!page) { + kvm_inject_gp(vcpu, 0); + free_pio_guest_pages(vcpu); + return 1; + } + } + + pio_dev = vcpu_find_pio_dev(vcpu, port); + if (!vcpu->arch.pio.in) { + /* string PIO write */ + ret = pio_copy_data(vcpu); + if (ret >= 0 && pio_dev) { + pio_string_write(pio_dev, vcpu); + complete_pio(vcpu); + if (vcpu->arch.pio.count == 0) + ret = 1; + } + } else if (pio_dev) + pr_unimpl(vcpu, "no string pio read support yet, " + "port %x size %d count %ld\n", + port, size, count); + + return ret; +} +EXPORT_SYMBOL_GPL(kvm_emulate_pio_string); + +int kvm_arch_init(void *opaque) +{ + int r; + struct kvm_x86_ops *ops = (struct kvm_x86_ops *)opaque; + + if (kvm_x86_ops) { + printk(KERN_ERR "kvm: already loaded the other module\n"); + r = -EEXIST; + goto out; + } + + if (!ops->cpu_has_kvm_support()) { + printk(KERN_ERR "kvm: no hardware support\n"); + r = -EOPNOTSUPP; + goto out; + } + if (ops->disabled_by_bios()) { + printk(KERN_ERR "kvm: disabled by bios\n"); + r = -EOPNOTSUPP; + goto out; + } + + r = kvm_mmu_module_init(); + if (r) + goto out; + + kvm_init_msr_list(); + + kvm_x86_ops = ops; + kvm_mmu_set_nonpresent_ptes(0ull, 0ull); + return 0; + +out: + return r; +} + +void kvm_arch_exit(void) +{ + kvm_x86_ops = NULL; + kvm_mmu_module_exit(); +} + +int kvm_emulate_halt(struct kvm_vcpu *vcpu) +{ + ++vcpu->stat.halt_exits; + if (irqchip_in_kernel(vcpu->kvm)) { + vcpu->arch.mp_state = VCPU_MP_STATE_HALTED; + kvm_vcpu_block(vcpu); + if (vcpu->arch.mp_state != VCPU_MP_STATE_RUNNABLE) + return -EINTR; + return 1; + } else { + vcpu->run->exit_reason = KVM_EXIT_HLT; + return 0; + } +} +EXPORT_SYMBOL_GPL(kvm_emulate_halt); + +int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) +{ + unsigned long nr, a0, a1, a2, a3, ret; + + kvm_x86_ops->cache_regs(vcpu); + + nr = vcpu->arch.regs[VCPU_REGS_RAX]; + a0 = vcpu->arch.regs[VCPU_REGS_RBX]; + a1 = vcpu->arch.regs[VCPU_REGS_RCX]; + a2 = vcpu->arch.regs[VCPU_REGS_RDX]; + a3 = vcpu->arch.regs[VCPU_REGS_RSI]; + + if (!is_long_mode(vcpu)) { + nr &= 0xFFFFFFFF; + a0 &= 0xFFFFFFFF; + a1 &= 0xFFFFFFFF; + a2 &= 0xFFFFFFFF; + a3 &= 0xFFFFFFFF; + } + + if (kvm_x86_ops->get_cpl(vcpu) != 0) { + ret = -KVM_EPERM; + goto out; + } + + switch (nr) { + case KVM_HC_VAPIC_POLL_IRQ: + ret = 0; + break; + default: + ret = -KVM_ENOSYS; + break; + } +out: + vcpu->arch.regs[VCPU_REGS_RAX] = ret; + kvm_x86_ops->decache_regs(vcpu); + ++vcpu->stat.hypercalls; + return 0; +} +EXPORT_SYMBOL_GPL(kvm_emulate_hypercall); + +int kvm_fix_hypercall(struct kvm_vcpu *vcpu) +{ + char instruction[3]; + int ret = 0; + + + /* + * Blow out the MMU to ensure that no other VCPU has an active mapping + * to ensure that the updated hypercall appears atomically across all + * VCPUs. + */ + kvm_mmu_zap_all(vcpu->kvm); + + kvm_x86_ops->cache_regs(vcpu); + kvm_x86_ops->patch_hypercall(vcpu, instruction); + if (emulator_write_emulated(vcpu->arch.rip, instruction, 3, vcpu) + != X86EMUL_CONTINUE) + ret = -EFAULT; + + return ret; +} + +static u64 mk_cr_64(u64 curr_cr, u32 new_val) +{ + return (curr_cr & ~((1ULL << 32) - 1)) | new_val; +} + +void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) +{ + struct descriptor_table dt = { limit, base }; + + kvm_x86_ops->set_gdt(vcpu, &dt); +} + +void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) +{ + struct descriptor_table dt = { limit, base }; + + kvm_x86_ops->set_idt(vcpu, &dt); +} + +void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, + unsigned long *rflags) +{ + kvm_lmsw(vcpu, msw); + *rflags = kvm_x86_ops->get_rflags(vcpu); +} + +unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr) +{ + kvm_x86_ops->decache_cr4_guest_bits(vcpu); + switch (cr) { + case 0: + return vcpu->arch.cr0; + case 2: + return vcpu->arch.cr2; + case 3: + return vcpu->arch.cr3; + case 4: + return vcpu->arch.cr4; + case 8: + return kvm_get_cr8(vcpu); + default: + vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr); + return 0; + } +} + +void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val, + unsigned long *rflags) +{ + switch (cr) { + case 0: + kvm_set_cr0(vcpu, mk_cr_64(vcpu->arch.cr0, val)); + *rflags = kvm_x86_ops->get_rflags(vcpu); + break; + case 2: + vcpu->arch.cr2 = val; + break; + case 3: + kvm_set_cr3(vcpu, val); + break; + case 4: + kvm_set_cr4(vcpu, mk_cr_64(vcpu->arch.cr4, val)); + break; + case 8: + kvm_set_cr8(vcpu, val & 0xfUL); + break; + default: + vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr); + } +} + +static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i) +{ + struct kvm_cpuid_entry2 *e = &vcpu->arch.cpuid_entries[i]; + int j, nent = vcpu->arch.cpuid_nent; + + e->flags &= ~KVM_CPUID_FLAG_STATE_READ_NEXT; + /* when no next entry is found, the current entry[i] is reselected */ + for (j = i + 1; j == i; j = (j + 1) % nent) { + struct kvm_cpuid_entry2 *ej = &vcpu->arch.cpuid_entries[j]; + if (ej->function == e->function) { + ej->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT; + return j; + } + } + return 0; /* silence gcc, even though control never reaches here */ +} + +/* find an entry with matching function, matching index (if needed), and that + * should be read next (if it's stateful) */ +static int is_matching_cpuid_entry(struct kvm_cpuid_entry2 *e, + u32 function, u32 index) +{ + if (e->function != function) + return 0; + if ((e->flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX) && e->index != index) + return 0; + if ((e->flags & KVM_CPUID_FLAG_STATEFUL_FUNC) && + !(e->flags & KVM_CPUID_FLAG_STATE_READ_NEXT)) + return 0; + return 1; +} + +void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) +{ + int i; + u32 function, index; + struct kvm_cpuid_entry2 *e, *best; + + kvm_x86_ops->cache_regs(vcpu); + function = vcpu->arch.regs[VCPU_REGS_RAX]; + index = vcpu->arch.regs[VCPU_REGS_RCX]; + vcpu->arch.regs[VCPU_REGS_RAX] = 0; + vcpu->arch.regs[VCPU_REGS_RBX] = 0; + vcpu->arch.regs[VCPU_REGS_RCX] = 0; + vcpu->arch.regs[VCPU_REGS_RDX] = 0; + best = NULL; + for (i = 0; i < vcpu->arch.cpuid_nent; ++i) { + e = &vcpu->arch.cpuid_entries[i]; + if (is_matching_cpuid_entry(e, function, index)) { + if (e->flags & KVM_CPUID_FLAG_STATEFUL_FUNC) + move_to_next_stateful_cpuid_entry(vcpu, i); + best = e; + break; + } + /* + * Both basic or both extended? + */ + if (((e->function ^ function) & 0x80000000) == 0) + if (!best || e->function > best->function) + best = e; + } + if (best) { + vcpu->arch.regs[VCPU_REGS_RAX] = best->eax; + vcpu->arch.regs[VCPU_REGS_RBX] = best->ebx; + vcpu->arch.regs[VCPU_REGS_RCX] = best->ecx; + vcpu->arch.regs[VCPU_REGS_RDX] = best->edx; + } + kvm_x86_ops->decache_regs(vcpu); + kvm_x86_ops->skip_emulated_instruction(vcpu); +} +EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); + +/* + * Check if userspace requested an interrupt window, and that the + * interrupt window is open. + * + * No need to exit to userspace if we already have an interrupt queued. + */ +static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + return (!vcpu->arch.irq_summary && + kvm_run->request_interrupt_window && + vcpu->arch.interrupt_window_open && + (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF)); +} + +static void post_kvm_run_save(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0; + kvm_run->cr8 = kvm_get_cr8(vcpu); + kvm_run->apic_base = kvm_get_apic_base(vcpu); + if (irqchip_in_kernel(vcpu->kvm)) + kvm_run->ready_for_interrupt_injection = 1; + else + kvm_run->ready_for_interrupt_injection = + (vcpu->arch.interrupt_window_open && + vcpu->arch.irq_summary == 0); +} + +static void vapic_enter(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + struct page *page; + + if (!apic || !apic->vapic_addr) + return; + + down_read(¤t->mm->mmap_sem); + page = gfn_to_page(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT); + up_read(¤t->mm->mmap_sem); + + vcpu->arch.apic->vapic_page = page; +} + +static void vapic_exit(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + + if (!apic || !apic->vapic_addr) + return; + + kvm_release_page_dirty(apic->vapic_page); + mark_page_dirty(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT); +} + +static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + int r; + + if (unlikely(vcpu->arch.mp_state == VCPU_MP_STATE_SIPI_RECEIVED)) { + pr_debug("vcpu %d received sipi with vector # %x\n", + vcpu->vcpu_id, vcpu->arch.sipi_vector); + kvm_lapic_reset(vcpu); + r = kvm_x86_ops->vcpu_reset(vcpu); + if (r) + return r; + vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE; + } + + vapic_enter(vcpu); + +preempted: + if (vcpu->guest_debug.enabled) + kvm_x86_ops->guest_debug_pre(vcpu); + +again: + if (vcpu->requests) + if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) + kvm_mmu_unload(vcpu); + + r = kvm_mmu_reload(vcpu); + if (unlikely(r)) + goto out; + + if (vcpu->requests) { + if (test_and_clear_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests)) + __kvm_migrate_apic_timer(vcpu); + if (test_and_clear_bit(KVM_REQ_REPORT_TPR_ACCESS, + &vcpu->requests)) { + kvm_run->exit_reason = KVM_EXIT_TPR_ACCESS; + r = 0; + goto out; + } + if (test_and_clear_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests)) { + kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; + r = 0; + goto out; + } + } + + kvm_inject_pending_timer_irqs(vcpu); + + preempt_disable(); + + kvm_x86_ops->prepare_guest_switch(vcpu); + kvm_load_guest_fpu(vcpu); + + local_irq_disable(); + + if (need_resched()) { + local_irq_enable(); + preempt_enable(); + r = 1; + goto out; + } + + if (vcpu->requests) + if (test_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) { + local_irq_enable(); + preempt_enable(); + r = 1; + goto out; + } + + if (signal_pending(current)) { + local_irq_enable(); + preempt_enable(); + r = -EINTR; + kvm_run->exit_reason = KVM_EXIT_INTR; + ++vcpu->stat.signal_exits; + goto out; + } + + if (vcpu->arch.exception.pending) + __queue_exception(vcpu); + else if (irqchip_in_kernel(vcpu->kvm)) + kvm_x86_ops->inject_pending_irq(vcpu); + else + kvm_x86_ops->inject_pending_vectors(vcpu, kvm_run); + + kvm_lapic_sync_to_vapic(vcpu); + + vcpu->guest_mode = 1; + kvm_guest_enter(); + + if (vcpu->requests) + if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests)) + kvm_x86_ops->tlb_flush(vcpu); + + kvm_x86_ops->run(vcpu, kvm_run); + + vcpu->guest_mode = 0; + local_irq_enable(); + + ++vcpu->stat.exits; + + /* + * We must have an instruction between local_irq_enable() and + * kvm_guest_exit(), so the timer interrupt isn't delayed by + * the interrupt shadow. The stat.exits increment will do nicely. + * But we need to prevent reordering, hence this barrier(): + */ + barrier(); + + kvm_guest_exit(); + + preempt_enable(); + + /* + * Profile KVM exit RIPs: + */ + if (unlikely(prof_on == KVM_PROFILING)) { + kvm_x86_ops->cache_regs(vcpu); + profile_hit(KVM_PROFILING, (void *)vcpu->arch.rip); + } + + if (vcpu->arch.exception.pending && kvm_x86_ops->exception_injected(vcpu)) + vcpu->arch.exception.pending = false; + + kvm_lapic_sync_from_vapic(vcpu); + + r = kvm_x86_ops->handle_exit(kvm_run, vcpu); + + if (r > 0) { + if (dm_request_for_irq_injection(vcpu, kvm_run)) { + r = -EINTR; + kvm_run->exit_reason = KVM_EXIT_INTR; + ++vcpu->stat.request_irq_exits; + goto out; + } + if (!need_resched()) + goto again; + } + +out: + if (r > 0) { + kvm_resched(vcpu); + goto preempted; + } + + post_kvm_run_save(vcpu, kvm_run); + + vapic_exit(vcpu); + + return r; +} + +int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + int r; + sigset_t sigsaved; + + vcpu_load(vcpu); + + if (unlikely(vcpu->arch.mp_state == VCPU_MP_STATE_UNINITIALIZED)) { + kvm_vcpu_block(vcpu); + vcpu_put(vcpu); + return -EAGAIN; + } + + if (vcpu->sigset_active) + sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); + + /* re-sync apic's tpr */ + if (!irqchip_in_kernel(vcpu->kvm)) + kvm_set_cr8(vcpu, kvm_run->cr8); + + if (vcpu->arch.pio.cur_count) { + r = complete_pio(vcpu); + if (r) + goto out; + } +#if CONFIG_HAS_IOMEM + if (vcpu->mmio_needed) { + memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8); + vcpu->mmio_read_completed = 1; + vcpu->mmio_needed = 0; + r = emulate_instruction(vcpu, kvm_run, + vcpu->arch.mmio_fault_cr2, 0, + EMULTYPE_NO_DECODE); + if (r == EMULATE_DO_MMIO) { + /* + * Read-modify-write. Back to userspace. + */ + r = 0; + goto out; + } + } +#endif + if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL) { + kvm_x86_ops->cache_regs(vcpu); + vcpu->arch.regs[VCPU_REGS_RAX] = kvm_run->hypercall.ret; + kvm_x86_ops->decache_regs(vcpu); + } + + r = __vcpu_run(vcpu, kvm_run); + +out: + if (vcpu->sigset_active) + sigprocmask(SIG_SETMASK, &sigsaved, NULL); + + vcpu_put(vcpu); + return r; +} + +int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) +{ + vcpu_load(vcpu); + + kvm_x86_ops->cache_regs(vcpu); + + regs->rax = vcpu->arch.regs[VCPU_REGS_RAX]; + regs->rbx = vcpu->arch.regs[VCPU_REGS_RBX]; + regs->rcx = vcpu->arch.regs[VCPU_REGS_RCX]; + regs->rdx = vcpu->arch.regs[VCPU_REGS_RDX]; + regs->rsi = vcpu->arch.regs[VCPU_REGS_RSI]; + regs->rdi = vcpu->arch.regs[VCPU_REGS_RDI]; + regs->rsp = vcpu->arch.regs[VCPU_REGS_RSP]; + regs->rbp = vcpu->arch.regs[VCPU_REGS_RBP]; +#ifdef CONFIG_X86_64 + regs->r8 = vcpu->arch.regs[VCPU_REGS_R8]; + regs->r9 = vcpu->arch.regs[VCPU_REGS_R9]; + regs->r10 = vcpu->arch.regs[VCPU_REGS_R10]; + regs->r11 = vcpu->arch.regs[VCPU_REGS_R11]; + regs->r12 = vcpu->arch.regs[VCPU_REGS_R12]; + regs->r13 = vcpu->arch.regs[VCPU_REGS_R13]; + regs->r14 = vcpu->arch.regs[VCPU_REGS_R14]; + regs->r15 = vcpu->arch.regs[VCPU_REGS_R15]; +#endif + + regs->rip = vcpu->arch.rip; + regs->rflags = kvm_x86_ops->get_rflags(vcpu); + + /* + * Don't leak debug flags in case they were set for guest debugging + */ + if (vcpu->guest_debug.enabled && vcpu->guest_debug.singlestep) + regs->rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF); + + vcpu_put(vcpu); + + return 0; +} + +int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) +{ + vcpu_load(vcpu); + + vcpu->arch.regs[VCPU_REGS_RAX] = regs->rax; + vcpu->arch.regs[VCPU_REGS_RBX] = regs->rbx; + vcpu->arch.regs[VCPU_REGS_RCX] = regs->rcx; + vcpu->arch.regs[VCPU_REGS_RDX] = regs->rdx; + vcpu->arch.regs[VCPU_REGS_RSI] = regs->rsi; + vcpu->arch.regs[VCPU_REGS_RDI] = regs->rdi; + vcpu->arch.regs[VCPU_REGS_RSP] = regs->rsp; + vcpu->arch.regs[VCPU_REGS_RBP] = regs->rbp; +#ifdef CONFIG_X86_64 + vcpu->arch.regs[VCPU_REGS_R8] = regs->r8; + vcpu->arch.regs[VCPU_REGS_R9] = regs->r9; + vcpu->arch.regs[VCPU_REGS_R10] = regs->r10; + vcpu->arch.regs[VCPU_REGS_R11] = regs->r11; + vcpu->arch.regs[VCPU_REGS_R12] = regs->r12; + vcpu->arch.regs[VCPU_REGS_R13] = regs->r13; + vcpu->arch.regs[VCPU_REGS_R14] = regs->r14; + vcpu->arch.regs[VCPU_REGS_R15] = regs->r15; +#endif + + vcpu->arch.rip = regs->rip; + kvm_x86_ops->set_rflags(vcpu, regs->rflags); + + kvm_x86_ops->decache_regs(vcpu); + + vcpu_put(vcpu); + + return 0; +} + +static void get_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) +{ + kvm_x86_ops->get_segment(vcpu, var, seg); +} + +void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) +{ + struct kvm_segment cs; + + get_segment(vcpu, &cs, VCPU_SREG_CS); + *db = cs.db; + *l = cs.l; +} +EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits); + +int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, + struct kvm_sregs *sregs) +{ + struct descriptor_table dt; + int pending_vec; + + vcpu_load(vcpu); + + get_segment(vcpu, &sregs->cs, VCPU_SREG_CS); + get_segment(vcpu, &sregs->ds, VCPU_SREG_DS); + get_segment(vcpu, &sregs->es, VCPU_SREG_ES); + get_segment(vcpu, &sregs->fs, VCPU_SREG_FS); + get_segment(vcpu, &sregs->gs, VCPU_SREG_GS); + get_segment(vcpu, &sregs->ss, VCPU_SREG_SS); + + get_segment(vcpu, &sregs->tr, VCPU_SREG_TR); + get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); + + kvm_x86_ops->get_idt(vcpu, &dt); + sregs->idt.limit = dt.limit; + sregs->idt.base = dt.base; + kvm_x86_ops->get_gdt(vcpu, &dt); + sregs->gdt.limit = dt.limit; + sregs->gdt.base = dt.base; + + kvm_x86_ops->decache_cr4_guest_bits(vcpu); + sregs->cr0 = vcpu->arch.cr0; + sregs->cr2 = vcpu->arch.cr2; + sregs->cr3 = vcpu->arch.cr3; + sregs->cr4 = vcpu->arch.cr4; + sregs->cr8 = kvm_get_cr8(vcpu); + sregs->efer = vcpu->arch.shadow_efer; + sregs->apic_base = kvm_get_apic_base(vcpu); + + if (irqchip_in_kernel(vcpu->kvm)) { + memset(sregs->interrupt_bitmap, 0, + sizeof sregs->interrupt_bitmap); + pending_vec = kvm_x86_ops->get_irq(vcpu); + if (pending_vec >= 0) + set_bit(pending_vec, + (unsigned long *)sregs->interrupt_bitmap); + } else + memcpy(sregs->interrupt_bitmap, vcpu->arch.irq_pending, + sizeof sregs->interrupt_bitmap); + + vcpu_put(vcpu); + + return 0; +} + +static void set_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) +{ + kvm_x86_ops->set_segment(vcpu, var, seg); +} + +int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, + struct kvm_sregs *sregs) +{ + int mmu_reset_needed = 0; + int i, pending_vec, max_bits; + struct descriptor_table dt; + + vcpu_load(vcpu); + + dt.limit = sregs->idt.limit; + dt.base = sregs->idt.base; + kvm_x86_ops->set_idt(vcpu, &dt); + dt.limit = sregs->gdt.limit; + dt.base = sregs->gdt.base; + kvm_x86_ops->set_gdt(vcpu, &dt); + + vcpu->arch.cr2 = sregs->cr2; + mmu_reset_needed |= vcpu->arch.cr3 != sregs->cr3; + + down_read(&vcpu->kvm->slots_lock); + if (gfn_to_memslot(vcpu->kvm, sregs->cr3 >> PAGE_SHIFT)) + vcpu->arch.cr3 = sregs->cr3; + else + set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests); + up_read(&vcpu->kvm->slots_lock); + + kvm_set_cr8(vcpu, sregs->cr8); + + mmu_reset_needed |= vcpu->arch.shadow_efer != sregs->efer; + kvm_x86_ops->set_efer(vcpu, sregs->efer); + kvm_set_apic_base(vcpu, sregs->apic_base); + + kvm_x86_ops->decache_cr4_guest_bits(vcpu); + + mmu_reset_needed |= vcpu->arch.cr0 != sregs->cr0; + kvm_x86_ops->set_cr0(vcpu, sregs->cr0); + vcpu->arch.cr0 = sregs->cr0; + + mmu_reset_needed |= vcpu->arch.cr4 != sregs->cr4; + kvm_x86_ops->set_cr4(vcpu, sregs->cr4); + if (!is_long_mode(vcpu) && is_pae(vcpu)) + load_pdptrs(vcpu, vcpu->arch.cr3); + + if (mmu_reset_needed) + kvm_mmu_reset_context(vcpu); + + if (!irqchip_in_kernel(vcpu->kvm)) { + memcpy(vcpu->arch.irq_pending, sregs->interrupt_bitmap, + sizeof vcpu->arch.irq_pending); + vcpu->arch.irq_summary = 0; + for (i = 0; i < ARRAY_SIZE(vcpu->arch.irq_pending); ++i) + if (vcpu->arch.irq_pending[i]) + __set_bit(i, &vcpu->arch.irq_summary); + } else { + max_bits = (sizeof sregs->interrupt_bitmap) << 3; + pending_vec = find_first_bit( + (const unsigned long *)sregs->interrupt_bitmap, + max_bits); + /* Only pending external irq is handled here */ + if (pending_vec < max_bits) { + kvm_x86_ops->set_irq(vcpu, pending_vec); + pr_debug("Set back pending irq %d\n", + pending_vec); + } + } + + set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); + set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); + set_segment(vcpu, &sregs->es, VCPU_SREG_ES); + set_segment(vcpu, &sregs->fs, VCPU_SREG_FS); + set_segment(vcpu, &sregs->gs, VCPU_SREG_GS); + set_segment(vcpu, &sregs->ss, VCPU_SREG_SS); + + set_segment(vcpu, &sregs->tr, VCPU_SREG_TR); + set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); + + vcpu_put(vcpu); + + return 0; +} + +int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, + struct kvm_debug_guest *dbg) +{ + int r; + + vcpu_load(vcpu); + + r = kvm_x86_ops->set_guest_debug(vcpu, dbg); + + vcpu_put(vcpu); + + return r; +} + +/* + * fxsave fpu state. Taken from x86_64/processor.h. To be killed when + * we have asm/x86/processor.h + */ +struct fxsave { + u16 cwd; + u16 swd; + u16 twd; + u16 fop; + u64 rip; + u64 rdp; + u32 mxcsr; + u32 mxcsr_mask; + u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ +#ifdef CONFIG_X86_64 + u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */ +#else + u32 xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */ +#endif +}; + +/* + * Translate a guest virtual address to a guest physical address. + */ +int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, + struct kvm_translation *tr) +{ + unsigned long vaddr = tr->linear_address; + gpa_t gpa; + + vcpu_load(vcpu); + down_read(&vcpu->kvm->slots_lock); + gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, vaddr); + up_read(&vcpu->kvm->slots_lock); + tr->physical_address = gpa; + tr->valid = gpa != UNMAPPED_GVA; + tr->writeable = 1; + tr->usermode = 0; + vcpu_put(vcpu); + + return 0; +} + +int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) +{ + struct fxsave *fxsave = (struct fxsave *)&vcpu->arch.guest_fx_image; + + vcpu_load(vcpu); + + memcpy(fpu->fpr, fxsave->st_space, 128); + fpu->fcw = fxsave->cwd; + fpu->fsw = fxsave->swd; + fpu->ftwx = fxsave->twd; + fpu->last_opcode = fxsave->fop; + fpu->last_ip = fxsave->rip; + fpu->last_dp = fxsave->rdp; + memcpy(fpu->xmm, fxsave->xmm_space, sizeof fxsave->xmm_space); + + vcpu_put(vcpu); + + return 0; +} + +int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) +{ + struct fxsave *fxsave = (struct fxsave *)&vcpu->arch.guest_fx_image; + + vcpu_load(vcpu); + + memcpy(fxsave->st_space, fpu->fpr, 128); + fxsave->cwd = fpu->fcw; + fxsave->swd = fpu->fsw; + fxsave->twd = fpu->ftwx; + fxsave->fop = fpu->last_opcode; + fxsave->rip = fpu->last_ip; + fxsave->rdp = fpu->last_dp; + memcpy(fxsave->xmm_space, fpu->xmm, sizeof fxsave->xmm_space); + + vcpu_put(vcpu); + + return 0; +} + +void fx_init(struct kvm_vcpu *vcpu) +{ + unsigned after_mxcsr_mask; + + /* Initialize guest FPU by resetting ours and saving into guest's */ + preempt_disable(); + fx_save(&vcpu->arch.host_fx_image); + fpu_init(); + fx_save(&vcpu->arch.guest_fx_image); + fx_restore(&vcpu->arch.host_fx_image); + preempt_enable(); + + vcpu->arch.cr0 |= X86_CR0_ET; + after_mxcsr_mask = offsetof(struct i387_fxsave_struct, st_space); + vcpu->arch.guest_fx_image.mxcsr = 0x1f80; + memset((void *)&vcpu->arch.guest_fx_image + after_mxcsr_mask, + 0, sizeof(struct i387_fxsave_struct) - after_mxcsr_mask); +} +EXPORT_SYMBOL_GPL(fx_init); + +void kvm_load_guest_fpu(struct kvm_vcpu *vcpu) +{ + if (!vcpu->fpu_active || vcpu->guest_fpu_loaded) + return; + + vcpu->guest_fpu_loaded = 1; + fx_save(&vcpu->arch.host_fx_image); + fx_restore(&vcpu->arch.guest_fx_image); +} +EXPORT_SYMBOL_GPL(kvm_load_guest_fpu); + +void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) +{ + if (!vcpu->guest_fpu_loaded) + return; + + vcpu->guest_fpu_loaded = 0; + fx_save(&vcpu->arch.guest_fx_image); + fx_restore(&vcpu->arch.host_fx_image); + ++vcpu->stat.fpu_reload; +} +EXPORT_SYMBOL_GPL(kvm_put_guest_fpu); + +void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu) +{ + kvm_x86_ops->vcpu_free(vcpu); +} + +struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, + unsigned int id) +{ + return kvm_x86_ops->vcpu_create(kvm, id); +} + +int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) +{ + int r; + + /* We do fxsave: this must be aligned. */ + BUG_ON((unsigned long)&vcpu->arch.host_fx_image & 0xF); + + vcpu_load(vcpu); + r = kvm_arch_vcpu_reset(vcpu); + if (r == 0) + r = kvm_mmu_setup(vcpu); + vcpu_put(vcpu); + if (r < 0) + goto free_vcpu; + + return 0; +free_vcpu: + kvm_x86_ops->vcpu_free(vcpu); + return r; +} + +void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) +{ + vcpu_load(vcpu); + kvm_mmu_unload(vcpu); + vcpu_put(vcpu); + + kvm_x86_ops->vcpu_free(vcpu); +} + +int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu) +{ + return kvm_x86_ops->vcpu_reset(vcpu); +} + +void kvm_arch_hardware_enable(void *garbage) +{ + kvm_x86_ops->hardware_enable(garbage); +} + +void kvm_arch_hardware_disable(void *garbage) +{ + kvm_x86_ops->hardware_disable(garbage); +} + +int kvm_arch_hardware_setup(void) +{ + return kvm_x86_ops->hardware_setup(); +} + +void kvm_arch_hardware_unsetup(void) +{ + kvm_x86_ops->hardware_unsetup(); +} + +void kvm_arch_check_processor_compat(void *rtn) +{ + kvm_x86_ops->check_processor_compatibility(rtn); +} + +int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) +{ + struct page *page; + struct kvm *kvm; + int r; + + BUG_ON(vcpu->kvm == NULL); + kvm = vcpu->kvm; + + vcpu->arch.mmu.root_hpa = INVALID_PAGE; + if (!irqchip_in_kernel(kvm) || vcpu->vcpu_id == 0) + vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE; + else + vcpu->arch.mp_state = VCPU_MP_STATE_UNINITIALIZED; + + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) { + r = -ENOMEM; + goto fail; + } + vcpu->arch.pio_data = page_address(page); + + r = kvm_mmu_create(vcpu); + if (r < 0) + goto fail_free_pio_data; + + if (irqchip_in_kernel(kvm)) { + r = kvm_create_lapic(vcpu); + if (r < 0) + goto fail_mmu_destroy; + } + + return 0; + +fail_mmu_destroy: + kvm_mmu_destroy(vcpu); +fail_free_pio_data: + free_page((unsigned long)vcpu->arch.pio_data); +fail: + return r; +} + +void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) +{ + kvm_free_lapic(vcpu); + kvm_mmu_destroy(vcpu); + free_page((unsigned long)vcpu->arch.pio_data); +} + +struct kvm *kvm_arch_create_vm(void) +{ + struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL); + + if (!kvm) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&kvm->arch.active_mmu_pages); + + return kvm; +} + +static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu) +{ + vcpu_load(vcpu); + kvm_mmu_unload(vcpu); + vcpu_put(vcpu); +} + +static void kvm_free_vcpus(struct kvm *kvm) +{ + unsigned int i; + + /* + * Unpin any mmu pages first. + */ + for (i = 0; i < KVM_MAX_VCPUS; ++i) + if (kvm->vcpus[i]) + kvm_unload_vcpu_mmu(kvm->vcpus[i]); + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + if (kvm->vcpus[i]) { + kvm_arch_vcpu_free(kvm->vcpus[i]); + kvm->vcpus[i] = NULL; + } + } + +} + +void kvm_arch_destroy_vm(struct kvm *kvm) +{ + kfree(kvm->arch.vpic); + kfree(kvm->arch.vioapic); + kvm_free_vcpus(kvm); + kvm_free_physmem(kvm); + kfree(kvm); +} + +int kvm_arch_set_memory_region(struct kvm *kvm, + struct kvm_userspace_memory_region *mem, + struct kvm_memory_slot old, + int user_alloc) +{ + int npages = mem->memory_size >> PAGE_SHIFT; + struct kvm_memory_slot *memslot = &kvm->memslots[mem->slot]; + + /*To keep backward compatibility with older userspace, + *x86 needs to hanlde !user_alloc case. + */ + if (!user_alloc) { + if (npages && !old.rmap) { + down_write(¤t->mm->mmap_sem); + memslot->userspace_addr = do_mmap(NULL, 0, + npages * PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, + 0); + up_write(¤t->mm->mmap_sem); + + if (IS_ERR((void *)memslot->userspace_addr)) + return PTR_ERR((void *)memslot->userspace_addr); + } else { + if (!old.user_alloc && old.rmap) { + int ret; + + down_write(¤t->mm->mmap_sem); + ret = do_munmap(current->mm, old.userspace_addr, + old.npages * PAGE_SIZE); + up_write(¤t->mm->mmap_sem); + if (ret < 0) + printk(KERN_WARNING + "kvm_vm_ioctl_set_memory_region: " + "failed to munmap memory\n"); + } + } + } + + if (!kvm->arch.n_requested_mmu_pages) { + unsigned int nr_mmu_pages = kvm_mmu_calculate_mmu_pages(kvm); + kvm_mmu_change_mmu_pages(kvm, nr_mmu_pages); + } + + kvm_mmu_slot_remove_write_access(kvm, mem->slot); + kvm_flush_remote_tlbs(kvm); + + return 0; +} + +int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.mp_state == VCPU_MP_STATE_RUNNABLE + || vcpu->arch.mp_state == VCPU_MP_STATE_SIPI_RECEIVED; +} + +static void vcpu_kick_intr(void *info) +{ +#ifdef DEBUG + struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info; + printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu); +#endif +} + +void kvm_vcpu_kick(struct kvm_vcpu *vcpu) +{ + int ipi_pcpu = vcpu->cpu; + + if (waitqueue_active(&vcpu->wq)) { + wake_up_interruptible(&vcpu->wq); + ++vcpu->stat.halt_wakeup; + } + if (vcpu->guest_mode) + smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); +} --- linux-2.6.24.orig/arch/x86/kvm/mmu.c +++ linux-2.6.24/arch/x86/kvm/mmu.c @@ -0,0 +1,2176 @@ +/* + * Kernel-based Virtual Machine driver for Linux + * + * This module enables machines with Intel VT-x extensions to run virtual + * machines without emulation or binary translation. + * + * MMU support + * + * Copyright (C) 2006 Qumranet, Inc. + * + * Authors: + * Yaniv Kamay + * Avi Kivity + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "vmx.h" +#include "mmu.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * When setting this variable to true it enables Two-Dimensional-Paging + * where the hardware walks 2 page tables: + * 1. the guest-virtual to guest-physical + * 2. while doing 1. it walks guest-physical to host-physical + * If the hardware supports that we don't need to do shadow paging. + */ +static bool tdp_enabled = false; + +#undef MMU_DEBUG + +#undef AUDIT + +#ifdef AUDIT +static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg); +#else +static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {} +#endif + +#ifdef MMU_DEBUG + +#define pgprintk(x...) do { if (dbg) printk(x); } while (0) +#define rmap_printk(x...) do { if (dbg) printk(x); } while (0) + +#else + +#define pgprintk(x...) do { } while (0) +#define rmap_printk(x...) do { } while (0) + +#endif + +#if defined(MMU_DEBUG) || defined(AUDIT) +static int dbg = 1; +#endif + +#ifndef MMU_DEBUG +#define ASSERT(x) do { } while (0) +#else +#define ASSERT(x) \ + if (!(x)) { \ + printk(KERN_WARNING "assertion failed %s:%d: %s\n", \ + __FILE__, __LINE__, #x); \ + } +#endif + +#define PT64_PT_BITS 9 +#define PT64_ENT_PER_PAGE (1 << PT64_PT_BITS) +#define PT32_PT_BITS 10 +#define PT32_ENT_PER_PAGE (1 << PT32_PT_BITS) + +#define PT_WRITABLE_SHIFT 1 + +#define PT_PRESENT_MASK (1ULL << 0) +#define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT) +#define PT_USER_MASK (1ULL << 2) +#define PT_PWT_MASK (1ULL << 3) +#define PT_PCD_MASK (1ULL << 4) +#define PT_ACCESSED_MASK (1ULL << 5) +#define PT_DIRTY_MASK (1ULL << 6) +#define PT_PAGE_SIZE_MASK (1ULL << 7) +#define PT_PAT_MASK (1ULL << 7) +#define PT_GLOBAL_MASK (1ULL << 8) +#define PT64_NX_SHIFT 63 +#define PT64_NX_MASK (1ULL << PT64_NX_SHIFT) + +#define PT_PAT_SHIFT 7 +#define PT_DIR_PAT_SHIFT 12 +#define PT_DIR_PAT_MASK (1ULL << PT_DIR_PAT_SHIFT) + +#define PT32_DIR_PSE36_SIZE 4 +#define PT32_DIR_PSE36_SHIFT 13 +#define PT32_DIR_PSE36_MASK \ + (((1ULL << PT32_DIR_PSE36_SIZE) - 1) << PT32_DIR_PSE36_SHIFT) + + +#define PT_FIRST_AVAIL_BITS_SHIFT 9 +#define PT64_SECOND_AVAIL_BITS_SHIFT 52 + +#define VALID_PAGE(x) ((x) != INVALID_PAGE) + +#define PT64_LEVEL_BITS 9 + +#define PT64_LEVEL_SHIFT(level) \ + (PAGE_SHIFT + (level - 1) * PT64_LEVEL_BITS) + +#define PT64_LEVEL_MASK(level) \ + (((1ULL << PT64_LEVEL_BITS) - 1) << PT64_LEVEL_SHIFT(level)) + +#define PT64_INDEX(address, level)\ + (((address) >> PT64_LEVEL_SHIFT(level)) & ((1 << PT64_LEVEL_BITS) - 1)) + + +#define PT32_LEVEL_BITS 10 + +#define PT32_LEVEL_SHIFT(level) \ + (PAGE_SHIFT + (level - 1) * PT32_LEVEL_BITS) + +#define PT32_LEVEL_MASK(level) \ + (((1ULL << PT32_LEVEL_BITS) - 1) << PT32_LEVEL_SHIFT(level)) + +#define PT32_INDEX(address, level)\ + (((address) >> PT32_LEVEL_SHIFT(level)) & ((1 << PT32_LEVEL_BITS) - 1)) + + +#define PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1)) +#define PT64_DIR_BASE_ADDR_MASK \ + (PT64_BASE_ADDR_MASK & ~((1ULL << (PAGE_SHIFT + PT64_LEVEL_BITS)) - 1)) + +#define PT32_BASE_ADDR_MASK PAGE_MASK +#define PT32_DIR_BASE_ADDR_MASK \ + (PAGE_MASK & ~((1ULL << (PAGE_SHIFT + PT32_LEVEL_BITS)) - 1)) + +#define PT64_PERM_MASK (PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK \ + | PT64_NX_MASK) + +#define PFERR_PRESENT_MASK (1U << 0) +#define PFERR_WRITE_MASK (1U << 1) +#define PFERR_USER_MASK (1U << 2) +#define PFERR_FETCH_MASK (1U << 4) + +#define PT64_ROOT_LEVEL 4 +#define PT32_ROOT_LEVEL 2 +#define PT32E_ROOT_LEVEL 3 + +#define PT_DIRECTORY_LEVEL 2 +#define PT_PAGE_TABLE_LEVEL 1 + +#define RMAP_EXT 4 + +#define ACC_EXEC_MASK 1 +#define ACC_WRITE_MASK PT_WRITABLE_MASK +#define ACC_USER_MASK PT_USER_MASK +#define ACC_ALL (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK) + +struct kvm_rmap_desc { + u64 *shadow_ptes[RMAP_EXT]; + struct kvm_rmap_desc *more; +}; + +static struct kmem_cache *pte_chain_cache; +static struct kmem_cache *rmap_desc_cache; +static struct kmem_cache *mmu_page_header_cache; + +static u64 __read_mostly shadow_trap_nonpresent_pte; +static u64 __read_mostly shadow_notrap_nonpresent_pte; + +void kvm_mmu_set_nonpresent_ptes(u64 trap_pte, u64 notrap_pte) +{ + shadow_trap_nonpresent_pte = trap_pte; + shadow_notrap_nonpresent_pte = notrap_pte; +} +EXPORT_SYMBOL_GPL(kvm_mmu_set_nonpresent_ptes); + +static int is_write_protection(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.cr0 & X86_CR0_WP; +} + +static int is_cpuid_PSE36(void) +{ + return 1; +} + +static int is_nx(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.shadow_efer & EFER_NX; +} + +static int is_present_pte(unsigned long pte) +{ + return pte & PT_PRESENT_MASK; +} + +static int is_shadow_present_pte(u64 pte) +{ + return pte != shadow_trap_nonpresent_pte + && pte != shadow_notrap_nonpresent_pte; +} + +static int is_large_pte(u64 pte) +{ + return pte & PT_PAGE_SIZE_MASK; +} + +static int is_writeble_pte(unsigned long pte) +{ + return pte & PT_WRITABLE_MASK; +} + +static int is_dirty_pte(unsigned long pte) +{ + return pte & PT_DIRTY_MASK; +} + +static int is_rmap_pte(u64 pte) +{ + return pte != shadow_trap_nonpresent_pte + && pte != shadow_notrap_nonpresent_pte; +} + +static gfn_t pse36_gfn_delta(u32 gpte) +{ + int shift = 32 - PT32_DIR_PSE36_SHIFT - PAGE_SHIFT; + + return (gpte & PT32_DIR_PSE36_MASK) << shift; +} + +static void set_shadow_pte(u64 *sptep, u64 spte) +{ +#ifdef CONFIG_X86_64 + set_64bit((unsigned long *)sptep, spte); +#else + set_64bit((unsigned long long *)sptep, spte); +#endif +} + +static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, + struct kmem_cache *base_cache, int min) +{ + void *obj; + + if (cache->nobjs >= min) + return 0; + while (cache->nobjs < ARRAY_SIZE(cache->objects)) { + obj = kmem_cache_zalloc(base_cache, GFP_KERNEL); + if (!obj) + return -ENOMEM; + cache->objects[cache->nobjs++] = obj; + } + return 0; +} + +static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc) +{ + while (mc->nobjs) + kfree(mc->objects[--mc->nobjs]); +} + +static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache, + int min) +{ + struct page *page; + + if (cache->nobjs >= min) + return 0; + while (cache->nobjs < ARRAY_SIZE(cache->objects)) { + page = alloc_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + set_page_private(page, 0); + cache->objects[cache->nobjs++] = page_address(page); + } + return 0; +} + +static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc) +{ + while (mc->nobjs) + free_page((unsigned long)mc->objects[--mc->nobjs]); +} + +static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) +{ + int r; + + r = mmu_topup_memory_cache(&vcpu->arch.mmu_pte_chain_cache, + pte_chain_cache, 4); + if (r) + goto out; + r = mmu_topup_memory_cache(&vcpu->arch.mmu_rmap_desc_cache, + rmap_desc_cache, 1); + if (r) + goto out; + r = mmu_topup_memory_cache_page(&vcpu->arch.mmu_page_cache, 8); + if (r) + goto out; + r = mmu_topup_memory_cache(&vcpu->arch.mmu_page_header_cache, + mmu_page_header_cache, 4); +out: + return r; +} + +static void mmu_free_memory_caches(struct kvm_vcpu *vcpu) +{ + mmu_free_memory_cache(&vcpu->arch.mmu_pte_chain_cache); + mmu_free_memory_cache(&vcpu->arch.mmu_rmap_desc_cache); + mmu_free_memory_cache_page(&vcpu->arch.mmu_page_cache); + mmu_free_memory_cache(&vcpu->arch.mmu_page_header_cache); +} + +static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc, + size_t size) +{ + void *p; + + BUG_ON(!mc->nobjs); + p = mc->objects[--mc->nobjs]; + memset(p, 0, size); + return p; +} + +static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu) +{ + return mmu_memory_cache_alloc(&vcpu->arch.mmu_pte_chain_cache, + sizeof(struct kvm_pte_chain)); +} + +static void mmu_free_pte_chain(struct kvm_pte_chain *pc) +{ + kfree(pc); +} + +static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu) +{ + return mmu_memory_cache_alloc(&vcpu->arch.mmu_rmap_desc_cache, + sizeof(struct kvm_rmap_desc)); +} + +static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd) +{ + kfree(rd); +} + +/* + * Return the pointer to the largepage write count for a given + * gfn, handling slots that are not large page aligned. + */ +static int *slot_largepage_idx(gfn_t gfn, struct kvm_memory_slot *slot) +{ + unsigned long idx; + + idx = (gfn / KVM_PAGES_PER_HPAGE) - + (slot->base_gfn / KVM_PAGES_PER_HPAGE); + return &slot->lpage_info[idx].write_count; +} + +static void account_shadowed(struct kvm *kvm, gfn_t gfn) +{ + int *write_count; + + write_count = slot_largepage_idx(gfn, gfn_to_memslot(kvm, gfn)); + *write_count += 1; + WARN_ON(*write_count > KVM_PAGES_PER_HPAGE); +} + +static void unaccount_shadowed(struct kvm *kvm, gfn_t gfn) +{ + int *write_count; + + write_count = slot_largepage_idx(gfn, gfn_to_memslot(kvm, gfn)); + *write_count -= 1; + WARN_ON(*write_count < 0); +} + +static int has_wrprotected_page(struct kvm *kvm, gfn_t gfn) +{ + struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn); + int *largepage_idx; + + if (slot) { + largepage_idx = slot_largepage_idx(gfn, slot); + return *largepage_idx; + } + + return 1; +} + +static int host_largepage_backed(struct kvm *kvm, gfn_t gfn) +{ + struct vm_area_struct *vma; + unsigned long addr; + + addr = gfn_to_hva(kvm, gfn); + if (kvm_is_error_hva(addr)) + return 0; + + vma = find_vma(current->mm, addr); + if (vma && is_vm_hugetlb_page(vma)) + return 1; + + return 0; +} + +static int is_largepage_backed(struct kvm_vcpu *vcpu, gfn_t large_gfn) +{ + struct kvm_memory_slot *slot; + + if (has_wrprotected_page(vcpu->kvm, large_gfn)) + return 0; + + if (!host_largepage_backed(vcpu->kvm, large_gfn)) + return 0; + + slot = gfn_to_memslot(vcpu->kvm, large_gfn); + if (slot && slot->dirty_bitmap) + return 0; + + return 1; +} + +/* + * Take gfn and return the reverse mapping to it. + * Note: gfn must be unaliased before this function get called + */ + +static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int lpage) +{ + struct kvm_memory_slot *slot; + unsigned long idx; + + slot = gfn_to_memslot(kvm, gfn); + if (!lpage) + return &slot->rmap[gfn - slot->base_gfn]; + + idx = (gfn / KVM_PAGES_PER_HPAGE) - + (slot->base_gfn / KVM_PAGES_PER_HPAGE); + + return &slot->lpage_info[idx].rmap_pde; +} + +/* + * Reverse mapping data structures: + * + * If rmapp bit zero is zero, then rmapp point to the shadw page table entry + * that points to page_address(page). + * + * If rmapp bit zero is one, (then rmap & ~1) points to a struct kvm_rmap_desc + * containing more mappings. + */ +static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn, int lpage) +{ + struct kvm_mmu_page *sp; + struct kvm_rmap_desc *desc; + unsigned long *rmapp; + int i; + + if (!is_rmap_pte(*spte)) + return; + gfn = unalias_gfn(vcpu->kvm, gfn); + sp = page_header(__pa(spte)); + sp->gfns[spte - sp->spt] = gfn; + rmapp = gfn_to_rmap(vcpu->kvm, gfn, lpage); + if (!*rmapp) { + rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte); + *rmapp = (unsigned long)spte; + } else if (!(*rmapp & 1)) { + rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte); + desc = mmu_alloc_rmap_desc(vcpu); + desc->shadow_ptes[0] = (u64 *)*rmapp; + desc->shadow_ptes[1] = spte; + *rmapp = (unsigned long)desc | 1; + } else { + rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte); + desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul); + while (desc->shadow_ptes[RMAP_EXT-1] && desc->more) + desc = desc->more; + if (desc->shadow_ptes[RMAP_EXT-1]) { + desc->more = mmu_alloc_rmap_desc(vcpu); + desc = desc->more; + } + for (i = 0; desc->shadow_ptes[i]; ++i) + ; + desc->shadow_ptes[i] = spte; + } +} + +static void rmap_desc_remove_entry(unsigned long *rmapp, + struct kvm_rmap_desc *desc, + int i, + struct kvm_rmap_desc *prev_desc) +{ + int j; + + for (j = RMAP_EXT - 1; !desc->shadow_ptes[j] && j > i; --j) + ; + desc->shadow_ptes[i] = desc->shadow_ptes[j]; + desc->shadow_ptes[j] = NULL; + if (j != 0) + return; + if (!prev_desc && !desc->more) + *rmapp = (unsigned long)desc->shadow_ptes[0]; + else + if (prev_desc) + prev_desc->more = desc->more; + else + *rmapp = (unsigned long)desc->more | 1; + mmu_free_rmap_desc(desc); +} + +static void rmap_remove(struct kvm *kvm, u64 *spte) +{ + struct kvm_rmap_desc *desc; + struct kvm_rmap_desc *prev_desc; + struct kvm_mmu_page *sp; + struct page *page; + unsigned long *rmapp; + int i; + + if (!is_rmap_pte(*spte)) + return; + sp = page_header(__pa(spte)); + page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT); + mark_page_accessed(page); + if (is_writeble_pte(*spte)) + kvm_release_page_dirty(page); + else + kvm_release_page_clean(page); + rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt], is_large_pte(*spte)); + if (!*rmapp) { + printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte); + BUG(); + } else if (!(*rmapp & 1)) { + rmap_printk("rmap_remove: %p %llx 1->0\n", spte, *spte); + if ((u64 *)*rmapp != spte) { + printk(KERN_ERR "rmap_remove: %p %llx 1->BUG\n", + spte, *spte); + BUG(); + } + *rmapp = 0; + } else { + rmap_printk("rmap_remove: %p %llx many->many\n", spte, *spte); + desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul); + prev_desc = NULL; + while (desc) { + for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i) + if (desc->shadow_ptes[i] == spte) { + rmap_desc_remove_entry(rmapp, + desc, i, + prev_desc); + return; + } + prev_desc = desc; + desc = desc->more; + } + BUG(); + } +} + +static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte) +{ + struct kvm_rmap_desc *desc; + struct kvm_rmap_desc *prev_desc; + u64 *prev_spte; + int i; + + if (!*rmapp) + return NULL; + else if (!(*rmapp & 1)) { + if (!spte) + return (u64 *)*rmapp; + return NULL; + } + desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul); + prev_desc = NULL; + prev_spte = NULL; + while (desc) { + for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i) { + if (prev_spte == spte) + return desc->shadow_ptes[i]; + prev_spte = desc->shadow_ptes[i]; + } + desc = desc->more; + } + return NULL; +} + +static void rmap_write_protect(struct kvm *kvm, u64 gfn) +{ + unsigned long *rmapp; + u64 *spte; + int write_protected = 0; + + gfn = unalias_gfn(kvm, gfn); + rmapp = gfn_to_rmap(kvm, gfn, 0); + + spte = rmap_next(kvm, rmapp, NULL); + while (spte) { + BUG_ON(!spte); + BUG_ON(!(*spte & PT_PRESENT_MASK)); + rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte); + if (is_writeble_pte(*spte)) { + set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK); + write_protected = 1; + } + spte = rmap_next(kvm, rmapp, spte); + } + /* check for huge page mappings */ + rmapp = gfn_to_rmap(kvm, gfn, 1); + spte = rmap_next(kvm, rmapp, NULL); + while (spte) { + BUG_ON(!spte); + BUG_ON(!(*spte & PT_PRESENT_MASK)); + BUG_ON((*spte & (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)) != (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)); + pgprintk("rmap_write_protect(large): spte %p %llx %lld\n", spte, *spte, gfn); + if (is_writeble_pte(*spte)) { + rmap_remove(kvm, spte); + --kvm->stat.lpages; + set_shadow_pte(spte, shadow_trap_nonpresent_pte); + write_protected = 1; + } + spte = rmap_next(kvm, rmapp, spte); + } + + if (write_protected) + kvm_flush_remote_tlbs(kvm); + + account_shadowed(kvm, gfn); +} + +#ifdef MMU_DEBUG +static int is_empty_shadow_page(u64 *spt) +{ + u64 *pos; + u64 *end; + + for (pos = spt, end = pos + PAGE_SIZE / sizeof(u64); pos != end; pos++) + if (*pos != shadow_trap_nonpresent_pte) { + printk(KERN_ERR "%s: %p %llx\n", __FUNCTION__, + pos, *pos); + return 0; + } + return 1; +} +#endif + +static void kvm_mmu_free_page(struct kvm *kvm, struct kvm_mmu_page *sp) +{ + ASSERT(is_empty_shadow_page(sp->spt)); + list_del(&sp->link); + __free_page(virt_to_page(sp->spt)); + __free_page(virt_to_page(sp->gfns)); + kfree(sp); + ++kvm->arch.n_free_mmu_pages; +} + +static unsigned kvm_page_table_hashfn(gfn_t gfn) +{ + return gfn & ((1 << KVM_MMU_HASH_SHIFT) - 1); +} + +static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, + u64 *parent_pte) +{ + struct kvm_mmu_page *sp; + + sp = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_header_cache, sizeof *sp); + sp->spt = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache, PAGE_SIZE); + sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache, PAGE_SIZE); + set_page_private(virt_to_page(sp->spt), (unsigned long)sp); + list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages); + ASSERT(is_empty_shadow_page(sp->spt)); + sp->slot_bitmap = 0; + sp->multimapped = 0; + sp->parent_pte = parent_pte; + --vcpu->kvm->arch.n_free_mmu_pages; + return sp; +} + +static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *sp, u64 *parent_pte) +{ + struct kvm_pte_chain *pte_chain; + struct hlist_node *node; + int i; + + if (!parent_pte) + return; + if (!sp->multimapped) { + u64 *old = sp->parent_pte; + + if (!old) { + sp->parent_pte = parent_pte; + return; + } + sp->multimapped = 1; + pte_chain = mmu_alloc_pte_chain(vcpu); + INIT_HLIST_HEAD(&sp->parent_ptes); + hlist_add_head(&pte_chain->link, &sp->parent_ptes); + pte_chain->parent_ptes[0] = old; + } + hlist_for_each_entry(pte_chain, node, &sp->parent_ptes, link) { + if (pte_chain->parent_ptes[NR_PTE_CHAIN_ENTRIES-1]) + continue; + for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) + if (!pte_chain->parent_ptes[i]) { + pte_chain->parent_ptes[i] = parent_pte; + return; + } + } + pte_chain = mmu_alloc_pte_chain(vcpu); + BUG_ON(!pte_chain); + hlist_add_head(&pte_chain->link, &sp->parent_ptes); + pte_chain->parent_ptes[0] = parent_pte; +} + +static void mmu_page_remove_parent_pte(struct kvm_mmu_page *sp, + u64 *parent_pte) +{ + struct kvm_pte_chain *pte_chain; + struct hlist_node *node; + int i; + + if (!sp->multimapped) { + BUG_ON(sp->parent_pte != parent_pte); + sp->parent_pte = NULL; + return; + } + hlist_for_each_entry(pte_chain, node, &sp->parent_ptes, link) + for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) { + if (!pte_chain->parent_ptes[i]) + break; + if (pte_chain->parent_ptes[i] != parent_pte) + continue; + while (i + 1 < NR_PTE_CHAIN_ENTRIES + && pte_chain->parent_ptes[i + 1]) { + pte_chain->parent_ptes[i] + = pte_chain->parent_ptes[i + 1]; + ++i; + } + pte_chain->parent_ptes[i] = NULL; + if (i == 0) { + hlist_del(&pte_chain->link); + mmu_free_pte_chain(pte_chain); + if (hlist_empty(&sp->parent_ptes)) { + sp->multimapped = 0; + sp->parent_pte = NULL; + } + } + return; + } + BUG(); +} + +static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm *kvm, gfn_t gfn) +{ + unsigned index; + struct hlist_head *bucket; + struct kvm_mmu_page *sp; + struct hlist_node *node; + + pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn); + index = kvm_page_table_hashfn(gfn); + bucket = &kvm->arch.mmu_page_hash[index]; + hlist_for_each_entry(sp, node, bucket, hash_link) + if (sp->gfn == gfn && !sp->role.metaphysical + && !sp->role.invalid) { + pgprintk("%s: found role %x\n", + __FUNCTION__, sp->role.word); + return sp; + } + return NULL; +} + +static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, + gfn_t gfn, + gva_t gaddr, + unsigned level, + int metaphysical, + unsigned access, + u64 *parent_pte, + bool *new_page) +{ + union kvm_mmu_page_role role; + unsigned index; + unsigned quadrant; + struct hlist_head *bucket; + struct kvm_mmu_page *sp; + struct hlist_node *node; + + role.word = 0; + role.glevels = vcpu->arch.mmu.root_level; + role.level = level; + role.metaphysical = metaphysical; + role.access = access; + if (vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) { + quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level)); + quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; + role.quadrant = quadrant; + } + pgprintk("%s: looking gfn %lx role %x\n", __FUNCTION__, + gfn, role.word); + index = kvm_page_table_hashfn(gfn); + bucket = &vcpu->kvm->arch.mmu_page_hash[index]; + hlist_for_each_entry(sp, node, bucket, hash_link) + if (sp->gfn == gfn && sp->role.word == role.word) { + mmu_page_add_parent_pte(vcpu, sp, parent_pte); + pgprintk("%s: found\n", __FUNCTION__); + return sp; + } + ++vcpu->kvm->stat.mmu_cache_miss; + sp = kvm_mmu_alloc_page(vcpu, parent_pte); + if (!sp) + return sp; + pgprintk("%s: adding gfn %lx role %x\n", __FUNCTION__, gfn, role.word); + sp->gfn = gfn; + sp->role = role; + hlist_add_head(&sp->hash_link, bucket); + if (!metaphysical) + rmap_write_protect(vcpu->kvm, gfn); + vcpu->arch.mmu.prefetch_page(vcpu, sp); + if (new_page) + *new_page = 1; + return sp; +} + +static void kvm_mmu_page_unlink_children(struct kvm *kvm, + struct kvm_mmu_page *sp) +{ + unsigned i; + u64 *pt; + u64 ent; + + pt = sp->spt; + + if (sp->role.level == PT_PAGE_TABLE_LEVEL) { + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { + if (is_shadow_present_pte(pt[i])) + rmap_remove(kvm, &pt[i]); + pt[i] = shadow_trap_nonpresent_pte; + } + kvm_flush_remote_tlbs(kvm); + return; + } + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { + ent = pt[i]; + + if (is_shadow_present_pte(ent)) { + if (!is_large_pte(ent)) { + ent &= PT64_BASE_ADDR_MASK; + mmu_page_remove_parent_pte(page_header(ent), + &pt[i]); + } else { + --kvm->stat.lpages; + rmap_remove(kvm, &pt[i]); + } + } + pt[i] = shadow_trap_nonpresent_pte; + } + kvm_flush_remote_tlbs(kvm); +} + +static void kvm_mmu_put_page(struct kvm_mmu_page *sp, u64 *parent_pte) +{ + mmu_page_remove_parent_pte(sp, parent_pte); +} + +static void kvm_mmu_reset_last_pte_updated(struct kvm *kvm) +{ + int i; + + for (i = 0; i < KVM_MAX_VCPUS; ++i) + if (kvm->vcpus[i]) + kvm->vcpus[i]->arch.last_pte_updated = NULL; +} + +static void kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp) +{ + u64 *parent_pte; + + ++kvm->stat.mmu_shadow_zapped; + while (sp->multimapped || sp->parent_pte) { + if (!sp->multimapped) + parent_pte = sp->parent_pte; + else { + struct kvm_pte_chain *chain; + + chain = container_of(sp->parent_ptes.first, + struct kvm_pte_chain, link); + parent_pte = chain->parent_ptes[0]; + } + BUG_ON(!parent_pte); + kvm_mmu_put_page(sp, parent_pte); + set_shadow_pte(parent_pte, shadow_trap_nonpresent_pte); + } + kvm_mmu_page_unlink_children(kvm, sp); + if (!sp->root_count) { + if (!sp->role.metaphysical) + unaccount_shadowed(kvm, sp->gfn); + hlist_del(&sp->hash_link); + kvm_mmu_free_page(kvm, sp); + } else { + list_move(&sp->link, &kvm->arch.active_mmu_pages); + sp->role.invalid = 1; + kvm_reload_remote_mmus(kvm); + } + kvm_mmu_reset_last_pte_updated(kvm); +} + +/* + * Changing the number of mmu pages allocated to the vm + * Note: if kvm_nr_mmu_pages is too small, you will get dead lock + */ +void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages) +{ + /* + * If we set the number of mmu pages to be smaller be than the + * number of actived pages , we must to free some mmu pages before we + * change the value + */ + + if ((kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages) > + kvm_nr_mmu_pages) { + int n_used_mmu_pages = kvm->arch.n_alloc_mmu_pages + - kvm->arch.n_free_mmu_pages; + + while (n_used_mmu_pages > kvm_nr_mmu_pages) { + struct kvm_mmu_page *page; + + page = container_of(kvm->arch.active_mmu_pages.prev, + struct kvm_mmu_page, link); + kvm_mmu_zap_page(kvm, page); + n_used_mmu_pages--; + } + kvm->arch.n_free_mmu_pages = 0; + } + else + kvm->arch.n_free_mmu_pages += kvm_nr_mmu_pages + - kvm->arch.n_alloc_mmu_pages; + + kvm->arch.n_alloc_mmu_pages = kvm_nr_mmu_pages; +} + +static int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn) +{ + unsigned index; + struct hlist_head *bucket; + struct kvm_mmu_page *sp; + struct hlist_node *node, *n; + int r; + + pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn); + r = 0; + index = kvm_page_table_hashfn(gfn); + bucket = &kvm->arch.mmu_page_hash[index]; + hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) + if (sp->gfn == gfn && !sp->role.metaphysical) { + pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn, + sp->role.word); + kvm_mmu_zap_page(kvm, sp); + r = 1; + } + return r; +} + +static void mmu_unshadow(struct kvm *kvm, gfn_t gfn) +{ + struct kvm_mmu_page *sp; + + while ((sp = kvm_mmu_lookup_page(kvm, gfn)) != NULL) { + pgprintk("%s: zap %lx %x\n", __FUNCTION__, gfn, sp->role.word); + kvm_mmu_zap_page(kvm, sp); + } +} + +static void page_header_update_slot(struct kvm *kvm, void *pte, gfn_t gfn) +{ + int slot = memslot_id(kvm, gfn_to_memslot(kvm, gfn)); + struct kvm_mmu_page *sp = page_header(__pa(pte)); + + __set_bit(slot, &sp->slot_bitmap); +} + +struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva) +{ + struct page *page; + + gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, gva); + + if (gpa == UNMAPPED_GVA) + return NULL; + + down_read(¤t->mm->mmap_sem); + page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); + up_read(¤t->mm->mmap_sem); + + return page; +} + +static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, + unsigned pt_access, unsigned pte_access, + int user_fault, int write_fault, int dirty, + int *ptwrite, int largepage, gfn_t gfn, + struct page *page) +{ + u64 spte; + int was_rmapped = is_rmap_pte(*shadow_pte); + int was_writeble = is_writeble_pte(*shadow_pte); + + /* + * If we overwrite a PTE page pointer with a 2MB PMD, unlink + * the parent of the now unreachable PTE. + */ + if (largepage) { + if (was_rmapped && !is_large_pte(*shadow_pte)) { + struct kvm_mmu_page *child; + u64 pte = *shadow_pte; + + child = page_header(pte & PT64_BASE_ADDR_MASK); + mmu_page_remove_parent_pte(child, shadow_pte); + } + was_rmapped = is_large_pte(*shadow_pte); + } + + pgprintk("%s: spte %llx access %x write_fault %d" + " user_fault %d gfn %lx\n", + __FUNCTION__, *shadow_pte, pt_access, + write_fault, user_fault, gfn); + + /* + * We don't set the accessed bit, since we sometimes want to see + * whether the guest actually used the pte (in order to detect + * demand paging). + */ + spte = PT_PRESENT_MASK | PT_DIRTY_MASK; + if (!dirty) + pte_access &= ~ACC_WRITE_MASK; + if (!(pte_access & ACC_EXEC_MASK)) + spte |= PT64_NX_MASK; + + spte |= PT_PRESENT_MASK; + if (pte_access & ACC_USER_MASK) + spte |= PT_USER_MASK; + if (largepage) + spte |= PT_PAGE_SIZE_MASK; + + spte |= page_to_phys(page); + + if ((pte_access & ACC_WRITE_MASK) + || (write_fault && !is_write_protection(vcpu) && !user_fault)) { + struct kvm_mmu_page *shadow; + + spte |= PT_WRITABLE_MASK; + if (user_fault) { + mmu_unshadow(vcpu->kvm, gfn); + goto unshadowed; + } + + shadow = kvm_mmu_lookup_page(vcpu->kvm, gfn); + if (shadow || + (largepage && has_wrprotected_page(vcpu->kvm, gfn))) { + pgprintk("%s: found shadow page for %lx, marking ro\n", + __FUNCTION__, gfn); + pte_access &= ~ACC_WRITE_MASK; + if (is_writeble_pte(spte)) { + spte &= ~PT_WRITABLE_MASK; + kvm_x86_ops->tlb_flush(vcpu); + } + if (write_fault) + *ptwrite = 1; + } + } + +unshadowed: + + if (pte_access & ACC_WRITE_MASK) + mark_page_dirty(vcpu->kvm, gfn); + + pgprintk("%s: setting spte %llx\n", __FUNCTION__, spte); + pgprintk("instantiating %s PTE (%s) at %d (%llx) addr %llx\n", + (spte&PT_PAGE_SIZE_MASK)? "2MB" : "4kB", + (spte&PT_WRITABLE_MASK)?"RW":"R", gfn, spte, shadow_pte); + set_shadow_pte(shadow_pte, spte); + if (!was_rmapped && (spte & PT_PAGE_SIZE_MASK) + && (spte & PT_PRESENT_MASK)) + ++vcpu->kvm->stat.lpages; + + page_header_update_slot(vcpu->kvm, shadow_pte, gfn); + if (!was_rmapped) { + rmap_add(vcpu, shadow_pte, gfn, largepage); + if (!is_rmap_pte(*shadow_pte)) + kvm_release_page_clean(page); + } else { + if (was_writeble) + kvm_release_page_dirty(page); + else + kvm_release_page_clean(page); + } + if (!ptwrite || !*ptwrite) + vcpu->arch.last_pte_updated = shadow_pte; +} + +static void nonpaging_new_cr3(struct kvm_vcpu *vcpu) +{ +} + +static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, + int largepage, gfn_t gfn, struct page *page, + int level) +{ + hpa_t table_addr = vcpu->arch.mmu.root_hpa; + int pt_write = 0; + + for (; ; level--) { + u32 index = PT64_INDEX(v, level); + u64 *table; + + ASSERT(VALID_PAGE(table_addr)); + table = __va(table_addr); + + if (level == 1) { + mmu_set_spte(vcpu, &table[index], ACC_ALL, ACC_ALL, + 0, write, 1, &pt_write, 0, gfn, page); + return pt_write; + } + + if (largepage && level == 2) { + mmu_set_spte(vcpu, &table[index], ACC_ALL, ACC_ALL, + 0, write, 1, &pt_write, 1, gfn, page); + return pt_write; + } + + if (table[index] == shadow_trap_nonpresent_pte) { + struct kvm_mmu_page *new_table; + gfn_t pseudo_gfn; + + pseudo_gfn = (v & PT64_DIR_BASE_ADDR_MASK) + >> PAGE_SHIFT; + new_table = kvm_mmu_get_page(vcpu, pseudo_gfn, + v, level - 1, + 1, ACC_ALL, &table[index], + NULL); + if (!new_table) { + pgprintk("nonpaging_map: ENOMEM\n"); + kvm_release_page_clean(page); + return -ENOMEM; + } + + table[index] = __pa(new_table->spt) | PT_PRESENT_MASK + | PT_WRITABLE_MASK | PT_USER_MASK; + } + table_addr = table[index] & PT64_BASE_ADDR_MASK; + } +} + +static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) +{ + int r; + int largepage = 0; + + struct page *page; + + down_read(&vcpu->kvm->slots_lock); + + down_read(¤t->mm->mmap_sem); + if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) { + gfn &= ~(KVM_PAGES_PER_HPAGE-1); + largepage = 1; + } + + page = gfn_to_page(vcpu->kvm, gfn); + up_read(¤t->mm->mmap_sem); + + /* mmio */ + if (is_error_page(page)) { + kvm_release_page_clean(page); + up_read(&vcpu->kvm->slots_lock); + return 1; + } + + spin_lock(&vcpu->kvm->mmu_lock); + kvm_mmu_free_some_pages(vcpu); + r = __direct_map(vcpu, v, write, largepage, gfn, page, + PT32E_ROOT_LEVEL); + spin_unlock(&vcpu->kvm->mmu_lock); + + up_read(&vcpu->kvm->slots_lock); + + return r; +} + + +static void nonpaging_prefetch_page(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *sp) +{ + int i; + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) + sp->spt[i] = shadow_trap_nonpresent_pte; +} + +static void mmu_free_roots(struct kvm_vcpu *vcpu) +{ + int i; + struct kvm_mmu_page *sp; + + if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + return; + spin_lock(&vcpu->kvm->mmu_lock); +#ifdef CONFIG_X86_64 + if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) { + hpa_t root = vcpu->arch.mmu.root_hpa; + + sp = page_header(root); + --sp->root_count; + if (!sp->root_count && sp->role.invalid) + kvm_mmu_zap_page(vcpu->kvm, sp); + vcpu->arch.mmu.root_hpa = INVALID_PAGE; + spin_unlock(&vcpu->kvm->mmu_lock); + return; + } +#endif + for (i = 0; i < 4; ++i) { + hpa_t root = vcpu->arch.mmu.pae_root[i]; + + if (root) { + root &= PT64_BASE_ADDR_MASK; + sp = page_header(root); + --sp->root_count; + if (!sp->root_count && sp->role.invalid) + kvm_mmu_zap_page(vcpu->kvm, sp); + } + vcpu->arch.mmu.pae_root[i] = INVALID_PAGE; + } + spin_unlock(&vcpu->kvm->mmu_lock); + vcpu->arch.mmu.root_hpa = INVALID_PAGE; +} + +static void mmu_alloc_roots(struct kvm_vcpu *vcpu) +{ + int i; + gfn_t root_gfn; + struct kvm_mmu_page *sp; + int metaphysical = 0; + + root_gfn = vcpu->arch.cr3 >> PAGE_SHIFT; + +#ifdef CONFIG_X86_64 + if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) { + hpa_t root = vcpu->arch.mmu.root_hpa; + + ASSERT(!VALID_PAGE(root)); + if (tdp_enabled) + metaphysical = 1; + sp = kvm_mmu_get_page(vcpu, root_gfn, 0, + PT64_ROOT_LEVEL, metaphysical, + ACC_ALL, NULL, NULL); + root = __pa(sp->spt); + ++sp->root_count; + vcpu->arch.mmu.root_hpa = root; + return; + } +#endif + metaphysical = !is_paging(vcpu); + if (tdp_enabled) + metaphysical = 1; + for (i = 0; i < 4; ++i) { + hpa_t root = vcpu->arch.mmu.pae_root[i]; + + ASSERT(!VALID_PAGE(root)); + if (vcpu->arch.mmu.root_level == PT32E_ROOT_LEVEL) { + if (!is_present_pte(vcpu->arch.pdptrs[i])) { + vcpu->arch.mmu.pae_root[i] = 0; + continue; + } + root_gfn = vcpu->arch.pdptrs[i] >> PAGE_SHIFT; + } else if (vcpu->arch.mmu.root_level == 0) + root_gfn = 0; + sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, + PT32_ROOT_LEVEL, metaphysical, + ACC_ALL, NULL, NULL); + root = __pa(sp->spt); + ++sp->root_count; + vcpu->arch.mmu.pae_root[i] = root | PT_PRESENT_MASK; + } + vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root); +} + +static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr) +{ + return vaddr; +} + +static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, + u32 error_code) +{ + gfn_t gfn; + int r; + + pgprintk("%s: gva %lx error %x\n", __FUNCTION__, gva, error_code); + r = mmu_topup_memory_caches(vcpu); + if (r) + return r; + + ASSERT(vcpu); + ASSERT(VALID_PAGE(vcpu->arch.mmu.root_hpa)); + + gfn = gva >> PAGE_SHIFT; + + return nonpaging_map(vcpu, gva & PAGE_MASK, + error_code & PFERR_WRITE_MASK, gfn); +} + +static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, + u32 error_code) +{ + struct page *page; + int r; + int largepage = 0; + gfn_t gfn = gpa >> PAGE_SHIFT; + + ASSERT(vcpu); + ASSERT(VALID_PAGE(vcpu->arch.mmu.root_hpa)); + + r = mmu_topup_memory_caches(vcpu); + if (r) + return r; + + down_read(¤t->mm->mmap_sem); + if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) { + gfn &= ~(KVM_PAGES_PER_HPAGE-1); + largepage = 1; + } + page = gfn_to_page(vcpu->kvm, gfn); + if (is_error_page(page)) { + kvm_release_page_clean(page); + up_read(¤t->mm->mmap_sem); + return 1; + } + spin_lock(&vcpu->kvm->mmu_lock); + kvm_mmu_free_some_pages(vcpu); + r = __direct_map(vcpu, gpa, error_code & PFERR_WRITE_MASK, + largepage, gfn, page, TDP_ROOT_LEVEL); + spin_unlock(&vcpu->kvm->mmu_lock); + up_read(¤t->mm->mmap_sem); + + return r; +} + +static void nonpaging_free(struct kvm_vcpu *vcpu) +{ + mmu_free_roots(vcpu); +} + +static int nonpaging_init_context(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu *context = &vcpu->arch.mmu; + + context->new_cr3 = nonpaging_new_cr3; + context->page_fault = nonpaging_page_fault; + context->gva_to_gpa = nonpaging_gva_to_gpa; + context->free = nonpaging_free; + context->prefetch_page = nonpaging_prefetch_page; + context->root_level = 0; + context->shadow_root_level = PT32E_ROOT_LEVEL; + context->root_hpa = INVALID_PAGE; + return 0; +} + +void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu) +{ + ++vcpu->stat.tlb_flush; + kvm_x86_ops->tlb_flush(vcpu); +} + +static void paging_new_cr3(struct kvm_vcpu *vcpu) +{ + pgprintk("%s: cr3 %lx\n", __FUNCTION__, vcpu->arch.cr3); + mmu_free_roots(vcpu); +} + +static void inject_page_fault(struct kvm_vcpu *vcpu, + u64 addr, + u32 err_code) +{ + kvm_inject_page_fault(vcpu, addr, err_code); +} + +static void paging_free(struct kvm_vcpu *vcpu) +{ + nonpaging_free(vcpu); +} + +#define PTTYPE 64 +#include "paging_tmpl.h" +#undef PTTYPE + +#define PTTYPE 32 +#include "paging_tmpl.h" +#undef PTTYPE + +static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level) +{ + struct kvm_mmu *context = &vcpu->arch.mmu; + + ASSERT(is_pae(vcpu)); + context->new_cr3 = paging_new_cr3; + context->page_fault = paging64_page_fault; + context->gva_to_gpa = paging64_gva_to_gpa; + context->prefetch_page = paging64_prefetch_page; + context->free = paging_free; + context->root_level = level; + context->shadow_root_level = level; + context->root_hpa = INVALID_PAGE; + return 0; +} + +static int paging64_init_context(struct kvm_vcpu *vcpu) +{ + return paging64_init_context_common(vcpu, PT64_ROOT_LEVEL); +} + +static int paging32_init_context(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu *context = &vcpu->arch.mmu; + + context->new_cr3 = paging_new_cr3; + context->page_fault = paging32_page_fault; + context->gva_to_gpa = paging32_gva_to_gpa; + context->free = paging_free; + context->prefetch_page = paging32_prefetch_page; + context->root_level = PT32_ROOT_LEVEL; + context->shadow_root_level = PT32E_ROOT_LEVEL; + context->root_hpa = INVALID_PAGE; + return 0; +} + +static int paging32E_init_context(struct kvm_vcpu *vcpu) +{ + return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL); +} + +static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu *context = &vcpu->arch.mmu; + + context->new_cr3 = nonpaging_new_cr3; + context->page_fault = tdp_page_fault; + context->free = nonpaging_free; + context->prefetch_page = nonpaging_prefetch_page; + context->shadow_root_level = TDP_ROOT_LEVEL; + context->root_hpa = INVALID_PAGE; + + if (!is_paging(vcpu)) { + context->gva_to_gpa = nonpaging_gva_to_gpa; + context->root_level = 0; + } else if (is_long_mode(vcpu)) { + context->gva_to_gpa = paging64_gva_to_gpa; + context->root_level = PT64_ROOT_LEVEL; + } else if (is_pae(vcpu)) { + context->gva_to_gpa = paging64_gva_to_gpa; + context->root_level = PT32E_ROOT_LEVEL; + } else { + context->gva_to_gpa = paging32_gva_to_gpa; + context->root_level = PT32_ROOT_LEVEL; + } + + return 0; +} + +static int init_kvm_softmmu(struct kvm_vcpu *vcpu) +{ + ASSERT(vcpu); + ASSERT(!VALID_PAGE(vcpu->arch.mmu.root_hpa)); + + if (!is_paging(vcpu)) + return nonpaging_init_context(vcpu); + else if (is_long_mode(vcpu)) + return paging64_init_context(vcpu); + else if (is_pae(vcpu)) + return paging32E_init_context(vcpu); + else + return paging32_init_context(vcpu); +} + +static int init_kvm_mmu(struct kvm_vcpu *vcpu) +{ + if (tdp_enabled) + return init_kvm_tdp_mmu(vcpu); + else + return init_kvm_softmmu(vcpu); +} + +static void destroy_kvm_mmu(struct kvm_vcpu *vcpu) +{ + ASSERT(vcpu); + if (VALID_PAGE(vcpu->arch.mmu.root_hpa)) { + vcpu->arch.mmu.free(vcpu); + vcpu->arch.mmu.root_hpa = INVALID_PAGE; + } +} + +int kvm_mmu_reset_context(struct kvm_vcpu *vcpu) +{ + destroy_kvm_mmu(vcpu); + return init_kvm_mmu(vcpu); +} +EXPORT_SYMBOL_GPL(kvm_mmu_reset_context); + +int kvm_mmu_load(struct kvm_vcpu *vcpu) +{ + int r; + + r = mmu_topup_memory_caches(vcpu); + if (r) + goto out; + spin_lock(&vcpu->kvm->mmu_lock); + kvm_mmu_free_some_pages(vcpu); + mmu_alloc_roots(vcpu); + spin_unlock(&vcpu->kvm->mmu_lock); + kvm_x86_ops->set_cr3(vcpu, vcpu->arch.mmu.root_hpa); + kvm_mmu_flush_tlb(vcpu); +out: + return r; +} +EXPORT_SYMBOL_GPL(kvm_mmu_load); + +void kvm_mmu_unload(struct kvm_vcpu *vcpu) +{ + mmu_free_roots(vcpu); +} + +static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *sp, + u64 *spte) +{ + u64 pte; + struct kvm_mmu_page *child; + + pte = *spte; + if (is_shadow_present_pte(pte)) { + if (sp->role.level == PT_PAGE_TABLE_LEVEL || + is_large_pte(pte)) + rmap_remove(vcpu->kvm, spte); + else { + child = page_header(pte & PT64_BASE_ADDR_MASK); + mmu_page_remove_parent_pte(child, spte); + } + } + set_shadow_pte(spte, shadow_trap_nonpresent_pte); + if (is_large_pte(pte)) + --vcpu->kvm->stat.lpages; +} + +static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *sp, + u64 *spte, + const void *new) +{ + if ((sp->role.level != PT_PAGE_TABLE_LEVEL) + && !vcpu->arch.update_pte.largepage) { + ++vcpu->kvm->stat.mmu_pde_zapped; + return; + } + + ++vcpu->kvm->stat.mmu_pte_updated; + if (sp->role.glevels == PT32_ROOT_LEVEL) + paging32_update_pte(vcpu, sp, spte, new); + else + paging64_update_pte(vcpu, sp, spte, new); +} + +static bool need_remote_flush(u64 old, u64 new) +{ + if (!is_shadow_present_pte(old)) + return false; + if (!is_shadow_present_pte(new)) + return true; + if ((old ^ new) & PT64_BASE_ADDR_MASK) + return true; + old ^= PT64_NX_MASK; + new ^= PT64_NX_MASK; + return (old & ~new & PT64_PERM_MASK) != 0; +} + +static void mmu_pte_write_flush_tlb(struct kvm_vcpu *vcpu, u64 old, u64 new) +{ + if (need_remote_flush(old, new)) + kvm_flush_remote_tlbs(vcpu->kvm); + else + kvm_mmu_flush_tlb(vcpu); +} + +static bool last_updated_pte_accessed(struct kvm_vcpu *vcpu) +{ + u64 *spte = vcpu->arch.last_pte_updated; + + return !!(spte && (*spte & PT_ACCESSED_MASK)); +} + +static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, + const u8 *new, int bytes) +{ + gfn_t gfn; + int r; + u64 gpte = 0; + struct page *page; + + vcpu->arch.update_pte.largepage = 0; + + if (bytes != 4 && bytes != 8) + return; + + /* + * Assume that the pte write on a page table of the same type + * as the current vcpu paging mode. This is nearly always true + * (might be false while changing modes). Note it is verified later + * by update_pte(). + */ + if (is_pae(vcpu)) { + /* Handle a 32-bit guest writing two halves of a 64-bit gpte */ + if ((bytes == 4) && (gpa % 4 == 0)) { + r = kvm_read_guest(vcpu->kvm, gpa & ~(u64)7, &gpte, 8); + if (r) + return; + memcpy((void *)&gpte + (gpa % 8), new, 4); + } else if ((bytes == 8) && (gpa % 8 == 0)) { + memcpy((void *)&gpte, new, 8); + } + } else { + if ((bytes == 4) && (gpa % 4 == 0)) + memcpy((void *)&gpte, new, 4); + } + if (!is_present_pte(gpte)) + return; + gfn = (gpte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; + + down_read(¤t->mm->mmap_sem); + if (is_large_pte(gpte) && is_largepage_backed(vcpu, gfn)) { + gfn &= ~(KVM_PAGES_PER_HPAGE-1); + vcpu->arch.update_pte.largepage = 1; + } + page = gfn_to_page(vcpu->kvm, gfn); + up_read(¤t->mm->mmap_sem); + + if (is_error_page(page)) { + kvm_release_page_clean(page); + return; + } + vcpu->arch.update_pte.gfn = gfn; + vcpu->arch.update_pte.page = page; +} + +void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, + const u8 *new, int bytes) +{ + gfn_t gfn = gpa >> PAGE_SHIFT; + struct kvm_mmu_page *sp; + struct hlist_node *node, *n; + struct hlist_head *bucket; + unsigned index; + u64 entry, gentry; + u64 *spte; + unsigned offset = offset_in_page(gpa); + unsigned pte_size; + unsigned page_offset; + unsigned misaligned; + unsigned quadrant; + int level; + int flooded = 0; + int npte; + int r; + + pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes); + mmu_guess_page_from_pte_write(vcpu, gpa, new, bytes); + spin_lock(&vcpu->kvm->mmu_lock); + kvm_mmu_free_some_pages(vcpu); + ++vcpu->kvm->stat.mmu_pte_write; + kvm_mmu_audit(vcpu, "pre pte write"); + if (gfn == vcpu->arch.last_pt_write_gfn + && !last_updated_pte_accessed(vcpu)) { + ++vcpu->arch.last_pt_write_count; + if (vcpu->arch.last_pt_write_count >= 3) + flooded = 1; + } else { + vcpu->arch.last_pt_write_gfn = gfn; + vcpu->arch.last_pt_write_count = 1; + vcpu->arch.last_pte_updated = NULL; + } + index = kvm_page_table_hashfn(gfn); + bucket = &vcpu->kvm->arch.mmu_page_hash[index]; + hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) { + if (sp->gfn != gfn || sp->role.metaphysical) + continue; + pte_size = sp->role.glevels == PT32_ROOT_LEVEL ? 4 : 8; + misaligned = (offset ^ (offset + bytes - 1)) & ~(pte_size - 1); + misaligned |= bytes < 4; + if (misaligned || flooded) { + /* + * Misaligned accesses are too much trouble to fix + * up; also, they usually indicate a page is not used + * as a page table. + * + * If we're seeing too many writes to a page, + * it may no longer be a page table, or we may be + * forking, in which case it is better to unmap the + * page. + */ + pgprintk("misaligned: gpa %llx bytes %d role %x\n", + gpa, bytes, sp->role.word); + kvm_mmu_zap_page(vcpu->kvm, sp); + ++vcpu->kvm->stat.mmu_flooded; + continue; + } + page_offset = offset; + level = sp->role.level; + npte = 1; + if (sp->role.glevels == PT32_ROOT_LEVEL) { + page_offset <<= 1; /* 32->64 */ + /* + * A 32-bit pde maps 4MB while the shadow pdes map + * only 2MB. So we need to double the offset again + * and zap two pdes instead of one. + */ + if (level == PT32_ROOT_LEVEL) { + page_offset &= ~7; /* kill rounding error */ + page_offset <<= 1; + npte = 2; + } + quadrant = page_offset >> PAGE_SHIFT; + page_offset &= ~PAGE_MASK; + if (quadrant != sp->role.quadrant) + continue; + } + spte = &sp->spt[page_offset / sizeof(*spte)]; + if ((gpa & (pte_size - 1)) || (bytes < pte_size)) { + gentry = 0; + r = kvm_read_guest_atomic(vcpu->kvm, + gpa & ~(u64)(pte_size - 1), + &gentry, pte_size); + new = (const void *)&gentry; + if (r < 0) + new = NULL; + } + while (npte--) { + entry = *spte; + mmu_pte_write_zap_pte(vcpu, sp, spte); + if (new) + mmu_pte_write_new_pte(vcpu, sp, spte, new); + mmu_pte_write_flush_tlb(vcpu, entry, *spte); + ++spte; + } + } + kvm_mmu_audit(vcpu, "post pte write"); + spin_unlock(&vcpu->kvm->mmu_lock); + if (vcpu->arch.update_pte.page) { + kvm_release_page_clean(vcpu->arch.update_pte.page); + vcpu->arch.update_pte.page = NULL; + } +} + +int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva) +{ + gpa_t gpa; + int r; + + down_read(&vcpu->kvm->slots_lock); + gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, gva); + up_read(&vcpu->kvm->slots_lock); + + spin_lock(&vcpu->kvm->mmu_lock); + r = kvm_mmu_unprotect_page(vcpu->kvm, gpa >> PAGE_SHIFT); + spin_unlock(&vcpu->kvm->mmu_lock); + return r; +} + +void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) +{ + while (vcpu->kvm->arch.n_free_mmu_pages < KVM_REFILL_PAGES) { + struct kvm_mmu_page *sp; + + sp = container_of(vcpu->kvm->arch.active_mmu_pages.prev, + struct kvm_mmu_page, link); + kvm_mmu_zap_page(vcpu->kvm, sp); + ++vcpu->kvm->stat.mmu_recycled; + } +} + +int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code) +{ + int r; + enum emulation_result er; + + r = vcpu->arch.mmu.page_fault(vcpu, cr2, error_code); + if (r < 0) + goto out; + + if (!r) { + r = 1; + goto out; + } + + r = mmu_topup_memory_caches(vcpu); + if (r) + goto out; + + er = emulate_instruction(vcpu, vcpu->run, cr2, error_code, 0); + + switch (er) { + case EMULATE_DONE: + return 1; + case EMULATE_DO_MMIO: + ++vcpu->stat.mmio_exits; + return 0; + case EMULATE_FAIL: + kvm_report_emulation_failure(vcpu, "pagetable"); + return 1; + default: + BUG(); + } +out: + return r; +} +EXPORT_SYMBOL_GPL(kvm_mmu_page_fault); + +void kvm_enable_tdp(void) +{ + tdp_enabled = true; +} +EXPORT_SYMBOL_GPL(kvm_enable_tdp); + +static void free_mmu_pages(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu_page *sp; + + while (!list_empty(&vcpu->kvm->arch.active_mmu_pages)) { + sp = container_of(vcpu->kvm->arch.active_mmu_pages.next, + struct kvm_mmu_page, link); + kvm_mmu_zap_page(vcpu->kvm, sp); + } + free_page((unsigned long)vcpu->arch.mmu.pae_root); +} + +static int alloc_mmu_pages(struct kvm_vcpu *vcpu) +{ + struct page *page; + int i; + + ASSERT(vcpu); + + if (vcpu->kvm->arch.n_requested_mmu_pages) + vcpu->kvm->arch.n_free_mmu_pages = + vcpu->kvm->arch.n_requested_mmu_pages; + else + vcpu->kvm->arch.n_free_mmu_pages = + vcpu->kvm->arch.n_alloc_mmu_pages; + /* + * When emulating 32-bit mode, cr3 is only 32 bits even on x86_64. + * Therefore we need to allocate shadow page tables in the first + * 4GB of memory, which happens to fit the DMA32 zone. + */ + page = alloc_page(GFP_KERNEL | __GFP_DMA32); + if (!page) + goto error_1; + vcpu->arch.mmu.pae_root = page_address(page); + for (i = 0; i < 4; ++i) + vcpu->arch.mmu.pae_root[i] = INVALID_PAGE; + + return 0; + +error_1: + free_mmu_pages(vcpu); + return -ENOMEM; +} + +int kvm_mmu_create(struct kvm_vcpu *vcpu) +{ + ASSERT(vcpu); + ASSERT(!VALID_PAGE(vcpu->arch.mmu.root_hpa)); + + return alloc_mmu_pages(vcpu); +} + +int kvm_mmu_setup(struct kvm_vcpu *vcpu) +{ + ASSERT(vcpu); + ASSERT(!VALID_PAGE(vcpu->arch.mmu.root_hpa)); + + return init_kvm_mmu(vcpu); +} + +void kvm_mmu_destroy(struct kvm_vcpu *vcpu) +{ + ASSERT(vcpu); + + destroy_kvm_mmu(vcpu); + free_mmu_pages(vcpu); + mmu_free_memory_caches(vcpu); +} + +void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot) +{ + struct kvm_mmu_page *sp; + + spin_lock(&kvm->mmu_lock); + list_for_each_entry(sp, &kvm->arch.active_mmu_pages, link) { + int i; + u64 *pt; + + if (!test_bit(slot, &sp->slot_bitmap)) + continue; + + pt = sp->spt; + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) + /* avoid RMW */ + if (pt[i] & PT_WRITABLE_MASK) + pt[i] &= ~PT_WRITABLE_MASK; + } + spin_unlock(&kvm->mmu_lock); +} + +void kvm_mmu_zap_all(struct kvm *kvm) +{ + struct kvm_mmu_page *sp, *node; + + spin_lock(&kvm->mmu_lock); + list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link) + kvm_mmu_zap_page(kvm, sp); + spin_unlock(&kvm->mmu_lock); + + kvm_flush_remote_tlbs(kvm); +} + +void kvm_mmu_module_exit(void) +{ + if (pte_chain_cache) + kmem_cache_destroy(pte_chain_cache); + if (rmap_desc_cache) + kmem_cache_destroy(rmap_desc_cache); + if (mmu_page_header_cache) + kmem_cache_destroy(mmu_page_header_cache); +} + +int kvm_mmu_module_init(void) +{ + pte_chain_cache = kmem_cache_create("kvm_pte_chain", + sizeof(struct kvm_pte_chain), + 0, 0, NULL); + if (!pte_chain_cache) + goto nomem; + rmap_desc_cache = kmem_cache_create("kvm_rmap_desc", + sizeof(struct kvm_rmap_desc), + 0, 0, NULL); + if (!rmap_desc_cache) + goto nomem; + + mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header", + sizeof(struct kvm_mmu_page), + 0, 0, NULL); + if (!mmu_page_header_cache) + goto nomem; + + return 0; + +nomem: + kvm_mmu_module_exit(); + return -ENOMEM; +} + +/* + * Caculate mmu pages needed for kvm. + */ +unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm) +{ + int i; + unsigned int nr_mmu_pages; + unsigned int nr_pages = 0; + + for (i = 0; i < kvm->nmemslots; i++) + nr_pages += kvm->memslots[i].npages; + + nr_mmu_pages = nr_pages * KVM_PERMILLE_MMU_PAGES / 1000; + nr_mmu_pages = max(nr_mmu_pages, + (unsigned int) KVM_MIN_ALLOC_MMU_PAGES); + + return nr_mmu_pages; +} + +#ifdef AUDIT + +static const char *audit_msg; + +static gva_t canonicalize(gva_t gva) +{ +#ifdef CONFIG_X86_64 + gva = (long long)(gva << 16) >> 16; +#endif + return gva; +} + +static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, + gva_t va, int level) +{ + u64 *pt = __va(page_pte & PT64_BASE_ADDR_MASK); + int i; + gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1)); + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) { + u64 ent = pt[i]; + + if (ent == shadow_trap_nonpresent_pte) + continue; + + va = canonicalize(va); + if (level > 1) { + if (ent == shadow_notrap_nonpresent_pte) + printk(KERN_ERR "audit: (%s) nontrapping pte" + " in nonleaf level: levels %d gva %lx" + " level %d pte %llx\n", audit_msg, + vcpu->arch.mmu.root_level, va, level, ent); + + audit_mappings_page(vcpu, ent, va, level - 1); + } else { + gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, va); + struct page *page = gpa_to_page(vcpu, gpa); + hpa_t hpa = page_to_phys(page); + + if (is_shadow_present_pte(ent) + && (ent & PT64_BASE_ADDR_MASK) != hpa) + printk(KERN_ERR "xx audit error: (%s) levels %d" + " gva %lx gpa %llx hpa %llx ent %llx %d\n", + audit_msg, vcpu->arch.mmu.root_level, + va, gpa, hpa, ent, + is_shadow_present_pte(ent)); + else if (ent == shadow_notrap_nonpresent_pte + && !is_error_hpa(hpa)) + printk(KERN_ERR "audit: (%s) notrap shadow," + " valid guest gva %lx\n", audit_msg, va); + kvm_release_page_clean(page); + + } + } +} + +static void audit_mappings(struct kvm_vcpu *vcpu) +{ + unsigned i; + + if (vcpu->arch.mmu.root_level == 4) + audit_mappings_page(vcpu, vcpu->arch.mmu.root_hpa, 0, 4); + else + for (i = 0; i < 4; ++i) + if (vcpu->arch.mmu.pae_root[i] & PT_PRESENT_MASK) + audit_mappings_page(vcpu, + vcpu->arch.mmu.pae_root[i], + i << 30, + 2); +} + +static int count_rmaps(struct kvm_vcpu *vcpu) +{ + int nmaps = 0; + int i, j, k; + + for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { + struct kvm_memory_slot *m = &vcpu->kvm->memslots[i]; + struct kvm_rmap_desc *d; + + for (j = 0; j < m->npages; ++j) { + unsigned long *rmapp = &m->rmap[j]; + + if (!*rmapp) + continue; + if (!(*rmapp & 1)) { + ++nmaps; + continue; + } + d = (struct kvm_rmap_desc *)(*rmapp & ~1ul); + while (d) { + for (k = 0; k < RMAP_EXT; ++k) + if (d->shadow_ptes[k]) + ++nmaps; + else + break; + d = d->more; + } + } + } + return nmaps; +} + +static int count_writable_mappings(struct kvm_vcpu *vcpu) +{ + int nmaps = 0; + struct kvm_mmu_page *sp; + int i; + + list_for_each_entry(sp, &vcpu->kvm->arch.active_mmu_pages, link) { + u64 *pt = sp->spt; + + if (sp->role.level != PT_PAGE_TABLE_LEVEL) + continue; + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { + u64 ent = pt[i]; + + if (!(ent & PT_PRESENT_MASK)) + continue; + if (!(ent & PT_WRITABLE_MASK)) + continue; + ++nmaps; + } + } + return nmaps; +} + +static void audit_rmap(struct kvm_vcpu *vcpu) +{ + int n_rmap = count_rmaps(vcpu); + int n_actual = count_writable_mappings(vcpu); + + if (n_rmap != n_actual) + printk(KERN_ERR "%s: (%s) rmap %d actual %d\n", + __FUNCTION__, audit_msg, n_rmap, n_actual); +} + +static void audit_write_protection(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu_page *sp; + struct kvm_memory_slot *slot; + unsigned long *rmapp; + gfn_t gfn; + + list_for_each_entry(sp, &vcpu->kvm->arch.active_mmu_pages, link) { + if (sp->role.metaphysical) + continue; + + slot = gfn_to_memslot(vcpu->kvm, sp->gfn); + gfn = unalias_gfn(vcpu->kvm, sp->gfn); + rmapp = &slot->rmap[gfn - slot->base_gfn]; + if (*rmapp) + printk(KERN_ERR "%s: (%s) shadow page has writable" + " mappings: gfn %lx role %x\n", + __FUNCTION__, audit_msg, sp->gfn, + sp->role.word); + } +} + +static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) +{ + int olddbg = dbg; + + dbg = 0; + audit_msg = msg; + audit_rmap(vcpu); + audit_write_protection(vcpu); + audit_mappings(vcpu); + dbg = olddbg; +} + +#endif --- linux-2.6.24.orig/arch/x86/kvm/irq.h +++ linux-2.6.24/arch/x86/kvm/irq.h @@ -0,0 +1,88 @@ +/* + * irq.h: in kernel interrupt controller related definitions + * Copyright (c) 2007, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * Authors: + * Yaozu (Eddie) Dong + * + */ + +#ifndef __IRQ_H +#define __IRQ_H + +#include +#include +#include + +#include "iodev.h" +#include "ioapic.h" +#include "lapic.h" + +struct kvm; +struct kvm_vcpu; + +typedef void irq_request_func(void *opaque, int level); + +struct kvm_kpic_state { + u8 last_irr; /* edge detection */ + u8 irr; /* interrupt request register */ + u8 imr; /* interrupt mask register */ + u8 isr; /* interrupt service register */ + u8 priority_add; /* highest irq priority */ + u8 irq_base; + u8 read_reg_select; + u8 poll; + u8 special_mask; + u8 init_state; + u8 auto_eoi; + u8 rotate_on_auto_eoi; + u8 special_fully_nested_mode; + u8 init4; /* true if 4 byte init */ + u8 elcr; /* PIIX edge/trigger selection */ + u8 elcr_mask; + struct kvm_pic *pics_state; +}; + +struct kvm_pic { + struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */ + irq_request_func *irq_request; + void *irq_request_opaque; + int output; /* intr from master PIC */ + struct kvm_io_device dev; +}; + +struct kvm_pic *kvm_create_pic(struct kvm *kvm); +void kvm_pic_set_irq(void *opaque, int irq, int level); +int kvm_pic_read_irq(struct kvm_pic *s); +void kvm_pic_update_irq(struct kvm_pic *s); + +static inline struct kvm_pic *pic_irqchip(struct kvm *kvm) +{ + return kvm->arch.vpic; +} + +static inline int irqchip_in_kernel(struct kvm *kvm) +{ + return pic_irqchip(kvm) != NULL; +} + +void kvm_pic_reset(struct kvm_kpic_state *s); + +void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec); +void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); +void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); +void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); + +#endif --- linux-2.6.24.orig/arch/x86/kvm/mmu.h +++ linux-2.6.24/arch/x86/kvm/mmu.h @@ -0,0 +1,50 @@ +#ifndef __KVM_X86_MMU_H +#define __KVM_X86_MMU_H + +#include + +#ifdef CONFIG_X86_64 +#define TDP_ROOT_LEVEL PT64_ROOT_LEVEL +#else +#define TDP_ROOT_LEVEL PT32E_ROOT_LEVEL +#endif + +static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) +{ + if (unlikely(vcpu->kvm->arch.n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES)) + __kvm_mmu_free_some_pages(vcpu); +} + +static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu) +{ + if (likely(vcpu->arch.mmu.root_hpa != INVALID_PAGE)) + return 0; + + return kvm_mmu_load(vcpu); +} + +static inline int is_long_mode(struct kvm_vcpu *vcpu) +{ +#ifdef CONFIG_X86_64 + return vcpu->arch.shadow_efer & EFER_LME; +#else + return 0; +#endif +} + +static inline int is_pae(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.cr4 & X86_CR4_PAE; +} + +static inline int is_pse(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.cr4 & X86_CR4_PSE; +} + +static inline int is_paging(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.cr0 & X86_CR0_PG; +} + +#endif --- linux-2.6.24.orig/arch/x86/kvm/lapic.c +++ linux-2.6.24/arch/x86/kvm/lapic.c @@ -0,0 +1,1158 @@ + +/* + * Local APIC virtualization + * + * Copyright (C) 2006 Qumranet, Inc. + * Copyright (C) 2007 Novell + * Copyright (C) 2007 Intel + * + * Authors: + * Dor Laor + * Gregory Haskins + * Yaozu (Eddie) Dong + * + * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "irq.h" + +#define PRId64 "d" +#define PRIx64 "llx" +#define PRIu64 "u" +#define PRIo64 "o" + +#define APIC_BUS_CYCLE_NS 1 + +/* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */ +#define apic_debug(fmt, arg...) + +#define APIC_LVT_NUM 6 +/* 14 is the version for Xeon and Pentium 8.4.8*/ +#define APIC_VERSION (0x14UL | ((APIC_LVT_NUM - 1) << 16)) +#define LAPIC_MMIO_LENGTH (1 << 12) +/* followed define is not in apicdef.h */ +#define APIC_SHORT_MASK 0xc0000 +#define APIC_DEST_NOSHORT 0x0 +#define APIC_DEST_MASK 0x800 +#define MAX_APIC_VECTOR 256 + +#define VEC_POS(v) ((v) & (32 - 1)) +#define REG_POS(v) (((v) >> 5) << 4) + +static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off) +{ + return *((u32 *) (apic->regs + reg_off)); +} + +static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val) +{ + *((u32 *) (apic->regs + reg_off)) = val; +} + +static inline int apic_test_and_set_vector(int vec, void *bitmap) +{ + return test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline int apic_test_and_clear_vector(int vec, void *bitmap) +{ + return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline void apic_set_vector(int vec, void *bitmap) +{ + set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline void apic_clear_vector(int vec, void *bitmap) +{ + clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); +} + +static inline int apic_hw_enabled(struct kvm_lapic *apic) +{ + return (apic)->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE; +} + +static inline int apic_sw_enabled(struct kvm_lapic *apic) +{ + return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED; +} + +static inline int apic_enabled(struct kvm_lapic *apic) +{ + return apic_sw_enabled(apic) && apic_hw_enabled(apic); +} + +#define LVT_MASK \ + (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK) + +#define LINT_MASK \ + (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \ + APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER) + +static inline int kvm_apic_id(struct kvm_lapic *apic) +{ + return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff; +} + +static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type) +{ + return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED); +} + +static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type) +{ + return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK; +} + +static inline int apic_lvtt_period(struct kvm_lapic *apic) +{ + return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC; +} + +static unsigned int apic_lvt_mask[APIC_LVT_NUM] = { + LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */ + LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ + LVT_MASK | APIC_MODE_MASK, /* LVTPC */ + LINT_MASK, LINT_MASK, /* LVT0-1 */ + LVT_MASK /* LVTERR */ +}; + +static int find_highest_vector(void *bitmap) +{ + u32 *word = bitmap; + int word_offset = MAX_APIC_VECTOR >> 5; + + while ((word_offset != 0) && (word[(--word_offset) << 2] == 0)) + continue; + + if (likely(!word_offset && !word[0])) + return -1; + else + return fls(word[word_offset << 2]) - 1 + (word_offset << 5); +} + +static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic) +{ + return apic_test_and_set_vector(vec, apic->regs + APIC_IRR); +} + +static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) +{ + apic_clear_vector(vec, apic->regs + APIC_IRR); +} + +static inline int apic_find_highest_irr(struct kvm_lapic *apic) +{ + int result; + + result = find_highest_vector(apic->regs + APIC_IRR); + ASSERT(result == -1 || result >= 16); + + return result; +} + +int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + int highest_irr; + + if (!apic) + return 0; + highest_irr = apic_find_highest_irr(apic); + + return highest_irr; +} +EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr); + +int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + + if (!apic_test_and_set_irr(vec, apic)) { + /* a new pending irq is set in IRR */ + if (trig) + apic_set_vector(vec, apic->regs + APIC_TMR); + else + apic_clear_vector(vec, apic->regs + APIC_TMR); + kvm_vcpu_kick(apic->vcpu); + return 1; + } + return 0; +} + +static inline int apic_find_highest_isr(struct kvm_lapic *apic) +{ + int result; + + result = find_highest_vector(apic->regs + APIC_ISR); + ASSERT(result == -1 || result >= 16); + + return result; +} + +static void apic_update_ppr(struct kvm_lapic *apic) +{ + u32 tpr, isrv, ppr; + int isr; + + tpr = apic_get_reg(apic, APIC_TASKPRI); + isr = apic_find_highest_isr(apic); + isrv = (isr != -1) ? isr : 0; + + if ((tpr & 0xf0) >= (isrv & 0xf0)) + ppr = tpr & 0xff; + else + ppr = isrv & 0xf0; + + apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x", + apic, ppr, isr, isrv); + + apic_set_reg(apic, APIC_PROCPRI, ppr); +} + +static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr) +{ + apic_set_reg(apic, APIC_TASKPRI, tpr); + apic_update_ppr(apic); +} + +int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest) +{ + return kvm_apic_id(apic) == dest; +} + +int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) +{ + int result = 0; + u8 logical_id; + + logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR)); + + switch (apic_get_reg(apic, APIC_DFR)) { + case APIC_DFR_FLAT: + if (logical_id & mda) + result = 1; + break; + case APIC_DFR_CLUSTER: + if (((logical_id >> 4) == (mda >> 0x4)) + && (logical_id & mda & 0xf)) + result = 1; + break; + default: + printk(KERN_WARNING "Bad DFR vcpu %d: %08x\n", + apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR)); + break; + } + + return result; +} + +static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, + int short_hand, int dest, int dest_mode) +{ + int result = 0; + struct kvm_lapic *target = vcpu->arch.apic; + + apic_debug("target %p, source %p, dest 0x%x, " + "dest_mode 0x%x, short_hand 0x%x", + target, source, dest, dest_mode, short_hand); + + ASSERT(!target); + switch (short_hand) { + case APIC_DEST_NOSHORT: + if (dest_mode == 0) { + /* Physical mode. */ + if ((dest == 0xFF) || (dest == kvm_apic_id(target))) + result = 1; + } else + /* Logical mode. */ + result = kvm_apic_match_logical_addr(target, dest); + break; + case APIC_DEST_SELF: + if (target == source) + result = 1; + break; + case APIC_DEST_ALLINC: + result = 1; + break; + case APIC_DEST_ALLBUT: + if (target != source) + result = 1; + break; + default: + printk(KERN_WARNING "Bad dest shorthand value %x\n", + short_hand); + break; + } + + return result; +} + +/* + * Add a pending IRQ into lapic. + * Return 1 if successfully added and 0 if discarded. + */ +static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, + int vector, int level, int trig_mode) +{ + int orig_irr, result = 0; + struct kvm_vcpu *vcpu = apic->vcpu; + + switch (delivery_mode) { + case APIC_DM_FIXED: + case APIC_DM_LOWEST: + /* FIXME add logic for vcpu on reset */ + if (unlikely(!apic_enabled(apic))) + break; + + orig_irr = apic_test_and_set_irr(vector, apic); + if (orig_irr && trig_mode) { + apic_debug("level trig mode repeatedly for vector %d", + vector); + break; + } + + if (trig_mode) { + apic_debug("level trig mode for vector %d", vector); + apic_set_vector(vector, apic->regs + APIC_TMR); + } else + apic_clear_vector(vector, apic->regs + APIC_TMR); + + if (vcpu->arch.mp_state == VCPU_MP_STATE_RUNNABLE) + kvm_vcpu_kick(vcpu); + else if (vcpu->arch.mp_state == VCPU_MP_STATE_HALTED) { + vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE; + if (waitqueue_active(&vcpu->wq)) + wake_up_interruptible(&vcpu->wq); + } + + result = (orig_irr == 0); + break; + + case APIC_DM_REMRD: + printk(KERN_DEBUG "Ignoring delivery mode 3\n"); + break; + + case APIC_DM_SMI: + printk(KERN_DEBUG "Ignoring guest SMI\n"); + break; + case APIC_DM_NMI: + printk(KERN_DEBUG "Ignoring guest NMI\n"); + break; + + case APIC_DM_INIT: + if (level) { + if (vcpu->arch.mp_state == VCPU_MP_STATE_RUNNABLE) + printk(KERN_DEBUG + "INIT on a runnable vcpu %d\n", + vcpu->vcpu_id); + vcpu->arch.mp_state = VCPU_MP_STATE_INIT_RECEIVED; + kvm_vcpu_kick(vcpu); + } else { + printk(KERN_DEBUG + "Ignoring de-assert INIT to vcpu %d\n", + vcpu->vcpu_id); + } + + break; + + case APIC_DM_STARTUP: + printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n", + vcpu->vcpu_id, vector); + if (vcpu->arch.mp_state == VCPU_MP_STATE_INIT_RECEIVED) { + vcpu->arch.sipi_vector = vector; + vcpu->arch.mp_state = VCPU_MP_STATE_SIPI_RECEIVED; + if (waitqueue_active(&vcpu->wq)) + wake_up_interruptible(&vcpu->wq); + } + break; + + default: + printk(KERN_ERR "TODO: unsupported delivery mode %x\n", + delivery_mode); + break; + } + return result; +} + +static struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector, + unsigned long bitmap) +{ + int last; + int next; + struct kvm_lapic *apic = NULL; + + last = kvm->arch.round_robin_prev_vcpu; + next = last; + + do { + if (++next == KVM_MAX_VCPUS) + next = 0; + if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap)) + continue; + apic = kvm->vcpus[next]->arch.apic; + if (apic && apic_enabled(apic)) + break; + apic = NULL; + } while (next != last); + kvm->arch.round_robin_prev_vcpu = next; + + if (!apic) + printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n"); + + return apic; +} + +struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector, + unsigned long bitmap) +{ + struct kvm_lapic *apic; + + apic = kvm_apic_round_robin(kvm, vector, bitmap); + if (apic) + return apic->vcpu; + return NULL; +} + +static void apic_set_eoi(struct kvm_lapic *apic) +{ + int vector = apic_find_highest_isr(apic); + + /* + * Not every write EOI will has corresponding ISR, + * one example is when Kernel check timer on setup_IO_APIC + */ + if (vector == -1) + return; + + apic_clear_vector(vector, apic->regs + APIC_ISR); + apic_update_ppr(apic); + + if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR)) + kvm_ioapic_update_eoi(apic->vcpu->kvm, vector); +} + +static void apic_send_ipi(struct kvm_lapic *apic) +{ + u32 icr_low = apic_get_reg(apic, APIC_ICR); + u32 icr_high = apic_get_reg(apic, APIC_ICR2); + + unsigned int dest = GET_APIC_DEST_FIELD(icr_high); + unsigned int short_hand = icr_low & APIC_SHORT_MASK; + unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG; + unsigned int level = icr_low & APIC_INT_ASSERT; + unsigned int dest_mode = icr_low & APIC_DEST_MASK; + unsigned int delivery_mode = icr_low & APIC_MODE_MASK; + unsigned int vector = icr_low & APIC_VECTOR_MASK; + + struct kvm_vcpu *target; + struct kvm_vcpu *vcpu; + unsigned long lpr_map = 0; + int i; + + apic_debug("icr_high 0x%x, icr_low 0x%x, " + "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " + "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n", + icr_high, icr_low, short_hand, dest, + trig_mode, level, dest_mode, delivery_mode, vector); + + for (i = 0; i < KVM_MAX_VCPUS; i++) { + vcpu = apic->vcpu->kvm->vcpus[i]; + if (!vcpu) + continue; + + if (vcpu->arch.apic && + apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) { + if (delivery_mode == APIC_DM_LOWEST) + set_bit(vcpu->vcpu_id, &lpr_map); + else + __apic_accept_irq(vcpu->arch.apic, delivery_mode, + vector, level, trig_mode); + } + } + + if (delivery_mode == APIC_DM_LOWEST) { + target = kvm_get_lowest_prio_vcpu(vcpu->kvm, vector, lpr_map); + if (target != NULL) + __apic_accept_irq(target->arch.apic, delivery_mode, + vector, level, trig_mode); + } +} + +static u32 apic_get_tmcct(struct kvm_lapic *apic) +{ + u64 counter_passed; + ktime_t passed, now; + u32 tmcct; + + ASSERT(apic != NULL); + + now = apic->timer.dev.base->get_time(); + tmcct = apic_get_reg(apic, APIC_TMICT); + + /* if initial count is 0, current count should also be 0 */ + if (tmcct == 0) + return 0; + + if (unlikely(ktime_to_ns(now) <= + ktime_to_ns(apic->timer.last_update))) { + /* Wrap around */ + passed = ktime_add(( { + (ktime_t) { + .tv64 = KTIME_MAX - + (apic->timer.last_update).tv64}; } + ), now); + apic_debug("time elapsed\n"); + } else + passed = ktime_sub(now, apic->timer.last_update); + + counter_passed = div64_64(ktime_to_ns(passed), + (APIC_BUS_CYCLE_NS * apic->timer.divide_count)); + + if (counter_passed > tmcct) { + if (unlikely(!apic_lvtt_period(apic))) { + /* one-shot timers stick at 0 until reset */ + tmcct = 0; + } else { + /* + * periodic timers reset to APIC_TMICT when they + * hit 0. The while loop simulates this happening N + * times. (counter_passed %= tmcct) would also work, + * but might be slower or not work on 32-bit?? + */ + while (counter_passed > tmcct) + counter_passed -= tmcct; + tmcct -= counter_passed; + } + } else { + tmcct -= counter_passed; + } + + return tmcct; +} + +static void __report_tpr_access(struct kvm_lapic *apic, bool write) +{ + struct kvm_vcpu *vcpu = apic->vcpu; + struct kvm_run *run = vcpu->run; + + set_bit(KVM_REQ_REPORT_TPR_ACCESS, &vcpu->requests); + kvm_x86_ops->cache_regs(vcpu); + run->tpr_access.rip = vcpu->arch.rip; + run->tpr_access.is_write = write; +} + +static inline void report_tpr_access(struct kvm_lapic *apic, bool write) +{ + if (apic->vcpu->arch.tpr_access_reporting) + __report_tpr_access(apic, write); +} + +static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset) +{ + u32 val = 0; + + if (offset >= LAPIC_MMIO_LENGTH) + return 0; + + switch (offset) { + case APIC_ARBPRI: + printk(KERN_WARNING "Access APIC ARBPRI register " + "which is for P6\n"); + break; + + case APIC_TMCCT: /* Timer CCR */ + val = apic_get_tmcct(apic); + break; + + case APIC_TASKPRI: + report_tpr_access(apic, false); + /* fall thru */ + default: + apic_update_ppr(apic); + val = apic_get_reg(apic, offset); + break; + } + + return val; +} + +static void apic_mmio_read(struct kvm_io_device *this, + gpa_t address, int len, void *data) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)this->private; + unsigned int offset = address - apic->base_address; + unsigned char alignment = offset & 0xf; + u32 result; + + if ((alignment + len) > 4) { + printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d", + (unsigned long)address, len); + return; + } + result = __apic_read(apic, offset & ~0xf); + + switch (len) { + case 1: + case 2: + case 4: + memcpy(data, (char *)&result + alignment, len); + break; + default: + printk(KERN_ERR "Local APIC read with len = %x, " + "should be 1,2, or 4 instead\n", len); + break; + } +} + +static void update_divide_count(struct kvm_lapic *apic) +{ + u32 tmp1, tmp2, tdcr; + + tdcr = apic_get_reg(apic, APIC_TDCR); + tmp1 = tdcr & 0xf; + tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; + apic->timer.divide_count = 0x1 << (tmp2 & 0x7); + + apic_debug("timer divide count is 0x%x\n", + apic->timer.divide_count); +} + +static void start_apic_timer(struct kvm_lapic *apic) +{ + ktime_t now = apic->timer.dev.base->get_time(); + + apic->timer.last_update = now; + + apic->timer.period = apic_get_reg(apic, APIC_TMICT) * + APIC_BUS_CYCLE_NS * apic->timer.divide_count; + atomic_set(&apic->timer.pending, 0); + + if (!apic->timer.period) + return; + + hrtimer_start(&apic->timer.dev, + ktime_add_ns(now, apic->timer.period), + HRTIMER_MODE_ABS); + + apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" + PRIx64 ", " + "timer initial count 0x%x, period %lldns, " + "expire @ 0x%016" PRIx64 ".\n", __FUNCTION__, + APIC_BUS_CYCLE_NS, ktime_to_ns(now), + apic_get_reg(apic, APIC_TMICT), + apic->timer.period, + ktime_to_ns(ktime_add_ns(now, + apic->timer.period))); +} + +static void apic_mmio_write(struct kvm_io_device *this, + gpa_t address, int len, const void *data) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)this->private; + unsigned int offset = address - apic->base_address; + unsigned char alignment = offset & 0xf; + u32 val; + + /* + * APIC register must be aligned on 128-bits boundary. + * 32/64/128 bits registers must be accessed thru 32 bits. + * Refer SDM 8.4.1 + */ + if (len != 4 || alignment) { + if (printk_ratelimit()) + printk(KERN_ERR "apic write: bad size=%d %lx\n", + len, (long)address); + return; + } + + val = *(u32 *) data; + + /* too common printing */ + if (offset != APIC_EOI) + apic_debug("%s: offset 0x%x with length 0x%x, and value is " + "0x%x\n", __FUNCTION__, offset, len, val); + + offset &= 0xff0; + + switch (offset) { + case APIC_ID: /* Local APIC ID */ + apic_set_reg(apic, APIC_ID, val); + break; + + case APIC_TASKPRI: + report_tpr_access(apic, true); + apic_set_tpr(apic, val & 0xff); + break; + + case APIC_EOI: + apic_set_eoi(apic); + break; + + case APIC_LDR: + apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK); + break; + + case APIC_DFR: + apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF); + break; + + case APIC_SPIV: + apic_set_reg(apic, APIC_SPIV, val & 0x3ff); + if (!(val & APIC_SPIV_APIC_ENABLED)) { + int i; + u32 lvt_val; + + for (i = 0; i < APIC_LVT_NUM; i++) { + lvt_val = apic_get_reg(apic, + APIC_LVTT + 0x10 * i); + apic_set_reg(apic, APIC_LVTT + 0x10 * i, + lvt_val | APIC_LVT_MASKED); + } + atomic_set(&apic->timer.pending, 0); + + } + break; + + case APIC_ICR: + /* No delay here, so we always clear the pending bit */ + apic_set_reg(apic, APIC_ICR, val & ~(1 << 12)); + apic_send_ipi(apic); + break; + + case APIC_ICR2: + apic_set_reg(apic, APIC_ICR2, val & 0xff000000); + break; + + case APIC_LVTT: + case APIC_LVTTHMR: + case APIC_LVTPC: + case APIC_LVT0: + case APIC_LVT1: + case APIC_LVTERR: + /* TODO: Check vector */ + if (!apic_sw_enabled(apic)) + val |= APIC_LVT_MASKED; + + val &= apic_lvt_mask[(offset - APIC_LVTT) >> 4]; + apic_set_reg(apic, offset, val); + + break; + + case APIC_TMICT: + hrtimer_cancel(&apic->timer.dev); + apic_set_reg(apic, APIC_TMICT, val); + start_apic_timer(apic); + return; + + case APIC_TDCR: + if (val & 4) + printk(KERN_ERR "KVM_WRITE:TDCR %x\n", val); + apic_set_reg(apic, APIC_TDCR, val); + update_divide_count(apic); + break; + + default: + apic_debug("Local APIC Write to read-only register %x\n", + offset); + break; + } + +} + +static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr) +{ + struct kvm_lapic *apic = (struct kvm_lapic *)this->private; + int ret = 0; + + + if (apic_hw_enabled(apic) && + (addr >= apic->base_address) && + (addr < (apic->base_address + LAPIC_MMIO_LENGTH))) + ret = 1; + + return ret; +} + +void kvm_free_lapic(struct kvm_vcpu *vcpu) +{ + if (!vcpu->arch.apic) + return; + + hrtimer_cancel(&vcpu->arch.apic->timer.dev); + + if (vcpu->arch.apic->regs_page) + __free_page(vcpu->arch.apic->regs_page); + + kfree(vcpu->arch.apic); +} + +/* + *---------------------------------------------------------------------- + * LAPIC interface + *---------------------------------------------------------------------- + */ + +void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + + if (!apic) + return; + apic_set_tpr(apic, ((cr8 & 0x0f) << 4) + | (apic_get_reg(apic, APIC_TASKPRI) & 4)); +} + +u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + u64 tpr; + + if (!apic) + return 0; + tpr = (u64) apic_get_reg(apic, APIC_TASKPRI); + + return (tpr & 0xf0) >> 4; +} +EXPORT_SYMBOL_GPL(kvm_lapic_get_cr8); + +void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + + if (!apic) { + value |= MSR_IA32_APICBASE_BSP; + vcpu->arch.apic_base = value; + return; + } + if (apic->vcpu->vcpu_id) + value &= ~MSR_IA32_APICBASE_BSP; + + vcpu->arch.apic_base = value; + apic->base_address = apic->vcpu->arch.apic_base & + MSR_IA32_APICBASE_BASE; + + /* with FSB delivery interrupt, we can restart APIC functionality */ + apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is " + "0x%lx.\n", apic->vcpu->arch.apic_base, apic->base_address); + +} + +u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.apic_base; +} +EXPORT_SYMBOL_GPL(kvm_lapic_get_base); + +void kvm_lapic_reset(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic; + int i; + + apic_debug("%s\n", __FUNCTION__); + + ASSERT(vcpu); + apic = vcpu->arch.apic; + ASSERT(apic != NULL); + + /* Stop the timer in case it's a reset to an active apic */ + hrtimer_cancel(&apic->timer.dev); + + apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24); + apic_set_reg(apic, APIC_LVR, APIC_VERSION); + + for (i = 0; i < APIC_LVT_NUM; i++) + apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); + apic_set_reg(apic, APIC_LVT0, + SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT)); + + apic_set_reg(apic, APIC_DFR, 0xffffffffU); + apic_set_reg(apic, APIC_SPIV, 0xff); + apic_set_reg(apic, APIC_TASKPRI, 0); + apic_set_reg(apic, APIC_LDR, 0); + apic_set_reg(apic, APIC_ESR, 0); + apic_set_reg(apic, APIC_ICR, 0); + apic_set_reg(apic, APIC_ICR2, 0); + apic_set_reg(apic, APIC_TDCR, 0); + apic_set_reg(apic, APIC_TMICT, 0); + for (i = 0; i < 8; i++) { + apic_set_reg(apic, APIC_IRR + 0x10 * i, 0); + apic_set_reg(apic, APIC_ISR + 0x10 * i, 0); + apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); + } + update_divide_count(apic); + atomic_set(&apic->timer.pending, 0); + if (vcpu->vcpu_id == 0) + vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP; + apic_update_ppr(apic); + + apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr=" + "0x%016" PRIx64 ", base_address=0x%0lx.\n", __FUNCTION__, + vcpu, kvm_apic_id(apic), + vcpu->arch.apic_base, apic->base_address); +} +EXPORT_SYMBOL_GPL(kvm_lapic_reset); + +int kvm_lapic_enabled(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + int ret = 0; + + if (!apic) + return 0; + ret = apic_enabled(apic); + + return ret; +} +EXPORT_SYMBOL_GPL(kvm_lapic_enabled); + +/* + *---------------------------------------------------------------------- + * timer interface + *---------------------------------------------------------------------- + */ + +/* TODO: make sure __apic_timer_fn runs in current pCPU */ +static int __apic_timer_fn(struct kvm_lapic *apic) +{ + int result = 0; + wait_queue_head_t *q = &apic->vcpu->wq; + + atomic_inc(&apic->timer.pending); + if (waitqueue_active(q)) { + apic->vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE; + wake_up_interruptible(q); + } + if (apic_lvtt_period(apic)) { + result = 1; + apic->timer.dev.expires = ktime_add_ns( + apic->timer.dev.expires, + apic->timer.period); + } + return result; +} + +static int __inject_apic_timer_irq(struct kvm_lapic *apic) +{ + int vector; + + vector = apic_lvt_vector(apic, APIC_LVTT); + return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0); +} + +static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) +{ + struct kvm_lapic *apic; + int restart_timer = 0; + + apic = container_of(data, struct kvm_lapic, timer.dev); + + restart_timer = __apic_timer_fn(apic); + + if (restart_timer) + return HRTIMER_RESTART; + else + return HRTIMER_NORESTART; +} + +int kvm_create_lapic(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic; + + ASSERT(vcpu != NULL); + apic_debug("apic_init %d\n", vcpu->vcpu_id); + + apic = kzalloc(sizeof(*apic), GFP_KERNEL); + if (!apic) + goto nomem; + + vcpu->arch.apic = apic; + + apic->regs_page = alloc_page(GFP_KERNEL); + if (apic->regs_page == NULL) { + printk(KERN_ERR "malloc apic regs error for vcpu %x\n", + vcpu->vcpu_id); + goto nomem_free_apic; + } + apic->regs = page_address(apic->regs_page); + memset(apic->regs, 0, PAGE_SIZE); + apic->vcpu = vcpu; + + hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + apic->timer.dev.function = apic_timer_fn; + apic->base_address = APIC_DEFAULT_PHYS_BASE; + vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE; + + kvm_lapic_reset(vcpu); + apic->dev.read = apic_mmio_read; + apic->dev.write = apic_mmio_write; + apic->dev.in_range = apic_mmio_range; + apic->dev.private = apic; + + return 0; +nomem_free_apic: + kfree(apic); +nomem: + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(kvm_create_lapic); + +int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + int highest_irr; + + if (!apic || !apic_enabled(apic)) + return -1; + + apic_update_ppr(apic); + highest_irr = apic_find_highest_irr(apic); + if ((highest_irr == -1) || + ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI))) + return -1; + return highest_irr; +} + +int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu) +{ + u32 lvt0 = apic_get_reg(vcpu->arch.apic, APIC_LVT0); + int r = 0; + + if (vcpu->vcpu_id == 0) { + if (!apic_hw_enabled(vcpu->arch.apic)) + r = 1; + if ((lvt0 & APIC_LVT_MASKED) == 0 && + GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT) + r = 1; + } + return r; +} + +void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + + if (apic && apic_lvt_enabled(apic, APIC_LVTT) && + atomic_read(&apic->timer.pending) > 0) { + if (__inject_apic_timer_irq(apic)) + atomic_dec(&apic->timer.pending); + } +} + +void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + + if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec) + apic->timer.last_update = ktime_add_ns( + apic->timer.last_update, + apic->timer.period); +} + +int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) +{ + int vector = kvm_apic_has_interrupt(vcpu); + struct kvm_lapic *apic = vcpu->arch.apic; + + if (vector == -1) + return -1; + + apic_set_vector(vector, apic->regs + APIC_ISR); + apic_update_ppr(apic); + apic_clear_irr(vector, apic); + return vector; +} + +void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + + apic->base_address = vcpu->arch.apic_base & + MSR_IA32_APICBASE_BASE; + apic_set_reg(apic, APIC_LVR, APIC_VERSION); + apic_update_ppr(apic); + hrtimer_cancel(&apic->timer.dev); + update_divide_count(apic); + start_apic_timer(apic); +} + +void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + struct hrtimer *timer; + + if (!apic) + return; + + timer = &apic->timer.dev; + if (hrtimer_cancel(timer)) + hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS); +} + +void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu) +{ + u32 data; + void *vapic; + + if (!irqchip_in_kernel(vcpu->kvm) || !vcpu->arch.apic->vapic_addr) + return; + + vapic = kmap_atomic(vcpu->arch.apic->vapic_page, KM_USER0); + data = *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)); + kunmap_atomic(vapic, KM_USER0); + + apic_set_tpr(vcpu->arch.apic, data & 0xff); +} + +void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu) +{ + u32 data, tpr; + int max_irr, max_isr; + struct kvm_lapic *apic; + void *vapic; + + if (!irqchip_in_kernel(vcpu->kvm) || !vcpu->arch.apic->vapic_addr) + return; + + apic = vcpu->arch.apic; + tpr = apic_get_reg(apic, APIC_TASKPRI) & 0xff; + max_irr = apic_find_highest_irr(apic); + if (max_irr < 0) + max_irr = 0; + max_isr = apic_find_highest_isr(apic); + if (max_isr < 0) + max_isr = 0; + data = (tpr & 0xff) | ((max_isr & 0xf0) << 8) | (max_irr << 24); + + vapic = kmap_atomic(vcpu->arch.apic->vapic_page, KM_USER0); + *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)) = data; + kunmap_atomic(vapic, KM_USER0); +} + +void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr) +{ + if (!irqchip_in_kernel(vcpu->kvm)) + return; + + vcpu->arch.apic->vapic_addr = vapic_addr; +} --- linux-2.6.24.orig/arch/x86/kvm/kvm_svm.h +++ linux-2.6.24/arch/x86/kvm/kvm_svm.h @@ -0,0 +1,47 @@ +#ifndef __KVM_SVM_H +#define __KVM_SVM_H + +#include +#include +#include +#include +#include + +#include "svm.h" + +static const u32 host_save_user_msrs[] = { +#ifdef CONFIG_X86_64 + MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE, + MSR_FS_BASE, +#endif + MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, +}; + +#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs) +#define NUM_DB_REGS 4 + +struct kvm_vcpu; + +struct vcpu_svm { + struct kvm_vcpu vcpu; + struct vmcb *vmcb; + unsigned long vmcb_pa; + struct svm_cpu_data *svm_data; + uint64_t asid_generation; + + unsigned long db_regs[NUM_DB_REGS]; + + u64 next_rip; + + u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS]; + u64 host_gs_base; + unsigned long host_cr2; + unsigned long host_db_regs[NUM_DB_REGS]; + unsigned long host_dr6; + unsigned long host_dr7; + + u32 *msrpm; +}; + +#endif + --- linux-2.6.24.orig/arch/x86/kvm/segment_descriptor.h +++ linux-2.6.24/arch/x86/kvm/segment_descriptor.h @@ -0,0 +1,29 @@ +#ifndef __SEGMENT_DESCRIPTOR_H +#define __SEGMENT_DESCRIPTOR_H + +struct segment_descriptor { + u16 limit_low; + u16 base_low; + u8 base_mid; + u8 type : 4; + u8 system : 1; + u8 dpl : 2; + u8 present : 1; + u8 limit_high : 4; + u8 avl : 1; + u8 long_mode : 1; + u8 default_op : 1; + u8 granularity : 1; + u8 base_high; +} __attribute__((packed)); + +#ifdef CONFIG_X86_64 +/* LDT or TSS descriptor in the GDT. 16 bytes. */ +struct segment_descriptor_64 { + struct segment_descriptor s; + u32 base_higher; + u32 pad_zero; +}; + +#endif +#endif --- linux-2.6.24.orig/arch/x86/kvm/lapic.h +++ linux-2.6.24/arch/x86/kvm/lapic.h @@ -0,0 +1,50 @@ +#ifndef __KVM_X86_LAPIC_H +#define __KVM_X86_LAPIC_H + +#include "iodev.h" + +#include + +struct kvm_lapic { + unsigned long base_address; + struct kvm_io_device dev; + struct { + atomic_t pending; + s64 period; /* unit: ns */ + u32 divide_count; + ktime_t last_update; + struct hrtimer dev; + } timer; + struct kvm_vcpu *vcpu; + struct page *regs_page; + void *regs; + gpa_t vapic_addr; + struct page *vapic_page; +}; +int kvm_create_lapic(struct kvm_vcpu *vcpu); +void kvm_free_lapic(struct kvm_vcpu *vcpu); + +int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu); +int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu); +int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu); +void kvm_lapic_reset(struct kvm_vcpu *vcpu); +u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu); +void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); +void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); + +int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); +int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); +int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig); + +u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); +void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); +void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); +int kvm_lapic_enabled(struct kvm_vcpu *vcpu); +int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); +void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec); + +void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr); +void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu); +void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu); + +#endif --- linux-2.6.24.orig/arch/x86/kvm/i8259.c +++ linux-2.6.24/arch/x86/kvm/i8259.c @@ -0,0 +1,450 @@ +/* + * 8259 interrupt controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * Authors: + * Yaozu (Eddie) Dong + * Port from Qemu. + */ +#include +#include "irq.h" + +#include + +/* + * set irq level. If an edge is detected, then the IRR is set to 1 + */ +static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level) +{ + int mask; + mask = 1 << irq; + if (s->elcr & mask) /* level triggered */ + if (level) { + s->irr |= mask; + s->last_irr |= mask; + } else { + s->irr &= ~mask; + s->last_irr &= ~mask; + } + else /* edge triggered */ + if (level) { + if ((s->last_irr & mask) == 0) + s->irr |= mask; + s->last_irr |= mask; + } else + s->last_irr &= ~mask; +} + +/* + * return the highest priority found in mask (highest = smallest + * number). Return 8 if no irq + */ +static inline int get_priority(struct kvm_kpic_state *s, int mask) +{ + int priority; + if (mask == 0) + return 8; + priority = 0; + while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) + priority++; + return priority; +} + +/* + * return the pic wanted interrupt. return -1 if none + */ +static int pic_get_irq(struct kvm_kpic_state *s) +{ + int mask, cur_priority, priority; + + mask = s->irr & ~s->imr; + priority = get_priority(s, mask); + if (priority == 8) + return -1; + /* + * compute current priority. If special fully nested mode on the + * master, the IRQ coming from the slave is not taken into account + * for the priority computation. + */ + mask = s->isr; + if (s->special_fully_nested_mode && s == &s->pics_state->pics[0]) + mask &= ~(1 << 2); + cur_priority = get_priority(s, mask); + if (priority < cur_priority) + /* + * higher priority found: an irq should be generated + */ + return (priority + s->priority_add) & 7; + else + return -1; +} + +/* + * raise irq to CPU if necessary. must be called every time the active + * irq may change + */ +static void pic_update_irq(struct kvm_pic *s) +{ + int irq2, irq; + + irq2 = pic_get_irq(&s->pics[1]); + if (irq2 >= 0) { + /* + * if irq request by slave pic, signal master PIC + */ + pic_set_irq1(&s->pics[0], 2, 1); + pic_set_irq1(&s->pics[0], 2, 0); + } + irq = pic_get_irq(&s->pics[0]); + if (irq >= 0) + s->irq_request(s->irq_request_opaque, 1); + else + s->irq_request(s->irq_request_opaque, 0); +} + +void kvm_pic_update_irq(struct kvm_pic *s) +{ + pic_update_irq(s); +} + +void kvm_pic_set_irq(void *opaque, int irq, int level) +{ + struct kvm_pic *s = opaque; + + pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); + pic_update_irq(s); +} + +/* + * acknowledge interrupt 'irq' + */ +static inline void pic_intack(struct kvm_kpic_state *s, int irq) +{ + if (s->auto_eoi) { + if (s->rotate_on_auto_eoi) + s->priority_add = (irq + 1) & 7; + } else + s->isr |= (1 << irq); + /* + * We don't clear a level sensitive interrupt here + */ + if (!(s->elcr & (1 << irq))) + s->irr &= ~(1 << irq); +} + +int kvm_pic_read_irq(struct kvm_pic *s) +{ + int irq, irq2, intno; + + irq = pic_get_irq(&s->pics[0]); + if (irq >= 0) { + pic_intack(&s->pics[0], irq); + if (irq == 2) { + irq2 = pic_get_irq(&s->pics[1]); + if (irq2 >= 0) + pic_intack(&s->pics[1], irq2); + else + /* + * spurious IRQ on slave controller + */ + irq2 = 7; + intno = s->pics[1].irq_base + irq2; + irq = irq2 + 8; + } else + intno = s->pics[0].irq_base + irq; + } else { + /* + * spurious IRQ on host controller + */ + irq = 7; + intno = s->pics[0].irq_base + irq; + } + pic_update_irq(s); + + return intno; +} + +void kvm_pic_reset(struct kvm_kpic_state *s) +{ + s->last_irr = 0; + s->irr = 0; + s->imr = 0; + s->isr = 0; + s->priority_add = 0; + s->irq_base = 0; + s->read_reg_select = 0; + s->poll = 0; + s->special_mask = 0; + s->init_state = 0; + s->auto_eoi = 0; + s->rotate_on_auto_eoi = 0; + s->special_fully_nested_mode = 0; + s->init4 = 0; +} + +static void pic_ioport_write(void *opaque, u32 addr, u32 val) +{ + struct kvm_kpic_state *s = opaque; + int priority, cmd, irq; + + addr &= 1; + if (addr == 0) { + if (val & 0x10) { + kvm_pic_reset(s); /* init */ + /* + * deassert a pending interrupt + */ + s->pics_state->irq_request(s->pics_state-> + irq_request_opaque, 0); + s->init_state = 1; + s->init4 = val & 1; + if (val & 0x02) + printk(KERN_ERR "single mode not supported"); + if (val & 0x08) + printk(KERN_ERR + "level sensitive irq not supported"); + } else if (val & 0x08) { + if (val & 0x04) + s->poll = 1; + if (val & 0x02) + s->read_reg_select = val & 1; + if (val & 0x40) + s->special_mask = (val >> 5) & 1; + } else { + cmd = val >> 5; + switch (cmd) { + case 0: + case 4: + s->rotate_on_auto_eoi = cmd >> 2; + break; + case 1: /* end of interrupt */ + case 5: + priority = get_priority(s, s->isr); + if (priority != 8) { + irq = (priority + s->priority_add) & 7; + s->isr &= ~(1 << irq); + if (cmd == 5) + s->priority_add = (irq + 1) & 7; + pic_update_irq(s->pics_state); + } + break; + case 3: + irq = val & 7; + s->isr &= ~(1 << irq); + pic_update_irq(s->pics_state); + break; + case 6: + s->priority_add = (val + 1) & 7; + pic_update_irq(s->pics_state); + break; + case 7: + irq = val & 7; + s->isr &= ~(1 << irq); + s->priority_add = (irq + 1) & 7; + pic_update_irq(s->pics_state); + break; + default: + break; /* no operation */ + } + } + } else + switch (s->init_state) { + case 0: /* normal mode */ + s->imr = val; + pic_update_irq(s->pics_state); + break; + case 1: + s->irq_base = val & 0xf8; + s->init_state = 2; + break; + case 2: + if (s->init4) + s->init_state = 3; + else + s->init_state = 0; + break; + case 3: + s->special_fully_nested_mode = (val >> 4) & 1; + s->auto_eoi = (val >> 1) & 1; + s->init_state = 0; + break; + } +} + +static u32 pic_poll_read(struct kvm_kpic_state *s, u32 addr1) +{ + int ret; + + ret = pic_get_irq(s); + if (ret >= 0) { + if (addr1 >> 7) { + s->pics_state->pics[0].isr &= ~(1 << 2); + s->pics_state->pics[0].irr &= ~(1 << 2); + } + s->irr &= ~(1 << ret); + s->isr &= ~(1 << ret); + if (addr1 >> 7 || ret != 2) + pic_update_irq(s->pics_state); + } else { + ret = 0x07; + pic_update_irq(s->pics_state); + } + + return ret; +} + +static u32 pic_ioport_read(void *opaque, u32 addr1) +{ + struct kvm_kpic_state *s = opaque; + unsigned int addr; + int ret; + + addr = addr1; + addr &= 1; + if (s->poll) { + ret = pic_poll_read(s, addr1); + s->poll = 0; + } else + if (addr == 0) + if (s->read_reg_select) + ret = s->isr; + else + ret = s->irr; + else + ret = s->imr; + return ret; +} + +static void elcr_ioport_write(void *opaque, u32 addr, u32 val) +{ + struct kvm_kpic_state *s = opaque; + s->elcr = val & s->elcr_mask; +} + +static u32 elcr_ioport_read(void *opaque, u32 addr1) +{ + struct kvm_kpic_state *s = opaque; + return s->elcr; +} + +static int picdev_in_range(struct kvm_io_device *this, gpa_t addr) +{ + switch (addr) { + case 0x20: + case 0x21: + case 0xa0: + case 0xa1: + case 0x4d0: + case 0x4d1: + return 1; + default: + return 0; + } +} + +static void picdev_write(struct kvm_io_device *this, + gpa_t addr, int len, const void *val) +{ + struct kvm_pic *s = this->private; + unsigned char data = *(unsigned char *)val; + + if (len != 1) { + if (printk_ratelimit()) + printk(KERN_ERR "PIC: non byte write\n"); + return; + } + switch (addr) { + case 0x20: + case 0x21: + case 0xa0: + case 0xa1: + pic_ioport_write(&s->pics[addr >> 7], addr, data); + break; + case 0x4d0: + case 0x4d1: + elcr_ioport_write(&s->pics[addr & 1], addr, data); + break; + } +} + +static void picdev_read(struct kvm_io_device *this, + gpa_t addr, int len, void *val) +{ + struct kvm_pic *s = this->private; + unsigned char data = 0; + + if (len != 1) { + if (printk_ratelimit()) + printk(KERN_ERR "PIC: non byte read\n"); + return; + } + switch (addr) { + case 0x20: + case 0x21: + case 0xa0: + case 0xa1: + data = pic_ioport_read(&s->pics[addr >> 7], addr); + break; + case 0x4d0: + case 0x4d1: + data = elcr_ioport_read(&s->pics[addr & 1], addr); + break; + } + *(unsigned char *)val = data; +} + +/* + * callback when PIC0 irq status changed + */ +static void pic_irq_request(void *opaque, int level) +{ + struct kvm *kvm = opaque; + struct kvm_vcpu *vcpu = kvm->vcpus[0]; + + pic_irqchip(kvm)->output = level; + if (vcpu) + kvm_vcpu_kick(vcpu); +} + +struct kvm_pic *kvm_create_pic(struct kvm *kvm) +{ + struct kvm_pic *s; + s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); + if (!s) + return NULL; + s->pics[0].elcr_mask = 0xf8; + s->pics[1].elcr_mask = 0xde; + s->irq_request = pic_irq_request; + s->irq_request_opaque = kvm; + s->pics[0].pics_state = s; + s->pics[1].pics_state = s; + + /* + * Initialize PIO device + */ + s->dev.read = picdev_read; + s->dev.write = picdev_write; + s->dev.in_range = picdev_in_range; + s->dev.private = s; + kvm_io_bus_register_dev(&kvm->pio_bus, &s->dev); + return s; +} --- linux-2.6.24.orig/arch/x86/kvm/paging_tmpl.h +++ linux-2.6.24/arch/x86/kvm/paging_tmpl.h @@ -0,0 +1,505 @@ +/* + * Kernel-based Virtual Machine driver for Linux + * + * This module enables machines with Intel VT-x extensions to run virtual + * machines without emulation or binary translation. + * + * MMU support + * + * Copyright (C) 2006 Qumranet, Inc. + * + * Authors: + * Yaniv Kamay + * Avi Kivity + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +/* + * We need the mmu code to access both 32-bit and 64-bit guest ptes, + * so the code in this file is compiled twice, once per pte size. + */ + +#if PTTYPE == 64 + #define pt_element_t u64 + #define guest_walker guest_walker64 + #define FNAME(name) paging##64_##name + #define PT_BASE_ADDR_MASK PT64_BASE_ADDR_MASK + #define PT_DIR_BASE_ADDR_MASK PT64_DIR_BASE_ADDR_MASK + #define PT_INDEX(addr, level) PT64_INDEX(addr, level) + #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) + #define PT_LEVEL_MASK(level) PT64_LEVEL_MASK(level) + #define PT_LEVEL_BITS PT64_LEVEL_BITS + #ifdef CONFIG_X86_64 + #define PT_MAX_FULL_LEVELS 4 + #define CMPXCHG cmpxchg + #else + #define CMPXCHG cmpxchg64 + #define PT_MAX_FULL_LEVELS 2 + #endif +#elif PTTYPE == 32 + #define pt_element_t u32 + #define guest_walker guest_walker32 + #define FNAME(name) paging##32_##name + #define PT_BASE_ADDR_MASK PT32_BASE_ADDR_MASK + #define PT_DIR_BASE_ADDR_MASK PT32_DIR_BASE_ADDR_MASK + #define PT_INDEX(addr, level) PT32_INDEX(addr, level) + #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) + #define PT_LEVEL_MASK(level) PT32_LEVEL_MASK(level) + #define PT_LEVEL_BITS PT32_LEVEL_BITS + #define PT_MAX_FULL_LEVELS 2 + #define CMPXCHG cmpxchg +#else + #error Invalid PTTYPE value +#endif + +#define gpte_to_gfn FNAME(gpte_to_gfn) +#define gpte_to_gfn_pde FNAME(gpte_to_gfn_pde) + +/* + * The guest_walker structure emulates the behavior of the hardware page + * table walker. + */ +struct guest_walker { + int level; + gfn_t table_gfn[PT_MAX_FULL_LEVELS]; + pt_element_t ptes[PT_MAX_FULL_LEVELS]; + gpa_t pte_gpa[PT_MAX_FULL_LEVELS]; + unsigned pt_access; + unsigned pte_access; + gfn_t gfn; + u32 error_code; +}; + +static gfn_t gpte_to_gfn(pt_element_t gpte) +{ + return (gpte & PT_BASE_ADDR_MASK) >> PAGE_SHIFT; +} + +static gfn_t gpte_to_gfn_pde(pt_element_t gpte) +{ + return (gpte & PT_DIR_BASE_ADDR_MASK) >> PAGE_SHIFT; +} + +static bool FNAME(cmpxchg_gpte)(struct kvm *kvm, + gfn_t table_gfn, unsigned index, + pt_element_t orig_pte, pt_element_t new_pte) +{ + pt_element_t ret; + pt_element_t *table; + struct page *page; + + down_read(¤t->mm->mmap_sem); + page = gfn_to_page(kvm, table_gfn); + up_read(¤t->mm->mmap_sem); + + table = kmap_atomic(page, KM_USER0); + + ret = CMPXCHG(&table[index], orig_pte, new_pte); + + kunmap_atomic(table, KM_USER0); + + kvm_release_page_dirty(page); + + return (ret != orig_pte); +} + +static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte) +{ + unsigned access; + + access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK; +#if PTTYPE == 64 + if (is_nx(vcpu)) + access &= ~(gpte >> PT64_NX_SHIFT); +#endif + return access; +} + +/* + * Fetch a guest pte for a guest virtual address + */ +static int FNAME(walk_addr)(struct guest_walker *walker, + struct kvm_vcpu *vcpu, gva_t addr, + int write_fault, int user_fault, int fetch_fault) +{ + pt_element_t pte; + gfn_t table_gfn; + unsigned index, pt_access, pte_access; + gpa_t pte_gpa; + + pgprintk("%s: addr %lx\n", __FUNCTION__, addr); +walk: + walker->level = vcpu->arch.mmu.root_level; + pte = vcpu->arch.cr3; +#if PTTYPE == 64 + if (!is_long_mode(vcpu)) { + pte = vcpu->arch.pdptrs[(addr >> 30) & 3]; + if (!is_present_pte(pte)) + goto not_present; + --walker->level; + } +#endif + ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || + (vcpu->arch.cr3 & CR3_NONPAE_RESERVED_BITS) == 0); + + pt_access = ACC_ALL; + + for (;;) { + index = PT_INDEX(addr, walker->level); + + table_gfn = gpte_to_gfn(pte); + pte_gpa = gfn_to_gpa(table_gfn); + pte_gpa += index * sizeof(pt_element_t); + walker->table_gfn[walker->level - 1] = table_gfn; + walker->pte_gpa[walker->level - 1] = pte_gpa; + pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__, + walker->level - 1, table_gfn); + + kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte)); + + if (!is_present_pte(pte)) + goto not_present; + + if (write_fault && !is_writeble_pte(pte)) + if (user_fault || is_write_protection(vcpu)) + goto access_error; + + if (user_fault && !(pte & PT_USER_MASK)) + goto access_error; + +#if PTTYPE == 64 + if (fetch_fault && is_nx(vcpu) && (pte & PT64_NX_MASK)) + goto access_error; +#endif + + if (!(pte & PT_ACCESSED_MASK)) { + mark_page_dirty(vcpu->kvm, table_gfn); + if (FNAME(cmpxchg_gpte)(vcpu->kvm, table_gfn, + index, pte, pte|PT_ACCESSED_MASK)) + goto walk; + pte |= PT_ACCESSED_MASK; + } + + pte_access = pt_access & FNAME(gpte_access)(vcpu, pte); + + walker->ptes[walker->level - 1] = pte; + + if (walker->level == PT_PAGE_TABLE_LEVEL) { + walker->gfn = gpte_to_gfn(pte); + break; + } + + if (walker->level == PT_DIRECTORY_LEVEL + && (pte & PT_PAGE_SIZE_MASK) + && (PTTYPE == 64 || is_pse(vcpu))) { + walker->gfn = gpte_to_gfn_pde(pte); + walker->gfn += PT_INDEX(addr, PT_PAGE_TABLE_LEVEL); + if (PTTYPE == 32 && is_cpuid_PSE36()) + walker->gfn += pse36_gfn_delta(pte); + break; + } + + pt_access = pte_access; + --walker->level; + } + + if (write_fault && !is_dirty_pte(pte)) { + bool ret; + + mark_page_dirty(vcpu->kvm, table_gfn); + ret = FNAME(cmpxchg_gpte)(vcpu->kvm, table_gfn, index, pte, + pte|PT_DIRTY_MASK); + if (ret) + goto walk; + pte |= PT_DIRTY_MASK; + kvm_mmu_pte_write(vcpu, pte_gpa, (u8 *)&pte, sizeof(pte)); + walker->ptes[walker->level - 1] = pte; + } + + walker->pt_access = pt_access; + walker->pte_access = pte_access; + pgprintk("%s: pte %llx pte_access %x pt_access %x\n", + __FUNCTION__, (u64)pte, pt_access, pte_access); + return 1; + +not_present: + walker->error_code = 0; + goto err; + +access_error: + walker->error_code = PFERR_PRESENT_MASK; + +err: + if (write_fault) + walker->error_code |= PFERR_WRITE_MASK; + if (user_fault) + walker->error_code |= PFERR_USER_MASK; + if (fetch_fault) + walker->error_code |= PFERR_FETCH_MASK; + return 0; +} + +static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page, + u64 *spte, const void *pte) +{ + pt_element_t gpte; + unsigned pte_access; + struct page *npage; + int largepage = vcpu->arch.update_pte.largepage; + + gpte = *(const pt_element_t *)pte; + if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) { + if (!is_present_pte(gpte)) + set_shadow_pte(spte, shadow_notrap_nonpresent_pte); + return; + } + pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte); + pte_access = page->role.access & FNAME(gpte_access)(vcpu, gpte); + if (gpte_to_gfn(gpte) != vcpu->arch.update_pte.gfn) + return; + npage = vcpu->arch.update_pte.page; + if (!npage) + return; + get_page(npage); + mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0, + gpte & PT_DIRTY_MASK, NULL, largepage, gpte_to_gfn(gpte), + npage); +} + +/* + * Fetch a shadow pte for a specific level in the paging hierarchy. + */ +static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, + struct guest_walker *walker, + int user_fault, int write_fault, int largepage, + int *ptwrite, struct page *page) +{ + hpa_t shadow_addr; + int level; + u64 *shadow_ent; + unsigned access = walker->pt_access; + + if (!is_present_pte(walker->ptes[walker->level - 1])) + return NULL; + + shadow_addr = vcpu->arch.mmu.root_hpa; + level = vcpu->arch.mmu.shadow_root_level; + if (level == PT32E_ROOT_LEVEL) { + shadow_addr = vcpu->arch.mmu.pae_root[(addr >> 30) & 3]; + shadow_addr &= PT64_BASE_ADDR_MASK; + --level; + } + + for (; ; level--) { + u32 index = SHADOW_PT_INDEX(addr, level); + struct kvm_mmu_page *shadow_page; + u64 shadow_pte; + int metaphysical; + gfn_t table_gfn; + bool new_page = 0; + + shadow_ent = ((u64 *)__va(shadow_addr)) + index; + if (level == PT_PAGE_TABLE_LEVEL) + break; + + if (largepage && level == PT_DIRECTORY_LEVEL) + break; + + if (is_shadow_present_pte(*shadow_ent) + && !is_large_pte(*shadow_ent)) { + shadow_addr = *shadow_ent & PT64_BASE_ADDR_MASK; + continue; + } + + if (is_large_pte(*shadow_ent)) + rmap_remove(vcpu->kvm, shadow_ent); + + if (level - 1 == PT_PAGE_TABLE_LEVEL + && walker->level == PT_DIRECTORY_LEVEL) { + metaphysical = 1; + if (!is_dirty_pte(walker->ptes[level - 1])) + access &= ~ACC_WRITE_MASK; + table_gfn = gpte_to_gfn(walker->ptes[level - 1]); + } else { + metaphysical = 0; + table_gfn = walker->table_gfn[level - 2]; + } + shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1, + metaphysical, access, + shadow_ent, &new_page); + if (new_page && !metaphysical) { + int r; + pt_element_t curr_pte; + r = kvm_read_guest_atomic(vcpu->kvm, + walker->pte_gpa[level - 2], + &curr_pte, sizeof(curr_pte)); + if (r || curr_pte != walker->ptes[level - 2]) { + kvm_release_page_clean(page); + return NULL; + } + } + shadow_addr = __pa(shadow_page->spt); + shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK + | PT_WRITABLE_MASK | PT_USER_MASK; + *shadow_ent = shadow_pte; + } + + mmu_set_spte(vcpu, shadow_ent, access, walker->pte_access & access, + user_fault, write_fault, + walker->ptes[walker->level-1] & PT_DIRTY_MASK, + ptwrite, largepage, walker->gfn, page); + + return shadow_ent; +} + +/* + * Page fault handler. There are several causes for a page fault: + * - there is no shadow pte for the guest pte + * - write access through a shadow pte marked read only so that we can set + * the dirty bit + * - write access to a shadow pte marked read only so we can update the page + * dirty bitmap, when userspace requests it + * - mmio access; in this case we will never install a present shadow pte + * - normal guest page fault due to the guest pte marked not present, not + * writable, or not executable + * + * Returns: 1 if we need to emulate the instruction, 0 otherwise, or + * a negative value on error. + */ +static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, + u32 error_code) +{ + int write_fault = error_code & PFERR_WRITE_MASK; + int user_fault = error_code & PFERR_USER_MASK; + int fetch_fault = error_code & PFERR_FETCH_MASK; + struct guest_walker walker; + u64 *shadow_pte; + int write_pt = 0; + int r; + struct page *page; + int largepage = 0; + + pgprintk("%s: addr %lx err %x\n", __FUNCTION__, addr, error_code); + kvm_mmu_audit(vcpu, "pre page fault"); + + r = mmu_topup_memory_caches(vcpu); + if (r) + return r; + + down_read(&vcpu->kvm->slots_lock); + /* + * Look up the shadow pte for the faulting address. + */ + r = FNAME(walk_addr)(&walker, vcpu, addr, write_fault, user_fault, + fetch_fault); + + /* + * The page is not mapped by the guest. Let the guest handle it. + */ + if (!r) { + pgprintk("%s: guest page fault\n", __FUNCTION__); + inject_page_fault(vcpu, addr, walker.error_code); + vcpu->arch.last_pt_write_count = 0; /* reset fork detector */ + up_read(&vcpu->kvm->slots_lock); + return 0; + } + + down_read(¤t->mm->mmap_sem); + if (walker.level == PT_DIRECTORY_LEVEL) { + gfn_t large_gfn; + large_gfn = walker.gfn & ~(KVM_PAGES_PER_HPAGE-1); + if (is_largepage_backed(vcpu, large_gfn)) { + walker.gfn = large_gfn; + largepage = 1; + } + } + page = gfn_to_page(vcpu->kvm, walker.gfn); + up_read(¤t->mm->mmap_sem); + + /* mmio */ + if (is_error_page(page)) { + pgprintk("gfn %x is mmio\n", walker.gfn); + kvm_release_page_clean(page); + up_read(&vcpu->kvm->slots_lock); + return 1; + } + + spin_lock(&vcpu->kvm->mmu_lock); + kvm_mmu_free_some_pages(vcpu); + shadow_pte = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault, + largepage, &write_pt, page); + + pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __FUNCTION__, + shadow_pte, *shadow_pte, write_pt); + + if (!write_pt) + vcpu->arch.last_pt_write_count = 0; /* reset fork detector */ + + ++vcpu->stat.pf_fixed; + kvm_mmu_audit(vcpu, "post page fault (fixed)"); + spin_unlock(&vcpu->kvm->mmu_lock); + up_read(&vcpu->kvm->slots_lock); + + return write_pt; +} + +static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) +{ + struct guest_walker walker; + gpa_t gpa = UNMAPPED_GVA; + int r; + + r = FNAME(walk_addr)(&walker, vcpu, vaddr, 0, 0, 0); + + if (r) { + gpa = gfn_to_gpa(walker.gfn); + gpa |= vaddr & ~PAGE_MASK; + } + + return gpa; +} + +static void FNAME(prefetch_page)(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *sp) +{ + int i, offset = 0, r = 0; + pt_element_t pt; + + if (sp->role.metaphysical + || (PTTYPE == 32 && sp->role.level > PT_PAGE_TABLE_LEVEL)) { + nonpaging_prefetch_page(vcpu, sp); + return; + } + + if (PTTYPE == 32) + offset = sp->role.quadrant << PT64_LEVEL_BITS; + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { + gpa_t pte_gpa = gfn_to_gpa(sp->gfn); + pte_gpa += (i+offset) * sizeof(pt_element_t); + + r = kvm_read_guest_atomic(vcpu->kvm, pte_gpa, &pt, + sizeof(pt_element_t)); + if (r || is_present_pte(pt)) + sp->spt[i] = shadow_trap_nonpresent_pte; + else + sp->spt[i] = shadow_notrap_nonpresent_pte; + } +} + +#undef pt_element_t +#undef guest_walker +#undef FNAME +#undef PT_BASE_ADDR_MASK +#undef PT_INDEX +#undef SHADOW_PT_INDEX +#undef PT_LEVEL_MASK +#undef PT_DIR_BASE_ADDR_MASK +#undef PT_LEVEL_BITS +#undef PT_MAX_FULL_LEVELS +#undef gpte_to_gfn +#undef gpte_to_gfn_pde +#undef CMPXCHG --- linux-2.6.24.orig/arch/x86/kvm/svm.c +++ linux-2.6.24/arch/x86/kvm/svm.c @@ -0,0 +1,1874 @@ +/* + * Kernel-based Virtual Machine driver for Linux + * + * AMD SVM support + * + * Copyright (C) 2006 Qumranet, Inc. + * + * Authors: + * Yaniv Kamay + * Avi Kivity + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ +#include + +#include "kvm_svm.h" +#include "irq.h" +#include "mmu.h" + +#include +#include +#include +#include +#include + +#include + +MODULE_AUTHOR("Qumranet"); +MODULE_LICENSE("GPL"); + +#define IOPM_ALLOC_ORDER 2 +#define MSRPM_ALLOC_ORDER 1 + +#define DB_VECTOR 1 +#define UD_VECTOR 6 +#define GP_VECTOR 13 + +#define DR7_GD_MASK (1 << 13) +#define DR6_BD_MASK (1 << 13) + +#define SEG_TYPE_LDT 2 +#define SEG_TYPE_BUSY_TSS16 3 + +#define SVM_FEATURE_NPT (1 << 0) +#define SVM_FEATURE_LBRV (1 << 1) +#define SVM_DEATURE_SVML (1 << 2) + +#define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) + +/* enable NPT for AMD64 and X86 with PAE */ +#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) +static bool npt_enabled = true; +#else +static bool npt_enabled = false; +#endif +static int npt = 1; + +module_param(npt, int, S_IRUGO); + +static void kvm_reput_irq(struct vcpu_svm *svm); + +static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu) +{ + return container_of(vcpu, struct vcpu_svm, vcpu); +} + +static unsigned long iopm_base; + +struct kvm_ldttss_desc { + u16 limit0; + u16 base0; + unsigned base1 : 8, type : 5, dpl : 2, p : 1; + unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8; + u32 base3; + u32 zero1; +} __attribute__((packed)); + +struct svm_cpu_data { + int cpu; + + u64 asid_generation; + u32 max_asid; + u32 next_asid; + struct kvm_ldttss_desc *tss_desc; + + struct page *save_area; +}; + +static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data); +static uint32_t svm_features; + +struct svm_init_data { + int cpu; + int r; +}; + +static u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000}; + +#define NUM_MSR_MAPS ARRAY_SIZE(msrpm_ranges) +#define MSRS_RANGE_SIZE 2048 +#define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2) + +#define MAX_INST_SIZE 15 + +static inline u32 svm_has(u32 feat) +{ + return svm_features & feat; +} + +static inline u8 pop_irq(struct kvm_vcpu *vcpu) +{ + int word_index = __ffs(vcpu->arch.irq_summary); + int bit_index = __ffs(vcpu->arch.irq_pending[word_index]); + int irq = word_index * BITS_PER_LONG + bit_index; + + clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]); + if (!vcpu->arch.irq_pending[word_index]) + clear_bit(word_index, &vcpu->arch.irq_summary); + return irq; +} + +static inline void push_irq(struct kvm_vcpu *vcpu, u8 irq) +{ + set_bit(irq, vcpu->arch.irq_pending); + set_bit(irq / BITS_PER_LONG, &vcpu->arch.irq_summary); +} + +static inline void clgi(void) +{ + asm volatile (SVM_CLGI); +} + +static inline void stgi(void) +{ + asm volatile (SVM_STGI); +} + +static inline void invlpga(unsigned long addr, u32 asid) +{ + asm volatile (SVM_INVLPGA :: "a"(addr), "c"(asid)); +} + +static inline unsigned long kvm_read_cr2(void) +{ + unsigned long cr2; + + asm volatile ("mov %%cr2, %0" : "=r" (cr2)); + return cr2; +} + +static inline void kvm_write_cr2(unsigned long val) +{ + asm volatile ("mov %0, %%cr2" :: "r" (val)); +} + +static inline unsigned long read_dr6(void) +{ + unsigned long dr6; + + asm volatile ("mov %%dr6, %0" : "=r" (dr6)); + return dr6; +} + +static inline void write_dr6(unsigned long val) +{ + asm volatile ("mov %0, %%dr6" :: "r" (val)); +} + +static inline unsigned long read_dr7(void) +{ + unsigned long dr7; + + asm volatile ("mov %%dr7, %0" : "=r" (dr7)); + return dr7; +} + +static inline void write_dr7(unsigned long val) +{ + asm volatile ("mov %0, %%dr7" :: "r" (val)); +} + +static inline void force_new_asid(struct kvm_vcpu *vcpu) +{ + to_svm(vcpu)->asid_generation--; +} + +static inline void flush_guest_tlb(struct kvm_vcpu *vcpu) +{ + force_new_asid(vcpu); +} + +static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) +{ + if (!npt_enabled && !(efer & EFER_LMA)) + efer &= ~EFER_LME; + + to_svm(vcpu)->vmcb->save.efer = efer | MSR_EFER_SVME_MASK; + vcpu->arch.shadow_efer = efer; +} + +static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, + bool has_error_code, u32 error_code) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->control.event_inj = nr + | SVM_EVTINJ_VALID + | (has_error_code ? SVM_EVTINJ_VALID_ERR : 0) + | SVM_EVTINJ_TYPE_EXEPT; + svm->vmcb->control.event_inj_err = error_code; +} + +static bool svm_exception_injected(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + return !(svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID); +} + +static int is_external_interrupt(u32 info) +{ + info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID; + return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR); +} + +static void skip_emulated_instruction(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + if (!svm->next_rip) { + printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__); + return; + } + if (svm->next_rip - svm->vmcb->save.rip > MAX_INST_SIZE) + printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n", + __FUNCTION__, + svm->vmcb->save.rip, + svm->next_rip); + + vcpu->arch.rip = svm->vmcb->save.rip = svm->next_rip; + svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; + + vcpu->arch.interrupt_window_open = 1; +} + +static int has_svm(void) +{ + uint32_t eax, ebx, ecx, edx; + + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { + printk(KERN_INFO "has_svm: not amd\n"); + return 0; + } + + cpuid(0x80000000, &eax, &ebx, &ecx, &edx); + if (eax < SVM_CPUID_FUNC) { + printk(KERN_INFO "has_svm: can't execute cpuid_8000000a\n"); + return 0; + } + + cpuid(0x80000001, &eax, &ebx, &ecx, &edx); + if (!(ecx & (1 << SVM_CPUID_FEATURE_SHIFT))) { + printk(KERN_DEBUG "has_svm: svm not available\n"); + return 0; + } + return 1; +} + +static void svm_hardware_disable(void *garbage) +{ + struct svm_cpu_data *svm_data + = per_cpu(svm_data, raw_smp_processor_id()); + + if (svm_data) { + uint64_t efer; + + wrmsrl(MSR_VM_HSAVE_PA, 0); + rdmsrl(MSR_EFER, efer); + wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK); + per_cpu(svm_data, raw_smp_processor_id()) = NULL; + __free_page(svm_data->save_area); + kfree(svm_data); + } +} + +static void svm_hardware_enable(void *garbage) +{ + + struct svm_cpu_data *svm_data; + uint64_t efer; +#ifdef CONFIG_X86_64 + struct desc_ptr gdt_descr; +#else + struct Xgt_desc_struct gdt_descr; +#endif + struct desc_struct *gdt; + int me = raw_smp_processor_id(); + + if (!has_svm()) { + printk(KERN_ERR "svm_cpu_init: err EOPNOTSUPP on %d\n", me); + return; + } + svm_data = per_cpu(svm_data, me); + + if (!svm_data) { + printk(KERN_ERR "svm_cpu_init: svm_data is NULL on %d\n", + me); + return; + } + + svm_data->asid_generation = 1; + svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1; + svm_data->next_asid = svm_data->max_asid + 1; + + asm volatile ("sgdt %0" : "=m"(gdt_descr)); + gdt = (struct desc_struct *)gdt_descr.address; + svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS); + + rdmsrl(MSR_EFER, efer); + wrmsrl(MSR_EFER, efer | MSR_EFER_SVME_MASK); + + wrmsrl(MSR_VM_HSAVE_PA, + page_to_pfn(svm_data->save_area) << PAGE_SHIFT); +} + +static int svm_cpu_init(int cpu) +{ + struct svm_cpu_data *svm_data; + int r; + + svm_data = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL); + if (!svm_data) + return -ENOMEM; + svm_data->cpu = cpu; + svm_data->save_area = alloc_page(GFP_KERNEL); + r = -ENOMEM; + if (!svm_data->save_area) + goto err_1; + + per_cpu(svm_data, cpu) = svm_data; + + return 0; + +err_1: + kfree(svm_data); + return r; + +} + +static void set_msr_interception(u32 *msrpm, unsigned msr, + int read, int write) +{ + int i; + + for (i = 0; i < NUM_MSR_MAPS; i++) { + if (msr >= msrpm_ranges[i] && + msr < msrpm_ranges[i] + MSRS_IN_RANGE) { + u32 msr_offset = (i * MSRS_IN_RANGE + msr - + msrpm_ranges[i]) * 2; + + u32 *base = msrpm + (msr_offset / 32); + u32 msr_shift = msr_offset % 32; + u32 mask = ((write) ? 0 : 2) | ((read) ? 0 : 1); + *base = (*base & ~(0x3 << msr_shift)) | + (mask << msr_shift); + return; + } + } + BUG(); +} + +static void svm_vcpu_init_msrpm(u32 *msrpm) +{ + memset(msrpm, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER)); + +#ifdef CONFIG_X86_64 + set_msr_interception(msrpm, MSR_GS_BASE, 1, 1); + set_msr_interception(msrpm, MSR_FS_BASE, 1, 1); + set_msr_interception(msrpm, MSR_KERNEL_GS_BASE, 1, 1); + set_msr_interception(msrpm, MSR_LSTAR, 1, 1); + set_msr_interception(msrpm, MSR_CSTAR, 1, 1); + set_msr_interception(msrpm, MSR_SYSCALL_MASK, 1, 1); +#endif + set_msr_interception(msrpm, MSR_K6_STAR, 1, 1); + set_msr_interception(msrpm, MSR_IA32_SYSENTER_CS, 1, 1); + set_msr_interception(msrpm, MSR_IA32_SYSENTER_ESP, 1, 1); + set_msr_interception(msrpm, MSR_IA32_SYSENTER_EIP, 1, 1); +} + +static void svm_enable_lbrv(struct vcpu_svm *svm) +{ + u32 *msrpm = svm->msrpm; + + svm->vmcb->control.lbr_ctl = 1; + set_msr_interception(msrpm, MSR_IA32_LASTBRANCHFROMIP, 1, 1); + set_msr_interception(msrpm, MSR_IA32_LASTBRANCHTOIP, 1, 1); + set_msr_interception(msrpm, MSR_IA32_LASTINTFROMIP, 1, 1); + set_msr_interception(msrpm, MSR_IA32_LASTINTTOIP, 1, 1); +} + +static void svm_disable_lbrv(struct vcpu_svm *svm) +{ + u32 *msrpm = svm->msrpm; + + svm->vmcb->control.lbr_ctl = 0; + set_msr_interception(msrpm, MSR_IA32_LASTBRANCHFROMIP, 0, 0); + set_msr_interception(msrpm, MSR_IA32_LASTBRANCHTOIP, 0, 0); + set_msr_interception(msrpm, MSR_IA32_LASTINTFROMIP, 0, 0); + set_msr_interception(msrpm, MSR_IA32_LASTINTTOIP, 0, 0); +} + +static __init int svm_hardware_setup(void) +{ + int cpu; + struct page *iopm_pages; + void *iopm_va; + int r; + + iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER); + + if (!iopm_pages) + return -ENOMEM; + + iopm_va = page_address(iopm_pages); + memset(iopm_va, 0xff, PAGE_SIZE * (1 << IOPM_ALLOC_ORDER)); + clear_bit(0x80, iopm_va); /* allow direct access to PC debug port */ + iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT; + + if (boot_cpu_has(X86_FEATURE_NX)) + kvm_enable_efer_bits(EFER_NX); + + for_each_online_cpu(cpu) { + r = svm_cpu_init(cpu); + if (r) + goto err; + } + + svm_features = cpuid_edx(SVM_CPUID_FUNC); + + if (!svm_has(SVM_FEATURE_NPT)) + npt_enabled = false; + + if (npt_enabled && !npt) { + printk(KERN_INFO "kvm: Nested Paging disabled\n"); + npt_enabled = false; + } + + if (npt_enabled) { + printk(KERN_INFO "kvm: Nested Paging enabled\n"); + kvm_enable_tdp(); + } + + return 0; + +err: + __free_pages(iopm_pages, IOPM_ALLOC_ORDER); + iopm_base = 0; + return r; +} + +static __exit void svm_hardware_unsetup(void) +{ + __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER); + iopm_base = 0; +} + +static void init_seg(struct vmcb_seg *seg) +{ + seg->selector = 0; + seg->attrib = SVM_SELECTOR_P_MASK | SVM_SELECTOR_S_MASK | + SVM_SELECTOR_WRITE_MASK; /* Read/Write Data Segment */ + seg->limit = 0xffff; + seg->base = 0; +} + +static void init_sys_seg(struct vmcb_seg *seg, uint32_t type) +{ + seg->selector = 0; + seg->attrib = SVM_SELECTOR_P_MASK | type; + seg->limit = 0xffff; + seg->base = 0; +} + +static void init_vmcb(struct vcpu_svm *svm) +{ + struct vmcb_control_area *control = &svm->vmcb->control; + struct vmcb_save_area *save = &svm->vmcb->save; + + control->intercept_cr_read = INTERCEPT_CR0_MASK | + INTERCEPT_CR3_MASK | + INTERCEPT_CR4_MASK | + INTERCEPT_CR8_MASK; + + control->intercept_cr_write = INTERCEPT_CR0_MASK | + INTERCEPT_CR3_MASK | + INTERCEPT_CR4_MASK | + INTERCEPT_CR8_MASK; + + control->intercept_dr_read = INTERCEPT_DR0_MASK | + INTERCEPT_DR1_MASK | + INTERCEPT_DR2_MASK | + INTERCEPT_DR3_MASK; + + control->intercept_dr_write = INTERCEPT_DR0_MASK | + INTERCEPT_DR1_MASK | + INTERCEPT_DR2_MASK | + INTERCEPT_DR3_MASK | + INTERCEPT_DR5_MASK | + INTERCEPT_DR7_MASK; + + control->intercept_exceptions = (1 << PF_VECTOR) | + (1 << UD_VECTOR); + + + control->intercept = (1ULL << INTERCEPT_INTR) | + (1ULL << INTERCEPT_NMI) | + (1ULL << INTERCEPT_SMI) | + /* + * selective cr0 intercept bug? + * 0: 0f 22 d8 mov %eax,%cr3 + * 3: 0f 20 c0 mov %cr0,%eax + * 6: 0d 00 00 00 80 or $0x80000000,%eax + * b: 0f 22 c0 mov %eax,%cr0 + * set cr3 ->interception + * get cr0 ->interception + * set cr0 -> no interception + */ + /* (1ULL << INTERCEPT_SELECTIVE_CR0) | */ + (1ULL << INTERCEPT_CPUID) | + (1ULL << INTERCEPT_INVD) | + (1ULL << INTERCEPT_HLT) | + (1ULL << INTERCEPT_INVLPGA) | + (1ULL << INTERCEPT_IOIO_PROT) | + (1ULL << INTERCEPT_MSR_PROT) | + (1ULL << INTERCEPT_TASK_SWITCH) | + (1ULL << INTERCEPT_SHUTDOWN) | + (1ULL << INTERCEPT_VMRUN) | + (1ULL << INTERCEPT_VMMCALL) | + (1ULL << INTERCEPT_VMLOAD) | + (1ULL << INTERCEPT_VMSAVE) | + (1ULL << INTERCEPT_STGI) | + (1ULL << INTERCEPT_CLGI) | + (1ULL << INTERCEPT_SKINIT) | + (1ULL << INTERCEPT_WBINVD) | + (1ULL << INTERCEPT_MONITOR) | + (1ULL << INTERCEPT_MWAIT); + + control->iopm_base_pa = iopm_base; + control->msrpm_base_pa = __pa(svm->msrpm); + control->tsc_offset = 0; + control->int_ctl = V_INTR_MASKING_MASK; + + init_seg(&save->es); + init_seg(&save->ss); + init_seg(&save->ds); + init_seg(&save->fs); + init_seg(&save->gs); + + save->cs.selector = 0xf000; + /* Executable/Readable Code Segment */ + save->cs.attrib = SVM_SELECTOR_READ_MASK | SVM_SELECTOR_P_MASK | + SVM_SELECTOR_S_MASK | SVM_SELECTOR_CODE_MASK; + save->cs.limit = 0xffff; + /* + * cs.base should really be 0xffff0000, but vmx can't handle that, so + * be consistent with it. + * + * Replace when we have real mode working for vmx. + */ + save->cs.base = 0xf0000; + + save->gdtr.limit = 0xffff; + save->idtr.limit = 0xffff; + + init_sys_seg(&save->ldtr, SEG_TYPE_LDT); + init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16); + + save->efer = MSR_EFER_SVME_MASK; + save->dr6 = 0xffff0ff0; + save->dr7 = 0x400; + save->rflags = 2; + save->rip = 0x0000fff0; + + /* + * cr0 val on cpu init should be 0x60000010, we enable cpu + * cache by default. the orderly way is to enable cache in bios. + */ + save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP; + save->cr4 = X86_CR4_PAE; + /* rdx = ?? */ + + if (npt_enabled) { + /* Setup VMCB for Nested Paging */ + control->nested_ctl = 1; + control->intercept_exceptions &= ~(1 << PF_VECTOR); + control->intercept_cr_read &= ~(INTERCEPT_CR0_MASK| + INTERCEPT_CR3_MASK); + control->intercept_cr_write &= ~(INTERCEPT_CR0_MASK| + INTERCEPT_CR3_MASK); + save->g_pat = 0x0007040600070406ULL; + /* enable caching because the QEMU Bios doesn't enable it */ + save->cr0 = X86_CR0_ET; + save->cr3 = 0; + save->cr4 = 0; + } + +} + +static int svm_vcpu_reset(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + init_vmcb(svm); + + if (vcpu->vcpu_id != 0) { + svm->vmcb->save.rip = 0; + svm->vmcb->save.cs.base = svm->vcpu.arch.sipi_vector << 12; + svm->vmcb->save.cs.selector = svm->vcpu.arch.sipi_vector << 8; + } + + return 0; +} + +static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) +{ + struct vcpu_svm *svm; + struct page *page; + struct page *msrpm_pages; + int err; + + svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); + if (!svm) { + err = -ENOMEM; + goto out; + } + + err = kvm_vcpu_init(&svm->vcpu, kvm, id); + if (err) + goto free_svm; + + page = alloc_page(GFP_KERNEL); + if (!page) { + err = -ENOMEM; + goto uninit; + } + + err = -ENOMEM; + msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER); + if (!msrpm_pages) + goto uninit; + svm->msrpm = page_address(msrpm_pages); + svm_vcpu_init_msrpm(svm->msrpm); + + svm->vmcb = page_address(page); + clear_page(svm->vmcb); + svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; + svm->asid_generation = 0; + memset(svm->db_regs, 0, sizeof(svm->db_regs)); + init_vmcb(svm); + + fx_init(&svm->vcpu); + svm->vcpu.fpu_active = 1; + svm->vcpu.arch.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; + if (svm->vcpu.vcpu_id == 0) + svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP; + + return &svm->vcpu; + +uninit: + kvm_vcpu_uninit(&svm->vcpu); +free_svm: + kmem_cache_free(kvm_vcpu_cache, svm); +out: + return ERR_PTR(err); +} + +static void svm_free_vcpu(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + __free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT)); + __free_pages(virt_to_page(svm->msrpm), MSRPM_ALLOC_ORDER); + kvm_vcpu_uninit(vcpu); + kmem_cache_free(kvm_vcpu_cache, svm); +} + +static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + int i; + + if (unlikely(cpu != vcpu->cpu)) { + u64 tsc_this, delta; + + /* + * Make sure that the guest sees a monotonically + * increasing TSC. + */ + rdtscll(tsc_this); + delta = vcpu->arch.host_tsc - tsc_this; + svm->vmcb->control.tsc_offset += delta; + vcpu->cpu = cpu; + kvm_migrate_apic_timer(vcpu); + } + + for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) + rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); +} + +static void svm_vcpu_put(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + int i; + + ++vcpu->stat.host_state_reload; + for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) + wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); + + rdtscll(vcpu->arch.host_tsc); +} + +static void svm_vcpu_decache(struct kvm_vcpu *vcpu) +{ +} + +static void svm_cache_regs(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + vcpu->arch.regs[VCPU_REGS_RAX] = svm->vmcb->save.rax; + vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp; + vcpu->arch.rip = svm->vmcb->save.rip; +} + +static void svm_decache_regs(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX]; + svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP]; + svm->vmcb->save.rip = vcpu->arch.rip; +} + +static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu) +{ + return to_svm(vcpu)->vmcb->save.rflags; +} + +static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) +{ + to_svm(vcpu)->vmcb->save.rflags = rflags; +} + +static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg) +{ + struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save; + + switch (seg) { + case VCPU_SREG_CS: return &save->cs; + case VCPU_SREG_DS: return &save->ds; + case VCPU_SREG_ES: return &save->es; + case VCPU_SREG_FS: return &save->fs; + case VCPU_SREG_GS: return &save->gs; + case VCPU_SREG_SS: return &save->ss; + case VCPU_SREG_TR: return &save->tr; + case VCPU_SREG_LDTR: return &save->ldtr; + } + BUG(); + return NULL; +} + +static u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg) +{ + struct vmcb_seg *s = svm_seg(vcpu, seg); + + return s->base; +} + +static void svm_get_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) +{ + struct vmcb_seg *s = svm_seg(vcpu, seg); + + var->base = s->base; + var->limit = s->limit; + var->selector = s->selector; + var->type = s->attrib & SVM_SELECTOR_TYPE_MASK; + var->s = (s->attrib >> SVM_SELECTOR_S_SHIFT) & 1; + var->dpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3; + var->present = (s->attrib >> SVM_SELECTOR_P_SHIFT) & 1; + var->avl = (s->attrib >> SVM_SELECTOR_AVL_SHIFT) & 1; + var->l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1; + var->db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1; + var->g = (s->attrib >> SVM_SELECTOR_G_SHIFT) & 1; + var->unusable = !var->present; +} + +static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + dt->limit = svm->vmcb->save.idtr.limit; + dt->base = svm->vmcb->save.idtr.base; +} + +static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->save.idtr.limit = dt->limit; + svm->vmcb->save.idtr.base = dt->base ; +} + +static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + dt->limit = svm->vmcb->save.gdtr.limit; + dt->base = svm->vmcb->save.gdtr.base; +} + +static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->save.gdtr.limit = dt->limit; + svm->vmcb->save.gdtr.base = dt->base ; +} + +static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) +{ +} + +static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) +{ + struct vcpu_svm *svm = to_svm(vcpu); + +#ifdef CONFIG_X86_64 + if (vcpu->arch.shadow_efer & EFER_LME) { + if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) { + vcpu->arch.shadow_efer |= EFER_LMA; + svm->vmcb->save.efer |= EFER_LMA | EFER_LME; + } + + if (is_paging(vcpu) && !(cr0 & X86_CR0_PG)) { + vcpu->arch.shadow_efer &= ~EFER_LMA; + svm->vmcb->save.efer &= ~(EFER_LMA | EFER_LME); + } + } +#endif + if (npt_enabled) + goto set; + + if ((vcpu->arch.cr0 & X86_CR0_TS) && !(cr0 & X86_CR0_TS)) { + svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); + vcpu->fpu_active = 1; + } + + vcpu->arch.cr0 = cr0; + cr0 |= X86_CR0_PG | X86_CR0_WP; + if (!vcpu->fpu_active) { + svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR); + cr0 |= X86_CR0_TS; + } +set: + /* + * re-enable caching here because the QEMU bios + * does not do it - this results in some delay at + * reboot + */ + cr0 &= ~(X86_CR0_CD | X86_CR0_NW); + svm->vmcb->save.cr0 = cr0; +} + +static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) +{ + vcpu->arch.cr4 = cr4; + if (!npt_enabled) + cr4 |= X86_CR4_PAE; + to_svm(vcpu)->vmcb->save.cr4 = cr4; +} + +static void svm_set_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) +{ + struct vcpu_svm *svm = to_svm(vcpu); + struct vmcb_seg *s = svm_seg(vcpu, seg); + + s->base = var->base; + s->limit = var->limit; + s->selector = var->selector; + if (var->unusable) + s->attrib = 0; + else { + s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK); + s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT; + s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT; + s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT; + s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT; + s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT; + s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT; + s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; + } + if (seg == VCPU_SREG_CS) + svm->vmcb->save.cpl + = (svm->vmcb->save.cs.attrib + >> SVM_SELECTOR_DPL_SHIFT) & 3; + +} + +/* FIXME: + + svm(vcpu)->vmcb->control.int_ctl &= ~V_TPR_MASK; + svm(vcpu)->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK); + +*/ + +static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) +{ + return -EOPNOTSUPP; +} + +static int svm_get_irq(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + u32 exit_int_info = svm->vmcb->control.exit_int_info; + + if (is_external_interrupt(exit_int_info)) + return exit_int_info & SVM_EVTINJ_VEC_MASK; + return -1; +} + +static void load_host_msrs(struct kvm_vcpu *vcpu) +{ +#ifdef CONFIG_X86_64 + wrmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base); +#endif +} + +static void save_host_msrs(struct kvm_vcpu *vcpu) +{ +#ifdef CONFIG_X86_64 + rdmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base); +#endif +} + +static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data) +{ + if (svm_data->next_asid > svm_data->max_asid) { + ++svm_data->asid_generation; + svm_data->next_asid = 1; + svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID; + } + + svm->vcpu.cpu = svm_data->cpu; + svm->asid_generation = svm_data->asid_generation; + svm->vmcb->control.asid = svm_data->next_asid++; +} + +static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr) +{ + return to_svm(vcpu)->db_regs[dr]; +} + +static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, + int *exception) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + *exception = 0; + + if (svm->vmcb->save.dr7 & DR7_GD_MASK) { + svm->vmcb->save.dr7 &= ~DR7_GD_MASK; + svm->vmcb->save.dr6 |= DR6_BD_MASK; + *exception = DB_VECTOR; + return; + } + + switch (dr) { + case 0 ... 3: + svm->db_regs[dr] = value; + return; + case 4 ... 5: + if (vcpu->arch.cr4 & X86_CR4_DE) { + *exception = UD_VECTOR; + return; + } + case 7: { + if (value & ~((1ULL << 32) - 1)) { + *exception = GP_VECTOR; + return; + } + svm->vmcb->save.dr7 = value; + return; + } + default: + printk(KERN_DEBUG "%s: unexpected dr %u\n", + __FUNCTION__, dr); + *exception = UD_VECTOR; + return; + } +} + +static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + u32 exit_int_info = svm->vmcb->control.exit_int_info; + struct kvm *kvm = svm->vcpu.kvm; + u64 fault_address; + u32 error_code; + + if (!irqchip_in_kernel(kvm) && + is_external_interrupt(exit_int_info)) + push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); + + fault_address = svm->vmcb->control.exit_info_2; + error_code = svm->vmcb->control.exit_info_1; + return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code); +} + +static int ud_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + int er; + + er = emulate_instruction(&svm->vcpu, kvm_run, 0, 0, EMULTYPE_TRAP_UD); + if (er != EMULATE_DONE) + kvm_queue_exception(&svm->vcpu, UD_VECTOR); + return 1; +} + +static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); + if (!(svm->vcpu.arch.cr0 & X86_CR0_TS)) + svm->vmcb->save.cr0 &= ~X86_CR0_TS; + svm->vcpu.fpu_active = 1; + + return 1; +} + +static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + /* + * VMCB is undefined after a SHUTDOWN intercept + * so reinitialize it. + */ + clear_page(svm->vmcb); + init_vmcb(svm); + + kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; + return 0; +} + +static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + u32 io_info = svm->vmcb->control.exit_info_1; /* address size bug? */ + int size, down, in, string, rep; + unsigned port; + + ++svm->vcpu.stat.io_exits; + + svm->next_rip = svm->vmcb->control.exit_info_2; + + string = (io_info & SVM_IOIO_STR_MASK) != 0; + + if (string) { + if (emulate_instruction(&svm->vcpu, + kvm_run, 0, 0, 0) == EMULATE_DO_MMIO) + return 0; + return 1; + } + + in = (io_info & SVM_IOIO_TYPE_MASK) != 0; + port = io_info >> 16; + size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT; + rep = (io_info & SVM_IOIO_REP_MASK) != 0; + down = (svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0; + + return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port); +} + +static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + return 1; +} + +static int halt_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + svm->next_rip = svm->vmcb->save.rip + 1; + skip_emulated_instruction(&svm->vcpu); + return kvm_emulate_halt(&svm->vcpu); +} + +static int vmmcall_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + svm->next_rip = svm->vmcb->save.rip + 3; + skip_emulated_instruction(&svm->vcpu); + kvm_emulate_hypercall(&svm->vcpu); + return 1; +} + +static int invalid_op_interception(struct vcpu_svm *svm, + struct kvm_run *kvm_run) +{ + kvm_queue_exception(&svm->vcpu, UD_VECTOR); + return 1; +} + +static int task_switch_interception(struct vcpu_svm *svm, + struct kvm_run *kvm_run) +{ + pr_unimpl(&svm->vcpu, "%s: task switch is unsupported\n", __FUNCTION__); + kvm_run->exit_reason = KVM_EXIT_UNKNOWN; + return 0; +} + +static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + svm->next_rip = svm->vmcb->save.rip + 2; + kvm_emulate_cpuid(&svm->vcpu); + return 1; +} + +static int emulate_on_interception(struct vcpu_svm *svm, + struct kvm_run *kvm_run) +{ + if (emulate_instruction(&svm->vcpu, NULL, 0, 0, 0) != EMULATE_DONE) + pr_unimpl(&svm->vcpu, "%s: failed\n", __FUNCTION__); + return 1; +} + +static int cr8_write_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + emulate_instruction(&svm->vcpu, NULL, 0, 0, 0); + if (irqchip_in_kernel(svm->vcpu.kvm)) + return 1; + kvm_run->exit_reason = KVM_EXIT_SET_TPR; + return 0; +} + +static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + switch (ecx) { + case MSR_IA32_TIME_STAMP_COUNTER: { + u64 tsc; + + rdtscll(tsc); + *data = svm->vmcb->control.tsc_offset + tsc; + break; + } + case MSR_K6_STAR: + *data = svm->vmcb->save.star; + break; +#ifdef CONFIG_X86_64 + case MSR_LSTAR: + *data = svm->vmcb->save.lstar; + break; + case MSR_CSTAR: + *data = svm->vmcb->save.cstar; + break; + case MSR_KERNEL_GS_BASE: + *data = svm->vmcb->save.kernel_gs_base; + break; + case MSR_SYSCALL_MASK: + *data = svm->vmcb->save.sfmask; + break; +#endif + case MSR_IA32_SYSENTER_CS: + *data = svm->vmcb->save.sysenter_cs; + break; + case MSR_IA32_SYSENTER_EIP: + *data = svm->vmcb->save.sysenter_eip; + break; + case MSR_IA32_SYSENTER_ESP: + *data = svm->vmcb->save.sysenter_esp; + break; + /* Nobody will change the following 5 values in the VMCB so + we can safely return them on rdmsr. They will always be 0 + until LBRV is implemented. */ + case MSR_IA32_DEBUGCTLMSR: + *data = svm->vmcb->save.dbgctl; + break; + case MSR_IA32_LASTBRANCHFROMIP: + *data = svm->vmcb->save.br_from; + break; + case MSR_IA32_LASTBRANCHTOIP: + *data = svm->vmcb->save.br_to; + break; + case MSR_IA32_LASTINTFROMIP: + *data = svm->vmcb->save.last_excp_from; + break; + case MSR_IA32_LASTINTTOIP: + *data = svm->vmcb->save.last_excp_to; + break; + default: + return kvm_get_msr_common(vcpu, ecx, data); + } + return 0; +} + +static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + u32 ecx = svm->vcpu.arch.regs[VCPU_REGS_RCX]; + u64 data; + + if (svm_get_msr(&svm->vcpu, ecx, &data)) + kvm_inject_gp(&svm->vcpu, 0); + else { + svm->vmcb->save.rax = data & 0xffffffff; + svm->vcpu.arch.regs[VCPU_REGS_RDX] = data >> 32; + svm->next_rip = svm->vmcb->save.rip + 2; + skip_emulated_instruction(&svm->vcpu); + } + return 1; +} + +static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + switch (ecx) { + case MSR_IA32_TIME_STAMP_COUNTER: { + u64 tsc; + + rdtscll(tsc); + svm->vmcb->control.tsc_offset = data - tsc; + break; + } + case MSR_K6_STAR: + svm->vmcb->save.star = data; + break; +#ifdef CONFIG_X86_64 + case MSR_LSTAR: + svm->vmcb->save.lstar = data; + break; + case MSR_CSTAR: + svm->vmcb->save.cstar = data; + break; + case MSR_KERNEL_GS_BASE: + svm->vmcb->save.kernel_gs_base = data; + break; + case MSR_SYSCALL_MASK: + svm->vmcb->save.sfmask = data; + break; +#endif + case MSR_IA32_SYSENTER_CS: + svm->vmcb->save.sysenter_cs = data; + break; + case MSR_IA32_SYSENTER_EIP: + svm->vmcb->save.sysenter_eip = data; + break; + case MSR_IA32_SYSENTER_ESP: + svm->vmcb->save.sysenter_esp = data; + break; + case MSR_IA32_DEBUGCTLMSR: + if (!svm_has(SVM_FEATURE_LBRV)) { + pr_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTL 0x%llx, nop\n", + __FUNCTION__, data); + break; + } + if (data & DEBUGCTL_RESERVED_BITS) + return 1; + + svm->vmcb->save.dbgctl = data; + if (data & (1ULL<<0)) + svm_enable_lbrv(svm); + else + svm_disable_lbrv(svm); + break; + case MSR_K7_EVNTSEL0: + case MSR_K7_EVNTSEL1: + case MSR_K7_EVNTSEL2: + case MSR_K7_EVNTSEL3: + /* + * only support writing 0 to the performance counters for now + * to make Windows happy. Should be replaced by a real + * performance counter emulation later. + */ + if (data != 0) + goto unhandled; + break; + default: + unhandled: + return kvm_set_msr_common(vcpu, ecx, data); + } + return 0; +} + +static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + u32 ecx = svm->vcpu.arch.regs[VCPU_REGS_RCX]; + u64 data = (svm->vmcb->save.rax & -1u) + | ((u64)(svm->vcpu.arch.regs[VCPU_REGS_RDX] & -1u) << 32); + svm->next_rip = svm->vmcb->save.rip + 2; + if (svm_set_msr(&svm->vcpu, ecx, data)) + kvm_inject_gp(&svm->vcpu, 0); + else + skip_emulated_instruction(&svm->vcpu); + return 1; +} + +static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + if (svm->vmcb->control.exit_info_1) + return wrmsr_interception(svm, kvm_run); + else + return rdmsr_interception(svm, kvm_run); +} + +static int interrupt_window_interception(struct vcpu_svm *svm, + struct kvm_run *kvm_run) +{ + svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR); + svm->vmcb->control.int_ctl &= ~V_IRQ_MASK; + /* + * If the user space waits to inject interrupts, exit as soon as + * possible + */ + if (kvm_run->request_interrupt_window && + !svm->vcpu.arch.irq_summary) { + ++svm->vcpu.stat.irq_window_exits; + kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; + return 0; + } + + return 1; +} + +static int (*svm_exit_handlers[])(struct vcpu_svm *svm, + struct kvm_run *kvm_run) = { + [SVM_EXIT_READ_CR0] = emulate_on_interception, + [SVM_EXIT_READ_CR3] = emulate_on_interception, + [SVM_EXIT_READ_CR4] = emulate_on_interception, + [SVM_EXIT_READ_CR8] = emulate_on_interception, + /* for now: */ + [SVM_EXIT_WRITE_CR0] = emulate_on_interception, + [SVM_EXIT_WRITE_CR3] = emulate_on_interception, + [SVM_EXIT_WRITE_CR4] = emulate_on_interception, + [SVM_EXIT_WRITE_CR8] = cr8_write_interception, + [SVM_EXIT_READ_DR0] = emulate_on_interception, + [SVM_EXIT_READ_DR1] = emulate_on_interception, + [SVM_EXIT_READ_DR2] = emulate_on_interception, + [SVM_EXIT_READ_DR3] = emulate_on_interception, + [SVM_EXIT_WRITE_DR0] = emulate_on_interception, + [SVM_EXIT_WRITE_DR1] = emulate_on_interception, + [SVM_EXIT_WRITE_DR2] = emulate_on_interception, + [SVM_EXIT_WRITE_DR3] = emulate_on_interception, + [SVM_EXIT_WRITE_DR5] = emulate_on_interception, + [SVM_EXIT_WRITE_DR7] = emulate_on_interception, + [SVM_EXIT_EXCP_BASE + UD_VECTOR] = ud_interception, + [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, + [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, + [SVM_EXIT_INTR] = nop_on_interception, + [SVM_EXIT_NMI] = nop_on_interception, + [SVM_EXIT_SMI] = nop_on_interception, + [SVM_EXIT_INIT] = nop_on_interception, + [SVM_EXIT_VINTR] = interrupt_window_interception, + /* [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, */ + [SVM_EXIT_CPUID] = cpuid_interception, + [SVM_EXIT_INVD] = emulate_on_interception, + [SVM_EXIT_HLT] = halt_interception, + [SVM_EXIT_INVLPG] = emulate_on_interception, + [SVM_EXIT_INVLPGA] = invalid_op_interception, + [SVM_EXIT_IOIO] = io_interception, + [SVM_EXIT_MSR] = msr_interception, + [SVM_EXIT_TASK_SWITCH] = task_switch_interception, + [SVM_EXIT_SHUTDOWN] = shutdown_interception, + [SVM_EXIT_VMRUN] = invalid_op_interception, + [SVM_EXIT_VMMCALL] = vmmcall_interception, + [SVM_EXIT_VMLOAD] = invalid_op_interception, + [SVM_EXIT_VMSAVE] = invalid_op_interception, + [SVM_EXIT_STGI] = invalid_op_interception, + [SVM_EXIT_CLGI] = invalid_op_interception, + [SVM_EXIT_SKINIT] = invalid_op_interception, + [SVM_EXIT_WBINVD] = emulate_on_interception, + [SVM_EXIT_MONITOR] = invalid_op_interception, + [SVM_EXIT_MWAIT] = invalid_op_interception, + [SVM_EXIT_NPF] = pf_interception, +}; + +static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + u32 exit_code = svm->vmcb->control.exit_code; + + if (npt_enabled) { + int mmu_reload = 0; + if ((vcpu->arch.cr0 ^ svm->vmcb->save.cr0) & X86_CR0_PG) { + svm_set_cr0(vcpu, svm->vmcb->save.cr0); + mmu_reload = 1; + } + vcpu->arch.cr0 = svm->vmcb->save.cr0; + vcpu->arch.cr3 = svm->vmcb->save.cr3; + if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) { + if (!load_pdptrs(vcpu, vcpu->arch.cr3)) { + kvm_inject_gp(vcpu, 0); + return 1; + } + } + if (mmu_reload) { + kvm_mmu_reset_context(vcpu); + kvm_mmu_load(vcpu); + } + } + + kvm_reput_irq(svm); + + if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) { + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; + kvm_run->fail_entry.hardware_entry_failure_reason + = svm->vmcb->control.exit_code; + return 0; + } + + if (is_external_interrupt(svm->vmcb->control.exit_int_info) && + exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR && + exit_code != SVM_EXIT_NPF) + printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " + "exit_code 0x%x\n", + __FUNCTION__, svm->vmcb->control.exit_int_info, + exit_code); + + if (exit_code >= ARRAY_SIZE(svm_exit_handlers) + || !svm_exit_handlers[exit_code]) { + kvm_run->exit_reason = KVM_EXIT_UNKNOWN; + kvm_run->hw.hardware_exit_reason = exit_code; + return 0; + } + + return svm_exit_handlers[exit_code](svm, kvm_run); +} + +static void reload_tss(struct kvm_vcpu *vcpu) +{ + int cpu = raw_smp_processor_id(); + + struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu); + svm_data->tss_desc->type = 9; /* available 32/64-bit TSS */ + load_TR_desc(); +} + +static void pre_svm_run(struct vcpu_svm *svm) +{ + int cpu = raw_smp_processor_id(); + + struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu); + + svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING; + if (svm->vcpu.cpu != cpu || + svm->asid_generation != svm_data->asid_generation) + new_asid(svm, svm_data); +} + + +static inline void svm_inject_irq(struct vcpu_svm *svm, int irq) +{ + struct vmcb_control_area *control; + + control = &svm->vmcb->control; + control->int_vector = irq; + control->int_ctl &= ~V_INTR_PRIO_MASK; + control->int_ctl |= V_IRQ_MASK | + ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); +} + +static void svm_set_irq(struct kvm_vcpu *vcpu, int irq) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + svm_inject_irq(svm, irq); +} + +static void svm_intr_assist(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + struct vmcb *vmcb = svm->vmcb; + int intr_vector = -1; + + if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) && + ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) { + intr_vector = vmcb->control.exit_int_info & + SVM_EVTINJ_VEC_MASK; + vmcb->control.exit_int_info = 0; + svm_inject_irq(svm, intr_vector); + return; + } + + if (vmcb->control.int_ctl & V_IRQ_MASK) + return; + + if (!kvm_cpu_has_interrupt(vcpu)) + return; + + if (!(vmcb->save.rflags & X86_EFLAGS_IF) || + (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) || + (vmcb->control.event_inj & SVM_EVTINJ_VALID)) { + /* unable to deliver irq, set pending irq */ + vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR); + svm_inject_irq(svm, 0x0); + return; + } + /* Okay, we can deliver the interrupt: grab it and update PIC state. */ + intr_vector = kvm_cpu_get_interrupt(vcpu); + svm_inject_irq(svm, intr_vector); + kvm_timer_intr_post(vcpu, intr_vector); +} + +static void kvm_reput_irq(struct vcpu_svm *svm) +{ + struct vmcb_control_area *control = &svm->vmcb->control; + + if ((control->int_ctl & V_IRQ_MASK) + && !irqchip_in_kernel(svm->vcpu.kvm)) { + control->int_ctl &= ~V_IRQ_MASK; + push_irq(&svm->vcpu, control->int_vector); + } + + svm->vcpu.arch.interrupt_window_open = + !(control->int_state & SVM_INTERRUPT_SHADOW_MASK); +} + +static void svm_do_inject_vector(struct vcpu_svm *svm) +{ + struct kvm_vcpu *vcpu = &svm->vcpu; + int word_index = __ffs(vcpu->arch.irq_summary); + int bit_index = __ffs(vcpu->arch.irq_pending[word_index]); + int irq = word_index * BITS_PER_LONG + bit_index; + + clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]); + if (!vcpu->arch.irq_pending[word_index]) + clear_bit(word_index, &vcpu->arch.irq_summary); + svm_inject_irq(svm, irq); +} + +static void do_interrupt_requests(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + struct vcpu_svm *svm = to_svm(vcpu); + struct vmcb_control_area *control = &svm->vmcb->control; + + svm->vcpu.arch.interrupt_window_open = + (!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) && + (svm->vmcb->save.rflags & X86_EFLAGS_IF)); + + if (svm->vcpu.arch.interrupt_window_open && svm->vcpu.arch.irq_summary) + /* + * If interrupts enabled, and not blocked by sti or mov ss. Good. + */ + svm_do_inject_vector(svm); + + /* + * Interrupts blocked. Wait for unblock. + */ + if (!svm->vcpu.arch.interrupt_window_open && + (svm->vcpu.arch.irq_summary || kvm_run->request_interrupt_window)) + control->intercept |= 1ULL << INTERCEPT_VINTR; + else + control->intercept &= ~(1ULL << INTERCEPT_VINTR); +} + +static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr) +{ + return 0; +} + +static void save_db_regs(unsigned long *db_regs) +{ + asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0])); + asm volatile ("mov %%dr1, %0" : "=r"(db_regs[1])); + asm volatile ("mov %%dr2, %0" : "=r"(db_regs[2])); + asm volatile ("mov %%dr3, %0" : "=r"(db_regs[3])); +} + +static void load_db_regs(unsigned long *db_regs) +{ + asm volatile ("mov %0, %%dr0" : : "r"(db_regs[0])); + asm volatile ("mov %0, %%dr1" : : "r"(db_regs[1])); + asm volatile ("mov %0, %%dr2" : : "r"(db_regs[2])); + asm volatile ("mov %0, %%dr3" : : "r"(db_regs[3])); +} + +static void svm_flush_tlb(struct kvm_vcpu *vcpu) +{ + force_new_asid(vcpu); +} + +static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu) +{ +} + +static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + struct vcpu_svm *svm = to_svm(vcpu); + u16 fs_selector; + u16 gs_selector; + u16 ldt_selector; + + pre_svm_run(svm); + + save_host_msrs(vcpu); + fs_selector = read_fs(); + gs_selector = read_gs(); + ldt_selector = read_ldt(); + svm->host_cr2 = kvm_read_cr2(); + svm->host_dr6 = read_dr6(); + svm->host_dr7 = read_dr7(); + svm->vmcb->save.cr2 = vcpu->arch.cr2; + /* required for live migration with NPT */ + if (npt_enabled) + svm->vmcb->save.cr3 = vcpu->arch.cr3; + + if (svm->vmcb->save.dr7 & 0xff) { + write_dr7(0); + save_db_regs(svm->host_db_regs); + load_db_regs(svm->db_regs); + } + + clgi(); + + local_irq_enable(); + + asm volatile ( +#ifdef CONFIG_X86_64 + "push %%rbp; \n\t" +#else + "push %%ebp; \n\t" +#endif + +#ifdef CONFIG_X86_64 + "mov %c[rbx](%[svm]), %%rbx \n\t" + "mov %c[rcx](%[svm]), %%rcx \n\t" + "mov %c[rdx](%[svm]), %%rdx \n\t" + "mov %c[rsi](%[svm]), %%rsi \n\t" + "mov %c[rdi](%[svm]), %%rdi \n\t" + "mov %c[rbp](%[svm]), %%rbp \n\t" + "mov %c[r8](%[svm]), %%r8 \n\t" + "mov %c[r9](%[svm]), %%r9 \n\t" + "mov %c[r10](%[svm]), %%r10 \n\t" + "mov %c[r11](%[svm]), %%r11 \n\t" + "mov %c[r12](%[svm]), %%r12 \n\t" + "mov %c[r13](%[svm]), %%r13 \n\t" + "mov %c[r14](%[svm]), %%r14 \n\t" + "mov %c[r15](%[svm]), %%r15 \n\t" +#else + "mov %c[rbx](%[svm]), %%ebx \n\t" + "mov %c[rcx](%[svm]), %%ecx \n\t" + "mov %c[rdx](%[svm]), %%edx \n\t" + "mov %c[rsi](%[svm]), %%esi \n\t" + "mov %c[rdi](%[svm]), %%edi \n\t" + "mov %c[rbp](%[svm]), %%ebp \n\t" +#endif + +#ifdef CONFIG_X86_64 + /* Enter guest mode */ + "push %%rax \n\t" + "mov %c[vmcb](%[svm]), %%rax \n\t" + SVM_VMLOAD "\n\t" + SVM_VMRUN "\n\t" + SVM_VMSAVE "\n\t" + "pop %%rax \n\t" +#else + /* Enter guest mode */ + "push %%eax \n\t" + "mov %c[vmcb](%[svm]), %%eax \n\t" + SVM_VMLOAD "\n\t" + SVM_VMRUN "\n\t" + SVM_VMSAVE "\n\t" + "pop %%eax \n\t" +#endif + + /* Save guest registers, load host registers */ +#ifdef CONFIG_X86_64 + "mov %%rbx, %c[rbx](%[svm]) \n\t" + "mov %%rcx, %c[rcx](%[svm]) \n\t" + "mov %%rdx, %c[rdx](%[svm]) \n\t" + "mov %%rsi, %c[rsi](%[svm]) \n\t" + "mov %%rdi, %c[rdi](%[svm]) \n\t" + "mov %%rbp, %c[rbp](%[svm]) \n\t" + "mov %%r8, %c[r8](%[svm]) \n\t" + "mov %%r9, %c[r9](%[svm]) \n\t" + "mov %%r10, %c[r10](%[svm]) \n\t" + "mov %%r11, %c[r11](%[svm]) \n\t" + "mov %%r12, %c[r12](%[svm]) \n\t" + "mov %%r13, %c[r13](%[svm]) \n\t" + "mov %%r14, %c[r14](%[svm]) \n\t" + "mov %%r15, %c[r15](%[svm]) \n\t" + + "pop %%rbp; \n\t" +#else + "mov %%ebx, %c[rbx](%[svm]) \n\t" + "mov %%ecx, %c[rcx](%[svm]) \n\t" + "mov %%edx, %c[rdx](%[svm]) \n\t" + "mov %%esi, %c[rsi](%[svm]) \n\t" + "mov %%edi, %c[rdi](%[svm]) \n\t" + "mov %%ebp, %c[rbp](%[svm]) \n\t" + + "pop %%ebp; \n\t" +#endif + : + : [svm]"a"(svm), + [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)), + [rbx]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_RBX])), + [rcx]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_RCX])), + [rdx]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_RDX])), + [rsi]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_RSI])), + [rdi]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_RDI])), + [rbp]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_RBP])) +#ifdef CONFIG_X86_64 + , [r8]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R8])), + [r9]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R9])), + [r10]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R10])), + [r11]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R11])), + [r12]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R12])), + [r13]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R13])), + [r14]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R14])), + [r15]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R15])) +#endif + : "cc", "memory" +#ifdef CONFIG_X86_64 + , "rbx", "rcx", "rdx", "rsi", "rdi" + , "r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15" +#else + , "ebx", "ecx", "edx" , "esi", "edi" +#endif + ); + + if ((svm->vmcb->save.dr7 & 0xff)) + load_db_regs(svm->host_db_regs); + + vcpu->arch.cr2 = svm->vmcb->save.cr2; + + write_dr6(svm->host_dr6); + write_dr7(svm->host_dr7); + kvm_write_cr2(svm->host_cr2); + + load_fs(fs_selector); + load_gs(gs_selector); + load_ldt(ldt_selector); + load_host_msrs(vcpu); + + reload_tss(vcpu); + + local_irq_disable(); + + stgi(); + + svm->next_rip = 0; +} + +static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + if (npt_enabled) { + svm->vmcb->control.nested_cr3 = root; + force_new_asid(vcpu); + return; + } + + svm->vmcb->save.cr3 = root; + force_new_asid(vcpu); + + if (vcpu->fpu_active) { + svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR); + svm->vmcb->save.cr0 |= X86_CR0_TS; + vcpu->fpu_active = 0; + } +} + +static int is_disabled(void) +{ + u64 vm_cr; + + rdmsrl(MSR_VM_CR, vm_cr); + if (vm_cr & (1 << SVM_VM_CR_SVM_DISABLE)) + return 1; + + return 0; +} + +static void +svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) +{ + /* + * Patch in the VMMCALL instruction: + */ + hypercall[0] = 0x0f; + hypercall[1] = 0x01; + hypercall[2] = 0xd9; +} + +static void svm_check_processor_compat(void *rtn) +{ + *(int *)rtn = 0; +} + +static bool svm_cpu_has_accelerated_tpr(void) +{ + return false; +} + +static struct kvm_x86_ops svm_x86_ops = { + .cpu_has_kvm_support = has_svm, + .disabled_by_bios = is_disabled, + .hardware_setup = svm_hardware_setup, + .hardware_unsetup = svm_hardware_unsetup, + .check_processor_compatibility = svm_check_processor_compat, + .hardware_enable = svm_hardware_enable, + .hardware_disable = svm_hardware_disable, + .cpu_has_accelerated_tpr = svm_cpu_has_accelerated_tpr, + + .vcpu_create = svm_create_vcpu, + .vcpu_free = svm_free_vcpu, + .vcpu_reset = svm_vcpu_reset, + + .prepare_guest_switch = svm_prepare_guest_switch, + .vcpu_load = svm_vcpu_load, + .vcpu_put = svm_vcpu_put, + .vcpu_decache = svm_vcpu_decache, + + .set_guest_debug = svm_guest_debug, + .get_msr = svm_get_msr, + .set_msr = svm_set_msr, + .get_segment_base = svm_get_segment_base, + .get_segment = svm_get_segment, + .set_segment = svm_set_segment, + .get_cs_db_l_bits = kvm_get_cs_db_l_bits, + .decache_cr4_guest_bits = svm_decache_cr4_guest_bits, + .set_cr0 = svm_set_cr0, + .set_cr3 = svm_set_cr3, + .set_cr4 = svm_set_cr4, + .set_efer = svm_set_efer, + .get_idt = svm_get_idt, + .set_idt = svm_set_idt, + .get_gdt = svm_get_gdt, + .set_gdt = svm_set_gdt, + .get_dr = svm_get_dr, + .set_dr = svm_set_dr, + .cache_regs = svm_cache_regs, + .decache_regs = svm_decache_regs, + .get_rflags = svm_get_rflags, + .set_rflags = svm_set_rflags, + + .tlb_flush = svm_flush_tlb, + + .run = svm_vcpu_run, + .handle_exit = handle_exit, + .skip_emulated_instruction = skip_emulated_instruction, + .patch_hypercall = svm_patch_hypercall, + .get_irq = svm_get_irq, + .set_irq = svm_set_irq, + .queue_exception = svm_queue_exception, + .exception_injected = svm_exception_injected, + .inject_pending_irq = svm_intr_assist, + .inject_pending_vectors = do_interrupt_requests, + + .set_tss_addr = svm_set_tss_addr, +}; + +static int __init svm_init(void) +{ + return kvm_init(&svm_x86_ops, sizeof(struct vcpu_svm), + THIS_MODULE); +} + +static void __exit svm_exit(void) +{ + kvm_exit(); +} + +module_init(svm_init) +module_exit(svm_exit) --- linux-2.6.24.orig/arch/x86/kvm/Kconfig +++ linux-2.6.24/arch/x86/kvm/Kconfig @@ -0,0 +1,58 @@ +# +# KVM configuration +# +config HAVE_KVM + bool + +menuconfig VIRTUALIZATION + bool "Virtualization" + depends on HAVE_KVM || X86 + default y + ---help--- + Say Y here to get to see options for using your Linux host to run other + operating systems inside virtual machines (guests). + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if VIRTUALIZATION + +config KVM + tristate "Kernel-based Virtual Machine (KVM) support" + depends on HAVE_KVM && EXPERIMENTAL + select PREEMPT_NOTIFIERS + select ANON_INODES + ---help--- + Support hosting fully virtualized guest machines using hardware + virtualization extensions. You will need a fairly recent + processor equipped with virtualization extensions. You will also + need to select one or more of the processor modules below. + + This module provides access to the hardware capabilities through + a character device node named /dev/kvm. + + To compile this as a module, choose M here: the module + will be called kvm. + + If unsure, say N. + +config KVM_INTEL + tristate "KVM for Intel processors support" + depends on KVM + ---help--- + Provides support for KVM on Intel processors equipped with the VT + extensions. + +config KVM_AMD + tristate "KVM for AMD processors support" + depends on KVM + ---help--- + Provides support for KVM on AMD processors equipped with the AMD-V + (SVM) extensions. + +# OK, it's a little counter-intuitive to do this, but it puts it neatly under +# the virtualization menu. +source drivers/lguest/Kconfig +source drivers/virtio/Kconfig + +endif # VIRTUALIZATION --- linux-2.6.24.orig/arch/x86/kvm/svm.h +++ linux-2.6.24/arch/x86/kvm/svm.h @@ -0,0 +1,325 @@ +#ifndef __SVM_H +#define __SVM_H + +enum { + INTERCEPT_INTR, + INTERCEPT_NMI, + INTERCEPT_SMI, + INTERCEPT_INIT, + INTERCEPT_VINTR, + INTERCEPT_SELECTIVE_CR0, + INTERCEPT_STORE_IDTR, + INTERCEPT_STORE_GDTR, + INTERCEPT_STORE_LDTR, + INTERCEPT_STORE_TR, + INTERCEPT_LOAD_IDTR, + INTERCEPT_LOAD_GDTR, + INTERCEPT_LOAD_LDTR, + INTERCEPT_LOAD_TR, + INTERCEPT_RDTSC, + INTERCEPT_RDPMC, + INTERCEPT_PUSHF, + INTERCEPT_POPF, + INTERCEPT_CPUID, + INTERCEPT_RSM, + INTERCEPT_IRET, + INTERCEPT_INTn, + INTERCEPT_INVD, + INTERCEPT_PAUSE, + INTERCEPT_HLT, + INTERCEPT_INVLPG, + INTERCEPT_INVLPGA, + INTERCEPT_IOIO_PROT, + INTERCEPT_MSR_PROT, + INTERCEPT_TASK_SWITCH, + INTERCEPT_FERR_FREEZE, + INTERCEPT_SHUTDOWN, + INTERCEPT_VMRUN, + INTERCEPT_VMMCALL, + INTERCEPT_VMLOAD, + INTERCEPT_VMSAVE, + INTERCEPT_STGI, + INTERCEPT_CLGI, + INTERCEPT_SKINIT, + INTERCEPT_RDTSCP, + INTERCEPT_ICEBP, + INTERCEPT_WBINVD, + INTERCEPT_MONITOR, + INTERCEPT_MWAIT, + INTERCEPT_MWAIT_COND, +}; + + +struct __attribute__ ((__packed__)) vmcb_control_area { + u16 intercept_cr_read; + u16 intercept_cr_write; + u16 intercept_dr_read; + u16 intercept_dr_write; + u32 intercept_exceptions; + u64 intercept; + u8 reserved_1[44]; + u64 iopm_base_pa; + u64 msrpm_base_pa; + u64 tsc_offset; + u32 asid; + u8 tlb_ctl; + u8 reserved_2[3]; + u32 int_ctl; + u32 int_vector; + u32 int_state; + u8 reserved_3[4]; + u32 exit_code; + u32 exit_code_hi; + u64 exit_info_1; + u64 exit_info_2; + u32 exit_int_info; + u32 exit_int_info_err; + u64 nested_ctl; + u8 reserved_4[16]; + u32 event_inj; + u32 event_inj_err; + u64 nested_cr3; + u64 lbr_ctl; + u8 reserved_5[832]; +}; + + +#define TLB_CONTROL_DO_NOTHING 0 +#define TLB_CONTROL_FLUSH_ALL_ASID 1 + +#define V_TPR_MASK 0x0f + +#define V_IRQ_SHIFT 8 +#define V_IRQ_MASK (1 << V_IRQ_SHIFT) + +#define V_INTR_PRIO_SHIFT 16 +#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT) + +#define V_IGN_TPR_SHIFT 20 +#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT) + +#define V_INTR_MASKING_SHIFT 24 +#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT) + +#define SVM_INTERRUPT_SHADOW_MASK 1 + +#define SVM_IOIO_STR_SHIFT 2 +#define SVM_IOIO_REP_SHIFT 3 +#define SVM_IOIO_SIZE_SHIFT 4 +#define SVM_IOIO_ASIZE_SHIFT 7 + +#define SVM_IOIO_TYPE_MASK 1 +#define SVM_IOIO_STR_MASK (1 << SVM_IOIO_STR_SHIFT) +#define SVM_IOIO_REP_MASK (1 << SVM_IOIO_REP_SHIFT) +#define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT) +#define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT) + +struct __attribute__ ((__packed__)) vmcb_seg { + u16 selector; + u16 attrib; + u32 limit; + u64 base; +}; + +struct __attribute__ ((__packed__)) vmcb_save_area { + struct vmcb_seg es; + struct vmcb_seg cs; + struct vmcb_seg ss; + struct vmcb_seg ds; + struct vmcb_seg fs; + struct vmcb_seg gs; + struct vmcb_seg gdtr; + struct vmcb_seg ldtr; + struct vmcb_seg idtr; + struct vmcb_seg tr; + u8 reserved_1[43]; + u8 cpl; + u8 reserved_2[4]; + u64 efer; + u8 reserved_3[112]; + u64 cr4; + u64 cr3; + u64 cr0; + u64 dr7; + u64 dr6; + u64 rflags; + u64 rip; + u8 reserved_4[88]; + u64 rsp; + u8 reserved_5[24]; + u64 rax; + u64 star; + u64 lstar; + u64 cstar; + u64 sfmask; + u64 kernel_gs_base; + u64 sysenter_cs; + u64 sysenter_esp; + u64 sysenter_eip; + u64 cr2; + u8 reserved_6[32]; + u64 g_pat; + u64 dbgctl; + u64 br_from; + u64 br_to; + u64 last_excp_from; + u64 last_excp_to; +}; + +struct __attribute__ ((__packed__)) vmcb { + struct vmcb_control_area control; + struct vmcb_save_area save; +}; + +#define SVM_CPUID_FEATURE_SHIFT 2 +#define SVM_CPUID_FUNC 0x8000000a + +#define MSR_EFER_SVME_MASK (1ULL << 12) +#define MSR_VM_CR 0xc0010114 +#define MSR_VM_HSAVE_PA 0xc0010117ULL + +#define SVM_VM_CR_SVM_DISABLE 4 + +#define SVM_SELECTOR_S_SHIFT 4 +#define SVM_SELECTOR_DPL_SHIFT 5 +#define SVM_SELECTOR_P_SHIFT 7 +#define SVM_SELECTOR_AVL_SHIFT 8 +#define SVM_SELECTOR_L_SHIFT 9 +#define SVM_SELECTOR_DB_SHIFT 10 +#define SVM_SELECTOR_G_SHIFT 11 + +#define SVM_SELECTOR_TYPE_MASK (0xf) +#define SVM_SELECTOR_S_MASK (1 << SVM_SELECTOR_S_SHIFT) +#define SVM_SELECTOR_DPL_MASK (3 << SVM_SELECTOR_DPL_SHIFT) +#define SVM_SELECTOR_P_MASK (1 << SVM_SELECTOR_P_SHIFT) +#define SVM_SELECTOR_AVL_MASK (1 << SVM_SELECTOR_AVL_SHIFT) +#define SVM_SELECTOR_L_MASK (1 << SVM_SELECTOR_L_SHIFT) +#define SVM_SELECTOR_DB_MASK (1 << SVM_SELECTOR_DB_SHIFT) +#define SVM_SELECTOR_G_MASK (1 << SVM_SELECTOR_G_SHIFT) + +#define SVM_SELECTOR_WRITE_MASK (1 << 1) +#define SVM_SELECTOR_READ_MASK SVM_SELECTOR_WRITE_MASK +#define SVM_SELECTOR_CODE_MASK (1 << 3) + +#define INTERCEPT_CR0_MASK 1 +#define INTERCEPT_CR3_MASK (1 << 3) +#define INTERCEPT_CR4_MASK (1 << 4) +#define INTERCEPT_CR8_MASK (1 << 8) + +#define INTERCEPT_DR0_MASK 1 +#define INTERCEPT_DR1_MASK (1 << 1) +#define INTERCEPT_DR2_MASK (1 << 2) +#define INTERCEPT_DR3_MASK (1 << 3) +#define INTERCEPT_DR4_MASK (1 << 4) +#define INTERCEPT_DR5_MASK (1 << 5) +#define INTERCEPT_DR6_MASK (1 << 6) +#define INTERCEPT_DR7_MASK (1 << 7) + +#define SVM_EVTINJ_VEC_MASK 0xff + +#define SVM_EVTINJ_TYPE_SHIFT 8 +#define SVM_EVTINJ_TYPE_MASK (7 << SVM_EVTINJ_TYPE_SHIFT) + +#define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT) +#define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT) +#define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT) +#define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT) + +#define SVM_EVTINJ_VALID (1 << 31) +#define SVM_EVTINJ_VALID_ERR (1 << 11) + +#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK + +#define SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR +#define SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI +#define SVM_EXITINTINFO_TYPE_EXEPT SVM_EVTINJ_TYPE_EXEPT +#define SVM_EXITINTINFO_TYPE_SOFT SVM_EVTINJ_TYPE_SOFT + +#define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID +#define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR + +#define SVM_EXIT_READ_CR0 0x000 +#define SVM_EXIT_READ_CR3 0x003 +#define SVM_EXIT_READ_CR4 0x004 +#define SVM_EXIT_READ_CR8 0x008 +#define SVM_EXIT_WRITE_CR0 0x010 +#define SVM_EXIT_WRITE_CR3 0x013 +#define SVM_EXIT_WRITE_CR4 0x014 +#define SVM_EXIT_WRITE_CR8 0x018 +#define SVM_EXIT_READ_DR0 0x020 +#define SVM_EXIT_READ_DR1 0x021 +#define SVM_EXIT_READ_DR2 0x022 +#define SVM_EXIT_READ_DR3 0x023 +#define SVM_EXIT_READ_DR4 0x024 +#define SVM_EXIT_READ_DR5 0x025 +#define SVM_EXIT_READ_DR6 0x026 +#define SVM_EXIT_READ_DR7 0x027 +#define SVM_EXIT_WRITE_DR0 0x030 +#define SVM_EXIT_WRITE_DR1 0x031 +#define SVM_EXIT_WRITE_DR2 0x032 +#define SVM_EXIT_WRITE_DR3 0x033 +#define SVM_EXIT_WRITE_DR4 0x034 +#define SVM_EXIT_WRITE_DR5 0x035 +#define SVM_EXIT_WRITE_DR6 0x036 +#define SVM_EXIT_WRITE_DR7 0x037 +#define SVM_EXIT_EXCP_BASE 0x040 +#define SVM_EXIT_INTR 0x060 +#define SVM_EXIT_NMI 0x061 +#define SVM_EXIT_SMI 0x062 +#define SVM_EXIT_INIT 0x063 +#define SVM_EXIT_VINTR 0x064 +#define SVM_EXIT_CR0_SEL_WRITE 0x065 +#define SVM_EXIT_IDTR_READ 0x066 +#define SVM_EXIT_GDTR_READ 0x067 +#define SVM_EXIT_LDTR_READ 0x068 +#define SVM_EXIT_TR_READ 0x069 +#define SVM_EXIT_IDTR_WRITE 0x06a +#define SVM_EXIT_GDTR_WRITE 0x06b +#define SVM_EXIT_LDTR_WRITE 0x06c +#define SVM_EXIT_TR_WRITE 0x06d +#define SVM_EXIT_RDTSC 0x06e +#define SVM_EXIT_RDPMC 0x06f +#define SVM_EXIT_PUSHF 0x070 +#define SVM_EXIT_POPF 0x071 +#define SVM_EXIT_CPUID 0x072 +#define SVM_EXIT_RSM 0x073 +#define SVM_EXIT_IRET 0x074 +#define SVM_EXIT_SWINT 0x075 +#define SVM_EXIT_INVD 0x076 +#define SVM_EXIT_PAUSE 0x077 +#define SVM_EXIT_HLT 0x078 +#define SVM_EXIT_INVLPG 0x079 +#define SVM_EXIT_INVLPGA 0x07a +#define SVM_EXIT_IOIO 0x07b +#define SVM_EXIT_MSR 0x07c +#define SVM_EXIT_TASK_SWITCH 0x07d +#define SVM_EXIT_FERR_FREEZE 0x07e +#define SVM_EXIT_SHUTDOWN 0x07f +#define SVM_EXIT_VMRUN 0x080 +#define SVM_EXIT_VMMCALL 0x081 +#define SVM_EXIT_VMLOAD 0x082 +#define SVM_EXIT_VMSAVE 0x083 +#define SVM_EXIT_STGI 0x084 +#define SVM_EXIT_CLGI 0x085 +#define SVM_EXIT_SKINIT 0x086 +#define SVM_EXIT_RDTSCP 0x087 +#define SVM_EXIT_ICEBP 0x088 +#define SVM_EXIT_WBINVD 0x089 +#define SVM_EXIT_MONITOR 0x08a +#define SVM_EXIT_MWAIT 0x08b +#define SVM_EXIT_MWAIT_COND 0x08c +#define SVM_EXIT_NPF 0x400 + +#define SVM_EXIT_ERR -1 + +#define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) /* TS and MP */ + +#define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda" +#define SVM_VMRUN ".byte 0x0f, 0x01, 0xd8" +#define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb" +#define SVM_CLGI ".byte 0x0f, 0x01, 0xdd" +#define SVM_STGI ".byte 0x0f, 0x01, 0xdc" +#define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf" + +#endif + --- linux-2.6.24.orig/arch/x86/kvm/irq.c +++ linux-2.6.24/arch/x86/kvm/irq.c @@ -0,0 +1,78 @@ +/* + * irq.c: API for in kernel interrupt controller + * Copyright (c) 2007, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * Authors: + * Yaozu (Eddie) Dong + * + */ + +#include +#include + +#include "irq.h" + +/* + * check if there is pending interrupt without + * intack. + */ +int kvm_cpu_has_interrupt(struct kvm_vcpu *v) +{ + struct kvm_pic *s; + + if (kvm_apic_has_interrupt(v) == -1) { /* LAPIC */ + if (kvm_apic_accept_pic_intr(v)) { + s = pic_irqchip(v->kvm); /* PIC */ + return s->output; + } else + return 0; + } + return 1; +} +EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); + +/* + * Read pending interrupt vector and intack. + */ +int kvm_cpu_get_interrupt(struct kvm_vcpu *v) +{ + struct kvm_pic *s; + int vector; + + vector = kvm_get_apic_interrupt(v); /* APIC */ + if (vector == -1) { + if (kvm_apic_accept_pic_intr(v)) { + s = pic_irqchip(v->kvm); + s->output = 0; /* PIC */ + vector = kvm_pic_read_irq(s); + } + } + return vector; +} +EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); + +void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) +{ + kvm_inject_apic_timer_irqs(vcpu); + /* TODO: PIT, RTC etc. */ +} +EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); + +void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec) +{ + kvm_apic_timer_intr_post(vcpu, vec); + /* TODO: PIT, RTC etc. */ +} +EXPORT_SYMBOL_GPL(kvm_timer_intr_post); --- linux-2.6.24.orig/arch/x86/kvm/x86_emulate.c +++ linux-2.6.24/arch/x86/kvm/x86_emulate.c @@ -0,0 +1,1945 @@ +/****************************************************************************** + * x86_emulate.c + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. + * + * Copyright (c) 2005 Keir Fraser + * + * Linux coding style, mod r/m decoder, segment base fixes, real-mode + * privileged instructions: + * + * Copyright (C) 2006 Qumranet + * + * Avi Kivity + * Yaniv Kamay + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4 + */ + +#ifndef __KERNEL__ +#include +#include +#include +#define DPRINTF(_f, _a ...) printf(_f , ## _a) +#else +#include +#define DPRINTF(x...) do {} while (0) +#endif +#include +#include + +/* + * Opcode effective-address decode tables. + * Note that we only emulate instructions that have at least one memory + * operand (excluding implicit stack references). We assume that stack + * references and instruction fetches will never occur in special memory + * areas that require emulation. So, for example, 'mov ,' need + * not be handled. + */ + +/* Operand sizes: 8-bit operands or specified/overridden size. */ +#define ByteOp (1<<0) /* 8-bit operands. */ +/* Destination operand type. */ +#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */ +#define DstReg (2<<1) /* Register operand. */ +#define DstMem (3<<1) /* Memory operand. */ +#define DstMask (3<<1) +/* Source operand type. */ +#define SrcNone (0<<3) /* No source operand. */ +#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */ +#define SrcReg (1<<3) /* Register operand. */ +#define SrcMem (2<<3) /* Memory operand. */ +#define SrcMem16 (3<<3) /* Memory operand (16-bit). */ +#define SrcMem32 (4<<3) /* Memory operand (32-bit). */ +#define SrcImm (5<<3) /* Immediate operand. */ +#define SrcImmByte (6<<3) /* 8-bit sign-extended immediate operand. */ +#define SrcMask (7<<3) +/* Generic ModRM decode. */ +#define ModRM (1<<6) +/* Destination is only written; never read. */ +#define Mov (1<<7) +#define BitOp (1<<8) +#define MemAbs (1<<9) /* Memory operand is absolute displacement */ +#define String (1<<10) /* String instruction (rep capable) */ +#define Stack (1<<11) /* Stack instruction (push/pop) */ +#define Group (1<<14) /* Bits 3:5 of modrm byte extend opcode */ +#define GroupDual (1<<15) /* Alternate decoding of mod == 3 */ +#define GroupMask 0xff /* Group number stored in bits 0:7 */ + +enum { + Group1_80, Group1_81, Group1_82, Group1_83, + Group1A, Group3_Byte, Group3, Group4, Group5, Group7, +}; + +static u16 opcode_table[256] = { + /* 0x00 - 0x07 */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x08 - 0x0F */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x10 - 0x17 */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x18 - 0x1F */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x20 - 0x27 */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + SrcImmByte, SrcImm, 0, 0, + /* 0x28 - 0x2F */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x30 - 0x37 */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x38 - 0x3F */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + 0, 0, 0, 0, + /* 0x40 - 0x47 */ + DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, + /* 0x48 - 0x4F */ + DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, + /* 0x50 - 0x57 */ + SrcReg | Stack, SrcReg | Stack, SrcReg | Stack, SrcReg | Stack, + SrcReg | Stack, SrcReg | Stack, SrcReg | Stack, SrcReg | Stack, + /* 0x58 - 0x5F */ + DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack, + DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack, + /* 0x60 - 0x67 */ + 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , + 0, 0, 0, 0, + /* 0x68 - 0x6F */ + 0, 0, ImplicitOps | Mov | Stack, 0, + SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */ + SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */ + /* 0x70 - 0x77 */ + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + /* 0x78 - 0x7F */ + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + /* 0x80 - 0x87 */ + Group | Group1_80, Group | Group1_81, + Group | Group1_82, Group | Group1_83, + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + /* 0x88 - 0x8F */ + ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov, + ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + 0, ModRM | DstReg, 0, Group | Group1A, + /* 0x90 - 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, ImplicitOps | Stack, ImplicitOps | Stack, 0, 0, + /* 0xA0 - 0xA7 */ + ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs, + ByteOp | DstMem | SrcReg | Mov | MemAbs, DstMem | SrcReg | Mov | MemAbs, + ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String, + ByteOp | ImplicitOps | String, ImplicitOps | String, + /* 0xA8 - 0xAF */ + 0, 0, ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String, + ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String, + ByteOp | ImplicitOps | String, ImplicitOps | String, + /* 0xB0 - 0xBF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xC0 - 0xC7 */ + ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, + 0, ImplicitOps | Stack, 0, 0, + ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov, + /* 0xC8 - 0xCF */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xD0 - 0xD7 */ + ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM, + ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM, + 0, 0, 0, 0, + /* 0xD8 - 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE0 - 0xE7 */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE8 - 0xEF */ + ImplicitOps | Stack, SrcImm|ImplicitOps, 0, SrcImmByte|ImplicitOps, + 0, 0, 0, 0, + /* 0xF0 - 0xF7 */ + 0, 0, 0, 0, + ImplicitOps, ImplicitOps, Group | Group3_Byte, Group | Group3, + /* 0xF8 - 0xFF */ + ImplicitOps, 0, ImplicitOps, ImplicitOps, + 0, 0, Group | Group4, Group | Group5, +}; + +static u16 twobyte_table[256] = { + /* 0x00 - 0x0F */ + 0, Group | GroupDual | Group7, 0, 0, 0, 0, ImplicitOps, 0, + ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0, + /* 0x10 - 0x1F */ + 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, + /* 0x20 - 0x2F */ + ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x30 - 0x3F */ + ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x40 - 0x47 */ + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + /* 0x48 - 0x4F */ + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + /* 0x50 - 0x5F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x60 - 0x6F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x70 - 0x7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x80 - 0x8F */ + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + /* 0x90 - 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xA0 - 0xA7 */ + 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0, + /* 0xA8 - 0xAF */ + 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0, + /* 0xB0 - 0xB7 */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, 0, + DstMem | SrcReg | ModRM | BitOp, + 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem16 | ModRM | Mov, + /* 0xB8 - 0xBF */ + 0, 0, DstMem | SrcImmByte | ModRM, DstMem | SrcReg | ModRM | BitOp, + 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem16 | ModRM | Mov, + /* 0xC0 - 0xCF */ + 0, 0, 0, DstMem | SrcReg | ModRM | Mov, 0, 0, 0, ImplicitOps | ModRM, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xD0 - 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE0 - 0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xF0 - 0xFF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static u16 group_table[] = { + [Group1_80*8] = + ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, + ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, + ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, + ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, + [Group1_81*8] = + DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, + DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, + DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, + DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, + [Group1_82*8] = + ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, + ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, + ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, + ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, + [Group1_83*8] = + DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM, + DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM, + DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM, + DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM, + [Group1A*8] = + DstMem | SrcNone | ModRM | Mov | Stack, 0, 0, 0, 0, 0, 0, 0, + [Group3_Byte*8] = + ByteOp | SrcImm | DstMem | ModRM, 0, + ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM, + 0, 0, 0, 0, + [Group3*8] = + DstMem | SrcImm | ModRM | SrcImm, 0, + DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM, + 0, 0, 0, 0, + [Group4*8] = + ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM, + 0, 0, 0, 0, 0, 0, + [Group5*8] = + DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM, 0, 0, + SrcMem | ModRM, 0, SrcMem | ModRM | Stack, 0, + [Group7*8] = + 0, 0, ModRM | SrcMem, ModRM | SrcMem, + SrcNone | ModRM | DstMem, 0, SrcMem | ModRM, SrcMem | ModRM | ByteOp, +}; + +static u16 group2_table[] = { + [Group7*8] = + SrcNone | ModRM, 0, 0, 0, SrcNone | ModRM | DstMem, 0, SrcMem | ModRM, 0, +}; + +/* EFLAGS bit definitions. */ +#define EFLG_OF (1<<11) +#define EFLG_DF (1<<10) +#define EFLG_SF (1<<7) +#define EFLG_ZF (1<<6) +#define EFLG_AF (1<<4) +#define EFLG_PF (1<<2) +#define EFLG_CF (1<<0) + +/* + * Instruction emulation: + * Most instructions are emulated directly via a fragment of inline assembly + * code. This allows us to save/restore EFLAGS and thus very easily pick up + * any modified flags. + */ + +#if defined(CONFIG_X86_64) +#define _LO32 "k" /* force 32-bit operand */ +#define _STK "%%rsp" /* stack pointer */ +#elif defined(__i386__) +#define _LO32 "" /* force 32-bit operand */ +#define _STK "%%esp" /* stack pointer */ +#endif + +/* + * These EFLAGS bits are restored from saved value during emulation, and + * any changes are written back to the saved value after emulation. + */ +#define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF) + +/* Before executing instruction: restore necessary bits in EFLAGS. */ +#define _PRE_EFLAGS(_sav, _msk, _tmp) \ + /* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); _sav &= ~_msk; */ \ + "movl %"_sav",%"_LO32 _tmp"; " \ + "push %"_tmp"; " \ + "push %"_tmp"; " \ + "movl %"_msk",%"_LO32 _tmp"; " \ + "andl %"_LO32 _tmp",("_STK"); " \ + "pushf; " \ + "notl %"_LO32 _tmp"; " \ + "andl %"_LO32 _tmp",("_STK"); " \ + "andl %"_LO32 _tmp","__stringify(BITS_PER_LONG/4)"("_STK"); " \ + "pop %"_tmp"; " \ + "orl %"_LO32 _tmp",("_STK"); " \ + "popf; " \ + "pop %"_sav"; " + +/* After executing instruction: write-back necessary bits in EFLAGS. */ +#define _POST_EFLAGS(_sav, _msk, _tmp) \ + /* _sav |= EFLAGS & _msk; */ \ + "pushf; " \ + "pop %"_tmp"; " \ + "andl %"_msk",%"_LO32 _tmp"; " \ + "orl %"_LO32 _tmp",%"_sav"; " + +/* Raw emulation: instruction has two explicit operands. */ +#define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy) \ + do { \ + unsigned long _tmp; \ + \ + switch ((_dst).bytes) { \ + case 2: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0", "4", "2") \ + _op"w %"_wx"3,%1; " \ + _POST_EFLAGS("0", "4", "2") \ + : "=m" (_eflags), "=m" ((_dst).val), \ + "=&r" (_tmp) \ + : _wy ((_src).val), "i" (EFLAGS_MASK)); \ + break; \ + case 4: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0", "4", "2") \ + _op"l %"_lx"3,%1; " \ + _POST_EFLAGS("0", "4", "2") \ + : "=m" (_eflags), "=m" ((_dst).val), \ + "=&r" (_tmp) \ + : _ly ((_src).val), "i" (EFLAGS_MASK)); \ + break; \ + case 8: \ + __emulate_2op_8byte(_op, _src, _dst, \ + _eflags, _qx, _qy); \ + break; \ + } \ + } while (0) + +#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy) \ + do { \ + unsigned long __tmp; \ + switch ((_dst).bytes) { \ + case 1: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0", "4", "2") \ + _op"b %"_bx"3,%1; " \ + _POST_EFLAGS("0", "4", "2") \ + : "=m" (_eflags), "=m" ((_dst).val), \ + "=&r" (__tmp) \ + : _by ((_src).val), "i" (EFLAGS_MASK)); \ + break; \ + default: \ + __emulate_2op_nobyte(_op, _src, _dst, _eflags, \ + _wx, _wy, _lx, _ly, _qx, _qy); \ + break; \ + } \ + } while (0) + +/* Source operand is byte-sized and may be restricted to just %cl. */ +#define emulate_2op_SrcB(_op, _src, _dst, _eflags) \ + __emulate_2op(_op, _src, _dst, _eflags, \ + "b", "c", "b", "c", "b", "c", "b", "c") + +/* Source operand is byte, word, long or quad sized. */ +#define emulate_2op_SrcV(_op, _src, _dst, _eflags) \ + __emulate_2op(_op, _src, _dst, _eflags, \ + "b", "q", "w", "r", _LO32, "r", "", "r") + +/* Source operand is word, long or quad sized. */ +#define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags) \ + __emulate_2op_nobyte(_op, _src, _dst, _eflags, \ + "w", "r", _LO32, "r", "", "r") + +/* Instruction has only one explicit operand (no source operand). */ +#define emulate_1op(_op, _dst, _eflags) \ + do { \ + unsigned long _tmp; \ + \ + switch ((_dst).bytes) { \ + case 1: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0", "3", "2") \ + _op"b %1; " \ + _POST_EFLAGS("0", "3", "2") \ + : "=m" (_eflags), "=m" ((_dst).val), \ + "=&r" (_tmp) \ + : "i" (EFLAGS_MASK)); \ + break; \ + case 2: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0", "3", "2") \ + _op"w %1; " \ + _POST_EFLAGS("0", "3", "2") \ + : "=m" (_eflags), "=m" ((_dst).val), \ + "=&r" (_tmp) \ + : "i" (EFLAGS_MASK)); \ + break; \ + case 4: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0", "3", "2") \ + _op"l %1; " \ + _POST_EFLAGS("0", "3", "2") \ + : "=m" (_eflags), "=m" ((_dst).val), \ + "=&r" (_tmp) \ + : "i" (EFLAGS_MASK)); \ + break; \ + case 8: \ + __emulate_1op_8byte(_op, _dst, _eflags); \ + break; \ + } \ + } while (0) + +/* Emulate an instruction with quadword operands (x86/64 only). */ +#if defined(CONFIG_X86_64) +#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy) \ + do { \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0", "4", "2") \ + _op"q %"_qx"3,%1; " \ + _POST_EFLAGS("0", "4", "2") \ + : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ + : _qy ((_src).val), "i" (EFLAGS_MASK)); \ + } while (0) + +#define __emulate_1op_8byte(_op, _dst, _eflags) \ + do { \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0", "3", "2") \ + _op"q %1; " \ + _POST_EFLAGS("0", "3", "2") \ + : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ + : "i" (EFLAGS_MASK)); \ + } while (0) + +#elif defined(__i386__) +#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy) +#define __emulate_1op_8byte(_op, _dst, _eflags) +#endif /* __i386__ */ + +/* Fetch next part of the instruction being emulated. */ +#define insn_fetch(_type, _size, _eip) \ +({ unsigned long _x; \ + rc = do_insn_fetch(ctxt, ops, (_eip), &_x, (_size)); \ + if (rc != 0) \ + goto done; \ + (_eip) += (_size); \ + (_type)_x; \ +}) + +static inline unsigned long ad_mask(struct decode_cache *c) +{ + return (1UL << (c->ad_bytes << 3)) - 1; +} + +/* Access/update address held in a register, based on addressing mode. */ +static inline unsigned long +address_mask(struct decode_cache *c, unsigned long reg) +{ + if (c->ad_bytes == sizeof(unsigned long)) + return reg; + else + return reg & ad_mask(c); +} + +static inline unsigned long +register_address(struct decode_cache *c, unsigned long base, unsigned long reg) +{ + return base + address_mask(c, reg); +} + +static inline void +register_address_increment(struct decode_cache *c, unsigned long *reg, int inc) +{ + if (c->ad_bytes == sizeof(unsigned long)) + *reg += inc; + else + *reg = (*reg & ~ad_mask(c)) | ((*reg + inc) & ad_mask(c)); +} + +static inline void jmp_rel(struct decode_cache *c, int rel) +{ + register_address_increment(c, &c->eip, rel); +} + +static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, + unsigned long linear, u8 *dest) +{ + struct fetch_cache *fc = &ctxt->decode.fetch; + int rc; + int size; + + if (linear < fc->start || linear >= fc->end) { + size = min(15UL, PAGE_SIZE - offset_in_page(linear)); + rc = ops->read_std(linear, fc->data, size, ctxt->vcpu); + if (rc) + return rc; + fc->start = linear; + fc->end = linear + size; + } + *dest = fc->data[linear - fc->start]; + return 0; +} + +static int do_insn_fetch(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, + unsigned long eip, void *dest, unsigned size) +{ + int rc = 0; + + /* x86 instructions are limited to 15 bytes. */ + if (eip + size - ctxt->decode.eip_orig > 15) + return X86EMUL_UNHANDLEABLE; + eip += ctxt->cs_base; + while (size--) { + rc = do_fetch_insn_byte(ctxt, ops, eip++, dest++); + if (rc) + return rc; + } + return 0; +} + +/* + * Given the 'reg' portion of a ModRM byte, and a register block, return a + * pointer into the block that addresses the relevant register. + * @highbyte_regs specifies whether to decode AH,CH,DH,BH. + */ +static void *decode_register(u8 modrm_reg, unsigned long *regs, + int highbyte_regs) +{ + void *p; + + p = ®s[modrm_reg]; + if (highbyte_regs && modrm_reg >= 4 && modrm_reg < 8) + p = (unsigned char *)®s[modrm_reg & 3] + 1; + return p; +} + +static int read_descriptor(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, + void *ptr, + u16 *size, unsigned long *address, int op_bytes) +{ + int rc; + + if (op_bytes == 2) + op_bytes = 3; + *address = 0; + rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, + ctxt->vcpu); + if (rc) + return rc; + rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, + ctxt->vcpu); + return rc; +} + +static int test_cc(unsigned int condition, unsigned int flags) +{ + int rc = 0; + + switch ((condition & 15) >> 1) { + case 0: /* o */ + rc |= (flags & EFLG_OF); + break; + case 1: /* b/c/nae */ + rc |= (flags & EFLG_CF); + break; + case 2: /* z/e */ + rc |= (flags & EFLG_ZF); + break; + case 3: /* be/na */ + rc |= (flags & (EFLG_CF|EFLG_ZF)); + break; + case 4: /* s */ + rc |= (flags & EFLG_SF); + break; + case 5: /* p/pe */ + rc |= (flags & EFLG_PF); + break; + case 7: /* le/ng */ + rc |= (flags & EFLG_ZF); + /* fall through */ + case 6: /* l/nge */ + rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF)); + break; + } + + /* Odd condition identifiers (lsb == 1) have inverted sense. */ + return (!!rc ^ (condition & 1)); +} + +static void decode_register_operand(struct operand *op, + struct decode_cache *c, + int inhibit_bytereg) +{ + unsigned reg = c->modrm_reg; + int highbyte_regs = c->rex_prefix == 0; + + if (!(c->d & ModRM)) + reg = (c->b & 7) | ((c->rex_prefix & 1) << 3); + op->type = OP_REG; + if ((c->d & ByteOp) && !inhibit_bytereg) { + op->ptr = decode_register(reg, c->regs, highbyte_regs); + op->val = *(u8 *)op->ptr; + op->bytes = 1; + } else { + op->ptr = decode_register(reg, c->regs, 0); + op->bytes = c->op_bytes; + switch (op->bytes) { + case 2: + op->val = *(u16 *)op->ptr; + break; + case 4: + op->val = *(u32 *)op->ptr; + break; + case 8: + op->val = *(u64 *) op->ptr; + break; + } + } + op->orig_val = op->val; +} + +static int decode_modrm(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops) +{ + struct decode_cache *c = &ctxt->decode; + u8 sib; + int index_reg = 0, base_reg = 0, scale, rip_relative = 0; + int rc = 0; + + if (c->rex_prefix) { + c->modrm_reg = (c->rex_prefix & 4) << 1; /* REX.R */ + index_reg = (c->rex_prefix & 2) << 2; /* REX.X */ + c->modrm_rm = base_reg = (c->rex_prefix & 1) << 3; /* REG.B */ + } + + c->modrm = insn_fetch(u8, 1, c->eip); + c->modrm_mod |= (c->modrm & 0xc0) >> 6; + c->modrm_reg |= (c->modrm & 0x38) >> 3; + c->modrm_rm |= (c->modrm & 0x07); + c->modrm_ea = 0; + c->use_modrm_ea = 1; + + if (c->modrm_mod == 3) { + c->modrm_val = *(unsigned long *) + decode_register(c->modrm_rm, c->regs, c->d & ByteOp); + return rc; + } + + if (c->ad_bytes == 2) { + unsigned bx = c->regs[VCPU_REGS_RBX]; + unsigned bp = c->regs[VCPU_REGS_RBP]; + unsigned si = c->regs[VCPU_REGS_RSI]; + unsigned di = c->regs[VCPU_REGS_RDI]; + + /* 16-bit ModR/M decode. */ + switch (c->modrm_mod) { + case 0: + if (c->modrm_rm == 6) + c->modrm_ea += insn_fetch(u16, 2, c->eip); + break; + case 1: + c->modrm_ea += insn_fetch(s8, 1, c->eip); + break; + case 2: + c->modrm_ea += insn_fetch(u16, 2, c->eip); + break; + } + switch (c->modrm_rm) { + case 0: + c->modrm_ea += bx + si; + break; + case 1: + c->modrm_ea += bx + di; + break; + case 2: + c->modrm_ea += bp + si; + break; + case 3: + c->modrm_ea += bp + di; + break; + case 4: + c->modrm_ea += si; + break; + case 5: + c->modrm_ea += di; + break; + case 6: + if (c->modrm_mod != 0) + c->modrm_ea += bp; + break; + case 7: + c->modrm_ea += bx; + break; + } + if (c->modrm_rm == 2 || c->modrm_rm == 3 || + (c->modrm_rm == 6 && c->modrm_mod != 0)) + if (!c->override_base) + c->override_base = &ctxt->ss_base; + c->modrm_ea = (u16)c->modrm_ea; + } else { + /* 32/64-bit ModR/M decode. */ + switch (c->modrm_rm) { + case 4: + case 12: + sib = insn_fetch(u8, 1, c->eip); + index_reg |= (sib >> 3) & 7; + base_reg |= sib & 7; + scale = sib >> 6; + + switch (base_reg) { + case 5: + if (c->modrm_mod != 0) + c->modrm_ea += c->regs[base_reg]; + else + c->modrm_ea += + insn_fetch(s32, 4, c->eip); + break; + default: + c->modrm_ea += c->regs[base_reg]; + } + switch (index_reg) { + case 4: + break; + default: + c->modrm_ea += c->regs[index_reg] << scale; + } + break; + case 5: + if (c->modrm_mod != 0) + c->modrm_ea += c->regs[c->modrm_rm]; + else if (ctxt->mode == X86EMUL_MODE_PROT64) + rip_relative = 1; + break; + default: + c->modrm_ea += c->regs[c->modrm_rm]; + break; + } + switch (c->modrm_mod) { + case 0: + if (c->modrm_rm == 5) + c->modrm_ea += insn_fetch(s32, 4, c->eip); + break; + case 1: + c->modrm_ea += insn_fetch(s8, 1, c->eip); + break; + case 2: + c->modrm_ea += insn_fetch(s32, 4, c->eip); + break; + } + } + if (rip_relative) { + c->modrm_ea += c->eip; + switch (c->d & SrcMask) { + case SrcImmByte: + c->modrm_ea += 1; + break; + case SrcImm: + if (c->d & ByteOp) + c->modrm_ea += 1; + else + if (c->op_bytes == 8) + c->modrm_ea += 4; + else + c->modrm_ea += c->op_bytes; + } + } +done: + return rc; +} + +static int decode_abs(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops) +{ + struct decode_cache *c = &ctxt->decode; + int rc = 0; + + switch (c->ad_bytes) { + case 2: + c->modrm_ea = insn_fetch(u16, 2, c->eip); + break; + case 4: + c->modrm_ea = insn_fetch(u32, 4, c->eip); + break; + case 8: + c->modrm_ea = insn_fetch(u64, 8, c->eip); + break; + } +done: + return rc; +} + +int +x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) +{ + struct decode_cache *c = &ctxt->decode; + int rc = 0; + int mode = ctxt->mode; + int def_op_bytes, def_ad_bytes, group; + + /* Shadow copy of register state. Committed on successful emulation. */ + + memset(c, 0, sizeof(struct decode_cache)); + c->eip = c->eip_orig = ctxt->vcpu->arch.rip; + memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs); + + switch (mode) { + case X86EMUL_MODE_REAL: + case X86EMUL_MODE_PROT16: + def_op_bytes = def_ad_bytes = 2; + break; + case X86EMUL_MODE_PROT32: + def_op_bytes = def_ad_bytes = 4; + break; +#ifdef CONFIG_X86_64 + case X86EMUL_MODE_PROT64: + def_op_bytes = 4; + def_ad_bytes = 8; + break; +#endif + default: + return -1; + } + + c->op_bytes = def_op_bytes; + c->ad_bytes = def_ad_bytes; + + /* Legacy prefixes. */ + for (;;) { + switch (c->b = insn_fetch(u8, 1, c->eip)) { + case 0x66: /* operand-size override */ + /* switch between 2/4 bytes */ + c->op_bytes = def_op_bytes ^ 6; + break; + case 0x67: /* address-size override */ + if (mode == X86EMUL_MODE_PROT64) + /* switch between 4/8 bytes */ + c->ad_bytes = def_ad_bytes ^ 12; + else + /* switch between 2/4 bytes */ + c->ad_bytes = def_ad_bytes ^ 6; + break; + case 0x2e: /* CS override */ + c->override_base = &ctxt->cs_base; + break; + case 0x3e: /* DS override */ + c->override_base = &ctxt->ds_base; + break; + case 0x26: /* ES override */ + c->override_base = &ctxt->es_base; + break; + case 0x64: /* FS override */ + c->override_base = &ctxt->fs_base; + break; + case 0x65: /* GS override */ + c->override_base = &ctxt->gs_base; + break; + case 0x36: /* SS override */ + c->override_base = &ctxt->ss_base; + break; + case 0x40 ... 0x4f: /* REX */ + if (mode != X86EMUL_MODE_PROT64) + goto done_prefixes; + c->rex_prefix = c->b; + continue; + case 0xf0: /* LOCK */ + c->lock_prefix = 1; + break; + case 0xf2: /* REPNE/REPNZ */ + c->rep_prefix = REPNE_PREFIX; + break; + case 0xf3: /* REP/REPE/REPZ */ + c->rep_prefix = REPE_PREFIX; + break; + default: + goto done_prefixes; + } + + /* Any legacy prefix after a REX prefix nullifies its effect. */ + + c->rex_prefix = 0; + } + +done_prefixes: + + /* REX prefix. */ + if (c->rex_prefix) + if (c->rex_prefix & 8) + c->op_bytes = 8; /* REX.W */ + + /* Opcode byte(s). */ + c->d = opcode_table[c->b]; + if (c->d == 0) { + /* Two-byte opcode? */ + if (c->b == 0x0f) { + c->twobyte = 1; + c->b = insn_fetch(u8, 1, c->eip); + c->d = twobyte_table[c->b]; + } + } + + if (c->d & Group) { + group = c->d & GroupMask; + c->modrm = insn_fetch(u8, 1, c->eip); + --c->eip; + + group = (group << 3) + ((c->modrm >> 3) & 7); + if ((c->d & GroupDual) && (c->modrm >> 6) == 3) + c->d = group2_table[group]; + else + c->d = group_table[group]; + } + + /* Unrecognised? */ + if (c->d == 0) { + DPRINTF("Cannot emulate %02x\n", c->b); + return -1; + } + + if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack)) + c->op_bytes = 8; + + /* ModRM and SIB bytes. */ + if (c->d & ModRM) + rc = decode_modrm(ctxt, ops); + else if (c->d & MemAbs) + rc = decode_abs(ctxt, ops); + if (rc) + goto done; + + if (!c->override_base) + c->override_base = &ctxt->ds_base; + if (mode == X86EMUL_MODE_PROT64 && + c->override_base != &ctxt->fs_base && + c->override_base != &ctxt->gs_base) + c->override_base = NULL; + + if (c->override_base) + c->modrm_ea += *c->override_base; + + if (c->ad_bytes != 8) + c->modrm_ea = (u32)c->modrm_ea; + /* + * Decode and fetch the source operand: register, memory + * or immediate. + */ + switch (c->d & SrcMask) { + case SrcNone: + break; + case SrcReg: + decode_register_operand(&c->src, c, 0); + break; + case SrcMem16: + c->src.bytes = 2; + goto srcmem_common; + case SrcMem32: + c->src.bytes = 4; + goto srcmem_common; + case SrcMem: + c->src.bytes = (c->d & ByteOp) ? 1 : + c->op_bytes; + /* Don't fetch the address for invlpg: it could be unmapped. */ + if (c->twobyte && c->b == 0x01 && c->modrm_reg == 7) + break; + srcmem_common: + /* + * For instructions with a ModR/M byte, switch to register + * access if Mod = 3. + */ + if ((c->d & ModRM) && c->modrm_mod == 3) { + c->src.type = OP_REG; + break; + } + c->src.type = OP_MEM; + break; + case SrcImm: + c->src.type = OP_IMM; + c->src.ptr = (unsigned long *)c->eip; + c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + if (c->src.bytes == 8) + c->src.bytes = 4; + /* NB. Immediates are sign-extended as necessary. */ + switch (c->src.bytes) { + case 1: + c->src.val = insn_fetch(s8, 1, c->eip); + break; + case 2: + c->src.val = insn_fetch(s16, 2, c->eip); + break; + case 4: + c->src.val = insn_fetch(s32, 4, c->eip); + break; + } + break; + case SrcImmByte: + c->src.type = OP_IMM; + c->src.ptr = (unsigned long *)c->eip; + c->src.bytes = 1; + c->src.val = insn_fetch(s8, 1, c->eip); + break; + } + + /* Decode and fetch the destination operand: register or memory. */ + switch (c->d & DstMask) { + case ImplicitOps: + /* Special instructions do their own operand decoding. */ + return 0; + case DstReg: + decode_register_operand(&c->dst, c, + c->twobyte && (c->b == 0xb6 || c->b == 0xb7)); + break; + case DstMem: + if ((c->d & ModRM) && c->modrm_mod == 3) { + c->dst.type = OP_REG; + break; + } + c->dst.type = OP_MEM; + break; + } + +done: + return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0; +} + +static inline void emulate_push(struct x86_emulate_ctxt *ctxt) +{ + struct decode_cache *c = &ctxt->decode; + + c->dst.type = OP_MEM; + c->dst.bytes = c->op_bytes; + c->dst.val = c->src.val; + register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes); + c->dst.ptr = (void *) register_address(c, ctxt->ss_base, + c->regs[VCPU_REGS_RSP]); +} + +static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops) +{ + struct decode_cache *c = &ctxt->decode; + int rc; + + rc = ops->read_std(register_address(c, ctxt->ss_base, + c->regs[VCPU_REGS_RSP]), + &c->dst.val, c->dst.bytes, ctxt->vcpu); + if (rc != 0) + return rc; + + register_address_increment(c, &c->regs[VCPU_REGS_RSP], c->dst.bytes); + + return 0; +} + +static inline void emulate_grp2(struct x86_emulate_ctxt *ctxt) +{ + struct decode_cache *c = &ctxt->decode; + switch (c->modrm_reg) { + case 0: /* rol */ + emulate_2op_SrcB("rol", c->src, c->dst, ctxt->eflags); + break; + case 1: /* ror */ + emulate_2op_SrcB("ror", c->src, c->dst, ctxt->eflags); + break; + case 2: /* rcl */ + emulate_2op_SrcB("rcl", c->src, c->dst, ctxt->eflags); + break; + case 3: /* rcr */ + emulate_2op_SrcB("rcr", c->src, c->dst, ctxt->eflags); + break; + case 4: /* sal/shl */ + case 6: /* sal/shl */ + emulate_2op_SrcB("sal", c->src, c->dst, ctxt->eflags); + break; + case 5: /* shr */ + emulate_2op_SrcB("shr", c->src, c->dst, ctxt->eflags); + break; + case 7: /* sar */ + emulate_2op_SrcB("sar", c->src, c->dst, ctxt->eflags); + break; + } +} + +static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops) +{ + struct decode_cache *c = &ctxt->decode; + int rc = 0; + + switch (c->modrm_reg) { + case 0 ... 1: /* test */ + emulate_2op_SrcV("test", c->src, c->dst, ctxt->eflags); + break; + case 2: /* not */ + c->dst.val = ~c->dst.val; + break; + case 3: /* neg */ + emulate_1op("neg", c->dst, ctxt->eflags); + break; + default: + DPRINTF("Cannot emulate %02x\n", c->b); + rc = X86EMUL_UNHANDLEABLE; + break; + } + return rc; +} + +static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops) +{ + struct decode_cache *c = &ctxt->decode; + + switch (c->modrm_reg) { + case 0: /* inc */ + emulate_1op("inc", c->dst, ctxt->eflags); + break; + case 1: /* dec */ + emulate_1op("dec", c->dst, ctxt->eflags); + break; + case 4: /* jmp abs */ + c->eip = c->src.val; + break; + case 6: /* push */ + emulate_push(ctxt); + break; + } + return 0; +} + +static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, + unsigned long memop) +{ + struct decode_cache *c = &ctxt->decode; + u64 old, new; + int rc; + + rc = ops->read_emulated(memop, &old, 8, ctxt->vcpu); + if (rc != 0) + return rc; + + if (((u32) (old >> 0) != (u32) c->regs[VCPU_REGS_RAX]) || + ((u32) (old >> 32) != (u32) c->regs[VCPU_REGS_RDX])) { + + c->regs[VCPU_REGS_RAX] = (u32) (old >> 0); + c->regs[VCPU_REGS_RDX] = (u32) (old >> 32); + ctxt->eflags &= ~EFLG_ZF; + + } else { + new = ((u64)c->regs[VCPU_REGS_RCX] << 32) | + (u32) c->regs[VCPU_REGS_RBX]; + + rc = ops->cmpxchg_emulated(memop, &old, &new, 8, ctxt->vcpu); + if (rc != 0) + return rc; + ctxt->eflags |= EFLG_ZF; + } + return 0; +} + +static inline int writeback(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops) +{ + int rc; + struct decode_cache *c = &ctxt->decode; + + switch (c->dst.type) { + case OP_REG: + /* The 4-byte case *is* correct: + * in 64-bit mode we zero-extend. + */ + switch (c->dst.bytes) { + case 1: + *(u8 *)c->dst.ptr = (u8)c->dst.val; + break; + case 2: + *(u16 *)c->dst.ptr = (u16)c->dst.val; + break; + case 4: + *c->dst.ptr = (u32)c->dst.val; + break; /* 64b: zero-ext */ + case 8: + *c->dst.ptr = c->dst.val; + break; + } + break; + case OP_MEM: + if (c->lock_prefix) + rc = ops->cmpxchg_emulated( + (unsigned long)c->dst.ptr, + &c->dst.orig_val, + &c->dst.val, + c->dst.bytes, + ctxt->vcpu); + else + rc = ops->write_emulated( + (unsigned long)c->dst.ptr, + &c->dst.val, + c->dst.bytes, + ctxt->vcpu); + if (rc != 0) + return rc; + break; + case OP_NONE: + /* no writeback */ + break; + default: + break; + } + return 0; +} + +int +x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) +{ + unsigned long memop = 0; + u64 msr_data; + unsigned long saved_eip = 0; + struct decode_cache *c = &ctxt->decode; + int rc = 0; + + /* Shadow copy of register state. Committed on successful emulation. + * NOTE: we can copy them from vcpu as x86_decode_insn() doesn't + * modify them. + */ + + memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs); + saved_eip = c->eip; + + if (((c->d & ModRM) && (c->modrm_mod != 3)) || (c->d & MemAbs)) + memop = c->modrm_ea; + + if (c->rep_prefix && (c->d & String)) { + /* All REP prefixes have the same first termination condition */ + if (c->regs[VCPU_REGS_RCX] == 0) { + ctxt->vcpu->arch.rip = c->eip; + goto done; + } + /* The second termination condition only applies for REPE + * and REPNE. Test if the repeat string operation prefix is + * REPE/REPZ or REPNE/REPNZ and if it's the case it tests the + * corresponding termination condition according to: + * - if REPE/REPZ and ZF = 0 then done + * - if REPNE/REPNZ and ZF = 1 then done + */ + if ((c->b == 0xa6) || (c->b == 0xa7) || + (c->b == 0xae) || (c->b == 0xaf)) { + if ((c->rep_prefix == REPE_PREFIX) && + ((ctxt->eflags & EFLG_ZF) == 0)) { + ctxt->vcpu->arch.rip = c->eip; + goto done; + } + if ((c->rep_prefix == REPNE_PREFIX) && + ((ctxt->eflags & EFLG_ZF) == EFLG_ZF)) { + ctxt->vcpu->arch.rip = c->eip; + goto done; + } + } + c->regs[VCPU_REGS_RCX]--; + c->eip = ctxt->vcpu->arch.rip; + } + + if (c->src.type == OP_MEM) { + c->src.ptr = (unsigned long *)memop; + c->src.val = 0; + rc = ops->read_emulated((unsigned long)c->src.ptr, + &c->src.val, + c->src.bytes, + ctxt->vcpu); + if (rc != 0) + goto done; + c->src.orig_val = c->src.val; + } + + if ((c->d & DstMask) == ImplicitOps) + goto special_insn; + + + if (c->dst.type == OP_MEM) { + c->dst.ptr = (unsigned long *)memop; + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->dst.val = 0; + if (c->d & BitOp) { + unsigned long mask = ~(c->dst.bytes * 8 - 1); + + c->dst.ptr = (void *)c->dst.ptr + + (c->src.val & mask) / 8; + } + if (!(c->d & Mov) && + /* optimisation - avoid slow emulated read */ + ((rc = ops->read_emulated((unsigned long)c->dst.ptr, + &c->dst.val, + c->dst.bytes, ctxt->vcpu)) != 0)) + goto done; + } + c->dst.orig_val = c->dst.val; + +special_insn: + + if (c->twobyte) + goto twobyte_insn; + + switch (c->b) { + case 0x00 ... 0x05: + add: /* add */ + emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags); + break; + case 0x08 ... 0x0d: + or: /* or */ + emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags); + break; + case 0x10 ... 0x15: + adc: /* adc */ + emulate_2op_SrcV("adc", c->src, c->dst, ctxt->eflags); + break; + case 0x18 ... 0x1d: + sbb: /* sbb */ + emulate_2op_SrcV("sbb", c->src, c->dst, ctxt->eflags); + break; + case 0x20 ... 0x23: + and: /* and */ + emulate_2op_SrcV("and", c->src, c->dst, ctxt->eflags); + break; + case 0x24: /* and al imm8 */ + c->dst.type = OP_REG; + c->dst.ptr = &c->regs[VCPU_REGS_RAX]; + c->dst.val = *(u8 *)c->dst.ptr; + c->dst.bytes = 1; + c->dst.orig_val = c->dst.val; + goto and; + case 0x25: /* and ax imm16, or eax imm32 */ + c->dst.type = OP_REG; + c->dst.bytes = c->op_bytes; + c->dst.ptr = &c->regs[VCPU_REGS_RAX]; + if (c->op_bytes == 2) + c->dst.val = *(u16 *)c->dst.ptr; + else + c->dst.val = *(u32 *)c->dst.ptr; + c->dst.orig_val = c->dst.val; + goto and; + case 0x28 ... 0x2d: + sub: /* sub */ + emulate_2op_SrcV("sub", c->src, c->dst, ctxt->eflags); + break; + case 0x30 ... 0x35: + xor: /* xor */ + emulate_2op_SrcV("xor", c->src, c->dst, ctxt->eflags); + break; + case 0x38 ... 0x3d: + cmp: /* cmp */ + emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags); + break; + case 0x40 ... 0x47: /* inc r16/r32 */ + emulate_1op("inc", c->dst, ctxt->eflags); + break; + case 0x48 ... 0x4f: /* dec r16/r32 */ + emulate_1op("dec", c->dst, ctxt->eflags); + break; + case 0x50 ... 0x57: /* push reg */ + c->dst.type = OP_MEM; + c->dst.bytes = c->op_bytes; + c->dst.val = c->src.val; + register_address_increment(c, &c->regs[VCPU_REGS_RSP], + -c->op_bytes); + c->dst.ptr = (void *) register_address( + c, ctxt->ss_base, c->regs[VCPU_REGS_RSP]); + break; + case 0x58 ... 0x5f: /* pop reg */ + pop_instruction: + if ((rc = ops->read_std(register_address(c, ctxt->ss_base, + c->regs[VCPU_REGS_RSP]), c->dst.ptr, + c->op_bytes, ctxt->vcpu)) != 0) + goto done; + + register_address_increment(c, &c->regs[VCPU_REGS_RSP], + c->op_bytes); + c->dst.type = OP_NONE; /* Disable writeback. */ + break; + case 0x63: /* movsxd */ + if (ctxt->mode != X86EMUL_MODE_PROT64) + goto cannot_emulate; + c->dst.val = (s32) c->src.val; + break; + case 0x6a: /* push imm8 */ + c->src.val = 0L; + c->src.val = insn_fetch(s8, 1, c->eip); + emulate_push(ctxt); + break; + case 0x6c: /* insb */ + case 0x6d: /* insw/insd */ + if (kvm_emulate_pio_string(ctxt->vcpu, NULL, + 1, + (c->d & ByteOp) ? 1 : c->op_bytes, + c->rep_prefix ? + address_mask(c, c->regs[VCPU_REGS_RCX]) : 1, + (ctxt->eflags & EFLG_DF), + register_address(c, ctxt->es_base, + c->regs[VCPU_REGS_RDI]), + c->rep_prefix, + c->regs[VCPU_REGS_RDX]) == 0) { + c->eip = saved_eip; + return -1; + } + return 0; + case 0x6e: /* outsb */ + case 0x6f: /* outsw/outsd */ + if (kvm_emulate_pio_string(ctxt->vcpu, NULL, + 0, + (c->d & ByteOp) ? 1 : c->op_bytes, + c->rep_prefix ? + address_mask(c, c->regs[VCPU_REGS_RCX]) : 1, + (ctxt->eflags & EFLG_DF), + register_address(c, c->override_base ? + *c->override_base : + ctxt->ds_base, + c->regs[VCPU_REGS_RSI]), + c->rep_prefix, + c->regs[VCPU_REGS_RDX]) == 0) { + c->eip = saved_eip; + return -1; + } + return 0; + case 0x70 ... 0x7f: /* jcc (short) */ { + int rel = insn_fetch(s8, 1, c->eip); + + if (test_cc(c->b, ctxt->eflags)) + jmp_rel(c, rel); + break; + } + case 0x80 ... 0x83: /* Grp1 */ + switch (c->modrm_reg) { + case 0: + goto add; + case 1: + goto or; + case 2: + goto adc; + case 3: + goto sbb; + case 4: + goto and; + case 5: + goto sub; + case 6: + goto xor; + case 7: + goto cmp; + } + break; + case 0x84 ... 0x85: + emulate_2op_SrcV("test", c->src, c->dst, ctxt->eflags); + break; + case 0x86 ... 0x87: /* xchg */ + /* Write back the register source. */ + switch (c->dst.bytes) { + case 1: + *(u8 *) c->src.ptr = (u8) c->dst.val; + break; + case 2: + *(u16 *) c->src.ptr = (u16) c->dst.val; + break; + case 4: + *c->src.ptr = (u32) c->dst.val; + break; /* 64b reg: zero-extend */ + case 8: + *c->src.ptr = c->dst.val; + break; + } + /* + * Write back the memory destination with implicit LOCK + * prefix. + */ + c->dst.val = c->src.val; + c->lock_prefix = 1; + break; + case 0x88 ... 0x8b: /* mov */ + goto mov; + case 0x8d: /* lea r16/r32, m */ + c->dst.val = c->modrm_val; + break; + case 0x8f: /* pop (sole member of Grp1a) */ + rc = emulate_grp1a(ctxt, ops); + if (rc != 0) + goto done; + break; + case 0x9c: /* pushf */ + c->src.val = (unsigned long) ctxt->eflags; + emulate_push(ctxt); + break; + case 0x9d: /* popf */ + c->dst.ptr = (unsigned long *) &ctxt->eflags; + goto pop_instruction; + case 0xa0 ... 0xa1: /* mov */ + c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX]; + c->dst.val = c->src.val; + break; + case 0xa2 ... 0xa3: /* mov */ + c->dst.val = (unsigned long)c->regs[VCPU_REGS_RAX]; + break; + case 0xa4 ... 0xa5: /* movs */ + c->dst.type = OP_MEM; + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->dst.ptr = (unsigned long *)register_address(c, + ctxt->es_base, + c->regs[VCPU_REGS_RDI]); + if ((rc = ops->read_emulated(register_address(c, + c->override_base ? *c->override_base : + ctxt->ds_base, + c->regs[VCPU_REGS_RSI]), + &c->dst.val, + c->dst.bytes, ctxt->vcpu)) != 0) + goto done; + register_address_increment(c, &c->regs[VCPU_REGS_RSI], + (ctxt->eflags & EFLG_DF) ? -c->dst.bytes + : c->dst.bytes); + register_address_increment(c, &c->regs[VCPU_REGS_RDI], + (ctxt->eflags & EFLG_DF) ? -c->dst.bytes + : c->dst.bytes); + break; + case 0xa6 ... 0xa7: /* cmps */ + c->src.type = OP_NONE; /* Disable writeback. */ + c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->src.ptr = (unsigned long *)register_address(c, + c->override_base ? *c->override_base : + ctxt->ds_base, + c->regs[VCPU_REGS_RSI]); + if ((rc = ops->read_emulated((unsigned long)c->src.ptr, + &c->src.val, + c->src.bytes, + ctxt->vcpu)) != 0) + goto done; + + c->dst.type = OP_NONE; /* Disable writeback. */ + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->dst.ptr = (unsigned long *)register_address(c, + ctxt->es_base, + c->regs[VCPU_REGS_RDI]); + if ((rc = ops->read_emulated((unsigned long)c->dst.ptr, + &c->dst.val, + c->dst.bytes, + ctxt->vcpu)) != 0) + goto done; + + DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr); + + emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags); + + register_address_increment(c, &c->regs[VCPU_REGS_RSI], + (ctxt->eflags & EFLG_DF) ? -c->src.bytes + : c->src.bytes); + register_address_increment(c, &c->regs[VCPU_REGS_RDI], + (ctxt->eflags & EFLG_DF) ? -c->dst.bytes + : c->dst.bytes); + + break; + case 0xaa ... 0xab: /* stos */ + c->dst.type = OP_MEM; + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->dst.ptr = (unsigned long *)register_address(c, + ctxt->es_base, + c->regs[VCPU_REGS_RDI]); + c->dst.val = c->regs[VCPU_REGS_RAX]; + register_address_increment(c, &c->regs[VCPU_REGS_RDI], + (ctxt->eflags & EFLG_DF) ? -c->dst.bytes + : c->dst.bytes); + break; + case 0xac ... 0xad: /* lods */ + c->dst.type = OP_REG; + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX]; + if ((rc = ops->read_emulated(register_address(c, + c->override_base ? *c->override_base : + ctxt->ds_base, + c->regs[VCPU_REGS_RSI]), + &c->dst.val, + c->dst.bytes, + ctxt->vcpu)) != 0) + goto done; + register_address_increment(c, &c->regs[VCPU_REGS_RSI], + (ctxt->eflags & EFLG_DF) ? -c->dst.bytes + : c->dst.bytes); + break; + case 0xae ... 0xaf: /* scas */ + DPRINTF("Urk! I don't handle SCAS.\n"); + goto cannot_emulate; + case 0xc0 ... 0xc1: + emulate_grp2(ctxt); + break; + case 0xc3: /* ret */ + c->dst.ptr = &c->eip; + goto pop_instruction; + case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */ + mov: + c->dst.val = c->src.val; + break; + case 0xd0 ... 0xd1: /* Grp2 */ + c->src.val = 1; + emulate_grp2(ctxt); + break; + case 0xd2 ... 0xd3: /* Grp2 */ + c->src.val = c->regs[VCPU_REGS_RCX]; + emulate_grp2(ctxt); + break; + case 0xe8: /* call (near) */ { + long int rel; + switch (c->op_bytes) { + case 2: + rel = insn_fetch(s16, 2, c->eip); + break; + case 4: + rel = insn_fetch(s32, 4, c->eip); + break; + default: + DPRINTF("Call: Invalid op_bytes\n"); + goto cannot_emulate; + } + c->src.val = (unsigned long) c->eip; + jmp_rel(c, rel); + c->op_bytes = c->ad_bytes; + emulate_push(ctxt); + break; + } + case 0xe9: /* jmp rel */ + case 0xeb: /* jmp rel short */ + jmp_rel(c, c->src.val); + c->dst.type = OP_NONE; /* Disable writeback. */ + break; + case 0xf4: /* hlt */ + ctxt->vcpu->arch.halt_request = 1; + goto done; + case 0xf5: /* cmc */ + /* complement carry flag from eflags reg */ + ctxt->eflags ^= EFLG_CF; + c->dst.type = OP_NONE; /* Disable writeback. */ + break; + case 0xf6 ... 0xf7: /* Grp3 */ + rc = emulate_grp3(ctxt, ops); + if (rc != 0) + goto done; + break; + case 0xf8: /* clc */ + ctxt->eflags &= ~EFLG_CF; + c->dst.type = OP_NONE; /* Disable writeback. */ + break; + case 0xfa: /* cli */ + ctxt->eflags &= ~X86_EFLAGS_IF; + c->dst.type = OP_NONE; /* Disable writeback. */ + break; + case 0xfb: /* sti */ + ctxt->eflags |= X86_EFLAGS_IF; + c->dst.type = OP_NONE; /* Disable writeback. */ + break; + case 0xfe ... 0xff: /* Grp4/Grp5 */ + rc = emulate_grp45(ctxt, ops); + if (rc != 0) + goto done; + break; + } + +writeback: + rc = writeback(ctxt, ops); + if (rc != 0) + goto done; + + /* Commit shadow register state. */ + memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs); + ctxt->vcpu->arch.rip = c->eip; + +done: + if (rc == X86EMUL_UNHANDLEABLE) { + c->eip = saved_eip; + return -1; + } + return 0; + +twobyte_insn: + switch (c->b) { + case 0x01: /* lgdt, lidt, lmsw */ + switch (c->modrm_reg) { + u16 size; + unsigned long address; + + case 0: /* vmcall */ + if (c->modrm_mod != 3 || c->modrm_rm != 1) + goto cannot_emulate; + + rc = kvm_fix_hypercall(ctxt->vcpu); + if (rc) + goto done; + + kvm_emulate_hypercall(ctxt->vcpu); + break; + case 2: /* lgdt */ + rc = read_descriptor(ctxt, ops, c->src.ptr, + &size, &address, c->op_bytes); + if (rc) + goto done; + realmode_lgdt(ctxt->vcpu, size, address); + break; + case 3: /* lidt/vmmcall */ + if (c->modrm_mod == 3 && c->modrm_rm == 1) { + rc = kvm_fix_hypercall(ctxt->vcpu); + if (rc) + goto done; + kvm_emulate_hypercall(ctxt->vcpu); + } else { + rc = read_descriptor(ctxt, ops, c->src.ptr, + &size, &address, + c->op_bytes); + if (rc) + goto done; + realmode_lidt(ctxt->vcpu, size, address); + } + break; + case 4: /* smsw */ + if (c->modrm_mod != 3) + goto cannot_emulate; + *(u16 *)&c->regs[c->modrm_rm] + = realmode_get_cr(ctxt->vcpu, 0); + break; + case 6: /* lmsw */ + if (c->modrm_mod != 3) + goto cannot_emulate; + realmode_lmsw(ctxt->vcpu, (u16)c->modrm_val, + &ctxt->eflags); + break; + case 7: /* invlpg*/ + emulate_invlpg(ctxt->vcpu, memop); + break; + default: + goto cannot_emulate; + } + /* Disable writeback. */ + c->dst.type = OP_NONE; + break; + case 0x06: + emulate_clts(ctxt->vcpu); + c->dst.type = OP_NONE; + break; + case 0x08: /* invd */ + case 0x09: /* wbinvd */ + case 0x0d: /* GrpP (prefetch) */ + case 0x18: /* Grp16 (prefetch/nop) */ + c->dst.type = OP_NONE; + break; + case 0x20: /* mov cr, reg */ + if (c->modrm_mod != 3) + goto cannot_emulate; + c->regs[c->modrm_rm] = + realmode_get_cr(ctxt->vcpu, c->modrm_reg); + c->dst.type = OP_NONE; /* no writeback */ + break; + case 0x21: /* mov from dr to reg */ + if (c->modrm_mod != 3) + goto cannot_emulate; + rc = emulator_get_dr(ctxt, c->modrm_reg, &c->regs[c->modrm_rm]); + if (rc) + goto cannot_emulate; + c->dst.type = OP_NONE; /* no writeback */ + break; + case 0x22: /* mov reg, cr */ + if (c->modrm_mod != 3) + goto cannot_emulate; + realmode_set_cr(ctxt->vcpu, + c->modrm_reg, c->modrm_val, &ctxt->eflags); + c->dst.type = OP_NONE; + break; + case 0x23: /* mov from reg to dr */ + if (c->modrm_mod != 3) + goto cannot_emulate; + rc = emulator_set_dr(ctxt, c->modrm_reg, + c->regs[c->modrm_rm]); + if (rc) + goto cannot_emulate; + c->dst.type = OP_NONE; /* no writeback */ + break; + case 0x30: + /* wrmsr */ + msr_data = (u32)c->regs[VCPU_REGS_RAX] + | ((u64)c->regs[VCPU_REGS_RDX] << 32); + rc = kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data); + if (rc) { + kvm_inject_gp(ctxt->vcpu, 0); + c->eip = ctxt->vcpu->arch.rip; + } + rc = X86EMUL_CONTINUE; + c->dst.type = OP_NONE; + break; + case 0x32: + /* rdmsr */ + rc = kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data); + if (rc) { + kvm_inject_gp(ctxt->vcpu, 0); + c->eip = ctxt->vcpu->arch.rip; + } else { + c->regs[VCPU_REGS_RAX] = (u32)msr_data; + c->regs[VCPU_REGS_RDX] = msr_data >> 32; + } + rc = X86EMUL_CONTINUE; + c->dst.type = OP_NONE; + break; + case 0x40 ... 0x4f: /* cmov */ + c->dst.val = c->dst.orig_val = c->src.val; + if (!test_cc(c->b, ctxt->eflags)) + c->dst.type = OP_NONE; /* no writeback */ + break; + case 0x80 ... 0x8f: /* jnz rel, etc*/ { + long int rel; + + switch (c->op_bytes) { + case 2: + rel = insn_fetch(s16, 2, c->eip); + break; + case 4: + rel = insn_fetch(s32, 4, c->eip); + break; + case 8: + rel = insn_fetch(s64, 8, c->eip); + break; + default: + DPRINTF("jnz: Invalid op_bytes\n"); + goto cannot_emulate; + } + if (test_cc(c->b, ctxt->eflags)) + jmp_rel(c, rel); + c->dst.type = OP_NONE; + break; + } + case 0xa3: + bt: /* bt */ + c->dst.type = OP_NONE; + /* only subword offset */ + c->src.val &= (c->dst.bytes << 3) - 1; + emulate_2op_SrcV_nobyte("bt", c->src, c->dst, ctxt->eflags); + break; + case 0xab: + bts: /* bts */ + /* only subword offset */ + c->src.val &= (c->dst.bytes << 3) - 1; + emulate_2op_SrcV_nobyte("bts", c->src, c->dst, ctxt->eflags); + break; + case 0xb0 ... 0xb1: /* cmpxchg */ + /* + * Save real source value, then compare EAX against + * destination. + */ + c->src.orig_val = c->src.val; + c->src.val = c->regs[VCPU_REGS_RAX]; + emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags); + if (ctxt->eflags & EFLG_ZF) { + /* Success: write back to memory. */ + c->dst.val = c->src.orig_val; + } else { + /* Failure: write the value we saw to EAX. */ + c->dst.type = OP_REG; + c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX]; + } + break; + case 0xb3: + btr: /* btr */ + /* only subword offset */ + c->src.val &= (c->dst.bytes << 3) - 1; + emulate_2op_SrcV_nobyte("btr", c->src, c->dst, ctxt->eflags); + break; + case 0xb6 ... 0xb7: /* movzx */ + c->dst.bytes = c->op_bytes; + c->dst.val = (c->d & ByteOp) ? (u8) c->src.val + : (u16) c->src.val; + break; + case 0xba: /* Grp8 */ + switch (c->modrm_reg & 3) { + case 0: + goto bt; + case 1: + goto bts; + case 2: + goto btr; + case 3: + goto btc; + } + break; + case 0xbb: + btc: /* btc */ + /* only subword offset */ + c->src.val &= (c->dst.bytes << 3) - 1; + emulate_2op_SrcV_nobyte("btc", c->src, c->dst, ctxt->eflags); + break; + case 0xbe ... 0xbf: /* movsx */ + c->dst.bytes = c->op_bytes; + c->dst.val = (c->d & ByteOp) ? (s8) c->src.val : + (s16) c->src.val; + break; + case 0xc3: /* movnti */ + c->dst.bytes = c->op_bytes; + c->dst.val = (c->op_bytes == 4) ? (u32) c->src.val : + (u64) c->src.val; + break; + case 0xc7: /* Grp9 (cmpxchg8b) */ + rc = emulate_grp9(ctxt, ops, memop); + if (rc != 0) + goto done; + c->dst.type = OP_NONE; + break; + } + goto writeback; + +cannot_emulate: + DPRINTF("Cannot emulate %02x\n", c->b); + c->eip = saved_eip; + return -1; +} --- linux-2.6.24.orig/arch/x86/kvm/vmx.h +++ linux-2.6.24/arch/x86/kvm/vmx.h @@ -0,0 +1,330 @@ +#ifndef VMX_H +#define VMX_H + +/* + * vmx.h: VMX Architecture related definitions + * Copyright (c) 2004, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * A few random additions are: + * Copyright (C) 2006 Qumranet + * Avi Kivity + * Yaniv Kamay + * + */ + +/* + * Definitions of Primary Processor-Based VM-Execution Controls. + */ +#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004 +#define CPU_BASED_USE_TSC_OFFSETING 0x00000008 +#define CPU_BASED_HLT_EXITING 0x00000080 +#define CPU_BASED_INVLPG_EXITING 0x00000200 +#define CPU_BASED_MWAIT_EXITING 0x00000400 +#define CPU_BASED_RDPMC_EXITING 0x00000800 +#define CPU_BASED_RDTSC_EXITING 0x00001000 +#define CPU_BASED_CR8_LOAD_EXITING 0x00080000 +#define CPU_BASED_CR8_STORE_EXITING 0x00100000 +#define CPU_BASED_TPR_SHADOW 0x00200000 +#define CPU_BASED_MOV_DR_EXITING 0x00800000 +#define CPU_BASED_UNCOND_IO_EXITING 0x01000000 +#define CPU_BASED_USE_IO_BITMAPS 0x02000000 +#define CPU_BASED_USE_MSR_BITMAPS 0x10000000 +#define CPU_BASED_MONITOR_EXITING 0x20000000 +#define CPU_BASED_PAUSE_EXITING 0x40000000 +#define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 0x80000000 +/* + * Definitions of Secondary Processor-Based VM-Execution Controls. + */ +#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 +#define SECONDARY_EXEC_ENABLE_VPID 0x00000020 +#define SECONDARY_EXEC_WBINVD_EXITING 0x00000040 + + +#define PIN_BASED_EXT_INTR_MASK 0x00000001 +#define PIN_BASED_NMI_EXITING 0x00000008 +#define PIN_BASED_VIRTUAL_NMIS 0x00000020 + +#define VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200 +#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 + +#define VM_ENTRY_IA32E_MODE 0x00000200 +#define VM_ENTRY_SMM 0x00000400 +#define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800 + +/* VMCS Encodings */ +enum vmcs_field { + VIRTUAL_PROCESSOR_ID = 0x00000000, + GUEST_ES_SELECTOR = 0x00000800, + GUEST_CS_SELECTOR = 0x00000802, + GUEST_SS_SELECTOR = 0x00000804, + GUEST_DS_SELECTOR = 0x00000806, + GUEST_FS_SELECTOR = 0x00000808, + GUEST_GS_SELECTOR = 0x0000080a, + GUEST_LDTR_SELECTOR = 0x0000080c, + GUEST_TR_SELECTOR = 0x0000080e, + HOST_ES_SELECTOR = 0x00000c00, + HOST_CS_SELECTOR = 0x00000c02, + HOST_SS_SELECTOR = 0x00000c04, + HOST_DS_SELECTOR = 0x00000c06, + HOST_FS_SELECTOR = 0x00000c08, + HOST_GS_SELECTOR = 0x00000c0a, + HOST_TR_SELECTOR = 0x00000c0c, + IO_BITMAP_A = 0x00002000, + IO_BITMAP_A_HIGH = 0x00002001, + IO_BITMAP_B = 0x00002002, + IO_BITMAP_B_HIGH = 0x00002003, + MSR_BITMAP = 0x00002004, + MSR_BITMAP_HIGH = 0x00002005, + VM_EXIT_MSR_STORE_ADDR = 0x00002006, + VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007, + VM_EXIT_MSR_LOAD_ADDR = 0x00002008, + VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009, + VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a, + VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b, + TSC_OFFSET = 0x00002010, + TSC_OFFSET_HIGH = 0x00002011, + VIRTUAL_APIC_PAGE_ADDR = 0x00002012, + VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013, + APIC_ACCESS_ADDR = 0x00002014, + APIC_ACCESS_ADDR_HIGH = 0x00002015, + VMCS_LINK_POINTER = 0x00002800, + VMCS_LINK_POINTER_HIGH = 0x00002801, + GUEST_IA32_DEBUGCTL = 0x00002802, + GUEST_IA32_DEBUGCTL_HIGH = 0x00002803, + PIN_BASED_VM_EXEC_CONTROL = 0x00004000, + CPU_BASED_VM_EXEC_CONTROL = 0x00004002, + EXCEPTION_BITMAP = 0x00004004, + PAGE_FAULT_ERROR_CODE_MASK = 0x00004006, + PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008, + CR3_TARGET_COUNT = 0x0000400a, + VM_EXIT_CONTROLS = 0x0000400c, + VM_EXIT_MSR_STORE_COUNT = 0x0000400e, + VM_EXIT_MSR_LOAD_COUNT = 0x00004010, + VM_ENTRY_CONTROLS = 0x00004012, + VM_ENTRY_MSR_LOAD_COUNT = 0x00004014, + VM_ENTRY_INTR_INFO_FIELD = 0x00004016, + VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018, + VM_ENTRY_INSTRUCTION_LEN = 0x0000401a, + TPR_THRESHOLD = 0x0000401c, + SECONDARY_VM_EXEC_CONTROL = 0x0000401e, + VM_INSTRUCTION_ERROR = 0x00004400, + VM_EXIT_REASON = 0x00004402, + VM_EXIT_INTR_INFO = 0x00004404, + VM_EXIT_INTR_ERROR_CODE = 0x00004406, + IDT_VECTORING_INFO_FIELD = 0x00004408, + IDT_VECTORING_ERROR_CODE = 0x0000440a, + VM_EXIT_INSTRUCTION_LEN = 0x0000440c, + VMX_INSTRUCTION_INFO = 0x0000440e, + GUEST_ES_LIMIT = 0x00004800, + GUEST_CS_LIMIT = 0x00004802, + GUEST_SS_LIMIT = 0x00004804, + GUEST_DS_LIMIT = 0x00004806, + GUEST_FS_LIMIT = 0x00004808, + GUEST_GS_LIMIT = 0x0000480a, + GUEST_LDTR_LIMIT = 0x0000480c, + GUEST_TR_LIMIT = 0x0000480e, + GUEST_GDTR_LIMIT = 0x00004810, + GUEST_IDTR_LIMIT = 0x00004812, + GUEST_ES_AR_BYTES = 0x00004814, + GUEST_CS_AR_BYTES = 0x00004816, + GUEST_SS_AR_BYTES = 0x00004818, + GUEST_DS_AR_BYTES = 0x0000481a, + GUEST_FS_AR_BYTES = 0x0000481c, + GUEST_GS_AR_BYTES = 0x0000481e, + GUEST_LDTR_AR_BYTES = 0x00004820, + GUEST_TR_AR_BYTES = 0x00004822, + GUEST_INTERRUPTIBILITY_INFO = 0x00004824, + GUEST_ACTIVITY_STATE = 0X00004826, + GUEST_SYSENTER_CS = 0x0000482A, + HOST_IA32_SYSENTER_CS = 0x00004c00, + CR0_GUEST_HOST_MASK = 0x00006000, + CR4_GUEST_HOST_MASK = 0x00006002, + CR0_READ_SHADOW = 0x00006004, + CR4_READ_SHADOW = 0x00006006, + CR3_TARGET_VALUE0 = 0x00006008, + CR3_TARGET_VALUE1 = 0x0000600a, + CR3_TARGET_VALUE2 = 0x0000600c, + CR3_TARGET_VALUE3 = 0x0000600e, + EXIT_QUALIFICATION = 0x00006400, + GUEST_LINEAR_ADDRESS = 0x0000640a, + GUEST_CR0 = 0x00006800, + GUEST_CR3 = 0x00006802, + GUEST_CR4 = 0x00006804, + GUEST_ES_BASE = 0x00006806, + GUEST_CS_BASE = 0x00006808, + GUEST_SS_BASE = 0x0000680a, + GUEST_DS_BASE = 0x0000680c, + GUEST_FS_BASE = 0x0000680e, + GUEST_GS_BASE = 0x00006810, + GUEST_LDTR_BASE = 0x00006812, + GUEST_TR_BASE = 0x00006814, + GUEST_GDTR_BASE = 0x00006816, + GUEST_IDTR_BASE = 0x00006818, + GUEST_DR7 = 0x0000681a, + GUEST_RSP = 0x0000681c, + GUEST_RIP = 0x0000681e, + GUEST_RFLAGS = 0x00006820, + GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822, + GUEST_SYSENTER_ESP = 0x00006824, + GUEST_SYSENTER_EIP = 0x00006826, + HOST_CR0 = 0x00006c00, + HOST_CR3 = 0x00006c02, + HOST_CR4 = 0x00006c04, + HOST_FS_BASE = 0x00006c06, + HOST_GS_BASE = 0x00006c08, + HOST_TR_BASE = 0x00006c0a, + HOST_GDTR_BASE = 0x00006c0c, + HOST_IDTR_BASE = 0x00006c0e, + HOST_IA32_SYSENTER_ESP = 0x00006c10, + HOST_IA32_SYSENTER_EIP = 0x00006c12, + HOST_RSP = 0x00006c14, + HOST_RIP = 0x00006c16, +}; + +#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 + +#define EXIT_REASON_EXCEPTION_NMI 0 +#define EXIT_REASON_EXTERNAL_INTERRUPT 1 +#define EXIT_REASON_TRIPLE_FAULT 2 + +#define EXIT_REASON_PENDING_INTERRUPT 7 + +#define EXIT_REASON_TASK_SWITCH 9 +#define EXIT_REASON_CPUID 10 +#define EXIT_REASON_HLT 12 +#define EXIT_REASON_INVLPG 14 +#define EXIT_REASON_RDPMC 15 +#define EXIT_REASON_RDTSC 16 +#define EXIT_REASON_VMCALL 18 +#define EXIT_REASON_VMCLEAR 19 +#define EXIT_REASON_VMLAUNCH 20 +#define EXIT_REASON_VMPTRLD 21 +#define EXIT_REASON_VMPTRST 22 +#define EXIT_REASON_VMREAD 23 +#define EXIT_REASON_VMRESUME 24 +#define EXIT_REASON_VMWRITE 25 +#define EXIT_REASON_VMOFF 26 +#define EXIT_REASON_VMON 27 +#define EXIT_REASON_CR_ACCESS 28 +#define EXIT_REASON_DR_ACCESS 29 +#define EXIT_REASON_IO_INSTRUCTION 30 +#define EXIT_REASON_MSR_READ 31 +#define EXIT_REASON_MSR_WRITE 32 +#define EXIT_REASON_MWAIT_INSTRUCTION 36 +#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 +#define EXIT_REASON_APIC_ACCESS 44 +#define EXIT_REASON_WBINVD 54 + +/* + * Interruption-information format + */ +#define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */ +#define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */ +#define INTR_INFO_DELIVER_CODE_MASK 0x800 /* 11 */ +#define INTR_INFO_VALID_MASK 0x80000000 /* 31 */ + +#define VECTORING_INFO_VECTOR_MASK INTR_INFO_VECTOR_MASK +#define VECTORING_INFO_TYPE_MASK INTR_INFO_INTR_TYPE_MASK +#define VECTORING_INFO_DELIVER_CODE_MASK INTR_INFO_DELIVER_CODE_MASK +#define VECTORING_INFO_VALID_MASK INTR_INFO_VALID_MASK + +#define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */ +#define INTR_TYPE_EXCEPTION (3 << 8) /* processor exception */ +#define INTR_TYPE_SOFT_INTR (4 << 8) /* software interrupt */ + +/* + * Exit Qualifications for MOV for Control Register Access + */ +#define CONTROL_REG_ACCESS_NUM 0x7 /* 2:0, number of control reg.*/ +#define CONTROL_REG_ACCESS_TYPE 0x30 /* 5:4, access type */ +#define CONTROL_REG_ACCESS_REG 0xf00 /* 10:8, general purpose reg. */ +#define LMSW_SOURCE_DATA_SHIFT 16 +#define LMSW_SOURCE_DATA (0xFFFF << LMSW_SOURCE_DATA_SHIFT) /* 16:31 lmsw source */ +#define REG_EAX (0 << 8) +#define REG_ECX (1 << 8) +#define REG_EDX (2 << 8) +#define REG_EBX (3 << 8) +#define REG_ESP (4 << 8) +#define REG_EBP (5 << 8) +#define REG_ESI (6 << 8) +#define REG_EDI (7 << 8) +#define REG_R8 (8 << 8) +#define REG_R9 (9 << 8) +#define REG_R10 (10 << 8) +#define REG_R11 (11 << 8) +#define REG_R12 (12 << 8) +#define REG_R13 (13 << 8) +#define REG_R14 (14 << 8) +#define REG_R15 (15 << 8) + +/* + * Exit Qualifications for MOV for Debug Register Access + */ +#define DEBUG_REG_ACCESS_NUM 0x7 /* 2:0, number of debug reg. */ +#define DEBUG_REG_ACCESS_TYPE 0x10 /* 4, direction of access */ +#define TYPE_MOV_TO_DR (0 << 4) +#define TYPE_MOV_FROM_DR (1 << 4) +#define DEBUG_REG_ACCESS_REG 0xf00 /* 11:8, general purpose reg. */ + + +/* segment AR */ +#define SEGMENT_AR_L_MASK (1 << 13) + +#define AR_TYPE_ACCESSES_MASK 1 +#define AR_TYPE_READABLE_MASK (1 << 1) +#define AR_TYPE_WRITEABLE_MASK (1 << 2) +#define AR_TYPE_CODE_MASK (1 << 3) +#define AR_TYPE_MASK 0x0f +#define AR_TYPE_BUSY_64_TSS 11 +#define AR_TYPE_BUSY_32_TSS 11 +#define AR_TYPE_BUSY_16_TSS 3 +#define AR_TYPE_LDT 2 + +#define AR_UNUSABLE_MASK (1 << 16) +#define AR_S_MASK (1 << 4) +#define AR_P_MASK (1 << 7) +#define AR_L_MASK (1 << 13) +#define AR_DB_MASK (1 << 14) +#define AR_G_MASK (1 << 15) +#define AR_DPL_SHIFT 5 +#define AR_DPL(ar) (((ar) >> AR_DPL_SHIFT) & 3) + +#define AR_RESERVD_MASK 0xfffe0f00 + +#define MSR_IA32_VMX_BASIC 0x480 +#define MSR_IA32_VMX_PINBASED_CTLS 0x481 +#define MSR_IA32_VMX_PROCBASED_CTLS 0x482 +#define MSR_IA32_VMX_EXIT_CTLS 0x483 +#define MSR_IA32_VMX_ENTRY_CTLS 0x484 +#define MSR_IA32_VMX_MISC 0x485 +#define MSR_IA32_VMX_CR0_FIXED0 0x486 +#define MSR_IA32_VMX_CR0_FIXED1 0x487 +#define MSR_IA32_VMX_CR4_FIXED0 0x488 +#define MSR_IA32_VMX_CR4_FIXED1 0x489 +#define MSR_IA32_VMX_VMCS_ENUM 0x48a +#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48b + +#define MSR_IA32_FEATURE_CONTROL 0x3a +#define MSR_IA32_FEATURE_CONTROL_LOCKED 0x1 +#define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED 0x4 + +#define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT 9 + +#define VMX_NR_VPIDS (1 << 16) +#define VMX_VPID_EXTENT_SINGLE_CONTEXT 1 +#define VMX_VPID_EXTENT_ALL_CONTEXT 2 + +#endif --- linux-2.6.24.orig/arch/x86/kvm/vmx.c +++ linux-2.6.24/arch/x86/kvm/vmx.c @@ -0,0 +1,2765 @@ +/* + * Kernel-based Virtual Machine driver for Linux + * + * This module enables machines with Intel VT-x extensions to run virtual + * machines without emulation or binary translation. + * + * Copyright (C) 2006 Qumranet, Inc. + * + * Authors: + * Avi Kivity + * Yaniv Kamay + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "irq.h" +#include "vmx.h" +#include "segment_descriptor.h" +#include "mmu.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Qumranet"); +MODULE_LICENSE("GPL"); + +static int bypass_guest_pf = 1; +module_param(bypass_guest_pf, bool, 0); + +static int enable_vpid = 1; +module_param(enable_vpid, bool, 0); + +struct vmcs { + u32 revision_id; + u32 abort; + char data[0]; +}; + +struct vcpu_vmx { + struct kvm_vcpu vcpu; + int launched; + u8 fail; + u32 idt_vectoring_info; + struct kvm_msr_entry *guest_msrs; + struct kvm_msr_entry *host_msrs; + int nmsrs; + int save_nmsrs; + int msr_offset_efer; +#ifdef CONFIG_X86_64 + int msr_offset_kernel_gs_base; +#endif + struct vmcs *vmcs; + struct { + int loaded; + u16 fs_sel, gs_sel, ldt_sel; + int gs_ldt_reload_needed; + int fs_reload_needed; + int guest_efer_loaded; + } host_state; + struct { + struct { + bool pending; + u8 vector; + unsigned rip; + } irq; + } rmode; + int vpid; +}; + +static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) +{ + return container_of(vcpu, struct vcpu_vmx, vcpu); +} + +static int init_rmode_tss(struct kvm *kvm); + +static DEFINE_PER_CPU(struct vmcs *, vmxarea); +static DEFINE_PER_CPU(struct vmcs *, current_vmcs); + +static struct page *vmx_io_bitmap_a; +static struct page *vmx_io_bitmap_b; + +static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS); +static DEFINE_SPINLOCK(vmx_vpid_lock); + +static struct vmcs_config { + int size; + int order; + u32 revision_id; + u32 pin_based_exec_ctrl; + u32 cpu_based_exec_ctrl; + u32 cpu_based_2nd_exec_ctrl; + u32 vmexit_ctrl; + u32 vmentry_ctrl; +} vmcs_config; + +#define VMX_SEGMENT_FIELD(seg) \ + [VCPU_SREG_##seg] = { \ + .selector = GUEST_##seg##_SELECTOR, \ + .base = GUEST_##seg##_BASE, \ + .limit = GUEST_##seg##_LIMIT, \ + .ar_bytes = GUEST_##seg##_AR_BYTES, \ + } + +static struct kvm_vmx_segment_field { + unsigned selector; + unsigned base; + unsigned limit; + unsigned ar_bytes; +} kvm_vmx_segment_fields[] = { + VMX_SEGMENT_FIELD(CS), + VMX_SEGMENT_FIELD(DS), + VMX_SEGMENT_FIELD(ES), + VMX_SEGMENT_FIELD(FS), + VMX_SEGMENT_FIELD(GS), + VMX_SEGMENT_FIELD(SS), + VMX_SEGMENT_FIELD(TR), + VMX_SEGMENT_FIELD(LDTR), +}; + +/* + * Keep MSR_K6_STAR at the end, as setup_msrs() will try to optimize it + * away by decrementing the array size. + */ +static const u32 vmx_msr_index[] = { +#ifdef CONFIG_X86_64 + MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, MSR_KERNEL_GS_BASE, +#endif + MSR_EFER, MSR_K6_STAR, +}; +#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index) + +static void load_msrs(struct kvm_msr_entry *e, int n) +{ + int i; + + for (i = 0; i < n; ++i) + wrmsrl(e[i].index, e[i].data); +} + +static void save_msrs(struct kvm_msr_entry *e, int n) +{ + int i; + + for (i = 0; i < n; ++i) + rdmsrl(e[i].index, e[i].data); +} + +static inline int is_page_fault(u32 intr_info) +{ + return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | + INTR_INFO_VALID_MASK)) == + (INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK); +} + +static inline int is_no_device(u32 intr_info) +{ + return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | + INTR_INFO_VALID_MASK)) == + (INTR_TYPE_EXCEPTION | NM_VECTOR | INTR_INFO_VALID_MASK); +} + +static inline int is_invalid_opcode(u32 intr_info) +{ + return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | + INTR_INFO_VALID_MASK)) == + (INTR_TYPE_EXCEPTION | UD_VECTOR | INTR_INFO_VALID_MASK); +} + +static inline int is_external_interrupt(u32 intr_info) +{ + return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) + == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); +} + +static inline int cpu_has_vmx_tpr_shadow(void) +{ + return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW); +} + +static inline int vm_need_tpr_shadow(struct kvm *kvm) +{ + return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm))); +} + +static inline int cpu_has_secondary_exec_ctrls(void) +{ + return (vmcs_config.cpu_based_exec_ctrl & + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS); +} + +static inline bool cpu_has_vmx_virtualize_apic_accesses(void) +{ + return (vmcs_config.cpu_based_2nd_exec_ctrl & + SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES); +} + +static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm) +{ + return ((cpu_has_vmx_virtualize_apic_accesses()) && + (irqchip_in_kernel(kvm))); +} + +static inline int cpu_has_vmx_vpid(void) +{ + return (vmcs_config.cpu_based_2nd_exec_ctrl & + SECONDARY_EXEC_ENABLE_VPID); +} + +static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) +{ + int i; + + for (i = 0; i < vmx->nmsrs; ++i) + if (vmx->guest_msrs[i].index == msr) + return i; + return -1; +} + +static inline void __invvpid(int ext, u16 vpid, gva_t gva) +{ + struct { + u64 vpid : 16; + u64 rsvd : 48; + u64 gva; + } operand = { vpid, 0, gva }; + + asm volatile (ASM_VMX_INVVPID + /* CF==1 or ZF==1 --> rc = -1 */ + "; ja 1f ; ud2 ; 1:" + : : "a"(&operand), "c"(ext) : "cc", "memory"); +} + +static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr) +{ + int i; + + i = __find_msr_index(vmx, msr); + if (i >= 0) + return &vmx->guest_msrs[i]; + return NULL; +} + +static void vmcs_clear(struct vmcs *vmcs) +{ + u64 phys_addr = __pa(vmcs); + u8 error; + + asm volatile (ASM_VMX_VMCLEAR_RAX "; setna %0" + : "=g"(error) : "a"(&phys_addr), "m"(phys_addr) + : "cc", "memory"); + if (error) + printk(KERN_ERR "kvm: vmclear fail: %p/%llx\n", + vmcs, phys_addr); +} + +static void __vcpu_clear(void *arg) +{ + struct vcpu_vmx *vmx = arg; + int cpu = raw_smp_processor_id(); + + if (vmx->vcpu.cpu == cpu) + vmcs_clear(vmx->vmcs); + if (per_cpu(current_vmcs, cpu) == vmx->vmcs) + per_cpu(current_vmcs, cpu) = NULL; + rdtscll(vmx->vcpu.arch.host_tsc); +} + +static void vcpu_clear(struct vcpu_vmx *vmx) +{ + if (vmx->vcpu.cpu == -1) + return; + smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 0, 1); + vmx->launched = 0; +} + +static inline void vpid_sync_vcpu_all(struct vcpu_vmx *vmx) +{ + if (vmx->vpid == 0) + return; + + __invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vmx->vpid, 0); +} + +static unsigned long vmcs_readl(unsigned long field) +{ + unsigned long value; + + asm volatile (ASM_VMX_VMREAD_RDX_RAX + : "=a"(value) : "d"(field) : "cc"); + return value; +} + +static u16 vmcs_read16(unsigned long field) +{ + return vmcs_readl(field); +} + +static u32 vmcs_read32(unsigned long field) +{ + return vmcs_readl(field); +} + +static u64 vmcs_read64(unsigned long field) +{ +#ifdef CONFIG_X86_64 + return vmcs_readl(field); +#else + return vmcs_readl(field) | ((u64)vmcs_readl(field+1) << 32); +#endif +} + +static noinline void vmwrite_error(unsigned long field, unsigned long value) +{ + printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n", + field, value, vmcs_read32(VM_INSTRUCTION_ERROR)); + dump_stack(); +} + +static void vmcs_writel(unsigned long field, unsigned long value) +{ + u8 error; + + asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0" + : "=q"(error) : "a"(value), "d"(field) : "cc"); + if (unlikely(error)) + vmwrite_error(field, value); +} + +static void vmcs_write16(unsigned long field, u16 value) +{ + vmcs_writel(field, value); +} + +static void vmcs_write32(unsigned long field, u32 value) +{ + vmcs_writel(field, value); +} + +static void vmcs_write64(unsigned long field, u64 value) +{ +#ifdef CONFIG_X86_64 + vmcs_writel(field, value); +#else + vmcs_writel(field, value); + asm volatile (""); + vmcs_writel(field+1, value >> 32); +#endif +} + +static void vmcs_clear_bits(unsigned long field, u32 mask) +{ + vmcs_writel(field, vmcs_readl(field) & ~mask); +} + +static void vmcs_set_bits(unsigned long field, u32 mask) +{ + vmcs_writel(field, vmcs_readl(field) | mask); +} + +static void update_exception_bitmap(struct kvm_vcpu *vcpu) +{ + u32 eb; + + eb = (1u << PF_VECTOR) | (1u << UD_VECTOR); + if (!vcpu->fpu_active) + eb |= 1u << NM_VECTOR; + if (vcpu->guest_debug.enabled) + eb |= 1u << 1; + if (vcpu->arch.rmode.active) + eb = ~0; + vmcs_write32(EXCEPTION_BITMAP, eb); +} + +static void reload_tss(void) +{ + /* + * VT restores TR but not its size. Useless. + */ + struct descriptor_table gdt; + struct segment_descriptor *descs; + + get_gdt(&gdt); + descs = (void *)gdt.base; + descs[GDT_ENTRY_TSS].type = 9; /* available TSS */ + load_TR_desc(); +} + +static void load_transition_efer(struct vcpu_vmx *vmx) +{ + int efer_offset = vmx->msr_offset_efer; + u64 host_efer = vmx->host_msrs[efer_offset].data; + u64 guest_efer = vmx->guest_msrs[efer_offset].data; + u64 ignore_bits; + + if (efer_offset < 0) + return; + /* + * NX is emulated; LMA and LME handled by hardware; SCE meaninless + * outside long mode + */ + ignore_bits = EFER_NX | EFER_SCE; +#ifdef CONFIG_X86_64 + ignore_bits |= EFER_LMA | EFER_LME; + /* SCE is meaningful only in long mode on Intel */ + if (guest_efer & EFER_LMA) + ignore_bits &= ~(u64)EFER_SCE; +#endif + if ((guest_efer & ~ignore_bits) == (host_efer & ~ignore_bits)) + return; + + vmx->host_state.guest_efer_loaded = 1; + guest_efer &= ~ignore_bits; + guest_efer |= host_efer & ignore_bits; + wrmsrl(MSR_EFER, guest_efer); + vmx->vcpu.stat.efer_reload++; +} + +static void reload_host_efer(struct vcpu_vmx *vmx) +{ + if (vmx->host_state.guest_efer_loaded) { + vmx->host_state.guest_efer_loaded = 0; + load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1); + } +} + +static void vmx_save_host_state(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + if (vmx->host_state.loaded) + return; + + vmx->host_state.loaded = 1; + /* + * Set host fs and gs selectors. Unfortunately, 22.2.3 does not + * allow segment selectors with cpl > 0 or ti == 1. + */ + vmx->host_state.ldt_sel = read_ldt(); + vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel; + vmx->host_state.fs_sel = read_fs(); + if (!(vmx->host_state.fs_sel & 7)) { + vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel); + vmx->host_state.fs_reload_needed = 0; + } else { + vmcs_write16(HOST_FS_SELECTOR, 0); + vmx->host_state.fs_reload_needed = 1; + } + vmx->host_state.gs_sel = read_gs(); + if (!(vmx->host_state.gs_sel & 7)) + vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel); + else { + vmcs_write16(HOST_GS_SELECTOR, 0); + vmx->host_state.gs_ldt_reload_needed = 1; + } + +#ifdef CONFIG_X86_64 + vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE)); + vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE)); +#else + vmcs_writel(HOST_FS_BASE, segment_base(vmx->host_state.fs_sel)); + vmcs_writel(HOST_GS_BASE, segment_base(vmx->host_state.gs_sel)); +#endif + +#ifdef CONFIG_X86_64 + if (is_long_mode(&vmx->vcpu)) + save_msrs(vmx->host_msrs + + vmx->msr_offset_kernel_gs_base, 1); + +#endif + load_msrs(vmx->guest_msrs, vmx->save_nmsrs); + load_transition_efer(vmx); +} + +static void vmx_load_host_state(struct vcpu_vmx *vmx) +{ + unsigned long flags; + + if (!vmx->host_state.loaded) + return; + + ++vmx->vcpu.stat.host_state_reload; + vmx->host_state.loaded = 0; + if (vmx->host_state.fs_reload_needed) + load_fs(vmx->host_state.fs_sel); + if (vmx->host_state.gs_ldt_reload_needed) { + load_ldt(vmx->host_state.ldt_sel); + /* + * If we have to reload gs, we must take care to + * preserve our gs base. + */ + local_irq_save(flags); + load_gs(vmx->host_state.gs_sel); +#ifdef CONFIG_X86_64 + wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE)); +#endif + local_irq_restore(flags); + } + reload_tss(); + save_msrs(vmx->guest_msrs, vmx->save_nmsrs); + load_msrs(vmx->host_msrs, vmx->save_nmsrs); + reload_host_efer(vmx); +} + +/* + * Switches to specified vcpu, until a matching vcpu_put(), but assumes + * vcpu mutex is already taken. + */ +static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + u64 phys_addr = __pa(vmx->vmcs); + u64 tsc_this, delta; + + if (vcpu->cpu != cpu) { + vcpu_clear(vmx); + kvm_migrate_apic_timer(vcpu); + vpid_sync_vcpu_all(vmx); + } + + if (per_cpu(current_vmcs, cpu) != vmx->vmcs) { + u8 error; + + per_cpu(current_vmcs, cpu) = vmx->vmcs; + asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0" + : "=g"(error) : "a"(&phys_addr), "m"(phys_addr) + : "cc"); + if (error) + printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n", + vmx->vmcs, phys_addr); + } + + if (vcpu->cpu != cpu) { + struct descriptor_table dt; + unsigned long sysenter_esp; + + vcpu->cpu = cpu; + /* + * Linux uses per-cpu TSS and GDT, so set these when switching + * processors. + */ + vmcs_writel(HOST_TR_BASE, read_tr_base()); /* 22.2.4 */ + get_gdt(&dt); + vmcs_writel(HOST_GDTR_BASE, dt.base); /* 22.2.4 */ + + rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp); + vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */ + + /* + * Make sure the time stamp counter is monotonous. + */ + rdtscll(tsc_this); + delta = vcpu->arch.host_tsc - tsc_this; + vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta); + } +} + +static void vmx_vcpu_put(struct kvm_vcpu *vcpu) +{ + vmx_load_host_state(to_vmx(vcpu)); +} + +static void vmx_fpu_activate(struct kvm_vcpu *vcpu) +{ + if (vcpu->fpu_active) + return; + vcpu->fpu_active = 1; + vmcs_clear_bits(GUEST_CR0, X86_CR0_TS); + if (vcpu->arch.cr0 & X86_CR0_TS) + vmcs_set_bits(GUEST_CR0, X86_CR0_TS); + update_exception_bitmap(vcpu); +} + +static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu) +{ + if (!vcpu->fpu_active) + return; + vcpu->fpu_active = 0; + vmcs_set_bits(GUEST_CR0, X86_CR0_TS); + update_exception_bitmap(vcpu); +} + +static void vmx_vcpu_decache(struct kvm_vcpu *vcpu) +{ + vcpu_clear(to_vmx(vcpu)); +} + +static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) +{ + return vmcs_readl(GUEST_RFLAGS); +} + +static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) +{ + if (vcpu->arch.rmode.active) + rflags |= IOPL_MASK | X86_EFLAGS_VM; + vmcs_writel(GUEST_RFLAGS, rflags); +} + +static void skip_emulated_instruction(struct kvm_vcpu *vcpu) +{ + unsigned long rip; + u32 interruptibility; + + rip = vmcs_readl(GUEST_RIP); + rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN); + vmcs_writel(GUEST_RIP, rip); + + /* + * We emulated an instruction, so temporary interrupt blocking + * should be removed, if set. + */ + interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); + if (interruptibility & 3) + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, + interruptibility & ~3); + vcpu->arch.interrupt_window_open = 1; +} + +static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, + bool has_error_code, u32 error_code) +{ + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + nr | INTR_TYPE_EXCEPTION + | (has_error_code ? INTR_INFO_DELIVER_CODE_MASK : 0) + | INTR_INFO_VALID_MASK); + if (has_error_code) + vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code); +} + +static bool vmx_exception_injected(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + return !(vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK); +} + +/* + * Swap MSR entry in host/guest MSR entry array. + */ +#ifdef CONFIG_X86_64 +static void move_msr_up(struct vcpu_vmx *vmx, int from, int to) +{ + struct kvm_msr_entry tmp; + + tmp = vmx->guest_msrs[to]; + vmx->guest_msrs[to] = vmx->guest_msrs[from]; + vmx->guest_msrs[from] = tmp; + tmp = vmx->host_msrs[to]; + vmx->host_msrs[to] = vmx->host_msrs[from]; + vmx->host_msrs[from] = tmp; +} +#endif + +/* + * Set up the vmcs to automatically save and restore system + * msrs. Don't touch the 64-bit msrs if the guest is in legacy + * mode, as fiddling with msrs is very expensive. + */ +static void setup_msrs(struct vcpu_vmx *vmx) +{ + int save_nmsrs; + + save_nmsrs = 0; +#ifdef CONFIG_X86_64 + if (is_long_mode(&vmx->vcpu)) { + int index; + + index = __find_msr_index(vmx, MSR_SYSCALL_MASK); + if (index >= 0) + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_LSTAR); + if (index >= 0) + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_CSTAR); + if (index >= 0) + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_KERNEL_GS_BASE); + if (index >= 0) + move_msr_up(vmx, index, save_nmsrs++); + /* + * MSR_K6_STAR is only needed on long mode guests, and only + * if efer.sce is enabled. + */ + index = __find_msr_index(vmx, MSR_K6_STAR); + if ((index >= 0) && (vmx->vcpu.arch.shadow_efer & EFER_SCE)) + move_msr_up(vmx, index, save_nmsrs++); + } +#endif + vmx->save_nmsrs = save_nmsrs; + +#ifdef CONFIG_X86_64 + vmx->msr_offset_kernel_gs_base = + __find_msr_index(vmx, MSR_KERNEL_GS_BASE); +#endif + vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER); +} + +/* + * reads and returns guest's timestamp counter "register" + * guest_tsc = host_tsc + tsc_offset -- 21.3 + */ +static u64 guest_read_tsc(void) +{ + u64 host_tsc, tsc_offset; + + rdtscll(host_tsc); + tsc_offset = vmcs_read64(TSC_OFFSET); + return host_tsc + tsc_offset; +} + +/* + * writes 'guest_tsc' into guest's timestamp counter "register" + * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc + */ +static void guest_write_tsc(u64 guest_tsc) +{ + u64 host_tsc; + + rdtscll(host_tsc); + vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc); +} + +/* + * Reads an msr value (of 'msr_index') into 'pdata'. + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. + */ +static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) +{ + u64 data; + struct kvm_msr_entry *msr; + + if (!pdata) { + printk(KERN_ERR "BUG: get_msr called with NULL pdata\n"); + return -EINVAL; + } + + switch (msr_index) { +#ifdef CONFIG_X86_64 + case MSR_FS_BASE: + data = vmcs_readl(GUEST_FS_BASE); + break; + case MSR_GS_BASE: + data = vmcs_readl(GUEST_GS_BASE); + break; + case MSR_EFER: + return kvm_get_msr_common(vcpu, msr_index, pdata); +#endif + case MSR_IA32_TIME_STAMP_COUNTER: + data = guest_read_tsc(); + break; + case MSR_IA32_SYSENTER_CS: + data = vmcs_read32(GUEST_SYSENTER_CS); + break; + case MSR_IA32_SYSENTER_EIP: + data = vmcs_readl(GUEST_SYSENTER_EIP); + break; + case MSR_IA32_SYSENTER_ESP: + data = vmcs_readl(GUEST_SYSENTER_ESP); + break; + default: + msr = find_msr_entry(to_vmx(vcpu), msr_index); + if (msr) { + data = msr->data; + break; + } + return kvm_get_msr_common(vcpu, msr_index, pdata); + } + + *pdata = data; + return 0; +} + +/* + * Writes msr value into into the appropriate "register". + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. + */ +static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct kvm_msr_entry *msr; + int ret = 0; + + switch (msr_index) { + case MSR_EFER: + ret = kvm_set_msr_common(vcpu, msr_index, data); + if (vmx->host_state.loaded) { + reload_host_efer(vmx); + load_transition_efer(vmx); + } + break; +#ifdef CONFIG_X86_64 + case MSR_FS_BASE: + vmcs_writel(GUEST_FS_BASE, data); + break; + case MSR_GS_BASE: + vmcs_writel(GUEST_GS_BASE, data); + break; +#endif + case MSR_IA32_SYSENTER_CS: + vmcs_write32(GUEST_SYSENTER_CS, data); + break; + case MSR_IA32_SYSENTER_EIP: + vmcs_writel(GUEST_SYSENTER_EIP, data); + break; + case MSR_IA32_SYSENTER_ESP: + vmcs_writel(GUEST_SYSENTER_ESP, data); + break; + case MSR_IA32_TIME_STAMP_COUNTER: + guest_write_tsc(data); + break; + default: + msr = find_msr_entry(vmx, msr_index); + if (msr) { + msr->data = data; + if (vmx->host_state.loaded) + load_msrs(vmx->guest_msrs, vmx->save_nmsrs); + break; + } + ret = kvm_set_msr_common(vcpu, msr_index, data); + } + + return ret; +} + +/* + * Sync the rsp and rip registers into the vcpu structure. This allows + * registers to be accessed by indexing vcpu->arch.regs. + */ +static void vcpu_load_rsp_rip(struct kvm_vcpu *vcpu) +{ + vcpu->arch.regs[VCPU_REGS_RSP] = vmcs_readl(GUEST_RSP); + vcpu->arch.rip = vmcs_readl(GUEST_RIP); +} + +/* + * Syncs rsp and rip back into the vmcs. Should be called after possible + * modification. + */ +static void vcpu_put_rsp_rip(struct kvm_vcpu *vcpu) +{ + vmcs_writel(GUEST_RSP, vcpu->arch.regs[VCPU_REGS_RSP]); + vmcs_writel(GUEST_RIP, vcpu->arch.rip); +} + +static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) +{ + unsigned long dr7 = 0x400; + int old_singlestep; + + old_singlestep = vcpu->guest_debug.singlestep; + + vcpu->guest_debug.enabled = dbg->enabled; + if (vcpu->guest_debug.enabled) { + int i; + + dr7 |= 0x200; /* exact */ + for (i = 0; i < 4; ++i) { + if (!dbg->breakpoints[i].enabled) + continue; + vcpu->guest_debug.bp[i] = dbg->breakpoints[i].address; + dr7 |= 2 << (i*2); /* global enable */ + dr7 |= 0 << (i*4+16); /* execution breakpoint */ + } + + vcpu->guest_debug.singlestep = dbg->singlestep; + } else + vcpu->guest_debug.singlestep = 0; + + if (old_singlestep && !vcpu->guest_debug.singlestep) { + unsigned long flags; + + flags = vmcs_readl(GUEST_RFLAGS); + flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF); + vmcs_writel(GUEST_RFLAGS, flags); + } + + update_exception_bitmap(vcpu); + vmcs_writel(GUEST_DR7, dr7); + + return 0; +} + +static int vmx_get_irq(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + u32 idtv_info_field; + + idtv_info_field = vmx->idt_vectoring_info; + if (idtv_info_field & INTR_INFO_VALID_MASK) { + if (is_external_interrupt(idtv_info_field)) + return idtv_info_field & VECTORING_INFO_VECTOR_MASK; + else + printk(KERN_DEBUG "pending exception: not handled yet\n"); + } + return -1; +} + +static __init int cpu_has_kvm_support(void) +{ + unsigned long ecx = cpuid_ecx(1); + return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */ +} + +static __init int vmx_disabled_by_bios(void) +{ + u64 msr; + + rdmsrl(MSR_IA32_FEATURE_CONTROL, msr); + return (msr & (MSR_IA32_FEATURE_CONTROL_LOCKED | + MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) + == MSR_IA32_FEATURE_CONTROL_LOCKED; + /* locked but not enabled */ +} + +static void hardware_enable(void *garbage) +{ + int cpu = raw_smp_processor_id(); + u64 phys_addr = __pa(per_cpu(vmxarea, cpu)); + u64 old; + + rdmsrl(MSR_IA32_FEATURE_CONTROL, old); + if ((old & (MSR_IA32_FEATURE_CONTROL_LOCKED | + MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) + != (MSR_IA32_FEATURE_CONTROL_LOCKED | + MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) + /* enable and lock */ + wrmsrl(MSR_IA32_FEATURE_CONTROL, old | + MSR_IA32_FEATURE_CONTROL_LOCKED | + MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED); + write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */ + asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr) + : "memory", "cc"); +} + +static void hardware_disable(void *garbage) +{ + asm volatile (ASM_VMX_VMXOFF : : : "cc"); + write_cr4(read_cr4() & ~X86_CR4_VMXE); +} + +static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, + u32 msr, u32 *result) +{ + u32 vmx_msr_low, vmx_msr_high; + u32 ctl = ctl_min | ctl_opt; + + rdmsr(msr, vmx_msr_low, vmx_msr_high); + + ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */ + ctl |= vmx_msr_low; /* bit == 1 in low word ==> must be one */ + + /* Ensure minimum (required) set of control bits are supported. */ + if (ctl_min & ~ctl) + return -EIO; + + *result = ctl; + return 0; +} + +static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) +{ + u32 vmx_msr_low, vmx_msr_high; + u32 min, opt; + u32 _pin_based_exec_control = 0; + u32 _cpu_based_exec_control = 0; + u32 _cpu_based_2nd_exec_control = 0; + u32 _vmexit_control = 0; + u32 _vmentry_control = 0; + + min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; + opt = 0; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, + &_pin_based_exec_control) < 0) + return -EIO; + + min = CPU_BASED_HLT_EXITING | +#ifdef CONFIG_X86_64 + CPU_BASED_CR8_LOAD_EXITING | + CPU_BASED_CR8_STORE_EXITING | +#endif + CPU_BASED_USE_IO_BITMAPS | + CPU_BASED_MOV_DR_EXITING | + CPU_BASED_USE_TSC_OFFSETING; + opt = CPU_BASED_TPR_SHADOW | + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, + &_cpu_based_exec_control) < 0) + return -EIO; +#ifdef CONFIG_X86_64 + if ((_cpu_based_exec_control & CPU_BASED_TPR_SHADOW)) + _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING & + ~CPU_BASED_CR8_STORE_EXITING; +#endif + if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) { + min = 0; + opt = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | + SECONDARY_EXEC_WBINVD_EXITING | + SECONDARY_EXEC_ENABLE_VPID; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS2, + &_cpu_based_2nd_exec_control) < 0) + return -EIO; + } +#ifndef CONFIG_X86_64 + if (!(_cpu_based_2nd_exec_control & + SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) + _cpu_based_exec_control &= ~CPU_BASED_TPR_SHADOW; +#endif + + min = 0; +#ifdef CONFIG_X86_64 + min |= VM_EXIT_HOST_ADDR_SPACE_SIZE; +#endif + opt = 0; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS, + &_vmexit_control) < 0) + return -EIO; + + min = opt = 0; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS, + &_vmentry_control) < 0) + return -EIO; + + rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high); + + /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ + if ((vmx_msr_high & 0x1fff) > PAGE_SIZE) + return -EIO; + +#ifdef CONFIG_X86_64 + /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */ + if (vmx_msr_high & (1u<<16)) + return -EIO; +#endif + + /* Require Write-Back (WB) memory type for VMCS accesses. */ + if (((vmx_msr_high >> 18) & 15) != 6) + return -EIO; + + vmcs_conf->size = vmx_msr_high & 0x1fff; + vmcs_conf->order = get_order(vmcs_config.size); + vmcs_conf->revision_id = vmx_msr_low; + + vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control; + vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control; + vmcs_conf->cpu_based_2nd_exec_ctrl = _cpu_based_2nd_exec_control; + vmcs_conf->vmexit_ctrl = _vmexit_control; + vmcs_conf->vmentry_ctrl = _vmentry_control; + + return 0; +} + +static struct vmcs *alloc_vmcs_cpu(int cpu) +{ + int node = cpu_to_node(cpu); + struct page *pages; + struct vmcs *vmcs; + + pages = alloc_pages_node(node, GFP_KERNEL, vmcs_config.order); + if (!pages) + return NULL; + vmcs = page_address(pages); + memset(vmcs, 0, vmcs_config.size); + vmcs->revision_id = vmcs_config.revision_id; /* vmcs revision id */ + return vmcs; +} + +static struct vmcs *alloc_vmcs(void) +{ + return alloc_vmcs_cpu(raw_smp_processor_id()); +} + +static void free_vmcs(struct vmcs *vmcs) +{ + free_pages((unsigned long)vmcs, vmcs_config.order); +} + +static void free_kvm_area(void) +{ + int cpu; + + for_each_online_cpu(cpu) + free_vmcs(per_cpu(vmxarea, cpu)); +} + +static __init int alloc_kvm_area(void) +{ + int cpu; + + for_each_online_cpu(cpu) { + struct vmcs *vmcs; + + vmcs = alloc_vmcs_cpu(cpu); + if (!vmcs) { + free_kvm_area(); + return -ENOMEM; + } + + per_cpu(vmxarea, cpu) = vmcs; + } + return 0; +} + +static __init int hardware_setup(void) +{ + if (setup_vmcs_config(&vmcs_config) < 0) + return -EIO; + + if (boot_cpu_has(X86_FEATURE_NX)) + kvm_enable_efer_bits(EFER_NX); + + return alloc_kvm_area(); +} + +static __exit void hardware_unsetup(void) +{ + free_kvm_area(); +} + +static void fix_pmode_dataseg(int seg, struct kvm_save_segment *save) +{ + struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + + if (vmcs_readl(sf->base) == save->base && (save->base & AR_S_MASK)) { + vmcs_write16(sf->selector, save->selector); + vmcs_writel(sf->base, save->base); + vmcs_write32(sf->limit, save->limit); + vmcs_write32(sf->ar_bytes, save->ar); + } else { + u32 dpl = (vmcs_read16(sf->selector) & SELECTOR_RPL_MASK) + << AR_DPL_SHIFT; + vmcs_write32(sf->ar_bytes, 0x93 | dpl); + } +} + +static void enter_pmode(struct kvm_vcpu *vcpu) +{ + unsigned long flags; + + vcpu->arch.rmode.active = 0; + + vmcs_writel(GUEST_TR_BASE, vcpu->arch.rmode.tr.base); + vmcs_write32(GUEST_TR_LIMIT, vcpu->arch.rmode.tr.limit); + vmcs_write32(GUEST_TR_AR_BYTES, vcpu->arch.rmode.tr.ar); + + flags = vmcs_readl(GUEST_RFLAGS); + flags &= ~(IOPL_MASK | X86_EFLAGS_VM); + flags |= (vcpu->arch.rmode.save_iopl << IOPL_SHIFT); + vmcs_writel(GUEST_RFLAGS, flags); + + vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) | + (vmcs_readl(CR4_READ_SHADOW) & X86_CR4_VME)); + + update_exception_bitmap(vcpu); + + fix_pmode_dataseg(VCPU_SREG_ES, &vcpu->arch.rmode.es); + fix_pmode_dataseg(VCPU_SREG_DS, &vcpu->arch.rmode.ds); + fix_pmode_dataseg(VCPU_SREG_GS, &vcpu->arch.rmode.gs); + fix_pmode_dataseg(VCPU_SREG_FS, &vcpu->arch.rmode.fs); + + vmcs_write16(GUEST_SS_SELECTOR, 0); + vmcs_write32(GUEST_SS_AR_BYTES, 0x93); + + vmcs_write16(GUEST_CS_SELECTOR, + vmcs_read16(GUEST_CS_SELECTOR) & ~SELECTOR_RPL_MASK); + vmcs_write32(GUEST_CS_AR_BYTES, 0x9b); +} + +static gva_t rmode_tss_base(struct kvm *kvm) +{ + if (!kvm->arch.tss_addr) { + gfn_t base_gfn = kvm->memslots[0].base_gfn + + kvm->memslots[0].npages - 3; + return base_gfn << PAGE_SHIFT; + } + return kvm->arch.tss_addr; +} + +static void fix_rmode_seg(int seg, struct kvm_save_segment *save) +{ + struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + + save->selector = vmcs_read16(sf->selector); + save->base = vmcs_readl(sf->base); + save->limit = vmcs_read32(sf->limit); + save->ar = vmcs_read32(sf->ar_bytes); + vmcs_write16(sf->selector, save->base >> 4); + vmcs_write32(sf->base, save->base & 0xfffff); + vmcs_write32(sf->limit, 0xffff); + vmcs_write32(sf->ar_bytes, 0xf3); +} + +static void enter_rmode(struct kvm_vcpu *vcpu) +{ + unsigned long flags; + + vcpu->arch.rmode.active = 1; + + vcpu->arch.rmode.tr.base = vmcs_readl(GUEST_TR_BASE); + vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm)); + + vcpu->arch.rmode.tr.limit = vmcs_read32(GUEST_TR_LIMIT); + vmcs_write32(GUEST_TR_LIMIT, RMODE_TSS_SIZE - 1); + + vcpu->arch.rmode.tr.ar = vmcs_read32(GUEST_TR_AR_BYTES); + vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); + + flags = vmcs_readl(GUEST_RFLAGS); + vcpu->arch.rmode.save_iopl = (flags & IOPL_MASK) >> IOPL_SHIFT; + + flags |= IOPL_MASK | X86_EFLAGS_VM; + + vmcs_writel(GUEST_RFLAGS, flags); + vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME); + update_exception_bitmap(vcpu); + + vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4); + vmcs_write32(GUEST_SS_LIMIT, 0xffff); + vmcs_write32(GUEST_SS_AR_BYTES, 0xf3); + + vmcs_write32(GUEST_CS_AR_BYTES, 0xf3); + vmcs_write32(GUEST_CS_LIMIT, 0xffff); + if (vmcs_readl(GUEST_CS_BASE) == 0xffff0000) + vmcs_writel(GUEST_CS_BASE, 0xf0000); + vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4); + + fix_rmode_seg(VCPU_SREG_ES, &vcpu->arch.rmode.es); + fix_rmode_seg(VCPU_SREG_DS, &vcpu->arch.rmode.ds); + fix_rmode_seg(VCPU_SREG_GS, &vcpu->arch.rmode.gs); + fix_rmode_seg(VCPU_SREG_FS, &vcpu->arch.rmode.fs); + + kvm_mmu_reset_context(vcpu); + init_rmode_tss(vcpu->kvm); +} + +#ifdef CONFIG_X86_64 + +static void enter_lmode(struct kvm_vcpu *vcpu) +{ + u32 guest_tr_ar; + + guest_tr_ar = vmcs_read32(GUEST_TR_AR_BYTES); + if ((guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) { + printk(KERN_DEBUG "%s: tss fixup for long mode. \n", + __FUNCTION__); + vmcs_write32(GUEST_TR_AR_BYTES, + (guest_tr_ar & ~AR_TYPE_MASK) + | AR_TYPE_BUSY_64_TSS); + } + + vcpu->arch.shadow_efer |= EFER_LMA; + + find_msr_entry(to_vmx(vcpu), MSR_EFER)->data |= EFER_LMA | EFER_LME; + vmcs_write32(VM_ENTRY_CONTROLS, + vmcs_read32(VM_ENTRY_CONTROLS) + | VM_ENTRY_IA32E_MODE); +} + +static void exit_lmode(struct kvm_vcpu *vcpu) +{ + vcpu->arch.shadow_efer &= ~EFER_LMA; + + vmcs_write32(VM_ENTRY_CONTROLS, + vmcs_read32(VM_ENTRY_CONTROLS) + & ~VM_ENTRY_IA32E_MODE); +} + +#endif + +static void vmx_flush_tlb(struct kvm_vcpu *vcpu) +{ + vpid_sync_vcpu_all(to_vmx(vcpu)); +} + +static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) +{ + vcpu->arch.cr4 &= KVM_GUEST_CR4_MASK; + vcpu->arch.cr4 |= vmcs_readl(GUEST_CR4) & ~KVM_GUEST_CR4_MASK; +} + +static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) +{ + vmx_fpu_deactivate(vcpu); + + if (vcpu->arch.rmode.active && (cr0 & X86_CR0_PE)) + enter_pmode(vcpu); + + if (!vcpu->arch.rmode.active && !(cr0 & X86_CR0_PE)) + enter_rmode(vcpu); + +#ifdef CONFIG_X86_64 + if (vcpu->arch.shadow_efer & EFER_LME) { + if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) + enter_lmode(vcpu); + if (is_paging(vcpu) && !(cr0 & X86_CR0_PG)) + exit_lmode(vcpu); + } +#endif + + vmcs_writel(CR0_READ_SHADOW, cr0); + vmcs_writel(GUEST_CR0, + (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON); + vcpu->arch.cr0 = cr0; + + if (!(cr0 & X86_CR0_TS) || !(cr0 & X86_CR0_PE)) + vmx_fpu_activate(vcpu); +} + +static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) +{ + vmx_flush_tlb(vcpu); + vmcs_writel(GUEST_CR3, cr3); + if (vcpu->arch.cr0 & X86_CR0_PE) + vmx_fpu_deactivate(vcpu); +} + +static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) +{ + vmcs_writel(CR4_READ_SHADOW, cr4); + vmcs_writel(GUEST_CR4, cr4 | (vcpu->arch.rmode.active ? + KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON)); + vcpu->arch.cr4 = cr4; +} + +static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER); + + vcpu->arch.shadow_efer = efer; + if (!msr) + return; + if (efer & EFER_LMA) { + vmcs_write32(VM_ENTRY_CONTROLS, + vmcs_read32(VM_ENTRY_CONTROLS) | + VM_ENTRY_IA32E_MODE); + msr->data = efer; + + } else { + vmcs_write32(VM_ENTRY_CONTROLS, + vmcs_read32(VM_ENTRY_CONTROLS) & + ~VM_ENTRY_IA32E_MODE); + + msr->data = efer & ~EFER_LME; + } + setup_msrs(vmx); +} + +static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg) +{ + struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + + return vmcs_readl(sf->base); +} + +static void vmx_get_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) +{ + struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + u32 ar; + + var->base = vmcs_readl(sf->base); + var->limit = vmcs_read32(sf->limit); + var->selector = vmcs_read16(sf->selector); + ar = vmcs_read32(sf->ar_bytes); + if (ar & AR_UNUSABLE_MASK) + ar = 0; + var->type = ar & 15; + var->s = (ar >> 4) & 1; + var->dpl = (ar >> 5) & 3; + var->present = (ar >> 7) & 1; + var->avl = (ar >> 12) & 1; + var->l = (ar >> 13) & 1; + var->db = (ar >> 14) & 1; + var->g = (ar >> 15) & 1; + var->unusable = (ar >> 16) & 1; +} + +static int vmx_get_cpl(struct kvm_vcpu *vcpu) +{ + struct kvm_segment kvm_seg; + + if (!(vcpu->arch.cr0 & X86_CR0_PE)) /* if real mode */ + return 0; + + if (vmx_get_rflags(vcpu) & X86_EFLAGS_VM) /* if virtual 8086 */ + return 3; + + vmx_get_segment(vcpu, &kvm_seg, VCPU_SREG_CS); + return kvm_seg.selector & 3; +} + +static u32 vmx_segment_access_rights(struct kvm_segment *var) +{ + u32 ar; + + if (var->unusable) + ar = 1 << 16; + else { + ar = var->type & 15; + ar |= (var->s & 1) << 4; + ar |= (var->dpl & 3) << 5; + ar |= (var->present & 1) << 7; + ar |= (var->avl & 1) << 12; + ar |= (var->l & 1) << 13; + ar |= (var->db & 1) << 14; + ar |= (var->g & 1) << 15; + } + if (ar == 0) /* a 0 value means unusable */ + ar = AR_UNUSABLE_MASK; + + return ar; +} + +static void vmx_set_segment(struct kvm_vcpu *vcpu, + struct kvm_segment *var, int seg) +{ + struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + u32 ar; + + if (vcpu->arch.rmode.active && seg == VCPU_SREG_TR) { + vcpu->arch.rmode.tr.selector = var->selector; + vcpu->arch.rmode.tr.base = var->base; + vcpu->arch.rmode.tr.limit = var->limit; + vcpu->arch.rmode.tr.ar = vmx_segment_access_rights(var); + return; + } + vmcs_writel(sf->base, var->base); + vmcs_write32(sf->limit, var->limit); + vmcs_write16(sf->selector, var->selector); + if (vcpu->arch.rmode.active && var->s) { + /* + * Hack real-mode segments into vm86 compatibility. + */ + if (var->base == 0xffff0000 && var->selector == 0xf000) + vmcs_writel(sf->base, 0xf0000); + ar = 0xf3; + } else + ar = vmx_segment_access_rights(var); + vmcs_write32(sf->ar_bytes, ar); +} + +static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) +{ + u32 ar = vmcs_read32(GUEST_CS_AR_BYTES); + + *db = (ar >> 14) & 1; + *l = (ar >> 13) & 1; +} + +static void vmx_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + dt->limit = vmcs_read32(GUEST_IDTR_LIMIT); + dt->base = vmcs_readl(GUEST_IDTR_BASE); +} + +static void vmx_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + vmcs_write32(GUEST_IDTR_LIMIT, dt->limit); + vmcs_writel(GUEST_IDTR_BASE, dt->base); +} + +static void vmx_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + dt->limit = vmcs_read32(GUEST_GDTR_LIMIT); + dt->base = vmcs_readl(GUEST_GDTR_BASE); +} + +static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) +{ + vmcs_write32(GUEST_GDTR_LIMIT, dt->limit); + vmcs_writel(GUEST_GDTR_BASE, dt->base); +} + +static int init_rmode_tss(struct kvm *kvm) +{ + gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT; + u16 data = 0; + int ret = 0; + int r; + + down_read(¤t->mm->mmap_sem); + r = kvm_clear_guest_page(kvm, fn, 0, PAGE_SIZE); + if (r < 0) + goto out; + data = TSS_BASE_SIZE + TSS_REDIRECTION_SIZE; + r = kvm_write_guest_page(kvm, fn++, &data, 0x66, sizeof(u16)); + if (r < 0) + goto out; + r = kvm_clear_guest_page(kvm, fn++, 0, PAGE_SIZE); + if (r < 0) + goto out; + r = kvm_clear_guest_page(kvm, fn, 0, PAGE_SIZE); + if (r < 0) + goto out; + data = ~0; + r = kvm_write_guest_page(kvm, fn, &data, + RMODE_TSS_SIZE - 2 * PAGE_SIZE - 1, + sizeof(u8)); + if (r < 0) + goto out; + + ret = 1; +out: + up_read(¤t->mm->mmap_sem); + return ret; +} + +static void seg_setup(int seg) +{ + struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + + vmcs_write16(sf->selector, 0); + vmcs_writel(sf->base, 0); + vmcs_write32(sf->limit, 0xffff); + vmcs_write32(sf->ar_bytes, 0x93); +} + +static int alloc_apic_access_page(struct kvm *kvm) +{ + struct kvm_userspace_memory_region kvm_userspace_mem; + int r = 0; + + down_write(&kvm->slots_lock); + if (kvm->arch.apic_access_page) + goto out; + kvm_userspace_mem.slot = APIC_ACCESS_PAGE_PRIVATE_MEMSLOT; + kvm_userspace_mem.flags = 0; + kvm_userspace_mem.guest_phys_addr = 0xfee00000ULL; + kvm_userspace_mem.memory_size = PAGE_SIZE; + r = __kvm_set_memory_region(kvm, &kvm_userspace_mem, 0); + if (r) + goto out; + + down_read(¤t->mm->mmap_sem); + kvm->arch.apic_access_page = gfn_to_page(kvm, 0xfee00); + up_read(¤t->mm->mmap_sem); +out: + up_write(&kvm->slots_lock); + return r; +} + +static void allocate_vpid(struct vcpu_vmx *vmx) +{ + int vpid; + + vmx->vpid = 0; + if (!enable_vpid || !cpu_has_vmx_vpid()) + return; + spin_lock(&vmx_vpid_lock); + vpid = find_first_zero_bit(vmx_vpid_bitmap, VMX_NR_VPIDS); + if (vpid < VMX_NR_VPIDS) { + vmx->vpid = vpid; + __set_bit(vpid, vmx_vpid_bitmap); + } + spin_unlock(&vmx_vpid_lock); +} + +/* + * Sets up the vmcs for emulated real mode. + */ +static int vmx_vcpu_setup(struct vcpu_vmx *vmx) +{ + u32 host_sysenter_cs; + u32 junk; + unsigned long a; + struct descriptor_table dt; + int i; + unsigned long kvm_vmx_return; + u32 exec_control; + + /* I/O */ + vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a)); + vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b)); + + vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */ + + /* Control */ + vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, + vmcs_config.pin_based_exec_ctrl); + + exec_control = vmcs_config.cpu_based_exec_ctrl; + if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) { + exec_control &= ~CPU_BASED_TPR_SHADOW; +#ifdef CONFIG_X86_64 + exec_control |= CPU_BASED_CR8_STORE_EXITING | + CPU_BASED_CR8_LOAD_EXITING; +#endif + } + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control); + + if (cpu_has_secondary_exec_ctrls()) { + exec_control = vmcs_config.cpu_based_2nd_exec_ctrl; + if (!vm_need_virtualize_apic_accesses(vmx->vcpu.kvm)) + exec_control &= + ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; + if (vmx->vpid == 0) + exec_control &= ~SECONDARY_EXEC_ENABLE_VPID; + vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control); + } + + vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, !!bypass_guest_pf); + vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, !!bypass_guest_pf); + vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */ + + vmcs_writel(HOST_CR0, read_cr0()); /* 22.2.3 */ + vmcs_writel(HOST_CR4, read_cr4()); /* 22.2.3, 22.2.5 */ + vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */ + + vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */ + vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ + vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */ + vmcs_write16(HOST_FS_SELECTOR, read_fs()); /* 22.2.4 */ + vmcs_write16(HOST_GS_SELECTOR, read_gs()); /* 22.2.4 */ + vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ +#ifdef CONFIG_X86_64 + rdmsrl(MSR_FS_BASE, a); + vmcs_writel(HOST_FS_BASE, a); /* 22.2.4 */ + rdmsrl(MSR_GS_BASE, a); + vmcs_writel(HOST_GS_BASE, a); /* 22.2.4 */ +#else + vmcs_writel(HOST_FS_BASE, 0); /* 22.2.4 */ + vmcs_writel(HOST_GS_BASE, 0); /* 22.2.4 */ +#endif + + vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8); /* 22.2.4 */ + + get_idt(&dt); + vmcs_writel(HOST_IDTR_BASE, dt.base); /* 22.2.4 */ + + asm("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return)); + vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */ + vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0); + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0); + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0); + + rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk); + vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs); + rdmsrl(MSR_IA32_SYSENTER_ESP, a); + vmcs_writel(HOST_IA32_SYSENTER_ESP, a); /* 22.2.3 */ + rdmsrl(MSR_IA32_SYSENTER_EIP, a); + vmcs_writel(HOST_IA32_SYSENTER_EIP, a); /* 22.2.3 */ + + for (i = 0; i < NR_VMX_MSR; ++i) { + u32 index = vmx_msr_index[i]; + u32 data_low, data_high; + u64 data; + int j = vmx->nmsrs; + + if (rdmsr_safe(index, &data_low, &data_high) < 0) + continue; + if (wrmsr_safe(index, data_low, data_high) < 0) + continue; + data = data_low | ((u64)data_high << 32); + vmx->host_msrs[j].index = index; + vmx->host_msrs[j].reserved = 0; + vmx->host_msrs[j].data = data; + vmx->guest_msrs[j] = vmx->host_msrs[j]; + ++vmx->nmsrs; + } + + vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl); + + /* 22.2.1, 20.8.1 */ + vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl); + + vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL); + vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK); + + + return 0; +} + +static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + u64 msr; + int ret; + + if (!init_rmode_tss(vmx->vcpu.kvm)) { + ret = -ENOMEM; + goto out; + } + + vmx->vcpu.arch.rmode.active = 0; + + vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val(); + kvm_set_cr8(&vmx->vcpu, 0); + msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; + if (vmx->vcpu.vcpu_id == 0) + msr |= MSR_IA32_APICBASE_BSP; + kvm_set_apic_base(&vmx->vcpu, msr); + + fx_init(&vmx->vcpu); + + /* + * GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode + * insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4. Sigh. + */ + if (vmx->vcpu.vcpu_id == 0) { + vmcs_write16(GUEST_CS_SELECTOR, 0xf000); + vmcs_writel(GUEST_CS_BASE, 0x000f0000); + } else { + vmcs_write16(GUEST_CS_SELECTOR, vmx->vcpu.arch.sipi_vector << 8); + vmcs_writel(GUEST_CS_BASE, vmx->vcpu.arch.sipi_vector << 12); + } + vmcs_write32(GUEST_CS_LIMIT, 0xffff); + vmcs_write32(GUEST_CS_AR_BYTES, 0x9b); + + seg_setup(VCPU_SREG_DS); + seg_setup(VCPU_SREG_ES); + seg_setup(VCPU_SREG_FS); + seg_setup(VCPU_SREG_GS); + seg_setup(VCPU_SREG_SS); + + vmcs_write16(GUEST_TR_SELECTOR, 0); + vmcs_writel(GUEST_TR_BASE, 0); + vmcs_write32(GUEST_TR_LIMIT, 0xffff); + vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); + + vmcs_write16(GUEST_LDTR_SELECTOR, 0); + vmcs_writel(GUEST_LDTR_BASE, 0); + vmcs_write32(GUEST_LDTR_LIMIT, 0xffff); + vmcs_write32(GUEST_LDTR_AR_BYTES, 0x00082); + + vmcs_write32(GUEST_SYSENTER_CS, 0); + vmcs_writel(GUEST_SYSENTER_ESP, 0); + vmcs_writel(GUEST_SYSENTER_EIP, 0); + + vmcs_writel(GUEST_RFLAGS, 0x02); + if (vmx->vcpu.vcpu_id == 0) + vmcs_writel(GUEST_RIP, 0xfff0); + else + vmcs_writel(GUEST_RIP, 0); + vmcs_writel(GUEST_RSP, 0); + + /* todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0 */ + vmcs_writel(GUEST_DR7, 0x400); + + vmcs_writel(GUEST_GDTR_BASE, 0); + vmcs_write32(GUEST_GDTR_LIMIT, 0xffff); + + vmcs_writel(GUEST_IDTR_BASE, 0); + vmcs_write32(GUEST_IDTR_LIMIT, 0xffff); + + vmcs_write32(GUEST_ACTIVITY_STATE, 0); + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0); + vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0); + + guest_write_tsc(0); + + /* Special registers */ + vmcs_write64(GUEST_IA32_DEBUGCTL, 0); + + setup_msrs(vmx); + + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */ + + if (cpu_has_vmx_tpr_shadow()) { + vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0); + if (vm_need_tpr_shadow(vmx->vcpu.kvm)) + vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, + page_to_phys(vmx->vcpu.arch.apic->regs_page)); + vmcs_write32(TPR_THRESHOLD, 0); + } + + if (vm_need_virtualize_apic_accesses(vmx->vcpu.kvm)) + vmcs_write64(APIC_ACCESS_ADDR, + page_to_phys(vmx->vcpu.kvm->arch.apic_access_page)); + + if (vmx->vpid != 0) + vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid); + + vmx->vcpu.arch.cr0 = 0x60000010; + vmx_set_cr0(&vmx->vcpu, vmx->vcpu.arch.cr0); /* enter rmode */ + vmx_set_cr4(&vmx->vcpu, 0); + vmx_set_efer(&vmx->vcpu, 0); + vmx_fpu_activate(&vmx->vcpu); + update_exception_bitmap(&vmx->vcpu); + + vpid_sync_vcpu_all(vmx); + + return 0; + +out: + return ret; +} + +static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + if (vcpu->arch.rmode.active) { + vmx->rmode.irq.pending = true; + vmx->rmode.irq.vector = irq; + vmx->rmode.irq.rip = vmcs_readl(GUEST_RIP); + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + irq | INTR_TYPE_SOFT_INTR | INTR_INFO_VALID_MASK); + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1); + vmcs_writel(GUEST_RIP, vmx->rmode.irq.rip - 1); + return; + } + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); +} + +static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) +{ + int word_index = __ffs(vcpu->arch.irq_summary); + int bit_index = __ffs(vcpu->arch.irq_pending[word_index]); + int irq = word_index * BITS_PER_LONG + bit_index; + + clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]); + if (!vcpu->arch.irq_pending[word_index]) + clear_bit(word_index, &vcpu->arch.irq_summary); + vmx_inject_irq(vcpu, irq); +} + + +static void do_interrupt_requests(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + u32 cpu_based_vm_exec_control; + + vcpu->arch.interrupt_window_open = + ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && + (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0); + + if (vcpu->arch.interrupt_window_open && + vcpu->arch.irq_summary && + !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK)) + /* + * If interrupts enabled, and not blocked by sti or mov ss. Good. + */ + kvm_do_inject_irq(vcpu); + + cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + if (!vcpu->arch.interrupt_window_open && + (vcpu->arch.irq_summary || kvm_run->request_interrupt_window)) + /* + * Interrupts blocked. Wait for unblock. + */ + cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; + else + cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); +} + +static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr) +{ + int ret; + struct kvm_userspace_memory_region tss_mem = { + .slot = 8, + .guest_phys_addr = addr, + .memory_size = PAGE_SIZE * 3, + .flags = 0, + }; + + ret = kvm_set_memory_region(kvm, &tss_mem, 0); + if (ret) + return ret; + kvm->arch.tss_addr = addr; + return 0; +} + +static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu) +{ + struct kvm_guest_debug *dbg = &vcpu->guest_debug; + + set_debugreg(dbg->bp[0], 0); + set_debugreg(dbg->bp[1], 1); + set_debugreg(dbg->bp[2], 2); + set_debugreg(dbg->bp[3], 3); + + if (dbg->singlestep) { + unsigned long flags; + + flags = vmcs_readl(GUEST_RFLAGS); + flags |= X86_EFLAGS_TF | X86_EFLAGS_RF; + vmcs_writel(GUEST_RFLAGS, flags); + } +} + +static int handle_rmode_exception(struct kvm_vcpu *vcpu, + int vec, u32 err_code) +{ + if (!vcpu->arch.rmode.active) + return 0; + + /* + * Instruction with address size override prefix opcode 0x67 + * Cause the #SS fault with 0 error code in VM86 mode. + */ + if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0) + if (emulate_instruction(vcpu, NULL, 0, 0, 0) == EMULATE_DONE) + return 1; + return 0; +} + +static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + u32 intr_info, error_code; + unsigned long cr2, rip; + u32 vect_info; + enum emulation_result er; + + vect_info = vmx->idt_vectoring_info; + intr_info = vmcs_read32(VM_EXIT_INTR_INFO); + + if ((vect_info & VECTORING_INFO_VALID_MASK) && + !is_page_fault(intr_info)) + printk(KERN_ERR "%s: unexpected, vectoring info 0x%x " + "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info); + + if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) { + int irq = vect_info & VECTORING_INFO_VECTOR_MASK; + set_bit(irq, vcpu->arch.irq_pending); + set_bit(irq / BITS_PER_LONG, &vcpu->arch.irq_summary); + } + + if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */ + return 1; /* already handled by vmx_vcpu_run() */ + + if (is_no_device(intr_info)) { + vmx_fpu_activate(vcpu); + return 1; + } + + if (is_invalid_opcode(intr_info)) { + er = emulate_instruction(vcpu, kvm_run, 0, 0, EMULTYPE_TRAP_UD); + if (er != EMULATE_DONE) + kvm_queue_exception(vcpu, UD_VECTOR); + return 1; + } + + error_code = 0; + rip = vmcs_readl(GUEST_RIP); + if (intr_info & INTR_INFO_DELIVER_CODE_MASK) + error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE); + if (is_page_fault(intr_info)) { + cr2 = vmcs_readl(EXIT_QUALIFICATION); + return kvm_mmu_page_fault(vcpu, cr2, error_code); + } + + if (vcpu->arch.rmode.active && + handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK, + error_code)) { + if (vcpu->arch.halt_request) { + vcpu->arch.halt_request = 0; + return kvm_emulate_halt(vcpu); + } + return 1; + } + + if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) == + (INTR_TYPE_EXCEPTION | 1)) { + kvm_run->exit_reason = KVM_EXIT_DEBUG; + return 0; + } + kvm_run->exit_reason = KVM_EXIT_EXCEPTION; + kvm_run->ex.exception = intr_info & INTR_INFO_VECTOR_MASK; + kvm_run->ex.error_code = error_code; + return 0; +} + +static int handle_external_interrupt(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + ++vcpu->stat.irq_exits; + return 1; +} + +static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; + return 0; +} + +static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + unsigned long exit_qualification; + int size, down, in, string, rep; + unsigned port; + + ++vcpu->stat.io_exits; + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); + string = (exit_qualification & 16) != 0; + + if (string) { + if (emulate_instruction(vcpu, + kvm_run, 0, 0, 0) == EMULATE_DO_MMIO) + return 0; + return 1; + } + + size = (exit_qualification & 7) + 1; + in = (exit_qualification & 8) != 0; + down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; + rep = (exit_qualification & 32) != 0; + port = exit_qualification >> 16; + + return kvm_emulate_pio(vcpu, kvm_run, in, size, port); +} + +static void +vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) +{ + /* + * Patch in the VMCALL instruction: + */ + hypercall[0] = 0x0f; + hypercall[1] = 0x01; + hypercall[2] = 0xc1; +} + +static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + unsigned long exit_qualification; + int cr; + int reg; + + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); + cr = exit_qualification & 15; + reg = (exit_qualification >> 8) & 15; + switch ((exit_qualification >> 4) & 3) { + case 0: /* mov to cr */ + switch (cr) { + case 0: + vcpu_load_rsp_rip(vcpu); + kvm_set_cr0(vcpu, vcpu->arch.regs[reg]); + skip_emulated_instruction(vcpu); + return 1; + case 3: + vcpu_load_rsp_rip(vcpu); + kvm_set_cr3(vcpu, vcpu->arch.regs[reg]); + skip_emulated_instruction(vcpu); + return 1; + case 4: + vcpu_load_rsp_rip(vcpu); + kvm_set_cr4(vcpu, vcpu->arch.regs[reg]); + skip_emulated_instruction(vcpu); + return 1; + case 8: + vcpu_load_rsp_rip(vcpu); + kvm_set_cr8(vcpu, vcpu->arch.regs[reg]); + skip_emulated_instruction(vcpu); + if (irqchip_in_kernel(vcpu->kvm)) + return 1; + kvm_run->exit_reason = KVM_EXIT_SET_TPR; + return 0; + }; + break; + case 2: /* clts */ + vcpu_load_rsp_rip(vcpu); + vmx_fpu_deactivate(vcpu); + vcpu->arch.cr0 &= ~X86_CR0_TS; + vmcs_writel(CR0_READ_SHADOW, vcpu->arch.cr0); + vmx_fpu_activate(vcpu); + skip_emulated_instruction(vcpu); + return 1; + case 1: /*mov from cr*/ + switch (cr) { + case 3: + vcpu_load_rsp_rip(vcpu); + vcpu->arch.regs[reg] = vcpu->arch.cr3; + vcpu_put_rsp_rip(vcpu); + skip_emulated_instruction(vcpu); + return 1; + case 8: + vcpu_load_rsp_rip(vcpu); + vcpu->arch.regs[reg] = kvm_get_cr8(vcpu); + vcpu_put_rsp_rip(vcpu); + skip_emulated_instruction(vcpu); + return 1; + } + break; + case 3: /* lmsw */ + kvm_lmsw(vcpu, (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f); + + skip_emulated_instruction(vcpu); + return 1; + default: + break; + } + kvm_run->exit_reason = 0; + pr_unimpl(vcpu, "unhandled control register: op %d cr %d\n", + (int)(exit_qualification >> 4) & 3, cr); + return 0; +} + +static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + unsigned long exit_qualification; + unsigned long val; + int dr, reg; + + if (!kvm_require_cpl(vcpu, 0)) + return 1; + + /* + * FIXME: this code assumes the host is debugging the guest. + * need to deal with guest debugging itself too. + */ + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); + dr = exit_qualification & 7; + reg = (exit_qualification >> 8) & 15; + vcpu_load_rsp_rip(vcpu); + if (exit_qualification & 16) { + /* mov from dr */ + switch (dr) { + case 6: + val = 0xffff0ff0; + break; + case 7: + val = 0x400; + break; + default: + val = 0; + } + vcpu->arch.regs[reg] = val; + } else { + /* mov to dr */ + } + vcpu_put_rsp_rip(vcpu); + skip_emulated_instruction(vcpu); + return 1; +} + +static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + kvm_emulate_cpuid(vcpu); + return 1; +} + +static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u32 ecx = vcpu->arch.regs[VCPU_REGS_RCX]; + u64 data; + + if (vmx_get_msr(vcpu, ecx, &data)) { + kvm_inject_gp(vcpu, 0); + return 1; + } + + /* FIXME: handling of bits 32:63 of rax, rdx */ + vcpu->arch.regs[VCPU_REGS_RAX] = data & -1u; + vcpu->arch.regs[VCPU_REGS_RDX] = (data >> 32) & -1u; + skip_emulated_instruction(vcpu); + return 1; +} + +static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u32 ecx = vcpu->arch.regs[VCPU_REGS_RCX]; + u64 data = (vcpu->arch.regs[VCPU_REGS_RAX] & -1u) + | ((u64)(vcpu->arch.regs[VCPU_REGS_RDX] & -1u) << 32); + + if (vmx_set_msr(vcpu, ecx, data) != 0) { + kvm_inject_gp(vcpu, 0); + return 1; + } + + skip_emulated_instruction(vcpu); + return 1; +} + +static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + return 1; +} + +static int handle_interrupt_window(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + u32 cpu_based_vm_exec_control; + + /* clear pending irq */ + cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); + /* + * If the user space waits to inject interrupts, exit as soon as + * possible + */ + if (kvm_run->request_interrupt_window && + !vcpu->arch.irq_summary) { + kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; + ++vcpu->stat.irq_window_exits; + return 0; + } + return 1; +} + +static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + skip_emulated_instruction(vcpu); + return kvm_emulate_halt(vcpu); +} + +static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + skip_emulated_instruction(vcpu); + kvm_emulate_hypercall(vcpu); + return 1; +} + +static int handle_wbinvd(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + skip_emulated_instruction(vcpu); + /* TODO: Add support for VT-d/pass-through device */ + return 1; +} + +static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + u64 exit_qualification; + enum emulation_result er; + unsigned long offset; + + exit_qualification = vmcs_read64(EXIT_QUALIFICATION); + offset = exit_qualification & 0xffful; + + er = emulate_instruction(vcpu, kvm_run, 0, 0, 0); + + if (er != EMULATE_DONE) { + printk(KERN_ERR + "Fail to handle apic access vmexit! Offset is 0x%lx\n", + offset); + return -ENOTSUPP; + } + return 1; +} + +/* + * The exit handlers return 1 if the exit was handled fully and guest execution + * may resume. Otherwise they set the kvm_run parameter to indicate what needs + * to be done to userspace and return 0. + */ +static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) = { + [EXIT_REASON_EXCEPTION_NMI] = handle_exception, + [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt, + [EXIT_REASON_TRIPLE_FAULT] = handle_triple_fault, + [EXIT_REASON_IO_INSTRUCTION] = handle_io, + [EXIT_REASON_CR_ACCESS] = handle_cr, + [EXIT_REASON_DR_ACCESS] = handle_dr, + [EXIT_REASON_CPUID] = handle_cpuid, + [EXIT_REASON_MSR_READ] = handle_rdmsr, + [EXIT_REASON_MSR_WRITE] = handle_wrmsr, + [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window, + [EXIT_REASON_HLT] = handle_halt, + [EXIT_REASON_VMCALL] = handle_vmcall, + [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold, + [EXIT_REASON_APIC_ACCESS] = handle_apic_access, + [EXIT_REASON_WBINVD] = handle_wbinvd, +}; + +static const int kvm_vmx_max_exit_handlers = + ARRAY_SIZE(kvm_vmx_exit_handlers); + +/* + * The guest has exited. See if we can fix it or if we need userspace + * assistance. + */ +static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) +{ + u32 exit_reason = vmcs_read32(VM_EXIT_REASON); + struct vcpu_vmx *vmx = to_vmx(vcpu); + u32 vectoring_info = vmx->idt_vectoring_info; + + if (unlikely(vmx->fail)) { + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; + kvm_run->fail_entry.hardware_entry_failure_reason + = vmcs_read32(VM_INSTRUCTION_ERROR); + return 0; + } + + if ((vectoring_info & VECTORING_INFO_VALID_MASK) && + exit_reason != EXIT_REASON_EXCEPTION_NMI) + printk(KERN_WARNING "%s: unexpected, valid vectoring info and " + "exit reason is 0x%x\n", __FUNCTION__, exit_reason); + if (exit_reason < kvm_vmx_max_exit_handlers + && kvm_vmx_exit_handlers[exit_reason]) + return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run); + else { + kvm_run->exit_reason = KVM_EXIT_UNKNOWN; + kvm_run->hw.hardware_exit_reason = exit_reason; + } + return 0; +} + +static void update_tpr_threshold(struct kvm_vcpu *vcpu) +{ + int max_irr, tpr; + + if (!vm_need_tpr_shadow(vcpu->kvm)) + return; + + if (!kvm_lapic_enabled(vcpu) || + ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) { + vmcs_write32(TPR_THRESHOLD, 0); + return; + } + + tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4; + vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4); +} + +static void enable_irq_window(struct kvm_vcpu *vcpu) +{ + u32 cpu_based_vm_exec_control; + + cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); +} + +static void vmx_intr_assist(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + u32 idtv_info_field, intr_info_field; + int has_ext_irq, interrupt_window_open; + int vector; + + update_tpr_threshold(vcpu); + + has_ext_irq = kvm_cpu_has_interrupt(vcpu); + intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD); + idtv_info_field = vmx->idt_vectoring_info; + if (intr_info_field & INTR_INFO_VALID_MASK) { + if (idtv_info_field & INTR_INFO_VALID_MASK) { + /* TODO: fault when IDT_Vectoring */ + if (printk_ratelimit()) + printk(KERN_ERR "Fault when IDT_Vectoring\n"); + } + if (has_ext_irq) + enable_irq_window(vcpu); + return; + } + if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) { + if ((idtv_info_field & VECTORING_INFO_TYPE_MASK) + == INTR_TYPE_EXT_INTR + && vcpu->arch.rmode.active) { + u8 vect = idtv_info_field & VECTORING_INFO_VECTOR_MASK; + + vmx_inject_irq(vcpu, vect); + if (unlikely(has_ext_irq)) + enable_irq_window(vcpu); + return; + } + + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, + vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); + + if (unlikely(idtv_info_field & INTR_INFO_DELIVER_CODE_MASK)) + vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, + vmcs_read32(IDT_VECTORING_ERROR_CODE)); + if (unlikely(has_ext_irq)) + enable_irq_window(vcpu); + return; + } + if (!has_ext_irq) + return; + interrupt_window_open = + ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && + (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0); + if (interrupt_window_open) { + vector = kvm_cpu_get_interrupt(vcpu); + vmx_inject_irq(vcpu, vector); + kvm_timer_intr_post(vcpu, vector); + } else + enable_irq_window(vcpu); +} + +/* + * Failure to inject an interrupt should give us the information + * in IDT_VECTORING_INFO_FIELD. However, if the failure occurs + * when fetching the interrupt redirection bitmap in the real-mode + * tss, this doesn't happen. So we do it ourselves. + */ +static void fixup_rmode_irq(struct vcpu_vmx *vmx) +{ + vmx->rmode.irq.pending = 0; + if (vmcs_readl(GUEST_RIP) + 1 != vmx->rmode.irq.rip) + return; + vmcs_writel(GUEST_RIP, vmx->rmode.irq.rip); + if (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) { + vmx->idt_vectoring_info &= ~VECTORING_INFO_TYPE_MASK; + vmx->idt_vectoring_info |= INTR_TYPE_EXT_INTR; + return; + } + vmx->idt_vectoring_info = + VECTORING_INFO_VALID_MASK + | INTR_TYPE_EXT_INTR + | vmx->rmode.irq.vector; +} + +static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + u32 intr_info; + + /* + * Loading guest fpu may have cleared host cr0.ts + */ + vmcs_writel(HOST_CR0, read_cr0()); + + asm( + /* Store host registers */ +#ifdef CONFIG_X86_64 + "push %%rdx; push %%rbp;" + "push %%rcx \n\t" +#else + "push %%edx; push %%ebp;" + "push %%ecx \n\t" +#endif + ASM_VMX_VMWRITE_RSP_RDX "\n\t" + /* Check if vmlaunch of vmresume is needed */ + "cmpl $0, %c[launched](%0) \n\t" + /* Load guest registers. Don't clobber flags. */ +#ifdef CONFIG_X86_64 + "mov %c[cr2](%0), %%rax \n\t" + "mov %%rax, %%cr2 \n\t" + "mov %c[rax](%0), %%rax \n\t" + "mov %c[rbx](%0), %%rbx \n\t" + "mov %c[rdx](%0), %%rdx \n\t" + "mov %c[rsi](%0), %%rsi \n\t" + "mov %c[rdi](%0), %%rdi \n\t" + "mov %c[rbp](%0), %%rbp \n\t" + "mov %c[r8](%0), %%r8 \n\t" + "mov %c[r9](%0), %%r9 \n\t" + "mov %c[r10](%0), %%r10 \n\t" + "mov %c[r11](%0), %%r11 \n\t" + "mov %c[r12](%0), %%r12 \n\t" + "mov %c[r13](%0), %%r13 \n\t" + "mov %c[r14](%0), %%r14 \n\t" + "mov %c[r15](%0), %%r15 \n\t" + "mov %c[rcx](%0), %%rcx \n\t" /* kills %0 (rcx) */ +#else + "mov %c[cr2](%0), %%eax \n\t" + "mov %%eax, %%cr2 \n\t" + "mov %c[rax](%0), %%eax \n\t" + "mov %c[rbx](%0), %%ebx \n\t" + "mov %c[rdx](%0), %%edx \n\t" + "mov %c[rsi](%0), %%esi \n\t" + "mov %c[rdi](%0), %%edi \n\t" + "mov %c[rbp](%0), %%ebp \n\t" + "mov %c[rcx](%0), %%ecx \n\t" /* kills %0 (ecx) */ +#endif + /* Enter guest mode */ + "jne .Llaunched \n\t" + ASM_VMX_VMLAUNCH "\n\t" + "jmp .Lkvm_vmx_return \n\t" + ".Llaunched: " ASM_VMX_VMRESUME "\n\t" + ".Lkvm_vmx_return: " + /* Save guest registers, load host registers, keep flags */ +#ifdef CONFIG_X86_64 + "xchg %0, (%%rsp) \n\t" + "mov %%rax, %c[rax](%0) \n\t" + "mov %%rbx, %c[rbx](%0) \n\t" + "pushq (%%rsp); popq %c[rcx](%0) \n\t" + "mov %%rdx, %c[rdx](%0) \n\t" + "mov %%rsi, %c[rsi](%0) \n\t" + "mov %%rdi, %c[rdi](%0) \n\t" + "mov %%rbp, %c[rbp](%0) \n\t" + "mov %%r8, %c[r8](%0) \n\t" + "mov %%r9, %c[r9](%0) \n\t" + "mov %%r10, %c[r10](%0) \n\t" + "mov %%r11, %c[r11](%0) \n\t" + "mov %%r12, %c[r12](%0) \n\t" + "mov %%r13, %c[r13](%0) \n\t" + "mov %%r14, %c[r14](%0) \n\t" + "mov %%r15, %c[r15](%0) \n\t" + "mov %%cr2, %%rax \n\t" + "mov %%rax, %c[cr2](%0) \n\t" + + "pop %%rbp; pop %%rbp; pop %%rdx \n\t" +#else + "xchg %0, (%%esp) \n\t" + "mov %%eax, %c[rax](%0) \n\t" + "mov %%ebx, %c[rbx](%0) \n\t" + "pushl (%%esp); popl %c[rcx](%0) \n\t" + "mov %%edx, %c[rdx](%0) \n\t" + "mov %%esi, %c[rsi](%0) \n\t" + "mov %%edi, %c[rdi](%0) \n\t" + "mov %%ebp, %c[rbp](%0) \n\t" + "mov %%cr2, %%eax \n\t" + "mov %%eax, %c[cr2](%0) \n\t" + + "pop %%ebp; pop %%ebp; pop %%edx \n\t" +#endif + "setbe %c[fail](%0) \n\t" + : : "c"(vmx), "d"((unsigned long)HOST_RSP), + [launched]"i"(offsetof(struct vcpu_vmx, launched)), + [fail]"i"(offsetof(struct vcpu_vmx, fail)), + [rax]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RAX])), + [rbx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RBX])), + [rcx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RCX])), + [rdx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RDX])), + [rsi]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RSI])), + [rdi]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RDI])), + [rbp]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RBP])), +#ifdef CONFIG_X86_64 + [r8]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R8])), + [r9]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R9])), + [r10]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R10])), + [r11]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R11])), + [r12]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R12])), + [r13]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R13])), + [r14]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R14])), + [r15]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R15])), +#endif + [cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2)) + : "cc", "memory" +#ifdef CONFIG_X86_64 + , "rbx", "rdi", "rsi" + , "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +#else + , "ebx", "edi", "rsi" +#endif + ); + + vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); + if (vmx->rmode.irq.pending) + fixup_rmode_irq(vmx); + + vcpu->arch.interrupt_window_open = + (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; + + asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); + vmx->launched = 1; + + intr_info = vmcs_read32(VM_EXIT_INTR_INFO); + + /* We need to handle NMIs before interrupts are enabled */ + if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */ + asm("int $2"); +} + +static void vmx_free_vmcs(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + if (vmx->vmcs) { + on_each_cpu(__vcpu_clear, vmx, 0, 1); + free_vmcs(vmx->vmcs); + vmx->vmcs = NULL; + } +} + +static void vmx_free_vcpu(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + spin_lock(&vmx_vpid_lock); + if (vmx->vpid != 0) + __clear_bit(vmx->vpid, vmx_vpid_bitmap); + spin_unlock(&vmx_vpid_lock); + vmx_free_vmcs(vcpu); + kfree(vmx->host_msrs); + kfree(vmx->guest_msrs); + kvm_vcpu_uninit(vcpu); + kmem_cache_free(kvm_vcpu_cache, vmx); +} + +static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) +{ + int err; + struct vcpu_vmx *vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); + int cpu; + + if (!vmx) + return ERR_PTR(-ENOMEM); + + allocate_vpid(vmx); + + err = kvm_vcpu_init(&vmx->vcpu, kvm, id); + if (err) + goto free_vcpu; + + vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!vmx->guest_msrs) { + err = -ENOMEM; + goto uninit_vcpu; + } + + vmx->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!vmx->host_msrs) + goto free_guest_msrs; + + vmx->vmcs = alloc_vmcs(); + if (!vmx->vmcs) + goto free_msrs; + + vmcs_clear(vmx->vmcs); + + cpu = get_cpu(); + vmx_vcpu_load(&vmx->vcpu, cpu); + err = vmx_vcpu_setup(vmx); + vmx_vcpu_put(&vmx->vcpu); + put_cpu(); + if (err) + goto free_vmcs; + if (vm_need_virtualize_apic_accesses(kvm)) + if (alloc_apic_access_page(kvm) != 0) + goto free_vmcs; + + return &vmx->vcpu; + +free_vmcs: + free_vmcs(vmx->vmcs); +free_msrs: + kfree(vmx->host_msrs); +free_guest_msrs: + kfree(vmx->guest_msrs); +uninit_vcpu: + kvm_vcpu_uninit(&vmx->vcpu); +free_vcpu: + kmem_cache_free(kvm_vcpu_cache, vmx); + return ERR_PTR(err); +} + +static void __init vmx_check_processor_compat(void *rtn) +{ + struct vmcs_config vmcs_conf; + + *(int *)rtn = 0; + if (setup_vmcs_config(&vmcs_conf) < 0) + *(int *)rtn = -EIO; + if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) { + printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n", + smp_processor_id()); + *(int *)rtn = -EIO; + } +} + +static struct kvm_x86_ops vmx_x86_ops = { + .cpu_has_kvm_support = cpu_has_kvm_support, + .disabled_by_bios = vmx_disabled_by_bios, + .hardware_setup = hardware_setup, + .hardware_unsetup = hardware_unsetup, + .check_processor_compatibility = vmx_check_processor_compat, + .hardware_enable = hardware_enable, + .hardware_disable = hardware_disable, + .cpu_has_accelerated_tpr = cpu_has_vmx_virtualize_apic_accesses, + + .vcpu_create = vmx_create_vcpu, + .vcpu_free = vmx_free_vcpu, + .vcpu_reset = vmx_vcpu_reset, + + .prepare_guest_switch = vmx_save_host_state, + .vcpu_load = vmx_vcpu_load, + .vcpu_put = vmx_vcpu_put, + .vcpu_decache = vmx_vcpu_decache, + + .set_guest_debug = set_guest_debug, + .guest_debug_pre = kvm_guest_debug_pre, + .get_msr = vmx_get_msr, + .set_msr = vmx_set_msr, + .get_segment_base = vmx_get_segment_base, + .get_segment = vmx_get_segment, + .set_segment = vmx_set_segment, + .get_cpl = vmx_get_cpl, + .get_cs_db_l_bits = vmx_get_cs_db_l_bits, + .decache_cr4_guest_bits = vmx_decache_cr4_guest_bits, + .set_cr0 = vmx_set_cr0, + .set_cr3 = vmx_set_cr3, + .set_cr4 = vmx_set_cr4, + .set_efer = vmx_set_efer, + .get_idt = vmx_get_idt, + .set_idt = vmx_set_idt, + .get_gdt = vmx_get_gdt, + .set_gdt = vmx_set_gdt, + .cache_regs = vcpu_load_rsp_rip, + .decache_regs = vcpu_put_rsp_rip, + .get_rflags = vmx_get_rflags, + .set_rflags = vmx_set_rflags, + + .tlb_flush = vmx_flush_tlb, + + .run = vmx_vcpu_run, + .handle_exit = kvm_handle_exit, + .skip_emulated_instruction = skip_emulated_instruction, + .patch_hypercall = vmx_patch_hypercall, + .get_irq = vmx_get_irq, + .set_irq = vmx_inject_irq, + .queue_exception = vmx_queue_exception, + .exception_injected = vmx_exception_injected, + .inject_pending_irq = vmx_intr_assist, + .inject_pending_vectors = do_interrupt_requests, + + .set_tss_addr = vmx_set_tss_addr, +}; + +static int __init vmx_init(void) +{ + void *iova; + int r; + + vmx_io_bitmap_a = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); + if (!vmx_io_bitmap_a) + return -ENOMEM; + + vmx_io_bitmap_b = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); + if (!vmx_io_bitmap_b) { + r = -ENOMEM; + goto out; + } + + /* + * Allow direct access to the PC debug port (it is often used for I/O + * delays, but the vmexits simply slow things down). + */ + iova = kmap(vmx_io_bitmap_a); + memset(iova, 0xff, PAGE_SIZE); + clear_bit(0x80, iova); + kunmap(vmx_io_bitmap_a); + + iova = kmap(vmx_io_bitmap_b); + memset(iova, 0xff, PAGE_SIZE); + kunmap(vmx_io_bitmap_b); + + set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */ + + r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE); + if (r) + goto out1; + + if (bypass_guest_pf) + kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull); + + return 0; + +out1: + __free_page(vmx_io_bitmap_b); +out: + __free_page(vmx_io_bitmap_a); + return r; +} + +static void __exit vmx_exit(void) +{ + __free_page(vmx_io_bitmap_b); + __free_page(vmx_io_bitmap_a); + + kvm_exit(); +} + +module_init(vmx_init) +module_exit(vmx_exit) --- linux-2.6.24.orig/arch/x86/kvm/Makefile +++ linux-2.6.24/arch/x86/kvm/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for Kernel-based Virtual Machine module +# + +common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o) + +EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm + +kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o +obj-$(CONFIG_KVM) += kvm.o +kvm-intel-objs = vmx.o +obj-$(CONFIG_KVM_INTEL) += kvm-intel.o +kvm-amd-objs = svm.o +obj-$(CONFIG_KVM_AMD) += kvm-amd.o --- linux-2.6.24.orig/arch/x86/ia32/ia32_signal.c +++ linux-2.6.24/arch/x86/ia32/ia32_signal.c @@ -494,7 +494,7 @@ regs->ss = __USER32_DS; set_fs(USER_DS); - regs->eflags &= ~TF_MASK; + regs->eflags &= ~(TF_MASK | X86_EFLAGS_DF); if (test_thread_flag(TIF_SINGLESTEP)) ptrace_notify(SIGTRAP); @@ -600,7 +600,7 @@ regs->ss = __USER32_DS; set_fs(USER_DS); - regs->eflags &= ~TF_MASK; + regs->eflags &= ~(TF_MASK | X86_EFLAGS_DF); if (test_thread_flag(TIF_SINGLESTEP)) ptrace_notify(SIGTRAP); --- linux-2.6.24.orig/arch/x86/ia32/ia32entry.S +++ linux-2.6.24/arch/x86/ia32/ia32entry.S @@ -16,6 +16,11 @@ #include #include +#ifndef CONFIG_AUDITSYSCALL +#define sysexit_audit ia32_ret_from_sys_call +#define sysretl_audit ia32_ret_from_sys_call +#endif + #define IA32_NR_syscalls ((ia32_syscall_end - ia32_sys_call_table)/8) .macro IA32_ARG_FIXUP noebp=0 @@ -30,12 +35,12 @@ .endm /* clobbers %eax */ - .macro CLEAR_RREGS + .macro CLEAR_RREGS offset=0 xorl %eax,%eax - movq %rax,R11(%rsp) - movq %rax,R10(%rsp) - movq %rax,R9(%rsp) - movq %rax,R8(%rsp) + movq %rax,\offset+R11(%rsp) + movq %rax,\offset+R10(%rsp) + movq %rax,\offset+R9(%rsp) + movq %rax,\offset+R8(%rsp) .endm .macro LOAD_ARGS32 offset @@ -143,6 +148,10 @@ /* clear IF, that popfq doesn't enable interrupts early */ andl $~0x200,EFLAGS-R11(%rsp) RESTORE_ARGS 1,24,1,1,1,1 + xorq %r8,%r8 + xorq %r9,%r9 + xorq %r10,%r10 + xorq %r11,%r11 popfq CFI_ADJUST_CFA_OFFSET -8 /*CFI_RESTORE rflags*/ @@ -250,6 +259,9 @@ CFI_REGISTER rip,rcx movl EFLAGS-ARGOFFSET(%rsp),%r11d /*CFI_REGISTER rflags,r11*/ + xorq %r10,%r10 + xorq %r9,%r9 + xorq %r8,%r8 TRACE_IRQS_ON movl RSP-ARGOFFSET(%rsp),%esp CFI_RESTORE rsp @@ -260,7 +272,7 @@ CFI_RESTORE_STATE xchgl %r9d,%ebp SAVE_REST - CLEAR_RREGS + CLEAR_RREGS 0 movq %r9,R9(%rsp) movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ @@ -331,6 +343,8 @@ call *ia32_sys_call_table(,%rax,8) # xxx: rip relative ia32_sysret: movq %rax,RAX-ARGOFFSET(%rsp) +ia32_ret_from_sys_call: + CLEAR_RREGS -ARGOFFSET jmp int_ret_from_sys_call ia32_tracesys: @@ -346,8 +360,8 @@ ia32_badsys: movq $0,ORIG_RAX-ARGOFFSET(%rsp) - movq $-ENOSYS,RAX-ARGOFFSET(%rsp) - jmp int_ret_from_sys_call + movq $-ENOSYS,%rax + jmp ia32_sysret quiet_ni_syscall: movq $-ENOSYS,%rax @@ -593,7 +607,7 @@ .quad quiet_ni_syscall /* streams2 */ .quad stub32_vfork /* 190 */ .quad compat_sys_getrlimit - .quad sys32_mmap2 + .quad sys_mmap_pgoff .quad sys32_truncate64 .quad sys32_ftruncate64 .quad sys32_stat64 /* 195 */ --- linux-2.6.24.orig/arch/x86/ia32/sys_ia32.c +++ linux-2.6.24/arch/x86/ia32/sys_ia32.c @@ -225,9 +225,6 @@ sys32_mmap(struct mmap_arg_struct __user *arg) { struct mmap_arg_struct a; - struct file *file = NULL; - unsigned long retval; - struct mm_struct *mm ; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; @@ -235,21 +232,8 @@ if (a.offset & ~PAGE_MASK) return -EINVAL; - if (!(a.flags & MAP_ANONYMOUS)) { - file = fget(a.fd); - if (!file) - return -EBADF; - } - - mm = current->mm; - down_write(&mm->mmap_sem); - retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset>>PAGE_SHIFT); - if (file) - fput(file); - - up_write(&mm->mmap_sem); - - return retval; + return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, + a.offset>>PAGE_SHIFT); } asmlinkage long @@ -693,30 +677,6 @@ return ret; } -asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - struct mm_struct *mm = current->mm; - unsigned long error; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - return -EBADF; - } - - down_write(&mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(&mm->mmap_sem); - - if (file) - fput(file); - return error; -} - asmlinkage long sys32_olduname(struct oldold_utsname __user * name) { int err; --- linux-2.6.24.orig/arch/m68k/kernel/sys_m68k.c +++ linux-2.6.24/arch/m68k/kernel/sys_m68k.c @@ -47,37 +47,16 @@ return error; } -/* common code for old and new mmaps */ -static inline long do_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - int error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) { - return do_mmap2(addr, len, prot, flags, fd, pgoff); + /* + * This is wrong for sun3 - there PAGE_SIZE is 8Kb, + * so we need to shift the argument down by 1; m68k mmap64(3) + * (in libc) expects the last argument of mmap2 in 4Kb units. + */ + return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); } /* @@ -108,57 +87,11 @@ if (a.offset & ~PAGE_MASK) goto out; - a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); -out: - return error; -} - -#if 0 -struct mmap_arg_struct64 { - __u32 addr; - __u32 len; - __u32 prot; - __u32 flags; - __u64 offset; /* 64 bits */ - __u32 fd; -}; - -asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg) -{ - int error = -EFAULT; - struct file * file = NULL; - struct mmap_arg_struct64 a; - unsigned long pgoff; - - if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; - - if ((long)a.offset & ~PAGE_MASK) - return -EINVAL; - - pgoff = a.offset >> PAGE_SHIFT; - if ((a.offset >> PAGE_SHIFT) != pgoff) - return -EINVAL; - - if (!(a.flags & MAP_ANONYMOUS)) { - error = -EBADF; - file = fget(a.fd); - if (!file) - goto out; - } - a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); - up_write(¤t->mm->mmap_sem); - if (file) - fput(file); + error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, + a.offset >> PAGE_SHIFT); out: return error; } -#endif struct sel_arg_struct { unsigned long n; --- linux-2.6.24.orig/arch/alpha/kernel/osf_sys.c +++ linux-2.6.24/arch/alpha/kernel/osf_sys.c @@ -179,25 +179,18 @@ osf_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off) { - struct file *file = NULL; - unsigned long ret = -EBADF; + unsigned long ret = -EINVAL; #if 0 if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED)) printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, flags); #endif - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down_write(¤t->mm->mmap_sem); - ret = do_mmap(file, addr, len, prot, flags, off); - up_write(¤t->mm->mmap_sem); - if (file) - fput(file); + if ((off + PAGE_ALIGN(len)) < off) + goto out; + if (off & ~PAGE_MASK) + goto out; + ret = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); out: return ret; } --- linux-2.6.24.orig/arch/h8300/kernel/sys_h8300.c +++ linux-2.6.24/arch/h8300/kernel/sys_h8300.c @@ -44,39 +44,6 @@ return error; } -/* common code for old and new mmaps */ -static inline long do_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - int error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - return do_mmap2(addr, len, prot, flags, fd, pgoff); -} - /* * Perform the select(nd, in, out, ex, tv) and mmap() system * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to @@ -105,58 +72,12 @@ if (a.offset & ~PAGE_MASK) goto out; - a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); + error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, + a.offset >> PAGE_SHIFT); out: return error; } -#if 0 /* DAVIDM - do we want this */ -struct mmap_arg_struct64 { - __u32 addr; - __u32 len; - __u32 prot; - __u32 flags; - __u64 offset; /* 64 bits */ - __u32 fd; -}; - -asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg) -{ - int error = -EFAULT; - struct file * file = NULL; - struct mmap_arg_struct64 a; - unsigned long pgoff; - - if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; - - if ((long)a.offset & ~PAGE_MASK) - return -EINVAL; - - pgoff = a.offset >> PAGE_SHIFT; - if ((a.offset >> PAGE_SHIFT) != pgoff) - return -EINVAL; - - if (!(a.flags & MAP_ANONYMOUS)) { - error = -EBADF; - file = fget(a.fd); - if (!file) - goto out; - } - a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); - up_write(¤t->mm->mmap_sem); - if (file) - fput(file); -out: - return error; -} -#endif - struct sel_arg_struct { unsigned long n; fd_set *inp, *outp, *exp; --- linux-2.6.24.orig/arch/h8300/kernel/syscalls.S +++ linux-2.6.24/arch/h8300/kernel/syscalls.S @@ -206,7 +206,7 @@ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ .long SYMBOL_NAME(sys_vfork) /* 190 */ .long SYMBOL_NAME(sys_getrlimit) - .long SYMBOL_NAME(sys_mmap2) + .long SYMBOL_NAME(sys_mmap_pgoff) .long SYMBOL_NAME(sys_truncate64) .long SYMBOL_NAME(sys_ftruncate64) .long SYMBOL_NAME(sys_stat64) /* 195 */ --- linux-2.6.24.orig/arch/xtensa/kernel/syscall.c +++ linux-2.6.24/arch/xtensa/kernel/syscall.c @@ -57,31 +57,6 @@ return error; } - -asmlinkage long xtensa_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - int error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg) { unsigned long ret; --- linux-2.6.24.orig/arch/parisc/kernel/signal.c +++ linux-2.6.24/arch/parisc/kernel/signal.c @@ -534,7 +534,8 @@ * Flushing one cacheline is cheap. * "sync" on bigger (> 4 way) boxes is not. */ - flush_icache_range(regs->gr[30], regs->gr[30] + 4); + flush_user_dcache_range(regs->gr[30], regs->gr[30] + 4); + flush_user_icache_range(regs->gr[30], regs->gr[30] + 4); regs->gr[31] = regs->gr[30] + 8; /* Preserve original r28. */ --- linux-2.6.24.orig/arch/parisc/kernel/pdc_cons.c +++ linux-2.6.24/arch/parisc/kernel/pdc_cons.c @@ -52,10 +52,18 @@ #include #include /* for iodc_call() proto and friends */ +static spinlock_t pdc_console_lock = SPIN_LOCK_UNLOCKED; static void pdc_console_write(struct console *co, const char *s, unsigned count) { - pdc_iodc_print(s, count); + int i = 0; + unsigned long flags; + + spin_lock_irqsave(&pdc_console_lock, flags); + do { + i += pdc_iodc_print(s + i, count - i); + } while (i < count); + spin_unlock_irqrestore(&pdc_console_lock, flags); } void pdc_printf(const char *fmt, ...) @@ -73,7 +81,14 @@ int pdc_console_poll_key(struct console *co) { - return pdc_iodc_getc(); + int c; + unsigned long flags; + + spin_lock_irqsave(&pdc_console_lock, flags); + c = pdc_iodc_getc(); + spin_unlock_irqrestore(&pdc_console_lock, flags); + + return c; } static int pdc_console_setup(struct console *co, char *options) --- linux-2.6.24.orig/arch/parisc/kernel/sys_parisc.c +++ linux-2.6.24/arch/parisc/kernel/sys_parisc.c @@ -123,37 +123,14 @@ return addr; } -static unsigned long do_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, unsigned long fd, - unsigned long pgoff) -{ - struct file * file = NULL; - unsigned long error = -EBADF; - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file != NULL) - fput(file); -out: - return error; -} - asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) { /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE we have. */ - return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12)); + return sys_mmap_pgoff(addr, len, prot, flags, fd, + pgoff >> (PAGE_SHIFT - 12)); } asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, @@ -161,7 +138,8 @@ unsigned long offset) { if (!(offset & ~PAGE_MASK)) { - return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + return sys_mmap_pgoff(addr, len, prot, flags, fd, + offset >> PAGE_SHIFT); } else { return -EINVAL; } --- linux-2.6.24.orig/arch/parisc/kernel/firmware.c +++ linux-2.6.24/arch/parisc/kernel/firmware.c @@ -1080,6 +1080,9 @@ spin_unlock_irqrestore(&pdc_lock, flags); } +/* locked by pdc_console_lock */ +static int __attribute__((aligned(8))) iodc_retbuf[32]; +static char __attribute__((aligned(64))) iodc_dbuf[4096]; /** * pdc_iodc_print - Console print using IODC. @@ -1091,24 +1094,20 @@ * Since the HP console requires CR+LF to perform a 'newline', we translate * "\n" to "\r\n". */ -int pdc_iodc_print(unsigned char *str, unsigned count) +int pdc_iodc_print(const unsigned char *str, unsigned count) { - /* XXX Should we spinlock posx usage */ static int posx; /* for simple TAB-Simulation... */ - int __attribute__((aligned(8))) iodc_retbuf[32]; - char __attribute__((aligned(64))) iodc_dbuf[4096]; unsigned int i; unsigned long flags; - memset(iodc_dbuf, 0, 4096); - for (i = 0; i < count && i < 2048;) { + for (i = 0; i < count && i < 79;) { switch(str[i]) { case '\n': iodc_dbuf[i+0] = '\r'; iodc_dbuf[i+1] = '\n'; i += 2; posx = 0; - break; + goto print; case '\t': while (posx & 7) { iodc_dbuf[i] = ' '; @@ -1124,6 +1123,16 @@ } } + /* if we're at the end of line, and not already inserting a newline, + * insert one anyway. iodc console doesn't claim to support >79 char + * lines. don't account for this in the return value. + */ + if (i == 79 && iodc_dbuf[i-1] != '\n') { + iodc_dbuf[i+0] = '\r'; + iodc_dbuf[i+1] = '\n'; + } + +print: spin_lock_irqsave(&pdc_lock, flags); real32_call(PAGE0->mem_cons.iodc_io, (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT, @@ -1142,11 +1151,9 @@ */ int pdc_iodc_getc(void) { - unsigned long flags; - static int __attribute__((aligned(8))) iodc_retbuf[32]; - static char __attribute__((aligned(64))) iodc_dbuf[4096]; int ch; int status; + unsigned long flags; /* Bail if no console input device. */ if (!PAGE0->mem_kbd.iodc_io) --- linux-2.6.24.orig/arch/blackfin/mach-common/entry.S +++ linux-2.6.24/arch/blackfin/mach-common/entry.S @@ -1199,7 +1199,7 @@ .long _sys_ni_syscall /* streams2 */ .long _sys_vfork /* 190 */ .long _sys_getrlimit - .long _sys_mmap2 + .long _sys_mmap_pgoff .long _sys_truncate64 .long _sys_ftruncate64 .long _sys_stat64 /* 195 */ --- linux-2.6.24.orig/arch/blackfin/kernel/sys_bfin.c +++ linux-2.6.24/arch/blackfin/kernel/sys_bfin.c @@ -62,39 +62,6 @@ return error; } -/* common code for old and new mmaps */ -static inline long -do_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - int error = -EBADF; - struct file *file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); - out: - return error; -} - -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - return do_mmap2(addr, len, prot, flags, fd, pgoff); -} - asmlinkage int sys_getpagesize(void) { return PAGE_SIZE; --- linux-2.6.24.orig/arch/cris/kernel/sys_cris.c +++ linux-2.6.24/arch/cris/kernel/sys_cris.c @@ -46,31 +46,6 @@ return error; } -/* common code for old and new mmaps */ -static inline long -do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flags, unsigned long fd, unsigned long pgoff) -{ - int error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - asmlinkage unsigned long old_mmap(unsigned long __user *args) { unsigned long buffer[6]; @@ -83,7 +58,7 @@ if (buffer[5] & ~PAGE_MASK) /* verify that offset is on page boundary */ goto out; - err = do_mmap2(buffer[0], buffer[1], buffer[2], buffer[3], + err = sys_mmap_pgoff(buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5] >> PAGE_SHIFT); out: return err; @@ -93,7 +68,8 @@ sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) { - return do_mmap2(addr, len, prot, flags, fd, pgoff); + /* bug(?): 8Kb pages here */ + return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); } /* --- linux-2.6.24.orig/arch/m68knommu/kernel/sys_m68k.c +++ linux-2.6.24/arch/m68knommu/kernel/sys_m68k.c @@ -45,39 +45,6 @@ return error; } -/* common code for old and new mmaps */ -static inline long do_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - int error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - return do_mmap2(addr, len, prot, flags, fd, pgoff); -} - /* * Perform the select(nd, in, out, ex, tv) and mmap() system * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to @@ -106,9 +73,8 @@ if (a.offset & ~PAGE_MASK) goto out; - a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); + error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, + a.offset >> PAGE_SHIFT); out: return error; } --- linux-2.6.24.orig/arch/m68knommu/kernel/syscalltable.S +++ linux-2.6.24/arch/m68knommu/kernel/syscalltable.S @@ -210,7 +210,7 @@ .long sys_ni_syscall /* streams2 */ .long sys_vfork /* 190 */ .long sys_getrlimit - .long sys_mmap2 + .long sys_mmap_pgoff .long sys_truncate64 .long sys_ftruncate64 .long sys_stat64 /* 195 */ --- linux-2.6.24.orig/arch/sh/kernel/sys_sh.c +++ linux-2.6.24/arch/sh/kernel/sys_sh.c @@ -139,44 +139,20 @@ } #endif /* CONFIG_MMU */ -static inline long -do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flags, int fd, unsigned long pgoff) -{ - int error = -EBADF; - struct file *file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - asmlinkage int old_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, int fd, unsigned long off) { if (off & ~PAGE_MASK) return -EINVAL; - return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT); + return sys_mmap_pgoff(addr, len, prot, flags, fd, off>>PAGE_SHIFT); } asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) { - return do_mmap2(addr, len, prot, flags, fd, pgoff); + return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); } /* --- linux-2.6.24.orig/arch/powerpc/kernel/misc_32.S +++ linux-2.6.24/arch/powerpc/kernel/misc_32.S @@ -756,6 +756,27 @@ or r4,r4,r7 # LSW |= t2 blr +/* + * __ucmpdi2: 64-bit comparison + * + * R3/R4 has 64 bit value A + * R5/R6 has 64 bit value B + * result in R3: 0 for A < B + * 1 for A == B + * 2 for A > B + */ +_GLOBAL(__ucmpdi2) + cmplw r7,r3,r5 # compare high words + li r3,0 + blt r7,2f # a < b ... return 0 + bgt r7,1f # a > b ... return 2 + cmplw r6,r4,r6 # compare low words + blt r6,2f # a < b ... return 0 + li r3,1 + ble r6,2f # a = b ... return 1 +1: li r3,2 +2: blr + _GLOBAL(abs) srawi r4,r3,31 xor r3,r3,r4 --- linux-2.6.24.orig/arch/powerpc/kernel/syscalls.c +++ linux-2.6.24/arch/powerpc/kernel/syscalls.c @@ -158,7 +158,6 @@ unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off, int shift) { - struct file * file = NULL; unsigned long ret = -EINVAL; if (shift) { @@ -166,20 +165,8 @@ goto out; off >>= shift; } - - ret = -EBADF; - if (!(flags & MAP_ANONYMOUS)) { - if (!(file = fget(fd))) - goto out; - } - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down_write(¤t->mm->mmap_sem); - ret = do_mmap_pgoff(file, addr, len, prot, flags, off); - up_write(¤t->mm->mmap_sem); - if (file) - fput(file); + ret = sys_mmap_pgoff(addr, len, prot, flags, fd, off); out: return ret; } --- linux-2.6.24.orig/arch/powerpc/kernel/vdso.c +++ linux-2.6.24/arch/powerpc/kernel/vdso.c @@ -141,7 +141,7 @@ printk("kpg: %p (c:%d,f:%08lx)", __va(page_to_pfn(pg) << PAGE_SHIFT), page_count(pg), pg->flags); - if (upg/* && pg != upg*/) { + if (upg && !IS_ERR(upg) /* && pg != upg*/) { printk(" upg: %p (c:%d,f:%08lx)", __va(page_to_pfn(upg) << PAGE_SHIFT), page_count(upg), --- linux-2.6.24.orig/arch/powerpc/kernel/ppc_ksyms.c +++ linux-2.6.24/arch/powerpc/kernel/ppc_ksyms.c @@ -145,9 +145,11 @@ long long __ashrdi3(long long, int); long long __ashldi3(long long, int); long long __lshrdi3(long long, int); +int __ucmpdi2(uint64_t, uint64_t); EXPORT_SYMBOL(__ashrdi3); EXPORT_SYMBOL(__ashldi3); EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__ucmpdi2); #endif EXPORT_SYMBOL(memcpy); --- linux-2.6.24.orig/arch/powerpc/platforms/chrp/pci.c +++ linux-2.6.24/arch/powerpc/platforms/chrp/pci.c @@ -354,7 +354,7 @@ * mode as well. The same fixup must be done to the class-code property in * the IDE node /pci@80000000/ide@C,1 */ -static void __devinit chrp_pci_fixup_vt8231_ata(struct pci_dev *viaide) +static void chrp_pci_fixup_vt8231_ata(struct pci_dev *viaide) { u8 progif; struct pci_dev *viaisa; @@ -375,4 +375,4 @@ pci_dev_put(viaisa); } -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, chrp_pci_fixup_vt8231_ata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, chrp_pci_fixup_vt8231_ata); --- linux-2.6.24.orig/arch/powerpc/platforms/chrp/setup.c +++ linux-2.6.24/arch/powerpc/platforms/chrp/setup.c @@ -115,7 +115,7 @@ seq_printf(m, "machine\t\t: CHRP %s\n", model); /* longtrail (goldengate) stuff */ - if (!strncmp(model, "IBM,LongTrail", 13)) { + if (model && !strncmp(model, "IBM,LongTrail", 13)) { /* VLSI VAS96011/12 `Golden Gate 2' */ /* Memory banks */ sdramen = (in_le32(gg2_pci_config_base + GG2_PCI_DRAM_CTRL) @@ -203,15 +203,20 @@ static void __init sio_init(void) { struct device_node *root; + const char *model; - if ((root = of_find_node_by_path("/")) && - !strncmp(of_get_property(root, "model", NULL), - "IBM,LongTrail", 13)) { + root = of_find_node_by_path("/"); + if (!root) + return; + + model = of_get_property(root, "model", NULL); + if (model && !strncmp(model, "IBM,LongTrail", 13)) { /* logical device 0 (KBC/Keyboard) */ sio_fixup_irq("keyboard", 0, 1, 2); /* select logical device 1 (KBC/Mouse) */ sio_fixup_irq("mouse", 1, 12, 2); } + of_node_put(root); } --- linux-2.6.24.orig/arch/powerpc/platforms/powermac/feature.c +++ linux-2.6.24/arch/powerpc/platforms/powermac/feature.c @@ -2565,6 +2565,8 @@ /* Locate core99 Uni-N */ uninorth_node = of_find_node_by_name(NULL, "uni-n"); + uninorth_maj = 1; + /* Locate G5 u3 */ if (uninorth_node == NULL) { uninorth_node = of_find_node_by_name(NULL, "u3"); @@ -2575,8 +2577,10 @@ uninorth_node = of_find_node_by_name(NULL, "u4"); uninorth_maj = 4; } - if (uninorth_node == NULL) + if (uninorth_node == NULL) { + uninorth_maj = 0; return; + } addrp = of_get_property(uninorth_node, "reg", NULL); if (addrp == NULL) @@ -3029,3 +3033,8 @@ pmac_agp_resume(pmac_agp_bridge); } EXPORT_SYMBOL(pmac_resume_agp_for_card); + +int pmac_get_uninorth_variant(void) +{ + return uninorth_maj; +} --- linux-2.6.24.orig/arch/powerpc/platforms/powermac/setup.c +++ linux-2.6.24/arch/powerpc/platforms/powermac/setup.c @@ -584,12 +584,10 @@ DMA_MODE_READ = 1; DMA_MODE_WRITE = 2; -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -#ifdef CONFIG_BLK_DEV_IDE_PMAC +#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports; ppc_ide_md.default_io_base = pmac_ide_get_base; -#endif /* CONFIG_BLK_DEV_IDE_PMAC */ -#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ +#endif #endif /* CONFIG_PPC32 */ --- linux-2.6.24.orig/virt/kvm/kvm_main.c +++ linux-2.6.24/virt/kvm/kvm_main.c @@ -0,0 +1,1451 @@ +/* + * Kernel-based Virtual Machine driver for Linux + * + * This module enables machines with Intel VT-x extensions to run virtual + * machines without emulation or binary translation. + * + * Copyright (C) 2006 Qumranet, Inc. + * + * Authors: + * Avi Kivity + * Yaniv Kamay + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "iodev.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +MODULE_AUTHOR("Qumranet"); +MODULE_LICENSE("GPL"); + +DEFINE_SPINLOCK(kvm_lock); +LIST_HEAD(vm_list); + +static cpumask_t cpus_hardware_enabled; + +struct kmem_cache *kvm_vcpu_cache; +EXPORT_SYMBOL_GPL(kvm_vcpu_cache); + +static __read_mostly struct preempt_ops kvm_preempt_ops; + +static struct dentry *debugfs_dir; + +static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl, + unsigned long arg); + +static inline int valid_vcpu(int n) +{ + return likely(n >= 0 && n < KVM_MAX_VCPUS); +} + +/* + * Switches to specified vcpu, until a matching vcpu_put() + */ +void vcpu_load(struct kvm_vcpu *vcpu) +{ + int cpu; + + mutex_lock(&vcpu->mutex); + cpu = get_cpu(); + preempt_notifier_register(&vcpu->preempt_notifier); + kvm_arch_vcpu_load(vcpu, cpu); + put_cpu(); +} + +void vcpu_put(struct kvm_vcpu *vcpu) +{ + preempt_disable(); + kvm_arch_vcpu_put(vcpu); + preempt_notifier_unregister(&vcpu->preempt_notifier); + preempt_enable(); + mutex_unlock(&vcpu->mutex); +} + +static void ack_flush(void *_completed) +{ +} + +void kvm_flush_remote_tlbs(struct kvm *kvm) +{ + int i, cpu; + cpumask_t cpus; + struct kvm_vcpu *vcpu; + + cpus_clear(cpus); + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = kvm->vcpus[i]; + if (!vcpu) + continue; + if (test_and_set_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests)) + continue; + cpu = vcpu->cpu; + if (cpu != -1 && cpu != raw_smp_processor_id()) + cpu_set(cpu, cpus); + } + if (cpus_empty(cpus)) + return; + ++kvm->stat.remote_tlb_flush; + smp_call_function_mask(cpus, ack_flush, NULL, 1); +} + +void kvm_reload_remote_mmus(struct kvm *kvm) +{ + int i, cpu; + cpumask_t cpus; + struct kvm_vcpu *vcpu; + + cpus_clear(cpus); + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = kvm->vcpus[i]; + if (!vcpu) + continue; + if (test_and_set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) + continue; + cpu = vcpu->cpu; + if (cpu != -1 && cpu != raw_smp_processor_id()) + cpu_set(cpu, cpus); + } + if (cpus_empty(cpus)) + return; + smp_call_function_mask(cpus, ack_flush, NULL, 1); +} + + +int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) +{ + struct page *page; + int r; + + mutex_init(&vcpu->mutex); + vcpu->cpu = -1; + vcpu->kvm = kvm; + vcpu->vcpu_id = id; + init_waitqueue_head(&vcpu->wq); + + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) { + r = -ENOMEM; + goto fail; + } + vcpu->run = page_address(page); + + r = kvm_arch_vcpu_init(vcpu); + if (r < 0) + goto fail_free_run; + return 0; + +fail_free_run: + free_page((unsigned long)vcpu->run); +fail: + return r; +} +EXPORT_SYMBOL_GPL(kvm_vcpu_init); + +void kvm_vcpu_uninit(struct kvm_vcpu *vcpu) +{ + kvm_arch_vcpu_uninit(vcpu); + free_page((unsigned long)vcpu->run); +} +EXPORT_SYMBOL_GPL(kvm_vcpu_uninit); + +static struct kvm *kvm_create_vm(void) +{ + struct kvm *kvm = kvm_arch_create_vm(); + + if (IS_ERR(kvm)) + goto out; + + kvm->mm = current->mm; + atomic_inc(&kvm->mm->mm_count); + spin_lock_init(&kvm->mmu_lock); + kvm_io_bus_init(&kvm->pio_bus); + mutex_init(&kvm->lock); + kvm_io_bus_init(&kvm->mmio_bus); + init_rwsem(&kvm->slots_lock); + spin_lock(&kvm_lock); + list_add(&kvm->vm_list, &vm_list); + spin_unlock(&kvm_lock); +out: + return kvm; +} + +/* + * Free any memory in @free but not in @dont. + */ +static void kvm_free_physmem_slot(struct kvm_memory_slot *free, + struct kvm_memory_slot *dont) +{ + if (!dont || free->rmap != dont->rmap) + vfree(free->rmap); + + if (!dont || free->dirty_bitmap != dont->dirty_bitmap) + vfree(free->dirty_bitmap); + + if (!dont || free->lpage_info != dont->lpage_info) + vfree(free->lpage_info); + + free->npages = 0; + free->dirty_bitmap = NULL; + free->rmap = NULL; + free->lpage_info = NULL; +} + +void kvm_free_physmem(struct kvm *kvm) +{ + int i; + + for (i = 0; i < kvm->nmemslots; ++i) + kvm_free_physmem_slot(&kvm->memslots[i], NULL); +} + +static void kvm_destroy_vm(struct kvm *kvm) +{ + struct mm_struct *mm = kvm->mm; + + spin_lock(&kvm_lock); + list_del(&kvm->vm_list); + spin_unlock(&kvm_lock); + kvm_io_bus_destroy(&kvm->pio_bus); + kvm_io_bus_destroy(&kvm->mmio_bus); + kvm_arch_destroy_vm(kvm); + mmdrop(mm); +} + +static int kvm_vm_release(struct inode *inode, struct file *filp) +{ + struct kvm *kvm = filp->private_data; + + kvm_destroy_vm(kvm); + return 0; +} + +/* + * Allocate some memory and give it an address in the guest physical address + * space. + * + * Discontiguous memory is allowed, mostly for framebuffers. + * + * Must be called holding mmap_sem for write. + */ +int __kvm_set_memory_region(struct kvm *kvm, + struct kvm_userspace_memory_region *mem, + int user_alloc) +{ + int r; + gfn_t base_gfn; + unsigned long npages; + unsigned long i; + struct kvm_memory_slot *memslot; + struct kvm_memory_slot old, new; + + r = -EINVAL; + /* General sanity checks */ + if (mem->memory_size & (PAGE_SIZE - 1)) + goto out; + if (mem->guest_phys_addr & (PAGE_SIZE - 1)) + goto out; + if (mem->slot >= KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS) + goto out; + if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr) + goto out; + + memslot = &kvm->memslots[mem->slot]; + base_gfn = mem->guest_phys_addr >> PAGE_SHIFT; + npages = mem->memory_size >> PAGE_SHIFT; + + if (!npages) + mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES; + + new = old = *memslot; + + new.base_gfn = base_gfn; + new.npages = npages; + new.flags = mem->flags; + + /* Disallow changing a memory slot's size. */ + r = -EINVAL; + if (npages && old.npages && npages != old.npages) + goto out_free; + + /* Check for overlaps */ + r = -EEXIST; + for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { + struct kvm_memory_slot *s = &kvm->memslots[i]; + + if (s == memslot) + continue; + if (!((base_gfn + npages <= s->base_gfn) || + (base_gfn >= s->base_gfn + s->npages))) + goto out_free; + } + + /* Free page dirty bitmap if unneeded */ + if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES)) + new.dirty_bitmap = NULL; + + r = -ENOMEM; + + /* Allocate if a slot is being created */ + if (npages && !new.rmap) { + new.rmap = vmalloc(npages * sizeof(struct page *)); + + if (!new.rmap) + goto out_free; + + memset(new.rmap, 0, npages * sizeof(*new.rmap)); + + new.user_alloc = user_alloc; + new.userspace_addr = mem->userspace_addr; + } + if (npages && !new.lpage_info) { + int largepages = npages / KVM_PAGES_PER_HPAGE; + if (npages % KVM_PAGES_PER_HPAGE) + largepages++; + new.lpage_info = vmalloc(largepages * sizeof(*new.lpage_info)); + + if (!new.lpage_info) + goto out_free; + + memset(new.lpage_info, 0, largepages * sizeof(*new.lpage_info)); + + if (base_gfn % KVM_PAGES_PER_HPAGE) + new.lpage_info[0].write_count = 1; + if ((base_gfn+npages) % KVM_PAGES_PER_HPAGE) + new.lpage_info[largepages-1].write_count = 1; + } + + /* Allocate page dirty bitmap if needed */ + if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) { + unsigned dirty_bytes = ALIGN(npages, BITS_PER_LONG) / 8; + + new.dirty_bitmap = vmalloc(dirty_bytes); + if (!new.dirty_bitmap) + goto out_free; + memset(new.dirty_bitmap, 0, dirty_bytes); + } + + if (mem->slot >= kvm->nmemslots) + kvm->nmemslots = mem->slot + 1; + + *memslot = new; + + r = kvm_arch_set_memory_region(kvm, mem, old, user_alloc); + if (r) { + *memslot = old; + goto out_free; + } + + kvm_free_physmem_slot(&old, &new); + return 0; + +out_free: + kvm_free_physmem_slot(&new, &old); +out: + return r; + +} +EXPORT_SYMBOL_GPL(__kvm_set_memory_region); + +int kvm_set_memory_region(struct kvm *kvm, + struct kvm_userspace_memory_region *mem, + int user_alloc) +{ + int r; + + down_write(&kvm->slots_lock); + r = __kvm_set_memory_region(kvm, mem, user_alloc); + up_write(&kvm->slots_lock); + return r; +} +EXPORT_SYMBOL_GPL(kvm_set_memory_region); + +int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, + struct + kvm_userspace_memory_region *mem, + int user_alloc) +{ + if (mem->slot >= KVM_MEMORY_SLOTS) + return -EINVAL; + return kvm_set_memory_region(kvm, mem, user_alloc); +} + +int kvm_get_dirty_log(struct kvm *kvm, + struct kvm_dirty_log *log, int *is_dirty) +{ + struct kvm_memory_slot *memslot; + int r, i; + int n; + unsigned long any = 0; + + r = -EINVAL; + if (log->slot >= KVM_MEMORY_SLOTS) + goto out; + + memslot = &kvm->memslots[log->slot]; + r = -ENOENT; + if (!memslot->dirty_bitmap) + goto out; + + n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; + + for (i = 0; !any && i < n/sizeof(long); ++i) + any = memslot->dirty_bitmap[i]; + + r = -EFAULT; + if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n)) + goto out; + + if (any) + *is_dirty = 1; + + r = 0; +out: + return r; +} + +int is_error_page(struct page *page) +{ + return page == bad_page; +} +EXPORT_SYMBOL_GPL(is_error_page); + +static inline unsigned long bad_hva(void) +{ + return PAGE_OFFSET; +} + +int kvm_is_error_hva(unsigned long addr) +{ + return addr == bad_hva(); +} +EXPORT_SYMBOL_GPL(kvm_is_error_hva); + +static struct kvm_memory_slot *__gfn_to_memslot(struct kvm *kvm, gfn_t gfn) +{ + int i; + + for (i = 0; i < kvm->nmemslots; ++i) { + struct kvm_memory_slot *memslot = &kvm->memslots[i]; + + if (gfn >= memslot->base_gfn + && gfn < memslot->base_gfn + memslot->npages) + return memslot; + } + return NULL; +} + +struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) +{ + gfn = unalias_gfn(kvm, gfn); + return __gfn_to_memslot(kvm, gfn); +} + +int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn) +{ + int i; + + gfn = unalias_gfn(kvm, gfn); + for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { + struct kvm_memory_slot *memslot = &kvm->memslots[i]; + + if (gfn >= memslot->base_gfn + && gfn < memslot->base_gfn + memslot->npages) + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(kvm_is_visible_gfn); + +unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) +{ + struct kvm_memory_slot *slot; + + gfn = unalias_gfn(kvm, gfn); + slot = __gfn_to_memslot(kvm, gfn); + if (!slot) + return bad_hva(); + return (slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE); +} + +/* + * Requires current->mm->mmap_sem to be held + */ +struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) +{ + struct page *page[1]; + unsigned long addr; + int npages; + + might_sleep(); + + addr = gfn_to_hva(kvm, gfn); + if (kvm_is_error_hva(addr)) { + get_page(bad_page); + return bad_page; + } + + npages = get_user_pages(current, current->mm, addr, 1, 1, 1, page, + NULL); + + if (npages != 1) { + get_page(bad_page); + return bad_page; + } + + return page[0]; +} + +EXPORT_SYMBOL_GPL(gfn_to_page); + +void kvm_release_page_clean(struct page *page) +{ + put_page(page); +} +EXPORT_SYMBOL_GPL(kvm_release_page_clean); + +void kvm_release_page_dirty(struct page *page) +{ + if (!PageReserved(page)) + SetPageDirty(page); + put_page(page); +} +EXPORT_SYMBOL_GPL(kvm_release_page_dirty); + +static int next_segment(unsigned long len, int offset) +{ + if (len > PAGE_SIZE - offset) + return PAGE_SIZE - offset; + else + return len; +} + +int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset, + int len) +{ + int r; + unsigned long addr; + + addr = gfn_to_hva(kvm, gfn); + if (kvm_is_error_hva(addr)) + return -EFAULT; + r = copy_from_user(data, (void __user *)addr + offset, len); + if (r) + return -EFAULT; + return 0; +} +EXPORT_SYMBOL_GPL(kvm_read_guest_page); + +int kvm_read_guest(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len) +{ + gfn_t gfn = gpa >> PAGE_SHIFT; + int seg; + int offset = offset_in_page(gpa); + int ret; + + while ((seg = next_segment(len, offset)) != 0) { + ret = kvm_read_guest_page(kvm, gfn, data, offset, seg); + if (ret < 0) + return ret; + offset = 0; + len -= seg; + data += seg; + ++gfn; + } + return 0; +} +EXPORT_SYMBOL_GPL(kvm_read_guest); + +int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data, + unsigned long len) +{ + int r; + unsigned long addr; + gfn_t gfn = gpa >> PAGE_SHIFT; + int offset = offset_in_page(gpa); + + addr = gfn_to_hva(kvm, gfn); + if (kvm_is_error_hva(addr)) + return -EFAULT; + pagefault_disable(); + r = __copy_from_user_inatomic(data, (void __user *)addr + offset, len); + pagefault_enable(); + if (r) + return -EFAULT; + return 0; +} +EXPORT_SYMBOL(kvm_read_guest_atomic); + +int kvm_write_guest_page(struct kvm *kvm, gfn_t gfn, const void *data, + int offset, int len) +{ + int r; + unsigned long addr; + + addr = gfn_to_hva(kvm, gfn); + if (kvm_is_error_hva(addr)) + return -EFAULT; + r = copy_to_user((void __user *)addr + offset, data, len); + if (r) + return -EFAULT; + mark_page_dirty(kvm, gfn); + return 0; +} +EXPORT_SYMBOL_GPL(kvm_write_guest_page); + +int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data, + unsigned long len) +{ + gfn_t gfn = gpa >> PAGE_SHIFT; + int seg; + int offset = offset_in_page(gpa); + int ret; + + while ((seg = next_segment(len, offset)) != 0) { + ret = kvm_write_guest_page(kvm, gfn, data, offset, seg); + if (ret < 0) + return ret; + offset = 0; + len -= seg; + data += seg; + ++gfn; + } + return 0; +} + +int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len) +{ + return kvm_write_guest_page(kvm, gfn, empty_zero_page, offset, len); +} +EXPORT_SYMBOL_GPL(kvm_clear_guest_page); + +int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len) +{ + gfn_t gfn = gpa >> PAGE_SHIFT; + int seg; + int offset = offset_in_page(gpa); + int ret; + + while ((seg = next_segment(len, offset)) != 0) { + ret = kvm_clear_guest_page(kvm, gfn, offset, seg); + if (ret < 0) + return ret; + offset = 0; + len -= seg; + ++gfn; + } + return 0; +} +EXPORT_SYMBOL_GPL(kvm_clear_guest); + +void mark_page_dirty(struct kvm *kvm, gfn_t gfn) +{ + struct kvm_memory_slot *memslot; + + gfn = unalias_gfn(kvm, gfn); + memslot = __gfn_to_memslot(kvm, gfn); + if (memslot && memslot->dirty_bitmap) { + unsigned long rel_gfn = gfn - memslot->base_gfn; + + /* avoid RMW */ + if (!test_bit(rel_gfn, memslot->dirty_bitmap)) + set_bit(rel_gfn, memslot->dirty_bitmap); + } +} + +/* + * The vCPU has executed a HLT instruction with in-kernel mode enabled. + */ +void kvm_vcpu_block(struct kvm_vcpu *vcpu) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&vcpu->wq, &wait); + + /* + * We will block until either an interrupt or a signal wakes us up + */ + while (!kvm_cpu_has_interrupt(vcpu) + && !signal_pending(current) + && !kvm_arch_vcpu_runnable(vcpu)) { + set_current_state(TASK_INTERRUPTIBLE); + vcpu_put(vcpu); + schedule(); + vcpu_load(vcpu); + } + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&vcpu->wq, &wait); +} + +void kvm_resched(struct kvm_vcpu *vcpu) +{ + if (!need_resched()) + return; + cond_resched(); +} +EXPORT_SYMBOL_GPL(kvm_resched); + +static int kvm_vcpu_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct kvm_vcpu *vcpu = vma->vm_file->private_data; + struct page *page; + + if (vmf->pgoff == 0) + page = virt_to_page(vcpu->run); +#ifdef CONFIG_X86 + else if (vmf->pgoff == KVM_PIO_PAGE_OFFSET) + page = virt_to_page(vcpu->arch.pio_data); +#endif + else + return VM_FAULT_SIGBUS; + get_page(page); + vmf->page = page; + return 0; +} + +static struct vm_operations_struct kvm_vcpu_vm_ops = { + .fault = kvm_vcpu_fault, +}; + +static int kvm_vcpu_mmap(struct file *file, struct vm_area_struct *vma) +{ + vma->vm_ops = &kvm_vcpu_vm_ops; + return 0; +} + +static int kvm_vcpu_release(struct inode *inode, struct file *filp) +{ + struct kvm_vcpu *vcpu = filp->private_data; + + fput(vcpu->kvm->filp); + return 0; +} + +static const struct file_operations kvm_vcpu_fops = { + .release = kvm_vcpu_release, + .unlocked_ioctl = kvm_vcpu_ioctl, + .compat_ioctl = kvm_vcpu_ioctl, + .mmap = kvm_vcpu_mmap, +}; + +/* + * Allocates an inode for the vcpu. + */ +static int create_vcpu_fd(struct kvm_vcpu *vcpu) +{ + int fd, r; + struct inode *inode; + struct file *file; + + r = anon_inode_getfd(&fd, &inode, &file, + "kvm-vcpu", &kvm_vcpu_fops, vcpu); + if (r) + return r; + atomic_inc(&vcpu->kvm->filp->f_count); + return fd; +} + +/* + * Creates some virtual cpus. Good luck creating more than one. + */ +static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) +{ + int r; + struct kvm_vcpu *vcpu; + + if (!valid_vcpu(n)) + return -EINVAL; + + vcpu = kvm_arch_vcpu_create(kvm, n); + if (IS_ERR(vcpu)) + return PTR_ERR(vcpu); + + preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops); + + r = kvm_arch_vcpu_setup(vcpu); + if (r) + goto vcpu_destroy; + + mutex_lock(&kvm->lock); + if (kvm->vcpus[n]) { + r = -EEXIST; + mutex_unlock(&kvm->lock); + goto vcpu_destroy; + } + kvm->vcpus[n] = vcpu; + mutex_unlock(&kvm->lock); + + /* Now it's all set up, let userspace reach it */ + r = create_vcpu_fd(vcpu); + if (r < 0) + goto unlink; + return r; + +unlink: + mutex_lock(&kvm->lock); + kvm->vcpus[n] = NULL; + mutex_unlock(&kvm->lock); +vcpu_destroy: + kvm_arch_vcpu_destroy(vcpu); + return r; +} + +static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset) +{ + if (sigset) { + sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP)); + vcpu->sigset_active = 1; + vcpu->sigset = *sigset; + } else + vcpu->sigset_active = 0; + return 0; +} + +static long kvm_vcpu_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + struct kvm_vcpu *vcpu = filp->private_data; + void __user *argp = (void __user *)arg; + int r; + + if (vcpu->kvm->mm != current->mm) + return -EIO; + switch (ioctl) { + case KVM_RUN: + r = -EINVAL; + if (arg) + goto out; + r = kvm_arch_vcpu_ioctl_run(vcpu, vcpu->run); + break; + case KVM_GET_REGS: { + struct kvm_regs kvm_regs; + + memset(&kvm_regs, 0, sizeof kvm_regs); + r = kvm_arch_vcpu_ioctl_get_regs(vcpu, &kvm_regs); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &kvm_regs, sizeof kvm_regs)) + goto out; + r = 0; + break; + } + case KVM_SET_REGS: { + struct kvm_regs kvm_regs; + + r = -EFAULT; + if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs)) + goto out; + r = kvm_arch_vcpu_ioctl_set_regs(vcpu, &kvm_regs); + if (r) + goto out; + r = 0; + break; + } + case KVM_GET_SREGS: { + struct kvm_sregs kvm_sregs; + + memset(&kvm_sregs, 0, sizeof kvm_sregs); + r = kvm_arch_vcpu_ioctl_get_sregs(vcpu, &kvm_sregs); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &kvm_sregs, sizeof kvm_sregs)) + goto out; + r = 0; + break; + } + case KVM_SET_SREGS: { + struct kvm_sregs kvm_sregs; + + r = -EFAULT; + if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs)) + goto out; + r = kvm_arch_vcpu_ioctl_set_sregs(vcpu, &kvm_sregs); + if (r) + goto out; + r = 0; + break; + } + case KVM_TRANSLATE: { + struct kvm_translation tr; + + r = -EFAULT; + if (copy_from_user(&tr, argp, sizeof tr)) + goto out; + r = kvm_arch_vcpu_ioctl_translate(vcpu, &tr); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &tr, sizeof tr)) + goto out; + r = 0; + break; + } + case KVM_DEBUG_GUEST: { + struct kvm_debug_guest dbg; + + r = -EFAULT; + if (copy_from_user(&dbg, argp, sizeof dbg)) + goto out; + r = kvm_arch_vcpu_ioctl_debug_guest(vcpu, &dbg); + if (r) + goto out; + r = 0; + break; + } + case KVM_SET_SIGNAL_MASK: { + struct kvm_signal_mask __user *sigmask_arg = argp; + struct kvm_signal_mask kvm_sigmask; + sigset_t sigset, *p; + + p = NULL; + if (argp) { + r = -EFAULT; + if (copy_from_user(&kvm_sigmask, argp, + sizeof kvm_sigmask)) + goto out; + r = -EINVAL; + if (kvm_sigmask.len != sizeof sigset) + goto out; + r = -EFAULT; + if (copy_from_user(&sigset, sigmask_arg->sigset, + sizeof sigset)) + goto out; + p = &sigset; + } + r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset); + break; + } + case KVM_GET_FPU: { + struct kvm_fpu fpu; + + memset(&fpu, 0, sizeof fpu); + r = kvm_arch_vcpu_ioctl_get_fpu(vcpu, &fpu); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &fpu, sizeof fpu)) + goto out; + r = 0; + break; + } + case KVM_SET_FPU: { + struct kvm_fpu fpu; + + r = -EFAULT; + if (copy_from_user(&fpu, argp, sizeof fpu)) + goto out; + r = kvm_arch_vcpu_ioctl_set_fpu(vcpu, &fpu); + if (r) + goto out; + r = 0; + break; + } + default: + r = kvm_arch_vcpu_ioctl(filp, ioctl, arg); + } +out: + return r; +} + +static long kvm_vm_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + struct kvm *kvm = filp->private_data; + void __user *argp = (void __user *)arg; + int r; + + if (kvm->mm != current->mm) + return -EIO; + switch (ioctl) { + case KVM_CREATE_VCPU: + r = kvm_vm_ioctl_create_vcpu(kvm, arg); + if (r < 0) + goto out; + break; + case KVM_SET_USER_MEMORY_REGION: { + struct kvm_userspace_memory_region kvm_userspace_mem; + + r = -EFAULT; + if (copy_from_user(&kvm_userspace_mem, argp, + sizeof kvm_userspace_mem)) + goto out; + + r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 1); + if (r) + goto out; + break; + } + case KVM_GET_DIRTY_LOG: { + struct kvm_dirty_log log; + + r = -EFAULT; + if (copy_from_user(&log, argp, sizeof log)) + goto out; + r = kvm_vm_ioctl_get_dirty_log(kvm, &log); + if (r) + goto out; + break; + } + default: + r = kvm_arch_vm_ioctl(filp, ioctl, arg); + } +out: + return r; +} + +static int kvm_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct kvm *kvm = vma->vm_file->private_data; + struct page *page; + + if (!kvm_is_visible_gfn(kvm, vmf->pgoff)) + return VM_FAULT_SIGBUS; + page = gfn_to_page(kvm, vmf->pgoff); + if (is_error_page(page)) { + kvm_release_page_clean(page); + return VM_FAULT_SIGBUS; + } + vmf->page = page; + return 0; +} + +static struct vm_operations_struct kvm_vm_vm_ops = { + .fault = kvm_vm_fault, +}; + +static int kvm_vm_mmap(struct file *file, struct vm_area_struct *vma) +{ + vma->vm_ops = &kvm_vm_vm_ops; + return 0; +} + +static const struct file_operations kvm_vm_fops = { + .release = kvm_vm_release, + .unlocked_ioctl = kvm_vm_ioctl, + .compat_ioctl = kvm_vm_ioctl, + .mmap = kvm_vm_mmap, +}; + +static int kvm_dev_ioctl_create_vm(void) +{ + int fd, r; + struct inode *inode; + struct file *file; + struct kvm *kvm; + + kvm = kvm_create_vm(); + if (IS_ERR(kvm)) + return PTR_ERR(kvm); + r = anon_inode_getfd(&fd, &inode, &file, "kvm-vm", &kvm_vm_fops, kvm); + if (r) { + kvm_destroy_vm(kvm); + return r; + } + + kvm->filp = file; + + return fd; +} + +static long kvm_dev_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + long r = -EINVAL; + + switch (ioctl) { + case KVM_GET_API_VERSION: + r = -EINVAL; + if (arg) + goto out; + r = KVM_API_VERSION; + break; + case KVM_CREATE_VM: + r = -EINVAL; + if (arg) + goto out; + r = kvm_dev_ioctl_create_vm(); + break; + case KVM_CHECK_EXTENSION: + r = kvm_dev_ioctl_check_extension((long)argp); + break; + case KVM_GET_VCPU_MMAP_SIZE: + r = -EINVAL; + if (arg) + goto out; + r = PAGE_SIZE; /* struct kvm_run */ +#ifdef CONFIG_X86 + r += PAGE_SIZE; /* pio data page */ +#endif + break; + default: + return kvm_arch_dev_ioctl(filp, ioctl, arg); + } +out: + return r; +} + +static struct file_operations kvm_chardev_ops = { + .unlocked_ioctl = kvm_dev_ioctl, + .compat_ioctl = kvm_dev_ioctl, +}; + +static struct miscdevice kvm_dev = { + KVM_MINOR, + "kvm", + &kvm_chardev_ops, +}; + +static void hardware_enable(void *junk) +{ + int cpu = raw_smp_processor_id(); + + if (cpu_isset(cpu, cpus_hardware_enabled)) + return; + cpu_set(cpu, cpus_hardware_enabled); + kvm_arch_hardware_enable(NULL); +} + +static void hardware_disable(void *junk) +{ + int cpu = raw_smp_processor_id(); + + if (!cpu_isset(cpu, cpus_hardware_enabled)) + return; + cpu_clear(cpu, cpus_hardware_enabled); + decache_vcpus_on_cpu(cpu); + kvm_arch_hardware_disable(NULL); +} + +static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, + void *v) +{ + int cpu = (long)v; + + val &= ~CPU_TASKS_FROZEN; + switch (val) { + case CPU_DYING: + printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n", + cpu); + hardware_disable(NULL); + break; + case CPU_UP_CANCELED: + printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n", + cpu); + smp_call_function_single(cpu, hardware_disable, NULL, 0, 1); + break; + case CPU_ONLINE: + printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n", + cpu); + smp_call_function_single(cpu, hardware_enable, NULL, 0, 1); + break; + } + return NOTIFY_OK; +} + +static int kvm_reboot(struct notifier_block *notifier, unsigned long val, + void *v) +{ + if (val == SYS_RESTART) { + /* + * Some (well, at least mine) BIOSes hang on reboot if + * in vmx root mode. + */ + printk(KERN_INFO "kvm: exiting hardware virtualization\n"); + on_each_cpu(hardware_disable, NULL, 0, 1); + } + return NOTIFY_OK; +} + +static struct notifier_block kvm_reboot_notifier = { + .notifier_call = kvm_reboot, + .priority = 0, +}; + +void kvm_io_bus_init(struct kvm_io_bus *bus) +{ + memset(bus, 0, sizeof(*bus)); +} + +void kvm_io_bus_destroy(struct kvm_io_bus *bus) +{ + int i; + + for (i = 0; i < bus->dev_count; i++) { + struct kvm_io_device *pos = bus->devs[i]; + + kvm_iodevice_destructor(pos); + } +} + +struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr) +{ + int i; + + for (i = 0; i < bus->dev_count; i++) { + struct kvm_io_device *pos = bus->devs[i]; + + if (pos->in_range(pos, addr)) + return pos; + } + + return NULL; +} + +void kvm_io_bus_register_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev) +{ + BUG_ON(bus->dev_count > (NR_IOBUS_DEVS-1)); + + bus->devs[bus->dev_count++] = dev; +} + +static struct notifier_block kvm_cpu_notifier = { + .notifier_call = kvm_cpu_hotplug, + .priority = 20, /* must be > scheduler priority */ +}; + +static u64 vm_stat_get(void *_offset) +{ + unsigned offset = (long)_offset; + u64 total = 0; + struct kvm *kvm; + + spin_lock(&kvm_lock); + list_for_each_entry(kvm, &vm_list, vm_list) + total += *(u32 *)((void *)kvm + offset); + spin_unlock(&kvm_lock); + return total; +} + +DEFINE_SIMPLE_ATTRIBUTE(vm_stat_fops, vm_stat_get, NULL, "%llu\n"); + +static u64 vcpu_stat_get(void *_offset) +{ + unsigned offset = (long)_offset; + u64 total = 0; + struct kvm *kvm; + struct kvm_vcpu *vcpu; + int i; + + spin_lock(&kvm_lock); + list_for_each_entry(kvm, &vm_list, vm_list) + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = kvm->vcpus[i]; + if (vcpu) + total += *(u32 *)((void *)vcpu + offset); + } + spin_unlock(&kvm_lock); + return total; +} + +DEFINE_SIMPLE_ATTRIBUTE(vcpu_stat_fops, vcpu_stat_get, NULL, "%llu\n"); + +static struct file_operations *stat_fops[] = { + [KVM_STAT_VCPU] = &vcpu_stat_fops, + [KVM_STAT_VM] = &vm_stat_fops, +}; + +static void kvm_init_debug(void) +{ + struct kvm_stats_debugfs_item *p; + + debugfs_dir = debugfs_create_dir("kvm", NULL); + for (p = debugfs_entries; p->name; ++p) + p->dentry = debugfs_create_file(p->name, 0444, debugfs_dir, + (void *)(long)p->offset, + stat_fops[p->kind]); +} + +static void kvm_exit_debug(void) +{ + struct kvm_stats_debugfs_item *p; + + for (p = debugfs_entries; p->name; ++p) + debugfs_remove(p->dentry); + debugfs_remove(debugfs_dir); +} + +static int kvm_suspend(struct sys_device *dev, pm_message_t state) +{ + hardware_disable(NULL); + return 0; +} + +static int kvm_resume(struct sys_device *dev) +{ + hardware_enable(NULL); + return 0; +} + +static struct sysdev_class kvm_sysdev_class = { + set_kset_name("kvm"), + .suspend = kvm_suspend, + .resume = kvm_resume, +}; + +static struct sys_device kvm_sysdev = { + .id = 0, + .cls = &kvm_sysdev_class, +}; + +struct page *bad_page; + +static inline +struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn) +{ + return container_of(pn, struct kvm_vcpu, preempt_notifier); +} + +static void kvm_sched_in(struct preempt_notifier *pn, int cpu) +{ + struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); + + kvm_arch_vcpu_load(vcpu, cpu); +} + +static void kvm_sched_out(struct preempt_notifier *pn, + struct task_struct *next) +{ + struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); + + kvm_arch_vcpu_put(vcpu); +} + +int kvm_init(void *opaque, unsigned int vcpu_size, + struct module *module) +{ + int r; + int cpu; + + kvm_init_debug(); + + r = kvm_arch_init(opaque); + if (r) + goto out_fail; + + bad_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + + if (bad_page == NULL) { + r = -ENOMEM; + goto out; + } + + r = kvm_arch_hardware_setup(); + if (r < 0) + goto out_free_0; + + for_each_online_cpu(cpu) { + smp_call_function_single(cpu, + kvm_arch_check_processor_compat, + &r, 0, 1); + if (r < 0) + goto out_free_1; + } + + on_each_cpu(hardware_enable, NULL, 0, 1); + r = register_cpu_notifier(&kvm_cpu_notifier); + if (r) + goto out_free_2; + register_reboot_notifier(&kvm_reboot_notifier); + + r = sysdev_class_register(&kvm_sysdev_class); + if (r) + goto out_free_3; + + r = sysdev_register(&kvm_sysdev); + if (r) + goto out_free_4; + + /* A kmem cache lets us meet the alignment requirements of fx_save. */ + kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size, + __alignof__(struct kvm_vcpu), + 0, NULL); + if (!kvm_vcpu_cache) { + r = -ENOMEM; + goto out_free_5; + } + + kvm_chardev_ops.owner = module; + + r = misc_register(&kvm_dev); + if (r) { + printk(KERN_ERR "kvm: misc device register failed\n"); + goto out_free; + } + + kvm_preempt_ops.sched_in = kvm_sched_in; + kvm_preempt_ops.sched_out = kvm_sched_out; + + return 0; + +out_free: + kmem_cache_destroy(kvm_vcpu_cache); +out_free_5: + sysdev_unregister(&kvm_sysdev); +out_free_4: + sysdev_class_unregister(&kvm_sysdev_class); +out_free_3: + unregister_reboot_notifier(&kvm_reboot_notifier); + unregister_cpu_notifier(&kvm_cpu_notifier); +out_free_2: + on_each_cpu(hardware_disable, NULL, 0, 1); +out_free_1: + kvm_arch_hardware_unsetup(); +out_free_0: + __free_page(bad_page); +out: + kvm_arch_exit(); + kvm_exit_debug(); +out_fail: + return r; +} +EXPORT_SYMBOL_GPL(kvm_init); + +void kvm_exit(void) +{ + misc_deregister(&kvm_dev); + kmem_cache_destroy(kvm_vcpu_cache); + sysdev_unregister(&kvm_sysdev); + sysdev_class_unregister(&kvm_sysdev_class); + unregister_reboot_notifier(&kvm_reboot_notifier); + unregister_cpu_notifier(&kvm_cpu_notifier); + on_each_cpu(hardware_disable, NULL, 0, 1); + kvm_arch_hardware_unsetup(); + kvm_arch_exit(); + kvm_exit_debug(); + __free_page(bad_page); +} +EXPORT_SYMBOL_GPL(kvm_exit); --- linux-2.6.24.orig/virt/kvm/iodev.h +++ linux-2.6.24/virt/kvm/iodev.h @@ -0,0 +1,63 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KVM_IODEV_H__ +#define __KVM_IODEV_H__ + +#include + +struct kvm_io_device { + void (*read)(struct kvm_io_device *this, + gpa_t addr, + int len, + void *val); + void (*write)(struct kvm_io_device *this, + gpa_t addr, + int len, + const void *val); + int (*in_range)(struct kvm_io_device *this, gpa_t addr); + void (*destructor)(struct kvm_io_device *this); + + void *private; +}; + +static inline void kvm_iodevice_read(struct kvm_io_device *dev, + gpa_t addr, + int len, + void *val) +{ + dev->read(dev, addr, len, val); +} + +static inline void kvm_iodevice_write(struct kvm_io_device *dev, + gpa_t addr, + int len, + const void *val) +{ + dev->write(dev, addr, len, val); +} + +static inline int kvm_iodevice_inrange(struct kvm_io_device *dev, gpa_t addr) +{ + return dev->in_range(dev, addr); +} + +static inline void kvm_iodevice_destructor(struct kvm_io_device *dev) +{ + if (dev->destructor) + dev->destructor(dev); +} + +#endif /* __KVM_IODEV_H__ */ --- linux-2.6.24.orig/virt/kvm/ioapic.h +++ linux-2.6.24/virt/kvm/ioapic.h @@ -0,0 +1,95 @@ +#ifndef __KVM_IO_APIC_H +#define __KVM_IO_APIC_H + +#include + +#include "iodev.h" + +struct kvm; +struct kvm_vcpu; + +#define IOAPIC_NUM_PINS KVM_IOAPIC_NUM_PINS +#define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */ +#define IOAPIC_EDGE_TRIG 0 +#define IOAPIC_LEVEL_TRIG 1 + +#define IOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000 +#define IOAPIC_MEM_LENGTH 0x100 + +/* Direct registers. */ +#define IOAPIC_REG_SELECT 0x00 +#define IOAPIC_REG_WINDOW 0x10 +#define IOAPIC_REG_EOI 0x40 /* IA64 IOSAPIC only */ + +/* Indirect registers. */ +#define IOAPIC_REG_APIC_ID 0x00 /* x86 IOAPIC only */ +#define IOAPIC_REG_VERSION 0x01 +#define IOAPIC_REG_ARB_ID 0x02 /* x86 IOAPIC only */ + +/*ioapic delivery mode*/ +#define IOAPIC_FIXED 0x0 +#define IOAPIC_LOWEST_PRIORITY 0x1 +#define IOAPIC_PMI 0x2 +#define IOAPIC_NMI 0x4 +#define IOAPIC_INIT 0x5 +#define IOAPIC_EXTINT 0x7 + +struct kvm_ioapic { + u64 base_address; + u32 ioregsel; + u32 id; + u32 irr; + u32 pad; + union ioapic_redir_entry { + u64 bits; + struct { + u8 vector; + u8 delivery_mode:3; + u8 dest_mode:1; + u8 delivery_status:1; + u8 polarity:1; + u8 remote_irr:1; + u8 trig_mode:1; + u8 mask:1; + u8 reserve:7; + u8 reserved[4]; + u8 dest_id; + } fields; + } redirtbl[IOAPIC_NUM_PINS]; + struct kvm_io_device dev; + struct kvm *kvm; +}; + +#ifdef DEBUG +#define ASSERT(x) \ +do { \ + if (!(x)) { \ + printk(KERN_EMERG "assertion failed %s: %d: %s\n", \ + __FILE__, __LINE__, #x); \ + BUG(); \ + } \ +} while (0) +#else +#define ASSERT(x) do { } while (0) +#endif + +static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm) +{ + return kvm->arch.vioapic; +} + +#ifdef CONFIG_IA64 +static inline int irqchip_in_kernel(struct kvm *kvm) +{ + return 1; +} +#endif + +struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector, + unsigned long bitmap); +void kvm_ioapic_update_eoi(struct kvm *kvm, int vector); +int kvm_ioapic_init(struct kvm *kvm); +void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); +void kvm_ioapic_reset(struct kvm_ioapic *ioapic); + +#endif --- linux-2.6.24.orig/virt/kvm/ioapic.c +++ linux-2.6.24/virt/kvm/ioapic.c @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2001 MandrakeSoft S.A. + * + * MandrakeSoft S.A. + * 43, rue d'Aboukir + * 75002 Paris - France + * http://www.linux-mandrake.com/ + * http://www.mandrakesoft.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Yunhong Jiang + * Yaozu (Eddie) Dong + * Based on Xen 3.1 code. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ioapic.h" +#include "lapic.h" + +#if 0 +#define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) +#else +#define ioapic_debug(fmt, arg...) +#endif +static void ioapic_deliver(struct kvm_ioapic *vioapic, int irq); + +static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, + unsigned long addr, + unsigned long length) +{ + unsigned long result = 0; + + switch (ioapic->ioregsel) { + case IOAPIC_REG_VERSION: + result = ((((IOAPIC_NUM_PINS - 1) & 0xff) << 16) + | (IOAPIC_VERSION_ID & 0xff)); + break; + + case IOAPIC_REG_APIC_ID: + case IOAPIC_REG_ARB_ID: + result = ((ioapic->id & 0xf) << 24); + break; + + default: + { + u32 redir_index = (ioapic->ioregsel - 0x10) >> 1; + u64 redir_content; + + ASSERT(redir_index < IOAPIC_NUM_PINS); + + redir_content = ioapic->redirtbl[redir_index].bits; + result = (ioapic->ioregsel & 0x1) ? + (redir_content >> 32) & 0xffffffff : + redir_content & 0xffffffff; + break; + } + } + + return result; +} + +static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) +{ + union ioapic_redir_entry *pent; + + pent = &ioapic->redirtbl[idx]; + + if (!pent->fields.mask) { + ioapic_deliver(ioapic, idx); + if (pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) + pent->fields.remote_irr = 1; + } + if (!pent->fields.trig_mode) + ioapic->irr &= ~(1 << idx); +} + +static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) +{ + unsigned index; + + switch (ioapic->ioregsel) { + case IOAPIC_REG_VERSION: + /* Writes are ignored. */ + break; + + case IOAPIC_REG_APIC_ID: + ioapic->id = (val >> 24) & 0xf; + break; + + case IOAPIC_REG_ARB_ID: + break; + + default: + index = (ioapic->ioregsel - 0x10) >> 1; + + ioapic_debug("change redir index %x val %x\n", index, val); + if (index >= IOAPIC_NUM_PINS) + return; + if (ioapic->ioregsel & 1) { + ioapic->redirtbl[index].bits &= 0xffffffff; + ioapic->redirtbl[index].bits |= (u64) val << 32; + } else { + ioapic->redirtbl[index].bits &= ~0xffffffffULL; + ioapic->redirtbl[index].bits |= (u32) val; + ioapic->redirtbl[index].fields.remote_irr = 0; + } + if (ioapic->irr & (1 << index)) + ioapic_service(ioapic, index); + break; + } +} + +static void ioapic_inj_irq(struct kvm_ioapic *ioapic, + struct kvm_vcpu *vcpu, + u8 vector, u8 trig_mode, u8 delivery_mode) +{ + ioapic_debug("irq %d trig %d deliv %d\n", vector, trig_mode, + delivery_mode); + + ASSERT((delivery_mode == IOAPIC_FIXED) || + (delivery_mode == IOAPIC_LOWEST_PRIORITY)); + + kvm_apic_set_irq(vcpu, vector, trig_mode); +} + +static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest, + u8 dest_mode) +{ + u32 mask = 0; + int i; + struct kvm *kvm = ioapic->kvm; + struct kvm_vcpu *vcpu; + + ioapic_debug("dest %d dest_mode %d\n", dest, dest_mode); + + if (dest_mode == 0) { /* Physical mode. */ + if (dest == 0xFF) { /* Broadcast. */ + for (i = 0; i < KVM_MAX_VCPUS; ++i) + if (kvm->vcpus[i] && kvm->vcpus[i]->arch.apic) + mask |= 1 << i; + return mask; + } + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = kvm->vcpus[i]; + if (!vcpu) + continue; + if (kvm_apic_match_physical_addr(vcpu->arch.apic, dest)) { + if (vcpu->arch.apic) + mask = 1 << i; + break; + } + } + } else if (dest != 0) /* Logical mode, MDA non-zero. */ + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = kvm->vcpus[i]; + if (!vcpu) + continue; + if (vcpu->arch.apic && + kvm_apic_match_logical_addr(vcpu->arch.apic, dest)) + mask |= 1 << vcpu->vcpu_id; + } + ioapic_debug("mask %x\n", mask); + return mask; +} + +static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq) +{ + u8 dest = ioapic->redirtbl[irq].fields.dest_id; + u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode; + u8 delivery_mode = ioapic->redirtbl[irq].fields.delivery_mode; + u8 vector = ioapic->redirtbl[irq].fields.vector; + u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode; + u32 deliver_bitmask; + struct kvm_vcpu *vcpu; + int vcpu_id; + + ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " + "vector=%x trig_mode=%x\n", + dest, dest_mode, delivery_mode, vector, trig_mode); + + deliver_bitmask = ioapic_get_delivery_bitmask(ioapic, dest, dest_mode); + if (!deliver_bitmask) { + ioapic_debug("no target on destination\n"); + return; + } + + switch (delivery_mode) { + case IOAPIC_LOWEST_PRIORITY: + vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector, + deliver_bitmask); +#ifdef CONFIG_X86 + if (irq == 0) + vcpu = ioapic->kvm->vcpus[0]; +#endif + if (vcpu != NULL) + ioapic_inj_irq(ioapic, vcpu, vector, + trig_mode, delivery_mode); + else + ioapic_debug("null lowest prio vcpu: " + "mask=%x vector=%x delivery_mode=%x\n", + deliver_bitmask, vector, IOAPIC_LOWEST_PRIORITY); + break; + case IOAPIC_FIXED: +#ifdef CONFIG_X86 + if (irq == 0) + deliver_bitmask = 1; +#endif + for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { + if (!(deliver_bitmask & (1 << vcpu_id))) + continue; + deliver_bitmask &= ~(1 << vcpu_id); + vcpu = ioapic->kvm->vcpus[vcpu_id]; + if (vcpu) { + ioapic_inj_irq(ioapic, vcpu, vector, + trig_mode, delivery_mode); + } + } + break; + + /* TODO: NMI */ + default: + printk(KERN_WARNING "Unsupported delivery mode %d\n", + delivery_mode); + break; + } +} + +void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) +{ + u32 old_irr = ioapic->irr; + u32 mask = 1 << irq; + union ioapic_redir_entry entry; + + if (irq >= 0 && irq < IOAPIC_NUM_PINS) { + entry = ioapic->redirtbl[irq]; + level ^= entry.fields.polarity; + if (!level) + ioapic->irr &= ~mask; + else { + ioapic->irr |= mask; + if ((!entry.fields.trig_mode && old_irr != ioapic->irr) + || !entry.fields.remote_irr) + ioapic_service(ioapic, irq); + } + } +} + +static int get_eoi_gsi(struct kvm_ioapic *ioapic, int vector) +{ + int i; + + for (i = 0; i < IOAPIC_NUM_PINS; i++) + if (ioapic->redirtbl[i].fields.vector == vector) + return i; + return -1; +} + +void kvm_ioapic_update_eoi(struct kvm *kvm, int vector) +{ + struct kvm_ioapic *ioapic = kvm->arch.vioapic; + union ioapic_redir_entry *ent; + int gsi; + + gsi = get_eoi_gsi(ioapic, vector); + if (gsi == -1) { + printk(KERN_WARNING "Can't find redir item for %d EOI\n", + vector); + return; + } + + ent = &ioapic->redirtbl[gsi]; + ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); + + ent->fields.remote_irr = 0; + if (!ent->fields.mask && (ioapic->irr & (1 << gsi))) + ioapic_deliver(ioapic, gsi); +} + +static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr) +{ + struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; + + return ((addr >= ioapic->base_address && + (addr < ioapic->base_address + IOAPIC_MEM_LENGTH))); +} + +static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len, + void *val) +{ + struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; + u32 result; + + ioapic_debug("addr %lx\n", (unsigned long)addr); + ASSERT(!(addr & 0xf)); /* check alignment */ + + addr &= 0xff; + switch (addr) { + case IOAPIC_REG_SELECT: + result = ioapic->ioregsel; + break; + + case IOAPIC_REG_WINDOW: + result = ioapic_read_indirect(ioapic, addr, len); + break; + + default: + result = 0; + break; + } + switch (len) { + case 8: + *(u64 *) val = result; + break; + case 1: + case 2: + case 4: + memcpy(val, (char *)&result, len); + break; + default: + printk(KERN_WARNING "ioapic: wrong length %d\n", len); + } +} + +static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len, + const void *val) +{ + struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; + u32 data; + + ioapic_debug("ioapic_mmio_write addr=%p len=%d val=%p\n", + (void*)addr, len, val); + ASSERT(!(addr & 0xf)); /* check alignment */ + if (len == 4 || len == 8) + data = *(u32 *) val; + else { + printk(KERN_WARNING "ioapic: Unsupported size %d\n", len); + return; + } + + addr &= 0xff; + switch (addr) { + case IOAPIC_REG_SELECT: + ioapic->ioregsel = data; + break; + + case IOAPIC_REG_WINDOW: + ioapic_write_indirect(ioapic, data); + break; +#ifdef CONFIG_IA64 + case IOAPIC_REG_EOI: + kvm_ioapic_update_eoi(ioapic->kvm, data); + break; +#endif + + default: + break; + } +} + +void kvm_ioapic_reset(struct kvm_ioapic *ioapic) +{ + int i; + + for (i = 0; i < IOAPIC_NUM_PINS; i++) + ioapic->redirtbl[i].fields.mask = 1; + ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS; + ioapic->ioregsel = 0; + ioapic->irr = 0; + ioapic->id = 0; +} + +int kvm_ioapic_init(struct kvm *kvm) +{ + struct kvm_ioapic *ioapic; + + ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL); + if (!ioapic) + return -ENOMEM; + kvm->arch.vioapic = ioapic; + kvm_ioapic_reset(ioapic); + ioapic->dev.read = ioapic_mmio_read; + ioapic->dev.write = ioapic_mmio_write; + ioapic->dev.in_range = ioapic_in_range; + ioapic->dev.private = ioapic; + ioapic->kvm = kvm; + kvm_io_bus_register_dev(&kvm->mmio_bus, &ioapic->dev); + return 0; +} --- linux-2.6.24.orig/scripts/mod/modpost.h +++ linux-2.6.24/scripts/mod/modpost.h @@ -130,6 +130,7 @@ }; /* file2alias.c */ +extern unsigned int cross_build; void handle_moddevtable(struct module *mod, struct elf_info *info, Elf_Sym *sym, const char *symname); void add_moddevtable(struct buffer *buf, struct module *mod); --- linux-2.6.24.orig/scripts/mod/modpost.c +++ linux-2.6.24/scripts/mod/modpost.c @@ -1659,7 +1659,7 @@ int opt; int err; - while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) { + while ((opt = getopt(argc, argv, "i:I:cmso:aw")) != -1) { switch(opt) { case 'i': kernel_read = optarg; @@ -1668,6 +1668,9 @@ module_read = optarg; external_module = 1; break; + case 'c': + cross_build = 1; + break; case 'm': modversions = 1; break; --- linux-2.6.24.orig/scripts/mod/file2alias.c +++ linux-2.6.24/scripts/mod/file2alias.c @@ -51,11 +51,13 @@ sprintf(str + strlen(str), "*"); \ } while(0) +unsigned int cross_build = 0; /** * Check that sizeof(device_id type) are consistent with size of section * in .o file. If in-consistent then userspace and kernel does not agree * on actual size which is a bug. * Also verify that the final entry in the table is all zeros. + * Ignore both checks if build host differ from target host and size differs. **/ static void device_id_check(const char *modname, const char *device_id, unsigned long size, unsigned long id_size, @@ -64,6 +66,8 @@ int i; if (size % id_size || size < id_size) { + if (cross_build != 0) + return; fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " "of the size of section __mod_%s_device_table=%lu.\n" "Fix definition of struct %s_device_id " --- linux-2.6.24.orig/scripts/Makefile.modpost +++ linux-2.6.24/scripts/Makefile.modpost @@ -53,6 +53,9 @@ # Stop after building .o files if NOFINAL is set. Makes compile tests quicker _modpost: $(if $(KBUILD_MODPOST_NOFINAL), $(modules:.ko:.o),$(modules)) +ifneq ($(KBUILD_BUILDHOST),$(ARCH)) + cross_build := 1 +endif # Step 2), invoke modpost # Includes step 3,4 @@ -62,7 +65,8 @@ $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \ $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ - $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) + $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \ + $(if $(cross_build),-c) quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules cmd_modpost = $(modpost) -s --- linux-2.6.24.orig/patches/0062-Modified-hci_usb-to-include-new-USB-ID-for-Dell-Mini.patch +++ linux-2.6.24/patches/0062-Modified-hci_usb-to-include-new-USB-ID-for-Dell-Mini.patch @@ -0,0 +1,26 @@ +From 4abdfae7a39c91695a62facd58a9557f8b3baeb8 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Thu, 9 Oct 2008 15:15:49 -0400 +Subject: [PATCH 062/170] Modified hci_usb to include new USB:ID for Dell Mini 9 BT module + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/bluetooth/hci_usb.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c +index c65e78c..aa1b73b 100644 +--- a/drivers/bluetooth/hci_usb.c ++++ b/drivers/bluetooth/hci_usb.c +@@ -139,6 +139,8 @@ static struct usb_device_id blacklist_ids[] = { + { USB_DEVICE(0x413c, 0x8156), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, + /* Dell Wireless 410 */ + { USB_DEVICE(0x413c, 0x8152), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, ++ /* Dell Wireless 2046 */ ++ { USB_DEVICE(0x413c, 0x02b0), .driver_info = HCI_RESET }, + + /* Broadcom 2046 */ + { USB_DEVICE(0x0a5c, 0x2151), .driver_info = HCI_RESET }, +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0141-ESCO-interval-rejection-fix.patch +++ linux-2.6.24/patches/0141-ESCO-interval-rejection-fix.patch @@ -0,0 +1,81 @@ +From 38bcf064d403f712b39e6743ae0784c800a33d90 Mon Sep 17 00:00:00 2001 +From: Krishnan Nair +Date: Mon, 20 Apr 2009 15:59:24 -0400 +Subject: [PATCH 141/170] ESCO interval rejection fix + +This fixes ESCO interval rejection issues; upon an interval rejection, +a SCO connection is attempted. This patch comes from CSR. + +Signed-off-by: Andres Salomon +--- + include/net/bluetooth/hci.h | 7 +++++++ + net/bluetooth/hci_conn.c | 9 ++++++++- + net/bluetooth/hci_event.c | 6 ++++++ + 3 files changed, 21 insertions(+), 1 deletions(-) + +diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h +index a8a9eb6..f02be5b 100644 +--- a/include/net/bluetooth/hci.h ++++ b/include/net/bluetooth/hci.h +@@ -136,6 +136,13 @@ enum { + #define ESCO_EV3 0x0008 + #define ESCO_EV4 0x0010 + #define ESCO_EV5 0x0020 ++#define ESCO_2EV3 0x0040 ++#define ESCO_3EV3 0x0080 ++#define ESCO_2EV5 0x0100 ++#define ESCO_3EV5 0x0200 ++ ++#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3) ++#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5) + + /* ACL flags */ + #define ACL_CONT 0x01 +diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c +index 34d1a3c..39c2ac3 100644 +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -121,8 +121,14 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) + conn->state = BT_CONNECT; + conn->out = 1; + ++ conn->attempt++; ++ + cp.handle = cpu_to_le16(handle); +- cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); ++ if (conn->attempt > 1) ++ cp.pkt_type = (hdev->esco_type & SCO_ESCO_MASK) | ++ (hdev->esco_type & EDR_ESCO_MASK); ++ else ++ cp.pkt_type = cpu_to_le16(hdev->esco_type); + + hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp); + } +@@ -217,6 +223,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) + conn->idle_timer.data = (unsigned long) conn; + + atomic_set(&conn->refcnt, 0); ++ conn->sent = 0; + + hci_dev_hold(hdev); + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 3361373..bc2347d 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -1324,6 +1324,12 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu + conn->type = SCO_LINK; + } + ++ if (conn->out && ev->status == 0x1c && conn->attempt < 2) { ++ BT_INFO("reattempt due to ScoInterval rejected"); ++ hci_setup_sync(conn, conn->link->handle); ++ goto unlock; ++ } ++ + if (!ev->status) { + conn->handle = __le16_to_cpu(ev->handle); + conn->state = BT_CONNECTED; +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0024-kgdb-debugger-reboot-notifier-hook.patch +++ linux-2.6.24/patches/0024-kgdb-debugger-reboot-notifier-hook.patch @@ -0,0 +1,78 @@ +From e7ba15791cd33c032a054bb3bdcccd1831e94e4a Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:45 -0500 +Subject: [PATCH 024/170] kgdb: debugger reboot notifier hook + +Notify debugger as well as catch reboot events when a kgdb I/O driver +is registered. + +Signed-off-by: Jason Wessel +--- + kernel/kgdb.c | 39 +++++++++++++++++++++++++++++++++++++++ + 1 files changed, 39 insertions(+), 0 deletions(-) + +diff --git a/kernel/kgdb.c b/kernel/kgdb.c +index 1bd0ec1..22285c4 100644 +--- a/kernel/kgdb.c ++++ b/kernel/kgdb.c +@@ -1552,11 +1552,49 @@ static struct sysrq_key_op sysrq_gdb_op = { + }; + #endif + ++static int ++kgdb_notify_reboot(struct notifier_block *this, unsigned long code, void *x) ++{ ++ unsigned long flags; ++ ++ if (!kgdb_connected) ++ return 0; ++ ++ if (code == SYS_RESTART || code == SYS_HALT || code == SYS_POWER_OFF) { ++ local_irq_save(flags); ++ if (kgdb_io_ops->write_char) { ++ /* Do not use put_packet to avoid hanging ++ * in case the attached debugger disappeared ++ * or does not respond timely. ++ */ ++ kgdb_io_ops->write_char('$'); ++ kgdb_io_ops->write_char('X'); ++ kgdb_io_ops->write_char('0'); ++ kgdb_io_ops->write_char('0'); ++ kgdb_io_ops->write_char('#'); ++ kgdb_io_ops->write_char('b'); ++ kgdb_io_ops->write_char('8'); ++ if (kgdb_io_ops->flush) ++ kgdb_io_ops->flush(); ++ } ++ kgdb_connected = 0; ++ local_irq_restore(flags); ++ } ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block kgdb_reboot_notifier = { ++ .notifier_call = kgdb_notify_reboot, ++ .next = NULL, ++ .priority = INT_MAX, ++}; ++ + static void kgdb_register_callbacks(void) + { + if (!kgdb_io_module_registered) { + kgdb_io_module_registered = 1; + kgdb_arch_init(); ++ register_reboot_notifier(&kgdb_reboot_notifier); + #ifdef CONFIG_MAGIC_SYSRQ + register_sysrq_key('g', &sysrq_gdb_op); + #endif +@@ -1575,6 +1613,7 @@ static void kgdb_unregister_callbacks(void) + * break exceptions at the time. + */ + if (kgdb_io_module_registered) { ++ unregister_reboot_notifier(&kgdb_reboot_notifier); + kgdb_io_module_registered = 0; + kgdb_arch_exit(); + #ifdef CONFIG_MAGIC_SYSRQ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0148-UBUNTU-Do-not-rename-debug-packages-for-OEM-buildd-s.patch +++ linux-2.6.24/patches/0148-UBUNTU-Do-not-rename-debug-packages-for-OEM-buildd-s.patch @@ -0,0 +1,38 @@ +From 647250e64966554bff79124b87770fb60e70f40c Mon Sep 17 00:00:00 2001 +From: Tim Gardner +Date: Tue, 5 May 2009 14:04:11 -0600 +Subject: [PATCH 148/170] UBUNTU: Do not rename debug packages for OEM buildd's + +Ignore: yes + +Renaming debug packages from .deb to .ddeb is done in the primary +archive in order to avoid copying really large packages to mirrors +after every kernel build. Since the OEM archive is not widely mirrored, +its much less of a problem. + +Signed-off-by: Tim Gardner +--- + debian/rules.d/6-binary-custom.mk | 8 -------- + 1 files changed, 0 insertions(+), 8 deletions(-) + +diff --git a/debian/rules.d/6-binary-custom.mk b/debian/rules.d/6-binary-custom.mk +index 98ea584..48d5be4 100644 +--- a/debian/rules.d/6-binary-custom.mk ++++ b/debian/rules.d/6-binary-custom.mk +@@ -156,13 +156,5 @@ ifneq ($(skipdbg),true) + dh_gencontrol -p$(dbgpkg) + dh_md5sums -p$(dbgpkg) + dh_builddeb -p$(dbgpkg) +- +- # Hokay...here's where we do a little twiddling... +- mv ../$(dbgpkg)_$(release)-$(revision)_$(arch).deb \ +- ../$(dbgpkg)_$(release)-$(revision)_$(arch).ddeb +- grep -v '^$(dbgpkg)_.*$$' debian/files > debian/files.new +- mv debian/files.new debian/files +- # Now, the package wont get into the archive, but it will get put +- # into the debug system. + endif + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0057-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook2.patch +++ linux-2.6.24/patches/0057-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook2.patch @@ -0,0 +1,30 @@ +From c1b1519da1f5f64f4545ea9e35bb5775ef2cbc99 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 10 Sep 2008 15:23:02 -0400 +Subject: [PATCH 057/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook2 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 3de55d1..6d6e647 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-19.41netbook2) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * Backport of HPET clock changes from 2.6.27 ++ ++ -- Michael Frey Wed, 10 Sep 2008 15:20:56 -0400 ++ + linux (2.6.24-19.41netbook1) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0040-UBUNTU-NBK-Ubuntu-2.6.24-19.35netbook2.patch +++ linux-2.6.24/patches/0040-UBUNTU-NBK-Ubuntu-2.6.24-19.35netbook2.patch @@ -0,0 +1,30 @@ +From 3ab72d255d7d568da11778bd8812d97aee650903 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 8 Jul 2008 14:03:54 +0100 +Subject: [PATCH 040/170] UBUNTU: NBK-Ubuntu-2.6.24-19.35netbook2 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index f2c9189..8bca264 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-19.35netbook2) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * Send HCI_RESET for Broadcomm 2046 fix for LP#241749 ++ ++ -- Michael Frey Tue, 08 Jul 2008 13:10:05 +0100 ++ + linux (2.6.24-19.35netbook1) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0157-UBUNTU-printchanges-rebase-tree-does-not-have-stable.patch +++ linux-2.6.24/patches/0157-UBUNTU-printchanges-rebase-tree-does-not-have-stable.patch @@ -0,0 +1,33 @@ +From 1465174bddbf0dd5412a623a6eea33845e637a02 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 10 Jul 2009 12:32:44 +0100 +Subject: [PATCH 157/170] UBUNTU: printchanges -- rebase tree does not have stable tags use changelog + +When generating the changes list we normally use the previous tag to locate +the start of the new changes. However with a rebase tree the tag is off +on another branch. Instead simply search back in the log looking for the +commit which represents the previous release commit and use that directly. + +Signed-off-by: Andy Whitcroft +--- + debian/rules.d/1-maintainer.mk | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/debian/rules.d/1-maintainer.mk b/debian/rules.d/1-maintainer.mk +index add1e3f..90231d9 100644 +--- a/debian/rules.d/1-maintainer.mk ++++ b/debian/rules.d/1-maintainer.mk +@@ -66,7 +66,9 @@ endif + @echo "CONCURRENCY_LEVEL = $(CONCURRENCY_LEVEL)" + + printchanges: +- @git-log NBK-Ubuntu-$(release)-$(prev_revision)..HEAD | \ ++ @baseCommit=$$(git log --pretty=format:'%H %s' | \ ++ awk '/UBUNTU: '".*Ubuntu-$(release)-$(prev_revision)"'$$/ { print $$1; exit }'); \ ++ git log "$$baseCommit"..HEAD | \ + perl -w -f debian/scripts/misc/git-ubuntu-log $(ubuntu_log_opts) + + insertchanges: +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0069-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook8.patch +++ linux-2.6.24/patches/0069-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook8.patch @@ -0,0 +1,30 @@ +From abe2b211b15be1ae73f36aa9a543dca781809605 Mon Sep 17 00:00:00 2001 +From: Tony Espy +Date: Thu, 23 Oct 2008 15:35:12 -0400 +Subject: [PATCH 069/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook8 + +Ignore: yes +Signed-off-by: Tony Espy +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index bc31776..80561f2 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-19.41netbook8) hardy; urgency=low ++ ++ [Upstream Kernel Changes] ++ ++ * USB: make USB PERSIST work after every system sleep. ++ ++ -- Tony Espy Thu, 23 Oct 2008 19:18:49 +0000 ++ + linux (2.6.24-19.41netbook7) hardy; urgency=low + + [Debbie Beliveau] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0063-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook5.patch +++ linux-2.6.24/patches/0063-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook5.patch @@ -0,0 +1,33 @@ +From dc3ded388ca01082f1ec6d217ea821cc98a9034d Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Thu, 9 Oct 2008 15:19:29 -0400 +Subject: [PATCH 063/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook5 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 11 +++++++++++ + 1 files changed, 11 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 161b763..2de5640 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,14 @@ ++linux (2.6.24-19.41netbook5) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * Modified hci_usb to include new USB:ID for Dell Mini 9 BT module ++ * Cherry pick from Hardy which Stefan Bader kindly back ported ++ * from upstream. It will reset the device by writing RESET_VALUE to port ++ * RESET_REG - these values are gleaned from the ACPI FACP table ++ ++ -- Michael Frey Thu, 09 Oct 2008 15:15:40 -0400 ++ + linux (2.6.24-19.41netbook4) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0143-UBUNTU-changes-to-rebase-script-for-netbook-lpia.patch +++ linux-2.6.24/patches/0143-UBUNTU-changes-to-rebase-script-for-netbook-lpia.patch @@ -0,0 +1,102 @@ +From 20fa80f1518cb30a52ddd37ff2246c736e936505 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Wed, 29 Apr 2009 17:03:15 -0500 +Subject: [PATCH 143/170] UBUNTU: changes to rebase script for netbook-lpia + +OriginalAuthor: Steve Conklin + +Signed-off-by: Steve Conklin +--- + debian/scripts/misc/rebase-branch | 34 +++++++++++++++------------------- + 1 files changed, 15 insertions(+), 19 deletions(-) + +diff --git a/debian/scripts/misc/rebase-branch b/debian/scripts/misc/rebase-branch +index 8426f99..39813ba 100755 +--- a/debian/scripts/misc/rebase-branch ++++ b/debian/scripts/misc/rebase-branch +@@ -4,24 +4,26 @@ + # Author: Amit Kucheria (amit@ubuntu.com) + # Date: 11/07/08 + ++# Modified for netbook-lpia branch ++# Steve Conklin ++ + # Assumptions: + # 1. Every rebase during devel-cycle is an ABI bump + # 2. The target tree's patches are always on top + # 3. As a consequence of 2., tags are not really useful + # 4. autogenerated patches are marked with AUTO; others are marked with SAUCE +-# 5. Keep things in a state that they can be merged back into the main tree at the end of the dev cycle ++# 5. Keep things in a state that they can be merged back ++# into the main tree at the end of the dev cycle + +-targetDir=${1:?"Usage: $0 "} +-remoteTag=${2:?"Usage: $0 "} ++remoteTag=${1:?"Usage: $0 "} + + rebasing=".git/rebase-apply" + + # Configuration variables + release="hardy" + basever="2.6.24" +-patchDir=$targetDir/patches +-#masterTree=git://zinc.ubuntu.com/ubuntu/ubuntu-$release.git +-#masterName=ubuntu-$release ++patchDir=./patches ++# masterTree=git://zinc.ubuntu.com/ubuntu/ubuntu-$release.git + baseTag="NBK-Ubuntu-$basever-0.0" + tmpTag="tmplpia" + +@@ -30,7 +32,6 @@ git=`which git` + + rm -rf .patches "$patchDir" + mkdir -p $patchDir +-cd $targetDir + rm -rf "$rebasing/" + + echo "* Check for uncommitted files..." +@@ -39,16 +40,12 @@ if [ ! $? -eq "0" ]; then + echo "\tUncommitted changes found!\n\tClean out your tree before running this script. Exiting." + exit 1; + fi +-#$git checkout master +-#$git reset --hard + + echo "\n" +-echo "* Fetching Ubuntu master tree..." +-$git branch -r | grep $masterName +-if [ $? -eq "0" ]; then +- echo "\t$masterName is already used as a branch name in your tree. Please change the \$masterName variable in this script." +- exit 1; +-fi ++echo "* Checking out master tree..." ++$git checkout origin/netbook-lpia ++$git reset --hard ++ + + echo "\n" + echo "* Exporting current work as patches..." +@@ -166,7 +163,7 @@ $git commit -a -s -m "UBUNTU: AUTO: Start new changelog and revert to known abi" + $git status + + # Apply pending patches +-$git am -C0 patches/* ++$git am --whitespace=fix -C0 patches/* + if [ -d "$rebasing/" ]; then + echo "\tFailed to apply patches" + echo "\tPlease fix the patches on branch $remoteBranch and then sync to the master branch" +@@ -180,9 +177,8 @@ git tag -d $tmpTag + + echo "\n" + echo "If the final result looks good, then do the following to make it permanent:" +-echo " * Run debian/scripts/misc/retag-lpia to retag" +-echo " * git checkout master" ++echo " * Run debian/scripts/misc/retag-branch to retag" ++echo " * git checkout netbook-lpia" + echo " * git reset --hard $remoteBranch" +-echo " * git remote rm $masterName" + echo " * rm -rf patches/" + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0080-Turned-on-Ericsson-3G-modem-support-in-config.lpia.patch +++ linux-2.6.24/patches/0080-Turned-on-Ericsson-3G-modem-support-in-config.lpia.patch @@ -0,0 +1,56 @@ +From bbdfa2839f3c932e8e8d83fc2e99502f9482413e Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Fri, 21 Nov 2008 14:54:57 -0500 +Subject: [PATCH 080/170] Turned on Ericsson 3G modem support in config.lpia + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/binary-custom.d/lpia/config.lpia | 11 ++++------- + 1 files changed, 4 insertions(+), 7 deletions(-) + +diff --git a/debian/binary-custom.d/lpia/config.lpia b/debian/binary-custom.d/lpia/config.lpia +index 6ca6fbc..87eb1ef 100644 +--- a/debian/binary-custom.d/lpia/config.lpia ++++ b/debian/binary-custom.d/lpia/config.lpia +@@ -117,7 +117,7 @@ CONFIG_BLOCK=y + # CONFIG_BLK_DEV_BSG is not set + CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 + CONFIG_LSM_MMAP_MIN_ADDR=0 +- ++# CONFIG_KGDB is not set + # + # IO Schedulers + # +@@ -507,11 +507,6 @@ CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m + CONFIG_IPV6_SIT=m + CONFIG_IPV6_TUNNEL=m + # CONFIG_IPV6_MULTIPLE_TABLES is not set +-CONFIG_KGDB=y +-CONFIG_KGDBOE=y +-# CONFIG_KGDB_8250 is not set +-CONFIG_KGDB_SERIAL_CONSOLE=y +-# CONFIG_KGDB_TESTS is not set + CONFIG_NETWORK_SECMARK=y + CONFIG_NETFILTER=y + # CONFIG_NETFILTER_DEBUG is not set +@@ -1668,6 +1663,8 @@ CONFIG_USB_BELKIN=y + CONFIG_USB_ARMLINUX=y + CONFIG_USB_EPSON2888=y + CONFIG_USB_KC2190=y ++CONFIG_USB_NET_MBM=m ++CONFIG_USB_WDM=m + # CONFIG_USB_NET_ZAURUS is not set + # CONFIG_WAN is not set + # CONFIG_ATM_DRIVERS is not set +@@ -1695,7 +1692,7 @@ CONFIG_SHAPER=m + CONFIG_NETCONSOLE=m + CONFIG_NETCONSOLE_DYNAMIC=y + CONFIG_NETPOLL=y +-CONFIG_NETPOLL_TRAP=y ++# CONFIG_NETPOLL_TRAP is not set + CONFIG_NET_POLL_CONTROLLER=y + CONFIG_VIRTIO_NET=m + # CONFIG_ISDN is not set +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0098-Added-CONFIG_USB_KBD-m-CONFIG_USB_MOUSE-m.patch +++ linux-2.6.24/patches/0098-Added-CONFIG_USB_KBD-m-CONFIG_USB_MOUSE-m.patch @@ -0,0 +1,27 @@ +From 95b1767273a1ca7f7fc8232c69c61965b7d6c751 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 17 Mar 2009 16:35:48 -0400 +Subject: [PATCH 098/170] Added CONFIG_USB_KBD=m CONFIG_USB_MOUSE=m + +Signed-off-by: Michael Frey (Senior Manager, MID) +Signed-off-by: Steve Conklin +--- + debian/binary-custom.d/lpia/config.lpia | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/debian/binary-custom.d/lpia/config.lpia b/debian/binary-custom.d/lpia/config.lpia +index af0977b..4bbc3d0 100644 +--- a/debian/binary-custom.d/lpia/config.lpia ++++ b/debian/binary-custom.d/lpia/config.lpia +@@ -2604,6 +2604,8 @@ CONFIG_HIDRAW=y + # + CONFIG_USB_HID=m + CONFIG_USB_HIDINPUT_POWERBOOK=y ++CONFIG_USB_KBD=m ++CONFIG_USB_MOUSE=m + # CONFIG_HID_FF is not set + CONFIG_USB_HIDDEV=y + CONFIG_USB_SUPPORT=y +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0019-kgdb-allow-static-kgdbts-boot-configuration.patch +++ linux-2.6.24/patches/0019-kgdb-allow-static-kgdbts-boot-configuration.patch @@ -0,0 +1,213 @@ +From eccf311a3b22036b153e8e6502ff88c87143d426 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Mon, 10 Mar 2008 08:43:54 -0500 +Subject: [PATCH 019/170] kgdb: allow static kgdbts boot configuration + +This patch adds in the ability to compile the kgdb internal test +string into the kernel so as to run the tests at boot without changing +the kernel boot arguments. This patch also changes all the error +paths to invoke WARN_ON(1) which will emit the line number of the file +and dump the kernel stack when an error occurs. + +You can disable the tests in a kernel that is built this way +using "kgdbts=" + +Jason. + +Signed-off-by: Jason Wessel +--- + drivers/misc/kgdbts.c | 41 ++++++++++++++++++++++++----------------- + lib/Kconfig.kgdb | 18 ++++++++++++++++++ + 2 files changed, 42 insertions(+), 17 deletions(-) + +diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c +index cbc4822..6d6286c 100644 +--- a/drivers/misc/kgdbts.c ++++ b/drivers/misc/kgdbts.c +@@ -112,6 +112,10 @@ + printk(KERN_INFO a); \ + touch_nmi_watchdog(); \ + } while (0) ++#define eprintk(a...) do { \ ++ printk(KERN_ERR a); \ ++ WARN_ON(1); \ ++ } while (0) + #define MAX_CONFIG_LEN 40 + + static const char hexchars[] = "0123456789abcdef"; +@@ -145,7 +149,11 @@ static struct pt_regs kgdbts_regs; + /* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ + static int configured = -1; + ++#ifdef CONFIG_KGDB_TESTS_BOOT_STRING ++static char config[MAX_CONFIG_LEN] = CONFIG_KGDB_TESTS_BOOT_STRING; ++#else + static char config[MAX_CONFIG_LEN]; ++#endif + static struct kparam_string kps = { + .string = config, + .maxlen = MAX_CONFIG_LEN, +@@ -289,7 +297,7 @@ static int check_and_rewind_pc(char *put_str, char *arg) + #endif + if (strcmp(arg, "silent") && + instruction_pointer(&kgdbts_regs) + offset != addr) { +- printk(KERN_ERR "kgdbts: BP mismatch %lx expected %lx\n", ++ eprintk("kgdbts: BP mismatch %lx expected %lx\n", + instruction_pointer(&kgdbts_regs) + offset, addr); + return 1; + } +@@ -313,7 +321,7 @@ static int check_single_step(char *put_str, char *arg) + v2printk("Singlestep stopped at IP: %lx\n", + instruction_pointer(&kgdbts_regs)); + if (instruction_pointer(&kgdbts_regs) == addr) { +- printk(KERN_ERR "kgdbts: SingleStep failed at %lx\n", ++ eprintk("kgdbts: SingleStep failed at %lx\n", + instruction_pointer(&kgdbts_regs)); + return 1; + } +@@ -378,7 +386,7 @@ static void emul_sstep_get(char *arg) + break_helper("z0", 0, sstep_addr); + break; + default: +- printk(KERN_ERR "kgdbts: ERROR failed sstep get emulation\n"); ++ eprintk("kgdbts: ERROR failed sstep get emulation\n"); + } + sstep_state++; + } +@@ -404,26 +412,26 @@ static int emul_sstep_put(char *put_str, char *arg) + break; + case 2: + if (strncmp(put_str, "$OK", 3)) { +- printk(KERN_ERR "kgdbts: failed sstep break set\n"); ++ eprintk("kgdbts: failed sstep break set\n"); + return 1; + } + break; + case 3: + if (strncmp(put_str, "$T0", 3)) { +- printk(KERN_ERR "kgdbts: failed continue sstep\n"); ++ eprintk("kgdbts: failed continue sstep\n"); + return 1; + } + break; + case 4: + if (strncmp(put_str, "$OK", 3)) { +- printk(KERN_ERR "kgdbts: failed sstep break unset\n"); ++ eprintk("kgdbts: failed sstep break unset\n"); + return 1; + } + /* Single step is complete so continue on! */ + sstep_state = 0; + return 0; + default: +- printk(KERN_ERR "kgdbts: ERROR failed sstep put emulation\n"); ++ eprintk("kgdbts: ERROR failed sstep put emulation\n"); + } + + /* Continue on the same test line until emulation is complete */ +@@ -668,8 +676,7 @@ static int run_simple_test(int is_get_char, int chr) + } + + if (get_buf[get_buf_cnt] == '\0') { +- printk(KERN_ERR +- "kgdbts: ERROR GET: end of buffer on '%s' at %i\n", ++ eprintk("kgdbts: ERROR GET: EOB on '%s' at %i\n", + ts.name, ts.idx); + get_buf_cnt = 0; + fill_get_buf("D"); +@@ -684,13 +691,13 @@ static int run_simple_test(int is_get_char, int chr) + */ + if (ts.tst[ts.idx].get[0] == '\0' && + ts.tst[ts.idx].put[0] == '\0') { +- printk(KERN_ERR "kgdbts: ERROR: beyond end of test on" ++ eprintk("kgdbts: ERROR: beyond end of test on" + " '%s' line %i\n", ts.name, ts.idx); + return 0; + } + + if (put_buf_cnt >= BUFMAX) { +- printk(KERN_ERR "kgdbts: ERROR: put buffer overflow on" ++ eprintk("kgdbts: ERROR: put buffer overflow on" + " '%s' line %i\n", ts.name, ts.idx); + put_buf_cnt = 0; + return 0; +@@ -708,7 +715,7 @@ static int run_simple_test(int is_get_char, int chr) + v2printk("put%i: %s\n", ts.idx, put_buf); + /* Trigger check here */ + if (ts.validate_put && ts.validate_put(put_buf)) { +- printk(KERN_ERR "kgdbts: ERROR PUT: end of test " ++ eprintk("kgdbts: ERROR PUT: end of test " + "buffer on '%s' line %i expected %s got %s\n", + ts.name, ts.idx, ts.tst[ts.idx].put, put_buf); + } +@@ -772,7 +779,7 @@ static void run_breakpoint_test(int is_hw_breakpoint) + if (test_complete) + return; + +- printk(KERN_ERR "kgdbts: ERROR %s test failed\n", ts.name); ++ eprintk("kgdbts: ERROR %s test failed\n", ts.name); + } + + static void run_hw_break_test(int is_write_test) +@@ -791,7 +798,7 @@ static void run_hw_break_test(int is_write_test) + hw_break_val_access(); + if (is_write_test) { + if (test_complete == 2) +- printk(KERN_ERR "kgdbts: ERROR %s broke on access\n", ++ eprintk("kgdbts: ERROR %s broke on access\n", + ts.name); + hw_break_val_write(); + } +@@ -800,7 +807,7 @@ static void run_hw_break_test(int is_write_test) + if (test_complete == 1) + return; + +- printk(KERN_ERR "kgdbts: ERROR %s test failed\n", ts.name); ++ eprintk("kgdbts: ERROR %s test failed\n", ts.name); + } + + static void run_nmi_sleep_test(int nmi_sleep) +@@ -817,12 +824,12 @@ static void run_nmi_sleep_test(int nmi_sleep) + touch_nmi_watchdog(); + local_irq_restore(flags); + if (test_complete != 2) +- printk(KERN_ERR "kgdbts: ERROR nmi_test did not hit nmi\n"); ++ eprintk("kgdbts: ERROR nmi_test did not hit nmi\n"); + kgdb_breakpoint(); + if (test_complete == 1) + return; + +- printk(KERN_ERR "kgdbts: ERROR %s test failed\n", ts.name); ++ eprintk("kgdbts: ERROR %s test failed\n", ts.name); + } + + static void run_bad_read_test(void) +diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb +index aaabcdd..f2e01ac 100644 +--- a/lib/Kconfig.kgdb ++++ b/lib/Kconfig.kgdb +@@ -38,3 +38,21 @@ config KGDB_TESTS + See the drivers/misc/kgdbts.c for the details about + the tests. The most basic of this I/O module is to boot + a kernel boot arguments "kgdbwait kgdbts=V1F100" ++ ++config KGDB_TESTS_ON_BOOT ++ bool "KGDB: Run tests on boot" ++ depends on KGDB_TESTS ++ default n ++ help ++ Run the kgdb tests on boot up automatically without the need ++ to pass in a kernel parameter ++ ++config KGDB_TESTS_BOOT_STRING ++ string "KGDB: which internal kgdb tests to run" ++ depends on KGDB_TESTS_ON_BOOT ++ default "V1F100" ++ help ++ This is the command string to send the kgdb test suite on ++ boot. See the drivers/misc/kgdbts.c for detailed ++ information about other strings you could use beyond the ++ default of V1F100. +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0166-Ubuntu-NBK-Ubuntu-2.6.24-25.62netbook01.patch +++ linux-2.6.24/patches/0166-Ubuntu-NBK-Ubuntu-2.6.24-25.62netbook01.patch @@ -0,0 +1,29 @@ +From a7802b98578c9f0023be924088223b5441a4f9f8 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Fri, 16 Oct 2009 09:29:16 -0500 +Subject: [PATCH 166/170] Ubuntu: NBK-Ubuntu-2.6.24-25.62netbook01 + +Signed-off-by: Steve Conklin +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 9cd035d..2d022f9 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-25.62netbook01) netbook-common; urgency=low ++ ++ [ Steve Conklin] ++ ++ * Rebase onto hardy distro SRU release Ubuntu-2.6.24-25.62 ++ ++ -- sconklin Fri, 16 Oct 2009 14:11:25 +0000 ++ + linux (2.6.24-24.59netbook02) netbook-common; urgency=low + + [Steve Conklin] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0026-kgdb-stand-alone-8250-for-early-debug.patch +++ linux-2.6.24/patches/0026-kgdb-stand-alone-8250-for-early-debug.patch @@ -0,0 +1,726 @@ +From 8c70a5c6a12b13e0bdc81a6eec6bc7ec3bda7cec Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:46 -0500 +Subject: [PATCH 026/170] kgdb: stand alone 8250 for early debug + +Documentation and a kgdb8250 implementation for to allow for early +rs232 debugging as well as to have a dedicated rs232 port for +debugging. + +This driver was significantly cleaned up by Jan Kiszka who added the +ability for the I/O driver to work as a built-in with dynamic +configuration. + +Signed-off-by: Jason Wessel +Signed-off-by: Jan Kiszka +--- + Documentation/DocBook/kgdb.tmpl | 93 ++++++++ + drivers/serial/8250.c | 30 +++ + drivers/serial/8250_kgdb.c | 489 +++++++++++++++++++++++++++++++++++++++ + drivers/serial/Makefile | 1 + + include/linux/serial_8250.h | 1 + + lib/Kconfig.kgdb | 20 ++ + 6 files changed, 634 insertions(+), 0 deletions(-) + create mode 100644 drivers/serial/8250_kgdb.c + +diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl +index 97618be..6e1e2a1 100644 +--- a/Documentation/DocBook/kgdb.tmpl ++++ b/Documentation/DocBook/kgdb.tmpl +@@ -147,6 +147,99 @@ + kgdb I/O driver as a kernel module kgdbwait will not do anything. + + ++ ++ Kernel parameter: kgdb8250 ++ ++ You can build the make the kgdb8250 driver as a kernel module ++ "8250_kgdb.ko" or as a built-in. Either way you must pass the ++ parameter kgdb8250=<args described ++ below> to configure the I/O driver. Alternately if ++ you used the kgdb8250 kgdb I/O driver as a built-in you can ++ configure it at run time by using the echo command to send the ++ configuration into the sysfs parameters. Note that when using ++ sysfs, you omit the "kgdb8250=" For example: ++ ++ kgdb8250=ttyS<n>,<baud rate> ++ ++ ++ ++ You can also return kgdb back to the unregistered state by using: ++ ++ echo "" > /sys/module/8250_kgdb/paramaters/kgdb8250 ++ ++ ++ ++ When loading the 8250_kgdb.ko module or using the kgdb8250 driver as a built in, the configuration takes one of two forms. ++ ++ Full serial address specification: ++ ++ kgdb8250=<io|mmio>,<address>[/<regshift>],<baud rate>,<irq> ++ ++ The values io or mmio ++ refer to if the address being passed next needs to be memory ++ mapped (mmio) or not. The ++ address must be passed in hex and is the ++ hardware address and will be remapped if passed as ++ mmio. An optional ++ regshift value can be given to express ++ address spreading of the 8250 ++ registers. regshift just as the succeeding ++ baud rate and irq values ++ are base-10. The supported values for baud ++ rate are 9600, ++ 19200, 38400, ++ 57600, and 115200. ++ ++ ++ To specify the values of the serial port at boot: ++ ++ ++ kgdb8250=io,3f8,115200,3 ++ ++ ++ On certain non x86 archs it might look something like: ++ ++ ++ kgdb8250=mmio,0xff5e0000,115200,74 ++ ++ ++ ++ ++ Simple configuration: ++ ++ kgdb8250=<tty_name>,<baud rate> ++ ++ ++ The simple configuration can be used so long as you are not trying ++ to perform "early" debugging on a platform that supports early ++ debugging. Early debugging allows you to debug the kernel prior ++ to console_init() and the tty driver registration. In the case of ++ the simple configuration the address, port type and irq ++ information can be obtained dynamically by the kgdb I/O driver ++ after the tty's are registered. Here is an example of the simple ++ configuration parameter for ttyS0: ++ ++ ++ kgdb8250=ttyS0,115200 ++ ++ ++ ++ ++ ++ If you do use the full serial address configuration and the ++ kgdbwait parameter to boot your kernel, on some architectures it ++ may be able to stop before console output has started in which it ++ might look like the target machine is hung when in reality it is ++ just waiting for the debugger. ++ ++ ++ Finally, it should be noted that you should not try to multiplex a ++ standard serial console and use the kgdb8250 driver at the same ++ time if you have a single serial port IE: "console=ttyS0,11520 ++ kgdb8250=ttyS0,115200". You should use the kgdboc and not the ++ kgdb8250 driver if this is what you want to do. ++ ++ + + Kernel parameter: kgdboc + +diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c +index 30c1622..d57244f 100644 +--- a/drivers/serial/8250.c ++++ b/drivers/serial/8250.c +@@ -2640,6 +2640,7 @@ int serial8250_find_port(struct uart_port *p) + } + return -ENODEV; + } ++EXPORT_SYMBOL_GPL(serial8250_find_port); + + #define SERIAL8250_CONSOLE &serial8250_console + #else +@@ -2921,6 +2922,35 @@ void serial8250_unregister_port(int line) + } + EXPORT_SYMBOL(serial8250_unregister_port); + ++/** ++ * serial8250_get_port_def - Get port definition for a specific line ++ * @port: generic uart_port output for a specific serial line ++ * @line: specific serial line index ++ * ++ * Return 0 if the port existed ++ * Return -errno on failure ++ */ ++int serial8250_get_port_def(struct uart_port *port, int line) ++{ ++ struct uart_port *port8250 = &serial8250_ports[line].port; ++ ++ if (!port8250->iobase && !port8250->membase) ++ return -ENODEV; ++ ++ port->iobase = port8250->iobase; ++ port->membase = port8250->membase; ++ port->irq = port8250->irq; ++ port->uartclk = port8250->uartclk; ++ port->fifosize = port8250->fifosize; ++ port->regshift = port8250->regshift; ++ port->iotype = port8250->iotype; ++ port->flags = port8250->flags; ++ port->mapbase = port8250->mapbase; ++ port->dev = port8250->dev; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(serial8250_get_port_def); ++ + static int __init serial8250_init(void) + { + int ret, i; +diff --git a/drivers/serial/8250_kgdb.c b/drivers/serial/8250_kgdb.c +new file mode 100644 +index 0000000..ea42ea7 +--- /dev/null ++++ b/drivers/serial/8250_kgdb.c +@@ -0,0 +1,489 @@ ++/* ++ * 8250 serial I/O driver for KGDB. ++ * ++ * This is a merging of many different drivers, and all of the people have ++ * had an impact in some form or another: ++ * ++ * 2004-2005 (c) MontaVista Software, Inc. ++ * 2005-2006 (c) Wind River Systems, Inc. ++ * ++ * Amit Kale , David Grothe , ++ * Scott Foehner , George Anzinger , ++ * Robert Walsh , wangdi , ++ * San Mehat, Tom Rini , ++ * Jason Wessel ++ * ++ * Refactoring and cleanup for initial merge: ++ * 2008 (c) Jan Kiszka ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* for BASE_BAUD */ ++ ++MODULE_DESCRIPTION("KGDB driver for the 8250"); ++MODULE_LICENSE("GPL"); ++ ++#define KGD8250_MAX_CONFIG_STR 64 ++static char config[KGD8250_MAX_CONFIG_STR]; ++static struct kparam_string kps = { ++ .string = config, ++ .maxlen = KGD8250_MAX_CONFIG_STR, ++}; ++ ++static int kgdb8250_baud; ++static void *kgdb8250_addr; ++static int kgdb8250_irq = -1; ++static struct uart_port kgdb8250_port; ++ ++/* UART port we might have stolen from the 8250 driver */ ++static int hijacked_line; ++ ++static int late_init_passed; ++static int fully_initialized; ++static int buffered_char = -1; ++ ++static struct kgdb_io kgdb8250_io_ops; /* initialized later */ ++ ++static int kgdb8250_uart_init(void); ++ ++static inline unsigned int kgdb8250_ioread(u8 mask) ++{ ++ return ioread8(kgdb8250_addr + (mask << kgdb8250_port.regshift)); ++} ++ ++static inline void kgdb8250_iowrite(u8 val, u8 mask) ++{ ++ iowrite8(val, kgdb8250_addr + (mask << kgdb8250_port.regshift)); ++} ++ ++/* ++ * Wait until the interface can accept a char, then write it. ++ */ ++static void kgdb8250_put_debug_char(u8 chr) ++{ ++ while (!(kgdb8250_ioread(UART_LSR) & UART_LSR_THRE)) ++ cpu_relax(); ++ ++ kgdb8250_iowrite(chr, UART_TX); ++} ++ ++/* ++ * Get a byte from the hardware data buffer and return it. ++ */ ++static int kgdb8250_get_debug_char(void) ++{ ++ unsigned int lsr; ++ ++ while (1) { ++ /* Did the interrupt handler catch something before us? */ ++ if (buffered_char >= 0) ++ return xchg(&buffered_char, -1); ++ ++ lsr = kgdb8250_ioread(UART_LSR); ++ if (lsr & UART_LSR_DR) ++ return kgdb8250_ioread(UART_RX); ++ ++ /* ++ * If we have a framing error assume somebody messed with ++ * our uart. Reprogram it and send '-' both ways... ++ */ ++ if (lsr & (UART_LSR_PE | UART_LSR_FE)) { ++ kgdb8250_uart_init(); ++ kgdb8250_put_debug_char('-'); ++ return '-'; ++ } ++ ++ cpu_relax(); ++ } ++} ++ ++/* ++ * This is the receiver interrupt routine for the GDB stub. ++ * All that we need to do is verify that the interrupt happened on the ++ * line we're in charge of. If this is true, schedule a breakpoint and ++ * return. ++ */ ++static irqreturn_t kgdb8250_interrupt(int irq, void *dev_id) ++{ ++ unsigned int iir = kgdb8250_ioread(UART_IIR); ++ char c; ++ ++ if (iir & UART_IIR_NO_INT) ++ return IRQ_NONE; ++ ++ if ((iir & UART_IIR_ID) == UART_IIR_RDI) { ++ c = kgdb8250_ioread(UART_RX); ++ if (c != 0x03) ++ buffered_char = c; ++ if (c == 0x03 || (c == '$' && !kgdb_connected)) ++ kgdb_breakpoint(); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Initializes the UART. ++ * Returns: ++ * 0 on success, -errno on failure. ++ */ ++static int kgdb8250_uart_init(void) ++{ ++ unsigned int ier; ++ unsigned int base_baud = kgdb8250_port.uartclk ? ++ kgdb8250_port.uartclk / 16 : BASE_BAUD; ++ ++ /* Test UART existance. */ ++ if (kgdb8250_ioread(UART_LSR) == 0xff) ++ return -EIO; ++ ++ /* Disable interrupts. */ ++ kgdb8250_iowrite(0, UART_IER); ++ ++#ifdef CONFIG_ARCH_OMAP1510 ++ /* Workaround to enable 115200 baud on OMAP1510 internal ports */ ++ if (cpu_is_omap1510() && is_omap_port((void *)kgdb8250_addr)) { ++ if (kgdb8250_baud == 115200) { ++ base_baud = 1; ++ kgdb8250_baud = 1; ++ kgdb8250_iowrite(1, UART_OMAP_OSC_12M_SEL); ++ } else ++ kgdb8250_iowrite(0, UART_OMAP_OSC_12M_SEL); ++ } ++#endif ++ ++ /* Line settings 8n1, no FIFO, DTR+RTS on. */ ++ kgdb8250_iowrite(UART_LCR_WLEN8, UART_LCR); ++ kgdb8250_iowrite(0, UART_FCR); ++ kgdb8250_iowrite(UART_MCR_OUT2 | UART_MCR_DTR | ++ UART_MCR_RTS, UART_MCR); ++ ++ /* Set baud rate. */ ++ kgdb8250_iowrite(UART_LCR_WLEN8 | UART_LCR_DLAB, UART_LCR); ++ kgdb8250_iowrite((base_baud / kgdb8250_baud) & 0xff, UART_DLL); ++ kgdb8250_iowrite((base_baud / kgdb8250_baud) >> 8, UART_DLM); ++ kgdb8250_iowrite(UART_LCR_WLEN8, UART_LCR); ++ ++ /* Clear pending interrupts. */ ++ (void) kgdb8250_ioread(UART_IIR); ++ (void) kgdb8250_ioread(UART_RX); ++ (void) kgdb8250_ioread(UART_LSR); ++ (void) kgdb8250_ioread(UART_MSR); ++ ++ /* ++ * Borrowed from the main 8250 driver. ++ * Try writing and reading the UART_IER_UUE bit (b6). ++ * If it works, this is probably one of the Xscale platform's ++ * internal UARTs. ++ * We're going to explicitly set the UUE bit to 0 before ++ * trying to write and read a 1 just to make sure it's not ++ * already a 1 and maybe locked there before we even start start. ++ */ ++ ier = kgdb8250_ioread(UART_IER); ++ kgdb8250_iowrite(ier & ~UART_IER_UUE, UART_IER); ++ if (!(kgdb8250_ioread(UART_IER) & UART_IER_UUE)) { ++ /* ++ * OK it's in a known zero state, try writing and reading ++ * without disturbing the current state of the other bits. ++ */ ++ kgdb8250_iowrite(ier | UART_IER_UUE, UART_IER); ++ if (kgdb8250_ioread(UART_IER) & UART_IER_UUE) ++ /* It's an Xscale. */ ++ ier |= UART_IER_UUE | UART_IER_RTOIE; ++ } ++ kgdb8250_iowrite(ier, UART_IER); ++ ++ return 0; ++} ++ ++/* ++ * Syntax for this cmdline option is: ++ * ,
[/],, or ++ * ttyS, ++ */ ++static int kgdb8250_parse_config(char *str) ++{ ++ int line, err; ++ ++ /* Save the option string in case we fail and can retry later. */ ++ strncpy(config, str, KGD8250_MAX_CONFIG_STR-1); ++ ++ /* Empty config or leading white space (like LF) means "disabled" */ ++ if (!strlen(config) || isspace(config[0])) ++ return 0; ++ ++ if (!strncmp(str, "io", 2)) { ++ kgdb8250_port.iotype = UPIO_PORT; ++ str += 2; ++ } else if (!strncmp(str, "mmio", 4)) { ++ kgdb8250_port.iotype = UPIO_MEM; ++ kgdb8250_port.flags = UPF_IOREMAP; ++ str += 4; ++ } else if (!strncmp(str, "ttyS", 4)) { ++ str += 4; ++ if (*str < '0' || *str > '9') ++ return -EINVAL; ++ line = simple_strtoul(str, &str, 10); ++ if (line >= CONFIG_SERIAL_8250_NR_UARTS) ++ return -EINVAL; ++ ++ err = serial8250_get_port_def(&kgdb8250_port, line); ++ if (err) { ++ if (late_init_passed) ++ return err; ++ printk(KERN_WARNING "kgdb8250: ttyS%d init delayed, " ++ "use io/mmio syntax for early init.\n", ++ line); ++ return 0; ++ } ++ ++ if (*str != ',') ++ return -EINVAL; ++ str++; ++ ++ kgdb8250_baud = simple_strtoul(str, &str, 10); ++ if (!kgdb8250_baud) ++ return -EINVAL; ++ ++ if (*str == ',') ++ return -EINVAL; ++ ++ goto finish; ++ } else ++ return -EINVAL; ++ ++ if (*str != ',') ++ return -EINVAL; ++ str++; ++ ++ if (kgdb8250_port.iotype == UPIO_PORT) ++ kgdb8250_port.iobase = simple_strtoul(str, &str, 16); ++ else ++ kgdb8250_port.mapbase = ++ (unsigned long)simple_strtoul(str, &str, 16); ++ ++ if (*str == '/') { ++ str++; ++ kgdb8250_port.regshift = simple_strtoul(str, &str, 10); ++ } ++ ++ if (*str != ',') ++ return -EINVAL; ++ str++; ++ ++ kgdb8250_baud = simple_strtoul(str, &str, 10); ++ if (!kgdb8250_baud) ++ return -EINVAL; ++ ++ if (*str != ',') ++ return -EINVAL; ++ str++; ++ ++ kgdb8250_port.irq = simple_strtoul(str, &str, 10); ++ ++finish: ++ err = kgdb_register_io_module(&kgdb8250_io_ops); ++ if (err) ++ kgdb8250_addr = 0; ++ ++ return err; ++} ++ ++static int kgdb8250_early_init(void) ++{ ++ /* Internal driver setup. */ ++ switch (kgdb8250_port.iotype) { ++ case UPIO_MEM: ++ if (kgdb8250_port.flags & UPF_IOREMAP) ++ kgdb8250_port.membase = ioremap(kgdb8250_port.mapbase, ++ 8 << kgdb8250_port.regshift); ++ kgdb8250_addr = kgdb8250_port.membase; ++ break; ++ case UPIO_PORT: ++ default: ++ kgdb8250_addr = ioport_map(kgdb8250_port.iobase, ++ 8 << kgdb8250_port.regshift); ++ } ++ if (!kgdb8250_addr) ++ return -EIO; ++ ++ if (kgdb8250_uart_init() < 0) { ++ printk(KERN_ERR "kgdb8250: UART initialization failed\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int kgdb8250_late_init(void) ++{ ++ int err; ++ ++ if (fully_initialized) ++ return 0; ++ ++ late_init_passed = 1; ++ ++ /* ++ * If we didn't initialize yet or if an earlier attempt failed, ++ * evaluate the configuration and register with KGDB. ++ */ ++ if (!kgdb8250_addr) { ++ err = kgdb8250_parse_config(config); ++ if (err || !kgdb8250_addr) ++ return err; ++ } ++ ++ /* Take the port away from the main driver. */ ++ hijacked_line = serial8250_find_port(&kgdb8250_port); ++ if (hijacked_line >= 0) ++ serial8250_unregister_port(hijacked_line); ++ ++ /* Now reinit the port as the above has disabled things. */ ++ kgdb8250_uart_init(); ++ ++ /* Request memory/io regions that we use. */ ++ if (kgdb8250_port.iotype == UPIO_MEM) { ++ if (!request_mem_region(kgdb8250_port.mapbase, ++ 8 << kgdb8250_port.regshift, "kgdb")) ++ goto rollback; ++ } else { ++ if (!request_region(kgdb8250_port.iobase, ++ 8 << kgdb8250_port.regshift, "kgdb")) ++ goto rollback; ++ } ++ ++ if (request_irq(kgdb8250_port.irq, kgdb8250_interrupt, IRQF_SHARED, ++ "kgdb", &kgdb8250_port) == 0) { ++ /* Turn on RX interrupt only. */ ++ kgdb8250_iowrite(UART_IER_RDI, UART_IER); ++ ++ kgdb8250_irq = kgdb8250_port.irq; ++ } else { ++ /* ++ * The IRQ line is not mandatory for KGDB to provide at least ++ * basic services. So report the error and continue. ++ */ ++ printk(KERN_ERR "kgdb8250: failed to request the IRQ (%d)\n", ++ kgdb8250_irq); ++ kgdb8250_irq = -1; ++ } ++ ++ fully_initialized = 1; ++ return 0; ++ ++rollback: ++ if (hijacked_line >= 0) ++ serial8250_register_port(&kgdb8250_port); ++ ++ printk(KERN_CRIT "kgdb: Unable to reserve mandatory hardware " ++ "resources.\n"); ++ return -EBUSY; ++} ++ ++static void kgdb8250_cleanup(void) ++{ ++ void *ioaddr = kgdb8250_addr; ++ ++ if (!kgdb8250_addr) ++ return; ++ ++ /* Disable and unregister interrupt. */ ++ kgdb8250_iowrite(0, UART_IER); ++ (void) kgdb8250_ioread(UART_RX); ++ ++ if (kgdb8250_irq >= 0) ++ free_irq(kgdb8250_irq, &kgdb8250_port); ++ ++ /* Deregister from KGDB core. */ ++ kgdb_unregister_io_module(&kgdb8250_io_ops); ++ kgdb8250_addr = 0; ++ ++ if (!fully_initialized) ++ return; ++ ++ fully_initialized = 0; ++ ++ if (kgdb8250_port.iotype == UPIO_MEM) { ++ if (kgdb8250_port.flags & UPF_IOREMAP) ++ iounmap(kgdb8250_port.membase); ++ release_mem_region(kgdb8250_port.mapbase, ++ 8 << kgdb8250_port.regshift); ++ } else { ++ ioport_unmap(ioaddr); ++ release_region(kgdb8250_port.iobase, ++ 8 << kgdb8250_port.regshift); ++ } ++ ++ /* Give the port back to the 8250 driver. */ ++ if (hijacked_line >= 0) ++ serial8250_register_port(&kgdb8250_port); ++} ++ ++static int kgdb8250_set_config(const char *kmessage, struct kernel_param *kp) ++{ ++ int err; ++ ++ if (strlen(kmessage) >= KGD8250_MAX_CONFIG_STR) { ++ printk(KERN_ERR "%s: config string too long.\n", kp->name); ++ return -ENOSPC; ++ } ++ ++ if (kgdb_connected) { ++ printk(KERN_ERR "kgd8250: Cannot reconfigure while KGDB is " ++ "connected.\n"); ++ return -EBUSY; ++ } ++ ++ if (kgdb8250_addr) ++ kgdb8250_cleanup(); ++ ++ err = kgdb8250_parse_config((char *)kmessage); ++ ++ if (err || !late_init_passed) ++ return err; ++ ++ /* Call the botton-half initialization as we are re-configuring. */ ++ return kgdb8250_late_init(); ++} ++ ++static void kgdb8250_pre_exception_handler(void) ++{ ++ if (!kgdb_connected) ++ try_module_get(THIS_MODULE); ++} ++ ++static void kgdb8250_post_exception_handler(void) ++{ ++ if (!kgdb_connected) ++ module_put(THIS_MODULE); ++} ++ ++static struct kgdb_io kgdb8250_io_ops = { ++ .name = "kgdb8250", ++ .read_char = kgdb8250_get_debug_char, ++ .write_char = kgdb8250_put_debug_char, ++ .init = kgdb8250_early_init, ++ .pre_exception = kgdb8250_pre_exception_handler, ++ .post_exception = kgdb8250_post_exception_handler, ++}; ++ ++module_init(kgdb8250_late_init); ++module_exit(kgdb8250_cleanup); ++ ++module_param_call(kgdb8250, kgdb8250_set_config, param_get_string, &kps, 0644); ++MODULE_PARM_DESC(kgdb8250, "ttyS,"); ++ ++#ifdef CONFIG_KGDB_8250 ++early_param("kgdb8250", kgdb8250_parse_config); ++#endif +diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile +index 5aa9765..03286cd 100644 +--- a/drivers/serial/Makefile ++++ b/drivers/serial/Makefile +@@ -65,3 +65,4 @@ obj-$(CONFIG_SERIAL_NETX) += netx-serial.o + obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o + obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o + obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o ++obj-$(CONFIG_KGDB_8250) += 8250_kgdb.o +diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h +index afe0f6d..bec84cf 100644 +--- a/include/linux/serial_8250.h ++++ b/include/linux/serial_8250.h +@@ -65,5 +65,6 @@ extern int early_serial_setup(struct uart_port *port); + extern int serial8250_find_port(struct uart_port *p); + extern int serial8250_find_port_for_earlycon(void); + extern int setup_early_serial8250_console(char *cmdline); ++int serial8250_get_port_def(struct uart_port *port, int line); + + #endif +diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb +index 0c359dd..bb7c5a5 100644 +--- a/lib/Kconfig.kgdb ++++ b/lib/Kconfig.kgdb +@@ -34,6 +34,26 @@ config KGDB_SERIAL_CONSOLE + Share a serial console with kgdb. Sysrq-g must be used + to break in initially. + ++config KGDB_8250 ++ tristate "8250/16550 and compatible serial support" ++ depends on KGDB ++ select SERIAL_8250 ++ help ++ Uses a 8250/16550 compatible serial ports to communicate with the ++ host GDB. This is independent of the normal driver (SERIAL_8250) ++ for this chipset. The port is configured via kgdb8250=, ++ passed as kernel or module parameter, respectively. The ++ configuration comes in two flavors: ++ ++ ,
[/],, ++ or ++ ttyS, ++ ++ When built into the kernel, this driver allows debugging of ++ the early boot process. Note that, as long as the debugger is ++ attached via this driver, the configured serial port cannot be ++ used by the standard 8250 driver or serial earlyprintk/earlycon. ++ + config KGDB_TESTS + bool "KGDB: internal test suite" + depends on KGDB +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0104-UBUNTU-dib0700-add-basic-support-for-Hauppauge-Nova-.patch +++ linux-2.6.24/patches/0104-UBUNTU-dib0700-add-basic-support-for-Hauppauge-Nova-.patch @@ -0,0 +1,72 @@ +From a6aa127fd0ad44889e39abb785fdf1ed58d47d3e Mon Sep 17 00:00:00 2001 +From: Michael Krufky +Date: Fri, 20 Mar 2009 16:43:38 -0400 +Subject: [PATCH 104/170] UBUNTU: dib0700: add basic support for Hauppauge Nova-TD-500 (84xxx) + +OriginalAuthor: Michael Krufky +OriginalLocation: http://git.kernel.org/?p=linux/kernel/git/mkrufky/v4l-dvb-2.6.x.y.git;a=commitdiff_plain;h=9a0c04a1ee3b4df6a30ae6975e13c558908df400 + +backported upstream changeset: +V4L/DVB (8840): dib0700: add basic support for Hauppauge Nova-TD-500 (84xxx) + +This adds basic support for the Hauppauge Nova-TD-500 84xxx series. + +A future patch will allow for one aerial input to supply both tuners. + +With the current code, an aerial must be plugged into each antannae input +in order for both tuners to function. + +Signed-off-by: Michael Krufky +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- + drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + + 2 files changed, 7 insertions(+), 1 deletions(-) + +diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c +index 89e9dbf..5144f25 100644 +--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c ++++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c +@@ -842,6 +842,7 @@ struct usb_device_id dib0700_usb_id_table[] = { + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, ++ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, + /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, + { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, + { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, +@@ -1083,7 +1084,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { + } + }, + +- .num_device_descs = 3, ++ .num_device_descs = 4, + .devices = { + { "DiBcom STK7070PD reference design", + { &dib0700_usb_id_table[17], NULL }, +@@ -1097,6 +1098,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { + { &dib0700_usb_id_table[26], NULL }, + { NULL }, + }, ++ { "Hauppauge Nova-TD-500 (84xxx)", ++ { &dib0700_usb_id_table[27], NULL }, ++ { NULL }, ++ }, + } + }, + }; +diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +index c28f8d5..cb39ca1 100644 +--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h ++++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +@@ -121,6 +121,7 @@ + #define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 + #define USB_PID_HAUPPAUGE_NOVA_T_500 0x9941 + #define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 ++#define USB_PID_HAUPPAUGE_NOVA_T_500_3 0x8400 + #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 + #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 + #define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0151-UBUNTU-NBK-Ubuntu-2.6.24-24.53netbook01.patch +++ linux-2.6.24/patches/0151-UBUNTU-NBK-Ubuntu-2.6.24-24.53netbook01.patch @@ -0,0 +1,29 @@ +From a6d2f5495fc29b0d9c0d6d3344ceeec60bba7f8e Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Thu, 7 May 2009 14:28:30 -0500 +Subject: [PATCH 151/170] UBUNTU: NBK-Ubuntu-2.6.24-24.53netbook01 + +Signed-off-by: Steve Conklin +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 495f96b..45eedfa 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-24.53netbook01) netbook-common; urgency=low ++ ++ * Now that the rebase is finished, remove the whitespace correction ++ * This branch has been rebased onto the hardy distro release ++ Ubuntu-2.6.24-24.53 ++ ++ -- Steve Conklin Thu, 07 May 2009 19:23:35 +0000 ++ + linux (2.6.24-24.51netbook14) netbook-common; urgency=low + + * Incorporate minor change to not rename debug debs +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0012-kgdb-light-v10-x86-HW-breakpoints.patch +++ linux-2.6.24/patches/0012-kgdb-light-v10-x86-HW-breakpoints.patch @@ -0,0 +1,259 @@ +From c8409f05fc39f06cca6ac2ea1e9cebcb4898c427 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 15 Feb 2008 14:55:56 -0600 +Subject: [PATCH 012/170] kgdb-light-v10: x86 HW breakpoints + +Add HW breakpoints into the arch specific portion of x86 kgdb. In the +current x86 kernel.org kernels HW breakpoints are changed out in lazy +fashion because there is no infrastructure around changing them when +changing to a kernel task or entering the kernel mode via a system +call. This lazy approach means that if a user process uses HW +breakpoints the kgdb will loose out. This is an acceptable trade off +because the developer debugging the kernel is assumed to know what is +going on system wide and would be aware of this trade off. + +There is a minor bug fix to the kgdb core so as to correctly call the +hw breakpoint functions with a valid value from the enum. + +There is also a minor change to the x86_64 startup code when using +early HW breakpoints. When the debugger is connected, the cpu startup +code must not zero out the HW breakpoint registers or you cannot hit +the breakpoints you are interested in, in the first place. + +Signed-off-by: Jason Wessel +Signed-off-by: Ingo Molnar +--- + arch/x86/kernel/kgdb.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ + arch/x86/kernel/setup64.c | 16 +++++ + kernel/kgdb.c | 4 +- + 3 files changed, 156 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c +index 5d7a211..7d651ad 100644 +--- a/arch/x86/kernel/kgdb.c ++++ b/arch/x86/kernel/kgdb.c +@@ -182,6 +182,122 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) + #endif + } + ++static struct hw_breakpoint { ++ unsigned enabled; ++ unsigned type; ++ unsigned len; ++ unsigned long addr; ++} breakinfo[4]; ++ ++static void kgdb_correct_hw_break(void) ++{ ++ unsigned long dr7; ++ int correctit = 0; ++ int breakbit; ++ int breakno; ++ ++ get_debugreg(dr7, 7); ++ for (breakno = 0; breakno < 4; breakno++) { ++ breakbit = 2 << (breakno << 1); ++ if (!(dr7 & breakbit) && breakinfo[breakno].enabled) { ++ correctit = 1; ++ dr7 |= breakbit; ++ dr7 &= ~(0xf0000 << (breakno << 2)); ++ dr7 |= ((breakinfo[breakno].len << 2) | ++ breakinfo[breakno].type) << ++ ((breakno << 2) + 16); ++ if (breakno >= 0 && breakno <= 3) ++ set_debugreg(breakinfo[breakno].addr, breakno); ++ ++ } else { ++ if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { ++ correctit = 1; ++ dr7 &= ~breakbit; ++ dr7 &= ~(0xf0000 << (breakno << 2)); ++ } ++ } ++ } ++ if (correctit) ++ set_debugreg(dr7, 7); ++} ++ ++static int ++kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) ++{ ++ int i; ++ ++ for (i = 0; i < 4; i++) ++ if (breakinfo[i].addr == addr && breakinfo[i].enabled) ++ break; ++ if (i == 4) ++ return -1; ++ ++ breakinfo[i].enabled = 0; ++ ++ return 0; ++} ++ ++static void kgdb_remove_all_hw_break(void) ++{ ++ int i; ++ ++ for (i = 0; i < 4; i++) ++ memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint)); ++} ++ ++static int ++kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) ++{ ++ unsigned type; ++ int i; ++ ++ for (i = 0; i < 4; i++) ++ if (!breakinfo[i].enabled) ++ break; ++ if (i == 4) ++ return -1; ++ ++ switch (bptype) { ++ case BP_HARDWARE_BREAKPOINT: ++ type = 0; ++ len = 1; ++ break; ++ case BP_WRITE_WATCHPOINT: ++ type = 1; ++ break; ++ case BP_ACCESS_WATCHPOINT: ++ type = 3; ++ break; ++ default: ++ return -1; ++ } ++ ++ if (len == 1 || len == 2 || len == 4) ++ breakinfo[i].len = len - 1; ++ else ++ return -1; ++ ++ breakinfo[i].enabled = 1; ++ breakinfo[i].addr = addr; ++ breakinfo[i].type = type; ++ ++ return 0; ++} ++ ++/** ++ * kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb. ++ * @regs: Current &struct pt_regs. ++ * ++ * This function will be called if the particular architecture must ++ * disable hardware debugging while it is processing gdb packets or ++ * handling exception. ++ */ ++void kgdb_disable_hw_debug(struct pt_regs *regs) ++{ ++ /* Disable hardware debugging while we are in kgdb: */ ++ set_debugreg(0UL, 7); ++} ++ + /** + * kgdb_post_primary_code - Save error vector/code numbers. + * @regs: Original pt_regs. +@@ -243,6 +359,7 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, + struct pt_regs *linux_regs) + { + unsigned long addr; ++ unsigned long dr6; + char *ptr; + int newPC; + +@@ -269,6 +386,22 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, + } + } + ++ get_debugreg(dr6, 6); ++ if (!(dr6 & 0x4000)) { ++ int breakno; ++ ++ for (breakno = 0; breakno < 4; breakno++) { ++ if (dr6 & (1 << breakno) && ++ breakinfo[breakno].type == 0) { ++ /* Set restore flag: */ ++ linux_regs->flags |= X86_EFLAGS_RF; ++ break; ++ } ++ } ++ } ++ set_debugreg(0UL, 6); ++ kgdb_correct_hw_break(); ++ + return 0; + } + +@@ -426,4 +559,9 @@ unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs) + struct kgdb_arch arch_kgdb_ops = { + /* Breakpoint instruction: */ + .gdb_bpt_instr = { 0xcc }, ++ .flags = KGDB_HW_BREAKPOINT, ++ .set_hw_breakpoint = kgdb_set_hw_break, ++ .remove_hw_breakpoint = kgdb_remove_hw_break, ++ .remove_all_hw_break = kgdb_remove_all_hw_break, ++ .correct_hw_break = kgdb_correct_hw_break, + }; +diff --git a/arch/x86/kernel/setup64.c b/arch/x86/kernel/setup64.c +index 3558ac7..3f3191e 100644 +--- a/arch/x86/kernel/setup64.c ++++ b/arch/x86/kernel/setup64.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -278,6 +279,17 @@ void __cpuinit cpu_init (void) + load_TR_desc(); + load_LDT(&init_mm.context); + ++#ifdef CONFIG_KGDB ++ /* ++ * If the kgdb is connected no debug regs should be altered. This ++ * is only applicable when KGDB and a KGDB I/O module are built ++ * into the kernel and you are using early debugging with ++ * kgdbwait. KGDB will control the kernel HW breakpoint registers. ++ */ ++ if (kgdb_connected && arch_kgdb_ops.correct_hw_break) ++ arch_kgdb_ops.correct_hw_break(); ++ else { ++#endif + /* + * Clear all 6 debug registers: + */ +@@ -288,6 +300,10 @@ void __cpuinit cpu_init (void) + set_debugreg(0UL, 3); + set_debugreg(0UL, 6); + set_debugreg(0UL, 7); ++#ifdef CONFIG_KGDB ++ /* If the kgdb is connected no debug regs should be altered. */ ++ } ++#endif + + fpu_init(); + +diff --git a/kernel/kgdb.c b/kernel/kgdb.c +index 319c08c..68aea78 100644 +--- a/kernel/kgdb.c ++++ b/kernel/kgdb.c +@@ -1139,10 +1139,10 @@ static void gdb_cmd_break(struct kgdb_state *ks) + error = kgdb_remove_sw_break(addr); + else if (remcom_in_buffer[0] == 'Z') + error = arch_kgdb_ops.set_hw_breakpoint(addr, +- (int)length, *bpt_type); ++ (int)length, *bpt_type - '0'); + else if (remcom_in_buffer[0] == 'z') + error = arch_kgdb_ops.remove_hw_breakpoint(addr, +- (int) length, *bpt_type); ++ (int) length, *bpt_type - '0'); + + if (error == 0) + strcpy(remcom_out_buffer, "OK"); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0035-kgdb-kgdboc-console-poll-hooks-for-mpsc-uart.patch +++ linux-2.6.24/patches/0035-kgdb-kgdboc-console-poll-hooks-for-mpsc-uart.patch @@ -0,0 +1,193 @@ +From 6260b271875aaf7f610ea33485b03e195c669a9d Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:48 -0500 +Subject: [PATCH 035/170] kgdb: kgdboc console poll hooks for mpsc uart + +Add in console polling hooks for the mpsc uart for use with kgdboc. + +Signed-off-by: Jason Wessel +--- + drivers/serial/mpsc.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++- + 1 files changed, 138 insertions(+), 1 deletions(-) + +diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c +index 4d643c9..83a2aa1 100644 +--- a/drivers/serial/mpsc.c ++++ b/drivers/serial/mpsc.c +@@ -920,6 +920,10 @@ static int mpsc_make_ready(struct mpsc_port_info *pi) + return 0; + } + ++#ifdef CONFIG_CONSOLE_POLL ++static int serial_polled; ++#endif ++ + /* + ****************************************************************************** + * +@@ -955,7 +959,12 @@ static int mpsc_rx_intr(struct mpsc_port_info *pi) + while (!((cmdstat = be32_to_cpu(rxre->cmdstat)) + & SDMA_DESC_CMDSTAT_O)) { + bytes_in = be16_to_cpu(rxre->bytecnt); +- ++#ifdef CONFIG_CONSOLE_POLL ++ if (unlikely(serial_polled)) { ++ serial_polled = 0; ++ return 0; ++ } ++#endif + /* Following use of tty struct directly is deprecated */ + if (unlikely(tty_buffer_request_room(tty, bytes_in) + < bytes_in)) { +@@ -1016,6 +1025,12 @@ static int mpsc_rx_intr(struct mpsc_port_info *pi) + if (uart_handle_sysrq_char(&pi->port, *bp)) { + bp++; + bytes_in--; ++#ifdef CONFIG_CONSOLE_POLL ++ if (unlikely(serial_polled)) { ++ serial_polled = 0; ++ return 0; ++ } ++#endif + goto next_frame; + } + +@@ -1518,6 +1533,124 @@ static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser) + + return rc; + } ++#ifdef CONFIG_CONSOLE_POLL ++/* Serial polling routines for writing and reading from the uart while ++ * in an interrupt or debug context. ++ */ ++ ++static char poll_buf[2048]; ++static int poll_ptr; ++static int poll_cnt; ++static void mpsc_put_poll_char(struct uart_port *port, ++ unsigned char c); ++ ++static int mpsc_get_poll_char(struct uart_port *port) ++{ ++ struct mpsc_port_info *pi = (struct mpsc_port_info *)port; ++ struct mpsc_rx_desc *rxre; ++ u32 cmdstat, bytes_in, i; ++ u8 *bp; ++ ++ if (!serial_polled) ++ serial_polled = 1; ++ ++ pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line); ++ ++ if (poll_cnt) { ++ poll_cnt--; ++ return poll_buf[poll_ptr++]; ++ } ++ poll_ptr = 0; ++ poll_cnt = 0; ++ ++ while (poll_cnt == 0) { ++ rxre = (struct mpsc_rx_desc *)(pi->rxr + (pi->rxr_posn*MPSC_RXRE_SIZE)); ++ dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, DMA_FROM_DEVICE); ++#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) ++ if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ ++ invalidate_dcache_range((ulong)rxre, ++ (ulong)rxre + MPSC_RXRE_SIZE); ++#endif ++ /* ++ * Loop through Rx descriptors handling ones that have been completed. ++ */ ++ while (poll_cnt == 0 && !((cmdstat = be32_to_cpu(rxre->cmdstat)) & SDMA_DESC_CMDSTAT_O)){ ++ bytes_in = be16_to_cpu(rxre->bytecnt); ++ bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE); ++ dma_cache_sync(pi->port.dev, (void *) bp, MPSC_RXBE_SIZE, DMA_FROM_DEVICE); ++#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) ++ if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ ++ invalidate_dcache_range((ulong)bp, ++ (ulong)bp + MPSC_RXBE_SIZE); ++#endif ++ if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR | ++ SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) && ++ !(cmdstat & pi->port.ignore_status_mask)) { ++ poll_buf[poll_cnt] = *bp; ++ poll_cnt++; ++ } else { ++ for (i=0; iport.icount.rx += bytes_in; ++ } ++ rxre->bytecnt = cpu_to_be16(0); ++ wmb(); ++ rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | ++ SDMA_DESC_CMDSTAT_EI | ++ SDMA_DESC_CMDSTAT_F | ++ SDMA_DESC_CMDSTAT_L); ++ wmb(); ++ dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL); ++#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) ++ if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ ++ flush_dcache_range((ulong)rxre, ++ (ulong)rxre + MPSC_RXRE_SIZE); ++#endif ++ ++ /* Advance to next descriptor */ ++ pi->rxr_posn = (pi->rxr_posn + 1) & (MPSC_RXR_ENTRIES - 1); ++ rxre = (struct mpsc_rx_desc *)(pi->rxr + ++ (pi->rxr_posn * MPSC_RXRE_SIZE)); ++ dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, DMA_FROM_DEVICE); ++#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) ++ if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ ++ invalidate_dcache_range((ulong)rxre, ++ (ulong)rxre + MPSC_RXRE_SIZE); ++#endif ++ } ++ ++ /* Restart rx engine, if its stopped */ ++ if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0) ++ mpsc_start_rx(pi); ++ } ++ if (poll_cnt) { ++ poll_cnt--; ++ return poll_buf[poll_ptr++]; ++ } ++ ++ return 0; ++} ++ ++ ++static void mpsc_put_poll_char(struct uart_port *port, ++ unsigned char c) ++{ ++ struct mpsc_port_info *pi = (struct mpsc_port_info *)port; ++ u32 data; ++ ++ data = readl(pi->mpsc_base + MPSC_MPCR); ++ writeb(c, pi->mpsc_base + MPSC_CHR_1); ++ mb(); ++ data = readl(pi->mpsc_base + MPSC_CHR_2); ++ data |= MPSC_CHR_2_TTCS; ++ writel(data, pi->mpsc_base + MPSC_CHR_2); ++ mb(); ++ ++ while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS) ; ++} ++#endif + + static struct uart_ops mpsc_pops = { + .tx_empty = mpsc_tx_empty, +@@ -1536,6 +1669,10 @@ static struct uart_ops mpsc_pops = { + .request_port = mpsc_request_port, + .config_port = mpsc_config_port, + .verify_port = mpsc_verify_port, ++#ifdef CONFIG_CONSOLE_POLL ++ .poll_get_char = mpsc_get_poll_char, ++ .poll_put_char = mpsc_put_poll_char, ++#endif + }; + + /* +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0011-kgdb-light-v10-print-breakpoint-removed-on-exception.patch +++ linux-2.6.24/patches/0011-kgdb-light-v10-print-breakpoint-removed-on-exception.patch @@ -0,0 +1,31 @@ +From a044c960b549ba6aa6fcdbd860b359ae9e86e4c7 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 15 Feb 2008 14:55:55 -0600 +Subject: [PATCH 011/170] kgdb-light-v10: print breakpoint removed on exception + +If kgdb does remove a breakpoint that had a problem on the recursion +check, it should also print the address of the breakpoint. + +Signed-off-by: Jason Wessel +Signed-off-by: Ingo Molnar +--- + kernel/kgdb.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/kernel/kgdb.c b/kernel/kgdb.c +index e3f6037..319c08c 100644 +--- a/kernel/kgdb.c ++++ b/kernel/kgdb.c +@@ -1327,7 +1327,8 @@ static int kgdb_reenter_check(struct kgdb_state *ks) + exception_level = 0; + kgdb_skipexception(ks->ex_vector, ks->linux_regs); + kgdb_activate_sw_breakpoints(); +- printk(KERN_CRIT "KGDB: re-enter error: breakpoint removed\n"); ++ printk(KERN_CRIT "KGDB: re-enter error: breakpoint removed %lx\n", ++ addr); + WARN_ON_ONCE(1); + + return 1; +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0030-kgdb-Implement-kgdb-over-ethernet-with-NET_POLL.patch +++ linux-2.6.24/patches/0030-kgdb-Implement-kgdb-over-ethernet-with-NET_POLL.patch @@ -0,0 +1,494 @@ +From f2a93c96df86ef85283b53118e196db035617f0a Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:47 -0500 +Subject: [PATCH 030/170] kgdb: Implement kgdb over ethernet with NET_POLL + +At one point this was very similar to the version Matt Mackall wrote +to allow for the use of KGDB over ethernet. Since then it has been +reworked to fit into the unified KGDB model. + +This kgdb I/O driver can work as a kernel built-in or a kernel +module. + +Signed-off-by: Tom Rini +Signed-off-by: Jason Wessel +Acked-by: Matt Mackall +--- + Documentation/DocBook/kgdb.tmpl | 55 +++++++ + Documentation/kernel-parameters.txt | 7 + + drivers/net/Makefile | 1 + + drivers/net/kgdboe.c | 286 +++++++++++++++++++++++++++++++++++ + include/linux/kgdb.h | 1 + + kernel/kgdb.c | 26 +++ + lib/Kconfig.kgdb | 11 ++ + 7 files changed, 387 insertions(+), 0 deletions(-) + create mode 100644 drivers/net/kgdboe.c + +diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl +index 2438712..3bd42ac 100644 +--- a/Documentation/DocBook/kgdb.tmpl ++++ b/Documentation/DocBook/kgdb.tmpl +@@ -290,6 +290,61 @@ + + + ++ ++ Kernel parameter: kgdboe ++ ++ The term kgdboe is meant to stand for kgdb over ethernet. To use ++ kgdboe, the ethernet driver must have implemented the NETPOLL API, ++ and the kernel must be compiled with NETPOLL support. Also kgdboe ++ uses unicast udp. This means your debug host needs to be on the ++ same lan as the target system you wish to debug. ++ ++ ++ NOTE: Even though an ethernet driver may implement the NETPOLL API ++ it is possible that kgdboe will not work as a robust debug method. ++ Trying to debug the network stack for instance, would likely hang ++ the kernel. Also certain IRQ resources cannot be easily shared ++ between the normal kernel operation and the "polled context" where ++ the system is stopped by kgdb. Using kgdboe with preemptible IRQ ++ handlers for the device kgdboe is using is known to have with the ++ system hanging for instance. ++ ++ ++ The kgdboe parameter string is as follows: ++ kgdboe=[src-port]@<src-ip>/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr] ++ where: ++ ++ src-port (optional): source for UDP packets (defaults to 6443) ++ src-ip (optional unless from boot): source IP to use (interface address) ++ dev (optional): network interface (eth0) ++ tgt-port (optional): port GDB will use (defaults to 6442) ++ tgt-ip: IP address GDB will be connecting from ++ tgt-macaddr (optional): ethernet MAC address for logging agent (default is broadcast) ++ ++ ++ ++ What follows are several examples of how to configure kgdboe in various ways. ++ ++ From boot with target ip = 10.0.2.15 and debug host ip = 10.0.2.2 ++ kgdboe=@10.0.2.15/,@10.0.2.2/ ++ ++ From boot using eth1, with target ip = 10.0.2.15 and debug host ip = 10.0.2.2 ++ kgdboe=@10.0.2.15/eth1,@10.0.2.2/ ++ ++ As a module, with target ip = 10.0.2.15 and debug host ip = 10.0.2.2. NOTE: The src ip is only required when booting with kgdboe enabled ++ kgdboe=@/,@10.0.2.2/ ++ ++ ++ ++ ++ You can also reconfigure kgdboe dynamically at run time as follows: ++ ++ ++ echo "@/,@10.0.2.2/" > /sys/module/kgdboe/paramters/kgdboe ++ ++ ++ ++ + + Kernel parameter: kgdbcon + +diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt +index bad214a..864730a 100644 +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -821,6 +821,13 @@ and is between 256 and 4096 characters. It is defined in the file + ips= [HW,SCSI] Adaptec / IBM ServeRAID controller + See header of drivers/scsi/ips.c. + ++ kgdboe= [HW] Setup the local ip information and host ip ++ information when the network driver supports ++ NETPOLL and kgdboe is configured as a built in. ++ Options are: ++ [src-port]@/[dev],[tgt-port]@/ ++ IE: kgdboe=@10.0.1.2/,@10.0.0.1.3/ ++ + ports= [IP_VS_FTP] IPVS ftp helper module + Default is 21. + Up to 8 (IP_VS_APP_MAX_PORTS) ports +diff --git a/drivers/net/Makefile b/drivers/net/Makefile +index 0e5fde4..2a5d71a 100644 +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -241,6 +241,7 @@ obj-$(CONFIG_ETRAX_ETHERNET) += cris/ + obj-$(CONFIG_ENP2611_MSF_NET) += ixp2000/ + + obj-$(CONFIG_NETCONSOLE) += netconsole.o ++obj-$(CONFIG_KGDBOE) += kgdboe.o + + obj-$(CONFIG_FS_ENET) += fs_enet/ + +diff --git a/drivers/net/kgdboe.c b/drivers/net/kgdboe.c +new file mode 100644 +index 0000000..939797a +--- /dev/null ++++ b/drivers/net/kgdboe.c +@@ -0,0 +1,286 @@ ++/* ++ * drivers/net/kgdboe.c ++ * ++ * A network interface for GDB. ++ * Based upon 'gdbserial' by David Grothe ++ * and Scott Foehner ++ * ++ * Maintainer: Jason Wessel ++ * ++ * 2004 (c) Amit S. Kale ++ * 2004-2005 (c) MontaVista Software, Inc. ++ * 2005-2008 (c) Wind River Systems, Inc. ++ * ++ * Contributors at various stages not listed above: ++ * San Mehat , Robert Walsh , ++ * wangdi , Matt Mackall , ++ * Pavel Machek , Jason Wessel ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define IN_BUF_SIZE 512 /* power of 2, please */ ++#define OUT_BUF_SIZE 30 /* We don't want to send too big of a packet. */ ++#define MAX_CONFIG_LEN 256 ++ ++static char in_buf[IN_BUF_SIZE], out_buf[OUT_BUF_SIZE]; ++static int in_head, in_tail, out_count; ++static atomic_t in_count; ++/* 0 = unconfigured, 1 = netpoll options parsed, 2 = fully configured. */ ++static int configured; ++static struct kgdb_io local_kgdb_io_ops; ++static int use_dynamic_mac; ++ ++MODULE_DESCRIPTION("KGDB driver for network interfaces"); ++MODULE_LICENSE("GPL"); ++static char config[MAX_CONFIG_LEN]; ++static struct kparam_string kps = { ++ .string = config, ++ .maxlen = MAX_CONFIG_LEN, ++}; ++ ++static void rx_hook(struct netpoll *np, int port, char *msg, int len, ++ struct sk_buff *skb) ++{ ++ int i; ++ ++ np->remote_port = port; ++ ++ /* Copy the MAC address if we need to. */ ++ if (use_dynamic_mac) { ++ memcpy(np->remote_mac, eth_hdr(skb)->h_source, ++ sizeof(np->remote_mac)); ++ use_dynamic_mac = 0; ++ } ++ ++ /* ++ * This could be GDB trying to attach. But it could also be GDB ++ * finishing up a session, with kgdb_connected=0 but GDB sending ++ * an ACK for the final packet. To make sure we don't try and ++ * make a breakpoint when GDB is leaving, make sure that if ++ * !kgdb_connected the only len == 1 packet we allow is ^C. ++ */ ++ if (!kgdb_connected && (len != 1 || msg[0] == 3)) ++ kgdb_schedule_breakpoint(); ++ ++ for (i = 0; i < len; i++) { ++ if (msg[i] == 3) ++ kgdb_schedule_breakpoint(); ++ ++ if (atomic_read(&in_count) >= IN_BUF_SIZE) { ++ /* buffer overflow, clear it */ ++ in_head = 0; ++ in_tail = 0; ++ atomic_set(&in_count, 0); ++ break; ++ } ++ in_buf[in_head++] = msg[i]; ++ in_head &= (IN_BUF_SIZE - 1); ++ atomic_inc(&in_count); ++ } ++} ++ ++static struct netpoll np = { ++ .dev_name = "eth0", ++ .name = "kgdboe", ++ .rx_hook = rx_hook, ++ .local_port = 6443, ++ .remote_port = 6442, ++ .remote_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++}; ++ ++static void eth_pre_exception_handler(void) ++{ ++ /* Increment the module count when the debugger is active */ ++ if (!kgdb_connected) ++ try_module_get(THIS_MODULE); ++ netpoll_set_trap(1); ++} ++ ++static void eth_post_exception_handler(void) ++{ ++ /* decrement the module count when the debugger detaches */ ++ if (!kgdb_connected) ++ module_put(THIS_MODULE); ++ netpoll_set_trap(0); ++} ++ ++static int eth_get_char(void) ++{ ++ int chr; ++ ++ while (atomic_read(&in_count) == 0) ++ netpoll_poll(&np); ++ ++ chr = in_buf[in_tail++]; ++ in_tail &= (IN_BUF_SIZE - 1); ++ atomic_dec(&in_count); ++ return chr; ++} ++ ++static void eth_flush_buf(void) ++{ ++ if (out_count && np.dev) { ++ netpoll_send_udp(&np, out_buf, out_count); ++ memset(out_buf, 0, sizeof(out_buf)); ++ out_count = 0; ++ } ++} ++ ++static void eth_put_char(u8 chr) ++{ ++ out_buf[out_count++] = chr; ++ if (out_count == OUT_BUF_SIZE) ++ eth_flush_buf(); ++} ++ ++static int option_setup(char *opt) ++{ ++ char opt_scratch[MAX_CONFIG_LEN]; ++ ++ configured = 0; ++ /* If we're being given a new configuration, copy it in. */ ++ if (opt != config) ++ strcpy(config, opt); ++ ++ if (opt[0] == '\0') ++ return 1; ++ ++ /* But work on a copy as netpoll_parse_options will eat it. */ ++ strcpy(opt_scratch, opt); ++ configured = !netpoll_parse_options(&np, opt_scratch); ++ ++ use_dynamic_mac = 1; ++ ++ return 0; ++} ++__setup("kgdboe=", option_setup); ++ ++/* With our config string set by some means, configure kgdboe. */ ++static int configure_kgdboe(void) ++{ ++ if (option_setup(config)) ++ return 0; ++ ++ if (!configured) { ++ printk(KERN_ERR "kgdboe: configuration incorrect - kgdboe not " ++ "loaded.\n"); ++ printk(KERN_ERR " Usage: kgdboe=[src-port]@[src-ip]/[dev]," ++ "[tgt-port]@/\n"); ++ return -EINVAL; ++ } ++ ++ /* Bring it up. */ ++ if (netpoll_setup(&np)) { ++ printk(KERN_ERR "kgdboe: netpoll_setup failed kgdboe failed\n"); ++ return -EINVAL; ++ } ++ ++ if (kgdb_register_io_module(&local_kgdb_io_ops)) { ++ netpoll_cleanup(&np); ++ return -EINVAL; ++ } ++ ++ configured = 2; ++ ++ return 0; ++} ++ ++static int init_kgdboe(void) ++{ ++ int ret; ++ ++ /* Already done? */ ++ if (configured == 2) ++ return 0; ++ ++ /* OK, go ahead and do it. */ ++ ret = configure_kgdboe(); ++ ++ if (configured == 2) ++ printk(KERN_INFO "kgdboe: debugging over ethernet enabled\n"); ++ ++ return ret; ++} ++ ++static void cleanup_kgdboe(void) ++{ ++ netpoll_cleanup(&np); ++ configured = 0; ++ kgdb_unregister_io_module(&local_kgdb_io_ops); ++} ++ ++static int param_set_kgdboe_var(const char *kmessage, struct kernel_param *kp) ++{ ++ char kmessage_save[MAX_CONFIG_LEN]; ++ int len = strlen(kmessage); ++ ++ if (len >= MAX_CONFIG_LEN) { ++ printk(KERN_ERR "kgdboc: config string too long\n"); ++ return -ENOSPC; ++ } ++ ++ if (kgdb_connected) { ++ printk(KERN_ERR "kgdboe: Cannot reconfigure while KGDB is " ++ "connected.\n"); ++ return 0; ++ } ++ ++ /* Start the reconfiguration process by saving the old string */ ++ strncpy(kmessage_save, config, sizeof(kmessage_save)); ++ ++ ++ /* Copy in the new param and strip out invalid characters so we ++ * can optionally specify the MAC. ++ */ ++ strcpy(config, kmessage); ++ /* Chop out \n char as a result of echo */ ++ if (config[len - 1] == '\n') ++ config[len - 1] = '\0'; ++ ++ len--; ++ while (len > 0 && (config[len] < ',' || config[len] > 'f')) { ++ config[len] = '\0'; ++ len--; ++ } ++ ++ if (configured == 2) { ++ cleanup_kgdboe(); ++ configured = 0; ++ } ++ if (config[0] == '\0') ++ return 0; ++ ++ configure_kgdboe(); ++ ++ if (configured != 2) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static struct kgdb_io local_kgdb_io_ops = { ++ .name = "kgdboe", ++ .read_char = eth_get_char, ++ .write_char = eth_put_char, ++ .flush = eth_flush_buf, ++ .pre_exception = eth_pre_exception_handler, ++ .post_exception = eth_post_exception_handler ++}; ++ ++module_init(init_kgdboe); ++module_exit(cleanup_kgdboe); ++module_param_call(kgdboe, param_set_kgdboe_var, param_get_string, &kps, 0644); ++MODULE_PARM_DESC(kgdboe, "[src-port]@[src-ip]/[dev]," ++ "[tgt-port]@/"); +diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h +index 9757b1a..ff8b7c0 100644 +--- a/include/linux/kgdb.h ++++ b/include/linux/kgdb.h +@@ -277,5 +277,6 @@ extern int kgdb_nmicallback(int cpu, void *regs); + + extern int kgdb_single_step; + extern atomic_t kgdb_active; ++extern void kgdb_schedule_breakpoint(void); + + #endif /* _KGDB_H_ */ +diff --git a/kernel/kgdb.c b/kernel/kgdb.c +index 476bb3b..8b75360 100644 +--- a/kernel/kgdb.c ++++ b/kernel/kgdb.c +@@ -120,6 +120,7 @@ atomic_t kgdb_active = ATOMIC_INIT(-1); + */ + static atomic_t passive_cpu_wait[NR_CPUS]; + static atomic_t cpu_in_kgdb[NR_CPUS]; ++static atomic_t kgdb_break_tasklet_var; + atomic_t kgdb_setting_breakpoint; + + struct task_struct *kgdb_usethread; +@@ -1643,6 +1644,31 @@ static void kgdb_unregister_callbacks(void) + } + } + ++/* ++ * There are times a tasklet needs to be used vs a compiled in in ++ * break point so as to cause an exception outside a kgdb I/O module, ++ * such as is the case with kgdboe, where calling a breakpoint in the ++ * I/O driver itself would be fatal. ++ */ ++static void kgdb_tasklet_bpt(unsigned long ing) ++{ ++ kgdb_breakpoint(); ++ atomic_set(&kgdb_break_tasklet_var, 0); ++} ++ ++DECLARE_TASKLET(kgdb_tasklet_breakpoint, kgdb_tasklet_bpt, 0); ++ ++void kgdb_schedule_breakpoint(void) ++{ ++ if (atomic_read(&kgdb_break_tasklet_var) || ++ atomic_read(&kgdb_active) != -1 || ++ atomic_read(&kgdb_setting_breakpoint)) ++ return; ++ atomic_inc(&kgdb_break_tasklet_var); ++ tasklet_schedule(&kgdb_tasklet_breakpoint); ++} ++EXPORT_SYMBOL_GPL(kgdb_schedule_breakpoint); ++ + static void kgdb_initial_breakpoint(void) + { + kgdb_break_asap = 0; +diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb +index bb7c5a5..5589e99 100644 +--- a/lib/Kconfig.kgdb ++++ b/lib/Kconfig.kgdb +@@ -54,6 +54,17 @@ config KGDB_8250 + attached via this driver, the configured serial port cannot be + used by the standard 8250 driver or serial earlyprintk/earlycon. + ++config KGDBOE ++ tristate "KGDB: On ethernet" ++ depends on KGDB ++ select NETPOLL ++ select NETPOLL_TRAP ++ help ++ Uses the NETPOLL API to communicate with the host GDB via UDP. ++ In order for this to work, the ethernet interface specified must ++ support the NETPOLL API, and this must be initialized at boot. ++ See the documentation for syntax. ++ + config KGDB_TESTS + bool "KGDB: internal test suite" + depends on KGDB +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0119-Turn-debian-binary-custom.d-lpia-patchset-0014-pouls.patch +++ linux-2.6.24/patches/0119-Turn-debian-binary-custom.d-lpia-patchset-0014-pouls.patch @@ -0,0 +1,430 @@ +From ed5f27936c72a20ff89d4d82f9df56893ae67467 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:32 +0100 +Subject: [PATCH 119/170] Turn debian/binary-custom.d/lpia/patchset/0014-poulsbo_hda.patch into a commit. + +Signed-off-by: Andy Whitcroft + +commit 974128ae34a0e1907d86aa3f915cf9b6208cda88 +Author: Amit Kucheria +Date: Thu Mar 6 04:39:22 2008 +0200 + + UBUNTU: Poulsbo: Sync patches with moblin/ume-hardy tree + + Signed-off-by: Amit Kucheria + +commit 4883c50b37f2e791e29f545766e53ac456576926 +Author: Amit Kucheria +Date: Fri Jan 11 13:59:04 2008 +0200 + + UBUNTU: Poulsbo: Mass update of patches to be identical to those on moblin + + Sigh, we need better communication... + + Signed-off-by: Amit Kucheria +--- + .../lpia/patchset/0014-poulsbo_hda.patch | 196 -------------------- + sound/pci/hda/hda_intel.c | 117 +++++++++++-- + 2 files changed, 105 insertions(+), 208 deletions(-) + delete mode 100644 debian/binary-custom.d/lpia/patchset/0014-poulsbo_hda.patch + +diff --git a/debian/binary-custom.d/lpia/patchset/0014-poulsbo_hda.patch b/debian/binary-custom.d/lpia/patchset/0014-poulsbo_hda.patch +deleted file mode 100644 +index 13f9fd8..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0014-poulsbo_hda.patch ++++ /dev/null +@@ -1,196 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c +-index 3fa0f97..0b0c0bc 100644 +---- a/sound/pci/hda/hda_intel.c +-+++ b/sound/pci/hda/hda_intel.c +-@@ -75,6 +75,12 @@ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " +- module_param(enable_msi, int, 0); +- MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); +- +-+/* For workaround Poulsbo SI bugs, it affects stream descriptor offset and +-+ * corresponding control bits +-+ */ +-+static int sd_offset_fixup= 0; +-+static int sd_bit_fixup=0; +-+ +- #ifdef CONFIG_SND_HDA_POWER_SAVE +- /* power_save option is defined in hda_codec.c */ +- +-@@ -269,6 +275,10 @@ enum { +- #define NVIDIA_HDA_TRANSREG_ADDR 0x4e +- #define NVIDIA_HDA_ENABLE_COHBITS 0x0f +- +-+/* Defines for Intel SCH HDA snoop control */ +-+#define INTEL_SCH_HDA_DEVC 0x78 +-+#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) +-+ +- /* +- */ +- +-@@ -788,8 +798,20 @@ static void azx_int_clear(struct azx *chip) +- static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) +- { +- /* enable SIE */ +-- azx_writeb(chip, INTCTL, +-- azx_readb(chip, INTCTL) | (1 << azx_dev->index)); +-+ if (!sd_bit_fixup) { +-+ azx_writeb(chip, INTCTL, +-+ azx_readb(chip, INTCTL) | (1 << azx_dev->index)); +-+ } +-+ else { +-+ if (azx_dev->index < sd_bit_fixup) { +-+ azx_writel(chip, INTCTL, +-+ azx_readl(chip, INTCTL) | (1 << azx_dev->index)); +-+ } else { +-+ azx_writel(chip, INTCTL, +-+ azx_readl(chip, INTCTL) | (1 << (azx_dev->index+sd_bit_fixup))); +-+ } +-+ } +-+ +- /* set DMA start and interrupt mask */ +- azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | +- SD_CTL_DMA_START | SD_INT_MASK); +-@@ -803,8 +825,18 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) +- ~(SD_CTL_DMA_START | SD_INT_MASK)); +- azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ +- /* disable SIE */ +-- azx_writeb(chip, INTCTL, +-- azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); +-+ if (!sd_bit_fixup) { +-+ azx_writeb(chip, INTCTL, +-+ azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); +-+ } else { +-+ if (azx_dev->index < sd_bit_fixup ) { +-+ azx_writeb(chip, INTCTL, +-+ azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); +-+ } else { +-+ azx_writeb(chip, INTCTL, +-+ azx_readb(chip, INTCTL) & ~(1 << (azx_dev->index+sd_bit_fixup))); +-+ } +-+ } +- } +- +- +-@@ -851,6 +883,7 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg, +- +- static void azx_init_pci(struct azx *chip) +- { +-+ unsigned short reg16; +- /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) +- * TCSEL == Traffic Class Select Register, which sets PCI express QOS +- * Ensuring these bits are 0 clears playback static on some HD Audio +-@@ -871,6 +904,19 @@ static void azx_init_pci(struct azx *chip) +- NVIDIA_HDA_TRANSREG_ADDR, +- 0x0f, NVIDIA_HDA_ENABLE_COHBITS); +- break; +-+ case AZX_DRIVER_ICH: +-+ /* For SCH (Poulsbo), enable snoop */ +-+ if (chip->pci->device == PCI_DEVICE_ID_INTEL_POULSBO_HDA) { +-+ pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, ®16); +-+ if (reg16 & INTEL_SCH_HDA_DEVC_NOSNOOP) { +-+ pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, \ +-+ reg16 & (~INTEL_SCH_HDA_DEVC_NOSNOOP)); +-+ pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, ®16); +-+ snd_printk(KERN_INFO "HDA snoop disabled, try to enable ... %s\n", \ +-+ (reg16 & INTEL_SCH_HDA_DEVC_NOSNOOP)?"Failed":"OK"); +-+ } +-+ } +-+ break; +- } +- } +- +-@@ -1467,11 +1513,24 @@ static int __devinit azx_init_stream(struct azx *chip) +- struct azx_dev *azx_dev = &chip->azx_dev[i]; +- azx_dev->bdl = (u32 *)(chip->bdl.area + off); +- azx_dev->bdl_addr = chip->bdl.addr + off; +-- azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); +- /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ +-- azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); +-- /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ +-- azx_dev->sd_int_sta_mask = 1 << i; +-+ if (!sd_bit_fixup) { +-+ azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); +-+ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); +-+ /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ +-+ azx_dev->sd_int_sta_mask = 1 << i; +-+ } else { +-+ if (iposbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); +-+ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); +-+ azx_dev->sd_int_sta_mask = 1 << i; +-+ } else { +-+ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80 + sd_offset_fixup); +-+ azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + (2+i) * 8); +-+ azx_dev->sd_int_sta_mask = 1 << (i+sd_bit_fixup); +-+ } +-+ } +-+ +- /* stream tag: must be non-zero and unique */ +- azx_dev->index = i; +- azx_dev->stream_tag = i + 1; +-@@ -1702,9 +1761,11 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, +- { +- struct azx *chip; +- int err; +-+ unsigned short stepping; +- static struct snd_device_ops ops = { +- .dev_free = azx_dev_free, +- }; +-+ unsigned short gcap; +- +- *rchip = NULL; +- +-@@ -1783,10 +1844,41 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, +- chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX; +- break; +- default: +-- chip->playback_streams = ICH6_NUM_PLAYBACK; +-- chip->capture_streams = ICH6_NUM_CAPTURE; +-- chip->playback_index_offset = ICH6_PLAYBACK_INDEX; +-- chip->capture_index_offset = ICH6_CAPTURE_INDEX; +-+ /* read number of streams from GCAP regiser instead of using +-+ * hardcoded value +-+ */ +-+ gcap = azx_readw(chip, GCAP); +-+ if (!gcap) { +-+ snd_printk(KERN_ERR "Device has no streams \n"); +-+ goto errout; +-+ }; +-+ chip->playback_streams = (gcap&(0xF<<12))>>12; +-+ chip->capture_streams = (gcap&(0xF<<8))>>8; +-+ chip->playback_index_offset = (gcap&(0xF<<12))>>12; +-+ chip->capture_index_offset = 0; +-+ /* do fixup for poulsbo */ +-+ if (pci->device == PCI_DEVICE_ID_INTEL_POULSBO_HDA) { +-+ snd_printk(KERN_INFO "Do fixup for Poulsbo "); +-+ pci_bus_read_config_word(pci->bus, 0, 0x8, &stepping); +-+ switch (stepping) { +-+ case 0: +-+ /* A2 has wrong OSD0 offset and control bits */ +-+ snd_printk(KERN_INFO "A2 stepping\n"); +-+ sd_offset_fixup = 0x40; +-+ sd_bit_fixup = 0x2; +-+ break; +-+ case 2: +-+ case 3: +-+ case 4: +-+ /* B0/1 and C0 moved OSD0 offset but not control bits */ +-+ snd_printk(KERN_INFO "B0/1 or C0 stepping\n"); +-+ sd_bit_fixup = 0x2; +-+ break; +-+ default: +-+ snd_printk(KERN_INFO "D0 or newer stepping\n"); +-+ break; +-+ } +-+ } +- break; +- } +- chip->num_streams = chip->playback_streams + chip->capture_streams; +-@@ -1936,6 +2028,7 @@ static struct pci_device_id azx_ids[] = { +- { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */ +- { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ +- { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ +-+ { 0x8086, 0x811b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* POULSBO */ +- { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ +- { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ +- { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */ +diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c +index 62b9fb3..58c8ea5 100644 +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -75,6 +75,12 @@ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " + module_param(enable_msi, int, 0); + MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); + ++/* For workaround Poulsbo SI bugs, it affects stream descriptor offset and ++ * corresponding control bits ++ */ ++static int sd_offset_fixup= 0; ++static int sd_bit_fixup=0; ++ + #ifdef CONFIG_SND_HDA_POWER_SAVE + /* power_save option is defined in hda_codec.c */ + +@@ -269,6 +275,10 @@ enum { + #define NVIDIA_HDA_TRANSREG_ADDR 0x4e + #define NVIDIA_HDA_ENABLE_COHBITS 0x0f + ++/* Defines for Intel SCH HDA snoop control */ ++#define INTEL_SCH_HDA_DEVC 0x78 ++#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) ++ + /* + */ + +@@ -789,8 +799,20 @@ static void azx_int_clear(struct azx *chip) + static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) + { + /* enable SIE */ +- azx_writeb(chip, INTCTL, +- azx_readb(chip, INTCTL) | (1 << azx_dev->index)); ++ if (!sd_bit_fixup) { ++ azx_writeb(chip, INTCTL, ++ azx_readb(chip, INTCTL) | (1 << azx_dev->index)); ++ } ++ else { ++ if (azx_dev->index < sd_bit_fixup) { ++ azx_writel(chip, INTCTL, ++ azx_readl(chip, INTCTL) | (1 << azx_dev->index)); ++ } else { ++ azx_writel(chip, INTCTL, ++ azx_readl(chip, INTCTL) | (1 << (azx_dev->index+sd_bit_fixup))); ++ } ++ } ++ + /* set DMA start and interrupt mask */ + azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | + SD_CTL_DMA_START | SD_INT_MASK); +@@ -804,8 +826,18 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) + ~(SD_CTL_DMA_START | SD_INT_MASK)); + azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ + /* disable SIE */ +- azx_writeb(chip, INTCTL, +- azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); ++ if (!sd_bit_fixup) { ++ azx_writeb(chip, INTCTL, ++ azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); ++ } else { ++ if (azx_dev->index < sd_bit_fixup ) { ++ azx_writeb(chip, INTCTL, ++ azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); ++ } else { ++ azx_writeb(chip, INTCTL, ++ azx_readb(chip, INTCTL) & ~(1 << (azx_dev->index+sd_bit_fixup))); ++ } ++ } + } + + +@@ -852,6 +884,7 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg, + + static void azx_init_pci(struct azx *chip) + { ++ unsigned short reg16; + /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) + * TCSEL == Traffic Class Select Register, which sets PCI express QOS + * Ensuring these bits are 0 clears playback static on some HD Audio +@@ -872,6 +905,19 @@ static void azx_init_pci(struct azx *chip) + NVIDIA_HDA_TRANSREG_ADDR, + 0x0f, NVIDIA_HDA_ENABLE_COHBITS); + break; ++ case AZX_DRIVER_ICH: ++ /* For SCH (Poulsbo), enable snoop */ ++ if (chip->pci->device == PCI_DEVICE_ID_INTEL_POULSBO_HDA) { ++ pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, ®16); ++ if (reg16 & INTEL_SCH_HDA_DEVC_NOSNOOP) { ++ pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, \ ++ reg16 & (~INTEL_SCH_HDA_DEVC_NOSNOOP)); ++ pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, ®16); ++ snd_printk(KERN_INFO "HDA snoop disabled, try to enable ... %s\n", \ ++ (reg16 & INTEL_SCH_HDA_DEVC_NOSNOOP)?"Failed":"OK"); ++ } ++ } ++ break; + } + } + +@@ -1468,11 +1514,24 @@ static int __devinit azx_init_stream(struct azx *chip) + struct azx_dev *azx_dev = &chip->azx_dev[i]; + azx_dev->bdl = (u32 *)(chip->bdl.area + off); + azx_dev->bdl_addr = chip->bdl.addr + off; +- azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); + /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ +- azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); +- /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ +- azx_dev->sd_int_sta_mask = 1 << i; ++ if (!sd_bit_fixup) { ++ azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); ++ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); ++ /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ ++ azx_dev->sd_int_sta_mask = 1 << i; ++ } else { ++ if (iposbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); ++ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); ++ azx_dev->sd_int_sta_mask = 1 << i; ++ } else { ++ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80 + sd_offset_fixup); ++ azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + (2+i) * 8); ++ azx_dev->sd_int_sta_mask = 1 << (i+sd_bit_fixup); ++ } ++ } ++ + /* stream tag: must be non-zero and unique */ + azx_dev->index = i; + azx_dev->stream_tag = i + 1; +@@ -1703,9 +1762,11 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, + { + struct azx *chip; + int err; ++ unsigned short stepping; + static struct snd_device_ops ops = { + .dev_free = azx_dev_free, + }; ++ unsigned short gcap; + + *rchip = NULL; + +@@ -1784,10 +1845,41 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, + chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX; + break; + default: +- chip->playback_streams = ICH6_NUM_PLAYBACK; +- chip->capture_streams = ICH6_NUM_CAPTURE; +- chip->playback_index_offset = ICH6_PLAYBACK_INDEX; +- chip->capture_index_offset = ICH6_CAPTURE_INDEX; ++ /* read number of streams from GCAP regiser instead of using ++ * hardcoded value ++ */ ++ gcap = azx_readw(chip, GCAP); ++ if (!gcap) { ++ snd_printk(KERN_ERR "Device has no streams \n"); ++ goto errout; ++ }; ++ chip->playback_streams = (gcap&(0xF<<12))>>12; ++ chip->capture_streams = (gcap&(0xF<<8))>>8; ++ chip->playback_index_offset = (gcap&(0xF<<12))>>12; ++ chip->capture_index_offset = 0; ++ /* do fixup for poulsbo */ ++ if (pci->device == PCI_DEVICE_ID_INTEL_POULSBO_HDA) { ++ snd_printk(KERN_INFO "Do fixup for Poulsbo "); ++ pci_bus_read_config_word(pci->bus, 0, 0x8, &stepping); ++ switch (stepping) { ++ case 0: ++ /* A2 has wrong OSD0 offset and control bits */ ++ snd_printk(KERN_INFO "A2 stepping\n"); ++ sd_offset_fixup = 0x40; ++ sd_bit_fixup = 0x2; ++ break; ++ case 2: ++ case 3: ++ case 4: ++ /* B0/1 and C0 moved OSD0 offset but not control bits */ ++ snd_printk(KERN_INFO "B0/1 or C0 stepping\n"); ++ sd_bit_fixup = 0x2; ++ break; ++ default: ++ snd_printk(KERN_INFO "D0 or newer stepping\n"); ++ break; ++ } ++ } + break; + } + chip->num_streams = chip->playback_streams + chip->capture_streams; +@@ -1937,6 +2029,7 @@ static struct pci_device_id azx_ids[] = { + { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */ + { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ + { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ ++ { 0x8086, 0x811b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* POULSBO */ + { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ + { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ + { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0031-kgdb-mips-This-adds-basic-support-to-the-MIPS-archit.patch +++ linux-2.6.24/patches/0031-kgdb-mips-This-adds-basic-support-to-the-MIPS-archit.patch @@ -0,0 +1,2107 @@ +From 1eeee04b10f9452a367f97dec79210a2cdeb4983 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:47 -0500 +Subject: [PATCH 031/170] kgdb, mips: This adds basic support to the MIPS architecture + +This patch removes the gdb-stub for mips and replaces it with an +architecture specific implementation to work with the kgdb core. This +required the removal of a number of board specific gdb-stub hacks. + +The new kgdb architecture specific handler registers and unregisters +dynamically for exceptions depending on when you configure a kgdb I/O +driver. + +There have been quite a number of contributors during the existence +of this patch (see arch/mips/kernel/kgdb.c). + +Signed-off-by: Jason Wessel +--- + arch/mips/Kconfig | 9 +- + arch/mips/Kconfig.debug | 22 -- + arch/mips/au1000/Kconfig | 1 - + arch/mips/au1000/common/Makefile | 1 - + arch/mips/basler/excite/Makefile | 1 - + arch/mips/basler/excite/excite_irq.c | 7 - + arch/mips/basler/excite/excite_setup.c | 4 +- + arch/mips/jmr3927/rbhma3100/Makefile | 1 - + arch/mips/kernel/Makefile | 2 +- + arch/mips/kernel/irq.c | 29 +- + arch/mips/kernel/kgdb.c | 298 +++++++++++++++++ + arch/mips/kernel/kgdb_handler.S | 339 ++++++++++++++++++++ + arch/mips/kernel/traps.c | 9 + + arch/mips/mips-boards/atlas/Makefile | 1 - + arch/mips/mips-boards/atlas/atlas_setup.c | 3 - + arch/mips/mips-boards/generic/Makefile | 1 - + arch/mips/mips-boards/generic/init.c | 62 ---- + arch/mips/mips-boards/malta/malta_setup.c | 4 - + arch/mips/pci/fixup-atlas.c | 21 -- + arch/mips/philips/pnx8550/common/Makefile | 1 - + arch/mips/philips/pnx8550/common/setup.c | 11 - + arch/mips/pmc-sierra/yosemite/Makefile | 1 - + arch/mips/pmc-sierra/yosemite/irq.c | 9 - + arch/mips/sgi-ip22/ip22-setup.c | 24 -- + arch/mips/sgi-ip27/Makefile | 1 - + arch/mips/sibyte/bcm1480/irq.c | 80 ----- + arch/mips/sibyte/cfe/setup.c | 14 - + arch/mips/sibyte/sb1250/irq.c | 61 +--- + arch/mips/sibyte/sb1250/kgdb_sibyte.c | 145 +++++++++ + arch/mips/sibyte/swarm/Makefile | 2 - + arch/mips/tx4927/common/Makefile | 1 - + .../toshiba_rbtx4927/toshiba_rbtx4927_setup.c | 12 +- + arch/mips/tx4938/common/Makefile | 1 - + arch/mips/tx4938/toshiba_rbtx4938/setup.c | 10 +- + include/asm-mips/asmmacro-32.h | 43 +++ + include/asm-mips/asmmacro-64.h | 99 ++++++ + include/asm-mips/kdebug.h | 30 ++- + include/asm-mips/kgdb.h | 50 +++ + 38 files changed, 1052 insertions(+), 358 deletions(-) + create mode 100644 arch/mips/kernel/kgdb.c + create mode 100644 arch/mips/kernel/kgdb_handler.S + create mode 100644 arch/mips/sibyte/sb1250/kgdb_sibyte.c + create mode 100644 include/asm-mips/kgdb.h + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index b22c043..f41dbf1 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -4,6 +4,7 @@ config MIPS + # Horrible source of confusion. Die, die, die ... + select EMBEDDED + select RTC_LIB ++ select HAVE_ARCH_KGDB + + mainmenu "Linux/MIPS Kernel Configuration" + +@@ -32,7 +33,6 @@ config BASLER_EXCITE + select SYS_HAS_CPU_RM9000 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN +- select SYS_SUPPORTS_KGDB + help + The eXcite is a smart camera platform manufactured by + Basler Vision Technologies AG. +@@ -332,7 +332,6 @@ config PMC_MSP + select SYS_HAS_CPU_MIPS32_R2 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN +- select SYS_SUPPORTS_KGDB + select IRQ_CPU + select SERIAL_8250 + select SERIAL_8250_CONSOLE +@@ -358,7 +357,6 @@ config PMC_YOSEMITE + select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_HIGHMEM +- select SYS_SUPPORTS_KGDB + select SYS_SUPPORTS_SMP + help + Yosemite is an evaluation board for the RM9000x2 processor +@@ -431,7 +429,6 @@ config SGI_IP27 + select SYS_HAS_CPU_R10000 + select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN +- select SYS_SUPPORTS_KGDB + select SYS_SUPPORTS_NUMA + select SYS_SUPPORTS_SMP + select GENERIC_HARDIRQS_NO__DO_IRQ +@@ -516,7 +513,6 @@ config SIBYTE_SWARM + select SYS_HAS_CPU_SB1 + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_HIGHMEM +- select SYS_SUPPORTS_KGDB + select SYS_SUPPORTS_LITTLE_ENDIAN + select ZONE_DMA32 if 64BIT + +@@ -636,7 +632,6 @@ config TOSHIBA_RBTX4927 + select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_BIG_ENDIAN +- select SYS_SUPPORTS_KGDB + select GENERIC_HARDIRQS_NO__DO_IRQ + help + This Toshiba board is based on the TX4927 processor. Say Y here to +@@ -657,7 +652,6 @@ config TOSHIBA_RBTX4938 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_BIG_ENDIAN +- select SYS_SUPPORTS_KGDB + select GENERIC_HARDIRQS_NO__DO_IRQ + select GENERIC_GPIO + help +@@ -942,7 +936,6 @@ config SOC_PNX8550 + select SYS_HAS_EARLY_PRINTK + select SYS_SUPPORTS_32BIT_KERNEL + select GENERIC_HARDIRQS_NO__DO_IRQ +- select SYS_SUPPORTS_KGDB + select GENERIC_GPIO + + config SWAP_IO_SPACE +diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug +index fd7124c..43d0b8d 100644 +--- a/arch/mips/Kconfig.debug ++++ b/arch/mips/Kconfig.debug +@@ -34,28 +34,6 @@ config SMTC_IDLE_HOOK_DEBUG + arch/mips/kernel/smtc.c. This debugging option result in significant + overhead so should be disabled in production kernels. + +-config KGDB +- bool "Remote GDB kernel debugging" +- depends on DEBUG_KERNEL && SYS_SUPPORTS_KGDB +- select DEBUG_INFO +- help +- If you say Y here, it will be possible to remotely debug the MIPS +- kernel using gdb. This enlarges your kernel image disk size by +- several megabytes and requires a machine with more than 16 MB, +- better 32 MB RAM to avoid excessive linking time. This is only +- useful for kernel hackers. If unsure, say N. +- +-config SYS_SUPPORTS_KGDB +- bool +- +-config GDB_CONSOLE +- bool "Console output to GDB" +- depends on KGDB +- help +- If you are using GDB for remote debugging over a serial port and +- would like kernel messages to be formatted into GDB $O packets so +- that GDB prints them as program output, say 'Y'. +- + config SB1XXX_CORELIS + bool "Corelis Debugger" + depends on SIBYTE_SB1xxx_SOC +diff --git a/arch/mips/au1000/Kconfig b/arch/mips/au1000/Kconfig +index 1fe97cc..e4a057d 100644 +--- a/arch/mips/au1000/Kconfig ++++ b/arch/mips/au1000/Kconfig +@@ -134,4 +134,3 @@ config SOC_AU1X00 + select SYS_HAS_CPU_MIPS32_R1 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_APM_EMULATION +- select SYS_SUPPORTS_KGDB +diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile +index 90e2d7a..9d3e557 100644 +--- a/arch/mips/au1000/common/Makefile ++++ b/arch/mips/au1000/common/Makefile +@@ -10,7 +10,6 @@ obj-y += prom.o irq.o puts.o time.o reset.o \ + au1xxx_irqmap.o clocks.o platform.o power.o setup.o \ + sleeper.o cputable.o dma.o dbdma.o gpio.o + +-obj-$(CONFIG_KGDB) += dbg_io.o + obj-$(CONFIG_PCI) += pci.o + + EXTRA_CFLAGS += -Werror +diff --git a/arch/mips/basler/excite/Makefile b/arch/mips/basler/excite/Makefile +index 519142c..cff29cf 100644 +--- a/arch/mips/basler/excite/Makefile ++++ b/arch/mips/basler/excite/Makefile +@@ -5,5 +5,4 @@ + obj-$(CONFIG_BASLER_EXCITE) += excite_irq.o excite_prom.o excite_setup.o \ + excite_device.o excite_procfs.o + +-obj-$(CONFIG_KGDB) += excite_dbg_io.o + obj-m += excite_iodev.o +diff --git a/arch/mips/basler/excite/excite_irq.c b/arch/mips/basler/excite/excite_irq.c +index 4903e06..934e0a6 100644 +--- a/arch/mips/basler/excite/excite_irq.c ++++ b/arch/mips/basler/excite/excite_irq.c +@@ -50,10 +50,6 @@ void __init arch_init_irq(void) + mips_cpu_irq_init(); + rm7k_cpu_irq_init(); + rm9k_cpu_irq_init(); +- +-#ifdef CONFIG_KGDB +- excite_kgdb_init(); +-#endif + } + + asmlinkage void plat_irq_dispatch(void) +@@ -90,9 +86,6 @@ asmlinkage void plat_irq_dispatch(void) + msgint = msgintflags & msgintmask & (0x1 << (TITAN_MSGINT % 0x20)); + if ((pending & (1 << TITAN_IRQ)) && msgint) { + ocd_writel(msgint, INTP0Clear0 + (TITAN_MSGINT / 0x20 * 0x10)); +-#if defined(CONFIG_KGDB) +- excite_kgdb_inthdl(); +-#endif + do_IRQ(TITAN_IRQ); + return; + } +diff --git a/arch/mips/basler/excite/excite_setup.c b/arch/mips/basler/excite/excite_setup.c +index 6dd8f0d..d66b3b8 100644 +--- a/arch/mips/basler/excite/excite_setup.c ++++ b/arch/mips/basler/excite/excite_setup.c +@@ -95,13 +95,13 @@ static int __init excite_init_console(void) + /* Take the DUART out of reset */ + titan_writel(0x00ff1cff, CPRR); + +-#if defined(CONFIG_KGDB) || (CONFIG_SERIAL_8250_NR_UARTS > 1) ++#if (CONFIG_SERIAL_8250_NR_UARTS > 1) + /* Enable both ports */ + titan_writel(MASK_SER0 | MASK_SER1, UACFG); + #else + /* Enable port #0 only */ + titan_writel(MASK_SER0, UACFG); +-#endif /* defined(CONFIG_KGDB) */ ++#endif + + /* + * Set up serial port #0. Do not use autodetection; the result is +diff --git a/arch/mips/jmr3927/rbhma3100/Makefile b/arch/mips/jmr3927/rbhma3100/Makefile +index d86e30d..06316f6 100644 +--- a/arch/mips/jmr3927/rbhma3100/Makefile ++++ b/arch/mips/jmr3927/rbhma3100/Makefile +@@ -3,6 +3,5 @@ + # + + obj-y += init.o irq.o setup.o +-obj-$(CONFIG_KGDB) += kgdb_io.o + + EXTRA_CFLAGS += -Werror +diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile +index ffa0836..d3e9e29 100644 +--- a/arch/mips/kernel/Makefile ++++ b/arch/mips/kernel/Makefile +@@ -70,7 +70,7 @@ obj-$(CONFIG_MIPS32_COMPAT) += linux32.o ptrace32.o signal32.o + obj-$(CONFIG_MIPS32_N32) += binfmt_elfn32.o scall64-n32.o signal_n32.o + obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o + +-obj-$(CONFIG_KGDB) += gdb-low.o gdb-stub.o ++obj-$(CONFIG_KGDB) += kgdb_handler.o kgdb.o + obj-$(CONFIG_PROC_FS) += proc.o + + obj-$(CONFIG_64BIT) += cpu-bugs64.o +diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c +index e3309ff..0466497 100644 +--- a/arch/mips/kernel/irq.c ++++ b/arch/mips/kernel/irq.c +@@ -21,11 +21,15 @@ + #include + #include + #include ++#include + + #include + #include + #include + ++/* Keep track of if we've done certain initialization already or not. */ ++int kgdb_early_setup; ++ + static unsigned long irq_map[NR_IRQS / BITS_PER_LONG]; + + int allocate_irqno(void) +@@ -130,33 +134,22 @@ asmlinkage void spurious_interrupt(void) + atomic_inc(&irq_err_count); + } + +-#ifdef CONFIG_KGDB +-extern void breakpoint(void); +-extern void set_debug_traps(void); +- +-static int kgdb_flag = 1; +-static int __init nokgdb(char *str) +-{ +- kgdb_flag = 0; +- return 1; +-} +-__setup("nokgdb", nokgdb); +-#endif +- + void __init init_IRQ(void) + { + int i; + ++#ifdef CONFIG_KGDB ++ if (kgdb_early_setup) ++ return; ++#endif ++ + for (i = 0; i < NR_IRQS; i++) + set_irq_noprobe(i); + + arch_init_irq(); + + #ifdef CONFIG_KGDB +- if (kgdb_flag) { +- printk("Wait for gdb client connection ...\n"); +- set_debug_traps(); +- breakpoint(); +- } ++ if (kgdb_early_setup == 0) ++ kgdb_early_setup = 1; + #endif + } +diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c +new file mode 100644 +index 0000000..c7154bb +--- /dev/null ++++ b/arch/mips/kernel/kgdb.c +@@ -0,0 +1,298 @@ ++/* ++ * arch/mips/kernel/kgdb.c ++ * ++ * Originally written by Glenn Engel, Lake Stevens Instrument Division ++ * ++ * Contributed by HP Systems ++ * ++ * Modified for SPARC by Stu Grossman, Cygnus Support. ++ * ++ * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse ++ * Send complaints, suggestions etc. to ++ * ++ * Copyright (C) 1995 Andreas Busse ++ * ++ * Copyright (C) 2003 MontaVista Software Inc. ++ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net ++ * ++ * Copyright (C) 2004-2005 MontaVista Software Inc. ++ * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com ++ * ++ * Copyright (C) 2007-2008 Wind River Systems, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* for linux pt_regs struct */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct hard_trap_info { ++ unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */ ++ unsigned char signo; /* Signal that we map this trap into */ ++} hard_trap_info[] = { ++ { 6, SIGBUS }, /* instruction bus error */ ++ { 7, SIGBUS }, /* data bus error */ ++ { 9, SIGTRAP }, /* break */ ++/* { 11, SIGILL }, */ /* CPU unusable */ ++ { 12, SIGFPE }, /* overflow */ ++ { 13, SIGTRAP }, /* trap */ ++ { 14, SIGSEGV }, /* virtual instruction cache coherency */ ++ { 15, SIGFPE }, /* floating point exception */ ++ { 23, SIGSEGV }, /* watch */ ++ { 31, SIGSEGV }, /* virtual data cache coherency */ ++ { 0, 0} /* Must be last */ ++}; ++ ++/* Save the normal trap handlers for user-mode traps. */ ++void *saved_vectors[32]; ++ ++extern void trap_low(void); ++extern void breakinst(void); ++extern void init_IRQ(void); ++ ++void kgdb_call_nmi_hook(void *ignored) ++{ ++ kgdb_nmicallback(raw_smp_processor_id(), (void *)0); ++} ++ ++void kgdb_roundup_cpus(unsigned long flags) ++{ ++ local_irq_enable(); ++ smp_call_function(kgdb_call_nmi_hook, 0, 0, 0); ++ local_irq_disable(); ++} ++ ++static int compute_signal(int tt) ++{ ++ struct hard_trap_info *ht; ++ ++ for (ht = hard_trap_info; ht->tt && ht->signo; ht++) ++ if (ht->tt == tt) ++ return ht->signo; ++ ++ return SIGHUP; /* default for things we don't know about */ ++} ++ ++/* ++ * Set up exception handlers for tracing and breakpoints ++ */ ++void handle_exception(struct pt_regs *regs) ++{ ++ int trap = (regs->cp0_cause & 0x7c) >> 2; ++ ++ if (fixup_exception(regs)) ++ return; ++ ++ if (atomic_read(&kgdb_active) != -1) ++ kgdb_nmicallback(smp_processor_id(), regs); ++ ++ if (atomic_read(&kgdb_setting_breakpoint)) ++ if ((trap == 9) && (regs->cp0_epc == (unsigned long)breakinst)) ++ regs->cp0_epc += 4; ++ ++ kgdb_handle_exception(0, compute_signal(trap), 0, regs); ++ ++ /* In SMP mode, __flush_cache_all does IPI */ ++ local_irq_enable(); ++ __flush_cache_all(); ++} ++ ++void set_debug_traps(void) ++{ ++ struct hard_trap_info *ht; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ for (ht = hard_trap_info; ht->tt && ht->signo; ht++) ++ saved_vectors[ht->tt] = set_except_vector(ht->tt, trap_low); ++ ++ local_irq_restore(flags); ++} ++ ++void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) ++{ ++ int reg; ++#if (KGDB_GDB_REG_SIZE == 32) ++ u32 *ptr = (u32 *)gdb_regs; ++#else ++ u64 *ptr = (u64 *)gdb_regs; ++#endif ++ ++ for (reg = 0; reg < 32; reg++) ++ *(ptr++) = regs->regs[reg]; ++ ++ *(ptr++) = regs->cp0_status; ++ *(ptr++) = regs->lo; ++ *(ptr++) = regs->hi; ++ *(ptr++) = regs->cp0_badvaddr; ++ *(ptr++) = regs->cp0_cause; ++ *(ptr++) = regs->cp0_epc; ++ ++ return; ++} ++ ++void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) ++{ ++ ++ int reg; ++#if (KGDB_GDB_REG_SIZE == 32) ++ const u32 *ptr = (u32 *)gdb_regs; ++#else ++ const u64 *ptr = (u64 *)gdb_regs; ++#endif ++ ++ for (reg = 0; reg < 32; reg++) ++ regs->regs[reg] = *(ptr++); ++ ++ regs->cp0_status = *(ptr++); ++ regs->lo = *(ptr++); ++ regs->hi = *(ptr++); ++ regs->cp0_badvaddr = *(ptr++); ++ regs->cp0_cause = *(ptr++); ++ regs->cp0_epc = *(ptr++); ++ ++ return; ++} ++ ++/* ++ * Similar to regs_to_gdb_regs() except that process is sleeping and so ++ * we may not be able to get all the info. ++ */ ++void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) ++{ ++ int reg; ++ struct thread_info *ti = task_thread_info(p); ++ unsigned long ksp = (unsigned long)ti + THREAD_SIZE - 32; ++ struct pt_regs *regs = (struct pt_regs *)ksp - 1; ++#if (KGDB_GDB_REG_SIZE == 32) ++ u32 *ptr = (u32 *)gdb_regs; ++#else ++ u64 *ptr = (u64 *)gdb_regs; ++#endif ++ ++ for (reg = 0; reg < 16; reg++) ++ *(ptr++) = regs->regs[reg]; ++ ++ /* S0 - S7 */ ++ for (reg = 16; reg < 24; reg++) ++ *(ptr++) = regs->regs[reg]; ++ ++ for (reg = 24; reg < 28; reg++) ++ *(ptr++) = 0; ++ ++ /* GP, SP, FP, RA */ ++ for (reg = 28; reg < 32; reg++) ++ *(ptr++) = regs->regs[reg]; ++ ++ *(ptr++) = regs->cp0_status; ++ *(ptr++) = regs->lo; ++ *(ptr++) = regs->hi; ++ *(ptr++) = regs->cp0_badvaddr; ++ *(ptr++) = regs->cp0_cause; ++ *(ptr++) = regs->cp0_epc; ++ ++ return; ++} ++ ++/* ++ * Calls linux_debug_hook before the kernel dies. If KGDB is enabled, ++ * then try to fall into the debugger ++ */ ++static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd, ++ void *ptr) ++{ ++ struct die_args *args = (struct die_args *)ptr; ++ struct pt_regs *regs = args->regs; ++ int trap = (regs->cp0_cause & 0x7c) >> 2; ++ ++ /* See if KGDB is interested. */ ++ if (user_mode(regs)) ++ /* Userpace events, ignore. */ ++ return NOTIFY_DONE; ++ ++ kgdb_handle_exception(trap, compute_signal(trap), 0, regs); ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block kgdb_notifier = { ++ .notifier_call = kgdb_mips_notify, ++}; ++ ++/* ++ * Handle the 's' and 'c' commands ++ */ ++int kgdb_arch_handle_exception(int vector, int signo, int err_code, ++ char *remcom_in_buffer, char *remcom_out_buffer, ++ struct pt_regs *regs) ++{ ++ char *ptr; ++ unsigned long address; ++ int cpu = smp_processor_id(); ++ ++ switch (remcom_in_buffer[0]) { ++ case 's': ++ case 'c': ++ /* handle the optional parameter */ ++ ptr = &remcom_in_buffer[1]; ++ if (kgdb_hex2long(&ptr, &address)) ++ regs->cp0_epc = address; ++ ++ atomic_set(&kgdb_cpu_doing_single_step, -1); ++ if (remcom_in_buffer[0] == 's') ++ if (kgdb_contthread) ++ atomic_set(&kgdb_cpu_doing_single_step, cpu); ++ ++ return 0; ++ } ++ ++ return -1; ++} ++ ++struct kgdb_arch arch_kgdb_ops = { ++#ifdef CONFIG_CPU_LITTLE_ENDIAN ++ .gdb_bpt_instr = {0xd}, ++#else /* ! CONFIG_CPU_LITTLE_ENDIAN */ ++ .gdb_bpt_instr = {0x00, 0x00, 0x00, 0x0d}, ++#endif ++}; ++ ++/* ++ * We use kgdb_early_setup so that functions we need to call now don't ++ * cause trouble when called again later. ++ */ ++int kgdb_arch_init(void) ++{ ++ /* Set our traps. */ ++ /* This needs to be done more finely grained again, paired in ++ * a before/after in kgdb_handle_exception(...) -- Tom */ ++ set_debug_traps(); ++ register_die_notifier(&kgdb_notifier); ++ ++ return 0; ++} ++ ++/** ++ * kgdb_arch_exit - Perform any architecture specific uninitalization. ++ * ++ * This function will handle the uninitalization of any architecture ++ * specific callbacks, for dynamic registration and unregistration. ++ */ ++void kgdb_arch_exit(void) ++{ ++ unregister_die_notifier(&kgdb_notifier); ++} +diff --git a/arch/mips/kernel/kgdb_handler.S b/arch/mips/kernel/kgdb_handler.S +new file mode 100644 +index 0000000..4aefb44 +--- /dev/null ++++ b/arch/mips/kernel/kgdb_handler.S +@@ -0,0 +1,339 @@ ++/* ++ * arch/mips/kernel/kgdb_handler.S ++ * ++ * Copyright (C) 2007 Wind River Systems, Inc ++ * ++ * Copyright (C) 2004-2005 MontaVista Software Inc. ++ * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++/* ++ * Trap Handler for the new KGDB framework. The main KGDB handler is ++ * handle_exception that will be called from here ++ * ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_32BIT ++#define DMFC0 mfc0 ++#define DMTC0 mtc0 ++#define LDC1 lwc1 ++#define SDC1 swc1 ++#endif ++#ifdef CONFIG_64BIT ++#define DMFC0 dmfc0 ++#define DMTC0 dmtc0 ++#define LDC1 ldc1 ++#define SDC1 sdc1 ++#endif ++ ++#include ++ ++/* ++ * [jsun] We reserves about 2x GDB_FR_SIZE in stack. The lower (addressed) ++ * part is used to store registers and passed to exception handler. ++ * The upper part is reserved for "call func" feature where gdb client ++ * saves some of the regs, setups call frame and passes args. ++ * ++ * A trace shows about 200 bytes are used to store about half of all regs. ++ * The rest should be big enough for frame setup and passing args. ++ */ ++ ++/* ++ * The low level trap handler ++ */ ++ .align 5 ++ NESTED(trap_low, GDB_FR_SIZE, sp) ++ .set noat ++ .set noreorder ++ ++ mfc0 k0, CP0_STATUS ++ sll k0, 3 /* extract cu0 bit */ ++ bltz k0, 1f ++ move k1, sp ++ ++ /* ++ * Called from user mode, go somewhere else. ++ */ ++#if defined(CONFIG_32BIT) ++ lui k1, %hi(saved_vectors) ++ mfc0 k0, CP0_CAUSE ++ andi k0, k0, 0x7c ++ add k1, k1, k0 ++ lw k0, %lo(saved_vectors)(k1) ++#elif defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF32) ++ DMFC0 k0, CP0_CAUSE ++ lui k1, %highest(saved_vectors) ++ andi k0, k0, 0x7c /* mask exception type */ ++ dsll k0, 1 /* turn into byte offset */ ++ daddiu k1, %higher(saved_vectors) ++ dsll k1, k1, 16 ++ daddiu k1, %hi(saved_vectors) ++ dsll k1, k1, 16 ++ daddu k1, k1, k0 ++ LONG_L k0, %lo(saved_vectors)(k1) ++#else ++#error "MIPS configuration is unsupported for kgdb!!" ++#endif ++ jr k0 ++ nop ++1: ++ move k0, sp ++ PTR_SUBU sp, k1, GDB_FR_SIZE*2 # see comment above ++ LONG_S k0, GDB_FR_REG29(sp) ++ LONG_S $2, GDB_FR_REG2(sp) ++ ++/* ++ * First save the CP0 and special registers ++ */ ++ ++ mfc0 v0, CP0_STATUS ++ LONG_S v0, GDB_FR_STATUS(sp) ++ mfc0 v0, CP0_CAUSE ++ LONG_S v0, GDB_FR_CAUSE(sp) ++ DMFC0 v0, CP0_EPC ++ LONG_S v0, GDB_FR_EPC(sp) ++ DMFC0 v0, CP0_BADVADDR ++ LONG_S v0, GDB_FR_BADVADDR(sp) ++ mfhi v0 ++ LONG_S v0, GDB_FR_HI(sp) ++ mflo v0 ++ LONG_S v0, GDB_FR_LO(sp) ++ ++/* ++ * Now the integer registers ++ */ ++ ++ LONG_S zero, GDB_FR_REG0(sp) /* I know... */ ++ LONG_S $1, GDB_FR_REG1(sp) ++ /* v0 already saved */ ++ LONG_S $3, GDB_FR_REG3(sp) ++ LONG_S $4, GDB_FR_REG4(sp) ++ LONG_S $5, GDB_FR_REG5(sp) ++ LONG_S $6, GDB_FR_REG6(sp) ++ LONG_S $7, GDB_FR_REG7(sp) ++ LONG_S $8, GDB_FR_REG8(sp) ++ LONG_S $9, GDB_FR_REG9(sp) ++ LONG_S $10, GDB_FR_REG10(sp) ++ LONG_S $11, GDB_FR_REG11(sp) ++ LONG_S $12, GDB_FR_REG12(sp) ++ LONG_S $13, GDB_FR_REG13(sp) ++ LONG_S $14, GDB_FR_REG14(sp) ++ LONG_S $15, GDB_FR_REG15(sp) ++ LONG_S $16, GDB_FR_REG16(sp) ++ LONG_S $17, GDB_FR_REG17(sp) ++ LONG_S $18, GDB_FR_REG18(sp) ++ LONG_S $19, GDB_FR_REG19(sp) ++ LONG_S $20, GDB_FR_REG20(sp) ++ LONG_S $21, GDB_FR_REG21(sp) ++ LONG_S $22, GDB_FR_REG22(sp) ++ LONG_S $23, GDB_FR_REG23(sp) ++ LONG_S $24, GDB_FR_REG24(sp) ++ LONG_S $25, GDB_FR_REG25(sp) ++ LONG_S $26, GDB_FR_REG26(sp) ++ LONG_S $27, GDB_FR_REG27(sp) ++ LONG_S $28, GDB_FR_REG28(sp) ++ /* sp already saved */ ++ LONG_S $30, GDB_FR_REG30(sp) ++ LONG_S $31, GDB_FR_REG31(sp) ++ ++ CLI /* disable interrupts */ ++ ++/* ++ * Followed by the floating point registers ++ */ ++ mfc0 v0, CP0_STATUS /* FPU enabled? */ ++ srl v0, v0, 16 ++ andi v0, v0, (ST0_CU1 >> 16) ++ ++ beqz v0,3f /* disabled, skip */ ++ nop ++ ++ li t0, 0 ++#ifdef CONFIG_64BIT ++ mfc0 t0, CP0_STATUS ++#endif ++ fpu_save_double_kgdb sp t0 t1 # clobbers t1 ++ ++ ++/* ++ * Current stack frame ptr ++ */ ++ ++3: ++ LONG_S sp, GDB_FR_FRP(sp) ++ ++/* ++ * CP0 registers (R4000/R4400 unused registers skipped) ++ */ ++ ++ mfc0 v0, CP0_INDEX ++ LONG_S v0, GDB_FR_CP0_INDEX(sp) ++ mfc0 v0, CP0_RANDOM ++ LONG_S v0, GDB_FR_CP0_RANDOM(sp) ++ DMFC0 v0, CP0_ENTRYLO0 ++ LONG_S v0, GDB_FR_CP0_ENTRYLO0(sp) ++ DMFC0 v0, CP0_ENTRYLO1 ++ LONG_S v0, GDB_FR_CP0_ENTRYLO1(sp) ++ DMFC0 v0, CP0_CONTEXT ++ LONG_S v0, GDB_FR_CP0_CONTEXT(sp) ++ mfc0 v0, CP0_PAGEMASK ++ LONG_S v0, GDB_FR_CP0_PAGEMASK(sp) ++ mfc0 v0, CP0_WIRED ++ LONG_S v0, GDB_FR_CP0_WIRED(sp) ++ DMFC0 v0, CP0_ENTRYHI ++ LONG_S v0, GDB_FR_CP0_ENTRYHI(sp) ++ mfc0 v0, CP0_PRID ++ LONG_S v0, GDB_FR_CP0_PRID(sp) ++ ++ .set at ++ ++/* ++ * Continue with the higher level handler ++ */ ++ ++ move a0,sp ++ ++ jal handle_exception ++ nop ++ ++/* ++ * Restore all writable registers, in reverse order ++ */ ++ ++ .set noat ++ ++ LONG_L v0, GDB_FR_CP0_ENTRYHI(sp) ++ LONG_L v1, GDB_FR_CP0_WIRED(sp) ++ DMTC0 v0, CP0_ENTRYHI ++ mtc0 v1, CP0_WIRED ++ LONG_L v0, GDB_FR_CP0_PAGEMASK(sp) ++ LONG_L v1, GDB_FR_CP0_ENTRYLO1(sp) ++ mtc0 v0, CP0_PAGEMASK ++ DMTC0 v1, CP0_ENTRYLO1 ++ LONG_L v0, GDB_FR_CP0_ENTRYLO0(sp) ++ LONG_L v1, GDB_FR_CP0_INDEX(sp) ++ DMTC0 v0, CP0_ENTRYLO0 ++ LONG_L v0, GDB_FR_CP0_CONTEXT(sp) ++ mtc0 v1, CP0_INDEX ++ DMTC0 v0, CP0_CONTEXT ++ ++ ++/* ++ * Next, the floating point registers ++ */ ++ mfc0 v0, CP0_STATUS /* check if FPU is enabled */ ++ srl v0, v0, 16 ++ andi v0, v0, (ST0_CU1 >> 16) ++ ++ beqz v0, 3f /* disabled, skip */ ++ nop ++ ++ li t0, 0 ++#ifdef CONFIG_64BIT ++ mfc0 t0, CP0_STATUS ++#endif ++ fpu_restore_double_kgdb sp t0 t1 # clobbers t1 ++ ++ ++/* ++ * Now the CP0 and integer registers ++ */ ++ ++3: ++ mfc0 t0, CP0_STATUS ++ ori t0, 0x1f ++ xori t0, 0x1f ++ mtc0 t0, CP0_STATUS ++ ++ LONG_L v0, GDB_FR_STATUS(sp) ++ LONG_L v1, GDB_FR_EPC(sp) ++ mtc0 v0, CP0_STATUS ++ DMTC0 v1, CP0_EPC ++ LONG_L v0, GDB_FR_HI(sp) ++ LONG_L v1, GDB_FR_LO(sp) ++ mthi v0 ++ mtlo v1 ++ LONG_L $31, GDB_FR_REG31(sp) ++ LONG_L $30, GDB_FR_REG30(sp) ++ LONG_L $28, GDB_FR_REG28(sp) ++ LONG_L $27, GDB_FR_REG27(sp) ++ LONG_L $26, GDB_FR_REG26(sp) ++ LONG_L $25, GDB_FR_REG25(sp) ++ LONG_L $24, GDB_FR_REG24(sp) ++ LONG_L $23, GDB_FR_REG23(sp) ++ LONG_L $22, GDB_FR_REG22(sp) ++ LONG_L $21, GDB_FR_REG21(sp) ++ LONG_L $20, GDB_FR_REG20(sp) ++ LONG_L $19, GDB_FR_REG19(sp) ++ LONG_L $18, GDB_FR_REG18(sp) ++ LONG_L $17, GDB_FR_REG17(sp) ++ LONG_L $16, GDB_FR_REG16(sp) ++ LONG_L $15, GDB_FR_REG15(sp) ++ LONG_L $14, GDB_FR_REG14(sp) ++ LONG_L $13, GDB_FR_REG13(sp) ++ LONG_L $12, GDB_FR_REG12(sp) ++ LONG_L $11, GDB_FR_REG11(sp) ++ LONG_L $10, GDB_FR_REG10(sp) ++ LONG_L $9, GDB_FR_REG9(sp) ++ LONG_L $8, GDB_FR_REG8(sp) ++ LONG_L $7, GDB_FR_REG7(sp) ++ LONG_L $6, GDB_FR_REG6(sp) ++ LONG_L $5, GDB_FR_REG5(sp) ++ LONG_L $4, GDB_FR_REG4(sp) ++ LONG_L $3, GDB_FR_REG3(sp) ++ LONG_L $2, GDB_FR_REG2(sp) ++ LONG_L $1, GDB_FR_REG1(sp) ++#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) ++ LONG_L k0, GDB_FR_EPC(sp) ++ LONG_L $29, GDB_FR_REG29(sp) /* Deallocate stack */ ++ jr k0 ++ rfe ++#else ++ LONG_L sp, GDB_FR_REG29(sp) /* Deallocate stack */ ++ ++ .set mips3 ++ eret ++ .set mips0 ++#endif ++ .set at ++ .set reorder ++ END(trap_low) ++ ++LEAF(kgdb_read_byte) ++4: lb t0, (a0) ++ sb t0, (a1) ++ li v0, 0 ++ jr ra ++ .section __ex_table,"a" ++ PTR 4b, kgdbfault ++ .previous ++ END(kgdb_read_byte) ++ ++LEAF(kgdb_write_byte) ++5: sb a0, (a1) ++ li v0, 0 ++ jr ra ++ .section __ex_table,"a" ++ PTR 5b, kgdbfault ++ .previous ++ END(kgdb_write_byte) ++ ++ .type kgdbfault@function ++ .ent kgdbfault ++ ++kgdbfault: li v0, -EFAULT ++ jr ra ++ .end kgdbfault +diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c +index fcae667..2b7f908 100644 +--- a/arch/mips/kernel/traps.c ++++ b/arch/mips/kernel/traps.c +@@ -10,6 +10,8 @@ + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000, 01 MIPS Technologies, Inc. + * Copyright (C) 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki ++ * ++ * KGDB specific changes - Manish Lachwani (mlachwani@mvista.com) + */ + #include + #include +@@ -22,6 +24,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -1438,6 +1442,11 @@ void __init trap_init(void) + extern char except_vec4; + unsigned long i; + ++#if defined(CONFIG_KGDB) ++ if (kgdb_early_setup) ++ return; /* Already done */ ++#endif ++ + if (cpu_has_veic || cpu_has_vint) + ebase = (unsigned long) alloc_bootmem_low_pages(0x200 + VECTORSPACING*64); + else +diff --git a/arch/mips/mips-boards/atlas/Makefile b/arch/mips/mips-boards/atlas/Makefile +index f71c2dd..b6e743d 100644 +--- a/arch/mips/mips-boards/atlas/Makefile ++++ b/arch/mips/mips-boards/atlas/Makefile +@@ -17,6 +17,5 @@ + # + + obj-y := atlas_int.o atlas_setup.o +-obj-$(CONFIG_KGDB) += atlas_gdb.o + + EXTRA_CFLAGS += -Werror +diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c +index e405d11..5e9c171 100644 +--- a/arch/mips/mips-boards/atlas/atlas_setup.c ++++ b/arch/mips/mips-boards/atlas/atlas_setup.c +@@ -57,9 +57,6 @@ void __init plat_mem_setup(void) + + serial_init(); + +-#ifdef CONFIG_KGDB +- kgdb_config(); +-#endif + mips_reboot_setup(); + } + +diff --git a/arch/mips/mips-boards/generic/Makefile b/arch/mips/mips-boards/generic/Makefile +index b31d8df..2a3ebe7 100644 +--- a/arch/mips/mips-boards/generic/Makefile ++++ b/arch/mips/mips-boards/generic/Makefile +@@ -23,6 +23,5 @@ obj-y := reset.o display.o init.o memory.o \ + + obj-$(CONFIG_EARLY_PRINTK) += console.o + obj-$(CONFIG_PCI) += pci.o +-obj-$(CONFIG_KGDB) += gdb_hook.o + + EXTRA_CFLAGS += -Werror +diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c +index 30f1f54..ed59172 100644 +--- a/arch/mips/mips-boards/generic/init.c ++++ b/arch/mips/mips-boards/generic/init.c +@@ -37,15 +37,6 @@ + + #include + +-#ifdef CONFIG_KGDB +-extern int rs_kgdb_hook(int, int); +-extern int rs_putDebugChar(char); +-extern char rs_getDebugChar(void); +-extern int saa9730_kgdb_hook(int); +-extern int saa9730_putDebugChar(char); +-extern char saa9730_getDebugChar(void); +-#endif +- + int prom_argc; + int *_prom_argv, *_prom_envp; + +@@ -173,59 +164,6 @@ static void __init console_config(void) + } + #endif + +-#ifdef CONFIG_KGDB +-void __init kgdb_config(void) +-{ +- extern int (*generic_putDebugChar)(char); +- extern char (*generic_getDebugChar)(void); +- char *argptr; +- int line, speed; +- +- argptr = prom_getcmdline(); +- if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) { +- argptr += strlen("kgdb=ttyS"); +- if (*argptr != '0' && *argptr != '1') +- printk("KGDB: Unknown serial line /dev/ttyS%c, " +- "falling back to /dev/ttyS1\n", *argptr); +- line = *argptr == '0' ? 0 : 1; +- printk("KGDB: Using serial line /dev/ttyS%d for session\n", line); +- +- speed = 0; +- if (*++argptr == ',') +- { +- int c; +- while ((c = *++argptr) && ('0' <= c && c <= '9')) +- speed = speed * 10 + c - '0'; +- } +-#ifdef CONFIG_MIPS_ATLAS +- if (line == 1) { +- speed = saa9730_kgdb_hook(speed); +- generic_putDebugChar = saa9730_putDebugChar; +- generic_getDebugChar = saa9730_getDebugChar; +- } +- else +-#endif +- { +- speed = rs_kgdb_hook(line, speed); +- generic_putDebugChar = rs_putDebugChar; +- generic_getDebugChar = rs_getDebugChar; +- } +- +- pr_info("KGDB: Using serial line /dev/ttyS%d at %d for " +- "session, please connect your debugger\n", +- line ? 1 : 0, speed); +- +- { +- char *s; +- for (s = "Please connect GDB to this port\r\n"; *s; ) +- generic_putDebugChar(*s++); +- } +- +- /* Breakpoint is invoked after interrupts are initialised */ +- } +-} +-#endif +- + void __init mips_nmi_setup(void) + { + void *base; +diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c +index bc43a5c..7b365f6 100644 +--- a/arch/mips/mips-boards/malta/malta_setup.c ++++ b/arch/mips/mips-boards/malta/malta_setup.c +@@ -38,10 +38,6 @@ + extern void mips_reboot_setup(void); + extern unsigned long mips_rtc_get_time(void); + +-#ifdef CONFIG_KGDB +-extern void kgdb_config(void); +-#endif +- + struct resource standard_io_resources[] = { + { .name = "dma1", .start = 0x00, .end = 0x1f, .flags = IORESOURCE_BUSY }, + { .name = "timer", .start = 0x40, .end = 0x5f, .flags = IORESOURCE_BUSY }, +diff --git a/arch/mips/pci/fixup-atlas.c b/arch/mips/pci/fixup-atlas.c +index 506e883..bfdfd91 100644 +--- a/arch/mips/pci/fixup-atlas.c ++++ b/arch/mips/pci/fixup-atlas.c +@@ -68,24 +68,3 @@ int pcibios_plat_dev_init(struct pci_dev *dev) + { + return 0; + } +- +-#ifdef CONFIG_KGDB +-/* +- * The PCI scan may have moved the saa9730 I/O address, so reread +- * the address here. +- * This does mean that it's not possible to debug the PCI bus configuration +- * code, but it is better than nothing... +- */ +- +-static void atlas_saa9730_base_fixup(struct pci_dev *pdev) +-{ +- extern void *saa9730_base; +- if (pdev->bus == 0 && PCI_SLOT(pdev->devfn) == 19) +- (void) pci_read_config_dword(pdev, 0x14, (u32 *)&saa9730_base); +- printk("saa9730_base = %x\n", saa9730_base); +-} +- +-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730, +- atlas_saa9730_base_fixup); +- +-#endif +diff --git a/arch/mips/philips/pnx8550/common/Makefile b/arch/mips/philips/pnx8550/common/Makefile +index 31cc1a5..dd9e7b1 100644 +--- a/arch/mips/philips/pnx8550/common/Makefile ++++ b/arch/mips/philips/pnx8550/common/Makefile +@@ -24,6 +24,5 @@ + + obj-y := setup.o prom.o int.o reset.o time.o proc.o platform.o + obj-$(CONFIG_PCI) += pci.o +-obj-$(CONFIG_KGDB) += gdb_hook.o + + EXTRA_CFLAGS += -Werror +diff --git a/arch/mips/philips/pnx8550/common/setup.c b/arch/mips/philips/pnx8550/common/setup.c +index 2ce298f..8364007 100644 +--- a/arch/mips/philips/pnx8550/common/setup.c ++++ b/arch/mips/philips/pnx8550/common/setup.c +@@ -142,16 +142,5 @@ void __init plat_mem_setup(void) + ip3106_baud(UART_BASE, pnx8550_console_port) = 5; + } + +-#ifdef CONFIG_KGDB +- argptr = prom_getcmdline(); +- if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) { +- int line; +- argptr += strlen("kgdb=ttyS"); +- line = *argptr == '0' ? 0 : 1; +- rs_kgdb_hook(line); +- pr_info("KGDB: Using ttyS%i for session, " +- "please connect your debugger\n", line ? 1 : 0); +- } +-#endif + return; + } +diff --git a/arch/mips/pmc-sierra/yosemite/Makefile b/arch/mips/pmc-sierra/yosemite/Makefile +index 8fd9a04..b16f95c 100644 +--- a/arch/mips/pmc-sierra/yosemite/Makefile ++++ b/arch/mips/pmc-sierra/yosemite/Makefile +@@ -4,7 +4,6 @@ + + obj-y += irq.o prom.o py-console.o setup.o + +-obj-$(CONFIG_KGDB) += dbg_io.o + obj-$(CONFIG_SMP) += smp.o + + EXTRA_CFLAGS += -Werror +diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c +index 4decc28..5f673eb 100644 +--- a/arch/mips/pmc-sierra/yosemite/irq.c ++++ b/arch/mips/pmc-sierra/yosemite/irq.c +@@ -141,10 +141,6 @@ asmlinkage void plat_irq_dispatch(void) + } + } + +-#ifdef CONFIG_KGDB +-extern void init_second_port(void); +-#endif +- + /* + * Initialize the next level interrupt handler + */ +@@ -156,11 +152,6 @@ void __init arch_init_irq(void) + rm7k_cpu_irq_init(); + rm9k_cpu_irq_init(); + +-#ifdef CONFIG_KGDB +- /* At this point, initialize the second serial port */ +- init_second_port(); +-#endif +- + #ifdef CONFIG_GDB_CONSOLE + register_gdb_console(); + #endif +diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c +index 5f389ee..0adcea5 100644 +--- a/arch/mips/sgi-ip22/ip22-setup.c ++++ b/arch/mips/sgi-ip22/ip22-setup.c +@@ -81,30 +81,6 @@ void __init plat_mem_setup(void) + add_preferred_console("arc", 0, NULL); + } + +-#ifdef CONFIG_KGDB +- { +- char *kgdb_ttyd = prom_getcmdline(); +- +- if ((kgdb_ttyd = strstr(kgdb_ttyd, "kgdb=ttyd")) != NULL) { +- int line; +- kgdb_ttyd += strlen("kgdb=ttyd"); +- if (*kgdb_ttyd != '1' && *kgdb_ttyd != '2') +- printk(KERN_INFO "KGDB: Uknown serial line /dev/ttyd%c" +- ", falling back to /dev/ttyd1\n", *kgdb_ttyd); +- line = *kgdb_ttyd == '2' ? 0 : 1; +- printk(KERN_INFO "KGDB: Using serial line /dev/ttyd%d for " +- "session\n", line ? 1 : 2); +- rs_kgdb_hook(line); +- +- printk(KERN_INFO "KGDB: Using serial line /dev/ttyd%d for " +- "session, please connect your debugger\n", line ? 1:2); +- +- kgdb_enabled = 1; +- /* Breakpoints and stuff are in sgi_irq_setup() */ +- } +- } +-#endif +- + #if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE) + { + ULONG *gfxinfo; +diff --git a/arch/mips/sgi-ip27/Makefile b/arch/mips/sgi-ip27/Makefile +index e0a6871..31f4931 100644 +--- a/arch/mips/sgi-ip27/Makefile ++++ b/arch/mips/sgi-ip27/Makefile +@@ -7,7 +7,6 @@ obj-y := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o ip27-klnuma.o \ + ip27-xtalk.o + + obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o +-obj-$(CONFIG_KGDB) += ip27-dbgio.o + obj-$(CONFIG_SMP) += ip27-smp.o + + EXTRA_CFLAGS += -Werror +diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c +index db372a0..a35818e 100644 +--- a/arch/mips/sibyte/bcm1480/irq.c ++++ b/arch/mips/sibyte/bcm1480/irq.c +@@ -57,30 +57,6 @@ static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask); + extern unsigned long ht_eoi_space; + #endif + +-#ifdef CONFIG_KGDB +-#include +-extern void breakpoint(void); +-static int kgdb_irq; +-#ifdef CONFIG_GDB_CONSOLE +-extern void register_gdb_console(void); +-#endif +- +-/* kgdb is on when configured. Pass "nokgdb" kernel arg to turn it off */ +-static int kgdb_flag = 1; +-static int __init nokgdb(char *str) +-{ +- kgdb_flag = 0; +- return 1; +-} +-__setup("nokgdb", nokgdb); +- +-/* Default to UART1 */ +-int kgdb_port = 1; +-#ifdef CONFIG_SERIAL_SB1250_DUART +-extern char sb1250_duart_present[]; +-#endif +-#endif +- + static struct irq_chip bcm1480_irq_type = { + .name = "BCM1480-IMR", + .ack = ack_bcm1480_irq, +@@ -355,61 +331,10 @@ void __init arch_init_irq(void) + * does its own management of IP7. + */ + +-#ifdef CONFIG_KGDB +- imask |= STATUSF_IP6; +-#endif + /* Enable necessary IPs, disable the rest */ + change_c0_status(ST0_IM, imask); +- +-#ifdef CONFIG_KGDB +- if (kgdb_flag) { +- kgdb_irq = K_BCM1480_INT_UART_0 + kgdb_port; +- +-#ifdef CONFIG_SERIAL_SB1250_DUART +- sb1250_duart_present[kgdb_port] = 0; +-#endif +- /* Setup uart 1 settings, mapper */ +- /* QQQ FIXME */ +- __raw_writeq(M_DUART_IMR_BRK, IOADDR(A_DUART_IMRREG(kgdb_port))); +- +- __raw_writeq(IMR_IP6_VAL, +- IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + +- (kgdb_irq << 3))); +- bcm1480_unmask_irq(0, kgdb_irq); +- +-#ifdef CONFIG_GDB_CONSOLE +- register_gdb_console(); +-#endif +- printk("Waiting for GDB on UART port %d\n", kgdb_port); +- set_debug_traps(); +- breakpoint(); +- } +-#endif +-} +- +-#ifdef CONFIG_KGDB +- +-#include +- +-#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port, reg))) +-#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port, reg))) +- +-static void bcm1480_kgdb_interrupt(void) +-{ +- /* +- * Clear break-change status (allow some time for the remote +- * host to stop the break, since we would see another +- * interrupt on the end-of-break too) +- */ +- kstat.irqs[smp_processor_id()][kgdb_irq]++; +- mdelay(500); +- duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT | +- M_DUART_RX_EN | M_DUART_TX_EN); +- set_async_breakpoint(&get_irq_regs()->cp0_epc); + } + +-#endif /* CONFIG_KGDB */ +- + extern void bcm1480_mailbox_interrupt(void); + + static inline void dispatch_ip2(void) +@@ -462,11 +387,6 @@ asmlinkage void plat_irq_dispatch(void) + bcm1480_mailbox_interrupt(); + #endif + +-#ifdef CONFIG_KGDB +- else if (pending & CAUSEF_IP6) +- bcm1480_kgdb_interrupt(); /* KGDB (uart 1) */ +-#endif +- + else if (pending & CAUSEF_IP2) + dispatch_ip2(); + } +diff --git a/arch/mips/sibyte/cfe/setup.c b/arch/mips/sibyte/cfe/setup.c +index dbd6e6f..6bbd79a 100644 +--- a/arch/mips/sibyte/cfe/setup.c ++++ b/arch/mips/sibyte/cfe/setup.c +@@ -58,10 +58,6 @@ int cfe_cons_handle; + extern unsigned long initrd_start, initrd_end; + #endif + +-#ifdef CONFIG_KGDB +-extern int kgdb_port; +-#endif +- + static void __noreturn cfe_linux_exit(void *arg) + { + int warm = *(int *)arg; +@@ -242,9 +238,6 @@ void __init prom_init(void) + int argc = fw_arg0; + char **envp = (char **) fw_arg2; + int *prom_vec = (int *) fw_arg3; +-#ifdef CONFIG_KGDB +- char *arg; +-#endif + + _machine_restart = cfe_linux_restart; + _machine_halt = cfe_linux_halt; +@@ -308,13 +301,6 @@ void __init prom_init(void) + } + } + +-#ifdef CONFIG_KGDB +- if ((arg = strstr(arcs_cmdline, "kgdb=duart")) != NULL) +- kgdb_port = (arg[10] == '0') ? 0 : 1; +- else +- kgdb_port = 1; +-#endif +- + #ifdef CONFIG_BLK_DEV_INITRD + { + char *ptr; +diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c +index eac9065..b6fb564 100644 +--- a/arch/mips/sibyte/sb1250/irq.c ++++ b/arch/mips/sibyte/sb1250/irq.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -57,16 +58,6 @@ static void sb1250_set_affinity(unsigned int irq, cpumask_t mask); + extern unsigned long ldt_eoi_space; + #endif + +-#ifdef CONFIG_KGDB +-static int kgdb_irq; +- +-/* Default to UART1 */ +-int kgdb_port = 1; +-#ifdef CONFIG_SERIAL_SB1250_DUART +-extern char sb1250_duart_present[]; +-#endif +-#endif +- + static struct irq_chip sb1250_irq_type = { + .name = "SB1250-IMR", + .ack = ack_sb1250_irq, +@@ -270,6 +261,11 @@ void __init arch_init_irq(void) + unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | + STATUSF_IP1 | STATUSF_IP0; + ++#ifdef CONFIG_KGDB ++ if (kgdb_early_setup) ++ return; ++#endif ++ + /* Default everything to IP2 */ + for (i = 0; i < SB1250_NR_IRQS; i++) { /* was I0 */ + __raw_writeq(IMR_IP2_VAL, +@@ -313,55 +309,14 @@ void __init arch_init_irq(void) + * does its own management of IP7. + */ + +-#ifdef CONFIG_KGDB ++#ifdef CONFIG_KGDB_SIBYTE + imask |= STATUSF_IP6; + #endif + /* Enable necessary IPs, disable the rest */ + change_c0_status(ST0_IM, imask); + +-#ifdef CONFIG_KGDB +- if (kgdb_flag) { +- kgdb_irq = K_INT_UART_0 + kgdb_port; +- +-#ifdef CONFIG_SERIAL_SB1250_DUART +- sb1250_duart_present[kgdb_port] = 0; +-#endif +- /* Setup uart 1 settings, mapper */ +- __raw_writeq(M_DUART_IMR_BRK, +- IOADDR(A_DUART_IMRREG(kgdb_port))); +- +- __raw_writeq(IMR_IP6_VAL, +- IOADDR(A_IMR_REGISTER(0, +- R_IMR_INTERRUPT_MAP_BASE) + +- (kgdb_irq << 3))); +- sb1250_unmask_irq(0, kgdb_irq); +- } +-#endif +-} +- +-#ifdef CONFIG_KGDB +- +-#include +- +-#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port, reg))) +-#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port, reg))) +- +-static void sb1250_kgdb_interrupt(void) +-{ +- /* +- * Clear break-change status (allow some time for the remote +- * host to stop the break, since we would see another +- * interrupt on the end-of-break too) +- */ +- kstat_this_cpu.irqs[kgdb_irq]++; +- mdelay(500); +- duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT | +- M_DUART_RX_EN | M_DUART_TX_EN); +- set_async_breakpoint(&get_irq_regs()->cp0_epc); + } + +-#endif /* CONFIG_KGDB */ +- + extern void sb1250_mailbox_interrupt(void); + + static inline void dispatch_ip2(void) +@@ -407,7 +362,7 @@ asmlinkage void plat_irq_dispatch(void) + sb1250_mailbox_interrupt(); + #endif + +-#ifdef CONFIG_KGDB ++#ifdef CONFIG_KGDB_SIBYTE + else if (pending & CAUSEF_IP6) /* KGDB (uart 1) */ + sb1250_kgdb_interrupt(); + #endif +diff --git a/arch/mips/sibyte/sb1250/kgdb_sibyte.c b/arch/mips/sibyte/sb1250/kgdb_sibyte.c +new file mode 100644 +index 0000000..02d8e9e +--- /dev/null ++++ b/arch/mips/sibyte/sb1250/kgdb_sibyte.c +@@ -0,0 +1,145 @@ ++/* ++ * arch/mips/sibyte/sb1250/kgdb_sibyte.c ++ * ++ * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com ++ * ++ * 2004 (c) MontaVista Software, Inc. This file is licensed under ++ * the terms of the GNU General Public License version 2. This program ++ * is licensed "as is" without any warranty of any kind, whether express ++ * or implied. ++ */ ++ ++/* ++ * Support for KGDB on the Broadcom Sibyte. The SWARM board ++ * for example does not have a 8250/16550 compatible serial ++ * port. Hence, we need to have a driver for the serial ++ * ports to handle KGDB. This board needs nothing in addition ++ * to what is normally provided by the gdb portion of the stub. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++int kgdb_port = 1; ++static int kgdb_irq; ++ ++extern char sb1250_duart_present[]; ++extern int sb1250_steal_irq(int irq); ++ ++/* Forward declarations. */ ++static void kgdbsibyte_init_duart(void); ++static int kgdb_init_io(void); ++ ++#define IMR_IP6_VAL K_INT_MAP_I4 ++#define duart_out(reg, val) csr_out32(val, \ ++ IOADDR(A_DUART_CHANREG(kgdb_port, reg))) ++#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port, reg))) ++ ++static void kgdbsibyte_write_char(u8 c) ++{ ++ while ((duart_in(R_DUART_STATUS) & M_DUART_TX_RDY) == 0) ; ++ duart_out(R_DUART_TX_HOLD, c); ++} ++ ++static int kgdbsibyte_read_char(void) ++{ ++ int ret_char; ++ unsigned int status; ++ ++ do { ++ status = duart_in(R_DUART_STATUS); ++ } while ((status & M_DUART_RX_RDY) == 0); ++ ++ /* ++ * Check for framing error ++ */ ++ if (status & M_DUART_FRM_ERR) { ++ kgdbsibyte_init_duart(); ++ kgdbsibyte_write_char('-'); ++ return '-'; ++ } ++ ++ ret_char = duart_in(R_DUART_RX_HOLD); ++ ++ return ret_char; ++} ++ ++void sb1250_kgdb_interrupt(void) ++{ ++ int kgdb_irq = K_INT_UART_0 + kgdb_port; ++ ++ /* ++ * Clear break-change status (allow some time for the remote ++ * host to stop the break, since we would see another ++ * interrupt on the end-of-break too) ++ */ ++ kstat_this_cpu.irqs[kgdb_irq]++; ++ mdelay(500); ++ duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT | ++ M_DUART_RX_EN | M_DUART_TX_EN); ++ breakpoint(); ++ ++} ++ ++/* ++ * We use port #1 and we set it for 115200 BAUD, 8n1. ++ */ ++static void kgdbsibyte_init_duart(void) ++{ ++ /* Set 8n1. */ ++ duart_out(R_DUART_MODE_REG_1, ++ V_DUART_BITS_PER_CHAR_8 | V_DUART_PARITY_MODE_NONE); ++ duart_out(R_DUART_MODE_REG_2, M_DUART_STOP_BIT_LEN_1); ++ /* Set baud rate of 115200. */ ++ duart_out(R_DUART_CLK_SEL, V_DUART_BAUD_RATE(115200)); ++ /* Enable rx and tx */ ++ duart_out(R_DUART_CMD, M_DUART_RX_EN | M_DUART_TX_EN); ++} ++ ++static int kgdb_init_io(void) ++{ ++#ifdef CONFIG_SIBYTE_SB1250_DUART ++ sb1250_duart_present[kgdb_port] = 0; ++#endif ++ ++ kgdbsibyte_init_duart(); ++ ++ return 0; ++} ++ ++/* ++ * Hookup our IRQ line. We will already have been initialized a ++ * this point. ++ */ ++static void __init kgdbsibyte_hookup_irq(void) ++{ ++ /* Steal the IRQ. */ ++ kgdb_irq = K_INT_UART_0 + kgdb_port; ++ ++ /* Setup uart 1 settings, mapper */ ++ __raw_writeq(M_DUART_IMR_BRK, IOADDR(A_DUART_IMRREG(kgdb_port))); ++ ++ sb1250_steal_irq(kgdb_irq); ++ ++ __raw_writeq(IMR_IP6_VAL, ++ IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) + ++ (kgdb_irq << 3))); ++ ++ sb1250_unmask_irq(0, kgdb_irq); ++} ++ ++struct kgdb_io kgdb_io_ops = { ++ .read_char = kgdbsibyte_read_char, ++ .write_char = kgdbsibyte_write_char, ++ .init = kgdb_init_io, ++ .late_init = kgdbsibyte_hookup_irq, ++}; +diff --git a/arch/mips/sibyte/swarm/Makefile b/arch/mips/sibyte/swarm/Makefile +index 2d62603..147a7b3 100644 +--- a/arch/mips/sibyte/swarm/Makefile ++++ b/arch/mips/sibyte/swarm/Makefile +@@ -1,3 +1 @@ + lib-y = setup.o rtc_xicor1241.o rtc_m41t81.o +- +-lib-$(CONFIG_KGDB) += dbg_io.o +diff --git a/arch/mips/tx4927/common/Makefile b/arch/mips/tx4927/common/Makefile +index 1837578..7f94f9f 100644 +--- a/arch/mips/tx4927/common/Makefile ++++ b/arch/mips/tx4927/common/Makefile +@@ -9,6 +9,5 @@ + obj-y += tx4927_prom.o tx4927_setup.o tx4927_irq.o + + obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o +-obj-$(CONFIG_KGDB) += tx4927_dbgio.o + + EXTRA_CFLAGS += -Werror +diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c +index 0299595..ebc3be8 100644 +--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c ++++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c +@@ -77,7 +77,7 @@ + #include + #include + #endif +-#ifdef CONFIG_SERIAL_TXX9 ++#if defined(CONFIG_SERIAL_TXX9) || defined(CONFIG_KGDB_TXX9) + #include + #include + #include +@@ -892,9 +892,10 @@ void __init toshiba_rbtx4927_setup(void) + + #endif /* CONFIG_PCI */ + +-#ifdef CONFIG_SERIAL_TXX9 ++#if defined(CONFIG_SERIAL_TXX9) || defined(CONFIG_KGDB_TXX9) + { + extern int early_serial_txx9_setup(struct uart_port *port); ++ extern int txx9_kgdb_add_port(int n, struct uart_port *port); + struct uart_port req; + for(i = 0; i < 2; i++) { + memset(&req, 0, sizeof(req)); +@@ -905,7 +906,12 @@ void __init toshiba_rbtx4927_setup(void) + req.irq = TX4927_IRQ_PIC_BEG + 8 + i; + req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; + req.uartclk = 50000000; ++#ifdef CONFIG_SERIAL_TXX9 + early_serial_txx9_setup(&req); ++#endif ++#ifdef CONFIG_KGDB_TXX9 ++ txx9_kgdb_add_port(i, &req); ++#endif + } + } + #ifdef CONFIG_SERIAL_TXX9_CONSOLE +@@ -914,7 +920,7 @@ void __init toshiba_rbtx4927_setup(void) + strcat(argptr, " console=ttyS0,38400"); + } + #endif +-#endif ++#endif /* defined(CONFIG_SERIAL_TXX9) || defined(CONFIG_KGDB_TXX9) */ + + #ifdef CONFIG_ROOT_NFS + argptr = prom_getcmdline(); +diff --git a/arch/mips/tx4938/common/Makefile b/arch/mips/tx4938/common/Makefile +index 8352eca..d53f872 100644 +--- a/arch/mips/tx4938/common/Makefile ++++ b/arch/mips/tx4938/common/Makefile +@@ -7,6 +7,5 @@ + # + + obj-y += prom.o setup.o irq.o +-obj-$(CONFIG_KGDB) += dbgio.o + + EXTRA_CFLAGS += -Werror +diff --git a/arch/mips/tx4938/toshiba_rbtx4938/setup.c b/arch/mips/tx4938/toshiba_rbtx4938/setup.c +index 632e5d2..b8bc22c 100644 +--- a/arch/mips/tx4938/toshiba_rbtx4938/setup.c ++++ b/arch/mips/tx4938/toshiba_rbtx4938/setup.c +@@ -31,7 +31,7 @@ + #include + #include + #include +-#ifdef CONFIG_SERIAL_TXX9 ++#if defined(CONFIG_SERIAL_TXX9) || defined(CONFIG_KGDB_TXX9) + #include + #include + #include +@@ -873,9 +873,10 @@ void __init toshiba_rbtx4938_setup(void) + set_io_port_base(RBTX4938_ETHER_BASE); + #endif + +-#ifdef CONFIG_SERIAL_TXX9 ++#if defined(CONFIG_SERIAL_TXX9) || defined(CONFIG_KGDB_TXX9) + { + extern int early_serial_txx9_setup(struct uart_port *port); ++ extern int txx9_kgdb_add_port(int n, struct uart_port *port); + int i; + struct uart_port req; + for(i = 0; i < 2; i++) { +@@ -887,7 +888,12 @@ void __init toshiba_rbtx4938_setup(void) + req.irq = RBTX4938_IRQ_IRC_SIO(i); + req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; + req.uartclk = 50000000; ++#ifdef CONFIG_SERIAL_TXX9 + early_serial_txx9_setup(&req); ++#endif ++#ifdef CONFIG_KGDB_TXX9 ++ txx9_kgdb_add_port(i, &req); ++#endif + } + } + #ifdef CONFIG_SERIAL_TXX9_CONSOLE +diff --git a/include/asm-mips/asmmacro-32.h b/include/asm-mips/asmmacro-32.h +index 5de3963..ed9be99 100644 +--- a/include/asm-mips/asmmacro-32.h ++++ b/include/asm-mips/asmmacro-32.h +@@ -11,6 +11,28 @@ + #include + #include + #include ++#include ++ ++ .macro fpu_save_double_kgdb stack status tmp1 = t0 ++ cfc1 \tmp1, fcr31 ++ sdc1 $f0, GDB_FR_FPR0(\stack) ++ sdc1 $f2, GDB_FR_FPR2(\stack) ++ sdc1 $f4, GDB_FR_FPR4(\stack) ++ sdc1 $f6, GDB_FR_FPR6(\stack) ++ sdc1 $f8, GDB_FR_FPR8(\stack) ++ sdc1 $f10, GDB_FR_FPR10(\stack) ++ sdc1 $f12, GDB_FR_FPR12(\stack) ++ sdc1 $f14, GDB_FR_FPR14(\stack) ++ sdc1 $f16, GDB_FR_FPR16(\stack) ++ sdc1 $f18, GDB_FR_FPR18(\stack) ++ sdc1 $f20, GDB_FR_FPR20(\stack) ++ sdc1 $f22, GDB_FR_FPR22(\stack) ++ sdc1 $f24, GDB_FR_FPR24(\stack) ++ sdc1 $f26, GDB_FR_FPR26(\stack) ++ sdc1 $f28, GDB_FR_FPR28(\stack) ++ sdc1 $f30, GDB_FR_FPR30(\stack) ++ sw \tmp1, GDB_FR_FSR(\stack) ++ .endm + + .macro fpu_save_double thread status tmp1=t0 + cfc1 \tmp1, fcr31 +@@ -91,6 +113,27 @@ + ctc1 \tmp, fcr31 + .endm + ++ .macro fpu_restore_double_kgdb stack status tmp = t0 ++ lw \tmp, GDB_FR_FSR(\stack) ++ ldc1 $f0, GDB_FR_FPR0(\stack) ++ ldc1 $f2, GDB_FR_FPR2(\stack) ++ ldc1 $f4, GDB_FR_FPR4(\stack) ++ ldc1 $f6, GDB_FR_FPR6(\stack) ++ ldc1 $f8, GDB_FR_FPR8(\stack) ++ ldc1 $f10, GDB_FR_FPR10(\stack) ++ ldc1 $f12, GDB_FR_FPR12(\stack) ++ ldc1 $f14, GDB_FR_FPR14(\stack) ++ ldc1 $f16, GDB_FR_FPR16(\stack) ++ ldc1 $f18, GDB_FR_FPR18(\stack) ++ ldc1 $f20, GDB_FR_FPR20(\stack) ++ ldc1 $f22, GDB_FR_FPR22(\stack) ++ ldc1 $f24, GDB_FR_FPR24(\stack) ++ ldc1 $f26, GDB_FR_FPR26(\stack) ++ ldc1 $f28, GDB_FR_FPR28(\stack) ++ ldc1 $f30, GDB_FR_FPR30(\stack) ++ ctc1 \tmp, fcr31 ++ .endm ++ + .macro fpu_restore_single thread tmp=t0 + lw \tmp, THREAD_FCR31(\thread) + lwc1 $f0, THREAD_FPR0(\thread) +diff --git a/include/asm-mips/asmmacro-64.h b/include/asm-mips/asmmacro-64.h +index 225feef..9789218 100644 +--- a/include/asm-mips/asmmacro-64.h ++++ b/include/asm-mips/asmmacro-64.h +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + .macro fpu_save_16even thread tmp=t0 + cfc1 \tmp, fcr31 +@@ -53,6 +54,46 @@ + sdc1 $f31, THREAD_FPR31(\thread) + .endm + ++ .macro fpu_save_16odd_kgdb stack ++ sdc1 $f1, GDB_FR_FPR1(\stack) ++ sdc1 $f3, GDB_FR_FPR3(\stack) ++ sdc1 $f5, GDB_FR_FPR5(\stack) ++ sdc1 $f7, GDB_FR_FPR7(\stack) ++ sdc1 $f9, GDB_FR_FPR9(\stack) ++ sdc1 $f11, GDB_FR_FPR11(\stack) ++ sdc1 $f13, GDB_FR_FPR13(\stack) ++ sdc1 $f15, GDB_FR_FPR15(\stack) ++ sdc1 $f17, GDB_FR_FPR17(\stack) ++ sdc1 $f19, GDB_FR_FPR19(\stack) ++ sdc1 $f21, GDB_FR_FPR21(\stack) ++ sdc1 $f23, GDB_FR_FPR23(\stack) ++ sdc1 $f25, GDB_FR_FPR25(\stack) ++ sdc1 $f27, GDB_FR_FPR27(\stack) ++ sdc1 $f29, GDB_FR_FPR29(\stack) ++ sdc1 $f31, GDB_FR_FPR31(\stack) ++ .endm ++ ++ .macro fpu_save_16even_kgdb stack tmp = t0 ++ cfc1 \tmp, fcr31 ++ sdc1 $f0, GDB_FR_FPR0(\stack) ++ sdc1 $f2, GDB_FR_FPR2(\stack) ++ sdc1 $f4, GDB_FR_FPR4(\stack) ++ sdc1 $f6, GDB_FR_FPR6(\stack) ++ sdc1 $f8, GDB_FR_FPR8(\stack) ++ sdc1 $f10, GDB_FR_FPR10(\stack) ++ sdc1 $f12, GDB_FR_FPR12(\stack) ++ sdc1 $f14, GDB_FR_FPR14(\stack) ++ sdc1 $f16, GDB_FR_FPR16(\stack) ++ sdc1 $f18, GDB_FR_FPR18(\stack) ++ sdc1 $f20, GDB_FR_FPR20(\stack) ++ sdc1 $f22, GDB_FR_FPR22(\stack) ++ sdc1 $f24, GDB_FR_FPR24(\stack) ++ sdc1 $f26, GDB_FR_FPR26(\stack) ++ sdc1 $f28, GDB_FR_FPR28(\stack) ++ sdc1 $f30, GDB_FR_FPR30(\stack) ++ sw \tmp, GDB_FR_FSR(\stack) ++ .endm ++ + .macro fpu_save_double thread status tmp + sll \tmp, \status, 5 + bgez \tmp, 2f +@@ -61,6 +102,15 @@ + fpu_save_16even \thread \tmp + .endm + ++ .macro fpu_save_double_kgdb stack status tmp ++ sll \tmp, \status, 5 ++ bgez \tmp, 2f ++ nop ++ fpu_save_16odd_kgdb \stack ++2: ++ fpu_save_16even_kgdb \stack \tmp ++ .endm ++ + .macro fpu_restore_16even thread tmp=t0 + lw \tmp, THREAD_FCR31(\thread) + ldc1 $f0, THREAD_FPR0(\thread) +@@ -101,6 +151,46 @@ + ldc1 $f31, THREAD_FPR31(\thread) + .endm + ++ .macro fpu_restore_16even_kgdb stack tmp = t0 ++ lw \tmp, GDB_FR_FSR(\stack) ++ ldc1 $f0, GDB_FR_FPR0(\stack) ++ ldc1 $f2, GDB_FR_FPR2(\stack) ++ ldc1 $f4, GDB_FR_FPR4(\stack) ++ ldc1 $f6, GDB_FR_FPR6(\stack) ++ ldc1 $f8, GDB_FR_FPR8(\stack) ++ ldc1 $f10, GDB_FR_FPR10(\stack) ++ ldc1 $f12, GDB_FR_FPR12(\stack) ++ ldc1 $f14, GDB_FR_FPR14(\stack) ++ ldc1 $f16, GDB_FR_FPR16(\stack) ++ ldc1 $f18, GDB_FR_FPR18(\stack) ++ ldc1 $f20, GDB_FR_FPR20(\stack) ++ ldc1 $f22, GDB_FR_FPR22(\stack) ++ ldc1 $f24, GDB_FR_FPR24(\stack) ++ ldc1 $f26, GDB_FR_FPR26(\stack) ++ ldc1 $f28, GDB_FR_FPR28(\stack) ++ ldc1 $f30, GDB_FR_FPR30(\stack) ++ ctc1 \tmp, fcr31 ++ .endm ++ ++ .macro fpu_restore_16odd_kgdb stack ++ ldc1 $f1, GDB_FR_FPR1(\stack) ++ ldc1 $f3, GDB_FR_FPR3(\stack) ++ ldc1 $f5, GDB_FR_FPR5(\stack) ++ ldc1 $f7, GDB_FR_FPR7(\stack) ++ ldc1 $f9, GDB_FR_FPR9(\stack) ++ ldc1 $f11, GDB_FR_FPR11(\stack) ++ ldc1 $f13, GDB_FR_FPR13(\stack) ++ ldc1 $f15, GDB_FR_FPR15(\stack) ++ ldc1 $f17, GDB_FR_FPR17(\stack) ++ ldc1 $f19, GDB_FR_FPR19(\stack) ++ ldc1 $f21, GDB_FR_FPR21(\stack) ++ ldc1 $f23, GDB_FR_FPR23(\stack) ++ ldc1 $f25, GDB_FR_FPR25(\stack) ++ ldc1 $f27, GDB_FR_FPR27(\stack) ++ ldc1 $f29, GDB_FR_FPR29(\stack) ++ ldc1 $f31, GDB_FR_FPR31(\stack) ++ .endm ++ + .macro fpu_restore_double thread status tmp + sll \tmp, \status, 5 + bgez \tmp, 1f # 16 register mode? +@@ -109,6 +199,15 @@ + 1: fpu_restore_16even \thread \tmp + .endm + ++ .macro fpu_restore_double_kgdb stack status tmp ++ sll \tmp, \status, 5 ++ bgez \tmp, 1f # 16 register mode? ++ nop ++ ++ fpu_restore_16odd_kgdb \stack ++1: fpu_restore_16even_kgdb \stack \tmp ++ .endm ++ + .macro cpu_save_nonscratch thread + LONG_S s0, THREAD_REG16(\thread) + LONG_S s1, THREAD_REG17(\thread) +diff --git a/include/asm-mips/kdebug.h b/include/asm-mips/kdebug.h +index 6ece1b0..d78abd7 100644 +--- a/include/asm-mips/kdebug.h ++++ b/include/asm-mips/kdebug.h +@@ -1 +1,29 @@ +-#include ++/* ++ * ++ * Copyright (C) 2004 MontaVista Software Inc. ++ * Author: Manish Lachwani, mlachwani@mvista.com or manish@koffee-break.com ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++#ifndef _MIPS_KDEBUG_H ++#define _MIPS_KDEBUG_H ++ ++#include ++ ++struct pt_regs; ++ ++extern struct atomic_notifier_head mips_die_head; ++ ++enum die_val { ++ DIE_OOPS = 1, ++ DIE_PANIC, ++ DIE_DIE, ++ DIE_KERNELDEBUG, ++ DIE_TRAP, ++}; ++ ++#endif /* _MIPS_KDEBUG_H */ +diff --git a/include/asm-mips/kgdb.h b/include/asm-mips/kgdb.h +new file mode 100644 +index 0000000..76facd8 +--- /dev/null ++++ b/include/asm-mips/kgdb.h +@@ -0,0 +1,50 @@ ++#ifdef __KERNEL__ ++#ifndef _ASM_KGDB_H_ ++#define _ASM_KGDB_H_ ++ ++#include ++ ++#ifndef __ASSEMBLY__ ++#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \ ++ (_MIPS_ISA == _MIPS_ISA_MIPS32) ++ ++#define KGDB_GDB_REG_SIZE 32 ++ ++#elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ ++ (_MIPS_ISA == _MIPS_ISA_MIPS64) ++ ++#ifdef CONFIG_32BIT ++#define KGDB_GDB_REG_SIZE 32 ++#else /* CONFIG_CPU_32BIT */ ++#define KGDB_GDB_REG_SIZE 64 ++#endif ++#else ++#error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA" ++#endif /* _MIPS_ISA */ ++ ++#define BUFMAX 2048 ++#if (KGDB_GDB_REG_SIZE == 32) ++#define NUMREGBYTES (90*sizeof(u32)) ++#define NUMCRITREGBYTES (12*sizeof(u32)) ++#else ++#define NUMREGBYTES (90*sizeof(u64)) ++#define NUMCRITREGBYTES (12*sizeof(u64)) ++#endif ++#define BREAK_INSTR_SIZE 4 ++static inline void arch_kgdb_breakpoint(void) ++{ ++ __asm__ __volatile__( ++ ".globl breakinst\n\t" ++ ".set\tnoreorder\n\t" ++ "nop\n" ++ "breakinst:\tbreak\n\t" ++ "nop\n\t" ++ ".set\treorder"); ++} ++#define CACHE_FLUSH_IS_SAFE 0 ++ ++extern int kgdb_early_setup; ++ ++#endif /* !__ASSEMBLY__ */ ++#endif /* _ASM_KGDB_H_ */ ++#endif /* __KERNEL__ */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0004-kgdb-core.patch +++ linux-2.6.24/patches/0004-kgdb-core.patch @@ -0,0 +1,2059 @@ +From 44e4a793ed58307fb4999066b3fae759022d835f Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Mon, 10 Mar 2008 08:41:28 +0100 +Subject: [PATCH 004/170] kgdb: core + +kgdb core code. Handles the protocol and the arch details. + +[ mingo@elte.hu: heavily modified, simplified and cleaned up. ] +[ xemul@openvz.org: use find_task_by_pid_ns ] + +Signed-off-by: Jason Wessel +Signed-off-by: Ingo Molnar +Signed-off-by: Jan Kiszka +Reviewed-by: Thomas Gleixner +--- + include/linux/kgdb.h | 271 ++++++++ + kernel/Makefile | 1 + + kernel/kgdb.c | 1693 ++++++++++++++++++++++++++++++++++++++++++++++++++ + lib/Kconfig.debug | 2 + + lib/Kconfig.kgdb | 27 + + 5 files changed, 1994 insertions(+), 0 deletions(-) + create mode 100644 include/linux/kgdb.h + create mode 100644 kernel/kgdb.c + create mode 100644 lib/Kconfig.kgdb + +diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h +new file mode 100644 +index 0000000..b0985b7 +--- /dev/null ++++ b/include/linux/kgdb.h +@@ -0,0 +1,271 @@ ++/* ++ * This provides the callbacks and functions that KGDB needs to share between ++ * the core, I/O and arch-specific portions. ++ * ++ * Author: Amit Kale and ++ * Tom Rini ++ * ++ * 2001-2004 (c) Amit S. Kale and 2003-2005 (c) MontaVista Software, Inc. ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++#ifndef _KGDB_H_ ++#define _KGDB_H_ ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++struct pt_regs; ++ ++/* ++ * kgdb_skipexception - Bail out of KGDB when we've been triggered. ++ * @exception: Exception vector number ++ * @regs: Current &struct pt_regs. ++ * ++ * On some architectures we need to skip a breakpoint exception when ++ * it occurs after a breakpoint has been removed. ++ */ ++extern int kgdb_skipexception(int exception, struct pt_regs *regs); ++ ++/* ++ * kgdb_post_primary_code - Save error vector/code numbers. ++ * @regs: Original pt_regs. ++ * @e_vector: Original error vector. ++ * @err_code: Original error code. ++ * ++ * This is needed on architectures which support SMP and KGDB. ++ * This function is called after all the secondary cpus have been put ++ * to a know spin state and the primary CPU has control over KGDB. ++ */ ++extern void kgdb_post_primary_code(struct pt_regs *regs, int e_vector, ++ int err_code); ++ ++/* ++ * kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb. ++ * @regs: Current &struct pt_regs. ++ * ++ * This function will be called if the particular architecture must ++ * disable hardware debugging while it is processing gdb packets or ++ * handling exception. ++ */ ++extern void kgdb_disable_hw_debug(struct pt_regs *regs); ++ ++struct tasklet_struct; ++struct task_struct; ++struct uart_port; ++ ++/* To enter the debugger explicitly. */ ++void kgdb_breakpoint(void); ++ ++extern int kgdb_connected; ++ ++extern atomic_t kgdb_setting_breakpoint; ++extern atomic_t kgdb_cpu_doing_single_step; ++ ++extern struct task_struct *kgdb_usethread; ++extern struct task_struct *kgdb_contthread; ++ ++enum kgdb_bptype { ++ BP_BREAKPOINT = 0, ++ BP_HARDWARE_BREAKPOINT, ++ BP_WRITE_WATCHPOINT, ++ BP_READ_WATCHPOINT, ++ BP_ACCESS_WATCHPOINT ++}; ++ ++enum kgdb_bpstate { ++ BP_UNDEFINED = 0, ++ BP_REMOVED, ++ BP_SET, ++ BP_ACTIVE ++}; ++ ++struct kgdb_bkpt { ++ unsigned long bpt_addr; ++ unsigned char saved_instr[BREAK_INSTR_SIZE]; ++ enum kgdb_bptype type; ++ enum kgdb_bpstate state; ++}; ++ ++#ifndef KGDB_MAX_BREAKPOINTS ++# define KGDB_MAX_BREAKPOINTS 1000 ++#endif ++ ++#define KGDB_HW_BREAKPOINT 1 ++ ++/* ++ * Functions each KGDB-supporting architecture must provide: ++ */ ++ ++/* ++ * kgdb_arch_init - Perform any architecture specific initalization. ++ * ++ * This function will handle the initalization of any architecture ++ * specific callbacks. ++ */ ++extern int kgdb_arch_init(void); ++ ++/* ++ * kgdb_arch_exit - Perform any architecture specific uninitalization. ++ * ++ * This function will handle the uninitalization of any architecture ++ * specific callbacks, for dynamic registration and unregistration. ++ */ ++extern void kgdb_arch_exit(void); ++ ++/* ++ * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs ++ * @gdb_regs: A pointer to hold the registers in the order GDB wants. ++ * @regs: The &struct pt_regs of the current process. ++ * ++ * Convert the pt_regs in @regs into the format for registers that ++ * GDB expects, stored in @gdb_regs. ++ */ ++extern void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs); ++ ++/* ++ * sleeping_thread_to_gdb_regs - Convert ptrace regs to GDB regs ++ * @gdb_regs: A pointer to hold the registers in the order GDB wants. ++ * @p: The &struct task_struct of the desired process. ++ * ++ * Convert the register values of the sleeping process in @p to ++ * the format that GDB expects. ++ * This function is called when kgdb does not have access to the ++ * &struct pt_regs and therefore it should fill the gdb registers ++ * @gdb_regs with what has been saved in &struct thread_struct ++ * thread field during switch_to. ++ */ ++extern void ++sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p); ++ ++/* ++ * gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs. ++ * @gdb_regs: A pointer to hold the registers we've received from GDB. ++ * @regs: A pointer to a &struct pt_regs to hold these values in. ++ * ++ * Convert the GDB regs in @gdb_regs into the pt_regs, and store them ++ * in @regs. ++ */ ++extern void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs); ++ ++/* ++ * kgdb_arch_handle_exception - Handle architecture specific GDB packets. ++ * @vector: The error vector of the exception that happened. ++ * @signo: The signal number of the exception that happened. ++ * @err_code: The error code of the exception that happened. ++ * @remcom_in_buffer: The buffer of the packet we have read. ++ * @remcom_out_buffer: The buffer of %BUFMAX bytes to write a packet into. ++ * @regs: The &struct pt_regs of the current process. ++ * ++ * This function MUST handle the 'c' and 's' command packets, ++ * as well packets to set / remove a hardware breakpoint, if used. ++ * If there are additional packets which the hardware needs to handle, ++ * they are handled here. The code should return -1 if it wants to ++ * process more packets, and a %0 or %1 if it wants to exit from the ++ * kgdb callback. ++ */ ++extern int ++kgdb_arch_handle_exception(int vector, int signo, int err_code, ++ char *remcom_in_buffer, ++ char *remcom_out_buffer, ++ struct pt_regs *regs); ++ ++/* ++ * kgdb_roundup_cpus - Get other CPUs into a holding pattern ++ * @flags: Current IRQ state ++ * ++ * On SMP systems, we need to get the attention of the other CPUs ++ * and get them be in a known state. This should do what is needed ++ * to get the other CPUs to call kgdb_wait(). Note that on some arches, ++ * the NMI approach is not used for rounding up all the CPUs. For example, ++ * in case of MIPS, smp_call_function() is used to roundup CPUs. In ++ * this case, we have to make sure that interrupts are enabled before ++ * calling smp_call_function(). The argument to this function is ++ * the flags that will be used when restoring the interrupts. There is ++ * local_irq_save() call before kgdb_roundup_cpus(). ++ * ++ * On non-SMP systems, this is not called. ++ */ ++extern void kgdb_roundup_cpus(unsigned long flags); ++ ++/* Optional functions. */ ++extern int kgdb_validate_break_address(unsigned long addr); ++extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr); ++extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle); ++ ++/* ++ * struct kgdb_arch - Describe architecture specific values. ++ * @gdb_bpt_instr: The instruction to trigger a breakpoint. ++ * @flags: Flags for the breakpoint, currently just %KGDB_HW_BREAKPOINT. ++ * @set_breakpoint: Allow an architecture to specify how to set a software ++ * breakpoint. ++ * @remove_breakpoint: Allow an architecture to specify how to remove a ++ * software breakpoint. ++ * @set_hw_breakpoint: Allow an architecture to specify how to set a hardware ++ * breakpoint. ++ * @remove_hw_breakpoint: Allow an architecture to specify how to remove a ++ * hardware breakpoint. ++ * @remove_all_hw_break: Allow an architecture to specify how to remove all ++ * hardware breakpoints. ++ * @correct_hw_break: Allow an architecture to specify how to correct the ++ * hardware debug registers. ++ */ ++struct kgdb_arch { ++ unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE]; ++ unsigned long flags; ++ ++ int (*set_breakpoint)(unsigned long, char *); ++ int (*remove_breakpoint)(unsigned long, char *); ++ int (*set_hw_breakpoint)(unsigned long, int, enum kgdb_bptype); ++ int (*remove_hw_breakpoint)(unsigned long, int, enum kgdb_bptype); ++ void (*remove_all_hw_break)(void); ++ void (*correct_hw_break)(void); ++}; ++ ++/* ++ * struct kgdb_io - Describe the interface for an I/O driver to talk with KGDB. ++ * @name: Name of the I/O driver. ++ * @read_char: Pointer to a function that will return one char. ++ * @write_char: Pointer to a function that will write one char. ++ * @flush: Pointer to a function that will flush any pending writes. ++ * @init: Pointer to a function that will initialize the device. ++ * @pre_exception: Pointer to a function that will do any prep work for ++ * the I/O driver. ++ * @post_exception: Pointer to a function that will do any cleanup work ++ * for the I/O driver. ++ */ ++struct kgdb_io { ++ const char *name; ++ int (*read_char) (void); ++ void (*write_char) (u8); ++ void (*flush) (void); ++ int (*init) (void); ++ void (*pre_exception) (void); ++ void (*post_exception) (void); ++}; ++ ++extern struct kgdb_arch arch_kgdb_ops; ++ ++extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops); ++extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops); ++ ++extern int kgdb_hex2long(char **ptr, long *long_val); ++extern int kgdb_mem2hex(char *mem, char *buf, int count); ++extern int kgdb_hex2mem(char *buf, char *mem, int count); ++ ++extern int kgdb_isremovedbreak(unsigned long addr); ++ ++extern int ++kgdb_handle_exception(int ex_vector, int signo, int err_code, ++ struct pt_regs *regs); ++extern int kgdb_nmicallback(int cpu, void *regs); ++ ++extern int kgdb_single_step; ++extern atomic_t kgdb_active; ++ ++#endif /* _KGDB_H_ */ +diff --git a/kernel/Makefile b/kernel/Makefile +index 6d9a87c..796a6a1 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -47,6 +47,7 @@ obj-$(CONFIG_AUDIT) += audit.o auditfilter.o + obj-$(CONFIG_AUDITSYSCALL) += auditsc.o + obj-$(CONFIG_AUDIT_TREE) += audit_tree.o + obj-$(CONFIG_KPROBES) += kprobes.o ++obj-$(CONFIG_KGDB) += kgdb.o + obj-$(CONFIG_SYSFS) += ksysfs.o + obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o + obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ +diff --git a/kernel/kgdb.c b/kernel/kgdb.c +new file mode 100644 +index 0000000..017ee78 +--- /dev/null ++++ b/kernel/kgdb.c +@@ -0,0 +1,1693 @@ ++/* ++ * KGDB stub. ++ * ++ * Maintainer: Jason Wessel ++ * ++ * Copyright (C) 2000-2001 VERITAS Software Corporation. ++ * Copyright (C) 2002-2004 Timesys Corporation ++ * Copyright (C) 2003-2004 Amit S. Kale ++ * Copyright (C) 2004 Pavel Machek ++ * Copyright (C) 2004-2006 Tom Rini ++ * Copyright (C) 2004-2006 LinSysSoft Technologies Pvt. Ltd. ++ * Copyright (C) 2005-2008 Wind River Systems, Inc. ++ * Copyright (C) 2007 MontaVista Software, Inc. ++ * Copyright (C) 2008 Red Hat, Inc., Ingo Molnar ++ * ++ * Contributors at various stages not listed above: ++ * Jason Wessel ( jason.wessel@windriver.com ) ++ * George Anzinger ++ * Anurekh Saxena (anurekh.saxena@timesys.com) ++ * Lake Stevens Instrument Division (Glenn Engel) ++ * Jim Kingdon, Cygnus Support. ++ * ++ * Original KGDB stub: David Grothe , ++ * Tigran Aivazian ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++static int kgdb_break_asap; ++ ++struct kgdb_state { ++ int ex_vector; ++ int signo; ++ int err_code; ++ int cpu; ++ int pass_exception; ++ long threadid; ++ long kgdb_usethreadid; ++ struct pt_regs *linux_regs; ++}; ++ ++static struct debuggerinfo_struct { ++ void *debuggerinfo; ++ struct task_struct *task; ++} kgdb_info[NR_CPUS]; ++ ++/** ++ * kgdb_connected - Is a host GDB connected to us? ++ */ ++int kgdb_connected; ++EXPORT_SYMBOL_GPL(kgdb_connected); ++ ++/* All the KGDB handlers are installed */ ++static int kgdb_io_module_registered; ++ ++/* Guard for recursive entry */ ++static int exception_level; ++ ++static struct kgdb_io *kgdb_io_ops; ++static DEFINE_SPINLOCK(kgdb_registration_lock); ++ ++/* kgdb console driver is loaded */ ++static int kgdb_con_registered; ++/* determine if kgdb console output should be used */ ++static int kgdb_use_con; ++ ++static int __init opt_kgdb_con(char *str) ++{ ++ kgdb_use_con = 1; ++ return 0; ++} ++ ++early_param("kgdbcon", opt_kgdb_con); ++ ++module_param(kgdb_use_con, int, 0644); ++ ++/* ++ * Holds information about breakpoints in a kernel. These breakpoints are ++ * added and removed by gdb. ++ */ ++static struct kgdb_bkpt kgdb_break[KGDB_MAX_BREAKPOINTS] = { ++ [0 ... KGDB_MAX_BREAKPOINTS-1] = { .state = BP_UNDEFINED } ++}; ++ ++/* ++ * The CPU# of the active CPU, or -1 if none: ++ */ ++atomic_t kgdb_active = ATOMIC_INIT(-1); ++ ++/* ++ * We use NR_CPUs not PERCPU, in case kgdb is used to debug early ++ * bootup code (which might not have percpu set up yet): ++ */ ++static atomic_t passive_cpu_wait[NR_CPUS]; ++static atomic_t cpu_in_kgdb[NR_CPUS]; ++atomic_t kgdb_setting_breakpoint; ++ ++struct task_struct *kgdb_usethread; ++struct task_struct *kgdb_contthread; ++ ++int kgdb_single_step; ++ ++/* Our I/O buffers. */ ++static char remcom_in_buffer[BUFMAX]; ++static char remcom_out_buffer[BUFMAX]; ++ ++/* Storage for the registers, in GDB format. */ ++static unsigned long gdb_regs[(NUMREGBYTES + ++ sizeof(unsigned long) - 1) / ++ sizeof(unsigned long)]; ++ ++/* to keep track of the CPU which is doing the single stepping*/ ++atomic_t kgdb_cpu_doing_single_step = ATOMIC_INIT(-1); ++ ++/* ++ * If you are debugging a problem where roundup (the collection of ++ * all other CPUs) is a problem [this should be extremely rare], ++ * then use the nokgdbroundup option to avoid roundup. In that case ++ * the other CPUs might interfere with your debugging context, so ++ * use this with care: ++ */ ++int kgdb_do_roundup = 1; ++ ++static int __init opt_nokgdbroundup(char *str) ++{ ++ kgdb_do_roundup = 0; ++ ++ return 0; ++} ++ ++early_param("nokgdbroundup", opt_nokgdbroundup); ++ ++/* ++ * Finally, some KGDB code :-) ++ */ ++ ++/* ++ * Weak aliases for breakpoint management, ++ * can be overriden by architectures when needed: ++ */ ++int __weak kgdb_validate_break_address(unsigned long addr) ++{ ++ char tmp_variable[BREAK_INSTR_SIZE]; ++ ++ return probe_kernel_read(tmp_variable, (char *)addr, BREAK_INSTR_SIZE); ++} ++ ++int __weak kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr) ++{ ++ int err; ++ ++ err = probe_kernel_read(saved_instr, (char *)addr, BREAK_INSTR_SIZE); ++ if (err) ++ return err; ++ ++ return probe_kernel_write((char *)addr, arch_kgdb_ops.gdb_bpt_instr, ++ BREAK_INSTR_SIZE); ++} ++ ++int __weak kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle) ++{ ++ return probe_kernel_write((char *)addr, ++ (char *)bundle, BREAK_INSTR_SIZE); ++} ++ ++unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs) ++{ ++ return instruction_pointer(regs); ++} ++ ++int __weak kgdb_arch_init(void) ++{ ++ return 0; ++} ++ ++/** ++ * kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb. ++ * @regs: Current &struct pt_regs. ++ * ++ * This function will be called if the particular architecture must ++ * disable hardware debugging while it is processing gdb packets or ++ * handling exception. ++ */ ++void __weak kgdb_disable_hw_debug(struct pt_regs *regs) ++{ ++} ++ ++/* ++ * GDB remote protocol parser: ++ */ ++ ++static const char hexchars[] = "0123456789abcdef"; ++ ++static int hex(char ch) ++{ ++ if ((ch >= 'a') && (ch <= 'f')) ++ return ch - 'a' + 10; ++ if ((ch >= '0') && (ch <= '9')) ++ return ch - '0'; ++ if ((ch >= 'A') && (ch <= 'F')) ++ return ch - 'A' + 10; ++ return -1; ++} ++ ++/* scan for the sequence $# */ ++static void get_packet(char *buffer) ++{ ++ unsigned char checksum; ++ unsigned char xmitcsum; ++ int count; ++ char ch; ++ ++ do { ++ /* ++ * Spin and wait around for the start character, ignore all ++ * other characters: ++ */ ++ while ((ch = (kgdb_io_ops->read_char())) != '$') ++ /* nothing */; ++ ++ kgdb_connected = 1; ++ checksum = 0; ++ xmitcsum = -1; ++ ++ count = 0; ++ ++ /* ++ * now, read until a # or end of buffer is found: ++ */ ++ while (count < (BUFMAX - 1)) { ++ ch = kgdb_io_ops->read_char(); ++ if (ch == '#') ++ break; ++ checksum = checksum + ch; ++ buffer[count] = ch; ++ count = count + 1; ++ } ++ buffer[count] = 0; ++ ++ if (ch == '#') { ++ xmitcsum = hex(kgdb_io_ops->read_char()) << 4; ++ xmitcsum += hex(kgdb_io_ops->read_char()); ++ ++ if (checksum != xmitcsum) ++ /* failed checksum */ ++ kgdb_io_ops->write_char('-'); ++ else ++ /* successful transfer */ ++ kgdb_io_ops->write_char('+'); ++ if (kgdb_io_ops->flush) ++ kgdb_io_ops->flush(); ++ } ++ } while (checksum != xmitcsum); ++} ++ ++/* ++ * Send the packet in buffer. ++ * Check for gdb connection if asked for. ++ */ ++static void put_packet(char *buffer) ++{ ++ unsigned char checksum; ++ int count; ++ char ch; ++ ++ /* ++ * $#. ++ */ ++ while (1) { ++ kgdb_io_ops->write_char('$'); ++ checksum = 0; ++ count = 0; ++ ++ while ((ch = buffer[count])) { ++ kgdb_io_ops->write_char(ch); ++ checksum += ch; ++ count++; ++ } ++ ++ kgdb_io_ops->write_char('#'); ++ kgdb_io_ops->write_char(hexchars[checksum >> 4]); ++ kgdb_io_ops->write_char(hexchars[checksum & 0xf]); ++ if (kgdb_io_ops->flush) ++ kgdb_io_ops->flush(); ++ ++ /* Now see what we get in reply. */ ++ ch = kgdb_io_ops->read_char(); ++ ++ if (ch == 3) ++ ch = kgdb_io_ops->read_char(); ++ ++ /* If we get an ACK, we are done. */ ++ if (ch == '+') ++ return; ++ ++ /* ++ * If we get the start of another packet, this means ++ * that GDB is attempting to reconnect. We will NAK ++ * the packet being sent, and stop trying to send this ++ * packet. ++ */ ++ if (ch == '$') { ++ kgdb_io_ops->write_char('-'); ++ if (kgdb_io_ops->flush) ++ kgdb_io_ops->flush(); ++ return; ++ } ++ } ++} ++ ++static char *pack_hex_byte(char *pkt, u8 byte) ++{ ++ *pkt++ = hexchars[byte >> 4]; ++ *pkt++ = hexchars[byte & 0xf]; ++ ++ return pkt; ++} ++ ++/* ++ * Convert the memory pointed to by mem into hex, placing result in buf. ++ * Return a pointer to the last char put in buf (null). May return an error. ++ */ ++int kgdb_mem2hex(char *mem, char *buf, int count) ++{ ++ char *tmp; ++ int err; ++ ++ /* ++ * We use the upper half of buf as an intermediate buffer for the ++ * raw memory copy. Hex conversion will work against this one. ++ */ ++ tmp = buf + count; ++ ++ err = probe_kernel_read(tmp, mem, count); ++ if (!err) { ++ while (count > 0) { ++ buf = pack_hex_byte(buf, *tmp); ++ tmp++; ++ count--; ++ } ++ ++ *buf = 0; ++ } ++ ++ return err; ++} ++ ++/* ++ * Copy the binary array pointed to by buf into mem. Fix $, #, and ++ * 0x7d escaped with 0x7d. Return a pointer to the character after ++ * the last byte written. ++ */ ++static int kgdb_ebin2mem(char *buf, char *mem, int count) ++{ ++ int err = 0; ++ char c; ++ ++ while (count-- > 0) { ++ c = *buf++; ++ if (c == 0x7d) ++ c = *buf++ ^ 0x20; ++ ++ err = probe_kernel_write(mem, &c, 1); ++ if (err) ++ break; ++ ++ mem++; ++ } ++ ++ return err; ++} ++ ++/* ++ * Convert the hex array pointed to by buf into binary to be placed in mem. ++ * Return a pointer to the character AFTER the last byte written. ++ * May return an error. ++ */ ++int kgdb_hex2mem(char *buf, char *mem, int count) ++{ ++ char *tmp_raw; ++ char *tmp_hex; ++ ++ /* ++ * We use the upper half of buf as an intermediate buffer for the ++ * raw memory that is converted from hex. ++ */ ++ tmp_raw = buf + count * 2; ++ ++ tmp_hex = tmp_raw - 1; ++ while (tmp_hex >= buf) { ++ tmp_raw--; ++ *tmp_raw = hex(*tmp_hex--); ++ *tmp_raw |= hex(*tmp_hex--) << 4; ++ } ++ ++ return probe_kernel_write(mem, tmp_raw, count); ++} ++ ++/* ++ * While we find nice hex chars, build a long_val. ++ * Return number of chars processed. ++ */ ++int kgdb_hex2long(char **ptr, long *long_val) ++{ ++ int hex_val; ++ int num = 0; ++ ++ *long_val = 0; ++ ++ while (**ptr) { ++ hex_val = hex(**ptr); ++ if (hex_val < 0) ++ break; ++ ++ *long_val = (*long_val << 4) | hex_val; ++ num++; ++ (*ptr)++; ++ } ++ ++ return num; ++} ++ ++/* Write memory due to an 'M' or 'X' packet. */ ++static int write_mem_msg(int binary) ++{ ++ char *ptr = &remcom_in_buffer[1]; ++ unsigned long addr; ++ unsigned long length; ++ int err; ++ ++ if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ',' && ++ kgdb_hex2long(&ptr, &length) > 0 && *(ptr++) == ':') { ++ if (binary) ++ err = kgdb_ebin2mem(ptr, (char *)addr, length); ++ else ++ err = kgdb_hex2mem(ptr, (char *)addr, length); ++ if (err) ++ return err; ++ if (CACHE_FLUSH_IS_SAFE) ++ flush_icache_range(addr, addr + length + 1); ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static void error_packet(char *pkt, int error) ++{ ++ error = -error; ++ pkt[0] = 'E'; ++ pkt[1] = hexchars[(error / 10)]; ++ pkt[2] = hexchars[(error % 10)]; ++ pkt[3] = '\0'; ++} ++ ++/* ++ * Thread ID accessors. We represent a flat TID space to GDB, where ++ * the per CPU idle threads (which under Linux all have PID 0) are ++ * remapped to negative TIDs. ++ */ ++ ++#define BUF_THREAD_ID_SIZE 16 ++ ++static char *pack_threadid(char *pkt, unsigned char *id) ++{ ++ char *limit; ++ ++ limit = pkt + BUF_THREAD_ID_SIZE; ++ while (pkt < limit) ++ pkt = pack_hex_byte(pkt, *id++); ++ ++ return pkt; ++} ++ ++static void int_to_threadref(unsigned char *id, int value) ++{ ++ unsigned char *scan; ++ int i = 4; ++ ++ scan = (unsigned char *)id; ++ while (i--) ++ *scan++ = 0; ++ *scan++ = (value >> 24) & 0xff; ++ *scan++ = (value >> 16) & 0xff; ++ *scan++ = (value >> 8) & 0xff; ++ *scan++ = (value & 0xff); ++} ++ ++static struct task_struct *getthread(struct pt_regs *regs, int tid) ++{ ++ /* ++ * Non-positive TIDs are remapped idle tasks: ++ */ ++ if (tid <= 0) ++ return idle_task(-tid); ++ ++ /* ++ * find_task_by_pid_ns() does not take the tasklist lock anymore ++ * but is nicely RCU locked - hence is a pretty resilient ++ * thing to use: ++ */ ++ return find_task_by_pid_ns(tid, &init_pid_ns); ++} ++ ++/* ++ * CPU debug state control: ++ */ ++ ++#ifdef CONFIG_SMP ++static void kgdb_wait(struct pt_regs *regs) ++{ ++ unsigned long flags; ++ int cpu; ++ ++ local_irq_save(flags); ++ cpu = raw_smp_processor_id(); ++ kgdb_info[cpu].debuggerinfo = regs; ++ kgdb_info[cpu].task = current; ++ /* ++ * Make sure the above info reaches the primary CPU before ++ * our cpu_in_kgdb[] flag setting does: ++ */ ++ smp_wmb(); ++ atomic_set(&cpu_in_kgdb[cpu], 1); ++ ++ /* ++ * The primary CPU must be active to enter here, but this is ++ * guard in case the primary CPU had not been selected if ++ * this was an entry via nmi. ++ */ ++ while (atomic_read(&kgdb_active) == -1) ++ cpu_relax(); ++ ++ /* Wait till primary CPU goes completely into the debugger. */ ++ while (!atomic_read(&cpu_in_kgdb[atomic_read(&kgdb_active)])) ++ cpu_relax(); ++ ++ /* Wait till primary CPU is done with debugging */ ++ while (atomic_read(&passive_cpu_wait[cpu])) ++ cpu_relax(); ++ ++ kgdb_info[cpu].debuggerinfo = NULL; ++ kgdb_info[cpu].task = NULL; ++ ++ /* fix up hardware debug registers on local cpu */ ++ if (arch_kgdb_ops.correct_hw_break) ++ arch_kgdb_ops.correct_hw_break(); ++ ++ /* Signal the primary CPU that we are done: */ ++ atomic_set(&cpu_in_kgdb[cpu], 0); ++ local_irq_restore(flags); ++} ++#endif ++ ++/* ++ * Some architectures need cache flushes when we set/clear a ++ * breakpoint: ++ */ ++static void kgdb_flush_swbreak_addr(unsigned long addr) ++{ ++ if (!CACHE_FLUSH_IS_SAFE) ++ return; ++ ++ if (current->mm) { ++ flush_cache_range(current->mm->mmap_cache, ++ addr, addr + BREAK_INSTR_SIZE); ++ } else { ++ flush_icache_range(addr, addr + BREAK_INSTR_SIZE); ++ } ++} ++ ++/* ++ * SW breakpoint management: ++ */ ++static int kgdb_activate_sw_breakpoints(void) ++{ ++ unsigned long addr; ++ int error = 0; ++ int i; ++ ++ for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { ++ if (kgdb_break[i].state != BP_SET) ++ continue; ++ ++ addr = kgdb_break[i].bpt_addr; ++ error = kgdb_arch_set_breakpoint(addr, ++ kgdb_break[i].saved_instr); ++ if (error) ++ return error; ++ ++ kgdb_flush_swbreak_addr(addr); ++ kgdb_break[i].state = BP_ACTIVE; ++ } ++ return 0; ++} ++ ++static int kgdb_set_sw_break(unsigned long addr) ++{ ++ int err = kgdb_validate_break_address(addr); ++ int breakno = -1; ++ int i; ++ ++ if (err) ++ return err; ++ ++ for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { ++ if ((kgdb_break[i].state == BP_SET) && ++ (kgdb_break[i].bpt_addr == addr)) ++ return -EEXIST; ++ } ++ for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { ++ if (kgdb_break[i].state == BP_REMOVED && ++ kgdb_break[i].bpt_addr == addr) { ++ breakno = i; ++ break; ++ } ++ } ++ ++ if (breakno == -1) { ++ for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { ++ if (kgdb_break[i].state == BP_UNDEFINED) { ++ breakno = i; ++ break; ++ } ++ } ++ } ++ ++ if (breakno == -1) ++ return -E2BIG; ++ ++ kgdb_break[breakno].state = BP_SET; ++ kgdb_break[breakno].type = BP_BREAKPOINT; ++ kgdb_break[breakno].bpt_addr = addr; ++ ++ return 0; ++} ++ ++static int kgdb_deactivate_sw_breakpoints(void) ++{ ++ unsigned long addr; ++ int error = 0; ++ int i; ++ ++ for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { ++ if (kgdb_break[i].state != BP_ACTIVE) ++ continue; ++ addr = kgdb_break[i].bpt_addr; ++ error = kgdb_arch_remove_breakpoint(addr, ++ kgdb_break[i].saved_instr); ++ if (error) ++ return error; ++ ++ kgdb_flush_swbreak_addr(addr); ++ kgdb_break[i].state = BP_SET; ++ } ++ return 0; ++} ++ ++static int kgdb_remove_sw_break(unsigned long addr) ++{ ++ int i; ++ ++ for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { ++ if ((kgdb_break[i].state == BP_SET) && ++ (kgdb_break[i].bpt_addr == addr)) { ++ kgdb_break[i].state = BP_REMOVED; ++ return 0; ++ } ++ } ++ return -ENOENT; ++} ++ ++int kgdb_isremovedbreak(unsigned long addr) ++{ ++ int i; ++ ++ for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { ++ if ((kgdb_break[i].state == BP_REMOVED) && ++ (kgdb_break[i].bpt_addr == addr)) ++ return 1; ++ } ++ return 0; ++} ++ ++int remove_all_break(void) ++{ ++ unsigned long addr; ++ int error; ++ int i; ++ ++ /* Clear memory breakpoints. */ ++ for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { ++ if (kgdb_break[i].state != BP_SET) ++ continue; ++ addr = kgdb_break[i].bpt_addr; ++ error = kgdb_arch_remove_breakpoint(addr, ++ kgdb_break[i].saved_instr); ++ if (error) ++ return error; ++ kgdb_break[i].state = BP_REMOVED; ++ } ++ ++ /* Clear hardware breakpoints. */ ++ if (arch_kgdb_ops.remove_all_hw_break) ++ arch_kgdb_ops.remove_all_hw_break(); ++ ++ return 0; ++} ++ ++/* ++ * Remap normal tasks to their real PID, idle tasks to -1 ... -NR_CPUs: ++ */ ++static inline int shadow_pid(int realpid) ++{ ++ if (realpid) ++ return realpid; ++ ++ return -1-raw_smp_processor_id(); ++} ++ ++static char gdbmsgbuf[BUFMAX + 1]; ++ ++static void kgdb_msg_write(const char *s, int len) ++{ ++ char *bufptr; ++ int wcount; ++ int i; ++ ++ /* 'O'utput */ ++ gdbmsgbuf[0] = 'O'; ++ ++ /* Fill and send buffers... */ ++ while (len > 0) { ++ bufptr = gdbmsgbuf + 1; ++ ++ /* Calculate how many this time */ ++ if ((len << 1) > (BUFMAX - 2)) ++ wcount = (BUFMAX - 2) >> 1; ++ else ++ wcount = len; ++ ++ /* Pack in hex chars */ ++ for (i = 0; i < wcount; i++) ++ bufptr = pack_hex_byte(bufptr, s[i]); ++ *bufptr = '\0'; ++ ++ /* Move up */ ++ s += wcount; ++ len -= wcount; ++ ++ /* Write packet */ ++ put_packet(gdbmsgbuf); ++ } ++} ++ ++/* ++ * Return true if there is a valid kgdb I/O module. Also if no ++ * debugger is attached a message can be printed to the console about ++ * waiting for the debugger to attach. ++ * ++ * The print_wait argument is only to be true when called from inside ++ * the core kgdb_handle_exception, because it will wait for the ++ * debugger to attach. ++ */ ++static int kgdb_io_ready(int print_wait) ++{ ++ if (!kgdb_io_ops) ++ return 0; ++ if (kgdb_connected) ++ return 1; ++ if (atomic_read(&kgdb_setting_breakpoint)) ++ return 1; ++ if (print_wait) ++ printk(KERN_CRIT "KGDB: Waiting for remote debugger\n"); ++ return 1; ++} ++ ++/* ++ * All the functions that start with gdb_cmd are the various ++ * operations to implement the handlers for the gdbserial protocol ++ * where KGDB is communicating with an external debugger ++ */ ++ ++/* Handle the '?' status packets */ ++static void gdb_cmd_status(struct kgdb_state *ks) ++{ ++ /* ++ * We know that this packet is only sent ++ * during initial connect. So to be safe, ++ * we clear out our breakpoints now in case ++ * GDB is reconnecting. ++ */ ++ remove_all_break(); ++ ++ remcom_out_buffer[0] = 'S'; ++ pack_hex_byte(&remcom_out_buffer[1], ks->signo); ++} ++ ++/* Handle the 'g' get registers request */ ++static void gdb_cmd_getregs(struct kgdb_state *ks) ++{ ++ struct task_struct *thread; ++ void *local_debuggerinfo; ++ int i; ++ ++ thread = kgdb_usethread; ++ if (!thread) { ++ thread = kgdb_info[ks->cpu].task; ++ local_debuggerinfo = kgdb_info[ks->cpu].debuggerinfo; ++ } else { ++ local_debuggerinfo = NULL; ++ for (i = 0; i < NR_CPUS; i++) { ++ /* ++ * Try to find the task on some other ++ * or possibly this node if we do not ++ * find the matching task then we try ++ * to approximate the results. ++ */ ++ if (thread == kgdb_info[i].task) ++ local_debuggerinfo = kgdb_info[i].debuggerinfo; ++ } ++ } ++ ++ /* ++ * All threads that don't have debuggerinfo should be ++ * in __schedule() sleeping, since all other CPUs ++ * are in kgdb_wait, and thus have debuggerinfo. ++ */ ++ if (local_debuggerinfo) { ++ pt_regs_to_gdb_regs(gdb_regs, local_debuggerinfo); ++ } else { ++ /* ++ * Pull stuff saved during switch_to; nothing ++ * else is accessible (or even particularly ++ * relevant). ++ * ++ * This should be enough for a stack trace. ++ */ ++ sleeping_thread_to_gdb_regs(gdb_regs, thread); ++ } ++ kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES); ++} ++ ++/* Handle the 'G' set registers request */ ++static void gdb_cmd_setregs(struct kgdb_state *ks) ++{ ++ kgdb_hex2mem(&remcom_in_buffer[1], (char *)gdb_regs, NUMREGBYTES); ++ ++ if (kgdb_usethread && kgdb_usethread != current) { ++ error_packet(remcom_out_buffer, -EINVAL); ++ } else { ++ gdb_regs_to_pt_regs(gdb_regs, ks->linux_regs); ++ strcpy(remcom_out_buffer, "OK"); ++ } ++} ++ ++/* Handle the 'm' memory read bytes */ ++static void gdb_cmd_memread(struct kgdb_state *ks) ++{ ++ char *ptr = &remcom_in_buffer[1]; ++ unsigned long length; ++ unsigned long addr; ++ int err; ++ ++ if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && ++ kgdb_hex2long(&ptr, &length) > 0) { ++ err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length); ++ if (err) ++ error_packet(remcom_out_buffer, err); ++ } else { ++ error_packet(remcom_out_buffer, -EINVAL); ++ } ++} ++ ++/* Handle the 'M' memory write bytes */ ++static void gdb_cmd_memwrite(struct kgdb_state *ks) ++{ ++ int err = write_mem_msg(0); ++ ++ if (err) ++ error_packet(remcom_out_buffer, err); ++ else ++ strcpy(remcom_out_buffer, "OK"); ++} ++ ++/* Handle the 'X' memory binary write bytes */ ++static void gdb_cmd_binwrite(struct kgdb_state *ks) ++{ ++ int err = write_mem_msg(1); ++ ++ if (err) ++ error_packet(remcom_out_buffer, err); ++ else ++ strcpy(remcom_out_buffer, "OK"); ++} ++ ++/* Handle the 'D' or 'k', detach or kill packets */ ++static void gdb_cmd_detachkill(struct kgdb_state *ks) ++{ ++ int error; ++ ++ /* The detach case */ ++ if (remcom_in_buffer[0] == 'D') { ++ error = remove_all_break(); ++ if (error < 0) { ++ error_packet(remcom_out_buffer, error); ++ } else { ++ strcpy(remcom_out_buffer, "OK"); ++ kgdb_connected = 0; ++ } ++ put_packet(remcom_out_buffer); ++ } else { ++ /* ++ * Assume the kill case, with no exit code checking, ++ * trying to force detach the debugger: ++ */ ++ remove_all_break(); ++ kgdb_connected = 0; ++ } ++} ++ ++/* Handle the 'R' reboot packets */ ++static int gdb_cmd_reboot(struct kgdb_state *ks) ++{ ++ /* For now, only honor R0 */ ++ if (strcmp(remcom_in_buffer, "R0") == 0) { ++ printk(KERN_CRIT "Executing emergency reboot\n"); ++ strcpy(remcom_out_buffer, "OK"); ++ put_packet(remcom_out_buffer); ++ ++ /* ++ * Execution should not return from ++ * machine_emergency_restart() ++ */ ++ machine_emergency_restart(); ++ kgdb_connected = 0; ++ ++ return 1; ++ } ++ return 0; ++} ++ ++/* Handle the 'q' query packets */ ++static void gdb_cmd_query(struct kgdb_state *ks) ++{ ++ struct task_struct *thread; ++ unsigned char thref[8]; ++ char *ptr; ++ int i; ++ ++ switch (remcom_in_buffer[1]) { ++ case 's': ++ case 'f': ++ if (memcmp(remcom_in_buffer + 2, "ThreadInfo", 10)) { ++ error_packet(remcom_out_buffer, -EINVAL); ++ break; ++ } ++ ++ if (remcom_in_buffer[1] == 'f') ++ ks->threadid = 1; ++ ++ remcom_out_buffer[0] = 'm'; ++ ptr = remcom_out_buffer + 1; ++ ++ for (i = 0; i < 17; ks->threadid++) { ++ thread = getthread(ks->linux_regs, ks->threadid); ++ if (thread) { ++ int_to_threadref(thref, ks->threadid); ++ pack_threadid(ptr, thref); ++ ptr += BUF_THREAD_ID_SIZE; ++ *(ptr++) = ','; ++ i++; ++ } ++ } ++ *(--ptr) = '\0'; ++ break; ++ ++ case 'C': ++ /* Current thread id */ ++ strcpy(remcom_out_buffer, "QC"); ++ ks->threadid = shadow_pid(current->pid); ++ int_to_threadref(thref, ks->threadid); ++ pack_threadid(remcom_out_buffer + 2, thref); ++ break; ++ case 'T': ++ if (memcmp(remcom_in_buffer + 1, "ThreadExtraInfo,", 16)) { ++ error_packet(remcom_out_buffer, -EINVAL); ++ break; ++ } ++ ks->threadid = 0; ++ ptr = remcom_in_buffer + 17; ++ kgdb_hex2long(&ptr, &ks->threadid); ++ if (!getthread(ks->linux_regs, ks->threadid)) { ++ error_packet(remcom_out_buffer, -EINVAL); ++ break; ++ } ++ if (ks->threadid > 0) { ++ kgdb_mem2hex(getthread(ks->linux_regs, ++ ks->threadid)->comm, ++ remcom_out_buffer, 16); ++ } else { ++ static char tmpstr[23 + BUF_THREAD_ID_SIZE]; ++ ++ sprintf(tmpstr, "Shadow task %d for pid 0", ++ (int)(-ks->threadid-1)); ++ kgdb_mem2hex(tmpstr, remcom_out_buffer, strlen(tmpstr)); ++ } ++ break; ++ } ++} ++ ++/* Handle the 'H' task query packets */ ++static void gdb_cmd_task(struct kgdb_state *ks) ++{ ++ struct task_struct *thread; ++ char *ptr; ++ ++ switch (remcom_in_buffer[1]) { ++ case 'g': ++ ptr = &remcom_in_buffer[2]; ++ kgdb_hex2long(&ptr, &ks->threadid); ++ thread = getthread(ks->linux_regs, ks->threadid); ++ if (!thread && ks->threadid > 0) { ++ error_packet(remcom_out_buffer, -EINVAL); ++ break; ++ } ++ kgdb_usethread = thread; ++ ks->kgdb_usethreadid = ks->threadid; ++ strcpy(remcom_out_buffer, "OK"); ++ break; ++ case 'c': ++ ptr = &remcom_in_buffer[2]; ++ kgdb_hex2long(&ptr, &ks->threadid); ++ if (!ks->threadid) { ++ kgdb_contthread = NULL; ++ } else { ++ thread = getthread(ks->linux_regs, ks->threadid); ++ if (!thread && ks->threadid > 0) { ++ error_packet(remcom_out_buffer, -EINVAL); ++ break; ++ } ++ kgdb_contthread = thread; ++ } ++ strcpy(remcom_out_buffer, "OK"); ++ break; ++ } ++} ++ ++/* Handle the 'T' thread query packets */ ++static void gdb_cmd_thread(struct kgdb_state *ks) ++{ ++ char *ptr = &remcom_in_buffer[1]; ++ struct task_struct *thread; ++ ++ kgdb_hex2long(&ptr, &ks->threadid); ++ thread = getthread(ks->linux_regs, ks->threadid); ++ if (thread) ++ strcpy(remcom_out_buffer, "OK"); ++ else ++ error_packet(remcom_out_buffer, -EINVAL); ++} ++ ++/* Handle the 'z' or 'Z' breakpoint remove or set packets */ ++static void gdb_cmd_break(struct kgdb_state *ks) ++{ ++ /* ++ * Since GDB-5.3, it's been drafted that '0' is a software ++ * breakpoint, '1' is a hardware breakpoint, so let's do that. ++ */ ++ char *bpt_type = &remcom_in_buffer[1]; ++ char *ptr = &remcom_in_buffer[2]; ++ unsigned long addr; ++ unsigned long length; ++ int error = 0; ++ ++ if (arch_kgdb_ops.set_hw_breakpoint && *bpt_type >= '1') { ++ /* Unsupported */ ++ if (*bpt_type > '4') ++ return; ++ } else { ++ if (*bpt_type != '0' && *bpt_type != '1') ++ /* Unsupported. */ ++ return; ++ } ++ ++ /* ++ * Test if this is a hardware breakpoint, and ++ * if we support it: ++ */ ++ if (*bpt_type == '1' && !(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT)) ++ /* Unsupported. */ ++ return; ++ ++ if (*(ptr++) != ',') { ++ error_packet(remcom_out_buffer, -EINVAL); ++ return; ++ } ++ if (!kgdb_hex2long(&ptr, &addr)) { ++ error_packet(remcom_out_buffer, -EINVAL); ++ return; ++ } ++ if (*(ptr++) != ',' || ++ !kgdb_hex2long(&ptr, &length)) { ++ error_packet(remcom_out_buffer, -EINVAL); ++ return; ++ } ++ ++ if (remcom_in_buffer[0] == 'Z' && *bpt_type == '0') ++ error = kgdb_set_sw_break(addr); ++ else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0') ++ error = kgdb_remove_sw_break(addr); ++ else if (remcom_in_buffer[0] == 'Z') ++ error = arch_kgdb_ops.set_hw_breakpoint(addr, ++ (int)length, *bpt_type); ++ else if (remcom_in_buffer[0] == 'z') ++ error = arch_kgdb_ops.remove_hw_breakpoint(addr, ++ (int) length, *bpt_type); ++ ++ if (error == 0) ++ strcpy(remcom_out_buffer, "OK"); ++ else ++ error_packet(remcom_out_buffer, error); ++} ++ ++/* Handle the 'C' signal / exception passing packets */ ++static int gdb_cmd_exception_pass(struct kgdb_state *ks) ++{ ++ /* C09 == pass exception ++ * C15 == detach kgdb, pass exception ++ */ ++ if (remcom_in_buffer[1] == '0' && remcom_in_buffer[2] == '9') { ++ ++ ks->pass_exception = 1; ++ remcom_in_buffer[0] = 'c'; ++ ++ } else if (remcom_in_buffer[1] == '1' && remcom_in_buffer[2] == '5') { ++ ++ ks->pass_exception = 1; ++ remcom_in_buffer[0] = 'D'; ++ remove_all_break(); ++ kgdb_connected = 0; ++ return 1; ++ ++ } else { ++ error_packet(remcom_out_buffer, -EINVAL); ++ return 0; ++ } ++ ++ /* Indicate fall through */ ++ return -1; ++} ++ ++/* ++ * This function performs all gdbserial command procesing ++ */ ++static int gdb_serial_stub(struct kgdb_state *ks) ++{ ++ int error = 0; ++ int tmp; ++ ++ /* Clear the out buffer. */ ++ memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); ++ ++ if (kgdb_connected) { ++ unsigned char thref[8]; ++ char *ptr; ++ ++ /* Reply to host that an exception has occurred */ ++ ptr = remcom_out_buffer; ++ *ptr++ = 'T'; ++ ptr = pack_hex_byte(ptr, ks->signo); ++ ptr += strlen(strcpy(ptr, "thread:")); ++ int_to_threadref(thref, shadow_pid(current->pid)); ++ ptr = pack_threadid(ptr, thref); ++ *ptr++ = ';'; ++ put_packet(remcom_out_buffer); ++ } ++ ++ kgdb_usethread = kgdb_info[ks->cpu].task; ++ ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid); ++ ks->pass_exception = 0; ++ ++ while (1) { ++ error = 0; ++ ++ /* Clear the out buffer. */ ++ memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); ++ ++ get_packet(remcom_in_buffer); ++ ++ switch (remcom_in_buffer[0]) { ++ case '?': /* gdbserial status */ ++ gdb_cmd_status(ks); ++ break; ++ case 'g': /* return the value of the CPU registers */ ++ gdb_cmd_getregs(ks); ++ break; ++ case 'G': /* set the value of the CPU registers - return OK */ ++ gdb_cmd_setregs(ks); ++ break; ++ case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ ++ gdb_cmd_memread(ks); ++ break; ++ case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */ ++ gdb_cmd_memwrite(ks); ++ break; ++ case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */ ++ gdb_cmd_binwrite(ks); ++ break; ++ /* kill or detach. KGDB should treat this like a ++ * continue. ++ */ ++ case 'D': /* Debugger detach */ ++ case 'k': /* Debugger detach via kill */ ++ gdb_cmd_detachkill(ks); ++ goto default_handle; ++ case 'R': /* Reboot */ ++ if (gdb_cmd_reboot(ks)) ++ goto default_handle; ++ break; ++ case 'q': /* query command */ ++ gdb_cmd_query(ks); ++ break; ++ case 'H': /* task related */ ++ gdb_cmd_task(ks); ++ break; ++ case 'T': /* Query thread status */ ++ gdb_cmd_thread(ks); ++ break; ++ case 'z': /* Break point remove */ ++ case 'Z': /* Break point set */ ++ gdb_cmd_break(ks); ++ break; ++ case 'C': /* Exception passing */ ++ tmp = gdb_cmd_exception_pass(ks); ++ if (tmp > 0) ++ goto default_handle; ++ if (tmp == 0) ++ break; ++ /* Fall through on tmp < 0 */ ++ case 'c': /* Continue packet */ ++ case 's': /* Single step packet */ ++ if (kgdb_contthread && kgdb_contthread != current) { ++ /* Can't switch threads in kgdb */ ++ error_packet(remcom_out_buffer, -EINVAL); ++ break; ++ } ++ kgdb_activate_sw_breakpoints(); ++ /* Fall through to default processing */ ++ default: ++default_handle: ++ error = kgdb_arch_handle_exception(ks->ex_vector, ++ ks->signo, ++ ks->err_code, ++ remcom_in_buffer, ++ remcom_out_buffer, ++ ks->linux_regs); ++ /* ++ * Leave cmd processing on error, detach, ++ * kill, continue, or single step. ++ */ ++ if (error >= 0 || remcom_in_buffer[0] == 'D' || ++ remcom_in_buffer[0] == 'k') { ++ error = 0; ++ goto kgdb_exit; ++ } ++ ++ } ++ ++ /* reply to the request */ ++ put_packet(remcom_out_buffer); ++ } ++ ++kgdb_exit: ++ if (ks->pass_exception) ++ error = 1; ++ return error; ++} ++ ++static int kgdb_reenter_check(struct kgdb_state *ks) ++{ ++ unsigned long addr; ++ ++ if (atomic_read(&kgdb_active) != raw_smp_processor_id()) ++ return 0; ++ ++ /* Panic on recursive debugger calls: */ ++ exception_level++; ++ addr = kgdb_arch_pc(ks->ex_vector, ks->linux_regs); ++ kgdb_deactivate_sw_breakpoints(); ++ ++ /* ++ * If the break point removed ok at the place exception ++ * occurred, try to recover and print a warning to the end ++ * user because the user planted a breakpoint in a place that ++ * KGDB needs in order to function. ++ */ ++ if (kgdb_remove_sw_break(addr) == 0) { ++ exception_level = 0; ++ kgdb_skipexception(ks->ex_vector, ks->linux_regs); ++ kgdb_activate_sw_breakpoints(); ++ printk(KERN_CRIT "KGDB: re-enter error: breakpoint removed\n"); ++ WARN_ON_ONCE(1); ++ ++ return 1; ++ } ++ remove_all_break(); ++ kgdb_skipexception(ks->ex_vector, ks->linux_regs); ++ ++ if (exception_level > 1) { ++ dump_stack(); ++ panic("Recursive entry to debugger"); ++ } ++ ++ printk(KERN_CRIT "KGDB: re-enter exception: ALL breakpoints killed\n"); ++ dump_stack(); ++ panic("Recursive entry to debugger"); ++ ++ return 1; ++} ++ ++/* ++ * kgdb_handle_exception() - main entry point from a kernel exception ++ * ++ * Locking hierarchy: ++ * interface locks, if any (begin_session) ++ * kgdb lock (kgdb_active) ++ */ ++int ++kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) ++{ ++ struct kgdb_state kgdb_var; ++ struct kgdb_state *ks = &kgdb_var; ++ unsigned long flags; ++ int error = 0; ++ int i, cpu; ++ ++ ks->cpu = raw_smp_processor_id(); ++ ks->ex_vector = evector; ++ ks->signo = signo; ++ ks->ex_vector = evector; ++ ks->err_code = ecode; ++ ks->kgdb_usethreadid = 0; ++ ks->linux_regs = regs; ++ ++ if (kgdb_reenter_check(ks)) ++ return 0; /* Ouch, double exception ! */ ++ ++acquirelock: ++ /* ++ * Interrupts will be restored by the 'trap return' code, except when ++ * single stepping. ++ */ ++ local_irq_save(flags); ++ ++ cpu = raw_smp_processor_id(); ++ ++ /* ++ * Acquire the kgdb_active lock: ++ */ ++ while (atomic_cmpxchg(&kgdb_active, -1, cpu) != -1) ++ cpu_relax(); ++ ++ /* ++ * Do not start the debugger connection on this CPU if the last ++ * instance of the exception handler wanted to come into the ++ * debugger on a different CPU via a single step ++ */ ++ if (atomic_read(&kgdb_cpu_doing_single_step) != -1 && ++ atomic_read(&kgdb_cpu_doing_single_step) != cpu) { ++ ++ atomic_set(&kgdb_active, -1); ++ local_irq_restore(flags); ++ ++ goto acquirelock; ++ } ++ ++ if (!kgdb_io_ready(1)) { ++ error = 1; ++ goto kgdb_restore; /* No I/O connection, so resume the system */ ++ } ++ ++ /* ++ * Don't enter if we have hit a removed breakpoint. ++ */ ++ if (kgdb_skipexception(ks->ex_vector, ks->linux_regs)) ++ goto kgdb_restore; ++ ++ /* Call the I/O driver's pre_exception routine */ ++ if (kgdb_io_ops->pre_exception) ++ kgdb_io_ops->pre_exception(); ++ ++ kgdb_info[ks->cpu].debuggerinfo = ks->linux_regs; ++ kgdb_info[ks->cpu].task = current; ++ ++ kgdb_disable_hw_debug(ks->linux_regs); ++ ++ /* ++ * Get the passive CPU lock which will hold all the non-primary ++ * CPU in a spin state while the debugger is active ++ */ ++ if (!kgdb_single_step || !kgdb_contthread) { ++ for (i = 0; i < NR_CPUS; i++) ++ atomic_set(&passive_cpu_wait[i], 1); ++ } ++ ++#ifdef CONFIG_SMP ++ /* Signal the other CPUs to enter kgdb_wait() */ ++ if ((!kgdb_single_step || !kgdb_contthread) && kgdb_do_roundup) ++ kgdb_roundup_cpus(flags); ++#endif ++ ++ /* ++ * spin_lock code is good enough as a barrier so we don't ++ * need one here: ++ */ ++ atomic_set(&cpu_in_kgdb[ks->cpu], 1); ++ ++ /* ++ * Wait for the other CPUs to be notified and be waiting for us: ++ */ ++ for_each_online_cpu(i) { ++ while (!atomic_read(&cpu_in_kgdb[i])) ++ cpu_relax(); ++ } ++ ++ /* ++ * At this point the primary processor is completely ++ * in the debugger and all secondary CPUs are quiescent ++ */ ++ kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code); ++ kgdb_deactivate_sw_breakpoints(); ++ kgdb_single_step = 0; ++ kgdb_contthread = NULL; ++ exception_level = 0; ++ ++ /* Talk to debugger with gdbserial protocol */ ++ error = gdb_serial_stub(ks); ++ ++ /* Call the I/O driver's post_exception routine */ ++ if (kgdb_io_ops->post_exception) ++ kgdb_io_ops->post_exception(); ++ ++ kgdb_info[ks->cpu].debuggerinfo = NULL; ++ kgdb_info[ks->cpu].task = NULL; ++ atomic_set(&cpu_in_kgdb[ks->cpu], 0); ++ ++ if (!kgdb_single_step || !kgdb_contthread) { ++ for (i = NR_CPUS-1; i >= 0; i--) ++ atomic_set(&passive_cpu_wait[i], 0); ++ /* ++ * Wait till all the CPUs have quit ++ * from the debugger. ++ */ ++ for_each_online_cpu(i) { ++ while (atomic_read(&cpu_in_kgdb[i])) ++ cpu_relax(); ++ } ++ } ++ ++kgdb_restore: ++ /* Free kgdb_active */ ++ atomic_set(&kgdb_active, -1); ++ local_irq_restore(flags); ++ ++ return error; ++} ++ ++int kgdb_nmicallback(int cpu, void *regs) ++{ ++#ifdef CONFIG_SMP ++ if (!atomic_read(&cpu_in_kgdb[cpu]) && ++ atomic_read(&kgdb_active) != cpu) { ++ kgdb_wait((struct pt_regs *)regs); ++ return 0; ++ } ++#endif ++ return 1; ++} ++ ++void kgdb_console_write(struct console *co, const char *s, unsigned count) ++{ ++ unsigned long flags; ++ ++ /* If we're debugging, or KGDB has not connected, don't try ++ * and print. */ ++ if (!kgdb_connected || atomic_read(&kgdb_active) != -1) ++ return; ++ ++ local_irq_save(flags); ++ kgdb_msg_write(s, count); ++ local_irq_restore(flags); ++} ++ ++static struct console kgdbcons = { ++ .name = "kgdb", ++ .write = kgdb_console_write, ++ .flags = CON_PRINTBUFFER | CON_ENABLED, ++ .index = -1, ++}; ++ ++#ifdef CONFIG_MAGIC_SYSRQ ++static void sysrq_handle_gdb(int key, struct tty_struct *tty) ++{ ++ if (!kgdb_io_ops) { ++ printk(KERN_CRIT "ERROR: No KGDB I/O module available\n"); ++ return; ++ } ++ if (!kgdb_connected) ++ printk(KERN_CRIT "Entering KGDB\n"); ++ ++ kgdb_breakpoint(); ++} ++ ++static struct sysrq_key_op sysrq_gdb_op = { ++ .handler = sysrq_handle_gdb, ++ .help_msg = "Gdb", ++ .action_msg = "GDB", ++}; ++#endif ++ ++static void kgdb_register_callbacks(void) ++{ ++ if (!kgdb_io_module_registered) { ++ kgdb_io_module_registered = 1; ++ kgdb_arch_init(); ++#ifdef CONFIG_MAGIC_SYSRQ ++ register_sysrq_key('g', &sysrq_gdb_op); ++#endif ++ if (kgdb_use_con && !kgdb_con_registered) { ++ register_console(&kgdbcons); ++ kgdb_con_registered = 1; ++ } ++ } ++} ++ ++static void kgdb_unregister_callbacks(void) ++{ ++ /* ++ * When this routine is called KGDB should unregister from the ++ * panic handler and clean up, making sure it is not handling any ++ * break exceptions at the time. ++ */ ++ if (kgdb_io_module_registered) { ++ kgdb_io_module_registered = 0; ++ kgdb_arch_exit(); ++#ifdef CONFIG_MAGIC_SYSRQ ++ unregister_sysrq_key('g', &sysrq_gdb_op); ++#endif ++ if (kgdb_con_registered) { ++ unregister_console(&kgdbcons); ++ kgdb_con_registered = 0; ++ } ++ } ++} ++ ++static void kgdb_initial_breakpoint(void) ++{ ++ kgdb_break_asap = 0; ++ ++ printk(KERN_CRIT "kgdb: Waiting for connection from remote gdb...\n"); ++ kgdb_breakpoint(); ++} ++ ++/** ++ * kkgdb_register_io_module - register KGDB IO module ++ * @new_kgdb_io_ops: the io ops vector ++ * ++ * Register it with the KGDB core. ++ */ ++int kgdb_register_io_module(struct kgdb_io *new_kgdb_io_ops) ++{ ++ int err; ++ ++ spin_lock(&kgdb_registration_lock); ++ ++ if (kgdb_io_ops) { ++ spin_unlock(&kgdb_registration_lock); ++ ++ printk(KERN_ERR "kgdb: Another I/O driver is already " ++ "registered with KGDB.\n"); ++ return -EBUSY; ++ } ++ ++ if (new_kgdb_io_ops->init) { ++ err = new_kgdb_io_ops->init(); ++ if (err) { ++ spin_unlock(&kgdb_registration_lock); ++ return err; ++ } ++ } ++ ++ kgdb_io_ops = new_kgdb_io_ops; ++ ++ spin_unlock(&kgdb_registration_lock); ++ ++ printk(KERN_INFO "kgdb: Registered I/O driver %s.\n", ++ new_kgdb_io_ops->name); ++ ++ /* Arm KGDB now. */ ++ kgdb_register_callbacks(); ++ ++ if (kgdb_break_asap) ++ kgdb_initial_breakpoint(); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(kgdb_register_io_module); ++ ++/** ++ * kkgdb_unregister_io_module - unregister KGDB IO module ++ * @old_kgdb_io_ops: the io ops vector ++ * ++ * Unregister it with the KGDB core. ++ */ ++void kgdb_unregister_io_module(struct kgdb_io *old_kgdb_io_ops) ++{ ++ BUG_ON(kgdb_connected); ++ ++ /* ++ * KGDB is no longer able to communicate out, so ++ * unregister our callbacks and reset state. ++ */ ++ kgdb_unregister_callbacks(); ++ ++ spin_lock(&kgdb_registration_lock); ++ ++ WARN_ON_ONCE(kgdb_io_ops != old_kgdb_io_ops); ++ kgdb_io_ops = NULL; ++ ++ spin_unlock(&kgdb_registration_lock); ++ ++ printk(KERN_INFO ++ "kgdb: Unregistered I/O driver %s, debugger disabled.\n", ++ old_kgdb_io_ops->name); ++} ++EXPORT_SYMBOL_GPL(kgdb_unregister_io_module); ++ ++/** ++ * kgdb_breakpoint - generate breakpoint exception ++ * ++ * This function will generate a breakpoint exception. It is used at the ++ * beginning of a program to sync up with a debugger and can be used ++ * otherwise as a quick means to stop program execution and "break" into ++ * the debugger. ++ */ ++void kgdb_breakpoint(void) ++{ ++ atomic_set(&kgdb_setting_breakpoint, 1); ++ wmb(); /* Sync point before breakpoint */ ++ arch_kgdb_breakpoint(); ++ wmb(); /* Sync point after breakpoint */ ++ atomic_set(&kgdb_setting_breakpoint, 0); ++} ++EXPORT_SYMBOL_GPL(kgdb_breakpoint); ++ ++static int __init opt_kgdb_wait(char *str) ++{ ++ kgdb_break_asap = 1; ++ ++ if (kgdb_io_module_registered) ++ kgdb_initial_breakpoint(); ++ ++ return 0; ++} ++ ++early_param("kgdbwait", opt_kgdb_wait); +diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug +index 01872e2..be69239 100644 +--- a/lib/Kconfig.debug ++++ b/lib/Kconfig.debug +@@ -530,3 +530,5 @@ config LATENCYTOP + + + source "samples/Kconfig" ++ ++source "lib/Kconfig.kgdb" +diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb +new file mode 100644 +index 0000000..9631ba3 +--- /dev/null ++++ b/lib/Kconfig.kgdb +@@ -0,0 +1,27 @@ ++ ++menuconfig KGDB ++ bool "KGDB: kernel debugging with remote gdb" ++ select FRAME_POINTER ++ depends on HAVE_ARCH_KGDB ++ depends on DEBUG_KERNEL && EXPERIMENTAL ++ help ++ If you say Y here, it will be possible to remotely debug the ++ kernel using gdb. Documentation of kernel debugger is available ++ at http://kgdb.sourceforge.net as well as in DocBook form ++ in Documentation/DocBook/. If unsure, say N. ++ ++config HAVE_ARCH_KGDB_SHADOW_INFO ++ bool ++ ++config HAVE_ARCH_KGDB ++ bool ++ ++config KGDB_SERIAL_CONSOLE ++ tristate "KGDB: use kgdb over the serial console" ++ depends on KGDB ++ select CONSOLE_POLL ++ select MAGIC_SYSRQ ++ default y ++ help ++ Share a serial console with kgdb. Sysrq-g must be used ++ to break in initially. +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0133-UBUNTU-SAUCE-hardy-netbook-lpia-Expose-EEPROM-antenn.patch +++ linux-2.6.24/patches/0133-UBUNTU-SAUCE-hardy-netbook-lpia-Expose-EEPROM-antenn.patch @@ -0,0 +1,40 @@ +From 2e083267ff13b54014551201aea6ab9d619a7253 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Mon, 6 Apr 2009 15:20:59 -0500 +Subject: [PATCH 133/170] UBUNTU: SAUCE: hardy netbook-lpia - Expose EEPROM antenna configuration data + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/352439 + +OriginalAuthor: Steve Magoun +Signed-off-by: Steve Conklin +--- + drivers/net/wireless/rt2x00/rt73usb.c | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c +index b9d5310..aa73dbf 100644 +--- a/drivers/net/wireless/rt2x00/rt73usb.c ++++ b/drivers/net/wireless/rt2x00/rt73usb.c +@@ -1515,6 +1515,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) + u32 reg; + u16 value; + u16 eeprom; ++ int num_antennas; + + /* + * Read EEPROM word for configuration. +@@ -1549,6 +1550,11 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) + rt2x00dev->default_ant.rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + ++ num_antennas = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM); ++ INFO(rt2x00dev, "Number of antennas: %d\n", num_antennas); ++ INFO(rt2x00dev, "Tx default antenna control: 0x%x\n", rt2x00dev->default_ant.tx); ++ INFO(rt2x00dev, "Rx default antenna control: 0x%x\n", rt2x00dev->default_ant.rx); ++ + /* + * Read the Frame type. + */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0109-UBUNTU-add-support-for-MaxLinear-MxL5007T-silicon-tu.patch +++ linux-2.6.24/patches/0109-UBUNTU-add-support-for-MaxLinear-MxL5007T-silicon-tu.patch @@ -0,0 +1,1250 @@ +From ca0aef0033fc7da34a2e51300e5d6e16953ba5c1 Mon Sep 17 00:00:00 2001 +From: Michael Krufky +Date: Tue, 24 Mar 2009 23:38:46 -0400 +Subject: [PATCH 109/170] UBUNTU: add support for MaxLinear MxL5007T silicon tuner + +OriginalAuthor: Michael Krufky +OriginalLocation: http://linuxtv.org/hg/v4l-dvb/rev/15fb29843b6d + +add support for MaxLinear MxL5007T silicon tuner + +Signed-off-by: Michael Krufky +Signed-off-by: Asaf Fishov +Signed-off-by: Charles Kim +--- + drivers/media/dvb/frontends/Kconfig | 7 + + drivers/media/dvb/frontends/Makefile | 1 + + drivers/media/dvb/frontends/mxl5007t.c | 893 +++++++++++++++++++++++++++++++ + drivers/media/dvb/frontends/mxl5007t.h | 104 ++++ + drivers/media/dvb/frontends/tuner-i2c.h | 181 +++++++ + 5 files changed, 1186 insertions(+), 0 deletions(-) + create mode 100644 drivers/media/dvb/frontends/mxl5007t.c + create mode 100644 drivers/media/dvb/frontends/mxl5007t.h + create mode 100644 drivers/media/dvb/frontends/tuner-i2c.h + +diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig +index aea62aa..dd45acb 100644 +--- a/drivers/media/dvb/frontends/Kconfig ++++ b/drivers/media/dvb/frontends/Kconfig +@@ -361,6 +361,13 @@ config DVB_TUNER_DIB0070 + This device is only used inside a SiP called togther with a + demodulator for now. + ++config DVB_TUNER_MXL5007T ++ tristate "MaxLinear MxL5007T silicon tuner" ++ depends on DVB_CORE && I2C ++ default m if DVB_FE_CUSTOMISE ++ help ++ A driver for the MaxLinear MxL5007T silicon tuner. ++ + comment "Miscellaneous devices" + depends on DVB_CORE + +diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile +index 80a073a..8ff3795 100644 +--- a/drivers/media/dvb/frontends/Makefile ++++ b/drivers/media/dvb/frontends/Makefile +@@ -47,3 +47,4 @@ obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o + obj-$(CONFIG_DVB_TUA6100) += tua6100.o + obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o + obj-$(CONFIG_DVB_S5H1409) += s5h1409.o ++obj-$(CONFIG_DVB_TUNER_MXL5007T) += mxl5007t.o +diff --git a/drivers/media/dvb/frontends/mxl5007t.c b/drivers/media/dvb/frontends/mxl5007t.c +new file mode 100644 +index 0000000..faf080a +--- /dev/null ++++ b/drivers/media/dvb/frontends/mxl5007t.c +@@ -0,0 +1,893 @@ ++/* ++ * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner ++ * ++ * Copyright (C) 2008, 2009 Michael Krufky ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include "tuner-i2c.h" ++#include "mxl5007t.h" ++ ++static DEFINE_MUTEX(mxl5007t_list_mutex); ++static LIST_HEAD(hybrid_tuner_instance_list); ++ ++static int mxl5007t_debug; ++module_param_named(debug, mxl5007t_debug, int, 0644); ++MODULE_PARM_DESC(debug, "set debug level"); ++ ++/* ------------------------------------------------------------------------- */ ++ ++#define mxl_printk(kern, fmt, arg...) \ ++ printk(kern "%s: " fmt "\n", __func__, ##arg) ++ ++#define mxl_err(fmt, arg...) \ ++ mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg) ++ ++#define mxl_warn(fmt, arg...) \ ++ mxl_printk(KERN_WARNING, fmt, ##arg) ++ ++#define mxl_info(fmt, arg...) \ ++ mxl_printk(KERN_INFO, fmt, ##arg) ++ ++#define mxl_debug(fmt, arg...) \ ++({ \ ++ if (mxl5007t_debug) \ ++ mxl_printk(KERN_DEBUG, fmt, ##arg); \ ++}) ++ ++#define mxl_fail(ret) \ ++({ \ ++ int __ret; \ ++ __ret = (ret < 0); \ ++ if (__ret) \ ++ mxl_printk(KERN_ERR, "error %d on line %d", \ ++ ret, __LINE__); \ ++ __ret; \ ++}) ++ ++/* ------------------------------------------------------------------------- */ ++ ++#define MHz 1000000 ++ ++enum mxl5007t_mode { ++ MxL_MODE_ISDBT = 0, ++ MxL_MODE_DVBT = 1, ++ MxL_MODE_ATSC = 2, ++ MxL_MODE_CABLE = 0x10, ++}; ++ ++enum mxl5007t_chip_version { ++ MxL_UNKNOWN_ID = 0x00, ++ MxL_5007_V1_F1 = 0x11, ++ MxL_5007_V1_F2 = 0x12, ++ MxL_5007_V4 = 0x14, ++ MxL_5007_V2_100_F1 = 0x21, ++ MxL_5007_V2_100_F2 = 0x22, ++ MxL_5007_V2_200_F1 = 0x23, ++ MxL_5007_V2_200_F2 = 0x24, ++}; ++ ++struct reg_pair_t { ++ u8 reg; ++ u8 val; ++}; ++ ++/* ------------------------------------------------------------------------- */ ++ ++static struct reg_pair_t init_tab[] = { ++ { 0x02, 0x06 }, ++ { 0x03, 0x48 }, ++ { 0x05, 0x04 }, ++ { 0x06, 0x10 }, ++ { 0x2e, 0x15 }, /* OVERRIDE */ ++ { 0x30, 0x10 }, /* OVERRIDE */ ++ { 0x45, 0x58 }, /* OVERRIDE */ ++ { 0x48, 0x19 }, /* OVERRIDE */ ++ { 0x52, 0x03 }, /* OVERRIDE */ ++ { 0x53, 0x44 }, /* OVERRIDE */ ++ { 0x6a, 0x4b }, /* OVERRIDE */ ++ { 0x76, 0x00 }, /* OVERRIDE */ ++ { 0x78, 0x18 }, /* OVERRIDE */ ++ { 0x7a, 0x17 }, /* OVERRIDE */ ++ { 0x85, 0x06 }, /* OVERRIDE */ ++ { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ ++ { 0, 0 } ++}; ++ ++static struct reg_pair_t init_tab_cable[] = { ++ { 0x02, 0x06 }, ++ { 0x03, 0x48 }, ++ { 0x05, 0x04 }, ++ { 0x06, 0x10 }, ++ { 0x09, 0x3f }, ++ { 0x0a, 0x3f }, ++ { 0x0b, 0x3f }, ++ { 0x2e, 0x15 }, /* OVERRIDE */ ++ { 0x30, 0x10 }, /* OVERRIDE */ ++ { 0x45, 0x58 }, /* OVERRIDE */ ++ { 0x48, 0x19 }, /* OVERRIDE */ ++ { 0x52, 0x03 }, /* OVERRIDE */ ++ { 0x53, 0x44 }, /* OVERRIDE */ ++ { 0x6a, 0x4b }, /* OVERRIDE */ ++ { 0x76, 0x00 }, /* OVERRIDE */ ++ { 0x78, 0x18 }, /* OVERRIDE */ ++ { 0x7a, 0x17 }, /* OVERRIDE */ ++ { 0x85, 0x06 }, /* OVERRIDE */ ++ { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ ++ { 0, 0 } ++}; ++ ++/* ------------------------------------------------------------------------- */ ++ ++static struct reg_pair_t reg_pair_rftune[] = { ++ { 0x0f, 0x00 }, /* abort tune */ ++ { 0x0c, 0x15 }, ++ { 0x0d, 0x40 }, ++ { 0x0e, 0x0e }, ++ { 0x1f, 0x87 }, /* OVERRIDE */ ++ { 0x20, 0x1f }, /* OVERRIDE */ ++ { 0x21, 0x87 }, /* OVERRIDE */ ++ { 0x22, 0x1f }, /* OVERRIDE */ ++ { 0x80, 0x01 }, /* freq dependent */ ++ { 0x0f, 0x01 }, /* start tune */ ++ { 0, 0 } ++}; ++ ++/* ------------------------------------------------------------------------- */ ++ ++struct mxl5007t_state { ++ struct list_head hybrid_tuner_instance_list; ++ struct tuner_i2c_props i2c_props; ++ ++ struct mutex lock; ++ ++ struct mxl5007t_config *config; ++ ++ enum mxl5007t_chip_version chip_id; ++ ++ struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)]; ++ struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; ++ struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; ++ ++ u32 frequency; ++ u32 bandwidth; ++}; ++ ++/* ------------------------------------------------------------------------- */ ++ ++/* called by _init and _rftun to manipulate the register arrays */ ++ ++static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val) ++{ ++ unsigned int i = 0; ++ ++ while (reg_pair[i].reg || reg_pair[i].val) { ++ if (reg_pair[i].reg == reg) { ++ reg_pair[i].val &= ~mask; ++ reg_pair[i].val |= val; ++ } ++ i++; ++ ++ } ++ return; ++} ++ ++static void copy_reg_bits(struct reg_pair_t *reg_pair1, ++ struct reg_pair_t *reg_pair2) ++{ ++ unsigned int i, j; ++ ++ i = j = 0; ++ ++ while (reg_pair1[i].reg || reg_pair1[i].val) { ++ while (reg_pair2[j].reg || reg_pair2[j].reg) { ++ if (reg_pair1[i].reg != reg_pair2[j].reg) { ++ j++; ++ continue; ++ } ++ reg_pair2[j].val = reg_pair1[i].val; ++ break; ++ } ++ i++; ++ } ++ return; ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++static void mxl5007t_set_mode_bits(struct mxl5007t_state *state, ++ enum mxl5007t_mode mode, ++ s32 if_diff_out_level) ++{ ++ switch (mode) { ++ case MxL_MODE_ATSC: ++ set_reg_bits(state->tab_init, 0x06, 0x1f, 0x12); ++ break; ++ case MxL_MODE_DVBT: ++ set_reg_bits(state->tab_init, 0x06, 0x1f, 0x11); ++ break; ++ case MxL_MODE_ISDBT: ++ set_reg_bits(state->tab_init, 0x06, 0x1f, 0x10); ++ break; ++ case MxL_MODE_CABLE: ++ set_reg_bits(state->tab_init_cable, 0x09, 0xff, 0xc1); ++ set_reg_bits(state->tab_init_cable, 0x0a, 0xff, ++ 8 - if_diff_out_level); ++ set_reg_bits(state->tab_init_cable, 0x0b, 0xff, 0x17); ++ break; ++ default: ++ mxl_fail(-EINVAL); ++ } ++ return; ++} ++ ++static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, ++ enum mxl5007t_if_freq if_freq, ++ int invert_if) ++{ ++ u8 val; ++ ++ switch (if_freq) { ++ case MxL_IF_4_MHZ: ++ val = 0x00; ++ break; ++ case MxL_IF_4_5_MHZ: ++ val = 0x02; ++ break; ++ case MxL_IF_4_57_MHZ: ++ val = 0x03; ++ break; ++ case MxL_IF_5_MHZ: ++ val = 0x04; ++ break; ++ case MxL_IF_5_38_MHZ: ++ val = 0x05; ++ break; ++ case MxL_IF_6_MHZ: ++ val = 0x06; ++ break; ++ case MxL_IF_6_28_MHZ: ++ val = 0x07; ++ break; ++ case MxL_IF_9_1915_MHZ: ++ val = 0x08; ++ break; ++ case MxL_IF_35_25_MHZ: ++ val = 0x09; ++ break; ++ case MxL_IF_36_15_MHZ: ++ val = 0x0a; ++ break; ++ case MxL_IF_44_MHZ: ++ val = 0x0b; ++ break; ++ default: ++ mxl_fail(-EINVAL); ++ return; ++ } ++ set_reg_bits(state->tab_init, 0x02, 0x0f, val); ++ ++ /* set inverted IF or normal IF */ ++ set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00); ++ ++ return; ++} ++ ++static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, ++ enum mxl5007t_xtal_freq xtal_freq) ++{ ++ switch (xtal_freq) { ++ case MxL_XTAL_16_MHZ: ++ /* select xtal freq & ref freq */ ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x00); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x00); ++ break; ++ case MxL_XTAL_20_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x10); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x01); ++ break; ++ case MxL_XTAL_20_25_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x20); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x02); ++ break; ++ case MxL_XTAL_20_48_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x30); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x03); ++ break; ++ case MxL_XTAL_24_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x40); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x04); ++ break; ++ case MxL_XTAL_25_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x50); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x05); ++ break; ++ case MxL_XTAL_25_14_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x60); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x06); ++ break; ++ case MxL_XTAL_27_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x70); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x07); ++ break; ++ case MxL_XTAL_28_8_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x80); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x08); ++ break; ++ case MxL_XTAL_32_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x90); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x09); ++ break; ++ case MxL_XTAL_40_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0xa0); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0a); ++ break; ++ case MxL_XTAL_44_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0xb0); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0b); ++ break; ++ case MxL_XTAL_48_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0xc0); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0c); ++ break; ++ case MxL_XTAL_49_3811_MHZ: ++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0xd0); ++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0d); ++ break; ++ default: ++ mxl_fail(-EINVAL); ++ return; ++ } ++ ++ return; ++} ++ ++static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, ++ enum mxl5007t_mode mode) ++{ ++ struct mxl5007t_config *cfg = state->config; ++ ++ memcpy(&state->tab_init, &init_tab, sizeof(init_tab)); ++ memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable)); ++ ++ mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level); ++ mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if); ++ mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz); ++ ++ set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable); ++ set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3); ++ set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp); ++ ++ if (mode >= MxL_MODE_CABLE) { ++ copy_reg_bits(state->tab_init, state->tab_init_cable); ++ return state->tab_init_cable; ++ } else ++ return state->tab_init; ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++enum mxl5007t_bw_mhz { ++ MxL_BW_6MHz = 6, ++ MxL_BW_7MHz = 7, ++ MxL_BW_8MHz = 8, ++}; ++ ++static void mxl5007t_set_bw_bits(struct mxl5007t_state *state, ++ enum mxl5007t_bw_mhz bw) ++{ ++ u8 val; ++ ++ switch (bw) { ++ case MxL_BW_6MHz: ++ val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A, ++ * and DIG_MODEINDEX_CSF */ ++ break; ++ case MxL_BW_7MHz: ++ val = 0x2a; ++ break; ++ case MxL_BW_8MHz: ++ val = 0x3f; ++ break; ++ default: ++ mxl_fail(-EINVAL); ++ return; ++ } ++ set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val); ++ ++ return; ++} ++ ++static struct ++reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state, ++ u32 rf_freq, enum mxl5007t_bw_mhz bw) ++{ ++ u32 dig_rf_freq = 0; ++ u32 temp; ++ u32 frac_divider = 1000000; ++ unsigned int i; ++ ++ memcpy(&state->tab_rftune, ®_pair_rftune, sizeof(reg_pair_rftune)); ++ ++ mxl5007t_set_bw_bits(state, bw); ++ ++ /* Convert RF frequency into 16 bits => ++ * 10 bit integer (MHz) + 6 bit fraction */ ++ dig_rf_freq = rf_freq / MHz; ++ ++ temp = rf_freq % MHz; ++ ++ for (i = 0; i < 6; i++) { ++ dig_rf_freq <<= 1; ++ frac_divider /= 2; ++ if (temp > frac_divider) { ++ temp -= frac_divider; ++ dig_rf_freq++; ++ } ++ } ++ ++ /* add to have shift center point by 7.8124 kHz */ ++ if (temp > 7812) ++ dig_rf_freq++; ++ ++ set_reg_bits(state->tab_rftune, 0x0d, 0xff, (u8) dig_rf_freq); ++ set_reg_bits(state->tab_rftune, 0x0e, 0xff, (u8) (dig_rf_freq >> 8)); ++ ++ if (rf_freq >= 333000000) ++ set_reg_bits(state->tab_rftune, 0x80, 0x40, 0x40); ++ ++ return state->tab_rftune; ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val) ++{ ++ u8 buf[] = { reg, val }; ++ struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, ++ .buf = buf, .len = 2 }; ++ int ret; ++ ++ ret = i2c_transfer(state->i2c_props.adap, &msg, 1); ++ if (ret != 1) { ++ mxl_err("failed!"); ++ return -EREMOTEIO; ++ } ++ return 0; ++} ++ ++static int mxl5007t_write_regs(struct mxl5007t_state *state, ++ struct reg_pair_t *reg_pair) ++{ ++ unsigned int i = 0; ++ int ret = 0; ++ ++ while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) { ++ ret = mxl5007t_write_reg(state, ++ reg_pair[i].reg, reg_pair[i].val); ++ i++; ++ } ++ return ret; ++} ++ ++static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) ++{ ++ struct i2c_msg msg[] = { ++ { .addr = state->i2c_props.addr, .flags = 0, ++ .buf = ®, .len = 1 }, ++ { .addr = state->i2c_props.addr, .flags = I2C_M_RD, ++ .buf = val, .len = 1 }, ++ }; ++ int ret; ++ ++ ret = i2c_transfer(state->i2c_props.adap, msg, 2); ++ if (ret != 2) { ++ mxl_err("failed!"); ++ return -EREMOTEIO; ++ } ++ return 0; ++} ++ ++static int mxl5007t_soft_reset(struct mxl5007t_state *state) ++{ ++ u8 d = 0xff; ++ struct i2c_msg msg = { ++ .addr = state->i2c_props.addr, .flags = 0, ++ .buf = &d, .len = 1 ++ }; ++ int ret = i2c_transfer(state->i2c_props.adap, &msg, 1); ++ ++ if (ret != 1) { ++ mxl_err("failed!"); ++ return -EREMOTEIO; ++ } ++ return 0; ++} ++ ++static int mxl5007t_tuner_init(struct mxl5007t_state *state, ++ enum mxl5007t_mode mode) ++{ ++ struct reg_pair_t *init_regs; ++ int ret; ++ ++ ret = mxl5007t_soft_reset(state); ++ if (mxl_fail(ret)) ++ goto fail; ++ ++ /* calculate initialization reg array */ ++ init_regs = mxl5007t_calc_init_regs(state, mode); ++ ++ ret = mxl5007t_write_regs(state, init_regs); ++ if (mxl_fail(ret)) ++ goto fail; ++ mdelay(1); ++fail: ++ return ret; ++} ++ ++static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz, ++ enum mxl5007t_bw_mhz bw) ++{ ++ struct reg_pair_t *rf_tune_regs; ++ int ret; ++ ++ /* calculate channel change reg array */ ++ rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw); ++ ++ ret = mxl5007t_write_regs(state, rf_tune_regs); ++ if (mxl_fail(ret)) ++ goto fail; ++ msleep(3); ++fail: ++ return ret; ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++static int mxl5007t_synth_lock_status(struct mxl5007t_state *state, ++ int *rf_locked, int *ref_locked) ++{ ++ u8 d; ++ int ret; ++ ++ *rf_locked = 0; ++ *ref_locked = 0; ++ ++ ret = mxl5007t_read_reg(state, 0xd8, &d); ++ if (mxl_fail(ret)) ++ goto fail; ++ ++ if ((d & 0x0c) == 0x0c) ++ *rf_locked = 1; ++ ++ if ((d & 0x03) == 0x03) ++ *ref_locked = 1; ++fail: ++ return ret; ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) ++{ ++ struct mxl5007t_state *state = fe->tuner_priv; ++ int rf_locked, ref_locked, ret; ++ ++ *status = 0; ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 1); ++ ++ ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked); ++ if (mxl_fail(ret)) ++ goto fail; ++ mxl_debug("%s%s", rf_locked ? "rf locked " : "", ++ ref_locked ? "ref locked" : ""); ++ ++ if ((rf_locked) || (ref_locked)) ++ *status |= TUNER_STATUS_LOCKED; ++fail: ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 0); ++ ++ return ret; ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++static int mxl5007t_set_params(struct dvb_frontend *fe, ++ struct dvb_frontend_parameters *params) ++{ ++ struct mxl5007t_state *state = fe->tuner_priv; ++ enum mxl5007t_bw_mhz bw; ++ enum mxl5007t_mode mode; ++ int ret; ++ u32 freq = params->frequency; ++ ++ if (fe->ops.info.type == FE_ATSC) { ++ switch (params->u.vsb.modulation) { ++ case VSB_8: ++ case VSB_16: ++ mode = MxL_MODE_ATSC; ++ break; ++ case QAM_64: ++ case QAM_256: ++ mode = MxL_MODE_CABLE; ++ break; ++ default: ++ mxl_err("modulation not set!"); ++ return -EINVAL; ++ } ++ bw = MxL_BW_6MHz; ++ } else if (fe->ops.info.type == FE_OFDM) { ++ switch (params->u.ofdm.bandwidth) { ++ case BANDWIDTH_6_MHZ: ++ bw = MxL_BW_6MHz; ++ break; ++ case BANDWIDTH_7_MHZ: ++ bw = MxL_BW_7MHz; ++ break; ++ case BANDWIDTH_8_MHZ: ++ bw = MxL_BW_8MHz; ++ break; ++ default: ++ mxl_err("bandwidth not set!"); ++ return -EINVAL; ++ } ++ mode = MxL_MODE_DVBT; ++ } else { ++ mxl_err("modulation type not supported!"); ++ return -EINVAL; ++ } ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 1); ++ ++ mutex_lock(&state->lock); ++ ++ ret = mxl5007t_tuner_init(state, mode); ++ if (mxl_fail(ret)) ++ goto fail; ++ ++ ret = mxl5007t_tuner_rf_tune(state, freq, bw); ++ if (mxl_fail(ret)) ++ goto fail; ++ ++ state->frequency = freq; ++ state->bandwidth = (fe->ops.info.type == FE_OFDM) ? ++ params->u.ofdm.bandwidth : 0; ++fail: ++ mutex_unlock(&state->lock); ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 0); ++ ++ return ret; ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++static int mxl5007t_init(struct dvb_frontend *fe) ++{ ++ struct mxl5007t_state *state = fe->tuner_priv; ++ int ret; ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 1); ++ ++ /* wake from standby */ ++ ret = mxl5007t_write_reg(state, 0x01, 0x01); ++ mxl_fail(ret); ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 0); ++ ++ return ret; ++} ++ ++static int mxl5007t_sleep(struct dvb_frontend *fe) ++{ ++ struct mxl5007t_state *state = fe->tuner_priv; ++ int ret; ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 1); ++ ++ /* enter standby mode */ ++ ret = mxl5007t_write_reg(state, 0x01, 0x00); ++ mxl_fail(ret); ++ ret = mxl5007t_write_reg(state, 0x0f, 0x00); ++ mxl_fail(ret); ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 0); ++ ++ return ret; ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency) ++{ ++ struct mxl5007t_state *state = fe->tuner_priv; ++ *frequency = state->frequency; ++ return 0; ++} ++ ++static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) ++{ ++ struct mxl5007t_state *state = fe->tuner_priv; ++ *bandwidth = state->bandwidth; ++ return 0; ++} ++ ++static int mxl5007t_release(struct dvb_frontend *fe) ++{ ++ struct mxl5007t_state *state = fe->tuner_priv; ++ ++ mutex_lock(&mxl5007t_list_mutex); ++ ++ if (state) ++ hybrid_tuner_release_state(state); ++ ++ mutex_unlock(&mxl5007t_list_mutex); ++ ++ fe->tuner_priv = NULL; ++ ++ return 0; ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++static struct dvb_tuner_ops mxl5007t_tuner_ops = { ++ .info = { ++ .name = "MaxLinear MxL5007T", ++#if 0 ++ .frequency_min = , ++ .frequency_max = , ++ .frequency_step = , ++#endif ++ }, ++ .init = mxl5007t_init, ++ .sleep = mxl5007t_sleep, ++ .set_params = mxl5007t_set_params, ++ .get_status = mxl5007t_get_status, ++ .get_frequency = mxl5007t_get_frequency, ++ .get_bandwidth = mxl5007t_get_bandwidth, ++ .release = mxl5007t_release, ++}; ++ ++static int mxl5007t_get_chip_id(struct mxl5007t_state *state) ++{ ++ char *name; ++ int ret; ++ u8 id; ++ ++ ret = mxl5007t_read_reg(state, 0xd9, &id); ++ if (mxl_fail(ret)) ++ goto fail; ++ ++ switch (id) { ++ case MxL_5007_V1_F1: ++ name = "MxL5007.v1.f1"; ++ break; ++ case MxL_5007_V1_F2: ++ name = "MxL5007.v1.f2"; ++ break; ++ case MxL_5007_V2_100_F1: ++ name = "MxL5007.v2.100.f1"; ++ break; ++ case MxL_5007_V2_100_F2: ++ name = "MxL5007.v2.100.f2"; ++ break; ++ case MxL_5007_V2_200_F1: ++ name = "MxL5007.v2.200.f1"; ++ break; ++ case MxL_5007_V2_200_F2: ++ name = "MxL5007.v2.200.f2"; ++ break; ++ case MxL_5007_V4: ++ name = "MxL5007T.v4"; ++ break; ++ default: ++#if 0 ++ ret = -EINVAL; ++ goto fail; ++#else ++ name = "MxL5007T"; ++ printk(KERN_WARNING "%s: unknown rev (%02x)\n", __func__, id); ++ id = MxL_UNKNOWN_ID; ++#endif ++ } ++ state->chip_id = id; ++ mxl_info("%s detected @ %d-%04x", name, ++ i2c_adapter_id(state->i2c_props.adap), ++ state->i2c_props.addr); ++ return 0; ++fail: ++ mxl_warn("unable to identify device @ %d-%04x", ++ i2c_adapter_id(state->i2c_props.adap), ++ state->i2c_props.addr); ++ ++ state->chip_id = MxL_UNKNOWN_ID; ++ return ret; ++} ++ ++struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, ++ struct i2c_adapter *i2c, u8 addr, ++ struct mxl5007t_config *cfg) ++{ ++ struct mxl5007t_state *state = NULL; ++ int instance, ret; ++ ++ mutex_lock(&mxl5007t_list_mutex); ++ instance = hybrid_tuner_request_state(struct mxl5007t_state, state, ++ hybrid_tuner_instance_list, ++ i2c, addr, "mxl5007t"); ++ switch (instance) { ++ case 0: ++ goto fail; ++ case 1: ++ /* new tuner instance */ ++ state->config = cfg; ++ ++ mutex_init(&state->lock); ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 1); ++ ++ ret = mxl5007t_get_chip_id(state); ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 0); ++ ++ /* check return value of mxl5007t_get_chip_id */ ++ if (mxl_fail(ret)) ++ goto fail; ++ break; ++ default: ++ /* existing tuner instance */ ++ break; ++ } ++ fe->tuner_priv = state; ++ mutex_unlock(&mxl5007t_list_mutex); ++ ++ memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops, ++ sizeof(struct dvb_tuner_ops)); ++ ++ return fe; ++fail: ++ mutex_unlock(&mxl5007t_list_mutex); ++ ++ mxl5007t_release(fe); ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(mxl5007t_attach); ++MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); ++MODULE_AUTHOR("Michael Krufky "); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("0.2"); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-basic-offset: 8 ++ * End: ++ */ +diff --git a/drivers/media/dvb/frontends/mxl5007t.h b/drivers/media/dvb/frontends/mxl5007t.h +new file mode 100644 +index 0000000..973a71d +--- /dev/null ++++ b/drivers/media/dvb/frontends/mxl5007t.h +@@ -0,0 +1,104 @@ ++/* ++ * mxl5007t.h - driver for the MaxLinear MxL5007T silicon tuner ++ * ++ * Copyright (C) 2008 Michael Krufky ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifndef __MXL5007T_H__ ++#define __MXL5007T_H__ ++ ++#include "dvb_frontend.h" ++ ++/* ------------------------------------------------------------------------- */ ++ ++enum mxl5007t_if_freq { ++ MxL_IF_4_MHZ, /* 4000000 */ ++ MxL_IF_4_5_MHZ, /* 4500000 */ ++ MxL_IF_4_57_MHZ, /* 4570000 */ ++ MxL_IF_5_MHZ, /* 5000000 */ ++ MxL_IF_5_38_MHZ, /* 5380000 */ ++ MxL_IF_6_MHZ, /* 6000000 */ ++ MxL_IF_6_28_MHZ, /* 6280000 */ ++ MxL_IF_9_1915_MHZ, /* 9191500 */ ++ MxL_IF_35_25_MHZ, /* 35250000 */ ++ MxL_IF_36_15_MHZ, /* 36150000 */ ++ MxL_IF_44_MHZ, /* 44000000 */ ++}; ++ ++enum mxl5007t_xtal_freq { ++ MxL_XTAL_16_MHZ, /* 16000000 */ ++ MxL_XTAL_20_MHZ, /* 20000000 */ ++ MxL_XTAL_20_25_MHZ, /* 20250000 */ ++ MxL_XTAL_20_48_MHZ, /* 20480000 */ ++ MxL_XTAL_24_MHZ, /* 24000000 */ ++ MxL_XTAL_25_MHZ, /* 25000000 */ ++ MxL_XTAL_25_14_MHZ, /* 25140000 */ ++ MxL_XTAL_27_MHZ, /* 27000000 */ ++ MxL_XTAL_28_8_MHZ, /* 28800000 */ ++ MxL_XTAL_32_MHZ, /* 32000000 */ ++ MxL_XTAL_40_MHZ, /* 40000000 */ ++ MxL_XTAL_44_MHZ, /* 44000000 */ ++ MxL_XTAL_48_MHZ, /* 48000000 */ ++ MxL_XTAL_49_3811_MHZ, /* 49381100 */ ++}; ++ ++enum mxl5007t_clkout_amp { ++ MxL_CLKOUT_AMP_0_94V = 0, ++ MxL_CLKOUT_AMP_0_53V = 1, ++ MxL_CLKOUT_AMP_0_37V = 2, ++ MxL_CLKOUT_AMP_0_28V = 3, ++ MxL_CLKOUT_AMP_0_23V = 4, ++ MxL_CLKOUT_AMP_0_20V = 5, ++ MxL_CLKOUT_AMP_0_17V = 6, ++ MxL_CLKOUT_AMP_0_15V = 7, ++}; ++ ++struct mxl5007t_config { ++ s32 if_diff_out_level; ++ enum mxl5007t_clkout_amp clk_out_amp; ++ enum mxl5007t_xtal_freq xtal_freq_hz; ++ enum mxl5007t_if_freq if_freq_hz; ++ unsigned int invert_if:1; ++ unsigned int loop_thru_enable:1; ++ unsigned int clk_out_enable:1; ++}; ++ ++#if defined(CONFIG_DVB_TUNER_MXL5007T) || (defined(CONFIG_DVB_TUNER_MXL5007T_MODULE) && defined(MODULE)) ++extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, ++ struct i2c_adapter *i2c, u8 addr, ++ struct mxl5007t_config *cfg); ++#else ++static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, ++ struct i2c_adapter *i2c, ++ u8 addr, ++ struct mxl5007t_config *cfg) ++{ ++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); ++ return NULL; ++} ++#endif ++ ++#endif /* __MXL5007T_H__ */ ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-basic-offset: 8 ++ * End: ++ */ ++ +diff --git a/drivers/media/dvb/frontends/tuner-i2c.h b/drivers/media/dvb/frontends/tuner-i2c.h +new file mode 100644 +index 0000000..cb1c714 +--- /dev/null ++++ b/drivers/media/dvb/frontends/tuner-i2c.h +@@ -0,0 +1,181 @@ ++/* ++ tuner-i2c.h - i2c interface for different tuners ++ ++ Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++#ifndef __TUNER_I2C_H__ ++#define __TUNER_I2C_H__ ++ ++#include ++ ++struct tuner_i2c_props { ++ u8 addr; ++ struct i2c_adapter *adap; ++ ++ /* used for tuner instance management */ ++ int count; ++ char *name; ++}; ++ ++static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len) ++{ ++ struct i2c_msg msg = { .addr = props->addr, .flags = 0, ++ .buf = buf, .len = len }; ++ int ret = i2c_transfer(props->adap, &msg, 1); ++ ++ return (ret == 1) ? len : ret; ++} ++ ++static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len) ++{ ++ struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, ++ .buf = buf, .len = len }; ++ int ret = i2c_transfer(props->adap, &msg, 1); ++ ++ return (ret == 1) ? len : ret; ++} ++ ++static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, ++ char *obuf, int olen, ++ char *ibuf, int ilen) ++{ ++ struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, ++ .buf = obuf, .len = olen }, ++ { .addr = props->addr, .flags = I2C_M_RD, ++ .buf = ibuf, .len = ilen } }; ++ int ret = i2c_transfer(props->adap, msg, 2); ++ ++ return (ret == 2) ? ilen : ret; ++} ++ ++/* Callers must declare as a global for the module: ++ * ++ * static LIST_HEAD(hybrid_tuner_instance_list); ++ * ++ * hybrid_tuner_instance_list should be the third argument ++ * passed into hybrid_tuner_request_state(). ++ * ++ * state structure must contain the following: ++ * ++ * struct list_head hybrid_tuner_instance_list; ++ * struct tuner_i2c_props i2c_props; ++ * ++ * hybrid_tuner_instance_list (both within state structure and globally) ++ * is only required if the driver is using hybrid_tuner_request_state ++ * and hybrid_tuner_release_state to manage state sharing between ++ * multiple instances of hybrid tuners. ++ */ ++ ++#define tuner_printk(kernlvl, i2cprops, fmt, arg...) do { \ ++ printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name, \ ++ i2cprops.adap ? \ ++ i2c_adapter_id(i2cprops.adap) : -1, \ ++ i2cprops.addr, ##arg); \ ++ } while (0) ++ ++/* TO DO: convert all callers of these macros to pass in ++ * struct tuner_i2c_props, then remove the macro wrappers */ ++ ++#define __tuner_warn(i2cprops, fmt, arg...) do { \ ++ tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg); \ ++ } while (0) ++ ++#define __tuner_info(i2cprops, fmt, arg...) do { \ ++ tuner_printk(KERN_INFO, i2cprops, fmt, ##arg); \ ++ } while (0) ++ ++#define __tuner_err(i2cprops, fmt, arg...) do { \ ++ tuner_printk(KERN_ERR, i2cprops, fmt, ##arg); \ ++ } while (0) ++ ++#define __tuner_dbg(i2cprops, fmt, arg...) do { \ ++ if ((debug)) \ ++ tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg); \ ++ } while (0) ++ ++#define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg) ++#define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg) ++#define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg) ++#define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg) ++ ++/****************************************************************************/ ++ ++/* The return value of hybrid_tuner_request_state indicates the number of ++ * instances using this tuner object. ++ * ++ * 0 - no instances, indicates an error - kzalloc must have failed ++ * ++ * 1 - one instance, indicates that the tuner object was created successfully ++ * ++ * 2 (or more) instances, indicates that an existing tuner object was found ++ */ ++ ++#define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\ ++({ \ ++ int __ret = 0; \ ++ list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \ ++ if (((i2cadap) && (state->i2c_props.adap)) && \ ++ ((i2c_adapter_id(state->i2c_props.adap) == \ ++ i2c_adapter_id(i2cadap)) && \ ++ (i2caddr == state->i2c_props.addr))) { \ ++ __tuner_info(state->i2c_props, \ ++ "attaching existing instance\n"); \ ++ state->i2c_props.count++; \ ++ __ret = state->i2c_props.count; \ ++ break; \ ++ } \ ++ } \ ++ if (0 == __ret) { \ ++ state = kzalloc(sizeof(type), GFP_KERNEL); \ ++ if (NULL == state) \ ++ goto __fail; \ ++ state->i2c_props.addr = i2caddr; \ ++ state->i2c_props.adap = i2cadap; \ ++ state->i2c_props.name = devname; \ ++ __tuner_info(state->i2c_props, \ ++ "creating new instance\n"); \ ++ list_add_tail(&state->hybrid_tuner_instance_list, &list);\ ++ state->i2c_props.count++; \ ++ __ret = state->i2c_props.count; \ ++ } \ ++__fail: \ ++ __ret; \ ++}) ++ ++#define hybrid_tuner_release_state(state) \ ++({ \ ++ int __ret; \ ++ state->i2c_props.count--; \ ++ __ret = state->i2c_props.count; \ ++ if (!state->i2c_props.count) { \ ++ __tuner_info(state->i2c_props, "destroying instance\n");\ ++ list_del(&state->hybrid_tuner_instance_list); \ ++ kfree(state); \ ++ } \ ++ __ret; \ ++}) ++ ++#define hybrid_tuner_report_instance_count(state) \ ++({ \ ++ int __ret = 0; \ ++ if (state) \ ++ __ret = state->i2c_props.count; \ ++ __ret; \ ++}) ++ ++#endif /* __TUNER_I2C_H__ */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0155-UBUNTU-pull-in-updated-rebase-branch-script.patch +++ linux-2.6.24/patches/0155-UBUNTU-pull-in-updated-rebase-branch-script.patch @@ -0,0 +1,182 @@ +From 98ca20a1303acb110debdde33fdad21be6a82222 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Tue, 28 Jul 2009 16:46:41 +0100 +Subject: [PATCH 155/170] UBUNTU: pull in updated rebase-branch script + +Pull in an updated rebase-branch script which is not tag sensitive. + +Signed-off-by: Andy Whitcroft +--- + debian/scripts/misc/rebase-branch | 99 +++++++++++++++--------------------- + 1 files changed, 41 insertions(+), 58 deletions(-) + +diff --git a/debian/scripts/misc/rebase-branch b/debian/scripts/misc/rebase-branch +index 7be17db..8e4e388 100755 +--- a/debian/scripts/misc/rebase-branch ++++ b/debian/scripts/misc/rebase-branch +@@ -1,9 +1,12 @@ +-#!/bin/sh ++#!/bin/bash + + # Script to maintain a (target) tree based on the main kernel + # Author: Amit Kucheria (amit@ubuntu.com) + # Date: 11/07/08 + ++# Modified for netbook use ++# Andy Whitcroft ++ + # Modified for netbook-lpia branch + # Steve Conklin + +@@ -20,12 +23,29 @@ remoteTag=${1:?"Usage: $0 "} + rebasing=".git/rebase-apply" + + # Configuration variables +-release="hardy" +-basever="2.6.24" ++release="ubuntu" ++basever=`sed -n '1s/^.*(\(.*\)-.*).*$/\1/p' debian/changelog` + patchDir=./patches + # masterTree=git://zinc.ubuntu.com/ubuntu/ubuntu-$release.git +-baseTag="NBK-Ubuntu-$basever-0.0" +-tmpTag="tmplpia" ++ ++# Find the base of the tree, and extract branch specific prefix. ++baseCommit=$(git log --pretty=format:'%H %s' \ ++ `git merge-base origin/master HEAD`..HEAD | \ ++ awk '/UBUNTU: '".*-Ubuntu-$basever-0.0"'$/ { print $1 " " $NF }' ++) ++baseHash="${baseCommit% *}" ++basePrefix="${baseCommit#* }" ++basePrefix="${basePrefix%%-*}" ++ ++baseTag="$basePrefix-Ubuntu-$basever-0.0" ++ ++if [ "$baseHash" = "" -o "$basePrefix" = "" ]; then ++ echo "$0: base commit not found -- aborting" 1>&2 ++ exit 1 ++fi ++ ++#echo "baseHash<$baseHash> basePrefix<$basePrefix> baseTag<$baseTag>" ++#exit 0 + + remoteBranch=auto-tmp-remote + git=`which git` +@@ -41,24 +61,22 @@ if [ ! $? -eq "0" ]; then + exit 1; + fi + +-echo "\n" +-echo "* Checking out master tree..." +-$git checkout origin/netbook-lpia +-$git reset --hard +- ++##echo "\n" ++##echo "* Checking out master tree..." ++##$git checkout origin/netbook ++##$git reset --hard + + echo "\n" + echo "* Exporting current work as patches..." +-$git format-patch -o $patchDir $baseTag ++$git format-patch -o $patchDir $baseHash + # Deleting tags is evil... + #$git tag -l | grep "Ubuntu-2.6.2*" | xargs $git tag -d + #$git tag -l | grep "Ubuntu-LPIA-2.6.2*" | xargs $git tag -d +-$git tag -d $tmpTag + +-# Debugging +-mkdir -p .patches +-cp $patchDir/*.patch .patches +-# end Debugging ++### Debugging ++##mkdir -p .patches ++##cp $patchDir/*.patch .patches ++### end Debugging + + echo "* Cleaning up patches..." + # Remove auto-generated patches +@@ -70,8 +88,6 @@ do + echo "$i ..." + awk ' + BEGIN { on=1 } +- /Subject:/ { sub("UBUNTU: 2\\.6\\.", +- "UBUNTU: NBK-Ubuntu-2.6.", $0); } + /^diff --git a\/debian\/control / { on=0; next } + /^diff --git a\/debian\/control.stub / { on=0; next } + /^diff --git a\/debian\/d-i\/kernel-versions / { on=0; next } +@@ -95,39 +111,10 @@ $git config --bool ubuntu.flavour-changes-ok true + $git config --bool ubuntu.allow-non-sauce-commit true + $git config --bool ubuntu.others-changes-ok true + +-$git tag -m "Tip of ubuntu git on which we apply patches" $tmpTag +- +-# Tag our base point on the tree. ++# Mark our base point on the tree. + echo "AUTO #0" + $git commit --allow-empty -s -m "UBUNTU: $baseTag" + +-if false; then +-# Move debian/ out of the way +-echo "AUTO #1" +-rm -rf debian-main/ +-$git mv debian/ debian-main/ +-$git commit -s -m "UBUNTU: AUTO: Move upstream debian/ dir out of the way for a lpia-specific debian/" +-$git status +- +-# Disable all git hooks +-$git config --bool ubuntu.flavour-changes-ok true +-$git config --bool ubuntu.allow-non-sauce-commit true +-$git config --bool ubuntu.others-changes-ok true +- +-# Copy debian-main/ to debian/ +-echo "AUTO #2" +-cp -a debian-main/ debian/ +-$git add debian/ +-$git commit -a -s -m "UBUNTU: AUTO: Create a new debian/" +-$git status +- +-# Disable all git hooks +-$git config --bool ubuntu.flavour-changes-ok true +-$git config --bool ubuntu.allow-non-sauce-commit true +-$git config --bool ubuntu.others-changes-ok true +- +-fi +- + # Delete upstream ABI, extra arch/flavours + echo "AUTO #3" + $git rm -r debian/abi/\* +@@ -145,8 +132,9 @@ $git config --bool ubuntu.others-changes-ok true + # Start new changelog + echo "AUTO #4" + $git mv debian/changelog debian/changelog.$release +-DEBEMAIL="Ubuntu Kernel Team " \ +- EDITOR=: dch --create --package linux-lpia --newversion $basever-0.0 ++DEBFULLNAME="Ubuntu Kernel Team" \ ++DEBEMAIL="kernel-team@lists.ubuntu.com" \ ++ EDITOR=: dch --create --package linux --newversion $basever-0.0 + + # Need to change timestamp else patches fail -- use the timestamp of the first + # entry from the main changelog. +@@ -170,15 +158,10 @@ if [ -d "$rebasing/" ]; then + exit 1; + fi + +-# Delete tags and recreate them on rebased tree +-#git tag | grep LPIA | xargs git tag -d +-#git tag -f -s -m $baseTag $baseTag $tmpTag +-git tag -d $tmpTag +- +-echo "\n" ++echo "" + echo "If the final result looks good, then do the following to make it permanent:" +-echo " * Run debian/scripts/misc/retag-branch to retag" +-echo " * git checkout netbook-lpia" ++##echo " * Run debian/scripts/misc/retag-branch to retag" ++echo " * git checkout " + echo " * git reset --hard $remoteBranch" + echo " * rm -rf patches/" + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0154-UBUNTU-NBK-Ubuntu-2.6.24-24.54netbook02.patch +++ linux-2.6.24/patches/0154-UBUNTU-NBK-Ubuntu-2.6.24-24.54netbook02.patch @@ -0,0 +1,28 @@ +From 0b441f991db786c80ab1165e22064b07714d90b3 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Tue, 28 Jul 2009 09:54:57 -0500 +Subject: [PATCH 154/170] UBUNTU: NBK-Ubuntu-2.6.24-24.54netbook02 + +Signed-off-by: Steve Conklin +--- + debian/changelog | 7 +++++++ + 1 files changed, 7 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index dffbc61..d578524 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,10 @@ ++linux (2.6.24-24.54netbook02) netbook-common; urgency=low ++ ++ [ Steve Conklin ] ++ * Fix NVR ++ ++ -- sconklin Tue, 28 Jul 2009 14:09:38 +0000 ++ + linux (2.6.24-24.54netboot01) netboot-common; urgency=low + + [ Andy Whitcroft ] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0087-Patch-to-ps-2-driver-to-support-new-Elantech-touchpa.patch +++ linux-2.6.24/patches/0087-Patch-to-ps-2-driver-to-support-new-Elantech-touchpa.patch @@ -0,0 +1,334 @@ +From 61fdc67e1ecc9e422776814610fa3225e23d8a4d Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 17 Dec 2008 11:44:19 -0500 +Subject: [PATCH 087/170] Patch to ps/2 driver to support new Elantech touchpad. + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/input/mouse/Kconfig | 10 +++++ + drivers/input/mouse/Makefile | 2 + + drivers/input/mouse/psmouse-base.c | 54 +++++++++++++++++++++++++++- + drivers/input/mouse/psmouse.h | 1 + + drivers/input/serio/i8042.c | 70 ++++++++++++++++++++++++++++++++---- + drivers/input/serio/libps2.c | 5 +-- + 6 files changed, 131 insertions(+), 11 deletions(-) + +diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig +index 7bbea09..84f94e4 100644 +--- a/drivers/input/mouse/Kconfig ++++ b/drivers/input/mouse/Kconfig +@@ -67,6 +67,16 @@ config MOUSE_PS2_SYNAPTICS + + If unsure, say Y. + ++config MOUSE_PS2_ELANTECH ++ bool "ELANTECH PS/2 mouse protocol extension" if EMBEDDED ++ default y ++ depends on MOUSE_PS2 ++ help ++ Say Y here if you have an ELANTECH PS/2 touchpad connected to ++ your system. ++ ++ If unsure, say Y. ++ + config MOUSE_PS2_LIFEBOOK + bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED + default y +diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile +index 9e6e363..bbf5c84 100644 +--- a/drivers/input/mouse/Makefile ++++ b/drivers/input/mouse/Makefile +@@ -17,6 +17,7 @@ obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o + obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o + obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o + ++ + psmouse-objs := psmouse-base.o synaptics.o + + psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o +@@ -24,3 +25,4 @@ psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o + psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o + psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o + psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o ++psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o +diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c +index b862825..299e7bd 100644 +--- a/drivers/input/mouse/psmouse-base.c ++++ b/drivers/input/mouse/psmouse-base.c +@@ -13,7 +13,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -21,6 +20,7 @@ + #include + #include + #include ++#include + + #include "psmouse.h" + #include "synaptics.h" +@@ -29,6 +29,7 @@ + #include "lifebook.h" + #include "trackpoint.h" + #include "touchkit_ps2.h" ++#include "elantech.h" + + #define DRIVER_DESC "PS/2 mouse driver" + +@@ -572,6 +573,47 @@ static int psmouse_extensions(struct psmouse *psmouse, + unsigned int max_proto, int set_properties) + { + int synaptics_hardware = 0; ++ int repeat_elantech = 0; ++ int elantech_hardware = 0; ++ ++/* ++ *Try Elan touchpad ++ */ ++ if (max_proto > PSMOUSE_IMEX) { ++ for(repeat_elantech=0;repeat_elantech < 3;repeat_elantech++) ++ { ++ if (elantech_detect(psmouse, set_properties) == 0) ++ { ++ printk(KERN_DEBUG "elantech_detect(psmouse, set_properties) == 0\n"); ++ if (elantech_init(psmouse,set_properties) == 0) ++ { ++ printk(KERN_DEBUG "elantech_init(psmouse) == 0\n"); ++ return PSMOUSE_ELANTECH; ++ } ++ //else if(!set_properties){ ++ // printk(KERN_DEBUG "!set_properties is TRUE\n"); ++ // return PSMOUSE_ELANTECH; ++ //} ++ psmouse_reset(psmouse); ++ max_proto = PSMOUSE_IMEX; ++ printk(KERN_DEBUG "elantech_init not work\n"); ++ clear_bit(EV_ABS, psmouse->dev->evbit);//tom ++ elantech_hardware=1; ++ } ++ } ++ if(!set_properties) ++ clear_bit(EV_ABS, psmouse->dev->evbit);//tom ++ } ++ if(repeat_elantech >= 3) ++ psmouse_reset(psmouse); ++ ++ if(elantech_hardware){ ++ //+chris ++ psmouse->protocol_handler = psmouse_process_byte; ++ psmouse->pktsize = 3; ++ //-chris ++ } ++ + + /* + * We always check for lifebook because it does not disturb mouse +@@ -763,6 +805,14 @@ static const struct psmouse_protocol psmouse_protocols[] = { + .detect = touchkit_ps2_detect, + }, + #endif ++#ifdef CONFIG_MOUSE_PS2_ELANTECH ++ { .type = PSMOUSE_ELANTECH, ++ .name = "ETPS/2", ++ .alias = "elantech", ++ .detect = elantech_detect, ++ .init = elantech_init, ++ }, ++#endif + { + .type = PSMOUSE_CORTRON, + .name = "CortronPS/2", +@@ -1218,7 +1268,9 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) + psmouse->resync_time = parent ? 0 : psmouse_resync_time; + psmouse->smartscroll = psmouse_smartscroll; + ++ i8042_command(NULL,I8042_CMD_KBD_DISABLE);// tom + + psmouse_switch_protocol(psmouse, NULL); ++ i8042_command(NULL,I8042_CMD_KBD_ENABLE);// tom + + + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); +diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h +index 1317bdd..27c26aa 100644 +--- a/drivers/input/mouse/psmouse.h ++++ b/drivers/input/mouse/psmouse.h +@@ -89,6 +89,7 @@ enum psmouse_type { + PSMOUSE_TRACKPOINT, + PSMOUSE_TOUCHKIT_PS2, + PSMOUSE_CORTRON, ++ PSMOUSE_ELANTECH, + PSMOUSE_AUTO /* This one should always be last */ + }; + +diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c +index 1a0cea3..0ac35e3 100644 +--- a/drivers/input/serio/i8042.c ++++ b/drivers/input/serio/i8042.c +@@ -12,7 +12,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -64,6 +63,12 @@ static unsigned int i8042_blink_frequency = 500; + module_param_named(panicblink, i8042_blink_frequency, uint, 0600); + MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics"); + ++#ifdef CONFIG_X86 ++static unsigned int i8042_dritek; ++module_param_named(dritek, i8042_dritek, bool, 0); ++MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension"); ++#endif ++ + #ifdef CONFIG_PNP + static int i8042_nopnp; + module_param_named(nopnp, i8042_nopnp, bool, 0); +@@ -280,7 +285,14 @@ static void i8042_stop(struct serio *serio) + struct i8042_port *port = serio->port_data; + + port->exists = 0; +- synchronize_sched(); ++ ++ /* ++ * We synchronize with both AUX and KBD IRQs because there is ++ * a (very unlikely) chance that AUX IRQ is raised for KBD port ++ * and vice versa. ++ */ ++ synchronize_irq(I8042_AUX_IRQ); ++ synchronize_irq(I8042_KBD_IRQ); + port->serio = NULL; + } + +@@ -317,6 +329,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) + dfl = 0; + if (str & I8042_STR_MUXERR) { + dbg("MUX error, status is %02x, data is %02x", str, data); ++ + /* + * When MUXERR condition is signalled the data register can only contain + * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately +@@ -332,7 +345,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) + + switch (data) { + default: +- if (time_before(jiffies, last_transmit + HZ/10)) { ++ if (time_before(jiffies, last_transmit + HZ)) { //tom + HZ/10 -> HZ + str = last_str; + break; + } +@@ -873,6 +886,20 @@ static long i8042_panic_blink(long count) + + #undef DELAY + ++#ifdef CONFIG_X86 ++static void i8042_dritek_enable(void) ++{ ++ char param = 0x90; ++ int error; ++ ++ error = i8042_command(¶m, 0x1059); ++ if (error) ++ printk(KERN_WARNING ++ "Failed to enable DRITEK extension: %d\n", ++ error); ++} ++#endif ++ + #ifdef CONFIG_PM + /* + * Here we try to restore the original BIOS settings. We only want to +@@ -926,10 +953,20 @@ static int i8042_resume(struct platform_device *dev) + i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; + i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { +- printk(KERN_ERR "i8042: Can't write CTR to resume\n"); +- return -EIO; ++ printk(KERN_WARNING "i8042: Can't write CTR to resume, retrying...\n"); ++ msleep(50); ++ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { ++ printk(KERN_ERR "i8042: CTR write retry failed\n"); ++ return -EIO; ++ } + } + ++ ++#ifdef CONFIG_X86 ++ if (i8042_dritek) ++ i8042_dritek_enable(); ++#endif ++ + if (i8042_mux_present) { + if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports()) + printk(KERN_WARNING +@@ -1148,18 +1185,37 @@ static int __devinit i8042_probe(struct platform_device *dev) + if (error) + return error; + ++#ifdef CONFIG_X86 ++ if (i8042_dritek) ++ i8042_dritek_enable(); ++#endif ++ ++ error=i8042_command(NULL,I8042_CMD_KBD_DISABLE);// tom + ++ if(!error) ++ printk(KERN_INFO"i8042_command I8042_CMD_KBD_DISABLE OK\n"); ++ + if (!i8042_noaux) { + error = i8042_setup_aux(); +- if (error && error != -ENODEV && error != -EBUSY) ++ if (error && error != -ENODEV && error != -EBUSY){ ++ ++ if(!error) ++ error=i8042_command(NULL,I8042_CMD_KBD_ENABLE);// tom + ++ if(!error) ++ printk(KERN_INFO"i8042_command I8042_CMD_KBD_ENABLE OK\n"); + goto out_fail; ++ } + } + ++ if(!error) ++ error=i8042_command(NULL,I8042_CMD_KBD_ENABLE);// tom + ++ if(!error) ++ printk(KERN_INFO"i8042_command I8042_CMD_KBD_ENABLE OK\n"); ++ + if (!i8042_nokbd) { + error = i8042_setup_kbd(); + if (error) + goto out_fail; + } +- + /* + * Ok, everything is ready, let's register all serio ports + */ +diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c +index 10d9d74..f76fd3a 100644 +--- a/drivers/input/serio/libps2.c ++++ b/drivers/input/serio/libps2.c +@@ -13,7 +13,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -127,8 +126,8 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout) + * The next byte will come soon (keyboard) or not + * at all (mouse). + */ +- if (timeout > msecs_to_jiffies(100)) +- timeout = msecs_to_jiffies(100); ++ //if (timeout > msecs_to_jiffies(100)) ++ timeout = msecs_to_jiffies(1100);//tom + + break; + + case PS2_CMD_GETID: +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0094-UBUNTU-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook5.patch +++ linux-2.6.24/patches/0094-UBUNTU-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook5.patch @@ -0,0 +1,35 @@ +From 310401339381765cf77bbd304cbcaa97134a33f2 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Wed, 4 Feb 2009 07:50:07 -0600 +Subject: [PATCH 094/170] UBUNTU: UBUNTU: NBK-Ubuntu-2.6.24-22.45netbook5 + +Ignore: yes +Signed-off-by: Steve Conklin +--- + debian/changelog | 13 +++++++++++++ + 1 files changed, 13 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 4511773..ce562fb 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,16 @@ ++linux (2.6.24-22.45netbook5) hardy; urgency=low ++ ++ [Tony Espy] ++ ++ * drm/i915 fixes to AR register restore; LP: #264284 ++ ++ [Upstream Kernel Changes] ++ ++ * This patch provides an new kernel boot parameter "delayloop" to disable ++ tsc_delay() and use delay_loop() instead. (LP: #304247) ++ ++ -- Steve Conklin Wed, 04 Feb 2009 07:42:40 -0600 ++ + linux (2.6.24-22.45netbook4) hardy; urgency=low + + [Colin King] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0096-PATCH-100-132-FRIG.patch +++ linux-2.6.24/patches/0096-PATCH-100-132-FRIG.patch @@ -0,0 +1,22 @@ +From 14d177bff57786a2668a67cd672ec2207dbb1c91 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 19:36:31 +0100 +Subject: [PATCH 096/170] [PATCH 100/132] FRIG + +--- + debian/changelog | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index ce562fb..8687cdd 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,4 +1,4 @@ +-linux (2.6.24-22.45netbook5) hardy; urgency=low ++linux (2.6.24-22.45netbook5) netbook-common; urgency=low + + [Tony Espy] + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0046-UBUNTU-NBK-Ubuntu-2.6.24-19.35netbook4.patch +++ linux-2.6.24/patches/0046-UBUNTU-NBK-Ubuntu-2.6.24-19.35netbook4.patch @@ -0,0 +1,29 @@ +From 49f165ac743bf7f11b7dbcfc17c74c2bd5efd4ac Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 16 Jul 2008 16:47:46 +0100 +Subject: [PATCH 046/170] UBUNTU: NBK-Ubuntu-2.6.24-19.35netbook4 + +Ignore: yes +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 44a3e88..ecf0d5c 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-19.35netbook4) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * Updated Memory Stick driver ++ ++ -- Michael Frey Wed, 16 Jul 2008 16:46:04 +0100 ++ + linux (2.6.24-19.35netbook3) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0127-Turn-debian-binary-custom.d-lpia-patchset-0023-crown.patch +++ linux-2.6.24/patches/0127-Turn-debian-binary-custom.d-lpia-patchset-0023-crown.patch @@ -0,0 +1,72 @@ +From bd500a6df47c19780a89b897bcb92f36e0cb6d35 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:35 +0100 +Subject: [PATCH 127/170] Turn debian/binary-custom.d/lpia/patchset/0023-crown_beach_reboot.patch into a commit. + +Signed-off-by: Andy Whitcroft + +commit 6b39c7c4f2afc4e046382ef34f889b6078ab4a5c +Author: Amit Kucheria +Date: Tue Apr 1 00:39:09 2008 +0300 + + UBUNTU: LPIA: Fix reboot problem after S3/S4 + + Signed-off-by: Amit Kucheria +--- + arch/x86/kernel/reboot_32.c | 10 +++++++++ + .../lpia/patchset/0023-crown_beach_reboot.patch | 22 -------------------- + 2 files changed, 10 insertions(+), 22 deletions(-) + delete mode 100644 debian/binary-custom.d/lpia/patchset/0023-crown_beach_reboot.patch + +diff --git a/arch/x86/kernel/reboot_32.c b/arch/x86/kernel/reboot_32.c +index 4ba7bcd..c4bf9c8 100644 +--- a/arch/x86/kernel/reboot_32.c ++++ b/arch/x86/kernel/reboot_32.c +@@ -162,6 +162,16 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_VERSION, "Gen 1.5"), + }, + }, ++ { /* Handle problems with rebooting on Intel Crown Beach board */ ++ .callback = set_bios_reboot, ++ .ident = "Intel Crown Beach board", ++ .matches = { ++ /* Currently the DMI info is not customized and indicates ++ * OEM need change that */ ++ DMI_MATCH(DMI_SYS_VENDOR, "To Be Filled By O.E.M."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "To Be Filled By O.E.M."), ++ }, ++ }, + { } + }; + +diff --git a/debian/binary-custom.d/lpia/patchset/0023-crown_beach_reboot.patch b/debian/binary-custom.d/lpia/patchset/0023-crown_beach_reboot.patch +deleted file mode 100644 +index b38a561..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0023-crown_beach_reboot.patch ++++ /dev/null +@@ -1,22 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/arch/x86/kernel/reboot_32.c b/arch/x86/kernel/reboot_32.c +-index bb1a0f8..50c2f11 100644 +---- a/arch/x86/kernel/reboot_32.c +-+++ b/arch/x86/kernel/reboot_32.c +-@@ -135,6 +135,16 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { +- DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), +- }, +- }, +-+ { /* Handle problems with rebooting on Intel Crown Beach board */ +-+ .callback = set_bios_reboot, +-+ .ident = "Intel Crown Beach board", +-+ .matches = { +-+ /* Currently the DMI info is not customized and indicates +-+ * OEM need change that */ +-+ DMI_MATCH(DMI_SYS_VENDOR, "To Be Filled By O.E.M."), +-+ DMI_MATCH(DMI_PRODUCT_NAME, "To Be Filled By O.E.M."), +-+ }, +-+ }, +- { } +- }; +- +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0070-debian-binary-custom.d-lpia-config.lpia.-Turned-on-H.patch +++ linux-2.6.24/patches/0070-debian-binary-custom.d-lpia-config.lpia.-Turned-on-H.patch @@ -0,0 +1,73 @@ +From b361cf0147a1c8b988f81f43a051f47b87395395 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Fri, 24 Oct 2008 18:57:23 -0400 +Subject: [PATCH 070/170] debian/binary-custom.d/lpia/config.lpia. Turned on HIGHMEM and HIGHMEM4G as well as enabled SECURITY configs to match the 386 kernel. + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/binary-custom.d/lpia/config.lpia | 28 +++++++++++++++++++++++++--- + 1 files changed, 25 insertions(+), 3 deletions(-) + +diff --git a/debian/binary-custom.d/lpia/config.lpia b/debian/binary-custom.d/lpia/config.lpia +index 18fa3ca..53f1f4c 100644 +--- a/debian/binary-custom.d/lpia/config.lpia ++++ b/debian/binary-custom.d/lpia/config.lpia +@@ -215,14 +215,19 @@ CONFIG_MICROCODE=m + CONFIG_MICROCODE_OLD_INTERFACE=y + CONFIG_X86_MSR=m + CONFIG_X86_CPUID=m +-CONFIG_NOHIGHMEM=y +-# CONFIG_HIGHMEM4G is not set ++# CONFIG_NOHIGHMEM is not set ++CONFIG_HIGHMEM=y ++CONFIG_HIGHMEM4G=y ++CONFIG_HIGHPTE=y ++# CONFIG_DEBUG_HIGHMEM is not set + # CONFIG_HIGHMEM64G is not set + CONFIG_VMSPLIT_3G=y + # CONFIG_VMSPLIT_3G_OPT is not set + # CONFIG_VMSPLIT_2G is not set + # CONFIG_VMSPLIT_2G_OPT is not set + # CONFIG_VMSPLIT_1G is not set ++CONFIG_CRASH_DUMP=y ++CONFIG_PROC_VMCORE=y + CONFIG_PAGE_OFFSET=0xC0000000 + # CONFIG_X86_PAE is not set + CONFIG_ARCH_FLATMEM_ENABLE=y +@@ -770,6 +775,7 @@ CONFIG_NET_ACT_IPT=m + CONFIG_NET_ACT_NAT=m + CONFIG_NET_ACT_PEDIT=m + CONFIG_NET_ACT_SIMP=m ++# CONFIG_NETLABEL is not set + # CONFIG_NET_CLS_POLICE is not set + # CONFIG_NET_CLS_IND is not set + CONFIG_NET_SCH_FIFO=y +@@ -3219,8 +3225,24 @@ CONFIG_DEFAULT_IO_DELAY_TYPE=0 + # + CONFIG_KEYS=y + # CONFIG_KEYS_DEBUG_PROC_KEYS is not set +-# CONFIG_SECURITY is not set ++CONFIG_SECURITY=y ++CONFIG_SECURITY_APPARMOR=y ++CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 ++# CONFIG_SECURITY_APPARMOR_DISABLE is not set ++CONFIG_SECURITY_CAPABILITIES=y + # CONFIG_SECURITY_FILE_CAPABILITIES is not set ++CONFIG_SECURITY_NETWORK=y ++# CONFIG_SECURITY_NETWORK_XFRM is not set ++CONFIG_SECURITY_SELINUX=y ++CONFIG_SECURITY_SELINUX_AVC_STATS=y ++CONFIG_SECURITY_SELINUX_BOOTPARAM=y ++CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 ++CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 ++CONFIG_SECURITY_SELINUX_DEVELOP=y ++CONFIG_SECURITY_SELINUX_DISABLE=y ++# CONFIG_SECURITY_ROOTPLUG is not set ++# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set ++# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set + CONFIG_XOR_BLOCKS=m + CONFIG_ASYNC_CORE=m + CONFIG_ASYNC_MEMCPY=m +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0044-UBUNTU-NBK-Ubuntu-2.6.24-19.35netbook3.patch +++ linux-2.6.24/patches/0044-UBUNTU-NBK-Ubuntu-2.6.24-19.35netbook3.patch @@ -0,0 +1,32 @@ +From 4fb993e3333916d881070af2b0e98829c27be718 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 15 Jul 2008 13:58:25 +0100 +Subject: [PATCH 044/170] UBUNTU: NBK-Ubuntu-2.6.24-19.35netbook3 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 10 ++++++++++ + 1 files changed, 10 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 8bca264..44a3e88 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,13 @@ ++linux (2.6.24-19.35netbook3) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * New Memory Stick block driver ++ * Add config option for Memory Stick driver ++ * Turn on Memory Stick driver ++ ++ -- Michael Frey Tue, 15 Jul 2008 13:55:48 +0100 ++ + linux (2.6.24-19.35netbook2) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0097-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook6.patch +++ linux-2.6.24/patches/0097-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook6.patch @@ -0,0 +1,30 @@ +From 430e3fe87a5ae7a672f9338e45a8c3afd6da0d02 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 17 Mar 2009 15:30:57 -0400 +Subject: [PATCH 097/170] UBUNTU: NBK-Ubuntu-2.6.24-22.45netbook6 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 8687cdd..9afe43d 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-22.45netbook6) netbook-common; urgency=low ++ ++ [Michael Frey] ++ ++ * Load USB HID as a module (LP: #320866) ++ ++ -- Michael Frey Tue, 17 Mar 2009 15:27:59 -0400 ++ + linux (2.6.24-22.45netbook5) netbook-common; urgency=low + + [Tony Espy] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0092-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook4.patch +++ linux-2.6.24/patches/0092-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook4.patch @@ -0,0 +1,31 @@ +From 07914c72eb0bbedf7e7bf72940c252446f1a38c8 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 17 Dec 2008 15:21:37 -0500 +Subject: [PATCH 092/170] UBUNTU: NBK-Ubuntu-2.6.24-22.45netbook4 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 9 +++++++++ + 1 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 249aaf9..4511773 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,12 @@ ++linux (2.6.24-22.45netbook4) hardy; urgency=low ++ ++ [Colin King] ++ ++ * RT73 driver has shown to have poor performance. Backport of RT73 driver. ++ - LP: #294603 ++ ++ -- Michael Frey Wed, 17 Dec 2008 15:15:09 -0500 ++ + linux (2.6.24-22.45netbook3) hardy; urgency=low + + [Upstream Kernel Changes] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0007-kgdb-document-parameters.patch +++ linux-2.6.24/patches/0007-kgdb-document-parameters.patch @@ -0,0 +1,33 @@ +From 65ad7528a06067b08e7a5b1834591a997a3c3dee Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Mon, 10 Mar 2008 08:41:28 +0100 +Subject: [PATCH 007/170] kgdb: document parameters + +document the kgdboc module/boot parameter. + +Signed-off-by: Jason Wessel +Signed-off-by: Jan Kiszka +Signed-off-by: Ingo Molnar +--- + Documentation/kernel-parameters.txt | 5 +++++ + 1 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt +index e862271..bad214a 100644 +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -896,6 +896,11 @@ and is between 256 and 4096 characters. It is defined in the file + kstack=N [X86-32,X86-64] Print N words from the kernel stack + in oops dumps. + ++ kgdboc= [HW] kgdb over consoles. ++ Requires a tty driver that supports console polling. ++ (only serial suported for now) ++ Format: [,baud] ++ + l2cr= [PPC] + + lapic [X86-32,APIC] Enable the local APIC even if BIOS +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0167-UBUNTU-Make-proc-version_signature-match-the-kernel-.patch +++ linux-2.6.24/patches/0167-UBUNTU-Make-proc-version_signature-match-the-kernel-.patch @@ -0,0 +1,37 @@ +From 8ec8e54a2e762f663ecc479d22aef5a81d537200 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Wed, 14 Oct 2009 15:11:36 -0500 +Subject: [PATCH 167/170] UBUNTU: Make /proc/version_signature match the kernel version OriginalAuthor: Steve Conklin + +Add the required text subsitution to have the kernel version +in /proc/version_signature, instead of "Unofficial". + +Signed-off-by: Steve Conklin +Signed-off-by: Tim Gardner +--- + debian/rules.d/6-binary-custom.mk | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/debian/rules.d/6-binary-custom.mk b/debian/rules.d/6-binary-custom.mk +index 48d5be4..9c38f85 100644 +--- a/debian/rules.d/6-binary-custom.mk ++++ b/debian/rules.d/6-binary-custom.mk +@@ -17,13 +17,14 @@ $(stampdir)/stamp-custom-prepare-%: debian/binary-custom.d/%/config.$(arch) \ + install -d $(origsrc) + install -d $(srcdir) + touch $(srcdir)/ubuntu-build ++ + find . \( -path ./debian -o -path ./.git -o -name .gitignore \) \ + -prune -o -print | cpio -dumpl $(origsrc) + for patch in `ls debian/binary-custom.d/$*/patchset/*.patch | sort`; do \ + echo $$patch; \ + patch -p1 -d $(origsrc) < $$patch ;\ + done +- cat $< > $(srcdir)/.config ++ cat $< | sed -e 's/.*CONFIG_VERSION_SIGNATURE.*/CONFIG_VERSION_SIGNATURE="Ubuntu $(release)-$(revision)-$*"/' > $(srcdir)/.config + $(kmake) -C $(origsrc) O=$(srcdir) silentoldconfig prepare scripts + touch $@ + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0128-UBUNTU-rebase-against-distro-version-Ubuntu-2.6.24-2.patch +++ linux-2.6.24/patches/0128-UBUNTU-rebase-against-distro-version-Ubuntu-2.6.24-2.patch @@ -0,0 +1,411 @@ +From 47c5069c84065e915c7bd2550fde46eb36f1a869 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 20:10:22 +0100 +Subject: [PATCH 128/170] UBUNTU: rebase against distro version Ubuntu-2.6.24-24.51 + +Note that we have rebased against distro version Ubuntu-2.6.24-24.51 and +pull in the distro changelog for that delta. + +Signed-off-by: Andy Whitcroft +--- + debian/changelog | 387 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 387 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 319920e..4f241ad 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,390 @@ ++linux (2.6.24-24.51netbook11) UNRELEASED; urgency=low ++ ++ CHANGELOG: Do not edit directly. Autogenerated at release. ++ CHANGELOG: Use the printchanges target to see the curent changes. ++ CHANGELOG: Use the insertchanges target to create the final log. ++ ++ [Distro Changes] ++ ++ * UBUNTU: SAUCE: do not make sysdev links for processors which are not booted ++ * SUNRPC: Fix autobind on cloned rpc clients ++ * UBUNTU: Start new release Ignore: yes ++ * UBUNTU: Ubuntu-2.6.24-24.51 ++ * UBUNTU: Deleted debian/scripts/misc/prepare-ppa-source Ignore: yes ++ * ACPI: Clear WAK_STS on resume ++ * UBUNTU: fix apparmor memory leak on deleted file ops ++ * 8250.c: port.lock is irq-safe ++ * serial: 8250: fix shared interrupts issues with SMP and RT kernels ++ * KVM: MMU: Add locking around kvm_mmu_slot_remove_write_access() ++ * Merge branch 'master' of git://kernel.ubuntu.com/abogani/ubuntu-hardy-rt into rtnext ++ * UBUNTU: Start new release Ignore: yes ++ * UBUNTU: rt: Updated PREEMPT_RT support to rt27 ++ * UBUNTU: Ubuntu-2.6.24-24.50 ++ * UBUNTU: Xen: Fix FTBS after Vmware TSC updates. ++ * UBUNTU: Bump ABI to -24 Ignore: yes ++ * UBUNTU: x86: Mark TSC synchronized on VMware. ++ * UBUNTU: x86: Skip verification by the watchdog for TSC clocksource. ++ * UBUNTU: x86: Use the synthetic TSC_RELIABLE bit to workaround virtualization anomalies. ++ * UBUNTU: x86: Hypervisor detection and get tsc_freq from hypervisor ++ * UBUNTU: x86: vmware: look for DMI string in the product serial key ++ * UBUNTU: x86: add a synthetic TSC_RELIABLE feature bit ++ * UBUNTU: x86: add X86_FEATURE_HYPERVISOR feature bit ++ * UBUNTU: SAUCE: Bluetooth USB: fix kernel panic during suspend while streaming audio to bluetooth headset ++ * UBUNTU: XEN: Enable architecture specific get_unmapped_area_topdown ++ * Fix memory corruption in console selection ++ * r8169: additional 8101 and 8102 support ++ * r8169: add hw start helpers for the 8168 and the 8101 ++ * r8169: add 8168/8101 registers description ++ * r8169: use pci_find_capability for the PCI-E features ++ * r8169: Tx performance tweak helper ++ * r8169: fix RxMissed register access ++ * UBUNTU: Start new release Ignore: yes ++ * UBUNTU: Ubuntu-2.6.24-23.49 ++ * UBUNTU: Start new release Ignore: yes ++ * UBUNTU: Merge of Ubuntu-2.6.24-23.48 security release ++ * UBUNTU: Ubuntu-2.6.24-23.48 ++ * ib700wdt.c - fix buffer_underflow bug ++ * Enforce a minimum SG_IO timeout ++ * net: Fix soft lockups/OOM issues w/ unix garbage collector ++ * Fix inotify watch removal/umount races ++ * libertas: fix buffer overrun ++ * ATM: CVE-2008-5079: duplicate listen() on socket corrupts the vcc table ++ * UBUNTU: Start new release Ubuntu-2.6.24-23.48 Ignore: yes ++ * UBUNTU: Ubuntu-2.6.24-23.47 ++ * UBUNTU: openvz: Adapt openvz patch to compile with improved tcp hash ++ * NIU: Bump driver version and release date. ++ * NIU: Fix BMAC alternate MAC address indexing. ++ * NIU: More BMAC alt MAC address fixes. ++ * TCP: Improve ipv4 established hash function. ++ * SPARC: Fix link errors with gcc-4.3 ++ * SPARC64: Loosen checks in exception table handling. ++ * UBUNTU: Enable CONFIG_NFSD_V4=y in -virtual flavour. Bug: #224138 ++ * UBUNTU: Enable USB serial support on sparc ++ * UBUNTU: ACPI: Add DMI check to disable power state check in power transition ++ * UBUNTU: ACPI: Attach the ACPI device to the ACPI handle as early as possible ++ * UBUNTU: Add "acpi.power_nocheck=1" to disable power state check in power transition ++ * UBUNTU: Start new release Ubuntu-2.6.24-23.47 Ignore: yes ++ * UBUNTU: drm/i915 fixes to AR register restore Bug: #302421 ++ * UBUNTU: Minor teak to the 2.6.24-23.46 changelog. Ignore: yes ++ * UBUNTU: Ubuntu-2.6.24-23.46 ++ * UBUNTU: XEN: Fix FTBS with stable updates ++ * UBUNTU: Update openvz patchset to apply to latest stable tree. ++ * UBUNTU: rt: Updated PREEMPT_RT support to rt21 ++ * Linux 2.6.24.6 ++ * V4L: Fix VIDIOCGAP corruption in ivtv ++ * USB: remove broken usb-serial num_endpoints check ++ * Increase the max_burst threshold from 3 to tp->reordering. ++ * JFFS2: Fix free space leak with in-band cleanmarkers ++ * USB: gadget: queue usb USB_CDC_GET_ENCAPSULATED_RESPONSE message ++ * fix oops on rmmod capidrv ++ * splice: use mapping_gfp_mask ++ * Linux 2.6.24.5 ++ * locks: fix possible infinite loop in fcntl(F_SETLKW) over nfs ++ * file capabilities: remove cap_task_kill() ++ * macb: Call phy_disconnect on removing ++ * fbdev: fix /proc/fb oops after module removal ++ * acpi: bus: check once more for an empty list after locking it ++ * PARISC fix signal trampoline cache flushing ++ * PARISC pdc_console: fix bizarre panic on boot ++ * PARISC futex: special case cmpxchg NULL in kernel space ++ * POWERPC: Fix build of modular drivers/macintosh/apm_emu.c ++ * signalfd: fix for incorrect SI_QUEUE user data reporting ++ * plip: replace spin_lock_irq with spin_lock_irqsave in irq context ++ * HFS+: fix unlink of links ++ * DVB: tda10086: make the 22kHz tone for DISEQC a config option ++ * SPARC64: Fix FPU saving in 64-bit signal handling. ++ * bluetooth: hci_core: defer hci_unregister_sysfs() ++ * sis190: read the mac address from the eeprom first ++ * libata: assume no device is attached if both IDENTIFYs are aborted ++ * SPARC64: flush_ptrace_access() needs preemption disable. ++ * SPARC64: Fix __get_cpu_var in preemption-enabled area. ++ * SPARC64: Fix atomic backoff limit. ++ * VLAN: Don't copy ALLMULTI/PROMISC flags from underlying device ++ * TCP: Let skbs grow over a page on fast peers ++ * TCP: Fix shrinking windows with window scaling ++ * NET: Fix multicast device ioctl checks ++ * SCTP: Fix local_addr deletions during list traversals. ++ * sch_htb: fix "too many events" situation ++ * NET: Add preemption point in qdisc_run ++ * PPPOL2TP: Fix SMP issues in skb reorder queue handling ++ * PPPOL2TP: Make locking calls softirq-safe ++ * netpoll: zap_completion_queue: adjust skb->users counter ++ * LLC: Restrict LLC sockets to root ++ * INET: inet_frag_evictor() must run with BH disabled ++ * SUNGEM: Fix NAPI assertion failure. ++ * NET: include into linux/ethtool.h for __u* typedef ++ * AX25 ax25_out: check skb for NULL in ax25_kick() ++ * ipmi: change device node ordering to reflect probe order ++ * mtd: fix broken state in CFI driver caused by FL_SHUTDOWN ++ * CRYPTO xcbc: Fix crash when ipsec uses xcbc-mac with big data chunk ++ * USB: serial: ti_usb_3410_5052: Correct TUSB3410 endpoint requirements. ++ * USB: serial: fix regression in Visor/Palm OS module for kernels >= 2.6.24 ++ * USB: Allow initialization of broken keyspan serial adapters. ++ * vmcoreinfo: add the symbol "phys_base" ++ * pci: revert SMBus unhide on HP Compaq nx6110 ++ * vfs: fix data leak in nobh_write_end() ++ * alloc_percpu() fails to allocate percpu data ++ * PERCPU : __percpu_alloc_mask() can dynamically size percpu_data storage ++ * xen: fix UP setup of shared_info ++ * xen: mask out SEP from CPUID ++ * xen: fix RMW when unmasking events ++ * slab: fix cache_cache bootstrap in kmem_cache_init() ++ * NOHZ: reevaluate idle sleep length after add_timer_on() ++ * USB: new quirk flag to avoid Set-Interface ++ * UIO: add pgprot_noncached() to UIO mmap code ++ * V4L: ivtv: Add missing sg_init_table() ++ * md: remove the 'super' sysfs attribute from devices in an 'md' array ++ * mtd: memory corruption in block2mtd.c ++ * kbuild: soften modpost checks when doing cross builds ++ * time: prevent the loop in timespec_add_ns() from being optimised away ++ * Linux 2.6.24.4 ++ * S390 futex: let futex_atomic_cmpxchg_pt survive early functional tests. ++ * slab: NUMA slab allocator migration bugfix ++ * relay: fix subbuf_splice_actor() adding too many pages ++ * BLUETOOTH: Fix bugs in previous conn add/del workqueue changes. ++ * SCSI advansys: Fix bug in AdvLoadMicrocode ++ * async_tx: avoid the async xor_zero_sum path when src_cnt > device->max_xor ++ * aio: bad AIO race in aio_complete() leads to process hang ++ * jbd: correctly unescape journal data blocks ++ * jbd2: correctly unescape journal data blocks ++ * zisofs: fix readpage() outside i_size ++ * NETFILTER: nfnetlink_log: fix computation of netlink skb size ++ * NETFILTER: nfnetlink_queue: fix computation of allocated size for netlink skb ++ * NETFILTER: xt_time: fix failure to match on Sundays ++ * sched_nr_migrate wrong mode bits ++ * nfsd: fix oops on access from high-numbered ports ++ * sched: fix race in schedule() ++ * SCSI: gdth: bugfix for the at-exit problems ++ * Fix default compose table initialization ++ * x86: don't use P6_NOPs if compiling with CONFIG_X86_GENERIC ++ * SCSI: fix BUG when sum(scatterlist) > bufflen ++ * USB: ftdi_sio - really enable EM1010PC ++ * USB: ftdi_sio: Workaround for broken Matrix Orbital serial port ++ * VT notifier fix for VT switch ++ * ioat: fix 'ack' handling, driver must ensure that 'ack' is zero ++ * macb: Fix speed setting ++ * x86: move out tick_nohz_stop_sched_tick() call from the loop ++ * atmel_spi: fix clock polarity ++ * e1000e: Fix CRC stripping in hardware context bug ++ * PCI x86: always use conf1 to access config space below 256 bytes ++ * moduleparam: fix alpha, ia64 and ppc64 compile failures ++ * pata_hpt*, pata_serverworks: fix UDMA masking ++ * SCSI advansys: fix overrun_buf aligned bug ++ * NETFILTER: fix ebtable targets return ++ * NETFILTER: Fix incorrect use of skb_make_writable ++ * spi: pxa2xx_spi clock polarity fix ++ * ufs: fix parenthesisation in ufs_set_fs_state() ++ * hugetlb: ensure we do not reference a surplus page after handing it to buddy ++ * file capabilities: simplify signal check ++ * futex: runtime enable pi and robust functionality ++ * futex: fix init order ++ * ARM pxa: fix clock lookup to find specific device clocks ++ * x86: replace LOCK_PREFIX in futex.h ++ * SCSI aic94xx: fix REQ_TASK_ABORT and REQ_DEVICE_RESET ++ * SCSI ips: fix data buffer accessors conversion bug ++ * CRYPTO xts: Use proper alignment ++ * CRYPTO xcbc: Fix crash with IPsec ++ * SCSI ips: handle scsi_add_host() failure, and other err cleanups ++ * x86: adjust enable_NMI_through_LVT0() ++ * ub: fix up the conversion to sg_init_table() ++ * MIPS: Mark all but i8259 interrupts as no-probe. ++ * IRQ_NOPROBE helper functions ++ * IPCOMP: Disable BH on output when using shared tfm ++ * IPCONFIG: The kernel gets no IP from some DHCP servers ++ * IPV4: Remove IP_TOS setting privilege checks. ++ * IPV6: dst_entry leak in ip4ip6_err. ++ * IPV6: Fix IPsec datagram fragmentation ++ * NET: Fix race in dev_close(). (Bug 9750) ++ * UBUNTU: Merging back Ubuntu-2.6.24-22.45 security release ++ * UBUNTU: Ubuntu-2.6.24-23.46 ++ * UBUNTU: Merged security Ubuntu-2.6.24-22.45 Ignore: yes ++ * UBUNTU: Ubuntu-2.6.24-22.45 ++ * V4L/DVB (9621): Avoid writing outside shadow.bytes[] array ++ * hfs: fix namelength memory corruption ++ * security: avoid calling a NULL function pointer in drivers/video/tvaudio.c ++ * net: unix: fix inflight counting bug in garbage collector ++ * UBUNTU: Bump ABI to -22 ++ * net: Fix recursive descent in __scm_destroy(). ++ * Merge branch 'LP140608-hardy' ++ * UBUNTU: [PATCH] UBUNTU: Add HID quirk for dual USB gamepad Bug: 140608 ++ * hfsplus: check read_mapping_page() return value ++ * hfsplus: fix Buffer overflow with a corrupted image ++ * sctp: Fix kernel panic while process protocol violation parameter ++ * sctp: Fix oops when INIT-ACK indicates that peer doesn't support AUTH ++ * Don't allow splice() to files opened with O_APPEND ++ * UBUNTU: Start new release Ubuntu-2.6.24-21.45 ++ * x86-64: Fix "bytes left to copy" return value for copy_from_user() ++ * UBUNTU: Xen: dma: avoid unnecessarily SWIOTLB bounce buffering ++ * Merge branch 'openvz' ++ * UBUNTU: Start new release Ubuntu-2.6.24-22.45 Ignore: yes ++ * Merge branch 'proposed' ++ * Merge branch 'openvz' of git://git.openvz.org/pub/ubuntu-hardy-openvz into openvz ++ * UBUNTU: Ubuntu-2.6.24-22.44 ++ * UBUNTU: SAUCE: replace gfs2_bitfit with upstream version to prevent oops ++ * openvz: fix OOPS while stopping VE started before binfmt_misc.ko loaded ++ * openvz: fix wrong size of ub0_percpu ++ * openvz: fix netlink and rtnl inside container ++ * openvz: fix ve stop deadlock after nfs connect ++ * openvz: some autofs related fixes ++ * openvz: merge missed fixes from vanilla 2.6.24 openvz branch ++ * UBUNTU: buildenv: Send git-ubuntu-log informational message to stderr ++ * UBUNTU: SAUCE: buildenv: Show CVE entries in printchanges ++ * UBUNTU: SAUCE: Update lpia patches from moblin tree Bug: #291457 ++ * UBUNTU: Start new release Ubuntu-2.6.24-22.44 Ignore: yes ++ * UBUNTU: Merged Ubuntu-2.6.24-21.43 security release Ignore: yes ++ * UBUNTU: Ubuntu-2.6.24-21.43 ++ * Only allow access to DRM_I915_HWS_ADDR ioctl() for Xserver. ++ * UBUNTU: Enable CONFIG_DEBUG_RODATA=y for all architectures. ++ * sctp: fix random memory dereference with SCTP_HMAC_IDENT option. ++ * nfsd: fix buffer overrun decoding NFSv4 acl ++ * sctp: fix potential panics in the SCTP-AUTH API. ++ * Incorrect length was used in SCTP_*_AUTH_CHUNKS socket option ++ * Fix off-by-one error in iov_iter_advance() ++ * iov_iter_advance() fix ++ * fbdefio: add set_page_dirty handler to deferred IO FB ++ * tmpfs: fix kernel BUG in shmem_delete_inode ++ * sctp: add verification checks to SCTP_AUTH_KEY option ++ * wan: Missing capability checks in sbni_ioctl() ++ * Fix ZERO_PAGE breakage with vmware ++ * UBUNTU: SAUCE: ALPS touchpad for Dell Latitude E6500/E6400 ++ * UBUNTU: SAUCE: Correctly blacklist Thinkpad r40e in ACPI OriginalAuthor: martin@objectgizmos.com OriginalLocation: http://launchpadlibrarian.net/18243520/ubuntu-hardy-processor_idle.diff Bug: #278794 ++ * UBUNTU: Start new release Ubuntu-2.6.24-21.43 Ignore: yes ++ * x86: Reserve FIRST_DEVICE_VECTOR in used_vectors bitmap. ++ * Revert "[Bluetooth] Eliminate checks for impossible conditions in IRQ handler" ++ * b43legacy: Fix failure in rate-adjustment mechanism Bug: #273143 ++ * x86: Fix 32-bit x86 MSI-X allocation leakage ++ * USB: serial: ch341: New VID/PID for CH341 USB-serial Bug: #272485 ++ * Fix off-by-one error in iov_iter_advance() ++ * iov_iter_advance() fix ++ * KVM: VMX: Clear CR4.VMXE in hardware_disable Bug: #268981 ++ * UBUNTU: md: fix an occasional deadlock in raid5 OriginalAuthor: Neil Brown Bug: #208551 ++ * UBUNTU: USB: add support for Motorola ROKR Z6 cellphone in mass storage mode OriginalAuthor: Constantin Baranov Bug: #263217 ++ * UBUNTU: hwmon: (coretemp) Add Penryn CPU to coretemp OriginalAuthor: Rudolf Marek Bug: #235119 ++ * UBUNTU: isdn: Do not validate ISDN net device address prior to interface-up OriginalAuthor: Paul Bolle Bug: #237306 ++ * UBUNTU: Bump ABI to -22 Ignore: yes ++ * UBUNTU: Enable CONFIG_AX25_DAMA_SLAVE=y ++ * UBUNTU: Start new release Ubuntu-2.6.24-21.43 Ignore: yes ++ * UBUNTU: Ubuntu-2.6.24-21.42 Ignore: yes ++ * UBUNTU: Ubuntu-2.6.24-21.42 ++ * Revert "UBUNTU: Enable CONFIG_AX25_DAMA_SLAVE=y" ++ * x86, gart: add resume handling ++ * suspend-vs-iommu: prevent suspend if we could not resume ++ * UBUNTU: Remove some old ABI files Ignore: yes ++ * UBUNTU: Merged with Ubuntu-2.6.24-19.41 ++ * (CVE-2008-3276) dccp: change L/R must have at least one byte in the dccpsf_val field ++ * (CVE-2008-3276) dccp: change L/R must have at least one byte in the dccpsf_val field ++ * UBUNTU: Pulled in 2.6.24-19.41 Ignore: yes ++ * netfilter: nf_nat_snmp_basic: fix a range check in NAT for SNMP ++ * Fix compiler warning on 64-bit ++ * UBUNTU: Enabled CONFIG_NF_CT_NETLINK/CONFIG_NF_CONNTRACK_EVENTS in -virtual flavour. Bug: #257569 ++ * r8169: avoid thrashing PCI conf space above RTL_GIGA_MAC_VER_06 Bug: #141343 ++ * SCSI: gdth: fix to internal commands execution ++ * gdth: don't call pci_free_consistent under spinlock ++ * UBUNTU: Print bug reference number for upstream changes ++ * eCryptfs: make ecryptfs_prepare_write decrypt the page Bug: #242448 ++ * UBUNTU: b43 - Add Dell adapter to Bluetooth coexiastence check. OriginalAuthor: Larry Finger Bug: #257020 ++ * acpi: unneccessary to scan the PCI bus already scanned Bug: #258143 http://bugzilla.kernel.org/show_bug.cgi?id=10124 ++ * Merge branch 'openvz' of git://git.openvz.org/pub/ubuntu-hardy-openvz into openvz ++ * USB: quirk PLL power down mode Bug: #257931 ++ * openvz: sync with stable 2.6.18-rhel5 branch ++ * UBUNTU: Bump ABI to -22 Ignore: yes ++ * UBUNTU: Enable CONFIG_AX25_DAMA_SLAVE=y Bug: #257684 ++ * UBUNTU: Start new release Ignore: yes ++ * eCryptfs: use page_alloc not kmalloc to get a page of memory Bug: #242448 ++ * UBUNTU: Bump ABI to -21 Ignore: yes ++ * UBUNTU: Ubuntu-2.6.24-20.40 Ignore: yes ++ * b43: Add more btcoexist workarounds Bug: #257020 ++ * UBUNTU: Ubuntu-2.6.24-20.39 ++ * UBUNTU: if_arp: add a WiMax pseudo header ++ * UBUNTU: rfkill: add the WiMAX radio type ++ * UBUNTU: SAUCE: Fix FTBS on amd64 introduced by previous commit. ++ * UBUNTU: Backport make USB-PERSIST work after every system sleep ++ * UBUNTU: SAUCE: Add reboot=a preselection quirk ++ * UBUNTU: SAUCE: Add the ability to whitelist systems to use ACPI reboot ++ * UBUNTU: Backport ability to reset the machine using the RESET_REG of ACPI ++ * UBUNTU: Start new release ++ * Merge branch 'proposed' ++ * Fix typos from signal_32/64.h merge Bug: #230315 ++ * md: close a livelock window in handle_parity_checks5 Bug: #244377 ++ * sky2: 88E8040T pci device id Bug: #237211 ++ * [NETFILTER]: {ip,ip6,nfnetlink}_queue: fix SKB_LINEAR_ASSERT when mangling packet data Bug: #236699 ++ * V4L/DVB (7068): Add support for WinTV Nova-T-CE driver Bug: #238164 ++ * UBUNTU: Start new release Ignore: yes ++ * UBUNTU: Disable CHROME9 for sparc, ia64, and powerpc Ignore: yes ++ * UBUNTU: Define TRUE/FALSE for Chrome 9 headers ++ * UBUNTU: Ubuntu-2.6.24-20.38 Ignore: yes ++ * x86: lfence fix ++ * UBUNTU: Start new release 2.6.24-20.38 Ignore: yes ++ * Revert "UBUNTU: Start new release 21.37" ++ * x86: fix bootup crash in native_read_tsc() (aka use XMM2) Bug : #249135 ++ * UBUNTU: Enable VIA Chrome 9 DRM 3D Engines Ignore: yes ++ * UBUNTU: VIA - Add VIA DRM Chrome9 3D engine OriginalAuthor: Bruce.C.Chang Bug: #251862 ++ * UBUNTU: VIA AGP VT3364 is not detected OriginalAuthor: Bruce.C.Chang Bug: #251854 ++ * create sysfs link from acpi device to sysdev for cpu ++ * force offline the processor during hot-removal ++ * fix a deadlock issue when poking "eject" file ++ * flush kacpi_notify_wq before removing notify handler ++ * x86: fix paranoia about using BIOS quickboot mechanism. ++ * acpi: fix "buggy BIOS check" when CPUs are hot removed ++ * UBUNTU: Enable TULIP ethernet support in virtual appliance flavour Bug: #250857 ++ * UBUNTU: SAUCE: Export usbhid_modify_dquirk for LBM module bcm5974 Bug: #250838 ++ * net/usb: add support for Apple USB Ethernet Adapter Bug: #232200 ++ * UBUNTU: Start new release 21.37 Ignore: yes ++ * UBUNTU: Ubuntu-2.6.24-20.37 Ignore: yes ++ * x86: remove 6 bank limitation in 64 bit MCE reporting code Bug: #239666 ++ * Revert "eCryptfs: remove unnecessary page decrypt call" ++ * UBUNTU: ACPI: EC: Some hardware requires burst mode to operate properly ++ * UBUNTU: ACPI: EC: Do the byte access with a fast path ++ * UBUNTU: Default CONCURRENCY_LEVEL to the number of CPUs*2 Ignore: yes ++ * UBUNTU: Renamed ABIs to 2.6.24-19.36 Ignore: yes ++ * UBUNTU: Merged with hardy-security Ignore: yes ++ * UBUNTU: Rename debian/abi/2.6.24-19.34 to debian/abi/2.6.24-19.35 Ignore: yes ++ * UBUNTU: Cleanup xen patchset to remove .orig and .rej files Ignore: yes ++ * UBUNTU: Start new release Ignore: yes ++ * UBUNTU: Ubuntu-2.6.24-19.35 Ignore: yes ++ * UBUNTU: Clear host capabilities number of ports after quirking JMB361 OriginalAuthor: Marius Gedminas Bug: #244363 ++ * UBUNTU: ahci: jmb361 has only one port Bug: #244363 ++ * UBUNTU: Reinstate ZERO_PAGE optimization in 'get_user_pages()' and fix XIP Bug: #246663 OriginalLocation: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=89f5b7da2a6bad2e84670422ab8192382a5aeb9f ++ * Merge branch 'openvz' of git://git.openvz.org/pub/ubuntu-hardy-openvz ++ * UBUNTU: SAUCE: Send HCI_RESET for Broadcomm 2046 Bug: #241749 ++ * UBUNTU SAUCE: Update rtl8101/2(e) hardware initialization value OriginalAuthor: From Realtek. Bug: #240648 ++ * UBUNTU SAUCE: Setup PHYs correctly on rtl8101/2(e) hardware ++ * openvz: sync with stable 2.6.18-rhel5 branch ++ * inotify: remove debug code Bug: #104837 ++ * inotify: fix race Bug: #104837 ++ * UBUNTU: Enable CONFIG_CIFS_UPCALL=y to support Kerberos authentication OriginalAuthor: Steve Langasek OriginalLocation: http://launchpadlibrarian.net/15159794/linux-cifs-experimental.diff Bug: #236830 ++ * UBUNTU: Slim USB Apple Keyboard not working correctly when pressing the "numlock" key OriginalAuthor: Diego 'Flameeyes' Petteno Bug: #201887 ++ * hwmon: (w83781d) Fix I/O resource conflict with PNP Bug: #242761 ++ * UBUNTU: Enabled hppa CONFIG_EXT{23)_FS_POSIX_ACL=y and CONFIG_EXT{23}_FS_SECURITY=y Ignore: yes ++ * UBUNTU: Enabled hppa CONFIG_EXT2_FS=m and CONFIG_EXT3_FS=m Ignore: yes ++ * UBUNTU: Enable POSIX_ACL/SECURITY/XATTR for hppa Ignore: yes ++ * eCryptfs: remove unnecessary page decrypt call Bug: #242448 upstream commit: d3e49afbb66109613c3474f2273f5830ac2dcb09 ++ * UBUNTU: SAUCE: e1000 checksum recheck after reset Bug: #60388 ++ * UBUNTU: scheduling while atomic: archhttp64/7146/0x1000000001 OriginalAuthor: Daniel Drake Bug: #235889 ++ * UBUNTU: cpuidle acpi driver: fix oops on AC<->DC Bug: #241229 ++ * UBUNTU: ACPI: Fix acpi_processor_idle and idle= boot parameters interaction Bug: #241229 ++ * UBUNTU: Enabled CONFIG_NETDEVICES_MULTIQUEUE=y in order to support 802.11n Bug: #241423 ++ * UBUNTU: Renamed ABI files to debian/abi/2.6.24-19.34 Ignore: yes ++ * UBUNTU: Bump ABI to -20 Ignore: yes ++ * Merge branch 'master' of /usr3/ubuntu/ubuntu-hardy into tsc ++ * UBUNTU: ACPICA: Fix for resource descriptor optimization issues for _CRS/_SRC ++ * UBUNTU: Modify log generation to catch bug numbers when adding with git-am. ++ * UBUNTU: drivers: fix dma_get_required_mask Bug: #238118 ++ * UBUNTU: Start new release Ignore: yes ++ * UBUNTU: Use readtsc-barrier in xen ++ * Add barriers to native_read_tsc ++ * UBUNTU: Fix x86-64 FTBS after upstream cherry-pick of 898ad535e2c81e0b02628c1ee5d8400c971500dd ++ * UBUNTU: Add native_read_tsc to non __i386__ code. ++ * x86: read_tsc sync ++ * x86: remove get_cycles_sync ++ * x86: introduce rdtsc_barrier() ++ * x86: move nop declarations into separate include file ++ * x86: Implement support to synchronize RDTSC with LFENCE on Intel CPUs ++ * x86: implement support to synchronize RDTSC through MFENCE on AMD CPUs ++ * x86: tsc prevent time going backwards ++ ++ -- Andy Whitcroft Fri, 03 Apr 2009 19:06:38 +0000 ++ + linux (2.6.24-22.45netbook10) netbook-common; urgency=low + + [Upstream Kernel Changes] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0055-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook1.patch +++ linux-2.6.24/patches/0055-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook1.patch @@ -0,0 +1,30 @@ +From 6b2bd3b29a7bdc8fd4384e487bca51972c637f3e Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Thu, 4 Sep 2008 10:54:36 -0400 +Subject: [PATCH 055/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook1 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index c30a7fc..3de55d1 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-19.41netbook1) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * Bump release ++ ++ -- Michael Frey Thu, 04 Sep 2008 10:52:48 -0400 ++ + linux (2.6.24-19.36netbook3) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0162-UBUNTU-rebase-onto-Ubuntu-2.6.24-24.59.patch +++ linux-2.6.24/patches/0162-UBUNTU-rebase-onto-Ubuntu-2.6.24-24.59.patch @@ -0,0 +1,33 @@ +From 2f66f44949f01c52696da4dc22273df8f0583c03 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 21 Aug 2009 12:45:04 +0100 +Subject: [PATCH 162/170] UBUNTU: rebase onto Ubuntu-2.6.24-24.59 + +Signed-off-by: Andy Whitcroft +--- + debian/changelog | 7 ++++++- + 1 files changed, 6 insertions(+), 1 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index fbcacdf..9318ebf 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,9 +1,14 @@ +-linux (2.6.24-24.57netbook02) UNRELEASED; urgency=low ++linux (2.6.24-24.59netbook01) UNRELEASED; urgency=low + + CHANGELOG: Do not edit directly. Autogenerated at release. + CHANGELOG: Use the printchanges target to see the curent changes. + CHANGELOG: Use the insertchanges target to create the final log. + ++ [ Ubuntu: 2.6.24-24.59 ] ++ ++ * Make sock_sendpage() use kernel_sendpage() ++ - CVE-2009-2692 ++ + -- Andy Whitcroft Fri, 21 Aug 2009 12:27:50 +0100 + + linux (2.6.24-24.57netbook01) netbook-common; urgency=low +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0025-kgdb-modules-This-allows-for-KGDB-to-better-deal-wit.patch +++ linux-2.6.24/patches/0025-kgdb-modules-This-allows-for-KGDB-to-better-deal-wit.patch @@ -0,0 +1,194 @@ +From b25e3160396019bd72cc75933b5eebc540e11dcf Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:45 -0500 +Subject: [PATCH 025/170] kgdb, modules: This allows for KGDB to better deal with autoloaded modules. + +With more information in the kernel, gdb can be modified in such a way +as to automatically read the kernel module section information and +allow for easy kernel module debugging. + +In gdb the solib-search-path must contain the location of any module +to be debugged. When a module is loaded GDB acts like a shared +library has been loaded and will collect the information about the +memory location so the kernel module can be debugged or inspected. + +Even when not using kgdb+gdb, it is quite useful for a +debugger+ICE/jtag to have the module section information, which +can be obtained by configure KGDB into the kernel or using +CONFIG_KALLSYMS. + +Signed-off-by: Jason Wessel +--- + include/linux/module.h | 8 +++++--- + kernel/kgdb.c | 17 +++++++++++++++++ + kernel/module.c | 31 ++++++++++++++++++++----------- + lib/Kconfig.kgdb | 8 ++++++++ + 4 files changed, 50 insertions(+), 14 deletions(-) + +diff --git a/include/linux/module.h b/include/linux/module.h +index 2cbc0b8..37cde1d 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -342,13 +342,15 @@ struct module + unsigned long num_symtab; + char *strtab; + +- /* Section attributes */ +- struct module_sect_attrs *sect_attrs; +- + /* Notes attributes */ + struct module_notes_attrs *notes_attrs; + #endif + ++#if defined(CONFIG_KALLSYMS) || defined(CONFIG_KGDB_MODULES) ++ /* Section attributes */ ++ struct module_sect_attrs *sect_attrs; ++#endif ++ + /* Per-cpu data. */ + void *percpu; + +diff --git a/kernel/kgdb.c b/kernel/kgdb.c +index 22285c4..476bb3b 100644 +--- a/kernel/kgdb.c ++++ b/kernel/kgdb.c +@@ -1498,6 +1498,21 @@ kgdb_restore: + return error; + } + ++/* ++ * GDB places a breakpoint at this function to know dynamically ++ * loaded objects. It's not defined static so that only one instance with this ++ * name exists in the kernel. ++ */ ++ ++int module_event(struct notifier_block *self, unsigned long val, void *data) ++{ ++ return 0; ++} ++ ++static struct notifier_block kgdb_module_load_nb = { ++ .notifier_call = module_event, ++}; ++ + int kgdb_nmicallback(int cpu, void *regs) + { + #ifdef CONFIG_SMP +@@ -1594,6 +1609,7 @@ static void kgdb_register_callbacks(void) + if (!kgdb_io_module_registered) { + kgdb_io_module_registered = 1; + kgdb_arch_init(); ++ register_module_notifier(&kgdb_module_load_nb); + register_reboot_notifier(&kgdb_reboot_notifier); + #ifdef CONFIG_MAGIC_SYSRQ + register_sysrq_key('g', &sysrq_gdb_op); +@@ -1614,6 +1630,7 @@ static void kgdb_unregister_callbacks(void) + */ + if (kgdb_io_module_registered) { + unregister_reboot_notifier(&kgdb_reboot_notifier); ++ unregister_module_notifier(&kgdb_module_load_nb); + kgdb_io_module_registered = 0; + kgdb_arch_exit(); + #ifdef CONFIG_MAGIC_SYSRQ +diff --git a/kernel/module.c b/kernel/module.c +index c2e3e2e..4556581 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -580,6 +580,9 @@ static void module_unload_free(struct module *mod) + } + } + } ++ blocking_notifier_call_chain(&module_notify_list, ++ MODULE_STATE_GOING, ++ mod); + } + + #ifdef CONFIG_MODULE_FORCE_UNLOAD +@@ -967,6 +970,7 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, + * /sys/module/foo/sections stuff + * J. Corbet + */ ++#if (defined(CONFIG_KGDB_MODULES) || defined(CONFIG_KALLSYMS)) + #ifdef CONFIG_KALLSYMS + static ssize_t module_sect_show(struct module_attribute *mattr, + struct module *mod, char *buf) +@@ -975,6 +979,7 @@ static ssize_t module_sect_show(struct module_attribute *mattr, + container_of(mattr, struct module_sect_attr, mattr); + return sprintf(buf, "0x%lx\n", sattr->address); + } ++#endif /* CONFIG_KALLSYMS */ + + static void free_sect_attrs(struct module_sect_attrs *sect_attrs) + { +@@ -1021,7 +1026,9 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, + if (sattr->name == NULL) + goto out; + sect_attrs->nsections++; ++#ifdef CONFIG_KALLSYMS + sattr->mattr.show = module_sect_show; ++#endif + sattr->mattr.store = NULL; + sattr->mattr.attr.name = sattr->name; + sattr->mattr.attr.mode = S_IRUGO; +@@ -1049,7 +1056,20 @@ static void remove_sect_attrs(struct module *mod) + mod->sect_attrs = NULL; + } + } ++#else /* ! (CONFIG_KALLSYMS || CONFIG_KGDB_MODULES) */ ++ ++static inline void add_sect_attrs(struct module *mod, unsigned int nsect, ++ char *sectstrings, Elf_Shdr *sechdrs) ++{ ++} ++ ++static inline void remove_sect_attrs(struct module *mod) ++{ ++} + ++#endif /* CONFIG_KALLSYMS || CONFIG_KGDB_MODULES */ ++ ++#ifdef CONFIG_KALLSYMS + /* + * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections. + */ +@@ -1143,18 +1163,7 @@ static void remove_notes_attrs(struct module *mod) + if (mod->notes_attrs) + free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes); + } +- + #else +- +-static inline void add_sect_attrs(struct module *mod, unsigned int nsect, +- char *sectstrings, Elf_Shdr *sechdrs) +-{ +-} +- +-static inline void remove_sect_attrs(struct module *mod) +-{ +-} +- + static inline void add_notes_attrs(struct module *mod, unsigned int nsect, + char *sectstrings, Elf_Shdr *sechdrs) + { +diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb +index f2e01ac..0c359dd 100644 +--- a/lib/Kconfig.kgdb ++++ b/lib/Kconfig.kgdb +@@ -16,6 +16,14 @@ config HAVE_ARCH_KGDB_SHADOW_INFO + config HAVE_ARCH_KGDB + bool + ++config KGDB_MODULES ++ bool "KGDB: Debug modules without KALLSYMS" ++ depends on KGDB && !KALLSYMS && SYSFS ++ default y ++ help ++ This option allows you to debug kernel modules with a ++ kernel module aware debugger without using KALLSYMS. ++ + config KGDB_SERIAL_CONSOLE + tristate "KGDB: use kgdb over the serial console" + depends on KGDB +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0160-UBUNTU-re-re-re-fix-pocket-name.patch +++ linux-2.6.24/patches/0160-UBUNTU-re-re-re-fix-pocket-name.patch @@ -0,0 +1,24 @@ +From ad341262197cceb72476efd4f9452328787c6c3e Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Tue, 4 Aug 2009 17:12:22 +0100 +Subject: [PATCH 160/170] UBUNTU: re-re-re fix pocket name + +Ignore: yes +Signed-off-by: Andy Whitcroft +--- + debian/changelog | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 86a05e5..4b6af13 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,4 +1,4 @@ +-linux (2.6.24-24.57netbook01) netboot-common; urgency=low ++linux (2.6.24-24.57netbook01) netbook-common; urgency=low + + [ Andy Whitcroft ] + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0126-Turn-debian-binary-custom.d-lpia-patchset-0022-usb_r.patch +++ linux-2.6.24/patches/0126-Turn-debian-binary-custom.d-lpia-patchset-0022-usb_r.patch @@ -0,0 +1,183 @@ +From a5e86df9e1a11b7c10267a7fc9ca032fbbf66db2 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:34 +0100 +Subject: [PATCH 126/170] Turn debian/binary-custom.d/lpia/patchset/0022-usb_reset_resume_quirk.patch into a commit. + +Signed-off-by: Andy Whitcroft + +commit 0f01dfe672c8927bd3968306732ca63066fc0b4b +Author: Amit Kucheria +Date: Tue Apr 1 00:36:28 2008 +0300 + + UBUNTU: LPIA: Update from moblin + + * Better way to fix reset_resume quirk USB devices and replaced previous patch + * Reduce SiB's extra delay from 100ms to 25ms + + Signed-off-by: Amit Kucheria +--- + .../patchset/0022-usb_reset_resume_quirk.patch | 75 -------------------- + drivers/usb/core/driver.c | 13 +++- + drivers/usb/core/hub.c | 3 +- + drivers/usb/core/quirks.c | 2 + + 4 files changed, 15 insertions(+), 78 deletions(-) + delete mode 100644 debian/binary-custom.d/lpia/patchset/0022-usb_reset_resume_quirk.patch + +diff --git a/debian/binary-custom.d/lpia/patchset/0022-usb_reset_resume_quirk.patch b/debian/binary-custom.d/lpia/patchset/0022-usb_reset_resume_quirk.patch +deleted file mode 100644 +index 9cc4436..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0022-usb_reset_resume_quirk.patch ++++ /dev/null +@@ -1,75 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c +-index c51f8e9..1a93989 100644 +---- a/drivers/usb/core/driver.c +-+++ b/drivers/usb/core/driver.c +-@@ -866,6 +866,9 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg) +- return status; +- } +- +-+struct usb_hub; +-+void hub_port_logical_disconnect(struct usb_hub *hub, int port1); +-+ +- /* Caller has locked intf's usb_device's pm_mutex */ +- static int usb_resume_interface(struct usb_interface *intf, int reset_resume) +- { +-@@ -894,9 +897,15 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) +- dev_err(&intf->dev, "%s error %d\n", +- "reset_resume", status); +- } else { +-- // status = -EOPNOTSUPP; +-+ struct usb_device *udev = interface_to_usbdev(intf); +-+ struct usb_device *parent_hdev = udev->parent; +-+ /* status = -EOPNOTSUPP; */ +- dev_warn(&intf->dev, "no %s for driver %s?\n", +- "reset_resume", driver->name); +-+ if (parent_hdev) { +-+ struct usb_hub *parent_hub = usb_get_intfdata(parent_hdev->actconfig->interface[0]); +-+ hub_port_logical_disconnect(parent_hub, udev->portnum); +-+ } +- } +- } else { +- if (driver->resume) { +-@@ -905,7 +914,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) +- dev_err(&intf->dev, "%s error %d\n", +- "resume", status); +- } else { +-- // status = -EOPNOTSUPP; +-+ /* status = -EOPNOTSUPP; */ +- dev_warn(&intf->dev, "no %s for driver %s?\n", +- "resume", driver->name); +- } +-diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +-index b04d232..ca269bb 100644 +---- a/drivers/usb/core/hub.c +-+++ b/drivers/usb/core/hub.c +-@@ -584,7 +584,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) +- * time later khubd will disconnect() any existing usb_device on the port +- * and will re-enumerate if there actually is a device attached. +- */ +--static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) +-+void hub_port_logical_disconnect(struct usb_hub *hub, int port1) +- { +- dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1); +- hub_port_disable(hub, port1, 1); +-@@ -601,6 +601,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) +- set_bit(port1, hub->change_bits); +- kick_khubd(hub); +- } +-+EXPORT_SYMBOL(hub_port_logical_disconnect); +- +- /* caller has locked the hub device */ +- static int hub_pre_reset(struct usb_interface *intf) +-diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +-index d42c561..d5e867d 100644 +---- a/drivers/usb/core/quirks.c +-+++ b/drivers/usb/core/quirks.c +-@@ -45,6 +45,8 @@ static const struct usb_device_id usb_quirk_list[] = { +- /* SKYMEDI USB_DRIVE */ +- { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, +- +-+ /* ASIX Ethernet device */ +-+ { USB_DEVICE(0x0b95, 0x1720), .driver_info = USB_QUIRK_RESET_RESUME }, +- { } /* terminating entry must be last */ +- }; +- +diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c +index b469718..f0061bc 100644 +--- a/drivers/usb/core/driver.c ++++ b/drivers/usb/core/driver.c +@@ -866,6 +866,9 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg) + return status; + } + ++struct usb_hub; ++void hub_port_logical_disconnect(struct usb_hub *hub, int port1); ++ + /* Caller has locked intf's usb_device's pm_mutex */ + static int usb_resume_interface(struct usb_interface *intf, int reset_resume) + { +@@ -894,9 +897,15 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) + dev_err(&intf->dev, "%s error %d\n", + "reset_resume", status); + } else { +- // status = -EOPNOTSUPP; ++ struct usb_device *udev = interface_to_usbdev(intf); ++ struct usb_device *parent_hdev = udev->parent; ++ /* status = -EOPNOTSUPP; */ + dev_warn(&intf->dev, "no %s for driver %s?\n", + "reset_resume", driver->name); ++ if (parent_hdev) { ++ struct usb_hub *parent_hub = usb_get_intfdata(parent_hdev->actconfig->interface[0]); ++ hub_port_logical_disconnect(parent_hub, udev->portnum); ++ } + } + } else { + if (driver->resume) { +@@ -905,7 +914,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) + dev_err(&intf->dev, "%s error %d\n", + "resume", status); + } else { +- // status = -EOPNOTSUPP; ++ /* status = -EOPNOTSUPP; */ + dev_warn(&intf->dev, "no %s for driver %s?\n", + "resume", driver->name); + } +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index e7dab8e..493135f 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -587,7 +587,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) + * time later khubd will disconnect() any existing usb_device on the port + * and will re-enumerate if there actually is a device attached. + */ +-static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) ++void hub_port_logical_disconnect(struct usb_hub *hub, int port1) + { + dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1); + hub_port_disable(hub, port1, 1); +@@ -604,6 +604,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) + set_bit(port1, hub->change_bits); + kick_khubd(hub); + } ++EXPORT_SYMBOL(hub_port_logical_disconnect); + + #define HUB_RESET 1 + #define HUB_RESUME 2 +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index fb552d7..b6d17d5 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -48,6 +48,8 @@ static const struct usb_device_id usb_quirk_list[] = { + /* SKYMEDI USB_DRIVE */ + { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, + ++ /* ASIX Ethernet device */ ++ { USB_DEVICE(0x0b95, 0x1720), .driver_info = USB_QUIRK_RESET_RESUME }, + { } /* terminating entry must be last */ + }; + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0111-Updated-touchpad-driver-from-Elantech.patch +++ linux-2.6.24/patches/0111-Updated-touchpad-driver-from-Elantech.patch @@ -0,0 +1,1386 @@ +From 17c92b1e3fbede38ade8cc3ee321a1635f11e420 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Thu, 26 Mar 2009 12:22:00 -0400 +Subject: [PATCH 111/170] Updated touchpad driver from Elantech + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/input/mouse/elantech.c | 1214 +++++++++++++++++++++++++++++++++++++--- + drivers/input/mouse/elantech.h | 2 +- + 2 files changed, 1139 insertions(+), 77 deletions(-) + +diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c +index ec8e489..9de43f6 100644 +--- a/drivers/input/mouse/elantech.c ++++ b/drivers/input/mouse/elantech.c +@@ -27,6 +27,7 @@ + #define ETP_RAW_MODE 0x04 + #define ETP_4_BYTE_MODE 0x02 + ++ + /* These values work with the touchpad on my laptop. Do they need adjustment? */ + #define ETP_XMIN 32 + #define ETP_XMAX 0x240 +@@ -124,6 +125,44 @@ static int elantech_write_reg_new(struct psmouse *psmouse, unsigned char reg, un + } + + ++static int elantech_write_reg_debug(struct psmouse *psmouse, unsigned char reg, unsigned char val) ++{ ++ ++ ++ //printk(KERN_DEBUG "+elantech_write_reg\n"); ++ ++ ++ //printk(KERN_DEBUG "reg=%x val=%x\n",reg,val); ++ if(elantech_ps2_command(psmouse,NULL,0x00f8) != 0) ++ return -1; ++ ++ if(reg==0x06){ ++ if(elantech_ps2_command(psmouse,NULL,0x0019) != 0) ++ return -1; ++ }else{ ++ if(elantech_ps2_command(psmouse,NULL,0x0011) != 0) ++ return -1; ++ } ++ ++ if(elantech_ps2_command(psmouse,NULL,0x00f8) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,reg) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,0x00f8) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,val) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,0x00e6) != 0) ++ return -1; ++ //printk(KERN_DEBUG "-elantech_write_reg\n"); ++ ++ return 0; ++} ++ + static int elantech_read_reg_new(struct psmouse *psmouse, unsigned char reg, unsigned char val) + { + int i; +@@ -656,14 +695,17 @@ static psmouse_ret_t elantech_process_6byte_EF113(struct psmouse *psmouse) + input_report_key(dev, BTN_TOOL_TRIPLETAP, z == 3); + + +- input_report_key(dev, BTN_LEFT, button == 1); +- input_report_key(dev, BTN_RIGHT, button == 2); +- input_report_key(dev, BTN_MIDDLE, button == 3); +- input_report_key(dev, BTN_FORWARD, button == 4); +- input_report_key(dev, BTN_BACK, button == 5); +- input_report_key(dev, BTN_0, button == 6); +- input_report_key(dev, BTN_1, button == 7); + ++ input_report_key(dev, BTN_LEFT, button == 1); ++ input_report_key(dev, BTN_RIGHT, button == 2); ++ input_report_key(dev, BTN_MIDDLE, button == 3); ++ input_report_key(dev, BTN_FORWARD, button == 4); ++ input_report_key(dev, BTN_BACK, button == 5); ++ input_report_key(dev, BTN_0, button == 6); ++ input_report_key(dev, BTN_1, button == 7); ++ input_report_key(dev, BTN_2, button == 1); ++ input_report_key(dev, BTN_3, button == 2); ++ input_report_key(dev, BTN_4, button == 3); + + packet[0]=0; + packet[1]=0; +@@ -678,6 +720,277 @@ static psmouse_ret_t elantech_process_6byte_EF113(struct psmouse *psmouse) + + } + ++ ++static psmouse_ret_t elantech_process_6byte_EF123(struct psmouse *psmouse) ++{ ++ ++ ++ struct input_dev *dev = psmouse->dev; ++ unsigned char *packet = psmouse->packet; ++ unsigned char SA1,A1,B1,SB1,C1,D1; ++ static unsigned char SA1_O,A1_O,B1_O,SB1_O,C1_O,D1_O; ++ unsigned int fingers,button; ++ int x1,y1,z1,x2,y2,w1; ++ int MKY,VF; ++ static int Debug; ++ ++ ++ x1=y1=x2=y2=0; ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte\n"); ++ ++ ++ ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte psmouse->fw_version=%d\n",psmouse->fw_version); ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++//-----------------in check byte data-------------------------------------- ++ if (psmouse->pktcnt < 6) ++ return PSMOUSE_GOOD_DATA; ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++ SA1= packet[0]; ++ A1 = packet[1]; ++ B1 = packet[2]; ++ SB1= packet[3]; ++ C1 = packet[4]; ++ D1 = packet[5]; ++ ++ if( ((SA1 & 0x0C) != 0x04) || // check Byte 1 ++ ((SB1 & 0x0f) != 0x02) ) // check Byte 4 ++ { ++ packet[0] = A1; ++ packet[1] = B1; ++ packet[2] = SB1; ++ packet[3] = C1; ++ packet[4] = D1; ++ psmouse->pktcnt = psmouse->pktcnt - 1; ++ return PSMOUSE_GOOD_DATA; ++ } ++ ++ ++ ++ ++//-----------------out check byte data-------------------------------------- ++ //printk(KERN_DEBUG "Data2= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++ ++ if( SA1 != SA1_O || ++ A1 != A1_O || ++ B1 != B1_O || ++ SB1 != SB1_O || ++ C1 != C1_O || ++ D1 != D1_O) ++ { ++ fingers = ((packet[0] & 0xC0) >> 6); ++ button = (packet[0] & 0x03); ++ w1 = (((packet[0]&0x30)>>2)|((packet[3]&0x30)>>4)) & 0x0f; ++ MKY = ((packet[3] & 0x80) >> 7); ++ VF = ((packet[3] & 0x40) >> 6); ++ ++ ++ //printk(KERN_DEBUG "w1= %d \n",w1); ++ if(fingers==0) ++ input_report_abs(dev,ABS_PRESSURE,0); ++ ++ if(fingers==1){ ++ ++ x1=(((packet[1] & 0x0f) << 8) | packet[2]); ++ y1= 0x2F0 -(((packet[4] & 0x0f) << 8) | packet[5]); ++ x2=(x1*420)/100 + 1400; ++ y2=(y1*562)/100 + 1400; ++ z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); ++ ++ ++ input_report_abs(dev, ABS_X,x2); ++ input_report_abs(dev, ABS_Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x y2=%.2x\n",x2,y2); ++ ++ } ++ ++ if(fingers==2){ ++ //input_report_key(dev, BTN_C,z > 0); ++ x1=((packet[0] & 0x10) << 4) | packet[1]; ++ y1=0xFF -(((packet[0] & 0x20) << 3) | packet[2]); ++ x2=((packet[3] & 0x10) << 4) | packet[4]; ++ y2=0xFF -(((packet[3] & 0x20) << 3 )| packet[5]); ++ z1=61; ++ input_report_abs(dev, ABS_HAT0X,x1); ++ input_report_abs(dev, ABS_HAT0Y,y1); ++ input_report_abs(dev, ABS_HAT1X,x2); ++ input_report_abs(dev, ABS_HAT1Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x %d y2=%.2x %d\n",x2,x2,y2,y2); ++ ++ //printk(KERN_DEBUG "x3=%.2x y3=%.2x z3=%.2x\n",x3,y3,z1); ++ //printk(KERN_DEBUG "x4=%.2x %d y4=%.2x %d\n",x4,x4,y4,y4); ++ ++ } ++ if(fingers==3){ ++ x1=(((packet[1] & 0x0f) << 8) | packet[2]); ++ y1= 0x7FF - (((packet[4] & 0x0f) << 8) | packet[5]); ++ z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); ++ ++ //x2=(x1*420)/100 + 1126; ++ //y2=(y1*562)/100 + 897; ++ input_report_abs(dev, ABS_HAT2X,x1); ++ input_report_abs(dev, ABS_HAT2Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ } ++ ++ ++ ++ input_report_abs(dev,ABS_TOOL_WIDTH,w1); ++ input_report_key(dev, BTN_TOUCH, fingers > 0); ++ input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); ++ input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); ++ input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); ++ ++ ++ input_report_key(dev, BTN_LEFT, button == 1); ++ input_report_key(dev, BTN_RIGHT, button == 2); ++ input_report_key(dev, BTN_MIDDLE, button == 3); ++ input_report_key(dev, BTN_FORWARD, button == 4); ++ input_report_key(dev, BTN_BACK, button == 5); ++ input_report_key(dev, BTN_0, button == 6); ++ input_report_key(dev, BTN_1, button == 7); ++ input_report_key(dev, BTN_2, button == 1); ++ input_report_key(dev, BTN_3, button == 2); ++ input_report_key(dev, BTN_4, button == 3); ++ input_report_key(dev, BTN_5, MKY == 1); ++ input_report_key(dev, BTN_6, VF == 1); ++ ++ SA1_O = SA1; ++ A1_O = A1; ++ B1_O = B1; ++ SB1_O = SB1; ++ C1_O = C1; ++ D1_O = D1; ++ } ++ input_sync(dev); ++ //printk(KERN_DEBUG "-psmouse_ret_t elantech_process_byte\n"); ++ return PSMOUSE_FULL_PACKET; ++ ++ ++} ++ ++static int EF023_DEBUG_SOLUTION(int fingers,int button,int w) ++{ ++ static int can_bug=0,debug_condition_1=0,count_report=0,debug_condition_3=0,debug_condition_5=0; ++ static int solution=0; ++ ++ ++ ++ //printk(KERN_DEBUG "\n solution=%d fingers=%d button=%d\n",solution,fingers,button); ++ //printk(KERN_DEBUG "1 count_report=%d \n", count_report); ++ ++ ++ if(solution==3) ++ return 0; ++ ++ if(fingers >=2 || (fingers == 1 && button > 0)) ++ can_bug=1; ++ ++ ++ if(can_bug && button > 0) ++ debug_condition_1=1; ++ ++ if(fingers <= 1 && can_bug && button==0) ++ can_bug=0; ++ ++ if(debug_condition_1&& fingers ==0 && button > 0){ ++ count_report++; ++ //printk(KERN_DEBUG "2 count_report=%d \n", count_report); ++ if(count_report==4){ ++ debug_condition_1=0; ++ EF_023_DEBUG=2; ++ solution=2; ++ return 1; ++ ++ } ++ ++ } ++ else if(debug_condition_1 && fingers == 1 && button > 0) ++ { ++ count_report=0; ++ } ++ else if(debug_condition_1 && count_report > 0 && count_report < 4 && button == 0) ++ { ++ EF_023_DEBUG=1; ++ solution=1; ++ debug_condition_1=0; ++ count_report=0; ++ return 1; ++ } ++ else if(fingers ==0 && button == 0) ++ { ++ count_report=0; ++ debug_condition_1=0; ++ ++ } ++ ++ ++ ++ //if(debug_condition_5 != 0) ++ //printk(KERN_DEBUG "debug_condition_5=%d fingers=%d button=%d\n",debug_condition_5,fingers,button); ++ ++ ++ if(debug_condition_5==1 &&fingers ==1 && button ==0){ ++ EF_023_DEBUG=4; ++ debug_condition_5=2; ++ return 1; ++ }else if(debug_condition_5==2){ ++ if(fingers ==0 && button > 0){ ++ EF_023_DEBUG=5; ++ debug_condition_5=3; ++ }else{ ++ EF_023_DEBUG=5; ++ debug_condition_5=5; ++ } ++ return 1; ++ }else if(debug_condition_5==3 && fingers < 2 && button==0){ ++ debug_condition_5=4; ++ }else if(debug_condition_5 ==4 && fingers ==1 && button==0 && w !=4){ ++ solution=3; ++ }else if(debug_condition_5==5){ ++ EF_023_DEBUG=1; ++ debug_condition_5=0; ++ return 1; ++ }else if (debug_condition_5 !=0 ){ ++ ++ if((w ==4 && fingers==1)||(fingers > 1 && debug_condition_5 >= 3)) ++ { ++ EF_023_DEBUG=1; ++ debug_condition_5=0; ++ return 1; ++ } ++ debug_condition_5=0; ++ }else if(debug_condition_5==0 && button ==0){ ++ debug_condition_5=1; ++ } ++ ++ ++ ++ if(fingers ==1 && button ==0){ ++ debug_condition_3=1; ++ }else if(debug_condition_3==1 && fingers ==0 && button ==1){ ++ solution = 3; ++ }else { ++ debug_condition_3=0; ++ } ++ ++ ++ return 0; ++} ++ ++ + static psmouse_ret_t elantech_process_6byte_EF023(struct psmouse *psmouse) + { + +@@ -685,7 +998,177 @@ static psmouse_ret_t elantech_process_6byte_EF023(struct psmouse *psmouse) + struct input_dev *dev = psmouse->dev; + unsigned char *packet = psmouse->packet; + unsigned char SA1,A1,B1,SB1,C1,D1; +- static unsigned char SA1_O,A1_O,B1_O,SB1_O,C1_O,D1_O,finger_O; ++ static unsigned char SA1_O,A1_O,B1_O,SB1_O,C1_O,D1_O; ++ unsigned int fingers,button; ++ int x1,y1,z1,x2,y2,w1; ++ static int Debug; ++ ++ ++ x1=y1=x2=y2=0; ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte\n"); ++ ++ ++ ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte psmouse->fw_version=%d\n",psmouse->fw_version); ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++//-----------------in check byte data-------------------------------------- ++ if (psmouse->pktcnt < 6) ++ return PSMOUSE_GOOD_DATA; ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++ SA1= packet[0]; ++ A1 = packet[1]; ++ B1 = packet[2]; ++ SB1= packet[3]; ++ C1 = packet[4]; ++ D1 = packet[5]; ++ ++ if( ((SA1 & 0x0C) != 0x04) || // check Byte 1 ++ ((SB1 & 0x0f) != 0x02) ) // check Byte 4 ++ { ++ packet[0] = A1; ++ packet[1] = B1; ++ packet[2] = SB1; ++ packet[3] = C1; ++ packet[4] = D1; ++ psmouse->pktcnt = psmouse->pktcnt - 1; ++ return PSMOUSE_GOOD_DATA; ++ } ++ ++ ++ ++ ++//-----------------out check byte data-------------------------------------- ++ //printk(KERN_DEBUG "Data2= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ fingers = ((packet[0] & 0xC0) >> 6); ++ button = ((packet[3]&0x01 << 2) | (packet[0] & 0x03)); ++ w1 = (((packet[0]&0x30)>>2)|((packet[3]&0x30)>>4)) & 0x0f; ++ Debug = EF023_DEBUG_SOLUTION(fingers,button,w1); ++ if(Debug){ ++ psmouse->resetafter = psmouse->out_of_sync+1; ++ return PSMOUSE_BAD_DATA; ++ } ++ ++ if( SA1 != SA1_O || ++ A1 != A1_O || ++ B1 != B1_O || ++ SB1 != SB1_O || ++ C1 != C1_O || ++ D1 != D1_O) ++ { ++ fingers = ((packet[0] & 0xC0) >> 6); ++ button = ((packet[3]&0x01 << 2) | (packet[0] & 0x03)); ++ w1 = (((packet[0]&0x30)>>2)|((packet[3]&0x30)>>4)) & 0x0f; ++ #if 0 ++ Debug = EF023_DEBUG_SOLUTION(fingers,button,w1); ++ if(Debug){ ++ psmouse->resetafter = psmouse->out_of_sync+1; ++ return PSMOUSE_BAD_DATA; ++ } ++ #endif ++ ++ ++ //printk(KERN_DEBUG "w1= %d \n",w1); ++ if(fingers==0) ++ input_report_abs(dev,ABS_PRESSURE,0); ++ ++ if(fingers==1){ ++ ++ x1=(((packet[1] & 0x0f) << 8) | packet[2]); ++ y1= 0x2F0 -(((packet[4] & 0x0f) << 8) | packet[5]); ++ x2=(x1*420)/100 + 1400; ++ y2=(y1*562)/100 + 1400; ++ z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); ++ ++ ++ input_report_abs(dev, ABS_X,x2); ++ input_report_abs(dev, ABS_Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x y2=%.2x\n",x2,y2); ++ ++ } ++ ++ if(fingers==2){ ++ //input_report_key(dev, BTN_C,z > 0); ++ x1=((packet[0] & 0x10) << 4) | packet[1]; ++ y1=0xFF -(((packet[0] & 0x20) << 3) | packet[2]); ++ x2=((packet[3] & 0x10) << 4) | packet[4]; ++ y2=0xFF -(((packet[3] & 0x20) << 3 )| packet[5]); ++ z1=61; ++ input_report_abs(dev, ABS_HAT0X,x1); ++ input_report_abs(dev, ABS_HAT0Y,y1); ++ input_report_abs(dev, ABS_HAT1X,x2); ++ input_report_abs(dev, ABS_HAT1Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x %d y2=%.2x %d\n",x2,x2,y2,y2); ++ ++ //printk(KERN_DEBUG "x3=%.2x y3=%.2x z3=%.2x\n",x3,y3,z1); ++ //printk(KERN_DEBUG "x4=%.2x %d y4=%.2x %d\n",x4,x4,y4,y4); ++ ++ } ++ if(fingers==3){ ++ x1=(((packet[1] & 0x0f) << 8) | packet[2]); ++ y1= 0x7FF - (((packet[4] & 0x0f) << 8) | packet[5]); ++ z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); ++ ++ //x2=(x1*420)/100 + 1126; ++ //y2=(y1*562)/100 + 897; ++ input_report_abs(dev, ABS_HAT2X,x1); ++ input_report_abs(dev, ABS_HAT2Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ } ++ ++ ++ ++ input_report_abs(dev,ABS_TOOL_WIDTH,w1); ++ input_report_key(dev, BTN_TOUCH, fingers > 0); ++ input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); ++ input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); ++ input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); ++ ++ ++ input_report_key(dev, BTN_LEFT, button == 1); ++ input_report_key(dev, BTN_RIGHT, button == 2); ++ input_report_key(dev, BTN_MIDDLE, button == 3); ++ input_report_key(dev, BTN_FORWARD, button == 4); ++ input_report_key(dev, BTN_BACK, button == 5); ++ input_report_key(dev, BTN_0, button == 6); ++ input_report_key(dev, BTN_1, button == 7); ++ input_report_key(dev, BTN_2, button == 1); ++ input_report_key(dev, BTN_3, button == 2); ++ input_report_key(dev, BTN_4, button == 3); ++ ++ SA1_O = SA1; ++ A1_O = A1; ++ B1_O = B1; ++ SB1_O = SB1; ++ C1_O = C1; ++ D1_O = D1; ++ } ++ input_sync(dev); ++ //printk(KERN_DEBUG "-psmouse_ret_t elantech_process_byte\n"); ++ return PSMOUSE_FULL_PACKET; ++ ++ ++} ++ ++ ++static psmouse_ret_t elantech_process_6byte_EF215(struct psmouse *psmouse) ++{ ++ ++ ++ struct input_dev *dev = psmouse->dev; ++ unsigned char *packet = psmouse->packet; ++ unsigned char SA1,A1,B1,SB1,C1,D1; ++ static unsigned char SA1_O,A1_O,B1_O,SB1_O,C1_O,D1_O; + unsigned int fingers,button; + int x1,y1,z1,x2,y2,w1; + +@@ -735,46 +1218,46 @@ static psmouse_ret_t elantech_process_6byte_EF023(struct psmouse *psmouse) + C1 != C1_O || + D1 != D1_O) + { +- fingers = ((packet[0] & 0xC0) >> 6); +- if(finger_O == fingers){ +- button = ((packet[3]&0x01 << 2) | (packet[0] & 0x03)); +- w1 = (((packet[0]&0x30)>>2)|((packet[3]&0x30)>>4)) & 0x0f; +- //printk(KERN_DEBUG "w1= %d \n",w1); +- if(fingers==0) +- input_report_abs(dev,ABS_PRESSURE,0); ++ fingers = ((packet[0] & 0xC0) >> 6); + +- if(fingers==1){ ++ button = ((packet[3]&0x01 << 2) | (packet[0] & 0x03)); ++ w1 = (((packet[0]&0x30)>>2)|((packet[3]&0x30)>>4)) & 0x0f; ++ //printk(KERN_DEBUG "w1= %d \n",w1); ++ if(fingers==0) ++ input_report_abs(dev,ABS_PRESSURE,0); + +- x1=(((packet[1] & 0x0f) << 8) | packet[2]); +- y1= 0x2F0 -(((packet[4] & 0x0f) << 8) | packet[5]); +- x2=(x1*420)/100 + 1400; +- y2=(y1*562)/100 + 1400; +- z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); ++ if(fingers==1){ + ++ x1=(((packet[1] & 0x0f) << 8) | packet[2]); ++ y1= 0x2F0 -(((packet[4] & 0x0f) << 8) | packet[5]); ++ x2=(x1*420)/100 + 1400; ++ y2=(y1*562)/100 + 1400; ++ z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); + +- input_report_abs(dev, ABS_X,x2); +- input_report_abs(dev, ABS_Y,y2); +- input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ input_report_abs(dev, ABS_X,x2); ++ input_report_abs(dev, ABS_Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); + + + //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); + //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); + //printk(KERN_DEBUG "x2=%.2x y2=%.2x\n",x2,y2); + +- } ++ } + +- if(fingers==2){ ++ if(fingers==2){ + //input_report_key(dev, BTN_C,z > 0); +- x1=((packet[0] & 0x10) << 4) | packet[1]; +- y1=0xFF -(((packet[0] & 0x20) << 3) | packet[2]); +- x2=((packet[3] & 0x10) << 4) | packet[4]; +- y2=0xFF -(((packet[3] & 0x20) << 3 )| packet[5]); +- z1=70; +- input_report_abs(dev, ABS_HAT0X,x1); +- input_report_abs(dev, ABS_HAT0Y,y1); +- input_report_abs(dev, ABS_HAT1X,x2); +- input_report_abs(dev, ABS_HAT1Y,y2); +- input_report_abs(dev,ABS_PRESSURE,z1); ++ x1=((packet[0] & 0x10) << 4) | packet[1]; ++ y1=0xFF -(((packet[0] & 0x20) << 3) | packet[2]); ++ x2=((packet[3] & 0x10) << 4) | packet[4]; ++ y2=0xFF -(((packet[3] & 0x20) << 3 )| packet[5]); ++ z1=61; ++ input_report_abs(dev, ABS_HAT0X,x1); ++ input_report_abs(dev, ABS_HAT0Y,y1); ++ input_report_abs(dev, ABS_HAT1X,x2); ++ input_report_abs(dev, ABS_HAT1Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); + + //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); + //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); +@@ -784,46 +1267,45 @@ static psmouse_ret_t elantech_process_6byte_EF023(struct psmouse *psmouse) + //printk(KERN_DEBUG "x4=%.2x %d y4=%.2x %d\n",x4,x4,y4,y4); + + } +- if(fingers==3){ +- x1=(((packet[1] & 0x0f) << 8) | packet[2]); +- y1= 0x7FF - (((packet[4] & 0x0f) << 8) | packet[5]); +- z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); +- +- //x2=(x1*420)/100 + 1126; +- //y2=(y1*562)/100 + 897; +- input_report_abs(dev, ABS_HAT2X,x1); +- input_report_abs(dev, ABS_HAT2Y,y1); +- input_report_abs(dev,ABS_PRESSURE,z1); +- } ++ if(fingers==3){ ++ x1=(((packet[1] & 0x0f) << 8) | packet[2]); ++ y1= 0x7FF - (((packet[4] & 0x0f) << 8) | packet[5]); ++ z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); + ++ //x2=(x1*420)/100 + 1126; ++ //y2=(y1*562)/100 + 897; ++ input_report_abs(dev, ABS_HAT2X,x1); ++ input_report_abs(dev, ABS_HAT2Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ } + + +- input_report_abs(dev,ABS_TOOL_WIDTH,w1); +- input_report_key(dev, BTN_TOUCH, fingers > 0); +- input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); +- input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); +- input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); +- +- /* +- input_report_key(dev, BTN_LEFT, button == 1); +- input_report_key(dev, BTN_RIGHT, button == 2); +- input_report_key(dev, BTN_MIDDLE, button == 3);*/ +- input_report_key(dev, BTN_FORWARD, button == 4); +- input_report_key(dev, BTN_BACK, button == 5); +- input_report_key(dev, BTN_0, button == 6); +- input_report_key(dev, BTN_1, button == 7); +- input_report_key(dev, BTN_2, button == 1); +- input_report_key(dev, BTN_3, button == 2); +- input_report_key(dev, BTN_4, button == 3); +- +- SA1_O = SA1; +- A1_O = A1; +- B1_O = B1; +- SB1_O = SB1; +- C1_O = C1; +- D1_O = D1; +- } +- finger_O = fingers; ++ ++ input_report_abs(dev,ABS_TOOL_WIDTH,w1); ++ input_report_key(dev, BTN_TOUCH, fingers > 0); ++ input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); ++ input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); ++ input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); ++ ++ ++ ++ input_report_key(dev, BTN_LEFT, button == 1); ++ input_report_key(dev, BTN_RIGHT, button == 2); ++ input_report_key(dev, BTN_MIDDLE, button == 3); ++ input_report_key(dev, BTN_FORWARD, button == 4); ++ input_report_key(dev, BTN_BACK, button == 5); ++ input_report_key(dev, BTN_0, button == 6); ++ input_report_key(dev, BTN_1, button == 7); ++ input_report_key(dev, BTN_2, button == 1); ++ input_report_key(dev, BTN_3, button == 2); ++ input_report_key(dev, BTN_4, button == 3); ++ ++ SA1_O = SA1; ++ A1_O = A1; ++ B1_O = B1; ++ SB1_O = SB1; ++ C1_O = C1; ++ D1_O = D1; + } + input_sync(dev); + //printk(KERN_DEBUG "-psmouse_ret_t elantech_process_byte\n"); +@@ -959,6 +1441,7 @@ static psmouse_ret_t elantech_process_6byte_EF051(struct psmouse *psmouse) + input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); + + ++ + input_report_key(dev, BTN_LEFT, button == 1); + input_report_key(dev, BTN_RIGHT, button == 2); + input_report_key(dev, BTN_MIDDLE, button == 3); +@@ -966,8 +1449,163 @@ static psmouse_ret_t elantech_process_6byte_EF051(struct psmouse *psmouse) + input_report_key(dev, BTN_BACK, button == 5); + input_report_key(dev, BTN_0, button == 6); + input_report_key(dev, BTN_1, button == 7); ++ input_report_key(dev, BTN_2, button == 1); ++ input_report_key(dev, BTN_3, button == 2); ++ input_report_key(dev, BTN_4, button == 3); ++ ++ SA1_O = SA1; ++ A1_O = A1; ++ B1_O = B1; ++ SB1_O = SB1; ++ C1_O = C1; ++ D1_O = D1; ++ } ++ input_sync(dev); ++ //printk(KERN_DEBUG "-psmouse_ret_t elantech_process_byte\n"); ++ return PSMOUSE_FULL_PACKET; ++ ++ ++} ++ ++static psmouse_ret_t elantech_process_6byte_Scroll_EF051(struct psmouse *psmouse) ++{ ++ ++ ++ struct input_dev *dev = psmouse->dev; ++ unsigned char *packet = psmouse->packet; ++ unsigned char SA1,A1,B1,SB1,C1,D1; ++ static unsigned char SA1_O,A1_O,B1_O,SB1_O,C1_O,D1_O; ++ unsigned int fingers,button; ++ int x1,y1,z1,x2,y2,w1; + + ++ x1=y1=x2=y2=0; ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte\n"); ++ ++ ++ ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte psmouse->fw_version=%d\n",psmouse->fw_version); ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++//-----------------in check byte data-------------------------------------- ++ if (psmouse->pktcnt < 6) ++ return PSMOUSE_GOOD_DATA; ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++ SA1= packet[0]; ++ A1 = packet[1]; ++ B1 = packet[2]; ++ SB1= packet[3]; ++ C1 = packet[4]; ++ D1 = packet[5]; ++ ++ if( ((SA1 & 0x0C) != 0x04) || // check Byte 1 ++ ((SB1 & 0x0f) != 0x02) ) // check Byte 4 ++ { ++ packet[0] = A1; ++ packet[1] = B1; ++ packet[2] = SB1; ++ packet[3] = C1; ++ packet[4] = D1; ++ psmouse->pktcnt = psmouse->pktcnt - 1; ++ return PSMOUSE_GOOD_DATA; ++ } ++ ++ ++ ++ ++//-----------------out check byte data-------------------------------------- ++ //printk(KERN_DEBUG "Data2= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++ if( SA1 != SA1_O || ++ A1 != A1_O || ++ B1 != B1_O || ++ SB1 != SB1_O || ++ C1 != C1_O || ++ D1 != D1_O) ++ { ++ fingers = ((packet[0] & 0xC0) >> 6); ++ ++ button = ((packet[3]&0x01 << 2) | (packet[0] & 0x03)); ++ w1 = (((packet[0]&0x30)>>2)|((packet[3]&0x30)>>4)) & 0x0f; ++ //printk(KERN_DEBUG "w1= %d \n",w1); ++ if(fingers==0) ++ input_report_abs(dev,ABS_PRESSURE,0); ++ ++ if(fingers==1){ ++ ++ x1=(((packet[1] & 0x0f) << 8) | packet[2]); ++ y1= 0x2F0 -(((packet[4] & 0x0f) << 8) | packet[5]); ++ x2=(x1*420)/100 + 1400; ++ y2=(y1*562)/100 + 1400; ++ z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); ++ ++ ++ input_report_abs(dev, ABS_X,x2); ++ input_report_abs(dev, ABS_Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x y2=%.2x\n",x2,y2); ++ ++ } ++ ++ if(fingers==2){ ++ //input_report_key(dev, BTN_C,z > 0); ++ x1=((packet[0] & 0x10) << 4) | packet[1]; ++ y1=0xFF -(((packet[0] & 0x20) << 3) | packet[2]); ++ x2=((packet[3] & 0x10) << 4) | packet[4]; ++ y2=0xFF -(((packet[3] & 0x20) << 3 )| packet[5]); ++ z1=61; ++ input_report_abs(dev, ABS_HAT0X,x1); ++ input_report_abs(dev, ABS_HAT0Y,y1); ++ input_report_abs(dev, ABS_HAT1X,x2); ++ input_report_abs(dev, ABS_HAT1Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x %d y2=%.2x %d\n",x2,x2,y2,y2); ++ ++ //printk(KERN_DEBUG "x3=%.2x y3=%.2x z3=%.2x\n",x3,y3,z1); ++ //printk(KERN_DEBUG "x4=%.2x %d y4=%.2x %d\n",x4,x4,y4,y4); ++ ++ } ++ if(fingers==3){ ++ x1=(((packet[1] & 0x0f) << 8) | packet[2]); ++ y1= 0x7FF - (((packet[4] & 0x0f) << 8) | packet[5]); ++ z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); ++ ++ //x2=(x1*420)/100 + 1126; ++ //y2=(y1*562)/100 + 897; ++ input_report_abs(dev, ABS_HAT2X,x1); ++ input_report_abs(dev, ABS_HAT2Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ } ++ ++ ++ ++ input_report_abs(dev,ABS_TOOL_WIDTH,w1); ++ input_report_key(dev, BTN_TOUCH, fingers > 0); ++ input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); ++ input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); ++ input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); ++ ++ ++ ++ input_report_key(dev, BTN_LEFT, button == 1); ++ input_report_key(dev, BTN_RIGHT, button == 2); ++ input_report_key(dev, BTN_MIDDLE, button == 3); ++ input_report_key(dev, BTN_FORWARD, button == 4); ++ input_report_key(dev, BTN_BACK, button == 5); ++ input_report_key(dev, BTN_0, button == 6); ++ input_report_key(dev, BTN_1, button == 7); ++ input_report_key(dev, BTN_2, button == 1); ++ input_report_key(dev, BTN_3, button == 2); ++ input_report_key(dev, BTN_4, button == 3); ++ + SA1_O = SA1; + A1_O = A1; + B1_O = B1; +@@ -982,6 +1620,7 @@ static psmouse_ret_t elantech_process_6byte_EF051(struct psmouse *psmouse) + + } + ++ + /* + * Initialise the touchpad to a default state. Because we don't know (yet) + * how to read registers we need to write some default values so we can +@@ -1359,6 +1998,201 @@ repeat_com: + return err; + } + ++static int elantech_set_6byte_defaults_EF123(struct psmouse *psmouse) ++{ ++ ++ struct elantech_data *etd = psmouse->private; ++ struct input_dev *dev = psmouse->dev; ++ int err,repeat_run,checkrepeat_run; ++ ++ //printk(KERN_DEBUG "+elantech_set_defaults\n"); ++ /* ++ * For now, use the Elantech Windows driver default values ++ */ ++ repeat_run=checkrepeat_run=0; ++ err=-1; ++ ++repeat_com: ++ ++ etd->reg_10 = 0xc4; ++ err=elantech_write_reg_new(psmouse, 0x10, etd->reg_10); ++ if((err != 0) && (repeat_run<2)){ ++ repeat_run++; ++ goto repeat_com; ++ } ++ ++ etd->reg_11 = 0x8a; ++ err=elantech_write_reg_new(psmouse, 0x11, etd->reg_11); ++ //elantech_read_reg_new(psmouse, 0x11, etd->reg_11); ++ ++ /*etd->reg_21 = 0x60; ++ elantech_write_reg_new(psmouse, 0x21, etd->reg_21); ++ //elantech_read_reg_new(psmouse, 0x21, etd->reg_21);*/ ++ ++ ++ ++ err = elantech_read_reg_new(psmouse, 0x10, etd->reg_10); ++ ++ if((err != 0) && (checkrepeat_run<2)){ ++ checkrepeat_run++; ++ goto repeat_com; ++ } ++ ++ if(err==0){ ++ set_bit(EV_KEY, dev->evbit); ++ set_bit(BTN_LEFT, dev->keybit); ++ set_bit(BTN_MIDDLE, dev->keybit); ++ set_bit(BTN_RIGHT, dev->keybit); ++ set_bit(BTN_FORWARD, dev->keybit); ++ set_bit(BTN_BACK, dev->keybit); ++ ++ set_bit(BTN_TOUCH, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ /* Corner taps */ ++ set_bit(BTN_0, dev->keybit); ++ set_bit(BTN_1, dev->keybit); ++ set_bit(BTN_2, dev->keybit); ++ set_bit(BTN_3, dev->keybit); ++ set_bit(BTN_4, dev->keybit); ++ set_bit(BTN_5, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ ++ ++ ++ set_bit(EV_ABS, dev->evbit); ++// input_set_abs_params(dev, ABS_X, ETP_XMIN, ETP_XMAX, 0, 0); ++// input_set_abs_params(dev, ABS_Y, ETP_YMIN, ETP_YMAX, 0, 0); ++ ++ input_set_abs_params(dev, ABS_X,1202, 5876, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 999, 5112, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X, 4, 281, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,4,187, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,4, 281, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,4, 187, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_TOOL_WIDTH,0,16,0,0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); ++/* ++ input_set_abs_params(dev, ABS_X, 0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 0,2047, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 127, 0, 0); ++*/ ++ } ++ //printk(KERN_DEBUG "-elantech_set_defaults\n"); ++ ++ return err; ++} ++ ++static int elantech_set_6byte_defaults_EF215(struct psmouse *psmouse) ++{ ++ ++ struct elantech_data *etd = psmouse->private; ++ struct input_dev *dev = psmouse->dev; ++ int err,repeat_run,checkrepeat_run; ++ ++ //printk(KERN_DEBUG "+elantech_set_defaults\n"); ++ /* ++ * For now, use the Elantech Windows driver default values ++ */ ++ repeat_run=checkrepeat_run=0; ++ err=-1; ++ ++repeat_com: ++ ++ etd->reg_10 = 0xc4; ++ err=elantech_write_reg_new(psmouse, 0x10, etd->reg_10); ++ if((err != 0) && (repeat_run<2)){ ++ repeat_run++; ++ goto repeat_com; ++ } ++ ++ etd->reg_11 = 0x8a; ++ err=elantech_write_reg_new(psmouse, 0x11, etd->reg_11); ++ //elantech_read_reg_new(psmouse, 0x11, etd->reg_11); ++ ++ /*etd->reg_21 = 0x60; ++ elantech_write_reg_new(psmouse, 0x21, etd->reg_21); ++ //elantech_read_reg_new(psmouse, 0x21, etd->reg_21);*/ ++ ++ ++ ++ err = elantech_read_reg_new(psmouse, 0x10, etd->reg_10); ++ ++ if((err != 0) && (checkrepeat_run<2)){ ++ checkrepeat_run++; ++ goto repeat_com; ++ } ++ ++ if(err==0){ ++ set_bit(EV_KEY, dev->evbit); ++ set_bit(BTN_LEFT, dev->keybit); ++ set_bit(BTN_MIDDLE, dev->keybit); ++ set_bit(BTN_RIGHT, dev->keybit); ++ set_bit(BTN_FORWARD, dev->keybit); ++ set_bit(BTN_BACK, dev->keybit); ++ ++ set_bit(BTN_TOUCH, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ /* Corner taps */ ++ set_bit(BTN_0, dev->keybit); ++ set_bit(BTN_1, dev->keybit); ++ set_bit(BTN_2, dev->keybit); ++ set_bit(BTN_3, dev->keybit); ++ set_bit(BTN_4, dev->keybit); ++ set_bit(BTN_5, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ ++ ++ ++ set_bit(EV_ABS, dev->evbit); ++// input_set_abs_params(dev, ABS_X, ETP_XMIN, ETP_XMAX, 0, 0); ++// input_set_abs_params(dev, ABS_Y, ETP_YMIN, ETP_YMAX, 0, 0); ++ ++ input_set_abs_params(dev, ABS_X,1202, 5876, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 999, 5112, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X, 4, 281, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,4,187, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,4, 281, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,4, 187, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_TOOL_WIDTH,0,16,0,0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); ++/* ++ input_set_abs_params(dev, ABS_X, 0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 0,2047, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 127, 0, 0); ++*/ ++ } ++ //printk(KERN_DEBUG "-elantech_set_defaults\n"); ++ ++ return err; ++} ++ ++ + static int elantech_set_6byte_defaults_EF051(struct psmouse *psmouse) + { + +@@ -1456,6 +2290,104 @@ repeat_com: + return err; + } + ++static int elantech_set_6byte_defaults_Scroll_EF051(struct psmouse *psmouse) ++{ ++ ++ struct elantech_data *etd = psmouse->private; ++ struct input_dev *dev = psmouse->dev; ++ int err,repeat_run,checkrepeat_run; ++ ++ //printk(KERN_DEBUG "+elantech_set_defaults\n"); ++ /* ++ * For now, use the Elantech Windows driver default values ++ */ ++ repeat_run=checkrepeat_run=0; ++ err=-1; ++ ++repeat_com: ++ ++ etd->reg_10 = 0xc4; ++ err=elantech_write_reg_new(psmouse, 0x10, etd->reg_10); ++ if((err != 0) && (repeat_run<2)){ ++ repeat_run++; ++ goto repeat_com; ++ } ++ ++ etd->reg_11 = 0x8a; ++ err=elantech_write_reg_new(psmouse, 0x11, etd->reg_11); ++ //elantech_read_reg_new(psmouse, 0x11, etd->reg_11); ++ ++ /*etd->reg_21 = 0x60; ++ elantech_write_reg_new(psmouse, 0x21, etd->reg_21); ++ //elantech_read_reg_new(psmouse, 0x21, etd->reg_21);*/ ++ ++ ++ ++ err = elantech_read_reg_new(psmouse, 0x10, etd->reg_10); ++ ++ if((err != 0) && (checkrepeat_run<2)){ ++ checkrepeat_run++; ++ goto repeat_com; ++ } ++ ++ if(err==0){ ++ set_bit(EV_KEY, dev->evbit); ++ set_bit(BTN_LEFT, dev->keybit); ++ set_bit(BTN_MIDDLE, dev->keybit); ++ set_bit(BTN_RIGHT, dev->keybit); ++ set_bit(BTN_FORWARD, dev->keybit); ++ set_bit(BTN_BACK, dev->keybit); ++ ++ set_bit(BTN_TOUCH, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ /* Corner taps */ ++ set_bit(BTN_0, dev->keybit); ++ set_bit(BTN_1, dev->keybit); ++ set_bit(BTN_2, dev->keybit); ++ set_bit(BTN_3, dev->keybit); ++ set_bit(BTN_4, dev->keybit); ++ set_bit(BTN_5, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ ++ ++ ++ set_bit(EV_ABS, dev->evbit); ++// input_set_abs_params(dev, ABS_X, ETP_XMIN, ETP_XMAX, 0, 0); ++// input_set_abs_params(dev, ABS_Y, ETP_YMIN, ETP_YMAX, 0, 0); ++ ++ input_set_abs_params(dev, ABS_X,1202, 5876, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 999, 5112, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X, 4, 281, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,4,187, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,4, 281, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,4, 187, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_TOOL_WIDTH,0,16,0,0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); ++/* ++ input_set_abs_params(dev, ABS_X, 0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 0,2047, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 127, 0, 0); ++*/ ++ } ++ //printk(KERN_DEBUG "-elantech_set_defaults\n"); ++ ++ return err; ++} ++ ++ + struct elantech_attr_data { + size_t field_offset; + unsigned char reg; +@@ -1559,6 +2491,101 @@ static void elantech_disconnect(struct psmouse *psmouse) + */ + + ++static int elantech_reconnect_EF023(struct psmouse *psmouse) ++{ ++ struct ps2dev *ps2dev = &psmouse->ps2dev; ++ int i; ++ int err,debug_err; ++ err=i8042_command(NULL,I8042_CMD_KBD_DISABLE);// tom + ++ ++ if(!err) ++ printk(KERN_INFO"i8042_command I8042_CMD_KBD_DISABLE OK\n"); ++ ++ switch(EF_023_DEBUG){ ++ ++ case 1: ++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x04); ++ debug_err=elantech_write_reg_debug(psmouse, 0x60, 0x00); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x00); ++ EF_023_DEBUG=0; ++ ++ break; ++ ++ case 2: ++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x04); ++ debug_err=elantech_write_reg_debug(psmouse, 0x1F, 0x00); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x00); ++ EF_023_DEBUG=0; ++ break; ++ case 3: ++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x04); ++ debug_err=elantech_write_reg_debug(psmouse, 0x13, 0x08); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x00); ++ EF_023_DEBUG=0; ++ break; ++ case 4: ++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x04); ++ debug_err=elantech_write_reg_debug(psmouse, 0x06, 0x07); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x00); ++ EF_023_DEBUG=0; ++ break; ++ case 5: ++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x04); ++ debug_err=elantech_write_reg_debug(psmouse, 0x06, 0x17); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x00); ++ EF_023_DEBUG=0; ++ break; ++#if 0 ++ case 6: ++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x04); ++ debug_err=elantech_write_reg_debug(psmouse, 0x06, 0x17); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x00); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x04); ++ debug_err=elantech_write_reg_debug(psmouse, 0x60, 0x00); ++ debug_err=elantech_write_reg_debug(psmouse, 0x12, 0x00); ++ //ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); ++ printk(KERN_DEBUG "EF_023_DEBUG=%d \n",EF_023_DEBUG); ++ EF_023_DEBUG=0; ++ printk(KERN_DEBUG "EF_023_DEBUG=%d\n",EF_023_DEBUG); ++ break; ++#endif ++ ++ default: ++ ++ for(i=0;i<3;i++){ ++ printk(KERN_INFO"elantech_reconnect\n"); ++ if (!elantech_detect(psmouse, 0)){ ++ if (!elantech_init(psmouse,0)) ++ break; ++ } ++ else ++ continue; ++ } ++ ++ if(i>=3){ ++ printk(KERN_INFO"elantech_reconnect fail\n"); ++ if(!err) ++ err=i8042_command(NULL,I8042_CMD_KBD_ENABLE);// tom + ++ if(!err) ++ printk(KERN_INFO"i8042_command I8042_CMD_KBD_ENABLE OK\n"); ++ return -1; ++ } ++ break; ++ ++ } ++ if(!err) ++ err=i8042_command(NULL,I8042_CMD_KBD_ENABLE);// tom + ++ if(!err) ++ printk(KERN_INFO"i8042_command I8042_CMD_KBD_ENABLE OK\n"); ++ return 0; ++} ++ + static int elantech_reconnect(struct psmouse *psmouse) + { + +@@ -1593,6 +2620,7 @@ static int elantech_reconnect(struct psmouse *psmouse) + return 0; + } + ++ + int elantech_detect(struct psmouse *psmouse, int set_properties) + { + +@@ -1600,7 +2628,7 @@ int elantech_detect(struct psmouse *psmouse, int set_properties) + unsigned char param[3]; + int i; + +- printk(KERN_INFO "2.6.2X-Elan-touchpad-2008-11-28\n"); ++ printk(KERN_INFO "2.6.2X-Elan-touchpad-2009-03-09\n"); + printk(KERN_DEBUG "+elantech_detect\n"); + + for(i=0;i<3;i++) +@@ -1767,11 +2795,45 @@ int elantech_init(struct psmouse *psmouse,int set_properties) + psmouse->protocol_handler = elantech_process_6byte_EF023; + psmouse->pktsize = 6; + psmouse->disconnect = elantech_disconnect; ++ psmouse->reconnect =elantech_reconnect_EF023; + psmouse->name = "Elantech Touchpad 6byte mode EF023"; + + } + } +- else if(param[0]==0x04 && param[1]==0x02 && param[2] == 0x00){ ++ else if(param[0]==0x02 && param[1]==0x08){ ++ err=elantech_set_6byte_defaults_EF123(psmouse); ++ if(err==0){ ++ printk(KERN_ERR "elantech.c:elantech_init 6 EF123\n"); ++ psmouse->protocol_handler = elantech_process_6byte_EF123; ++ psmouse->pktsize = 6; ++ psmouse->disconnect = elantech_disconnect; ++ psmouse->name = "Elantech Touchpad 6byte mode EF123"; ++ ++ } ++ } ++ else if(param[0]==0x02 && param[1]==0x0B && param[2] == 0x00){ ++ err=elantech_set_6byte_defaults_EF215(psmouse); ++ if(err==0){ ++ printk(KERN_ERR "elantech.c:elantech_init 6 EF215\n"); ++ psmouse->protocol_handler = elantech_process_6byte_EF215; ++ psmouse->pktsize = 6; ++ psmouse->disconnect = elantech_disconnect; ++ psmouse->name = "Elantech Touchpad 6byte mode EF215"; ++ ++ } ++ } ++ else if(param[0]==0x04 && param[1]==0x01){ ++ err=elantech_set_6byte_defaults_Scroll_EF051(psmouse); ++ if(err==0){ ++ printk(KERN_ERR "elantech.c:elantech_init 6 Scroll_EF051\n"); ++ psmouse->protocol_handler = elantech_process_6byte_Scroll_EF051; ++ psmouse->pktsize = 6; ++ psmouse->disconnect = elantech_disconnect; ++ psmouse->name = "Elantech Touchpad 6byte mode Scroll_EF051"; ++ ++ } ++ } ++ else if(param[0]==0x04 && param[1]==0x02){ + err=elantech_set_6byte_defaults_EF051(psmouse); + if(err==0){ + printk(KERN_ERR "elantech.c:elantech_init 6 EF051\n"); +@@ -1786,7 +2848,7 @@ int elantech_init(struct psmouse *psmouse,int set_properties) + printk(KERN_DEBUG "elantech -- don't find fw version\n"); + err=1; + } +- ++ //EF_023_DEBUG=0; + + //err=1;//chris + if(err){ +diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h +index 7dff73f..11f4f70 100644 +--- a/drivers/input/mouse/elantech.h ++++ b/drivers/input/mouse/elantech.h +@@ -27,7 +27,7 @@ struct elantech_data { + unsigned char reg_26; + }; + +- ++static int EF_023_DEBUG=0; + int elantech_detect(struct psmouse *psmouse, int set_properties); + int elantech_init(struct psmouse *psmouse, int set_properties); + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0095-Load-USB-HID-as-a-module-LP-320866.patch +++ linux-2.6.24/patches/0095-Load-USB-HID-as-a-module-LP-320866.patch @@ -0,0 +1,28 @@ +From c6833121870fc983f78887938adc7bab00656ee5 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 17 Mar 2009 15:28:22 -0400 +Subject: [PATCH 095/170] Load USB HID as a module (LP: #320866) + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/320866 +Signed-off-by: Michael Frey (Senior Manager, MID) +Signed-off-by: Steve Conklin +--- + debian/binary-custom.d/lpia/config.lpia | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/debian/binary-custom.d/lpia/config.lpia b/debian/binary-custom.d/lpia/config.lpia +index 76d8699..af0977b 100644 +--- a/debian/binary-custom.d/lpia/config.lpia ++++ b/debian/binary-custom.d/lpia/config.lpia +@@ -2602,7 +2602,7 @@ CONFIG_HIDRAW=y + # + # USB Input Devices + # +-CONFIG_USB_HID=y ++CONFIG_USB_HID=m + CONFIG_USB_HIDINPUT_POWERBOOK=y + # CONFIG_HID_FF is not set + CONFIG_USB_HIDDEV=y +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0136-Revert-UBUNTU-Bluetooth-SCO-flow-control-to-enable-b.patch +++ linux-2.6.24/patches/0136-Revert-UBUNTU-Bluetooth-SCO-flow-control-to-enable-b.patch @@ -0,0 +1,632 @@ +From 015d61884c581f3679f40e0c7bad2f8a33aac596 Mon Sep 17 00:00:00 2001 +From: Andres Salomon +Date: Mon, 20 Apr 2009 15:58:36 -0400 +Subject: [PATCH 136/170] Revert "UBUNTU: Bluetooth: SCO flow control to enable bluetooth headsets + +OriginalLocation: http://bluetooth-alsa.cvs.sourceforge.net/*checkout*/bluetooth-alsa/plugz/patches/sco-flowcontrol-v4.4.diff" + +These are against ubuntu-hardy's netbook-lpia branch. They probably +shouldn't be committed until we Ulisses's userspace patches are ready for +netbook-common, but it would be good to get the kernel team's ACKs for now. + +This reverts commit 20424eae73ff0bc78802b8fdf5b2bc9c0d587772. + +As Marcel points out in #130870, this patch is incorrect. The bug is +fixed in later bluez userspace packages. + +Signed-off-by: Andres Salomon +--- + include/net/bluetooth/hci_core.h | 8 +-- + include/net/bluetooth/sco.h | 5 ++ + net/bluetooth/hci_conn.c | 30 +-------- + net/bluetooth/hci_core.c | 108 ++++++++++++------------------ + net/bluetooth/hci_event.c | 7 ++- + net/bluetooth/sco.c | 136 +++++--------------------------------- + 6 files changed, 73 insertions(+), 221 deletions(-) + +diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h +index 65a8e6b..ea13baa 100644 +--- a/include/net/bluetooth/hci_core.h ++++ b/include/net/bluetooth/hci_core.h +@@ -25,8 +25,6 @@ + #ifndef __HCI_CORE_H + #define __HCI_CORE_H + +-#include +- + #include + + /* HCI upper protocols */ +@@ -95,7 +93,7 @@ struct hci_dev { + + atomic_t cmd_cnt; + unsigned int acl_cnt; +- atomic_t sco_cnt; ++ unsigned int sco_cnt; + + unsigned int acl_mtu; + unsigned int sco_mtu; +@@ -152,6 +150,7 @@ struct hci_conn { + struct list_head list; + + atomic_t refcnt; ++ spinlock_t lock; + + bdaddr_t dst; + __u16 handle; +@@ -168,11 +167,10 @@ struct hci_conn { + __u8 power_save; + unsigned long pend; + +- atomic_t sent; ++ unsigned int sent; + + struct sk_buff_head data_q; + +- struct hrtimer tx_timer; + struct timer_list disc_timer; + struct timer_list idle_timer; + +diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h +index 599b3d0..e28a2a7 100644 +--- a/include/net/bluetooth/sco.h ++++ b/include/net/bluetooth/sco.h +@@ -26,7 +26,12 @@ + #define __SCO_H + + /* SCO defaults */ ++#define SCO_DEFAULT_MTU 500 ++#define SCO_DEFAULT_FLUSH_TO 0xFFFF ++ + #define SCO_CONN_TIMEOUT (HZ * 40) ++#define SCO_DISCONN_TIMEOUT (HZ * 2) ++#define SCO_CONN_IDLE_TIMEOUT (HZ * 60) + + /* SCO socket address */ + struct sockaddr_sco { +diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c +index e71af27..34d1a3c 100644 +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -188,26 +188,6 @@ static void hci_conn_idle(unsigned long arg) + hci_conn_enter_sniff_mode(conn); + } + +-static enum hrtimer_restart hci_sco_tx_timer(struct hrtimer *timer) +-{ +- struct hci_conn *conn = container_of(timer, struct hci_conn, tx_timer); +-#ifdef CONFIG_BT_HCI_CORE_DEBUG +- ktime_t now = timer->base->get_time(); +- +- BT_DBG("%s, conn %p, time %5lu.%06lu", conn->hdev->name, conn, +- (unsigned long) now.tv64, +- do_div(now.tv64, NSEC_PER_SEC) / 1000); +-#endif +- +- if (atomic_read(&conn->sent) > 0) { +- atomic_dec(&conn->sent); +- atomic_inc(&conn->hdev->sco_cnt); +- hci_sched_tx(conn->hdev); +- } +- return HRTIMER_NORESTART; +-} +- +- + struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) + { + struct hci_conn *conn; +@@ -228,11 +208,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) + + skb_queue_head_init(&conn->data_q); + +- hrtimer_init(&conn->tx_timer, CLOCK_MONOTONIC, HRTIMER_NORESTART); +- +- if(type == SCO_LINK) +- conn->tx_timer.function = hci_sco_tx_timer; +- + init_timer(&conn->disc_timer); + conn->disc_timer.function = hci_conn_timeout; + conn->disc_timer.data = (unsigned long) conn; +@@ -242,7 +217,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) + conn->idle_timer.data = (unsigned long) conn; + + atomic_set(&conn->refcnt, 0); +- atomic_set(&conn->sent, 0); + + hci_dev_hold(hdev); + +@@ -269,15 +243,13 @@ int hci_conn_del(struct hci_conn *conn) + + del_timer(&conn->disc_timer); + +- hrtimer_cancel(&conn->tx_timer); +- + if (conn->type == ACL_LINK) { + struct hci_conn *sco = conn->link; + if (sco) + sco->link = NULL; + + /* Unacked frames */ +- hdev->acl_cnt += atomic_read(&conn->sent); ++ hdev->acl_cnt += conn->sent; + } else { + struct hci_conn *acl = conn->link; + if (acl) { +diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c +index 24c2d92..76f5f6f 100644 +--- a/net/bluetooth/hci_core.c ++++ b/net/bluetooth/hci_core.c +@@ -624,8 +624,7 @@ int hci_dev_reset(__u16 dev) + hdev->flush(hdev); + + atomic_set(&hdev->cmd_cnt, 1); +- atomic_set(&hdev->sco_cnt, 0); +- hdev->acl_cnt = 0; ++ hdev->acl_cnt = 0; hdev->sco_cnt = 0; + + if (!test_bit(HCI_RAW, &hdev->flags)) + ret = __hci_request(hdev, hci_reset_req, 0, +@@ -1231,7 +1230,6 @@ int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) + { + struct hci_dev *hdev = conn->hdev; + struct hci_sco_hdr hdr; +- ktime_t now; + + BT_DBG("%s len %d", hdev->name, skb->len); + +@@ -1240,13 +1238,6 @@ int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) + return -EINVAL; + } + +- now = conn->tx_timer.base->get_time(); +- +- /* force a clean start for 100 ms or later underrun */ +- if (conn->tx_timer.expires.tv64 + NSEC_PER_SEC / 10 <= now.tv64) { +- conn->tx_timer.expires = now; +- } +- + hdr.handle = cpu_to_le16(conn->handle); + hdr.dlen = skb->len; + +@@ -1264,12 +1255,12 @@ EXPORT_SYMBOL(hci_send_sco); + + /* ---- HCI TX task (outgoing data) ---- */ + +-/* HCI ACL Connection scheduler */ +-static inline struct hci_conn *hci_low_sent_acl(struct hci_dev *hdev, int *quote) ++/* HCI Connection scheduler */ ++static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote) + { + struct hci_conn_hash *h = &hdev->conn_hash; + struct hci_conn *conn = NULL; +- unsigned int num = 0, min = ~0; ++ int num = 0, min = ~0; + struct list_head *p; + + /* We don't have to lock device here. Connections are always +@@ -1278,22 +1269,20 @@ static inline struct hci_conn *hci_low_sent_acl(struct hci_dev *hdev, int *quote + struct hci_conn *c; + c = list_entry(p, struct hci_conn, list); + +- BT_DBG("c->type %d c->state %d len(c->data_q) %d min %d c->sent %d", +- c->type, c->state, skb_queue_len(&c->data_q), min, atomic_read(&c->sent)); +- +- if (c->type != ACL_LINK || c->state != BT_CONNECTED ++ if (c->type != type || c->state != BT_CONNECTED + || skb_queue_empty(&c->data_q)) + continue; + num++; + +- if (atomic_read(&c->sent) < min) { +- min = atomic_read(&c->sent); ++ if (c->sent < min) { ++ min = c->sent; + conn = c; + } + } + + if (conn) { +- int q = hdev->acl_cnt / num; ++ int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt); ++ int q = cnt / num; + *quote = q ? q : 1; + } else + *quote = 0; +@@ -1313,7 +1302,7 @@ static inline void hci_acl_tx_to(struct hci_dev *hdev) + /* Kill stalled connections */ + list_for_each(p, &h->list) { + c = list_entry(p, struct hci_conn, list); +- if (c->type == ACL_LINK && atomic_read(&c->sent)) { ++ if (c->type == ACL_LINK && c->sent) { + BT_ERR("%s killing stalled ACL connection %s", + hdev->name, batostr(&c->dst)); + hci_acl_disconn(c, 0x13); +@@ -1336,7 +1325,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev) + hci_acl_tx_to(hdev); + } + +- while (hdev->acl_cnt && (conn = hci_low_sent_acl(hdev, "e))) { ++ while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { + while (quote-- && (skb = skb_dequeue(&conn->data_q))) { + BT_DBG("skb %p len %d", skb, skb->len); + +@@ -1346,61 +1335,48 @@ static inline void hci_sched_acl(struct hci_dev *hdev) + hdev->acl_last_tx = jiffies; + + hdev->acl_cnt--; +- atomic_inc(&conn->sent); ++ conn->sent++; + } + } + } + +-/* HCI SCO Connection scheduler */ +- ++/* Schedule SCO */ + static inline void hci_sched_sco(struct hci_dev *hdev) + { +- struct hci_conn_hash *h = &hdev->conn_hash; ++ struct hci_conn *conn; + struct sk_buff *skb; +- struct list_head *p; +- struct hci_conn *c; +- ktime_t now, pkt_time; +- ++ int quote; ++ + BT_DBG("%s", hdev->name); +- +- /* We don't have to lock device here. Connections are always +- added and removed with TX task disabled. */ +- list_for_each(p, &h->list) { +- c = list_entry(p, struct hci_conn, list); +- +- /* SCO scheduling algorithm makes sure there is never more than +- 1 outstanding packet for each connection */ + +- if (c->type == ACL_LINK) +- continue; ++ while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, "e))) { ++ while (quote-- && (skb = skb_dequeue(&conn->data_q))) { ++ BT_DBG("skb %p len %d", skb, skb->len); ++ hci_send_frame(skb); + +- if (atomic_read(&c->sent) >= 1) +- continue; ++ conn->sent++; ++ if (conn->sent == ~0) ++ conn->sent = 0; ++ } ++ } ++} + +- if (c->state != BT_CONNECTED) +- continue; ++static inline void hci_sched_esco(struct hci_dev *hdev) ++{ ++ struct hci_conn *conn; ++ struct sk_buff *skb; ++ int quote; + +- if (atomic_read(&hdev->sco_cnt) <= 0) +- continue; ++ BT_DBG("%s", hdev->name); + +- if ((skb = skb_dequeue(&c->data_q)) == NULL) +- continue; ++ while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, "e))) { ++ while (quote-- && (skb = skb_dequeue(&conn->data_q))) { ++ BT_DBG("skb %p len %d", skb, skb->len); ++ hci_send_frame(skb); + +- hci_send_frame(skb); +- +- atomic_inc(&c->sent); +- atomic_dec(&hdev->sco_cnt); +- +- pkt_time = ktime_set(0, NSEC_PER_SEC / 16000 * (skb->len - HCI_SCO_HDR_SIZE)); +- now = c->tx_timer.base->get_time(); +- +- c->tx_timer.expires.tv64 += pkt_time.tv64; +- if (c->tx_timer.expires.tv64 > now.tv64) { +- hrtimer_restart(&c->tx_timer); +- } else { +- /* Timer is to expire in the past - force timer expiration. +- this can happen if timer base precision is less than pkt_time */ +- c->tx_timer.function(&c->tx_timer); ++ conn->sent++; ++ if (conn->sent == ~0) ++ conn->sent = 0; + } + } + } +@@ -1412,13 +1388,15 @@ static void hci_tx_task(unsigned long arg) + + read_lock(&hci_task_lock); + +- BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, atomic_read(&hdev->sco_cnt)); ++ BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt); + + /* Schedule queues and send stuff to HCI driver */ + ++ hci_sched_acl(hdev); ++ + hci_sched_sco(hdev); + +- hci_sched_acl(hdev); ++ hci_sched_esco(hdev); + + /* Send next queued raw (unknown type) packet */ + while ((skb = skb_dequeue(&hdev->raw_q))) +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 9a99247..46df2e4 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -434,7 +434,7 @@ static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) + } + + hdev->acl_cnt = hdev->acl_pkts; +- atomic_set(&hdev->sco_cnt, hdev->sco_pkts); ++ hdev->sco_cnt = hdev->sco_pkts; + + BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name, + hdev->acl_mtu, hdev->acl_pkts, +@@ -1157,11 +1157,14 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s + + conn = hci_conn_hash_lookup_handle(hdev, handle); + if (conn) { +- atomic_sub(count, &conn->sent); ++ conn->sent -= count; + + if (conn->type == ACL_LINK) { + if ((hdev->acl_cnt += count) > hdev->acl_pkts) + hdev->acl_cnt = hdev->acl_pkts; ++ } else { ++ if ((hdev->sco_cnt += count) > hdev->sco_pkts) ++ hdev->sco_cnt = hdev->sco_pkts; + } + } + } +diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c +index 97f13c4..153e7f6 100644 +--- a/net/bluetooth/sco.c ++++ b/net/bluetooth/sco.c +@@ -53,13 +53,7 @@ + #define BT_DBG(D...) + #endif + +-#define VERSION "0.6" +- +-#define MAX_SCO_TXBUFS 200 +-#define MAX_SCO_RXBUFS 200 +- +-#define DEFAULT_SCO_TXBUFS 5 +-#define DEFAULT_SCO_RXBUFS 5 ++#define VERSION "0.5" + + static const struct proto_ops sco_sock_ops; + +@@ -75,33 +69,6 @@ static int sco_conn_del(struct hci_conn *conn, int err); + static void sco_sock_close(struct sock *sk); + static void sco_sock_kill(struct sock *sk); + +-/* +- * Write buffer destructor automatically called from kfree_skb. +- */ +-void sco_sock_wfree(struct sk_buff *skb) +-{ +- struct sock *sk = skb->sk; +- +- atomic_dec(&sk->sk_wmem_alloc); +- sk->sk_write_space(sk); +- sock_put(sk); +-} +- +-static void sco_sock_write_space(struct sock *sk) +-{ +- read_lock(&sk->sk_callback_lock); +- +- if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { +- if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) +- wake_up_interruptible(sk->sk_sleep); +- +- if (sock_writeable(sk)) +- sk_wake_async(sk, 2, POLL_OUT); +- } +- +- read_unlock(&sk->sk_callback_lock); +-} +- + /* ---- SCO timers ---- */ + static void sco_sock_timeout(unsigned long arg) + { +@@ -274,55 +241,33 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) + { + struct sco_conn *conn = sco_pi(sk)->conn; + struct sk_buff *skb; +- int err; ++ int err, count; ++ ++ /* Check outgoing MTU */ ++ if (len > conn->mtu) ++ return -EINVAL; + + BT_DBG("sk %p len %d", sk, len); + +- if (!(skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) ++ count = min_t(unsigned int, conn->mtu, len); ++ if (!(skb = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err))) + return err; + +- /* fix sk_wmem_alloc value : by default it is increased by skb->truesize, but +- we want it only increased by 1 */ +- atomic_sub(skb->truesize - 1, &sk->sk_wmem_alloc); +- /* fix destructor */ +- skb->destructor = sco_sock_wfree; +- +- if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { ++ if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { + err = -EFAULT; + goto fail; + } + +- err = hci_send_sco(conn->hcon, skb); +- +- if (err < 0) +- goto fail; ++ if ((err = hci_send_sco(conn->hcon, skb)) < 0) ++ return err; + +- return len; ++ return count; + + fail: + kfree_skb(skb); + return err; + } + +-static int sco_sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) +-{ +- BT_DBG("sock %p, sk_rcvbuf %d, qlen %d", sk, sk->sk_rcvbuf, skb_queue_len(&sk->sk_receive_queue)); +- +- if (skb_queue_len(&sk->sk_receive_queue) + 1 > (unsigned)sk->sk_rcvbuf) +- return -ENOMEM; +- +- skb->dev = NULL; +- skb->sk = sk; +- skb->destructor = NULL; +- +- skb_queue_tail(&sk->sk_receive_queue, skb); +- +- if (!sock_flag(sk, SOCK_DEAD)) +- sk->sk_data_ready(sk, 1); +- +- return 0; +-} +- + static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) + { + struct sock *sk = sco_chan_get(conn); +@@ -335,7 +280,7 @@ static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) + if (sk->sk_state != BT_CONNECTED) + goto drop; + +- if (!sco_sock_queue_rcv_skb(sk, skb)) ++ if (!sock_queue_rcv_skb(sk, skb)) + return; + + drop: +@@ -390,6 +335,7 @@ static void sco_sock_destruct(struct sock *sk) + BT_DBG("sk %p", sk); + + skb_queue_purge(&sk->sk_receive_queue); ++ skb_queue_purge(&sk->sk_write_queue); + } + + static void sco_sock_cleanup_listen(struct sock *parent) +@@ -487,10 +433,6 @@ static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int pro + INIT_LIST_HEAD(&bt_sk(sk)->accept_q); + + sk->sk_destruct = sco_sock_destruct; +- sk->sk_write_space = sco_sock_write_space; +- +- sk->sk_sndbuf = DEFAULT_SCO_TXBUFS; +- sk->sk_rcvbuf = DEFAULT_SCO_RXBUFS; + sk->sk_sndtimeo = SCO_CONN_TIMEOUT; + + sock_reset_flag(sk, SOCK_ZAPPED); +@@ -721,7 +663,6 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock, + static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) + { + struct sock *sk = sock->sk; +- u32 opt; + int err = 0; + + BT_DBG("sk %p", sk); +@@ -729,32 +670,6 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char + lock_sock(sk); + + switch (optname) { +- case SO_SNDBUF: +- if (get_user(opt, (u32 __user *) optval)) { +- err = -EFAULT; +- break; +- } +- if (opt > MAX_SCO_TXBUFS) { +- err = -EINVAL; +- break; +- } +- +- sk->sk_sndbuf = opt; +- /* Wake up sending tasks if we upped the value */ +- sk->sk_write_space(sk); +- break; +- case SO_RCVBUF: +- if (get_user(opt, (u32 __user *) optval)) { +- err = -EFAULT; +- break; +- } +- if (opt > MAX_SCO_RXBUFS) { +- err = -EINVAL; +- break; +- } +- +- sk->sk_rcvbuf = opt; +- break; + default: + err = -ENOPROTOOPT; + break; +@@ -770,7 +685,6 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char + struct sco_options opts; + struct sco_conninfo cinfo; + int len, err = 0; +- int val; + + BT_DBG("sk %p", sk); + +@@ -780,24 +694,6 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char + lock_sock(sk); + + switch (optname) { +- case SO_RCVBUF: +- val = sk->sk_rcvbuf; +- +- len = min_t(unsigned int, len, sizeof(val)); +- if (copy_to_user(optval, (char *) &val, len)) +- err = -EFAULT; +- +- break; +- +- case SO_SNDBUF: +- val = sk->sk_sndbuf; +- +- len = min_t(unsigned int, len, sizeof(val)); +- if (copy_to_user(optval, (char *) &val, len)) +- err = -EFAULT; +- +- break; +- + case SCO_OPTIONS: + if (sk->sk_state != BT_CONNECTED) { + err = -ENOTCONN; +@@ -809,7 +705,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char + BT_DBG("mtu %d", opts.mtu); + + len = min_t(unsigned int, len, sizeof(opts)); +- if (copy_to_user(optval, (char *) &opts, len)) ++ if (copy_to_user(optval, (char *)&opts, len)) + err = -EFAULT; + + break; +@@ -824,7 +720,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char + memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3); + + len = min_t(unsigned int, len, sizeof(cinfo)); +- if (copy_to_user(optval, (char *) &cinfo, len)) ++ if (copy_to_user(optval, (char *)&cinfo, len)) + err = -EFAULT; + + break; +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0161-UBUNTU-Start-new-release.patch +++ linux-2.6.24/patches/0161-UBUNTU-Start-new-release.patch @@ -0,0 +1,31 @@ +From 197f7eb014abe4ff65c0eed452addfbfaff393a4 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 21 Aug 2009 12:27:01 +0100 +Subject: [PATCH 161/170] UBUNTU: Start new release + +Ignore: yes + +Signed-off-by: Andy Whitcroft +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 4b6af13..fbcacdf 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-24.57netbook02) UNRELEASED; urgency=low ++ ++ CHANGELOG: Do not edit directly. Autogenerated at release. ++ CHANGELOG: Use the printchanges target to see the curent changes. ++ CHANGELOG: Use the insertchanges target to create the final log. ++ ++ -- Andy Whitcroft Fri, 21 Aug 2009 12:27:50 +0100 ++ + linux (2.6.24-24.57netbook01) netbook-common; urgency=low + + [ Andy Whitcroft ] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0077-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook12.patch +++ linux-2.6.24/patches/0077-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook12.patch @@ -0,0 +1,30 @@ +From ea64add4927ce28160e43c2509eab977822eae0c Mon Sep 17 00:00:00 2001 +From: Tony Espy +Date: Wed, 5 Nov 2008 18:18:28 -0500 +Subject: [PATCH 077/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook12 + +Ignore: yes +Signed-off-by: Tony Espy +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 9342a06..8529e57 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-19.41netbook12) hardy; urgency=low ++ ++ [Colin Ian King] ++ ++ * ACPI reboot method - workaround for hardware on port 0xCF9. ++ ++ -- Tony Espy Wed, 05 Nov 2008 23:09:51 +0000 ++ + linux (2.6.24-19.41netbook11) hardy; urgency=low + + [Upstream Kernel Changes] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0042-Add-config-option-for-Memory-Stick-driver.patch +++ linux-2.6.24/patches/0042-Add-config-option-for-Memory-Stick-driver.patch @@ -0,0 +1,41 @@ +From 94fbdc0f11252cfe85f465833a974d7c94ff759b Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 15 Jul 2008 13:56:49 +0100 +Subject: [PATCH 042/170] Add config option for Memory Stick driver + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/mmc/Kconfig | 6 ++++++ + drivers/mmc/Makefile | 2 +- + 2 files changed, 7 insertions(+), 1 deletions(-) + +diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig +index 3e351f3..01bb23b 100644 +--- a/drivers/mmc/Kconfig ++++ b/drivers/mmc/Kconfig +@@ -19,6 +19,12 @@ config MMC_DEBUG + help + This is an option for use by developers; most people should + say N here. This enables MMC core and driver debugging. ++ ++config MSPRO ++ bool "Memory Stick Pro" ++ depends on MMC != n ++ help ++ This option is to support Sony Memory Stick Pro + if MMC + + source "drivers/mmc/core/Kconfig" +diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile +index 8eb49ea..3cba7a5 100644 +--- a/drivers/mmc/Makefile ++++ b/drivers/mmc/Makefile +@@ -10,4 +10,4 @@ obj-$(CONFIG_MMC) += core/ + obj-$(CONFIG_MMC) += card/ + obj-$(CONFIG_MMC) += host/ + obj-$(CONFIG_MSS) += mss/ +- ++obj-$(CONFIG_MSPRO) += ms/ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0005-consoles-polling-support-kgdboc.patch +++ linux-2.6.24/patches/0005-consoles-polling-support-kgdboc.patch @@ -0,0 +1,546 @@ +From f4c6e1b223f91a2279a96c5a416f0896be016498 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Mon, 10 Mar 2008 08:41:28 +0100 +Subject: [PATCH 005/170] consoles: polling support, kgdboc + +polled console handling support, to access a console in an irq-less +way while in debug or irq context. + +absolutely zero impact as long as CONFIG_CONSOLE_POLL is disabled. +(which is the default) + +[ jan.kiszka@siemens.com: lots of cleanups ] +[ mingo@elte.hu: redesign, splitups, cleanups. ] + +Signed-off-by: Jason Wessel +Signed-off-by: Ingo Molnar +Signed-off-by: Jan Kiszka +Reviewed-by: Thomas Gleixner +--- + drivers/char/tty_io.c | 47 ++++++++++++ + drivers/serial/8250.c | 58 +++++++++++++++ + drivers/serial/Kconfig | 3 + + drivers/serial/Makefile | 1 + + drivers/serial/kgdboc.c | 163 ++++++++++++++++++++++++++++++++++++++++++ + drivers/serial/serial_core.c | 72 ++++++++++++++++++- + include/linux/serial_core.h | 4 + + include/linux/tty_driver.h | 12 +++ + 8 files changed, 357 insertions(+), 3 deletions(-) + create mode 100644 drivers/serial/kgdboc.c + +diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c +index f36fecd..e0cdb94 100644 +--- a/drivers/char/tty_io.c ++++ b/drivers/char/tty_io.c +@@ -1153,6 +1153,48 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) + return NULL; + } + ++#ifdef CONFIG_CONSOLE_POLL ++ ++/** ++ * tty_find_polling_driver - find device of a polled tty ++ * @name: name string to match ++ * @line: pointer to resulting tty line nr ++ * ++ * This routine returns a tty driver structure, given a name ++ * and the condition that the tty driver is capable of polled ++ * operation. ++ */ ++struct tty_driver *tty_find_polling_driver(char *name, int *line) ++{ ++ struct tty_driver *p, *res = NULL; ++ int tty_line = 0; ++ char *str; ++ ++ mutex_lock(&tty_mutex); ++ /* Search through the tty devices to look for a match */ ++ list_for_each_entry(p, &tty_drivers, tty_drivers) { ++ str = name + strlen(p->name); ++ tty_line = simple_strtoul(str, &str, 10); ++ if (*str == ',') ++ str++; ++ if (*str == '\0') ++ str = 0; ++ ++ if (tty_line >= 0 && tty_line <= p->num && p->poll_init && ++ !p->poll_init(p, tty_line, str)) { ++ ++ res = p; ++ *line = tty_line; ++ break; ++ } ++ } ++ mutex_unlock(&tty_mutex); ++ ++ return res; ++} ++EXPORT_SYMBOL_GPL(tty_find_polling_driver); ++#endif ++ + /** + * tty_check_change - check for POSIX terminal changes + * @tty: tty to check +@@ -3847,6 +3889,11 @@ void tty_set_operations(struct tty_driver *driver, + driver->write_proc = op->write_proc; + driver->tiocmget = op->tiocmget; + driver->tiocmset = op->tiocmset; ++#ifdef CONFIG_CONSOLE_POLL ++ driver->poll_init = op->poll_init; ++ driver->poll_get_char = op->poll_get_char; ++ driver->poll_put_char = op->poll_put_char; ++#endif + } + + +diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c +index d82399b..30c1622 100644 +--- a/drivers/serial/8250.c ++++ b/drivers/serial/8250.c +@@ -1739,6 +1739,60 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits) + } + } + ++#ifdef CONFIG_CONSOLE_POLL ++/* ++ * Console polling routines for writing and reading from the uart while ++ * in an interrupt or debug context. ++ */ ++ ++static int serial8250_get_poll_char(struct uart_port *port) ++{ ++ struct uart_8250_port *up = (struct uart_8250_port *)port; ++ unsigned char lsr = serial_inp(up, UART_LSR); ++ ++ while (!(lsr & UART_LSR_DR)) ++ lsr = serial_inp(up, UART_LSR); ++ ++ return serial_inp(up, UART_RX); ++} ++ ++ ++static void serial8250_put_poll_char(struct uart_port *port, ++ unsigned char c) ++{ ++ unsigned int ier; ++ struct uart_8250_port *up = (struct uart_8250_port *)port; ++ ++ /* ++ * First save the IER then disable the interrupts ++ */ ++ ier = serial_in(up, UART_IER); ++ if (up->capabilities & UART_CAP_UUE) ++ serial_out(up, UART_IER, UART_IER_UUE); ++ else ++ serial_out(up, UART_IER, 0); ++ ++ wait_for_xmitr(up, BOTH_EMPTY); ++ /* ++ * Send the character out. ++ * If a LF, also do CR... ++ */ ++ serial_out(up, UART_TX, c); ++ if (c == 10) { ++ wait_for_xmitr(up, BOTH_EMPTY); ++ serial_out(up, UART_TX, 13); ++ } ++ ++ /* ++ * Finally, wait for transmitter to become empty ++ * and restore the IER ++ */ ++ wait_for_xmitr(up, BOTH_EMPTY); ++ serial_out(up, UART_IER, ier); ++} ++ ++#endif /* CONFIG_CONSOLE_POLL */ ++ + static int serial8250_startup(struct uart_port *port) + { + struct uart_8250_port *up = (struct uart_8250_port *)port; +@@ -2388,6 +2442,10 @@ static struct uart_ops serial8250_pops = { + .request_port = serial8250_request_port, + .config_port = serial8250_config_port, + .verify_port = serial8250_verify_port, ++#ifdef CONFIG_CONSOLE_POLL ++ .poll_get_char = serial8250_get_poll_char, ++ .poll_put_char = serial8250_put_poll_char, ++#endif + }; + + static struct uart_8250_port serial8250_ports[UART_NR]; +diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig +index d7e1996..efcb82d 100644 +--- a/drivers/serial/Kconfig ++++ b/drivers/serial/Kconfig +@@ -942,6 +942,9 @@ config SERIAL_CORE + config SERIAL_CORE_CONSOLE + bool + ++config CONSOLE_POLL ++ bool ++ + config SERIAL_68328 + bool "68328 serial support" + depends on M68328 || M68EZ328 || M68VZ328 +diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile +index af6377d..5aa9765 100644 +--- a/drivers/serial/Makefile ++++ b/drivers/serial/Makefile +@@ -64,3 +64,4 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o + obj-$(CONFIG_SERIAL_NETX) += netx-serial.o + obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o + obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o ++obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o +diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c +new file mode 100644 +index 0000000..3418307 +--- /dev/null ++++ b/drivers/serial/kgdboc.c +@@ -0,0 +1,163 @@ ++/* ++ * Based on the same principle as kgdboe using the NETPOLL api, this ++ * driver uses a console polling api to implement a gdb serial inteface ++ * which is multiplexed on a console port. ++ * ++ * Maintainer: Jason Wessel ++ * ++ * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++#include ++#include ++#include ++#include ++ ++#define MAX_CONFIG_LEN 40 ++ ++static struct kgdb_io kgdboc_io_ops; ++ ++/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ ++static int configured = -1; ++ ++static char config[MAX_CONFIG_LEN]; ++static struct kparam_string kps = { ++ .string = config, ++ .maxlen = MAX_CONFIG_LEN, ++}; ++ ++static struct tty_driver *kgdb_tty_driver; ++static int kgdb_tty_line; ++ ++static int kgdboc_option_setup(char *opt) ++{ ++ if (strlen(opt) > MAX_CONFIG_LEN) { ++ printk(KERN_ERR "kgdboc: config string too long\n"); ++ return -ENOSPC; ++ } ++ strcpy(config, opt); ++ ++ return 0; ++} ++ ++__setup("kgdboc=", kgdboc_option_setup); ++ ++static int configure_kgdboc(void) ++{ ++ struct tty_driver *p; ++ int tty_line = 0; ++ int err; ++ ++ err = kgdboc_option_setup(config); ++ if (err || !strlen(config) || isspace(config[0])) ++ goto noconfig; ++ ++ err = -ENODEV; ++ ++ p = tty_find_polling_driver(config, &tty_line); ++ if (!p) ++ goto noconfig; ++ ++ kgdb_tty_driver = p; ++ kgdb_tty_line = tty_line; ++ ++ err = kgdb_register_io_module(&kgdboc_io_ops); ++ if (err) ++ goto noconfig; ++ ++ configured = 1; ++ ++ return 0; ++ ++noconfig: ++ config[0] = 0; ++ configured = 0; ++ ++ return err; ++} ++ ++static int __init init_kgdboc(void) ++{ ++ /* Already configured? */ ++ if (configured == 1) ++ return 0; ++ ++ return configure_kgdboc(); ++} ++ ++static void cleanup_kgdboc(void) ++{ ++ if (configured == 1) ++ kgdb_unregister_io_module(&kgdboc_io_ops); ++} ++ ++static int kgdboc_get_char(void) ++{ ++ return kgdb_tty_driver->poll_get_char(kgdb_tty_driver, kgdb_tty_line); ++} ++ ++static void kgdboc_put_char(u8 chr) ++{ ++ kgdb_tty_driver->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr); ++} ++ ++static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) ++{ ++ if (strlen(kmessage) >= MAX_CONFIG_LEN) { ++ printk(KERN_ERR "kgdboc: config string too long\n"); ++ return -ENOSPC; ++ } ++ ++ /* Only copy in the string if the init function has not run yet */ ++ if (configured < 0) { ++ strcpy(config, kmessage); ++ return 0; ++ } ++ ++ if (kgdb_connected) { ++ printk(KERN_ERR ++ "kgdboc: Cannot reconfigure while KGDB is connected.\n"); ++ ++ return -EBUSY; ++ } ++ ++ strcpy(config, kmessage); ++ ++ if (configured == 1) ++ cleanup_kgdboc(); ++ ++ /* Go and configure with the new params. */ ++ return configure_kgdboc(); ++} ++ ++static void kgdboc_pre_exp_handler(void) ++{ ++ /* Increment the module count when the debugger is active */ ++ if (!kgdb_connected) ++ try_module_get(THIS_MODULE); ++} ++ ++static void kgdboc_post_exp_handler(void) ++{ ++ /* decrement the module count when the debugger detaches */ ++ if (!kgdb_connected) ++ module_put(THIS_MODULE); ++} ++ ++static struct kgdb_io kgdboc_io_ops = { ++ .name = "kgdboc", ++ .read_char = kgdboc_get_char, ++ .write_char = kgdboc_put_char, ++ .pre_exception = kgdboc_pre_exp_handler, ++ .post_exception = kgdboc_post_exp_handler, ++}; ++ ++module_init(init_kgdboc); ++module_exit(cleanup_kgdboc); ++module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); ++MODULE_PARM_DESC(kgdboc, "[,baud]"); ++MODULE_DESCRIPTION("KGDB Console TTY Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c +index 3bb5d24..0000240 100644 +--- a/drivers/serial/serial_core.c ++++ b/drivers/serial/serial_core.c +@@ -1825,7 +1825,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) + * options. The format of the string is , + * eg: 115200n8r + */ +-void __init ++void + uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) + { + char *s = options; +@@ -1840,6 +1840,7 @@ uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) + if (*s) + *flow = *s; + } ++EXPORT_SYMBOL_GPL(uart_parse_options); + + struct baud_rates { + unsigned int rate; +@@ -1870,7 +1871,7 @@ static const struct baud_rates baud_rates[] = { + * @bits: number of data bits + * @flow: flow control character - 'r' (rts) + */ +-int __init ++int + uart_set_options(struct uart_port *port, struct console *co, + int baud, int parity, int bits, int flow) + { +@@ -1922,10 +1923,16 @@ uart_set_options(struct uart_port *port, struct console *co, + port->mctrl |= TIOCM_DTR; + + port->ops->set_termios(port, &termios, &dummy); +- co->cflag = termios.c_cflag; ++ /* ++ * Allow the setting of the UART parameters with a NULL console ++ * too: ++ */ ++ if (co) ++ co->cflag = termios.c_cflag; + + return 0; + } ++EXPORT_SYMBOL_GPL(uart_set_options); + #endif /* CONFIG_SERIAL_CORE_CONSOLE */ + + static void uart_change_pm(struct uart_state *state, int pm_state) +@@ -2173,6 +2180,60 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, + } + } + ++#ifdef CONFIG_CONSOLE_POLL ++ ++static int uart_poll_init(struct tty_driver *driver, int line, char *options) ++{ ++ struct uart_driver *drv = driver->driver_state; ++ struct uart_state *state = drv->state + line; ++ struct uart_port *port; ++ int baud = 9600; ++ int bits = 8; ++ int parity = 'n'; ++ int flow = 'n'; ++ ++ if (!state || !state->port) ++ return -1; ++ ++ port = state->port; ++ if (!(port->ops->poll_get_char && port->ops->poll_put_char)) ++ return -1; ++ ++ if (options) { ++ uart_parse_options(options, &baud, &parity, &bits, &flow); ++ return uart_set_options(port, NULL, baud, parity, bits, flow); ++ } ++ ++ return 0; ++} ++ ++static int uart_poll_get_char(struct tty_driver *driver, int line) ++{ ++ struct uart_driver *drv = driver->driver_state; ++ struct uart_state *state = drv->state + line; ++ struct uart_port *port; ++ ++ if (!state || !state->port) ++ return -1; ++ ++ port = state->port; ++ return port->ops->poll_get_char(port); ++} ++ ++static void uart_poll_put_char(struct tty_driver *driver, int line, char ch) ++{ ++ struct uart_driver *drv = driver->driver_state; ++ struct uart_state *state = drv->state + line; ++ struct uart_port *port; ++ ++ if (!state || !state->port) ++ return; ++ ++ port = state->port; ++ port->ops->poll_put_char(port, ch); ++} ++#endif ++ + static const struct tty_operations uart_ops = { + .open = uart_open, + .close = uart_close, +@@ -2197,6 +2258,11 @@ static const struct tty_operations uart_ops = { + #endif + .tiocmget = uart_tiocmget, + .tiocmset = uart_tiocmset, ++#ifdef CONFIG_CONSOLE_POLL ++ .poll_init = uart_poll_init, ++ .poll_get_char = uart_poll_get_char, ++ .poll_put_char = uart_poll_put_char, ++#endif + }; + + /** +diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h +index 9963f81..d97115a 100644 +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -207,6 +207,10 @@ struct uart_ops { + void (*config_port)(struct uart_port *, int); + int (*verify_port)(struct uart_port *, struct serial_struct *); + int (*ioctl)(struct uart_port *, unsigned int, unsigned long); ++#ifdef CONFIG_CONSOLE_POLL ++ void (*poll_put_char)(struct uart_port *, unsigned char); ++ int (*poll_get_char)(struct uart_port *); ++#endif + }; + + #define UART_CONFIG_TYPE (1 << 0) +diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h +index 85c95cd..21f69ac 100644 +--- a/include/linux/tty_driver.h ++++ b/include/linux/tty_driver.h +@@ -125,6 +125,7 @@ + #include + + struct tty_struct; ++struct tty_driver; + + struct tty_operations { + int (*open)(struct tty_struct * tty, struct file * filp); +@@ -157,6 +158,11 @@ struct tty_operations { + int (*tiocmget)(struct tty_struct *tty, struct file *file); + int (*tiocmset)(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear); ++#ifdef CONFIG_CONSOLE_POLL ++ int (*poll_init)(struct tty_driver *driver, int line, char *options); ++ int (*poll_get_char)(struct tty_driver *driver, int line); ++ void (*poll_put_char)(struct tty_driver *driver, int line, char ch); ++#endif + }; + + struct tty_driver { +@@ -220,6 +226,11 @@ struct tty_driver { + int (*tiocmget)(struct tty_struct *tty, struct file *file); + int (*tiocmset)(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear); ++#ifdef CONFIG_CONSOLE_POLL ++ int (*poll_init)(struct tty_driver *driver, int line, char *options); ++ int (*poll_get_char)(struct tty_driver *driver, int line); ++ void (*poll_put_char)(struct tty_driver *driver, int line, char ch); ++#endif + + struct list_head tty_drivers; + }; +@@ -230,6 +241,7 @@ struct tty_driver *alloc_tty_driver(int lines); + void put_tty_driver(struct tty_driver *driver); + void tty_set_operations(struct tty_driver *driver, + const struct tty_operations *op); ++extern struct tty_driver *tty_find_polling_driver(char *name, int *line); + + /* tty driver magic number */ + #define TTY_DRIVER_MAGIC 0x5402 +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0067-Added-PCI-ID-for-Dennis.-Enable-40-wire-cable-detect.patch +++ linux-2.6.24/patches/0067-Added-PCI-ID-for-Dennis.-Enable-40-wire-cable-detect.patch @@ -0,0 +1,25 @@ +From 22f08b9f5147fd6e8030e2f6add629d8fe85ea6d Mon Sep 17 00:00:00 2001 +From: Tony Espy +Date: Fri, 17 Oct 2008 14:49:27 -0400 +Subject: [PATCH 067/170] Added PCI ID for Dennis. Enable 40 wire cable detect to ata_pix.c + +Signed-off-by: Tony Espy +--- + drivers/ata/ata_piix.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c +index 967789c..4f3a9ac 100644 +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -705,6 +705,7 @@ static const struct ich_laptop ich_laptop[] = { + { 0x811A, 0x1509, 0x5001 }, /* SCH on Chelsea */ + { 0x27DF, 0x1028, 0x02b0 }, /* ICH7 on Belmont */ + { 0x27DF, 0x152D, 0x0778 }, /* ICH7 on Natick */ ++ { 0x27DF, 0x103C, 0x361A }, /* ICH7 on Dennis */ + /* end marker */ + { 0, } + }; +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0107-UBUNTU-add-option-disable_streaming_master_mode.patch +++ linux-2.6.24/patches/0107-UBUNTU-add-option-disable_streaming_master_mode.patch @@ -0,0 +1,57 @@ +From 709d1fbbd152e4f6cddd68410472ce78ff117432 Mon Sep 17 00:00:00 2001 +From: Devin Heitmueller +Date: Mon, 23 Mar 2009 16:31:06 -0400 +Subject: [PATCH 107/170] UBUNTU: add option, "disable_streaming_master_mode" + +OriginalAuthor: Devin Heitmueller +OriginalLocation: http://linuxtv.org/hg/v4l-dvb/rev/a79b809b763a + +This mode of the dib0700 is required for usage of any demodulator +other than the dib0x00 demods. + +This was backported from an original patch that adds support for +the PCTV HD Pro 801e. The bits that add the new device support +have been held back due to missing driver dependencies, such as +xc5000 and s5h1411. + +Signed-off-by: Devin Heitmueller +Signed-off-by: Patrick Boettcher +Signed-off-by: Michael Krufky +--- + drivers/media/dvb/dvb-usb/dib0700.h | 1 + + drivers/media/dvb/dvb-usb/dib0700_core.c | 7 ++++++- + 2 files changed, 7 insertions(+), 1 deletions(-) + +diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h +index c84e12d..db879b8 100644 +--- a/drivers/media/dvb/dvb-usb/dib0700.h ++++ b/drivers/media/dvb/dvb-usb/dib0700.h +@@ -41,6 +41,7 @@ struct dib0700_state { + u8 rc_toggle; + u8 is_dib7000pc; + u8 fw_use_new_i2c_api; ++ u8 disable_streaming_master_mode; + }; + + extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); +diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c +index 52363d2..f313002 100644 +--- a/drivers/media/dvb/dvb-usb/dib0700_core.c ++++ b/drivers/media/dvb/dvb-usb/dib0700_core.c +@@ -348,7 +348,12 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) + + b[0] = REQUEST_ENABLE_VIDEO; + b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ +- b[2] = (0x01 << 4); /* Master mode */ ++ ++ if (st->disable_streaming_master_mode == 1) ++ b[2] = 0x00; ++ else ++ b[2] = (0x01 << 4); /* Master mode */ ++ + b[3] = 0x00; + + deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0130-UBUNTU-switch-to-new-rebase-tooling.patch +++ linux-2.6.24/patches/0130-UBUNTU-switch-to-new-rebase-tooling.patch @@ -0,0 +1,266 @@ +From e78f96e3a7c84956e9c7b5e46c333de38fbff4a9 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Sat, 4 Apr 2009 05:16:02 +0100 +Subject: [PATCH 130/170] UBUNTU: switch to new rebase tooling + +Ignore: yes + +Insert the new rebase tooling and fix insertchanges to use the new tags. + +Signed-off-by: Andy Whitcroft +--- + debian/rules.d/1-maintainer.mk | 2 +- + debian/scripts/misc/rebase-branch | 188 +++++++++++++++++++++++++++++++++++++ + debian/scripts/misc/retag-branch | 32 ++++++ + 3 files changed, 221 insertions(+), 1 deletions(-) + create mode 100755 debian/scripts/misc/rebase-branch + create mode 100755 debian/scripts/misc/retag-branch + +diff --git a/debian/rules.d/1-maintainer.mk b/debian/rules.d/1-maintainer.mk +index 4625252..add1e3f 100644 +--- a/debian/rules.d/1-maintainer.mk ++++ b/debian/rules.d/1-maintainer.mk +@@ -66,7 +66,7 @@ endif + @echo "CONCURRENCY_LEVEL = $(CONCURRENCY_LEVEL)" + + printchanges: +- @git-log Ubuntu-$(release)-$(prev_revision)..HEAD | \ ++ @git-log NBK-Ubuntu-$(release)-$(prev_revision)..HEAD | \ + perl -w -f debian/scripts/misc/git-ubuntu-log $(ubuntu_log_opts) + + insertchanges: +diff --git a/debian/scripts/misc/rebase-branch b/debian/scripts/misc/rebase-branch +new file mode 100755 +index 0000000..5368d39 +--- /dev/null ++++ b/debian/scripts/misc/rebase-branch +@@ -0,0 +1,188 @@ ++#!/bin/sh ++ ++# Script to maintain a (target) tree based on the main kernel ++# Author: Amit Kucheria (amit@ubuntu.com) ++# Date: 11/07/08 ++ ++# Assumptions: ++# 1. Every rebase during devel-cycle is an ABI bump ++# 2. The target tree's patches are always on top ++# 3. As a consequence of 2., tags are not really useful ++# 4. autogenerated patches are marked with AUTO; others are marked with SAUCE ++# 5. Keep things in a state that they can be merged back into the main tree at the end of the dev cycle ++ ++targetDir=${1:?"Usage: $0 "} ++remoteTag=${2:?"Usage: $0 "} ++ ++rebasing=".git/rebase-apply" ++ ++# Configuration variables ++release="hardy" ++basever="2.6.24" ++patchDir=$targetDir/patches ++#masterTree=git://zinc.ubuntu.com/ubuntu/ubuntu-$release.git ++#masterName=ubuntu-$release ++baseTag="LPIA-Ubuntu-$basever-0.0" ++tmpTag="tmplpia" ++ ++remoteBranch=auto-tmp-remote ++git=`which git` ++ ++rm -rf .patches "$patchDir" ++mkdir -p $patchDir ++cd $targetDir ++rm -rf "$rebasing/" ++ ++echo "* Check for uncommitted files..." ++$git status | grep -q "nothing to commit" ++if [ ! $? -eq "0" ]; then ++ echo "\tUncommitted changes found!\n\tClean out your tree before running this script. Exiting." ++ exit 1; ++fi ++#$git checkout master ++#$git reset --hard ++ ++echo "\n" ++echo "* Fetching Ubuntu master tree..." ++$git branch -r | grep $masterName ++if [ $? -eq "0" ]; then ++ echo "\t$masterName is already used as a branch name in your tree. Please change the \$masterName variable in this script." ++ exit 1; ++fi ++ ++echo "\n" ++echo "* Exporting current work as patches..." ++$git format-patch -o $patchDir $baseTag ++# Deleting tags is evil... ++#$git tag -l | grep "Ubuntu-2.6.2*" | xargs $git tag -d ++#$git tag -l | grep "Ubuntu-LPIA-2.6.2*" | xargs $git tag -d ++$git tag -d $tmpTag ++ ++# Debugging ++mkdir -p .patches ++cp $patchDir/*.patch .patches ++# end Debugging ++ ++echo "* Cleaning up patches..." ++# Remove auto-generated patches ++find $patchDir -type f -name "*UBUNTU-AUTO*" -print0 | xargs -0 rm -f ++ ++# Remove updates to debian/control, debian/control.stub and di/kernel-versions ++for i in "$patchDir"/*.patch ++do ++ echo "$i ..." ++ awk ' ++ BEGIN { on=1 } ++ /Subject:/ { sub("UBUNTU: 2\\.6\\.", ++ "UBUNTU: NBK-Ubuntu-2.6.", $0); } ++ /^diff --git a\/debian\/control / { on=0; next } ++ /^diff --git a\/debian\/control.stub / { on=0; next } ++ /^diff --git a\/debian\/d-i\/kernel-versions / { on=0; next } ++ /^diff / { on=1 } ++ (on == 1) { print } ++ ' <"$i" >"$i.new" ++ mv "$i.new" "$i" ++ # If the patch is now empty just remove it. ++ if ! grep '^diff ' "$i" >/dev/null; then ++ rm -f "$i" ++ fi ++done ++ ++echo "\n" ++echo "* Starting rebase" ++$git branch -D $remoteBranch ++$git checkout -b $remoteBranch $remoteTag ++ ++# Disable all git hooks ++$git config --bool ubuntu.flavour-changes-ok true ++$git config --bool ubuntu.allow-non-sauce-commit true ++$git config --bool ubuntu.others-changes-ok true ++ ++$git tag -m "Tip of ubuntu git on which we apply patches" $tmpTag ++ ++# Tag our base point on the tree. ++echo "AUTO #0" ++$git commit --allow-empty -s -m "UBUNTU: $baseTag" ++ ++if false; then ++# Move debian/ out of the way ++echo "AUTO #1" ++rm -rf debian-main/ ++$git mv debian/ debian-main/ ++$git commit -s -m "UBUNTU: AUTO: Move upstream debian/ dir out of the way for a lpia-specific debian/" ++$git status ++ ++# Disable all git hooks ++$git config --bool ubuntu.flavour-changes-ok true ++$git config --bool ubuntu.allow-non-sauce-commit true ++$git config --bool ubuntu.others-changes-ok true ++ ++# Copy debian-main/ to debian/ ++echo "AUTO #2" ++cp -a debian-main/ debian/ ++$git add debian/ ++$git commit -a -s -m "UBUNTU: AUTO: Create a new debian/" ++$git status ++ ++# Disable all git hooks ++$git config --bool ubuntu.flavour-changes-ok true ++$git config --bool ubuntu.allow-non-sauce-commit true ++$git config --bool ubuntu.others-changes-ok true ++ ++fi ++ ++# Delete upstream ABI, extra arch/flavours ++echo "AUTO #3" ++$git rm -r debian/abi/\* ++$git rm -r debian/config/\* ++$git rm debian/control.d/vars.generic debian/control.d/vars.server ++$git rm debian/rules.d/amd64.mk debian/rules.d/i386.mk ++$git commit -a -s -m "UBUNTU: AUTO: Delete unncessary ABI/arch/flavours" ++$git status ++ ++# Disable all git hooks ++$git config --bool ubuntu.flavour-changes-ok true ++$git config --bool ubuntu.allow-non-sauce-commit true ++$git config --bool ubuntu.others-changes-ok true ++ ++# Start new changelog ++echo "AUTO #4" ++$git mv debian/changelog debian/changelog.$release ++DEBEMAIL="Ubuntu Kernel Team " \ ++ EDITOR=: dch --create --package linux-lpia --newversion $basever-0.0 ++ ++# Need to change timestamp else patches fail -- use the timestamp of the first ++# entry from the main changelog. ++ts_current=`tail -n1 debian/changelog | sed 's/.*> \(.*\)$/\1/'` ++ts_desired=`tail -n1 debian/changelog.$release | sed 's/.*> \(.*\)$/\1/'` ++sed -i -e "s/${ts_current}/${ts_desired}/" debian/changelog ++ ++currAbi=`head -n1 debian/changelog.$release | sed 's/.*('"$basever"'-\(.*\)\..*).*$$/\1/'` ++sed -i -e "s/$basever-${currAbi}/$basever-1/g" debian/control.stub ++sed -i -e "s/$basever-${currAbi}/$basever-1/g" debian/control ++sed -i -e "s/$basever-${currAbi}/$basever-1/g" debian/d-i/kernel-versions ++$git add debian/changelog debian/control.stub debian/control debian/d-i/kernel-versions ++$git commit -a -s -m "UBUNTU: AUTO: Start new changelog and revert to known abi" ++$git status ++ ++# Apply pending patches ++$git am -C0 patches/* ++if [ -d "$rebasing/" ]; then ++ echo "\tFailed to apply patches" ++ echo "\tPlease fix the patches on branch $remoteBranch and then sync to the master branch" ++ exit 1; ++fi ++ ++# Delete tags and recreate them on rebased tree ++#git tag | grep LPIA | xargs git tag -d ++#git tag -f -s -m $baseTag $baseTag $tmpTag ++git tag -d $tmpTag ++ ++echo "\n" ++echo "If the final result looks good, then do the following to make it permanent:" ++echo " * Run debian/scripts/misc/retag-lpia to retag" ++echo " * git checkout master" ++echo " * git reset --hard $remoteBranch" ++echo " * git remote rm $masterName" ++echo " * rm -rf patches/" ++ +diff --git a/debian/scripts/misc/retag-branch b/debian/scripts/misc/retag-branch +new file mode 100755 +index 0000000..983cf97 +--- /dev/null ++++ b/debian/scripts/misc/retag-branch +@@ -0,0 +1,32 @@ ++#!/usr/bin/perl -w ++# Modified from the original script to only list commit we care about.. ++ ++open(TAGS, "git tag -l |") or die "Could not get list of tags"; ++@tags = ; ++close(TAGS); ++ ++open(LOGS, "git log --pretty=short |") or die "ERROR: Calling git-log"; ++my $commit = ""; ++ ++while () { ++ if (m|^commit (.*)$|) { ++ $commit = $1; ++ next; ++ } ++ ++ m|\s*UBUNTU: (NBK-Ubuntu-2\.6\.\S*)| or next; ++ $tag = $1; ++ ++ ($origtag) = grep(/^$tag.orig$/, @tags); ++ ++ if (!defined($origtag)) { ++ print "I: Adding original tag for $tag\n"; ++ system("git tag -m $tag $tag.orig $tag"); ++ } ++ ++ print "I: Tagging $tag => $commit\n"; ++ ++ system("git tag -f -m $tag $tag $commit"); ++} ++ ++close(LOGS); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0016-kgdb-fix-several-kgdb-regressions.patch +++ linux-2.6.24/patches/0016-kgdb-fix-several-kgdb-regressions.patch @@ -0,0 +1,120 @@ +From db838f1738dc336d8fd54cf0f6e2c6ad59715f06 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 7 Mar 2008 16:34:16 -0600 +Subject: [PATCH 016/170] kgdb: fix several kgdb regressions + +kgdb core fixes: +- Check to see that mm->mmap_cache is not null before calling + flush_cache_range(), else on arch=ARM it will cause a fatal + fault. + +- Breakpoints should only be restored if they are in the BP_ACTIVE + state. + +- Fix a typo in comments to "kgdb_register_io_module" + +x86 kgdb fixes: +- Fix the x86 arch handler such that on a kill or detach that the + appropriate cleanup on the single stepping flags gets run. + +- Add in the DIE_NMIWATCHDOG call for x86_64 + +- Touch the nmi watchdog before returning the system to normal + operation after performing any kind of kgdb operation, else + the possibility exists to trigger the watchdog. + +Signed-off-by: Jason Wessel +Signed-off-by: Ingo Molnar +--- + arch/x86/kernel/kgdb.c | 4 ++++ + arch/x86/kernel/traps_64.c | 7 ++++++- + kernel/kgdb.c | 14 ++++++++------ + 3 files changed, 18 insertions(+), 7 deletions(-) + +diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c +index 7d651ad..8c7e555 100644 +--- a/arch/x86/kernel/kgdb.c ++++ b/arch/x86/kernel/kgdb.c +@@ -370,6 +370,8 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, + ptr = &remcomInBuffer[1]; + if (kgdb_hex2long(&ptr, &addr)) + linux_regs->ip = addr; ++ case 'D': ++ case 'k': + newPC = linux_regs->ip; + + /* clear the trace bit */ +@@ -480,6 +482,8 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) + if (kgdb_handle_exception(args->trapnr, args->signr, args->err, regs)) + return NOTIFY_DONE; + ++ /* Must touch watchdog before return to normal operation */ ++ touch_nmi_watchdog(); + return NOTIFY_STOP; + } + +diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c +index 11857be..e2a2553 100644 +--- a/arch/x86/kernel/traps_64.c ++++ b/arch/x86/kernel/traps_64.c +@@ -549,8 +549,13 @@ void die(const char * str, struct pt_regs * regs, long err) + + void __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic) + { +- unsigned long flags = oops_begin(); ++ unsigned long flags; ++ ++ if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == ++ NOTIFY_STOP) ++ return; + ++ flags = oops_begin(); + /* + * We are in trouble anyway, lets at least try + * to get a message out. +diff --git a/kernel/kgdb.c b/kernel/kgdb.c +index 31425e0..85b7e5b 100644 +--- a/kernel/kgdb.c ++++ b/kernel/kgdb.c +@@ -600,7 +600,7 @@ static void kgdb_flush_swbreak_addr(unsigned long addr) + if (!CACHE_FLUSH_IS_SAFE) + return; + +- if (current->mm) { ++ if (current->mm && current->mm->mmap_cache) { + flush_cache_range(current->mm->mmap_cache, + addr, addr + BREAK_INSTR_SIZE); + } else { +@@ -729,14 +729,16 @@ int remove_all_break(void) + + /* Clear memory breakpoints. */ + for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { +- if (kgdb_break[i].state != BP_SET) +- continue; ++ if (kgdb_break[i].state != BP_ACTIVE) ++ goto setundefined; + addr = kgdb_break[i].bpt_addr; + error = kgdb_arch_remove_breakpoint(addr, + kgdb_break[i].saved_instr); + if (error) +- return error; +- kgdb_break[i].state = BP_REMOVED; ++ printk(KERN_ERR "KGDB: breakpoint remove failed: %lx\n", ++ addr); ++setundefined: ++ kgdb_break[i].state = BP_UNDEFINED; + } + + /* Clear hardware breakpoints. */ +@@ -1605,7 +1607,7 @@ static void kgdb_initial_breakpoint(void) + } + + /** +- * kkgdb_register_io_module - register KGDB IO module ++ * kgdb_register_io_module - register KGDB IO module + * @new_kgdb_io_ops: the io ops vector + * + * Register it with the KGDB core. +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0061-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook4.patch +++ linux-2.6.24/patches/0061-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook4.patch @@ -0,0 +1,30 @@ +From 6ed7f0a80c128784daceafe6906a339296fd6e02 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 24 Sep 2008 11:02:37 -0400 +Subject: [PATCH 061/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook4 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index b1dfd8f..161b763 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-19.41netbook4) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * Added PCI ID for Natick. Enable 40 wire cable detect to ata_pix.c ++ ++ -- Michael Frey Wed, 24 Sep 2008 10:59:25 -0400 ++ + linux (2.6.24-19.41netbook3) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0117-Turn-debian-binary-custom.d-lpia-patchset-0012-pouls.patch +++ linux-2.6.24/patches/0117-Turn-debian-binary-custom.d-lpia-patchset-0012-pouls.patch @@ -0,0 +1,76 @@ +From 9e51bd1e7a4568915adcc38a186310ea5e998305 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:31 +0100 +Subject: [PATCH 117/170] Turn debian/binary-custom.d/lpia/patchset/0012-poulsbo_hda_class_id.patch into a commit. + +Signed-off-by: Andy Whitcroft + +commit 4883c50b37f2e791e29f545766e53ac456576926 +Author: Amit Kucheria +Date: Fri Jan 11 13:59:04 2008 +0200 + + UBUNTU: Poulsbo: Mass update of patches to be identical to those on moblin + + Sigh, we need better communication... + + Signed-off-by: Amit Kucheria +--- + .../lpia/patchset/0012-poulsbo_hda_class_id.patch | 23 -------------------- + drivers/pci/quirks.c | 11 +++++++++ + 2 files changed, 11 insertions(+), 23 deletions(-) + delete mode 100644 debian/binary-custom.d/lpia/patchset/0012-poulsbo_hda_class_id.patch + +diff --git a/debian/binary-custom.d/lpia/patchset/0012-poulsbo_hda_class_id.patch b/debian/binary-custom.d/lpia/patchset/0012-poulsbo_hda_class_id.patch +deleted file mode 100644 +index b8f6f5f..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0012-poulsbo_hda_class_id.patch ++++ /dev/null +@@ -1,23 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +-index 01d8f8a..6792eca 100644 +---- a/drivers/pci/quirks.c +-+++ b/drivers/pci/quirks.c +-@@ -1490,6 +1490,17 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev) +- } +- DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810); +- +-+ +-+static void __devinit fixup_poulsbo_hda(struct pci_dev* dev) +-+{ +-+ /* poulsbo A2 HD audio controller has the wrong class type of 604h */ +-+ if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) { +-+ printk(KERN_INFO "Poulsbo A2 HDA detected, setting PCI class.\n"); +-+ dev->class = PCI_CLASS_MULTIMEDIA_AUDIO; +-+ } +-+} +-+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_POULSBO_HDA, fixup_poulsbo_hda); +-+ +- static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) +- { +- while (f < end) { +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 1ed35f7..6f97c2f 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -1486,6 +1486,17 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev) + } + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810); + ++ ++static void __devinit fixup_poulsbo_hda(struct pci_dev* dev) ++{ ++ /* poulsbo A2 HD audio controller has the wrong class type of 604h */ ++ if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) { ++ printk(KERN_INFO "Poulsbo A2 HDA detected, setting PCI class.\n"); ++ dev->class = PCI_CLASS_MULTIMEDIA_AUDIO; ++ } ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_POULSBO_HDA, fixup_poulsbo_hda); ++ + static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) + { + while (f < end) { +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0159-UBUNTU-NBK-Ubuntu-2.6.24-24.57netbook01.patch +++ linux-2.6.24/patches/0159-UBUNTU-NBK-Ubuntu-2.6.24-24.57netbook01.patch @@ -0,0 +1,32 @@ +From b0368da413b82f3c5eda9394ec5f9eef8a804aec Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Tue, 28 Jul 2009 21:07:17 +0100 +Subject: [PATCH 159/170] UBUNTU: NBK-Ubuntu-2.6.24-24.57netbook01 + +Signed-off-by: Andy Whitcroft +--- + debian/changelog | 10 ++++++---- + 1 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index f4af58c..86a05e5 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,8 +1,10 @@ +-linux (2.6.24-24.57netbook01) UNRELEASED; urgency=low ++linux (2.6.24-24.57netbook01) netboot-common; urgency=low + +- CHANGELOG: Do not edit directly. Autogenerated at release. +- CHANGELOG: Use the printchanges target to see the curent changes. +- CHANGELOG: Use the insertchanges target to create the final log. ++ [ Andy Whitcroft ] ++ ++ * pull in updated rebase-branch script ++ * printchanges -- rebase tree does not have stable tags use changelog ++ * rebase onto Ubuntu-2.6.24-24.57 + + [ Ubuntu Kernel Changes ] + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0064-ACPI-Remove-extraneous-inb-call-from-EC-read.patch +++ linux-2.6.24/patches/0064-ACPI-Remove-extraneous-inb-call-from-EC-read.patch @@ -0,0 +1,31 @@ +From 2d7f6a35d498a00406a7fd5ad2e0c373bbe51566 Mon Sep 17 00:00:00 2001 +From: Tony Espy +Date: Thu, 16 Oct 2008 12:42:04 -0400 +Subject: [PATCH 064/170] ACPI: Remove extraneous inb() call from EC read. + +acpi_ec_read_data() is performing two inb() calls - +instead it should be doing just a single inb() call +and returning it's value. + +Signed-off-by: Colin Ian King +Signed-off-by: Tony Espy +--- + drivers/acpi/ec.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c +index 7222a18..928c4c8 100644 +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -147,7 +147,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec) + { + u8 x = inb(ec->data_addr); + pr_debug(PREFIX "---> data = 0x%2.2x\n", x); +- return inb(ec->data_addr); ++ return x; + } + + static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0150-Now-that-the-rebase-is-finished-remove-the-whitespac.patch +++ linux-2.6.24/patches/0150-Now-that-the-rebase-is-finished-remove-the-whitespac.patch @@ -0,0 +1,26 @@ +From 0ca726e0d5f4fc11d8c4299d839acc2bc7aa1359 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Thu, 7 May 2009 14:21:47 -0500 +Subject: [PATCH 150/170] Now that the rebase is finished, remove the whitespace correction from the rebase script. We shouldn't need it any more. + +Signed-off-by: Steve Conklin +--- + debian/scripts/misc/rebase-branch | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/debian/scripts/misc/rebase-branch b/debian/scripts/misc/rebase-branch +index e31c3fc..7be17db 100755 +--- a/debian/scripts/misc/rebase-branch ++++ b/debian/scripts/misc/rebase-branch +@@ -163,7 +163,7 @@ $git commit -a -s -m "UBUNTU: AUTO: Start new changelog and revert to known abi" + $git status + + # Apply pending patches +-$git am --whitespace=fix -C0 patches/* ++$git am -C0 patches/* + if [ -d "$rebasing/" ]; then + echo "\tFailed to apply patches" + echo "\tPlease fix the patches on branch $remoteBranch and then sync to the master branch" +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0091-RT73-driver-has-shown-to-have-poor-performance.-This.patch +++ linux-2.6.24/patches/0091-RT73-driver-has-shown-to-have-poor-performance.-This.patch @@ -0,0 +1,2139 @@ +From c03d20af8b593110d408ceb51a9762f66778f679 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 17 Dec 2008 15:17:34 -0500 +Subject: [PATCH 091/170] RT73 driver has shown to have poor performance. This patch upgrades the driver to version 2.0.11 and also includes antenna switching fixes. Fix for LP: #294603 + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/294603 +The Upstream commits included for this patch are as follows: + + ebcf26dae9f10e247ea41ef66f89b336ba456097 + - rt2x00: Move quality statistics into seperate structure + + 362f3b6bfbb18b4b8bd8a8ef391fb95efb43c632 + - rt2x00: Use enum defines + + addc81bd428f9eb29ed2ab64ad4039c6aed55aea + - rt2x00: Correctly translate mac80211 antenna setup to rt2x00 + + 39e75857d08fe35ffad4dd9004580acf0d725b75 + - rt2x00: SW diversity should default to antenna B + + 8de8c5162b157884aa4855564cbfd9ec9119c819 + - rt2x00: Remove rt2x00_clear_link + + 69f81a2cac860cf183eb9ef7787525c3552d4612 + - rt2x00: Implement SW diversity + + ddc827f93a2f2a7dcfda5b691d046af4dfe76427 + - rt2x00: Cleanup if-statements + + 16b1951f53c6097d7355e76ed9ca64b056f88f31 + - rt2x00: Fix antenna selection + + 2d68de3efa62655d551092f5c787505735d561ad + - rtx200: Release rt2x00 2.0.11 + + e25c4bb913e54d729631ba7eb50daf1d9aacbef6 + - rt2x00: Disable RX when switching antenna + + e4cd2ff89f91b0556a2e2d928219b2908cafd67f + - rt2x00: Split rt61/rt73 antenna selection into RX and TX antenna + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/net/wireless/rt2x00/rt2400pci.c | 80 ++++--- + drivers/net/wireless/rt2x00/rt2500pci.c | 88 ++++---- + drivers/net/wireless/rt2x00/rt2500usb.c | 84 +++++--- + drivers/net/wireless/rt2x00/rt2500usb.h | 13 +- + drivers/net/wireless/rt2x00/rt2x00.h | 165 +++++++++++---- + drivers/net/wireless/rt2x00/rt2x00config.c | 95 ++++++++- + drivers/net/wireless/rt2x00/rt2x00dev.c | 199 +++++++++++++++--- + drivers/net/wireless/rt2x00/rt2x00lib.h | 2 + + drivers/net/wireless/rt2x00/rt61pci.c | 327 +++++++++++++++++----------- + drivers/net/wireless/rt2x00/rt61pci.h | 2 +- + drivers/net/wireless/rt2x00/rt73usb.c | 140 ++++++++---- + drivers/net/wireless/rt2x00/rt73usb.h | 2 +- + 12 files changed, 838 insertions(+), 359 deletions(-) + +diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c +index 31c1dd2..fc16212 100644 +--- a/drivers/net/wireless/rt2x00/rt2400pci.c ++++ b/drivers/net/wireless/rt2x00/rt2400pci.c +@@ -397,7 +397,7 @@ static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower) + } + + static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, +- int antenna_tx, int antenna_rx) ++ struct antenna_setup *ant) + { + u8 r1; + u8 r4; +@@ -408,14 +408,20 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, + /* + * Configure the TX antenna. + */ +- switch (antenna_tx) { +- case ANTENNA_SW_DIVERSITY: ++ switch (ant->tx) { + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0); + break; ++ case ANTENNA_SW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ + case ANTENNA_B: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2); + break; +@@ -424,14 +430,20 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, + /* + * Configure the RX antenna. + */ +- switch (antenna_rx) { +- case ANTENNA_SW_DIVERSITY: ++ switch (ant->rx) { + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0); + break; ++ case ANTENNA_SW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + break; +@@ -485,9 +497,7 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, + rt2400pci_config_txpower(rt2x00dev, + libconf->conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) +- rt2400pci_config_antenna(rt2x00dev, +- libconf->conf->antenna_sel_tx, +- libconf->conf->antenna_sel_rx); ++ rt2400pci_config_antenna(rt2x00dev, &libconf->ant); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt2400pci_config_duration(rt2x00dev, libconf); + } +@@ -514,18 +524,10 @@ static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev) + + rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70); + rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30); +- +- if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) { +- rt2x00_set_field32(®, LEDCSR_LINK, 1); +- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); +- } else if (rt2x00dev->led_mode == LED_MODE_ASUS) { +- rt2x00_set_field32(®, LEDCSR_LINK, 0); +- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); +- } else { +- rt2x00_set_field32(®, LEDCSR_LINK, 1); +- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); +- } +- ++ rt2x00_set_field32(®, LEDCSR_LINK, ++ (rt2x00dev->led_mode != LED_MODE_ASUS)); ++ rt2x00_set_field32(®, LEDCSR_ACTIVITY, ++ (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY)); + rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); + } + +@@ -542,7 +544,8 @@ static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev) + /* + * Link tuning + */ +-static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev) ++static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev, ++ struct link_qual *qual) + { + u32 reg; + u8 bbp; +@@ -551,13 +554,13 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev) + * Update FCS error count from register. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®); +- rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); ++ qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt2400pci_bbp_read(rt2x00dev, 39, &bbp); +- rt2x00dev->link.false_cca = bbp; ++ qual->false_cca = bbp; + } + + static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev) +@@ -582,10 +585,10 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) + */ + rt2400pci_bbp_read(rt2x00dev, 13, ®); + +- if (rt2x00dev->link.false_cca > 512 && reg < 0x20) { ++ if (rt2x00dev->link.qual.false_cca > 512 && reg < 0x20) { + rt2400pci_bbp_write(rt2x00dev, 13, ++reg); + rt2x00dev->link.vgc_level = reg; +- } else if (rt2x00dev->link.false_cca < 100 && reg > 0x08) { ++ } else if (rt2x00dev->link.qual.false_cca < 100 && reg > 0x08) { + rt2400pci_bbp_write(rt2x00dev, 13, --reg); + rt2x00dev->link.vgc_level = reg; + } +@@ -1099,12 +1102,12 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + } + + rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); +- if (queue == IEEE80211_TX_QUEUE_DATA0) +- rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); +- else if (queue == IEEE80211_TX_QUEUE_DATA1) +- rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); +- else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) +- rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); ++ rt2x00_set_field32(®, TXCSR0_KICK_PRIO, ++ (queue == IEEE80211_TX_QUEUE_DATA0)); ++ rt2x00_set_field32(®, TXCSR0_KICK_TX, ++ (queue == IEEE80211_TX_QUEUE_DATA1)); ++ rt2x00_set_field32(®, TXCSR0_KICK_ATIM, ++ (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)); + rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); + } + +@@ -1315,12 +1318,23 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) + /* + * Identify default antenna configuration. + */ +- rt2x00dev->hw->conf.antenna_sel_tx = ++ rt2x00dev->default_ant.tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); +- rt2x00dev->hw->conf.antenna_sel_rx = ++ rt2x00dev->default_ant.rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* ++ * When the eeprom indicates SW_DIVERSITY use HW_DIVERSITY instead. ++ * I am not 100% sure about this, but the legacy drivers do not ++ * indicate antenna swapping in software is required when ++ * diversity is enabled. ++ */ ++ if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) ++ rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY; ++ if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) ++ rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY; ++ ++ /* + * Store led mode, for correct led behaviour. + */ + rt2x00dev->led_mode = +diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c +index 702321c..869b1a7 100644 +--- a/drivers/net/wireless/rt2x00/rt2500pci.c ++++ b/drivers/net/wireless/rt2x00/rt2500pci.c +@@ -424,7 +424,7 @@ static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, + } + + static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, +- const int antenna_tx, const int antenna_rx) ++ struct antenna_setup *ant) + { + u32 reg; + u8 r14; +@@ -437,18 +437,20 @@ static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, + /* + * Configure the TX antenna. + */ +- switch (antenna_tx) { +- case ANTENNA_SW_DIVERSITY: +- case ANTENNA_HW_DIVERSITY: +- rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); +- rt2x00_set_field32(®, BBPCSR1_CCK, 2); +- rt2x00_set_field32(®, BBPCSR1_OFDM, 2); +- break; ++ switch (ant->tx) { + case ANTENNA_A: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0); + rt2x00_set_field32(®, BBPCSR1_CCK, 0); + rt2x00_set_field32(®, BBPCSR1_OFDM, 0); + break; ++ case ANTENNA_HW_DIVERSITY: ++ case ANTENNA_SW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ + case ANTENNA_B: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); + rt2x00_set_field32(®, BBPCSR1_CCK, 2); +@@ -459,14 +461,18 @@ static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, + /* + * Configure the RX antenna. + */ +- switch (antenna_rx) { +- case ANTENNA_SW_DIVERSITY: +- case ANTENNA_HW_DIVERSITY: +- rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); +- break; ++ switch (ant->rx) { + case ANTENNA_A: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); + break; ++ case ANTENNA_HW_DIVERSITY: ++ case ANTENNA_SW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ + case ANTENNA_B: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); + break; +@@ -541,9 +547,7 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, + rt2500pci_config_txpower(rt2x00dev, + libconf->conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) +- rt2500pci_config_antenna(rt2x00dev, +- libconf->conf->antenna_sel_tx, +- libconf->conf->antenna_sel_rx); ++ rt2500pci_config_antenna(rt2x00dev, &libconf->ant); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt2500pci_config_duration(rt2x00dev, libconf); + } +@@ -559,18 +563,10 @@ static void rt2500pci_enable_led(struct rt2x00_dev *rt2x00dev) + + rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70); + rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30); +- +- if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) { +- rt2x00_set_field32(®, LEDCSR_LINK, 1); +- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); +- } else if (rt2x00dev->led_mode == LED_MODE_ASUS) { +- rt2x00_set_field32(®, LEDCSR_LINK, 0); +- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); +- } else { +- rt2x00_set_field32(®, LEDCSR_LINK, 1); +- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); +- } +- ++ rt2x00_set_field32(®, LEDCSR_LINK, ++ (rt2x00dev->led_mode != LED_MODE_ASUS)); ++ rt2x00_set_field32(®, LEDCSR_ACTIVITY, ++ (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY)); + rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); + } + +@@ -587,7 +583,8 @@ static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev) + /* + * Link tuning + */ +-static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev) ++static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev, ++ struct link_qual *qual) + { + u32 reg; + +@@ -595,13 +592,13 @@ static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev) + * Update FCS error count from register. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®); +- rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); ++ qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt2x00pci_register_read(rt2x00dev, CNT3, ®); +- rt2x00dev->link.false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA); ++ qual->false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA); + } + + static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev) +@@ -679,10 +676,10 @@ dynamic_cca_tune: + * R17 is inside the dynamic tuning range, + * start tuning the link based on the false cca counter. + */ +- if (rt2x00dev->link.false_cca > 512 && r17 < 0x40) { ++ if (rt2x00dev->link.qual.false_cca > 512 && r17 < 0x40) { + rt2500pci_bbp_write(rt2x00dev, 17, ++r17); + rt2x00dev->link.vgc_level = r17; +- } else if (rt2x00dev->link.false_cca < 100 && r17 > 0x32) { ++ } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > 0x32) { + rt2500pci_bbp_write(rt2x00dev, 17, --r17); + rt2x00dev->link.vgc_level = r17; + } +@@ -1239,12 +1236,12 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + } + + rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); +- if (queue == IEEE80211_TX_QUEUE_DATA0) +- rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); +- else if (queue == IEEE80211_TX_QUEUE_DATA1) +- rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); +- else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) +- rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); ++ rt2x00_set_field32(®, TXCSR0_KICK_PRIO, ++ (queue == IEEE80211_TX_QUEUE_DATA0)); ++ rt2x00_set_field32(®, TXCSR0_KICK_TX, ++ (queue == IEEE80211_TX_QUEUE_DATA1)); ++ rt2x00_set_field32(®, TXCSR0_KICK_ATIM, ++ (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)); + rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); + } + +@@ -1420,9 +1417,12 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); +- rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0); +- rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0); +- rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0); ++ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, ++ ANTENNA_SW_DIVERSITY); ++ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, ++ ANTENNA_SW_DIVERSITY); ++ rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, ++ LED_MODE_DEFAULT); + rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522); +@@ -1481,9 +1481,9 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) + /* + * Identify default antenna configuration. + */ +- rt2x00dev->hw->conf.antenna_sel_tx = ++ rt2x00dev->default_ant.tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); +- rt2x00dev->hw->conf.antenna_sel_rx = ++ rt2x00dev->default_ant.rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* +diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c +index 18b1f91..4f8e388 100644 +--- a/drivers/net/wireless/rt2x00/rt2500usb.c ++++ b/drivers/net/wireless/rt2x00/rt2500usb.c +@@ -385,7 +385,7 @@ static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, + } + + static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, +- const int antenna_tx, const int antenna_rx) ++ struct antenna_setup *ant) + { + u8 r2; + u8 r14; +@@ -400,8 +400,7 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, + /* + * Configure the TX antenna. + */ +- switch (antenna_tx) { +- case ANTENNA_SW_DIVERSITY: ++ switch (ant->tx) { + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 1); + rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 1); +@@ -412,6 +411,13 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, + rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 0); + rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 0); + break; ++ case ANTENNA_SW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ + case ANTENNA_B: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); + rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 2); +@@ -422,14 +428,20 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, + /* + * Configure the RX antenna. + */ +- switch (antenna_rx) { +- case ANTENNA_SW_DIVERSITY: ++ switch (ant->rx) { + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); + break; ++ case ANTENNA_SW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ + case ANTENNA_B: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); + break; +@@ -487,9 +499,7 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, + rt2500usb_config_txpower(rt2x00dev, + libconf->conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) +- rt2500usb_config_antenna(rt2x00dev, +- libconf->conf->antenna_sel_tx, +- libconf->conf->antenna_sel_rx); ++ rt2500usb_config_antenna(rt2x00dev, &libconf->ant); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt2500usb_config_duration(rt2x00dev, libconf); + } +@@ -507,18 +517,10 @@ static void rt2500usb_enable_led(struct rt2x00_dev *rt2x00dev) + rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg); + + rt2500usb_register_read(rt2x00dev, MAC_CSR20, ®); +- +- if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) { +- rt2x00_set_field16(®, MAC_CSR20_LINK, 1); +- rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 0); +- } else if (rt2x00dev->led_mode == LED_MODE_ASUS) { +- rt2x00_set_field16(®, MAC_CSR20_LINK, 0); +- rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 1); +- } else { +- rt2x00_set_field16(®, MAC_CSR20_LINK, 1); +- rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 1); +- } +- ++ rt2x00_set_field16(®, MAC_CSR20_LINK, ++ (rt2x00dev->led_mode != LED_MODE_ASUS)); ++ rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, ++ (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY)); + rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg); + } + +@@ -535,7 +537,8 @@ static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev) + /* + * Link tuning + */ +-static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev) ++static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev, ++ struct link_qual *qual) + { + u16 reg; + +@@ -543,14 +546,13 @@ static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev) + * Update FCS error count from register. + */ + rt2500usb_register_read(rt2x00dev, STA_CSR0, ®); +- rt2x00dev->link.rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR); ++ qual->rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt2500usb_register_read(rt2x00dev, STA_CSR3, ®); +- rt2x00dev->link.false_cca = +- rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR); ++ qual->false_cca = rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR); + } + + static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev) +@@ -673,10 +675,10 @@ static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev) + if (r17 > up_bound) { + rt2500usb_bbp_write(rt2x00dev, 17, up_bound); + rt2x00dev->link.vgc_level = up_bound; +- } else if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) { ++ } else if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) { + rt2500usb_bbp_write(rt2x00dev, 17, ++r17); + rt2x00dev->link.vgc_level = r17; +- } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { ++ } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) { + rt2500usb_bbp_write(rt2x00dev, 17, --r17); + rt2x00dev->link.vgc_level = r17; + } +@@ -755,9 +757,11 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) + + if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) { + rt2500usb_register_read(rt2x00dev, PHY_CSR2, ®); +- reg &= ~0x0002; ++ rt2x00_set_field16(®, PHY_CSR2_LNA, 0); + } else { +- reg = 0x3002; ++ reg = 0; ++ rt2x00_set_field16(®, PHY_CSR2_LNA, 1); ++ rt2x00_set_field16(®, PHY_CSR2_LNA_MODE, 3); + } + rt2500usb_register_write(rt2x00dev, PHY_CSR2, reg); + +@@ -1163,9 +1167,12 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); +- rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0); +- rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0); +- rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0); ++ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, ++ ANTENNA_SW_DIVERSITY); ++ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, ++ ANTENNA_SW_DIVERSITY); ++ rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, ++ LED_MODE_DEFAULT); + rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522); +@@ -1275,12 +1282,23 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) + /* + * Identify default antenna configuration. + */ +- rt2x00dev->hw->conf.antenna_sel_tx = ++ rt2x00dev->default_ant.tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); +- rt2x00dev->hw->conf.antenna_sel_rx = ++ rt2x00dev->default_ant.rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* ++ * When the eeprom indicates SW_DIVERSITY use HW_DIVERSITY instead. ++ * I am not 100% sure about this, but the legacy drivers do not ++ * indicate antenna swapping in software is required when ++ * diversity is enabled. ++ */ ++ if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) ++ rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY; ++ if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) ++ rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY; ++ ++ /* + * Store led mode, for correct led behaviour. + */ + rt2x00dev->led_mode = +diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h +index b18d56e..2741840 100644 +--- a/drivers/net/wireless/rt2x00/rt2500usb.h ++++ b/drivers/net/wireless/rt2x00/rt2500usb.h +@@ -430,10 +430,21 @@ + + /* + * MAC configuration registers. ++ */ ++ ++/* + * PHY_CSR2: TX MAC configuration. +- * PHY_CSR3: RX MAC configuration. ++ * NOTE: Both register fields are complete dummy, ++ * documentation and legacy drivers are unclear un ++ * what this register means or what fields exists. + */ + #define PHY_CSR2 0x04c4 ++#define PHY_CSR2_LNA FIELD16(0x0002) ++#define PHY_CSR2_LNA_MODE FIELD16(0x3000) ++ ++/* ++ * PHY_CSR3: RX MAC configuration. ++ */ + #define PHY_CSR3 0x04c6 + + /* +diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h +index c8f16f1..871d631 100644 +--- a/drivers/net/wireless/rt2x00/rt2x00.h ++++ b/drivers/net/wireless/rt2x00/rt2x00.h +@@ -42,7 +42,7 @@ + * Module information. + * DRV_NAME should be set within the individual module source files. + */ +-#define DRV_VERSION "2.0.10" ++#define DRV_VERSION "2.0.11" + #define DRV_PROJECT "http://rt2x00.serialmonkey.com" + + /* +@@ -133,20 +133,20 @@ + */ + static inline int is_rts_frame(u16 fc) + { +- return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && +- ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS)); ++ return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && ++ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS)); + } + + static inline int is_cts_frame(u16 fc) + { +- return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && +- ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS)); ++ return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && ++ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS)); + } + + static inline int is_probe_resp(u16 fc) + { +- return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && +- ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)); ++ return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && ++ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)); + } + + /* +@@ -180,18 +180,17 @@ struct rf_channel { + }; + + /* +- * To optimize the quality of the link we need to store +- * the quality of received frames and periodically +- * optimize the link. ++ * Antenna setup values. + */ +-struct link { +- /* +- * Link tuner counter +- * The number of times the link has been tuned +- * since the radio has been switched on. +- */ +- u32 count; ++struct antenna_setup { ++ enum antenna rx; ++ enum antenna tx; ++}; + ++/* ++ * Quality statistics about the currently active link. ++ */ ++struct link_qual { + /* + * Statistics required for Link tuning. + * For the average RSSI value we use the "Walking average" approach. +@@ -211,7 +210,6 @@ struct link { + * the new values correctly allowing a effective link tuning. + */ + int avg_rssi; +- int vgc_level; + int false_cca; + + /* +@@ -240,6 +238,72 @@ struct link { + #define WEIGHT_RSSI 20 + #define WEIGHT_RX 40 + #define WEIGHT_TX 40 ++}; ++ ++/* ++ * Antenna settings about the currently active link. ++ */ ++struct link_ant { ++ /* ++ * Antenna flags ++ */ ++ unsigned int flags; ++#define ANTENNA_RX_DIVERSITY 0x00000001 ++#define ANTENNA_TX_DIVERSITY 0x00000002 ++#define ANTENNA_MODE_SAMPLE 0x00000004 ++ ++ /* ++ * Currently active TX/RX antenna setup. ++ * When software diversity is used, this will indicate ++ * which antenna is actually used at this time. ++ */ ++ struct antenna_setup active; ++ ++ /* ++ * RSSI information for the different antenna's. ++ * These statistics are used to determine when ++ * to switch antenna when using software diversity. ++ * ++ * rssi[0] -> Antenna A RSSI ++ * rssi[1] -> Antenna B RSSI ++ */ ++ int rssi_history[2]; ++ ++ /* ++ * Current RSSI average of the currently active antenna. ++ * Similar to the avg_rssi in the link_qual structure ++ * this value is updated by using the walking average. ++ */ ++ int rssi_ant; ++}; ++ ++/* ++ * To optimize the quality of the link we need to store ++ * the quality of received frames and periodically ++ * optimize the link. ++ */ ++struct link { ++ /* ++ * Link tuner counter ++ * The number of times the link has been tuned ++ * since the radio has been switched on. ++ */ ++ u32 count; ++ ++ /* ++ * Quality measurement values. ++ */ ++ struct link_qual qual; ++ ++ /* ++ * TX/RX antenna setup. ++ */ ++ struct link_ant ant; ++ ++ /* ++ * Active VGC level ++ */ ++ int vgc_level; + + /* + * Work structure for scheduling periodic link tuning. +@@ -248,36 +312,47 @@ struct link { + }; + + /* +- * Clear all counters inside the link structure. +- * This can be easiest achieved by memsetting everything +- * except for the work structure at the end. ++ * Small helper macro to work with moving/walking averages. + */ +-static inline void rt2x00_clear_link(struct link *link) +-{ +- memset(link, 0x00, sizeof(*link) - sizeof(link->work)); +- link->rx_percentage = 50; +- link->tx_percentage = 50; +-} ++#define MOVING_AVERAGE(__avg, __val, __samples) \ ++ ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) ) + + /* +- * Update the rssi using the walking average approach. ++ * When we lack RSSI information return something less then -80 to ++ * tell the driver to tune the device to maximum sensitivity. + */ +-static inline void rt2x00_update_link_rssi(struct link *link, int rssi) +-{ +- if (!link->avg_rssi) +- link->avg_rssi = rssi; +- else +- link->avg_rssi = ((link->avg_rssi * 7) + rssi) / 8; +-} ++#define DEFAULT_RSSI ( -128 ) + + /* +- * When the avg_rssi is unset or no frames have been received), +- * we need to return the default value which needs to be less +- * than -80 so the device will select the maximum sensitivity. ++ * Link quality access functions. + */ + static inline int rt2x00_get_link_rssi(struct link *link) + { +- return (link->avg_rssi && link->rx_success) ? link->avg_rssi : -128; ++ if (link->qual.avg_rssi && link->qual.rx_success) ++ return link->qual.avg_rssi; ++ return DEFAULT_RSSI; ++} ++ ++static inline int rt2x00_get_link_ant_rssi(struct link *link) ++{ ++ if (link->ant.rssi_ant && link->qual.rx_success) ++ return link->ant.rssi_ant; ++ return DEFAULT_RSSI; ++} ++ ++static inline int rt2x00_get_link_ant_rssi_history(struct link *link, ++ enum antenna ant) ++{ ++ if (link->ant.rssi_history[ant - ANTENNA_A]) ++ return link->ant.rssi_history[ant - ANTENNA_A]; ++ return DEFAULT_RSSI; ++} ++ ++static inline int rt2x00_update_ant_rssi(struct link *link, int rssi) ++{ ++ int old_rssi = link->ant.rssi_history[link->ant.active.rx - ANTENNA_A]; ++ link->ant.rssi_history[link->ant.active.rx - ANTENNA_A] = rssi; ++ return old_rssi; + } + + /* +@@ -362,6 +437,8 @@ struct rt2x00lib_conf { + struct ieee80211_conf *conf; + struct rf_channel rf; + ++ struct antenna_setup ant; ++ + int phymode; + + int basic_rates; +@@ -402,7 +479,8 @@ struct rt2x00lib_ops { + int (*set_device_state) (struct rt2x00_dev *rt2x00dev, + enum dev_state state); + int (*rfkill_poll) (struct rt2x00_dev *rt2x00dev); +- void (*link_stats) (struct rt2x00_dev *rt2x00dev); ++ void (*link_stats) (struct rt2x00_dev *rt2x00dev, ++ struct link_qual *qual); + void (*reset_tuner) (struct rt2x00_dev *rt2x00dev); + void (*link_tuner) (struct rt2x00_dev *rt2x00dev); + +@@ -566,6 +644,13 @@ struct rt2x00_dev { + struct hw_mode_spec spec; + + /* ++ * This is the default TX/RX antenna setup as indicated ++ * by the device's EEPROM. When mac80211 sets its ++ * antenna value to 0 we should be using these values. ++ */ ++ struct antenna_setup default_ant; ++ ++ /* + * Register pointers + * csr_addr: Base register address. (PCI) + * csr_cache: CSR cache for usb_control_msg. (USB) +diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c +index 12914cf..9f0733b 100644 +--- a/drivers/net/wireless/rt2x00/rt2x00config.c ++++ b/drivers/net/wireless/rt2x00/rt2x00config.c +@@ -94,12 +94,44 @@ void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type) + rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync); + } + ++void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, ++ enum antenna rx, enum antenna tx) ++{ ++ struct rt2x00lib_conf libconf; ++ ++ libconf.ant.rx = rx; ++ libconf.ant.tx = tx; ++ ++ /* ++ * Antenna setup changes require the RX to be disabled, ++ * else the changes will be ignored by the device. ++ */ ++ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); ++ ++ /* ++ * Write new antenna setup to device and reset the link tuner. ++ * The latter is required since we need to recalibrate the ++ * noise-sensitivity ratio for the new setup. ++ */ ++ rt2x00dev->ops->lib->config(rt2x00dev, CONFIG_UPDATE_ANTENNA, &libconf); ++ rt2x00lib_reset_link_tuner(rt2x00dev); ++ ++ rt2x00dev->link.ant.active.rx = libconf.ant.rx; ++ rt2x00dev->link.ant.active.tx = libconf.ant.tx; ++ ++ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); ++} ++ + void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, const int force_config) + { + struct rt2x00lib_conf libconf; + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; ++ struct antenna_setup *default_ant = &rt2x00dev->default_ant; ++ struct antenna_setup *active_ant = &rt2x00dev->link.ant.active; + int flags = 0; + int short_slot_time; + +@@ -122,7 +154,39 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, + flags |= CONFIG_UPDATE_CHANNEL; + if (rt2x00dev->tx_power != conf->power_level) + flags |= CONFIG_UPDATE_TXPOWER; +- if (rt2x00dev->rx_status.antenna == conf->antenna_sel_rx) ++ ++ /* ++ * Determining changes in the antenna setups request several checks: ++ * antenna_sel_{r,t}x = 0 ++ * -> Does active_{r,t}x match default_{r,t}x ++ * -> Is default_{r,t}x SW_DIVERSITY ++ * antenna_sel_{r,t}x = 1/2 ++ * -> Does active_{r,t}x match antenna_sel_{r,t}x ++ * The reason for not updating the antenna while SW diversity ++ * should be used is simple: Software diversity means that ++ * we should switch between the antenna's based on the ++ * quality. This means that the current antenna is good enough ++ * to work with untill the link tuner decides that an antenna ++ * switch should be performed. ++ */ ++ if (!conf->antenna_sel_rx && ++ default_ant->rx != ANTENNA_SW_DIVERSITY && ++ default_ant->rx != active_ant->rx) ++ flags |= CONFIG_UPDATE_ANTENNA; ++ else if (conf->antenna_sel_rx && ++ conf->antenna_sel_rx != active_ant->rx) ++ flags |= CONFIG_UPDATE_ANTENNA; ++ else if (active_ant->rx == ANTENNA_SW_DIVERSITY) ++ flags |= CONFIG_UPDATE_ANTENNA; ++ ++ if (!conf->antenna_sel_tx && ++ default_ant->tx != ANTENNA_SW_DIVERSITY && ++ default_ant->tx != active_ant->tx) ++ flags |= CONFIG_UPDATE_ANTENNA; ++ else if (conf->antenna_sel_tx && ++ conf->antenna_sel_tx != active_ant->tx) ++ flags |= CONFIG_UPDATE_ANTENNA; ++ else if (active_ant->tx == ANTENNA_SW_DIVERSITY) + flags |= CONFIG_UPDATE_ANTENNA; + + /* +@@ -171,6 +235,22 @@ config: + sizeof(libconf.rf)); + } + ++ if (flags & CONFIG_UPDATE_ANTENNA) { ++ if (conf->antenna_sel_rx) ++ libconf.ant.rx = conf->antenna_sel_rx; ++ else if (default_ant->rx != ANTENNA_SW_DIVERSITY) ++ libconf.ant.rx = default_ant->rx; ++ else if (active_ant->rx == ANTENNA_SW_DIVERSITY) ++ libconf.ant.rx = ANTENNA_B; ++ ++ if (conf->antenna_sel_tx) ++ libconf.ant.tx = conf->antenna_sel_tx; ++ else if (default_ant->tx != ANTENNA_SW_DIVERSITY) ++ libconf.ant.tx = default_ant->tx; ++ else if (active_ant->tx == ANTENNA_SW_DIVERSITY) ++ libconf.ant.tx = ANTENNA_B; ++ } ++ + if (flags & CONFIG_UPDATE_SLOT_TIME) { + short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + +@@ -196,10 +276,17 @@ config: + if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA)) + rt2x00lib_reset_link_tuner(rt2x00dev); + +- rt2x00dev->curr_hwmode = libconf.phymode; +- rt2x00dev->rx_status.phymode = conf->phymode; ++ if (flags & CONFIG_UPDATE_PHYMODE) { ++ rt2x00dev->curr_hwmode = libconf.phymode; ++ rt2x00dev->rx_status.phymode = conf->phymode; ++ } ++ + rt2x00dev->rx_status.freq = conf->freq; + rt2x00dev->rx_status.channel = conf->channel; + rt2x00dev->tx_power = conf->power_level; +- rt2x00dev->rx_status.antenna = conf->antenna_sel_rx; ++ ++ if (flags & CONFIG_UPDATE_ANTENNA) { ++ rt2x00dev->link.ant.active.rx = libconf.ant.rx; ++ rt2x00dev->link.ant.active.tx = libconf.ant.tx; ++ } + } +diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c +index ff399f8..360f03a 100644 +--- a/drivers/net/wireless/rt2x00/rt2x00dev.c ++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c +@@ -67,7 +67,21 @@ EXPORT_SYMBOL_GPL(rt2x00lib_get_ring); + */ + static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev) + { +- rt2x00_clear_link(&rt2x00dev->link); ++ rt2x00dev->link.count = 0; ++ rt2x00dev->link.vgc_level = 0; ++ ++ memset(&rt2x00dev->link.qual, 0, sizeof(rt2x00dev->link.qual)); ++ ++ /* ++ * The RX and TX percentage should start at 50% ++ * this will assure we will get at least get some ++ * decent value when the link tuner starts. ++ * The value will be dropped and overwritten with ++ * the correct (measured )value anyway during the ++ * first run of the link tuner. ++ */ ++ rt2x00dev->link.qual.rx_percentage = 50; ++ rt2x00dev->link.qual.tx_percentage = 50; + + /* + * Reset the link tuner. +@@ -179,26 +193,153 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) + rt2x00lib_start_link_tuner(rt2x00dev); + } + +-static void rt2x00lib_precalculate_link_signal(struct link *link) ++static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev) ++{ ++ enum antenna rx = rt2x00dev->link.ant.active.rx; ++ enum antenna tx = rt2x00dev->link.ant.active.tx; ++ int sample_a = ++ rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_A); ++ int sample_b = ++ rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_B); ++ ++ /* ++ * We are done sampling. Now we should evaluate the results. ++ */ ++ rt2x00dev->link.ant.flags &= ~ANTENNA_MODE_SAMPLE; ++ ++ /* ++ * During the last period we have sampled the RSSI ++ * from both antenna's. It now is time to determine ++ * which antenna demonstrated the best performance. ++ * When we are already on the antenna with the best ++ * performance, then there really is nothing for us ++ * left to do. ++ */ ++ if (sample_a == sample_b) ++ return; ++ ++ if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) { ++ if (sample_a > sample_b && rx == ANTENNA_B) ++ rx = ANTENNA_A; ++ else if (rx == ANTENNA_A) ++ rx = ANTENNA_B; ++ } ++ ++ if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) { ++ if (sample_a > sample_b && tx == ANTENNA_B) ++ tx = ANTENNA_A; ++ else if (tx == ANTENNA_A) ++ tx = ANTENNA_B; ++ } ++ ++ rt2x00lib_config_antenna(rt2x00dev, rx, tx); ++} ++ ++static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev) ++{ ++ enum antenna rx = rt2x00dev->link.ant.active.rx; ++ enum antenna tx = rt2x00dev->link.ant.active.tx; ++ int rssi_curr = rt2x00_get_link_ant_rssi(&rt2x00dev->link); ++ int rssi_old = rt2x00_update_ant_rssi(&rt2x00dev->link, rssi_curr); ++ ++ /* ++ * Legacy driver indicates that we should swap antenna's ++ * when the difference in RSSI is greater that 5. This ++ * also should be done when the RSSI was actually better ++ * then the previous sample. ++ * When the difference exceeds the threshold we should ++ * sample the rssi from the other antenna to make a valid ++ * comparison between the 2 antennas. ++ */ ++ if ((rssi_curr - rssi_old) > -5 || (rssi_curr - rssi_old) < 5) ++ return; ++ ++ rt2x00dev->link.ant.flags |= ANTENNA_MODE_SAMPLE; ++ ++ if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) ++ rx = (rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; ++ ++ if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) ++ tx = (tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; ++ ++ rt2x00lib_config_antenna(rt2x00dev, rx, tx); ++} ++ ++static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev) ++{ ++ /* ++ * Determine if software diversity is enabled for ++ * either the TX or RX antenna (or both). ++ * Always perform this check since within the link ++ * tuner interval the configuration might have changed. ++ */ ++ rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY; ++ rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY; ++ ++ if (rt2x00dev->hw->conf.antenna_sel_rx == 0 && ++ rt2x00dev->default_ant.rx != ANTENNA_SW_DIVERSITY) ++ rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY; ++ if (rt2x00dev->hw->conf.antenna_sel_tx == 0 && ++ rt2x00dev->default_ant.tx != ANTENNA_SW_DIVERSITY) ++ rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY; ++ ++ if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) && ++ !(rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)) { ++ rt2x00dev->link.ant.flags &= ~ANTENNA_MODE_SAMPLE; ++ return; ++ } ++ ++ /* ++ * If we have only sampled the data over the last period ++ * we should now harvest the data. Otherwise just evaluate ++ * the data. The latter should only be performed once ++ * every 2 seconds. ++ */ ++ if (rt2x00dev->link.ant.flags & ANTENNA_MODE_SAMPLE) ++ rt2x00lib_evaluate_antenna_sample(rt2x00dev); ++ else if (rt2x00dev->link.count & 1) ++ rt2x00lib_evaluate_antenna_eval(rt2x00dev); ++} ++ ++static void rt2x00lib_update_link_stats(struct link *link, int rssi) + { +- if (link->rx_failed || link->rx_success) +- link->rx_percentage = +- (link->rx_success * 100) / +- (link->rx_failed + link->rx_success); ++ int avg_rssi = rssi; ++ ++ /* ++ * Update global RSSI ++ */ ++ if (link->qual.avg_rssi) ++ avg_rssi = MOVING_AVERAGE(link->qual.avg_rssi, rssi, 8); ++ link->qual.avg_rssi = avg_rssi; ++ ++ /* ++ * Update antenna RSSI ++ */ ++ if (link->ant.rssi_ant) ++ rssi = MOVING_AVERAGE(link->ant.rssi_ant, rssi, 8); ++ link->ant.rssi_ant = rssi; ++} ++ ++static void rt2x00lib_precalculate_link_signal(struct link_qual *qual) ++{ ++ if (qual->rx_failed || qual->rx_success) ++ qual->rx_percentage = ++ (qual->rx_success * 100) / ++ (qual->rx_failed + qual->rx_success); + else +- link->rx_percentage = 50; ++ qual->rx_percentage = 50; + +- if (link->tx_failed || link->tx_success) +- link->tx_percentage = +- (link->tx_success * 100) / +- (link->tx_failed + link->tx_success); ++ if (qual->tx_failed || qual->tx_success) ++ qual->tx_percentage = ++ (qual->tx_success * 100) / ++ (qual->tx_failed + qual->tx_success); + else +- link->tx_percentage = 50; ++ qual->tx_percentage = 50; + +- link->rx_success = 0; +- link->rx_failed = 0; +- link->tx_success = 0; +- link->tx_failed = 0; ++ qual->rx_success = 0; ++ qual->rx_failed = 0; ++ qual->tx_success = 0; ++ qual->tx_failed = 0; + } + + static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev, +@@ -225,8 +366,8 @@ static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev, + * defines to calculate the current link signal. + */ + signal = ((WEIGHT_RSSI * rssi_percentage) + +- (WEIGHT_TX * rt2x00dev->link.tx_percentage) + +- (WEIGHT_RX * rt2x00dev->link.rx_percentage)) / 100; ++ (WEIGHT_TX * rt2x00dev->link.qual.tx_percentage) + ++ (WEIGHT_RX * rt2x00dev->link.qual.rx_percentage)) / 100; + + return (signal > 100) ? 100 : signal; + } +@@ -246,10 +387,9 @@ static void rt2x00lib_link_tuner(struct work_struct *work) + /* + * Update statistics. + */ +- rt2x00dev->ops->lib->link_stats(rt2x00dev); +- ++ rt2x00dev->ops->lib->link_stats(rt2x00dev, &rt2x00dev->link.qual); + rt2x00dev->low_level_stats.dot11FCSErrorCount += +- rt2x00dev->link.rx_failed; ++ rt2x00dev->link.qual.rx_failed; + + /* + * Only perform the link tuning when Link tuning +@@ -259,10 +399,15 @@ static void rt2x00lib_link_tuner(struct work_struct *work) + rt2x00dev->ops->lib->link_tuner(rt2x00dev); + + /* ++ * Evaluate antenna setup. ++ */ ++ rt2x00lib_evaluate_antenna(rt2x00dev); ++ ++ /* + * Precalculate a portion of the link signal which is + * in based on the tx/rx success/failure counters. + */ +- rt2x00lib_precalculate_link_signal(&rt2x00dev->link); ++ rt2x00lib_precalculate_link_signal(&rt2x00dev->link.qual); + + /* + * Increase tuner counter, and reschedule the next link tuner run. +@@ -350,8 +495,8 @@ void rt2x00lib_txdone(struct data_entry *entry, + tx_status->ack_signal = 0; + tx_status->excessive_retries = (status == TX_FAIL_RETRY); + tx_status->retry_count = retry; +- rt2x00dev->link.tx_success += success; +- rt2x00dev->link.tx_failed += retry + fail; ++ rt2x00dev->link.qual.tx_success += success; ++ rt2x00dev->link.qual.tx_failed += retry + fail; + + if (!(tx_status->control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (success) +@@ -412,13 +557,15 @@ void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, + } + } + +- rt2x00_update_link_rssi(&rt2x00dev->link, desc->rssi); +- rt2x00dev->link.rx_success++; ++ rt2x00lib_update_link_stats(&rt2x00dev->link, desc->rssi); ++ rt2x00dev->link.qual.rx_success++; ++ + rx_status->rate = val; + rx_status->signal = + rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi); + rx_status->ssi = desc->rssi; + rx_status->flag = desc->flags; ++ rx_status->antenna = rt2x00dev->link.ant.active.rx; + + /* + * Send frame to mac80211 +diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h +index 06d9bc0..7319411 100644 +--- a/drivers/net/wireless/rt2x00/rt2x00lib.h ++++ b/drivers/net/wireless/rt2x00/rt2x00lib.h +@@ -53,6 +53,8 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev); + void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); + void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); + void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type); ++void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, ++ enum antenna rx, enum antenna tx); + void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, const int force_config); + +diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c +index ecae968..7c97761 100644 +--- a/drivers/net/wireless/rt2x00/rt61pci.c ++++ b/drivers/net/wireless/rt2x00/rt61pci.c +@@ -411,8 +411,7 @@ static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, + } + + static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, +- const int antenna_tx, +- const int antenna_rx) ++ struct antenna_setup *ant) + { + u8 r3; + u8 r4; +@@ -425,30 +424,49 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, + !rt2x00_rf(&rt2x00dev->chip, RF5225)); + +- switch (antenna_rx) { ++ /* ++ * Configure the TX antenna. ++ */ ++ switch (ant->tx) { ++ case ANTENNA_A: ++ rt2x00_set_field8(&r77, BBP_R77_TX_ANTENNA, 0); ++ break; + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ ++ case ANTENNA_B: ++ rt2x00_set_field8(&r77, BBP_R77_TX_ANTENNA, 3); ++ break; ++ } ++ ++ /* ++ * Configure the RX antenna. ++ */ ++ switch (ant->rx) { ++ case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, +- !!(rt2x00dev->curr_hwmode != HWMODE_A)); ++ (rt2x00dev->curr_hwmode != HWMODE_A)); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); +- +- if (rt2x00dev->curr_hwmode == HWMODE_A) +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); +- else +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + break; ++ case ANTENNA_SW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); +- +- if (rt2x00dev->curr_hwmode == HWMODE_A) +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); +- else +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + break; + } + +@@ -458,8 +476,7 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, + } + + static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, +- const int antenna_tx, +- const int antenna_rx) ++ struct antenna_setup *ant) + { + u8 r3; + u8 r4; +@@ -474,18 +491,45 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, + !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); + +- switch (antenna_rx) { ++ /* ++ * Configure the TX antenna. ++ */ ++ switch (ant->tx) { ++ case ANTENNA_A: ++ rt2x00_set_field8(&r77, BBP_R77_TX_ANTENNA, 0); ++ break; + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ ++ case ANTENNA_B: ++ rt2x00_set_field8(&r77, BBP_R77_TX_ANTENNA, 3); ++ break; ++ } ++ ++ /* ++ * Configure the RX antenna. ++ */ ++ switch (ant->rx) { ++ case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + break; ++ case ANTENNA_SW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + break; + } + +@@ -514,81 +558,81 @@ static void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev, + } + + static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev, +- const int antenna_tx, +- const int antenna_rx) ++ struct antenna_setup *ant) + { + u16 eeprom; + u8 r3; + u8 r4; + u8 r77; ++ u8 rx_ant; + + rt61pci_bbp_read(rt2x00dev, 3, &r3); + rt61pci_bbp_read(rt2x00dev, 4, &r4); + rt61pci_bbp_read(rt2x00dev, 77, &r77); ++ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); ++ rx_ant = !!(rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED) & 2); + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); + +- if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) && +- rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) { +- rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); +- rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 1); +- rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1); +- } else if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY)) { +- if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED) >= 2) { +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); +- rt61pci_bbp_write(rt2x00dev, 77, r77); +- } +- rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); +- rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); +- } else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) && +- rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) { +- rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); +- rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); ++ /* ++ * Configure the TX antenna. ++ */ ++ switch (ant->tx) { ++ case ANTENNA_A: ++ rt2x00_set_field8(&r77, BBP_R77_TX_ANTENNA, 0); ++ break; ++ case ANTENNA_SW_DIVERSITY: ++ case ANTENNA_HW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ ++ case ANTENNA_B: ++ rt2x00_set_field8(&r77, BBP_R77_TX_ANTENNA, 3); ++ break; ++ } + +- switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) { +- case 0: +- rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1); +- break; +- case 1: +- rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0); +- break; +- case 2: +- rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0); +- break; +- case 3: +- rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); +- break; +- } +- } else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) && +- !rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) { ++ /* ++ * Configure the RX antenna. ++ */ ++ switch (ant->rx) { ++ case ANTENNA_A: ++ rt61pci_config_antenna_2529_rx(rt2x00dev, 0, rx_ant); ++ break; ++ case ANTENNA_SW_DIVERSITY: ++ case ANTENNA_HW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ ++ case ANTENNA_B: ++ rt61pci_config_antenna_2529_rx(rt2x00dev, 1, rx_ant); ++ break; ++ } ++ ++ /* ++ * FIXME: We are using the default antenna setup to ++ * determine the remaining settings. This because we ++ * need to know what the EEPROM indicated. ++ * It is however unclear if this is required, and overall ++ * using the default antenna settings here is incorrect ++ * since mac80211 might have told us to use fixed settings. ++ */ ++ if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) ++ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); ++ else + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); +- rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + +- switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) { +- case 0: +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); +- rt61pci_bbp_write(rt2x00dev, 77, r77); +- rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1); +- break; +- case 1: +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); +- rt61pci_bbp_write(rt2x00dev, 77, r77); +- rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0); +- break; +- case 2: +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); +- rt61pci_bbp_write(rt2x00dev, 77, r77); +- rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0); +- break; +- case 3: +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); +- rt61pci_bbp_write(rt2x00dev, 77, r77); +- rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); +- break; +- } +- } ++ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, ++ (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) && ++ (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)); + ++ rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_bbp_write(rt2x00dev, 3, r3); + rt61pci_bbp_write(rt2x00dev, 4, r4); + } +@@ -625,7 +669,7 @@ static const struct antenna_sel antenna_sel_bg[] = { + }; + + static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, +- const int antenna_tx, const int antenna_rx) ++ struct antenna_setup *ant) + { + const struct antenna_sel *sel; + unsigned int lna; +@@ -637,17 +681,17 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, + if (rt2x00dev->curr_hwmode == HWMODE_A) { + sel = antenna_sel_a; + lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); +- +- rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 0); +- rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 1); + } else { + sel = antenna_sel_bg; + lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); +- +- rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 1); +- rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 0); + } + ++ rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, ++ (rt2x00dev->curr_hwmode == HWMODE_B || ++ rt2x00dev->curr_hwmode == HWMODE_G)); ++ rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, ++ (rt2x00dev->curr_hwmode == HWMODE_A)); ++ + for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) + rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); + +@@ -655,16 +699,14 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, + + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF5325)) +- rt61pci_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx); ++ rt61pci_config_antenna_5x(rt2x00dev, ant); + else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) +- rt61pci_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx); ++ rt61pci_config_antenna_2x(rt2x00dev, ant); + else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) { + if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) +- rt61pci_config_antenna_2x(rt2x00dev, antenna_tx, +- antenna_rx); ++ rt61pci_config_antenna_2x(rt2x00dev, ant); + else +- rt61pci_config_antenna_2529(rt2x00dev, antenna_tx, +- antenna_rx); ++ rt61pci_config_antenna_2529(rt2x00dev, ant); + } + } + +@@ -709,8 +751,7 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, + if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) +- rt61pci_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx, +- libconf->conf->antenna_sel_rx); ++ rt61pci_config_antenna(rt2x00dev, &libconf->ant); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt61pci_config_duration(rt2x00dev, libconf); + } +@@ -721,7 +762,6 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, + static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev) + { + u32 reg; +- u16 led_reg; + u8 arg0; + u8 arg1; + +@@ -730,15 +770,14 @@ static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev) + rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, 30); + rt2x00pci_register_write(rt2x00dev, MAC_CSR14, reg); + +- led_reg = rt2x00dev->led_reg; +- rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 1); +- if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) +- rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 1); +- else +- rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 1); ++ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1); ++ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, ++ (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)); ++ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, ++ (rt2x00dev->rx_status.phymode != MODE_IEEE80211A)); + +- arg0 = led_reg & 0xff; +- arg1 = (led_reg >> 8) & 0xff; ++ arg0 = rt2x00dev->led_reg & 0xff; ++ arg1 = (rt2x00dev->led_reg >> 8) & 0xff; + + rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1); + } +@@ -792,7 +831,8 @@ static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi) + /* + * Link tuning + */ +-static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev) ++static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev, ++ struct link_qual *qual) + { + u32 reg; + +@@ -800,14 +840,13 @@ static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev) + * Update FCS error count from register. + */ + rt2x00pci_register_read(rt2x00dev, STA_CSR0, ®); +- rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); ++ qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt2x00pci_register_read(rt2x00dev, STA_CSR1, ®); +- rt2x00dev->link.false_cca = +- rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); ++ qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); + } + + static void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev) +@@ -904,11 +943,11 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) + * r17 does not yet exceed upper limit, continue and base + * the r17 tuning on the false CCA count. + */ +- if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) { ++ if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) { + if (++r17 > up_bound) + r17 = up_bound; + rt61pci_bbp_write(rt2x00dev, 17, r17); +- } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { ++ } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) { + if (--r17 < low_bound) + r17 = low_bound; + rt61pci_bbp_write(rt2x00dev, 17, r17); +@@ -1649,16 +1688,16 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + } + + rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); +- if (queue == IEEE80211_TX_QUEUE_DATA0) +- rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, 1); +- else if (queue == IEEE80211_TX_QUEUE_DATA1) +- rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, 1); +- else if (queue == IEEE80211_TX_QUEUE_DATA2) +- rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, 1); +- else if (queue == IEEE80211_TX_QUEUE_DATA3) +- rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, 1); +- else if (queue == IEEE80211_TX_QUEUE_DATA4) +- rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_MGMT, 1); ++ rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, ++ (queue == IEEE80211_TX_QUEUE_DATA0)); ++ rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, ++ (queue == IEEE80211_TX_QUEUE_DATA1)); ++ rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, ++ (queue == IEEE80211_TX_QUEUE_DATA2)); ++ rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, ++ (queue == IEEE80211_TX_QUEUE_DATA3)); ++ rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_MGMT, ++ (queue == IEEE80211_TX_QUEUE_DATA4)); + rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); + } + +@@ -1920,8 +1959,10 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); +- rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2); +- rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2); ++ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, ++ ANTENNA_B); ++ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, ++ ANTENNA_B); + rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); +@@ -2025,11 +2066,17 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) + } + + /* ++ * Determine number of antenna's. ++ */ ++ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) ++ __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags); ++ ++ /* + * Identify default antenna configuration. + */ +- rt2x00dev->hw->conf.antenna_sel_tx = ++ rt2x00dev->default_ant.tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); +- rt2x00dev->hw->conf.antenna_sel_rx = ++ rt2x00dev->default_ant.rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* +@@ -2039,12 +2086,6 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) + __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); + + /* +- * Determine number of antenna's. +- */ +- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) +- __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags); +- +- /* + * Detect if this device has an hardware controlled radio. + */ + #ifdef CONFIG_RT61PCI_RFKILL +@@ -2072,6 +2113,38 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) + __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + + /* ++ * When working with a RF2529 chip without double antenna ++ * the antenna settings should be gathered from the NIC ++ * eeprom word. ++ */ ++ if (rt2x00_rf(&rt2x00dev->chip, RF2529) && ++ !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) { ++ switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) { ++ case 0: ++ rt2x00dev->default_ant.tx = ANTENNA_B; ++ rt2x00dev->default_ant.rx = ANTENNA_A; ++ break; ++ case 1: ++ rt2x00dev->default_ant.tx = ANTENNA_B; ++ rt2x00dev->default_ant.rx = ANTENNA_B; ++ break; ++ case 2: ++ rt2x00dev->default_ant.tx = ANTENNA_A; ++ rt2x00dev->default_ant.rx = ANTENNA_A; ++ break; ++ case 3: ++ rt2x00dev->default_ant.tx = ANTENNA_A; ++ rt2x00dev->default_ant.rx = ANTENNA_B; ++ break; ++ } ++ ++ if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) ++ rt2x00dev->default_ant.tx = ANTENNA_SW_DIVERSITY; ++ if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY)) ++ rt2x00dev->default_ant.rx = ANTENNA_SW_DIVERSITY; ++ } ++ ++ /* + * Store led settings, for correct led behaviour. + * If the eeprom value is invalid, + * switch to default led mode. +diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h +index 6721d7d..ba51016 100644 +--- a/drivers/net/wireless/rt2x00/rt61pci.h ++++ b/drivers/net/wireless/rt2x00/rt61pci.h +@@ -1083,7 +1083,7 @@ struct hw_pairwise_ta_entry { + /* + * R77 + */ +-#define BBP_R77_PAIR FIELD8(0x03) ++#define BBP_R77_TX_ANTENNA FIELD8(0x03) + + /* + * RF registers +diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c +index c0671c2..b9d5310 100644 +--- a/drivers/net/wireless/rt2x00/rt73usb.c ++++ b/drivers/net/wireless/rt2x00/rt73usb.c +@@ -200,8 +200,8 @@ rf_write: + * all others contain 20 bits. + */ + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, +- 20 + !!(rt2x00_rf(&rt2x00dev->chip, RF5225) || +- rt2x00_rf(&rt2x00dev->chip, RF2527))); ++ 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) || ++ rt2x00_rf(&rt2x00dev->chip, RF2527))); + rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); + rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); + +@@ -396,8 +396,7 @@ static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, + } + + static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, +- const int antenna_tx, +- const int antenna_rx) ++ struct antenna_setup *ant) + { + u8 r3; + u8 r4; +@@ -409,30 +408,49 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); + +- switch (antenna_rx) { ++ /* ++ * Configure the TX antenna. ++ */ ++ switch (ant->tx) { ++ case ANTENNA_A: ++ rt2x00_set_field8(&r77, BBP_R77_TX_ANTENNA, 0); ++ break; + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ ++ case ANTENNA_B: ++ rt2x00_set_field8(&r77, BBP_R77_TX_ANTENNA, 3); ++ break; ++ } ++ ++ /* ++ * Configure the RX antenna. ++ */ ++ switch (ant->rx) { ++ case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, +- !!(rt2x00dev->curr_hwmode != HWMODE_A)); ++ (rt2x00dev->curr_hwmode != HWMODE_A)); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); +- +- if (rt2x00dev->curr_hwmode == HWMODE_A) +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); +- else +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + break; ++ case ANTENNA_SW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); +- +- if (rt2x00dev->curr_hwmode == HWMODE_A) +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); +- else +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + break; + } + +@@ -442,8 +460,7 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, + } + + static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev, +- const int antenna_tx, +- const int antenna_rx) ++ struct antenna_setup *ant) + { + u8 r3; + u8 r4; +@@ -457,18 +474,45 @@ static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev, + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, + !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); + +- switch (antenna_rx) { ++ /* ++ * Configure the TX antenna. ++ */ ++ switch (ant->tx) { ++ case ANTENNA_A: ++ rt2x00_set_field8(&r77, BBP_R77_TX_ANTENNA, 0); ++ break; + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ ++ case ANTENNA_B: ++ rt2x00_set_field8(&r77, BBP_R77_TX_ANTENNA, 3); ++ break; ++ } ++ ++ /* ++ * Configure the RX antenna. ++ */ ++ switch (ant->rx) { ++ case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + break; ++ case ANTENNA_SW_DIVERSITY: ++ /* ++ * NOTE: We should never come here because rt2x00lib is ++ * supposed to catch this and send us the correct antenna ++ * explicitely. However we are nog going to bug about this. ++ * Instead, just default to antenna B. ++ */ + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); +- rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + break; + } + +@@ -509,7 +553,7 @@ static const struct antenna_sel antenna_sel_bg[] = { + }; + + static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, +- const int antenna_tx, const int antenna_rx) ++ struct antenna_setup *ant) + { + const struct antenna_sel *sel; + unsigned int lna; +@@ -521,17 +565,17 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, + if (rt2x00dev->curr_hwmode == HWMODE_A) { + sel = antenna_sel_a; + lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); +- +- rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 0); +- rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 1); + } else { + sel = antenna_sel_bg; + lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); +- +- rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 1); +- rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 0); + } + ++ rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, ++ (rt2x00dev->curr_hwmode == HWMODE_B || ++ rt2x00dev->curr_hwmode == HWMODE_G)); ++ rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, ++ (rt2x00dev->curr_hwmode == HWMODE_A)); ++ + for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) + rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); + +@@ -539,10 +583,10 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, + + if (rt2x00_rf(&rt2x00dev->chip, RF5226) || + rt2x00_rf(&rt2x00dev->chip, RF5225)) +- rt73usb_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx); ++ rt73usb_config_antenna_5x(rt2x00dev, ant); + else if (rt2x00_rf(&rt2x00dev->chip, RF2528) || + rt2x00_rf(&rt2x00dev->chip, RF2527)) +- rt73usb_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx); ++ rt73usb_config_antenna_2x(rt2x00dev, ant); + } + + static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, +@@ -586,8 +630,7 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev, + if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) +- rt73usb_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx, +- libconf->conf->antenna_sel_rx); ++ rt73usb_config_antenna(rt2x00dev, &libconf->ant); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt73usb_config_duration(rt2x00dev, libconf); + } +@@ -605,12 +648,10 @@ static void rt73usb_enable_led(struct rt2x00_dev *rt2x00dev) + rt73usb_register_write(rt2x00dev, MAC_CSR14, reg); + + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1); +- if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) +- rt2x00_set_field16(&rt2x00dev->led_reg, +- MCU_LEDCS_LINK_A_STATUS, 1); +- else +- rt2x00_set_field16(&rt2x00dev->led_reg, +- MCU_LEDCS_LINK_BG_STATUS, 1); ++ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, ++ (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)); ++ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, ++ (rt2x00dev->rx_status.phymode != MODE_IEEE80211A)); + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000, + rt2x00dev->led_reg, REGISTER_TIMEOUT); +@@ -659,7 +700,8 @@ static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, int rssi) + /* + * Link tuning + */ +-static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev) ++static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev, ++ struct link_qual *qual) + { + u32 reg; + +@@ -667,15 +709,13 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev) + * Update FCS error count from register. + */ + rt73usb_register_read(rt2x00dev, STA_CSR0, ®); +- rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); ++ qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt73usb_register_read(rt2x00dev, STA_CSR1, ®); +- reg = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); +- rt2x00dev->link.false_cca = +- rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); ++ qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); + } + + static void rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev) +@@ -781,12 +821,12 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) + * r17 does not yet exceed upper limit, continue and base + * the r17 tuning on the false CCA count. + */ +- if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) { ++ if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) { + r17 += 4; + if (r17 > up_bound) + r17 = up_bound; + rt73usb_bbp_write(rt2x00dev, 17, r17); +- } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { ++ } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) { + r17 -= 4; + if (r17 < low_bound) + r17 = low_bound; +@@ -1392,8 +1432,10 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); +- rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2); +- rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2); ++ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, ++ ANTENNA_B); ++ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, ++ ANTENNA_B); + rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); +@@ -1502,9 +1544,9 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) + /* + * Identify default antenna configuration. + */ +- rt2x00dev->hw->conf.antenna_sel_tx = ++ rt2x00dev->default_ant.tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); +- rt2x00dev->hw->conf.antenna_sel_rx = ++ rt2x00dev->default_ant.rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* +diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h +index f095151..13f479c 100644 +--- a/drivers/net/wireless/rt2x00/rt73usb.h ++++ b/drivers/net/wireless/rt2x00/rt73usb.h +@@ -719,7 +719,7 @@ struct hw_pairwise_ta_entry { + /* + * R77 + */ +-#define BBP_R77_PAIR FIELD8(0x03) ++#define BBP_R77_TX_ANTENNA FIELD8(0x03) + + /* + * RF registers +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0120-Turn-debian-binary-custom.d-lpia-patchset-0015-pouls.patch +++ linux-2.6.24/patches/0120-Turn-debian-binary-custom.d-lpia-patchset-0015-pouls.patch @@ -0,0 +1,897 @@ +From ff08a414c46ee0a8c57ebe81d8eb1ec4274509d4 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:32 +0100 +Subject: [PATCH 120/170] Turn debian/binary-custom.d/lpia/patchset/0015-poulsbo_smbus.patch into a commit. + +Signed-off-by: Andy Whitcroft + +commit 4883c50b37f2e791e29f545766e53ac456576926 +Author: Amit Kucheria +Date: Fri Jan 11 13:59:04 2008 +0200 + + UBUNTU: Poulsbo: Mass update of patches to be identical to those on moblin + + Sigh, we need better communication... + + Signed-off-by: Amit Kucheria +--- + .../lpia/patchset/0015-poulsbo_smbus.patch | 432 -------------------- + drivers/i2c/busses/Kconfig | 9 + + drivers/i2c/busses/Makefile | 1 + + drivers/i2c/busses/i2c-sch.c | 393 ++++++++++++++++++ + 4 files changed, 403 insertions(+), 432 deletions(-) + delete mode 100644 debian/binary-custom.d/lpia/patchset/0015-poulsbo_smbus.patch + create mode 100644 drivers/i2c/busses/i2c-sch.c + +diff --git a/debian/binary-custom.d/lpia/patchset/0015-poulsbo_smbus.patch b/debian/binary-custom.d/lpia/patchset/0015-poulsbo_smbus.patch +deleted file mode 100644 +index 318af74..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0015-poulsbo_smbus.patch ++++ /dev/null +@@ -1,432 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +-index c466c6c..85abf0a 100644 +---- a/drivers/i2c/busses/Kconfig +-+++ b/drivers/i2c/busses/Kconfig +-@@ -239,6 +239,15 @@ config I2C_PIIX4 +- This driver can also be built as a module. If so, the module +- will be called i2c-piix4. +- +-+config I2C_POULSBO +-+ tristate "Intel SCH (Poulsbo SMBUS 1.0)" +-+ depends on I2C && PCI +-+ help +-+ If you say yes to this option, support will be included for the Intel +-+ SCH +-+ Intel POULSBO +-+ will be called i2c-sch. +-+ +- config I2C_IBM_IIC +- tristate "IBM PPC 4xx on-chip I2C interface" +- depends on IBM_OCP +-diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +-index 81d43c2..ece538a 100644 +---- a/drivers/i2c/busses/Makefile +-+++ b/drivers/i2c/busses/Makefile +-@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o +- obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o +- obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o +- obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o +-+obj-$(CONFIG_I2C_POULSBO) += i2c-sch.o +- obj-$(CONFIG_I2C_PNX) += i2c-pnx.o +- obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o +- obj-$(CONFIG_I2C_PXA) += i2c-pxa.o +-diff --git a/drivers/i2c/busses/i2c-sch.c b/drivers/i2c/busses/i2c-sch.c +-new file mode 100644 +-index 0000000..8940362 +---- /dev/null +-+++ b/drivers/i2c/busses/i2c-sch.c +-@@ -0,0 +1,393 @@ +-+/* +-+ i2c-sch.c - Part of lm_sensors, Linux kernel modules for hardware +-+ monitoring +-+ Based on piix4.c +-+ Copyright (c) 1998 - 2002 Frodo Looijaard and +-+ Philip Edelbrock +-+ +-+ This program is free software; you can redistribute it and/or modify +-+ it under the terms of the GNU General Public License as published by +-+ the Free Software Foundation; either version 2 of the License, or +-+ (at your option) any later version. +-+ +-+ This program is distributed in the hope that it will be useful, +-+ but WITHOUT ANY WARRANTY; without even the implied warranty of +-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-+ GNU General Public License for more details. +-+ +-+ You should have received a copy of the GNU General Public License +-+ along with this program; if not, write to the Free Software +-+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +-+*/ +-+ +-+/* +-+ Supports: +-+ Intel POULSBO +-+ +-+ Note: we assume there can only be one device, with one SMBus interface. +-+*/ +-+ +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+ +-+ +-+struct sd { +-+ const unsigned short mfr; +-+ const unsigned short dev; +-+ const unsigned char fn; +-+ const char *name; +-+}; +-+/* POULSBO SMBus address offsets */ +-+#define SMBHSTCNT (0 + poulsbo_smba) +-+#define SMBHSTSTS (1 + poulsbo_smba) +-+#define SMBHSTADD (4 + poulsbo_smba) /* TSA */ +-+#define SMBHSTCMD (5 + poulsbo_smba) +-+#define SMBHSTDAT0 (6 + poulsbo_smba) +-+#define SMBHSTDAT1 (7 + poulsbo_smba) +-+#define SMBBLKDAT (0x20 + poulsbo_smba) +-+ +-+ +-+/* count for request_region */ +-+#define SMBIOSIZE 8 +-+ +-+/* PCI Address Constants */ +-+#define SMBBA_SCH 0x040 +-+ +-+/* Other settings */ +-+#define MAX_TIMEOUT 500 +-+#define ENABLE_INT9 0 +-+ +-+/* POULSBO constants */ +-+#define POULSBO_QUICK 0x00 +-+#define POULSBO_BYTE 0x01 +-+#define POULSBO_BYTE_DATA 0x02 +-+#define POULSBO_WORD_DATA 0x03 +-+#define POULSBO_BLOCK_DATA 0x05 +-+ +-+/* insmod parameters */ +-+ +-+/* If force is set to anything different from 0, we forcibly enable the +-+ POULSBO. DANGEROUS! */ +-+static int force; +-+module_param (force, int, 0); +-+MODULE_PARM_DESC(force, "Forcibly enable the POULSBO. DANGEROUS!"); +-+ +-+ +-+static int poulsbo_transaction(void); +-+ +-+static unsigned short poulsbo_smba; +-+static struct pci_driver poulsbo_driver; +-+static struct i2c_adapter poulsbo_adapter; +-+ +-+ +-+static int __devinit poulsbo_setup(struct pci_dev *POULSBO_dev, +-+ const struct pci_device_id *id) +-+{ +-+ unsigned short smbase; +-+ if(POULSBO_dev->device != PCI_DEVICE_ID_INTEL_POULSBO_LPC) { +-+ /* match up the function */ +-+ if (PCI_FUNC(POULSBO_dev->devfn) != id->driver_data) +-+ return -ENODEV; +-+ dev_info(&POULSBO_dev->dev, "Found %s device\n", pci_name(POULSBO_dev)); +-+ } else { +-+ dev_info(&POULSBO_dev->dev, "Found POULSBO SMBUS %s device\n", pci_name(POULSBO_dev)); +-+ /* find SMBUS base address */ +-+ pci_read_config_word(POULSBO_dev, 0x40, &smbase); +-+ dev_info(&POULSBO_dev->dev, "POULSBO SM base = 0x%04x\n", smbase); +-+ } +-+ +-+ +-+ /* Determine the address of the SMBus areas */ +-+ if(POULSBO_dev->device == PCI_DEVICE_ID_INTEL_POULSBO_LPC) +-+ pci_read_config_word(POULSBO_dev, SMBBA_SCH, &poulsbo_smba); +-+ else +-+ poulsbo_smba=0; +-+ +-+ poulsbo_smba &= 0xfff0; +-+ if(poulsbo_smba == 0) { +-+ dev_err(&POULSBO_dev->dev, "SMB base address " +-+ "uninitialized - upgrade BIOS or use " +-+ "force_addr=0xaddr\n"); +-+ return -ENODEV; +-+ } +-+ +-+ if (!request_region(poulsbo_smba, SMBIOSIZE, poulsbo_driver.name)) { +-+ dev_err(&POULSBO_dev->dev, "SMB region 0x%x already in use!\n", +-+ poulsbo_smba); +-+ return -ENODEV; +-+ } +-+ +-+ dev_dbg(&POULSBO_dev->dev, "SMBA = 0x%X\n", poulsbo_smba); +-+ +-+ return 0; +-+} +-+ +-+/* Another internally used function */ +-+static int poulsbo_transaction(void) +-+{ +-+ int temp; +-+ int result = 0; +-+ int timeout = 0; +-+ +-+ dev_dbg(&poulsbo_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " +-+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), +-+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), +-+ inb_p(SMBHSTDAT1)); +-+ +-+ /* Make sure the SMBus host is ready to start transmitting */ +-+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { +-+ if(temp == 1) { +-+ dev_dbg(&poulsbo_adapter.dev, "Completion (%02x). " +-+ "clear...\n", temp); +-+ outb_p(temp, SMBHSTSTS); +-+ +-+ } else if(temp & 0xe) { +-+ dev_dbg(&poulsbo_adapter.dev, "SMBus error (%02x). " +-+ "Resetting...\n", temp); +-+ outb_p(temp, SMBHSTSTS); +-+ } +-+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { +-+ dev_err(&poulsbo_adapter.dev, "Failed! (%02x)\n", temp); +-+ return -1; +-+ } else { +-+ dev_dbg(&poulsbo_adapter.dev, "Successfull!\n"); +-+ } +-+ } +-+ +-+ /* start the transaction by setting bit 4 */ +-+ outb_p(inb(SMBHSTCNT) | 0x10, SMBHSTCNT); +-+ +-+ /* We will always wait for a fraction of a second! (See POULSBO docs errata) */ +-+ do { +-+ msleep(1); +-+ temp = inb_p(SMBHSTSTS); +-+ } while ((temp & 0x08) && (timeout++ < MAX_TIMEOUT)); +-+ +-+ /* If the SMBus is still busy, we give up */ +-+ if (timeout >= MAX_TIMEOUT) { +-+ dev_err(&poulsbo_adapter.dev, "SMBus Timeout!\n"); +-+ result = -1; +-+ } +-+ +-+ if (temp & 0x10) { +-+ result = -1; +-+ dev_err(&poulsbo_adapter.dev, "Error: Failed bus transaction\n"); +-+ } +-+ +-+ if (temp & 0x08) { +-+ result = -1; +-+ dev_dbg(&poulsbo_adapter.dev, "Bus collision! SMBus may be " +-+ "locked until next hard reset. (sorry!)\n"); +-+ /* Clock stops and slave is stuck in mid-transmission */ +-+ } +-+ +-+ if (temp & 0x04) { +-+ result = -1; +-+ dev_dbg(&poulsbo_adapter.dev, "Error: no response!\n"); +-+ } +-+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { +-+ if( temp == 0x1) { +-+ dev_dbg(&poulsbo_adapter.dev, "post complete!\n"); +-+ outb_p(temp, SMBHSTSTS); +-+ } +-+ else if(temp & 0xe) { +-+ dev_dbg(&poulsbo_adapter.dev, "Error: bus, etc!\n"); +-+ outb_p(inb(SMBHSTSTS), SMBHSTSTS); +-+ } +-+ } +-+ msleep(1); +-+ if ((temp = inb_p(SMBHSTSTS)) & 0xe) { +-+ /* BSY, device or bus error */ +-+ dev_err(&poulsbo_adapter.dev, "Failed reset at end of " +-+ "transaction (%02x), Bus error\n", temp); +-+ } +-+ dev_dbg(&poulsbo_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " +-+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), +-+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), +-+ inb_p(SMBHSTDAT1)); +-+ return result; +-+} +-+ +-+/* Return -1 on error. */ +-+static s32 poulsbo_access(struct i2c_adapter * adap, u16 addr, +-+ unsigned short flags, char read_write, +-+ u8 command, int size, union i2c_smbus_data * data) +-+{ +-+ int i, len; +-+ dev_dbg(&poulsbo_adapter.dev,"access size: %d %s\n", size, (read_write)?"READ":"WRITE"); +-+ switch (size) { +-+ case I2C_SMBUS_PROC_CALL: +-+ dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); +-+ return -1; +-+ case I2C_SMBUS_QUICK: +-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), +-+ SMBHSTADD); +-+ size = POULSBO_QUICK; +-+ break; +-+ case I2C_SMBUS_BYTE: +-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), +-+ SMBHSTADD); +-+ if (read_write == I2C_SMBUS_WRITE) +-+ outb_p(command, SMBHSTCMD); +-+ size = POULSBO_BYTE; +-+ break; +-+ case I2C_SMBUS_BYTE_DATA: +-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), +-+ SMBHSTADD); +-+ outb_p(command, SMBHSTCMD); +-+ if (read_write == I2C_SMBUS_WRITE) +-+ outb_p(data->byte, SMBHSTDAT0); +-+ size = POULSBO_BYTE_DATA; +-+ break; +-+ case I2C_SMBUS_WORD_DATA: +-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), +-+ SMBHSTADD); +-+ outb_p(command, SMBHSTCMD); +-+ if (read_write == I2C_SMBUS_WRITE) { +-+ outb_p(data->word & 0xff, SMBHSTDAT0); +-+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); +-+ } +-+ size = POULSBO_WORD_DATA; +-+ break; +-+ case I2C_SMBUS_BLOCK_DATA: +-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), +-+ SMBHSTADD); +-+ outb_p(command, SMBHSTCMD); +-+ if (read_write == I2C_SMBUS_WRITE) { +-+ len = data->block[0]; +-+ if (len < 0) +-+ len = 0; +-+ if (len > 32) +-+ len = 32; +-+ outb_p(len, SMBHSTDAT0); +-+ i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ +-+ for (i = 1; i <= len; i++) +-+ outb_p(data->block[i], SMBBLKDAT); +-+ } +-+ size = POULSBO_BLOCK_DATA; +-+ break; +-+ } +-+ dev_dbg(&poulsbo_adapter.dev,"write size %d to 0x%04x\n", size, SMBHSTCNT); +-+ outb_p((size & 0x7), SMBHSTCNT); +-+ +-+ if (poulsbo_transaction()) /* Error in transaction */ +-+ return -1; +-+ +-+ if ((read_write == I2C_SMBUS_WRITE) || (size == POULSBO_QUICK)) +-+ return 0; +-+ +-+ +-+ switch (size) { +-+ case POULSBO_BYTE: /* Where is the result put? I assume here it is in +-+ SMBHSTDAT0 but it might just as well be in the +-+ SMBHSTCMD. No clue in the docs */ +-+ +-+ data->byte = inb_p(SMBHSTDAT0); +-+ break; +-+ case POULSBO_BYTE_DATA: +-+ data->byte = inb_p(SMBHSTDAT0); +-+ break; +-+ case POULSBO_WORD_DATA: +-+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); +-+ break; +-+ case POULSBO_BLOCK_DATA: +-+ data->block[0] = inb_p(SMBHSTDAT0); +-+ i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ +-+ for (i = 1; i <= data->block[0]; i++) +-+ data->block[i] = inb_p(SMBBLKDAT); +-+ break; +-+ } +-+ return 0; +-+} +-+ +-+static u32 poulsbo_func(struct i2c_adapter *adapter) +-+{ +-+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | +-+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | +-+ I2C_FUNC_SMBUS_BLOCK_DATA; +-+} +-+ +-+static const struct i2c_algorithm smbus_algorithm = { +-+ .smbus_xfer = poulsbo_access, +-+ .functionality = poulsbo_func, +-+}; +-+ +-+static struct i2c_adapter poulsbo_adapter = { +-+ .owner = THIS_MODULE, +-+ .class = I2C_CLASS_HWMON, +-+ .algo = &smbus_algorithm, +-+}; +-+ +-+static struct pci_device_id poulsbo_ids[] = { +-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_POULSBO_LPC), +-+ .driver_data = 0xf8 }, +-+ { 0, } +-+}; +-+ +-+MODULE_DEVICE_TABLE (pci, poulsbo_ids); +-+ +-+static int __devinit poulsbo_probe(struct pci_dev *dev, +-+ const struct pci_device_id *id) +-+{ +-+ int retval; +-+ retval = poulsbo_setup(dev, id); +-+ if (retval) +-+ return retval; +-+ +-+ /* set up the driverfs linkage to our parent device */ +-+ poulsbo_adapter.dev.parent = &dev->dev; +-+ +-+ snprintf(poulsbo_adapter.name, I2C_NAME_SIZE, +-+ "SMBus POULSBO adapter at %04x", poulsbo_smba); +-+ +-+ if ((retval = i2c_add_adapter(&poulsbo_adapter))) { +-+ dev_err(&dev->dev, "Couldn't register adapter!\n"); +-+ release_region(poulsbo_smba, SMBIOSIZE); +-+ poulsbo_smba = 0; +-+ } +-+ +-+ return retval; +-+} +-+ +-+static void __devexit poulsbo_remove(struct pci_dev *dev) +-+{ +-+ if (poulsbo_smba) { +-+ i2c_del_adapter(&poulsbo_adapter); +-+ release_region(poulsbo_smba, SMBIOSIZE); +-+ poulsbo_smba = 0; +-+ } +-+} +-+ +-+static struct pci_driver poulsbo_driver = { +-+ .name = "poulsbo_smbus", +-+ .id_table = poulsbo_ids, +-+ .probe = poulsbo_probe, +-+ .remove = __devexit_p(poulsbo_remove), +-+}; +-+ +-+static int __init i2c_poulsbo_init(void) +-+{ +-+ return pci_register_driver(&poulsbo_driver); +-+} +-+ +-+static void __exit i2c_poulsbo_exit(void) +-+{ +-+ pci_unregister_driver(&poulsbo_driver); +-+} +-+ +-+MODULE_AUTHOR("Jacob Pan "); +-+MODULE_DESCRIPTION("POULSBO SMBus driver"); +-+MODULE_LICENSE("GPL"); +-+ +-+module_init(i2c_poulsbo_init); +-+module_exit(i2c_poulsbo_exit); +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index c466c6c..85abf0a 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -239,6 +239,15 @@ config I2C_PIIX4 + This driver can also be built as a module. If so, the module + will be called i2c-piix4. + ++config I2C_POULSBO ++ tristate "Intel SCH (Poulsbo SMBUS 1.0)" ++ depends on I2C && PCI ++ help ++ If you say yes to this option, support will be included for the Intel ++ SCH ++ Intel POULSBO ++ will be called i2c-sch. ++ + config I2C_IBM_IIC + tristate "IBM PPC 4xx on-chip I2C interface" + depends on IBM_OCP +diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +index 81d43c2..ece538a 100644 +--- a/drivers/i2c/busses/Makefile ++++ b/drivers/i2c/busses/Makefile +@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o + obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o + obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o + obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o ++obj-$(CONFIG_I2C_POULSBO) += i2c-sch.o + obj-$(CONFIG_I2C_PNX) += i2c-pnx.o + obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o + obj-$(CONFIG_I2C_PXA) += i2c-pxa.o +diff --git a/drivers/i2c/busses/i2c-sch.c b/drivers/i2c/busses/i2c-sch.c +new file mode 100644 +index 0000000..10c0cad +--- /dev/null ++++ b/drivers/i2c/busses/i2c-sch.c +@@ -0,0 +1,393 @@ ++/* ++ i2c-sch.c - Part of lm_sensors, Linux kernel modules for hardware ++ monitoring ++ Based on piix4.c ++ Copyright (c) 1998 - 2002 Frodo Looijaard and ++ Philip Edelbrock ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++/* ++ Supports: ++ Intel POULSBO ++ ++ Note: we assume there can only be one device, with one SMBus interface. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++struct sd { ++ const unsigned short mfr; ++ const unsigned short dev; ++ const unsigned char fn; ++ const char *name; ++}; ++/* POULSBO SMBus address offsets */ ++#define SMBHSTCNT (0 + poulsbo_smba) ++#define SMBHSTSTS (1 + poulsbo_smba) ++#define SMBHSTADD (4 + poulsbo_smba) /* TSA */ ++#define SMBHSTCMD (5 + poulsbo_smba) ++#define SMBHSTDAT0 (6 + poulsbo_smba) ++#define SMBHSTDAT1 (7 + poulsbo_smba) ++#define SMBBLKDAT (0x20 + poulsbo_smba) ++ ++ ++/* count for request_region */ ++#define SMBIOSIZE 8 ++ ++/* PCI Address Constants */ ++#define SMBBA_SCH 0x040 ++ ++/* Other settings */ ++#define MAX_TIMEOUT 500 ++#define ENABLE_INT9 0 ++ ++/* POULSBO constants */ ++#define POULSBO_QUICK 0x00 ++#define POULSBO_BYTE 0x01 ++#define POULSBO_BYTE_DATA 0x02 ++#define POULSBO_WORD_DATA 0x03 ++#define POULSBO_BLOCK_DATA 0x05 ++ ++/* insmod parameters */ ++ ++/* If force is set to anything different from 0, we forcibly enable the ++ POULSBO. DANGEROUS! */ ++static int force; ++module_param (force, int, 0); ++MODULE_PARM_DESC(force, "Forcibly enable the POULSBO. DANGEROUS!"); ++ ++ ++static int poulsbo_transaction(void); ++ ++static unsigned short poulsbo_smba; ++static struct pci_driver poulsbo_driver; ++static struct i2c_adapter poulsbo_adapter; ++ ++ ++static int __devinit poulsbo_setup(struct pci_dev *POULSBO_dev, ++ const struct pci_device_id *id) ++{ ++ unsigned short smbase; ++ if(POULSBO_dev->device != PCI_DEVICE_ID_INTEL_POULSBO_LPC) { ++ /* match up the function */ ++ if (PCI_FUNC(POULSBO_dev->devfn) != id->driver_data) ++ return -ENODEV; ++ dev_info(&POULSBO_dev->dev, "Found %s device\n", pci_name(POULSBO_dev)); ++ } else { ++ dev_info(&POULSBO_dev->dev, "Found POULSBO SMBUS %s device\n", pci_name(POULSBO_dev)); ++ /* find SMBUS base address */ ++ pci_read_config_word(POULSBO_dev, 0x40, &smbase); ++ dev_info(&POULSBO_dev->dev, "POULSBO SM base = 0x%04x\n", smbase); ++ } ++ ++ ++ /* Determine the address of the SMBus areas */ ++ if(POULSBO_dev->device == PCI_DEVICE_ID_INTEL_POULSBO_LPC) ++ pci_read_config_word(POULSBO_dev, SMBBA_SCH, &poulsbo_smba); ++ else ++ poulsbo_smba=0; ++ ++ poulsbo_smba &= 0xfff0; ++ if(poulsbo_smba == 0) { ++ dev_err(&POULSBO_dev->dev, "SMB base address " ++ "uninitialized - upgrade BIOS or use " ++ "force_addr=0xaddr\n"); ++ return -ENODEV; ++ } ++ ++ if (!request_region(poulsbo_smba, SMBIOSIZE, poulsbo_driver.name)) { ++ dev_err(&POULSBO_dev->dev, "SMB region 0x%x already in use!\n", ++ poulsbo_smba); ++ return -ENODEV; ++ } ++ ++ dev_dbg(&POULSBO_dev->dev, "SMBA = 0x%X\n", poulsbo_smba); ++ ++ return 0; ++} ++ ++/* Another internally used function */ ++static int poulsbo_transaction(void) ++{ ++ int temp; ++ int result = 0; ++ int timeout = 0; ++ ++ dev_dbg(&poulsbo_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " ++ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), ++ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), ++ inb_p(SMBHSTDAT1)); ++ ++ /* Make sure the SMBus host is ready to start transmitting */ ++ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { ++ if(temp == 1) { ++ dev_dbg(&poulsbo_adapter.dev, "Completion (%02x). " ++ "clear...\n", temp); ++ outb_p(temp, SMBHSTSTS); ++ ++ } else if(temp & 0xe) { ++ dev_dbg(&poulsbo_adapter.dev, "SMBus error (%02x). " ++ "Resetting...\n", temp); ++ outb_p(temp, SMBHSTSTS); ++ } ++ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { ++ dev_err(&poulsbo_adapter.dev, "Failed! (%02x)\n", temp); ++ return -1; ++ } else { ++ dev_dbg(&poulsbo_adapter.dev, "Successfull!\n"); ++ } ++ } ++ ++ /* start the transaction by setting bit 4 */ ++ outb_p(inb(SMBHSTCNT) | 0x10, SMBHSTCNT); ++ ++ /* We will always wait for a fraction of a second! (See POULSBO docs errata) */ ++ do { ++ msleep(1); ++ temp = inb_p(SMBHSTSTS); ++ } while ((temp & 0x08) && (timeout++ < MAX_TIMEOUT)); ++ ++ /* If the SMBus is still busy, we give up */ ++ if (timeout >= MAX_TIMEOUT) { ++ dev_err(&poulsbo_adapter.dev, "SMBus Timeout!\n"); ++ result = -1; ++ } ++ ++ if (temp & 0x10) { ++ result = -1; ++ dev_err(&poulsbo_adapter.dev, "Error: Failed bus transaction\n"); ++ } ++ ++ if (temp & 0x08) { ++ result = -1; ++ dev_dbg(&poulsbo_adapter.dev, "Bus collision! SMBus may be " ++ "locked until next hard reset. (sorry!)\n"); ++ /* Clock stops and slave is stuck in mid-transmission */ ++ } ++ ++ if (temp & 0x04) { ++ result = -1; ++ dev_dbg(&poulsbo_adapter.dev, "Error: no response!\n"); ++ } ++ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { ++ if( temp == 0x1) { ++ dev_dbg(&poulsbo_adapter.dev, "post complete!\n"); ++ outb_p(temp, SMBHSTSTS); ++ } ++ else if(temp & 0xe) { ++ dev_dbg(&poulsbo_adapter.dev, "Error: bus, etc!\n"); ++ outb_p(inb(SMBHSTSTS), SMBHSTSTS); ++ } ++ } ++ msleep(1); ++ if ((temp = inb_p(SMBHSTSTS)) & 0xe) { ++ /* BSY, device or bus error */ ++ dev_err(&poulsbo_adapter.dev, "Failed reset at end of " ++ "transaction (%02x), Bus error\n", temp); ++ } ++ dev_dbg(&poulsbo_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " ++ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), ++ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), ++ inb_p(SMBHSTDAT1)); ++ return result; ++} ++ ++/* Return -1 on error. */ ++static s32 poulsbo_access(struct i2c_adapter * adap, u16 addr, ++ unsigned short flags, char read_write, ++ u8 command, int size, union i2c_smbus_data * data) ++{ ++ int i, len; ++ dev_dbg(&poulsbo_adapter.dev,"access size: %d %s\n", size, (read_write)?"READ":"WRITE"); ++ switch (size) { ++ case I2C_SMBUS_PROC_CALL: ++ dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); ++ return -1; ++ case I2C_SMBUS_QUICK: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD); ++ size = POULSBO_QUICK; ++ break; ++ case I2C_SMBUS_BYTE: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD); ++ if (read_write == I2C_SMBUS_WRITE) ++ outb_p(command, SMBHSTCMD); ++ size = POULSBO_BYTE; ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD); ++ outb_p(command, SMBHSTCMD); ++ if (read_write == I2C_SMBUS_WRITE) ++ outb_p(data->byte, SMBHSTDAT0); ++ size = POULSBO_BYTE_DATA; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD); ++ outb_p(command, SMBHSTCMD); ++ if (read_write == I2C_SMBUS_WRITE) { ++ outb_p(data->word & 0xff, SMBHSTDAT0); ++ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); ++ } ++ size = POULSBO_WORD_DATA; ++ break; ++ case I2C_SMBUS_BLOCK_DATA: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD); ++ outb_p(command, SMBHSTCMD); ++ if (read_write == I2C_SMBUS_WRITE) { ++ len = data->block[0]; ++ if (len < 0) ++ len = 0; ++ if (len > 32) ++ len = 32; ++ outb_p(len, SMBHSTDAT0); ++ i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ ++ for (i = 1; i <= len; i++) ++ outb_p(data->block[i], SMBBLKDAT); ++ } ++ size = POULSBO_BLOCK_DATA; ++ break; ++ } ++ dev_dbg(&poulsbo_adapter.dev,"write size %d to 0x%04x\n", size, SMBHSTCNT); ++ outb_p((size & 0x7), SMBHSTCNT); ++ ++ if (poulsbo_transaction()) /* Error in transaction */ ++ return -1; ++ ++ if ((read_write == I2C_SMBUS_WRITE) || (size == POULSBO_QUICK)) ++ return 0; ++ ++ ++ switch (size) { ++ case POULSBO_BYTE: /* Where is the result put? I assume here it is in ++ SMBHSTDAT0 but it might just as well be in the ++ SMBHSTCMD. No clue in the docs */ ++ ++ data->byte = inb_p(SMBHSTDAT0); ++ break; ++ case POULSBO_BYTE_DATA: ++ data->byte = inb_p(SMBHSTDAT0); ++ break; ++ case POULSBO_WORD_DATA: ++ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); ++ break; ++ case POULSBO_BLOCK_DATA: ++ data->block[0] = inb_p(SMBHSTDAT0); ++ i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ ++ for (i = 1; i <= data->block[0]; i++) ++ data->block[i] = inb_p(SMBBLKDAT); ++ break; ++ } ++ return 0; ++} ++ ++static u32 poulsbo_func(struct i2c_adapter *adapter) ++{ ++ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | ++ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | ++ I2C_FUNC_SMBUS_BLOCK_DATA; ++} ++ ++static const struct i2c_algorithm smbus_algorithm = { ++ .smbus_xfer = poulsbo_access, ++ .functionality = poulsbo_func, ++}; ++ ++static struct i2c_adapter poulsbo_adapter = { ++ .owner = THIS_MODULE, ++ .class = I2C_CLASS_HWMON, ++ .algo = &smbus_algorithm, ++}; ++ ++static struct pci_device_id poulsbo_ids[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_POULSBO_LPC), ++ .driver_data = 0xf8 }, ++ { 0, } ++}; ++ ++MODULE_DEVICE_TABLE (pci, poulsbo_ids); ++ ++static int __devinit poulsbo_probe(struct pci_dev *dev, ++ const struct pci_device_id *id) ++{ ++ int retval; ++ retval = poulsbo_setup(dev, id); ++ if (retval) ++ return retval; ++ ++ /* set up the driverfs linkage to our parent device */ ++ poulsbo_adapter.dev.parent = &dev->dev; ++ ++ snprintf(poulsbo_adapter.name, I2C_NAME_SIZE, ++ "SMBus POULSBO adapter at %04x", poulsbo_smba); ++ ++ if ((retval = i2c_add_adapter(&poulsbo_adapter))) { ++ dev_err(&dev->dev, "Couldn't register adapter!\n"); ++ release_region(poulsbo_smba, SMBIOSIZE); ++ poulsbo_smba = 0; ++ } ++ ++ return retval; ++} ++ ++static void __devexit poulsbo_remove(struct pci_dev *dev) ++{ ++ if (poulsbo_smba) { ++ i2c_del_adapter(&poulsbo_adapter); ++ release_region(poulsbo_smba, SMBIOSIZE); ++ poulsbo_smba = 0; ++ } ++} ++ ++static struct pci_driver poulsbo_driver = { ++ .name = "poulsbo_smbus", ++ .id_table = poulsbo_ids, ++ .probe = poulsbo_probe, ++ .remove = __devexit_p(poulsbo_remove), ++}; ++ ++static int __init i2c_poulsbo_init(void) ++{ ++ return pci_register_driver(&poulsbo_driver); ++} ++ ++static void __exit i2c_poulsbo_exit(void) ++{ ++ pci_unregister_driver(&poulsbo_driver); ++} ++ ++MODULE_AUTHOR("Jacob Pan "); ++MODULE_DESCRIPTION("POULSBO SMBus driver"); ++MODULE_LICENSE("GPL"); ++ ++module_init(i2c_poulsbo_init); ++module_exit(i2c_poulsbo_exit); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0105-UBUNTU-V4L-DVB-9039-Add-support-for-new-i2c-API-prov.patch +++ linux-2.6.24/patches/0105-UBUNTU-V4L-DVB-9039-Add-support-for-new-i2c-API-prov.patch @@ -0,0 +1,200 @@ +From 17639f2910d4ae8c62bdee5ddab5392af36d90a5 Mon Sep 17 00:00:00 2001 +From: Devin Heitmueller +Date: Sat, 6 Sep 2008 13:45:27 -0300 +Subject: [PATCH 105/170] UBUNTU: V4L/DVB (9039): Add support for new i2c API provided in firmware version 1.20 + +The Pinnacle PCTV HD Pro has an xc5000, which exposed a bug in the dib0700's +i2c implementation where it did not properly support a single i2c read request +(sending it as an i2c write request instead). Version 1.20 of the firmware +added support for a new i2c API which supported such requests. + +This change defaults to fw 1.20 for all devices, but does not default to using +the new i2c API (since initial testing suggests problems interacting with the +mt2060). Maintainers can enable the use of the new i2c API by putting +the following into their frontend initialization: + +struct dib0700_state *st = adap->dev->priv; +st->fw_use_new_i2c_api = 1; + +Also note that the code expects i2c repeated start to be supported. If the +i2c slave does not support repeated start, i2c messsages should have the +I2C_M_NOSTART flag set. + +Thanks to Patrick Boettcher for providing new +firmware fixing the issue as well as example i2c code utilizing the interface. + +Signed-off-by: Devin Heitmueller +Signed-off-by: Patrick Boettcher +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Michael Krufky +(cherry picked from commit bdc203e156ce938e12d957912bd29ca53d160540) +--- + drivers/media/dvb/dvb-usb/dib0700.h | 3 + + drivers/media/dvb/dvb-usb/dib0700_core.c | 108 ++++++++++++++++++++++++++- + drivers/media/dvb/dvb-usb/dib0700_devices.c | 2 +- + 3 files changed, 110 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h +index 4a903ea..c84e12d 100644 +--- a/drivers/media/dvb/dvb-usb/dib0700.h ++++ b/drivers/media/dvb/dvb-usb/dib0700.h +@@ -31,6 +31,8 @@ extern int dvb_usb_dib0700_debug; + // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) + // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) + #define REQUEST_SET_RC 0x11 ++#define REQUEST_NEW_I2C_READ 0x12 ++#define REQUEST_NEW_I2C_WRITE 0x13 + #define REQUEST_GET_VERSION 0x15 + + struct dib0700_state { +@@ -38,6 +40,7 @@ struct dib0700_state { + u16 mt2060_if1[2]; + u8 rc_toggle; + u8 is_dib7000pc; ++ u8 fw_use_new_i2c_api; + }; + + extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); +diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c +index c9857d5..52363d2 100644 +--- a/drivers/media/dvb/dvb-usb/dib0700_core.c ++++ b/drivers/media/dvb/dvb-usb/dib0700_core.c +@@ -80,9 +80,98 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ + } + + /* +- * I2C master xfer function ++ * I2C master xfer function (supported in 1.20 firmware) + */ +-static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num) ++static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, ++ int num) ++{ ++ /* The new i2c firmware messages are more reliable and in particular ++ properly support i2c read calls not preceded by a write */ ++ ++ struct dvb_usb_device *d = i2c_get_adapdata(adap); ++ uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */ ++ uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */ ++ uint8_t en_start = 0; ++ uint8_t en_stop = 0; ++ uint8_t buf[255]; /* TBV: malloc ? */ ++ int result, i; ++ ++ /* Ensure nobody else hits the i2c bus while we're sending our ++ sequence of messages, (such as the remote control thread) */ ++ if (mutex_lock_interruptible(&d->i2c_mutex) < 0) ++ return -EAGAIN; ++ ++ for (i = 0; i < num; i++) { ++ if (i == 0) { ++ /* First message in the transaction */ ++ en_start = 1; ++ } else if (!(msg[i].flags & I2C_M_NOSTART)) { ++ /* Device supports repeated-start */ ++ en_start = 1; ++ } else { ++ /* Not the first packet and device doesn't support ++ repeated start */ ++ en_start = 0; ++ } ++ if (i == (num - 1)) { ++ /* Last message in the transaction */ ++ en_stop = 1; ++ } ++ ++ if (msg[i].flags & I2C_M_RD) { ++ /* Read request */ ++ u16 index, value; ++ uint8_t i2c_dest; ++ ++ i2c_dest = (msg[i].addr << 1); ++ value = ((en_start << 7) | (en_stop << 6) | ++ (msg[i].len & 0x3F)) << 8 | i2c_dest; ++ /* I2C ctrl + FE bus; */ ++ index = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30); ++ ++ result = usb_control_msg(d->udev, ++ usb_rcvctrlpipe(d->udev, 0), ++ REQUEST_NEW_I2C_READ, ++ USB_TYPE_VENDOR | USB_DIR_IN, ++ value, index, msg[i].buf, ++ msg[i].len, ++ USB_CTRL_GET_TIMEOUT); ++ if (result < 0) { ++ err("i2c read error (status = %d)\n", result); ++ break; ++ } ++ } else { ++ /* Write request */ ++ buf[0] = REQUEST_NEW_I2C_WRITE; ++ buf[1] = (msg[i].addr << 1); ++ buf[2] = (en_start << 7) | (en_stop << 6) | ++ (msg[i].len & 0x3F); ++ /* I2C ctrl + FE bus; */ ++ buf[3] = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30); ++ /* The Actual i2c payload */ ++ memcpy(&buf[4], msg[i].buf, msg[i].len); ++ ++ result = usb_control_msg(d->udev, ++ usb_sndctrlpipe(d->udev, 0), ++ REQUEST_NEW_I2C_WRITE, ++ USB_TYPE_VENDOR | USB_DIR_OUT, ++ 0, 0, buf, msg[i].len + 4, ++ USB_CTRL_GET_TIMEOUT); ++ if (result < 0) { ++ err("i2c write error (status = %d)\n", result); ++ break; ++ } ++ } ++ } ++ mutex_unlock(&d->i2c_mutex); ++ return i; ++} ++ ++/* ++ * I2C master xfer function (pre-1.20 firmware) ++ */ ++static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, ++ struct i2c_msg *msg, int num) + { + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i,len; +@@ -122,6 +211,21 @@ static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num + return i; + } + ++static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, ++ int num) ++{ ++ struct dvb_usb_device *d = i2c_get_adapdata(adap); ++ struct dib0700_state *st = d->priv; ++ ++ if (st->fw_use_new_i2c_api == 1) { ++ /* User running at least fw 1.20 */ ++ return dib0700_i2c_xfer_new(adap, msg, num); ++ } else { ++ /* Use legacy calls */ ++ return dib0700_i2c_xfer_legacy(adap, msg, num); ++ } ++} ++ + static u32 dib0700_i2c_func(struct i2c_adapter *adapter) + { + return I2C_FUNC_I2C; +diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c +index 5144f25..b1d1461 100644 +--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c ++++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c +@@ -856,7 +856,7 @@ MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); + #define DIB0700_DEFAULT_DEVICE_PROPERTIES \ + .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ + .usb_ctrl = DEVICE_SPECIFIC, \ +- .firmware = "dvb-usb-dib0700-1.10.fw", \ ++ .firmware = "dvb-usb-dib0700-1.20.fw", \ + .download_firmware = dib0700_download_firmware, \ + .no_reconnect = 1, \ + .size_of_priv = sizeof(struct dib0700_state), \ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0139-l2cap-info_timer-delete-fix-in-hci_conn_del.patch +++ linux-2.6.24/patches/0139-l2cap-info_timer-delete-fix-in-hci_conn_del.patch @@ -0,0 +1,37 @@ +From 3311063370d6b69dfe9ae6ff688758e7d296b444 Mon Sep 17 00:00:00 2001 +From: Dave Young +Date: Mon, 20 Apr 2009 15:59:05 -0400 +Subject: [PATCH 139/170] l2cap info_timer delete fix in hci_conn_del + +When the l2cap info_timer is active the info_state will be set to +L2CAP_INFO_FEAT_MASK_REQ_SENT, and it will be unset after the timer is +deleted or timeout triggered. + +Here in l2cap_conn_del only call del_timer_sync when the info_state is +set to L2CAP_INFO_FEAT_MASK_REQ_SENT. + +Signed-off-by: Dave Young +Acked-by: Marcel Holtmann +Signed-off-by: David S. Miller +Signed-off-by: Andres Salomon +--- + net/bluetooth/l2cap.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c +index e165c9b..e4b5d62 100644 +--- a/net/bluetooth/l2cap.c ++++ b/net/bluetooth/l2cap.c +@@ -426,7 +426,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) + l2cap_sock_kill(sk); + } + +- del_timer_sync(&conn->info_timer); ++ if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) ++ del_timer_sync(&conn->info_timer); + + hcon->l2cap_data = NULL; + kfree(conn); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0072-Clear-IRQ-bit-when-drivers-are-unloaded.-Part-Fix-fo.patch +++ linux-2.6.24/patches/0072-Clear-IRQ-bit-when-drivers-are-unloaded.-Part-Fix-fo.patch @@ -0,0 +1,36 @@ +From 823cbaf45dc76444e701be134b247f99e9d5699c Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Mon, 3 Nov 2008 09:36:24 -0500 +Subject: [PATCH 072/170] Clear IRQ bit when drivers are unloaded. Part Fix for LP#243047 + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/243047 +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + arch/x86/kernel/io_apic_32.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c +index 8ab5252..6685f9e 100644 +--- a/arch/x86/kernel/io_apic_32.c ++++ b/arch/x86/kernel/io_apic_32.c +@@ -2309,6 +2309,9 @@ void __init setup_IO_APIC(void) + /* Mark FIRST_DEVICE_VECTOR which is assigned to IRQ0 as used. */ + set_bit(FIRST_DEVICE_VECTOR, used_vectors); + ++ /* Mark FIRST_DEVICE_VECTOR which is assigned to IRQ0 as used. */ ++ set_bit(FIRST_DEVICE_VECTOR, used_vectors); ++ + enable_IO_APIC(); + + if (acpi_ioapic) +@@ -2472,6 +2475,7 @@ int create_irq(void) + dynamic_irq_init(irq); + } + return irq; ++ clear_bit(irq_vector[irq], used_vectors); + } + + void destroy_irq(unsigned int irq) +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0008-kgdb-light-v10-fix-kgdboc-dynamic-module-configurati.patch +++ linux-2.6.24/patches/0008-kgdb-light-v10-fix-kgdboc-dynamic-module-configurati.patch @@ -0,0 +1,43 @@ +From cd01e6e329bd28d19de8e3e4abdff17a6436f162 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 15 Feb 2008 14:55:52 -0600 +Subject: [PATCH 008/170] kgdb-light-v10: fix kgdboc dynamic module configuration + +Fix the run time configuration of kgdboc such that it does not default +to 9600 baud if you use the "echo" command to configure the sysfs +module paramater. + +Signed-off-by: Jason Wessel +Signed-off-by: Ingo Molnar +--- + drivers/serial/kgdboc.c | 7 ++++++- + 1 files changed, 6 insertions(+), 1 deletions(-) + +diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c +index 3418307..9cf0332 100644 +--- a/drivers/serial/kgdboc.c ++++ b/drivers/serial/kgdboc.c +@@ -106,7 +106,9 @@ static void kgdboc_put_char(u8 chr) + + static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) + { +- if (strlen(kmessage) >= MAX_CONFIG_LEN) { ++ int len = strlen(kmessage); ++ ++ if (len >= MAX_CONFIG_LEN) { + printk(KERN_ERR "kgdboc: config string too long\n"); + return -ENOSPC; + } +@@ -125,6 +127,9 @@ static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) + } + + strcpy(config, kmessage); ++ /* Chop out \n char as a result of echo */ ++ if (config[len - 1] == '\n') ++ config[len - 1] = '\0'; + + if (configured == 1) + cleanup_kgdboc(); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0043-Turn-on-Memory-Stick-driver.patch +++ linux-2.6.24/patches/0043-Turn-on-Memory-Stick-driver.patch @@ -0,0 +1,25 @@ +From 21cbc7fcfc339212fa42bcd5a323d944f789d648 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 15 Jul 2008 13:57:11 +0100 +Subject: [PATCH 043/170] Turn on Memory Stick driver + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/binary-custom.d/lpia/config.lpia | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/debian/binary-custom.d/lpia/config.lpia b/debian/binary-custom.d/lpia/config.lpia +index 2cd1e76..70e3ca9 100644 +--- a/debian/binary-custom.d/lpia/config.lpia ++++ b/debian/binary-custom.d/lpia/config.lpia +@@ -2821,6 +2821,7 @@ CONFIG_MMC_SDHCI=y + # CONFIG_MMC_TIFM_SD is not set + # CONFIG_MMC_SPI is not set + # CONFIG_MSS is not set ++CONFIG_MSPRO=y + CONFIG_NEW_LEDS=y + CONFIG_LEDS_CLASS=m + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0021-kgdb-documentation-fixes.patch +++ linux-2.6.24/patches/0021-kgdb-documentation-fixes.patch @@ -0,0 +1,167 @@ +From cacc3fa0a403faa3f79c64cb1785148de5be0a95 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:45 -0500 +Subject: [PATCH 021/170] kgdb: documentation fixes + +Minor cleanups to kgdb docs. + +Signed-off-by: Jason Wessel +--- + Documentation/DocBook/kgdb.tmpl | 104 ++++++++++++++++++++++----------------- + 1 files changed, 58 insertions(+), 46 deletions(-) + +diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl +index 95e5f84..97618be 100644 +--- a/Documentation/DocBook/kgdb.tmpl ++++ b/Documentation/DocBook/kgdb.tmpl +@@ -152,9 +152,10 @@ + + The kgdboc driver was originally an abbreviation meant to stand for + "kgdb over console". Kgdboc is designed to work with a single +- serial port as example, and it was meant to cover the circumstance ++ serial port. It was meant to cover the circumstance + where you wanted to use a serial console as your primary console as +- well as using it to perform kernel debugging. ++ well as using it to perform kernel debugging. Of course you can ++ also use kgdboc without assigning a console to the same port. + + + Using kgdboc +@@ -195,37 +196,6 @@ + unmodified gdb to do the debugging. + + +- +- kgdboc internals +- +- The kgdboc driver is actually a very thin driver that relies on the +- underlying low level to the hardware driver having "polling hooks" +- which the to which the tty driver is attached. In the initial +- implementation of kgdboc it the serial_core was changed to expose a +- low level uart hook for doing polled mode reading and writing of a +- single character while in an atomic context. When kgdb makes an I/O +- request to the debugger, kgdboc invokes a call back in the serial +- core which in turn uses the call back in the uart driver. It is +- certainly possible to extend kgdboc to work with non-uart based +- consoles in the future. +- +- +- When using kgdboc with a uart, the uart driver must implement two callbacks in the struct uart_ops. Example from drivers/8250.c: +-#ifdef CONFIG_CONSOLE_POLL +- .poll_get_char = serial8250_get_poll_char, +- .poll_put_char = serial8250_put_poll_char, +-#endif +- +- Any implementation specifics around creating a polling driver use the +- #ifdef CONFIG_CONSOLE_POLL, as shown above. +- Keep in mind that polling hooks have to be implemented in such a way +- that they can be called from an atomic context and have to restore +- the state of the uart chip on return such that the system can return +- to normal when the debugger detaches. You need to be very careful +- with any kind of lock you consider, because failing here is most +- going to mean pressing the reset button. +- +- + + + Kernel parameter: kgdbcon +@@ -327,6 +297,8 @@ + + + ++ KGDB Internals ++ + Architecture Specifics + + Kgdb is organized into three basic components: +@@ -365,18 +337,23 @@ + + kgdb I/O driver + +- Each kgdb I/O driver has to provide an configuration +- initialization, and cleanup handler for when it +- unloads/unconfigures. Any given kgdb I/O driver has to operate +- very closely with the hardware and must do it in such a way that +- does not enable interrupts or change other parts of the system +- context without completely restoring them. Every kgdb I/O +- driver must provide a read and write character interface. The +- kgdb core will repeatedly "poll" a kgdb I/O driver for characters +- when it needs input. The I/O driver is expected to return +- immediately if there is no data available. Doing so allows for +- the future possibility to touch watch dog hardware in such a way +- as to have a target system not reset when these are enabled. ++ Each kgdb I/O driver has to provide an implemenation for the following: ++ ++ configuration via builtin or module ++ dynamic configuration and kgdb hook registration calls ++ read and write character interface ++ A cleanup handler for unconfiguring from the kgdb core ++ (optional) Early debug methodology ++ ++ Any given kgdb I/O driver has to operate very closely with the ++ hardware and must do it in such a way that does not enable ++ interrupts or change other parts of the system context without ++ completely restoring them. The kgdb core will repeatedly "poll" ++ a kgdb I/O driver for characters when it needs input. The I/O ++ driver is expected to return immediately if there is no data ++ available. Doing so allows for the future possibility to touch ++ watch dog hardware in such a way as to have a target system not ++ reset when these are enabled. + + + +@@ -419,6 +396,38 @@ + does not need to provide a specific implementation. + + !Iinclude/linux/kgdb.h ++ ++ ++ kgdboc internals ++ ++ The kgdboc driver is actually a very thin driver that relies on the ++ underlying low level to the hardware driver having "polling hooks" ++ which the to which the tty driver is attached. In the initial ++ implementation of kgdboc it the serial_core was changed to expose a ++ low level uart hook for doing polled mode reading and writing of a ++ single character while in an atomic context. When kgdb makes an I/O ++ request to the debugger, kgdboc invokes a call back in the serial ++ core which in turn uses the call back in the uart driver. It is ++ certainly possible to extend kgdboc to work with non-uart based ++ consoles in the future. ++ ++ ++ When using kgdboc with a uart, the uart driver must implement two callbacks in the struct uart_ops. Example from drivers/8250.c: ++#ifdef CONFIG_CONSOLE_POLL ++ .poll_get_char = serial8250_get_poll_char, ++ .poll_put_char = serial8250_put_poll_char, ++#endif ++ ++ Any implementation specifics around creating a polling driver use the ++ #ifdef CONFIG_CONSOLE_POLL, as shown above. ++ Keep in mind that polling hooks have to be implemented in such a way ++ that they can be called from an atomic context and have to restore ++ the state of the uart chip on return such that the system can return ++ to normal when the debugger detaches. You need to be very careful ++ with any kind of lock you consider, because failing here is most ++ going to mean pressing the reset button. ++ ++ + + + Credits +@@ -427,8 +436,11 @@ + + Amit Kaleamitkale@linsyssoft.com + Tom Rinitrini@kernel.crashing.org +- Jason Wesseljason.wessel@windriver.com + ++ In March 2008 this document was completely rewritten by: ++ ++ Jason Wesseljason.wessel@windriver.com ++ + + + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0066-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook6.patch +++ linux-2.6.24/patches/0066-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook6.patch @@ -0,0 +1,32 @@ +From 5f7cb6f81f6df86b488d0ae404b9cc8f39ec40ec Mon Sep 17 00:00:00 2001 +From: Tony Espy +Date: Thu, 16 Oct 2008 12:51:30 -0400 +Subject: [PATCH 066/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook6 + +Ignore: yes +Signed-off-by: Tony Espy +--- + debian/changelog | 10 ++++++++++ + 1 files changed, 10 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 2de5640..5a0e217 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,13 @@ ++linux (2.6.24-19.41netbook6) hardy; urgency=low ++ ++ [Upstream Kernel Changes] ++ ++ * ACPI: Remove extraneous inb() call from EC read. ++ * ACPI: Do the EC byte access with a fast path ++ * ACPI: EC: Some hardware requires burst mode to operate properly ++ ++ -- Tony Espy Thu, 16 Oct 2008 16:40:55 +0000 ++ + linux (2.6.24-19.41netbook5) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0158-UBUNTU-rebase-onto-Ubuntu-2.6.24-24.57.patch +++ linux-2.6.24/patches/0158-UBUNTU-rebase-onto-Ubuntu-2.6.24-24.57.patch @@ -0,0 +1,79 @@ +From 5ddac608a4df81d3d76c26e785f2406087a8774e Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Tue, 28 Jul 2009 16:53:16 +0100 +Subject: [PATCH 158/170] UBUNTU: rebase onto Ubuntu-2.6.24-24.57 + +Signed-off-by: Andy Whitcroft +--- + debian/changelog | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 files changed, 52 insertions(+), 1 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 0c6e97e..f4af58c 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,9 +1,60 @@ +-linux (2.6.24-24.54netbook03) UNRELEASED; urgency=low ++linux (2.6.24-24.57netbook01) UNRELEASED; urgency=low + + CHANGELOG: Do not edit directly. Autogenerated at release. + CHANGELOG: Use the printchanges target to see the curent changes. + CHANGELOG: Use the insertchanges target to create the final log. + ++ [ Ubuntu Kernel Changes ] ++ ++ * cifs: backport buffer size fixes for CIFSGetDFSRefer() ++ - CVE-2009-1633 ++ * OPENVZ: Fixup for 'kill sig -1' must only apply to caller's namespace ++ - CVE-2009-1338 ++ * Ubuntu-2.6.24-24.55 ++ * Ubuntu-2.6.24-24.56 ++ * Ubuntu-2.6.24-24.57 ++ * nfsd: nfsd should drop CAP_MKNOD for non-root ++ - CVE-2009-1072 ++ * KVM: VMX: Don't allow uninhibited access to EFER on i386 ++ - CVE-2009-1242 ++ * exit_notify: kill the wrong capable(CAP_KILL) check ++ - CVE-2009-1337 ++ * e1000: add missing length check to e1000 receive routine ++ - CVE-2009-1385 ++ * Fix memory overwrite when saving nativeFileSystem field during mount ++ - CVE-2009-1439 ++ * cifs: Increase size of tmp_buf in cifs_readdir to avoid potential ++ overflows ++ - CVE-2009-1633 ++ * cifs: fix unicode string area word alignment in session setup ++ - CVE-2009-1633 ++ * sparc64: Fix crash with /proc/iomem ++ - CVE-2009-1914 ++ * splice: fix deadlock in splicing to file ++ - CVE-2009-1961 ++ * agp: zero pages before sending to userspace ++ - CVE-2009-1192 ++ * af_rose/x25: Sanity check the maximum user frame size ++ - CVE-2009-1265 ++ * 'kill sig -1' must only apply to caller's namespace ++ - CVE-2009-1338 ++ * nfs: Fix NFS v4 client handling of MAY_EXEC in nfs_permission. ++ - CVE-2009-1630 ++ * Add '-fno-delete-null-pointer-checks' to gcc CFLAGS ++ - LP: #403647 ++ * personality: fix PER_CLEAR_ON_SETID ++ - CVE-2009-1895 ++ * KVM: detect if VCPU triple faults ++ - CVE-2009-2287 ++ * KVM: x86: check for cr3 validity in ioctl_set_sregs ++ - CVE-2009-2287 ++ * r8169: fix crash when large packets are received ++ - CVE-2009-1389 ++ * eCryptfs: Check Tag 11 literal data buffer size ++ - CVE-2009-2406 ++ * eCryptfs: parse_tag_3_packet check tag 3 packet encrypted key size ++ - CVE-2009-2407 ++ + -- Andy Whitcroft Tue, 28 Jul 2009 16:51:16 +0100 + + linux (2.6.24-24.54netbook02) netbook-common; urgency=low +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0149-UBUNTU-NBK-Ubuntu-2.6.24-24.51netbook14.patch +++ linux-2.6.24/patches/0149-UBUNTU-NBK-Ubuntu-2.6.24-24.51netbook14.patch @@ -0,0 +1,27 @@ +From b4942871b9f730002878662e1b3b65a4a661f4a7 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Tue, 5 May 2009 15:40:46 -0500 +Subject: [PATCH 149/170] UBUNTU: NBK-Ubuntu-2.6.24-24.51netbook14 + +Signed-off-by: Steve Conklin +--- + debian/changelog | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 1c6e5d1..495f96b 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,9 @@ ++linux (2.6.24-24.51netbook14) netbook-common; urgency=low ++ ++ * Incorporate minor change to not rename debug debs ++ ++ -- Steve Conklin Tue, 05 May 2009 20:37:38 +0000 ++ + linux (2.6.24-24.51netbook13) netbook-common; urgency=low + + [Jim Lieb] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0003-uaccess-add-probe_kernel_write.patch +++ linux-2.6.24/patches/0003-uaccess-add-probe_kernel_write.patch @@ -0,0 +1,122 @@ +From c37756fb20317876bdb01244dd6ed88cb1f6b979 Mon Sep 17 00:00:00 2001 +From: Ingo Molnar +Date: Mon, 10 Mar 2008 08:41:27 +0100 +Subject: [PATCH 003/170] uaccess: add probe_kernel_write() + +add probe_kernel_read() and probe_kernel_write(). + +Uninlined and restricted to kernel range memory only, as suggested +by Linus. + +Signed-off-by: Ingo Molnar +Reviewed-by: Thomas Gleixner +Signed-off-by: Jason Wessel +--- + include/linux/uaccess.h | 22 +++++++++++++++++++++ + mm/Makefile | 2 +- + mm/maccess.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 72 insertions(+), 1 deletions(-) + create mode 100644 mm/maccess.c + +diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h +index 975c963..fec6dec 100644 +--- a/include/linux/uaccess.h ++++ b/include/linux/uaccess.h +@@ -84,4 +84,26 @@ static inline unsigned long __copy_from_user_nocache(void *to, + ret; \ + }) + ++/* ++ * probe_kernel_read(): safely attempt to read from a location ++ * @dst: pointer to the buffer that shall take the data ++ * @src: address to read from ++ * @size: size of the data chunk ++ * ++ * Safely read from address @src to the buffer at @dst. If a kernel fault ++ * happens, handle that and return -EFAULT. ++ */ ++extern long probe_kernel_read(void *dst, void *src, size_t size); ++ ++/* ++ * probe_kernel_write(): safely attempt to write to a location ++ * @dst: address to write to ++ * @src: pointer to the data that shall be written ++ * @size: size of the data chunk ++ * ++ * Safely write to address @dst from the buffer at @src. If a kernel fault ++ * happens, handle that and return -EFAULT. ++ */ ++extern long probe_kernel_write(void *dst, void *src, size_t size); ++ + #endif /* __LINUX_UACCESS_H__ */ +diff --git a/mm/Makefile b/mm/Makefile +index 5c0b0ea..00fdd8f 100644 +--- a/mm/Makefile ++++ b/mm/Makefile +@@ -8,7 +8,7 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \ + vmalloc.o + + obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ +- page_alloc.o page-writeback.o pdflush.o \ ++ maccess.o page_alloc.o page-writeback.o pdflush.o \ + readahead.o swap.o truncate.o vmscan.o \ + prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \ + page_isolation.o $(mmu-y) +diff --git a/mm/maccess.c b/mm/maccess.c +new file mode 100644 +index 0000000..24f81b9 +--- /dev/null ++++ b/mm/maccess.c +@@ -0,0 +1,49 @@ ++/* ++ * Access kernel memory without faulting. ++ */ ++#include ++#include ++#include ++ ++/** ++ * probe_kernel_read(): safely attempt to read from a location ++ * @dst: pointer to the buffer that shall take the data ++ * @src: address to read from ++ * @size: size of the data chunk ++ * ++ * Safely read from address @src to the buffer at @dst. If a kernel fault ++ * happens, handle that and return -EFAULT. ++ */ ++long probe_kernel_read(void *dst, void *src, size_t size) ++{ ++ long ret; ++ ++ pagefault_disable(); ++ ret = __copy_from_user_inatomic(dst, ++ (__force const void __user *)src, size); ++ pagefault_enable(); ++ ++ return ret ? -EFAULT : 0; ++} ++EXPORT_SYMBOL_GPL(probe_kernel_read); ++ ++/** ++ * probe_kernel_write(): safely attempt to write to a location ++ * @dst: address to write to ++ * @src: pointer to the data that shall be written ++ * @size: size of the data chunk ++ * ++ * Safely write to address @dst from the buffer at @src. If a kernel fault ++ * happens, handle that and return -EFAULT. ++ */ ++long probe_kernel_write(void *dst, void *src, size_t size) ++{ ++ long ret; ++ ++ pagefault_disable(); ++ ret = __copy_to_user_inatomic((__force void __user *)dst, src, size); ++ pagefault_enable(); ++ ++ return ret ? -EFAULT : 0; ++} ++EXPORT_SYMBOL_GPL(probe_kernel_write); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0121-Turn-debian-binary-custom.d-lpia-patchset-0016-pouls.patch +++ linux-2.6.24/patches/0121-Turn-debian-binary-custom.d-lpia-patchset-0016-pouls.patch @@ -0,0 +1,168 @@ +From bc38d3722062184a9729be3fef2b1d450bf05e8a Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:33 +0100 +Subject: [PATCH 121/170] Turn debian/binary-custom.d/lpia/patchset/0016-poulsbo_ide.patch into a commit. + +Signed-off-by: Andy Whitcroft + +commit bd9f0e56edabc239ce41867ff8ea77ccdc4d0741 +Author: Jay Chetty +Date: Fri Feb 8 11:23:22 2008 -0800 + + UBUNTU:moblin:Integrated moblin patches & rebased with ubuntu-hardy + + * Added patch to fix legacy USB interrupt issue + * Enabled Poulsbo PATA udma5 support + * Add touchscreen doubleclick workaround + + Signed-off-by: Jay Chetty + Signed-off-by: Amit Kucheria + +commit 4883c50b37f2e791e29f545766e53ac456576926 +Author: Amit Kucheria +Date: Fri Jan 11 13:59:04 2008 +0200 + + UBUNTU: Poulsbo: Mass update of patches to be identical to those on moblin + + Sigh, we need better communication... + + Signed-off-by: Amit Kucheria +--- + .../lpia/patchset/0016-poulsbo_ide.patch | 62 -------------------- + drivers/ata/ata_piix.c | 16 +++++- + drivers/ide/pci/piix.c | 2 + + 3 files changed, 16 insertions(+), 64 deletions(-) + delete mode 100644 debian/binary-custom.d/lpia/patchset/0016-poulsbo_ide.patch + +diff --git a/debian/binary-custom.d/lpia/patchset/0016-poulsbo_ide.patch b/debian/binary-custom.d/lpia/patchset/0016-poulsbo_ide.patch +deleted file mode 100644 +index 949c9cf..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0016-poulsbo_ide.patch ++++ /dev/null +@@ -1,62 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c +-index b406b39..57e4990 100644 +---- a/drivers/ata/ata_piix.c +-+++ b/drivers/ata/ata_piix.c +-@@ -214,6 +214,7 @@ static const struct pci_device_id piix_pci_tbl[] = { +- /* ICH7/7-R (i945, i975) UDMA 100*/ +- { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, +- { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, +-+ { 0x8086, 0x811A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, +- /* ICH8 Mobile PATA Controller */ +- { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, +- +-@@ -731,6 +732,12 @@ static int ich_pata_cable_detect(struct ata_port *ap) +- lap++; +- } +- +-+ /* workaround for Poulsbo PATA controller, this controller's +-+ * IOCFG register is "reserved" +-+ */ +-+ if (pdev->vendor == PCI_VENDOR_ID_INTEL && +-+ pdev->device == PCI_DEVICE_ID_INTEL_POULSBO_IDE) +-+ return ATA_CBL_PATA80; +- /* check BIOS cable detect results */ +- mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; +- pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); +-@@ -752,8 +759,13 @@ static int piix_pata_prereset(struct ata_link *link, unsigned long deadline) +- struct ata_port *ap = link->ap; +- struct pci_dev *pdev = to_pci_dev(ap->host->dev); +- +-- if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) +-- return -ENOENT; +-+ /* workaround for Poulsbo PATA controller, this controller's port +-+ * enable registers are "reserved" +-+ */ +-+ if (pdev->vendor != PCI_VENDOR_ID_INTEL || +-+ pdev->device != PCI_DEVICE_ID_INTEL_POULSBO_IDE) +-+ if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) +-+ return -ENOENT; +- return ata_std_prereset(link, deadline); +- } +- +-diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c +-index 27781d2..6070358 100644 +---- a/drivers/ide/pci/piix.c +-+++ b/drivers/ide/pci/piix.c +-@@ -438,6 +438,7 @@ static const struct ide_port_info piix_pci_info[] __devinitdata = { +- /* 22 */ DECLARE_ICH_DEV("ICH4", ATA_UDMA5), +- /* 23 */ DECLARE_ICH_DEV("ESB2", ATA_UDMA5), +- /* 24 */ DECLARE_ICH_DEV("ICH8M", ATA_UDMA5), +-+ /* 25 */ DECLARE_ICH_DEV("POULSBO", ATA_UDMA5), +- }; +- +- /** +-@@ -511,6 +512,7 @@ static const struct pci_device_id piix_pci_tbl[] = { +- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1), 22 }, +- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 23 }, +- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6), 24 }, +-+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_POULSBO_IDE), 25 }, +- { 0, }, +- }; +- MODULE_DEVICE_TABLE(pci, piix_pci_tbl); +diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c +index 4f3a9ac..9a9645d 100644 +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -214,6 +214,7 @@ static const struct pci_device_id piix_pci_tbl[] = { + /* ICH7/7-R (i945, i975) UDMA 100*/ + { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, ++ { 0x8086, 0x811A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* ICH8 Mobile PATA Controller */ + { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + +@@ -737,6 +738,12 @@ static int ich_pata_cable_detect(struct ata_port *ap) + lap++; + } + ++ /* workaround for Poulsbo PATA controller, this controller's ++ * IOCFG register is "reserved" ++ */ ++ if (pdev->vendor == PCI_VENDOR_ID_INTEL && ++ pdev->device == PCI_DEVICE_ID_INTEL_POULSBO_IDE) ++ return ATA_CBL_PATA80; + /* check BIOS cable detect results */ + mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; + pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); +@@ -758,8 +765,13 @@ static int piix_pata_prereset(struct ata_link *link, unsigned long deadline) + struct ata_port *ap = link->ap; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + +- if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) +- return -ENOENT; ++ /* workaround for Poulsbo PATA controller, this controller's port ++ * enable registers are "reserved" ++ */ ++ if (pdev->vendor != PCI_VENDOR_ID_INTEL || ++ pdev->device != PCI_DEVICE_ID_INTEL_POULSBO_IDE) ++ if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) ++ return -ENOENT; + return ata_std_prereset(link, deadline); + } + +diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c +index 27781d2..6070358 100644 +--- a/drivers/ide/pci/piix.c ++++ b/drivers/ide/pci/piix.c +@@ -438,6 +438,7 @@ static const struct ide_port_info piix_pci_info[] __devinitdata = { + /* 22 */ DECLARE_ICH_DEV("ICH4", ATA_UDMA5), + /* 23 */ DECLARE_ICH_DEV("ESB2", ATA_UDMA5), + /* 24 */ DECLARE_ICH_DEV("ICH8M", ATA_UDMA5), ++ /* 25 */ DECLARE_ICH_DEV("POULSBO", ATA_UDMA5), + }; + + /** +@@ -511,6 +512,7 @@ static const struct pci_device_id piix_pci_tbl[] = { + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1), 22 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 23 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6), 24 }, ++ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_POULSBO_IDE), 25 }, + { 0, }, + }; + MODULE_DEVICE_TABLE(pci, piix_pci_tbl); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0086-Elantech-ps-2-touchpad-driver.patch +++ linux-2.6.24/patches/0086-Elantech-ps-2-touchpad-driver.patch @@ -0,0 +1,1890 @@ +From 98b5629adf71453119685826454e041b5de35412 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 17 Dec 2008 11:43:39 -0500 +Subject: [PATCH 086/170] Elantech ps/2 touchpad driver. + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/input/mouse/elantech.c | 1828 ++++++++++++++++++++++++++++++++++++++++ + drivers/input/mouse/elantech.h | 34 + + 2 files changed, 1862 insertions(+), 0 deletions(-) + create mode 100644 drivers/input/mouse/elantech.c + create mode 100644 drivers/input/mouse/elantech.h + +diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c +new file mode 100644 +index 0000000..ec8e489 +--- /dev/null ++++ b/drivers/input/mouse/elantech.c +@@ -0,0 +1,1828 @@ ++/* ++ * Elantech Touchpad driver ++ * ++ * Copyright (C) 2008 Tom Lin ++ * (c) 2008 Chris Yang ++ * add Elantech smart pad and touchpad ++ * ++ * Copyright (C) 2007 Arjan Opmeer ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ * Trademarks are the property of their respective owners. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "psmouse.h" ++//#include "synaptics.h" ++#include "elantech.h" ++ ++#define ETP_RAW_MODE 0x04 ++#define ETP_4_BYTE_MODE 0x02 ++ ++/* These values work with the touchpad on my laptop. Do they need adjustment? */ ++#define ETP_XMIN 32 ++#define ETP_XMAX 0x240 ++#define ETP_YMIN 32 ++#define ETP_YMAX 0x160 ++ ++/* ++ * Send a synaptics style special commands ++ */ ++/*static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param) ++{ ++ printk(KERN_DEBUG "+synaptics_send_cmd\n"); ++ if (psmouse_sliced_command(psmouse, c)) ++ return -1; ++ if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) ++ return -1; ++ printk(KERN_DEBUG "-synaptics_send_cmd\n"); ++ return 0; ++}*/ ++ ++/* ++ * Send an Elantech style special command to write a register with a value ++ */ ++ ++static int elantech_ps2_command(struct psmouse *psmouse,unsigned char *para, unsigned char val) ++{ ++ int err,i; ++ err=0; ++ ++ for(i=0;i < 2 ;i++){ ++ if(ps2_command(&psmouse->ps2dev,para,val)==0){ ++ err=0; ++ break; ++ } ++ err=-1; ++ } ++ ++ return err; ++} ++ ++static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, unsigned char val) ++{ ++ ++ ++ //printk(KERN_DEBUG "+elantech_write_reg\n"); ++ if ((reg < 0x10) || (reg > 0x26)) ++ return -1; ++ if ((reg > 0x11) && (reg < 0x20)) ++ return -1; ++ //printk(KERN_DEBUG "reg=%x val=%x\n",reg,val); ++ if (psmouse_sliced_command(psmouse, ELANTECH_COMMAND) || ++ psmouse_sliced_command(psmouse, reg) || ++ psmouse_sliced_command(psmouse, val) || ++ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) { ++ return -1; ++ } ++ //printk(KERN_DEBUG "-elantech_write_reg\n"); ++ return 0; ++} ++ ++static int elantech_write_reg_new(struct psmouse *psmouse, unsigned char reg, unsigned char val) ++{ ++ ++ ++ //printk(KERN_DEBUG "+elantech_write_reg\n"); ++ if ((reg < 0x10) || (reg > 0x26)) ++ return -1; ++ if ((reg > 0x11) && (reg < 0x20)) ++ return -1; ++ ++ //printk(KERN_DEBUG "reg=%x val=%x\n",reg,val); ++ if(elantech_ps2_command(psmouse,NULL,0x00f8) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,0x0011) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,0x00f8) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,reg) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,0x00f8) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,val) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,0x00e6) != 0) ++ return -1; ++ //printk(KERN_DEBUG "-elantech_write_reg\n"); ++ ++ return 0; ++} ++ ++ ++static int elantech_read_reg_new(struct psmouse *psmouse, unsigned char reg, unsigned char val) ++{ ++ int i; ++ unsigned char param[3]; ++ //printk(KERN_DEBUG "+elantech_read_reg_new\n"); ++ if ((reg < 0x10) || (reg > 0x26)) ++ return -1; ++ if ((reg > 0x11) && (reg < 0x20)) ++ return -1; ++ //printk(KERN_DEBUG "reg=%x val=%x\n",reg,val); ++ ++ if(elantech_ps2_command(psmouse,NULL,0x00f8) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,0x0010) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,0x00f8) != 0) ++ return -1; ++ ++ if(elantech_ps2_command(psmouse,NULL,reg) != 0) ++ return -1; ++ ++ ++ ++ for(i=0;i < 2 ;i++){ ++ if(ps2_command(&psmouse->ps2dev,param,PSMOUSE_CMD_GETINFO)==0){ ++ break; ++ } ++ } ++ printk(KERN_DEBUG "-elantech_read_reg_new param[0]=%x param[1]=%x param[2]=%x\n",param[0],param[1],param[2]); ++ if(param[0]!=val) ++ return -1; ++ //printk(KERN_DEBUG "-elantech_read_reg_new\n"); ++ return 0; ++} ++ ++static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, unsigned char val) ++{ ++ unsigned char param[3]; ++ //printk(KERN_DEBUG "+elantech_write_reg\n"); ++ if ((reg < 0x10) || (reg > 0x26)) ++ return -1; ++ if ((reg > 0x11) && (reg < 0x20)) ++ return -1; ++ //printk(KERN_DEBUG "reg=%x val=%x\n",reg,val); ++ if (psmouse_sliced_command(psmouse, 0x10) || ++ psmouse_sliced_command(psmouse, reg) || ++ ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { ++ return -1; ++ } ++ printk(KERN_DEBUG "elantech_read_reg reg=%x val=%x param[0]=%x\n",reg,val,param[0]); ++ if(param[0]!=val) ++ return -1; ++ //printk(KERN_DEBUG "-elantech_write_reg\n"); ++ return 0; ++} ++ ++/* ++ * Process byte stream from mouse and interpret complete data packages ++ */ ++static psmouse_ret_t elantech_process_4byte_EF013(struct psmouse *psmouse) ++{ ++ ++ ++ struct input_dev *dev = psmouse->dev; ++ unsigned char *packet = psmouse->packet; ++ unsigned int z,button,rock_switch; ++ int x1,y1,z1=60,x2,y2,x3,y3,x4,y4; ++ static int x1_old,y1_old,count; ++ unsigned char bit7,bit6,bit5,bit4,bit3,bit2,bit1,bit0; ++ unsigned char SA,B,C,D; ++ int C_B,C_C,C_D; ++ ++ ++ ++ ++ x1=y1=x2=y2=x3=y3=x4=y4=0; ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte\n"); ++ //printk(KERN_ERR "elantech.c: psmouse->fw_version %d\n",psmouse->fw_version); ++ ++ ++ ++ ++ if (psmouse->pktcnt < 4) ++ return PSMOUSE_GOOD_DATA; ++//-----------------in check byte data-------------------------------------- ++ ++ SA = packet[0]; ++ B = packet[1]; ++ C = packet[2]; ++ D = packet[3]; ++ ++ if(!(packet[0] & 0x08)) //chech SA byte ++ goto shift_data; ++ ++ bit7 = (packet[1] & 0x80) >> 7; ++ bit6 = (packet[1] & 0x40) >> 6; ++ bit5 = (packet[1] & 0x20) >> 5; ++ bit4 = (packet[1] & 0x10) >> 4; ++ bit3 = (packet[1] & 0x08) >> 3; ++ bit2 = (packet[1] & 0x04) >> 2; ++ bit1 = (packet[1] & 0x02) >> 1; ++ bit0 = (packet[1] & 0x01) ; ++ C_B = (bit7 + bit6 + bit5 + bit4 + bit3 + bit2 + bit1 + bit0)%2; ++ ++ if((packet[0]&0x10) && (C_B == 1)) //chech B byte ++ goto shift_data; ++ else if(!(packet[0]&0x10) && (C_B == 0)) ++ goto shift_data; ++ ++ bit7 = (packet[2] & 0x80) >> 7; ++ bit6 = (packet[2] & 0x40) >> 6; ++ bit5 = (packet[2] & 0x20) >> 5; ++ bit4 = (packet[2] & 0x10) >> 4; ++ bit3 = (packet[2] & 0x08) >> 3; ++ bit2 = (packet[2] & 0x04) >> 2; ++ bit1 = (packet[2] & 0x02) >> 1; ++ bit0 = (packet[2] & 0x01) ; ++ C_C = (bit7 + bit6 + bit5 + bit4 + bit3 + bit2 + bit1 + bit0)%2; ++ ++ if((packet[0]&0x20) && (C_C == 1)) //chech C byte ++ goto shift_data; ++ else if(!(packet[0]&0x20) && (C_C == 0)) ++ goto shift_data; ++ ++ ++ bit7 = (packet[3] & 0x80) >> 7; ++ bit6 = (packet[3] & 0x40) >> 6; ++ bit5 = (packet[3] & 0x20) >> 5; ++ bit4 = (packet[3] & 0x10) >> 4; ++ bit3 = (packet[3] & 0x08) >> 3; ++ bit2 = (packet[3] & 0x04) >> 2; ++ bit1 = (packet[3] & 0x02) >> 1; ++ bit0 = (packet[3] & 0x01) ; ++ C_D = (bit7 + bit6 + bit5 + bit4 + bit3 + bit2 + bit1 + bit0)%2; ++ ++ if((packet[0]&0x04) && (C_D == 1)) //chech D byte ++ goto shift_data; ++ else if(!(packet[0]&0x04) && (C_D == 0)) ++ goto shift_data; ++ ++//-----------------out check byte data-------------------------------------- ++ ++ ++ z = ((packet[0] & 0xC0) >> 6); ++ if(z==0){ ++ input_report_abs(dev,ABS_PRESSURE,0); ++ count=0; ++ ++ } ++ ++ button=packet[0] & 0x03; ++ rock_switch = ((packet[1] & 0xF0) >> 4); ++ ++ x1 = ((packet[1] & 0x0c) << 6) | packet[2]; ++ y1 = 0x1FF - (((packet[1] & 0x03) << 8) | packet[3]); ++ ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte psmouse->fw_version=%d\n",psmouse->fw_version); ++ ++ ++ ++ if((x1 != x1_old )||(y1 != y1_old)){ ++ x1_old=x1; ++ y1_old=y1; ++ ++ if (z == 2) { ++ count = 0; ++ input_report_abs(dev, ABS_HAT0X,x1); ++ input_report_abs(dev, ABS_HAT0Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ //printk(KERN_DEBUG "Data= %x %x %x %x\n",packet[0],packet[1],packet[2],packet[3]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x y2=%.2x count=%d \n",x2,y2,count); ++ ++ /*input_report_abs(dev, ABS_X,((packet[1] & 0x0c) << 6) | packet[2]); ++ input_report_abs(dev, ABS_Y,ETP_YMIN + ETP_YMAX - (((packet[1] & 0x03) << 8) | packet[3]));*/ ++ } ++ if (z == 3){ ++ ++ input_report_abs(dev, ABS_HAT2X,x1); ++ input_report_abs(dev, ABS_HAT2Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ count = 0; ++ ++ ++ } ++ if (z == 1) { ++ count++; ++ if(count < 3){ ++ input_report_abs(dev,ABS_PRESSURE,0); ++ goto out_finger_one; ++ } ++ input_report_abs(dev, ABS_X,x1); ++ input_report_abs(dev, ABS_Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ count=4; ++ ++ //printk(KERN_DEBUG "Data= %x %x %x %x\n",packet[0],packet[1],packet[2],packet[3]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x y2=%.2x count=%d \n",x2,y2,count); ++ ++ ++ } ++ x1=y1=x2=y2=x3=y3=x4=y4=0; ++ ++ } ++ ++ ++ input_report_key(dev, BTN_TOUCH, z > 0); ++ input_report_key(dev, BTN_TOOL_FINGER, z == 1); ++ input_report_key(dev, BTN_TOOL_DOUBLETAP, z == 2); ++ input_report_key(dev, BTN_TOOL_TRIPLETAP, z == 3); ++out_finger_one: ++ input_report_key(dev, BTN_LEFT, button == 1); ++ input_report_key(dev, BTN_RIGHT, button == 2); ++ input_report_key(dev, BTN_MIDDLE, button == 3); ++ input_report_key(dev, BTN_FORWARD, rock_switch == 1); ++ input_report_key(dev, BTN_BACK, rock_switch == 2); ++ input_report_key(dev, BTN_0, rock_switch == 4); ++ input_report_key(dev, BTN_1, rock_switch == 8); ++ ++ ++ ++ ++ ++ input_sync(dev); ++ //printk(KERN_DEBUG "-psmouse_ret_t elantech_process_byte\n"); ++ return PSMOUSE_FULL_PACKET; ++ ++shift_data: ++ packet[0] = B; ++ packet[1] = C; ++ packet[2] = D; ++ psmouse->pktcnt = psmouse->pktcnt-1; ++ return PSMOUSE_GOOD_DATA; ++} ++ ++static psmouse_ret_t elantech_process_4byte_EF019(struct psmouse *psmouse) ++{ ++ ++ ++ struct input_dev *dev = psmouse->dev; ++ unsigned char *packet = psmouse->packet; ++ unsigned int z,button,rock_switch; ++ int x1,y1,z1=60,x2,y2,x3,y3,x4,y4; ++ static int x1_old,y1_old,count; ++ unsigned char bit7,bit6,bit5,bit4,bit3,bit2,bit1,bit0; ++ unsigned char SA,B,C,D; ++ int C_B,C_C,C_D; ++ ++ ++ ++ ++ x1=y1=x2=y2=x3=y3=x4=y4=0; ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte\n"); ++ //printk(KERN_ERR "elantech.c: psmouse->fw_version %d\n",psmouse->fw_version); ++ ++ ++ ++ ++ if (psmouse->pktcnt < 4) ++ return PSMOUSE_GOOD_DATA; ++//-----------------in check byte data-------------------------------------- ++ ++ SA = packet[0]; ++ B = packet[1]; ++ C = packet[2]; ++ D = packet[3]; ++ ++ if((packet[0] & 0x08)) //chech SA byte ++ goto shift_data; ++ ++ bit7 = (packet[1] & 0x80) >> 7; ++ bit6 = (packet[1] & 0x40) >> 6; ++ bit5 = (packet[1] & 0x20) >> 5; ++ bit4 = (packet[1] & 0x10) >> 4; ++ bit3 = (packet[1] & 0x08) >> 3; ++ bit2 = (packet[1] & 0x04) >> 2; ++ bit1 = (packet[1] & 0x02) >> 1; ++ bit0 = (packet[1] & 0x01) ; ++ C_B = (bit7 + bit6 + bit5 + bit4 + bit3 + bit2 + bit1 + bit0)%2; ++ ++ if((packet[0]&0x10) && (C_B == 1)) //chech B byte ++ goto shift_data; ++ else if(!(packet[0]&0x10) && (C_B == 0)) ++ goto shift_data; ++ ++ bit7 = (packet[2] & 0x80) >> 7; ++ bit6 = (packet[2] & 0x40) >> 6; ++ bit5 = (packet[2] & 0x20) >> 5; ++ bit4 = (packet[2] & 0x10) >> 4; ++ bit3 = (packet[2] & 0x08) >> 3; ++ bit2 = (packet[2] & 0x04) >> 2; ++ bit1 = (packet[2] & 0x02) >> 1; ++ bit0 = (packet[2] & 0x01) ; ++ C_C = (bit7 + bit6 + bit5 + bit4 + bit3 + bit2 + bit1 + bit0)%2; ++ ++ if((packet[0]&0x20) && (C_C == 1)) //chech C byte ++ goto shift_data; ++ else if(!(packet[0]&0x20) && (C_C == 0)) ++ goto shift_data; ++ ++ ++ bit7 = (packet[3] & 0x80) >> 7; ++ bit6 = (packet[3] & 0x40) >> 6; ++ bit5 = (packet[3] & 0x20) >> 5; ++ bit4 = (packet[3] & 0x10) >> 4; ++ bit3 = (packet[3] & 0x08) >> 3; ++ bit2 = (packet[3] & 0x04) >> 2; ++ bit1 = (packet[3] & 0x02) >> 1; ++ bit0 = (packet[3] & 0x01) ; ++ C_D = (bit7 + bit6 + bit5 + bit4 + bit3 + bit2 + bit1 + bit0)%2; ++ ++ if((packet[0]&0x04) && (C_D == 1)) //chech D byte ++ goto shift_data; ++ else if(!(packet[0]&0x04) && (C_D == 0)) ++ goto shift_data; ++ ++//-----------------out check byte data-------------------------------------- ++ ++ ++ z = ((packet[0] & 0xC0) >> 6); ++ if(z==0){ ++ input_report_abs(dev,ABS_PRESSURE,0); ++ count=0; ++ ++ } ++ ++ button=packet[0] & 0x03; ++ rock_switch = ((packet[1] & 0xF0) >> 4); ++ ++ x1 = ((packet[1] & 0x0c) << 6) | packet[2]; ++ y1 = 0x1FF - (((packet[1] & 0x03) << 8) | packet[3]); ++ ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte psmouse->fw_version=%d\n",psmouse->fw_version); ++ ++ ++ ++ if((x1 != x1_old )||(y1 != y1_old)){ ++ x1_old=x1; ++ y1_old=y1; ++ ++ if (z == 2) { ++ count = 0; ++ input_report_abs(dev, ABS_HAT0X,x1); ++ input_report_abs(dev, ABS_HAT0Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ //printk(KERN_DEBUG "Data= %x %x %x %x\n",packet[0],packet[1],packet[2],packet[3]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x y2=%.2x count=%d \n",x2,y2,count); ++ ++ /*input_report_abs(dev, ABS_X,((packet[1] & 0x0c) << 6) | packet[2]); ++ input_report_abs(dev, ABS_Y,ETP_YMIN + ETP_YMAX - (((packet[1] & 0x03) << 8) | packet[3]));*/ ++ } ++ if (z == 3){ ++ ++ input_report_abs(dev, ABS_HAT2X,x1); ++ input_report_abs(dev, ABS_HAT2Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ count = 0; ++ ++ ++ } ++ if (z == 1) { ++ count++; ++ if(count < 3){ ++ input_report_abs(dev,ABS_PRESSURE,0); ++ goto out_finger_one; ++ } ++ input_report_abs(dev, ABS_X,x1); ++ input_report_abs(dev, ABS_Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ count=4; ++ ++ //printk(KERN_DEBUG "Data= %x %x %x %x\n",packet[0],packet[1],packet[2],packet[3]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x y2=%.2x count=%d \n",x2,y2,count); ++ ++ ++ } ++ x1=y1=x2=y2=x3=y3=x4=y4=0; ++ ++ } ++ ++ ++ input_report_key(dev, BTN_TOUCH, z > 0); ++ input_report_key(dev, BTN_TOOL_FINGER, z == 1); ++ input_report_key(dev, BTN_TOOL_DOUBLETAP, z == 2); ++ input_report_key(dev, BTN_TOOL_TRIPLETAP, z == 3); ++out_finger_one: ++ input_report_key(dev, BTN_LEFT, button == 1); ++ input_report_key(dev, BTN_RIGHT, button == 2); ++ input_report_key(dev, BTN_MIDDLE, button == 3); ++ input_report_key(dev, BTN_FORWARD, rock_switch == 1); ++ input_report_key(dev, BTN_BACK, rock_switch == 2); ++ input_report_key(dev, BTN_0, rock_switch == 4); ++ input_report_key(dev, BTN_1, rock_switch == 8); ++ ++ ++ ++ ++ ++ input_sync(dev); ++ //printk(KERN_DEBUG "-psmouse_ret_t elantech_process_byte\n"); ++ return PSMOUSE_FULL_PACKET; ++ ++shift_data: ++ packet[0] = B; ++ packet[1] = C; ++ packet[2] = D; ++ psmouse->pktcnt = psmouse->pktcnt-1; ++ return PSMOUSE_GOOD_DATA; ++} ++ ++static psmouse_ret_t elantech_process_6byte_EF113(struct psmouse *psmouse) ++{ ++ ++ ++ struct input_dev *dev = psmouse->dev; ++ unsigned char *packet = psmouse->packet; ++ unsigned char SA1,A1,B1,SB1,C1,D1; ++ unsigned int z,button; ++ int x1,y1,z1=60,x2,y2; ++ ++ ++ x1=y1=x2=y2=0; ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte\n"); ++ ++ ++ ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte psmouse->fw_version=%d\n",psmouse->fw_version); ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++//-----------------in check byte data-------------------------------------- ++ if (psmouse->pktcnt < 6) ++ return PSMOUSE_GOOD_DATA; ++ ++ SA1= packet[0]; ++ A1 = packet[1]; ++ B1 = packet[2]; ++ SB1= packet[3]; ++ C1 = packet[4]; ++ D1 = packet[5]; ++ ++ if( (((SA1 & 0x3C) != 0x3C) && ((SA1 & 0xC0) != 0x80)) || // check Byte 1 ++ (((SA1 & 0x0C) != 0x0C) && ((SA1 & 0xC0) == 0x80)) || // check Byte 1 ++ (((SA1 & 0xC0) != 0x80) && (( A1 & 0xF0) != 0x00)) || // check Byte 2 ++ (((SB1 & 0x3E) != 0x38) && ((SA1 & 0xC0) != 0x80)) || // check Byte 4 ++ (((SB1 & 0x0E) != 0x08) && ((SA1 & 0xC0) == 0x80)) || // check Byte 4 ++ (((SA1 & 0xC0) != 0x80) && (( C1 & 0xF0) != 0x00)) ) // check Byte5 ++ { ++ packet[0] = A1; ++ packet[1] = B1; ++ packet[2] = SB1; ++ packet[3] = C1; ++ packet[4] = D1; ++ psmouse->pktcnt = psmouse->pktcnt - 1; ++ return PSMOUSE_GOOD_DATA; ++ } ++ ++ ++ ++ ++//-----------------out check byte data-------------------------------------- ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++ ++ z = ((packet[0] & 0xC0) >> 6); ++ ++ button = ((packet[3]&0x01 << 2) | (packet[0] & 0x03)); ++ ++ if(z==0) ++ input_report_abs(dev,ABS_PRESSURE,0); ++ ++ if(z==1){ ++ ++ x1=((packet[1] << 8) | packet[2]); ++ y1= 0x2D0 - ((packet[4] << 8) | packet[5]); ++ x2=(x1*420)/100 + 1400; ++ y2=(y1*562)/100 + 1400; ++ input_report_abs(dev, ABS_X,x2); ++ input_report_abs(dev, ABS_Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x y2=%.2x\n",x2,y2); ++ ++ } ++ ++ if(z==2){ ++ //input_report_key(dev, BTN_C,z > 0); ++ x1=((packet[0] & 0x10) << 4) | packet[1]; ++ y1=0xFF -(((packet[0] & 0x20) << 3) | packet[2]); ++ x2=((packet[3] & 0x10) << 4) | packet[4]; ++ y2=0xFF -(((packet[3] & 0x20) << 3 )| packet[5]); ++ ++ input_report_abs(dev, ABS_HAT0X,x1); ++ input_report_abs(dev, ABS_HAT0Y,y1); ++ input_report_abs(dev, ABS_HAT1X,x2); ++ input_report_abs(dev, ABS_HAT1Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x %d y2=%.2x %d\n",x2,x2,y2,y2); ++ ++ //printk(KERN_DEBUG "x3=%.2x y3=%.2x z3=%.2x\n",x3,y3,z1); ++ //printk(KERN_DEBUG "x4=%.2x %d y4=%.2x %d\n",x4,x4,y4,y4); ++ ++ } ++ if(z==3){ ++ x1=((packet[1] << 8) | packet[2]); ++ y1= 0x7FF - ((packet[4] << 8) | packet[5]); ++ //x2=(x1*420)/100 + 1126; ++ //y2=(y1*562)/100 + 897; ++ input_report_abs(dev, ABS_HAT2X,x1); ++ input_report_abs(dev, ABS_HAT2Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ } ++ ++ ++ ++ input_report_key(dev, BTN_TOUCH, z > 0); ++ input_report_key(dev, BTN_TOOL_FINGER, z == 1); ++ input_report_key(dev, BTN_TOOL_DOUBLETAP, z == 2); ++ input_report_key(dev, BTN_TOOL_TRIPLETAP, z == 3); ++ ++ ++ input_report_key(dev, BTN_LEFT, button == 1); ++ input_report_key(dev, BTN_RIGHT, button == 2); ++ input_report_key(dev, BTN_MIDDLE, button == 3); ++ input_report_key(dev, BTN_FORWARD, button == 4); ++ input_report_key(dev, BTN_BACK, button == 5); ++ input_report_key(dev, BTN_0, button == 6); ++ input_report_key(dev, BTN_1, button == 7); ++ ++ ++ packet[0]=0; ++ packet[1]=0; ++ packet[2]=0; ++ packet[3]=0; ++ packet[4]=0; ++ packet[5]=0; ++ input_sync(dev); ++ //printk(KERN_DEBUG "-psmouse_ret_t elantech_process_byte\n"); ++ return PSMOUSE_FULL_PACKET; ++ ++ ++} ++ ++static psmouse_ret_t elantech_process_6byte_EF023(struct psmouse *psmouse) ++{ ++ ++ ++ struct input_dev *dev = psmouse->dev; ++ unsigned char *packet = psmouse->packet; ++ unsigned char SA1,A1,B1,SB1,C1,D1; ++ static unsigned char SA1_O,A1_O,B1_O,SB1_O,C1_O,D1_O,finger_O; ++ unsigned int fingers,button; ++ int x1,y1,z1,x2,y2,w1; ++ ++ ++ x1=y1=x2=y2=0; ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte\n"); ++ ++ ++ ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte psmouse->fw_version=%d\n",psmouse->fw_version); ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++//-----------------in check byte data-------------------------------------- ++ if (psmouse->pktcnt < 6) ++ return PSMOUSE_GOOD_DATA; ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++ SA1= packet[0]; ++ A1 = packet[1]; ++ B1 = packet[2]; ++ SB1= packet[3]; ++ C1 = packet[4]; ++ D1 = packet[5]; ++ ++ if( ((SA1 & 0x0C) != 0x04) || // check Byte 1 ++ ((SB1 & 0x0f) != 0x02) ) // check Byte 4 ++ { ++ packet[0] = A1; ++ packet[1] = B1; ++ packet[2] = SB1; ++ packet[3] = C1; ++ packet[4] = D1; ++ psmouse->pktcnt = psmouse->pktcnt - 1; ++ return PSMOUSE_GOOD_DATA; ++ } ++ ++ ++ ++ ++//-----------------out check byte data-------------------------------------- ++ //printk(KERN_DEBUG "Data2= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++ if( SA1 != SA1_O || ++ A1 != A1_O || ++ B1 != B1_O || ++ SB1 != SB1_O || ++ C1 != C1_O || ++ D1 != D1_O) ++ { ++ fingers = ((packet[0] & 0xC0) >> 6); ++ if(finger_O == fingers){ ++ button = ((packet[3]&0x01 << 2) | (packet[0] & 0x03)); ++ w1 = (((packet[0]&0x30)>>2)|((packet[3]&0x30)>>4)) & 0x0f; ++ //printk(KERN_DEBUG "w1= %d \n",w1); ++ if(fingers==0) ++ input_report_abs(dev,ABS_PRESSURE,0); ++ ++ if(fingers==1){ ++ ++ x1=(((packet[1] & 0x0f) << 8) | packet[2]); ++ y1= 0x2F0 -(((packet[4] & 0x0f) << 8) | packet[5]); ++ x2=(x1*420)/100 + 1400; ++ y2=(y1*562)/100 + 1400; ++ z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); ++ ++ ++ input_report_abs(dev, ABS_X,x2); ++ input_report_abs(dev, ABS_Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x y2=%.2x\n",x2,y2); ++ ++ } ++ ++ if(fingers==2){ ++ //input_report_key(dev, BTN_C,z > 0); ++ x1=((packet[0] & 0x10) << 4) | packet[1]; ++ y1=0xFF -(((packet[0] & 0x20) << 3) | packet[2]); ++ x2=((packet[3] & 0x10) << 4) | packet[4]; ++ y2=0xFF -(((packet[3] & 0x20) << 3 )| packet[5]); ++ z1=70; ++ input_report_abs(dev, ABS_HAT0X,x1); ++ input_report_abs(dev, ABS_HAT0Y,y1); ++ input_report_abs(dev, ABS_HAT1X,x2); ++ input_report_abs(dev, ABS_HAT1Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x %d y2=%.2x %d\n",x2,x2,y2,y2); ++ ++ //printk(KERN_DEBUG "x3=%.2x y3=%.2x z3=%.2x\n",x3,y3,z1); ++ //printk(KERN_DEBUG "x4=%.2x %d y4=%.2x %d\n",x4,x4,y4,y4); ++ ++ } ++ if(fingers==3){ ++ x1=(((packet[1] & 0x0f) << 8) | packet[2]); ++ y1= 0x7FF - (((packet[4] & 0x0f) << 8) | packet[5]); ++ z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); ++ ++ //x2=(x1*420)/100 + 1126; ++ //y2=(y1*562)/100 + 897; ++ input_report_abs(dev, ABS_HAT2X,x1); ++ input_report_abs(dev, ABS_HAT2Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ } ++ ++ ++ ++ input_report_abs(dev,ABS_TOOL_WIDTH,w1); ++ input_report_key(dev, BTN_TOUCH, fingers > 0); ++ input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); ++ input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); ++ input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); ++ ++ /* ++ input_report_key(dev, BTN_LEFT, button == 1); ++ input_report_key(dev, BTN_RIGHT, button == 2); ++ input_report_key(dev, BTN_MIDDLE, button == 3);*/ ++ input_report_key(dev, BTN_FORWARD, button == 4); ++ input_report_key(dev, BTN_BACK, button == 5); ++ input_report_key(dev, BTN_0, button == 6); ++ input_report_key(dev, BTN_1, button == 7); ++ input_report_key(dev, BTN_2, button == 1); ++ input_report_key(dev, BTN_3, button == 2); ++ input_report_key(dev, BTN_4, button == 3); ++ ++ SA1_O = SA1; ++ A1_O = A1; ++ B1_O = B1; ++ SB1_O = SB1; ++ C1_O = C1; ++ D1_O = D1; ++ } ++ finger_O = fingers; ++ } ++ input_sync(dev); ++ //printk(KERN_DEBUG "-psmouse_ret_t elantech_process_byte\n"); ++ return PSMOUSE_FULL_PACKET; ++ ++ ++} ++ ++static psmouse_ret_t elantech_process_6byte_EF051(struct psmouse *psmouse) ++{ ++ ++ ++ struct input_dev *dev = psmouse->dev; ++ unsigned char *packet = psmouse->packet; ++ unsigned char SA1,A1,B1,SB1,C1,D1; ++ static unsigned char SA1_O,A1_O,B1_O,SB1_O,C1_O,D1_O; ++ unsigned int fingers,button; ++ int x1,y1,z1,x2,y2,w1; ++ ++ ++ x1=y1=x2=y2=0; ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte\n"); ++ ++ ++ ++ //printk(KERN_DEBUG "+psmouse_ret_t elantech_process_byte psmouse->fw_version=%d\n",psmouse->fw_version); ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++//-----------------in check byte data-------------------------------------- ++ if (psmouse->pktcnt < 6) ++ return PSMOUSE_GOOD_DATA; ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++ SA1= packet[0]; ++ A1 = packet[1]; ++ B1 = packet[2]; ++ SB1= packet[3]; ++ C1 = packet[4]; ++ D1 = packet[5]; ++ ++ if( ((SA1 & 0x0C) != 0x04) || // check Byte 1 ++ ((SB1 & 0x0f) != 0x02) ) // check Byte 4 ++ { ++ packet[0] = A1; ++ packet[1] = B1; ++ packet[2] = SB1; ++ packet[3] = C1; ++ packet[4] = D1; ++ psmouse->pktcnt = psmouse->pktcnt - 1; ++ return PSMOUSE_GOOD_DATA; ++ } ++ ++ ++ ++ ++//-----------------out check byte data-------------------------------------- ++ //printk(KERN_DEBUG "Data2= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ ++ if( SA1 != SA1_O || ++ A1 != A1_O || ++ B1 != B1_O || ++ SB1 != SB1_O || ++ C1 != C1_O || ++ D1 != D1_O) ++ { ++ fingers = ((packet[0] & 0xC0) >> 6); ++ ++ button = ((packet[3]&0x01 << 2) | (packet[0] & 0x03)); ++ w1 = (((packet[0]&0x30)>>2)|((packet[3]&0x30)>>4)) & 0x0f; ++ //printk(KERN_DEBUG "w1= %d \n",w1); ++ if(fingers==0) ++ input_report_abs(dev,ABS_PRESSURE,0); ++ ++ if(fingers==1){ ++ ++ x1=(((packet[1] & 0x0f) << 8) | packet[2]); ++ y1= 0x2F0 -(((packet[4] & 0x0f) << 8) | packet[5]); ++ x2=(x1*420)/100 + 1400; ++ y2=(y1*562)/100 + 1400; ++ z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); ++ ++ ++ input_report_abs(dev, ABS_X,x2); ++ input_report_abs(dev, ABS_Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x y2=%.2x\n",x2,y2); ++ ++ } ++ ++ if(fingers==2){ ++ //input_report_key(dev, BTN_C,z > 0); ++ x1=((packet[0] & 0x10) << 4) | packet[1]; ++ y1=0xFF -(((packet[0] & 0x20) << 3) | packet[2]); ++ x2=((packet[3] & 0x10) << 4) | packet[4]; ++ y2=0xFF -(((packet[3] & 0x20) << 3 )| packet[5]); ++ z1=61; ++ input_report_abs(dev, ABS_HAT0X,x1); ++ input_report_abs(dev, ABS_HAT0Y,y1); ++ input_report_abs(dev, ABS_HAT1X,x2); ++ input_report_abs(dev, ABS_HAT1Y,y2); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ ++ //printk(KERN_DEBUG "Data= %.2x %.2x %.2x %.2x %.2x %.2x\n",packet[0],packet[1],packet[2],packet[3],packet[4],packet[5]); ++ //printk(KERN_DEBUG "x1=%.2x y1=%.2x z1=%.2x\n",x1,y1,z1); ++ //printk(KERN_DEBUG "x2=%.2x %d y2=%.2x %d\n",x2,x2,y2,y2); ++ ++ //printk(KERN_DEBUG "x3=%.2x y3=%.2x z3=%.2x\n",x3,y3,z1); ++ //printk(KERN_DEBUG "x4=%.2x %d y4=%.2x %d\n",x4,x4,y4,y4); ++ ++ } ++ if(fingers==3){ ++ x1=(((packet[1] & 0x0f) << 8) | packet[2]); ++ y1= 0x7FF - (((packet[4] & 0x0f) << 8) | packet[5]); ++ z1 = ((packet[1]&0xf0)|((packet[4]&0xf0)>>4)); ++ ++ //x2=(x1*420)/100 + 1126; ++ //y2=(y1*562)/100 + 897; ++ input_report_abs(dev, ABS_HAT2X,x1); ++ input_report_abs(dev, ABS_HAT2Y,y1); ++ input_report_abs(dev,ABS_PRESSURE,z1); ++ } ++ ++ ++ ++ input_report_abs(dev,ABS_TOOL_WIDTH,w1); ++ input_report_key(dev, BTN_TOUCH, fingers > 0); ++ input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); ++ input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); ++ input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); ++ ++ ++ input_report_key(dev, BTN_LEFT, button == 1); ++ input_report_key(dev, BTN_RIGHT, button == 2); ++ input_report_key(dev, BTN_MIDDLE, button == 3); ++ input_report_key(dev, BTN_FORWARD, button == 4); ++ input_report_key(dev, BTN_BACK, button == 5); ++ input_report_key(dev, BTN_0, button == 6); ++ input_report_key(dev, BTN_1, button == 7); ++ ++ ++ SA1_O = SA1; ++ A1_O = A1; ++ B1_O = B1; ++ SB1_O = SB1; ++ C1_O = C1; ++ D1_O = D1; ++ } ++ input_sync(dev); ++ //printk(KERN_DEBUG "-psmouse_ret_t elantech_process_byte\n"); ++ return PSMOUSE_FULL_PACKET; ++ ++ ++} ++ ++/* ++ * Initialise the touchpad to a default state. Because we don't know (yet) ++ * how to read registers we need to write some default values so we can ++ * report their contents when asked to. ++ */ ++ ++ ++static int elantech_set_4byte_defaults_EF013(struct psmouse *psmouse) ++{ ++ ++ struct elantech_data *etd = psmouse->private; ++ struct input_dev *dev = psmouse->dev; ++ ++ int err,repeat_run,checkrepeat_run; ++ ++ //printk(KERN_DEBUG "+elantech_set_defaults\n"); ++ /* ++ * For now, use the Elantech Windows driver default values ++ */ ++ repeat_run=checkrepeat_run=0; ++ ++repeat_com: ++ ++ ++ ++ etd->reg_10 = 0x14; ++ if((elantech_write_reg(psmouse, 0x10, etd->reg_10) != 0) && (repeat_run<2)){ ++ repeat_run++; ++ goto repeat_com; ++ } ++ ++ ++ ++ etd->reg_11 = 0x8b; ++ elantech_write_reg(psmouse, 0x11, etd->reg_11); ++ ++ err=elantech_read_reg(psmouse, 0x10, etd->reg_10); ++ ++ if((err != 0) && (checkrepeat_run<2)){ ++ checkrepeat_run++; ++ goto repeat_com; ++ } ++ ++ if(err==0){ ++ set_bit(EV_KEY, dev->evbit); ++ set_bit(BTN_LEFT, dev->keybit); ++ set_bit(BTN_MIDDLE, dev->keybit); ++ set_bit(BTN_RIGHT, dev->keybit); ++ set_bit(BTN_FORWARD, dev->keybit); ++ set_bit(BTN_BACK, dev->keybit); ++ ++ set_bit(BTN_TOUCH, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ /* Corner taps */ ++ set_bit(BTN_0, dev->keybit); ++ set_bit(BTN_1, dev->keybit); ++ set_bit(BTN_2, dev->keybit); ++ set_bit(BTN_3, dev->keybit); ++ set_bit(BTN_4, dev->keybit); ++ set_bit(BTN_5, dev->keybit); ++ set_bit(BTN_6, dev->keybit); ++ set_bit(BTN_7, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP , dev->keybit); ++ ++ ++ ++ set_bit(EV_ABS, dev->evbit); ++// input_set_abs_params(dev, ABS_X, ETP_XMIN, ETP_XMAX, 0, 0); ++// input_set_abs_params(dev, ABS_Y, ETP_YMIN, ETP_YMAX, 0, 0);255 ++ ++ //input_set_abs_params(dev, ABS_X, 1150,6032, 0, 0); ++ //input_set_abs_params(dev, ABS_Y, 1019,5980, 0,0); ++ ++ input_set_abs_params(dev, ABS_X, 0,511, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 0,511, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X,0,511, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,0,511, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,0,511, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,0,511, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,511, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,511, 0, 0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 127, 0, 0); ++ ++ } ++ //printk(KERN_DEBUG "-elantech_set_defaults\n"); ++ ++ return err; ++} ++ ++static int elantech_set_4byte_defaults_EF019(struct psmouse *psmouse) ++{ ++ ++ struct elantech_data *etd = psmouse->private; ++ struct input_dev *dev = psmouse->dev; ++ ++ int err,repeat_run,checkrepeat_run; ++ ++ //printk(KERN_DEBUG "+elantech_set_defaults\n"); ++ /* ++ * For now, use the Elantech Windows driver default values ++ */ ++ repeat_run=checkrepeat_run=0; ++ ++repeat_com: ++ ++ ++ ++ etd->reg_10 = 0x14; ++ if((elantech_write_reg(psmouse, 0x10, etd->reg_10) != 0) && (repeat_run<2)){ ++ repeat_run++; ++ goto repeat_com; ++ } ++ ++ ++ ++ etd->reg_11 = 0x8b; ++ elantech_write_reg(psmouse, 0x11, etd->reg_11); ++ ++ err=elantech_read_reg(psmouse, 0x10, etd->reg_10); ++ ++ if((err != 0) && (checkrepeat_run<2)){ ++ checkrepeat_run++; ++ goto repeat_com; ++ } ++ ++ if(err==0){ ++ set_bit(EV_KEY, dev->evbit); ++ set_bit(BTN_LEFT, dev->keybit); ++ set_bit(BTN_MIDDLE, dev->keybit); ++ set_bit(BTN_RIGHT, dev->keybit); ++ set_bit(BTN_FORWARD, dev->keybit); ++ set_bit(BTN_BACK, dev->keybit); ++ ++ set_bit(BTN_TOUCH, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ /* Corner taps */ ++ set_bit(BTN_0, dev->keybit); ++ set_bit(BTN_1, dev->keybit); ++ set_bit(BTN_2, dev->keybit); ++ set_bit(BTN_3, dev->keybit); ++ set_bit(BTN_4, dev->keybit); ++ set_bit(BTN_5, dev->keybit); ++ set_bit(BTN_6, dev->keybit); ++ set_bit(BTN_7, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP , dev->keybit); ++ ++ ++ ++ set_bit(EV_ABS, dev->evbit); ++// input_set_abs_params(dev, ABS_X, ETP_XMIN, ETP_XMAX, 0, 0); ++// input_set_abs_params(dev, ABS_Y, ETP_YMIN, ETP_YMAX, 0, 0);255 ++ ++ //input_set_abs_params(dev, ABS_X, 1150,6032, 0, 0); ++ //input_set_abs_params(dev, ABS_Y, 1019,5980, 0,0); ++ ++ input_set_abs_params(dev, ABS_X, 0,511, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 0,511, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X,0,511, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,0,511, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,0,511, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,0,511, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,511, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,511, 0, 0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 127, 0, 0); ++ ++ } ++ //printk(KERN_DEBUG "-elantech_set_defaults\n"); ++ ++ return err; ++} ++ ++static int elantech_set_6byte_defaults_EF113(struct psmouse *psmouse) ++{ ++ ++ struct elantech_data *etd = psmouse->private; ++ struct input_dev *dev = psmouse->dev; ++ int err,repeat_run,checkrepeat_run; ++ ++ //printk(KERN_DEBUG "+elantech_set_defaults\n"); ++ /* ++ * For now, use the Elantech Windows driver default values ++ */ ++ repeat_run=checkrepeat_run=0; ++ err=-1; ++ ++repeat_com: ++ ++ etd->reg_10 = 0x54; ++ err=elantech_write_reg_new(psmouse, 0x10, etd->reg_10); ++ if((err != 0) && (repeat_run<2)){ ++ repeat_run++; ++ goto repeat_com; ++ } ++ ++ etd->reg_11 = 0x8a; ++ err=elantech_write_reg_new(psmouse, 0x11, etd->reg_11); ++ //elantech_read_reg_new(psmouse, 0x11, etd->reg_11); ++ ++ /*etd->reg_21 = 0x60; ++ elantech_write_reg_new(psmouse, 0x21, etd->reg_21); ++ //elantech_read_reg_new(psmouse, 0x21, etd->reg_21);*/ ++ ++ ++ ++ err = elantech_read_reg_new(psmouse, 0x10, etd->reg_10); ++ ++ if((err != 0) && (checkrepeat_run<2)){ ++ checkrepeat_run++; ++ goto repeat_com; ++ } ++ ++ if(err==0){ ++ set_bit(EV_KEY, dev->evbit); ++ set_bit(BTN_LEFT, dev->keybit); ++ set_bit(BTN_MIDDLE, dev->keybit); ++ set_bit(BTN_RIGHT, dev->keybit); ++ set_bit(BTN_FORWARD, dev->keybit); ++ set_bit(BTN_BACK, dev->keybit); ++ ++ set_bit(BTN_TOUCH, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ /* Corner taps */ ++ set_bit(BTN_0, dev->keybit); ++ set_bit(BTN_1, dev->keybit); ++ set_bit(BTN_2, dev->keybit); ++ set_bit(BTN_3, dev->keybit); ++ set_bit(BTN_4, dev->keybit); ++ set_bit(BTN_5, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ ++ ++ ++ set_bit(EV_ABS, dev->evbit); ++// input_set_abs_params(dev, ABS_X, ETP_XMIN, ETP_XMAX, 0, 0); ++// input_set_abs_params(dev, ABS_Y, ETP_YMIN, ETP_YMAX, 0, 0); ++ ++ input_set_abs_params(dev, ABS_X,1202, 5876, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 999, 5112, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X, 4, 281, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,4,187, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,4, 281, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,4, 187, 0, 0); ++ //input_set_abs_params(dev, ABS_TOOL_WIDTH,0,16,0,0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,2047, 0, 0); ++ ++ ++/* ++ input_set_abs_params(dev, ABS_X, 0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 0,2047, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 127, 0, 0); ++*/ ++ } ++ //printk(KERN_DEBUG "-elantech_set_defaults\n"); ++ ++ return err; ++} ++ ++static int elantech_set_6byte_defaults_EF023(struct psmouse *psmouse) ++{ ++ ++ struct elantech_data *etd = psmouse->private; ++ struct input_dev *dev = psmouse->dev; ++ int err,repeat_run,checkrepeat_run; ++ ++ //printk(KERN_DEBUG "+elantech_set_defaults\n"); ++ /* ++ * For now, use the Elantech Windows driver default values ++ */ ++ repeat_run=checkrepeat_run=0; ++ err=-1; ++ ++repeat_com: ++ ++ etd->reg_10 = 0xc4; ++ err=elantech_write_reg_new(psmouse, 0x10, etd->reg_10); ++ if((err != 0) && (repeat_run<2)){ ++ repeat_run++; ++ goto repeat_com; ++ } ++ ++ etd->reg_11 = 0x8a; ++ err=elantech_write_reg_new(psmouse, 0x11, etd->reg_11); ++ //elantech_read_reg_new(psmouse, 0x11, etd->reg_11); ++ ++ /*etd->reg_21 = 0x60; ++ elantech_write_reg_new(psmouse, 0x21, etd->reg_21); ++ //elantech_read_reg_new(psmouse, 0x21, etd->reg_21);*/ ++ ++ ++ ++ err = elantech_read_reg_new(psmouse, 0x10, etd->reg_10); ++ ++ if((err != 0) && (checkrepeat_run<2)){ ++ checkrepeat_run++; ++ goto repeat_com; ++ } ++ ++ if(err==0){ ++ set_bit(EV_KEY, dev->evbit); ++ set_bit(BTN_LEFT, dev->keybit); ++ set_bit(BTN_MIDDLE, dev->keybit); ++ set_bit(BTN_RIGHT, dev->keybit); ++ set_bit(BTN_FORWARD, dev->keybit); ++ set_bit(BTN_BACK, dev->keybit); ++ ++ set_bit(BTN_TOUCH, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ /* Corner taps */ ++ set_bit(BTN_0, dev->keybit); ++ set_bit(BTN_1, dev->keybit); ++ set_bit(BTN_2, dev->keybit); ++ set_bit(BTN_3, dev->keybit); ++ set_bit(BTN_4, dev->keybit); ++ set_bit(BTN_5, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ ++ ++ ++ set_bit(EV_ABS, dev->evbit); ++// input_set_abs_params(dev, ABS_X, ETP_XMIN, ETP_XMAX, 0, 0); ++// input_set_abs_params(dev, ABS_Y, ETP_YMIN, ETP_YMAX, 0, 0); ++ ++ input_set_abs_params(dev, ABS_X,1202, 5876, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 999, 5112, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X, 4, 281, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,4,187, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,4, 281, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,4, 187, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_TOOL_WIDTH,0,16,0,0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); ++/* ++ input_set_abs_params(dev, ABS_X, 0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 0,2047, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 127, 0, 0); ++*/ ++ } ++ //printk(KERN_DEBUG "-elantech_set_defaults\n"); ++ ++ return err; ++} ++ ++static int elantech_set_6byte_defaults_EF051(struct psmouse *psmouse) ++{ ++ ++ struct elantech_data *etd = psmouse->private; ++ struct input_dev *dev = psmouse->dev; ++ int err,repeat_run,checkrepeat_run; ++ ++ //printk(KERN_DEBUG "+elantech_set_defaults\n"); ++ /* ++ * For now, use the Elantech Windows driver default values ++ */ ++ repeat_run=checkrepeat_run=0; ++ err=-1; ++ ++repeat_com: ++ ++ etd->reg_10 = 0xc4; ++ err=elantech_write_reg_new(psmouse, 0x10, etd->reg_10); ++ if((err != 0) && (repeat_run<2)){ ++ repeat_run++; ++ goto repeat_com; ++ } ++ ++ etd->reg_11 = 0x8a; ++ err=elantech_write_reg_new(psmouse, 0x11, etd->reg_11); ++ //elantech_read_reg_new(psmouse, 0x11, etd->reg_11); ++ ++ /*etd->reg_21 = 0x60; ++ elantech_write_reg_new(psmouse, 0x21, etd->reg_21); ++ //elantech_read_reg_new(psmouse, 0x21, etd->reg_21);*/ ++ ++ ++ ++ err = elantech_read_reg_new(psmouse, 0x10, etd->reg_10); ++ ++ if((err != 0) && (checkrepeat_run<2)){ ++ checkrepeat_run++; ++ goto repeat_com; ++ } ++ ++ if(err==0){ ++ set_bit(EV_KEY, dev->evbit); ++ set_bit(BTN_LEFT, dev->keybit); ++ set_bit(BTN_MIDDLE, dev->keybit); ++ set_bit(BTN_RIGHT, dev->keybit); ++ set_bit(BTN_FORWARD, dev->keybit); ++ set_bit(BTN_BACK, dev->keybit); ++ ++ set_bit(BTN_TOUCH, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ /* Corner taps */ ++ set_bit(BTN_0, dev->keybit); ++ set_bit(BTN_1, dev->keybit); ++ set_bit(BTN_2, dev->keybit); ++ set_bit(BTN_3, dev->keybit); ++ set_bit(BTN_4, dev->keybit); ++ set_bit(BTN_5, dev->keybit); ++ set_bit(BTN_TOOL_FINGER, dev->keybit); ++ set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); ++ set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); ++ ++ ++ ++ set_bit(EV_ABS, dev->evbit); ++// input_set_abs_params(dev, ABS_X, ETP_XMIN, ETP_XMAX, 0, 0); ++// input_set_abs_params(dev, ABS_Y, ETP_YMIN, ETP_YMAX, 0, 0); ++ ++ input_set_abs_params(dev, ABS_X,1202, 5876, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 999, 5112, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X, 4, 281, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,4,187, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,4, 281, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,4, 187, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_TOOL_WIDTH,0,16,0,0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); ++/* ++ input_set_abs_params(dev, ABS_X, 0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_Y, 0,2047, 0,0); ++ input_set_abs_params(dev, ABS_HAT0X,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT0Y,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1X,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT1Y,0,255, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2X,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_HAT2Y,0,2047, 0, 0); ++ input_set_abs_params(dev, ABS_PRESSURE, 0, 127, 0, 0); ++*/ ++ } ++ //printk(KERN_DEBUG "-elantech_set_defaults\n"); ++ ++ return err; ++} ++ ++struct elantech_attr_data { ++ size_t field_offset; ++ unsigned char reg; ++}; ++ ++/* ++ * Display a register value by reading a sysfs entry ++ */ ++static ssize_t elantech_show_int_attr(struct psmouse *psmouse, void *data, char *buf) ++{ ++ ++ struct elantech_data *etd = psmouse->private; ++ struct elantech_attr_data *attr = data; ++ unsigned char *reg = (unsigned char *) ++ etd + attr->field_offset; ++ //printk(KERN_DEBUG "+ssize_t elantech_show_int_attr\n"); ++ //printk(KERN_DEBUG "-ssize_t elantech_show_int_attr\n"); ++ return sprintf(buf, "0x%02x\n", *reg); ++} ++ ++/* ++ * Write a register value by writing a sysfs entry ++ */ ++static ssize_t elantech_set_int_attr(struct psmouse *psmouse, void *data, ++ const char *buf, size_t count) ++{ ++ ++ struct elantech_data *etd = psmouse->private; ++ struct elantech_attr_data *attr = data; ++ unsigned char *reg = (unsigned char *) ++ etd + attr->field_offset; ++ unsigned long value; ++ char *rest; ++ //printk(KERN_DEBUG "+ssize_t elantech_set_int_attr\n"); ++ value = simple_strtoul(buf, &rest, 16); ++ if (*rest || value > 255) ++ return -EINVAL; ++ ++ /* Force 4 byte packet mode because driver expects this */ ++ if (attr->reg == 0x11) ++ value |= ETP_4_BYTE_MODE; ++ ++ *reg = value; ++ elantech_write_reg(psmouse, attr->reg, value); ++ //printk(KERN_DEBUG "-ssize_t elantech_set_int_attr\n"); ++ return count; ++} ++ ++#define ELANTECH_INT_ATTR(_name, _register) \ ++ static struct elantech_attr_data elantech_attr_##_name = { \ ++ .field_offset = offsetof(struct elantech_data, _name), \ ++ .reg = _register, \ ++ }; \ ++ PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ ++ &elantech_attr_##_name, \ ++ elantech_show_int_attr, \ ++ elantech_set_int_attr) ++ ++ELANTECH_INT_ATTR(reg_10, 0x10); ++ELANTECH_INT_ATTR(reg_11, 0x11); ++ELANTECH_INT_ATTR(reg_20, 0x20); ++ELANTECH_INT_ATTR(reg_21, 0x21); ++ELANTECH_INT_ATTR(reg_22, 0x22); ++ELANTECH_INT_ATTR(reg_23, 0x23); ++ELANTECH_INT_ATTR(reg_24, 0x24); ++ELANTECH_INT_ATTR(reg_25, 0x25); ++ELANTECH_INT_ATTR(reg_26, 0x26); ++ ++static struct attribute *elantech_attrs[] = { ++ &psmouse_attr_reg_10.dattr.attr, ++ &psmouse_attr_reg_11.dattr.attr, ++ &psmouse_attr_reg_20.dattr.attr, ++ &psmouse_attr_reg_21.dattr.attr, ++ &psmouse_attr_reg_22.dattr.attr, ++ &psmouse_attr_reg_23.dattr.attr, ++ &psmouse_attr_reg_24.dattr.attr, ++ &psmouse_attr_reg_25.dattr.attr, ++ &psmouse_attr_reg_26.dattr.attr, ++ NULL ++}; ++ ++static struct attribute_group elantech_attr_group = { ++ .attrs = elantech_attrs, ++}; ++ ++/* ++ * Clean up sysfs entries when disconnecting ++ */ ++static void elantech_disconnect(struct psmouse *psmouse) ++{ ++ printk(KERN_DEBUG "elantech_disconnect\n"); ++ sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, ++ &elantech_attr_group); ++ kfree(psmouse->private); ++ psmouse->private = NULL; ++ //printk(KERN_DEBUG "-elantech_disconnect\n"); ++} ++ ++/* ++ * Use magic knock to detect Elantech touchpad ++ */ ++ ++ ++static int elantech_reconnect(struct psmouse *psmouse) ++{ ++ ++ int i; ++ int err; ++ err=i8042_command(NULL,I8042_CMD_KBD_DISABLE);// tom + ++ ++ if(!err) ++ printk(KERN_INFO"i8042_command I8042_CMD_KBD_DISABLE OK\n"); ++ for(i=0;i<3;i++){ ++ printk(KERN_INFO"elantech_reconnect\n"); ++ if (!elantech_detect(psmouse, 0)){ ++ if (!elantech_init(psmouse,0)) ++ break; ++ } ++ else ++ continue; ++ } ++ ++ if(i>=3){ ++ printk(KERN_INFO"elantech_reconnect fail\n"); ++ if(!err) ++ err=i8042_command(NULL,I8042_CMD_KBD_ENABLE);// tom + ++ if(!err) ++ printk(KERN_INFO"i8042_command I8042_CMD_KBD_ENABLE OK\n"); ++ return -1; ++ } ++ if(!err) ++ err=i8042_command(NULL,I8042_CMD_KBD_ENABLE);// tom + ++ if(!err) ++ printk(KERN_INFO"i8042_command I8042_CMD_KBD_ENABLE OK\n"); ++ return 0; ++} ++ ++int elantech_detect(struct psmouse *psmouse, int set_properties) ++{ ++ ++ struct ps2dev *ps2dev = &psmouse->ps2dev; ++ unsigned char param[3]; ++ int i; ++ ++ printk(KERN_INFO "2.6.2X-Elan-touchpad-2008-11-28\n"); ++ printk(KERN_DEBUG "+elantech_detect\n"); ++ ++ for(i=0;i<3;i++) ++ { ++ if(!ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE)) ++ break; ++ } ++ ++ for(i=0;i<3;i++) ++ { ++ param[0]=0; ++ param[1]=0; ++ param[2]=0; ++ if(!ps2_command(ps2dev, param, 0x02ff)) ++ { ++ printk(KERN_INFO "elantech.c: PSMOUSE_CMD_RESET_BAT param[0]=%x param[1]=%x param[2]=%x\n",param[0],param[1],param[2]); ++ break; ++ } ++ } //FF ->reply FA AA 00 ++ ++ if(i >= 3) ++ printk(KERN_INFO "elantech.c: PSMOUSE_CMD_RESET_BAT fail param[0]=%x param[1]=%x param[2]=%x\n",param[0],param[1],param[2]); ++ ++ ++ ++ for(i=0;i<3;i++) ++ { ++ if(!ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) ++ break; ++ } ++ ++ for(i=0;i<3;i++) ++ { ++ if(!ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) ++ break; ++ } ++ ++ for(i=0;i<3;i++) ++ { ++ if(!ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) ++ break; ++ } ++ ++ for(i=0;i<3;i++) ++ { ++ if(!ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) ++ break; ++ } ++ ++ ++ if ((param[0] != 0x3c) || (param[1] != 0x03) || (param[2] != 0xc8)) ++ { ++ pr_info("elantech.c: unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", ++ param[0], param[1], param[2]); ++ return -1; ++ } ++ ++ printk(KERN_INFO "elantech.c: param[0]=%x param[1]=%x param[2]=%x\n",param[0],param[1],param[2]); ++ ++ /* Why does the Elantech Windows driver try this? ++ * For now just report it and see if it makes sense ++ * when more people use this driver ++ */ ++ ++ if (set_properties) { ++ psmouse->vendor = "Elantech"; ++ psmouse->reconnect =elantech_reconnect; ++ ++ //psmouse->name = "Touchpad"; ++ //printk(KERN_DEBUG "-elantech_detect Ok\n"); ++ } ++ //printk(KERN_DEBUG "-elantech_detect\n"); ++ return 0; ++ ++} ++ ++/* ++ * Initialize the touchpad and create sysfs entries ++ */ ++int elantech_init(struct psmouse *psmouse,int set_properties) ++{ ++ ++ struct elantech_data *priv; ++ unsigned char param[3]; ++ unsigned char d; ++ int error,err,i,j,m; ++ //printk(KERN_DEBUG "+elantech_init\n"); ++ ++ priv = kzalloc(sizeof(struct elantech_data), GFP_KERNEL); ++ psmouse->private = priv; ++ ++ if (!priv) ++ return -1; ++ ++ error=err= -1; ++ for(j=0;j<3;j++){ ++ for(i=0;i<4;i++){ ++ if(!ps2_command(&psmouse->ps2dev, NULL,PSMOUSE_CMD_SETSCALE11)) ++ break; ++ ++ } ++ ++ ++ for (i = 6; i >= 0; i -= 2) { ++ d = (0x01 >> i) & 3; ++ for(m=0;m<4;m++){ ++ if (!ps2_command(&psmouse->ps2dev, &d, PSMOUSE_CMD_SETRES)) ++ break; ++ } ++ } ++ ++ if(!ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)){ ++ printk(KERN_DEBUG "+elantech_init param[0]=%x param[1]=%x param[2]=%x\n",param[0],param[1],param[2]); ++ break; ++ }else{ ++ for(i=0;i<3;i++){ ++ if(!ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT)){ ++ printk(KERN_INFO "elantech_init: param[0]=%x param[1]=%x param[2]=%x\n",param[0],param[1],param[2]); ++ break; ++ } ++ } //FF ->reply FA AA 00 ++ printk(KERN_DEBUG "+elantech_init fw version error\n"); ++ ++ } ++ } ++ ++ if(param[0]==0x02 && param[1]==0x00 && param[2] == 0x22){ ++ err=elantech_set_4byte_defaults_EF013(psmouse); ++ if(err==0){ ++ printk(KERN_ERR "elantech.c:elantech_init 4 EF013\n"); ++ psmouse->protocol_handler = elantech_process_4byte_EF013; ++ psmouse->pktsize = 4; ++ psmouse->disconnect = elantech_disconnect; ++ psmouse->name = "Elantech Touchpad 4byte mode EF013"; ++ ++ } ++ } ++ else if(param[0]==0x02 && param[1]==0x06 && param[2] == 0x00){ ++ err=elantech_set_4byte_defaults_EF019(psmouse); ++ if(err==0){ ++ printk(KERN_ERR "elantech.c:elantech_init 4 EF019\n"); ++ psmouse->protocol_handler = elantech_process_4byte_EF019; ++ psmouse->pktsize = 4; ++ psmouse->disconnect = elantech_disconnect; ++ psmouse->name = "Elantech Touchpad 4byte mode EF019"; ++ ++ } ++ } ++ else if(param[0]==0x02 && param[1]==0x00 && param[2] == 0x30){ ++ err=elantech_set_6byte_defaults_EF113(psmouse); ++ if(err==0){ ++ printk(KERN_ERR "elantech.c:elantech_init 6 EF113\n"); ++ psmouse->protocol_handler = elantech_process_6byte_EF113; ++ psmouse->pktsize = 6; ++ psmouse->disconnect = elantech_disconnect; ++ psmouse->name = "Elantech Touchpad 6byte mode EF113"; ++ ++ } ++ } ++ else if(param[0]==0x02 && param[1]==0x08 && param[2] == 0x00){ ++ err=elantech_set_6byte_defaults_EF023(psmouse); ++ if(err==0){ ++ printk(KERN_ERR "elantech.c:elantech_init 6 EF023\n"); ++ psmouse->protocol_handler = elantech_process_6byte_EF023; ++ psmouse->pktsize = 6; ++ psmouse->disconnect = elantech_disconnect; ++ psmouse->name = "Elantech Touchpad 6byte mode EF023"; ++ ++ } ++ } ++ else if(param[0]==0x04 && param[1]==0x02 && param[2] == 0x00){ ++ err=elantech_set_6byte_defaults_EF051(psmouse); ++ if(err==0){ ++ printk(KERN_ERR "elantech.c:elantech_init 6 EF051\n"); ++ psmouse->protocol_handler = elantech_process_6byte_EF051; ++ psmouse->pktsize = 6; ++ psmouse->disconnect = elantech_disconnect; ++ psmouse->name = "Elantech Touchpad 6byte mode EF051"; ++ ++ } ++ } ++ else { ++ printk(KERN_DEBUG "elantech -- don't find fw version\n"); ++ err=1; ++ } ++ ++ ++ //err=1;//chris ++ if(err){ ++ for(i=0;i<3;i++){ ++ if(!ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT)){ ++ printk(KERN_ERR "elantech.c:err=%d param[0]=%x param[1]=%x param[2]=%x\n",err,param[0],param[1],param[2]); ++ break; ++ } ++ else ++ printk(KERN_ERR "elantech.c:err=%d FF command fail\n",err); ++ } ++ ++ }else{ ++ if(set_properties) ++ error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,&elantech_attr_group); ++ } ++ ++ if ((error && set_properties)||err) { ++ for(i=0;i<3;i++){ ++ if(!ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT)){ ++ printk(KERN_ERR "elantech.c:error=%d param[0]=%x param[1]=%x param[2]=%x\n",error,param[0],param[1],param[2]); ++ break; ++ } ++ else ++ printk(KERN_ERR "elantech.c:error=%d FF command fail\n",error); ++ } ++ ++ ++ //printk(KERN_ERR "elantech.c: failed to create sysfs attributes, error: %d\n",error); ++ psmouse->private=NULL; ++ kfree(priv); ++ return -1; ++ } ++ ++ ++ //printk(KERN_DEBUG "-elantech_init\n"); ++ return 0; ++} ++ +diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h +new file mode 100644 +index 0000000..7dff73f +--- /dev/null ++++ b/drivers/input/mouse/elantech.h +@@ -0,0 +1,34 @@ ++/* ++ * Elantech Touchpad driver ++ * ++ * Copyright (C) 2007 Arjan Opmeer ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ * Trademarks are the property of their respective owners. ++ */ ++ ++#ifndef _ELANTECH_H ++#define _ELANTECH_H ++ ++#define ELANTECH_COMMAND 0x11 /* Commands start with this value */ ++#define ELANTECH_FW_VER 0x01 /* Tom Lin */ ++struct elantech_data { ++ unsigned char reg_10; ++ unsigned char reg_11; ++ unsigned char reg_20; ++ unsigned char reg_21; ++ unsigned char reg_22; ++ unsigned char reg_23; ++ unsigned char reg_24; ++ unsigned char reg_25; ++ unsigned char reg_26; ++}; ++ ++ ++int elantech_detect(struct psmouse *psmouse, int set_properties); ++int elantech_init(struct psmouse *psmouse, int set_properties); ++ ++#endif +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0100-This-patch-adds-tracking-for-the-display-orientation.patch +++ linux-2.6.24/patches/0100-This-patch-adds-tracking-for-the-display-orientation.patch @@ -0,0 +1,93 @@ +From bcf3ae8da7482ed9c631e4a8a9840816d93d6ce8 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 25 Mar 2009 13:21:44 -0400 +Subject: [PATCH 100/170] This patch adds tracking for the display orientation which comes to us as a key event from the USB keyboard driver. We track the current status and export it using the proc file system. (LP# 320866) + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/320866 +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/input/input.c | 38 ++++++++++++++++++++++++++++++++++++++ + 1 files changed, 38 insertions(+), 0 deletions(-) + +diff --git a/drivers/input/input.c b/drivers/input/input.c +index a0be978..cb3b097 100644 +--- a/drivers/input/input.c ++++ b/drivers/input/input.c +@@ -41,6 +41,8 @@ static DEFINE_MUTEX(input_mutex); + + static struct input_handler *input_table[8]; + ++static int easelmode; ++ + static inline int is_event_supported(unsigned int code, + unsigned long *bm, unsigned int max) + { +@@ -72,6 +74,16 @@ static void input_pass_event(struct input_dev *dev, + { + struct input_handle *handle; + ++ /* ++ * Keep track of the display orientation, which is received as a keycode ++ */ ++ if (type == EV_KEY) { ++ if (code == KEY_F23) ++ easelmode = 1; ++ else if (code == KEY_F24) ++ easelmode = 0; ++ } ++ + rcu_read_lock(); + + handle = rcu_dereference(dev->grab); +@@ -828,6 +840,22 @@ static const struct file_operations input_handlers_fileops = { + .release = seq_release, + }; + ++static int proc_read_easelmode(char *buffer, char **buffer_location, ++ off_t offset, int buffer_length, ++ int *eof, void *data) ++{ ++ int ret; ++ ++ if (offset > 0) ++ ret = 0; ++ else ++ ret = sprintf(buffer, "%1d\n", easelmode); ++ ++ return ret; ++ ++} ++ ++ + static int __init input_proc_init(void) + { + struct proc_dir_entry *entry; +@@ -852,8 +880,17 @@ static int __init input_proc_init(void) + entry->owner = THIS_MODULE; + entry->proc_fops = &input_handlers_fileops; + ++ entry = create_proc_entry("easelmode", 0, proc_bus_input_dir); ++ if (!entry) ++ goto fail3; ++ ++ entry->owner = THIS_MODULE; ++ entry->read_proc = proc_read_easelmode; ++ entry->size = 8; ++ + return 0; + ++ fail3: remove_proc_entry("easelmode", proc_bus_input_dir); + fail2: remove_proc_entry("devices", proc_bus_input_dir); + fail1: remove_proc_entry("input", proc_bus); + return -ENOMEM; +@@ -861,6 +898,7 @@ static int __init input_proc_init(void) + + static void input_proc_exit(void) + { ++ remove_proc_entry("easelmode", proc_bus_input_dir); + remove_proc_entry("devices", proc_bus_input_dir); + remove_proc_entry("handlers", proc_bus_input_dir); + remove_proc_entry("input", proc_bus); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0078-Misc-fixes-for-kgdb-build.patch +++ linux-2.6.24/patches/0078-Misc-fixes-for-kgdb-build.patch @@ -0,0 +1,242 @@ +From 2d5c2937636308af12ad3465629d68a44fccb994 Mon Sep 17 00:00:00 2001 +From: =?utf-8?q?Lo=C3=AFc=20Minier?= +Date: Mon, 17 Nov 2008 22:52:45 +0100 +Subject: [PATCH 078/170] Misc fixes for kgdb build + +- add kgdb config +- include asm-x86/processor.h +- fix asm-x86/processor.h to always export early_init +- fix 0001-dabney_thermal patch to apply against the config with KGDB + config +- fix reg names +--- + arch/x86/kernel/kgdb.c | 72 ++++++++++---------- + arch/x86/kernel/setup_32.c | 1 + + debian/binary-custom.d/lpia/config.lpia | 7 ++- + .../lpia/patchset/0001-dabney_thermal.patch | 4 +- + include/asm-x86/processor.h | 6 +- + 5 files changed, 48 insertions(+), 42 deletions(-) + +diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c +index 8c7e555..53707f6 100644 +--- a/arch/x86/kernel/kgdb.c ++++ b/arch/x86/kernel/kgdb.c +@@ -73,19 +73,19 @@ static int gdb_x86vector = -1; + */ + void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) + { +- gdb_regs[GDB_AX] = regs->ax; +- gdb_regs[GDB_BX] = regs->bx; +- gdb_regs[GDB_CX] = regs->cx; +- gdb_regs[GDB_DX] = regs->dx; +- gdb_regs[GDB_SI] = regs->si; +- gdb_regs[GDB_DI] = regs->di; +- gdb_regs[GDB_BP] = regs->bp; +- gdb_regs[GDB_PS] = regs->flags; +- gdb_regs[GDB_PC] = regs->ip; ++ gdb_regs[GDB_AX] = regs->eax; ++ gdb_regs[GDB_BX] = regs->ebx; ++ gdb_regs[GDB_CX] = regs->ecx; ++ gdb_regs[GDB_DX] = regs->edx; ++ gdb_regs[GDB_SI] = regs->esi; ++ gdb_regs[GDB_DI] = regs->edi; ++ gdb_regs[GDB_BP] = regs->ebp; ++ gdb_regs[GDB_PS] = regs->eflags; ++ gdb_regs[GDB_PC] = regs->eip; + #ifdef CONFIG_X86_32 +- gdb_regs[GDB_DS] = regs->ds; +- gdb_regs[GDB_ES] = regs->es; +- gdb_regs[GDB_CS] = regs->cs; ++ gdb_regs[GDB_DS] = regs->xds; ++ gdb_regs[GDB_ES] = regs->xes; ++ gdb_regs[GDB_CS] = regs->xcs; + gdb_regs[GDB_SS] = __KERNEL_DS; + gdb_regs[GDB_FS] = 0xFFFF; + gdb_regs[GDB_GS] = 0xFFFF; +@@ -99,7 +99,7 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) + gdb_regs[GDB_R14] = regs->r14; + gdb_regs[GDB_R15] = regs->r15; + #endif +- gdb_regs[GDB_SP] = regs->sp; ++ gdb_regs[GDB_SP] = regs->esp; + } + + /** +@@ -122,18 +122,18 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) + gdb_regs[GDB_DX] = 0; + gdb_regs[GDB_SI] = 0; + gdb_regs[GDB_DI] = 0; +- gdb_regs[GDB_BP] = *(unsigned long *)p->thread.sp; ++ gdb_regs[GDB_BP] = *(unsigned long *)p->thread.esp; + #ifdef CONFIG_X86_32 + gdb_regs[GDB_DS] = __KERNEL_DS; + gdb_regs[GDB_ES] = __KERNEL_DS; + gdb_regs[GDB_PS] = 0; + gdb_regs[GDB_CS] = __KERNEL_CS; +- gdb_regs[GDB_PC] = p->thread.ip; ++ gdb_regs[GDB_PC] = p->thread.eip; + gdb_regs[GDB_SS] = __KERNEL_DS; + gdb_regs[GDB_FS] = 0xFFFF; + gdb_regs[GDB_GS] = 0xFFFF; + #else +- gdb_regs[GDB_PS] = *(unsigned long *)(p->thread.sp + 8); ++ gdb_regs[GDB_PS] = *(unsigned long *)(p->thread.esp + 8); + gdb_regs[GDB_PC] = 0; + gdb_regs[GDB_R8] = 0; + gdb_regs[GDB_R9] = 0; +@@ -144,7 +144,7 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) + gdb_regs[GDB_R14] = 0; + gdb_regs[GDB_R15] = 0; + #endif +- gdb_regs[GDB_SP] = p->thread.sp; ++ gdb_regs[GDB_SP] = p->thread.esp; + } + + /** +@@ -157,19 +157,19 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) + */ + void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) + { +- regs->ax = gdb_regs[GDB_AX]; +- regs->bx = gdb_regs[GDB_BX]; +- regs->cx = gdb_regs[GDB_CX]; +- regs->dx = gdb_regs[GDB_DX]; +- regs->si = gdb_regs[GDB_SI]; +- regs->di = gdb_regs[GDB_DI]; +- regs->bp = gdb_regs[GDB_BP]; +- regs->flags = gdb_regs[GDB_PS]; +- regs->ip = gdb_regs[GDB_PC]; ++ regs->eax = gdb_regs[GDB_AX]; ++ regs->ebx = gdb_regs[GDB_BX]; ++ regs->ecx = gdb_regs[GDB_CX]; ++ regs->edx = gdb_regs[GDB_DX]; ++ regs->esi = gdb_regs[GDB_SI]; ++ regs->edi = gdb_regs[GDB_DI]; ++ regs->ebp = gdb_regs[GDB_BP]; ++ regs->eflags = gdb_regs[GDB_PS]; ++ regs->eip = gdb_regs[GDB_PC]; + #ifdef CONFIG_X86_32 +- regs->ds = gdb_regs[GDB_DS]; +- regs->es = gdb_regs[GDB_ES]; +- regs->cs = gdb_regs[GDB_CS]; ++ regs->xds = gdb_regs[GDB_DS]; ++ regs->xes = gdb_regs[GDB_ES]; ++ regs->xcs = gdb_regs[GDB_CS]; + #else + regs->r8 = gdb_regs[GDB_R8]; + regs->r9 = gdb_regs[GDB_R9]; +@@ -369,18 +369,18 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, + /* try to read optional parameter, pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + if (kgdb_hex2long(&ptr, &addr)) +- linux_regs->ip = addr; ++ linux_regs->eip = addr; + case 'D': + case 'k': +- newPC = linux_regs->ip; ++ newPC = linux_regs->eip; + + /* clear the trace bit */ +- linux_regs->flags &= ~TF_MASK; ++ linux_regs->eflags &= ~TF_MASK; + atomic_set(&kgdb_cpu_doing_single_step, -1); + + /* set the trace bit if we're stepping */ + if (remcomInBuffer[0] == 's') { +- linux_regs->flags |= TF_MASK; ++ linux_regs->eflags |= TF_MASK; + kgdb_single_step = 1; + if (kgdb_contthread) { + atomic_set(&kgdb_cpu_doing_single_step, +@@ -396,7 +396,7 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, + if (dr6 & (1 << breakno) && + breakinfo[breakno].type == 0) { + /* Set restore flag: */ +- linux_regs->flags |= X86_EFLAGS_RF; ++ linux_regs->eflags |= X86_EFLAGS_RF; + break; + } + } +@@ -546,8 +546,8 @@ void kgdb_arch_exit(void) + */ + int kgdb_skipexception(int exception, struct pt_regs *regs) + { +- if (exception == 3 && kgdb_isremovedbreak(regs->ip - 1)) { +- regs->ip -= 1; ++ if (exception == 3 && kgdb_isremovedbreak(regs->eip - 1)) { ++ regs->eip -= 1; + return 1; + } + return 0; +diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c +index 3455481..22efba7 100644 +--- a/arch/x86/kernel/setup_32.c ++++ b/arch/x86/kernel/setup_32.c +@@ -55,6 +55,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/debian/binary-custom.d/lpia/config.lpia b/debian/binary-custom.d/lpia/config.lpia +index 53f1f4c..6ca6fbc 100644 +--- a/debian/binary-custom.d/lpia/config.lpia ++++ b/debian/binary-custom.d/lpia/config.lpia +@@ -507,6 +507,11 @@ CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m + CONFIG_IPV6_SIT=m + CONFIG_IPV6_TUNNEL=m + # CONFIG_IPV6_MULTIPLE_TABLES is not set ++CONFIG_KGDB=y ++CONFIG_KGDBOE=y ++# CONFIG_KGDB_8250 is not set ++CONFIG_KGDB_SERIAL_CONSOLE=y ++# CONFIG_KGDB_TESTS is not set + CONFIG_NETWORK_SECMARK=y + CONFIG_NETFILTER=y + # CONFIG_NETFILTER_DEBUG is not set +@@ -1690,7 +1695,7 @@ CONFIG_SHAPER=m + CONFIG_NETCONSOLE=m + CONFIG_NETCONSOLE_DYNAMIC=y + CONFIG_NETPOLL=y +-# CONFIG_NETPOLL_TRAP is not set ++CONFIG_NETPOLL_TRAP=y + CONFIG_NET_POLL_CONTROLLER=y + CONFIG_VIRTIO_NET=m + # CONFIG_ISDN is not set +diff --git a/debian/binary-custom.d/lpia/patchset/0001-dabney_thermal.patch b/debian/binary-custom.d/lpia/patchset/0001-dabney_thermal.patch +index 855aed2..850ebd3 100644 +--- a/debian/binary-custom.d/lpia/patchset/0001-dabney_thermal.patch ++++ b/debian/binary-custom.d/lpia/patchset/0001-dabney_thermal.patch +@@ -1635,10 +1635,10 @@ diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile + index 87f2685..a9e8faf 100644 + --- a/drivers/misc/Makefile + +++ b/drivers/misc/Makefile +-@@ -17,3 +17,4 @@ obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o +- obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o ++@@ -17,3 +17,4 @@ + obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o + obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o ++ obj-$(CONFIG_KGDB_TESTS) += kgdbts.o + +obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o + diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c + new file mode 100644 +diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h +index 93a4e19..74b08b4 100644 +--- a/include/asm-x86/processor.h ++++ b/include/asm-x86/processor.h +@@ -1,7 +1,7 @@ +-#ifdef CONFIG_X86_32 ++extern void early_trap_init(void); ++ ++#if defined(CONFIG_X86_32) + # include "processor_32.h" + #else + # include "processor_64.h" +-extern void early_trap_init(void); +- + #endif +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0135-UBUNTU-NBK-Ubuntu-2.6.24-24.51netbook11.patch +++ linux-2.6.24/patches/0135-UBUNTU-NBK-Ubuntu-2.6.24-24.51netbook11.patch @@ -0,0 +1,75 @@ +From 1babcd4f847d9b9df938ee3244552f69bbd336e3 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Wed, 8 Apr 2009 12:57:24 -0500 +Subject: [PATCH 135/170] UBUNTU: NBK-Ubuntu-2.6.24-24.51netbook11 + +Signed-off-by: Steve Conklin +--- + debian/changelog | 53 +++++++++++++++++++++++++++++++++++++++++++++++++---- + 1 files changed, 49 insertions(+), 4 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 4f241ad..0989075 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,8 +1,53 @@ +-linux (2.6.24-24.51netbook11) UNRELEASED; urgency=low ++linux (2.6.24-24.51netbook11) netbook-common; urgency=low + +- CHANGELOG: Do not edit directly. Autogenerated at release. +- CHANGELOG: Use the printchanges target to see the curent changes. +- CHANGELOG: Use the insertchanges target to create the final log. ++ [Andy Whitcroft] ++ ++ * rebase against distro version Ubuntu-2.6.24-24.51 ++ * temporarily reinstroduce a null patch ++ * SAUCE: reorder acpi/Makefile avoiding sysfs duplicate insert warning ++ - LP: #355977 ++ * fix rebase script to use correct tag names for netbook ++ ++ [Steve Conklin] ++ ++ * SAUCE: hardy netbook-lpia branch display easel mode ++ - LP: #320866 ++ * SAUCE: hardy netbook-lpia - Expose EEPROM antenna configuration data ++ - LP: #352439 ++ ++ [Upstream Kernel Changes] ++ ++ * Turn debian/binary-custom.d/lpia/patchset/0001-dabney_thermal.patch ++ into a commit. ++ - LP: #291457 ++ * Turn debian/binary-custom.d/lpia/patchset/0010-hda_sigmatel.patch into ++ a commit. ++ * Turn ++ debian/binary-custom.d/lpia/patchset/0012-poulsbo_hda_class_id.patch ++ into a commit. ++ * Turn debian/binary-custom.d/lpia/patchset/0013-poulsbo_pci_ids.patch ++ into a commit. ++ * Turn debian/binary-custom.d/lpia/patchset/0014-poulsbo_hda.patch into a ++ commit. ++ * Turn debian/binary-custom.d/lpia/patchset/0015-poulsbo_smbus.patch into ++ a commit. ++ * Turn debian/binary-custom.d/lpia/patchset/0016-poulsbo_ide.patch into a ++ commit. ++ * Turn debian/binary-custom.d/lpia/patchset/0017-poulsbo_USBC.patch into ++ a commit. ++ * Turn debian/binary-custom.d/lpia/patchset/0018-sdio_crown_beach.patch ++ into a commit. ++ - LP: #291457 ++ * Turn ++ debian/binary-custom.d/lpia/patchset/0020-ts-doubleclick-workaround.pat ++ ch into a commit. ++ * Turn debian/binary-custom.d/lpia/patchset/0021-legacy-usb-int-fix.patch ++ into a commit. ++ * Turn ++ debian/binary-custom.d/lpia/patchset/0022-usb_reset_resume_quirk.patch ++ into a commit. ++ * Turn debian/binary-custom.d/lpia/patchset/0023-crown_beach_reboot.patch ++ into a commit. + + [Distro Changes] + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0006-x86-kgdb-support.patch +++ linux-2.6.24/patches/0006-x86-kgdb-support.patch @@ -0,0 +1,564 @@ +From 8578553aa9631e1ca01393a19ad5efc44792c523 Mon Sep 17 00:00:00 2001 +From: Ingo Molnar +Date: Mon, 10 Mar 2008 08:41:28 +0100 +Subject: [PATCH 006/170] x86: kgdb support + +simplified and streamlined kgdb support on x86, both 32-bit and 64-bit, +based on patch from: + + Subject: kgdb: core-lite + From: Jason Wessel + +[ and countless other authors - see the patch for details. ] + +Signed-off-by: Ingo Molnar +Signed-off-by: Jason Wessel +Signed-off-by: Jan Kiszka +Reviewed-by: Thomas Gleixner +--- + arch/x86/Kconfig | 1 + + arch/x86/kernel/Makefile | 2 + + arch/x86/kernel/kgdb.c | 417 ++++++++++++++++++++++++++++++++++++++++++++++ + include/asm-x86/kgdb.h | 81 +++++++++ + 4 files changed, 501 insertions(+), 0 deletions(-) + create mode 100644 arch/x86/kernel/kgdb.c + create mode 100644 include/asm-x86/kgdb.h + +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index 6a2ef47..ca939e6 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -18,6 +18,7 @@ config X86_64 + ### Arch settings + config X86 + bool ++ select HAVE_ARCH_KGDB + default y + + config GENERIC_TIME +diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile +index 3857334..565f98f 100644 +--- a/arch/x86/kernel/Makefile ++++ b/arch/x86/kernel/Makefile +@@ -4,6 +4,8 @@ else + include ${srctree}/arch/x86/kernel/Makefile_64 + endif + ++obj-$(CONFIG_KGDB) += kgdb.o ++ + # Workaround to delete .lds files with make clean + # The problem is that we do not enter Makefile_32 with make clean. + clean-files := vsyscall*.lds vsyscall*.so +diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c +new file mode 100644 +index 0000000..37194d6 +--- /dev/null ++++ b/arch/x86/kernel/kgdb.c +@@ -0,0 +1,417 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2, or (at your option) any ++ * later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ */ ++ ++/* ++ * Copyright (C) 2004 Amit S. Kale ++ * Copyright (C) 2000-2001 VERITAS Software Corporation. ++ * Copyright (C) 2002 Andi Kleen, SuSE Labs ++ * Copyright (C) 2004 LinSysSoft Technologies Pvt. Ltd. ++ * Copyright (C) 2007 MontaVista Software, Inc. ++ * Copyright (C) 2007-2008 Jason Wessel, Wind River Systems, Inc. ++ */ ++/**************************************************************************** ++ * Contributor: Lake Stevens Instrument Division$ ++ * Written by: Glenn Engel $ ++ * Updated by: Amit Kale ++ * Updated by: Tom Rini ++ * Updated by: Jason Wessel ++ * Modified for 386 by Jim Kingdon, Cygnus Support. ++ * Origianl kgdb, compatibility with 2.1.xx kernel by ++ * David Grothe ++ * Integrated into 2.2.5 kernel by Tigran Aivazian ++ * X86_64 changes from Andi Kleen's patch merged by Jim Houston ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#ifdef CONFIG_X86_32 ++# include ++#else ++# include ++#endif ++ ++/* ++ * Put the error code here just in case the user cares: ++ */ ++static int gdb_x86errcode; ++ ++/* ++ * Likewise, the vector number here (since GDB only gets the signal ++ * number through the usual means, and that's not very specific): ++ */ ++static int gdb_x86vector = -1; ++ ++/** ++ * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs ++ * @gdb_regs: A pointer to hold the registers in the order GDB wants. ++ * @regs: The &struct pt_regs of the current process. ++ * ++ * Convert the pt_regs in @regs into the format for registers that ++ * GDB expects, stored in @gdb_regs. ++ */ ++void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) ++{ ++ gdb_regs[GDB_AX] = regs->ax; ++ gdb_regs[GDB_BX] = regs->bx; ++ gdb_regs[GDB_CX] = regs->cx; ++ gdb_regs[GDB_DX] = regs->dx; ++ gdb_regs[GDB_SI] = regs->si; ++ gdb_regs[GDB_DI] = regs->di; ++ gdb_regs[GDB_BP] = regs->bp; ++ gdb_regs[GDB_PS] = regs->flags; ++ gdb_regs[GDB_PC] = regs->ip; ++#ifdef CONFIG_X86_32 ++ gdb_regs[GDB_DS] = regs->ds; ++ gdb_regs[GDB_ES] = regs->es; ++ gdb_regs[GDB_CS] = regs->cs; ++ gdb_regs[GDB_SS] = __KERNEL_DS; ++ gdb_regs[GDB_FS] = 0xFFFF; ++ gdb_regs[GDB_GS] = 0xFFFF; ++#else ++ gdb_regs[GDB_R8] = regs->r8; ++ gdb_regs[GDB_R9] = regs->r9; ++ gdb_regs[GDB_R10] = regs->r10; ++ gdb_regs[GDB_R11] = regs->r11; ++ gdb_regs[GDB_R12] = regs->r12; ++ gdb_regs[GDB_R13] = regs->r13; ++ gdb_regs[GDB_R14] = regs->r14; ++ gdb_regs[GDB_R15] = regs->r15; ++#endif ++ gdb_regs[GDB_SP] = regs->sp; ++} ++ ++/** ++ * sleeping_thread_to_gdb_regs - Convert ptrace regs to GDB regs ++ * @gdb_regs: A pointer to hold the registers in the order GDB wants. ++ * @p: The &struct task_struct of the desired process. ++ * ++ * Convert the register values of the sleeping process in @p to ++ * the format that GDB expects. ++ * This function is called when kgdb does not have access to the ++ * &struct pt_regs and therefore it should fill the gdb registers ++ * @gdb_regs with what has been saved in &struct thread_struct ++ * thread field during switch_to. ++ */ ++void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) ++{ ++ gdb_regs[GDB_AX] = 0; ++ gdb_regs[GDB_BX] = 0; ++ gdb_regs[GDB_CX] = 0; ++ gdb_regs[GDB_DX] = 0; ++ gdb_regs[GDB_SI] = 0; ++ gdb_regs[GDB_DI] = 0; ++ gdb_regs[GDB_BP] = *(unsigned long *)p->thread.sp; ++#ifdef CONFIG_X86_32 ++ gdb_regs[GDB_DS] = __KERNEL_DS; ++ gdb_regs[GDB_ES] = __KERNEL_DS; ++ gdb_regs[GDB_PS] = 0; ++ gdb_regs[GDB_CS] = __KERNEL_CS; ++ gdb_regs[GDB_PC] = p->thread.ip; ++ gdb_regs[GDB_SS] = __KERNEL_DS; ++ gdb_regs[GDB_FS] = 0xFFFF; ++ gdb_regs[GDB_GS] = 0xFFFF; ++#else ++ gdb_regs[GDB_PS] = *(unsigned long *)(p->thread.sp + 8); ++ gdb_regs[GDB_PC] = 0; ++ gdb_regs[GDB_R8] = 0; ++ gdb_regs[GDB_R9] = 0; ++ gdb_regs[GDB_R10] = 0; ++ gdb_regs[GDB_R11] = 0; ++ gdb_regs[GDB_R12] = 0; ++ gdb_regs[GDB_R13] = 0; ++ gdb_regs[GDB_R14] = 0; ++ gdb_regs[GDB_R15] = 0; ++#endif ++ gdb_regs[GDB_SP] = p->thread.sp; ++} ++ ++/** ++ * gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs. ++ * @gdb_regs: A pointer to hold the registers we've received from GDB. ++ * @regs: A pointer to a &struct pt_regs to hold these values in. ++ * ++ * Convert the GDB regs in @gdb_regs into the pt_regs, and store them ++ * in @regs. ++ */ ++void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) ++{ ++ regs->ax = gdb_regs[GDB_AX]; ++ regs->bx = gdb_regs[GDB_BX]; ++ regs->cx = gdb_regs[GDB_CX]; ++ regs->dx = gdb_regs[GDB_DX]; ++ regs->si = gdb_regs[GDB_SI]; ++ regs->di = gdb_regs[GDB_DI]; ++ regs->bp = gdb_regs[GDB_BP]; ++ regs->flags = gdb_regs[GDB_PS]; ++ regs->ip = gdb_regs[GDB_PC]; ++#ifdef CONFIG_X86_32 ++ regs->ds = gdb_regs[GDB_DS]; ++ regs->es = gdb_regs[GDB_ES]; ++ regs->cs = gdb_regs[GDB_CS]; ++#else ++ regs->r8 = gdb_regs[GDB_R8]; ++ regs->r9 = gdb_regs[GDB_R9]; ++ regs->r10 = gdb_regs[GDB_R10]; ++ regs->r11 = gdb_regs[GDB_R11]; ++ regs->r12 = gdb_regs[GDB_R12]; ++ regs->r13 = gdb_regs[GDB_R13]; ++ regs->r14 = gdb_regs[GDB_R14]; ++ regs->r15 = gdb_regs[GDB_R15]; ++#endif ++} ++ ++/** ++ * kgdb_post_primary_code - Save error vector/code numbers. ++ * @regs: Original pt_regs. ++ * @e_vector: Original error vector. ++ * @err_code: Original error code. ++ * ++ * This is needed on architectures which support SMP and KGDB. ++ * This function is called after all the slave cpus have been put ++ * to a know spin state and the primary CPU has control over KGDB. ++ */ ++void kgdb_post_primary_code(struct pt_regs *regs, int e_vector, int err_code) ++{ ++ /* primary processor is completely in the debugger */ ++ gdb_x86vector = e_vector; ++ gdb_x86errcode = err_code; ++} ++ ++#ifdef CONFIG_SMP ++/** ++ * kgdb_roundup_cpus - Get other CPUs into a holding pattern ++ * @flags: Current IRQ state ++ * ++ * On SMP systems, we need to get the attention of the other CPUs ++ * and get them be in a known state. This should do what is needed ++ * to get the other CPUs to call kgdb_wait(). Note that on some arches, ++ * the NMI approach is not used for rounding up all the CPUs. For example, ++ * in case of MIPS, smp_call_function() is used to roundup CPUs. In ++ * this case, we have to make sure that interrupts are enabled before ++ * calling smp_call_function(). The argument to this function is ++ * the flags that will be used when restoring the interrupts. There is ++ * local_irq_save() call before kgdb_roundup_cpus(). ++ * ++ * On non-SMP systems, this is not called. ++ */ ++void kgdb_roundup_cpus(unsigned long flags) ++{ ++ send_IPI_allbutself(APIC_DM_NMI); ++} ++#endif ++ ++/** ++ * kgdb_arch_handle_exception - Handle architecture specific GDB packets. ++ * @vector: The error vector of the exception that happened. ++ * @signo: The signal number of the exception that happened. ++ * @err_code: The error code of the exception that happened. ++ * @remcom_in_buffer: The buffer of the packet we have read. ++ * @remcom_out_buffer: The buffer of %BUFMAX bytes to write a packet into. ++ * @regs: The &struct pt_regs of the current process. ++ * ++ * This function MUST handle the 'c' and 's' command packets, ++ * as well packets to set / remove a hardware breakpoint, if used. ++ * If there are additional packets which the hardware needs to handle, ++ * they are handled here. The code should return -1 if it wants to ++ * process more packets, and a %0 or %1 if it wants to exit from the ++ * kgdb callback. ++ */ ++int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, ++ char *remcomInBuffer, char *remcomOutBuffer, ++ struct pt_regs *linux_regs) ++{ ++ unsigned long addr; ++ char *ptr; ++ int newPC; ++ ++ switch (remcomInBuffer[0]) { ++ case 'c': ++ case 's': ++ /* try to read optional parameter, pc unchanged if no parm */ ++ ptr = &remcomInBuffer[1]; ++ if (kgdb_hex2long(&ptr, &addr)) ++ linux_regs->ip = addr; ++ newPC = linux_regs->ip; ++ ++ /* clear the trace bit */ ++ linux_regs->flags &= ~TF_MASK; ++ atomic_set(&kgdb_cpu_doing_single_step, -1); ++ ++ /* set the trace bit if we're stepping */ ++ if (remcomInBuffer[0] == 's') { ++ linux_regs->flags |= TF_MASK; ++ kgdb_single_step = 1; ++ if (kgdb_contthread) { ++ atomic_set(&kgdb_cpu_doing_single_step, ++ raw_smp_processor_id()); ++ } ++ } ++ ++ return 0; ++ } ++ ++ /* this means that we do not want to exit from the handler: */ ++ return -1; ++} ++ ++static inline int ++single_step_cont(struct pt_regs *regs, struct die_args *args) ++{ ++ /* ++ * Single step exception from kernel space to user space so ++ * eat the exception and continue the process: ++ */ ++ printk(KERN_ERR "KGDB: trap/step from kernel to user space, " ++ "resuming...\n"); ++ kgdb_arch_handle_exception(args->trapnr, args->signr, ++ args->err, "c", "", regs); ++ ++ return NOTIFY_STOP; ++} ++ ++static int __kgdb_notify(struct die_args *args, unsigned long cmd) ++{ ++ struct pt_regs *regs = args->regs; ++ ++ switch (cmd) { ++ case DIE_NMI: ++ if (atomic_read(&kgdb_active) != -1) { ++ /* KGDB CPU roundup */ ++ kgdb_nmicallback(raw_smp_processor_id(), regs); ++ return NOTIFY_STOP; ++ } ++ return NOTIFY_DONE; ++ ++ case DIE_NMI_IPI: ++ if (atomic_read(&kgdb_active) != -1) { ++ /* KGDB CPU roundup: */ ++ if (kgdb_nmicallback(raw_smp_processor_id(), regs)) ++ return NOTIFY_DONE; ++ return NOTIFY_STOP; ++ } ++ return NOTIFY_DONE; ++ ++ case DIE_NMIWATCHDOG: ++ if (atomic_read(&kgdb_active) != -1) { ++ /* KGDB CPU roundup: */ ++ kgdb_nmicallback(raw_smp_processor_id(), regs); ++ return NOTIFY_STOP; ++ } ++ /* Enter debugger: */ ++ break; ++ ++ case DIE_DEBUG: ++ if (atomic_read(&kgdb_cpu_doing_single_step) == ++ raw_smp_processor_id() && ++ user_mode(regs)) ++ return single_step_cont(regs, args); ++ /* fall through */ ++ default: ++ if (user_mode(regs)) ++ return NOTIFY_DONE; ++ } ++ ++ if (kgdb_handle_exception(args->trapnr, args->signr, args->err, regs)) ++ return NOTIFY_DONE; ++ ++ return NOTIFY_STOP; ++} ++ ++static int ++kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) ++{ ++ unsigned long flags; ++ int ret; ++ ++ local_irq_save(flags); ++ ret = __kgdb_notify(ptr, cmd); ++ local_irq_restore(flags); ++ ++ return ret; ++} ++ ++static struct notifier_block kgdb_notifier = { ++ .notifier_call = kgdb_notify, ++ ++ /* ++ * Lowest-prio notifier priority, we want to be notified last: ++ */ ++ .priority = -INT_MAX, ++}; ++ ++/** ++ * kgdb_arch_init - Perform any architecture specific initalization. ++ * ++ * This function will handle the initalization of any architecture ++ * specific callbacks. ++ */ ++int kgdb_arch_init(void) ++{ ++ return register_die_notifier(&kgdb_notifier); ++} ++ ++/** ++ * kgdb_arch_exit - Perform any architecture specific uninitalization. ++ * ++ * This function will handle the uninitalization of any architecture ++ * specific callbacks, for dynamic registration and unregistration. ++ */ ++void kgdb_arch_exit(void) ++{ ++ unregister_die_notifier(&kgdb_notifier); ++} ++ ++/** ++ * ++ * kgdb_skipexception - Bail out of KGDB when we've been triggered. ++ * @exception: Exception vector number ++ * @regs: Current &struct pt_regs. ++ * ++ * On some architectures we need to skip a breakpoint exception when ++ * it occurs after a breakpoint has been removed. ++ * ++ * Skip an int3 exception when it occurs after a breakpoint has been ++ * removed. Backtrack eip by 1 since the int3 would have caused it to ++ * increment by 1. ++ */ ++int kgdb_skipexception(int exception, struct pt_regs *regs) ++{ ++ if (exception == 3 && kgdb_isremovedbreak(regs->ip - 1)) { ++ regs->ip -= 1; ++ return 1; ++ } ++ return 0; ++} ++ ++unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs) ++{ ++ if (exception == 3) ++ return instruction_pointer(regs) - 1; ++ return instruction_pointer(regs); ++} ++ ++struct kgdb_arch arch_kgdb_ops = { ++ /* Breakpoint instruction: */ ++ .gdb_bpt_instr = { 0xcc }, ++}; +diff --git a/include/asm-x86/kgdb.h b/include/asm-x86/kgdb.h +new file mode 100644 +index 0000000..484c475 +--- /dev/null ++++ b/include/asm-x86/kgdb.h +@@ -0,0 +1,81 @@ ++#ifndef _ASM_KGDB_H_ ++#define _ASM_KGDB_H_ ++ ++/* ++ * Copyright (C) 2001-2004 Amit S. Kale ++ * Copyright (C) 2008 Wind River Systems, Inc. ++ */ ++ ++/* ++ * BUFMAX defines the maximum number of characters in inbound/outbound ++ * buffers at least NUMREGBYTES*2 are needed for register packets ++ * Longer buffer is needed to list all threads ++ */ ++#define BUFMAX 1024 ++ ++/* ++ * Note that this register image is in a different order than ++ * the register image that Linux produces at interrupt time. ++ * ++ * Linux's register image is defined by struct pt_regs in ptrace.h. ++ * Just why GDB uses a different order is a historical mystery. ++ */ ++#ifdef CONFIG_X86_32 ++enum regnames { ++ GDB_AX, /* 0 */ ++ GDB_CX, /* 1 */ ++ GDB_DX, /* 2 */ ++ GDB_BX, /* 3 */ ++ GDB_SP, /* 4 */ ++ GDB_BP, /* 5 */ ++ GDB_SI, /* 6 */ ++ GDB_DI, /* 7 */ ++ GDB_PC, /* 8 also known as eip */ ++ GDB_PS, /* 9 also known as eflags */ ++ GDB_CS, /* 10 */ ++ GDB_SS, /* 11 */ ++ GDB_DS, /* 12 */ ++ GDB_ES, /* 13 */ ++ GDB_FS, /* 14 */ ++ GDB_GS, /* 15 */ ++}; ++#else /* ! CONFIG_X86_32 */ ++enum regnames { ++ GDB_AX, /* 0 */ ++ GDB_DX, /* 1 */ ++ GDB_CX, /* 2 */ ++ GDB_BX, /* 3 */ ++ GDB_SI, /* 4 */ ++ GDB_DI, /* 5 */ ++ GDB_BP, /* 6 */ ++ GDB_SP, /* 7 */ ++ GDB_R8, /* 8 */ ++ GDB_R9, /* 9 */ ++ GDB_R10, /* 10 */ ++ GDB_R11, /* 11 */ ++ GDB_R12, /* 12 */ ++ GDB_R13, /* 13 */ ++ GDB_R14, /* 14 */ ++ GDB_R15, /* 15 */ ++ GDB_PC, /* 16 */ ++ GDB_PS, /* 17 */ ++}; ++#endif /* CONFIG_X86_32 */ ++ ++/* ++ * Number of bytes of registers: ++ */ ++#ifdef CONFIG_X86_32 ++# define NUMREGBYTES 64 ++#else ++# define NUMREGBYTES ((GDB_PS+1)*8) ++#endif ++ ++static inline void arch_kgdb_breakpoint(void) ++{ ++ asm(" int $3"); ++} ++#define BREAK_INSTR_SIZE 1 ++#define CACHE_FLUSH_IS_SAFE 1 ++ ++#endif /* _ASM_KGDB_H_ */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0071-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook9.patch +++ linux-2.6.24/patches/0071-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook9.patch @@ -0,0 +1,31 @@ +From 9bce6d27ba3ac355adab5415fac0e79bef623ecb Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Fri, 24 Oct 2008 18:59:44 -0400 +Subject: [PATCH 071/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook9 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 9 +++++++++ + 1 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 80561f2..770f62b 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,12 @@ ++linux (2.6.24-19.41netbook9) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * debian/binary-custom.d/lpia/config.lpia. Turned on HIGHMEM and ++ HIGHMEM4G as well as enabled SECURITY configs to match the 386 kernel. ++ ++ -- Michael Frey Fri, 24 Oct 2008 18:57:07 -0400 ++ + linux (2.6.24-19.41netbook8) hardy; urgency=low + + [Upstream Kernel Changes] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0013-kgdb-fix-optional-arch-functions-and-probe_kernel_.patch +++ linux-2.6.24/patches/0013-kgdb-fix-optional-arch-functions-and-probe_kernel_.patch @@ -0,0 +1,82 @@ +From c72c40b517d554af5a8674796ef574636b42533e Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Wed, 20 Feb 2008 13:33:38 -0600 +Subject: [PATCH 013/170] kgdb: fix optional arch functions and probe_kernel_* + +Fix two regressions dealing with the kgdb core. + +1) kgdb_skipexception and kgdb_post_primary_code are optional +functions that are only required on archs that need special exception +fixups. + +2) The kernel address space scope must be set on any probe_kernel_* +function or archs such as ARCH=arm will not allow access to the kernel +memory space. As an example, it is required to allow the full kernel +address space is when you the kernel debugger to inspect a system +call. + +Signed-off-by: Jason Wessel +Signed-off-by: Ingo Molnar +--- + kernel/kgdb.c | 11 +++++++++++ + mm/maccess.c | 6 ++++++ + 2 files changed, 17 insertions(+), 0 deletions(-) + +diff --git a/kernel/kgdb.c b/kernel/kgdb.c +index 68aea78..31425e0 100644 +--- a/kernel/kgdb.c ++++ b/kernel/kgdb.c +@@ -200,6 +200,17 @@ int __weak kgdb_arch_init(void) + return 0; + } + ++int __weak kgdb_skipexception(int exception, struct pt_regs *regs) ++{ ++ return 0; ++} ++ ++void __weak ++kgdb_post_primary_code(struct pt_regs *regs, int e_vector, int err_code) ++{ ++ return; ++} ++ + /** + * kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb. + * @regs: Current &struct pt_regs. +diff --git a/mm/maccess.c b/mm/maccess.c +index 24f81b9..ac40796 100644 +--- a/mm/maccess.c ++++ b/mm/maccess.c +@@ -17,11 +17,14 @@ + long probe_kernel_read(void *dst, void *src, size_t size) + { + long ret; ++ mm_segment_t old_fs = get_fs(); + ++ set_fs(KERNEL_DS); + pagefault_disable(); + ret = __copy_from_user_inatomic(dst, + (__force const void __user *)src, size); + pagefault_enable(); ++ set_fs(old_fs); + + return ret ? -EFAULT : 0; + } +@@ -39,10 +42,13 @@ EXPORT_SYMBOL_GPL(probe_kernel_read); + long probe_kernel_write(void *dst, void *src, size_t size) + { + long ret; ++ mm_segment_t old_fs = get_fs(); + ++ set_fs(KERNEL_DS); + pagefault_disable(); + ret = __copy_to_user_inatomic((__force void __user *)dst, src, size); + pagefault_enable(); ++ set_fs(old_fs); + + return ret ? -EFAULT : 0; + } +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0060-Added-PCI-ID-for-Natick.-Enable-40-wire-cable-detect.patch +++ linux-2.6.24/patches/0060-Added-PCI-ID-for-Natick.-Enable-40-wire-cable-detect.patch @@ -0,0 +1,25 @@ +From 3564ec0d6b37b5d8ef4e8b61920ca1ab687586b5 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 24 Sep 2008 10:59:38 -0400 +Subject: [PATCH 060/170] Added PCI ID for Natick. Enable 40 wire cable detect to ata_pix.c + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/ata/ata_piix.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c +index a00abc5..967789c 100644 +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -704,6 +704,7 @@ static const struct ich_laptop ich_laptop[] = { + { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ + { 0x811A, 0x1509, 0x5001 }, /* SCH on Chelsea */ + { 0x27DF, 0x1028, 0x02b0 }, /* ICH7 on Belmont */ ++ { 0x27DF, 0x152D, 0x0778 }, /* ICH7 on Natick */ + /* end marker */ + { 0, } + }; +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0129-UBUNTU-temporarily-reinstroduce-a-null-patch.patch +++ linux-2.6.24/patches/0129-UBUNTU-temporarily-reinstroduce-a-null-patch.patch @@ -0,0 +1,37 @@ +From 85c2535f3ddb0e8e8fa2ce612dfb8e2c3e6e988e Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 22:27:01 +0100 +Subject: [PATCH 129/170] UBUNTU: temporarily reinstroduce a null patch + +As the lpia tree is configured as a custom binary tree we have no choice +but have some patch. This commit reintroduces a null patch creating a +benign file. Without a patch the custom binary preparation fails. + +Signed-off-by: Andy Whitcroft +--- + debian/binary-custom.d/lpia/patchset/0000-NULL | 13 +++++++++++++ + 1 files changed, 13 insertions(+), 0 deletions(-) + create mode 100644 debian/binary-custom.d/lpia/patchset/0000-NULL + +diff --git a/debian/binary-custom.d/lpia/patchset/0000-NULL b/debian/binary-custom.d/lpia/patchset/0000-NULL +new file mode 100644 +index 0000000..447f97a +--- /dev/null ++++ b/debian/binary-custom.d/lpia/patchset/0000-NULL +@@ -0,0 +1,13 @@ ++commit 7a0a51987004ee4157f008307091bc1c8eaa6a91 ++Author: Andy Whitcroft ++Date: Fri Apr 3 21:45:35 2009 +0100 ++ ++ NULL ++ ++diff --git a/debian/NULL b/debian/NULL ++new file mode 100644 ++index 0000000..7951def ++--- /dev/null +++++ b/debian/NULL ++@@ -0,0 +1 @@ +++NULL +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0142-UBUNTU-NBK-Ubuntu-2.6.24-24.51netbook12.patch +++ linux-2.6.24/patches/0142-UBUNTU-NBK-Ubuntu-2.6.24-24.51netbook12.patch @@ -0,0 +1,40 @@ +From a33c8960252da2396c83e2f01cc3dad50c6ac684 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Mon, 27 Apr 2009 16:18:19 -0500 +Subject: [PATCH 142/170] UBUNTU: NBK-Ubuntu-2.6.24-24.51netbook12 + +Signed-off-by: Steve Conklin +--- + debian/changelog | 19 +++++++++++++++++++ + 1 files changed, 19 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 0989075..990d759 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,22 @@ ++linux (2.6.24-24.51netbook12) netbook-common; urgency=low ++ ++ [Andres Salomon] ++ ++ * Revert "Bluetooth: SCO flow control to enable bluetooth headsets ++ OriginalLocation: ++ http://bluetooth-alsa.cvs.sourceforge.net/*checkout*/bluetooth-alsa/plu ++ gz/patches/sco-flowcontrol-v4.4.diff" ++ * Revert "SAUCE: Always use SCO protocol (disable eSCO support)" ++ ++ [Upstream Kernel Changes] ++ ++ * bluetooth: delete timer in l2cap_conn_del() ++ * l2cap info_timer delete fix in hci_conn_del ++ * Support the case when headset falls back to SCO link ++ * ESCO interval rejection fix ++ ++ -- Steve Conklin Mon, 27 Apr 2009 20:49:29 +0000 ++ + linux (2.6.24-24.51netbook11) netbook-common; urgency=low + + [Andy Whitcroft] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0106-UBUNTU-dib0700-prevent-previous-changeset-from-affec.patch +++ linux-2.6.24/patches/0106-UBUNTU-dib0700-prevent-previous-changeset-from-affec.patch @@ -0,0 +1,54 @@ +From 4c854a640b80da088c792986da50351d41892360 Mon Sep 17 00:00:00 2001 +From: Michael Krufky +Date: Mon, 23 Mar 2009 15:41:30 -0400 +Subject: [PATCH 106/170] UBUNTU: dib0700: prevent previous changeset from affecting older devices + +OriginalAuthor: Michael Krufky + +The previous changeset updates the DIB0700_DEFAULT_DEVICE_PROPERTIES +to use the 1.20 firmware for all devices. We might not want to make +this drastic change in a stable kernel, so better off to only use the +new firmware only where it is actually necessary. + +This changeset reverts DIB0700_DEFAULT_DEVICE_PROPERTIES to use the +1.10 firmware, and creates DIB0700_FW_1_20_DEVICE_PROPERTIES for the +1.20 firmware. + +Signed-off-by: Michael Krufky +--- + drivers/media/dvb/dvb-usb/dib0700_devices.c | 12 +++++++++++- + 1 files changed, 11 insertions(+), 1 deletions(-) + +diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c +index b1d1461..133bc6e 100644 +--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c ++++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c +@@ -853,7 +853,7 @@ struct usb_device_id dib0700_usb_id_table[] = { + }; + MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); + +-#define DIB0700_DEFAULT_DEVICE_PROPERTIES \ ++#define DIB0700_FW_1_20_DEVICE_PROPERTIES \ + .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ + .usb_ctrl = DEVICE_SPECIFIC, \ + .firmware = "dvb-usb-dib0700-1.20.fw", \ +@@ -863,6 +863,16 @@ MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); + .i2c_algo = &dib0700_i2c_algo, \ + .identify_state = dib0700_identify_state + ++#define DIB0700_DEFAULT_DEVICE_PROPERTIES \ ++ .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ ++ .usb_ctrl = DEVICE_SPECIFIC, \ ++ .firmware = "dvb-usb-dib0700-1.10.fw", \ ++ .download_firmware = dib0700_download_firmware, \ ++ .no_reconnect = 1, \ ++ .size_of_priv = sizeof(struct dib0700_state), \ ++ .i2c_algo = &dib0700_i2c_algo, \ ++ .identify_state = dib0700_identify_state ++ + #define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \ + .streaming_ctrl = dib0700_streaming_ctrl, \ + .stream = { \ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0010-kgdb-light-v10-clocksource-watchdog.patch +++ linux-2.6.24/patches/0010-kgdb-light-v10-clocksource-watchdog.patch @@ -0,0 +1,90 @@ +From cccaf29d578a3316254ea44a4366be9a8ddae781 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 15 Feb 2008 14:55:54 -0600 +Subject: [PATCH 010/170] kgdb-light-v10: clocksource watchdog + +In order to not trip the clocksource watchdog, kgdb must touch the +clocksource watchdog on the return to normal system run state. + +Signed-off-by: Jason Wessel +Signed-off-by: Ingo Molnar +--- + include/linux/clocksource.h | 1 + + kernel/kgdb.c | 4 ++++ + kernel/time/clocksource.c | 12 ++++++++++++ + 3 files changed, 17 insertions(+), 0 deletions(-) + +diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h +index 107787a..72eb08f 100644 +--- a/include/linux/clocksource.h ++++ b/include/linux/clocksource.h +@@ -216,6 +216,7 @@ static inline void clocksource_calculate_interval(struct clocksource *c, + /* used to install a new clocksource */ + extern int clocksource_register(struct clocksource*); + extern struct clocksource* clocksource_get_next(void); ++extern void clocksource_touch_watchdog(void); + extern void clocksource_change_rating(struct clocksource *cs, int rating); + extern void clocksource_resume(void); + +diff --git a/kernel/kgdb.c b/kernel/kgdb.c +index 017ee78..e3f6037 100644 +--- a/kernel/kgdb.c ++++ b/kernel/kgdb.c +@@ -28,6 +28,7 @@ + * kind, whether express or implied. + */ + #include ++#include + #include + #include + #include +@@ -574,6 +575,7 @@ static void kgdb_wait(struct pt_regs *regs) + + /* Signal the primary CPU that we are done: */ + atomic_set(&cpu_in_kgdb[cpu], 0); ++ clocksource_touch_watchdog(); + local_irq_restore(flags); + } + #endif +@@ -1396,6 +1398,7 @@ acquirelock: + atomic_read(&kgdb_cpu_doing_single_step) != cpu) { + + atomic_set(&kgdb_active, -1); ++ clocksource_touch_watchdog(); + local_irq_restore(flags); + + goto acquirelock; +@@ -1487,6 +1490,7 @@ acquirelock: + kgdb_restore: + /* Free kgdb_active */ + atomic_set(&kgdb_active, -1); ++ clocksource_touch_watchdog(); + local_irq_restore(flags); + + return error; +diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c +index c8a9d13..5a2cb1e 100644 +--- a/kernel/time/clocksource.c ++++ b/kernel/time/clocksource.c +@@ -223,6 +223,18 @@ void clocksource_resume(void) + } + + /** ++ * clocksource_touch_watchdog - Update watchdog ++ * ++ * Update the watchdog after exception contexts such as kgdb so as not ++ * to incorrectly trip the watchdog. ++ * ++ */ ++void clocksource_touch_watchdog(void) ++{ ++ clocksource_resume_watchdog(); ++} ++ ++/** + * clocksource_get_next - Returns the selected clocksource + * + */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0032-kgdb-mips-pad-pt_regs-on-MIPS64-for-function-argumen.patch +++ linux-2.6.24/patches/0032-kgdb-mips-pad-pt_regs-on-MIPS64-for-function-argumen.patch @@ -0,0 +1,29 @@ +From aae83a2e3e6cb5c406e1661826489556cb147415 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:47 -0500 +Subject: [PATCH 032/170] kgdb, mips: pad pt_regs on MIPS64 for function arguments in an exception + +When using KGDB the pt_regs structure has the function arguments saved +to the stack. 48 bytes are required for MIPS 64 for this purpose. + +Signed-off-by: Jason Wessel +--- + include/asm-mips/ptrace.h | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h +index 786f7e3..c3f535f 100644 +--- a/include/asm-mips/ptrace.h ++++ b/include/asm-mips/ptrace.h +@@ -28,7 +28,7 @@ + * system call/exception. As usual the registers k0/k1 aren't being saved. + */ + struct pt_regs { +-#ifdef CONFIG_32BIT ++#if defined(CONFIG_32BIT) || defined(CONFIG_KGDB) + /* Pad bytes for argument save space on the stack. */ + unsigned long pad0[6]; + #endif +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0170-UBUNTU-NBK-Ubuntu-2.6.24-27.66netbook01.patch +++ linux-2.6.24/patches/0170-UBUNTU-NBK-Ubuntu-2.6.24-27.66netbook01.patch @@ -0,0 +1,29 @@ +From 7120c395e52309b3e7aeef95980c5905ca3c3ace Mon Sep 17 00:00:00 2001 +From: Stefan Bader +Date: Tue, 9 Feb 2010 15:15:01 +0100 +Subject: [PATCH 170/170] UBUNTU: NBK-Ubuntu-2.6.24-27.66netbook01 + +Signed-off-by: Stefan Bader +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 5025b07..c383268 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-27.66netbook01) netbook-common; urgency=low ++ ++ [Stefan Bader] ++ ++ * Rebase onto Ubuntu-2.6.24-27.66 proposed release. ++ ++ -- Stefan Bader Tue, 09 Feb 2010 15:13:55 +0100 ++ + linux (2.6.24-27.65netbook01) netbook-common; urgency=low + + [Leann Ogasawara] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0125-Turn-debian-binary-custom.d-lpia-patchset-0021-legac.patch +++ linux-2.6.24/patches/0125-Turn-debian-binary-custom.d-lpia-patchset-0021-legac.patch @@ -0,0 +1,137 @@ +From 487294b1c1d2194b4e2f0a6277a20e74575249d5 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:34 +0100 +Subject: [PATCH 125/170] Turn debian/binary-custom.d/lpia/patchset/0021-legacy-usb-int-fix.patch into a commit. + +Signed-off-by: Andy Whitcroft + +commit 974128ae34a0e1907d86aa3f915cf9b6208cda88 +Author: Amit Kucheria +Date: Thu Mar 6 04:39:22 2008 +0200 + + UBUNTU: Poulsbo: Sync patches with moblin/ume-hardy tree + + Signed-off-by: Amit Kucheria +--- + .../lpia/patchset/0021-legacy-usb-int-fix.patch | 54 -------------------- + drivers/usb/host/pci-quirks.c | 11 ++++ + drivers/usb/host/uhci-hcd.c | 13 +++++ + 3 files changed, 24 insertions(+), 54 deletions(-) + delete mode 100644 debian/binary-custom.d/lpia/patchset/0021-legacy-usb-int-fix.patch + +diff --git a/debian/binary-custom.d/lpia/patchset/0021-legacy-usb-int-fix.patch b/debian/binary-custom.d/lpia/patchset/0021-legacy-usb-int-fix.patch +deleted file mode 100644 +index 5c3df51..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0021-legacy-usb-int-fix.patch ++++ /dev/null +@@ -1,54 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c +-index c225159..b71f504 100644 +---- a/drivers/usb/host/pci-quirks.c +-+++ b/drivers/usb/host/pci-quirks.c +-@@ -51,6 +51,17 @@ +- #define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ +- #define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */ +- +-+void uhci_clear_usb_int(unsigned long base) +-+{ +-+ outw(UHCI_USBCMD_HCRESET, base + UHCI_USBCMD); +-+ mb(); +-+ udelay(5); +-+ outw(0, base + UHCI_USBINTR); +-+ outw(0, base + UHCI_USBCMD); +-+ mb(); +-+ return; +-+} +-+EXPORT_SYMBOL (uhci_clear_usb_int); +- +- /* +- * Make sure the controller is completely inactive, unable to +-diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c +-index ec98789..0c2b47d 100644 +---- a/drivers/usb/host/uhci-hcd.c +-+++ b/drivers/usb/host/uhci-hcd.c +-@@ -898,6 +898,18 @@ static const struct pci_device_id uhci_pci_ids[] = { { +- +- MODULE_DEVICE_TABLE(pci, uhci_pci_ids); +- +-+extern void uhci_clear_usb_int(unsigned long base); +-+static int usb_hcd_resume_early(struct pci_dev *dev) +-+{ +-+ struct usb_hcd *hcd; +-+ struct uhci_hcd *uhci; +-+ +-+ hcd = pci_get_drvdata(dev); +-+ uhci = hcd_to_uhci(hcd); +-+ uhci_clear_usb_int(uhci->io_addr); +-+ return 0; +-+} +-+ +- static struct pci_driver uhci_pci_driver = { +- .name = (char *)hcd_name, +- .id_table = uhci_pci_ids, +-@@ -907,6 +919,7 @@ static struct pci_driver uhci_pci_driver = { +- .shutdown = uhci_shutdown, +- +- #ifdef CONFIG_PM +-+ .resume_early = usb_hcd_resume_early, +- .suspend = usb_hcd_pci_suspend, +- .resume = usb_hcd_pci_resume, +- #endif /* PM */ +diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c +index c225159..b71f504 100644 +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -51,6 +51,17 @@ + #define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ + #define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */ + ++void uhci_clear_usb_int(unsigned long base) ++{ ++ outw(UHCI_USBCMD_HCRESET, base + UHCI_USBCMD); ++ mb(); ++ udelay(5); ++ outw(0, base + UHCI_USBINTR); ++ outw(0, base + UHCI_USBCMD); ++ mb(); ++ return; ++} ++EXPORT_SYMBOL (uhci_clear_usb_int); + + /* + * Make sure the controller is completely inactive, unable to +diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c +index ec98789..0c2b47d 100644 +--- a/drivers/usb/host/uhci-hcd.c ++++ b/drivers/usb/host/uhci-hcd.c +@@ -898,6 +898,18 @@ static const struct pci_device_id uhci_pci_ids[] = { { + + MODULE_DEVICE_TABLE(pci, uhci_pci_ids); + ++extern void uhci_clear_usb_int(unsigned long base); ++static int usb_hcd_resume_early(struct pci_dev *dev) ++{ ++ struct usb_hcd *hcd; ++ struct uhci_hcd *uhci; ++ ++ hcd = pci_get_drvdata(dev); ++ uhci = hcd_to_uhci(hcd); ++ uhci_clear_usb_int(uhci->io_addr); ++ return 0; ++} ++ + static struct pci_driver uhci_pci_driver = { + .name = (char *)hcd_name, + .id_table = uhci_pci_ids, +@@ -907,6 +919,7 @@ static struct pci_driver uhci_pci_driver = { + .shutdown = uhci_shutdown, + + #ifdef CONFIG_PM ++ .resume_early = usb_hcd_resume_early, + .suspend = usb_hcd_pci_suspend, + .resume = usb_hcd_pci_resume, + #endif /* PM */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0018-kgdb-Kconfig-fix.patch +++ linux-2.6.24/patches/0018-kgdb-Kconfig-fix.patch @@ -0,0 +1,31 @@ +From 7d21d562a9935bf904219c563453b237f392978c Mon Sep 17 00:00:00 2001 +From: Andrew Morton +Date: Fri, 7 Mar 2008 15:51:16 -0800 +Subject: [PATCH 018/170] kgdb: Kconfig fix + +ERROR: "uart_parse_options" [drivers/serial/serial_core.ko] undefined! + +Cc: Jason Wessel +Signed-off-by: Andrew Morton +Signed-off-by: Ingo Molnar +Signed-off-by: Jason Wessel +--- + drivers/serial/serial_core.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c +index 0000240..4ea9b03 100644 +--- a/drivers/serial/serial_core.c ++++ b/drivers/serial/serial_core.c +@@ -1769,7 +1769,7 @@ static int uart_read_proc(char *page, char **start, off_t off, + } + #endif + +-#ifdef CONFIG_SERIAL_CORE_CONSOLE ++#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) + /* + * uart_console_write - write a console message to a serial port + * @port: the port to write the message +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0038-UBUNTU-NBK-Ubuntu-2.6.24-19.35netbook1.patch +++ linux-2.6.24/patches/0038-UBUNTU-NBK-Ubuntu-2.6.24-19.35netbook1.patch @@ -0,0 +1,32 @@ +From 9fd3230c84cc302f9a3b7f7c05b6c5a607ae6a9b Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Mon, 7 Jul 2008 12:41:53 +0100 +Subject: [PATCH 038/170] UBUNTU: NBK-Ubuntu-2.6.24-19.35netbook1 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 10 ++++++++++ + 1 files changed, 10 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index b56d9b5..f2c9189 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,13 @@ ++linux (2.6.24-19.35netbook1) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * Remove lpiacompat from build ++ * Patch from abi-18 for Realtek Ethernet fix ++ * Netbook LPIA kernel config. New ABI-19 bump ++ ++ -- Michael Frey Mon, 07 Jul 2008 12:37:24 +0100 ++ + linux (2.6.24-0.0) UNRELEASED; urgency=low + + * Initial release. (Closes: #XXXXXX) +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0156-UBUNTU-Start-new-release.patch +++ linux-2.6.24/patches/0156-UBUNTU-Start-new-release.patch @@ -0,0 +1,37 @@ +From 286c3f0498ff9ae645f8b3389c1edf8145b7a999 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Tue, 28 Jul 2009 16:51:35 +0100 +Subject: [PATCH 156/170] UBUNTU: Start new release + +Ignore: yes + +Signed-off-by: Andy Whitcroft +--- + debian/changelog | 10 +++++++++- + 1 files changed, 9 insertions(+), 1 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index d578524..0c6e97e 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,8 +1,16 @@ ++linux (2.6.24-24.54netbook03) UNRELEASED; urgency=low ++ ++ CHANGELOG: Do not edit directly. Autogenerated at release. ++ CHANGELOG: Use the printchanges target to see the curent changes. ++ CHANGELOG: Use the insertchanges target to create the final log. ++ ++ -- Andy Whitcroft Tue, 28 Jul 2009 16:51:16 +0100 ++ + linux (2.6.24-24.54netbook02) netbook-common; urgency=low + + [ Steve Conklin ] + * Fix NVR +- ++ + -- sconklin Tue, 28 Jul 2009 14:09:38 +0000 + + linux (2.6.24-24.54netboot01) netboot-common; urgency=low +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0112-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook9.patch +++ linux-2.6.24/patches/0112-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook9.patch @@ -0,0 +1,49 @@ +From 1080d79e4a5b9f28083243925b2692f0fe4d8dc9 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Thu, 26 Mar 2009 12:24:17 -0400 +Subject: [PATCH 112/170] UBUNTU: NBK-Ubuntu-2.6.24-22.45netbook9 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 27 +++++++++++++++++++++++++++ + 1 files changed, 27 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index cccfca7..b372be1 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,30 @@ ++linux (2.6.24-22.45netbook9) netbook-common; urgency=low ++ ++ [Devin Heitmueller] ++ ++ * V4L/DVB (9039): Add support for new i2c API provided in firmware ++ version 1.20 ++ * add option, "disable_streaming_master_mode" ++ ++ [Michael Krufky] ++ ++ * dib0700: add support for Hauppauge Nova-TD Stick 52009 ++ * dib0700: add basic support for Hauppauge Nova-TD-500 (84xxx) ++ * dib0700: prevent previous changeset from affecting older devices ++ * add support for LG Electronics LGDT3305 ATSC/QAM-B Demodulator ++ * add support for MaxLinear MxL5007T silicon tuner ++ * dib0700: add support for Hauppauge ATSC MiniCard ++ ++ [Patrick Boettcher] ++ ++ * V4L/DVB (7071): DiB0700: Start streaming the right way ++ ++ [Michael Frey] ++ ++ * Updated touchpad driver from Elantech ++ ++ -- Michael Frey Thu, 26 Mar 2009 12:21:50 -0400 ++ + linux (2.6.24-22.45netbook8) netbook-common; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0023-kgdb-Always-use-icache-flush-for-sw-breakpoints.patch +++ linux-2.6.24/patches/0023-kgdb-Always-use-icache-flush-for-sw-breakpoints.patch @@ -0,0 +1,33 @@ +From e2076ce9d51d5fa6952e2f43b600619420a9cc06 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:45 -0500 +Subject: [PATCH 023/170] kgdb: Always use icache flush for sw breakpoints + +On the ppc 4xx architecture the instruction cache must be flushed as +well as the data cache. This patch just makes it generic for all +architectures where CACHE_FLUSH_IS_SAFE is set to 1. + +Signed-off-by: Jason Wessel +--- + kernel/kgdb.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kernel/kgdb.c b/kernel/kgdb.c +index 4d1b3c2..1bd0ec1 100644 +--- a/kernel/kgdb.c ++++ b/kernel/kgdb.c +@@ -591,9 +591,9 @@ static void kgdb_flush_swbreak_addr(unsigned long addr) + if (current->mm && current->mm->mmap_cache) { + flush_cache_range(current->mm->mmap_cache, + addr, addr + BREAK_INSTR_SIZE); +- } else { +- flush_icache_range(addr, addr + BREAK_INSTR_SIZE); + } ++ /* Force flush instruction cache if it was outside the mm */ ++ flush_icache_range(addr, addr + BREAK_INSTR_SIZE); + } + + /* +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0015-kgdb-support-for-ARCH-arm.patch +++ linux-2.6.24/patches/0015-kgdb-support-for-ARCH-arm.patch @@ -0,0 +1,472 @@ +From 8c4139b6d3a0b5236c62bf6caddc5b32f04ac5ed Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Wed, 20 Feb 2008 13:33:40 -0600 +Subject: [PATCH 015/170] kgdb: support for ARCH=arm + +This patch adds the ARCH=arm specific a kgdb backend, originally +written by Deepak Saxena and George Davis +. Geoff Levand , +Nicolas Pitre, and Manish Lachwani have contributed various fixups +here as well. + +The changes to setup the traps earlier allow for early debugging with +a uart based KGDB I/O driver. The do_undefinstr() routine also needed +to allow the lookup of kernel address space in order for the debugger +to plant undefined instructions in kernel memory space and receive the +correct notification. + +[ mingo@elte.hu: small cleanups. ] + +Signed-off-by: Jason Wessel +Signed-off-by: Ingo Molnar +--- + arch/arm/Kconfig | 1 + + arch/arm/kernel/Makefile | 1 + + arch/arm/kernel/kgdb.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++ + arch/arm/kernel/setup.c | 5 + + arch/arm/kernel/traps.c | 11 +++ + include/asm-arm/kgdb.h | 104 ++++++++++++++++++++++ + include/asm-arm/traps.h | 2 + + 7 files changed, 343 insertions(+), 0 deletions(-) + create mode 100644 arch/arm/kernel/kgdb.c + create mode 100644 include/asm-arm/kgdb.h + +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index a04f507..19707cb 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration" + config ARM + bool + default y ++ select HAVE_ARCH_KGDB + select RTC_LIB + select SYS_SUPPORTS_APM_EMULATION + help +diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile +index 593b565..b6ffc45 100644 +--- a/arch/arm/kernel/Makefile ++++ b/arch/arm/kernel/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_PCI) += bios32.o isa.o + obj-$(CONFIG_SMP) += smp.o + obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o + obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o ++obj-$(CONFIG_KGDB) += kgdb.o + + obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o + AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 +diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c +new file mode 100644 +index 0000000..365dfb6 +--- /dev/null ++++ b/arch/arm/kernel/kgdb.c +@@ -0,0 +1,219 @@ ++/* ++ * arch/arm/kernel/kgdb.c ++ * ++ * ARM KGDB support ++ * ++ * Copyright (c) 2002-2004 MontaVista Software, Inc ++ * Copyright (c) 2008 Wind River Systems, Inc. ++ * ++ * Authors: George Davis ++ * Deepak Saxena ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* Make a local copy of the registers passed into the handler (bletch) */ ++void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) ++{ ++ int regno; ++ ++ /* Initialize all to zero. */ ++ for (regno = 0; regno < GDB_MAX_REGS; regno++) ++ gdb_regs[regno] = 0; ++ ++ gdb_regs[_R0] = kernel_regs->ARM_r0; ++ gdb_regs[_R1] = kernel_regs->ARM_r1; ++ gdb_regs[_R2] = kernel_regs->ARM_r2; ++ gdb_regs[_R3] = kernel_regs->ARM_r3; ++ gdb_regs[_R4] = kernel_regs->ARM_r4; ++ gdb_regs[_R5] = kernel_regs->ARM_r5; ++ gdb_regs[_R6] = kernel_regs->ARM_r6; ++ gdb_regs[_R7] = kernel_regs->ARM_r7; ++ gdb_regs[_R8] = kernel_regs->ARM_r8; ++ gdb_regs[_R9] = kernel_regs->ARM_r9; ++ gdb_regs[_R10] = kernel_regs->ARM_r10; ++ gdb_regs[_FP] = kernel_regs->ARM_fp; ++ gdb_regs[_IP] = kernel_regs->ARM_ip; ++ gdb_regs[_SPT] = kernel_regs->ARM_sp; ++ gdb_regs[_LR] = kernel_regs->ARM_lr; ++ gdb_regs[_PC] = kernel_regs->ARM_pc; ++ gdb_regs[_CPSR] = kernel_regs->ARM_cpsr; ++} ++ ++/* Copy local gdb registers back to kgdb regs, for later copy to kernel */ ++void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) ++{ ++ kernel_regs->ARM_r0 = gdb_regs[_R0]; ++ kernel_regs->ARM_r1 = gdb_regs[_R1]; ++ kernel_regs->ARM_r2 = gdb_regs[_R2]; ++ kernel_regs->ARM_r3 = gdb_regs[_R3]; ++ kernel_regs->ARM_r4 = gdb_regs[_R4]; ++ kernel_regs->ARM_r5 = gdb_regs[_R5]; ++ kernel_regs->ARM_r6 = gdb_regs[_R6]; ++ kernel_regs->ARM_r7 = gdb_regs[_R7]; ++ kernel_regs->ARM_r8 = gdb_regs[_R8]; ++ kernel_regs->ARM_r9 = gdb_regs[_R9]; ++ kernel_regs->ARM_r10 = gdb_regs[_R10]; ++ kernel_regs->ARM_fp = gdb_regs[_FP]; ++ kernel_regs->ARM_ip = gdb_regs[_IP]; ++ kernel_regs->ARM_sp = gdb_regs[_SPT]; ++ kernel_regs->ARM_lr = gdb_regs[_LR]; ++ kernel_regs->ARM_pc = gdb_regs[_PC]; ++ kernel_regs->ARM_cpsr = gdb_regs[_CPSR]; ++} ++ ++void ++sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) ++{ ++ struct pt_regs *thread_regs; ++ int regno; ++ ++ /* Just making sure... */ ++ if (task == NULL) ++ return; ++ ++ /* Initialize to zero */ ++ for (regno = 0; regno < GDB_MAX_REGS; regno++) ++ gdb_regs[regno] = 0; ++ ++ /* Otherwise, we have only some registers from switch_to() */ ++ thread_regs = task_pt_regs(task); ++ gdb_regs[_R0] = thread_regs->ARM_r0; ++ gdb_regs[_R1] = thread_regs->ARM_r1; ++ gdb_regs[_R2] = thread_regs->ARM_r2; ++ gdb_regs[_R3] = thread_regs->ARM_r3; ++ gdb_regs[_R4] = thread_regs->ARM_r4; ++ gdb_regs[_R5] = thread_regs->ARM_r5; ++ gdb_regs[_R6] = thread_regs->ARM_r6; ++ gdb_regs[_R7] = thread_regs->ARM_r7; ++ gdb_regs[_R8] = thread_regs->ARM_r8; ++ gdb_regs[_R9] = thread_regs->ARM_r9; ++ gdb_regs[_R10] = thread_regs->ARM_r10; ++ gdb_regs[_FP] = thread_regs->ARM_fp; ++ gdb_regs[_IP] = thread_regs->ARM_ip; ++ gdb_regs[_SPT] = thread_regs->ARM_sp; ++ gdb_regs[_LR] = thread_regs->ARM_lr; ++ gdb_regs[_PC] = thread_regs->ARM_pc; ++ gdb_regs[_CPSR] = thread_regs->ARM_cpsr; ++} ++ ++static int compiled_break; ++ ++int kgdb_arch_handle_exception(int exception_vector, int signo, ++ int err_code, char *remcom_in_buffer, ++ char *remcom_out_buffer, ++ struct pt_regs *linux_regs) ++{ ++ long addr; ++ char *ptr; ++ ++ switch (remcom_in_buffer[0]) { ++ case 'D': ++ case 'k': ++ case 'c': ++ kgdb_contthread = NULL; ++ ++ /* ++ * Try to read optional parameter, pc unchanged if no parm. ++ * If this was a compiled breakpoint, we need to move ++ * to the next instruction or we will just breakpoint ++ * over and over again. ++ */ ++ ptr = &remcom_in_buffer[1]; ++ if (kgdb_hex2long(&ptr, &addr)) ++ linux_regs->ARM_pc = addr; ++ else if (compiled_break == 1) ++ linux_regs->ARM_pc += 4; ++ ++ compiled_break = 0; ++ ++ return 0; ++ } ++ ++ return -1; ++} ++ ++static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr) ++{ ++ kgdb_handle_exception(1, SIGTRAP, 0, regs); ++ ++ return 0; ++} ++ ++static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr) ++{ ++ compiled_break = 1; ++ kgdb_handle_exception(1, SIGTRAP, 0, regs); ++ ++ return 0; ++} ++ ++static struct undef_hook kgdb_brkpt_hook = { ++ .instr_mask = 0xffffffff, ++ .instr_val = KGDB_BREAKINST, ++ .fn = kgdb_brk_fn ++}; ++ ++static struct undef_hook kgdb_compiled_brkpt_hook = { ++ .instr_mask = 0xffffffff, ++ .instr_val = KGDB_COMPILED_BREAK, ++ .fn = kgdb_compiled_brk_fn ++}; ++ ++/** ++ * kgdb_arch_init - Perform any architecture specific initalization. ++ * ++ * This function will handle the initalization of any architecture ++ * specific callbacks. ++ */ ++int kgdb_arch_init(void) ++{ ++ register_undef_hook(&kgdb_brkpt_hook); ++ register_undef_hook(&kgdb_compiled_brkpt_hook); ++ ++ return 0; ++} ++ ++/** ++ * kgdb_arch_exit - Perform any architecture specific uninitalization. ++ * ++ * This function will handle the uninitalization of any architecture ++ * specific callbacks, for dynamic registration and unregistration. ++ */ ++void kgdb_arch_exit(void) ++{ ++ unregister_undef_hook(&kgdb_brkpt_hook); ++ unregister_undef_hook(&kgdb_compiled_brkpt_hook); ++} ++ ++/* ++ * Register our undef instruction hooks with ARM undef core. ++ * We regsiter a hook specifically looking for the KGB break inst ++ * and we handle the normal undef case within the do_undefinstr ++ * handler. ++ */ ++struct kgdb_arch arch_kgdb_ops = { ++#ifndef __ARMEB__ ++ .gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7} ++#else /* ! __ARMEB__ */ ++ .gdb_bpt_instr = {0xe7, 0xff, 0xde, 0xfe} ++#endif ++}; +diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c +index bf56eb3..e78de19 100644 +--- a/arch/arm/kernel/setup.c ++++ b/arch/arm/kernel/setup.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #include "compat.h" + +@@ -880,6 +881,10 @@ void __init setup_arch(char **cmdline_p) + conswitchp = &dummy_con; + #endif + #endif ++ ++#if defined(CONFIG_KGDB) ++ early_trap_init(); ++#endif + } + + +diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c +index c34db4e..f18a9e1 100644 +--- a/arch/arm/kernel/traps.c ++++ b/arch/arm/kernel/traps.c +@@ -302,6 +302,7 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) + unsigned int instr; + struct undef_hook *hook; + siginfo_t info; ++ mm_segment_t fs; + void __user *pc; + unsigned long flags; + +@@ -312,6 +313,8 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) + */ + regs->ARM_pc -= correction; + ++ fs = get_fs(); ++ set_fs(KERNEL_DS); + pc = (void __user *)instruction_pointer(regs); + + if (processor_mode(regs) == SVC_MODE) { +@@ -321,6 +324,7 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) + } else { + get_user(instr, (u32 __user *)pc); + } ++ set_fs(fs); + + spin_lock_irqsave(&undef_lock, flags); + list_for_each_entry(hook, &undef_hook, node) { +@@ -705,6 +709,13 @@ EXPORT_SYMBOL(abort); + + void __init trap_init(void) + { ++#if defined(CONFIG_KGDB) ++ return; ++} ++ ++void __init early_trap_init(void) ++{ ++#endif + unsigned long vectors = CONFIG_VECTORS_BASE; + extern char __stubs_start[], __stubs_end[]; + extern char __vectors_start[], __vectors_end[]; +diff --git a/include/asm-arm/kgdb.h b/include/asm-arm/kgdb.h +new file mode 100644 +index 0000000..67af4b8 +--- /dev/null ++++ b/include/asm-arm/kgdb.h +@@ -0,0 +1,104 @@ ++/* ++ * ARM KGDB support ++ * ++ * Author: Deepak Saxena ++ * ++ * Copyright (C) 2002 MontaVista Software Inc. ++ * ++ */ ++ ++#ifndef __ARM_KGDB_H__ ++#define __ARM_KGDB_H__ ++ ++#include ++ ++/* ++ * GDB assumes that we're a user process being debugged, so ++ * it will send us an SWI command to write into memory as the ++ * debug trap. When an SWI occurs, the next instruction addr is ++ * placed into R14_svc before jumping to the vector trap. ++ * This doesn't work for kernel debugging as we are already in SVC ++ * we would loose the kernel's LR, which is a bad thing. This ++ * is bad thing. ++ * ++ * By doing this as an undefined instruction trap, we force a mode ++ * switch from SVC to UND mode, allowing us to save full kernel state. ++ * ++ * We also define a KGDB_COMPILED_BREAK which can be used to compile ++ * in breakpoints. This is important for things like sysrq-G and for ++ * the initial breakpoint from trap_init(). ++ * ++ * Note to ARM HW designers: Add real trap support like SH && PPC to ++ * make our lives much much simpler. :) ++ */ ++#define BREAK_INSTR_SIZE 4 ++#define GDB_BREAKINST 0xef9f0001 ++#define KGDB_BREAKINST 0xe7ffdefe ++#define KGDB_COMPILED_BREAK 0xe7ffdeff ++#define CACHE_FLUSH_IS_SAFE 1 ++ ++#ifndef __ASSEMBLY__ ++ ++static inline void arch_kgdb_breakpoint(void) ++{ ++ asm(".word 0xe7ffdeff"); ++} ++ ++extern void kgdb_handle_bus_error(void); ++extern int kgdb_fault_expected; ++ ++#endif /* !__ASSEMBLY__ */ ++ ++/* ++ * From Kevin Hilman: ++ * ++ * gdb is expecting the following registers layout. ++ * ++ * r0-r15: 1 long word each ++ * f0-f7: unused, 3 long words each !! ++ * fps: unused, 1 long word ++ * cpsr: 1 long word ++ * ++ * Even though f0-f7 and fps are not used, they need to be ++ * present in the registers sent for correct processing in ++ * the host-side gdb. ++ * ++ * In particular, it is crucial that CPSR is in the right place, ++ * otherwise gdb will not be able to correctly interpret stepping over ++ * conditional branches. ++ */ ++#define _GP_REGS 16 ++#define _FP_REGS 8 ++#define _EXTRA_REGS 2 ++#define GDB_MAX_REGS (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS) ++ ++#define KGDB_MAX_NO_CPUS 1 ++#define BUFMAX 400 ++#define NUMREGBYTES (GDB_MAX_REGS << 2) ++#define NUMCRITREGBYTES (32 << 2) ++ ++#define _R0 0 ++#define _R1 1 ++#define _R2 2 ++#define _R3 3 ++#define _R4 4 ++#define _R5 5 ++#define _R6 6 ++#define _R7 7 ++#define _R8 8 ++#define _R9 9 ++#define _R10 10 ++#define _FP 11 ++#define _IP 12 ++#define _SPT 13 ++#define _LR 14 ++#define _PC 15 ++#define _CPSR (GDB_MAX_REGS - 1) ++ ++/* ++ * So that we can denote the end of a frame for tracing, ++ * in the simple case: ++ */ ++#define CFI_END_FRAME(func) __CFI_END_FRAME(_PC, _SPT, func) ++ ++#endif /* __ASM_KGDB_H__ */ +diff --git a/include/asm-arm/traps.h b/include/asm-arm/traps.h +index d4f34dc..94c0760 100644 +--- a/include/asm-arm/traps.h ++++ b/include/asm-arm/traps.h +@@ -15,4 +15,6 @@ struct undef_hook { + void register_undef_hook(struct undef_hook *hook); + void unregister_undef_hook(struct undef_hook *hook); + ++extern void __init early_trap_init(void); ++ + #endif +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0084-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook2.patch +++ linux-2.6.24/patches/0084-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook2.patch @@ -0,0 +1,30 @@ +From 4c3359c7ee73d465c0ae32350a1e6c4d25d0e94a Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Thu, 11 Dec 2008 11:25:52 -0800 +Subject: [PATCH 084/170] UBUNTU: NBK-Ubuntu-2.6.24-22.45netbook2 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index bb9f17e..e8a1f92 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-22.45netbook2) hardy; urgency=low ++ ++ [Upstream Kernel Changes] ++ ++ * Fix for suspend / resume (LP: 284062) ++ ++ -- Michael Frey Thu, 11 Dec 2008 11:23:45 -0800 ++ + linux (2.6.24-22.45netbook1) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0131-UBUNTU-SAUCE-hardy-netbook-lpia-branch-display-easel.patch +++ linux-2.6.24/patches/0131-UBUNTU-SAUCE-hardy-netbook-lpia-branch-display-easel.patch @@ -0,0 +1,60 @@ +From 49d03150bda401bd09523f92f66a4e0cf9a37372 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Mon, 6 Apr 2009 08:01:41 -0500 +Subject: [PATCH 131/170] UBUNTU: SAUCE: hardy netbook-lpia branch display easel mode + +OriginalAuthor: Steve Conklin +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/320866 +Change the formatting of the ourput in the procfs entry +for easel mode, and add an uninitialized state (-1) so we +can tell if we never got any keycodes. + +Signed-off-by: Steve Conklin +--- + drivers/input/input.c | 21 ++++++++++++++++++--- + 1 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/drivers/input/input.c b/drivers/input/input.c +index cb3b097..7d09ac6 100644 +--- a/drivers/input/input.c ++++ b/drivers/input/input.c +@@ -41,7 +41,7 @@ static DEFINE_MUTEX(input_mutex); + + static struct input_handler *input_table[8]; + +-static int easelmode; ++static int easelmode = -1; + + static inline int is_event_supported(unsigned int code, + unsigned long *bm, unsigned int max) +@@ -849,10 +849,25 @@ static int proc_read_easelmode(char *buffer, char **buffer_location, + if (offset > 0) + ret = 0; + else +- ret = sprintf(buffer, "%1d\n", easelmode); ++ switch (easelmode) { ++ case -1: ++ strncpy(buffer, "-1\n", 3); ++ ret = 3; ++ break; ++ case 0: ++ strncpy(buffer, "0\n", 2); ++ ret = 2; ++ break; ++ case 1: ++ strncpy(buffer, "1\n", 2); ++ ret = 2; ++ break; ++ default: ++ strncpy(buffer, "?\n", 2); ++ ret = 2; ++ } + + return ret; +- + } + + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0134-UBUNTU-fix-rebase-script-to-use-correct-tag-names-fo.patch +++ linux-2.6.24/patches/0134-UBUNTU-fix-rebase-script-to-use-correct-tag-names-fo.patch @@ -0,0 +1,28 @@ +From 57ad54c695ed27ef60e40611cfa37a28db8442ab Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Wed, 8 Apr 2009 18:19:34 +0100 +Subject: [PATCH 134/170] UBUNTU: fix rebase script to use correct tag names for netbook + +Ensure we are using the right tag names for netbook tree. LPIA -> NBK. + +Signed-off-by: Andy Whitcroft +--- + debian/scripts/misc/rebase-branch | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/debian/scripts/misc/rebase-branch b/debian/scripts/misc/rebase-branch +index 5368d39..8426f99 100755 +--- a/debian/scripts/misc/rebase-branch ++++ b/debian/scripts/misc/rebase-branch +@@ -22,7 +22,7 @@ basever="2.6.24" + patchDir=$targetDir/patches + #masterTree=git://zinc.ubuntu.com/ubuntu/ubuntu-$release.git + #masterName=ubuntu-$release +-baseTag="LPIA-Ubuntu-$basever-0.0" ++baseTag="NBK-Ubuntu-$basever-0.0" + tmpTag="tmplpia" + + remoteBranch=auto-tmp-remote +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0122-Turn-debian-binary-custom.d-lpia-patchset-0017-pouls.patch +++ linux-2.6.24/patches/0122-Turn-debian-binary-custom.d-lpia-patchset-0017-pouls.patch @@ -0,0 +1,7562 @@ +From 97f4fed2816be985dbc2961070d7d15302ebd0d0 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:33 +0100 +Subject: [PATCH 122/170] Turn debian/binary-custom.d/lpia/patchset/0017-poulsbo_USBC.patch into a commit. + +Signed-off-by: Andy Whitcroft + +commit 2f4fe33cfbf6016f9dc2ff07b79adde8c6d3b410 +Author: Amit Kucheria +Date: Sat May 17 15:19:08 2008 +0300 + + UBUNTU: LPIA: USB Client PV release from Intel + + Signed-off-by: Amit Kucheria + +commit d3d7bf00d0bb682f6b929321ff01747e72469639 +Author: Jay Chetty +Date: Mon Mar 24 11:21:47 2008 -0700 + + UBUNTU:USBC:Integrated USBC 2.0.0.32L.0009 + + modified: debian/binary-custom.d/lpia/patchset/0017-poulsbo_USBC.patch + + Signed-off-by: Jay Chetty + Signed-off-by: Amit Kucheria + +commit 974128ae34a0e1907d86aa3f915cf9b6208cda88 +Author: Amit Kucheria +Date: Thu Mar 6 04:39:22 2008 +0200 + + UBUNTU: Poulsbo: Sync patches with moblin/ume-hardy tree + + Signed-off-by: Amit Kucheria + +commit 4883c50b37f2e791e29f545766e53ac456576926 +Author: Amit Kucheria +Date: Fri Jan 11 13:59:04 2008 +0200 + + UBUNTU: Poulsbo: Mass update of patches to be identical to those on moblin + + Sigh, we need better communication... + + Signed-off-by: Amit Kucheria +--- + .../lpia/patchset/0017-poulsbo_USBC.patch | 3748 -------------------- + drivers/usb/gadget/Kconfig | 21 + + drivers/usb/gadget/Makefile | 1 + + drivers/usb/gadget/ether.c | 39 +- + drivers/usb/gadget/file_storage.c | 62 +- + drivers/usb/gadget/gadget_chips.h | 7 + + drivers/usb/gadget/iusbc.c | 3120 ++++++++++++++++ + drivers/usb/gadget/iusbc.h | 213 ++ + drivers/usb/gadget/rndis.c | 14 +- + 9 files changed, 3464 insertions(+), 3761 deletions(-) + delete mode 100644 debian/binary-custom.d/lpia/patchset/0017-poulsbo_USBC.patch + create mode 100644 drivers/usb/gadget/iusbc.c + create mode 100644 drivers/usb/gadget/iusbc.h + +diff --git a/debian/binary-custom.d/lpia/patchset/0017-poulsbo_USBC.patch b/debian/binary-custom.d/lpia/patchset/0017-poulsbo_USBC.patch +deleted file mode 100644 +index a048aec..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0017-poulsbo_USBC.patch ++++ /dev/null +@@ -1,3748 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig +-index f81d08d..8d71885 100644 +---- a/drivers/usb/gadget/Kconfig +-+++ b/drivers/usb/gadget/Kconfig +-@@ -324,6 +324,27 @@ config USB_AT91 +- depends on USB_GADGET_AT91 +- default USB_GADGET +- +-+config USB_GADGET_IUSBC +-+ boolean "Intel USB Client Controller" +-+ depends on PCI +-+ select USB_GADGET_DUALSPEED +-+ help +-+ Intel USB client controller is a PCI based USB peripheral controller +-+ which supports both full and high speed USB 2.0 data transfers. +-+ +-+ It has three IN and three OUT configurable endpoints, as well +-+ as endpoint zero (for control transfers). +-+ +-+ Say "y" to link the driver statically, or "m" to build a +-+ dynamically linked module called "iusbc" and force all +-+ gadget drivers to also be dynamically linked. +-+ +-+config USB_IUSBC +-+ tristate +-+ depends on USB_GADGET_IUSBC +-+ default USB_GADGET +-+ select USB_GADGET_SELECTED +-+ +- config USB_GADGET_DUMMY_HCD +- boolean "Dummy HCD (DEVELOPMENT)" +- depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL +-diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile +-index 904e57b..8e533bf 100644 +---- a/drivers/usb/gadget/Makefile +-+++ b/drivers/usb/gadget/Makefile +-@@ -17,6 +17,7 @@ obj-$(CONFIG_USB_AT91) += at91_udc.o +- obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o +- obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o +- obj-$(CONFIG_USB_M66592) += m66592-udc.o +-+obj-$(CONFIG_USB_IUSBC) += iusbc.o +- +- # +- # USB gadget drivers +-diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c +-index 9e732bf..15a6dce 100644 +---- a/drivers/usb/gadget/ether.c +-+++ b/drivers/usb/gadget/ether.c +-@@ -19,7 +19,7 @@ +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +- +--/* #define VERBOSE_DEBUG */ +-+#define VERBOSE_DEBUG +- +- #include +- #include +-@@ -34,6 +34,10 @@ +- +- #include "gadget_chips.h" +- +-+#ifdef CONFIG_USB_GADGET_IUSBC +-+#include "iusbc.h" +-+#endif +-+ +- /*-------------------------------------------------------------------------*/ +- +- /* +-@@ -68,7 +72,7 @@ +- */ +- +- #define DRIVER_DESC "Ethernet Gadget" +--#define DRIVER_VERSION "May Day 2005" +-+#define DRIVER_VERSION "2.0.0.32L.0010" +- +- static const char shortname [] = "ether"; +- static const char driver_desc [] = DRIVER_DESC; +-@@ -239,6 +243,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); +- #define DEV_CONFIG_CDC +- #endif +- +-+#ifdef CONFIG_USB_GADGET_IUSBC +-+#define DEV_CONFIG_CDC +-+#endif +-+ +- #ifdef CONFIG_USB_GADGET_S3C2410 +- #define DEV_CONFIG_CDC +- #endif +-@@ -1353,11 +1361,31 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +- u16 wIndex = le16_to_cpu(ctrl->wIndex); +- u16 wValue = le16_to_cpu(ctrl->wValue); +- u16 wLength = le16_to_cpu(ctrl->wLength); +-+ __le16 status = 0; +- +- /* descriptors just go into the pre-allocated ep0 buffer, +- * while config change events may enable network traffic. +- */ +- req->complete = eth_setup_complete; +-+ +-+#ifdef CONFIG_USB_GADGET_IUSBC +-+ /* software handles get_status in iusbc controller */ +-+ if (gadget_is_iusbc(dev->gadget)) { +-+ if ((ctrl->bRequest == USB_REQ_GET_STATUS) +-+ && (ctrl->bRequestType & USB_DIR_IN) +-+ && (ctrl->bRequestType != 0x21)) { +-+ struct iusbc *controller = +-+ container_of(dev->gadget, +-+ struct iusbc, +-+ gadget); +-+ status = controller->status_d; +-+ DEBUG (dev, "status_d: %d\n", status); +-+ value = sizeof status; +-+ *(u16 *) req->buf = le16_to_cpu(status); +-+ } +-+ } +-+#endif +-+ +- switch (ctrl->bRequest) { +- +- case USB_REQ_GET_DESCRIPTOR: +-@@ -1421,7 +1449,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +- || !dev->config +- || wIndex > 1) +- break; +-- if (!cdc_active(dev) && wIndex != 0) +-+ if (!rndis_active(dev) && !cdc_active(dev) && wIndex != 0) +- break; +- spin_lock (&dev->lock); +- +-@@ -1556,9 +1584,9 @@ done_set_intf: +- u32 n; +- +- /* return the result */ +-- buf = rndis_get_next_response(dev->rndis_config, &n); +-+ buf = rndis_get_next_response (dev->rndis_config, &value); +- if (buf) { +-- memcpy(req->buf, buf, n); +-+ memcpy (req->buf, buf, value); +- req->complete = rndis_response_complete; +- rndis_free_response(dev->rndis_config, buf); +- } +-@@ -2639,6 +2667,7 @@ static struct usb_gadget_driver eth_driver = { +- +- MODULE_DESCRIPTION (DRIVER_DESC); +- MODULE_AUTHOR ("David Brownell, Benedikt Spanger"); +-+MODULE_VERSION(DRIVER_VERSION); +- MODULE_LICENSE ("GPL"); +- +- +-diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c +-index 1d174dc..4a48112 100644 +---- a/drivers/usb/gadget/file_storage.c +-+++ b/drivers/usb/gadget/file_storage.c +-@@ -244,18 +244,23 @@ +- +- #include "gadget_chips.h" +- +-+#ifdef CONFIG_USB_GADGET_IUSBC +-+#include "iusbc.h" +-+#include /* for uevent usage */ +-+#endif +- +- /*-------------------------------------------------------------------------*/ +- +- #define DRIVER_DESC "File-backed Storage Gadget" +- #define DRIVER_NAME "g_file_storage" +--#define DRIVER_VERSION "7 August 2007" +-+#define DRIVER_VERSION "2.0.0.32L.0010" +- +- static const char longname[] = DRIVER_DESC; +- static const char shortname[] = DRIVER_NAME; +- +- MODULE_DESCRIPTION(DRIVER_DESC); +- MODULE_AUTHOR("Alan Stern"); +-+MODULE_VERSION(DRIVER_VERSION); +- MODULE_LICENSE("Dual BSD/GPL"); +- +- /* Thanks to NetChip Technologies for donating this product ID. +-@@ -545,6 +550,7 @@ struct lun { +- unsigned int prevent_medium_removal : 1; +- unsigned int registered : 1; +- unsigned int info_valid : 1; +-+ unsigned int switch_flag : 1; +- +- u32 sense_data; +- u32 sense_data_info; +-@@ -684,6 +690,7 @@ struct fsg_dev { +- unsigned int nluns; +- struct lun *luns; +- struct lun *curlun; +-+ int uevent_flag; +- }; +- +- typedef void (*fsg_routine_t)(struct fsg_dev *); +-@@ -1335,11 +1342,27 @@ static int standard_setup_req(struct fsg_dev *fsg, +- int value = -EOPNOTSUPP; +- u16 w_index = le16_to_cpu(ctrl->wIndex); +- u16 w_value = le16_to_cpu(ctrl->wValue); +-+ __le16 status = 0; +- +- /* Usually this just stores reply data in the pre-allocated ep0 buffer, +- * but config change events will also reconfigure hardware. */ +- switch (ctrl->bRequest) { +- +-+#ifdef CONFIG_USB_GADGET_IUSBC +-+ case USB_REQ_GET_STATUS: +-+ /* software handles get_status in iusbc controller */ +-+ if (gadget_is_iusbc(fsg->gadget)) { +-+ struct iusbc *controller = +-+ container_of(fsg->gadget, +-+ struct iusbc, +-+ gadget); +-+ status = controller->status_d; +-+ DBG(fsg, "status_d: %d\n", status); +-+ value = sizeof status; +-+ *(u16 *) req->buf = le16_to_cpu(status); +-+ } +-+ break; +-+#endif +- case USB_REQ_GET_DESCRIPTOR: +- if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | +- USB_RECIP_DEVICE)) +-@@ -1392,6 +1415,13 @@ get_config: +- if (w_value == CONFIG_VALUE || w_value == 0) { +- fsg->new_config = w_value; +- +-+#ifdef CONFIG_USB_GADGET_IUSBC +-+ /* for resume from S3 in iusbc controller */ +-+ if (gadget_is_iusbc(fsg->gadget)) { +-+ fsg->state = FSG_STATE_IDLE; +-+ fsg->config = 0; +-+ } +-+#endif +- /* Raise an exception to wipe out previous transaction +- * state (queued bufs, etc) and set the new config. */ +- raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); +-@@ -2853,6 +2883,9 @@ static int do_scsi_command(struct fsg_dev *fsg) +- break; +- +- case SC_TEST_UNIT_READY: +-+ i = fsg->cmnd[2]; +-+ if (i == 0x55) +-+ fsg->curlun->switch_flag = 1; +- fsg->data_size_from_cmnd = 0; +- reply = check_command(fsg, 6, DATA_DIR_NONE, +- 0, 1, +-@@ -3357,6 +3390,13 @@ static void handle_exception(struct fsg_dev *fsg) +- +- case FSG_STATE_CONFIG_CHANGE: +- rc = do_set_config(fsg, new_config); +-+#ifdef CONFIG_USB_GADGET_IUSBC +-+ if (!fsg->uevent_flag){ +-+ struct iusbc *_iusbc=container_of(fsg->gadget,struct iusbc,gadget); +-+ kobject_uevent(&(_iusbc->pdev->dev.kobj), KOBJ_ONLINE); +-+ fsg->uevent_flag=1; +-+ } +-+#endif +- if (fsg->ep0_req_tag != exception_req_tag) +- break; +- if (rc != 0) // STALL on errors +-@@ -3368,6 +3408,13 @@ static void handle_exception(struct fsg_dev *fsg) +- case FSG_STATE_DISCONNECT: +- fsync_all(fsg); +- do_set_config(fsg, 0); // Unconfigured state +-+#ifdef CONFIG_USB_GADGET_IUSBC +-+ if (fsg->uevent_flag) { +-+ struct iusbc *_iusbc=container_of(fsg->gadget,struct iusbc,gadget); +-+ kobject_uevent(&(_iusbc->pdev->dev.kobj), KOBJ_OFFLINE); +-+ fsg->uevent_flag=0; +-+ } +-+#endif +- break; +- +- case FSG_STATE_EXIT: +-@@ -3585,6 +3632,12 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, +- return rc; +- } +- +-+static ssize_t show_switch(struct device *dev, struct device_attribute *attr, char *buf) +-+{ +-+ struct lun *curlun = dev_to_lun(dev); +-+ +-+ return sprintf(buf, "%d\n", curlun->switch_flag); +-+} +- +- static ssize_t store_ro(struct device *dev, struct device_attribute *attr, +- const char *buf, size_t count) +-@@ -3649,6 +3702,7 @@ static ssize_t store_file(struct device *dev, struct device_attribute *attr, +- /* The write permissions and store_xxx pointers are set in fsg_bind() */ +- static DEVICE_ATTR(ro, 0444, show_ro, NULL); +- static DEVICE_ATTR(file, 0444, show_file, NULL); +-+static DEVICE_ATTR(switch, 0444, show_switch, NULL); +- +- +- /*-------------------------------------------------------------------------*/ +-@@ -3684,6 +3738,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) +- if (curlun->registered) { +- device_remove_file(&curlun->dev, &dev_attr_ro); +- device_remove_file(&curlun->dev, &dev_attr_file); +-+ device_remove_file(&curlun->dev, &dev_attr_switch); +- device_unregister(&curlun->dev); +- curlun->registered = 0; +- } +-@@ -3842,6 +3897,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) +- +- for (i = 0; i < fsg->nluns; ++i) { +- curlun = &fsg->luns[i]; +-+ curlun->switch_flag = 0; +- curlun->ro = mod_data.ro[i]; +- curlun->dev.release = lun_release; +- curlun->dev.parent = &gadget->dev; +-@@ -3857,7 +3913,9 @@ static int __init fsg_bind(struct usb_gadget *gadget) +- if ((rc = device_create_file(&curlun->dev, +- &dev_attr_ro)) != 0 || +- (rc = device_create_file(&curlun->dev, +-- &dev_attr_file)) != 0) { +-+ &dev_attr_file)) != 0 || +-+ (rc = device_create_file(&curlun->dev, +-+ &dev_attr_switch)) != 0) { +- device_unregister(&curlun->dev); +- goto out; +- } +-diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h +-index f7f159c..41b5c9a 100644 +---- a/drivers/usb/gadget/gadget_chips.h +-+++ b/drivers/usb/gadget/gadget_chips.h +-@@ -147,6 +147,11 @@ +- #define gadget_is_m66592(g) 0 +- #endif +- +-+#ifdef CONFIG_USB_GADGET_IUSBC +-+#define gadget_is_iusbc(g) !strcmp("iusbc", (g)->name) +-+#else +-+#define gadget_is_iusbc(g) 0 +-+#endif +- +- // CONFIG_USB_GADGET_SX2 +- // CONFIG_USB_GADGET_AU1X00 +-@@ -212,5 +217,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) +- return 0x20; +- else if (gadget_is_m66592(gadget)) +- return 0x21; +-+ else if (gadget_is_iusbc(gadget)) +-+ return 0x99; +- return -ENOENT; +- } +-diff --git a/drivers/usb/gadget/iusbc.c b/drivers/usb/gadget/iusbc.c +-new file mode 100644 +-index 0000000..345c64b +---- /dev/null +-+++ b/drivers/usb/gadget/iusbc.c +-@@ -0,0 +1,3120 @@ +-+/* +-+ * Intel Poulsbo USB Client Controller Driver +-+ * Copyright (C) 2006-07, Intel Corporation. +-+ * +-+ * This program is free software; you can redistribute it and/or modify it +-+ * under the terms and conditions of the GNU General Public License, +-+ * version 2, as published by the Free Software Foundation. +-+ * +-+ * This program is distributed in the hope it will be useful, but WITHOUT +-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +-+ * more details. +-+ * +-+ * You should have received a copy of the GNU General Public License along with +-+ * this program; if not, write to the Free Software Foundation, Inc., +-+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +-+ * +-+ */ +-+ +-+ +-+#define DEBUG /* messages on error and most fault paths */ +-+//#define VERBOSE /* extra debug messages (success too) */ +-+ +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+ +-+/* Power management */ +-+#include +-+ +-+#include +-+#include +-+#include +-+#include +-+#include +-+ +-+#include "iusbc.h" +-+ +-+#define DRIVER_DESC "Intel Poulsbo USB Client Controller Driver" +-+#define DRIVER_VERSION "2.0.0.32L.0010" +-+ +-+#define DMA_ADDR_INVALID (~(dma_addr_t)0) +-+ +-+static const char driver_name [] = "iusbc"; +-+static const char driver_desc [] = DRIVER_DESC; +-+ +-+static const char *const ep_name [] = { +-+ "ep0-in", "ep0-out", +-+ "ep1in-bulk", "ep1out-bulk", +-+ "ep2in-int", "ep2out-int", +-+ "ep3in-iso", "ep3out-iso", +-+}; +-+ +-+ +-+/* module parameter */ +-+ +-+/* force_fullspeed -- device will be forced to full speed operation +-+ * default value: 0 for high speed +-+ */ +-+static int force_fullspeed = 0; +-+ +-+/* modprobe iusbc force_fullspeed=n" etc */ +-+/* XXX: remove this feature due to HW full-speed bug +-+ * module_param (force_fullspeed, bool, S_IRUGO); +-+ */ +-+ +-+//#define RNDIS_INIT_HW_BUG +-+//#define DMA_DISABLED +-+ +-+/*-------------------------------------------------------------------------*/ +-+/* DEBUGGING */ +-+#define xprintk(dev,level,fmt,args...) \ +-+ printk(level "%s %s: " fmt , driver_name , \ +-+ pci_name(dev->pdev) , ## args) +-+ +-+#ifdef DEBUG +-+#undef DEBUG +-+#define DEBUG(dev,fmt,args...) \ +-+ xprintk(dev , KERN_DEBUG , fmt , ## args) +-+#else +-+#define DEBUG(dev,fmt,args...) \ +-+ do { } while (0) +-+#endif /* DEBUG */ +-+ +-+ +-+#ifdef VERBOSE +-+#define VDEBUG DEBUG +-+#else +-+#define VDEBUG(dev,fmt,args...) \ +-+ do { } while (0) +-+#endif /* VERBOSE */ +-+ +-+ +-+#define ERROR(dev,fmt,args...) \ +-+ xprintk(dev , KERN_ERR , fmt , ## args) +-+#define WARN(dev,fmt,args...) \ +-+ xprintk(dev , KERN_WARNING , fmt , ## args) +-+#define INFO(dev,fmt,args...) \ +-+ xprintk(dev , KERN_INFO , fmt , ## args) +-+ +-+ +-+#ifdef VERBOSE +-+static inline void print_all_registers(struct iusbc_regs *regs) +-+{ +-+ unsigned i, j; +-+ /* device */ +-+ printk(KERN_DEBUG "----Intel USB-C Memory Space Registers----\n"); +-+ printk(KERN_DEBUG "Register Length: 0x%x\n", +-+ sizeof(struct iusbc_regs)); +-+ printk(KERN_DEBUG "gcap=0x%08x\n", readl(®s->gcap)); +-+ printk(KERN_DEBUG "dev_sts=0x%08x\n", readl(®s->dev_sts)); +-+ printk(KERN_DEBUG "frame=0x%04x\n", readw(®s->frame)); +-+ printk(KERN_DEBUG "int_sts=0x%08x\n", readl(®s->int_sts)); +-+ printk(KERN_DEBUG "int_ctrl=0x%08x\n", readl(®s->int_ctrl)); +-+ printk(KERN_DEBUG "dev_ctrl=0x%08x\n", readl(®s->dev_ctrl)); +-+ +-+ /* endpoints */ +-+ for (i = 0; i < 5; i++) { +-+ printk(KERN_DEBUG "ep[%d]_base_low_32=0x%08x\n", +-+ i, readl(®s->ep[i].ep_base_low_32)); +-+ printk(KERN_DEBUG "ep[%d]_base_hi_32=0x%08x\n", +-+ i, readl(®s->ep[i].ep_base_hi_32)); +-+ printk(KERN_DEBUG "ep[%d]_len=0x%04x\n", +-+ i, readw(®s->ep[i].ep_len)); +-+ printk(KERN_DEBUG "ep[%d]_pib=0x%04x\n", +-+ i, readw(®s->ep[i].ep_pib)); +-+ printk(KERN_DEBUG "ep[%d]_dil=0x%04x\n", +-+ i, readw(®s->ep[i].ep_dil)); +-+ printk(KERN_DEBUG "ep[%d]_tiq=0x%04x\n", +-+ i, readw(®s->ep[i].ep_tiq)); +-+ printk(KERN_DEBUG "ep[%d]_max=0x%04x\n", +-+ i, readw(®s->ep[i].ep_max)); +-+ printk(KERN_DEBUG "ep[%d]_sts=0x%04x\n", +-+ i, readw(®s->ep[i].ep_sts)); +-+ printk(KERN_DEBUG "ep[%d]_cfg=0x%04x\n", +-+ i, readw(®s->ep[i].ep_cfg)); +-+ +-+ if (1 == i) { /* ep0-out */ +-+ printk(KERN_DEBUG "ep-out setup_pkt_sts=0x%02x\n", +-+ readb(®s->ep[i].setup_pkt_sts)); +-+ for (j = 0; j< 8; j++) { +-+ printk(KERN_DEBUG "ep0-out " +-+ "setup_pkt[%d]=0x%02x\n", +-+ j, readb(®s->ep[i].setup_pkt[j])); +-+ } +-+ } +-+ } +-+} +-+ +-+#endif /* VERBOSE */ +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out") +-+ +-+ +-+#if defined(CONFIG_USB_GADGET_DEBUG_FILES) || defined (DEBUG) +-+static char *type_string(u8 bmAttributes) +-+{ +-+ switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { +-+ case USB_ENDPOINT_XFER_BULK: +-+ return "bulk"; +-+ case USB_ENDPOINT_XFER_ISOC: +-+ return "iso"; +-+ case USB_ENDPOINT_XFER_INT: +-+ return "int"; +-+ }; +-+ +-+ return "control"; +-+} +-+#endif +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+/* configure endpoint, making it usable */ +-+static int +-+iusbc_ep_enable(struct usb_ep *_ep, +-+ const struct usb_endpoint_descriptor *desc) +-+{ +-+ struct iusbc *dev; +-+ struct iusbc_ep *ep; +-+ u16 val_16, max; +-+ u8 val_8; +-+ unsigned long flags; +-+ unsigned i; +-+ int retval; +-+ +-+ ep = container_of(_ep, struct iusbc_ep, ep); +-+ +-+ DEBUG(ep->dev, "---> iusbc_ep_enable() \n"); +-+ +-+ if (!_ep || !desc || _ep->name == "ep0-in" +-+ || _ep->name == "ep0-out" +-+ || desc->bDescriptorType != USB_DT_ENDPOINT) +-+ return -EINVAL; +-+ +-+ dev = ep->dev; +-+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) +-+ return -ESHUTDOWN; +-+ +-+ /* wMaxPacketSize up to 1024 bytes */ +-+ max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff; +-+ +-+ spin_lock_irqsave(&dev->lock, flags); +-+ ep->ep.maxpacket = max; +-+ if (!ep->desc) +-+ ep->desc = desc; +-+ +-+ /* ep_reset() has already been called */ +-+ ep->stopped = 0; +-+ ep->is_in = (USB_DIR_IN & desc->bEndpointAddress) != 0; +-+ +-+ /* sanity check type, direction, address */ +-+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { +-+ case USB_ENDPOINT_XFER_BULK: +-+ if ((dev->gadget.speed == USB_SPEED_HIGH +-+ && max != 512) +-+ || (dev->gadget.speed == USB_SPEED_FULL +-+ && max > 64)) { +-+ goto done; +-+ } +-+ break; +-+ case USB_ENDPOINT_XFER_INT: +-+ if (strstr (ep->ep.name, "-iso")) /* bulk is ok */ +-+ goto done; +-+ +-+ switch (dev->gadget.speed) { +-+ case USB_SPEED_HIGH: +-+ if (max <= 1024) +-+ break; +-+ case USB_SPEED_FULL: +-+ if (max <= 64) +-+ break; +-+ default: +-+ if (max <= 8) +-+ break; +-+ goto done; +-+ } +-+ break; +-+ case USB_ENDPOINT_XFER_ISOC: +-+ if (strstr (ep->ep.name, "-bulk") +-+ || strstr (ep->ep.name, "-int")) +-+ goto done; +-+ +-+ switch (dev->gadget.speed) { +-+ case USB_SPEED_HIGH: +-+ if (max <= 1024) +-+ break; +-+ case USB_SPEED_FULL: +-+ if (max <= 1023) +-+ break; +-+ default: +-+ goto done; +-+ } +-+ break; +-+ default: +-+ goto done; +-+ } +-+ +-+ /* ep_type */ +-+ ep->ep_type = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); +-+ +-+ /* DMA modes, only support Linear Mode now */ +-+ if (ep->dev->sg_mode_dma) { +-+ ep->dma_mode = SCATTER_GATHER_MODE; +-+ } else { +-+ ep->dma_mode = LINEAR_MODE; +-+ } +-+ +-+ /* reset ep registers to default value */ +-+ i = ep->num; +-+ writew(0, &dev->regs->ep[i].ep_cfg); +-+ +-+ /* set endpoints valid */ +-+ val_16 = readw(&dev->regs->ep[i].ep_cfg); +-+ val_16 |= INTR_BAD_PID_TYPE +-+ | INTR_CRC_ERROR +-+ | INTR_FIFO_ERROR +-+ | INTR_DMA_ERROR +-+ | INTR_TRANS_COMPLETE +-+ /* | INTR_PING_NAK_SENT */ +-+ | INTR_DMA_IOC +-+ | ep->dma_mode << 6 +-+ | ep->ep_type << 4 +-+ /* | EP_ENABLE */ +-+ | EP_VALID; +-+ +-+ /* will set EP_ENABLE later to start dma */ +-+ writew(val_16, &dev->regs->ep[i].ep_cfg); +-+ +-+ val_16 = readw(&dev->regs->ep[i].ep_cfg); +-+ VDEBUG(dev, "%s.ep_cfg = 0x%04x\n", _ep->name, val_16); +-+ +-+ val_8 = desc->bEndpointAddress; +-+ DEBUG(dev, "enabled %s (ep%d%s-%s), max %04x, dma_mode: %02x\n", +-+ _ep->name, +-+ val_8 & USB_ENDPOINT_NUMBER_MASK, +-+ DIR_STRING(val_8), +-+ type_string(desc->bmAttributes), +-+ max, +-+ ep->dma_mode); +-+ +-+ retval = 0; +-+done: +-+ spin_unlock_irqrestore(&dev->lock, flags); +-+ DEBUG(ep->dev, "<--- iusbc_ep_enable() \n"); +-+ return retval; +-+} +-+ +-+ +-+static const struct usb_ep_ops iusbc_ep_ops; +-+ +-+static void ep_reset(struct iusbc_regs __iomem *regs, struct iusbc_ep *ep) +-+{ +-+ unsigned i = ep->num; +-+ +-+ /* reset ep values */ +-+ ep->stopped = 1; +-+ ep->ep.maxpacket = ~0; +-+ ep->ep.ops = &iusbc_ep_ops; +-+ +-+ /* reset ep registers to default value +-+ * clear all interrupt and status +-+ * clear and reset all DMA FIFOs and state machine +-+ * hardware shall minimize power usage +-+ */ +-+ writew(0, ®s->ep[i].ep_cfg); +-+} +-+ +-+ +-+static void nuke(struct iusbc_ep *); +-+ +-+/* endpoint is no longer usable */ +-+static int +-+iusbc_ep_disable(struct usb_ep *_ep) +-+{ +-+ struct iusbc_ep *ep; +-+ unsigned long flags; +-+ struct iusbc *dev; +-+ unsigned i; +-+ u16 val_16; +-+ +-+ ep = container_of(_ep, struct iusbc_ep, ep); +-+ +-+ VDEBUG(ep->dev, "---> iusbc_ep_disable() \n"); +-+ +-+ if (!_ep || !ep->desc +-+ || _ep->name == "ep0-in" +-+ || _ep->name == "ep0-out") +-+ return -EINVAL; +-+ +-+ dev = ep->dev; +-+ if (dev->ep0state == EP0_SUSPEND) +-+ return -EBUSY; +-+ +-+ spin_lock_irqsave(&ep->dev->lock, flags); +-+ nuke(ep); +-+ ep_reset(ep->dev->regs, ep); +-+ +-+ i = ep->num; +-+ +-+ /* display endpoint configuration register */ +-+ val_16 = readw(&dev->regs->ep[i].ep_cfg); +-+ VDEBUG(dev, "%s.ep_cfg = 0x%04x\n", _ep->name, val_16); +-+ +-+ spin_unlock_irqrestore(&ep->dev->lock, flags); +-+ +-+ DEBUG(ep->dev, "disabled %s\n", _ep->name); +-+ +-+ VDEBUG(ep->dev, "<--- iusbc_ep_disable() \n"); +-+ +-+ return 0; +-+} +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+/* allocate a request object to use with this endpoint */ +-+static struct usb_request * +-+iusbc_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +-+{ +-+ struct iusbc_ep *ep; +-+ struct iusbc_request *req; +-+ struct iusbc_dma *td; +-+ +-+ if (!_ep) +-+ return NULL; +-+ ep = container_of(_ep, struct iusbc_ep, ep); +-+ +-+ VDEBUG(ep->dev, "---> iusbc_alloc_request() \n"); +-+ +-+ req = kzalloc(sizeof(*req), gfp_flags); +-+ if (!req) +-+ return NULL; +-+ +-+ req->req.dma = DMA_ADDR_INVALID; +-+ INIT_LIST_HEAD(&req->queue); +-+ +-+ /* this dma descriptor may be swapped with the previous dummy */ +-+ td = pci_pool_alloc(ep->dev->requests, +-+ gfp_flags, +-+ &req->td_dma); +-+ +-+ if (!td) { +-+ kfree(req); +-+ return NULL; +-+ } +-+ +-+ td->dmacount = 0; /* not VALID */ +-+ td->dmaaddr = __constant_cpu_to_le32(DMA_ADDR_INVALID); +-+ +-+ req->td = td; +-+ +-+ VDEBUG(ep->dev, "alloc request for %s\n", _ep->name); +-+ +-+ VDEBUG(ep->dev, "<--- iusbc_alloc_request() \n"); +-+ +-+ return &req->req; +-+} +-+ +-+ +-+/* frees a request object */ +-+static void +-+iusbc_free_request(struct usb_ep *_ep, struct usb_request *_req) +-+{ +-+ struct iusbc_ep *ep; +-+ struct iusbc_request *req; +-+ +-+ ep = container_of(_ep, struct iusbc_ep, ep); +-+ +-+ VDEBUG(ep->dev, "---> iusbc_free_request() \n"); +-+ +-+ if (!_ep || !_req) +-+ return; +-+ +-+ req = container_of(_req, struct iusbc_request, req); +-+ +-+ WARN_ON(!list_empty(&req->queue)); +-+ +-+ if (req->td) +-+ pci_pool_free(ep->dev->requests, req->td, req->td_dma); +-+ +-+ kfree(req); +-+ +-+ VDEBUG(ep->dev, "free request for %s\n", _ep->name); +-+ +-+ VDEBUG(ep->dev, "<--- iusbc_free_request() \n"); +-+} +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+/* allocate an I/O buffer +-+ * +-+ * dma-coherent memory allocation +-+ * +-+ * NOTE: the dma_*_coherent() API calls suck. Most implementations are +-+ * (a) page-oriented, so small buffers lose big; and (b) asymmetric with +-+ * respect to calls with irqs disabled: alloc is safe, free is not. +-+ * We currently work around (b), but not (a). +-+ */ +-+static void * +-+iusbc_alloc_buffer( +-+ struct usb_ep *_ep, +-+ unsigned bytes, +-+ dma_addr_t *dma, +-+ gfp_t gfp_flags +-+) +-+{ +-+ void *retval; +-+ struct iusbc_ep *ep; +-+ +-+ ep = container_of(_ep, struct iusbc_ep, ep); +-+ +-+ VDEBUG(ep->dev, "---> iusbc_alloc_buffer() \n"); +-+ +-+ if (!_ep) +-+ return NULL; +-+ +-+ *dma = DMA_ADDR_INVALID; +-+ +-+ retval = dma_alloc_coherent(&ep->dev->pdev->dev, +-+ bytes, dma, gfp_flags); +-+ +-+ DEBUG(ep->dev, "alloc buffer for %s\n", _ep->name); +-+ +-+ VDEBUG(ep->dev, "<--- iusbc_alloc_buffer() \n"); +-+ +-+ return retval; +-+} +-+ +-+ +-+static DEFINE_SPINLOCK(buflock); +-+static LIST_HEAD(buffers); +-+ +-+struct free_record { +-+ struct list_head list; +-+ struct device *dev; +-+ unsigned bytes; +-+ dma_addr_t dma; +-+}; +-+ +-+ +-+static void do_free(unsigned long ignored) +-+{ +-+#ifdef VERBOSE +-+ printk(KERN_DEBUG "---> do_free() \n"); +-+#endif +-+ +-+ spin_lock_irq(&buflock); +-+ while (!list_empty(&buffers)) { +-+ struct free_record *buf; +-+ +-+ buf = list_entry(buffers.next, struct free_record, list); +-+ list_del(&buf->list); +-+ spin_unlock_irq(&buflock); +-+ +-+ dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma); +-+ +-+ spin_lock_irq(&buflock); +-+ } +-+ spin_unlock_irq(&buflock); +-+ +-+#ifdef VERBOSE +-+ printk(KERN_DEBUG "<--- do_free() \n"); +-+#endif +-+} +-+ +-+static DECLARE_TASKLET(deferred_free, do_free, 0); +-+ +-+/* free an I/O buffer */ +-+static void +-+iusbc_free_buffer( +-+ struct usb_ep *_ep, +-+ void *address, +-+ dma_addr_t dma, +-+ unsigned bytes +-+) { +-+ +-+ /* free memory into the right allocator */ +-+ if (dma != DMA_ADDR_INVALID) { +-+ struct iusbc_ep *ep; +-+ struct free_record *buf = address; +-+ unsigned long flags; +-+ +-+ ep = container_of(_ep, struct iusbc_ep, ep); +-+ +-+ VDEBUG(ep->dev, "---> iusbc_free_buffer() \n"); +-+ +-+ if (!_ep) +-+ return; +-+ +-+ buf->dev = &ep->dev->pdev->dev; +-+ buf->bytes = bytes; +-+ buf->dma = dma; +-+ +-+ spin_lock_irqsave(&buflock, flags); +-+ list_add_tail(&buf->list, &buffers); +-+ tasklet_schedule(&deferred_free); +-+ spin_unlock_irqrestore(&buflock, flags); +-+ +-+ DEBUG(ep->dev, "free buffer for %s\n", _ep->name); +-+ VDEBUG(ep->dev, "<--- iusbc_free_buffer() \n"); +-+ +-+ } else +-+ kfree(address); +-+} +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+/* fill out dma descriptor to match a given request */ +-+static void +-+fill_dma(struct iusbc_ep *ep, struct iusbc_request *req) +-+{ +-+ struct iusbc_dma *td = req->td; +-+ u16 dmacount; +-+ +-+ VDEBUG(ep->dev, "---> fill_dma() \n"); +-+ +-+ dmacount = req->req.length; +-+ +-+ td->dmaaddr = cpu_to_le32(req->req.dma); +-+ td->dmacount = cpu_to_le16(dmacount); +-+ +-+ VDEBUG(ep->dev, "<--- fill_dma() \n"); +-+} +-+ +-+ +-+static void start_dma(struct iusbc_ep *ep, struct iusbc_request *req) +-+{ +-+ u16 val_16; +-+ u32 val_32; +-+ unsigned i; +-+ +-+ VDEBUG(ep->dev, "---> start_dma() \n"); +-+ +-+ i = ep->num; +-+ +-+ /* init req->td, pointing to the current dummy */ +-+ fill_dma(ep, req); +-+ +-+ /* ep_base_low_32 */ +-+ writel(cpu_to_le32(req->req.dma), +-+ &ep->dev->regs->ep[i].ep_base_low_32); +-+ val_32 = readl(&ep->dev->regs->ep[i].ep_base_low_32); +-+ VDEBUG(ep->dev, "%s.ep_base_low_32=0x%08x\n", +-+ ep->ep.name, val_32); +-+ +-+ /* ep_base_hi_32 */ +-+ writel(0, &ep->dev->regs->ep[i].ep_base_hi_32); +-+ val_32 = readl(&ep->dev->regs->ep[i].ep_base_hi_32); +-+ VDEBUG(ep->dev, "%s.ep_base_hi_32=0x%08x\n", +-+ ep->ep.name, val_32); +-+ +-+ writew(le16_to_cpu(req->td->dmacount), &ep->dev->regs->ep[i].ep_len); +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_len); +-+ VDEBUG(ep->dev, "%s.ep_len=0x%04x\n", +-+ ep->ep.name, val_16); +-+ +-+ /* endpoint maximum transaction size, up to 1024 Bytes */ +-+ writew((ep->ep.maxpacket & 0x3ff), +-+ &ep->dev->regs->ep[i].ep_max); +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_max); +-+ VDEBUG(ep->dev, "%s.ep_max=0x%04x\n", +-+ ep->ep.name, val_16); +-+ +-+ /* validate endpoint, enable DMA */ +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); +-+ val_16 |= EP_VALID | EP_ENABLE; +-+ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); +-+ +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); +-+ VDEBUG(ep->dev, "enable %s DMA transfer...\n", +-+ ep->ep.name); +-+ VDEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", +-+ ep->ep.name, val_16); +-+ +-+ VDEBUG(ep->dev, "<--- start_dma() \n"); +-+} +-+ +-+ +-+/* queues I/O requests in endpoint queue */ +-+static inline void +-+queue_dma(struct iusbc_ep *ep, struct iusbc_request *req) +-+{ +-+ struct iusbc_dma *end; +-+ dma_addr_t tmp_dma_addr; +-+ +-+ VDEBUG(ep->dev, "---> queue_dma() \n"); +-+ +-+ /* swap new dummy for old, link; fill and maybe activate */ +-+ end = ep->dummy; +-+ ep->dummy = req->td; +-+ req->td = end; +-+ +-+ tmp_dma_addr = ep->td_dma; +-+ ep->td_dma = req->td_dma; +-+ req->td_dma = tmp_dma_addr; +-+ +-+ fill_dma(ep, req); +-+ +-+ VDEBUG(ep->dev, "<--- queue_dma() \n"); +-+} +-+ +-+ +-+static void +-+done(struct iusbc_ep *ep, struct iusbc_request *req, int status) +-+{ +-+ struct iusbc *dev; +-+ unsigned stopped = ep->stopped; +-+ +-+ VDEBUG(ep->dev, "---> done() \n"); +-+ +-+ list_del_init(&req->queue); +-+ +-+ if (req->req.status == -EINPROGRESS) +-+ req->req.status = status; +-+ else +-+ status = req->req.status; +-+ +-+ dev = ep->dev; +-+ +-+ if (req->mapped) { +-+ pci_unmap_single(dev->pdev, req->req.dma, req->req.length, +-+ ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); +-+ req->req.dma = DMA_ADDR_INVALID; +-+ req->mapped = 0; +-+ } +-+ +-+ if (status != -ESHUTDOWN) +-+ DEBUG(dev, "complete %s, req %p, stat %d, len %u/%u\n", +-+ ep->ep.name, &req->req, status, +-+ req->req.actual, req->req.length); +-+ +-+ /* don't modify queue heads during completion callback */ +-+ ep->stopped = 1; +-+ +-+ /* XXX WORKAROUND: first ep0-out OUT packet HW BUG */ +-+#ifdef RNDIS_INIT_HW_BUG +-+ if (ep->num == 1) { +-+ char *buf; +-+ const u8 remote_ndis_initialize_msg[24] = { +-+ 0x02, 0x00, 0x00, 0x00, +-+ 0x18, 0x00, 0x00, 0x00, +-+ 0x02, 0x00, 0x00, 0x00, +-+ 0x01, 0x00, 0x00, 0x00, +-+ 0x00, 0x00, 0x00, 0x00, +-+ 0x00, 0x04, 0x00, 0x00 +-+ }; +-+ +-+ buf = req->req.buf; +-+ +-+ /* req->buf haven't been DMAed for hardware bug? */ +-+ if ((buf[0] == 0x09) && (buf[1] == 0x02)) { +-+ memcpy(buf, remote_ndis_initialize_msg, 24); +-+ DEBUG(ep->dev, "WORKAROUND HW BUG: ep0-out OUT\n"); +-+ } +-+ } +-+#endif +-+ /* XXX */ +-+ +-+ spin_unlock(&dev->lock); +-+ req->req.complete(&ep->ep, &req->req); +-+ spin_lock(&dev->lock); +-+ ep->stopped = stopped; +-+ +-+ VDEBUG(ep->dev, "<--- done() \n"); +-+} +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+/* queues (submits) an I/O requests to an endpoint */ +-+static int +-+iusbc_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +-+{ +-+ struct iusbc_request *req; +-+ struct iusbc_ep *ep; +-+ struct iusbc *dev; +-+ unsigned long flags; +-+ u16 val_16; +-+ unsigned zlflag = 0; +-+ +-+ /* always require a cpu-view buffer */ +-+ req = container_of(_req, struct iusbc_request, req); +-+ ep = container_of(_ep, struct iusbc_ep, ep); +-+ dev = ep->dev; +-+ VDEBUG(ep->dev, "---> iusbc_queue() \n"); +-+ +-+ if (dev->ep0state == EP0_DISCONNECT || ep->stopped) +-+ return -EINVAL; +-+ +-+ if (!_req || !_req->complete || !_req->buf +-+ || !list_empty(&req->queue)){ +-+ VDEBUG(ep->dev, "_req=%p, complete=%p, buf=%p, list_empty=%d\n", +-+ _req, _req->complete, +-+ _req->buf, +-+ list_empty(&req->queue)); +-+ return -EINVAL; +-+ } +-+ +-+ if (!_ep || (!ep->desc && ep->num > 1)){ +-+ VDEBUG(ep->dev, "ep->desc=%p, ep->num=%d\n", +-+ ep->desc, ep->num); +-+ return -ESHUTDOWN; +-+ } +-+ +-+ if (dev->ep0state == EP0_DISCONNECT) +-+ return -ESHUTDOWN; +-+ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) +-+ return -ESHUTDOWN; +-+ +-+ /* can't touch registers when suspended */ +-+ if (dev->ep0state == EP0_SUSPEND) +-+ return -EBUSY; +-+ +-+ /* set up dma mapping in case the caller didn't */ +-+ if (_req->dma == DMA_ADDR_INVALID) { +-+ /* WORKAROUND: WARN_ON(size == 0) */ +-+ if (_req->length == 0) { +-+ VDEBUG(dev, "req->length: 0->1\n"); +-+ zlflag = 1; +-+ _req->length++; +-+ } +-+ +-+ _req->dma = pci_map_single(dev->pdev, _req->buf, _req->length, +-+ ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); +-+ +-+ if (zlflag && (_req->length == 1)) { +-+ VDEBUG(dev, "req->length: 1->0\n"); +-+ zlflag = 0; +-+ _req->length = 0; +-+ } +-+ +-+ req->mapped = 1; +-+ } +-+ +-+ DEBUG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08x\n", +-+ _ep->name, _req, _req->length, +-+ _req->buf, _req->dma); +-+ +-+ spin_lock_irqsave(&dev->lock, flags); +-+ +-+ _req->status = -EINPROGRESS; +-+ _req->actual = 0; +-+ +-+ /* set ZLP flag for ep0-in, when writting data, +-+ * makes the last packet be "short" by adding a zero +-+ * length packet as needed +-+ */ +-+ if (unlikely(ep->num == 0 && ep->is_in)) +-+ _req->zero = 1; +-+ +-+ /* kickstart this I/O queue */ +-+ if (list_empty(&ep->queue) && !ep->stopped) { +-+ start_dma(ep, req); +-+ +-+ val_16 = readw(&ep->dev->regs->ep[ep->num].ep_pib); +-+ VDEBUG(ep->dev, "after dma, %s.ep_pib = 0x%04x\n", +-+ _ep->name, val_16); +-+ +-+ val_16 = readw(&ep->dev->regs->ep[ep->num].ep_sts); +-+ VDEBUG(ep->dev, "after dma, %s.ep_sts = 0x%04x\n", +-+ _ep->name, val_16); +-+ } else { +-+ queue_dma(ep, req); +-+ VDEBUG(ep->dev, "%s queue_dma()\n", _ep->name); +-+ } +-+ +-+ if (likely(req != 0)) { +-+ list_add_tail(&req->queue, &ep->queue); +-+ VDEBUG(ep->dev, "list_add_tail() \n"); +-+ } +-+ +-+ spin_unlock_irqrestore(&dev->lock, flags); +-+ +-+ VDEBUG(ep->dev, "<--- iusbc_queue() \n"); +-+ +-+ return 0; +-+} +-+ +-+ +-+static inline void +-+dma_done(struct iusbc_ep *ep, struct iusbc_request *req, int status) +-+{ +-+ unsigned i; +-+ VDEBUG(ep->dev, "---> dma_done() \n"); +-+ +-+ i = ep->num; +-+ req->req.actual = readw(&ep->dev->regs->ep[i].ep_pib); +-+ VDEBUG(ep->dev, "req->req.actual = %d\n", req->req.actual); +-+ +-+ done(ep, req, status); +-+ +-+ VDEBUG(ep->dev, "<--- dma_done() \n"); +-+} +-+ +-+ +-+/* restart dma in endpoint */ +-+static void restart_dma(struct iusbc_ep *ep) +-+{ +-+ struct iusbc_request *req; +-+ +-+ VDEBUG(ep->dev, "---> restart_dma() \n"); +-+ +-+ if (ep->stopped) +-+ return; +-+ +-+ req = list_entry(ep->queue.next, struct iusbc_request, queue); +-+ start_dma(ep, req); +-+ +-+ VDEBUG(ep->dev, "<--- restart_dma() \n"); +-+ +-+ return; +-+} +-+ +-+ +-+/* dequeue ALL requests */ +-+static void nuke(struct iusbc_ep *ep) +-+{ +-+ struct iusbc_request *req; +-+ +-+ VDEBUG(ep->dev, "---> nuke() \n"); +-+ +-+ /* called with spinlock held */ +-+ ep->stopped = 1; +-+ while (!list_empty(&ep->queue)) { +-+ req = list_entry(ep->queue.next, +-+ struct iusbc_request, +-+ queue); +-+ done(ep, req, -ESHUTDOWN); +-+ } +-+ +-+ VDEBUG(ep->dev, "<--- nuke() \n"); +-+} +-+ +-+ +-+/* dequeues (cancels, unlinks) an I/O request from an endpoint */ +-+static int +-+iusbc_dequeue(struct usb_ep *_ep, struct usb_request *_req) +-+{ +-+ struct iusbc_ep *ep; +-+ struct iusbc *dev; +-+ struct iusbc_request *req; +-+ unsigned long flags; +-+ int stopped; +-+ +-+ ep = container_of(_ep, struct iusbc_ep, ep); +-+ +-+ VDEBUG(ep->dev, "---> iusbc_dequeue() \n"); +-+ +-+ if (!_ep || (!ep->desc && ep->num > 1) || !_req) +-+ return -EINVAL; +-+ +-+ dev = ep->dev; +-+ +-+ if (!dev->driver) +-+ return -ESHUTDOWN; +-+ +-+ /* can't touch registers when suspended */ +-+ if (dev->ep0state == EP0_SUSPEND) +-+ return -EBUSY; +-+ +-+ spin_lock_irqsave(&ep->dev->lock, flags); +-+ stopped = ep->stopped; +-+ +-+ /* quiesce dma while we patch the queue */ +-+ ep->stopped = 1; +-+ +-+ /* make sure it's still queued on this endpoint */ +-+ list_for_each_entry(req, &ep->queue, queue) { +-+ if (&req->req == _req) +-+ break; +-+ } +-+ +-+ if (&req->req != _req) { +-+ spin_unlock_irqrestore(&ep->dev->lock, flags); +-+ return -EINVAL; +-+ } +-+ +-+ /* queue head may be partially complete. */ +-+ if (ep->queue.next == &req->queue) { +-+ DEBUG(ep->dev, "unlink (%s) dma\n", _ep->name); +-+ _req->status = -ECONNRESET; +-+ if (likely(ep->queue.next == &req->queue)) { +-+ req->td->dmacount = 0; /* invalidate */ +-+ dma_done(ep, req, -ECONNRESET); +-+ } +-+ req = NULL; +-+ } +-+ +-+ if (req) +-+ done(ep, req, -ECONNRESET); +-+ +-+ ep->stopped = stopped; +-+ +-+ if (!list_empty(&ep->queue) && (!ep->stopped)) { +-+ /* resume current request, or start new one */ +-+ if (!req) +-+ start_dma(ep, list_entry(ep->queue.next, +-+ struct iusbc_request, queue)); +-+ } +-+ +-+ spin_unlock_irqrestore(&ep->dev->lock, flags); +-+ +-+ VDEBUG(ep->dev, "<--- iusbc_dequeue() \n"); +-+ +-+ return 0; +-+} +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+static void ep0_start(struct iusbc *dev); +-+static void ep_ack(struct iusbc_ep *ep); +-+static int iusbc_ep_enable(struct usb_ep *_ep, +-+ const struct usb_endpoint_descriptor *desc); +-+ +-+static void clear_halt(struct iusbc_ep *ep) +-+{ +-+ u16 val_16; +-+ unsigned i = ep->num; +-+ int rc = 0; +-+ struct iusbc_request *req; +-+ const struct usb_endpoint_descriptor *desc; +-+ +-+ DEBUG(ep->dev, "---> clear_halt() \n"); +-+ +-+ /* validate and enable endpoint */ +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); +-+ val_16 |= EP_VALID | EP_ENABLE; +-+ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); +-+ +-+ /* re-enable endpoint */ +-+ if (i < 2) { /* ep0-in and ep0-out */ +-+ ep0_start(ep->dev); +-+ } else { +-+ spin_unlock_irq(&ep->dev->lock); +-+ /* remember ep->desc */ +-+ desc = ep->desc; +-+ rc = iusbc_ep_enable(&ep->ep, desc); +-+ if (rc) { +-+ DEBUG(ep->dev, "re-enable error: %d\n", rc); +-+ } +-+ spin_lock_irq(&ep->dev->lock); +-+ } +-+ +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); +-+ DEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); +-+ +-+ ep->stopped = 0; +-+ if (list_empty(&ep->queue)) +-+ return; +-+ +-+ req = list_entry(ep->queue.next, struct iusbc_request,queue); +-+ start_dma(ep, req); +-+ +-+ DEBUG(ep->dev, "<--- clear_halt() \n"); +-+} +-+ +-+ +-+static void set_halt(struct iusbc_ep *ep) +-+{ +-+ u16 val_16; +-+ unsigned i = ep->num; +-+ +-+ DEBUG(ep->dev, "---> set_halt() \n"); +-+ +-+ /* reset data buffer zero length */ +-+ writew(0, &ep->dev->regs->ep[i].ep_len); +-+ +-+ /* invalidate and disable endpoint */ +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); +-+ val_16 &= (~EP_VALID & ~EP_ENABLE); +-+ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); +-+ +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); +-+ DEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); +-+ +-+ ep->stopped = 1; +-+ +-+ DEBUG(ep->dev, "<--- set_halt() \n"); +-+} +-+ +-+ +-+static int iusbc_fifo_status(struct usb_ep *_ep); +-+ +-+/* sets the endpoint halt feature */ +-+static int +-+iusbc_set_halt(struct usb_ep *_ep, int value) +-+{ +-+ struct iusbc_ep *ep; +-+ unsigned long flags; +-+ int retval = 0; +-+ +-+ ep = container_of(_ep, struct iusbc_ep, ep); +-+ +-+ DEBUG(ep->dev, "---> iusbc_set_halt() \n"); +-+ +-+ if (!_ep || (!ep->desc && ep->num > 1)) +-+ return -EINVAL; +-+ +-+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) +-+ return -ESHUTDOWN; +-+ +-+ if (ep->desc && (ep->desc->bmAttributes & 0x03) +-+ == USB_ENDPOINT_XFER_ISOC) +-+ return -EINVAL; +-+ +-+ spin_lock_irqsave(&ep->dev->lock, flags); +-+ +-+ /* transfer requests are still queued */ +-+ if (!list_empty(&ep->queue)) +-+ retval = -EAGAIN; +-+ +-+ else if (ep->is_in && value && iusbc_fifo_status(_ep) != 0) { +-+ /* FIFO holds bytes, the host hasn't collected */ +-+ DEBUG(ep->dev, "%s FIFO holds bytes\n", _ep->name); +-+ +-+ /* reset position in buffer register */ +-+ writew(0, &ep->dev->regs->ep[ep->num].ep_pib); +-+ +-+ retval = -EAGAIN; +-+ } else { +-+ DEBUG(ep->dev, "%s %s halt\n", _ep->name, +-+ value ? "set" : "clear"); +-+ /* set/clear, then synch memory views with the device */ +-+ if (value) { +-+ if (ep->num < 2) { /* ep0-in/out */ +-+ ep->dev->ep0state = EP0_STALL; +-+ VDEBUG(ep->dev, "ep0state: EP0_STALL\n"); +-+ } else { +-+ set_halt(ep); +-+ ep_ack(&ep->dev->ep[0]); +-+ } +-+ } else { +-+ clear_halt(ep); +-+ ep_ack(&ep->dev->ep[0]); +-+ } +-+ +-+ } +-+ spin_unlock_irqrestore(&ep->dev->lock, flags); +-+ +-+ DEBUG(ep->dev, "<--- iusbc_set_halt() \n"); +-+ +-+ return retval; +-+} +-+ +-+ +-+/* return number of bytes in fifo, or error */ +-+static int +-+iusbc_fifo_status(struct usb_ep *_ep) +-+{ +-+ struct iusbc_ep *ep; +-+ unsigned i; +-+ u16 nbytes, fifo_size; +-+ +-+ ep = container_of(_ep, struct iusbc_ep, ep); +-+ +-+ DEBUG(ep->dev, "---> iusbc_fifo_status() \n"); +-+ +-+ if (!_ep || (!ep->desc && ep->num > 1)) +-+ return -ENODEV; +-+ +-+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) +-+ return -ESHUTDOWN; +-+ +-+ i = ep->num; +-+ fifo_size = readw(&ep->dev->regs->ep[i].ep_len); +-+ nbytes = readw(&ep->dev->regs->ep[i].ep_pib); +-+ +-+ if (nbytes > fifo_size) +-+ return -EOVERFLOW; +-+ +-+ DEBUG(ep->dev, "%s, 0x%04x bytes (%s) in FIFO\n", +-+ _ep->name, nbytes, ep->is_in? "IN" : "OUT"); +-+ +-+ DEBUG(ep->dev, "<--- iusbc_fifo_status() \n"); +-+ +-+ return nbytes; +-+} +-+ +-+ +-+static void ep_nak(struct iusbc_ep *ep); +-+ +-+/* flushes contents of a fifo */ +-+static void +-+iusbc_fifo_flush(struct usb_ep *_ep) +-+{ +-+ struct iusbc_ep *ep; +-+ unsigned i; +-+ u16 val_16; +-+ +-+ ep = container_of(_ep, struct iusbc_ep, ep); +-+ +-+ DEBUG(ep->dev, "---> iusbc_fifo_flush() \n"); +-+ +-+ if (!_ep || (!ep->desc && ep->num > 1)){ +-+ return; +-+ } +-+ +-+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) +-+ return; +-+ +-+ i = ep->num; +-+ +-+ /* FIXME: remove it ? */ +-+ ep_nak(ep); +-+ +-+ /* reset position in buffer register */ +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_pib); +-+ DEBUG(ep->dev, "%s.ep_pib = 0x%04x\n", _ep->name, val_16); +-+ writew(0, &ep->dev->regs->ep[i].ep_pib); +-+ +-+ DEBUG(ep->dev, "<--- iusbc_fifo_flush() \n"); +-+} +-+ +-+static const struct usb_ep_ops iusbc_ep_ops = { +-+ +-+ /* configure endpoint, making it usable */ +-+ .enable = iusbc_ep_enable, +-+ +-+ /* endpoint is no longer usable */ +-+ .disable = iusbc_ep_disable, +-+ +-+ /* allocate a request object to use with this endpoint */ +-+ .alloc_request = iusbc_alloc_request, +-+ +-+ /* frees a request object */ +-+ .free_request = iusbc_free_request, +-+ +-+ /* allocate an I/O buffer */ +-+ /*.alloc_buffer = iusbc_alloc_buffer,*/ +-+ +-+ /* free an I/O buffer */ +-+ /*.free_buffer = iusbc_free_buffer,*/ +-+ +-+ /* queues (submits) an I/O requests to an endpoint */ +-+ .queue = iusbc_queue, +-+ +-+ /* dequeues (cancels, unlinks) an I/O request from an endpoint */ +-+ .dequeue = iusbc_dequeue, +-+ +-+ /* sets the endpoint halt feature */ +-+ .set_halt = iusbc_set_halt, +-+ +-+ /* return number of bytes in fifo, or error */ +-+ .fifo_status = iusbc_fifo_status, +-+ +-+ /* flushes contents of a fifo */ +-+ .fifo_flush = iusbc_fifo_flush, +-+}; +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+/* returns the current frame number */ +-+static int iusbc_get_frame(struct usb_gadget *_gadget) +-+{ +-+ struct iusbc *dev; +-+ unsigned long flags; +-+ u16 retval; +-+ +-+ if (!_gadget) +-+ return -ENODEV; +-+ +-+ dev = container_of(_gadget, struct iusbc, gadget); +-+ +-+ VDEBUG(dev, "---> iusbc_get_frame() \n"); +-+ +-+ spin_lock_irqsave(&dev->lock, flags); +-+ retval = readw(&dev->regs->frame); +-+ spin_unlock_irqrestore(&dev->lock, flags); +-+ +-+ VDEBUG(dev, "<--- iusbc_get_frame() \n"); +-+ +-+ return retval; +-+} +-+ +-+ +-+/* TODO: wakeup host function */ +-+/* tries to wake up the host connected to this gadget */ +-+static int iusbc_wakeup(struct usb_gadget *_gadget) +-+{ +-+ struct iusbc *dev; +-+ +-+ if (!_gadget) +-+ return 0; +-+ +-+ dev = container_of(_gadget, struct iusbc, gadget); +-+ +-+ VDEBUG(dev, "---> iusbc_wakeup() \n"); +-+ +-+ /* TODO: spec 4.3 */ +-+ +-+ VDEBUG(dev, "<--- iusbc_wakeup() \n"); +-+ +-+ return 0; +-+} +-+ +-+ +-+/* software-controlled connect/disconnect to USB host */ +-+static int iusbc_pullup(struct usb_gadget *_gadget, int is_on) +-+{ +-+ struct iusbc *dev; +-+ u32 val_32; +-+ unsigned long flags; +-+ +-+ if (!_gadget) +-+ return -ENODEV; +-+ dev = container_of(_gadget, struct iusbc, gadget); +-+ +-+ VDEBUG(dev, "---> iusbc_pullup() \n"); +-+ +-+ spin_lock_irqsave(&dev->lock, flags); +-+ val_32 = readl(&dev->regs->dev_ctrl); +-+ dev->connected = (is_on != 0); +-+ if (is_on) +-+ val_32 |= CONNECTION_ENABLE; +-+ else +-+ val_32 &= ~CONNECTION_ENABLE; +-+ +-+ writel(val_32, &dev->regs->dev_ctrl); +-+ spin_unlock_irqrestore(&dev->lock, flags); +-+ +-+ VDEBUG(dev, "<--- iusbc_pullup() \n"); +-+ +-+ return 0; +-+} +-+ +-+ +-+static const struct usb_gadget_ops iusbc_ops = { +-+ +-+ /* returns the current frame number */ +-+ .get_frame = iusbc_get_frame, +-+ +-+ /* TODO */ +-+ /* tries to wake up the host connected to this gadget */ +-+ .wakeup = iusbc_wakeup, +-+ +-+ /* software-controlled connect/disconnect to USB host */ +-+ .pullup = iusbc_pullup, +-+}; +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+#ifdef CONFIG_USB_GADGET_DEBUG_FILES +-+ +-+/* "function" sysfs attribute */ +-+static ssize_t +-+show_function(struct device *_dev, struct device_attribute *attr, char *buf) +-+{ +-+ struct iusbc *dev = dev_get_drvdata(_dev); +-+ +-+ if (!dev->driver +-+ || !dev->driver->function +-+ || strlen(dev->driver->function) > PAGE_SIZE) +-+ return 0; +-+ +-+ return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function); +-+} +-+static DEVICE_ATTR(function, S_IRUGO, show_function, NULL); +-+ +-+ +-+static ssize_t +-+show_registers(struct device *_dev, struct device_attribute *attr, char *buf) +-+{ +-+ struct iusbc *dev; +-+ char *next; +-+ unsigned size; +-+ unsigned t; +-+ unsigned i; +-+ unsigned long flags; +-+ const char *name; +-+ const char *speed; +-+ volatile u32 dev_sts; +-+ +-+ dev = dev_get_drvdata(_dev); +-+ next = buf; +-+ size = PAGE_SIZE; +-+ spin_lock_irqsave(&dev->lock, flags); +-+ +-+ if (dev->driver) +-+ name = dev->driver->driver.name; +-+ else +-+ name = "(none)"; +-+ +-+ dev_sts = readl(&dev->regs->dev_sts); +-+ if ((dev->gadget.speed == USB_SPEED_HIGH) && (dev_sts & CONNECTED)) +-+ speed = "high speed"; +-+ else if ((dev->gadget.speed == USB_SPEED_FULL) && (dev_sts & CONNECTED)) +-+ speed = "full speed"; +-+ else +-+ speed = "unknown speed"; +-+ +-+ /* device information */ +-+ t = scnprintf(next, size, +-+ "%s %s - %s\n" +-+ "Version: %s\n" +-+ "Gadget driver: %s\n" +-+ "Speed mode: %s\n", +-+ driver_name, pci_name(dev->pdev), driver_desc, +-+ DRIVER_VERSION, +-+ name, +-+ speed); +-+ size -= t; +-+ next += t; +-+ +-+ /* device memory space registers */ +-+ t = scnprintf(next, size, +-+ "\nDevice registers:\n" +-+ "\tgcap=0x%08x\n" +-+ "\tdev_sts=0x%08x\n" +-+ "\tframe=0x%04x\n" +-+ "\tint_sts=0x%08x\n" +-+ "\tint_ctrl=0x%08x\n" +-+ "\tdev_ctrl=0x%08x\n", +-+ readl(&dev->regs->gcap), +-+ readl(&dev->regs->dev_sts), +-+ readw(&dev->regs->frame), +-+ readl(&dev->regs->int_sts), +-+ readl(&dev->regs->int_ctrl), +-+ readl(&dev->regs->dev_ctrl) +-+ ); +-+ size -= t; +-+ next += t; +-+ +-+ /* endpoints memory space registers */ +-+ t = scnprintf(next, size, "\nEndpoints registers:\n"); +-+ size -= t; +-+ next += t; +-+ +-+ for (i = 0; i < 5; i++) { +-+ struct iusbc_ep *ep; +-+ ep = &dev->ep[i]; +-+ +-+ if (i > 1 && !ep->desc) +-+ continue; +-+ +-+ name = ep->ep.name; +-+ t = scnprintf(next, size, +-+ "\t%s.ep_base_low_32=0x%08x\n" +-+ "\t%s.ep_base_hi_32=0x%08x\n" +-+ "\t%s.ep_len=0x%04x\n" +-+ "\t%s.ep_pib=0x%04x\n" +-+ "\t%s.ep_dil=0x%04x\n" +-+ "\t%s.ep_tiq=0x%04x\n" +-+ "\t%s.ep_max=0x%04x\n" +-+ "\t%s.ep_sts=0x%04x\n" +-+ "\t%s.ep_cfg=0x%04x\n", +-+ name, readl(&dev->regs->ep[i].ep_base_low_32), +-+ name, readl(&dev->regs->ep[i].ep_base_hi_32), +-+ name, readw(&dev->regs->ep[i].ep_len), +-+ name, readw(&dev->regs->ep[i].ep_pib), +-+ name, readw(&dev->regs->ep[i].ep_dil), +-+ name, readw(&dev->regs->ep[i].ep_tiq), +-+ name, readw(&dev->regs->ep[i].ep_max), +-+ name, readw(&dev->regs->ep[i].ep_sts), +-+ name, readw(&dev->regs->ep[i].ep_cfg) +-+ ); +-+ size -= t; +-+ next += t; +-+ } +-+ +-+ /* ep0-out setup packet registers */ +-+ t = scnprintf(next, size, +-+ "\tsetup_pkt_sts=0x%02x\n", +-+ readb(&dev->regs->ep[1].setup_pkt_sts) +-+ ); +-+ size -= t; +-+ next += t; +-+ +-+ for (i = 0; i < 8; i++) { +-+ t = scnprintf(next, size, +-+ "\tsetup_pkt[%d]=0x%02x\n", +-+ i, +-+ readb(&dev->regs->ep[1].setup_pkt[i]) +-+ ); +-+ size -= t; +-+ next += t; +-+ } +-+ +-+ /* Irq statistics */ +-+ t = scnprintf(next, size, "\nIrq statistics:\n"); +-+ size -= t; +-+ next += t; +-+ +-+ for (i = 0; i < 5; i++) { +-+ struct iusbc_ep *ep; +-+ ep = &dev->ep[i]; +-+ +-+ if (i && !ep->irqs) +-+ continue; +-+ +-+ t = scnprintf(next, size, +-+ "\t%s/%lu\n", +-+ ep->ep.name, ep->irqs); +-+ size -= t; +-+ next += t; +-+ } +-+ +-+ spin_unlock_irqrestore(&dev->lock, flags); +-+ +-+ return PAGE_SIZE - size; +-+} +-+static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); +-+ +-+ +-+static ssize_t +-+show_queues(struct device *_dev, struct device_attribute *attr, char *buf) +-+{ +-+ struct iusbc *dev; +-+ char *next; +-+ unsigned size, i; +-+ unsigned long flags; +-+ +-+ dev = dev_get_drvdata(_dev); +-+ next = buf; +-+ size = PAGE_SIZE; +-+ spin_lock_irqsave(&dev->lock, flags); +-+ +-+ for (i = 0; i < 5; i++) { +-+ struct iusbc_ep *ep = &dev->ep[i]; +-+ struct iusbc_request *req; +-+ struct iusbc_dma *td; +-+ int t; +-+ int addr; +-+ +-+ if (i > 1 && !ep->desc) +-+ continue; +-+ +-+ /* ep0-in, ep0-out */ +-+ if (i == 0 || i == 1) { +-+ t = scnprintf(next, size, +-+ "%s (ep%d%s-%s), " +-+ "max %04x, dma_mode: %02x\n", +-+ ep->ep.name, +-+ 0, +-+ ep->is_in ? "in" : "out", +-+ "control", +-+ ep->ep.maxpacket, +-+ ep->dma_mode); +-+ } else { +-+ addr = ep->desc->bEndpointAddress; +-+ t = scnprintf(next, size, +-+ "\n%s (ep%d%s-%s), " +-+ "max %04x, dma_mode: %02x\n", +-+ ep->ep.name, +-+ addr & USB_ENDPOINT_NUMBER_MASK, +-+ DIR_STRING(addr), +-+ type_string(ep->desc->bmAttributes), +-+ ep->ep.maxpacket, +-+ ep->dma_mode); +-+ } +-+ +-+ if (t <= 0 || t > size) +-+ goto done; +-+ +-+ size -= t; +-+ next += t; +-+ +-+ if (list_empty(&ep->queue)) { +-+ t = scnprintf(next, size, "\t(nothing queued)\n"); +-+ if (t <= 0 || t > size) +-+ goto done; +-+ +-+ size -= t; +-+ next += t; +-+ continue; +-+ } +-+ +-+ list_for_each_entry(req, &ep->queue, queue) { +-+ t = scnprintf(next, size, +-+ "\treq %p, len %u/%u, " +-+ "buf %p, dma 0x%08x)\n", +-+ &req->req, req->req.actual, +-+ req->req.length, req->req.buf, +-+ req->req.dma); +-+ +-+ if (t <= 0 || t > size) +-+ goto done; +-+ +-+ size -= t; +-+ next += t; +-+ +-+ td = req->td; +-+ t = scnprintf(next, size, "\ttd 0x%08x, " +-+ " count 0x%08x, buf 0x%08x\n", +-+ (u32) req->td_dma, +-+ le32_to_cpu(td->dmacount), +-+ le32_to_cpu(td->dmaaddr)); +-+ +-+ if (t <= 0 || t > size) +-+ goto done; +-+ +-+ size -= t; +-+ next += t; +-+ } +-+ } +-+ +-+done: +-+ spin_unlock_irqrestore(&dev->lock, flags); +-+ return PAGE_SIZE - size; +-+} +-+static DEVICE_ATTR(queues, S_IRUGO, show_queues, NULL); +-+ +-+#else +-+ +-+#define device_create_file(a,b) (0) +-+#define device_remove_file(a,b) do { } while (0) +-+ +-+#endif /*CONFIG_USB_GADGET_DEBUG_FILES */ +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+/* global variable */ +-+static struct iusbc *the_controller; +-+ +-+static void iusbc_reset(struct iusbc *dev) +-+{ +-+ DEBUG(dev, "---> iusbc_reset() \n"); +-+ +-+ /* disable irqs */ +-+ writel(0, &dev->regs->int_ctrl); +-+ +-+ /* set device power stauts */ +-+ dev->powered = 1; +-+ +-+ /* set device remote wakeup flag */ +-+ dev->enable_wakeup = 0; +-+ +-+ /* 16 bits status data for GET_STATUS */ +-+ dev->status_d = 0; +-+ +-+ DEBUG(dev, "<--- iusbc_reset() \n"); +-+} +-+ +-+ +-+static void iusbc_reinit(struct iusbc *dev) +-+{ +-+ unsigned i; +-+ +-+ DEBUG(dev, "---> iusbc_reinit() \n"); +-+ +-+ INIT_LIST_HEAD(&dev->gadget.ep_list); +-+ +-+ /* ep0-in */ +-+ dev->gadget.ep0 = &dev->ep[0].ep; +-+ +-+ /* init ep0-in and ep0-out driver_data */ +-+ dev->ep[0].ep.driver_data = get_gadget_data(&dev->gadget); +-+ dev->ep[1].ep.driver_data = get_gadget_data(&dev->gadget); +-+ +-+ dev->ep0state = EP0_DISCONNECT; +-+ VDEBUG(dev, "ep0state: EP0_DISCONNECT\n"); +-+ +-+ /* basic endpoint init */ +-+ /* 2 ep0, 3 data ep */ +-+ for (i = 0; i < 5; i++) { +-+ struct iusbc_ep *ep = &dev->ep[i]; +-+ ep->dev = dev; +-+ +-+ INIT_LIST_HEAD(&ep->queue); +-+ +-+ ep->desc = NULL; +-+ ep->num = i; +-+ ep->stopped = 1; +-+ ep->ep.name = ep_name[i]; +-+ ep->ep.maxpacket = ~0; +-+ ep->ep.ops = &iusbc_ep_ops; +-+ +-+ list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); +-+ ep_reset(dev->regs, ep); +-+ } +-+ +-+ /* set ep0 maxpacket */ +-+ dev->ep[0].ep.maxpacket = 64; /* ep0_in */ +-+ dev->ep[1].ep.maxpacket = 64; /* ep0_out */ +-+ +-+ dev->ep[0].stopped = 0; +-+ dev->ep[1].stopped = 0; +-+ +-+ list_del_init(&dev->ep[0].ep.ep_list); +-+ list_del_init(&dev->ep[1].ep.ep_list); +-+ +-+ DEBUG(dev, "<--- iusbc_reinit() \n"); +-+} +-+ +-+ +-+static void ep0_start(struct iusbc *dev) +-+{ +-+ u16 val_16; +-+ u32 val_32; +-+ unsigned i; +-+ +-+ DEBUG(dev, "---> ep0_start() \n"); +-+ +-+ iusbc_reset(dev); +-+ iusbc_reinit(dev); +-+ +-+ for (i = 0; i < 2; i++) { +-+ struct iusbc_ep *ep = &dev->ep[i]; +-+ +-+ /* ep[0]: ep0-in, ep[1]: ep0-out */ +-+ ep->is_in = (i == 0 ? 1 : 0); +-+ +-+ /* ep0 ep_type */ +-+ ep->ep_type = USB_ENDPOINT_XFER_CONTROL; +-+ +-+ /* linear mode only, control mode is useless */ +-+ ep->dma_mode = LINEAR_MODE; +-+ +-+ /* reset ep0-in/out registers to default value */ +-+ writew(0, &dev->regs->ep[i].ep_cfg); +-+ +-+ /* set ep0-in/out endpoints valid */ +-+ val_16 = readw(&dev->regs->ep[i].ep_cfg); +-+ val_16 |= INTR_BAD_PID_TYPE +-+ | INTR_CRC_ERROR +-+ | INTR_FIFO_ERROR +-+ | INTR_DMA_ERROR +-+ | INTR_TRANS_COMPLETE +-+ /* | INTR_PING_NAK_SENT */ +-+ | INTR_DMA_IOC +-+ | ep->dma_mode << 6 +-+ | ep->ep_type << 4 +-+ /* | EP_ENABLE */ +-+ | EP_VALID; +-+ +-+ writew(val_16, &dev->regs->ep[i].ep_cfg); +-+ +-+ val_16 = readw(&dev->regs->ep[i].ep_cfg); +-+ DEBUG(dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); +-+ +-+ DEBUG(dev, "enabled %s (ep0-%s), max %d, dma_mode: %02x\n", +-+ ep->ep.name, +-+ ep->is_in ? "in" : "out", +-+ ep->ep.maxpacket, ep->dma_mode); +-+ } +-+ +-+ /* enable irqs */ +-+ val_32 = readl(&dev->regs->int_ctrl); +-+ val_32 |= RESET_INTR_ENABLE +-+ | CONNECT_INTR_ENABLE +-+ | SUSPEND_INTR_ENABLE +-+ /* | EP3_OUT_INTR_ENABLE */ +-+ /* | EP3_IN_INTR_ENABLE */ +-+ /* | EP2_OUT_INTR_ENABLE */ +-+ | EP2_IN_INTR_ENABLE +-+ | EP1_OUT_INTR_ENABLE +-+ | EP1_IN_INTR_ENABLE +-+ | EP0_OUT_INTR_ENABLE +-+ | EP0_IN_INTR_ENABLE; +-+ +-+ writel(val_32, &dev->regs->int_ctrl); +-+ val_32 = readl(&dev->regs->int_ctrl); +-+ DEBUG(dev, "ep0_start: enable irqs, int_ctrl = 0x%08x\n", +-+ val_32); +-+ +-+ dev->ep0state = EP0_IDLE; +-+ VDEBUG(dev, "ep0state: EP0_IDLE\n"); +-+ +-+ DEBUG(dev, "<--- ep0_start() \n"); +-+} +-+ +-+ +-+static void iusbc_do_tasklet(unsigned long arg); +-+ +-+static void device_start(struct iusbc *dev) +-+{ +-+ u32 val_32; +-+ +-+ DEBUG(dev, "---> device_start() \n"); +-+ +-+ /* reset all registers */ +-+ writel(0, &dev->regs->dev_ctrl); +-+ +-+ /* PCI enable: write 1 to DeviceEnable */ +-+ writel(DEVICE_ENABLE, &dev->regs->dev_ctrl); +-+ /* FIXME: 5 ms is not enough? */ +-+ mdelay(5); +-+ val_32 = readl(&dev->regs->dev_ctrl); +-+ if (!(val_32 & DEVICE_ENABLE)) +-+ ERROR(dev, "hardware reset error\n"); +-+ +-+ /* hardware transfer to running state now */ +-+ val_32 |= DEVICE_ENABLE +-+ /* | CONNECTION_ENABLE */ +-+ | SIGNAL_RESUME +-+ | CHARGE_ENABLE; +-+ +-+ /* module parameter: force_fullspeed */ +-+ if (force_fullspeed) { +-+ val_32 |= FORCE_FULLSPEED; +-+ dev->force_fullspeed = 1; +-+ } else { +-+ /* disable DMAs in high speed mode */ +-+#ifdef DMA_DISABLED +-+ val_32 |= DMA1_DISABLED +-+ | DMA2_DISABLED +-+ | DMA3_DISABLED; +-+#endif +-+ dev->force_fullspeed = 0; +-+ } +-+ +-+ writel(val_32, &dev->regs->dev_ctrl); +-+ val_32 = readl(&dev->regs->dev_ctrl); +-+ DEBUG(dev, "dev_ctrl = 0x%08x\n", val_32); +-+ +-+ /* check device status */ +-+ val_32 = readl(&dev->regs->dev_sts); +-+ DEBUG(dev, "device_start: dev_sts = 0x%08x\n", val_32); +-+ +-+ if (val_32 & CONNECTED) { +-+ dev->connected = 1; +-+ VDEBUG(dev, "device_start: USB attached\n"); +-+ } else { +-+ dev->connected = 0; +-+ VDEBUG(dev, "device_start: USB detached\n"); +-+ } +-+ +-+ if (val_32 & SUSPEND) +-+ dev->suspended = 1; +-+ else +-+ dev->suspended = 0; +-+ +-+ /* set device reset flag */ +-+ dev->is_reset = 0; +-+ +-+ iusbc_pullup(&dev->gadget, 1); +-+ +-+ /* init irq tasklet */ +-+ tasklet_init(&dev->iusbc_tasklet, +-+ iusbc_do_tasklet, (unsigned long) dev); +-+ +-+ /* enable ep0 and host detection */ +-+ ep0_start(dev); +-+ +-+ DEBUG(dev, "<--- device_start() \n"); +-+} +-+ +-+ +-+/* when a driver is successfully registered, it will receive +-+ * control requests including set_configuration(), which enables +-+ * non-control requests. then usb traffic follows until a +-+ * disconnect is reported. then a host may connect again, or +-+ * the driver might get unbound. +-+ */ +-+int usb_gadget_register_driver(struct usb_gadget_driver *driver) +-+{ +-+ struct iusbc *dev = the_controller; +-+ int retval; +-+ unsigned i; +-+ +-+ if (!driver || !driver->bind || !driver->disconnect || !driver->setup) +-+ return -EINVAL; +-+ +-+ if (!dev) +-+ return -ENODEV; +-+ +-+ DEBUG(dev, "---> usb_gadget_register_driver() \n"); +-+ +-+ if (dev->driver) +-+ return -EBUSY; +-+ +-+ dev->irqs = 0; +-+ +-+ /* 2 ep0, 3 data eps */ +-+ for (i = 0; i < 5; i++) +-+ dev->ep[i].irqs = 0; +-+ +-+ /* hook up the driver ... */ +-+ driver->driver.bus = NULL; +-+ dev->driver = driver; +-+ dev->gadget.dev.driver = &driver->driver; +-+ +-+ retval = driver->bind(&dev->gadget); +-+ if (retval) { +-+ DEBUG(dev, "bind to driver %s --> %d\n", +-+ driver->driver.name, retval); +-+ dev->driver = NULL; +-+ dev->gadget.dev.driver = NULL; +-+ return retval; +-+ } +-+ +-+ retval = device_create_file(&dev->pdev->dev, &dev_attr_function); +-+ if (retval) +-+ goto err_unbind; +-+ +-+ retval = device_create_file(&dev->pdev->dev, &dev_attr_queues); +-+ if (retval) +-+ goto err_func; +-+ +-+ device_start(dev); +-+ +-+ INFO(dev, "register driver: %s\n", driver->driver.name); +-+ DEBUG(dev, "<--- usb_gadget_register_driver() \n"); +-+ +-+ return 0; +-+ +-+err_func: +-+ device_remove_file(&dev->pdev->dev, &dev_attr_function); +-+ +-+err_unbind: +-+ driver->unbind(&dev->gadget); +-+ dev->gadget.dev.driver = NULL; +-+ dev->driver = NULL; +-+ +-+ DEBUG(dev, "<--- usb_gadget_register_driver() \n"); +-+ +-+ return retval; +-+} +-+EXPORT_SYMBOL(usb_gadget_register_driver); +-+ +-+ +-+static void +-+stop_activity(struct iusbc *dev, struct usb_gadget_driver *driver) +-+{ +-+ unsigned i; +-+ +-+ DEBUG(dev, "---> stop_activity() \n"); +-+ +-+ /* don't disconnect if it's not connected */ +-+ if (dev->gadget.speed == USB_SPEED_UNKNOWN) +-+ driver = NULL; +-+ +-+ /* stop hardware; prevent new request submissions; +-+ * and kill any outstanding requests. +-+ */ +-+ iusbc_reset(dev); +-+ +-+ /* we need to mark ep0state to disconnect to avoid upper layer to start +-+ * next transfer immediately after the following nuke operation, the +-+ * iusbc_queue function need to check ep0state before issue a transfer +-+ */ +-+ dev->ep0state = EP0_DISCONNECT; +-+ +-+ /* 2 ep0, 3 data ep */ +-+ for (i = 0; i < 5; i++) +-+ nuke(&dev->ep[i]); +-+ +-+ /* report disconnect; the driver is already quiesced */ +-+ if (driver) { +-+ spin_unlock(&dev->lock); +-+ driver->disconnect(&dev->gadget); +-+ spin_lock(&dev->lock); +-+ } +-+ +-+ iusbc_reinit(dev); +-+ +-+ DEBUG(dev, "<--- stop_activity() \n"); +-+} +-+ +-+ +-+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +-+{ +-+ struct iusbc *dev = the_controller; +-+ unsigned long flags; +-+ +-+ DEBUG(dev, "---> usb_gadget_unregister_driver() \n"); +-+ +-+ if (!dev) +-+ return -ENODEV; +-+ if (!driver || driver != dev->driver || !driver->unbind) +-+ return -EINVAL; +-+ +-+ /* kill irq tasklet */ +-+ tasklet_kill(&dev->iusbc_tasklet); +-+ +-+ spin_lock_irqsave(&dev->lock, flags); +-+ stop_activity(dev, driver); +-+ spin_unlock_irqrestore(&dev->lock, flags); +-+ +-+ iusbc_pullup(&dev->gadget, 0); +-+ +-+ driver->unbind(&dev->gadget); +-+ dev->gadget.dev.driver = NULL; +-+ dev->driver = NULL; +-+ +-+ device_remove_file(&dev->pdev->dev, &dev_attr_function); +-+ device_remove_file(&dev->pdev->dev, &dev_attr_queues); +-+ +-+ INFO(dev, "unregistered driver '%s'\n", driver->driver.name); +-+ +-+ DEBUG(dev, "<--- usb_gadget_unregister_driver() \n"); +-+ +-+ return 0; +-+} +-+EXPORT_SYMBOL(usb_gadget_unregister_driver); +-+ +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+static struct iusbc_ep * +-+get_ep_by_addr(struct iusbc *dev, u16 wIndex) +-+{ +-+ struct iusbc_ep *ep; +-+ +-+ if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) +-+ return &dev->ep[0]; +-+ +-+ list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { +-+ u8 bEndpointAddress; +-+ if (!ep->desc) +-+ continue; +-+ +-+ bEndpointAddress = ep->desc->bEndpointAddress; +-+ if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) +-+ continue; +-+ +-+ if ((wIndex & USB_ENDPOINT_NUMBER_MASK) +-+ == (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) +-+ return ep; +-+ } +-+ return NULL; +-+} +-+ +-+ +-+/* NAK an endpoint */ +-+static void ep_nak(struct iusbc_ep *ep) +-+{ +-+ u16 val_16; +-+ unsigned i = ep->num; +-+ +-+ DEBUG(ep->dev, "---> ep_nak() \n"); +-+ +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); +-+ val_16 &= ~EP_ENABLE; +-+ val_16 |= EP_VALID; +-+ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); +-+ +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); +-+ VDEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); +-+ +-+ DEBUG(ep->dev, "<--- ep_nak() \n"); +-+} +-+ +-+ +-+/* ACK an out transfer with a zero length packet (ZLP) */ +-+static void ep_ack(struct iusbc_ep *ep) +-+{ +-+ u16 val_16; +-+ unsigned i = ep->num; +-+ +-+ DEBUG(ep->dev, "---> ep_ack() \n"); +-+ +-+ /* reset data buffer zero length */ +-+ writew(0, &ep->dev->regs->ep[i].ep_len); +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_len); +-+ VDEBUG(ep->dev, "%s.ep_len = 0x%04x\n", ep->ep.name, val_16); +-+ +-+ /* validate endpoint, enable DMA */ +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); +-+ val_16 |= (EP_VALID | EP_ENABLE); +-+ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); +-+ +-+ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); +-+ VDEBUG(ep->dev, "enable %s DMA transfer...\n", ep->ep.name); +-+ VDEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); +-+ +-+ DEBUG(ep->dev, "<--- ep_ack() \n"); +-+} +-+ +-+ +-+static void ep0_setup(struct iusbc *dev) +-+{ +-+ struct usb_ctrlrequest ctrl; +-+ struct iusbc_ep *epn; +-+ unsigned i, tmp = 0; +-+ u8 addr_new, setup_pkt[8]; +-+ +-+ VDEBUG(dev, "---> ep0_setup() \n"); +-+ +-+ for (i = 0; i < 8; i++) { +-+ setup_pkt[i] = readb(&dev->regs->ep[1].setup_pkt[i]); +-+ } +-+ +-+ /* read SETUP packet and enter DATA stage */ +-+ ctrl.bRequestType = setup_pkt[0]; +-+ ctrl.bRequest = setup_pkt[1]; +-+ ctrl.wValue = cpu_to_le16((setup_pkt[3] << 8) +-+ | setup_pkt[2]); +-+ ctrl.wIndex = cpu_to_le16((setup_pkt[5] << 8) +-+ | setup_pkt[4]); +-+ ctrl.wLength = cpu_to_le16((setup_pkt[7] << 8) +-+ | setup_pkt[6]); +-+ +-+ dev->ep[1].stopped = 0; +-+ +-+ /* data stage direction */ +-+ if (ctrl.bRequestType & USB_DIR_IN) { +-+ dev->ep0state = EP0_IN; +-+ VDEBUG(dev, "ep0state: EP0_IN\n"); +-+ } else { +-+ dev->ep0state = EP0_OUT; +-+ VDEBUG(dev, "ep0state: EP0_OUT\n"); +-+ } +-+ +-+ /* WORKAROUND: for RNDIS */ +-+ /* CDC: SEND_ENCAPSULATED_COMMAND */ +-+ if ((ctrl.bRequestType == 0x21) && (ctrl.bRequest == 0x00)) { +-+ goto delegate; +-+ } +-+ /* CDC: GET_ENCAPSULATED_COMMAND */ +-+ if ((ctrl.bRequestType == 0xa1) && (ctrl.bRequest == 0x01)) { +-+ goto delegate; +-+ } +-+ +-+ switch (ctrl.bRequest) { +-+ /* GET_STATUS is handled by software */ +-+ case USB_REQ_GET_STATUS: +-+ DEBUG(dev, "SETUP: USB_REQ_GET_STATUS\n"); +-+ switch (ctrl.bRequestType & +-+ __constant_cpu_to_le16(USB_RECIP_MASK)) { +-+ case USB_RECIP_DEVICE: +-+ /* bit 0: USB_DEVICE_SELF_POWERED +-+ * bit 1: USB_DEVICE_REMOTE_WAKEUP +-+ */ +-+ if (dev->enable_wakeup) { +-+ dev->status_d = +-+ __constant_cpu_to_le16(1 << 1 | 1); +-+ } else { +-+ dev->status_d = __constant_cpu_to_le16(1); +-+ } +-+ DEBUG(dev, "device status 0x%04x\n", dev->status_d); +-+ break; +-+ case USB_RECIP_INTERFACE: +-+ /* all bits zero */ +-+ dev->status_d = __constant_cpu_to_le16(0); +-+ DEBUG(dev, "interface status 0x%04x\n", dev->status_d); +-+ break; +-+ case USB_RECIP_ENDPOINT: +-+ if ((epn = get_ep_by_addr(dev, +-+ le16_to_cpu(ctrl.wIndex))) == 0) +-+ goto stall; +-+ if (epn->stopped) { /* halted */ +-+ dev->status_d = __constant_cpu_to_le16(1); +-+ } else { +-+ dev->status_d = __constant_cpu_to_le16(0); +-+ } +-+ DEBUG(dev, "%s endpoint status 0x%04x\n", +-+ epn->ep.name, dev->status_d); +-+ break; +-+ } +-+ /* GET_STATUS is partially handled in gadget driver */ +-+ goto delegate; +-+ +-+ case USB_REQ_CLEAR_FEATURE: +-+ DEBUG(dev, "SETUP: USB_REQ_CLEAR_FEATURE\n"); +-+ switch (ctrl.bRequestType) { +-+ case USB_RECIP_DEVICE: +-+ if (ctrl.wValue == __constant_cpu_to_le16( +-+ USB_DEVICE_REMOTE_WAKEUP)) { +-+ dev->enable_wakeup = 0; +-+ DEBUG(dev, "CLEAR_FEATURE: " +-+ "remote wakeup disabled\n"); +-+ goto end; +-+ } else { +-+ DEBUG(dev, "unsupported CLEAR_FEATURE\n"); +-+ goto stall; +-+ } +-+ break; +-+ case USB_RECIP_INTERFACE: +-+ DEBUG(dev, "unsupported CLEAR_FEATURE\n"); +-+ goto stall; +-+ case USB_RECIP_ENDPOINT: +-+ if (ctrl.wValue != __constant_cpu_to_le16( +-+ USB_ENDPOINT_HALT) +-+ || le16_to_cpu(ctrl.wLength) != 0) +-+ goto stall; +-+ if ((epn = get_ep_by_addr(dev, +-+ le16_to_cpu(ctrl.wIndex))) == 0) +-+ goto stall; +-+ clear_halt(epn); +-+ ep_ack(&dev->ep[0]); +-+ +-+ dev->ep0state = EP0_STATUS; +-+ VDEBUG(dev, "ep0state: EP0_STATUS\n"); +-+ +-+ DEBUG(dev, "%s clear halt\n", epn->ep.name); +-+ goto end; +-+ } +-+ break; +-+ +-+ case USB_REQ_SET_FEATURE: +-+ DEBUG (dev, "SETUP: USB_REQ_SET_FEATURE\n"); +-+ switch (ctrl.bRequestType) { +-+ case USB_RECIP_DEVICE: +-+ if (ctrl.wValue == __constant_cpu_to_le16( +-+ USB_DEVICE_REMOTE_WAKEUP)) { +-+ dev->enable_wakeup = 1; +-+ DEBUG(dev, "SET_FEATURE: " +-+ "remote wakeup enabled\n"); +-+ goto end; +-+ } else { +-+ DEBUG(dev, "unsupported SET_FEATURE\n"); +-+ goto stall; +-+ } +-+ break; +-+ case USB_RECIP_INTERFACE: +-+ DEBUG(dev, "unsupported SET_FEATURE\n"); +-+ goto stall; +-+ case USB_RECIP_ENDPOINT: +-+ if (ctrl.wValue != __constant_cpu_to_le16( +-+ USB_ENDPOINT_HALT) +-+ || le16_to_cpu(ctrl.wLength) != 0) +-+ goto stall; +-+ if ((epn = get_ep_by_addr(dev, +-+ le16_to_cpu(ctrl.wIndex))) == 0) +-+ goto stall; +-+ set_halt(epn); +-+ ep_ack(&dev->ep[0]); +-+ +-+ DEBUG(dev, "%s set halt\n", epn->ep.name); +-+ goto end; +-+ } +-+ break; +-+ +-+ case USB_REQ_SET_ADDRESS: +-+ /* hw handles set_address, address range: 1-127 */ +-+ DEBUG(dev, "SETUP: USB_REQ_SET_ADDRESS\n"); +-+ if (setup_pkt[1] == USB_REQ_SET_ADDRESS) { +-+ addr_new = le16_to_cpu(ctrl.wValue) & 0x7f; +-+ DEBUG(dev, "addr_new = 0x%02x\n", addr_new); +-+ +-+ /* hardware didn't ACK SET_ADDRESS */ +-+ ep_ack(&dev->ep[0]); +-+ } +-+ goto end; +-+ +-+ case USB_REQ_GET_DESCRIPTOR: +-+ DEBUG(dev, "SETUP: USB_REQ_GET_DESCRIPTOR\n"); +-+ goto delegate; +-+ +-+ case USB_REQ_SET_DESCRIPTOR: +-+ DEBUG(dev, "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n"); +-+ goto stall; +-+ break; +-+ +-+ case USB_REQ_GET_CONFIGURATION: +-+ DEBUG(dev, "SETUP: USB_REQ_GET_CONFIGURATION\n"); +-+ goto delegate; +-+ +-+ case USB_REQ_SET_CONFIGURATION: +-+ DEBUG(dev, "SETUP: USB_REQ_SET_CONFIGURATION\n"); +-+ goto delegate; +-+ +-+ case USB_REQ_GET_INTERFACE: +-+ DEBUG(dev, "SETUP: USB_REQ_GET_INTERFACE\n"); +-+ goto delegate; +-+ +-+ case USB_REQ_SET_INTERFACE: +-+ DEBUG(dev, "SETUP: USB_REQ_SET_INTERFACE\n"); +-+ goto delegate; +-+ +-+ case USB_REQ_SYNCH_FRAME: +-+ DEBUG(dev, "SETUP: USB_REQ_SYNCH_FRAME unsupported\n"); +-+ goto stall; +-+ break; +-+ default: +-+ /* delegate usb standard requests to the gadget driver. +-+ * it may respond after this irq handler returns. +-+ */ +-+ goto delegate; +-+delegate: +-+ DEBUG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", +-+ ctrl.bRequestType, ctrl.bRequest, +-+ le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex), +-+ le16_to_cpu(ctrl.wLength)); +-+ +-+ /* WORKAROUND: for RNDIS */ +-+ /* CDC: SEND_ENCAPSULATED_COMMAND */ +-+ if ((ctrl.bRequestType == 0x21) +-+ && (ctrl.bRequest == 0x00)) { +-+ /* CDC: SEND_ENCAPSULATED_COMMAND */ +-+ DEBUG(dev, "CDC: SEND_ENCAPSULATED_COMMAND\n"); +-+ dev->gadget.ep0 = &dev->ep[1].ep; +-+ spin_unlock(&dev->lock); +-+ tmp = dev->driver->setup(&dev->gadget, &ctrl); +-+ spin_lock(&dev->lock); +-+ +-+ /* switch back to ep0-in */ +-+ dev->gadget.ep0 = &dev->ep[0].ep; +-+ +-+ /* hardware didn't ACK */ +-+ ep_ack(&dev->ep[0]); +-+ } else { +-+ dev->gadget.ep0 = &dev->ep[0].ep; +-+ spin_unlock(&dev->lock); +-+ tmp = dev->driver->setup(&dev->gadget, &ctrl); +-+ spin_lock(&dev->lock); +-+ +-+ /* CDC: GET_ENCAPSULATED_COMMAND */ +-+ if ((ctrl.bRequestType == 0xa1) +-+ && (ctrl.bRequest == 0x01)) { +-+ DEBUG(dev, "CDC: GET_ENCAPSULATED_COMMAND\n"); +-+ +-+ /* hardware didn't ACK */ +-+ ep_ack(&dev->ep[1]); +-+ } +-+ } +-+ break; +-+ } +-+ +-+ /* stall ep0-out on error */ +-+ if (unlikely(tmp < 0)) { +-+stall: +-+ DEBUG(dev, "req %02x.%02x protocol STALL; err %d\n", +-+ ctrl.bRequestType, ctrl.bRequest, tmp); +-+ dev->ep[1].stopped = 1; +-+ dev->ep0state = EP0_STALL; +-+ VDEBUG(dev, "ep0state: EP0_STALL\n"); +-+ } +-+end: +-+ VDEBUG(dev, "<--- ep0_setup() \n"); +-+} +-+ +-+ +-+static void handle_device_irqs(struct iusbc *dev) +-+{ +-+ u32 stat; +-+ volatile u32 dev_sts; +-+ unsigned is_connected = 0; +-+ +-+ DEBUG(dev, "---> handle_device_irqs() \n"); +-+ +-+ stat = dev->int_sts; +-+ +-+ /* get device status, set USB speed */ +-+ if ((stat & RESET_INTR) || (stat & CONNECT_INTR) +-+ || (stat & SUSPEND_INTR)) { +-+ /* check device status */ +-+ dev_sts = readl(&dev->regs->dev_sts); +-+ DEBUG(dev, "handle_device_irqs: dev_sts = 0x%08x\n", +-+ dev_sts); +-+ +-+ if (dev_sts & CONNECTED) { +-+ is_connected = 1; +-+ DEBUG(dev, "device connected\n"); +-+ +-+ /* check suspend/resume status now */ +-+ if (dev_sts & SUSPEND) +-+ dev->suspended = 1; +-+ else +-+ dev->suspended = 0; +-+ +-+ /* RATE: high/full speed flag +-+ * 1 clock cycle after CONNECT, +-+ * read one more time until RATE bit set +-+ */ +-+ dev_sts = readl(&dev->regs->dev_sts); +-+ DEBUG(dev, "read for RATE: dev_sts = 0x%08x\n", +-+ dev_sts); +-+ if (dev_sts & RATE) { +-+ if (dev->force_fullspeed) { +-+ dev->gadget.speed = USB_SPEED_FULL; +-+ DEBUG(dev, "speed: USB_SPEED_FULL\n"); +-+ } else { +-+ dev->gadget.speed = USB_SPEED_HIGH; +-+ DEBUG(dev, "speed: USB_SPEED_HIGH\n"); +-+ } +-+ } else { +-+ dev->gadget.speed = USB_SPEED_FULL; +-+ DEBUG(dev, "speed: USB_SPEED_FULL\n"); +-+ } +-+ } else { /* disconnected */ +-+ is_connected = 0; +-+ DEBUG(dev, "device disconnected\n"); +-+ } +-+ } +-+ +-+ /* USB reset interrupt indication */ +-+ if ((stat & RESET_INTR) && (!dev->is_reset)) { +-+ DEBUG(dev, "USB Reset interrupt: stat = 0x%08x\n", stat); +-+ /* ACK RESET_INTR */ +-+ stat &= ~RESET_INTR; +-+ dev->irqs++; +-+ VDEBUG(dev, "dev->irqs: %lu\n", dev->irqs); +-+ +-+ /* set device reset flag */ +-+ dev->is_reset = 1; +-+ +-+ stop_activity(dev, dev->driver); +-+ ep0_start(dev); +-+ VDEBUG(dev, "reset: ep0_start()\n"); +-+ +-+ goto end; +-+ } +-+ +-+ +-+ /* connect interrupt indication */ +-+ if (stat & CONNECT_INTR) { +-+ DEBUG(dev, "CONNECT interrupt: stat = 0x%08x\n", stat); +-+ /* ACK CONNECT_INTR */ +-+ stat &= ~CONNECT_INTR; +-+ dev->irqs++; +-+ VDEBUG(dev, "dev->irqs: %lu\n", dev->irqs); +-+ +-+ /* connected status has changed */ +-+ if (dev->connected != is_connected) { +-+ DEBUG(dev, "connected status has changed\n"); +-+ dev->connected = is_connected; +-+ if (is_connected) { +-+ ep0_start(dev); +-+ DEBUG(dev, "connect %s\n", dev->driver->driver.name); +-+ } else { /* disconnected */ +-+ /* set device reset flag */ +-+ dev->is_reset = 0; +-+ stop_activity(dev, dev->driver); +-+ DEBUG(dev, "disconnect %s\n", dev->driver->driver.name); +-+ dev->ep0state = EP0_DISCONNECT; +-+ VDEBUG(dev, "ep0state: EP0_DISCONNECT\n"); +-+ } +-+ } +-+ } +-+ +-+ /* host suspend interrupt indication */ +-+ if (stat & SUSPEND_INTR) { +-+ DEBUG(dev, "SUSPEND interrupt: stat = 0x%08x\n", stat); +-+ /* ACK SUSPEND_INTR */ +-+ stat &= ~SUSPEND_INTR; +-+ dev->irqs++; +-+ VDEBUG(dev, "dev->irqs: %lu\n", dev->irqs); +-+ +-+ /* call gadget driver suspend/resume routines */ +-+ if (dev->suspended) { +-+ if (dev->driver->suspend) { +-+ spin_unlock(&dev->lock); +-+ dev->driver->suspend(&dev->gadget); +-+ spin_lock(&dev->lock); +-+ } +-+ DEBUG(dev, "suspend %s\n", dev->driver->driver.name); +-+ } else { +-+ if (dev->driver->resume) { +-+ spin_unlock(&dev->lock); +-+ dev->driver->resume(&dev->gadget); +-+ spin_lock(&dev->lock); +-+ } +-+ DEBUG(dev, "resume %s\n", dev->driver->driver.name); +-+ } +-+ } +-+ +-+ /* if haven't USB Reset yet, wait for the next USB reset interrupt */ +-+ if (!dev->is_reset) { +-+ DEBUG(dev, "Skip other interrupts before RESET\n"); +-+ } +-+ +-+end: +-+ VDEBUG(dev, "handle device_irq finish: int_sts = 0x%08x, " +-+ "stat = 0x%08x\n", dev->int_sts, stat); +-+ +-+ VDEBUG(dev, "<--- handle_device_irqs() \n"); +-+} +-+ +-+ +-+static void handle_ep0_irqs(struct iusbc *dev) +-+{ +-+ volatile u16 ep_sts, val_16; +-+ u32 stat; +-+ u8 setup_pkt_sts; +-+ struct iusbc_request *req; +-+ +-+ VDEBUG(dev, "---> handle_ep0_irqs() \n"); +-+ +-+ stat = dev->int_sts; +-+ VDEBUG(dev, "stat = 0x%08x\n", stat); +-+ +-+ /* ep0-out interrupt */ +-+ if (stat & EP0_OUT_INTR) { +-+ dev->ep[1].irqs++; +-+ VDEBUG(dev, "%s.irqs = %lu\n", +-+ dev->ep[1].ep.name ,dev->ep[1].irqs); +-+ +-+ ep_sts = readw(&dev->regs->ep[1].ep_sts); +-+ VDEBUG(dev, "%s.ep_sts = 0x%04x\n", +-+ dev->ep[1].ep.name, ep_sts); +-+ +-+ /* W1C ep0-out status register */ +-+ writew(ep_sts, &dev->regs->ep[1].ep_sts); +-+ +-+ if ((ep_sts & BAD_PID_TYPE) +-+ || (ep_sts & CRC_ERROR) +-+ || (ep_sts & FIFO_ERROR) +-+ || (ep_sts & DMA_ERROR) +-+ || (ep_sts & DMA_IOC)) { +-+ DEBUG(dev, "%s error: 0x%04x \n", +-+ dev->ep[1].ep.name, ep_sts); +-+ } +-+ +-+ if (ep_sts & TRANS_COMPLETE) { +-+ VDEBUG(dev, "handle ep0-out interrupt\n"); +-+ +-+ setup_pkt_sts = readb(&dev->regs->ep[1].setup_pkt_sts); +-+ VDEBUG(dev, "setup_pkt_sts = 0x%02x\n", setup_pkt_sts); +-+ /* ep0-out SETUP packet */ +-+ if (setup_pkt_sts) { +-+ VDEBUG(dev, "ep0-out SETUP packet\n"); +-+ +-+ /* W1C ep0-out Setup Packet Status Register */ +-+ writeb(1, &dev->regs->ep[1].setup_pkt_sts); +-+ +-+ /* read ep0-out Setup Packet Register +-+ * then handle ep0-out SETUP packet +-+ */ +-+ ep0_setup(dev); +-+ } else { +-+ /* ep0-out standard OUT packet */ +-+ DEBUG(dev, "ep0-out OUT packet\n"); +-+ if (!list_empty(&dev->ep[1].queue)) { +-+ req = list_entry(dev->ep[1].queue.next, +-+ struct iusbc_request, +-+ queue); +-+ VDEBUG(dev, "dmacount = %d\n", +-+ req->td->dmacount); +-+ dma_done(&dev->ep[1], req, 0); +-+ VDEBUG(dev, "%s dma_done()\n", +-+ dev->ep[1].ep.name); +-+ } +-+ +-+ /* handle next standard OUT packet */ +-+ if (!list_empty(&dev->ep[1].queue)) { +-+ restart_dma(&dev->ep[1]); +-+ VDEBUG(dev, "%s restart_dma()\n", +-+ dev->ep[1].ep.name); +-+ } +-+ } +-+ } else { +-+ /* WORKAROUND: FIFO_ERROR TC=0 */ +-+ if (ep_sts & FIFO_ERROR) +-+ DEBUG(dev, "ep0-out FIFO_ERROR, TC=0\n"); +-+ } +-+ +-+ /* enable DMA again */ +-+ val_16 = readw(&dev->regs->ep[1].ep_cfg); +-+ val_16 |= EP_ENABLE; +-+ writew(val_16, &dev->regs->ep[1].ep_cfg); +-+ +-+ val_16 = readw(&dev->regs->ep[1].ep_cfg); +-+ VDEBUG(dev, "enable %s DMA transfer...\n", +-+ dev->ep[1].ep.name); +-+ VDEBUG(dev, "%s EP_ENABLE again, ep_cfg=0x%04x\n", +-+ dev->ep[1].ep.name, val_16); +-+ } +-+ +-+ /* ep0-in interrupt */ +-+ if (stat & EP0_IN_INTR) { +-+ dev->ep[0].irqs++; +-+ VDEBUG(dev, "%s.irqs = %lu\n", +-+ dev->ep[0].ep.name, dev->ep[0].irqs); +-+ +-+ ep_sts = readw(&dev->regs->ep[0].ep_sts); +-+ VDEBUG(dev, "%s.ep_sts = 0x%04x\n", +-+ dev->ep[0].ep.name, ep_sts); +-+ +-+ /* W1C ep0-in status register */ +-+ writew(ep_sts, &dev->regs->ep[0].ep_sts); +-+ +-+ if ((ep_sts & BAD_PID_TYPE) +-+ || (ep_sts & CRC_ERROR) +-+ || (ep_sts & FIFO_ERROR) +-+ || (ep_sts & DMA_ERROR) +-+ || (ep_sts & DMA_IOC)) { +-+ DEBUG(dev, "%s error: 0x%04x \n", +-+ dev->ep[0].ep.name, ep_sts); +-+ } +-+ +-+ if (ep_sts & TRANS_COMPLETE) { +-+ VDEBUG(dev, "handle ep0-in interrupt\n"); +-+ if (!list_empty(&dev->ep[0].queue)) { +-+ req = list_entry(dev->ep[0].queue.next, +-+ struct iusbc_request, +-+ queue); +-+ VDEBUG(dev, "dmacount = %d\n", req->td->dmacount); +-+ dma_done(&dev->ep[0], req, 0); +-+ VDEBUG(dev, "%s dma_done()\n", +-+ dev->ep[0].ep.name); +-+ } +-+ +-+ /* handle next standard IN packet */ +-+ if (!list_empty(&dev->ep[0].queue)) { +-+ restart_dma(&dev->ep[0]); +-+ VDEBUG(dev, "%s restart_dma()\n", +-+ dev->ep[0].ep.name); +-+ } +-+ } else { +-+ if (ep_sts & FIFO_ERROR) +-+ DEBUG(dev, "ep0-in FIFO_ERROR, TC=0\n"); +-+ } +-+ +-+ } +-+ +-+ VDEBUG(dev, "<--- handle_ep0_irqs() \n"); +-+} +-+ +-+ +-+static void handle_ep_irqs(struct iusbc *dev) +-+{ +-+ volatile u16 ep_sts; +-+ u32 stat; +-+ unsigned i; +-+ struct iusbc_request *req; +-+ +-+ VDEBUG(dev, "---> handle_ep_irqs() \n"); +-+ +-+ stat = dev->int_sts; +-+ VDEBUG(dev, "stat = 0x%08x\n", stat); +-+ +-+ /* ep1in-bulk, ep1out-bulk and ep2in-int */ +-+ for (i = 2; i < 5; i++) { +-+ if ((1 << i) & stat) { +-+ dev->ep[i].irqs++; +-+ ep_sts = readw(&dev->regs->ep[i].ep_sts); +-+ if (ep_sts) +-+ VDEBUG(dev, "%s.ep_sts = 0x%04x\n", +-+ dev->ep[i].ep.name, ep_sts); +-+ +-+ /* W1C ep status register */ +-+ writew(ep_sts, &dev->regs->ep[i].ep_sts); +-+ +-+ if ((ep_sts & BAD_PID_TYPE) +-+ || (ep_sts & CRC_ERROR) +-+ || (ep_sts & FIFO_ERROR) +-+ || (ep_sts & DMA_ERROR) +-+ || (ep_sts & DMA_IOC)) { +-+ DEBUG(dev, "%s error: 0x%04x \n", +-+ dev->ep[i].ep.name, ep_sts); +-+ } +-+ +-+ if (ep_sts & TRANS_COMPLETE) { +-+ VDEBUG(dev, "handle %s interrupt\n", +-+ dev->ep[i].ep.name); +-+ VDEBUG(dev, "data ep dma TRANS_COMPLETE\n"); +-+ if (!list_empty(&dev->ep[i].queue)) { +-+ req = list_entry(dev->ep[i].queue.next, +-+ struct iusbc_request, +-+ queue); +-+ VDEBUG(dev, "dmacount = %d\n", +-+ req->td->dmacount); +-+ dma_done(&dev->ep[i], req, 0); +-+ VDEBUG(dev, "%s dma_done()\n", +-+ dev->ep[i].ep.name); +-+ } +-+ +-+ /* handle next standard OUT and IN packet */ +-+ if (!list_empty(&dev->ep[i].queue)) { +-+ restart_dma(&dev->ep[i]); +-+ VDEBUG(dev, "%s restart_dma()\n", +-+ dev->ep[i].ep.name); +-+ } +-+ } else { +-+ if (ep_sts & FIFO_ERROR) +-+ DEBUG(dev, "%s FIFO_ERROR, TC=0\n", +-+ dev->ep[i].ep.name); +-+ } +-+ } +-+ } +-+ +-+ VDEBUG(dev, "<--- handle_ep_irqs() \n"); +-+} +-+ +-+ +-+static void iusbc_do_tasklet(unsigned long arg) +-+{ +-+ u32 val_32; +-+ volatile u32 dev_sts; +-+ struct iusbc *dev; +-+ dev = (struct iusbc *) arg; +-+ DEBUG(dev, "---> iusbc_do_tasklet() \n"); +-+ +-+ spin_lock(&dev->lock); +-+ +-+ /* disable irqs, will re-enable later */ +-+ writel(0, &dev->regs->int_ctrl); +-+ +-+ /* device-wide reset, connect, suspend */ +-+ if (dev->int_sts & (RESET_INTR | CONNECT_INTR | SUSPEND_INTR)) { +-+ DEBUG(dev, "iusbc_do_tasklet -> handle_device_irqs\n"); +-+ handle_device_irqs(dev); +-+ } +-+ +-+ /* QQQ: disable Full speed mode for D1 hw issues. */ +-+ dev_sts = readl(&dev->regs->dev_sts); +-+ if ((dev_sts & RATE) && (dev_sts & CONNECTED)) { +-+ /* ep0-in/out control requests and interrupt */ +-+ if (dev->int_sts & (EP0_IN_INTR | EP0_OUT_INTR)) { +-+ DEBUG(dev, "iusbc_do_tasklet -> handle_ep0_irqs\n"); +-+ handle_ep0_irqs(dev); +-+ } +-+ /* data endpoints requests interrupt */ +-+ if (dev->int_sts & (EP1_IN_INTR | EP1_OUT_INTR | EP2_IN_INTR)) { +-+ DEBUG(dev, "iusbc_do_tasklet -> handle_ep_irqs\n"); +-+ handle_ep_irqs(dev); +-+ } +-+ } else if (dev_sts & CONNECTED) { +-+ stop_activity(dev, dev->driver); +-+ dev->ep0state = EP0_DISCONNECT; +-+ /*iusbc_pullup(&dev->gadget, 0);*/ +-+ } +-+ +-+ /* enable irqs again */ +-+ val_32 = 0; +-+ val_32 |= RESET_INTR_ENABLE +-+ | CONNECT_INTR_ENABLE +-+ | SUSPEND_INTR_ENABLE +-+ /* | EP3_OUT_INTR_ENABLE */ +-+ /* | EP3_IN_INTR_ENABLE */ +-+ /* | EP2_OUT_INTR_ENABLE */ +-+ | EP2_IN_INTR_ENABLE +-+ | EP1_OUT_INTR_ENABLE +-+ | EP1_IN_INTR_ENABLE +-+ | EP0_OUT_INTR_ENABLE +-+ | EP0_IN_INTR_ENABLE; +-+ +-+ writel(val_32, &dev->regs->int_ctrl); +-+ val_32 = readl(&dev->regs->int_ctrl); +-+ DEBUG(dev, "enable irqs again in iusbc_do_tasklet(), " +-+ "int_ctrl = 0x%08x\n", val_32); +-+ +-+ spin_unlock(&dev->lock); +-+ +-+ DEBUG(dev, "<--- iusbc_do_tasklet() \n"); +-+} +-+ +-+ +-+static irqreturn_t iusbc_irq(int irq, void *_dev) +-+{ +-+ struct iusbc *dev = _dev; +-+ u32 int_sts, +-+ int_ctrl, +-+ val_32; +-+ +-+ VDEBUG(dev, "---> iusbc_irq() \n"); +-+ +-+ /* interrupt control */ +-+ int_ctrl = readl(&dev->regs->int_ctrl); +-+ VDEBUG(dev, "int_ctrl = 0x%08x\n", int_ctrl); +-+ +-+ /* interrupt status */ +-+ int_sts = readl(&dev->regs->int_sts); +-+ VDEBUG(dev, "int_sts = 0x%08x\n", int_sts); +-+ +-+ if (!int_sts || !int_ctrl) { +-+ VDEBUG(dev, "handle IRQ_NONE\n"); +-+ VDEBUG(dev, "<--- iusbc_irq() \n"); +-+ return IRQ_NONE; +-+ } +-+ +-+ /* disable irqs, will re-enable later */ +-+ writel(0, &dev->regs->int_ctrl); +-+ +-+ /* W1C interrupt status register */ +-+ writel(int_sts, &dev->regs->int_sts); +-+ val_32 = readl(&dev->regs->int_sts); +-+ VDEBUG(dev, "W1C: regs->int_sts = 0x%08x\n", val_32); +-+ +-+ /* for iusbc_tasklet */ +-+ dev->int_sts = int_sts; +-+ +-+ /* check device status */ +-+ val_32 = readl(&dev->regs->dev_sts); +-+ DEBUG(dev, "iusbc_irq: dev_sts = 0x%08x\n", val_32); +-+ +-+ /* schedule irq tasklet */ +-+ tasklet_schedule(&dev->iusbc_tasklet); +-+ +-+ VDEBUG(dev, "<--- iusbc_irq() \n"); +-+ return IRQ_HANDLED; +-+} +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+static void gadget_release(struct device *_dev) +-+{ +-+ struct iusbc *dev; +-+#ifdef VERBOSE +-+ printk(KERN_DEBUG "---> gadget_release() \n"); +-+#endif +-+ +-+ dev = dev_get_drvdata(_dev); +-+ kfree(dev); +-+ +-+#ifdef VERBOSE +-+ printk(KERN_DEBUG "<--- gadget_release() \n"); +-+#endif +-+} +-+ +-+ +-+/* tear down the binding between this driver and the pci device */ +-+static void iusbc_remove(struct pci_dev *pdev) +-+{ +-+ struct iusbc *dev; +-+ +-+ dev = pci_get_drvdata(pdev); +-+ +-+ BUG_ON(dev->driver); +-+ +-+ VDEBUG(dev, "---> iusbc_remove() \n"); +-+ +-+ /* then clean up the resources we allocated during probe() */ +-+ if (dev->requests) { +-+ unsigned i; +-+ /* 2 ep0, 3 data ep */ +-+ for (i = 0; i < 5; i++) { +-+ if (!dev->ep[i].dummy) +-+ continue; +-+ +-+ pci_pool_free(dev->requests, dev->ep[i].dummy, +-+ dev->ep[i].td_dma); +-+ } +-+ pci_pool_destroy(dev->requests); +-+ } +-+ +-+ if (dev->got_irq) +-+ free_irq(pdev->irq, dev); +-+ +-+ if (dev->regs) +-+ iounmap(dev->regs); +-+ +-+ if (dev->region) +-+ release_mem_region(pci_resource_start(pdev, 0), +-+ pci_resource_len(pdev, 0)); +-+ +-+ if (dev->enabled) +-+ pci_disable_device(pdev); +-+ +-+ device_unregister(&dev->gadget.dev); +-+ device_remove_file(&pdev->dev, &dev_attr_registers); +-+ pci_set_drvdata(pdev, NULL); +-+ +-+ INFO(dev, "unbind\n"); +-+ +-+ the_controller = NULL; +-+ +-+ VDEBUG(dev, "<--- iusbc_remove() \n"); +-+} +-+ +-+ +-+/* wrap this driver around the specified device, but +-+ * don't respond over USB until a gadget driver binds to us. +-+ */ +-+static int iusbc_probe(struct pci_dev *pdev, const struct pci_device_id *id) +-+{ +-+ struct iusbc *dev; +-+ unsigned long resource, len; +-+ void __iomem *base = NULL; +-+ int retval; +-+ unsigned i; +-+ u32 val_32; +-+ +-+ /* if you want to support more than one controller in a system, +-+ * usb_gadget_{register,unregister}_driver() must change. +-+ */ +-+ if (the_controller) { +-+ dev_warn(&pdev->dev, "ignoring\n"); +-+ return -EBUSY; +-+ } +-+ +-+ /* alloc, and start init */ +-+ dev = kzalloc(sizeof *dev, GFP_KERNEL); +-+ if (dev == NULL){ +-+ retval = -ENOMEM; +-+ goto done; +-+ } +-+ +-+ pci_set_drvdata(pdev, dev); +-+ spin_lock_init(&dev->lock); +-+ dev->pdev = pdev; +-+ +-+ DEBUG(dev, "---> iusbc_probe() \n"); +-+ +-+ dev->gadget.ops = &iusbc_ops; +-+ dev->gadget.is_dualspeed = 1; /* support high/full speed */ +-+ +-+ /* the "gadget" abstracts/virtualizes the controller */ +-+ strcpy(dev->gadget.dev.bus_id, "gadget"); +-+ dev->gadget.dev.parent = &pdev->dev; +-+ dev->gadget.dev.dma_mask = pdev->dev.dma_mask; +-+ dev->gadget.dev.release = gadget_release; +-+ dev->gadget.name = driver_name; +-+ +-+ /* now all the pci goodies ... */ +-+ if (pci_enable_device(pdev) < 0) { +-+ retval = -ENODEV; +-+ goto done; +-+ } +-+ +-+ /* WORKAROUND: USB port routing bug */ +-+ pci_write_config_byte(pdev, 0x40, 0x82); +-+ +-+ dev->enabled = 1; +-+ +-+ /* control register: BAR 0 */ +-+ resource = pci_resource_start(pdev, 0); +-+ len = pci_resource_len(pdev, 0); +-+ if (!request_mem_region(resource, len, driver_name)) { +-+ DEBUG(dev, "controller already in use\n"); +-+ retval = -EBUSY; +-+ goto done; +-+ } +-+ dev->region = 1; +-+ +-+ base = ioremap_nocache(resource, len); +-+ if (base == NULL) { +-+ DEBUG(dev, "can't map memory\n"); +-+ retval = -EFAULT; +-+ goto done; +-+ } +-+ dev->regs = (struct iusbc_regs __iomem *) base; +-+ +-+ /* global capabilities, ep number and dma modes */ +-+ val_32 = readl(&dev->regs->gcap); +-+ if (val_32 & TRANSFER_MODE_CAP) +-+ dev->transfer_mode_dma = 1; +-+ +-+ if (val_32 & SCATTER_GATHER_MODE_CAP) +-+ dev->sg_mode_dma = 1; +-+ +-+ if (val_32 & LINEAR_MODE_CAP) +-+ dev->linear_mode_dma = 1; +-+ +-+ if (val_32 & CONTROL_MODE_CAP) +-+ dev->control_mode_dma = 1; +-+ +-+ dev->ep_cap = (val_32 >> 28); +-+ +-+ /* reset all registers */ +-+ writel(0, &dev->regs->dev_ctrl); +-+ +-+ /* init usb client controller device */ +-+ iusbc_reset(dev); +-+ iusbc_reinit(dev); +-+ +-+ /* irq setup after old hardware is cleaned up */ +-+ if (!pdev->irq) { +-+ ERROR(dev, "No IRQ. Check PCI setup!\n"); +-+ retval = -ENODEV; +-+ goto done; +-+ } +-+ +-+ if (request_irq(pdev->irq, iusbc_irq, IRQF_SHARED, driver_name, dev) +-+ != 0) { +-+ ERROR(dev, "request interrupt %d failed\n", pdev->irq); +-+ retval = -EBUSY; +-+ goto done; +-+ } +-+ dev->got_irq = 1; +-+ +-+ /* ------------------------------------------------------------------ */ +-+ /* DMA setup +-+ * NOTE: we know only the 32 LSBs of dma addresses may be nonzero +-+ */ +-+ dev->requests = pci_pool_create("requests", pdev, +-+ sizeof(struct iusbc_dma), +-+ 0 /* no alignment requirements */, +-+ 0 /* or page-crossing issues */); +-+ +-+ if (!dev->requests) { +-+ DEBUG(dev, "can't get request pool\n"); +-+ retval = -ENOMEM; +-+ goto done; +-+ } +-+ +-+ /* assgined DMA */ +-+ /* 2 ep0, 3 data ep */ +-+ for (i = 0; i < 5 ; i++) { +-+ struct iusbc_dma *td; +-+ td = pci_pool_alloc(dev->requests, +-+ GFP_KERNEL, +-+ &dev->ep[i].td_dma); +-+ +-+ if (!td) { +-+ DEBUG(dev, "can't get dummy %d\n", i); +-+ retval = -ENOMEM; +-+ goto done; +-+ } +-+ +-+ td->dmacount = 0; /* not VALID */ +-+ td->dmaaddr = __constant_cpu_to_le32(DMA_ADDR_INVALID); +-+ +-+ dev->ep[i].dummy = td; +-+ } +-+ +-+ /* enables bus-mastering for device dev */ +-+ pci_set_master(pdev); +-+ +-+ /* ------------------------------------------------------------------ */ +-+ /* done */ +-+ INFO(dev, "%s\n", driver_desc); +-+ INFO(dev, "irq %d, pci mem %p\n", pdev->irq, base); +-+ INFO(dev, "version: " DRIVER_VERSION "\n"); +-+ INFO(dev, "support (max) %d endpoints\n", dev->ep_cap * 2); +-+ +-+#ifdef VERBOSE +-+ /* only for debugging, print mapped memory registers */ +-+ VDEBUG(dev, "After iusbc_probe(), print register values:\n"); +-+ print_all_registers(dev->regs); +-+#endif +-+ +-+ the_controller = dev; +-+ retval = device_register(&dev->gadget.dev); +-+ +-+ if (retval) +-+ goto done; +-+ +-+ retval = device_create_file(&pdev->dev, &dev_attr_registers); +-+ +-+ if (retval) +-+ goto done; +-+ +-+ DEBUG(dev, "<--- iusbc_probe() \n"); +-+ +-+ return 0; +-+ +-+done: +-+ if (dev) +-+ iusbc_remove(pdev); +-+ +-+ DEBUG(dev, "<--- iusbc_probe() \n"); +-+ +-+ return retval; +-+} +-+ +-+ +-+#ifdef CONFIG_PM +-+/* client suspend */ +-+static int iusbc_suspend(struct pci_dev *pdev, pm_message_t state) +-+{ +-+ struct iusbc *dev; +-+ unsigned long flags; +-+ +-+ dev = pci_get_drvdata(pdev); +-+ +-+ DEBUG(dev, "---> iusbc_suspend() \n"); +-+ +-+ tasklet_kill(&dev->iusbc_tasklet); +-+ +-+ spin_lock_irqsave(&dev->lock, flags); +-+ stop_activity(dev, dev->driver); +-+ spin_unlock_irqrestore(&dev->lock, flags); +-+ +-+ iusbc_pullup(&dev->gadget, 0); +-+ +-+ pci_save_state(pdev); +-+ pci_set_power_state(pdev, PCI_D3hot); +-+ +-+ DEBUG(dev, "<--- iusbc_suspend() \n"); +-+ +-+ return 0; +-+} +-+ +-+/* client resume */ +-+static int iusbc_resume(struct pci_dev *pdev) +-+{ +-+ struct iusbc *dev; +-+ +-+ dev = pci_get_drvdata(pdev); +-+ +-+ DEBUG(dev, "---> iusbc_resume() \n"); +-+ +-+ pci_set_power_state(pdev, PCI_D0); +-+ pci_restore_state(pdev); +-+ +-+ device_start(dev); +-+ +-+ DEBUG(dev, "<--- iusbc_resume() \n"); +-+ +-+ return 0; +-+} +-+#endif +-+ +-+ +-+static void iusbc_shutdown(struct pci_dev *pdev) +-+{ +-+ struct iusbc *dev; +-+ u32 val_32; +-+ +-+ dev = pci_get_drvdata(pdev); +-+ +-+ DEBUG(dev, "---> iusbc_shutdown() \n"); +-+ +-+ /* disable irqs */ +-+ writel(0, &dev->regs->int_ctrl); +-+ +-+ /* reset all registers */ +-+ writel(0, &dev->regs->dev_ctrl); +-+ +-+ val_32 = readl(&dev->regs->dev_ctrl); +-+ DEBUG(dev, "dev_ctrl = 0x%08x\n", val_32); +-+ +-+ DEBUG(dev, "<--- iusbc_shutdown() \n"); +-+} +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+static const struct pci_device_id pci_ids [] = { { +-+ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0x80), +-+ .class_mask = ~0, +-+ .vendor = 0x8086, /* Intel */ +-+ .device = 0x8118, /* Poulsbo USB Client Controller */ +-+ .subvendor = PCI_ANY_ID, +-+ .subdevice = PCI_ANY_ID, +-+}, { /* end: all zeroes */ } +-+}; +-+ +-+MODULE_DEVICE_TABLE(pci, pci_ids); +-+ +-+/* pci driver glue; this is a "new style" PCI driver module */ +-+static struct pci_driver iusbc_pci_driver = { +-+ .name = (char *) driver_name, +-+ .id_table = pci_ids, +-+ +-+ .probe = iusbc_probe, +-+ .remove = iusbc_remove, +-+ +-+#ifdef CONFIG_PM +-+ .suspend = iusbc_suspend, +-+ .resume = iusbc_resume, +-+#endif +-+ +-+ .shutdown = iusbc_shutdown, +-+}; +-+ +-+ +-+MODULE_DESCRIPTION(DRIVER_DESC); +-+MODULE_AUTHOR("Xiaochen Shen: xiaochen.shen@intel.com"); +-+MODULE_VERSION(DRIVER_VERSION); +-+MODULE_LICENSE("GPL"); +-+ +-+ +-+static int __init init(void) +-+{ +-+ return pci_register_driver(&iusbc_pci_driver); +-+} +-+module_init(init); +-+ +-+ +-+static void __exit cleanup(void) +-+{ +-+ /* in case deferred_free tasklet not finished */ +-+ spin_lock(&buflock); +-+ while (!list_empty(&buffers)) { +-+ spin_unlock(&buflock); +-+ msleep(1); +-+ spin_lock(&buflock); +-+ } +-+ spin_unlock(&buflock); +-+ pci_unregister_driver(&iusbc_pci_driver); +-+} +-+module_exit(cleanup); +-+ +-diff --git a/drivers/usb/gadget/iusbc.h b/drivers/usb/gadget/iusbc.h +-new file mode 100644 +-index 0000000..9e0517b +---- /dev/null +-+++ b/drivers/usb/gadget/iusbc.h +-@@ -0,0 +1,213 @@ +-+/* +-+ * Intel Poulsbo USB Client Controller Driver +-+ * Copyright (C) 2006-07, Intel Corporation. +-+ * +-+ * This program is free software; you can redistribute it and/or modify it +-+ * under the terms and conditions of the GNU General Public License, +-+ * version 2, as published by the Free Software Foundation. +-+ * +-+ * This program is distributed in the hope it will be useful, but WITHOUT +-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +-+ * more details. +-+ * +-+ * You should have received a copy of the GNU General Public License along with +-+ * this program; if not, write to the Free Software Foundation, Inc., +-+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +-+ * +-+ */ +-+ +-+#include +-+ +-+/* +-+ * MEMORY SPACE REGISTERS +-+ */ +-+ +-+struct iusbc_ep_regs { /* 0x20 bytes */ +-+ u32 ep_base_low_32; +-+ u32 ep_base_hi_32; +-+ u16 ep_len; +-+ u16 ep_pib; +-+ u16 ep_dil; +-+ u16 ep_tiq; +-+ u16 ep_max; +-+ u16 ep_sts; +-+#define BAD_PID_TYPE (1 << 15) +-+#define CRC_ERROR (1 << 14) +-+#define FIFO_ERROR (1 << 13) +-+#define DMA_ERROR (1 << 12) +-+#define TRANS_COMPLETE (1 << 11) +-+#define PING_NAK_SENT (1 << 10) +-+#define DMA_IOC (1 << 9) +-+ u16 ep_cfg; +-+#define INTR_BAD_PID_TYPE (1 << 15) +-+#define INTR_CRC_ERROR (1 << 14) +-+#define INTR_FIFO_ERROR (1 << 13) +-+#define INTR_DMA_ERROR (1 << 12) +-+#define INTR_TRANS_COMPLETE (1 << 11) +-+#define INTR_PING_NAK_SENT (1 << 10) +-+#define INTR_DMA_IOC (1 << 9) +-+#define LINEAR_MODE 0 +-+#define SCATTER_GATHER_MODE 1 +-+#define TRANSFER_MODE 2 +-+#define CONTROL_MODE 3 +-+#define EP_ENABLE (1 << 1) +-+#define EP_VALID (1 << 0) +-+ u8 _unused; +-+ u8 setup_pkt_sts; +-+#define SETUPPACKET_VALID (1 << 0) +-+ u8 setup_pkt[8]; +-+} __attribute__ ((packed)); +-+ +-+ +-+struct iusbc_regs { +-+ /* offset 0x0000 */ +-+ u32 gcap; +-+#define DMA_IOC_CAP (1 << 4) +-+#define TRANSFER_MODE_CAP (1 << 3) +-+#define SCATTER_GATHER_MODE_CAP (1 << 2) +-+#define LINEAR_MODE_CAP (1 << 1) +-+#define CONTROL_MODE_CAP (1 << 0) +-+ u8 _unused0[0x100-0x004]; +-+ +-+ /* offset 0x0100 */ +-+ u32 dev_sts; +-+#define RATE (1 << 3) +-+#define CONNECTED (1 << 1) +-+#define SUSPEND (1 << 0) +-+ u16 frame; +-+ u8 _unused1[0x10c-0x106]; +-+ +-+ /* offset 0x010c */ +-+ u32 int_sts; +-+#define RESET_INTR (1 << 18) +-+#define CONNECT_INTR (1 << 17) +-+#define SUSPEND_INTR (1 << 16) +-+#define EP3_OUT_INTR (1 << 7) +-+#define EP3_IN_INTR (1 << 6) +-+#define EP2_OUT_INTR (1 << 5) +-+#define EP2_IN_INTR (1 << 4) +-+#define EP1_OUT_INTR (1 << 3) +-+#define EP1_IN_INTR (1 << 2) +-+#define EP0_OUT_INTR (1 << 1) +-+#define EP0_IN_INTR (1 << 0) +-+ u32 int_ctrl; +-+#define RESET_INTR_ENABLE (1 << 18) +-+#define CONNECT_INTR_ENABLE (1 << 17) +-+#define SUSPEND_INTR_ENABLE (1 << 16) +-+#define EP3_OUT_INTR_ENABLE (1 << 7) +-+#define EP3_IN_INTR_ENABLE (1 << 6) +-+#define EP2_OUT_INTR_ENABLE (1 << 5) +-+#define EP2_IN_INTR_ENABLE (1 << 4) +-+#define EP1_OUT_INTR_ENABLE (1 << 3) +-+#define EP1_IN_INTR_ENABLE (1 << 2) +-+#define EP0_OUT_INTR_ENABLE (1 << 1) +-+#define EP0_IN_INTR_ENABLE (1 << 0) +-+ u32 dev_ctrl; +-+#define DEVICE_ENABLE (1 << 31) +-+#define CONNECTION_ENABLE (1 << 30) +-+#define DMA3_DISABLED (1 << 15) +-+#define DMA2_DISABLED (1 << 14) +-+#define DMA1_DISABLED (1 << 13) +-+#define DMA0_DISABLED (1 << 12) +-+#define CPU_SET_ADDRESS (1 << 11) +-+#define DISABLE_NYET (1 << 9) +-+#define TEST_MODE (1 << 8) +-+#define SIGNAL_RESUME (1 << 4) +-+#define CHARGE_ENABLE (5 << 1) +-+#define FORCE_FULLSPEED (1 << 0) +-+ u8 _unused2[0x200-0x118]; +-+ +-+ /* offset: 0x200, 0x220, ..., 0x2e0 */ +-+ struct iusbc_ep_regs ep[8]; +-+} __attribute__ ((packed)); +-+ +-+ +-+/*-------------------------------------------------------------------------*/ +-+ +-+/* DRIVER DATA STRUCTURES and UTILITIES */ +-+ +-+/* FIXME: for scatter/gather mode DMA */ +-+struct iusbc_dma { +-+ __le16 dmacount; +-+ __le32 dmaaddr; /* the buffer */ +-+ __le32 dmadesc; /* next dma descriptor */ +-+ __le32 _reserved; +-+} __attribute__ ((aligned (16))); +-+ +-+struct iusbc_ep { +-+ struct usb_ep ep; +-+ struct iusbc_dma *dummy; +-+ dma_addr_t td_dma; /* of dummy */ +-+ struct iusbc *dev; +-+ unsigned long irqs; +-+ +-+ /* analogous to a host-side qh */ +-+ struct list_head queue; +-+ const struct usb_endpoint_descriptor *desc; +-+ unsigned num : 8, +-+ stopped : 1, +-+ is_in : 1, +-+ dma_mode : 2, +-+ ep_type : 2; +-+}; +-+ +-+struct iusbc_request { +-+ struct usb_request req; +-+ struct iusbc_dma *td; +-+ dma_addr_t td_dma; +-+ struct list_head queue; +-+ unsigned mapped : 1, +-+ valid : 1; +-+}; +-+ +-+enum ep0state { +-+ EP0_DISCONNECT, /* no host */ +-+ EP0_IDLE, /* between STATUS ack and SETUP report */ +-+ EP0_IN, EP0_OUT, /* data stage */ +-+ EP0_STATUS, /* status stage */ +-+ EP0_STALL, /* data or status stages */ +-+ EP0_SUSPEND, /* usb suspend */ +-+}; +-+ +-+struct iusbc { +-+ /* each pci device provides one gadget, several endpoints */ +-+ struct usb_gadget gadget; +-+ spinlock_t lock; +-+ struct iusbc_ep ep[8]; +-+ struct usb_gadget_driver *driver; +-+ enum ep0state ep0state; +-+ unsigned ep_cap; +-+ unsigned enabled : 1, +-+ powered : 1, +-+ enable_wakeup : 1, +-+ force_fullspeed : 1, +-+ rate : 1, +-+ connected : 1, +-+ suspended : 1, +-+ got_irq : 1, +-+ region : 1, +-+ transfer_mode_dma : 1, +-+ sg_mode_dma : 1, +-+ linear_mode_dma : 1, +-+ control_mode_dma : 1, +-+ is_reset : 1; +-+ +-+ /* pci state used to access those endpoints */ +-+ struct pci_dev *pdev; +-+ struct iusbc_regs __iomem *regs; +-+ struct pci_pool *requests; +-+ +-+ /* statistics... */ +-+ unsigned long irqs; +-+ +-+ /* 16 bits status data for GET_STATUS */ +-+ __le16 status_d; +-+ +-+ /* device irq tasklet */ +-+ struct tasklet_struct iusbc_tasklet; +-+ +-+ /* interrupt status register value */ +-+ volatile u32 int_sts; +-+}; +-+ +-diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c +-index db1b2bf..d6b7a83 100644 +---- a/drivers/usb/gadget/rndis.c +-+++ b/drivers/usb/gadget/rndis.c +-@@ -40,7 +40,7 @@ +- +- #undef RNDIS_PM +- #undef RNDIS_WAKEUP +--#undef VERBOSE +-+#define VERBOSE +- +- #include "rndis.h" +- +-@@ -52,14 +52,14 @@ +- * and will be happier if you provide the host_addr module parameter. +- */ +- +--#if 0 +-+#if 1 +- #define DBG(str,args...) do { \ +- if (rndis_debug) \ +- printk(KERN_DEBUG str , ## args ); \ +- } while (0) +--static int rndis_debug = 0; +-+static int rndis_debug = 2; +- +--module_param (rndis_debug, int, 0); +-+module_param (rndis_debug, int, S_IRUGO|S_IWUSR); +- MODULE_PARM_DESC (rndis_debug, "enable debugging"); +- +- #else +-@@ -586,12 +586,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, +- case OID_802_3_MAXIMUM_LIST_SIZE: +- DBG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); +- /* Multicast base address only */ +-- *outbuf = __constant_cpu_to_le32 (1); +-+ *outbuf = __constant_cpu_to_le32 (32); +- retval = 0; +- break; +- +- case OID_802_3_MAC_OPTIONS: +- DBG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__); +-+ *outbuf = __constant_cpu_to_le32 (0); +-+ retval = 0; +- break; +- +- /* ieee802.3 statistics OIDs (table 4-4) */ +-@@ -898,7 +900,7 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf) +- +- static int rndis_set_response (int configNr, rndis_set_msg_type *buf) +- { +-- u32 BufLength, BufOffset; +-+ u32 BufLength, BufOffset, i; +- rndis_set_cmplt_type *resp; +- rndis_resp_t *r; +- +diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig +index f81d08d..8d71885 100644 +--- a/drivers/usb/gadget/Kconfig ++++ b/drivers/usb/gadget/Kconfig +@@ -324,6 +324,27 @@ config USB_AT91 + depends on USB_GADGET_AT91 + default USB_GADGET + ++config USB_GADGET_IUSBC ++ boolean "Intel USB Client Controller" ++ depends on PCI ++ select USB_GADGET_DUALSPEED ++ help ++ Intel USB client controller is a PCI based USB peripheral controller ++ which supports both full and high speed USB 2.0 data transfers. ++ ++ It has three IN and three OUT configurable endpoints, as well ++ as endpoint zero (for control transfers). ++ ++ Say "y" to link the driver statically, or "m" to build a ++ dynamically linked module called "iusbc" and force all ++ gadget drivers to also be dynamically linked. ++ ++config USB_IUSBC ++ tristate ++ depends on USB_GADGET_IUSBC ++ default USB_GADGET ++ select USB_GADGET_SELECTED ++ + config USB_GADGET_DUMMY_HCD + boolean "Dummy HCD (DEVELOPMENT)" + depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL +diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile +index 904e57b..8e533bf 100644 +--- a/drivers/usb/gadget/Makefile ++++ b/drivers/usb/gadget/Makefile +@@ -17,6 +17,7 @@ obj-$(CONFIG_USB_AT91) += at91_udc.o + obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o + obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o + obj-$(CONFIG_USB_M66592) += m66592-udc.o ++obj-$(CONFIG_USB_IUSBC) += iusbc.o + + # + # USB gadget drivers +diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c +index ba7935d..7423a19 100644 +--- a/drivers/usb/gadget/ether.c ++++ b/drivers/usb/gadget/ether.c +@@ -19,7 +19,7 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +-/* #define VERBOSE_DEBUG */ ++#define VERBOSE_DEBUG + + #include + #include +@@ -34,6 +34,10 @@ + + #include "gadget_chips.h" + ++#ifdef CONFIG_USB_GADGET_IUSBC ++#include "iusbc.h" ++#endif ++ + /*-------------------------------------------------------------------------*/ + + /* +@@ -68,7 +72,7 @@ + */ + + #define DRIVER_DESC "Ethernet Gadget" +-#define DRIVER_VERSION "May Day 2005" ++#define DRIVER_VERSION "2.0.0.32L.0010" + + static const char shortname [] = "ether"; + static const char driver_desc [] = DRIVER_DESC; +@@ -239,6 +243,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); + #define DEV_CONFIG_CDC + #endif + ++#ifdef CONFIG_USB_GADGET_IUSBC ++#define DEV_CONFIG_CDC ++#endif ++ + #ifdef CONFIG_USB_GADGET_S3C2410 + #define DEV_CONFIG_CDC + #endif +@@ -1353,11 +1361,31 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); ++ __le16 status = 0; + + /* descriptors just go into the pre-allocated ep0 buffer, + * while config change events may enable network traffic. + */ + req->complete = eth_setup_complete; ++ ++#ifdef CONFIG_USB_GADGET_IUSBC ++ /* software handles get_status in iusbc controller */ ++ if (gadget_is_iusbc(dev->gadget)) { ++ if ((ctrl->bRequest == USB_REQ_GET_STATUS) ++ && (ctrl->bRequestType & USB_DIR_IN) ++ && (ctrl->bRequestType != 0x21)) { ++ struct iusbc *controller = ++ container_of(dev->gadget, ++ struct iusbc, ++ gadget); ++ status = controller->status_d; ++ DEBUG (dev, "status_d: %d\n", status); ++ value = sizeof status; ++ *(u16 *) req->buf = le16_to_cpu(status); ++ } ++ } ++#endif ++ + switch (ctrl->bRequest) { + + case USB_REQ_GET_DESCRIPTOR: +@@ -1421,7 +1449,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) + || !dev->config + || wIndex > 1) + break; +- if (!cdc_active(dev) && wIndex != 0) ++ if (!rndis_active(dev) && !cdc_active(dev) && wIndex != 0) + break; + spin_lock (&dev->lock); + +@@ -1556,9 +1584,9 @@ done_set_intf: + u32 n; + + /* return the result */ +- buf = rndis_get_next_response(dev->rndis_config, &n); ++ buf = rndis_get_next_response (dev->rndis_config, &value); + if (buf) { +- memcpy(req->buf, buf, n); ++ memcpy (req->buf, buf, value); + req->complete = rndis_response_complete; + rndis_free_response(dev->rndis_config, buf); + value = n; +@@ -2640,6 +2668,7 @@ static struct usb_gadget_driver eth_driver = { + + MODULE_DESCRIPTION (DRIVER_DESC); + MODULE_AUTHOR ("David Brownell, Benedikt Spanger"); ++MODULE_VERSION(DRIVER_VERSION); + MODULE_LICENSE ("GPL"); + + +diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c +index 1d174dc..03bb0c9 100644 +--- a/drivers/usb/gadget/file_storage.c ++++ b/drivers/usb/gadget/file_storage.c +@@ -244,18 +244,23 @@ + + #include "gadget_chips.h" + ++#ifdef CONFIG_USB_GADGET_IUSBC ++#include "iusbc.h" ++#include /* for uevent usage */ ++#endif + + /*-------------------------------------------------------------------------*/ + + #define DRIVER_DESC "File-backed Storage Gadget" + #define DRIVER_NAME "g_file_storage" +-#define DRIVER_VERSION "7 August 2007" ++#define DRIVER_VERSION "2.0.0.32L.0010" + + static const char longname[] = DRIVER_DESC; + static const char shortname[] = DRIVER_NAME; + + MODULE_DESCRIPTION(DRIVER_DESC); + MODULE_AUTHOR("Alan Stern"); ++MODULE_VERSION(DRIVER_VERSION); + MODULE_LICENSE("Dual BSD/GPL"); + + /* Thanks to NetChip Technologies for donating this product ID. +@@ -545,6 +550,7 @@ struct lun { + unsigned int prevent_medium_removal : 1; + unsigned int registered : 1; + unsigned int info_valid : 1; ++ unsigned int switch_flag : 1; + + u32 sense_data; + u32 sense_data_info; +@@ -684,6 +690,7 @@ struct fsg_dev { + unsigned int nluns; + struct lun *luns; + struct lun *curlun; ++ int uevent_flag; + }; + + typedef void (*fsg_routine_t)(struct fsg_dev *); +@@ -1335,11 +1342,27 @@ static int standard_setup_req(struct fsg_dev *fsg, + int value = -EOPNOTSUPP; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); ++ __le16 status = 0; + + /* Usually this just stores reply data in the pre-allocated ep0 buffer, + * but config change events will also reconfigure hardware. */ + switch (ctrl->bRequest) { + ++#ifdef CONFIG_USB_GADGET_IUSBC ++ case USB_REQ_GET_STATUS: ++ /* software handles get_status in iusbc controller */ ++ if (gadget_is_iusbc(fsg->gadget)) { ++ struct iusbc *controller = ++ container_of(fsg->gadget, ++ struct iusbc, ++ gadget); ++ status = controller->status_d; ++ DBG(fsg, "status_d: %d\n", status); ++ value = sizeof status; ++ *(u16 *) req->buf = le16_to_cpu(status); ++ } ++ break; ++#endif + case USB_REQ_GET_DESCRIPTOR: + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | + USB_RECIP_DEVICE)) +@@ -1392,6 +1415,13 @@ get_config: + if (w_value == CONFIG_VALUE || w_value == 0) { + fsg->new_config = w_value; + ++#ifdef CONFIG_USB_GADGET_IUSBC ++ /* for resume from S3 in iusbc controller */ ++ if (gadget_is_iusbc(fsg->gadget)) { ++ fsg->state = FSG_STATE_IDLE; ++ fsg->config = 0; ++ } ++#endif + /* Raise an exception to wipe out previous transaction + * state (queued bufs, etc) and set the new config. */ + raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); +@@ -2853,6 +2883,9 @@ static int do_scsi_command(struct fsg_dev *fsg) + break; + + case SC_TEST_UNIT_READY: ++ i = fsg->cmnd[2]; ++ if (i == 0x55) ++ fsg->curlun->switch_flag = 1; + fsg->data_size_from_cmnd = 0; + reply = check_command(fsg, 6, DATA_DIR_NONE, + 0, 1, +@@ -3357,6 +3390,13 @@ static void handle_exception(struct fsg_dev *fsg) + + case FSG_STATE_CONFIG_CHANGE: + rc = do_set_config(fsg, new_config); ++#ifdef CONFIG_USB_GADGET_IUSBC ++ if (!fsg->uevent_flag){ ++ struct iusbc *_iusbc=container_of(fsg->gadget,struct iusbc,gadget); ++ kobject_uevent(&(_iusbc->pdev->dev.kobj), KOBJ_ONLINE); ++ fsg->uevent_flag=1; ++ } ++#endif + if (fsg->ep0_req_tag != exception_req_tag) + break; + if (rc != 0) // STALL on errors +@@ -3368,6 +3408,13 @@ static void handle_exception(struct fsg_dev *fsg) + case FSG_STATE_DISCONNECT: + fsync_all(fsg); + do_set_config(fsg, 0); // Unconfigured state ++#ifdef CONFIG_USB_GADGET_IUSBC ++ if (fsg->uevent_flag) { ++ struct iusbc *_iusbc=container_of(fsg->gadget,struct iusbc,gadget); ++ kobject_uevent(&(_iusbc->pdev->dev.kobj), KOBJ_OFFLINE); ++ fsg->uevent_flag=0; ++ } ++#endif + break; + + case FSG_STATE_EXIT: +@@ -3585,6 +3632,12 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, + return rc; + } + ++static ssize_t show_switch(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct lun *curlun = dev_to_lun(dev); ++ ++ return sprintf(buf, "%d\n", curlun->switch_flag); ++} + + static ssize_t store_ro(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +@@ -3649,6 +3702,7 @@ static ssize_t store_file(struct device *dev, struct device_attribute *attr, + /* The write permissions and store_xxx pointers are set in fsg_bind() */ + static DEVICE_ATTR(ro, 0444, show_ro, NULL); + static DEVICE_ATTR(file, 0444, show_file, NULL); ++static DEVICE_ATTR(switch, 0444, show_switch, NULL); + + + /*-------------------------------------------------------------------------*/ +@@ -3684,6 +3738,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) + if (curlun->registered) { + device_remove_file(&curlun->dev, &dev_attr_ro); + device_remove_file(&curlun->dev, &dev_attr_file); ++ device_remove_file(&curlun->dev, &dev_attr_switch); + device_unregister(&curlun->dev); + curlun->registered = 0; + } +@@ -3842,6 +3897,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) + + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; ++ curlun->switch_flag = 0; + curlun->ro = mod_data.ro[i]; + curlun->dev.release = lun_release; + curlun->dev.parent = &gadget->dev; +@@ -3857,7 +3913,9 @@ static int __init fsg_bind(struct usb_gadget *gadget) + if ((rc = device_create_file(&curlun->dev, + &dev_attr_ro)) != 0 || + (rc = device_create_file(&curlun->dev, +- &dev_attr_file)) != 0) { ++ &dev_attr_file)) != 0 || ++ (rc = device_create_file(&curlun->dev, ++ &dev_attr_switch)) != 0) { + device_unregister(&curlun->dev); + goto out; + } +diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h +index f7f159c..41b5c9a 100644 +--- a/drivers/usb/gadget/gadget_chips.h ++++ b/drivers/usb/gadget/gadget_chips.h +@@ -147,6 +147,11 @@ + #define gadget_is_m66592(g) 0 + #endif + ++#ifdef CONFIG_USB_GADGET_IUSBC ++#define gadget_is_iusbc(g) !strcmp("iusbc", (g)->name) ++#else ++#define gadget_is_iusbc(g) 0 ++#endif + + // CONFIG_USB_GADGET_SX2 + // CONFIG_USB_GADGET_AU1X00 +@@ -212,5 +217,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) + return 0x20; + else if (gadget_is_m66592(gadget)) + return 0x21; ++ else if (gadget_is_iusbc(gadget)) ++ return 0x99; + return -ENOENT; + } +diff --git a/drivers/usb/gadget/iusbc.c b/drivers/usb/gadget/iusbc.c +new file mode 100644 +index 0000000..6d7d2d6 +--- /dev/null ++++ b/drivers/usb/gadget/iusbc.c +@@ -0,0 +1,3120 @@ ++/* ++ * Intel Poulsbo USB Client Controller Driver ++ * Copyright (C) 2006-07, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++ ++ ++#define DEBUG /* messages on error and most fault paths */ ++//#define VERBOSE /* extra debug messages (success too) */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Power management */ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "iusbc.h" ++ ++#define DRIVER_DESC "Intel Poulsbo USB Client Controller Driver" ++#define DRIVER_VERSION "2.0.0.32L.0010" ++ ++#define DMA_ADDR_INVALID (~(dma_addr_t)0) ++ ++static const char driver_name [] = "iusbc"; ++static const char driver_desc [] = DRIVER_DESC; ++ ++static const char *const ep_name [] = { ++ "ep0-in", "ep0-out", ++ "ep1in-bulk", "ep1out-bulk", ++ "ep2in-int", "ep2out-int", ++ "ep3in-iso", "ep3out-iso", ++}; ++ ++ ++/* module parameter */ ++ ++/* force_fullspeed -- device will be forced to full speed operation ++ * default value: 0 for high speed ++ */ ++static int force_fullspeed = 0; ++ ++/* modprobe iusbc force_fullspeed=n" etc */ ++/* XXX: remove this feature due to HW full-speed bug ++ * module_param (force_fullspeed, bool, S_IRUGO); ++ */ ++ ++//#define RNDIS_INIT_HW_BUG ++//#define DMA_DISABLED ++ ++/*-------------------------------------------------------------------------*/ ++/* DEBUGGING */ ++#define xprintk(dev,level,fmt,args...) \ ++ printk(level "%s %s: " fmt , driver_name , \ ++ pci_name(dev->pdev) , ## args) ++ ++#ifdef DEBUG ++#undef DEBUG ++#define DEBUG(dev,fmt,args...) \ ++ xprintk(dev , KERN_DEBUG , fmt , ## args) ++#else ++#define DEBUG(dev,fmt,args...) \ ++ do { } while (0) ++#endif /* DEBUG */ ++ ++ ++#ifdef VERBOSE ++#define VDEBUG DEBUG ++#else ++#define VDEBUG(dev,fmt,args...) \ ++ do { } while (0) ++#endif /* VERBOSE */ ++ ++ ++#define ERROR(dev,fmt,args...) \ ++ xprintk(dev , KERN_ERR , fmt , ## args) ++#define WARN(dev,fmt,args...) \ ++ xprintk(dev , KERN_WARNING , fmt , ## args) ++#define INFO(dev,fmt,args...) \ ++ xprintk(dev , KERN_INFO , fmt , ## args) ++ ++ ++#ifdef VERBOSE ++static inline void print_all_registers(struct iusbc_regs *regs) ++{ ++ unsigned i, j; ++ /* device */ ++ printk(KERN_DEBUG "----Intel USB-C Memory Space Registers----\n"); ++ printk(KERN_DEBUG "Register Length: 0x%x\n", ++ sizeof(struct iusbc_regs)); ++ printk(KERN_DEBUG "gcap=0x%08x\n", readl(®s->gcap)); ++ printk(KERN_DEBUG "dev_sts=0x%08x\n", readl(®s->dev_sts)); ++ printk(KERN_DEBUG "frame=0x%04x\n", readw(®s->frame)); ++ printk(KERN_DEBUG "int_sts=0x%08x\n", readl(®s->int_sts)); ++ printk(KERN_DEBUG "int_ctrl=0x%08x\n", readl(®s->int_ctrl)); ++ printk(KERN_DEBUG "dev_ctrl=0x%08x\n", readl(®s->dev_ctrl)); ++ ++ /* endpoints */ ++ for (i = 0; i < 5; i++) { ++ printk(KERN_DEBUG "ep[%d]_base_low_32=0x%08x\n", ++ i, readl(®s->ep[i].ep_base_low_32)); ++ printk(KERN_DEBUG "ep[%d]_base_hi_32=0x%08x\n", ++ i, readl(®s->ep[i].ep_base_hi_32)); ++ printk(KERN_DEBUG "ep[%d]_len=0x%04x\n", ++ i, readw(®s->ep[i].ep_len)); ++ printk(KERN_DEBUG "ep[%d]_pib=0x%04x\n", ++ i, readw(®s->ep[i].ep_pib)); ++ printk(KERN_DEBUG "ep[%d]_dil=0x%04x\n", ++ i, readw(®s->ep[i].ep_dil)); ++ printk(KERN_DEBUG "ep[%d]_tiq=0x%04x\n", ++ i, readw(®s->ep[i].ep_tiq)); ++ printk(KERN_DEBUG "ep[%d]_max=0x%04x\n", ++ i, readw(®s->ep[i].ep_max)); ++ printk(KERN_DEBUG "ep[%d]_sts=0x%04x\n", ++ i, readw(®s->ep[i].ep_sts)); ++ printk(KERN_DEBUG "ep[%d]_cfg=0x%04x\n", ++ i, readw(®s->ep[i].ep_cfg)); ++ ++ if (1 == i) { /* ep0-out */ ++ printk(KERN_DEBUG "ep-out setup_pkt_sts=0x%02x\n", ++ readb(®s->ep[i].setup_pkt_sts)); ++ for (j = 0; j< 8; j++) { ++ printk(KERN_DEBUG "ep0-out " ++ "setup_pkt[%d]=0x%02x\n", ++ j, readb(®s->ep[i].setup_pkt[j])); ++ } ++ } ++ } ++} ++ ++#endif /* VERBOSE */ ++ ++/*-------------------------------------------------------------------------*/ ++ ++#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out") ++ ++ ++#if defined(CONFIG_USB_GADGET_DEBUG_FILES) || defined (DEBUG) ++static char *type_string(u8 bmAttributes) ++{ ++ switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { ++ case USB_ENDPOINT_XFER_BULK: ++ return "bulk"; ++ case USB_ENDPOINT_XFER_ISOC: ++ return "iso"; ++ case USB_ENDPOINT_XFER_INT: ++ return "int"; ++ }; ++ ++ return "control"; ++} ++#endif ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* configure endpoint, making it usable */ ++static int ++iusbc_ep_enable(struct usb_ep *_ep, ++ const struct usb_endpoint_descriptor *desc) ++{ ++ struct iusbc *dev; ++ struct iusbc_ep *ep; ++ u16 val_16, max; ++ u8 val_8; ++ unsigned long flags; ++ unsigned i; ++ int retval; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ DEBUG(ep->dev, "---> iusbc_ep_enable() \n"); ++ ++ if (!_ep || !desc || _ep->name == "ep0-in" ++ || _ep->name == "ep0-out" ++ || desc->bDescriptorType != USB_DT_ENDPOINT) ++ return -EINVAL; ++ ++ dev = ep->dev; ++ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) ++ return -ESHUTDOWN; ++ ++ /* wMaxPacketSize up to 1024 bytes */ ++ max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff; ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ ep->ep.maxpacket = max; ++ if (!ep->desc) ++ ep->desc = desc; ++ ++ /* ep_reset() has already been called */ ++ ep->stopped = 0; ++ ep->is_in = (USB_DIR_IN & desc->bEndpointAddress) != 0; ++ ++ /* sanity check type, direction, address */ ++ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { ++ case USB_ENDPOINT_XFER_BULK: ++ if ((dev->gadget.speed == USB_SPEED_HIGH ++ && max != 512) ++ || (dev->gadget.speed == USB_SPEED_FULL ++ && max > 64)) { ++ goto done; ++ } ++ break; ++ case USB_ENDPOINT_XFER_INT: ++ if (strstr (ep->ep.name, "-iso")) /* bulk is ok */ ++ goto done; ++ ++ switch (dev->gadget.speed) { ++ case USB_SPEED_HIGH: ++ if (max <= 1024) ++ break; ++ case USB_SPEED_FULL: ++ if (max <= 64) ++ break; ++ default: ++ if (max <= 8) ++ break; ++ goto done; ++ } ++ break; ++ case USB_ENDPOINT_XFER_ISOC: ++ if (strstr (ep->ep.name, "-bulk") ++ || strstr (ep->ep.name, "-int")) ++ goto done; ++ ++ switch (dev->gadget.speed) { ++ case USB_SPEED_HIGH: ++ if (max <= 1024) ++ break; ++ case USB_SPEED_FULL: ++ if (max <= 1023) ++ break; ++ default: ++ goto done; ++ } ++ break; ++ default: ++ goto done; ++ } ++ ++ /* ep_type */ ++ ep->ep_type = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); ++ ++ /* DMA modes, only support Linear Mode now */ ++ if (ep->dev->sg_mode_dma) { ++ ep->dma_mode = SCATTER_GATHER_MODE; ++ } else { ++ ep->dma_mode = LINEAR_MODE; ++ } ++ ++ /* reset ep registers to default value */ ++ i = ep->num; ++ writew(0, &dev->regs->ep[i].ep_cfg); ++ ++ /* set endpoints valid */ ++ val_16 = readw(&dev->regs->ep[i].ep_cfg); ++ val_16 |= INTR_BAD_PID_TYPE ++ | INTR_CRC_ERROR ++ | INTR_FIFO_ERROR ++ | INTR_DMA_ERROR ++ | INTR_TRANS_COMPLETE ++ /* | INTR_PING_NAK_SENT */ ++ | INTR_DMA_IOC ++ | ep->dma_mode << 6 ++ | ep->ep_type << 4 ++ /* | EP_ENABLE */ ++ | EP_VALID; ++ ++ /* will set EP_ENABLE later to start dma */ ++ writew(val_16, &dev->regs->ep[i].ep_cfg); ++ ++ val_16 = readw(&dev->regs->ep[i].ep_cfg); ++ VDEBUG(dev, "%s.ep_cfg = 0x%04x\n", _ep->name, val_16); ++ ++ val_8 = desc->bEndpointAddress; ++ DEBUG(dev, "enabled %s (ep%d%s-%s), max %04x, dma_mode: %02x\n", ++ _ep->name, ++ val_8 & USB_ENDPOINT_NUMBER_MASK, ++ DIR_STRING(val_8), ++ type_string(desc->bmAttributes), ++ max, ++ ep->dma_mode); ++ ++ retval = 0; ++done: ++ spin_unlock_irqrestore(&dev->lock, flags); ++ DEBUG(ep->dev, "<--- iusbc_ep_enable() \n"); ++ return retval; ++} ++ ++ ++static const struct usb_ep_ops iusbc_ep_ops; ++ ++static void ep_reset(struct iusbc_regs __iomem *regs, struct iusbc_ep *ep) ++{ ++ unsigned i = ep->num; ++ ++ /* reset ep values */ ++ ep->stopped = 1; ++ ep->ep.maxpacket = ~0; ++ ep->ep.ops = &iusbc_ep_ops; ++ ++ /* reset ep registers to default value ++ * clear all interrupt and status ++ * clear and reset all DMA FIFOs and state machine ++ * hardware shall minimize power usage ++ */ ++ writew(0, ®s->ep[i].ep_cfg); ++} ++ ++ ++static void nuke(struct iusbc_ep *); ++ ++/* endpoint is no longer usable */ ++static int ++iusbc_ep_disable(struct usb_ep *_ep) ++{ ++ struct iusbc_ep *ep; ++ unsigned long flags; ++ struct iusbc *dev; ++ unsigned i; ++ u16 val_16; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ VDEBUG(ep->dev, "---> iusbc_ep_disable() \n"); ++ ++ if (!_ep || !ep->desc ++ || _ep->name == "ep0-in" ++ || _ep->name == "ep0-out") ++ return -EINVAL; ++ ++ dev = ep->dev; ++ if (dev->ep0state == EP0_SUSPEND) ++ return -EBUSY; ++ ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ nuke(ep); ++ ep_reset(ep->dev->regs, ep); ++ ++ i = ep->num; ++ ++ /* display endpoint configuration register */ ++ val_16 = readw(&dev->regs->ep[i].ep_cfg); ++ VDEBUG(dev, "%s.ep_cfg = 0x%04x\n", _ep->name, val_16); ++ ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ ++ DEBUG(ep->dev, "disabled %s\n", _ep->name); ++ ++ VDEBUG(ep->dev, "<--- iusbc_ep_disable() \n"); ++ ++ return 0; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* allocate a request object to use with this endpoint */ ++static struct usb_request * ++iusbc_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) ++{ ++ struct iusbc_ep *ep; ++ struct iusbc_request *req; ++ struct iusbc_dma *td; ++ ++ if (!_ep) ++ return NULL; ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ VDEBUG(ep->dev, "---> iusbc_alloc_request() \n"); ++ ++ req = kzalloc(sizeof(*req), gfp_flags); ++ if (!req) ++ return NULL; ++ ++ req->req.dma = DMA_ADDR_INVALID; ++ INIT_LIST_HEAD(&req->queue); ++ ++ /* this dma descriptor may be swapped with the previous dummy */ ++ td = pci_pool_alloc(ep->dev->requests, ++ gfp_flags, ++ &req->td_dma); ++ ++ if (!td) { ++ kfree(req); ++ return NULL; ++ } ++ ++ td->dmacount = 0; /* not VALID */ ++ td->dmaaddr = __constant_cpu_to_le32(DMA_ADDR_INVALID); ++ ++ req->td = td; ++ ++ VDEBUG(ep->dev, "alloc request for %s\n", _ep->name); ++ ++ VDEBUG(ep->dev, "<--- iusbc_alloc_request() \n"); ++ ++ return &req->req; ++} ++ ++ ++/* frees a request object */ ++static void ++iusbc_free_request(struct usb_ep *_ep, struct usb_request *_req) ++{ ++ struct iusbc_ep *ep; ++ struct iusbc_request *req; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ VDEBUG(ep->dev, "---> iusbc_free_request() \n"); ++ ++ if (!_ep || !_req) ++ return; ++ ++ req = container_of(_req, struct iusbc_request, req); ++ ++ WARN_ON(!list_empty(&req->queue)); ++ ++ if (req->td) ++ pci_pool_free(ep->dev->requests, req->td, req->td_dma); ++ ++ kfree(req); ++ ++ VDEBUG(ep->dev, "free request for %s\n", _ep->name); ++ ++ VDEBUG(ep->dev, "<--- iusbc_free_request() \n"); ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* allocate an I/O buffer ++ * ++ * dma-coherent memory allocation ++ * ++ * NOTE: the dma_*_coherent() API calls suck. Most implementations are ++ * (a) page-oriented, so small buffers lose big; and (b) asymmetric with ++ * respect to calls with irqs disabled: alloc is safe, free is not. ++ * We currently work around (b), but not (a). ++ */ ++static void * ++iusbc_alloc_buffer( ++ struct usb_ep *_ep, ++ unsigned bytes, ++ dma_addr_t *dma, ++ gfp_t gfp_flags ++) ++{ ++ void *retval; ++ struct iusbc_ep *ep; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ VDEBUG(ep->dev, "---> iusbc_alloc_buffer() \n"); ++ ++ if (!_ep) ++ return NULL; ++ ++ *dma = DMA_ADDR_INVALID; ++ ++ retval = dma_alloc_coherent(&ep->dev->pdev->dev, ++ bytes, dma, gfp_flags); ++ ++ DEBUG(ep->dev, "alloc buffer for %s\n", _ep->name); ++ ++ VDEBUG(ep->dev, "<--- iusbc_alloc_buffer() \n"); ++ ++ return retval; ++} ++ ++ ++static DEFINE_SPINLOCK(buflock); ++static LIST_HEAD(buffers); ++ ++struct free_record { ++ struct list_head list; ++ struct device *dev; ++ unsigned bytes; ++ dma_addr_t dma; ++}; ++ ++ ++static void do_free(unsigned long ignored) ++{ ++#ifdef VERBOSE ++ printk(KERN_DEBUG "---> do_free() \n"); ++#endif ++ ++ spin_lock_irq(&buflock); ++ while (!list_empty(&buffers)) { ++ struct free_record *buf; ++ ++ buf = list_entry(buffers.next, struct free_record, list); ++ list_del(&buf->list); ++ spin_unlock_irq(&buflock); ++ ++ dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma); ++ ++ spin_lock_irq(&buflock); ++ } ++ spin_unlock_irq(&buflock); ++ ++#ifdef VERBOSE ++ printk(KERN_DEBUG "<--- do_free() \n"); ++#endif ++} ++ ++static DECLARE_TASKLET(deferred_free, do_free, 0); ++ ++/* free an I/O buffer */ ++static void ++iusbc_free_buffer( ++ struct usb_ep *_ep, ++ void *address, ++ dma_addr_t dma, ++ unsigned bytes ++) { ++ ++ /* free memory into the right allocator */ ++ if (dma != DMA_ADDR_INVALID) { ++ struct iusbc_ep *ep; ++ struct free_record *buf = address; ++ unsigned long flags; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ VDEBUG(ep->dev, "---> iusbc_free_buffer() \n"); ++ ++ if (!_ep) ++ return; ++ ++ buf->dev = &ep->dev->pdev->dev; ++ buf->bytes = bytes; ++ buf->dma = dma; ++ ++ spin_lock_irqsave(&buflock, flags); ++ list_add_tail(&buf->list, &buffers); ++ tasklet_schedule(&deferred_free); ++ spin_unlock_irqrestore(&buflock, flags); ++ ++ DEBUG(ep->dev, "free buffer for %s\n", _ep->name); ++ VDEBUG(ep->dev, "<--- iusbc_free_buffer() \n"); ++ ++ } else ++ kfree(address); ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* fill out dma descriptor to match a given request */ ++static void ++fill_dma(struct iusbc_ep *ep, struct iusbc_request *req) ++{ ++ struct iusbc_dma *td = req->td; ++ u16 dmacount; ++ ++ VDEBUG(ep->dev, "---> fill_dma() \n"); ++ ++ dmacount = req->req.length; ++ ++ td->dmaaddr = cpu_to_le32(req->req.dma); ++ td->dmacount = cpu_to_le16(dmacount); ++ ++ VDEBUG(ep->dev, "<--- fill_dma() \n"); ++} ++ ++ ++static void start_dma(struct iusbc_ep *ep, struct iusbc_request *req) ++{ ++ u16 val_16; ++ u32 val_32; ++ unsigned i; ++ ++ VDEBUG(ep->dev, "---> start_dma() \n"); ++ ++ i = ep->num; ++ ++ /* init req->td, pointing to the current dummy */ ++ fill_dma(ep, req); ++ ++ /* ep_base_low_32 */ ++ writel(cpu_to_le32(req->req.dma), ++ &ep->dev->regs->ep[i].ep_base_low_32); ++ val_32 = readl(&ep->dev->regs->ep[i].ep_base_low_32); ++ VDEBUG(ep->dev, "%s.ep_base_low_32=0x%08x\n", ++ ep->ep.name, val_32); ++ ++ /* ep_base_hi_32 */ ++ writel(0, &ep->dev->regs->ep[i].ep_base_hi_32); ++ val_32 = readl(&ep->dev->regs->ep[i].ep_base_hi_32); ++ VDEBUG(ep->dev, "%s.ep_base_hi_32=0x%08x\n", ++ ep->ep.name, val_32); ++ ++ writew(le16_to_cpu(req->td->dmacount), &ep->dev->regs->ep[i].ep_len); ++ val_16 = readw(&ep->dev->regs->ep[i].ep_len); ++ VDEBUG(ep->dev, "%s.ep_len=0x%04x\n", ++ ep->ep.name, val_16); ++ ++ /* endpoint maximum transaction size, up to 1024 Bytes */ ++ writew((ep->ep.maxpacket & 0x3ff), ++ &ep->dev->regs->ep[i].ep_max); ++ val_16 = readw(&ep->dev->regs->ep[i].ep_max); ++ VDEBUG(ep->dev, "%s.ep_max=0x%04x\n", ++ ep->ep.name, val_16); ++ ++ /* validate endpoint, enable DMA */ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ val_16 |= EP_VALID | EP_ENABLE; ++ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); ++ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ VDEBUG(ep->dev, "enable %s DMA transfer...\n", ++ ep->ep.name); ++ VDEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ++ ep->ep.name, val_16); ++ ++ VDEBUG(ep->dev, "<--- start_dma() \n"); ++} ++ ++ ++/* queues I/O requests in endpoint queue */ ++static inline void ++queue_dma(struct iusbc_ep *ep, struct iusbc_request *req) ++{ ++ struct iusbc_dma *end; ++ dma_addr_t tmp_dma_addr; ++ ++ VDEBUG(ep->dev, "---> queue_dma() \n"); ++ ++ /* swap new dummy for old, link; fill and maybe activate */ ++ end = ep->dummy; ++ ep->dummy = req->td; ++ req->td = end; ++ ++ tmp_dma_addr = ep->td_dma; ++ ep->td_dma = req->td_dma; ++ req->td_dma = tmp_dma_addr; ++ ++ fill_dma(ep, req); ++ ++ VDEBUG(ep->dev, "<--- queue_dma() \n"); ++} ++ ++ ++static void ++done(struct iusbc_ep *ep, struct iusbc_request *req, int status) ++{ ++ struct iusbc *dev; ++ unsigned stopped = ep->stopped; ++ ++ VDEBUG(ep->dev, "---> done() \n"); ++ ++ list_del_init(&req->queue); ++ ++ if (req->req.status == -EINPROGRESS) ++ req->req.status = status; ++ else ++ status = req->req.status; ++ ++ dev = ep->dev; ++ ++ if (req->mapped) { ++ pci_unmap_single(dev->pdev, req->req.dma, req->req.length, ++ ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); ++ req->req.dma = DMA_ADDR_INVALID; ++ req->mapped = 0; ++ } ++ ++ if (status != -ESHUTDOWN) ++ DEBUG(dev, "complete %s, req %p, stat %d, len %u/%u\n", ++ ep->ep.name, &req->req, status, ++ req->req.actual, req->req.length); ++ ++ /* don't modify queue heads during completion callback */ ++ ep->stopped = 1; ++ ++ /* XXX WORKAROUND: first ep0-out OUT packet HW BUG */ ++#ifdef RNDIS_INIT_HW_BUG ++ if (ep->num == 1) { ++ char *buf; ++ const u8 remote_ndis_initialize_msg[24] = { ++ 0x02, 0x00, 0x00, 0x00, ++ 0x18, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x00, 0x00 ++ }; ++ ++ buf = req->req.buf; ++ ++ /* req->buf haven't been DMAed for hardware bug? */ ++ if ((buf[0] == 0x09) && (buf[1] == 0x02)) { ++ memcpy(buf, remote_ndis_initialize_msg, 24); ++ DEBUG(ep->dev, "WORKAROUND HW BUG: ep0-out OUT\n"); ++ } ++ } ++#endif ++ /* XXX */ ++ ++ spin_unlock(&dev->lock); ++ req->req.complete(&ep->ep, &req->req); ++ spin_lock(&dev->lock); ++ ep->stopped = stopped; ++ ++ VDEBUG(ep->dev, "<--- done() \n"); ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* queues (submits) an I/O requests to an endpoint */ ++static int ++iusbc_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) ++{ ++ struct iusbc_request *req; ++ struct iusbc_ep *ep; ++ struct iusbc *dev; ++ unsigned long flags; ++ u16 val_16; ++ unsigned zlflag = 0; ++ ++ /* always require a cpu-view buffer */ ++ req = container_of(_req, struct iusbc_request, req); ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ dev = ep->dev; ++ VDEBUG(ep->dev, "---> iusbc_queue() \n"); ++ ++ if (dev->ep0state == EP0_DISCONNECT || ep->stopped) ++ return -EINVAL; ++ ++ if (!_req || !_req->complete || !_req->buf ++ || !list_empty(&req->queue)){ ++ VDEBUG(ep->dev, "_req=%p, complete=%p, buf=%p, list_empty=%d\n", ++ _req, _req->complete, ++ _req->buf, ++ list_empty(&req->queue)); ++ return -EINVAL; ++ } ++ ++ if (!_ep || (!ep->desc && ep->num > 1)){ ++ VDEBUG(ep->dev, "ep->desc=%p, ep->num=%d\n", ++ ep->desc, ep->num); ++ return -ESHUTDOWN; ++ } ++ ++ if (dev->ep0state == EP0_DISCONNECT) ++ return -ESHUTDOWN; ++ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) ++ return -ESHUTDOWN; ++ ++ /* can't touch registers when suspended */ ++ if (dev->ep0state == EP0_SUSPEND) ++ return -EBUSY; ++ ++ /* set up dma mapping in case the caller didn't */ ++ if (_req->dma == DMA_ADDR_INVALID) { ++ /* WORKAROUND: WARN_ON(size == 0) */ ++ if (_req->length == 0) { ++ VDEBUG(dev, "req->length: 0->1\n"); ++ zlflag = 1; ++ _req->length++; ++ } ++ ++ _req->dma = pci_map_single(dev->pdev, _req->buf, _req->length, ++ ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); ++ ++ if (zlflag && (_req->length == 1)) { ++ VDEBUG(dev, "req->length: 1->0\n"); ++ zlflag = 0; ++ _req->length = 0; ++ } ++ ++ req->mapped = 1; ++ } ++ ++ DEBUG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08x\n", ++ _ep->name, _req, _req->length, ++ _req->buf, _req->dma); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ ++ _req->status = -EINPROGRESS; ++ _req->actual = 0; ++ ++ /* set ZLP flag for ep0-in, when writting data, ++ * makes the last packet be "short" by adding a zero ++ * length packet as needed ++ */ ++ if (unlikely(ep->num == 0 && ep->is_in)) ++ _req->zero = 1; ++ ++ /* kickstart this I/O queue */ ++ if (list_empty(&ep->queue) && !ep->stopped) { ++ start_dma(ep, req); ++ ++ val_16 = readw(&ep->dev->regs->ep[ep->num].ep_pib); ++ VDEBUG(ep->dev, "after dma, %s.ep_pib = 0x%04x\n", ++ _ep->name, val_16); ++ ++ val_16 = readw(&ep->dev->regs->ep[ep->num].ep_sts); ++ VDEBUG(ep->dev, "after dma, %s.ep_sts = 0x%04x\n", ++ _ep->name, val_16); ++ } else { ++ queue_dma(ep, req); ++ VDEBUG(ep->dev, "%s queue_dma()\n", _ep->name); ++ } ++ ++ if (likely(req != 0)) { ++ list_add_tail(&req->queue, &ep->queue); ++ VDEBUG(ep->dev, "list_add_tail() \n"); ++ } ++ ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ VDEBUG(ep->dev, "<--- iusbc_queue() \n"); ++ ++ return 0; ++} ++ ++ ++static inline void ++dma_done(struct iusbc_ep *ep, struct iusbc_request *req, int status) ++{ ++ unsigned i; ++ VDEBUG(ep->dev, "---> dma_done() \n"); ++ ++ i = ep->num; ++ req->req.actual = readw(&ep->dev->regs->ep[i].ep_pib); ++ VDEBUG(ep->dev, "req->req.actual = %d\n", req->req.actual); ++ ++ done(ep, req, status); ++ ++ VDEBUG(ep->dev, "<--- dma_done() \n"); ++} ++ ++ ++/* restart dma in endpoint */ ++static void restart_dma(struct iusbc_ep *ep) ++{ ++ struct iusbc_request *req; ++ ++ VDEBUG(ep->dev, "---> restart_dma() \n"); ++ ++ if (ep->stopped) ++ return; ++ ++ req = list_entry(ep->queue.next, struct iusbc_request, queue); ++ start_dma(ep, req); ++ ++ VDEBUG(ep->dev, "<--- restart_dma() \n"); ++ ++ return; ++} ++ ++ ++/* dequeue ALL requests */ ++static void nuke(struct iusbc_ep *ep) ++{ ++ struct iusbc_request *req; ++ ++ VDEBUG(ep->dev, "---> nuke() \n"); ++ ++ /* called with spinlock held */ ++ ep->stopped = 1; ++ while (!list_empty(&ep->queue)) { ++ req = list_entry(ep->queue.next, ++ struct iusbc_request, ++ queue); ++ done(ep, req, -ESHUTDOWN); ++ } ++ ++ VDEBUG(ep->dev, "<--- nuke() \n"); ++} ++ ++ ++/* dequeues (cancels, unlinks) an I/O request from an endpoint */ ++static int ++iusbc_dequeue(struct usb_ep *_ep, struct usb_request *_req) ++{ ++ struct iusbc_ep *ep; ++ struct iusbc *dev; ++ struct iusbc_request *req; ++ unsigned long flags; ++ int stopped; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ VDEBUG(ep->dev, "---> iusbc_dequeue() \n"); ++ ++ if (!_ep || (!ep->desc && ep->num > 1) || !_req) ++ return -EINVAL; ++ ++ dev = ep->dev; ++ ++ if (!dev->driver) ++ return -ESHUTDOWN; ++ ++ /* can't touch registers when suspended */ ++ if (dev->ep0state == EP0_SUSPEND) ++ return -EBUSY; ++ ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ stopped = ep->stopped; ++ ++ /* quiesce dma while we patch the queue */ ++ ep->stopped = 1; ++ ++ /* make sure it's still queued on this endpoint */ ++ list_for_each_entry(req, &ep->queue, queue) { ++ if (&req->req == _req) ++ break; ++ } ++ ++ if (&req->req != _req) { ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ return -EINVAL; ++ } ++ ++ /* queue head may be partially complete. */ ++ if (ep->queue.next == &req->queue) { ++ DEBUG(ep->dev, "unlink (%s) dma\n", _ep->name); ++ _req->status = -ECONNRESET; ++ if (likely(ep->queue.next == &req->queue)) { ++ req->td->dmacount = 0; /* invalidate */ ++ dma_done(ep, req, -ECONNRESET); ++ } ++ req = NULL; ++ } ++ ++ if (req) ++ done(ep, req, -ECONNRESET); ++ ++ ep->stopped = stopped; ++ ++ if (!list_empty(&ep->queue) && (!ep->stopped)) { ++ /* resume current request, or start new one */ ++ if (!req) ++ start_dma(ep, list_entry(ep->queue.next, ++ struct iusbc_request, queue)); ++ } ++ ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ ++ VDEBUG(ep->dev, "<--- iusbc_dequeue() \n"); ++ ++ return 0; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void ep0_start(struct iusbc *dev); ++static void ep_ack(struct iusbc_ep *ep); ++static int iusbc_ep_enable(struct usb_ep *_ep, ++ const struct usb_endpoint_descriptor *desc); ++ ++static void clear_halt(struct iusbc_ep *ep) ++{ ++ u16 val_16; ++ unsigned i = ep->num; ++ int rc = 0; ++ struct iusbc_request *req; ++ const struct usb_endpoint_descriptor *desc; ++ ++ DEBUG(ep->dev, "---> clear_halt() \n"); ++ ++ /* validate and enable endpoint */ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ val_16 |= EP_VALID | EP_ENABLE; ++ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); ++ ++ /* re-enable endpoint */ ++ if (i < 2) { /* ep0-in and ep0-out */ ++ ep0_start(ep->dev); ++ } else { ++ spin_unlock_irq(&ep->dev->lock); ++ /* remember ep->desc */ ++ desc = ep->desc; ++ rc = iusbc_ep_enable(&ep->ep, desc); ++ if (rc) { ++ DEBUG(ep->dev, "re-enable error: %d\n", rc); ++ } ++ spin_lock_irq(&ep->dev->lock); ++ } ++ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ DEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); ++ ++ ep->stopped = 0; ++ if (list_empty(&ep->queue)) ++ return; ++ ++ req = list_entry(ep->queue.next, struct iusbc_request,queue); ++ start_dma(ep, req); ++ ++ DEBUG(ep->dev, "<--- clear_halt() \n"); ++} ++ ++ ++static void set_halt(struct iusbc_ep *ep) ++{ ++ u16 val_16; ++ unsigned i = ep->num; ++ ++ DEBUG(ep->dev, "---> set_halt() \n"); ++ ++ /* reset data buffer zero length */ ++ writew(0, &ep->dev->regs->ep[i].ep_len); ++ ++ /* invalidate and disable endpoint */ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ val_16 &= (~EP_VALID & ~EP_ENABLE); ++ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); ++ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ DEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); ++ ++ ep->stopped = 1; ++ ++ DEBUG(ep->dev, "<--- set_halt() \n"); ++} ++ ++ ++static int iusbc_fifo_status(struct usb_ep *_ep); ++ ++/* sets the endpoint halt feature */ ++static int ++iusbc_set_halt(struct usb_ep *_ep, int value) ++{ ++ struct iusbc_ep *ep; ++ unsigned long flags; ++ int retval = 0; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ DEBUG(ep->dev, "---> iusbc_set_halt() \n"); ++ ++ if (!_ep || (!ep->desc && ep->num > 1)) ++ return -EINVAL; ++ ++ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) ++ return -ESHUTDOWN; ++ ++ if (ep->desc && (ep->desc->bmAttributes & 0x03) ++ == USB_ENDPOINT_XFER_ISOC) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ ++ /* transfer requests are still queued */ ++ if (!list_empty(&ep->queue)) ++ retval = -EAGAIN; ++ ++ else if (ep->is_in && value && iusbc_fifo_status(_ep) != 0) { ++ /* FIFO holds bytes, the host hasn't collected */ ++ DEBUG(ep->dev, "%s FIFO holds bytes\n", _ep->name); ++ ++ /* reset position in buffer register */ ++ writew(0, &ep->dev->regs->ep[ep->num].ep_pib); ++ ++ retval = -EAGAIN; ++ } else { ++ DEBUG(ep->dev, "%s %s halt\n", _ep->name, ++ value ? "set" : "clear"); ++ /* set/clear, then synch memory views with the device */ ++ if (value) { ++ if (ep->num < 2) { /* ep0-in/out */ ++ ep->dev->ep0state = EP0_STALL; ++ VDEBUG(ep->dev, "ep0state: EP0_STALL\n"); ++ } else { ++ set_halt(ep); ++ ep_ack(&ep->dev->ep[0]); ++ } ++ } else { ++ clear_halt(ep); ++ ep_ack(&ep->dev->ep[0]); ++ } ++ ++ } ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ ++ DEBUG(ep->dev, "<--- iusbc_set_halt() \n"); ++ ++ return retval; ++} ++ ++ ++/* return number of bytes in fifo, or error */ ++static int ++iusbc_fifo_status(struct usb_ep *_ep) ++{ ++ struct iusbc_ep *ep; ++ unsigned i; ++ u16 nbytes, fifo_size; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ DEBUG(ep->dev, "---> iusbc_fifo_status() \n"); ++ ++ if (!_ep || (!ep->desc && ep->num > 1)) ++ return -ENODEV; ++ ++ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) ++ return -ESHUTDOWN; ++ ++ i = ep->num; ++ fifo_size = readw(&ep->dev->regs->ep[i].ep_len); ++ nbytes = readw(&ep->dev->regs->ep[i].ep_pib); ++ ++ if (nbytes > fifo_size) ++ return -EOVERFLOW; ++ ++ DEBUG(ep->dev, "%s, 0x%04x bytes (%s) in FIFO\n", ++ _ep->name, nbytes, ep->is_in? "IN" : "OUT"); ++ ++ DEBUG(ep->dev, "<--- iusbc_fifo_status() \n"); ++ ++ return nbytes; ++} ++ ++ ++static void ep_nak(struct iusbc_ep *ep); ++ ++/* flushes contents of a fifo */ ++static void ++iusbc_fifo_flush(struct usb_ep *_ep) ++{ ++ struct iusbc_ep *ep; ++ unsigned i; ++ u16 val_16; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ DEBUG(ep->dev, "---> iusbc_fifo_flush() \n"); ++ ++ if (!_ep || (!ep->desc && ep->num > 1)){ ++ return; ++ } ++ ++ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) ++ return; ++ ++ i = ep->num; ++ ++ /* FIXME: remove it ? */ ++ ep_nak(ep); ++ ++ /* reset position in buffer register */ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_pib); ++ DEBUG(ep->dev, "%s.ep_pib = 0x%04x\n", _ep->name, val_16); ++ writew(0, &ep->dev->regs->ep[i].ep_pib); ++ ++ DEBUG(ep->dev, "<--- iusbc_fifo_flush() \n"); ++} ++ ++static const struct usb_ep_ops iusbc_ep_ops = { ++ ++ /* configure endpoint, making it usable */ ++ .enable = iusbc_ep_enable, ++ ++ /* endpoint is no longer usable */ ++ .disable = iusbc_ep_disable, ++ ++ /* allocate a request object to use with this endpoint */ ++ .alloc_request = iusbc_alloc_request, ++ ++ /* frees a request object */ ++ .free_request = iusbc_free_request, ++ ++ /* allocate an I/O buffer */ ++ /*.alloc_buffer = iusbc_alloc_buffer,*/ ++ ++ /* free an I/O buffer */ ++ /*.free_buffer = iusbc_free_buffer,*/ ++ ++ /* queues (submits) an I/O requests to an endpoint */ ++ .queue = iusbc_queue, ++ ++ /* dequeues (cancels, unlinks) an I/O request from an endpoint */ ++ .dequeue = iusbc_dequeue, ++ ++ /* sets the endpoint halt feature */ ++ .set_halt = iusbc_set_halt, ++ ++ /* return number of bytes in fifo, or error */ ++ .fifo_status = iusbc_fifo_status, ++ ++ /* flushes contents of a fifo */ ++ .fifo_flush = iusbc_fifo_flush, ++}; ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* returns the current frame number */ ++static int iusbc_get_frame(struct usb_gadget *_gadget) ++{ ++ struct iusbc *dev; ++ unsigned long flags; ++ u16 retval; ++ ++ if (!_gadget) ++ return -ENODEV; ++ ++ dev = container_of(_gadget, struct iusbc, gadget); ++ ++ VDEBUG(dev, "---> iusbc_get_frame() \n"); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ retval = readw(&dev->regs->frame); ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ VDEBUG(dev, "<--- iusbc_get_frame() \n"); ++ ++ return retval; ++} ++ ++ ++/* TODO: wakeup host function */ ++/* tries to wake up the host connected to this gadget */ ++static int iusbc_wakeup(struct usb_gadget *_gadget) ++{ ++ struct iusbc *dev; ++ ++ if (!_gadget) ++ return 0; ++ ++ dev = container_of(_gadget, struct iusbc, gadget); ++ ++ VDEBUG(dev, "---> iusbc_wakeup() \n"); ++ ++ /* TODO: spec 4.3 */ ++ ++ VDEBUG(dev, "<--- iusbc_wakeup() \n"); ++ ++ return 0; ++} ++ ++ ++/* software-controlled connect/disconnect to USB host */ ++static int iusbc_pullup(struct usb_gadget *_gadget, int is_on) ++{ ++ struct iusbc *dev; ++ u32 val_32; ++ unsigned long flags; ++ ++ if (!_gadget) ++ return -ENODEV; ++ dev = container_of(_gadget, struct iusbc, gadget); ++ ++ VDEBUG(dev, "---> iusbc_pullup() \n"); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ val_32 = readl(&dev->regs->dev_ctrl); ++ dev->connected = (is_on != 0); ++ if (is_on) ++ val_32 |= CONNECTION_ENABLE; ++ else ++ val_32 &= ~CONNECTION_ENABLE; ++ ++ writel(val_32, &dev->regs->dev_ctrl); ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ VDEBUG(dev, "<--- iusbc_pullup() \n"); ++ ++ return 0; ++} ++ ++ ++static const struct usb_gadget_ops iusbc_ops = { ++ ++ /* returns the current frame number */ ++ .get_frame = iusbc_get_frame, ++ ++ /* TODO */ ++ /* tries to wake up the host connected to this gadget */ ++ .wakeup = iusbc_wakeup, ++ ++ /* software-controlled connect/disconnect to USB host */ ++ .pullup = iusbc_pullup, ++}; ++ ++/*-------------------------------------------------------------------------*/ ++ ++#ifdef CONFIG_USB_GADGET_DEBUG_FILES ++ ++/* "function" sysfs attribute */ ++static ssize_t ++show_function(struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ struct iusbc *dev = dev_get_drvdata(_dev); ++ ++ if (!dev->driver ++ || !dev->driver->function ++ || strlen(dev->driver->function) > PAGE_SIZE) ++ return 0; ++ ++ return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function); ++} ++static DEVICE_ATTR(function, S_IRUGO, show_function, NULL); ++ ++ ++static ssize_t ++show_registers(struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ struct iusbc *dev; ++ char *next; ++ unsigned size; ++ unsigned t; ++ unsigned i; ++ unsigned long flags; ++ const char *name; ++ const char *speed; ++ volatile u32 dev_sts; ++ ++ dev = dev_get_drvdata(_dev); ++ next = buf; ++ size = PAGE_SIZE; ++ spin_lock_irqsave(&dev->lock, flags); ++ ++ if (dev->driver) ++ name = dev->driver->driver.name; ++ else ++ name = "(none)"; ++ ++ dev_sts = readl(&dev->regs->dev_sts); ++ if ((dev->gadget.speed == USB_SPEED_HIGH) && (dev_sts & CONNECTED)) ++ speed = "high speed"; ++ else if ((dev->gadget.speed == USB_SPEED_FULL) && (dev_sts & CONNECTED)) ++ speed = "full speed"; ++ else ++ speed = "unknown speed"; ++ ++ /* device information */ ++ t = scnprintf(next, size, ++ "%s %s - %s\n" ++ "Version: %s\n" ++ "Gadget driver: %s\n" ++ "Speed mode: %s\n", ++ driver_name, pci_name(dev->pdev), driver_desc, ++ DRIVER_VERSION, ++ name, ++ speed); ++ size -= t; ++ next += t; ++ ++ /* device memory space registers */ ++ t = scnprintf(next, size, ++ "\nDevice registers:\n" ++ "\tgcap=0x%08x\n" ++ "\tdev_sts=0x%08x\n" ++ "\tframe=0x%04x\n" ++ "\tint_sts=0x%08x\n" ++ "\tint_ctrl=0x%08x\n" ++ "\tdev_ctrl=0x%08x\n", ++ readl(&dev->regs->gcap), ++ readl(&dev->regs->dev_sts), ++ readw(&dev->regs->frame), ++ readl(&dev->regs->int_sts), ++ readl(&dev->regs->int_ctrl), ++ readl(&dev->regs->dev_ctrl) ++ ); ++ size -= t; ++ next += t; ++ ++ /* endpoints memory space registers */ ++ t = scnprintf(next, size, "\nEndpoints registers:\n"); ++ size -= t; ++ next += t; ++ ++ for (i = 0; i < 5; i++) { ++ struct iusbc_ep *ep; ++ ep = &dev->ep[i]; ++ ++ if (i > 1 && !ep->desc) ++ continue; ++ ++ name = ep->ep.name; ++ t = scnprintf(next, size, ++ "\t%s.ep_base_low_32=0x%08x\n" ++ "\t%s.ep_base_hi_32=0x%08x\n" ++ "\t%s.ep_len=0x%04x\n" ++ "\t%s.ep_pib=0x%04x\n" ++ "\t%s.ep_dil=0x%04x\n" ++ "\t%s.ep_tiq=0x%04x\n" ++ "\t%s.ep_max=0x%04x\n" ++ "\t%s.ep_sts=0x%04x\n" ++ "\t%s.ep_cfg=0x%04x\n", ++ name, readl(&dev->regs->ep[i].ep_base_low_32), ++ name, readl(&dev->regs->ep[i].ep_base_hi_32), ++ name, readw(&dev->regs->ep[i].ep_len), ++ name, readw(&dev->regs->ep[i].ep_pib), ++ name, readw(&dev->regs->ep[i].ep_dil), ++ name, readw(&dev->regs->ep[i].ep_tiq), ++ name, readw(&dev->regs->ep[i].ep_max), ++ name, readw(&dev->regs->ep[i].ep_sts), ++ name, readw(&dev->regs->ep[i].ep_cfg) ++ ); ++ size -= t; ++ next += t; ++ } ++ ++ /* ep0-out setup packet registers */ ++ t = scnprintf(next, size, ++ "\tsetup_pkt_sts=0x%02x\n", ++ readb(&dev->regs->ep[1].setup_pkt_sts) ++ ); ++ size -= t; ++ next += t; ++ ++ for (i = 0; i < 8; i++) { ++ t = scnprintf(next, size, ++ "\tsetup_pkt[%d]=0x%02x\n", ++ i, ++ readb(&dev->regs->ep[1].setup_pkt[i]) ++ ); ++ size -= t; ++ next += t; ++ } ++ ++ /* Irq statistics */ ++ t = scnprintf(next, size, "\nIrq statistics:\n"); ++ size -= t; ++ next += t; ++ ++ for (i = 0; i < 5; i++) { ++ struct iusbc_ep *ep; ++ ep = &dev->ep[i]; ++ ++ if (i && !ep->irqs) ++ continue; ++ ++ t = scnprintf(next, size, ++ "\t%s/%lu\n", ++ ep->ep.name, ep->irqs); ++ size -= t; ++ next += t; ++ } ++ ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ return PAGE_SIZE - size; ++} ++static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); ++ ++ ++static ssize_t ++show_queues(struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ struct iusbc *dev; ++ char *next; ++ unsigned size, i; ++ unsigned long flags; ++ ++ dev = dev_get_drvdata(_dev); ++ next = buf; ++ size = PAGE_SIZE; ++ spin_lock_irqsave(&dev->lock, flags); ++ ++ for (i = 0; i < 5; i++) { ++ struct iusbc_ep *ep = &dev->ep[i]; ++ struct iusbc_request *req; ++ struct iusbc_dma *td; ++ int t; ++ int addr; ++ ++ if (i > 1 && !ep->desc) ++ continue; ++ ++ /* ep0-in, ep0-out */ ++ if (i == 0 || i == 1) { ++ t = scnprintf(next, size, ++ "%s (ep%d%s-%s), " ++ "max %04x, dma_mode: %02x\n", ++ ep->ep.name, ++ 0, ++ ep->is_in ? "in" : "out", ++ "control", ++ ep->ep.maxpacket, ++ ep->dma_mode); ++ } else { ++ addr = ep->desc->bEndpointAddress; ++ t = scnprintf(next, size, ++ "\n%s (ep%d%s-%s), " ++ "max %04x, dma_mode: %02x\n", ++ ep->ep.name, ++ addr & USB_ENDPOINT_NUMBER_MASK, ++ DIR_STRING(addr), ++ type_string(ep->desc->bmAttributes), ++ ep->ep.maxpacket, ++ ep->dma_mode); ++ } ++ ++ if (t <= 0 || t > size) ++ goto done; ++ ++ size -= t; ++ next += t; ++ ++ if (list_empty(&ep->queue)) { ++ t = scnprintf(next, size, "\t(nothing queued)\n"); ++ if (t <= 0 || t > size) ++ goto done; ++ ++ size -= t; ++ next += t; ++ continue; ++ } ++ ++ list_for_each_entry(req, &ep->queue, queue) { ++ t = scnprintf(next, size, ++ "\treq %p, len %u/%u, " ++ "buf %p, dma 0x%08x)\n", ++ &req->req, req->req.actual, ++ req->req.length, req->req.buf, ++ req->req.dma); ++ ++ if (t <= 0 || t > size) ++ goto done; ++ ++ size -= t; ++ next += t; ++ ++ td = req->td; ++ t = scnprintf(next, size, "\ttd 0x%08x, " ++ " count 0x%08x, buf 0x%08x\n", ++ (u32) req->td_dma, ++ le32_to_cpu(td->dmacount), ++ le32_to_cpu(td->dmaaddr)); ++ ++ if (t <= 0 || t > size) ++ goto done; ++ ++ size -= t; ++ next += t; ++ } ++ } ++ ++done: ++ spin_unlock_irqrestore(&dev->lock, flags); ++ return PAGE_SIZE - size; ++} ++static DEVICE_ATTR(queues, S_IRUGO, show_queues, NULL); ++ ++#else ++ ++#define device_create_file(a,b) (0) ++#define device_remove_file(a,b) do { } while (0) ++ ++#endif /*CONFIG_USB_GADGET_DEBUG_FILES */ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* global variable */ ++static struct iusbc *the_controller; ++ ++static void iusbc_reset(struct iusbc *dev) ++{ ++ DEBUG(dev, "---> iusbc_reset() \n"); ++ ++ /* disable irqs */ ++ writel(0, &dev->regs->int_ctrl); ++ ++ /* set device power stauts */ ++ dev->powered = 1; ++ ++ /* set device remote wakeup flag */ ++ dev->enable_wakeup = 0; ++ ++ /* 16 bits status data for GET_STATUS */ ++ dev->status_d = 0; ++ ++ DEBUG(dev, "<--- iusbc_reset() \n"); ++} ++ ++ ++static void iusbc_reinit(struct iusbc *dev) ++{ ++ unsigned i; ++ ++ DEBUG(dev, "---> iusbc_reinit() \n"); ++ ++ INIT_LIST_HEAD(&dev->gadget.ep_list); ++ ++ /* ep0-in */ ++ dev->gadget.ep0 = &dev->ep[0].ep; ++ ++ /* init ep0-in and ep0-out driver_data */ ++ dev->ep[0].ep.driver_data = get_gadget_data(&dev->gadget); ++ dev->ep[1].ep.driver_data = get_gadget_data(&dev->gadget); ++ ++ dev->ep0state = EP0_DISCONNECT; ++ VDEBUG(dev, "ep0state: EP0_DISCONNECT\n"); ++ ++ /* basic endpoint init */ ++ /* 2 ep0, 3 data ep */ ++ for (i = 0; i < 5; i++) { ++ struct iusbc_ep *ep = &dev->ep[i]; ++ ep->dev = dev; ++ ++ INIT_LIST_HEAD(&ep->queue); ++ ++ ep->desc = NULL; ++ ep->num = i; ++ ep->stopped = 1; ++ ep->ep.name = ep_name[i]; ++ ep->ep.maxpacket = ~0; ++ ep->ep.ops = &iusbc_ep_ops; ++ ++ list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); ++ ep_reset(dev->regs, ep); ++ } ++ ++ /* set ep0 maxpacket */ ++ dev->ep[0].ep.maxpacket = 64; /* ep0_in */ ++ dev->ep[1].ep.maxpacket = 64; /* ep0_out */ ++ ++ dev->ep[0].stopped = 0; ++ dev->ep[1].stopped = 0; ++ ++ list_del_init(&dev->ep[0].ep.ep_list); ++ list_del_init(&dev->ep[1].ep.ep_list); ++ ++ DEBUG(dev, "<--- iusbc_reinit() \n"); ++} ++ ++ ++static void ep0_start(struct iusbc *dev) ++{ ++ u16 val_16; ++ u32 val_32; ++ unsigned i; ++ ++ DEBUG(dev, "---> ep0_start() \n"); ++ ++ iusbc_reset(dev); ++ iusbc_reinit(dev); ++ ++ for (i = 0; i < 2; i++) { ++ struct iusbc_ep *ep = &dev->ep[i]; ++ ++ /* ep[0]: ep0-in, ep[1]: ep0-out */ ++ ep->is_in = (i == 0 ? 1 : 0); ++ ++ /* ep0 ep_type */ ++ ep->ep_type = USB_ENDPOINT_XFER_CONTROL; ++ ++ /* linear mode only, control mode is useless */ ++ ep->dma_mode = LINEAR_MODE; ++ ++ /* reset ep0-in/out registers to default value */ ++ writew(0, &dev->regs->ep[i].ep_cfg); ++ ++ /* set ep0-in/out endpoints valid */ ++ val_16 = readw(&dev->regs->ep[i].ep_cfg); ++ val_16 |= INTR_BAD_PID_TYPE ++ | INTR_CRC_ERROR ++ | INTR_FIFO_ERROR ++ | INTR_DMA_ERROR ++ | INTR_TRANS_COMPLETE ++ /* | INTR_PING_NAK_SENT */ ++ | INTR_DMA_IOC ++ | ep->dma_mode << 6 ++ | ep->ep_type << 4 ++ /* | EP_ENABLE */ ++ | EP_VALID; ++ ++ writew(val_16, &dev->regs->ep[i].ep_cfg); ++ ++ val_16 = readw(&dev->regs->ep[i].ep_cfg); ++ DEBUG(dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); ++ ++ DEBUG(dev, "enabled %s (ep0-%s), max %d, dma_mode: %02x\n", ++ ep->ep.name, ++ ep->is_in ? "in" : "out", ++ ep->ep.maxpacket, ep->dma_mode); ++ } ++ ++ /* enable irqs */ ++ val_32 = readl(&dev->regs->int_ctrl); ++ val_32 |= RESET_INTR_ENABLE ++ | CONNECT_INTR_ENABLE ++ | SUSPEND_INTR_ENABLE ++ /* | EP3_OUT_INTR_ENABLE */ ++ /* | EP3_IN_INTR_ENABLE */ ++ /* | EP2_OUT_INTR_ENABLE */ ++ | EP2_IN_INTR_ENABLE ++ | EP1_OUT_INTR_ENABLE ++ | EP1_IN_INTR_ENABLE ++ | EP0_OUT_INTR_ENABLE ++ | EP0_IN_INTR_ENABLE; ++ ++ writel(val_32, &dev->regs->int_ctrl); ++ val_32 = readl(&dev->regs->int_ctrl); ++ DEBUG(dev, "ep0_start: enable irqs, int_ctrl = 0x%08x\n", ++ val_32); ++ ++ dev->ep0state = EP0_IDLE; ++ VDEBUG(dev, "ep0state: EP0_IDLE\n"); ++ ++ DEBUG(dev, "<--- ep0_start() \n"); ++} ++ ++ ++static void iusbc_do_tasklet(unsigned long arg); ++ ++static void device_start(struct iusbc *dev) ++{ ++ u32 val_32; ++ ++ DEBUG(dev, "---> device_start() \n"); ++ ++ /* reset all registers */ ++ writel(0, &dev->regs->dev_ctrl); ++ ++ /* PCI enable: write 1 to DeviceEnable */ ++ writel(DEVICE_ENABLE, &dev->regs->dev_ctrl); ++ /* FIXME: 5 ms is not enough? */ ++ mdelay(5); ++ val_32 = readl(&dev->regs->dev_ctrl); ++ if (!(val_32 & DEVICE_ENABLE)) ++ ERROR(dev, "hardware reset error\n"); ++ ++ /* hardware transfer to running state now */ ++ val_32 |= DEVICE_ENABLE ++ /* | CONNECTION_ENABLE */ ++ | SIGNAL_RESUME ++ | CHARGE_ENABLE; ++ ++ /* module parameter: force_fullspeed */ ++ if (force_fullspeed) { ++ val_32 |= FORCE_FULLSPEED; ++ dev->force_fullspeed = 1; ++ } else { ++ /* disable DMAs in high speed mode */ ++#ifdef DMA_DISABLED ++ val_32 |= DMA1_DISABLED ++ | DMA2_DISABLED ++ | DMA3_DISABLED; ++#endif ++ dev->force_fullspeed = 0; ++ } ++ ++ writel(val_32, &dev->regs->dev_ctrl); ++ val_32 = readl(&dev->regs->dev_ctrl); ++ DEBUG(dev, "dev_ctrl = 0x%08x\n", val_32); ++ ++ /* check device status */ ++ val_32 = readl(&dev->regs->dev_sts); ++ DEBUG(dev, "device_start: dev_sts = 0x%08x\n", val_32); ++ ++ if (val_32 & CONNECTED) { ++ dev->connected = 1; ++ VDEBUG(dev, "device_start: USB attached\n"); ++ } else { ++ dev->connected = 0; ++ VDEBUG(dev, "device_start: USB detached\n"); ++ } ++ ++ if (val_32 & SUSPEND) ++ dev->suspended = 1; ++ else ++ dev->suspended = 0; ++ ++ /* set device reset flag */ ++ dev->is_reset = 0; ++ ++ iusbc_pullup(&dev->gadget, 1); ++ ++ /* init irq tasklet */ ++ tasklet_init(&dev->iusbc_tasklet, ++ iusbc_do_tasklet, (unsigned long) dev); ++ ++ /* enable ep0 and host detection */ ++ ep0_start(dev); ++ ++ DEBUG(dev, "<--- device_start() \n"); ++} ++ ++ ++/* when a driver is successfully registered, it will receive ++ * control requests including set_configuration(), which enables ++ * non-control requests. then usb traffic follows until a ++ * disconnect is reported. then a host may connect again, or ++ * the driver might get unbound. ++ */ ++int usb_gadget_register_driver(struct usb_gadget_driver *driver) ++{ ++ struct iusbc *dev = the_controller; ++ int retval; ++ unsigned i; ++ ++ if (!driver || !driver->bind || !driver->disconnect || !driver->setup) ++ return -EINVAL; ++ ++ if (!dev) ++ return -ENODEV; ++ ++ DEBUG(dev, "---> usb_gadget_register_driver() \n"); ++ ++ if (dev->driver) ++ return -EBUSY; ++ ++ dev->irqs = 0; ++ ++ /* 2 ep0, 3 data eps */ ++ for (i = 0; i < 5; i++) ++ dev->ep[i].irqs = 0; ++ ++ /* hook up the driver ... */ ++ driver->driver.bus = NULL; ++ dev->driver = driver; ++ dev->gadget.dev.driver = &driver->driver; ++ ++ retval = driver->bind(&dev->gadget); ++ if (retval) { ++ DEBUG(dev, "bind to driver %s --> %d\n", ++ driver->driver.name, retval); ++ dev->driver = NULL; ++ dev->gadget.dev.driver = NULL; ++ return retval; ++ } ++ ++ retval = device_create_file(&dev->pdev->dev, &dev_attr_function); ++ if (retval) ++ goto err_unbind; ++ ++ retval = device_create_file(&dev->pdev->dev, &dev_attr_queues); ++ if (retval) ++ goto err_func; ++ ++ device_start(dev); ++ ++ INFO(dev, "register driver: %s\n", driver->driver.name); ++ DEBUG(dev, "<--- usb_gadget_register_driver() \n"); ++ ++ return 0; ++ ++err_func: ++ device_remove_file(&dev->pdev->dev, &dev_attr_function); ++ ++err_unbind: ++ driver->unbind(&dev->gadget); ++ dev->gadget.dev.driver = NULL; ++ dev->driver = NULL; ++ ++ DEBUG(dev, "<--- usb_gadget_register_driver() \n"); ++ ++ return retval; ++} ++EXPORT_SYMBOL(usb_gadget_register_driver); ++ ++ ++static void ++stop_activity(struct iusbc *dev, struct usb_gadget_driver *driver) ++{ ++ unsigned i; ++ ++ DEBUG(dev, "---> stop_activity() \n"); ++ ++ /* don't disconnect if it's not connected */ ++ if (dev->gadget.speed == USB_SPEED_UNKNOWN) ++ driver = NULL; ++ ++ /* stop hardware; prevent new request submissions; ++ * and kill any outstanding requests. ++ */ ++ iusbc_reset(dev); ++ ++ /* we need to mark ep0state to disconnect to avoid upper layer to start ++ * next transfer immediately after the following nuke operation, the ++ * iusbc_queue function need to check ep0state before issue a transfer ++ */ ++ dev->ep0state = EP0_DISCONNECT; ++ ++ /* 2 ep0, 3 data ep */ ++ for (i = 0; i < 5; i++) ++ nuke(&dev->ep[i]); ++ ++ /* report disconnect; the driver is already quiesced */ ++ if (driver) { ++ spin_unlock(&dev->lock); ++ driver->disconnect(&dev->gadget); ++ spin_lock(&dev->lock); ++ } ++ ++ iusbc_reinit(dev); ++ ++ DEBUG(dev, "<--- stop_activity() \n"); ++} ++ ++ ++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ++{ ++ struct iusbc *dev = the_controller; ++ unsigned long flags; ++ ++ DEBUG(dev, "---> usb_gadget_unregister_driver() \n"); ++ ++ if (!dev) ++ return -ENODEV; ++ if (!driver || driver != dev->driver || !driver->unbind) ++ return -EINVAL; ++ ++ /* kill irq tasklet */ ++ tasklet_kill(&dev->iusbc_tasklet); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ stop_activity(dev, driver); ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ iusbc_pullup(&dev->gadget, 0); ++ ++ driver->unbind(&dev->gadget); ++ dev->gadget.dev.driver = NULL; ++ dev->driver = NULL; ++ ++ device_remove_file(&dev->pdev->dev, &dev_attr_function); ++ device_remove_file(&dev->pdev->dev, &dev_attr_queues); ++ ++ INFO(dev, "unregistered driver '%s'\n", driver->driver.name); ++ ++ DEBUG(dev, "<--- usb_gadget_unregister_driver() \n"); ++ ++ return 0; ++} ++EXPORT_SYMBOL(usb_gadget_unregister_driver); ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static struct iusbc_ep * ++get_ep_by_addr(struct iusbc *dev, u16 wIndex) ++{ ++ struct iusbc_ep *ep; ++ ++ if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) ++ return &dev->ep[0]; ++ ++ list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { ++ u8 bEndpointAddress; ++ if (!ep->desc) ++ continue; ++ ++ bEndpointAddress = ep->desc->bEndpointAddress; ++ if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) ++ continue; ++ ++ if ((wIndex & USB_ENDPOINT_NUMBER_MASK) ++ == (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) ++ return ep; ++ } ++ return NULL; ++} ++ ++ ++/* NAK an endpoint */ ++static void ep_nak(struct iusbc_ep *ep) ++{ ++ u16 val_16; ++ unsigned i = ep->num; ++ ++ DEBUG(ep->dev, "---> ep_nak() \n"); ++ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ val_16 &= ~EP_ENABLE; ++ val_16 |= EP_VALID; ++ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); ++ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ VDEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); ++ ++ DEBUG(ep->dev, "<--- ep_nak() \n"); ++} ++ ++ ++/* ACK an out transfer with a zero length packet (ZLP) */ ++static void ep_ack(struct iusbc_ep *ep) ++{ ++ u16 val_16; ++ unsigned i = ep->num; ++ ++ DEBUG(ep->dev, "---> ep_ack() \n"); ++ ++ /* reset data buffer zero length */ ++ writew(0, &ep->dev->regs->ep[i].ep_len); ++ val_16 = readw(&ep->dev->regs->ep[i].ep_len); ++ VDEBUG(ep->dev, "%s.ep_len = 0x%04x\n", ep->ep.name, val_16); ++ ++ /* validate endpoint, enable DMA */ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ val_16 |= (EP_VALID | EP_ENABLE); ++ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); ++ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ VDEBUG(ep->dev, "enable %s DMA transfer...\n", ep->ep.name); ++ VDEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); ++ ++ DEBUG(ep->dev, "<--- ep_ack() \n"); ++} ++ ++ ++static void ep0_setup(struct iusbc *dev) ++{ ++ struct usb_ctrlrequest ctrl; ++ struct iusbc_ep *epn; ++ unsigned i, tmp = 0; ++ u8 addr_new, setup_pkt[8]; ++ ++ VDEBUG(dev, "---> ep0_setup() \n"); ++ ++ for (i = 0; i < 8; i++) { ++ setup_pkt[i] = readb(&dev->regs->ep[1].setup_pkt[i]); ++ } ++ ++ /* read SETUP packet and enter DATA stage */ ++ ctrl.bRequestType = setup_pkt[0]; ++ ctrl.bRequest = setup_pkt[1]; ++ ctrl.wValue = cpu_to_le16((setup_pkt[3] << 8) ++ | setup_pkt[2]); ++ ctrl.wIndex = cpu_to_le16((setup_pkt[5] << 8) ++ | setup_pkt[4]); ++ ctrl.wLength = cpu_to_le16((setup_pkt[7] << 8) ++ | setup_pkt[6]); ++ ++ dev->ep[1].stopped = 0; ++ ++ /* data stage direction */ ++ if (ctrl.bRequestType & USB_DIR_IN) { ++ dev->ep0state = EP0_IN; ++ VDEBUG(dev, "ep0state: EP0_IN\n"); ++ } else { ++ dev->ep0state = EP0_OUT; ++ VDEBUG(dev, "ep0state: EP0_OUT\n"); ++ } ++ ++ /* WORKAROUND: for RNDIS */ ++ /* CDC: SEND_ENCAPSULATED_COMMAND */ ++ if ((ctrl.bRequestType == 0x21) && (ctrl.bRequest == 0x00)) { ++ goto delegate; ++ } ++ /* CDC: GET_ENCAPSULATED_COMMAND */ ++ if ((ctrl.bRequestType == 0xa1) && (ctrl.bRequest == 0x01)) { ++ goto delegate; ++ } ++ ++ switch (ctrl.bRequest) { ++ /* GET_STATUS is handled by software */ ++ case USB_REQ_GET_STATUS: ++ DEBUG(dev, "SETUP: USB_REQ_GET_STATUS\n"); ++ switch (ctrl.bRequestType & ++ __constant_cpu_to_le16(USB_RECIP_MASK)) { ++ case USB_RECIP_DEVICE: ++ /* bit 0: USB_DEVICE_SELF_POWERED ++ * bit 1: USB_DEVICE_REMOTE_WAKEUP ++ */ ++ if (dev->enable_wakeup) { ++ dev->status_d = ++ __constant_cpu_to_le16(1 << 1 | 1); ++ } else { ++ dev->status_d = __constant_cpu_to_le16(1); ++ } ++ DEBUG(dev, "device status 0x%04x\n", dev->status_d); ++ break; ++ case USB_RECIP_INTERFACE: ++ /* all bits zero */ ++ dev->status_d = __constant_cpu_to_le16(0); ++ DEBUG(dev, "interface status 0x%04x\n", dev->status_d); ++ break; ++ case USB_RECIP_ENDPOINT: ++ if ((epn = get_ep_by_addr(dev, ++ le16_to_cpu(ctrl.wIndex))) == 0) ++ goto stall; ++ if (epn->stopped) { /* halted */ ++ dev->status_d = __constant_cpu_to_le16(1); ++ } else { ++ dev->status_d = __constant_cpu_to_le16(0); ++ } ++ DEBUG(dev, "%s endpoint status 0x%04x\n", ++ epn->ep.name, dev->status_d); ++ break; ++ } ++ /* GET_STATUS is partially handled in gadget driver */ ++ goto delegate; ++ ++ case USB_REQ_CLEAR_FEATURE: ++ DEBUG(dev, "SETUP: USB_REQ_CLEAR_FEATURE\n"); ++ switch (ctrl.bRequestType) { ++ case USB_RECIP_DEVICE: ++ if (ctrl.wValue == __constant_cpu_to_le16( ++ USB_DEVICE_REMOTE_WAKEUP)) { ++ dev->enable_wakeup = 0; ++ DEBUG(dev, "CLEAR_FEATURE: " ++ "remote wakeup disabled\n"); ++ goto end; ++ } else { ++ DEBUG(dev, "unsupported CLEAR_FEATURE\n"); ++ goto stall; ++ } ++ break; ++ case USB_RECIP_INTERFACE: ++ DEBUG(dev, "unsupported CLEAR_FEATURE\n"); ++ goto stall; ++ case USB_RECIP_ENDPOINT: ++ if (ctrl.wValue != __constant_cpu_to_le16( ++ USB_ENDPOINT_HALT) ++ || le16_to_cpu(ctrl.wLength) != 0) ++ goto stall; ++ if ((epn = get_ep_by_addr(dev, ++ le16_to_cpu(ctrl.wIndex))) == 0) ++ goto stall; ++ clear_halt(epn); ++ ep_ack(&dev->ep[0]); ++ ++ dev->ep0state = EP0_STATUS; ++ VDEBUG(dev, "ep0state: EP0_STATUS\n"); ++ ++ DEBUG(dev, "%s clear halt\n", epn->ep.name); ++ goto end; ++ } ++ break; ++ ++ case USB_REQ_SET_FEATURE: ++ DEBUG (dev, "SETUP: USB_REQ_SET_FEATURE\n"); ++ switch (ctrl.bRequestType) { ++ case USB_RECIP_DEVICE: ++ if (ctrl.wValue == __constant_cpu_to_le16( ++ USB_DEVICE_REMOTE_WAKEUP)) { ++ dev->enable_wakeup = 1; ++ DEBUG(dev, "SET_FEATURE: " ++ "remote wakeup enabled\n"); ++ goto end; ++ } else { ++ DEBUG(dev, "unsupported SET_FEATURE\n"); ++ goto stall; ++ } ++ break; ++ case USB_RECIP_INTERFACE: ++ DEBUG(dev, "unsupported SET_FEATURE\n"); ++ goto stall; ++ case USB_RECIP_ENDPOINT: ++ if (ctrl.wValue != __constant_cpu_to_le16( ++ USB_ENDPOINT_HALT) ++ || le16_to_cpu(ctrl.wLength) != 0) ++ goto stall; ++ if ((epn = get_ep_by_addr(dev, ++ le16_to_cpu(ctrl.wIndex))) == 0) ++ goto stall; ++ set_halt(epn); ++ ep_ack(&dev->ep[0]); ++ ++ DEBUG(dev, "%s set halt\n", epn->ep.name); ++ goto end; ++ } ++ break; ++ ++ case USB_REQ_SET_ADDRESS: ++ /* hw handles set_address, address range: 1-127 */ ++ DEBUG(dev, "SETUP: USB_REQ_SET_ADDRESS\n"); ++ if (setup_pkt[1] == USB_REQ_SET_ADDRESS) { ++ addr_new = le16_to_cpu(ctrl.wValue) & 0x7f; ++ DEBUG(dev, "addr_new = 0x%02x\n", addr_new); ++ ++ /* hardware didn't ACK SET_ADDRESS */ ++ ep_ack(&dev->ep[0]); ++ } ++ goto end; ++ ++ case USB_REQ_GET_DESCRIPTOR: ++ DEBUG(dev, "SETUP: USB_REQ_GET_DESCRIPTOR\n"); ++ goto delegate; ++ ++ case USB_REQ_SET_DESCRIPTOR: ++ DEBUG(dev, "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n"); ++ goto stall; ++ break; ++ ++ case USB_REQ_GET_CONFIGURATION: ++ DEBUG(dev, "SETUP: USB_REQ_GET_CONFIGURATION\n"); ++ goto delegate; ++ ++ case USB_REQ_SET_CONFIGURATION: ++ DEBUG(dev, "SETUP: USB_REQ_SET_CONFIGURATION\n"); ++ goto delegate; ++ ++ case USB_REQ_GET_INTERFACE: ++ DEBUG(dev, "SETUP: USB_REQ_GET_INTERFACE\n"); ++ goto delegate; ++ ++ case USB_REQ_SET_INTERFACE: ++ DEBUG(dev, "SETUP: USB_REQ_SET_INTERFACE\n"); ++ goto delegate; ++ ++ case USB_REQ_SYNCH_FRAME: ++ DEBUG(dev, "SETUP: USB_REQ_SYNCH_FRAME unsupported\n"); ++ goto stall; ++ break; ++ default: ++ /* delegate usb standard requests to the gadget driver. ++ * it may respond after this irq handler returns. ++ */ ++ goto delegate; ++delegate: ++ DEBUG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", ++ ctrl.bRequestType, ctrl.bRequest, ++ le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex), ++ le16_to_cpu(ctrl.wLength)); ++ ++ /* WORKAROUND: for RNDIS */ ++ /* CDC: SEND_ENCAPSULATED_COMMAND */ ++ if ((ctrl.bRequestType == 0x21) ++ && (ctrl.bRequest == 0x00)) { ++ /* CDC: SEND_ENCAPSULATED_COMMAND */ ++ DEBUG(dev, "CDC: SEND_ENCAPSULATED_COMMAND\n"); ++ dev->gadget.ep0 = &dev->ep[1].ep; ++ spin_unlock(&dev->lock); ++ tmp = dev->driver->setup(&dev->gadget, &ctrl); ++ spin_lock(&dev->lock); ++ ++ /* switch back to ep0-in */ ++ dev->gadget.ep0 = &dev->ep[0].ep; ++ ++ /* hardware didn't ACK */ ++ ep_ack(&dev->ep[0]); ++ } else { ++ dev->gadget.ep0 = &dev->ep[0].ep; ++ spin_unlock(&dev->lock); ++ tmp = dev->driver->setup(&dev->gadget, &ctrl); ++ spin_lock(&dev->lock); ++ ++ /* CDC: GET_ENCAPSULATED_COMMAND */ ++ if ((ctrl.bRequestType == 0xa1) ++ && (ctrl.bRequest == 0x01)) { ++ DEBUG(dev, "CDC: GET_ENCAPSULATED_COMMAND\n"); ++ ++ /* hardware didn't ACK */ ++ ep_ack(&dev->ep[1]); ++ } ++ } ++ break; ++ } ++ ++ /* stall ep0-out on error */ ++ if (unlikely(tmp < 0)) { ++stall: ++ DEBUG(dev, "req %02x.%02x protocol STALL; err %d\n", ++ ctrl.bRequestType, ctrl.bRequest, tmp); ++ dev->ep[1].stopped = 1; ++ dev->ep0state = EP0_STALL; ++ VDEBUG(dev, "ep0state: EP0_STALL\n"); ++ } ++end: ++ VDEBUG(dev, "<--- ep0_setup() \n"); ++} ++ ++ ++static void handle_device_irqs(struct iusbc *dev) ++{ ++ u32 stat; ++ volatile u32 dev_sts; ++ unsigned is_connected = 0; ++ ++ DEBUG(dev, "---> handle_device_irqs() \n"); ++ ++ stat = dev->int_sts; ++ ++ /* get device status, set USB speed */ ++ if ((stat & RESET_INTR) || (stat & CONNECT_INTR) ++ || (stat & SUSPEND_INTR)) { ++ /* check device status */ ++ dev_sts = readl(&dev->regs->dev_sts); ++ DEBUG(dev, "handle_device_irqs: dev_sts = 0x%08x\n", ++ dev_sts); ++ ++ if (dev_sts & CONNECTED) { ++ is_connected = 1; ++ DEBUG(dev, "device connected\n"); ++ ++ /* check suspend/resume status now */ ++ if (dev_sts & SUSPEND) ++ dev->suspended = 1; ++ else ++ dev->suspended = 0; ++ ++ /* RATE: high/full speed flag ++ * 1 clock cycle after CONNECT, ++ * read one more time until RATE bit set ++ */ ++ dev_sts = readl(&dev->regs->dev_sts); ++ DEBUG(dev, "read for RATE: dev_sts = 0x%08x\n", ++ dev_sts); ++ if (dev_sts & RATE) { ++ if (dev->force_fullspeed) { ++ dev->gadget.speed = USB_SPEED_FULL; ++ DEBUG(dev, "speed: USB_SPEED_FULL\n"); ++ } else { ++ dev->gadget.speed = USB_SPEED_HIGH; ++ DEBUG(dev, "speed: USB_SPEED_HIGH\n"); ++ } ++ } else { ++ dev->gadget.speed = USB_SPEED_FULL; ++ DEBUG(dev, "speed: USB_SPEED_FULL\n"); ++ } ++ } else { /* disconnected */ ++ is_connected = 0; ++ DEBUG(dev, "device disconnected\n"); ++ } ++ } ++ ++ /* USB reset interrupt indication */ ++ if ((stat & RESET_INTR) && (!dev->is_reset)) { ++ DEBUG(dev, "USB Reset interrupt: stat = 0x%08x\n", stat); ++ /* ACK RESET_INTR */ ++ stat &= ~RESET_INTR; ++ dev->irqs++; ++ VDEBUG(dev, "dev->irqs: %lu\n", dev->irqs); ++ ++ /* set device reset flag */ ++ dev->is_reset = 1; ++ ++ stop_activity(dev, dev->driver); ++ ep0_start(dev); ++ VDEBUG(dev, "reset: ep0_start()\n"); ++ ++ goto end; ++ } ++ ++ ++ /* connect interrupt indication */ ++ if (stat & CONNECT_INTR) { ++ DEBUG(dev, "CONNECT interrupt: stat = 0x%08x\n", stat); ++ /* ACK CONNECT_INTR */ ++ stat &= ~CONNECT_INTR; ++ dev->irqs++; ++ VDEBUG(dev, "dev->irqs: %lu\n", dev->irqs); ++ ++ /* connected status has changed */ ++ if (dev->connected != is_connected) { ++ DEBUG(dev, "connected status has changed\n"); ++ dev->connected = is_connected; ++ if (is_connected) { ++ ep0_start(dev); ++ DEBUG(dev, "connect %s\n", dev->driver->driver.name); ++ } else { /* disconnected */ ++ /* set device reset flag */ ++ dev->is_reset = 0; ++ stop_activity(dev, dev->driver); ++ DEBUG(dev, "disconnect %s\n", dev->driver->driver.name); ++ dev->ep0state = EP0_DISCONNECT; ++ VDEBUG(dev, "ep0state: EP0_DISCONNECT\n"); ++ } ++ } ++ } ++ ++ /* host suspend interrupt indication */ ++ if (stat & SUSPEND_INTR) { ++ DEBUG(dev, "SUSPEND interrupt: stat = 0x%08x\n", stat); ++ /* ACK SUSPEND_INTR */ ++ stat &= ~SUSPEND_INTR; ++ dev->irqs++; ++ VDEBUG(dev, "dev->irqs: %lu\n", dev->irqs); ++ ++ /* call gadget driver suspend/resume routines */ ++ if (dev->suspended) { ++ if (dev->driver->suspend) { ++ spin_unlock(&dev->lock); ++ dev->driver->suspend(&dev->gadget); ++ spin_lock(&dev->lock); ++ } ++ DEBUG(dev, "suspend %s\n", dev->driver->driver.name); ++ } else { ++ if (dev->driver->resume) { ++ spin_unlock(&dev->lock); ++ dev->driver->resume(&dev->gadget); ++ spin_lock(&dev->lock); ++ } ++ DEBUG(dev, "resume %s\n", dev->driver->driver.name); ++ } ++ } ++ ++ /* if haven't USB Reset yet, wait for the next USB reset interrupt */ ++ if (!dev->is_reset) { ++ DEBUG(dev, "Skip other interrupts before RESET\n"); ++ } ++ ++end: ++ VDEBUG(dev, "handle device_irq finish: int_sts = 0x%08x, " ++ "stat = 0x%08x\n", dev->int_sts, stat); ++ ++ VDEBUG(dev, "<--- handle_device_irqs() \n"); ++} ++ ++ ++static void handle_ep0_irqs(struct iusbc *dev) ++{ ++ volatile u16 ep_sts, val_16; ++ u32 stat; ++ u8 setup_pkt_sts; ++ struct iusbc_request *req; ++ ++ VDEBUG(dev, "---> handle_ep0_irqs() \n"); ++ ++ stat = dev->int_sts; ++ VDEBUG(dev, "stat = 0x%08x\n", stat); ++ ++ /* ep0-out interrupt */ ++ if (stat & EP0_OUT_INTR) { ++ dev->ep[1].irqs++; ++ VDEBUG(dev, "%s.irqs = %lu\n", ++ dev->ep[1].ep.name ,dev->ep[1].irqs); ++ ++ ep_sts = readw(&dev->regs->ep[1].ep_sts); ++ VDEBUG(dev, "%s.ep_sts = 0x%04x\n", ++ dev->ep[1].ep.name, ep_sts); ++ ++ /* W1C ep0-out status register */ ++ writew(ep_sts, &dev->regs->ep[1].ep_sts); ++ ++ if ((ep_sts & BAD_PID_TYPE) ++ || (ep_sts & CRC_ERROR) ++ || (ep_sts & FIFO_ERROR) ++ || (ep_sts & DMA_ERROR) ++ || (ep_sts & DMA_IOC)) { ++ DEBUG(dev, "%s error: 0x%04x \n", ++ dev->ep[1].ep.name, ep_sts); ++ } ++ ++ if (ep_sts & TRANS_COMPLETE) { ++ VDEBUG(dev, "handle ep0-out interrupt\n"); ++ ++ setup_pkt_sts = readb(&dev->regs->ep[1].setup_pkt_sts); ++ VDEBUG(dev, "setup_pkt_sts = 0x%02x\n", setup_pkt_sts); ++ /* ep0-out SETUP packet */ ++ if (setup_pkt_sts) { ++ VDEBUG(dev, "ep0-out SETUP packet\n"); ++ ++ /* W1C ep0-out Setup Packet Status Register */ ++ writeb(1, &dev->regs->ep[1].setup_pkt_sts); ++ ++ /* read ep0-out Setup Packet Register ++ * then handle ep0-out SETUP packet ++ */ ++ ep0_setup(dev); ++ } else { ++ /* ep0-out standard OUT packet */ ++ DEBUG(dev, "ep0-out OUT packet\n"); ++ if (!list_empty(&dev->ep[1].queue)) { ++ req = list_entry(dev->ep[1].queue.next, ++ struct iusbc_request, ++ queue); ++ VDEBUG(dev, "dmacount = %d\n", ++ req->td->dmacount); ++ dma_done(&dev->ep[1], req, 0); ++ VDEBUG(dev, "%s dma_done()\n", ++ dev->ep[1].ep.name); ++ } ++ ++ /* handle next standard OUT packet */ ++ if (!list_empty(&dev->ep[1].queue)) { ++ restart_dma(&dev->ep[1]); ++ VDEBUG(dev, "%s restart_dma()\n", ++ dev->ep[1].ep.name); ++ } ++ } ++ } else { ++ /* WORKAROUND: FIFO_ERROR TC=0 */ ++ if (ep_sts & FIFO_ERROR) ++ DEBUG(dev, "ep0-out FIFO_ERROR, TC=0\n"); ++ } ++ ++ /* enable DMA again */ ++ val_16 = readw(&dev->regs->ep[1].ep_cfg); ++ val_16 |= EP_ENABLE; ++ writew(val_16, &dev->regs->ep[1].ep_cfg); ++ ++ val_16 = readw(&dev->regs->ep[1].ep_cfg); ++ VDEBUG(dev, "enable %s DMA transfer...\n", ++ dev->ep[1].ep.name); ++ VDEBUG(dev, "%s EP_ENABLE again, ep_cfg=0x%04x\n", ++ dev->ep[1].ep.name, val_16); ++ } ++ ++ /* ep0-in interrupt */ ++ if (stat & EP0_IN_INTR) { ++ dev->ep[0].irqs++; ++ VDEBUG(dev, "%s.irqs = %lu\n", ++ dev->ep[0].ep.name, dev->ep[0].irqs); ++ ++ ep_sts = readw(&dev->regs->ep[0].ep_sts); ++ VDEBUG(dev, "%s.ep_sts = 0x%04x\n", ++ dev->ep[0].ep.name, ep_sts); ++ ++ /* W1C ep0-in status register */ ++ writew(ep_sts, &dev->regs->ep[0].ep_sts); ++ ++ if ((ep_sts & BAD_PID_TYPE) ++ || (ep_sts & CRC_ERROR) ++ || (ep_sts & FIFO_ERROR) ++ || (ep_sts & DMA_ERROR) ++ || (ep_sts & DMA_IOC)) { ++ DEBUG(dev, "%s error: 0x%04x \n", ++ dev->ep[0].ep.name, ep_sts); ++ } ++ ++ if (ep_sts & TRANS_COMPLETE) { ++ VDEBUG(dev, "handle ep0-in interrupt\n"); ++ if (!list_empty(&dev->ep[0].queue)) { ++ req = list_entry(dev->ep[0].queue.next, ++ struct iusbc_request, ++ queue); ++ VDEBUG(dev, "dmacount = %d\n", req->td->dmacount); ++ dma_done(&dev->ep[0], req, 0); ++ VDEBUG(dev, "%s dma_done()\n", ++ dev->ep[0].ep.name); ++ } ++ ++ /* handle next standard IN packet */ ++ if (!list_empty(&dev->ep[0].queue)) { ++ restart_dma(&dev->ep[0]); ++ VDEBUG(dev, "%s restart_dma()\n", ++ dev->ep[0].ep.name); ++ } ++ } else { ++ if (ep_sts & FIFO_ERROR) ++ DEBUG(dev, "ep0-in FIFO_ERROR, TC=0\n"); ++ } ++ ++ } ++ ++ VDEBUG(dev, "<--- handle_ep0_irqs() \n"); ++} ++ ++ ++static void handle_ep_irqs(struct iusbc *dev) ++{ ++ volatile u16 ep_sts; ++ u32 stat; ++ unsigned i; ++ struct iusbc_request *req; ++ ++ VDEBUG(dev, "---> handle_ep_irqs() \n"); ++ ++ stat = dev->int_sts; ++ VDEBUG(dev, "stat = 0x%08x\n", stat); ++ ++ /* ep1in-bulk, ep1out-bulk and ep2in-int */ ++ for (i = 2; i < 5; i++) { ++ if ((1 << i) & stat) { ++ dev->ep[i].irqs++; ++ ep_sts = readw(&dev->regs->ep[i].ep_sts); ++ if (ep_sts) ++ VDEBUG(dev, "%s.ep_sts = 0x%04x\n", ++ dev->ep[i].ep.name, ep_sts); ++ ++ /* W1C ep status register */ ++ writew(ep_sts, &dev->regs->ep[i].ep_sts); ++ ++ if ((ep_sts & BAD_PID_TYPE) ++ || (ep_sts & CRC_ERROR) ++ || (ep_sts & FIFO_ERROR) ++ || (ep_sts & DMA_ERROR) ++ || (ep_sts & DMA_IOC)) { ++ DEBUG(dev, "%s error: 0x%04x \n", ++ dev->ep[i].ep.name, ep_sts); ++ } ++ ++ if (ep_sts & TRANS_COMPLETE) { ++ VDEBUG(dev, "handle %s interrupt\n", ++ dev->ep[i].ep.name); ++ VDEBUG(dev, "data ep dma TRANS_COMPLETE\n"); ++ if (!list_empty(&dev->ep[i].queue)) { ++ req = list_entry(dev->ep[i].queue.next, ++ struct iusbc_request, ++ queue); ++ VDEBUG(dev, "dmacount = %d\n", ++ req->td->dmacount); ++ dma_done(&dev->ep[i], req, 0); ++ VDEBUG(dev, "%s dma_done()\n", ++ dev->ep[i].ep.name); ++ } ++ ++ /* handle next standard OUT and IN packet */ ++ if (!list_empty(&dev->ep[i].queue)) { ++ restart_dma(&dev->ep[i]); ++ VDEBUG(dev, "%s restart_dma()\n", ++ dev->ep[i].ep.name); ++ } ++ } else { ++ if (ep_sts & FIFO_ERROR) ++ DEBUG(dev, "%s FIFO_ERROR, TC=0\n", ++ dev->ep[i].ep.name); ++ } ++ } ++ } ++ ++ VDEBUG(dev, "<--- handle_ep_irqs() \n"); ++} ++ ++ ++static void iusbc_do_tasklet(unsigned long arg) ++{ ++ u32 val_32; ++ volatile u32 dev_sts; ++ struct iusbc *dev; ++ dev = (struct iusbc *) arg; ++ DEBUG(dev, "---> iusbc_do_tasklet() \n"); ++ ++ spin_lock(&dev->lock); ++ ++ /* disable irqs, will re-enable later */ ++ writel(0, &dev->regs->int_ctrl); ++ ++ /* device-wide reset, connect, suspend */ ++ if (dev->int_sts & (RESET_INTR | CONNECT_INTR | SUSPEND_INTR)) { ++ DEBUG(dev, "iusbc_do_tasklet -> handle_device_irqs\n"); ++ handle_device_irqs(dev); ++ } ++ ++ /* QQQ: disable Full speed mode for D1 hw issues. */ ++ dev_sts = readl(&dev->regs->dev_sts); ++ if ((dev_sts & RATE) && (dev_sts & CONNECTED)) { ++ /* ep0-in/out control requests and interrupt */ ++ if (dev->int_sts & (EP0_IN_INTR | EP0_OUT_INTR)) { ++ DEBUG(dev, "iusbc_do_tasklet -> handle_ep0_irqs\n"); ++ handle_ep0_irqs(dev); ++ } ++ /* data endpoints requests interrupt */ ++ if (dev->int_sts & (EP1_IN_INTR | EP1_OUT_INTR | EP2_IN_INTR)) { ++ DEBUG(dev, "iusbc_do_tasklet -> handle_ep_irqs\n"); ++ handle_ep_irqs(dev); ++ } ++ } else if (dev_sts & CONNECTED) { ++ stop_activity(dev, dev->driver); ++ dev->ep0state = EP0_DISCONNECT; ++ /*iusbc_pullup(&dev->gadget, 0);*/ ++ } ++ ++ /* enable irqs again */ ++ val_32 = 0; ++ val_32 |= RESET_INTR_ENABLE ++ | CONNECT_INTR_ENABLE ++ | SUSPEND_INTR_ENABLE ++ /* | EP3_OUT_INTR_ENABLE */ ++ /* | EP3_IN_INTR_ENABLE */ ++ /* | EP2_OUT_INTR_ENABLE */ ++ | EP2_IN_INTR_ENABLE ++ | EP1_OUT_INTR_ENABLE ++ | EP1_IN_INTR_ENABLE ++ | EP0_OUT_INTR_ENABLE ++ | EP0_IN_INTR_ENABLE; ++ ++ writel(val_32, &dev->regs->int_ctrl); ++ val_32 = readl(&dev->regs->int_ctrl); ++ DEBUG(dev, "enable irqs again in iusbc_do_tasklet(), " ++ "int_ctrl = 0x%08x\n", val_32); ++ ++ spin_unlock(&dev->lock); ++ ++ DEBUG(dev, "<--- iusbc_do_tasklet() \n"); ++} ++ ++ ++static irqreturn_t iusbc_irq(int irq, void *_dev) ++{ ++ struct iusbc *dev = _dev; ++ u32 int_sts, ++ int_ctrl, ++ val_32; ++ ++ VDEBUG(dev, "---> iusbc_irq() \n"); ++ ++ /* interrupt control */ ++ int_ctrl = readl(&dev->regs->int_ctrl); ++ VDEBUG(dev, "int_ctrl = 0x%08x\n", int_ctrl); ++ ++ /* interrupt status */ ++ int_sts = readl(&dev->regs->int_sts); ++ VDEBUG(dev, "int_sts = 0x%08x\n", int_sts); ++ ++ if (!int_sts || !int_ctrl) { ++ VDEBUG(dev, "handle IRQ_NONE\n"); ++ VDEBUG(dev, "<--- iusbc_irq() \n"); ++ return IRQ_NONE; ++ } ++ ++ /* disable irqs, will re-enable later */ ++ writel(0, &dev->regs->int_ctrl); ++ ++ /* W1C interrupt status register */ ++ writel(int_sts, &dev->regs->int_sts); ++ val_32 = readl(&dev->regs->int_sts); ++ VDEBUG(dev, "W1C: regs->int_sts = 0x%08x\n", val_32); ++ ++ /* for iusbc_tasklet */ ++ dev->int_sts = int_sts; ++ ++ /* check device status */ ++ val_32 = readl(&dev->regs->dev_sts); ++ DEBUG(dev, "iusbc_irq: dev_sts = 0x%08x\n", val_32); ++ ++ /* schedule irq tasklet */ ++ tasklet_schedule(&dev->iusbc_tasklet); ++ ++ VDEBUG(dev, "<--- iusbc_irq() \n"); ++ return IRQ_HANDLED; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void gadget_release(struct device *_dev) ++{ ++ struct iusbc *dev; ++#ifdef VERBOSE ++ printk(KERN_DEBUG "---> gadget_release() \n"); ++#endif ++ ++ dev = dev_get_drvdata(_dev); ++ kfree(dev); ++ ++#ifdef VERBOSE ++ printk(KERN_DEBUG "<--- gadget_release() \n"); ++#endif ++} ++ ++ ++/* tear down the binding between this driver and the pci device */ ++static void iusbc_remove(struct pci_dev *pdev) ++{ ++ struct iusbc *dev; ++ ++ dev = pci_get_drvdata(pdev); ++ ++ BUG_ON(dev->driver); ++ ++ VDEBUG(dev, "---> iusbc_remove() \n"); ++ ++ /* then clean up the resources we allocated during probe() */ ++ if (dev->requests) { ++ unsigned i; ++ /* 2 ep0, 3 data ep */ ++ for (i = 0; i < 5; i++) { ++ if (!dev->ep[i].dummy) ++ continue; ++ ++ pci_pool_free(dev->requests, dev->ep[i].dummy, ++ dev->ep[i].td_dma); ++ } ++ pci_pool_destroy(dev->requests); ++ } ++ ++ if (dev->got_irq) ++ free_irq(pdev->irq, dev); ++ ++ if (dev->regs) ++ iounmap(dev->regs); ++ ++ if (dev->region) ++ release_mem_region(pci_resource_start(pdev, 0), ++ pci_resource_len(pdev, 0)); ++ ++ if (dev->enabled) ++ pci_disable_device(pdev); ++ ++ device_unregister(&dev->gadget.dev); ++ device_remove_file(&pdev->dev, &dev_attr_registers); ++ pci_set_drvdata(pdev, NULL); ++ ++ INFO(dev, "unbind\n"); ++ ++ the_controller = NULL; ++ ++ VDEBUG(dev, "<--- iusbc_remove() \n"); ++} ++ ++ ++/* wrap this driver around the specified device, but ++ * don't respond over USB until a gadget driver binds to us. ++ */ ++static int iusbc_probe(struct pci_dev *pdev, const struct pci_device_id *id) ++{ ++ struct iusbc *dev; ++ unsigned long resource, len; ++ void __iomem *base = NULL; ++ int retval; ++ unsigned i; ++ u32 val_32; ++ ++ /* if you want to support more than one controller in a system, ++ * usb_gadget_{register,unregister}_driver() must change. ++ */ ++ if (the_controller) { ++ dev_warn(&pdev->dev, "ignoring\n"); ++ return -EBUSY; ++ } ++ ++ /* alloc, and start init */ ++ dev = kzalloc(sizeof *dev, GFP_KERNEL); ++ if (dev == NULL){ ++ retval = -ENOMEM; ++ goto done; ++ } ++ ++ pci_set_drvdata(pdev, dev); ++ spin_lock_init(&dev->lock); ++ dev->pdev = pdev; ++ ++ DEBUG(dev, "---> iusbc_probe() \n"); ++ ++ dev->gadget.ops = &iusbc_ops; ++ dev->gadget.is_dualspeed = 1; /* support high/full speed */ ++ ++ /* the "gadget" abstracts/virtualizes the controller */ ++ strcpy(dev->gadget.dev.bus_id, "gadget"); ++ dev->gadget.dev.parent = &pdev->dev; ++ dev->gadget.dev.dma_mask = pdev->dev.dma_mask; ++ dev->gadget.dev.release = gadget_release; ++ dev->gadget.name = driver_name; ++ ++ /* now all the pci goodies ... */ ++ if (pci_enable_device(pdev) < 0) { ++ retval = -ENODEV; ++ goto done; ++ } ++ ++ /* WORKAROUND: USB port routing bug */ ++ pci_write_config_byte(pdev, 0x40, 0x82); ++ ++ dev->enabled = 1; ++ ++ /* control register: BAR 0 */ ++ resource = pci_resource_start(pdev, 0); ++ len = pci_resource_len(pdev, 0); ++ if (!request_mem_region(resource, len, driver_name)) { ++ DEBUG(dev, "controller already in use\n"); ++ retval = -EBUSY; ++ goto done; ++ } ++ dev->region = 1; ++ ++ base = ioremap_nocache(resource, len); ++ if (base == NULL) { ++ DEBUG(dev, "can't map memory\n"); ++ retval = -EFAULT; ++ goto done; ++ } ++ dev->regs = (struct iusbc_regs __iomem *) base; ++ ++ /* global capabilities, ep number and dma modes */ ++ val_32 = readl(&dev->regs->gcap); ++ if (val_32 & TRANSFER_MODE_CAP) ++ dev->transfer_mode_dma = 1; ++ ++ if (val_32 & SCATTER_GATHER_MODE_CAP) ++ dev->sg_mode_dma = 1; ++ ++ if (val_32 & LINEAR_MODE_CAP) ++ dev->linear_mode_dma = 1; ++ ++ if (val_32 & CONTROL_MODE_CAP) ++ dev->control_mode_dma = 1; ++ ++ dev->ep_cap = (val_32 >> 28); ++ ++ /* reset all registers */ ++ writel(0, &dev->regs->dev_ctrl); ++ ++ /* init usb client controller device */ ++ iusbc_reset(dev); ++ iusbc_reinit(dev); ++ ++ /* irq setup after old hardware is cleaned up */ ++ if (!pdev->irq) { ++ ERROR(dev, "No IRQ. Check PCI setup!\n"); ++ retval = -ENODEV; ++ goto done; ++ } ++ ++ if (request_irq(pdev->irq, iusbc_irq, IRQF_SHARED, driver_name, dev) ++ != 0) { ++ ERROR(dev, "request interrupt %d failed\n", pdev->irq); ++ retval = -EBUSY; ++ goto done; ++ } ++ dev->got_irq = 1; ++ ++ /* ------------------------------------------------------------------ */ ++ /* DMA setup ++ * NOTE: we know only the 32 LSBs of dma addresses may be nonzero ++ */ ++ dev->requests = pci_pool_create("requests", pdev, ++ sizeof(struct iusbc_dma), ++ 0 /* no alignment requirements */, ++ 0 /* or page-crossing issues */); ++ ++ if (!dev->requests) { ++ DEBUG(dev, "can't get request pool\n"); ++ retval = -ENOMEM; ++ goto done; ++ } ++ ++ /* assgined DMA */ ++ /* 2 ep0, 3 data ep */ ++ for (i = 0; i < 5 ; i++) { ++ struct iusbc_dma *td; ++ td = pci_pool_alloc(dev->requests, ++ GFP_KERNEL, ++ &dev->ep[i].td_dma); ++ ++ if (!td) { ++ DEBUG(dev, "can't get dummy %d\n", i); ++ retval = -ENOMEM; ++ goto done; ++ } ++ ++ td->dmacount = 0; /* not VALID */ ++ td->dmaaddr = __constant_cpu_to_le32(DMA_ADDR_INVALID); ++ ++ dev->ep[i].dummy = td; ++ } ++ ++ /* enables bus-mastering for device dev */ ++ pci_set_master(pdev); ++ ++ /* ------------------------------------------------------------------ */ ++ /* done */ ++ INFO(dev, "%s\n", driver_desc); ++ INFO(dev, "irq %d, pci mem %p\n", pdev->irq, base); ++ INFO(dev, "version: " DRIVER_VERSION "\n"); ++ INFO(dev, "support (max) %d endpoints\n", dev->ep_cap * 2); ++ ++#ifdef VERBOSE ++ /* only for debugging, print mapped memory registers */ ++ VDEBUG(dev, "After iusbc_probe(), print register values:\n"); ++ print_all_registers(dev->regs); ++#endif ++ ++ the_controller = dev; ++ retval = device_register(&dev->gadget.dev); ++ ++ if (retval) ++ goto done; ++ ++ retval = device_create_file(&pdev->dev, &dev_attr_registers); ++ ++ if (retval) ++ goto done; ++ ++ DEBUG(dev, "<--- iusbc_probe() \n"); ++ ++ return 0; ++ ++done: ++ if (dev) ++ iusbc_remove(pdev); ++ ++ DEBUG(dev, "<--- iusbc_probe() \n"); ++ ++ return retval; ++} ++ ++ ++#ifdef CONFIG_PM ++/* client suspend */ ++static int iusbc_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct iusbc *dev; ++ unsigned long flags; ++ ++ dev = pci_get_drvdata(pdev); ++ ++ DEBUG(dev, "---> iusbc_suspend() \n"); ++ ++ tasklet_kill(&dev->iusbc_tasklet); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ stop_activity(dev, dev->driver); ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ iusbc_pullup(&dev->gadget, 0); ++ ++ pci_save_state(pdev); ++ pci_set_power_state(pdev, PCI_D3hot); ++ ++ DEBUG(dev, "<--- iusbc_suspend() \n"); ++ ++ return 0; ++} ++ ++/* client resume */ ++static int iusbc_resume(struct pci_dev *pdev) ++{ ++ struct iusbc *dev; ++ ++ dev = pci_get_drvdata(pdev); ++ ++ DEBUG(dev, "---> iusbc_resume() \n"); ++ ++ pci_set_power_state(pdev, PCI_D0); ++ pci_restore_state(pdev); ++ ++ device_start(dev); ++ ++ DEBUG(dev, "<--- iusbc_resume() \n"); ++ ++ return 0; ++} ++#endif ++ ++ ++static void iusbc_shutdown(struct pci_dev *pdev) ++{ ++ struct iusbc *dev; ++ u32 val_32; ++ ++ dev = pci_get_drvdata(pdev); ++ ++ DEBUG(dev, "---> iusbc_shutdown() \n"); ++ ++ /* disable irqs */ ++ writel(0, &dev->regs->int_ctrl); ++ ++ /* reset all registers */ ++ writel(0, &dev->regs->dev_ctrl); ++ ++ val_32 = readl(&dev->regs->dev_ctrl); ++ DEBUG(dev, "dev_ctrl = 0x%08x\n", val_32); ++ ++ DEBUG(dev, "<--- iusbc_shutdown() \n"); ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static const struct pci_device_id pci_ids [] = { { ++ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0x80), ++ .class_mask = ~0, ++ .vendor = 0x8086, /* Intel */ ++ .device = 0x8118, /* Poulsbo USB Client Controller */ ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++}, { /* end: all zeroes */ } ++}; ++ ++MODULE_DEVICE_TABLE(pci, pci_ids); ++ ++/* pci driver glue; this is a "new style" PCI driver module */ ++static struct pci_driver iusbc_pci_driver = { ++ .name = (char *) driver_name, ++ .id_table = pci_ids, ++ ++ .probe = iusbc_probe, ++ .remove = iusbc_remove, ++ ++#ifdef CONFIG_PM ++ .suspend = iusbc_suspend, ++ .resume = iusbc_resume, ++#endif ++ ++ .shutdown = iusbc_shutdown, ++}; ++ ++ ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_AUTHOR("Xiaochen Shen: xiaochen.shen@intel.com"); ++MODULE_VERSION(DRIVER_VERSION); ++MODULE_LICENSE("GPL"); ++ ++ ++static int __init init(void) ++{ ++ return pci_register_driver(&iusbc_pci_driver); ++} ++module_init(init); ++ ++ ++static void __exit cleanup(void) ++{ ++ /* in case deferred_free tasklet not finished */ ++ spin_lock(&buflock); ++ while (!list_empty(&buffers)) { ++ spin_unlock(&buflock); ++ msleep(1); ++ spin_lock(&buflock); ++ } ++ spin_unlock(&buflock); ++ pci_unregister_driver(&iusbc_pci_driver); ++} ++module_exit(cleanup); ++ +diff --git a/drivers/usb/gadget/iusbc.h b/drivers/usb/gadget/iusbc.h +new file mode 100644 +index 0000000..62ab58b +--- /dev/null ++++ b/drivers/usb/gadget/iusbc.h +@@ -0,0 +1,213 @@ ++/* ++ * Intel Poulsbo USB Client Controller Driver ++ * Copyright (C) 2006-07, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++ ++#include ++ ++/* ++ * MEMORY SPACE REGISTERS ++ */ ++ ++struct iusbc_ep_regs { /* 0x20 bytes */ ++ u32 ep_base_low_32; ++ u32 ep_base_hi_32; ++ u16 ep_len; ++ u16 ep_pib; ++ u16 ep_dil; ++ u16 ep_tiq; ++ u16 ep_max; ++ u16 ep_sts; ++#define BAD_PID_TYPE (1 << 15) ++#define CRC_ERROR (1 << 14) ++#define FIFO_ERROR (1 << 13) ++#define DMA_ERROR (1 << 12) ++#define TRANS_COMPLETE (1 << 11) ++#define PING_NAK_SENT (1 << 10) ++#define DMA_IOC (1 << 9) ++ u16 ep_cfg; ++#define INTR_BAD_PID_TYPE (1 << 15) ++#define INTR_CRC_ERROR (1 << 14) ++#define INTR_FIFO_ERROR (1 << 13) ++#define INTR_DMA_ERROR (1 << 12) ++#define INTR_TRANS_COMPLETE (1 << 11) ++#define INTR_PING_NAK_SENT (1 << 10) ++#define INTR_DMA_IOC (1 << 9) ++#define LINEAR_MODE 0 ++#define SCATTER_GATHER_MODE 1 ++#define TRANSFER_MODE 2 ++#define CONTROL_MODE 3 ++#define EP_ENABLE (1 << 1) ++#define EP_VALID (1 << 0) ++ u8 _unused; ++ u8 setup_pkt_sts; ++#define SETUPPACKET_VALID (1 << 0) ++ u8 setup_pkt[8]; ++} __attribute__ ((packed)); ++ ++ ++struct iusbc_regs { ++ /* offset 0x0000 */ ++ u32 gcap; ++#define DMA_IOC_CAP (1 << 4) ++#define TRANSFER_MODE_CAP (1 << 3) ++#define SCATTER_GATHER_MODE_CAP (1 << 2) ++#define LINEAR_MODE_CAP (1 << 1) ++#define CONTROL_MODE_CAP (1 << 0) ++ u8 _unused0[0x100-0x004]; ++ ++ /* offset 0x0100 */ ++ u32 dev_sts; ++#define RATE (1 << 3) ++#define CONNECTED (1 << 1) ++#define SUSPEND (1 << 0) ++ u16 frame; ++ u8 _unused1[0x10c-0x106]; ++ ++ /* offset 0x010c */ ++ u32 int_sts; ++#define RESET_INTR (1 << 18) ++#define CONNECT_INTR (1 << 17) ++#define SUSPEND_INTR (1 << 16) ++#define EP3_OUT_INTR (1 << 7) ++#define EP3_IN_INTR (1 << 6) ++#define EP2_OUT_INTR (1 << 5) ++#define EP2_IN_INTR (1 << 4) ++#define EP1_OUT_INTR (1 << 3) ++#define EP1_IN_INTR (1 << 2) ++#define EP0_OUT_INTR (1 << 1) ++#define EP0_IN_INTR (1 << 0) ++ u32 int_ctrl; ++#define RESET_INTR_ENABLE (1 << 18) ++#define CONNECT_INTR_ENABLE (1 << 17) ++#define SUSPEND_INTR_ENABLE (1 << 16) ++#define EP3_OUT_INTR_ENABLE (1 << 7) ++#define EP3_IN_INTR_ENABLE (1 << 6) ++#define EP2_OUT_INTR_ENABLE (1 << 5) ++#define EP2_IN_INTR_ENABLE (1 << 4) ++#define EP1_OUT_INTR_ENABLE (1 << 3) ++#define EP1_IN_INTR_ENABLE (1 << 2) ++#define EP0_OUT_INTR_ENABLE (1 << 1) ++#define EP0_IN_INTR_ENABLE (1 << 0) ++ u32 dev_ctrl; ++#define DEVICE_ENABLE (1 << 31) ++#define CONNECTION_ENABLE (1 << 30) ++#define DMA3_DISABLED (1 << 15) ++#define DMA2_DISABLED (1 << 14) ++#define DMA1_DISABLED (1 << 13) ++#define DMA0_DISABLED (1 << 12) ++#define CPU_SET_ADDRESS (1 << 11) ++#define DISABLE_NYET (1 << 9) ++#define TEST_MODE (1 << 8) ++#define SIGNAL_RESUME (1 << 4) ++#define CHARGE_ENABLE (5 << 1) ++#define FORCE_FULLSPEED (1 << 0) ++ u8 _unused2[0x200-0x118]; ++ ++ /* offset: 0x200, 0x220, ..., 0x2e0 */ ++ struct iusbc_ep_regs ep[8]; ++} __attribute__ ((packed)); ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* DRIVER DATA STRUCTURES and UTILITIES */ ++ ++/* FIXME: for scatter/gather mode DMA */ ++struct iusbc_dma { ++ __le16 dmacount; ++ __le32 dmaaddr; /* the buffer */ ++ __le32 dmadesc; /* next dma descriptor */ ++ __le32 _reserved; ++} __attribute__ ((aligned (16))); ++ ++struct iusbc_ep { ++ struct usb_ep ep; ++ struct iusbc_dma *dummy; ++ dma_addr_t td_dma; /* of dummy */ ++ struct iusbc *dev; ++ unsigned long irqs; ++ ++ /* analogous to a host-side qh */ ++ struct list_head queue; ++ const struct usb_endpoint_descriptor *desc; ++ unsigned num : 8, ++ stopped : 1, ++ is_in : 1, ++ dma_mode : 2, ++ ep_type : 2; ++}; ++ ++struct iusbc_request { ++ struct usb_request req; ++ struct iusbc_dma *td; ++ dma_addr_t td_dma; ++ struct list_head queue; ++ unsigned mapped : 1, ++ valid : 1; ++}; ++ ++enum ep0state { ++ EP0_DISCONNECT, /* no host */ ++ EP0_IDLE, /* between STATUS ack and SETUP report */ ++ EP0_IN, EP0_OUT, /* data stage */ ++ EP0_STATUS, /* status stage */ ++ EP0_STALL, /* data or status stages */ ++ EP0_SUSPEND, /* usb suspend */ ++}; ++ ++struct iusbc { ++ /* each pci device provides one gadget, several endpoints */ ++ struct usb_gadget gadget; ++ spinlock_t lock; ++ struct iusbc_ep ep[8]; ++ struct usb_gadget_driver *driver; ++ enum ep0state ep0state; ++ unsigned ep_cap; ++ unsigned enabled : 1, ++ powered : 1, ++ enable_wakeup : 1, ++ force_fullspeed : 1, ++ rate : 1, ++ connected : 1, ++ suspended : 1, ++ got_irq : 1, ++ region : 1, ++ transfer_mode_dma : 1, ++ sg_mode_dma : 1, ++ linear_mode_dma : 1, ++ control_mode_dma : 1, ++ is_reset : 1; ++ ++ /* pci state used to access those endpoints */ ++ struct pci_dev *pdev; ++ struct iusbc_regs __iomem *regs; ++ struct pci_pool *requests; ++ ++ /* statistics... */ ++ unsigned long irqs; ++ ++ /* 16 bits status data for GET_STATUS */ ++ __le16 status_d; ++ ++ /* device irq tasklet */ ++ struct tasklet_struct iusbc_tasklet; ++ ++ /* interrupt status register value */ ++ volatile u32 int_sts; ++}; ++ +diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c +index db1b2bf..d6b7a83 100644 +--- a/drivers/usb/gadget/rndis.c ++++ b/drivers/usb/gadget/rndis.c +@@ -40,7 +40,7 @@ + + #undef RNDIS_PM + #undef RNDIS_WAKEUP +-#undef VERBOSE ++#define VERBOSE + + #include "rndis.h" + +@@ -52,14 +52,14 @@ + * and will be happier if you provide the host_addr module parameter. + */ + +-#if 0 ++#if 1 + #define DBG(str,args...) do { \ + if (rndis_debug) \ + printk(KERN_DEBUG str , ## args ); \ + } while (0) +-static int rndis_debug = 0; ++static int rndis_debug = 2; + +-module_param (rndis_debug, int, 0); ++module_param (rndis_debug, int, S_IRUGO|S_IWUSR); + MODULE_PARM_DESC (rndis_debug, "enable debugging"); + + #else +@@ -586,12 +586,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, + case OID_802_3_MAXIMUM_LIST_SIZE: + DBG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); + /* Multicast base address only */ +- *outbuf = __constant_cpu_to_le32 (1); ++ *outbuf = __constant_cpu_to_le32 (32); + retval = 0; + break; + + case OID_802_3_MAC_OPTIONS: + DBG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__); ++ *outbuf = __constant_cpu_to_le32 (0); ++ retval = 0; + break; + + /* ieee802.3 statistics OIDs (table 4-4) */ +@@ -898,7 +900,7 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf) + + static int rndis_set_response (int configNr, rndis_set_msg_type *buf) + { +- u32 BufLength, BufOffset; ++ u32 BufLength, BufOffset, i; + rndis_set_cmplt_type *resp; + rndis_resp_t *r; + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0058-Applied-USB-another-ehci_iaa_watchdog-fix-from-upstr.patch +++ linux-2.6.24/patches/0058-Applied-USB-another-ehci_iaa_watchdog-fix-from-upstr.patch @@ -0,0 +1,38 @@ +From 468e6e671db7ce5240558e3b21b2cc1dce96c904 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 17 Sep 2008 11:20:27 -0400 +Subject: [PATCH 058/170] Applied "USB: another ehci_iaa_watchdog fix" from upstream kernel. This patch fixes ehci lockup issues on resume from S3. This patch specifically fixes LP#243047 and LP#253053 + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/243047 +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/253053 +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/usb/host/ehci-hub.c | 5 +++-- + 1 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c +index 16cc92b..30e8ffd 100644 +--- a/drivers/usb/host/ehci-hub.c ++++ b/drivers/usb/host/ehci-hub.c +@@ -135,8 +135,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) + hcd->state = HC_STATE_QUIESCING; + } + ehci->command = ehci_readl(ehci, &ehci->regs->command); +- if (ehci->reclaim) +- end_unlink_async(ehci); + ehci_work(ehci); + + /* Unlike other USB host controller types, EHCI doesn't have +@@ -176,6 +174,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) + ehci_halt (ehci); + hcd->state = HC_STATE_SUSPENDED; + ++ if (ehci->reclaim) ++ end_unlink_async(ehci); ++ + /* allow remote wakeup */ + mask = INTR_MASK; + if (!device_may_wakeup(&hcd->self.root_hub->dev)) +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0009-kgdb-light-v10-fix-NMI-hangs.patch +++ linux-2.6.24/patches/0009-kgdb-light-v10-fix-NMI-hangs.patch @@ -0,0 +1,113 @@ +From 90a31810eaf994c4e721b6545ec08dec5324ab85 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 15 Feb 2008 14:55:53 -0600 +Subject: [PATCH 009/170] kgdb-light-v10: fix NMI hangs + +This patch fixes the hang regression with kgdb when the NMI interrupt +comes in while the master core is returning from an exception. + +Adjust the NMI logic such that KGDB will not stop NMI exceptions from +occurring by in general returning NOTIFY_DONE. It is not possible to +distinguish the debug NMI sync vs the normal NMI apic interrupt so +kgdb needs to catch the unknown NMI if it the debugger was previously +active on one of the cpus. + +Signed-off-by: Jason Wessel +Signed-off-by: Ingo Molnar +--- + arch/x86/kernel/kgdb.c | 18 +++++++++++++++--- + arch/x86/kernel/traps_32.c | 2 ++ + arch/x86/kernel/traps_64.c | 2 ++ + include/asm-x86/kdebug.h | 1 + + 4 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c +index 37194d6..5d7a211 100644 +--- a/arch/x86/kernel/kgdb.c ++++ b/arch/x86/kernel/kgdb.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -290,6 +291,8 @@ single_step_cont(struct pt_regs *regs, struct die_args *args) + return NOTIFY_STOP; + } + ++static int was_in_debug_nmi[NR_CPUS]; ++ + static int __kgdb_notify(struct die_args *args, unsigned long cmd) + { + struct pt_regs *regs = args->regs; +@@ -299,15 +302,24 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) + if (atomic_read(&kgdb_active) != -1) { + /* KGDB CPU roundup */ + kgdb_nmicallback(raw_smp_processor_id(), regs); ++ was_in_debug_nmi[raw_smp_processor_id()] = 1; ++ touch_nmi_watchdog(); + return NOTIFY_STOP; + } + return NOTIFY_DONE; + + case DIE_NMI_IPI: + if (atomic_read(&kgdb_active) != -1) { +- /* KGDB CPU roundup: */ +- if (kgdb_nmicallback(raw_smp_processor_id(), regs)) +- return NOTIFY_DONE; ++ /* KGDB CPU roundup */ ++ kgdb_nmicallback(raw_smp_processor_id(), regs); ++ was_in_debug_nmi[raw_smp_processor_id()] = 1; ++ touch_nmi_watchdog(); ++ } ++ return NOTIFY_DONE; ++ ++ case DIE_NMIUNKNOWN: ++ if (was_in_debug_nmi[raw_smp_processor_id()]) { ++ was_in_debug_nmi[raw_smp_processor_id()] = 0; + return NOTIFY_STOP; + } + return NOTIFY_DONE; +diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c +index 02d1e1e..6d0a0de 100644 +--- a/arch/x86/kernel/traps_32.c ++++ b/arch/x86/kernel/traps_32.c +@@ -673,6 +673,8 @@ io_check_error(unsigned char reason, struct pt_regs * regs) + static __kprobes void + unknown_nmi_error(unsigned char reason, struct pt_regs * regs) + { ++ if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) ++ return; + #ifdef CONFIG_MCA + /* Might actually be able to figure out what the guilty party + * is. */ +diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c +index cc68b92..11857be 100644 +--- a/arch/x86/kernel/traps_64.c ++++ b/arch/x86/kernel/traps_64.c +@@ -763,6 +763,8 @@ io_check_error(unsigned char reason, struct pt_regs * regs) + static __kprobes void + unknown_nmi_error(unsigned char reason, struct pt_regs * regs) + { ++ if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) ++ return; + printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", + reason); + printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); +diff --git a/include/asm-x86/kdebug.h b/include/asm-x86/kdebug.h +index e2f9b62..2f5f832 100644 +--- a/include/asm-x86/kdebug.h ++++ b/include/asm-x86/kdebug.h +@@ -20,6 +20,7 @@ enum die_val { + DIE_CALL, + DIE_NMI_IPI, + DIE_PAGE_FAULT, ++ DIE_NMIUNKNOWN, + }; + + extern void printk_address(unsigned long address); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0164-UBUNTU-Add-back-missing-.mk-files-so-fdr-clean-will-.patch +++ linux-2.6.24/patches/0164-UBUNTU-Add-back-missing-.mk-files-so-fdr-clean-will-.patch @@ -0,0 +1,67 @@ +From 51c2634ae45513fd8b4ab7c48e0a8b994651a5cb Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Fri, 11 Sep 2009 12:08:20 -0500 +Subject: [PATCH 164/170] UBUNTU: Add back missing .mk files so fdr clean will work + +Signed-off-by: Steve Conklin +--- + debian/rules.d/amd64.mk | 18 ++++++++++++++++++ + debian/rules.d/i386.mk | 21 +++++++++++++++++++++ + 2 files changed, 39 insertions(+), 0 deletions(-) + create mode 100644 debian/rules.d/amd64.mk + create mode 100644 debian/rules.d/i386.mk + +diff --git a/debian/rules.d/amd64.mk b/debian/rules.d/amd64.mk +new file mode 100644 +index 0000000..1bea5c9 +--- /dev/null ++++ b/debian/rules.d/amd64.mk +@@ -0,0 +1,18 @@ ++build_arch = x86_64 ++header_arch = $(build_arch) ++asm_link = x86 ++defconfig = defconfig ++flavours = generic ++flavours += server ++build_image = bzImage ++kernel_file = arch/$(build_arch)/boot/bzImage ++install_file = vmlinuz ++ ++do_debug_image = true ++ ++loader = grub ++ ++# ++# No custom binaries for the PPA build. ++# ++custom_flavours = rt xen openvz +diff --git a/debian/rules.d/i386.mk b/debian/rules.d/i386.mk +new file mode 100644 +index 0000000..c906c9d +--- /dev/null ++++ b/debian/rules.d/i386.mk +@@ -0,0 +1,21 @@ ++build_arch = i386 ++header_arch = x86_64 ++asm_link = x86 ++defconfig = defconfig ++# ++# Only build -386 and -generic for PPA. ++# ++flavours = 386 generic ++flavours += server virtual ++build_image = bzImage ++kernel_file = arch/$(build_arch)/boot/bzImage ++install_file = vmlinuz ++ ++do_debug_image = true ++ ++loader = grub ++ ++# ++# No custom binaries for the PPA build. ++# ++custom_flavours = rt xen openvz +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0145-Fix-tag-parsing-in-the-retag-script.patch +++ linux-2.6.24/patches/0145-Fix-tag-parsing-in-the-retag-script.patch @@ -0,0 +1,31 @@ +From 39d3053c50704d941b1209738f6282aa20cd8321 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Thu, 30 Apr 2009 20:42:50 -0500 +Subject: [PATCH 145/170] Fix tag parsing in the retag script + +OriginalAuthor: Steve Conklin + +Signed-off-by: Steve Conklin + +The retag script would incorrectly match tags which appeared +in the commit text and fail. +--- + debian/scripts/misc/retag-branch | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/debian/scripts/misc/retag-branch b/debian/scripts/misc/retag-branch +index 983cf97..c609b92 100755 +--- a/debian/scripts/misc/retag-branch ++++ b/debian/scripts/misc/retag-branch +@@ -14,7 +14,7 @@ while () { + next; + } + +- m|\s*UBUNTU: (NBK-Ubuntu-2\.6\.\S*)| or next; ++ m|^\s*UBUNTU: (NBK-Ubuntu-2\.6\.\S*)| or next; + $tag = $1; + + ($origtag) = grep(/^$tag.orig$/, @tags); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0152-UBUNTU-Start-new-release.patch +++ linux-2.6.24/patches/0152-UBUNTU-Start-new-release.patch @@ -0,0 +1,31 @@ +From b0aae73df24d4a60fca71975c440b5a7cc522365 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Mon, 15 Jun 2009 17:14:54 +0100 +Subject: [PATCH 152/170] UBUNTU: Start new release + +Ignore: yes + +Signed-off-by: Andy Whitcroft +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 45eedfa..ca7d190 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-24.54netboot01) UNRELEASED; urgency=low ++ ++ CHANGELOG: Do not edit directly. Autogenerated at release. ++ CHANGELOG: Use the printchanges target to see the curent changes. ++ CHANGELOG: Use the insertchanges target to create the final log. ++ ++ -- Andy Whitcroft Mon, 15 Jun 2009 17:14:24 +0100 ++ + linux (2.6.24-24.53netbook01) netbook-common; urgency=low + + * Now that the rebase is finished, remove the whitespace correction +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0076-ACPI-reboot-method-workaround-for-hardware-on-port-0.patch +++ linux-2.6.24/patches/0076-ACPI-reboot-method-workaround-for-hardware-on-port-0.patch @@ -0,0 +1,39 @@ +From 3ced4abfa4b1f73d8a64ffb329f9be26ebd60710 Mon Sep 17 00:00:00 2001 +From: Tony Espy +Date: Wed, 5 Nov 2008 18:13:48 -0500 +Subject: [PATCH 076/170] ACPI reboot method - workaround for hardware on port 0xCF9. + +OriginalAuthor: Colin Ian King + +Signed-off-by: Tony Espy +--- + drivers/acpi/reboot.c | 13 ++++++++++++- + 1 files changed, 12 insertions(+), 1 deletions(-) + +diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c +index e1097f2..cb2fbec 100644 +--- a/drivers/acpi/reboot.c ++++ b/drivers/acpi/reboot.c +@@ -73,7 +73,18 @@ void acpi_reboot(void) + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + case ACPI_ADR_SPACE_SYSTEM_IO: + printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n"); +- acpi_hw_low_level_write(8, reset_value, rr); ++ ++ /* A reset on port 0xcf9 should be broken into several ++ * stages with one I/O cycle delay between each write ++ * to work correctly on some hardware platforms */ ++ if ((rr->address == 0x0cf9) && (reset_value == 0x6)) { ++ acpi_hw_low_level_write(8, 0x2, rr); ++ acpi_hw_low_level_write(8, 0x4, rr); ++ acpi_hw_low_level_write(8, reset_value, rr); ++ } ++ else { ++ acpi_hw_low_level_write(8, reset_value, rr); ++ } + break; + } + /* Wait ten seconds */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0014-kgdb-kgdboc-pl011-I-O-module.patch +++ linux-2.6.24/patches/0014-kgdb-kgdboc-pl011-I-O-module.patch @@ -0,0 +1,71 @@ +From 1944a6e8bf5790a007b9aa574647cf0bc3b99578 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Wed, 20 Feb 2008 13:33:39 -0600 +Subject: [PATCH 014/170] kgdb: kgdboc pl011 I/O module + +Implement the serial polling hooks for the pl011 uart for use with +kgdboc. + +This patch was specifically tested on the ARM Versatile AB reference +platform. + +[ mingo@elte.hu: minor cleanups. ] + +Signed-off-by: Jason Wessel +Signed-off-by: Ingo Molnar +Signed-off-by: Thomas Gleixner +--- + drivers/serial/amba-pl011.c | 30 ++++++++++++++++++++++++++++++ + 1 files changed, 30 insertions(+), 0 deletions(-) + +diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c +index 40604a0..08adc1d 100644 +--- a/drivers/serial/amba-pl011.c ++++ b/drivers/serial/amba-pl011.c +@@ -314,6 +314,32 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) + spin_unlock_irqrestore(&uap->port.lock, flags); + } + ++#ifdef CONFIG_CONSOLE_POLL ++static int pl010_get_poll_char(struct uart_port *port) ++{ ++ struct uart_amba_port *uap = (struct uart_amba_port *)port; ++ unsigned int status; ++ ++ do { ++ status = readw(uap->port.membase + UART01x_FR); ++ } while (status & UART01x_FR_RXFE); ++ ++ return readw(uap->port.membase + UART01x_DR); ++} ++ ++static void pl010_put_poll_char(struct uart_port *port, ++ unsigned char ch) ++{ ++ struct uart_amba_port *uap = (struct uart_amba_port *)port; ++ ++ while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) ++ barrier(); ++ ++ writew(ch, uap->port.membase + UART01x_DR); ++} ++ ++#endif /* CONFIG_CONSOLE_POLL */ ++ + static int pl011_startup(struct uart_port *port) + { + struct uart_amba_port *uap = (struct uart_amba_port *)port; +@@ -572,6 +598,10 @@ static struct uart_ops amba_pl011_pops = { + .request_port = pl010_request_port, + .config_port = pl010_config_port, + .verify_port = pl010_verify_port, ++#ifdef CONFIG_CONSOLE_POLL ++ .poll_get_char = pl010_get_poll_char, ++ .poll_put_char = pl010_put_poll_char, ++#endif + }; + + static struct uart_amba_port *amba_ports[UART_NR]; +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0146-UBUNTU-SAUCE-Enable-debug-package-generation.patch +++ linux-2.6.24/patches/0146-UBUNTU-SAUCE-Enable-debug-package-generation.patch @@ -0,0 +1,204 @@ +From 79c884dd47a21042ce66a3de96c1b13fb940b910 Mon Sep 17 00:00:00 2001 +From: Jim Lieb +Date: Fri, 1 May 2009 16:28:20 -0700 +Subject: [PATCH 146/170] UBUNTU: SAUCE: Enable debug package generation + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/340181 + +Enable debug package generation as part of the standard build. +This works for both main builds and custom builds. The original +method did not follow the build systems convention and the custom +build did not have debug build handling at all. Debug builds now +follow the same method as Intrepid and Jaunty builds. + +The default case is not to create debug (.ddeb) packages. This applies +to local builds. + +A debug package will be created in the build environment (chroot or VM) +if and only if the directory '/CurrentlyBuilding' exists. To turn on +a debug build, all that is necessary is: + + sudo mkdir /CurrentlyBuilding + +before the build. This is the method used on the build systems. + +There were some environment variables that were set per architecture. These +did not consistantly work and were removed. The build systems do not use +these special environment variables. They will not be missed. + +Signed-off-by: Jim Lieb +Signed-off-by: Tim Gardner +Signed-off-by: Stefan Bader +--- + debian/binary-custom.d/lpia/vars | 1 + + debian/rules.d/0-common-vars.mk | 5 +++++ + debian/rules.d/2-binary-arch.mk | 20 +++++++++++++++++--- + debian/rules.d/6-binary-custom.mk | 35 +++++++++++++++++++++++++++++++++++ + debian/rules.d/lpia.mk | 2 -- + 5 files changed, 58 insertions(+), 5 deletions(-) + +diff --git a/debian/binary-custom.d/lpia/vars b/debian/binary-custom.d/lpia/vars +index 3d69ff2..7d3ac4b 100644 +--- a/debian/binary-custom.d/lpia/vars ++++ b/debian/binary-custom.d/lpia/vars +@@ -5,3 +5,4 @@ target="UME kernel" + bootloader="lilo (>= 19.1) | grub" + provides="kvm-api-4, redhat-cluster-modules" + section_image="universe/base" ++do_debug="Yes" +diff --git a/debian/rules.d/0-common-vars.mk b/debian/rules.d/0-common-vars.mk +index 41c681a..13de178 100644 +--- a/debian/rules.d/0-common-vars.mk ++++ b/debian/rules.d/0-common-vars.mk +@@ -46,6 +46,7 @@ abi_suffix = + else + skipabi = true + skipmodule = true ++skipdbg = true + gitver=$(shell if test -f .git/HEAD; then cat .git/HEAD; else uuidgen; fi) + gitverpre=$(shell echo $(gitver) | cut -b -3) + gitverpost=$(shell echo $(gitver) | cut -b 38-40) +@@ -64,6 +65,10 @@ ifneq ($(PRINTSHAS),) + ubuntu_log_opts += --print-shas + endif + ++ifeq ($(wildcard /CurrentlyBuilding),) ++skipdbg=true ++endif ++ + abinum := $(shell echo $(revision) | sed -e 's/\..*//')$(abisuffix) + prev_abinum := $(shell echo $(prev_revision) | sed -e 's/\..*//')$(abisuffix) + debnum := -$(abinum) +diff --git a/debian/rules.d/2-binary-arch.mk b/debian/rules.d/2-binary-arch.mk +index 0c774f5..713a3f0 100644 +--- a/debian/rules.d/2-binary-arch.mk ++++ b/debian/rules.d/2-binary-arch.mk +@@ -79,9 +79,15 @@ endif + done + + # Debug image is simple +-ifneq ($(do_debug_image),) ++ifneq ($(skipdbg),true) + install -m644 -D $(builddir)/build-$*/vmlinux \ +- $(dbgpkgdir)//boot/vmlinux-debug-$(release)$(debnum)-$* ++ $(dbgpkgdir)/usr/lib/debug/boot/vmlinux-$(release)$(debnum)-$* ++ $(kmake) O=$(builddir)/build-$* modules_install \ ++ INSTALL_MOD_PATH=$(dbgpkgdir)/usr/lib/debug ++ rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(release)$(debnum)-$*/build ++ rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(release)$(debnum)-$*/source ++ rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(release)$(debnum)-$*/modules.* ++ rm -fr $(dbgpkgdir)/usr/lib/debug/lib/firmware + endif + + # The flavour specific headers image +@@ -193,7 +199,7 @@ binary-%: install-% + dh_md5sums -p$(pkghdr) + dh_builddeb -p$(pkghdr) + +-ifneq ($(do_debug_image),) ++ifneq ($(skipdbg),true) + dh_installchangelogs -p$(dbgpkg) + dh_installdocs -p$(dbgpkg) + dh_compress -p$(dbgpkg) +@@ -202,6 +208,14 @@ ifneq ($(do_debug_image),) + dh_gencontrol -p$(dbgpkg) + dh_md5sums -p$(dbgpkg) + dh_builddeb -p$(dbgpkg) ++ ++ # Hokay...here's where we do a little twiddling... ++ mv ../$(dbgpkg)_$(release)-$(revision)_$(arch).deb \ ++ ../$(dbgpkg)_$(release)-$(revision)_$(arch).ddeb ++ grep -v '^$(dbgpkg)_.*$$' debian/files > debian/files.new ++ mv debian/files.new debian/files ++ # Now, the package wont get into the archive, but it will get put ++ # into the debug system. + endif + + $(stampdir)/stamp-flavours: +diff --git a/debian/rules.d/6-binary-custom.mk b/debian/rules.d/6-binary-custom.mk +index ec34480..98ea584 100644 +--- a/debian/rules.d/6-binary-custom.mk ++++ b/debian/rules.d/6-binary-custom.mk +@@ -40,6 +40,7 @@ $(stampdir)/stamp-custom-build-%: $(stampdir)/stamp-custom-prepare-% + @touch $@ + + custom-install-%: pkgdir = $(CURDIR)/debian/linux-image-$(release)$(debnum)-$* ++custom-install-%: dbgpkgdir = $(CURDIR)/debian/linux-image-debug-$(release)$(debnum)-$* + custom-install-%: basepkg = linux-headers-$(release)$(debnum) + custom-install-%: hdrdir = $(CURDIR)/debian/$(basepkg)-$*/usr/src/$(basepkg)-$* + custom-install-%: target_flavour = $* +@@ -51,6 +52,7 @@ custom-install-%: $(stampdir)/stamp-custom-build-% + dh_testroot + dh_clean -k -plinux-image-$(release)$(debnum)-$* + dh_clean -k -plinux-headers-$(release)$(debnum)-$* ++ dh_clean -k -plinux-image-debug-$(release)$(debnum)-$* + + # The main image + # xen doesnt put stuff in the same directory. its quirky that way +@@ -85,6 +87,18 @@ endif + chmod 755 $(pkgdir)/DEBIAN/$$script; \ + done + ++ # Debug image is simple ++ifneq ($(skipdbg),true) ++ install -m644 -D $(builddir)/custom-build-$*/vmlinux \ ++ $(dbgpkgdir)/usr/lib/debug/boot/vmlinux-$(release)$(debnum)-$* ++ $(kmake) O=$(builddir)/custom-build-$* modules_install \ ++ INSTALL_MOD_PATH=$(dbgpkgdir)/usr/lib/debug ++ rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(release)$(debnum)-$*/build ++ rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(release)$(debnum)-$*/source ++ rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(release)$(debnum)-$*/modules.* ++ rm -fr $(dbgpkgdir)/usr/lib/debug/lib/firmware ++endif ++ + # The flavour specific headers image + # XXX Would be nice if we didn't have to dupe the original builddir + install -m644 -D $(srcdir)/.config \ +@@ -109,6 +123,7 @@ endif + + custom-binary-%: pkgimg = linux-image-$(release)$(debnum)-$* + custom-binary-%: pkghdr = linux-headers-$(release)$(debnum)-$* ++custom-binary-%: dbgpkg = linux-image-debug-$(release)$(debnum)-$* + custom-binary-%: custom-install-% + dh_testdir + dh_testroot +@@ -131,3 +146,23 @@ custom-binary-%: custom-install-% + dh_gencontrol -p$(pkghdr) + dh_md5sums -p$(pkghdr) + dh_builddeb -p$(pkghdr) ++ ++ifneq ($(skipdbg),true) ++ dh_installchangelogs -p$(dbgpkg) ++ dh_installdocs -p$(dbgpkg) ++ dh_compress -p$(dbgpkg) ++ dh_fixperms -p$(dbgpkg) ++ dh_installdeb -p$(dbgpkg) ++ dh_gencontrol -p$(dbgpkg) ++ dh_md5sums -p$(dbgpkg) ++ dh_builddeb -p$(dbgpkg) ++ ++ # Hokay...here's where we do a little twiddling... ++ mv ../$(dbgpkg)_$(release)-$(revision)_$(arch).deb \ ++ ../$(dbgpkg)_$(release)-$(revision)_$(arch).ddeb ++ grep -v '^$(dbgpkg)_.*$$' debian/files > debian/files.new ++ mv debian/files.new debian/files ++ # Now, the package wont get into the archive, but it will get put ++ # into the debug system. ++endif ++ +diff --git a/debian/rules.d/lpia.mk b/debian/rules.d/lpia.mk +index 123c7bc..a1ff613 100644 +--- a/debian/rules.d/lpia.mk ++++ b/debian/rules.d/lpia.mk +@@ -7,8 +7,6 @@ build_image = bzImage + kernel_file = arch/$(build_arch)/boot/bzImage + install_file = vmlinuz + +-do_debug_image = true +- + loader = grub + + #custom_flavours = lpiacompat lpia +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0056-Backport-of-HPET-clock-changes-from-2.6.27.patch +++ linux-2.6.24/patches/0056-Backport-of-HPET-clock-changes-from-2.6.27.patch @@ -0,0 +1,429 @@ +From aaa3d1322869e62175481f60726cc8ac469f079a Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 10 Sep 2008 15:21:30 -0400 +Subject: [PATCH 056/170] Backport of HPET clock changes from 2.6.27 + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + arch/x86/kernel/hpet.c | 19 +++++++--- + drivers/clocksource/acpi_pm.c | 54 +++++++++++++++++----------- + include/linux/clockchips.h | 2 + + kernel/time/clockevents.c | 3 +- + kernel/time/tick-broadcast.c | 78 ++++++++++++++++++++++++++++++---------- + kernel/time/tick-common.c | 1 + + kernel/time/tick-internal.h | 2 + + kernel/time/tick-oneshot.c | 46 +++++++++++++++++++++--- + 8 files changed, 150 insertions(+), 55 deletions(-) + +diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c +index 2f99ee2..038a1dc 100644 +--- a/arch/x86/kernel/hpet.c ++++ b/arch/x86/kernel/hpet.c +@@ -221,8 +221,8 @@ static void hpet_legacy_clockevent_register(void) + /* Calculate the min / max delta */ + hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, + &hpet_clockevent); +- hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30, +- &hpet_clockevent); ++ /* 5 usec minimum reprogramming delta. */ ++ hpet_clockevent.min_delta_ns = 5000; + + /* + * Start hpet with the boot cpu mask and make it +@@ -281,15 +281,22 @@ static void hpet_legacy_set_mode(enum clock_event_mode mode, + } + + static int hpet_legacy_next_event(unsigned long delta, +- struct clock_event_device *evt) ++ struct clock_event_device *evt) + { +- unsigned long cnt; ++ u32 cnt; + + cnt = hpet_readl(HPET_COUNTER); +- cnt += delta; ++ cnt += (u32) delta; + hpet_writel(cnt, HPET_T0_CMP); + +- return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0) ? -ETIME : 0; ++ /* ++ * We need to read back the CMP register to make sure that ++ * what we wrote hit the chip before we compare it to the ++ * counter. ++ */ ++ WARN_ON((u32)hpet_readl(HPET_T0_CMP) != cnt); ++ ++ return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; + } + + /* +diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c +index 7b46faf..5564fde 100644 +--- a/drivers/clocksource/acpi_pm.c ++++ b/drivers/clocksource/acpi_pm.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + /* +@@ -151,13 +152,13 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE, + */ + static int verify_pmtmr_rate(void) + { +- u32 value1, value2; ++ cycle_t value1, value2; + unsigned long count, delta; + + mach_prepare_counter(); +- value1 = read_pmtmr(); ++ value1 = clocksource_acpi_pm.read(); + mach_countup(&count); +- value2 = read_pmtmr(); ++ value2 = clocksource_acpi_pm.read(); + delta = (value2 - value1) & ACPI_PM_MASK; + + /* Check that the PMTMR delta is within 5% of what we expect */ +@@ -175,10 +176,13 @@ static int verify_pmtmr_rate(void) + #define verify_pmtmr_rate() (0) + #endif + ++/* Number of monotonicity checks to perform during initialization */ ++#define ACPI_PM_MONOTONICITY_CHECKS 10 ++ + static int __init init_acpi_pm_clocksource(void) + { +- u32 value1, value2; +- unsigned int i; ++ cycle_t value1, value2; ++ unsigned int i, j, good = 0; + + if (!pmtmr_ioport) + return -ENODEV; +@@ -187,24 +191,32 @@ static int __init init_acpi_pm_clocksource(void) + clocksource_acpi_pm.shift); + + /* "verify" this timing source: */ +- value1 = read_pmtmr(); +- for (i = 0; i < 10000; i++) { +- value2 = read_pmtmr(); +- if (value2 == value1) +- continue; +- if (value2 > value1) +- goto pm_good; +- if ((value2 < value1) && ((value2) < 0xFFF)) +- goto pm_good; +- printk(KERN_INFO "PM-Timer had inconsistent results:" +- " 0x%#x, 0x%#x - aborting.\n", value1, value2); +- return -EINVAL; ++ for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) { ++ value1 = clocksource_acpi_pm.read(); ++ for (i = 0; i < 10000; i++) { ++ value2 = clocksource_acpi_pm.read(); ++ if (value2 == value1) ++ continue; ++ if (value2 > value1) ++ good++; ++ break; ++ if ((value2 < value1) && ((value2) < 0xFFF)) ++ good++; ++ break; ++ printk(KERN_INFO "PM-Timer had inconsistent results:" ++ " 0x%#llx, 0x%#llx - aborting.\n", ++ value1, value2); ++ return -EINVAL; ++ } ++ udelay(300 * i); ++ } ++ ++ if (good != ACPI_PM_MONOTONICITY_CHECKS) { ++ printk(KERN_INFO "PM-Timer failed consistency check " ++ " (0x%#llx) - aborting.\n", value1); ++ return -ENODEV; + } +- printk(KERN_INFO "PM-Timer had no reasonable result:" +- " 0x%#x - aborting.\n", value1); +- return -ENODEV; + +-pm_good: + if (verify_pmtmr_rate() != 0) + return -ENODEV; + +diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h +index c33b0dc..ed3a5d4 100644 +--- a/include/linux/clockchips.h ++++ b/include/linux/clockchips.h +@@ -127,6 +127,8 @@ extern int clockevents_register_notifier(struct notifier_block *nb); + extern int clockevents_program_event(struct clock_event_device *dev, + ktime_t expires, ktime_t now); + ++extern void clockevents_handle_noop(struct clock_event_device *dev); ++ + #ifdef CONFIG_GENERIC_CLOCKEVENTS + extern void clockevents_notify(unsigned long reason, void *arg); + #else +diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c +index 5fb139f..54872fd 100644 +--- a/kernel/time/clockevents.c ++++ b/kernel/time/clockevents.c +@@ -164,7 +164,7 @@ void clockevents_register_device(struct clock_event_device *dev) + /* + * Noop handler when we shut down an event device + */ +-static void clockevents_handle_noop(struct clock_event_device *dev) ++void clockevents_handle_noop(struct clock_event_device *dev) + { + } + +@@ -186,7 +186,6 @@ void clockevents_exchange_device(struct clock_event_device *old, + * released list and do a notify add later. + */ + if (old) { +- old->event_handler = clockevents_handle_noop; + clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED); + list_del(&old->list); + list_add(&old->list, &clockevents_released); +diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c +index 5b86698..cdd12e2 100644 +--- a/kernel/time/tick-broadcast.c ++++ b/kernel/time/tick-broadcast.c +@@ -177,6 +177,8 @@ static void tick_do_periodic_broadcast(void) + */ + static void tick_handle_periodic_broadcast(struct clock_event_device *dev) + { ++ ktime_t next; ++ + tick_do_periodic_broadcast(); + + /* +@@ -187,10 +189,13 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev) + + /* + * Setup the next period for devices, which do not have +- * periodic mode: ++ * periodic mode. We read dev->next_event first and add to it ++ * when the event alrady expired. clockevents_program_event() ++ * sets dev->next_event only when the event is really ++ * programmed to the device. + */ +- for (;;) { +- ktime_t next = ktime_add(dev->next_event, tick_period); ++ for (next = dev->next_event; ;) { ++ next = ktime_add(next, tick_period); + + if (!clockevents_program_event(dev, next, ktime_get())) + return; +@@ -207,7 +212,7 @@ static void tick_do_broadcast_on_off(void *why) + struct clock_event_device *bc, *dev; + struct tick_device *td; + unsigned long flags, *reason = why; +- int cpu; ++ int cpu, bc_stopped; + + spin_lock_irqsave(&tick_broadcast_lock, flags); + +@@ -225,6 +230,8 @@ static void tick_do_broadcast_on_off(void *why) + if (!tick_device_is_functional(dev)) + goto out; + ++ bc_stopped = cpus_empty(tick_broadcast_mask); ++ + switch (*reason) { + case CLOCK_EVT_NOTIFY_BROADCAST_ON: + case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: +@@ -246,9 +253,10 @@ static void tick_do_broadcast_on_off(void *why) + break; + } + +- if (cpus_empty(tick_broadcast_mask)) +- clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); +- else { ++ if (cpus_empty(tick_broadcast_mask)) { ++ if (!bc_stopped) ++ clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); ++ } else if (bc_stopped) { + if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) + tick_broadcast_start_periodic(bc); + else +@@ -365,16 +373,8 @@ cpumask_t *tick_get_broadcast_oneshot_mask(void) + static int tick_broadcast_set_event(ktime_t expires, int force) + { + struct clock_event_device *bc = tick_broadcast_device.evtdev; +- ktime_t now = ktime_get(); +- int res; +- +- for(;;) { +- res = clockevents_program_event(bc, expires, now); +- if (!res || !force) +- return res; +- now = ktime_get(); +- expires = ktime_add(now, ktime_set(0, bc->min_delta_ns)); +- } ++ ++ return tick_dev_program_event(bc, expires, force); + } + + int tick_resume_broadcast_oneshot(struct clock_event_device *bc) +@@ -493,14 +493,52 @@ static void tick_broadcast_clear_oneshot(int cpu) + cpu_clear(cpu, tick_broadcast_oneshot_mask); + } + ++static void tick_broadcast_init_next_event(cpumask_t *mask, ktime_t expires) ++{ ++ struct tick_device *td; ++ int cpu; ++ ++ for_each_cpu_mask (cpu, *mask) { ++ td = &per_cpu(tick_cpu_device, cpu); ++ if (td->evtdev) ++ td->evtdev->next_event = expires; ++ } ++} ++ + /** + * tick_broadcast_setup_oneshot - setup the broadcast device + */ + void tick_broadcast_setup_oneshot(struct clock_event_device *bc) + { +- bc->event_handler = tick_handle_oneshot_broadcast; +- clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); +- bc->next_event.tv64 = KTIME_MAX; ++ /* Set it up only once ! */ ++ if (bc->event_handler != tick_handle_oneshot_broadcast) { ++ int was_periodic = bc->mode == CLOCK_EVT_MODE_PERIODIC; ++ int cpu = smp_processor_id(); ++ cpumask_t mask; ++ ++ bc->event_handler = tick_handle_oneshot_broadcast; ++ clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); ++ ++ /* Take the do_timer update */ ++ tick_do_timer_cpu = cpu; ++ ++ /* ++ * We must be careful here. There might be other CPUs ++ * waiting for periodic broadcast. We need to set the ++ * oneshot_mask bits for those and program the ++ * broadcast device to fire. ++ */ ++ mask = tick_broadcast_mask; ++ cpu_clear(cpu, mask); ++ cpus_or(tick_broadcast_oneshot_mask, ++ tick_broadcast_oneshot_mask, mask); ++ ++ if (was_periodic && !cpus_empty(mask)) { ++ tick_broadcast_init_next_event(&mask, tick_next_period); ++ tick_broadcast_set_event(tick_next_period, 1); ++ } else ++ bc->next_event.tv64 = KTIME_MAX; ++ } + } + + /* +diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c +index 1bea399..d106d61 100644 +--- a/kernel/time/tick-common.c ++++ b/kernel/time/tick-common.c +@@ -159,6 +159,7 @@ static void tick_setup_device(struct tick_device *td, + } else { + handler = td->evtdev->event_handler; + next_event = td->evtdev->next_event; ++ td->evtdev->event_handler = clockevents_handle_noop; + } + + td->evtdev = newdev; +diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h +index bb13f27..26b04aa 100644 +--- a/kernel/time/tick-internal.h ++++ b/kernel/time/tick-internal.h +@@ -17,6 +17,8 @@ extern void tick_handle_periodic(struct clock_event_device *dev); + extern void tick_setup_oneshot(struct clock_event_device *newdev, + void (*handler)(struct clock_event_device *), + ktime_t nextevt); ++extern int tick_dev_program_event(struct clock_event_device *dev, ++ ktime_t expires, int force); + extern int tick_program_event(ktime_t expires, int force); + extern void tick_oneshot_notify(void); + extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)); +diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c +index 0258d31..f3527f0 100644 +--- a/kernel/time/tick-oneshot.c ++++ b/kernel/time/tick-oneshot.c +@@ -23,24 +23,58 @@ + #include "tick-internal.h" + + /** +- * tick_program_event ++ * tick_program_event internal worker function + */ +-int tick_program_event(ktime_t expires, int force) ++int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires, ++ int force) + { +- struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; + ktime_t now = ktime_get(); ++ int i; + +- while (1) { ++ for (i = 0;;) { + int ret = clockevents_program_event(dev, expires, now); + + if (!ret || !force) + return ret; ++ ++ /* ++ * We tried 2 times to program the device with the given ++ * min_delta_ns. If that's not working then we double it ++ * and emit a warning. ++ */ ++ if (++i > 2) { ++ printk(KERN_WARNING "CE: __tick_program_event of %s is " ++ "stuck %llx %llx\n", dev->name ? dev->name : "?", ++ now.tv64, expires.tv64); ++ printk(KERN_WARNING ++ "CE: increasing min_delta_ns %ld to %ld nsec\n", ++ dev->min_delta_ns, dev->min_delta_ns << 1); ++ WARN_ON(1); ++ ++ /* Double the min. delta and try again */ ++ if (!dev->min_delta_ns) ++ dev->min_delta_ns = 5000; ++ else ++ dev->min_delta_ns <<= 1; ++ i = 0; ++ } ++ + now = ktime_get(); +- expires = ktime_add(now, ktime_set(0, dev->min_delta_ns)); ++ expires = ktime_add_ns(now, dev->min_delta_ns); + } + } + + /** ++ * tick_program_event ++ */ ++int tick_program_event(ktime_t expires, int force) ++{ ++ struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; ++ ++ return tick_dev_program_event(dev, expires, force); ++} ++ ++/** + * tick_resume_onshot - resume oneshot mode + */ + void tick_resume_oneshot(void) +@@ -61,7 +95,7 @@ void tick_setup_oneshot(struct clock_event_device *newdev, + { + newdev->event_handler = handler; + clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); +- clockevents_program_event(newdev, next_event, ktime_get()); ++ tick_dev_program_event(newdev, next_event, 1); + } + + /** +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0081-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook13.patch +++ linux-2.6.24/patches/0081-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook13.patch @@ -0,0 +1,66 @@ +From e8b65dedcbd9664949ed8e0163ecb73e4ac486c5 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Fri, 21 Nov 2008 14:57:23 -0500 +Subject: [PATCH 081/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook13 + +Ignore: yes +--- + debian/changelog | 45 +++++++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 45 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 8529e57..aed7438 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,48 @@ ++linux (2.6.24-19.41netbook13) hardy; urgency=low ++ ++ [Upstream Kernel Changes] ++ ++ * uaccess: add probe_kernel_write() ++ * kgdb: core ++ * consoles: polling support, kgdboc ++ * x86: kgdb support ++ * kgdb: document parameters ++ * kgdb-light-v10: fix kgdboc dynamic module configuration ++ * kgdb-light-v10: fix NMI hangs ++ * kgdb-light-v10: clocksource watchdog ++ * kgdb-light-v10: print breakpoint removed on exception ++ * kgdb-light-v10: x86 HW breakpoints ++ * kgdb: fix optional arch functions and probe_kernel_* ++ * kgdb: kgdboc pl011 I/O module ++ * kgdb: support for ARCH=arm ++ * kgdb: fix several kgdb regressions ++ * kgdb: Add kgdb internal test suite ++ * kgdb: Kconfig fix ++ * kgdb: allow static kgdbts boot configuration ++ * kgdb: Add documentation ++ * kgdb: documentation fixes ++ * kgdb: Fix SMP NMI kgdb_handle_exception exit race ++ * kgdb: Always use icache flush for sw breakpoints ++ * kgdb: debugger reboot notifier hook ++ * kgdb, modules: This allows for KGDB to better deal with autoloaded ++ modules. ++ * kgdb: stand alone 8250 for early debug ++ * kgdb, serial_core: early init API for kgdb8250 ++ * kgdb, x86: early trap init for early debug ++ * NET_POLL: Pass skb via NET_POLL rx routine ++ * kgdb: Implement kgdb over ethernet with NET_POLL ++ * kgdb, mips: This adds basic support to the MIPS architecture ++ * kgdb, mips: pad pt_regs on MIPS64 for function arguments in an ++ exception ++ * kgdb, powerpc, ppc: arch specific ppc and powerpc kgdb support ++ * kgdb: kgdboc console poll hooks for cpm uart ++ * kgdb: kgdboc console poll hooks for mpsc uart ++ * Misc fixes for kgdb build ++ * Added support for Ericsson USB 3G modem ++ * Turned on Ericsson 3G modem support in config.lpia ++ ++ -- Michael Frey Fri, 21 Nov 2008 14:52:40 -0500 ++ + linux (2.6.24-19.41netbook12) hardy; urgency=low + + [Colin Ian King] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0053-Modified-ata_piix.c-to-add-proper-PCI-ID-for-Chelsea.patch +++ linux-2.6.24/patches/0053-Modified-ata_piix.c-to-add-proper-PCI-ID-for-Chelsea.patch @@ -0,0 +1,27 @@ +From c0c41829ab4fb9f134b1ac2977db3a515329bf73 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 27 Aug 2008 11:09:57 -0400 +Subject: [PATCH 053/170] Modified ata_piix.c to add proper PCI ID for Chelsea ata controller Fix for LP#248835 + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/248835 +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/ata/ata_piix.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c +index 72dca47..a00abc5 100644 +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -702,7 +702,7 @@ static const struct ich_laptop ich_laptop[] = { + { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */ + { 0x24CA, 0x1025, 0x003d }, /* ICH4 on Acer TM290 */ + { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ +- { 0x811a, 0x8086, 0x8119 }, /* SCH on Chelsea */ ++ { 0x811A, 0x1509, 0x5001 }, /* SCH on Chelsea */ + { 0x27DF, 0x1028, 0x02b0 }, /* ICH7 on Belmont */ + /* end marker */ + { 0, } +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0132-UBUNTU-SAUCE-reorder-acpi-Makefile-avoiding-sysfs-du.patch +++ linux-2.6.24/patches/0132-UBUNTU-SAUCE-reorder-acpi-Makefile-avoiding-sysfs-du.patch @@ -0,0 +1,64 @@ +From 06b09f80aa62c5d7ae6f3cb46be56c6591b90033 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Mon, 6 Apr 2009 03:12:18 +0100 +Subject: [PATCH 132/170] UBUNTU: SAUCE: reorder acpi/Makefile avoiding sysfs duplicate insert warning + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/355977 + +We are seeing the following kernel warning on Hardy netbook kernels: + + [ 9.459204] WARNING: at .../fs/sysfs/dir.c:429 sysfs_add_one() + [ 9.459210] Pid: 1, comm: swapper Not tainted 2.6.24-24-lpia #3 + [ 9.459213] [] sysfs_add_one+0xd4/0x110 + [ 9.459220] [] create_dir+0x48/0x90 + [ 9.459227] [] sysfs_create_dir+0x29/0x50 + [ 9.459233] [] kobject_get+0xf/0x20 + [ 9.459239] [] kobject_add+0x93/0x1b0 + [ 9.459245] [] kobject_set_name+0x81/0xb0 + [ 9.459252] [] kernel_param_sysfs_setup+0x54/0xa0 + [ 9.459259] [] param_sysfs_init+0x10d/0x190 + [ 9.459266] [] kernel_init+0x131/0x320 + [ 9.459271] [] __switch_to+0x9e/0x150 + [ 9.459278] [] ret_from_fork+0x6/0x20 + [ 9.459284] [] kernel_init+0x0/0x320 + [ 9.459289] [] kernel_init+0x0/0x320 + [ 9.459295] [] kernel_thread_helper+0x7/0x10 + [...] + [ 9.459453] Module 'acpi' failed to be added to sysfs, error number -17 + +We are getting this message because we have two modules (both builtin) +which are using acpi. prefixes for their modules parameters. This triggers +the code in param_sysfs_builtin() to find two acpi modules and attempt +to create the acpi module parameters directory in sysfs twice, tripping +the warning. + +Reorder the linking of the acpi modules to place these together causing +their module entries to appear consecutivly in the module parameter +table and prevent the warning. + +Signed-off-by: Andy Whitcroft +Acked-by: Stefan Bader +Acked-by: Colin King +--- + drivers/acpi/Makefile | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile +index 9938d06..a2c731a 100644 +--- a/drivers/acpi/Makefile ++++ b/drivers/acpi/Makefile +@@ -48,10 +48,10 @@ obj-$(CONFIG_ACPI_DOCK) += dock.o + obj-$(CONFIG_ACPI_BAY) += bay.o + obj-$(CONFIG_ACPI_VIDEO) += video.o + obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o +-obj-$(CONFIG_ACPI_POWER) += power.o + obj-$(CONFIG_ACPI_PROCESSOR) += processor.o + obj-$(CONFIG_ACPI_CONTAINER) += container.o + obj-$(CONFIG_ACPI_THERMAL) += thermal.o ++obj-$(CONFIG_ACPI_POWER) += power.o + obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o + obj-$(CONFIG_ACPI_DEBUG) += debug.o + obj-$(CONFIG_ACPI_NUMA) += numa.o +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0020-kgdb-Add-documentation.patch +++ linux-2.6.24/patches/0020-kgdb-Add-documentation.patch @@ -0,0 +1,637 @@ +From f3f0a61e204c1f2d12f5e89ff83f2a01f5f22508 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:44 -0500 +Subject: [PATCH 020/170] kgdb: Add documentation + +Add in the kgdb documentation for kgdb. + +Signed-off-by: Jason Wessel +--- + Documentation/DocBook/Makefile | 2 +- + Documentation/DocBook/kgdb.tmpl | 435 +++++++++++++++++++++++++++++++++++++++ + MAINTAINERS | 6 + + include/linux/kgdb.h | 52 +++-- + 4 files changed, 473 insertions(+), 22 deletions(-) + create mode 100644 Documentation/DocBook/kgdb.tmpl + +diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile +index 4953bc2..3d26fdf 100644 +--- a/Documentation/DocBook/Makefile ++++ b/Documentation/DocBook/Makefile +@@ -8,7 +8,7 @@ + + DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \ + kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ +- procfs-guide.xml writing_usb_driver.xml \ ++ procfs-guide.xml writing_usb_driver.xml kgdb.xml \ + kernel-api.xml filesystems.xml lsm.xml usb.xml \ + gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ + genericirq.xml s390-drivers.xml uio-howto.xml +diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl +new file mode 100644 +index 0000000..95e5f84 +--- /dev/null ++++ b/Documentation/DocBook/kgdb.tmpl +@@ -0,0 +1,435 @@ ++ ++ ++ ++ ++ ++ Using kgdb and the kgdb Internals ++ ++ ++ ++ Jason ++ Wessel ++ ++
++ jason.wessel@windriver.com ++
++
++
++
++ ++ ++ ++ Tom ++ Rini ++ ++
++ trini@kernel.crashing.org ++
++
++
++
++ ++ ++ ++ Amit S. ++ Kale ++ ++
++ amitkale@linsyssoft.com ++
++
++
++
++ ++ ++ 2008 ++ Wind River Systems, Inc. ++ ++ ++ 2004-2005 ++ MontaVista Software, Inc. ++ ++ ++ 2004 ++ Amit S. Kale ++ ++ ++ ++ ++ This file is licensed under the terms of the GNU General Public License ++ version 2. This program is licensed "as is" without any warranty of any ++ kind, whether express or implied. ++ ++ ++ ++
++ ++ ++ ++ Introduction ++ ++ kgdb is a source level debugger for linux kernel. It is used along ++ with gdb to debug a linux kernel. The expectation is that gdb can ++ be used to "break in" to the kernel to inspect memory, variables ++ and look through a cal stack information similar to what an ++ application developer would use gdb for. It is possible to place ++ breakpoints in kernel code and perform some limited execution ++ stepping. ++ ++ ++ Two machines are required for using kgdb. One of these machines is a ++ development machine and the other is a test machine. The kernel ++ to be debugged runs on the test machine. The development machine ++ runs an instance of gdb against the vmlinux file which contains ++ the symbols (not boot image such as bzImage, zImage, uImage...). ++ In gdb the developer specifies the connection parameters and ++ connects to kgdb. Depending on which kgdb I/O modules exist in ++ the kernel for a given architecture, it may be possible to debug ++ the test machine's kernel with the development machine using a ++ rs232 or ethernet connection. ++ ++ ++ ++ Compiling a kernel ++ ++ To enable CONFIG_KGDB, look under the "Kernel debugging" ++ and then select "KGDB: kernel debugging with remote gdb". ++ ++ ++ Next you should choose one of more I/O drivers to interconnect debugging ++ host and debugged target. Early boot debugging requires a KGDB ++ I/O driver that supports early debugging and the driver must be ++ built into the kernel directly. Kgdb I/O driver configuration ++ takes place via kernel or module parameters, see following ++ chapter. ++ ++ ++ The kgdb test compile options are described in the kgdb test suite chapter. ++ ++ ++ ++ ++ Enable kgdb for debugging ++ ++ In order to use kgdb you must activate it by passing configuration ++ information to one of the kgdb I/O drivers. If you do not pass any ++ configuration information kgdb will not do anything at all. Kgdb ++ will only actively hook up to the kernel trap hooks if a kgdb I/O ++ driver is loaded and configured. If you unconfigure a kgdb I/O ++ driver, kgdb will unregister all the kernel hook points. ++ ++ ++ All drivers can be reconfigured at run time, if ++ CONFIG_SYSFS and CONFIG_MODULES ++ are enabled, by echo'ing a new config string to ++ /sys/module/<driver>/parameter/<option>. ++ The driver can be unconfigured by passing an empty string. You cannot ++ change the configuration while the debugger is attached. Make sure ++ to detach the debugger with the detach command ++ prior to trying unconfigure a kgdb I/O driver. ++ ++ ++ Kernel parameter: kgdbwait ++ ++ The Kernel command line option kgdbwait makes ++ kgdb wait for a debugger connection during booting of a kernel. You ++ can only use this option you compiled a kgdb I/O driver into the ++ kernel and you specified the I/O driver configuration as a kernel ++ command line option. The kgdbwait parameter should always follow the ++ configuration parameter for the kgdb I/O driver in the kernel ++ command line else the I/O driver will not be configured prior to ++ asking the kernel to use it to wait. ++ ++ ++ The kernel will stop and wait as early as the I/O driver and ++ architecture will allow when you use this option. If you build the ++ kgdb I/O driver as a kernel module kgdbwait will not do anything. ++ ++ ++ ++ Kernel parameter: kgdboc ++ ++ The kgdboc driver was originally an abbreviation meant to stand for ++ "kgdb over console". Kgdboc is designed to work with a single ++ serial port as example, and it was meant to cover the circumstance ++ where you wanted to use a serial console as your primary console as ++ well as using it to perform kernel debugging. ++ ++ ++ Using kgdboc ++ ++ You can configure kgdboc via sysfs or a module or kernel boot line ++ parameter depending on if you build with CONFIG_KGDBOC as a module ++ or built-in. ++ ++ From the module load or build-in ++ kgdboc=<tty-device>,[baud] ++ ++ The example here would be if your console port was typically ttyS0, you would use something like kgdboc=ttyS0,115200 or on the ARM Versatile AB you would likely use kgdboc=ttyAMA0,115200 ++ ++ ++ From sysfs ++ echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc ++ ++ ++ ++ ++ NOTE: Kgdboc does not support interrupting the target via the ++ gdb remote protocol. You must manually send a sysrq-g unless you ++ have a proxy that splits console output to a terminal problem and ++ has a separate port for the debugger to connect to that sends the ++ sysrq-g for you. ++ ++ When using kgdboc with no debugger proxy, you can end up ++ connecting the debugger for one of two entry points. If an ++ exception occurs after you have loaded kgdboc a message should print ++ on the console stating it is waiting for the debugger. In case you ++ disconnect your terminal program and then connect the debugger in ++ its place. If you want to interrupt the target system and forcibly ++ enter a debug session you have to issue a Sysrq sequence and then ++ type the letter g. Then you disconnect the ++ terminal session and connect gdb. Your options if you don't like ++ this are to hack gdb to send the sysrq-g for you as well as on the ++ initial connect, or to use a debugger proxy that allows an ++ unmodified gdb to do the debugging. ++ ++ ++ ++ kgdboc internals ++ ++ The kgdboc driver is actually a very thin driver that relies on the ++ underlying low level to the hardware driver having "polling hooks" ++ which the to which the tty driver is attached. In the initial ++ implementation of kgdboc it the serial_core was changed to expose a ++ low level uart hook for doing polled mode reading and writing of a ++ single character while in an atomic context. When kgdb makes an I/O ++ request to the debugger, kgdboc invokes a call back in the serial ++ core which in turn uses the call back in the uart driver. It is ++ certainly possible to extend kgdboc to work with non-uart based ++ consoles in the future. ++ ++ ++ When using kgdboc with a uart, the uart driver must implement two callbacks in the struct uart_ops. Example from drivers/8250.c: ++#ifdef CONFIG_CONSOLE_POLL ++ .poll_get_char = serial8250_get_poll_char, ++ .poll_put_char = serial8250_put_poll_char, ++#endif ++ ++ Any implementation specifics around creating a polling driver use the ++ #ifdef CONFIG_CONSOLE_POLL, as shown above. ++ Keep in mind that polling hooks have to be implemented in such a way ++ that they can be called from an atomic context and have to restore ++ the state of the uart chip on return such that the system can return ++ to normal when the debugger detaches. You need to be very careful ++ with any kind of lock you consider, because failing here is most ++ going to mean pressing the reset button. ++ ++ ++ ++ ++ Kernel parameter: kgdbcon ++ ++ Kgdb supports using the gdb serial protocol to send console messages ++ to the debugger when the debugger is connected and running. There ++ are two ways to activate this feature. ++ ++ Activate with the kernel command line option: ++ kgdbcon ++ ++ Use sysfs before configuring an io driver ++ ++ echo 1 > /sys/module/kgdb/parameters/kgdb_use_con ++ ++ ++ NOTE: If you do this after you configure the kgdb I/O driver, the ++ setting will not take effect until the next point the I/O is ++ reconfigured. ++ ++ ++ ++ ++ ++ IMPORTANT NOTE: Using this option with kgdb over the console ++ (kgdboc) or kgdb over ethernet (kgdboe) is not supported. ++ ++ ++ ++ ++ Connecting gdb ++ ++ If you are using kgdboc, you need to have used kgdbwait as a boot ++ argument, issued a sysrq-g, or the system you are going to debug ++ has already taken an exception and is waiting for the debugger to ++ attach before you can connect gdb. ++ ++ ++ If you are not using different kgdb I/O driver other than kgdboc, ++ you should be able to connect and the target will automatically ++ respond. ++ ++ ++ Example (using a serial port): ++ ++ ++ % gdb ./vmlinux ++ (gdb) set remotebaud 115200 ++ (gdb) target remote /dev/ttyS0 ++ ++ ++ Example (kgdb to a terminal server): ++ ++ ++ % gdb ./vmlinux ++ (gdb) target remote udp:192.168.2.2:6443 ++ ++ ++ Example (kgdb over ethernet): ++ ++ ++ % gdb ./vmlinux ++ (gdb) target remote udp:192.168.2.2:6443 ++ ++ ++ Once connected, you can debug a kernel the way you would debug an ++ application program. ++ ++ ++ If you are having problems connecting or something is going ++ seriously wrong while debugging, it will most often be the case ++ that you want to enable gdb to be verbose about its target ++ communications. You do this prior to issuing the target ++ remote command by typing in: set remote debug 1 ++ ++ ++ ++ kgdb Test Suite ++ ++ When kgdb is enabled in the kernel config you can also elect to ++ enable the config parameter KGDB_TESTS. Turning this on will ++ enable a special kgdb I/O module which is designed to test the ++ kgdb internal functions. ++ ++ ++ The kgdb tests are mainly intended for developers to test the kgdb ++ internals as well as a tool for developing a new kgdb architecture ++ specific implementation. These tests are not really for end users ++ of the Linux kernel. The primary source of documentation would be ++ to look in the drivers/misc/kgdbts.c file. ++ ++ ++ The kgdb test suite can also be configured at compile time to run ++ the core set of tests by setting the kernel config parameter ++ KGDB_TESTS_ON_BOOT. This particular option is aimed at automated ++ regression testing and does not require modifying the kernel boot ++ config arguments. If this is turned on, the kgdb test suite can ++ be disabled by specifying "kgdbts=" as a kernel boot argument. ++ ++ ++ ++ Architecture Specifics ++ ++ Kgdb is organized into three basic components: ++ ++ kgdb core ++ ++ The kgdb core is found in kernel/kgdb.c. It contains: ++ ++ All the logic to implement the gdb serial protocol ++ A generic OS exception handler which includes sync'ing the processors into a stopped state on an multi cpu system. ++ The API to talk to the kgdb I/O drivers ++ The API to make calls to the arch specific kgdb implementation ++ The logic to perform safe memory reads and writes to memory while using the debugger ++ A full implementation for software breakpoints unless overridden by the arch ++ ++ ++ ++ kgdb arch specific implementation ++ ++ This implementation is generally found in arch/*/kernel/kgdb.c. ++ As an example, arch/x86/kernel/kgdb.c contains the specifics to ++ implement HW breakpoint as well as the initialization to ++ dynamically register and unregister for the trap handlers on ++ this architecture. The arch specific portion implements: ++ ++ contains an arch specific trap catcher which ++ invokes kgdb_handle_exception() to start kgdb about doing its ++ work ++ translation to and from gdb specific packet format to pt_regs ++ Registration and unregistration of architecture specific trap hooks ++ Any special exception handling and cleanup ++ NMI exception handling and cleanup ++ (optional)HW breakpoints ++ ++ ++ ++ kgdb I/O driver ++ ++ Each kgdb I/O driver has to provide an configuration ++ initialization, and cleanup handler for when it ++ unloads/unconfigures. Any given kgdb I/O driver has to operate ++ very closely with the hardware and must do it in such a way that ++ does not enable interrupts or change other parts of the system ++ context without completely restoring them. Every kgdb I/O ++ driver must provide a read and write character interface. The ++ kgdb core will repeatedly "poll" a kgdb I/O driver for characters ++ when it needs input. The I/O driver is expected to return ++ immediately if there is no data available. Doing so allows for ++ the future possibility to touch watch dog hardware in such a way ++ as to have a target system not reset when these are enabled. ++ ++ ++ ++ ++ ++ If you are intent on adding kgdb architecture specific support ++ for a new architecture, the architecture should define ++ HAVE_ARCH_KGDB in the architecture specific ++ Kconfig file. This will enable kgdb for the architecture, and ++ at that point you must create an architecture specific kgdb ++ implementation. ++ ++ ++ There are a few flags which must be set on every architecture in ++ their <asm/kgdb.h> file. These are: ++ ++ ++ ++ NUMREGBYTES: The size in bytes of all of the registers, so ++ that we can ensure they will all fit into a packet. ++ ++ ++ BUFMAX: The size in bytes of the buffer GDB will read into. ++ This must be larger than NUMREGBYTES. ++ ++ ++ CACHE_FLUSH_IS_SAFE: Set to 1 if it is always safe to call ++ flush_cache_range or flush_icache_range. On some architectures, ++ these functions may not be safe to call on SMP since we keep other ++ CPUs in a holding pattern. ++ ++ ++ ++ ++ ++ There are also the following functions for the common backend, ++ found in kernel/kgdb.c, that must be supplied by the ++ architecture-specific backend unless marked as (optional), in ++ which case a default function maybe used if the architecture ++ does not need to provide a specific implementation. ++ ++!Iinclude/linux/kgdb.h ++ ++ ++ Credits ++ ++ The following people have contributed to this document: ++ ++ Amit Kaleamitkale@linsyssoft.com ++ Tom Rinitrini@kernel.crashing.org ++ Jason Wesseljason.wessel@windriver.com ++ ++ ++ ++
++ +diff --git a/MAINTAINERS b/MAINTAINERS +index 2340cfb..fbb4fc3 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -2233,6 +2233,12 @@ L: linux-kernel@vger.kernel.org + L: kexec@lists.infradead.org + S: Maintained + ++KGDB ++P: Jason Wessel ++M: jason.wessel@windriver.com ++L: kgdb-bugreport@lists.sourceforge.net ++S: Maintained ++ + KPROBES + P: Prasanna S Panchamukhi + M: prasanna@in.ibm.com +diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h +index b0985b7..9757b1a 100644 +--- a/include/linux/kgdb.h ++++ b/include/linux/kgdb.h +@@ -22,31 +22,34 @@ + + struct pt_regs; + +-/* +- * kgdb_skipexception - Bail out of KGDB when we've been triggered. ++/** ++ * kgdb_skipexception - (optional) exit kgdb_handle_exception early + * @exception: Exception vector number + * @regs: Current &struct pt_regs. + * +- * On some architectures we need to skip a breakpoint exception when +- * it occurs after a breakpoint has been removed. ++ * On some architectures it is required to skip a breakpoint ++ * exception when it occurs after a breakpoint has been removed. ++ * This can be implemented in the architecture specific portion of ++ * for kgdb. + */ + extern int kgdb_skipexception(int exception, struct pt_regs *regs); + +-/* +- * kgdb_post_primary_code - Save error vector/code numbers. ++/** ++ * kgdb_post_primary_code - (optional) Save error vector/code numbers. + * @regs: Original pt_regs. + * @e_vector: Original error vector. + * @err_code: Original error code. + * +- * This is needed on architectures which support SMP and KGDB. +- * This function is called after all the secondary cpus have been put +- * to a know spin state and the primary CPU has control over KGDB. ++ * This is usually needed on architectures which support SMP and ++ * KGDB. This function is called after all the secondary cpus have ++ * been put to a know spin state and the primary CPU has control over ++ * KGDB. + */ + extern void kgdb_post_primary_code(struct pt_regs *regs, int e_vector, + int err_code); + +-/* +- * kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb. ++/** ++ * kgdb_disable_hw_debug - (optional) Disable hardware debugging hook + * @regs: Current &struct pt_regs. + * + * This function will be called if the particular architecture must +@@ -59,7 +62,14 @@ struct tasklet_struct; + struct task_struct; + struct uart_port; + +-/* To enter the debugger explicitly. */ ++/** ++ * kgdb_breakpoint - compiled in breakpoint ++ * ++ * This will be impelmented a static inline per architecture. This ++ * function is called by the kgdb core to execute an architecture ++ * specific trap to cause kgdb to enter the exception processing. ++ * ++ */ + void kgdb_breakpoint(void); + + extern int kgdb_connected; +@@ -102,7 +112,7 @@ struct kgdb_bkpt { + * Functions each KGDB-supporting architecture must provide: + */ + +-/* ++/** + * kgdb_arch_init - Perform any architecture specific initalization. + * + * This function will handle the initalization of any architecture +@@ -110,7 +120,7 @@ struct kgdb_bkpt { + */ + extern int kgdb_arch_init(void); + +-/* ++/** + * kgdb_arch_exit - Perform any architecture specific uninitalization. + * + * This function will handle the uninitalization of any architecture +@@ -118,7 +128,7 @@ extern int kgdb_arch_init(void); + */ + extern void kgdb_arch_exit(void); + +-/* ++/** + * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs + * @gdb_regs: A pointer to hold the registers in the order GDB wants. + * @regs: The &struct pt_regs of the current process. +@@ -128,7 +138,7 @@ extern void kgdb_arch_exit(void); + */ + extern void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs); + +-/* ++/** + * sleeping_thread_to_gdb_regs - Convert ptrace regs to GDB regs + * @gdb_regs: A pointer to hold the registers in the order GDB wants. + * @p: The &struct task_struct of the desired process. +@@ -143,7 +153,7 @@ extern void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs); + extern void + sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p); + +-/* ++/** + * gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs. + * @gdb_regs: A pointer to hold the registers we've received from GDB. + * @regs: A pointer to a &struct pt_regs to hold these values in. +@@ -153,7 +163,7 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p); + */ + extern void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs); + +-/* ++/** + * kgdb_arch_handle_exception - Handle architecture specific GDB packets. + * @vector: The error vector of the exception that happened. + * @signo: The signal number of the exception that happened. +@@ -175,7 +185,7 @@ kgdb_arch_handle_exception(int vector, int signo, int err_code, + char *remcom_out_buffer, + struct pt_regs *regs); + +-/* ++/** + * kgdb_roundup_cpus - Get other CPUs into a holding pattern + * @flags: Current IRQ state + * +@@ -198,7 +208,7 @@ extern int kgdb_validate_break_address(unsigned long addr); + extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr); + extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle); + +-/* ++/** + * struct kgdb_arch - Describe architecture specific values. + * @gdb_bpt_instr: The instruction to trigger a breakpoint. + * @flags: Flags for the breakpoint, currently just %KGDB_HW_BREAKPOINT. +@@ -227,7 +237,7 @@ struct kgdb_arch { + void (*correct_hw_break)(void); + }; + +-/* ++/** + * struct kgdb_io - Describe the interface for an I/O driver to talk with KGDB. + * @name: Name of the I/O driver. + * @read_char: Pointer to a function that will return one char. +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0093-This-patch-provides-an-new-kernel-boot-parameter-del.patch +++ linux-2.6.24/patches/0093-This-patch-provides-an-new-kernel-boot-parameter-del.patch @@ -0,0 +1,56 @@ +From 011a451925d26befa53e1414950735e5726f8740 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 17 Dec 2008 17:20:26 -0500 +Subject: [PATCH 093/170] This patch provides an new kernel boot parameter "delayloop" to disable tsc_delay() and use delay_loop() instead. (LP: #304247) + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/304247 +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + arch/x86/lib/delay_32.c | 20 ++++++++++++++++++-- + 1 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/lib/delay_32.c b/arch/x86/lib/delay_32.c +index aad9d95..2f99db2 100644 +--- a/arch/x86/lib/delay_32.c ++++ b/arch/x86/lib/delay_32.c +@@ -23,6 +23,19 @@ + # include + #endif + ++static int read_tsc_valid = 0; ++static int no_tsc_delay = 0; ++ ++static int __init notscdelay_setup(char *str) ++{ ++ no_tsc_delay = 1; ++ printk(KERN_INFO "Disabling TSC delay\n"); ++ return 1; ++} ++ ++__setup("delayloop", notscdelay_setup); ++ ++ + /* simple loop based delay: */ + static void delay_loop(unsigned long loops) + { +@@ -60,12 +73,15 @@ static void (*delay_fn)(unsigned long) = delay_loop; + + void use_tsc_delay(void) + { +- delay_fn = delay_tsc; ++ read_tsc_valid = 1; ++ ++ if (!no_tsc_delay) ++ delay_fn = delay_tsc; + } + + int read_current_timer(unsigned long *timer_val) + { +- if (delay_fn == delay_tsc) { ++ if (read_tsc_valid) { + rdtscl(*timer_val); + return 0; + } +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0045-Updated-Memory-Stick-driver.patch +++ linux-2.6.24/patches/0045-Updated-Memory-Stick-driver.patch @@ -0,0 +1,7109 @@ +From 10c0875f48e638ea65bf4770c412638a8bd3d6b1 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 16 Jul 2008 16:46:16 +0100 +Subject: [PATCH 045/170] Updated Memory Stick driver + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/mmc/ms/Makefile | 4 +- + drivers/mmc/ms/flash_bd.c | 867 ++++++++++++ + drivers/mmc/ms/jmb38x_ms.c | 249 ++-- + drivers/mmc/ms/jmb38x_xd.c | 780 +++++++++++ + drivers/mmc/ms/linux/flash_bd.h | 119 ++ + drivers/mmc/ms/linux/memstick.h | 346 +++++ + drivers/mmc/ms/linux/xd_card.h | 248 ++++ + drivers/mmc/ms/memstick.c | 87 +- + drivers/mmc/ms/mspro_block.c | 582 ++++---- + drivers/mmc/ms/xd_card_blk.c | 2955 +++++++++++++++++++++++++++++++++++++++ + drivers/mmc/ms/xd_card_ecc.c | 167 +++ + 11 files changed, 5974 insertions(+), 430 deletions(-) + create mode 100755 drivers/mmc/ms/flash_bd.c + create mode 100755 drivers/mmc/ms/jmb38x_xd.c + create mode 100755 drivers/mmc/ms/linux/flash_bd.h + create mode 100755 drivers/mmc/ms/linux/memstick.h + create mode 100755 drivers/mmc/ms/linux/xd_card.h + create mode 100755 drivers/mmc/ms/xd_card_blk.c + create mode 100755 drivers/mmc/ms/xd_card_ecc.c + +diff --git a/drivers/mmc/ms/Makefile b/drivers/mmc/ms/Makefile +index 3f82524..409d9b0 100644 +--- a/drivers/mmc/ms/Makefile ++++ b/drivers/mmc/ms/Makefile +@@ -2,5 +2,7 @@ ifeq ($(CONFIG_MMC_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG + endif + +-obj-$(CONFIG_MSPRO) += memstick.o mspro_block.o jmb38x_ms.o ++obj-$(CONFIG_MSPRO) += memstick.o mspro_block.o xd_card.o flash_bd.o jmb38x_ms.o jmb38x_xd.o ++ ++xd_card-objs := xd_card_blk.o xd_card_ecc.o + +diff --git a/drivers/mmc/ms/flash_bd.c b/drivers/mmc/ms/flash_bd.c +new file mode 100755 +index 0000000..6fe7d14 +--- /dev/null ++++ b/drivers/mmc/ms/flash_bd.c +@@ -0,0 +1,867 @@ ++/* ++ * flash_bd.c - Simple flash to block device translation layer ++ * ++ * Copyright (C) 2008 Alex Dubov ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include "linux/flash_bd.h" ++#include ++#include ++#include ++#include ++#include ++ ++struct flash_bd { ++ unsigned int zone_cnt; ++ unsigned int phy_block_cnt; ++ unsigned int log_block_cnt; ++ unsigned int page_cnt; ++ unsigned int page_size; ++ unsigned int block_size; ++ unsigned int block_addr_bits; ++ ++ unsigned int *free_cnt; ++ unsigned int *block_table; ++ unsigned long *erase_map; ++ unsigned long *data_map; ++ ++ unsigned long long byte_offset; ++ unsigned int t_count; ++ unsigned int rem_count; ++ ++ unsigned int w_log_block; ++ unsigned int w_src_block; ++ unsigned int w_dst_block; ++ ++ unsigned int buf_offset; /* offset in the current block*/ ++ unsigned int buf_page_off; ++ unsigned int buf_count; /* count due in the current block */ ++ unsigned int buf_page_cnt; ++ unsigned int req_count; /* expected count for the current cmd*/ ++ ++ unsigned int last_count; ++ int last_error; ++ ++ int (*cmd_handler)(struct flash_bd *fbd, ++ struct flash_bd_request *req); ++ unsigned int p_line_size; ++ char *p_line; ++}; ++ ++/* For each block two bits are maintained: ++ * Block status erase_map data_map ++ * unallocated 0 0 ++ * clean 1 0 ++ * semi-filled 1 1 <- not in use ++ * full 0 1 ++ * ++ */ ++ ++static int h_flash_bd_read(struct flash_bd *fbd, struct flash_bd_request *req); ++static int h_flash_bd_write(struct flash_bd *fbd, struct flash_bd_request *req); ++static int h_flash_bd_write_inc(struct flash_bd *fbd, ++ struct flash_bd_request *req); ++static int h_flash_bd_erase_src(struct flash_bd *fbd, ++ struct flash_bd_request *req); ++static int h_flash_bd_erase_dst(struct flash_bd *fbd, ++ struct flash_bd_request *req); ++ ++static void flash_bd_mark_used(struct flash_bd *fbd, unsigned int phy_block) ++{ ++ if (!test_bit(phy_block, fbd->data_map)) { ++ unsigned int zone = phy_block >> fbd->block_addr_bits; ++ if (fbd->free_cnt[zone]) ++ fbd->free_cnt[zone]--; ++ } ++ ++ set_bit(phy_block, fbd->data_map); ++ clear_bit(phy_block, fbd->erase_map); ++} ++ ++static void flash_bd_mark_erased(struct flash_bd *fbd, unsigned int phy_block) ++{ ++ if (test_bit(phy_block, fbd->data_map)) { ++ unsigned int zone = phy_block >> fbd->block_addr_bits; ++ fbd->free_cnt[zone]++; ++ } ++ ++ clear_bit(phy_block, fbd->data_map); ++ set_bit(phy_block, fbd->erase_map); ++} ++ ++struct flash_bd* flash_bd_init(unsigned int zone_cnt, ++ unsigned int phy_block_cnt, ++ unsigned int log_block_cnt, ++ unsigned int page_cnt, ++ unsigned int page_size) ++ ++{ ++ unsigned int cnt; ++ struct flash_bd *fbd = kzalloc(sizeof(struct flash_bd), GFP_KERNEL); ++ ++ if (!fbd) ++ return NULL; ++ ++ fbd->zone_cnt = zone_cnt; ++ fbd->phy_block_cnt = phy_block_cnt; ++ fbd->log_block_cnt = log_block_cnt; ++ fbd->page_cnt = page_cnt; ++ fbd->page_size = page_size; ++ fbd->block_size = page_size * page_cnt; ++ ++ fbd->block_addr_bits = fls(fbd->phy_block_cnt - 1); ++ if ((1 << fbd->block_addr_bits) < fbd->phy_block_cnt) ++ fbd->block_addr_bits++; ++ ++ cnt = (fbd->block_addr_bits + 3) / 4; ++ ++ if (fbd->zone_cnt < 2) ++ /* */ ++ fbd->p_line_size = 2 * cnt + 5; ++ else { ++ /* : */ ++ fbd->p_line_size = 2 * cnt; ++ cnt = fls(fbd->zone_cnt - 1); ++ if ((1 << cnt) < fbd->zone_cnt) ++ cnt++; ++ ++ cnt = (cnt + 3) / 4; ++ fbd->p_line_size += cnt + 7; ++ } ++ ++ fbd->p_line = kmalloc(fbd->p_line_size, GFP_KERNEL); ++ if (!fbd->p_line) ++ goto err_out; ++ ++ fbd->free_cnt = kmalloc(sizeof(unsigned int) * fbd->zone_cnt, ++ GFP_KERNEL); ++ if (!fbd->free_cnt) ++ goto err_out; ++ ++ for (cnt = 0; cnt < fbd->zone_cnt; ++cnt) ++ fbd->free_cnt[cnt] = fbd->phy_block_cnt; ++ ++ fbd->block_table = kmalloc(sizeof(unsigned int) ++ * (fbd->zone_cnt << fbd->block_addr_bits), ++ GFP_KERNEL); ++ if (!fbd->block_table) ++ goto err_out; ++ ++ for (cnt = 0; cnt < (fbd->zone_cnt << fbd->block_addr_bits); ++cnt) ++ fbd->block_table[cnt] = FLASH_BD_INVALID; ++ ++ fbd->erase_map = kzalloc(BITS_TO_LONGS(fbd->zone_cnt ++ << fbd->block_addr_bits) ++ * sizeof(unsigned long), GFP_KERNEL); ++ if (!fbd->erase_map) ++ goto err_out; ++ ++ fbd->data_map = kzalloc(BITS_TO_LONGS(fbd->zone_cnt ++ << fbd->block_addr_bits) ++ * sizeof(unsigned long), GFP_KERNEL); ++ if (!fbd->data_map) ++ goto err_out; ++ ++ return fbd; ++ ++err_out: ++ flash_bd_destroy(fbd); ++ return NULL; ++} ++EXPORT_SYMBOL(flash_bd_init); ++ ++void flash_bd_destroy(struct flash_bd *fbd) ++{ ++ if (!fbd) ++ return; ++ ++ kfree(fbd->free_cnt); ++ kfree(fbd->block_table); ++ kfree(fbd->erase_map); ++ kfree(fbd->data_map); ++ kfree(fbd->p_line); ++ kfree(fbd); ++} ++EXPORT_SYMBOL(flash_bd_destroy); ++ ++unsigned int flash_bd_get_logical(struct flash_bd *fbd, unsigned int phy_block) ++{ ++ unsigned int cnt; ++ unsigned int zone = phy_block >> fbd->block_addr_bits; ++ ++ if (phy_block == FLASH_BD_INVALID) ++ return FLASH_BD_INVALID; ++ ++ for (cnt = zone << fbd->block_addr_bits; ++ cnt < ((zone + 1) << fbd->block_addr_bits); ++ ++cnt) { ++ if (fbd->block_table[cnt] == phy_block) ++ return cnt; ++ } ++ return FLASH_BD_INVALID; ++} ++ ++unsigned int flash_bd_get_physical(struct flash_bd *fbd, unsigned int zone, ++ unsigned int log_block) ++{ ++ if (log_block == FLASH_BD_INVALID ++ || log_block >= fbd->log_block_cnt) ++ return FLASH_BD_INVALID; ++ ++ log_block |= zone << fbd->block_addr_bits; ++ ++ return fbd->block_table[log_block] == FLASH_BD_INVALID ++ ? FLASH_BD_INVALID ++ : (fbd->block_table[log_block] ++ & ((1 << fbd->block_addr_bits) - 1)); ++} ++EXPORT_SYMBOL(flash_bd_get_physical); ++ ++int flash_bd_set_empty(struct flash_bd *fbd, unsigned int zone, ++ unsigned int phy_block, int erased) ++{ ++ unsigned int log_block; ++ ++ if (phy_block == FLASH_BD_INVALID ++ || phy_block >= fbd->phy_block_cnt) ++ return -EINVAL; ++ ++ phy_block |= zone << fbd->block_addr_bits; ++ ++ if (test_bit(phy_block, fbd->data_map)) { ++ log_block = flash_bd_get_logical(fbd, phy_block); ++ if (log_block != FLASH_BD_INVALID) ++ fbd->block_table[log_block] = FLASH_BD_INVALID; ++ ++ clear_bit(phy_block, fbd->data_map); ++ fbd->free_cnt[zone]++; ++ } ++ ++ if (erased) ++ set_bit(phy_block, fbd->erase_map); ++ ++ return 0; ++} ++EXPORT_SYMBOL(flash_bd_set_empty); ++ ++int flash_bd_set_full(struct flash_bd *fbd, unsigned int zone, ++ unsigned int phy_block, unsigned int log_block) ++{ ++ if (phy_block == FLASH_BD_INVALID ++ || phy_block >= fbd->phy_block_cnt) ++ return -EINVAL; ++ ++ phy_block |= zone << fbd->block_addr_bits; ++ ++ if (log_block == FLASH_BD_INVALID) { ++ if (test_bit(phy_block, fbd->data_map)) { ++ log_block = flash_bd_get_logical(fbd, phy_block); ++ if (log_block != FLASH_BD_INVALID) ++ fbd->block_table[log_block] = FLASH_BD_INVALID; ++ } ++ } else if (log_block < fbd->log_block_cnt) { ++ if (test_bit(phy_block, fbd->data_map)) ++ return -EEXIST; ++ ++ log_block |= zone << fbd->block_addr_bits; ++ fbd->block_table[log_block] = phy_block; ++ } else ++ return -EINVAL; ++ ++ ++ if (!test_bit(phy_block, fbd->data_map)) { ++ set_bit(phy_block, fbd->data_map); ++ if (fbd->free_cnt[zone]) ++ fbd->free_cnt[zone]--; ++ } ++ ++ clear_bit(phy_block, fbd->erase_map); ++ return 0; ++} ++EXPORT_SYMBOL(flash_bd_set_full); ++ ++int flash_bd_start_writing(struct flash_bd *fbd, unsigned long long offset, ++ unsigned int count) ++{ ++ fbd->byte_offset = offset; ++ fbd->t_count = 0; ++ fbd->rem_count = count; ++ ++ fbd->cmd_handler = h_flash_bd_write; ++ ++ return 0; ++} ++EXPORT_SYMBOL(flash_bd_start_writing); ++ ++int flash_bd_start_reading(struct flash_bd *fbd, unsigned long long offset, ++ unsigned int count) ++{ ++ fbd->byte_offset = offset; ++ fbd->t_count = 0; ++ fbd->rem_count = count; ++ fbd->cmd_handler = h_flash_bd_read; ++ fbd->buf_offset = 0; ++ fbd->buf_count = 0; ++ fbd->last_count = 0; ++ fbd->last_error = 0; ++ fbd->req_count = 0; ++ ++ return 0; ++} ++EXPORT_SYMBOL(flash_bd_start_reading); ++ ++int flash_bd_next_req(struct flash_bd *fbd, struct flash_bd_request *req, ++ unsigned int count, int error) ++{ ++ if (!fbd->cmd_handler) ++ return fbd->last_error; ++ ++ fbd->last_count = count; ++ fbd->last_error = error; ++ ++ return (fbd->cmd_handler)(fbd, req); ++} ++EXPORT_SYMBOL(flash_bd_next_req); ++ ++/* Nothing interesting for now */ ++unsigned int flash_bd_end(struct flash_bd *fbd) ++{ ++ return fbd->t_count; ++} ++EXPORT_SYMBOL(flash_bd_end); ++ ++static void flash_bd_print_line(struct flash_bd *fbd, unsigned int log_block) ++{ ++ unsigned int zone = log_block / fbd->log_block_cnt; ++ unsigned int phy_block; ++ unsigned int line_pos = 0, b_fmt; ++ char s_fmt[] = "%08x"; ++ ++ log_block = log_block % fbd->log_block_cnt; ++ if (zone >= fbd->zone_cnt) ++ goto fill_out; ++ ++ phy_block = flash_bd_get_physical(fbd, zone, log_block); ++ ++ if (fbd->zone_cnt > 1) { ++ b_fmt = fls(fbd->zone_cnt - 1); ++ if ((1 << b_fmt) < fbd->zone_cnt) ++ b_fmt++; ++ ++ b_fmt = (b_fmt + 3) / 4; ++ s_fmt[2] = b_fmt | 0x30; ++ ++ line_pos += scnprintf(fbd->p_line + line_pos, ++ fbd->p_line_size - line_pos, ++ s_fmt, zone); ++ line_pos += scnprintf(fbd->p_line + line_pos, ++ fbd->p_line_size - line_pos, ++ ": "); ++ } ++ ++ b_fmt = (fbd->block_addr_bits + 3) / 4; ++ s_fmt[2] = b_fmt | 0x30; ++ line_pos += scnprintf(fbd->p_line + line_pos, ++ fbd->p_line_size - line_pos, ++ s_fmt, log_block ++ & ((1 << fbd->block_addr_bits) - 1)); ++ line_pos += scnprintf(fbd->p_line + line_pos, ++ fbd->p_line_size - line_pos, ++ " "); ++ ++ if (phy_block == FLASH_BD_INVALID) { ++ line_pos += scnprintf(fbd->p_line + line_pos, ++ fbd->p_line_size - line_pos, ++ "--"); ++ goto fill_out; ++ } ++ ++ line_pos += scnprintf(fbd->p_line + line_pos, ++ fbd->p_line_size - line_pos, s_fmt, phy_block); ++ ++ b_fmt = 0; ++ ++ phy_block |= zone << fbd->block_addr_bits; ++ ++ if (test_bit(phy_block, fbd->data_map)) ++ b_fmt = 1; ++ ++ if (test_bit(phy_block, fbd->erase_map)) ++ b_fmt |= 2; ++ ++ switch (b_fmt) { ++ case 0: ++ line_pos += scnprintf(fbd->p_line + line_pos, ++ fbd->p_line_size - line_pos, ++ " U"); ++ break; ++ case 1: ++ line_pos += scnprintf(fbd->p_line + line_pos, ++ fbd->p_line_size - line_pos, ++ " F"); ++ break; ++ case 2: ++ line_pos += scnprintf(fbd->p_line + line_pos, ++ fbd->p_line_size - line_pos, ++ " C"); ++ break; ++ case 3: ++ line_pos += scnprintf(fbd->p_line + line_pos, ++ fbd->p_line_size - line_pos, ++ " F"); ++ break; ++ } ++ ++fill_out: ++ memset(fbd->p_line + line_pos, ' ', fbd->p_line_size - line_pos); ++ fbd->p_line[fbd->p_line_size - 1] = '\n'; ++} ++ ++/** ++ * flash_bd_map_size - calculate size of the complete block map text dump ++ * Return number of characters needed. ++ * fbd: owner of the map ++ */ ++size_t flash_bd_map_size(struct flash_bd *fbd) ++{ ++ return fbd->p_line_size * fbd->zone_cnt * fbd->log_block_cnt; ++} ++EXPORT_SYMBOL(flash_bd_map_size); ++ ++/** ++ * flash_bd_read_map - read current block map as text. ++ * Return number of characters written into buffer. ++ * fbd: owner of the map ++ * buf: where to put the printout ++ * offset: offset into the text representation of the map ++ * count: size of the buffer ++ */ ++ssize_t flash_bd_read_map(struct flash_bd *fbd, char *buf, loff_t offset, ++ size_t count) ++{ ++ loff_t l_begin = offset; ++ unsigned int l_begin_rem = do_div(l_begin, fbd->p_line_size); ++ loff_t l_end = offset + count - 1; ++ ssize_t rc = 0; ++ ++ do_div(l_end, fbd->p_line_size); ++ ++ if (!count) ++ return 0; ++ ++ flash_bd_print_line(fbd, l_begin); ++ ++ if (l_begin != l_end) { ++ rc = fbd->p_line_size - l_begin_rem; ++ memcpy(buf, fbd->p_line + l_begin_rem, rc); ++ } else { ++ memcpy(buf, fbd->p_line + l_begin_rem, count); ++ return count; ++ } ++ ++ for (++l_begin; l_begin < l_end; ++l_begin) { ++ flash_bd_print_line(fbd, l_begin); ++ memcpy(buf + rc, fbd->p_line, fbd->p_line_size); ++ rc += fbd->p_line_size; ++ } ++ ++ flash_bd_print_line(fbd, l_end); ++ memcpy(buf + rc, fbd->p_line, count - rc); ++ ++ return count; ++} ++EXPORT_SYMBOL(flash_bd_read_map); ++ ++/*** Protocol processing ***/ ++ ++static unsigned int flash_bd_get_free(struct flash_bd *fbd, unsigned int zone) ++{ ++ unsigned long r_pos; ++ unsigned long pos = zone << fbd->block_addr_bits; ++ ++ if (!fbd->free_cnt[zone]) ++ return FLASH_BD_INVALID; ++ ++ r_pos = random32() % fbd->free_cnt[zone]; ++ ++ while (1) { ++ pos = find_next_zero_bit(fbd->data_map, ++ fbd->phy_block_cnt * fbd->zone_cnt, ++ pos); ++ if (pos >= ((zone + 1) << fbd->block_addr_bits)) ++ return FLASH_BD_INVALID; ++ ++ if (!r_pos) ++ break; ++ ++ r_pos--; ++ pos++; ++ }; ++ ++ set_bit(pos, fbd->data_map); ++ if (fbd->free_cnt[zone]) ++ fbd->free_cnt[zone]--; ++ ++ return pos; ++} ++ ++static int h_flash_bd_read_tmp_r(struct flash_bd *fbd, ++ struct flash_bd_request *req) ++{ ++ if (fbd->last_error) ++ return fbd->last_error; ++ ++ if (fbd->req_count != fbd->last_count) ++ return -EIO; ++ ++ req->cmd = FBD_FLUSH_TMP; ++ req->zone = FLASH_BD_INVALID; ++ req->log_block = FLASH_BD_INVALID; ++ req->phy_block = FLASH_BD_INVALID; ++ req->byte_off = fbd->buf_offset - (fbd->buf_page_off * fbd->page_size); ++ req->byte_cnt = fbd->buf_count; ++ fbd->req_count = fbd->buf_count; ++ fbd->cmd_handler = h_flash_bd_read; ++ return 0; ++} ++ ++static int h_flash_bd_read(struct flash_bd *fbd, struct flash_bd_request *req) ++{ ++ unsigned long long zone_off; ++ unsigned int log_block; ++ ++ if (fbd->last_error) ++ return fbd->last_error; ++ ++ if (fbd->req_count != fbd->last_count) ++ return -EIO; ++ ++ fbd->t_count += fbd->last_count; ++ fbd->rem_count -= fbd->last_count; ++ ++ if (!fbd->rem_count) { ++ req->cmd = FBD_NONE; ++ return 0; ++ } ++ ++ zone_off = fbd->byte_offset + fbd->t_count; ++ fbd->buf_offset = do_div(zone_off, fbd->block_size); ++ log_block = do_div(zone_off, fbd->log_block_cnt); ++ ++ req->zone = zone_off; ++ ++ if (req->zone >= fbd->zone_cnt) ++ return -ENOSPC; ++ ++ fbd->buf_count = min(fbd->rem_count, fbd->block_size - fbd->buf_offset); ++ ++ fbd->buf_page_off = fbd->buf_offset / fbd->page_size; ++ fbd->buf_page_cnt = ((fbd->buf_offset + fbd->buf_count) ++ / fbd->page_size) - fbd->buf_page_off; ++ if ((fbd->buf_offset + fbd->buf_count) % fbd->page_size) ++ fbd->buf_page_cnt++; ++ ++ req->log_block = log_block; ++ ++ req->phy_block = flash_bd_get_physical(fbd, zone_off, log_block); ++ ++ if (req->phy_block == FLASH_BD_INVALID) { ++ req->cmd = FBD_SKIP; ++ req->byte_off = 0; ++ req->byte_cnt = fbd->buf_count; ++ fbd->req_count = fbd->buf_count; ++ fbd->cmd_handler = h_flash_bd_read; ++ return 0; ++ } ++ ++ req->page_off = fbd->buf_page_off; ++ req->page_cnt = fbd->buf_page_cnt; ++ fbd->req_count = fbd->buf_page_cnt * fbd->page_size; ++ ++ if ((fbd->buf_offset % fbd->page_size) ++ || (fbd->buf_count % fbd->page_size)) { ++ req->cmd = FBD_READ_TMP; ++ fbd->cmd_handler = h_flash_bd_read_tmp_r; ++ } else { ++ req->cmd = FBD_READ; ++ fbd->cmd_handler = h_flash_bd_read; ++ } ++ ++ return 0; ++} ++ ++static int h_flash_bd_mark_dst_bad(struct flash_bd *fbd, ++ struct flash_bd_request *req) ++{ ++ req->cmd = FBD_NONE; ++ return 0; ++} ++ ++ ++static int h_flash_bd_erase_dst(struct flash_bd *fbd, ++ struct flash_bd_request *req) ++{ ++ req->zone = fbd->w_dst_block >> fbd->block_addr_bits; ++ req->log_block = fbd->w_log_block ++ & ((1 << fbd->block_addr_bits) - 1); ++ req->phy_block = fbd->w_dst_block ++ & ((1 << fbd->block_addr_bits) - 1); ++ req->src.phy_block = fbd->w_src_block ++ & ((1 << fbd->block_addr_bits) - 1); ++ req->page_off = 0; ++ ++ if (fbd->last_error) { ++ if (fbd->last_error == -EFAULT) { ++ req->cmd = FBD_MARK_BAD; ++ req->page_cnt = fbd->page_cnt; ++ fbd->req_count = 0; ++ fbd->cmd_handler = h_flash_bd_mark_dst_bad; ++ return 0; ++ } else ++ return fbd->last_error; ++ } ++ ++ if ((fbd->buf_count < fbd->block_size) ++ || (fbd->w_src_block == fbd->w_dst_block)) { ++ req->cmd = FBD_WRITE_TMP; ++ req->page_cnt = fbd->page_cnt; ++ fbd->req_count = fbd->block_size; ++ fbd->cmd_handler = h_flash_bd_write_inc; ++ } else { ++ req->cmd = FBD_WRITE; ++ req->page_cnt = fbd->buf_page_cnt; ++ fbd->req_count = req->page_cnt * fbd->page_size; ++ fbd->cmd_handler = h_flash_bd_write_inc; ++ } ++ ++ return 0; ++} ++ ++static int h_flash_bd_mark_src_bad(struct flash_bd *fbd, ++ struct flash_bd_request *req) ++{ ++ if (!fbd->rem_count) { ++ req->cmd = FBD_NONE; ++ return 0; ++ } else ++ return h_flash_bd_write(fbd, req); ++} ++ ++static int h_flash_bd_erase_src(struct flash_bd *fbd, ++ struct flash_bd_request *req) ++{ ++ req->zone = fbd->w_dst_block >> fbd->block_addr_bits; ++ req->log_block = fbd->w_log_block ++ & ((1 << fbd->block_addr_bits) - 1); ++ req->phy_block = fbd->w_src_block ++ & ((1 << fbd->block_addr_bits) - 1); ++ ++ flash_bd_mark_erased(fbd, fbd->w_src_block); ++ ++ if (fbd->last_error) { ++ if (fbd->last_error == -EFAULT) { ++ flash_bd_mark_used(fbd, fbd->w_src_block); ++ req->cmd = FBD_MARK_BAD; ++ req->page_off = 0; ++ req->page_cnt = fbd->page_cnt; ++ fbd->req_count = 0; ++ fbd->cmd_handler = h_flash_bd_mark_src_bad; ++ return 0; ++ } else ++ return fbd->last_error; ++ } ++ ++ if (!fbd->rem_count) { ++ req->cmd = FBD_NONE; ++ return 0; ++ } else ++ return h_flash_bd_write(fbd, req); ++} ++ ++static int h_flash_bd_write_inc(struct flash_bd *fbd, ++ struct flash_bd_request *req) ++{ ++ req->zone = fbd->w_log_block >> fbd->block_addr_bits; ++ req->log_block = fbd->w_log_block & ((1 << fbd->block_addr_bits) - 1); ++ ++ if (!fbd->last_error) { ++ if (fbd->req_count != fbd->last_count) ++ return -EIO; ++ } else if (fbd->last_error == -EFAULT) { ++ flash_bd_mark_used(fbd, fbd->w_dst_block); ++ req->phy_block = fbd->w_dst_block ++ & ((1 << fbd->block_addr_bits) - 1); ++ req->cmd = FBD_MARK_BAD; ++ req->page_off = 0; ++ req->page_cnt = fbd->page_cnt; ++ fbd->req_count = 0; ++ fbd->cmd_handler = NULL; ++ return 0; ++ } else ++ return fbd->last_error; ++ ++ fbd->block_table[fbd->w_log_block] = fbd->w_dst_block; ++ fbd->t_count += fbd->buf_count; ++ fbd->rem_count -= fbd->buf_count; ++ ++ if ((fbd->w_src_block != fbd->w_dst_block) ++ && (fbd->w_src_block != FLASH_BD_INVALID)) { ++ clear_bit(fbd->w_src_block, fbd->erase_map); ++ req->cmd = FBD_ERASE; ++ req->phy_block = fbd->w_src_block ++ & ((1 << fbd->block_addr_bits) - 1); ++ req->page_off = 0; ++ req->page_cnt = 0; ++ fbd->req_count = 0; ++ fbd->cmd_handler = h_flash_bd_erase_src; ++ return 0; ++ } ++ ++ if (!fbd->rem_count) { ++ req->cmd = FBD_NONE; ++ return 0; ++ } else ++ return h_flash_bd_write(fbd, req); ++} ++ ++static int h_flash_bd_fill_tmp(struct flash_bd *fbd, ++ struct flash_bd_request *req) ++{ ++ if (fbd->last_error) ++ return fbd->last_error; ++ ++ if (fbd->req_count != fbd->last_count) ++ return -EIO; ++ ++ req->zone = fbd->w_log_block >> fbd->block_addr_bits; ++ req->log_block = fbd->w_log_block & ((1 << fbd->block_addr_bits) - 1); ++ req->phy_block = fbd->w_dst_block & ((1 << fbd->block_addr_bits) - 1); ++ ++ if (test_bit(fbd->w_dst_block, fbd->erase_map)) { ++ fbd->last_error = 0; ++ fbd->last_count = 0; ++ return h_flash_bd_erase_dst(fbd, req); ++ } else { ++ req->cmd = FBD_ERASE; ++ req->page_off = 0; ++ req->page_cnt = 0; ++ fbd->req_count = 0; ++ fbd->cmd_handler = h_flash_bd_erase_dst; ++ } ++ ++ return 0; ++} ++ ++static int h_flash_bd_read_tmp_w(struct flash_bd *fbd, ++ struct flash_bd_request *req) ++{ ++ if (fbd->last_error) ++ return fbd->last_error; ++ ++ if (fbd->req_count != fbd->last_count) ++ return -EIO; ++ ++ req->cmd = FBD_FILL_TMP; ++ req->zone = FLASH_BD_INVALID; ++ req->log_block = FLASH_BD_INVALID; ++ req->phy_block = FLASH_BD_INVALID; ++ req->byte_off = fbd->buf_offset; ++ req->byte_cnt = fbd->buf_count; ++ fbd->req_count = fbd->buf_count; ++ fbd->cmd_handler = h_flash_bd_fill_tmp; ++ return 0; ++} ++ ++static int h_flash_bd_write(struct flash_bd *fbd, ++ struct flash_bd_request *req) ++{ ++ unsigned long long zone_off; ++ ++ if (fbd->last_error) ++ return fbd->last_error; ++ ++ zone_off = fbd->byte_offset + fbd->t_count; ++ fbd->buf_offset = do_div(zone_off, fbd->block_size); ++ fbd->buf_count = min(fbd->rem_count, fbd->block_size - fbd->buf_offset); ++ req->log_block = do_div(zone_off, fbd->log_block_cnt); ++ ++ fbd->buf_page_off = fbd->buf_offset / fbd->page_size; ++ fbd->buf_page_cnt = ((fbd->buf_offset + fbd->buf_count) ++ / fbd->page_size) - fbd->buf_page_off; ++ if ((fbd->buf_offset + fbd->buf_count) % fbd->page_size) ++ fbd->buf_page_cnt++; ++ ++ req->zone = zone_off; ++ ++ if (req->zone >= fbd->zone_cnt) ++ return -ENOSPC; ++ ++ fbd->w_src_block = flash_bd_get_physical(fbd, zone_off, req->log_block); ++ fbd->w_log_block = req->log_block | req->zone << fbd->block_addr_bits; ++ if (fbd->w_src_block != FLASH_BD_INVALID) ++ fbd->w_src_block |= req->zone << fbd->block_addr_bits; ++ ++ fbd->w_dst_block = flash_bd_get_free(fbd, zone_off); ++ if (fbd->w_dst_block == FLASH_BD_INVALID) ++ fbd->w_dst_block = fbd->w_src_block; ++ if (fbd->w_dst_block == FLASH_BD_INVALID) ++ return -EIO; ++ ++ if ((fbd->w_dst_block != fbd->w_src_block) ++ || (fbd->buf_count == fbd->block_size)) { ++ ++ if (fbd->buf_count < fbd->block_size) { ++ fbd->req_count = fbd->block_size; ++ if (fbd->w_src_block != FLASH_BD_INVALID) { ++ req->cmd = FBD_READ_TMP; ++ req->phy_block = fbd->w_src_block; ++ req->phy_block &= (1 << fbd->block_addr_bits) ++ - 1; ++ req->page_off = 0; ++ req->page_cnt = fbd->page_cnt; ++ } else { ++ req->cmd = FBD_ERASE_TMP; ++ req->phy_block = FLASH_BD_INVALID; ++ req->byte_off = 0; ++ req->byte_cnt = fbd->req_count; ++ } ++ fbd->cmd_handler = h_flash_bd_read_tmp_w; ++ } else { ++ req->phy_block = fbd->w_dst_block; ++ req->phy_block &= (1 << fbd->block_addr_bits) ++ - 1; ++ if (test_bit(fbd->w_dst_block, fbd->erase_map)) { ++ fbd->last_error = 0; ++ fbd->last_count = 0; ++ return h_flash_bd_erase_dst(fbd, req); ++ } else { ++ req->cmd = FBD_ERASE; ++ req->page_off = 0; ++ req->page_cnt = 0; ++ fbd->req_count = 0; ++ fbd->cmd_handler = h_flash_bd_erase_dst; ++ } ++ } ++ } else { ++ fbd->buf_page_off = 0; ++ fbd->buf_page_cnt = fbd->page_cnt; ++ req->cmd = FBD_READ_TMP; ++ req->phy_block = fbd->w_src_block; ++ req->phy_block &= (1 << fbd->block_addr_bits) - 1; ++ req->page_off = 0; ++ req->page_cnt = fbd->page_cnt; ++ fbd->req_count = fbd->block_size; ++ fbd->cmd_handler = h_flash_bd_read_tmp_w; ++ } ++ ++ return 0; ++} ++ ++MODULE_AUTHOR("Alex Dubov"); ++MODULE_DESCRIPTION("Simple flash to block device translation layer"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mmc/ms/jmb38x_ms.c b/drivers/mmc/ms/jmb38x_ms.c +index e606012..71466da 100644 +--- a/drivers/mmc/ms/jmb38x_ms.c ++++ b/drivers/mmc/ms/jmb38x_ms.c +@@ -14,12 +14,20 @@ + #include + #include + #include ++#include + +-#include "memstick.h" ++#include "linux/memstick.h" + + #define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383 + #define DRIVER_NAME "jmb38x_ms" +-#define DRIVER_VERSION "Rev133" ++#define DRIVER_VERSION "Rev166a" ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++static inline struct page *sg_page(struct scatterlist *sg) ++{ ++ return sg->page; ++} ++#endif + + static int no_dma; + module_param(no_dma, bool, 0644); +@@ -52,14 +60,10 @@ struct jmb38x_ms_host { + struct jmb38x_ms *chip; + void __iomem *addr; + spinlock_t lock; ++ struct tasklet_struct notify; + int id; + char host_id[DEVICE_ID_SIZE]; + int irq; +- unsigned int host_ctl; +- unsigned int pad_out; +- unsigned int pad_pu_pd; +- unsigned int clock_delay; +- unsigned int clock_ctl; + unsigned int block_pos; + unsigned long timeout_jiffies; + struct timer_list timer; +@@ -151,7 +155,6 @@ enum { + DMA_DATA = 0x08 + }; + +- + static unsigned int jmb38x_ms_read_data(struct jmb38x_ms_host *host, + unsigned char *buf, unsigned int length) + { +@@ -367,18 +370,14 @@ static int jmb38x_ms_issue_cmd(struct memstick_host *msh) + unsigned int data_len, cmd, t_val; + + if (!(STATUS_HAS_MEDIA & readl(host->addr + STATUS))) { +-#ifdef DBG + dev_dbg(msh->cdev.dev, "no media status\n"); +-#endif + host->req->error = -ETIME; + return host->req->error; + } + +-#ifdef DBG + dev_dbg(msh->cdev.dev, "control %08x\n", readl(host->addr + HOST_CONTROL)); + dev_dbg(msh->cdev.dev, "status %08x\n", readl(host->addr + INT_STATUS)); + dev_dbg(msh->cdev.dev, "hstatus %08x\n", readl(host->addr + STATUS)); +-#endif + + host->cmd_flags = 0; + host->block_pos = 0; +@@ -457,9 +456,7 @@ static int jmb38x_ms_issue_cmd(struct memstick_host *msh) + host->req->error = 0; + + writel(cmd, host->addr + TPC); +-#ifdef DBG + dev_dbg(msh->cdev.dev, "executing TPC %08x, len %x\n", cmd, data_len); +-#endif + + return 0; + } +@@ -472,16 +469,16 @@ static void jmb38x_ms_complete_cmd(struct memstick_host *msh, int last) + + del_timer(&host->timer); + +-#ifdef DBG + dev_dbg(msh->cdev.dev, "c control %08x\n", + readl(host->addr + HOST_CONTROL)); + dev_dbg(msh->cdev.dev, "c hstatus %08x\n", readl(host->addr + STATUS)); +-#endif + + host->req->int_reg = readl(host->addr + STATUS) & 0xff; + ++ writel(0, host->addr + BLOCK); ++ writel(0, host->addr + DMA_CONTROL); ++ + if (host->cmd_flags & DMA_DATA) { +- writel(0, host->addr + DMA_CONTROL); + pci_unmap_sg(host->chip->pdev, &host->req->sg, 1, + host->req->data_dir == READ + ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); +@@ -520,9 +517,7 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id) + + spin_lock(&host->lock); + irq_status = readl(host->addr + INT_STATUS); +-#ifdef DBG + dev_dbg(&host->chip->pdev->dev, "irq_status = %08x\n", irq_status); +-#endif + if (irq_status == 0 || irq_status == (~0)) { + spin_unlock(&host->lock); + return IRQ_NONE; +@@ -570,9 +565,7 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id) + } + + if (irq_status & (INT_STATUS_MEDIA_IN | INT_STATUS_MEDIA_OUT)) { +-#ifdef DBG + dev_dbg(&host->chip->pdev->dev, "media changed\n"); +-#endif + memstick_detect_change(msh); + } + +@@ -588,138 +581,162 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id) + return IRQ_HANDLED; + } + +-static void jmb38x_ms_reset(struct jmb38x_ms_host *host) +-{ +- unsigned int host_ctl = readl(host->addr + HOST_CONTROL); +- +- writel(HOST_CONTROL_RESET_REQ, host->addr + HOST_CONTROL); +- +- while (HOST_CONTROL_RESET_REQ +- & (host_ctl = readl(host->addr + HOST_CONTROL))) { +- ndelay(20); +-#ifdef DBG +- dev_dbg(&host->chip->pdev->dev, "reset %08x\n", host_ctl); +-#endif +- } +- +- writel(HOST_CONTROL_RESET, host->addr + HOST_CONTROL); +- writel(CLOCK_CONTROL_40MHZ, host->addr + HOST_CONTROL); +- mmiowb(); +- writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); +- writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); +-} +- + static void jmb38x_ms_abort(unsigned long data) + { + struct memstick_host *msh = (struct memstick_host *)data; + struct jmb38x_ms_host *host = memstick_priv(msh); + unsigned long flags; + +-#ifdef DBG + dev_dbg(&host->chip->pdev->dev, "abort\n"); +-#endif + spin_lock_irqsave(&host->lock, flags); + if (host->req) { +- jmb38x_ms_reset(host); +- writel(host->pad_pu_pd, host->addr + PAD_PU_PD); +- writel(host->pad_out, host->addr + PAD_OUTPUT_ENABLE); +- writel(host->host_ctl, host->addr + HOST_CONTROL); +- writel(host->clock_ctl, host->addr + CLOCK_CONTROL); +- writel(host->clock_delay, host->addr + CLOCK_DELAY); + host->req->error = -ETIME; + jmb38x_ms_complete_cmd(msh, 0); + } + spin_unlock_irqrestore(&host->lock, flags); + } + +-static void jmb38x_ms_request(struct memstick_host *msh) ++static void jmb38x_ms_req_tasklet(unsigned long data) + { ++ struct memstick_host *msh = (struct memstick_host *)data; + struct jmb38x_ms_host *host = memstick_priv(msh); + unsigned long flags; + int rc; + + spin_lock_irqsave(&host->lock, flags); +- if (host->req) { +- spin_unlock_irqrestore(&host->lock, flags); +- BUG(); +- return; ++ if (!host->req) { ++ do { ++ rc = memstick_next_req(msh, &host->req); ++ dev_dbg(&host->chip->pdev->dev, "tasklet req %d\n", rc); ++ } while (!rc && jmb38x_ms_issue_cmd(msh)); + } +- +- do { +- rc = memstick_next_req(msh, &host->req); +- } while (!rc && jmb38x_ms_issue_cmd(msh)); + spin_unlock_irqrestore(&host->lock, flags); + } + +-static void jmb38x_ms_set_param(struct memstick_host *msh, +- enum memstick_param param, +- int value) ++static void jmb38x_ms_dummy_submit(struct memstick_host *msh) ++{ ++ return; ++} ++ ++static void jmb38x_ms_submit_req(struct memstick_host *msh) + { + struct jmb38x_ms_host *host = memstick_priv(msh); + ++ tasklet_schedule(&host->notify); ++} ++ ++static int jmb38x_ms_reset(struct jmb38x_ms_host *host) ++{ ++ int cnt; ++ ++ writel(HOST_CONTROL_RESET_REQ | HOST_CONTROL_CLOCK_EN ++ | readl(host->addr + HOST_CONTROL), ++ host->addr + HOST_CONTROL); ++ mmiowb(); ++ ++ for (cnt = 0; cnt < 20; ++cnt) { ++ if (!(HOST_CONTROL_RESET_REQ ++ & readl(host->addr + HOST_CONTROL))) ++ goto reset_next; ++ ++ ndelay(20); ++ } ++ dev_dbg(&host->chip->pdev->dev, "reset_req timeout\n"); ++ ++reset_next: ++ writel(HOST_CONTROL_RESET | HOST_CONTROL_CLOCK_EN ++ | readl(host->addr + HOST_CONTROL), ++ host->addr + HOST_CONTROL); ++ mmiowb(); ++ ++ for (cnt = 0; cnt < 20; ++cnt) { ++ if (!(HOST_CONTROL_RESET ++ & readl(host->addr + HOST_CONTROL))) ++ goto reset_ok; ++ ++ ndelay(20); ++ } ++ dev_dbg(&host->chip->pdev->dev, "reset timeout\n"); ++ ++reset_ok: ++ mmiowb(); ++ writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); ++ writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); ++ return 0; ++} ++ ++static int jmb38x_ms_set_param(struct memstick_host *msh, ++ enum memstick_param param, ++ int value) ++{ ++ struct jmb38x_ms_host *host = memstick_priv(msh); ++ unsigned int host_ctl = readl(host->addr + HOST_CONTROL); ++ unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0; ++ int rc = 0; ++ + switch(param) { + case MEMSTICK_POWER: + if (value == MEMSTICK_POWER_ON) { +- jmb38x_ms_reset(host); ++ rc = jmb38x_ms_reset(host); ++ if (rc) ++ return rc; ++ ++ host_ctl = 7; ++ host_ctl |= HOST_CONTROL_POWER_EN ++ | HOST_CONTROL_CLOCK_EN; ++ writel(host_ctl, host->addr + HOST_CONTROL); + +- host->pad_pu_pd = host->id ? PAD_PU_PD_ON_MS_SOCK1 +- : PAD_PU_PD_ON_MS_SOCK0, +- host->pad_out = PAD_OUTPUT_ENABLE_MS; +- writel(host->pad_pu_pd, host->addr + PAD_PU_PD); +- writel(host->pad_out, host->addr + PAD_OUTPUT_ENABLE); ++ writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 ++ : PAD_PU_PD_ON_MS_SOCK0, ++ host->addr + PAD_PU_PD); + +- //host->host_ctl = readl(host->addr + HOST_CONTROL); +- host->host_ctl |= 7; +- host->host_ctl |= HOST_CONTROL_POWER_EN +- | HOST_CONTROL_CLOCK_EN; +- writel(host->host_ctl, host->addr + HOST_CONTROL); ++ writel(PAD_OUTPUT_ENABLE_MS, ++ host->addr + PAD_OUTPUT_ENABLE); + +-#ifdef DBG ++ msleep(10); + dev_dbg(&host->chip->pdev->dev, "power on\n"); +-#endif + } else if (value == MEMSTICK_POWER_OFF) { +- host->host_ctl &= ~(HOST_CONTROL_POWER_EN +- | HOST_CONTROL_CLOCK_EN); +- writel(host->host_ctl, host->addr + HOST_CONTROL); +- host->pad_out = 0; +- writel(host->pad_out, host->addr + PAD_OUTPUT_ENABLE); +- host->pad_pu_pd = PAD_PU_PD_OFF; +- writel(host->pad_pu_pd, host->addr + PAD_PU_PD); +-#ifdef DBG ++ host_ctl &= ~(HOST_CONTROL_POWER_EN ++ | HOST_CONTROL_CLOCK_EN); ++ writel(host_ctl, host->addr + HOST_CONTROL); ++ writel(0, host->addr + PAD_OUTPUT_ENABLE); ++ writel(PAD_PU_PD_OFF, host->addr + PAD_PU_PD); + dev_dbg(&host->chip->pdev->dev, "power off\n"); +-#endif +- } ++ } else ++ return -EINVAL; + break; + case MEMSTICK_INTERFACE: +- host->host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); ++ host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); + + if (value == MEMSTICK_SERIAL) { +- host->host_ctl &= ~HOST_CONTROL_FAST_CLK; +- host->host_ctl |= HOST_CONTROL_IF_SERIAL +- << HOST_CONTROL_IF_SHIFT; +- host->host_ctl |= HOST_CONTROL_REI; +- host->clock_ctl = CLOCK_CONTROL_40MHZ; +- host->clock_delay = 0; ++ host_ctl &= ~HOST_CONTROL_FAST_CLK; ++ host_ctl |= HOST_CONTROL_IF_SERIAL ++ << HOST_CONTROL_IF_SHIFT; ++ host_ctl |= HOST_CONTROL_REI; ++ clock_ctl = CLOCK_CONTROL_40MHZ; ++ clock_delay = 0; + } else if (value == MEMSTICK_PAR4) { +- host->host_ctl |= HOST_CONTROL_FAST_CLK; +- host->host_ctl |= HOST_CONTROL_IF_PAR4 +- << HOST_CONTROL_IF_SHIFT; +- host->host_ctl &= ~HOST_CONTROL_REI; +- host->clock_ctl = CLOCK_CONTROL_40MHZ; +- host->clock_delay = 4; ++ host_ctl |= HOST_CONTROL_FAST_CLK; ++ host_ctl |= HOST_CONTROL_IF_PAR4 ++ << HOST_CONTROL_IF_SHIFT; ++ host_ctl &= ~HOST_CONTROL_REI; ++ clock_ctl = CLOCK_CONTROL_40MHZ; ++ clock_delay = 4; + } else if (value == MEMSTICK_PAR8) { +- host->host_ctl |= HOST_CONTROL_FAST_CLK; +- host->host_ctl |= HOST_CONTROL_IF_PAR8 +- << HOST_CONTROL_IF_SHIFT; +- host->host_ctl &= ~HOST_CONTROL_REI; +- host->clock_ctl = CLOCK_CONTROL_60MHZ; +- host->clock_delay = 0; +- } +- writel(host->host_ctl, host->addr + HOST_CONTROL); +- writel(host->clock_ctl, host->addr + CLOCK_CONTROL); +- writel(host->clock_delay, host->addr + CLOCK_DELAY); ++ host_ctl |= HOST_CONTROL_FAST_CLK; ++ host_ctl |= HOST_CONTROL_IF_PAR8 ++ << HOST_CONTROL_IF_SHIFT; ++ host_ctl &= ~HOST_CONTROL_REI; ++ clock_ctl = CLOCK_CONTROL_60MHZ; ++ clock_delay = 0; ++ } else ++ return -EINVAL; ++ writel(host_ctl, host->addr + HOST_CONTROL); ++ writel(clock_ctl, host->addr + CLOCK_CONTROL); ++ writel(clock_delay, host->addr + CLOCK_DELAY); + break; + }; ++ return 0; + } + + #ifdef CONFIG_PM +@@ -730,6 +747,7 @@ static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state) + int cnt; + + for (cnt = 0; cnt < jm->host_cnt; ++cnt) { ++ dev_dbg(&jm->pdev->dev, "suspend %d, %p\n", cnt, jm->hosts[cnt]); + if (!jm->hosts[cnt]) + break; + memstick_suspend_host(jm->hosts[cnt]); +@@ -754,12 +772,13 @@ static int jmb38x_ms_resume(struct pci_dev *dev) + return rc; + pci_set_master(dev); + +- pci_read_config_dword(dev, 0xac, &rc); +- pci_write_config_dword(dev, 0xac, rc | 0x00470000); ++ //pci_read_config_dword(dev, 0xac, &rc); ++ //pci_write_config_dword(dev, 0xac, rc | 0x00470000); + + for (rc = 0; rc < jm->host_cnt; ++rc) { + if (!jm->hosts[rc]) + break; ++ dev_dbg(&jm->pdev->dev, "resume %d, %p\n", rc, jm->hosts[rc]); + memstick_resume_host(jm->hosts[rc]); + memstick_detect_change(jm->hosts[rc]); + } +@@ -813,7 +832,9 @@ static struct memstick_host* jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt) + host->id); + host->irq = jm->pdev->irq; + host->timeout_jiffies = msecs_to_jiffies(1000); +- msh->request = jmb38x_ms_request; ++ ++ tasklet_init(&host->notify, jmb38x_ms_req_tasklet, (unsigned long)msh); ++ msh->request = jmb38x_ms_submit_req; + msh->set_param = jmb38x_ms_set_param; + + msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8; +@@ -925,12 +946,12 @@ static void jmb38x_ms_remove(struct pci_dev *dev) + + host = memstick_priv(jm->hosts[cnt]); + ++ jm->hosts[cnt]->request = jmb38x_ms_dummy_submit; ++ tasklet_kill(&host->notify); + writel(0, host->addr + INT_SIGNAL_ENABLE); + writel(0, host->addr + INT_STATUS_ENABLE); + mmiowb(); +-#ifdef DBG + dev_dbg(&jm->pdev->dev, "interrupts off\n"); +-#endif + spin_lock_irqsave(&host->lock, flags); + if (host->req) { + host->req->error = -ETIME; +@@ -978,8 +999,8 @@ static void __exit jmb38x_ms_exit(void) + MODULE_AUTHOR("Alex Dubov"); + MODULE_DESCRIPTION("JMicron jmb38x MemoryStick driver"); + MODULE_LICENSE("GPL"); +-MODULE_DEVICE_TABLE(pci, jmb38x_ms_id_tbl); + MODULE_VERSION(DRIVER_VERSION); ++MODULE_DEVICE_TABLE(pci, jmb38x_ms_id_tbl); + + module_init(jmb38x_ms_init); + module_exit(jmb38x_ms_exit); +diff --git a/drivers/mmc/ms/jmb38x_xd.c b/drivers/mmc/ms/jmb38x_xd.c +new file mode 100755 +index 0000000..753ebb9 +--- /dev/null ++++ b/drivers/mmc/ms/jmb38x_xd.c +@@ -0,0 +1,780 @@ ++/* ++ * JMicron jmb38x xD picture card reader ++ * ++ * Copyright (C) 2008 JMicron Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "linux/xd_card.h" ++/* ++#undef dev_dbg ++ ++#define dev_dbg(dev, format, arg...) \ ++ dev_printk(KERN_EMERG , dev , format , ## arg) ++*/ ++#define PCI_DEVICE_ID_JMICRON_JMB38X_XD 0x2384 ++#define DRIVER_NAME "jmb38x_xd" ++#define DRIVER_VERSION "Rev166" ++ ++enum { ++ DMA_ADDRESS = 0x00, ++ HOST_CONTROL = 0x04, ++ COMMAND = 0x08, ++ MEDIA_ADDRESS_LO = 0x0c, ++ MEDIA_ADDRESS_HI = 0x10, ++ MCOMMAND = 0x14, ++ MADDRESS = 0x18, ++ MREAD = 0x1c, ++ MDATA = 0x20, ++ PIN_STATUS = 0x24, ++ ID_CODE = 0x28, ++ RDATA0 = 0x2c, ++ RDATA1 = 0x30, ++ RDATA2 = 0x34, ++ RDATA3 = 0x38, ++ ECC = 0x3c, ++ INT_STATUS = 0x40, ++ INT_STATUS_ENABLE = 0x44, ++ INT_SIGNAL_ENABLE = 0x48, ++ TIMER = 0x4c, ++ TIMER_CONTROL = 0x50, ++ PAD_OUTPUT_ENABLE = 0x54, ++ PAD_PU_PD = 0x58, ++ CLOCK_CONTROL = 0x5c, ++ DEBUG_PARAM = 0x60, ++ LED_CONTROL = 0x64, ++ CARD_DEBOUNCE = 0x68, ++ VERSION = 0x6c ++}; ++ ++#define JMB38X_XD_EXTRA_DATA_SIZE 16 ++ ++struct jmb38x_xd_host { ++ struct pci_dev *pdev; ++ void __iomem *addr; ++ spinlock_t lock; ++ struct tasklet_struct notify; ++ char id[DEVICE_ID_SIZE]; ++ unsigned short page_size; ++ unsigned short extra_size; ++ unsigned int host_ctl; ++ unsigned long timeout_jiffies; ++ struct timer_list timer; ++ struct xd_card_request *req; ++ unsigned char cmd_flags; ++ unsigned char extra_data[JMB38X_XD_EXTRA_DATA_SIZE]; ++}; ++ ++enum { ++ CMD_READY = 0x01, ++ DATA_READY = 0x02 ++}; ++ ++#define PAD_OUTPUT_ENABLE_XD0 0x00004fcf ++#define PAD_OUTPUT_ENABLE_XD1 0x00005fff ++#define PAD_OUTPUT_DISABLE_XD 0x000000c0 ++ ++#define PAD_PU_PD_OFF 0x7FFF0000 ++#define PAD_PU_PD_ON_XD 0x4f8f1030 ++ ++#define HOST_CONTROL_RESET_REQ 0x80000000 ++#define HOST_CONTROL_PAGE_CNT_MASK 0x00ff0000 ++#define HOST_CONTROL_PAGE_CNT_SHIFT 16 ++#define HOST_CONTROL_LED_TYPE 0x00008000 ++#define HOST_CONTROL_4P_MODE 0x00004000 ++#define HOST_CONTROL_COPY_BACK 0x00002000 ++#define HOST_CONTROL_CLK_DIV2 0x00001000 ++#define HOST_CONTROL_WP 0x00000800 ++#define HOST_CONTROL_LED 0x00000400 ++#define HOST_CONTROL_POWER_EN 0x00000200 ++#define HOST_CONTROL_CLOCK_EN 0x00000100 ++#define HOST_CONTROL_RESET 0x00000080 ++#define HOST_CONTROL_SLOW_CLK 0x00000040 ++#define HOST_CONTROL_CS_EN 0x00000020 ++#define HOST_CONTROL_DATA_DIR 0x00000010 ++#define HOST_CONTROL_ECC_EN 0x00000008 ++#define HOST_CONTROL_ADDR_SIZE_MASK 0x00000006 ++#define HOST_CONTROL_AC_EN 0x00000001 ++ ++#define PIN_STATUS_XDINS 0x00000002 ++#define PIN_STATUS_XDRB 0x00000001 ++ ++#define ECC_CODE1_ERR 0x00008000 ++#define ECC_DATA1_ERR 0x00004000 ++#define ECC_CORR1 0x00002000 ++#define ECC_GOOD1 0x00001000 ++#define ECC_CODE0_ERR 0x00000800 ++#define ECC_DATA0_ERR 0x00000400 ++#define ECC_CORR0 0x00000200 ++#define ECC_GOOD0 0x00000100 ++#define ECC_XD_STATUS_MASK 0x000000ff ++ ++#define INT_STATUS_OC_ERROR 0x00000080 ++#define INT_STATUS_ECC_ERROR 0x00000040 ++#define INT_STATUS_DMA_BOUNDARY 0x00000020 ++#define INT_STATUS_TIMER_TO 0x00000010 ++#define INT_STATUS_MEDIA_OUT 0x00000008 ++#define INT_STATUS_MEDIA_IN 0x00000004 ++#define INT_STATUS_EOTRAN 0x00000002 ++#define INT_STATUS_EOCMD 0x00000001 ++ ++#define INT_STATUS_ALL 0x000000ff ++ ++#define CLOCK_CONTROL_MMIO 0x00000008 ++#define CLOCK_CONTROL_62_5MHZ 0x00000004 ++#define CLOCK_CONTROL_50MHZ 0x00000002 ++#define CLOCK_CONTROL_40MHZ 0x00000001 ++ ++static int jmb38x_xd_issue_cmd(struct xd_card_host *host) ++{ ++ struct jmb38x_xd_host *jhost = xd_card_priv(host); ++ unsigned int p_cnt = 0; ++ ++ if (!(PIN_STATUS_XDINS & readl(jhost->addr + PIN_STATUS))) { ++ dev_dbg(host->dev, "no media status\n"); ++ jhost->req->error = -ETIME; ++ return jhost->req->error; ++ } ++ ++ writel(jhost->req->addr, jhost->addr + MEDIA_ADDRESS_LO); ++ writel(jhost->req->addr >> 32, jhost->addr + MEDIA_ADDRESS_HI); ++ ++ if (jhost->req->flags & XD_CARD_REQ_DATA) { ++ if (1 != pci_map_sg(jhost->pdev, &jhost->req->sg, 1, ++ jhost->req->flags & XD_CARD_REQ_DIR ++ ? PCI_DMA_TODEVICE ++ : PCI_DMA_FROMDEVICE)) { ++ jhost->req->error = -ENOMEM; ++ return jhost->req->error; ++ } ++ ++ writel(sg_dma_address(&jhost->req->sg), ++ jhost->addr + DMA_ADDRESS); ++ p_cnt = sg_dma_len(&jhost->req->sg) / jhost->page_size; ++ p_cnt <<= HOST_CONTROL_PAGE_CNT_SHIFT; ++ dev_dbg(host->dev, "trans %llx, %d, %08x\n", ++ sg_dma_address(&jhost->req->sg), ++ sg_dma_len(&jhost->req->sg), p_cnt); ++ } ++ ++ if ((jhost->req->flags & XD_CARD_REQ_EXTRA) ++ && (jhost->req->flags & XD_CARD_REQ_DIR)) { ++ xd_card_get_extra(host, jhost->extra_data, ++ jhost->extra_size); ++ __raw_writel(*(unsigned int *)(jhost->extra_data), ++ jhost->addr + RDATA0); ++ __raw_writel(*(unsigned int *)(jhost->extra_data + 4), ++ jhost->addr + RDATA1); ++ __raw_writel(*(unsigned int *)(jhost->extra_data + 8), ++ jhost->addr + RDATA2); ++ __raw_writel(*(unsigned int *)(jhost->extra_data + 12), ++ jhost->addr + RDATA3); ++ } ++ ++ if (!(jhost->req->flags & XD_CARD_REQ_NO_ECC)) { ++ writel(INT_STATUS_ECC_ERROR ++ | readl(jhost->addr + INT_SIGNAL_ENABLE), ++ jhost->addr + INT_SIGNAL_ENABLE); ++ writel(INT_STATUS_ECC_ERROR ++ | readl(jhost->addr + INT_STATUS_ENABLE), ++ jhost->addr + INT_STATUS_ENABLE); ++ } else { ++ writel((~INT_STATUS_ECC_ERROR) ++ & readl(jhost->addr + INT_SIGNAL_ENABLE), ++ jhost->addr + INT_SIGNAL_ENABLE); ++ writel((~INT_STATUS_ECC_ERROR) ++ & readl(jhost->addr + INT_STATUS_ENABLE), ++ jhost->addr + INT_STATUS_ENABLE); ++ } ++ ++ if (jhost->req->flags & XD_CARD_REQ_DIR) { ++ jhost->host_ctl |= HOST_CONTROL_WP; ++ jhost->host_ctl &= ~HOST_CONTROL_DATA_DIR; ++ } else { ++ jhost->host_ctl &= ~HOST_CONTROL_WP; ++ jhost->host_ctl |= HOST_CONTROL_DATA_DIR; ++ } ++ ++ /* The controller has a bug, requiring IDs to be "written", not "read". ++ */ ++ if (jhost->req->flags & XD_CARD_REQ_ID) ++ jhost->host_ctl &= ~HOST_CONTROL_DATA_DIR; ++ ++ writel(jhost->host_ctl | HOST_CONTROL_LED ++ | (p_cnt & HOST_CONTROL_PAGE_CNT_MASK), ++ jhost->addr + HOST_CONTROL); ++ ++ mod_timer(&jhost->timer, jiffies + jhost->timeout_jiffies); ++ jhost->req->error = 0; ++ jhost->cmd_flags = 0; ++ ++ writel(jhost->req->cmd << 16, jhost->addr + COMMAND); ++ ++ dev_dbg(host->dev, "issue command %02x, %08x, %llx\n", jhost->req->cmd, ++ readl(jhost->addr + HOST_CONTROL), jhost->req->addr); ++ return 0; ++} ++ ++static void jmb38x_xd_read_id(struct jmb38x_xd_host *jhost) ++{ ++ unsigned int id_val = __raw_readl(jhost->addr + ID_CODE); ++ ++ memset(jhost->req->id, 0, jhost->req->count); ++ ++ if (jhost->req->count >= 4) { ++ *(unsigned int *)(jhost->req->id) = id_val; ++ } else { ++ switch (jhost->req->count) { ++ case 3: ++ ((unsigned char *)jhost->req->id)[2] ++ = (id_val >> 16) & 0xff; ++ case 2: ++ ((unsigned char *)jhost->req->id)[1] ++ = (id_val >> 8) & 0xff; ++ case 1: ++ ((unsigned char *)jhost->req->id)[0] ++ = id_val & 0xff; ++ } ++ } ++} ++ ++static void jmb38x_xd_complete_cmd(struct xd_card_host *host, int last) ++{ ++ struct jmb38x_xd_host *jhost = xd_card_priv(host); ++ unsigned int host_ctl; ++ int rc; ++ ++ if (!last) ++ del_timer(&jhost->timer); ++ ++ host_ctl = readl(jhost->addr + HOST_CONTROL); ++ dev_dbg(&jhost->pdev->dev, "c control %08x\n", host_ctl); ++ dev_dbg(&jhost->pdev->dev, "c hstatus %08x\n", ++ readl(jhost->addr + ECC)); ++ ++ ++ writel((~(HOST_CONTROL_LED | HOST_CONTROL_PAGE_CNT_MASK ++ | HOST_CONTROL_WP)) & host_ctl, ++ jhost->addr + HOST_CONTROL); ++ ++ if (jhost->req->flags & XD_CARD_REQ_ID) ++ jmb38x_xd_read_id(jhost); ++ ++ if (jhost->req->flags & XD_CARD_REQ_STATUS) ++ jhost->req->status = readl(jhost->addr + ECC) ++ & ECC_XD_STATUS_MASK; ++ ++ if (jhost->req->flags & XD_CARD_REQ_DATA) { ++ host_ctl &= HOST_CONTROL_PAGE_CNT_MASK; ++ host_ctl >>= HOST_CONTROL_PAGE_CNT_SHIFT; ++ ++ jhost->req->count = sg_dma_len(&jhost->req->sg) ++ - host_ctl * jhost->page_size; ++ ++ writel(0, jhost->addr + DMA_ADDRESS); ++ pci_unmap_sg(jhost->pdev, &jhost->req->sg, 1, ++ jhost->req->flags & XD_CARD_REQ_DIR ++ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); ++ ++ } ++ ++ if ((jhost->req->flags & XD_CARD_REQ_EXTRA) ++ && !(jhost->req->flags & XD_CARD_REQ_DIR)) { ++ *(unsigned int *)(jhost->extra_data) ++ = __raw_readl(jhost->addr + RDATA0); ++ *(unsigned int *)(jhost->extra_data + 4) ++ = __raw_readl(jhost->addr + RDATA1); ++ *(unsigned int *)(jhost->extra_data + 8) ++ = __raw_readl(jhost->addr + RDATA2); ++ *(unsigned int *)(jhost->extra_data + 12) ++ = __raw_readl(jhost->addr + RDATA3); ++ ++ xd_card_set_extra(host, jhost->extra_data, ++ jhost->extra_size); ++ } ++ ++ if (!last) { ++ do { ++ rc = xd_card_next_req(host, &jhost->req); ++ } while (!rc && jmb38x_xd_issue_cmd(host)); ++ } else { ++ do { ++ rc = xd_card_next_req(host, &jhost->req); ++ if (!rc) ++ jhost->req->error = -ETIME; ++ } while (!rc); ++ } ++} ++ ++ ++static irqreturn_t jmb38x_xd_isr(int irq, void *dev_id) ++{ ++ struct xd_card_host *host = dev_id; ++ struct jmb38x_xd_host *jhost = xd_card_priv(host); ++ unsigned int irq_status, p_cnt; ++ ++ spin_lock(&jhost->lock); ++ irq_status = readl(jhost->addr + INT_STATUS); ++ dev_dbg(host->dev, "irq_status = %08x\n", irq_status); ++ if (irq_status == 0 || irq_status == (~0)) { ++ spin_unlock(&jhost->lock); ++ return IRQ_NONE; ++ } ++ ++ if (jhost->req) { ++ if (irq_status & INT_STATUS_TIMER_TO) ++ jhost->req->error = -ETIME; ++ else if (irq_status & INT_STATUS_ECC_ERROR) ++ jhost->req->error = -EILSEQ; ++ ++ if (irq_status & INT_STATUS_EOCMD) { ++ jhost->cmd_flags |= CMD_READY; ++ ++ if (!(jhost->req->flags & XD_CARD_REQ_DATA)) ++ jhost->cmd_flags |= DATA_READY; ++ } ++ ++ if (irq_status & INT_STATUS_EOTRAN) ++ jhost->cmd_flags |= DATA_READY; ++ ++ if ((jhost->req->flags & XD_CARD_REQ_DATA) ++ && (irq_status & INT_STATUS_DMA_BOUNDARY)) { ++ p_cnt = readl(jhost->addr + HOST_CONTROL); ++ p_cnt &= HOST_CONTROL_PAGE_CNT_MASK; ++ p_cnt >>= HOST_CONTROL_PAGE_CNT_SHIFT; ++ p_cnt = sg_dma_len(&jhost->req->sg) ++ - p_cnt * jhost->page_size; ++ dev_dbg(host->dev, "dma boundary %llx, %d, %d\n", ++ sg_dma_address(&jhost->req->sg) + p_cnt, ++ sg_dma_len(&jhost->req->sg), p_cnt); ++ writel(sg_dma_address(&jhost->req->sg) + p_cnt, ++ jhost->addr + DMA_ADDRESS); ++ } ++ } ++ ++ if (irq_status & (INT_STATUS_MEDIA_IN | INT_STATUS_MEDIA_OUT)) { ++ dev_dbg(host->dev, "media changed\n"); ++ xd_card_detect_change(host); ++ } ++ ++ writel(irq_status, jhost->addr + INT_STATUS); ++ ++ if (jhost->req ++ && (((jhost->cmd_flags & CMD_READY) ++ && (jhost->cmd_flags & DATA_READY)) ++ || jhost->req->error)) ++ jmb38x_xd_complete_cmd(host, 0); ++ ++ spin_unlock(&jhost->lock); ++ return IRQ_HANDLED; ++} ++ ++static void jmb38x_xd_abort(unsigned long data) ++{ ++ struct xd_card_host *host = (struct xd_card_host *)data; ++ struct jmb38x_xd_host *jhost = xd_card_priv(host); ++ unsigned long flags; ++ ++ dev_err(host->dev, "Software timeout!\n"); ++ spin_lock_irqsave(&jhost->lock, flags); ++ if (jhost->req) { ++ jhost->req->error = -ETIME; ++ jmb38x_xd_complete_cmd(host, 1); ++ } ++ spin_unlock_irqrestore(&jhost->lock, flags); ++} ++ ++static void jmb38x_xd_req_tasklet(unsigned long data) ++{ ++ struct xd_card_host *host = (struct xd_card_host *)data; ++ struct jmb38x_xd_host *jhost = xd_card_priv(host); ++ int rc; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&jhost->lock, flags); ++ if (!jhost->req) { ++ do { ++ rc = xd_card_next_req(host, &jhost->req); ++ dev_dbg(host->dev, "tasklet req %d\n", rc); ++ } while (!rc && jmb38x_xd_issue_cmd(host)); ++ } ++ spin_unlock_irqrestore(&jhost->lock, flags); ++} ++ ++static void jmb38x_xd_dummy_submit(struct xd_card_host *host) ++{ ++ return; ++} ++ ++static void jmb38x_xd_submit_req(struct xd_card_host *host) ++{ ++ struct jmb38x_xd_host *jhost = xd_card_priv(host); ++ ++ tasklet_schedule(&jhost->notify); ++} ++ ++static int jmb38x_xd_reset(struct jmb38x_xd_host *jhost) ++{ ++ int cnt; ++ ++ writel(HOST_CONTROL_RESET_REQ | HOST_CONTROL_CLOCK_EN ++ | readl(jhost->addr + HOST_CONTROL), ++ jhost->addr + HOST_CONTROL); ++ mmiowb(); ++ ++ for (cnt = 0; cnt < 20; ++cnt) { ++ if (!(HOST_CONTROL_RESET_REQ ++ & readl(jhost->addr + HOST_CONTROL))) ++ goto reset_next; ++ ++ ndelay(20); ++ } ++ dev_dbg(&jhost->pdev->dev, "reset_req timeout\n"); ++ return -EIO; ++ ++reset_next: ++ writel(HOST_CONTROL_RESET | HOST_CONTROL_CLOCK_EN ++ |readl(jhost->addr + HOST_CONTROL), ++ jhost->addr + HOST_CONTROL); ++ mmiowb(); ++ ++ for (cnt = 0; cnt < 20; ++cnt) { ++ if (!(HOST_CONTROL_RESET ++ & readl(jhost->addr + HOST_CONTROL))) ++ return 0; ++ ++ ndelay(20); ++ } ++ dev_dbg(&jhost->pdev->dev, "reset timeout\n"); ++ return -EIO; ++} ++ ++static int jmb38x_xd_set_param(struct xd_card_host *host, ++ enum xd_card_param param, ++ int value) ++{ ++ struct jmb38x_xd_host *jhost = xd_card_priv(host); ++ unsigned int t_val; ++ int rc = 0; ++ ++ switch(param) { ++ case XD_CARD_POWER: ++ if (value == XD_CARD_POWER_ON) { ++ /* jmb38x_xd_reset(jhost); */ ++ writel(CLOCK_CONTROL_MMIO | CLOCK_CONTROL_40MHZ, ++ jhost->addr + CLOCK_CONTROL); ++ ++ writel(PAD_OUTPUT_ENABLE_XD0 << 16, ++ jhost->addr + PAD_PU_PD); ++ writel(PAD_OUTPUT_ENABLE_XD0, ++ jhost->addr + PAD_OUTPUT_ENABLE); ++ ++ msleep(60); ++ ++ jhost->host_ctl = HOST_CONTROL_POWER_EN ++ | HOST_CONTROL_CLOCK_EN ++ | HOST_CONTROL_ECC_EN ++ | HOST_CONTROL_AC_EN; ++ writel(jhost->host_ctl, jhost->addr + HOST_CONTROL); ++ ++ msleep(1); ++ ++ writel(PAD_PU_PD_ON_XD, jhost->addr + PAD_PU_PD); ++ writel(PAD_OUTPUT_ENABLE_XD1, ++ jhost->addr + PAD_OUTPUT_ENABLE); ++ dev_dbg(host->dev, "power on\n"); ++ writel(INT_STATUS_ALL, jhost->addr + INT_SIGNAL_ENABLE); ++ writel(INT_STATUS_ALL, jhost->addr + INT_STATUS_ENABLE); ++ mmiowb(); ++ } else if (value == XD_CARD_POWER_OFF) { ++ jhost->host_ctl &= ~HOST_CONTROL_WP; ++ writel(jhost->host_ctl, jhost->addr + HOST_CONTROL); ++ ++ dev_dbg(host->dev, "p1\n"); ++ rc = jmb38x_xd_reset(jhost); ++ ++ dev_dbg(host->dev, "p2\n"); ++ msleep(1); ++ ++ dev_dbg(host->dev, "p3\n"); ++ if (readl(jhost->addr + PAD_OUTPUT_ENABLE)) ++ writel(PAD_OUTPUT_ENABLE_XD0, ++ jhost->addr + PAD_OUTPUT_ENABLE); ++ ++ msleep(1); ++ dev_dbg(host->dev, "p4\n"); ++ ++ jhost->host_ctl &= ~(HOST_CONTROL_POWER_EN ++ | HOST_CONTROL_CLOCK_EN); ++ writel(jhost->host_ctl, jhost->addr + HOST_CONTROL); ++ ++ msleep(1); ++ ++ dev_dbg(host->dev, "p5\n"); ++ writel(PAD_PU_PD_OFF, jhost->addr + PAD_PU_PD); ++ ++ dev_dbg(host->dev, "p6\n"); ++ writel(PAD_OUTPUT_DISABLE_XD, ++ jhost->addr + PAD_OUTPUT_ENABLE); ++ msleep(60); ++ writel(0, jhost->addr + PAD_OUTPUT_ENABLE); ++ dev_dbg(host->dev, "power off\n"); ++ writel(INT_STATUS_ALL, jhost->addr + INT_SIGNAL_ENABLE); ++ writel(INT_STATUS_ALL, jhost->addr + INT_STATUS_ENABLE); ++ mmiowb(); ++ } else ++ rc = -EINVAL; ++ break; ++ case XD_CARD_CLOCK: ++ if (value == XD_CARD_SLOW) ++ jhost->host_ctl |= HOST_CONTROL_SLOW_CLK; ++ else if (value == XD_CARD_NORMAL) ++ jhost->host_ctl &= ~HOST_CONTROL_SLOW_CLK; ++ else ++ return -EINVAL; ++ ++ writel(jhost->host_ctl, jhost->addr + HOST_CONTROL); ++ break; ++ case XD_CARD_PAGE_SIZE: ++ if (value > 2047) ++ rc = -EINVAL; ++ else { ++ jhost->page_size = value; ++ t_val = readl(jhost->addr + DEBUG_PARAM); ++ t_val &= ~0xfff; ++ t_val |= jhost->page_size; ++ writel(t_val, jhost->addr + DEBUG_PARAM); ++ } ++ break; ++ case XD_CARD_EXTRA_SIZE: ++ if (value > JMB38X_XD_EXTRA_DATA_SIZE) ++ rc = -EINVAL; ++ else { ++ jhost->extra_size = value; ++ t_val = readl(jhost->addr + DEBUG_PARAM); ++ t_val &= ~(0xff << 16); ++ t_val |= value << 16; ++ writel(t_val, jhost->addr + DEBUG_PARAM); ++ } ++ break; ++ case XD_CARD_ADDR_SIZE: ++ if ((value < 3) || (value > 6)) ++ rc = -EINVAL; ++ else { ++ jhost->host_ctl &= ~ HOST_CONTROL_ADDR_SIZE_MASK; ++ jhost->host_ctl |= (value - 3) << 1; ++ writel(jhost->host_ctl, jhost->addr + HOST_CONTROL); ++ } ++ break; ++ }; ++ return rc; ++} ++ ++ ++#ifdef CONFIG_PM ++ ++static int jmb38x_xd_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct xd_card_host *host = pci_get_drvdata(pdev); ++ int rc; ++ ++ rc = xd_card_suspend_host(host); ++ if (rc) ++ return rc; ++ ++ pci_save_state(pdev); ++ pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); ++ pci_disable_device(pdev); ++ pci_set_power_state(pdev, pci_choose_state(pdev, state)); ++ return 0; ++} ++ ++static int jmb38x_xd_resume(struct pci_dev *pdev) ++{ ++ struct xd_card_host *host = pci_get_drvdata(pdev); ++ int rc; ++ ++ pci_set_power_state(pdev, PCI_D0); ++ pci_restore_state(pdev); ++ rc = pci_enable_device(pdev); ++ if (rc) ++ return rc; ++ pci_set_master(pdev); ++ ++ pci_read_config_dword(pdev, 0xac, &rc); ++ pci_write_config_dword(pdev, 0xac, rc | 0x00470000); ++ pci_read_config_dword(pdev, 0xb0, &rc); ++ pci_write_config_dword(pdev, 0xb0, rc & 0xffff0000); ++ ++ return xd_card_resume_host(host); ++} ++ ++#else ++ ++#define jmb38x_xd_suspend NULL ++#define jmb38x_xd_resume NULL ++ ++#endif /* CONFIG_PM */ ++ ++static int jmb38x_xd_probe(struct pci_dev *pdev, ++ const struct pci_device_id *dev_id) ++{ ++ struct xd_card_host *host; ++ struct jmb38x_xd_host *jhost; ++ int pci_dev_busy = 0; ++ int rc; ++ ++ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); ++ if (rc) ++ return rc; ++ ++ rc = pci_enable_device(pdev); ++ if (rc) ++ return rc; ++ ++ pci_set_master(pdev); ++ ++ rc = pci_request_regions(pdev, DRIVER_NAME); ++ if (rc) { ++ pci_dev_busy = 1; ++ goto err_out; ++ } ++ ++ pci_read_config_dword(pdev, 0xac, &rc); ++ pci_write_config_dword(pdev, 0xac, rc | 0x00470000); ++ pci_read_config_dword(pdev, 0xb0, &rc); ++ pci_write_config_dword(pdev, 0xb0, rc & 0xffff00ff); ++ ++ host = xd_card_alloc_host(sizeof(struct jmb38x_xd_host), &pdev->dev); ++ ++ if (!host) { ++ rc = -ENOMEM; ++ goto err_out_release; ++ } ++ ++ jhost = xd_card_priv(host); ++ ++ jhost->addr = ioremap(pci_resource_start(pdev, 0), ++ pci_resource_len(pdev, 0)); ++ ++ if (!jhost->addr) { ++ rc = -ENOMEM; ++ goto err_out_free; ++ } ++ ++ jhost->pdev = pdev; ++ jhost->timeout_jiffies = msecs_to_jiffies(1000); ++ ++ tasklet_init(&jhost->notify, jmb38x_xd_req_tasklet, ++ (unsigned long)host); ++ host->request = jmb38x_xd_submit_req; ++ host->set_param = jmb38x_xd_set_param; ++ host->caps = XD_CARD_CAP_AUTO_ECC | XD_CARD_CAP_FIXED_EXTRA ++ | XD_CARD_CAP_CMD_SHORTCUT; ++ ++ pci_set_drvdata(pdev, host); ++ ++ snprintf(jhost->id, DEVICE_ID_SIZE, DRIVER_NAME); ++ ++ spin_lock_init(&jhost->lock); ++ setup_timer(&jhost->timer, jmb38x_xd_abort, (unsigned long)host); ++ ++ rc = request_irq(pdev->irq, jmb38x_xd_isr, IRQF_SHARED, jhost->id, ++ host); ++ ++ if(!rc) { ++ xd_card_detect_change(host); ++ return 0; ++ } ++ ++ iounmap(jhost->addr); ++ pci_set_drvdata(pdev, NULL); ++err_out_free: ++ xd_card_free_host(host); ++err_out_release: ++ pci_release_regions(pdev); ++err_out: ++ if (!pci_dev_busy) ++ pci_disable_device(pdev); ++ return rc; ++} ++ ++static void jmb38x_xd_remove(struct pci_dev *pdev) ++{ ++ struct xd_card_host *host = pci_get_drvdata(pdev); ++ struct jmb38x_xd_host *jhost = xd_card_priv(host); ++ void __iomem *addr = jhost->addr; ++ unsigned long flags; ++ ++ host->request = jmb38x_xd_dummy_submit; ++ tasklet_kill(&jhost->notify); ++ writel(0, addr + INT_SIGNAL_ENABLE); ++ writel(0, addr + INT_STATUS_ENABLE); ++ mmiowb(); ++ free_irq(pdev->irq, host); ++ dev_dbg(&pdev->dev, "interrupts off\n"); ++ del_timer_sync(&jhost->timer); ++ ++ spin_lock_irqsave(&jhost->lock, flags); ++ if (jhost->req) { ++ jhost->req->error = -ETIME; ++ jmb38x_xd_complete_cmd(host, 1); ++ } ++ spin_unlock_irqrestore(&jhost->lock, flags); ++ ++ xd_card_free_host(host); ++ writel(PAD_PU_PD_OFF, addr + PAD_PU_PD); ++ writel(PAD_OUTPUT_DISABLE_XD, addr + PAD_OUTPUT_ENABLE); ++ msleep(60); ++ writel(0, addr + PAD_OUTPUT_ENABLE); ++ mmiowb(); ++ ++ iounmap(addr); ++ ++ pci_set_drvdata(pdev, NULL); ++ pci_release_regions(pdev); ++ pci_disable_device(pdev); ++} ++ ++static struct pci_device_id jmb38x_xd_id_tbl [] = { ++ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_XD, PCI_ANY_ID, ++ PCI_ANY_ID, 0, 0, 0 }, ++ { } ++}; ++ ++static struct pci_driver jmb38x_xd_driver = { ++ .name = DRIVER_NAME, ++ .id_table = jmb38x_xd_id_tbl, ++ .probe = jmb38x_xd_probe, ++ .remove = jmb38x_xd_remove, ++ .suspend = jmb38x_xd_suspend, ++ .resume = jmb38x_xd_resume ++}; ++ ++static int __init jmb38x_xd_init(void) ++{ ++ return pci_register_driver(&jmb38x_xd_driver); ++} ++ ++static void __exit jmb38x_xd_exit(void) ++{ ++ pci_unregister_driver(&jmb38x_xd_driver); ++} ++ ++MODULE_AUTHOR("Alex Dubov"); ++MODULE_DESCRIPTION("JMicron jmb38x xD Picture card driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRIVER_VERSION); ++MODULE_DEVICE_TABLE(pci, jmb38x_xd_id_tbl); ++ ++module_init(jmb38x_xd_init); ++module_exit(jmb38x_xd_exit); +diff --git a/drivers/mmc/ms/linux/flash_bd.h b/drivers/mmc/ms/linux/flash_bd.h +new file mode 100755 +index 0000000..ad43a10 +--- /dev/null ++++ b/drivers/mmc/ms/linux/flash_bd.h +@@ -0,0 +1,119 @@ ++/* ++ * Simple flash to block device translation layer ++ * ++ * Copyright (C) 2008 Alex Dubov ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++/* ++ * Unlike MTD components (if I understand it correctly) this translation layer ++ * avoids keeping any metadata on the flash, to prevent interference with ++ * removable media metadata and keep things compatible. ++ * ++ */ ++ ++#ifndef _FLASH_BD_H ++#define _FLASH_BD_H ++ ++#include ++ ++#define FLASH_BD_INVALID 0xffffffffU ++ ++struct flash_bd; ++ ++enum flash_bd_cmd { ++ FBD_NONE = 0, ++ FBD_READ, /* read from media */ ++ FBD_READ_TMP, /* read from media into temporary storage */ ++ FBD_FLUSH_TMP, /* copy data from temporary to permanent storage */ ++ FBD_SKIP, /* pretend like reading from media */ ++ FBD_ERASE_TMP, /* fill tmp area with default values */ ++ FBD_ERASE, /* erase media block */ ++ FBD_COPY, /* media side page copy */ ++ FBD_WRITE, /* write to media */ ++ FBD_WRITE_TMP, /* write to media from temporary storage */ ++ FBD_FILL_TMP, /* copy data from permanent to temporary storage */ ++ FBD_MARK, /* write only extradata to some pages */ ++ FBD_MARK_BAD /* as above, mark pages as bad */ ++}; ++ ++static inline const char *flash_bd_cmd_name(enum flash_bd_cmd cmd) ++{ ++ switch (cmd) { ++ case FBD_NONE: ++ return "FBD_NONE"; ++ case FBD_READ: ++ return "FBD_READ"; ++ case FBD_READ_TMP: ++ return "FBD_READ_TMP"; ++ case FBD_FLUSH_TMP: ++ return "FBD_FLUSH_TMP"; ++ case FBD_SKIP: ++ return "FBD_SKIP"; ++ case FBD_ERASE_TMP: ++ return "FBD_ERASE_TMP"; ++ case FBD_ERASE: ++ return "FBD_ERASE"; ++ case FBD_COPY: ++ return "FBD_COPY"; ++ case FBD_WRITE: ++ return "FBD_WRITE"; ++ case FBD_WRITE_TMP: ++ return "FBD_WRITE_TMP"; ++ case FBD_FILL_TMP: ++ return "FBD_FILL_TMP"; ++ case FBD_MARK: ++ return "FBD_MARK"; ++ case FBD_MARK_BAD: ++ return "FBD_MARK_BAD"; ++ default: ++ return "INVALID"; ++ } ++} ++ ++struct flash_bd_request { ++ enum flash_bd_cmd cmd; ++ unsigned int zone; ++ unsigned int log_block; ++ unsigned int phy_block; ++ union { ++ unsigned int page_off; ++ unsigned int byte_off; ++ }; ++ union { ++ unsigned int page_cnt; ++ unsigned int byte_cnt; ++ }; ++ struct { /* used by FBD_COPY */ ++ unsigned int phy_block; ++ unsigned int page_off; ++ } src; ++}; ++ ++struct flash_bd* flash_bd_init(unsigned int zone_cnt, ++ unsigned int phy_block_cnt, ++ unsigned int log_block_cnt, ++ unsigned int page_cnt, ++ unsigned int page_size); ++void flash_bd_destroy(struct flash_bd *fbd); ++int flash_bd_set_empty(struct flash_bd *fbd, unsigned int zone, ++ unsigned int phy_block, int erased); ++int flash_bd_set_full(struct flash_bd *fbd, unsigned int zone, ++ unsigned int phy_block, unsigned int log_block); ++unsigned int flash_bd_get_physical(struct flash_bd *fbd, unsigned int zone, ++ unsigned int log_block); ++int flash_bd_next_req(struct flash_bd *fbd, struct flash_bd_request *req, ++ unsigned int count, int error); ++unsigned int flash_bd_end(struct flash_bd *fbd); ++int flash_bd_start_reading(struct flash_bd *fbd, unsigned long long offset, ++ unsigned int count); ++int flash_bd_start_writing(struct flash_bd *fbd, unsigned long long offset, ++ unsigned int count); ++size_t flash_bd_map_size(struct flash_bd *fbd); ++ssize_t flash_bd_read_map(struct flash_bd *fbd, char *buf, loff_t offset, ++ size_t count); ++#endif +diff --git a/drivers/mmc/ms/linux/memstick.h b/drivers/mmc/ms/linux/memstick.h +new file mode 100755 +index 0000000..7cbe7f4 +--- /dev/null ++++ b/drivers/mmc/ms/linux/memstick.h +@@ -0,0 +1,346 @@ ++/* ++ * Sony MemoryStick support ++ * ++ * Copyright (C) 2007 Alex Dubov ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef _MEMSTICK_H ++#define _MEMSTICK_H ++ ++#include ++#include ++#include ++ ++/*** Hardware based structures ***/ ++ ++struct ms_status_register { ++ unsigned char reserved; ++ unsigned char interrupt; ++#define MEMSTICK_INT_CMDNAK 0x0001 ++#define MEMSTICK_INT_IOREQ 0x0008 ++#define MEMSTICK_INT_IOBREQ 0x0010 ++#define MEMSTICK_INT_BREQ 0x0020 ++#define MEMSTICK_INT_ERR 0x0040 ++#define MEMSTICK_INT_CED 0x0080 ++ ++ unsigned char status0; ++#define MEMSTICK_STATUS0_WP 0x0001 ++#define MEMSTICK_STATUS0_SL 0x0002 ++#define MEMSTICK_STATUS0_BF 0x0010 ++#define MEMSTICK_STATUS0_BE 0x0020 ++#define MEMSTICK_STATUS0_FB0 0x0040 ++#define MEMSTICK_STATUS0_MB 0x0080 ++ ++ unsigned char status1; ++#define MEMSTICK_STATUS1_UCFG 0x0001 ++#define MEMSTICK_STATUS1_FGER 0x0002 ++#define MEMSTICK_STATUS1_UCEX 0x0004 ++#define MEMSTICK_STATUS1_EXER 0x0008 ++#define MEMSTICK_STATUS1_UCDT 0x0010 ++#define MEMSTICK_STATUS1_DTER 0x0020 ++#define MEMSTICK_STATUS1_FBI 0x0040 ++#define MEMSTICK_STATUS1_MB 0x0080 ++} __attribute__((packed)); ++ ++struct ms_id_register { ++ unsigned char type; ++ unsigned char if_mode; ++ unsigned char category; ++ unsigned char class; ++} __attribute__((packed)); ++ ++struct ms_param_register { ++ unsigned char system; ++#define MEMSTICK_SYS_ATEN 0xc0 ++#define MEMSTICK_SYS_BAMD 0x80 ++#define MEMSTICK_SYS_PAM 0x08 ++ ++ unsigned char block_address_msb; ++ unsigned short block_address; ++ unsigned char cp; ++#define MEMSTICK_CP_BLOCK 0x0000 ++#define MEMSTICK_CP_PAGE 0x0020 ++#define MEMSTICK_CP_EXTRA 0x0040 ++#define MEMSTICK_CP_OVERWRITE 0x0080 ++ ++ unsigned char page_address; ++} __attribute__((packed)); ++ ++struct ms_extra_data_register { ++ unsigned char overwrite_flag; ++#define MEMSTICK_OVERWRITE_UPDATA 0x0010 ++#define MEMSTICK_OVERWRITE_PAGE 0x0060 ++#define MEMSTICK_OVERWRITE_BLOCK 0x0080 ++ ++ unsigned char management_flag; ++#define MEMSTICK_MANAGEMENT_SYSTEM 0x0004 ++#define MEMSTICK_MANAGEMENT_TRANS_TABLE 0x0008 ++#define MEMSTICK_MANAGEMENT_COPY 0x0010 ++#define MEMSTICK_MANAGEMENT_ACCESS 0x0020 ++ ++ unsigned short logical_address; ++} __attribute__((packed)); ++ ++struct ms_register { ++ struct ms_status_register status; ++ struct ms_id_register id; ++ unsigned char reserved[8]; ++ struct ms_param_register param; ++ struct ms_extra_data_register extra_data; ++} __attribute__((packed)); ++ ++struct mspro_param_register { ++ unsigned char system; ++#define MEMSTICK_SYS_SERIAL 0x80 ++#define MEMSTICK_SYS_PAR4 0x00 ++#define MEMSTICK_SYS_PAR8 0x40 ++ ++ unsigned short data_count; ++ unsigned int data_address; ++ unsigned char tpc_param; ++} __attribute__((packed)); ++ ++struct mspro_io_info_register { ++ unsigned char version; ++ unsigned char io_category; ++ unsigned char current_req; ++ unsigned char card_opt_info; ++ unsigned char rdy_wait_time; ++}__attribute__((packed)); ++ ++struct mspro_io_func_register { ++ unsigned char func_enable; ++ unsigned char func_select; ++ unsigned char func_intmask; ++ unsigned char transfer_mode; ++}__attribute__((packed)); ++ ++struct mspro_io_cmd_register { ++ unsigned short tpc_param; ++ unsigned short data_count; ++ unsigned int data_address; ++}__attribute__((packed)); ++ ++struct mspro_register { ++ struct ms_status_register status; ++ struct ms_id_register id; ++ unsigned char reserved0[8]; ++ struct mspro_param_register param; ++ unsigned char reserved1[8]; ++ struct mspro_io_info_register io_info; ++ struct mspro_io_func_register io_func; ++ unsigned char reserved2[7]; ++ struct mspro_io_cmd_register io_cmd; ++ unsigned char io_int; ++ unsigned char io_int_func; ++} __attribute__((packed)); ++ ++struct ms_register_addr { ++ unsigned char r_offset; ++ unsigned char r_length; ++ unsigned char w_offset; ++ unsigned char w_length; ++} __attribute__((packed)); ++ ++enum { ++ MS_TPC_READ_MG_STATUS = 0x01, ++ MS_TPC_READ_LONG_DATA = 0x02, ++ MS_TPC_READ_SHORT_DATA = 0x03, ++ MS_TPC_READ_MG_DATA = 0x03, ++ MS_TPC_READ_REG = 0x04, ++ MS_TPC_READ_QUAD_DATA = 0x05, ++ MS_TPC_READ_IO_DATA = 0x05, ++ MS_TPC_GET_INT = 0x07, ++ MS_TPC_SET_RW_REG_ADRS = 0x08, ++ MS_TPC_EX_SET_CMD = 0x09, ++ MS_TPC_WRITE_QUAD_DATA = 0x0a, ++ MS_TPC_WRITE_IO_DATA = 0x0a, ++ MS_TPC_WRITE_REG = 0x0b, ++ MS_TPC_WRITE_SHORT_DATA = 0x0c, ++ MS_TPC_WRITE_MG_DATA = 0x0c, ++ MS_TPC_WRITE_LONG_DATA = 0x0d, ++ MS_TPC_SET_CMD = 0x0e ++}; ++ ++enum { ++ MS_CMD_BLOCK_END = 0x33, ++ MS_CMD_RESET = 0x3c, ++ MS_CMD_BLOCK_WRITE = 0x55, ++ MS_CMD_SLEEP = 0x5a, ++ MS_CMD_BLOCK_ERASE = 0x99, ++ MS_CMD_BLOCK_READ = 0xaa, ++ MS_CMD_CLEAR_BUF = 0xc3, ++ MS_CMD_FLASH_STOP = 0xcc, ++ MS_CMD_LOAD_ID = 0x60, ++ MS_CMD_CMP_ICV = 0x7f, ++ MSPRO_CMD_FORMAT = 0x10, ++ MSPRO_CMD_SLEEP = 0x11, ++ MSPRO_CMD_WAKEUP = 0x12, ++ MSPRO_CMD_READ_DATA = 0x20, ++ MSPRO_CMD_WRITE_DATA = 0x21, ++ MSPRO_CMD_READ_ATRB = 0x24, ++ MSPRO_CMD_STOP = 0x25, ++ MSPRO_CMD_ERASE = 0x26, ++ MSPRO_CMD_READ_QUAD = 0x27, ++ MSPRO_CMD_WRITE_QUAD = 0x28, ++ MSPRO_CMD_SET_IBD = 0x46, ++ MSPRO_CMD_GET_IBD = 0x47, ++ MSPRO_CMD_IN_IO_DATA = 0xb0, ++ MSPRO_CMD_OUT_IO_DATA = 0xb1, ++ MSPRO_CMD_READ_IO_ATRB = 0xb2, ++ MSPRO_CMD_IN_IO_FIFO = 0xb3, ++ MSPRO_CMD_OUT_IO_FIFO = 0xb4, ++ MSPRO_CMD_IN_IOM = 0xb5, ++ MSPRO_CMD_OUT_IOM = 0xb6, ++}; ++ ++/*** Driver structures and functions ***/ ++ ++#define MEMSTICK_PART_SHIFT 3 ++ ++enum memstick_param { MEMSTICK_POWER = 1, MEMSTICK_INTERFACE }; ++ ++#define MEMSTICK_POWER_OFF 0 ++#define MEMSTICK_POWER_ON 1 ++ ++#define MEMSTICK_SERIAL 0 ++#define MEMSTICK_PAR4 1 ++#define MEMSTICK_PAR8 2 ++ ++struct memstick_host; ++struct memstick_driver; ++ ++#define MEMSTICK_MATCH_ALL 0x01 ++ ++#define MEMSTICK_TYPE_LEGACY 0xff ++#define MEMSTICK_TYPE_DUO 0x00 ++#define MEMSTICK_TYPE_PRO 0x01 ++ ++#define MEMSTICK_CATEGORY_STORAGE 0xff ++#define MEMSTICK_CATEGORY_STORAGE_DUO 0x00 ++ ++#define MEMSTICK_CLASS_GENERIC 0xff ++#define MEMSTICK_CLASS_GENERIC_DUO 0x00 ++ ++ ++struct memstick_device_id { ++ unsigned char match_flags; ++ unsigned char type; ++ unsigned char category; ++ unsigned char class; ++}; ++ ++struct memstick_request { ++ unsigned char tpc; ++ unsigned char data_dir:1, ++ need_card_int:1, ++ long_data:1; ++ unsigned char int_reg; ++ int error; ++ union { ++ struct scatterlist sg; ++ struct { ++ unsigned char data_len; ++ unsigned char data[15]; ++ }; ++ }; ++}; ++ ++struct memstick_dev { ++ struct memstick_device_id id; ++ struct memstick_host *host; ++ struct ms_register_addr reg_addr; ++ struct completion mrq_complete; ++ struct memstick_request current_mrq; ++ ++ /* Check that media driver is still willing to operate the device. */ ++ int (*check)(struct memstick_dev *card); ++ /* Get next request from the media driver. */ ++ int (*next_request)(struct memstick_dev *card, ++ struct memstick_request **mrq); ++ /* Tell the media driver to stop doing things */ ++ void (*stop)(struct memstick_dev *card); ++ /* Allow the media driver to continue */ ++ void (*start)(struct memstick_dev *card); ++ ++ struct device dev; ++}; ++ ++struct memstick_host { ++ struct mutex lock; ++ unsigned int id; ++ unsigned int caps; ++#define MEMSTICK_CAP_AUTO_GET_INT 1 ++#define MEMSTICK_CAP_PAR4 2 ++#define MEMSTICK_CAP_PAR8 4 ++ ++ struct work_struct media_checker; ++ struct class_device cdev; ++ ++ struct memstick_dev *card; ++ unsigned int retries; ++ ++ /* Notify the host that some requests are pending. */ ++ void (*request)(struct memstick_host *host); ++ /* Set host IO parameters (power, clock, etc). */ ++ int (*set_param)(struct memstick_host *host, ++ enum memstick_param param, ++ int value); ++ unsigned long private[0] ____cacheline_aligned; ++}; ++ ++struct memstick_driver { ++ struct memstick_device_id *id_table; ++ int (*probe)(struct memstick_dev *card); ++ void (*remove)(struct memstick_dev *card); ++ int (*suspend)(struct memstick_dev *card, ++ pm_message_t state); ++ int (*resume)(struct memstick_dev *card); ++ ++ struct device_driver driver; ++}; ++ ++int memstick_register_driver(struct memstick_driver *drv); ++void memstick_unregister_driver(struct memstick_driver *drv); ++ ++struct memstick_host *memstick_alloc_host(unsigned int extra, ++ struct device *dev); ++ ++int memstick_add_host(struct memstick_host *host); ++void memstick_remove_host(struct memstick_host *host); ++void memstick_free_host(struct memstick_host *host); ++void memstick_detect_change(struct memstick_host *host); ++void memstick_suspend_host(struct memstick_host *host); ++void memstick_resume_host(struct memstick_host *host); ++ ++void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc, ++ struct scatterlist *sg); ++void memstick_init_req(struct memstick_request *mrq, unsigned char tpc, ++ void *buf, size_t length); ++int memstick_next_req(struct memstick_host *host, ++ struct memstick_request **mrq); ++void memstick_new_req(struct memstick_host *host); ++ ++int memstick_set_rw_addr(struct memstick_dev *card); ++ ++static inline void *memstick_priv(struct memstick_host *host) ++{ ++ return (void *)host->private; ++} ++ ++static inline void *memstick_get_drvdata(struct memstick_dev *card) ++{ ++ return dev_get_drvdata(&card->dev); ++} ++ ++static inline void memstick_set_drvdata(struct memstick_dev *card, void *data) ++{ ++ dev_set_drvdata(&card->dev, data); ++} ++ ++#endif +diff --git a/drivers/mmc/ms/linux/xd_card.h b/drivers/mmc/ms/linux/xd_card.h +new file mode 100755 +index 0000000..179873e +--- /dev/null ++++ b/drivers/mmc/ms/linux/xd_card.h +@@ -0,0 +1,248 @@ ++/* ++ * xD Picture card support ++ * ++ * Copyright (C) 2008 JMicron Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef _XD_CARD_H ++#define _XD_CARD_H ++ ++#include ++#include ++#include ++#include ++#include "flash_bd.h" ++ ++struct xd_card_id1 { ++ unsigned char maker_code; ++ unsigned char device_code; ++ unsigned char option_code1; ++ unsigned char option_code2; ++} __attribute__((packed)); ++ ++struct xd_card_id2 { ++ unsigned char characteristics_code; ++#define XD_CARD_CELL_TYPE_MASK 0xc0 ++#define XD_CARD_MULTI_BLOCK_MASK 0x30 ++ ++ unsigned char vendor_code1; ++ unsigned char size_code; ++ unsigned char vendor_code2; ++ unsigned char vendor_code3; ++} __attribute__((packed)); ++ ++struct xd_card_id3 { ++ unsigned char vendor_code1; ++ unsigned char vendor_code2; ++ unsigned char id_code; ++ unsigned char vendor_code3; ++} __attribute__((packed)); ++ ++struct xd_card_extra { ++ unsigned int reserved; ++ unsigned char data_status; ++ unsigned char block_status; ++ unsigned short addr1; ++ unsigned char ecc_hi[3]; ++ unsigned short addr2; /* this should be identical to addr1 */ ++ unsigned char ecc_lo[3]; ++} __attribute__((packed)); ++ ++struct xd_card_idi { ++ unsigned char vendor_code1[6]; ++ unsigned char serial_number[20]; ++ unsigned char model_number[40]; ++ unsigned char vendor_code2[62]; ++} __attribute__((packed)); ++ ++enum { ++ XD_CARD_CMD_INPUT = 0x80, ++ XD_CARD_CMD_READ1 = 0x00, ++ XD_CARD_CMD_READ2 = 0x01, ++ XD_CARD_CMD_READ3 = 0x50, ++ XD_CARD_CMD_RESET = 0xff, ++ XD_CARD_CMD_PAGE_PROG = 0x10, ++ XD_CARD_CMD_DUMMY_PROG = 0x11, ++ XD_CARD_CMD_MULTI_PROG = 0x15, ++ XD_CARD_CMD_ERASE_SET = 0x60, ++ XD_CARD_CMD_ERASE_START = 0xd0, ++ XD_CARD_CMD_STATUS1 = 0x70, ++ XD_CARD_CMD_STATUS2 = 0x71, ++ XD_CARD_CMD_ID1 = 0x90, ++ XD_CARD_CMD_ID2 = 0x91, ++ XD_CARD_CMD_ID3 = 0x9a ++}; ++ ++struct xd_card_request { ++ unsigned char cmd; ++ unsigned char flags; ++#define XD_CARD_REQ_NO_ECC 0x20 ++#define XD_CARD_REQ_DATA 0x10 ++#define XD_CARD_REQ_ID 0x08 ++#define XD_CARD_REQ_STATUS 0x04 ++#define XD_CARD_REQ_EXTRA 0x02 ++#define XD_CARD_REQ_DIR 0x01 ++ ++ unsigned char status; ++#define XD_CARD_STTS_RW 0x80 ++#define XD_CARD_STTS_READY 0x40 ++#define XD_CARD_STTS_D3_FAIL 0x10 ++#define XD_CARD_STTS_D2_FAIL 0x08 ++#define XD_CARD_STTS_D1_FAIL 0x04 ++#define XD_CARD_STTS_D0_FAIL 0x02 ++#define XD_CARD_STTS_FAIL 0x01 ++ ++ void *id; ++ unsigned long long addr; ++ int error; ++ unsigned int count; ++ struct scatterlist sg; ++}; ++ ++ ++enum { ++ XD_CARD_CIS_TPL_DEVICE = 0x01, ++ XD_CARD_CIS_TPL_NO_LINK = 0x14, ++ XD_CARD_CIS_TPL_VERS_1 = 0x15, ++ XD_CARD_CIS_TPL_JEDEC_C = 0x18, ++ XD_CARD_CIS_TPL_CONFIG = 0x1a, ++ XD_CARD_CIS_TPL_CFTABLE_E = 0x1b, ++ XD_CARD_CIS_TPL_MANF_ID = 0x20, ++ XD_CARD_CIS_TPL_FUNC_ID = 0x21, ++ XD_CARD_CIS_TPL_FUNC_E = 0x22 ++}; ++ ++struct xd_card_host; ++ ++struct xd_card_media { ++ struct xd_card_host *host; ++ unsigned int usage_count; ++ struct gendisk *disk; ++ struct request_queue *queue; ++ spinlock_t q_lock; ++ struct task_struct *f_thread; ++ struct request *block_req; ++ struct flash_bd_request flash_req; ++ struct flash_bd *fbd; ++ struct bin_attribute dev_attr_block_map; ++ struct xd_card_request req; ++ struct completion req_complete; ++ int (*next_request[2])(struct xd_card_media *card, ++ struct xd_card_request **req); ++ ++ unsigned char mask_rom:1, ++ sm_media:1, ++ read_only:1, ++ auto_ecc:1; ++ ++ /* These bits must be protected by q_lock */ ++ unsigned char has_request:1, ++ format:1, ++ eject:1; ++ ++ unsigned char page_addr_bits; ++ unsigned char block_addr_bits; ++ unsigned char addr_bytes; ++ ++ unsigned int capacity; ++ unsigned int cylinders; ++ unsigned int heads; ++ unsigned int sectors_per_head; ++ ++ unsigned int page_size; ++ unsigned int hw_page_size; ++ ++ unsigned int zone_cnt; ++ unsigned int phy_block_cnt; ++ unsigned int log_block_cnt; ++ unsigned int page_cnt; ++ unsigned int cis_block; ++ ++ struct xd_card_id1 id1; ++ struct xd_card_id2 id2; ++ struct xd_card_id3 id3; ++ unsigned char cis[128]; ++ struct xd_card_idi idi; ++ ++#define XD_CARD_MAX_SEGS 32 ++ struct scatterlist req_sg[XD_CARD_MAX_SEGS]; ++ unsigned int seg_count; ++ unsigned int seg_pos; ++ unsigned int seg_off; ++ ++ unsigned int trans_cnt; ++ unsigned int trans_len; ++ unsigned char *t_buf; ++}; ++ ++enum xd_card_param { ++ XD_CARD_POWER = 1, ++ XD_CARD_CLOCK, ++ XD_CARD_PAGE_SIZE, ++ XD_CARD_EXTRA_SIZE, ++ XD_CARD_ADDR_SIZE ++}; ++ ++#define XD_CARD_POWER_OFF 0 ++#define XD_CARD_POWER_ON 1 ++ ++#define XD_CARD_NORMAL 0 ++#define XD_CARD_SLOW 1 ++ ++struct xd_card_host { ++ struct device *dev; ++ struct mutex lock; ++ struct work_struct media_checker; ++ struct xd_card_media *card; ++ struct xd_card_extra extra; ++ unsigned int extra_pos; ++ ++ unsigned int retries; ++ unsigned int caps; ++#define XD_CARD_CAP_AUTO_ECC 1 ++#define XD_CARD_CAP_FIXED_EXTRA 2 ++#define XD_CARD_CAP_CMD_SHORTCUT 4 ++ ++ /* Notify the host that some flash memory requests are pending. */ ++ void (*request)(struct xd_card_host *host); ++ /* Set host IO parameters (power, clock, etc). */ ++ int (*set_param)(struct xd_card_host *host, enum xd_card_param param, ++ int value); ++ unsigned long private[0] ____cacheline_aligned; ++}; ++ ++#define XD_CARD_PART_SHIFT 3 ++ ++void xd_card_detect_change(struct xd_card_host *host); ++int xd_card_suspend_host(struct xd_card_host *host); ++int xd_card_resume_host(struct xd_card_host *host); ++struct xd_card_host *xd_card_alloc_host(unsigned int extra, struct device *dev); ++void xd_card_free_host(struct xd_card_host *host); ++int xd_card_next_req(struct xd_card_host *host, struct xd_card_request **req); ++void xd_card_set_extra(struct xd_card_host *host, unsigned char *e_data, ++ unsigned int e_size); ++void xd_card_get_extra(struct xd_card_host *host, unsigned char *e_data, ++ unsigned int e_size); ++ ++unsigned long long xd_card_trans_addr(struct xd_card_host *host, ++ unsigned int zone, unsigned int block, ++ unsigned int page); ++ ++int xd_card_ecc_step(unsigned int *state, unsigned int *pos, ++ unsigned char *data, unsigned int count); ++unsigned int xd_card_ecc_value(unsigned int state); ++int xd_card_fix_ecc(unsigned int *pos, unsigned char *mask, ++ unsigned int act_ecc, unsigned int ref_ecc); ++ ++static inline void *xd_card_priv(struct xd_card_host *host) ++{ ++ return (void *)host->private; ++} ++ ++#endif ++ +diff --git a/drivers/mmc/ms/memstick.c b/drivers/mmc/ms/memstick.c +index acd2151..21d17e1 100644 +--- a/drivers/mmc/ms/memstick.c ++++ b/drivers/mmc/ms/memstick.c +@@ -12,13 +12,14 @@ + * + */ + +-#include "memstick.h" ++#include "linux/memstick.h" + #include + #include + #include ++#include + + #define DRIVER_NAME "memstick" +-#define DRIVER_VERSION "0.2" ++#define DRIVER_VERSION "0.2a" + + static unsigned int cmd_retries = 3; + module_param(cmd_retries, uint, 0644); +@@ -59,44 +60,46 @@ static int memstick_bus_match(struct device *dev, struct device_driver *drv) + return 0; + } + +-static int memstick_uevent(struct device *dev, char **envp, int num_envp, +- char *buffer, int buffer_size) ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) ++static int memstick_uevent(struct device *dev, struct kobj_uevent_env *env) + { + struct memstick_dev *card = container_of(dev, struct memstick_dev, +- dev); +- int i = 0; +- int length = 0; ++ dev); + +- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, +- "MEMSTICK_TYPE=%02X", card->id.type)) ++ if (add_uevent_var(env, "MEMSTICK_TYPE=%02X", card->id.type)) + return -ENOMEM; +- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, +- "MEMSTICK_CATEGORY=%02X", card->id.category)) ++ ++ if (add_uevent_var(env, "MEMSTICK_CATEGORY=%02X", card->id.category)) + return -ENOMEM; +- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, +- "MEMSTICK_CLASS=%02X", card->id.class)) ++ ++ if (add_uevent_var(env, "MEMSTICK_CLASS=%02X", card->id.class)) + return -ENOMEM; + + return 0; + } +-/* +-static int memstick_uevent(struct device *dev, struct kobj_uevent_env *env) ++#else ++static int memstick_uevent(struct device *dev, char **envp, int num_envp, ++ char *buffer, int buffer_size) + { + struct memstick_dev *card = container_of(dev, struct memstick_dev, + dev); ++ int i = 0; ++ int length = 0; + +- if (add_uevent_var(env, "MEMSTICK_TYPE=%02X", card->id.type)) ++ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "MEMSTICK_TYPE=%02X", card->id.type)) + return -ENOMEM; +- +- if (add_uevent_var(env, "MEMSTICK_CATEGORY=%02X", card->id.category)) ++ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "MEMSTICK_CATEGORY=%02X", card->id.category)) + return -ENOMEM; +- +- if (add_uevent_var(env, "MEMSTICK_CLASS=%02X", card->id.class)) ++ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "MEMSTICK_CLASS=%02X", card->id.class)) + return -ENOMEM; + + return 0; + } +-*/ ++#endif ++ + static int memstick_device_probe(struct device *dev) + { + struct memstick_dev *card = container_of(dev, struct memstick_dev, +@@ -271,9 +274,12 @@ EXPORT_SYMBOL(memstick_next_req); + */ + void memstick_new_req(struct memstick_host *host) + { ++ if (host->card) { + host->retries = cmd_retries; ++ INIT_COMPLETION(host->card->mrq_complete); + host->request(host); + } ++} + EXPORT_SYMBOL(memstick_new_req); + + /** +@@ -360,9 +366,7 @@ static int h_memstick_read_dev_id(struct memstick_dev *card, + card->id.class = id_reg.class; + } + complete(&card->mrq_complete); +-#ifdef DBG + dev_dbg(&card->dev, "if_mode = %02x\n", id_reg.if_mode); +-#endif + return -EAGAIN; + } + } +@@ -439,11 +443,14 @@ err_out: + return NULL; + } + +-static void memstick_power_on(struct memstick_host *host) ++static int memstick_power_on(struct memstick_host *host) + { +- host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); +- host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); +- msleep(1); ++ int rc = host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); ++ ++ if (!rc) ++ rc = host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); ++ ++ return rc; + } + + static void memstick_check(struct work_struct *work) +@@ -452,12 +459,13 @@ static void memstick_check(struct work_struct *work) + media_checker); + struct memstick_dev *card; + +-#ifdef DBG + dev_dbg(host->cdev.dev, "memstick_check started\n"); +-#endif + mutex_lock(&host->lock); +- if (!host->card) +- memstick_power_on(host); ++ if (!host->card) { ++ if (memstick_power_on(host)) ++ goto out_power_off; ++ } else ++ host->card->stop(host->card); + + card = memstick_alloc_card(host); + +@@ -467,17 +475,16 @@ static void memstick_check(struct work_struct *work) + host->card = NULL; + } + } else { +-#ifdef DBG + dev_dbg(host->cdev.dev, "new card %02x, %02x, %02x\n", + card->id.type, card->id.category, card->id.class); +-#endif + if (host->card) { + if (memstick_set_rw_addr(host->card) + || !memstick_dev_match(host->card, &card->id) + || !(host->card->check(host->card))) { + device_unregister(&host->card->dev); + host->card = NULL; +- } ++ } else ++ host->card->start(host->card); + } + + if (!host->card) { +@@ -490,13 +497,12 @@ static void memstick_check(struct work_struct *work) + kfree(card); + } + ++out_power_off: + if (!host->card) + host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); + + mutex_unlock(&host->lock); +-#ifdef DBG + dev_dbg(host->cdev.dev, "memstick_check finished\n"); +-#endif + } + + /** +@@ -605,10 +611,15 @@ EXPORT_SYMBOL(memstick_suspend_host); + */ + void memstick_resume_host(struct memstick_host *host) + { ++ int rc = 0; ++ + mutex_lock(&host->lock); +- host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); ++ if (host->card) ++ rc = memstick_power_on(host); + mutex_unlock(&host->lock); +- memstick_detect_change(host); ++ ++ if (!rc) ++ memstick_detect_change(host); + } + EXPORT_SYMBOL(memstick_resume_host); + +diff --git a/drivers/mmc/ms/mspro_block.c b/drivers/mmc/ms/mspro_block.c +index bd6b069..941d356 100644 +--- a/drivers/mmc/ms/mspro_block.c ++++ b/drivers/mmc/ms/mspro_block.c +@@ -17,10 +17,10 @@ + #include + #include + #include +-#include "memstick.h" ++#include ++#include "linux/memstick.h" + + #define DRIVER_NAME "mspro_block" +-#define DRIVER_VERSION "0.2" + + static int major; + module_param(major, int, 0644); +@@ -31,6 +31,52 @@ module_param(major, int, 0644); + #define MSPRO_BLOCK_SIGNATURE 0xa5c3 + #define MSPRO_BLOCK_MAX_ATTRIBUTES 41 + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) ++static inline int __blk_end_request(struct request *rq, int error, ++ unsigned int nr_bytes) ++{ ++ int chunk; ++ ++ if (!error) ++ chunk = end_that_request_chunk(rq, 1, nr_bytes); ++ else ++ chunk = end_that_request_first(rq, error, nr_bytes); ++ ++ if (!chunk) { ++ add_disk_randomness(rq->rq_disk); ++ blkdev_dequeue_request(rq); ++ end_that_request_last(rq, error < 0 ? error : 1); ++ } ++ ++ return chunk; ++} ++ ++unsigned int ms_blk_rq_cur_bytes(struct request *rq) ++{ ++ if (blk_fs_request(rq)) ++ return rq->current_nr_sectors << 9; ++ ++ if (rq->bio) ++ return rq->bio->bi_size; ++ ++ return rq->data_len; ++} ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++static inline void sg_set_page(struct scatterlist *sg, struct page *page, ++ unsigned int len, unsigned int offset) ++{ ++ sg->page = page; ++ sg->offset = offset; ++ sg->length = len; ++} ++ ++static inline struct page *sg_page(struct scatterlist *sg) ++{ ++ return sg->page; ++} ++ + static unsigned int rq_byte_size(struct request *rq) + { + if (blk_fs_request(rq)) +@@ -40,16 +86,22 @@ static unsigned int rq_byte_size(struct request *rq) + } + + static inline void __end_request(struct request *rq, int uptodate, +- unsigned int nr_bytes, int dequeue) ++ unsigned int nr_bytes, int dequeue) + { + if (!end_that_request_chunk(rq, uptodate, nr_bytes)) { + if (dequeue) + blkdev_dequeue_request(rq); + add_disk_randomness(rq->rq_disk); + end_that_request_last(rq, uptodate); +- } ++ } + } + ++void end_queued_request(struct request *rq, int uptodate) ++{ ++ __end_request(rq, uptodate, rq_byte_size(rq), 1); ++} ++#endif ++ + enum { + MSPRO_BLOCK_ID_SYSINFO = 0x10, + MSPRO_BLOCK_ID_MODELNAME = 0x15, +@@ -156,9 +208,8 @@ struct mspro_block_data { + unsigned int caps; + struct gendisk *disk; + struct request_queue *queue; ++ struct request *block_req; + spinlock_t q_lock; +- wait_queue_head_t q_wait; +- struct task_struct *q_thread; + + unsigned short page_size; + unsigned short cylinders; +@@ -167,9 +218,10 @@ struct mspro_block_data { + + unsigned char system; + unsigned char read_only:1, +- active:1, ++ eject:1, + has_request:1, +- data_dir:1; ++ data_dir:1, ++ active:1; + unsigned char transfer_cmd; + + int (*mrq_handler)(struct memstick_dev *card, +@@ -180,12 +232,14 @@ struct mspro_block_data { + struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; + unsigned int seg_count; + unsigned int current_seg; +- unsigned short current_page; ++ unsigned int current_page; + }; + + static DEFINE_IDR(mspro_block_disk_idr); + static DEFINE_MUTEX(mspro_block_disk_lock); + ++static int mspro_block_complete_req(struct memstick_dev *card, int error); ++ + /*** Block device ***/ + + static int mspro_block_bd_open(struct inode *inode, struct file *filp) +@@ -217,8 +271,10 @@ static int mspro_block_disk_release(struct gendisk *disk) + + mutex_lock(&mspro_block_disk_lock); + +- if (msb->usage_count) { +- msb->usage_count--; ++ if (msb) { ++ if (msb->usage_count) ++ msb->usage_count--; ++ + if (!msb->usage_count) { + kfree(msb); + disk->private_data = NULL; +@@ -353,13 +409,15 @@ static ssize_t mspro_block_attr_show_sysinfo(struct device *dev, + rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: " + "GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n", + date_tz, date_tz_f, +- be16_to_cpu(*(unsigned short *)&x_sys->assembly_date[1]), ++ be16_to_cpu(*(unsigned short *) ++ &x_sys->assembly_date[1]), + x_sys->assembly_date[3], x_sys->assembly_date[4], + x_sys->assembly_date[5], x_sys->assembly_date[6], + x_sys->assembly_date[7]); + rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "serial number: %x\n", + be32_to_cpu(x_sys->serial_number)); +- rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly maker code: %x\n", ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, ++ "assembly maker code: %x\n", + x_sys->assembly_maker_code); + rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly model code: " + "%02x%02x%02x\n", x_sys->assembly_model_code[0], +@@ -375,7 +433,8 @@ static ssize_t mspro_block_attr_show_sysinfo(struct device *dev, + x_sys->vpp); + rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller number: %x\n", + be16_to_cpu(x_sys->controller_number)); +- rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller function: %x\n", ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, ++ "controller function: %x\n", + be16_to_cpu(x_sys->controller_function)); + rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n", + be16_to_cpu(x_sys->start_sector)); +@@ -540,11 +599,13 @@ static int h_mspro_block_req_init(struct memstick_dev *card, + static int h_mspro_block_default(struct memstick_dev *card, + struct memstick_request **mrq) + { +- complete(&card->mrq_complete); +- if (!(*mrq)->error) +- return -EAGAIN; +- else +- return (*mrq)->error; ++ return mspro_block_complete_req(card, (*mrq)->error); ++} ++ ++static int h_mspro_block_default_bad(struct memstick_dev *card, ++ struct memstick_request **mrq) ++{ ++ return -ENXIO; + } + + static int h_mspro_block_get_ro(struct memstick_dev *card, +@@ -552,46 +613,30 @@ static int h_mspro_block_get_ro(struct memstick_dev *card, + { + struct mspro_block_data *msb = memstick_get_drvdata(card); + +- if ((*mrq)->error) { +- complete(&card->mrq_complete); +- return (*mrq)->error; ++ if (!(*mrq)->error) { ++ if ((*mrq)->data[offsetof(struct ms_status_register, status0)] ++ & MEMSTICK_STATUS0_WP) ++ msb->read_only = 1; ++ else ++ msb->read_only = 0; + } + +- if ((*mrq)->data[offsetof(struct ms_status_register, status0)] +- & MEMSTICK_STATUS0_WP) +- msb->read_only = 1; +- else +- msb->read_only = 0; +- +- complete(&card->mrq_complete); +- return -EAGAIN; ++ return mspro_block_complete_req(card, (*mrq)->error); + } + + static int h_mspro_block_wait_for_ced(struct memstick_dev *card, + struct memstick_request **mrq) + { +- if ((*mrq)->error) { +- complete(&card->mrq_complete); +- return (*mrq)->error; +- } +- +-#ifdef DBG + dev_dbg(&card->dev, "wait for ced: value %x\n", (*mrq)->data[0]); +-#endif + +- if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) { +- card->current_mrq.error = -EFAULT; +- complete(&card->mrq_complete); +- return card->current_mrq.error; ++ if (!(*mrq)->error) { ++ if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) ++ (*mrq)->error = -EFAULT; ++ else if (!((*mrq)->data[0] & MEMSTICK_INT_CED)) ++ return 0; + } + +- if (!((*mrq)->data[0] & MEMSTICK_INT_CED)) +- return 0; +- else { +- card->current_mrq.error = 0; +- complete(&card->mrq_complete); +- return -EAGAIN; +- } ++ return mspro_block_complete_req(card, (*mrq)->error); + } + + static int h_mspro_block_transfer_data(struct memstick_dev *card, +@@ -602,10 +647,8 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card, + struct scatterlist t_sg = { 0 }; + size_t t_offset; + +- if ((*mrq)->error) { +- complete(&card->mrq_complete); +- return (*mrq)->error; +- } ++ if ((*mrq)->error) ++ return mspro_block_complete_req(card, (*mrq)->error); + + switch ((*mrq)->tpc) { + case MS_TPC_WRITE_REG: +@@ -636,8 +679,8 @@ has_int_reg: + + if (msb->current_seg == msb->seg_count) { + if (t_val & MEMSTICK_INT_CED) { +- complete(&card->mrq_complete); +- return -EAGAIN; ++ return mspro_block_complete_req(card, ++ 0); + } else { + card->next_request + = h_mspro_block_wait_for_ced; +@@ -685,157 +728,184 @@ has_int_reg: + + /*** Data transfer ***/ + +-static void mspro_block_process_request(struct memstick_dev *card, +- struct request *req) ++static int mspro_block_issue_req(struct memstick_dev *card, int chunk) + { + struct mspro_block_data *msb = memstick_get_drvdata(card); +- struct mspro_param_register param; +- int rc, chunk, cnt; +- unsigned short page_count; + sector_t t_sec; +- unsigned long flags; ++ unsigned int count; ++ struct mspro_param_register param; + +- do { +- page_count = 0; ++try_again: ++ while (chunk) { ++ msb->current_page = 0; + msb->current_seg = 0; +- msb->seg_count = blk_rq_map_sg(req->q, req, msb->req_sg); ++ msb->seg_count = blk_rq_map_sg(msb->block_req->q, ++ msb->block_req, ++ msb->req_sg); + +- if (msb->seg_count) { +- msb->current_page = 0; +- for (rc = 0; rc < msb->seg_count; rc++) +- page_count += msb->req_sg[rc].length +- / msb->page_size; +- +- t_sec = req->sector; +- sector_div(t_sec, msb->page_size >> 9); +- param.system = msb->system; +- param.data_count = cpu_to_be16(page_count); +- param.data_address = cpu_to_be32((uint32_t)t_sec); +- param.tpc_param = 0; +- +- msb->data_dir = rq_data_dir(req); +- msb->transfer_cmd = msb->data_dir == READ +- ? MSPRO_CMD_READ_DATA +- : MSPRO_CMD_WRITE_DATA; +- +-#ifdef DBG +- dev_dbg(&card->dev, "data transfer: cmd %x, " +- "lba %x, count %x\n", msb->transfer_cmd, +- be32_to_cpu(param.data_address), +- page_count); +-#endif ++ if (!msb->seg_count) { ++ chunk = __blk_end_request(msb->block_req, -ENOMEM, ++ ms_blk_rq_cur_bytes(msb->block_req)); ++ continue; ++ } + +- card->next_request = h_mspro_block_req_init; +- msb->mrq_handler = h_mspro_block_transfer_data; +- memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, +- ¶m, sizeof(param)); +- memstick_new_req(card->host); +- wait_for_completion(&card->mrq_complete); +- rc = card->current_mrq.error; ++ t_sec = msb->block_req->sector << 9; ++ sector_div(t_sec, msb->page_size); + +- if (rc || (card->current_mrq.tpc == MSPRO_CMD_STOP)) { +- for (cnt = 0; cnt < msb->current_seg; cnt++) +- page_count += msb->req_sg[cnt].length +- / msb->page_size; +- +- if (msb->current_page) +- page_count += msb->current_page - 1; +- +- if (page_count && (msb->data_dir == READ)) +- rc = msb->page_size * page_count; +- else +- rc = -EIO; +- } else +- rc = msb->page_size * page_count; +- } else +- rc = -EFAULT; ++ count = msb->block_req->nr_sectors << 9; ++ count /= msb->page_size; + +- spin_lock_irqsave(&msb->q_lock, flags); +- if (rc >= 0) +- chunk = end_that_request_chunk(req, 1, rc); +- else +- chunk = end_that_request_first(req, rc, +- req->current_nr_sectors); ++ param.system = msb->system; ++ param.data_count = cpu_to_be16(count); ++ param.data_address = cpu_to_be32((uint32_t)t_sec); ++ param.tpc_param = 0; + +-#ifdef DBG +- dev_dbg(&card->dev, "end chunk %d, %d\n", rc, chunk); +-#endif +- if (!chunk) { +- add_disk_randomness(req->rq_disk); +- blkdev_dequeue_request(req); +- end_that_request_last(req, rc > 0 ? 1 : rc); +- } +- spin_unlock_irqrestore(&msb->q_lock, flags); +- } while (chunk); ++ msb->data_dir = rq_data_dir(msb->block_req); ++ msb->transfer_cmd = msb->data_dir == READ ++ ? MSPRO_CMD_READ_DATA ++ : MSPRO_CMD_WRITE_DATA; ++ ++ dev_dbg(&card->dev, "data transfer: cmd %x, " ++ "lba %x, count %x\n", msb->transfer_cmd, ++ be32_to_cpu(param.data_address), count); ++ ++ card->next_request = h_mspro_block_req_init; ++ msb->mrq_handler = h_mspro_block_transfer_data; ++ memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ++ ¶m, sizeof(param)); ++ memstick_new_req(card->host); ++ return 0; ++ } ++ ++ dev_dbg(&card->dev, "elv_next\n"); ++ msb->block_req = elv_next_request(msb->queue); ++ if (!msb->block_req) { ++ dev_dbg(&card->dev, "issue end\n"); ++ return -EAGAIN; ++ } + ++ dev_dbg(&card->dev, "trying again\n"); ++ chunk = 1; ++ goto try_again; + } + +-static int mspro_block_has_request(struct mspro_block_data *msb) ++static int mspro_block_complete_req(struct memstick_dev *card, int error) + { +- int rc = 0; +- unsigned long flags; ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ int chunk, cnt; ++ unsigned int t_len = 0; ++ unsigned int flags; + + spin_lock_irqsave(&msb->q_lock, flags); +- if (kthread_should_stop() || msb->has_request) +- rc = 1; ++ dev_dbg(&card->dev, "complete %d, %d\n", msb->has_request ? 1 : 0, ++ error); ++ ++ if (msb->has_request) { ++ /* Nothing to do - not really an error */ ++ if (error == -EAGAIN) ++ error = 0; ++ ++ if (error || (card->current_mrq.tpc == MSPRO_CMD_STOP)) { ++ if (msb->data_dir == READ) { ++ for (cnt = 0; cnt < msb->current_seg; cnt++) ++ t_len += msb->req_sg[cnt].length ++ / msb->page_size; ++ ++ if (msb->current_page) ++ t_len += msb->current_page - 1; ++ ++ t_len *= msb->page_size; ++ } ++ } else ++ t_len = msb->block_req->nr_sectors << 9; ++ ++ dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error); ++ ++ if (error && !t_len) ++ t_len = ms_blk_rq_cur_bytes(msb->block_req); ++ ++ chunk = __blk_end_request(msb->block_req, error, t_len); ++ ++ error = mspro_block_issue_req(card, chunk); ++ ++ if (!error) ++ goto out; ++ else ++ msb->has_request = 0; ++ } else { ++ if (!error) ++ error = -EAGAIN; ++ } ++ ++ card->next_request = h_mspro_block_default_bad; ++ complete_all(&card->mrq_complete); ++out: + spin_unlock_irqrestore(&msb->q_lock, flags); +- return rc; ++ return error; + } + +-static int mspro_block_queue_thread(void *data) ++static void mspro_block_stop(struct memstick_dev *card) + { +- struct memstick_dev *card = data; +- struct memstick_host *host = card->host; + struct mspro_block_data *msb = memstick_get_drvdata(card); +- struct request *req; ++ int rc = 0; + unsigned long flags; + + while (1) { +- wait_event(msb->q_wait, mspro_block_has_request(msb)); +-#ifdef DBG +- dev_dbg(&card->dev, "thread iter\n"); +-#endif +- + spin_lock_irqsave(&msb->q_lock, flags); +- req = elv_next_request(msb->queue); +-#ifdef DBG +- dev_dbg(&card->dev, "next req %p\n", req); +-#endif +- if (!req) { +- msb->has_request = 0; +- if (kthread_should_stop()) { +- spin_unlock_irqrestore(&msb->q_lock, flags); +- break; +- } +- } else +- msb->has_request = 1; ++ if (!msb->has_request) { ++ blk_stop_queue(msb->queue); ++ rc = 1; ++ } + spin_unlock_irqrestore(&msb->q_lock, flags); + +- if (req) { +- mutex_lock(&host->lock); +- mspro_block_process_request(card, req); +- mutex_unlock(&host->lock); +- } ++ if (rc) ++ break; ++ ++ wait_for_completion(&card->mrq_complete); + } +-#ifdef DBG +- dev_dbg(&card->dev, "thread finished\n"); +-#endif +- return 0; + } + +-static void mspro_block_request(struct request_queue *q) ++static void mspro_block_start(struct memstick_dev *card) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&msb->q_lock, flags); ++ blk_start_queue(msb->queue); ++ spin_unlock_irqrestore(&msb->q_lock, flags); ++} ++ ++static int mspro_block_prepare_req(struct request_queue *q, struct request *req) ++{ ++ if (!blk_fs_request(req) && !blk_pc_request(req)) { ++ blk_dump_rq_flags(req, "MSPro unsupported request"); ++ return BLKPREP_KILL; ++ } ++ ++ req->cmd_flags |= REQ_DONTPREP; ++ ++ return BLKPREP_OK; ++} ++ ++static void mspro_block_submit_req(struct request_queue *q) + { + struct memstick_dev *card = q->queuedata; + struct mspro_block_data *msb = memstick_get_drvdata(card); + struct request *req = NULL; + +- if (msb->q_thread) { +- msb->has_request = 1; +- wake_up_all(&msb->q_wait); +- } else { ++ if (msb->has_request) ++ return; ++ ++ if (msb->eject) { + while ((req = elv_next_request(q)) != NULL) +- __end_request(req, -ENODEV, rq_byte_size(req), 1); ++ end_queued_request(req, -ENODEV); ++ ++ return; + } ++ ++ msb->has_request = 1; ++ if (mspro_block_issue_req(card, 0)) ++ msb->has_request = 0; + } + + /*** Initialization ***/ +@@ -852,79 +922,88 @@ static int mspro_block_wait_for_ced(struct memstick_dev *card) + return card->current_mrq.error; + } + +-static int mspro_block_switch_interface(struct memstick_dev *card, +- unsigned int interface) ++static int mspro_block_set_interface(struct memstick_dev *card, ++ unsigned char sys_reg) + { + struct memstick_host *host = card->host; + struct mspro_block_data *msb = memstick_get_drvdata(card); + struct mspro_param_register param = { +- .system = 0, ++ .system = sys_reg, + .data_count = 0, + .data_address = 0, + .tpc_param = 0 + }; + +- switch (interface) { +- case MEMSTICK_SERIAL: +- param.system = MEMSTICK_SYS_SERIAL; +- break; +- case MEMSTICK_PAR4: +- param.system = MEMSTICK_SYS_PAR4; +- break; +- case MEMSTICK_PAR8: +- if (msb->system != MEMSTICK_SYS_PAR4) +- return -EINVAL; +- param.system = MEMSTICK_SYS_PAR8; +- break; +- default: +- return -EINVAL; +- }; +- + card->next_request = h_mspro_block_req_init; + msb->mrq_handler = h_mspro_block_default; + memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, + sizeof(param)); + memstick_new_req(host); + wait_for_completion(&card->mrq_complete); +-#ifdef DBG +- dev_dbg(&card->dev, "switch interface to %x, error %d\n", interface, +- card->current_mrq.error); +-#endif +- if (card->current_mrq.error) +- return card->current_mrq.error; ++ return card->current_mrq.error; ++} + +- msb->system = param.system; +- host->set_param(host, MEMSTICK_INTERFACE, interface); ++static int mspro_block_switch_interface(struct memstick_dev *card) ++{ ++ struct memstick_host *host = card->host; ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ int rc = 0; ++ ++ if (msb->caps & MEMSTICK_CAP_PAR4) ++ rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR4); ++ else ++ return 0; ++ ++ if (rc) { ++ printk(KERN_WARNING ++ "%s: could not switch to 4-bit mode, error %d\n", ++ card->dev.bus_id, rc); ++ return 0; ++ } ++ ++ msb->system = MEMSTICK_SYS_PAR4; ++ host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4); ++ printk(KERN_INFO "%s: switching to 4-bit parallel mode\n", ++ card->dev.bus_id); ++ ++ if (msb->caps & MEMSTICK_CAP_PAR8) { ++ rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR8); ++ ++ if (!rc) { ++ msb->system = MEMSTICK_SYS_PAR8; ++ host->set_param(host, MEMSTICK_INTERFACE, ++ MEMSTICK_PAR8); ++ printk(KERN_INFO ++ "%s: switching to 8-bit parallel mode\n", ++ card->dev.bus_id); ++ } else ++ printk(KERN_WARNING ++ "%s: could not switch to 8-bit mode, error %d\n", ++ card->dev.bus_id, rc); ++ } + + card->next_request = h_mspro_block_req_init; + msb->mrq_handler = h_mspro_block_default; + memstick_init_req(&card->current_mrq, MS_TPC_GET_INT, NULL, 1); + memstick_new_req(card->host); + wait_for_completion(&card->mrq_complete); ++ rc = card->current_mrq.error; + +- if (card->current_mrq.error) { ++ if (rc) { ++ printk(KERN_WARNING ++ "%s: interface error, trying to fall back to serial\n", ++ card->dev.bus_id); + msb->system = MEMSTICK_SYS_SERIAL; + host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); + msleep(10); + host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); + host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); + +- if (memstick_set_rw_addr(card)) +- return card->current_mrq.error; +- +- param.system = msb->system; +- +- card->next_request = h_mspro_block_req_init; +- msb->mrq_handler = h_mspro_block_default; +- memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, +- sizeof(param)); +- memstick_new_req(host); +- wait_for_completion(&card->mrq_complete); +- +- return -EFAULT; ++ rc = memstick_set_rw_addr(card); ++ if (!rc) ++ rc = mspro_block_set_interface(card, msb->system); + } +- +- return 0; ++ return rc; + } + + /* Memory allocated for attributes by this function should be freed by +@@ -1010,16 +1089,14 @@ static int mspro_block_read_attributes(struct memstick_dev *card) + msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr; + addr = be32_to_cpu(attr->entries[cnt].address); + rc = be32_to_cpu(attr->entries[cnt].size); +-#ifdef DBG + dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, " + "size %x\n", cnt, attr->entries[cnt].id, addr, rc); +-#endif + s_attr->id = attr->entries[cnt].id; + if (mspro_block_attr_name(s_attr->id)) +- scnprintf(s_attr->name, sizeof(s_attr->name), "%s", ++ snprintf(s_attr->name, sizeof(s_attr->name), "%s", + mspro_block_attr_name(attr->entries[cnt].id)); + else +- scnprintf(s_attr->name, sizeof(s_attr->name), ++ snprintf(s_attr->name, sizeof(s_attr->name), + "attr_x%02x", attr->entries[cnt].id); + + s_attr->dev_attr.attr.name = s_attr->name; +@@ -1070,11 +1147,9 @@ static int mspro_block_read_attributes(struct memstick_dev *card) + msb->data_dir = READ; + msb->transfer_cmd = MSPRO_CMD_READ_ATRB; + +-#ifdef DBG + dev_dbg(&card->dev, "reading attribute pages %x, %x\n", + be32_to_cpu(param.data_address), + be16_to_cpu(param.data_count)); +-#endif + + card->next_request = h_mspro_block_req_init; + msb->mrq_handler = h_mspro_block_transfer_data; +@@ -1114,20 +1189,9 @@ static int mspro_block_init_card(struct memstick_dev *card) + return -EIO; + + msb->caps = host->caps; +- if (msb->caps & MEMSTICK_CAP_PAR4) { +- if (mspro_block_switch_interface(card, MEMSTICK_PAR4)) { +- printk(KERN_WARNING "%s: could not switch to " +- "4-bit mode\n", card->dev.bus_id); +- msb->caps &= ~MEMSTICK_CAP_PAR4; +- } else if (msb->caps & MEMSTICK_CAP_PAR8) { +- if (mspro_block_switch_interface(card, +- MEMSTICK_PAR8)) { +- printk(KERN_WARNING "%s: could not switch to " +- "8-bit mode\n", card->dev.bus_id); +- msb->caps &= ~MEMSTICK_CAP_PAR8; +- } +- } +- } ++ rc = mspro_block_switch_interface(card); ++ if (rc) ++ return rc; + + msleep(200); + rc = mspro_block_wait_for_ced(card); +@@ -1146,18 +1210,14 @@ static int mspro_block_init_card(struct memstick_dev *card) + if (card->current_mrq.error) + return card->current_mrq.error; + +-#ifdef DBG + dev_dbg(&card->dev, "card r/w status %d\n", msb->read_only ? 0 : 1); +-#endif + + msb->page_size = 512; + rc = mspro_block_read_attributes(card); + if (rc) + return rc; + +-#ifdef DBG + dev_dbg(&card->dev, "attributes loaded\n"); +-#endif + return 0; + + } +@@ -1215,16 +1275,14 @@ static int mspro_block_init_disk(struct memstick_dev *card) + goto out_release_id; + } + +- spin_lock_init(&msb->q_lock); +- init_waitqueue_head(&msb->q_wait); +- +- msb->queue = blk_init_queue(mspro_block_request, &msb->q_lock); ++ msb->queue = blk_init_queue(mspro_block_submit_req, &msb->q_lock); + if (!msb->queue) { + rc = -ENOMEM; + goto out_put_disk; + } + + msb->queue->queuedata = card; ++ blk_queue_prep_rq(msb->queue, mspro_block_prepare_req); + + blk_queue_bounce_limit(msb->queue, limit); + blk_queue_max_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES); +@@ -1249,17 +1307,9 @@ static int mspro_block_init_disk(struct memstick_dev *card) + capacity *= be16_to_cpu(sys_info->block_size); + capacity *= msb->page_size >> 9; + set_capacity(msb->disk, capacity); +-#ifdef DBG + dev_dbg(&card->dev, "capacity set %ld\n", capacity); +-#endif +- msb->q_thread = kthread_run(mspro_block_queue_thread, card, +- DRIVER_NAME"d"); +- if (IS_ERR(msb->q_thread)) +- goto out_put_disk; + +- mutex_unlock(&host->lock); + add_disk(msb->disk); +- mutex_lock(&host->lock); + msb->active = 1; + return 0; + +@@ -1307,6 +1357,7 @@ static int mspro_block_probe(struct memstick_dev *card) + return -ENOMEM; + memstick_set_drvdata(card, msb); + msb->card = card; ++ spin_lock_init(&msb->q_lock); + + rc = mspro_block_init_card(card); + +@@ -1320,6 +1371,8 @@ static int mspro_block_probe(struct memstick_dev *card) + rc = mspro_block_init_disk(card); + if (!rc) { + card->check = mspro_block_check_card; ++ card->stop = mspro_block_stop; ++ card->start = mspro_block_start; + return 0; + } + +@@ -1334,28 +1387,17 @@ out_free: + static void mspro_block_remove(struct memstick_dev *card) + { + struct mspro_block_data *msb = memstick_get_drvdata(card); +- struct task_struct *q_thread = NULL; + unsigned long flags; + + del_gendisk(msb->disk); + dev_dbg(&card->dev, "mspro block remove\n"); + spin_lock_irqsave(&msb->q_lock, flags); +- q_thread = msb->q_thread; +- msb->q_thread = NULL; +- msb->active = 0; ++ msb->eject = 1; ++ blk_start_queue(msb->queue); + spin_unlock_irqrestore(&msb->q_lock, flags); + +- if (q_thread) { +- mutex_unlock(&card->host->lock); +- kthread_stop(q_thread); +- mutex_lock(&card->host->lock); +- } +- +-#ifdef DBG +- dev_dbg(&card->dev, "queue thread stopped\n"); +-#endif +- + blk_cleanup_queue(msb->queue); ++ msb->queue = NULL; + + sysfs_remove_group(&card->dev.kobj, &msb->attr_group); + +@@ -1372,19 +1414,13 @@ static void mspro_block_remove(struct memstick_dev *card) + static int mspro_block_suspend(struct memstick_dev *card, pm_message_t state) + { + struct mspro_block_data *msb = memstick_get_drvdata(card); +- struct task_struct *q_thread = NULL; + unsigned long flags; + + spin_lock_irqsave(&msb->q_lock, flags); +- q_thread = msb->q_thread; +- msb->q_thread = NULL; +- msb->active = 0; + blk_stop_queue(msb->queue); ++ msb->active = 0; + spin_unlock_irqrestore(&msb->q_lock, flags); + +- if (q_thread) +- kthread_stop(q_thread); +- + return 0; + } + +@@ -1423,14 +1459,7 @@ static int mspro_block_resume(struct memstick_dev *card) + if (memcmp(s_attr->data, r_attr->data, s_attr->size)) + break; + +- memstick_set_drvdata(card, msb); +- msb->q_thread = kthread_run(mspro_block_queue_thread, +- card, DRIVER_NAME"d"); +- if (IS_ERR(msb->q_thread)) +- msb->q_thread = NULL; +- else +- msb->active = 1; +- ++ msb->active = 1; + break; + } + } +@@ -1509,4 +1538,3 @@ MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Alex Dubov"); + MODULE_DESCRIPTION("Sony MemoryStickPro block device driver"); + MODULE_DEVICE_TABLE(memstick, mspro_block_id_tbl); +-MODULE_VERSION(DRIVER_VERSION); +diff --git a/drivers/mmc/ms/xd_card_blk.c b/drivers/mmc/ms/xd_card_blk.c +new file mode 100755 +index 0000000..a25c71a +--- /dev/null ++++ b/drivers/mmc/ms/xd_card_blk.c +@@ -0,0 +1,2955 @@ ++/* ++ * xD picture card block device support ++ * ++ * Copyright (C) 2008 JMicron Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include "linux/xd_card.h" ++#include ++#include ++#include ++ ++/* ++static int kill_cnt = 50000; ++ ++static int xx_ratelimit(void) ++{ ++ if (kill_cnt > 0) { ++ kill_cnt--; ++ return 1; ++ } else if (!kill_cnt) { ++ kill_cnt--; ++ printk(KERN_EMERG "printk stopped\n"); ++ } ++ return 0; ++} ++ ++#undef dev_dbg ++ ++#define dev_dbg(dev, format, arg...) \ ++ do { if (xx_ratelimit()) dev_printk(KERN_EMERG , dev , format , ## arg); } while (0) ++*/ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) ++static inline int __blk_end_request(struct request *rq, int error, ++ unsigned int nr_bytes) ++{ ++ int chunk; ++ ++ if (!error) ++ chunk = end_that_request_chunk(rq, 1, nr_bytes); ++ else ++ chunk = end_that_request_first(rq, error, nr_bytes); ++ ++ if (!chunk) { ++ add_disk_randomness(rq->rq_disk); ++ blkdev_dequeue_request(rq); ++ end_that_request_last(rq, error < 0 ? error : 1); ++ } ++ ++ return chunk; ++} ++ ++unsigned int xd_blk_rq_cur_bytes(struct request *rq) ++{ ++ if (blk_fs_request(rq)) ++ return rq->current_nr_sectors << 9; ++ ++ if (rq->bio) ++ return rq->bio->bi_size; ++ ++ return rq->data_len; ++} ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++static inline void sg_set_page(struct scatterlist *sg, struct page *page, ++ unsigned int len, unsigned int offset) ++{ ++ sg->page = page; ++ sg->offset = offset; ++ sg->length = len; ++} ++ ++static inline struct page *sg_page(struct scatterlist *sg) ++{ ++ return sg->page; ++} ++ ++static unsigned int rq_byte_size(struct request *rq) ++{ ++ if (blk_fs_request(rq)) ++ return rq->hard_nr_sectors << 9; ++ ++ return rq->data_len; ++} ++ ++static inline void __end_request(struct request *rq, int uptodate, ++ unsigned int nr_bytes, int dequeue) ++{ ++ if (!end_that_request_chunk(rq, uptodate, nr_bytes)) { ++ if (dequeue) ++ blkdev_dequeue_request(rq); ++ add_disk_randomness(rq->rq_disk); ++ end_that_request_last(rq, uptodate); ++ } ++} ++ ++void end_queued_request(struct request *rq, int uptodate) ++{ ++ __end_request(rq, uptodate, rq_byte_size(rq), 1); ++} ++#endif ++ ++static int h_xd_card_read(struct xd_card_media *card, ++ struct xd_card_request **req); ++static int h_xd_card_read_tmp(struct xd_card_media *card, ++ struct xd_card_request **req); ++static int h_xd_card_read_copy(struct xd_card_media *card, ++ struct xd_card_request **req); ++static int h_xd_card_write(struct xd_card_media *card, ++ struct xd_card_request **req); ++static int h_xd_card_write_tmp(struct xd_card_media *card, ++ struct xd_card_request **req); ++static int h_xd_card_erase(struct xd_card_media *card, ++ struct xd_card_request **req); ++static int h_xd_card_req_init(struct xd_card_media *card, ++ struct xd_card_request **req); ++static void xd_card_free_media(struct xd_card_media *card); ++static int xd_card_stop_queue(struct xd_card_media *card); ++static int xd_card_trans_req(struct xd_card_media *card, ++ struct xd_card_request *req); ++ ++#define DRIVER_NAME "xd_card" ++ ++static int major; ++module_param(major, int, 0644); ++ ++static unsigned int cmd_retries = 3; ++module_param(cmd_retries, uint, 0644); ++ ++static struct workqueue_struct *workqueue; ++static DEFINE_IDR(xd_card_disk_idr); ++static DEFINE_MUTEX(xd_card_disk_lock); ++ ++static const unsigned char xd_card_cis_header[] = { ++ 0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20 ++}; ++ ++/*** Helper functions ***/ ++ ++static void xd_card_addr_to_extra(struct xd_card_extra *extra, ++ unsigned int addr) ++{ ++ addr &= 0x3ff; ++ extra->addr1 = 0x10 | (addr >> 7) | ((addr << 9) & 0xfe00); ++ extra->addr1 |= (hweight16(extra->addr1) & 1) << 8; ++ extra->addr2 = extra->addr1; ++} ++ ++static unsigned int xd_card_extra_to_addr(struct xd_card_extra *extra) ++{ ++ unsigned int addr1, addr2; ++ ++ addr1 = ((extra->addr1 & 7) << 7) | ((extra->addr1 & 0xfe00) >> 9); ++ addr2 = ((extra->addr2 & 7) << 7) | ((extra->addr2 & 0xfe00) >> 9); ++ ++ if (extra->addr1 == 0xffff) ++ addr1 = FLASH_BD_INVALID; ++ else if ((((~hweight16(addr1)) ^ (extra->addr1 >> 8)) & 1) ++ || !(extra->addr1 & 0x10)) ++ addr1 = FLASH_BD_INVALID; ++ ++ ++ if (extra->addr2 == 0xffff) ++ addr2 = FLASH_BD_INVALID; ++ else if ((((~hweight16(addr2)) ^ (extra->addr2 >> 8)) & 1) ++ || !(extra->addr2 & 0x10)) ++ addr2 = FLASH_BD_INVALID; ++ ++ if (addr1 == FLASH_BD_INVALID) ++ addr1 = addr2; ++ ++ return addr1; ++} ++ ++/*** Block device ***/ ++ ++static int xd_card_bd_open(struct inode *inode, struct file *filp) ++{ ++ struct gendisk *disk = inode->i_bdev->bd_disk; ++ struct xd_card_media *card; ++ int rc = -ENXIO; ++ ++ mutex_lock(&xd_card_disk_lock); ++ card = disk->private_data; ++ ++ if (card && card->host) { ++ card->usage_count++; ++ if ((filp->f_mode & FMODE_WRITE) && card->read_only) ++ rc = -EROFS; ++ else ++ rc = 0; ++ } ++ ++ mutex_unlock(&xd_card_disk_lock); ++ ++ return rc; ++} ++ ++static int xd_card_disk_release(struct gendisk *disk) ++{ ++ struct xd_card_media *card; ++ int disk_id = disk->first_minor >> XD_CARD_PART_SHIFT; ++ ++ mutex_lock(&xd_card_disk_lock); ++ card = disk->private_data; ++ ++ if (card) { ++ if (card->usage_count) ++ card->usage_count--; ++ ++ if (!card->usage_count) { ++ xd_card_free_media(card); ++ disk->private_data = NULL; ++ idr_remove(&xd_card_disk_idr, disk_id); ++ put_disk(disk); ++ } ++ } ++ ++ mutex_unlock(&xd_card_disk_lock); ++ ++ return 0; ++} ++ ++static int xd_card_bd_release(struct inode *inode, struct file *filp) ++{ ++ struct gendisk *disk = inode->i_bdev->bd_disk; ++ return xd_card_disk_release(disk); ++} ++ ++static int xd_card_bd_getgeo(struct block_device *bdev, ++ struct hd_geometry *geo) ++{ ++ struct xd_card_media *card; ++ ++ mutex_lock(&xd_card_disk_lock); ++ card = bdev->bd_disk->private_data; ++ if (card) { ++ geo->heads = card->heads; ++ geo->sectors = card->sectors_per_head; ++ geo->cylinders = card->cylinders; ++ mutex_unlock(&xd_card_disk_lock); ++ return 0; ++ } ++ mutex_unlock(&xd_card_disk_lock); ++ return -ENODEV; ++} ++ ++static struct block_device_operations xd_card_bdops = { ++ .open = xd_card_bd_open, ++ .release = xd_card_bd_release, ++ .getgeo = xd_card_bd_getgeo, ++ .owner = THIS_MODULE ++}; ++ ++/*** Information ***/ ++ ++static ssize_t xd_card_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct xd_card_host *host = dev_get_drvdata(dev); ++ ssize_t rc = 0; ++ ++ mutex_lock(&host->lock); ++ if (!host->card) ++ goto out; ++ ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "ID 1:\n"); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\tmaker code: %02x\n", ++ host->card->id1.maker_code); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\tdevice code: %02x\n", ++ host->card->id1.device_code); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\toption code 1: %02x\n", ++ host->card->id1.option_code1); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\toption code 2: %02x\n", ++ host->card->id1.option_code2); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\nID 2:\n"); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\tcharacteristics code: " ++ "%02x\n", host->card->id2.characteristics_code); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\tvendor code 1: %02x\n", ++ host->card->id2.vendor_code1); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\tsize code: %02x\n", ++ host->card->id2.size_code); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\tvendor code 2: %02x\n", ++ host->card->id2.vendor_code2); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\tvendor code 3: %02x\n", ++ host->card->id2.vendor_code3); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\nID 3:\n"); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\tvendor code 1: %02x\n", ++ host->card->id3.vendor_code1); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\tvendor code 2: %02x\n", ++ host->card->id3.vendor_code2); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\tid code: %02x\n", ++ host->card->id3.id_code); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "\tvendor code 3: %02x\n", ++ host->card->id3.vendor_code3); ++out: ++ mutex_unlock(&host->lock); ++ return rc; ++} ++ ++ ++static ssize_t xd_card_cis_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct xd_card_host *host = dev_get_drvdata(dev); ++ struct xd_card_media *card; ++ ssize_t rc = 0; ++ size_t cnt; ++ ++ mutex_lock(&host->lock); ++ if (!host->card) ++ goto out; ++ card = host->card; ++ ++ for (cnt = 0; cnt < sizeof(card->cis); ++cnt) { ++ if (cnt && !(cnt & 0xf)) { ++ if (PAGE_SIZE - rc) ++ buf[rc++] = '\n'; ++ } ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "%02x ", ++ card->cis[cnt]); ++ } ++ ++out: ++ mutex_unlock(&host->lock); ++ return rc; ++} ++ ++static ssize_t xd_card_idi_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct xd_card_host *host = dev_get_drvdata(dev); ++ struct xd_card_media *card; ++ ssize_t rc = 0; ++ size_t cnt; ++ ++ mutex_lock(&host->lock); ++ if (!host->card) ++ goto out; ++ card = host->card; ++ ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "vendor code 1: "); ++ for (cnt = 0; cnt < sizeof(card->idi.vendor_code1); ++cnt) { ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "%02x", ++ card->idi.vendor_code1[cnt]); ++ } ++ if (PAGE_SIZE - rc) ++ buf[rc++] = '\n'; ++ ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "serial number: "); ++ for (cnt = 0; cnt < sizeof(card->idi.serial_number); ++cnt) { ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "%02x", ++ card->idi.serial_number[cnt]); ++ } ++ if (PAGE_SIZE - rc) ++ buf[rc++] = '\n'; ++ ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "model number: "); ++ for (cnt = 0; cnt < sizeof(card->idi.model_number); ++cnt) { ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "%02x", ++ card->idi.model_number[cnt]); ++ } ++ if (PAGE_SIZE - rc) ++ buf[rc++] = '\n'; ++ ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "vendor code 2: "); ++ for (cnt = 0; cnt < sizeof(card->idi.vendor_code2); ++cnt) { ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "%02x", ++ card->idi.vendor_code1[cnt]); ++ } ++ if (PAGE_SIZE - rc) ++ buf[rc++] = '\n'; ++ ++out: ++ mutex_unlock(&host->lock); ++ return rc; ++} ++ ++static ssize_t xd_card_format_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct xd_card_host *host = dev_get_drvdata(dev); ++ ssize_t rc = 0; ++ ++ mutex_lock(&host->lock); ++ if (!host->card) ++ goto out; ++ ++ if (host->card->format) ++ rc = sprintf(buf, "Block %x of %x, progress %d%%\n", ++ host->card->trans_cnt, host->card->trans_len, ++ (host->card->trans_cnt * 100) ++ / host->card->trans_len); ++ else { ++ rc = scnprintf(buf, PAGE_SIZE, "Not running.\n\n"); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, ++ "Do \"echo format > xd_card_format\" " ++ "to start formatting.\n"); ++ rc += scnprintf(buf + rc, PAGE_SIZE - rc, "But first, think " ++ "about it, really good.\n"); ++ } ++ ++out: ++ mutex_unlock(&host->lock); ++ return rc; ++} ++ ++static int xd_card_format_thread(void *data); ++ ++static ssize_t xd_card_format_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct xd_card_host *host = dev_get_drvdata(dev); ++ unsigned long flags; ++ ++ mutex_lock(&host->lock); ++ if (!host->card) ++ goto out; ++ ++ if (count < 6 || strncmp(buf, "format", 6)) ++ goto out; ++ ++ while (!xd_card_stop_queue(host->card)) ++ wait_for_completion(&host->card->req_complete); ++ ++ spin_lock_irqsave(&host->card->q_lock, flags); ++ if (host->card->format || host->card->eject) { ++ spin_unlock_irqrestore(&host->card->q_lock, flags); ++ goto out; ++ } ++ ++ host->card->format = 1; ++ spin_unlock_irqrestore(&host->card->q_lock, flags); ++ ++ host->card->f_thread = kthread_create(xd_card_format_thread, host->card, ++ DRIVER_NAME"_fmtd"); ++ if (IS_ERR(host->card->f_thread)) { ++ host->card->f_thread = NULL; ++ goto out; ++ } ++ ++ wake_up_process(host->card->f_thread); ++out: ++ mutex_unlock(&host->lock); ++ return count; ++} ++ ++static DEVICE_ATTR(xd_card_id, S_IRUGO, xd_card_id_show, NULL); ++static DEVICE_ATTR(xd_card_cis, S_IRUGO, xd_card_cis_show, NULL); ++static DEVICE_ATTR(xd_card_idi, S_IRUGO, xd_card_idi_show, NULL); ++static DEVICE_ATTR(xd_card_format, S_IRUGO | S_IWUSR, xd_card_format_show, ++ xd_card_format_store); ++ ++static ssize_t xd_card_block_map_read(struct kobject *kobj, ++ struct bin_attribute *attr, ++ char *buf, loff_t offset, ++ size_t count) ++{ ++ struct device *dev = container_of(kobj, struct device, kobj); ++ struct xd_card_host *host = dev_get_drvdata(dev); ++ ssize_t rc = 0; ++ ++ mutex_lock(&host->lock); ++ if (host->card) ++ rc = flash_bd_read_map(host->card->fbd, buf, offset, count); ++ mutex_unlock(&host->lock); ++ return rc; ++} ++ ++/*** Protocol handlers ***/ ++ ++/** ++ * xd_card_next_req - called by host driver to obtain next request to process ++ * @host: host to use ++ * @req: pointer to stick the request to ++ * ++ * Host calls this function from idle state (*req == NULL) or after finishing ++ * previous request (*req should point to it). If previous request was ++ * unsuccessful, it is retried for predetermined number of times. Return value ++ * of 0 means that new request was assigned to the host. ++ */ ++int xd_card_next_req(struct xd_card_host *host, struct xd_card_request **req) ++{ ++ int rc = -ENXIO; ++ ++ if ((*req) && (*req)->error && host->retries) { ++ (*req)->error = rc; ++ host->retries--; ++ return 0; ++ } ++ ++ if (host->card && host->card->next_request[0]) ++ rc = host->card->next_request[0](host->card, req); ++ ++ if (!rc) ++ host->retries = cmd_retries > 1 ? cmd_retries - 1 : 1; ++ else ++ *req = NULL; ++ ++ return rc; ++} ++EXPORT_SYMBOL(xd_card_next_req); ++ ++/** ++ * xd_card_new_req - notify the host that some requests are pending ++ * @host: host to use ++ */ ++void xd_card_new_req(struct xd_card_host *host) ++{ ++ if (host->card) { ++ host->card->next_request[1] = host->card->next_request[0]; ++ host->card->next_request[0] = h_xd_card_req_init; ++ host->retries = cmd_retries; ++ INIT_COMPLETION(host->card->req_complete); ++ host->request(host); ++ } ++} ++EXPORT_SYMBOL(xd_card_new_req); ++ ++/** ++ * xd_card_set_extra - deliver extra data value to host ++ * host: host in question ++ * e_data: pointer to extra data ++ * e_size: number of extra data bytes ++ */ ++void xd_card_set_extra(struct xd_card_host *host, unsigned char *e_data, ++ unsigned int e_size) ++{ ++ if (e_size <= (sizeof(host->extra) - host->extra_pos)) { ++ memcpy(((unsigned char *)&host->extra) + host->extra_pos, ++ e_data, e_size); ++ host->extra_pos += e_size; ++ host->extra_pos %= sizeof(host->extra); ++ } ++} ++EXPORT_SYMBOL(xd_card_set_extra); ++ ++ ++/** ++ * xd_card_get_extra - get extra data value from host ++ * host: host in question ++ * e_data: pointer to extra data ++ * e_size: number of extra data bytes ++ */ ++void xd_card_get_extra(struct xd_card_host *host, unsigned char *e_data, ++ unsigned int e_size) ++{ ++ if (e_size <= (sizeof(host->extra) - host->extra_pos)) { ++ memcpy(e_data, ++ ((unsigned char *)&host->extra) + host->extra_pos, ++ e_size); ++ host->extra_pos += e_size; ++ host->extra_pos %= sizeof(host->extra); ++ } ++} ++EXPORT_SYMBOL(xd_card_get_extra); ++ ++/* ++ * Functions prefixed with "h_" are protocol callbacks. They can be called from ++ * interrupt context. Return value of 0 means that request processing is still ++ * ongoing, while special error value of -EAGAIN means that current request is ++ * finished (and request processor should come back some time later). ++ */ ++ ++static int xd_card_issue_req(struct xd_card_media *card, int chunk) ++{ ++ unsigned long long offset; ++ unsigned int count = 0; ++ int rc; ++ ++try_again: ++ while (chunk) { ++ card->seg_pos = 0; ++ card->seg_off = 0; ++ card->seg_count = blk_rq_map_sg(card->block_req->q, ++ card->block_req, ++ card->req_sg); ++ ++ if (!card->seg_count) { ++ rc = -ENOMEM; ++ goto req_failed; ++ } ++ ++ offset = card->block_req->sector << 9; ++ count = card->block_req->nr_sectors << 9; ++ ++ if (rq_data_dir(card->block_req) == READ) { ++ dev_dbg(card->host->dev, "Read segs: %d, offset: %llx, " ++ "size: %x\n", card->seg_count, offset, count); ++ ++ rc = flash_bd_start_reading(card->fbd, offset, count); ++ } else { ++ dev_dbg(card->host->dev, "Write segs: %d, offset: %llx," ++ " size: %x\n", card->seg_count, offset, count); ++ ++ rc = flash_bd_start_writing(card->fbd, offset, count); ++ } ++ ++ if (rc) ++ goto req_failed; ++ ++ rc = flash_bd_next_req(card->fbd, &card->flash_req, 0, 0); ++ ++ if (rc) { ++ flash_bd_end(card->fbd); ++ goto req_failed; ++ } ++ ++ rc = xd_card_trans_req(card, &card->req); ++ ++ if (!rc) { ++ xd_card_new_req(card->host); ++ return 0; ++ } ++ ++ count = flash_bd_end(card->fbd); ++req_failed: ++ if (rc == -EAGAIN) ++ rc = 0; ++ ++ if (rc && !count) ++ count = xd_blk_rq_cur_bytes(card->block_req); ++ ++ chunk = __blk_end_request(card->block_req, rc, count); ++ } ++ ++ dev_dbg(card->host->dev, "elv_next\n"); ++ card->block_req = elv_next_request(card->queue); ++ if (!card->block_req) { ++ dev_dbg(card->host->dev, "issue end\n"); ++ return -EAGAIN; ++ } ++ ++ dev_dbg(card->host->dev, "trying again\n"); ++ chunk = 1; ++ goto try_again; ++} ++ ++static int h_xd_card_default_bad(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ return -ENXIO; ++} ++ ++static int xd_card_complete_req(struct xd_card_media *card, int error) ++{ ++ int chunk; ++ unsigned int t_len; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&card->q_lock, flags); ++ dev_dbg(card->host->dev, "complete %d, %d\n", card->has_request ? 1 : 0, ++ error); ++ if (card->has_request) { ++ /* Nothing to do - not really an error */ ++ if (error == -EAGAIN) ++ error = 0; ++ t_len = flash_bd_end(card->fbd); ++ ++ dev_dbg(card->host->dev, "transferred %x (%d)\n", t_len, error); ++ if (error == -EAGAIN) ++ error = 0; ++ ++ if (error && !t_len) ++ t_len = xd_blk_rq_cur_bytes(card->block_req); ++ ++ chunk = __blk_end_request(card->block_req, error, t_len); ++ ++ error = xd_card_issue_req(card, chunk); ++ ++ if (!error) ++ goto out; ++ else ++ card->has_request = 0; ++ } else { ++ if (!error) ++ error = -EAGAIN; ++ } ++ ++ card->next_request[0] = h_xd_card_default_bad; ++ complete_all(&card->req_complete); ++out: ++ spin_unlock_irqrestore(&card->q_lock, flags); ++ return error; ++} ++ ++static int xd_card_stop_queue(struct xd_card_media *card) ++{ ++ int rc = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&card->q_lock, flags); ++ if (!card->has_request) { ++ blk_stop_queue(card->queue); ++ rc = 1; ++ } ++ spin_unlock_irqrestore(&card->q_lock, flags); ++ return rc; ++} ++ ++static unsigned long long xd_card_req_address(struct xd_card_media *card, ++ unsigned int byte_off) ++{ ++ unsigned long long rv = card->flash_req.zone; ++ ++ rv <<= card->block_addr_bits; ++ rv |= card->flash_req.phy_block; ++ rv <<= card->page_addr_bits; ++ rv |= card->flash_req.page_off * (card->page_size / card->hw_page_size); ++ rv <<= 8; ++ ++ if (byte_off) ++ rv += (byte_off / card->hw_page_size) << 8; ++ ++ return rv; ++} ++ ++static int h_xd_card_req_init(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ *req = &card->req; ++ card->next_request[0] = card->next_request[1]; ++ return 0; ++} ++ ++static int h_xd_card_default(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ return xd_card_complete_req(card, (*req)->error); ++} ++ ++static int h_xd_card_read_extra(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ if ((*req)->error) ++ return xd_card_complete_req(card, (*req)->error); ++ ++ if (!card->host->extra_pos) ++ return xd_card_complete_req(card, -EAGAIN); ++ else { ++ unsigned int extra_pos = sizeof(struct xd_card_extra) ++ / (card->page_size ++ / card->hw_page_size); ++ extra_pos = card->host->extra_pos / extra_pos; ++ extra_pos *= card->hw_page_size; ++ (*req)->count = 0; ++ (*req)->error = 0; ++ (*req)->addr = xd_card_req_address(card, extra_pos); ++ return 0; ++ } ++} ++ ++static void xd_card_advance(struct xd_card_media *card, int count) ++{ ++ unsigned int s_len; ++ ++ if (count >= 0) { ++ while (count) { ++ s_len = card->req_sg[card->seg_pos].length ++ - card->seg_off; ++ s_len = min(count, (int)s_len); ++ card->seg_off += s_len; ++ count -= s_len; ++ if (card->seg_off ++ == card->req_sg[card->seg_pos].length) { ++ if ((card->seg_count - card->seg_pos) > 1) { ++ card->seg_off = 0; ++ card->seg_pos++; ++ } else ++ break; ++ } ++ } ++ } else { ++ count = -count; ++ ++ while (count >= card->seg_off) { ++ count -= card->seg_off; ++ if (card->seg_pos) ++ card->seg_pos--; ++ else { ++ card->seg_off = 0; ++ return; ++ } ++ card->seg_off = card->req_sg[card->seg_pos].length; ++ } ++ ++ card->seg_off -= count; ++ ++ if ((card->seg_off == card->req_sg[card->seg_pos].length) ++ && ((card->seg_count - card->seg_pos) > 1)) { ++ card->seg_off = 0; ++ card->seg_pos++; ++ } ++ } ++} ++ ++enum tmp_action { ++ FILL_TMP = 0, ++ FLUSH_TMP, ++ ONE_FILL ++}; ++ ++static void xd_card_copy_tmp(struct xd_card_media *card, unsigned int off, ++ unsigned int count, enum tmp_action act) ++{ ++ struct page *pg; ++ unsigned char *buf; ++ unsigned int p_off, p_cnt; ++ unsigned long flags; ++ ++ while (count) { ++ if (card->seg_off == card->req_sg[card->seg_pos].length) { ++ card->seg_off = 0; ++ card->seg_pos++; ++ if (card->seg_pos == card->seg_count) ++ break; ++ } ++ ++ p_off = card->req_sg[card->seg_pos].offset + card->seg_off; ++ ++ pg = nth_page(sg_page(&card->req_sg[card->seg_pos]), ++ p_off >> PAGE_SHIFT); ++ p_off = offset_in_page(p_off); ++ p_cnt = PAGE_SIZE - p_off; ++ p_cnt = min(p_cnt, count); ++ ++ local_irq_save(flags); ++ buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off; ++ ++ switch (act) { ++ case FILL_TMP: ++ memcpy(card->t_buf + off, buf, p_cnt); ++ break; ++ case FLUSH_TMP: ++ memcpy(buf, card->t_buf + off, p_cnt); ++ break; ++ case ONE_FILL: ++ memset(buf, 0xff, p_cnt); ++ break; ++ }; ++ ++ kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); ++ local_irq_restore(flags); ++ ++ count -= p_cnt; ++ off += p_cnt; ++ card->seg_off += p_cnt; ++ } ++} ++ ++static int xd_card_check_ecc(struct xd_card_media *card) ++{ ++ unsigned int ref_ecc, act_ecc; ++ unsigned int e_pos = 0, c_pos, off = 0, e_state, p_off, p_cnt, s_len; ++ struct scatterlist *c_sg; ++ struct page *pg; ++ unsigned char *buf; ++ unsigned char c_mask; ++ int do_other = 0; ++ unsigned long flags; ++ ++ ref_ecc = card->host->extra.ecc_lo[0] ++ | (card->host->extra.ecc_lo[1] << 8) ++ | (card->host->extra.ecc_lo[2] << 16); ++ c_sg = &card->req_sg[card->seg_pos]; ++ off = card->seg_off; ++ s_len = c_sg->length - off; ++ ++ while (do_other < 2) { ++ e_pos = 0; ++ e_state = 0; ++ ++ while (s_len) { ++ pg = nth_page(sg_page(c_sg), ++ (c_sg->offset + off + e_pos) ++ >> PAGE_SHIFT); ++ p_off = offset_in_page(c_sg->offset + off + e_pos); ++ p_cnt = PAGE_SIZE - p_off; ++ p_cnt = min(p_cnt, s_len); ++ ++ local_irq_save(flags); ++ buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off; ++ ++ if (xd_card_ecc_step(&e_state, &e_pos, buf, p_cnt)) { ++ kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); ++ local_irq_restore(flags); ++ s_len = c_sg->length - off - e_pos; ++ break; ++ } ++ kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); ++ local_irq_restore(flags); ++ s_len = c_sg->length - off - e_pos; ++ } ++ ++ act_ecc = xd_card_ecc_value(e_state); ++ switch (xd_card_fix_ecc(&c_pos, &c_mask, act_ecc, ref_ecc)) { ++ case -1: ++ return -EILSEQ; ++ case 0: ++ break; ++ case 1: ++ pg = nth_page(sg_page(c_sg), ++ (c_sg->offset + off + c_pos) ++ >> PAGE_SHIFT); ++ p_off = offset_in_page(c_sg->offset + off + c_pos); ++ local_irq_save(flags); ++ buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off; ++ *buf ^= c_mask; ++ kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); ++ local_irq_restore(flags); ++ break; ++ } ++ ++ off += e_pos; ++ ++ do_other++; ++ ref_ecc = card->host->extra.ecc_hi[0] ++ | (card->host->extra.ecc_hi[1] << 8) ++ | (card->host->extra.ecc_hi[2] << 16); ++ } ++ return 0; ++} ++ ++static void xd_card_update_extra(struct xd_card_media *card) ++{ ++ unsigned int act_ecc; ++ unsigned int e_pos = 0, off = 0, e_state, p_off, p_cnt, s_len; ++ struct scatterlist *c_sg; ++ struct page *pg; ++ unsigned char *buf; ++ int do_other = 0; ++ unsigned long flags; ++ ++ c_sg = &card->req_sg[card->seg_pos]; ++ off = card->seg_off; ++ s_len = c_sg->length - off; ++ ++ if (s_len < card->page_size) ++ return; ++ ++ xd_card_addr_to_extra(&card->host->extra, card->flash_req.log_block); ++ ++ if (card->auto_ecc || (card->req.flags & XD_CARD_REQ_NO_ECC)) ++ return; ++ ++ while (do_other < 2) { ++ e_pos = 0; ++ e_state = 0; ++ ++ while (s_len) { ++ pg = nth_page(sg_page(c_sg), ++ (c_sg->offset + off + e_pos) ++ >> PAGE_SHIFT); ++ p_off = offset_in_page(c_sg->offset + off + e_pos); ++ p_cnt = PAGE_SIZE - p_off; ++ p_cnt = min(p_cnt, s_len); ++ ++ local_irq_save(flags); ++ buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off; ++ ++ if (xd_card_ecc_step(&e_state, &e_pos, buf, p_cnt)) { ++ kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); ++ local_irq_restore(flags); ++ s_len = c_sg->length - off - e_pos; ++ break; ++ } ++ kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); ++ local_irq_restore(flags); ++ s_len = c_sg->length - off - e_pos; ++ } ++ ++ act_ecc = xd_card_ecc_value(e_state); ++ ++ if (!do_other) { ++ card->host->extra.ecc_lo[0] = act_ecc & 0xff; ++ card->host->extra.ecc_lo[1] = (act_ecc >> 8) & 0xff; ++ card->host->extra.ecc_lo[2] = (act_ecc >> 16) & 0xff; ++ } else { ++ card->host->extra.ecc_hi[0] = act_ecc & 0xff; ++ card->host->extra.ecc_hi[1] = (act_ecc >> 8) & 0xff; ++ card->host->extra.ecc_hi[2] = (act_ecc >> 16) & 0xff; ++ } ++ ++ off += e_pos; ++ ++ do_other++; ++ } ++} ++ ++static void xd_card_update_extra_tmp(struct xd_card_media *card) ++{ ++ unsigned int act_ecc; ++ unsigned int e_pos = 0, e_state = 0, len = card->page_size; ++ unsigned char *buf = card->t_buf + card->trans_cnt; ++ ++ if ((card->trans_len - card->trans_cnt) < card->page_size) ++ return; ++ ++ if (card->auto_ecc || (card->req.flags & XD_CARD_REQ_NO_ECC)) ++ return; ++ ++ xd_card_ecc_step(&e_state, &e_pos, buf, len); ++ act_ecc = xd_card_ecc_value(e_state); ++ card->host->extra.ecc_lo[0] = act_ecc & 0xff; ++ card->host->extra.ecc_lo[1] = (act_ecc >> 8) & 0xff; ++ card->host->extra.ecc_lo[2] = (act_ecc >> 16) & 0xff; ++ ++ e_state = 0; ++ buf += e_pos; ++ len -= e_pos; ++ e_pos = 0; ++ xd_card_ecc_step(&e_state, &e_pos, buf, len); ++ act_ecc = xd_card_ecc_value(e_state); ++ card->host->extra.ecc_hi[0] = act_ecc & 0xff; ++ card->host->extra.ecc_hi[1] = (act_ecc >> 8) & 0xff; ++ card->host->extra.ecc_hi[2] = (act_ecc >> 16) & 0xff; ++} ++ ++static int xd_card_check_ecc_tmp(struct xd_card_media *card) ++{ ++ unsigned int ref_ecc, act_ecc; ++ unsigned int e_pos = 0, e_state = 0, c_pos, len = card->page_size; ++ unsigned char c_mask; ++ unsigned char *buf = card->t_buf + card->trans_cnt - card->page_size; ++ int rc; ++ ++ if (card->trans_cnt < card->page_size) ++ return -EILSEQ; ++ ++ ref_ecc = card->host->extra.ecc_lo[0] ++ | (card->host->extra.ecc_lo[1] << 8) ++ | (card->host->extra.ecc_lo[2] << 16); ++ ++ xd_card_ecc_step(&e_state, &e_pos, buf, len); ++ ++ act_ecc = xd_card_ecc_value(e_state); ++ rc = xd_card_fix_ecc(&c_pos, &c_mask, act_ecc, ref_ecc); ++ ++ if (rc == -1) ++ return -EILSEQ; ++ else if (rc == 1) ++ buf[c_pos] ^= c_mask; ++ ++ ref_ecc = card->host->extra.ecc_hi[0] ++ | (card->host->extra.ecc_hi[1] << 8) ++ | (card->host->extra.ecc_hi[2] << 16); ++ ++ e_state = 0; ++ buf += e_pos; ++ len -= e_pos; ++ e_pos = 0; ++ xd_card_ecc_step(&e_state, &e_pos, buf, len); ++ ++ act_ecc = xd_card_ecc_value(e_state); ++ rc = xd_card_fix_ecc(&c_pos, &c_mask, act_ecc, ref_ecc); ++ ++ if (rc == -1) ++ return -EILSEQ; ++ else if (rc == 1) ++ buf[c_pos] ^= c_mask; ++ ++ return 0; ++} ++ ++static int xd_card_trans_req(struct xd_card_media *card, ++ struct xd_card_request *req) ++{ ++ unsigned int count = 0; ++ int rc = 0; ++ ++process_next: ++ dev_dbg(card->host->dev, ++ "fbd req %s: (%x) %x -> %x, dst: %x + %x, src: %x:%x\n", ++ flash_bd_cmd_name(card->flash_req.cmd), card->flash_req.zone, ++ card->flash_req.log_block, card->flash_req.phy_block, ++ card->flash_req.page_off, card->flash_req.page_cnt, ++ card->flash_req.src.phy_block, card->flash_req.src.page_off); ++ card->host->extra_pos = 0; ++ ++ switch (card->flash_req.cmd) { ++ case FBD_NONE: ++ return -EAGAIN; ++ case FBD_READ: ++ req->cmd = XD_CARD_CMD_READ1; ++ req->flags = XD_CARD_REQ_DATA; ++ req->addr = xd_card_req_address(card, 0); ++ req->error = 0; ++ req->count = 0; ++ sg_set_page(&req->sg, sg_page(&card->req_sg[card->seg_pos]), ++ card->req_sg[card->seg_pos].length ++ - card->seg_off, ++ card->req_sg[card->seg_pos].offset ++ + card->seg_off); ++ ++ ++ ++ card->trans_cnt = 0; ++ card->trans_len = card->flash_req.page_cnt * card->page_size; ++ ++ if (card->auto_ecc) { ++ req->sg.length = min(card->trans_len, req->sg.length); ++ } else { ++ req->flags |= XD_CARD_REQ_EXTRA; ++ req->sg.length = card->hw_page_size; ++ } ++ ++ dev_dbg(card->host->dev, "trans r %x, %x, %x, %x\n", ++ card->seg_pos, card->seg_off, req->sg.offset, ++ req->sg.length); ++ ++ card->next_request[0] = h_xd_card_read; ++ return 0; ++ case FBD_READ_TMP: ++ req->cmd = XD_CARD_CMD_READ1; ++ req->flags = XD_CARD_REQ_DATA; ++ req->addr = xd_card_req_address(card, 0); ++ req->error = 0; ++ req->count = 0; ++ card->trans_cnt = 0; ++ card->trans_len = card->flash_req.page_cnt * card->page_size; ++ ++ if (card->auto_ecc) ++ sg_set_buf(&req->sg, card->t_buf, card->trans_len); ++ else { ++ req->flags |= XD_CARD_REQ_EXTRA; ++ sg_set_buf(&req->sg, card->t_buf, card->hw_page_size); ++ } ++ ++ dev_dbg(card->host->dev, "trans r_tmp %x, %x\n", ++ req->sg.offset, req->sg.length); ++ ++ card->next_request[0] = h_xd_card_read_tmp; ++ return 0; ++ case FBD_FLUSH_TMP: ++ xd_card_copy_tmp(card, card->flash_req.byte_off, ++ card->flash_req.byte_cnt, FLUSH_TMP); ++ card->trans_cnt -= card->flash_req.byte_cnt; ++ count = card->flash_req.byte_cnt; ++ break; ++ case FBD_SKIP: ++ xd_card_copy_tmp(card, 0, card->flash_req.byte_cnt, ONE_FILL); ++ card->trans_cnt -= card->flash_req.byte_cnt; ++ count = card->flash_req.byte_cnt; ++ break; ++ case FBD_ERASE_TMP: ++ memset(card->t_buf + card->flash_req.byte_off, 0xff, ++ card->flash_req.byte_cnt); ++ count = card->flash_req.byte_cnt; ++ break; ++ case FBD_ERASE: ++ req->cmd = XD_CARD_CMD_ERASE_SET; ++ req->flags = XD_CARD_REQ_DIR | XD_CARD_REQ_STATUS; ++ req->addr = card->flash_req.zone; ++ req->addr <<= card->block_addr_bits; ++ req->addr |= card->flash_req.phy_block; ++ req->addr <<= card->page_addr_bits; ++ req->error = 0; ++ req->count = 0; ++ card->trans_cnt = 0; ++ card->trans_len = 0; ++ ++ card->host->set_param(card->host, XD_CARD_ADDR_SIZE, ++ card->addr_bytes - 1); ++ card->next_request[0] = h_xd_card_erase; ++ return 0; ++ case FBD_COPY: ++ req->cmd = XD_CARD_CMD_READ1; ++ req->flags = XD_CARD_REQ_DATA; ++ req->addr = card->flash_req.zone; ++ req->addr <<= card->block_addr_bits; ++ req->addr |= card->flash_req.src.phy_block; ++ req->addr <<= card->page_addr_bits; ++ req->addr |= card->flash_req.src.page_off ++ * (card->page_size / card->hw_page_size); ++ req->addr <<= 8; ++ ++ req->error = 0; ++ req->count = 0; ++ card->trans_cnt = 0; ++ card->trans_len = card->flash_req.page_cnt * card->page_size; ++ ++ if (card->auto_ecc) ++ sg_set_buf(&req->sg, card->t_buf, card->trans_len); ++ else { ++ req->flags |= XD_CARD_REQ_EXTRA; ++ sg_set_buf(&req->sg, card->t_buf, card->hw_page_size); ++ } ++ ++ card->next_request[0] = h_xd_card_read_copy; ++ return 0; ++ case FBD_WRITE: ++ req->cmd = XD_CARD_CMD_INPUT; ++ req->flags = XD_CARD_REQ_DATA | XD_CARD_REQ_DIR ++ | XD_CARD_REQ_EXTRA | XD_CARD_REQ_STATUS; ++ req->addr = xd_card_req_address(card, 0); ++ req->error = 0; ++ req->count = 0; ++ card->trans_cnt = 0; ++ card->trans_len = card->flash_req.page_cnt * card->page_size; ++ ++ sg_set_page(&req->sg, sg_page(&card->req_sg[card->seg_pos]), ++ card->hw_page_size, ++ card->req_sg[card->seg_pos].offset ++ + card->seg_off); ++ ++ dev_dbg(card->host->dev, "trans w %x, %x\n", card->trans_cnt, ++ card->trans_len); ++ ++ memset(&card->host->extra, 0xff, sizeof(struct xd_card_extra)); ++ xd_card_addr_to_extra(&card->host->extra, ++ card->flash_req.log_block); ++ xd_card_update_extra(card); ++ dev_dbg(card->host->dev, "log addr %08x, %04x\n", ++ card->flash_req.log_block, card->host->extra.addr1); ++ ++ card->next_request[0] = h_xd_card_write; ++ return 0; ++ case FBD_WRITE_TMP: ++ req->cmd = XD_CARD_CMD_INPUT; ++ req->flags = XD_CARD_REQ_DATA | XD_CARD_REQ_DIR ++ | XD_CARD_REQ_EXTRA | XD_CARD_REQ_STATUS; ++ req->addr = xd_card_req_address(card, 0); ++ req->error = 0; ++ req->count = 0; ++ card->trans_cnt = 0; ++ card->trans_len = card->flash_req.page_cnt * card->page_size; ++ ++ sg_set_buf(&req->sg, card->t_buf, card->hw_page_size); ++ ++ memset(&card->host->extra, 0xff, sizeof(struct xd_card_extra)); ++ xd_card_addr_to_extra(&card->host->extra, ++ card->flash_req.log_block); ++ xd_card_update_extra_tmp(card); ++ ++ card->next_request[0] = h_xd_card_write_tmp; ++ return 0; ++ case FBD_FILL_TMP: ++ xd_card_copy_tmp(card, card->flash_req.byte_off, ++ card->flash_req.byte_cnt, FILL_TMP); ++ card->trans_cnt -= card->flash_req.byte_cnt; ++ count = card->flash_req.byte_cnt; ++ break; ++ case FBD_MARK: ++ memset(card->t_buf, 0xff, ++ card->page_size * card->flash_req.page_cnt); ++ req->cmd = XD_CARD_CMD_INPUT; ++ req->flags = XD_CARD_REQ_DATA | XD_CARD_REQ_DIR ++ | XD_CARD_REQ_EXTRA | XD_CARD_REQ_NO_ECC ++ | XD_CARD_REQ_STATUS; ++ req->addr = xd_card_req_address(card, 0); ++ req->error = 0; ++ req->count = 0; ++ card->trans_cnt = 0; ++ card->trans_len = card->flash_req.page_cnt * card->page_size; ++ ++ sg_set_buf(&req->sg, card->t_buf, card->hw_page_size); ++ ++ memset(&card->host->extra, 0xff, sizeof(struct xd_card_extra)); ++ xd_card_addr_to_extra(&card->host->extra, ++ card->flash_req.log_block); ++ xd_card_update_extra_tmp(card); ++ ++ card->next_request[0] = h_xd_card_write_tmp; ++ return 0; ++ case FBD_MARK_BAD: ++ memset(card->t_buf, 0xff, ++ card->page_size * card->flash_req.page_cnt); ++ req->cmd = XD_CARD_CMD_INPUT; ++ req->flags = XD_CARD_REQ_DATA | XD_CARD_REQ_DIR ++ | XD_CARD_REQ_EXTRA | XD_CARD_REQ_NO_ECC ++ | XD_CARD_REQ_STATUS; ++ req->addr = xd_card_req_address(card, 0); ++ req->error = 0; ++ req->count = 0; ++ card->trans_cnt = 0; ++ card->trans_len = card->flash_req.page_cnt * card->page_size; ++ ++ sg_set_buf(&req->sg, card->t_buf, card->hw_page_size); ++ ++ memset(&card->host->extra, 0xff, sizeof(struct xd_card_extra)); ++ card->host->extra.block_status = 0xf0; ++ ++ card->next_request[0] = h_xd_card_write_tmp; ++ return 0; ++ default: ++ BUG(); ++ }; ++ ++ rc = flash_bd_next_req(card->fbd, &card->flash_req, count, rc); ++ if (rc) ++ return rc; ++ ++ goto process_next; ++} ++ ++static int xd_card_try_next_req(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ int rc = (*req)->error; ++ ++ dev_dbg(card->host->dev, "start error %d\n", rc); ++ rc = flash_bd_next_req(card->fbd, &card->flash_req, ++ card->trans_cnt, rc); ++ ++ if (rc) { ++ dev_dbg(card->host->dev, "next req error %d\n", rc); ++ return xd_card_complete_req(card, rc); ++ } ++ ++ rc = xd_card_trans_req(card, *req); ++ ++ if (rc) { ++ dev_dbg(card->host->dev, "trans req error %d\n", rc); ++ return xd_card_complete_req(card, rc); ++ } ++ ++ return 0; ++} ++ ++static int h_xd_card_read(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ unsigned int count; ++ int rc = 0; ++ ++ dev_dbg(card->host->dev, "read %d (%d) of %d at %d:%d\n", ++ (*req)->count, (*req)->error, card->trans_cnt, card->seg_pos, ++ card->seg_off); ++ ++ if ((*req)->count) { ++ if (card->auto_ecc) { ++ xd_card_advance(card, (*req)->count); ++ card->trans_cnt += (*req)->count; ++ ++ count = min(card->req_sg[card->seg_pos].length ++ - card->seg_off, ++ card->trans_len - card->trans_cnt); ++ ++ if (!count) ++ goto out; ++ ++ (*req)->cmd = XD_CARD_CMD_READ1; ++ (*req)->flags = XD_CARD_REQ_DATA; ++ (*req)->addr = xd_card_req_address(card, ++ card->trans_cnt); ++ (*req)->error = 0; ++ (*req)->count = 0; ++ ++ sg_set_page(&(*req)->sg, ++ sg_page(&card->req_sg[card->seg_pos]), ++ count, ++ card->req_sg[card->seg_pos].offset ++ + card->seg_off); ++ return 0; ++ } else { ++ rc = card->hw_page_size; ++ ++ if ((*req)->count != rc) { ++ rc *= card->host->extra_pos ++ / (sizeof(struct xd_card_extra) ++ / (card->page_size ++ / card->hw_page_size)); ++ xd_card_advance(card, -rc); ++ card->trans_cnt -= rc; ++ rc = -EILSEQ; ++ } else { ++ xd_card_advance(card, rc); ++ card->trans_cnt += rc; ++ rc = 0; ++ } ++ ++ if (!rc && !card->host->extra_pos) { ++ xd_card_advance(card, -card->page_size); ++ rc = xd_card_check_ecc(card); ++ if (!rc) ++ xd_card_advance(card, card->page_size); ++ else ++ card->trans_cnt -= card->page_size; ++ } ++ ++ if (rc || ((card->trans_len - card->trans_cnt) ++ < card->hw_page_size)) ++ goto out; ++ ++ (*req)->count = 0; ++ (*req)->error = 0; ++ (*req)->addr = xd_card_req_address(card, ++ card->trans_cnt); ++ sg_set_page(&(*req)->sg, ++ sg_page(&card->req_sg[card->seg_pos]), ++ card->hw_page_size, ++ card->req_sg[card->seg_pos].offset ++ + card->seg_off); ++ return 0; ++ } ++ } ++ ++out: ++ if (!(*req)->error) ++ (*req)->error = rc; ++ ++ return xd_card_try_next_req(card, req); ++} ++ ++static int h_xd_card_read_tmp(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ int rc = 0; ++ ++ dev_dbg(card->host->dev, "read tmp %d of %d\n", ++ (*req)->count, card->trans_cnt); ++ ++ if ((*req)->count) { ++ if (card->auto_ecc) ++ card->trans_cnt = (*req)->count; ++ else { ++ rc = card->hw_page_size; ++ ++ if ((*req)->count != rc) { ++ rc *= card->host->extra_pos ++ / (sizeof(struct xd_card_extra) ++ / (card->page_size ++ / card->hw_page_size)); ++ card->trans_cnt -= rc; ++ rc = -EILSEQ; ++ } else { ++ card->trans_cnt += rc; ++ rc = 0; ++ } ++ ++ if (!rc && !card->host->extra_pos) { ++ rc = xd_card_check_ecc_tmp(card); ++ if (rc) ++ card->trans_cnt -= card->page_size; ++ } ++ ++ if (!rc && ((card->trans_len - card->trans_cnt) ++ >= card->hw_page_size)) { ++ (*req)->count = 0; ++ (*req)->error = 0; ++ (*req)->addr ++ = xd_card_req_address(card, ++ card->trans_cnt); ++ sg_set_buf(&(*req)->sg, ++ card->t_buf + card->trans_cnt, ++ card->hw_page_size); ++ return 0; ++ } ++ } ++ } else ++ rc = -EIO; ++ ++ if (!(*req)->error) ++ (*req)->error = rc; ++ ++ return xd_card_try_next_req(card, req); ++} ++ ++static int h_xd_card_check_stat(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ if (!(*req)->error) { ++ if ((*req)->status & XD_CARD_STTS_FAIL) ++ (*req)->error = -EFAULT; ++ } ++ return xd_card_try_next_req(card, req); ++} ++ ++static int h_xd_card_write_tmp_adv(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ if (!(*req)->error && ((*req)->status & XD_CARD_STTS_FAIL)) ++ (*req)->error = -EFAULT; ++ ++ dev_dbg(card->host->dev, "card_write_tmp_adv %d, %d, %02x\n", ++ (*req)->error, (*req)->count, (*req)->status); ++ if (!(*req)->error) { ++ card->trans_cnt += card->hw_page_size; ++ ++ if ((card->trans_len - card->trans_cnt) >= card->hw_page_size) { ++ if (!card->host->extra_pos) ++ xd_card_update_extra_tmp(card); ++ ++ (*req)->cmd = XD_CARD_CMD_INPUT; ++ (*req)->flags = XD_CARD_REQ_DATA ++ | XD_CARD_REQ_DIR ++ | XD_CARD_REQ_EXTRA ++ | XD_CARD_REQ_STATUS; ++ (*req)->addr = xd_card_req_address(card, ++ card->trans_cnt); ++ (*req)->error = 0; ++ (*req)->count = 0; ++ sg_set_buf(&(*req)->sg, card->t_buf + card->trans_cnt, ++ card->hw_page_size); ++ card->next_request[0] = h_xd_card_write_tmp; ++ return 0; ++ } ++ } ++ ++ return xd_card_try_next_req(card, req); ++} ++ ++static int h_xd_card_write_adv(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ if (!(*req)->error && ((*req)->status & XD_CARD_STTS_FAIL)) ++ (*req)->error = -EFAULT; ++ ++ dev_dbg(card->host->dev, "card_write_adv %d, %d, %02x\n", (*req)->error, ++ (*req)->count, (*req)->status); ++ if (!(*req)->error) { ++ xd_card_advance(card, card->hw_page_size); ++ card->trans_cnt += card->hw_page_size; ++ ++ if ((card->trans_len - card->trans_cnt) >= card->hw_page_size) { ++ if (!card->host->extra_pos) ++ xd_card_update_extra(card); ++ ++ (*req)->cmd = XD_CARD_CMD_INPUT; ++ (*req)->flags = XD_CARD_REQ_DATA ++ | XD_CARD_REQ_DIR ++ | XD_CARD_REQ_EXTRA ++ | XD_CARD_REQ_STATUS; ++ (*req)->addr = xd_card_req_address(card, ++ card->trans_cnt); ++ (*req)->error = 0; ++ (*req)->count = 0; ++ sg_set_page(&(*req)->sg, ++ sg_page(&card->req_sg[card->seg_pos]), ++ card->hw_page_size, ++ card->req_sg[card->seg_pos].offset ++ + card->seg_off); ++ card->next_request[0] = h_xd_card_write; ++ return 0; ++ } ++ } ++ ++ return xd_card_try_next_req(card, req); ++} ++ ++static int h_xd_card_write_stat(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ dev_dbg(card->host->dev, "card_write_stat %d, %d\n", (*req)->error, ++ (*req)->count); ++ if (!(*req)->error) { ++ (*req)->cmd = XD_CARD_CMD_STATUS1; ++ (*req)->flags = XD_CARD_REQ_STATUS; ++ (*req)->error = 0; ++ (*req)->count = 0; ++ card->next_request[0] = card->next_request[1]; ++ return 0; ++ } else ++ return xd_card_try_next_req(card, req); ++} ++ ++static int h_xd_card_write(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ if (!(*req)->error) { ++ if ((*req)->count != card->hw_page_size) ++ (*req)->error = -EIO; ++ } ++ dev_dbg(card->host->dev, "card_write %d, %d\n", (*req)->error, ++ (*req)->count); ++ ++ if ((*req)->error) ++ return xd_card_try_next_req(card, req); ++ ++ if (card->host->caps & XD_CARD_CAP_CMD_SHORTCUT) { ++ return h_xd_card_write_adv(card, req); ++ } else { ++ (*req)->cmd = XD_CARD_CMD_PAGE_PROG; ++ (*req)->flags = XD_CARD_REQ_DIR; ++ (*req)->error = 0; ++ (*req)->count = 0; ++ ++ card->next_request[0] = h_xd_card_write_stat; ++ card->next_request[1] = h_xd_card_write_adv; ++ return 0; ++ } ++} ++ ++static int h_xd_card_write_tmp(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ if (!(*req)->error) { ++ if ((*req)->count != card->hw_page_size) ++ (*req)->error = -EIO; ++ } ++ dev_dbg(card->host->dev, "card_write_tmp %d, %d\n", (*req)->error, ++ (*req)->count); ++ ++ if ((*req)->error) ++ return xd_card_try_next_req(card, req); ++ ++ if (card->host->caps & XD_CARD_CAP_CMD_SHORTCUT) { ++ return h_xd_card_write_tmp_adv(card, req); ++ } else { ++ (*req)->cmd = XD_CARD_CMD_PAGE_PROG; ++ (*req)->flags = XD_CARD_REQ_DIR; ++ (*req)->error = 0; ++ (*req)->count = 0; ++ ++ card->next_request[0] = h_xd_card_write_stat; ++ card->next_request[1] = h_xd_card_write_tmp_adv; ++ return 0; ++ } ++} ++ ++static int h_xd_card_read_copy(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ int rc = 0; ++ ++ dev_dbg(card->host->dev, "read copy %d of %d\n", ++ (*req)->count, card->trans_cnt); ++ ++ if ((*req)->count) { ++ if (card->auto_ecc) ++ card->trans_cnt = (*req)->count; ++ else { ++ rc = card->hw_page_size; ++ ++ if ((*req)->count != rc) { ++ rc *= card->host->extra_pos ++ / (sizeof(struct xd_card_extra) ++ / (card->page_size ++ / card->hw_page_size)); ++ card->trans_cnt -= rc; ++ rc = -EILSEQ; ++ } else { ++ card->trans_cnt += rc; ++ rc = 0; ++ } ++ ++ if (!rc && !card->host->extra_pos) { ++ rc = xd_card_check_ecc_tmp(card); ++ if (rc) ++ card->trans_cnt -= card->page_size; ++ } ++ ++ if (!rc && ((card->trans_len - card->trans_cnt) ++ >= card->hw_page_size)) { ++ (*req)->count = 0; ++ (*req)->error = 0; ++ (*req)->addr ++ = xd_card_req_address(card, ++ card->trans_cnt); ++ sg_set_buf(&(*req)->sg, ++ card->t_buf + card->trans_cnt, ++ card->hw_page_size); ++ return 0; ++ } ++ } ++ } ++ ++ if (!(*req)->error) { ++ if (rc) ++ (*req)->error = rc; ++ else if (card->trans_cnt != card->trans_len) ++ (*req)->error = -EIO; ++ } ++ ++ if (!(*req)->error) { ++ (*req)->cmd = XD_CARD_CMD_INPUT; ++ (*req)->flags = XD_CARD_REQ_DATA | XD_CARD_REQ_DIR ++ | XD_CARD_REQ_EXTRA | XD_CARD_REQ_STATUS; ++ (*req)->addr = xd_card_req_address(card, 0); ++ (*req)->error = 0; ++ (*req)->count = card->hw_page_size; ++ card->trans_cnt = 0; ++ card->trans_len = card->flash_req.page_cnt * card->page_size; ++ ++ sg_set_buf(&(*req)->sg, card->t_buf, card->hw_page_size); ++ ++ memset(&card->host->extra, 0xff, sizeof(struct xd_card_extra)); ++ xd_card_addr_to_extra(&card->host->extra, ++ card->flash_req.log_block); ++ xd_card_update_extra_tmp(card); ++ card->next_request[0] = h_xd_card_write_tmp; ++ return 0; ++ } else ++ return xd_card_try_next_req(card, req); ++} ++ ++static int h_xd_card_erase_stat_fmt(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ if (!(*req)->error) { ++ (*req)->cmd = XD_CARD_CMD_STATUS1; ++ (*req)->flags = XD_CARD_REQ_STATUS; ++ (*req)->error = 0; ++ (*req)->count = 0; ++ card->next_request[0] = h_xd_card_default; ++ return 0; ++ } else ++ return xd_card_complete_req(card, (*req)->error); ++} ++ ++static int h_xd_card_erase_fmt(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ card->host->set_param(card->host, XD_CARD_ADDR_SIZE, card->addr_bytes); ++ if ((*req)->error || (card->host->caps & XD_CARD_CAP_CMD_SHORTCUT)) ++ return xd_card_complete_req(card, (*req)->error); ++ else { ++ (*req)->cmd = XD_CARD_CMD_ERASE_START; ++ (*req)->flags = XD_CARD_REQ_DIR; ++ (*req)->error = 0; ++ (*req)->count = 0; ++ card->next_request[0] = h_xd_card_erase_stat_fmt; ++ return 0; ++ } ++} ++ ++static int h_xd_card_erase_stat(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ if (!(*req)->error) { ++ (*req)->cmd = XD_CARD_CMD_STATUS1; ++ (*req)->flags = XD_CARD_REQ_STATUS; ++ (*req)->error = 0; ++ (*req)->count = 0; ++ card->trans_cnt = 0; ++ card->trans_len = 0; ++ card->next_request[0] = h_xd_card_check_stat; ++ return 0; ++ } else ++ return xd_card_try_next_req(card, req); ++} ++ ++static int h_xd_card_erase(struct xd_card_media *card, ++ struct xd_card_request **req) ++{ ++ card->host->set_param(card->host, XD_CARD_ADDR_SIZE, card->addr_bytes); ++ dev_dbg(card->host->dev, "card_erase %d, %02x\n", (*req)->error, ++ (*req)->status); ++ ++ if (!(*req)->error) { ++ if (card->host->caps & XD_CARD_CAP_CMD_SHORTCUT) { ++ if ((*req)->status & XD_CARD_STTS_FAIL) ++ (*req)->error = -EFAULT; ++ ++ return xd_card_try_next_req(card, req); ++ } ++ ++ (*req)->cmd = XD_CARD_CMD_ERASE_START; ++ (*req)->flags = XD_CARD_REQ_DIR; ++ (*req)->error = 0; ++ (*req)->count = 0; ++ card->trans_cnt = 0; ++ card->trans_len = 0; ++ card->next_request[0] = h_xd_card_erase_stat; ++ return 0; ++ } else ++ return xd_card_try_next_req(card, req); ++} ++ ++static int xd_card_get_status(struct xd_card_host *host, ++ unsigned char cmd, unsigned char *status) ++{ ++ struct xd_card_media *card = host->card; ++ ++ card->req.cmd = cmd; ++ card->req.flags = XD_CARD_REQ_STATUS; ++ card->req.error = 0; ++ ++ card->next_request[0] = h_xd_card_default; ++ xd_card_new_req(host); ++ wait_for_completion(&card->req_complete); ++ *status = card->req.status; ++ card->req.flags = 0; ++ return card->req.error; ++} ++ ++static int xd_card_get_id(struct xd_card_host *host, unsigned char cmd, ++ void *data, unsigned int count) ++{ ++ struct xd_card_media *card = host->card; ++ ++ card->req.cmd = cmd; ++ card->req.flags = XD_CARD_REQ_ID; ++ card->req.addr = 0; ++ card->req.count = count; ++ card->req.id = data; ++ card->req.error = 0; ++ card->next_request[0] = h_xd_card_default; ++ xd_card_new_req(host); ++ wait_for_completion(&card->req_complete); ++ card->req.flags = 0; ++ return card->req.error; ++} ++ ++ ++static int xd_card_bad_data(struct xd_card_host *host) ++{ ++ if (host->extra.data_status != 0xff) { ++ if (hweight8(host->extra.block_status) < 5) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int xd_card_bad_block(struct xd_card_host *host) ++{ ++ if (host->extra.block_status != 0xff) { ++ if (hweight8(host->extra.block_status) < 7) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int xd_card_read_extra(struct xd_card_host *host, unsigned int zone, ++ unsigned int phy_block, unsigned int page) ++{ ++ struct xd_card_media *card = host->card; ++ ++ card->flash_req.zone = zone; ++ card->flash_req.phy_block = phy_block; ++ card->flash_req.page_off = page; ++ card->req.cmd = XD_CARD_CMD_READ3; ++ card->req.flags = XD_CARD_REQ_EXTRA; ++ card->req.addr = xd_card_req_address(card, 0); ++ card->req.error = 0; ++ card->req.count = 0; ++ ++ host->extra_pos = 0; ++ ++ card->next_request[0] = h_xd_card_read_extra; ++ xd_card_new_req(host); ++ wait_for_completion(&card->req_complete); ++ return card->req.error; ++} ++ ++static int xd_card_find_cis(struct xd_card_host *host) ++{ ++ struct xd_card_media *card = host->card; ++ unsigned int r_size = sizeof(card->cis) + sizeof(card->idi); ++ unsigned int p_cnt, b_cnt; ++ unsigned char *buf; ++ unsigned int last_block = card->phy_block_cnt - card->log_block_cnt - 1; ++ int rc = 0; ++ ++ card->cis_block = FLASH_BD_INVALID; ++ buf = kmalloc(2 * r_size, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ sg_set_buf(&card->req_sg[0], buf, 2 * r_size); ++ card->seg_count = 1; ++ ++ dev_dbg(host->dev, "looking for cis in %d blocks\n", last_block); ++ ++ /* Map the desired blocks for one to one log/phy mapping */ ++ for (b_cnt = 0; b_cnt < last_block; ++b_cnt) ++ flash_bd_set_full(card->fbd, 0, b_cnt, b_cnt); ++ ++ for (b_cnt = 0; b_cnt < last_block; ++b_cnt) { ++ for (p_cnt = 0; p_cnt < card->page_cnt; ++p_cnt) { ++ dev_dbg(host->dev, "checking page %d:%d\n", b_cnt, ++ p_cnt); ++ ++ card->seg_pos = 0; ++ card->seg_off = 0; ++ rc = flash_bd_start_reading(card->fbd, ++ (b_cnt * card->page_cnt ++ + p_cnt) * card->page_size, ++ 2 * r_size); ++ if (rc) ++ goto out; ++ ++ rc = flash_bd_next_req(card->fbd, &card->flash_req, 0, ++ 0); ++ ++ if (rc) { ++ flash_bd_end(card->fbd); ++ goto out; ++ } ++ ++ xd_card_trans_req(card, &card->req); ++ ++ card->req.flags |= XD_CARD_REQ_NO_ECC ++ | XD_CARD_REQ_EXTRA; ++ ++ xd_card_new_req(host); ++ wait_for_completion(&card->req_complete); ++ rc = card->req.error; ++ ++ flash_bd_end(card->fbd); ++ ++ dev_dbg(host->dev, "extra: %08x, %02x, %02x, %04x " ++ "(%02x, %02x, %02x), %04x, (%02x, %02x, %02x)\n", ++ host->extra.reserved, host->extra.data_status, ++ host->extra.block_status, host->extra.addr1, ++ host->extra.ecc_hi[0], host->extra.ecc_hi[1], ++ host->extra.ecc_hi[2], host->extra.addr2, ++ host->extra.ecc_lo[0], host->extra.ecc_lo[1], ++ host->extra.ecc_lo[2]); ++ ++ if (!rc) { ++ if (xd_card_bad_block(host)) ++ break; ++ else if (!xd_card_bad_data(host)) { ++ memcpy(&card->cis, buf, ++ sizeof(card->cis)); ++ rc = sizeof(card->cis); ++ memcpy(&card->idi, buf + rc, ++ sizeof(card->idi)); ++ rc += sizeof(card->idi); ++ if (memcmp(&card->cis, buf + rc, ++ sizeof(card->cis))) { ++ rc = -EMEDIUMTYPE; ++ goto out; ++ } ++ rc += sizeof(card->cis); ++ if (memcmp(&card->idi, buf + rc, ++ sizeof(card->idi))) { ++ rc = -EMEDIUMTYPE; ++ goto out; ++ } ++ ++ card->cis_block = b_cnt; ++ rc = 0; ++ goto out; ++ } ++ } else ++ goto out; ++ } ++ } ++ ++out: ++ for (b_cnt = 0; b_cnt < last_block; ++b_cnt) ++ flash_bd_set_empty(card->fbd, 0, b_cnt, 0); ++ ++ if (card->cis_block != FLASH_BD_INVALID) { ++ for (b_cnt = 0; b_cnt <= card->cis_block; ++b_cnt) ++ flash_bd_set_full(card->fbd, 0, b_cnt, ++ FLASH_BD_INVALID); ++ } ++ kfree(buf); ++ return rc; ++} ++ ++static int xd_card_resolve_conflict(struct xd_card_host *host, ++ unsigned int zone, ++ unsigned int phy_block, ++ unsigned int log_block) ++{ ++ struct xd_card_media *card = host->card; ++ unsigned int o_phy_block = flash_bd_get_physical(card->fbd, zone, ++ log_block); ++ unsigned int l_addr, l_addr_o; ++ int rc; ++ ++ rc = xd_card_read_extra(host, zone, phy_block, card->page_cnt - 1); ++ if (rc) ++ return rc; ++ ++ l_addr = xd_card_extra_to_addr(&host->extra); ++ ++ rc = xd_card_read_extra(host, zone, o_phy_block, card->page_cnt - 1); ++ if (rc) ++ return rc; ++ ++ l_addr_o = xd_card_extra_to_addr(&host->extra); ++ ++ ++ dev_warn(host->dev, "block map conflict (%x) %x -> %x, %x (%x, %x)\n", ++ zone, log_block, phy_block, o_phy_block, l_addr, l_addr_o); ++ ++ if (l_addr != log_block) ++ l_addr = FLASH_BD_INVALID; ++ ++ if (l_addr_o !=log_block) ++ l_addr_o = FLASH_BD_INVALID; ++ ++ if (l_addr == l_addr_o) { ++ if (phy_block < o_phy_block) { ++ flash_bd_set_empty(card->fbd, zone, o_phy_block, 0); ++ flash_bd_set_full(card->fbd, zone, phy_block, ++ log_block); ++ } else ++ flash_bd_set_empty(card->fbd, zone, phy_block, 0); ++ } else if (l_addr != FLASH_BD_INVALID) { ++ flash_bd_set_empty(card->fbd, zone, o_phy_block, 0); ++ flash_bd_set_full(card->fbd, zone, phy_block, log_block); ++ } else if (l_addr_o != FLASH_BD_INVALID) { ++ flash_bd_set_empty(card->fbd, zone, phy_block, 0); ++ } ++ ++ return 0; ++} ++ ++static int xd_card_fill_lut(struct xd_card_host *host) ++{ ++ struct xd_card_media *card = host->card; ++ unsigned int z_cnt = 0, b_cnt, log_block, s_block = card->cis_block + 1; ++ int rc; ++ ++ for (z_cnt = 0; z_cnt < card->zone_cnt; ++z_cnt) { ++ for (b_cnt = s_block; b_cnt < card->phy_block_cnt; ++b_cnt) { ++ rc = xd_card_read_extra(host, z_cnt, b_cnt, 0); ++ if (rc) ++ return rc; ++ ++ dev_dbg(host->dev, "extra (%x) %x : %02x, %04x, %04x\n", ++ z_cnt, b_cnt, host->extra.block_status, ++ host->extra.addr1, host->extra.addr2); ++ ++ if (xd_card_bad_block(host)) { ++ flash_bd_set_full(card->fbd, z_cnt, b_cnt, ++ FLASH_BD_INVALID); ++ continue; ++ } ++ ++ log_block = xd_card_extra_to_addr(&host->extra); ++ if (log_block == FLASH_BD_INVALID) { ++ flash_bd_set_empty(card->fbd, z_cnt, b_cnt, 0); ++ continue; ++ } ++ ++ rc = flash_bd_set_full(card->fbd, z_cnt, b_cnt, ++ log_block); ++ if (rc == -EEXIST) ++ rc = xd_card_resolve_conflict(host, z_cnt, ++ b_cnt, log_block); ++ ++ dev_dbg(host->dev, "fill lut (%x) %x -> %x, %x\n", ++ z_cnt, log_block, b_cnt, rc); ++ ++ if (rc) ++ return rc; ++ } ++ s_block = 0; ++ } ++ return 0; ++} ++ ++/* Mask ROM devices are required to have the same format as Flash ones */ ++static int xd_card_fill_lut_rom(struct xd_card_host *host) ++{ ++ struct xd_card_media *card = host->card; ++ unsigned int z_cnt = 0, b_cnt; ++ unsigned int s_block = card->cis_block + 1; ++ ++ for (z_cnt = 0; z_cnt < card->zone_cnt; ++z_cnt) { ++ for (b_cnt = 0; b_cnt < card->log_block_cnt; ++b_cnt) { ++ flash_bd_set_full(card->fbd, z_cnt, s_block, b_cnt); ++ s_block++; ++ } ++ s_block = 0; ++ } ++ return 0; ++} ++ ++static int xd_card_format_thread(void *data) ++{ ++ struct xd_card_media *card = data; ++ struct xd_card_host *host = card->host; ++ struct flash_bd *o_fbd; ++ int rc = 0; ++ unsigned long flags; ++ ++ mutex_lock(&host->lock); ++ card->trans_len = card->zone_cnt << card->block_addr_bits; ++ o_fbd = card->fbd; ++ card->fbd = flash_bd_init(card->zone_cnt, card->phy_block_cnt, ++ card->log_block_cnt, card->page_cnt, ++ card->page_size); ++ if (!card->fbd) { ++ card->fbd = o_fbd; ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ flash_bd_destroy(o_fbd); ++ ++ for(card->trans_cnt = card->cis_block + 1; ++ card->trans_cnt < card->trans_len; ++ ++card->trans_cnt) { ++ host->set_param(host, XD_CARD_ADDR_SIZE, card->addr_bytes - 1); ++ card->req.cmd = XD_CARD_CMD_ERASE_SET; ++ card->req.flags = XD_CARD_REQ_DIR | XD_CARD_REQ_STATUS; ++ card->req.addr = card->trans_cnt << card->page_addr_bits; ++ card->req.error = 0; ++ card->req.count = 0; ++ card->next_request[0] = h_xd_card_erase_fmt; ++ ++ xd_card_new_req(host); ++ wait_for_completion(&card->req_complete); ++ rc = card->req.error; ++ ++ if (!rc) { ++ if (!(card->req.status & XD_CARD_STTS_FAIL)) ++ flash_bd_set_empty(card->fbd, ++ card->trans_cnt ++ >> card->block_addr_bits, ++ card->trans_cnt ++ & ((1 ++ << card->block_addr_bits) ++ - 1), 1); ++ else ++ flash_bd_set_full(card->fbd, ++ card->trans_cnt ++ >> card->block_addr_bits, ++ card->trans_cnt ++ & ((1 ++ << card->block_addr_bits) ++ - 1), FLASH_BD_INVALID); ++ } ++ ++ mutex_unlock(&host->lock); ++ yield(); ++ mutex_lock(&host->lock); ++ if (kthread_should_stop()) { ++ dev_info(host->dev, "format aborted at block " ++ "%x of %x\n", card->trans_cnt, ++ card->trans_len); ++ card->format = 0; ++ mutex_unlock(&host->lock); ++ return 0; ++ } ++ ++ if (rc) ++ break; ++ } ++out: ++ if (!rc) ++ dev_info(host->dev, "format complete\n"); ++ else ++ dev_err(host->dev, "format failed (%d)\n", rc); ++ ++ spin_lock_irqsave(&host->card->q_lock, flags); ++ host->card->format = 0; ++ host->card->f_thread = NULL; ++ blk_start_queue(host->card->queue); ++ spin_unlock_irqrestore(&host->card->q_lock, flags); ++ ++ mutex_unlock(&host->lock); ++ return 0; ++} ++ ++static int xd_card_prepare_req(struct request_queue *q, struct request *req) ++{ ++ if (!blk_fs_request(req) && !blk_pc_request(req)) { ++ blk_dump_rq_flags(req, "xD card bad request"); ++ return BLKPREP_KILL; ++ } ++ ++ req->cmd_flags |= REQ_DONTPREP; ++ ++ return BLKPREP_OK; ++} ++ ++static void xd_card_submit_req(struct request_queue *q) ++{ ++ struct xd_card_media *card = q->queuedata; ++ struct request *req = NULL; ++ ++ if (card->has_request) ++ return; ++ ++ if (card->eject) { ++ while ((req = elv_next_request(q)) != NULL) ++ end_queued_request(req, -ENODEV); ++ ++ return; ++ } ++ ++ card->has_request = 1; ++ if (xd_card_issue_req(card, 0)) ++ card->has_request = 0; ++} ++ ++ ++/*** Initialization ***/ ++ ++static int xd_card_set_disk_size(struct xd_card_media *card) ++{ ++ card->page_size = 512; ++ card->hw_page_size = 512; ++ card->zone_cnt = 1; ++ card->phy_block_cnt = 1024; ++ card->log_block_cnt = 1000; ++ card->page_cnt = 32; ++ ++ if (card->id1.option_code2 != 0xc0) ++ card->sm_media = 1; ++ ++ switch (card->id1.device_code) { ++ case 0x6e: ++ case 0xe8: ++ case 0xec: ++ card->hw_page_size = 256; ++ card->capacity = 2000; ++ card->cylinders = 125; ++ card->heads = 4; ++ card->sectors_per_head = 4; ++ card->phy_block_cnt = 256; ++ card->log_block_cnt = 250; ++ card->page_cnt = 8; ++ break; ++ case 0x5d: ++ case 0xea: ++ case 0x64: ++ if (card->id1.device_code != 0x5d) { ++ card->hw_page_size = 256; ++ card->phy_block_cnt = 512; ++ card->log_block_cnt = 500; ++ card->page_cnt = 8; ++ } else { ++ card->mask_rom = 1; ++ card->phy_block_cnt = 256; ++ card->log_block_cnt = 250; ++ card->page_cnt = 16; ++ } ++ card->capacity = 4000; ++ card->cylinders = 125; ++ card->heads = 4; ++ card->sectors_per_head = 8; ++ break; ++ case 0xd5: ++ if (card->sm_media) ++ card->mask_rom = 1; /* deliberate fall-through */ ++ else { ++ card->capacity = 4095630; ++ card->cylinders = 985; ++ card->heads = 66; ++ card->sectors_per_head = 63; ++ card->zone_cnt = 128; ++ break; ++ } ++ case 0xe3: ++ case 0xe5: ++ case 0x6b: ++ card->capacity = 8000; ++ card->cylinders = 250; ++ card->heads = 4; ++ card->sectors_per_head = 8; ++ card->phy_block_cnt = 512; ++ card->log_block_cnt = 500; ++ card->page_cnt = 16; ++ break; ++ case 0xd6: ++ if (card->sm_media) ++ card->mask_rom = 1; /* deliberate fall-through */ ++ else ++ return -EMEDIUMTYPE; ++ case 0xe6: ++ card->capacity = 16000; ++ card->cylinders = 250; ++ card->heads = 4; ++ card->sectors_per_head = 16; ++ card->page_cnt = 16; ++ break; ++ case 0x57: ++ card->mask_rom = 1; ++ case 0x73: ++ card->capacity = 32000; ++ card->cylinders = 500; ++ card->heads = 4; ++ card->sectors_per_head = 16; ++ break; ++ case 0x58: ++ card->mask_rom = 1; ++ case 0x75: ++ card->capacity = 64000; ++ card->cylinders = 500; ++ card->heads = 8; ++ card->sectors_per_head = 16; ++ card->zone_cnt = 2; ++ break; ++ case 0xd9: ++ if (card->sm_media) ++ card->mask_rom = 1; /* deliberate fall-through */ ++ else ++ return -EMEDIUMTYPE; ++ case 0x76: ++ card->capacity = 128000; ++ card->cylinders = 500; ++ card->heads = 8; ++ card->sectors_per_head = 32; ++ card->zone_cnt = 4; ++ break; ++ case 0xda: ++ card->mask_rom = 1; ++ case 0x79: ++ card->capacity = 256000; ++ card->cylinders = 500; ++ card->heads = 16; ++ card->sectors_per_head = 32; ++ card->zone_cnt = 8; ++ break; ++ case 0x5b: ++ card->mask_rom = 1; ++ case 0x71: ++ card->capacity = 512000; ++ card->cylinders = 1000; ++ card->heads = 16; ++ card->sectors_per_head = 32; ++ card->zone_cnt = 16; ++ break; ++ case 0xdc: ++ card->capacity = 1023120; ++ card->cylinders = 1015; ++ card->heads = 16; ++ card->sectors_per_head = 63; ++ card->zone_cnt = 32; ++ break; ++ case 0xd3: ++ card->capacity = 2047815; ++ card->cylinders = 985; ++ card->heads = 33; ++ card->sectors_per_head = 63; ++ card->zone_cnt = 64; ++ break; ++ default: ++ return -EMEDIUMTYPE; ++ }; ++ return 0; ++} ++ ++static int xd_card_init_disk(struct xd_card_media *card) ++{ ++ struct xd_card_host *host = card->host; ++ int rc, disk_id; ++ u64 limit = BLK_BOUNCE_HIGH; ++ unsigned int max_sectors; ++ ++ if (host->dev->dma_mask && *(host->dev->dma_mask)) ++ limit = *(host->dev->dma_mask); ++ ++ if (!idr_pre_get(&xd_card_disk_idr, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ mutex_lock(&xd_card_disk_lock); ++ rc = idr_get_new(&xd_card_disk_idr, card, &disk_id); ++ mutex_unlock(&xd_card_disk_lock); ++ ++ if (rc) ++ return rc; ++ ++ if ((disk_id << XD_CARD_PART_SHIFT) > 255) { ++ rc = -ENOSPC; ++ goto out_release_id; ++ } ++ ++ card->disk = alloc_disk(1 << XD_CARD_PART_SHIFT); ++ if (!card->disk) { ++ rc = -ENOMEM; ++ goto out_release_id; ++ } ++ ++ card->queue = blk_init_queue(xd_card_submit_req, &card->q_lock); ++ if (!card->queue) { ++ rc = -ENOMEM; ++ goto out_put_disk; ++ } ++ ++ card->queue->queuedata = card; ++ blk_queue_prep_rq(card->queue, xd_card_prepare_req); ++ ++ max_sectors = card->zone_cnt * card->log_block_cnt * card->page_size ++ * card->page_cnt; ++ max_sectors >>= 9; ++ ++ blk_queue_bounce_limit(card->queue, limit); ++ blk_queue_max_sectors(card->queue, max_sectors); ++ blk_queue_max_phys_segments(card->queue, XD_CARD_MAX_SEGS); ++ blk_queue_max_hw_segments(card->queue, XD_CARD_MAX_SEGS); ++ blk_queue_max_segment_size(card->queue, max_sectors << 9); ++ ++ card->disk->major = major; ++ card->disk->first_minor = disk_id << XD_CARD_PART_SHIFT; ++ card->disk->fops = &xd_card_bdops; ++ card->usage_count = 1; ++ card->disk->private_data = card; ++ card->disk->queue = card->queue; ++ card->disk->driverfs_dev = host->dev; ++ ++ sprintf(card->disk->disk_name, "xd_card%d", disk_id); ++ ++ blk_queue_hardsect_size(card->queue, card->page_size); ++ ++ set_capacity(card->disk, card->capacity); ++ dev_dbg(host->dev, "capacity set %d\n", card->capacity); ++ ++ add_disk(card->disk); ++ return 0; ++ ++out_put_disk: ++ put_disk(card->disk); ++out_release_id: ++ mutex_lock(&xd_card_disk_lock); ++ idr_remove(&xd_card_disk_idr, disk_id); ++ mutex_unlock(&xd_card_disk_lock); ++ return rc; ++} ++ ++static void xd_card_set_media_param(struct xd_card_host *host) ++{ ++ struct xd_card_media *card = host->card; ++ ++ host->set_param(host, XD_CARD_PAGE_SIZE, card->hw_page_size); ++ host->set_param(host, XD_CARD_EXTRA_SIZE, ++ sizeof(struct xd_card_extra) ++ / (card->page_size / card->hw_page_size)); ++ host->set_param(host, XD_CARD_ADDR_SIZE, card->addr_bytes); ++ ++ if (!card->sm_media) ++ host->set_param(host, XD_CARD_CLOCK, XD_CARD_NORMAL); ++ else ++ host->set_param(host, XD_CARD_CLOCK, XD_CARD_SLOW); ++} ++ ++static int xd_card_sysfs_register(struct xd_card_host *host) ++{ ++ int rc; ++ ++ rc = device_create_file(host->dev, &dev_attr_xd_card_id); ++ if (rc) ++ return rc; ++ ++ rc = device_create_file(host->dev, &dev_attr_xd_card_cis); ++ if (rc) ++ goto out_remove_id; ++ ++ rc = device_create_file(host->dev, &dev_attr_xd_card_idi); ++ if (rc) ++ goto out_remove_cis; ++ ++ host->card->dev_attr_block_map.attr.name = "xd_card_block_map"; ++ host->card->dev_attr_block_map.attr.mode = S_IRUGO; ++ host->card->dev_attr_block_map.attr.owner = THIS_MODULE; ++ ++ host->card->dev_attr_block_map.size ++ = flash_bd_map_size(host->card->fbd); ++ host->card->dev_attr_block_map.read = xd_card_block_map_read; ++ ++ rc = device_create_bin_file(host->dev, &host->card->dev_attr_block_map); ++ if (rc) ++ goto out_remove_idi; ++ ++ rc = device_create_file(host->dev, &dev_attr_xd_card_format); ++ if (!rc) ++ return 0; ++ ++ device_remove_bin_file(host->dev, &host->card->dev_attr_block_map); ++out_remove_idi: ++ device_remove_file(host->dev, &dev_attr_xd_card_idi); ++out_remove_cis: ++ device_remove_file(host->dev, &dev_attr_xd_card_cis); ++out_remove_id: ++ device_remove_file(host->dev, &dev_attr_xd_card_id); ++ return rc; ++} ++ ++static void xd_card_sysfs_unregister(struct xd_card_host *host) ++{ ++ device_remove_file(host->dev, &dev_attr_xd_card_format); ++ device_remove_bin_file(host->dev, &host->card->dev_attr_block_map); ++ device_remove_file(host->dev, &dev_attr_xd_card_idi); ++ device_remove_file(host->dev, &dev_attr_xd_card_cis); ++ device_remove_file(host->dev, &dev_attr_xd_card_id); ++} ++#if 0 ++static void xd_card_test_wr(struct xd_card_host *host) ++{ ++ struct xd_card_media *card = host->card; ++ unsigned int p_cnt; ++ ++ card->flash_req.zone = 0; ++ card->flash_req.phy_block = 2002; ++ card->flash_req.page_off = 10; ++ card->flash_req.page_cnt = 20;//card->page_cnt; ++ ++ memset(&host->extra, 0xff, sizeof(host->extra)); ++ host->extra.addr1 = 0x0110; ++ host->extra.addr2 = 0x0110; ++ host->extra_pos = 0; ++ memset(card->t_buf, 0, card->page_cnt * card->page_size); ++ dev_dbg(host->dev, "ref block %016llx\n", *(unsigned long long *)host->card->t_buf); ++ ++ for (p_cnt = 10; ++ p_cnt < card->flash_req.page_cnt; ++ ++p_cnt) { ++ card->flash_req.page_off = p_cnt; ++ card->req.cmd = XD_CARD_CMD_INPUT; ++ card->req.flags = XD_CARD_REQ_DATA | XD_CARD_REQ_DIR ++ | XD_CARD_REQ_EXTRA | XD_CARD_REQ_STATUS; ++ card->req.addr = xd_card_req_address(card, 0); ++ card->req.error = 0; ++ card->req.count = 0; ++ card->trans_cnt = 0; ++ card->trans_len = card->hw_page_size; ++ ++ sg_set_buf(&card->req.sg, ++ card->t_buf,/* + p_cnt * card->page_size,*/ ++ card->trans_len); ++ card->next_request[0] = h_xd_card_default; ++ ++ xd_card_new_req(host); ++ wait_for_completion(&card->req_complete); ++ ++ dev_dbg(host->dev, "test write page %x, status %02x\n", ++ p_cnt, card->req.status); ++ msleep(1); ++ card->req.cmd = XD_CARD_CMD_PAGE_PROG; ++ card->req.flags = XD_CARD_REQ_DIR | XD_CARD_REQ_STATUS; ++ card->req.error = 0; ++ card->req.count = 0; ++ card->trans_cnt = 0; ++ card->trans_len = 0; ++ ++ card->next_request[0] = h_xd_card_default; ++ ++ xd_card_new_req(host); ++ wait_for_completion(&card->req_complete); ++ } ++} ++#endif ++static int xd_card_init_media(struct xd_card_host *host) ++{ ++ int rc; ++ ++ xd_card_set_media_param(host); ++ ++ if (!host->card->mask_rom) ++ rc = xd_card_fill_lut(host); ++ else ++ rc = xd_card_fill_lut_rom(host); ++ ++ if (rc) ++ return rc; ++ ++ /* We just read a single page to reset flash column pointer. */ ++ host->card->flash_req.zone = 0; ++ host->card->flash_req.phy_block = host->card->cis_block; ++ host->card->flash_req.page_off = 0; ++ host->card->flash_req.page_cnt = 1; ++ host->card->req.cmd = XD_CARD_CMD_READ1; ++ host->card->req.flags = XD_CARD_REQ_DATA; ++ host->card->req.addr = xd_card_req_address(host->card, 0); ++ host->card->req.error = 0; ++ host->card->req.count = 0; ++ host->card->trans_cnt = 0; ++ host->card->trans_len = host->card->hw_page_size; ++ ++ sg_set_buf(&host->card->req.sg, host->card->t_buf, ++ host->card->trans_len); ++ host->card->next_request[0] = h_xd_card_default; ++ xd_card_new_req(host); ++ wait_for_completion(&host->card->req_complete); ++ ++// dev_dbg(host->dev, "block %016llx\n", *(unsigned long long *)host->card->t_buf); ++// msleep(1); ++// if (host->card->t_buf[0]) { ++// dev_dbg(host->dev, "test writing\n"); ++// xd_card_test_wr(host); ++// } ++ ++ ++ rc = xd_card_sysfs_register(host); ++ if (rc) ++ return rc; ++ ++ rc = xd_card_init_disk(host->card); ++ if (!rc) ++ return 0; ++ ++ xd_card_sysfs_unregister(host); ++ return rc; ++} ++ ++static void xd_card_free_media(struct xd_card_media *card) ++{ ++ flash_bd_destroy(card->fbd); ++ kfree(card->t_buf); ++ kfree(card); ++} ++ ++struct xd_card_media *xd_card_alloc_media(struct xd_card_host *host) ++{ ++ struct xd_card_media *card = kzalloc(sizeof(struct xd_card_media), ++ GFP_KERNEL); ++ struct xd_card_media *old_card = host->card; ++ unsigned int t_val; ++ int rc = -ENOMEM; ++ unsigned char status; ++ ++ if (!card) ++ goto out; ++ ++ card->host = host; ++ host->card = card; ++ card->usage_count = 1; ++ spin_lock_init(&card->q_lock); ++ init_completion(&card->req_complete); ++ ++ rc = xd_card_get_status(host, XD_CARD_CMD_RESET, &status); ++ if (rc) ++ goto out; ++ ++ /* xd card must get ready in about 40ms */ ++ for (t_val = 1; t_val <= 32; t_val *= 2) { ++ rc = xd_card_get_status(host, XD_CARD_CMD_STATUS1, &status); ++ if (rc) ++ goto out; ++ if (status & XD_CARD_STTS_READY) { ++ rc = 0; ++ break; ++ } else ++ rc = -ETIME; ++ ++ msleep(t_val); ++ } ++ ++ if (rc) ++ goto out; ++ ++ rc = xd_card_get_id(host, XD_CARD_CMD_ID1, &card->id1, ++ sizeof(card->id1)); ++ if (rc) ++ goto out; ++ ++ rc = xd_card_set_disk_size(card); ++ if (rc) ++ goto out; ++ ++ if (card->mask_rom) ++ card->read_only = 1; ++ ++ rc = card->page_cnt * (card->page_size / card->hw_page_size); ++ card->page_addr_bits = fls(rc - 1); ++ if ((1 << card->page_addr_bits) < rc) ++ card->page_addr_bits++; ++ ++ card->block_addr_bits = fls(card->phy_block_cnt - 1); ++ if ((1 << card->block_addr_bits) < card->phy_block_cnt) ++ card->block_addr_bits++; ++ ++ if (card->capacity < 62236) ++ card->addr_bytes = 3; ++ else if (card->capacity < 8388608) ++ card->addr_bytes = 4; ++ else { ++ rc = -EINVAL; ++ goto out; ++ } ++ ++ dev_dbg(host->dev, "address bits: page %d, block %d, addr %d\n", ++ card->page_addr_bits, card->block_addr_bits, card->addr_bytes); ++ ++ if (host->caps & XD_CARD_CAP_AUTO_ECC) ++ card->auto_ecc = 1; ++ ++ if (host->caps & XD_CARD_CAP_FIXED_EXTRA) { ++ if (card->page_size != card->hw_page_size) ++ card->auto_ecc = 0; ++ } ++ ++ if (!card->sm_media) { ++ rc = xd_card_get_id(host, XD_CARD_CMD_ID2, &card->id2, ++ sizeof(card->id2)); ++ if (rc) ++ goto out; ++ } ++ ++ if (!card->sm_media) { ++ /* This appears to be totally optional */ ++ xd_card_get_id(host, XD_CARD_CMD_ID3, &card->id3, ++ sizeof(card->id3)); ++ } ++ ++ xd_card_set_media_param(host); ++ ++ dev_dbg(host->dev, "alloc %d bytes for tmp\n", ++ card->page_size * card->page_cnt); ++ card->t_buf = kmalloc(card->page_size * card->page_cnt, GFP_KERNEL); ++ if (!card->t_buf) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ dev_dbg(host->dev, "init flash_bd\n"); ++ card->fbd = flash_bd_init(card->zone_cnt, card->phy_block_cnt, ++ card->log_block_cnt, card->page_cnt, ++ card->page_size); ++ if (!card->fbd) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ rc = xd_card_find_cis(host); ++ if (rc) ++ goto out; ++ ++ /* It is possible to parse CIS header, but recent version of the spec ++ * suggests that it is frozen and information it contains (mostly ++ * ancient Compact Flash stuff) irrelevant. ++ */ ++ if (memcmp(xd_card_cis_header, card->cis, sizeof(xd_card_cis_header))) ++ rc = -EMEDIUMTYPE; ++ ++out: ++ host->card = old_card; ++ if (host->card) ++ xd_card_set_media_param(host); ++ if (rc) { ++ xd_card_free_media(card); ++ return ERR_PTR(rc); ++ } else ++ return card; ++} ++ ++static void xd_card_remove_media(struct xd_card_media *card) ++{ ++ struct xd_card_host *host = card->host; ++ struct task_struct *f_thread = NULL; ++ struct gendisk *disk = card->disk; ++ unsigned long flags; ++ ++ del_gendisk(card->disk); ++ dev_dbg(host->dev, "xd card remove\n"); ++ xd_card_sysfs_unregister(host); ++ ++ spin_lock_irqsave(&card->q_lock, flags); ++ f_thread = card->f_thread; ++ card->f_thread = NULL; ++ card->eject = 1; ++ blk_start_queue(card->queue); ++ spin_unlock_irqrestore(&card->q_lock, flags); ++ ++ if (f_thread) { ++ mutex_unlock(&host->lock); ++ kthread_stop(f_thread); ++ mutex_lock(&host->lock); ++ dev_dbg(host->dev, "format thread stopped\n"); ++ } ++ ++ blk_cleanup_queue(card->queue); ++ card->queue = NULL; ++ ++ xd_card_disk_release(disk); ++} ++ ++static void xd_card_check(struct work_struct *work) ++{ ++ struct xd_card_host *host = container_of(work, struct xd_card_host, ++ media_checker); ++ struct xd_card_media *card; ++ ++ dev_dbg(host->dev, "xd_card_check started\n"); ++ mutex_lock(&host->lock); ++ ++ if (!host->card) ++ host->set_param(host, XD_CARD_POWER, XD_CARD_POWER_ON); ++ else { ++ while (!xd_card_stop_queue(host->card)) ++ wait_for_completion(&host->card->req_complete); ++ } ++ ++ card = xd_card_alloc_media(host); ++ dev_dbg(host->dev, "card allocated %p\n", card); ++ ++ if (IS_ERR(card)) { ++ dev_dbg(host->dev, "error %ld allocating card\n", ++ PTR_ERR(card)); ++ if (host->card) { ++ dev_dbg(host->dev, "x1 %p\n", host->card); ++ xd_card_remove_media(host->card); ++ dev_dbg(host->dev, "x2\n"); ++ host->card = NULL; ++ } ++ } else { ++ dev_dbg(host->dev, "new card %02x, %02x, %02x, %02x\n", ++ card->id1.maker_code, card->id1.device_code, ++ card->id1.option_code1, card->id1.option_code2); ++ ++ if (host->card) { ++ xd_card_remove_media(host->card); ++ host->card = NULL; ++ } ++ ++ host->card = card; ++ if (xd_card_init_media(host)) { ++ xd_card_free_media(host->card); ++ host->card = NULL; ++ } ++ } ++ dev_dbg(host->dev, "x3\n"); ++ if (!host->card) ++ host->set_param(host, XD_CARD_POWER, XD_CARD_POWER_OFF); ++ ++ mutex_unlock(&host->lock); ++ dev_dbg(host->dev, "xd_card_check finished\n"); ++} ++ ++/** ++ * xd_card_detect_change - schedule media detection on memstick host ++ * @host: host to use ++ */ ++void xd_card_detect_change(struct xd_card_host *host) ++{ ++ queue_work(workqueue, &host->media_checker); ++} ++EXPORT_SYMBOL(xd_card_detect_change); ++ ++/** ++ * xd_card_suspend_host - notify bus driver of host suspension ++ * @host - host to use ++ */ ++int xd_card_suspend_host(struct xd_card_host *host) ++{ ++ struct task_struct *f_thread = NULL; ++ unsigned long flags; ++ ++ mutex_lock(&host->lock); ++ if (host->card) { ++ spin_lock_irqsave(&host->card->q_lock, flags); ++ f_thread = host->card->f_thread; ++ host->card->f_thread = NULL; ++ blk_stop_queue(host->card->queue); ++ spin_unlock_irqrestore(&host->card->q_lock, flags); ++ ++ if (f_thread) { ++ mutex_unlock(&host->lock); ++ kthread_stop(f_thread); ++ mutex_lock(&host->lock); ++ } ++ } ++ host->set_param(host, XD_CARD_POWER, XD_CARD_POWER_OFF); ++ mutex_unlock(&host->lock); ++ return 0; ++} ++EXPORT_SYMBOL(xd_card_suspend_host); ++ ++/** ++ * xd_card_resume_host - notify bus driver of host resumption ++ * @host - host to use ++ */ ++int xd_card_resume_host(struct xd_card_host *host) ++{ ++ struct xd_card_media *card; ++ unsigned int flags; ++ ++ mutex_lock(&host->lock); ++ if (host->card) { ++ host->set_param(host, XD_CARD_POWER, XD_CARD_POWER_ON); ++#if defined(CONFIG_XD_CARD_UNSAFE_RESUME) ++ card = xd_card_alloc_media(host); ++ if (!IS_ERR(card) ++ && !memcmp(&card->cis, &host->card->cis, ++ sizeof(card->cis)) ++ && !memcmp(&card->idi, &host->card->idi, ++ sizeof(card->idi))) { ++ xd_card_free_media(card); ++ } else ++ xd_card_detect_change(host); ++#else ++ xd_card_detect_change(host); ++#endif /* CONFIG_XD_CARD_UNSAFE_RESUME */ ++ spin_lock_irqsave(&host->card->q_lock, flags); ++ blk_start_queue(host->card->queue); ++ spin_unlock_irqrestore(&host->card->q_lock, flags); ++ } else ++ xd_card_detect_change(host); ++ mutex_unlock(&host->lock); ++ return 0; ++} ++EXPORT_SYMBOL(xd_card_resume_host); ++ ++ ++/** ++ * xd_card_alloc_host - allocate an xd_card_host structure ++ * @extra: size of the user private data to allocate ++ * @dev: parent device of the host ++ */ ++struct xd_card_host *xd_card_alloc_host(unsigned int extra, struct device *dev) ++{ ++ struct xd_card_host *host = kzalloc(sizeof(struct xd_card_host) + extra, ++ GFP_KERNEL); ++ if (!host) ++ return NULL; ++ ++ host->dev = dev; ++ mutex_init(&host->lock); ++ INIT_WORK(&host->media_checker, xd_card_check); ++ return host; ++} ++EXPORT_SYMBOL(xd_card_alloc_host); ++ ++/** ++ * xd_card_free_host - stop request processing and deallocate xd card host ++ * @host: host to use ++ */ ++void xd_card_free_host(struct xd_card_host *host) ++{ ++ flush_workqueue(workqueue); ++ mutex_lock(&host->lock); ++ if (host->card) ++ xd_card_remove_media(host->card); ++ host->card = NULL; ++ mutex_unlock(&host->lock); ++ ++ mutex_destroy(&host->lock); ++ kfree(host); ++} ++EXPORT_SYMBOL(xd_card_free_host); ++ ++static int __init xd_card_init(void) ++{ ++ int rc = -ENOMEM; ++ ++ workqueue = create_freezeable_workqueue("kxd_card"); ++ if (!workqueue) ++ return -ENOMEM; ++ ++ rc = register_blkdev(major, DRIVER_NAME); ++ if (rc < 0) { ++ printk(KERN_ERR DRIVER_NAME ": failed to register " ++ "major %d, error %d\n", major, rc); ++ destroy_workqueue(workqueue); ++ return rc; ++ } ++ ++ if (!major) ++ major = rc; ++ ++ return 0; ++} ++ ++static void __exit xd_card_exit(void) ++{ ++ unregister_blkdev(major, DRIVER_NAME); ++ destroy_workqueue(workqueue); ++ idr_destroy(&xd_card_disk_idr); ++} ++ ++module_init(xd_card_init); ++module_exit(xd_card_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Alex Dubov"); ++MODULE_DESCRIPTION("xD picture card block device driver"); +diff --git a/drivers/mmc/ms/xd_card_ecc.c b/drivers/mmc/ms/xd_card_ecc.c +new file mode 100755 +index 0000000..7bf2acb +--- /dev/null ++++ b/drivers/mmc/ms/xd_card_ecc.c +@@ -0,0 +1,167 @@ ++/* ++ * xD picture card ECC algorithm ++ * ++ * Copyright (C) 2008 JMicron Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include "linux/xd_card.h" ++ ++/* ++ * Rather straightforward implementation of SmartMedia ECC algorithm. ++ * Probably very slow. ++ */ ++ ++const static unsigned char xd_card_ecc_table[] = { ++ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0C, 0x0F, 0x5A, ++ 0x5A, 0x0F, 0x0C, 0x59, 0x03, 0x56, 0x55, 0x00, ++ 0x65, 0x30, 0x33, 0x66, 0x3C, 0x69, 0x6A, 0x3F, ++ 0x3F, 0x6A, 0x69, 0x3C, 0x66, 0x33, 0x30, 0x65, ++ 0x66, 0x33, 0x30, 0x65, 0x3F, 0x6A, 0x69, 0x3C, ++ 0x3C, 0x69, 0x6A, 0x3F, 0x65, 0x30, 0x33, 0x66, ++ 0x03, 0x56, 0x55, 0x00, 0x5A, 0x0F, 0x0C, 0x59, ++ 0x59, 0x0C, 0x0F, 0x5A, 0x00, 0x55, 0x56, 0x03, ++ 0x69, 0x3C, 0x3F, 0x6A, 0x30, 0x65, 0x66, 0x33, ++ 0x33, 0x66, 0x65, 0x30, 0x6A, 0x3F, 0x3C, 0x69, ++ 0x0C, 0x59, 0x5A, 0x0F, 0x55, 0x00, 0x03, 0x56, ++ 0x56, 0x03, 0x00, 0x55, 0x0F, 0x5A, 0x59, 0x0C, ++ 0x0F, 0x5A, 0x59, 0x0C, 0x56, 0x03, 0x00, 0x55, ++ 0x55, 0x00, 0x03, 0x56, 0x0C, 0x59, 0x5A, 0x0F, ++ 0x6A, 0x3F, 0x3C, 0x69, 0x33, 0x66, 0x65, 0x30, ++ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3C, 0x3F, 0x6A, ++ 0x6A, 0x3F, 0x3C, 0x69, 0x33, 0x66, 0x65, 0x30, ++ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3C, 0x3F, 0x6A, ++ 0x0F, 0x5A, 0x59, 0x0C, 0x56, 0x03, 0x00, 0x55, ++ 0x55, 0x00, 0x03, 0x56, 0x0C, 0x59, 0x5A, 0x0F, ++ 0x0C, 0x59, 0x5A, 0x0F, 0x55, 0x00, 0x03, 0x56, ++ 0x56, 0x03, 0x00, 0x55, 0x0F, 0x5A, 0x59, 0x0C, ++ 0x69, 0x3C, 0x3F, 0x6A, 0x30, 0x65, 0x66, 0x33, ++ 0x33, 0x66, 0x65, 0x30, 0x6A, 0x3F, 0x3C, 0x69, ++ 0x03, 0x56, 0x55, 0x00, 0x5A, 0x0F, 0x0C, 0x59, ++ 0x59, 0x0C, 0x0F, 0x5A, 0x00, 0x55, 0x56, 0x03, ++ 0x66, 0x33, 0x30, 0x65, 0x3F, 0x6A, 0x69, 0x3C, ++ 0x3C, 0x69, 0x6A, 0x3F, 0x65, 0x30, 0x33, 0x66, ++ 0x65, 0x30, 0x33, 0x66, 0x3C, 0x69, 0x6A, 0x3F, ++ 0x3F, 0x6A, 0x69, 0x3C, 0x66, 0x33, 0x30, 0x65, ++ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0C, 0x0F, 0x5A, ++ 0x5A, 0x0F, 0x0C, 0x59, 0x03, 0x56, 0x55, 0x00 ++}; ++ ++#define XD_CARD_ECC_CORR 0x00555554UL ++ ++/** ++ * xd_card_ecc_step - update the ecc state with some data ++ * @state: ecc state (initial - 0) ++ * @pos: ecc byte counter value ++ * @data: pointer to some data ++ * @count: length of data ++ * ++ * Returns 0 if more data needed or 1 if ecc can be computed ++ */ ++int xd_card_ecc_step(unsigned int *state, unsigned int *pos, ++ unsigned char *data, unsigned int count) ++{ ++ unsigned char c; ++ ++ while (*pos < 256) { ++ c = xd_card_ecc_table[data[*pos]]; ++ *state ^= c & 0x3f; ++ if (c & 0x40) ++ *state ^= (((*pos) & 0xff) << 16) ++ | (((~(*pos)) & 0xff) << 8); ++ ++ (*pos)++; ++ count--; ++ if (!count) ++ break; ++ } ++ ++ return (*pos) == 256; ++} ++ ++/** ++ * xd_card_ecc_value - turn ecc state into value ++ * @state: current ecc state ++ * ++ * Returns ecc value in SmartMedia format ++ */ ++unsigned int xd_card_ecc_value(unsigned int state) ++{ ++ unsigned int a = 0x808000, b = 0x8000, cnt; ++ unsigned int rv = 0; ++ ++ for (cnt = 0; cnt < 4; ++cnt) { ++ if (state & a & 0xff0000) ++ rv |= b; ++ b >>= 1; ++ if (state & a & 0xff00) ++ rv |= b; ++ b >>= 1; ++ a >>= 1; ++ } ++ b = 0x80; ++ for (cnt = 0; cnt < 4; ++cnt) { ++ if (state & a & 0xff0000) ++ rv |= b; ++ b >>= 1; ++ if (state & a & 0xff00) ++ rv |= b; ++ b >>= 1; ++ a >>= 1; ++ } ++ ++ rv = (~rv) & 0xffff; ++ rv |= (((~(state & 0xff)) << 2) | 3) << 16; ++ ++ return rv; ++} ++ ++/** ++ * xd_card_fix_ecc - try to fix 1-bit error ++ * @pos: error position in the original data block (returned) ++ * @mask: value to xor into error position (returned) ++ * @act_ecc: computed ecc of the original data block ++ * @ref_ecc: assumed ecc of the original data block ++ * ++ * Returns 0 if no error, -1 if uncorrectable, +1 if correctable ++ */ ++int xd_card_fix_ecc(unsigned int *pos, unsigned char *mask, ++ unsigned int act_ecc, unsigned int ref_ecc) ++{ ++ unsigned char a = 0x80, b = 0x04, cnt; ++ unsigned int b_pos = 0x00800000UL; ++ ++ if (act_ecc == ref_ecc) ++ return 0; ++ ++ ref_ecc = ((ref_ecc & 0xffff) << 8) | ((ref_ecc >> 16) & 0xff); ++ ++ if (((ref_ecc ^ (ref_ecc >> 1)) & XD_CARD_ECC_CORR) ++ == XD_CARD_ECC_CORR) { ++ *pos = 0; ++ *mask = 0; ++ ++ for (cnt = 0; cnt < 8; ++cnt) { ++ if (ref_ecc & b_pos) ++ *pos |= a; ++ b_pos >>= 2; ++ a >>= 1; ++ } ++ ++ for (cnt = 0; cnt < 3; ++cnt) { ++ if (ref_ecc & b_pos) ++ *mask |= b; ++ b_pos >>= 2; ++ b >>= 1; ++ } ++ ++ *mask = 1 << *mask; ++ return 1; ++ } ++ ++ return -1; ++} +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0073-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook10.patch +++ linux-2.6.24/patches/0073-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook10.patch @@ -0,0 +1,31 @@ +From 6ab317c1c6d2e7dfc929e23626ccdbab5241334a Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Mon, 3 Nov 2008 09:39:51 -0500 +Subject: [PATCH 073/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook10 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 9 +++++++++ + 1 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 770f62b..08b74d4 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,12 @@ ++linux (2.6.24-19.41netbook10) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * arch/x86/kernel/io_apic_32.c ++ Clear IRQ bit when drivers are unloaded. Part Fix for LP#243047 ++ ++ -- Michael Frey Mon, 03 Nov 2008 09:35:43 -0500 ++ + linux (2.6.24-19.41netbook9) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0118-Turn-debian-binary-custom.d-lpia-patchset-0013-pouls.patch +++ linux-2.6.24/patches/0118-Turn-debian-binary-custom.d-lpia-patchset-0013-pouls.patch @@ -0,0 +1,82 @@ +From 0e23095b9a6a300a26166217baa1e4e06943e5ba Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:32 +0100 +Subject: [PATCH 118/170] Turn debian/binary-custom.d/lpia/patchset/0013-poulsbo_pci_ids.patch into a commit. + +Signed-off-by: Andy Whitcroft + +commit 4883c50b37f2e791e29f545766e53ac456576926 +Author: Amit Kucheria +Date: Fri Jan 11 13:59:04 2008 +0200 + + UBUNTU: Poulsbo: Mass update of patches to be identical to those on moblin + + Sigh, we need better communication... + + Signed-off-by: Amit Kucheria +--- + .../lpia/patchset/0013-poulsbo_pci_ids.patch | 26 -------------------- + include/linux/pci_ids.h | 14 ++++++++++ + 2 files changed, 14 insertions(+), 26 deletions(-) + delete mode 100644 debian/binary-custom.d/lpia/patchset/0013-poulsbo_pci_ids.patch + +diff --git a/debian/binary-custom.d/lpia/patchset/0013-poulsbo_pci_ids.patch b/debian/binary-custom.d/lpia/patchset/0013-poulsbo_pci_ids.patch +deleted file mode 100644 +index 1cced87..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0013-poulsbo_pci_ids.patch ++++ /dev/null +@@ -1,26 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h +-index 1ee009e..cf03fe8 100644 +---- a/include/linux/pci_ids.h +-+++ b/include/linux/pci_ids.h +-@@ -2364,6 +2364,20 @@ +- #define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0 +- #define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2 +- #define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601 +-+#define PCI_DEVICE_ID_INTEL_POULSBO_HC 0x8100 +-+#define PCI_DEVICE_ID_INTEL_POULSBO_PE1 0x8110 +-+#define PCI_DEVICE_ID_INTEL_POULSBO_PE2 0x8112 +-+#define PCI_DEVICE_ID_INTEL_POULSBO_UC1 0x8114 +-+#define PCI_DEVICE_ID_INTEL_POULSBO_UC2 0x8115 +-+#define PCI_DEVICE_ID_INTEL_POULSBO_UC3 0x8116 +-+#define PCI_DEVICE_ID_INTEL_POULSBO_EC 0x8117 +-+#define PCI_DEVICE_ID_INTEL_POULSBO_UT 0x8118 +-+#define PCI_DEVICE_ID_INTEL_POULSBO_LPC 0x8119 +-+#define PCI_DEVICE_ID_INTEL_POULSBO_IDE 0x811a +-+#define PCI_DEVICE_ID_INTEL_POULSBO_HDA 0x811b +-+#define PCI_DEVICE_ID_INTEL_POULSBO_SD1 0x811c +-+#define PCI_DEVICE_ID_INTEL_POULSBO_SD2 0x811d +-+#define PCI_DEVICE_ID_INTEL_POULSBO_SD3 0x811e +- #define PCI_DEVICE_ID_INTEL_82454GX 0x84c4 +- #define PCI_DEVICE_ID_INTEL_82450GX 0x84c5 +- #define PCI_DEVICE_ID_INTEL_82451NX 0x84ca +diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h +index 7f22151..e992808 100644 +--- a/include/linux/pci_ids.h ++++ b/include/linux/pci_ids.h +@@ -2371,6 +2371,20 @@ + #define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0 + #define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2 + #define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601 ++#define PCI_DEVICE_ID_INTEL_POULSBO_HC 0x8100 ++#define PCI_DEVICE_ID_INTEL_POULSBO_PE1 0x8110 ++#define PCI_DEVICE_ID_INTEL_POULSBO_PE2 0x8112 ++#define PCI_DEVICE_ID_INTEL_POULSBO_UC1 0x8114 ++#define PCI_DEVICE_ID_INTEL_POULSBO_UC2 0x8115 ++#define PCI_DEVICE_ID_INTEL_POULSBO_UC3 0x8116 ++#define PCI_DEVICE_ID_INTEL_POULSBO_EC 0x8117 ++#define PCI_DEVICE_ID_INTEL_POULSBO_UT 0x8118 ++#define PCI_DEVICE_ID_INTEL_POULSBO_LPC 0x8119 ++#define PCI_DEVICE_ID_INTEL_POULSBO_IDE 0x811a ++#define PCI_DEVICE_ID_INTEL_POULSBO_HDA 0x811b ++#define PCI_DEVICE_ID_INTEL_POULSBO_SD1 0x811c ++#define PCI_DEVICE_ID_INTEL_POULSBO_SD2 0x811d ++#define PCI_DEVICE_ID_INTEL_POULSBO_SD3 0x811e + #define PCI_DEVICE_ID_INTEL_82454GX 0x84c4 + #define PCI_DEVICE_ID_INTEL_82450GX 0x84c5 + #define PCI_DEVICE_ID_INTEL_82451NX 0x84ca +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0037-Netbook-LPIA-kernel-config.-New-ABI-19-bump.patch +++ linux-2.6.24/patches/0037-Netbook-LPIA-kernel-config.-New-ABI-19-bump.patch @@ -0,0 +1,311 @@ +From 0615ee99444d631bf58dcaee8e06af0a3833dd57 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Mon, 7 Jul 2008 12:39:38 +0100 +Subject: [PATCH 037/170] Netbook LPIA kernel config. New ABI-19 bump + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/binary-custom.d/lpia/config.lpia | 222 ++++--------------------------- + 1 files changed, 28 insertions(+), 194 deletions(-) + +diff --git a/debian/binary-custom.d/lpia/config.lpia b/debian/binary-custom.d/lpia/config.lpia +index 717717c..2cd1e76 100644 +--- a/debian/binary-custom.d/lpia/config.lpia ++++ b/debian/binary-custom.d/lpia/config.lpia +@@ -303,7 +303,11 @@ CONFIG_ACPI_SYSTEM=y + CONFIG_X86_PM_TIMER=y + CONFIG_ACPI_CONTAINER=y + CONFIG_ACPI_SBS=y ++CONFIG_SOUND=m ++# CONFIG_SOUND_PRIME is not set ++# CONFIG_SND is not set + # CONFIG_APM is not set ++CONFIG_HID_SUPPORT=y + + # + # CPU Frequency scaling +@@ -841,10 +845,10 @@ CONFIG_ALI_FIR=m + CONFIG_VLSI_FIR=m + CONFIG_VIA_FIR=m + CONFIG_MCS_FIR=m +-CONFIG_BT=y +-CONFIG_BT_L2CAP=y ++CONFIG_BT=m ++CONFIG_BT_L2CAP=m + CONFIG_BT_SCO=m +-CONFIG_BT_RFCOMM=y ++CONFIG_BT_RFCOMM=m + CONFIG_BT_RFCOMM_TTY=y + CONFIG_BT_BNEP=m + CONFIG_BT_BNEP_MC_FILTER=y +@@ -864,6 +868,10 @@ CONFIG_BT_HCIUART_LL=y + CONFIG_BT_HCIBCM203X=m + CONFIG_BT_HCIBPA10X=m + CONFIG_BT_HCIBFUSB=m ++CONFIG_BT_HCIDTL1=m ++CONFIG_BT_HCIBT3C=m ++CONFIG_BT_HCIBLUECARD=m ++CONFIG_BT_HCIBTUART=m + CONFIG_BT_HCIVHCI=m + CONFIG_AF_RXRPC=m + # CONFIG_AF_RXRPC_DEBUG is not set +@@ -1350,7 +1358,7 @@ CONFIG_PATA_SERVERWORKS=m + CONFIG_PATA_PDC2027X=m + CONFIG_PATA_SIL680=m + CONFIG_PATA_SIS=m +-# CONFIG_PATA_VIA is not set ++CONFIG_PATA_VIA=m + CONFIG_PATA_WINBOND=m + # CONFIG_PATA_PLATFORM is not set + CONFIG_MD=y +@@ -1902,7 +1910,7 @@ CONFIG_I2C_CHARDEV=m + # + # I2C Algorithms + # +-CONFIG_I2C_ALGOBIT=y ++CONFIG_I2C_ALGOBIT=m + CONFIG_I2C_ALGOPCF=m + CONFIG_I2C_ALGOPCA=m + +@@ -1918,7 +1926,7 @@ CONFIG_I2C_AMD8111=m + CONFIG_I2C_I801=m + CONFIG_I2C_I810=m + CONFIG_I2C_PIIX4=m +-CONFIG_I2C_POULSBO=y ++CONFIG_I2C_POULSBO=m + CONFIG_I2C_NFORCE2=m + CONFIG_I2C_OCORES=m + CONFIG_I2C_PARPORT=m +@@ -2427,7 +2435,7 @@ CONFIG_USB_DABUSB=m + # + # Graphics support + # +-CONFIG_AGP=y ++CONFIG_AGP=m + CONFIG_AGP_ALI=m + CONFIG_AGP_ATI=m + CONFIG_AGP_AMD=m +@@ -2438,7 +2446,17 @@ CONFIG_AGP_SIS=m + CONFIG_AGP_SWORKS=m + CONFIG_AGP_VIA=m + CONFIG_AGP_EFFICEON=m +-# CONFIG_DRM is not set ++CONFIG_DRM=m ++CONFIG_DRM_I810=m ++CONFIG_DRM_I830=m ++CONFIG_DRM_I915=m ++CONFIG_DRM_MGA=m ++CONFIG_DRM_R128=m ++CONFIG_DRM_RADEON=m ++CONFIG_DRM_SAVAGE=m ++CONFIG_DRM_SIS=m ++CONFIG_DRM_TDFX=m ++CONFIG_DRM_VIA=m + CONFIG_VGASTATE=m + CONFIG_VIDEO_OUTPUT_CONTROL=y + CONFIG_FB=y +@@ -2568,191 +2586,7 @@ CONFIG_FONT_8x8=y + CONFIG_FONT_8x16=y + # CONFIG_LOGO is not set + +-# +-# Sound +-# +-CONFIG_SOUND=y +- +-# +-# Advanced Linux Sound Architecture +-# +-CONFIG_SND=y +-CONFIG_SND_TIMER=y +-CONFIG_SND_PCM=y +-CONFIG_SND_HWDEP=y +-CONFIG_SND_RAWMIDI=m +-CONFIG_SND_SEQUENCER=y +-CONFIG_SND_SEQ_DUMMY=y +-CONFIG_SND_OSSEMUL=y +-CONFIG_SND_MIXER_OSS=y +-CONFIG_SND_PCM_OSS=y +-CONFIG_SND_PCM_OSS_PLUGINS=y +-CONFIG_SND_SEQUENCER_OSS=y +-CONFIG_SND_RTCTIMER=m +-CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y +-CONFIG_SND_DYNAMIC_MINORS=y +-CONFIG_SND_SUPPORT_OLD_API=y +-# CONFIG_SND_VERBOSE_PROCFS is not set +-# CONFIG_SND_VERBOSE_PRINTK is not set +-# CONFIG_SND_DEBUG is not set +- +-# +-# Generic devices +-# +-CONFIG_SND_MPU401_UART=m +-CONFIG_SND_OPL3_LIB=m +-CONFIG_SND_VX_LIB=m +-CONFIG_SND_AC97_CODEC=m +-CONFIG_SND_DUMMY=m +-CONFIG_SND_VIRMIDI=m +-CONFIG_SND_MTPAV=m +-CONFIG_SND_MTS64=m +-CONFIG_SND_SERIAL_U16550=m +-CONFIG_SND_MPU401=m +-CONFIG_SND_PORTMAN2X4=m +-CONFIG_SND_SB_COMMON=m +-CONFIG_SND_SB16_DSP=m +- +-# +-# PCI devices +-# +-CONFIG_SND_AD1889=m +-CONFIG_SND_ALS300=m +-CONFIG_SND_ALS4000=m +-CONFIG_SND_ALI5451=m +-CONFIG_SND_ATIIXP=m +-CONFIG_SND_ATIIXP_MODEM=m +-CONFIG_SND_AU8810=m +-CONFIG_SND_AU8820=m +-CONFIG_SND_AU8830=m +-CONFIG_SND_AZT3328=m +-CONFIG_SND_BT87X=m +-CONFIG_SND_BT87X_OVERCLOCK=y +-CONFIG_SND_CA0106=m +-CONFIG_SND_CMIPCI=m +-CONFIG_SND_CS4281=m +-CONFIG_SND_CS46XX=m +-CONFIG_SND_CS46XX_NEW_DSP=y +-CONFIG_SND_CS5530=m +-CONFIG_SND_CS5535AUDIO=m +-CONFIG_SND_DARLA20=m +-CONFIG_SND_GINA20=m +-CONFIG_SND_LAYLA20=m +-CONFIG_SND_DARLA24=m +-CONFIG_SND_GINA24=m +-CONFIG_SND_LAYLA24=m +-CONFIG_SND_MONA=m +-CONFIG_SND_MIA=m +-CONFIG_SND_ECHO3G=m +-CONFIG_SND_INDIGO=m +-CONFIG_SND_INDIGOIO=m +-CONFIG_SND_INDIGODJ=m +-CONFIG_SND_EMU10K1=m +-CONFIG_SND_EMU10K1X=m +-CONFIG_SND_ENS1370=m +-CONFIG_SND_ENS1371=m +-CONFIG_SND_ES1938=m +-CONFIG_SND_ES1968=m +-CONFIG_SND_FM801=m +-CONFIG_SND_FM801_TEA575X_BOOL=y +-CONFIG_SND_FM801_TEA575X=m +-CONFIG_SND_HDA_INTEL=y +-CONFIG_SND_HDA_HWDEP=y +-CONFIG_SND_HDA_CODEC_REALTEK=y +-CONFIG_SND_HDA_CODEC_ANALOG=y +-CONFIG_SND_HDA_CODEC_SIGMATEL=y +-CONFIG_SND_HDA_CODEC_VIA=y +-CONFIG_SND_HDA_CODEC_ATIHDMI=y +-CONFIG_SND_HDA_CODEC_CONEXANT=y +-CONFIG_SND_HDA_CODEC_CMEDIA=y +-CONFIG_SND_HDA_CODEC_SI3054=y +-CONFIG_SND_HDA_GENERIC=y +-CONFIG_SND_HDA_POWER_SAVE=y +-CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +-CONFIG_SND_HDSP=m +-CONFIG_SND_HDSPM=m +-CONFIG_SND_ICE1712=m +-CONFIG_SND_ICE1724=m +-CONFIG_SND_INTEL8X0=m +-CONFIG_SND_INTEL8X0M=m +-CONFIG_SND_KORG1212=m +-CONFIG_SND_KORG1212_FIRMWARE_IN_KERNEL=y +-CONFIG_SND_MAESTRO3=m +-CONFIG_SND_MAESTRO3_FIRMWARE_IN_KERNEL=y +-CONFIG_SND_MIXART=m +-CONFIG_SND_NM256=m +-CONFIG_SND_PCXHR=m +-CONFIG_SND_RIPTIDE=m +-CONFIG_SND_RME32=m +-CONFIG_SND_RME96=m +-CONFIG_SND_RME9652=m +-CONFIG_SND_SONICVIBES=m +-CONFIG_SND_TRIDENT=m +-CONFIG_SND_VIA82XX=m +-CONFIG_SND_VIA82XX_MODEM=m +-CONFIG_SND_VX222=m +-CONFIG_SND_YMFPCI=m +-CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y +-CONFIG_SND_AC97_POWER_SAVE=y +-CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 +- +-# +-# SPI devices +-# +- +-# +-# USB devices +-# +-CONFIG_SND_USB_AUDIO=m +-CONFIG_SND_USB_USX2Y=m +-CONFIG_SND_USB_CAIAQ=m +-CONFIG_SND_USB_CAIAQ_INPUT=y +- +-# +-# System on Chip audio support +-# +-CONFIG_SND_SOC=m +- +-# +-# SoC Audio support for SuperH +-# +- +-# +-# Open Sound System +-# +-CONFIG_SOUND_PRIME=m +-CONFIG_SOUND_TRIDENT=m +-CONFIG_SOUND_MSNDCLAS=m +-CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin" +-CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin" +-CONFIG_SOUND_MSNDPIN=m +-CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin" +-CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin" +-CONFIG_SOUND_OSS=m +-# CONFIG_SOUND_TRACEINIT is not set +-CONFIG_SOUND_DMAP=y +-CONFIG_SOUND_SSCAPE=m +-CONFIG_SOUND_VMIDI=m +-CONFIG_SOUND_TRIX=m +-CONFIG_SOUND_MSS=m +-CONFIG_SOUND_MPU401=m +-CONFIG_SOUND_PAS=m +-CONFIG_SOUND_PSS=m +-CONFIG_PSS_MIXER=y +-CONFIG_SOUND_SB=m +-CONFIG_SOUND_YM3812=m +-CONFIG_SOUND_UART6850=m +-CONFIG_SOUND_AEDSP16=m +-CONFIG_SC6600=y +-CONFIG_SC6600_JOY=y +-CONFIG_SC6600_CDROM=4 +-CONFIG_SC6600_CDROMBASE=0 +-CONFIG_AEDSP16_MSS=y +-# CONFIG_AEDSP16_SBPRO is not set +-CONFIG_SOUND_KAHLUA=m +-CONFIG_AC97_BUS=m +-CONFIG_HID_SUPPORT=y +-CONFIG_HID=y ++CONFIG_HID=m + # CONFIG_HID_DEBUG is not set + CONFIG_HIDRAW=y + +@@ -3092,7 +2926,7 @@ CONFIG_UIO_CIF=m + # CONFIG_EDD is not set + CONFIG_EFI_VARS=y + # CONFIG_DELL_RBU is not set +-# CONFIG_DCDBAS is not set ++CONFIG_DCDBAS=m + CONFIG_DMIID=y + + # +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0052-Build-ehci_hcd-as-a-module.patch +++ linux-2.6.24/patches/0052-Build-ehci_hcd-as-a-module.patch @@ -0,0 +1,26 @@ +From 5ba768369a5fde000c7cbc4957ea4f5ce4ecd9e0 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 27 Aug 2008 11:07:34 -0400 +Subject: [PATCH 052/170] Build ehci_hcd as a module + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/binary-custom.d/lpia/config.lpia | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/debian/binary-custom.d/lpia/config.lpia b/debian/binary-custom.d/lpia/config.lpia +index 70e3ca9..18fa3ca 100644 +--- a/debian/binary-custom.d/lpia/config.lpia ++++ b/debian/binary-custom.d/lpia/config.lpia +@@ -2617,7 +2617,7 @@ CONFIG_USB_PERSIST=y + # + # USB Host Controller Drivers + # +-CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_EHCI_HCD=m + CONFIG_USB_EHCI_SPLIT_ISO=y + CONFIG_USB_EHCI_ROOT_HUB_TT=y + CONFIG_USB_EHCI_TT_NEWSCHED=y +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0033-kgdb-powerpc-ppc-arch-specific-ppc-and-powerpc-kgdb-.patch +++ linux-2.6.24/patches/0033-kgdb-powerpc-ppc-arch-specific-ppc-and-powerpc-kgdb-.patch @@ -0,0 +1,3346 @@ +From 315a5aa807149c2ebb1fb9a1c7454620f1a103d3 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:48 -0500 +Subject: [PATCH 033/170] kgdb, powerpc, ppc: arch specific ppc and powerpc kgdb support + +This patch removes the old style kgdb support from arch=ppc and +implements the new style arch specific stub for the common kgdb core +interface. The patch also provides the powerpc archtecture specific +implementation for the common kgdb core interface. + +The arch=ppc rs232 handlers required changes for some boards so as to +allow for early debugging prior to the console being initialized. + +It is possible to have xmon and kgdb in the same kernel, but you +cannot use both at the same time because there is only one set of +debug hooks. + +The arch specific kgdb implementation saves the previous state of the +debug hooks and restores them if you unconfigure the kgdb I/O driver. +Kgdb should have no impact on a kernel that has no kgdb I/O driver +configured. + +Signed-off-by: Jason Wessel +--- + arch/powerpc/Kconfig | 1 + + arch/powerpc/Kconfig.debug | 50 +-- + arch/powerpc/kernel/Makefile | 1 + + arch/powerpc/kernel/kgdb.c | 410 +++++++++++++++ + arch/powerpc/kernel/legacy_serial.c | 6 + + arch/powerpc/kernel/setup_32.c | 16 - + arch/powerpc/mm/fault.c | 1 + + arch/powerpc/platforms/powermac/setup.c | 6 - + arch/powerpc/sysdev/mv64x60_dev.c | 8 + + arch/ppc/Kconfig | 1 + + arch/ppc/Kconfig.debug | 36 -- + arch/ppc/kernel/Makefile | 2 +- + arch/ppc/kernel/kgdb.c | 373 +++++++++++++ + arch/ppc/kernel/ppc-stub.c | 866 ------------------------------- + arch/ppc/kernel/setup.c | 16 - + arch/ppc/mm/fault.c | 1 + + arch/ppc/platforms/4xx/bamboo.c | 23 +- + arch/ppc/platforms/4xx/bubinga.c | 30 +- + arch/ppc/platforms/4xx/ebony.c | 33 +- + arch/ppc/platforms/4xx/luan.c | 16 +- + arch/ppc/platforms/4xx/ocotea.c | 32 +- + arch/ppc/platforms/4xx/taishan.c | 7 +- + arch/ppc/platforms/4xx/xilinx_ml300.c | 5 +- + arch/ppc/platforms/4xx/xilinx_ml403.c | 3 - + arch/ppc/platforms/4xx/yucca.c | 3 - + arch/ppc/platforms/chestnut.c | 7 +- + arch/ppc/platforms/ev64260.c | 12 +- + arch/ppc/platforms/hdpu.c | 19 - + arch/ppc/platforms/pplus.c | 5 +- + arch/ppc/platforms/radstone_ppc7d.c | 12 +- + arch/ppc/platforms/sandpoint.c | 5 +- + arch/ppc/platforms/spruce.c | 30 +- + arch/ppc/syslib/Makefile | 1 - + arch/ppc/syslib/gen550.h | 1 - + arch/ppc/syslib/gen550_kgdb.c | 83 --- + arch/ppc/syslib/ibm44x_common.c | 3 - + arch/ppc/syslib/mv64x60.c | 62 ++- + arch/ppc/syslib/mv64x60_dbg.c | 52 +-- + arch/ppc/syslib/ppc4xx_setup.c | 1 - + include/asm-powerpc/kgdb.h | 92 ++-- + include/asm-ppc/kgdb.h | 59 +-- + include/asm-ppc/machdep.h | 2 - + include/asm-ppc/mv64x60.h | 2 + + include/asm-ppc/mv64x60_defs.h | 3 +- + 44 files changed, 1062 insertions(+), 1335 deletions(-) + create mode 100644 arch/powerpc/kernel/kgdb.c + create mode 100644 arch/ppc/kernel/kgdb.c + delete mode 100644 arch/ppc/kernel/ppc-stub.c + delete mode 100644 arch/ppc/syslib/gen550_kgdb.c + +diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig +index 232c298..bc0f6b3 100644 +--- a/arch/powerpc/Kconfig ++++ b/arch/powerpc/Kconfig +@@ -78,6 +78,7 @@ config ARCH_NO_VIRT_TO_BUS + + config PPC + bool ++ select HAVE_ARCH_KGDB + default y + + config EARLY_PRINTK +diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug +index 6a79fe4..f963ebb 100644 +--- a/arch/powerpc/Kconfig.debug ++++ b/arch/powerpc/Kconfig.debug +@@ -41,52 +41,9 @@ config HCALL_STATS + This option will add a small amount of overhead to all hypervisor + calls. + +-config DEBUGGER +- bool "Enable debugger hooks" +- depends on DEBUG_KERNEL +- help +- Include in-kernel hooks for kernel debuggers. Unless you are +- intending to debug the kernel, say N here. +- +-config KGDB +- bool "Include kgdb kernel debugger" +- depends on DEBUGGER && (BROKEN || PPC_GEN550 || 4xx) +- select DEBUG_INFO +- help +- Include in-kernel hooks for kgdb, the Linux kernel source level +- debugger. See for more information. +- Unless you are intending to debug the kernel, say N here. +- +-choice +- prompt "Serial Port" +- depends on KGDB +- default KGDB_TTYS1 +- +-config KGDB_TTYS0 +- bool "ttyS0" +- +-config KGDB_TTYS1 +- bool "ttyS1" +- +-config KGDB_TTYS2 +- bool "ttyS2" +- +-config KGDB_TTYS3 +- bool "ttyS3" +- +-endchoice +- +-config KGDB_CONSOLE +- bool "Enable serial console thru kgdb port" +- depends on KGDB && 8xx || CPM2 +- help +- If you enable this, all serial console messages will be sent +- over the gdb stub. +- If unsure, say N. +- + config XMON + bool "Include xmon kernel debugger" +- depends on DEBUGGER ++ depends on DEBUG_KERNEL + help + Include in-kernel hooks for the xmon kernel monitor/debugger. + Unless you are intending to debug the kernel, say N here. +@@ -116,6 +73,11 @@ config XMON_DISASSEMBLY + to say Y here, unless you're building for a memory-constrained + system. + ++config DEBUGGER ++ bool ++ depends on KGDB || XMON ++ default y ++ + config IRQSTACKS + bool "Use separate kernel stacks when processing interrupts" + depends on PPC64 +diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile +index ca51f0c..8ee65b5 100644 +--- a/arch/powerpc/kernel/Makefile ++++ b/arch/powerpc/kernel/Makefile +@@ -59,6 +59,7 @@ obj-y += time.o prom.o traps.o setup-common.o \ + misc_$(CONFIG_WORD_SIZE).o + obj-$(CONFIG_PPC32) += entry_32.o setup_32.o + obj-$(CONFIG_PPC64) += dma_64.o iommu.o ++obj-$(CONFIG_KGDB) += kgdb.o + obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o + obj-$(CONFIG_MODULES) += ppc_ksyms.o + obj-$(CONFIG_BOOTX_TEXT) += btext.o +diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c +new file mode 100644 +index 0000000..b2f0f53 +--- /dev/null ++++ b/arch/powerpc/kernel/kgdb.c +@@ -0,0 +1,410 @@ ++/* ++ * PowerPC backend to the KGDB stub. ++ * ++ * 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu) ++ * Copyright (C) 2003 Timesys Corporation. ++ * Copyright (C) 2004-2006 MontaVista Software, Inc. ++ * PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com) ++ * PPC32 support restored by Vitaly Wool and ++ * Sergei Shtylyov ++ * Copyright (C) 2007-2008 Wind River Systems, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program as licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * This table contains the mapping between PowerPC hardware trap types, and ++ * signals, which are primarily what GDB understands. GDB and the kernel ++ * don't always agree on values, so we use constants taken from gdb-6.2. ++ */ ++static struct hard_trap_info ++{ ++ unsigned int tt; /* Trap type code for powerpc */ ++ unsigned char signo; /* Signal that we map this trap into */ ++} hard_trap_info[] = { ++ { 0x0100, 0x02 /* SIGINT */ }, /* system reset */ ++ { 0x0200, 0x0b /* SIGSEGV */ }, /* machine check */ ++ { 0x0300, 0x0b /* SIGSEGV */ }, /* data access */ ++ { 0x0400, 0x0b /* SIGSEGV */ }, /* instruction access */ ++ { 0x0500, 0x02 /* SIGINT */ }, /* external interrupt */ ++ { 0x0600, 0x0a /* SIGBUS */ }, /* alignment */ ++ { 0x0700, 0x05 /* SIGTRAP */ }, /* program check */ ++ { 0x0800, 0x08 /* SIGFPE */ }, /* fp unavailable */ ++ { 0x0900, 0x0e /* SIGALRM */ }, /* decrementer */ ++ { 0x0c00, 0x14 /* SIGCHLD */ }, /* system call */ ++#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) ++ { 0x2002, 0x05 /* SIGTRAP */ }, /* debug */ ++#if defined(CONFIG_FSL_BOOKE) ++ { 0x2010, 0x08 /* SIGFPE */ }, /* spe unavailable */ ++ { 0x2020, 0x08 /* SIGFPE */ }, /* spe unavailable */ ++ { 0x2030, 0x08 /* SIGFPE */ }, /* spe fp data */ ++ { 0x2040, 0x08 /* SIGFPE */ }, /* spe fp data */ ++ { 0x2050, 0x08 /* SIGFPE */ }, /* spe fp round */ ++ { 0x2060, 0x0e /* SIGILL */ }, /* performace monitor */ ++ { 0x2900, 0x08 /* SIGFPE */ }, /* apu unavailable */ ++ { 0x3100, 0x0e /* SIGALRM */ }, /* fixed interval timer */ ++ { 0x3200, 0x02 /* SIGINT */ }, /* watchdog */ ++#else /* ! CONFIG_FSL_BOOKE */ ++ { 0x1000, 0x0e /* SIGALRM */ }, /* prog interval timer */ ++ { 0x1010, 0x0e /* SIGALRM */ }, /* fixed interval timer */ ++ { 0x1020, 0x02 /* SIGINT */ }, /* watchdog */ ++ { 0x2010, 0x08 /* SIGFPE */ }, /* fp unavailable */ ++ { 0x2020, 0x08 /* SIGFPE */ }, /* ap unavailable */ ++#endif ++#else /* ! (defined(CONFIG_40x) || defined(CONFIG_BOOKE)) */ ++ { 0x0d00, 0x05 /* SIGTRAP */ }, /* single-step */ ++#if defined(CONFIG_8xx) ++ { 0x1000, 0x04 /* SIGILL */ }, /* software emulation */ ++#else /* ! CONFIG_8xx */ ++ { 0x0f00, 0x04 /* SIGILL */ }, /* performance monitor */ ++ { 0x0f20, 0x08 /* SIGFPE */ }, /* altivec unavailable */ ++ { 0x1300, 0x05 /* SIGTRAP */ }, /* instruction address break */ ++#if defined(CONFIG_PPC64) ++ { 0x1200, 0x05 /* SIGILL */ }, /* system error */ ++ { 0x1500, 0x04 /* SIGILL */ }, /* soft patch */ ++ { 0x1600, 0x04 /* SIGILL */ }, /* maintenance */ ++ { 0x1700, 0x08 /* SIGFPE */ }, /* altivec assist */ ++ { 0x1800, 0x04 /* SIGILL */ }, /* thermal */ ++#else /* ! CONFIG_PPC64 */ ++ { 0x1400, 0x02 /* SIGINT */ }, /* SMI */ ++ { 0x1600, 0x08 /* SIGFPE */ }, /* altivec assist */ ++ { 0x1700, 0x04 /* SIGILL */ }, /* TAU */ ++ { 0x2000, 0x05 /* SIGTRAP */ }, /* run mode */ ++#endif ++#endif ++#endif ++ { 0x0000, 0x00 } /* Must be last */ ++}; ++ ++static int computeSignal(unsigned int tt) ++{ ++ struct hard_trap_info *ht; ++ ++ for (ht = hard_trap_info; ht->tt && ht->signo; ht++) ++ if (ht->tt == tt) ++ return ht->signo; ++ ++ return SIGHUP; /* default for things we don't know about */ ++} ++ ++static int kgdb_call_nmi_hook(struct pt_regs *regs) ++{ ++ kgdb_nmicallback(raw_smp_processor_id(), regs); ++ return 0; ++} ++ ++#ifdef CONFIG_SMP ++void kgdb_roundup_cpus(unsigned long flags) ++{ ++ smp_send_debugger_break(MSG_ALL_BUT_SELF); ++} ++#endif ++ ++/* KGDB functions to use existing PowerPC64 hooks. */ ++static int kgdb_debugger(struct pt_regs *regs) ++{ ++ return kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); ++} ++ ++static int kgdb_handle_breakpoint(struct pt_regs *regs) ++{ ++ if (user_mode(regs)) ++ return 0; ++ ++ if (kgdb_handle_exception(0, SIGTRAP, 0, regs) != 0) ++ return 0; ++ ++ if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) ++ regs->nip += 4; ++ ++ return 1; ++} ++ ++static int kgdb_singlestep(struct pt_regs *regs) ++{ ++ struct thread_info *thread_info, *exception_thread_info; ++ ++ if (user_mode(regs)) ++ return 0; ++ ++ /* ++ * On Book E and perhaps other processsors, singlestep is handled on ++ * the critical exception stack. This causes current_thread_info() ++ * to fail, since it it locates the thread_info by masking off ++ * the low bits of the current stack pointer. We work around ++ * this issue by copying the thread_info from the kernel stack ++ * before calling kgdb_handle_exception, and copying it back ++ * afterwards. On most processors the copy is avoided since ++ * exception_thread_info == thread_info. ++ */ ++ thread_info = (struct thread_info *)(regs->gpr[1] & ~(THREAD_SIZE-1)); ++ exception_thread_info = current_thread_info(); ++ ++ if (thread_info != exception_thread_info) ++ memcpy(exception_thread_info, thread_info, sizeof *thread_info); ++ ++ kgdb_handle_exception(0, SIGTRAP, 0, regs); ++ ++ if (thread_info != exception_thread_info) ++ memcpy(thread_info, exception_thread_info, sizeof *thread_info); ++ ++ return 1; ++} ++ ++int kgdb_iabr_match(struct pt_regs *regs) ++{ ++ if (user_mode(regs)) ++ return 0; ++ ++ if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0) ++ return 0; ++ return 1; ++} ++ ++int kgdb_dabr_match(struct pt_regs *regs) ++{ ++ if (user_mode(regs)) ++ return 0; ++ ++ if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0) ++ return 0; ++ return 1; ++} ++ ++#define PACK64(ptr, src) do { *(ptr++) = (src); } while (0) ++ ++#define PACK32(ptr, src) do { \ ++ u32 *ptr32; \ ++ ptr32 = (u32 *)ptr; \ ++ *(ptr32++) = (src); \ ++ ptr = (unsigned long *)ptr32; \ ++ } while (0) ++ ++ ++void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) ++{ ++ unsigned long *ptr = gdb_regs; ++ int reg; ++ ++ memset(gdb_regs, 0, NUMREGBYTES); ++ ++ for (reg = 0; reg < 32; reg++) ++ PACK64(ptr, regs->gpr[reg]); ++ ++#ifdef CONFIG_FSL_BOOKE ++#ifdef CONFIG_SPE ++ for (reg = 0; reg < 32; reg++) ++ PACK64(ptr, current->thread.evr[reg]); ++#else ++ ptr += 32; ++#endif ++#else ++ /* fp registers not used by kernel, leave zero */ ++ ptr += 32 * 8 / sizeof(long); ++#endif ++ ++ PACK64(ptr, regs->nip); ++ PACK64(ptr, regs->msr); ++ PACK32(ptr, regs->ccr); ++ PACK64(ptr, regs->link); ++ PACK64(ptr, regs->ctr); ++ PACK32(ptr, regs->xer); ++ ++ BUG_ON((unsigned long)ptr > ++ (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); ++} ++ ++void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) ++{ ++ struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp + ++ STACK_FRAME_OVERHEAD); ++ unsigned long *ptr = gdb_regs; ++ int reg; ++ ++ memset(gdb_regs, 0, NUMREGBYTES); ++ ++ /* Regs GPR0-2 */ ++ for (reg = 0; reg < 3; reg++) ++ PACK64(ptr, regs->gpr[reg]); ++ ++ /* Regs GPR3-13 are caller saved, not in regs->gpr[] */ ++ ptr += 11; ++ ++ /* Regs GPR14-31 */ ++ for (reg = 14; reg < 32; reg++) ++ PACK64(ptr, regs->gpr[reg]); ++ ++#ifdef CONFIG_FSL_BOOKE ++#ifdef CONFIG_SPE ++ for (reg = 0; reg < 32; reg++) ++ PACK64(ptr, p->thread.evr[reg]); ++#else ++ ptr += 32; ++#endif ++#else ++ /* fp registers not used by kernel, leave zero */ ++ ptr += 32 * 8 / sizeof(long); ++#endif ++ ++ PACK64(ptr, regs->nip); ++ PACK64(ptr, regs->msr); ++ PACK32(ptr, regs->ccr); ++ PACK64(ptr, regs->link); ++ PACK64(ptr, regs->ctr); ++ PACK32(ptr, regs->xer); ++ ++ BUG_ON((unsigned long)ptr > ++ (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); ++} ++ ++#define UNPACK64(dest, ptr) do { dest = *(ptr++); } while (0) ++ ++#define UNPACK32(dest, ptr) do { \ ++ u32 *ptr32; \ ++ ptr32 = (u32 *)ptr; \ ++ dest = *(ptr32++); \ ++ ptr = (unsigned long *)ptr32; \ ++ } while (0) ++ ++void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) ++{ ++ unsigned long *ptr = gdb_regs; ++ int reg; ++#ifdef CONFIG_SPE ++ union { ++ u32 v32[2]; ++ u64 v64; ++ } acc; ++#endif ++ ++ for (reg = 0; reg < 32; reg++) ++ UNPACK64(regs->gpr[reg], ptr); ++ ++#ifdef CONFIG_FSL_BOOKE ++#ifdef CONFIG_SPE ++ for (reg = 0; reg < 32; reg++) ++ UNPACK64(current->thread.evr[reg], ptr); ++#else ++ ptr += 32; ++#endif ++#else ++ /* fp registers not used by kernel, leave zero */ ++ ptr += 32 * 8 / sizeof(int); ++#endif ++ ++ UNPACK64(regs->nip, ptr); ++ UNPACK64(regs->msr, ptr); ++ UNPACK32(regs->ccr, ptr); ++ UNPACK64(regs->link, ptr); ++ UNPACK64(regs->ctr, ptr); ++ UNPACK32(regs->xer, ptr); ++ ++ BUG_ON((unsigned long)ptr > ++ (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); ++} ++ ++/* ++ * This function does PowerPC specific procesing for interfacing to gdb. ++ */ ++int kgdb_arch_handle_exception(int vector, int signo, int err_code, ++ char *remcom_in_buffer, char *remcom_out_buffer, ++ struct pt_regs *linux_regs) ++{ ++ char *ptr = &remcom_in_buffer[1]; ++ unsigned long addr; ++ ++ switch (remcom_in_buffer[0]) { ++ /* ++ * sAA..AA Step one instruction from AA..AA ++ * This will return an error to gdb .. ++ */ ++ case 's': ++ case 'c': ++ /* handle the optional parameter */ ++ if (kgdb_hex2long(&ptr, &addr)) ++ linux_regs->nip = addr; ++ ++ atomic_set(&kgdb_cpu_doing_single_step, -1); ++ /* set the trace bit if we're stepping */ ++ if (remcom_in_buffer[0] == 's') { ++#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) ++ mtspr(SPRN_DBCR0, ++ mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM); ++ linux_regs->msr |= MSR_DE; ++#else ++ linux_regs->msr |= MSR_SE; ++#endif ++ kgdb_single_step = 1; ++ if (kgdb_contthread) ++ atomic_set(&kgdb_cpu_doing_single_step, ++ raw_smp_processor_id()); ++ } ++ return 0; ++ } ++ ++ return -1; ++} ++ ++/* ++ * Global data ++ */ ++struct kgdb_arch arch_kgdb_ops = { ++ .gdb_bpt_instr = {0x7d, 0x82, 0x10, 0x08}, ++}; ++ ++int kgdb_not_implemented(struct pt_regs *regs) ++{ ++ return 0; ++} ++ ++static void *old__debugger_ipi; ++static void *old__debugger; ++static void *old__debugger_bpt; ++static void *old__debugger_sstep; ++static void *old__debugger_iabr_match; ++static void *old__debugger_dabr_match; ++static void *old__debugger_fault_handler; ++ ++int kgdb_arch_init(void) ++{ ++ old__debugger_ipi = __debugger_ipi; ++ old__debugger = __debugger; ++ old__debugger_bpt = __debugger_bpt; ++ old__debugger_sstep = __debugger_sstep; ++ old__debugger_iabr_match = __debugger_iabr_match; ++ old__debugger_dabr_match = __debugger_dabr_match; ++ old__debugger_fault_handler = __debugger_fault_handler; ++ ++ __debugger_ipi = kgdb_call_nmi_hook; ++ __debugger = kgdb_debugger; ++ __debugger_bpt = kgdb_handle_breakpoint; ++ __debugger_sstep = kgdb_singlestep; ++ __debugger_iabr_match = kgdb_iabr_match; ++ __debugger_dabr_match = kgdb_dabr_match; ++ __debugger_fault_handler = kgdb_not_implemented; ++ ++ return 0; ++} ++ ++void kgdb_arch_exit(void) ++{ ++ __debugger_ipi = old__debugger_ipi; ++ __debugger = old__debugger; ++ __debugger_bpt = old__debugger_bpt; ++ __debugger_sstep = old__debugger_sstep; ++ __debugger_iabr_match = old__debugger_iabr_match; ++ __debugger_dabr_match = old__debugger_dabr_match; ++ __debugger_fault_handler = old__debugger_fault_handler; ++} +diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c +index 4ed5887..d4cf111 100644 +--- a/arch/powerpc/kernel/legacy_serial.c ++++ b/arch/powerpc/kernel/legacy_serial.c +@@ -11,6 +11,9 @@ + #include + #include + #include ++#ifdef CONFIG_KGDB_8250 ++#include ++#endif + + #undef DEBUG + +@@ -488,6 +491,9 @@ static int __init serial_dev_init(void) + fixup_port_pio(i, np, port); + if ((port->iotype == UPIO_MEM) || (port->iotype == UPIO_TSI)) + fixup_port_mmio(i, np, port); ++#ifdef CONFIG_KGDB_8250_HACK_HACK_HACK ++ kgdb8250_add_platform_port(i, port); ++#endif + } + + DBG("Registering platform serial ports\n"); +diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c +index cd870a8..1aad3c0 100644 +--- a/arch/powerpc/kernel/setup_32.c ++++ b/arch/powerpc/kernel/setup_32.c +@@ -45,10 +45,6 @@ + + #define DBG(fmt...) + +-#if defined CONFIG_KGDB +-#include +-#endif +- + extern void bootx_init(unsigned long r4, unsigned long phys); + + #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +@@ -248,18 +244,6 @@ void __init setup_arch(char **cmdline_p) + + xmon_setup(); + +-#if defined(CONFIG_KGDB) +- if (ppc_md.kgdb_map_scc) +- ppc_md.kgdb_map_scc(); +- set_debug_traps(); +- if (strstr(cmd_line, "gdb")) { +- if (ppc_md.progress) +- ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000); +- printk("kgdb breakpoint activated\n"); +- breakpoint(); +- } +-#endif +- + /* + * Set cache line size based on type of cpu as a default. + * Systems with OF can look in the properties on the cpu node(s) +diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c +index 8135da0..b5feebd 100644 +--- a/arch/powerpc/mm/fault.c ++++ b/arch/powerpc/mm/fault.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + #include + #include +diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c +index 209478b..e73626c 100644 +--- a/arch/powerpc/platforms/powermac/setup.c ++++ b/arch/powerpc/platforms/powermac/setup.c +@@ -98,8 +98,6 @@ extern struct machdep_calls pmac_md; + int sccdbg; + #endif + +-extern void zs_kgdb_hook(int tty_num); +- + sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN; + EXPORT_SYMBOL(sys_ctrler); + +@@ -330,10 +328,6 @@ static void __init pmac_setup_arch(void) + l2cr_init(); + #endif /* CONFIG_PPC32 */ + +-#ifdef CONFIG_KGDB +- zs_kgdb_hook(0); +-#endif +- + find_via_cuda(); + find_via_pmu(); + smu_init(); +diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c +index 548a320..54acc07 100644 +--- a/arch/powerpc/sysdev/mv64x60_dev.c ++++ b/arch/powerpc/sysdev/mv64x60_dev.c +@@ -30,6 +30,7 @@ + */ + static int __init mv64x60_mpsc_register_shared_pdev(struct device_node *np) + { ++ extern void kgdbmpsc_set_shared_dev(struct platform_device *); + struct platform_device *pdev; + struct resource r[2]; + struct mpsc_shared_pdata pdata; +@@ -75,6 +76,9 @@ static int __init mv64x60_mpsc_register_shared_pdev(struct device_node *np) + if (err) + goto error; + ++#ifdef CONFIG_KGDB_MPSC ++ kgdbmpsc_set_shared_dev(pdev); ++#endif + return 0; + + error: +@@ -85,6 +89,7 @@ error: + + static int __init mv64x60_mpsc_device_setup(struct device_node *np, int id) + { ++ extern void kgdbmpsc_set_mpsc_dev(struct platform_device *, int); + struct resource r[5]; + struct mpsc_pdata pdata; + struct platform_device *pdev; +@@ -195,6 +200,9 @@ static int __init mv64x60_mpsc_device_setup(struct device_node *np, int id) + if (err) + goto error; + ++#ifdef CONFIG_KGDB_MPSC ++ kgdbmpsc_set_mpsc_dev(pdev, id); ++#endif + return 0; + + error: +diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig +index 6473fa7..b0be5af 100644 +--- a/arch/ppc/Kconfig ++++ b/arch/ppc/Kconfig +@@ -41,6 +41,7 @@ config GENERIC_CALIBRATE_DELAY + + config PPC + bool ++ select HAVE_ARCH_KGDB + default y + + config PPC32 +diff --git a/arch/ppc/Kconfig.debug b/arch/ppc/Kconfig.debug +index f94b877..0a74eea 100644 +--- a/arch/ppc/Kconfig.debug ++++ b/arch/ppc/Kconfig.debug +@@ -2,42 +2,6 @@ menu "Kernel hacking" + + source "lib/Kconfig.debug" + +-config KGDB +- bool "Include kgdb kernel debugger" +- depends on DEBUG_KERNEL && (BROKEN || PPC_GEN550 || 4xx) +- select DEBUG_INFO +- help +- Include in-kernel hooks for kgdb, the Linux kernel source level +- debugger. See for more information. +- Unless you are intending to debug the kernel, say N here. +- +-choice +- prompt "Serial Port" +- depends on KGDB +- default KGDB_TTYS1 +- +-config KGDB_TTYS0 +- bool "ttyS0" +- +-config KGDB_TTYS1 +- bool "ttyS1" +- +-config KGDB_TTYS2 +- bool "ttyS2" +- +-config KGDB_TTYS3 +- bool "ttyS3" +- +-endchoice +- +-config KGDB_CONSOLE +- bool "Enable serial console thru kgdb port" +- depends on KGDB && 8xx || CPM2 +- help +- If you enable this, all serial console messages will be sent +- over the gdb stub. +- If unsure, say N. +- + config XMON + bool "Include xmon kernel debugger" + depends on DEBUG_KERNEL +diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile +index 6b4f022..da61193 100644 +--- a/arch/ppc/kernel/Makefile ++++ b/arch/ppc/kernel/Makefile +@@ -14,7 +14,7 @@ obj-y := entry.o traps.o time.o misc.o \ + obj-$(CONFIG_MODULES) += ppc_ksyms.o + obj-$(CONFIG_PCI) += pci.o + obj-$(CONFIG_RAPIDIO) += rio.o +-obj-$(CONFIG_KGDB) += ppc-stub.o ++obj-$(CONFIG_KGDB) += kgdb.o + obj-$(CONFIG_SMP) += smp.o smp-tbsync.o + obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o + +diff --git a/arch/ppc/kernel/kgdb.c b/arch/ppc/kernel/kgdb.c +new file mode 100644 +index 0000000..ba6d264 +--- /dev/null ++++ b/arch/ppc/kernel/kgdb.c +@@ -0,0 +1,373 @@ ++/* ++ * arch/ppc/kernel/kgdb.c ++ * ++ * PowerPC backend to the KGDB stub. ++ * ++ * Maintainer: Tom Rini ++ * ++ * 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu) ++ * Copyright (C) 2003 Timesys Corporation. ++ * Copyright (C) 2004, 2006 MontaVista Software, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program as licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * This table contains the mapping between PowerPC hardware trap types, and ++ * signals, which are primarily what GDB understands. GDB and the kernel ++ * don't always agree on values, so we use constants taken from gdb-6.2. ++ */ ++static struct hard_trap_info ++{ ++ unsigned int tt; /* Trap type code for powerpc */ ++ unsigned char signo; /* Signal that we map this trap into */ ++} hard_trap_info[] = { ++ { 0x0100, 0x02 /* SIGINT */ }, /* system reset */ ++ { 0x0200, 0x0b /* SIGSEGV */ }, /* machine check */ ++ { 0x0300, 0x0b /* SIGSEGV */ }, /* data access */ ++ { 0x0400, 0x0b /* SIGSEGV */ }, /* instruction access */ ++ { 0x0500, 0x02 /* SIGINT */ }, /* external interrupt */ ++ { 0x0600, 0x0a /* SIGBUS */ }, /* alignment */ ++ { 0x0700, 0x05 /* SIGTRAP */ }, /* program check */ ++ { 0x0800, 0x08 /* SIGFPE */ }, /* fp unavailable */ ++ { 0x0900, 0x0e /* SIGALRM */ }, /* decrementer */ ++ { 0x0c00, 0x14 /* SIGCHLD */ }, /* system call */ ++#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) ++ { 0x2002, 0x05 /* SIGTRAP */ }, /* debug */ ++#if defined(CONFIG_FSL_BOOKE) ++ { 0x2010, 0x08 /* SIGFPE */ }, /* spe unavailable */ ++ { 0x2020, 0x08 /* SIGFPE */ }, /* spe unavailable */ ++ { 0x2030, 0x08 /* SIGFPE */ }, /* spe fp data */ ++ { 0x2040, 0x08 /* SIGFPE */ }, /* spe fp data */ ++ { 0x2050, 0x08 /* SIGFPE */ }, /* spe fp round */ ++ { 0x2060, 0x0e /* SIGILL */ }, /* performace monitor */ ++ { 0x2900, 0x08 /* SIGFPE */ }, /* apu unavailable */ ++ { 0x3100, 0x0e /* SIGALRM */ }, /* fixed interval timer */ ++ { 0x3200, 0x02 /* SIGINT */ }, /* watchdog */ ++#else /* ! CONFIG_FSL_BOOKE */ ++ { 0x1000, 0x0e /* SIGALRM */ }, /* prog interval timer */ ++ { 0x1010, 0x0e /* SIGALRM */ }, /* fixed interval timer */ ++ { 0x1020, 0x02 /* SIGINT */ }, /* watchdog */ ++ { 0x2010, 0x08 /* SIGFPE */ }, /* fp unavailable */ ++ { 0x2020, 0x08 /* SIGFPE */ }, /* ap unavailable */ ++#endif ++#else /* ! (defined(CONFIG_40x) || defined(CONFIG_BOOKE)) */ ++ { 0x0d00, 0x05 /* SIGTRAP */ }, /* single-step */ ++#if defined(CONFIG_8xx) ++ { 0x1000, 0x04 /* SIGILL */ }, /* software emulation */ ++#else /* ! CONFIG_8xx */ ++ { 0x0f00, 0x04 /* SIGILL */ }, /* performance monitor */ ++ { 0x0f20, 0x08 /* SIGFPE */ }, /* altivec unavailable */ ++ { 0x1300, 0x05 /* SIGTRAP */ }, /* instruction address break */ ++ { 0x1400, 0x02 /* SIGINT */ }, /* SMI */ ++ { 0x1600, 0x08 /* SIGFPE */ }, /* altivec assist */ ++ { 0x1700, 0x04 /* SIGILL */ }, /* TAU */ ++ { 0x2000, 0x05 /* SIGTRAP */ }, /* run mode */ ++#endif ++#endif ++ { 0x0000, 0x00 } /* Must be last */ ++}; ++ ++static int computeSignal(unsigned int tt) ++{ ++ struct hard_trap_info *ht; ++ ++ for (ht = hard_trap_info; ht->tt && ht->signo; ht++) ++ if (ht->tt == tt) ++ return ht->signo; ++ ++ return SIGHUP; /* default for things we don't know about */ ++} ++ ++/* KGDB functions to use existing PowerPC hooks. */ ++static void kgdb_debugger(struct pt_regs *regs) ++{ ++ kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); ++} ++ ++static int kgdb_handle_breakpoint(struct pt_regs *regs) ++{ ++ if (user_mode(regs)) ++ return 0; ++ ++ if (kgdb_handle_exception(0, SIGTRAP, 0, regs) != 0) ++ return 0; ++ ++ if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) ++ regs->nip += 4; ++ ++ return 1; ++} ++ ++static int kgdb_singlestep(struct pt_regs *regs) ++{ ++ struct thread_info *thread_info, *exception_thread_info; ++ ++ if (user_mode(regs)) ++ return 0; ++ /* ++ * On Book E and perhaps other processsors, singlestep is handled on ++ * the critical exception stack. This causes current_thread_info() ++ * to fail, since it it locates the thread_info by masking off ++ * the low bits of the current stack pointer. We work around ++ * this issue by copying the thread_info from the kernel stack ++ * before calling kgdb_handle_exception, and copying it back ++ * afterwards. On most processors the copy is avoided since ++ * exception_thread_info == thread_info. ++ */ ++ thread_info = (struct thread_info *)(regs->gpr[1] & ~(THREAD_SIZE-1)); ++ exception_thread_info = current_thread_info(); ++ ++ if (thread_info != exception_thread_info) ++ memcpy(exception_thread_info, thread_info, sizeof *thread_info); ++ ++ kgdb_handle_exception(0, SIGTRAP, 0, regs); ++ ++ if (thread_info != exception_thread_info) ++ memcpy(thread_info, exception_thread_info, sizeof *thread_info); ++ ++ return 1; ++} ++ ++int kgdb_iabr_match(struct pt_regs *regs) ++{ ++ if (user_mode(regs)) ++ return 0; ++ ++ if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0) ++ return 0; ++ return 1; ++} ++ ++int kgdb_dabr_match(struct pt_regs *regs) ++{ ++ if (user_mode(regs)) ++ return 0; ++ ++ if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0) ++ return 0; ++ return 1; ++} ++ ++void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) ++{ ++ unsigned long *ptr = gdb_regs; ++ int reg; ++ ++ memset(gdb_regs, 0, MAXREG * 4); ++ ++ for (reg = 0; reg < 32; reg++) ++ * (ptr++) = regs->gpr[reg]; ++ ++#ifdef CONFIG_FSL_BOOKE ++#ifdef CONFIG_SPE ++ for (reg = 0; reg < 32; reg++) ++ * (ptr++) = current->thread.evr[reg]; ++#else ++ ptr += 32; ++#endif ++#else ++ ptr += 64; ++#endif ++ ++ *(ptr++) = regs->nip; ++ *(ptr++) = regs->msr; ++ *(ptr++) = regs->ccr; ++ *(ptr++) = regs->link; ++ *(ptr++) = regs->ctr; ++ *(ptr++) = regs->xer; ++ ++#ifdef CONFIG_SPE ++ /* u64 acc */ ++ *(ptr++) = current->thread.acc >> 32; ++ *(ptr++) = current->thread.acc & 0xffffffff; ++ *(ptr++) = current->thread.spefscr; ++#endif ++} ++ ++void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) ++{ ++ struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp + ++ STACK_FRAME_OVERHEAD); ++ unsigned long *ptr = gdb_regs; ++ int reg; ++ ++ memset(gdb_regs, 0, MAXREG * 4); ++ ++ /* Regs GPR0-2 */ ++ for (reg = 0; reg < 3; reg++) ++ * (ptr++) = regs->gpr[reg]; ++ ++ /* Regs GPR3-13 are not saved */ ++ ptr += 11; ++ ++ /* Regs GPR14-31 */ ++ for (reg = 14; reg < 32; reg++) ++ * (ptr++) = regs->gpr[reg]; ++ ++#ifdef CONFIG_FSL_BOOKE ++#ifdef CONFIG_SPE ++ for (reg = 0; reg < 32; reg++) ++ * (ptr++) = p->thread.evr[reg]; ++#else ++ ptr += 32; ++#endif ++#else ++ ptr += 64; ++#endif ++ ++ *(ptr++) = regs->nip; ++ *(ptr++) = regs->msr; ++ *(ptr++) = regs->ccr; ++ *(ptr++) = regs->link; ++ *(ptr++) = regs->ctr; ++ *(ptr++) = regs->xer; ++ ++#ifdef CONFIG_SPE ++ /* u64 acc */ ++ *(ptr++) = p->thread.acc >> 32; ++ *(ptr++) = p->thread.acc & 0xffffffff; ++ *(ptr++) = p->thread.spefscr; ++#endif ++} ++ ++void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) ++{ ++ unsigned long *ptr = gdb_regs; ++ int reg; ++#ifdef CONFIG_SPE ++ union { ++ u32 v32[2]; ++ u64 v64; ++ } acc; ++#endif ++ ++ for (reg = 0; reg < 32; reg++) ++ regs->gpr[reg] = *(ptr++); ++ ++#ifdef CONFIG_FSL_BOOKE ++#ifdef CONFIG_SPE ++ for (reg = 0; reg < 32; reg++) ++ current->thread.evr[reg] = *(ptr++); ++#else ++ ptr += 32; ++#endif ++#else ++ ptr += 64; ++#endif ++ ++ regs->nip = *(ptr++); ++ regs->msr = *(ptr++); ++ regs->ccr = *(ptr++); ++ regs->link = *(ptr++); ++ regs->ctr = *(ptr++); ++ regs->xer = *(ptr++); ++ ++#ifdef CONFIG_SPE ++ /* u64 acc */ ++ acc.v32[0] = *(ptr++); ++ acc.v32[1] = *(ptr++); ++ current->thread.acc = acc.v64; ++ current->thread.spefscr = *(ptr++); ++#endif ++} ++ ++#ifdef CONFIG_SMP ++void kgdb_roundup_cpus(unsigned long flags) ++{ ++ smp_send_debugger_break(MSG_ALL_BUT_SELF); ++} ++#endif ++ ++/* ++ * This function does PowerPC specific processing for interfacing to gdb. ++ */ ++int kgdb_arch_handle_exception(int vector, int signo, int err_code, ++ char *remcom_in_buffer, char *remcom_out_buffer, ++ struct pt_regs *linux_regs) ++{ ++ char *ptr = &remcom_in_buffer[1]; ++ unsigned long addr; ++ ++ switch (remcom_in_buffer[0]) { ++ /* ++ * sAA..AA Step one instruction from AA..AA ++ * This will return an error to gdb .. ++ */ ++ case 's': ++ case 'c': ++ /* handle the optional parameter */ ++ if (kgdb_hex2long(&ptr, &addr)) ++ linux_regs->nip = addr; ++ ++ atomic_set(&kgdb_cpu_doing_single_step, -1); ++ /* set the trace bit if we're stepping */ ++ if (remcom_in_buffer[0] == 's') { ++#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) ++ mtspr(SPRN_DBCR0, ++ mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM); ++ linux_regs->msr |= MSR_DE; ++#else ++ linux_regs->msr |= MSR_SE; ++#endif ++ kgdb_single_step = 1; ++ if (kgdb_contthread) ++ atomic_set(&kgdb_cpu_doing_single_step, ++ smp_processor_id()); ++ } ++ return 0; ++ } ++ ++ return -1; ++} ++ ++/* ++ * Global data ++ */ ++struct kgdb_arch arch_kgdb_ops = { ++ .gdb_bpt_instr = {0x7d, 0x82, 0x10, 0x08}, ++}; ++ ++static void *old_debugger; ++static void *old_debugger_bpt; ++static void *old_debugger_sstep; ++static void *old_debugger_iabr_match; ++static void *old_debugger_dabr_match; ++ ++int kgdb_arch_init(void) ++{ ++ old_debugger = debugger; ++ old_debugger_bpt = debugger_bpt; ++ old_debugger_sstep = debugger_sstep; ++ old_debugger_iabr_match = debugger_iabr_match; ++ old_debugger_dabr_match = debugger_dabr_match; ++ ++ debugger = kgdb_debugger; ++ debugger_bpt = kgdb_handle_breakpoint; ++ debugger_sstep = kgdb_singlestep; ++ debugger_iabr_match = kgdb_iabr_match; ++ debugger_dabr_match = kgdb_dabr_match; ++ ++ return 0; ++} ++ ++void kgdb_arch_exit(void) ++{ ++ debugger = old_debugger; ++ debugger_bpt = old_debugger_bpt; ++ debugger_sstep = old_debugger_sstep; ++ debugger_iabr_match = old_debugger_iabr_match; ++ debugger_dabr_match = old_debugger_dabr_match; ++} +diff --git a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c +deleted file mode 100644 +index 5f9ee7b..0000000 +--- a/arch/ppc/kernel/ppc-stub.c ++++ /dev/null +@@ -1,866 +0,0 @@ +-/* +- * ppc-stub.c: KGDB support for the Linux kernel. +- * +- * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC +- * some stuff borrowed from Paul Mackerras' xmon +- * Copyright (C) 1998 Michael AK Tesch (tesch@cs.wisc.edu) +- * +- * Modifications to run under Linux +- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) +- * +- * This file originally came from the gdb sources, and the +- * copyright notices have been retained below. +- */ +- +-/**************************************************************************** +- +- THIS SOFTWARE IS NOT COPYRIGHTED +- +- HP offers the following for use in the public domain. HP makes no +- warranty with regard to the software or its performance and the +- user accepts the software "AS IS" with all faults. +- +- HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD +- TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES +- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +- +-****************************************************************************/ +- +-/**************************************************************************** +- * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ +- * +- * Module name: remcom.c $ +- * Revision: 1.34 $ +- * Date: 91/03/09 12:29:49 $ +- * Contributor: Lake Stevens Instrument Division$ +- * +- * Description: low level support for gdb debugger. $ +- * +- * Considerations: only works on target hardware $ +- * +- * Written by: Glenn Engel $ +- * ModuleState: Experimental $ +- * +- * NOTES: See Below $ +- * +- * Modified for SPARC by Stu Grossman, Cygnus Support. +- * +- * This code has been extensively tested on the Fujitsu SPARClite demo board. +- * +- * To enable debugger support, two things need to happen. One, a +- * call to set_debug_traps() is necessary in order to allow any breakpoints +- * or error conditions to be properly intercepted and reported to gdb. +- * Two, a breakpoint needs to be generated to begin communication. This +- * is most easily accomplished by a call to breakpoint(). Breakpoint() +- * simulates a breakpoint by executing a trap #1. +- * +- ************* +- * +- * The following gdb commands are supported: +- * +- * command function Return value +- * +- * g return the value of the CPU registers hex data or ENN +- * G set the value of the CPU registers OK or ENN +- * qOffsets Get section offsets. Reply is Text=xxx;Data=yyy;Bss=zzz +- * +- * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN +- * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN +- * +- * c Resume at current address SNN ( signal NN) +- * cAA..AA Continue at address AA..AA SNN +- * +- * s Step one instruction SNN +- * sAA..AA Step one instruction from AA..AA SNN +- * +- * k kill +- * +- * ? What was the last sigval ? SNN (signal NN) +- * +- * bBB..BB Set baud rate to BB..BB OK or BNN, then sets +- * baud rate +- * +- * All commands and responses are sent with a packet which includes a +- * checksum. A packet consists of +- * +- * $#. +- * +- * where +- * :: +- * :: > +- * +- * When a packet is received, it is first acknowledged with either '+' or '-'. +- * '+' indicates a successful transfer. '-' indicates a failed transfer. +- * +- * Example: +- * +- * Host: Reply: +- * $m0,10#2a +$00010203040506070809101112131415#42 +- * +- ****************************************************************************/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-void breakinst(void); +- +-/* +- * BUFMAX defines the maximum number of characters in inbound/outbound buffers +- * at least NUMREGBYTES*2 are needed for register packets +- */ +-#define BUFMAX 2048 +-static char remcomInBuffer[BUFMAX]; +-static char remcomOutBuffer[BUFMAX]; +- +-static int initialized; +-static int kgdb_active; +-static int kgdb_started; +-static u_int fault_jmp_buf[100]; +-static int kdebug; +- +- +-static const char hexchars[]="0123456789abcdef"; +- +-/* Place where we save old trap entries for restoration - sparc*/ +-/* struct tt_entry kgdb_savettable[256]; */ +-/* typedef void (*trapfunc_t)(void); */ +- +-static void kgdb_fault_handler(struct pt_regs *regs); +-static int handle_exception (struct pt_regs *regs); +- +-#if 0 +-/* Install an exception handler for kgdb */ +-static void exceptionHandler(int tnum, unsigned int *tfunc) +-{ +- /* We are dorking with a live trap table, all irqs off */ +-} +-#endif +- +-int +-kgdb_setjmp(long *buf) +-{ +- asm ("mflr 0; stw 0,0(%0);" +- "stw 1,4(%0); stw 2,8(%0);" +- "mfcr 0; stw 0,12(%0);" +- "stmw 13,16(%0)" +- : : "r" (buf)); +- /* XXX should save fp regs as well */ +- return 0; +-} +-void +-kgdb_longjmp(long *buf, int val) +-{ +- if (val == 0) +- val = 1; +- asm ("lmw 13,16(%0);" +- "lwz 0,12(%0); mtcrf 0x38,0;" +- "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);" +- "mtlr 0; mr 3,%1" +- : : "r" (buf), "r" (val)); +-} +-/* Convert ch from a hex digit to an int */ +-static int +-hex(unsigned char ch) +-{ +- if (ch >= 'a' && ch <= 'f') +- return ch-'a'+10; +- if (ch >= '0' && ch <= '9') +- return ch-'0'; +- if (ch >= 'A' && ch <= 'F') +- return ch-'A'+10; +- return -1; +-} +- +-/* Convert the memory pointed to by mem into hex, placing result in buf. +- * Return a pointer to the last char put in buf (null), in case of mem fault, +- * return 0. +- */ +-static unsigned char * +-mem2hex(const char *mem, char *buf, int count) +-{ +- unsigned char ch; +- unsigned short tmp_s; +- unsigned long tmp_l; +- +- if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { +- debugger_fault_handler = kgdb_fault_handler; +- +- /* Accessing 16 bit and 32 bit objects in a single +- ** load instruction is required to avoid bad side +- ** effects for some IO registers. +- */ +- +- if ((count == 2) && (((long)mem & 1) == 0)) { +- tmp_s = *(unsigned short *)mem; +- mem += 2; +- *buf++ = hexchars[(tmp_s >> 12) & 0xf]; +- *buf++ = hexchars[(tmp_s >> 8) & 0xf]; +- *buf++ = hexchars[(tmp_s >> 4) & 0xf]; +- *buf++ = hexchars[tmp_s & 0xf]; +- +- } else if ((count == 4) && (((long)mem & 3) == 0)) { +- tmp_l = *(unsigned int *)mem; +- mem += 4; +- *buf++ = hexchars[(tmp_l >> 28) & 0xf]; +- *buf++ = hexchars[(tmp_l >> 24) & 0xf]; +- *buf++ = hexchars[(tmp_l >> 20) & 0xf]; +- *buf++ = hexchars[(tmp_l >> 16) & 0xf]; +- *buf++ = hexchars[(tmp_l >> 12) & 0xf]; +- *buf++ = hexchars[(tmp_l >> 8) & 0xf]; +- *buf++ = hexchars[(tmp_l >> 4) & 0xf]; +- *buf++ = hexchars[tmp_l & 0xf]; +- +- } else { +- while (count-- > 0) { +- ch = *mem++; +- *buf++ = hexchars[ch >> 4]; +- *buf++ = hexchars[ch & 0xf]; +- } +- } +- +- } else { +- /* error condition */ +- } +- debugger_fault_handler = NULL; +- *buf = 0; +- return buf; +-} +- +-/* convert the hex array pointed to by buf into binary to be placed in mem +- * return a pointer to the character AFTER the last byte written. +-*/ +-static char * +-hex2mem(char *buf, char *mem, int count) +-{ +- unsigned char ch; +- int i; +- char *orig_mem; +- unsigned short tmp_s; +- unsigned long tmp_l; +- +- orig_mem = mem; +- +- if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { +- debugger_fault_handler = kgdb_fault_handler; +- +- /* Accessing 16 bit and 32 bit objects in a single +- ** store instruction is required to avoid bad side +- ** effects for some IO registers. +- */ +- +- if ((count == 2) && (((long)mem & 1) == 0)) { +- tmp_s = hex(*buf++) << 12; +- tmp_s |= hex(*buf++) << 8; +- tmp_s |= hex(*buf++) << 4; +- tmp_s |= hex(*buf++); +- +- *(unsigned short *)mem = tmp_s; +- mem += 2; +- +- } else if ((count == 4) && (((long)mem & 3) == 0)) { +- tmp_l = hex(*buf++) << 28; +- tmp_l |= hex(*buf++) << 24; +- tmp_l |= hex(*buf++) << 20; +- tmp_l |= hex(*buf++) << 16; +- tmp_l |= hex(*buf++) << 12; +- tmp_l |= hex(*buf++) << 8; +- tmp_l |= hex(*buf++) << 4; +- tmp_l |= hex(*buf++); +- +- *(unsigned long *)mem = tmp_l; +- mem += 4; +- +- } else { +- for (i=0; i# */ +-static void +-getpacket(char *buffer) +-{ +- unsigned char checksum; +- unsigned char xmitcsum; +- int i; +- int count; +- unsigned char ch; +- +- do { +- /* wait around for the start character, ignore all other +- * characters */ +- while ((ch = (getDebugChar() & 0x7f)) != '$') ; +- +- checksum = 0; +- xmitcsum = -1; +- +- count = 0; +- +- /* now, read until a # or end of buffer is found */ +- while (count < BUFMAX) { +- ch = getDebugChar() & 0x7f; +- if (ch == '#') +- break; +- checksum = checksum + ch; +- buffer[count] = ch; +- count = count + 1; +- } +- +- if (count >= BUFMAX) +- continue; +- +- buffer[count] = 0; +- +- if (ch == '#') { +- xmitcsum = hex(getDebugChar() & 0x7f) << 4; +- xmitcsum |= hex(getDebugChar() & 0x7f); +- if (checksum != xmitcsum) +- putDebugChar('-'); /* failed checksum */ +- else { +- putDebugChar('+'); /* successful transfer */ +- /* if a sequence char is present, reply the ID */ +- if (buffer[2] == ':') { +- putDebugChar(buffer[0]); +- putDebugChar(buffer[1]); +- /* remove sequence chars from buffer */ +- count = strlen(buffer); +- for (i=3; i <= count; i++) +- buffer[i-3] = buffer[i]; +- } +- } +- } +- } while (checksum != xmitcsum); +-} +- +-/* send the packet in buffer. */ +-static void putpacket(unsigned char *buffer) +-{ +- unsigned char checksum; +- int count; +- unsigned char ch, recv; +- +- /* $#. */ +- do { +- putDebugChar('$'); +- checksum = 0; +- count = 0; +- +- while ((ch = buffer[count])) { +- putDebugChar(ch); +- checksum += ch; +- count += 1; +- } +- +- putDebugChar('#'); +- putDebugChar(hexchars[checksum >> 4]); +- putDebugChar(hexchars[checksum & 0xf]); +- recv = getDebugChar(); +- } while ((recv & 0x7f) != '+'); +-} +- +-static void kgdb_flush_cache_all(void) +-{ +- flush_instruction_cache(); +-} +- +-/* Set up exception handlers for tracing and breakpoints +- * [could be called kgdb_init()] +- */ +-void set_debug_traps(void) +-{ +-#if 0 +- unsigned char c; +- +- save_and_cli(flags); +- +- /* In case GDB is started before us, ack any packets (presumably +- * "$?#xx") sitting there. +- * +- * I've found this code causes more problems than it solves, +- * so that's why it's commented out. GDB seems to work fine +- * now starting either before or after the kernel -bwb +- */ +- +- while((c = getDebugChar()) != '$'); +- while((c = getDebugChar()) != '#'); +- c = getDebugChar(); /* eat first csum byte */ +- c = getDebugChar(); /* eat second csum byte */ +- putDebugChar('+'); /* ack it */ +-#endif +- debugger = kgdb; +- debugger_bpt = kgdb_bpt; +- debugger_sstep = kgdb_sstep; +- debugger_iabr_match = kgdb_iabr_match; +- debugger_dabr_match = kgdb_dabr_match; +- +- initialized = 1; +-} +- +-static void kgdb_fault_handler(struct pt_regs *regs) +-{ +- kgdb_longjmp((long*)fault_jmp_buf, 1); +-} +- +-int kgdb_bpt(struct pt_regs *regs) +-{ +- return handle_exception(regs); +-} +- +-int kgdb_sstep(struct pt_regs *regs) +-{ +- return handle_exception(regs); +-} +- +-void kgdb(struct pt_regs *regs) +-{ +- handle_exception(regs); +-} +- +-int kgdb_iabr_match(struct pt_regs *regs) +-{ +- printk(KERN_ERR "kgdb doesn't support iabr, what?!?\n"); +- return handle_exception(regs); +-} +- +-int kgdb_dabr_match(struct pt_regs *regs) +-{ +- printk(KERN_ERR "kgdb doesn't support dabr, what?!?\n"); +- return handle_exception(regs); +-} +- +-/* Convert the hardware trap type code to a unix signal number. */ +-/* +- * This table contains the mapping between PowerPC hardware trap types, and +- * signals, which are primarily what GDB understands. +- */ +-static struct hard_trap_info +-{ +- unsigned int tt; /* Trap type code for powerpc */ +- unsigned char signo; /* Signal that we map this trap into */ +-} hard_trap_info[] = { +-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) +- { 0x100, SIGINT }, /* critical input interrupt */ +- { 0x200, SIGSEGV }, /* machine check */ +- { 0x300, SIGSEGV }, /* data storage */ +- { 0x400, SIGBUS }, /* instruction storage */ +- { 0x500, SIGINT }, /* interrupt */ +- { 0x600, SIGBUS }, /* alignment */ +- { 0x700, SIGILL }, /* program */ +- { 0x800, SIGILL }, /* reserved */ +- { 0x900, SIGILL }, /* reserved */ +- { 0xa00, SIGILL }, /* reserved */ +- { 0xb00, SIGILL }, /* reserved */ +- { 0xc00, SIGCHLD }, /* syscall */ +- { 0xd00, SIGILL }, /* reserved */ +- { 0xe00, SIGILL }, /* reserved */ +- { 0xf00, SIGILL }, /* reserved */ +- /* +- ** 0x1000 PIT +- ** 0x1010 FIT +- ** 0x1020 watchdog +- ** 0x1100 data TLB miss +- ** 0x1200 instruction TLB miss +- */ +- { 0x2002, SIGTRAP}, /* debug */ +-#else +- { 0x200, SIGSEGV }, /* machine check */ +- { 0x300, SIGSEGV }, /* address error (store) */ +- { 0x400, SIGBUS }, /* instruction bus error */ +- { 0x500, SIGINT }, /* interrupt */ +- { 0x600, SIGBUS }, /* alingment */ +- { 0x700, SIGTRAP }, /* breakpoint trap */ +- { 0x800, SIGFPE }, /* fpu unavail */ +- { 0x900, SIGALRM }, /* decrementer */ +- { 0xa00, SIGILL }, /* reserved */ +- { 0xb00, SIGILL }, /* reserved */ +- { 0xc00, SIGCHLD }, /* syscall */ +- { 0xd00, SIGTRAP }, /* single-step/watch */ +- { 0xe00, SIGFPE }, /* fp assist */ +-#endif +- { 0, 0} /* Must be last */ +- +-}; +- +-static int computeSignal(unsigned int tt) +-{ +- struct hard_trap_info *ht; +- +- for (ht = hard_trap_info; ht->tt && ht->signo; ht++) +- if (ht->tt == tt) +- return ht->signo; +- +- return SIGHUP; /* default for things we don't know about */ +-} +- +-#define PC_REGNUM 64 +-#define SP_REGNUM 1 +- +-/* +- * This function does all command processing for interfacing to gdb. +- */ +-static int +-handle_exception (struct pt_regs *regs) +-{ +- int sigval; +- int addr; +- int length; +- char *ptr; +- unsigned int msr; +- +- /* We don't handle user-mode breakpoints. */ +- if (user_mode(regs)) +- return 0; +- +- if (debugger_fault_handler) { +- debugger_fault_handler(regs); +- panic("kgdb longjump failed!\n"); +- } +- if (kgdb_active) { +- printk(KERN_ERR "interrupt while in kgdb, returning\n"); +- return 0; +- } +- +- kgdb_active = 1; +- kgdb_started = 1; +- +-#ifdef KGDB_DEBUG +- printk("kgdb: entering handle_exception; trap [0x%x]\n", +- (unsigned int)regs->trap); +-#endif +- +- kgdb_interruptible(0); +- lock_kernel(); +- msr = mfmsr(); +- mtmsr(msr & ~MSR_EE); /* disable interrupts */ +- +- if (regs->nip == (unsigned long)breakinst) { +- /* Skip over breakpoint trap insn */ +- regs->nip += 4; +- } +- +- /* reply to host that an exception has occurred */ +- sigval = computeSignal(regs->trap); +- ptr = remcomOutBuffer; +- +- *ptr++ = 'T'; +- *ptr++ = hexchars[sigval >> 4]; +- *ptr++ = hexchars[sigval & 0xf]; +- *ptr++ = hexchars[PC_REGNUM >> 4]; +- *ptr++ = hexchars[PC_REGNUM & 0xf]; +- *ptr++ = ':'; +- ptr = mem2hex((char *)®s->nip, ptr, 4); +- *ptr++ = ';'; +- *ptr++ = hexchars[SP_REGNUM >> 4]; +- *ptr++ = hexchars[SP_REGNUM & 0xf]; +- *ptr++ = ':'; +- ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4); +- *ptr++ = ';'; +- *ptr++ = 0; +- +- putpacket(remcomOutBuffer); +- if (kdebug) +- printk("remcomOutBuffer: %s\n", remcomOutBuffer); +- +- /* XXX We may want to add some features dealing with poking the +- * XXX page tables, ... (look at sparc-stub.c for more info) +- * XXX also required hacking to the gdb sources directly... +- */ +- +- while (1) { +- remcomOutBuffer[0] = 0; +- +- getpacket(remcomInBuffer); +- switch (remcomInBuffer[0]) { +- case '?': /* report most recent signal */ +- remcomOutBuffer[0] = 'S'; +- remcomOutBuffer[1] = hexchars[sigval >> 4]; +- remcomOutBuffer[2] = hexchars[sigval & 0xf]; +- remcomOutBuffer[3] = 0; +- break; +-#if 0 +- case 'q': /* this screws up gdb for some reason...*/ +- { +- extern long _start, sdata, __bss_start; +- +- ptr = &remcomInBuffer[1]; +- if (strncmp(ptr, "Offsets", 7) != 0) +- break; +- +- ptr = remcomOutBuffer; +- sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x", +- &_start, &sdata, &__bss_start); +- break; +- } +-#endif +- case 'd': +- /* toggle debug flag */ +- kdebug ^= 1; +- break; +- +- case 'g': /* return the value of the CPU registers. +- * some of them are non-PowerPC names :( +- * they are stored in gdb like: +- * struct { +- * u32 gpr[32]; +- * f64 fpr[32]; +- * u32 pc, ps, cnd, lr; (ps=msr) +- * u32 cnt, xer, mq; +- * } +- */ +- { +- int i; +- ptr = remcomOutBuffer; +- /* General Purpose Regs */ +- ptr = mem2hex((char *)regs, ptr, 32 * 4); +- /* Floating Point Regs - FIXME */ +- /*ptr = mem2hex((char *), ptr, 32 * 8);*/ +- for(i=0; i<(32*8*2); i++) { /* 2chars/byte */ +- ptr[i] = '0'; +- } +- ptr += 32*8*2; +- /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ +- ptr = mem2hex((char *)®s->nip, ptr, 4); +- ptr = mem2hex((char *)®s->msr, ptr, 4); +- ptr = mem2hex((char *)®s->ccr, ptr, 4); +- ptr = mem2hex((char *)®s->link, ptr, 4); +- ptr = mem2hex((char *)®s->ctr, ptr, 4); +- ptr = mem2hex((char *)®s->xer, ptr, 4); +- } +- break; +- +- case 'G': /* set the value of the CPU registers */ +- { +- ptr = &remcomInBuffer[1]; +- +- /* +- * If the stack pointer has moved, you should pray. +- * (cause only god can help you). +- */ +- +- /* General Purpose Regs */ +- hex2mem(ptr, (char *)regs, 32 * 4); +- +- /* Floating Point Regs - FIXME?? */ +- /*ptr = hex2mem(ptr, ??, 32 * 8);*/ +- ptr += 32*8*2; +- +- /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ +- ptr = hex2mem(ptr, (char *)®s->nip, 4); +- ptr = hex2mem(ptr, (char *)®s->msr, 4); +- ptr = hex2mem(ptr, (char *)®s->ccr, 4); +- ptr = hex2mem(ptr, (char *)®s->link, 4); +- ptr = hex2mem(ptr, (char *)®s->ctr, 4); +- ptr = hex2mem(ptr, (char *)®s->xer, 4); +- +- strcpy(remcomOutBuffer,"OK"); +- } +- break; +- case 'H': +- /* don't do anything, yet, just acknowledge */ +- hexToInt(&ptr, &addr); +- strcpy(remcomOutBuffer,"OK"); +- break; +- +- case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ +- /* Try to read %x,%x. */ +- +- ptr = &remcomInBuffer[1]; +- +- if (hexToInt(&ptr, &addr) && *ptr++ == ',' +- && hexToInt(&ptr, &length)) { +- if (mem2hex((char *)addr, remcomOutBuffer, +- length)) +- break; +- strcpy(remcomOutBuffer, "E03"); +- } else +- strcpy(remcomOutBuffer, "E01"); +- break; +- +- case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ +- /* Try to read '%x,%x:'. */ +- +- ptr = &remcomInBuffer[1]; +- +- if (hexToInt(&ptr, &addr) && *ptr++ == ',' +- && hexToInt(&ptr, &length) +- && *ptr++ == ':') { +- if (hex2mem(ptr, (char *)addr, length)) +- strcpy(remcomOutBuffer, "OK"); +- else +- strcpy(remcomOutBuffer, "E03"); +- flush_icache_range(addr, addr+length); +- } else +- strcpy(remcomOutBuffer, "E02"); +- break; +- +- +- case 'k': /* kill the program, actually just continue */ +- case 'c': /* cAA..AA Continue; address AA..AA optional */ +- /* try to read optional parameter, pc unchanged if no parm */ +- +- ptr = &remcomInBuffer[1]; +- if (hexToInt(&ptr, &addr)) +- regs->nip = addr; +- +-/* Need to flush the instruction cache here, as we may have deposited a +- * breakpoint, and the icache probably has no way of knowing that a data ref to +- * some location may have changed something that is in the instruction cache. +- */ +- kgdb_flush_cache_all(); +- mtmsr(msr); +- +- kgdb_interruptible(1); +- unlock_kernel(); +- kgdb_active = 0; +- if (kdebug) { +- printk("remcomInBuffer: %s\n", remcomInBuffer); +- printk("remcomOutBuffer: %s\n", remcomOutBuffer); +- } +- return 1; +- +- case 's': +- kgdb_flush_cache_all(); +-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) +- mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC); +- regs->msr |= MSR_DE; +-#else +- regs->msr |= MSR_SE; +-#endif +- unlock_kernel(); +- kgdb_active = 0; +- if (kdebug) { +- printk("remcomInBuffer: %s\n", remcomInBuffer); +- printk("remcomOutBuffer: %s\n", remcomOutBuffer); +- } +- return 1; +- +- case 'r': /* Reset (if user process..exit ???)*/ +- panic("kgdb reset."); +- break; +- } /* switch */ +- if (remcomOutBuffer[0] && kdebug) { +- printk("remcomInBuffer: %s\n", remcomInBuffer); +- printk("remcomOutBuffer: %s\n", remcomOutBuffer); +- } +- /* reply to the request */ +- putpacket(remcomOutBuffer); +- } /* while(1) */ +-} +- +-/* This function will generate a breakpoint exception. It is used at the +- beginning of a program to sync up with a debugger and can be used +- otherwise as a quick means to stop program execution and "break" into +- the debugger. */ +- +-void +-breakpoint(void) +-{ +- if (!initialized) { +- printk("breakpoint() called b4 kgdb init\n"); +- return; +- } +- +- asm(" .globl breakinst \n\ +- breakinst: .long 0x7d821008"); +-} +- +-#ifdef CONFIG_KGDB_CONSOLE +-/* Output string in GDB O-packet format if GDB has connected. If nothing +- output, returns 0 (caller must then handle output). */ +-int +-kgdb_output_string (const char* s, unsigned int count) +-{ +- char buffer[512]; +- +- if (!kgdb_started) +- return 0; +- +- count = (count <= (sizeof(buffer) / 2 - 2)) +- ? count : (sizeof(buffer) / 2 - 2); +- +- buffer[0] = 'O'; +- mem2hex (s, &buffer[1], count); +- putpacket(buffer); +- +- return 1; +-} +-#endif +- +-static void sysrq_handle_gdb(int key, struct pt_regs *pt_regs, +- struct tty_struct *tty) +-{ +- printk("Entering GDB stub\n"); +- breakpoint(); +-} +-static struct sysrq_key_op sysrq_gdb_op = { +- .handler = sysrq_handle_gdb, +- .help_msg = "Gdb", +- .action_msg = "GDB", +-}; +- +-static int gdb_register_sysrq(void) +-{ +- printk("Registering GDB sysrq handler\n"); +- register_sysrq_key('g', &sysrq_gdb_op); +- return 0; +-} +-module_init(gdb_register_sysrq); +diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c +index 5255bd8..944be1f 100644 +--- a/arch/ppc/kernel/setup.c ++++ b/arch/ppc/kernel/setup.c +@@ -47,10 +47,6 @@ + #include + #endif + +-#if defined CONFIG_KGDB +-#include +-#endif +- + extern void platform_init(unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, unsigned long r7); + extern void reloc_got2(unsigned long offset); +@@ -515,18 +511,6 @@ void __init setup_arch(char **cmdline_p) + #endif /* CONFIG_XMON */ + if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab); + +-#if defined(CONFIG_KGDB) +- if (ppc_md.kgdb_map_scc) +- ppc_md.kgdb_map_scc(); +- set_debug_traps(); +- if (strstr(cmd_line, "gdb")) { +- if (ppc_md.progress) +- ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000); +- printk("kgdb breakpoint activated\n"); +- breakpoint(); +- } +-#endif +- + /* + * Set cache line size based on type of cpu as a default. + * Systems with OF can look in the properties on the cpu node(s) +diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c +index 36c0e75..a51fd3e 100644 +--- a/arch/ppc/mm/fault.c ++++ b/arch/ppc/mm/fault.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include + #include +diff --git a/arch/ppc/platforms/4xx/bamboo.c b/arch/ppc/platforms/4xx/bamboo.c +index 017623c..d7020bb 100644 +--- a/arch/ppc/platforms/4xx/bamboo.c ++++ b/arch/ppc/platforms/4xx/bamboo.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -319,6 +320,14 @@ bamboo_setup_hose(void) + + TODC_ALLOC(); + ++#ifdef CONFIG_KGDB_8250 ++static int kgdb8250_ready; ++int kgdb8250_early_debug_ready(void) ++{ ++ return kgdb8250_ready; ++} ++#endif ++ + static void __init + bamboo_early_serial_map(void) + { +@@ -338,7 +347,7 @@ bamboo_early_serial_map(void) + printk("Early serial init of port 0 failed\n"); + } + +-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Configure debug serial access */ + gen550_init(0, &port); + #endif +@@ -352,7 +361,7 @@ bamboo_early_serial_map(void) + printk("Early serial init of port 1 failed\n"); + } + +-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Configure debug serial access */ + gen550_init(1, &port); + #endif +@@ -366,7 +375,7 @@ bamboo_early_serial_map(void) + printk("Early serial init of port 2 failed\n"); + } + +-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Configure debug serial access */ + gen550_init(2, &port); + #endif +@@ -379,6 +388,11 @@ bamboo_early_serial_map(void) + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 3 failed\n"); + } ++ ++#ifdef CONFIG_KGDB_8250 ++ kgdb8250_ready = 1; ++ kgdb8250_arch_init(); ++#endif + } + + static void __init +@@ -436,8 +450,5 @@ void __init platform_init(unsigned long r3, unsigned long r4, + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +-#ifdef CONFIG_KGDB +- ppc_md.early_serial_map = bamboo_early_serial_map; +-#endif + } + +diff --git a/arch/ppc/platforms/4xx/bubinga.c b/arch/ppc/platforms/4xx/bubinga.c +index cd696be..46b1cc5 100644 +--- a/arch/ppc/platforms/4xx/bubinga.c ++++ b/arch/ppc/platforms/4xx/bubinga.c +@@ -4,7 +4,7 @@ + * Author: SAW (IBM), derived from walnut.c. + * Maintained by MontaVista Software + * +- * 2003 (c) MontaVista Softare Inc. This file is licensed under the ++ * 2003-2004 (c) MontaVista Softare Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program is + * licensed "as is" without any warranty of any kind, whether express + * or implied. +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -31,7 +32,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -71,6 +71,14 @@ ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) + return PCI_IRQ_TABLE_LOOKUP; + }; + ++#ifdef CONFIG_KGDB_8250 ++static int kgdb8250_ready; ++int kgdb8250_early_debug_ready(void) ++{ ++ return kgdb8250_ready; ++} ++#endif ++ + /* The serial clock for the chip is an internal clock determined by + * different clock speeds/dividers. + * Calculate the proper input baud rate and setup the serial driver. +@@ -101,17 +109,23 @@ bubinga_early_serial_map(void) + port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; + port.line = 0; + +- if (early_serial_setup(&port) != 0) { ++#ifdef CONFIG_SERIAL_8250 ++ if (early_serial_setup(&port) != 0) + printk("Early serial init of port 0 failed\n"); +- } ++#endif + + port.membase = (void*)ACTING_UART1_IO_BASE; + port.irq = ACTING_UART1_INT; + port.line = 1; + +- if (early_serial_setup(&port) != 0) { ++#ifdef CONFIG_SERIAL_8250 ++ if (early_serial_setup(&port) != 0) + printk("Early serial init of port 1 failed\n"); +- } ++#endif ++#ifdef CONFIG_KGDB_8250 ++ kgdb8250_ready = 1; ++ kgdb8250_arch_init(); ++#endif + } + + void __init +@@ -258,8 +272,4 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + #endif +-#ifdef CONFIG_KGDB +- ppc_md.early_serial_map = bubinga_early_serial_map; +-#endif + } +- +diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c +index 453643a..172ac7f 100644 +--- a/arch/ppc/platforms/4xx/ebony.c ++++ b/arch/ppc/platforms/4xx/ebony.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -212,6 +213,14 @@ ebony_setup_hose(void) + + TODC_ALLOC(); + ++#ifdef CONFIG_KGDB_8250 ++static int kgdb8250_ready; ++int kgdb8250_early_debug_ready(void) ++{ ++ return kgdb8250_ready; ++} ++#endif ++ + static void __init + ebony_early_serial_map(void) + { +@@ -227,14 +236,17 @@ ebony_early_serial_map(void) + port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; + port.line = 0; + +- if (early_serial_setup(&port) != 0) { ++#ifdef CONFIG_SERIAL_8250 ++ if (early_serial_setup(&port) != 0) + printk("Early serial init of port 0 failed\n"); +- } ++#endif + +-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Configure debug serial access */ + gen550_init(0, &port); ++#endif + ++#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) + /* Purge TLB entry added in head_44x.S for early serial access */ + _tlbie(UART0_IO_BASE, 0); + #endif +@@ -244,14 +256,19 @@ ebony_early_serial_map(void) + port.uartclk = clocks.uart1; + port.line = 1; + +- if (early_serial_setup(&port) != 0) { ++#ifdef CONFIG_SERIAL_8250 ++ if (early_serial_setup(&port) != 1) + printk("Early serial init of port 1 failed\n"); +- } ++#endif + +-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Configure debug serial access */ + gen550_init(1, &port); + #endif ++#ifdef CONFIG_KGDB_8250 ++ kgdb8250_ready = 1; ++ kgdb8250_arch_init(); ++#endif + } + + static void __init +@@ -328,8 +345,4 @@ void __init platform_init(unsigned long r3, unsigned long r4, + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +-#ifdef CONFIG_KGDB +- ppc_md.early_serial_map = ebony_early_serial_map; +-#endif + } +- +diff --git a/arch/ppc/platforms/4xx/luan.c b/arch/ppc/platforms/4xx/luan.c +index b79ebb8..fb3a0ec 100644 +--- a/arch/ppc/platforms/4xx/luan.c ++++ b/arch/ppc/platforms/4xx/luan.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -271,6 +272,14 @@ luan_setup_hoses(void) + + TODC_ALLOC(); + ++#ifdef CONFIG_KGDB_8250 ++static int kgdb8250_ready; ++int kgdb8250_early_debug_ready(void) ++{ ++ return kgdb8250_ready; ++} ++#endif ++ + static void __init + luan_early_serial_map(void) + { +@@ -307,6 +316,10 @@ luan_early_serial_map(void) + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 2 failed\n"); + } ++#ifdef CONFIG_KGDB_8250 ++ kgdb8250_ready = 1; ++ kgdb8250_arch_init(); ++#endif + } + + static void __init +@@ -366,7 +379,4 @@ void __init platform_init(unsigned long r3, unsigned long r4, + ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ + + ppc_md.calibrate_decr = luan_calibrate_decr; +-#ifdef CONFIG_KGDB +- ppc_md.early_serial_map = luan_early_serial_map; +-#endif + } +diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c +index 28a712c..94f2736 100644 +--- a/arch/ppc/platforms/4xx/ocotea.c ++++ b/arch/ppc/platforms/4xx/ocotea.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -235,6 +236,14 @@ ocotea_setup_hose(void) + + TODC_ALLOC(); + ++#ifdef CONFIG_KGDB_8250 ++static int kgdb8250_ready; ++int kgdb8250_early_debug_ready(void) ++{ ++ return kgdb8250_ready; ++} ++#endif ++ + static void __init + ocotea_early_serial_map(void) + { +@@ -250,14 +259,17 @@ ocotea_early_serial_map(void) + port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; + port.line = 0; + +- if (early_serial_setup(&port) != 0) { ++#ifdef CONFIG_SERIAL_8250 ++ if (early_serial_setup(&port) != 0) + printk("Early serial init of port 0 failed\n"); +- } ++#endif + +-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Configure debug serial access */ + gen550_init(0, &port); ++#endif + ++#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) + /* Purge TLB entry added in head_44x.S for early serial access */ + _tlbie(UART0_IO_BASE, 0); + #endif +@@ -267,14 +279,19 @@ ocotea_early_serial_map(void) + port.uartclk = clocks.uart1; + port.line = 1; + +- if (early_serial_setup(&port) != 0) { ++#ifdef CONFIG_SERIAL_8250 ++ if (early_serial_setup(&port) != 1) + printk("Early serial init of port 1 failed\n"); +- } ++#endif + +-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Configure debug serial access */ + gen550_init(1, &port); + #endif ++#ifdef CONFIG_KGDB_8250 ++ kgdb8250_ready = 1; ++ kgdb8250_arch_init(); ++#endif + } + + static void __init +@@ -344,8 +361,5 @@ void __init platform_init(unsigned long r3, unsigned long r4, + + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +-#ifdef CONFIG_KGDB +- ppc_md.early_serial_map = ocotea_early_serial_map; +-#endif + ppc_md.init = ocotea_init; + } +diff --git a/arch/ppc/platforms/4xx/taishan.c b/arch/ppc/platforms/4xx/taishan.c +index f6a0c66..3cba065 100644 +--- a/arch/ppc/platforms/4xx/taishan.c ++++ b/arch/ppc/platforms/4xx/taishan.c +@@ -311,7 +311,7 @@ taishan_early_serial_map(void) + if (early_serial_setup(&port) != 0) + printk("Early serial init of port 0 failed\n"); + +-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Configure debug serial access */ + gen550_init(0, &port); + +@@ -327,7 +327,7 @@ taishan_early_serial_map(void) + if (early_serial_setup(&port) != 0) + printk("Early serial init of port 1 failed\n"); + +-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Configure debug serial access */ + gen550_init(1, &port); + #endif +@@ -388,9 +388,6 @@ void __init platform_init(unsigned long r3, unsigned long r4, + + ppc_md.calibrate_decr = taishan_calibrate_decr; + +-#ifdef CONFIG_KGDB +- ppc_md.early_serial_map = taishan_early_serial_map; +-#endif + ppc_md.init = taishan_init; + } + +diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.c b/arch/ppc/platforms/4xx/xilinx_ml300.c +index 6e522fe..9f640a3 100644 +--- a/arch/ppc/platforms/4xx/xilinx_ml300.c ++++ b/arch/ppc/platforms/4xx/xilinx_ml300.c +@@ -16,6 +16,8 @@ + #include + #include + #include ++#include ++ + #include + #include + +@@ -41,9 +43,6 @@ + * ppc4xx_map_io arch/ppc/syslib/ppc4xx_setup.c + * start_kernel init/main.c + * setup_arch arch/ppc/kernel/setup.c +- * #if defined(CONFIG_KGDB) +- * *ppc_md.kgdb_map_scc() == gen550_kgdb_map_scc +- * #endif + * *ppc_md.setup_arch == ml300_setup_arch this file + * ppc4xx_setup_arch arch/ppc/syslib/ppc4xx_setup.c + * ppc4xx_find_bridges arch/ppc/syslib/ppc405_pci.c +diff --git a/arch/ppc/platforms/4xx/xilinx_ml403.c b/arch/ppc/platforms/4xx/xilinx_ml403.c +index bc3ace3..019963b 100644 +--- a/arch/ppc/platforms/4xx/xilinx_ml403.c ++++ b/arch/ppc/platforms/4xx/xilinx_ml403.c +@@ -43,9 +43,6 @@ + * ppc4xx_map_io arch/ppc/syslib/ppc4xx_setup.c + * start_kernel init/main.c + * setup_arch arch/ppc/kernel/setup.c +- * #if defined(CONFIG_KGDB) +- * *ppc_md.kgdb_map_scc() == gen550_kgdb_map_scc +- * #endif + * *ppc_md.setup_arch == ml403_setup_arch this file + * ppc4xx_setup_arch arch/ppc/syslib/ppc4xx_setup.c + * ppc4xx_find_bridges arch/ppc/syslib/ppc405_pci.c +diff --git a/arch/ppc/platforms/4xx/yucca.c b/arch/ppc/platforms/4xx/yucca.c +index 66a44ff..ec4ca44 100644 +--- a/arch/ppc/platforms/4xx/yucca.c ++++ b/arch/ppc/platforms/4xx/yucca.c +@@ -388,7 +388,4 @@ void __init platform_init(unsigned long r3, unsigned long r4, + ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ + + ppc_md.calibrate_decr = yucca_calibrate_decr; +-#ifdef CONFIG_KGDB +- ppc_md.early_serial_map = yucca_early_serial_map; +-#endif + } +diff --git a/arch/ppc/platforms/chestnut.c b/arch/ppc/platforms/chestnut.c +index dcd6070..ccd2faa 100644 +--- a/arch/ppc/platforms/chestnut.c ++++ b/arch/ppc/platforms/chestnut.c +@@ -35,9 +35,9 @@ + #include + #include + #include +-#include + #include + #include ++#include + #include + + static void __iomem *sram_base; /* Virtual addr of Internal SRAM */ +@@ -492,7 +492,7 @@ chestnut_power_off(void) + static void __init + chestnut_map_io(void) + { +-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) ++#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) + io_block_mapping(CHESTNUT_UART_BASE, CHESTNUT_UART_BASE, 0x100000, + _PAGE_IO); + #endif +@@ -566,9 +566,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + #if defined(CONFIG_SERIAL_TEXT_DEBUG) + ppc_md.progress = gen550_progress; + #endif +-#if defined(CONFIG_KGDB) +- ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +-#endif + + if (ppc_md.progress) + ppc_md.progress("chestnut_init(): exit", 0); +diff --git a/arch/ppc/platforms/ev64260.c b/arch/ppc/platforms/ev64260.c +index 976270d..beaa70c 100644 +--- a/arch/ppc/platforms/ev64260.c ++++ b/arch/ppc/platforms/ev64260.c +@@ -331,7 +331,7 @@ ev64260_early_serial_map(void) + port.iotype = UPIO_MEM; + port.flags = STD_COM_FLAGS; + +-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + gen550_init(0, &port); + #endif + +@@ -569,7 +569,7 @@ ev64260_set_bat(void) + return; + } + +-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + static void __init + ev64260_map_io(void) + { +@@ -625,20 +625,12 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + ppc_md.setup_io_mappings = ev64260_map_io; + ppc_md.progress = gen550_progress; + #endif +-#if defined(CONFIG_KGDB) +- ppc_md.setup_io_mappings = ev64260_map_io; +- ppc_md.early_serial_map = ev64260_early_serial_map; +-#endif + #elif defined(CONFIG_SERIAL_MPSC_CONSOLE) + #ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.setup_io_mappings = ev64260_map_io; + ppc_md.progress = mv64x60_mpsc_progress; + mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE); + #endif /* CONFIG_SERIAL_TEXT_DEBUG */ +-#ifdef CONFIG_KGDB +- ppc_md.setup_io_mappings = ev64260_map_io; +- ppc_md.early_serial_map = ev64260_early_serial_map; +-#endif /* CONFIG_KGDB */ + + #endif + +diff --git a/arch/ppc/platforms/hdpu.c b/arch/ppc/platforms/hdpu.c +index ca5de13..687db90 100644 +--- a/arch/ppc/platforms/hdpu.c ++++ b/arch/ppc/platforms/hdpu.c +@@ -281,25 +281,6 @@ static void __init hdpu_setup_bridge(void) + #if defined(CONFIG_SERIAL_MPSC_CONSOLE) + static void __init hdpu_early_serial_map(void) + { +-#ifdef CONFIG_KGDB +- static char first_time = 1; +- +-#if defined(CONFIG_KGDB_TTYS0) +-#define KGDB_PORT 0 +-#elif defined(CONFIG_KGDB_TTYS1) +-#define KGDB_PORT 1 +-#else +-#error "Invalid kgdb_tty port" +-#endif +- +- if (first_time) { +- gt_early_mpsc_init(KGDB_PORT, +- B9600 | CS8 | CREAD | HUPCL | CLOCAL); +- first_time = 0; +- } +- +- return; +-#endif + } + #endif + +diff --git a/arch/ppc/platforms/pplus.c b/arch/ppc/platforms/pplus.c +index 8a1788c..b006fcd 100644 +--- a/arch/ppc/platforms/pplus.c ++++ b/arch/ppc/platforms/pplus.c +@@ -35,9 +35,9 @@ + #include + #include + #include +-#include + #include + ++#include + #include "pplus.h" + + #undef DUMP_DBATS +@@ -893,9 +893,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + #ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; + #endif /* CONFIG_SERIAL_TEXT_DEBUG */ +-#ifdef CONFIG_KGDB +- ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +-#endif + #ifdef CONFIG_SMP + smp_ops = &pplus_smp_ops; + #endif /* CONFIG_SMP */ +diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c +index 44d4398..d62e132 100644 +--- a/arch/ppc/platforms/radstone_ppc7d.c ++++ b/arch/ppc/platforms/radstone_ppc7d.c +@@ -85,7 +85,7 @@ unsigned char __res[sizeof(bd_t)]; + * Serial port code + *****************************************************************************/ + +-#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + static void __init ppc7d_early_serial_map(void) + { + #if defined(CONFIG_SERIAL_MPSC_CONSOLE) +@@ -114,10 +114,10 @@ static void __init ppc7d_early_serial_map(void) + if (early_serial_setup(&serial_req) != 0) + printk(KERN_ERR "Early serial init of port 1 failed\n"); + #else +-#error CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG has no supported CONFIG_SERIAL_XXX ++#error CONFIG_SERIAL_TEXT_DEBUG has no supported CONFIG_SERIAL_XXX + #endif + } +-#endif /* CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG */ ++#endif /* CONFIG_SERIAL_TEXT_DEBUG */ + + /***************************************************************************** + * Low-level board support code +@@ -1460,18 +1460,16 @@ void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + PPC7D_CPLD_COMS_COM4_TXEN, PPC7D_CPLD_COMS); + #endif /* CONFIG_SERIAL_MPSC */ + +-#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG) ++#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc7d_early_serial_map(); +-#ifdef CONFIG_SERIAL_TEXT_DEBUG + #if defined(CONFIG_SERIAL_MPSC_CONSOLE) + ppc_md.progress = mv64x60_mpsc_progress; + #elif defined(CONFIG_SERIAL_8250) + ppc_md.progress = gen550_progress; + #else +-#error CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG has no supported CONFIG_SERIAL_XXX ++#error CONFIG_SERIAL_TEXT_DEBUG has no supported CONFIG_SERIAL_XXX + #endif /* CONFIG_SERIAL_8250 */ + #endif /* CONFIG_SERIAL_TEXT_DEBUG */ +-#endif /* CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG */ + + /* Enable write access to user flash. This is necessary for + * flash probe. +diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c +index 3352fae..f3c9bcd 100644 +--- a/arch/ppc/platforms/sandpoint.c ++++ b/arch/ppc/platforms/sandpoint.c +@@ -95,9 +95,9 @@ + #include + #include + #include +-#include + #include + ++#include + #include "sandpoint.h" + + /* Set non-zero if an X2 Sandpoint detected. */ +@@ -730,9 +730,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + ppc_md.nvram_read_val = todc_mc146818_read_val; + ppc_md.nvram_write_val = todc_mc146818_write_val; + +-#ifdef CONFIG_KGDB +- ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +-#endif + #ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; + #endif +diff --git a/arch/ppc/platforms/spruce.c b/arch/ppc/platforms/spruce.c +index f4de50b..438b5dd 100644 +--- a/arch/ppc/platforms/spruce.c ++++ b/arch/ppc/platforms/spruce.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -38,9 +39,9 @@ + #include + #include + #include +-#include + + #include ++#include + + #include "spruce.h" + +@@ -179,30 +180,42 @@ spruce_early_serial_map(void) + serial_req.membase = (u_char *)UART0_IO_BASE; + serial_req.regshift = 0; + +-#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG) +- gen550_init(0, &serial_req); +-#endif + #ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&serial_req) != 0) + printk("Early serial init of port 0 failed\n"); + #endif ++#ifdef CONFIG_SERIAL_TEXT_DEBUG ++ gen550_init(0, &serial_req); ++#endif + + /* Assume early_serial_setup() doesn't modify serial_req */ + serial_req.line = 1; + serial_req.irq = UART1_INT; + serial_req.membase = (u_char *)UART1_IO_BASE; + +-#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG) +- gen550_init(1, &serial_req); +-#endif + #ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&serial_req) != 0) + printk("Early serial init of port 1 failed\n"); + #endif ++#ifdef CONFIG_SERIAL_TEXT_DEBUG ++ gen550_init(1, &serial_req); ++#endif ++#ifdef CONFIG_KGDB_8250 ++ kgdb8250_ready = 1; ++ kgdb8250_arch_init(); ++#endif + } + + TODC_ALLOC(); + ++#ifdef CONFIG_KGDB_8250 ++static int kgdb8250_ready; ++int kgdb8250_early_debug_ready(void) ++{ ++ return kgdb8250_ready; ++} ++#endif ++ + static void __init + spruce_setup_arch(void) + { +@@ -317,7 +330,4 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + #ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; + #endif /* CONFIG_SERIAL_TEXT_DEBUG */ +-#ifdef CONFIG_KGDB +- ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +-#endif + } +diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile +index 543795b..7794f8f 100644 +--- a/arch/ppc/syslib/Makefile ++++ b/arch/ppc/syslib/Makefile +@@ -78,7 +78,6 @@ obj-$(CONFIG_PCI_8260) += m82xx_pci.o pci_auto.o + obj-$(CONFIG_8260_PCI9) += m8260_pci_erratum9.o + obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o + ifeq ($(CONFIG_PPC_GEN550),y) +-obj-$(CONFIG_KGDB) += gen550_kgdb.o gen550_dbg.o + obj-$(CONFIG_SERIAL_TEXT_DEBUG) += gen550_dbg.o + endif + ifeq ($(CONFIG_SERIAL_MPSC_CONSOLE),y) +diff --git a/arch/ppc/syslib/gen550.h b/arch/ppc/syslib/gen550.h +index 5254d3c..edd6d33 100644 +--- a/arch/ppc/syslib/gen550.h ++++ b/arch/ppc/syslib/gen550.h +@@ -11,4 +11,3 @@ + + extern void gen550_progress(char *, unsigned short); + extern void gen550_init(int, struct uart_port *); +-extern void gen550_kgdb_map_scc(void); +diff --git a/arch/ppc/syslib/gen550_kgdb.c b/arch/ppc/syslib/gen550_kgdb.c +deleted file mode 100644 +index 987cc04..0000000 +--- a/arch/ppc/syslib/gen550_kgdb.c ++++ /dev/null +@@ -1,83 +0,0 @@ +-/* +- * Generic 16550 kgdb support intended to be useful on a variety +- * of platforms. To enable this support, it is necessary to set +- * the CONFIG_GEN550 option. Any virtual mapping of the serial +- * port(s) to be used can be accomplished by setting +- * ppc_md.early_serial_map to a platform-specific mapping function. +- * +- * Adapted from ppc4xx_kgdb.c. +- * +- * Author: Matt Porter +- * +- * 2002-2004 (c) MontaVista Software, Inc. This file is licensed under +- * the terms of the GNU General Public License version 2. This program +- * is licensed "as is" without any warranty of any kind, whether express +- * or implied. +- */ +- +-#include +-#include +- +-#include +- +-extern unsigned long serial_init(int, void *); +-extern unsigned long serial_getc(unsigned long); +-extern unsigned long serial_putc(unsigned long, unsigned char); +- +-#if defined(CONFIG_KGDB_TTYS0) +-#define KGDB_PORT 0 +-#elif defined(CONFIG_KGDB_TTYS1) +-#define KGDB_PORT 1 +-#elif defined(CONFIG_KGDB_TTYS2) +-#define KGDB_PORT 2 +-#elif defined(CONFIG_KGDB_TTYS3) +-#define KGDB_PORT 3 +-#else +-#error "invalid kgdb_tty port" +-#endif +- +-static volatile unsigned int kgdb_debugport; +- +-void putDebugChar(unsigned char c) +-{ +- if (kgdb_debugport == 0) +- kgdb_debugport = serial_init(KGDB_PORT, NULL); +- +- serial_putc(kgdb_debugport, c); +-} +- +-int getDebugChar(void) +-{ +- if (kgdb_debugport == 0) +- kgdb_debugport = serial_init(KGDB_PORT, NULL); +- +- return(serial_getc(kgdb_debugport)); +-} +- +-void kgdb_interruptible(int enable) +-{ +- return; +-} +- +-void putDebugString(char* str) +-{ +- while (*str != '\0') { +- putDebugChar(*str); +- str++; +- } +- putDebugChar('\r'); +- return; +-} +- +-/* +- * Note: gen550_init() must be called already on the port we are going +- * to use. +- */ +-void +-gen550_kgdb_map_scc(void) +-{ +- printk(KERN_DEBUG "kgdb init\n"); +- if (ppc_md.early_serial_map) +- ppc_md.early_serial_map(); +- kgdb_debugport = serial_init(KGDB_PORT, NULL); +-} +diff --git a/arch/ppc/syslib/ibm44x_common.c b/arch/ppc/syslib/ibm44x_common.c +index 01f99b4..232df69 100644 +--- a/arch/ppc/syslib/ibm44x_common.c ++++ b/arch/ppc/syslib/ibm44x_common.c +@@ -192,9 +192,6 @@ void __init ibm44x_platform_init(unsigned long r3, unsigned long r4, unsigned lo + #ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; + #endif /* CONFIG_SERIAL_TEXT_DEBUG */ +-#ifdef CONFIG_KGDB +- ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +-#endif + + /* + * The Abatron BDI JTAG debugger does not tolerate others +diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c +index 2744b8a..56e9ca1 100644 +--- a/arch/ppc/syslib/mv64x60.c ++++ b/arch/ppc/syslib/mv64x60.c +@@ -242,6 +242,12 @@ static struct resource mv64x60_mpsc0_resources[] = { + .end = MV64x60_IRQ_SDMA_0, + .flags = IORESOURCE_IRQ, + }, ++ [4] = { ++ .name = "mpsc 0 irq", ++ .start = MV64x60_IRQ_MPSC_0, ++ .end = MV64x60_IRQ_MPSC_0, ++ .flags = IORESOURCE_IRQ, ++ }, + }; + + static struct platform_device mpsc0_device = { +@@ -299,6 +305,12 @@ static struct resource mv64x60_mpsc1_resources[] = { + .end = MV64360_IRQ_SDMA_1, + .flags = IORESOURCE_IRQ, + }, ++ [4] = { ++ .name = "mpsc 1 irq", ++ .start = MV64360_IRQ_MPSC_1, ++ .end = MV64360_IRQ_MPSC_1, ++ .flags = IORESOURCE_IRQ, ++ }, + }; + + static struct platform_device mpsc1_device = { +@@ -1462,12 +1474,48 @@ mv64x60_pd_fixup(struct mv64x60_handle *bh, struct platform_device *pd_devs[], + static int __init + mv64x60_add_pds(void) + { +- return platform_add_devices(mv64x60_pd_devs, +- ARRAY_SIZE(mv64x60_pd_devs)); ++ int i; ++ int ret = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(mv64x60_pd_devs); i++) { ++ if (mv64x60_pd_devs[i]) ++ ret = platform_device_register(mv64x60_pd_devs[i]); ++ ++ if (ret) { ++ while (--i >= 0) ++ platform_device_unregister(mv64x60_pd_devs[i]); ++ break; ++ } ++ } ++ return ret; + } + arch_initcall(mv64x60_add_pds); + + /* ++ * mv64x60_early_get_pdev_data() ++ * ++ * Get the data associated with a platform device by name and number. ++ */ ++struct platform_device *__init ++mv64x60_early_get_pdev_data(const char *name, int id, int remove) ++{ ++ int i; ++ struct platform_device *pdev; ++ ++ for (i = 0; i < ARRAY_SIZE(mv64x60_pd_devs); i++) { ++ pdev = mv64x60_pd_devs[i]; ++ if (pdev && ++ pdev->id == id && ++ !strcmp(pdev->name, name)) { ++ if (remove) ++ mv64x60_pd_devs[i] = NULL; ++ return pdev; ++ } ++ } ++ return NULL; ++} ++ ++/* + ***************************************************************************** + * + * GT64260-Specific Routines +@@ -1794,12 +1842,16 @@ gt64260a_chip_specific_init(struct mv64x60_handle *bh, + mv64x60_mpsc0_pdata.cache_mgmt = 1; + mv64x60_mpsc1_pdata.mirror_regs = 1; + mv64x60_mpsc1_pdata.cache_mgmt = 1; +- +- if ((r = platform_get_resource(&mpsc1_device, IORESOURCE_IRQ, 0)) +- != NULL) { ++ r = platform_get_resource(&mpsc1_device, IORESOURCE_IRQ, 0); ++ if (r != NULL) { + r->start = MV64x60_IRQ_SDMA_0; + r->end = MV64x60_IRQ_SDMA_0; + } ++ r = platform_get_resource(&mpsc1_device, IORESOURCE_IRQ, 1); ++ if (r != NULL) { ++ r->start = GT64260_IRQ_MPSC_1; ++ r->end = GT64260_IRQ_MPSC_1; ++ } + #endif + } + +diff --git a/arch/ppc/syslib/mv64x60_dbg.c b/arch/ppc/syslib/mv64x60_dbg.c +index e187626..19c7ed6 100644 +--- a/arch/ppc/syslib/mv64x60_dbg.c ++++ b/arch/ppc/syslib/mv64x60_dbg.c +@@ -34,7 +34,7 @@ static struct mv64x60_handle mv64x60_dbg_bh; + void + mv64x60_progress_init(u32 base) + { +- mv64x60_dbg_bh.v_base = base; ++ mv64x60_dbg_bh.v_base = (void *)base; + return; + } + +@@ -69,53 +69,3 @@ mv64x60_mpsc_progress(char *s, unsigned short hex) + return; + } + #endif /* CONFIG_SERIAL_TEXT_DEBUG */ +- +- +-#if defined(CONFIG_KGDB) +- +-#if defined(CONFIG_KGDB_TTYS0) +-#define KGDB_PORT 0 +-#elif defined(CONFIG_KGDB_TTYS1) +-#define KGDB_PORT 1 +-#else +-#error "Invalid kgdb_tty port" +-#endif +- +-void +-putDebugChar(unsigned char c) +-{ +- mv64x60_polled_putc(KGDB_PORT, (char)c); +-} +- +-int +-getDebugChar(void) +-{ +- unsigned char c; +- +- while (!mv64x60_polled_getc(KGDB_PORT, &c)); +- return (int)c; +-} +- +-void +-putDebugString(char* str) +-{ +- while (*str != '\0') { +- putDebugChar(*str); +- str++; +- } +- putDebugChar('\r'); +- return; +-} +- +-void +-kgdb_interruptible(int enable) +-{ +-} +- +-void +-kgdb_map_scc(void) +-{ +- if (ppc_md.early_serial_map) +- ppc_md.early_serial_map(); +-} +-#endif /* CONFIG_KGDB */ +diff --git a/arch/ppc/syslib/ppc4xx_setup.c b/arch/ppc/syslib/ppc4xx_setup.c +index debe14c..c64c96d 100644 +--- a/arch/ppc/syslib/ppc4xx_setup.c ++++ b/arch/ppc/syslib/ppc4xx_setup.c +@@ -32,7 +32,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/include/asm-powerpc/kgdb.h b/include/asm-powerpc/kgdb.h +index b617dac..1399caf 100644 +--- a/include/asm-powerpc/kgdb.h ++++ b/include/asm-powerpc/kgdb.h +@@ -1,57 +1,65 @@ + /* +- * kgdb.h: Defines and declarations for serial line source level +- * remote debugging of the Linux kernel using gdb. ++ * include/asm-powerpc/kgdb.h + * ++ * The PowerPC (32/64) specific defines / externs for KGDB. Based on ++ * the previous 32bit and 64bit specific files, which had the following ++ * copyrights: ++ * ++ * PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com) ++ * PPC Mods (C) 2004 Tom Rini (trini@mvista.com) ++ * PPC Mods (C) 2003 John Whitney (john.whitney@timesys.com) + * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu) + * ++ * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) ++ * Author: Tom Rini ++ * ++ * 2006 (c) MontaVista Software, Inc. This file is licensed under ++ * the terms of the GNU General Public License version 2. This program ++ * is licensed "as is" without any warranty of any kind, whether express ++ * or implied. + */ + #ifdef __KERNEL__ +-#ifndef _PPC_KGDB_H +-#define _PPC_KGDB_H ++#ifndef __POWERPC_KGDB_H__ ++#define __POWERPC_KGDB_H__ + + #ifndef __ASSEMBLY__ + +-/* Things specific to the gen550 backend. */ +-struct uart_port; +- +-extern void gen550_progress(char *, unsigned short); +-extern void gen550_kgdb_map_scc(void); +-extern void gen550_init(int, struct uart_port *); +- +-/* Things specific to the pmac backend. */ +-extern void zs_kgdb_hook(int tty_num); +- +-/* To init the kgdb engine. (called by serial hook)*/ +-extern void set_debug_traps(void); +- +-/* To enter the debugger explicitly. */ +-extern void breakpoint(void); +- +-/* For taking exceptions +- * these are defined in traps.c +- */ +-extern int (*debugger)(struct pt_regs *regs); +-extern int (*debugger_bpt)(struct pt_regs *regs); +-extern int (*debugger_sstep)(struct pt_regs *regs); +-extern int (*debugger_iabr_match)(struct pt_regs *regs); +-extern int (*debugger_dabr_match)(struct pt_regs *regs); +-extern void (*debugger_fault_handler)(struct pt_regs *regs); +- +-/* What we bring to the party */ +-int kgdb_bpt(struct pt_regs *regs); +-int kgdb_sstep(struct pt_regs *regs); +-void kgdb(struct pt_regs *regs); +-int kgdb_iabr_match(struct pt_regs *regs); +-int kgdb_dabr_match(struct pt_regs *regs); ++#define BREAK_INSTR_SIZE 4 ++#define BUFMAX ((NUMREGBYTES * 2) + 512) ++#define OUTBUFMAX ((NUMREGBYTES * 2) + 512) ++static inline void arch_kgdb_breakpoint(void) ++{ ++ asm(".long 0x7d821008"); /* twge r2, r2 */ ++} ++#define CACHE_FLUSH_IS_SAFE 1 + ++/* The number bytes of registers we have to save depends on a few ++ * things. For 64bit we default to not including vector registers and ++ * vector state registers. */ ++#ifdef CONFIG_PPC64 + /* +- * external low-level support routines (ie macserial.c) ++ * 64 bit (8 byte) registers: ++ * 32 gpr, 32 fpr, nip, msr, link, ctr ++ * 32 bit (4 byte) registers: ++ * ccr, xer, fpscr + */ +-extern void kgdb_interruptible(int); /* control interrupts from serial */ +-extern void putDebugChar(char); /* write a single character */ +-extern char getDebugChar(void); /* read and return a single char */ +- ++#define NUMREGBYTES ((68 * 8) + (3 * 4)) ++#define NUMCRITREGBYTES 184 ++#else /* CONFIG_PPC32 */ ++/* On non-E500 family PPC32 we determine the size by picking the last ++ * register we need, but on E500 we skip sections so we list what we ++ * need to store, and add it up. */ ++#ifndef CONFIG_E500 ++#define MAXREG (PT_FPSCR+1) ++#else ++/* 32 GPRs (8 bytes), nip, msr, ccr, link, ctr, xer, acc (8 bytes), spefscr*/ ++#define MAXREG ((32*2)+6+2+1) ++#endif ++#define NUMREGBYTES (MAXREG * sizeof(int)) ++/* CR/LR, R1, R2, R13-R31 inclusive. */ ++#define NUMCRITREGBYTES (23 * sizeof(int)) ++#endif /* 32/64 */ + #endif /* !(__ASSEMBLY__) */ +-#endif /* !(_PPC_KGDB_H) */ ++#endif /* !__POWERPC_KGDB_H__ */ + #endif /* __KERNEL__ */ +diff --git a/include/asm-ppc/kgdb.h b/include/asm-ppc/kgdb.h +index b617dac..7d6b8cd 100644 +--- a/include/asm-ppc/kgdb.h ++++ b/include/asm-ppc/kgdb.h +@@ -1,57 +1,18 @@ +-/* +- * kgdb.h: Defines and declarations for serial line source level +- * remote debugging of the Linux kernel using gdb. +- * +- * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu) +- * +- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) +- */ + #ifdef __KERNEL__ +-#ifndef _PPC_KGDB_H +-#define _PPC_KGDB_H +- ++#ifndef __PPC_KGDB_H__ ++#define __PPC_KGDB_H__ ++#include + #ifndef __ASSEMBLY__ +- +-/* Things specific to the gen550 backend. */ +-struct uart_port; +- +-extern void gen550_progress(char *, unsigned short); +-extern void gen550_kgdb_map_scc(void); +-extern void gen550_init(int, struct uart_port *); +- +-/* Things specific to the pmac backend. */ +-extern void zs_kgdb_hook(int tty_num); +- +-/* To init the kgdb engine. (called by serial hook)*/ +-extern void set_debug_traps(void); +- +-/* To enter the debugger explicitly. */ +-extern void breakpoint(void); +- +-/* For taking exceptions +- * these are defined in traps.c +- */ +-extern int (*debugger)(struct pt_regs *regs); ++ /* For taking exceptions ++ * these are defined in traps.c ++ */ ++struct pt_regs; ++extern void (*debugger)(struct pt_regs *regs); + extern int (*debugger_bpt)(struct pt_regs *regs); + extern int (*debugger_sstep)(struct pt_regs *regs); + extern int (*debugger_iabr_match)(struct pt_regs *regs); + extern int (*debugger_dabr_match)(struct pt_regs *regs); + extern void (*debugger_fault_handler)(struct pt_regs *regs); +- +-/* What we bring to the party */ +-int kgdb_bpt(struct pt_regs *regs); +-int kgdb_sstep(struct pt_regs *regs); +-void kgdb(struct pt_regs *regs); +-int kgdb_iabr_match(struct pt_regs *regs); +-int kgdb_dabr_match(struct pt_regs *regs); +- +-/* +- * external low-level support routines (ie macserial.c) +- */ +-extern void kgdb_interruptible(int); /* control interrupts from serial */ +-extern void putDebugChar(char); /* write a single character */ +-extern char getDebugChar(void); /* read and return a single char */ +- +-#endif /* !(__ASSEMBLY__) */ +-#endif /* !(_PPC_KGDB_H) */ ++#endif /* !__ASSEMBLY__ */ ++#endif /* __PPC_KGDB_H__ */ + #endif /* __KERNEL__ */ +diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h +index a20b499..ffead63 100644 +--- a/include/asm-ppc/machdep.h ++++ b/include/asm-ppc/machdep.h +@@ -68,9 +68,7 @@ struct machdep_calls { + unsigned long (*find_end_of_memory)(void); + void (*setup_io_mappings)(void); + +- void (*early_serial_map)(void); + void (*progress)(char *, unsigned short); +- void (*kgdb_map_scc)(void); + + unsigned char (*nvram_read_val)(int addr); + void (*nvram_write_val)(int addr, unsigned char val); +diff --git a/include/asm-ppc/mv64x60.h b/include/asm-ppc/mv64x60.h +index 2963d6a..f50c3eb 100644 +--- a/include/asm-ppc/mv64x60.h ++++ b/include/asm-ppc/mv64x60.h +@@ -340,6 +340,8 @@ u32 mv64x60_calc_mem_size(struct mv64x60_handle *bh, + + void mv64x60_progress_init(u32 base); + void mv64x60_mpsc_progress(char *s, unsigned short hex); ++struct platform_device *mv64x60_early_get_pdev_data(const char *name, ++ int id, int remove); + + extern struct mv64x60_32bit_window + gt64260_32bit_windows[MV64x60_32BIT_WIN_COUNT]; +diff --git a/include/asm-ppc/mv64x60_defs.h b/include/asm-ppc/mv64x60_defs.h +index 5b0704a..3a31e9c 100644 +--- a/include/asm-ppc/mv64x60_defs.h ++++ b/include/asm-ppc/mv64x60_defs.h +@@ -57,7 +57,8 @@ + #define MV64x60_IRQ_I2C 37 + #define MV64x60_IRQ_BRG 39 + #define MV64x60_IRQ_MPSC_0 40 +-#define MV64x60_IRQ_MPSC_1 42 ++#define MV64360_IRQ_MPSC_1 41 ++#define GT64260_IRQ_MPSC_1 42 + #define MV64x60_IRQ_COMM 43 + #define MV64x60_IRQ_P0_GPP_0_7 56 + #define MV64x60_IRQ_P0_GPP_8_15 57 +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0039-Send-HCI_RESET-for-Broadcomm-2046-fix-for-LP-241749.patch +++ linux-2.6.24/patches/0039-Send-HCI_RESET-for-Broadcomm-2046-fix-for-LP-241749.patch @@ -0,0 +1,28 @@ +From b63972d89df6549baa33fa483b45769b0f23757a Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 8 Jul 2008 14:01:48 +0100 +Subject: [PATCH 039/170] Send HCI_RESET for Broadcomm 2046 fix for LP#241749 + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/241749 +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/bluetooth/hci_usb.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c +index 3c20751..c65e78c 100644 +--- a/drivers/bluetooth/hci_usb.c ++++ b/drivers/bluetooth/hci_usb.c +@@ -130,6 +130,9 @@ static struct usb_device_id blacklist_ids[] = { + /* HP laptop with Broadcom chip */ + { USB_DEVICE(0x03f0, 0x171d), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, + ++ ++ /* Broadcom 2046 */ ++ { USB_DEVICE(0x0a5c, 0x2151), .driver_info = HCI_RESET }, + /* Dell laptop with Broadcom chip */ + { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, + /* Dell Wireless 370 */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0137-Revert-UBUNTU-SAUCE-Always-use-SCO-protocol-disable-.patch +++ linux-2.6.24/patches/0137-Revert-UBUNTU-SAUCE-Always-use-SCO-protocol-disable-.patch @@ -0,0 +1,35 @@ +From 100342dfacfefa0bcb9239b2be968f589dbd1678 Mon Sep 17 00:00:00 2001 +From: Andres Salomon +Date: Mon, 20 Apr 2009 15:58:46 -0400 +Subject: [PATCH 137/170] Revert "UBUNTU: SAUCE: Always use SCO protocol (disable eSCO support)" + +This reverts commit 64cf2f7d98b02772c0df05e3614cd5cde34bcac5. + +This "fix" is incorrect; the proper fix is http://lkml.org/lkml/2008/2/27/105, +and is already upstream. + +Signed-off-by: Andres Salomon +--- + net/bluetooth/sco.c | 6 +----- + 1 files changed, 1 insertions(+), 5 deletions(-) + +diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c +index 153e7f6..93ad1aa 100644 +--- a/net/bluetooth/sco.c ++++ b/net/bluetooth/sco.c +@@ -200,11 +200,7 @@ static int sco_connect(struct sock *sk) + + err = -ENOMEM; + +- /* +- * Since eSCO seems currently broken, always use SCO (LP#39414). +- * type = lmp_esco_capable(hdev) ? ESCO_LINK : SCO_LINK; +- */ +- type = SCO_LINK; ++ type = lmp_esco_capable(hdev) ? ESCO_LINK : SCO_LINK; + + hcon = hci_connect(hdev, type, dst); + if (!hcon) +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0090-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook3.patch +++ linux-2.6.24/patches/0090-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook3.patch @@ -0,0 +1,38 @@ +From cd787d89bc4b425b5a088bb0100e771a167b2759 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 17 Dec 2008 11:48:38 -0500 +Subject: [PATCH 090/170] UBUNTU: NBK-Ubuntu-2.6.24-22.45netbook3 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 16 ++++++++++++++++ + 1 files changed, 16 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index e8a1f92..249aaf9 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,19 @@ ++linux (2.6.24-22.45netbook3) hardy; urgency=low ++ ++ [Upstream Kernel Changes] ++ ++ * x86: fix: s2ram + P4 + tsc = annoyance ++ - LP: #304247 ++ ++ [Michael Frey] ++ ++ * Elantech ps/2 touchpad driver. LP: #308752 ++ * Patch to ps/2 driver to support new Elantech touchpad. ++ * Updated Ericsson mbm 3G module driver LP: #308765 ++ * Turn on Elantech PS/2 touchpad option ++ ++ -- Michael Frey Wed, 17 Dec 2008 11:41:32 -0500 ++ + linux (2.6.24-22.45netbook2) hardy; urgency=low + + [Upstream Kernel Changes] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0083-Fix-for-suspend-resume-LP-284062.patch +++ linux-2.6.24/patches/0083-Fix-for-suspend-resume-LP-284062.patch @@ -0,0 +1,328 @@ +From 29605e804574fc2dfc1e640f660a928cd95fb23e Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Thu, 11 Dec 2008 11:24:03 -0800 +Subject: [PATCH 083/170] Fix for suspend / resume (LP: 284062) + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/284062 +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/clocksource/acpi_pm.c | 21 ++++++++++----------- + kernel/time/clockevents.c | 12 +++++++++++- + kernel/time/tick-broadcast.c | 21 ++++++++++++++------- + kernel/time/tick-common.c | 14 ++++++++------ + kernel/time/tick-internal.h | 9 +++++++++ + kernel/time/tick-sched.c | 11 +++++++---- + 6 files changed, 59 insertions(+), 29 deletions(-) + +diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c +index 5564fde..9cab8c1 100644 +--- a/drivers/clocksource/acpi_pm.c ++++ b/drivers/clocksource/acpi_pm.c +@@ -178,11 +178,13 @@ static int verify_pmtmr_rate(void) + + /* Number of monotonicity checks to perform during initialization */ + #define ACPI_PM_MONOTONICITY_CHECKS 10 ++/* Number of reads we try to get two different values */ ++#define ACPI_PM_READ_CHECKS 10000 + + static int __init init_acpi_pm_clocksource(void) + { + cycle_t value1, value2; +- unsigned int i, j, good = 0; ++ unsigned int i, j = 0; + + if (!pmtmr_ioport) + return -ENODEV; +@@ -192,29 +194,26 @@ static int __init init_acpi_pm_clocksource(void) + + /* "verify" this timing source: */ + for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) { ++ udelay(100 * j); + value1 = clocksource_acpi_pm.read(); +- for (i = 0; i < 10000; i++) { ++ for (i = 0; i < ACPI_PM_READ_CHECKS; i++) { + value2 = clocksource_acpi_pm.read(); + if (value2 == value1) + continue; + if (value2 > value1) +- good++; + break; + if ((value2 < value1) && ((value2) < 0xFFF)) +- good++; + break; + printk(KERN_INFO "PM-Timer had inconsistent results:" + " 0x%#llx, 0x%#llx - aborting.\n", + value1, value2); + return -EINVAL; + } +- udelay(300 * i); +- } +- +- if (good != ACPI_PM_MONOTONICITY_CHECKS) { +- printk(KERN_INFO "PM-Timer failed consistency check " +- " (0x%#llx) - aborting.\n", value1); +- return -ENODEV; ++ if (i == ACPI_PM_READ_CHECKS) { ++ printk(KERN_INFO "PM-Timer failed consistency check " ++ " (0x%#llx) - aborting.\n", value1); ++ return -ENODEV; ++ } + } + + if (verify_pmtmr_rate() != 0) +diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c +index 54872fd..52a2187 100644 +--- a/kernel/time/clockevents.c ++++ b/kernel/time/clockevents.c +@@ -67,6 +67,16 @@ void clockevents_set_mode(struct clock_event_device *dev, + } + + /** ++ * clockevents_shutdown - shutdown the device and clear next_event ++ * @dev: device to shutdown ++ */ ++void clockevents_shutdown(struct clock_event_device *dev) ++{ ++ clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN); ++ dev->next_event.tv64 = KTIME_MAX; ++} ++ ++/** + * clockevents_program_event - Reprogram the clock event device. + * @expires: absolute expiry time (monotonic clock) + * +@@ -193,7 +203,7 @@ void clockevents_exchange_device(struct clock_event_device *old, + + if (new) { + BUG_ON(new->mode != CLOCK_EVT_MODE_UNUSED); +- clockevents_set_mode(new, CLOCK_EVT_MODE_SHUTDOWN); ++ clockevents_shutdown(new); + } + local_irq_restore(flags); + } +diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c +index cdd12e2..3756880 100644 +--- a/kernel/time/tick-broadcast.c ++++ b/kernel/time/tick-broadcast.c +@@ -237,9 +237,8 @@ static void tick_do_broadcast_on_off(void *why) + case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: + if (!cpu_isset(cpu, tick_broadcast_mask)) { + cpu_set(cpu, tick_broadcast_mask); +- if (td->mode == TICKDEV_MODE_PERIODIC) +- clockevents_set_mode(dev, +- CLOCK_EVT_MODE_SHUTDOWN); ++ if (bc->mode == TICKDEV_MODE_PERIODIC) ++ clockevents_shutdown(dev); + } + if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_FORCE) + dev->features |= CLOCK_EVT_FEAT_DUMMY; +@@ -247,7 +246,7 @@ static void tick_do_broadcast_on_off(void *why) + case CLOCK_EVT_NOTIFY_BROADCAST_OFF: + if (cpu_isset(cpu, tick_broadcast_mask)) { + cpu_clear(cpu, tick_broadcast_mask); +- if (td->mode == TICKDEV_MODE_PERIODIC) ++ if (bc->mode == TICKDEV_MODE_PERIODIC) + tick_setup_periodic(dev, 0); + } + break; +@@ -255,7 +254,7 @@ static void tick_do_broadcast_on_off(void *why) + + if (cpus_empty(tick_broadcast_mask)) { + if (!bc_stopped) +- clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); ++ clockevents_shutdown(bc); + } else if (bc_stopped) { + if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) + tick_broadcast_start_periodic(bc); +@@ -307,7 +306,7 @@ void tick_shutdown_broadcast(unsigned int *cpup) + + if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) { + if (bc && cpus_empty(tick_broadcast_mask)) +- clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); ++ clockevents_shutdown(bc); + } + + spin_unlock_irqrestore(&tick_broadcast_lock, flags); +@@ -322,7 +321,7 @@ void tick_suspend_broadcast(void) + + bc = tick_broadcast_device.evtdev; + if (bc) +- clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); ++ clockevents_shutdown(bc); + + spin_unlock_irqrestore(&tick_broadcast_lock, flags); + } +@@ -578,4 +577,12 @@ void tick_shutdown_broadcast_oneshot(unsigned int *cpup) + spin_unlock_irqrestore(&tick_broadcast_lock, flags); + } + ++/* ++ * Check, whether the broadcast device is in one shot mode ++ */ ++int tick_broadcast_oneshot_active(void) ++{ ++ return tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT; ++} ++ + #endif +diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c +index d106d61..2988678 100644 +--- a/kernel/time/tick-common.c ++++ b/kernel/time/tick-common.c +@@ -31,7 +31,7 @@ DEFINE_PER_CPU(struct tick_device, tick_cpu_device); + */ + ktime_t tick_next_period; + ktime_t tick_period; +-int tick_do_timer_cpu __read_mostly = -1; ++int tick_do_timer_cpu __read_mostly = TICK_DO_TIMER_BOOT; + DEFINE_SPINLOCK(tick_device_lock); + + /* +@@ -107,7 +107,8 @@ void tick_setup_periodic(struct clock_event_device *dev, int broadcast) + if (!tick_device_is_functional(dev)) + return; + +- if (dev->features & CLOCK_EVT_FEAT_PERIODIC) { ++ if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) && ++ !tick_broadcast_oneshot_active()) { + clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC); + } else { + unsigned long seq; +@@ -146,7 +147,7 @@ static void tick_setup_device(struct tick_device *td, + * If no cpu took the do_timer update, assign it to + * this cpu: + */ +- if (tick_do_timer_cpu == -1) { ++ if (tick_do_timer_cpu == TICK_DO_TIMER_BOOT) { + tick_do_timer_cpu = cpu; + tick_next_period = ktime_get(); + tick_period = ktime_set(0, NSEC_PER_SEC / HZ); +@@ -249,7 +250,7 @@ static int tick_check_new_device(struct clock_event_device *newdev) + * not give it back to the clockevents layer ! + */ + if (tick_is_broadcast_device(curdev)) { +- clockevents_set_mode(curdev, CLOCK_EVT_MODE_SHUTDOWN); ++ clockevents_shutdown(curdev); + curdev = NULL; + } + clockevents_exchange_device(curdev, newdev); +@@ -300,7 +301,8 @@ static void tick_shutdown(unsigned int *cpup) + if (*cpup == tick_do_timer_cpu) { + int cpu = first_cpu(cpu_online_map); + +- tick_do_timer_cpu = (cpu != NR_CPUS) ? cpu : -1; ++ tick_do_timer_cpu = (cpu != NR_CPUS) ? cpu : ++ TICK_DO_TIMER_NONE; + } + spin_unlock_irqrestore(&tick_device_lock, flags); + } +@@ -311,7 +313,7 @@ static void tick_suspend(void) + unsigned long flags; + + spin_lock_irqsave(&tick_device_lock, flags); +- clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_SHUTDOWN); ++ clockevents_shutdown(td->evtdev); + spin_unlock_irqrestore(&tick_device_lock, flags); + } + +diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h +index 26b04aa..1b4d173 100644 +--- a/kernel/time/tick-internal.h ++++ b/kernel/time/tick-internal.h +@@ -1,6 +1,10 @@ + /* + * tick internal variable and functions used by low/high res code + */ ++ ++#define TICK_DO_TIMER_NONE -1 ++#define TICK_DO_TIMER_BOOT -2 ++ + DECLARE_PER_CPU(struct tick_device, tick_cpu_device); + extern spinlock_t tick_device_lock; + extern ktime_t tick_next_period; +@@ -10,6 +14,8 @@ extern int tick_do_timer_cpu __read_mostly; + extern void tick_setup_periodic(struct clock_event_device *dev, int broadcast); + extern void tick_handle_periodic(struct clock_event_device *dev); + ++extern void clockevents_shutdown(struct clock_event_device *dev); ++ + /* + * NO_HZ / high resolution timer shared code + */ +@@ -29,6 +35,7 @@ extern void tick_broadcast_oneshot_control(unsigned long reason); + extern void tick_broadcast_switch_to_oneshot(void); + extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup); + extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc); ++extern int tick_broadcast_oneshot_active(void); + # else /* BROADCAST */ + static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) + { +@@ -37,6 +44,7 @@ static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) + static inline void tick_broadcast_oneshot_control(unsigned long reason) { } + static inline void tick_broadcast_switch_to_oneshot(void) { } + static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { } ++static inline int tick_broadcast_oneshot_active(void) { return 0; } + # endif /* !BROADCAST */ + + #else /* !ONESHOT */ +@@ -66,6 +74,7 @@ static inline int tick_resume_broadcast_oneshot(struct clock_event_device *bc) + { + return 0; + } ++static inline int tick_broadcast_oneshot_active(void) { return 0; } + #endif /* !TICK_ONESHOT */ + + /* +diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c +index cb89fa8..a487027 100644 +--- a/kernel/time/tick-sched.c ++++ b/kernel/time/tick-sched.c +@@ -68,6 +68,9 @@ static void tick_do_update_jiffies64(ktime_t now) + incr * ticks); + } + do_timer(++ticks); ++ ++ /* Keep the tick_next_period variable up to date */ ++ tick_next_period = ktime_add(last_jiffies_update, tick_period); + } + write_sequnlock(&xtime_lock); + } +@@ -172,7 +175,7 @@ void tick_nohz_stop_sched_tick(void) + */ + if (unlikely(!cpu_online(cpu))) { + if (cpu == tick_do_timer_cpu) +- tick_do_timer_cpu = -1; ++ tick_do_timer_cpu = TICK_DO_TIMER_NONE; + } + + if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) +@@ -260,7 +263,7 @@ void tick_nohz_stop_sched_tick(void) + * invoked. + */ + if (cpu == tick_do_timer_cpu) +- tick_do_timer_cpu = -1; ++ tick_do_timer_cpu = TICK_DO_TIMER_NONE; + + ts->idle_sleeps++; + +@@ -419,7 +422,7 @@ static void tick_nohz_handler(struct clock_event_device *dev) + * this duty, then the jiffies update is still serialized by + * xtime_lock. + */ +- if (unlikely(tick_do_timer_cpu == -1)) ++ if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) + tick_do_timer_cpu = cpu; + + /* Check, if the jiffies need an update */ +@@ -522,7 +525,7 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) + * this duty, then the jiffies update is still serialized by + * xtime_lock. + */ +- if (unlikely(tick_do_timer_cpu == -1)) ++ if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) + tick_do_timer_cpu = cpu; + #endif + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0168-Ubuntu-NBK-Ubuntu-2.6.24-25.62netbook02.patch +++ linux-2.6.24/patches/0168-Ubuntu-NBK-Ubuntu-2.6.24-25.62netbook02.patch @@ -0,0 +1,29 @@ +From 5ca7aa60fd9a6a28844b0a96b1395bb4784b2b39 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Fri, 16 Oct 2009 09:44:21 -0500 +Subject: [PATCH 168/170] Ubuntu: NBK-Ubuntu-2.6.24-25.62netbook02 + +Signed-off-by: Steve Conklin +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 2d022f9..24ca475 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-25.62netbook02) netbook-common; urgency=low ++ ++ [Steve Conklin] ++ ++ * Make /proc/version_signature match the kernel version ++ ++ -- sconklin Fri, 16 Oct 2009 14:31:07 +0000 ++ + linux (2.6.24-25.62netbook01) netbook-common; urgency=low + + [ Steve Conklin] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0022-kgdb-Fix-SMP-NMI-kgdb_handle_exception-exit-race.patch +++ linux-2.6.24/patches/0022-kgdb-Fix-SMP-NMI-kgdb_handle_exception-exit-race.patch @@ -0,0 +1,92 @@ +From 998bbf327a70adb4435a10c8698b86d853cc7e31 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:45 -0500 +Subject: [PATCH 022/170] kgdb: Fix SMP NMI kgdb_handle_exception exit race + +Fix the problem of protecting the kgdb handle_exception exit +which had an NMI race condition, while trying to restore +normal system operation. + +There was a small window after the master processor sets +procindebug to zero but before it has set debugger_active +to zero where a non-master processor in an SMP system +could receive an NMI and re-enter the kgdb_wait() +loop. + +As long as the master processor sets the procindebug before +sending the cpu roundup the procindebug variable can also +be used to guard against the race condition. + +The kgdb_wait() function no longer needs to check +debugger_active because it is done in the arch specific code +and handled along with the nmi traps at the low level. +This also allows kgdb_wait() to exit correctly if it was +entered for some unknown reason due to a spurious NMI that +could not be handled by the arch specific code. + +Signed-off-by: Jason Wessel +--- + kernel/kgdb.c | 27 ++++++++------------------- + 1 files changed, 8 insertions(+), 19 deletions(-) + +diff --git a/kernel/kgdb.c b/kernel/kgdb.c +index 85b7e5b..4d1b3c2 100644 +--- a/kernel/kgdb.c ++++ b/kernel/kgdb.c +@@ -561,18 +561,6 @@ static void kgdb_wait(struct pt_regs *regs) + smp_wmb(); + atomic_set(&cpu_in_kgdb[cpu], 1); + +- /* +- * The primary CPU must be active to enter here, but this is +- * guard in case the primary CPU had not been selected if +- * this was an entry via nmi. +- */ +- while (atomic_read(&kgdb_active) == -1) +- cpu_relax(); +- +- /* Wait till primary CPU goes completely into the debugger. */ +- while (!atomic_read(&cpu_in_kgdb[atomic_read(&kgdb_active)])) +- cpu_relax(); +- + /* Wait till primary CPU is done with debugging */ + while (atomic_read(&passive_cpu_wait[cpu])) + cpu_relax(); +@@ -1447,18 +1435,18 @@ acquirelock: + atomic_set(&passive_cpu_wait[i], 1); + } + +-#ifdef CONFIG_SMP +- /* Signal the other CPUs to enter kgdb_wait() */ +- if ((!kgdb_single_step || !kgdb_contthread) && kgdb_do_roundup) +- kgdb_roundup_cpus(flags); +-#endif +- + /* + * spin_lock code is good enough as a barrier so we don't + * need one here: + */ + atomic_set(&cpu_in_kgdb[ks->cpu], 1); + ++#ifdef CONFIG_SMP ++ /* Signal the other CPUs to enter kgdb_wait() */ ++ if ((!kgdb_single_step || !kgdb_contthread) && kgdb_do_roundup) ++ kgdb_roundup_cpus(flags); ++#endif ++ + /* + * Wait for the other CPUs to be notified and be waiting for us: + */ +@@ -1514,7 +1502,8 @@ int kgdb_nmicallback(int cpu, void *regs) + { + #ifdef CONFIG_SMP + if (!atomic_read(&cpu_in_kgdb[cpu]) && +- atomic_read(&kgdb_active) != cpu) { ++ atomic_read(&kgdb_active) != cpu && ++ atomic_read(&cpu_in_kgdb[atomic_read(&kgdb_active)])) { + kgdb_wait((struct pt_regs *)regs); + return 0; + } +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0049-UBUNTU-NBK-Ubuntu-2.6.24-19.36netbook2.patch +++ linux-2.6.24/patches/0049-UBUNTU-NBK-Ubuntu-2.6.24-19.36netbook2.patch @@ -0,0 +1,30 @@ +From b39ddd927eef1b643516016b68d16bf797ef6437 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 29 Jul 2008 09:43:40 -0400 +Subject: [PATCH 049/170] UBUNTU: NBK-Ubuntu-2.6.24-19.36netbook2 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 35c0892..58e0df3 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-19.36netbook2) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * Added ich_laptop entries for Belmont and Chelsea ++ ++ -- Michael Frey Tue, 29 Jul 2008 09:39:13 -0400 ++ + linux (2.6.24-19.36netbook1) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0115-Turn-debian-binary-custom.d-lpia-patchset-0001-dabne.patch +++ linux-2.6.24/patches/0115-Turn-debian-binary-custom.d-lpia-patchset-0001-dabne.patch @@ -0,0 +1,6228 @@ +From b397467cd561e0908336032d51a168d79f25496b Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:31 +0100 +Subject: [PATCH 115/170] Turn debian/binary-custom.d/lpia/patchset/0001-dabney_thermal.patch into a commit. +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Andy Whitcroft + +commit 8e5ad88d3f1c7104a8ec64f81125215460021200 +Author: Loïc Minier +Date: Mon Nov 17 22:52:45 2008 +0100 + + Misc fixes for kgdb build + + - add kgdb config + - include asm-x86/processor.h + - fix asm-x86/processor.h to always export early_init + - fix 0001-dabney_thermal patch to apply against the config with KGDB + config + - fix reg names + +commit 5c158947412d2fe21a7a61b3df1e5ce74efe5d7f +Author: Amit Kucheria +Date: Thu Oct 30 14:03:39 2008 +0200 + + UBUNTU: SAUCE: Update lpia patches from moblin tree + Bug: #291457 + + Reworked the dabney thermal patch to apply cleanly to the Ubuntu tree + + Signed-off-by: Amit Kucheria + +commit 5a4ed17397cde9f5d0d19da51796f1dd0cb0d038 +Author: Amit Kucheria +Date: Tue Apr 1 00:41:31 2008 +0300 + + UBUNTU: LPIA: Integrate latest Dabney thermal patches + + Signed-off-by: Amit Kucheria +--- + Documentation/thermal/sysfs-api.txt | 247 ++ + .../lpia/patchset/0001-dabney_thermal.patch | 3076 -------------------- + drivers/Kconfig | 2 + + drivers/Makefile | 1 + + drivers/acpi/Kconfig | 1 + + drivers/acpi/bus.c | 25 + + drivers/acpi/fan.c | 90 +- + drivers/acpi/processor_core.c | 23 + + drivers/acpi/processor_thermal.c | 134 +- + drivers/acpi/thermal.c | 646 ++++- + drivers/acpi/video.c | 78 +- + drivers/misc/Kconfig | 10 + + drivers/misc/Makefile | 1 + + drivers/misc/intel_menlow.c | 527 ++++ + drivers/thermal/Kconfig | 16 + + drivers/thermal/Makefile | 6 + + drivers/thermal/thermal.c | 714 +++++ + include/acpi/acpi_bus.h | 2 + + include/acpi/processor.h | 6 +- + include/linux/thermal.h | 94 + + 20 files changed, 2453 insertions(+), 3246 deletions(-) + create mode 100644 Documentation/thermal/sysfs-api.txt + delete mode 100644 debian/binary-custom.d/lpia/patchset/0001-dabney_thermal.patch + create mode 100644 drivers/misc/intel_menlow.c + create mode 100644 drivers/thermal/Kconfig + create mode 100644 drivers/thermal/Makefile + create mode 100644 drivers/thermal/thermal.c + create mode 100644 include/linux/thermal.h + +diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt +new file mode 100644 +index 0000000..f627016 +--- /dev/null ++++ b/Documentation/thermal/sysfs-api.txt +@@ -0,0 +1,247 @@ ++Generic Thermal Sysfs driver How To ++========================= ++ ++Written by Sujith Thomas , Zhang Rui ++ ++Updated: 2 January 2008 ++ ++Copyright (c) 2008 Intel Corporation ++ ++ ++0. Introduction ++ ++The generic thermal sysfs provides a set of interfaces for thermal zone devices (sensors) ++and thermal cooling devices (fan, processor...) to register with the thermal management ++solution and to be a part of it. ++ ++This how-to focusses on enabling new thermal zone and cooling devices to participate ++in thermal management. ++This solution is platform independent and any type of thermal zone devices and ++cooling devices should be able to make use of the infrastructure. ++ ++The main task of the thermal sysfs driver is to expose thermal zone attributes as well ++as cooling device attributes to the user space. ++An intelligent thermal management application can make decisions based on inputs ++from thermal zone attributes (the current temperature and trip point temperature) ++and throttle appropriate devices. ++ ++[0-*] denotes any positive number starting from 0 ++[1-*] denotes any positive number starting from 1 ++ ++1. thermal sysfs driver interface functions ++ ++1.1 thermal zone device interface ++1.1.1 struct thermal_zone_device *thermal_zone_device_register(char *name, int trips, ++ void *devdata, struct thermal_zone_device_ops *ops) ++ ++ This interface function adds a new thermal zone device (sensor) to ++ /sys/class/thermal folder as thermal_zone[0-*]. ++ It tries to bind all the thermal cooling devices registered at the same time. ++ ++ name: the thermal zone name. ++ trips: the total number of trip points this thermal zone supports. ++ devdata: device private data ++ ops: thermal zone device callbacks. ++ .bind: bind the thermal zone device with a thermal cooling device. ++ .unbind: unbing the thermal zone device with a thermal cooling device. ++ .get_temp: get the current temperature of the thermal zone. ++ .get_mode: get the current mode (user/kernel) of the thermal zone. ++ "kernel" means thermal management is done in kernel. ++ "user" will prevent kernel thermal driver actions upon trip points ++ so that user applications can take charge of thermal management. ++ .set_mode: set the mode (user/kernel) of the thermal zone. ++ .get_trip_type: get the type of certain trip point. ++ .get_trip_temp: get the temperature above which the certain trip point ++ will be fired. ++ ++1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz) ++ ++ This interface function removes the thermal zone device. ++ It deletes the corresponding entry form /sys/class/thermal folder and unbind all ++ the thermal cooling devices it uses. ++ ++1.2 thermal cooling device interface ++1.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name, ++ void *devdata, struct thermal_cooling_device_ops *) ++ ++ This interface function adds a new thermal cooling device (fan/processor/...) to ++ /sys/class/thermal/ folder as cooling_device[0-*]. ++ It tries to bind itself to all the thermal zone devices register at the same time. ++ name: the cooling device name. ++ devdata: device private data. ++ ops: thermal cooling devices callbacks. ++ .get_max_state: get the Maximum throttle state of the cooling device. ++ .get_cur_state: get the Current throttle state of the cooling device. ++ .set_cur_state: set the Current throttle state of the cooling device. ++ ++1.2.2 void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) ++ ++ This interface function remove the thermal cooling device. ++ It deletes the corresponding entry form /sys/class/thermal folder and unbind ++ itself from all the thermal zone devices using it. ++ ++1.3 interface for binding a thermal zone device with a thermal cooling device ++1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, ++ int trip, struct thermal_cooling_device *cdev); ++ ++ This interface function bind a thermal cooling device to the certain trip point ++ of a thermal zone device. ++ This function is usually called in the thermal zone device .bind callback. ++ tz: the thermal zone device ++ cdev: thermal cooling device ++ trip: indicates which trip point the cooling devices is associated with ++ in this thermal zone. ++ ++1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, ++ int trip, struct thermal_cooling_device *cdev); ++ ++ This interface function unbind a thermal cooling device from the certain trip point ++ of a thermal zone device. ++ This function is usually called in the thermal zone device .unbind callback. ++ tz: the thermal zone device ++ cdev: thermal cooling device ++ trip: indicates which trip point the cooling devices is associated with ++ in this thermal zone. ++ ++2. sysfs attributes structure ++ ++RO read only value ++RW read/write value ++ ++All thermal sysfs attributes will be represented under /sys/class/thermal ++/sys/class/thermal/ ++ ++Thermal zone device sys I/F, created once it's registered: ++|thermal_zone[0-*]: ++ |-----type: Type of the thermal zone ++ |-----temp: Current temperature ++ |-----mode: Working mode of the thermal zone ++ |-----trip_point_[0-*]_temp: Trip point temperature ++ |-----trip_point_[0-*]_type: Trip point type ++ ++Thermal cooling device sys I/F, created once it's registered: ++|cooling_device[0-*]: ++ |-----type : Type of the cooling device(processor/fan/...) ++ |-----max_state: Maximum cooling state of the cooling device ++ |-----cur_state: Current cooling state of the cooling device ++ ++ ++These two dynamic attributes are created/removed in pairs. ++They represent the relationship between a thermal zone and its associated cooling device. ++They are created/removed for each ++thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful exection. ++ ++|thermal_zone[0-*] ++ |-----cdev[0-*]: The [0-*]th cooling device in the current thermal zone ++ |-----cdev[0-*]_trip_point: Trip point that cdev[0-*] is associated with ++ ++ ++*************************** ++* Thermal zone attributes * ++*************************** ++ ++type Strings which represent the thermal zone type. ++ This is given by thermal zone driver as part of registration. ++ Eg: "ACPI thermal zone" indicates it's a ACPI thermal device ++ RO ++ Optional ++ ++temp Current temperature as reported by thermal zone (sensor) ++ Unit: degree celsius ++ RO ++ Required ++ ++mode One of the predifned values in [kernel, user] ++ This file gives information about the algorithm ++ that is currently managing the thermal zone. ++ It can be either default kernel based algorithm ++ or user space application. ++ RW ++ Optional ++ kernel = Thermal management in kernel thermal zone driver. ++ user = Preventing kernel thermal zone driver actions upon ++ trip points so that user application can take full ++ charge of the thermal management. ++ ++trip_point_[0-*]_temp The temperature above which trip point will be fired ++ Unit: degree celsius ++ RO ++ Optional ++ ++trip_point_[0-*]_type Strings which indicate the type of the trip point ++ Eg. it can be one of critical, hot, passive, ++ active[0-*] for ACPI thermal zone. ++ RO ++ Optional ++ ++cdev[0-*] Sysfs link to the thermal cooling device node where the sys I/F ++ for cooling device throttling control represents. ++ RO ++ Optional ++ ++cdev[0-*]_trip_point The trip point with which cdev[0-*] is assocated in this thermal zone ++ -1 means the cooling device is not associated with any trip point. ++ RO ++ Optional ++ ++****************************** ++* Cooling device attributes * ++****************************** ++ ++type String which represents the type of device ++ eg: For generic ACPI: this should be "Fan", ++ "Processor" or "LCD" ++ eg. For memory controller device on intel_menlow platform: ++ this should be "Memory controller" ++ RO ++ Optional ++ ++max_state The maximum permissible cooling state of this cooling device. ++ RO ++ Required ++ ++cur_state The current cooling state of this cooling device. ++ the value can any integer numbers between 0 and max_state, ++ cur_state == 0 means no cooling ++ cur_state == max_state means the maximum cooling. ++ RW ++ Required ++ ++3. A simple implementation ++ ++ACPI thermal zone may support multiple trip points like critical/hot/passive/active. ++If an ACPI thermal zone supports critical, passive, active[0] and active[1] at the same time, ++it may register itself as a thermale_zone_device (thermal_zone1) with 4 trip points in all. ++It has one processor and one fan, which are both registered as thermal_cooling_device. ++If the processor is listed in _PSL method, and the fan is listed in _AL0 method, ++the sys I/F structure will be built like this: ++ ++/sys/class/thermal: ++ ++|thermal_zone1: ++ |-----type: ACPI thermal zone ++ |-----temp: 37 ++ |-----mode: kernel ++ |-----trip_point_0_temp: 100 ++ |-----trip_point_0_type: critical ++ |-----trip_point_1_temp: 80 ++ |-----trip_point_1_type: passive ++ |-----trip_point_2_temp: 70 ++ |-----trip_point_2_type: active[0] ++ |-----trip_point_3_temp: 60 ++ |-----trip_point_3_type: active[1] ++ |-----cdev0: --->/sys/class/thermal/cooling_device0 ++ |-----cdev0_trip_point: 1 /* cdev0 can be used for passive */ ++ |-----cdev1: --->/sys/class/thermal/cooling_device3 ++ |-----cdev1_trip_point: 2 /* cdev1 can be used for active[0]*/ ++ ++|cooling_device0: ++ |-----type: Processor ++ |-----max_state: 8 ++ |-----cur_state: 0 ++ ++|cooling_device3: ++ |-----type: Fan ++ |-----max_state: 2 ++ |-----cur_state: 0 ++ +diff --git a/debian/binary-custom.d/lpia/patchset/0001-dabney_thermal.patch b/debian/binary-custom.d/lpia/patchset/0001-dabney_thermal.patch +deleted file mode 100644 +index 850ebd3..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0001-dabney_thermal.patch ++++ /dev/null +@@ -1,3076 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt +-new file mode 100644 +-index 0000000..f627016 +---- /dev/null +-+++ b/Documentation/thermal/sysfs-api.txt +-@@ -0,0 +1,247 @@ +-+Generic Thermal Sysfs driver How To +-+========================= +-+ +-+Written by Sujith Thomas , Zhang Rui +-+ +-+Updated: 2 January 2008 +-+ +-+Copyright (c) 2008 Intel Corporation +-+ +-+ +-+0. Introduction +-+ +-+The generic thermal sysfs provides a set of interfaces for thermal zone devices (sensors) +-+and thermal cooling devices (fan, processor...) to register with the thermal management +-+solution and to be a part of it. +-+ +-+This how-to focusses on enabling new thermal zone and cooling devices to participate +-+in thermal management. +-+This solution is platform independent and any type of thermal zone devices and +-+cooling devices should be able to make use of the infrastructure. +-+ +-+The main task of the thermal sysfs driver is to expose thermal zone attributes as well +-+as cooling device attributes to the user space. +-+An intelligent thermal management application can make decisions based on inputs +-+from thermal zone attributes (the current temperature and trip point temperature) +-+and throttle appropriate devices. +-+ +-+[0-*] denotes any positive number starting from 0 +-+[1-*] denotes any positive number starting from 1 +-+ +-+1. thermal sysfs driver interface functions +-+ +-+1.1 thermal zone device interface +-+1.1.1 struct thermal_zone_device *thermal_zone_device_register(char *name, int trips, +-+ void *devdata, struct thermal_zone_device_ops *ops) +-+ +-+ This interface function adds a new thermal zone device (sensor) to +-+ /sys/class/thermal folder as thermal_zone[0-*]. +-+ It tries to bind all the thermal cooling devices registered at the same time. +-+ +-+ name: the thermal zone name. +-+ trips: the total number of trip points this thermal zone supports. +-+ devdata: device private data +-+ ops: thermal zone device callbacks. +-+ .bind: bind the thermal zone device with a thermal cooling device. +-+ .unbind: unbing the thermal zone device with a thermal cooling device. +-+ .get_temp: get the current temperature of the thermal zone. +-+ .get_mode: get the current mode (user/kernel) of the thermal zone. +-+ "kernel" means thermal management is done in kernel. +-+ "user" will prevent kernel thermal driver actions upon trip points +-+ so that user applications can take charge of thermal management. +-+ .set_mode: set the mode (user/kernel) of the thermal zone. +-+ .get_trip_type: get the type of certain trip point. +-+ .get_trip_temp: get the temperature above which the certain trip point +-+ will be fired. +-+ +-+1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz) +-+ +-+ This interface function removes the thermal zone device. +-+ It deletes the corresponding entry form /sys/class/thermal folder and unbind all +-+ the thermal cooling devices it uses. +-+ +-+1.2 thermal cooling device interface +-+1.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name, +-+ void *devdata, struct thermal_cooling_device_ops *) +-+ +-+ This interface function adds a new thermal cooling device (fan/processor/...) to +-+ /sys/class/thermal/ folder as cooling_device[0-*]. +-+ It tries to bind itself to all the thermal zone devices register at the same time. +-+ name: the cooling device name. +-+ devdata: device private data. +-+ ops: thermal cooling devices callbacks. +-+ .get_max_state: get the Maximum throttle state of the cooling device. +-+ .get_cur_state: get the Current throttle state of the cooling device. +-+ .set_cur_state: set the Current throttle state of the cooling device. +-+ +-+1.2.2 void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) +-+ +-+ This interface function remove the thermal cooling device. +-+ It deletes the corresponding entry form /sys/class/thermal folder and unbind +-+ itself from all the thermal zone devices using it. +-+ +-+1.3 interface for binding a thermal zone device with a thermal cooling device +-+1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, +-+ int trip, struct thermal_cooling_device *cdev); +-+ +-+ This interface function bind a thermal cooling device to the certain trip point +-+ of a thermal zone device. +-+ This function is usually called in the thermal zone device .bind callback. +-+ tz: the thermal zone device +-+ cdev: thermal cooling device +-+ trip: indicates which trip point the cooling devices is associated with +-+ in this thermal zone. +-+ +-+1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, +-+ int trip, struct thermal_cooling_device *cdev); +-+ +-+ This interface function unbind a thermal cooling device from the certain trip point +-+ of a thermal zone device. +-+ This function is usually called in the thermal zone device .unbind callback. +-+ tz: the thermal zone device +-+ cdev: thermal cooling device +-+ trip: indicates which trip point the cooling devices is associated with +-+ in this thermal zone. +-+ +-+2. sysfs attributes structure +-+ +-+RO read only value +-+RW read/write value +-+ +-+All thermal sysfs attributes will be represented under /sys/class/thermal +-+/sys/class/thermal/ +-+ +-+Thermal zone device sys I/F, created once it's registered: +-+|thermal_zone[0-*]: +-+ |-----type: Type of the thermal zone +-+ |-----temp: Current temperature +-+ |-----mode: Working mode of the thermal zone +-+ |-----trip_point_[0-*]_temp: Trip point temperature +-+ |-----trip_point_[0-*]_type: Trip point type +-+ +-+Thermal cooling device sys I/F, created once it's registered: +-+|cooling_device[0-*]: +-+ |-----type : Type of the cooling device(processor/fan/...) +-+ |-----max_state: Maximum cooling state of the cooling device +-+ |-----cur_state: Current cooling state of the cooling device +-+ +-+ +-+These two dynamic attributes are created/removed in pairs. +-+They represent the relationship between a thermal zone and its associated cooling device. +-+They are created/removed for each +-+thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful exection. +-+ +-+|thermal_zone[0-*] +-+ |-----cdev[0-*]: The [0-*]th cooling device in the current thermal zone +-+ |-----cdev[0-*]_trip_point: Trip point that cdev[0-*] is associated with +-+ +-+ +-+*************************** +-+* Thermal zone attributes * +-+*************************** +-+ +-+type Strings which represent the thermal zone type. +-+ This is given by thermal zone driver as part of registration. +-+ Eg: "ACPI thermal zone" indicates it's a ACPI thermal device +-+ RO +-+ Optional +-+ +-+temp Current temperature as reported by thermal zone (sensor) +-+ Unit: degree celsius +-+ RO +-+ Required +-+ +-+mode One of the predifned values in [kernel, user] +-+ This file gives information about the algorithm +-+ that is currently managing the thermal zone. +-+ It can be either default kernel based algorithm +-+ or user space application. +-+ RW +-+ Optional +-+ kernel = Thermal management in kernel thermal zone driver. +-+ user = Preventing kernel thermal zone driver actions upon +-+ trip points so that user application can take full +-+ charge of the thermal management. +-+ +-+trip_point_[0-*]_temp The temperature above which trip point will be fired +-+ Unit: degree celsius +-+ RO +-+ Optional +-+ +-+trip_point_[0-*]_type Strings which indicate the type of the trip point +-+ Eg. it can be one of critical, hot, passive, +-+ active[0-*] for ACPI thermal zone. +-+ RO +-+ Optional +-+ +-+cdev[0-*] Sysfs link to the thermal cooling device node where the sys I/F +-+ for cooling device throttling control represents. +-+ RO +-+ Optional +-+ +-+cdev[0-*]_trip_point The trip point with which cdev[0-*] is assocated in this thermal zone +-+ -1 means the cooling device is not associated with any trip point. +-+ RO +-+ Optional +-+ +-+****************************** +-+* Cooling device attributes * +-+****************************** +-+ +-+type String which represents the type of device +-+ eg: For generic ACPI: this should be "Fan", +-+ "Processor" or "LCD" +-+ eg. For memory controller device on intel_menlow platform: +-+ this should be "Memory controller" +-+ RO +-+ Optional +-+ +-+max_state The maximum permissible cooling state of this cooling device. +-+ RO +-+ Required +-+ +-+cur_state The current cooling state of this cooling device. +-+ the value can any integer numbers between 0 and max_state, +-+ cur_state == 0 means no cooling +-+ cur_state == max_state means the maximum cooling. +-+ RW +-+ Required +-+ +-+3. A simple implementation +-+ +-+ACPI thermal zone may support multiple trip points like critical/hot/passive/active. +-+If an ACPI thermal zone supports critical, passive, active[0] and active[1] at the same time, +-+it may register itself as a thermale_zone_device (thermal_zone1) with 4 trip points in all. +-+It has one processor and one fan, which are both registered as thermal_cooling_device. +-+If the processor is listed in _PSL method, and the fan is listed in _AL0 method, +-+the sys I/F structure will be built like this: +-+ +-+/sys/class/thermal: +-+ +-+|thermal_zone1: +-+ |-----type: ACPI thermal zone +-+ |-----temp: 37 +-+ |-----mode: kernel +-+ |-----trip_point_0_temp: 100 +-+ |-----trip_point_0_type: critical +-+ |-----trip_point_1_temp: 80 +-+ |-----trip_point_1_type: passive +-+ |-----trip_point_2_temp: 70 +-+ |-----trip_point_2_type: active[0] +-+ |-----trip_point_3_temp: 60 +-+ |-----trip_point_3_type: active[1] +-+ |-----cdev0: --->/sys/class/thermal/cooling_device0 +-+ |-----cdev0_trip_point: 1 /* cdev0 can be used for passive */ +-+ |-----cdev1: --->/sys/class/thermal/cooling_device3 +-+ |-----cdev1_trip_point: 2 /* cdev1 can be used for active[0]*/ +-+ +-+|cooling_device0: +-+ |-----type: Processor +-+ |-----max_state: 8 +-+ |-----cur_state: 0 +-+ +-+|cooling_device3: +-+ |-----type: Fan +-+ |-----max_state: 2 +-+ |-----cur_state: 0 +-+ +-diff --git a/drivers/Kconfig b/drivers/Kconfig +-index 3f8a231..d127a9a 100644 +---- a/drivers/Kconfig +-+++ b/drivers/Kconfig +-@@ -58,6 +58,8 @@ source "drivers/power/Kconfig" +- +- source "drivers/hwmon/Kconfig" +- +-+source "drivers/thermal/Kconfig" +-+ +- source "drivers/watchdog/Kconfig" +- +- source "drivers/ssb/Kconfig" +-diff --git a/drivers/Makefile b/drivers/Makefile +-index a5cfc61..e0013ee 100644 +---- a/drivers/Makefile +-+++ b/drivers/Makefile +-@@ -64,6 +64,7 @@ obj-y += i2c/ +- obj-$(CONFIG_W1) += w1/ +- obj-$(CONFIG_POWER_SUPPLY) += power/ +- obj-$(CONFIG_HWMON) += hwmon/ +-+obj-$(CONFIG_THERMAL) += thermal/ +- obj-$(CONFIG_WATCHDOG) += watchdog/ +- obj-$(CONFIG_PHONE) += telephony/ +- obj-$(CONFIG_MD) += md/ +-diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig +-index aa608a2..03bdbf9 100644 +---- a/drivers/acpi/Kconfig +-+++ b/drivers/acpi/Kconfig +-@@ -186,6 +186,7 @@ config ACPI_HOTPLUG_CPU +- config ACPI_THERMAL +- tristate "Thermal Zone" +- depends on ACPI_PROCESSOR +-+ select THERMAL +- default y +- help +- This driver adds support for ACPI thermal zones. Most mobile and +-diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c +-index f4487c3..34ba7c3 100644 +---- a/drivers/acpi/bus.c +-+++ b/drivers/acpi/bus.c +-@@ -122,6 +122,31 @@ int acpi_bus_get_status(struct acpi_device *device) +- +- EXPORT_SYMBOL(acpi_bus_get_status); +- +-+void acpi_bus_private_data_handler(acpi_handle handle, +-+ u32 function, void *context) +-+{ +-+ return; +-+} +-+EXPORT_SYMBOL(acpi_bus_private_data_handler); +-+ +-+int acpi_bus_get_private_data(acpi_handle handle, void **data) +-+{ +-+ acpi_status status = AE_OK; +-+ +-+ if (!*data) +-+ return -EINVAL; +-+ +-+ status = acpi_get_data(handle, acpi_bus_private_data_handler, data); +-+ if (ACPI_FAILURE(status) || !*data) { +-+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", +-+ handle)); +-+ return -ENODEV; +-+ } +-+ +-+ return 0; +-+} +-+EXPORT_SYMBOL(acpi_bus_get_private_data); +-+ +- /* -------------------------------------------------------------------------- +- Power Management +- -------------------------------------------------------------------------- */ +-diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c +-index a6e149d..f6e8165 100644 +---- a/drivers/acpi/fan.c +-+++ b/drivers/acpi/fan.c +-@@ -30,7 +30,7 @@ +- #include +- #include +- #include +-- +-+#include +- #include +- #include +- +-@@ -68,9 +68,55 @@ static struct acpi_driver acpi_fan_driver = { +- }, +- }; +- +-+/* thermal cooling device callbacks */ +-+static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf) +-+{ +-+ /* ACPI fan device only support two states: ON/OFF */ +-+ return sprintf(buf, "1\n"); +-+} +-+ +-+static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf) +-+{ +-+ struct acpi_device *device = cdev->devdata; +-+ int state; +-+ int result; +-+ +-+ if (!device) +-+ return -EINVAL; +-+ +-+ result = acpi_bus_get_power(device->handle, &state); +-+ if (result) +-+ return result; +-+ +-+ return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" : +-+ (state == ACPI_STATE_D0 ? "1" : "unknown")); +-+} +-+ +-+static int +-+fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) +-+{ +-+ struct acpi_device *device = cdev->devdata; +-+ int result; +-+ +-+ if (!device || (state != 0 && state != 1)) +-+ return -EINVAL; +-+ +-+ result = acpi_bus_set_power(device->handle, +-+ state ? ACPI_STATE_D0 : ACPI_STATE_D3); +-+ +-+ return result; +-+} +-+ +-+static struct thermal_cooling_device_ops fan_cooling_ops = { +-+ .get_max_state = fan_get_max_state, +-+ .get_cur_state = fan_get_cur_state, +-+ .set_cur_state = fan_set_cur_state, +-+}; +-+ +- /* -------------------------------------------------------------------------- +- FS Interface (/proc) +- -------------------------------------------------------------------------- */ +-+#ifdef CONFIG_ACPI_PROCFS +- +- static struct proc_dir_entry *acpi_fan_dir; +- +-@@ -171,7 +217,17 @@ static int acpi_fan_remove_fs(struct acpi_device *device) +- +- return 0; +- } +-+#else +-+static int acpi_fan_add_fs(struct acpi_device *device) +-+{ +-+ return 0; +-+} +- +-+static int acpi_fan_remove_fs(struct acpi_device *device) +-+{ +-+ return 0; +-+} +-+#endif +- /* -------------------------------------------------------------------------- +- Driver Interface +- -------------------------------------------------------------------------- */ +-@@ -179,9 +235,8 @@ static int acpi_fan_remove_fs(struct acpi_device *device) +- static int acpi_fan_add(struct acpi_device *device) +- { +- int result = 0; +-- struct acpi_fan *fan = NULL; +- int state = 0; +-- +-+ struct thermal_cooling_device *cdev; +- +- if (!device) +- return -EINVAL; +-@@ -199,6 +254,25 @@ static int acpi_fan_add(struct acpi_device *device) +- acpi_bus_set_power(device->handle, state); +- device->flags.force_power_state = 0; +- +-+ cdev = thermal_cooling_device_register("Fan", device, +-+ &fan_cooling_ops); +-+ if (cdev) +-+ printk(KERN_INFO PREFIX +-+ "%s is registered as cooling_device%d\n", +-+ device->dev.bus_id, cdev->id); +-+ else +-+ goto end; +-+ acpi_driver_data(device) = cdev; +-+ result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj, +-+ "thermal_cooling"); +-+ if (result) +-+ return result; +-+ +-+ result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj, +-+ "device"); +-+ if (result) +-+ return result; +-+ +- result = acpi_fan_add_fs(device); +- if (result) +- goto end; +-@@ -208,18 +282,20 @@ static int acpi_fan_add(struct acpi_device *device) +- !device->power.state ? "on" : "off"); +- +- end: +-- if (result) +-- kfree(fan); +-- +- return result; +- } +- +- static int acpi_fan_remove(struct acpi_device *device, int type) +- { +-- if (!device || !acpi_driver_data(device)) +-+ struct thermal_cooling_device *cdev = acpi_driver_data(device); +-+ +-+ if (!device || !cdev) +- return -EINVAL; +- +- acpi_fan_remove_fs(device); +-+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); +-+ sysfs_remove_link(&cdev->device.kobj, "device"); +-+ thermal_cooling_device_unregister(cdev); +- +- return 0; +- } +-diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c +-index c703eab..146b67d 100644 +---- a/drivers/acpi/processor_core.c +-+++ b/drivers/acpi/processor_core.c +-@@ -672,6 +672,24 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) +- +- acpi_processor_power_init(pr, device); +- +-+ pr->cdev = thermal_cooling_device_register("Processor", device, +-+ &processor_cooling_ops); +-+ if (pr->cdev) +-+ printk(KERN_INFO PREFIX +-+ "%s is registered as cooling_device%d\n", +-+ device->dev.bus_id, pr->cdev->id); +-+ else +-+ goto end; +-+ +-+ result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj, +-+ "thermal_cooling"); +-+ if (result) +-+ return result; +-+ result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, +-+ "device"); +-+ if (result) +-+ return result; +-+ +- if (pr->flags.throttling) { +- printk(KERN_INFO PREFIX "%s [%s] (supports", +- acpi_device_name(device), acpi_device_bid(device)); +-@@ -797,6 +815,11 @@ static int acpi_processor_remove(struct acpi_device *device, int type) +- +- acpi_processor_remove_fs(device); +- +-+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); +-+ sysfs_remove_link(&pr->cdev->device.kobj, "device"); +-+ thermal_cooling_device_unregister(pr->cdev); +-+ pr->cdev = NULL; +-+ +- processors[pr->id] = NULL; +- processor_device_array[pr->id] = NULL; +- kfree(pr); +-diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c +-index 06e6f3f..9cb43f5 100644 +---- a/drivers/acpi/processor_thermal.c +-+++ b/drivers/acpi/processor_thermal.c +-@@ -32,6 +32,7 @@ +- #include +- #include +- #include +-+#include +- +- #include +- +-@@ -93,6 +94,9 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr) +- * _any_ cpufreq driver and not only the acpi-cpufreq driver. +- */ +- +-+#define CPUFREQ_THERMAL_MIN_STEP 0 +-+#define CPUFREQ_THERMAL_MAX_STEP 3 +-+ +- static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS]; +- static unsigned int acpi_thermal_cpufreq_is_init = 0; +- +-@@ -109,8 +113,9 @@ static int acpi_thermal_cpufreq_increase(unsigned int cpu) +- if (!cpu_has_cpufreq(cpu)) +- return -ENODEV; +- +-- if (cpufreq_thermal_reduction_pctg[cpu] < 60) { +-- cpufreq_thermal_reduction_pctg[cpu] += 20; +-+ if (cpufreq_thermal_reduction_pctg[cpu] < +-+ CPUFREQ_THERMAL_MAX_STEP) { +-+ cpufreq_thermal_reduction_pctg[cpu]++; +- cpufreq_update_policy(cpu); +- return 0; +- } +-@@ -123,8 +128,9 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu) +- if (!cpu_has_cpufreq(cpu)) +- return -ENODEV; +- +-- if (cpufreq_thermal_reduction_pctg[cpu] > 20) +-- cpufreq_thermal_reduction_pctg[cpu] -= 20; +-+ if (cpufreq_thermal_reduction_pctg[cpu] > +-+ (CPUFREQ_THERMAL_MIN_STEP + 1)) +-+ cpufreq_thermal_reduction_pctg[cpu]--; +- else +- cpufreq_thermal_reduction_pctg[cpu] = 0; +- cpufreq_update_policy(cpu); +-@@ -143,7 +149,7 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb, +- +- max_freq = +- (policy->cpuinfo.max_freq * +-- (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100; +-+ (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100; +- +- cpufreq_verify_within_limits(policy, 0, max_freq); +- +-@@ -155,6 +161,32 @@ static struct notifier_block acpi_thermal_cpufreq_notifier_block = { +- .notifier_call = acpi_thermal_cpufreq_notifier, +- }; +- +-+static int cpufreq_get_max_state(unsigned int cpu) +-+{ +-+ if (!cpu_has_cpufreq(cpu)) +-+ return 0; +-+ +-+ return CPUFREQ_THERMAL_MAX_STEP; +-+} +-+ +-+static int cpufreq_get_cur_state(unsigned int cpu) +-+{ +-+ if (!cpu_has_cpufreq(cpu)) +-+ return 0; +-+ +-+ return cpufreq_thermal_reduction_pctg[cpu]; +-+} +-+ +-+static int cpufreq_set_cur_state(unsigned int cpu, int state) +-+{ +-+ if (!cpu_has_cpufreq(cpu)) +-+ return 0; +-+ +-+ cpufreq_thermal_reduction_pctg[cpu] = state; +-+ cpufreq_update_policy(cpu); +-+ return 0; +-+} +-+ +- void acpi_thermal_cpufreq_init(void) +- { +- int i; +-@@ -179,6 +211,20 @@ void acpi_thermal_cpufreq_exit(void) +- } +- +- #else /* ! CONFIG_CPU_FREQ */ +-+static int cpufreq_get_max_state(unsigned int cpu) +-+{ +-+ return 0; +-+} +-+ +-+static int cpufreq_get_cur_state(unsigned int cpu) +-+{ +-+ return 0; +-+} +-+ +-+static int cpufreq_set_cur_state(unsigned int cpu, int state) +-+{ +-+ return 0; +-+} +- +- static int acpi_thermal_cpufreq_increase(unsigned int cpu) +- { +-@@ -310,6 +356,84 @@ int acpi_processor_get_limit_info(struct acpi_processor *pr) +- return 0; +- } +- +-+/* thermal coolign device callbacks */ +-+static int acpi_processor_max_state(struct acpi_processor *pr) +-+{ +-+ int max_state = 0; +-+ +-+ /* +-+ * There exists four states according to +-+ * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3 +-+ */ +-+ max_state += cpufreq_get_max_state(pr->id); +-+ if (pr->flags.throttling) +-+ max_state += (pr->throttling.state_count -1); +-+ +-+ return max_state; +-+} +-+static int +-+processor_get_max_state(struct thermal_cooling_device *cdev, char *buf) +-+{ +-+ struct acpi_device *device = cdev->devdata; +-+ struct acpi_processor *pr = acpi_driver_data(device); +-+ +-+ if (!device || !pr) +-+ return -EINVAL; +-+ +-+ return sprintf(buf, "%d\n", acpi_processor_max_state(pr)); +-+} +-+ +-+static int +-+processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf) +-+{ +-+ struct acpi_device *device = cdev->devdata; +-+ struct acpi_processor *pr = acpi_driver_data(device); +-+ int cur_state; +-+ +-+ if (!device || !pr) +-+ return -EINVAL; +-+ +-+ cur_state = cpufreq_get_cur_state(pr->id); +-+ if (pr->flags.throttling) +-+ cur_state += pr->throttling.state; +-+ +-+ return sprintf(buf, "%d\n", cur_state); +-+} +-+ +-+static int +-+processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) +-+{ +-+ struct acpi_device *device = cdev->devdata; +-+ struct acpi_processor *pr = acpi_driver_data(device); +-+ int result = 0; +-+ int max_pstate; +-+ +-+ if (!device || !pr) +-+ return -EINVAL; +-+ +-+ max_pstate = cpufreq_get_max_state(pr->id); +-+ +-+ if (state > acpi_processor_max_state(pr)) +-+ return -EINVAL; +-+ +-+ if (state <= max_pstate) { +-+ if (pr->flags.throttling && pr->throttling.state) +-+ result = acpi_processor_set_throttling(pr, 0); +-+ cpufreq_set_cur_state(pr->id, state); +-+ } else { +-+ cpufreq_set_cur_state(pr->id, max_pstate); +-+ result = acpi_processor_set_throttling(pr, +-+ state - max_pstate); +-+ } +-+ return result; +-+} +-+ +-+struct thermal_cooling_device_ops processor_cooling_ops = { +-+ .get_max_state = processor_get_max_state, +-+ .get_cur_state = processor_get_cur_state, +-+ .set_cur_state = processor_set_cur_state, +-+}; +-+ +- /* /proc interface */ +- +- static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset) +-diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c +-index 5f79b44..73f276b 100644 +---- a/drivers/acpi/thermal.c +-+++ b/drivers/acpi/thermal.c +-@@ -43,7 +43,7 @@ +- #include +- #include +- #include +-- +-+#include +- #include +- #include +- +-@@ -65,9 +65,6 @@ +- #define ACPI_THERMAL_MAX_ACTIVE 10 +- #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65 +- +--#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10) +--#define CELSIUS_TO_KELVIN(t) ((t+273)*10) +-- +- #define _COMPONENT ACPI_THERMAL_COMPONENT +- ACPI_MODULE_NAME("thermal"); +- +-@@ -195,6 +192,8 @@ struct acpi_thermal { +- struct acpi_thermal_trips trips; +- struct acpi_handle_list devices; +- struct timer_list timer; +-+ struct thermal_zone_device *thermal_zone; +-+ int tz_enabled; +- struct mutex lock; +- }; +- +-@@ -321,173 +320,221 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode) +- return 0; +- } +- +--static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) +--{ +-- acpi_status status = AE_OK; +-- int i = 0; +-+#define ACPI_TRIPS_CRITICAL 0x01 +-+#define ACPI_TRIPS_HOT 0x02 +-+#define ACPI_TRIPS_PASSIVE 0x04 +-+#define ACPI_TRIPS_ACTIVE 0x08 +-+#define ACPI_TRIPS_DEVICES 0x10 +- +-+#define ACPI_TRIPS_REFRESH_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE) +-+#define ACPI_TRIPS_REFRESH_DEVICES ACPI_TRIPS_DEVICES +- +-- if (!tz) +-- return -EINVAL; +-+#define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \ +-+ ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \ +-+ ACPI_TRIPS_DEVICES) +- +-- /* Critical Shutdown (required) */ +-- +-- status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, +-- &tz->trips.critical.temperature); +-- if (ACPI_FAILURE(status)) { +-- tz->trips.critical.flags.valid = 0; +-- ACPI_EXCEPTION((AE_INFO, status, "No critical threshold")); +-- return -ENODEV; +-- } else { +-- tz->trips.critical.flags.valid = 1; +-- ACPI_DEBUG_PRINT((ACPI_DB_INFO, +-- "Found critical threshold [%lu]\n", +-- tz->trips.critical.temperature)); +-- } +-+/* +-+ * This exception is thrown out in two cases: +-+ * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid +-+ * when re-evaluating the AML code. +-+ * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change. +-+ * We need to re-bind the cooling devices of a thermal zone when this occurs. +-+ */ +-+#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str) \ +-+do { \ +-+ if (flags != ACPI_TRIPS_INIT) \ +-+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, \ +-+ "ACPI thermal trip point %s changed\n" \ +-+ "Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \ +-+} while (0) +-+ +-+static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) +-+{ +-+ acpi_status status = AE_OK; +-+ struct acpi_handle_list devices; +-+ int valid = 0; +-+ int i; +- +-- if (tz->trips.critical.flags.valid == 1) { +-- if (crt == -1) { +-+ /* Critical Shutdown (required) */ +-+ if (flag & ACPI_TRIPS_CRITICAL) { +-+ status = acpi_evaluate_integer(tz->device->handle, +-+ "_CRT", NULL, &tz->trips.critical.temperature); +-+ if (ACPI_FAILURE(status)) { +- tz->trips.critical.flags.valid = 0; +-- } else if (crt > 0) { +-- unsigned long crt_k = CELSIUS_TO_KELVIN(crt); +-- +-- /* +-- * Allow override to lower critical threshold +-- */ +-- if (crt_k < tz->trips.critical.temperature) +-- tz->trips.critical.temperature = crt_k; +-+ ACPI_EXCEPTION((AE_INFO, status, +-+ "No critical threshold")); +-+ return -ENODEV; +-+ } else { +-+ tz->trips.critical.flags.valid = 1; +-+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, +-+ "Found critical threshold [%lu]\n", +-+ tz->trips.critical.temperature)); +-+ } +-+ if (tz->trips.critical.flags.valid == 1) { +-+ if (crt == -1) { +-+ tz->trips.critical.flags.valid = 0; +-+ } else if (crt > 0) { +-+ unsigned long crt_k = CELSIUS_TO_KELVIN(crt); +-+ /* +-+ * Allow override to lower critical threshold +-+ */ +-+ if (crt_k < tz->trips.critical.temperature) +-+ tz->trips.critical.temperature = crt_k; +-+ } +- } +- } +- +- /* Critical Sleep (optional) */ +-- +-- status = +-- acpi_evaluate_integer(tz->device->handle, "_HOT", NULL, +-- &tz->trips.hot.temperature); +-- if (ACPI_FAILURE(status)) { +-- tz->trips.hot.flags.valid = 0; +-- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n")); +-- } else { +-- tz->trips.hot.flags.valid = 1; +-- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n", +-- tz->trips.hot.temperature)); +-- } +-- +-- /* Passive: Processors (optional) */ +-- +-- if (psv == -1) { +-- status = AE_SUPPORT; +-- } else if (psv > 0) { +-- tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv); +-- status = AE_OK; +-- } else { +-+ if (flag & ACPI_TRIPS_HOT) { +- status = acpi_evaluate_integer(tz->device->handle, +-- "_PSV", NULL, &tz->trips.passive.temperature); +-+ "_HOT", NULL, &tz->trips.hot.temperature); +-+ if (ACPI_FAILURE(status)) { +-+ tz->trips.hot.flags.valid = 0; +-+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, +-+ "No hot threshold\n")); +-+ } else { +-+ tz->trips.hot.flags.valid = 1; +-+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, +-+ "Found hot threshold [%lu]\n", +-+ tz->trips.critical.temperature)); +-+ } +- } +- +-- if (ACPI_FAILURE(status)) { +-- tz->trips.passive.flags.valid = 0; +-- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n")); +-- } else { +-- tz->trips.passive.flags.valid = 1; +-- +-- status = +-- acpi_evaluate_integer(tz->device->handle, "_TC1", NULL, +-- &tz->trips.passive.tc1); +-- if (ACPI_FAILURE(status)) +-- tz->trips.passive.flags.valid = 0; +-- +-- status = +-- acpi_evaluate_integer(tz->device->handle, "_TC2", NULL, +-- &tz->trips.passive.tc2); +-- if (ACPI_FAILURE(status)) +-- tz->trips.passive.flags.valid = 0; +-+ /* Passive (optional) */ +-+ if (flag & ACPI_TRIPS_PASSIVE) { +-+ valid = tz->trips.passive.flags.valid; +-+ if (psv == -1) { +-+ status = AE_SUPPORT; +-+ } else if (psv > 0) { +-+ tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv); +-+ status = AE_OK; +-+ } else { +-+ status = acpi_evaluate_integer(tz->device->handle, +-+ "_PSV", NULL, &tz->trips.passive.temperature); +-+ } +- +-- status = +-- acpi_evaluate_integer(tz->device->handle, "_TSP", NULL, +-- &tz->trips.passive.tsp); +- if (ACPI_FAILURE(status)) +- tz->trips.passive.flags.valid = 0; +-- +-- status = +-- acpi_evaluate_reference(tz->device->handle, "_PSL", NULL, +-- &tz->trips.passive.devices); +-+ else { +-+ tz->trips.passive.flags.valid = 1; +-+ if (flag == ACPI_TRIPS_INIT) { +-+ status = acpi_evaluate_integer( +-+ tz->device->handle, "_TC1", +-+ NULL, &tz->trips.passive.tc1); +-+ if (ACPI_FAILURE(status)) +-+ tz->trips.passive.flags.valid = 0; +-+ status = acpi_evaluate_integer( +-+ tz->device->handle, "_TC2", +-+ NULL, &tz->trips.passive.tc2); +-+ if (ACPI_FAILURE(status)) +-+ tz->trips.passive.flags.valid = 0; +-+ status = acpi_evaluate_integer( +-+ tz->device->handle, "_TSP", +-+ NULL, &tz->trips.passive.tsp); +-+ if (ACPI_FAILURE(status)) +-+ tz->trips.passive.flags.valid = 0; +-+ } +-+ } +-+ } +-+ if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) { +-+ memset(&devices, 0, sizeof(struct acpi_handle_list)); +-+ status = acpi_evaluate_reference(tz->device->handle, "_PSL", +-+ NULL, &devices); +- if (ACPI_FAILURE(status)) +- tz->trips.passive.flags.valid = 0; +-- +-- if (!tz->trips.passive.flags.valid) +-- printk(KERN_WARNING PREFIX "Invalid passive threshold\n"); +- else +-- ACPI_DEBUG_PRINT((ACPI_DB_INFO, +-- "Found passive threshold [%lu]\n", +-- tz->trips.passive.temperature)); +-- } +-+ tz->trips.passive.flags.valid = 1; +- +-- /* Active: Fans, etc. (optional) */ +-+ if (memcmp(&tz->trips.passive.devices, &devices, +-+ sizeof(struct acpi_handle_list))) { +-+ memcpy(&tz->trips.passive.devices, &devices, +-+ sizeof(struct acpi_handle_list)); +-+ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); +-+ } +-+ } +-+ if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) { +-+ if (valid != tz->trips.passive.flags.valid) +-+ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state"); +-+ } +- +-+ /* Active (optional) */ +- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { +-- +- char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; +-+ valid = tz->trips.active[i].flags.valid; +- +- if (act == -1) +-- break; /* disable all active trip points */ +-- +-- status = acpi_evaluate_integer(tz->device->handle, +-- name, NULL, &tz->trips.active[i].temperature); +-- +-- if (ACPI_FAILURE(status)) { +-- if (i == 0) /* no active trip points */ +-+ break; /* disable all active trip points */ +-+ +-+ if (flag & ACPI_TRIPS_ACTIVE) { +-+ status = acpi_evaluate_integer(tz->device->handle, +-+ name, NULL, &tz->trips.active[i].temperature); +-+ if (ACPI_FAILURE(status)) { +-+ tz->trips.active[i].flags.valid = 0; +-+ if (i == 0) +-+ break; +-+ if (act <= 0) +-+ break; +-+ if (i == 1) +-+ tz->trips.active[0].temperature = +-+ CELSIUS_TO_KELVIN(act); +-+ else +-+ /* +-+ * Don't allow override higher than +-+ * the next higher trip point +-+ */ +-+ tz->trips.active[i - 1].temperature = +-+ (tz->trips.active[i - 2].temperature < +-+ CELSIUS_TO_KELVIN(act) ? +-+ tz->trips.active[i - 2].temperature : +-+ CELSIUS_TO_KELVIN(act)); +- break; +-- if (act <= 0) /* no override requested */ +-- break; +-- if (i == 1) { /* 1 trip point */ +-- tz->trips.active[0].temperature = +-- CELSIUS_TO_KELVIN(act); +-- } else { /* multiple trips */ +-- /* +-- * Don't allow override higher than +-- * the next higher trip point +-- */ +-- tz->trips.active[i - 1].temperature = +-- (tz->trips.active[i - 2].temperature < +-- CELSIUS_TO_KELVIN(act) ? +-- tz->trips.active[i - 2].temperature : +-- CELSIUS_TO_KELVIN(act)); +-- } +-- break; +-+ } else +-+ tz->trips.active[i].flags.valid = 1; +- } +- +- name[2] = 'L'; +-- status = +-- acpi_evaluate_reference(tz->device->handle, name, NULL, +-- &tz->trips.active[i].devices); +-- if (ACPI_SUCCESS(status)) { +-- tz->trips.active[i].flags.valid = 1; +-- ACPI_DEBUG_PRINT((ACPI_DB_INFO, +-- "Found active threshold [%d]:[%lu]\n", +-- i, tz->trips.active[i].temperature)); +-- } else +-- ACPI_EXCEPTION((AE_INFO, status, +-- "Invalid active threshold [%d]", i)); +-+ if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) { +-+ memset(&devices, 0, sizeof(struct acpi_handle_list)); +-+ status = acpi_evaluate_reference(tz->device->handle, +-+ name, NULL, &devices); +-+ if (ACPI_FAILURE(status)) +-+ tz->trips.active[i].flags.valid = 0; +-+ else +-+ tz->trips.active[i].flags.valid = 1; +-+ +-+ if (memcmp(&tz->trips.active[i].devices, &devices, +-+ sizeof(struct acpi_handle_list))) { +-+ memcpy(&tz->trips.active[i].devices, &devices, +-+ sizeof(struct acpi_handle_list)); +-+ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); +-+ } +-+ } +-+ if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES)) +-+ if (valid != tz->trips.active[i].flags.valid) +-+ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state"); +-+ +-+ if (!tz->trips.active[i].flags.valid) +-+ break; +-+ } +-+ +-+ if (flag & ACPI_TRIPS_DEVICES) { +-+ memset(&devices, 0, sizeof(struct acpi_handle_list)); +-+ status = acpi_evaluate_reference(tz->device->handle, "_TZD", +-+ NULL, &devices); +-+ if (memcmp(&tz->devices, &devices, +-+ sizeof(struct acpi_handle_list))) { +-+ memcpy(&tz->devices, &devices, +-+ sizeof(struct acpi_handle_list)); +-+ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); +-+ } +- } +- +- return 0; +- } +- +--static int acpi_thermal_get_devices(struct acpi_thermal *tz) +-+static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) +- { +-- acpi_status status = AE_OK; +-- +-- +-- if (!tz) +-- return -EINVAL; +-- +-- status = +-- acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices); +-- if (ACPI_FAILURE(status)) +-- return -ENODEV; +-- +-- return 0; +-+ return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT); +- } +- +- static int acpi_thermal_critical(struct acpi_thermal *tz) +-@@ -732,6 +779,9 @@ static void acpi_thermal_check(void *data) +- if (result) +- goto unlock; +- +-+ if (!tz->tz_enabled) +-+ goto unlock; +-+ +- memset(&tz->state, 0, sizeof(tz->state)); +- +- /* +-@@ -825,6 +875,290 @@ static void acpi_thermal_check(void *data) +- mutex_unlock(&tz->lock); +- } +- +-+/* sys I/F for generic thermal sysfs support */ +-+static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf) +-+{ +-+ struct acpi_thermal *tz = thermal->devdata; +-+ +-+ if (!tz) +-+ return -EINVAL; +-+ +-+ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature)); +-+} +-+ +-+static const char enabled[] = "kernel"; +-+static const char disabled[] = "user"; +-+static int thermal_get_mode(struct thermal_zone_device *thermal, +-+ char *buf) +-+{ +-+ struct acpi_thermal *tz = thermal->devdata; +-+ +-+ if (!tz) +-+ return -EINVAL; +-+ +-+ return sprintf(buf, "%s\n", tz->tz_enabled ? +-+ enabled : disabled); +-+} +-+ +-+static int thermal_set_mode(struct thermal_zone_device *thermal, +-+ const char *buf) +-+{ +-+ struct acpi_thermal *tz = thermal->devdata; +-+ int enable; +-+ +-+ if (!tz) +-+ return -EINVAL; +-+ +-+ /* +-+ * enable/disable thermal management from ACPI thermal driver +-+ */ +-+ if (!strncmp(buf, enabled, sizeof enabled - 1)) +-+ enable = 1; +-+ else if (!strncmp(buf, disabled, sizeof disabled - 1)) +-+ enable = 0; +-+ else +-+ return -EINVAL; +-+ +-+ if (enable != tz->tz_enabled) { +-+ tz->tz_enabled = enable; +-+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, +-+ "%s ACPI thermal control\n", +-+ tz->tz_enabled ? enabled : disabled)); +-+ acpi_thermal_check(tz); +-+ } +-+ return 0; +-+} +-+ +-+static int thermal_get_trip_type(struct thermal_zone_device *thermal, +-+ int trip, char *buf) +-+{ +-+ struct acpi_thermal *tz = thermal->devdata; +-+ int i; +-+ +-+ if (!tz || trip < 0) +-+ return -EINVAL; +-+ +-+ if (tz->trips.critical.flags.valid) { +-+ if (!trip) +-+ return sprintf(buf, "critical\n"); +-+ trip--; +-+ } +-+ +-+ if (tz->trips.hot.flags.valid) { +-+ if (!trip) +-+ return sprintf(buf, "hot\n"); +-+ trip--; +-+ } +-+ +-+ if (tz->trips.passive.flags.valid) { +-+ if (!trip) +-+ return sprintf(buf, "passive\n"); +-+ trip--; +-+ } +-+ +-+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && +-+ tz->trips.active[i].flags.valid; i++) { +-+ if (!trip) +-+ return sprintf(buf, "active%d\n", i); +-+ trip--; +-+ } +-+ +-+ return -EINVAL; +-+} +-+ +-+static int thermal_get_trip_temp(struct thermal_zone_device *thermal, +-+ int trip, char *buf) +-+{ +-+ struct acpi_thermal *tz = thermal->devdata; +-+ int i; +-+ +-+ if (!tz || trip < 0) +-+ return -EINVAL; +-+ +-+ if (tz->trips.critical.flags.valid) { +-+ if (!trip) +-+ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( +-+ tz->trips.critical.temperature)); +-+ trip--; +-+ } +-+ +-+ if (tz->trips.hot.flags.valid) { +-+ if (!trip) +-+ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( +-+ tz->trips.hot.temperature)); +-+ trip--; +-+ } +-+ +-+ if (tz->trips.passive.flags.valid) { +-+ if (!trip) +-+ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( +-+ tz->trips.passive.temperature)); +-+ trip--; +-+ } +-+ +-+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && +-+ tz->trips.active[i].flags.valid; i++) { +-+ if (!trip) +-+ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( +-+ tz->trips.active[i].temperature)); +-+ trip--; +-+ } +-+ +-+ return -EINVAL; +-+} +-+ +-+typedef int (*cb)(struct thermal_zone_device *, int, +-+ struct thermal_cooling_device *); +-+static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, +-+ struct thermal_cooling_device *cdev, +-+ cb action) +-+{ +-+ struct acpi_device *device = cdev->devdata; +-+ struct acpi_thermal *tz = thermal->devdata; +-+ struct acpi_device *dev; +-+ acpi_status status; +-+ acpi_handle handle; +-+ int i; +-+ int j; +-+ int trip = -1; +-+ int result = 0; +-+ +-+ if (tz->trips.critical.flags.valid) +-+ trip++; +-+ +-+ if (tz->trips.hot.flags.valid) +-+ trip++; +-+ +-+ if (tz->trips.passive.flags.valid) { +-+ trip++; +-+ for (i = 0; i < tz->trips.passive.devices.count; +-+ i++) { +-+ handle = tz->trips.passive.devices.handles[i]; +-+ status = acpi_bus_get_device(handle, &dev); +-+ if (ACPI_SUCCESS(status) && (dev == device)) { +-+ result = action(thermal, trip, cdev); +-+ if (result) +-+ goto failed; +-+ } +-+ } +-+ } +-+ +-+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { +-+ if (!tz->trips.active[i].flags.valid) +-+ break; +-+ trip++; +-+ for (j = 0; +-+ j < tz->trips.active[i].devices.count; +-+ j++) { +-+ handle = tz->trips.active[i].devices.handles[j]; +-+ status = acpi_bus_get_device(handle, &dev); +-+ if (ACPI_SUCCESS(status) && (dev == device)) { +-+ result = action(thermal, trip, cdev); +-+ if (result) +-+ goto failed; +-+ } +-+ } +-+ } +-+ +-+ for (i = 0; i < tz->devices.count; i++) { +-+ handle = tz->devices.handles[i]; +-+ status = acpi_bus_get_device(handle, &dev); +-+ if (ACPI_SUCCESS(status) && (dev == device)) { +-+ result = action(thermal, -1, cdev); +-+ if (result) +-+ goto failed; +-+ } +-+ } +-+ +-+failed: +-+ return result; +-+} +-+ +-+static int +-+acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal, +-+ struct thermal_cooling_device *cdev) +-+{ +-+ return acpi_thermal_cooling_device_cb(thermal, cdev, +-+ thermal_zone_bind_cooling_device); +-+} +-+ +-+static int +-+acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal, +-+ struct thermal_cooling_device *cdev) +-+{ +-+ return acpi_thermal_cooling_device_cb(thermal, cdev, +-+ thermal_zone_unbind_cooling_device); +-+} +-+ +-+static struct thermal_zone_device_ops acpi_thermal_zone_ops = { +-+ .bind = acpi_thermal_bind_cooling_device, +-+ .unbind = acpi_thermal_unbind_cooling_device, +-+ .get_temp = thermal_get_temp, +-+ .get_mode = thermal_get_mode, +-+ .set_mode = thermal_set_mode, +-+ .get_trip_type = thermal_get_trip_type, +-+ .get_trip_temp = thermal_get_trip_temp, +-+}; +-+ +-+static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) +-+{ +-+ int trips = 0; +-+ int result; +-+ acpi_status status; +-+ int i; +-+ +-+ if (tz->trips.critical.flags.valid) +-+ trips++; +-+ +-+ if (tz->trips.hot.flags.valid) +-+ trips++; +-+ +-+ if (tz->trips.passive.flags.valid) +-+ trips++; +-+ +-+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && +-+ tz->trips.active[i].flags.valid; i++, trips++); +-+ tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone", +-+ trips, tz, &acpi_thermal_zone_ops); +-+ if (!tz->thermal_zone) +-+ return -ENODEV; +-+ +-+ result = sysfs_create_link(&tz->device->dev.kobj, +-+ &tz->thermal_zone->device.kobj, "thermal_zone"); +-+ if (result) +-+ return result; +-+ +-+ result = sysfs_create_link(&tz->thermal_zone->device.kobj, +-+ &tz->device->dev.kobj, "device"); +-+ if (result) +-+ return result; +-+ +-+ status = acpi_attach_data(tz->device->handle, +-+ acpi_bus_private_data_handler, +-+ tz->thermal_zone); +-+ if (ACPI_FAILURE(status)) { +-+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, +-+ "Error attaching device data\n")); +-+ return -ENODEV; +-+ } +-+ +-+ tz->tz_enabled = 1; +-+ +-+ printk(KERN_INFO PREFIX "%s is registered as thermal_zone%d\n", +-+ tz->device->dev.bus_id, tz->thermal_zone->id); +-+ return 0; +-+} +-+ +-+static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) +-+{ +-+ sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone"); +-+ sysfs_remove_link(&tz->thermal_zone->device.kobj, "device"); +-+ thermal_zone_device_unregister(tz->thermal_zone); +-+ tz->thermal_zone = NULL; +-+ acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler); +-+} +-+ +-+ +- /* -------------------------------------------------------------------------- +- FS Interface (/proc) +- -------------------------------------------------------------------------- */ +-@@ -1181,15 +1515,15 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data) +- acpi_thermal_check(tz); +- break; +- case ACPI_THERMAL_NOTIFY_THRESHOLDS: +-- acpi_thermal_get_trip_points(tz); +-+ acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS); +- acpi_thermal_check(tz); +- acpi_bus_generate_proc_event(device, event, 0); +- acpi_bus_generate_netlink_event(device->pnp.device_class, +- device->dev.bus_id, event, 0); +- break; +- case ACPI_THERMAL_NOTIFY_DEVICES: +-- if (tz->flags.devices) +-- acpi_thermal_get_devices(tz); +-+ acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES); +-+ acpi_thermal_check(tz); +- acpi_bus_generate_proc_event(device, event, 0); +- acpi_bus_generate_netlink_event(device->pnp.device_class, +- device->dev.bus_id, event, 0); +-@@ -1232,11 +1566,6 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz) +- else +- acpi_thermal_get_polling_frequency(tz); +- +-- /* Get devices in this thermal zone [_TZD] (optional) */ +-- result = acpi_thermal_get_devices(tz); +-- if (!result) +-- tz->flags.devices = 1; +-- +- return 0; +- } +- +-@@ -1260,13 +1589,19 @@ static int acpi_thermal_add(struct acpi_device *device) +- strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); +- acpi_driver_data(device) = tz; +- mutex_init(&tz->lock); +-+ +-+ +- result = acpi_thermal_get_info(tz); +- if (result) +-- goto end; +-+ goto free_memory; +-+ +-+ result = acpi_thermal_register_thermal_zone(tz); +-+ if (result) +-+ goto free_memory; +- +- result = acpi_thermal_add_fs(device); +- if (result) +-- goto end; +-+ goto unregister_thermal_zone; +- +- init_timer(&tz->timer); +- +-@@ -1277,19 +1612,21 @@ static int acpi_thermal_add(struct acpi_device *device) +- acpi_thermal_notify, tz); +- if (ACPI_FAILURE(status)) { +- result = -ENODEV; +-- goto end; +-+ goto remove_fs; +- } +- +- printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n", +- acpi_device_name(device), acpi_device_bid(device), +- KELVIN_TO_CELSIUS(tz->temperature)); +-+ goto end; +- +-- end: +-- if (result) { +-- acpi_thermal_remove_fs(device); +-- kfree(tz); +-- } +-- +-+remove_fs: +-+ acpi_thermal_remove_fs(device); +-+unregister_thermal_zone: +-+ thermal_zone_device_unregister(tz->thermal_zone); +-+free_memory: +-+ kfree(tz); +-+end: +- return result; +- } +- +-@@ -1329,6 +1666,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type) +- } +- +- acpi_thermal_remove_fs(device); +-+ acpi_thermal_unregister_thermal_zone(tz); +- mutex_destroy(&tz->lock); +- kfree(tz); +- return 0; +-diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c +-index 826a52f..c83b76c 100644 +---- a/drivers/acpi/video.c +-+++ b/drivers/acpi/video.c +-@@ -34,6 +34,7 @@ +- #include +- #include +- #include +-+#include +- #include +- #include +- +-@@ -183,6 +184,7 @@ struct acpi_video_device { +- struct acpi_device *dev; +- struct acpi_video_device_brightness *brightness; +- struct backlight_device *backlight; +-+ struct thermal_cooling_device *cdev; +- struct output_device *output_dev; +- }; +- +-@@ -346,6 +348,54 @@ static struct output_properties acpi_output_properties = { +- .set_state = acpi_video_output_set, +- .get_status = acpi_video_output_get, +- }; +-+ +-+ +-+/* thermal cooling device callbacks */ +-+static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf) +-+{ +-+ struct acpi_device *device = cdev->devdata; +-+ struct acpi_video_device *video = acpi_driver_data(device); +-+ +-+ return sprintf(buf, "%d\n", video->brightness->count - 3); +-+} +-+ +-+static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf) +-+{ +-+ struct acpi_device *device = cdev->devdata; +-+ struct acpi_video_device *video = acpi_driver_data(device); +-+ unsigned long level; +-+ int state; +-+ +-+ acpi_video_device_lcd_get_level_current(video, &level); +-+ for (state = 2; state < video->brightness->count; state++) +-+ if (level == video->brightness->levels[state]) +-+ return sprintf(buf, "%d\n", +-+ video->brightness->count - state - 1); +-+ +-+ return -EINVAL; +-+} +-+ +-+static int +-+video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) +-+{ +-+ struct acpi_device *device = cdev->devdata; +-+ struct acpi_video_device *video = acpi_driver_data(device); +-+ int level; +-+ +-+ if ( state >= video->brightness->count - 2) +-+ return -EINVAL; +-+ +-+ state = video->brightness->count - state; +-+ level = video->brightness->levels[state -1]; +-+ return acpi_video_device_lcd_set_level(video, level); +-+} +-+ +-+static struct thermal_cooling_device_ops video_cooling_ops = { +-+ .get_max_state = video_get_max_state, +-+ .get_cur_state = video_get_cur_state, +-+ .set_cur_state = video_set_cur_state, +-+}; +-+ +- /* -------------------------------------------------------------------------- +- Video Management +- -------------------------------------------------------------------------- */ +-@@ -664,6 +714,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) +- kfree(obj); +- +- if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){ +-+ int result; +- static int count = 0; +- char *name; +- name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); +-@@ -676,8 +727,25 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) +- device->backlight->props.max_brightness = device->brightness->count-3; +- device->backlight->props.brightness = acpi_video_get_brightness(device->backlight); +- backlight_update_status(device->backlight); +-- +- kfree(name); +-+ +-+ device->cdev = thermal_cooling_device_register("LCD", +-+ device->dev, &video_cooling_ops); +-+ if (device->cdev) { +-+ printk(KERN_INFO PREFIX +-+ "%s is registered as cooling_device%d\n", +-+ device->dev->dev.bus_id, device->cdev->id); +-+ result = sysfs_create_link(&device->dev->dev.kobj, +-+ &device->cdev->device.kobj, +-+ "thermal_cooling"); +-+ if (result) +-+ printk(KERN_ERR PREFIX "Create sysfs link\n"); +-+ result = sysfs_create_link(&device->cdev->device.kobj, +-+ &device->dev->dev.kobj, +-+ "device"); +-+ if (result) +-+ printk(KERN_ERR PREFIX "Create sysfs link\n"); +-+ } +- } +- if (device->cap._DCS && device->cap._DSS){ +- static int count = 0; +-@@ -1739,6 +1807,14 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) +- ACPI_DEVICE_NOTIFY, +- acpi_video_device_notify); +- backlight_device_unregister(device->backlight); +-+ if (device->cdev) { +-+ sysfs_remove_link(&device->dev->dev.kobj, +-+ "thermal_cooling"); +-+ sysfs_remove_link(&device->cdev->device.kobj, +-+ "device"); +-+ thermal_cooling_device_unregister(device->cdev); +-+ device->cdev = NULL; +-+ } +- video_output_unregister(device->output_dev); +- +- return 0; +-diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +-index b5e67c0..46a131a 100644 +---- a/drivers/misc/Kconfig +-+++ b/drivers/misc/Kconfig +-@@ -232,4 +232,14 @@ config ATMEL_SSC +- +- If unsure, say N. +- +-+config INTEL_MENLOW +-+ tristate "Thermal Management driver for Intel menlow platform" +-+ depends on ACPI_THERMAL +-+ default n +-+ ---help--- +-+ ACPI thermal management enhancement driver on +-+ Intel Menlow platform. +-+ +-+ If you are not sure, say N here. +-+ +- endif # MISC_DEVICES +-diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +-index 87f2685..a9e8faf 100644 +---- a/drivers/misc/Makefile +-+++ b/drivers/misc/Makefile +-@@ -17,3 +17,4 @@ +- obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o +- obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o +- obj-$(CONFIG_KGDB_TESTS) += kgdbts.o +-+obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o +-diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c +-new file mode 100644 +-index 0000000..753dc5f +---- /dev/null +-+++ b/drivers/misc/intel_menlow.c +-@@ -0,0 +1,527 @@ +-+/* +-+* intel_menlow.c - Intel menlow Driver for thermal management extension +-+* +-+* Copyright (C) 2008 Intel Corp +-+* Copyright (C) 2008 Sujith Thomas +-+* Copyright (C) 2008 Zhang Rui +-+* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-+* +-+* 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; version 2 of the License. +-+* +-+* This program is distributed in the hope that it will be useful, but +-+* WITHOUT ANY WARRANTY; without even the implied warranty of +-+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-+* General Public License for more details. +-+* +-+* You should have received a copy of the GNU General Public License along +-+* with this program; if not, write to the Free Software Foundation, Inc., +-+* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +-+* +-+* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-+* +-+* This driver creates the sys I/F for programming the sensors. +-+* It also implements the driver for intel menlow memory controller (hardware +-+* id is INT0002) which makes use of the platform specific ACPI methods +-+* to get/set bandwidth. +-+*/ +-+ +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+ +-+#include +-+#include +-+#include +-+ +-+MODULE_AUTHOR("Thomas Sujith"); +-+MODULE_AUTHOR("Zhang Rui"); +-+MODULE_DESCRIPTION("Intel Menlow platform specific driver"); +-+MODULE_LICENSE("GPL"); +-+ +-+/* +-+ * Memory controller device control +-+ */ +-+ +-+#define MEMORY_GET_BANDWIDTH "GTHS" +-+#define MEMORY_SET_BANDWIDTH "STHS" +-+#define MEMORY_ARG_CUR_BANDWIDTH 1 +-+#define MEMORY_ARG_MAX_BANDWIDTH 0 +-+ +-+static int +-+memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev, +-+ unsigned long *max_state) +-+{ +-+ struct acpi_device *device = cdev->devdata; +-+ acpi_handle handle = device->handle; +-+ unsigned long value; +-+ struct acpi_object_list arg_list; +-+ union acpi_object arg; +-+ acpi_status status = AE_OK; +-+ +-+ arg_list.count = 1; +-+ arg_list.pointer = &arg; +-+ arg.type = ACPI_TYPE_INTEGER; +-+ arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH; +-+ status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, +-+ &arg_list, &value); +-+ if (ACPI_FAILURE(status)) +-+ return -EFAULT; +-+ +-+ *max_state = value - 1; +-+ return 0; +-+} +-+ +-+static int +-+memory_get_max_bandwidth(struct thermal_cooling_device *cdev, char *buf) +-+{ +-+ unsigned long value; +-+ if (memory_get_int_max_bandwidth(cdev,&value)) +-+ return -EINVAL; +-+ +-+ return sprintf(buf, "%ld\n", value); +-+} +-+ +-+static int +-+memory_get_cur_bandwidth(struct thermal_cooling_device *cdev, char *buf) +-+{ +-+ struct acpi_device *device = cdev->devdata; +-+ acpi_handle handle = device->handle; +-+ unsigned long value; +-+ struct acpi_object_list arg_list; +-+ union acpi_object arg; +-+ acpi_status status = AE_OK; +-+ +-+ arg_list.count = 1; +-+ arg_list.pointer = &arg; +-+ arg.type = ACPI_TYPE_INTEGER; +-+ arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH; +-+ status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, +-+ &arg_list, &value); +-+ if (ACPI_FAILURE(status)) +-+ return -EFAULT; +-+ +-+ return sprintf(buf, "%ld\n", value); +-+} +-+ +-+static int +-+memory_set_cur_bandwidth(struct thermal_cooling_device *cdev, +-+ unsigned int state) +-+{ +-+ struct acpi_device *device = cdev->devdata; +-+ acpi_handle handle = device->handle; +-+ struct acpi_object_list arg_list; +-+ union acpi_object arg; +-+ acpi_status status; +-+ int temp; +-+ unsigned long max_state; +-+ +-+ if (memory_get_int_max_bandwidth(cdev,&max_state)) +-+ return -EFAULT; +-+ +-+ if (max_state < 0 || state > max_state) +-+ return -EINVAL; +-+ +-+ arg_list.count = 1; +-+ arg_list.pointer = &arg; +-+ arg.type = ACPI_TYPE_INTEGER; +-+ arg.integer.value = state; +-+ +-+ status = +-+ acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list, +-+ (unsigned long *)&temp); +-+ +-+ printk(KERN_INFO +-+ "Bandwidth value was %d: status is %d\n", state, status); +-+ if (ACPI_FAILURE(status)) +-+ return -EFAULT; +-+ +-+ return 0; +-+} +-+ +-+static struct thermal_cooling_device_ops memory_cooling_ops = { +-+ .get_max_state = memory_get_max_bandwidth, +-+ .get_cur_state = memory_get_cur_bandwidth, +-+ .set_cur_state = memory_set_cur_bandwidth, +-+}; +-+ +-+/* +-+ * Memory Device Management +-+ */ +-+static int intel_menlow_memory_add(struct acpi_device *device) +-+{ +-+ int result = -ENODEV; +-+ acpi_status status = AE_OK; +-+ acpi_handle dummy; +-+ struct thermal_cooling_device *cdev; +-+ +-+ if (!device) +-+ return -EINVAL; +-+ +-+ status = acpi_get_handle(device->handle, MEMORY_GET_BANDWIDTH, &dummy); +-+ if (ACPI_FAILURE(status)) +-+ goto end; +-+ +-+ status = acpi_get_handle(device->handle, MEMORY_SET_BANDWIDTH, &dummy); +-+ if (ACPI_FAILURE(status)) +-+ goto end; +-+ +-+ cdev = thermal_cooling_device_register("Memory controller", device, +-+ &memory_cooling_ops); +-+ acpi_driver_data(device) = cdev; +-+ if (!cdev) +-+ result = -ENODEV; +-+ else { +-+ result = +-+ sysfs_create_link(&device->dev.kobj, &cdev->device.kobj, +-+ "thermal_cooling"); +-+ if (result) +-+ goto end; +-+ result = +-+ sysfs_create_link(&cdev->device.kobj, &device->dev.kobj, +-+ "device"); +-+ if (result) +-+ goto end; +-+ } +-+ +-+ end: +-+ return result; +-+} +-+ +-+static int intel_menlow_memory_remove(struct acpi_device *device, int type) +-+{ +-+ struct thermal_cooling_device *cdev = acpi_driver_data(device); +-+ +-+ if (!device || !cdev) +-+ return -EINVAL; +-+ +-+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); +-+ sysfs_remove_link(&cdev->device.kobj, "device"); +-+ thermal_cooling_device_unregister(cdev); +-+ +-+ return 0; +-+} +-+ +-+const static struct acpi_device_id intel_menlow_memory_ids[] = { +-+ {"INT0002", 0}, +-+ {"", 0}, +-+}; +-+ +-+static struct acpi_driver intel_menlow_memory_driver = { +-+ .name = "intel_menlow_thermal_control", +-+ .ids = intel_menlow_memory_ids, +-+ .ops = { +-+ .add = intel_menlow_memory_add, +-+ .remove = intel_menlow_memory_remove, +-+ }, +-+}; +-+ +-+/* +-+ * Sensor control on menlow platform +-+ */ +-+ +-+#define THERMAL_AUX0 0 +-+#define THERMAL_AUX1 1 +-+#define GET_AUX0 "GAX0" +-+#define GET_AUX1 "GAX1" +-+#define SET_AUX0 "SAX0" +-+#define SET_AUX1 "SAX1" +-+ +-+struct intel_menlow_attribute { +-+ struct device_attribute attr; +-+ struct device *device; +-+ acpi_handle handle; +-+ struct list_head node; +-+}; +-+ +-+static LIST_HEAD(intel_menlow_attr_list); +-+static DEFINE_MUTEX(intel_menlow_attr_lock); +-+ +-+/* +-+ * sensor_get_auxtrip +-+ * ----------------- +-+ * get the current auxtrip value from sensor through proprietory ACPI methods +-+ * name: Thermalzone name +-+ * auxtype : AUX0/AUX1 +-+ * buf: syfs buffer +-+ */ +-+static int sensor_get_auxtrip(acpi_handle handle, int index, int *value) +-+{ +-+ acpi_status status; +-+ +-+ if ((index != 0 && index != 1) || !value) +-+ return -EINVAL; +-+ +-+ status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0, +-+ NULL, (unsigned long *)value); +-+ if (ACPI_FAILURE(status)) +-+ return -EIO; +-+ +-+ return 0; +-+} +-+ +-+/* +-+ * sensor_set_auxtrip +-+ * ----------------- +-+ * set the new auxtrip value to sensor through proprietory ACPI methods +-+ * name: Thermalzone name +-+ * auxtype : AUX0/AUX1 +-+ * buf: syfs buffer +-+ */ +-+static int sensor_set_auxtrip(acpi_handle handle, int index, int value) +-+{ +-+ acpi_status status; +-+ union acpi_object arg = { +-+ ACPI_TYPE_INTEGER +-+ }; +-+ struct acpi_object_list args = { +-+ 1, &arg +-+ }; +-+ int temp; +-+ +-+ if (index != 0 && index != 1) +-+ return -EINVAL; +-+ +-+ status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1, +-+ NULL, (unsigned long *)&temp); +-+ if (ACPI_FAILURE(status)) +-+ return -EIO; +-+ if ((index && value < temp) || (!index && value > temp)) +-+ return -EINVAL; +-+ +-+ arg.integer.value = value; +-+ status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0, +-+ &args, (unsigned long *)&temp); +-+ if (ACPI_FAILURE(status)) +-+ return -EIO; +-+ +-+ /* do we need to check the return value of SAX0/SAX1 ? */ +-+ +-+ return 0; +-+} +-+ +-+#define to_intel_menlow_attr(_attr) \ +-+ container_of(_attr, struct intel_menlow_attribute, attr) +-+ +-+static ssize_t aux0_show(struct device *dev, +-+ struct device_attribute *dev_attr, char *buf) +-+{ +-+ struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); +-+ int value; +-+ int result; +-+ +-+ result = sensor_get_auxtrip(attr->handle, 0, &value); +-+ +-+ return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); +-+} +-+ +-+static ssize_t aux1_show(struct device *dev, +-+ struct device_attribute *dev_attr, char *buf) +-+{ +-+ struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); +-+ int value; +-+ int result; +-+ +-+ result = sensor_get_auxtrip(attr->handle, 1, &value); +-+ +-+ return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); +-+} +-+ +-+static ssize_t aux0_store(struct device *dev, +-+ struct device_attribute *dev_attr, +-+ const char *buf, size_t count) +-+{ +-+ struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); +-+ int value; +-+ int result; +-+ +-+ /*Sanity check; should be a positive integer */ +-+ if (!sscanf(buf, "%d", &value)) +-+ return -EINVAL; +-+ +-+ if (value < 0) +-+ return -EINVAL; +-+ +-+ result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value)); +-+ return result ? result : count; +-+} +-+ +-+static ssize_t aux1_store(struct device *dev, +-+ struct device_attribute *dev_attr, +-+ const char *buf, size_t count) +-+{ +-+ struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); +-+ int value; +-+ int result; +-+ +-+ /*Sanity check; should be a positive integer */ +-+ if (!sscanf(buf, "%d", &value)) +-+ return -EINVAL; +-+ +-+ if (value < 0) +-+ return -EINVAL; +-+ +-+ result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value)); +-+ return result ? result : count; +-+} +-+ +-+/* BIOS can enable/disable the thermal user application in dabney platform */ +-+#define BIOS_ENABLED "\\_TZ.GSTS" +-+static ssize_t bios_enabled_show(struct device *dev, +-+ struct device_attribute *attr, char *buf) +-+{ +-+ acpi_status status; +-+ unsigned long bios_enabled; +-+ +-+ status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled); +-+ if (ACPI_FAILURE(status)) +-+ return -ENODEV; +-+ +-+ return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled"); +-+} +-+ +-+static int intel_menlow_add_one_attribute(char *name, int mode, void *show, +-+ void *store, struct device *dev, +-+ acpi_handle handle) +-+{ +-+ struct intel_menlow_attribute *attr; +-+ int result; +-+ +-+ attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL); +-+ if (!attr) +-+ return -ENOMEM; +-+ +-+ attr->attr.attr.name = name; +-+ attr->attr.attr.mode = mode; +-+ attr->attr.show = show; +-+ attr->attr.store = store; +-+ attr->device = dev; +-+ attr->handle = handle; +-+ +-+ result = device_create_file(dev, &attr->attr); +-+ if (result) +-+ return result; +-+ +-+ mutex_lock(&intel_menlow_attr_lock); +-+ list_add_tail(&attr->node, &intel_menlow_attr_list); +-+ mutex_unlock(&intel_menlow_attr_lock); +-+ +-+ return 0; +-+} +-+ +-+static acpi_status +-+intel_menlow_register_sensor(acpi_handle handle, u32 lvl, +-+ void *context, void **rv) +-+{ +-+ acpi_status status; +-+ acpi_handle dummy; +-+ struct thermal_zone_device *thermal; +-+ int result; +-+ +-+ result = acpi_bus_get_private_data(handle, (void **)&thermal); +-+ if (result) +-+ return 0; +-+ +-+ /* _TZ must have the AUX0/1 methods */ +-+ status = acpi_get_handle(handle, GET_AUX0, &dummy); +-+ if (ACPI_FAILURE(status)) +-+ goto not_found; +-+ +-+ status = acpi_get_handle(handle, SET_AUX0, &dummy); +-+ if (ACPI_FAILURE(status)) +-+ goto not_found; +-+ +-+ result = intel_menlow_add_one_attribute("aux0", 0644, +-+ aux0_show, aux0_store, +-+ &thermal->device, handle); +-+ if (result) +-+ return AE_ERROR; +-+ +-+ status = acpi_get_handle(handle, GET_AUX1, &dummy); +-+ if (ACPI_FAILURE(status)) +-+ goto not_found; +-+ +-+ status = acpi_get_handle(handle, SET_AUX1, &dummy); +-+ if (ACPI_FAILURE(status)) +-+ goto not_found; +-+ +-+ result = intel_menlow_add_one_attribute("aux1", 0644, +-+ aux1_show, aux1_store, +-+ &thermal->device, handle); +-+ if (result) +-+ return AE_ERROR; +-+ +-+ /* +-+ * create the "dabney_enabled" attribute which means the user app +-+ * should be loaded or not +-+ */ +-+ +-+ result = intel_menlow_add_one_attribute("bios_enabled", 0444, +-+ bios_enabled_show, NULL, +-+ &thermal->device, handle); +-+ if (result) +-+ return AE_ERROR; +-+ +-+ not_found: +-+ if (status == AE_NOT_FOUND) +-+ return AE_OK; +-+ else +-+ return status; +-+} +-+ +-+static void intel_menlow_unregister_sensor(void) +-+{ +-+ struct intel_menlow_attribute *pos, *next; +-+ +-+ mutex_lock(&intel_menlow_attr_lock); +-+ list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) { +-+ list_del(&pos->node); +-+ device_remove_file(pos->device, &pos->attr); +-+ kfree(pos); +-+ } +-+ mutex_unlock(&intel_menlow_attr_lock); +-+ +-+ return; +-+} +-+ +-+static int __init intel_menlow_module_init(void) +-+{ +-+ int result = -ENODEV; +-+ acpi_status status; +-+ unsigned long enable; +-+ +-+ if (acpi_disabled) +-+ return result; +-+ +-+ /* Looking for the \_TZ.GSTS method */ +-+ status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable); +-+ if (ACPI_FAILURE(status) || !enable) +-+ return -ENODEV; +-+ +-+ /* Looking for ACPI device MEM0 with hardware id INT0002 */ +-+ result = acpi_bus_register_driver(&intel_menlow_memory_driver); +-+ if (result) +-+ return result; +-+ +-+ /* Looking for sensors in each ACPI thermal zone */ +-+ status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT, +-+ ACPI_UINT32_MAX, +-+ intel_menlow_register_sensor, NULL, NULL); +-+ if (ACPI_FAILURE(status)) +-+ result = -ENODEV; +-+ +-+ return 0; +-+} +-+ +-+static void __exit intel_menlow_module_exit(void) +-+{ +-+ acpi_bus_unregister_driver(&intel_menlow_memory_driver); +-+ intel_menlow_unregister_sensor(); +-+} +-+ +-+module_init(intel_menlow_module_init); +-+module_exit(intel_menlow_module_exit); +-diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig +-new file mode 100644 +-index 0000000..b879d27 +---- /dev/null +-+++ b/drivers/thermal/Kconfig +-@@ -0,0 +1,16 @@ +-+# +-+# Generic thermal sysfs drivers configuration +-+# +-+ +-+menuconfig THERMAL +-+ bool "Generic Thermal sysfs driver" +-+ default y +-+ help +-+ Generic Thermal Sysfs driver offers a generic mechanism for +-+ thermal management. Usually it's made up of one or more thermal +-+ zone and cooling device. +-+ each thermal zone contains its own temperature, trip points, +-+ cooling devices. +-+ All platforms with ACPI thermal support can use this driver. +-+ If you want this support, you should say Y here +-+ +-diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile +-new file mode 100644 +-index 0000000..75b4bf2 +---- /dev/null +-+++ b/drivers/thermal/Makefile +-@@ -0,0 +1,6 @@ +-+# +-+# Makefile for sensor chip drivers. +-+# +-+ +-+obj-$(CONFIG_THERMAL) += thermal.o +-+ +-diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal.c +-new file mode 100644 +-index 0000000..3273e34 +---- /dev/null +-+++ b/drivers/thermal/thermal.c +-@@ -0,0 +1,714 @@ +-+/* +-+ * thermal.c - Generic Thermal Management Sysfs support. +-+ * +-+ * Copyright (C) 2008 Intel Corp +-+ * Copyright (C) 2008 Zhang Rui +-+ * Copyright (C) 2008 Sujith Thomas +-+ * +-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-+ * +-+ * 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; version 2 of the License. +-+ * +-+ * This program is distributed in the hope that it will be useful, but +-+ * WITHOUT ANY WARRANTY; without even the implied warranty of +-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-+ * General Public License for more details. +-+ * +-+ * You should have received a copy of the GNU General Public License along +-+ * with this program; if not, write to the Free Software Foundation, Inc., +-+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +-+ * +-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-+ */ +-+ +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+#include +-+ +-+MODULE_AUTHOR("Zhang Rui") +-+MODULE_DESCRIPTION("Generic thermal management sysfs support"); +-+MODULE_LICENSE("GPL"); +-+ +-+#define PREFIX "Thermal: " +-+ +-+struct thermal_cooling_device_instance { +-+ int id; +-+ char name[THERMAL_NAME_LENGTH]; +-+ struct thermal_zone_device *tz; +-+ struct thermal_cooling_device *cdev; +-+ int trip; +-+ char attr_name[THERMAL_NAME_LENGTH]; +-+ struct device_attribute attr; +-+ struct list_head node; +-+}; +-+ +-+static DEFINE_IDR(thermal_tz_idr); +-+static DEFINE_IDR(thermal_cdev_idr); +-+static DEFINE_MUTEX(thermal_idr_lock); +-+ +-+static LIST_HEAD(thermal_tz_list); +-+static LIST_HEAD(thermal_cdev_list); +-+static DEFINE_MUTEX(thermal_list_lock); +-+ +-+static int get_idr(struct idr *idr, struct mutex *lock, int *id) +-+{ +-+ int err; +-+ +-+ again: +-+ if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0)) +-+ return -ENOMEM; +-+ +-+ if (lock) +-+ mutex_lock(lock); +-+ err = idr_get_new(idr, NULL, id); +-+ if (lock) +-+ mutex_unlock(lock); +-+ if (unlikely(err == -EAGAIN)) +-+ goto again; +-+ else if (unlikely(err)) +-+ return err; +-+ +-+ *id = *id & MAX_ID_MASK; +-+ return 0; +-+} +-+ +-+static void release_idr(struct idr *idr, struct mutex *lock, int id) +-+{ +-+ if (lock) +-+ mutex_lock(lock); +-+ idr_remove(idr, id); +-+ if (lock) +-+ mutex_unlock(lock); +-+} +-+ +-+/* sys I/F for thermal zone */ +-+ +-+#define to_thermal_zone(_dev) \ +-+ container_of(_dev, struct thermal_zone_device, device) +-+ +-+static ssize_t +-+type_show(struct device *dev, struct device_attribute *attr, char *buf) +-+{ +-+ struct thermal_zone_device *tz = to_thermal_zone(dev); +-+ +-+ return sprintf(buf, "%s\n", tz->type); +-+} +-+ +-+static ssize_t +-+temp_show(struct device *dev, struct device_attribute *attr, char *buf) +-+{ +-+ struct thermal_zone_device *tz = to_thermal_zone(dev); +-+ +-+ if (!tz->ops->get_temp) +-+ return -EPERM; +-+ +-+ return tz->ops->get_temp(tz, buf); +-+} +-+ +-+static ssize_t +-+mode_show(struct device *dev, struct device_attribute *attr, char *buf) +-+{ +-+ struct thermal_zone_device *tz = to_thermal_zone(dev); +-+ +-+ if (!tz->ops->get_mode) +-+ return -EPERM; +-+ +-+ return tz->ops->get_mode(tz, buf); +-+} +-+ +-+static ssize_t +-+mode_store(struct device *dev, struct device_attribute *attr, +-+ const char *buf, size_t count) +-+{ +-+ struct thermal_zone_device *tz = to_thermal_zone(dev); +-+ int result; +-+ +-+ if (!tz->ops->set_mode) +-+ return -EPERM; +-+ +-+ result = tz->ops->set_mode(tz, buf); +-+ if (result) +-+ return result; +-+ +-+ return count; +-+} +-+ +-+static ssize_t +-+trip_point_type_show(struct device *dev, struct device_attribute *attr, +-+ char *buf) +-+{ +-+ struct thermal_zone_device *tz = to_thermal_zone(dev); +-+ int trip; +-+ +-+ if (!tz->ops->get_trip_type) +-+ return -EPERM; +-+ +-+ if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) +-+ return -EINVAL; +-+ +-+ return tz->ops->get_trip_type(tz, trip, buf); +-+} +-+ +-+static ssize_t +-+trip_point_temp_show(struct device *dev, struct device_attribute *attr, +-+ char *buf) +-+{ +-+ struct thermal_zone_device *tz = to_thermal_zone(dev); +-+ int trip; +-+ +-+ if (!tz->ops->get_trip_temp) +-+ return -EPERM; +-+ +-+ if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip)) +-+ return -EINVAL; +-+ +-+ return tz->ops->get_trip_temp(tz, trip, buf); +-+} +-+ +-+static DEVICE_ATTR(type, 0444, type_show, NULL); +-+static DEVICE_ATTR(temp, 0444, temp_show, NULL); +-+static DEVICE_ATTR(mode, 0644, mode_show, mode_store); +-+ +-+static struct device_attribute trip_point_attrs[] = { +-+ __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL), +-+ __ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL), +-+ __ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL), +-+ __ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL), +-+ __ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL), +-+ __ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL), +-+ __ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL), +-+ __ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL), +-+ __ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL), +-+ __ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL), +-+ __ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL), +-+ __ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL), +-+ __ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL), +-+ __ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL), +-+ __ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL), +-+ __ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL), +-+ __ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL), +-+ __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL), +-+ __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL), +-+ __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL), +-+}; +-+ +-+#define TRIP_POINT_ATTR_ADD(_dev, _index, result) \ +-+do { \ +-+ result = device_create_file(_dev, \ +-+ &trip_point_attrs[_index * 2]); \ +-+ if (result) \ +-+ break; \ +-+ result = device_create_file(_dev, \ +-+ &trip_point_attrs[_index * 2 + 1]); \ +-+} while (0) +-+ +-+#define TRIP_POINT_ATTR_REMOVE(_dev, _index) \ +-+do { \ +-+ device_remove_file(_dev, &trip_point_attrs[_index * 2]); \ +-+ device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ +-+} while (0) +-+ +-+/* sys I/F for cooling device */ +-+#define to_cooling_device(_dev) \ +-+ container_of(_dev, struct thermal_cooling_device, device) +-+ +-+static ssize_t +-+thermal_cooling_device_type_show(struct device *dev, +-+ struct device_attribute *attr, char *buf) +-+{ +-+ struct thermal_cooling_device *cdev = to_cooling_device(dev); +-+ +-+ return sprintf(buf, "%s\n", cdev->type); +-+} +-+ +-+static ssize_t +-+thermal_cooling_device_max_state_show(struct device *dev, +-+ struct device_attribute *attr, char *buf) +-+{ +-+ struct thermal_cooling_device *cdev = to_cooling_device(dev); +-+ +-+ return cdev->ops->get_max_state(cdev, buf); +-+} +-+ +-+static ssize_t +-+thermal_cooling_device_cur_state_show(struct device *dev, +-+ struct device_attribute *attr, char *buf) +-+{ +-+ struct thermal_cooling_device *cdev = to_cooling_device(dev); +-+ +-+ return cdev->ops->get_cur_state(cdev, buf); +-+} +-+ +-+static ssize_t +-+thermal_cooling_device_cur_state_store(struct device *dev, +-+ struct device_attribute *attr, +-+ const char *buf, size_t count) +-+{ +-+ struct thermal_cooling_device *cdev = to_cooling_device(dev); +-+ int state; +-+ int result; +-+ +-+ if (!sscanf(buf, "%d\n", &state)) +-+ return -EINVAL; +-+ +-+ if (state < 0) +-+ return -EINVAL; +-+ +-+ result = cdev->ops->set_cur_state(cdev, state); +-+ if (result) +-+ return result; +-+ return count; +-+} +-+ +-+static struct device_attribute dev_attr_cdev_type = +-+ __ATTR(type, 0444, thermal_cooling_device_type_show, NULL); +-+static DEVICE_ATTR(max_state, 0444, +-+ thermal_cooling_device_max_state_show, NULL); +-+static DEVICE_ATTR(cur_state, 0644, +-+ thermal_cooling_device_cur_state_show, +-+ thermal_cooling_device_cur_state_store); +-+ +-+static ssize_t +-+thermal_cooling_device_trip_point_show(struct device *dev, +-+ struct device_attribute *attr, char *buf) +-+{ +-+ struct thermal_cooling_device_instance *instance; +-+ +-+ instance = +-+ container_of(attr, struct thermal_cooling_device_instance, attr); +-+ +-+ if (instance->trip == THERMAL_TRIPS_NONE) +-+ return sprintf(buf, "-1\n"); +-+ else +-+ return sprintf(buf, "%d\n", instance->trip); +-+} +-+ +-+/* Device management */ +-+ +-+/** +-+ * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone +-+ * this function is usually called in the thermal zone device .bind callback. +-+ * @tz: thermal zone device +-+ * @trip: indicates which trip point the cooling devices is +-+ * associated with in this thermal zone. +-+ * @cdev: thermal cooling device +-+ */ +-+int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, +-+ int trip, +-+ struct thermal_cooling_device *cdev) +-+{ +-+ struct thermal_cooling_device_instance *dev; +-+ struct thermal_cooling_device_instance *pos; +-+ int result; +-+ +-+ if (trip >= tz->trips || +-+ (trip < 0 && trip != THERMAL_TRIPS_NONE)) +-+ return -EINVAL; +-+ +-+ if (!tz || !cdev) +-+ return -EINVAL; +-+ +-+ dev = +-+ kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL); +-+ if (!dev) +-+ return -ENOMEM; +-+ dev->tz = tz; +-+ dev->cdev = cdev; +-+ dev->trip = trip; +-+ result = get_idr(&tz->idr, &tz->lock, &dev->id); +-+ if (result) +-+ goto free_mem; +-+ +-+ sprintf(dev->name, "cdev%d", dev->id); +-+ result = +-+ sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name); +-+ if (result) +-+ goto release_idr; +-+ +-+ sprintf(dev->attr_name, "cdev%d_trip_point", dev->id); +-+ dev->attr.attr.name = dev->attr_name; +-+ dev->attr.attr.mode = 0444; +-+ dev->attr.show = thermal_cooling_device_trip_point_show; +-+ result = device_create_file(&tz->device, &dev->attr); +-+ if (result) +-+ goto remove_symbol_link; +-+ +-+ mutex_lock(&tz->lock); +-+ list_for_each_entry(pos, &tz->cooling_devices, node) +-+ if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) { +-+ result = -EEXIST; +-+ break; +-+ } +-+ if (!result) +-+ list_add_tail(&dev->node, &tz->cooling_devices); +-+ mutex_unlock(&tz->lock); +-+ +-+ if (!result) +-+ return 0; +-+ +-+ device_remove_file(&tz->device, &dev->attr); +-+ remove_symbol_link: +-+ sysfs_remove_link(&tz->device.kobj, dev->name); +-+ release_idr: +-+ release_idr(&tz->idr, &tz->lock, dev->id); +-+ free_mem: +-+ kfree(dev); +-+ return result; +-+} +-+EXPORT_SYMBOL(thermal_zone_bind_cooling_device); +-+ +-+/** +-+ * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone +-+ * this function is usually called in the thermal zone device .unbind callback. +-+ * @tz: thermal zone device +-+ * @trip: indicates which trip point the cooling devices is +-+ * associated with in this thermal zone. +-+ * @cdev: thermal cooling device +-+ */ +-+int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, +-+ int trip, +-+ struct thermal_cooling_device *cdev) +-+{ +-+ struct thermal_cooling_device_instance *pos, *next; +-+ +-+ mutex_lock(&tz->lock); +-+ list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) { +-+ if (pos->tz == tz && pos->trip == trip +-+ && pos->cdev == cdev) { +-+ list_del(&pos->node); +-+ mutex_unlock(&tz->lock); +-+ goto unbind; +-+ } +-+ } +-+ mutex_unlock(&tz->lock); +-+ +-+ return -ENODEV; +-+ +-+ unbind: +-+ device_remove_file(&tz->device, &pos->attr); +-+ sysfs_remove_link(&tz->device.kobj, pos->name); +-+ release_idr(&tz->idr, &tz->lock, pos->id); +-+ kfree(pos); +-+ return 0; +-+} +-+EXPORT_SYMBOL(thermal_zone_unbind_cooling_device); +-+ +-+static void thermal_release(struct device *dev) +-+{ +-+ struct thermal_zone_device *tz; +-+ struct thermal_cooling_device *cdev; +-+ +-+ if (!strncmp(dev->bus_id, "thermal_zone", sizeof "thermal_zone" - 1)) { +-+ tz = to_thermal_zone(dev); +-+ kfree(tz); +-+ } else { +-+ cdev = to_cooling_device(dev); +-+ kfree(cdev); +-+ } +-+} +-+ +-+static struct class thermal_class = { +-+ .name = "thermal", +-+ .dev_release = thermal_release, +-+}; +-+ +-+/** +-+ * thermal_cooling_device_register - register a new thermal cooling device +-+ * @type: the thermal cooling device type. +-+ * @devdata: device private data. +-+ * @ops: standard thermal cooling devices callbacks. +-+ */ +-+struct thermal_cooling_device *thermal_cooling_device_register(char *type, +-+ void *devdata, struct thermal_cooling_device_ops *ops) +-+{ +-+ struct thermal_cooling_device *cdev; +-+ struct thermal_zone_device *pos; +-+ int result; +-+ +-+ if (strlen(type) >= THERMAL_NAME_LENGTH) +-+ return NULL; +-+ +-+ if (!ops || !ops->get_max_state || !ops->get_cur_state || +-+ !ops->set_cur_state) +-+ return NULL; +-+ +-+ cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL); +-+ if (!cdev) +-+ return NULL; +-+ +-+ result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id); +-+ if (result) { +-+ kfree(cdev); +-+ return NULL; +-+ } +-+ +-+ strcpy(cdev->type, type); +-+ cdev->ops = ops; +-+ cdev->device.class = &thermal_class; +-+ cdev->devdata = devdata; +-+ sprintf(cdev->device.bus_id, "cooling_device%d", cdev->id); +-+ result = device_register(&cdev->device); +-+ if (result) { +-+ release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); +-+ kfree(cdev); +-+ return NULL; +-+ } +-+ +-+ /* sys I/F */ +-+ if (type) { +-+ result = device_create_file(&cdev->device, +-+ &dev_attr_cdev_type); +-+ if (result) +-+ goto unregister; +-+ } +-+ +-+ result = device_create_file(&cdev->device, &dev_attr_max_state); +-+ if (result) +-+ goto unregister; +-+ +-+ result = device_create_file(&cdev->device, &dev_attr_cur_state); +-+ if (result) +-+ goto unregister; +-+ +-+ mutex_lock(&thermal_list_lock); +-+ list_add(&cdev->node, &thermal_cdev_list); +-+ list_for_each_entry(pos, &thermal_tz_list, node) { +-+ if (!pos->ops->bind) +-+ continue; +-+ result = pos->ops->bind(pos, cdev); +-+ if (result) +-+ break; +-+ +-+ } +-+ mutex_unlock(&thermal_list_lock); +-+ +-+ if (!result) +-+ return cdev; +-+ +-+ unregister: +-+ release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); +-+ device_unregister(&cdev->device); +-+ return NULL; +-+} +-+EXPORT_SYMBOL(thermal_cooling_device_register); +-+ +-+/** +-+ * thermal_cooling_device_unregister - removes the registered thermal cooling device +-+ * +-+ * @cdev: the thermal cooling device to remove. +-+ * +-+ * thermal_cooling_device_unregister() must be called when the device is no +-+ * longer needed. +-+ */ +-+void thermal_cooling_device_unregister(struct +-+ thermal_cooling_device +-+ *cdev) +-+{ +-+ struct thermal_zone_device *tz; +-+ struct thermal_cooling_device *pos = NULL; +-+ +-+ if (!cdev) +-+ return; +-+ +-+ mutex_lock(&thermal_list_lock); +-+ list_for_each_entry(pos, &thermal_cdev_list, node) +-+ if (pos == cdev) +-+ break; +-+ if (pos != cdev) { +-+ /* thermal cooling device not found */ +-+ mutex_unlock(&thermal_list_lock); +-+ return; +-+ } +-+ list_del(&cdev->node); +-+ list_for_each_entry(tz, &thermal_tz_list, node) { +-+ if (!tz->ops->unbind) +-+ continue; +-+ tz->ops->unbind(tz, cdev); +-+ } +-+ mutex_unlock(&thermal_list_lock); +-+ if (cdev->type[0]) +-+ device_remove_file(&cdev->device, +-+ &dev_attr_cdev_type); +-+ device_remove_file(&cdev->device, &dev_attr_max_state); +-+ device_remove_file(&cdev->device, &dev_attr_cur_state); +-+ +-+ release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); +-+ device_unregister(&cdev->device); +-+ return; +-+} +-+EXPORT_SYMBOL(thermal_cooling_device_unregister); +-+ +-+/** +-+ * thermal_zone_device_register - register a new thermal zone device +-+ * @type: the thermal zone device type +-+ * @trips: the number of trip points the thermal zone support +-+ * @devdata: private device data +-+ * @ops: standard thermal zone device callbacks +-+ * +-+ * thermal_zone_device_unregister() must be called when the device is no +-+ * longer needed. +-+ */ +-+struct thermal_zone_device *thermal_zone_device_register(char *type, +-+ int trips, void *devdata, +-+ struct thermal_zone_device_ops *ops) +-+{ +-+ struct thermal_zone_device *tz; +-+ struct thermal_cooling_device *pos; +-+ int result; +-+ int count; +-+ +-+ if (strlen(type) >= THERMAL_NAME_LENGTH) +-+ return NULL; +-+ +-+ if (trips > THERMAL_MAX_TRIPS || trips < 0) +-+ return NULL; +-+ +-+ if (!ops || !ops->get_temp) +-+ return NULL; +-+ +-+ tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL); +-+ if (!tz) +-+ return NULL; +-+ +-+ INIT_LIST_HEAD(&tz->cooling_devices); +-+ idr_init(&tz->idr); +-+ mutex_init(&tz->lock); +-+ result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id); +-+ if (result) { +-+ kfree(tz); +-+ return NULL; +-+ } +-+ +-+ strcpy(tz->type, type); +-+ tz->ops = ops; +-+ tz->device.class = &thermal_class; +-+ tz->devdata = devdata; +-+ tz->trips = trips; +-+ sprintf(tz->device.bus_id, "thermal_zone%d", tz->id); +-+ result = device_register(&tz->device); +-+ if (result) { +-+ release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); +-+ kfree(tz); +-+ return NULL; +-+ } +-+ +-+ /* sys I/F */ +-+ if (type) { +-+ result = device_create_file(&tz->device, &dev_attr_type); +-+ if (result) +-+ goto unregister; +-+ } +-+ +-+ result = device_create_file(&tz->device, &dev_attr_temp); +-+ if (result) +-+ goto unregister; +-+ +-+ if (ops->get_mode) { +-+ result = device_create_file(&tz->device, &dev_attr_mode); +-+ if (result) +-+ goto unregister; +-+ } +-+ +-+ for (count = 0; count < trips; count++) { +-+ TRIP_POINT_ATTR_ADD(&tz->device, count, result); +-+ if (result) +-+ goto unregister; +-+ } +-+ +-+ mutex_lock(&thermal_list_lock); +-+ list_add_tail(&tz->node, &thermal_tz_list); +-+ if (ops->bind) +-+ list_for_each_entry(pos, &thermal_cdev_list, node) { +-+ result = ops->bind(tz, pos); +-+ if (result) +-+ break; +-+ } +-+ mutex_unlock(&thermal_list_lock); +-+ +-+ if (!result) +-+ return tz; +-+ +-+ unregister: +-+ release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); +-+ device_unregister(&tz->device); +-+ return NULL; +-+} +-+EXPORT_SYMBOL(thermal_zone_device_register); +-+ +-+/** +-+ * thermal_device_unregister - removes the registered thermal zone device +-+ * +-+ * @tz: the thermal zone device to remove +-+ */ +-+void thermal_zone_device_unregister(struct thermal_zone_device *tz) +-+{ +-+ struct thermal_cooling_device *cdev; +-+ struct thermal_zone_device *pos = NULL; +-+ int count; +-+ +-+ if (!tz) +-+ return; +-+ +-+ mutex_lock(&thermal_list_lock); +-+ list_for_each_entry(pos, &thermal_tz_list, node) +-+ if (pos == tz) +-+ break; +-+ if (pos != tz) { +-+ /* thermal zone device not found */ +-+ mutex_unlock(&thermal_list_lock); +-+ return; +-+ } +-+ list_del(&tz->node); +-+ if (tz->ops->unbind) +-+ list_for_each_entry(cdev, &thermal_cdev_list, node) +-+ tz->ops->unbind(tz, cdev); +-+ mutex_unlock(&thermal_list_lock); +-+ +-+ if (tz->type[0]) +-+ device_remove_file(&tz->device, &dev_attr_type); +-+ device_remove_file(&tz->device, &dev_attr_temp); +-+ if (tz->ops->get_mode) +-+ device_remove_file(&tz->device, &dev_attr_mode); +-+ +-+ for (count = 0; count < tz->trips; count++) +-+ TRIP_POINT_ATTR_REMOVE(&tz->device, count); +-+ +-+ release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); +-+ idr_destroy(&tz->idr); +-+ mutex_destroy(&tz->lock); +-+ device_unregister(&tz->device); +-+ return; +-+} +-+EXPORT_SYMBOL(thermal_zone_device_unregister); +-+ +-+static int __init thermal_init(void) +-+{ +-+ int result = 0; +-+ +-+ result = class_register(&thermal_class); +-+ if (result) { +-+ idr_destroy(&thermal_tz_idr); +-+ idr_destroy(&thermal_cdev_idr); +-+ mutex_destroy(&thermal_idr_lock); +-+ mutex_destroy(&thermal_list_lock); +-+ } +-+ return result; +-+} +-+ +-+static void __exit thermal_exit(void) +-+{ +-+ class_unregister(&thermal_class); +-+ idr_destroy(&thermal_tz_idr); +-+ idr_destroy(&thermal_cdev_idr); +-+ mutex_destroy(&thermal_idr_lock); +-+ mutex_destroy(&thermal_list_lock); +-+} +-+ +-+subsys_initcall(thermal_init); +-+module_exit(thermal_exit); +-diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h +-index 7b74b60..2b7eece 100644 +---- a/include/acpi/acpi_bus.h +-+++ b/include/acpi/acpi_bus.h +-@@ -321,6 +321,8 @@ struct acpi_bus_event { +- +- extern struct kset acpi_subsys; +- extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); +-+void acpi_bus_private_data_handler(acpi_handle, u32, void *); +-+int acpi_bus_get_private_data(acpi_handle, void **); +- /* +- * External Functions +- */ +-diff --git a/include/acpi/processor.h b/include/acpi/processor.h +-index 76411b1..0787635 100644 +---- a/include/acpi/processor.h +-+++ b/include/acpi/processor.h +-@@ -4,7 +4,7 @@ +- #include +- #include +- #include +-- +-+#include +- #include +- +- #define ACPI_PROCESSOR_BUSY_METRIC 10 +-@@ -218,7 +218,7 @@ struct acpi_processor { +- struct acpi_processor_performance *performance; +- struct acpi_processor_throttling throttling; +- struct acpi_processor_limit limit; +-- +-+ struct thermal_cooling_device *cdev; +- /* the _PDC objects for this processor, if any */ +- struct acpi_object_list *pdc; +- }; +-@@ -330,7 +330,7 @@ extern struct cpuidle_driver acpi_idle_driver; +- /* in processor_thermal.c */ +- int acpi_processor_get_limit_info(struct acpi_processor *pr); +- extern struct file_operations acpi_processor_limit_fops; +-- +-+extern struct thermal_cooling_device_ops processor_cooling_ops; +- #ifdef CONFIG_CPU_FREQ +- void acpi_thermal_cpufreq_init(void); +- void acpi_thermal_cpufreq_exit(void); +-diff --git a/include/linux/thermal.h b/include/linux/thermal.h +-new file mode 100644 +-index 0000000..bba7712 +---- /dev/null +-+++ b/include/linux/thermal.h +-@@ -0,0 +1,94 @@ +-+/* +-+ * thermal.h ($Revision: 0 $) +-+ * +-+ * Copyright (C) 2008 Intel Corp +-+ * Copyright (C) 2008 Zhang Rui +-+ * Copyright (C) 2008 Sujith Thomas +-+ * +-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-+ * 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; version 2 of the License. +-+ * +-+ * This program is distributed in the hope that it will be useful, but +-+ * WITHOUT ANY WARRANTY; without even the implied warranty of +-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-+ * General Public License for more details. +-+ * +-+ * You should have received a copy of the GNU General Public License along +-+ * with this program; if not, write to the Free Software Foundation, Inc., +-+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +-+ * +-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-+ */ +-+ +-+#ifndef __THERMAL_H__ +-+#define __THERMAL_H__ +-+ +-+#include +-+#include +-+ +-+struct thermal_zone_device; +-+struct thermal_cooling_device; +-+ +-+struct thermal_zone_device_ops { +-+ int (*bind) (struct thermal_zone_device *, +-+ struct thermal_cooling_device *); +-+ int (*unbind) (struct thermal_zone_device *, +-+ struct thermal_cooling_device *); +-+ int (*get_temp) (struct thermal_zone_device *, char *); +-+ int (*get_mode) (struct thermal_zone_device *, char *); +-+ int (*set_mode) (struct thermal_zone_device *, const char *); +-+ int (*get_trip_type) (struct thermal_zone_device *, int, char *); +-+ int (*get_trip_temp) (struct thermal_zone_device *, int, char *); +-+}; +-+ +-+struct thermal_cooling_device_ops { +-+ int (*get_max_state) (struct thermal_cooling_device *, char *); +-+ int (*get_cur_state) (struct thermal_cooling_device *, char *); +-+ int (*set_cur_state) (struct thermal_cooling_device *, unsigned int); +-+}; +-+ +-+#define THERMAL_TRIPS_NONE -1 +-+#define THERMAL_MAX_TRIPS 10 +-+#define THERMAL_NAME_LENGTH 20 +-+struct thermal_cooling_device { +-+ int id; +-+ char type[THERMAL_NAME_LENGTH]; +-+ struct device device; +-+ void *devdata; +-+ struct thermal_cooling_device_ops *ops; +-+ struct list_head node; +-+}; +-+ +-+#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \ +-+ ((long)t-2732+5)/10 : ((long)t-2732-5)/10) +-+#define CELSIUS_TO_KELVIN(t) ((t)*10+2732) +-+ +-+struct thermal_zone_device { +-+ int id; +-+ char type[THERMAL_NAME_LENGTH]; +-+ struct device device; +-+ void *devdata; +-+ int trips; +-+ struct thermal_zone_device_ops *ops; +-+ struct list_head cooling_devices; +-+ struct idr idr; +-+ struct mutex lock; /* protect cooling devices list */ +-+ struct list_head node; +-+}; +-+ +-+struct thermal_zone_device *thermal_zone_device_register(char *, int, void *, +-+ struct thermal_zone_device_ops *); +-+void thermal_zone_device_unregister(struct thermal_zone_device *); +-+ +-+int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int, +-+ struct thermal_cooling_device *); +-+int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int, +-+ struct thermal_cooling_device *); +-+ +-+struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, +-+ struct thermal_cooling_device_ops *); +-+void thermal_cooling_device_unregister(struct thermal_cooling_device *); +-+ +-+#endif /* __THERMAL_H__ */ +--- +-1.5.6.3 +- +diff --git a/drivers/Kconfig b/drivers/Kconfig +index 3f8a231..d127a9a 100644 +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -58,6 +58,8 @@ source "drivers/power/Kconfig" + + source "drivers/hwmon/Kconfig" + ++source "drivers/thermal/Kconfig" ++ + source "drivers/watchdog/Kconfig" + + source "drivers/ssb/Kconfig" +diff --git a/drivers/Makefile b/drivers/Makefile +index a5cfc61..e0013ee 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -64,6 +64,7 @@ obj-y += i2c/ + obj-$(CONFIG_W1) += w1/ + obj-$(CONFIG_POWER_SUPPLY) += power/ + obj-$(CONFIG_HWMON) += hwmon/ ++obj-$(CONFIG_THERMAL) += thermal/ + obj-$(CONFIG_WATCHDOG) += watchdog/ + obj-$(CONFIG_PHONE) += telephony/ + obj-$(CONFIG_MD) += md/ +diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig +index 5b543e1..6a0f9cf 100644 +--- a/drivers/acpi/Kconfig ++++ b/drivers/acpi/Kconfig +@@ -186,6 +186,7 @@ config ACPI_HOTPLUG_CPU + config ACPI_THERMAL + tristate "Thermal Zone" + depends on ACPI_PROCESSOR ++ select THERMAL + default y + help + This driver adds support for ACPI thermal zones. Most mobile and +diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c +index d417358..582e9de 100644 +--- a/drivers/acpi/bus.c ++++ b/drivers/acpi/bus.c +@@ -139,6 +139,31 @@ int acpi_bus_get_status(struct acpi_device *device) + + EXPORT_SYMBOL(acpi_bus_get_status); + ++void acpi_bus_private_data_handler(acpi_handle handle, ++ u32 function, void *context) ++{ ++ return; ++} ++EXPORT_SYMBOL(acpi_bus_private_data_handler); ++ ++int acpi_bus_get_private_data(acpi_handle handle, void **data) ++{ ++ acpi_status status = AE_OK; ++ ++ if (!*data) ++ return -EINVAL; ++ ++ status = acpi_get_data(handle, acpi_bus_private_data_handler, data); ++ if (ACPI_FAILURE(status) || !*data) { ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", ++ handle)); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(acpi_bus_get_private_data); ++ + /* -------------------------------------------------------------------------- + Power Management + -------------------------------------------------------------------------- */ +diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c +index a6e149d..f6e8165 100644 +--- a/drivers/acpi/fan.c ++++ b/drivers/acpi/fan.c +@@ -30,7 +30,7 @@ + #include + #include + #include +- ++#include + #include + #include + +@@ -68,9 +68,55 @@ static struct acpi_driver acpi_fan_driver = { + }, + }; + ++/* thermal cooling device callbacks */ ++static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf) ++{ ++ /* ACPI fan device only support two states: ON/OFF */ ++ return sprintf(buf, "1\n"); ++} ++ ++static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf) ++{ ++ struct acpi_device *device = cdev->devdata; ++ int state; ++ int result; ++ ++ if (!device) ++ return -EINVAL; ++ ++ result = acpi_bus_get_power(device->handle, &state); ++ if (result) ++ return result; ++ ++ return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" : ++ (state == ACPI_STATE_D0 ? "1" : "unknown")); ++} ++ ++static int ++fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) ++{ ++ struct acpi_device *device = cdev->devdata; ++ int result; ++ ++ if (!device || (state != 0 && state != 1)) ++ return -EINVAL; ++ ++ result = acpi_bus_set_power(device->handle, ++ state ? ACPI_STATE_D0 : ACPI_STATE_D3); ++ ++ return result; ++} ++ ++static struct thermal_cooling_device_ops fan_cooling_ops = { ++ .get_max_state = fan_get_max_state, ++ .get_cur_state = fan_get_cur_state, ++ .set_cur_state = fan_set_cur_state, ++}; ++ + /* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ ++#ifdef CONFIG_ACPI_PROCFS + + static struct proc_dir_entry *acpi_fan_dir; + +@@ -171,7 +217,17 @@ static int acpi_fan_remove_fs(struct acpi_device *device) + + return 0; + } ++#else ++static int acpi_fan_add_fs(struct acpi_device *device) ++{ ++ return 0; ++} + ++static int acpi_fan_remove_fs(struct acpi_device *device) ++{ ++ return 0; ++} ++#endif + /* -------------------------------------------------------------------------- + Driver Interface + -------------------------------------------------------------------------- */ +@@ -179,9 +235,8 @@ static int acpi_fan_remove_fs(struct acpi_device *device) + static int acpi_fan_add(struct acpi_device *device) + { + int result = 0; +- struct acpi_fan *fan = NULL; + int state = 0; +- ++ struct thermal_cooling_device *cdev; + + if (!device) + return -EINVAL; +@@ -199,6 +254,25 @@ static int acpi_fan_add(struct acpi_device *device) + acpi_bus_set_power(device->handle, state); + device->flags.force_power_state = 0; + ++ cdev = thermal_cooling_device_register("Fan", device, ++ &fan_cooling_ops); ++ if (cdev) ++ printk(KERN_INFO PREFIX ++ "%s is registered as cooling_device%d\n", ++ device->dev.bus_id, cdev->id); ++ else ++ goto end; ++ acpi_driver_data(device) = cdev; ++ result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj, ++ "thermal_cooling"); ++ if (result) ++ return result; ++ ++ result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj, ++ "device"); ++ if (result) ++ return result; ++ + result = acpi_fan_add_fs(device); + if (result) + goto end; +@@ -208,18 +282,20 @@ static int acpi_fan_add(struct acpi_device *device) + !device->power.state ? "on" : "off"); + + end: +- if (result) +- kfree(fan); +- + return result; + } + + static int acpi_fan_remove(struct acpi_device *device, int type) + { +- if (!device || !acpi_driver_data(device)) ++ struct thermal_cooling_device *cdev = acpi_driver_data(device); ++ ++ if (!device || !cdev) + return -EINVAL; + + acpi_fan_remove_fs(device); ++ sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); ++ sysfs_remove_link(&cdev->device.kobj, "device"); ++ thermal_cooling_device_unregister(cdev); + + return 0; + } +diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c +index 6705259..ef4bfca 100644 +--- a/drivers/acpi/processor_core.c ++++ b/drivers/acpi/processor_core.c +@@ -673,6 +673,24 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) + + acpi_processor_power_init(pr, device); + ++ pr->cdev = thermal_cooling_device_register("Processor", device, ++ &processor_cooling_ops); ++ if (pr->cdev) ++ printk(KERN_INFO PREFIX ++ "%s is registered as cooling_device%d\n", ++ device->dev.bus_id, pr->cdev->id); ++ else ++ goto end; ++ ++ result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj, ++ "thermal_cooling"); ++ if (result) ++ return result; ++ result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, ++ "device"); ++ if (result) ++ return result; ++ + if (pr->flags.throttling) { + printk(KERN_INFO PREFIX "%s [%s] (supports", + acpi_device_name(device), acpi_device_bid(device)); +@@ -799,6 +817,11 @@ static int acpi_processor_remove(struct acpi_device *device, int type) + + acpi_processor_remove_fs(device); + ++ sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); ++ sysfs_remove_link(&pr->cdev->device.kobj, "device"); ++ thermal_cooling_device_unregister(pr->cdev); ++ pr->cdev = NULL; ++ + processors[pr->id] = NULL; + processor_device_array[pr->id] = NULL; + kfree(pr); +diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c +index 06e6f3f..9cb43f5 100644 +--- a/drivers/acpi/processor_thermal.c ++++ b/drivers/acpi/processor_thermal.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + #include + +@@ -93,6 +94,9 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr) + * _any_ cpufreq driver and not only the acpi-cpufreq driver. + */ + ++#define CPUFREQ_THERMAL_MIN_STEP 0 ++#define CPUFREQ_THERMAL_MAX_STEP 3 ++ + static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS]; + static unsigned int acpi_thermal_cpufreq_is_init = 0; + +@@ -109,8 +113,9 @@ static int acpi_thermal_cpufreq_increase(unsigned int cpu) + if (!cpu_has_cpufreq(cpu)) + return -ENODEV; + +- if (cpufreq_thermal_reduction_pctg[cpu] < 60) { +- cpufreq_thermal_reduction_pctg[cpu] += 20; ++ if (cpufreq_thermal_reduction_pctg[cpu] < ++ CPUFREQ_THERMAL_MAX_STEP) { ++ cpufreq_thermal_reduction_pctg[cpu]++; + cpufreq_update_policy(cpu); + return 0; + } +@@ -123,8 +128,9 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu) + if (!cpu_has_cpufreq(cpu)) + return -ENODEV; + +- if (cpufreq_thermal_reduction_pctg[cpu] > 20) +- cpufreq_thermal_reduction_pctg[cpu] -= 20; ++ if (cpufreq_thermal_reduction_pctg[cpu] > ++ (CPUFREQ_THERMAL_MIN_STEP + 1)) ++ cpufreq_thermal_reduction_pctg[cpu]--; + else + cpufreq_thermal_reduction_pctg[cpu] = 0; + cpufreq_update_policy(cpu); +@@ -143,7 +149,7 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb, + + max_freq = + (policy->cpuinfo.max_freq * +- (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100; ++ (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100; + + cpufreq_verify_within_limits(policy, 0, max_freq); + +@@ -155,6 +161,32 @@ static struct notifier_block acpi_thermal_cpufreq_notifier_block = { + .notifier_call = acpi_thermal_cpufreq_notifier, + }; + ++static int cpufreq_get_max_state(unsigned int cpu) ++{ ++ if (!cpu_has_cpufreq(cpu)) ++ return 0; ++ ++ return CPUFREQ_THERMAL_MAX_STEP; ++} ++ ++static int cpufreq_get_cur_state(unsigned int cpu) ++{ ++ if (!cpu_has_cpufreq(cpu)) ++ return 0; ++ ++ return cpufreq_thermal_reduction_pctg[cpu]; ++} ++ ++static int cpufreq_set_cur_state(unsigned int cpu, int state) ++{ ++ if (!cpu_has_cpufreq(cpu)) ++ return 0; ++ ++ cpufreq_thermal_reduction_pctg[cpu] = state; ++ cpufreq_update_policy(cpu); ++ return 0; ++} ++ + void acpi_thermal_cpufreq_init(void) + { + int i; +@@ -179,6 +211,20 @@ void acpi_thermal_cpufreq_exit(void) + } + + #else /* ! CONFIG_CPU_FREQ */ ++static int cpufreq_get_max_state(unsigned int cpu) ++{ ++ return 0; ++} ++ ++static int cpufreq_get_cur_state(unsigned int cpu) ++{ ++ return 0; ++} ++ ++static int cpufreq_set_cur_state(unsigned int cpu, int state) ++{ ++ return 0; ++} + + static int acpi_thermal_cpufreq_increase(unsigned int cpu) + { +@@ -310,6 +356,84 @@ int acpi_processor_get_limit_info(struct acpi_processor *pr) + return 0; + } + ++/* thermal coolign device callbacks */ ++static int acpi_processor_max_state(struct acpi_processor *pr) ++{ ++ int max_state = 0; ++ ++ /* ++ * There exists four states according to ++ * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3 ++ */ ++ max_state += cpufreq_get_max_state(pr->id); ++ if (pr->flags.throttling) ++ max_state += (pr->throttling.state_count -1); ++ ++ return max_state; ++} ++static int ++processor_get_max_state(struct thermal_cooling_device *cdev, char *buf) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_processor *pr = acpi_driver_data(device); ++ ++ if (!device || !pr) ++ return -EINVAL; ++ ++ return sprintf(buf, "%d\n", acpi_processor_max_state(pr)); ++} ++ ++static int ++processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_processor *pr = acpi_driver_data(device); ++ int cur_state; ++ ++ if (!device || !pr) ++ return -EINVAL; ++ ++ cur_state = cpufreq_get_cur_state(pr->id); ++ if (pr->flags.throttling) ++ cur_state += pr->throttling.state; ++ ++ return sprintf(buf, "%d\n", cur_state); ++} ++ ++static int ++processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_processor *pr = acpi_driver_data(device); ++ int result = 0; ++ int max_pstate; ++ ++ if (!device || !pr) ++ return -EINVAL; ++ ++ max_pstate = cpufreq_get_max_state(pr->id); ++ ++ if (state > acpi_processor_max_state(pr)) ++ return -EINVAL; ++ ++ if (state <= max_pstate) { ++ if (pr->flags.throttling && pr->throttling.state) ++ result = acpi_processor_set_throttling(pr, 0); ++ cpufreq_set_cur_state(pr->id, state); ++ } else { ++ cpufreq_set_cur_state(pr->id, max_pstate); ++ result = acpi_processor_set_throttling(pr, ++ state - max_pstate); ++ } ++ return result; ++} ++ ++struct thermal_cooling_device_ops processor_cooling_ops = { ++ .get_max_state = processor_get_max_state, ++ .get_cur_state = processor_get_cur_state, ++ .set_cur_state = processor_set_cur_state, ++}; ++ + /* /proc interface */ + + static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset) +diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c +index 5f79b44..73f276b 100644 +--- a/drivers/acpi/thermal.c ++++ b/drivers/acpi/thermal.c +@@ -43,7 +43,7 @@ + #include + #include + #include +- ++#include + #include + #include + +@@ -65,9 +65,6 @@ + #define ACPI_THERMAL_MAX_ACTIVE 10 + #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65 + +-#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10) +-#define CELSIUS_TO_KELVIN(t) ((t+273)*10) +- + #define _COMPONENT ACPI_THERMAL_COMPONENT + ACPI_MODULE_NAME("thermal"); + +@@ -195,6 +192,8 @@ struct acpi_thermal { + struct acpi_thermal_trips trips; + struct acpi_handle_list devices; + struct timer_list timer; ++ struct thermal_zone_device *thermal_zone; ++ int tz_enabled; + struct mutex lock; + }; + +@@ -321,173 +320,221 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode) + return 0; + } + +-static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) +-{ +- acpi_status status = AE_OK; +- int i = 0; ++#define ACPI_TRIPS_CRITICAL 0x01 ++#define ACPI_TRIPS_HOT 0x02 ++#define ACPI_TRIPS_PASSIVE 0x04 ++#define ACPI_TRIPS_ACTIVE 0x08 ++#define ACPI_TRIPS_DEVICES 0x10 + ++#define ACPI_TRIPS_REFRESH_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE) ++#define ACPI_TRIPS_REFRESH_DEVICES ACPI_TRIPS_DEVICES + +- if (!tz) +- return -EINVAL; ++#define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \ ++ ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \ ++ ACPI_TRIPS_DEVICES) + +- /* Critical Shutdown (required) */ +- +- status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, +- &tz->trips.critical.temperature); +- if (ACPI_FAILURE(status)) { +- tz->trips.critical.flags.valid = 0; +- ACPI_EXCEPTION((AE_INFO, status, "No critical threshold")); +- return -ENODEV; +- } else { +- tz->trips.critical.flags.valid = 1; +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, +- "Found critical threshold [%lu]\n", +- tz->trips.critical.temperature)); +- } ++/* ++ * This exception is thrown out in two cases: ++ * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid ++ * when re-evaluating the AML code. ++ * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change. ++ * We need to re-bind the cooling devices of a thermal zone when this occurs. ++ */ ++#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str) \ ++do { \ ++ if (flags != ACPI_TRIPS_INIT) \ ++ ACPI_EXCEPTION((AE_INFO, AE_ERROR, \ ++ "ACPI thermal trip point %s changed\n" \ ++ "Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \ ++} while (0) ++ ++static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) ++{ ++ acpi_status status = AE_OK; ++ struct acpi_handle_list devices; ++ int valid = 0; ++ int i; + +- if (tz->trips.critical.flags.valid == 1) { +- if (crt == -1) { ++ /* Critical Shutdown (required) */ ++ if (flag & ACPI_TRIPS_CRITICAL) { ++ status = acpi_evaluate_integer(tz->device->handle, ++ "_CRT", NULL, &tz->trips.critical.temperature); ++ if (ACPI_FAILURE(status)) { + tz->trips.critical.flags.valid = 0; +- } else if (crt > 0) { +- unsigned long crt_k = CELSIUS_TO_KELVIN(crt); +- +- /* +- * Allow override to lower critical threshold +- */ +- if (crt_k < tz->trips.critical.temperature) +- tz->trips.critical.temperature = crt_k; ++ ACPI_EXCEPTION((AE_INFO, status, ++ "No critical threshold")); ++ return -ENODEV; ++ } else { ++ tz->trips.critical.flags.valid = 1; ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, ++ "Found critical threshold [%lu]\n", ++ tz->trips.critical.temperature)); ++ } ++ if (tz->trips.critical.flags.valid == 1) { ++ if (crt == -1) { ++ tz->trips.critical.flags.valid = 0; ++ } else if (crt > 0) { ++ unsigned long crt_k = CELSIUS_TO_KELVIN(crt); ++ /* ++ * Allow override to lower critical threshold ++ */ ++ if (crt_k < tz->trips.critical.temperature) ++ tz->trips.critical.temperature = crt_k; ++ } + } + } + + /* Critical Sleep (optional) */ +- +- status = +- acpi_evaluate_integer(tz->device->handle, "_HOT", NULL, +- &tz->trips.hot.temperature); +- if (ACPI_FAILURE(status)) { +- tz->trips.hot.flags.valid = 0; +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n")); +- } else { +- tz->trips.hot.flags.valid = 1; +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n", +- tz->trips.hot.temperature)); +- } +- +- /* Passive: Processors (optional) */ +- +- if (psv == -1) { +- status = AE_SUPPORT; +- } else if (psv > 0) { +- tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv); +- status = AE_OK; +- } else { ++ if (flag & ACPI_TRIPS_HOT) { + status = acpi_evaluate_integer(tz->device->handle, +- "_PSV", NULL, &tz->trips.passive.temperature); ++ "_HOT", NULL, &tz->trips.hot.temperature); ++ if (ACPI_FAILURE(status)) { ++ tz->trips.hot.flags.valid = 0; ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, ++ "No hot threshold\n")); ++ } else { ++ tz->trips.hot.flags.valid = 1; ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, ++ "Found hot threshold [%lu]\n", ++ tz->trips.critical.temperature)); ++ } + } + +- if (ACPI_FAILURE(status)) { +- tz->trips.passive.flags.valid = 0; +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n")); +- } else { +- tz->trips.passive.flags.valid = 1; +- +- status = +- acpi_evaluate_integer(tz->device->handle, "_TC1", NULL, +- &tz->trips.passive.tc1); +- if (ACPI_FAILURE(status)) +- tz->trips.passive.flags.valid = 0; +- +- status = +- acpi_evaluate_integer(tz->device->handle, "_TC2", NULL, +- &tz->trips.passive.tc2); +- if (ACPI_FAILURE(status)) +- tz->trips.passive.flags.valid = 0; ++ /* Passive (optional) */ ++ if (flag & ACPI_TRIPS_PASSIVE) { ++ valid = tz->trips.passive.flags.valid; ++ if (psv == -1) { ++ status = AE_SUPPORT; ++ } else if (psv > 0) { ++ tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv); ++ status = AE_OK; ++ } else { ++ status = acpi_evaluate_integer(tz->device->handle, ++ "_PSV", NULL, &tz->trips.passive.temperature); ++ } + +- status = +- acpi_evaluate_integer(tz->device->handle, "_TSP", NULL, +- &tz->trips.passive.tsp); + if (ACPI_FAILURE(status)) + tz->trips.passive.flags.valid = 0; +- +- status = +- acpi_evaluate_reference(tz->device->handle, "_PSL", NULL, +- &tz->trips.passive.devices); ++ else { ++ tz->trips.passive.flags.valid = 1; ++ if (flag == ACPI_TRIPS_INIT) { ++ status = acpi_evaluate_integer( ++ tz->device->handle, "_TC1", ++ NULL, &tz->trips.passive.tc1); ++ if (ACPI_FAILURE(status)) ++ tz->trips.passive.flags.valid = 0; ++ status = acpi_evaluate_integer( ++ tz->device->handle, "_TC2", ++ NULL, &tz->trips.passive.tc2); ++ if (ACPI_FAILURE(status)) ++ tz->trips.passive.flags.valid = 0; ++ status = acpi_evaluate_integer( ++ tz->device->handle, "_TSP", ++ NULL, &tz->trips.passive.tsp); ++ if (ACPI_FAILURE(status)) ++ tz->trips.passive.flags.valid = 0; ++ } ++ } ++ } ++ if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) { ++ memset(&devices, 0, sizeof(struct acpi_handle_list)); ++ status = acpi_evaluate_reference(tz->device->handle, "_PSL", ++ NULL, &devices); + if (ACPI_FAILURE(status)) + tz->trips.passive.flags.valid = 0; +- +- if (!tz->trips.passive.flags.valid) +- printk(KERN_WARNING PREFIX "Invalid passive threshold\n"); + else +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, +- "Found passive threshold [%lu]\n", +- tz->trips.passive.temperature)); +- } ++ tz->trips.passive.flags.valid = 1; + +- /* Active: Fans, etc. (optional) */ ++ if (memcmp(&tz->trips.passive.devices, &devices, ++ sizeof(struct acpi_handle_list))) { ++ memcpy(&tz->trips.passive.devices, &devices, ++ sizeof(struct acpi_handle_list)); ++ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); ++ } ++ } ++ if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) { ++ if (valid != tz->trips.passive.flags.valid) ++ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state"); ++ } + ++ /* Active (optional) */ + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { +- + char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; ++ valid = tz->trips.active[i].flags.valid; + + if (act == -1) +- break; /* disable all active trip points */ +- +- status = acpi_evaluate_integer(tz->device->handle, +- name, NULL, &tz->trips.active[i].temperature); +- +- if (ACPI_FAILURE(status)) { +- if (i == 0) /* no active trip points */ ++ break; /* disable all active trip points */ ++ ++ if (flag & ACPI_TRIPS_ACTIVE) { ++ status = acpi_evaluate_integer(tz->device->handle, ++ name, NULL, &tz->trips.active[i].temperature); ++ if (ACPI_FAILURE(status)) { ++ tz->trips.active[i].flags.valid = 0; ++ if (i == 0) ++ break; ++ if (act <= 0) ++ break; ++ if (i == 1) ++ tz->trips.active[0].temperature = ++ CELSIUS_TO_KELVIN(act); ++ else ++ /* ++ * Don't allow override higher than ++ * the next higher trip point ++ */ ++ tz->trips.active[i - 1].temperature = ++ (tz->trips.active[i - 2].temperature < ++ CELSIUS_TO_KELVIN(act) ? ++ tz->trips.active[i - 2].temperature : ++ CELSIUS_TO_KELVIN(act)); + break; +- if (act <= 0) /* no override requested */ +- break; +- if (i == 1) { /* 1 trip point */ +- tz->trips.active[0].temperature = +- CELSIUS_TO_KELVIN(act); +- } else { /* multiple trips */ +- /* +- * Don't allow override higher than +- * the next higher trip point +- */ +- tz->trips.active[i - 1].temperature = +- (tz->trips.active[i - 2].temperature < +- CELSIUS_TO_KELVIN(act) ? +- tz->trips.active[i - 2].temperature : +- CELSIUS_TO_KELVIN(act)); +- } +- break; ++ } else ++ tz->trips.active[i].flags.valid = 1; + } + + name[2] = 'L'; +- status = +- acpi_evaluate_reference(tz->device->handle, name, NULL, +- &tz->trips.active[i].devices); +- if (ACPI_SUCCESS(status)) { +- tz->trips.active[i].flags.valid = 1; +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, +- "Found active threshold [%d]:[%lu]\n", +- i, tz->trips.active[i].temperature)); +- } else +- ACPI_EXCEPTION((AE_INFO, status, +- "Invalid active threshold [%d]", i)); ++ if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) { ++ memset(&devices, 0, sizeof(struct acpi_handle_list)); ++ status = acpi_evaluate_reference(tz->device->handle, ++ name, NULL, &devices); ++ if (ACPI_FAILURE(status)) ++ tz->trips.active[i].flags.valid = 0; ++ else ++ tz->trips.active[i].flags.valid = 1; ++ ++ if (memcmp(&tz->trips.active[i].devices, &devices, ++ sizeof(struct acpi_handle_list))) { ++ memcpy(&tz->trips.active[i].devices, &devices, ++ sizeof(struct acpi_handle_list)); ++ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); ++ } ++ } ++ if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES)) ++ if (valid != tz->trips.active[i].flags.valid) ++ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state"); ++ ++ if (!tz->trips.active[i].flags.valid) ++ break; ++ } ++ ++ if (flag & ACPI_TRIPS_DEVICES) { ++ memset(&devices, 0, sizeof(struct acpi_handle_list)); ++ status = acpi_evaluate_reference(tz->device->handle, "_TZD", ++ NULL, &devices); ++ if (memcmp(&tz->devices, &devices, ++ sizeof(struct acpi_handle_list))) { ++ memcpy(&tz->devices, &devices, ++ sizeof(struct acpi_handle_list)); ++ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); ++ } + } + + return 0; + } + +-static int acpi_thermal_get_devices(struct acpi_thermal *tz) ++static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) + { +- acpi_status status = AE_OK; +- +- +- if (!tz) +- return -EINVAL; +- +- status = +- acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices); +- if (ACPI_FAILURE(status)) +- return -ENODEV; +- +- return 0; ++ return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT); + } + + static int acpi_thermal_critical(struct acpi_thermal *tz) +@@ -732,6 +779,9 @@ static void acpi_thermal_check(void *data) + if (result) + goto unlock; + ++ if (!tz->tz_enabled) ++ goto unlock; ++ + memset(&tz->state, 0, sizeof(tz->state)); + + /* +@@ -825,6 +875,290 @@ static void acpi_thermal_check(void *data) + mutex_unlock(&tz->lock); + } + ++/* sys I/F for generic thermal sysfs support */ ++static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf) ++{ ++ struct acpi_thermal *tz = thermal->devdata; ++ ++ if (!tz) ++ return -EINVAL; ++ ++ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature)); ++} ++ ++static const char enabled[] = "kernel"; ++static const char disabled[] = "user"; ++static int thermal_get_mode(struct thermal_zone_device *thermal, ++ char *buf) ++{ ++ struct acpi_thermal *tz = thermal->devdata; ++ ++ if (!tz) ++ return -EINVAL; ++ ++ return sprintf(buf, "%s\n", tz->tz_enabled ? ++ enabled : disabled); ++} ++ ++static int thermal_set_mode(struct thermal_zone_device *thermal, ++ const char *buf) ++{ ++ struct acpi_thermal *tz = thermal->devdata; ++ int enable; ++ ++ if (!tz) ++ return -EINVAL; ++ ++ /* ++ * enable/disable thermal management from ACPI thermal driver ++ */ ++ if (!strncmp(buf, enabled, sizeof enabled - 1)) ++ enable = 1; ++ else if (!strncmp(buf, disabled, sizeof disabled - 1)) ++ enable = 0; ++ else ++ return -EINVAL; ++ ++ if (enable != tz->tz_enabled) { ++ tz->tz_enabled = enable; ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, ++ "%s ACPI thermal control\n", ++ tz->tz_enabled ? enabled : disabled)); ++ acpi_thermal_check(tz); ++ } ++ return 0; ++} ++ ++static int thermal_get_trip_type(struct thermal_zone_device *thermal, ++ int trip, char *buf) ++{ ++ struct acpi_thermal *tz = thermal->devdata; ++ int i; ++ ++ if (!tz || trip < 0) ++ return -EINVAL; ++ ++ if (tz->trips.critical.flags.valid) { ++ if (!trip) ++ return sprintf(buf, "critical\n"); ++ trip--; ++ } ++ ++ if (tz->trips.hot.flags.valid) { ++ if (!trip) ++ return sprintf(buf, "hot\n"); ++ trip--; ++ } ++ ++ if (tz->trips.passive.flags.valid) { ++ if (!trip) ++ return sprintf(buf, "passive\n"); ++ trip--; ++ } ++ ++ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && ++ tz->trips.active[i].flags.valid; i++) { ++ if (!trip) ++ return sprintf(buf, "active%d\n", i); ++ trip--; ++ } ++ ++ return -EINVAL; ++} ++ ++static int thermal_get_trip_temp(struct thermal_zone_device *thermal, ++ int trip, char *buf) ++{ ++ struct acpi_thermal *tz = thermal->devdata; ++ int i; ++ ++ if (!tz || trip < 0) ++ return -EINVAL; ++ ++ if (tz->trips.critical.flags.valid) { ++ if (!trip) ++ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( ++ tz->trips.critical.temperature)); ++ trip--; ++ } ++ ++ if (tz->trips.hot.flags.valid) { ++ if (!trip) ++ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( ++ tz->trips.hot.temperature)); ++ trip--; ++ } ++ ++ if (tz->trips.passive.flags.valid) { ++ if (!trip) ++ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( ++ tz->trips.passive.temperature)); ++ trip--; ++ } ++ ++ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && ++ tz->trips.active[i].flags.valid; i++) { ++ if (!trip) ++ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( ++ tz->trips.active[i].temperature)); ++ trip--; ++ } ++ ++ return -EINVAL; ++} ++ ++typedef int (*cb)(struct thermal_zone_device *, int, ++ struct thermal_cooling_device *); ++static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, ++ struct thermal_cooling_device *cdev, ++ cb action) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_thermal *tz = thermal->devdata; ++ struct acpi_device *dev; ++ acpi_status status; ++ acpi_handle handle; ++ int i; ++ int j; ++ int trip = -1; ++ int result = 0; ++ ++ if (tz->trips.critical.flags.valid) ++ trip++; ++ ++ if (tz->trips.hot.flags.valid) ++ trip++; ++ ++ if (tz->trips.passive.flags.valid) { ++ trip++; ++ for (i = 0; i < tz->trips.passive.devices.count; ++ i++) { ++ handle = tz->trips.passive.devices.handles[i]; ++ status = acpi_bus_get_device(handle, &dev); ++ if (ACPI_SUCCESS(status) && (dev == device)) { ++ result = action(thermal, trip, cdev); ++ if (result) ++ goto failed; ++ } ++ } ++ } ++ ++ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { ++ if (!tz->trips.active[i].flags.valid) ++ break; ++ trip++; ++ for (j = 0; ++ j < tz->trips.active[i].devices.count; ++ j++) { ++ handle = tz->trips.active[i].devices.handles[j]; ++ status = acpi_bus_get_device(handle, &dev); ++ if (ACPI_SUCCESS(status) && (dev == device)) { ++ result = action(thermal, trip, cdev); ++ if (result) ++ goto failed; ++ } ++ } ++ } ++ ++ for (i = 0; i < tz->devices.count; i++) { ++ handle = tz->devices.handles[i]; ++ status = acpi_bus_get_device(handle, &dev); ++ if (ACPI_SUCCESS(status) && (dev == device)) { ++ result = action(thermal, -1, cdev); ++ if (result) ++ goto failed; ++ } ++ } ++ ++failed: ++ return result; ++} ++ ++static int ++acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal, ++ struct thermal_cooling_device *cdev) ++{ ++ return acpi_thermal_cooling_device_cb(thermal, cdev, ++ thermal_zone_bind_cooling_device); ++} ++ ++static int ++acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal, ++ struct thermal_cooling_device *cdev) ++{ ++ return acpi_thermal_cooling_device_cb(thermal, cdev, ++ thermal_zone_unbind_cooling_device); ++} ++ ++static struct thermal_zone_device_ops acpi_thermal_zone_ops = { ++ .bind = acpi_thermal_bind_cooling_device, ++ .unbind = acpi_thermal_unbind_cooling_device, ++ .get_temp = thermal_get_temp, ++ .get_mode = thermal_get_mode, ++ .set_mode = thermal_set_mode, ++ .get_trip_type = thermal_get_trip_type, ++ .get_trip_temp = thermal_get_trip_temp, ++}; ++ ++static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) ++{ ++ int trips = 0; ++ int result; ++ acpi_status status; ++ int i; ++ ++ if (tz->trips.critical.flags.valid) ++ trips++; ++ ++ if (tz->trips.hot.flags.valid) ++ trips++; ++ ++ if (tz->trips.passive.flags.valid) ++ trips++; ++ ++ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && ++ tz->trips.active[i].flags.valid; i++, trips++); ++ tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone", ++ trips, tz, &acpi_thermal_zone_ops); ++ if (!tz->thermal_zone) ++ return -ENODEV; ++ ++ result = sysfs_create_link(&tz->device->dev.kobj, ++ &tz->thermal_zone->device.kobj, "thermal_zone"); ++ if (result) ++ return result; ++ ++ result = sysfs_create_link(&tz->thermal_zone->device.kobj, ++ &tz->device->dev.kobj, "device"); ++ if (result) ++ return result; ++ ++ status = acpi_attach_data(tz->device->handle, ++ acpi_bus_private_data_handler, ++ tz->thermal_zone); ++ if (ACPI_FAILURE(status)) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "Error attaching device data\n")); ++ return -ENODEV; ++ } ++ ++ tz->tz_enabled = 1; ++ ++ printk(KERN_INFO PREFIX "%s is registered as thermal_zone%d\n", ++ tz->device->dev.bus_id, tz->thermal_zone->id); ++ return 0; ++} ++ ++static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) ++{ ++ sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone"); ++ sysfs_remove_link(&tz->thermal_zone->device.kobj, "device"); ++ thermal_zone_device_unregister(tz->thermal_zone); ++ tz->thermal_zone = NULL; ++ acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler); ++} ++ ++ + /* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ +@@ -1181,15 +1515,15 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data) + acpi_thermal_check(tz); + break; + case ACPI_THERMAL_NOTIFY_THRESHOLDS: +- acpi_thermal_get_trip_points(tz); ++ acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS); + acpi_thermal_check(tz); + acpi_bus_generate_proc_event(device, event, 0); + acpi_bus_generate_netlink_event(device->pnp.device_class, + device->dev.bus_id, event, 0); + break; + case ACPI_THERMAL_NOTIFY_DEVICES: +- if (tz->flags.devices) +- acpi_thermal_get_devices(tz); ++ acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES); ++ acpi_thermal_check(tz); + acpi_bus_generate_proc_event(device, event, 0); + acpi_bus_generate_netlink_event(device->pnp.device_class, + device->dev.bus_id, event, 0); +@@ -1232,11 +1566,6 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz) + else + acpi_thermal_get_polling_frequency(tz); + +- /* Get devices in this thermal zone [_TZD] (optional) */ +- result = acpi_thermal_get_devices(tz); +- if (!result) +- tz->flags.devices = 1; +- + return 0; + } + +@@ -1260,13 +1589,19 @@ static int acpi_thermal_add(struct acpi_device *device) + strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); + acpi_driver_data(device) = tz; + mutex_init(&tz->lock); ++ ++ + result = acpi_thermal_get_info(tz); + if (result) +- goto end; ++ goto free_memory; ++ ++ result = acpi_thermal_register_thermal_zone(tz); ++ if (result) ++ goto free_memory; + + result = acpi_thermal_add_fs(device); + if (result) +- goto end; ++ goto unregister_thermal_zone; + + init_timer(&tz->timer); + +@@ -1277,19 +1612,21 @@ static int acpi_thermal_add(struct acpi_device *device) + acpi_thermal_notify, tz); + if (ACPI_FAILURE(status)) { + result = -ENODEV; +- goto end; ++ goto remove_fs; + } + + printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n", + acpi_device_name(device), acpi_device_bid(device), + KELVIN_TO_CELSIUS(tz->temperature)); ++ goto end; + +- end: +- if (result) { +- acpi_thermal_remove_fs(device); +- kfree(tz); +- } +- ++remove_fs: ++ acpi_thermal_remove_fs(device); ++unregister_thermal_zone: ++ thermal_zone_device_unregister(tz->thermal_zone); ++free_memory: ++ kfree(tz); ++end: + return result; + } + +@@ -1329,6 +1666,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type) + } + + acpi_thermal_remove_fs(device); ++ acpi_thermal_unregister_thermal_zone(tz); + mutex_destroy(&tz->lock); + kfree(tz); + return 0; +diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c +index 826a52f..c83b76c 100644 +--- a/drivers/acpi/video.c ++++ b/drivers/acpi/video.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -183,6 +184,7 @@ struct acpi_video_device { + struct acpi_device *dev; + struct acpi_video_device_brightness *brightness; + struct backlight_device *backlight; ++ struct thermal_cooling_device *cdev; + struct output_device *output_dev; + }; + +@@ -346,6 +348,54 @@ static struct output_properties acpi_output_properties = { + .set_state = acpi_video_output_set, + .get_status = acpi_video_output_get, + }; ++ ++ ++/* thermal cooling device callbacks */ ++static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_video_device *video = acpi_driver_data(device); ++ ++ return sprintf(buf, "%d\n", video->brightness->count - 3); ++} ++ ++static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_video_device *video = acpi_driver_data(device); ++ unsigned long level; ++ int state; ++ ++ acpi_video_device_lcd_get_level_current(video, &level); ++ for (state = 2; state < video->brightness->count; state++) ++ if (level == video->brightness->levels[state]) ++ return sprintf(buf, "%d\n", ++ video->brightness->count - state - 1); ++ ++ return -EINVAL; ++} ++ ++static int ++video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_video_device *video = acpi_driver_data(device); ++ int level; ++ ++ if ( state >= video->brightness->count - 2) ++ return -EINVAL; ++ ++ state = video->brightness->count - state; ++ level = video->brightness->levels[state -1]; ++ return acpi_video_device_lcd_set_level(video, level); ++} ++ ++static struct thermal_cooling_device_ops video_cooling_ops = { ++ .get_max_state = video_get_max_state, ++ .get_cur_state = video_get_cur_state, ++ .set_cur_state = video_set_cur_state, ++}; ++ + /* -------------------------------------------------------------------------- + Video Management + -------------------------------------------------------------------------- */ +@@ -664,6 +714,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) + kfree(obj); + + if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){ ++ int result; + static int count = 0; + char *name; + name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); +@@ -676,8 +727,25 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) + device->backlight->props.max_brightness = device->brightness->count-3; + device->backlight->props.brightness = acpi_video_get_brightness(device->backlight); + backlight_update_status(device->backlight); +- + kfree(name); ++ ++ device->cdev = thermal_cooling_device_register("LCD", ++ device->dev, &video_cooling_ops); ++ if (device->cdev) { ++ printk(KERN_INFO PREFIX ++ "%s is registered as cooling_device%d\n", ++ device->dev->dev.bus_id, device->cdev->id); ++ result = sysfs_create_link(&device->dev->dev.kobj, ++ &device->cdev->device.kobj, ++ "thermal_cooling"); ++ if (result) ++ printk(KERN_ERR PREFIX "Create sysfs link\n"); ++ result = sysfs_create_link(&device->cdev->device.kobj, ++ &device->dev->dev.kobj, ++ "device"); ++ if (result) ++ printk(KERN_ERR PREFIX "Create sysfs link\n"); ++ } + } + if (device->cap._DCS && device->cap._DSS){ + static int count = 0; +@@ -1739,6 +1807,14 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) + ACPI_DEVICE_NOTIFY, + acpi_video_device_notify); + backlight_device_unregister(device->backlight); ++ if (device->cdev) { ++ sysfs_remove_link(&device->dev->dev.kobj, ++ "thermal_cooling"); ++ sysfs_remove_link(&device->cdev->device.kobj, ++ "device"); ++ thermal_cooling_device_unregister(device->cdev); ++ device->cdev = NULL; ++ } + video_output_unregister(device->output_dev); + + return 0; +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index b5e67c0..46a131a 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -232,4 +232,14 @@ config ATMEL_SSC + + If unsure, say N. + ++config INTEL_MENLOW ++ tristate "Thermal Management driver for Intel menlow platform" ++ depends on ACPI_THERMAL ++ default n ++ ---help--- ++ ACPI thermal management enhancement driver on ++ Intel Menlow platform. ++ ++ If you are not sure, say N here. ++ + endif # MISC_DEVICES +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index 757762b..fb70db8 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -18,3 +18,4 @@ obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o + obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o + obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o + obj-$(CONFIG_KGDB_TESTS) += kgdbts.o ++obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o +diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c +new file mode 100644 +index 0000000..753dc5f +--- /dev/null ++++ b/drivers/misc/intel_menlow.c +@@ -0,0 +1,527 @@ ++/* ++* intel_menlow.c - Intel menlow Driver for thermal management extension ++* ++* Copyright (C) 2008 Intel Corp ++* Copyright (C) 2008 Sujith Thomas ++* Copyright (C) 2008 Zhang Rui ++* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++* ++* 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; version 2 of the License. ++* ++* This program is distributed in the hope that it will be useful, but ++* WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++* General Public License for more details. ++* ++* You should have received a copy of the GNU General Public License along ++* with this program; if not, write to the Free Software Foundation, Inc., ++* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++* ++* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++* ++* This driver creates the sys I/F for programming the sensors. ++* It also implements the driver for intel menlow memory controller (hardware ++* id is INT0002) which makes use of the platform specific ACPI methods ++* to get/set bandwidth. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Thomas Sujith"); ++MODULE_AUTHOR("Zhang Rui"); ++MODULE_DESCRIPTION("Intel Menlow platform specific driver"); ++MODULE_LICENSE("GPL"); ++ ++/* ++ * Memory controller device control ++ */ ++ ++#define MEMORY_GET_BANDWIDTH "GTHS" ++#define MEMORY_SET_BANDWIDTH "STHS" ++#define MEMORY_ARG_CUR_BANDWIDTH 1 ++#define MEMORY_ARG_MAX_BANDWIDTH 0 ++ ++static int ++memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev, ++ unsigned long *max_state) ++{ ++ struct acpi_device *device = cdev->devdata; ++ acpi_handle handle = device->handle; ++ unsigned long value; ++ struct acpi_object_list arg_list; ++ union acpi_object arg; ++ acpi_status status = AE_OK; ++ ++ arg_list.count = 1; ++ arg_list.pointer = &arg; ++ arg.type = ACPI_TYPE_INTEGER; ++ arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH; ++ status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, ++ &arg_list, &value); ++ if (ACPI_FAILURE(status)) ++ return -EFAULT; ++ ++ *max_state = value - 1; ++ return 0; ++} ++ ++static int ++memory_get_max_bandwidth(struct thermal_cooling_device *cdev, char *buf) ++{ ++ unsigned long value; ++ if (memory_get_int_max_bandwidth(cdev,&value)) ++ return -EINVAL; ++ ++ return sprintf(buf, "%ld\n", value); ++} ++ ++static int ++memory_get_cur_bandwidth(struct thermal_cooling_device *cdev, char *buf) ++{ ++ struct acpi_device *device = cdev->devdata; ++ acpi_handle handle = device->handle; ++ unsigned long value; ++ struct acpi_object_list arg_list; ++ union acpi_object arg; ++ acpi_status status = AE_OK; ++ ++ arg_list.count = 1; ++ arg_list.pointer = &arg; ++ arg.type = ACPI_TYPE_INTEGER; ++ arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH; ++ status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, ++ &arg_list, &value); ++ if (ACPI_FAILURE(status)) ++ return -EFAULT; ++ ++ return sprintf(buf, "%ld\n", value); ++} ++ ++static int ++memory_set_cur_bandwidth(struct thermal_cooling_device *cdev, ++ unsigned int state) ++{ ++ struct acpi_device *device = cdev->devdata; ++ acpi_handle handle = device->handle; ++ struct acpi_object_list arg_list; ++ union acpi_object arg; ++ acpi_status status; ++ int temp; ++ unsigned long max_state; ++ ++ if (memory_get_int_max_bandwidth(cdev,&max_state)) ++ return -EFAULT; ++ ++ if (max_state < 0 || state > max_state) ++ return -EINVAL; ++ ++ arg_list.count = 1; ++ arg_list.pointer = &arg; ++ arg.type = ACPI_TYPE_INTEGER; ++ arg.integer.value = state; ++ ++ status = ++ acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list, ++ (unsigned long *)&temp); ++ ++ printk(KERN_INFO ++ "Bandwidth value was %d: status is %d\n", state, status); ++ if (ACPI_FAILURE(status)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static struct thermal_cooling_device_ops memory_cooling_ops = { ++ .get_max_state = memory_get_max_bandwidth, ++ .get_cur_state = memory_get_cur_bandwidth, ++ .set_cur_state = memory_set_cur_bandwidth, ++}; ++ ++/* ++ * Memory Device Management ++ */ ++static int intel_menlow_memory_add(struct acpi_device *device) ++{ ++ int result = -ENODEV; ++ acpi_status status = AE_OK; ++ acpi_handle dummy; ++ struct thermal_cooling_device *cdev; ++ ++ if (!device) ++ return -EINVAL; ++ ++ status = acpi_get_handle(device->handle, MEMORY_GET_BANDWIDTH, &dummy); ++ if (ACPI_FAILURE(status)) ++ goto end; ++ ++ status = acpi_get_handle(device->handle, MEMORY_SET_BANDWIDTH, &dummy); ++ if (ACPI_FAILURE(status)) ++ goto end; ++ ++ cdev = thermal_cooling_device_register("Memory controller", device, ++ &memory_cooling_ops); ++ acpi_driver_data(device) = cdev; ++ if (!cdev) ++ result = -ENODEV; ++ else { ++ result = ++ sysfs_create_link(&device->dev.kobj, &cdev->device.kobj, ++ "thermal_cooling"); ++ if (result) ++ goto end; ++ result = ++ sysfs_create_link(&cdev->device.kobj, &device->dev.kobj, ++ "device"); ++ if (result) ++ goto end; ++ } ++ ++ end: ++ return result; ++} ++ ++static int intel_menlow_memory_remove(struct acpi_device *device, int type) ++{ ++ struct thermal_cooling_device *cdev = acpi_driver_data(device); ++ ++ if (!device || !cdev) ++ return -EINVAL; ++ ++ sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); ++ sysfs_remove_link(&cdev->device.kobj, "device"); ++ thermal_cooling_device_unregister(cdev); ++ ++ return 0; ++} ++ ++const static struct acpi_device_id intel_menlow_memory_ids[] = { ++ {"INT0002", 0}, ++ {"", 0}, ++}; ++ ++static struct acpi_driver intel_menlow_memory_driver = { ++ .name = "intel_menlow_thermal_control", ++ .ids = intel_menlow_memory_ids, ++ .ops = { ++ .add = intel_menlow_memory_add, ++ .remove = intel_menlow_memory_remove, ++ }, ++}; ++ ++/* ++ * Sensor control on menlow platform ++ */ ++ ++#define THERMAL_AUX0 0 ++#define THERMAL_AUX1 1 ++#define GET_AUX0 "GAX0" ++#define GET_AUX1 "GAX1" ++#define SET_AUX0 "SAX0" ++#define SET_AUX1 "SAX1" ++ ++struct intel_menlow_attribute { ++ struct device_attribute attr; ++ struct device *device; ++ acpi_handle handle; ++ struct list_head node; ++}; ++ ++static LIST_HEAD(intel_menlow_attr_list); ++static DEFINE_MUTEX(intel_menlow_attr_lock); ++ ++/* ++ * sensor_get_auxtrip ++ * ----------------- ++ * get the current auxtrip value from sensor through proprietory ACPI methods ++ * name: Thermalzone name ++ * auxtype : AUX0/AUX1 ++ * buf: syfs buffer ++ */ ++static int sensor_get_auxtrip(acpi_handle handle, int index, int *value) ++{ ++ acpi_status status; ++ ++ if ((index != 0 && index != 1) || !value) ++ return -EINVAL; ++ ++ status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0, ++ NULL, (unsigned long *)value); ++ if (ACPI_FAILURE(status)) ++ return -EIO; ++ ++ return 0; ++} ++ ++/* ++ * sensor_set_auxtrip ++ * ----------------- ++ * set the new auxtrip value to sensor through proprietory ACPI methods ++ * name: Thermalzone name ++ * auxtype : AUX0/AUX1 ++ * buf: syfs buffer ++ */ ++static int sensor_set_auxtrip(acpi_handle handle, int index, int value) ++{ ++ acpi_status status; ++ union acpi_object arg = { ++ ACPI_TYPE_INTEGER ++ }; ++ struct acpi_object_list args = { ++ 1, &arg ++ }; ++ int temp; ++ ++ if (index != 0 && index != 1) ++ return -EINVAL; ++ ++ status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1, ++ NULL, (unsigned long *)&temp); ++ if (ACPI_FAILURE(status)) ++ return -EIO; ++ if ((index && value < temp) || (!index && value > temp)) ++ return -EINVAL; ++ ++ arg.integer.value = value; ++ status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0, ++ &args, (unsigned long *)&temp); ++ if (ACPI_FAILURE(status)) ++ return -EIO; ++ ++ /* do we need to check the return value of SAX0/SAX1 ? */ ++ ++ return 0; ++} ++ ++#define to_intel_menlow_attr(_attr) \ ++ container_of(_attr, struct intel_menlow_attribute, attr) ++ ++static ssize_t aux0_show(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); ++ int value; ++ int result; ++ ++ result = sensor_get_auxtrip(attr->handle, 0, &value); ++ ++ return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); ++} ++ ++static ssize_t aux1_show(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); ++ int value; ++ int result; ++ ++ result = sensor_get_auxtrip(attr->handle, 1, &value); ++ ++ return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); ++} ++ ++static ssize_t aux0_store(struct device *dev, ++ struct device_attribute *dev_attr, ++ const char *buf, size_t count) ++{ ++ struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); ++ int value; ++ int result; ++ ++ /*Sanity check; should be a positive integer */ ++ if (!sscanf(buf, "%d", &value)) ++ return -EINVAL; ++ ++ if (value < 0) ++ return -EINVAL; ++ ++ result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value)); ++ return result ? result : count; ++} ++ ++static ssize_t aux1_store(struct device *dev, ++ struct device_attribute *dev_attr, ++ const char *buf, size_t count) ++{ ++ struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); ++ int value; ++ int result; ++ ++ /*Sanity check; should be a positive integer */ ++ if (!sscanf(buf, "%d", &value)) ++ return -EINVAL; ++ ++ if (value < 0) ++ return -EINVAL; ++ ++ result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value)); ++ return result ? result : count; ++} ++ ++/* BIOS can enable/disable the thermal user application in dabney platform */ ++#define BIOS_ENABLED "\\_TZ.GSTS" ++static ssize_t bios_enabled_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ acpi_status status; ++ unsigned long bios_enabled; ++ ++ status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled); ++ if (ACPI_FAILURE(status)) ++ return -ENODEV; ++ ++ return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled"); ++} ++ ++static int intel_menlow_add_one_attribute(char *name, int mode, void *show, ++ void *store, struct device *dev, ++ acpi_handle handle) ++{ ++ struct intel_menlow_attribute *attr; ++ int result; ++ ++ attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL); ++ if (!attr) ++ return -ENOMEM; ++ ++ attr->attr.attr.name = name; ++ attr->attr.attr.mode = mode; ++ attr->attr.show = show; ++ attr->attr.store = store; ++ attr->device = dev; ++ attr->handle = handle; ++ ++ result = device_create_file(dev, &attr->attr); ++ if (result) ++ return result; ++ ++ mutex_lock(&intel_menlow_attr_lock); ++ list_add_tail(&attr->node, &intel_menlow_attr_list); ++ mutex_unlock(&intel_menlow_attr_lock); ++ ++ return 0; ++} ++ ++static acpi_status ++intel_menlow_register_sensor(acpi_handle handle, u32 lvl, ++ void *context, void **rv) ++{ ++ acpi_status status; ++ acpi_handle dummy; ++ struct thermal_zone_device *thermal; ++ int result; ++ ++ result = acpi_bus_get_private_data(handle, (void **)&thermal); ++ if (result) ++ return 0; ++ ++ /* _TZ must have the AUX0/1 methods */ ++ status = acpi_get_handle(handle, GET_AUX0, &dummy); ++ if (ACPI_FAILURE(status)) ++ goto not_found; ++ ++ status = acpi_get_handle(handle, SET_AUX0, &dummy); ++ if (ACPI_FAILURE(status)) ++ goto not_found; ++ ++ result = intel_menlow_add_one_attribute("aux0", 0644, ++ aux0_show, aux0_store, ++ &thermal->device, handle); ++ if (result) ++ return AE_ERROR; ++ ++ status = acpi_get_handle(handle, GET_AUX1, &dummy); ++ if (ACPI_FAILURE(status)) ++ goto not_found; ++ ++ status = acpi_get_handle(handle, SET_AUX1, &dummy); ++ if (ACPI_FAILURE(status)) ++ goto not_found; ++ ++ result = intel_menlow_add_one_attribute("aux1", 0644, ++ aux1_show, aux1_store, ++ &thermal->device, handle); ++ if (result) ++ return AE_ERROR; ++ ++ /* ++ * create the "dabney_enabled" attribute which means the user app ++ * should be loaded or not ++ */ ++ ++ result = intel_menlow_add_one_attribute("bios_enabled", 0444, ++ bios_enabled_show, NULL, ++ &thermal->device, handle); ++ if (result) ++ return AE_ERROR; ++ ++ not_found: ++ if (status == AE_NOT_FOUND) ++ return AE_OK; ++ else ++ return status; ++} ++ ++static void intel_menlow_unregister_sensor(void) ++{ ++ struct intel_menlow_attribute *pos, *next; ++ ++ mutex_lock(&intel_menlow_attr_lock); ++ list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) { ++ list_del(&pos->node); ++ device_remove_file(pos->device, &pos->attr); ++ kfree(pos); ++ } ++ mutex_unlock(&intel_menlow_attr_lock); ++ ++ return; ++} ++ ++static int __init intel_menlow_module_init(void) ++{ ++ int result = -ENODEV; ++ acpi_status status; ++ unsigned long enable; ++ ++ if (acpi_disabled) ++ return result; ++ ++ /* Looking for the \_TZ.GSTS method */ ++ status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable); ++ if (ACPI_FAILURE(status) || !enable) ++ return -ENODEV; ++ ++ /* Looking for ACPI device MEM0 with hardware id INT0002 */ ++ result = acpi_bus_register_driver(&intel_menlow_memory_driver); ++ if (result) ++ return result; ++ ++ /* Looking for sensors in each ACPI thermal zone */ ++ status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT, ++ ACPI_UINT32_MAX, ++ intel_menlow_register_sensor, NULL, NULL); ++ if (ACPI_FAILURE(status)) ++ result = -ENODEV; ++ ++ return 0; ++} ++ ++static void __exit intel_menlow_module_exit(void) ++{ ++ acpi_bus_unregister_driver(&intel_menlow_memory_driver); ++ intel_menlow_unregister_sensor(); ++} ++ ++module_init(intel_menlow_module_init); ++module_exit(intel_menlow_module_exit); +diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig +new file mode 100644 +index 0000000..b879d27 +--- /dev/null ++++ b/drivers/thermal/Kconfig +@@ -0,0 +1,16 @@ ++# ++# Generic thermal sysfs drivers configuration ++# ++ ++menuconfig THERMAL ++ bool "Generic Thermal sysfs driver" ++ default y ++ help ++ Generic Thermal Sysfs driver offers a generic mechanism for ++ thermal management. Usually it's made up of one or more thermal ++ zone and cooling device. ++ each thermal zone contains its own temperature, trip points, ++ cooling devices. ++ All platforms with ACPI thermal support can use this driver. ++ If you want this support, you should say Y here ++ +diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile +new file mode 100644 +index 0000000..75b4bf2 +--- /dev/null ++++ b/drivers/thermal/Makefile +@@ -0,0 +1,6 @@ ++# ++# Makefile for sensor chip drivers. ++# ++ ++obj-$(CONFIG_THERMAL) += thermal.o ++ +diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal.c +new file mode 100644 +index 0000000..3273e34 +--- /dev/null ++++ b/drivers/thermal/thermal.c +@@ -0,0 +1,714 @@ ++/* ++ * thermal.c - Generic Thermal Management Sysfs support. ++ * ++ * Copyright (C) 2008 Intel Corp ++ * Copyright (C) 2008 Zhang Rui ++ * Copyright (C) 2008 Sujith Thomas ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * 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; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Zhang Rui") ++MODULE_DESCRIPTION("Generic thermal management sysfs support"); ++MODULE_LICENSE("GPL"); ++ ++#define PREFIX "Thermal: " ++ ++struct thermal_cooling_device_instance { ++ int id; ++ char name[THERMAL_NAME_LENGTH]; ++ struct thermal_zone_device *tz; ++ struct thermal_cooling_device *cdev; ++ int trip; ++ char attr_name[THERMAL_NAME_LENGTH]; ++ struct device_attribute attr; ++ struct list_head node; ++}; ++ ++static DEFINE_IDR(thermal_tz_idr); ++static DEFINE_IDR(thermal_cdev_idr); ++static DEFINE_MUTEX(thermal_idr_lock); ++ ++static LIST_HEAD(thermal_tz_list); ++static LIST_HEAD(thermal_cdev_list); ++static DEFINE_MUTEX(thermal_list_lock); ++ ++static int get_idr(struct idr *idr, struct mutex *lock, int *id) ++{ ++ int err; ++ ++ again: ++ if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0)) ++ return -ENOMEM; ++ ++ if (lock) ++ mutex_lock(lock); ++ err = idr_get_new(idr, NULL, id); ++ if (lock) ++ mutex_unlock(lock); ++ if (unlikely(err == -EAGAIN)) ++ goto again; ++ else if (unlikely(err)) ++ return err; ++ ++ *id = *id & MAX_ID_MASK; ++ return 0; ++} ++ ++static void release_idr(struct idr *idr, struct mutex *lock, int id) ++{ ++ if (lock) ++ mutex_lock(lock); ++ idr_remove(idr, id); ++ if (lock) ++ mutex_unlock(lock); ++} ++ ++/* sys I/F for thermal zone */ ++ ++#define to_thermal_zone(_dev) \ ++ container_of(_dev, struct thermal_zone_device, device) ++ ++static ssize_t ++type_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ ++ return sprintf(buf, "%s\n", tz->type); ++} ++ ++static ssize_t ++temp_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ ++ if (!tz->ops->get_temp) ++ return -EPERM; ++ ++ return tz->ops->get_temp(tz, buf); ++} ++ ++static ssize_t ++mode_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ ++ if (!tz->ops->get_mode) ++ return -EPERM; ++ ++ return tz->ops->get_mode(tz, buf); ++} ++ ++static ssize_t ++mode_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ int result; ++ ++ if (!tz->ops->set_mode) ++ return -EPERM; ++ ++ result = tz->ops->set_mode(tz, buf); ++ if (result) ++ return result; ++ ++ return count; ++} ++ ++static ssize_t ++trip_point_type_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ int trip; ++ ++ if (!tz->ops->get_trip_type) ++ return -EPERM; ++ ++ if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) ++ return -EINVAL; ++ ++ return tz->ops->get_trip_type(tz, trip, buf); ++} ++ ++static ssize_t ++trip_point_temp_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ int trip; ++ ++ if (!tz->ops->get_trip_temp) ++ return -EPERM; ++ ++ if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip)) ++ return -EINVAL; ++ ++ return tz->ops->get_trip_temp(tz, trip, buf); ++} ++ ++static DEVICE_ATTR(type, 0444, type_show, NULL); ++static DEVICE_ATTR(temp, 0444, temp_show, NULL); ++static DEVICE_ATTR(mode, 0644, mode_show, mode_store); ++ ++static struct device_attribute trip_point_attrs[] = { ++ __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL), ++}; ++ ++#define TRIP_POINT_ATTR_ADD(_dev, _index, result) \ ++do { \ ++ result = device_create_file(_dev, \ ++ &trip_point_attrs[_index * 2]); \ ++ if (result) \ ++ break; \ ++ result = device_create_file(_dev, \ ++ &trip_point_attrs[_index * 2 + 1]); \ ++} while (0) ++ ++#define TRIP_POINT_ATTR_REMOVE(_dev, _index) \ ++do { \ ++ device_remove_file(_dev, &trip_point_attrs[_index * 2]); \ ++ device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ ++} while (0) ++ ++/* sys I/F for cooling device */ ++#define to_cooling_device(_dev) \ ++ container_of(_dev, struct thermal_cooling_device, device) ++ ++static ssize_t ++thermal_cooling_device_type_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct thermal_cooling_device *cdev = to_cooling_device(dev); ++ ++ return sprintf(buf, "%s\n", cdev->type); ++} ++ ++static ssize_t ++thermal_cooling_device_max_state_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct thermal_cooling_device *cdev = to_cooling_device(dev); ++ ++ return cdev->ops->get_max_state(cdev, buf); ++} ++ ++static ssize_t ++thermal_cooling_device_cur_state_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct thermal_cooling_device *cdev = to_cooling_device(dev); ++ ++ return cdev->ops->get_cur_state(cdev, buf); ++} ++ ++static ssize_t ++thermal_cooling_device_cur_state_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct thermal_cooling_device *cdev = to_cooling_device(dev); ++ int state; ++ int result; ++ ++ if (!sscanf(buf, "%d\n", &state)) ++ return -EINVAL; ++ ++ if (state < 0) ++ return -EINVAL; ++ ++ result = cdev->ops->set_cur_state(cdev, state); ++ if (result) ++ return result; ++ return count; ++} ++ ++static struct device_attribute dev_attr_cdev_type = ++ __ATTR(type, 0444, thermal_cooling_device_type_show, NULL); ++static DEVICE_ATTR(max_state, 0444, ++ thermal_cooling_device_max_state_show, NULL); ++static DEVICE_ATTR(cur_state, 0644, ++ thermal_cooling_device_cur_state_show, ++ thermal_cooling_device_cur_state_store); ++ ++static ssize_t ++thermal_cooling_device_trip_point_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct thermal_cooling_device_instance *instance; ++ ++ instance = ++ container_of(attr, struct thermal_cooling_device_instance, attr); ++ ++ if (instance->trip == THERMAL_TRIPS_NONE) ++ return sprintf(buf, "-1\n"); ++ else ++ return sprintf(buf, "%d\n", instance->trip); ++} ++ ++/* Device management */ ++ ++/** ++ * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone ++ * this function is usually called in the thermal zone device .bind callback. ++ * @tz: thermal zone device ++ * @trip: indicates which trip point the cooling devices is ++ * associated with in this thermal zone. ++ * @cdev: thermal cooling device ++ */ ++int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, ++ int trip, ++ struct thermal_cooling_device *cdev) ++{ ++ struct thermal_cooling_device_instance *dev; ++ struct thermal_cooling_device_instance *pos; ++ int result; ++ ++ if (trip >= tz->trips || ++ (trip < 0 && trip != THERMAL_TRIPS_NONE)) ++ return -EINVAL; ++ ++ if (!tz || !cdev) ++ return -EINVAL; ++ ++ dev = ++ kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ dev->tz = tz; ++ dev->cdev = cdev; ++ dev->trip = trip; ++ result = get_idr(&tz->idr, &tz->lock, &dev->id); ++ if (result) ++ goto free_mem; ++ ++ sprintf(dev->name, "cdev%d", dev->id); ++ result = ++ sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name); ++ if (result) ++ goto release_idr; ++ ++ sprintf(dev->attr_name, "cdev%d_trip_point", dev->id); ++ dev->attr.attr.name = dev->attr_name; ++ dev->attr.attr.mode = 0444; ++ dev->attr.show = thermal_cooling_device_trip_point_show; ++ result = device_create_file(&tz->device, &dev->attr); ++ if (result) ++ goto remove_symbol_link; ++ ++ mutex_lock(&tz->lock); ++ list_for_each_entry(pos, &tz->cooling_devices, node) ++ if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) { ++ result = -EEXIST; ++ break; ++ } ++ if (!result) ++ list_add_tail(&dev->node, &tz->cooling_devices); ++ mutex_unlock(&tz->lock); ++ ++ if (!result) ++ return 0; ++ ++ device_remove_file(&tz->device, &dev->attr); ++ remove_symbol_link: ++ sysfs_remove_link(&tz->device.kobj, dev->name); ++ release_idr: ++ release_idr(&tz->idr, &tz->lock, dev->id); ++ free_mem: ++ kfree(dev); ++ return result; ++} ++EXPORT_SYMBOL(thermal_zone_bind_cooling_device); ++ ++/** ++ * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone ++ * this function is usually called in the thermal zone device .unbind callback. ++ * @tz: thermal zone device ++ * @trip: indicates which trip point the cooling devices is ++ * associated with in this thermal zone. ++ * @cdev: thermal cooling device ++ */ ++int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, ++ int trip, ++ struct thermal_cooling_device *cdev) ++{ ++ struct thermal_cooling_device_instance *pos, *next; ++ ++ mutex_lock(&tz->lock); ++ list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) { ++ if (pos->tz == tz && pos->trip == trip ++ && pos->cdev == cdev) { ++ list_del(&pos->node); ++ mutex_unlock(&tz->lock); ++ goto unbind; ++ } ++ } ++ mutex_unlock(&tz->lock); ++ ++ return -ENODEV; ++ ++ unbind: ++ device_remove_file(&tz->device, &pos->attr); ++ sysfs_remove_link(&tz->device.kobj, pos->name); ++ release_idr(&tz->idr, &tz->lock, pos->id); ++ kfree(pos); ++ return 0; ++} ++EXPORT_SYMBOL(thermal_zone_unbind_cooling_device); ++ ++static void thermal_release(struct device *dev) ++{ ++ struct thermal_zone_device *tz; ++ struct thermal_cooling_device *cdev; ++ ++ if (!strncmp(dev->bus_id, "thermal_zone", sizeof "thermal_zone" - 1)) { ++ tz = to_thermal_zone(dev); ++ kfree(tz); ++ } else { ++ cdev = to_cooling_device(dev); ++ kfree(cdev); ++ } ++} ++ ++static struct class thermal_class = { ++ .name = "thermal", ++ .dev_release = thermal_release, ++}; ++ ++/** ++ * thermal_cooling_device_register - register a new thermal cooling device ++ * @type: the thermal cooling device type. ++ * @devdata: device private data. ++ * @ops: standard thermal cooling devices callbacks. ++ */ ++struct thermal_cooling_device *thermal_cooling_device_register(char *type, ++ void *devdata, struct thermal_cooling_device_ops *ops) ++{ ++ struct thermal_cooling_device *cdev; ++ struct thermal_zone_device *pos; ++ int result; ++ ++ if (strlen(type) >= THERMAL_NAME_LENGTH) ++ return NULL; ++ ++ if (!ops || !ops->get_max_state || !ops->get_cur_state || ++ !ops->set_cur_state) ++ return NULL; ++ ++ cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL); ++ if (!cdev) ++ return NULL; ++ ++ result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id); ++ if (result) { ++ kfree(cdev); ++ return NULL; ++ } ++ ++ strcpy(cdev->type, type); ++ cdev->ops = ops; ++ cdev->device.class = &thermal_class; ++ cdev->devdata = devdata; ++ sprintf(cdev->device.bus_id, "cooling_device%d", cdev->id); ++ result = device_register(&cdev->device); ++ if (result) { ++ release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); ++ kfree(cdev); ++ return NULL; ++ } ++ ++ /* sys I/F */ ++ if (type) { ++ result = device_create_file(&cdev->device, ++ &dev_attr_cdev_type); ++ if (result) ++ goto unregister; ++ } ++ ++ result = device_create_file(&cdev->device, &dev_attr_max_state); ++ if (result) ++ goto unregister; ++ ++ result = device_create_file(&cdev->device, &dev_attr_cur_state); ++ if (result) ++ goto unregister; ++ ++ mutex_lock(&thermal_list_lock); ++ list_add(&cdev->node, &thermal_cdev_list); ++ list_for_each_entry(pos, &thermal_tz_list, node) { ++ if (!pos->ops->bind) ++ continue; ++ result = pos->ops->bind(pos, cdev); ++ if (result) ++ break; ++ ++ } ++ mutex_unlock(&thermal_list_lock); ++ ++ if (!result) ++ return cdev; ++ ++ unregister: ++ release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); ++ device_unregister(&cdev->device); ++ return NULL; ++} ++EXPORT_SYMBOL(thermal_cooling_device_register); ++ ++/** ++ * thermal_cooling_device_unregister - removes the registered thermal cooling device ++ * ++ * @cdev: the thermal cooling device to remove. ++ * ++ * thermal_cooling_device_unregister() must be called when the device is no ++ * longer needed. ++ */ ++void thermal_cooling_device_unregister(struct ++ thermal_cooling_device ++ *cdev) ++{ ++ struct thermal_zone_device *tz; ++ struct thermal_cooling_device *pos = NULL; ++ ++ if (!cdev) ++ return; ++ ++ mutex_lock(&thermal_list_lock); ++ list_for_each_entry(pos, &thermal_cdev_list, node) ++ if (pos == cdev) ++ break; ++ if (pos != cdev) { ++ /* thermal cooling device not found */ ++ mutex_unlock(&thermal_list_lock); ++ return; ++ } ++ list_del(&cdev->node); ++ list_for_each_entry(tz, &thermal_tz_list, node) { ++ if (!tz->ops->unbind) ++ continue; ++ tz->ops->unbind(tz, cdev); ++ } ++ mutex_unlock(&thermal_list_lock); ++ if (cdev->type[0]) ++ device_remove_file(&cdev->device, ++ &dev_attr_cdev_type); ++ device_remove_file(&cdev->device, &dev_attr_max_state); ++ device_remove_file(&cdev->device, &dev_attr_cur_state); ++ ++ release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); ++ device_unregister(&cdev->device); ++ return; ++} ++EXPORT_SYMBOL(thermal_cooling_device_unregister); ++ ++/** ++ * thermal_zone_device_register - register a new thermal zone device ++ * @type: the thermal zone device type ++ * @trips: the number of trip points the thermal zone support ++ * @devdata: private device data ++ * @ops: standard thermal zone device callbacks ++ * ++ * thermal_zone_device_unregister() must be called when the device is no ++ * longer needed. ++ */ ++struct thermal_zone_device *thermal_zone_device_register(char *type, ++ int trips, void *devdata, ++ struct thermal_zone_device_ops *ops) ++{ ++ struct thermal_zone_device *tz; ++ struct thermal_cooling_device *pos; ++ int result; ++ int count; ++ ++ if (strlen(type) >= THERMAL_NAME_LENGTH) ++ return NULL; ++ ++ if (trips > THERMAL_MAX_TRIPS || trips < 0) ++ return NULL; ++ ++ if (!ops || !ops->get_temp) ++ return NULL; ++ ++ tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL); ++ if (!tz) ++ return NULL; ++ ++ INIT_LIST_HEAD(&tz->cooling_devices); ++ idr_init(&tz->idr); ++ mutex_init(&tz->lock); ++ result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id); ++ if (result) { ++ kfree(tz); ++ return NULL; ++ } ++ ++ strcpy(tz->type, type); ++ tz->ops = ops; ++ tz->device.class = &thermal_class; ++ tz->devdata = devdata; ++ tz->trips = trips; ++ sprintf(tz->device.bus_id, "thermal_zone%d", tz->id); ++ result = device_register(&tz->device); ++ if (result) { ++ release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); ++ kfree(tz); ++ return NULL; ++ } ++ ++ /* sys I/F */ ++ if (type) { ++ result = device_create_file(&tz->device, &dev_attr_type); ++ if (result) ++ goto unregister; ++ } ++ ++ result = device_create_file(&tz->device, &dev_attr_temp); ++ if (result) ++ goto unregister; ++ ++ if (ops->get_mode) { ++ result = device_create_file(&tz->device, &dev_attr_mode); ++ if (result) ++ goto unregister; ++ } ++ ++ for (count = 0; count < trips; count++) { ++ TRIP_POINT_ATTR_ADD(&tz->device, count, result); ++ if (result) ++ goto unregister; ++ } ++ ++ mutex_lock(&thermal_list_lock); ++ list_add_tail(&tz->node, &thermal_tz_list); ++ if (ops->bind) ++ list_for_each_entry(pos, &thermal_cdev_list, node) { ++ result = ops->bind(tz, pos); ++ if (result) ++ break; ++ } ++ mutex_unlock(&thermal_list_lock); ++ ++ if (!result) ++ return tz; ++ ++ unregister: ++ release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); ++ device_unregister(&tz->device); ++ return NULL; ++} ++EXPORT_SYMBOL(thermal_zone_device_register); ++ ++/** ++ * thermal_device_unregister - removes the registered thermal zone device ++ * ++ * @tz: the thermal zone device to remove ++ */ ++void thermal_zone_device_unregister(struct thermal_zone_device *tz) ++{ ++ struct thermal_cooling_device *cdev; ++ struct thermal_zone_device *pos = NULL; ++ int count; ++ ++ if (!tz) ++ return; ++ ++ mutex_lock(&thermal_list_lock); ++ list_for_each_entry(pos, &thermal_tz_list, node) ++ if (pos == tz) ++ break; ++ if (pos != tz) { ++ /* thermal zone device not found */ ++ mutex_unlock(&thermal_list_lock); ++ return; ++ } ++ list_del(&tz->node); ++ if (tz->ops->unbind) ++ list_for_each_entry(cdev, &thermal_cdev_list, node) ++ tz->ops->unbind(tz, cdev); ++ mutex_unlock(&thermal_list_lock); ++ ++ if (tz->type[0]) ++ device_remove_file(&tz->device, &dev_attr_type); ++ device_remove_file(&tz->device, &dev_attr_temp); ++ if (tz->ops->get_mode) ++ device_remove_file(&tz->device, &dev_attr_mode); ++ ++ for (count = 0; count < tz->trips; count++) ++ TRIP_POINT_ATTR_REMOVE(&tz->device, count); ++ ++ release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); ++ idr_destroy(&tz->idr); ++ mutex_destroy(&tz->lock); ++ device_unregister(&tz->device); ++ return; ++} ++EXPORT_SYMBOL(thermal_zone_device_unregister); ++ ++static int __init thermal_init(void) ++{ ++ int result = 0; ++ ++ result = class_register(&thermal_class); ++ if (result) { ++ idr_destroy(&thermal_tz_idr); ++ idr_destroy(&thermal_cdev_idr); ++ mutex_destroy(&thermal_idr_lock); ++ mutex_destroy(&thermal_list_lock); ++ } ++ return result; ++} ++ ++static void __exit thermal_exit(void) ++{ ++ class_unregister(&thermal_class); ++ idr_destroy(&thermal_tz_idr); ++ idr_destroy(&thermal_cdev_idr); ++ mutex_destroy(&thermal_idr_lock); ++ mutex_destroy(&thermal_list_lock); ++} ++ ++subsys_initcall(thermal_init); ++module_exit(thermal_exit); +diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h +index 7b74b60..2b7eece 100644 +--- a/include/acpi/acpi_bus.h ++++ b/include/acpi/acpi_bus.h +@@ -321,6 +321,8 @@ struct acpi_bus_event { + + extern struct kset acpi_subsys; + extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); ++void acpi_bus_private_data_handler(acpi_handle, u32, void *); ++int acpi_bus_get_private_data(acpi_handle, void **); + /* + * External Functions + */ +diff --git a/include/acpi/processor.h b/include/acpi/processor.h +index 76411b1..0787635 100644 +--- a/include/acpi/processor.h ++++ b/include/acpi/processor.h +@@ -4,7 +4,7 @@ + #include + #include + #include +- ++#include + #include + + #define ACPI_PROCESSOR_BUSY_METRIC 10 +@@ -218,7 +218,7 @@ struct acpi_processor { + struct acpi_processor_performance *performance; + struct acpi_processor_throttling throttling; + struct acpi_processor_limit limit; +- ++ struct thermal_cooling_device *cdev; + /* the _PDC objects for this processor, if any */ + struct acpi_object_list *pdc; + }; +@@ -330,7 +330,7 @@ extern struct cpuidle_driver acpi_idle_driver; + /* in processor_thermal.c */ + int acpi_processor_get_limit_info(struct acpi_processor *pr); + extern struct file_operations acpi_processor_limit_fops; +- ++extern struct thermal_cooling_device_ops processor_cooling_ops; + #ifdef CONFIG_CPU_FREQ + void acpi_thermal_cpufreq_init(void); + void acpi_thermal_cpufreq_exit(void); +diff --git a/include/linux/thermal.h b/include/linux/thermal.h +new file mode 100644 +index 0000000..bba7712 +--- /dev/null ++++ b/include/linux/thermal.h +@@ -0,0 +1,94 @@ ++/* ++ * thermal.h ($Revision: 0 $) ++ * ++ * Copyright (C) 2008 Intel Corp ++ * Copyright (C) 2008 Zhang Rui ++ * Copyright (C) 2008 Sujith Thomas ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * 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; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ */ ++ ++#ifndef __THERMAL_H__ ++#define __THERMAL_H__ ++ ++#include ++#include ++ ++struct thermal_zone_device; ++struct thermal_cooling_device; ++ ++struct thermal_zone_device_ops { ++ int (*bind) (struct thermal_zone_device *, ++ struct thermal_cooling_device *); ++ int (*unbind) (struct thermal_zone_device *, ++ struct thermal_cooling_device *); ++ int (*get_temp) (struct thermal_zone_device *, char *); ++ int (*get_mode) (struct thermal_zone_device *, char *); ++ int (*set_mode) (struct thermal_zone_device *, const char *); ++ int (*get_trip_type) (struct thermal_zone_device *, int, char *); ++ int (*get_trip_temp) (struct thermal_zone_device *, int, char *); ++}; ++ ++struct thermal_cooling_device_ops { ++ int (*get_max_state) (struct thermal_cooling_device *, char *); ++ int (*get_cur_state) (struct thermal_cooling_device *, char *); ++ int (*set_cur_state) (struct thermal_cooling_device *, unsigned int); ++}; ++ ++#define THERMAL_TRIPS_NONE -1 ++#define THERMAL_MAX_TRIPS 10 ++#define THERMAL_NAME_LENGTH 20 ++struct thermal_cooling_device { ++ int id; ++ char type[THERMAL_NAME_LENGTH]; ++ struct device device; ++ void *devdata; ++ struct thermal_cooling_device_ops *ops; ++ struct list_head node; ++}; ++ ++#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \ ++ ((long)t-2732+5)/10 : ((long)t-2732-5)/10) ++#define CELSIUS_TO_KELVIN(t) ((t)*10+2732) ++ ++struct thermal_zone_device { ++ int id; ++ char type[THERMAL_NAME_LENGTH]; ++ struct device device; ++ void *devdata; ++ int trips; ++ struct thermal_zone_device_ops *ops; ++ struct list_head cooling_devices; ++ struct idr idr; ++ struct mutex lock; /* protect cooling devices list */ ++ struct list_head node; ++}; ++ ++struct thermal_zone_device *thermal_zone_device_register(char *, int, void *, ++ struct thermal_zone_device_ops *); ++void thermal_zone_device_unregister(struct thermal_zone_device *); ++ ++int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int, ++ struct thermal_cooling_device *); ++int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int, ++ struct thermal_cooling_device *); ++ ++struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, ++ struct thermal_cooling_device_ops *); ++void thermal_cooling_device_unregister(struct thermal_cooling_device *); ++ ++#endif /* __THERMAL_H__ */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0085-UBUNTU-x86-fix-s2ram-P4-tsc-annoyance.patch +++ linux-2.6.24/patches/0085-UBUNTU-x86-fix-s2ram-P4-tsc-annoyance.patch @@ -0,0 +1,105 @@ +From 1f8c6e15212c102e064ad1f201e18db0ac951083 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 17 Dec 2008 11:41:45 -0500 +Subject: [PATCH 085/170] UBUNTU: x86: fix: s2ram + P4 + tsc = annoyance + +OriginalAuthor: Mike Galbraith +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/304247 + +On resuming from suspend we occasionally see TSC warping especially +when suspending in the Out-Of-the-Box-Experience state, and the following +is reported by the kernel: + +[ 1.002947] checking TSC synchronization [CPU#0 -> CPU#1]: +[ 1.022935] Measured 11654071440 cycles TSC warp between CPUs, turning off TSC clock. +[ 1.022941] Marking TSC unstable due to: check_tsc_sync_source failed. + +This is fixed with upstream commit 4c6b8b4d62fb4cb843c32db71e0a8301039908f3, quoting +the original posting: + +s2ram recently became useful here, except for the kernel's annoying +habit of disabling my P4's perfectly good TSC. + +[ 107.894470] CPU 1 is now offline +[ 107.894474] SMP alternatives: switching to UP code +[ 107.895832] CPU0 attaching sched-domain: +[ 107.895836] domain 0: span 1 +[ 107.895838] groups: 1 +[ 107.896097] CPU1 is down +[ 3.726156] Intel machine check architecture supported. +[ 3.726165] Intel machine check reporting enabled on CPU#0. +[ 3.726167] CPU0: Intel P4/Xeon Extended MCE MSRs (12) available +[ 3.726170] CPU0: Thermal monitoring enabled +[ 3.726175] Back to C! +[ 3.726708] Force enabled HPET at resume +[ 3.726775] Enabling non-boot CPUs ... +[ 3.727049] CPU0 attaching NULL sched-domain. +[ 3.727165] SMP alternatives: switching to SMP code +[ 3.727858] Booting processor 1/1 eip 3000 +[ 3.727862] CPU 1 irqstacks, hard=b042f000 soft=b042d000 +[ 3.738173] Initializing CPU#1 +[ 3.798912] Calibrating delay using timer specific routine.. 5986.12 BogoMIPS (lpj=2993061) +[ 3.798920] CPU: After generic identify, caps: bfebfbff 00000000 00000000 00000000 00004400 00000000 00000000 00000000 +[ 3.798931] CPU: Trace cache: 12K uops, L1 D cache: 8K +[ 3.798934] CPU: L2 cache: 512K +[ 3.798936] CPU: Physical Processor ID: 0 +[ 3.798938] CPU: After all inits, caps: bfebfbff 00000000 00000000 0000b080 00004400 00000000 00000000 00000000 +[ 3.798946] Intel machine check architecture supported. +[ 3.798952] Intel machine check reporting enabled on CPU#1. +[ 3.798955] CPU1: Intel P4/Xeon Extended MCE MSRs (12) available +[ 3.798959] CPU1: Thermal monitoring enabled +[ 3.799161] CPU1: Intel(R) Pentium(R) 4 CPU 3.00GHz stepping 09 +[ 3.799187] checking TSC synchronization [CPU#0 -> CPU#1]: +[ 3.819181] Measured 63588552840 cycles TSC warp between CPUs, turning off TSC clock. +[ 3.819184] Marking TSC unstable due to: check_tsc_sync_source failed. + +If check_tsc_warp() is called after initial boot, and the TSC has in the +meantime been set (BIOS, user, silicon, elves) to a value lower than the +last stored/stale value, we blame the TSC. Reset to pristine condition +after every test. + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + arch/x86/kernel/tsc_sync.c | 16 ++++++++-------- + 1 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c +index c9bf17d..73b1628 100644 +--- a/arch/x86/kernel/tsc_sync.c ++++ b/arch/x86/kernel/tsc_sync.c +@@ -135,24 +135,24 @@ void __cpuinit check_tsc_sync_source(int cpu) + while (atomic_read(&stop_count) != cpus-1) + cpu_relax(); + +- /* +- * Reset it - just in case we boot another CPU later: +- */ +- atomic_set(&start_count, 0); +- + if (nr_warps) { + printk("\n"); + printk(KERN_WARNING "Measured %Ld cycles TSC warp between CPUs," + " turning off TSC clock.\n", max_warp); + mark_tsc_unstable("check_tsc_sync_source failed"); +- nr_warps = 0; +- max_warp = 0; +- last_tsc = 0; + } else { + printk(" passed.\n"); + } + + /* ++ * Reset it - just in case we boot another CPU later: ++ */ ++ atomic_set(&start_count, 0); ++ nr_warps = 0; ++ max_warp = 0; ++ last_tsc = 0; ++ ++ /* + * Let the target continue with the bootup: + */ + atomic_inc(&stop_count); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0027-kgdb-serial_core-early-init-API-for-kgdb8250.patch +++ linux-2.6.24/patches/0027-kgdb-serial_core-early-init-API-for-kgdb8250.patch @@ -0,0 +1,286 @@ +From 3d4ee20d1b612a9814b95c9fb6cb2250cca6808f Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:46 -0500 +Subject: [PATCH 027/170] kgdb, serial_core: early init API for kgdb8250 + +This patch adds an early initialization API for the kgdb8250 driver to +allow an architecture or board specific implementation to debug as +early as possible (IE: right after the uarts and exceptions are +setup). + +This patch also allows for the kgdb8250 driver to accept a memory base +instead of a map base for boards that require it. + +Signed-off-by: Jason Wessel +--- + Documentation/DocBook/kgdb.tmpl | 57 +++++++++++++++++++++++++++++++++++++++ + drivers/serial/8250_kgdb.c | 50 +++++++++++++++++++++++++++++++--- + drivers/serial/serial_core.c | 10 ++++++- + include/linux/kgdb8250.h | 42 ++++++++++++++++++++++++++++ + 4 files changed, 154 insertions(+), 5 deletions(-) + create mode 100644 include/linux/kgdb8250.h + +diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl +index 6e1e2a1..2438712 100644 +--- a/Documentation/DocBook/kgdb.tmpl ++++ b/Documentation/DocBook/kgdb.tmpl +@@ -521,6 +521,63 @@ + going to mean pressing the reset button. + +
++ ++ kgdb8250 API ++ ++ The kgdb8250 driver essentially hijacks a uart for use with kgdb. ++ The aim of the implementation is to provide debugging as early as ++ possible after the exception processing and uarts are initialized. ++ ++ ++ On some architectures or specific boards the kgdb8250 driver's ++ registration needs to be delayed beyond the kernel argument ++ processing time. With the kgdb8250 driver it is possible to ++ override the default implementation so as to provide a hook to delay ++ the I/O driver registration for kgdb. ++ ++ ++ The following is and example of code that would go into the ++ architecture or board specific implementation to delay the kgdb8250 ++ final initialization to the correct time. ++ ++#include <linux/kgdb8250.h> ++ ++/* ... other arch or board specific functions ... */ ++ ++#ifdef CONFIG_KGDB_8250 ++static int kgdb8250_ready; ++int kgdb8250_early_debug_ready(void) ++{ ++ return kgdb8250_ready; ++} ++#endif ++ ++/* This is an example uart init function, the important part is ++ * adding in the part inclusive of the #ifdef ++ */ ++void example_uart_init(void) ++{ ++ ++/* ... uart and exceptions are finally setup ... */ ++#ifdef CONFIG_KGDB_8250 ++ kgdb8250_ready = 1; ++ kgdb8250_arch_init(); ++#endif ++ ++/* Note, that if kgdbwait was specified on the ++ * kernel command line the board will stop at this ++ * point and wait for the debugger ++ */ ++ ++} ++ ++ ++ ++ The API function descriptions follow for kgdb8250_early_debug_ready() and ++ kgdb8250_arch_init(). ++ ++!Iinclude/linux/kgdb8250.h ++ + + + Credits +diff --git a/drivers/serial/8250_kgdb.c b/drivers/serial/8250_kgdb.c +index ea42ea7..e73af4d 100644 +--- a/drivers/serial/8250_kgdb.c ++++ b/drivers/serial/8250_kgdb.c +@@ -49,6 +49,9 @@ static struct uart_port kgdb8250_port; + /* UART port we might have stolen from the 8250 driver */ + static int hijacked_line; + ++/* Flag for if we need to call request_mem_region */ ++static int kgdb8250_needs_request_mem_region; ++ + static int late_init_passed; + static int fully_initialized; + static int buffered_char = -1; +@@ -57,6 +60,18 @@ static struct kgdb_io kgdb8250_io_ops; /* initialized later */ + + static int kgdb8250_uart_init(void); + ++#ifdef CONFIG_KGDB_8250 ++/* Weak alias in case a particular arch need to implment a specific ++ * point where the serial initialization is completed for early debug. ++ * This is only applicable if the kgdb8250 driver is a built-in. ++ */ ++int __weak kgdb8250_early_debug_ready(void) ++{ ++ return 1; ++} ++#endif ++ ++ + static inline unsigned int kgdb8250_ioread(u8 mask) + { + return ioread8(kgdb8250_addr + (mask << kgdb8250_port.regshift)); +@@ -218,6 +233,11 @@ static int kgdb8250_parse_config(char *str) + /* Save the option string in case we fail and can retry later. */ + strncpy(config, str, KGD8250_MAX_CONFIG_STR-1); + ++#ifdef CONFIG_KGDB_8250 ++ if (!kgdb8250_early_debug_ready()) ++ return 0; ++#endif ++ + /* Empty config or leading white space (like LF) means "disabled" */ + if (!strlen(config) || isspace(config[0])) + return 0; +@@ -229,6 +249,10 @@ static int kgdb8250_parse_config(char *str) + kgdb8250_port.iotype = UPIO_MEM; + kgdb8250_port.flags = UPF_IOREMAP; + str += 4; ++ } else if (!strncmp(str, "mbase", 5)) { ++ kgdb8250_port.iotype = UPIO_MEM; ++ kgdb8250_port.flags &= ~UPF_IOREMAP; ++ str += 5; + } else if (!strncmp(str, "ttyS", 4)) { + str += 4; + if (*str < '0' || *str > '9') +@@ -268,9 +292,12 @@ static int kgdb8250_parse_config(char *str) + + if (kgdb8250_port.iotype == UPIO_PORT) + kgdb8250_port.iobase = simple_strtoul(str, &str, 16); +- else ++ else if (kgdb8250_port.flags & UPF_IOREMAP) + kgdb8250_port.mapbase = +- (unsigned long)simple_strtoul(str, &str, 16); ++ (unsigned long) simple_strtoul(str, &str, 16); ++ else ++ kgdb8250_port.membase = ++ (void *) simple_strtoul(str, &str, 16); + + if (*str == '/') { + str++; +@@ -304,6 +331,9 @@ static int kgdb8250_early_init(void) + /* Internal driver setup. */ + switch (kgdb8250_port.iotype) { + case UPIO_MEM: ++ kgdb8250_needs_request_mem_region = 0; ++ if (kgdb8250_port.mapbase) ++ kgdb8250_needs_request_mem_region = 1; + if (kgdb8250_port.flags & UPF_IOREMAP) + kgdb8250_port.membase = ioremap(kgdb8250_port.mapbase, + 8 << kgdb8250_port.regshift); +@@ -354,7 +384,8 @@ static int kgdb8250_late_init(void) + + /* Request memory/io regions that we use. */ + if (kgdb8250_port.iotype == UPIO_MEM) { +- if (!request_mem_region(kgdb8250_port.mapbase, ++ if (kgdb8250_needs_request_mem_region && ++ !request_mem_region(kgdb8250_port.mapbase, + 8 << kgdb8250_port.regshift, "kgdb")) + goto rollback; + } else { +@@ -417,7 +448,8 @@ static void kgdb8250_cleanup(void) + if (kgdb8250_port.iotype == UPIO_MEM) { + if (kgdb8250_port.flags & UPF_IOREMAP) + iounmap(kgdb8250_port.membase); +- release_mem_region(kgdb8250_port.mapbase, ++ if (kgdb8250_needs_request_mem_region) ++ release_mem_region(kgdb8250_port.mapbase, + 8 << kgdb8250_port.regshift); + } else { + ioport_unmap(ioaddr); +@@ -485,5 +517,15 @@ module_param_call(kgdb8250, kgdb8250_set_config, param_get_string, &kps, 0644); + MODULE_PARM_DESC(kgdb8250, "ttyS,"); + + #ifdef CONFIG_KGDB_8250 ++/* This function can be called for a board that has early debugging ++ * but later than early param processing time. It is expected that ++ * this function is called as soon as it is permissible for the board ++ * to start taking exceptions and the serial IO mappings are in ++ * place. ++ */ ++void kgdb8250_arch_init(void) ++{ ++ kgdb8250_parse_config(config); ++} + early_param("kgdb8250", kgdb8250_parse_config); + #endif +diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c +index 4ea9b03..d9788b2 100644 +--- a/drivers/serial/serial_core.c ++++ b/drivers/serial/serial_core.c +@@ -2109,7 +2109,13 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) + case UPIO_AU: + case UPIO_TSI: + case UPIO_DWAPB: +- snprintf(address, sizeof(address), ++ if (port->mapbase == 0) ++ snprintf(address, sizeof(address), ++ "MMIO 0x%llx membase %p", ++ (unsigned long long)port->mapbase, ++ port->membase); ++ else ++ snprintf(address, sizeof(address), + "MMIO 0x%llx", (unsigned long long)port->mapbase); + break; + default: +@@ -2521,6 +2527,8 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2) + case UPIO_AU: + case UPIO_TSI: + case UPIO_DWAPB: ++ if (port1->mapbase == 0 && port2->mapbase == 0) ++ return (port1->membase == port2->membase); + return (port1->mapbase == port2->mapbase); + } + return 0; +diff --git a/include/linux/kgdb8250.h b/include/linux/kgdb8250.h +new file mode 100644 +index 0000000..74f46f8 +--- /dev/null ++++ b/include/linux/kgdb8250.h +@@ -0,0 +1,42 @@ ++/* ++ * This header specifies the early debug hooks for the kgdb8250 ++ * driver, which can be implemented per arch and per board. ++ * ++ * Author: Jason Wessel ++ * ++ * 2008 (c) Wind River System, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++#ifndef _KGDB8250_H_ ++#define _KGDB8250_H_ ++ ++#include ++ ++/** ++ * kgdb8250_early_debug_ready - indicates when it safe to issue uart I/O ++ * ++ * This function should return 1 when it is safe to read and write ++ * to the uart. By default this is a weak alias which always returns ++ * true, unless overriden by an architecture or board specific ++ * implementation. This is overriden in case that uart I/O is only ++ * available some time after early kernel parameter processing. ++ */ ++extern int kgdb8250_early_debug_ready(void); ++ ++/** ++ * kgdb8250_arch_init - active early debugging, if configured ++ * ++ * This function must be implemented and called in the architecture or ++ * board specific code if kgdb8250_early_debug_ready() is implemented. ++ * This function should be called as soon as the board is able to ++ * process exceptions and the uart is setup for reading and writing. ++ * This function will invoke the kgdb I/O driver registration routines ++ * and immediately wait for the debugger if kgdbwait was specified on ++ * the kernel command line. ++ */ ++extern void kgdb8250_arch_init(void); ++ ++#endif /* _KGDB8250_H_ */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0048-Added-ich_laptop-entried-for-Belmont-and-Chelsea-Thi.patch +++ linux-2.6.24/patches/0048-Added-ich_laptop-entried-for-Belmont-and-Chelsea-Thi.patch @@ -0,0 +1,26 @@ +From b9ccf41afc3d334fef05cc456f1b48e9e9ae1fd0 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 29 Jul 2008 09:39:25 -0400 +Subject: [PATCH 048/170] Added ich_laptop entried for Belmont and Chelsea This turns on UDMA4 modes for the disk + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/ata/ata_piix.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c +index 4d769b8..72dca47 100644 +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -702,6 +702,8 @@ static const struct ich_laptop ich_laptop[] = { + { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */ + { 0x24CA, 0x1025, 0x003d }, /* ICH4 on Acer TM290 */ + { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ ++ { 0x811a, 0x8086, 0x8119 }, /* SCH on Chelsea */ ++ { 0x27DF, 0x1028, 0x02b0 }, /* ICH7 on Belmont */ + /* end marker */ + { 0, } + }; +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0163-UBUNTU-NBK-Ubuntu-2.6.24-24.59netbook01.patch +++ linux-2.6.24/patches/0163-UBUNTU-NBK-Ubuntu-2.6.24-24.59netbook01.patch @@ -0,0 +1,30 @@ +From b6c671c2c5e093bbd51dba2b42cb24a04fa346d8 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 21 Aug 2009 12:50:47 +0100 +Subject: [PATCH 163/170] UBUNTU: NBK-Ubuntu-2.6.24-24.59netbook01 + +Signed-off-by: Andy Whitcroft +--- + debian/changelog | 8 ++++---- + 1 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 9318ebf..471f0e6 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,8 +1,8 @@ +-linux (2.6.24-24.59netbook01) UNRELEASED; urgency=low ++linux (2.6.24-24.59netbook01) netbook-common; urgency=low + +- CHANGELOG: Do not edit directly. Autogenerated at release. +- CHANGELOG: Use the printchanges target to see the curent changes. +- CHANGELOG: Use the insertchanges target to create the final log. ++ [Andy Whitcroft] ++ ++ * rebase onto Ubuntu-2.6.24-24.59 + + [ Ubuntu: 2.6.24-24.59 ] + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0088-Updated-Ericsson-mbm-3G-module-driver.patch +++ linux-2.6.24/patches/0088-Updated-Ericsson-mbm-3G-module-driver.patch @@ -0,0 +1,197 @@ +From 2971635c093571a3b89df08b69e9bae8a07c1dc8 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 17 Dec 2008 11:44:49 -0500 +Subject: [PATCH 088/170] Updated Ericsson mbm 3G module driver + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/net/usb/mbm.c | 40 ++++++++++++++++++++-------------------- + drivers/net/usb/usbnet.c | 2 +- + drivers/usb/class/cdc-acm.c | 7 ------- + 3 files changed, 21 insertions(+), 28 deletions(-) + +diff --git a/drivers/net/usb/mbm.c b/drivers/net/usb/mbm.c +index 20ad486..55b1bc2 100644 +--- a/drivers/net/usb/mbm.c ++++ b/drivers/net/usb/mbm.c +@@ -45,7 +45,7 @@ static const u8 mbm_guid[16] = { + 0xa3, 0x17, 0xa8, 0x8b, 0x04, 0x5e, 0x4f, 0x01, + 0xa6, 0x07, 0xc0, 0xff, 0xcb, 0x7e, 0x39, 0x2a, + }; +-static void dumpspeed(struct usbnet *dev, __le32 * speeds) ++static void dumpspeed(struct usbnet *dev, __le32 *speeds) + { + struct mbm_data *data = (void *)&dev->data; + +@@ -72,7 +72,7 @@ static void mbm_status(struct usbnet *dev, struct urb *urb) + struct mbm_data *data = (void *)&dev->data; + struct usb_cdc_notification *event; + +- if (urb->actual_length < sizeof *event) ++ if (urb->actual_length < sizeof(*event)) + return; + + /* SPEED_CHANGE can get split into two 8-byte packets */ +@@ -97,10 +97,10 @@ static void mbm_status(struct usbnet *dev, struct urb *urb) + if (netif_msg_timer(dev)) + dev_dbg(&dev->udev->dev, "CDC: speed change (len %d)\n", + urb->actual_length); +- if (urb->actual_length != (sizeof *event + 8)) ++ if (urb->actual_length != (sizeof(*event) + 8)) + set_bit(EVENT_STS_SPLIT, &dev->flags); + else +- dumpspeed(dev, (__le32 *) & event[1]); ++ dumpspeed(dev, (__le32 *) &event[1]); + break; + default: + dev_err(&dev->udev->dev, "CDC: unexpected notification %02x!\n", +@@ -125,7 +125,7 @@ get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e) + int tmp, i; + unsigned char buf[13]; + +- tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf); ++ tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof(buf)); + if (tmp != 12) { + dev_dbg(&dev->udev->dev, + "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp); +@@ -144,11 +144,11 @@ static void mbm_get_drvinfo(struct net_device *net, + { + struct usbnet *dev = netdev_priv(net); + +- strncpy(info->driver, dev->driver_name, sizeof info->driver); +- strncpy(info->version, DRIVER_VERSION, sizeof info->version); ++ strncpy(info->driver, dev->driver_name, sizeof(info->driver)); ++ strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); + strncpy(info->fw_version, dev->driver_info->description, +- sizeof info->fw_version); +- usb_make_path(dev->udev, info->bus_info, sizeof info->bus_info); ++ sizeof(info->fw_version)); ++ usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info)); + } + + static struct ethtool_ops mbm_ethtool_ops = { +@@ -181,7 +181,7 @@ static int mbm_bind(struct usbnet *dev, struct usb_interface *intf) + int len = intf->cur_altsetting->extralen; + int status; + +- memset(info, 0, sizeof *info); ++ memset(info, 0, sizeof(*info)); + info->control = intf; + while (len > 3) { + if (buf[1] != USB_DT_CS_INTERFACE) +@@ -194,7 +194,7 @@ static int mbm_bind(struct usbnet *dev, struct usb_interface *intf) + + desc = (void *)buf; + +- if (desc->bLength != sizeof *desc) ++ if (desc->bLength != sizeof(*desc)) + goto bad_desc; + + if (memcmp(&desc->bGUID, mbm_guid, 16)) +@@ -207,7 +207,7 @@ static int mbm_bind(struct usbnet *dev, struct usb_interface *intf) + detail = (void *)buf; + + if (detail->bGuidDescriptorType == 0) { +- if (detail->bLength < (sizeof *detail + 1)) ++ if (detail->bLength < (sizeof(*detail) + 1)) + goto bad_desc; + } + break; +@@ -217,7 +217,7 @@ static int mbm_bind(struct usbnet *dev, struct usb_interface *intf) + + info->u = (void *)buf; + +- if (info->u->bLength != sizeof *info->u) ++ if (info->u->bLength != sizeof(*info->u)) + goto bad_desc; + + info->control = usb_ifnum_to_if(dev->udev, +@@ -245,13 +245,13 @@ static int mbm_bind(struct usbnet *dev, struct usb_interface *intf) + goto bad_desc; + + info->ether = (void *)buf; +- if (info->ether->bLength != sizeof *info->ether) ++ if (info->ether->bLength != sizeof(*info->ether)) + goto bad_desc; + dev->hard_mtu = + le16_to_cpu(info->ether->wMaxSegmentSize); + break; + } +- next_desc: ++next_desc: + len -= buf[0]; /* bLength */ + buf += buf[0]; + } +@@ -308,7 +308,7 @@ static int mbm_bind(struct usbnet *dev, struct usb_interface *intf) + + return 0; + +- bad_desc: ++bad_desc: + dev_info(&dev->udev->dev, "unsupported MDLM descriptors\n"); + return -ENODEV; + } +@@ -329,25 +329,25 @@ static const struct usb_device_id products[] = { + .driver_info = (unsigned long)&mbm_info, + }, + +- {}, // END ++ {}, /* END */ + }; + + MODULE_DEVICE_TABLE(usb, products); + + int mbm_suspend(struct usb_interface *intf, pm_message_t message) + { +- dev_dbg(&intf->dev, "mb%d_suspend\n", intf->minor); ++ dev_dbg(&intf->dev, "mbm%d_suspend\n", intf->minor); + return usbnet_suspend(intf, message); + } + + int mbm_resume(struct usb_interface *intf) + { +- dev_dbg(&intf->dev, "mb%d_resume\n", intf->minor); ++ dev_dbg(&intf->dev, "mbm%d_resume\n", intf->minor); + return usbnet_resume(intf); + } + + static struct usb_driver usbmbm_driver = { +- .name = "mb", ++ .name = "mbm", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, +diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c +index b620ed3..2b82d12 100644 +--- a/drivers/net/usb/usbnet.c ++++ b/drivers/net/usb/usbnet.c +@@ -1248,7 +1248,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) + strcpy (net->name, "eth%d"); + + if (dev->driver_info->flags & FLAG_MBN) +- strcpy (net->name, "mb%d"); ++ strcpy(net->name, "mb%d"); + + /* maybe the remote can't receive an Ethernet MTU */ + if (net->mtu > (dev->hard_mtu - net->hard_header_len)) +diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c +index 888c298..73d92df 100644 +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -269,13 +269,6 @@ static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL); + * Interrupt handlers for various ACM device responses + */ + +-#ifndef _LINUX_UNALIGNED_ACCESS_OK_H +-static inline u16 get_unaligned_le16(const void *p) +-{ +- return le16_to_cpup((__le16 *)p); +-} +-#endif +- + /* control interface reports status changes with "interrupt" transfers */ + static void acm_ctrl_irq(struct urb *urb) + { +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0034-kgdb-kgdboc-console-poll-hooks-for-cpm-uart.patch +++ linux-2.6.24/patches/0034-kgdb-kgdboc-console-poll-hooks-for-cpm-uart.patch @@ -0,0 +1,149 @@ +From 317d09f4d2b91cb8517946ea13deea42713e1a2a Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:48 -0500 +Subject: [PATCH 034/170] kgdb: kgdboc console poll hooks for cpm uart + +Add in console polling hooks for the cpm uart for use with kgdboc. + +Signed-off-by: Jason Wessel +--- + drivers/serial/cpm_uart/cpm_uart_core.c | 95 ++++++++++++++++++++++++++++++- + 1 files changed, 94 insertions(+), 1 deletions(-) + +diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c +index b5e4478..a7c51cc 100644 +--- a/drivers/serial/cpm_uart/cpm_uart_core.c ++++ b/drivers/serial/cpm_uart/cpm_uart_core.c +@@ -257,6 +257,10 @@ static void cpm_uart_int_tx(struct uart_port *port) + cpm_uart_tx_pump(port); + } + ++#ifdef CONFIG_CONSOLE_POLL ++static int serial_polled; ++#endif ++ + /* + * Receive characters + */ +@@ -278,6 +282,12 @@ static void cpm_uart_int_rx(struct uart_port *port) + */ + bdp = pinfo->rx_cur; + for (;;) { ++#ifdef CONFIG_CONSOLE_POLL ++ if (unlikely(serial_polled)) { ++ serial_polled = 0; ++ return; ++ } ++#endif + /* get status */ + status = in_be16(&bdp->cbd_sc); + /* If this one is empty, return happy */ +@@ -309,7 +319,12 @@ static void cpm_uart_int_rx(struct uart_port *port) + goto handle_error; + if (uart_handle_sysrq_char(port, ch)) + continue; +- ++#ifdef CONFIG_CONSOLE_POLL ++ if (unlikely(serial_polled)) { ++ serial_polled = 0; ++ return; ++ } ++#endif + error_return: + tty_insert_flip_char(tty, ch, flg); + +@@ -916,6 +931,80 @@ static void cpm_uart_config_port(struct uart_port *port, int flags) + cpm_uart_request_port(port); + } + } ++ ++#ifdef CONFIG_CONSOLE_POLL ++/* Serial polling routines for writing and reading from the uart while ++ * in an interrupt or debug context. ++ */ ++ ++#define GDB_BUF_SIZE 512 /* power of 2, please */ ++ ++static char poll_buf[GDB_BUF_SIZE]; ++static char *pollp; ++static int poll_chars; ++ ++static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo) ++{ ++ u_char c, *cp; ++ volatile cbd_t *bdp; ++ int i; ++ ++ /* Get the address of the host memory buffer. ++ */ ++ bdp = pinfo->rx_cur; ++ while (bdp->cbd_sc & BD_SC_EMPTY) ++ ; ++ ++ /* If the buffer address is in the CPM DPRAM, don't ++ * convert it. ++ */ ++ cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); ++ ++ if (obuf) { ++ i = c = bdp->cbd_datlen; ++ while (i-- > 0) ++ *obuf++ = *cp++; ++ } else ++ c = *cp; ++ bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID); ++ bdp->cbd_sc |= BD_SC_EMPTY; ++ ++ if (bdp->cbd_sc & BD_SC_WRAP) ++ bdp = pinfo->rx_bd_base; ++ else ++ bdp++; ++ pinfo->rx_cur = (cbd_t *)bdp; ++ ++ return (int)c; ++} ++ ++static int cpm_get_poll_char(struct uart_port *port) ++{ ++ struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; ++ ++ if (!serial_polled) { ++ serial_polled = 1; ++ poll_chars = 0; ++ } ++ if (poll_chars <= 0) { ++ poll_chars = poll_wait_key(poll_buf, pinfo); ++ pollp = poll_buf; ++ } ++ poll_chars--; ++ return (*pollp++); ++} ++ ++static void cpm_put_poll_char(struct uart_port *port, ++ unsigned char c) ++{ ++ struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; ++ static char ch[2]; ++ ++ ch[0] = (char)c; ++ cpm_uart_early_write(pinfo->port.line, ch, 1); ++} ++#endif /* CONFIG_CONSOLE_POLL */ ++ + static struct uart_ops cpm_uart_pops = { + .tx_empty = cpm_uart_tx_empty, + .set_mctrl = cpm_uart_set_mctrl, +@@ -933,6 +1022,10 @@ static struct uart_ops cpm_uart_pops = { + .request_port = cpm_uart_request_port, + .config_port = cpm_uart_config_port, + .verify_port = cpm_uart_verify_port, ++#ifdef CONFIG_CONSOLE_POLL ++ .poll_get_char = cpm_get_poll_char, ++ .poll_put_char = cpm_put_poll_char, ++#endif + }; + + #ifdef CONFIG_PPC_CPM_NEW_BINDING +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0028-kgdb-x86-early-trap-init-for-early-debug.patch +++ linux-2.6.24/patches/0028-kgdb-x86-early-trap-init-for-early-debug.patch @@ -0,0 +1,122 @@ +From 3f49d48f671680046432fb8bdc27a7874225cf36 Mon Sep 17 00:00:00 2001 +From: Jan Kiszka +Date: Fri, 28 Mar 2008 13:18:46 -0500 +Subject: [PATCH 028/170] kgdb, x86: early trap init for early debug + +Allow the x86 arch to have early exception processing for the purpose +of debugging via the kgdb8250 driver. + +Signed-off-by: Jason Wessel +Signed-off-by: Jan Kiszka +--- + arch/x86/kernel/setup_32.c | 1 + + arch/x86/kernel/setup_64.c | 2 ++ + arch/x86/kernel/traps_32.c | 11 ++++++++--- + arch/x86/kernel/traps_64.c | 10 +++++++++- + include/asm-x86/processor.h | 2 ++ + 5 files changed, 22 insertions(+), 4 deletions(-) + +diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c +index cc657b8..3455481 100644 +--- a/arch/x86/kernel/setup_32.c ++++ b/arch/x86/kernel/setup_32.c +@@ -546,6 +546,7 @@ void __init setup_arch(char **cmdline_p) + memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); + pre_setup_arch_hook(); + early_cpu_init(); ++ early_trap_init(); + + /* + * FIXME: This isn't an official loader_type right +diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c +index e6cd791..9143df4 100644 +--- a/arch/x86/kernel/setup_64.c ++++ b/arch/x86/kernel/setup_64.c +@@ -259,6 +259,8 @@ void __init setup_arch(char **cmdline_p) + { + printk(KERN_INFO "Command line: %s\n", boot_command_line); + ++ early_trap_init(); ++ + ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev); + screen_info = boot_params.screen_info; + edid_info = boot_params.edid_info; +diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c +index 6d0a0de..7b6f72c 100644 +--- a/arch/x86/kernel/traps_32.c ++++ b/arch/x86/kernel/traps_32.c +@@ -1131,6 +1131,14 @@ static void __init set_task_gate(unsigned int n, unsigned int gdt_entry) + _set_gate(n, DESCTYPE_TASK, (void *)0, (gdt_entry<<3)); + } + ++/* Set of traps needed for early debugging. */ ++void __init early_trap_init(void) ++{ ++ set_intr_gate(1, &debug); ++ set_system_intr_gate(3, &int3); /* int3 can be called from all */ ++ set_intr_gate(14, &page_fault); ++ load_idt(&idt_descr); ++} + + void __init trap_init(void) + { +@@ -1149,9 +1157,7 @@ void __init trap_init(void) + #endif + + set_trap_gate(0,÷_error); +- set_intr_gate(1,&debug); + set_intr_gate(2,&nmi); +- set_system_intr_gate(3, &int3); /* int3/4 can be called from all */ + set_system_gate(4,&overflow); + set_trap_gate(5,&bounds); + set_trap_gate(6,&invalid_op); +@@ -1162,7 +1168,6 @@ void __init trap_init(void) + set_trap_gate(11,&segment_not_present); + set_trap_gate(12,&stack_segment); + set_trap_gate(13,&general_protection); +- set_intr_gate(14,&page_fault); + set_trap_gate(15,&spurious_interrupt_bug); + set_trap_gate(16,&coprocessor_error); + set_trap_gate(17,&alignment_check); +diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c +index e2a2553..6f3c5f9 100644 +--- a/arch/x86/kernel/traps_64.c ++++ b/arch/x86/kernel/traps_64.c +@@ -1097,6 +1097,15 @@ asmlinkage void math_state_restore(void) + me->fpu_counter++; + } + ++/* Set of traps needed for early debugging. */ ++void __init early_trap_init(void) ++{ ++ set_intr_gate(1, &debug); ++ set_intr_gate(3, &int3); ++ set_intr_gate(14, &page_fault); ++ load_idt((const struct desc_ptr *)&idt_descr); ++} ++ + void __init trap_init(void) + { + set_intr_gate(0,÷_error); +@@ -1113,7 +1122,6 @@ void __init trap_init(void) + set_intr_gate(11,&segment_not_present); + set_intr_gate_ist(12,&stack_segment,STACKFAULT_STACK); + set_intr_gate(13,&general_protection); +- set_intr_gate(14,&page_fault); + set_intr_gate(15,&spurious_interrupt_bug); + set_intr_gate(16,&coprocessor_error); + set_intr_gate(17,&alignment_check); +diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h +index 46e1c04..93a4e19 100644 +--- a/include/asm-x86/processor.h ++++ b/include/asm-x86/processor.h +@@ -2,4 +2,6 @@ + # include "processor_32.h" + #else + # include "processor_64.h" ++extern void early_trap_init(void); ++ + #endif +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0099-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook7.patch +++ linux-2.6.24/patches/0099-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook7.patch @@ -0,0 +1,32 @@ +From 4da16d48f576878d94be30300428a1341253f3c8 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 17 Mar 2009 16:38:32 -0400 +Subject: [PATCH 099/170] UBUNTU: NBK-Ubuntu-2.6.24-22.45netbook7 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 10 ++++++++++ + 1 files changed, 10 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 9afe43d..2498be0 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,13 @@ ++linux (2.6.24-22.45netbook7) netbook-common; urgency=low ++ ++ [Michael Frey] ++ ++ * debian/binary-custom.d/lpia/config.lpia ++ * Added CONFIG_USB_MOUSE=m ++ * Added CONFIG_USB_KBD=m ++ ++ -- Michael Frey Tue, 17 Mar 2009 16:35:26 -0400 ++ + linux (2.6.24-22.45netbook6) netbook-common; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0110-UBUNTU-dib0700-add-support-for-Hauppauge-ATSC-MiniCa.patch +++ linux-2.6.24/patches/0110-UBUNTU-dib0700-add-support-for-Hauppauge-ATSC-MiniCa.patch @@ -0,0 +1,179 @@ +From 0d7340af6ba07562319c8d8d118313621083d3c7 Mon Sep 17 00:00:00 2001 +From: Michael Krufky +Date: Tue, 24 Mar 2009 23:40:35 -0400 +Subject: [PATCH 110/170] UBUNTU: dib0700: add support for Hauppauge ATSC MiniCard + +OriginalAuthor: Michael Krufky +OriginalLocation: http://linuxtv.org/hg/v4l-dvb/rev/15c9c3683be8 + +dib0700: add support for Hauppauge ATSC MiniCard + +Signed-off-by: Michael Krufky +--- + drivers/media/dvb/dvb-usb/Kconfig | 2 + + drivers/media/dvb/dvb-usb/dib0700_devices.c | 98 +++++++++++++++++++++++++++ + drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 + + 3 files changed, 102 insertions(+), 0 deletions(-) + +diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig +index d73934d..092f4b0 100644 +--- a/drivers/media/dvb/dvb-usb/Kconfig ++++ b/drivers/media/dvb/dvb-usb/Kconfig +@@ -73,9 +73,11 @@ config DVB_USB_DIB0700 + select DVB_DIB7000P + select DVB_DIB7000M + select DVB_DIB3000MC ++ select DVB_LGDT3305 if !DVB_FE_CUSTOMISE + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 ++ select DVB_TUNER_MXL5007T if !DVB_FE_CUSTOMISE + help + Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The + USB bridge is also present in devices having the DiB7700 DVB-T-USB +diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c +index 133bc6e..afc1131 100644 +--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c ++++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c +@@ -14,6 +14,8 @@ + #include "mt2060.h" + #include "mt2266.h" + #include "dib0070.h" ++#include "lgdt3305.h" ++#include "mxl5007t.h" + + static int force_lna_activation; + module_param(force_lna_activation, int, 0644); +@@ -818,6 +820,76 @@ static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) + return adap->fe == NULL ? -ENODEV : 0; + } + ++static struct lgdt3305_config hcw_lgdt3305_config = { ++ .i2c_addr = 0x0e, ++ .mpeg_mode = LGDT3305_MPEG_PARALLEL, ++ .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, ++ .tpvalid_polarity = LGDT3305_TP_VALID_LOW, ++ .deny_i2c_rptr = 0, ++ .spectral_inversion = 1, ++ .qam_if_khz = 6000, ++ .vsb_if_khz = 6000, ++ .usref_8vsb = 0x0500, ++}; ++ ++static struct mxl5007t_config hcw_mxl5007t_config = { ++ .xtal_freq_hz = MxL_XTAL_25_MHZ, ++ .if_freq_hz = MxL_IF_6_MHZ, ++ .invert_if = 1, ++#if 0 ++ .loop_thru_enable = 1, ++ .clk_out_enable = 1, ++#endif ++}; ++ ++/* TIGER-ATSC map: ++ GPIO0 - LNA_CTR (H: LNA power enabled, L: LNA power disabled) ++ GPIO1 - ANT_SEL (H: VPA, L: MCX) ++ GPIO4 - SCL2 ++ GPIO6 - EN_TUNER ++ GPIO7 - SDA2 ++ GPIO10 - DEM_RST ++ ++ MXL is behind LG's i2c repeater. LG is on SCL2/SDA2 gpios on the DIB ++ */ ++static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) ++{ ++ struct dib0700_state *st = adap->dev->priv; ++ ++ /* Make use of the new i2c functions from FW 1.20 */ ++ st->fw_use_new_i2c_api = 1; ++ ++ st->disable_streaming_master_mode = 1; ++ ++ /* fe power enable */ ++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); ++ msleep(30); ++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); ++ msleep(30); ++ ++ /* demod reset */ ++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); ++ msleep(30); ++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); ++ msleep(30); ++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); ++ msleep(30); ++ ++ adap->fe = dvb_attach(lgdt3305_attach, ++ &hcw_lgdt3305_config, ++ &adap->dev->i2c_adap); ++ ++ return adap->fe == NULL ? -ENODEV : 0; ++} ++ ++static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap) ++{ ++ return dvb_attach(mxl5007t_attach, adap->fe, ++ &adap->dev->i2c_adap, 0x60, ++ &hcw_mxl5007t_config) == NULL ? -ENODEV : 0; ++} ++ ++ + /* DVB-USB and USB stuff follows */ + struct usb_device_id dib0700_usb_id_table[] = { + /* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, +@@ -843,6 +915,8 @@ struct usb_device_id dib0700_usb_id_table[] = { + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, ++ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC) }, ++ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) }, + /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, + { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, + { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, +@@ -1113,6 +1187,30 @@ struct dvb_usb_device_properties dib0700_devices[] = { + { NULL }, + }, + } ++ }, { DIB0700_FW_1_20_DEVICE_PROPERTIES, ++ .num_adapters = 1, ++ .adapter = { ++ { ++ .frontend_attach = lgdt3305_frontend_attach, ++ .tuner_attach = mxl5007t_tuner_attach, ++ ++ DIB0700_DEFAULT_STREAMING_CONFIG(0x02), ++ ++ .size_of_priv = sizeof(struct dib0700_adapter_state), ++ }, ++ }, ++ ++ .num_device_descs = 2, ++ .devices = { ++ { "Hauppauge ATSC MiniCard", ++ { &dib0700_usb_id_table[28], NULL }, ++ { NULL }, ++ }, ++ { "Dell Digital TV Receiver", ++ { &dib0700_usb_id_table[29], NULL }, ++ { NULL }, ++ }, ++ }, + }, + }; + +diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +index cb39ca1..a64cb0c 100644 +--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h ++++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +@@ -127,6 +127,8 @@ + #define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 + #define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 + #define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009 0x5200 ++#define USB_PID_HAUPPAUGE_TIGER_ATSC 0xb200 ++#define USB_PID_HAUPPAUGE_TIGER_ATSC_B210 0xb210 + #define USB_PID_AVERMEDIA_EXPRESS 0xb568 + #define USB_PID_AVERMEDIA_VOLAR 0xa807 + #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0147-UBUNTU-NBK-Ubuntu-2.6.24-24.51netbook13.patch +++ linux-2.6.24/patches/0147-UBUNTU-NBK-Ubuntu-2.6.24-24.51netbook13.patch @@ -0,0 +1,39 @@ +From d4052dfac444270231e95e2aaea73405f2410871 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Tue, 5 May 2009 11:17:21 -0500 +Subject: [PATCH 147/170] UBUNTU: NBK-Ubuntu-2.6.24-24.51netbook13 + +Signed-off-by: Steve Conklin +--- + debian/changelog | 18 ++++++++++++++++++ + 1 files changed, 18 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 990d759..1c6e5d1 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,21 @@ ++linux (2.6.24-24.51netbook13) netbook-common; urgency=low ++ ++ [Jim Lieb] ++ ++ * SAUCE: Enable debug package generation ++ - LP: #340181 ++ ++ [Steve Conklin] ++ ++ * changes to rebase script for netbook-lpia ++ ++ [Upstream Kernel Changes] ++ ++ * Fix help prompt in rebase script when argument is missing ++ * Fix tag parsing in the retag script ++ ++ -- Steve Conklin Tue, 05 May 2009 16:14:09 +0000 ++ + linux (2.6.24-24.51netbook12) netbook-common; urgency=low + + [Andres Salomon] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0144-Fix-help-prompt-in-rebase-script-when-argument-is-mi.patch +++ linux-2.6.24/patches/0144-Fix-help-prompt-in-rebase-script-when-argument-is-mi.patch @@ -0,0 +1,26 @@ +From 266bc75857554f59997cbafe850d805b46f6714a Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Thu, 30 Apr 2009 19:41:04 -0500 +Subject: [PATCH 144/170] Fix help prompt in rebase script when argument is missing + +Signed-off-by: Steve Conklin +--- + debian/scripts/misc/rebase-branch | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/debian/scripts/misc/rebase-branch b/debian/scripts/misc/rebase-branch +index 39813ba..e31c3fc 100755 +--- a/debian/scripts/misc/rebase-branch ++++ b/debian/scripts/misc/rebase-branch +@@ -15,7 +15,7 @@ + # 5. Keep things in a state that they can be merged back + # into the main tree at the end of the dev cycle + +-remoteTag=${1:?"Usage: $0 "} ++remoteTag=${1:?"Usage: $0 "} + + rebasing=".git/rebase-apply" + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0123-Turn-debian-binary-custom.d-lpia-patchset-0018-sdio_.patch +++ linux-2.6.24/patches/0123-Turn-debian-binary-custom.d-lpia-patchset-0018-sdio_.patch @@ -0,0 +1,370 @@ +From 3c1d2d231799704eccded203e69ed26d6323e1e1 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:33 +0100 +Subject: [PATCH 123/170] Turn debian/binary-custom.d/lpia/patchset/0018-sdio_crown_beach.patch into a commit. + +Signed-off-by: Andy Whitcroft + +commit 5c158947412d2fe21a7a61b3df1e5ce74efe5d7f +Author: Amit Kucheria +Date: Thu Oct 30 14:03:39 2008 +0200 + + UBUNTU: SAUCE: Update lpia patches from moblin tree + Bug: #291457 + + Reworked the dabney thermal patch to apply cleanly to the Ubuntu tree + + Signed-off-by: Amit Kucheria + +commit 379bc1831cba94335dd54260c782ba0fe7f1ef91 +Author: Amit Kucheria +Date: Tue Apr 1 00:45:12 2008 +0300 + + UBUNTU: LPIA: Change-umd_dbg-debug-level-to-KERN_INFO + + Signed-off-by: Amit Kucheria + +commit 0f01dfe672c8927bd3968306732ca63066fc0b4b +Author: Amit Kucheria +Date: Tue Apr 1 00:36:28 2008 +0300 + + UBUNTU: LPIA: Update from moblin + + * Better way to fix reset_resume quirk USB devices and replaced previous patch + * Reduce SiB's extra delay from 100ms to 25ms + + Signed-off-by: Amit Kucheria + +commit 1088f016601907855499052f4814f3506557fb0b +Author: Jay Chetty +Date: Tue Jan 29 14:08:32 2008 -0800 + + UBUNTU: poulsbo: Add a 100ms delay for SiB workaround + + Signed-off-by: Jay Chetty + +commit 4883c50b37f2e791e29f545766e53ac456576926 +Author: Amit Kucheria +Date: Fri Jan 11 13:59:04 2008 +0200 + + UBUNTU: Poulsbo: Mass update of patches to be identical to those on moblin + + Sigh, we need better communication... + + Signed-off-by: Amit Kucheria +--- + .../lpia/patchset/0018-sdio_crown_beach.patch | 149 -------------------- + drivers/mmc/core/core.c | 4 + + drivers/mmc/core/sdio.c | 6 + + drivers/mmc/core/sdio_cis.c | 3 +- + drivers/mmc/core/sdio_io.c | 69 +++++++++ + include/linux/mmc/core.h | 16 ++ + 6 files changed, 97 insertions(+), 150 deletions(-) + delete mode 100644 debian/binary-custom.d/lpia/patchset/0018-sdio_crown_beach.patch + +diff --git a/debian/binary-custom.d/lpia/patchset/0018-sdio_crown_beach.patch b/debian/binary-custom.d/lpia/patchset/0018-sdio_crown_beach.patch +deleted file mode 100644 +index f835b93..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0018-sdio_crown_beach.patch ++++ /dev/null +@@ -1,149 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c +-index b966674..17d1d16 100644 +---- a/drivers/mmc/core/core.c +-+++ b/drivers/mmc/core/core.c +-@@ -645,6 +645,10 @@ void mmc_rescan(struct work_struct *work) +- mmc_claim_host(host); +- +- mmc_power_up(host); +-+ +-+ /* add a 25ms delay for SiB workaround */ +-+ mmc_delay(25); +-+ +- mmc_go_idle(host); +- +- mmc_send_if_cond(host, host->ocr_avail); +-diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c +-index d5e51b1..962b8be 100644 +---- a/drivers/mmc/core/sdio_cis.c +-+++ b/drivers/mmc/core/sdio_cis.c +-@@ -151,7 +151,8 @@ static int cistpl_funce(struct mmc_card *card, struct sdio_func *func, +- if (ret) { +- printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u " +- "type %u\n", mmc_hostname(card->host), size, buf[0]); +-- return ret; +-+ /* masked by feng for 8688 + CB debug . */ +-+ /* return ret; */ +- } +- +- return 0; +-diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c +-index 87a50f4..ba2a699 100644 +---- a/drivers/mmc/core/sdio.c +-+++ b/drivers/mmc/core/sdio.c +-@@ -332,6 +332,12 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) +- if (err) +- goto remove; +- +-+ /* add a workaround for Marvell SDIO dev */ +-+ if (card->cis.vendor == 0x2df) { +-+ if (card->cis.max_dtr >= 25000000) +-+ card->cis.max_dtr = 25000000; +-+ } +-+ +- /* +- * No support for high-speed yet, so just set +- * the card's maximum speed. +-diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c +-index 625b92c..f4c62c0 100644 +---- a/drivers/mmc/core/sdio_io.c +-+++ b/drivers/mmc/core/sdio_io.c +-@@ -546,3 +546,72 @@ void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, +- *err_ret = ret; +- } +- EXPORT_SYMBOL_GPL(sdio_f0_writeb); +-+ +-+static char* sdio_version[4] = { +-+ "version 1.00", +-+ "version 1.10", +-+ "version 1.20", +-+ "version 2.00" +-+}; +-+ +-+static char* sd_phy_version[4] = { +-+ "version 1.01", +-+ "version 1.10", +-+ "version 2.00" +-+}; +-+ +-+void sdio_dump_cccr(struct sdio_func *func) +-+{ +-+ struct mmc_card *card = func->card; +-+ u8 data, val; +-+ u8 *str; +-+ int i; +-+ +-+ printk(KERN_INFO "\nStart to dump SDIO CCCR registers:\n"); +-+ +-+ /* dump sdio version */ +-+ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); +-+ val = (data >> 4) & 0xf; +-+ if (val <= 3) +-+ printk(KERN_INFO "SDIO Spec: %s\n", sdio_version[val]); +-+ else +-+ printk(KERN_INFO "This card doesn't comply with any SDIO spec version!!\n"); +-+ +-+ /* dump sd PHY version */ +-+ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SD, 0, &data); +-+ val = data & 0xf; +-+ if (val <= 2) +-+ printk(KERN_INFO "SD PHY spec: %s\n", sd_phy_version[val]); +-+ else +-+ printk(KERN_INFO "This card doesn't comply with any SD PHY spec version!!\n"); +-+ +-+ /* dump IO Enalbe reg */ +-+ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IOEx, 0, &data); +-+ printk(KERN_INFO "IO Enable Reg: 0x%02x\n", data); +-+ +-+ /* dump IO Ready reg */ +-+ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IORx, 0, &data); +-+ printk(KERN_INFO "IO Ready Reg: 0x%02x\n", data); +-+ +-+ /* dump INT Enable reg */ +-+ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IENx, 0, &data); +-+ printk(KERN_INFO "INT Enable Reg: 0x%02x\n", data); +-+ +-+ /* dump INT Pending reg */ +-+ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &data); +-+ printk(KERN_INFO "INT Pending Reg: 0x%02x\n", data); +-+ +-+ /* dump Bus Interface reg */ +-+ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &data); +-+ val = data & 0x3; +-+ printk(KERN_INFO "Bus Width: %d bit\n", (val ? 4 : 1)); +-+ +-+ /* dump capability reg */ +-+ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data); +-+ printk(KERN_INFO "Multi-Block support: %s\n", (data & SDIO_CCCR_CAP_SMB) ? "YES" : "NO"); +-+ printk(KERN_INFO "Suspend/Resume support: %s\n", (data & SDIO_CCCR_CAP_SBS) ? "YES" : "NO"); +-+ printk(KERN_INFO "Low Speed Card: %s\n", (data & SDIO_CCCR_CAP_LSC) ? "YES" : "NO"); +-+ printk(KERN_INFO "4 bits Low Speed Card: %s\n", (data & SDIO_CCCR_CAP_4BLS) ? "YES" : "NO"); +-+} +-+EXPORT_SYMBOL_GPL(sdio_dump_cccr); +-+ +-diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h +-index d0c3abe..a5f4bd3 100644 +---- a/include/linux/mmc/core.h +-+++ b/include/linux/mmc/core.h +-@@ -150,4 +150,20 @@ static inline void mmc_claim_host(struct mmc_host *host) +- __mmc_claim_host(host, NULL); +- } +- +-+/* feng add for temply use */ +-+#define DBG_2622 1 +-+ +-+#ifdef DBG_2622 +-+#define umd_dbg(f, x...) \ +-+ printk(KERN_INFO "[%s()]: " f "\n", __func__,##x) +-+#define umd_enter() \ +-+ printk(KERN_INFO "[%s()]: enter\n", __func__) +-+#define umd_exit() \ +-+ printk(KERN_INFO "[%s()]: exit\n", __func__) +-+#else +-+#define umd_dbg(f, x...) do{} while(0) +-+#define umd_enter() do{} while(0) +-+#define umd_exit() do{} while(0) +-+#endif /* end of DBG_2622 */ +-+ +- #endif +diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c +index 8aea9e6..0c2e8fa 100644 +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -645,6 +645,10 @@ void mmc_rescan(struct work_struct *work) + mmc_claim_host(host); + + mmc_power_up(host); ++ ++ /* add a 25ms delay for SiB workaround */ ++ mmc_delay(25); ++ + mmc_go_idle(host); + + mmc_send_if_cond(host, host->ocr_avail); +diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c +index 87a50f4..ba2a699 100644 +--- a/drivers/mmc/core/sdio.c ++++ b/drivers/mmc/core/sdio.c +@@ -332,6 +332,12 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) + if (err) + goto remove; + ++ /* add a workaround for Marvell SDIO dev */ ++ if (card->cis.vendor == 0x2df) { ++ if (card->cis.max_dtr >= 25000000) ++ card->cis.max_dtr = 25000000; ++ } ++ + /* + * No support for high-speed yet, so just set + * the card's maximum speed. +diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c +index d5e51b1..962b8be 100644 +--- a/drivers/mmc/core/sdio_cis.c ++++ b/drivers/mmc/core/sdio_cis.c +@@ -151,7 +151,8 @@ static int cistpl_funce(struct mmc_card *card, struct sdio_func *func, + if (ret) { + printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u " + "type %u\n", mmc_hostname(card->host), size, buf[0]); +- return ret; ++ /* masked by feng for 8688 + CB debug . */ ++ /* return ret; */ + } + + return 0; +diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c +index 625b92c..ebda27e 100644 +--- a/drivers/mmc/core/sdio_io.c ++++ b/drivers/mmc/core/sdio_io.c +@@ -546,3 +546,72 @@ void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, + *err_ret = ret; + } + EXPORT_SYMBOL_GPL(sdio_f0_writeb); ++ ++static char* sdio_version[4] = { ++ "version 1.00", ++ "version 1.10", ++ "version 1.20", ++ "version 2.00" ++}; ++ ++static char* sd_phy_version[4] = { ++ "version 1.01", ++ "version 1.10", ++ "version 2.00" ++}; ++ ++void sdio_dump_cccr(struct sdio_func *func) ++{ ++ struct mmc_card *card = func->card; ++ u8 data, val; ++ u8 *str; ++ int i; ++ ++ printk(KERN_INFO "\nStart to dump SDIO CCCR registers:\n"); ++ ++ /* dump sdio version */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); ++ val = (data >> 4) & 0xf; ++ if (val <= 3) ++ printk(KERN_INFO "SDIO Spec: %s\n", sdio_version[val]); ++ else ++ printk(KERN_INFO "This card doesn't comply with any SDIO spec version!!\n"); ++ ++ /* dump sd PHY version */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SD, 0, &data); ++ val = data & 0xf; ++ if (val <= 2) ++ printk(KERN_INFO "SD PHY spec: %s\n", sd_phy_version[val]); ++ else ++ printk(KERN_INFO "This card doesn't comply with any SD PHY spec version!!\n"); ++ ++ /* dump IO Enalbe reg */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IOEx, 0, &data); ++ printk(KERN_INFO "IO Enable Reg: 0x%02x\n", data); ++ ++ /* dump IO Ready reg */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IORx, 0, &data); ++ printk(KERN_INFO "IO Ready Reg: 0x%02x\n", data); ++ ++ /* dump INT Enable reg */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IENx, 0, &data); ++ printk(KERN_INFO "INT Enable Reg: 0x%02x\n", data); ++ ++ /* dump INT Pending reg */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &data); ++ printk(KERN_INFO "INT Pending Reg: 0x%02x\n", data); ++ ++ /* dump Bus Interface reg */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &data); ++ val = data & 0x3; ++ printk(KERN_INFO "Bus Width: %d bit\n", (val ? 4 : 1)); ++ ++ /* dump capability reg */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data); ++ printk(KERN_INFO "Multi-Block support: %s\n", (data & SDIO_CCCR_CAP_SMB) ? "YES" : "NO"); ++ printk(KERN_INFO "Suspend/Resume support: %s\n", (data & SDIO_CCCR_CAP_SBS) ? "YES" : "NO"); ++ printk(KERN_INFO "Low Speed Card: %s\n", (data & SDIO_CCCR_CAP_LSC) ? "YES" : "NO"); ++ printk(KERN_INFO "4 bits Low Speed Card: %s\n", (data & SDIO_CCCR_CAP_4BLS) ? "YES" : "NO"); ++} ++EXPORT_SYMBOL_GPL(sdio_dump_cccr); ++ +diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h +index d0c3abe..9bead81 100644 +--- a/include/linux/mmc/core.h ++++ b/include/linux/mmc/core.h +@@ -150,4 +150,20 @@ static inline void mmc_claim_host(struct mmc_host *host) + __mmc_claim_host(host, NULL); + } + ++/* feng add for temply use */ ++#define DBG_2622 1 ++ ++#ifdef DBG_2622 ++#define umd_dbg(f, x...) \ ++ printk(KERN_INFO "[%s()]: " f "\n", __func__,##x) ++#define umd_enter() \ ++ printk(KERN_INFO "[%s()]: enter\n", __func__) ++#define umd_exit() \ ++ printk(KERN_INFO "[%s()]: exit\n", __func__) ++#else ++#define umd_dbg(f, x...) do{} while(0) ++#define umd_enter() do{} while(0) ++#define umd_exit() do{} while(0) ++#endif /* end of DBG_2622 */ ++ + #endif +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0114-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook10.patch +++ linux-2.6.24/patches/0114-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook10.patch @@ -0,0 +1,30 @@ +From 244409cad3250c1f770732cce32fd831095a3b40 Mon Sep 17 00:00:00 2001 +From: Tony Espy +Date: Wed, 1 Apr 2009 20:20:11 -0400 +Subject: [PATCH 114/170] UBUNTU: NBK-Ubuntu-2.6.24-22.45netbook10 + +Ignore: yes +Signed-off-by: Tony Espy +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index b372be1..319920e 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-22.45netbook10) netbook-common; urgency=low ++ ++ [Upstream Kernel Changes] ++ ++ * ACPI: backport of WMI from 2.6.28 ( LP: 334505 ) ++ ++ -- Tony Espy Wed, 01 Apr 2009 20:35:10 +0000 ++ + linux (2.6.24-22.45netbook9) netbook-common; urgency=low + + [Devin Heitmueller] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0124-Turn-debian-binary-custom.d-lpia-patchset-0020-ts-do.patch +++ linux-2.6.24/patches/0124-Turn-debian-binary-custom.d-lpia-patchset-0020-ts-do.patch @@ -0,0 +1,72 @@ +From b866f8b686ebf088c6299bce290e2147b92943d3 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:34 +0100 +Subject: [PATCH 124/170] Turn debian/binary-custom.d/lpia/patchset/0020-ts-doubleclick-workaround.patch into a commit. + +Signed-off-by: Andy Whitcroft + +commit 974128ae34a0e1907d86aa3f915cf9b6208cda88 +Author: Amit Kucheria +Date: Thu Mar 6 04:39:22 2008 +0200 + + UBUNTU: Poulsbo: Sync patches with moblin/ume-hardy tree + + Signed-off-by: Amit Kucheria +--- + .../patchset/0020-ts-doubleclick-workaround.patch | 22 -------------------- + drivers/input/mousedev.c | 3 ++ + 2 files changed, 3 insertions(+), 22 deletions(-) + delete mode 100644 debian/binary-custom.d/lpia/patchset/0020-ts-doubleclick-workaround.patch + +diff --git a/debian/binary-custom.d/lpia/patchset/0020-ts-doubleclick-workaround.patch b/debian/binary-custom.d/lpia/patchset/0020-ts-doubleclick-workaround.patch +deleted file mode 100644 +index 936ba16..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0020-ts-doubleclick-workaround.patch ++++ /dev/null +@@ -1,22 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c +-index be83516..1a7f0e0 100644 +---- a/drivers/input/mousedev.c +-+++ b/drivers/input/mousedev.c +-@@ -1009,6 +1009,8 @@ static const struct input_device_id mousedev_ids[] = { +- .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) }, +- .relbit = { BIT_MASK(REL_WHEEL) }, +- }, /* A separate scrollwheel */ +-+/* masked for MID device touchscreen double-click issue */ +-+#if 0 +- { +- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | +- INPUT_DEVICE_ID_MATCH_KEYBIT | +-@@ -1018,6 +1020,7 @@ static const struct input_device_id mousedev_ids[] = { +- .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, +- }, /* A tablet like device, at least touch detection, +- two absolute axes */ +-+#endif +- { +- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | +- INPUT_DEVICE_ID_MATCH_KEYBIT | +diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c +index be83516..1a7f0e0 100644 +--- a/drivers/input/mousedev.c ++++ b/drivers/input/mousedev.c +@@ -1009,6 +1009,8 @@ static const struct input_device_id mousedev_ids[] = { + .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) }, + .relbit = { BIT_MASK(REL_WHEEL) }, + }, /* A separate scrollwheel */ ++/* masked for MID device touchscreen double-click issue */ ++#if 0 + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_KEYBIT | +@@ -1018,6 +1020,7 @@ static const struct input_device_id mousedev_ids[] = { + .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, + }, /* A tablet like device, at least touch detection, + two absolute axes */ ++#endif + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_KEYBIT | +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0017-kgdb-Add-kgdb-internal-test-suite.patch +++ linux-2.6.24/patches/0017-kgdb-Add-kgdb-internal-test-suite.patch @@ -0,0 +1,1211 @@ +From 8398158327326f3a91840f995a6c4a0cc48cd4da Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 7 Mar 2008 16:34:17 -0600 +Subject: [PATCH 017/170] kgdb: Add kgdb internal test suite + +This patch adds regression tests for testing the kgdb core and arch +specific implementation. + +The kgdb test suite is designed to be built into the kernel and not as +a module because it uses a number of low level kernel and kgdb +primitives which should not be exported externally. + +The kgdb test suite is designed as a KGDB I/O module which +simulates the communications that a debugger would have with kgdb. +The tests are broken up in to a line by line and referenced here as +a "get" which is kgdb requesting input and "put" which is kgdb +sending a response. + +The kgdb suite can be invoked from the kernel command line +arguments system or executed dynamically at run time. The test +suite uses the variable "kgdbts" to obtain the information about +which tests to run and to configure the verbosity level. The +following are the various characters you can use with the kgdbts= +line: + +When using the "kgdbts=" you only choose one of the following core +test types: +A = Run all the core tests silently +V1 = Run all the core tests with minimal output +V2 = Run all the core tests in debug mode + +You can also specify optional tests: +N## = Go to sleep with interrupts of for ## seconds + to test the HW NMI watchdog +F## = Break at do_fork for ## iterations +S## = Break at sys_open for ## iterations + +NOTE: that the do_fork and sys_open tests are mutually exclusive. + +To invoke the kgdb test suite from boot you use a kernel start +argument as follows: + kgdbts=V1 kgdbwait +Or if you wanted to perform the NMI test for 6 seconds and do_fork +test for 100 forks, you could use: + kgdbts=V1N6F100 kgdbwait + +The test suite can also be invoked at run time with: +echo kgdbts=V1N6F100 > /sys/module/kgdbts/parameters/kgdbts +Or as another example: +echo kgdbts=V2 > /sys/module/kgdbts/parameters/kgdbts + +When developing a new kgdb arch specific implementation or +using these tests for the purpose of regression testing, +several invocations are required. + +1) Boot with the test suite enabled by using the kernel arguments + "kgdbts=V1F100 kgdbwait" + ## If kgdb arch specific implementation has NMI use + "kgdbts=V1N6F100 + +2) After the system boot run the basic test. +echo kgdbts=V1 > /sys/module/kgdbts/parameters/kgdbts + +3) Run the concurrency tests. It is best to use n+1 + while loops where n is the number of cpus you have + in your system. The example below uses only two + loops. + +## This tests break points on sys_open +while [ 1 ] ; do find / > /dev/null 2>&1 ; done & +while [ 1 ] ; do find / > /dev/null 2>&1 ; done & +echo kgdbts=V1S10000 > /sys/module/kgdbts/parameters/kgdbts +fg # and hit control-c +fg # and hit control-c +## This tests break points on do_fork +while [ 1 ] ; do date > /dev/null ; done & +while [ 1 ] ; do date > /dev/null ; done & +echo kgdbts=V1F1000 > /sys/module/kgdbts/parameters/kgdbts +fg # and hit control-c + +Signed-off-by: Jason Wessel +Signed-off-by: Ingo Molnar +--- + drivers/misc/Makefile | 1 + + drivers/misc/kgdbts.c | 1083 +++++++++++++++++++++++++++++++++++++++++++++++++ + lib/Kconfig.kgdb | 13 + + 3 files changed, 1097 insertions(+), 0 deletions(-) + create mode 100644 drivers/misc/kgdbts.c + +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index 87f2685..757762b 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -17,3 +17,4 @@ obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o + obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o + obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o + obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o ++obj-$(CONFIG_KGDB_TESTS) += kgdbts.o +diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c +new file mode 100644 +index 0000000..cbc4822 +--- /dev/null ++++ b/drivers/misc/kgdbts.c +@@ -0,0 +1,1083 @@ ++/* ++ * kgdbts is a test suite for kgdb for the sole purpose of validating ++ * that key pieces of the kgdb internals are working properly such as ++ * HW/SW breakpoints, single stepping, and NMI. ++ * ++ * Created by: Jason Wessel ++ * ++ * Copyright (c) 2008 Wind River Systems, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * See the GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++/* Information about the kgdb test suite. ++ * ------------------------------------- ++ * ++ * The kgdb test suite is designed as a KGDB I/O module which ++ * simulates the communications that a debugger would have with kgdb. ++ * The tests are broken up in to a line by line and referenced here as ++ * a "get" which is kgdb requesting input and "put" which is kgdb ++ * sending a response. ++ * ++ * The kgdb suite can be invoked from the kernel command line ++ * arguments system or executed dynamically at run time. The test ++ * suite uses the variable "kgdbts" to obtain the information about ++ * which tests to run and to configure the verbosity level. The ++ * following are the various characters you can use with the kgdbts= ++ * line: ++ * ++ * When using the "kgdbts=" you only choose one of the following core ++ * test types: ++ * A = Run all the core tests silently ++ * V1 = Run all the core tests with minimal output ++ * V2 = Run all the core tests in debug mode ++ * ++ * You can also specify optional tests: ++ * N## = Go to sleep with interrupts of for ## seconds ++ * to test the HW NMI watchdog ++ * F## = Break at do_fork for ## iterations ++ * S## = Break at sys_open for ## iterations ++ * ++ * NOTE: that the do_fork and sys_open tests are mutually exclusive. ++ * ++ * To invoke the kgdb test suite from boot you use a kernel start ++ * argument as follows: ++ * kgdbts=V1 kgdbwait ++ * Or if you wanted to perform the NMI test for 6 seconds and do_fork ++ * test for 100 forks, you could use: ++ * kgdbts=V1N6F100 kgdbwait ++ * ++ * The test suite can also be invoked at run time with: ++ * echo kgdbts=V1N6F100 > /sys/module/kgdbts/parameters/kgdbts ++ * Or as another example: ++ * echo kgdbts=V2 > /sys/module/kgdbts/parameters/kgdbts ++ * ++ * When developing a new kgdb arch specific implementation or ++ * using these tests for the purpose of regression testing, ++ * several invocations are required. ++ * ++ * 1) Boot with the test suite enabled by using the kernel arguments ++ * "kgdbts=V1F100 kgdbwait" ++ * ## If kgdb arch specific implementation has NMI use ++ * "kgdbts=V1N6F100 ++ * ++ * 2) After the system boot run the basic test. ++ * echo kgdbts=V1 > /sys/module/kgdbts/parameters/kgdbts ++ * ++ * 3) Run the concurrency tests. It is best to use n+1 ++ * while loops where n is the number of cpus you have ++ * in your system. The example below uses only two ++ * loops. ++ * ++ * ## This tests break points on sys_open ++ * while [ 1 ] ; do find / > /dev/null 2>&1 ; done & ++ * while [ 1 ] ; do find / > /dev/null 2>&1 ; done & ++ * echo kgdbts=V1S10000 > /sys/module/kgdbts/parameters/kgdbts ++ * fg # and hit control-c ++ * fg # and hit control-c ++ * ## This tests break points on do_fork ++ * while [ 1 ] ; do date > /dev/null ; done & ++ * while [ 1 ] ; do date > /dev/null ; done & ++ * echo kgdbts=V1F1000 > /sys/module/kgdbts/parameters/kgdbts ++ * fg # and hit control-c ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define v1printk(a...) do { \ ++ if (verbose) \ ++ printk(KERN_INFO a); \ ++ } while (0) ++#define v2printk(a...) do { \ ++ if (verbose > 1) \ ++ printk(KERN_INFO a); \ ++ touch_nmi_watchdog(); \ ++ } while (0) ++#define MAX_CONFIG_LEN 40 ++ ++static const char hexchars[] = "0123456789abcdef"; ++static struct kgdb_io kgdbts_io_ops; ++static char get_buf[BUFMAX]; ++static int get_buf_cnt; ++static char put_buf[BUFMAX]; ++static int put_buf_cnt; ++static char scratch_buf[BUFMAX]; ++static int verbose; ++static int repeat_test; ++static int test_complete; ++static int send_ack; ++static int final_ack; ++static int hw_break_val; ++static int hw_break_val2; ++#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) ++static int arch_needs_sstep_emulation = 1; ++#else ++static int arch_needs_sstep_emulation; ++#endif ++static unsigned long sstep_addr; ++static int sstep_state; ++ ++/* Storage for the registers, in GDB format. */ ++static unsigned long kgdbts_gdb_regs[(NUMREGBYTES + ++ sizeof(unsigned long) - 1) / ++ sizeof(unsigned long)]; ++static struct pt_regs kgdbts_regs; ++ ++/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ ++static int configured = -1; ++ ++static char config[MAX_CONFIG_LEN]; ++static struct kparam_string kps = { ++ .string = config, ++ .maxlen = MAX_CONFIG_LEN, ++}; ++ ++static void fill_get_buf(char *buf); ++ ++struct test_struct { ++ char *get; ++ char *put; ++ void (*get_handler)(char *); ++ int (*put_handler)(char *, char *); ++}; ++ ++struct test_state { ++ char *name; ++ struct test_struct *tst; ++ int idx; ++ int (*run_test) (int, int); ++ int (*validate_put) (char *); ++}; ++ ++static struct test_state ts; ++ ++static int kgdbts_unreg_thread(void *ptr) ++{ ++ /* Wait until the tests are complete and then ungresiter the I/O ++ * driver. ++ */ ++ while (!final_ack) ++ msleep_interruptible(1500); ++ ++ if (configured) ++ kgdb_unregister_io_module(&kgdbts_io_ops); ++ configured = 0; ++ ++ return 0; ++} ++ ++/* This is noinline such that it can be used for a single location to ++ * place a breakpoint ++ */ ++static noinline void kgdbts_break_test(void) ++{ ++ v2printk("kgdbts: breakpoint complete\n"); ++} ++ ++/* Lookup symbol info in the kernel */ ++static unsigned long lookup_addr(char *arg) ++{ ++ unsigned long addr = 0; ++ ++ if (!strcmp(arg, "kgdbts_break_test")) ++ addr = (unsigned long)kgdbts_break_test; ++ else if (!strcmp(arg, "sys_open")) ++ addr = (unsigned long)sys_open; ++ else if (!strcmp(arg, "do_fork")) ++ addr = (unsigned long)do_fork; ++ else if (!strcmp(arg, "hw_break_val")) ++ addr = (unsigned long)&hw_break_val; ++ return addr; ++} ++ ++static void break_helper(char *bp_type, char *arg, unsigned long vaddr) ++{ ++ unsigned long addr; ++ ++ if (arg) ++ addr = lookup_addr(arg); ++ else ++ addr = vaddr; ++ ++ sprintf(scratch_buf, "%s,%lx,%i", bp_type, addr, ++ BREAK_INSTR_SIZE); ++ fill_get_buf(scratch_buf); ++} ++ ++static void sw_break(char *arg) ++{ ++ break_helper("Z0", arg, 0); ++} ++ ++static void sw_rem_break(char *arg) ++{ ++ break_helper("z0", arg, 0); ++} ++ ++static void hw_break(char *arg) ++{ ++ break_helper("Z1", arg, 0); ++} ++ ++static void hw_rem_break(char *arg) ++{ ++ break_helper("z1", arg, 0); ++} ++ ++static void hw_write_break(char *arg) ++{ ++ break_helper("Z2", arg, 0); ++} ++ ++static void hw_rem_write_break(char *arg) ++{ ++ break_helper("z2", arg, 0); ++} ++ ++static void hw_access_break(char *arg) ++{ ++ break_helper("Z4", arg, 0); ++} ++ ++static void hw_rem_access_break(char *arg) ++{ ++ break_helper("z4", arg, 0); ++} ++ ++static void hw_break_val_access(void) ++{ ++ hw_break_val2 = hw_break_val; ++} ++ ++static void hw_break_val_write(void) ++{ ++ hw_break_val++; ++} ++ ++static int check_and_rewind_pc(char *put_str, char *arg) ++{ ++ unsigned long addr = lookup_addr(arg); ++ int offset = 0; ++ ++ kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, ++ NUMREGBYTES); ++ gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); ++ v2printk("Stopped at IP: %lx\n", instruction_pointer(&kgdbts_regs)); ++#ifdef CONFIG_X86 ++ /* On x86 a breakpoint stop requires it to be decremented */ ++ if (addr + 1 == kgdbts_regs.ip) ++ offset = -1; ++#endif ++ if (strcmp(arg, "silent") && ++ instruction_pointer(&kgdbts_regs) + offset != addr) { ++ printk(KERN_ERR "kgdbts: BP mismatch %lx expected %lx\n", ++ instruction_pointer(&kgdbts_regs) + offset, addr); ++ return 1; ++ } ++#ifdef CONFIG_X86 ++ /* On x86 adjust the instruction pointer if needed */ ++ kgdbts_regs.ip += offset; ++#endif ++ return 0; ++} ++ ++static int check_single_step(char *put_str, char *arg) ++{ ++ unsigned long addr = lookup_addr(arg); ++ /* ++ * From an arch indepent point of view the instruction pointer ++ * should be on a different instruction ++ */ ++ kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, ++ NUMREGBYTES); ++ gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); ++ v2printk("Singlestep stopped at IP: %lx\n", ++ instruction_pointer(&kgdbts_regs)); ++ if (instruction_pointer(&kgdbts_regs) == addr) { ++ printk(KERN_ERR "kgdbts: SingleStep failed at %lx\n", ++ instruction_pointer(&kgdbts_regs)); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void write_regs(char *arg) ++{ ++ memset(scratch_buf, 0, sizeof(scratch_buf)); ++ scratch_buf[0] = 'G'; ++ pt_regs_to_gdb_regs(kgdbts_gdb_regs, &kgdbts_regs); ++ kgdb_mem2hex((char *)kgdbts_gdb_regs, &scratch_buf[1], NUMREGBYTES); ++ fill_get_buf(scratch_buf); ++} ++ ++static void skip_back_repeat_test(char *arg) ++{ ++ int go_back = simple_strtol(arg, NULL, 10); ++ ++ repeat_test--; ++ if (repeat_test <= 0) ++ ts.idx++; ++ else ++ ts.idx -= go_back; ++ fill_get_buf(ts.tst[ts.idx].get); ++} ++ ++static int got_break(char *put_str, char *arg) ++{ ++ test_complete = 1; ++ if (!strncmp(put_str+1, arg, 2)) { ++ if (!strncmp(arg, "T0", 2)) ++ test_complete = 2; ++ return 0; ++ } ++ return 1; ++} ++ ++static void emul_sstep_get(char *arg) ++{ ++ if (!arch_needs_sstep_emulation) { ++ fill_get_buf(arg); ++ return; ++ } ++ switch (sstep_state) { ++ case 0: ++ v2printk("Emulate single step\n"); ++ /* Start by looking at the current PC */ ++ fill_get_buf("g"); ++ break; ++ case 1: ++ /* set breakpoint */ ++ break_helper("Z0", 0, sstep_addr); ++ break; ++ case 2: ++ /* Continue */ ++ fill_get_buf("c"); ++ break; ++ case 3: ++ /* Clear breakpoint */ ++ break_helper("z0", 0, sstep_addr); ++ break; ++ default: ++ printk(KERN_ERR "kgdbts: ERROR failed sstep get emulation\n"); ++ } ++ sstep_state++; ++} ++ ++static int emul_sstep_put(char *put_str, char *arg) ++{ ++ if (!arch_needs_sstep_emulation) { ++ if (!strncmp(put_str+1, arg, 2)) ++ return 0; ++ return 1; ++ } ++ switch (sstep_state) { ++ case 1: ++ /* validate the "g" packet to get the IP */ ++ kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, ++ NUMREGBYTES); ++ gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); ++ v2printk("Stopped at IP: %lx\n", ++ instruction_pointer(&kgdbts_regs)); ++ /* Want to stop at IP + break instruction size by default */ ++ sstep_addr = instruction_pointer(&kgdbts_regs) + ++ BREAK_INSTR_SIZE; ++ break; ++ case 2: ++ if (strncmp(put_str, "$OK", 3)) { ++ printk(KERN_ERR "kgdbts: failed sstep break set\n"); ++ return 1; ++ } ++ break; ++ case 3: ++ if (strncmp(put_str, "$T0", 3)) { ++ printk(KERN_ERR "kgdbts: failed continue sstep\n"); ++ return 1; ++ } ++ break; ++ case 4: ++ if (strncmp(put_str, "$OK", 3)) { ++ printk(KERN_ERR "kgdbts: failed sstep break unset\n"); ++ return 1; ++ } ++ /* Single step is complete so continue on! */ ++ sstep_state = 0; ++ return 0; ++ default: ++ printk(KERN_ERR "kgdbts: ERROR failed sstep put emulation\n"); ++ } ++ ++ /* Continue on the same test line until emulation is complete */ ++ ts.idx--; ++ return 0; ++} ++ ++static int final_ack_set(char *put_str, char *arg) ++{ ++ if (strncmp(put_str+1, arg, 2)) ++ return 1; ++ final_ack = 1; ++ return 0; ++} ++/* ++ * Test to plant a breakpoint and detach, which should clear out the ++ * breakpoint and restore the original instruction. ++ */ ++static struct test_struct plant_and_detach_test[] = { ++ { "?", "S0*" }, /* Clear break points */ ++ { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ ++ { "D", "OK" }, /* Detach */ ++ { "", "" }, ++}; ++ ++/* ++ * Simple test to write in a software breakpoint, check for the ++ * correct stop location and detach. ++ */ ++static struct test_struct sw_breakpoint_test[] = { ++ { "?", "S0*" }, /* Clear break points */ ++ { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ ++ { "c", "T0*", }, /* Continue */ ++ { "g", "kgdbts_break_test", 0, check_and_rewind_pc }, ++ { "write", "OK", write_regs }, ++ { "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */ ++ { "D", "OK" }, /* Detach */ ++ { "D", "OK", 0, got_break }, /* If the test worked we made it here */ ++ { "", "" }, ++}; ++ ++/* ++ * Test a known bad memory read location to test the fault handler and ++ * read bytes 1-8 at the bad address ++ */ ++static struct test_struct bad_read_test[] = { ++ { "?", "S0*" }, /* Clear break points */ ++ { "m0,1", "E*" }, /* read 1 byte at address 1 */ ++ { "m0,2", "E*" }, /* read 1 byte at address 2 */ ++ { "m0,3", "E*" }, /* read 1 byte at address 3 */ ++ { "m0,4", "E*" }, /* read 1 byte at address 4 */ ++ { "m0,5", "E*" }, /* read 1 byte at address 5 */ ++ { "m0,6", "E*" }, /* read 1 byte at address 6 */ ++ { "m0,7", "E*" }, /* read 1 byte at address 7 */ ++ { "m0,8", "E*" }, /* read 1 byte at address 8 */ ++ { "D", "OK" }, /* Detach which removes all breakpoints and continues */ ++ { "", "" }, ++}; ++ ++/* ++ * Test for hitting a breakpoint, remove it, single step, plant it ++ * again and detach. ++ */ ++static struct test_struct singlestep_break_test[] = { ++ { "?", "S0*" }, /* Clear break points */ ++ { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ ++ { "c", "T0*", }, /* Continue */ ++ { "g", "kgdbts_break_test", 0, check_and_rewind_pc }, ++ { "write", "OK", write_regs }, /* Write registers */ ++ { "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */ ++ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ ++ { "g", "kgdbts_break_test", 0, check_single_step }, ++ { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ ++ { "c", "T0*", }, /* Continue */ ++ { "g", "kgdbts_break_test", 0, check_and_rewind_pc }, ++ { "write", "OK", write_regs }, /* Write registers */ ++ { "D", "OK" }, /* Remove all breakpoints and continues */ ++ { "", "" }, ++}; ++ ++/* ++ * Test for hitting a breakpoint at do_fork for what ever the number ++ * of iterations required by the variable repeat_test. ++ */ ++static struct test_struct do_fork_test[] = { ++ { "?", "S0*" }, /* Clear break points */ ++ { "do_fork", "OK", sw_break, }, /* set sw breakpoint */ ++ { "c", "T0*", }, /* Continue */ ++ { "g", "do_fork", 0, check_and_rewind_pc }, /* check location */ ++ { "write", "OK", write_regs }, /* Write registers */ ++ { "do_fork", "OK", sw_rem_break }, /*remove breakpoint */ ++ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ ++ { "g", "do_fork", 0, check_single_step }, ++ { "do_fork", "OK", sw_break, }, /* set sw breakpoint */ ++ { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */ ++ { "D", "OK", 0, final_ack_set }, /* detach and unregister I/O */ ++ { "", "" }, ++}; ++ ++/* Test for hitting a breakpoint at sys_open for what ever the number ++ * of iterations required by the variable repeat_test. ++ */ ++static struct test_struct sys_open_test[] = { ++ { "?", "S0*" }, /* Clear break points */ ++ { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ ++ { "c", "T0*", }, /* Continue */ ++ { "g", "sys_open", 0, check_and_rewind_pc }, /* check location */ ++ { "write", "OK", write_regs }, /* Write registers */ ++ { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */ ++ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ ++ { "g", "sys_open", 0, check_single_step }, ++ { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ ++ { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */ ++ { "D", "OK", 0, final_ack_set }, /* detach and unregister I/O */ ++ { "", "" }, ++}; ++ ++/* ++ * Test for hitting a simple hw breakpoint ++ */ ++static struct test_struct hw_breakpoint_test[] = { ++ { "?", "S0*" }, /* Clear break points */ ++ { "kgdbts_break_test", "OK", hw_break, }, /* set hw breakpoint */ ++ { "c", "T0*", }, /* Continue */ ++ { "g", "kgdbts_break_test", 0, check_and_rewind_pc }, ++ { "write", "OK", write_regs }, ++ { "kgdbts_break_test", "OK", hw_rem_break }, /*remove breakpoint */ ++ { "D", "OK" }, /* Detach */ ++ { "D", "OK", 0, got_break }, /* If the test worked we made it here */ ++ { "", "" }, ++}; ++ ++/* ++ * Test for hitting a hw write breakpoint ++ */ ++static struct test_struct hw_write_break_test[] = { ++ { "?", "S0*" }, /* Clear break points */ ++ { "hw_break_val", "OK", hw_write_break, }, /* set hw breakpoint */ ++ { "c", "T0*", 0, got_break }, /* Continue */ ++ { "g", "silent", 0, check_and_rewind_pc }, ++ { "write", "OK", write_regs }, ++ { "hw_break_val", "OK", hw_rem_write_break }, /*remove breakpoint */ ++ { "D", "OK" }, /* Detach */ ++ { "D", "OK", 0, got_break }, /* If the test worked we made it here */ ++ { "", "" }, ++}; ++ ++/* ++ * Test for hitting a hw access breakpoint ++ */ ++static struct test_struct hw_access_break_test[] = { ++ { "?", "S0*" }, /* Clear break points */ ++ { "hw_break_val", "OK", hw_access_break, }, /* set hw breakpoint */ ++ { "c", "T0*", 0, got_break }, /* Continue */ ++ { "g", "silent", 0, check_and_rewind_pc }, ++ { "write", "OK", write_regs }, ++ { "hw_break_val", "OK", hw_rem_access_break }, /*remove breakpoint */ ++ { "D", "OK" }, /* Detach */ ++ { "D", "OK", 0, got_break }, /* If the test worked we made it here */ ++ { "", "" }, ++}; ++ ++/* ++ * Test for hitting a hw access breakpoint ++ */ ++static struct test_struct nmi_sleep_test[] = { ++ { "?", "S0*" }, /* Clear break points */ ++ { "c", "T0*", 0, got_break }, /* Continue */ ++ { "D", "OK" }, /* Detach */ ++ { "D", "OK", 0, got_break }, /* If the test worked we made it here */ ++ { "", "" }, ++}; ++ ++static void fill_get_buf(char *buf) ++{ ++ unsigned char checksum = 0; ++ int count = 0; ++ char ch; ++ ++ strcpy(get_buf, "$"); ++ strcat(get_buf, buf); ++ while ((ch = buf[count])) { ++ checksum += ch; ++ count++; ++ } ++ strcat(get_buf, "#"); ++ get_buf[count + 2] = hexchars[checksum >> 4]; ++ get_buf[count + 3] = hexchars[checksum & 0xf]; ++ get_buf[count + 4] = '\0'; ++ v2printk("get%i: %s\n", ts.idx, get_buf); ++} ++ ++static int validate_simple_test(char *put_str) ++{ ++ char *chk_str; ++ ++ if (ts.tst[ts.idx].put_handler) ++ return ts.tst[ts.idx].put_handler(put_str, ++ ts.tst[ts.idx].put); ++ ++ chk_str = ts.tst[ts.idx].put; ++ if (*put_str == '$') ++ put_str++; ++ ++ while (*chk_str != '\0' && *put_str != '\0') { ++ /* If someone does a * to match the rest of the string, allow ++ * it, or stop if the recieved string is complete. ++ */ ++ if (*put_str == '#' || *chk_str == '*') ++ return 0; ++ if (*put_str != *chk_str) ++ return 1; ++ ++ chk_str++; ++ put_str++; ++ } ++ if (*chk_str == '\0' && (*put_str == '\0' || *put_str == '#')) ++ return 0; ++ ++ return 1; ++} ++ ++static int run_simple_test(int is_get_char, int chr) ++{ ++ int ret = 0; ++ if (is_get_char) { ++ /* Send an ACK on the get if a prior put completed and set the ++ * send ack variable ++ */ ++ if (send_ack) { ++ send_ack = 0; ++ return '+'; ++ } ++ /* On the first get char, fill the transmit buffer and then ++ * take from the get_string. ++ */ ++ if (get_buf_cnt == 0) { ++ if (ts.tst[ts.idx].get_handler) ++ ts.tst[ts.idx].get_handler(ts.tst[ts.idx].get); ++ else ++ fill_get_buf(ts.tst[ts.idx].get); ++ } ++ ++ if (get_buf[get_buf_cnt] == '\0') { ++ printk(KERN_ERR ++ "kgdbts: ERROR GET: end of buffer on '%s' at %i\n", ++ ts.name, ts.idx); ++ get_buf_cnt = 0; ++ fill_get_buf("D"); ++ } ++ ret = get_buf[get_buf_cnt]; ++ get_buf_cnt++; ++ return ret; ++ } ++ ++ /* This callback is a put char which is when kgdb sends data to ++ * this I/O module. ++ */ ++ if (ts.tst[ts.idx].get[0] == '\0' && ++ ts.tst[ts.idx].put[0] == '\0') { ++ printk(KERN_ERR "kgdbts: ERROR: beyond end of test on" ++ " '%s' line %i\n", ts.name, ts.idx); ++ return 0; ++ } ++ ++ if (put_buf_cnt >= BUFMAX) { ++ printk(KERN_ERR "kgdbts: ERROR: put buffer overflow on" ++ " '%s' line %i\n", ts.name, ts.idx); ++ put_buf_cnt = 0; ++ return 0; ++ } ++ /* Ignore everything until the first valid packet start '$' */ ++ if (put_buf_cnt == 0 && chr != '$') ++ return 0; ++ ++ put_buf[put_buf_cnt] = chr; ++ put_buf_cnt++; ++ ++ /* End of packet == #XX so look for the '#' */ ++ if (put_buf_cnt > 3 && put_buf[put_buf_cnt - 3] == '#') { ++ put_buf[put_buf_cnt] = '\0'; ++ v2printk("put%i: %s\n", ts.idx, put_buf); ++ /* Trigger check here */ ++ if (ts.validate_put && ts.validate_put(put_buf)) { ++ printk(KERN_ERR "kgdbts: ERROR PUT: end of test " ++ "buffer on '%s' line %i expected %s got %s\n", ++ ts.name, ts.idx, ts.tst[ts.idx].put, put_buf); ++ } ++ ts.idx++; ++ put_buf_cnt = 0; ++ get_buf_cnt = 0; ++ send_ack = 1; ++ } ++ return 0; ++} ++ ++static void init_simple_test(void) ++{ ++ memset(&ts, 0, sizeof(ts)); ++ ts.run_test = run_simple_test; ++ ts.validate_put = validate_simple_test; ++} ++ ++static void run_plant_and_detach_test(int is_early) ++{ ++ char before[BREAK_INSTR_SIZE]; ++ char after[BREAK_INSTR_SIZE]; ++ ++ probe_kernel_read(before, (char *)kgdbts_break_test, ++ BREAK_INSTR_SIZE); ++ init_simple_test(); ++ ts.tst = plant_and_detach_test; ++ ts.name = "plant_and_detach_test"; ++ /* Activate test with initial breakpoint */ ++ if (!is_early) ++ kgdb_breakpoint(); ++ probe_kernel_read(after, (char *)kgdbts_break_test, ++ BREAK_INSTR_SIZE); ++ if (memcmp(before, after, BREAK_INSTR_SIZE)) { ++ printk(KERN_CRIT "kgdbts: ERROR kgdb corrupted memory\n"); ++ panic("kgdb memory corruption"); ++ } ++ ++ /* complete the detach test */ ++ if (!is_early) ++ kgdbts_break_test(); ++} ++ ++static void run_breakpoint_test(int is_hw_breakpoint) ++{ ++ test_complete = 0; ++ init_simple_test(); ++ if (is_hw_breakpoint) { ++ ts.tst = hw_breakpoint_test; ++ ts.name = "hw_breakpoint_test"; ++ } else { ++ ts.tst = sw_breakpoint_test; ++ ts.name = "sw_breakpoint_test"; ++ } ++ /* Activate test with initial breakpoint */ ++ kgdb_breakpoint(); ++ /* run code with the break point in it */ ++ kgdbts_break_test(); ++ kgdb_breakpoint(); ++ ++ if (test_complete) ++ return; ++ ++ printk(KERN_ERR "kgdbts: ERROR %s test failed\n", ts.name); ++} ++ ++static void run_hw_break_test(int is_write_test) ++{ ++ test_complete = 0; ++ init_simple_test(); ++ if (is_write_test) { ++ ts.tst = hw_write_break_test; ++ ts.name = "hw_write_break_test"; ++ } else { ++ ts.tst = hw_access_break_test; ++ ts.name = "hw_access_break_test"; ++ } ++ /* Activate test with initial breakpoint */ ++ kgdb_breakpoint(); ++ hw_break_val_access(); ++ if (is_write_test) { ++ if (test_complete == 2) ++ printk(KERN_ERR "kgdbts: ERROR %s broke on access\n", ++ ts.name); ++ hw_break_val_write(); ++ } ++ kgdb_breakpoint(); ++ ++ if (test_complete == 1) ++ return; ++ ++ printk(KERN_ERR "kgdbts: ERROR %s test failed\n", ts.name); ++} ++ ++static void run_nmi_sleep_test(int nmi_sleep) ++{ ++ unsigned long flags; ++ ++ init_simple_test(); ++ ts.tst = nmi_sleep_test; ++ ts.name = "nmi_sleep_test"; ++ /* Activate test with initial breakpoint */ ++ kgdb_breakpoint(); ++ local_irq_save(flags); ++ mdelay(nmi_sleep*1000); ++ touch_nmi_watchdog(); ++ local_irq_restore(flags); ++ if (test_complete != 2) ++ printk(KERN_ERR "kgdbts: ERROR nmi_test did not hit nmi\n"); ++ kgdb_breakpoint(); ++ if (test_complete == 1) ++ return; ++ ++ printk(KERN_ERR "kgdbts: ERROR %s test failed\n", ts.name); ++} ++ ++static void run_bad_read_test(void) ++{ ++ init_simple_test(); ++ ts.tst = bad_read_test; ++ ts.name = "bad_read_test"; ++ /* Activate test with initial breakpoint */ ++ kgdb_breakpoint(); ++} ++ ++static void run_do_fork_test(void) ++{ ++ init_simple_test(); ++ ts.tst = do_fork_test; ++ ts.name = "do_fork_test"; ++ /* Activate test with initial breakpoint */ ++ kgdb_breakpoint(); ++} ++ ++static void run_sys_open_test(void) ++{ ++ init_simple_test(); ++ ts.tst = sys_open_test; ++ ts.name = "sys_open_test"; ++ /* Activate test with initial breakpoint */ ++ kgdb_breakpoint(); ++} ++ ++static void run_singlestep_break_test(void) ++{ ++ init_simple_test(); ++ ts.tst = singlestep_break_test; ++ ts.name = "singlestep_breakpoint_test"; ++ /* Activate test with initial breakpoint */ ++ kgdb_breakpoint(); ++ kgdbts_break_test(); ++ kgdbts_break_test(); ++} ++ ++static void kgdbts_run_tests(void) ++{ ++ char *ptr; ++ int fork_test = 0; ++ int sys_open_test = 0; ++ int nmi_sleep = 0; ++ ++ ptr = strstr(config, "F"); ++ if (ptr) ++ fork_test = simple_strtol(ptr+1, NULL, 10); ++ ptr = strstr(config, "S"); ++ if (ptr) ++ sys_open_test = simple_strtol(ptr+1, NULL, 10); ++ ptr = strstr(config, "N"); ++ if (ptr) ++ nmi_sleep = simple_strtol(ptr+1, NULL, 10); ++ ++ /* required internal KGDB tests */ ++ v1printk("kgdbts:RUN plant and detach test\n"); ++ run_plant_and_detach_test(0); ++ v1printk("kgdbts:RUN sw breakpoint test\n"); ++ run_breakpoint_test(0); ++ v1printk("kgdbts:RUN bad memory access test\n"); ++ run_bad_read_test(); ++ v1printk("kgdbts:RUN singlestep breakpoint test\n"); ++ run_singlestep_break_test(); ++ ++ /* ===Optional tests=== */ ++ ++ /* All HW break point tests */ ++ if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) { ++ v1printk("kgdbts:RUN hw breakpoint test\n"); ++ run_breakpoint_test(1); ++ v1printk("kgdbts:RUN hw write breakpoint test\n"); ++ run_hw_break_test(1); ++ v1printk("kgdbts:RUN access write breakpoint test\n"); ++ run_hw_break_test(0); ++ } ++ ++ if (nmi_sleep) { ++ v1printk("kgdbts:RUN NMI sleep %i seconds test\n", nmi_sleep); ++ run_nmi_sleep_test(nmi_sleep); ++ } ++ ++ /* If the do_fork test is run it will be the last test that is ++ * executed because a kernel thread will be spawned at the very ++ * end to unregister the debug hooks. ++ */ ++ if (fork_test) { ++ repeat_test = fork_test; ++ printk(KERN_INFO "kgdbts:RUN do_fork for %i breakpoints\n", ++ repeat_test); ++ kthread_run(kgdbts_unreg_thread, 0, "kgdbts_unreg"); ++ run_do_fork_test(); ++ return; ++ } ++ ++ /* If the sys_open test is run it will be the last test that is ++ * executed because a kernel thread will be spawned at the very ++ * end to unregister the debug hooks. ++ */ ++ if (sys_open_test) { ++ repeat_test = sys_open_test; ++ printk(KERN_INFO "kgdbts:RUN sys_open for %i breakpoints\n", ++ repeat_test); ++ kthread_run(kgdbts_unreg_thread, 0, "kgdbts_unreg"); ++ run_sys_open_test(); ++ return; ++ } ++ /* Shutdown and unregister */ ++ kgdb_unregister_io_module(&kgdbts_io_ops); ++ configured = 0; ++} ++ ++static int kgdbts_option_setup(char *opt) ++{ ++ if (strlen(opt) > MAX_CONFIG_LEN) { ++ printk(KERN_ERR "kgdbts: config string too long\n"); ++ return -ENOSPC; ++ } ++ strcpy(config, opt); ++ ++ verbose = 0; ++ if (strstr(config, "V1")) ++ verbose = 1; ++ if (strstr(config, "V2")) ++ verbose = 2; ++ ++ return 0; ++} ++ ++__setup("kgdbts=", kgdbts_option_setup); ++ ++static int configure_kgdbts(void) ++{ ++ int err = 0; ++ ++ if (!strlen(config) || isspace(config[0])) ++ goto noconfig; ++ err = kgdbts_option_setup(config); ++ if (err) ++ goto noconfig; ++ ++ final_ack = 0; ++ run_plant_and_detach_test(1); ++ ++ err = kgdb_register_io_module(&kgdbts_io_ops); ++ if (err) { ++ configured = 0; ++ return err; ++ } ++ configured = 1; ++ kgdbts_run_tests(); ++ ++ return err; ++ ++noconfig: ++ config[0] = 0; ++ configured = 0; ++ ++ return err; ++} ++ ++static int __init init_kgdbts(void) ++{ ++ /* Already configured? */ ++ if (configured == 1) ++ return 0; ++ ++ return configure_kgdbts(); ++} ++ ++static void cleanup_kgdbts(void) ++{ ++ if (configured == 1) ++ kgdb_unregister_io_module(&kgdbts_io_ops); ++} ++ ++static int kgdbts_get_char(void) ++{ ++ int val = 0; ++ ++ if (ts.run_test) ++ val = ts.run_test(1, 0); ++ ++ return val; ++} ++ ++static void kgdbts_put_char(u8 chr) ++{ ++ if (ts.run_test) ++ ts.run_test(0, chr); ++} ++ ++static int param_set_kgdbts_var(const char *kmessage, struct kernel_param *kp) ++{ ++ int len = strlen(kmessage); ++ ++ if (len >= MAX_CONFIG_LEN) { ++ printk(KERN_ERR "kgdbts: config string too long\n"); ++ return -ENOSPC; ++ } ++ ++ /* Only copy in the string if the init function has not run yet */ ++ if (configured < 0) { ++ strcpy(config, kmessage); ++ return 0; ++ } ++ ++ if (kgdb_connected) { ++ printk(KERN_ERR ++ "kgdbts: Cannot reconfigure while KGDB is connected.\n"); ++ ++ return -EBUSY; ++ } ++ ++ strcpy(config, kmessage); ++ /* Chop out \n char as a result of echo */ ++ if (config[len - 1] == '\n') ++ config[len - 1] = '\0'; ++ ++ if (configured == 1) ++ cleanup_kgdbts(); ++ ++ /* Go and configure with the new params. */ ++ return configure_kgdbts(); ++} ++ ++static void kgdbts_pre_exp_handler(void) ++{ ++ /* Increment the module count when the debugger is active */ ++ if (!kgdb_connected) ++ try_module_get(THIS_MODULE); ++} ++ ++static void kgdbts_post_exp_handler(void) ++{ ++ /* decrement the module count when the debugger detaches */ ++ if (!kgdb_connected) ++ module_put(THIS_MODULE); ++} ++ ++static struct kgdb_io kgdbts_io_ops = { ++ .name = "kgdbts", ++ .read_char = kgdbts_get_char, ++ .write_char = kgdbts_put_char, ++ .pre_exception = kgdbts_pre_exp_handler, ++ .post_exception = kgdbts_post_exp_handler, ++}; ++ ++module_init(init_kgdbts); ++module_exit(cleanup_kgdbts); ++module_param_call(kgdbts, param_set_kgdbts_var, param_get_string, &kps, 0644); ++MODULE_PARM_DESC(kgdbts, "[F#|S#][N#]"); ++MODULE_DESCRIPTION("KGDB Test Suite"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Wind River Systems, Inc."); ++ +diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb +index 9631ba3..aaabcdd 100644 +--- a/lib/Kconfig.kgdb ++++ b/lib/Kconfig.kgdb +@@ -25,3 +25,16 @@ config KGDB_SERIAL_CONSOLE + help + Share a serial console with kgdb. Sysrq-g must be used + to break in initially. ++ ++config KGDB_TESTS ++ bool "KGDB: internal test suite" ++ depends on KGDB ++ default n ++ help ++ This is a kgdb I/O module specifically designed to test ++ kgdb's internal functions. This kgdb I/O module is ++ intended to for the development of new kgdb stubs ++ as well as regression testing the kgdb internals. ++ See the drivers/misc/kgdbts.c for the details about ++ the tests. The most basic of this I/O module is to boot ++ a kernel boot arguments "kgdbwait kgdbts=V1F100" +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0051-Revert-Turn-off-the-Belmont-80-wire-ATA-detection.patch +++ linux-2.6.24/patches/0051-Revert-Turn-off-the-Belmont-80-wire-ATA-detection.patch @@ -0,0 +1,26 @@ +From b16c02c4eb129569838442c407ee684375099e54 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Thu, 14 Aug 2008 14:46:33 -0400 +Subject: [PATCH 051/170] Revert "Turn off the Belmont 80-wire ATA detection" + +This reverts commit 35bb3de7757c4d6dda09c598e60635e2dbe8f0e5. +--- + drivers/ata/ata_piix.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c +index ff2c79c..72dca47 100644 +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -703,7 +703,7 @@ static const struct ich_laptop ich_laptop[] = { + { 0x24CA, 0x1025, 0x003d }, /* ICH4 on Acer TM290 */ + { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ + { 0x811a, 0x8086, 0x8119 }, /* SCH on Chelsea */ +- /* { 0x27DF, 0x1028, 0x02b0 }, ICH7 on Belmont */ ++ { 0x27DF, 0x1028, 0x02b0 }, /* ICH7 on Belmont */ + /* end marker */ + { 0, } + }; +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0082-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook1.patch +++ linux-2.6.24/patches/0082-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook1.patch @@ -0,0 +1,30 @@ +From 4a2ef82586eeeeb5e84bad31cff7cd97d6e94f20 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 9 Dec 2008 14:08:10 -0800 +Subject: [PATCH 082/170] UBUNTU: NBK-Ubuntu-2.6.24-22.45netbook1 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index aed7438..bb9f17e 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-22.45netbook1) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * Merge with Hardy kernel ++ ++ -- Michael Frey Tue, 09 Dec 2008 14:05:30 -0800 ++ + linux (2.6.24-19.41netbook13) hardy; urgency=low + + [Upstream Kernel Changes] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0165-UBUNTU-NBK-Ubuntu-2.6.24-24.59netbook02.patch +++ linux-2.6.24/patches/0165-UBUNTU-NBK-Ubuntu-2.6.24-24.59netbook02.patch @@ -0,0 +1,29 @@ +From 743879f2e6b6c463a40321d7f7ec9fb572208b73 Mon Sep 17 00:00:00 2001 +From: Steve Conklin +Date: Fri, 11 Sep 2009 12:12:33 -0500 +Subject: [PATCH 165/170] UBUNTU: NBK-Ubuntu-2.6.24-24.59netbook02 + +Signed-off-by: Steve Conklin +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 471f0e6..9cd035d 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-24.59netbook02) netbook-common; urgency=low ++ ++ [Steve Conklin] ++ ++ * Add back missing .mk files so fdr clean will work ++ ++ -- sconklin Fri, 11 Sep 2009 17:04:14 +0000 ++ + linux (2.6.24-24.59netbook01) netbook-common; urgency=low + + [Andy Whitcroft] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0169-UBUNTU-NBK-Ubuntu-2.6.24-27.65netbook01.patch +++ linux-2.6.24/patches/0169-UBUNTU-NBK-Ubuntu-2.6.24-27.65netbook01.patch @@ -0,0 +1,29 @@ +From 1bd453c8f077188ea49541889f69a55b3acd1aeb Mon Sep 17 00:00:00 2001 +From: Leann Ogasawara +Date: Thu, 4 Feb 2010 15:05:39 -0800 +Subject: [PATCH 169/170] UBUNTU: NBK-Ubuntu-2.6.24-27.65netbook01 + +Signed-off-by: Leann Ogasawara +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 24ca475..5025b07 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-27.65netbook01) netbook-common; urgency=low ++ ++ [Leann Ogasawara] ++ ++ * Rebase onto Ubuntu-2.6.24-27.65 security release ++ ++ -- Leann Ogasawara Thu, 04 Feb 2010 15:03:51 -0800 ++ + linux (2.6.24-25.62netbook02) netbook-common; urgency=low + + [Steve Conklin] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0153-UBUNTU-NBK-Ubuntu-2.6.24-24.54netbook01.patch +++ linux-2.6.24/patches/0153-UBUNTU-NBK-Ubuntu-2.6.24-24.54netbook01.patch @@ -0,0 +1,77 @@ +From 157b714863f380d32a344195c2dff0bb2bc7f15f Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Mon, 15 Jun 2009 17:16:28 +0100 +Subject: [PATCH 153/170] UBUNTU: NBK-Ubuntu-2.6.24-24.54netbook01 + +Signed-off-by: Andy Whitcroft +--- + debian/changelog | 48 +++++++++++++++++++++++++++++++++++++++++++----- + 1 files changed, 43 insertions(+), 5 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index ca7d190..dffbc61 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,8 +1,46 @@ +-linux (2.6.24-24.54netboot01) UNRELEASED; urgency=low ++linux (2.6.24-24.54netboot01) netboot-common; urgency=low + +- CHANGELOG: Do not edit directly. Autogenerated at release. +- CHANGELOG: Use the printchanges target to see the curent changes. +- CHANGELOG: Use the insertchanges target to create the final log. ++ [ Andy Whitcroft ] ++ ++ * rebase onto Ubuntu-2.6.24-24.54 (details below) ++ ++ [Andy Whitcroft] ++ ++ * SAUCE: do not make sysdev links for processors which are not booted ++ - LP: #295091 ++ ++ [Brad Figg] ++ ++ * [Hardy SRU][SAUCE]Add information to recognize Toshiba Satellite Pro ++ M10 Alps Touchpad ++ - LP: #330885 ++ * SAUCE: Add signatures to airprime driver to support newer Novatel ++ devices ++ - LP: #365291 ++ ++ [Stefan Bader] ++ ++ * SAUCE: vgacon: Return the upper half of 512 character fonts ++ - LP: #355057 ++ * Ubuntu-2.6.24-24.54 ++ ++ [Upstream Kernel Changes] ++ ++ * SUNRPC: Fix autobind on cloned rpc clients ++ - LP: #341783, #212485 ++ * Input: atkbd - mark keyboard as disabled when suspending/unloading ++ - LP: #213988 ++ * x86: mtrr: don't modify RdDram/WrDram bits of fixed MTRRs ++ - LP: #292619 ++ * sis190: add identifier for Atheros AR8021 PHY ++ - LP: #247889 ++ * bluetooth hid: enable quirk handling for Apple Wireless Keyboards in ++ 2.6.24 ++ - LP: #227501 ++ * nfsd: move callback rpc_client creation into separate thread ++ - LP: #253004 ++ * nfsd4: probe callback channel only once ++ - LP: #253004 + + -- Andy Whitcroft Mon, 15 Jun 2009 17:14:24 +0100 + +@@ -10,7 +48,7 @@ linux (2.6.24-24.53netbook01) netbook-common; urgency=low + + * Now that the rebase is finished, remove the whitespace correction + * This branch has been rebased onto the hardy distro release +- Ubuntu-2.6.24-24.53 ++ Ubuntu-2.6.24-24.53 + + -- Steve Conklin Thu, 07 May 2009 19:23:35 +0000 + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0054-UBUNTU-NBK-Ubuntu-2.6.24-19.36netbook3.patch +++ linux-2.6.24/patches/0054-UBUNTU-NBK-Ubuntu-2.6.24-19.36netbook3.patch @@ -0,0 +1,31 @@ +From 6a1614c8942623715c9e048f23b8a1d38522b207 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Thu, 28 Aug 2008 13:37:41 -0400 +Subject: [PATCH 054/170] UBUNTU: NBK-Ubuntu-2.6.24-19.36netbook3 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 9 +++++++++ + 1 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 58e0df3..c30a7fc 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,12 @@ ++linux (2.6.24-19.36netbook3) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * Build ehci_hcd as a module ++ * Modified ata_piix.c to add proper PCI ID for Chelsea ata controller ++ ++ -- Michael Frey Wed, 27 Aug 2008 11:07:18 -0400 ++ + linux (2.6.24-19.36netbook2) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0101-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook8.patch +++ linux-2.6.24/patches/0101-UBUNTU-NBK-Ubuntu-2.6.24-22.45netbook8.patch @@ -0,0 +1,24 @@ +From 3cd3e64a957747fc1e002896154397214f6664bb Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 25 Mar 2009 13:25:05 -0400 +Subject: [PATCH 101/170] UBUNTU: NBK-Ubuntu-2.6.24-22.45netbook8 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 2498be0..cccfca7 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,4 +1,4 @@ +-linux (2.6.24-22.45netbook7) netbook-common; urgency=low ++linux (2.6.24-22.45netbook8) netbook-common; urgency=low + + [Michael Frey] + +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0140-Support-the-case-when-headset-falls-back-to-SCO-link.patch +++ linux-2.6.24/patches/0140-Support-the-case-when-headset-falls-back-to-SCO-link.patch @@ -0,0 +1,43 @@ +From ceb6e6de9eebb78f9d98ace75de10aa4e79a67a3 Mon Sep 17 00:00:00 2001 +From: Marcel Holtmann +Date: Mon, 20 Apr 2009 15:59:17 -0400 +Subject: [PATCH 140/170] Support the case when headset falls back to SCO link + +When trying to establish an eSCO link between two devices then it can +happen that the remote device falls back to a SCO link. Currently this +case is not handled correctly and the message dispatching will break +since it is looking for eSCO packets. So in case the configured link +falls back to SCO overwrite the link type with the correct value. + +Signed-off-by: Marcel Holtmann +Signed-off-by: Andres Salomon +--- + net/bluetooth/hci_event.c | 12 ++++++++++-- + 1 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 46df2e4..3361373 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -1313,8 +1313,16 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); +- if (!conn) +- goto unlock; ++ if (!conn) { ++ if (ev->link_type == ESCO_LINK) ++ goto unlock; ++ ++ conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr); ++ if (!conn) ++ goto unlock; ++ ++ conn->type = SCO_LINK; ++ } + + if (!ev->status) { + conn->handle = __le16_to_cpu(ev->handle); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0079-Added-support-for-Ericsson-USB-3G-modem.patch +++ linux-2.6.24/patches/0079-Added-support-for-Ericsson-USB-3G-modem.patch @@ -0,0 +1,2414 @@ +From f8e40fb5e3dd372ae0694f98d354acf76d1e6bf4 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Fri, 21 Nov 2008 14:53:54 -0500 +Subject: [PATCH 079/170] Added support for Ericsson USB 3G modem + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/net/usb/Kconfig | 16 + + drivers/net/usb/Makefile | 1 + + drivers/net/usb/mbm.c | 375 +++++++++++++++++++ + drivers/net/usb/usbnet.c | 153 +++++++- + drivers/net/usb/usbnet.h | 9 +- + drivers/usb/class/Kconfig | 11 + + drivers/usb/class/Makefile | 1 + + drivers/usb/class/cdc-acm.c | 313 +++++++++++++---- + drivers/usb/class/cdc-acm.h | 14 +- + drivers/usb/class/cdc-wdm.c | 843 +++++++++++++++++++++++++++++++++++++++++++ + include/linux/usb/cdc.h | 29 +- + 11 files changed, 1665 insertions(+), 100 deletions(-) + create mode 100644 drivers/net/usb/mbm.c + create mode 100644 drivers/usb/class/cdc-wdm.c + +diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig +index a12c9c4..bfe053d 100644 +--- a/drivers/net/usb/Kconfig ++++ b/drivers/net/usb/Kconfig +@@ -327,5 +327,21 @@ config USB_NET_ZAURUS + really need this non-conformant variant of CDC Ethernet (or in + some cases CDC MDLM) protocol, not "g_ether". + ++config USB_NET_MBM ++ tristate "Ericsson Mobile Broadband Module" ++ depends on USB_USBNET ++ select USB_NET_CDCETHER ++ default y ++ help ++ Choose this option to support Mobile Broadband devices from ++ Ericsson MBM, Mobile Broadband Module. ++ This driver should work with at least the following devices: ++ * Ericsson Mobile Broadband Minicard ++ * Ericsson F3507g Wireless Module ++ * Dell Wireless 5530 HSPA ++ * Toshiba F3507g ++ * Sony Ericsson EC400 ++ * Sony Ericsson MD400 ++ + + endmenu +diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile +index 595a539..51c28f8 100644 +--- a/drivers/net/usb/Makefile ++++ b/drivers/net/usb/Makefile +@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_NET_PLUSB) += plusb.o + obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o + obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o + obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o ++obj-$(CONFIG_USB_NET_MBM) += mbm.o + obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o + obj-$(CONFIG_USB_USBNET) += usbnet.o + +diff --git a/drivers/net/usb/mbm.c b/drivers/net/usb/mbm.c +new file mode 100644 +index 0000000..20ad486 +--- /dev/null ++++ b/drivers/net/usb/mbm.c +@@ -0,0 +1,375 @@ ++/* -*- linux-c -*- ++ * Copyright (C) 2008 Carl Nordbeck ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "usbnet.h" ++ ++#define DRIVER_VERSION "0.03" ++ ++/* Bogus speed for bugy HSPA modems */ ++#define TX_LINK_SPEED 0x001E8480 /* 2.0 Mbps */ ++#define RX_LINK_SPEED 0x006DDD00 /* 7.2 Mbps */ ++#define FIX_SPEED 0x00989680 /* 10.0 Mbps */ ++ ++struct mbm_data { ++ unsigned int rx_speed; ++ unsigned int tx_speed; ++ unsigned int connect; ++}; ++ ++static const u8 mbm_guid[16] = { ++ 0xa3, 0x17, 0xa8, 0x8b, 0x04, 0x5e, 0x4f, 0x01, ++ 0xa6, 0x07, 0xc0, 0xff, 0xcb, 0x7e, 0x39, 0x2a, ++}; ++static void dumpspeed(struct usbnet *dev, __le32 * speeds) ++{ ++ struct mbm_data *data = (void *)&dev->data; ++ ++ data->rx_speed = __le32_to_cpu(speeds[0]); ++ data->tx_speed = __le32_to_cpu(speeds[1]); ++ ++ if (data->rx_speed == FIX_SPEED && data->tx_speed == FIX_SPEED) { ++/* Bogus speed for buggy HSPA modems */ ++ dev_info(&dev->udev->dev, ++ "link speeds: %u kbps RX, %u kbps TX\n", ++ RX_LINK_SPEED / 1000, TX_LINK_SPEED / 1000); ++ ++ data->rx_speed = RX_LINK_SPEED; ++ data->tx_speed = TX_LINK_SPEED; ++ } else ++ dev_info(&dev->udev->dev, ++ "link speeds: %u kbps RX, %u kbps TX\n", ++ __le32_to_cpu(speeds[0]) / 1000, ++ __le32_to_cpu(speeds[1]) / 1000); ++} ++ ++static void mbm_status(struct usbnet *dev, struct urb *urb) ++{ ++ struct mbm_data *data = (void *)&dev->data; ++ struct usb_cdc_notification *event; ++ ++ if (urb->actual_length < sizeof *event) ++ return; ++ ++ /* SPEED_CHANGE can get split into two 8-byte packets */ ++ if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) { ++ dumpspeed(dev, (__le32 *) urb->transfer_buffer); ++ return; ++ } ++ ++ event = urb->transfer_buffer; ++ switch (event->bNotificationType) { ++ case USB_CDC_NOTIFY_NETWORK_CONNECTION: ++ data->connect = event->wValue; ++ if (netif_msg_timer(dev)) ++ dev_dbg(&dev->udev->dev, "CDC: carrier %s\n", ++ data->connect ? "on" : "off"); ++ if (event->wValue) ++ netif_carrier_on(dev->net); ++ else ++ netif_carrier_off(dev->net); ++ break; ++ case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */ ++ if (netif_msg_timer(dev)) ++ dev_dbg(&dev->udev->dev, "CDC: speed change (len %d)\n", ++ urb->actual_length); ++ if (urb->actual_length != (sizeof *event + 8)) ++ set_bit(EVENT_STS_SPLIT, &dev->flags); ++ else ++ dumpspeed(dev, (__le32 *) & event[1]); ++ break; ++ default: ++ dev_err(&dev->udev->dev, "CDC: unexpected notification %02x!\n", ++ event->bNotificationType); ++ break; ++ } ++} ++ ++static u8 nibble(unsigned char c) ++{ ++ if (likely(isdigit(c))) ++ return c - '0'; ++ c = toupper(c); ++ if (likely(isxdigit(c))) ++ return 10 + c - 'A'; ++ return 0; ++} ++ ++static inline int ++get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e) ++{ ++ int tmp, i; ++ unsigned char buf[13]; ++ ++ tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf); ++ if (tmp != 12) { ++ dev_dbg(&dev->udev->dev, ++ "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp); ++ if (tmp >= 0) ++ tmp = -EINVAL; ++ return tmp; ++ } ++ for (i = tmp = 0; i < 6; i++, tmp += 2) ++ dev->net->dev_addr[i] = ++ (nibble(buf[tmp]) << 4) + nibble(buf[tmp + 1]); ++ return 0; ++} ++ ++static void mbm_get_drvinfo(struct net_device *net, ++ struct ethtool_drvinfo *info) ++{ ++ struct usbnet *dev = netdev_priv(net); ++ ++ strncpy(info->driver, dev->driver_name, sizeof info->driver); ++ strncpy(info->version, DRIVER_VERSION, sizeof info->version); ++ strncpy(info->fw_version, dev->driver_info->description, ++ sizeof info->fw_version); ++ usb_make_path(dev->udev, info->bus_info, sizeof info->bus_info); ++} ++ ++static struct ethtool_ops mbm_ethtool_ops = { ++ .get_drvinfo = mbm_get_drvinfo, ++ .get_link = usbnet_get_link, ++ .get_msglevel = usbnet_get_msglevel, ++ .set_msglevel = usbnet_set_msglevel, ++ .get_settings = usbnet_get_settings, ++ .set_settings = usbnet_set_settings, ++ .nway_reset = usbnet_nway_reset, ++}; ++ ++static int mbm_check_connect(struct usbnet *dev) ++{ ++ struct mbm_data *data = (void *)&dev->data; ++ ++ return !data->connect; ++} ++ ++static int mbm_bind(struct usbnet *dev, struct usb_interface *intf) ++{ ++ struct cdc_state *info = (void *)&dev->data; ++ struct usb_driver *driver = driver_of(intf); ++ struct usb_interface_descriptor *d = NULL; ++ struct usb_cdc_mdlm_desc *desc = NULL; ++ struct usb_cdc_mdlm_detail_desc *detail = NULL; ++ struct mbm_data *data = NULL; ++ ++ u8 *buf = intf->cur_altsetting->extra; ++ int len = intf->cur_altsetting->extralen; ++ int status; ++ ++ memset(info, 0, sizeof *info); ++ info->control = intf; ++ while (len > 3) { ++ if (buf[1] != USB_DT_CS_INTERFACE) ++ goto next_desc; ++ ++ switch (buf[2]) { ++ case USB_CDC_MDLM_TYPE: ++ if (info->header) ++ goto bad_desc; ++ ++ desc = (void *)buf; ++ ++ if (desc->bLength != sizeof *desc) ++ goto bad_desc; ++ ++ if (memcmp(&desc->bGUID, mbm_guid, 16)) ++ goto bad_desc; ++ break; ++ case USB_CDC_MDLM_DETAIL_TYPE: ++ if (detail) ++ goto bad_desc; ++ ++ detail = (void *)buf; ++ ++ if (detail->bGuidDescriptorType == 0) { ++ if (detail->bLength < (sizeof *detail + 1)) ++ goto bad_desc; ++ } ++ break; ++ case USB_CDC_UNION_TYPE: ++ if (info->u) ++ goto bad_desc; ++ ++ info->u = (void *)buf; ++ ++ if (info->u->bLength != sizeof *info->u) ++ goto bad_desc; ++ ++ info->control = usb_ifnum_to_if(dev->udev, ++ info->u-> ++ bMasterInterface0); ++ info->data = ++ usb_ifnum_to_if(dev->udev, ++ info->u->bSlaveInterface0); ++ if (!info->control || !info->data) { ++ dev_dbg(&intf->dev, ++ "master #%u/%p slave #%u/%p\n", ++ info->u->bMasterInterface0, ++ info->control, ++ info->u->bSlaveInterface0, info->data); ++ goto bad_desc; ++ } ++ ++ /* a data interface altsetting does the real i/o */ ++ d = &info->data->cur_altsetting->desc; ++ if (d->bInterfaceClass != USB_CLASS_CDC_DATA) ++ goto bad_desc; ++ break; ++ case USB_CDC_ETHERNET_TYPE: ++ if (info->ether) ++ goto bad_desc; ++ ++ info->ether = (void *)buf; ++ if (info->ether->bLength != sizeof *info->ether) ++ goto bad_desc; ++ dev->hard_mtu = ++ le16_to_cpu(info->ether->wMaxSegmentSize); ++ break; ++ } ++ next_desc: ++ len -= buf[0]; /* bLength */ ++ buf += buf[0]; ++ } ++ ++ if (!desc || !detail) { ++ dev_dbg(&intf->dev, "missing cdc mdlm %s%sdescriptor\n", ++ desc ? "" : "func ", detail ? "" : "detail "); ++ goto bad_desc; ++ } ++ ++ if (!info->u || (!info->ether)) { ++ dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n", ++ info->header ? "" : "header ", ++ info->u ? "" : "union ", info->ether ? "" : "ether "); ++ goto bad_desc; ++ } ++ ++ status = usb_driver_claim_interface(driver, info->data, dev); ++ if (status < 0) { ++ dev_dbg(&intf->dev, "Failed claimin interface\n"); ++ return status; ++ } ++ status = usbnet_get_endpoints(dev, info->data); ++ if (status < 0) { ++ dev_dbg(&intf->dev, "Failed get endpoints\n"); ++ usb_set_intfdata(info->data, NULL); ++ usb_driver_release_interface(driver, info->data); ++ return status; ++ } ++ ++ dev->status = NULL; ++ if (info->control->cur_altsetting->desc.bNumEndpoints == 1) { ++ struct usb_endpoint_descriptor *desc; ++ ++ dev->status = &info->control->cur_altsetting->endpoint[0]; ++ desc = &dev->status->desc; ++ if (!usb_endpoint_is_int_in(desc) ++ || (le16_to_cpu(desc->wMaxPacketSize) ++ < sizeof(struct usb_cdc_notification)) ++ || !desc->bInterval) { ++ dev_dbg(&intf->dev, "bad notification endpoint\n"); ++ dev->status = NULL; ++ } ++ } ++ usb_set_intfdata(intf, data); ++ dev->net->ethtool_ops = &mbm_ethtool_ops; ++ ++ status = get_ethernet_addr(dev, info->ether); ++ if (status < 0) { ++ usb_set_intfdata(info->data, NULL); ++ usb_driver_release_interface(driver_of(intf), info->data); ++ return status; ++ } ++ ++ return 0; ++ ++ bad_desc: ++ dev_info(&dev->udev->dev, "unsupported MDLM descriptors\n"); ++ return -ENODEV; ++} ++ ++static const struct driver_info mbm_info = { ++ .description = "Mobile Broadband Network Device", ++ .flags = FLAG_MBN, ++ .check_connect = mbm_check_connect, ++ .bind = mbm_bind, ++ .unbind = usbnet_cdc_unbind, ++ .status = mbm_status, ++}; ++ ++static const struct usb_device_id products[] = { ++ { ++ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, ++ USB_CDC_PROTO_NONE), ++ .driver_info = (unsigned long)&mbm_info, ++ }, ++ ++ {}, // END ++}; ++ ++MODULE_DEVICE_TABLE(usb, products); ++ ++int mbm_suspend(struct usb_interface *intf, pm_message_t message) ++{ ++ dev_dbg(&intf->dev, "mb%d_suspend\n", intf->minor); ++ return usbnet_suspend(intf, message); ++} ++ ++int mbm_resume(struct usb_interface *intf) ++{ ++ dev_dbg(&intf->dev, "mb%d_resume\n", intf->minor); ++ return usbnet_resume(intf); ++} ++ ++static struct usb_driver usbmbm_driver = { ++ .name = "mb", ++ .id_table = products, ++ .probe = usbnet_probe, ++ .disconnect = usbnet_disconnect, ++ .suspend = mbm_suspend, ++ .resume = mbm_resume, ++ .supports_autosuspend = 1, ++}; ++ ++static int __init usbmbm_init(void) ++{ ++ return usb_register(&usbmbm_driver); ++} ++ ++module_init(usbmbm_init); ++ ++static void __exit usbmbm_exit(void) ++{ ++ usb_deregister(&usbmbm_driver); ++} ++ ++module_exit(usbmbm_exit); ++ ++MODULE_AUTHOR("Carl Nordbeck"); ++MODULE_DESCRIPTION("Ericsson Mobile Broadband"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c +index 8ed1fc5..b620ed3 100644 +--- a/drivers/net/usb/usbnet.c ++++ b/drivers/net/usb/usbnet.c +@@ -41,7 +41,7 @@ + #include + #include + #include +- ++#include + #include "usbnet.h" + + #define DRIVER_VERSION "22-Aug-2005" +@@ -88,6 +88,8 @@ static int msg_level = -1; + module_param (msg_level, int, 0); + MODULE_PARM_DESC (msg_level, "Override default message level"); + ++static void waker(struct work_struct *work); ++ + /*-------------------------------------------------------------------------*/ + + /* handles CDC Ethernet and many other network "bulk data" interfaces */ +@@ -217,7 +219,7 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) + } + EXPORT_SYMBOL_GPL(usbnet_skb_return); + +- ++ + /*------------------------------------------------------------------------- + * + * Network Device Driver (peer link to "Host Device", from USB host) +@@ -326,6 +328,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) + if (netif_running (dev->net) + && netif_device_present (dev->net) + && !test_bit (EVENT_RX_HALT, &dev->flags)) { ++ usb_mark_last_busy(dev->udev); + switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) { + case -EPIPE: + usbnet_defer_kevent (dev, EVENT_RX_HALT); +@@ -497,6 +500,7 @@ static void intr_complete (struct urb *urb) + return; + + memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); ++ usb_mark_last_busy(dev->udev); + status = usb_submit_urb (urb, GFP_ATOMIC); + if (status != 0 && netif_msg_timer (dev)) + deverr(dev, "intr resubmit --> %d", status); +@@ -590,7 +594,10 @@ static int usbnet_stop (struct net_device *net) + dev->flags = 0; + del_timer_sync (&dev->delay); + tasklet_kill (&dev->bh); +- usb_autopm_put_interface(dev->intf); ++ ++ dev->used--; ++ ++ dev->intf->needs_remote_wakeup = 0; + + return 0; + } +@@ -670,6 +677,12 @@ static int usbnet_open (struct net_device *net) + + // delay posting reads until we're fully open + tasklet_schedule (&dev->bh); ++ ++ dev->used++; ++ ++ dev->intf->needs_remote_wakeup = 1; ++ usb_autopm_put_interface(dev->intf); ++ + return retval; + done: + usb_autopm_put_interface(dev->intf); +@@ -922,7 +935,7 @@ static void usbnet_tx_timeout (struct net_device *net) + + /*-------------------------------------------------------------------------*/ + +-static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) ++static int __usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) + { + struct usbnet *dev = netdev_priv(net); + int length; +@@ -956,6 +969,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) + entry->state = tx_start; + entry->length = length; + ++ dev->tx_goingon = 1; + usb_fill_bulk_urb (urb, dev->udev, dev->out, + skb->data, skb->len, tx_complete, skb); + +@@ -973,6 +987,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) + + spin_lock_irqsave (&dev->txq.lock, flags); + ++ usb_mark_last_busy(dev->udev); + switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { + case -EPIPE: + netif_stop_queue (net); +@@ -988,6 +1003,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) + if (dev->txq.qlen >= TX_QLEN (dev)) + netif_stop_queue (net); + } ++ + spin_unlock_irqrestore (&dev->txq.lock, flags); + + if (retval) { +@@ -1003,9 +1019,32 @@ drop: + devdbg (dev, "> tx, len %d, type 0x%x", + length, skb->protocol); + } ++ + return retval; + } + ++static int usbnet_start_xmit(struct sk_buff *skb, struct net_device *net) ++{ ++ struct usbnet *dev = netdev_priv(net); ++ int retval; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->txq.lock, flags); ++ if (dev->suspend_count) { ++ netif_stop_queue(net); ++ dev->tx_skb = skb; ++ if (!schedule_work (&dev->waker)) ++ deverr(dev, "waker may have been dropped"); ++ else ++ devdbg(dev, "waker scheduled"); ++ spin_unlock_irqrestore(&dev->txq.lock, flags); ++ return NET_XMIT_SUCCESS; ++ } ++ spin_unlock_irqrestore(&dev->txq.lock, flags); ++ ++ retval = __usbnet_start_xmit(skb, net); ++ return retval; ++} + + /*-------------------------------------------------------------------------*/ + +@@ -1025,6 +1064,7 @@ static void usbnet_bh (unsigned long param) + rx_process (dev, skb); + continue; + case tx_done: ++ dev->tx_goingon = 0; + case rx_cleanup: + usb_free_urb (entry->urb); + dev_kfree_skb (skb); +@@ -1044,6 +1084,7 @@ static void usbnet_bh (unsigned long param) + } else if (netif_running (dev->net) + && netif_device_present (dev->net) + && !timer_pending (&dev->delay) ++ && !dev->suspend_count + && !test_bit (EVENT_RX_HALT, &dev->flags)) { + int temp = dev->rxq.qlen; + int qlen = RX_QLEN (dev); +@@ -1162,6 +1203,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) + dev->bh.func = usbnet_bh; + dev->bh.data = (unsigned long) dev; + INIT_WORK (&dev->kevent, kevent); ++ INIT_WORK (&dev->waker, waker); + dev->delay.function = usbnet_bh; + dev->delay.data = (unsigned long) dev; + init_timer (&dev->delay); +@@ -1205,6 +1247,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) + && (net->dev_addr [0] & 0x02) == 0) + strcpy (net->name, "eth%d"); + ++ if (dev->driver_info->flags & FLAG_MBN) ++ strcpy (net->name, "mb%d"); ++ + /* maybe the remote can't receive an Ethernet MTU */ + if (net->mtu > (dev->hard_mtu - net->hard_header_len)) + net->mtu = dev->hard_mtu - net->hard_header_len; +@@ -1267,24 +1312,62 @@ EXPORT_SYMBOL_GPL(usbnet_probe); + * resume only when the last interface is resumed + */ + ++static void waker(struct work_struct *work) ++{ ++ struct usbnet *dev = container_of(work, struct usbnet, waker); ++ ++ if (!usb_autopm_get_interface(dev->intf)) { ++ usb_autopm_put_interface(dev->intf); ++ } else { ++ devdbg(dev, "autoresume failed"); ++ } ++} ++ ++static void stop_traffic(struct usbnet *dev) ++{ ++ int temp; ++ DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); ++ DECLARE_WAITQUEUE (wait, current); ++ ++ // ensure there are no more active urbs ++ add_wait_queue (&unlink_wakeup, &wait); ++ dev->wait = &unlink_wakeup; ++ temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq); ++ ++ // maybe wait for deletions to finish. ++ while (!skb_queue_empty(&dev->rxq) ++ && !skb_queue_empty(&dev->txq) ++ && !skb_queue_empty(&dev->done)) { ++ msleep(UNLINK_TIMEOUT_MS); ++ if (netif_msg_ifdown (dev)) ++ devdbg (dev, "waited for %d urb completions", temp); ++ } ++ dev->wait = NULL; ++ remove_wait_queue (&unlink_wakeup, &wait); ++ ++ usb_kill_urb(dev->interrupt); ++} ++ + int usbnet_suspend (struct usb_interface *intf, pm_message_t message) + { + struct usbnet *dev = usb_get_intfdata(intf); + +- if (!dev->suspend_count++) { +- /* +- * accelerate emptying of the rx and queues, to avoid +- * having everything error out. +- */ +- netif_device_detach (dev->net); +- (void) unlink_urbs (dev, &dev->rxq); +- (void) unlink_urbs (dev, &dev->txq); +- /* +- * reattach so runtime management can use and +- * wake the device +- */ +- netif_device_attach (dev->net); ++ if (dev->suspend_count++) ++ return 0; ++ ++ /* check for ongoing tx traffic */ ++ if (dev->tx_goingon && dev->udev->auto_pm) { ++ dev->suspend_count--; ++ return -EBUSY; + } ++ ++ stop_traffic(dev); ++ ++ /* cancel work */ ++ dev->flags = 0; ++ del_timer_sync(&dev->delay); ++ cancel_work_sync(&dev->kevent); ++ + return 0; + } + EXPORT_SYMBOL_GPL(usbnet_suspend); +@@ -1292,9 +1375,41 @@ EXPORT_SYMBOL_GPL(usbnet_suspend); + int usbnet_resume (struct usb_interface *intf) + { + struct usbnet *dev = usb_get_intfdata(intf); ++ int status; ++ ++ devdbg(dev, "%s: begin", __FUNCTION__); ++ ++ if (--dev->suspend_count) ++ return 0; ++ ++ if (dev->used) { ++ status = init_status (dev, dev->intf); ++ if (status) { ++ devdbg(dev, "init_status failed"); ++ return status; ++ } ++ ++ /* start any status interrupt transfer */ ++ if (dev->interrupt) { ++ status = usb_submit_urb (dev->interrupt, GFP_NOIO); ++ if (status < 0) { ++ devdbg(dev, "usb_submit intr urb failed"); ++ return status; ++ } ++ } ++ ++ tasklet_schedule(&dev->bh); ++ ++ /* transmit package that triggered resume */ ++ if (dev->tx_skb) { ++ status = __usbnet_start_xmit(dev->tx_skb, dev->net); ++ dev->tx_skb = NULL; ++ } ++ ++ netif_wake_queue(dev->net); ++ } + +- if (!--dev->suspend_count) +- tasklet_schedule (&dev->bh); ++ devdbg(dev, "%s: end", __FUNCTION__); + + return 0; + } +diff --git a/drivers/net/usb/usbnet.h b/drivers/net/usb/usbnet.h +index 1fae434..9eaccd7 100644 +--- a/drivers/net/usb/usbnet.h ++++ b/drivers/net/usb/usbnet.h +@@ -23,7 +23,6 @@ + #ifndef __USBNET_H + #define __USBNET_H + +- + /* interface from usbnet core to each USB networking link we handle */ + struct usbnet { + /* housekeeping */ +@@ -65,6 +64,12 @@ struct usbnet { + # define EVENT_RX_MEMORY 2 + # define EVENT_STS_SPLIT 3 + # define EVENT_LINK_RESET 4 ++ ++ /* autosuspend helpers */ ++ struct work_struct waker; ++ int used; ++ int tx_goingon; ++ struct sk_buff *tx_skb; /* skb queued during suspend */ + }; + + static inline struct usb_driver *driver_of(struct usb_interface *intf) +@@ -88,6 +93,8 @@ struct driver_info { + + #define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */ + ++#define FLAG_MBN 0x0100 /* use "mb%d" names */ ++ + /* init device ... can sleep, or cause probe() failure */ + int (*bind)(struct usbnet *, struct usb_interface *); + +diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig +index 3a9102d..66f17ed 100644 +--- a/drivers/usb/class/Kconfig ++++ b/drivers/usb/class/Kconfig +@@ -29,3 +29,14 @@ config USB_PRINTER + To compile this driver as a module, choose M here: the + module will be called usblp. + ++config USB_WDM ++ tristate "USB Wireless Device Management support" ++ depends on USB ++ ---help--- ++ This driver supports the WMC Device Management functionality ++ of cell phones compliant to the CDC WMC specification. You can use ++ AT commands over this device. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called cdc-wdm. ++ +diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile +index cc391e6..535d59a 100644 +--- a/drivers/usb/class/Makefile ++++ b/drivers/usb/class/Makefile +@@ -5,3 +5,4 @@ + + obj-$(CONFIG_USB_ACM) += cdc-acm.o + obj-$(CONFIG_USB_PRINTER) += usblp.o ++obj-$(CONFIG_USB_WDM) += cdc-wdm.o +diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c +index a3c2d92..888c298 100644 +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -31,6 +31,7 @@ + * v0.23 - use softirq for rx processing, as needed by tty layer + * v0.24 - change probe method to evaluate CDC union descriptor + * v0.25 - downstream tasks paralelized to maximize throughput ++ * v0.26 - multiple write urbs, writesize increased + */ + + /* +@@ -72,7 +73,7 @@ + /* + * Version Information + */ +-#define DRIVER_VERSION "v0.25" ++#define DRIVER_VERSION "v0.26" + #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek" + #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" + +@@ -118,7 +119,7 @@ static int acm_wb_alloc(struct acm *acm) + int i, wbn; + struct acm_wb *wb; + +- wbn = acm->write_current; ++ wbn = 0; + i = 0; + for (;;) { + wb = &acm->wb[wbn]; +@@ -132,11 +133,6 @@ static int acm_wb_alloc(struct acm *acm) + } + } + +-static void acm_wb_free(struct acm *acm, int wbn) +-{ +- acm->wb[wbn].use = 0; +-} +- + static int acm_wb_is_avail(struct acm *acm) + { + int i, n; +@@ -156,26 +152,44 @@ static inline int acm_wb_is_used(struct acm *acm, int wbn) + /* + * Finish write. + */ +-static void acm_write_done(struct acm *acm) ++static void acm_write_done(struct acm *acm, struct acm_wb *wb) + { + unsigned long flags; +- int wbn; + + spin_lock_irqsave(&acm->write_lock, flags); + acm->write_ready = 1; +- wbn = acm->write_current; +- acm_wb_free(acm, wbn); +- acm->write_current = (wbn + 1) % ACM_NW; ++ wb->use = 0; ++ acm->transmitting--; + spin_unlock_irqrestore(&acm->write_lock, flags); + } + + /* + * Poke write. ++ * ++ * the caller is responsible for locking + */ +-static int acm_write_start(struct acm *acm) ++ ++static int acm_start_wb(struct acm *acm, struct acm_wb *wb) ++{ ++ int rc; ++ ++ acm->transmitting++; ++ ++ wb->urb->transfer_buffer = wb->buf; ++ wb->urb->transfer_dma = wb->dmah; ++ wb->urb->transfer_buffer_length = wb->len; ++ wb->urb->dev = acm->dev; ++ ++ if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) { ++ dbg("usb_submit_urb(write bulk) failed: %d", rc); ++ acm_write_done(acm, wb); ++ } ++ return rc; ++} ++ ++static int acm_write_start(struct acm *acm, int wbn) + { + unsigned long flags; +- int wbn; + struct acm_wb *wb; + int rc; + +@@ -190,26 +204,31 @@ static int acm_write_start(struct acm *acm) + return 0; /* A white lie */ + } + +- wbn = acm->write_current; ++ wb = &acm->wb[wbn]; ++ if(acm_wb_is_avail(acm) <= 1) ++ acm->write_ready = 0; ++ ++ dbg("%s susp_count: %d", __func__, acm->susp_count); ++ if (acm->susp_count) { ++ acm->old_ready = acm->write_ready; ++ acm->delayed_wb = wb; ++ acm->write_ready = 0; ++ schedule_work(&acm->waker); ++ spin_unlock_irqrestore(&acm->write_lock, flags); ++ return 0; /* A white lie */ ++ } ++ usb_mark_last_busy(acm->dev); ++ + if (!acm_wb_is_used(acm, wbn)) { + spin_unlock_irqrestore(&acm->write_lock, flags); + return 0; + } +- wb = &acm->wb[wbn]; + +- acm->write_ready = 0; ++ rc = acm_start_wb(acm, wb); + spin_unlock_irqrestore(&acm->write_lock, flags); + +- acm->writeurb->transfer_buffer = wb->buf; +- acm->writeurb->transfer_dma = wb->dmah; +- acm->writeurb->transfer_buffer_length = wb->len; +- acm->writeurb->dev = acm->dev; +- +- if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) { +- dbg("usb_submit_urb(write bulk) failed: %d", rc); +- acm_write_done(acm); +- } + return rc; ++ + } + /* + * attributes exported through sysfs +@@ -250,6 +269,13 @@ static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL); + * Interrupt handlers for various ACM device responses + */ + ++#ifndef _LINUX_UNALIGNED_ACCESS_OK_H ++static inline u16 get_unaligned_le16(const void *p) ++{ ++ return le16_to_cpup((__le16 *)p); ++} ++#endif ++ + /* control interface reports status changes with "interrupt" transfers */ + static void acm_ctrl_irq(struct urb *urb) + { +@@ -268,10 +294,10 @@ static void acm_ctrl_irq(struct urb *urb) + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ +- dbg("%s - urb shutting down with status: %d", __FUNCTION__, status); ++ dbg("%s - urb shutting down with status: %d", __func__, status); + return; + default: +- dbg("%s - nonzero urb status received: %d", __FUNCTION__, status); ++ dbg("%s - nonzero urb status received: %d", __func__, status); + goto exit; + } + +@@ -312,10 +338,11 @@ static void acm_ctrl_irq(struct urb *urb) + break; + } + exit: ++ usb_mark_last_busy(acm->dev); + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval) + err ("%s - usb_submit_urb failed with result %d", +- __FUNCTION__, retval); ++ __func__, retval); + } + + /* data interface returns incoming bytes, or we got unthrottled */ +@@ -328,8 +355,11 @@ static void acm_read_bulk(struct urb *urb) + + dbg("Entering acm_read_bulk with status %d", status); + +- if (!ACM_READY(acm)) ++ if (!ACM_READY(acm)) { ++ dev_dbg(&acm->data->dev, "Aborting, acm not ready"); + return; ++ } ++ usb_mark_last_busy(acm->dev); + + if (status) + dev_dbg(&acm->data->dev, "bulk rx status %d\n", status); +@@ -339,6 +369,7 @@ static void acm_read_bulk(struct urb *urb) + + if (likely(status == 0)) { + spin_lock(&acm->read_lock); ++ acm->processing++; + list_add_tail(&rcv->list, &acm->spare_read_urbs); + list_add_tail(&buf->list, &acm->filled_read_bufs); + spin_unlock(&acm->read_lock); +@@ -351,7 +382,8 @@ static void acm_read_bulk(struct urb *urb) + /* nevertheless the tasklet must be kicked unconditionally + so the queue cannot dry up */ + } +- tasklet_schedule(&acm->urb_task); ++ if (likely(!acm->susp_count)) ++ tasklet_schedule(&acm->urb_task); + } + + static void acm_rx_tasklet(unsigned long _acm) +@@ -362,16 +394,23 @@ static void acm_rx_tasklet(unsigned long _acm) + struct acm_ru *rcv; + unsigned long flags; + unsigned char throttled; ++ + dbg("Entering acm_rx_tasklet"); + + if (!ACM_READY(acm)) ++ { ++ dbg("acm_rx_tasklet: ACM not ready"); + return; ++ } + + spin_lock_irqsave(&acm->throttle_lock, flags); + throttled = acm->throttle; + spin_unlock_irqrestore(&acm->throttle_lock, flags); + if (throttled) ++ { ++ dbg("acm_rx_tasklet: throttled"); + return; ++ } + + next_buffer: + spin_lock_irqsave(&acm->read_lock, flags); +@@ -411,6 +450,7 @@ urbs: + while (!list_empty(&acm->spare_read_bufs)) { + spin_lock_irqsave(&acm->read_lock, flags); + if (list_empty(&acm->spare_read_urbs)) { ++ acm->processing = 0; + spin_unlock_irqrestore(&acm->read_lock, flags); + return; + } +@@ -433,29 +473,35 @@ urbs: + rcv->urb->transfer_dma = buf->dma; + rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + +- dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf); +- + /* This shouldn't kill the driver as unsuccessful URBs are returned to the + free-urbs-pool and resubmited ASAP */ +- if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { ++ spin_lock_irqsave(&acm->read_lock, flags); ++ if (acm->susp_count || usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { + list_add(&buf->list, &acm->spare_read_bufs); +- spin_lock_irqsave(&acm->read_lock, flags); + list_add(&rcv->list, &acm->spare_read_urbs); ++ acm->processing = 0; + spin_unlock_irqrestore(&acm->read_lock, flags); + return; ++ } else { ++ spin_unlock_irqrestore(&acm->read_lock, flags); ++ dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf); + } + } ++ spin_lock_irqsave(&acm->read_lock, flags); ++ acm->processing = 0; ++ spin_unlock_irqrestore(&acm->read_lock, flags); + } + + /* data interface wrote those outgoing bytes */ + static void acm_write_bulk(struct urb *urb) + { +- struct acm *acm = (struct acm *)urb->context; ++ struct acm *acm; ++ struct acm_wb *wb = urb->context; + + dbg("Entering acm_write_bulk with status %d", urb->status); + +- acm_write_done(acm); +- acm_write_start(acm); ++ acm = wb->instance; ++ acm_write_done(acm, wb); + if (ACM_READY(acm)) + schedule_work(&acm->work); + } +@@ -470,6 +516,27 @@ static void acm_softint(struct work_struct *work) + tty_wakeup(acm->tty); + } + ++static void acm_waker(struct work_struct *waker) ++{ ++ struct acm *acm = container_of(waker, struct acm, waker); ++ long flags; ++ int rv; ++ ++ rv = usb_autopm_get_interface(acm->control); ++ if (rv < 0) { ++ err("Autopm failure in %s", __func__); ++ return; ++ } ++ if (acm->delayed_wb) { ++ acm_start_wb(acm, acm->delayed_wb); ++ acm->delayed_wb = NULL; ++ } ++ spin_lock_irqsave(&acm->write_lock, flags); ++ acm->write_ready = acm->old_ready; ++ spin_unlock_irqrestore(&acm->write_lock, flags); ++ usb_autopm_put_interface(acm->control); ++} ++ + /* + * TTY handlers + */ +@@ -489,6 +556,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) + else + rv = 0; + ++ set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); + tty->driver_data = acm; + acm->tty = tty; + +@@ -496,10 +564,18 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) + otherwise it is scheduled, and with high data rates data can get lost. */ + tty->low_latency = 1; + ++ if (usb_autopm_get_interface(acm->control) < 0) ++ goto early_bail; ++ else ++ acm->control->needs_remote_wakeup = 1; ++ ++ mutex_lock(&acm->mutex); + if (acm->used++) { ++ usb_autopm_put_interface(acm->control); + goto done; + } + ++ + acm->ctrlurb->dev = acm->dev; + if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { + dbg("usb_submit_urb(ctrl irq) failed"); +@@ -509,6 +585,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) + if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && + (acm->ctrl_caps & USB_CDC_CAP_LINE)) + goto full_bailout; ++ usb_autopm_put_interface(acm->control); + + INIT_LIST_HEAD(&acm->spare_read_urbs); + INIT_LIST_HEAD(&acm->spare_read_bufs); +@@ -526,13 +603,17 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) + + done: + err_out: ++ mutex_unlock(&acm->mutex); + mutex_unlock(&open_mutex); + return rv; + + full_bailout: + usb_kill_urb(acm->ctrlurb); + bail_out: ++ usb_autopm_put_interface(acm->control); + acm->used--; ++ mutex_unlock(&acm->mutex); ++early_bail: + mutex_unlock(&open_mutex); + return -EIO; + } +@@ -546,7 +627,8 @@ static void acm_tty_unregister(struct acm *acm) + usb_put_intf(acm->control); + acm_table[acm->minor] = NULL; + usb_free_urb(acm->ctrlurb); +- usb_free_urb(acm->writeurb); ++ for (i = 0; i < ACM_NW; i++) ++ usb_free_urb(acm->wb[i].urb); + for (i = 0; i < nr; i++) + usb_free_urb(acm->ru[i].urb); + kfree(acm->country_codes); +@@ -565,11 +647,15 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) + mutex_lock(&open_mutex); + if (!--acm->used) { + if (acm->dev) { ++ usb_autopm_get_interface(acm->control); + acm_set_control(acm, acm->ctrlout = 0); + usb_kill_urb(acm->ctrlurb); +- usb_kill_urb(acm->writeurb); ++ for (i = 0; i < ACM_NW; i++) ++ usb_kill_urb(acm->wb[i].urb); + for (i = 0; i < nr; i++) + usb_kill_urb(acm->ru[i].urb); ++ acm->control->needs_remote_wakeup = 0; ++ usb_autopm_put_interface(acm->control); + } else + acm_tty_unregister(acm); + } +@@ -594,7 +680,6 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c + spin_lock_irqsave(&acm->write_lock, flags); + if ((wbn = acm_wb_alloc(acm)) < 0) { + spin_unlock_irqrestore(&acm->write_lock, flags); +- acm_write_start(acm); + return 0; + } + wb = &acm->wb[wbn]; +@@ -605,7 +690,7 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c + wb->len = count; + spin_unlock_irqrestore(&acm->write_lock, flags); + +- if ((stat = acm_write_start(acm)) < 0) ++ if ((stat = acm_write_start(acm, wbn)) < 0) + return stat; + return count; + } +@@ -798,7 +883,7 @@ static int acm_probe (struct usb_interface *intf, + { + struct usb_cdc_union_desc *union_header = NULL; + struct usb_cdc_country_functional_desc *cfd = NULL; +- char *buffer = intf->altsetting->extra; ++ unsigned char *buffer = intf->altsetting->extra; + int buflen = intf->altsetting->extralen; + struct usb_interface *control_interface; + struct usb_interface *data_interface; +@@ -875,9 +960,13 @@ static int acm_probe (struct usb_interface *intf, + if ((call_management_function & 3) != 3) + err("This device cannot do calls on its own. It is no modem."); + break; +- + default: +- err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]); ++ /* there are LOTS more CDC descriptors that ++ * could legitimately be found here. ++ */ ++ dev_dbg(&intf->dev, "Ignoring descriptor: " ++ "type %02x, length %d\n", ++ buffer[2], buffer[0]); + break; + } + next_desc: +@@ -904,7 +993,7 @@ next_desc: + } + + if (data_interface_num != call_interface_num) +- dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n"); ++ dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n"); + + skip_normal_probe: + +@@ -965,7 +1054,7 @@ skip_normal_probe: + + ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); + readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2); +- acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize); ++ acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20; + acm->control = control_interface; + acm->data = data_interface; + acm->minor = minor; +@@ -977,9 +1066,11 @@ skip_normal_probe: + acm->urb_task.func = acm_rx_tasklet; + acm->urb_task.data = (unsigned long) acm; + INIT_WORK(&acm->work, acm_softint); ++ INIT_WORK(&acm->waker, acm_waker); + spin_lock_init(&acm->throttle_lock); + spin_lock_init(&acm->write_lock); + spin_lock_init(&acm->read_lock); ++ mutex_init(&acm->mutex); + acm->write_ready = 1; + acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); + +@@ -1019,10 +1110,19 @@ skip_normal_probe: + goto alloc_fail7; + } + } +- acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); +- if (!acm->writeurb) { +- dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n"); +- goto alloc_fail7; ++ for(i = 0; i < ACM_NW; i++) ++ { ++ struct acm_wb *snd = &(acm->wb[i]); ++ ++ if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) { ++ dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)"); ++ goto alloc_fail7; ++ } ++ ++ usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), ++ NULL, acm->writesize, acm_write_bulk, snd); ++ snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ snd->instance = acm; + } + + usb_set_intfdata (intf, acm); +@@ -1058,10 +1158,6 @@ skip_countries: + acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + acm->ctrlurb->transfer_dma = acm->ctrl_dma; + +- usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), +- NULL, acm->writesize, acm_write_bulk, acm); +- acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; +- + dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); + + acm_set_control(acm, acm->ctrlout); +@@ -1079,7 +1175,8 @@ skip_countries: + + return 0; + alloc_fail8: +- usb_free_urb(acm->writeurb); ++ for (i = 0; i < ACM_NW; i++) ++ usb_free_urb(acm->wb[i].urb); + alloc_fail7: + for (i = 0; i < num_rx_buf; i++) + usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); +@@ -1096,6 +1193,25 @@ alloc_fail: + return -ENOMEM; + } + ++static void stop_data_traffic(struct acm *acm) ++{ ++ int i; ++ dbg("Entering stop_data_traffic"); ++ ++ tasklet_disable(&acm->urb_task); ++ ++ usb_kill_urb(acm->ctrlurb); ++ for(i = 0; i < ACM_NW; i++) ++ usb_kill_urb(acm->wb[i].urb); ++ for (i = 0; i < acm->rx_buflimit; i++) ++ usb_kill_urb(acm->ru[i].urb); ++ ++ tasklet_enable(&acm->urb_task); ++ ++ cancel_work_sync(&acm->work); ++ cancel_work_sync(&acm->waker); ++} ++ + static void acm_disconnect(struct usb_interface *intf) + { + struct acm *acm = usb_get_intfdata(intf); +@@ -1123,19 +1239,7 @@ static void acm_disconnect(struct usb_interface *intf) + usb_set_intfdata(acm->control, NULL); + usb_set_intfdata(acm->data, NULL); + +- tasklet_disable(&acm->urb_task); +- +- usb_kill_urb(acm->ctrlurb); +- usb_kill_urb(acm->writeurb); +- for (i = 0; i < acm->rx_buflimit; i++) +- usb_kill_urb(acm->ru[i].urb); +- +- INIT_LIST_HEAD(&acm->filled_read_bufs); +- INIT_LIST_HEAD(&acm->spare_read_bufs); +- +- tasklet_enable(&acm->urb_task); +- +- flush_scheduled_work(); /* wait for acm_softint */ ++ stop_data_traffic(acm); + + acm_write_buffers_free(acm); + usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); +@@ -1156,6 +1260,71 @@ static void acm_disconnect(struct usb_interface *intf) + tty_hangup(acm->tty); + } + ++static int acm_suspend(struct usb_interface *intf, pm_message_t message) ++{ ++ struct acm *acm = usb_get_intfdata(intf); ++ int cnt; ++ ++ if (acm->dev->auto_pm) { ++ int b; ++ ++ spin_lock_irq(&acm->read_lock); ++ spin_lock(&acm->write_lock); ++ b = acm->processing + acm->transmitting; ++ spin_unlock(&acm->write_lock); ++ spin_unlock_irq(&acm->read_lock); ++ if (b) ++ return -EBUSY; ++ } ++ ++ spin_lock_irq(&acm->read_lock); ++ spin_lock(&acm->write_lock); ++ cnt = acm->susp_count++; ++ spin_unlock(&acm->write_lock); ++ spin_unlock_irq(&acm->read_lock); ++ ++ if (cnt) ++ return 0; ++ /* ++ we treat opened interfaces differently, ++ we must guard against open ++ */ ++ mutex_lock(&acm->mutex); ++ ++ if (acm->used) ++ stop_data_traffic(acm); ++ ++ mutex_unlock(&acm->mutex); ++ return 0; ++} ++ ++static int acm_resume(struct usb_interface *intf) ++{ ++ struct acm *acm = usb_get_intfdata(intf); ++ int rv = 0; ++ int cnt; ++ ++ spin_lock_irq(&acm->read_lock); ++ acm->susp_count -= 1; ++ cnt = acm->susp_count; ++ spin_unlock_irq(&acm->read_lock); ++ ++ if (cnt) ++ return 0; ++ ++ mutex_lock(&acm->mutex); ++ if (acm->used) { ++ rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); ++ if (rv < 0) ++ goto err_out; ++ ++ tasklet_schedule(&acm->urb_task); ++ } ++ ++err_out: ++ mutex_unlock(&acm->mutex); ++ return rv; ++} + /* + * USB driver structure. + */ +@@ -1186,6 +1355,9 @@ static struct usb_device_id acm_ids[] = { + { USB_DEVICE(0x0e8d,0x0003), /* MediaTek Inc MT6227 */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, ++ { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */ ++ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ ++ }, + + /* control interfaces with various AT-command sets */ + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, +@@ -1211,7 +1383,10 @@ static struct usb_driver acm_driver = { + .name = "cdc_acm", + .probe = acm_probe, + .disconnect = acm_disconnect, ++ .suspend = acm_suspend, ++ .resume = acm_resume, + .id_table = acm_ids, ++ .supports_autosuspend = 1, + }; + + /* +diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h +index 09f7765..85c3aaa 100644 +--- a/drivers/usb/class/cdc-acm.h ++++ b/drivers/usb/class/cdc-acm.h +@@ -59,7 +59,7 @@ + * when processing onlcr, so we only need 2 buffers. These values must be + * powers of 2. + */ +-#define ACM_NW 2 ++#define ACM_NW 16 + #define ACM_NR 16 + + struct acm_wb { +@@ -67,6 +67,8 @@ struct acm_wb { + dma_addr_t dmah; + int len; + int use; ++ struct urb *urb; ++ struct acm *instance; + }; + + struct acm_rb { +@@ -88,7 +90,7 @@ struct acm { + struct usb_interface *control; /* control interface */ + struct usb_interface *data; /* data interface */ + struct tty_struct *tty; /* the corresponding tty */ +- struct urb *ctrlurb, *writeurb; /* urbs */ ++ struct urb *ctrlurb; /* urbs */ + u8 *ctrl_buffer; /* buffers of urbs */ + dma_addr_t ctrl_dma; /* dma handles of buffers */ + u8 *country_codes; /* country codes from device */ +@@ -103,12 +105,16 @@ struct acm { + struct list_head spare_read_urbs; + struct list_head spare_read_bufs; + struct list_head filled_read_bufs; +- int write_current; /* current write buffer */ + int write_used; /* number of non-empty write buffers */ + int write_ready; /* write urb is not running */ ++ int old_ready; ++ int processing; ++ int transmitting; + spinlock_t write_lock; ++ struct mutex mutex; + struct usb_cdc_line_coding line; /* bits, stop, parity */ + struct work_struct work; /* work queue entry for line discipline waking up */ ++ struct work_struct waker; + struct tasklet_struct urb_task; /* rx processing */ + spinlock_t throttle_lock; /* synchronize throtteling and read callback */ + unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ +@@ -120,6 +126,8 @@ struct acm { + unsigned char throttle; /* throttled by tty layer */ + unsigned char clocal; /* termios CLOCAL */ + unsigned int ctrl_caps; /* control capabilities from the class specific header */ ++ unsigned int susp_count; /* number of suspended interfaces */ ++ struct acm_wb *delayed_wb; /* write queued for a device about to be woken */ + }; + + #define CDC_DATA_INTERFACE_TYPE 0x0a +diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c +new file mode 100644 +index 0000000..7e8e123 +--- /dev/null ++++ b/drivers/usb/class/cdc-wdm.c +@@ -0,0 +1,843 @@ ++/* ++ * cdc-wdm.c ++ * ++ * This driver supports USB CDC WCM Device Management. ++ * ++ * Copyright (c) 2007-2008 Oliver Neukum ++ * ++ * Some code taken from cdc-acm.c ++ * ++ * Released under the GPLv2. ++ * ++ * Many thanks to Carl Nordbeck ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Version Information ++ */ ++#define DRIVER_VERSION "v0.03" ++#define DRIVER_AUTHOR "Oliver Neukum" ++#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management" ++ ++static struct usb_device_id wdm_ids[] = { ++ { ++ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | ++ USB_DEVICE_ID_MATCH_INT_SUBCLASS, ++ .bInterfaceClass = USB_CLASS_COMM, ++ .bInterfaceSubClass = USB_CDC_SUBCLASS_DMM ++ }, ++ { } ++}; ++ ++#define WDM_MINOR_BASE 176 ++ ++ ++#define WDM_IN_USE 1 ++#define WDM_DISCONNECTING 2 ++#define WDM_RESULT 3 ++#define WDM_READ 4 ++#define WDM_INT_STALL 5 ++#define WDM_POLL_RUNNING 6 ++ ++ ++#define WDM_MAX 16 ++ ++ ++static DEFINE_MUTEX(wdm_mutex); ++ ++/* --- method tables --- */ ++ ++struct wdm_device { ++ u8 *inbuf; /* buffer for response */ ++ u8 *outbuf; /* buffer for command */ ++ u8 *sbuf; /* buffer for status */ ++ u8 *ubuf; /* buffer for copy to user space */ ++ ++ struct urb *command; ++ struct urb *response; ++ struct urb *validity; ++ struct usb_interface *intf; ++ struct usb_ctrlrequest *orq; ++ struct usb_ctrlrequest *irq; ++ spinlock_t iuspin; ++ ++ unsigned long flags; ++ u16 bufsize; ++ u16 wMaxCommand; ++ u16 wMaxPacketSize; ++ u16 bMaxPacketSize0; ++ __le16 inum; ++ int reslength; ++ int length; ++ int read; ++ int count; ++ dma_addr_t shandle; ++ dma_addr_t ihandle; ++ struct mutex wlock; ++ struct mutex rlock; ++ struct mutex plock; ++ wait_queue_head_t wait; ++ struct work_struct rxwork; ++ int werr; ++ int rerr; ++}; ++ ++static struct usb_driver wdm_driver; ++ ++/* --- callbacks --- */ ++static void wdm_out_callback(struct urb *urb) ++{ ++ struct wdm_device *desc; ++ desc = urb->context; ++ spin_lock(&desc->iuspin); ++ desc->werr = urb->status; ++ spin_unlock(&desc->iuspin); ++ clear_bit(WDM_IN_USE, &desc->flags); ++ kfree(desc->outbuf); ++ wake_up(&desc->wait); ++} ++ ++static void wdm_in_callback(struct urb *urb) ++{ ++ struct wdm_device *desc = urb->context; ++ int status = urb->status; ++ ++ spin_lock(&desc->iuspin); ++ ++ if (status) { ++ switch (status) { ++ case -ENOENT: ++ dev_dbg(&desc->intf->dev, ++ "nonzero urb status received: -ENOENT"); ++ break; ++ case -ECONNRESET: ++ dev_dbg(&desc->intf->dev, ++ "nonzero urb status received: -ECONNRESET"); ++ break; ++ case -ESHUTDOWN: ++ dev_dbg(&desc->intf->dev, ++ "nonzero urb status received: -ESHUTDOWN"); ++ break; ++ case -EPIPE: ++ err("nonzero urb status received: -EPIPE"); ++ break; ++ default: ++ err("Unexpected error %d", status); ++ break; ++ } ++ } ++ ++ desc->rerr = status; ++ desc->reslength = urb->actual_length; ++ memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength); ++ desc->length += desc->reslength; ++ wake_up(&desc->wait); ++ ++ set_bit(WDM_READ, &desc->flags); ++ spin_unlock(&desc->iuspin); ++} ++ ++static void wdm_int_callback(struct urb *urb) ++{ ++ int rv = 0; ++ int status = urb->status; ++ struct wdm_device *desc; ++ struct usb_ctrlrequest *req; ++ struct usb_cdc_notification *dr; ++ ++ desc = urb->context; ++ req = desc->irq; ++ dr = (struct usb_cdc_notification *)desc->sbuf; ++ ++ if (status) { ++ switch (status) { ++ case -ESHUTDOWN: ++ case -ENOENT: ++ case -ECONNRESET: ++ return; /* unplug */ ++ case -EPIPE: ++ set_bit(WDM_INT_STALL, &desc->flags); ++ err("Stall on int endpoint"); ++ goto sw; /* halt is cleared in work */ ++ default: ++ err("nonzero urb status received: %d", status); ++ break; ++ } ++ } ++ ++ if (urb->actual_length < sizeof(struct usb_cdc_notification)) { ++ err("wdm_int_callback - %d bytes", urb->actual_length); ++ goto exit; ++ } ++ ++ switch (dr->bNotificationType) { ++ case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: ++ dev_dbg(&desc->intf->dev, ++ "NOTIFY_RESPONSE_AVAILABLE received: index %d len %d", ++ dr->wIndex, dr->wLength); ++ break; ++ ++ case USB_CDC_NOTIFY_NETWORK_CONNECTION: ++ ++ dev_dbg(&desc->intf->dev, ++ "NOTIFY_NETWORK_CONNECTION %s network", ++ dr->wValue ? "connected to" : "disconnected from"); ++ goto exit; ++ default: ++ clear_bit(WDM_POLL_RUNNING, &desc->flags); ++ err("unknown notification %d received: index %d len %d", ++ dr->bNotificationType, dr->wIndex, dr->wLength); ++ goto exit; ++ } ++ ++ req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); ++ req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; ++ req->wValue = 0; ++ req->wIndex = desc->inum; ++ req->wLength = cpu_to_le16(desc->wMaxCommand); ++ ++ usb_fill_control_urb( ++ desc->response, ++ interface_to_usbdev(desc->intf), ++ /* using common endpoint 0 */ ++ usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0), ++ (unsigned char *)req, ++ desc->inbuf, ++ desc->wMaxCommand, ++ wdm_in_callback, ++ desc ++ ); ++ desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ spin_lock(&desc->iuspin); ++ clear_bit(WDM_READ, &desc->flags); ++ if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { ++ rv = usb_submit_urb(desc->response, GFP_ATOMIC); ++ dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d", ++ __func__, rv); ++ } ++ spin_unlock(&desc->iuspin); ++ if (rv < 0) { ++ if (rv == -EPERM) ++ return; ++ if (rv == -ENOMEM) { ++sw: ++ rv = schedule_work(&desc->rxwork); ++ if (rv) ++ err("Cannot schedule work"); ++ } ++ } ++exit: ++ rv = usb_submit_urb(urb, GFP_ATOMIC); ++ if (rv) ++ err("%s - usb_submit_urb failed with result %d", ++ __func__, rv); ++ ++} ++ ++static void kill_urbs(struct wdm_device *desc) ++{ ++ /* the order here is essential */ ++ usb_kill_urb(desc->command); ++ usb_kill_urb(desc->validity); ++ usb_kill_urb(desc->response); ++} ++ ++static void free_urbs(struct wdm_device *desc) ++{ ++ usb_free_urb(desc->validity); ++ usb_free_urb(desc->response); ++ usb_free_urb(desc->command); ++} ++ ++static void cleanup(struct wdm_device *desc) ++{ ++ usb_buffer_free(interface_to_usbdev(desc->intf), ++ desc->wMaxPacketSize, ++ desc->sbuf, ++ desc->validity->transfer_dma); ++ usb_buffer_free(interface_to_usbdev(desc->intf), ++ desc->wMaxCommand, ++ desc->inbuf, ++ desc->response->transfer_dma); ++ kfree(desc->orq); ++ kfree(desc->irq); ++ kfree(desc->ubuf); ++ free_urbs(desc); ++ kfree(desc); ++} ++ ++static ssize_t wdm_write ++(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) ++{ ++ u8 *buf; ++ int rv = -EMSGSIZE, r, we; ++ struct wdm_device *desc = file->private_data; ++ struct usb_ctrlrequest *req; ++ ++ if (count > desc->wMaxCommand) ++ count = desc->wMaxCommand; ++ ++ spin_lock_irq(&desc->iuspin); ++ we = desc->werr; ++ desc->werr = 0; ++ spin_unlock_irq(&desc->iuspin); ++ if (we < 0) ++ return -EIO; ++ ++ r = mutex_lock_interruptible(&desc->wlock); /* concurrent writes */ ++ rv = -ERESTARTSYS; ++ if (r) ++ goto outnl; ++ ++ r = usb_autopm_get_interface(desc->intf); ++ if (r < 0) ++ goto outnp; ++ r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE, ++ &desc->flags)); ++ if (r < 0) ++ goto out; ++ ++ if (test_bit(WDM_DISCONNECTING, &desc->flags)) { ++ rv = -ENODEV; ++ goto out; ++ } ++ ++ desc->outbuf = buf = kmalloc(count, GFP_KERNEL); ++ if (!buf) { ++ rv = -ENOMEM; ++ goto out; ++ } ++ ++ r = copy_from_user(buf, buffer, count); ++ if (r > 0) { ++ kfree(buf); ++ rv = -EFAULT; ++ goto out; ++ } ++ ++ req = desc->orq; ++ usb_fill_control_urb( ++ desc->command, ++ interface_to_usbdev(desc->intf), ++ /* using common endpoint 0 */ ++ usb_sndctrlpipe(interface_to_usbdev(desc->intf), 0), ++ (unsigned char *)req, ++ buf, ++ count, ++ wdm_out_callback, ++ desc ++ ); ++ ++ req->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS | ++ USB_RECIP_INTERFACE); ++ req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; ++ req->wValue = 0; ++ req->wIndex = desc->inum; ++ req->wLength = cpu_to_le16(count); ++ set_bit(WDM_IN_USE, &desc->flags); ++ ++ rv = usb_submit_urb(desc->command, GFP_KERNEL); ++ if (rv < 0) { ++ kfree(buf); ++ clear_bit(WDM_IN_USE, &desc->flags); ++ err("Tx URB error: %d", rv); ++ } else { ++ dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", ++ req->wIndex); ++ } ++out: ++ usb_autopm_put_interface(desc->intf); ++outnp: ++ mutex_unlock(&desc->wlock); ++outnl: ++ return rv < 0 ? rv : count; ++} ++ ++static ssize_t wdm_read ++(struct file *file, char __user *buffer, size_t count, loff_t *ppos) ++{ ++ int rv, cntr; ++ int i = 0; ++ struct wdm_device *desc = file->private_data; ++ ++ ++ rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */ ++ if (rv < 0) ++ return -ERESTARTSYS; ++ ++ if (desc->length == 0) { ++ desc->read = 0; ++retry: ++ i++; ++ rv = wait_event_interruptible(desc->wait, ++ test_bit(WDM_READ, &desc->flags)); ++ ++ if (test_bit(WDM_DISCONNECTING, &desc->flags)) { ++ rv = -ENODEV; ++ goto err; ++ } ++ usb_mark_last_busy(interface_to_usbdev(desc->intf)); ++ if (rv < 0) { ++ rv = -ERESTARTSYS; ++ goto err; ++ } ++ ++ spin_lock_irq(&desc->iuspin); ++ ++ if (desc->rerr) { /* read completed, error happened */ ++ int t = desc->rerr; ++ desc->rerr = 0; ++ spin_unlock_irq(&desc->iuspin); ++ err("reading had resulted in %d", t); ++ rv = -EIO; ++ goto err; ++ } ++ /* ++ * recheck whether we've lost the race ++ * against the completion handler ++ */ ++ if (!test_bit(WDM_READ, &desc->flags)) { /* lost race */ ++ spin_unlock_irq(&desc->iuspin); ++ goto retry; ++ } ++ if (!desc->reslength) { /* zero length read */ ++ spin_unlock_irq(&desc->iuspin); ++ goto retry; ++ } ++ clear_bit(WDM_READ, &desc->flags); ++ spin_unlock_irq(&desc->iuspin); ++ } ++ ++ cntr = count > desc->length ? desc->length : count; ++ rv = copy_to_user(buffer, desc->ubuf, cntr); ++ if (rv > 0) { ++ rv = -EFAULT; ++ goto err; ++ } ++ ++ for (i = 0; i < desc->length - cntr; i++) ++ desc->ubuf[i] = desc->ubuf[i + cntr]; ++ ++ desc->length -= cntr; ++ /* in case we had outstanding data */ ++ if (!desc->length) ++ clear_bit(WDM_READ, &desc->flags); ++ rv = cntr; ++ ++err: ++ mutex_unlock(&desc->rlock); ++ if (rv < 0) ++ err("wdm_read: exit error"); ++ return rv; ++} ++ ++static int wdm_flush(struct file *file, fl_owner_t id) ++{ ++ struct wdm_device *desc = file->private_data; ++ ++ wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); ++ if (desc->werr < 0) ++ err("Error in flush path: %d", desc->werr); ++ ++ return desc->werr; ++} ++ ++static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) ++{ ++ struct wdm_device *desc = file->private_data; ++ unsigned long flags; ++ unsigned int mask = 0; ++ ++ spin_lock_irqsave(&desc->iuspin, flags); ++ if (test_bit(WDM_DISCONNECTING, &desc->flags)) { ++ mask = POLLERR; ++ spin_unlock_irqrestore(&desc->iuspin, flags); ++ goto desc_out; ++ } ++ if (test_bit(WDM_READ, &desc->flags)) ++ mask = POLLIN | POLLRDNORM; ++ if (desc->rerr || desc->werr) ++ mask |= POLLERR; ++ if (!test_bit(WDM_IN_USE, &desc->flags)) ++ mask |= POLLOUT | POLLWRNORM; ++ spin_unlock_irqrestore(&desc->iuspin, flags); ++ ++ poll_wait(file, &desc->wait, wait); ++ ++desc_out: ++ return mask; ++} ++ ++static int wdm_open(struct inode *inode, struct file *file) ++{ ++ int minor = iminor(inode); ++ int rv = -ENODEV; ++ struct usb_interface *intf; ++ struct wdm_device *desc; ++ ++ mutex_lock(&wdm_mutex); ++ intf = usb_find_interface(&wdm_driver, minor); ++ if (!intf) ++ goto out; ++ ++ desc = usb_get_intfdata(intf); ++ if (test_bit(WDM_DISCONNECTING, &desc->flags)) ++ goto out; ++ ++ ; ++ file->private_data = desc; ++ ++ rv = usb_autopm_get_interface(desc->intf); ++ if (rv < 0) { ++ err("Error autopm - %d", rv); ++ goto out; ++ } ++ intf->needs_remote_wakeup = 1; ++ ++ mutex_lock(&desc->plock); ++ if (!desc->count++) { ++ rv = usb_submit_urb(desc->validity, GFP_KERNEL); ++ if (rv < 0) { ++ desc->count--; ++ err("Error submitting int urb - %d", rv); ++ } ++ } else { ++ rv = 0; ++ } ++ mutex_unlock(&desc->plock); ++ usb_autopm_put_interface(desc->intf); ++out: ++ mutex_unlock(&wdm_mutex); ++ return rv; ++} ++ ++static int wdm_release(struct inode *inode, struct file *file) ++{ ++ struct wdm_device *desc = file->private_data; ++ ++ mutex_lock(&wdm_mutex); ++ mutex_lock(&desc->plock); ++ desc->count--; ++ mutex_unlock(&desc->plock); ++ ++ if (!desc->count) { ++ dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); ++ kill_urbs(desc); ++ if (!test_bit(WDM_DISCONNECTING, &desc->flags)) ++ desc->intf->needs_remote_wakeup = 0; ++ } ++ mutex_unlock(&wdm_mutex); ++ return 0; ++} ++ ++static const struct file_operations wdm_fops = { ++ .owner = THIS_MODULE, ++ .read = wdm_read, ++ .write = wdm_write, ++ .open = wdm_open, ++ .flush = wdm_flush, ++ .release = wdm_release, ++ .poll = wdm_poll ++}; ++ ++static struct usb_class_driver wdm_class = { ++ .name = "cdc-wdm%d", ++ .fops = &wdm_fops, ++ .minor_base = WDM_MINOR_BASE, ++}; ++ ++/* --- error handling --- */ ++static void wdm_rxwork(struct work_struct *work) ++{ ++ struct wdm_device *desc = container_of(work, struct wdm_device, rxwork); ++ unsigned long flags; ++ int rv; ++ ++ spin_lock_irqsave(&desc->iuspin, flags); ++ if (test_bit(WDM_DISCONNECTING, &desc->flags)) { ++ spin_unlock_irqrestore(&desc->iuspin, flags); ++ } else { ++ spin_unlock_irqrestore(&desc->iuspin, flags); ++ rv = usb_submit_urb(desc->response, GFP_KERNEL); ++ if (rv < 0 && rv != -EPERM) { ++ spin_lock_irqsave(&desc->iuspin, flags); ++ if (!test_bit(WDM_DISCONNECTING, &desc->flags)) ++ schedule_work(&desc->rxwork); ++ spin_unlock_irqrestore(&desc->iuspin, flags); ++ } ++ } ++} ++ ++/* --- hotplug --- */ ++ ++static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) ++{ ++ int rv = -EINVAL; ++ struct usb_device *udev = interface_to_usbdev(intf); ++ struct wdm_device *desc; ++ struct usb_host_interface *iface; ++ struct usb_endpoint_descriptor *ep; ++ struct usb_cdc_dmm_desc *dmhd; ++ u8 *buffer = intf->altsetting->extra; ++ int buflen = intf->altsetting->extralen; ++ u16 maxcom = 0; ++ ++ if (!buffer) ++ goto out; ++ ++ while (buflen > 0) { ++ if (buffer [1] != USB_DT_CS_INTERFACE) { ++ err("skipping garbage"); ++ goto next_desc; ++ } ++ ++ switch (buffer [2]) { ++ case USB_CDC_HEADER_TYPE: ++ break; ++ case USB_CDC_DMM_TYPE: ++ dmhd = (struct usb_cdc_dmm_desc *)buffer; ++ maxcom = le16_to_cpu(dmhd->wMaxCommand); ++ dev_dbg(&intf->dev, ++ "Finding maximum buffer length: %d", maxcom); ++ break; ++ default: ++ err("Ignoring extra header, type %d, length %d", ++ buffer[2], buffer[0]); ++ break; ++ } ++next_desc: ++ buflen -= buffer[0]; ++ buffer += buffer[0]; ++ } ++ ++ rv = -ENOMEM; ++ desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); ++ if (!desc) ++ goto out; ++ mutex_init(&desc->wlock); ++ mutex_init(&desc->rlock); ++ mutex_init(&desc->plock); ++ spin_lock_init(&desc->iuspin); ++ init_waitqueue_head(&desc->wait); ++ desc->wMaxCommand = maxcom; ++ desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber); ++ desc->intf = intf; ++ INIT_WORK(&desc->rxwork, wdm_rxwork); ++ ++ iface = &intf->altsetting[0]; ++ ep = &iface->endpoint[0].desc; ++ if (!usb_endpoint_is_int_in(ep)) { ++ rv = -EINVAL; ++ goto err; ++ } ++ ++ desc->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize); ++ desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0; ++ ++ desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); ++ if (!desc->orq) ++ goto err; ++ desc->irq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); ++ if (!desc->irq) ++ goto err; ++ ++ desc->validity = usb_alloc_urb(0, GFP_KERNEL); ++ if (!desc->validity) ++ goto err; ++ ++ desc->response = usb_alloc_urb(0, GFP_KERNEL); ++ if (!desc->response) ++ goto err; ++ ++ desc->command = usb_alloc_urb(0, GFP_KERNEL); ++ if (!desc->command) ++ goto err; ++ ++ desc->ubuf = kmalloc(desc->wMaxCommand, GFP_KERNEL); ++ if (!desc->ubuf) ++ goto err; ++ ++ desc->sbuf = usb_buffer_alloc(interface_to_usbdev(intf), ++ desc->wMaxPacketSize, ++ GFP_KERNEL, ++ &desc->validity->transfer_dma); ++ if (!desc->sbuf) ++ goto err; ++ ++ desc->inbuf = usb_buffer_alloc(interface_to_usbdev(intf), ++ desc->bMaxPacketSize0, ++ GFP_KERNEL, ++ &desc->response->transfer_dma); ++ if (!desc->inbuf) ++ goto err2; ++ ++ usb_fill_int_urb( ++ desc->validity, ++ interface_to_usbdev(intf), ++ usb_rcvintpipe(interface_to_usbdev(intf), ep->bEndpointAddress), ++ desc->sbuf, ++ desc->wMaxPacketSize, ++ wdm_int_callback, ++ desc, ++ ep->bInterval ++ ); ++ desc->validity->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ ++ usb_set_intfdata(intf, desc); ++ rv = usb_register_dev(intf, &wdm_class); ++ dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n", ++ intf->minor - WDM_MINOR_BASE); ++ if (rv < 0) ++ goto err; ++out: ++ return rv; ++err2: ++ usb_buffer_free(interface_to_usbdev(desc->intf), ++ desc->wMaxPacketSize, ++ desc->sbuf, ++ desc->validity->transfer_dma); ++err: ++ free_urbs(desc); ++ kfree(desc->ubuf); ++ kfree(desc->orq); ++ kfree(desc->irq); ++ kfree(desc); ++ return rv; ++} ++ ++static void wdm_disconnect(struct usb_interface *intf) ++{ ++ struct wdm_device *desc; ++ unsigned long flags; ++ ++ usb_deregister_dev(intf, &wdm_class); ++ mutex_lock(&wdm_mutex); ++ desc = usb_get_intfdata(intf); ++ ++ /* the spinlock makes sure no new urbs are generated in the callbacks */ ++ spin_lock_irqsave(&desc->iuspin, flags); ++ set_bit(WDM_DISCONNECTING, &desc->flags); ++ set_bit(WDM_READ, &desc->flags); ++ /* to terminate pending flushes */ ++ clear_bit(WDM_IN_USE, &desc->flags); ++ spin_unlock_irqrestore(&desc->iuspin, flags); ++ cancel_work_sync(&desc->rxwork); ++ kill_urbs(desc); ++ wake_up_all(&desc->wait); ++ if (!desc->count) ++ cleanup(desc); ++ mutex_unlock(&wdm_mutex); ++} ++ ++static int wdm_suspend(struct usb_interface *intf, pm_message_t message) ++{ ++ struct wdm_device *desc = usb_get_intfdata(intf); ++ int rv = 0; ++ ++ dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); ++ ++ mutex_lock(&desc->plock); ++#ifdef CONFIG_PM ++ if (interface_to_usbdev(desc->intf)->auto_pm && test_bit(WDM_IN_USE, &desc->flags)) { ++ rv = -EBUSY; ++ } else { ++#endif ++ cancel_work_sync(&desc->rxwork); ++ kill_urbs(desc); ++#ifdef CONFIG_PM ++ } ++#endif ++ mutex_unlock(&desc->plock); ++ ++ return rv; ++} ++ ++static int recover_from_urb_loss(struct wdm_device *desc) ++{ ++ int rv = 0; ++ ++ if (desc->count) { ++ rv = usb_submit_urb(desc->validity, GFP_NOIO); ++ if (rv < 0) ++ err("Error resume submitting int urb - %d", rv); ++ } ++ return rv; ++} ++static int wdm_resume(struct usb_interface *intf) ++{ ++ struct wdm_device *desc = usb_get_intfdata(intf); ++ int rv; ++ ++ dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor); ++ mutex_lock(&desc->plock); ++ rv = recover_from_urb_loss(desc); ++ mutex_unlock(&desc->plock); ++ return rv; ++} ++ ++static int wdm_pre_reset(struct usb_interface *intf) ++{ ++ struct wdm_device *desc = usb_get_intfdata(intf); ++ ++ mutex_lock(&desc->plock); ++ return 0; ++} ++ ++static int wdm_post_reset(struct usb_interface *intf) ++{ ++ struct wdm_device *desc = usb_get_intfdata(intf); ++ int rv; ++ ++ rv = recover_from_urb_loss(desc); ++ mutex_unlock(&desc->plock); ++ return 0; ++} ++ ++static struct usb_driver wdm_driver = { ++ .name = "cdc_wdm", ++ .probe = wdm_probe, ++ .disconnect = wdm_disconnect, ++ .suspend = wdm_suspend, ++ .resume = wdm_resume, ++ .reset_resume = wdm_resume, ++ .pre_reset = wdm_pre_reset, ++ .post_reset = wdm_post_reset, ++ .id_table = wdm_ids, ++ .supports_autosuspend = 1, ++}; ++ ++/* --- low level module stuff --- */ ++ ++static int __init wdm_init(void) ++{ ++ int rv; ++ ++ rv = usb_register(&wdm_driver); ++ ++ return rv; ++} ++ ++static void __exit wdm_exit(void) ++{ ++ usb_deregister(&wdm_driver); ++} ++ ++module_init(wdm_init); ++module_exit(wdm_exit); ++ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL"); +diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h +index 2204ae2..ca228bb 100644 +--- a/include/linux/usb/cdc.h ++++ b/include/linux/usb/cdc.h +@@ -6,6 +6,9 @@ + * firmware based USB peripherals. + */ + ++#ifndef __LINUX_USB_CDC_H ++#define __LINUX_USB_CDC_H ++ + #define USB_CDC_SUBCLASS_ACM 0x02 + #define USB_CDC_SUBCLASS_ETHERNET 0x06 + #define USB_CDC_SUBCLASS_WHCM 0x08 +@@ -29,16 +32,16 @@ + * Class-Specific descriptors ... there are a couple dozen of them + */ + +-#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */ +-#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */ +-#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */ +-#define USB_CDC_UNION_TYPE 0x06 /* union_desc */ ++#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */ ++#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */ ++#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */ ++#define USB_CDC_UNION_TYPE 0x06 /* union_desc */ + #define USB_CDC_COUNTRY_TYPE 0x07 +-#define USB_CDC_NETWORK_TERMINAL_TYPE 0x0a /* network_terminal_desc */ +-#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */ ++#define USB_CDC_NETWORK_TERMINAL_TYPE 0x0a /* network_terminal_desc */ ++#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */ + #define USB_CDC_WHCM_TYPE 0x11 +-#define USB_CDC_MDLM_TYPE 0x12 /* mdlm_desc */ +-#define USB_CDC_MDLM_DETAIL_TYPE 0x13 /* mdlm_detail_desc */ ++#define USB_CDC_MDLM_TYPE 0x12 /* mdlm_desc */ ++#define USB_CDC_MDLM_DETAIL_TYPE 0x13 /* mdlm_detail_desc */ + #define USB_CDC_DMM_TYPE 0x14 + #define USB_CDC_OBEX_TYPE 0x15 + +@@ -127,6 +130,15 @@ struct usb_cdc_ether_desc { + __u8 bNumberPowerFilters; + } __attribute__ ((packed)); + ++/* "Telephone Control Model Functional Descriptor" from CDC WMC spec 6.3..3 */ ++struct usb_cdc_dmm_desc { ++ __u8 bFunctionLength; ++ __u8 bDescriptorType; ++ __u8 bDescriptorSubtype; ++ __u16 bcdVersion; ++ __le16 wMaxCommand; ++} __attribute__ ((packed)); ++ + /* "MDLM Functional Descriptor" from CDC WMC spec 6.7.2.3 */ + struct usb_cdc_mdlm_desc { + __u8 bLength; +@@ -221,3 +233,4 @@ struct usb_cdc_notification { + __le16 wLength; + } __attribute__ ((packed)); + ++#endif /* __LINUX_USB_CDC_H */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0036-Remove-lpiacompat.patch +++ linux-2.6.24/patches/0036-Remove-lpiacompat.patch @@ -0,0 +1,40 @@ +From 1b1ce5e2f431555b696736a13010982691b872a3 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Mon, 7 Jul 2008 12:38:37 +0100 +Subject: [PATCH 036/170] Remove lpiacompat + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/rules.d/0-common-vars.mk | 2 +- + debian/rules.d/lpia.mk | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/debian/rules.d/0-common-vars.mk b/debian/rules.d/0-common-vars.mk +index c5a5c30..41c681a 100644 +--- a/debian/rules.d/0-common-vars.mk ++++ b/debian/rules.d/0-common-vars.mk +@@ -112,7 +112,7 @@ ifneq ($(LOCAL_ENV_CC),) + kmake += CC=$(LOCAL_ENV_CC) DISTCC_HOSTS=$(LOCAL_ENV_DISTCC_HOSTS) + endif + +-all_custom_flavours = lpia rt lpiacompat xen openvz ++all_custom_flavours = lpia rt xen openvz + + # Checks if a var is overriden by the custom rules. Called with var and + # flavour as arguments. +diff --git a/debian/rules.d/lpia.mk b/debian/rules.d/lpia.mk +index 4a718b2..123c7bc 100644 +--- a/debian/rules.d/lpia.mk ++++ b/debian/rules.d/lpia.mk +@@ -12,7 +12,7 @@ do_debug_image = true + loader = grub + + #custom_flavours = lpiacompat lpia +-custom_flavours = lpia lpiacompat ++custom_flavours = lpia + + # + # Set this variable to 'true' in order to +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0075-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook11.patch +++ linux-2.6.24/patches/0075-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook11.patch @@ -0,0 +1,31 @@ +From 0c1bcb213e6dbcb2fec0550c1af6dae2264515b8 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Mon, 3 Nov 2008 10:07:26 -0500 +Subject: [PATCH 075/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook11 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 9 +++++++++ + 1 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 08b74d4..9342a06 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,12 @@ ++linux (2.6.24-19.41netbook11) hardy; urgency=low ++ ++ [Upstream Kernel Changes] ++ ++ * drivers/acpi/hardware/hwsleep.c ++ Clear WAK_STS on resume. Fix for LP#285611 ++ ++ -- Michael Frey Mon, 03 Nov 2008 10:04:29 -0500 ++ + linux (2.6.24-19.41netbook10) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0108-UBUNTU-add-support-for-LG-Electronics-LGDT3305-ATSC-.patch +++ linux-2.6.24/patches/0108-UBUNTU-add-support-for-LG-Electronics-LGDT3305-ATSC-.patch @@ -0,0 +1,1265 @@ +From 11e7a458084f56656c753aada58ca083691edf17 Mon Sep 17 00:00:00 2001 +From: Michael Krufky +Date: Tue, 24 Mar 2009 23:36:43 -0400 +Subject: [PATCH 108/170] UBUNTU: add support for LG Electronics LGDT3305 ATSC/QAM-B Demodulator + +OriginalAuthor: Michael Krufky +OriginalLocation: http://linuxtv.org/hg/v4l-dvb/rev/e801c484fc21 + +add support for LG Electronics LGDT3305 ATSC/QAM-B Demodulator + +Signed-off-by: Michael Krufky +--- + drivers/media/dvb/frontends/Kconfig | 8 + + drivers/media/dvb/frontends/Makefile | 1 + + drivers/media/dvb/frontends/lgdt3305.c | 1114 ++++++++++++++++++++++++++++++++ + drivers/media/dvb/frontends/lgdt3305.h | 85 +++ + 4 files changed, 1208 insertions(+), 0 deletions(-) + create mode 100644 drivers/media/dvb/frontends/lgdt3305.c + create mode 100644 drivers/media/dvb/frontends/lgdt3305.h + +diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig +index 59b9ed1..aea62aa 100644 +--- a/drivers/media/dvb/frontends/Kconfig ++++ b/drivers/media/dvb/frontends/Kconfig +@@ -291,6 +291,14 @@ config DVB_S5H1409 + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + ++config DVB_LGDT3305 ++ tristate "LG Electronics LGDT3305 based" ++ depends on DVB_CORE && I2C ++ default m if DVB_FE_CUSTOMISE ++ help ++ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want ++ to support this frontend. ++ + comment "Tuners/PLL support" + depends on DVB_CORE + +diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile +index 4b8ad1f..80a073a 100644 +--- a/drivers/media/dvb/frontends/Makefile ++++ b/drivers/media/dvb/frontends/Makefile +@@ -33,6 +33,7 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o + obj-$(CONFIG_DVB_BCM3510) += bcm3510.o + obj-$(CONFIG_DVB_S5H1420) += s5h1420.o + obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o ++obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o + obj-$(CONFIG_DVB_CX24123) += cx24123.o + obj-$(CONFIG_DVB_LNBP21) += lnbp21.o + obj-$(CONFIG_DVB_ISL6421) += isl6421.o +diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c +new file mode 100644 +index 0000000..b611b5f +--- /dev/null ++++ b/drivers/media/dvb/frontends/lgdt3305.c +@@ -0,0 +1,1114 @@ ++/* ++ * Support for LGDT3305 - VSB/QAM ++ * ++ * Copyright (C) 2008, 2009 Michael Krufky ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include "dvb_math.h" ++#include "lgdt3305.h" ++ ++static int debug; ++module_param(debug, int, 0644); ++MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))"); ++ ++#define DBG_INFO 1 ++#define DBG_REG 2 ++ ++#define lg_printk(kern, fmt, arg...) \ ++ printk(kern "%s: " fmt, __func__, ##arg) ++ ++#define lg_info(fmt, arg...) printk(KERN_INFO "lgdt3305: " fmt, ##arg) ++#define lg_warn(fmt, arg...) lg_printk(KERN_WARNING, fmt, ##arg) ++#define lg_err(fmt, arg...) lg_printk(KERN_ERR, fmt, ##arg) ++#define lg_dbg(fmt, arg...) if (debug & DBG_INFO) \ ++ lg_printk(KERN_DEBUG, fmt, ##arg) ++#define lg_reg(fmt, arg...) if (debug & DBG_REG) \ ++ lg_printk(KERN_DEBUG, fmt, ##arg) ++ ++#define lg_fail(ret) \ ++({ \ ++ int __ret; \ ++ __ret = (ret < 0); \ ++ if (__ret) \ ++ lg_err("error %d on line %d\n", ret, __LINE__); \ ++ __ret; \ ++}) ++ ++struct lgdt3305_state { ++ struct i2c_adapter *i2c_adap; ++ const struct lgdt3305_config *cfg; ++ ++ struct dvb_frontend frontend; ++ ++ fe_modulation_t current_modulation; ++ u32 current_frequency; ++ u32 snr; ++}; ++ ++/* ------------------------------------------------------------------------ */ ++ ++#define LGDT3305_GEN_CTRL_1 0x0000 ++#define LGDT3305_GEN_CTRL_2 0x0001 ++#define LGDT3305_GEN_CTRL_3 0x0002 ++#define LGDT3305_GEN_STATUS 0x0003 ++#define LGDT3305_GEN_CONTROL 0x0007 ++#define LGDT3305_GEN_CTRL_4 0x000a ++#define LGDT3305_DGTL_AGC_REF_1 0x0012 ++#define LGDT3305_DGTL_AGC_REF_2 0x0013 ++#define LGDT3305_CR_CTR_FREQ_1 0x0106 ++#define LGDT3305_CR_CTR_FREQ_2 0x0107 ++#define LGDT3305_CR_CTR_FREQ_3 0x0108 ++#define LGDT3305_CR_CTR_FREQ_4 0x0109 ++#define LGDT3305_CR_MSE_1 0x011b ++#define LGDT3305_CR_MSE_2 0x011c ++#define LGDT3305_CR_LOCK_STATUS 0x011d ++#define LGDT3305_CR_CTRL_7 0x0126 ++#define LGDT3305_AGC_POWER_REF_1 0x0300 ++#define LGDT3305_AGC_POWER_REF_2 0x0301 ++#define LGDT3305_AGC_DELAY_PT_1 0x0302 ++#define LGDT3305_AGC_DELAY_PT_2 0x0303 ++#define LGDT3305_RFAGC_LOOP_FLTR_BW_1 0x0306 ++#define LGDT3305_RFAGC_LOOP_FLTR_BW_2 0x0307 ++#define LGDT3305_IFBW_1 0x0308 ++#define LGDT3305_IFBW_2 0x0309 ++#define LGDT3305_AGC_CTRL_1 0x030c ++#define LGDT3305_AGC_CTRL_4 0x0314 ++#define LGDT3305_EQ_MSE_1 0x0413 ++#define LGDT3305_EQ_MSE_2 0x0414 ++#define LGDT3305_EQ_MSE_3 0x0415 ++#define LGDT3305_PT_MSE_1 0x0417 ++#define LGDT3305_PT_MSE_2 0x0418 ++#define LGDT3305_PT_MSE_3 0x0419 ++#define LGDT3305_FEC_BLOCK_CTRL 0x0504 ++#define LGDT3305_FEC_LOCK_STATUS 0x050a ++#define LGDT3305_FEC_PKT_ERR_1 0x050c ++#define LGDT3305_FEC_PKT_ERR_2 0x050d ++#define LGDT3305_TP_CTRL_1 0x050e ++#define LGDT3305_BERT_PERIOD 0x0801 ++#define LGDT3305_BERT_ERROR_COUNT_1 0x080a ++#define LGDT3305_BERT_ERROR_COUNT_2 0x080b ++#define LGDT3305_BERT_ERROR_COUNT_3 0x080c ++#define LGDT3305_BERT_ERROR_COUNT_4 0x080d ++ ++static int lgdt3305_write_reg(struct lgdt3305_state *state, u16 reg, u8 val) ++{ ++ int ret; ++ u8 buf[] = { reg >> 8, reg & 0xff, val }; ++ struct i2c_msg msg = { ++ .addr = state->cfg->i2c_addr, .flags = 0, ++ .buf = buf, .len = 3, ++ }; ++ ++ lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val); ++ ++ ret = i2c_transfer(state->i2c_adap, &msg, 1); ++ ++ if (ret != 1) { ++ lg_err("error (addr %02x %02x <- %02x, err = %i)\n", ++ msg.buf[0], msg.buf[1], msg.buf[2], ret); ++ if (ret < 0) ++ return ret; ++ else ++ return -EREMOTEIO; ++ } ++ return 0; ++} ++ ++static int lgdt3305_read_reg(struct lgdt3305_state *state, u16 reg, u8 *val) ++{ ++ int ret; ++ u8 reg_buf[] = { reg >> 8, reg & 0xff }; ++ struct i2c_msg msg[] = { ++ { .addr = state->cfg->i2c_addr, ++ .flags = 0, .buf = reg_buf, .len = 2 }, ++ { .addr = state->cfg->i2c_addr, ++ .flags = I2C_M_RD, .buf = val, .len = 1 }, ++ }; ++ ++ lg_reg("reg: 0x%04x\n", reg); ++ ++ ret = i2c_transfer(state->i2c_adap, msg, 2); ++ ++ if (ret != 2) { ++ lg_err("error (addr %02x reg %04x error (ret == %i)\n", ++ state->cfg->i2c_addr, reg, ret); ++ if (ret < 0) ++ return ret; ++ else ++ return -EREMOTEIO; ++ } ++ return 0; ++} ++ ++#define read_reg(state, reg) \ ++({ \ ++ u8 __val; \ ++ int ret = lgdt3305_read_reg(state, reg, &__val); \ ++ if (lg_fail(ret)) \ ++ __val = 0; \ ++ __val; \ ++}) ++ ++static int lgdt3305_set_reg_bit(struct lgdt3305_state *state, ++ u16 reg, int bit, int onoff) ++{ ++ u8 val; ++ int ret; ++ ++ lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff); ++ ++ ret = lgdt3305_read_reg(state, reg, &val); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ val &= ~(1 << bit); ++ val |= (onoff & 1) << bit; ++ ++ ret = lgdt3305_write_reg(state, reg, val); ++fail: ++ return ret; ++} ++ ++struct lgdt3305_reg { ++ u16 reg; ++ u8 val; ++}; ++ ++static int lgdt3305_write_regs(struct lgdt3305_state *state, ++ struct lgdt3305_reg *regs, int len) ++{ ++ int i, ret; ++ ++ lg_reg("writing %d registers...\n", len); ++ ++ for (i = 0; i < len - 1; i++) { ++ ret = lgdt3305_write_reg(state, regs[i].reg, regs[i].val); ++ if (lg_fail(ret)) ++ return ret; ++ } ++ return 0; ++} ++ ++/* ------------------------------------------------------------------------ */ ++ ++static int lgdt3305_soft_reset(struct lgdt3305_state *state) ++{ ++ int ret; ++ ++ lg_dbg("\n"); ++ ++ ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 0); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ msleep(20); ++ ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 1); ++fail: ++ return ret; ++} ++ ++static inline int lgdt3305_mpeg_mode(struct lgdt3305_state *state, ++ enum lgdt3305_mpeg_mode mode) ++{ ++ lg_dbg("(%d)\n", mode); ++ return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode); ++} ++ ++static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state, ++ enum lgdt3305_tp_clock_edge edge, ++ enum lgdt3305_tp_valid_polarity valid) ++{ ++ u8 val; ++ int ret; ++ ++ lg_dbg("edge = %d, valid = %d\n", edge, valid); ++ ++ ret = lgdt3305_read_reg(state, LGDT3305_TP_CTRL_1, &val); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ val &= ~0x09; ++ ++ if (edge) ++ val |= 0x08; ++ if (valid) ++ val |= 0x01; ++ ++ ret = lgdt3305_write_reg(state, LGDT3305_TP_CTRL_1, val); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ ret = lgdt3305_soft_reset(state); ++fail: ++ return ret; ++} ++ ++static int lgdt3305_set_modulation(struct lgdt3305_state *state, ++ struct dvb_frontend_parameters *param) ++{ ++ u8 opermode; ++ int ret; ++ ++ lg_dbg("\n"); ++ ++ ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_1, &opermode); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ opermode &= ~0x03; ++ ++ switch (param->u.vsb.modulation) { ++ case VSB_8: ++ opermode |= 0x03; ++ break; ++ case QAM_64: ++ opermode |= 0x00; ++ break; ++ case QAM_256: ++ opermode |= 0x01; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ret = lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_1, opermode); ++fail: ++ return ret; ++} ++ ++static int lgdt3305_set_filter_extension(struct lgdt3305_state *state, ++ struct dvb_frontend_parameters *param) ++{ ++ int val; ++ ++ switch (param->u.vsb.modulation) { ++ case VSB_8: ++ val = 0; ++ break; ++ case QAM_64: ++ case QAM_256: ++ val = 1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ lg_dbg("val = %d\n", val); ++ ++ return lgdt3305_set_reg_bit(state, 0x043f, 2, val); ++} ++ ++/* ------------------------------------------------------------------------ */ ++ ++static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state, ++ struct dvb_frontend_parameters *param) ++{ ++ u16 agc_ref; ++ ++ switch (param->u.vsb.modulation) { ++ case VSB_8: ++ agc_ref = 0x32c4; ++ break; ++ case QAM_64: ++ agc_ref = 0x2a00; ++ break; ++ case QAM_256: ++ agc_ref = 0x2a80; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ lg_dbg("agc ref: 0x%04x\n", agc_ref); ++ ++ lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_1, agc_ref >> 8); ++ lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_2, agc_ref & 0xff); ++ ++ return 0; ++} ++ ++static int lgdt3305_rfagc_loop(struct lgdt3305_state *state, ++ struct dvb_frontend_parameters *param) ++{ ++ u16 ifbw, rfbw, agcdelay; ++ ++ switch (param->u.vsb.modulation) { ++ case VSB_8: ++ agcdelay = 0x04c0; ++ rfbw = 0x8000; ++ ifbw = 0x8000; ++ break; ++ case QAM_64: ++ case QAM_256: ++ agcdelay = 0x046b; ++ rfbw = 0x8889; ++ ifbw = 0x8888; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (state->cfg->rf_agc_loop) { ++ lg_dbg("agcdelay: 0x%04x, rfbw: 0x%04x\n", agcdelay, rfbw); ++ ++ /* rf agc loop filter bandwidth */ ++ lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_1, ++ agcdelay >> 8); ++ lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_2, ++ agcdelay & 0xff); ++ ++ lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_1, ++ rfbw >> 8); ++ lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_2, ++ rfbw & 0xff); ++ } else { ++ lg_dbg("ifbw: 0x%04x\n", ifbw); ++ ++ /* if agc loop filter bandwidth */ ++ lgdt3305_write_reg(state, LGDT3305_IFBW_1, ifbw >> 8); ++ lgdt3305_write_reg(state, LGDT3305_IFBW_2, ifbw & 0xff); ++ } ++ ++ return 0; ++} ++ ++static int lgdt3305_agc_setup(struct lgdt3305_state *state, ++ struct dvb_frontend_parameters *param) ++{ ++ int lockdten, acqen; ++ ++ switch (param->u.vsb.modulation) { ++ case VSB_8: ++ lockdten = 0; ++ acqen = 0; ++ break; ++ case QAM_64: ++ case QAM_256: ++ lockdten = 1; ++ acqen = 1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen); ++ ++ /* control agc function */ ++ lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1); ++ lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen); ++ ++ return lgdt3305_rfagc_loop(state, param); ++} ++ ++static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state, ++ struct dvb_frontend_parameters *param) ++{ ++ u16 usref = 0; ++ ++ switch (param->u.vsb.modulation) { ++ case VSB_8: ++ if (state->cfg->usref_8vsb) ++ usref = state->cfg->usref_8vsb; ++ break; ++ case QAM_64: ++ if (state->cfg->usref_qam64) ++ usref = state->cfg->usref_qam64; ++ break; ++ case QAM_256: ++ if (state->cfg->usref_qam256) ++ usref = state->cfg->usref_qam256; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (usref) { ++ lg_dbg("set manual mode: 0x%04x\n", usref); ++ ++ lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 3, 1); ++ ++ lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_1, ++ 0xff & (usref >> 8)); ++ lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_2, ++ 0xff & (usref >> 0)); ++ } ++ return 0; ++} ++ ++/* ------------------------------------------------------------------------ */ ++ ++static int lgdt3305_spectral_inversion(struct lgdt3305_state *state, ++ struct dvb_frontend_parameters *param, ++ int inversion) ++{ ++ int ret; ++ ++ lg_dbg("(%d)\n", inversion); ++ ++ switch (param->u.vsb.modulation) { ++ case VSB_8: ++ ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7, ++ inversion ? 0xf9 : 0x79); ++ break; ++ case QAM_64: ++ case QAM_256: ++ ret = lgdt3305_write_reg(state, LGDT3305_FEC_BLOCK_CTRL, ++ inversion ? 0xfd : 0xff); ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++static int lgdt3305_set_if(struct lgdt3305_state *state, ++ struct dvb_frontend_parameters *param) ++{ ++ u16 if_freq_khz; ++ u8 nco1, nco2, nco3, nco4; ++ u64 nco; ++ ++ switch (param->u.vsb.modulation) { ++ case VSB_8: ++ if_freq_khz = state->cfg->vsb_if_khz; ++ break; ++ case QAM_64: ++ case QAM_256: ++ if_freq_khz = state->cfg->qam_if_khz; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ nco = if_freq_khz / 10; ++ ++#define LGDT3305_64BIT_DIVISION_ENABLED 0 ++ /* FIXME: 64bit division disabled to avoid linking error: ++ * WARNING: "__udivdi3" [lgdt3305.ko] undefined! ++ */ ++ switch (param->u.vsb.modulation) { ++ case VSB_8: ++#if LGDT3305_64BIT_DIVISION_ENABLED ++ nco <<= 24; ++ nco /= 625; ++#else ++ nco *= ((1 << 24) / 625); ++#endif ++ break; ++ case QAM_64: ++ case QAM_256: ++#if LGDT3305_64BIT_DIVISION_ENABLED ++ nco <<= 28; ++ nco /= 625; ++#else ++ nco *= ((1 << 28) / 625); ++#endif ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ nco1 = (nco >> 24) & 0x3f; ++ nco1 |= 0x40; ++ nco2 = (nco >> 16) & 0xff; ++ nco3 = (nco >> 8) & 0xff; ++ nco4 = nco & 0xff; ++ ++ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, nco1); ++ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, nco2); ++ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, nco3); ++ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, nco4); ++ ++ lg_dbg("%d KHz -> [%02x%02x%02x%02x]\n", ++ if_freq_khz, nco1, nco2, nco3, nco4); ++ ++ return 0; ++} ++ ++/* ------------------------------------------------------------------------ */ ++ ++static int lgdt3305_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) ++{ ++ struct lgdt3305_state *state = fe->demodulator_priv; ++ ++ if (state->cfg->deny_i2c_rptr) ++ return 0; ++ ++ lg_dbg("(%d)\n", enable); ++ ++ return lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_2, 5, ++ enable ? 0 : 1); ++} ++ ++static int lgdt3305_sleep(struct dvb_frontend *fe) ++{ ++ struct lgdt3305_state *state = fe->demodulator_priv; ++ u8 gen_ctrl_3, gen_ctrl_4; ++ ++ lg_dbg("\n"); ++ ++ gen_ctrl_3 = read_reg(state, LGDT3305_GEN_CTRL_3); ++ gen_ctrl_4 = read_reg(state, LGDT3305_GEN_CTRL_4); ++ ++ /* hold in software reset while sleeping */ ++ gen_ctrl_3 &= ~0x01; ++ /* tristate the IF-AGC pin */ ++ gen_ctrl_3 |= 0x02; ++ /* tristate the RF-AGC pin */ ++ gen_ctrl_3 |= 0x04; ++ ++ /* disable vsb/qam module */ ++ gen_ctrl_4 &= ~0x01; ++ /* disable adc module */ ++ gen_ctrl_4 &= ~0x02; ++ ++ lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_3, gen_ctrl_3); ++ lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_4, gen_ctrl_4); ++ ++ return 0; ++} ++ ++static int lgdt3305_init(struct dvb_frontend *fe) ++{ ++ struct lgdt3305_state *state = fe->demodulator_priv; ++ int ret; ++ ++ static struct lgdt3305_reg lgdt3305_init_data[] = { ++ { .reg = LGDT3305_GEN_CTRL_1, ++ .val = 0x03, }, ++ { .reg = LGDT3305_GEN_CTRL_2, ++ .val = 0xb0, }, ++ { .reg = LGDT3305_GEN_CTRL_3, ++ .val = 0x01, }, ++ { .reg = LGDT3305_GEN_CONTROL, ++ .val = 0x6f, }, ++ { .reg = LGDT3305_GEN_CTRL_4, ++ .val = 0x03, }, ++ { .reg = LGDT3305_DGTL_AGC_REF_1, ++ .val = 0x32, }, ++ { .reg = LGDT3305_DGTL_AGC_REF_2, ++ .val = 0xc4, }, ++ { .reg = LGDT3305_CR_CTR_FREQ_1, ++ .val = 0x00, }, ++ { .reg = LGDT3305_CR_CTR_FREQ_2, ++ .val = 0x00, }, ++ { .reg = LGDT3305_CR_CTR_FREQ_3, ++ .val = 0x00, }, ++ { .reg = LGDT3305_CR_CTR_FREQ_4, ++ .val = 0x00, }, ++ { .reg = LGDT3305_CR_CTRL_7, ++ .val = 0x79, }, ++ { .reg = LGDT3305_AGC_POWER_REF_1, ++ .val = 0x32, }, ++ { .reg = LGDT3305_AGC_POWER_REF_2, ++ .val = 0xc4, }, ++ { .reg = LGDT3305_AGC_DELAY_PT_1, ++ .val = 0x0d, }, ++ { .reg = LGDT3305_AGC_DELAY_PT_2, ++ .val = 0x30, }, ++ { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1, ++ .val = 0x80, }, ++ { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2, ++ .val = 0x00, }, ++ { .reg = LGDT3305_IFBW_1, ++ .val = 0x80, }, ++ { .reg = LGDT3305_IFBW_2, ++ .val = 0x00, }, ++ { .reg = LGDT3305_AGC_CTRL_1, ++ .val = 0x30, }, ++ { .reg = LGDT3305_AGC_CTRL_4, ++ .val = 0x61, }, ++ { .reg = LGDT3305_FEC_BLOCK_CTRL, ++ .val = 0xff, }, ++ { .reg = LGDT3305_TP_CTRL_1, ++ .val = 0x1b, }, ++ }; ++ ++ lg_dbg("\n"); ++ ++ ret = lgdt3305_write_regs(state, lgdt3305_init_data, ++ ARRAY_SIZE(lgdt3305_init_data)); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ ret = lgdt3305_soft_reset(state); ++fail: ++ return ret; ++} ++ ++static int lgdt3305_set_parameters(struct dvb_frontend *fe, ++ struct dvb_frontend_parameters *param) ++{ ++ struct lgdt3305_state *state = fe->demodulator_priv; ++ int ret; ++ ++ lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation); ++ ++ if (fe->ops.tuner_ops.set_params) { ++ ret = fe->ops.tuner_ops.set_params(fe, param); ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 0); ++ if (lg_fail(ret)) ++ goto fail; ++ state->current_frequency = param->frequency; ++ } ++ ++ ret = lgdt3305_set_modulation(state, param); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ ret = lgdt3305_passband_digital_agc(state, param); ++ if (lg_fail(ret)) ++ goto fail; ++ ret = lgdt3305_set_agc_power_ref(state, param); ++ if (lg_fail(ret)) ++ goto fail; ++ ret = lgdt3305_agc_setup(state, param); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ /* low if */ ++ ret = lgdt3305_write_reg(state, LGDT3305_GEN_CONTROL, 0x2f); ++ if (lg_fail(ret)) ++ goto fail; ++ ret = lgdt3305_set_reg_bit(state, LGDT3305_CR_CTR_FREQ_1, 6, 1); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ ret = lgdt3305_set_if(state, param); ++ if (lg_fail(ret)) ++ goto fail; ++ ret = lgdt3305_spectral_inversion(state, param, ++ state->cfg->spectral_inversion ++ ? 1 : 0); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ ret = lgdt3305_set_filter_extension(state, param); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ state->current_modulation = param->u.vsb.modulation; ++ ++ ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */ ++ ret = lgdt3305_mpeg_mode_polarity(state, ++ state->cfg->tpclk_edge, ++ state->cfg->tpvalid_polarity); ++fail: ++ return ret; ++} ++ ++static int lgdt3305_get_frontend(struct dvb_frontend *fe, ++ struct dvb_frontend_parameters *param) ++{ ++ struct lgdt3305_state *state = fe->demodulator_priv; ++ ++ lg_dbg("\n"); ++ ++ param->u.vsb.modulation = state->current_modulation; ++ param->frequency = state->current_frequency; ++ return 0; ++} ++ ++/* ------------------------------------------------------------------------ */ ++ ++static int lgdt3305_read_cr_lock_status(struct lgdt3305_state *state, ++ int *locked) ++{ ++ u8 val; ++ int ret; ++ char *cr_lock_state = ""; ++ ++ *locked = 0; ++ ++ ret = lgdt3305_read_reg(state, LGDT3305_CR_LOCK_STATUS, &val); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ switch (state->current_modulation) { ++ case QAM_256: ++ case QAM_64: ++ if (val & (1 << 1)) ++ *locked = 1; ++ ++ switch (val & 0x07) { ++ case 0: ++ cr_lock_state = "QAM UNLOCK"; ++ break; ++ case 4: ++ cr_lock_state = "QAM 1stLock"; ++ break; ++ case 6: ++ cr_lock_state = "QAM 2ndLock"; ++ break; ++ case 7: ++ cr_lock_state = "QAM FinalLock"; ++ break; ++ default: ++ cr_lock_state = "CLOCKQAM-INVALID!"; ++ break; ++ } ++ break; ++ case VSB_8: ++ if (val & (1 << 7)) { ++ *locked = 1; ++ cr_lock_state = "CLOCKVSB"; ++ } ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ lg_dbg("(%d) %s\n", *locked, cr_lock_state); ++fail: ++ return ret; ++} ++ ++static int lgdt3305_read_fec_lock_status(struct lgdt3305_state *state, ++ int *locked) ++{ ++ u8 val; ++ int ret, mpeg_lock, fec_lock, viterbi_lock; ++ ++ *locked = 0; ++ ++ switch (state->current_modulation) { ++ case QAM_256: ++ case QAM_64: ++ ret = lgdt3305_read_reg(state, ++ LGDT3305_FEC_LOCK_STATUS, &val); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ mpeg_lock = (val & (1 << 0)) ? 1 : 0; ++ fec_lock = (val & (1 << 2)) ? 1 : 0; ++ viterbi_lock = (val & (1 << 3)) ? 1 : 0; ++ ++ *locked = mpeg_lock && fec_lock && viterbi_lock; ++ ++ lg_dbg("(%d) %s%s%s\n", *locked, ++ mpeg_lock ? "mpeg lock " : "", ++ fec_lock ? "fec lock " : "", ++ viterbi_lock ? "viterbi lock" : ""); ++ break; ++ case VSB_8: ++ default: ++ ret = -EINVAL; ++ } ++fail: ++ return ret; ++} ++ ++static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status) ++{ ++ struct lgdt3305_state *state = fe->demodulator_priv; ++ u8 val; ++ int ret, signal, inlock, nofecerr, snrgood, ++ cr_lock, fec_lock, sync_lock; ++ ++ *status = 0; ++ ++ ret = lgdt3305_read_reg(state, LGDT3305_GEN_STATUS, &val); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ signal = (val & (1 << 4)) ? 1 : 0; ++ inlock = (val & (1 << 3)) ? 0 : 1; ++ sync_lock = (val & (1 << 2)) ? 1 : 0; ++ nofecerr = (val & (1 << 1)) ? 1 : 0; ++ snrgood = (val & (1 << 0)) ? 1 : 0; ++ ++ lg_dbg("%s%s%s%s%s\n", ++ signal ? "SIGNALEXIST " : "", ++ inlock ? "INLOCK " : "", ++ sync_lock ? "SYNCLOCK " : "", ++ nofecerr ? "NOFECERR " : "", ++ snrgood ? "SNRGOOD " : ""); ++ ++ ret = lgdt3305_read_cr_lock_status(state, &cr_lock); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ if (signal) ++ *status |= FE_HAS_SIGNAL; ++ if (cr_lock) ++ *status |= FE_HAS_CARRIER; ++ if (nofecerr) ++ *status |= FE_HAS_VITERBI; ++ if (sync_lock) ++ *status |= FE_HAS_SYNC; ++ ++ switch (state->current_modulation) { ++ case QAM_256: ++ case QAM_64: ++ ret = lgdt3305_read_fec_lock_status(state, &fec_lock); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ if (fec_lock) ++ *status |= FE_HAS_LOCK; ++ break; ++ case VSB_8: ++ if (inlock) ++ *status |= FE_HAS_LOCK; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++fail: ++ return ret; ++} ++ ++/* ------------------------------------------------------------------------ */ ++ ++/* borrowed from lgdt330x.c */ ++static u32 calculate_snr(u32 mse, u32 c) ++{ ++ if (mse == 0) /* no signal */ ++ return 0; ++ ++ mse = intlog10(mse); ++ if (mse > c) { ++ /* Negative SNR, which is possible, but realisticly the ++ demod will lose lock before the signal gets this bad. The ++ API only allows for unsigned values, so just return 0 */ ++ return 0; ++ } ++ return 10*(c - mse); ++} ++ ++static int lgdt3305_read_snr(struct dvb_frontend *fe, u16 *snr) ++{ ++ struct lgdt3305_state *state = fe->demodulator_priv; ++ u32 noise; /* noise value */ ++ u32 c; /* per-modulation SNR calculation constant */ ++ ++ switch (state->current_modulation) { ++ case VSB_8: ++#ifdef USE_PTMSE ++ /* Use Phase Tracker Mean-Square Error Register */ ++ /* SNR for ranges from -13.11 to +44.08 */ ++ noise = ((read_reg(state, LGDT3305_PT_MSE_1) & 0x07) << 16) | ++ (read_reg(state, LGDT3305_PT_MSE_2) << 8) | ++ (read_reg(state, LGDT3305_PT_MSE_3) & 0xff); ++ c = 73957994; /* log10(25*32^2)*2^24 */ ++#else ++ /* Use Equalizer Mean-Square Error Register */ ++ /* SNR for ranges from -16.12 to +44.08 */ ++ noise = ((read_reg(state, LGDT3305_EQ_MSE_1) & 0x0f) << 16) | ++ (read_reg(state, LGDT3305_EQ_MSE_2) << 8) | ++ (read_reg(state, LGDT3305_EQ_MSE_3) & 0xff); ++ c = 73957994; /* log10(25*32^2)*2^24 */ ++#endif ++ break; ++ case QAM_64: ++ case QAM_256: ++ noise = (read_reg(state, LGDT3305_CR_MSE_1) << 8) | ++ (read_reg(state, LGDT3305_CR_MSE_2) & 0xff); ++ ++ c = (state->current_modulation == QAM_64) ? ++ 97939837 : 98026066; ++ /* log10(688128)*2^24 and log10(696320)*2^24 */ ++ break; ++ default: ++ return -EINVAL; ++ } ++ state->snr = calculate_snr(noise, c); ++#if 0 ++ /* convert from 8.24 fixed-point to 8.8 */ ++ *snr = (state->snr) >> 16; ++#else ++ /* report SNR in dB * 10 */ ++ *snr = (state->snr / ((1 << 24) / 10)); ++#endif ++ lg_dbg("noise = 0x%08x, snr = %d.%02d dB\n", noise, ++ state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16); ++ ++ return 0; ++} ++ ++static int lgdt3305_read_signal_strength(struct dvb_frontend *fe, ++ u16 *strength) ++{ ++ /* borrowed from lgdt330x.c ++ * ++ * Calculate strength from SNR up to 35dB ++ * Even though the SNR can go higher than 35dB, ++ * there is some comfort factor in having a range of ++ * strong signals that can show at 100% ++ */ ++ struct lgdt3305_state *state = fe->demodulator_priv; ++ u16 snr; ++ int ret; ++ ++ *strength = 0; ++ ++ ret = fe->ops.read_snr(fe, &snr); ++ if (lg_fail(ret)) ++ goto fail; ++ /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ ++ /* scale the range 0 - 35*2^24 into 0 - 65535 */ ++ if (state->snr >= 8960 * 0x10000) ++ *strength = 0xffff; ++ else ++ *strength = state->snr / 8960; ++fail: ++ return ret; ++} ++ ++/* ------------------------------------------------------------------------ */ ++ ++static int lgdt3305_read_ber(struct dvb_frontend *fe, u32 *ber) ++{ ++#if 0 ++ struct lgdt3305_state *state = fe->demodulator_priv; ++ u32 period, biterror; ++ u8 bertperd; ++ ++ bertperd = read_reg(state, LGDT3305_BERT_PERIOD) & 0x1f; ++ if (bertperd < 4) ++ bertperd = 4; ++ period = (1 << bertperd); ++ ++ biterror = ++ (read_reg(state, LGDT3305_BERT_ERROR_COUNT_1) << 24) | ++ (read_reg(state, LGDT3305_BERT_ERROR_COUNT_2) << 16) | ++ (read_reg(state, LGDT3305_BERT_ERROR_COUNT_3) << 8) | ++ (read_reg(state, LGDT3305_BERT_ERROR_COUNT_4) & 0xff); ++ ++ *ber = (biterror) / period; ++ ++ lg_dbg("biterror = %d, period = %d, ber = 0x%x\n", ++ biterror, period, *ber); ++#else ++ *ber = 0; ++#endif ++ return 0; ++} ++ ++static int lgdt3305_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) ++{ ++ struct lgdt3305_state *state = fe->demodulator_priv; ++ ++ *ucblocks = ++ (read_reg(state, LGDT3305_FEC_PKT_ERR_1) << 8) | ++ (read_reg(state, LGDT3305_FEC_PKT_ERR_2) & 0xff); ++ ++ return 0; ++} ++ ++static int lgdt3305_get_tune_settings(struct dvb_frontend *fe, ++ struct dvb_frontend_tune_settings ++ *fe_tune_settings) ++{ ++ fe_tune_settings->min_delay_ms = 500; ++ lg_dbg("\n"); ++ return 0; ++} ++ ++static void lgdt3305_release(struct dvb_frontend *fe) ++{ ++ struct lgdt3305_state *state = fe->demodulator_priv; ++ lg_dbg("\n"); ++ kfree(state); ++} ++ ++static struct dvb_frontend_ops lgdt3305_ops; ++ ++struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, ++ struct i2c_adapter *i2c_adap) ++{ ++ struct lgdt3305_state *state = NULL; ++ int ret; ++ u8 val; ++ ++ lg_dbg("(%d-%04x)\n", ++ i2c_adap ? i2c_adapter_id(i2c_adap) : 0, ++ config ? config->i2c_addr : 0); ++ ++ state = kzalloc(sizeof(struct lgdt3305_state), GFP_KERNEL); ++ if (state == NULL) ++ goto fail; ++ ++ state->cfg = config; ++ state->i2c_adap = i2c_adap; ++ ++ memcpy(&state->frontend.ops, &lgdt3305_ops, ++ sizeof(struct dvb_frontend_ops)); ++ state->frontend.demodulator_priv = state; ++ ++ /* verify that we're talking to a lg dt3305 */ ++ ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val); ++ if ((lg_fail(ret)) | (val == 0)) ++ goto fail; ++ ret = lgdt3305_write_reg(state, 0x0808, 0x80); ++ if (lg_fail(ret)) ++ goto fail; ++ ret = lgdt3305_read_reg(state, 0x0808, &val); ++ if ((lg_fail(ret)) | (val != 0x80)) ++ goto fail; ++ ret = lgdt3305_write_reg(state, 0x0808, 0x00); ++ if (lg_fail(ret)) ++ goto fail; ++ ++ state->current_frequency = -1; ++ state->current_modulation = -1; ++ ++ return &state->frontend; ++fail: ++ lg_warn("unable to detect LGDT3305 hardware\n"); ++ kfree(state); ++ return NULL; ++} ++EXPORT_SYMBOL(lgdt3305_attach); ++ ++static struct dvb_frontend_ops lgdt3305_ops = { ++ .info = { ++ .name = "LG Electronics LGDT3305 VSB/QAM Frontend", ++ .type = FE_ATSC, ++ .frequency_min = 54000000, ++ .frequency_max = 858000000, ++ .frequency_stepsize = 62500, ++ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB ++ }, ++ .i2c_gate_ctrl = lgdt3305_i2c_gate_ctrl, ++ .init = lgdt3305_init, ++ .sleep = lgdt3305_sleep, ++ .set_frontend = lgdt3305_set_parameters, ++ .get_frontend = lgdt3305_get_frontend, ++ .get_tune_settings = lgdt3305_get_tune_settings, ++ .read_status = lgdt3305_read_status, ++ .read_ber = lgdt3305_read_ber, ++ .read_signal_strength = lgdt3305_read_signal_strength, ++ .read_snr = lgdt3305_read_snr, ++ .read_ucblocks = lgdt3305_read_ucblocks, ++ .release = lgdt3305_release, ++}; ++ ++MODULE_DESCRIPTION("LG Electronics LGDT3305 ATSC/QAM-B Demodulator Driver"); ++MODULE_AUTHOR("Michael Krufky "); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("0.1"); ++ ++/* ++ * Local variables: ++ * c-basic-offset: 8 ++ * End: ++ */ +diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h +new file mode 100644 +index 0000000..4fa6e52 +--- /dev/null ++++ b/drivers/media/dvb/frontends/lgdt3305.h +@@ -0,0 +1,85 @@ ++/* ++ * Support for LGDT3305 - VSB/QAM ++ * ++ * Copyright (C) 2008, 2009 Michael Krufky ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _LGDT3305_H_ ++#define _LGDT3305_H_ ++ ++#include ++#include "dvb_frontend.h" ++ ++ ++enum lgdt3305_mpeg_mode { ++ LGDT3305_MPEG_PARALLEL = 0, ++ LGDT3305_MPEG_SERIAL = 1, ++}; ++ ++enum lgdt3305_tp_clock_edge { ++ LGDT3305_TPCLK_RISING_EDGE = 0, ++ LGDT3305_TPCLK_FALLING_EDGE = 1, ++}; ++ ++enum lgdt3305_tp_valid_polarity { ++ LGDT3305_TP_VALID_LOW = 0, ++ LGDT3305_TP_VALID_HIGH = 1, ++}; ++ ++struct lgdt3305_config { ++ u8 i2c_addr; ++ ++ /* user defined IF frequency in KHz */ ++ u16 qam_if_khz; ++ u16 vsb_if_khz; ++ ++ /* AGC Power reference - defaults are used if left unset */ ++ u16 usref_8vsb; /* default: 0x32c4 */ ++ u16 usref_qam64; /* default: 0x5400 */ ++ u16 usref_qam256; /* default: 0x2a80 */ ++ ++ /* disable i2c repeater - 0:repeater enabled 1:repeater disabled */ ++ int deny_i2c_rptr:1; ++ ++ /* spectral inversion - 0:disabled 1:enabled */ ++ int spectral_inversion:1; ++ ++ /* use RF AGC loop - 0:disabled 1:enabled */ ++ int rf_agc_loop:1; ++ ++ enum lgdt3305_mpeg_mode mpeg_mode; ++ enum lgdt3305_tp_clock_edge tpclk_edge; ++ enum lgdt3305_tp_valid_polarity tpvalid_polarity; ++}; ++ ++#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \ ++ defined(MODULE)) ++extern ++struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, ++ struct i2c_adapter *i2c_adap); ++#else ++static inline ++struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, ++ struct i2c_adapter *i2c_adap) ++{ ++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); ++ return NULL; ++} ++#endif /* CONFIG_DVB_LGDT3305 */ ++ ++#endif /* _LGDT3305_H_ */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0113-ACPI-backport-of-WMI-from-2.6.28-LP-334505.patch +++ linux-2.6.24/patches/0113-ACPI-backport-of-WMI-from-2.6.28-LP-334505.patch @@ -0,0 +1,859 @@ +From 0ba3ea36869295d7453fbff98ed93d190eb8fa86 Mon Sep 17 00:00:00 2001 +From: Tony Espy +Date: Wed, 1 Apr 2009 20:17:53 -0400 +Subject: [PATCH 113/170] ACPI: backport of WMI from 2.6.28 ( LP: 334505 ). + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/334505 +Signed-off-by: Tony Espy +--- + debian/binary-custom.d/lpia/config.lpia | 1 + + drivers/acpi/Kconfig | 21 + + drivers/acpi/Makefile | 1 + + drivers/acpi/wmi.c | 747 +++++++++++++++++++++++++++++++ + include/linux/acpi.h | 20 + + 5 files changed, 790 insertions(+), 0 deletions(-) + create mode 100644 drivers/acpi/wmi.c + +diff --git a/debian/binary-custom.d/lpia/config.lpia b/debian/binary-custom.d/lpia/config.lpia +index 4bbc3d0..d575dd5 100644 +--- a/debian/binary-custom.d/lpia/config.lpia ++++ b/debian/binary-custom.d/lpia/config.lpia +@@ -307,6 +307,7 @@ CONFIG_ACPI_POWER=y + CONFIG_ACPI_SYSTEM=y + CONFIG_X86_PM_TIMER=y + CONFIG_ACPI_CONTAINER=y ++CONFIG_ACPI_WMI=y + CONFIG_ACPI_SBS=y + CONFIG_SOUND=m + # CONFIG_SOUND_PRIME is not set +diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig +index aa608a2..5b543e1 100644 +--- a/drivers/acpi/Kconfig ++++ b/drivers/acpi/Kconfig +@@ -199,6 +199,27 @@ config ACPI_NUMA + depends on (X86 || IA64) + default y if IA64_GENERIC || IA64_SGI_SN2 + ++config ACPI_WMI ++ tristate "WMI" ++ depends on X86 ++ help ++ This driver adds support for the ACPI-WMI (Windows Management ++ Instrumentation) mapper device (PNP0C14) found on some systems. ++ ++ ACPI-WMI is a proprietary extension to ACPI to expose parts of the ++ ACPI firmware to userspace - this is done through various vendor ++ defined methods and data blocks in a PNP0C14 device, which are then ++ made available for userspace to call. ++ ++ The implementation of this in Linux currently only exposes this to ++ other kernel space drivers. ++ ++ This driver is a required dependency to build the firmware specific ++ drivers needed on many machines, including Acer and HP laptops. ++ ++ It is safe to enable this driver even if your DSDT doesn't define ++ any ACPI-WMI devices. ++ + config ACPI_ASUS + tristate "ASUS/Medion Laptop Extras" + depends on X86 +diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile +index 945c4cf..9938d06 100644 +--- a/drivers/acpi/Makefile ++++ b/drivers/acpi/Makefile +@@ -55,6 +55,7 @@ obj-$(CONFIG_ACPI_THERMAL) += thermal.o + obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o + obj-$(CONFIG_ACPI_DEBUG) += debug.o + obj-$(CONFIG_ACPI_NUMA) += numa.o ++obj-$(CONFIG_ACPI_WMI) += wmi.o + obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o + obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o + obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o +diff --git a/drivers/acpi/wmi.c b/drivers/acpi/wmi.c +new file mode 100644 +index 0000000..47cd7ba +--- /dev/null ++++ b/drivers/acpi/wmi.c +@@ -0,0 +1,747 @@ ++/* ++ * ACPI-WMI mapping driver ++ * ++ * Copyright (C) 2007-2008 Carlos Corbacho ++ * ++ * GUID parsing code from ldm.c is: ++ * Copyright (C) 2001,2002 Richard Russon ++ * Copyright (c) 2001-2007 Anton Altaparmakov ++ * Copyright (C) 2001,2002 Jakob Kemi ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or (at ++ * your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ACPI_MODULE_NAME("wmi"); ++MODULE_AUTHOR("Carlos Corbacho"); ++MODULE_DESCRIPTION("ACPI-WMI Mapping Driver"); ++MODULE_LICENSE("GPL"); ++ ++#define ACPI_WMI_CLASS "wmi" ++ ++#undef PREFIX ++#define PREFIX "ACPI: WMI: " ++ ++static DEFINE_MUTEX(wmi_data_lock); ++ ++struct guid_block { ++ char guid[16]; ++ union { ++ char object_id[2]; ++ struct { ++ unsigned char notify_id; ++ unsigned char reserved; ++ }; ++ }; ++ u8 instance_count; ++ u8 flags; ++}; ++ ++struct wmi_block { ++ struct list_head list; ++ struct guid_block gblock; ++ acpi_handle handle; ++ wmi_notify_handler handler; ++ void *handler_data; ++}; ++ ++static struct wmi_block wmi_blocks; ++ ++/* ++ * If the GUID data block is marked as expensive, we must enable and ++ * explicitily disable data collection. ++ */ ++#define ACPI_WMI_EXPENSIVE 0x1 ++#define ACPI_WMI_METHOD 0x2 /* GUID is a method */ ++#define ACPI_WMI_STRING 0x4 /* GUID takes & returns a string */ ++#define ACPI_WMI_EVENT 0x8 /* GUID is an event */ ++ ++static int acpi_wmi_remove(struct acpi_device *device, int type); ++static int acpi_wmi_add(struct acpi_device *device); ++ ++static const struct acpi_device_id wmi_device_ids[] = { ++ {"PNP0C14", 0}, ++ {"pnp0c14", 0}, ++ {"", 0}, ++}; ++MODULE_DEVICE_TABLE(acpi, wmi_device_ids); ++ ++static struct acpi_driver acpi_wmi_driver = { ++ .name = "wmi", ++ .class = ACPI_WMI_CLASS, ++ .ids = wmi_device_ids, ++ .ops = { ++ .add = acpi_wmi_add, ++ .remove = acpi_wmi_remove, ++ }, ++}; ++ ++/* ++ * GUID parsing functions ++ */ ++ ++/** ++ * wmi_parse_hexbyte - Convert a ASCII hex number to a byte ++ * @src: Pointer to at least 2 characters to convert. ++ * ++ * Convert a two character ASCII hex string to a number. ++ * ++ * Return: 0-255 Success, the byte was parsed correctly ++ * -1 Error, an invalid character was supplied ++ */ ++static int wmi_parse_hexbyte(const u8 *src) ++{ ++ unsigned int x; /* For correct wrapping */ ++ int h; ++ ++ /* high part */ ++ x = src[0]; ++ if (x - '0' <= '9' - '0') { ++ h = x - '0'; ++ } else if (x - 'a' <= 'f' - 'a') { ++ h = x - 'a' + 10; ++ } else if (x - 'A' <= 'F' - 'A') { ++ h = x - 'A' + 10; ++ } else { ++ return -1; ++ } ++ h <<= 4; ++ ++ /* low part */ ++ x = src[1]; ++ if (x - '0' <= '9' - '0') ++ return h | (x - '0'); ++ if (x - 'a' <= 'f' - 'a') ++ return h | (x - 'a' + 10); ++ if (x - 'A' <= 'F' - 'A') ++ return h | (x - 'A' + 10); ++ return -1; ++} ++ ++/** ++ * wmi_swap_bytes - Rearrange GUID bytes to match GUID binary ++ * @src: Memory block holding binary GUID (16 bytes) ++ * @dest: Memory block to hold byte swapped binary GUID (16 bytes) ++ * ++ * Byte swap a binary GUID to match it's real GUID value ++ */ ++static void wmi_swap_bytes(u8 *src, u8 *dest) ++{ ++ int i; ++ ++ for (i = 0; i <= 3; i++) ++ memcpy(dest + i, src + (3 - i), 1); ++ ++ for (i = 0; i <= 1; i++) ++ memcpy(dest + 4 + i, src + (5 - i), 1); ++ ++ for (i = 0; i <= 1; i++) ++ memcpy(dest + 6 + i, src + (7 - i), 1); ++ ++ memcpy(dest + 8, src + 8, 8); ++} ++ ++/** ++ * wmi_parse_guid - Convert GUID from ASCII to binary ++ * @src: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba ++ * @dest: Memory block to hold binary GUID (16 bytes) ++ * ++ * N.B. The GUID need not be NULL terminated. ++ * ++ * Return: 'true' @dest contains binary GUID ++ * 'false' @dest contents are undefined ++ */ ++static bool wmi_parse_guid(const u8 *src, u8 *dest) ++{ ++ static const int size[] = { 4, 2, 2, 2, 6 }; ++ int i, j, v; ++ ++ if (src[8] != '-' || src[13] != '-' || ++ src[18] != '-' || src[23] != '-') ++ return false; ++ ++ for (j = 0; j < 5; j++, src++) { ++ for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) { ++ v = wmi_parse_hexbyte(src); ++ if (v < 0) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static bool find_guid(const char *guid_string, struct wmi_block **out) ++{ ++ char tmp[16], guid_input[16]; ++ struct wmi_block *wblock; ++ struct guid_block *block; ++ struct list_head *p; ++ ++ wmi_parse_guid(guid_string, tmp); ++ wmi_swap_bytes(tmp, guid_input); ++ ++ list_for_each(p, &wmi_blocks.list) { ++ wblock = list_entry(p, struct wmi_block, list); ++ block = &wblock->gblock; ++ ++ if (memcmp(block->guid, guid_input, 16) == 0) { ++ if (out) ++ *out = wblock; ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable) ++{ ++ struct guid_block *block = NULL; ++ char method[5]; ++ struct acpi_object_list input; ++ union acpi_object params[1]; ++ acpi_status status; ++ acpi_handle handle; ++ ++ block = &wblock->gblock; ++ handle = wblock->handle; ++ ++ if (!block) ++ return AE_NOT_EXIST; ++ ++ input.count = 1; ++ input.pointer = params; ++ params[0].type = ACPI_TYPE_INTEGER; ++ params[0].integer.value = enable; ++ ++ snprintf(method, 5, "WE%02X", block->notify_id); ++ status = acpi_evaluate_object(handle, method, &input, NULL); ++ ++ if (status != AE_OK && status != AE_NOT_FOUND) ++ return status; ++ else ++ return AE_OK; ++} ++ ++/* ++ * Exported WMI functions ++ */ ++/** ++ * wmi_evaluate_method - Evaluate a WMI method ++ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba ++ * @instance: Instance index ++ * @method_id: Method ID to call ++ * &in: Buffer containing input for the method call ++ * &out: Empty buffer to return the method results ++ * ++ * Call an ACPI-WMI method ++ */ ++acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, ++u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) ++{ ++ struct guid_block *block = NULL; ++ struct wmi_block *wblock = NULL; ++ acpi_handle handle; ++ acpi_status status; ++ struct acpi_object_list input; ++ union acpi_object params[3]; ++ char method[4] = "WM"; ++ ++ if (!find_guid(guid_string, &wblock)) ++ return AE_ERROR; ++ ++ block = &wblock->gblock; ++ handle = wblock->handle; ++ ++ if (!(block->flags & ACPI_WMI_METHOD)) ++ return AE_BAD_DATA; ++ ++ if (block->instance_count < instance) ++ return AE_BAD_PARAMETER; ++ ++ input.count = 2; ++ input.pointer = params; ++ params[0].type = ACPI_TYPE_INTEGER; ++ params[0].integer.value = instance; ++ params[1].type = ACPI_TYPE_INTEGER; ++ params[1].integer.value = method_id; ++ ++ if (in) { ++ input.count = 3; ++ ++ if (block->flags & ACPI_WMI_STRING) { ++ params[2].type = ACPI_TYPE_STRING; ++ } else { ++ params[2].type = ACPI_TYPE_BUFFER; ++ } ++ params[2].buffer.length = in->length; ++ params[2].buffer.pointer = in->pointer; ++ } ++ ++ strncat(method, block->object_id, 2); ++ ++ status = acpi_evaluate_object(handle, method, &input, out); ++ ++ return status; ++} ++EXPORT_SYMBOL_GPL(wmi_evaluate_method); ++ ++/** ++ * wmi_query_block - Return contents of a WMI block ++ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba ++ * @instance: Instance index ++ * &out: Empty buffer to return the contents of the data block to ++ * ++ * Return the contents of an ACPI-WMI data block to a buffer ++ */ ++acpi_status wmi_query_block(const char *guid_string, u8 instance, ++struct acpi_buffer *out) ++{ ++ struct guid_block *block = NULL; ++ struct wmi_block *wblock = NULL; ++ acpi_handle handle, wc_handle; ++ acpi_status status, wc_status = AE_ERROR; ++ struct acpi_object_list input, wc_input; ++ union acpi_object wc_params[1], wq_params[1]; ++ char method[4]; ++ char wc_method[4] = "WC"; ++ ++ if (!guid_string || !out) ++ return AE_BAD_PARAMETER; ++ ++ if (!find_guid(guid_string, &wblock)) ++ return AE_ERROR; ++ ++ block = &wblock->gblock; ++ handle = wblock->handle; ++ ++ if (block->instance_count < instance) ++ return AE_BAD_PARAMETER; ++ ++ /* Check GUID is a data block */ ++ if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) ++ return AE_ERROR; ++ ++ input.count = 1; ++ input.pointer = wq_params; ++ wq_params[0].type = ACPI_TYPE_INTEGER; ++ wq_params[0].integer.value = instance; ++ ++ /* ++ * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to ++ * enable collection. ++ */ ++ if (block->flags & ACPI_WMI_EXPENSIVE) { ++ wc_input.count = 1; ++ wc_input.pointer = wc_params; ++ wc_params[0].type = ACPI_TYPE_INTEGER; ++ wc_params[0].integer.value = 1; ++ ++ strncat(wc_method, block->object_id, 2); ++ ++ /* ++ * Some GUIDs break the specification by declaring themselves ++ * expensive, but have no corresponding WCxx method. So we ++ * should not fail if this happens. ++ */ ++ wc_status = acpi_get_handle(handle, wc_method, &wc_handle); ++ if (ACPI_SUCCESS(wc_status)) ++ wc_status = acpi_evaluate_object(handle, wc_method, ++ &wc_input, NULL); ++ } ++ ++ strcpy(method, "WQ"); ++ strncat(method, block->object_id, 2); ++ ++ status = acpi_evaluate_object(handle, method, &input, out); ++ ++ /* ++ * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if ++ * the WQxx method failed - we should disable collection anyway. ++ */ ++ if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) { ++ wc_params[0].integer.value = 0; ++ status = acpi_evaluate_object(handle, ++ wc_method, &wc_input, NULL); ++ } ++ ++ return status; ++} ++EXPORT_SYMBOL_GPL(wmi_query_block); ++ ++/** ++ * wmi_set_block - Write to a WMI block ++ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba ++ * @instance: Instance index ++ * &in: Buffer containing new values for the data block ++ * ++ * Write the contents of the input buffer to an ACPI-WMI data block ++ */ ++acpi_status wmi_set_block(const char *guid_string, u8 instance, ++const struct acpi_buffer *in) ++{ ++ struct guid_block *block = NULL; ++ struct wmi_block *wblock = NULL; ++ acpi_handle handle; ++ struct acpi_object_list input; ++ union acpi_object params[2]; ++ char method[4] = "WS"; ++ ++ if (!guid_string || !in) ++ return AE_BAD_DATA; ++ ++ if (!find_guid(guid_string, &wblock)) ++ return AE_ERROR; ++ ++ block = &wblock->gblock; ++ handle = wblock->handle; ++ ++ if (block->instance_count < instance) ++ return AE_BAD_PARAMETER; ++ ++ /* Check GUID is a data block */ ++ if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) ++ return AE_ERROR; ++ ++ input.count = 2; ++ input.pointer = params; ++ params[0].type = ACPI_TYPE_INTEGER; ++ params[0].integer.value = instance; ++ ++ if (block->flags & ACPI_WMI_STRING) { ++ params[1].type = ACPI_TYPE_STRING; ++ } else { ++ params[1].type = ACPI_TYPE_BUFFER; ++ } ++ params[1].buffer.length = in->length; ++ params[1].buffer.pointer = in->pointer; ++ ++ strncat(method, block->object_id, 2); ++ ++ return acpi_evaluate_object(handle, method, &input, NULL); ++} ++EXPORT_SYMBOL_GPL(wmi_set_block); ++ ++/** ++ * wmi_install_notify_handler - Register handler for WMI events ++ * @handler: Function to handle notifications ++ * @data: Data to be returned to handler when event is fired ++ * ++ * Register a handler for events sent to the ACPI-WMI mapper device. ++ */ ++acpi_status wmi_install_notify_handler(const char *guid, ++wmi_notify_handler handler, void *data) ++{ ++ struct wmi_block *block; ++ acpi_status status; ++ ++ if (!guid || !handler) ++ return AE_BAD_PARAMETER; ++ ++ find_guid(guid, &block); ++ if (!block) ++ return AE_NOT_EXIST; ++ ++ if (block->handler) ++ return AE_ALREADY_ACQUIRED; ++ ++ block->handler = handler; ++ block->handler_data = data; ++ ++ status = wmi_method_enable(block, 1); ++ ++ return status; ++} ++EXPORT_SYMBOL_GPL(wmi_install_notify_handler); ++ ++/** ++ * wmi_uninstall_notify_handler - Unregister handler for WMI events ++ * ++ * Unregister handler for events sent to the ACPI-WMI mapper device. ++ */ ++acpi_status wmi_remove_notify_handler(const char *guid) ++{ ++ struct wmi_block *block; ++ acpi_status status; ++ ++ if (!guid) ++ return AE_BAD_PARAMETER; ++ ++ find_guid(guid, &block); ++ if (!block) ++ return AE_NOT_EXIST; ++ ++ if (!block->handler) ++ return AE_NULL_ENTRY; ++ ++ status = wmi_method_enable(block, 0); ++ ++ block->handler = NULL; ++ block->handler_data = NULL; ++ ++ return status; ++} ++EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); ++ ++/** ++ * wmi_get_event_data - Get WMI data associated with an event ++ * ++ * @event - Event to find ++ * &out - Buffer to hold event data ++ * ++ * Returns extra data associated with an event in WMI. ++ */ ++acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out) ++{ ++ struct acpi_object_list input; ++ union acpi_object params[1]; ++ struct guid_block *gblock; ++ struct wmi_block *wblock; ++ struct list_head *p; ++ ++ input.count = 1; ++ input.pointer = params; ++ params[0].type = ACPI_TYPE_INTEGER; ++ params[0].integer.value = event; ++ ++ list_for_each(p, &wmi_blocks.list) { ++ wblock = list_entry(p, struct wmi_block, list); ++ gblock = &wblock->gblock; ++ ++ if ((gblock->flags & ACPI_WMI_EVENT) && ++ (gblock->notify_id == event)) ++ return acpi_evaluate_object(wblock->handle, "_WED", ++ &input, out); ++ } ++ ++ return AE_NOT_FOUND; ++} ++EXPORT_SYMBOL_GPL(wmi_get_event_data); ++ ++/** ++ * wmi_has_guid - Check if a GUID is available ++ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba ++ * ++ * Check if a given GUID is defined by _WDG ++ */ ++bool wmi_has_guid(const char *guid_string) ++{ ++ return find_guid(guid_string, NULL); ++} ++EXPORT_SYMBOL_GPL(wmi_has_guid); ++ ++/* ++ * Parse the _WDG method for the GUID data blocks ++ */ ++static __init acpi_status parse_wdg(acpi_handle handle) ++{ ++ struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; ++ union acpi_object *obj; ++ struct guid_block *gblock; ++ struct wmi_block *wblock; ++ acpi_status status; ++ u32 i, total; ++ ++ status = acpi_evaluate_object(handle, "_WDG", NULL, &out); ++ ++ if (ACPI_FAILURE(status)) ++ return status; ++ ++ obj = (union acpi_object *) out.pointer; ++ ++ if (obj->type != ACPI_TYPE_BUFFER) ++ return AE_ERROR; ++ ++ total = obj->buffer.length / sizeof(struct guid_block); ++ ++ gblock = kzalloc(obj->buffer.length, GFP_KERNEL); ++ if (!gblock) ++ return AE_NO_MEMORY; ++ ++ memcpy(gblock, obj->buffer.pointer, obj->buffer.length); ++ ++ for (i = 0; i < total; i++) { ++ wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); ++ if (!wblock) ++ return AE_NO_MEMORY; ++ ++ wblock->gblock = gblock[i]; ++ wblock->handle = handle; ++ list_add_tail(&wblock->list, &wmi_blocks.list); ++ } ++ ++ kfree(out.pointer); ++ kfree(gblock); ++ ++ return status; ++} ++ ++/* ++ * WMI can have EmbeddedControl access regions. In which case, we just want to ++ * hand these off to the EC driver. ++ */ ++static acpi_status ++acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address, ++ u32 bits, acpi_integer * value, ++ void *handler_context, void *region_context) ++{ ++ int result = 0, i = 0; ++ u8 temp = 0; ++ ++ if ((address > 0xFF) || !value) ++ return AE_BAD_PARAMETER; ++ ++ if (function != ACPI_READ && function != ACPI_WRITE) ++ return AE_BAD_PARAMETER; ++ ++ if (bits != 8) ++ return AE_BAD_PARAMETER; ++ ++ if (function == ACPI_READ) { ++ result = ec_read(address, &temp); ++ (*value) |= ((acpi_integer)temp) << i; ++ } else { ++ temp = 0xff & ((*value) >> i); ++ result = ec_write(address, temp); ++ } ++ ++ switch (result) { ++ case -EINVAL: ++ return AE_BAD_PARAMETER; ++ break; ++ case -ENODEV: ++ return AE_NOT_FOUND; ++ break; ++ case -ETIME: ++ return AE_TIME; ++ break; ++ default: ++ return AE_OK; ++ } ++} ++ ++static void acpi_wmi_notify(acpi_handle handle, u32 event, void *data) ++{ ++ struct guid_block *block; ++ struct wmi_block *wblock; ++ struct list_head *p; ++ struct acpi_device *device = data; ++ ++ list_for_each(p, &wmi_blocks.list) { ++ wblock = list_entry(p, struct wmi_block, list); ++ block = &wblock->gblock; ++ ++ if ((block->flags & ACPI_WMI_EVENT) && ++ (block->notify_id == event)) { ++ if (wblock->handler) ++ wblock->handler(event, wblock->handler_data); ++ ++ acpi_bus_generate_netlink_event( ++ device->pnp.device_class, device->dev.bus_id, ++ event, 0); ++ break; ++ } ++ } ++} ++ ++static int acpi_wmi_remove(struct acpi_device *device, int type) ++{ ++ acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, ++ acpi_wmi_notify); ++ ++ acpi_remove_address_space_handler(device->handle, ++ ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); ++ ++ return 0; ++} ++ ++static int __init acpi_wmi_add(struct acpi_device *device) ++{ ++ acpi_status status; ++ int result = 0; ++ ++ status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, ++ acpi_wmi_notify, device); ++ if (ACPI_FAILURE(status)) { ++ printk(KERN_ERR PREFIX "Error installing notify handler\n"); ++ return -ENODEV; ++ } ++ ++ status = acpi_install_address_space_handler(device->handle, ++ ACPI_ADR_SPACE_EC, ++ &acpi_wmi_ec_space_handler, ++ NULL, NULL); ++ if (ACPI_FAILURE(status)) ++ return -ENODEV; ++ ++ status = parse_wdg(device->handle); ++ if (ACPI_FAILURE(status)) { ++ printk(KERN_ERR PREFIX "Error installing EC region handler\n"); ++ return -ENODEV; ++ } ++ ++ return result; ++} ++ ++static int __init acpi_wmi_init(void) ++{ ++ acpi_status result; ++ ++ INIT_LIST_HEAD(&wmi_blocks.list); ++ ++ if (acpi_disabled) ++ return -ENODEV; ++ ++ result = acpi_bus_register_driver(&acpi_wmi_driver); ++ ++ if (result < 0) { ++ printk(KERN_INFO PREFIX "Error loading mapper\n"); ++ } else { ++ printk(KERN_INFO PREFIX "Mapper loaded\n"); ++ } ++ ++ return result; ++} ++ ++static void __exit acpi_wmi_exit(void) ++{ ++ struct list_head *p, *tmp; ++ struct wmi_block *wblock; ++ ++ acpi_bus_unregister_driver(&acpi_wmi_driver); ++ ++ list_for_each_safe(p, tmp, &wmi_blocks.list) { ++ wblock = list_entry(p, struct wmi_block, list); ++ ++ list_del(p); ++ kfree(wblock); ++ } ++ ++ printk(KERN_INFO PREFIX "Mapper unloaded\n"); ++} ++ ++subsys_initcall(acpi_wmi_init); ++module_exit(acpi_wmi_exit); +diff --git a/include/linux/acpi.h b/include/linux/acpi.h +index 63f2e6e..fab9f70 100644 +--- a/include/linux/acpi.h ++++ b/include/linux/acpi.h +@@ -192,6 +192,26 @@ extern int ec_transaction(u8 command, + + #endif /*CONFIG_ACPI_EC*/ + ++#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE) ++ ++typedef void (*wmi_notify_handler) (u32 value, void *context); ++ ++extern acpi_status wmi_evaluate_method(const char *guid, u8 instance, ++ u32 method_id, ++ const struct acpi_buffer *in, ++ struct acpi_buffer *out); ++extern acpi_status wmi_query_block(const char *guid, u8 instance, ++ struct acpi_buffer *out); ++extern acpi_status wmi_set_block(const char *guid, u8 instance, ++ const struct acpi_buffer *in); ++extern acpi_status wmi_install_notify_handler(const char *guid, ++ wmi_notify_handler handler, void *data); ++extern acpi_status wmi_remove_notify_handler(const char *guid); ++extern acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out); ++extern bool wmi_has_guid(const char *guid); ++ ++#endif /* CONFIG_ACPI_WMI */ ++ + extern int acpi_blacklisted(void); + #ifdef CONFIG_DMI + extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0047-UBUNTU-NBK-Ubuntu-2.6.24-19.36netbook1.patch +++ linux-2.6.24/patches/0047-UBUNTU-NBK-Ubuntu-2.6.24-19.36netbook1.patch @@ -0,0 +1,30 @@ +From b7418e6ad7e68a1d484d0f5a5c5cc87a078bcfe8 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 23 Jul 2008 11:52:56 +0100 +Subject: [PATCH 047/170] UBUNTU: NBK-Ubuntu-2.6.24-19.36netbook1 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index ecf0d5c..35c0892 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-19.36netbook1) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * Bumped release to match Hardy ++ ++ -- Michael Frey Wed, 23 Jul 2008 11:51:20 +0100 ++ + linux (2.6.24-19.35netbook4) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0059-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook3.patch +++ linux-2.6.24/patches/0059-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook3.patch @@ -0,0 +1,33 @@ +From 5011c6f0023d0c33e70833c291c8ef1e4665313e Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 17 Sep 2008 11:26:46 -0400 +Subject: [PATCH 059/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook3 + +Ignore: yes +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/changelog | 11 +++++++++++ + 1 files changed, 11 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 6d6e647..b1dfd8f 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,14 @@ ++linux (2.6.24-19.41netbook3) hardy; urgency=low ++ ++ [Michael Frey] ++ ++ * Applied "USB: another ehci_iaa_watchdog fix" from upstream kernel ++ * Git commit cdc647a9b75741659bfc6acc44a6b3a646ad53bf ++ * Fixes ehci lockup issue on resume from S3 ++ * Fixes LP#243047 and LP#253053 ++ ++ -- Michael Frey Wed, 17 Sep 2008 11:20:07 -0400 ++ + linux (2.6.24-19.41netbook2) hardy; urgency=low + + [Michael Frey] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0089-Turn-on-Elantech-PS-2-touchpad-option.patch +++ linux-2.6.24/patches/0089-Turn-on-Elantech-PS-2-touchpad-option.patch @@ -0,0 +1,25 @@ +From fc6fdbf9172f0cbefde3b047d5374d18881c4a5d Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Wed, 17 Dec 2008 11:45:14 -0500 +Subject: [PATCH 089/170] Turn on Elantech PS/2 touchpad option + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + debian/binary-custom.d/lpia/config.lpia | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/debian/binary-custom.d/lpia/config.lpia b/debian/binary-custom.d/lpia/config.lpia +index 87eb1ef..76d8699 100644 +--- a/debian/binary-custom.d/lpia/config.lpia ++++ b/debian/binary-custom.d/lpia/config.lpia +@@ -1734,6 +1734,7 @@ CONFIG_MOUSE_PS2_LOGIPS2PP=y + CONFIG_MOUSE_PS2_SYNAPTICS=y + CONFIG_MOUSE_PS2_LIFEBOOK=y + CONFIG_MOUSE_PS2_TRACKPOINT=y ++CONFIG_MOUSE_PS2_ELANTECH=y + # CONFIG_MOUSE_PS2_TOUCHKIT is not set + CONFIG_MOUSE_SERIAL=m + CONFIG_MOUSE_APPLETOUCH=m +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0138-bluetooth-delete-timer-in-l2cap_conn_del.patch +++ linux-2.6.24/patches/0138-bluetooth-delete-timer-in-l2cap_conn_del.patch @@ -0,0 +1,33 @@ +From c29b3e9b4d51751024fd61006b6a037b9520652d Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 20 Apr 2009 15:58:55 -0400 +Subject: [PATCH 138/170] bluetooth: delete timer in l2cap_conn_del() + +Delete a possibly armed timer before kfree'ing the connection object. + +Solves: http://lkml.org/lkml/2008/2/15/514 + +Reported-by:Quel Qun +Signed-off-by: Thomas Gleixner +Signed-off-by: David S. Miller +Signed-off-by: Andres Salomon +--- + net/bluetooth/l2cap.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c +index 477e052..e165c9b 100644 +--- a/net/bluetooth/l2cap.c ++++ b/net/bluetooth/l2cap.c +@@ -426,6 +426,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) + l2cap_sock_kill(sk); + } + ++ del_timer_sync(&conn->info_timer); ++ + hcon->l2cap_data = NULL; + kfree(conn); + } +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0103-UBUNTU-dib0700-add-support-for-Hauppauge-Nova-TD-Sti.patch +++ linux-2.6.24/patches/0103-UBUNTU-dib0700-add-support-for-Hauppauge-Nova-TD-Sti.patch @@ -0,0 +1,65 @@ +From 633338673fb3b427a36ef9148055d38dad818b5d Mon Sep 17 00:00:00 2001 +From: Michael Krufky +Date: Fri, 20 Mar 2009 16:28:53 -0400 +Subject: [PATCH 103/170] UBUNTU: dib0700: add support for Hauppauge Nova-TD Stick 52009 + +OriginalAuthor: Michael Krufky +OriginalLocation: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff_plain;h=d01eb2dc7d5265ec3bee9ec1b8ab79155e1310d6 + +backported upstream changeset: +V4L/DVB (8186): dib0700: add support for Hauppauge Nova-TD Stick 52009 + +Signed-off-by: Michael Krufky +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- + drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + + 2 files changed, 7 insertions(+), 1 deletions(-) + +diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c +index a7083d0..89e9dbf 100644 +--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c ++++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c +@@ -841,6 +841,7 @@ struct usb_device_id dib0700_usb_id_table[] = { + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, ++ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, + /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, + { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, + { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, +@@ -1082,7 +1083,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { + } + }, + +- .num_device_descs = 2, ++ .num_device_descs = 3, + .devices = { + { "DiBcom STK7070PD reference design", + { &dib0700_usb_id_table[17], NULL }, +@@ -1092,6 +1093,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { + { &dib0700_usb_id_table[18], NULL }, + { NULL }, + }, ++ { "Hauppauge Nova-TD Stick (52009)", ++ { &dib0700_usb_id_table[26], NULL }, ++ { NULL }, ++ }, + } + }, + }; +diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +index 32a025d..c28f8d5 100644 +--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h ++++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +@@ -125,6 +125,7 @@ + #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 + #define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 + #define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 ++#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009 0x5200 + #define USB_PID_AVERMEDIA_EXPRESS 0xb568 + #define USB_PID_AVERMEDIA_VOLAR 0xa807 + #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0102-UBUNTU-V4L-DVB-7071-DiB0700-Start-streaming-the-righ.patch +++ linux-2.6.24/patches/0102-UBUNTU-V4L-DVB-7071-DiB0700-Start-streaming-the-righ.patch @@ -0,0 +1,41 @@ +From 70befa834ef34c7a9ed4e8e627ca3af577698253 Mon Sep 17 00:00:00 2001 +From: Patrick Boettcher +Date: Fri, 25 Jan 2008 06:37:57 -0300 +Subject: [PATCH 102/170] UBUNTU: V4L/DVB (7071): DiB0700: Start streaming the right way + +There was a mistake in the way how to start the streaming in the dib0700. This patch fixes that. + +Signed-off-by: Patrick Boettcher +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Michael Krufky +(cherry picked from commit a162abb06bda3f38750a208e85e27f419798aa79) +--- + drivers/media/dvb/dvb-usb/dib0700_core.c | 5 +---- + 1 files changed, 1 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c +index 3ea294e..c9857d5 100644 +--- a/drivers/media/dvb/dvb-usb/dib0700_core.c ++++ b/drivers/media/dvb/dvb-usb/dib0700_core.c +@@ -243,7 +243,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) + u8 b[4]; + + b[0] = REQUEST_ENABLE_VIDEO; +- b[1] = 0x00; ++ b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ + b[2] = (0x01 << 4); /* Master mode */ + b[3] = 0x00; + +@@ -256,9 +256,6 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) + + b[2] |= st->channel_state; + +- if (st->channel_state) /* if at least one channel is active */ +- b[1] = (0x01 << 4) | 0x00; +- + deb_info("data for streaming: %x %x\n",b[1],b[2]); + + return dib0700_ctrl_wr(adap->dev, b, 4); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0041-New-Memory-Stick-block-driver.patch +++ linux-2.6.24/patches/0041-New-Memory-Stick-block-driver.patch @@ -0,0 +1,3562 @@ +From 3d208118a02b6d7167a426c1357154601bdf8749 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Tue, 15 Jul 2008 13:56:20 +0100 +Subject: [PATCH 041/170] New Memory Stick block driver + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/mmc/ms/Makefile | 6 + + drivers/mmc/ms/jmb38x_ms.c | 985 +++++++++++++++++++++++++++ + drivers/mmc/ms/memstick.c | 665 +++++++++++++++++++ + drivers/mmc/ms/memstick.h | 342 ++++++++++ + drivers/mmc/ms/mspro_block.c | 1512 ++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 3510 insertions(+), 0 deletions(-) + create mode 100644 drivers/mmc/ms/Makefile + create mode 100644 drivers/mmc/ms/jmb38x_ms.c + create mode 100644 drivers/mmc/ms/memstick.c + create mode 100644 drivers/mmc/ms/memstick.h + create mode 100644 drivers/mmc/ms/mspro_block.c + +diff --git a/drivers/mmc/ms/Makefile b/drivers/mmc/ms/Makefile +new file mode 100644 +index 0000000..3f82524 +--- /dev/null ++++ b/drivers/mmc/ms/Makefile +@@ -0,0 +1,6 @@ ++ifeq ($(CONFIG_MMC_DEBUG),y) ++ EXTRA_CFLAGS += -DDEBUG ++endif ++ ++obj-$(CONFIG_MSPRO) += memstick.o mspro_block.o jmb38x_ms.o ++ +diff --git a/drivers/mmc/ms/jmb38x_ms.c b/drivers/mmc/ms/jmb38x_ms.c +new file mode 100644 +index 0000000..e606012 +--- /dev/null ++++ b/drivers/mmc/ms/jmb38x_ms.c +@@ -0,0 +1,985 @@ ++/* ++ * jmb38x_ms.c - JMicron jmb38x MemoryStick card reader ++ * ++ * Copyright (C) 2008 Alex Dubov ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "memstick.h" ++ ++#define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383 ++#define DRIVER_NAME "jmb38x_ms" ++#define DRIVER_VERSION "Rev133" ++ ++static int no_dma; ++module_param(no_dma, bool, 0644); ++ ++enum { ++ DMA_ADDRESS = 0x00, ++ BLOCK = 0x04, ++ DMA_CONTROL = 0x08, ++ TPC_P0 = 0x0c, ++ TPC_P1 = 0x10, ++ TPC = 0x14, ++ HOST_CONTROL = 0x18, ++ DATA = 0x1c, ++ STATUS = 0x20, ++ INT_STATUS = 0x24, ++ INT_STATUS_ENABLE = 0x28, ++ INT_SIGNAL_ENABLE = 0x2c, ++ TIMER = 0x30, ++ TIMER_CONTROL = 0x34, ++ PAD_OUTPUT_ENABLE = 0x38, ++ PAD_PU_PD = 0x3c, ++ CLOCK_DELAY = 0x40, ++ ADMA_ADDRESS = 0x44, ++ CLOCK_CONTROL = 0x48, ++ LED_CONTROL = 0x4c, ++ VERSION = 0x50 ++}; ++ ++struct jmb38x_ms_host { ++ struct jmb38x_ms *chip; ++ void __iomem *addr; ++ spinlock_t lock; ++ int id; ++ char host_id[DEVICE_ID_SIZE]; ++ int irq; ++ unsigned int host_ctl; ++ unsigned int pad_out; ++ unsigned int pad_pu_pd; ++ unsigned int clock_delay; ++ unsigned int clock_ctl; ++ unsigned int block_pos; ++ unsigned long timeout_jiffies; ++ struct timer_list timer; ++ struct memstick_request *req; ++ unsigned char cmd_flags; ++ unsigned char io_pos; ++ unsigned int io_word[2]; ++}; ++ ++struct jmb38x_ms { ++ struct pci_dev *pdev; ++ int host_cnt; ++ struct memstick_host *hosts[]; ++}; ++ ++#define BLOCK_COUNT_MASK 0xffff0000 ++#define BLOCK_SIZE_MASK 0x00000fff ++ ++#define DMA_CONTROL_ENABLE 0x00000001 ++ ++#define TPC_DATA_SEL 0x00008000 ++#define TPC_DIR 0x00004000 ++#define TPC_WAIT_INT 0x00002000 ++#define TPC_GET_INT 0x00000800 ++#define TPC_CODE_SZ_MASK 0x00000700 ++#define TPC_DATA_SZ_MASK 0x00000007 ++ ++#define HOST_CONTROL_RESET_REQ 0x00008000 ++#define HOST_CONTROL_REI 0x00004000 ++#define HOST_CONTROL_LED 0x00000400 ++#define HOST_CONTROL_FAST_CLK 0x00000200 ++#define HOST_CONTROL_RESET 0x00000100 ++#define HOST_CONTROL_POWER_EN 0x00000080 ++#define HOST_CONTROL_CLOCK_EN 0x00000040 ++#define HOST_CONTROL_IF_SHIFT 4 ++ ++#define HOST_CONTROL_IF_SERIAL 0x0 ++#define HOST_CONTROL_IF_PAR4 0x1 ++#define HOST_CONTROL_IF_PAR8 0x3 ++ ++#define STATUS_BUSY 0x00080000 ++#define STATUS_MS_DAT7 0x00040000 ++#define STATUS_MS_DAT6 0x00020000 ++#define STATUS_MS_DAT5 0x00010000 ++#define STATUS_MS_DAT4 0x00008000 ++#define STATUS_MS_DAT3 0x00004000 ++#define STATUS_MS_DAT2 0x00002000 ++#define STATUS_MS_DAT1 0x00001000 ++#define STATUS_MS_DAT0 0x00000800 ++#define STATUS_HAS_MEDIA 0x00000400 ++#define STATUS_FIFO_EMPTY 0x00000200 ++#define STATUS_FIFO_FULL 0x00000100 ++#define STATUS_MS_CED 0x00000080 ++#define STATUS_MS_ERR 0x00000040 ++#define STATUS_MS_BRQ 0x00000020 ++#define STATUS_MS_CNK 0x00000001 ++ ++#define INT_STATUS_TPC_ERR 0x00080000 ++#define INT_STATUS_CRC_ERR 0x00040000 ++#define INT_STATUS_TIMER_TO 0x00020000 ++#define INT_STATUS_HSK_TO 0x00010000 ++#define INT_STATUS_ANY_ERR 0x00008000 ++#define INT_STATUS_FIFO_WRDY 0x00000080 ++#define INT_STATUS_FIFO_RRDY 0x00000040 ++#define INT_STATUS_MEDIA_OUT 0x00000010 ++#define INT_STATUS_MEDIA_IN 0x00000008 ++#define INT_STATUS_DMA_BOUNDARY 0x00000004 ++#define INT_STATUS_EOTRAN 0x00000002 ++#define INT_STATUS_EOTPC 0x00000001 ++ ++#define INT_STATUS_ALL 0x000f801f ++ ++#define PAD_OUTPUT_ENABLE_MS 0x0F3F ++ ++#define PAD_PU_PD_OFF 0x7FFF0000 ++#define PAD_PU_PD_ON_MS_SOCK0 0x5f8f0000 ++#define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000 ++ ++#define CLOCK_CONTROL_40MHZ 0x00000001 ++#define CLOCK_CONTROL_50MHZ 0x00000002 ++#define CLOCK_CONTROL_60MHZ 0x00000008 ++#define CLOCK_CONTROL_62_5MHZ 0x0000000c ++#define CLOCK_CONTROL_OFF 0x00000000 ++ ++enum { ++ CMD_READY = 0x01, ++ FIFO_READY = 0x02, ++ REG_DATA = 0x04, ++ DMA_DATA = 0x08 ++}; ++ ++ ++static unsigned int jmb38x_ms_read_data(struct jmb38x_ms_host *host, ++ unsigned char *buf, unsigned int length) ++{ ++ unsigned int off = 0; ++ ++ while (host->io_pos && length) { ++ buf[off++] = host->io_word[0] & 0xff; ++ host->io_word[0] >>= 8; ++ length--; ++ host->io_pos--; ++ } ++ ++ if (!length) ++ return off; ++ ++ while (!(STATUS_FIFO_EMPTY & readl(host->addr + STATUS))) { ++ if (length < 4) ++ break; ++ *(unsigned int *)(buf + off) = __raw_readl(host->addr + DATA); ++ length -= 4; ++ off += 4; ++ } ++ ++ if (length ++ && !(STATUS_FIFO_EMPTY & readl(host->addr + STATUS))) { ++ host->io_word[0] = readl(host->addr + DATA); ++ for (host->io_pos = 4; host->io_pos; --host->io_pos) { ++ buf[off++] = host->io_word[0] & 0xff; ++ host->io_word[0] >>= 8; ++ length--; ++ if (!length) ++ break; ++ } ++ } ++ ++ return off; ++} ++ ++static unsigned int jmb38x_ms_read_reg_data(struct jmb38x_ms_host *host, ++ unsigned char *buf, ++ unsigned int length) ++{ ++ unsigned int off = 0; ++ ++ while (host->io_pos > 4 && length) { ++ buf[off++] = host->io_word[0] & 0xff; ++ host->io_word[0] >>= 8; ++ length--; ++ host->io_pos--; ++ } ++ ++ if (!length) ++ return off; ++ ++ while (host->io_pos && length) { ++ buf[off++] = host->io_word[1] & 0xff; ++ host->io_word[1] >>= 8; ++ length--; ++ host->io_pos--; ++ } ++ ++ return off; ++} ++ ++static unsigned int jmb38x_ms_write_data(struct jmb38x_ms_host *host, ++ unsigned char *buf, ++ unsigned int length) ++{ ++ unsigned int off = 0; ++ ++ if (host->io_pos) { ++ while (host->io_pos < 4 && length) { ++ host->io_word[0] |= buf[off++] << (host->io_pos * 8); ++ host->io_pos++; ++ length--; ++ } ++ } ++ ++ if (host->io_pos == 4 ++ && !(STATUS_FIFO_FULL & readl(host->addr + STATUS))) { ++ writel(host->io_word[0], host->addr + DATA); ++ host->io_pos = 0; ++ host->io_word[0] = 0; ++ } else if (host->io_pos) { ++ return off; ++ } ++ ++ if (!length) ++ return off; ++ ++ while (!(STATUS_FIFO_FULL & readl(host->addr + STATUS))) { ++ if (length < 4) ++ break; ++ ++ __raw_writel(*(unsigned int *)(buf + off), ++ host->addr + DATA); ++ length -= 4; ++ off += 4; ++ } ++ ++ switch (length) { ++ case 3: ++ host->io_word[0] |= buf[off + 2] << 16; ++ host->io_pos++; ++ case 2: ++ host->io_word[0] |= buf[off + 1] << 8; ++ host->io_pos++; ++ case 1: ++ host->io_word[0] |= buf[off]; ++ host->io_pos++; ++ } ++ ++ off += host->io_pos; ++ ++ return off; ++} ++ ++static unsigned int jmb38x_ms_write_reg_data(struct jmb38x_ms_host *host, ++ unsigned char *buf, ++ unsigned int length) ++{ ++ unsigned int off = 0; ++ ++ while (host->io_pos < 4 && length) { ++ host->io_word[0] &= ~(0xff << (host->io_pos * 8)); ++ host->io_word[0] |= buf[off++] << (host->io_pos * 8); ++ host->io_pos++; ++ length--; ++ } ++ ++ if (!length) ++ return off; ++ ++ while (host->io_pos < 8 && length) { ++ host->io_word[1] &= ~(0xff << (host->io_pos * 8)); ++ host->io_word[1] |= buf[off++] << (host->io_pos * 8); ++ host->io_pos++; ++ length--; ++ } ++ ++ return off; ++} ++ ++static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) ++{ ++ unsigned int length; ++ unsigned int off; ++ unsigned int t_size, p_off, p_cnt; ++ unsigned char *buf; ++ struct page *pg; ++ unsigned long flags = 0; ++ ++ if (host->req->long_data) { ++ length = host->req->sg.length - host->block_pos; ++ off = host->req->sg.offset + host->block_pos; ++ } else { ++ length = host->req->data_len - host->block_pos; ++ off = 0; ++ } ++ ++ while (length) { ++ if (host->req->long_data) { ++ pg = nth_page(sg_page(&host->req->sg), ++ off >> PAGE_SHIFT); ++ p_off = offset_in_page(off); ++ p_cnt = PAGE_SIZE - p_off; ++ p_cnt = min(p_cnt, length); ++ ++ local_irq_save(flags); ++ buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off; ++ } else { ++ buf = host->req->data + host->block_pos; ++ p_cnt = host->req->data_len - host->block_pos; ++ } ++ ++ if (host->req->data_dir == WRITE) ++ t_size = !(host->cmd_flags & REG_DATA) ++ ? jmb38x_ms_write_data(host, buf, p_cnt) ++ : jmb38x_ms_write_reg_data(host, buf, p_cnt); ++ else ++ t_size = !(host->cmd_flags & REG_DATA) ++ ? jmb38x_ms_read_data(host, buf, p_cnt) ++ : jmb38x_ms_read_reg_data(host, buf, p_cnt); ++ ++ if (host->req->long_data) { ++ kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); ++ local_irq_restore(flags); ++ } ++ ++ if (!t_size) ++ break; ++ host->block_pos += t_size; ++ length -= t_size; ++ off += t_size; ++ } ++ ++ if (!length && host->req->data_dir == WRITE) { ++ if (host->cmd_flags & REG_DATA) { ++ writel(host->io_word[0], host->addr + TPC_P0); ++ writel(host->io_word[1], host->addr + TPC_P1); ++ } else if (host->io_pos) { ++ writel(host->io_word[0], host->addr + DATA); ++ } ++ } ++ ++ return length; ++} ++ ++static int jmb38x_ms_issue_cmd(struct memstick_host *msh) ++{ ++ struct jmb38x_ms_host *host = memstick_priv(msh); ++ unsigned char *data; ++ unsigned int data_len, cmd, t_val; ++ ++ if (!(STATUS_HAS_MEDIA & readl(host->addr + STATUS))) { ++#ifdef DBG ++ dev_dbg(msh->cdev.dev, "no media status\n"); ++#endif ++ host->req->error = -ETIME; ++ return host->req->error; ++ } ++ ++#ifdef DBG ++ dev_dbg(msh->cdev.dev, "control %08x\n", readl(host->addr + HOST_CONTROL)); ++ dev_dbg(msh->cdev.dev, "status %08x\n", readl(host->addr + INT_STATUS)); ++ dev_dbg(msh->cdev.dev, "hstatus %08x\n", readl(host->addr + STATUS)); ++#endif ++ ++ host->cmd_flags = 0; ++ host->block_pos = 0; ++ host->io_pos = 0; ++ host->io_word[0] = 0; ++ host->io_word[1] = 0; ++ ++ cmd = host->req->tpc << 16; ++ cmd |= TPC_DATA_SEL; ++ ++ if (host->req->data_dir == READ) ++ cmd |= TPC_DIR; ++ if (host->req->need_card_int) ++ cmd |= TPC_WAIT_INT; ++ ++ data = host->req->data; ++ ++ if (!no_dma) ++ host->cmd_flags |= DMA_DATA; ++ ++ if (host->req->long_data) { ++ data_len = host->req->sg.length; ++ } else { ++ data_len = host->req->data_len; ++ host->cmd_flags &= ~DMA_DATA; ++ } ++ ++ if (data_len <= 8) { ++ cmd &= ~(TPC_DATA_SEL | 0xf); ++ host->cmd_flags |= REG_DATA; ++ cmd |= data_len & 0xf; ++ host->cmd_flags &= ~DMA_DATA; ++ } ++ ++ if (host->cmd_flags & DMA_DATA) { ++ if (1 != pci_map_sg(host->chip->pdev, &host->req->sg, 1, ++ host->req->data_dir == READ ++ ? PCI_DMA_FROMDEVICE ++ : PCI_DMA_TODEVICE)) { ++ host->req->error = -ENOMEM; ++ return host->req->error; ++ } ++ data_len = sg_dma_len(&host->req->sg); ++ writel(sg_dma_address(&host->req->sg), ++ host->addr + DMA_ADDRESS); ++ writel(((1 << 16) & BLOCK_COUNT_MASK) ++ | (data_len & BLOCK_SIZE_MASK), ++ host->addr + BLOCK); ++ writel(DMA_CONTROL_ENABLE, host->addr + DMA_CONTROL); ++ } else if (!(host->cmd_flags & REG_DATA)) { ++ writel(((1 << 16) & BLOCK_COUNT_MASK) ++ | (data_len & BLOCK_SIZE_MASK), ++ host->addr + BLOCK); ++ t_val = readl(host->addr + INT_STATUS_ENABLE); ++ t_val |= host->req->data_dir == READ ++ ? INT_STATUS_FIFO_RRDY ++ : INT_STATUS_FIFO_WRDY; ++ ++ writel(t_val, host->addr + INT_STATUS_ENABLE); ++ writel(t_val, host->addr + INT_SIGNAL_ENABLE); ++ } else { ++ cmd &= ~(TPC_DATA_SEL | 0xf); ++ host->cmd_flags |= REG_DATA; ++ cmd |= data_len & 0xf; ++ ++ if (host->req->data_dir == WRITE) { ++ jmb38x_ms_transfer_data(host); ++ writel(host->io_word[0], host->addr + TPC_P0); ++ writel(host->io_word[1], host->addr + TPC_P1); ++ } ++ } ++ ++ mod_timer(&host->timer, jiffies + host->timeout_jiffies); ++ writel(HOST_CONTROL_LED | readl(host->addr + HOST_CONTROL), ++ host->addr + HOST_CONTROL); ++ host->req->error = 0; ++ ++ writel(cmd, host->addr + TPC); ++#ifdef DBG ++ dev_dbg(msh->cdev.dev, "executing TPC %08x, len %x\n", cmd, data_len); ++#endif ++ ++ return 0; ++} ++ ++static void jmb38x_ms_complete_cmd(struct memstick_host *msh, int last) ++{ ++ struct jmb38x_ms_host *host = memstick_priv(msh); ++ unsigned int t_val = 0; ++ int rc; ++ ++ del_timer(&host->timer); ++ ++#ifdef DBG ++ dev_dbg(msh->cdev.dev, "c control %08x\n", ++ readl(host->addr + HOST_CONTROL)); ++ dev_dbg(msh->cdev.dev, "c hstatus %08x\n", readl(host->addr + STATUS)); ++#endif ++ ++ host->req->int_reg = readl(host->addr + STATUS) & 0xff; ++ ++ if (host->cmd_flags & DMA_DATA) { ++ writel(0, host->addr + DMA_CONTROL); ++ pci_unmap_sg(host->chip->pdev, &host->req->sg, 1, ++ host->req->data_dir == READ ++ ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); ++ } else { ++ t_val = readl(host->addr + INT_STATUS_ENABLE); ++ if (host->req->data_dir == READ) ++ t_val &= ~INT_STATUS_FIFO_RRDY; ++ else ++ t_val &= ~INT_STATUS_FIFO_WRDY; ++ ++ writel(t_val, host->addr + INT_STATUS_ENABLE); ++ writel(t_val, host->addr + INT_SIGNAL_ENABLE); ++ } ++ ++ writel((~HOST_CONTROL_LED) & readl(host->addr + HOST_CONTROL), ++ host->addr + HOST_CONTROL); ++ ++ if (!last) { ++ do { ++ rc = memstick_next_req(msh, &host->req); ++ } while (!rc && jmb38x_ms_issue_cmd(msh)); ++ } else { ++ do { ++ rc = memstick_next_req(msh, &host->req); ++ if (!rc) ++ host->req->error = -ETIME; ++ } while (!rc); ++ } ++} ++ ++static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id) ++{ ++ struct memstick_host *msh = dev_id; ++ struct jmb38x_ms_host *host = memstick_priv(msh); ++ unsigned int irq_status; ++ ++ spin_lock(&host->lock); ++ irq_status = readl(host->addr + INT_STATUS); ++#ifdef DBG ++ dev_dbg(&host->chip->pdev->dev, "irq_status = %08x\n", irq_status); ++#endif ++ if (irq_status == 0 || irq_status == (~0)) { ++ spin_unlock(&host->lock); ++ return IRQ_NONE; ++ } ++ ++ if (host->req) { ++ if (irq_status & INT_STATUS_ANY_ERR) { ++ if (irq_status & INT_STATUS_CRC_ERR) ++ host->req->error = -EILSEQ; ++ else ++ host->req->error = -ETIME; ++ } else { ++ if (host->cmd_flags & DMA_DATA) { ++ if (irq_status & INT_STATUS_EOTRAN) ++ host->cmd_flags |= FIFO_READY; ++ } else { ++ if (irq_status & (INT_STATUS_FIFO_RRDY ++ | INT_STATUS_FIFO_WRDY)) ++ jmb38x_ms_transfer_data(host); ++ ++ if (irq_status & INT_STATUS_EOTRAN) { ++ jmb38x_ms_transfer_data(host); ++ host->cmd_flags |= FIFO_READY; ++ } ++ } ++ ++ if (irq_status & INT_STATUS_EOTPC) { ++ host->cmd_flags |= CMD_READY; ++ if (host->cmd_flags & REG_DATA) { ++ if (host->req->data_dir == READ) { ++ host->io_word[0] ++ = readl(host->addr ++ + TPC_P0); ++ host->io_word[1] ++ = readl(host->addr ++ + TPC_P1); ++ host->io_pos = 8; ++ ++ jmb38x_ms_transfer_data(host); ++ } ++ host->cmd_flags |= FIFO_READY; ++ } ++ } ++ } ++ } ++ ++ if (irq_status & (INT_STATUS_MEDIA_IN | INT_STATUS_MEDIA_OUT)) { ++#ifdef DBG ++ dev_dbg(&host->chip->pdev->dev, "media changed\n"); ++#endif ++ memstick_detect_change(msh); ++ } ++ ++ writel(irq_status, host->addr + INT_STATUS); ++ ++ if (host->req ++ && (((host->cmd_flags & CMD_READY) ++ && (host->cmd_flags & FIFO_READY)) ++ || host->req->error)) ++ jmb38x_ms_complete_cmd(msh, 0); ++ ++ spin_unlock(&host->lock); ++ return IRQ_HANDLED; ++} ++ ++static void jmb38x_ms_reset(struct jmb38x_ms_host *host) ++{ ++ unsigned int host_ctl = readl(host->addr + HOST_CONTROL); ++ ++ writel(HOST_CONTROL_RESET_REQ, host->addr + HOST_CONTROL); ++ ++ while (HOST_CONTROL_RESET_REQ ++ & (host_ctl = readl(host->addr + HOST_CONTROL))) { ++ ndelay(20); ++#ifdef DBG ++ dev_dbg(&host->chip->pdev->dev, "reset %08x\n", host_ctl); ++#endif ++ } ++ ++ writel(HOST_CONTROL_RESET, host->addr + HOST_CONTROL); ++ writel(CLOCK_CONTROL_40MHZ, host->addr + HOST_CONTROL); ++ mmiowb(); ++ writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); ++ writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); ++} ++ ++static void jmb38x_ms_abort(unsigned long data) ++{ ++ struct memstick_host *msh = (struct memstick_host *)data; ++ struct jmb38x_ms_host *host = memstick_priv(msh); ++ unsigned long flags; ++ ++#ifdef DBG ++ dev_dbg(&host->chip->pdev->dev, "abort\n"); ++#endif ++ spin_lock_irqsave(&host->lock, flags); ++ if (host->req) { ++ jmb38x_ms_reset(host); ++ writel(host->pad_pu_pd, host->addr + PAD_PU_PD); ++ writel(host->pad_out, host->addr + PAD_OUTPUT_ENABLE); ++ writel(host->host_ctl, host->addr + HOST_CONTROL); ++ writel(host->clock_ctl, host->addr + CLOCK_CONTROL); ++ writel(host->clock_delay, host->addr + CLOCK_DELAY); ++ host->req->error = -ETIME; ++ jmb38x_ms_complete_cmd(msh, 0); ++ } ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static void jmb38x_ms_request(struct memstick_host *msh) ++{ ++ struct jmb38x_ms_host *host = memstick_priv(msh); ++ unsigned long flags; ++ int rc; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ if (host->req) { ++ spin_unlock_irqrestore(&host->lock, flags); ++ BUG(); ++ return; ++ } ++ ++ do { ++ rc = memstick_next_req(msh, &host->req); ++ } while (!rc && jmb38x_ms_issue_cmd(msh)); ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static void jmb38x_ms_set_param(struct memstick_host *msh, ++ enum memstick_param param, ++ int value) ++{ ++ struct jmb38x_ms_host *host = memstick_priv(msh); ++ ++ switch(param) { ++ case MEMSTICK_POWER: ++ if (value == MEMSTICK_POWER_ON) { ++ jmb38x_ms_reset(host); ++ ++ host->pad_pu_pd = host->id ? PAD_PU_PD_ON_MS_SOCK1 ++ : PAD_PU_PD_ON_MS_SOCK0, ++ host->pad_out = PAD_OUTPUT_ENABLE_MS; ++ writel(host->pad_pu_pd, host->addr + PAD_PU_PD); ++ writel(host->pad_out, host->addr + PAD_OUTPUT_ENABLE); ++ ++ //host->host_ctl = readl(host->addr + HOST_CONTROL); ++ host->host_ctl |= 7; ++ host->host_ctl |= HOST_CONTROL_POWER_EN ++ | HOST_CONTROL_CLOCK_EN; ++ writel(host->host_ctl, host->addr + HOST_CONTROL); ++ ++#ifdef DBG ++ dev_dbg(&host->chip->pdev->dev, "power on\n"); ++#endif ++ } else if (value == MEMSTICK_POWER_OFF) { ++ host->host_ctl &= ~(HOST_CONTROL_POWER_EN ++ | HOST_CONTROL_CLOCK_EN); ++ writel(host->host_ctl, host->addr + HOST_CONTROL); ++ host->pad_out = 0; ++ writel(host->pad_out, host->addr + PAD_OUTPUT_ENABLE); ++ host->pad_pu_pd = PAD_PU_PD_OFF; ++ writel(host->pad_pu_pd, host->addr + PAD_PU_PD); ++#ifdef DBG ++ dev_dbg(&host->chip->pdev->dev, "power off\n"); ++#endif ++ } ++ break; ++ case MEMSTICK_INTERFACE: ++ host->host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); ++ ++ if (value == MEMSTICK_SERIAL) { ++ host->host_ctl &= ~HOST_CONTROL_FAST_CLK; ++ host->host_ctl |= HOST_CONTROL_IF_SERIAL ++ << HOST_CONTROL_IF_SHIFT; ++ host->host_ctl |= HOST_CONTROL_REI; ++ host->clock_ctl = CLOCK_CONTROL_40MHZ; ++ host->clock_delay = 0; ++ } else if (value == MEMSTICK_PAR4) { ++ host->host_ctl |= HOST_CONTROL_FAST_CLK; ++ host->host_ctl |= HOST_CONTROL_IF_PAR4 ++ << HOST_CONTROL_IF_SHIFT; ++ host->host_ctl &= ~HOST_CONTROL_REI; ++ host->clock_ctl = CLOCK_CONTROL_40MHZ; ++ host->clock_delay = 4; ++ } else if (value == MEMSTICK_PAR8) { ++ host->host_ctl |= HOST_CONTROL_FAST_CLK; ++ host->host_ctl |= HOST_CONTROL_IF_PAR8 ++ << HOST_CONTROL_IF_SHIFT; ++ host->host_ctl &= ~HOST_CONTROL_REI; ++ host->clock_ctl = CLOCK_CONTROL_60MHZ; ++ host->clock_delay = 0; ++ } ++ writel(host->host_ctl, host->addr + HOST_CONTROL); ++ writel(host->clock_ctl, host->addr + CLOCK_CONTROL); ++ writel(host->clock_delay, host->addr + CLOCK_DELAY); ++ break; ++ }; ++} ++ ++#ifdef CONFIG_PM ++ ++static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state) ++{ ++ struct jmb38x_ms *jm = pci_get_drvdata(dev); ++ int cnt; ++ ++ for (cnt = 0; cnt < jm->host_cnt; ++cnt) { ++ if (!jm->hosts[cnt]) ++ break; ++ memstick_suspend_host(jm->hosts[cnt]); ++ } ++ ++ pci_save_state(dev); ++ pci_enable_wake(dev, pci_choose_state(dev, state), 0); ++ pci_disable_device(dev); ++ pci_set_power_state(dev, pci_choose_state(dev, state)); ++ return 0; ++} ++ ++static int jmb38x_ms_resume(struct pci_dev *dev) ++{ ++ struct jmb38x_ms *jm = pci_get_drvdata(dev); ++ int rc; ++ ++ pci_set_power_state(dev, PCI_D0); ++ pci_restore_state(dev); ++ rc = pci_enable_device(dev); ++ if (rc) ++ return rc; ++ pci_set_master(dev); ++ ++ pci_read_config_dword(dev, 0xac, &rc); ++ pci_write_config_dword(dev, 0xac, rc | 0x00470000); ++ ++ for (rc = 0; rc < jm->host_cnt; ++rc) { ++ if (!jm->hosts[rc]) ++ break; ++ memstick_resume_host(jm->hosts[rc]); ++ memstick_detect_change(jm->hosts[rc]); ++ } ++ ++ return 0; ++} ++ ++#else ++ ++#define jmb38x_ms_suspend NULL ++#define jmb38x_ms_resume NULL ++ ++#endif /* CONFIG_PM */ ++ ++static int jmb38x_ms_count_slots(struct pci_dev *pdev) ++{ ++ int cnt, rc = 0; ++ ++ for (cnt = 0; cnt < PCI_ROM_RESOURCE; ++cnt) { ++ if (!(IORESOURCE_MEM & pci_resource_flags(pdev, cnt))) ++ break; ++ ++ if (256 != pci_resource_len(pdev, cnt)) ++ break; ++ ++ ++rc; ++ } ++ return rc; ++} ++ ++static struct memstick_host* jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt) ++{ ++ struct memstick_host *msh; ++ struct jmb38x_ms_host *host; ++ ++ msh = memstick_alloc_host(sizeof(struct jmb38x_ms_host), ++ &jm->pdev->dev); ++ if (!msh) ++ return NULL; ++ ++ host = memstick_priv(msh); ++ host->chip = jm; ++ host->addr = ioremap(pci_resource_start(jm->pdev, cnt), ++ pci_resource_len(jm->pdev, cnt)); ++ if (!host->addr) ++ goto err_out_free; ++ ++ spin_lock_init(&host->lock); ++ host->id = cnt; ++ snprintf(host->host_id, DEVICE_ID_SIZE, DRIVER_NAME ":slot%d", ++ host->id); ++ host->irq = jm->pdev->irq; ++ host->timeout_jiffies = msecs_to_jiffies(1000); ++ msh->request = jmb38x_ms_request; ++ msh->set_param = jmb38x_ms_set_param; ++ ++ msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8; ++ ++ setup_timer(&host->timer, jmb38x_ms_abort, (unsigned long)msh); ++ ++ if (!request_irq(host->irq, jmb38x_ms_isr, IRQF_SHARED, host->host_id, ++ msh)) ++ return msh; ++ ++ iounmap(host->addr); ++err_out_free: ++ kfree(msh); ++ return NULL; ++} ++ ++static void jmb38x_ms_free_host(struct memstick_host *msh) ++{ ++ struct jmb38x_ms_host *host = memstick_priv(msh); ++ ++ free_irq(host->irq, msh); ++ iounmap(host->addr); ++ memstick_free_host(msh); ++} ++ ++static int jmb38x_ms_probe(struct pci_dev *pdev, ++ const struct pci_device_id *dev_id) ++{ ++ struct jmb38x_ms *jm; ++ int pci_dev_busy = 0; ++ int rc, cnt; ++ ++ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); ++ if (rc) ++ return rc; ++ ++ rc = pci_enable_device(pdev); ++ if (rc) ++ return rc; ++ ++ pci_set_master(pdev); ++ ++ rc = pci_request_regions(pdev, DRIVER_NAME); ++ if (rc) { ++ pci_dev_busy = 1; ++ goto err_out; ++ } ++ ++ pci_read_config_dword(pdev, 0xac, &rc); ++ pci_write_config_dword(pdev, 0xac, rc | 0x00470000); ++ ++ cnt = jmb38x_ms_count_slots(pdev); ++ if (!cnt) { ++ rc = -ENODEV; ++ pci_dev_busy = 1; ++ goto err_out; ++ } ++ ++ jm = kzalloc(sizeof(struct jmb38x_ms) ++ + cnt * sizeof(struct memstick_host*), GFP_KERNEL); ++ if (!jm) { ++ rc = -ENOMEM; ++ goto err_out_int; ++ } ++ ++ jm->pdev = pdev; ++ jm->host_cnt = cnt; ++ pci_set_drvdata(pdev, jm); ++ ++ for (cnt = 0; cnt < jm->host_cnt; ++cnt) { ++ jm->hosts[cnt] = jmb38x_ms_alloc_host(jm, cnt); ++ if (!jm->hosts[cnt]) ++ break; ++ ++ rc = memstick_add_host(jm->hosts[cnt]); ++ ++ if (rc) { ++ jmb38x_ms_free_host(jm->hosts[cnt]); ++ jm->hosts[cnt] = NULL; ++ break; ++ } ++ } ++ ++ if (cnt) ++ return 0; ++ ++ rc = -ENODEV; ++ ++ pci_set_drvdata(pdev, NULL); ++ kfree(jm); ++err_out_int: ++ pci_release_regions(pdev); ++err_out: ++ if (!pci_dev_busy) ++ pci_disable_device(pdev); ++ return rc; ++} ++ ++static void jmb38x_ms_remove(struct pci_dev *dev) ++{ ++ struct jmb38x_ms *jm = pci_get_drvdata(dev); ++ struct jmb38x_ms_host *host; ++ int cnt; ++ unsigned long flags; ++ ++ for (cnt = 0; cnt < jm->host_cnt; ++cnt) { ++ if (!jm->hosts[cnt]) ++ break; ++ ++ host = memstick_priv(jm->hosts[cnt]); ++ ++ writel(0, host->addr + INT_SIGNAL_ENABLE); ++ writel(0, host->addr + INT_STATUS_ENABLE); ++ mmiowb(); ++#ifdef DBG ++ dev_dbg(&jm->pdev->dev, "interrupts off\n"); ++#endif ++ spin_lock_irqsave(&host->lock, flags); ++ if (host->req) { ++ host->req->error = -ETIME; ++ jmb38x_ms_complete_cmd(jm->hosts[cnt], 1); ++ } ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ memstick_remove_host(jm->hosts[cnt]); ++ dev_dbg(&jm->pdev->dev, "host removed\n"); ++ ++ jmb38x_ms_free_host(jm->hosts[cnt]); ++ } ++ ++ pci_set_drvdata(dev, NULL); ++ pci_release_regions(dev); ++ pci_disable_device(dev); ++ kfree(jm); ++} ++ ++static struct pci_device_id jmb38x_ms_id_tbl [] = { ++ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS, PCI_ANY_ID, ++ PCI_ANY_ID, 0, 0, 0 }, ++ { } ++}; ++ ++static struct pci_driver jmb38x_ms_driver = { ++ .name = DRIVER_NAME, ++ .id_table = jmb38x_ms_id_tbl, ++ .probe = jmb38x_ms_probe, ++ .remove = jmb38x_ms_remove, ++ .suspend = jmb38x_ms_suspend, ++ .resume = jmb38x_ms_resume ++}; ++ ++static int __init jmb38x_ms_init(void) ++{ ++ return pci_register_driver(&jmb38x_ms_driver); ++} ++ ++static void __exit jmb38x_ms_exit(void) ++{ ++ pci_unregister_driver(&jmb38x_ms_driver); ++} ++ ++MODULE_AUTHOR("Alex Dubov"); ++MODULE_DESCRIPTION("JMicron jmb38x MemoryStick driver"); ++MODULE_LICENSE("GPL"); ++MODULE_DEVICE_TABLE(pci, jmb38x_ms_id_tbl); ++MODULE_VERSION(DRIVER_VERSION); ++ ++module_init(jmb38x_ms_init); ++module_exit(jmb38x_ms_exit); +diff --git a/drivers/mmc/ms/memstick.c b/drivers/mmc/ms/memstick.c +new file mode 100644 +index 0000000..acd2151 +--- /dev/null ++++ b/drivers/mmc/ms/memstick.c +@@ -0,0 +1,665 @@ ++/* ++ * Sony MemoryStick support ++ * ++ * Copyright (C) 2007 Alex Dubov ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Special thanks to Carlos Corbacho for providing various MemoryStick cards ++ * that made this driver possible. ++ * ++ */ ++ ++#include "memstick.h" ++#include ++#include ++#include ++ ++#define DRIVER_NAME "memstick" ++#define DRIVER_VERSION "0.2" ++ ++static unsigned int cmd_retries = 3; ++module_param(cmd_retries, uint, 0644); ++ ++static struct workqueue_struct *workqueue; ++static DEFINE_IDR(memstick_host_idr); ++static DEFINE_SPINLOCK(memstick_host_lock); ++ ++static int memstick_dev_match(struct memstick_dev *card, ++ struct memstick_device_id *id) ++{ ++ if (id->match_flags & MEMSTICK_MATCH_ALL) { ++ if ((id->type == card->id.type) ++ && (id->category == card->id.category) ++ && (id->class == card->id.class)) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int memstick_bus_match(struct device *dev, struct device_driver *drv) ++{ ++ struct memstick_dev *card = container_of(dev, struct memstick_dev, ++ dev); ++ struct memstick_driver *ms_drv = container_of(drv, ++ struct memstick_driver, ++ driver); ++ struct memstick_device_id *ids = ms_drv->id_table; ++ ++ if (ids) { ++ while (ids->match_flags) { ++ if (memstick_dev_match(card, ids)) ++ return 1; ++ ++ids; ++ } ++ } ++ return 0; ++} ++ ++static int memstick_uevent(struct device *dev, char **envp, int num_envp, ++ char *buffer, int buffer_size) ++{ ++ struct memstick_dev *card = container_of(dev, struct memstick_dev, ++ dev); ++ int i = 0; ++ int length = 0; ++ ++ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "MEMSTICK_TYPE=%02X", card->id.type)) ++ return -ENOMEM; ++ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "MEMSTICK_CATEGORY=%02X", card->id.category)) ++ return -ENOMEM; ++ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "MEMSTICK_CLASS=%02X", card->id.class)) ++ return -ENOMEM; ++ ++ return 0; ++} ++/* ++static int memstick_uevent(struct device *dev, struct kobj_uevent_env *env) ++{ ++ struct memstick_dev *card = container_of(dev, struct memstick_dev, ++ dev); ++ ++ if (add_uevent_var(env, "MEMSTICK_TYPE=%02X", card->id.type)) ++ return -ENOMEM; ++ ++ if (add_uevent_var(env, "MEMSTICK_CATEGORY=%02X", card->id.category)) ++ return -ENOMEM; ++ ++ if (add_uevent_var(env, "MEMSTICK_CLASS=%02X", card->id.class)) ++ return -ENOMEM; ++ ++ return 0; ++} ++*/ ++static int memstick_device_probe(struct device *dev) ++{ ++ struct memstick_dev *card = container_of(dev, struct memstick_dev, ++ dev); ++ struct memstick_driver *drv = container_of(dev->driver, ++ struct memstick_driver, ++ driver); ++ int rc = -ENODEV; ++ ++ if (dev->driver && drv->probe) { ++ rc = drv->probe(card); ++ if (!rc) ++ get_device(dev); ++ } ++ return rc; ++} ++ ++static int memstick_device_remove(struct device *dev) ++{ ++ struct memstick_dev *card = container_of(dev, struct memstick_dev, ++ dev); ++ struct memstick_driver *drv = container_of(dev->driver, ++ struct memstick_driver, ++ driver); ++ ++ if (dev->driver && drv->remove) { ++ drv->remove(card); ++ card->dev.driver = NULL; ++ } ++ ++ put_device(dev); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++ ++static int memstick_device_suspend(struct device *dev, pm_message_t state) ++{ ++ struct memstick_dev *card = container_of(dev, struct memstick_dev, ++ dev); ++ struct memstick_driver *drv = container_of(dev->driver, ++ struct memstick_driver, ++ driver); ++ ++ if (dev->driver && drv->suspend) ++ return drv->suspend(card, state); ++ return 0; ++} ++ ++static int memstick_device_resume(struct device *dev) ++{ ++ struct memstick_dev *card = container_of(dev, struct memstick_dev, ++ dev); ++ struct memstick_driver *drv = container_of(dev->driver, ++ struct memstick_driver, ++ driver); ++ ++ if (dev->driver && drv->resume) ++ return drv->resume(card); ++ return 0; ++} ++ ++#else ++ ++#define memstick_device_suspend NULL ++#define memstick_device_resume NULL ++ ++#endif /* CONFIG_PM */ ++ ++#define MEMSTICK_ATTR(name, format) \ ++static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ ++ char *buf) \ ++{ \ ++ struct memstick_dev *card = container_of(dev, struct memstick_dev, \ ++ dev); \ ++ return sprintf(buf, format, card->id.name); \ ++} ++ ++MEMSTICK_ATTR(type, "%02X"); ++MEMSTICK_ATTR(category, "%02X"); ++MEMSTICK_ATTR(class, "%02X"); ++ ++#define MEMSTICK_ATTR_RO(name) __ATTR(name, S_IRUGO, name##_show, NULL) ++ ++static struct device_attribute memstick_dev_attrs[] = { ++ MEMSTICK_ATTR_RO(type), ++ MEMSTICK_ATTR_RO(category), ++ MEMSTICK_ATTR_RO(class), ++ __ATTR_NULL ++}; ++ ++static struct bus_type memstick_bus_type = { ++ .name = "memstick", ++ .dev_attrs = memstick_dev_attrs, ++ .match = memstick_bus_match, ++ .uevent = memstick_uevent, ++ .probe = memstick_device_probe, ++ .remove = memstick_device_remove, ++ .suspend = memstick_device_suspend, ++ .resume = memstick_device_resume ++}; ++ ++static void memstick_free(struct class_device *cdev) ++{ ++ struct memstick_host *host = container_of(cdev, struct memstick_host, ++ cdev); ++ kfree(host); ++} ++ ++static struct class memstick_host_class = { ++ .name = "memstick_host", ++ .release = memstick_free ++}; ++ ++static void memstick_free_card(struct device *dev) ++{ ++ struct memstick_dev *card = container_of(dev, struct memstick_dev, ++ dev); ++ kfree(card); ++} ++ ++static int memstick_dummy_check(struct memstick_dev *card) ++{ ++ return 0; ++} ++ ++/** ++ * memstick_detect_change - schedule media detection on memstick host ++ * @host - host to use ++ */ ++void memstick_detect_change(struct memstick_host *host) ++{ ++ queue_work(workqueue, &host->media_checker); ++} ++EXPORT_SYMBOL(memstick_detect_change); ++ ++/** ++ * memstick_next_req - called by host driver to obtain next request to process ++ * @host - host to use ++ * @mrq - pointer to stick the request to ++ * ++ * Host calls this function from idle state (*mrq == NULL) or after finishing ++ * previous request (*mrq should point to it). If previous request was ++ * unsuccessful, it is retried for predetermined number of times. Return value ++ * of 0 means that new request was assigned to the host. ++ */ ++int memstick_next_req(struct memstick_host *host, struct memstick_request **mrq) ++{ ++ int rc = -ENXIO; ++ ++ if ((*mrq) && (*mrq)->error && host->retries) { ++ (*mrq)->error = rc; ++ host->retries--; ++ return 0; ++ } ++ ++ if (host->card && host->card->next_request) ++ rc = host->card->next_request(host->card, mrq); ++ ++ if (!rc) ++ host->retries = cmd_retries > 1 ? cmd_retries - 1 : 1; ++ else ++ *mrq = NULL; ++ ++ return rc; ++} ++EXPORT_SYMBOL(memstick_next_req); ++ ++/** ++ * memstick_new_req - notify the host that some requests are pending ++ * @host - host to use ++ */ ++void memstick_new_req(struct memstick_host *host) ++{ ++ host->retries = cmd_retries; ++ host->request(host); ++} ++EXPORT_SYMBOL(memstick_new_req); ++ ++/** ++ * memstick_init_req_sg - set request fields needed for bulk data transfer ++ * @mrq - request to use ++ * @tpc - memstick Transport Protocol Command ++ * @sg - TPC argument ++ */ ++void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc, ++ struct scatterlist *sg) ++{ ++ mrq->tpc = tpc; ++ if (tpc & 8) ++ mrq->data_dir = WRITE; ++ else ++ mrq->data_dir = READ; ++ ++ mrq->sg = *sg; ++ mrq->long_data = 1; ++ ++ if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD) ++ mrq->need_card_int = 1; ++ else ++ mrq->need_card_int = 0; ++} ++EXPORT_SYMBOL(memstick_init_req_sg); ++ ++/** ++ * memstick_init_req - set request fields needed for short data transfer ++ * @mrq - request to use ++ * @tpc - memstick Transport Protocol Command ++ * @buf - TPC argument buffer ++ * @length - TPC argument size ++ * ++ * The intended use of this function (transfer of data items several bytes ++ * in size) allows us to just copy the value between request structure and ++ * user supplied buffer. ++ */ ++void memstick_init_req(struct memstick_request *mrq, unsigned char tpc, ++ void *buf, size_t length) ++{ ++ mrq->tpc = tpc; ++ if (tpc & 8) ++ mrq->data_dir = WRITE; ++ else ++ mrq->data_dir = READ; ++ ++ mrq->data_len = length > sizeof(mrq->data) ? sizeof(mrq->data) : length; ++ if (mrq->data_dir == WRITE) ++ memcpy(mrq->data, buf, mrq->data_len); ++ ++ mrq->long_data = 0; ++ ++ if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD) ++ mrq->need_card_int = 1; ++ else ++ mrq->need_card_int = 0; ++} ++EXPORT_SYMBOL(memstick_init_req); ++ ++/* ++ * Functions prefixed with "h_" are protocol callbacks. They can be called from ++ * interrupt context. Return value of 0 means that request processing is still ++ * ongoing, while special error value of -EAGAIN means that current request is ++ * finished (and request processor should come back some time later). ++ */ ++ ++static int h_memstick_read_dev_id(struct memstick_dev *card, ++ struct memstick_request **mrq) ++{ ++ struct ms_id_register id_reg; ++ ++ if (!(*mrq)) { ++ memstick_init_req(&card->current_mrq, MS_TPC_READ_REG, NULL, ++ sizeof(struct ms_id_register)); ++ *mrq = &card->current_mrq; ++ return 0; ++ } else { ++ if (!(*mrq)->error) { ++ memcpy(&id_reg, (*mrq)->data, sizeof(id_reg)); ++ card->id.match_flags = MEMSTICK_MATCH_ALL; ++ card->id.type = id_reg.type; ++ card->id.category = id_reg.category; ++ card->id.class = id_reg.class; ++ } ++ complete(&card->mrq_complete); ++#ifdef DBG ++ dev_dbg(&card->dev, "if_mode = %02x\n", id_reg.if_mode); ++#endif ++ return -EAGAIN; ++ } ++} ++ ++static int h_memstick_set_rw_addr(struct memstick_dev *card, ++ struct memstick_request **mrq) ++{ ++ if (!(*mrq)) { ++ memstick_init_req(&card->current_mrq, MS_TPC_SET_RW_REG_ADRS, ++ (char *)&card->reg_addr, ++ sizeof(card->reg_addr)); ++ *mrq = &card->current_mrq; ++ return 0; ++ } else { ++ complete(&card->mrq_complete); ++ return -EAGAIN; ++ } ++} ++ ++/** ++ * memstick_set_rw_addr - issue SET_RW_REG_ADDR request and wait for it to ++ * complete ++ * @card - media device to use ++ */ ++int memstick_set_rw_addr(struct memstick_dev *card) ++{ ++ card->next_request = h_memstick_set_rw_addr; ++ memstick_new_req(card->host); ++ wait_for_completion(&card->mrq_complete); ++ ++ return card->current_mrq.error; ++} ++EXPORT_SYMBOL(memstick_set_rw_addr); ++ ++static struct memstick_dev *memstick_alloc_card(struct memstick_host *host) ++{ ++ struct memstick_dev *card = kzalloc(sizeof(struct memstick_dev), ++ GFP_KERNEL); ++ struct memstick_dev *old_card = host->card; ++ struct ms_id_register id_reg; ++ ++ if (card) { ++ card->host = host; ++ snprintf(card->dev.bus_id, sizeof(card->dev.bus_id), ++ "%s", host->cdev.class_id); ++ card->dev.parent = host->cdev.dev; ++ card->dev.bus = &memstick_bus_type; ++ card->dev.release = memstick_free_card; ++ card->check = memstick_dummy_check; ++ ++ card->reg_addr.r_offset = offsetof(struct ms_register, id); ++ card->reg_addr.r_length = sizeof(id_reg); ++ card->reg_addr.w_offset = offsetof(struct ms_register, id); ++ card->reg_addr.w_length = sizeof(id_reg); ++ ++ init_completion(&card->mrq_complete); ++ ++ host->card = card; ++ if (memstick_set_rw_addr(card)) ++ goto err_out; ++ ++ card->next_request = h_memstick_read_dev_id; ++ memstick_new_req(host); ++ wait_for_completion(&card->mrq_complete); ++ ++ if (card->current_mrq.error) ++ goto err_out; ++ } ++ host->card = old_card; ++ return card; ++err_out: ++ host->card = old_card; ++ kfree(card); ++ return NULL; ++} ++ ++static void memstick_power_on(struct memstick_host *host) ++{ ++ host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); ++ host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); ++ msleep(1); ++} ++ ++static void memstick_check(struct work_struct *work) ++{ ++ struct memstick_host *host = container_of(work, struct memstick_host, ++ media_checker); ++ struct memstick_dev *card; ++ ++#ifdef DBG ++ dev_dbg(host->cdev.dev, "memstick_check started\n"); ++#endif ++ mutex_lock(&host->lock); ++ if (!host->card) ++ memstick_power_on(host); ++ ++ card = memstick_alloc_card(host); ++ ++ if (!card) { ++ if (host->card) { ++ device_unregister(&host->card->dev); ++ host->card = NULL; ++ } ++ } else { ++#ifdef DBG ++ dev_dbg(host->cdev.dev, "new card %02x, %02x, %02x\n", ++ card->id.type, card->id.category, card->id.class); ++#endif ++ if (host->card) { ++ if (memstick_set_rw_addr(host->card) ++ || !memstick_dev_match(host->card, &card->id) ++ || !(host->card->check(host->card))) { ++ device_unregister(&host->card->dev); ++ host->card = NULL; ++ } ++ } ++ ++ if (!host->card) { ++ host->card = card; ++ if (device_register(&card->dev)) { ++ kfree(host->card); ++ host->card = NULL; ++ } ++ } else ++ kfree(card); ++ } ++ ++ if (!host->card) ++ host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); ++ ++ mutex_unlock(&host->lock); ++#ifdef DBG ++ dev_dbg(host->cdev.dev, "memstick_check finished\n"); ++#endif ++} ++ ++/** ++ * memstick_alloc_host - allocate a memstick_host structure ++ * @extra: size of the user private data to allocate ++ * @dev: parent device of the host ++ */ ++struct memstick_host *memstick_alloc_host(unsigned int extra, ++ struct device *dev) ++{ ++ struct memstick_host *host; ++ ++ host = kzalloc(sizeof(struct memstick_host) + extra, GFP_KERNEL); ++ if (host) { ++ mutex_init(&host->lock); ++ INIT_WORK(&host->media_checker, memstick_check); ++ host->cdev.class = &memstick_host_class; ++ host->cdev.dev = dev; ++ class_device_initialize(&host->cdev); ++ } ++ return host; ++} ++EXPORT_SYMBOL(memstick_alloc_host); ++ ++/** ++ * memstick_add_host - start request processing on memstick host ++ * @host - host to use ++ */ ++int memstick_add_host(struct memstick_host *host) ++{ ++ int rc; ++ ++ if (!idr_pre_get(&memstick_host_idr, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ spin_lock(&memstick_host_lock); ++ rc = idr_get_new(&memstick_host_idr, host, &host->id); ++ spin_unlock(&memstick_host_lock); ++ if (rc) ++ return rc; ++ ++ snprintf(host->cdev.class_id, BUS_ID_SIZE, ++ "memstick%u", host->id); ++ ++ rc = class_device_add(&host->cdev); ++ if (rc) { ++ spin_lock(&memstick_host_lock); ++ idr_remove(&memstick_host_idr, host->id); ++ spin_unlock(&memstick_host_lock); ++ return rc; ++ } ++ ++ host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); ++ memstick_detect_change(host); ++ return 0; ++} ++EXPORT_SYMBOL(memstick_add_host); ++ ++/** ++ * memstick_remove_host - stop request processing on memstick host ++ * @host - host to use ++ */ ++void memstick_remove_host(struct memstick_host *host) ++{ ++ flush_workqueue(workqueue); ++ mutex_lock(&host->lock); ++ if (host->card) ++ device_unregister(&host->card->dev); ++ host->card = NULL; ++ host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); ++ mutex_unlock(&host->lock); ++ ++ spin_lock(&memstick_host_lock); ++ idr_remove(&memstick_host_idr, host->id); ++ spin_unlock(&memstick_host_lock); ++ class_device_del(&host->cdev); ++} ++EXPORT_SYMBOL(memstick_remove_host); ++ ++/** ++ * memstick_free_host - free memstick host ++ * @host - host to use ++ */ ++void memstick_free_host(struct memstick_host *host) ++{ ++ mutex_destroy(&host->lock); ++ class_device_put(&host->cdev); ++} ++EXPORT_SYMBOL(memstick_free_host); ++ ++/** ++ * memstick_suspend_host - notify bus driver of host suspension ++ * @host - host to use ++ */ ++void memstick_suspend_host(struct memstick_host *host) ++{ ++ mutex_lock(&host->lock); ++ host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); ++ mutex_unlock(&host->lock); ++} ++EXPORT_SYMBOL(memstick_suspend_host); ++ ++/** ++ * memstick_resume_host - notify bus driver of host resumption ++ * @host - host to use ++ */ ++void memstick_resume_host(struct memstick_host *host) ++{ ++ mutex_lock(&host->lock); ++ host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); ++ mutex_unlock(&host->lock); ++ memstick_detect_change(host); ++} ++EXPORT_SYMBOL(memstick_resume_host); ++ ++int memstick_register_driver(struct memstick_driver *drv) ++{ ++ drv->driver.bus = &memstick_bus_type; ++ ++ return driver_register(&drv->driver); ++} ++EXPORT_SYMBOL(memstick_register_driver); ++ ++void memstick_unregister_driver(struct memstick_driver *drv) ++{ ++ driver_unregister(&drv->driver); ++} ++EXPORT_SYMBOL(memstick_unregister_driver); ++ ++ ++static int __init memstick_init(void) ++{ ++ int rc; ++ ++ workqueue = create_freezeable_workqueue("kmemstick"); ++ if (!workqueue) ++ return -ENOMEM; ++ ++ rc = bus_register(&memstick_bus_type); ++ if (!rc) ++ rc = class_register(&memstick_host_class); ++ ++ if (!rc) ++ return 0; ++ ++ bus_unregister(&memstick_bus_type); ++ destroy_workqueue(workqueue); ++ ++ return rc; ++} ++ ++static void __exit memstick_exit(void) ++{ ++ class_unregister(&memstick_host_class); ++ bus_unregister(&memstick_bus_type); ++ destroy_workqueue(workqueue); ++ idr_destroy(&memstick_host_idr); ++} ++ ++module_init(memstick_init); ++module_exit(memstick_exit); ++ ++MODULE_AUTHOR("Alex Dubov"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Sony MemoryStick core driver"); ++MODULE_VERSION(DRIVER_VERSION); +diff --git a/drivers/mmc/ms/memstick.h b/drivers/mmc/ms/memstick.h +new file mode 100644 +index 0000000..46ae973 +--- /dev/null ++++ b/drivers/mmc/ms/memstick.h +@@ -0,0 +1,342 @@ ++/* ++ * Sony MemoryStick support ++ * ++ * Copyright (C) 2007 Alex Dubov ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef _MEMSTICK_H ++#define _MEMSTICK_H ++ ++#include ++#include ++#include ++ ++/*** Hardware based structures ***/ ++ ++struct ms_status_register { ++ unsigned char reserved; ++ unsigned char interrupt; ++#define MEMSTICK_INT_CMDNAK 0x0001 ++#define MEMSTICK_INT_IOREQ 0x0008 ++#define MEMSTICK_INT_IOBREQ 0x0010 ++#define MEMSTICK_INT_BREQ 0x0020 ++#define MEMSTICK_INT_ERR 0x0040 ++#define MEMSTICK_INT_CED 0x0080 ++ ++ unsigned char status0; ++#define MEMSTICK_STATUS0_WP 0x0001 ++#define MEMSTICK_STATUS0_SL 0x0002 ++#define MEMSTICK_STATUS0_BF 0x0010 ++#define MEMSTICK_STATUS0_BE 0x0020 ++#define MEMSTICK_STATUS0_FB0 0x0040 ++#define MEMSTICK_STATUS0_MB 0x0080 ++ ++ unsigned char status1; ++#define MEMSTICK_STATUS1_UCFG 0x0001 ++#define MEMSTICK_STATUS1_FGER 0x0002 ++#define MEMSTICK_STATUS1_UCEX 0x0004 ++#define MEMSTICK_STATUS1_EXER 0x0008 ++#define MEMSTICK_STATUS1_UCDT 0x0010 ++#define MEMSTICK_STATUS1_DTER 0x0020 ++#define MEMSTICK_STATUS1_FBI 0x0040 ++#define MEMSTICK_STATUS1_MB 0x0080 ++} __attribute__((packed)); ++ ++struct ms_id_register { ++ unsigned char type; ++ unsigned char if_mode; ++ unsigned char category; ++ unsigned char class; ++} __attribute__((packed)); ++ ++struct ms_param_register { ++ unsigned char system; ++#define MEMSTICK_SYS_ATEN 0xc0 ++#define MEMSTICK_SYS_BAMD 0x80 ++#define MEMSTICK_SYS_PAM 0x08 ++ ++ unsigned char block_address_msb; ++ unsigned short block_address; ++ unsigned char cp; ++#define MEMSTICK_CP_BLOCK 0x0000 ++#define MEMSTICK_CP_PAGE 0x0020 ++#define MEMSTICK_CP_EXTRA 0x0040 ++#define MEMSTICK_CP_OVERWRITE 0x0080 ++ ++ unsigned char page_address; ++} __attribute__((packed)); ++ ++struct ms_extra_data_register { ++ unsigned char overwrite_flag; ++#define MEMSTICK_OVERWRITE_UPDATA 0x0010 ++#define MEMSTICK_OVERWRITE_PAGE 0x0060 ++#define MEMSTICK_OVERWRITE_BLOCK 0x0080 ++ ++ unsigned char management_flag; ++#define MEMSTICK_MANAGEMENT_SYSTEM 0x0004 ++#define MEMSTICK_MANAGEMENT_TRANS_TABLE 0x0008 ++#define MEMSTICK_MANAGEMENT_COPY 0x0010 ++#define MEMSTICK_MANAGEMENT_ACCESS 0x0020 ++ ++ unsigned short logical_address; ++} __attribute__((packed)); ++ ++struct ms_register { ++ struct ms_status_register status; ++ struct ms_id_register id; ++ unsigned char reserved[8]; ++ struct ms_param_register param; ++ struct ms_extra_data_register extra_data; ++} __attribute__((packed)); ++ ++struct mspro_param_register { ++ unsigned char system; ++#define MEMSTICK_SYS_SERIAL 0x80 ++#define MEMSTICK_SYS_PAR4 0x00 ++#define MEMSTICK_SYS_PAR8 0x40 ++ ++ unsigned short data_count; ++ unsigned int data_address; ++ unsigned char tpc_param; ++} __attribute__((packed)); ++ ++struct mspro_io_info_register { ++ unsigned char version; ++ unsigned char io_category; ++ unsigned char current_req; ++ unsigned char card_opt_info; ++ unsigned char rdy_wait_time; ++}__attribute__((packed)); ++ ++struct mspro_io_func_register { ++ unsigned char func_enable; ++ unsigned char func_select; ++ unsigned char func_intmask; ++ unsigned char transfer_mode; ++}__attribute__((packed)); ++ ++struct mspro_io_cmd_register { ++ unsigned short tpc_param; ++ unsigned short data_count; ++ unsigned int data_address; ++}__attribute__((packed)); ++ ++struct mspro_register { ++ struct ms_status_register status; ++ struct ms_id_register id; ++ unsigned char reserved0[8]; ++ struct mspro_param_register param; ++ unsigned char reserved1[8]; ++ struct mspro_io_info_register io_info; ++ struct mspro_io_func_register io_func; ++ unsigned char reserved2[7]; ++ struct mspro_io_cmd_register io_cmd; ++ unsigned char io_int; ++ unsigned char io_int_func; ++} __attribute__((packed)); ++ ++struct ms_register_addr { ++ unsigned char r_offset; ++ unsigned char r_length; ++ unsigned char w_offset; ++ unsigned char w_length; ++} __attribute__((packed)); ++ ++enum { ++ MS_TPC_READ_MG_STATUS = 0x01, ++ MS_TPC_READ_LONG_DATA = 0x02, ++ MS_TPC_READ_SHORT_DATA = 0x03, ++ MS_TPC_READ_MG_DATA = 0x03, ++ MS_TPC_READ_REG = 0x04, ++ MS_TPC_READ_QUAD_DATA = 0x05, ++ MS_TPC_READ_IO_DATA = 0x05, ++ MS_TPC_GET_INT = 0x07, ++ MS_TPC_SET_RW_REG_ADRS = 0x08, ++ MS_TPC_EX_SET_CMD = 0x09, ++ MS_TPC_WRITE_QUAD_DATA = 0x0a, ++ MS_TPC_WRITE_IO_DATA = 0x0a, ++ MS_TPC_WRITE_REG = 0x0b, ++ MS_TPC_WRITE_SHORT_DATA = 0x0c, ++ MS_TPC_WRITE_MG_DATA = 0x0c, ++ MS_TPC_WRITE_LONG_DATA = 0x0d, ++ MS_TPC_SET_CMD = 0x0e ++}; ++ ++enum { ++ MS_CMD_BLOCK_END = 0x33, ++ MS_CMD_RESET = 0x3c, ++ MS_CMD_BLOCK_WRITE = 0x55, ++ MS_CMD_SLEEP = 0x5a, ++ MS_CMD_BLOCK_ERASE = 0x99, ++ MS_CMD_BLOCK_READ = 0xaa, ++ MS_CMD_CLEAR_BUF = 0xc3, ++ MS_CMD_FLASH_STOP = 0xcc, ++ MS_CMD_LOAD_ID = 0x60, ++ MS_CMD_CMP_ICV = 0x7f, ++ MSPRO_CMD_FORMAT = 0x10, ++ MSPRO_CMD_SLEEP = 0x11, ++ MSPRO_CMD_WAKEUP = 0x12, ++ MSPRO_CMD_READ_DATA = 0x20, ++ MSPRO_CMD_WRITE_DATA = 0x21, ++ MSPRO_CMD_READ_ATRB = 0x24, ++ MSPRO_CMD_STOP = 0x25, ++ MSPRO_CMD_ERASE = 0x26, ++ MSPRO_CMD_READ_QUAD = 0x27, ++ MSPRO_CMD_WRITE_QUAD = 0x28, ++ MSPRO_CMD_SET_IBD = 0x46, ++ MSPRO_CMD_GET_IBD = 0x47, ++ MSPRO_CMD_IN_IO_DATA = 0xb0, ++ MSPRO_CMD_OUT_IO_DATA = 0xb1, ++ MSPRO_CMD_READ_IO_ATRB = 0xb2, ++ MSPRO_CMD_IN_IO_FIFO = 0xb3, ++ MSPRO_CMD_OUT_IO_FIFO = 0xb4, ++ MSPRO_CMD_IN_IOM = 0xb5, ++ MSPRO_CMD_OUT_IOM = 0xb6, ++}; ++ ++/*** Driver structures and functions ***/ ++ ++#define MEMSTICK_PART_SHIFT 3 ++ ++enum memstick_param { MEMSTICK_POWER = 1, MEMSTICK_INTERFACE }; ++ ++#define MEMSTICK_POWER_OFF 0 ++#define MEMSTICK_POWER_ON 1 ++ ++#define MEMSTICK_SERIAL 0 ++#define MEMSTICK_PAR4 1 ++#define MEMSTICK_PAR8 2 ++ ++struct memstick_host; ++struct memstick_driver; ++ ++#define MEMSTICK_MATCH_ALL 0x01 ++ ++#define MEMSTICK_TYPE_LEGACY 0xff ++#define MEMSTICK_TYPE_DUO 0x00 ++#define MEMSTICK_TYPE_PRO 0x01 ++ ++#define MEMSTICK_CATEGORY_STORAGE 0xff ++#define MEMSTICK_CATEGORY_STORAGE_DUO 0x00 ++ ++#define MEMSTICK_CLASS_GENERIC 0xff ++#define MEMSTICK_CLASS_GENERIC_DUO 0x00 ++ ++ ++struct memstick_device_id { ++ unsigned char match_flags; ++ unsigned char type; ++ unsigned char category; ++ unsigned char class; ++}; ++ ++struct memstick_request { ++ unsigned char tpc; ++ unsigned char data_dir:1, ++ need_card_int:1, ++ long_data:1; ++ unsigned char int_reg; ++ int error; ++ union { ++ struct scatterlist sg; ++ struct { ++ unsigned char data_len; ++ unsigned char data[15]; ++ }; ++ }; ++}; ++ ++struct memstick_dev { ++ struct memstick_device_id id; ++ struct memstick_host *host; ++ struct ms_register_addr reg_addr; ++ struct completion mrq_complete; ++ struct memstick_request current_mrq; ++ ++ /* Check that media driver is still willing to operate the device. */ ++ int (*check)(struct memstick_dev *card); ++ /* Get next request from the media driver. */ ++ int (*next_request)(struct memstick_dev *card, ++ struct memstick_request **mrq); ++ ++ struct device dev; ++}; ++ ++struct memstick_host { ++ struct mutex lock; ++ unsigned int id; ++ unsigned int caps; ++#define MEMSTICK_CAP_AUTO_GET_INT 1 ++#define MEMSTICK_CAP_PAR4 2 ++#define MEMSTICK_CAP_PAR8 4 ++ ++ struct work_struct media_checker; ++ struct class_device cdev; ++ ++ struct memstick_dev *card; ++ unsigned int retries; ++ ++ /* Notify the host that some requests are pending. */ ++ void (*request)(struct memstick_host *host); ++ /* Set host IO parameters (power, clock, etc). */ ++ void (*set_param)(struct memstick_host *host, ++ enum memstick_param param, ++ int value); ++ unsigned long private[0] ____cacheline_aligned; ++}; ++ ++struct memstick_driver { ++ struct memstick_device_id *id_table; ++ int (*probe)(struct memstick_dev *card); ++ void (*remove)(struct memstick_dev *card); ++ int (*suspend)(struct memstick_dev *card, ++ pm_message_t state); ++ int (*resume)(struct memstick_dev *card); ++ ++ struct device_driver driver; ++}; ++ ++int memstick_register_driver(struct memstick_driver *drv); ++void memstick_unregister_driver(struct memstick_driver *drv); ++ ++struct memstick_host *memstick_alloc_host(unsigned int extra, ++ struct device *dev); ++ ++int memstick_add_host(struct memstick_host *host); ++void memstick_remove_host(struct memstick_host *host); ++void memstick_free_host(struct memstick_host *host); ++void memstick_detect_change(struct memstick_host *host); ++void memstick_suspend_host(struct memstick_host *host); ++void memstick_resume_host(struct memstick_host *host); ++ ++void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc, ++ struct scatterlist *sg); ++void memstick_init_req(struct memstick_request *mrq, unsigned char tpc, ++ void *buf, size_t length); ++int memstick_next_req(struct memstick_host *host, ++ struct memstick_request **mrq); ++void memstick_new_req(struct memstick_host *host); ++ ++int memstick_set_rw_addr(struct memstick_dev *card); ++ ++static inline void *memstick_priv(struct memstick_host *host) ++{ ++ return (void *)host->private; ++} ++ ++static inline void *memstick_get_drvdata(struct memstick_dev *card) ++{ ++ return dev_get_drvdata(&card->dev); ++} ++ ++static inline void memstick_set_drvdata(struct memstick_dev *card, void *data) ++{ ++ dev_set_drvdata(&card->dev, data); ++} ++ ++#endif +diff --git a/drivers/mmc/ms/mspro_block.c b/drivers/mmc/ms/mspro_block.c +new file mode 100644 +index 0000000..bd6b069 +--- /dev/null ++++ b/drivers/mmc/ms/mspro_block.c +@@ -0,0 +1,1512 @@ ++/* ++ * Sony MemoryStick Pro storage support ++ * ++ * Copyright (C) 2007 Alex Dubov ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Special thanks to Carlos Corbacho for providing various MemoryStick cards ++ * that made this driver possible. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "memstick.h" ++ ++#define DRIVER_NAME "mspro_block" ++#define DRIVER_VERSION "0.2" ++ ++static int major; ++module_param(major, int, 0644); ++ ++#define MSPRO_BLOCK_MAX_SEGS 32 ++#define MSPRO_BLOCK_MAX_PAGES ((2 << 16) - 1) ++ ++#define MSPRO_BLOCK_SIGNATURE 0xa5c3 ++#define MSPRO_BLOCK_MAX_ATTRIBUTES 41 ++ ++static unsigned int rq_byte_size(struct request *rq) ++{ ++ if (blk_fs_request(rq)) ++ return rq->hard_nr_sectors << 9; ++ ++ return rq->data_len; ++} ++ ++static inline void __end_request(struct request *rq, int uptodate, ++ unsigned int nr_bytes, int dequeue) ++{ ++ if (!end_that_request_chunk(rq, uptodate, nr_bytes)) { ++ if (dequeue) ++ blkdev_dequeue_request(rq); ++ add_disk_randomness(rq->rq_disk); ++ end_that_request_last(rq, uptodate); ++ } ++} ++ ++enum { ++ MSPRO_BLOCK_ID_SYSINFO = 0x10, ++ MSPRO_BLOCK_ID_MODELNAME = 0x15, ++ MSPRO_BLOCK_ID_MBR = 0x20, ++ MSPRO_BLOCK_ID_PBR16 = 0x21, ++ MSPRO_BLOCK_ID_PBR32 = 0x22, ++ MSPRO_BLOCK_ID_SPECFILEVALUES1 = 0x25, ++ MSPRO_BLOCK_ID_SPECFILEVALUES2 = 0x26, ++ MSPRO_BLOCK_ID_DEVINFO = 0x30 ++}; ++ ++struct mspro_sys_attr { ++ size_t size; ++ void *data; ++ unsigned char id; ++ char name[32]; ++ struct device_attribute dev_attr; ++}; ++ ++struct mspro_attr_entry { ++ unsigned int address; ++ unsigned int size; ++ unsigned char id; ++ unsigned char reserved[3]; ++} __attribute__((packed)); ++ ++struct mspro_attribute { ++ unsigned short signature; ++ unsigned short version; ++ unsigned char count; ++ unsigned char reserved[11]; ++ struct mspro_attr_entry entries[]; ++} __attribute__((packed)); ++ ++struct mspro_sys_info { ++ unsigned char class; ++ unsigned char reserved0; ++ unsigned short block_size; ++ unsigned short block_count; ++ unsigned short user_block_count; ++ unsigned short page_size; ++ unsigned char reserved1[2]; ++ unsigned char assembly_date[8]; ++ unsigned int serial_number; ++ unsigned char assembly_maker_code; ++ unsigned char assembly_model_code[3]; ++ unsigned short memory_maker_code; ++ unsigned short memory_model_code; ++ unsigned char reserved2[4]; ++ unsigned char vcc; ++ unsigned char vpp; ++ unsigned short controller_number; ++ unsigned short controller_function; ++ unsigned short start_sector; ++ unsigned short unit_size; ++ unsigned char ms_sub_class; ++ unsigned char reserved3[4]; ++ unsigned char interface_type; ++ unsigned short controller_code; ++ unsigned char format_type; ++ unsigned char reserved4; ++ unsigned char device_type; ++ unsigned char reserved5[7]; ++ unsigned char mspro_id[16]; ++ unsigned char reserved6[16]; ++} __attribute__((packed)); ++ ++struct mspro_mbr { ++ unsigned char boot_partition; ++ unsigned char start_head; ++ unsigned char start_sector; ++ unsigned char start_cylinder; ++ unsigned char partition_type; ++ unsigned char end_head; ++ unsigned char end_sector; ++ unsigned char end_cylinder; ++ unsigned int start_sectors; ++ unsigned int sectors_per_partition; ++} __attribute__((packed)); ++ ++struct mspro_specfile { ++ char name[8]; ++ char ext[3]; ++ unsigned char attr; ++ unsigned char reserved[10]; ++ unsigned short time; ++ unsigned short date; ++ unsigned short cluster; ++ unsigned int size; ++} __attribute__((packed)); ++ ++struct mspro_devinfo { ++ unsigned short cylinders; ++ unsigned short heads; ++ unsigned short bytes_per_track; ++ unsigned short bytes_per_sector; ++ unsigned short sectors_per_track; ++ unsigned char reserved[6]; ++} __attribute__((packed)); ++ ++struct mspro_block_data { ++ struct memstick_dev *card; ++ unsigned int usage_count; ++ unsigned int caps; ++ struct gendisk *disk; ++ struct request_queue *queue; ++ spinlock_t q_lock; ++ wait_queue_head_t q_wait; ++ struct task_struct *q_thread; ++ ++ unsigned short page_size; ++ unsigned short cylinders; ++ unsigned short heads; ++ unsigned short sectors_per_track; ++ ++ unsigned char system; ++ unsigned char read_only:1, ++ active:1, ++ has_request:1, ++ data_dir:1; ++ unsigned char transfer_cmd; ++ ++ int (*mrq_handler)(struct memstick_dev *card, ++ struct memstick_request **mrq); ++ ++ struct attribute_group attr_group; ++ ++ struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; ++ unsigned int seg_count; ++ unsigned int current_seg; ++ unsigned short current_page; ++}; ++ ++static DEFINE_IDR(mspro_block_disk_idr); ++static DEFINE_MUTEX(mspro_block_disk_lock); ++ ++/*** Block device ***/ ++ ++static int mspro_block_bd_open(struct inode *inode, struct file *filp) ++{ ++ struct gendisk *disk = inode->i_bdev->bd_disk; ++ struct mspro_block_data *msb = disk->private_data; ++ int rc = -ENXIO; ++ ++ mutex_lock(&mspro_block_disk_lock); ++ ++ if (msb && msb->card) { ++ msb->usage_count++; ++ if ((filp->f_mode & FMODE_WRITE) && msb->read_only) ++ rc = -EROFS; ++ else ++ rc = 0; ++ } ++ ++ mutex_unlock(&mspro_block_disk_lock); ++ ++ return rc; ++} ++ ++ ++static int mspro_block_disk_release(struct gendisk *disk) ++{ ++ struct mspro_block_data *msb = disk->private_data; ++ int disk_id = disk->first_minor >> MEMSTICK_PART_SHIFT; ++ ++ mutex_lock(&mspro_block_disk_lock); ++ ++ if (msb->usage_count) { ++ msb->usage_count--; ++ if (!msb->usage_count) { ++ kfree(msb); ++ disk->private_data = NULL; ++ idr_remove(&mspro_block_disk_idr, disk_id); ++ put_disk(disk); ++ } ++ } ++ ++ mutex_unlock(&mspro_block_disk_lock); ++ ++ return 0; ++} ++ ++static int mspro_block_bd_release(struct inode *inode, struct file *filp) ++{ ++ struct gendisk *disk = inode->i_bdev->bd_disk; ++ return mspro_block_disk_release(disk); ++} ++ ++static int mspro_block_bd_getgeo(struct block_device *bdev, ++ struct hd_geometry *geo) ++{ ++ struct mspro_block_data *msb = bdev->bd_disk->private_data; ++ ++ geo->heads = msb->heads; ++ geo->sectors = msb->sectors_per_track; ++ geo->cylinders = msb->cylinders; ++ ++ return 0; ++} ++ ++static struct block_device_operations ms_block_bdops = { ++ .open = mspro_block_bd_open, ++ .release = mspro_block_bd_release, ++ .getgeo = mspro_block_bd_getgeo, ++ .owner = THIS_MODULE ++}; ++ ++/*** Information ***/ ++ ++static struct mspro_sys_attr *mspro_from_sysfs_attr(struct attribute *attr) ++{ ++ struct device_attribute *dev_attr ++ = container_of(attr, struct device_attribute, attr); ++ return container_of(dev_attr, struct mspro_sys_attr, dev_attr); ++} ++ ++static const char *mspro_block_attr_name(unsigned char tag) ++{ ++ switch (tag) { ++ case MSPRO_BLOCK_ID_SYSINFO: ++ return "attr_sysinfo"; ++ case MSPRO_BLOCK_ID_MODELNAME: ++ return "attr_modelname"; ++ case MSPRO_BLOCK_ID_MBR: ++ return "attr_mbr"; ++ case MSPRO_BLOCK_ID_PBR16: ++ return "attr_pbr16"; ++ case MSPRO_BLOCK_ID_PBR32: ++ return "attr_pbr32"; ++ case MSPRO_BLOCK_ID_SPECFILEVALUES1: ++ return "attr_specfilevalues1"; ++ case MSPRO_BLOCK_ID_SPECFILEVALUES2: ++ return "attr_specfilevalues2"; ++ case MSPRO_BLOCK_ID_DEVINFO: ++ return "attr_devinfo"; ++ default: ++ return NULL; ++ }; ++} ++ ++typedef ssize_t (*sysfs_show_t)(struct device *dev, ++ struct device_attribute *attr, ++ char *buffer); ++ ++static ssize_t mspro_block_attr_show_default(struct device *dev, ++ struct device_attribute *attr, ++ char *buffer) ++{ ++ struct mspro_sys_attr *s_attr = container_of(attr, ++ struct mspro_sys_attr, ++ dev_attr); ++ ++ ssize_t cnt, rc = 0; ++ ++ for (cnt = 0; cnt < s_attr->size; cnt++) { ++ if (cnt && !(cnt % 16)) { ++ if (PAGE_SIZE - rc) ++ buffer[rc++] = '\n'; ++ } ++ ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "%02x ", ++ ((unsigned char *)s_attr->data)[cnt]); ++ } ++ return rc; ++} ++ ++static ssize_t mspro_block_attr_show_sysinfo(struct device *dev, ++ struct device_attribute *attr, ++ char *buffer) ++{ ++ struct mspro_sys_attr *x_attr = container_of(attr, ++ struct mspro_sys_attr, ++ dev_attr); ++ struct mspro_sys_info *x_sys = x_attr->data; ++ ssize_t rc = 0; ++ int date_tz = 0, date_tz_f = 0; ++ ++ if (x_sys->assembly_date[0] > 0x80U) { ++ date_tz = (~x_sys->assembly_date[0]) + 1; ++ date_tz_f = date_tz & 3; ++ date_tz >>= 2; ++ date_tz = -date_tz; ++ date_tz_f *= 15; ++ } else if (x_sys->assembly_date[0] < 0x80U) { ++ date_tz = x_sys->assembly_date[0]; ++ date_tz_f = date_tz & 3; ++ date_tz >>= 2; ++ date_tz_f *= 15; ++ } ++ ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "class: %x\n", ++ x_sys->class); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block size: %x\n", ++ be16_to_cpu(x_sys->block_size)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block count: %x\n", ++ be16_to_cpu(x_sys->block_count)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "user block count: %x\n", ++ be16_to_cpu(x_sys->user_block_count)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "page size: %x\n", ++ be16_to_cpu(x_sys->page_size)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: " ++ "GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n", ++ date_tz, date_tz_f, ++ be16_to_cpu(*(unsigned short *)&x_sys->assembly_date[1]), ++ x_sys->assembly_date[3], x_sys->assembly_date[4], ++ x_sys->assembly_date[5], x_sys->assembly_date[6], ++ x_sys->assembly_date[7]); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "serial number: %x\n", ++ be32_to_cpu(x_sys->serial_number)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly maker code: %x\n", ++ x_sys->assembly_maker_code); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly model code: " ++ "%02x%02x%02x\n", x_sys->assembly_model_code[0], ++ x_sys->assembly_model_code[1], ++ x_sys->assembly_model_code[2]); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory maker code: %x\n", ++ be16_to_cpu(x_sys->memory_maker_code)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory model code: %x\n", ++ be16_to_cpu(x_sys->memory_model_code)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vcc: %x\n", ++ x_sys->vcc); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vpp: %x\n", ++ x_sys->vpp); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller number: %x\n", ++ be16_to_cpu(x_sys->controller_number)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller function: %x\n", ++ be16_to_cpu(x_sys->controller_function)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n", ++ be16_to_cpu(x_sys->start_sector)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "unit size: %x\n", ++ be16_to_cpu(x_sys->unit_size)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sub class: %x\n", ++ x_sys->ms_sub_class); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "interface type: %x\n", ++ x_sys->interface_type); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller code: %x\n", ++ be16_to_cpu(x_sys->controller_code)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "format type: %x\n", ++ x_sys->format_type); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "device type: %x\n", ++ x_sys->device_type); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "mspro id: %s\n", ++ x_sys->mspro_id); ++ return rc; ++} ++ ++static ssize_t mspro_block_attr_show_modelname(struct device *dev, ++ struct device_attribute *attr, ++ char *buffer) ++{ ++ struct mspro_sys_attr *s_attr = container_of(attr, ++ struct mspro_sys_attr, ++ dev_attr); ++ ++ return scnprintf(buffer, PAGE_SIZE, "%s", (char *)s_attr->data); ++} ++ ++static ssize_t mspro_block_attr_show_mbr(struct device *dev, ++ struct device_attribute *attr, ++ char *buffer) ++{ ++ struct mspro_sys_attr *x_attr = container_of(attr, ++ struct mspro_sys_attr, ++ dev_attr); ++ struct mspro_mbr *x_mbr = x_attr->data; ++ ssize_t rc = 0; ++ ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "boot partition: %x\n", ++ x_mbr->boot_partition); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start head: %x\n", ++ x_mbr->start_head); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n", ++ x_mbr->start_sector); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cylinder: %x\n", ++ x_mbr->start_cylinder); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "partition type: %x\n", ++ x_mbr->partition_type); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end head: %x\n", ++ x_mbr->end_head); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end sector: %x\n", ++ x_mbr->end_sector); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end cylinder: %x\n", ++ x_mbr->end_cylinder); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sectors: %x\n", ++ x_mbr->start_sectors); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, ++ "sectors per partition: %x\n", ++ x_mbr->sectors_per_partition); ++ return rc; ++} ++ ++static ssize_t mspro_block_attr_show_specfile(struct device *dev, ++ struct device_attribute *attr, ++ char *buffer) ++{ ++ struct mspro_sys_attr *x_attr = container_of(attr, ++ struct mspro_sys_attr, ++ dev_attr); ++ struct mspro_specfile *x_spfile = x_attr->data; ++ char name[9], ext[4]; ++ ssize_t rc = 0; ++ ++ memcpy(name, x_spfile->name, 8); ++ name[8] = 0; ++ memcpy(ext, x_spfile->ext, 3); ++ ext[3] = 0; ++ ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "name: %s\n", name); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "ext: %s\n", ext); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "attribute: %x\n", ++ x_spfile->attr); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "time: %d:%d:%d\n", ++ x_spfile->time >> 11, ++ (x_spfile->time >> 5) & 0x3f, ++ (x_spfile->time & 0x1f) * 2); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "date: %d-%d-%d\n", ++ (x_spfile->date >> 9) + 1980, ++ (x_spfile->date >> 5) & 0xf, ++ x_spfile->date & 0x1f); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cluster: %x\n", ++ x_spfile->cluster); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "size: %x\n", ++ x_spfile->size); ++ return rc; ++} ++ ++static ssize_t mspro_block_attr_show_devinfo(struct device *dev, ++ struct device_attribute *attr, ++ char *buffer) ++{ ++ struct mspro_sys_attr *x_attr = container_of(attr, ++ struct mspro_sys_attr, ++ dev_attr); ++ struct mspro_devinfo *x_devinfo = x_attr->data; ++ ssize_t rc = 0; ++ ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "cylinders: %x\n", ++ be16_to_cpu(x_devinfo->cylinders)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "heads: %x\n", ++ be16_to_cpu(x_devinfo->heads)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per track: %x\n", ++ be16_to_cpu(x_devinfo->bytes_per_track)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per sector: %x\n", ++ be16_to_cpu(x_devinfo->bytes_per_sector)); ++ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sectors per track: %x\n", ++ be16_to_cpu(x_devinfo->sectors_per_track)); ++ return rc; ++} ++ ++static sysfs_show_t mspro_block_attr_show(unsigned char tag) ++{ ++ switch (tag) { ++ case MSPRO_BLOCK_ID_SYSINFO: ++ return mspro_block_attr_show_sysinfo; ++ case MSPRO_BLOCK_ID_MODELNAME: ++ return mspro_block_attr_show_modelname; ++ case MSPRO_BLOCK_ID_MBR: ++ return mspro_block_attr_show_mbr; ++ case MSPRO_BLOCK_ID_SPECFILEVALUES1: ++ case MSPRO_BLOCK_ID_SPECFILEVALUES2: ++ return mspro_block_attr_show_specfile; ++ case MSPRO_BLOCK_ID_DEVINFO: ++ return mspro_block_attr_show_devinfo; ++ default: ++ return mspro_block_attr_show_default; ++ } ++} ++ ++/*** Protocol handlers ***/ ++ ++/* ++ * Functions prefixed with "h_" are protocol callbacks. They can be called from ++ * interrupt context. Return value of 0 means that request processing is still ++ * ongoing, while special error value of -EAGAIN means that current request is ++ * finished (and request processor should come back some time later). ++ */ ++ ++static int h_mspro_block_req_init(struct memstick_dev *card, ++ struct memstick_request **mrq) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ ++ *mrq = &card->current_mrq; ++ card->next_request = msb->mrq_handler; ++ return 0; ++} ++ ++static int h_mspro_block_default(struct memstick_dev *card, ++ struct memstick_request **mrq) ++{ ++ complete(&card->mrq_complete); ++ if (!(*mrq)->error) ++ return -EAGAIN; ++ else ++ return (*mrq)->error; ++} ++ ++static int h_mspro_block_get_ro(struct memstick_dev *card, ++ struct memstick_request **mrq) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ ++ if ((*mrq)->error) { ++ complete(&card->mrq_complete); ++ return (*mrq)->error; ++ } ++ ++ if ((*mrq)->data[offsetof(struct ms_status_register, status0)] ++ & MEMSTICK_STATUS0_WP) ++ msb->read_only = 1; ++ else ++ msb->read_only = 0; ++ ++ complete(&card->mrq_complete); ++ return -EAGAIN; ++} ++ ++static int h_mspro_block_wait_for_ced(struct memstick_dev *card, ++ struct memstick_request **mrq) ++{ ++ if ((*mrq)->error) { ++ complete(&card->mrq_complete); ++ return (*mrq)->error; ++ } ++ ++#ifdef DBG ++ dev_dbg(&card->dev, "wait for ced: value %x\n", (*mrq)->data[0]); ++#endif ++ ++ if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) { ++ card->current_mrq.error = -EFAULT; ++ complete(&card->mrq_complete); ++ return card->current_mrq.error; ++ } ++ ++ if (!((*mrq)->data[0] & MEMSTICK_INT_CED)) ++ return 0; ++ else { ++ card->current_mrq.error = 0; ++ complete(&card->mrq_complete); ++ return -EAGAIN; ++ } ++} ++ ++static int h_mspro_block_transfer_data(struct memstick_dev *card, ++ struct memstick_request **mrq) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ unsigned char t_val = 0; ++ struct scatterlist t_sg = { 0 }; ++ size_t t_offset; ++ ++ if ((*mrq)->error) { ++ complete(&card->mrq_complete); ++ return (*mrq)->error; ++ } ++ ++ switch ((*mrq)->tpc) { ++ case MS_TPC_WRITE_REG: ++ memstick_init_req(*mrq, MS_TPC_SET_CMD, &msb->transfer_cmd, 1); ++ (*mrq)->need_card_int = 1; ++ return 0; ++ case MS_TPC_SET_CMD: ++ t_val = (*mrq)->int_reg; ++ memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1); ++ if (msb->caps & MEMSTICK_CAP_AUTO_GET_INT) ++ goto has_int_reg; ++ return 0; ++ case MS_TPC_GET_INT: ++ t_val = (*mrq)->data[0]; ++has_int_reg: ++ if (t_val & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) { ++ t_val = MSPRO_CMD_STOP; ++ memstick_init_req(*mrq, MS_TPC_SET_CMD, &t_val, 1); ++ card->next_request = h_mspro_block_default; ++ return 0; ++ } ++ ++ if (msb->current_page ++ == (msb->req_sg[msb->current_seg].length ++ / msb->page_size)) { ++ msb->current_page = 0; ++ msb->current_seg++; ++ ++ if (msb->current_seg == msb->seg_count) { ++ if (t_val & MEMSTICK_INT_CED) { ++ complete(&card->mrq_complete); ++ return -EAGAIN; ++ } else { ++ card->next_request ++ = h_mspro_block_wait_for_ced; ++ memstick_init_req(*mrq, MS_TPC_GET_INT, ++ NULL, 1); ++ return 0; ++ } ++ } ++ } ++ ++ if (!(t_val & MEMSTICK_INT_BREQ)) { ++ memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1); ++ return 0; ++ } ++ ++ t_offset = msb->req_sg[msb->current_seg].offset; ++ t_offset += msb->current_page * msb->page_size; ++ ++ sg_set_page(&t_sg, ++ nth_page(sg_page(&(msb->req_sg[msb->current_seg])), ++ t_offset >> PAGE_SHIFT), ++ msb->page_size, offset_in_page(t_offset)); ++ ++ memstick_init_req_sg(*mrq, msb->data_dir == READ ++ ? MS_TPC_READ_LONG_DATA ++ : MS_TPC_WRITE_LONG_DATA, ++ &t_sg); ++ (*mrq)->need_card_int = 1; ++ return 0; ++ case MS_TPC_READ_LONG_DATA: ++ case MS_TPC_WRITE_LONG_DATA: ++ msb->current_page++; ++ if (msb->caps & MEMSTICK_CAP_AUTO_GET_INT) { ++ t_val = (*mrq)->int_reg; ++ goto has_int_reg; ++ } else { ++ memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1); ++ return 0; ++ } ++ ++ default: ++ BUG(); ++ } ++} ++ ++/*** Data transfer ***/ ++ ++static void mspro_block_process_request(struct memstick_dev *card, ++ struct request *req) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ struct mspro_param_register param; ++ int rc, chunk, cnt; ++ unsigned short page_count; ++ sector_t t_sec; ++ unsigned long flags; ++ ++ do { ++ page_count = 0; ++ msb->current_seg = 0; ++ msb->seg_count = blk_rq_map_sg(req->q, req, msb->req_sg); ++ ++ if (msb->seg_count) { ++ msb->current_page = 0; ++ for (rc = 0; rc < msb->seg_count; rc++) ++ page_count += msb->req_sg[rc].length ++ / msb->page_size; ++ ++ t_sec = req->sector; ++ sector_div(t_sec, msb->page_size >> 9); ++ param.system = msb->system; ++ param.data_count = cpu_to_be16(page_count); ++ param.data_address = cpu_to_be32((uint32_t)t_sec); ++ param.tpc_param = 0; ++ ++ msb->data_dir = rq_data_dir(req); ++ msb->transfer_cmd = msb->data_dir == READ ++ ? MSPRO_CMD_READ_DATA ++ : MSPRO_CMD_WRITE_DATA; ++ ++#ifdef DBG ++ dev_dbg(&card->dev, "data transfer: cmd %x, " ++ "lba %x, count %x\n", msb->transfer_cmd, ++ be32_to_cpu(param.data_address), ++ page_count); ++#endif ++ ++ card->next_request = h_mspro_block_req_init; ++ msb->mrq_handler = h_mspro_block_transfer_data; ++ memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ++ ¶m, sizeof(param)); ++ memstick_new_req(card->host); ++ wait_for_completion(&card->mrq_complete); ++ rc = card->current_mrq.error; ++ ++ if (rc || (card->current_mrq.tpc == MSPRO_CMD_STOP)) { ++ for (cnt = 0; cnt < msb->current_seg; cnt++) ++ page_count += msb->req_sg[cnt].length ++ / msb->page_size; ++ ++ if (msb->current_page) ++ page_count += msb->current_page - 1; ++ ++ if (page_count && (msb->data_dir == READ)) ++ rc = msb->page_size * page_count; ++ else ++ rc = -EIO; ++ } else ++ rc = msb->page_size * page_count; ++ } else ++ rc = -EFAULT; ++ ++ spin_lock_irqsave(&msb->q_lock, flags); ++ if (rc >= 0) ++ chunk = end_that_request_chunk(req, 1, rc); ++ else ++ chunk = end_that_request_first(req, rc, ++ req->current_nr_sectors); ++ ++#ifdef DBG ++ dev_dbg(&card->dev, "end chunk %d, %d\n", rc, chunk); ++#endif ++ if (!chunk) { ++ add_disk_randomness(req->rq_disk); ++ blkdev_dequeue_request(req); ++ end_that_request_last(req, rc > 0 ? 1 : rc); ++ } ++ spin_unlock_irqrestore(&msb->q_lock, flags); ++ } while (chunk); ++ ++} ++ ++static int mspro_block_has_request(struct mspro_block_data *msb) ++{ ++ int rc = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&msb->q_lock, flags); ++ if (kthread_should_stop() || msb->has_request) ++ rc = 1; ++ spin_unlock_irqrestore(&msb->q_lock, flags); ++ return rc; ++} ++ ++static int mspro_block_queue_thread(void *data) ++{ ++ struct memstick_dev *card = data; ++ struct memstick_host *host = card->host; ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ struct request *req; ++ unsigned long flags; ++ ++ while (1) { ++ wait_event(msb->q_wait, mspro_block_has_request(msb)); ++#ifdef DBG ++ dev_dbg(&card->dev, "thread iter\n"); ++#endif ++ ++ spin_lock_irqsave(&msb->q_lock, flags); ++ req = elv_next_request(msb->queue); ++#ifdef DBG ++ dev_dbg(&card->dev, "next req %p\n", req); ++#endif ++ if (!req) { ++ msb->has_request = 0; ++ if (kthread_should_stop()) { ++ spin_unlock_irqrestore(&msb->q_lock, flags); ++ break; ++ } ++ } else ++ msb->has_request = 1; ++ spin_unlock_irqrestore(&msb->q_lock, flags); ++ ++ if (req) { ++ mutex_lock(&host->lock); ++ mspro_block_process_request(card, req); ++ mutex_unlock(&host->lock); ++ } ++ } ++#ifdef DBG ++ dev_dbg(&card->dev, "thread finished\n"); ++#endif ++ return 0; ++} ++ ++static void mspro_block_request(struct request_queue *q) ++{ ++ struct memstick_dev *card = q->queuedata; ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ struct request *req = NULL; ++ ++ if (msb->q_thread) { ++ msb->has_request = 1; ++ wake_up_all(&msb->q_wait); ++ } else { ++ while ((req = elv_next_request(q)) != NULL) ++ __end_request(req, -ENODEV, rq_byte_size(req), 1); ++ } ++} ++ ++/*** Initialization ***/ ++ ++static int mspro_block_wait_for_ced(struct memstick_dev *card) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ ++ card->next_request = h_mspro_block_req_init; ++ msb->mrq_handler = h_mspro_block_wait_for_ced; ++ memstick_init_req(&card->current_mrq, MS_TPC_GET_INT, NULL, 1); ++ memstick_new_req(card->host); ++ wait_for_completion(&card->mrq_complete); ++ return card->current_mrq.error; ++} ++ ++static int mspro_block_switch_interface(struct memstick_dev *card, ++ unsigned int interface) ++{ ++ struct memstick_host *host = card->host; ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ struct mspro_param_register param = { ++ .system = 0, ++ .data_count = 0, ++ .data_address = 0, ++ .tpc_param = 0 ++ }; ++ ++ switch (interface) { ++ case MEMSTICK_SERIAL: ++ param.system = MEMSTICK_SYS_SERIAL; ++ break; ++ case MEMSTICK_PAR4: ++ param.system = MEMSTICK_SYS_PAR4; ++ break; ++ case MEMSTICK_PAR8: ++ if (msb->system != MEMSTICK_SYS_PAR4) ++ return -EINVAL; ++ param.system = MEMSTICK_SYS_PAR8; ++ break; ++ default: ++ return -EINVAL; ++ }; ++ ++ card->next_request = h_mspro_block_req_init; ++ msb->mrq_handler = h_mspro_block_default; ++ memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, ++ sizeof(param)); ++ memstick_new_req(host); ++ wait_for_completion(&card->mrq_complete); ++#ifdef DBG ++ dev_dbg(&card->dev, "switch interface to %x, error %d\n", interface, ++ card->current_mrq.error); ++#endif ++ if (card->current_mrq.error) ++ return card->current_mrq.error; ++ ++ msb->system = param.system; ++ host->set_param(host, MEMSTICK_INTERFACE, interface); ++ ++ card->next_request = h_mspro_block_req_init; ++ msb->mrq_handler = h_mspro_block_default; ++ memstick_init_req(&card->current_mrq, MS_TPC_GET_INT, NULL, 1); ++ memstick_new_req(card->host); ++ wait_for_completion(&card->mrq_complete); ++ ++ if (card->current_mrq.error) { ++ msb->system = MEMSTICK_SYS_SERIAL; ++ host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); ++ msleep(10); ++ host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); ++ host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); ++ ++ if (memstick_set_rw_addr(card)) ++ return card->current_mrq.error; ++ ++ param.system = msb->system; ++ ++ card->next_request = h_mspro_block_req_init; ++ msb->mrq_handler = h_mspro_block_default; ++ memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, ++ sizeof(param)); ++ memstick_new_req(host); ++ wait_for_completion(&card->mrq_complete); ++ ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/* Memory allocated for attributes by this function should be freed by ++ * mspro_block_data_clear, no matter if the initialization process succeded ++ * or failed. ++ */ ++static int mspro_block_read_attributes(struct memstick_dev *card) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ struct mspro_param_register param = { ++ .system = msb->system, ++ .data_count = cpu_to_be16(1), ++ .data_address = 0, ++ .tpc_param = 0 ++ }; ++ struct mspro_attribute *attr = NULL; ++ struct mspro_sys_attr *s_attr = NULL; ++ unsigned char *buffer = NULL; ++ int cnt, rc, attr_count; ++ unsigned int addr; ++ unsigned short page_count; ++ ++ attr = kmalloc(msb->page_size, GFP_KERNEL); ++ if (!attr) ++ return -ENOMEM; ++ ++ sg_init_one(&msb->req_sg[0], attr, msb->page_size); ++ msb->seg_count = 1; ++ msb->current_seg = 0; ++ msb->current_page = 0; ++ msb->data_dir = READ; ++ msb->transfer_cmd = MSPRO_CMD_READ_ATRB; ++ ++ card->next_request = h_mspro_block_req_init; ++ msb->mrq_handler = h_mspro_block_transfer_data; ++ memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, ++ sizeof(param)); ++ memstick_new_req(card->host); ++ wait_for_completion(&card->mrq_complete); ++ if (card->current_mrq.error) { ++ rc = card->current_mrq.error; ++ goto out_free_attr; ++ } ++ ++ if (be16_to_cpu(attr->signature) != MSPRO_BLOCK_SIGNATURE) { ++ printk(KERN_ERR "%s: unrecognized device signature %x\n", ++ card->dev.bus_id, be16_to_cpu(attr->signature)); ++ rc = -ENODEV; ++ goto out_free_attr; ++ } ++ ++ if (attr->count > MSPRO_BLOCK_MAX_ATTRIBUTES) { ++ printk(KERN_WARNING "%s: way too many attribute entries\n", ++ card->dev.bus_id); ++ attr_count = MSPRO_BLOCK_MAX_ATTRIBUTES; ++ } else ++ attr_count = attr->count; ++ ++ msb->attr_group.attrs = kzalloc((attr_count + 1) ++ * sizeof(struct attribute), ++ GFP_KERNEL); ++ if (!msb->attr_group.attrs) { ++ rc = -ENOMEM; ++ goto out_free_attr; ++ } ++ msb->attr_group.name = "media_attributes"; ++ ++ buffer = kmalloc(msb->page_size, GFP_KERNEL); ++ if (!buffer) { ++ rc = -ENOMEM; ++ goto out_free_attr; ++ } ++ memcpy(buffer, (char *)attr, msb->page_size); ++ page_count = 1; ++ ++ for (cnt = 0; cnt < attr_count; ++cnt) { ++ s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL); ++ if (!s_attr) { ++ rc = -ENOMEM; ++ goto out_free_buffer; ++ } ++ ++ msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr; ++ addr = be32_to_cpu(attr->entries[cnt].address); ++ rc = be32_to_cpu(attr->entries[cnt].size); ++#ifdef DBG ++ dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, " ++ "size %x\n", cnt, attr->entries[cnt].id, addr, rc); ++#endif ++ s_attr->id = attr->entries[cnt].id; ++ if (mspro_block_attr_name(s_attr->id)) ++ scnprintf(s_attr->name, sizeof(s_attr->name), "%s", ++ mspro_block_attr_name(attr->entries[cnt].id)); ++ else ++ scnprintf(s_attr->name, sizeof(s_attr->name), ++ "attr_x%02x", attr->entries[cnt].id); ++ ++ s_attr->dev_attr.attr.name = s_attr->name; ++ s_attr->dev_attr.attr.mode = S_IRUGO; ++ s_attr->dev_attr.attr.owner = THIS_MODULE; ++ s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id); ++ ++ if (!rc) ++ continue; ++ ++ s_attr->size = rc; ++ s_attr->data = kmalloc(rc, GFP_KERNEL); ++ if (!s_attr->data) { ++ rc = -ENOMEM; ++ goto out_free_buffer; ++ } ++ ++ if (((addr / msb->page_size) ++ == be32_to_cpu(param.data_address)) ++ && (((addr + rc - 1) / msb->page_size) ++ == be32_to_cpu(param.data_address))) { ++ memcpy(s_attr->data, buffer + addr % msb->page_size, ++ rc); ++ continue; ++ } ++ ++ if (page_count <= (rc / msb->page_size)) { ++ kfree(buffer); ++ page_count = (rc / msb->page_size) + 1; ++ buffer = kmalloc(page_count * msb->page_size, ++ GFP_KERNEL); ++ if (!buffer) { ++ rc = -ENOMEM; ++ goto out_free_attr; ++ } ++ } ++ ++ param.system = msb->system; ++ param.data_count = cpu_to_be16((rc / msb->page_size) + 1); ++ param.data_address = cpu_to_be32(addr / msb->page_size); ++ param.tpc_param = 0; ++ ++ sg_init_one(&msb->req_sg[0], buffer, ++ be16_to_cpu(param.data_count) * msb->page_size); ++ msb->seg_count = 1; ++ msb->current_seg = 0; ++ msb->current_page = 0; ++ msb->data_dir = READ; ++ msb->transfer_cmd = MSPRO_CMD_READ_ATRB; ++ ++#ifdef DBG ++ dev_dbg(&card->dev, "reading attribute pages %x, %x\n", ++ be32_to_cpu(param.data_address), ++ be16_to_cpu(param.data_count)); ++#endif ++ ++ card->next_request = h_mspro_block_req_init; ++ msb->mrq_handler = h_mspro_block_transfer_data; ++ memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ++ (char *)¶m, sizeof(param)); ++ memstick_new_req(card->host); ++ wait_for_completion(&card->mrq_complete); ++ if (card->current_mrq.error) { ++ rc = card->current_mrq.error; ++ goto out_free_buffer; ++ } ++ ++ memcpy(s_attr->data, buffer + addr % msb->page_size, rc); ++ } ++ ++ rc = 0; ++out_free_buffer: ++ kfree(buffer); ++out_free_attr: ++ kfree(attr); ++ return rc; ++} ++ ++static int mspro_block_init_card(struct memstick_dev *card) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ struct memstick_host *host = card->host; ++ int rc = 0; ++ ++ msb->system = MEMSTICK_SYS_SERIAL; ++ card->reg_addr.r_offset = offsetof(struct mspro_register, status); ++ card->reg_addr.r_length = sizeof(struct ms_status_register); ++ card->reg_addr.w_offset = offsetof(struct mspro_register, param); ++ card->reg_addr.w_length = sizeof(struct mspro_param_register); ++ ++ if (memstick_set_rw_addr(card)) ++ return -EIO; ++ ++ msb->caps = host->caps; ++ if (msb->caps & MEMSTICK_CAP_PAR4) { ++ if (mspro_block_switch_interface(card, MEMSTICK_PAR4)) { ++ printk(KERN_WARNING "%s: could not switch to " ++ "4-bit mode\n", card->dev.bus_id); ++ msb->caps &= ~MEMSTICK_CAP_PAR4; ++ } else if (msb->caps & MEMSTICK_CAP_PAR8) { ++ if (mspro_block_switch_interface(card, ++ MEMSTICK_PAR8)) { ++ printk(KERN_WARNING "%s: could not switch to " ++ "8-bit mode\n", card->dev.bus_id); ++ msb->caps &= ~MEMSTICK_CAP_PAR8; ++ } ++ } ++ } ++ ++ msleep(200); ++ rc = mspro_block_wait_for_ced(card); ++ if (rc) ++ return rc; ++ dev_dbg(&card->dev, "card activated\n"); ++ if (msb->system != MEMSTICK_SYS_SERIAL) ++ msb->caps |= MEMSTICK_CAP_AUTO_GET_INT; ++ ++ card->next_request = h_mspro_block_req_init; ++ msb->mrq_handler = h_mspro_block_get_ro; ++ memstick_init_req(&card->current_mrq, MS_TPC_READ_REG, NULL, ++ sizeof(struct ms_status_register)); ++ memstick_new_req(card->host); ++ wait_for_completion(&card->mrq_complete); ++ if (card->current_mrq.error) ++ return card->current_mrq.error; ++ ++#ifdef DBG ++ dev_dbg(&card->dev, "card r/w status %d\n", msb->read_only ? 0 : 1); ++#endif ++ ++ msb->page_size = 512; ++ rc = mspro_block_read_attributes(card); ++ if (rc) ++ return rc; ++ ++#ifdef DBG ++ dev_dbg(&card->dev, "attributes loaded\n"); ++#endif ++ return 0; ++ ++} ++ ++static int mspro_block_init_disk(struct memstick_dev *card) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ struct memstick_host *host = card->host; ++ struct mspro_devinfo *dev_info = NULL; ++ struct mspro_sys_info *sys_info = NULL; ++ struct mspro_sys_attr *s_attr = NULL; ++ int rc, disk_id; ++ u64 limit = BLK_BOUNCE_HIGH; ++ unsigned long capacity; ++ ++ if (host->cdev.dev->dma_mask && *(host->cdev.dev->dma_mask)) ++ limit = *(host->cdev.dev->dma_mask); ++ ++ for (rc = 0; msb->attr_group.attrs[rc]; ++rc) { ++ s_attr = mspro_from_sysfs_attr(msb->attr_group.attrs[rc]); ++ ++ if (s_attr->id == MSPRO_BLOCK_ID_DEVINFO) ++ dev_info = s_attr->data; ++ else if (s_attr->id == MSPRO_BLOCK_ID_SYSINFO) ++ sys_info = s_attr->data; ++ } ++ ++ if (!dev_info || !sys_info) ++ return -ENODEV; ++ ++ msb->cylinders = be16_to_cpu(dev_info->cylinders); ++ msb->heads = be16_to_cpu(dev_info->heads); ++ msb->sectors_per_track = be16_to_cpu(dev_info->sectors_per_track); ++ ++ msb->page_size = be16_to_cpu(sys_info->unit_size); ++ ++ if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ mutex_lock(&mspro_block_disk_lock); ++ rc = idr_get_new(&mspro_block_disk_idr, card, &disk_id); ++ mutex_unlock(&mspro_block_disk_lock); ++ ++ if (rc) ++ return rc; ++ ++ if ((disk_id << MEMSTICK_PART_SHIFT) > 255) { ++ rc = -ENOSPC; ++ goto out_release_id; ++ } ++ ++ msb->disk = alloc_disk(1 << MEMSTICK_PART_SHIFT); ++ if (!msb->disk) { ++ rc = -ENOMEM; ++ goto out_release_id; ++ } ++ ++ spin_lock_init(&msb->q_lock); ++ init_waitqueue_head(&msb->q_wait); ++ ++ msb->queue = blk_init_queue(mspro_block_request, &msb->q_lock); ++ if (!msb->queue) { ++ rc = -ENOMEM; ++ goto out_put_disk; ++ } ++ ++ msb->queue->queuedata = card; ++ ++ blk_queue_bounce_limit(msb->queue, limit); ++ blk_queue_max_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES); ++ blk_queue_max_phys_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS); ++ blk_queue_max_hw_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS); ++ blk_queue_max_segment_size(msb->queue, ++ MSPRO_BLOCK_MAX_PAGES * msb->page_size); ++ ++ msb->disk->major = major; ++ msb->disk->first_minor = disk_id << MEMSTICK_PART_SHIFT; ++ msb->disk->fops = &ms_block_bdops; ++ msb->usage_count = 1; ++ msb->disk->private_data = msb; ++ msb->disk->queue = msb->queue; ++ msb->disk->driverfs_dev = &card->dev; ++ ++ sprintf(msb->disk->disk_name, "mspblk%d", disk_id); ++ ++ blk_queue_hardsect_size(msb->queue, msb->page_size); ++ ++ capacity = be16_to_cpu(sys_info->user_block_count); ++ capacity *= be16_to_cpu(sys_info->block_size); ++ capacity *= msb->page_size >> 9; ++ set_capacity(msb->disk, capacity); ++#ifdef DBG ++ dev_dbg(&card->dev, "capacity set %ld\n", capacity); ++#endif ++ msb->q_thread = kthread_run(mspro_block_queue_thread, card, ++ DRIVER_NAME"d"); ++ if (IS_ERR(msb->q_thread)) ++ goto out_put_disk; ++ ++ mutex_unlock(&host->lock); ++ add_disk(msb->disk); ++ mutex_lock(&host->lock); ++ msb->active = 1; ++ return 0; ++ ++out_put_disk: ++ put_disk(msb->disk); ++out_release_id: ++ mutex_lock(&mspro_block_disk_lock); ++ idr_remove(&mspro_block_disk_idr, disk_id); ++ mutex_unlock(&mspro_block_disk_lock); ++ return rc; ++} ++ ++static void mspro_block_data_clear(struct mspro_block_data *msb) ++{ ++ int cnt; ++ struct mspro_sys_attr *s_attr; ++ ++ if (msb->attr_group.attrs) { ++ for (cnt = 0; msb->attr_group.attrs[cnt]; ++cnt) { ++ s_attr = mspro_from_sysfs_attr(msb->attr_group ++ .attrs[cnt]); ++ kfree(s_attr->data); ++ kfree(s_attr); ++ } ++ kfree(msb->attr_group.attrs); ++ } ++ ++ msb->card = NULL; ++} ++ ++static int mspro_block_check_card(struct memstick_dev *card) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ ++ return (msb->active == 1); ++} ++ ++static int mspro_block_probe(struct memstick_dev *card) ++{ ++ struct mspro_block_data *msb; ++ int rc = 0; ++ ++ msb = kzalloc(sizeof(struct mspro_block_data), GFP_KERNEL); ++ if (!msb) ++ return -ENOMEM; ++ memstick_set_drvdata(card, msb); ++ msb->card = card; ++ ++ rc = mspro_block_init_card(card); ++ ++ if (rc) ++ goto out_free; ++ ++ rc = sysfs_create_group(&card->dev.kobj, &msb->attr_group); ++ if (rc) ++ goto out_free; ++ ++ rc = mspro_block_init_disk(card); ++ if (!rc) { ++ card->check = mspro_block_check_card; ++ return 0; ++ } ++ ++ sysfs_remove_group(&card->dev.kobj, &msb->attr_group); ++out_free: ++ memstick_set_drvdata(card, NULL); ++ mspro_block_data_clear(msb); ++ kfree(msb); ++ return rc; ++} ++ ++static void mspro_block_remove(struct memstick_dev *card) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ struct task_struct *q_thread = NULL; ++ unsigned long flags; ++ ++ del_gendisk(msb->disk); ++ dev_dbg(&card->dev, "mspro block remove\n"); ++ spin_lock_irqsave(&msb->q_lock, flags); ++ q_thread = msb->q_thread; ++ msb->q_thread = NULL; ++ msb->active = 0; ++ spin_unlock_irqrestore(&msb->q_lock, flags); ++ ++ if (q_thread) { ++ mutex_unlock(&card->host->lock); ++ kthread_stop(q_thread); ++ mutex_lock(&card->host->lock); ++ } ++ ++#ifdef DBG ++ dev_dbg(&card->dev, "queue thread stopped\n"); ++#endif ++ ++ blk_cleanup_queue(msb->queue); ++ ++ sysfs_remove_group(&card->dev.kobj, &msb->attr_group); ++ ++ mutex_lock(&mspro_block_disk_lock); ++ mspro_block_data_clear(msb); ++ mutex_unlock(&mspro_block_disk_lock); ++ ++ mspro_block_disk_release(msb->disk); ++ memstick_set_drvdata(card, NULL); ++} ++ ++#ifdef CONFIG_PM ++ ++static int mspro_block_suspend(struct memstick_dev *card, pm_message_t state) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ struct task_struct *q_thread = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&msb->q_lock, flags); ++ q_thread = msb->q_thread; ++ msb->q_thread = NULL; ++ msb->active = 0; ++ blk_stop_queue(msb->queue); ++ spin_unlock_irqrestore(&msb->q_lock, flags); ++ ++ if (q_thread) ++ kthread_stop(q_thread); ++ ++ return 0; ++} ++ ++static int mspro_block_resume(struct memstick_dev *card) ++{ ++ struct mspro_block_data *msb = memstick_get_drvdata(card); ++ unsigned long flags; ++ int rc = 0; ++ ++#ifdef CONFIG_MEMSTICK_UNSAFE_RESUME ++ ++ struct mspro_block_data *new_msb; ++ struct memstick_host *host = card->host; ++ struct mspro_sys_attr *s_attr, *r_attr; ++ unsigned char cnt; ++ ++ mutex_lock(&host->lock); ++ new_msb = kzalloc(sizeof(struct mspro_block_data), GFP_KERNEL); ++ if (!new_msb) { ++ rc = -ENOMEM; ++ goto out_unlock; ++ } ++ ++ new_msb->card = card; ++ memstick_set_drvdata(card, new_msb); ++ if (mspro_block_init_card(card)) ++ goto out_free; ++ ++ for (cnt = 0; new_msb->attr_group.attrs[cnt] ++ && msb->attr_group.attrs[cnt]; ++cnt) { ++ s_attr = mspro_from_sysfs_attr(new_msb->attr_group.attrs[cnt]); ++ r_attr = mspro_from_sysfs_attr(msb->attr_group.attrs[cnt]); ++ ++ if (s_attr->id == MSPRO_BLOCK_ID_SYSINFO ++ && r_attr->id == s_attr->id) { ++ if (memcmp(s_attr->data, r_attr->data, s_attr->size)) ++ break; ++ ++ memstick_set_drvdata(card, msb); ++ msb->q_thread = kthread_run(mspro_block_queue_thread, ++ card, DRIVER_NAME"d"); ++ if (IS_ERR(msb->q_thread)) ++ msb->q_thread = NULL; ++ else ++ msb->active = 1; ++ ++ break; ++ } ++ } ++ ++out_free: ++ memstick_set_drvdata(card, msb); ++ mspro_block_data_clear(new_msb); ++ kfree(new_msb); ++out_unlock: ++ mutex_unlock(&host->lock); ++ ++#endif /* CONFIG_MEMSTICK_UNSAFE_RESUME */ ++ ++ spin_lock_irqsave(&msb->q_lock, flags); ++ blk_start_queue(msb->queue); ++ spin_unlock_irqrestore(&msb->q_lock, flags); ++ return rc; ++} ++ ++#else ++ ++#define mspro_block_suspend NULL ++#define mspro_block_resume NULL ++ ++#endif /* CONFIG_PM */ ++ ++static struct memstick_device_id mspro_block_id_tbl[] = { ++ {MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_PRO, MEMSTICK_CATEGORY_STORAGE_DUO, ++ MEMSTICK_CLASS_GENERIC_DUO}, ++ {} ++}; ++ ++ ++static struct memstick_driver mspro_block_driver = { ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE ++ }, ++ .id_table = mspro_block_id_tbl, ++ .probe = mspro_block_probe, ++ .remove = mspro_block_remove, ++ .suspend = mspro_block_suspend, ++ .resume = mspro_block_resume ++}; ++ ++static int __init mspro_block_init(void) ++{ ++ int rc = -ENOMEM; ++ ++ rc = register_blkdev(major, DRIVER_NAME); ++ if (rc < 0) { ++ printk(KERN_ERR DRIVER_NAME ": failed to register " ++ "major %d, error %d\n", major, rc); ++ return rc; ++ } ++ if (!major) ++ major = rc; ++ ++ rc = memstick_register_driver(&mspro_block_driver); ++ if (rc) ++ unregister_blkdev(major, DRIVER_NAME); ++ return rc; ++} ++ ++static void __exit mspro_block_exit(void) ++{ ++ memstick_unregister_driver(&mspro_block_driver); ++ unregister_blkdev(major, DRIVER_NAME); ++ idr_destroy(&mspro_block_disk_idr); ++} ++ ++module_init(mspro_block_init); ++module_exit(mspro_block_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Alex Dubov"); ++MODULE_DESCRIPTION("Sony MemoryStickPro block device driver"); ++MODULE_DEVICE_TABLE(memstick, mspro_block_id_tbl); ++MODULE_VERSION(DRIVER_VERSION); +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0050-Turn-off-the-Belmont-80-wire-ATA-detection.patch +++ linux-2.6.24/patches/0050-Turn-off-the-Belmont-80-wire-ATA-detection.patch @@ -0,0 +1,26 @@ +From 11e44329b3085fcd285bb556564530cb513d627b Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Thu, 14 Aug 2008 11:02:03 -0400 +Subject: [PATCH 050/170] Turn off the Belmont 80-wire ATA detection + +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/ata/ata_piix.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c +index 72dca47..ff2c79c 100644 +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -703,7 +703,7 @@ static const struct ich_laptop ich_laptop[] = { + { 0x24CA, 0x1025, 0x003d }, /* ICH4 on Acer TM290 */ + { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ + { 0x811a, 0x8086, 0x8119 }, /* SCH on Chelsea */ +- { 0x27DF, 0x1028, 0x02b0 }, /* ICH7 on Belmont */ ++ /* { 0x27DF, 0x1028, 0x02b0 }, ICH7 on Belmont */ + /* end marker */ + { 0, } + }; +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0029-NET_POLL-Pass-skb-via-NET_POLL-rx-routine.patch +++ linux-2.6.24/patches/0029-NET_POLL-Pass-skb-via-NET_POLL-rx-routine.patch @@ -0,0 +1,47 @@ +From 218ff721f8e513f615982b2353301f4d8e5a57b8 Mon Sep 17 00:00:00 2001 +From: Jason Wessel +Date: Fri, 28 Mar 2008 13:18:47 -0500 +Subject: [PATCH 029/170] NET_POLL: Pass skb via NET_POLL rx routine + +This patch is a change to the NET POLL api so that the MAC address or +IP frame information can be parsed by the driver that wishes to use +it. Speficially for kgdboe, it is used to automatically collect the +MAC address of the GDB host. + +Signed-off-by: Jason Wessel +Acked-by: Matt Mackall +--- + include/linux/netpoll.h | 2 +- + net/core/netpoll.c | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h +index 20250d9..20815d8 100644 +--- a/include/linux/netpoll.h ++++ b/include/linux/netpoll.h +@@ -16,7 +16,7 @@ struct netpoll { + struct net_device *dev; + char dev_name[IFNAMSIZ]; + const char *name; +- void (*rx_hook)(struct netpoll *, int, char *, int); ++ void (*rx_hook)(struct netpoll *, int, char *, int, struct sk_buff *); + + u32 local_ip, remote_ip; + u16 local_port, remote_port; +diff --git a/net/core/netpoll.c b/net/core/netpoll.c +index 2386c5e..3184f86 100644 +--- a/net/core/netpoll.c ++++ b/net/core/netpoll.c +@@ -537,7 +537,8 @@ int __netpoll_rx(struct sk_buff *skb) + + np->rx_hook(np, ntohs(uh->source), + (char *)(uh+1), +- ulen - sizeof(struct udphdr)); ++ ulen - sizeof(struct udphdr), ++ skb); + + kfree_skb(skb); + return 1; +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0074-drivers-acpi-hardware-hwsleep.c-Clear-WAK_STS-on-res.patch +++ linux-2.6.24/patches/0074-drivers-acpi-hardware-hwsleep.c-Clear-WAK_STS-on-res.patch @@ -0,0 +1,32 @@ +From fc18c80b8e76e1941265a00b8cedf21fd0a8b5f3 Mon Sep 17 00:00:00 2001 +From: Michael Frey (Senior Manager, MID +Date: Mon, 3 Nov 2008 10:04:42 -0500 +Subject: [PATCH 074/170] drivers/acpi/hardware/hwsleep.c Clear WAK_STS on resume. Fix for LP#285611 + +BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/285611 +Signed-off-by: Michael Frey (Senior Manager, MID) +--- + drivers/acpi/hardware/hwsleep.c | 7 +++++++ + 1 files changed, 7 insertions(+), 0 deletions(-) + +diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c +index 3829a51..ad9cdf6 100644 +--- a/drivers/acpi/hardware/hwsleep.c ++++ b/drivers/acpi/hardware/hwsleep.c +@@ -594,6 +594,13 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) + */ + acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1); + ++ /* ++ * Some BIOSes assume that WAK_STS will be cleared on resume and use ++ * it to determine whether the system is rebooting or resuming. Clear ++ * it for compatibility. ++ */ ++ acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1); ++ + acpi_gbl_system_awake_and_running = TRUE; + + /* Enable power button */ +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0065-ACPI-EC-Some-hardware-requires-burst-mode-to-operate.patch +++ linux-2.6.24/patches/0065-ACPI-EC-Some-hardware-requires-burst-mode-to-operate.patch @@ -0,0 +1,42 @@ +From bfd0b3d3686e2c1c94cb16122de6f9601d0bd7e3 Mon Sep 17 00:00:00 2001 +From: Tony Espy +Date: Thu, 16 Oct 2008 12:46:38 -0400 +Subject: [PATCH 065/170] ACPI: EC: Some hardware requires burst mode to operate properly + +Burst mode temporary (50 ms) locks EC to do only transactions with +driver, without it some hardware returns abstract garbage. + +Reference: http://bugzilla.kernel.org/show_bug.cgi?id=9341 + +Signed-off-by: Alexey Starikovskiy +Signed-off-by: Len Brown +Signed-off-by: Tony Espy +--- + drivers/acpi/ec.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c +index 928c4c8..058768b 100644 +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -587,6 +587,8 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, + + acpi_ec_burst_enable(ec); + ++ acpi_ec_burst_enable(ec); ++ + if (function == ACPI_READ) { + result = acpi_ec_read(ec, address, &temp); + *value = temp; +@@ -608,6 +610,8 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, + + acpi_ec_burst_disable(ec); + ++ acpi_ec_burst_disable(ec); ++ + switch (result) { + case -EINVAL: + return AE_BAD_PARAMETER; +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0068-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook7.patch +++ linux-2.6.24/patches/0068-UBUNTU-NBK-Ubuntu-2.6.24-19.41netbook7.patch @@ -0,0 +1,30 @@ +From 23f6da41035bf8006fdf2a60830ee38e0312825e Mon Sep 17 00:00:00 2001 +From: Tony Espy +Date: Fri, 17 Oct 2008 15:00:01 -0400 +Subject: [PATCH 068/170] UBUNTU: NBK-Ubuntu-2.6.24-19.41netbook7 + +Ignore: yes +Signed-off-by: Tony Espy +--- + debian/changelog | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/debian/changelog b/debian/changelog +index 5a0e217..bc31776 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,11 @@ ++linux (2.6.24-19.41netbook7) hardy; urgency=low ++ ++ [Debbie Beliveau] ++ ++ * ATA: Added PCI ID for Dennis; Enable 40 wire cable detect to ata_pix.c ++ ++ -- Tony Espy Fri, 17 Oct 2008 18:37:43 +0000 ++ + linux (2.6.24-19.41netbook6) hardy; urgency=low + + [Upstream Kernel Changes] +-- +1.6.3.3 + --- linux-2.6.24.orig/patches/0116-Turn-debian-binary-custom.d-lpia-patchset-0010-hda_s.patch +++ linux-2.6.24/patches/0116-Turn-debian-binary-custom.d-lpia-patchset-0010-hda_s.patch @@ -0,0 +1,770 @@ +From 0fa079d75a527fcac1192557c0d54a7e7c518987 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Fri, 3 Apr 2009 18:54:31 +0100 +Subject: [PATCH 116/170] Turn debian/binary-custom.d/lpia/patchset/0010-hda_sigmatel.patch into a commit. + +Signed-off-by: Andy Whitcroft + +commit 4883c50b37f2e791e29f545766e53ac456576926 +Author: Amit Kucheria +Date: Fri Jan 11 13:59:04 2008 +0200 + + UBUNTU: Poulsbo: Mass update of patches to be identical to those on moblin + + Sigh, we need better communication... + + Signed-off-by: Amit Kucheria +--- + .../lpia/patchset/0010-hda_sigmatel.patch | 379 -------------------- + sound/pci/hda/patch_sigmatel.c | 265 ++++++++++++++- + 2 files changed, 260 insertions(+), 384 deletions(-) + delete mode 100644 debian/binary-custom.d/lpia/patchset/0010-hda_sigmatel.patch + +diff --git a/debian/binary-custom.d/lpia/patchset/0010-hda_sigmatel.patch b/debian/binary-custom.d/lpia/patchset/0010-hda_sigmatel.patch +deleted file mode 100644 +index d466eba..0000000 +--- a/debian/binary-custom.d/lpia/patchset/0010-hda_sigmatel.patch ++++ /dev/null +@@ -1,379 +0,0 @@ +-#! /bin/sh /usr/share/dpatch/dpatch-run +-diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c +-index 0401223..18bd160 100644 +---- a/sound/pci/hda/patch_sigmatel.c +-+++ b/sound/pci/hda/patch_sigmatel.c +-@@ -34,6 +34,9 @@ +- #include "hda_codec.h" +- #include "hda_local.h" +- +-+#define dbg(f, x...) \ +-+ printk(KERN_ALERT " [%s()]: " f "\n", __func__,## x) +-+ +- #define NUM_CONTROL_ALLOC 32 +- #define STAC_HP_EVENT 0x37 +- +-@@ -54,6 +57,12 @@ enum { +- }; +- +- enum { +-+ STAC_9202_REF, +-+ STAC_9202_TEST1, +-+ STAC_9202_MODELS +-+}; +-+ +-+enum { +- STAC_9205_REF, +- STAC_9205_DELL_M42, +- STAC_9205_DELL_M43, +-@@ -171,16 +180,32 @@ static hda_nid_t stac9200_dac_nids[1] = { +- 0x02, +- }; +- +-+static hda_nid_t stac9202_adc_nids[1] = { +-+ 0x03, +-+}; +-+ +-+static hda_nid_t stac9202_mux_nids[1] = { +-+ 0x0f, +-+}; +-+ +-+static hda_nid_t stac9202_dac_nids[1] = { +-+ 0x02, +-+}; +-+ +-+static hda_nid_t stac9202_dmic_nids[2] = { +-+ 0x15, 0 +-+}; +-+ +- static hda_nid_t stac925x_adc_nids[1] = { +-- 0x03, +-+ 0x03, +- }; +- +- static hda_nid_t stac925x_mux_nids[1] = { +-- 0x0f, +-+ 0x0f, +- }; +- +- static hda_nid_t stac925x_dac_nids[1] = { +-- 0x02, +-+ 0x02, +- }; +- +- #define STAC925X_NUM_DMICS 1 +-@@ -222,6 +247,11 @@ static hda_nid_t stac9200_pin_nids[8] = { +- 0x0f, 0x10, 0x11, 0x12, +- }; +- +-+static hda_nid_t stac9202_pin_nids[9] = { +-+ 0x07, 0x08, 0x0a, 0x0d, +-+ 0x0c, 0x0b, 0x10, 0x11, 0x15, +-+}; +-+ +- static hda_nid_t stac925x_pin_nids[8] = { +- 0x07, 0x08, 0x0a, 0x0b, +- 0x0c, 0x0d, 0x10, 0x11, +-@@ -354,6 +384,35 @@ static struct hda_verb stac9200_eapd_init[] = { +- {} +- }; +- +-+static struct hda_verb stac9202_core_init[] = { +-+ /* set dac0mux for dac converter */ +-+ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, +-+ {} +-+}; +-+ +-+/* NID 6, the DAC mux, is set to 0, which forces it to uses NID 2 as its input; +-+ Not the loopbacks from either the analog (NID 14) nor stereo (NID 7) inputs. +-+ +-+ NID 15, the DMIC input, has its widget control set to 0x20, which enables it's +-+ output into the Azalia link, not the Analog input +-+ +-+ NID 7, the SPDIF IN pin, set for EAPD; set power amplifier on */ +-+ +-+static struct hda_verb stac9202_test1_init[] = { +-+ /* set dac0mux for dac converter */ +-+ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, +-+ /* Set pin widgets */ +-+ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, +-+ /* Set EAPD on SPDIF IN for amp on */ +-+ { 0x07, AC_VERB_SET_EAPD_BTLENABLE , 0x02}, +-+ /* Set Input MUX for digital input */ +-+ { 0x14, AC_VERB_SET_CONNECT_SEL, 0x01}, +-+ /* Unmute the Input MUX */ +-+ { 0x14, 0x390, 0x00}, +-+ { 0x14, 0x3a0, 0x00}, +-+ {} +-+}; +-+ +- static struct hda_verb stac925x_core_init[] = { +- /* set dac0mux for dac converter */ +- { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, +-@@ -419,6 +478,60 @@ static struct snd_kcontrol_new stac9200_mixer[] = { +- { } /* end */ +- }; +- +-+static struct snd_kcontrol_new stac9202_mixer[] = { +-+ HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT), +-+ HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT), +-+ { +-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, +-+ .name = "Input Source", +-+ .count = 1, +-+ .info = stac92xx_mux_enum_info, +-+ .get = stac92xx_mux_enum_get, +-+ .put = stac92xx_mux_enum_put, +-+ }, +-+/* +-+ { +-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, +-+ .name = "Digital Input Source", +-+ .count = 1, +-+ .info = stac92xx_dmux_enum_info, +-+ .get = stac92xx_dmux_enum_get, +-+ .put = stac92xx_dmux_enum_put, +-+ }, +-+*/ +-+ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), +-+ HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), +-+ HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), +-+ { } /* end */ +-+}; +-+ +-+static struct snd_kcontrol_new stac9202_test1_mixer[] = { +-+ HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT), +-+ HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT), +-+ { +-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, +-+ .name = "Input Source", +-+ .count = 1, +-+ .info = stac92xx_mux_enum_info, +-+ .get = stac92xx_mux_enum_get, +-+ .put = stac92xx_mux_enum_put, +-+ }, +-+/* +-+ { +-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, +-+ .name = "Digital Input Source", +-+ .count = 1, +-+ .info = stac92xx_dmux_enum_info, +-+ .get = stac92xx_dmux_enum_get, +-+ .put = stac92xx_dmux_enum_put, +-+ }, +-+*/ +-+ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), +-+ HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), +-+ HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), +-+ { } /* end */ +-+}; +-+ +- static struct snd_kcontrol_new stac925x_mixer[] = { +- STAC_INPUT_SOURCE(1), +- HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), +-@@ -628,6 +741,30 @@ static unsigned int dell9200_m27_pin_configs[8] = { +- }; +- +- +-+static unsigned int ref9202_pin_configs[9] = { +-+ 0x01c10014, 0x01410013, 0x01210011, 0x01010012, +-+ 0x01810022, 0x01a10021, 0x01010031, 0x01310023, 0x01d10024, +-+}; +-+ +-+static unsigned int test19202_pin_configs[9] = { +-+ +-+ 0x01c100f4, 0x014100f3, 0x01010012, 0x01210011, +-+ 0x01210013, 0x01a10023, 0x01010031, 0x01310015, 0x01d10024, +-+ +-+/* +-+ +-+ 0x01c100f4, 0x014100f3, 0x01010012, 0x01010011, +-+ 0x01810013, 0x01a10023, 0x01010031, 0x01310015, 0x01d10024, +-+ +-+ 0x01c10014, 0x01410013, 0x01210011, 0x01010012, +-+ 0x01810022, 0x01a10021, 0x01010031, 0x01310023, 0x01d10024, +-+ +-+ 0x70fff100, 0x70fff100, 0x9717f11f, 0x03214011, +-+ 0x01810022, 0x01a10021, 0x01010031, 0x01310023, 0x97a00120, +-+*/ +-+ +-+}; +-+ +- static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { +- [STAC_REF] = ref9200_pin_configs, +- [STAC_9200_DELL_D21] = dell9200_d21_pin_configs, +-@@ -657,6 +794,16 @@ static const char *stac9200_models[STAC_9200_MODELS] = { +- [STAC_9200_GATEWAY] = "gateway", +- }; +- +-+static unsigned int *stac9202_brd_tbl[STAC_9202_MODELS] = { +-+ [STAC_REF] = ref9202_pin_configs, +-+ [STAC_9202_TEST1] = test19202_pin_configs, +-+}; +-+ +-+static const char *stac9202_models[STAC_9202_MODELS] = { +-+ [STAC_REF] = "ref", +-+ [STAC_9202_TEST1] = "test1", +-+}; +-+ +- static struct snd_pci_quirk stac9200_cfg_tbl[] = { +- /* SigmaTel reference board */ +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, +-@@ -731,6 +878,14 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { +- {} /* terminator */ +- }; +- +-+static struct snd_pci_quirk stac9202_cfg_tbl[] = { +-+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, +-+ "Stac 9202 Ref Config", STAC_REF), +-+ SND_PCI_QUIRK(0x8384, 0x7632, +-+ "Stac 9202 Test 1", STAC_9202_TEST1), +-+ {} +-+}; +-+ +- static unsigned int ref925x_pin_configs[8] = { +- 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, +- 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e, +-@@ -2178,6 +2333,37 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) +- return 1; +- } +- +-+static int stac9202_parse_auto_config(struct hda_codec *codec) +-+{ +-+ struct sigmatel_spec *spec = codec->spec; +-+ int err; +-+ +-+ if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) +-+ return err; +-+ +-+ if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) +-+ return err; +-+ +-+ if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0) +-+ return err; +-+ +-+ if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0) +-+ return err; +-+ +-+ if (spec->autocfg.dig_out_pin) +-+ spec->multiout.dig_out_nid = 0x05; +-+ if (spec->autocfg.dig_in_pin) +-+ spec->dig_in_nid = 0x04; +-+ +-+ if (spec->kctl_alloc) +-+ spec->mixers[spec->num_mixers++] = spec->kctl_alloc; +-+ +-+ spec->input_mux = &spec->private_imux; +-+ spec->dinput_mux = &spec->private_dimux; +-+ +-+ return 1; +-+} +-+ +- /* +- * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a +- * funky external mute control using GPIO pins. +-@@ -2478,7 +2664,7 @@ static int patch_stac9200(struct hda_codec *codec) +- return 0; +- } +- +--static int patch_stac925x(struct hda_codec *codec) +-+static int patch_stac9202(struct hda_codec *codec) +- { +- struct sigmatel_spec *spec; +- int err; +-@@ -2488,6 +2674,75 @@ static int patch_stac925x(struct hda_codec *codec) +- return -ENOMEM; +- +- codec->spec = spec; +-+ spec->num_pins = 9; +-+ spec->pin_nids = stac9202_pin_nids; +-+ spec->board_config = snd_hda_check_board_config(codec, STAC_9202_MODELS, +-+ stac9202_models, +-+ stac9202_cfg_tbl); +-+ if (spec->board_config < 0) { +-+ snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9202, using BIOS defaults\n"); +-+ err = stac92xx_save_bios_config_regs(codec); +-+ if (err < 0) { +-+ stac92xx_free(codec); +-+ return err; +-+ } +-+ spec->pin_configs = spec->bios_pin_configs; +-+ } else { +-+ spec->pin_configs = stac9202_brd_tbl[spec->board_config]; +-+ stac92xx_set_config_regs(codec); +-+ } +-+ +-+ switch (spec->board_config) { +-+ case STAC_9202_TEST1: +-+ snd_printdd(KERN_INFO "here in test1 %x\n", spec->board_config); +-+ spec->multiout.max_channels = 2; +-+ spec->multiout.num_dacs = 1; +-+ spec->multiout.dac_nids = stac9202_dac_nids; +-+ spec->adc_nids = stac9202_adc_nids; +-+ spec->mux_nids = stac9202_mux_nids; +-+ spec->dmic_nids = stac9202_dmic_nids; +-+ spec->num_dmics = 1; +-+ spec->num_muxes = 1; +-+ spec->init = stac9202_test1_init; +-+ spec->mixer = stac9202_test1_mixer; +-+ break; +-+ default: +-+ snd_printdd(KERN_INFO "here in default %x\n", spec->board_config); +-+ spec->multiout.max_channels = 2; +-+ spec->multiout.num_dacs = 1; +-+ spec->multiout.dac_nids = stac9202_dac_nids; +-+ spec->adc_nids = stac9202_adc_nids; +-+ spec->mux_nids = stac9202_mux_nids; +-+ spec->dmic_nids = stac9202_dmic_nids; +-+ spec->num_muxes = 1; +-+ spec->num_dmics = 1; +-+ spec->init = stac9202_core_init; +-+ spec->mixer = stac9202_mixer; +-+ } +-+ +-+ err = stac9202_parse_auto_config(codec); +-+ if (err < 0) { +-+ stac92xx_free(codec); +-+ return err; +-+ } +-+ +-+ codec->patch_ops = stac92xx_patch_ops; +-+ +-+ return 0; +-+} +-+ +-+ +-+ +-+static int patch_stac925x(struct hda_codec *codec) +-+{ +-+ struct sigmatel_spec *spec; +-+ int err; +-+ +-+ spec = kzalloc(sizeof(*spec), GFP_KERNEL); +-+ if (spec == NULL) +-+ return -ENOMEM; +-+ +-+ codec->spec = spec; +- spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); +- spec->pin_nids = stac925x_pin_nids; +- spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS, +-@@ -2530,7 +2785,7 @@ static int patch_stac925x(struct hda_codec *codec) +- +- spec->init = stac925x_core_init; +- spec->mixer = stac925x_mixer; +-- +-+ +- err = stac92xx_parse_auto_config(codec, 0x8, 0x7); +- if (!err) { +- if (spec->board_config < 0) { +-@@ -3083,8 +3338,8 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { +- { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, +- { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, +- { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, +-- { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x }, +-- { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x }, +-+ { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac9202 }, +-+ { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac9202 }, +- { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x }, +- { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x }, +- { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x }, +diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c +index b5f5b27..7dc110d 100644 +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -34,6 +34,9 @@ + #include "hda_codec.h" + #include "hda_local.h" + ++#define dbg(f, x...) \ ++ printk(KERN_ALERT " [%s()]: " f "\n", __func__,## x) ++ + #define NUM_CONTROL_ALLOC 32 + #define STAC_HP_EVENT 0x37 + +@@ -54,6 +57,12 @@ enum { + }; + + enum { ++ STAC_9202_REF, ++ STAC_9202_TEST1, ++ STAC_9202_MODELS ++}; ++ ++enum { + STAC_9205_REF, + STAC_9205_DELL_M42, + STAC_9205_DELL_M43, +@@ -172,16 +181,32 @@ static hda_nid_t stac9200_dac_nids[1] = { + 0x02, + }; + ++static hda_nid_t stac9202_adc_nids[1] = { ++ 0x03, ++}; ++ ++static hda_nid_t stac9202_mux_nids[1] = { ++ 0x0f, ++}; ++ ++static hda_nid_t stac9202_dac_nids[1] = { ++ 0x02, ++}; ++ ++static hda_nid_t stac9202_dmic_nids[2] = { ++ 0x15, 0 ++}; ++ + static hda_nid_t stac925x_adc_nids[1] = { +- 0x03, ++ 0x03, + }; + + static hda_nid_t stac925x_mux_nids[1] = { +- 0x0f, ++ 0x0f, + }; + + static hda_nid_t stac925x_dac_nids[1] = { +- 0x02, ++ 0x02, + }; + + #define STAC925X_NUM_DMICS 1 +@@ -223,6 +248,11 @@ static hda_nid_t stac9200_pin_nids[8] = { + 0x0f, 0x10, 0x11, 0x12, + }; + ++static hda_nid_t stac9202_pin_nids[9] = { ++ 0x07, 0x08, 0x0a, 0x0d, ++ 0x0c, 0x0b, 0x10, 0x11, 0x15, ++}; ++ + static hda_nid_t stac925x_pin_nids[8] = { + 0x07, 0x08, 0x0a, 0x0b, + 0x0c, 0x0d, 0x10, 0x11, +@@ -355,6 +385,35 @@ static struct hda_verb stac9200_eapd_init[] = { + {} + }; + ++static struct hda_verb stac9202_core_init[] = { ++ /* set dac0mux for dac converter */ ++ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ {} ++}; ++ ++/* NID 6, the DAC mux, is set to 0, which forces it to uses NID 2 as its input; ++ Not the loopbacks from either the analog (NID 14) nor stereo (NID 7) inputs. ++ ++ NID 15, the DMIC input, has its widget control set to 0x20, which enables it's ++ output into the Azalia link, not the Analog input ++ ++ NID 7, the SPDIF IN pin, set for EAPD; set power amplifier on */ ++ ++static struct hda_verb stac9202_test1_init[] = { ++ /* set dac0mux for dac converter */ ++ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ /* Set pin widgets */ ++ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, ++ /* Set EAPD on SPDIF IN for amp on */ ++ { 0x07, AC_VERB_SET_EAPD_BTLENABLE , 0x02}, ++ /* Set Input MUX for digital input */ ++ { 0x14, AC_VERB_SET_CONNECT_SEL, 0x01}, ++ /* Unmute the Input MUX */ ++ { 0x14, 0x390, 0x00}, ++ { 0x14, 0x3a0, 0x00}, ++ {} ++}; ++ + static struct hda_verb stac925x_core_init[] = { + /* set dac0mux for dac converter */ + { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, +@@ -420,6 +479,60 @@ static struct snd_kcontrol_new stac9200_mixer[] = { + { } /* end */ + }; + ++static struct snd_kcontrol_new stac9202_mixer[] = { ++ HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input Source", ++ .count = 1, ++ .info = stac92xx_mux_enum_info, ++ .get = stac92xx_mux_enum_get, ++ .put = stac92xx_mux_enum_put, ++ }, ++/* ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Digital Input Source", ++ .count = 1, ++ .info = stac92xx_dmux_enum_info, ++ .get = stac92xx_dmux_enum_get, ++ .put = stac92xx_dmux_enum_put, ++ }, ++*/ ++ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), ++ HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), ++ { } /* end */ ++}; ++ ++static struct snd_kcontrol_new stac9202_test1_mixer[] = { ++ HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input Source", ++ .count = 1, ++ .info = stac92xx_mux_enum_info, ++ .get = stac92xx_mux_enum_get, ++ .put = stac92xx_mux_enum_put, ++ }, ++/* ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Digital Input Source", ++ .count = 1, ++ .info = stac92xx_dmux_enum_info, ++ .get = stac92xx_dmux_enum_get, ++ .put = stac92xx_dmux_enum_put, ++ }, ++*/ ++ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), ++ HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), ++ { } /* end */ ++}; ++ + static struct snd_kcontrol_new stac925x_mixer[] = { + STAC_INPUT_SOURCE(1), + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), +@@ -629,6 +742,30 @@ static unsigned int dell9200_m27_pin_configs[8] = { + }; + + ++static unsigned int ref9202_pin_configs[9] = { ++ 0x01c10014, 0x01410013, 0x01210011, 0x01010012, ++ 0x01810022, 0x01a10021, 0x01010031, 0x01310023, 0x01d10024, ++}; ++ ++static unsigned int test19202_pin_configs[9] = { ++ ++ 0x01c100f4, 0x014100f3, 0x01010012, 0x01210011, ++ 0x01210013, 0x01a10023, 0x01010031, 0x01310015, 0x01d10024, ++ ++/* ++ ++ 0x01c100f4, 0x014100f3, 0x01010012, 0x01010011, ++ 0x01810013, 0x01a10023, 0x01010031, 0x01310015, 0x01d10024, ++ ++ 0x01c10014, 0x01410013, 0x01210011, 0x01010012, ++ 0x01810022, 0x01a10021, 0x01010031, 0x01310023, 0x01d10024, ++ ++ 0x70fff100, 0x70fff100, 0x9717f11f, 0x03214011, ++ 0x01810022, 0x01a10021, 0x01010031, 0x01310023, 0x97a00120, ++*/ ++ ++}; ++ + static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { + [STAC_REF] = ref9200_pin_configs, + [STAC_9200_DELL_D21] = dell9200_d21_pin_configs, +@@ -658,6 +795,16 @@ static const char *stac9200_models[STAC_9200_MODELS] = { + [STAC_9200_GATEWAY] = "gateway", + }; + ++static unsigned int *stac9202_brd_tbl[STAC_9202_MODELS] = { ++ [STAC_REF] = ref9202_pin_configs, ++ [STAC_9202_TEST1] = test19202_pin_configs, ++}; ++ ++static const char *stac9202_models[STAC_9202_MODELS] = { ++ [STAC_REF] = "ref", ++ [STAC_9202_TEST1] = "test1", ++}; ++ + static struct snd_pci_quirk stac9200_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, +@@ -732,6 +879,14 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { + {} /* terminator */ + }; + ++static struct snd_pci_quirk stac9202_cfg_tbl[] = { ++ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, ++ "Stac 9202 Ref Config", STAC_REF), ++ SND_PCI_QUIRK(0x8384, 0x7632, ++ "Stac 9202 Test 1", STAC_9202_TEST1), ++ {} ++}; ++ + static unsigned int ref925x_pin_configs[8] = { + 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, + 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e, +@@ -2186,6 +2341,37 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) + return 1; + } + ++static int stac9202_parse_auto_config(struct hda_codec *codec) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ int err; ++ ++ if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) ++ return err; ++ ++ if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) ++ return err; ++ ++ if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0) ++ return err; ++ ++ if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0) ++ return err; ++ ++ if (spec->autocfg.dig_out_pin) ++ spec->multiout.dig_out_nid = 0x05; ++ if (spec->autocfg.dig_in_pin) ++ spec->dig_in_nid = 0x04; ++ ++ if (spec->kctl_alloc) ++ spec->mixers[spec->num_mixers++] = spec->kctl_alloc; ++ ++ spec->input_mux = &spec->private_imux; ++ spec->dinput_mux = &spec->private_dimux; ++ ++ return 1; ++} ++ + /* + * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a + * funky external mute control using GPIO pins. +@@ -2486,6 +2672,75 @@ static int patch_stac9200(struct hda_codec *codec) + return 0; + } + ++static int patch_stac9202(struct hda_codec *codec) ++{ ++ struct sigmatel_spec *spec; ++ int err; ++ ++ spec = kzalloc(sizeof(*spec), GFP_KERNEL); ++ if (spec == NULL) ++ return -ENOMEM; ++ ++ codec->spec = spec; ++ spec->num_pins = 9; ++ spec->pin_nids = stac9202_pin_nids; ++ spec->board_config = snd_hda_check_board_config(codec, STAC_9202_MODELS, ++ stac9202_models, ++ stac9202_cfg_tbl); ++ if (spec->board_config < 0) { ++ snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9202, using BIOS defaults\n"); ++ err = stac92xx_save_bios_config_regs(codec); ++ if (err < 0) { ++ stac92xx_free(codec); ++ return err; ++ } ++ spec->pin_configs = spec->bios_pin_configs; ++ } else { ++ spec->pin_configs = stac9202_brd_tbl[spec->board_config]; ++ stac92xx_set_config_regs(codec); ++ } ++ ++ switch (spec->board_config) { ++ case STAC_9202_TEST1: ++ snd_printdd(KERN_INFO "here in test1 %x\n", spec->board_config); ++ spec->multiout.max_channels = 2; ++ spec->multiout.num_dacs = 1; ++ spec->multiout.dac_nids = stac9202_dac_nids; ++ spec->adc_nids = stac9202_adc_nids; ++ spec->mux_nids = stac9202_mux_nids; ++ spec->dmic_nids = stac9202_dmic_nids; ++ spec->num_dmics = 1; ++ spec->num_muxes = 1; ++ spec->init = stac9202_test1_init; ++ spec->mixer = stac9202_test1_mixer; ++ break; ++ default: ++ snd_printdd(KERN_INFO "here in default %x\n", spec->board_config); ++ spec->multiout.max_channels = 2; ++ spec->multiout.num_dacs = 1; ++ spec->multiout.dac_nids = stac9202_dac_nids; ++ spec->adc_nids = stac9202_adc_nids; ++ spec->mux_nids = stac9202_mux_nids; ++ spec->dmic_nids = stac9202_dmic_nids; ++ spec->num_muxes = 1; ++ spec->num_dmics = 1; ++ spec->init = stac9202_core_init; ++ spec->mixer = stac9202_mixer; ++ } ++ ++ err = stac9202_parse_auto_config(codec); ++ if (err < 0) { ++ stac92xx_free(codec); ++ return err; ++ } ++ ++ codec->patch_ops = stac92xx_patch_ops; ++ ++ return 0; ++} ++ ++ ++ + static int patch_stac925x(struct hda_codec *codec) + { + struct sigmatel_spec *spec; +@@ -3094,8 +3349,8 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { + { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, + { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, + { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, +- { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x }, +- { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x }, ++ { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac9202 }, ++ { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac9202 }, + { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x }, + { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x }, + { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x }, +-- +1.6.3.3 + --- linux-2.6.24.orig/init/version.c +++ linux-2.6.24/init/version.c @@ -36,7 +36,11 @@ /* FIXED STRINGS! Don't touch! */ const char linux_banner[] = "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" - LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n"; + LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION +#ifdef CONFIG_VERSION_SIGNATURE + " (" CONFIG_VERSION_SIGNATURE ")" +#endif + "\n"; const char linux_proc_banner[] = "%s version %s" --- linux-2.6.24.orig/init/initramfs.c +++ linux-2.6.24/init/initramfs.c @@ -541,6 +541,28 @@ #endif +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD +/* Tries to read the initramfs if it's already there, for ACPI Table Overiding */ +void __init early_populate_rootfs(void) +{ + char *err = unpack_to_rootfs(__initramfs_start, + __initramfs_end - __initramfs_start, 0); + if (err) + return; +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) { + printk(KERN_INFO "Early unpacking initramfs..."); + err = unpack_to_rootfs((char *)initrd_start, + initrd_end - initrd_start, 0); + if (err) + return; + printk(" done\n"); + } +#endif + return; +} +#endif /* CONFIG_ACPI_CUSTOM_DSDT_INITRD */ + static int __init populate_rootfs(void) { char *err = unpack_to_rootfs(__initramfs_start, --- linux-2.6.24.orig/init/Kconfig +++ linux-2.6.24/init/Kconfig @@ -92,6 +92,15 @@ which is done within the script "scripts/setlocalversion".) +config VERSION_SIGNATURE + string "Arbitrary version signature" + help + This string will be created in a file, /proc/version_signature. It + is useful in determining arbitrary data about your kernel. For instance, + if you have several kernels of the same version, but need to keep track + of a revision of the same kernel, but not affect it's ability to load + compatible modules, this is the easiest way to do that. + config SWAP bool "Support for paging of anonymous memory (swap)" depends on MMU && BLOCK --- linux-2.6.24.orig/init/calibrate.c +++ linux-2.6.24/init/calibrate.c @@ -9,7 +9,9 @@ #include #include +#include +unsigned long lpj_tsc; unsigned long preset_lpj; static int __init lpj_setup(char *str) { @@ -109,6 +111,10 @@ * This is the number of bits of precision for the loops_per_jiffy. Each * bit takes on average 1.5/HZ seconds. This (like the original) is a little * better than 1% + * For the boot cpu we can skip the delay calibration and assign it a value + * calculated based on the tsc frequency. + * For the rest of the CPUs we cannot assume that the tsc frequency is same as + * the cpu frequency, hence do the calibration for those. */ #define LPS_PREC 8 @@ -119,20 +125,20 @@ if (preset_lpj) { loops_per_jiffy = preset_lpj; - printk("Calibrating delay loop (skipped)... " - "%lu.%02lu BogoMIPS preset\n", - loops_per_jiffy/(500000/HZ), - (loops_per_jiffy/(5000/HZ)) % 100); + printk(KERN_INFO + "Calibrating delay loop (skipped) preset value.. "); + } else if ((smp_processor_id() == 0) && lpj_tsc) { + loops_per_jiffy = lpj_tsc; + printk(KERN_INFO + "Calibrating delay loop (skipped), " + "using tsc calculated value.. "); } else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) { - printk("Calibrating delay using timer specific routine.. "); - printk("%lu.%02lu BogoMIPS (lpj=%lu)\n", - loops_per_jiffy/(500000/HZ), - (loops_per_jiffy/(5000/HZ)) % 100, - loops_per_jiffy); + printk(KERN_INFO + "Calibrating delay using timer specific routine.. "); } else { loops_per_jiffy = (1<<12); - printk(KERN_DEBUG "Calibrating delay loop... "); + printk(KERN_INFO "Calibrating delay loop... "); while ((loops_per_jiffy <<= 1) != 0) { /* wait for "start of" clock tick */ ticks = jiffies; @@ -162,12 +168,8 @@ if (jiffies != ticks) /* longer than 1 tick */ loops_per_jiffy &= ~loopbit; } - - /* Round the value and print it */ - printk("%lu.%02lu BogoMIPS (lpj=%lu)\n", - loops_per_jiffy/(500000/HZ), - (loops_per_jiffy/(5000/HZ)) % 100, - loops_per_jiffy); } - + printk(KERN_CONT "%lu.%02lu BogoMIPS (lpj=%lu)\n", + loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy); } --- linux-2.6.24.orig/init/main.c +++ linux-2.6.24/init/main.c @@ -91,8 +91,12 @@ extern void free_initmem(void); #ifdef CONFIG_ACPI extern void acpi_early_init(void); +#ifdef CONFIG_BLK_DEV_INITRD +extern void early_populate_rootfs(void); +#endif #else static inline void acpi_early_init(void) { } +static inline void early_populate_rootfs(void) { } #endif #ifndef CONFIG_DEBUG_RODATA static inline void mark_rodata_ro(void) { } @@ -642,6 +646,9 @@ check_bugs(); +#ifdef CONFIG_BLK_DEV_INITRD + early_populate_rootfs(); /* For DSDT override from initramfs */ +#endif acpi_early_init(); /* before LAPIC and SMP init */ /* Do the rest non-__init'ed, we're now alive */ --- linux-2.6.24.orig/mm/slub.c +++ linux-2.6.24/mm/slub.c @@ -2592,6 +2592,7 @@ void kfree(const void *x) { struct page *page; + void *object = (void *)x; if (unlikely(ZERO_OR_NULL_PTR(x))) return; @@ -2601,7 +2602,7 @@ put_page(page); return; } - slab_free(page->slab, page, (void *)x, __builtin_return_address(0)); + slab_free(page->slab, page, object, __builtin_return_address(0)); } EXPORT_SYMBOL(kfree); --- linux-2.6.24.orig/mm/filemap.c +++ linux-2.6.24/mm/filemap.c @@ -1622,26 +1622,26 @@ } EXPORT_SYMBOL(should_remove_suid); -int __remove_suid(struct dentry *dentry, int kill) +int __remove_suid(struct path *path, int kill) { struct iattr newattrs; newattrs.ia_valid = ATTR_FORCE | kill; - return notify_change(dentry, &newattrs); + return notify_change(path->dentry, path->mnt, &newattrs); } -int remove_suid(struct dentry *dentry) +int remove_suid(struct path *path) { - int killsuid = should_remove_suid(dentry); - int killpriv = security_inode_need_killpriv(dentry); + int killsuid = should_remove_suid(path->dentry); + int killpriv = security_inode_need_killpriv(path->dentry); int error = 0; if (killpriv < 0) return killpriv; if (killpriv) - error = security_inode_killpriv(dentry); + error = security_inode_killpriv(path->dentry); if (!error && killsuid) - error = __remove_suid(dentry, killsuid); + error = __remove_suid(path, killsuid); return error; } @@ -1725,21 +1725,27 @@ } EXPORT_SYMBOL(iov_iter_copy_from_user); -static void __iov_iter_advance_iov(struct iov_iter *i, size_t bytes) +void iov_iter_advance(struct iov_iter *i, size_t bytes) { + BUG_ON(i->count < bytes); + if (likely(i->nr_segs == 1)) { i->iov_offset += bytes; + i->count -= bytes; } else { const struct iovec *iov = i->iov; size_t base = i->iov_offset; /* * The !iov->iov_len check ensures we skip over unlikely - * zero-length segments. + * zero-length segments (without overruning the iovec). */ - while (bytes || !iov->iov_len) { - int copy = min(bytes, iov->iov_len - base); + while (bytes || unlikely(i->count && !iov->iov_len)) { + int copy; + copy = min(bytes, iov->iov_len - base); + BUG_ON(!i->count || i->count < copy); + i->count -= copy; bytes -= copy; base += copy; if (iov->iov_len == base) { @@ -1751,14 +1757,6 @@ i->iov_offset = base; } } - -void iov_iter_advance(struct iov_iter *i, size_t bytes) -{ - BUG_ON(i->count < bytes); - - __iov_iter_advance_iov(i, bytes); - i->count -= bytes; -} EXPORT_SYMBOL(iov_iter_advance); /* @@ -2358,7 +2356,7 @@ if (count == 0) goto out; - err = remove_suid(file->f_path.dentry); + err = remove_suid(&file->f_path); if (err) goto out; --- linux-2.6.24.orig/mm/filemap_xip.c +++ linux-2.6.24/mm/filemap_xip.c @@ -379,7 +379,7 @@ if (count == 0) goto out_backing; - ret = remove_suid(filp->f_path.dentry); + ret = remove_suid(&filp->f_path); if (ret) goto out_backing; --- linux-2.6.24.orig/mm/util.c +++ linux-2.6.24/mm/util.c @@ -2,6 +2,10 @@ #include #include #include +#include +#include +#include +#include #include /** @@ -136,3 +140,28 @@ return p; } EXPORT_SYMBOL(strndup_user); + +SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, + unsigned long, prot, unsigned long, flags, + unsigned long, fd, unsigned long, pgoff) +{ + struct file * file = NULL; + unsigned long retval = -EBADF; + + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + down_write(¤t->mm->mmap_sem); + retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return retval; +} --- linux-2.6.24.orig/mm/mmap.c +++ linux-2.6.24/mm/mmap.c @@ -915,13 +915,9 @@ if (!(flags & MAP_FIXED)) addr = round_hint_to_min(addr); - error = arch_mmap_check(addr, len, flags); - if (error) - return error; - /* Careful about overflows.. */ len = PAGE_ALIGN(len); - if (!len || len > TASK_SIZE) + if (!len) return -ENOMEM; /* offset overflow? */ @@ -1411,6 +1407,14 @@ unsigned long (*get_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + unsigned long error = arch_mmap_check(addr, len, flags); + if (error) + return error; + + /* Careful about overflows.. */ + if (len > TASK_SIZE) + return -ENOMEM; + get_area = current->mm->get_unmapped_area; if (file && file->f_op && file->f_op->get_unmapped_area) get_area = file->f_op->get_unmapped_area; --- linux-2.6.24.orig/mm/mremap.c +++ linux-2.6.24/mm/mremap.c @@ -239,6 +239,137 @@ return new_addr; } +static struct vm_area_struct *vma_to_resize(unsigned long addr, + unsigned long old_len, unsigned long new_len, unsigned long *p) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma = find_vma(mm, addr); + + if (!vma || vma->vm_start > addr) + goto Efault; + + if (is_vm_hugetlb_page(vma)) + goto Einval; + + /* We can't remap across vm area boundaries */ + if (old_len > vma->vm_end - addr) + goto Efault; + + if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) { + if (new_len > old_len) + goto Efault; + } + + if (vma->vm_flags & VM_LOCKED) { + unsigned long locked, lock_limit; + locked = mm->locked_vm << PAGE_SHIFT; + lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; + locked += new_len - old_len; + if (locked > lock_limit && !capable(CAP_IPC_LOCK)) + goto Eagain; + } + + if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT)) + goto Enomem; + + if (vma->vm_flags & VM_ACCOUNT) { + unsigned long charged = (new_len - old_len) >> PAGE_SHIFT; + if (security_vm_enough_memory(charged)) + goto Efault; + *p = charged; + } + + return vma; + +Efault: /* very odd choice for most of the cases, but... */ + return ERR_PTR(-EFAULT); +Einval: + return ERR_PTR(-EINVAL); +Enomem: + return ERR_PTR(-ENOMEM); +Eagain: + return ERR_PTR(-EAGAIN); +} + +static unsigned long mremap_to(unsigned long addr, + unsigned long old_len, unsigned long new_addr, + unsigned long new_len) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long ret = -EINVAL; + unsigned long charged = 0; + unsigned long map_flags; + + if (new_addr & ~PAGE_MASK) + goto out; + + if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len) + goto out; + + /* Check if the location we're moving into overlaps the + * old location at all, and fail if it does. + */ + if ((new_addr <= addr) && (new_addr+new_len) > addr) + goto out; + + if ((addr <= new_addr) && (addr+old_len) > new_addr) + goto out; + + ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); + if (ret) + goto out; + + ret = do_munmap(mm, new_addr, new_len); + if (ret) + goto out; + + if (old_len >= new_len) { + ret = do_munmap(mm, addr+new_len, old_len - new_len); + if (ret && old_len != new_len) + goto out; + old_len = new_len; + } + + vma = vma_to_resize(addr, old_len, new_len, &charged); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto out; + } + + map_flags = MAP_FIXED; + if (vma->vm_flags & VM_MAYSHARE) + map_flags |= MAP_SHARED; + + ret = get_unmapped_area(vma->vm_file, new_addr, new_len, vma->vm_pgoff + + ((addr - vma->vm_start) >> PAGE_SHIFT), + map_flags); + if (ret & ~PAGE_MASK) + goto out1; + + ret = move_vma(vma, addr, old_len, new_len, new_addr); + if (!(ret & ~PAGE_MASK)) + goto out; +out1: + vm_unacct_memory(charged); + +out: + return ret; +} + +static int vma_expandable(struct vm_area_struct *vma, unsigned long delta) +{ + unsigned long end = vma->vm_end + delta; + if (end < vma->vm_end) /* overflow */ + return 0; + if (vma->vm_next && vma->vm_next->vm_start < end) /* intersection */ + return 0; + if (get_unmapped_area(NULL, vma->vm_start, end - vma->vm_start, + 0, MAP_FIXED) & ~PAGE_MASK) + return 0; + return 1; +} + /* * Expand (or shrink) an existing mapping, potentially moving it at the * same time (controlled by the MREMAP_MAYMOVE flag and available VM space) @@ -272,32 +403,10 @@ if (!new_len) goto out; - /* new_addr is only valid if MREMAP_FIXED is specified */ if (flags & MREMAP_FIXED) { - if (new_addr & ~PAGE_MASK) - goto out; - if (!(flags & MREMAP_MAYMOVE)) - goto out; - - if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len) - goto out; - - /* Check if the location we're moving into overlaps the - * old location at all, and fail if it does. - */ - if ((new_addr <= addr) && (new_addr+new_len) > addr) - goto out; - - if ((addr <= new_addr) && (addr+old_len) > new_addr) - goto out; - - ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); - if (ret) - goto out; - - ret = do_munmap(mm, new_addr, new_len); - if (ret) - goto out; + if (flags & MREMAP_MAYMOVE) + ret = mremap_to(addr, old_len, new_addr, new_len); + goto out; } /* @@ -310,60 +419,23 @@ if (ret && old_len != new_len) goto out; ret = addr; - if (!(flags & MREMAP_FIXED) || (new_addr == addr)) - goto out; - old_len = new_len; + goto out; } /* - * Ok, we need to grow.. or relocate. + * Ok, we need to grow.. */ - ret = -EFAULT; - vma = find_vma(mm, addr); - if (!vma || vma->vm_start > addr) + vma = vma_to_resize(addr, old_len, new_len, &charged); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); goto out; - if (is_vm_hugetlb_page(vma)) { - ret = -EINVAL; - goto out; - } - /* We can't remap across vm area boundaries */ - if (old_len > vma->vm_end - addr) - goto out; - if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) { - if (new_len > old_len) - goto out; - } - if (vma->vm_flags & VM_LOCKED) { - unsigned long locked, lock_limit; - locked = mm->locked_vm << PAGE_SHIFT; - lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; - locked += new_len - old_len; - ret = -EAGAIN; - if (locked > lock_limit && !capable(CAP_IPC_LOCK)) - goto out; - } - if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT)) { - ret = -ENOMEM; - goto out; - } - - if (vma->vm_flags & VM_ACCOUNT) { - charged = (new_len - old_len) >> PAGE_SHIFT; - if (security_vm_enough_memory(charged)) - goto out_nc; } /* old_len exactly to the end of the area.. - * And we're not relocating the area. */ - if (old_len == vma->vm_end - addr && - !((flags & MREMAP_FIXED) && (addr != new_addr)) && - (old_len != new_len || !(flags & MREMAP_MAYMOVE))) { - unsigned long max_addr = TASK_SIZE; - if (vma->vm_next) - max_addr = vma->vm_next->vm_start; + if (old_len == vma->vm_end - addr) { /* can we just expand the current mapping? */ - if (max_addr - addr >= new_len) { + if (vma_expandable(vma, new_len - old_len)) { int pages = (new_len - old_len) >> PAGE_SHIFT; vma_adjust(vma, vma->vm_start, @@ -387,28 +459,27 @@ */ ret = -ENOMEM; if (flags & MREMAP_MAYMOVE) { - if (!(flags & MREMAP_FIXED)) { - unsigned long map_flags = 0; - if (vma->vm_flags & VM_MAYSHARE) - map_flags |= MAP_SHARED; - - new_addr = get_unmapped_area(vma->vm_file, 0, new_len, - vma->vm_pgoff, map_flags); - if (new_addr & ~PAGE_MASK) { - ret = new_addr; - goto out; - } - - ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); - if (ret) - goto out; + unsigned long map_flags = 0; + if (vma->vm_flags & VM_MAYSHARE) + map_flags |= MAP_SHARED; + + new_addr = get_unmapped_area(vma->vm_file, 0, new_len, + vma->vm_pgoff + + ((addr - vma->vm_start) >> PAGE_SHIFT), + map_flags); + if (new_addr & ~PAGE_MASK) { + ret = new_addr; + goto out; } + + ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); + if (ret) + goto out; ret = move_vma(vma, addr, old_len, new_len, new_addr); } out: if (ret & ~PAGE_MASK) vm_unacct_memory(charged); -out_nc: return ret; } --- linux-2.6.24.orig/mm/allocpercpu.c +++ linux-2.6.24/mm/allocpercpu.c @@ -6,6 +6,10 @@ #include #include +#ifndef cache_line_size +#define cache_line_size() L1_CACHE_BYTES +#endif + /** * percpu_depopulate - depopulate per-cpu data for given cpu * @__pdata: per-cpu data to depopulate @@ -52,6 +56,11 @@ struct percpu_data *pdata = __percpu_disguise(__pdata); int node = cpu_to_node(cpu); + /* + * We should make sure each CPU gets private memory. + */ + size = roundup(size, cache_line_size()); + BUG_ON(pdata->ptrs[cpu]); if (node_online(node)) pdata->ptrs[cpu] = kmalloc_node(size, gfp|__GFP_ZERO, node); @@ -98,7 +107,11 @@ */ void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask) { - void *pdata = kzalloc(sizeof(struct percpu_data), gfp); + /* + * We allocate whole cache lines to avoid false sharing + */ + size_t sz = roundup(nr_cpu_ids * sizeof(void *), cache_line_size()); + void *pdata = kzalloc(sz, gfp); void *__pdata = __percpu_disguise(pdata); if (unlikely(!pdata)) --- linux-2.6.24.orig/mm/slab.c +++ linux-2.6.24/mm/slab.c @@ -1484,7 +1484,7 @@ list_add(&cache_cache.next, &cache_chain); cache_cache.colour_off = cache_line_size(); cache_cache.array[smp_processor_id()] = &initarray_cache.cache; - cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE]; + cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE + node]; /* * struct kmem_cache size depends on nr_node_ids, which @@ -1605,7 +1605,7 @@ int nid; for_each_online_node(nid) { - init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], nid); + init_list(&cache_cache, &initkmem_list3[CACHE_CACHE + nid], nid); init_list(malloc_sizes[INDEX_AC].cs_cachep, &initkmem_list3[SIZE_AC + nid], nid); @@ -2961,11 +2961,10 @@ struct array_cache *ac; int node; - node = numa_node_id(); - +retry: check_irq_off(); + node = numa_node_id(); ac = cpu_cache_get(cachep); -retry: batchcount = ac->batchcount; if (!ac->touched && batchcount > BATCHREFILL_LIMIT) { /* --- linux-2.6.24.orig/mm/Kconfig +++ linux-2.6.24/mm/Kconfig @@ -193,3 +193,21 @@ config VIRT_TO_BUS def_bool y depends on !ARCH_NO_VIRT_TO_BUS + +config DEFAULT_MMAP_MIN_ADDR + int "Low address space to protect from user allocation" + default 4096 + help + This is the portion of low virtual memory which should be protected + from userspace allocation. Keeping a user from writing to low pages + can help reduce the impact of kernel NULL pointer bugs. + + For most ia64, ppc64 and x86 users with lots of address space + a value of 65536 is reasonable and should cause no problems. + On arm and other archs it should not be higher than 32768. + Programs which use vm86 functionality or have some need to map + this low address space will need CAP_SYS_RAWIO or disable this + protection by setting the value to 0. + + This value can be changed after boot using the + /proc/sys/vm/mmap_min_addr tunable. --- linux-2.6.24.orig/mm/migrate.c +++ linux-2.6.24/mm/migrate.c @@ -823,6 +823,11 @@ goto set_status; page = follow_page(vma, pp->addr, FOLL_GET); + + err = PTR_ERR(page); + if (IS_ERR(page)) + goto set_status; + err = -ENOENT; if (!page) goto set_status; @@ -886,6 +891,11 @@ goto set_status; page = follow_page(vma, pm->addr, 0); + + err = PTR_ERR(page); + if (IS_ERR(page)) + goto set_status; + err = -ENOENT; /* Use PageReserved to check for zero page */ if (!page || PageReserved(page)) --- linux-2.6.24.orig/mm/memory.c +++ linux-2.6.24/mm/memory.c @@ -934,17 +934,15 @@ } ptep = pte_offset_map_lock(mm, pmd, address, &ptl); - if (!ptep) - goto out; pte = *ptep; if (!pte_present(pte)) - goto unlock; + goto no_page; if ((flags & FOLL_WRITE) && !pte_write(pte)) goto unlock; page = vm_normal_page(vma, address, pte); if (unlikely(!page)) - goto unlock; + goto bad_page; if (flags & FOLL_GET) get_page(page); @@ -959,6 +957,15 @@ out: return page; +bad_page: + pte_unmap_unlock(ptep, ptl); + return ERR_PTR(-EFAULT); + +no_page: + pte_unmap_unlock(ptep, ptl); + if (!pte_none(pte)) + return page; + /* Fall through to ZERO_PAGE handling */ no_page_table: /* * When core dumping an enormous anonymous area that nobody @@ -973,6 +980,27 @@ return page; } +/* Can we do the FOLL_ANON optimization? */ +static inline int use_zero_page(struct vm_area_struct *vma) +{ + /* + * We don't want to optimize FOLL_ANON for make_pages_present() + * when it tries to page in a VM_LOCKED region. As to VM_SHARED, + * we want to get the page from the page tables to make sure + * that we serialize and update with any other user of that + * mapping. + */ + if (vma->vm_flags & (VM_LOCKED | VM_SHARED)) + return 0; + /* + * And if we have a fault or a nopfn or a nopage routine, it's not an + * anonymous region. + */ + return !vma->vm_ops || + (!vma->vm_ops->fault && !vma->vm_ops->nopfn && + !vma->vm_ops->nopage); +} + int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int len, int write, int force, struct page **pages, struct vm_area_struct **vmas) @@ -980,6 +1008,8 @@ int i; unsigned int vm_flags; + if (len <= 0) + return 0; /* * Require read or write permissions. * If 'force' is set, we only require the "MAY" flags. @@ -1045,9 +1075,7 @@ foll_flags = FOLL_TOUCH; if (pages) foll_flags |= FOLL_GET; - if (!write && !(vma->vm_flags & VM_LOCKED) && - (!vma->vm_ops || (!vma->vm_ops->nopage && - !vma->vm_ops->fault))) + if (!write && use_zero_page(vma)) foll_flags |= FOLL_ANON; do { @@ -1093,6 +1121,8 @@ cond_resched(); } + if (IS_ERR(page)) + return i ? i : PTR_ERR(page); if (pages) { pages[i] = page; --- linux-2.6.24.orig/mm/tiny-shmem.c +++ linux-2.6.24/mm/tiny-shmem.c @@ -81,7 +81,7 @@ inode->i_nlink = 0; /* It is unlinked */ /* notify everyone as to the change of file size */ - error = do_truncate(dentry, size, 0, file); + error = do_truncate(dentry, file->f_path.mnt, size, 0, file); if (error < 0) goto close_file; --- linux-2.6.24.orig/mm/hugetlb.c +++ linux-2.6.24/mm/hugetlb.c @@ -119,6 +119,7 @@ struct address_space *mapping; mapping = (struct address_space *) page_private(page); + set_page_private(page, 0); BUG_ON(page_count(page)); INIT_LIST_HEAD(&page->lru); @@ -133,7 +134,6 @@ spin_unlock(&hugetlb_lock); if (mapping) hugetlb_put_quota(mapping, 1); - set_page_private(page, 0); } /* @@ -605,6 +605,16 @@ return 0; } +int hugetlb_overcommit_handler(struct ctl_table *table, int write, + struct file *file, void __user *buffer, + size_t *length, loff_t *ppos) +{ + spin_lock(&hugetlb_lock); + proc_doulongvec_minmax(table, write, file, buffer, length, ppos); + spin_unlock(&hugetlb_lock); + return 0; +} + #endif /* CONFIG_SYSCTL */ int hugetlb_report_meminfo(char *buf) --- linux-2.6.24.orig/mm/shmem.c +++ linux-2.6.24/mm/shmem.c @@ -1415,7 +1415,6 @@ inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; inode->i_blocks = 0; - inode->i_mapping->a_ops = &shmem_aops; inode->i_mapping->backing_dev_info = &shmem_backing_dev_info; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_generation = get_seconds(); @@ -1430,6 +1429,7 @@ init_special_inode(inode, mode, dev); break; case S_IFREG: + inode->i_mapping->a_ops = &shmem_aops; inode->i_op = &shmem_inode_operations; inode->i_fop = &shmem_file_operations; mpol_shared_policy_init(&info->policy, sbinfo->policy, @@ -1526,7 +1526,7 @@ if (err || !count) goto out; - err = remove_suid(file->f_path.dentry); + err = remove_suid(&file->f_path); if (err) goto out; @@ -1924,6 +1924,7 @@ iput(inode); return error; } + inode->i_mapping->a_ops = &shmem_aops; inode->i_op = &shmem_symlink_inode_operations; kaddr = kmap_atomic(page, KM_USER0); memcpy(kaddr, symname, len); --- linux-2.6.24.orig/net/bridge/br_input.c +++ linux-2.6.24/net/bridge/br_input.c @@ -136,14 +136,11 @@ if (skb->protocol == htons(ETH_P_PAUSE)) goto drop; - /* Process STP BPDU's through normal netif_receive_skb() path */ - if (p->br->stp_enabled != BR_NO_STP) { - if (NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, - NULL, br_handle_local_finish)) - return NULL; - else - return skb; - } + if (NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, + NULL, br_handle_local_finish)) + return NULL; /* frame consumed by filter */ + else + return skb; /* continue processing */ } switch (p->state) { --- linux-2.6.24.orig/net/bridge/netfilter/ebt_redirect.c +++ linux-2.6.24/net/bridge/netfilter/ebt_redirect.c @@ -21,8 +21,8 @@ { struct ebt_redirect_info *info = (struct ebt_redirect_info *)data; - if (skb_make_writable(skb, 0)) - return NF_DROP; + if (!skb_make_writable(skb, 0)) + return EBT_DROP; if (hooknr != NF_BR_BROUTING) memcpy(eth_hdr(skb)->h_dest, --- linux-2.6.24.orig/net/bridge/netfilter/ebt_snat.c +++ linux-2.6.24/net/bridge/netfilter/ebt_snat.c @@ -22,8 +22,8 @@ { struct ebt_nat_info *info = (struct ebt_nat_info *) data; - if (skb_make_writable(skb, 0)) - return NF_DROP; + if (!skb_make_writable(skb, 0)) + return EBT_DROP; memcpy(eth_hdr(skb)->h_source, info->mac, ETH_ALEN); if (!(info->target & NAT_ARP_BIT) && --- linux-2.6.24.orig/net/bridge/netfilter/ebtables.c +++ linux-2.6.24/net/bridge/netfilter/ebtables.c @@ -1438,6 +1438,9 @@ { int ret; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + switch(cmd) { case EBT_SO_SET_ENTRIES: ret = do_replace(user, len); @@ -1457,6 +1460,9 @@ struct ebt_replace tmp; struct ebt_table *t; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&tmp, user, sizeof(tmp))) return -EFAULT; --- linux-2.6.24.orig/net/bridge/netfilter/ebt_dnat.c +++ linux-2.6.24/net/bridge/netfilter/ebt_dnat.c @@ -20,8 +20,8 @@ { struct ebt_nat_info *info = (struct ebt_nat_info *)data; - if (skb_make_writable(skb, 0)) - return NF_DROP; + if (!skb_make_writable(skb, 0)) + return EBT_DROP; memcpy(eth_hdr(skb)->h_dest, info->mac, ETH_ALEN); return info->target; --- linux-2.6.24.orig/net/rose/af_rose.c +++ linux-2.6.24/net/rose/af_rose.c @@ -937,6 +937,7 @@ struct rose_sock *rose = rose_sk(sk); int n; + memset(srose, 0, sizeof(*srose)); if (peer != 0) { if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; @@ -1100,6 +1101,10 @@ /* Build a packet */ SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n"); + /* Sanity check the packet size */ + if (len > 65535) + return -EMSGSIZE; + size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) --- linux-2.6.24.orig/net/irda/af_irda.c +++ linux-2.6.24/net/irda/af_irda.c @@ -714,6 +714,7 @@ struct sock *sk = sock->sk; struct irda_sock *self = irda_sk(sk); + memset(&saddr, 0, sizeof(saddr)); if (peer) { if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; --- linux-2.6.24.orig/net/sctp/auth.c +++ linux-2.6.24/net/sctp/auth.c @@ -80,6 +80,10 @@ { struct sctp_auth_bytes *key; + /* Verify that we are not going to overflow INT_MAX */ + if ((INT_MAX - key_len) < sizeof(struct sctp_auth_bytes)) + return NULL; + /* Allocate the shared key */ key = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp); if (!key) @@ -782,6 +786,9 @@ for (i = 0; i < hmacs->shmac_num_idents; i++) { id = hmacs->shmac_idents[i]; + if (id > SCTP_AUTH_HMAC_ID_MAX) + return -EOPNOTSUPP; + if (SCTP_AUTH_HMAC_ID_SHA1 == id) has_sha1 = 1; --- linux-2.6.24.orig/net/sctp/associola.c +++ linux-2.6.24/net/sctp/associola.c @@ -589,11 +589,12 @@ /* Check to see if this is a duplicate. */ peer = sctp_assoc_lookup_paddr(asoc, addr); if (peer) { + /* An UNKNOWN state is only set on transports added by + * user in sctp_connectx() call. Such transports should be + * considered CONFIRMED per RFC 4960, Section 5.4. + */ if (peer->state == SCTP_UNKNOWN) { - if (peer_state == SCTP_ACTIVE) - peer->state = SCTP_ACTIVE; - if (peer_state == SCTP_UNCONFIRMED) - peer->state = SCTP_UNCONFIRMED; + peer->state = SCTP_ACTIVE; } return peer; } --- linux-2.6.24.orig/net/sctp/endpointola.c +++ linux-2.6.24/net/sctp/endpointola.c @@ -107,6 +107,7 @@ /* Initialize the CHUNKS parameter */ auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS; + auth_chunks->param_hdr.length = htons(sizeof(sctp_paramhdr_t)); /* If the Add-IP functionality is enabled, we must * authenticate, ASCONF and ASCONF-ACK chunks @@ -114,8 +115,7 @@ if (sctp_addip_enable) { auth_chunks->chunks[0] = SCTP_CID_ASCONF; auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK; - auth_chunks->param_hdr.length = - htons(sizeof(sctp_paramhdr_t) + 2); + auth_chunks->param_hdr.length += htons(2); } } --- linux-2.6.24.orig/net/sctp/protocol.c +++ linux-2.6.24/net/sctp/protocol.c @@ -626,6 +626,7 @@ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; struct sctp_sockaddr_entry *addr = NULL; struct sctp_sockaddr_entry *temp; + int found = 0; switch (ev) { case NETDEV_UP: @@ -645,13 +646,14 @@ list_for_each_entry_safe(addr, temp, &sctp_local_addr_list, list) { if (addr->a.v4.sin_addr.s_addr == ifa->ifa_local) { + found = 1; addr->valid = 0; list_del_rcu(&addr->list); break; } } spin_unlock_bh(&sctp_local_addr_lock); - if (addr && !addr->valid) + if (found) call_rcu(&addr->rcu, sctp_local_addr_free); break; } --- linux-2.6.24.orig/net/sctp/socket.c +++ linux-2.6.24/net/sctp/socket.c @@ -2959,6 +2959,9 @@ { struct sctp_authchunk val; + if (!sctp_auth_enable) + return -EACCES; + if (optlen != sizeof(struct sctp_authchunk)) return -EINVAL; if (copy_from_user(&val, optval, optlen)) @@ -2987,8 +2990,12 @@ int optlen) { struct sctp_hmacalgo *hmacs; + u32 idents; int err; + if (!sctp_auth_enable) + return -EACCES; + if (optlen < sizeof(struct sctp_hmacalgo)) return -EINVAL; @@ -3001,8 +3008,9 @@ goto out; } - if (hmacs->shmac_num_idents == 0 || - hmacs->shmac_num_idents > SCTP_AUTH_NUM_HMACS) { + idents = hmacs->shmac_num_idents; + if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || + (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) { err = -EINVAL; goto out; } @@ -3027,6 +3035,9 @@ struct sctp_association *asoc; int ret; + if (!sctp_auth_enable) + return -EACCES; + if (optlen <= sizeof(struct sctp_authkey)) return -EINVAL; @@ -3039,6 +3050,11 @@ goto out; } + if (authkey->sca_keylen > optlen) { + ret = -EINVAL; + goto out; + } + asoc = sctp_id2assoc(sk, authkey->sca_assoc_id); if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) { ret = -EINVAL; @@ -3064,6 +3080,9 @@ struct sctp_authkeyid val; struct sctp_association *asoc; + if (!sctp_auth_enable) + return -EACCES; + if (optlen != sizeof(struct sctp_authkeyid)) return -EINVAL; if (copy_from_user(&val, optval, optlen)) @@ -3089,6 +3108,9 @@ struct sctp_authkeyid val; struct sctp_association *asoc; + if (!sctp_auth_enable) + return -EACCES; + if (optlen != sizeof(struct sctp_authkeyid)) return -EINVAL; if (copy_from_user(&val, optval, optlen)) @@ -4391,7 +4413,9 @@ if (copy_from_user(&getaddrs, optval, len)) return -EFAULT; - if (getaddrs.addr_num <= 0) return -EINVAL; + if (getaddrs.addr_num <= 0 || + getaddrs.addr_num >= (INT_MAX / sizeof(union sctp_addr))) + return -EINVAL; /* * For UDP-style sockets, id specifies the association to query. * If the id field is set to the value '0' then the locally bound @@ -5016,19 +5040,29 @@ static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, char __user *optval, int __user *optlen) { + struct sctp_hmacalgo __user *p = (void __user *)optval; struct sctp_hmac_algo_param *hmacs; - __u16 param_len; + __u16 data_len = 0; + u32 num_idents; + + if (!sctp_auth_enable) + return -EACCES; hmacs = sctp_sk(sk)->ep->auth_hmacs_list; - param_len = ntohs(hmacs->param_hdr.length); + data_len = ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t); - if (len < param_len) + if (len < sizeof(struct sctp_hmacalgo) + data_len) return -EINVAL; + + len = sizeof(struct sctp_hmacalgo) + data_len; + num_idents = data_len / sizeof(u16); + if (put_user(len, optlen)) return -EFAULT; - if (copy_to_user(optval, hmacs->hmac_ids, len)) + if (put_user(num_idents, &p->shmac_num_idents)) + return -EFAULT; + if (copy_to_user(p->shmac_idents, hmacs->hmac_ids, data_len)) return -EFAULT; - return 0; } @@ -5038,6 +5072,9 @@ struct sctp_authkeyid val; struct sctp_association *asoc; + if (!sctp_auth_enable) + return -EACCES; + if (len < sizeof(struct sctp_authkeyid)) return -EINVAL; if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid))) @@ -5052,6 +5089,12 @@ else val.scact_keynumber = sctp_sk(sk)->ep->active_key_id; + len = sizeof(struct sctp_authkeyid); + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + return 0; } @@ -5062,12 +5105,16 @@ struct sctp_authchunks val; struct sctp_association *asoc; struct sctp_chunks_param *ch; + u32 num_chunks = 0; char __user *to; - if (len <= sizeof(struct sctp_authchunks)) + if (!sctp_auth_enable) + return -EACCES; + + if (len < sizeof(struct sctp_authchunks)) return -EINVAL; - if (copy_from_user(&val, p, sizeof(struct sctp_authchunks))) + if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) return -EFAULT; to = p->gauth_chunks; @@ -5076,16 +5123,19 @@ return -EINVAL; ch = asoc->peer.peer_chunks; + if (!ch) + goto num; /* See if the user provided enough room for all the data */ - if (len < ntohs(ch->param_hdr.length)) + num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); + if (len < num_chunks) return -EINVAL; - len = ntohs(ch->param_hdr.length); - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(to, ch->chunks, len)) + if (copy_to_user(to, ch->chunks, num_chunks)) return -EFAULT; +num: + len = sizeof(struct sctp_authchunks) + num_chunks; + if (put_user(len, optlen)) return -EFAULT; return 0; } @@ -5097,12 +5147,16 @@ struct sctp_authchunks val; struct sctp_association *asoc; struct sctp_chunks_param *ch; + u32 num_chunks = 0; char __user *to; - if (len <= sizeof(struct sctp_authchunks)) + if (!sctp_auth_enable) + return -EACCES; + + if (len < sizeof(struct sctp_authchunks)) return -EINVAL; - if (copy_from_user(&val, p, sizeof(struct sctp_authchunks))) + if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) return -EFAULT; to = p->gauth_chunks; @@ -5115,13 +5169,18 @@ else ch = sctp_sk(sk)->ep->auth_chunk_list; - if (len < ntohs(ch->param_hdr.length)) + if (!ch) + goto num; + + num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); + if (len < sizeof(struct sctp_authchunks) + num_chunks) return -EINVAL; - len = ntohs(ch->param_hdr.length); - if (put_user(len, optlen)) + if (copy_to_user(to, ch->chunks, num_chunks)) return -EFAULT; - if (copy_to_user(to, ch->chunks, len)) +num: + len = sizeof(struct sctp_authchunks) + num_chunks; + if (put_user(len, optlen)) return -EFAULT; return 0; --- linux-2.6.24.orig/net/sctp/ipv6.c +++ linux-2.6.24/net/sctp/ipv6.c @@ -89,6 +89,7 @@ struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; struct sctp_sockaddr_entry *addr = NULL; struct sctp_sockaddr_entry *temp; + int found = 0; switch (ev) { case NETDEV_UP: @@ -111,13 +112,14 @@ &sctp_local_addr_list, list) { if (ipv6_addr_equal(&addr->a.v6.sin6_addr, &ifa->addr)) { + found = 1; addr->valid = 0; list_del_rcu(&addr->list); break; } } spin_unlock_bh(&sctp_local_addr_lock); - if (addr && !addr->valid) + if (found) call_rcu(&addr->rcu, sctp_local_addr_free); break; } @@ -889,6 +891,10 @@ dev = dev_get_by_index(&init_net, addr->v6.sin6_scope_id); if (!dev) return 0; + if (!ipv6_chk_addr(&addr->v6.sin6_addr, dev, 0)) { + dev_put(dev); + return 0; + } dev_put(dev); } af = opt->pf->af; --- linux-2.6.24.orig/net/sctp/sm_make_chunk.c +++ linux-2.6.24/net/sctp/sm_make_chunk.c @@ -1012,6 +1012,29 @@ return retval; } +struct sctp_chunk *sctp_make_violation_paramlen( + const struct sctp_association *asoc, + const struct sctp_chunk *chunk, + struct sctp_paramhdr *param) +{ + struct sctp_chunk *retval; + static const char error[] = "The following parameter had invalid length:"; + size_t payload_len = sizeof(error) + sizeof(sctp_errhdr_t) + + sizeof(sctp_paramhdr_t); + + retval = sctp_make_abort(asoc, chunk, payload_len); + if (!retval) + goto nodata; + + sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, + sizeof(error) + sizeof(sctp_paramhdr_t)); + sctp_addto_chunk(retval, sizeof(error), error); + sctp_addto_param(retval, sizeof(sctp_paramhdr_t), param); + +nodata: + return retval; +} + /* Make a HEARTBEAT chunk. */ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, const struct sctp_transport *transport, @@ -1782,11 +1805,6 @@ const struct sctp_chunk *chunk, struct sctp_chunk **errp) { - char error[] = "The following parameter had invalid length:"; - size_t payload_len = WORD_ROUND(sizeof(error)) + - sizeof(sctp_paramhdr_t); - - /* This is a fatal error. Any accumulated non-fatal errors are * not reported. */ @@ -1794,14 +1812,7 @@ sctp_chunk_free(*errp); /* Create an error chunk and fill it in with our payload. */ - *errp = sctp_make_op_error_space(asoc, chunk, payload_len); - - if (*errp) { - sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, - sizeof(error) + sizeof(sctp_paramhdr_t)); - sctp_addto_chunk(*errp, sizeof(error), error); - sctp_addto_param(*errp, sizeof(sctp_paramhdr_t), param); - } + *errp = sctp_make_violation_paramlen(asoc, chunk, param); return 0; } @@ -2252,12 +2263,10 @@ /* Release the transport structures. */ list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); - list_del_init(pos); - sctp_transport_free(transport); + if (transport->state != SCTP_ACTIVE) + sctp_assoc_rm_peer(asoc, transport); } - asoc->peer.transport_count = 0; - nomem: return 0; } --- linux-2.6.24.orig/net/sctp/bind_addr.c +++ linux-2.6.24/net/sctp/bind_addr.c @@ -209,6 +209,7 @@ int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr) { struct sctp_sockaddr_entry *addr, *temp; + int found = 0; /* We hold the socket lock when calling this function, * and that acts as a writer synchronizing lock. @@ -216,13 +217,14 @@ list_for_each_entry_safe(addr, temp, &bp->address_list, list) { if (sctp_cmp_addr_exact(&addr->a, del_addr)) { /* Found the exact match. */ + found = 1; addr->valid = 0; list_del_rcu(&addr->list); break; } } - if (addr && !addr->valid) { + if (found) { call_rcu(&addr->rcu, sctp_local_addr_free); SCTP_DBG_OBJCNT_DEC(addr); return 0; --- linux-2.6.24.orig/net/sctp/sm_statefuns.c +++ linux-2.6.24/net/sctp/sm_statefuns.c @@ -121,7 +121,7 @@ const struct sctp_endpoint *ep, const struct sctp_association *asoc, const sctp_subtype_t type, - void *arg, + void *arg, void *ext, sctp_cmd_seq_t *commands); static sctp_disposition_t sctp_sf_violation_ctsn( @@ -3388,7 +3388,7 @@ addr_param = (union sctp_addr_param *)hdr->params; length = ntohs(addr_param->p.length); if (length < sizeof(sctp_paramhdr_t)) - return sctp_sf_violation_paramlen(ep, asoc, type, + return sctp_sf_violation_paramlen(ep, asoc, type, arg, (void *)addr_param, commands); /* Verify the ASCONF chunk before processing it. */ @@ -3396,8 +3396,8 @@ (sctp_paramhdr_t *)((void *)addr_param + length), (void *)chunk->chunk_end, &err_param)) - return sctp_sf_violation_paramlen(ep, asoc, type, - (void *)&err_param, commands); + return sctp_sf_violation_paramlen(ep, asoc, type, arg, + (void *)err_param, commands); /* ADDIP 4.2 C1) Compare the value of the serial number to the value * the endpoint stored in a new association variable @@ -3476,8 +3476,8 @@ (sctp_paramhdr_t *)addip_hdr->params, (void *)asconf_ack->chunk_end, &err_param)) - return sctp_sf_violation_paramlen(ep, asoc, type, - (void *)&err_param, commands); + return sctp_sf_violation_paramlen(ep, asoc, type, arg, + (void *)err_param, commands); if (last_asconf) { addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr; @@ -3569,6 +3569,7 @@ { struct sctp_chunk *chunk = arg; struct sctp_fwdtsn_hdr *fwdtsn_hdr; + struct sctp_fwdtsn_skip *skip; __u16 len; __u32 tsn; @@ -3598,6 +3599,12 @@ if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0) goto discard_noforce; + /* Silently discard the chunk if stream-id is not valid */ + sctp_walk_fwdtsn(skip, chunk) { + if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) + goto discard_noforce; + } + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn)); if (len > sizeof(struct sctp_fwdtsn_hdr)) sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, @@ -3629,6 +3636,7 @@ { struct sctp_chunk *chunk = arg; struct sctp_fwdtsn_hdr *fwdtsn_hdr; + struct sctp_fwdtsn_skip *skip; __u16 len; __u32 tsn; @@ -3658,6 +3666,12 @@ if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0) goto gen_shutdown; + /* Silently discard the chunk if stream-id is not valid */ + sctp_walk_fwdtsn(skip, chunk) { + if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) + goto gen_shutdown; + } + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn)); if (len > sizeof(struct sctp_fwdtsn_hdr)) sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, @@ -4152,12 +4166,38 @@ const struct sctp_endpoint *ep, const struct sctp_association *asoc, const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) { - char err_str[] = "The following parameter had invalid length:"; + void *arg, void *ext, + sctp_cmd_seq_t *commands) +{ + struct sctp_chunk *chunk = arg; + struct sctp_paramhdr *param = ext; + struct sctp_chunk *abort = NULL; - return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str, - sizeof(err_str)); + if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc)) + goto discard; + + /* Make the abort chunk. */ + abort = sctp_make_violation_paramlen(asoc, chunk, param); + if (!abort) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); + SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); + + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ECONNABORTED)); + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION)); + SCTP_DEC_STATS(SCTP_MIB_CURRESTAB); + +discard: + sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands); + + SCTP_INC_STATS(SCTP_MIB_ABORTEDS); + + return SCTP_DISPOSITION_ABORT; +nomem: + return SCTP_DISPOSITION_NOMEM; } /* Handle a protocol violation when the peer trying to advance the --- linux-2.6.24.orig/net/mac80211/ieee80211_ioctl.c +++ linux-2.6.24/net/mac80211/ieee80211_ioctl.c @@ -218,6 +218,8 @@ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); + range->scan_capa |= IW_SCAN_CAPA_ESSID; + return 0; } --- linux-2.6.24.orig/net/9p/trans_virtio.c +++ linux-2.6.24/net/9p/trans_virtio.c @@ -199,14 +199,12 @@ kfree(trans); } -static bool p9_virtio_intr(struct virtqueue *q) +static void p9_virtio_intr(struct virtqueue *q) { struct virtio_chan *chan = q->vdev->priv; P9_DPRINTK(P9_DEBUG_TRANS, "9p poll_wakeup: %p\n", &chan->wq); wake_up_interruptible(&chan->wq); - - return true; } static int p9_virtio_probe(struct virtio_device *dev) @@ -236,13 +234,13 @@ /* Find the input queue. */ dev->priv = chan; - chan->in_vq = dev->config->find_vq(dev, p9_virtio_intr); + chan->in_vq = dev->config->find_vq(dev, 0, p9_virtio_intr); if (IS_ERR(chan->in_vq)) { err = PTR_ERR(chan->in_vq); goto free; } - chan->out_vq = dev->config->find_vq(dev, NULL); + chan->out_vq = dev->config->find_vq(dev, 1, NULL); if (IS_ERR(chan->out_vq)) { err = PTR_ERR(chan->out_vq); goto free_in_vq; --- linux-2.6.24.orig/net/sched/sch_generic.c +++ linux-2.6.24/net/sched/sch_generic.c @@ -178,10 +178,22 @@ void __qdisc_run(struct net_device *dev) { - do { - if (!qdisc_restart(dev)) + unsigned long start_time = jiffies; + + while (qdisc_restart(dev)) { + if (netif_queue_stopped(dev)) + break; + + /* + * Postpone processing if + * 1. another process needs the CPU; + * 2. we've been doing it for too long. + */ + if (need_resched() || jiffies != start_time) { + netif_schedule(dev); break; - } while (!netif_queue_stopped(dev)); + } + } clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state); } --- linux-2.6.24.orig/net/sched/em_meta.c +++ linux-2.6.24/net/sched/em_meta.c @@ -719,11 +719,13 @@ static inline void meta_delete(struct meta_match *meta) { - struct meta_type_ops *ops = meta_type_ops(&meta->lvalue); + if (meta) { + struct meta_type_ops *ops = meta_type_ops(&meta->lvalue); - if (ops && ops->destroy) { - ops->destroy(&meta->lvalue); - ops->destroy(&meta->rvalue); + if (ops && ops->destroy) { + ops->destroy(&meta->lvalue); + ops->destroy(&meta->rvalue); + } } kfree(meta); --- linux-2.6.24.orig/net/sched/sch_api.c +++ linux-2.6.24/net/sched/sch_api.c @@ -1044,6 +1044,8 @@ nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); tcm = NLMSG_DATA(nlh); tcm->tcm_family = AF_UNSPEC; + tcm->tcm__pad1 = 0; + tcm->tcm__pad2 = 0; tcm->tcm_ifindex = q->dev->ifindex; tcm->tcm_parent = q->handle; tcm->tcm_handle = q->handle; --- linux-2.6.24.orig/net/sched/sch_htb.c +++ linux-2.6.24/net/sched/sch_htb.c @@ -708,9 +708,11 @@ */ static psched_time_t htb_do_events(struct htb_sched *q, int level) { - int i; - - for (i = 0; i < 500; i++) { + /* don't run for longer than 2 jiffies; 2 is used instead of + 1 to simplify things when jiffy is going to be incremented + too soon */ + unsigned long stop_at = jiffies + 2; + while (time_before(jiffies, stop_at)) { struct htb_class *cl; long diff; struct rb_node *p = rb_first(&q->wait_pq[level]); @@ -728,9 +730,8 @@ if (cl->cmode != HTB_CAN_SEND) htb_add_to_wait_tree(q, cl, diff); } - if (net_ratelimit()) - printk(KERN_WARNING "htb: too many events !\n"); - return q->now + PSCHED_TICKS_PER_SEC / 10; + /* too much load - let's continue on next jiffie */ + return q->now + PSCHED_TICKS_PER_SEC / HZ; } /* Returns class->node+prio from id-tree where classe's id is >= id. NULL --- linux-2.6.24.orig/net/sched/ematch.c +++ linux-2.6.24/net/sched/ematch.c @@ -305,10 +305,9 @@ struct tcf_ematch_tree_hdr *tree_hdr; struct tcf_ematch *em; - if (!rta) { - memset(tree, 0, sizeof(*tree)); + memset(tree, 0, sizeof(*tree)); + if (!rta) return 0; - } if (rtattr_parse_nested(tb, TCA_EMATCH_TREE_MAX, rta) < 0) goto errout; --- linux-2.6.24.orig/net/sched/cls_api.c +++ linux-2.6.24/net/sched/cls_api.c @@ -320,7 +320,7 @@ tcm = NLMSG_DATA(nlh); tcm->tcm_family = AF_UNSPEC; tcm->tcm__pad1 = 0; - tcm->tcm__pad1 = 0; + tcm->tcm__pad2 = 0; tcm->tcm_ifindex = tp->q->dev->ifindex; tcm->tcm_parent = tp->classid; tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol); --- linux-2.6.24.orig/net/bluetooth/hci_core.c +++ linux-2.6.24/net/bluetooth/hci_core.c @@ -624,7 +624,8 @@ hdev->flush(hdev); atomic_set(&hdev->cmd_cnt, 1); - hdev->acl_cnt = 0; hdev->sco_cnt = 0; + atomic_set(&hdev->sco_cnt, 0); + hdev->acl_cnt = 0; if (!test_bit(HCI_RAW, &hdev->flags)) ret = __hci_request(hdev, hci_reset_req, 0, @@ -901,8 +902,6 @@ BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); - hci_unregister_sysfs(hdev); - write_lock_bh(&hci_dev_list_lock); list_del(&hdev->list); write_unlock_bh(&hci_dev_list_lock); @@ -914,6 +913,8 @@ hci_notify(hdev, HCI_DEV_UNREG); + hci_unregister_sysfs(hdev); + __hci_dev_put(hdev); return 0; @@ -1230,6 +1231,7 @@ { struct hci_dev *hdev = conn->hdev; struct hci_sco_hdr hdr; + ktime_t now; BT_DBG("%s len %d", hdev->name, skb->len); @@ -1238,6 +1240,13 @@ return -EINVAL; } + now = conn->tx_timer.base->get_time(); + + /* force a clean start for 100 ms or later underrun */ + if (conn->tx_timer.expires.tv64 + NSEC_PER_SEC / 10 <= now.tv64) { + conn->tx_timer.expires = now; + } + hdr.handle = cpu_to_le16(conn->handle); hdr.dlen = skb->len; @@ -1255,12 +1264,12 @@ /* ---- HCI TX task (outgoing data) ---- */ -/* HCI Connection scheduler */ -static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote) +/* HCI ACL Connection scheduler */ +static inline struct hci_conn *hci_low_sent_acl(struct hci_dev *hdev, int *quote) { struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn *conn = NULL; - int num = 0, min = ~0; + unsigned int num = 0, min = ~0; struct list_head *p; /* We don't have to lock device here. Connections are always @@ -1269,20 +1278,22 @@ struct hci_conn *c; c = list_entry(p, struct hci_conn, list); - if (c->type != type || c->state != BT_CONNECTED + BT_DBG("c->type %d c->state %d len(c->data_q) %d min %d c->sent %d", + c->type, c->state, skb_queue_len(&c->data_q), min, atomic_read(&c->sent)); + + if (c->type != ACL_LINK || c->state != BT_CONNECTED || skb_queue_empty(&c->data_q)) continue; num++; - if (c->sent < min) { - min = c->sent; + if (atomic_read(&c->sent) < min) { + min = atomic_read(&c->sent); conn = c; } } if (conn) { - int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt); - int q = cnt / num; + int q = hdev->acl_cnt / num; *quote = q ? q : 1; } else *quote = 0; @@ -1302,7 +1313,7 @@ /* Kill stalled connections */ list_for_each(p, &h->list) { c = list_entry(p, struct hci_conn, list); - if (c->type == ACL_LINK && c->sent) { + if (c->type == ACL_LINK && atomic_read(&c->sent)) { BT_ERR("%s killing stalled ACL connection %s", hdev->name, batostr(&c->dst)); hci_acl_disconn(c, 0x13); @@ -1325,7 +1336,7 @@ hci_acl_tx_to(hdev); } - while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { + while (hdev->acl_cnt && (conn = hci_low_sent_acl(hdev, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); @@ -1335,48 +1346,61 @@ hdev->acl_last_tx = jiffies; hdev->acl_cnt--; - conn->sent++; + atomic_inc(&conn->sent); } } } -/* Schedule SCO */ +/* HCI SCO Connection scheduler */ + static inline void hci_sched_sco(struct hci_dev *hdev) { - struct hci_conn *conn; + struct hci_conn_hash *h = &hdev->conn_hash; struct sk_buff *skb; - int quote; - + struct list_head *p; + struct hci_conn *c; + ktime_t now, pkt_time; + BT_DBG("%s", hdev->name); + + /* We don't have to lock device here. Connections are always + added and removed with TX task disabled. */ + list_for_each(p, &h->list) { + c = list_entry(p, struct hci_conn, list); + + /* SCO scheduling algorithm makes sure there is never more than + 1 outstanding packet for each connection */ - while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, "e))) { - while (quote-- && (skb = skb_dequeue(&conn->data_q))) { - BT_DBG("skb %p len %d", skb, skb->len); - hci_send_frame(skb); + if (c->type == ACL_LINK) + continue; - conn->sent++; - if (conn->sent == ~0) - conn->sent = 0; - } - } -} + if (atomic_read(&c->sent) >= 1) + continue; -static inline void hci_sched_esco(struct hci_dev *hdev) -{ - struct hci_conn *conn; - struct sk_buff *skb; - int quote; + if (c->state != BT_CONNECTED) + continue; - BT_DBG("%s", hdev->name); + if (atomic_read(&hdev->sco_cnt) <= 0) + continue; - while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, "e))) { - while (quote-- && (skb = skb_dequeue(&conn->data_q))) { - BT_DBG("skb %p len %d", skb, skb->len); - hci_send_frame(skb); + if ((skb = skb_dequeue(&c->data_q)) == NULL) + continue; - conn->sent++; - if (conn->sent == ~0) - conn->sent = 0; + hci_send_frame(skb); + + atomic_inc(&c->sent); + atomic_dec(&hdev->sco_cnt); + + pkt_time = ktime_set(0, NSEC_PER_SEC / 16000 * (skb->len - HCI_SCO_HDR_SIZE)); + now = c->tx_timer.base->get_time(); + + c->tx_timer.expires.tv64 += pkt_time.tv64; + if (c->tx_timer.expires.tv64 > now.tv64) { + hrtimer_restart(&c->tx_timer); + } else { + /* Timer is to expire in the past - force timer expiration. + this can happen if timer base precision is less than pkt_time */ + c->tx_timer.function(&c->tx_timer); } } } @@ -1388,15 +1412,13 @@ read_lock(&hci_task_lock); - BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt); + BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, atomic_read(&hdev->sco_cnt)); /* Schedule queues and send stuff to HCI driver */ - hci_sched_acl(hdev); - hci_sched_sco(hdev); - hci_sched_esco(hdev); + hci_sched_acl(hdev); /* Send next queued raw (unknown type) packet */ while ((skb = skb_dequeue(&hdev->raw_q))) --- linux-2.6.24.orig/net/bluetooth/hci_event.c +++ linux-2.6.24/net/bluetooth/hci_event.c @@ -434,7 +434,7 @@ } hdev->acl_cnt = hdev->acl_pkts; - hdev->sco_cnt = hdev->sco_pkts; + atomic_set(&hdev->sco_cnt, hdev->sco_pkts); BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name, hdev->acl_mtu, hdev->acl_pkts, @@ -1157,14 +1157,11 @@ conn = hci_conn_hash_lookup_handle(hdev, handle); if (conn) { - conn->sent -= count; + atomic_sub(count, &conn->sent); if (conn->type == ACL_LINK) { if ((hdev->acl_cnt += count) > hdev->acl_pkts) hdev->acl_cnt = hdev->acl_pkts; - } else { - if ((hdev->sco_cnt += count) > hdev->sco_pkts) - hdev->sco_cnt = hdev->sco_pkts; } } } --- linux-2.6.24.orig/net/bluetooth/hidp/core.c +++ linux-2.6.24/net/bluetooth/hidp/core.c @@ -592,6 +592,12 @@ hid_free_device(session->hid); } + /* Wakeup user-space polling for socket errors */ + session->intr_sock->sk->sk_err = EUNATCH; + session->ctrl_sock->sk->sk_err = EUNATCH; + + hidp_schedule(session); + fput(session->intr_sock->file); wait_event_timeout(*(ctrl_sk->sk_sleep), @@ -688,6 +694,10 @@ } hidp_blacklist[] = { /* Apple wireless Mighty Mouse */ { 0x05ac, 0x030c, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, + /* Apple Wireless Aluminum Keyboard */ + { 0x05ac, 0x022c, HID_QUIRK_APPLE_HAS_FN }, + { 0x05ac, 0x022d, HID_QUIRK_APPLE_HAS_FN }, + { 0x05ac, 0x022e, HID_QUIRK_APPLE_HAS_FN }, { } /* Terminating entry */ }; @@ -891,6 +901,10 @@ skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); + /* Wakeup user-space polling for socket errors */ + session->intr_sock->sk->sk_err = EUNATCH; + session->ctrl_sock->sk->sk_err = EUNATCH; + /* Kill session thread */ atomic_inc(&session->terminate); hidp_schedule(session); --- linux-2.6.24.orig/net/bluetooth/sco.c +++ linux-2.6.24/net/bluetooth/sco.c @@ -53,7 +53,13 @@ #define BT_DBG(D...) #endif -#define VERSION "0.5" +#define VERSION "0.6" + +#define MAX_SCO_TXBUFS 200 +#define MAX_SCO_RXBUFS 200 + +#define DEFAULT_SCO_TXBUFS 5 +#define DEFAULT_SCO_RXBUFS 5 static const struct proto_ops sco_sock_ops; @@ -69,6 +75,33 @@ static void sco_sock_close(struct sock *sk); static void sco_sock_kill(struct sock *sk); +/* + * Write buffer destructor automatically called from kfree_skb. + */ +void sco_sock_wfree(struct sk_buff *skb) +{ + struct sock *sk = skb->sk; + + atomic_dec(&sk->sk_wmem_alloc); + sk->sk_write_space(sk); + sock_put(sk); +} + +static void sco_sock_write_space(struct sock *sk) +{ + read_lock(&sk->sk_callback_lock); + + if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); + + if (sock_writeable(sk)) + sk_wake_async(sk, 2, POLL_OUT); + } + + read_unlock(&sk->sk_callback_lock); +} + /* ---- SCO timers ---- */ static void sco_sock_timeout(unsigned long arg) { @@ -200,7 +233,11 @@ err = -ENOMEM; - type = lmp_esco_capable(hdev) ? ESCO_LINK : SCO_LINK; + /* + * Since eSCO seems currently broken, always use SCO (LP#39414). + * type = lmp_esco_capable(hdev) ? ESCO_LINK : SCO_LINK; + */ + type = SCO_LINK; hcon = hci_connect(hdev, type, dst); if (!hcon) @@ -237,33 +274,55 @@ { struct sco_conn *conn = sco_pi(sk)->conn; struct sk_buff *skb; - int err, count; - - /* Check outgoing MTU */ - if (len > conn->mtu) - return -EINVAL; + int err; BT_DBG("sk %p len %d", sk, len); - count = min_t(unsigned int, conn->mtu, len); - if (!(skb = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err))) + if (!(skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) return err; - if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { + /* fix sk_wmem_alloc value : by default it is increased by skb->truesize, but + we want it only increased by 1 */ + atomic_sub(skb->truesize - 1, &sk->sk_wmem_alloc); + /* fix destructor */ + skb->destructor = sco_sock_wfree; + + if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { err = -EFAULT; goto fail; } - if ((err = hci_send_sco(conn->hcon, skb)) < 0) - return err; + err = hci_send_sco(conn->hcon, skb); + + if (err < 0) + goto fail; - return count; + return len; fail: kfree_skb(skb); return err; } +static int sco_sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) +{ + BT_DBG("sock %p, sk_rcvbuf %d, qlen %d", sk, sk->sk_rcvbuf, skb_queue_len(&sk->sk_receive_queue)); + + if (skb_queue_len(&sk->sk_receive_queue) + 1 > (unsigned)sk->sk_rcvbuf) + return -ENOMEM; + + skb->dev = NULL; + skb->sk = sk; + skb->destructor = NULL; + + skb_queue_tail(&sk->sk_receive_queue, skb); + + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, 1); + + return 0; +} + static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) { struct sock *sk = sco_chan_get(conn); @@ -276,7 +335,7 @@ if (sk->sk_state != BT_CONNECTED) goto drop; - if (!sock_queue_rcv_skb(sk, skb)) + if (!sco_sock_queue_rcv_skb(sk, skb)) return; drop: @@ -331,7 +390,6 @@ BT_DBG("sk %p", sk); skb_queue_purge(&sk->sk_receive_queue); - skb_queue_purge(&sk->sk_write_queue); } static void sco_sock_cleanup_listen(struct sock *parent) @@ -429,6 +487,10 @@ INIT_LIST_HEAD(&bt_sk(sk)->accept_q); sk->sk_destruct = sco_sock_destruct; + sk->sk_write_space = sco_sock_write_space; + + sk->sk_sndbuf = DEFAULT_SCO_TXBUFS; + sk->sk_rcvbuf = DEFAULT_SCO_RXBUFS; sk->sk_sndtimeo = SCO_CONN_TIMEOUT; sock_reset_flag(sk, SOCK_ZAPPED); @@ -659,6 +721,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { struct sock *sk = sock->sk; + u32 opt; int err = 0; BT_DBG("sk %p", sk); @@ -666,6 +729,32 @@ lock_sock(sk); switch (optname) { + case SO_SNDBUF: + if (get_user(opt, (u32 __user *) optval)) { + err = -EFAULT; + break; + } + if (opt > MAX_SCO_TXBUFS) { + err = -EINVAL; + break; + } + + sk->sk_sndbuf = opt; + /* Wake up sending tasks if we upped the value */ + sk->sk_write_space(sk); + break; + case SO_RCVBUF: + if (get_user(opt, (u32 __user *) optval)) { + err = -EFAULT; + break; + } + if (opt > MAX_SCO_RXBUFS) { + err = -EINVAL; + break; + } + + sk->sk_rcvbuf = opt; + break; default: err = -ENOPROTOOPT; break; @@ -681,6 +770,7 @@ struct sco_options opts; struct sco_conninfo cinfo; int len, err = 0; + int val; BT_DBG("sk %p", sk); @@ -690,6 +780,24 @@ lock_sock(sk); switch (optname) { + case SO_RCVBUF: + val = sk->sk_rcvbuf; + + len = min_t(unsigned int, len, sizeof(val)); + if (copy_to_user(optval, (char *) &val, len)) + err = -EFAULT; + + break; + + case SO_SNDBUF: + val = sk->sk_sndbuf; + + len = min_t(unsigned int, len, sizeof(val)); + if (copy_to_user(optval, (char *) &val, len)) + err = -EFAULT; + + break; + case SCO_OPTIONS: if (sk->sk_state != BT_CONNECTED) { err = -ENOTCONN; @@ -701,7 +809,7 @@ BT_DBG("mtu %d", opts.mtu); len = min_t(unsigned int, len, sizeof(opts)); - if (copy_to_user(optval, (char *)&opts, len)) + if (copy_to_user(optval, (char *) &opts, len)) err = -EFAULT; break; @@ -716,7 +824,7 @@ memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3); len = min_t(unsigned int, len, sizeof(cinfo)); - if (copy_to_user(optval, (char *)&cinfo, len)) + if (copy_to_user(optval, (char *) &cinfo, len)) err = -EFAULT; break; --- linux-2.6.24.orig/net/bluetooth/hci_sysfs.c +++ linux-2.6.24/net/bluetooth/hci_sysfs.c @@ -12,6 +12,8 @@ #undef BT_DBG #define BT_DBG(D...) #endif +static struct workqueue_struct *btaddconn; +static struct workqueue_struct *btdelconn; static inline char *typetostr(int type) { @@ -279,6 +281,8 @@ struct hci_conn *conn = container_of(work, struct hci_conn, work); int i; + flush_workqueue(btdelconn); + if (device_add(&conn->dev) < 0) { BT_ERR("Failed to register connection device"); return; @@ -313,7 +317,7 @@ INIT_WORK(&conn->work, add_conn); - schedule_work(&conn->work); + queue_work(btaddconn, &conn->work); } static int __match_tty(struct device *dev, void *data) @@ -349,7 +353,7 @@ INIT_WORK(&conn->work, del_conn); - schedule_work(&conn->work); + queue_work(btdelconn, &conn->work); } int hci_register_sysfs(struct hci_dev *hdev) @@ -398,28 +402,54 @@ { int err; + btaddconn = create_singlethread_workqueue("btaddconn"); + if (!btaddconn) { + err = -ENOMEM; + goto out; + } + + btdelconn = create_singlethread_workqueue("btdelconn"); + if (!btdelconn) { + err = -ENOMEM; + goto out_del; + } + bt_platform = platform_device_register_simple("bluetooth", -1, NULL, 0); - if (IS_ERR(bt_platform)) - return PTR_ERR(bt_platform); + if (IS_ERR(bt_platform)) { + err = PTR_ERR(bt_platform); + goto out_platform; + } err = bus_register(&bt_bus); - if (err < 0) { - platform_device_unregister(bt_platform); - return err; - } + if (err < 0) + goto out_bus; bt_class = class_create(THIS_MODULE, "bluetooth"); if (IS_ERR(bt_class)) { - bus_unregister(&bt_bus); - platform_device_unregister(bt_platform); - return PTR_ERR(bt_class); + err = PTR_ERR(bt_class); + goto out_class; } return 0; + +out_class: + bus_unregister(&bt_bus); +out_bus: + platform_device_unregister(bt_platform); +out_platform: + destroy_workqueue(btdelconn); +out_del: + destroy_workqueue(btaddconn); +out: + return err; } void bt_sysfs_cleanup(void) { + destroy_workqueue(btaddconn); + + destroy_workqueue(btdelconn); + class_destroy(bt_class); bus_unregister(&bt_bus); --- linux-2.6.24.orig/net/bluetooth/hci_conn.c +++ linux-2.6.24/net/bluetooth/hci_conn.c @@ -188,6 +188,26 @@ hci_conn_enter_sniff_mode(conn); } +static enum hrtimer_restart hci_sco_tx_timer(struct hrtimer *timer) +{ + struct hci_conn *conn = container_of(timer, struct hci_conn, tx_timer); +#ifdef CONFIG_BT_HCI_CORE_DEBUG + ktime_t now = timer->base->get_time(); + + BT_DBG("%s, conn %p, time %5lu.%06lu", conn->hdev->name, conn, + (unsigned long) now.tv64, + do_div(now.tv64, NSEC_PER_SEC) / 1000); +#endif + + if (atomic_read(&conn->sent) > 0) { + atomic_dec(&conn->sent); + atomic_inc(&conn->hdev->sco_cnt); + hci_sched_tx(conn->hdev); + } + return HRTIMER_NORESTART; +} + + struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) { struct hci_conn *conn; @@ -208,6 +228,11 @@ skb_queue_head_init(&conn->data_q); + hrtimer_init(&conn->tx_timer, CLOCK_MONOTONIC, HRTIMER_NORESTART); + + if(type == SCO_LINK) + conn->tx_timer.function = hci_sco_tx_timer; + init_timer(&conn->disc_timer); conn->disc_timer.function = hci_conn_timeout; conn->disc_timer.data = (unsigned long) conn; @@ -217,6 +242,7 @@ conn->idle_timer.data = (unsigned long) conn; atomic_set(&conn->refcnt, 0); + atomic_set(&conn->sent, 0); hci_dev_hold(hdev); @@ -243,13 +269,15 @@ del_timer(&conn->disc_timer); + hrtimer_cancel(&conn->tx_timer); + if (conn->type == ACL_LINK) { struct hci_conn *sco = conn->link; if (sco) sco->link = NULL; /* Unacked frames */ - hdev->acl_cnt += conn->sent; + hdev->acl_cnt += atomic_read(&conn->sent); } else { struct hci_conn *acl = conn->link; if (acl) { --- linux-2.6.24.orig/net/ipv4/ipcomp.c +++ linux-2.6.24/net/ipv4/ipcomp.c @@ -74,6 +74,7 @@ static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb) { + int nexthdr; int err = -ENOMEM; struct ip_comp_hdr *ipch; @@ -84,13 +85,15 @@ /* Remove ipcomp header and decompress original payload */ ipch = (void *)skb->data; + nexthdr = ipch->nexthdr; + skb->transport_header = skb->network_header + sizeof(*ipch); __skb_pull(skb, sizeof(*ipch)); err = ipcomp_decompress(x, skb); if (err) goto out; - err = ipch->nexthdr; + err = nexthdr; out: return err; @@ -105,8 +108,11 @@ const int cpu = get_cpu(); u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu); struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu); - int err = crypto_comp_compress(tfm, start, plen, scratch, &dlen); + int err; + local_bh_disable(); + err = crypto_comp_compress(tfm, start, plen, scratch, &dlen); + local_bh_enable(); if (err) goto out; --- linux-2.6.24.orig/net/ipv4/fib_trie.c +++ linux-2.6.24/net/ipv4/fib_trie.c @@ -1203,20 +1203,45 @@ * and we need to allocate a new one of those as well. */ - if (fa && fa->fa_info->fib_priority == fi->fib_priority) { - struct fib_alias *fa_orig; + if (fa && fa->fa_tos == tos && + fa->fa_info->fib_priority == fi->fib_priority) { + struct fib_alias *fa_first, *fa_match; err = -EEXIST; if (cfg->fc_nlflags & NLM_F_EXCL) goto out; + /* We have 2 goals: + * 1. Find exact match for type, scope, fib_info to avoid + * duplicate routes + * 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it + */ + fa_match = NULL; + fa_first = fa; + fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list); + list_for_each_entry_continue(fa, fa_head, fa_list) { + if (fa->fa_tos != tos) + break; + if (fa->fa_info->fib_priority != fi->fib_priority) + break; + if (fa->fa_type == cfg->fc_type && + fa->fa_scope == cfg->fc_scope && + fa->fa_info == fi) { + fa_match = fa; + break; + } + } + if (cfg->fc_nlflags & NLM_F_REPLACE) { struct fib_info *fi_drop; u8 state; - if (fi->fib_treeref > 1) + fa = fa_first; + if (fa_match) { + if (fa == fa_match) + err = 0; goto out; - + } err = -ENOBUFS; new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); if (new_fa == NULL) @@ -1228,7 +1253,7 @@ new_fa->fa_type = cfg->fc_type; new_fa->fa_scope = cfg->fc_scope; state = fa->fa_state; - new_fa->fa_state &= ~FA_S_ACCESSED; + new_fa->fa_state = state & ~FA_S_ACCESSED; list_replace_rcu(&fa->fa_list, &new_fa->fa_list); alias_free_mem_rcu(fa); @@ -1245,20 +1270,11 @@ * uses the same scope, type, and nexthop * information. */ - fa_orig = fa; - list_for_each_entry(fa, fa_orig->fa_list.prev, fa_list) { - if (fa->fa_tos != tos) - break; - if (fa->fa_info->fib_priority != fi->fib_priority) - break; - if (fa->fa_type == cfg->fc_type && - fa->fa_scope == cfg->fc_scope && - fa->fa_info == fi) { - goto out; - } - } + if (fa_match) + goto out; + if (!(cfg->fc_nlflags & NLM_F_APPEND)) - fa = fa_orig; + fa = fa_first; } err = -ENOENT; if (!(cfg->fc_nlflags & NLM_F_CREATE)) @@ -1614,9 +1630,8 @@ pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t); fa_to_delete = NULL; - fa_head = fa->fa_list.prev; - - list_for_each_entry(fa, fa_head, fa_list) { + fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list); + list_for_each_entry_continue(fa, fa_head, fa_list) { struct fib_info *fi = fa->fa_info; if (fa->fa_tos != tos) --- linux-2.6.24.orig/net/ipv4/inet_diag.c +++ linux-2.6.24/net/ipv4/inet_diag.c @@ -259,8 +259,10 @@ const struct inet_diag_handler *handler; handler = inet_diag_lock_handler(nlh->nlmsg_type); - if (!handler) - return -ENOENT; + if (IS_ERR(handler)) { + err = PTR_ERR(handler); + goto unlock; + } hashinfo = handler->idiag_hashinfo; err = -EINVAL; @@ -708,8 +710,8 @@ struct inet_hashinfo *hashinfo; handler = inet_diag_lock_handler(cb->nlh->nlmsg_type); - if (!handler) - goto no_handler; + if (IS_ERR(handler)) + goto unlock; hashinfo = handler->idiag_hashinfo; @@ -838,7 +840,6 @@ cb->args[2] = num; unlock: inet_diag_unlock_handler(handler); -no_handler: return skb->len; } --- linux-2.6.24.orig/net/ipv4/esp4.c +++ linux-2.6.24/net/ipv4/esp4.c @@ -165,7 +165,7 @@ int padlen; int err; - if (!pskb_may_pull(skb, sizeof(*esph))) + if (!pskb_may_pull(skb, sizeof(*esph) + esp->conf.ivlen)) goto out; if (elen <= 0 || (elen & (blksize-1))) --- linux-2.6.24.orig/net/ipv4/tcp_output.c +++ linux-2.6.24/net/ipv4/tcp_output.c @@ -258,7 +258,7 @@ * * Relax Will Robinson. */ - new_win = cur_win; + new_win = ALIGN(cur_win, 1 << tp->rx_opt.rcv_wscale); } tp->rcv_wnd = new_win; tp->rcv_wup = tp->rcv_nxt; --- linux-2.6.24.orig/net/ipv4/fib_hash.c +++ linux-2.6.24/net/ipv4/fib_hash.c @@ -434,19 +434,43 @@ if (fa && fa->fa_tos == tos && fa->fa_info->fib_priority == fi->fib_priority) { - struct fib_alias *fa_orig; + struct fib_alias *fa_first, *fa_match; err = -EEXIST; if (cfg->fc_nlflags & NLM_F_EXCL) goto out; + /* We have 2 goals: + * 1. Find exact match for type, scope, fib_info to avoid + * duplicate routes + * 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it + */ + fa_match = NULL; + fa_first = fa; + fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list); + list_for_each_entry_continue(fa, &f->fn_alias, fa_list) { + if (fa->fa_tos != tos) + break; + if (fa->fa_info->fib_priority != fi->fib_priority) + break; + if (fa->fa_type == cfg->fc_type && + fa->fa_scope == cfg->fc_scope && + fa->fa_info == fi) { + fa_match = fa; + break; + } + } + if (cfg->fc_nlflags & NLM_F_REPLACE) { struct fib_info *fi_drop; u8 state; - if (fi->fib_treeref > 1) + fa = fa_first; + if (fa_match) { + if (fa == fa_match) + err = 0; goto out; - + } write_lock_bh(&fib_hash_lock); fi_drop = fa->fa_info; fa->fa_info = fi; @@ -469,20 +493,11 @@ * uses the same scope, type, and nexthop * information. */ - fa_orig = fa; - fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list); - list_for_each_entry_continue(fa, &f->fn_alias, fa_list) { - if (fa->fa_tos != tos) - break; - if (fa->fa_info->fib_priority != fi->fib_priority) - break; - if (fa->fa_type == cfg->fc_type && - fa->fa_scope == cfg->fc_scope && - fa->fa_info == fi) - goto out; - } + if (fa_match) + goto out; + if (!(cfg->fc_nlflags & NLM_F_APPEND)) - fa = fa_orig; + fa = fa_first; } err = -ENOENT; --- linux-2.6.24.orig/net/ipv4/ipconfig.c +++ linux-2.6.24/net/ipv4/ipconfig.c @@ -739,9 +739,9 @@ printk("Unknown ARP type 0x%04x for device %s\n", dev->type, dev->name); b->htype = dev->type; /* can cause undefined behavior */ } + + /* server_ip and your_ip address are both already zero per RFC2131 */ b->hlen = dev->addr_len; - b->your_ip = NONE; - b->server_ip = NONE; memcpy(b->hw_addr, dev->dev_addr, dev->addr_len); b->secs = htons(jiffies_diff / HZ); b->xid = d->xid; --- linux-2.6.24.orig/net/ipv4/xfrm4_tunnel.c +++ linux-2.6.24/net/ipv4/xfrm4_tunnel.c @@ -50,7 +50,7 @@ static int xfrm_tunnel_rcv(struct sk_buff *skb) { - return xfrm4_rcv_spi(skb, IPPROTO_IP, ip_hdr(skb)->saddr); + return xfrm4_rcv_spi(skb, IPPROTO_IPIP, ip_hdr(skb)->saddr); } static int xfrm_tunnel_err(struct sk_buff *skb, u32 info) --- linux-2.6.24.orig/net/ipv4/ip_sockglue.c +++ linux-2.6.24/net/ipv4/ip_sockglue.c @@ -514,11 +514,6 @@ val &= ~3; val |= inet->tos & 3; } - if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && - !capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } if (inet->tos != val) { inet->tos = val; sk->sk_priority = rt_tos2priority(val); --- linux-2.6.24.orig/net/ipv4/netfilter/ip_queue.c +++ linux-2.6.24/net/ipv4/netfilter/ip_queue.c @@ -336,8 +336,8 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) { int diff; - int err; struct iphdr *user_iph = (struct iphdr *)v->payload; + struct sk_buff *nskb; if (v->data_len < sizeof(*user_iph)) return 0; @@ -349,14 +349,16 @@ if (v->data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - err = pskb_expand_head(e->skb, 0, + nskb = skb_copy_expand(e->skb, 0, diff - skb_tailroom(e->skb), GFP_ATOMIC); - if (err) { + if (!nskb) { printk(KERN_WARNING "ip_queue: error " - "in mangle, dropping packet: %d\n", -err); - return err; + "in mangle, dropping packet\n"); + return -ENOMEM; } + kfree_skb(e->skb); + e->skb = nskb; } skb_put(e->skb, diff); } --- linux-2.6.24.orig/net/ipv4/netfilter/arpt_mangle.c +++ linux-2.6.24/net/ipv4/netfilter/arpt_mangle.c @@ -19,7 +19,7 @@ unsigned char *arpptr; int pln, hln; - if (skb_make_writable(skb, skb->len)) + if (!skb_make_writable(skb, skb->len)) return NF_DROP; arp = arp_hdr(skb); --- linux-2.6.24.orig/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ linux-2.6.24/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -231,6 +231,11 @@ } } } + + /* don't trust len bigger than ctx buffer */ + if (*len > ctx->end - ctx->pointer) + return 0; + return 1; } @@ -249,6 +254,10 @@ if (!asn1_length_decode(ctx, &def, &len)) return 0; + /* primitive shall be definite, indefinite shall be constructed */ + if (*con == ASN1_PRI && !def) + return 0; + if (def) *eoc = ctx->pointer + len; else @@ -429,10 +438,15 @@ unsigned int *len) { unsigned long subid; - unsigned int size; unsigned long *optr; + size_t size; size = eoc - ctx->pointer + 1; + + /* first subid actually encodes first two subids */ + if (size < 2 || size > ULONG_MAX/sizeof(unsigned long)) + return 0; + *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); if (*oid == NULL) { if (net_ratelimit()) --- linux-2.6.24.orig/net/ipv4/tcp.c +++ linux-2.6.24/net/ipv4/tcp.c @@ -583,7 +583,7 @@ if (!(psize -= copy)) goto out; - if (skb->len < mss_now || (flags & MSG_OOB)) + if (skb->len < size_goal || (flags & MSG_OOB)) continue; if (forced_push(tp)) { @@ -829,7 +829,7 @@ if ((seglen -= copy) == 0 && iovlen == 0) goto out; - if (skb->len < mss_now || (flags & MSG_OOB)) + if (skb->len < size_goal || (flags & MSG_OOB)) continue; if (forced_push(tp)) { --- linux-2.6.24.orig/net/ipv4/ip_output.c +++ linux-2.6.24/net/ipv4/ip_output.c @@ -462,6 +462,7 @@ if (skb_shinfo(skb)->frag_list) { struct sk_buff *frag; int first_len = skb_pagelen(skb); + int truesizes = 0; if (first_len - hlen > mtu || ((first_len - hlen) & 7) || @@ -485,7 +486,7 @@ sock_hold(skb->sk); frag->sk = skb->sk; frag->destructor = sock_wfree; - skb->truesize -= frag->truesize; + truesizes += frag->truesize; } } @@ -496,6 +497,7 @@ frag = skb_shinfo(skb)->frag_list; skb_shinfo(skb)->frag_list = NULL; skb->data_len = first_len - skb_headlen(skb); + skb->truesize -= truesizes; skb->len = first_len; iph->tot_len = htons(first_len); iph->frag_off = htons(IP_MF); --- linux-2.6.24.orig/net/ipv4/sysctl_net_ipv4.c +++ linux-2.6.24/net/ipv4/sysctl_net_ipv4.c @@ -248,7 +248,7 @@ tcp_get_available_congestion_control(tbl.data, tbl.maxlen); ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen); - if (ret == 0 && newval && newlen) + if (ret == 1 && newval && newlen) ret = tcp_set_allowed_congestion_control(tbl.data); kfree(tbl.data); --- linux-2.6.24.orig/net/netrom/af_netrom.c +++ linux-2.6.24/net/netrom/af_netrom.c @@ -840,6 +840,7 @@ sax->fsa_ax25.sax25_family = AF_NETROM; sax->fsa_ax25.sax25_ndigis = 1; sax->fsa_ax25.sax25_call = nr->user_addr; + memset(sax->fsa_digipeater, 0, sizeof(sax->fsa_digipeater)); sax->fsa_digipeater[0] = nr->dest_addr; *uaddr_len = sizeof(struct full_sockaddr_ax25); } else { @@ -1074,7 +1075,13 @@ SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n"); - /* Build a packet */ + /* Build a packet - the conventional user limit is 236 bytes. We can + do ludicrously large NetROM frames but must not overflow */ + if (len > 65536) { + err = -EMSGSIZE; + goto out; + } + SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n"); size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN; --- linux-2.6.24.orig/net/llc/af_llc.c +++ linux-2.6.24/net/llc/af_llc.c @@ -155,6 +155,9 @@ struct sock *sk; int rc = -ESOCKTNOSUPPORT; + if (!capable(CAP_NET_RAW)) + return -EPERM; + if (net != &init_net) return -EAFNOSUPPORT; @@ -914,6 +917,7 @@ struct llc_sock *llc = llc_sk(sk); int rc = 0; + memset(&sllc, 0, sizeof(sllc)); lock_sock(sk); if (sock_flag(sk, SOCK_ZAPPED)) goto out; --- linux-2.6.24.orig/net/econet/af_econet.c +++ linux-2.6.24/net/econet/af_econet.c @@ -520,6 +520,7 @@ if (peer) return -EOPNOTSUPP; + memset(sec, 0, sizeof(*sec)); mutex_lock(&econet_mutex); sk = sock->sk; --- linux-2.6.24.orig/net/ax25/ax25_out.c +++ linux-2.6.24/net/ax25/ax25_out.c @@ -117,6 +117,12 @@ unsigned char *p; int frontlen, len, fragno, ka9qfrag, first = 1; + if (paclen < 16) { + WARN_ON_ONCE(1); + kfree_skb(skb); + return; + } + if ((skb->len - 1) > paclen) { if (*skb->data == AX25_P_TEXT) { skb_pull(skb, 1); /* skip PID */ @@ -251,8 +257,6 @@ if (start == end) return; - ax25->vs = start; - /* * Transmit data until either we're out of data to send or * the window is full. Send a poll on the final I frame if @@ -261,8 +265,13 @@ /* * Dequeue the frame and copy it. + * Check for race with ax25_clear_queues(). */ skb = skb_dequeue(&ax25->write_queue); + if (!skb) + return; + + ax25->vs = start; do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { --- linux-2.6.24.orig/net/ax25/af_ax25.c +++ linux-2.6.24/net/ax25/af_ax25.c @@ -541,7 +541,7 @@ if (level != SOL_AX25) return -ENOPROTOOPT; - if (optlen < sizeof(int)) + if (optlen < (int)sizeof(int)) return -EINVAL; if (get_user(opt, (int __user *)optval)) --- linux-2.6.24.orig/net/core/scm.c +++ linux-2.6.24/net/core/scm.c @@ -75,6 +75,7 @@ if (!fpl) return -ENOMEM; *fplp = fpl; + INIT_LIST_HEAD(&fpl->list); fpl->count = 0; } fpp = &fpl->fp[fpl->count]; @@ -106,9 +107,25 @@ if (fpl) { scm->fp = NULL; - for (i=fpl->count-1; i>=0; i--) - fput(fpl->fp[i]); - kfree(fpl); + if (current->scm_work_list) { + list_add_tail(&fpl->list, current->scm_work_list); + } else { + LIST_HEAD(work_list); + + current->scm_work_list = &work_list; + + list_add(&fpl->list, &work_list); + while (!list_empty(&work_list)) { + fpl = list_first_entry(&work_list, struct scm_fp_list, list); + + list_del(&fpl->list); + for (i=fpl->count-1; i>=0; i--) + fput(fpl->fp[i]); + kfree(fpl); + } + + current->scm_work_list = NULL; + } } } @@ -284,6 +301,7 @@ new_fpl = kmalloc(sizeof(*fpl), GFP_KERNEL); if (new_fpl) { + INIT_LIST_HEAD(&new_fpl->list); for (i=fpl->count-1; i>=0; i--) get_file(fpl->fp[i]); memcpy(new_fpl, fpl, sizeof(*fpl)); --- linux-2.6.24.orig/net/core/skbuff.c +++ linux-2.6.24/net/core/skbuff.c @@ -2215,6 +2215,34 @@ return elt; } +/** + * skb_partial_csum_set - set up and verify partial csum values for packet + * @skb: the skb to set + * @start: the number of bytes after skb->data to start checksumming. + * @off: the offset from start to place the checksum. + * + * For untrusted partially-checksummed packets, we need to make sure the values + * for skb->csum_start and skb->csum_offset are valid so we don't oops. + * + * This function checks and sets those values and skb->ip_summed: if this + * returns false you should drop the packet. + */ +bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off) +{ + if (unlikely(start > skb->len - 2) || + unlikely((int)start + off > skb->len - 2)) { + if (net_ratelimit()) + printk(KERN_WARNING + "bad partial csum: csum=%u/%u len=%u\n", + start, off, skb->len); + return false; + } + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum_start = skb_headroom(skb) + start; + skb->csum_offset = off; + return true; +} + EXPORT_SYMBOL(___pskb_trim); EXPORT_SYMBOL(__kfree_skb); EXPORT_SYMBOL(kfree_skb); @@ -2251,3 +2279,4 @@ EXPORT_SYMBOL_GPL(skb_to_sgvec); EXPORT_SYMBOL_GPL(skb_cow_data); +EXPORT_SYMBOL_GPL(skb_partial_csum_set); --- linux-2.6.24.orig/net/core/netpoll.c +++ linux-2.6.24/net/core/netpoll.c @@ -219,10 +219,12 @@ while (clist != NULL) { struct sk_buff *skb = clist; clist = clist->next; - if (skb->destructor) + if (skb->destructor) { + atomic_inc(&skb->users); dev_kfree_skb_any(skb); /* put this one back */ - else + } else { __kfree_skb(skb); + } } } --- linux-2.6.24.orig/net/core/sock.c +++ linux-2.6.24/net/core/sock.c @@ -691,6 +691,8 @@ if (len < 0) return -EINVAL; + v.val = 0; + switch(optname) { case SO_DEBUG: v.val = sock_flag(sk, SOCK_DBG); --- linux-2.6.24.orig/net/core/dev.c +++ linux-2.6.24/net/core/dev.c @@ -1068,8 +1068,6 @@ */ call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); - dev_deactivate(dev); - clear_bit(__LINK_STATE_START, &dev->state); /* Synchronize to scheduled poll. We cannot touch poll list, @@ -1080,6 +1078,8 @@ */ smp_mb__after_clear_bit(); /* Commit netif_running(). */ + dev_deactivate(dev); + /* * Call the device specific close. This cannot fail. * Only if device is UP @@ -2906,7 +2906,7 @@ } } - da = kmalloc(sizeof(*da), GFP_ATOMIC); + da = kzalloc(sizeof(*da), GFP_ATOMIC); if (da == NULL) return -ENOMEM; memcpy(da->da_addr, addr, alen); @@ -3240,7 +3240,7 @@ return -EOPNOTSUPP; case SIOCADDMULTI: - if (!dev->set_multicast_list || + if ((!dev->set_multicast_list && !dev->set_rx_mode) || ifr->ifr_hwaddr.sa_family != AF_UNSPEC) return -EINVAL; if (!netif_device_present(dev)) @@ -3249,7 +3249,7 @@ dev->addr_len, 1); case SIOCDELMULTI: - if (!dev->set_multicast_list || + if ((!dev->set_multicast_list && !dev->set_rx_mode) || ifr->ifr_hwaddr.sa_family != AF_UNSPEC) return -EINVAL; if (!netif_device_present(dev)) --- linux-2.6.24.orig/net/8021q/vlan.c +++ linux-2.6.24/net/8021q/vlan.c @@ -326,7 +326,7 @@ int subclass = 0; /* IFF_BROADCAST|IFF_MULTICAST; ??? */ - dev->flags = real_dev->flags & ~IFF_UP; + dev->flags = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI); dev->iflink = real_dev->ifindex; dev->state = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))) | --- linux-2.6.24.orig/net/appletalk/aarp.c +++ linux-2.6.24/net/appletalk/aarp.c @@ -598,7 +598,7 @@ /* Non ELAP we cannot do. */ if (dev->type != ARPHRD_ETHER) - return -1; + goto free_it; skb->dev = dev; skb->protocol = htons(ETH_P_ATALK); @@ -633,7 +633,7 @@ if (!a) { /* Whoops slipped... good job it's an unreliable protocol 8) */ write_unlock_bh(&aarp_lock); - return -1; + goto free_it; } /* Set up the queue */ @@ -662,15 +662,21 @@ write_unlock_bh(&aarp_lock); /* Tell the ddp layer we have taken over for this frame. */ - return 0; + goto sent; sendit: if (skb->sk) skb->priority = skb->sk->sk_priority; - dev_queue_xmit(skb); + if (dev_queue_xmit(skb)) + goto drop; sent: - return 1; + return NET_XMIT_SUCCESS; +free_it: + kfree_skb(skb); +drop: + return NET_XMIT_DROP; } +EXPORT_SYMBOL(aarp_send_ddp); /* * An entry in the aarp unresolved queue has become resolved. Send --- linux-2.6.24.orig/net/appletalk/ddp.c +++ linux-2.6.24/net/appletalk/ddp.c @@ -1246,6 +1246,7 @@ return -ENOBUFS; *uaddr_len = sizeof(struct sockaddr_at); + memset(&sat.sat_zero, 0, sizeof(sat.sat_zero)); if (peer) { if (sk->sk_state != TCP_ESTABLISHED) @@ -1277,8 +1278,10 @@ struct net_device_stats *stats; /* This needs to be able to handle ipddp"N" devices */ - if (!dev) - return -ENODEV; + if (!dev) { + kfree_skb(skb); + return NET_RX_DROP; + } skb->protocol = htons(ETH_P_IP); skb_pull(skb, 13); @@ -1288,8 +1291,7 @@ stats = dev->priv; stats->rx_packets++; stats->rx_bytes += skb->len + 13; - netif_rx(skb); /* Send the SKB up to a higher place. */ - return 0; + return netif_rx(skb); /* Send the SKB up to a higher place. */ } #else /* make it easy for gcc to optimize this test out, i.e. kill the code */ @@ -1297,9 +1299,8 @@ #define handle_ip_over_ddp(skb) 0 #endif -static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev, - struct ddpehdr *ddp, __u16 len_hops, - int origlen) +static int atalk_route_packet(struct sk_buff *skb, struct net_device *dev, + struct ddpehdr *ddp, __u16 len_hops, int origlen) { struct atalk_route *rt; struct atalk_addr ta; @@ -1366,8 +1367,6 @@ /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */ struct sk_buff *nskb = skb_realloc_headroom(skb, 32); kfree_skb(skb); - if (!nskb) - goto out; skb = nskb; } else skb = skb_unshare(skb, GFP_ATOMIC); @@ -1376,12 +1375,16 @@ * If the buffer didn't vanish into the lack of space bitbucket we can * send it. */ - if (skb && aarp_send_ddp(rt->dev, skb, &ta, NULL) == -1) - goto free_it; -out: - return; + if (skb == NULL) + goto drop; + + if (aarp_send_ddp(rt->dev, skb, &ta, NULL) == NET_XMIT_DROP) + return NET_RX_DROP; + return NET_XMIT_SUCCESS; free_it: kfree_skb(skb); +drop: + return NET_RX_DROP; } /** @@ -1455,8 +1458,7 @@ /* Not ours, so we route the packet via the correct * AppleTalk iface */ - atalk_route_packet(skb, dev, ddp, len_hops, origlen); - goto out; + return atalk_route_packet(skb, dev, ddp, len_hops, origlen); } /* if IP over DDP is not selected this code will be optimized out */ @@ -1663,10 +1665,10 @@ if (skb2) { loopback = 1; SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk); - if (aarp_send_ddp(dev, skb2, - &usat->sat_addr, NULL) == -1) - kfree_skb(skb2); - /* else queued/sent above in the aarp queue */ + /* + * If it fails it is queued/sent above in the aarp queue + */ + aarp_send_ddp(dev, skb2, &usat->sat_addr, NULL); } } @@ -1696,9 +1698,12 @@ usat = &gsat; } - if (aarp_send_ddp(dev, skb, &usat->sat_addr, NULL) == -1) - kfree_skb(skb); - /* else queued/sent above in the aarp queue */ + /* + * If it fails it is queued/sent above in the aarp queue + */ + aarp_send_ddp(dev, skb, &usat->sat_addr, NULL); + + } SOCK_DEBUG(sk, "SK %p: Done write (%Zd).\n", sk, len); @@ -1877,7 +1882,6 @@ static unsigned char ddp_snap_id[] = { 0x08, 0x00, 0x07, 0x80, 0x9B }; /* Export symbols for use by drivers when AppleTalk is a module */ -EXPORT_SYMBOL(aarp_send_ddp); EXPORT_SYMBOL(atrtr_get_dev); EXPORT_SYMBOL(atalk_find_dev_addr); --- linux-2.6.24.orig/net/unix/af_unix.c +++ linux-2.6.24/net/unix/af_unix.c @@ -839,7 +839,7 @@ */ mode = S_IFSOCK | (SOCK_INODE(sock)->i_mode & ~current->fs->umask); - err = vfs_mknod(nd.dentry->d_inode, dentry, mode, 0); + err = vfs_mknod(nd.dentry->d_inode, dentry, nd.mnt, mode, 0); if (err) goto out_mknod_dput; mutex_unlock(&nd.dentry->d_inode->i_mutex); @@ -1071,6 +1071,8 @@ err = -ECONNREFUSED; if (other->sk_state != TCP_LISTEN) goto out_unlock; + if (other->sk_shutdown & RCV_SHUTDOWN) + goto out_unlock; if (skb_queue_len(&other->sk_receive_queue) > other->sk_max_ack_backlog) { @@ -1311,14 +1313,23 @@ sock_wfree(skb); } -static void unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) +static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) { int i; + + /* + * Need to duplicate file references for the sake of garbage + * collection. Otherwise a socket in the fps might become a + * candidate for GC while the skb is not yet queued. + */ + UNIXCB(skb).fp = scm_fp_dup(scm->fp); + if (!UNIXCB(skb).fp) + return -ENOMEM; + for (i=scm->fp->count-1; i>=0; i--) unix_inflight(scm->fp->fp[i]); - UNIXCB(skb).fp = scm->fp; skb->destructor = unix_destruct_fds; - scm->fp = NULL; + return 0; } /* @@ -1342,6 +1353,7 @@ if (NULL == siocb->scm) siocb->scm = &tmp_scm; + wait_for_unix_gc(); err = scm_send(sock, msg, siocb->scm); if (err < 0) return err; @@ -1376,8 +1388,11 @@ goto out; memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); - if (siocb->scm->fp) - unix_attach_fds(siocb->scm, skb); + if (siocb->scm->fp) { + err = unix_attach_fds(siocb->scm, skb); + if (err) + goto out_free; + } unix_get_secdata(siocb->scm, skb); skb_reset_transport_header(skb); @@ -1491,6 +1506,7 @@ if (NULL == siocb->scm) siocb->scm = &tmp_scm; + wait_for_unix_gc(); err = scm_send(sock, msg, siocb->scm); if (err < 0) return err; @@ -1548,8 +1564,13 @@ size = min_t(int, size, skb_tailroom(skb)); memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); - if (siocb->scm->fp) - unix_attach_fds(siocb->scm, skb); + if (siocb->scm->fp) { + err = unix_attach_fds(siocb->scm, skb); + if (err) { + kfree_skb(skb); + goto out_err; + } + } if ((err = memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) != 0) { kfree_skb(skb); --- linux-2.6.24.orig/net/unix/garbage.c +++ linux-2.6.24/net/unix/garbage.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include @@ -91,6 +92,7 @@ static LIST_HEAD(gc_inflight_list); static LIST_HEAD(gc_candidates); static DEFINE_SPINLOCK(unix_gc_lock); +static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait); unsigned int unix_tot_inflight; @@ -186,8 +188,17 @@ */ struct sock *sk = unix_get_socket(*fp++); if (sk) { - hit = true; - func(unix_sk(sk)); + struct unix_sock *u = unix_sk(sk); + + /* + * Ignore non-candidates, they could + * have been added to the queues after + * starting the garbage collection + */ + if (u->gc_candidate) { + hit = true; + func(u); + } } } if (hit && hitlist != NULL) { @@ -249,24 +260,29 @@ { atomic_inc(&u->inflight); /* - * If this is still a candidate, move it to the end of the - * list, so that it's checked even if it was already passed - * over + * If this still might be part of a cycle, move it to the end + * of the list, so that it's checked even if it was already + * passed over */ - if (u->gc_candidate) + if (u->gc_maybe_cycle) list_move_tail(&u->link, &gc_candidates); } -/* The external entry point: unix_gc() */ +static bool gc_in_progress = false; -void unix_gc(void) +void wait_for_unix_gc(void) { - static bool gc_in_progress = false; + wait_event(unix_gc_wait, gc_in_progress == false); +} +/* The external entry point: unix_gc() */ +void unix_gc(void) +{ struct unix_sock *u; struct unix_sock *next; struct sk_buff_head hitlist; struct list_head cursor; + LIST_HEAD(not_cycle_list); spin_lock(&unix_gc_lock); @@ -282,10 +298,14 @@ * * Holding unix_gc_lock will protect these candidates from * being detached, and hence from gaining an external - * reference. This also means, that since there are no - * possible receivers, the receive queues of these sockets are - * static during the GC, even though the dequeue is done - * before the detach without atomicity guarantees. + * reference. Since there are no possible receivers, all + * buffers currently on the candidates' queues stay there + * during the garbage collection. + * + * We also know that no new candidate can be added onto the + * receive queues. Other, non candidate sockets _can_ be + * added to queue, so we must make sure only to touch + * candidates. */ list_for_each_entry_safe(u, next, &gc_inflight_list, link) { int total_refs; @@ -299,6 +319,7 @@ if (total_refs == inflight_refs) { list_move_tail(&u->link, &gc_candidates); u->gc_candidate = 1; + u->gc_maybe_cycle = 1; } } @@ -325,14 +346,24 @@ list_move(&cursor, &u->link); if (atomic_read(&u->inflight) > 0) { - list_move_tail(&u->link, &gc_inflight_list); - u->gc_candidate = 0; + list_move_tail(&u->link, ¬_cycle_list); + u->gc_maybe_cycle = 0; scan_children(&u->sk, inc_inflight_move_tail, NULL); } } list_del(&cursor); /* + * not_cycle_list contains those sockets which do not make up a + * cycle. Restore these to the inflight list. + */ + while (!list_empty(¬_cycle_list)) { + u = list_entry(not_cycle_list.next, struct unix_sock, link); + u->gc_candidate = 0; + list_move_tail(&u->link, &gc_inflight_list); + } + + /* * Now gc_candidates contains only garbage. Restore original * inflight counters for these as well, and remove the skbuffs * which are creating the cycle(s). @@ -351,6 +382,7 @@ /* All candidates should have been detached by now. */ BUG_ON(!list_empty(&gc_candidates)); gc_in_progress = false; + wake_up(&unix_gc_wait); out: spin_unlock(&unix_gc_lock); --- linux-2.6.24.orig/net/socket.c +++ linux-2.6.24/net/socket.c @@ -688,7 +688,7 @@ if (more) flags |= MSG_MORE; - return sock->ops->sendpage(sock, page, offset, size, flags); + return kernel_sendpage(sock, page, offset, size, flags); } static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, --- linux-2.6.24.orig/net/netfilter/nfnetlink_log.c +++ linux-2.6.24/net/netfilter/nfnetlink_log.c @@ -594,7 +594,7 @@ /* FIXME: do we want to make the size calculation conditional based on * what is actually present? way more branches and checks, but more * memory efficient... */ - size = NLMSG_ALIGN(sizeof(struct nfgenmsg)) + size = NLMSG_SPACE(sizeof(struct nfgenmsg)) + nla_total_size(sizeof(struct nfulnl_msg_packet_hdr)) + nla_total_size(sizeof(u_int32_t)) /* ifindex */ + nla_total_size(sizeof(u_int32_t)) /* ifindex */ --- linux-2.6.24.orig/net/netfilter/nfnetlink_queue.c +++ linux-2.6.24/net/netfilter/nfnetlink_queue.c @@ -353,7 +353,7 @@ QDEBUG("entered\n"); - size = NLMSG_ALIGN(sizeof(struct nfgenmsg)) + size = NLMSG_SPACE(sizeof(struct nfgenmsg)) + nla_total_size(sizeof(struct nfqnl_msg_packet_hdr)) + nla_total_size(sizeof(u_int32_t)) /* ifindex */ + nla_total_size(sizeof(u_int32_t)) /* ifindex */ @@ -616,8 +616,8 @@ static int nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e) { + struct sk_buff *nskb; int diff; - int err; diff = data_len - e->skb->len; if (diff < 0) { @@ -627,14 +627,16 @@ if (data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - err = pskb_expand_head(e->skb, 0, + nskb = skb_copy_expand(e->skb, 0, diff - skb_tailroom(e->skb), GFP_ATOMIC); - if (err) { + if (!nskb) { printk(KERN_WARNING "nf_queue: OOM " "in mangle, dropping packet\n"); - return err; + return -ENOMEM; } + kfree_skb(e->skb); + e->skb = nskb; } skb_put(e->skb, diff); } --- linux-2.6.24.orig/net/netfilter/nf_conntrack_proto_tcp.c +++ linux-2.6.24/net/netfilter/nf_conntrack_proto_tcp.c @@ -135,7 +135,7 @@ * CLOSE_WAIT: ACK seen (after FIN) * LAST_ACK: FIN seen (after FIN) * TIME_WAIT: last ACK seen - * CLOSE: closed connection + * CLOSE: closed connection (RST) * * LISTEN state is not used. * @@ -834,8 +834,21 @@ case TCP_CONNTRACK_SYN_SENT: if (old_state < TCP_CONNTRACK_TIME_WAIT) break; - if ((conntrack->proto.tcp.seen[!dir].flags & - IP_CT_TCP_FLAG_CLOSE_INIT) + /* RFC 1122: "When a connection is closed actively, + * it MUST linger in TIME-WAIT state for a time 2xMSL + * (Maximum Segment Lifetime). However, it MAY accept + * a new SYN from the remote TCP to reopen the connection + * directly from TIME-WAIT state, if..." + * We ignore the conditions because we are in the + * TIME-WAIT state anyway. + * + * Handle aborted connections: we and the server + * think there is an existing connection but the client + * aborts it and starts a new one. + */ + if (((conntrack->proto.tcp.seen[dir].flags + | conntrack->proto.tcp.seen[!dir].flags) + & IP_CT_TCP_FLAG_CLOSE_INIT) || (conntrack->proto.tcp.last_dir == dir && conntrack->proto.tcp.last_index == TCP_RST_SET)) { /* Attempt to reopen a closed/aborted connection. @@ -848,18 +861,25 @@ } /* Fall through */ case TCP_CONNTRACK_IGNORE: - /* Ignored packets: + /* Ignored packets: + * + * Our connection entry may be out of sync, so ignore + * packets which may signal the real connection between + * the client and the server. * * a) SYN in ORIGINAL * b) SYN/ACK in REPLY * c) ACK in reply direction after initial SYN in original. + * + * If the ignored packet is invalid, the receiver will send + * a RST we'll catch below. */ if (index == TCP_SYNACK_SET && conntrack->proto.tcp.last_index == TCP_SYN_SET && conntrack->proto.tcp.last_dir != dir && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) { - /* This SYN/ACK acknowledges a SYN that we earlier + /* b) This SYN/ACK acknowledges a SYN that we earlier * ignored as invalid. This means that the client and * the server are both in sync, while the firewall is * not. We kill this session and block the SYN/ACK so @@ -884,7 +904,7 @@ write_unlock_bh(&tcp_lock); if (LOG_INVALID(IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, - "nf_ct_tcp: invalid packed ignored "); + "nf_ct_tcp: invalid packet ignored "); return NF_ACCEPT; case TCP_CONNTRACK_MAX: /* Invalid packet */ @@ -938,8 +958,7 @@ conntrack->proto.tcp.state = new_state; if (old_state != new_state - && (new_state == TCP_CONNTRACK_FIN_WAIT - || new_state == TCP_CONNTRACK_CLOSE)) + && new_state == TCP_CONNTRACK_FIN_WAIT) conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; timeout = conntrack->proto.tcp.retrans >= nf_ct_tcp_max_retrans && *tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans --- linux-2.6.24.orig/net/netfilter/xt_time.c +++ linux-2.6.24/net/netfilter/xt_time.c @@ -95,8 +95,11 @@ */ r->dse = time / 86400; - /* 1970-01-01 (w=0) was a Thursday (4). */ - r->weekday = (4 + r->dse) % 7; + /* + * 1970-01-01 (w=0) was a Thursday (4). + * -1 and +1 map Sunday properly onto 7. + */ + r->weekday = (4 + r->dse - 1) % 7 + 1; } static void localtime_3(struct xtm *r, time_t time) --- linux-2.6.24.orig/net/dccp/feat.c +++ linux-2.6.24/net/dccp/feat.c @@ -30,7 +30,7 @@ } if (!dccp_feat_is_valid_length(type, feature, len)) { DCCP_WARN("invalid length %d\n", len); - return 1; + return -EINVAL; } /* XXX add further sanity checks */ --- linux-2.6.24.orig/net/dccp/proto.c +++ linux-2.6.24/net/dccp/proto.c @@ -458,6 +458,11 @@ if (copy_from_user(&opt, optval, sizeof(opt))) return -EFAULT; + /* + * rfc4340: 6.1. Change Options + */ + if (opt.dccpsf_len < 1) + return -EINVAL; val = kmalloc(opt.dccpsf_len, GFP_KERNEL); if (!val) --- linux-2.6.24.orig/net/rfkill/rfkill-input.c +++ linux-2.6.24/net/rfkill/rfkill-input.c @@ -84,6 +84,7 @@ static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN); static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH); static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB); +static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX); static void rfkill_event(struct input_handle *handle, unsigned int type, unsigned int code, int down) @@ -99,6 +100,9 @@ case KEY_UWB: rfkill_schedule_toggle(&rfkill_uwb); break; + case KEY_WIMAX: + rfkill_schedule_toggle(&rfkill_wimax); + break; default: break; } @@ -159,6 +163,11 @@ .evbit = { BIT_MASK(EV_KEY) }, .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) }, }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT_MASK(EV_KEY) }, + .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) }, + }, { } }; --- linux-2.6.24.orig/net/rfkill/rfkill.c +++ linux-2.6.24/net/rfkill/rfkill.c @@ -126,6 +126,9 @@ case RFKILL_TYPE_UWB: type = "ultrawideband"; break; + case RFKILL_TYPE_WIMAX: + type = "wimax"; + break; default: BUG(); } @@ -229,7 +232,7 @@ struct rfkill *rfkill = to_rfkill(dev); if (dev->power.power_state.event != state.event) { - if (state.event == PM_EVENT_SUSPEND) { + if (state.event & PM_EVENT_SLEEP) { mutex_lock(&rfkill->mutex); if (rfkill->state == RFKILL_STATE_ON) --- linux-2.6.24.orig/net/x25/af_x25.c +++ linux-2.6.24/net/x25/af_x25.c @@ -1042,6 +1042,12 @@ sx25.sx25_addr = x25->dest_addr; } + /* Sanity check the packet size */ + if (len > 65535) { + rc = -EMSGSIZE; + goto out; + } + SOCK_DEBUG(sk, "x25_sendmsg: sendto: Addresses built.\n"); /* Build a packet */ --- linux-2.6.24.orig/net/atm/svc.c +++ linux-2.6.24/net/atm/svc.c @@ -293,7 +293,10 @@ error = -EINVAL; goto out; } - vcc_insert_socket(sk); + if (test_bit(ATM_VF_LISTEN, &vcc->flags)) { + error = -EADDRINUSE; + goto out; + } set_bit(ATM_VF_WAITING, &vcc->flags); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); @@ -307,6 +310,7 @@ goto out; } set_bit(ATM_VF_LISTEN,&vcc->flags); + vcc_insert_socket(sk); sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; error = -sk->sk_err; out: --- linux-2.6.24.orig/net/sunrpc/rpcb_clnt.c +++ linux-2.6.24/net/sunrpc/rpcb_clnt.c @@ -112,9 +112,9 @@ u32 r_vers; u32 r_prot; unsigned short r_port; - char * r_netid; - char r_addr[RPCB_MAXADDRLEN]; - char * r_owner; + const char * r_netid; + const char * r_addr; + const char * r_owner; }; static struct rpc_procinfo rpcb_procedures2[]; @@ -295,6 +295,28 @@ } EXPORT_SYMBOL_GPL(rpcb_getport_sync); +/* + * In the case where rpc clients have been cloned, we want to make + * sure that we use the program number/version etc of the actual + * owner of the xprt. To do so, we walk back up the tree of parents + * to find whoever created the transport and/or whoever has the + * autobind flag set. + */ +static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) +{ + struct rpc_clnt *parent = clnt->cl_parent; + + while (parent != clnt) { + if (parent->cl_xprt != clnt->cl_xprt) + break; + if (clnt->cl_autobind) + break; + clnt = parent; + parent = parent->cl_parent; + } + return clnt; +} + /** * rpcb_getport_async - obtain the port for a given RPC service on a given host * @task: task that is waiting for portmapper request @@ -304,9 +326,9 @@ */ void rpcb_getport_async(struct rpc_task *task) { - struct rpc_clnt *clnt = task->tk_client; + struct rpc_clnt *clnt; int bind_version; - struct rpc_xprt *xprt = task->tk_xprt; + struct rpc_xprt *xprt; struct rpc_clnt *rpcb_clnt; static struct rpcbind_args *map; struct rpc_task *child; @@ -314,13 +336,13 @@ int status; struct rpcb_info *info; + clnt = rpcb_find_transport_owner(task->tk_client); + xprt = clnt->cl_xprt; + dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", task->tk_pid, __FUNCTION__, clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); - /* Autobind on cloned rpc clients is discouraged */ - BUG_ON(clnt->cl_parent != clnt); - if (xprt_test_and_set_binding(xprt)) { status = -EAGAIN; /* tell caller to check again */ dprintk("RPC: %5u %s: waiting for another binder\n", @@ -390,9 +412,7 @@ map->r_port = 0; map->r_xprt = xprt_get(xprt); map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); - memcpy(map->r_addr, - rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR), - sizeof(map->r_addr)); + map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR); map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map); @@ -403,9 +423,9 @@ task->tk_pid, __FUNCTION__); goto bailout; } - rpc_put_task(child); - task->tk_xprt->stat.bind_count++; + xprt->stat.bind_count++; + rpc_put_task(child); return; bailout: --- linux-2.6.24.orig/net/ipv6/ip6_output.c +++ linux-2.6.24/net/ipv6/ip6_output.c @@ -593,7 +593,7 @@ * or if the skb it not generated by a local socket. (This last * check should be redundant, but it's free.) */ - if (!np || np->pmtudisc >= IPV6_PMTUDISC_DO) { + if (!skb->local_df) { skb->dev = skb->dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS); @@ -609,6 +609,7 @@ if (skb_shinfo(skb)->frag_list) { int first_len = skb_pagelen(skb); + int truesizes = 0; if (first_len - hlen > mtu || ((first_len - hlen) & 7) || @@ -631,7 +632,7 @@ sock_hold(skb->sk); frag->sk = skb->sk; frag->destructor = sock_wfree; - skb->truesize -= frag->truesize; + truesizes += frag->truesize; } } @@ -662,6 +663,7 @@ first_len = skb_pagelen(skb); skb->data_len = first_len - skb_headlen(skb); + skb->truesize -= truesizes; skb->len = first_len; ipv6_hdr(skb)->payload_len = htons(first_len - sizeof(struct ipv6hdr)); @@ -1387,6 +1389,10 @@ tmp_skb->sk = NULL; } + /* Allow local fragmentation. */ + if (np->pmtudisc < IPV6_PMTUDISC_DO) + skb->local_df = 1; + ipv6_addr_copy(final_dst, &fl->fl6_dst); __skb_pull(skb, skb_network_header_len(skb)); if (opt && opt->opt_flen) --- linux-2.6.24.orig/net/ipv6/ip6_tunnel.c +++ linux-2.6.24/net/ipv6/ip6_tunnel.c @@ -550,6 +550,7 @@ ip_rt_put(rt); goto out; } + skb2->dst = (struct dst_entry *)rt; } else { ip_rt_put(rt); if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, --- linux-2.6.24.orig/net/ipv6/esp6.c +++ linux-2.6.24/net/ipv6/esp6.c @@ -155,7 +155,7 @@ int nfrags; int ret = 0; - if (!pskb_may_pull(skb, sizeof(*esph))) { + if (!pskb_may_pull(skb, sizeof(*esph) + esp->conf.ivlen)) { ret = -EINVAL; goto out; } --- linux-2.6.24.orig/net/ipv6/xfrm6_output.c +++ linux-2.6.24/net/ipv6/xfrm6_output.c @@ -34,7 +34,7 @@ if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; - if (skb->len > mtu) { + if (!skb->local_df && skb->len > mtu) { skb->dev = dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); ret = -EMSGSIZE; --- linux-2.6.24.orig/net/ipv6/addrconf.c +++ linux-2.6.24/net/ipv6/addrconf.c @@ -752,6 +752,7 @@ struct inet6_dev *idev = ifp->idev; struct in6_addr addr, *tmpaddr; unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp; + unsigned long regen_advance; int tmp_plen; int ret = 0; int max_addresses; @@ -812,8 +813,23 @@ tmp_tstamp = ifp->tstamp; spin_unlock_bh(&ifp->lock); + regen_advance = idev->cnf.regen_max_retry * + idev->cnf.dad_transmits * + idev->nd_parms->retrans_time / HZ; write_unlock(&idev->lock); + /* A temporary address is created only if this calculated Preferred + * Lifetime is greater than REGEN_ADVANCE time units. In particular, + * an implementation must not create a temporary address with a zero + * Preferred Lifetime. + */ + if (tmp_prefered_lft <= regen_advance) { + in6_ifa_put(ifp); + in6_dev_put(idev); + ret = -1; + goto out; + } + addr_flags = IFA_F_TEMPORARY; /* set in addrconf_prefix_rcv() */ if (ifp->flags & IFA_F_OPTIMISTIC) @@ -1817,6 +1833,9 @@ * lifetimes of an existing temporary address * when processing a Prefix Information Option. */ + if (ifp != ift->ifpub) + continue; + spin_lock(&ift->lock); flags = ift->flags; if (ift->valid_lft > valid_lft && --- linux-2.6.24.orig/net/ipv6/ipcomp6.c +++ linux-2.6.24/net/ipv6/ipcomp6.c @@ -64,6 +64,7 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) { + int nexthdr; int err = -ENOMEM; struct ip_comp_hdr *ipch; int plen, dlen; @@ -79,6 +80,8 @@ /* Remove ipcomp header and decompress original payload */ ipch = (void *)skb->data; + nexthdr = ipch->nexthdr; + skb->transport_header = skb->network_header + sizeof(*ipch); __skb_pull(skb, sizeof(*ipch)); @@ -108,7 +111,7 @@ skb->truesize += dlen - plen; __skb_put(skb, dlen - plen); skb_copy_to_linear_data(skb, scratch, dlen); - err = ipch->nexthdr; + err = nexthdr; out_put_cpu: put_cpu(); @@ -143,7 +146,9 @@ scratch = *per_cpu_ptr(ipcomp6_scratches, cpu); tfm = *per_cpu_ptr(ipcd->tfms, cpu); + local_bh_disable(); err = crypto_comp_compress(tfm, start, plen, scratch, &dlen); + local_bh_enable(); if (err || (dlen + sizeof(*ipch)) >= plen) { put_cpu(); goto out_ok; --- linux-2.6.24.orig/net/ipv6/netfilter/nf_conntrack_reasm.c +++ linux-2.6.24/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -147,7 +147,9 @@ static void nf_ct_frag6_evictor(void) { + local_bh_disable(); inet_frag_evictor(&nf_frags); + local_bh_enable(); } static void nf_ct_frag6_expire(unsigned long data) --- linux-2.6.24.orig/net/ipv6/netfilter/ip6_queue.c +++ linux-2.6.24/net/ipv6/netfilter/ip6_queue.c @@ -333,8 +333,8 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) { int diff; - int err; struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload; + struct sk_buff *nskb; if (v->data_len < sizeof(*user_iph)) return 0; @@ -346,14 +346,16 @@ if (v->data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - err = pskb_expand_head(e->skb, 0, + nskb = skb_copy_expand(e->skb, 0, diff - skb_tailroom(e->skb), GFP_ATOMIC); - if (err) { + if (!nskb) { printk(KERN_WARNING "ip6_queue: OOM " "in mangle, dropping packet\n"); - return err; + return -ENOMEM; } + kfree_skb(e->skb); + e->skb = nskb; } skb_put(e->skb, diff); } --- linux-2.6.24.orig/net/ipv6/anycast.c +++ linux-2.6.24/net/ipv6/anycast.c @@ -67,6 +67,7 @@ break; } read_unlock_bh(&idev->lock); + in6_dev_put(idev); } rcu_read_unlock(); return onlink; --- linux-2.6.24.orig/net/ipv6/sit.c +++ linux-2.6.24/net/ipv6/sit.c @@ -395,9 +395,9 @@ } icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - kfree_skb(skb); read_unlock(&ipip6_lock); out: + kfree_skb(skb); return 0; } --- linux-2.6.24.orig/debian/rules +++ linux-2.6.24/debian/rules @@ -0,0 +1,121 @@ +#!/usr/bin/make -f +# +# debian/rules for Ubuntu linux +# +# Use this however you want, just give credit where credit is due. +# +# Copyright (c) 2007 Ben Collins +# + +# dpkg-buildpackage passes options that are incomptatible +# with the kernel build. +unexport CFLAGS +unexport LDFLAGS + +# This is the debhelper compatability version to use. +export DH_COMPAT=4 +export LC_ALL=C +export SHELL=/bin/bash -e + +# Common variables for all architectures +include debian/rules.d/0-common-vars.mk + +# Pill in some arch specific stuff +include debian/rules.d/$(arch).mk + +# Maintainer targets +include debian/rules.d/1-maintainer.mk + +# Debian Build System targets +binary: binary-indep binary-arch + +build: build-arch build-indep + +clean: debian/control + dh_testdir + dh_testroot + dh_clean + + # d-i stuff + rm -rf modules kernel-versions package-list + rm -rf debian/d-i-$(arch) + + # normal build junk + rm -rf debian/abi/$(release)-$(revision) + rm -rf $(builddir) + rm -f $(stampdir)/stamp-* + rm -rf debian/linux-* + + # This gets rid of the d-i packages in control + cp -f debian/control.stub debian/control + +# Builds the image, arch headers and debug packages +include debian/rules.d/2-binary-arch.mk + +# Rules for building the udebs (debian-installer) +include debian/rules.d/5-udebs.mk + +# Builds the source, doc and linux-headers indep packages +include debian/rules.d/3-binary-indep.mk + +# Various checks to be performed on builds +include debian/rules.d/4-checks.mk + +# Custom binary images (universe/unsupported) +include debian/rules.d/6-binary-custom.mk \ + $(patsubst %,debian/binary-custom.d/%/rules,$(custom_flavours)) + +# Misc stuff +debian/control.stub: debian/d-i/kernel-versions.in \ + debian/scripts/control-create \ + debian/control.stub.in \ + debian/changelog \ + $(wildcard debian/control.d/*) \ + $(patsubst %,debian/binary-custom.d/%/vars,$(all_custom_flavours)) + for i in debian/d-i/kernel-versions.in debian/control.stub.in; do \ + new=`echo $$i | sed 's/\.in$$//'`; \ + cat $$i | sed -e 's/PKGVER/$(release)/g' -e 's/ABINUM/$(abinum)/g' > \ + $$new; \ + done + flavours="$(wildcard debian/control.d/vars.*) $(patsubst %,debian/binary-custom.d/%/vars,$(all_custom_flavours))";\ + for i in $$flavours; do \ + $(SHELL) debian/scripts/control-create $$i | \ + sed -e 's/PKGVER/$(release)/g' -e 's/ABINUM/$(abinum)/g' >>\ + debian/control.stub; \ + done + cp debian/control.stub debian/control + +.PHONY: debian/control +debian/control: debian/control.stub + rm -rf modules kernel-versions package-list + mkdir -p modules/$(arch)/ + cp debian/d-i/modules/* modules/$(arch)/ + cp debian/d-i/package-list debian/d-i/kernel-versions . + touch modules/$(arch)/kernel-image + + # Per flavour module lists + flavour_modules=`ls debian/d-i/modules.$(arch)-* 2>/dev/null` \ + || true; \ + if [ "$$flavour_modules" != "" ]; then \ + for flav in $$flavour_modules; do \ + name=`echo $$flav | sed 's/.*\/modules.$(arch)-//'`; \ + mkdir modules/$(arch)-$$name; \ + (cd debian/d-i/modules/; tar cf - `cat ../../../$$flav`) |\ + (cd modules/$(arch)-$$name/; tar xf -); \ + touch modules/$(arch)-$$name/kernel-image; \ + done; \ + fi + + # Remove unwanted stuff + if [ -r "debian/d-i/exclude-modules.$(arch)" ]; then \ + (cat debian/d-i/exclude-modules.$(arch); \ + ls modules/$(arch)/) | sort | uniq -d | \ + (cd modules/$(arch)/; xargs rm -f); \ + fi + + if [ ! -d modules/$(build_arch) ]; then \ + mkdir -p modules/$(build_arch); \ + cp modules/$(arch)/* modules/$(build_arch); \ + fi + + kernel-wedge gen-control > debian/control --- linux-2.6.24.orig/debian/d-i/exclude-modules.amd64 +++ linux-2.6.24/debian/d-i/exclude-modules.amd64 @@ -0,0 +1,3 @@ +efi-modules +cdrom-modules +fancontrol-modules --- linux-2.6.24.orig/debian/d-i/exclude-modules.lpia +++ linux-2.6.24/debian/d-i/exclude-modules.lpia @@ -0,0 +1,9 @@ +efi-modules +serial-modules +cdrom-modules +plip-modules +md-modules +pcmcia-storage-modules +nic-pcmcia-modules +pcmcia-modules +fancontrol-modules --- linux-2.6.24.orig/debian/d-i/kernel-versions +++ linux-2.6.24/debian/d-i/kernel-versions @@ -0,0 +1,15 @@ +# arch version flavour installedname suffix bdep +amd64 2.6.24-27 generic 2.6.24-27-generic - + +hppa 2.6.24-27 hppa32 2.6.24-27-hppa32 y +hppa 2.6.24-27 hppa64 2.6.24-27-hppa64 y + +i386 2.6.24-27 386 2.6.24-27-386 - +i386 2.6.24-27 generic 2.6.24-27-generic - + +ia64 2.6.24-27 itanium 2.6.24-27-itanium - + +powerpc 2.6.24-27 powerpc 2.6.24-27-powerpc - +powerpc 2.6.24-27 powerpc64-smp 2.6.24-27-powerpc64-smp - + +sparc 2.6.24-27 sparc64 2.6.24-27-sparc64 - --- linux-2.6.24.orig/debian/d-i/exclude-modules.i386 +++ linux-2.6.24/debian/d-i/exclude-modules.i386 @@ -0,0 +1,2 @@ +efi-modules +fancontrol-modules --- linux-2.6.24.orig/debian/d-i/exclude-modules.hppa +++ linux-2.6.24/debian/d-i/exclude-modules.hppa @@ -0,0 +1,11 @@ +firewire-core-modules +efi-modules +socket-modules +irda-modules +floppy-modules +fb-modules +acpi-modules +cdrom-modules +nfs-modules +nic-usb-modules +fancontrol-modules --- linux-2.6.24.orig/debian/d-i/package-list +++ linux-2.6.24/debian/d-i/package-list @@ -0,0 +1,180 @@ +Package: acpi-modules +Depends: kernel-image +Priority: standard +Description: Support for ACPI + +Package: efi-modules +Depends: kernel-image +Priority: standard +Description: EFI support + +Package: fat-modules +Depends: kernel-image +Priority: standard +Description: FAT filesystem support + This includes Windows FAT and VFAT support. + +Package: fb-modules +Depends: kernel-image +Priority: standard +Description: Framebuffer modules + +Package: firewire-core-modules +Depends: kernel-image, storage-core-modules +Priority: standard +Description: Firewire (IEEE-1394) Support + +Package: floppy-modules +Depends: kernel-image +Priority: standard +Description: Floppy driver support + +Package: fs-core-modules +Depends: kernel-image +Priority: standard +Provides: ext2-modules, ext3-modules, jfs-modules, reiserfs-modules, xfs-modules +Description: Base filesystem modules + This includes ext2, ext3, jfs, reiserfs and xfs. + +Package: fs-secondary-modules +Depends: kernel-image, fat-modules +Priority: standard +Provides: ntfs-modules, ufs-modules, hfs-modules, affs-modules +Description: Extra filesystem modules + This includes support for Windows NTFS, SysV UFS, MacOS HFS and HFSPlus and + Amiga AFFS. + +Package: ide-modules +Depends: kernel-image, storage-core-modules +Priority: standard +Description: IDE support + +Package: input-modules +Depends: kernel-image, usb-modules +Priority: standard +Description: Support for various input methods + +Package: ipv6-modules +Depends: kernel-image +Priority: standard +Description: Support for IPv6 networking + +Package: irda-modules +Depends: kernel-image, nic-shared-modules +Priority: standard +Description: Support for Infrared protocols + +Package: md-modules +Depends: kernel-image +Priority: standard +Description: Multi-device support (raid, device-mapper, lvm) + +Package: nic-modules +Depends: kernel-image, nic-shared-modules +Priority: standard +Description: Network interface support + +Package: nic-pcmcia-modules +Depends: kernel-image, nic-shared-modules, nic-modules +Priority: standard +Description: PCMCIA network interface support + +Package: nic-usb-modules +Depends: kernel-image, nic-shared-modules, usb-modules +Priority: standard +Description: USB network interface support + +Package: parport-modules +Depends: kernel-image +Priority: standard +Description: Parallel port support + +Package: pata-modules +Depends: kernel-image, storage-core-modules +Priority: standard +Description: PATA support modules + +Package: pcmcia-modules +Depends: kernel-image +Priority: standard +Description: PCMCIA Modules + +Package: pcmcia-storage-modules +Depends: kernel-image, scsi-modules +Priority: standard +Description: PCMCIA storage support + +Package: plip-modules +Depends: kernel-image, nic-shared-modules, parport-modules +Priority: standard +Description: PLIP (parallel port) networking support + +Package: ppp-modules +Depends: kernel-image, nic-shared-modules, serial-modules +Priority: standard +Description: PPP (serial port) networking support + +Package: sata-modules +Depends: kernel-image, storage-core-modules +Priority: standard +Description: SATA storage support + +Package: scsi-modules +Depends: kernel-image, storage-core-modules +Priority: standard +Description: SCSI storage support + +Package: serial-modules +Depends: kernel-image +Priority: standard +Description: Serial port support + +Package: socket-modules +Depends: kernel-image +Priority: standard +Description: Unix socket support + +Package: storage-core-modules +Depends: kernel-image +Priority: standard +Provides: loop-modules +Description: Core storage support + Includes core SCSI, LibATA, USB-Storage. Also includes related block + devices for CD, Disk and Tape medium (and IDE Floppy). + +Package: usb-modules +Depends: kernel-image, storage-core-modules +Priority: standard +Description: Core USB support + +Package: nfs-modules +Priority: standard +Depends: kernel-image +Description: NFS filesystem drivers + Includes the NFS client driver, and supporting modules. + +Package: block-modules +Priority: standard +Depends: kernel-image, storage-core-modules, parport-modules +Description: Block storage devices + This package contains the block storage devices, including DAC960 and + paraide. + +Package: message-modules +Priority: standard +Depends: kernel-image, storage-core-modules, scsi-modules +Description: Fusion and i2o storage modules + This package containes the fusion and i2o storage modules. + +Package: crypto-modules +Priority: extra +Depends: kernel-image +Description: crypto modules + This package contains crypto modules. + +Package: fancontrol-modules +Priority: standard +Depends: kernel-image +Description: Apple powermac fancontrol modules + Contains drivers for macintosh i2c bus as well as for the monitoring devices + connected to it. This allows to control the fans during installation. --- linux-2.6.24.orig/debian/d-i/kernel-versions.in +++ linux-2.6.24/debian/d-i/kernel-versions.in @@ -0,0 +1,15 @@ +# arch version flavour installedname suffix bdep +amd64 PKGVER-ABINUM generic PKGVER-ABINUM-generic - + +hppa PKGVER-ABINUM hppa32 PKGVER-ABINUM-hppa32 y +hppa PKGVER-ABINUM hppa64 PKGVER-ABINUM-hppa64 y + +i386 PKGVER-ABINUM 386 PKGVER-ABINUM-386 - +i386 PKGVER-ABINUM generic PKGVER-ABINUM-generic - + +ia64 PKGVER-ABINUM itanium PKGVER-ABINUM-itanium - + +powerpc PKGVER-ABINUM powerpc PKGVER-ABINUM-powerpc - +powerpc PKGVER-ABINUM powerpc64-smp PKGVER-ABINUM-powerpc64-smp - + +sparc PKGVER-ABINUM sparc64 PKGVER-ABINUM-sparc64 - --- linux-2.6.24.orig/debian/d-i/exclude-modules.ia64 +++ linux-2.6.24/debian/d-i/exclude-modules.ia64 @@ -0,0 +1,4 @@ +socket-modules +floppy-modules +cdrom-modules +fancontrol-modules --- linux-2.6.24.orig/debian/d-i/modules/fs-core-modules +++ linux-2.6.24/debian/d-i/modules/fs-core-modules @@ -0,0 +1,5 @@ +ext2 ? +ext3 ? +jfs ? +reiserfs ? +xfs ? --- linux-2.6.24.orig/debian/d-i/modules/plip-modules +++ linux-2.6.24/debian/d-i/modules/plip-modules @@ -0,0 +1 @@ +plip ? --- linux-2.6.24.orig/debian/d-i/modules/crypto-modules +++ linux-2.6.24/debian/d-i/modules/crypto-modules @@ -0,0 +1,9 @@ +aes_generic +blowfish +twofish +serpent +sha256_generic +cbc ? +ebc ? +crc32c ? +libcrc32c ? --- linux-2.6.24.orig/debian/d-i/modules/acpi-modules +++ linux-2.6.24/debian/d-i/modules/acpi-modules @@ -0,0 +1,2 @@ +fan ? +thermal ? --- linux-2.6.24.orig/debian/d-i/modules/ppp-modules +++ linux-2.6.24/debian/d-i/modules/ppp-modules @@ -0,0 +1,6 @@ +ppp_async ? +ppp_deflate ? +ppp_mppe ? +pppoe ? +pppox ? +ppp_synctty ? --- linux-2.6.24.orig/debian/d-i/modules/parport-modules +++ linux-2.6.24/debian/d-i/modules/parport-modules @@ -0,0 +1,3 @@ +parport ? +parport_pc ? +parport_sunbpp ? --- linux-2.6.24.orig/debian/d-i/modules/socket-modules +++ linux-2.6.24/debian/d-i/modules/socket-modules @@ -0,0 +1 @@ +af_packet ? --- linux-2.6.24.orig/debian/d-i/modules/fs-secondary-modules +++ linux-2.6.24/debian/d-i/modules/fs-secondary-modules @@ -0,0 +1,13 @@ +# Windows filesystems; fuse is needed for ntfs-3g. +fuse ? +ntfs ? + +# UFS (Unix SysV) +ufs ? + +# Mac HFS +hfs ? +hfsplus ? + +# Amiga fs ? +affs ? --- linux-2.6.24.orig/debian/d-i/modules/floppy-modules +++ linux-2.6.24/debian/d-i/modules/floppy-modules @@ -0,0 +1 @@ +floppy ? --- linux-2.6.24.orig/debian/d-i/modules/pcmcia-modules +++ linux-2.6.24/debian/d-i/modules/pcmcia-modules @@ -0,0 +1,8 @@ +i82092 ? +i82365 ? +pcmcia ? +pcmcia_core ? +pd6729 ? +rsrc_nonstatic ? +tcic ? +yenta_socket ? --- linux-2.6.24.orig/debian/d-i/modules/speakup-modules +++ linux-2.6.24/debian/d-i/modules/speakup-modules @@ -0,0 +1,16 @@ +speakup_keyhelp ? +speakupmain ? +speakup_acntpc ? +speakup_acntsa ? +speakup_apollo ? +speakup_audptr ? +speakup_bns ? +speakup_decext ? +speakup_decpc ? +speakup_dectlk ? +speakup_dtlk ? +speakup_keypc ? +speakup_ltlk ? +speakup_sftsyn ? +speakup_spkout ? +speakup_txprt ? --- linux-2.6.24.orig/debian/d-i/modules/input-modules +++ linux-2.6.24/debian/d-i/modules/input-modules @@ -0,0 +1,12 @@ +atkbd ? +evdev ? +hil_kbd ? +hilkbd ? +hil_mlc ? +hp_sdc ? +hp_sdc_mlc ? +i8042 ? +mousedev ? +psmouse ? +usbhid ? +usbkbd ? --- linux-2.6.24.orig/debian/d-i/modules/firewire-core-modules +++ linux-2.6.24/debian/d-i/modules/firewire-core-modules @@ -0,0 +1,4 @@ +ieee1394 ? +ohci1394 ? +sbp2 ? +eth1394 ? --- linux-2.6.24.orig/debian/d-i/modules/irda-modules +++ linux-2.6.24/debian/d-i/modules/irda-modules @@ -0,0 +1,26 @@ +act200l-sir ? +actisys-sir ? +ali-ircc ? +donauboe ? +esi-sir ? +girbil-sir ? +ircomm ? +ircomm-tty ? +irda ? +irda-usb ? +irlan ? +irnet ? +irport ? +irtty-sir ? +litelink-sir ? +ma600-sir ? +mcp2120-sir ? +nsc-ircc ? +old_belkin-sir ? +sir-dev ? +smsc-ircc2 ? +stir4200 ? +tekram-sir ? +via-ircc ? +vlsi_ir ? +w83977af_ir ? --- linux-2.6.24.orig/debian/d-i/modules/nic-modules +++ linux-2.6.24/debian/d-i/modules/nic-modules @@ -0,0 +1,147 @@ +3c359 ? +3c501 ? +3c503 ? +3c505 ? +3c507 ? +3c509 ? +3c515 ? +3c523 ? +3c527 ? +3c59x ? +8139cp ? +8139too ? +82596 ? +abyss ? +ac3200 ? +adm8211 ? +airo ? +airport ? +amd8111e ? +arc4 ? +arcnet ? +arc-rawmode ? +arc-rimi ? +arlan ? +at1700 ? +atl1 ? +atmel ? +atmel_pci ? +b44 ? +bcm43xx ? +bcm43xx-mac80211 ? +bmac ? +bnx2 ? +bonding ? +cassini ? +com20020 ? +com20020-pci ? +com90io ? +com90xx ? +cs89x0 ? +de2104x ? +de4x5 ? +de600 ? +de620 ? +defxx ? +depca ? +dl2k ? +dmfe ? +dummy ? +e100 ? +e1000 ? +e1000e ? +e2100 ? +eepro ? +eepro100 ? +eexpress ? +epic100 ? +eql ? +es3210 ? +eth16i ? +ewrk3 ? +fealnx ? +forcedeth ? +ps3_gelic ? +hamachi ? +hermes ? +hp ? +hp100 ? +hp-plus ? +ibmtr ? +ipddp ? +ipw2100 ? +ipw2200 ? +ipw3945 ? +ixgb ? +lance ? +lanstreamer ? +lasi_82596 ? +lne390 ? +lp486e ? +mace ? +mv643xx_eth ? +myri_sbus ? +natsemi ? +ne ? +ne2 ? +ne2k-pci ? +ne3210 ? +netconsole ? +ni5010 ? +ni52 ? +ni65 ? +niu ? +ns83820 ? +olympic ? +orinoco ? +orinoco_pci ? +orinoco_plx ? +orinoco_tmd ? +pcnet32 ? +prism54 ? +r8169 ? +rate_control ? +rfc1051 ? +rfc1201 ? +rrunner ? +rt2400 ? +rt2500 ? +rt61pci ? +s2io ? +shaper ? +sis190 ? +sis900 ? +spidernet ? +skfp ? +skge ? +sk98lin ? +sky2 ? +smc9194 ? +smc-ultra ? +smc-ultra32 ? +starfire ? +strip ? +sunbmac ? +sundance ? +sungem ? +sungem_phy ? +sunhme ? +sunlance ? +sunqe ? +sunvnet ? +tg3 ? +tlan ? +tms380tr ? +tmspci ? +tulip ? +tun ? +typhoon ? +uli526x ? +via-rhine ? +via-velocity ? +virtio_net ? +wavelan ? +wd ? +winbond-840 ? +yellowfin ? +znet ? --- linux-2.6.24.orig/debian/d-i/modules/block-modules +++ linux-2.6.24/debian/d-i/modules/block-modules @@ -0,0 +1,33 @@ +cryptoloop ? +DAC960 ? +aoe ? +cciss ? +cpqarray ? +nbd ? +bpck6 ? +aten ? +bpck ? +comm ? +dstr ? +epat ? +epia ? +fit2 ? +fit3 ? +friq ? +frpw ? +kbic ? +ktti ? +on20 ? +on26 ? +paride ? +pcd ? +pd ? +pf ? +pg ? +pt ? +pktcdvd ? +ps3disk ? +sunvdc ? +sx8 ? +umem ? +xd ? --- linux-2.6.24.orig/debian/d-i/modules/efi-modules +++ linux-2.6.24/debian/d-i/modules/efi-modules @@ -0,0 +1 @@ +efivars ? --- linux-2.6.24.orig/debian/d-i/modules/pcmcia-storage-modules +++ linux-2.6.24/debian/d-i/modules/pcmcia-storage-modules @@ -0,0 +1,6 @@ +pata_pcmcia ? +qlogic_cs ? +fdomain_cs ? +aha152x_cs ? +nsp_cs ? +sym53c500_cs ? --- linux-2.6.24.orig/debian/d-i/modules/message-modules +++ linux-2.6.24/debian/d-i/modules/message-modules @@ -0,0 +1,13 @@ +mptbase ? +mptctl ? +mptfc ? +mptlan ? +mptsas ? +mptscsih ? +mptspi ? +i2o_block ? +i2o_bus ? +i2o_config ? +i2o_core ? +i2o_proc ? +i2o_scsi ? --- linux-2.6.24.orig/debian/d-i/modules/scsi-modules +++ linux-2.6.24/debian/d-i/modules/scsi-modules @@ -0,0 +1,113 @@ +# SCSI +raid_class ? +scsi_transport_spi ? +scsi_transport_fc ? +scsi_transport_iscsi ? +scsi_transport_sas ? +iscsi_tcp ? +libiscsi ? +amiga7xx ? +a3000 ? +a2091 ? +gvp11 ? +mvme147 ? +sgiwd93 ? +cyberstorm ? +cyberstormII ? +blz2060 ? +blz1230 ? +fastlane ? +oktagon_esp_mod ? +atari_scsi ? +mac_scsi ? +mac_esp ? +sun3_scsi ? +mvme16x ? +bvme6000 ? +sim710 ? +advansys ? +psi240i ? +BusLogic ? +dpt_i2o ? +u14-34f ? +ultrastor ? +aha152x ? +aha1542 ? +aha1740 ? +aic7xxx_old ? +ips ? +fd_mcs ? +fdomain ? +in2000 ? +g_NCR5380 ? +g_NCR5380_mmio ? +NCR53c406a ? +NCR_D700 ? +NCR_Q720_mod ? +sym53c416 ? +qlogicfas408 ? +qla1280 ? +pas16 ? +seagate ? +seagate ? +t128 ? +dmx3191d ? +dtc ? +zalon7xx ? +eata_pio ? +wd7000 ? +mca_53c9x ? +ibmmca ? +eata ? +dc395x ? +tmscsim ? +megaraid ? +atp870u ? +esp ? +gdth ? +initio ? +a100u2w ? +qlogicpti ? +ide-scsi ? +mesh ? +mac53c94 ? +pluto ? +dec_esp ? +3w-xxxx ? +3w-9xxx ? +ppa ? +imm ? +jazz_esp ? +sun3x_esp ? +fcal ? +lasi700 ? +nsp32 ? +ipr ? +hptiop ? +stex ? +osst ? +sg ? +ch ? +scsi_debug ? +aacraid ? +aic7xxx ? +aic79xx ? +aic94xx ? +arcmsr ? +acornscsi_mod ? +arxescsi ? +cumana_1 ? +cumana_2 ? +ecoscsi ? +oak ? +powertec ? +eesox ? +ibmvscsic ? +libsas ? +lpfc ? +megaraid_mm ? +megaraid_mbox ? +megaraid_sas ? +qla2xxx ? +sym53c8xx ? +qla4xxx ? --- linux-2.6.24.orig/debian/d-i/modules/ide-modules +++ linux-2.6.24/debian/d-i/modules/ide-modules @@ -0,0 +1,45 @@ +ide-generic ? +ide-pnp ? +icside ? +rapide ? +bast-ide ? +ide-cris ? +ali14xx ? +dtc2278 ? +ht6560b ? +qd65xx ? +umc8672 ? +ide-cs ? +hd ? +swarm ? +au1xxx-ide ? +aec62xx ? +alim15x3 ? +amd74xx ? +atiixp ? +cmd64x ? +cs5520 ? +cs5530 ? +cs5535 ? +sc1200 ? +cy82c693 ? +hpt34x ? +hpt366 ? +it821x ? +jmicron ? +ns87415 ? +opti621 ? +pdc202xx_old ? +pdc202xx_new ? +piix ? +rz1000 ? +serverworks ? +sgiioc4 ? +siimage ? +sis5513 ? +sl82c105 ? +slc90e66 ? +triflex ? +trm290 ? +via82cxxx ? +generic ? --- linux-2.6.24.orig/debian/d-i/modules/nic-usb-modules +++ linux-2.6.24/debian/d-i/modules/nic-usb-modules @@ -0,0 +1,11 @@ +catc ? +kaweth ? +pegasus ? +prism2_usb ? +rtl8150 ? +usbnet ? +zd1211rw ? +zd1201 ? +rt2500usb ? +rt73usb ? +rt2570 ? --- linux-2.6.24.orig/debian/d-i/modules/nic-pcmcia-modules +++ linux-2.6.24/debian/d-i/modules/nic-pcmcia-modules @@ -0,0 +1,19 @@ +3c574_cs ? +3c589_cs ? +airo_cs ? +atmel_cs ? +axnet_cs ? +com20020_cs ? +fmvj18x_cs ? +ibmtr_cs ? +netwave_cs ? +nmclan_cs ? +orinoco_cs ? +pcnet_cs ? +ray_cs ? +smc91c92_cs ? +wavelan_cs ? +wl3501_cs ? +xirc2ps_cs ? +xircom_cb ? +xircom_tulip_cb ? --- linux-2.6.24.orig/debian/d-i/modules/usb-modules +++ linux-2.6.24/debian/d-i/modules/usb-modules @@ -0,0 +1,5 @@ +ehci-hcd ? +ohci-hcd ? +sl811-hcd ? +uhci-hcd ? +usbserial ? --- linux-2.6.24.orig/debian/d-i/modules/sata-modules +++ linux-2.6.24/debian/d-i/modules/sata-modules @@ -0,0 +1,18 @@ +ahci ? +ata_piix ? +# Required by sata_sis +pata_sis ? +pdc_adma ? +sata_inic162x ? +sata_mv ? +sata_nv ? +sata_promise ? +sata_qstor ? +sata_sil ? +sata_sil24 ? +sata_sis ? +sata_svw ? +sata_sx4 ? +sata_uli ? +sata_via ? +sata_vsc ? --- linux-2.6.24.orig/debian/d-i/modules/nfs-modules +++ linux-2.6.24/debian/d-i/modules/nfs-modules @@ -0,0 +1,3 @@ +nfs ? +lockd ? +sunrpc ? --- linux-2.6.24.orig/debian/d-i/modules/fat-modules +++ linux-2.6.24/debian/d-i/modules/fat-modules @@ -0,0 +1,8 @@ +# Windows filesystems ? +fat ? +vfat ? + +# Supporting modules ? +nls_cp437 ? +nls_iso8859-1 ? +nls_utf8 ? --- linux-2.6.24.orig/debian/d-i/modules/fb-modules +++ linux-2.6.24/debian/d-i/modules/fb-modules @@ -0,0 +1,3 @@ +fbcon ? +vesafb ? +vga16fb ? --- linux-2.6.24.orig/debian/d-i/modules/storage-core-modules +++ linux-2.6.24/debian/d-i/modules/storage-core-modules @@ -0,0 +1,48 @@ +# For SATA and PATA +libata ? + +# For SCSI (and for ATA and USB) +scsi_mod ? + +# IDE Core support +ide-core ? + +# USB Core for usb-storage ? +usbcore ? + +## Block level modules for each bus type ? + +# Generic cdrom support ? +cdrom ? + +# PS3 storage lib +ps3stor_lib ? +# PS3 Optical Storage +ps3rom ? + +# Anything that wants cdrom support will want isofs too +isofs ? + +# IDE Block devices ? +ide-cd ? +ide-disk ? +ide-floppy ? +ide-tape ? + +# SCSI Block devices ? +sd_mod ? +sr_mod ? +st ? + +# USB Storage modull ? +usb-storage ? + +# Loop modules (loop is built-in on sparc64) +loop ? +cloop ? + +# virtio modules +virtio ? +virtio_ring ? +virtio_pci ? +virtio_blk ? --- linux-2.6.24.orig/debian/d-i/modules/serial-modules +++ linux-2.6.24/debian/d-i/modules/serial-modules @@ -0,0 +1,3 @@ +generic_serial ? +serial_cs ? +synclink_cs ? --- linux-2.6.24.orig/debian/d-i/modules/ipv6-modules +++ linux-2.6.24/debian/d-i/modules/ipv6-modules @@ -0,0 +1 @@ +ipv6 ? --- linux-2.6.24.orig/debian/d-i/modules/md-modules +++ linux-2.6.24/debian/d-i/modules/md-modules @@ -0,0 +1,17 @@ +dm-crypt ? +dm-emc ? +dm-mirror ? +dm-mod ? +dm-multipath ? +dm-round-robin ? +dm-snapshot ? +dm-zero ? +faulty ? +linear ? +md-mod ? +multipath ? +raid0 ? +raid10 ? +raid1 ? +raid456 ? +xor ? --- linux-2.6.24.orig/debian/d-i/modules/nic-shared-modules +++ linux-2.6.24/debian/d-i/modules/nic-shared-modules @@ -0,0 +1,23 @@ +# PHY +8390 ? +mii ? + +# CRC modules ? +crc-ccitt ? +crc-itu-t ? + +# mac80211 stuff ? +mac80211 ? +rc80211_simple ? +cfg80211 ? + +# rt2x00 lib ? +rt2x00lib ? + +# Wireless 802.11 modules ? +ieee80211 ? +ieee80211_crypt ? +ieee80211_crypt_ccmp ? +ieee80211_crypt_tkip ? +ieee80211_crypt_wep ? +ieee80211softmac ? --- linux-2.6.24.orig/debian/d-i/modules/pata-modules +++ linux-2.6.24/debian/d-i/modules/pata-modules @@ -0,0 +1,44 @@ +ata_generic ? +pata_ali ? +pata_amd ? +pata_artop ? +pata_atiixp ? +pata_cmd640 ? +pata_cmd64x ? +pata_cs5520 ? +pata_cs5530 ? +pata_cs5535 ? +pata_cypress ? +pata_efar ? +pata_hpt366 ? +pata_hpt37x ? +pata_hpt3x2n ? +pata_hpt3x3 ? +pata_isapnp ? +pata_it8213 ? +pata_it821x ? +pata_ixp4xx_cf ? +pata_jmicron ? +pata_legacy ? +pata_marvell ? +pata_mpc52xx ? +pata_mpiix ? +pata_netcell ? +pata_ns87410 ? +pata_oldpiix ? +pata_opti ? +pata_optidma ? +pata_pdc2027x ? +pata_pdc202xx_old ? +pata_platform ? +pata_qdi ? +pata_radisys ? +pata_rz1000 ? +pata_sc1200 ? +pata_scc ? +pata_serverworks ? +pata_sil680 ? +pata_sl82c105 ? +pata_triflex ? +pata_via ? +pata_winbond ? --- linux-2.6.24.orig/debian/d-i/exclude-modules.powerpc +++ linux-2.6.24/debian/d-i/exclude-modules.powerpc @@ -0,0 +1,5 @@ +efi-modules +fb-modules +acpi-modules +cdrom-modules +fancontrol-modules --- linux-2.6.24.orig/debian/d-i/exclude-modules.sparc +++ linux-2.6.24/debian/d-i/exclude-modules.sparc @@ -0,0 +1,11 @@ +efi-modules +nic-pcmcia-modules +pcmcia-modules +pcmcia-storage-modules +socket-modules +irda-modules +floppy-modules +fb-modules +acpi-modules +cdrom-modules +fancontrol-modules --- linux-2.6.24.orig/debian/copyright +++ linux-2.6.24/debian/copyright @@ -0,0 +1,30 @@ +This is the Ubuntu prepackaged version of the Linux kernel. +Linux was written by Linus Torvalds +and others. + +This package was put together by the Ubuntu Kernel Team, from +sources retrieved from upstream linux git. +The sources may be found at most Linux ftp sites, including +ftp://ftp.kernel.org/pub/linux/kernel/ + +This package is currently maintained by the +Ubuntu Kernel Team + +Linux is copyrighted by Linus Torvalds and others. + + 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; version 2 dated June, 1991. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + +On Ubuntu Linux systems, the complete text of the GNU General +Public License v2 can be found in `/usr/share/common-licenses/GPL-2'. --- linux-2.6.24.orig/debian/changelog.historical +++ linux-2.6.24/debian/changelog.historical @@ -0,0 +1,4408 @@ +linux-source-2.6.20 (2.6.20-16.30) UNRELEASED; urgency=low + + CHANGELOG: Do not edit directly. Autogenerated at release. + CHANGELOG: Use the printchanges target to see the curent changes. + CHANGELOG: Use the insertchanges target to create the final log. + + -- Phillip lougher Mon, 11 Jun 2007 19:25:08 +0100 + +linux-source-2.6.20 (2.6.20-16.29) feisty-security; urgency=low + + [Phillip Lougher] + + * Revert "{ata_,}piix: Consolidate PCI IDs. Move ata_piix pata IDs to + piix" + - GIT-SHA d20328e312148f5c47cb38482e967ed9a1b7fdb9 + + [Tim Gardner] + + * Work around Dell E520 BIOS reboot bug. + - GIT-SHA 7d6ddf6fc8d2b5f40faac3c7915df71b4acb2fd4 + - Bug #114854 + + [Upstream Kernel Changes] + + * Fix VMI logic error + * [CRYPTO] geode: Fix in-place operations and set key (CVE-2007-2451) + * random: fix error in entropy extraction (CVE-2007-2453) + * random: fix seeding with zero entropy (CVE-2007-2453) + * [Bluetooth] Fix L2CAP and HCI setsockopt() information leaks (CVE-2007-1353) + + + -- Phillip lougher Thu, 07 Jun 2007 12:51:55 +0100 + +linux-source-2.6.20 (2.6.20-16.28) feisty-security; urgency=low + + [Ben Collins] + + * rtc: Ratelimit "lost interrupts" message. + - GIT-SHA 0102aad3b17d22e67864aa5afd88bc108b881141 + * vbox: Remove this driver. It will be outdated by release. + - GIT-SHA 60c8a6c1fbe7ed5dc28ccdd5a48c624e9ece56f3 + * hppa: Build fixes from jbailey. + - GIT-SHA 4f87aff6afe3479c98f8a64e05c866027e7d473d + * mmc: Set parent for block dev's to host, not class device. + - GIT-SHA 0400a0ceb5afa2afcda76c92d4425c4696e72845 + - Bug #99648 + + [Daniel Chen] + + * sound/pci/: Forward-port intel8x0 quirks from ubuntu-edgy.git + (intel8x0.c) + - GIT-SHA a2ce991fa1b7d601c428564f3741044a492d13a4 + * sound/pci/: Forward-port more intel8x0 quirks from kernel-team@ + (intel8x0.c) + - GIT-SHA 5263bd37eeeedc72447441bdec9fc47e7cca83d9 + * sound/pci/hda/: Revert Toshiba model setting (ALC861_TOSHIBA) for SSID + 1179:ff10 (patch_realtek.c) + - GIT-SHA b6fffb0f499459dfaef0f022f2da1f3fcb4fbdc2 + * sound/pci/hda/: Add missing SSID for ALC861-VD (patch_realtek.c) + - GIT-SHA 0ca1a43cc8e4d484963a7f6e4866602d5fe576db + * sound/pci/ac97/: Fix regression from Edgy - readd jack sense blacklist + entries (ac97_patch.c) + - GIT-SHA 963f93d185fc40ab7853ce75480a5fbcd607e070 + * sound/pci/hda/: Fix regression from Edgy - incorrect model quirk for + ALC861-VD (patch_realtek.c) + - GIT-SHA 382e158458c0771a6bd48cc8a64df6e24a46682e + * sound/pci/hda/: Fix inaudible sound on yet another Toshiba laptop - + incorrect model quirk (patch_realtek.c) + - GIT-SHA fbbec3e6208990a1dbe34766396084d683bc3322 + + [Fabio M. Di Nitto] + + * [OCFS2] Local mounts should skip inode updates + - GIT-SHA 8cbf682c7a9016caf65fb30bb67d1e2de3e924c6 + + [Kyle McMartin] + + * Enable ICH8GM (Crestline) support + - GIT-SHA 5b87e59b3898d33e11f71fcc037e7d1c6480aee0 + * bcm43xx: Update to 2.6.21 + - GIT-SHA 9424583295f2fa0920a611eb0f37ccd8fb2dc453 + * p54pci: Fix error path when eeprom read fails + - GIT-SHA c10305577fa669b114bcb03d6f80bdcbcd46a93a + + [Phillip Lougher] + + * Squashfs: add SetPageError handling + - GIT-SHA ff5082e7b9e1b48d33bbb26fbe9104ee1956688a + * Fix pata_sis crashes preventing booting + - GIT-SHA 1b27e19fa9145a1579cfecccf7d5be7d7e242e46 + - Bug #107774 + * Initialize the Broadcom USB Bluetooth device in Dell laptops. + - GIT-SHA 0f50a719466ae29c18b9b75df3ae64312d6523cf + * Update tifm driver to 0.8d + - GIT-SHA 6bec583645852716f3fee4a7d2534be1acf060d6 + - Bug #53923 + * sound/pci/hda/: Forcibly set the maximum number of codecs (hda_intel.c) + - GIT-SHA d8f18e83ea5ef15ab519f6bf03cccb3bdeb2e469 + - Bug #106843 + * Change CONFIG_NR_CPUS from 32 to 64. + - GIT-SHA 00f6cb2c3cda7dab1d02ceb444f5a34506c7a30d + + [Tim Gardner] + + * Added more USB device IDs + - GIT-SHA 139e45123031d80bebcb8e609d6a079538db0970 + * Prevent i2c_ec module from faulting becasue of uninitialized device + parent. + - GIT-SHA 490e63428ab4b3801bc94f520097fd43a57fbc3f + * Initialize the device with the ACPI structure. + - GIT-SHA 5df920c2fd7da80ea1d47d0c664a747700bf33f1 + * Backported from 2.6.21-rc6 + - GIT-SHA 4d0bb04551b393dfc12552d26dff259034c7620c + * Remove vboxdrv from the module lists. + - GIT-SHA 4aae55dc540f17b7b295047b99f4f68c43d01930 + * Cause SoftMac to emit an association event when setting ESSID. + - GIT-SHA c7a6bbdf4493b2951f02c924bd4a85d01b46c839 + - Bug #https://bugs.launchpad.net/ubuntu/+source/linux-source-2.6.20/+bug/103768 + + [Upstream Kernel Changes] + + * ocfs2_dlm: Missing get/put lockres in dlm_run_purge_lockres + * ocfs2_dlm: Add missing locks in dlm_empty_lockres + * ocfs2_dlm: Fix lockres ref counting bug + * ocfs2_dlm: Check for migrateable lockres in dlm_empty_lockres() + * [PS3] Add HV call to local_irq_restore(). + * i2c: Remove the warning on missing adapter device + * 2.6.21 fix lba48 bug in libata fill_result_tf() + * futex: PI state locking fix + * [APPLETALK]: Fix a remotely triggerable crash (CVE-2007-1357) + * [IPV6]: Fix for ipv6_setsockopt NULL dereference (CVE-2007-1388) + * DCCP: Fix exploitable hole in DCCP socket options (CVE-2007-1730) + * [IPv4] fib: Fix out of bound access of fib_props[] (CVE-2007-2172) + * (Denial of Service security fix from stable kernel 2.6.20.8) + * (Fix to Denial of Service security fix, from stable kernel 2.6.20.10) + * (ipv6 security bug fix from stable kernel 2.6.20.9) + * (Bug fix to ipv6 security fix, from stable kernel 2.6.20.10) + * [SPARC64]: SUN4U PCI-E controller support. + * [VIDEO]: Add Sun XVR-500 framebuffer driver. + * [VIDEO]: Add Sun XVR-2500 framebuffer driver. + * [SPARC64]: Fix recursion in PROM tree building. + * [SPARC64]: Bump PROMINTR_MAX to 32. + * [SPARC64]: Correct FIRE_IOMMU_FLUSHINV register offset. + * [SPARC64]: Add bq4802 TOD chip support, as found on ultra45. + * [SERIAL] SUNHV: Add an ID string. + * [SPARC64]: Be more resiliant with PCI I/O space regs. + * [SPARC64]: Add missing cpus_empty() check in hypervisor xcall handling. + * Input: i8042 - fix AUX IRQ delivery check + * Input: i8042 - another attempt to fix AUX delivery checks + * Input: i8042 - fix AUX port detection with some chips + * [IPV6]: ipv6_fl_socklist is inadvertently shared. (CVE-2007-1592) + + [Wang Zhenyu] + + * intel_agp: fix G965 GTT size detect + - GIT-SHA 8d9fac9fa2123f186f9f7c2b5ba7aaa594de1b58 + + -- Phillip Lougher Tue, 22 May 2007 20:01:42 +0100 + +linux-source-2.6.20 (2.6.20-15.27) feisty; urgency=low + + [Ben Collins] + + * ubuntu: Revert back to amd74xx and disable the troublesome pata_amd + - GIT-SHA 5e93e85491bf4804954643141af47a4692d59a91 + + -- Ben Collins Sat, 14 Apr 2007 17:41:11 -0400 + +linux-source-2.6.20 (2.6.20-15.26) feisty; urgency=low + + [Ben Collins] + + * libata: Rework logic for hpa_resize to work around bad returns from + SET_MAX + - GIT-SHA 5d5f973bfa93079d8dd13a21e2af32306d5a009f + + -- Ben Collins Sat, 14 Apr 2007 15:50:34 -0400 + +linux-source-2.6.20 (2.6.20-15.25) feisty; urgency=low + + [Ben Collins] + + * sata_nv: Revert patch that enabled ADMA for NODATA transfers. + - GIT-SHA 6429d0744ca5ffe007109ef4d70414bebe15966c + * libata: Completely avoid HPA code paths when ignore_hpa=0 + - GIT-SHA 9e3e1aea530dcb2e792f14e365a0d6d95539bfa9 + + -- Ben Collins Fri, 13 Apr 2007 13:39:36 -0400 + +linux-source-2.6.20 (2.6.20-15.24) feisty; urgency=low + + [Ben Collins] + + * libata: Re-add the tracking of n_sectors_boot + - GIT-SHA 1fa3ab07416406841cc1c7064b55fb084bbb1e3f + * i2c_ec: Do not set parent device. Current ACPI is not setup for this. + - GIT-SHA d80fb3540d170f18639c08f64afd133129bed856 + - Bug #96480 + + [Upstream Kernel Changes] + + * 2.6.21 fix lba48 bug in libata fill_result_tf() + + -- Ben Collins Thu, 12 Apr 2007 18:58:24 -0400 + +linux-source-2.6.20 (2.6.20-14.23) feisty; urgency=low + + [Ben Collins] + + * piix: Revery back to using piix (IDE) driver instead of ata_piix + (libata) driver for Intel PATA chipsets. + - GIT-SHA a4b5f29bd0754d49a818a30126c45e3b94ec127c + - Bug #96857 + * piix: Put some newer chipsets back to ata_piix. + - GIT-SHA 18a347500d3c6a2c636ac81556cfa2e1daed70b4 + * libata: Add patch to support recognizing HPA drives. + - GIT-SHA ddc27b2bb3c66026044efc3a4d97f22cd1e9243b + * mmc: Set parent for block dev's to host, not class device. + - GIT-SHA 104cff7bb0413b58091e2e45b6dfda210c1028fe + - Bug #99648 + + -- Ben Collins Thu, 12 Apr 2007 14:01:17 -0400 + +linux-source-2.6.20 (2.6.20-14.22) feisty; urgency=low + + [Ben Collins] + + * powerpc: Make ps3 work in multiplatform kernel + - GIT-SHA 54517f89a70e7cea696d1d21d13b86000c20daf4 + * drivers/ata/: Sync with libata-dev#upstream (ref + 1770cd662ad619e78d73a08a2f12f203656e705b) + - GIT-SHA 6fff74ec14bcaf6ac8bf156787961db83d6c90cd + * debian/rules: Add NOEXTRAS build option to not build things like + lowlatency and crashdump kernels. + - GIT-SHA 76f9f235bbdf048db4f09ef2874ae5766276222a + * libata-acpi: Add _GTM and _STM support to libata + - GIT-SHA 2939a7a99cfac2d0e1b120098c2541514ba48ff4 + * libata-acpi: Cleanup and enable acpi for pata drives by default. + - GIT-SHA 36fe5af2bb79195923a08acc0ebd74a2dd90e0f7 + * pci: Git rid of duplicate quirk exports. + - GIT-SHA a8779f83252855ce1a79ef633be5e8c3c2fe56f9 + * ps3: Merge bits so that ps3 can be compiled into powerpc64-smp + - GIT-SHA 462362a41075c7c803e4b49dbdcccda400a3a8f8 + * ubuntu: Remove remnants of ps3 kernel, now merged with ppc64-smp. + - GIT-SHA 2ba1dc63ca38d8e80c8ad0126dc1eba8c3eb080c + * ps3: Include asm/firmware.h for device-init.c + - GIT-SHA 9e4507538545341dc8ec645249513081ec423970 + * ubuntu: Update sata/pata d-i module lists. + - GIT-SHA 75e3656071e565efe201ac2c287f4743d2e93e0b + * snd_ps3: New driver for ps3 sound, of course. + - GIT-SHA e1a797d335353ad9c16e2cbe080699e41c5828a6 + * libusual: Add my U3 Cruzer as a single LUN device (has driver iso) + - GIT-SHA 2ff96660777c0936ac8064fb2c20b22e4954ef71 + * ps3: Sync to latest ps3-linux-dev git. We now have snd_ps3. + - GIT-SHA 563465bcc598e5f5bce463f78c11a5859814c08c + * gelic_net: Allocate gelic_irq_status from GFP_DMA so it works with + __pa() + - GIT-SHA 3b56675a8df0c4b2a5fd09d663bb880a1024cd44 + * ubuntu/net/ipg: Add MODULE_DEVIVCE_TABLE for autoload of module + - GIT-SHA 025a73f21cf92ae4abe6928bb37ec4176da11eae + - Bug #86388 + * acpi: Make the lack of DSDT.aml in initramfs not sound like an error. + - GIT-SHA 7711ba4a2e77f02793fdceefddc1c9c198f68dce + + [Colin Watson] + + * d-i: Fix fs-core-modules description. + - GIT-SHA 6ab196033b5d41b8d5545a28da6d7c5f672f75ee + * d-i: Restore fat-modules udeb, split out from fs-secondary-modules. + - GIT-SHA 7e436bb85a1483978103b0f236993d7ac1dc20ff + + [Daniel Chen] + + * sound/pci/hda/: Add quirk for Dell Dimension E520 (patch_sigmatel.c) + - GIT-SHA de4755b3b5e905194d9a9d06eb86a9200c28c864 + * sound/pci/hda/: Add missing mic boost mixer controls (patch_analog.c) + - GIT-SHA e882468a6dc91bd9235a548a011c25a43878b70b + * sound/pci/hda/: Add (un)muting for jack sense on Lenovo 3000 N100 + (patch_analog.c) + - GIT-SHA 7c726dbd0d2dd4237d9a4c9a64c41821956d8901 + * sound/pci/hda/: Add missing array terminators resulting in premature + optimisation (patch_conexant.c) + - GIT-SHA 5448559cd8ce389393697b28b6903c876f535c6b + * sound/pci/hda/: Add support for AD1986A Ultra model (patch_analog.c) + - GIT-SHA 0d95cfd2b39aed11eeb72d5fe3889b933bb362e0 + + [Fabio M. Di Nitto] + + * [OCFS2] Wrap access of directory allocations with ip_alloc_sem. + - GIT-SHA ba2f1bf8193c9e0b338f45714f102468c862cc4c + * [OCFS2] Properly lock extent map size changes. + - GIT-SHA a98ce36259ee1f83442f93845b830f6033dc90c8 + * [OCFS2] Local mounts should not truncate the extent map. + - GIT-SHA e87ad18113393107fc7d5a86e6bbd9b32dd44b6c + + [Matthew Garrett] + + * Add _GTM and _STM support to libata + - GIT-SHA 5d320f7915c4124ed56aeb619efbae7ff3beb9d2 + + [Tim Gardner] + + * [SATA ACPI] Fix some thinkos from + 36fe5af2bb79195923a08acc0ebd74a2dd90e0f7 + - GIT-SHA cbf8b6de0c9a84344e16847b03db5adcf0f0c855 + * Catch nonsense keycodes and silently ignore. + - GIT-SHA 560b0ff514b90e4c8bfbddbce3a54c218dc9ff85 + + [Upstream Kernel Changes] + + * Upstream sky2 driver updates + * [PS3] Storage cleanups, defconfig updates. + * [PS3] Fixes for SDK 2.0 toolchain. + * [PS3] Add spufs-avoid-accessing-to-released-inode.diff. + * [PS3] Add spufs-always-release-mapping-lock.diff, + spufs-fix-ctx-lifetimes.diff. + * [PS3] Storage bus dma updates. + * Add NOPFN_REFAULT result from vm_ops->nopfn() + * genirq: do not mask interrupts by default + * add vm_insert_pfn() + + [Zachary Amsden] + + * Urgent fix for VMI in HIGHMEM configurations + - GIT-SHA 72e461e0d638eb608c6ae07f7991e1063c5cbdeb + + -- Ben Collins Sun, 1 Apr 2007 13:03:28 -0400 + +linux-source-2.6.20 (2.6.20-13.21) feisty; urgency=low + + [Ben Collins] + + * debian/config: Enable CONFIG_DEBUG_FS. + - GIT-SHA a02719608695e5d59344600353d4872775a9ae3b + * rtl8187: Rename dir's from 818x to 8187. + - GIT-SHA ef3d971e78ca393bb1bcf3f46895849848010a7e + * rtl818x: Re-add old driver, fixing oops in old code as well. + - GIT-SHA d5d0ac60abafb7438f6736f9033208cac1572c82 + - Bug #78255 + * bluetooth: Update stack to latest code from bluez + - GIT-SHA 138bb4d3d2e65988cefcbd59b180b3788305f071 + - Bug #91194 + * rt2x00-legacy: Re-add rt2570 driver. + - GIT-SHA 43ab28f4b58f129611be5e784cd72ab2b5c46505 + * rt2500usb: Disable module alias when rt2570 is built. + - GIT-SHA ab16ae43815bcf9215965b87d4b05dbcc03e3574 + * mmc: Update to latest git supplied mmc core. + - GIT-SHA 5bf598b427d0ff75bef7186a75194b6b9102e224 + - Bug #93171 + * tifm: Update tifm core. + - GIT-SHA c25cfc3ad3cb8cac3474febfe66cff8ee0bfba18 + * lmpcm_usb: USB Logitech MediaPlay Cordless Mouse driver + - GIT-SHA c4291c4e7b6c2facfd65d3d9460fa667066d1e54 + - Bug #86035 + * drivers/media: Disable CONFIG_VIDEO_HELPER_CHIPS_AUTO to allow all + modules to be built. + - GIT-SHA 994e8c1e58d7b138880190796e6bd0ce3dcbd62a + * unusual_dev: Netac OnlyDisk Mini U2CV2 512MB USB 2.0 Flash Drive + - GIT-SHA ef90ffeabdca584d3539ae00ce746256d818a1a4 + - Bug #94371 + * speedstep-centrino: Include linux-phc built-in tables. + - GIT-SHA fc9f7238d11d5a9ff03ce67fae0b5b5c9fd7f436 + - Bug #63789 + * drivers/char/{agp/drm}: Resync with 2.6.21-rc4. + - GIT-SHA 1eae0b2972e215e9f13b99b7fb64b90db04cc556 + * ps3: Update ps3-storage and ps3fb drivers. + - GIT-SHA f2d4c3f34a613671bbcbc4696ccac6e7737b623a + * ps3: Updates for vuart, ps3av and sys-manager + - GIT-SHA b02d7d3f27d539713d6abba6e23db0b0f758d682 + * ide/generic: Remove errant jmicron entries. + - GIT-SHA d76099fde0ef127fa4f532c72bcd948caca7c2c1 + - Bug #84964 + * xpad: Update to latest version from xbox-linux. + - GIT-SHA 829dee658c6d3d09f049ca430a79997e5ba44838 + - Bug #94560 + * uvcvideo: Update to latest SVN version. + - GIT-SHA 7ca4b455c60b38ad53d03834fe03799ace81166d + - Bug #86754 + * ivtv: Update to 0.10.1 + - GIT-SHA b428794c3de387e2f701a768f98a302d3b4c98ea + - Bug #88680 + * ata_piix/piix: Prefer piix for device 7111 (PIIX4) + - GIT-SHA 9c7b34046bd9de870713e4630b06f95260d37973 + - Bug #94637 + * vboxdrv: Added VirtualBox kernel modules, v1.3.8 + - GIT-SHA 36b8eb8995ff04facae364706f6598fd6dce1cc4 + - Bug #81527 + * ata_piix/piix: Have piix handle device ID 0x24db + - GIT-SHA a083e4e48de3d5399788264259f42db157787603 + - Bug #95105 + + [Daniel T. Chen] + + * sound/pci/hda/: Simplify acer quirk (patch_realtek.c) + - GIT-SHA 1144a6d2628cb11286d8dc44a6f4fa0b740266ef + * sound/pci/hda/: Use proper constraints for HDA spec (hda_intel.c) + - GIT-SHA a51fa971bcf05e18dc9d315c36549126cc5b68ba + * sound/pci/hda/: Fix AZX models (hda_codec.c) + - GIT-SHA 1939127f3614de9f12dc4d42fb9c5b04081fbf0a + * sound/pci/hda/: Fix generic parser (hda_codec.c) + - GIT-SHA d0e1a1280e03111d26c63504451d3bf4378d668c + * sound/pci/hda/: Convert Sigmatel models to enums; differentiate between + Mac Pro revisions (patch_sigmatel.c) + - GIT-SHA e813cfe016a57c0155660f7c247b479bbeb9c8d8 + * sound/pci/hda/: Add _cfg_tbl[] quirk entries (patch_sigmatel.c) + - GIT-SHA 4a56b2a0ccadded72b1575c42db461f18fd2cc75 + * sound/pci/hda/: Fix front/rear mic inputs on AD1986A (patch_analog.c) + - GIT-SHA 50c1252587fc4df1f15248d2ceae8e87225f1283 + * sound/pci/hda/: Probe additional codec slots only if necessary + (hda_intel.c) + - GIT-SHA 81347c779c57515b0375650328cb4054a820a5d9 + + [Fabio M. Di Nitto] + + * Enable CONFIG_DEBUGFS=y + - GIT-SHA 52899638c7ab7e38dad47b884382bdb4e0814ea1 + + [Kyle McMartin] + + * Add Netac OnlyDisk Mini to unusual_devs.h + - GIT-SHA 999e79c3ffa906a970b717821b459724b9c2d939 + - Bug #94371 + + [Phillip Lougher] + + * fix NFS mounting regression from Edgy->Feisty + - GIT-SHA 1ad6cbd54fd2506a39f203cc6b4163d985f94cf0 + - Bug #94814 + + [Tejun Heo] + + * sd: implement stop_on_shutdown + - GIT-SHA 5fafa8d12092c5d722fc02e245b4977fd0765f68 + + [Upstream Kernel Changes] + + * fix process crash caused by randomisation and 64k pages + * HID: zeroing of bytes in output fields is bogus + * libata: don't whine if ->prereset() returns -ENOENT + * sata_sil24: Add Adaptec 1220SA PCI ID + * sata_inic162x: kill double region requests + * libata: kernel-doc fix + * pata_ixp4xx_cf: fix oops on detach + * pata_ixp4xx_cf: fix interrupt + * Execute AML Notify() requests on stack (Ubuntu Bug: 63123) + * Fix buffer overflow and races in capi debug functions + * [SPARC64]: store-init needs trailing membar. + * i2c: Declare more i2c_adapter parent devices + * ieee1394: cycle timer read extension for raw1394 + * ieee1394: fix another deadlock in nodemgr + * ia64: fix noncoherent DMA API so devres builds + + -- Ben Collins Sun, 18 Mar 2007 22:52:00 -0400 + +linux-source-2.6.20 (2.6.20-12.20) feisty; urgency=low + + [Upstream Kernel Changes] + + * pci_iomap_regions() error handling fix + - Fixes bug #93648 + + -- Ben Collins Wed, 21 Mar 2007 11:47:18 -0400 + +linux-source-2.6.20 (2.6.20-12.19) feisty; urgency=low + + [Ben Collins] + + * piix: Fix typo that allowed this module to override ata_piix. + - GIT-SHA 80bc1fd97d95519b2ab8c5007924f9e591838351 + - Bug #84964 + * vdso: Fix incompatibility between vdso and paravirt+vmi + - GIT-SHA 83821a009b3ec3f3d3ebaeda9a4f45900928900c + * drivers/ata/: Sync with upstream for new drivers and acpi fixes. + - GIT-SHA c38186b50b5d8444091a2f974e035abeb783499b + * debian/d-i/: Update sata/pata module listings. + - GIT-SHA e2c160419a8c50e9adc5de4b81e33251a7e952af + * rt2x00: Disable module aliases if legacy drivers are built. + - GIT-SHA a4e3d596f4b304e01ce04e43762ddf3873635a8c + * rt2x00-legacy: Re-add some legacy drivers since mainline isn't working + everywhere yet. + - GIT-SHA 59992a59a531f62aeb82384abc8296779092f1cc + * rt2x00-legacy/rt61: Fix big-endian compilation. + - GIT-SHA 6603c59fa3aee248aaf5ae73015ad155977ddad8 + * lib/iomap: Only build on architectures that need it. + - GIT-SHA fb3d5ca41505e11b8cd2cd85bc8db0571d58a6ae + * rt61: Fixup build on ppc. + - GIT-SHA 8c7eebfaf5c0ea44e7a77165894ebd3861ed3668 + + [Dan Hecht] + + * Feisty VMI paravirt-ops: Fix cpu hotplug on VMI + - GIT-SHA 44bbb009bb465537b9d7660a101641174f67b678 + + [Daniel T. Chen] + + * sound/pci/hda/: LP: #92909: Fix regression in -11.18 for Toshiba + Satellite M115 - S3094 (patch_realtek.c) + - GIT-SHA ff352c874a71fcce9af5f04d19360a0a8a4318b8 + * sound/pci/: LP: #90349: Add SSID for Dell Inspiron 9100 to headphone + quirk table (intel8x0.c) + - GIT-SHA 94ea2cdff6440a5bc8602cc8431380a690520f80 + + [Fabio M. Di Nitto] + + * Make scsi_proc_hostdir_add silent on failure + - GIT-SHA a6ad8ab034e40e188825cede360f69e8101351d3 + + [Upstream Kernel Changes] + + * Synced drivers/ata/ + * ACPI support for IDE devices + * ide-acpi support warning fix + * Disable NMI watchdog by default properly + * devres: device resource management + * sort the devres mess out + * Add pci class code for SATA & AHCI, and replace some magic numbers. + * PCI: allow multiple calls to pcim_pin_device() + * devres: release resources on device_del() + + -- Ben Collins Sat, 17 Mar 2007 11:15:27 -0400 + +linux-source-2.6.20 (2.6.20-11.18) feisty; urgency=low + + [Ben Collins] + + * mac80211/d80211: Switch from d80211 backport to mac80211 from + intellinuxwireless.org + - GIT-SHA 5be1800f366dd9be849c44d1f9a57f938ee04a54 + * adm8211/p54: Convert to use mac80211. + - GIT-SHA 91601e433a7e126260c65ed5ed219691e3ed2b9a + * rt2x00: Fixup Kconfig for mac80211 + - GIT-SHA 07feef3cb5e135d9479d86863ed857b3f89b7deb + * ac97: make patch_ad1986 global for use in other files. + - GIT-SHA f032849c2162da0a2939ebd6451c9bed8b496709 + * wireless: Fix Kconfig for wext-compat + - GIT-SHA fcd5dcb1753f14697319dba5b6ab570def81b9ea + * mac80211: Fixups for correct usage. + - GIT-SHA 22fa222a8a195ea11f3066bd72d426e7ada4b24f + * net/core/wireless.o: Disable in favor of mac80211. + - GIT-SHA 5ea988da86d00b6917d55c4aa6cdc2381e81b113 + * Makefile: Add mac80211 wireless directory to drivers-y. + - GIT-SHA 96aaf9171af0900733952db97b422f5bb0e0cb19 + * adm8211: Update from wireless-dev + - GIT-SHA 3222b8da95637eb5d96b6b092c101dfb70c10e36 + * p54: Update from wireless-dev + - GIT-SHA ee719880109e8d4c53097f7d3e7680e7e6b71087 + * rtl818x/rtl8187: Remove old broken drivers. + - GIT-SHA 7a8d4270ccc39bec2e66d6196ca50d1aa91bfcee + * rtl818x: Add 8180/8187 driver from wireless-dev + - GIT-SHA d3de93c8319a0dfe58e37eb7c27371f2f2d52456 + * eeprom_93cx6: Taken from wireless-dev for rtl818x driver. + - GIT-SHA 2199d23aed53519d2814c6547e47bae72180212f + * rt2x00: Remove legacy and update to mac80211 (wireless-dev) code. + - GIT-SHA 3bc9d8de616716014f0db7de5d36be0587fdea6b + * bxm43xx: Add mac80211 variant of driver (sans module aliases). + - GIT-SHA 883ff4b3fcabad5271995327d9f26512bda33687 + * zd1211rw: Add mac80211 variant of driver (sans module aliases). + - GIT-SHA dde6813b66f1f31c766fcbbdcc20fb43cadd0be4 + * ssb: Update from wireless-dev for bcm43xx usage. + - GIT-SHA 3b86466916f303503d8052b41b720d12fd82d4dd + * kvm: Update to kvm-16. + - GIT-SHA d0388ee0c445d54fef0be4da7f283069c82df80d + * ubuntu/: Fixup some dma-mapping.h includes needed. + - GIT-SHA 3f3f237e8f9c9f986c464abc9ac75d7c4d3ae119 + * d-i: Update nic module listings. + - GIT-SHA f442d4e826548d027373b28562529fa5489105a2 + * prism54_softmac: Remove ancient prism54 code in favor of p54. + - GIT-SHA d924ddb5eb75f16473f7703d17e347dc350d0d4a + * vdso: Fix incompatibility between vdso and paravirt+vmi + - GIT-SHA 77b43e78df1c73c0a8f1333fa9bc440201bf3094 + * bluetooth: SCO flow control patch from bluez website. Fixes BTSCO. + - GIT-SHA a3e22dab227fcdc2778f19c462476bf3c6186938 + * btsco: Update to Revision 1.16 from CVS. + - GIT-SHA edc8305ea5d3b4056369c24c09b12a23b3d0857e + * d-i: Build udebs for ps3. + - GIT-SHA 1255b98db417c2ec0465ed73045b9101c244283c + * quickcam: Add 0.6.6 driver (from qc-usb package). + - GIT-SHA 6cfdbcfc6427769567a0b4bb593751c089f3d852 + * ubuntu/: Rework Makefiles for proper -y/-m recursion. + - GIT-SHA 84440f2f67b8cc89e11aeb5e6ccc4f38fd9f91d4 + * Makefile: Move ubuntu/ to just drivers-y. + - GIT-SHA d8b88338578e9fded8380d94e71d8292ac0eee7d + * ubuntu/: Add ubuntu/net/wireless/ to obj-y for CONFIG_WIRELESS_EXT. + - GIT-SHA 3c4dc7409d831ec9ff68ee7f8624ee6f0714eb34 + * Release 2.6.20-11.18 + - GIT-SHA 94830a5986ed94c5d6402827553bf6b5319a7e32 + * debian/d-i/: Allow per-flavour udeb module listings. + - GIT-SHA 6a2a10a8d622cc80d4a1668ce6fc095c84dceb7e + * ubuntu/: Remove crufty file. + - GIT-SHA 420dd6113f06f136ec745ff0f88776b210c971bf + + [Dan Hecht] + + * Feisty VMI paravirt-ops: fix prototype pragma to match definition + - GIT-SHA 0ebf6936c9e9dc252c7257da8efe471582c36f73 + + [Daniel T. Chen] + + * sound/pci/hda/: (Many) Bug fixes; add Macbook/Pro, Fujitsu, and Lenovo + 3000 C200 support (patch_realtek.c) + - GIT-SHA 21621559de65fb1b336fac148b98637db9b8876e + * sound/pci/: Fix muted speaker on resume from suspend-to-RAM + (intel8x0.c) + - GIT-SHA c73679b8f2fdec4083612671afcf72fe26681b4c + * sound/pci/ac97/: Backport AD1xxx AC'97 fixes (ac97_{codec,patch}.c) + - GIT-SHA b86ead0f620209dcd96c30decc8362ebe2ed5bff + * sound/pci/ac97/: Add MSI L720 laptop to quirk list (ac97_patch.c) + - GIT-SHA 252b8b19279355f1bf4f90b14269a936c3e26322 + * sound/pci/hda/: Add support for Fujitsu EAPD model (patch_conexant.c) + - GIT-SHA 94e796e42ba693e81a0e6497d9477cdbb742ce4c + * sound/pci/hda/: LP #74677: Add models to HDA AD codec (patch_analog.c) + - GIT-SHA 85e78cc0ca76490eec7d956998afe309bc1e4024 + * sound/pci/hda/: Fix codec initialization on ATI HDA chips (hda_intel.c) + - GIT-SHA aa53cf8aff62b05396b1a98e37bbf401e8fb2aa0 + * sound/pci/hda/: Fix speaker output on MacPro (patch_sigmatel.c) + - GIT-SHA 5e06d854c5fe5cdc3692ec067355411725a3ac9e + * include/sound/: Add missing struct member (ac97_codec.h) + - GIT-SHA 658cfb791c276d372433f4ee3b57c8bef99a986d + * sound/pci/: LP: #88080: Fix Oops triggered from interrupt handler + (intel8x0.c) + - GIT-SHA 8376f4bfd0af249c8ab0c9c788184147db07984f + * sound/pci/hda/: Add SSID for HP d5700 to ALC260 quirk table + (patch_realtek.c) + - GIT-SHA f57799abf88ad79fdab977ce40b118d900f8ffc7 + + [David Miller] + + * Fix mach64 with gcc-4.1 and later... + - GIT-SHA 11057e22f19a953916315bbbf2889d6293d31177 + + [Fabio M. Di Nitto] + + * debian/firmware: Update ql2400 file. + - GIT-SHA 40a42fab6f35773ee0dd0a58083897771fd07468 + * Disable CONFIG_IP_ROUTE_MULTIPATH_CACHED for real. + - GIT-SHA 7b7dc1f9197a0d8347517362aad8003882812949 + * Readd gnbd driver + - GIT-SHA de6fffe4180e18f64648d82697d3ca79e180da75 + + [Kyle McMartin] + + * acpi/hotkey: Add loglevel to "Using ... hotkey" printk + - GIT-SHA 398c3db849ca235addc3bc16b8c683f180518661 + + [Upstream Kernel Changes] + + * ocfs2: ocfs2_link() journal credits update + * ocfs2_dlm: fix cluster-wide refcounting of lock resources + * fs/ocfs2/dlm/: make functions static + * ocfs2_dlm: Fixes race between migrate and dirty + * ocfs2_dlm: Make dlmunlock() wait for migration to complete + * ocfs2_dlm: Fix migrate lockres handler queue scanning + * ocfs2_dlm: Flush dlm workqueue before starting to migrate + * ocfs2_dlm: Drop inflight refmap even if no locks found on the lockres + * ocfs2_dlm: Dlm dispatch was stopping too early + * ocfs2_dlm: wake up sleepers on the lockres waitqueue + * ocfs2_dlm: Silence a failed convert + * ocfs2_dlm: Cookies in locks not being printed correctly in error + messages + * ocfs2: Added post handler callable function in o2net message handler + * ocfs2_dlm: Calling post handler function in assert master handler + * ocfs2: Binds listener to the configured ip address + * ocfs2_dlm: Ensure correct ordering of set/clear refmap bit on lockres + * ocfs2_dlm: disallow a domain join if node maps mismatch + * ocfs2_dlm: Silence some messages during join domain + * ocfs2_dlm: Add timeout to dlm join domain + * ocfs2: ocfs2_link() journal credits update + * x86_64: fix 2.6.18 regression - PTRACE_OLDSETOPTIONS should be accepted + * rtc-pcf8563: detect polarity of century bit automatically + * prism54: correct assignment of DOT1XENABLE in WE-19 codepaths + * pata_amd: fix an obvious bug in cable detection + * knfsd: Fix a race in closing NFSd connections. + * Keys: Fix key serial number collision handling + * ide: fix drive side 80c cable check + * bcm43xx: Fix for oops on resume + * bcm43xx: Fix for oops on ampdu status + * AGP: intel-agp bugfix + * Missing critical phys_to_virt in lib/swiotlb.c + * USB: fix concurrent buffer access in the hub driver + * usbaudio - Fix Oops with broken usb descriptors + * usbaudio - Fix Oops with unconventional sample rates + * hda-intel - Don't try to probe invalid codecs + * Fix various bugs with aligned reads in RAID5. + * Fix ATM initcall ordering. + * Fix TCP FIN handling + * Fix allocation failure handling in multicast + * md: Avoid possible BUG_ON in md bitmap handling. + * Fix compile error for e500 core based processors + * ieee1394: video1394: DMA fix + * ieee1394: fix host device registering when nodemgr disabled + * Fix null pointer dereference in appledisplay driver + * USB HID: Fix USB vendor and product IDs endianness for USB HID devices + * Kconfig: FAULT_INJECTION can be selected only if LOCKDEP is enabled. + * MTD: Fatal regression in drivers/mtd/redboot.c in 2.6.20 + * IPV6: HASHTABLES: Use appropriate seed for caluculating ehash index. + * EHCI: turn off remote wakeup during shutdown + * Avoid using nfsd process pools on SMP machines. + * Fix recently introduced problem with shutting down a busy NFS server. + * UHCI: fix port resume problem + * Fix atmarp.h for userspace + * Clear TCP segmentation offload state in ipt_REJECT + * Fix IPX module unload + * Prevent pseudo garbage in SYN's advertized window + * Fix oops in xfrm_audit_log() + * sky2: dont flush good pause frames + * sky2: transmit timeout deadlock + * x86_64: Fix wrong gcc check in bitops.h + * x86: Don't require the vDSO for handling a.out signals + * i386: Fix broken CONFIG_COMPAT_VDSO on i386 + * bcm43xx: fix for 4309 + * md: Fix raid10 recovery problem. + * dvbdev: fix illegal re-usage of fileoperations struct + * V4L: pvrusb2: Fix video corruption on stream start + * V4L: pvrusb2: Handle larger cx2341x firmware images + * DVB: cxusb: fix firmware patch for big endian systems + * DVB: digitv: open nxt6000 i2c_gate for TDED4 tuner handling + * V4L: fix cx25840 firmware loading + * V4L: cx88-blackbird: allow usage of 376836 and 262144 sized firmware + images + * Fix posix-cpu-timer breakage caused by stale p->last_ran value + * swsusp: Fix possible oops in userland interface + * sata_sil: ignore and clear spurious IRQs while executing commands by + polling + * fix umask when noACL kernel meets extN tuned for ACLs + * UML - Fix 2.6.20 hang + * mmc: Power quirk for ENE controllers + * bcm43xx: Fix assertion failures in interrupt handler + * libata: add missing PM callbacks + * libata: add missing CONFIG_PM in LLDs + * POWERPC: Fix performance monitor exception + * HID: fix possible double-free on error path in hid parser + * Fix interrupt probing on E450 sparc64 systems + * Fix xfrm_add_sa_expire() return value + * Fix skb data reallocation handling in IPSEC + * Fix %100 cpu spinning on sparc64 + * Fix TCP MD5 locking. + * Don't add anycast reference to device multiple times + * Fix anycast procfs device leak + * Fix reference counting (memory leak) problem in __nfulnl_send() and + callers related to packet queueing. + * export blk_recount_segments + * forcedeth: disable msix + * tty_io: fix race in master pty close/slave pty close path + * sched: fix SMT scheduler bug + * USB: usbnet driver bugfix + * RPM: fix double free in portmapper code + * NLM: Fix double free in __nlm_async_call + * kexec: Fix CONFIG_SMP=n compilation V2 (ia64) + * Fix MTRR compat ioctl + * ufs: restore back support of openstep + * v9fs_vfs_mkdir(): fix a double free + * enable mouse button 2+3 emulation for x86 macs + * hugetlb: preserve hugetlb pte dirty state + * m32r: build fix for processors without ISA_DSP_LEVEL2 + * kernel/time/clocksource.c needs struct task_struct on m68k + * buffer: memorder fix + * Char: specialix, isr have 2 params + * lockdep: forward declare struct task_struct + * kvm: Fix asm constraint for lldt instruction + * ueagle-atm.c needs sched.h + * fix section mismatch warning in lockdep + * throttle_vm_writeout(): don't loop on GFP_NOFS and GFP_NOIO allocations + * revert "drivers/net/tulip/dmfe: support basic carrier detection" + * video/aty/mach64_ct.c: fix bogus delay loop + * pktcdvd: Correctly set cmd_len field in pkt_generic_packet + * ATA: convert GSI to irq on ia64 + * gfs2: fix locking mistake + * TCP: Fix minisock tcp_create_openreq_child() typo. + * Fix buffer overflow in Omnikey CardMan 4040 driver (CVE-2007-0005) + * x86-64: survive having no irq mapping for a vector + * IPV6: Handle np->opt being NULL in ipv6_getsockopt_sticky() + [CVE-2007-1000] + * Linux 2.6.20.2 + * conntrack: fix {nf, ip}_ct_iterate_cleanup endless loops + * nf_conntrack/nf_nat: fix incorrect config ifdefs + * tcp conntrack: accept SYN|URG as valid + * nfnetlink_log: fix reference leak + * nfnetlink_log: fix use after free + * nfnetlink_log: fix NULL pointer dereference + * nfnetlink_log: fix possible NULL pointer dereference + * ip6_route_me_harder should take into account mark + * nf_conntrack: fix incorrect classification of IPv6 fragments as + ESTABLISHED + * nfnetlink_log: zero-terminate prefix + * nfnetlink_log: fix crash on bridged packet + * Fix bug 7994 sleeping function called from invalid context + * bcm43xx: Fix problem with >1 GB RAM + * Fix compat_getsockopt + * fix for bugzilla #7544 (keyspan USB-to-serial converter) + * Fix callback bug in connector + * Fix sparc64 device register probing + * Fix timewait jiffies + * Fix UDP header pointer after pskb_trim_rcsum() + * Linux 2.6.20.3 + + -- Ben Collins Wed, 14 Mar 2007 13:24:01 -0400 + +linux-source-2.6.20 (2.6.20-10.17) feisty; urgency=low + + [Ben Collins] + + * powerpc: Fix build failure caused by include ordering. + - GIT-SHA ae1f75e4b3e0a5645c5c2e0ace4d98a5c41663bf + * ps3: Update to latest code in linux-ps3.git + - GIT-SHA 87402da9dab94849527c685f09b3aef61b8ccc32 + * i386: Allow VDSO + PARAVIRT + - GIT-SHA a3718cc571410e202382daca05e809fbeb7ffe41 + * acpi: DSDT from initramfs patch + - GIT-SHA 7b650b00d82ec5c80452b2f99de1cfdbae2a465b + * ps3: Use what kexec passed to us. + - GIT-SHA 7711acb4b58f1313830940008ccc03275265c705 + * ps3: Do not call early_init_dt_scan_memory() on PS3 (we use lv1 + routines) + - GIT-SHA daf88d0260215ce90b293c52c65adc819e4a8f65 + * gelic_net: Allocate gelic_irq_status with card struct. + - GIT-SHA a85fc7b805b0b16f4bd97fa707affd71b3a672d9 + * ps3: Disable debug messages. + - GIT-SHA 84fd42468c726cffaafd58df6019e5278c111ef5 + * ps3: Export a few repository symbols (GPL) for storage driver as + module. + - GIT-SHA 26b5fe72a4dfc4fc3293f4020add9b55fde73e67 + * kvm: Update to kvm-15 + - GIT-SHA addefaae3b6bbd33e0ccf804e01a2afc102ee0d5 + * ndiswrapper: Update to v1.38 + - GIT-SHA d45dc1f185baa28a04551acd7d96ad1102633f7a + * ipw3945: Add max timeout_spin for thermal. Avoids softlock up. + - GIT-SHA 5d6caa9edbffa13973a6f9bbbdf47473ac18dc16 + * configs: Enable PM_TRACE on x86_64. + - GIT-SHA 8bb67c60933e524f06133796fb8c60bf0c68fb0e + * tifm_7xx1: include linux/dma-mapping.h (ftbfs on sparc) + - GIT-SHA a44e76a014641330f064062eb86d1e1dce79a57e + * pci: Add empty decleration for pci_yes_msi() on non-msi architectures + - GIT-SHA 96d5fb49720b2ae60406394ca29e96ce0919d83d + + [Dan Hecht] + + * Feisty VMI paravirt-ops: fix vmi timer interrupt handler nested + xtime_lock + - GIT-SHA 3187b0e329245f3667b399dd4a0e8a687f44bce5 + * Feisty VMI paravirt-ops: fix no_timer_check compile fix + - GIT-SHA adec0fc22dcc9039a22f47dfa009d0d76ba37c14 + * Feisty VMI paravirt-ops: unconditionally enable disable_nodelay + - GIT-SHA 1aace0a61ee4e2f5d465f7667445d76ac944538e + + [Daniel T. Chen] + + * sound/pci/{ali5451,ca0106,echoaudio,riptide,rme9652}/: Add missing + sysfs device assignment for ALSA PCI drivers + ({ali5451,ca0106_main,echoaudio,riptide,hdspm}.c) + - GIT-SHA 7324806accd810818a7b66ba17f6ff5923743b2f + * sound/pci/hda/: Add SSID for LG LW40 Express (patch_realtek.c) + - GIT-SHA c3979792b7026ae9f43c5147e9617cf701af054b + * sound/pci/hda/: LP #88452: Fix headphone jack sense regression in + 2.6.20-9.16 on 504[57] (patch_conexant.c) + - GIT-SHA 5bb5522b65050a448245acdb42a63a590c385921 + + [Kyle McMartin] + + * drivers/ata: Enable libata Host Protected Area support + - GIT-SHA a0e61542121a0519bfbe9f6e43980ec96a16156e + * Disable MSI by default + - GIT-SHA dc205519fa6c5e487e9829090145d3eb3e73b496 + * Disable MMCONFIG by default + - GIT-SHA d613cff3d5968d3e93bad197480b90733c71b984 + * Update nozomi driver + - GIT-SHA ece7562eae20233c9ebca8677104f4f99680ab71 + * Add eeprom_bad_csum_allow option to e1000 + - GIT-SHA 4f26a22422aaf987a34b76451383cb243088498c + * Enable TCP_MD5SIG + - GIT-SHA 8afc57f2791aebc0a1180749438c7c84f0e812d0 + * UBUNTU:usb/serial: New device IDs for cp2101 driver + - GIT-SHA cdbb30cb9a1667a84f759b10b1fe714bcedf4084 + * Disable CONFIG_IP_ROUTE_MULTIPATH_CACHED + - GIT-SHA 14dfd17d483d8466faf3605cf931c5f2fc7eac63 + - Bug ##90597 + * Disable CONFIG_ACPI_DEBUG + - GIT-SHA 57516b6c60cdb5b97caed872a638d8efbd8e524e + + [Matthew Garrett] + + * Allow appletouch to bind to Apple touchpads + - GIT-SHA 5bb33520e67b89386880d3a218ecfde550848b5b + * add module_device_table entry for applesmc in order to have it + autoloaded + - GIT-SHA 524e8b89b619f19b70dd38e45fa9a59ff30a82c3 + + [Phillip Lougher] + + * Backport NFS branch oops fix from Unionfs 2.0 + - GIT-SHA feea4eb6e27ac04bbc34a525a6599a79204e81f0 + - Bug #85145 + * Backport unionfs_statfs() from Unionfs 2.0 + - GIT-SHA a47c7c9186612ad5f59bcca95bd5fac5cb01b287 + - Bug #90088 + * i2c-matroxfb: add code to correctly set .class field + - GIT-SHA 82e00f0e073de4849f6cd6ee8b361c28f952ca8d + - Bug #80608 + * i2c-matroxfb: fix typo in patch + - GIT-SHA 85294b26c526ce28c2e513b04293561fe2c8d5f4 + - Bug #80608 + * TI FlashMedia xx12/xx21 driver update to 0.8 release (20070222) + - GIT-SHA a3e42adedcd3c2f3364e6b620e12b14c68c7a149 + - Bug #82680 + + [Upstream Kernel Changes] + + * [PARISC] Delete arch/parisc/mm/kmap.c again + * [PARISC] Show more memory information and memory layout at bootup + * [PARISC] Unbreak discontigmem mem_init() + * [PARISC] Fix ccio_request_resource when CONFIG_IOMMU_CCIO is not + defined + * [PARISC] HPPB bus updates for E-Class systems + * [PARISC] [MUX] Mux driver bug fix + * [PARISC] [MUX] Mux driver updates + * [PARISC] [MUX] Claim resources for the Mux driver + * [PARISC] [MUX] Make the Serial Mux driver work as module + * [PARISC] [MUX] Detect multiple cards in the correct order + * [PARISC] [MUX] Correctly report the number of available ports + * [PARISC] [MUX] Get the hversion directly from the parisc_device + * [PARISC] parisc-agp: Fix integer/pointer warning + * [PARISC] sparse fixes + * [PARISC] more sparse fixes + * [PARISC] Reserve 1GB of space for vmalloc/tmpalias space on parisc64 + * [PARISC] Fix PCI bus numbering in the presence of Cardbus bridges + * [PARISC] avoid compiler warnings when compiling 64bit + * [PARISC] bloody printf fmt string warnings + * [TRIVIAL] [PARISC] Fix module.c printk message, add missing ')' + * [PARISC] lasi_82596: use BUILD_BUG_ON() and constify static array + * [PARISC] Make Lasi Ethernet depend on GSC only + * [PARISC] Remove GCC_VERSION usage as suggested by Adrian Bunk + * [PARISC] pdcpat remove extra brackets + * [PARISC] Remove duplicate PDC_PAT_CELL defines + * WorkStruct: Fix up some PA-RISC work items + * [PARISC] Move spinlock_t out of struct cpu_data + * [PARISC] Fix thinko in cpu_data.lock removal + * parisc: fix module_param iommu permission + * PA-RISC: Fix bogus warnings from modpost + * use __u64 rather than u64 in parisc statfs structs + * [PARISC] Optimize TLB flush on SMP systems + * [PARISC] Clean up the cache and tlb headers + * [PARISC] Only write to memory in test_and_set_bit/test_and_clear_bit if + we're + * [PARISC] "Fix" circular includes + * [PARISC] Add prototypes for flush_user_dcache_range and + flush_user_icache_range + * [PARISC] Remove sched.h from uaccess.h on parisc + * [PARISC] Fix show_stack() when we can't kmalloc + * [PARISC] Generic BUG + * [PARISC] fix build for WARN_ON() when CONFIG_DEBUG_BUGVERBOSE=y + * [PARISC] whitespace cleanups and unify 32/64bit user-access assembler + inlines + * [PARISC] fix fixup declarations for 32bit and use CONFIG_64BIT + * [PARISC] dump stack backtrace on BUG() and add syslog-levels to + printk()s + * [PARISC] add missing syscalls for vmsplice, move_pages, getcpu & + epoll_pwait + * [PARISC] lba_pci format warnings + * [PARISC] Use fstatat64 instead of newfstatat syscall + * [PARISC] use fls_long in irq.c + * [PARISC] a and b in "break a,b" message were swapped + * [PARISC] GENERIC_TIME patchset for parisc + * [PARISC] disable cr16 clocksource when multiple CPUs are online + * [PARISC] Convert soft power switch driver to kthread + * [PARISC] detect recursive kernel crash earlier + * [PARISC] Add TIF_RESTORE_SIGMASK support + * [PARISC] use less assembler statements in syscall path + * [PARISC] display parisc device modalias in sysfs + * [PARISC] move parisc_device_id definition to mod_devicetable.h + * [PARISC] generate modalias for parisc_device_id tables + * [PARISC] rename *_ANY_ID to PA_*_ANY_ID in the exported header + * [PARISC] factor syscall_restart code out of do_signal + * [PARISC] clean up debugging printks in smp.c + * [PARISC] kill ENTRY_SYS_CPUS + * [PARISC] implement standard ENTRY(), END() and ENDPROC() + * [PARISC] Fixes /proc/cpuinfo cache output on B160L + * [PARISC] fix ENTRY() and ENDPROC() for 64bit-parisc + * [PARISC] more ENTRY(), ENDPROC(), END() conversions + * [PARISC] add ASM_EXCEPTIONTABLE_ENTRY() macro + * [PARISC] use CONFIG_64BIT instead of __LP64__ + * [PARISC] convert to use CONFIG_64BIT instead of __LP64__ + * [PARISC] add ENTRY()/ENDPROC() and simplify assembly of HP/UX emulation + code + * [PARISC] do not export get_register/set_register + * [PARISC] fix section mismatch warnings in harmony sound driver + * [PARISC] Reorder syscalls to match unistd.h + * Fix a free-wrong-pointer bug in nfs/acl server (CVE-2007-0772) + * Linux 2.6.20.1 + * [PARISC] Add missing statfs64 and fstatfs64 syscalls + * [PARISC] Use symbolic last syscall in __NR_Linux_syscalls + * add vm_insert_pfn() + * Add NOPFN_REFAULT result from vm_ops->nopfn() + * [SPARC64]: Fix PCI interrupts on E450 et al. + * sata_sil: ignore and clear spurious IRQs while executing commands by + polling + + -- Ben Collins Sun, 11 Mar 2007 06:23:55 -0400 + +linux-source-2.6.20 (2.6.20-9.16) feisty; urgency=low + + == Re-upload for build failures == + + [Ben Collins] + + * d80211/dadwifi: Get rid of this, causes dumb failures + - GIT-SHA fe8556a197d3f3f01e2e71785b3eff55f9a98a0f + * powerpc: ifdef use of spu logo function + - GIT-SHA 8cf5e8f8e79e53b5d13038326a50f94c81bb01e8 + * ssb: Include dma-mapping.h + - GIT-SHA 7fbf0dd183ffbfcd01efebe4bd90172a4346190d + + == 2.6.20-9.15 == + + [Ben Collins] + + * sata_sis: Sync with upstream v0.7 + - GIT-SHA 54db2f91cd5a9115faf2a1142c3788665d4c08de + * d-i: Make storage-core-modules provide loop-modules + - GIT-SHA e9a5522297506bb285ef4c0c803a64fb289abe72 + * pm_trace: Fixup for non-pm architectures (compile failure) + - GIT-SHA 08cfd02cd6fab74af88fda7127d7ab5249a4606c + * ps3: Pull patches from linux-ps3.git HEAD. + - GIT-SHA 05383a8254692b547ae676b59b45d66f19229a27 + * ps3av: Allow native HDMI modes for boot case. + - GIT-SHA 641ab76ed883342c2a19df4c33ac17d795d2f5ca + * bcm43xx-dscape: Remove module_dev_table to avoid autoloading + - GIT-SHA 2082dec4a8ee18cf694a1f26bb136280c1053911 + * bcm43xx: Re-enable stock bcm43xx driver. + - GIT-SHA e5375f74acdad5cd54b7a1c96bd7aff6056941a6 + * bcm43xx-dscape: Actually rename this module to bcm43xx-dscape. + - GIT-SHA 7f8dabc63ea45b2ae0c411073b9044dc0904ea14 + * bcm43xx: Patch for DMA over 1G. + - GIT-SHA 032a9bb14008b8ab88e1e22ee956650de7532c6a + * bcm43xx: Patch to detect radio enable/disable. + - GIT-SHA 95824fb76a8b2ede3156f46c7be19dcf7656e75e + * bcm43xx: Fix bcm4309, patch from upstream -stable. + - GIT-SHA e9b2f2ef91b51796aec064f95f5a816b60498af0 + * namespace: AppArmor patches to export symbols as needed. + - GIT-SHA 9a364aef1f798c16648ef8611eedc675c6c522e8 + * gspcav1: SPCA Driver, for v4l1 + - GIT-SHA f5d420265ac21729cf4ba0d342b370066a2ac7a2 + * ubuntu/: Update kbuild for gspcav1 + - GIT-SHA 814e37d1e7f4ead8a8ca9bf1a238078489ebf0c0 + * iwlwifi: Update to v0.0.8 + - GIT-SHA 968a3b550a7640b4a508e784bb095af8d761d731 + * debian/firmware: Add iwlwifi ucode + - GIT-SHA 76a733559ffdb665a5c5b092c6d7921e9dca38d7 + * ubuntu/ssb: Set better defaults in Kconfig for Ubuntu setups + - GIT-SHA d0c669fe2ebaed94f9837eca9cc3646cca014057 + * bcm43xx-d80211: Disable MODULE_DEVICE_TABLE so it isn't auto-loaded + - GIT-SHA 65c348e7886894076b7610ab3df9162c4d1dfe73 + * fs/exec: Always set max rlim for piped core. + - GIT-SHA 1e0f4a95ab56cadb1e37fb36ee1bc51f7697e062 + - Bug #87065 + * Allow mac mouse emul to be compiled on non-ppc + - GIT-SHA 5ceb16c6c1ebe24463a05328b3b72eea88c21ef8 + - Bug #81421 + * drivers/ide/: Check for pata modules enabled as modules too. + - GIT-SHA 3abf25603e6c855027ea11f9420ae7bddc3f02aa + * i386/pci: Quieten some messages. + - GIT-SHA 8897331220c73b367ad0ab4756f7b0f6cbb51c85 + - Bug #54294 + + [Daniel T. Chen] + + * sound/pci/hda/: Add support for Medion and Toshiba models + (patch_realtek.c) + - GIT-SHA d0c374e410e02bbe608b1eb05ea830326305b25f + * sound/pci/hda/: Add support for more ALC262, ALC883 and ALC660 models + (patch_realtek.c) + - GIT-SHA dab0d409a6253e89769f230190c852f8326f7fcb + * sound/pci/hda/: Add support for Asus models (patch_realtek.c) + - GIT-SHA f281cbd170b929b0b92cabefdfd4ba43616172b0 + * sound/pci/hda/: Add laptop-eapd model for Clevo M540JE, M550JE laptops + (Nvidia MCP51 chipset, ALC883 codec) (patch_realtek.c) + - GIT-SHA b37d077f39d082a5622c70d34be9247691f4cc99 + * sound/pci/hda/: More Conexant HDA fixes (patch_conexant.c) + - GIT-SHA b55060489d99586e5aff8000e74a1f1f195dd20d + * sound/pci/hda/: Add Dell models to STAC_REF and fix probe OOPS + (patch_sigmatel.c) + - GIT-SHA 25107d232a38e525b0a89884315d18eb495c1575 + * sound/pci/ac97/: Fix silent output with Conexant Cx20551 codec + (ac97_codec.c, ac97_patch.c, ac97_patch.h) + - GIT-SHA 1b3afda1c3af46ea96e9c5a3992a7ca83716a6a8 + * sound/pci/hda/: (Re)Add support for Macmini/Macbook/Macbook Pro + (patch_sigmatel.c) + - GIT-SHA 2fadead62fc6222b10799bd8cb134cfb6a79171f + + [Fabio M. Di Nitto] + + * ubuntu/fs/gfs: full update for 2.6.20 as of CVS20070216 + - GIT-SHA a81d2cf71db54eadcae6e213c625287236942eb9 + + [Kyle McMartin] + + * debian/firmware: Add aic94xx firmware + - GIT-SHA 6b0cc3fd1e98f3d1ba4bff6e26af4c94e206257c + * debian/d-i/firmware: Add scsi-firmware + - GIT-SHA 14d79cfe7725796e200c1dd20d92e8d58ba4b9b6 + * debian/: regen control{,.stub} + - GIT-SHA 60e2542a78f55537f6eb5757da0c7b925d3fe9b8 + + [Matthew Garrett] + + * Avoid the hid driver binding the Apple IR controller + - GIT-SHA 482271127ff1e7e3b321867648ea6cb199f6ecf6 + * Add PM_TRACE support for x86_64 + - GIT-SHA c63e3d917a84214a98c81ae497bcd4a72ead62ed + + [Phillip Lougher] + + * r8169: disable TSO by default for RTL8111/8168B chipsets. + - GIT-SHA 0cc30725f64a07cc4084d9e6d1637de405315815 + - Bug #76489 + * r8087: Fix bug in workqueue changes for 2.6.20 + - GIT-SHA 07e3458bdf5ba97519a58e089841ccb185ede7d2 + + [Upstream Kernel Changes] + + * Updated d80211 bcm43xx + * Add ssb support + * Update adm8211 drivers + * Update p54 driver + * Fix config symbol names + * Really fix config symbol names + * Add iwlwifi + * Fix the iwlwifi build + * Make SSB busses children of their parent device + * Add dadwifi (doesn't really work yet, but builds) + + -- Ben Collins Mon, 12 Feb 2007 20:22:14 -0500 + +linux-source-2.6.20 (2.6.20-8.14) feisty; urgency=low + + [Ben Collins] + + * acx: Add wlan_compat bits for ia64 + - GIT-SHA 4f29d1a99f1f8b096aaec9dc7df81cce54aa72b3 + * power: Disable the "Adding/Removing info for" printk's + - GIT-SHA daff39bf329d2522663343d6835f15eb17c0068d + * i82365: Probe before adding platform dev. + - GIT-SHA 06fd3fa13e3b336fcea01c326f3af314e5f37688 + * fs/exec: Fix call_usermodehelper_pipe() to allow waiting for exit + - GIT-SHA bfefaf3d2bd72a193bf5809639180a94ddc032ff + + [Upstream Kernel Changes] + + * sata_promise: TX2plus PATA support + * sata_promise: ATAPI support + * sata_promise: ATAPI cleanup + * sata_promise: issue ATAPI commands as normal packets + * sata_promise: handle ATAPI_NODATA ourselves + + -- Ben Collins Fri, 09 Feb 2007 10:24:58 -0500 + +linux-source-2.6.20 (2.6.20-7.13) feisty; urgency=low + + [Ben Collins - 7.13] + + * adm8211: Include dma-mapping.h for DMA_* constants. + - GIT-SHA d2ef9310ac1482f9230c89161260d74a86b1c9f1 + * p54: Include dma-mapping.h + - GIT-SHA d53668d200221d86b0889706e6560f0579246adc + * ubuntu/: Remove extraneous rt2x00 subdir from d80211 Makefile. + - GIT-SHA 2e9e9411c163478a7ba4aa389fcea2f553045a78 + + [Ben Collins] + + * drivers/core: Add sysfs attr to disable auto binding of drivers/devices + - GIT-SHA 22e8edadfe0141ea0e9f4b3c9626c3f97bf76c93 + * Disable prism2_cs in favor of orinoco/hostap modules. + - GIT-SHA 30cde452a15d9d1f27d20ea95d5fdba319ccd252 + * Update tifm core to latest version. + - GIT-SHA 6e2e96b61fea2d370777af7affe0008a7a7769b4 + * tifm: Update sd driver to latest version. + - GIT-SHA 8b69d97c3415de445ac7f9feff6152f130d001bc + * tifm_memstick: New driver. + - GIT-SHA d4d68aec79a4cb26d49893b0e98212e98549e806 + * netdev header: Add ieee80211 pointer for d80211. + - GIT-SHA 9d5f35c65ae15e6205221dd259a472edcb697812 + * ubuntu/net: Add SSB driver. + - GIT-SHA 4a4e7f2b0d1c71bbf7bb98a3c7981cae1e963d75 + * d80211: Add devicescape 802.11 stack. + - GIT-SHA 4d0fb64df98a9e21644525615df34ab2056eb569 + * p54: d80211 version of prism54 drivers + - GIT-SHA 140c080a78cde3f2a96e55da9ca2b25e44682b3c + * adm8211: d80211 version of this driver. + - GIT-SHA bfb106b04449dc080024eb7dd9e8dd486bcd6d7c + * rt2x00: Use in-tree d80211 now. + - GIT-SHA ffd2b8634285fe51f7a1dbe941a3d3de9682959d + * bcm43xx: d80211 version of this driver. + - GIT-SHA 1c965fad34ead0323464b2fc2f154b769e23d0fa + * ubuntu/wireless: Kbuild mechanisms for d80211 drivers. + - GIT-SHA fa6f353d01467a991d32dfecab5a8d0a97a0ab15 + * ubuntu/net: Add proper obj-* for d80211. + - GIT-SHA 1c197c4b327899fa52334b876f0481e466b5ca33 + * Compile fixes for d80211 drivers. + - GIT-SHA d1fccda7269b068993e9cbfcb59876ca8034ab87 + * rt2x00: Shift to d80211 compatible code. + - GIT-SHA 2a05970a2dc1b4a50ffd1c94d0986d8d1d6c6c3d + * tifm_7xx1: Add defines for new devices. + - GIT-SHA f824ad5dcb0d62f09b78a7930436c513d0128a1d + * ps3fb: Build for PPC_PS3 only + - GIT-SHA f5e173c8b9ff3692f595c417938083b13e64e11a + * powerpc: Export some ps3 symbols for storage module. + - GIT-SHA ec400176132803af41c6aecb3b12db9a31b9c845 + * debian: Correctly copy the ubuntu/include dir to headers pkg. + - GIT-SHA ed07298c5e4d0ddcafed16c448b03113d9759585 + * drivers/video/Kconfig: Fix missing select + - GIT-SHA 6976480384e97a384a9f0e95566d57710389e695 + * ubuntu/wireless: Add and switch to rt61 and rt73 legacy drivers. + - GIT-SHA 04e61f157c9e6f803495f37771ada12ee962a21c + * ubuntu/wireless: rt61 and rt73 should be x86 only. + - GIT-SHA e4adb1e93f9dae772ea6afdcefa036fb0300d1ff + * arch/powerpc: __start_initialization_ps3 should not be called unless + romboot + - GIT-SHA 92d9beacf533c488921d88d1cfc04ecaac73091f + * paravirt: Temporarily remove the _GPL from the paravirt_ops export. + - GIT-SHA dc9ad6a068aee49ff28d684240ef728e4fbd3ccc + * serio: Remove device on shutdown to avoid buggy hw issues. + - GIT-SHA 29f0b9969512eb7b312b0760d7bea7e652e8764e + - Bug #82681 + * zd1211rw: Add support for USR805423 + - GIT-SHA 6a04f78207354e5802e36ed8667d14161a3091f6 + - Bug #82578 + * configs: Provide kvm-modules-APIVER for userspace to dep on. + - GIT-SHA 6ac8dc6d7cccec4d44aa5dfe0c0893cf74110dd6 + - Bug #82258 + * sound/hda_sigmatel: Fix ftbfs in last commit. + - GIT-SHA 7a4d0ac5947972f4ca432c723141310c52d40a4e + * linux_logo: Fix typo from extra_logo changes. + - GIT-SHA 2fcc2e7e6f09eb5a7a7ec4bf318da3c2dc329ec1 + * x86: Remove kdump kernel target since stock kernel can relocate. + - GIT-SHA 3404865f24d45497625128c96a0a0aac09742292 + * ppc: Wrap use of logo with CONFIG_LOGO + - GIT-SHA e047adc25bee4c0c508e2ed4d165a5e317dbf716 + * ppc/ps3: Fix dev_dbg() missing paren. + - GIT-SHA 9a81097a5db61b2c1c53281c6c3a1105b697b2b8 + * fs/exec: Increase size of psuedo rlim for piped core. + - GIT-SHA c92e62051e81a485016b1eb33a25d0d56ec6e3f3 + * fs/exec: Add a CORE_REAL_RLIM env for when we override it. + - GIT-SHA f0fa902c99ae4b462a57239c4828bf2a9b1054f6 + * atl1: Replace PCI vendor macro with constant. + - GIT-SHA c1c238a318c39d3c4f021a3767e9188b5a0cf66b + * megaraid: Add CERC device support patch. + - GIT-SHA 66f63e20e2e9a7fc796f6a9b1af9b3f0019085e3 + * ipw3945: Update to v1.2.0 + - GIT-SHA 1c2e8dfd7e9984658df98ad59e35ce122b47b119 + * Update ipw3945 ucode to 1.14.2. + - GIT-SHA d0f9c02060e586553cfff48776abb7d4e5e8d614 + * debian/config: Enable CONFIG_PM_TRACE to help debug suspend/resume + problems. + - GIT-SHA d52b29c1f900b5089592a20b0e6a0f39aa8c707d + * toshiba_acpi: Add hotkeys support. + - GIT-SHA ce6b8dd74b92e479aad58444b531685500a19aca + - Bug #77026 + + [Dan Hecht] + + * Feisty VMI paravirt-ops: enable vdso even when paravirt enabled + - GIT-SHA 067e03f920818d3b40062be994fd72f6d73b84ee + * Feisty VMI paravirt-ops: export paravirt_ops symbol + - GIT-SHA 4535bc1f5a50a20c2db2784cc655e75672ec92f4 + * Feisty VMI paravirt-ops: use real delay for i8042 + - GIT-SHA 89e6be485bb2f833eadb649daf8cff712fef500b + * Feisty VMI paravirt-ops: fix vmi-timer no-idle-hz idling code + - GIT-SHA d3153a3f8aa3f3c36d9132a58083e1c6bdc079da + * Feisty VMI paravirt-ops: fix profile_pc cpl checks + - GIT-SHA be7fd2bd3b9f85a4121303b8a354a08ba1f05af9 + * Feisty VMI paravirt-ops: Fix sched_clock units in VMI case + - GIT-SHA 16872a27f546105702324c8ebd400893b9a3196f + * Feisty VMI paravirt-ops: fix HIGHPTE when running on vmi hypervisor + - GIT-SHA a5bee01a5fe6c709fadcac4037da76fb77eb4841 + + [Daniel T. Chen] + + * sound/pci/hda/: Add Sigmatel 9205 EAPD support (patch_sigmatel.c) + - GIT-SHA 42a2e17c3caf2e69c54ecf265509c15b086a6dc6 + * sound/pci/hda/: Add digital mic support for STAC HDA (patch_sigmatel.c) + - GIT-SHA 0d584c03b7589c69541ca98854ceca1e76c44818 + * sound/pci/hda/: Add support for more STAC HDA codecs (patch_sigmatel.c) + - GIT-SHA a7346022281e59443ab0408ffe4ac2ae3abe785d + + [Kyle McMartin] + + * nozomi: Added driver + - GIT-SHA b4f2f69278e511e34d2cf248d1d74a4eb1a1e518 + * atl1: Add driver + - GIT-SHA be86d24abdff0cc9ab502e174e3be29cac040991 + * acx: Update driver + - GIT-SHA 11216265914d055c8b46ecb741b882f810e69946 + * Fix Attansic L1 Gigabit Ethernet driver + - GIT-SHA 657112d01c49bc4f4ed3de6ec30aca5801beb302 + + [Upstream Kernel Changes] + + * [libata sata_promise] support PATA ports on SATA controllers + * make sata_promise PATA ports work + * [AGPGART] intel_agp: restore graphics device's pci space early in + resume + * [PS3] Import + ps3-linux-patches-efc1ddc7203ae9a2418e03a9dbbafb260f4fe2a3. + * [PS3] Cleanup fb patches. + * [PS3] Export ps3_get_firmware_version(). + * [ARM] 4084/1: Remove CONFIG_DEBUG_WAITQ + * [ARM] 4085/1: AT91: Header fixes. + * [ARM] 4086/1: AT91: Whitespace cleanup + * [ARM] 4087/1: AT91: CPU reset for SAM9x processors + * [ARM] 4088/1: AT91: Unbalanced IRQ in serial driver suspend/resume + * [ARM] 4089/1: AT91: GPIO wake IRQ cleanup + * [ARM] 4092/1: i.MX/MX1 CPU Frequency scaling latency definition + * [ARM] 4095/1: S3C24XX: Fix GPIO set for Bank A + * [ARM] 4096/1: S3C24XX: change return code form s3c2410_gpio_getcfg() + * [ARM] Fix show_mem() for discontigmem + * [ARM] Update mach-types + * [ARM] 4100/1: iop3xx: fix cpu mask for iop333 + * [ARM] Fix AMBA serial drivers for non-first serial ports + * [ARM] 4102/1: Allow for PHYS_OFFSET on any valid 2MiB address + * [ARM] 4106/1: S3C2410: typo fixes in register definitions + * [PS3] Prepare patches for 2.6.21 submission. + * [ARM] 4112/1: Only ioremap to supersections if DOMAIN_IO is zero + * [ARM] 4111/1: Allow VFP to work with thread migration on SMP + * HID: fix memleaking of collection + * USB HID: fix hid_blacklist clash for 0x08ca/0x0010 + * HID: fix hid-input mapping for Firefly Mini Remote Control + * [PS3] Prepare av and fb patches for 2.6.21 submission. + * [PS3] Prepared patches for 2.6.21 submission. + * ahci: port_no should be used when clearing IRQ in ahci_thaw() + * libata: fix ata_eh_suspend() return value + * ide: update MAINTAINERS entry + * jmicron: fix warning + * atiixp.c: remove unused code + * atiixp.c: sb600 ide only has one channel + * atiixp.c: add cable detection support for ATI IDE + * ide/generic: Jmicron has its own drivers now + * ia64: add pci_get_legacy_ide_irq() + * ide: add missing __init tags to IDE PCI host drivers + * ide: unregister idepnp driver on unload + * via82cxxx/pata_via: correct PCI_DEVICE_ID_VIA_SATA_EIDE ID and add + support for CX700 and 8237S + * [SCSI] Fix scsi_add_device() for async scanning + * [SCSI] qla4xxx: bug fixes + * [SCSI] st: A MTIOCTOP/MTWEOF within the early warning will cause the + file number to be incorrect + * [AGPGART] Prevent (unlikely) memory leak in amd_create_gatt_pages() + * [AGPGART] Remove pointless typedef in ati-agp + * [AGPGART] Remove pointless assignment. + * [AGPGART] Add new IDs to VIA AGP. + * [CPUFREQ] check sysfs_create_link return value + * [CPUFREQ] Remove unneeded errata workaround from p4-clockmod. + * [ARM] 4117/1: S3C2412: Fix writel() usage in selection code + * [PS3] Prepare av and fb patches for 2nd round 2.6.21 submission. + * ALSA: Fix sysfs breakage + * Fix balance_dirty_page() calculations with CONFIG_HIGHMEM + * [PS3] Move system-bus to platform directory. + * sky2: revert IRQ dance on suspend/resume + * [PS3] Fixed ps3_map_sg, enabled CONFIG_USB_STORAGE. + * Fix try_to_free_buffer() locking + * Fix SG_IO timeout jiffy conversion + * Malta: Fix build if CONFIG_MTD is diabled. + * [MIPS] Ocelot G: Fix a few misspellings of CONFIG_GALILEO_GT64240_ETH + * [MIPS] Fix typo of "CONFIG_MT_SMP". + * HID: fix pb_fnmode and move it to generic HID + * pata_sil680: PIO1 taskfile transfers overclocking fix (repost) + * ata_if_xfermask() word 51 fix + * pata_platform: set_mode fix + * libata-scsi: ata_task_ioctl should return ATA registers from sense data + * libata: fix translation for START STOP UNIT + * b44: Fix frequent link changes + * net: ifb error path loop fix + * FS_ENET: OF-related fixup for FEC and SCC MAC's + * 82596 warning fixes + * ehea: Fixed wrong jumbo frames status query + * ehea: Fixed missing tasklet_kill() call + * bonding: ARP monitoring broken on x86_64 + * e100: fix irq leak on suspend/resume + * b44: src_desc->addr is little-endian + * Broadcom 4400 resume small fix + * namespaces: fix exit race by splitting exit + * uml: fix mknod + * use __u8/__u32 in userspace ioctl defines for I2O + * Fix "CONFIG_X86_64_" typo in drivers/kvm/svm.c + * m68k: uaccess.h needs sched.h + * fs/lockd/clntlock.c: add missing newlines to dprintk's + * knfsd: ratelimit some nfsd messages that are triggered by external + events + * use __u8 rather than u8 in userspace SIZE defines in hdreg.h + * fuse: fix bug in control filesystem mount + * ufs: alloc metadata null page fix + * ufs: truncate negative to unsigned fix + * ufs: reallocation fix + * cdev.h: forward declarations + * `make help' in build tree doesn't show headers_* targets + * i386: In assign_irq_vector look at all vectors before giving up + * mm: mremap correct rmap accounting + * missing exports of pm_power_off() on alpha and sparc32 + * mtd/nand/cafe.c missing include of dma-mapping.h + * sym53c500_cs: remove bogus call fo free_dma() + * pata_platform: fallout from set_mode() change + * missing dma_sync_single_range_for{cpu,device} on alpha + * dma-mapping.h stubs fix + * b44: src_desc->addr is little-endian + * fix indentation-related breakage in Kconfig.i386 + * [PS3] More av and fb prepearations for 2nd round 2.6.21 submission. + * [MAINTAINERS]: netfilter@ is subscribers-only + * [NETFILTER]: xt_connbytes: fix division by zero + * [NETFILTER]: SIP conntrack: fix skipping over user info in SIP headers + * [NETFILTER]: SIP conntrack: fix out of bounds memory access + * [IPV6]: Fix up some CONFIG typos + * [IPV6]: fix BUG of ndisc_send_redirect() + * [SCTP]: Force update of the rto when processing HB-ACK + * [PS3] Finish system bus move. + * Don't allow the stack to grow into hugetlb reserved regions + * translate dashes in filenames for headers install + * Remove warning: VFS is out of sync with lock manager + * kprobes: replace magic numbers with enum + * Fix VIA quirks + * jmicron: 40/80pin primary detection + * uml: fix signal frame alignment + * ntfs: kmap_atomic() atomicity fix + * IPMI: fix timeout list handling + * Linux 2.6.20-rc7 + * [NETFILTER]: xt_hashlimit: fix ip6tables dependency + * fix frv headers_check + * mca_nmi_hook() can be called at any point + * ide section fixes + * endianness bug: ntohl() misspelled as >> 24 in fh_verify(). + * fork_idle() should be __cpuinit, not __devinit + * __crc_... is intended to be absolute + * efi_set_rtc_mmss() is not __init + * sanitize sections for sparc32 smp + * radio modems sitting on serial port are not for s390 + * uml-i386: fix build breakage with CONFIG_HIGHMEM + * via quirk update + * pci: remove warning messages + * KVM: fix lockup on 32-bit intel hosts with nx disabled in the bios + * procfs: Fix listing of /proc/NOT_A_TGID/task + * sysrq: showBlockedTasks is sysrq-W + * via82cxxx: fix typo ("cx7000" should be corrected to "cx700") + * Remove avr32@atmel.com from MAINTAINERS + * [SPARC32]: Fix over-optimization by GCC near ip_fast_csum. + * [NET_SCHED]: act_ipt: fix regression in ipt action + * [BNX2]: PHY workaround for 5709 A0. + * e100: fix napi ifdefs removing needed code + * MAINTAINERS: ufs entry + * ahci/pata_jmicron: fix JMicron quirk + * pata_atiixp: propogate cable detection hack from drivers/ide to the new + driver + * pata_via: Correct missing comments + * libata: Fix ata_busy_wait() kernel docs + * libata: Initialize nbytes for internal sg commands + * [SCSI] sd: udev accessing an uninitialized scsi_disk field results in a + crash + * [NETFILTER]: ctnetlink: fix compile failure with NF_CONNTRACK_MARK=n + * [NETFILTER]: nf_conntrack_h323: fix compile error with CONFIG_IPV6=m, + CONFIG_NF_CONNTRACK_H323=y + * [PS3] SPE logo, sys-manager cleanups. + * aio: fix buggy put_ioctx call in aio_complete - v2 + * kexec: Avoid migration of already disabled irqs (ia64) + * net/smc911x: match up spin lock/unlock + * alpha: fix epoll syscall enumerations + * revert blockdev direct io back to 2.6.19 version + * Altix: more ACPI PRT support + * x86-64: define dma noncoherent API functions + * fix rtl8150 + * EFI x86: pass firmware call parameters on the stack + * Linux 2.6.20 + * [GFS2] don't try to lockfs after shutdown + * [DLM] fix resend rcom lock + * [DLM] fix old rcom messages + * [DLM] add version check + * [DLM] fix send_args() lvb copying + * [DLM] fix receive_request() lvb copying + * [DLM] fix lost flags in stub replies + * [DLM] fs/dlm/lowcomms-tcp.c: remove 2 functions + * [GFS2] Fix DIO deadlock + * [GFS2] Fail over to readpage for stuffed files + * [GFS2] Fix change nlink deadlock + * [DLM] Fix schedule() calls + * [DLM] Fix spin lock already unlocked bug + * [GFS2] Fix ordering of page disposal vs. glock_dq + * [GFS2] BZ 217008 fsfuzzer fix. + * [GFS2] Fix gfs2_rename deadlock + * [DLM] change some log_error to log_debug + * [DLM] rename dlm_config_info fields + * [DLM] add config entry to enable log_debug + * [DLM] expose dlm_config_info fields in configfs + * [GFS2] gfs2 knows of directories which it chooses not to display + * [GFS2] make gfs2_change_nlink_i() static + * [DLM] Use workqueues for dlm lowcomms + * [DLM] fix user unlocking + * [DLM] fix master recovery + * [GFS2] Add writepages for "data=writeback" mounts + * [GFS2] Clean up/speed up readdir + * [GFS2] Remove max_atomic_write tunable + * [GFS2] Shrink gfs2_inode memory by half + * [GFS2] Remove the "greedy" function from glock.[ch] + * [GFS2] Remove unused go_callback operation + * [GFS2] Remove local exclusive glock mode + * [DLM] lowcomms tidy + * [GFS2] Tidy up glops calls + * [DLM] fix lowcomms receiving + * [GFS2] Remove queue_empty() function + * [GFS2] Compile fix for glock.c + * [GFS2] use CURRENT_TIME_SEC instead of get_seconds in gfs2 + * [GFS2] Fix typo in glock.c + * [DLM] Make sock_sem into a mutex + * [DLM] saved dlm message can be dropped + * [DLM] can miss clearing resend flag + * [GFS2] Fix recursive locking attempt with NFS + * [GFS2] Fix list corruption in lops.c + * [GFS2] increase default lock limit + * [GFS2] make lock_dlm drop_count tunable in sysfs + * [GFS2/DLM] use sysfs + * [GFS2/DLM] fix GFS2 circular dependency + * [GFS2] more CURRENT_TIME_SEC + * [GFS2] Put back semaphore to avoid umount problem + * [GFS2] Fix unlink deadlocks + * [DLM/GFS2] indent help text + * [DLM] zero new user lvbs + * [DLM] fix softlockup in dlm_recv + * [GFS2] nfsd readdirplus assertion failure + * libata: ACPI and _GTF support + * libata: ACPI _SDD support + * libata: change order of _SDD/_GTF execution (resend #3) + * libata: wrong sizeof for BUFFER + + -- Ben Collins Tue, 30 Jan 2007 10:42:16 -0500 + +linux-source-2.6.20 (2.6.20-6.8) feisty; urgency=low + + [Ben Collins] + + * zd1211rw: Add WL-117 ZyDAS device (also to unusual_devs) + - GIT-SHA f4e590f04c115142f97ae121d1907a4c782f8fe0 + - Bug #78311 + * ubuntu/gfs1: Fixups for build warnings + - GIT-SHA e25792fce5c6d02004e51171387daabf811ae5ae + * ubuntu/mol: Fixes to build again. Fabio owes me a beer. + - GIT-SHA f57afa67e6410d9c3a21d3bf64fb4274c8d83bd2 + * acpi/osl: Dedicated work queue for notify() execution + - GIT-SHA 2365e9585cdc207280bbda4017921aa8b6e5224a + - Bug #75398 + * ubuntu/gfs1: Fix compile failure. + - GIT-SHA aed1705a979b1a4b228598980af5b6095cdb6cb5 + * debian/config: Disable via_pata and re-enable via-ide driver. + - GIT-SHA ec624a5acacae28761f73aa70f61d441fa9931c4 + - Bug #75492 + * fs/exec.c: Implement new style of apport interaction. + - GIT-SHA 1c3aaaa6866c3129e854887cee5180d0881742e1 + * debian/firmware: Update zd1211b_uphr file. + - GIT-SHA d17e13bfd559680e92ddc42b10d0bc0c1f81fd8c + + [Daniel T. Chen] + + * sound/pci/hda/: Add Conexant HDA codec support (hda_patch.h) + - GIT-SHA d3cba8f9d6053991b4979cbef059f9b9c3a49ace + * sound/pci/hda/: Add Conexant HDA codec support (Makefile) + - GIT-SHA c91da21e199515d9ac8daf99a4ffb9771ee249bc + * sound/pci/hda/: Add Conexant HDA codec support (patch_conexant.c) + - GIT-SHA b13229d7257c689bf6f9595b29aa812e918e3439 + + [Upstream Kernel Changes] + + * [JFFS2] kill warning RE debug-only variables + * [MTD NAND] Initial import of CAFÉ NAND driver. + * [MTD] SSFDC must depend on BLOCK + * [MTD NAND] OLPC CAFÉ driver update + * [MTD] MAPS: Add parameter to amd76xrom to override rom window size + * [MTD] CHIPS: Support for SST 49LF040B flash chip + * [MTD] MAPS: Support for BIOS flash chips on Intel ESB2 southbridge + * [JFFS2] Use rb_first() and rb_last() cleanup + * [MTD] JEDEC probe: fix comment typo (devic) + * [MTD] MAPS: esb2rom: use hotplug safe interfaces + * [JFFS2] Fix jffs2_follow_link() typo + * [MTD] NAND: AT91 NAND driver + * [MTD] mtdchar: Fix MEMGETOOBSEL and ECCGETLAYOUT ioctls + * [MTD] MAPS: Remove ITE 8172G and Globespan IVR MTD support + * [MTD] NAND: nandsim page-wise allocation (1/2) + * [MTD] NAND: nandsim page-wise allocation (2/2) + * [MTD] NAND: nandsim coding style fix + * [MTD] core: trivial comments fix + * [MTD] NOR: leave Intel chips in read-array mode on suspend + * [MTD] NAND: nandsim: support subpage write + * [MTD] NAND: Combined oob buffer so it's contiguous with data + * [MTD] NAND: Correct setting of chip->oob_poi OOB buffer + * [MTD] NAND: Add hardware ECC correction support to CAFÉ NAND driver + * [MTD] NAND: CAFÉ NAND driver cleanup, fix ECC on reading empty flash + * [MTD] NAND: Disable ECC checking on CAFÉ since it's broken for now + * [MTD] NAND: Fix nand_default_mark_blockbad() when flash-based BBT + disabled + * [MTD] NAND: Café ECC -- remove spurious BUG_ON() in err_pos() + * [MTD] NAND: Reset Café controller before initialising. + * [MTD] CAFÉ NAND: Add 'slowtiming' parameter, default usedma and + checkecc on + * [MTD] NAND: Add ECC debugging for CAFÉ + * [MTD] NAND: Remove empty block ECC workaround + * [MTD] NAND: Fix timing calculation in CAFÉ debugging message + * [MTD] NAND: Use register #defines throughout CAFÉ driver, not numbers + * [MTD] NAND: Add register debugging spew option to CAFÉ driver + * [MTD] NAND: Fix ECC settings in CAFÉ controller driver. + * MTD: OneNAND: interrupt based wait support + * [MTD] OneNAND: lock support + * [MTD] OneNAND: Single bit error detection + * [MTD] [NAND] rtc_from4.c: use lib/bitrev.c + * [MTD] make drivers/mtd/cmdlinepart.c:mtdpart_setup() static + * [MTD] [NAND] Fix endianess bug in ndfc.c + * [MTD] [MAPS] Support for BIOS flash chips on the nvidia ck804 + southbridge + * [MTD] Allow variable block sizes in mtd_blkdevs + * [MTD] [NAND] remove len/ooblen confusion. + * [MTD] Fix printk format warning in physmap. (resources again) + * [MTD] replace kmalloc+memset with kzalloc + * [MTD] [NAND] Update CAFÉ driver interrupt handler prototype + * [MTD] [NAND] fix ifdef option in nand_ecc.c + * [MTD] Tidy bitrev usage in rtc_from4.c + * [MTD] increase MAX_MTD_DEVICES + * [MTD] fix map probe name for cstm_mips_ixx + * [MTD] add MTD_BLKDEVS Kconfig option + * [MTD] NAND: add subpage write support + * [MTD] add get_mtd_device_nm() function + * [MTD] add get and put methods + * [MTD] return error code from get_mtd_device() + * [MTD] Use EXPORT_SYMBOL_GPL() for exported symbols. + * [MTD] Remove trailing whitespace + * [MTD] bugfix: DataFlash is not bit writable + * [MTD] [NAND] Compile fix in rfc_from4.c + * [MTD] redboot partition combined fis / config problem + * [MTD] NAND: use SmartMedia ECC byte order for ndfc + * [MTD] nandsim: bugfix in page addressing + * [MTD] NAND: Support for 16-bit bus-width on AT91. + * [MTD] Support combined RedBoot FIS directory and configuration area + * [MTD] of_device-based physmap driver + * [MTD] ESB2ROM uses PCI + * [MTD] Fix SSFDC build for variable blocksize. + * [JFFS2] replace kmalloc+memset with kzalloc + * [MTD] Fix ssfdc blksize typo + * [MTD] OneNAND: fix oob handling in recent oob patch + * [MTD] Nuke IVR leftovers + * [JFFS2] add cond_resched() when garbage collecting deletion dirent + * [CIFS] Update CIFS version number + * [JFFS2] Fix error-path leak in summary scan + * ieee80211: WLAN_GET_SEQ_SEQ fix (select correct region) + * ipw2100: Fix dropping fragmented small packet problem + * [SCSI] advansys: wrap PCI table inside ifdef CONFIG_PCI + * [SCSI] qla2xxx: make qla2x00_reg_remote_port() static + * [SCSI] Add missing completion to scsi_complete_async_scans() + * [SCSI] scsi_transport_spi: fix sense buffer size error + * [SCSI] seagate: remove BROKEN tag + * [SCSI] qla2xxx: Don't log trace-control async-events. + * [SCSI] qla2xxx: Correct endianess issue while interrogating MS status. + * [SCSI] qla2xxx: Use proper prep_ms_iocb() function during GFPN_ID. + * [SCSI] qla2xxx: Detect GPSC capabilities within a fabric. + * [SCSI] qla2xxx: Correct IOCB queueing mechanism for ISP54XX HBAs. + * [SCSI] qla2xxx: Correct reset handling logic. + * [SCSI] qla2xxx: Perform a fw-dump when an ISP23xx RISC-paused state is + detected. + * [SCSI] qla2xxx: Use generic isp_ops.fw_dump() function. + * [SCSI] qla2xxx: Update version number to 8.01.07-k4. + * ARM: OMAP: fix MMC workqueue changes + * MMC: at91 mmc linkage updates + * i2c-pnx: Fix interrupt handler, get rid of EARLY config option + * i2c-pnx: Add entry to MAINTAINERS + * i2c: Migration aids for i2c_adapter.dev removal + * ACPI: Altix: ACPI _PRT support + * IB/mthca: Fix off-by-one in FMR handling on memfree + * i2c-mv64xxx: Fix random oops at boot + * i2c/m41t00: Do not forget to write year + * UHCI: make test for ASUS motherboard more specific + * UHCI: support device_may_wakeup + * USB: fix interaction between different interfaces in an "Option" usb + device + * USB: funsoft is borken on sparc + * USB: omap_udc build fixes (sync with linux-omap) + * USB Storage: unusual_devs: add supertop drives + * USB storage: fix ipod ejecting issue + * USB: small update to Documentation/usb/acm.txt + * USB: Fixed bug in endpoint release function. + * sisusb_con warning fixes + * USB: usblp.c - add Kyocera Mita FS 820 to list of "quirky" printers + * USB: asix: Fix AX88772 device PHY selection + * PCI: disable PCI_MULTITHREAD_PROBE + * Driver core: Fix prefix driver links in /sys/module by bus-name + * ACPI: ec: enable printk on cmdline use + * Add AFS_SUPER_MAGIC to magic.h + * Fix implicit declarations in via-pmu + * Fix leds-s3c24xx hardware.h reference + * start_kernel: test if irq's got enabled early, barf, and disable them + again + * kernelparams: detect if and which parameter parsing enabled irq's + * PCI: prevent down_read when pci_devices is empty + * via82cxxx: fix cable detection + * KVM: Fix GFP_KERNEL alloc in atomic section bug + * KVM: Use raw_smp_processor_id() instead of smp_processor_id() where + applicable + * KVM: Recover after an arch module load failure + * KVM: Improve interrupt response + * rtc-at91rm9200 build fix + * Fix BUG at drivers/scsi/scsi_lib.c:1118 caused by "pktsetup dvd + /dev/sr0" + * atiixp: Old drivers/ide layer driver for the ATIIXP hang fix + * adfs: fix filename handling + * swsusp: Do not fail if resume device is not set + * profiling: fix sched profiling typo + * i386: Restore CONFIG_PHYSICAL_START option + * Sanely size hash tables when using large base pages + * i386: fix modpost warning in SMP trampoline code + * i386: fix another modpost warning + * i386: modpost smpboot code warning fix + * ip2 warning fix + * fix memory corruption from misinterpreted bad_inode_ops return values + * fix BUG_ON(!PageSlab) from fallback_alloc + * Update the rtc-rs5c372 driver + * KVM: Prevent stale bits in cr0 and cr4 + * KVM: MMU: Implement simple reverse mapping + * KVM: MMU: Teach the page table walker to track guest page table gfns + * KVM: MMU: Load the pae pdptrs on cr3 change like the processor does + * KVM: MMU: Fold fetch_guest() into init_walker() + * KVM: MU: Special treatment for shadow pae root pages + * KVM: MMU: Use the guest pdptrs instead of mapping cr3 in pae mode + * KVM: MMU: Make the shadow page tables also special-case pae + * KVM: MMU: Make kvm_mmu_alloc_page() return a kvm_mmu_page pointer + * KVM: MMU: Shadow page table caching + * KVM: MMU: Write protect guest pages when a shadow is created for them + * KVM: MMU: Let the walker extract the target page gfn from the pte + * KVM: MMU: Support emulated writes into RAM + * KVM: MMU: Zap shadow page table entries on writes to guest page tables + * KVM: MMU: If emulating an instruction fails, try unprotecting the page + * KVM: MMU: Implement child shadow unlinking + * KVM: MMU: kvm_mmu_put_page() only removes one link to the page + * KVM: MMU: oom handling + * KVM: MMU: Remove invlpg interception + * KVM: MMU: Remove release_pt_page_64() + * KVM: MMU: Handle misaligned accesses to write protected guest page + tables + * KVM: MMU: kvm a little earlier + * KVM: Avoid oom on cr3 switch + * KVM: Add missing 'break' + * KVM: Don't set guest cr3 from vmx_vcpu_setup() + * KVM: MMU: Add missing dirty bit + * KVM: Make loading cr3 more robust + * KVM: Simplify mmu_alloc_roots() + * KVM: Simplify test for interrupt window + * pata_optidma: typo in Kconfig + * hpt37x: Two important bug fixes + * Check for populated zone in __drain_pages + * qconf: fix SIGSEGV on empty menu items + * fix the toshiba_acpi write_lcd return value + * fix OOM killing of swapoff + * fix garbage instead of zeroes in UFS + * shrink_all_memory(): fix lru_pages handling + * connector: some fixes for ia64 unaligned access errors + * [ARM] 4079/1: iop: Update MAINTAINERS + * [ARM] 4070/1: arch/arm/kernel: fix warnings from missing includes + * [ARM] 4082/1: iop3xx: fix iop33x gpio register offset + * [SCSI] scsi_scan: fix report lun problems with CDROM or RBC devices + * [SCSI] iscsi: fix 2.6.19 data digest calculation bug + * [SCSI] iscsi: fix crypto_alloc_hash() error check + * [SCSI] iscsi: newline in printk + * [SCSI] iscsi: simplify IPv6 and IPv4 address printing + * [SCSI] libiscsi: fix senselen calculation + * [SCSI] aacraid: Product List Update + * [SCSI] scsi: lpfc error path fix + * [SCSI] sr: fix error code check in sr_block_ioctl() + * [SCSI] 3ware 8000 serialize reset code + * [SCSI] megaraid_sas: Update module author + * [SCSI] fusion: fibre channel: return DID_ERROR for + MPI_IOCSTATUS_SCSI_IOC_TERMINATED + * [SCSI] fusion: power pc and miscellaneous bug fixs + * [SCSI] fusion: MODULE_VERSION support + * [SCSI] fusion: bump version + * [SCSI] qla1280: set residual correctly + * ixgb: Fix early TSO completion + * ixgb: Maybe stop TX if not enough free descriptors + * [ARM] Fix kernel-mode undefined instruction aborts + * Linux 2.6.20-rc4 + * IB/iser: Return error code when PDUs may not be sent + * qla3xxx: Remove NETIF_F_LLTX from driver features. + * qla3xxx: Add delay to NVRAM register access. + * RDMA/iwcm: iWARP connection timeouts shouldn't be reported as rejects + * RDMA/ucma: Fix struct ucma_event leak when backlog is full + * RDMA/ucma: Don't report events with invalid user context + * IB/mthca: Fix PRM compliance problem in atomic-send completions + * i915: Fix a DRM_ERROR that should be DRM_DEBUG. + * HID: fix mappings for DiNovo Edge Keyboard - Logitech USB BT receiver + * HID: tiny patch to remove a kmalloc cast + * HID: mousepoll parameter makes no sense for generic HID + * [ARM] Fix potential MMCI bug + * [ARM] pass vma for flush_anon_page() + * [ARM] Resolve fuse and direct-IO failures due to missing cache flushes + * [ARM] Provide basic printk_clock() implementation + * [MIPS] Malta: Add missing MTD file. + * [MIPS] csum_partial and copy in parallel + * [MIPS] SMTC build fix + * [MIPS] Fix build errors on SEAD + * [MIPS] pnx8550: Fix write_config_byte() PCI config space accessor + * [MIPS] TX49: Fix use of CDEX build_store_reg() + * [MIPS] PNX8550: Fix system timer support + * [POWERPC] Fix bogus BUG_ON() in in hugetlb_get_unmapped_area() + * [POWERPC] Fix unbalanced uses of of_node_put + * [POWERPC] Avoid calling get_irq_server() with a real, not virtual irq. + * [POWERPC] Fix manual assembly WARN_ON() in enter_rtas(). + * [POWERPC] Update ppc64_defconfig + * [POWERPC] Add legacy iSeries to ppc64_defconfig + * [POWERPC] 52xx: Don't use device_initcall to probe of_platform_bus + * [POWERPC] Fix mpc52xx fdt to use correct device_type for sound devices + * [POWERPC] Don't include powerpc/sysdev/rom.o for arch/ppc builds + * [POWERPC] Fix mpc52xx serial driver to work for arch/ppc again + * [POWERPC] disable PReP and EFIKA during make oldconfig + * [POWERPC] iSeries: fix mf proc initialisation + * [POWERPC] iSeries: fix proc/iSeries initialisation + * [POWERPC] iSeries: fix lpevents initialisation + * [POWERPC] iSeries: fix viopath initialisation + * [POWERPC] iSeries: fix setup initcall + * [POWERPC] Fix corruption in hcall9 + * [POWERPC] Fix bugs in the hypervisor call stats code + * forcedeth: sideband management fix + * s390: qeth driver fixes: VLAN hdr, perf stats + * s390: qeth driver fixes: packet socket + * s390: qeth driver fixes: atomic context fixups + * s390: iucv Kconfig help description changes + * chelsio: error path fix + * pcnet_cs : add new id + * [ALSA] Audio: Add nvidia HD Audio controllers of MCP67 support to + hda_intel.c + * [ALSA] Fix potential NULL pointer dereference in echoaudio midi + * [ALSA] usb-audio: work around wrong frequency in CM6501 descriptors + * [ALSA] hda_intel: ALSA HD Audio patch for Intel ICH9 + * [ALSA] hda-codec - Fix NULL dereference in generic hda code + * [ALSA] _snd_cmipci_uswitch_put doesn't set zero flags + * [ALSA] usb: usbmixer error path fix + * [ALSA] usbaudio - Fix kobject_add() error at reconnection + * [INET]: Fix incorrect "inet_sock->is_icsk" assignment. + * [X25]: Trivial, SOCK_DEBUG's in x25_facilities missing newlines + * [Bluetooth] Add packet size checks for CAPI messages + * [Bluetooth] More checks if DLC is still attached to the TTY + * [Bluetooth] Fix uninitialized return value for RFCOMM sendmsg() + * [Bluetooth] Handle device registration failures + * [Bluetooth] Correct SCO buffer size for another ThinkPad laptop + * [Bluetooth] Correct SCO buffer for Broadcom based HP laptops + * [Bluetooth] Correct SCO buffer for Broadcom based Dell laptops + * NetLabel: correct locking in selinux_netlbl_socket_setsid() + * NetLabel: correct CIPSO tag handling when adding new DOI definitions + * [BNX2]: Don't apply CRC PHY workaround to 5709. + * [BNX2]: Fix 5709 Serdes detection. + * [BNX2]: Fix bug in bnx2_nvram_write(). + * [BNX2]: Update version and reldate. + * [TG3]: Add PHY workaround for 5755M. + * [NETFILTER]: nf_conntrack_netbios_ns: fix uninitialized member in + expectation + * [TCP]: Fix iov_len calculation in tcp_v4_send_ack(). + * [S390] memory detection misses 128k. + * [S390] cio: use barrier() in stsch_reset. + * [S390] Fix cpu hotplug (missing 'online' attribute). + * [S390] Fix vmalloc area size calculation. + * [S390] don't call handle_mm_fault() if in an atomic context. + * [S390] locking problem with __cpcmd. + * [ALSA] version 1.0.14rc1 + * HID: Fix DRIVER_DESC macro + * i2c/pci: fix sis96x smbus quirk once and for all + * IB/ehca: Use proper GFP_ flags for get_zeroed_page() + * IB/mthca: Don't execute QUERY_QP firmware command for QP in RESET state + * [NETFILTER]: nf_conntrack_ipv6: fix crash when handling fragments + * [NETFILTER]: arp_tables: fix userspace compilation + * [NETFILTER]: nf_nat: fix hanging connections when loading the NAT + module + * [NETFILTER]: tcp conntrack: fix IP_CT_TCP_FLAG_CLOSE_INIT value + * [SCTP]: Fix err_hdr assignment in sctp_init_cause. + * [INET]: style updates for the inet_sock->is_icsk assignment fix + * [IPV4] devinet: inetdev_init out label moved after RCU assignment + * [JFFS2] Reschedule in loops + * [JFFS2] use the ref_offset macro + * [MTD] OneNAND: fix onenand_wait bug + * [MTD] OneNAND: add subpage write support + * [MTD] OneNAND: release CPU in cycles + * [MTD] OneNAND: fix onenand_wait bug in read ecc error + * [MTD] OneNAND: Implement read-while-load + * [MTD] OneNAND: return ecc error code only when 2-bit ecc occurs + * [MTD] OneNAND: Handle DDP chip boundary during read-while-load + * MAINTAINERS: maintainer for sata_promise + * fix linux banner format string + * ieee1394: sbp2: fix probing of some DVD-ROM/RWs + * [MIPS] PNX8550: Fix system timer initialization + * [MIPS] Fix N32 SysV IPC routines + * [MIPS] Alchemy: Fix PCI-memory access + * Page allocation hooks for VMI backend + * Paravirt CPU hypercall batching mode + * IOPL handling for paravirt guests + * SMP boot hook for paravirt + * VMI backend for paravirt-ops + * VMI timer patches + * Vmi compile fix + * Vmi native fix + * x86-64: Update defconfig + * i386: Update defconfig + * x86-64: Make noirqdebug_setup function non init to fix modpost warning + * x86-64: Use different constraint for gcc < 4.1 in bitops.h + * i386: cpu hotplug/smpboot misc MODPOST warning fixes + * i386: make apic probe function non-init + * x86-64: modpost add more symbols to whitelist pattern2 + * x86-64: Modpost whitelist reference to more symbols (pattern 3) + * x86-64: pci quirks MODPOST warning fix + * x86-64: - Ignore long SMI interrupts in clock calibration + * x86-64: tighten up printks + * i386: Fix memory hotplug related MODPOST generated warning + * i386: Convert some functions to __init to avoid MODPOST warnings + * x86-64: Fix warnings in ia32_aout.c + * ACPI: rename cstate_entry_s to cstate_entry + * ACPI: delete two spurious ACPI messages + * ACPI: schedule obsolete features for deletion + * ACPI: update MAINTAINERS + * Pull trivial into release branch + * Don't put "linux_banner" in the .init section + * sched: tasks cannot run on cpus onlined after boot + * increment pos before looking for the next cap in __pci_find_next_ht_cap + * Fix sparsemem on Cell + * qconf: (re)fix SIGSEGV on empty menu items + * rtc-sh: correctly report rtc_wkalrm.enabled + * Change cpu_up and co from __devinit to __cpuinit + * Kdump documentation update + * i386: sched_clock using init data tsc_disable fix + * md: pass down BIO_RW_SYNC in raid{1,10} + * KVM: add VM-exit profiling + * NFS: Fix race in nfs_release_page() + * really fix funsoft driver + * Revert bd_mount_mutex back to a semaphore + * intel-rng workarounds + * Fix HWRNG built-in initcalls priority + * fix typo in geode_configre()@cyrix.c + * FD_ZERO build fix + * PCMCIA: fix drivers broken by recent cleanup + * blktrace: only add a bounce trace when we really bounce + * Linux v2.6.20-rc5 + * [JFFS2] debug.h: include for current->pid + * omap: Update MMC response types + * mmc: Correct definition of R6 + * V4L/DVB (5019): Fix the frame->grabstate update in read() entry point. + * V4L/DVB (5020): Fix: disable interrupts while at KM_BOUNCE_READ + * V4L/DVB (5021): Cx88xx: Fix lockup on suspend + * V4L/DVB (5024): Fix quickcam communicator driver for big endian + architectures + * V4L/DVB (5029): Ks0127 status flags + * V4L/DVB (5033): MSI TV@nywhere Plus fixes + * V4L/DVB (5069): Fix bttv and friends on 64bit machines with lots of + memory + * V4L/DVB (5071): Tveeprom: autodetect LG TAPC G701D as tuner type 37 + * V4L/DVB (5023): Fix compilation on ppc32 architecture + * bcm43xx: Fix failure to deliver PCI-E interrupts + * NTFS: 2.1.28 - Fix deadlock reported by Sergey Vlasov due to + ntfs_put_inode(). + * NTFS: Forgot to bump version number in makefile to 2.1.28... + * 8139cp: Don't blindly enable interrupts + * myri10ge: make wc_fifo usage load-time tunable + * myri10ge: check that we can get an irq + * myri10ge: update driver version to 1.2.0 + * Update ucc_geth.c for new workqueue structure + * Fix phy_read/write redefinition errors in ucc_geth_phy.c + * hwmon/w83793: Remove the description of AMDSI and update the voltage + formula + * hwmon: Fix the VRD 11 decoding + * hwmon/w83793: Ignore disabled temperature channels + * hwmon/w83793: Fix the fan input detection + * hwmon/w83793: Hide invalid VID readings + * [MIPS] SMTC: Fix cp0 hazard. + * [MIPS] Delete duplicate call to load_irq_save. + * sis190: failure to set the MAC address from EEPROM + * libata doc: "error : unterminated entity reference exceptions" + * sata_via: add PCI ID 0x5337 + * libata: initialize qc->dma_dir to DMA_NONE + * libata: fix handling of port actions in per-dev action mask + * sata_mv HighPoint 2310 support (88SX7042) + * HID: fix some ARM builds due to HID brokenness - make USB_HID depend on + INPUT + * HID: GEYSER4_ISO needs quirk + * HID: update MAINTAINERS entry for USB-HID + * HID: proper LED-mapping for SpaceNavigator + * HID: compilation fix when DEBUG_DATA is defined + * HID: hid/hid-input.c doesn't need to include linux/usb/input.h + * HID: add missing RX, RZ and RY enum values to hid-debug output + * HID: put usb_interface instead of usb_device into hid->dev to fix + udevinfo breakage + * hid-core.c: Adds GTCO CalComp Interwrite IPanel PIDs to blacklist + * [CIFS] Remove 2 unneeded kzalloc casts + * [CIFS] cifs sprintf fix + * ocfs2: Don't print errors when following symlinks + * ocfs2: Directory c/mtime update fixes + * ocfs2: cleanup ocfs2_iget() errors + * ocfs2: Add backup superblock info to ocfs2_fs.h + * [CIFS] Fix oops when Windows server sent bad domain name null + terminator + * [POWERPC] Remove bogus sanity check in pci -> OF node code + * [POWERPC] Fix cell's mmio nvram to properly parse device tree + * [POWERPC] Fix broken DMA on non-LPAR pSeries + * [POWERPC] Make it blatantly clear; mpc5200 device tree is not yet + stable + * [POWERPC] Fix OF node refcnt underflow in 836x and 832x platform code + * [POWERPC] atomic_dec_if_positive sign extension fix + * usbtouchscreen: make ITM screens report BTN_TOUCH as zero when not + touched + * USB: asix: Detect internal PHY and enable/use accordingly + * USB: rndis_host: fix crash while probing a Nokia S60 mobile + * USB: make usbhid ignore Imation Disc Stakka + * USB: unusual_devs.h for 0x046b:ff40 + * USB: add vendor/device id for Option GT Max 3.6 cards + * USB: disable USB_MULTITHREAD_PROBE + * USB: Fix for typo in ohci-ep93xx.c + * USB: unusual_devs.h entry for nokia 6233 + * PCI: Unhide the SMBus on the Asus P4P800-X + * PCI: rework Documentation/pci.txt + * PCI: fix pci-driver kernel-doc + * [Bluetooth] Missing endian swapping for L2CAP socket list + * [Bluetooth] Restrict well known PSM to privileged users + * IB/srp: Check match_strdup() return + * IB/ehca: Fix improper use of yield() with spinlock held + * IB/ehca: Fix mismatched spin_unlock in irq handler + * vmx: Fix register constraint in launch code + * x86: fix PDA variables to work during boot + * modify 3c589_cs to be SMP safe + * Note that JFFS (v1) is to be deleted, in feature-removal-schedule.txt + * more ftape removal + * PHY: Export phy ethtool helpers + * ehea: Fixed wrong dereferencation + * ehea: Fixing firmware queue config issue + * ehea: Modified initial autoneg state determination + * ehea: New method to determine number of available ports + * ehea: Improved logging of permission issues + * ehea: Added logging off associated errors + * ehea: Fixed possible nullpointer access + * NetXen: Firmware check modifications + * NetXen: Use pci_register_driver() instead of pci_module_init() in + init_module + * [ALSA] Repair snd-usb-usx2y over OHCI + * fix "kvm: add vm exit profiling" + * Revert nmi_known_cpu() check during boot option parsing + * blockdev direct_io: fix signedness bug + * SubmitChecklist update + * paravirt: mark the paravirt_ops export internal + * KVM: make sure there is a vcpu context loaded when destroying the mmu + * KVM: fix race between mmio reads and injected interrupts + * KVM: x86 emulator: fix bit string instructions + * KVM: fix bogus pagefault on writable pages + * rtc-sh: act on rtc_wkalrm.enabled when setting an alarm + * fix blk_direct_IO bio preparation + * tlclk: bug fix + misc fixes + * mbind: restrict nodes to the currently allowed cpuset + * resierfs: avoid tail packing if an inode was ever mmapped + * Kdump documentation update: kexec-tools update + * Kdump documentation update: ia64 portion + * acpi: remove "video device notify" message + * [MIPS] SMTC: Instant IPI replay. + * [MIPS] Vr41xx: Fix after GENERIC_HARDIRQS_NO__DO_IRQ change + * elevator: move clearing of unplug flag earlier + * notifiers: fix blocking_notifier_call_chain() scalability + * funsoft: ktermios fix + * horizon.c: missing __devinit + * s2io bogus memset + * fix prototype of csum_ipv6_magic() (ia64) + * correct sys_shmget allocation check + * s2io bogus memset + * mv643xx_eth: Fix race condition in mv643xx_eth_free_tx_descs + * Clear spurious irq stat information when adding irq handler + * email change for shemminger@osdl.org + * Change Linus' email address too + * V4L/DVB (5123): Buf_qbuf: fix: videobuf_queue->stream corruption and + lockup + * [IPSEC] flow: Fix potential memory leak + * [IPV6] MCAST: Fix joining all-node multicast group on device + initialization. + * [SELINUX]: increment flow cache genid + * [NETFILTER]: ctnetlink: fix leak in ctnetlink_create_conntrack error + path + * [NETFILTER]: fix xt_state compile failure + * [SCTP]: Set correct error cause value for missing parameters + * [SCTP]: Verify some mandatory parameters. + * [SCTP]: Correctly handle unexpected INIT-ACK chunk. + * [SCTP]: Fix SACK sequence during shutdown + * [X.25]: Add missing sock_put in x25_receive_data + * [IrDA]: irda-usb TX path optimization (was Re: IrDA spams logfiles - + since 2.6.19) + * [IrDA]: Removed incorrect IRDA_ASSERT() + * [IPSEC]: Policy list disorder + * [TCP]: skb is unexpectedly freed. + * [IRDA] vlsi_ir.{h,c}: remove kernel 2.4 code + * [NETFILTER]: Fix iptables ABI breakage on (at least) CRIS + * [NET]: Process include/linux/if_{addr,link}.h with unifdef + * [TCP]: rare bad TCP checksum with 2.6.19 + * [IPV6]: Fixed the size of the netlink message notified by + inet6_rt_notify(). + * [IP] TUNNEL: Fix to be built with user application. + * [SCTP]: Fix compiler warning. + * ahci: make ULi M5288 ignore interface fatal error bit + * sata_nv: don't rely on NV_INT_DEV indication with ADMA + * ahci: don't enter slumber on power down + * libata: Fixup n_elem initialization + * libata: Initialize qc->pad_len + * [POWERPC] PS3: Fix uniprocessor kernel build + * [POWERPC] ps3_free_io_irq: Fix inverted error check + * [MIPS] There is no __GNUC_MAJOR__ + * [MIPS] Fix APM build + * [MIPS] SMTC: Fix TLB sizing bug for TLB of 64 >= entries + * [MIPS] SMTC: Fix module build by exporting symbol + * [MIPS] vr41xx: need one more nop with mtc0_tlbw_hazard() + * [MIPS] Fix reported amount of freed memory - it's in kB not bytes + * [MIPS] VPE loader: Initialize lists before they're actually being used + ... + * [MIPS] Fix wrong checksum calculation on 64-bit MIPS + * NFS: Fix Oops in rpc_call_sync() + * NFS: Fix races in nfs_revalidate_mapping() + * [IPV4]: Fix the fib trie iterator to work with a single entry routing + tables + * [AF_PACKET]: Fix BPF handling. + * libata cmd64x: whack into a shape that looks like the documentation + * libata hpt3xn: Hopefully sort out the DPLL logic versus the vendor code + * libata: set_mode, Fix the FIXME + * Linux 2.6.20-rc6 + * [TCP]: Fix sorting of SACK blocks. + * sata_via: don't diddle with ATA_NIEN in ->freeze + * ahci: improve and limit spurious interrupt messages, take#3 + * libata: implement ATA_FLAG_IGN_SIMPLEX and use it in sata_uli + * libata-sff: Don't call bmdma_stop on non DMA capable controllers + * [BNX2]: Fix 2nd port's MAC address. + * [DECNET]: Handle a failure in neigh_parms_alloc (take 2) + * x86_64: fix put_user for 64-bit constant + * [AF_PACKET]: Check device down state before hard header callbacks. + * [TCP]: Restore SKB socket owner setting in tcp_transmit_skb(). + * [NETFILTER]: nf_nat: fix ICMP translation with statically linked + conntrack + * [NETFILTER]: nf_nat_pptp: fix expectation removal + * [NETFILTER]: nf_conntrack_pptp: fix NAT setup of expected GRE + connections + * [AVR32] Export clear_page symbol + * [AVR32] Update ATSTK1000 defconfig: Enable macb by default + * Resurrect 'try_to_free_buffers()' VM hackery + * Write back inode data pages even when the inode itself is locked + * KVM: SVM: Fix SVM idt confusion + * KVM: Emulate IA32_MISC_ENABLE msr + * KVM: MMU: Perform access checks in walk_addr() + * KVM: MMU: Report nx faults to the guest + * KVM: SVM: Propagate cpu shutdown events to userspace + * S3C24XX: fix passing spi chipselect to select routine + * spi: fix error setting the spi mode in pxa2xx_spi.c + * Fix CONFIG_COMPAT_VDSO + * Fix gate_vma.vm_flags + * Add VM_ALWAYSDUMP + * i386 vDSO: use VM_ALWAYSDUMP + * x86_64 ia32 vDSO: use VM_ALWAYSDUMP + * powerpc vDSO: use VM_ALWAYSDUMP + * x86_64 ia32 vDSO: define arch_vma_name + * Fix NULL ->nsproxy dereference in /proc/*/mounts + * SPI: alternative fix for spi_busnum_to_master + * ACPI: fix cpufreq regression + * Gigaset ISDN driver error handling fixes + * knfsd: update email address and status for NFSD in MAINTAINERS + * knfsd: fix setting of ACL server versions + * knfsd: fix an NFSD bug with full sized, non-page-aligned reads + * knfsd: replace some warning ins nfsfh.h with BUG_ON or WARN_ON + * knfsd: Don't mess with the 'mode' when storing a exclusive-create + cookie + * md: update email address and status for MD in MAINTAINERS + * md: make 'repair' actually work for raid1 + * md: make sure the events count in an md array never returns to zero + * md: avoid reading past the end of a bitmap file + * 9p: fix bogus return code checks during initialization + * 9p: fix rename return code + * 9p: update documentation regarding server applications + * 9p: fix segfault caused by race condition in meta-data operations + * 9p: null terminate error strings for debug print + * dm-multipath: fix stall on noflush suspend/resume + * remove __devinit markings from rtc_sysfs_add_device() + * fix various kernel-doc in header files + * knfsd: Fix type mismatch with filldir_t used by nfsd + * md: fix potential memalloc deadlock in md + * MM: Remove invalidate_inode_pages2_range() debug + * Fix UML on non-standard VM split hosts + * md: remove unnecessary printk when raid5 gets an unaligned read. + * core-dumping unreadable binaries via PT_INTERP + * netdev: add a MAINTAINERS entry for via-velocity and update my address + * Fix race in efi variable delete code + * ahci: fix endianness in spurious interrupt message + * sata_via: style clean up, no indirect method call in LLD + * ahci: use 0x80 as wait stat value instead of 0xff + * Fix Maple PATA IRQ assignment. + * ocfs2: fix thinko in ocfs2_backup_super_blkno() + * Boot loader ID for Gujin + * [SPARC64]: Set g4/g5 properly in sun4v dtlb-prot handling. + * [SELINUX]: Fix 2.6.20-rc6 build when no xfrm + * [IPV4]: Fix single-entry /proc/net/fib_trie output. + * [POWERPC] PS3: add not complete comment to kconfig + * [POWERPC] Fix sys_pciconfig_iobase bus matching + + -- Ben Collins Sat, 06 Jan 2007 13:41:11 -0500 + +linux-source-2.6.20 (2.6.20-5.7) feisty; urgency=low + + [Upstream Kernel Changes] + + * [PARTITION]: Add whole_disk attribute. + * [AGPGART] K8M890 support for amd-k8. + * [SPARC64]: Add obppath sysfs attribute for SBUS and PCI devices. + * [AGPGART] Remove unnecessary flushes when inserting and removing pages. + * [CPUFREQ] select consistently + * [CPUFREQ] Bug fix for acpi-cpufreq and cpufreq_stats oops on frequency + change notification + * [CPUFREQ] speedstep-centrino: missing space and bracket + * [AGPGART] fix detection of aperture size versus GTT size on G965 + * [AGPGART] Fix PCI-posting flush typo. + * [CPUFREQ] longhaul: Fix up unreachable code. + * [CPUFREQ] Longhaul - Fix up powersaver assumptions. + * backlight: fix backlight_device_register compile failures + * ACPI: EC: move verbose printk to debug build only + * ACPI: increase ACPI_MAX_REFERENCE_COUNT for larger systems + * ACPI: fix section mis-match build warning + * ACPI: asus_acpi: new MAINTAINER + * [AGPGART] drivers/char/agp/sgi-agp.c: check kmalloc() return value + * [CPUFREQ] Longhaul - Always guess FSB + * [CPUFREQ] Uninitialized use of cmd.val in + arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c:acpi_cpufreq_target() + * [CPUFREQ] longhaul: Kill off warnings introduced by recent changes. + * cdrom: set default timeout to 7 seconds + * ide-cd maintainer + * [SOUND] Sparc CS4231: Fix IRQ return value and initialization. + * [NET]: ifb double-counts packets + * [PKTGEN]: Convert to kthread API. + * [NET] drivers/net/loopback.c: convert to module_init() + * [NETFILTER] xt_hashlimit.c: fix typo + * [XFRM_USER]: avoid pointless void ** casts + * [AF_NETLINK]: module_put cleanup + * [X25]: proper prototype for x25_init_timers() + * [SOUND] Sparc CS4231: Use 64 for period_bytes_min + * [SUNGEM]: PHY updates & pause fixes (#2) + * Fix some ARM builds due to HID brokenness + * HID: fix help texts in Kconfig + * [NETFILTER]: compat offsets size change + * [NETFILTER]: Fix routing of REJECT target generated packets in output + chain + * [NETFILTER]: New connection tracking is not EXPERIMENTAL anymore + * [NETFILTER]: nf_nat: fix MASQUERADE crash on device down + * [NETFILTER]: ebtables: don't compute gap before checking struct type + * [TCP]: Use old definition of before + + -- Ben Collins Fri, 05 Jan 2007 01:27:26 -0500 + +linux-source-2.6.20 (2.6.20-4.6) feisty; urgency=low + + [Ben Collins] + + * acpi/ec: Quiet "evaluating _XX" messages + - GIT-SHA 312a9aed094affc358a8e22b17b209059e68252e + - Bug #77867 + + -- Ben Collins Wed, 03 Jan 2007 16:58:54 -0500 + +linux-source-2.6.20 (2.6.20-4.5) feisty; urgency=low + + [Ben Collins] + + * toshiba_acpi: Add toshset patch + - GIT-SHA 1ffa3a0ddcf076a379a1674725c80fd752e00ed9 + - Bug #73011 + * pm: Config option to disable handling of console during suspend/resume. + - GIT-SHA e301ddf3803af8e6e87048216c63f2adb3e98f10 + - Bug #56591 + * speakup: Update to latest CVS + - GIT-SHA 5f635ed9ba1cbaa1f6f3a0b1b9cba94be3129d2a + * speakup: Include jiffies.h (removed during update) + - GIT-SHA 1bbf403f5d5bb47b707fa4664c815ec42c155279 + + [Upstream Kernel Changes] + + * zd1211rw: Call ieee80211_rx in tasklet + * ieee80211softmac: Fix errors related to the work_struct changes + * ieee80211softmac: Fix mutex_lock at exit of ieee80211_softmac_get_genie + * e1000: The user-supplied itr setting needs the lower 2 bits masked off + * e1000: dynamic itr: take TSO and jumbo into account + * e1000: For sanity, reformat e1000_set_mac_type(), struct + e1000_hw[_stats] + * e1000: omit stats for broken counter in 82543 + * e1000: consolidate managability enabling/disabling + * e1000: Fix Wake-on-Lan with forced gigabit speed + * e1000: disable TSO on the 82544 with slab debugging + * e1000: workaround for the ESB2 NIC RX unit issue + * e1000: fix to set the new max frame size before resetting the adapter + * e1000: fix ethtool reported bus type for older adapters + * e1000: narrow down the scope of the tipg timer tweak + * e1000: Fix PBA allocation calculations + * e1000: Make the copybreak value a module parameter + * e1000: 3 new driver stats for managability testing + * e1000: No-delay link detection at interface up + * netxen: remove private ioctl + * netpoll: drivers must not enable IRQ unconditionally in their NAPI + handler + * r8169: use the broken_parity_status field in pci_dev + * myri10ge: match number of save_state and restore + * myri10ge: move request_irq to myri10ge_open + * myri10ge: make msi configurable at runtime through sysfs + * myri10ge: no need to save MSI and PCIe state in the driver + * myri10ge: handle failures in suspend and resume + * e1000: Do not truncate TSO TCP header with 82544 workaround + * via-velocity uses INET interfaces + * sky2: dual port NAPI problem + * sky2: power management/MSI workaround + * sky2: phy power down needs PCI config write enabled + * ep93xx: some minor cleanups to the ep93xx eth driver + * PHY probe not working properly for ibm_emac (PPC4xx) + * NetXen: Adding new device ids. + * NetXen: driver reload fix for newer firmware. + * NetXen: Using correct CHECKSUM flag. + * NetXen: Multiple adapter fix. + * NetXen: Link status message correction for quad port cards. + * NetXen: work queue fixes. + * NetXen: Fix for PPC machines. + * NetXen: Reducing ring sizes for IOMMU issue. + * forcedeth: modified comment header + * r8169: extraneous Cmd{Tx/Rx}Enb write + * V4L/DVB (4955): Fix autosearch index + * V4L/DVB (4956): [NOVA-T-USB2] Put remote-debugging in the right place + * V4L/DVB (4958): Fix namespace conflict between w9968cf.c on MIPS + * V4L/DVB (4959): Usbvision: possible cleanups + * V4L/DVB (4960): Removal of unused code from usbvision-i2c.c + * V4L/DVB (4964): VIDEO_PALETTE_YUYV and VIDEO_PALETTE_YUV422 are the + same palette + * V4L/DVB (4967): Add missing tuner module option pal=60 for PAL-60 + support. + * V4L/DVB (4968): Add PAL-60 support for cx2584x. + * V4L/DVB (4970): Usbvision memory fixes + * V4L/DVB (4972): Dvb-core: fix bug in CRC-32 checking on 64-bit systems + * V4L/DVB (4973): Dvb-core: fix printk type warning + * V4L/DVB (4979): Fixes compilation when CONFIG_V4L1_COMPAT is not + selected + * V4L/DVB (4980): Fixes bug 7267: PAL/60 is not working + * V4L/DVB (4982): Fix broken audio mode handling for line-in in msp3400. + * V4L/DVB (4983): Force temporal filter to 0 when scaling to prevent + ghosting. + * V4L/DVB (4984): LOG_STATUS should show the real temporal filter value. + * V4L/DVB (4988): Cx2341x audio_properties is an u16, not u8 + * V4L/DVB (4990): Cpia2/cpia2_usb.c: fix error-path leak + * V4L/DVB (4991): Cafe_ccic.c: fix NULL dereference + * V4L/DVB (4992): Fix typo in saa7134-dvb.c + * V4L/DVB (4994): Vivi: fix use after free in list_for_each() + * V4L/DVB (4995): Vivi: fix kthread_run() error check + * V4L/DVB (4996): Msp3400: fix kthread_run error check + * V4L/DVB (4997): Bttv: delete duplicated ioremap() + * V4L/DVB (5014): Allyesconfig build fixes on some non x86 arch + * V4L/DVB (5001): Add two required headers on kernel 2.6.20-rc1 + * V4L/DVB (5012): Usbvision fix: It was using "&&" instead "&" + * V4L/DVB (5010): Cx88: Fix leadtek_eeprom tagging + * [S390] Change max. buffer size for monwriter device. + * [S390] cio: fix stsch_reset. + * ocfs2: don't print error in ocfs2_permission() + * ocfs2: Allow direct I/O read past end of file + * ocfs2: ignore NULL vfsmnt in ocfs2_should_update_atime() + * ocfs2: always unmap in ocfs2_data_convert_worker() + * ocfs2: export heartbeat thread pid via configfs + * VM: Fix nasty and subtle race in shared mmap'ed page writeback + * ieee1394: sbp2: pass REQUEST_SENSE through to the target + * ieee1394: sbp2: fix bogus dma mapping + * [ARM] 4063/1: ep93xx: fix IRQ_EP93XX_GPIO?MUX numbering + * [ARM] 4064/1: make pxa_get_cycles() static + * [ARM] 4065/1: S3C24XX: dma printk fixes + * [ARM] 4066/1: correct a comment about PXA's sched_clock range + * [ARM] 4071/1: S3C24XX: Documentation update + * [ARM] 4073/1: Prevent s3c24xx drivers from including + asm/arch/hardware.h and asm/arch/irqs.h + * [ARM] 4074/1: Flat loader stack alignment + * [ARM] 4077/1: iop13xx: fix __io() macro + * [ARM] 4078/1: Fix ARM copypage cache coherency problems + * Fix IPMI watchdog set_param_str() using kstrdup + * Fix lock inversion aio_kick_handler() + * powerpc iseries link error in allmodconfig + * change WARN_ON back to "BUG: at ..." + * rcu: rcutorture suspend fix + * fix oom killer kills current every time if there is memory-less-node + take2 + * Add .gitignore file for relocs in arch/i386 + * pci/probe: fix macro that confuses kernel-doc + * Char: mxser, fix oops when removing opened + * IB/mthca: Fix FMR breakage caused by kmemdup() conversion + * MAINTAINERS: email addr change for Eric Moore + * make fn_keys work again on power/macbooks + * Char: isicom, eliminate spinlock recursion + * Update to Documentation/tty.txt on line disciplines + * fix mrproper incompleteness + * sched: fix cond_resched_softirq() offset + * Fix compilation of via-pmu-backlight + * module: fix mod_sysfs_setup() return value + * ramfs breaks without CONFIG_BLOCK + * MM: SLOB is broken by recent cleanup of slab.h + * cciss: build with PROC_FS=n + * page_mkclean_one(): fix call to set_pte_at() + * SPI: define null tx_buf to mean "shift out zeroes" + * m25p80 build fixes (with MTD debug) + * SPI/MTD: mtd_dataflash oops prevention + * ARM: OMAP: fix GPMC compiler errors + * ARM: OMAP: fix missing header on apollon board + * Buglet in vmscan.c + * cpuset procfs warning fix + * respect srctree/objtree in Documentation/DocBook/Makefile + * spi_s3c24xx_gpio: use right header + * lockdep: printk warning fix + * PIIX: remove check for broken MW DMA mode 0 + * PIIX/SLC90E66: PIO mode fallback fix + * Update CREDITS and MAINTAINERS entries for Lennert Buytenhek + * KVM: Use boot_cpu_data instead of current_cpu_data + * KVM: Simplify is_long_mode() + * KVM: Initialize kvm_arch_ops on unload + * KVM: Implement a few system configuration msrs + * KVM: Move common msr handling to arch independent code + * KVM: More msr misery + * KVM: Rename some msrs + * KVM: Fix oops on oom + * kvm: fix GFP_KERNEL allocation in atomic section in + kvm_dev_ioctl_create_vcpu() + * sparc32: add offset in pci_map_sg() + * fuse: fix typo + * [SPARC64]: Fix "mem=xxx" handling. + * [SPARC64]: Fix of_iounmap() region release. + * [SPARC64]: Update defconfig. + * [SPARC64]: Handle ISA devices with no 'regs' property. + * [NET]: Add memory barrrier to netif_poll_enable() + * [NET]: Don't export linux/random.h outside __KERNEL__. + * [XFRM]: Algorithm lookup using .compat name + * restore ->pdeath_signal behaviour + * sound: hda: detect ALC883 on MSI K9A Platinum motherboards (MS-7280) + * libata: fix combined mode + * cfq-iosched: merging problem + * selinux: fix selinux_netlbl_inode_permission() locking + * Fix insta-reboot with "i386: Relocatable kernel support" + * [ARM] Fix VFP initialisation issue for SMP systems + * [ARM] 4080/1: Fix for the SSCR0_SlotsPerFrm macro + * [ARM] 4081/1: Add definition for TI Sync Serial Protocol + * x86_64: Fix dump_trace() + + -- Ben Collins Mon, 25 Dec 2006 19:30:22 -0500 + +linux-source-2.6.20 (2.6.20-3.4) feisty; urgency=low + + * Fix FTBFS due to changes in kernel-wedge. + + [Ben Collins] + + * ubuntu/media/usbvideo: Add USB Video Class driver (iSight) + - GIT-SHA a948310ffdeb5d8dddff193aa31da63039d985d5 + * ubuntu/media: Add usbvideo to build. + - GIT-SHA 545ee922c0c492929eaa0a4c675c0f6d3dbc4cfd + * prism2: Fix incorrect conversion of work queue. + - GIT-SHA 44e61605e7d160397082028780da4f749c13db00 + - Bug #76220 + * uvcvideo: Fix usb urb callback prototypes. + - GIT-SHA 4aea9254ec30b7422ca59a617f6a59d951e0769e + * debian/config: Disable speedstep_centrino in favor of acpi_cpufreq. + - GIT-SHA 2a0e7ef37fb8db5953f4c467219552835d7dddd8 + * Fix compile breakage. Patch taken from lkml (will be reverted). + - GIT-SHA 93a714f337c0636b72d605400f41347c4465a344 + * Add ivtv firmware. + - GIT-SHA 9ed1a41d11cffb205f425cc71e7f6c605b284d25 + * sata_svw: Check for error from ata_device_ata() + - GIT-SHA 4b0e1e03cb077b5659d656d8b869c11e2ae47f94 + - Bug #76391 + * pmu-backlight: Fixup for change in backlight_register. + - GIT-SHA c4f21571091b0b7eb798b1e76956b53475bcb5d8 + + [Upstream Kernel Changes] + + * ACPI: Remove unnecessary from/to-void* and to-void casts in + drivers/acpi + * ACPI: avoid gcc warnings in ACPI mutex debug code + * ACPI: uninline ACPI global locking functions + * ACPI: acpi-cpufreq: remove unused data when !CONFIG_SMP + * ACPI: ibm_acpi: Add support for the generic backlight device + * ACPI: asus_acpi: Add support for the generic backlight device + * ACPI: toshiba_acpi: Add support for the generic backlight device + * ACPI: make ec_transaction not extern + * ACPI: optimize pci_rootbridge search + * ACPI: dock: use mutex instead of spinlock + * ACPI: S4: Use "platform" rather than "shutdown" mode by default + * ACPI: Get rid of 'unused variable' warning in + acpi_ev_global_lock_handler() + * ACPI: update comment + * ACPI: button: register with input layer + * ACPI: ibm-acpi: new ibm-acpi maintainer + * ACPI: ibm-acpi: do not use / in driver names + * ACPI: ibm-acpi: trivial Lindent cleanups + * ACPI: ibm-acpi: Use a enum to select the thermal sensor reading + strategy + * ACPI: ibm-acpi: Implement direct-ec-access thermal reading modes for up + to 16 sensors + * ACPI: ibm-acpi: document thermal sensor locations for the A31 + * ACPI: ibm-acpi: prepare to cleanup fan_read and fan_write + * ACPI: ibm-acpi: clean up fan_read + * ACPI: ibm-acpi: break fan_read into separate functions + * ACPI: ibm-acpi: cleanup fan_write + * ACPI: ibm-acpi: document fan control + * ACPI: ibm-acpi: extend fan status functions + * ACPI: ibm-acpi: fix and extend fan enable + * ACPI: ibm-acpi: fix and extend fan control functions + * ACPI: ibm-acpi: store embedded controller firmware version for matching + * ACPI: ibm-acpi: workaround for EC 0x2f initialization bug + * ACPI: ibm-acpi: implement fan watchdog command + * ACPI: ibm-acpi: add support for the ultrabay on the T60,X60 + * ACPI: ibm-acpi: make non-generic bay support optional + * ACPI: ibm-acpi: backlight device cleanup + * ACPI: ibm-acpi: style fixes and cruft removal + * ACPI: ibm-acpi: update version and copyright + * ACPI: dock: Make the dock station driver a platform device driver. + * ACPI: dock: fix build warning + * ACPI: dock: Add a docked sysfs file to the dock driver. + * ACPI: dock: Fix symbol conflict between acpiphp and dock + * ACPI: ec: Allow for write semantics in any command. + * ACPI: ec: Enable EC GPE at beginning of transaction + * ACPI: ec: Increase timeout from 50 to 500 ms to handle old slow + machines. + * ACPI: ec: Read status register from check_status() function + * ACPI: ec: Remove expect_event and all races around it. + * ACPI: ec: Remove calls to clear_gpe() and enable_gpe(), as these are + handled at + * ACPI: ec: Query only single query at a time. + * ACPI: ec: Change semaphore to mutex. + * ACPI: ec: Rename gpe_bit to gpe + * ACPI: ec: Drop udelay() from poll mode. Loop by reading status field + instead. + * ACPI: ec: Acquire Global Lock under EC mutex. + * ACPI: ec: Style changes. + * ACPI: ec: Change #define to enums there possible. + * ACPI: ec: Lindent once again + * drm: fix return value check + * DRM: handle pci_enable_device failure + * i915_vblank_tasklet: Try harder to avoid tearing. + * [CPUFREQ] fixes typo in cpufreq.c + * [CPUFREQ] Trivial cleanup for acpi read/write port in acpi-cpufreq.c + * Generic HID layer - build: USB_HID should select HID + * input/hid: Supporting more keys from the HUT Consumer Page + * Generic HID layer - update MAINTAINERS + * ACPI: dock: add uevent to indicate change in device status + * drm: Unify radeon offset checking. + * [DLM] fix compile warning + * [GFS2] Fix Kconfig + * IB: Fix ib_dma_alloc_coherent() wrapper + * IB/srp: Fix FMR mapping for 32-bit kernels and addresses above 4G + * Fix "delayed_work_pending()" macro expansion + * IB/mthca: Add HCA profile module parameters + * IB/mthca: Use DEFINE_MUTEX() instead of mutex_init() + * Pull ec into test branch + * Pull dock into test branch + * Pull button into test branch + * Pull platform-drivers into test branch + * ACPI: ibm_acpi: respond to workqueue update + * Pull trivial into test branch + * ACPI: fix git automerge failure + * Pull bugfix into test branch + * Pull style into test branch + * ata_piix: IDE mode SATA patch for Intel ICH9 + * ata_piix: use piix_host_stop() in ich_pata_ops + * [libata] use kmap_atomic(KM_IRQ0) in SCSI simulator + * [libata] sata_svw: Disable ATAPI DMA on current boards (errata + workaround) + * libata: don't initialize sg in ata_exec_internal() if DMA_NONE (take + #2) + * ahci: do not mangle saved HOST_CAP while resetting controller + * ata: fix platform_device_register_simple() error check + * initializer entry defined twice in pata_rz1000 + * Fix help text for CONFIG_ATA_PIIX + * pata_via: Cable detect error + * Fix incorrect user space access locking in mincore() + * Make workqueue bit operations work on "atomic_long_t" + * Fix up mm/mincore.c error value cases + * m68k trivial build fixes + * sys_mincore: s/max/min/ + * [ARM] Add more syscalls + * [SPARC64]: Kill no-remapping-needed code in head.S + * [SPARC64]: Minor irq handling cleanups. + * [DocBook]: Fix two typos in generic IRQ docs. + * [SUNKBD]: Fix sunkbd_enable(sunkbd, 0); obvious. + * [SPARC64]: Mirror x86_64's PERCPU_ENOUGH_ROOM definition. + * [SPARC]: Update defconfig. + * [CPUFREQ] set policy->curfreq on initialization + * [ARM] Fix BUG()s in ioremap() code + * [ARM] 4034/1: pxafb: Fix compile errors + * [ARM] 4035/1: fix collie compilation + * [ARM] 4038/1: S3C24XX: Fix copyrights in include/asm-arm/arch-s3c2410 + (core) + * [ARM] 4039/1: S3C24XX: Fix copyrights in include/asm-arm/arch-s3c2410 + (mach) + * [ARM] 4040/1: S3C24XX: Fix copyrights in arch/arm/mach-s3c2410 + * [ARM] 4041/1: S3C24XX: Fix sparse errors from VA addresses + * [ARM] 4042/1: H1940: Fix sparse errors from VA addresses + * [ARM] 4043/1: S3C24XX: fix sparse warnings in + arch/arm/mach-s3c2410/s3c2440-clock.c + * [ARM] 4044/1: S3C24XX: fix sparse warnings in + arch/arm/mach-s3c2410/s3c2442-clock.c + * [ARM] 4045/1: S3C24XX: remove old VA for non-shared areas + * [ARM] 4046/1: S3C24XX: fix sparse errors arch/arm/mach-s3c2410 + * [ARM] 4048/1: S3C24XX: make s3c2410_pm_resume() static + * [ARM] 4049/1: S3C24XX: fix sparse warning due to upf_t in regs-serial.h + * [ARM] 4050/1: S3C24XX: remove old changelogs in arch/arm/mach-s3c2410 + * [ARM] 4051/1: S3C24XX: clean includes in S3C2440 and S3C2442 support + * [CPUFREQ] Advise not to use longhaul on VIA C7. + * [CPUFREQ] longhaul compile fix. + * [ARM] Fix warnings from asm/system.h + * [ARM] 4052/1: S3C24XX: Fix PM in arch/arm/mach-s3c2410/Kconfig + * [ARM] 4054/1: ep93xx: add HWCAP_CRUNCH + * [ARM] 4055/1: iop13xx: fix phys_io/io_pg_offst for iq81340mc/sc + * [ARM] 4056/1: iop13xx: fix resource.end off-by-one in flash setup + * [ARM] 4057/1: ixp23xx: unconditionally enable hardware coherency + * [ARM] 4015/1: s3c2410 cpu ifdefs + * [SPARC]: Make bitops use same spinlocks as atomics. + * more work_struct fixes: tas300x sound drivers + * [TG3]: replace kmalloc+memset with kzalloc + * [AX.25]: Mark all kmalloc users __must_check + * [AX.25]: Fix unchecked ax25_protocol_register uses. + * [AX.25]: Fix unchecked ax25_listen_register uses + * [AX.25]: Fix unchecked nr_add_node uses. + * [AX.25]: Fix unchecked ax25_linkfail_register uses + * [AX.25]: Fix unchecked rose_add_loopback_node uses + * [AX.25]: Fix unchecked rose_add_loopback_neigh uses + * [BNX2]: Fix panic in bnx2_tx_int(). + * [BNX2]: Fix bug in bnx2_nvram_write(). + * [BNX2]: Fix minor loopback problem. + * [NETFILTER] IPV6: Fix dependencies. + * [TG3]: Assign tp->link_config.orig_* values. + * [TG3]: Fix race condition when calling register_netdev(). + * [TG3]: Power down/up 5906 PHY correctly. + * [TG3]: Update version and reldate. + * [CONNECTOR]: Fix compilation breakage introduced recently. + * [TCP]: Fix oops caused by tcp_v4_md5_do_del + * [TCP]: Trivial fix to message in tcp_v4_inbound_md5_hash + * [IPV4]: Fix BUG of ip_rt_send_redirect() + * [CONNECTOR]: Replace delayed work with usual work queue. + * cciss: set default raid level when reading geometry fails + * cciss: fix XFER_READ/XFER_WRITE in do_cciss_request + * drm: savage: compat fix from drm git. + * drm: fixup comment header style + * drm: make kernel context switch same as for drm git tree. + * drm: r128: comment aligment with drm git + * drm: Stop defining pci_pretty_name + * ->nr_sectors and ->hard_nr_sectors are not used for BLOCK_PC requests + * Remove queue merging hooks + * __blk_rq_map_user() doesn't need to grab the queue_lock + * __blk_rq_unmap_user() fails to return error + * Fixup blk_rq_unmap_user() API + * [PARTITION]: Add whole_disk attribute. + * [POWERPC] cell: update cell_defconfig + * [POWERPC] cell: add forward struct declarations to spu.h + * [POWERPC] cell: Enable spider workarounds on all PCI buses + * [POWERPC] cell: Fix spufs with "new style" device-tree + * [POWERPC] spufs: fix assignment of node numbers + * [POWERPC] powerpc: add scanning of ebc bus to of_platform + * [ARM] 4022/1: iop13xx: generic irq fixups + * [ARM] 4059/1: VR1000: fix LED3's platform device number + * [ARM] 4061/1: xsc3: change of maintainer + * [ARM] 4060/1: update several ARM defconfigs + * [ARM] 4062/1: S3C24XX: Anubis and Osiris shuld have CONFIG_PM_SIMTEC + * ACPI: ibm_acpi: allow clean removal + * ACPI: fix single linked list manipulation + * ACPI: prevent processor module from loading on failures + * [POWERPC] Workaround oldworld OF bug with IRQs & P2P bridges + * [POWERPC] iSeries: fix viodasd init + * [POWERPC] iSeries: fix viotape init + * [POWERPC] iSeries: fix iseries_veth init + * [POWERPC] iSeries: fix viocd init + * [POWERPC] iSeries: fix viocons init + * [POWERPC] iSeries: fix CONFIG_VIOPATH dependency + * [POWERPC] Fix build of cell zImage.initrd + * [POWERPC] Probe Efika platform before CHRP. + * [POWERPC] Update MTD OF documentation + * [POWERPC] Fix PCI device channel state initialization + * [POWERPC] Fix register save area alignment for swapcontext syscall + * ACPI: make drivers/acpi/ec.c:ec_ecdt static + * ACPI: fix NULL check in drivers/acpi/osl.c + * ACPI: Kconfig - depend on PM rather than selecting it + * ACPI: Implement acpi_video_get_next_level() + * ACPI: video: Add dev argument for backlight_device_register + * fbdev: update after backlight argument change + * ACPI: Add support for acpi_load_table/acpi_unload_table_id + * Pull platform-drivers into test branch + * Pull ec into test branch + * Pull bugfix into test branch + * merge linus into test branch + * Pull sgi into test branch + * [ALSA] via82xx: add __devinitdata + * [ALSA] sound/usb/usbaudio: Handle return value of usb_register() + * [ALSA] sound: Don't include i2c-dev.h + * [ALSA] ac97_codec (ALC655): add EAPD hack for MSI L725 laptop + * [ALSA] use the ALIGN macro + * [ALSA] use the roundup macro + * [ALSA] ymfpci: fix swap_rear for S/PDIF passthrough + * [ALSA] hda-codec - Fix wrong error checks in patch_{realtek,analog}.c + * [ALSA] hda-codec - Don't return error at initialization of modem codec + * [ALSA] hdsp: precise_ptr control switched off by default + * [ALSA] hda-codec - Fix a typo + * [ALSA] pcm core: fix silence_start calculations + * [ALSA] hda-codec - Add model for HP q965 + * [ALSA] sound/core/control.c: remove dead code + * [ALSA] hda-codec - Fix model for ASUS V1j laptop + * [ALSA] hda-codec - Fix detection of supported sample rates + * [ALSA] hda-codec - Verbose proc output for PCM parameters + * [ALSA] ac97 - Fix potential negative array index + * [ALSA] hda-codec - fix typo in PCI IDs + * [ALSA] Fix races in PCM OSS emulation + * [ALSA] Fix invalid assignment of PCI revision + * [ALSA] Remove IRQF_DISABLED for shared PCI irqs + * [ALSA] snd_hda_intel 3stack mode for ASUS P5P-L2 + * [ALSA] sound: initialize rawmidi substream list + * [ALSA] sound: fix PCM substream list + * [ALSA] snd-ca0106: Add new card variant. + * [ALSA] snd-ca0106: Fix typos. + * [ALSA] ac97_codec - trivial fix for bit update functions + * [ALSA] ac97: Identify CMI9761 chips. + * [ALSA] version 1.0.14rc1 + * cfq-iosched: don't allow sync merges across queues + * block: document io scheduler allow_merge_fn hook + * [libata] pata_cs5530: suspend/resume support tweak + * [libata] pata_via: suspend/resume support fix + * USB: Fix oops in PhidgetServo + * USB: fix transvibrator disconnect race + * USB: airprime: add device id for dell wireless 5500 hsdpa card + * USB: ftdi_sio - MachX product ID added + * USB: removing ifdefed code from gl620a + * usb serial: Eliminate bogus ioctl code + * USB: mutexification of usblp + * Add Baltech Reader ID to CP2101 driver + * USB: Prevent the funsoft serial device from entering raw mode + * USB: fix ohci.h over-use warnings + * USB: rtl8150 new device id + * usb-storage: Ignore the virtual cd-drive of the Huawei E220 USB Modem + * usb-gsm-driver: Added VendorId and ProductId for Huawei E220 USB Modem + * USB: fix Wacom Intuos3 4x6 bugs + * USB AUERSWALD: replace kmalloc+memset with kzalloc + * USB: Nokia E70 is an unusual device + * UHCI: module parameter to ignore overcurrent changes + * USB: gadget driver unbind() is optional; section fixes; misc + * USB: MAINTAINERS update, EHCI and OHCI + * USB: ohci whitespace/comment fixups + * USB: ohci at91 warning fix + * USB: ohci handles hardware faults during root port resets + * USB: OHCI support for PNX8550 + * USB: at91 udc, support at91sam926x addresses + * USB: at91_udc, misc fixes + * USB: u132-hcd/ftdi-elan: add support for Option GT 3G Quad card + * USB: at91_udc: allow drivers that support high speed + * USB: at91_udc: Cleanup variables after failure in + usb_gadget_register_driver() + * USB: at91_udc: Additional checks + * USB: fix to usbfs_snoop logging of user defined control urbs + * PCI: use /sys/bus/pci/drivers//new_id first + * pci: add class codes for Wireless RF controllers + * PCI quirks: remove redundant check + * rpaphp: compiler warning cleanup + * PCI: pcieport-driver: remove invalid warning message + * pci: Introduce pci_find_present + * PCI: Create __pci_bus_find_cap_start() from __pci_bus_find_cap() + * PCI: Add pci_find_ht_capability() for finding Hypertransport + capabilities + * PCI: Use pci_find_ht_capability() in drivers/pci/htirq.c + * PCI: Add #defines for Hypertransport MSI fields + * PCI: Use pci_find_ht_capability() in drivers/pci/quirks.c + * PCI: Only check the HT capability bits in mpic.c + * PCI: Fix multiple problems with VIA hardware + * PCI: Be a bit defensive in quirk_nvidia_ck804() so we don't risk + dereferencing a NULL pdev. + * PCI: don't export device IDs to userspace + * PCI legacy resource fix + * PCI: ATI sb600 sata quirk + * shpchp: remove unnecessary struct php_ctlr + * shpchp: cleanup struct controller + * shpchp: remove shpchprm_get_physical_slot_number + * shpchp: cleanup shpchp.h + * acpiphp: Link-time error for PCI Hotplug + * kref refcnt and false positives + * kobject: kobject_uevent() returns manageable value + * Driver core: proper prototype for drivers/base/init.c:driver_init() + * [libata] Move some PCI IDs from sata_nv to ahci + * libata: clean up variable name usage in xlat related functions + * libata: kill @cdb argument from xlat methods + * libata: take scmd->cmd_len into account when translating SCSI commands + * USB: Nokia E70 is an unusual device + * usb serial: add support for Novatel S720/U720 CDMA/EV-DO modems + * bluetooth: add support for another Kensington dongle + * [libata] sata_svw, sata_vsc: kill iomem warnings + * USB Storage: remove duplicate Nokia entry in unusual_devs.h + * ACPI: replace kmalloc+memset with kzalloc + * __set_irq_handler bogus space + * x86_64: fix boot hang caused by CALGARY_IOMMU_ENABLED_BY_DEFAULT + * x86_64: fix boot time hang in detect_calgary() + * sched: improve efficiency of sched_fork() + * fix leaks on pipe(2) failure exits + * workqueue: fix schedule_on_each_cpu() + * Clean up and make try_to_free_buffers() not race with dirty pages + * VM: Remove "clear_page_dirty()" and "test_clear_page_dirty()" functions + * Fix JFS after clear_page_dirty() removal + * fuse: remove clear_page_dirty() call + * Fix XFS after clear_page_dirty() removal + * elevator: fixup typo in merge logic + * truncate: dirty memory accounting fix + * KVM: add valid_vcpu() helper + * KVM: AMD SVM: handle MSR_STAR in 32-bit mode + * KVM: AMD SVM: Save and restore the floating point unit state + * KVM: Use more traditional error handling in kvm_mmu_init() + * KVM: Do not export unsupported msrs to userspace + * KVM: Force real-mode cs limit to 64K + * KVM: Handle p5 mce msrs + * KVM: API versioning + * CONFIG_VM_EVENT_COUNTER comment decrustify + * Conditionally check expected_preempt_count in __resched_legal() + * Fix for shmem_truncate_range() BUG_ON() + * rtc warning fix + * slab: fix kmem_ptr_validate definition + * fix kernel-doc warnings in 2.6.20-rc1 + * make kernel/printk.c:ignore_loglevel_setup() static + * fs/sysv/: proper prototypes for 2 functions + * Fix swapped parameters in mm/vmscan.c + * Add cscope generated files to .gitignore + * sched: remove __cpuinitdata anotation to cpu_isolated_map + * fix vm_events_fold_cpu() build breakage + * genirq: fix irq flow handler uninstall + * smc911x: fix netpoll compilation faliure + * smc911 workqueue fixes + * fsstack: Remove inode copy + * lock debugging: fix DEBUG_LOCKS_WARN_ON() & debug_locks_silent + * Make JFFS depend on CONFIG_BROKEN + * Add a new section to CodingStyle, promoting include/linux/kernel.h + * fix aoe without scatter-gather [Bug 7662] + * mm: more rmap debugging + * handle SLOB with sparsemen + * compile error of register_memory() + * audit: fix kstrdup() error check + * gss_spkm3: fix error handling in module init + * schedule_timeout(): improve warning message + * microcode: fix mc_cpu_notifier section warning + * MAINTAINERS: fix email for S3C2410 and S3C2440 + * tlclk: delete unnecessary sysfs_remove_group + * gxt4500: Fix colormap and PLL setting, support GXT6000P + * fdtable: Provide free_fdtable() wrapper + * kernel-doc: allow unnamed structs/unions + * kernel-doc: remove Martin from MAINTAINERS + * mips: if_fddi.h: Add a missing inclusion + * memory hotplug: fix compile error for i386 with NUMA config + * ptrace: Fix EFL_OFFSET value according to i386 pda changes + * relay: remove inlining + * increase CARDBUS_MEM_SIZE + * md: fix a few problems with the interface (sysfs and ioctl) to md + * fix s3c24xx gpio driver (include linux/workqueue.h) + * jbd: wait for already submitted t_sync_datalist buffer to complete + * sched: fix bad missed wakeups in the i386, x86_64, ia64, ACPI and APM + idle code + * build compile.h earlier + * Fix reparenting to the same thread group. (take 2) + * serial/uartlite: Only enable port if request_port succeeded + * Fix up page_mkclean_one(): virtual caches, s390 + * NetLabel: perform input validation earlier on CIPSOv4 DOI add ops + * NetLabel: correctly fill in unused CIPSOv4 level and category mappings + * [ATM]: Remove dead ATM_TNETA1570 option. + * [ATM] drivers/atm/fore200e.c: Cleanups. + * [TCP]: Fix ambiguity in the `before' relation. + * [SCTP]: Don't export include/linux/sctp.h to userspace. + * [SCTP]: Fix typo adaption -> adaptation as per the latest API draft. + * [SCTP]: make 2 functions static + * [IPV6]: Dumb typo in generic csum_ipv6_magic() + * [UDP]: Fix reversed logic in udp_get_port(). + * cfq-iosched: tighten allow merge criteria + * Call init_timer() for ISDN PPP CCP reset state timer + * Clean up and export cancel_dirty_page() to modules + * Fix reiserfs after "test_clear_page_dirty()" removal + * suspend: fix suspend on single-CPU systems + * arch/i386/pci/mmconfig.c tlb flush fix + * Fix up CIFS for "test_clear_page_dirty()" removal + * Linux 2.6.20-rc2 + + -- Ben Collins Sat, 16 Dec 2006 01:56:51 -0500 + +linux-source-2.6.20 (2.6.20-2.2) feisty; urgency=low + + [Ben Collins] + + * debian/config: Enable pata_marvell. + - GIT-SHA 8140eb247a50883afe037f57d4afd143cee902a6 + * ivtv: Add new mpeg encoder driver. + - GIT-SHA fc0ee3058f7ae7096235648aa1dbdf114fa3fc58 + * ubuntu/media: Add ivtv to build. + - GIT-SHA 4850a6d86424b28f967e2eab425152ba4f4147e8 + * ubuntu/ivtv: Build fixes for 2.6.20 (INIT_WORK). + - GIT-SHA fa28b2f82bba8c1bb014ab7de500d48b77404abf + * debian/d-i/package-list: Add nic-firmware + - GIT-SHA 42e1278480fe3c33e5c14fb056c34718fac5e713 + - Bug #73896 + * debian/d-i: Split out nfs modules into nfs-modules. + - GIT-SHA 941250b257eb8bbe7ad811fa56c6ec4973ec6545 + - Bug #73910 + * debian/d-i: Add cdrom modules + - GIT-SHA c2670818134e76c571cbc17aa26551d0064305e0 + - Bug #73911 + * include/asm-*/setup.h: Set command line size to 1024 + - GIT-SHA 3812de95f1b4d800081e7f06c5b9bc9c3873003c + - Bug #23716 + * debian/d-i: Add block and message udeb's. + - GIT-SHA 6e997e89249bfd8bbc20bf1f0349fb0bccde2d95 + * ide/piix: ifdef out some pci id's when ata_piix is enabled. + - GIT-SHA d28a0a771e1c30c5b89999e5c51e33471a6f6ed2 + + [Upstream Kernel Changes] + + * [CPUFREQ] Documentation fix + * [CPUFREQ][1/8] acpi-cpufreq: software coordination and handle all CPUs + in the group + * [CPUFREQ][2/8] acpi: reorganize code to make MSR support addition + easier + * [CPUFREQ][3/8] acpi-cpufreq: Pull in MSR based transition support + * [CPUFREQ][4/8] acpi-cpufreq: Mark speedstep-centrino ACPI as deprecated + * [CPUFREQ][5/8] acpi-cpufreq: lindent acpi-cpufreq.c + * [CPUFREQ][6/8] acpi-cpufreq: Eliminate get of current freq on + notification + * [CPUFREQ][7/8] acpi-cpufreq: Fix get of current frequency breakage + * [CPUFREQ][8/8] acpi-cpufreq: Add support for freq feedback from + hardware + * [CPUFREQ] sc520_freq.c: ioremap balanced with iounmap + * [CPUFREQ] Fix speedstep-smi CPU detection to not run on Pentium 4. + * [CPUFREQ] Remove duplicate include from acpi-cpufreq + * [CPUFREQ] acpi-cpufreq: Fix up some CodingStyle nits leftover from the + lindenting. + * [CPUFREQ] handle sysfs errors + * [CPUFREQ] speedstep-centrino: remove dead code + * [CPUFREQ] ifdef more unused on !SMP code. + * [AGPGART] Fix up misprogrammed bridges with incorrect AGPv2 rates. + * [CPUFREQ] Fix coding style issues in cpufreq. + * [CPUFREQ] p4-clockmod: add more CPUs + * [CPUFREQ] speedstep-centrino should ignore upper performance control + bits + * [CPUFREQ] Fix build failure on x86-64 + * JFS: Fix conflicting superblock flags + * [WATCHDOG] rm9k_wdt: fix compilation + * [WATCHDOG] rm9k_wdt: fix interrupt handler arguments + * [WATCHDOG] watchdog miscdevice patch + * ocfs2: local mounts + * ocfs2: update mount option documentation + * ocfs2: Synchronize feature incompat flags in ocfs2_fs.h + * [patch 1/3] OCFS2 - Expose struct o2nm_cluster + * [patch 2/3] OCFS2 Configurable timeouts + * [ARM] 4010/1: AT91SAM9260-EK board: Prepare for MACB Ethernet support + * [ARM] 4011/1: AT91SAM9260: Fix compilation with NAND driver + * [ARM] Handle HWCAP_VFP in VFP support code + * [ARM] Formalise the ARMv6 processor name string + * [ARM] 4004/1: S3C24XX: UDC remove implict addition of VA to regs + * [ARM] Add sys_*at syscalls + * i2c: Fix documentation typos + * i2c: Update the list of driver IDs + * i2c: Delete the broken i2c-ite bus driver + * i2c: New Philips PNX bus driver + * i2c: Add request/release_mem_region to i2c-ibm_iic bus driver + * i2c: Cleanups to the i2c-nforce2 bus driver + * i2c: Add support for nested i2c bus locking + * i2c: New Atmel AT91 bus driver + * i2c: Use put_user instead of copy_to_user where possible + * i2c: Whitespace cleanups + * i2c: Use the __ATTR macro where possible + * i2c: i2c-i801 documentation update + * i2c: fix broken ds1337 initialization + * i2c: New ARM Versatile/Realview bus driver + * i2c: Discard the i2c algo del_bus wrappers + * i2c: Enable PEC on more i2c-i801 devices + * i2c: Fix return value check in i2c-dev + * i2c: Refactor a kfree in i2c-dev + * i2c: Fix OMAP clock prescaler to match the comment + * [patch 3/3] OCFS2 Configurable timeouts - Protocol changes + * [ARM] Clean up KERNEL_RAM_ADDR + * sh: Reworked swap cache entry encoding for SH-X2 MMU. + * sh: Shut up csum_ipv6_magic() warnings. + * sh: push-switch fixups for work_struct API damage. + * sh: Add uImage and S-rec generation support. + * sh: SH-2 defconfig updates. + * sh: register rtc resources for sh775x. + * rtc: rtc-sh: fix for period rtc interrupts. + * sh: landisk board build fixes. + * sh: gcc4 symbol export fixups. + * sh: IPR IRQ updates for SH7619/SH7206. + * sh: Trivial build fixes for SH-2 support. + * sh: Fix Solution Engine 7619 build. + * sh: Split out atomic ops logically. + * serial: sh-sci: Shut up various sci_rxd_in() gcc4 warnings. + * sh: Kill off unused SE7619 I/O ops. + * rtc: rtc-sh: fix rtc for out-by-one for the month. + * rtc: rtc-sh: alarm support. + * sh: BUG() handling through trapa vector. + * sh: Fix get_wchan(). + * sh: Fixup kernel_execve() for syscall cleanups. + * sh: Convert remaining remap_area_pages() users to ioremap_page_range(). + * sh: Fixup dma_cache_sync() callers. + * sh: SH-MobileR SH7722 CPU support. + * sh: Fixup sh_bios() trap handling. + * sh: Hook up SH7722 scif ipr interrupts. + * sh: Fixup .data.page_aligned. + * sh: Fix .empty_zero_page alignment for PAGE_SIZE > 4096. + * sh: Use early_param() for earlyprintk parsing. + * sh: Fixup SH-2 BUG() trap handling. + * remove blk_queue_activity_fn + * fix SG_IO bio leak + * remove unnecessary blk_queue_bounce in SG_IO + * V4L/DVB (4954): Fix: On ia64, i2c adap->inb/adap->outb are wrongly + evaluated + * lockdep: fix seqlock_init() + * net, 8139too.c: fix netpoll deadlock + * netpoll: fix netpoll lockup + * hwmon/f71805f: Store the fan control registers + * hwmon/f71805f: Add manual fan speed control + * hwmon/f71805f: Let the user adjust the PWM base frequency + * hwmon/f71805f: Support DC fan speed control mode + * hwmon/f71805f: Add support for "speed mode" fan speed control + * hwmon/f71805f: Document the fan control features + * hwmon/pc87360: Autodetect the VRM version + * hwmon/hdaps: Move the DMI detection data to .data + * hwmon/hdaps: Update the list of supported devices + * hwmon/it87: Remove the SMBus interface support + * hwmon: New PC87427 hardware monitoring driver + * hwmon/f71805f: Add support for the Fintek F71872F/FG chip + * hwmon/f71805f: Always create all fan inputs + * hwmon/f71805f: Fix the device address decoding + * hwmon: Update Rudolf Marek's e-mail address + * hwmon: New Winbond W83793 hardware monitoring driver + * hwmon/w83793: Add documentation and maintainer + * hwmon: New AMS hardware monitoring driver + * hwmon: Add MAINTAINERS entry for new ams driver + * EXT{2,3,4}_FS: remove outdated part of the help text + * [IA64] Do not call SN_SAL_SET_CPU_NUMBER twice on cpu 0 + * Use consistent casing in help message + * [IA64] CONFIG_KEXEC/CONFIG_CRASH_DUMP permutations + * [IA64] Kexec/Kdump: honour non-zero crashkernel offset. + * [IA64] kexec/kdump: tidy up declaration of relocate_new_kernel_t + * Fix small typo in drivers/serial/icom.c + * Remove duplicate "have to" in comment + * Kconfig: fix spelling error in config KALLSYMS help text + * include/linux/compiler.h: reject gcc 3 < gcc 3.2 + * remove config ordering/dependency between ucb1400-ts and sound + subsystem + * [IA64] s/termios/ktermios/ in simserial.c + * fix typo in net/ipv4/ip_fragment.c + * um: replace kmalloc+memset with kzalloc + * e100: replace kmalloc with kcalloc + * kconfig: Standardize "depends" -> "depends on" in Kconfig files + * configfs.h: Remove dead macro definitions. + * fs: Convert kmalloc() + memset() to kzalloc() in fs/. + * Jon needs a new shift key. + * Fix typo in new debug options. + * Fix inotify maintainers entry + * [IA64] fix arch/ia64/mm/contig.c:235: warning: unused variable `nid' + * [IA64] - Reduce overhead of FP exception logging messages + * [IA64] fix possible XPC deadlock when disconnecting + * IB/fmr: ib_flush_fmr_pool() may wait too long + * IB/ipath: Remove unused "write-only" variables + * IB/iser: Remove unused "write-only" variables + * RDMA/amso1100: Fix memory leak in c2_qp_modify() + * IB/ipath: Fix IRQ for PCI Express HCAs + * RDMA/cma: Remove unneeded qp_type parameter from rdma_cm + * RDMA/cma: Report connect info with connect events + * RDMA/cma: Allow early transition to RTS to handle lost CM messages + * RDMA/cma: Add support for RDMA_PS_UDP + * RDMA/cma: Export rdma cm interface to userspace + * [IA64] Take defensive stance on ia64_pal_get_brand_info() + * [IA64] enable trap code on slot 1 + * [IA64] kprobe clears qp bits for special instructions + * [CPUFREQ] Optimize gx-suspmod revision ID fetching + * [CPUFREQ] speedstep-centrino should ignore upper performance control + bits + * [CPUFREQ] Fix the bug in duplicate freq elimination code in + acpi-cpufreq + * [CPUFREQ] Fix git URL. + * IB: Add DMA mapping functions to allow device drivers to interpose + * IB/ipath: Implement new verbs DMA mapping functions + * IB/core: Use the new verbs DMA mapping functions + * [CPUFREQ] p4-clockmod: fix support for Core + * IPoIB: Use the new verbs DMA mapping functions + * IB/srp: Use new verbs IB DMA mapping functions + * IB/iser: Use the new verbs DMA mapping functions + * [CPUFREQ] Longhaul - fix 200MHz FSB + * [CPUFREQ] Longhaul - Add support for CN400 + * [WATCHDOG] pcwd_usb.c generic HID include file + * IPoIB: Make sure struct ipoib_neigh.queue is always initialized + * [AGPGART] agp-amd64: section mismatches with HOTPLUG=n + * [AGPGART] VIA and SiS AGP chipsets are x86-only + * Propagate down request sync flag + * [PATCH 1/2] cciss: map out more memory for config table + * [PATCH 2/2] cciss: remove calls to pci_disable_device + * Allow as-iosched to be unloaded + * [ARM] Unuse another Linux PTE bit + * [ARM] Clean up ioremap code + * [ARM] 4012/1: Clocksource for pxa + * [ARM] 4013/1: clocksource driver for netx + * [ARM] 4014/1: include drivers/hid/Kconfig + * Fixup cciss error handling + * [ARM] Remove empty fixup function + * arch/i386/kernel/smpboot.c: remove unneeded ifdef + * tty: export get_current_tty + * KVM: Add missing include + * KVM: Put KVM in a new Virtualization menu + * KVM: Clean up AMD SVM debug registers load and unload + * KVM: Replace __x86_64__ with CONFIG_X86_64 + * fix more workqueue build breakage (tps65010) + * another build fix, header rearrangements (OSK) + * uml: fix net_kern workqueue abuse + * isdn/gigaset: fix possible missing wakeup + * i2o_exec_exit and i2o_driver_exit should not be __exit. + * Fix section mismatch in parainstructions + * KVM: Make the GET_SREGS and SET_SREGS ioctls symmetric + * KVM: Move find_vmx_entry() to vmx.c + * KVM: Remove extranous put_cpu() from vcpu_put() + * KVM: MMU: Ignore pcd, pwt, and pat bits on ptes + * KVM: Add MAINTAINERS entry + * vt: fix comments to not refer to kill_proc + * kconfig: new function "bool conf_get_changed(void)" + * kconfig: make sym_change_count static, let it be altered by 2 functions + only + * kconfig: add "void conf_set_changed_callback(void (*fn)(void))", use it + in qconf.cc + * kconfig: set gconf's save-widget's sensitivity according to .config's + changed state + * reorder struct pipe_buf_operations + * slab: fix sleeping in atomic bug + * Fix crossbuilding checkstack + * md: Don't assume that READ==0 and WRITE==1 - use the names explicitly + * KVM: Disallow the kvm-amd module on intel hardware, and vice versa + * KVM: Don't touch the virtual apic vt registers on 32-bit + * KVM: Fix vmx hardware_enable() on macbooks + * w1: Fix for kconfig entry typo + * isicom: fix build with PCI disabled + * mxser_new: fix non-PCI build + * sx: fix non-PCI build + * cciss: map out more memory for config table + * cciss: remove calls to pci_disable_device + * Cleanup slab headers / API to allow easy addition of new slab + allocators + * More slab.h cleanups + * cpuset: rework cpuset_zone_allowed api + * SLAB: use a multiply instead of a divide in obj_to_index() + * PM: Fix freezing of stopped tasks + * PM: Fix SMP races in the freezer + * Xtensa: Add ktermios and minor filename fix + * touch_atime() cleanup + * relative atime + * ocfs2: relative atime support + * optimize o_direct on block devices + * debug: add sysrq_always_enabled boot option + * lockdep: filter off by default + * lockdep: improve verbose messages + * lockdep: improve lockdep_reset() + * lockdep: clean up VERY_VERBOSE define + * lockdep: use chain hash on CONFIG_DEBUG_LOCKDEP too + * lockdep: print irq-trace info on asserts + * lockdep: fix possible races while disabling lock-debugging + * Use activate_mm() in fs/aio.c:use_mm() + * Fix numerous kcalloc() calls, convert to kzalloc() + * tty: remove useless memory barrier + * CONFIG_COMPUTONE should depend on ISA|EISA|PCI + * appldata_mem dependes on vm counters + * uml problems with linux/io.h + * missing includes in hilkbd + * hci endianness annotations + * lockd endianness annotations + * rtc: fx error case + * RTC driver init adjustment + * rtc: remove syslog spam on registration + * rtc framewok: rtc_wkalrm.enabled reporting updates + * tty_io.c balance tty_ldisc_ref() + * n_r3964: Use struct pid to track user space clients + * smbfs: Make conn_pid a struct pid + * ncpfs: Use struct pid to track the userspace watchdog process + * ncpfs: ensure we free wdog_pid on parse_option or fill_inode failure + * update Tigran's email addresses + * one more EXPORT_UNUSED_SYMBOL removal + * remove the broken BLK_DEV_SWIM_IOP driver + * knfsd: nfsd4: remove a dprink from nfsd4_lock + * knfsd: svcrpc: fix gss krb5i memory leak + * knfsd: nfsd4: clarify units of COMPOUND_SLACK_SPACE + * knfsd: nfsd: make exp_rootfh handle exp_parent errors + * knfsd: nfsd: simplify exp_pseudoroot + * knfsd: nfsd4: handling more nfsd_cross_mnt errors in nfsd4 readdir + * knfsd: nfsd: don't drop silently on upcall deferral + * knfsd: svcrpc: remove another silent drop from deferral code + * knfsd: nfsd4: pass saved and current fh together into nfsd4 operations + * knfsd: nfsd4: remove spurious replay_owner check + * knfsd: nfsd4: move replay_owner to cstate + * knfsd: nfsd4: don't inline nfsd4 compound op functions + * knfsd: nfsd4: make verify and nverify wrappers + * knfsd: nfsd4: reorganize compound ops + * knfsd: nfsd4: simplify migration op check + * knfsd: nfsd4: simplify filehandle check + * knfsd: Don't ignore kstrdup failure in rpc caches + * knfsd: Fix up some bit-rot in exp_export + * Optimize calc_load() + * ide: HPT3xxN clocking fixes + * ide: fix HPT37x timing tables + * ide: optimize HPT37x timing tables + * ide: fix HPT3xx hotswap support + * ide: fix the case of multiple HPT3xx chips present + * ide: HPT3xx: fix PCI clock detection + * HPT37x: read f_CNT saved by BIOS from port + * fbdev: remove references to non-existent fbmon_valid_timings() + * sstfb: add sysfs interface + * getting rid of all casts of k[cmz]alloc() calls + * Add support for Korenix 16C950-based PCI cards + * Fix COW D-cache aliasing on fork + * Pass vma argument to copy_user_highpage(). + * MIPS: Fix COW D-cache aliasing on fork + * Optimize D-cache alias handling on fork + * Add missing KORENIX PCI ID's + * [ARM] 4016/1: prefetch macro is wrong wrt gcc's + "delete-null-pointer-checks" + * [ARM] Provide a method to alter the control register + * [ARM] 3992/1: i.MX/MX1 CPU Frequency scaling support + * [IA64] Move sg_dma_{len,address} from pci.h to scatterlist.h + * [ARM] 4017/1: [Jornada7xx] - Updating Jornada720.c + * Driver core: show "initstate" of module + * driver core: delete virtual directory on class_unregister() + * DebugFS : inotify create/mkdir support + * DebugFS : coding style fixes + * DebugFS : file/directory creation error handling + * DebugFS : more file/directory creation error handling + * DebugFS : file/directory removal fix + * Driver core: "platform_driver_probe() can save codespace": save + codespace + * Driver core: Make platform_device_add_data accept a const pointer + * Driver core: deprecate PM_LEGACY, default it to N + * [NETFILTER]: Fix INET=n linking error + * [NETFILTER]: nf_nat: fix NF_NAT dependency + * [NETFILTER]: x_tables: error if ip_conntrack is asked to handle IPv6 + packets + * [NETFILTER]: x_tables: add missing try to load conntrack from + match/targets + * [NETFILTER]: ip_tables: ipt and ipt_compat checks unification + * [NETFILTER]: {ip,ip6,arp}_tables: fix exponential worst-case search for + loops + * [DCCP] ccid3: return value in ccid3_hc_rx_calc_first_li + * [IPV6]: Fix IPV6_UNICAST_HOPS getsockopt(). + * [TCP]: Fix oops caused by __tcp_put_md5sig_pool() + * [SCTP]: Handle address add/delete events in a more efficient way. + * [SCTP]: Enable auto loading of SCTP when creating an ipv6 SCTP socket. + * [SCTP]: Add support for SCTP_CONTEXT socket option. + * [IPV6]: Make fib6_node subtree depend on IPV6_SUBTREES + * Linux v2.6.20-rc1 + * ib_verbs: Use explicit if-else statements to avoid errors with do-while + macros + * [S390] update default configuration + * [S390] hypfs fixes + * [S390] Hipersocket multicast queue: make sure outbound handler is + called + * [S390] zcrypt: module unload fixes. + * [S390] sclp_cpi module license. + * [S390] Fix reboot hang on LPARs + * [S390] Fix reboot hang + * [S390] Save prefix register for dump on panic + * [S390] cio: css_register_subchannel race. + * Remove stack unwinder for now + + -- Ben Collins Wed, 13 Dec 2006 11:29:31 -0500 + +linux-source-2.6.20 (2.6.20-1.1) feisty; urgency=low + + [Ben Collins] + + * debian/: Fix lowlatency config rewrite so PREEMPT gets enabled. + - GIT-SHA 510032237707def6475ec51a206644ebf90da9c9 + * debian/: Add initramfs hook for copying firmware needed in initrd. + - GIT-SHA 2f049facd27d03ca42d0a00bcba3567ea6c43c1c + * x86: Revert patch that allows disabling hyper-threading. + - GIT-SHA a5443e2694749510381b4c54b95f5a3ee2656dcf + * debian/: Revert kernelfirmware changes in favour of initramfs-tools + solution. + - GIT-SHA b4ce570a6dff8b1acfb130e0840ef7bc1ca3194f + * forcedeth: Revert phy patch. + - GIT-SHA 3cd0410cba86a7e97535f5d7dda18a71ec91b772 + * rt2x00: Added drivers from Edgy with build fixes. + - GIT-SHA 3e684dade463576854892501ab33b3f4e6557b6a + * arch/sparc64/prom: Remove local change. + - GIT-SHA e9f507d104bbe9a1bf58671408682c095615c93d + * ndsiwrapper: Added driver + - GIT-SHA d11fd0dd38f5e903108e6205e38dfcf84ea149c6 + * ubuntu/: Compile fixes for header changes in 2.6.20 + - GIT-SHA 9fe44155276658fad4afab56bd80229bb9b903dc + * ubuntu/wireless/rt2x00: Add eeprom module to Makefile. + - GIT-SHA b6406283cc8b87b4f118e532d31f627b4071a086 + * kernel/workqueue: Export current_is_kevent() for libphy. + - GIT-SHA 6f786ce77e68085661a02ee99cfb4b7ca290fb17 + * debian/config: Enable all keyspan fw extensions. + - GIT-SHA 97079628a3cc9921eb5d7149580d2971860980eb + * ubuntu/: Add includes to make up for header changes on x86_64. + - GIT-SHA 1315457d772e24484c9fb5cfae2cf5dcbed6588d + * Remove UP-APIC off-by-default patch. + - GIT-SHA 57daa7b7720d9581f9a2261ef57d70c4160617b9 + * ubuntu/: INIT_WORK changes for ubuntu supplied drivers. + - GIT-SHA 5e330f1f67613ff6d092261c03ba3816a4e9c76d + * debian/config/: Disable legacy rt2x00 drivers, and enable newer ones. + - GIT-SHA 5f3f7f497bf055ee9e8796e08cc14f55e78b7b84 + * ubuntu/ndiswrapper: Allow enabling of OWN_WQ. + - GIT-SHA aef1808d7ce20b989c5da8e8fa983d23d8831447 + * ubuntu/misc/Kconfig: Add NIDSWRAPPER_WQ option. + - GIT-SHA 683ceae36cc76dccf60d0b42b6f7e6dc664338b9 + * ubuntu/fs/asfs: Fix compiler failure with new upstream code. + - GIT-SHA e651660640a32c6701a43ba6ea6b0b88ad3f2f70 + * ubuntu/: kmem_cache and SLAB_{ATOMIC,KERNEL} fixes. + - GIT-SHA 420832806cb9387909466f70739ca6a29281fac2 + * ubuntu/rtl_ieee80211/: Add some compatibility crypto calls. + - GIT-SHA 84d69c35b71f8daff106ff50471ee447adaaf6a9 + * ubuntu/: Fixes for freezer stuff moving to linux/freezer.h + - GIT-SHA f2fc18057022e3b792cddc8326e6116a08bd392b + * libata: Fix legacy mode for things like piix. + - GIT-SHA b604c4235e72743435b81fe20bfd78343edd159f + * ia64: Move sg_dma_* functions from pci.h to scatterlist.h + - GIT-SHA 71f54a36da8d5d098cdd13f86dabe8621834ba45 + * bacom_app: Fix typo introduced in + 15b1c0e822f578306332d4f4c449250db5c5dceb + - GIT-SHA 06c07cb91d6185f691bbd034670308c61bf70dcf + * dmasound: Fix INIT_WORK usage. + - GIT-SHA 9ba10c5168a94a51844b368af0fdcea22aa2ffe2 + * (promise) support PATA ports on SATA controllers + - GIT-SHA 1bcbb7e20a7eab8427ac9b227b3db887d873cbac + * Patch to correct INIT_WORK conversion. + - GIT-SHA d3e411fc1bf19f179b76b1e6e4e13127252e4c64 + * rt2500-legacy: Fixes for INIT_WORK changes. + - GIT-SHA 28b1115c58bda8f1eddffdf855d9034b0c33a7d7 + + [Kyle McMartin] + + * ipw3945: Update to v1.1.3 + - GIT-SHA d5969a44fb688e2a619b3320a571c584a1d6452f + * ubuntu/wireless/: Finish cleaning up INIT_WORK + - GIT-SHA 0f91ed3ff67c95751252172bb48b5fd96980c71f + + -- Ben Collins Tue, 28 Nov 2006 22:53:51 -0500 + +linux-source-2.6.19 (2.6.19-7.10) feisty; urgency=low + + [Ben Collins] + + * amd76x_edac: Disable because of conflict with amd_k7_agp. + - GIT-SHA 6027f7346f0f996c8efca626dec3b327bd7dca9e + - Bug #71522 + * debian/config: Disable aic7xxx_old (scary stuff) + - GIT-SHA a5a7e7b6bd8bb31c9c871aae441d1efd85ef815b + * debian/config: Enable qla2xxx FC driver. + - GIT-SHA afdcea31e92bf7d0de2938848ac21e87fe3ce584 + * debian/firmware: Add qla2xxx firmware. + - GIT-SHA c980a1cfa2bc6623c9732ebae9d63aae9f0d7e27 + * Add a lowlatency kernel target. + - GIT-SHA 1b7aff0509741650a83c7afddc5406ac5278a2c2 + * ubuntu/mactel: Add applesmc driver. + - GIT-SHA c983d32ab69771aadbf7d8f8451f3c28eda8223f + * ubuntu/mactel: Add apple IR driver. + - GIT-SHA 26bb7f92982a1e94c3743e8ebddda8c878979d35 + * debian/bin: Tuck my build scripts in here for public consumption. + - GIT-SHA a77f2b3d8fa59395d3be8e966411e4490a6f8779 + * git-ubuntu-log: Use Text::Wrap to format comments into changelog. + - GIT-SHA 997bab71d64926c335703bbaf5dc4d36bce3b335 + + [Fabio M. Di Nitto] + + * ubuntu/fs/gfs update to 24/11/2006 CVS snapshot + - GIT-SHA c8f1688a4d613c62d6e019aa66b2fd4817209e51 + + [Upstream Kernel Changes] + + * x86-64: Fix C3 timer test + * x86-64: increase PHB1 split transaction timeout + * [ARM] 3933/1: Source drivers/ata/Kconfig + * [ARM] ebsa110: fix warnings generated by asm/arch/io.h + * IB/ipath: Depend on CONFIG_NET + * [XFS] Fix uninitialized br_state and br_startoff in + * [XFS] Stale the correct inode when freeing clusters. + * x86_64: Align data segment to PAGE_SIZE boundary + * Fix CPU_FREQ_GOV_ONDEMAND=y compile error + * [IPV6] ROUTE: Try to use router which is not known unreachable. + * [IPV6] ROUTE: Prefer reachable nexthop only if the caller requests. + * [IPV6] ROUTE: Do not enable router reachability probing in router mode. + * [IPV6] IP6TUNNEL: Delete all tunnel device when unloading module. + * [IPV6] IP6TUNNEL: Add missing nf_reset() on input path. + * [Bluetooth] Attach low-level connections to the Bluetooth bus + * [Bluetooth] Handling pending connect attempts after inquiry + * [Bluetooth] Check if RFCOMM session is still attached to the TTY + * [Bluetooth] Always include MTU in L2CAP config responses + * [Bluetooth] Ignore L2CAP config requests on disconnect + * [IGMP]: Fix IGMPV3_EXP() normalization bit shift value. + * [XFRM]: Sub-policies broke policy events + * [XFRM]: nlmsg length not computed correctly in the presence of + subpolicies + * [BLUETOOTH]: Fix unaligned access in hci_send_to_sock. + * [POWERPC] Revert "[POWERPC] Enable generic rtc hook for the MPC8349 + mITX" + * [POWERPC] Revert "[POWERPC] Add powerpc get/set_rtc_time interface to + new generic rtc class" + * [IRDA]: Lockdep fix. + * [IPV6]: Fix address/interface handling in UDP and DCCP, according to + the scoping architecture. + * [TG3]: Add missing unlock in tg3_open() error path. + * [POWERPC] Fix ucc_geth of_device discovery on mpc832x + * Don't call "note_interrupt()" with irq descriptor lock held + * [AGP] Fix intel 965 AGP memory mapping function + * [ARM] 3942/1: ARM: comment: consistent_sync should not be called + directly + * [ARM] 3941/1: [Jornada7xx] - Addition to MAINTAINERS + * [AGP] Allocate AGP pages with GFP_DMA32 by default + * [MIPS] Hack for SB1 cache issues + * make au1xxx-ide compile again + * Correct bound checking from the value returned from _PPC method. + * Fix i2c-ixp4xx compile (missing brace) + * x86_64: fix bad page state in process 'swapper' + * fix "pcmcia: fix 'rmmod pcmcia' with unbound devices" + * initramfs: handle more than one source dir or file list + * fuse: fix Oops in lookup + * mounstats NULL pointer dereference + * debugfs: add header file + * Documentation/rtc.txt updates (for rtc class) + * rtc framework handles periodic irqs + * rtc class locking bugfixes + * drivers/rtc/rtc-rs5c372.c: fix a NULL dereference + * reiserfs: fmt bugfix + * Fix device_attribute memory leak in device_del + * qconf: fix uninitialsied member + * fix menuconfig colours with TERM=vt100 + * sgiioc4: Disable module unload + * fix copy_process() error check + * tlclk: fix platform_device_register_simple() error check + * Enforce "unsigned long flags;" when spinlocking + * lockdep: spin_lock_irqsave_nested() + * usb: ati remote memleak fix + * uml: make execvp safe for our usage + * [NETFILTER]: H.323 conntrack: fix crash with CONFIG_IP_NF_CT_ACCT + * [UDP]: Make udp_encap_rcv use pskb_may_pull + * [NET]: Fix kfifo_alloc() error check. + * [6PACK]: Masking bug in 6pack driver. + * [NET]: Re-fix of doc-comment in sock.h + * [XFRM] STATE: Fix to respond error to get operation if no matching + entry exists. + * V4L/DVB (4831): Fix tuning on older budget DVBS cards. + * V4L/DVB (4840): Budget: diseqc_method module parameter for cards with + subsystem-id 13c2:1003 + * V4L/DVB (4832): Fix uninitialised variable in dvb_frontend_swzigzag + * V4L/DVB (4849): Add missing spin_unlock to saa6588 decoder driver + * V4L/DVB (4865): Fix: Slot 0 not NULL on disconnecting SN9C10x PC Camera + * V4L/DVB (4885): Improve saa711x check + * Fix incorrent type of flags in + * Fix 'ALIGN()' macro, take 2 + + -- Ben Collins Tue, 21 Nov 2006 08:55:49 -0500 + +linux-source-2.6.19 (2.6.19-6.9) feisty; urgency=low + + [Ben Collins] + + * debian/post-install: Requires built scripts directory. + - GIT-SHA 6f4e4b8f3cf138b57825ed12a0b05ed5bf727216 + + -- Ben Collins Mon, 20 Nov 2006 19:44:27 -0500 + +linux-source-2.6.19 (2.6.19-6.8) feisty; urgency=low + + [Ben Collins] + + * ndsiwrapper: Updates driver to 1.28. + - GIT-SHA a37fed032ec826103a75e51ff1f82c5fea8e9b73 + * debian/*: Update ndiswrapper-modules provides to 1.9 API + - GIT-SHA 4b81c3da5bc7ddf7671f1dd8da2536495e5750ae + * debian/bin/git-hooks/commit-msg: Update to understand merges. + - GIT-SHA 41f189eba8d5645ef0b000007b42f9b26f243297 + * debian/{post,header}-install: Fixup header dirs and symlinks + - GIT-SHA 932cf4988ab7e53d6e71631604aec55c65d4ffa2 + + [Upstream Kernel Changes] + + * [SCSI] aic94xx SCSI timeout fix + * [SCSI] aic94xx SCSI timeout fix: SMP retry fix. + * [SCSI] 3ware 9000 add support for 9650SE + * [SCSI] sg: fix incorrect last scatg length + * [ARM] 3857/2: pnx4008: add devices' registration + * [SCSI] iscsi: always release crypto + * [SCSI] iscsi: add newlines to debug messages + * [SCSI] iscsi_tcp: fix xmittask oops + * [SCSI] iscsi class: update version + * [SCSI] gdth: Fix && typos + * [SCSI] psi240i.c: fix an array overrun + * [ARM] Remove PM_LEGACY=y from selected ARM defconfigs + * hpt37x: Check the enablebits + * pata_artop: fix "& (1 >>" typo + * libata: fix double-completion on error + * x86-64: Fix partial page check to ensure unusable memory is not being marked usable. + * x86-64: Fix PTRACE_[SG]ET_THREAD_AREA regression with ia32 emulation. + * x86-64: shorten the x86_64 boot setup GDT to what the comment says + * x86-64: Handle reserve_bootmem_generic beyond end_pfn + * x86-64: setup saved_max_pfn correctly (kdump) + * x86: Add acpi_user_timer_override option for Asus boards + * x86-64: Fix vgetcpu when CONFIG_HOTPLUG_CPU is disabled + * x86-64: Fix race in exit_idle + * setup_irq(): better mismatch debugging + * fix via586 irq routing for pirq 5 + * revert "PCI: quirk for IBM Dock II cardbus controllers" + * drivers/ide: stray bracket + * autofs4: panic after mount fail + * nvidiafb: fix unreachable code in nv10GetConfig + * usb: MAINTAINERS updates + * hugetlb: prepare_hugepage_range check offset too + * hugetlb: check for brk() entering a hugepage region + * libata: Convert from module_init to subsys_initcall + * cciss: fix iostat + * cpqarray: fix iostat + * Char: isicom, fix close bug + * ALSA: hda-intel - Disable MSI support by default + * Use delayed disable mode of ioapic edge triggered interrupts + * [IA64] bte_unaligned_copy() transfers one extra cache line. + * [POWERPC] Add the thread_siblings files to sysfs + * [POWERPC] Wire up sys_move_pages + * powerpc: windfarm shall request it's sub modules + * Linux 2.6.19-rc6 + * [TG3]: Increase 5906 firmware poll time. + * [NETFILTER]: nfnetlink_log: fix byteorder of NFULA_SEQ_GLOBAL + * [NETFILTER]: Use pskb_trim in {ip,ip6,nfnetlink}_queue + * [NETFILTER]: ip6_tables: fixed conflicted optname for getsockopt + * [NETFILTER]: ip6_tables: use correct nexthdr value in ipv6_find_hdr() + * [TCP]: Fix up sysctl_tcp_mem initialization. + * [TG3]: Disable TSO on 5906 if CLKREQ is enabled. + * [IA64] irqs: use `name' not `typename' + * [IA64] typename -> name conversion + * [IA64] use generic_handle_irq() + * [IA64] a fix towards allmodconfig build + * ipmi: use platform_device_add() instead of platform_device_register() to register device allocated dynamically + * some irq_chip variables point to NULL + * pnx4008: rename driver + * pnx4008:fix NULL dereference in rgbfb + * eCryptfs: dput() lower d_parent on rename + * set default video mode on PowerBook Wallstreet + * IB/ipath - fix driver build for platforms with PCI, but not HT + * parport: fix compilation failure + * hfs_fill_super returns success even if no root inode + * Update udf documentation to reflect current state of read/write support + * dell_rbu: fix error check + * AFS: Amend the AFS configuration options + * Don't give bad kprobes example aka ") < 0))" typo + * fat: add fat_getattr() + * Fix strange size check in __get_vm_area_node() + * eCryptfs: CIFS nlink fixes + * scsi: clear garbage after CDBs on SG_IO + * IPoIB: Clear high octet in QP number + * x86-64: Fix vsyscall.c compilation on UP + * x86_64: fix CONFIG_CC_STACKPROTECTOR build bug + * OHCI: disallow autostop when wakeup is not available + * USB: ftdi_sio: adds vendor/product id for a RFID construction kit + * USB: ftdi driver pid for dmx-interfaces + * USB: Fix UCR-61S2B unusual_dev entry + * USB: OHCI: fix root-hub resume bug + * USB: correct keymapping on Powerbook built-in USB ISO keyboards + * USB Storage: unusual_devs.h entry for Sony Ericsson P990i + * USB: hid-core: Add quirk for new Apple keyboard/trackpad + * usb-storage: Remove duplicated unusual_devs.h entries for Sony Ericsson P990i + * USB: Fixed outdated usb_get_device_descriptor() documentation + * USB: ipaq: Add HTC Modem Support + * USB: auerswald possible memleak fix + * W1: ioremap balanced with iounmap + * debugfs: check return value correctly + * aoe: Add forgotten NULL at end of attribute list in aoeblk.c + * Fix radeon DDC regression + * Fix generic fb_ddc i2c edid probe msg + * lkkbd: Remove my old snail-mail address + * x86_64: stack unwinder crash fix + * i386/x86_64: ACPI cpu_idle_wait() fix + * lockdep: fix static keys in module-allocated percpu areas + * Update my CREDITS entry + * [CRYPTO] api: Remove one too many semicolon + * pcmcia: fix 'rmmod pcmcia' with unbound devices + * i2c-ixp4xx: fix ") != 0))" typo + * scx200_acb: handle PCI errors + * x86_64: fix memory hotplug build with NUMA=n + * ftape: fix printk format warnings + * fix build error for HISAX_NETJET + * m68knommu: fix up for the irq_handler_t changes + * Add "pure_initcall" for static variable initialization + + -- Ben Collins Wed, 15 Nov 2006 13:39:18 -0800 + +linux-source-2.6.19 (2.6.19-6.7) feisty; urgency=low + + [Ben Collins] + + * debian/post-install: Fix typo in asm-ppc header symlinking. + - GIT-SHA 6031489f1288795bface60bf3be309f70046ab58 + + [Upstream Kernel Changes] + + * [CIFS] NFS stress test generates flood of "close with pending write" messages + * [CIFS] Explicitly set stat->blksize + * bcm43xx: Drain TX status before starting IRQs + * bcm43xx: Add error checking in bcm43xx_sprom_write() + * x86-64: clean up io-apic accesses + * x86-64: write IO APIC irq routing entries in correct order + * [CIFS] Fix mount failure when domain not specified + * Regression in 2.6.19-rc microcode driver + * A minor fix for set_mb() in Documentation/memory-barriers.txt + * nfsd4: reindent do_open_lookup() + * nfsd4: fix open-create permissions + * i386: Force data segment to be 4K aligned + * dm: fix find_device race + * dm: suspend: fix error path + * dm: multipath: fix rr_add_path order + * dm: raid1: fix waiting for io on suspend + * drivers/telephony/ixj: fix an array overrun + * Tigran has moved + * md: change ONLINE/OFFLINE events to a single CHANGE event + * md: fix sizing problem with raid5-reshape and CONFIG_LBD=n + * md: do not freeze md threads for suspend + * kretprobe: fix kretprobe-booster to save regs and set status + * ia64: select ACPI_NUMA if ACPI + * sysctl: Undeprecate sys_sysctl + * IPMI: Clean up the waiting message queue properly on unload + * IPMI: retry messages on certain error returns + * ipmi_si_intf.c: fix "&& 0xff" typos + * htirq: refactor so we only have one function that writes to the chip + * htirq: allow buggy drivers of buggy hardware to write the registers + * IB/ipath - program intconfig register using new HT irq hook + * nfsd: fix spurious error return from nfsd_create in async case + * [POWERPC] Make sure initrd and dtb sections get into zImage correctly + * MMC: Poll card status after rescanning cards + * MMC: Do not set unsupported bits in OCR response + * IB/ehca: Assure 4K alignment for firmware control blocks + * [CIFS] Fix minor problem with previous patch + * [IPVS]: Compile fix for annotations in userland. + * [POWERPC] CPM_UART: Fix non-console transmit + * [POWERPC] CPM_UART: Fix non-console initialisation + * [POWERPC] pseries: Force 4k update_flash block and list sizes + * [POWERPC] Fix cell "new style" mapping and add debug + * [POWERPC] cell: set ARCH_SPARSEMEM_DEFAULT in Kconfig + * bonding: lockdep annotation + * com20020 build fix + * drivers cris: return on NULL dev_alloc_skb() + * [IPVS]: More endianness fixed. + * [XFS] 956618: Linux crashes on boot with XFS-DMAPI filesystem when + * [XFS] Keep lockdep happy. + * [XFS] rename uio_read() to xfs_uio_read() + * [XFS] 956664: dm_read_invis() changes i_atime + * [XFS] Clean up i_flags and i_flags_lock handling. + * [XFS] Prevent a deadlock when xfslogd unpins inodes. + * [XFS] Remove KERNEL_VERSION macros from xfs_dmapi.h + * V4L/DVB (4795): Tda826x: use correct max frequency + * V4L/DVB (4802): Cx88: fix remote control on WinFast 2000XP Expert + * V4L/DVB (4804): Fix missing i2c dependency for saa7110 + * V4L/DVB (4814): Remote support for Avermedia 777 + * V4L/DVB (4815): Remote support for Avermedia A16AR + * V4L/DVB (4816): Change tuner type for Avermedia A16AR + * V4L/DVB (4817): Fix uses of "&&" where "&" was intended + * V4L/DVB (4818): Flexcop-usb: fix debug printk + * vmalloc: optimization, cleanup, bugfixes + * pci: don't try to remove sysfs files before they are setup. + * mspec driver build fix + * IPMI: Fix more && typos + * Patch for nvidia divide by zero error for 7600 pci-express card + * Fix missing parens in set_personality() + * .gitignore: add miscellaneous files + * fix Data Acess error in dup_fd + * Fix misrouted interrupts deadlocks + * SCSI core: always store >= 36 bytes of INQUIRY data + * IB/ehca: Use named constant for max mtu + * IB/ehca: Activate scaling code by default + * RDMA/amso1100: Fix unitialized pseudo_netdev accessed in c2_register_device + * RDMA/amso1100: Fix && typo + * IB/mad: Fix race between cancel and receive completion + * Fix bad data direction in SG_IO + * ide-cd: only set rq->errors SCSI style for block pc requests + * [dvb saa7134] Fix missing 'break' for avermedia card case + -- Ben Collins Wed, 15 Nov 2006 13:37:45 -0800 + +linux-source-2.6.19 (2.6.19-5.7) feisty; urgency=low + + [Ben Collins] + + * ubuntu/acerhk: Make this X86_32 only. + - GIT-SHA 58f2ee6dede56d3e412f17561cca861ab155ebfc + + [Upstream Kernel Changes] + + * [ARM] 3917/1: Fix dmabounce symbol exports + * [ARM] 3915/1: S3C2412: Add s3c2410_gpio_getirq() to general gpio.c + * [ARM] 3912/1: Make PXA270 advertise HWCAP_IWMMXT capability + * [ARM] 3918/1: ixp4xx irq-chip rework + * [ARM] 3919/1: Fixed definition of some PXA270 CIF related registers + * [ARM] 3920/1: S3C24XX: Remove smdk2410_defconfig + * [ARM] 3921/1: S3C24XX: remove bast_defconfig + * [ARM] 3922/1: S3C24XX: update s3c2410_defconfig to 2.6.19-rc4 + * [ARM] 3923/1: S3C24XX: update s3c2410_defconfig with new drivers + * [ARM] 3926/1: make timer led handle HZ != 100 + * [ARM] 3927/1: Allow show_mem() to work with holes in memory map. + * Update for the srm_env driver. + * [NET]: kconfig, correct traffic shaper + * [TCP]: Don't use highmem in tcp hash size calculation. + * [PKT_SCHED] sch_htb: Use hlist_del_init(). + * [NETPOLL]: Compute checksum properly in netpoll_send_udp(). + * [NET]: Set truesize in pskb_copy + * [TG3]: Fix array overrun in tg3_read_partno(). + * [DECNET]: Endianess fixes (try #2) + * Linux 2.6.19-rc5 + * [libata] sata_via: fix obvious typo + + -- Ben Collins Tue, 07 Nov 2006 15:18:08 -0800 + +linux-source-2.6.19 (2.6.19-5.6) feisty; urgency=low + + [Ben Collins] + + * debian/bin/git-hooks: Add my hooks for git. + - GIT-SHA 2786fe5a5cd024947d2eec6d9f9014c8a91a4e21 + * acerhk: Acer Travelmate support for special keys. + - GIT-SHA 827225e724afd903b316359effdbb8ae1139cf7b + * rfswitch: Software radio kill switch support. + - GIT-SHA 911f283b4150f73809331a7bcd4812e8d9903a70 + * ubuntu/{av5100,pbe5}: Remove inclusion of linux/config.h + - GIT-SHA 5e6495e09eed2d37c5e19cb827d55b1372f81dbb + * ipg: Added ICPlus 1000A Gigabit Ethernet Driver + - GIT-SHA 9cf35c595ca98658a03932342a4b5d65e36b1226 + * ubuntu/ipg: Fix PCI device ide. + - GIT-SHA 2cc83690105c317ad32ab5340677e894448fe552 + * ipw3945: Update to v1.1.2 + - GIT-SHA 9ad82afb9d97986a46fa849f8e590c070d8a53b5 + * powerpc: Make sure to create arch/powerpc/include/asm symlink + - GIT-SHA 2d655eb92d3a1fa9cdfdd3d5cc01568f0e5d03a7 + + [Upstream Kernel Changes] + + * ieee80211: don't flood log with errors + * hostap_plx: fix CIS verification + * bcm43xx: Fix low-traffic netdev watchdog TX timeouts + * bcm43xx: fix unexpected LED control values in BCM4303 sprom + * V4L/DVB (4752): DVB: Add DVB_FE_CUSTOMISE support for MT2060 + * V4L/DVB (4785): Budget-ci: Change DEBIADDR_IR to a safer default + * V4L/DVB (4786): Pvrusb2: use NULL instead of 0 + * V4L/DVB (4787): Budget-ci: Inversion setting fixed for Technotrend 1500 T + * V4L/DVB (4770): Fix mode switch of Compro Videomate T300 + * V4L/DVB (4784): [saa7146_i2c] short_delay mode fixed for fast machines + * V4L/DVB (4751): Fix DBV_FE_CUSTOMISE for card drivers compiled into kernel + * [IPX]: Trivial parts of endianness annotations + * [IPX]: Annotate and fix IPX checksum + * [IPV6]: Fix ECN bug on big-endian + * [NETFILTER] bug: NFULA_CFG_QTHRESH uses 32bit + * [NETFILTER] bug: nfulnl_msg_config_mode ->copy_range is 32bit + * [NETFILTER] bug: skb->protocol is already net-endian + * [TG3]: Fix 2nd ifup failure on 5752M. + * [PKTGEN]: TCI endianness fixes + * [NET]: __alloc_pages() failures reported due to fragmentation + * [IPV6]: Add ndisc_netdev_notifier unregister. + * [IPV6]: Give sit driver an appropriate module alias. + * [NETLABEL]: Fix build failure. + * [SPARC]: Fix robust futex syscalls and wire up migrate_pages. + * ehea: Nullpointer dereferencation fix + * ehea: Removed redundant define + * ehea: 64K page support fix + * Kconfig: remove redundant NETDEVICES depends + * AVR32: Get rid of board_early_init + * AVR32: Fix thinko in generic_find_next_zero_le_bit() + * Fix the spurious unlock_cpu_hotplug false warnings + * Fix for LKDTM MEM_SWAPOUT crashpoint + * isdn/gigaset: convert warning message + * lockdep: fix delayacct locking bug + * Improve the removed sysctl warnings + * sysctl: allow a zero ctl_name in the middle of a sysctl table + * sysctl: implement CTL_UNNUMBERED + * sunrpc: add missing spin_unlock + * [S390] revert add_active_range() usage patch. + * [S390] IRQs too early enabled. + * AVR32: Wire up sys_epoll_pwait + * AVR32: Add missing return instruction in __raw_writesb + * [GFS2] don't panic needlessly + * [GFS2] Fix incorrect fs sync behaviour. + * [GFS2] Fix OOM error handling + * [DLM] Fix kref_put oops + * [DLM] fix oops in kref_put when removing a lockspace + * [MIPS] Ocelot C: Fix large number of warnings. + * [MIPS] Ocelot C: fix eth registration after conversion to platform_device + * [MIPS] Ocelot C: Fix warning about missmatching format string. + * [MIPS] Ocelot C: Fix mapping of ioport address range. + * [MIPS] Ocelot 3: Fix large number of warnings. + * [MIPS] SB1: On bootup only flush cache on local CPU. + * [MIPS] Ocelot C: Fix MAC address detection after platform_device conversion. + * [MIPS] Ocelot 3: Fix MAC address detection after platform_device conversion. + * [MIPS] EV64120: Fix timer initialization for HZ != 100. + * [MIPS] Make irq number allocator generally available for fixing EV64120. + * [MIPS] EV64120: Fix PCI interrupt allocation. + * [MIPS] Fix EV64120 and Ocelot builds by providing a plat_timer_setup(). + * b44: change comment about irq mask register + * e1000: Fix regression: garbled stats and irq allocation during swsusp + + -- Ben Collins Tue, 7 Nov 2006 14:17:22 -0800 + +linux-source-2.6.19 (2.6.19-5.5) feisty; urgency=low + + [Ben Collins] + + * dev_acpi: Added ACPI Device driver + - GIT-SHA e076c92971e36ea2e629be25462ab40ad20cb704 + * pcc-acpi: Panasonc ACPI Driver + - GIT-SHA 95569514a203153c4c4496c8d9c118b39785022c + * ubuntu/acpi: New driver section + - GIT-SHA e22846d3da0ed6f835bcb60485a9bc93eb9ffc6a + * sony_acpi: Add Sony ACPI Laptop driver + - GIT-SHA e4d2ffe08e0b6930582bd81938fe7d2730a0b953 + * tc1100-wmi: Add IBM TC1100 WMI driver + - GIT-SHA e69c9de0b0a12f0917e2f2266c128dd2752c56f2 + * debian: Enable ABI checking + - GIT-SHA 328078e283ff6eacaf5d1a62720fede1e2a68780 + * ubuntu/acpi: Make ACPI sub menu depend on ACPI + - GIT-SHA f55d355afa1ed54296103ddc1f05afb08e5cfca0 + * debian/rules: Export KPKG_ARCH for post-install script. + - GIT-SHA d1669dc891344b6c155037d81234e0218bfbba90 + * ubuntu: Fix wireless drivers to be compatible with WE >= 21 + - GIT-SHA 2e0a08b1d1451201bcac8dae36cd42fdf07735e1 + + [Upstream Kernel Changes] + + * [IA64] don't double >> PAGE_SHIFT pointer for /dev/kmem access + * jfs: Add splice support + * [CIFS] Fix readdir breakage when blocksize set too small + * [CIFS] Allow null user connections + * [NET] sealevel: uses arp_broken_ops + * [APPLETALK]: Fix potential OOPS in atalk_sendmsg(). + * [XFRM] xfrm_user: Fix unaligned accesses. + * [NET]: Fix segmentation of linear packets + * [DCCP]: fix printk format warnings + * [ETH1394]: Fix unaligned accesses. + * [SCTP]: Always linearise packet on input + * [NET]: fix uaccess handling + * [IPV6]: fix lockup via /proc/net/ip6_flowlabel + * [NETFILTER]: remove masq/NAT from ip6tables Kconfig help + * [NETFILTER]: Missed and reordered checks in {arp,ip,ip6}_tables + * [NETFILTER]: ip_tables: compat error way cleanup + * [NETFILTER]: nf_conntrack: add missing unlock in get_next_corpse() + * [NETFILTER]: ip_tables: compat code module refcounting fix + * [NetLabel]: protect the CIPSOv4 socket option from setsockopt() + * [SCTP]: Correctly set IP id for SCTP traffic + * [SCTP]: Remove temporary associations from backlog and hash. + * [IPV6]: return EINVAL for invalid address with flowlabel lease request + * [SPARC64]: Fix Tomatillo/Schizo IRQ handling. + * [SPARC64]: Add some missing print_symbol() calls. + * sh: Wire up new syscalls. + * video: Fix include in hp680_bl. + * sh: Update r7780rp_defconfig. + * sh: Fix IPR-IRQ's for IRQ-chip change breakage. + * sh: Titan defconfig update. + * IB/iser: Start connection after enabling iSER + * RDMA/cma: rdma_bind_addr() leaks a cma_dev reference count + * IB/ehca: Fix eHCA driver compilation for uniprocessor + * IB/amso1100: Use dma_alloc_coherent() instead of kmalloc/dma_map_single + * IB/amso1100: Fix incorrect pr_debug() + * IB/uverbs: Return sq_draining value in query_qp response + * [IPV6]: fix flowlabel seqfile handling + * find_bd_holder() fix + * uml ubd driver: allow using up to 16 UBD devices + * uml ubd driver: document some struct fields + * uml ubd driver: var renames + * uml ubd driver: give better names to some functions. + * uml ubd driver: change ubd_lock to be a mutex + * uml ubd driver: ubd_io_lock usage fixup + * uml ubd driver: convert do_ubd to a boolean variable + * uml ubd driver: reformat ubd_config + * uml ubd driver: use bitfields where possible + * uml ubd driver: do not store error codes as ->fd + * uml ubd driver: various little changes + * uml: add _text definition to linker scripts + * uml: add INITCALLS + * taskstats: fix sub-threads accounting + * eCryptfs: Clean up crypto initialization + * eCryptfs: Hash code to new crypto API + * eCryptfs: Cipher code to new crypto API + * eCryptfs: Consolidate lower dentry_open's + * eCryptfs: Remove ecryptfs_umount_begin + * eCryptfs: Fix handling of lower d_count + * md: check bio address after mapping through partitions. + * CFQ: request <-> request merging rr_list fixup + * SCSI: ISCSI build failure + * IB/mthca: Fix MAD extended header format for MAD_IFC firmware command + * [MIPS] TX4927: Remove indent error message that somehow ended in the code. + * [MIPS] Add missing file for support of backplane on TX4927 based board + * [MIPS] Sort out missuse of __init for prom_getcmdline() + * [MIPS] Yosemite: fix uninitialized variable in titan_i2c_xfer() + * [MIPS] Fix warning of printk format in mips_srs_init() + * [MIPS] VSMP: Fix initialization ordering bug. + * [MIPS] Flags must be unsigned long. + * [MIPS] VSMP: Synchronize cp0 counters on bootup. + * [MIPS] Fixup migration to GENERIC_TIME + * [IA64] cpu-hotplug: Fixing confliction between CPU hot-add and IPI + * [IA64] MCA recovery: Montecito support + * [IA64] move SAL_CACHE_FLUSH check later in boot + * [IA64] Correct definition of handle_IPI + * ep93xx_eth: fix RX/TXstatus ring full handling + * ep93xx_eth: fix unlikely(x) > y test + * ep93xx_eth: don't report RX errors + * tokenring: fix module_init error handling + * n2: fix confusing error code + * sky2: not experimental + * myri10ge: ServerWorks HT2000 PCI id is already defined in pci_ids.h + * ehea: kzalloc GFP_ATOMIC fix + * net s2io: return on NULL dev_alloc_skb() + * skge, sky2, et all. gplv2 only + * sky2: netpoll on dual port cards + * sata_sis: fix flags handling for the secondary port + * Add 0x7110 piix to ata_piix.c + * libata: unexport ata_dev_revalidate() + * ata_piix: allow 01b MAP for both ICH6M and ICH7M + * [POWERPC] Fix various offb issues + * [POWERPC] Fix rmb() for e500-based machines it + * [POWERPC] Fix oprofile support for e500 in arch/powerpc + * [POWERPC] Use 4kB iommu pages even on 64kB-page systems + * [POWERPC] qe_lib: qe_issue_cmd writes wrong value to CECDR + * [POWERPC] Make current preempt-safe + * [POWERPC] Make high hugepage areas preempt safe + * [POWERPC] Make mmiowb's io_sync preempt safe + * [POWERPC] Disallow kprobes on emulate_step and branch_taken + * [POWERPC] Make alignment exception always check exception table + * ahci: fix status register check in ahci_softreset + * [libata] sata_nv: Add PCI IDs + * i386: clean up io-apic accesses + * [MIPS] 16K & 64K page size fixes + * [MIPS] SMTC: Fix crash if # of TC's > # of VPE's after pt_regs irq cleanup. + * [MIPS] SMTC: Synchronize cp0 counters on bootup. + * [MIPS] Fix warning in mips-boards generic PCI + * i386: write IO APIC irq routing entries in correct order + * powerpc: Eliminate "exceeds stub group size" linker warning + * [TIPC] net/tipc/port.c: fix NULL dereference + * [TCP]: Set default congestion control when no sysctl. + * [IPV6]: File the fingerprints off ah6->spi/esp6->spi + * [SPARC64]: Fix futex_atomic_cmpxchg_inatomic implementation. + * [CIFS] report rename failure when target file is locked by Windows + * [MIPS] Fix merge screwup by patch(1) + * [MIPS] IP27: Allow SMP ;-) Another changeset messed up by patch. + * [MIPS] Fix warning about init_initrd() call if !CONFIG_BLK_DEV_INITRD. + * [MIPS] Ocelot G: Fix : "CURRENTLY_UNUSED" is not defined warning. + * [MIPS] Don't use R10000 llsc workaround version for all llsc-full processors. + * [MIPS] Do not use -msym32 option for modules. + * RDMA/addr: Use client registration to fix module unload race + * [libata] Add support for PATA controllers of MCP67 to pata_amd.c. + * [libata] Add support for AHCI controllers of MCP67. + * pci_ids.h: Add NVIDIA PCI ID + * PCI: Revert "PCI: i386/x86_84: disable PCI resource decode on device disable" + * PCI: Let PCI_MULTITHREAD_PROBE depend on BROKEN + * USB: add another sierra wireless device id + * USB: usb-storage: Unusual_dev update + * hid-core: big-endian fix fix + * USB: new VID/PID-combos for cp2101 + * USB: sierra: Fix id for Sierra Wireless MC8755 in new table + * usbtouchscreen: use endpoint address from endpoint descriptor + * USB: failure in usblp's error path + * USB: usblp: fix system suspend for some systems + * USB: HID: add blacklist AIRcable USB, little beautification + * USB: fix compiler issues with newer gcc versions + * USB: xpad: additional USB id's added + * USB Storage: unusual_devs.h entry for Sony Ericsson P990i + * USB: use MII hooks only if CONFIG_MII is enabled + * eCryptfs: Fix pointer deref + * tidy "md: check bio address after mapping through partitions" + * md: send online/offline uevents when an md array starts/stops + * sys_pselect7 vs compat_sys_pselect7 uaccess error handling + * update some docbook comments + * docbook: merge journal-api into filesystems.tmpl + * Fix ipc entries removal + * mm: un-needed add-store operation wastes a few bytes + * fix UFS superblock alignment issues + * lkdtm: cleanup headers and module_param/MODULE_PARM_DESC + * Cleanup read_pages() + * cifs: ->readpages() fixes + * fuse: ->readpages() cleanup + * gfs2: ->readpages() fixes + * edac_mc: fix error handling + * NFS4: fix for recursive locking problem + * ipmi_si_intf.c sets bad class_mask with PCI_DEVICE_CLASS + * init_reap_node() initialization fix + * Add printk_timed_ratelimit() + * schedule removal of FUTEX_FD + * acpi_noirq section fix + * swsusp: debugging + * spi section fix + * reiserfs: reset errval after initializing bitmap cache + * uml: fix I/O hang + * uml: include tidying + * Create compat_sys_migrate_pages + * powerpc: wire up sys_migrate_pages + * drivers/isdn/hysdn/hysdn_sched.c: sleep after taking spinlock fix + * fix Documentation/accounting/getdelays.c buf size + * IDE: Add the support of nvidia PATA controllers of MCP67 to amd74xx.c + * Fix sys_move_pages when a NULL node list is passed + * Fix user.* xattr permission check for sticky dirs + * splice: fix problem introduced with inode diet + * Revert unintentional "volatile" changes in ipc/msg.c + * Fix unlikely (but possible) race condition on task->user access + * Make sure "user->sigpending" count is in sync + + -- Ben Collins Mon, 6 Nov 2006 07:11:08 -0800 + +linux-source-2.6.19 (2.6.19-4.4) feisty; urgency=low + + [Ben Collins] + + * debian: Fix ppc defconfig, and d-i braindamage + - GIT-SHA 3805cd5ab6796f26fdd2b69d58d72d5bf33f96bb + * debian: Prefix make-kpkg calls with sparc64 on sparc for now. + - GIT-SHA 3b2a6a332c9febffda9cdc26a9a0572ec859e999 + + [Upstream Kernel Changes] + + * CFQ: use irq safe locking in cfq_cic_link() + * CFQ: bad locking in changed_ioprio() + * Fix dmsetup table output change + * ioc4_serial: irq flags fix + * ndiswrapper: don't set the module->taints flags + * isdn/gigaset: avoid cs->dev null pointer dereference + * lockdep: annotate DECLARE_WAIT_QUEUE_HEAD + * cryptocop: double spin_lock_irqsave() + * MTD: fix last kernel-doc warning + * docbook: make a filesystems book + * Fix "Remove the use of _syscallX macros in UML" + * uml: fix compilation options for USER_OBJS + * xacct_add_tsk: fix pure theoretical ->mm use-after-free + * drivers/ide/pci/generic.c: add missing newline to the all-generic-ide message + * sunrpc: fix refcounting problems in rpc servers + * APM: URL of APM 1.2 specs has changed + * fix "sunrpc: fix refcounting problems in rpc servers" + * fix i386 regparm=3 RT signal handlers on x86_64 + * [MIPS] Oprofile: fix on non-VSMP / non-SMTC SMP configurations. + * [MIPS] Au1xx0 code sets incorrect mips_hpt_frequency + * [MIPS] Oprofile: Fix MIPSxx counter number detection. + * [MIPS] SMTC: Make 8 the default number of processors. + * [MIPS] Fix warning about unused definition in c-sb1.c + * [MIPS] Make SB1 cache flushes not to use on_each_cpu + * [MIPS] Wire up getcpu(2) and epoll_wait(2) syscalls. + * [MIPS] Au1000: Fix warning about unused variable. + * [MIPS] Fix return value of TXX9 SPI interrupt handler + * [MIPS] Ocelot G: Fix build error and numerous warnings. + * [MIPS] EMMA 2 / Markeins: Fix build wreckage due to genirq wreckage. + * [MIPS] EMMA 2 / Markeins: Formitting fixes split from actual address fixes. + * [MIPS] EMMA 2 / Markeins: Convert to name struct resource initialization. + * [MIPS] EMMA 2 / Markeins: struct resource takes physical addresses. + * [MIPS] JMR3927: Fixup another victim of the irq pt_regs cleanup. + * [MIPS] MIPS doesn't need compat_sys_getdents. + * fix bd_claim_by_kobject error handling + * clean up add_bd_holder() + * Linux 2.6.19-rc4 + + -- Ben Collins Tue, 31 Oct 2006 10:45:07 -0500 + +linux-source-2.6.19 (2.6.19-3.3) feisty; urgency=low + + [Ben Collins] + + * Revert "ppc: Add defconfig for build" + - GIT-SHA 540057c30de97922c99dcd198e1535c3986abfa0 + * debian: Add defconfig setting for each arch + - GIT-SHA 03248c8d8e00151e085448684eacdafb3acc0833 + * debian/rules: Re-add kernel-wedge workaround to fix sparc FTBFS + - GIT-SHA b0ea4d18b8c8bfdef670980700b2f78948205819 + + -- Ben Collins Tue, 31 Oct 2006 10:02:36 -0500 + +linux-source-2.6.19 (2.6.19-2.2) feisty; urgency=low + + [Ben Collins] + + * btsco: Added new driver + - GIT-SHA 18b128d55a6297da941055abda677cde1c1086ed + * at76: Atmel USB Driver + - GIT-SHA f2460fe216447baa35b7f7a9ca8d440f4922719e + * at76-usb-firmware: Added firmware for Atmel USB + - GIT-SHA b618084d1cf221755848d42bb5b45fe5b97479e1 + * ppc: Add defconfig for build + - GIT-SHA 7eefca4e80cd6016ecec0cf27e1e9dadb05e2e9f + * debian: git-ubuntu-log: Ommit matching revert/commits. + - GIT-SHA 68ed886f702f70e43f4e835d768a38309a4120ca + * debian: Fix KPKG_(ARCH|SUBARCH) to fix sparc64 build failure. + - GIT-SHA 0973b171e2334735687c647673e76f94d21a6d3c + * debian: insert-changes: New script. + - GIT-SHA 492ef6bf5f17554ab82ab170e728e51de7fc1fb1 + + [Upstream Kernel Changes] + + * e1000: FIX: don't poke at manageability registers for incompatible adapters + * e1000: FIX: 82542 doesn't support WoL + * e1000: FIX: fix wrong txdctl threshold bitmasks + * e1000: FIX: Disable Packet Split for non jumbo frames + * e1000: FIX: Don't limit descriptor size to 4kb for PCI-E adapters + * e1000: FIX: move length adjustment due to crc stripping disabled. + * e1000: Increment version to 7.2.9-k4 + * e100: account for closed interface when shutting down + * pcmcia: at91_cf update + * pcmcia: add more IDs to hostap_cs.c + * pcmcia: update alloc_io_space for conflict checking for multifunction PC card + * pcmcia/ds: driver layer error checking + * CONFIG_PM=n slim: drivers/pcmcia/* + * i82092: wire up errors from pci_register_driver() + * pcmcia: au1000_generic fix + * ioremap balanced with iounmap for drivers/pcmcia + * Export soc_common_drv_pcmcia_remove to allow modular PCMCIA. + * PCMCIA: handle sysfs, PCI errors + * PCMCIA: fix __must_check warnings + * [SPARC64]: Fix central/FHC bus handling on Ex000 systems. + * [SPARC64]: Fix memory corruption in pci_4u_free_consistent(). + * [TCP] cubic: scaling error + * [TCP] H-TCP: fix integer overflow + * [BRIDGE]: correct print message typo + * [SPARC]: Fix bus_id[] string overflow. + * [S390] sys_getcpu compat wrapper. + * [S390] Initialize interval value to 0. + * [S390] cio: css_probe_device() must be called enabled. + * [S390] uaccess error handling. + * [S390] Improve AP bus device removal. + * [S390] cio: Make ccw_device_register() static. + * acpiphp: fix latch status + * PCI: fix pci_fixup_video as it blows up on sparc64 + * PCI: x86-64: mmconfig missing printk levels + * PCI: reset pci device state to unknown state for resume + * PCI: Remove quirk_via_abnormal_poweroff + * vmlinux.lds: consolidate initcall sections + * drivers: wait for threaded probes between initcall levels + * silence 'make xmldocs' warning by adding missing description of 'raw' in nand_base.c:1485 + * [ARM] Fix SMP irqflags support + * [ARM] Add realview SMP default configuration + * [ARM] Add __must_check to uaccess functions + * [ARM] 3909/1: Disable UWIND_INFO for ARM (again) + * [ARM] 3899/1: Fix the normalization of the denormal double precision number. + * [ARM] 3900/1: Fix VFP Division by Zero exception handling. + * mm: clean up pagecache allocation + * vmscan: Fix temp_priority race + * Use min of two prio settings in calculating distress for reclaim + * ext4: fix printk format warnings + * jbd: journal_dirty_data re-check for unmapped buffers + * jbd2: journal_dirty_data re-check for unmapped buffers + * fix efi_memory_present_wrapper() + * md: fix bug where spares don't always get rebuilt properly when they become live + * md: simplify checking of available size when resizing an array + * md: fix up maintenance of ->degraded in multipath + * md: fix printk format warnings, seen on powerpc64: + * memory hotplug: __GFP_NOWARN is better for __kmalloc_section_memmap() + * Fix potential OOPs in blkdev_open() + * __vmalloc with GFP_ATOMIC causes 'sleeping from invalid context' + * visws build fix + * Add missing space in module.c for taintskernel + * ioc4: fix printk format warning + * cciss: fix printk format warning + * hugetlb: fix size=4G parsing + * hugetlb: fix prio_tree unit + * hugetlb: fix absurd HugePages_Rsvd + * missing unused dentry in prune_dcache()? + * VFS: Fix an error in unused dentry counting + * Constify compat_get_bitmap argument + * strstrip remove last blank fix + * fill_tgid: fix task_struct leak and possible oops + * bacct_add_tsk: fix unsafe and wrong parent/group_leader dereference + * taskstats_tgid_free: fix usage + * taskstats_tgid_alloc: optimization + * taskstats: kill ->taskstats_lock in favor of ->siglock + * taskstats: don't use tasklist_lock + * fill_tgid: cleanup delays accounting + * move SYS_HYPERVISOR inside the Generic Driver menu + * time_adjust cleared before use + * cpu-hotplug: release `workqueue_mutex' properly on CPU hot-remove + * JMB 368 PATA detection + * workqueue: update kerneldoc + * Calculation fix for memory holes beyong the end of physical memory + * [ARM] Fix i2c-pxa slave mode support + * [ARM] Fix suspend oops caused by PXA2xx PCMCIA driver + * [ARM] Add KBUILD_IMAGE target support + * Fix GFP_HIGHMEM slab panic + * [ARM] 3913/1: n2100: fix IRQ routing for second ethernet port + * ieee1394: ohci1394: revert fail on error in suspend + * taskstats: fix sk_buff leak + * taskstats: fix sk_buff size calculation + * m68k: consolidate initcall sections + * [WATCHDOG] sc1200wdt.c pnp unregister fix. + + + -- Ben Collins Thu, 26 Oct 2006 23:16:13 -0400 + +linux-source-2.6.19 (2.6.19-1.1) feisty; urgency=low + + [Ben Collins] + + * Makefile: Disable compiler stack protection + - GIT-SHA 88e5d8158cceacb7e7b559f5af74f729a17ade71 + * Add git-ubuntu-log parsing script. + - GIT-SHA 5d781e48af9265470bc5de9cfd072b80918e1db8 + * Disable APIC on UP machines by default + - GIT-SHA ce3c49d6164180bcb0e5d6a455f3ae163914af52 + * Quieten compressed boot messages. + - GIT-SHA b31aa3e4c69d1fc4868d39dc63bc2a4baab497b1 + * Add config option to disable hyperthreading by default + - GIT-SHA 161459709590b06c515c7e2657c376e28a98fdc1 + * Default to dongle type 9 on IBM hardware. + - GIT-SHA eb2eaa11c75f1c656a3bef54bef3e8c92e52049d + * Add "TOSHIBA CD-ROM XM-1702BC" to ide-dma blacklist + - GIT-SHA e64e371c8cdba5c0af8d8c8eaef69f07cd3b87b5 + * net/sunhme: Fix Sun Happy Meal ethernet lockups on Ultra 1E + - GIT-SHA add87b82b6ea9b4a9c695d4fb0b5ae1d4ce655cc + * pcmcia: Do not insert pcmcia cards on resume + - GIT-SHA 9334fc580d26a92c81651df4669ce8c19a68b260 + * scsi/BusLogic: Add MODULE_DEVICE_TABLE for autoloading + - GIT-SHA 55f6d5c8bf31270f7289ce9865cb15528327cca8 + * input/mouse/alps: Do not call psmouse_reset() for alps + - GIT-SHA fb3c8d616c602b8876dc50e89ac4987f5ba05bfe + * scsi: Add Matshita DMC-LC33 to devlist + - GIT-SHA b7f273bde8e6e02a6dea490f877ef9ee4f390448 + * scsi: Restore generic SCSI proc_info function + - GIT-SHA 9c1a5525614014486d2ba5ed1181f777c55587f3 + * ide: Make some drivers modular + - GIT-SHA 9ecb5d7cc5db4071f4d9218f8acff96ab5d599f0 + * ide/pnp: Allow ide-pnp to be modular. + - GIT-SHA 924f6bd12dc99b5176940895ec26607f2144b0f1 + * video/vesafb: Modularize + - GIT-SHA f160678572c5cbd97cc96a761d95646fb4c3a50f + * pcmcia: Add missing device releases + - GIT-SHA e3eeb6ee8e14cdcaccf0213446bef4a26ba78bcb + * general: Quieten noisy printk's + - GIT-SHA 13dbeb0d68d892cce0483594fbd795c289ae7c27 + * acpi: Allow loading of DSDT from initrd + - GIT-SHA 5272d84c2ae7ad6dcf98ec83fe2f510a0b8912ee + * ide: Cleaner merge of ide_scan_pcibus() changes (modular) + - GIT-SHA ab460a6bf9bb00b39443190efbc44cf8a9358032 + * video/vesafb: Fixup vesafb modular code to merge with platform driver changes. + - GIT-SHA 08c62e8dea078ca4510f00bbf1e8dce0cef53716 + * ide: Export ide_scan_direction + - GIT-SHA 1b49a08481e74417c114f16c2c6ec0e4e6d282e0 + * ide: Fix Oops in IDE caused by __init for ide_pci_scanbus() + - GIT-SHA d3e3800f6826c7a57872dd22ac93d034d36c91db + * fs: Revert bd_claim change. + - GIT-SHA 8cbff5a651066cd43f6736a45181c0549d91662a + * drivers/video: Fix some video drivers unchecked use of nvram functions + - GIT-SHA e79b253cceeee1f4022b825e3c6acbc9690b81a7 + * tulip: Fix for Uli5261 chipsets. + - GIT-SHA 278130f8818f8ac6550760807815d24dbeee6470 + * net/tulip: Define ULI PCI ID's + - GIT-SHA 68cdca366a7410a1a5c86f1365072edfedbc911c + * ia64: Export some extra symbols so we can build vga16fb + - GIT-SHA 48b37aa458e7e61f396f0bc2e4b8a4bdd039005a + * video: Enable VesaFB for ia64. + - GIT-SHA 9d859229d3ec3bb4325b65e05387f2d6cd12627f + * ide: Revert some of the "modular ide" patch. + - GIT-SHA ccbe68cc3928e6275f4fefed7856c7754d10dd84 + * vga16fb: Set default timings to 640x400 for compatibility. + - GIT-SHA 20556d56d5e13a642d5da77e4fd877f00a63bbdc + * block: Make CDROMEJECT more robust + - GIT-SHA 933956f84fdb520d9cce720fabbb6236efaa188f + * powerpc: Disable prom_printf + - GIT-SHA 52bca28eb10d88db59b8b16fd28f7bd71c859404 + * ide-cd: Disable verbose errors. + - GIT-SHA 72d40db7ba7478afe35e7302d0d61c2bcd41fa53 + * tulip: Fix mdio related lockups. Update from upstream driver. + - GIT-SHA e74fe2962b8fde95756505782a3226a5e30b92c2 + * input: Allow root to inject unknown scan codes. + - GIT-SHA 9dba2e8158382af26d4460242ffe6d45803f43fb + * 3w-9xxx: Add .proc_name member to scsi_host_template + - GIT-SHA a120864ddf97dcaf0a5565ffd2539852e884f411 + * synaptics: Add Toshiba Protege M300 to rate=40 blacklist. + - GIT-SHA d9b4f0e739d81b75fae3f9545d598d865e391e35 + * vga16fb: Do not use 640x480 on certain machines + - GIT-SHA faffc346a48402547964adde5b5c4bf3b37572a8 + * forcedeth: Let the driver work when no PHY is found + - GIT-SHA eb2bbfea12d9f3599ed6019fce78a5bb3b70f9d8 + - Bug #45257 + * tulip: Let dmfe handle davicom on non-sparc. + - GIT-SHA 901dcff694d2c177078a2f9a0e81d765c7db41fb + - Bug #48287 + * speakup: Driver addition + - GIT-SHA 1cf0afb09a96f1c381a9ac42ab56115c957177ab + * kbd: Fix typo in speakup patch + - GIT-SHA 71aeabbdc6e922a454cbb96c93bda44cd6f34613 + * powerpc: Allow config of pSeries panel message + - GIT-SHA 8290fcc662b7a9cb3035222f3c2f0160f5a14fcd + * general: crash helper support for apport + - GIT-SHA d9291b92a80b54e2212348ff82cd6c374351dd05 + * version: Implement version_signature proc file. + - GIT-SHA 87c212ae348ed89e2177af1907fbfff22b758eb4 + * hid-core: Add noget quirk for turbox keyboard. + - GIT-SHA c6ecb350590cbbb62207ecda8acdb36dc503830e + * ipw2100: Add option to disable C3/C4 state transistions. + - GIT-SHA a2a9f735de0c61a7be45ab0c55eea593098de70a + * ubuntu: Create ubuntu driver directory. + - GIT-SHA ce47ddb0f4e34a60599bedc8f0bff996ed252e6f + * hdrinst: Add stub for gfs headers + - GIT-SHA 6fde7f59fd4e921d8255c2fd6ebabc622c88947c + * general: Add MODULE_DEV_TABLE to some drivers for autoloading. + - GIT-SHA bef1c07e02bd1fb0bb2eb020e5c58dd12e56d53f + * i8042: Quiten message about no controlles being found. + - GIT-SHA a438ddf2becf5f6d4a5db68acf0cd9648030d192 + * asfs: Add Amiga Smart File System + - GIT-SHA 63e625a65070eee461f5f4bedd550e39ed8c171e + * kbuild: Add ubuntu/include/ for external driver includes. + - GIT-SHA 6cc08947078031622ef777dc91630b2a25e1cc51 + * fs: Export __d_path symbol for dazuko. + - GIT-SHA f816e1d4eab62bc229991a614f63731f599bf9ae + * speakup: Merges fixes and patches from Edgy. + - GIT-SHA d2c7021c474d7bbaeafd96f890471476514e219d + * ixj: Fix PCI vendor/device ID's for QUICKNET. + - GIT-SHA 7742c3f2837c62c64c08736ca8f6b8931258ba6b + * asfs: Compile fixes. + - GIT-SHA da4e90d5cb6bc656861de64cb200d6de124c39ce + * vt: Fix speakup code to compile. + - GIT-SHA a0ec07a4417656566e19d8415dbc86e91d6f974a + * kbuild: Fix location of ubuntu/include addition to LINUXINCLUDES + - GIT-SHA a30f7b62339415a90a6024ada0e2f10f86a85dbd + * general: Various compile fixes for edgy patch merges. + - GIT-SHA eea36c5c4f202eb95108fd8c1ef9fe5f38c10bcf + * dazuko: Added driver + - GIT-SHA 1283c07c2260047335a58be437dc8ba558011770 + * squashfs: Added v3.1-r2 driver + - GIT-SHA 6acce7627f044b72930dd6cc563aed9559a4b8c4 + * unionfs: Add 20060916 snapshot + - GIT-SHA c375f3b13be8c1f3aba1316b01332f7951d4dda2 + * gfs: Merged from Edgy + - GIT-SHA 29decd8128961ed2a79235240172ec2f646103f4 + * rt2x00: Added drivers from Edgy with build fixes. + - GIT-SHA e8a710260e32cefb7236a8bd3a111387818786c0 + * linux-wlan-ng: Added driver + - GIT-SHA 36d255e73f30f68a23d61048d3f0627bc5241025 + * ndsiwrapper: Added driver + - GIT-SHA f1e27ae3a39b0d389f212df44d6ab5468d04647d + * cloop: Added compressed loop driver + - GIT-SHA 26cb677f9b9205a2ed77a4ee4c554bcdd498eaa4 + * dm-bbr: Added new driver + - GIT-SHA ee36ac9e9c3065f8f594493a3be2e0ae4196e46e + * acx: Add driver from Edgy + - GIT-SHA 959183847e71f99bee6e5682708a672b9c2abd02 + * ipw3945: Add new driver + - GIT-SHA cc542d63e9bc05438570c084e6b701e82aafbda2 + * adm8211: Add new driver + - GIT-SHA 6a9957bd934f4db1dc80a5d7b48638e3373d7c88 + * rtl818x: Add new drivers + - GIT-SHA 9533d6e292539fae27c6062dbf4ba2b663caaa28 + * prism54_softmac: Add new driver + - GIT-SHA 559b895c45424e974caadc3ec249d5cdbcd5ddf4 + * fsam7400: Add new driver + - GIT-SHA 78b8978053c2ee6d0cbd42aec330d6ee2b555212 + * mol: Add Mac-On-Linux driver + - GIT-SHA 51410652caa26b301d6ac968d6fce04c1f21d925 + * ov511: Add ov511 camera driver + - GIT-SHA 63f1564f55645b26f157c418a6e28fb49b23a52b + * zd1211: Install firmware in subdirectory, like the driver expects it. + - GIT-SHA 33564d1acfa96e8cba778e2efb6b0376aad09e12 + * kbuild: Do not add debian/ to clean-dirs. + - GIT-SHA 8e1027b4fefded38704dd473394e2f7238012940 + * debian/: We don't need to run make-kpkg clean in the top level. + - GIT-SHA a8e5dc70095ebd21e21896c82cab8394e5c25a7c + * ubuntu/: Update all drivers for 2.6.19 changes + - GIT-SHA a8dc19f626a200ee837af570ce59a732b3094aa5 + * ubuntu/: More fixes for warnings. ubuntu/ is pretty much warning free + - GIT-SHA 807da64fba9aa414f256ea4d5664a448f9023d78 + * gfs2/dlm: Remove. These modules are in-tree now. + - GIT-SHA bb62e6c94034978605cc148d6c94dd15036eaf4e + * gfs2: Export extra symbols for gfs1 + - GIT-SHA d999702b86414c59d62f9b34450129a9221b523d + * kbuild: Allow header_install to work with O= + - GIT-SHA afa95b842e7b00b21537f2203e4879c2d860a3e9 + * debian/d-i: Update md-modules udeb list. + - GIT-SHA ed24b1fc393feb10061f83bbf152f7718cc94a83 + * debian/: Complete rework of d-i (kernel-wedge) handling + - GIT-SHA 435d7a8fa97f08f1ed39520bf4122434ad7d57ac + * ide: Disable some PCI entries when duplicate ATA driver is enabled. + - GIT-SHA c97951e8a2b085c6ec47fee8f1f933185bde3d75 + * fsam7400: Include linux/io.h for check_signature() + - GIT-SHA fb04e20928624ec398c54131fa7736a2fb6a971e + * sbus: BBC and ENVCTRL both need to be built-in + - GIT-SHA 75bc2c9764754ae2b446ac5613b7a33c2d7a0379 + * prism2: Make modules depend on subsystems. + - GIT-SHA 5d084bc0a60a146d81a910580eeb29a7e92d89d6 + * sparc: Fix some section mismatch warnings from sbus modules. + - GIT-SHA a1e1b46410e1095bad4e401d7bc0591d44137e2a + * kbuild: Remove local change for -fno-stack-protector. + - GIT-SHA 10137f027764e20df233111725a7b148047d92d1 + * sbus/char, synaptics: Revert local Ubuntu changes + - GIT-SHA a3852f015830915eb3fb33b8fea85a5edd7a5838 + * mv643xx: Remove pci dev table. Not needed for this driver. + - GIT-SHA f098f17a693fefb6aa03d4ac317faf4f92c0d05a + * imsttfb: Set USE_NV_MODES to 0 when CONFIG_NVRAM is not set + - GIT-SHA 292f071fb9492af9042e840ca81397108dd0ea83 + * prism2_plx: Disable on ppc for now. + - GIT-SHA db1b9f970535fdc567e08bca05b8bcf6a4e1f07f + * ppc: Do not re-export kd_mksound. + - GIT-SHA 5b7d5bbf5171fcb92d78b0e3fa5437ec6f912838 + * atm/block/wan: Require ISA_DMA_API for some drivers. + - GIT-SHA 40215f7cfb9ec59a90b781c50ffc9424ef16b3ba + * hvcs: select HVC_CONSOLE when enabled. + - GIT-SHA e41dbec0326f0e75e6a80b248b5c26f75899f866 + * ppc: Do not enable ISA_DMA_API on PPC64 + - GIT-SHA 75b0757318306ddd6868d65f2e2da6c806f140f6 + * tmscsim, i2o_config: Depends on ISA_DMA_API + - GIT-SHA f86bd4404911d9107c3bf7e36c894fa5907fac8c + * drivers/atm: Add CPPFLAGS to fore200e-fw endian check. + - GIT-SHA 694db9ff7e16042b3f58bbc01d19ef08609315ce + * bcm43xx: Move dma-mapping.h include to fix compile failure + - GIT-SHA 9cc7a903b72c231510f4cae7e9dee27b0ebc6d2c + + [Chuck Short] + + * atkbd: Disables stupid keyboard warning. + - GIT-SHA aedc2d9246885a41346584b1fe91696611eea756 + + [Fabio M. Di Nitto] + + * drivers/char/vt.c: make promcon driver init a boot option. + - GIT-SHA 41a393f2d8829bceb5c5da136dd12f3dcbe6c94c + + -- Ben Collins Thu, 26 Oct 2006 21:58:29 -0400 --- linux-2.6.24.orig/debian/rules.d/4-checks.mk +++ linux-2.6.24/debian/rules.d/4-checks.mk @@ -0,0 +1,26 @@ +# Check ABI for package against last release (if not same abinum) +abi-%: $(abidir)/% + @# Empty for make to be happy +$(abidir)/%: $(stampdir)/stamp-build-% + install -d $(abidir) + sed -e 's/^\(.\+\)[[:space:]]\+\(.\+\)[[:space:]]\(.\+\)$$/\3 \2 \1/' \ + $(builddir)/build-$*/Module.symvers | sort > $@ + +abi-check-%: $(abidir)/% + @$(SHELL) debian/scripts/abi-check "$*" "$(prev_abinum)" "$(abinum)" \ + "$(prev_abidir)" "$(abidir)" "$(skipabi)" + +# Check the module list against the last release (always) +module-%: $(abidir)/%.modules + @# Empty for make to be happy +$(abidir)/%.modules: $(stampdir)/stamp-build-% + install -d $(abidir) + find $(builddir)/build-$*/ -name \*.ko | \ + sed -e 's/.*\/\([^\/]*\)\.ko/\1/' | sort > $@ + +module-check-%: $(abidir)/%.modules + @perl -f debian/scripts/module-check "$*" \ + "$(prev_abidir)" "$(abidir)" $(skipmodule) + +checks-%: abi-check-% module-check-% + @# Will be calling more stuff later --- linux-2.6.24.orig/debian/rules.d/lpia.mk +++ linux-2.6.24/debian/rules.d/lpia.mk @@ -0,0 +1,21 @@ +build_arch = i386 +header_arch = i386 +asm_link = x86 +defconfig = defconfig +flavours = +build_image = bzImage +kernel_file = arch/$(build_arch)/boot/bzImage +install_file = vmlinuz + +do_debug_image = true + +loader = grub + +#custom_flavours = lpiacompat lpia +custom_flavours = lpia lpiacompat + +# +# Set this variable to 'true' in order to +# avoid building udebs for the debian installer. +# +disable_d_i = true --- linux-2.6.24.orig/debian/rules.d/3-binary-indep.mk +++ linux-2.6.24/debian/rules.d/3-binary-indep.mk @@ -0,0 +1,81 @@ +build-indep: + +docpkg = linux-doc-$(release) +docdir = $(CURDIR)/debian/$(docpkg)/usr/share/doc/$(docpkg) +install-doc: + dh_testdir + dh_testroot + dh_clean -k -p$(docpkg) + + # First the html docs + install -d $(docdir)/linux-doc-tmp + $(kmake) O=$(docdir)/linux-doc-tmp htmldocs + mv $(docdir)/linux-doc-tmp/Documentation/DocBook \ + $(docdir)/html + rm -rf $(docdir)/linux-doc-tmp + + # Copy the rest + cp -a Documentation $(docdir) + rm -rf $(docdir)/DocBook + +srcpkg = linux-source-$(release) +srcdir = $(CURDIR)/debian/$(srcpkg)/usr/src/$(srcpkg) +install-source: + dh_testdir + dh_testroot + dh_clean -k -p$(srcpkg) + + install -d $(srcdir) + find . -path './debian/*' -prune -o \ + -path './.*' -prune -o -print | \ + cpio -pd --preserve-modification-time $(srcdir) + (cd $(srcdir)/..; tar cf - $(srcpkg)) | bzip2 -9c > \ + $(srcdir).tar.bz2 + rm -rf $(srcdir) + +indep_hdrpkg = linux-headers-$(release)$(debnum) +indep_hdrdir = $(CURDIR)/debian/$(indep_hdrpkg)/usr/src/$(indep_hdrpkg) +install-headers: + dh_testdir + dh_testroot + dh_clean -k -p$(indep_hdrpkg) + + install -d $(indep_hdrdir) + find . -path './debian/*' -prune -o -path './include/*' -prune \ + -o -path './scripts/*' -prune -o -type f \ + \( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Kbuild*' -o \ + -name '*.sh' -o -name '*.pl' -o -name '*.lds' \) \ + -print | cpio -pd --preserve-modification-time $(indep_hdrdir) + # Copy headers for LUM + cp -a drivers/media/dvb/dvb-core/*.h $(indep_hdrdir)/drivers/media/dvb/dvb-core + cp -a drivers/media/video/*.h $(indep_hdrdir)/drivers/media/video + cp -a drivers/media/dvb/dvb-core/*.h $(indep_hdrdir)/drivers/media/dvb/dvb-core + cp -a drivers/media/dvb/frontends/*.h $(indep_hdrdir)/drivers/media/dvb/frontends + cp -a scripts include $(indep_hdrdir) + +install-indep: install-source install-headers install-doc + +binary-headers: install-headers + dh_testdir + dh_testroot + dh_installchangelogs -p$(indep_hdrpkg) + dh_installdocs -p$(indep_hdrpkg) + dh_compress -p$(indep_hdrpkg) + dh_fixperms -p$(indep_hdrpkg) + dh_installdeb -p$(indep_hdrpkg) + dh_gencontrol -p$(indep_hdrpkg) + dh_md5sums -p$(indep_hdrpkg) + dh_builddeb -p$(indep_hdrpkg) + +binary-indep: install-indep + dh_testdir + dh_testroot + + dh_installchangelogs -i + dh_installdocs -i + dh_compress -i + dh_fixperms -i + dh_installdeb -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i --- linux-2.6.24.orig/debian/rules.d/amd64.mk +++ linux-2.6.24/debian/rules.d/amd64.mk @@ -0,0 +1,18 @@ +build_arch = x86_64 +header_arch = $(build_arch) +asm_link = x86 +defconfig = defconfig +flavours = generic +flavours += server +build_image = bzImage +kernel_file = arch/$(build_arch)/boot/bzImage +install_file = vmlinuz + +do_debug_image = true + +loader = grub + +# +# No custom binaries for the PPA build. +# +custom_flavours = rt xen openvz --- linux-2.6.24.orig/debian/rules.d/6-binary-custom.mk +++ linux-2.6.24/debian/rules.d/6-binary-custom.mk @@ -0,0 +1,133 @@ +# This could be somewhere else, but we stub this file so that the include +# in debian/rules doesn't have an empty list. +binary-custom: $(addprefix custom-binary-,$(custom_flavours)) +build-custom: $(addprefix custom-build-,$(custom_flavours)) + +# Custom targets can dep on these targets to help things along. They can +# also override it with a :: target for addition processing. +custom-prepare-%: $(stampdir)/stamp-custom-prepare-% + @# Empty for make to be happy +$(stampdir)/stamp-custom-prepare-%: target_flavour = $* +$(stampdir)/stamp-custom-prepare-%: origsrc = $(builddir)/custom-source-$* +$(stampdir)/stamp-custom-prepare-%: srcdir = $(builddir)/custom-build-$* +$(stampdir)/stamp-custom-prepare-%: debian/binary-custom.d/%/config.$(arch) \ + debian/binary-custom.d/%/patchset + @echo "Preparing custom $*..." + rm -rf $(origsrc) + install -d $(origsrc) + install -d $(srcdir) + touch $(srcdir)/ubuntu-build + find . \( -path ./debian -o -path ./.git -o -name .gitignore \) \ + -prune -o -print | cpio -dumpl $(origsrc) + for patch in `ls debian/binary-custom.d/$*/patchset/*.patch | sort`; do \ + echo $$patch; \ + patch -p1 -d $(origsrc) < $$patch ;\ + done + cat $< > $(srcdir)/.config + $(kmake) -C $(origsrc) O=$(srcdir) silentoldconfig prepare scripts + touch $@ + +custom-build-%: $(stampdir)/stamp-custom-build-% + @# Empty for make to be happy +$(stampdir)/stamp-custom-build-%: target_flavour = $* +$(stampdir)/stamp-custom-build-%: origsrc = $(builddir)/custom-source-$* +$(stampdir)/stamp-custom-build-%: srcdir = $(builddir)/custom-build-$* +$(stampdir)/stamp-custom-build-%: bimage = $(call custom_override,build_image,$*) +$(stampdir)/stamp-custom-build-%: $(stampdir)/stamp-custom-prepare-% + @echo "Building custom $*..." + $(kmake) -C $(origsrc) O=$(srcdir) $(conc_level) + $(kmake) -C $(origsrc) O=$(srcdir) $(conc_level) modules + @touch $@ + +custom-install-%: pkgdir = $(CURDIR)/debian/linux-image-$(release)$(debnum)-$* +custom-install-%: basepkg = linux-headers-$(release)$(debnum) +custom-install-%: hdrdir = $(CURDIR)/debian/$(basepkg)-$*/usr/src/$(basepkg)-$* +custom-install-%: target_flavour = $* +custom-install-%: origsrc = $(builddir)/custom-source-$* +custom-install-%: srcdir = $(builddir)/custom-build-$* +custom-install-%: kfile = $(call custom_override,kernel_file,$*) +custom-install-%: $(stampdir)/stamp-custom-build-% + dh_testdir + dh_testroot + dh_clean -k -plinux-image-$(release)$(debnum)-$* + dh_clean -k -plinux-headers-$(release)$(debnum)-$* + + # The main image + # xen doesnt put stuff in the same directory. its quirky that way + if [ $(target_flavour) == "xen" ]; then \ + install -m644 -D $(srcdir)/arch/x86/boot/vmlinuz $(pkgdir)/boot/$(install_file)-$(release)$(debnum)-$* ; \ + else \ + install -m644 -D $(srcdir)/$(kfile) $(pkgdir)/boot/$(install_file)-$(release)$(debnum)-$* ; \ + fi + + install -m644 $(srcdir)/.config \ + $(pkgdir)/boot/config-$(release)$(debnum)-$* + install -m644 $(srcdir)/System.map \ + $(pkgdir)/boot/System.map-$(release)$(debnum)-$* + $(kmake) -C $(origsrc) O=$(srcdir) modules_install \ + INSTALL_MOD_PATH=$(pkgdir)/ + rm -f $(pkgdir)/lib/modules/$(release)$(debnum)-$*/build + rm -f $(pkgdir)/lib/modules/$(release)$(debnum)-$*/source +ifeq ($(no_image_strip),) + find $(pkgdir)/ -name \*.ko -print | xargs strip --strip-debug +endif + # Some initramfs-tools specific modules + install -d $(pkgdir)/lib/modules/$(release)$(debnum)-$*/initrd + #ln -f $(pkgdir)/lib/modules/$(release)$(debnum)-$*/kernel/security/capability.ko \ + # $(pkgdir)/lib/modules/$(release)$(debnum)-$*/initrd/ + + # Now the image scripts + install -d $(pkgdir)/DEBIAN + for script in postinst postrm preinst prerm; do \ + sed -e 's/=V/$(release)$(debnum)-$*/g' -e 's/=K/$(install_file)/g' \ + -e 's/=L/$(loader)/g' -e 's@=B@$(build_arch)@g' \ + debian/control-scripts/$$script > $(pkgdir)/DEBIAN/$$script; \ + chmod 755 $(pkgdir)/DEBIAN/$$script; \ + done + + # The flavour specific headers image + # XXX Would be nice if we didn't have to dupe the original builddir + install -m644 -D $(srcdir)/.config \ + $(hdrdir)/.config + $(kmake) -C $(origsrc) O=$(hdrdir) silentoldconfig prepare scripts + # We'll symlink this stuff + rm -f $(hdrdir)/Makefile + rm -rf $(hdrdir)/include2 + # Script to symlink everything up + $(SHELL) debian/scripts/link-headers "$(hdrdir)" "$(basepkg)" \ + "$(origsrc)" "$(build_arch)" "$*" + # Setup the proper asm symlink + rm -f $(hdrdir)/include/asm + ln -s asm-$(asm_link) $(hdrdir)/include/asm + # The build symlink + install -d debian/$(basepkg)-$*/lib/modules/$(release)$(debnum)-$* + ln -s /usr/src/$(basepkg)-$* \ + debian/$(basepkg)-$*/lib/modules/$(release)$(debnum)-$*/build + # And finally the symvers + install -m644 $(srcdir)/Module.symvers \ + $(hdrdir)/Module.symvers + +custom-binary-%: pkgimg = linux-image-$(release)$(debnum)-$* +custom-binary-%: pkghdr = linux-headers-$(release)$(debnum)-$* +custom-binary-%: custom-install-% + dh_testdir + dh_testroot + + dh_installchangelogs -p$(pkgimg) + dh_installdocs -p$(pkgimg) + dh_compress -p$(pkgimg) + dh_fixperms -p$(pkgimg) + dh_installdeb -p$(pkgimg) + dh_gencontrol -p$(pkgimg) + dh_md5sums -p$(pkgimg) + dh_builddeb -p$(pkgimg) -- -Zbzip2 -z9 + + dh_installchangelogs -p$(pkghdr) + dh_installdocs -p$(pkghdr) + dh_compress -p$(pkghdr) + dh_fixperms -p$(pkghdr) + dh_shlibdeps -p$(pkghdr) + dh_installdeb -p$(pkghdr) + dh_gencontrol -p$(pkghdr) + dh_md5sums -p$(pkghdr) + dh_builddeb -p$(pkghdr) --- linux-2.6.24.orig/debian/rules.d/2-binary-arch.mk +++ linux-2.6.24/debian/rules.d/2-binary-arch.mk @@ -0,0 +1,224 @@ +# We don't want make removing intermediary stamps +.SECONDARY : + +# Prepare the out-of-tree build directory + +prepare-%: $(stampdir)/stamp-prepare-% + @# Empty for make to be happy +$(stampdir)/stamp-prepare-%: target_flavour = $* +$(stampdir)/stamp-prepare-%: $(confdir)/config $(confdir)/config.% + @echo "Preparing $*..." + install -d $(builddir)/build-$* + touch $(builddir)/build-$*/ubuntu-build + cat $^ | sed -e 's/.*CONFIG_VERSION_SIGNATURE.*/CONFIG_VERSION_SIGNATURE="Ubuntu $(release)-$(revision)-$*"/' > $(builddir)/build-$*/.config + find $(builddir)/build-$* -name "*.ko" | xargs rm -f + $(kmake) O=$(builddir)/build-$* silentoldconfig prepare scripts + touch $@ + + +# Do the actual build, including image and modules +build-%: $(stampdir)/stamp-build-% + @# Empty for make to be happy +$(stampdir)/stamp-build-%: target_flavour = $* +$(stampdir)/stamp-build-%: $(stampdir)/stamp-prepare-% + @echo "Building $*..." + $(kmake) O=$(builddir)/build-$* $(conc_level) $(build_image) + $(kmake) O=$(builddir)/build-$* $(conc_level) modules + @touch $@ + +# Install the finished build +install-%: pkgdir = $(CURDIR)/debian/linux-image-$(release)$(debnum)-$* +install-%: dbgpkgdir = $(CURDIR)/debian/linux-image-debug-$(release)$(debnum)-$* +install-%: basepkg = linux-headers-$(release)$(debnum) +install-%: hdrdir = $(CURDIR)/debian/$(basepkg)-$*/usr/src/$(basepkg)-$* +install-%: target_flavour = $* +install-%: $(stampdir)/stamp-build-% checks-% + dh_testdir + dh_testroot + dh_clean -k -plinux-image-$(release)$(debnum)-$* + dh_clean -k -plinux-headers-$(release)$(debnum)-$* + dh_clean -k -plinux-image-debug-$(release)$(debnum)-$* + + # The main image +ifeq ($(compress_file),) + install -m644 -D $(builddir)/build-$*/$(kernel_file) \ + $(pkgdir)/boot/$(install_file)-$(release)$(debnum)-$* +else + install -d $(pkgdir)/boot/ + gzip -c9v $(builddir)/build-$*/$(kernel_file) > \ + $(pkgdir)/boot/$(install_file)-$(release)$(debnum)-$* + chmod 644 $(pkgdir)/boot/$(install_file)-$(release)$(debnum)-$* +endif + install -m644 $(builddir)/build-$*/.config \ + $(pkgdir)/boot/config-$(release)$(debnum)-$* + install -m644 $(abidir)/$* \ + $(pkgdir)/boot/abi-$(release)$(debnum)-$* + install -m644 $(builddir)/build-$*/System.map \ + $(pkgdir)/boot/System.map-$(release)$(debnum)-$* + $(kmake) O=$(builddir)/build-$* modules_install \ + INSTALL_MOD_PATH=$(pkgdir)/ + rm -f $(pkgdir)/lib/modules/$(release)$(debnum)-$*/build + rm -f $(pkgdir)/lib/modules/$(release)$(debnum)-$*/source +ifeq ($(no_image_strip),) + find $(pkgdir)/ -name \*.ko -print | xargs strip --strip-debug +endif + # Some initramfs-tools specific modules + install -d $(pkgdir)/lib/modules/$(release)$(debnum)-$*/initrd + if [ -f $(pkgdir)/lib/modules/$(release)$(debnum)-$*/kernel/drivers/video/vesafb.ko ]; then\ + ln -f $(pkgdir)/lib/modules/$(release)$(debnum)-$*/kernel/drivers/video/vesafb.ko \ + $(pkgdir)/lib/modules/$(release)$(debnum)-$*/initrd/; \ + fi + + # Now the image scripts + install -d $(pkgdir)/DEBIAN + for script in postinst postrm preinst prerm; do \ + sed -e 's/=V/$(release)$(debnum)-$*/g' -e 's/=K/$(install_file)/g' \ + -e 's/=L/$(loader)/g' -e 's@=B@$(build_arch)@g' \ + debian/control-scripts/$$script > $(pkgdir)/DEBIAN/$$script; \ + chmod 755 $(pkgdir)/DEBIAN/$$script; \ + done + + # Debug image is simple +ifneq ($(do_debug_image),) + install -m644 -D $(builddir)/build-$*/vmlinux \ + $(dbgpkgdir)//boot/vmlinux-debug-$(release)$(debnum)-$* +endif + + # The flavour specific headers image + # XXX Would be nice if we didn't have to dupe the original builddir + install -m644 -D $(builddir)/build-$*/.config \ + $(hdrdir)/.config + $(kmake) O=$(hdrdir) silentoldconfig prepare scripts + # We'll symlink this stuff + rm -f $(hdrdir)/Makefile + rm -rf $(hdrdir)/include2 + # Script to symlink everything up + $(SHELL) debian/scripts/link-headers "$(hdrdir)" "$(basepkg)" \ + "" "$(build_arch)" "$*" + # Setup the proper asm symlink + rm -f $(hdrdir)/include/asm + ln -s asm-$(asm_link) $(hdrdir)/include/asm + # The build symlink + install -d debian/$(basepkg)-$*/lib/modules/$(release)$(debnum)-$* + ln -s /usr/src/$(basepkg)-$* \ + debian/$(basepkg)-$*/lib/modules/$(release)$(debnum)-$*/build + # And finally the symvers + install -m644 $(builddir)/build-$*/Module.symvers \ + $(hdrdir)/Module.symvers + + # Now the header scripts + install -d $(CURDIR)/debian/$(basepkg)-$*/DEBIAN + for script in postinst; do \ + sed -e 's/=V/$(release)$(debnum)-$*/g' -e 's/=K/$(install_file)/g' \ + debian/control-scripts/headers-$$script > \ + $(CURDIR)/debian/$(basepkg)-$*/DEBIAN/$$script; \ + chmod 755 $(CURDIR)/debian/$(basepkg)-$*/DEBIAN/$$script; \ + done + + # At the end of the package prep, call the tests + DPKG_ARCH="$(arch)" KERN_ARCH="$(build_arch)" FLAVOUR="$*" \ + VERSION="$(release)$(debnum)" REVISION="$(revision)" \ + PREV_REVISION="$(prev_revision)" ABI_NUM="$(abinum)" \ + PREV_ABI_NUM="$(prev_abinum)" BUILD_DIR="$(builddir)/build-$*" \ + INSTALL_DIR="$(pkgdir)" SOURCE_DIR="$(CURDIR)" \ + run-parts -v debian/tests + + +headers_tmp := $(CURDIR)/debian/tmp-headers +headers_dir := $(CURDIR)/debian/linux-libc-dev + +hmake := $(MAKE) -C $(CURDIR) O=$(headers_tmp) SUBLEVEL=$(SUBLEVEL) \ + EXTRAVERSION=$(debnum) INSTALL_HDR_PATH=$(headers_tmp)/install \ + SHELL="$(SHELL)" + +install-arch-headers: + dh_testdir + dh_testroot + dh_clean -k -plinux-libc-dev + + rm -rf $(headers_tmp) + install -d $(headers_tmp) $(headers_dir)/usr/include/ + + $(hmake) ARCH=$(header_arch) $(defconfig) + mv $(headers_tmp)/.config $(headers_tmp)/.config.old + sed -e 's/^# \(CONFIG_MODVERSIONS\) is not set$$/\1=y/' \ + -e 's/.*CONFIG_LOCALVERSION_AUTO.*/# CONFIG_LOCALVERSION_AUTO is not set/' \ + $(headers_tmp)/.config.old > $(headers_tmp)/.config + $(hmake) ARCH=$(header_arch) silentoldconfig + $(hmake) ARCH=$(header_arch) headers_install + + mv $(headers_tmp)/install/include/asm* \ + $(headers_dir)/usr/include/ + mv $(headers_tmp)/install/include/linux \ + $(headers_dir)/usr/include/ + + rm -rf $(headers_tmp) + +binary-arch-headers: install-arch-headers + dh_testdir + dh_testroot + + dh_installchangelogs -plinux-libc-dev + dh_installdocs -plinux-libc-dev + dh_compress -plinux-libc-dev + dh_fixperms -plinux-libc-dev + dh_installdeb -plinux-libc-dev + dh_gencontrol -plinux-libc-dev + dh_md5sums -plinux-libc-dev + dh_builddeb -plinux-libc-dev + +binary-%: pkgimg = linux-image-$(release)$(debnum)-$* +binary-%: pkghdr = linux-headers-$(release)$(debnum)-$* +binary-%: dbgpkg = linux-image-debug-$(release)$(debnum)-$* +binary-%: install-% + dh_testdir + dh_testroot + + dh_installchangelogs -p$(pkgimg) + dh_installdocs -p$(pkgimg) + dh_compress -p$(pkgimg) + dh_fixperms -p$(pkgimg) + dh_installdeb -p$(pkgimg) + dh_gencontrol -p$(pkgimg) + dh_md5sums -p$(pkgimg) + dh_builddeb -p$(pkgimg) -- -Zbzip2 -z9 + + dh_installchangelogs -p$(pkghdr) + dh_installdocs -p$(pkghdr) + dh_compress -p$(pkghdr) + dh_fixperms -p$(pkghdr) + dh_shlibdeps -p$(pkghdr) + dh_installdeb -p$(pkghdr) + dh_gencontrol -p$(pkghdr) + dh_md5sums -p$(pkghdr) + dh_builddeb -p$(pkghdr) + +ifneq ($(do_debug_image),) + dh_installchangelogs -p$(dbgpkg) + dh_installdocs -p$(dbgpkg) + dh_compress -p$(dbgpkg) + dh_fixperms -p$(dbgpkg) + dh_installdeb -p$(dbgpkg) + dh_gencontrol -p$(dbgpkg) + dh_md5sums -p$(dbgpkg) + dh_builddeb -p$(dbgpkg) +endif + +$(stampdir)/stamp-flavours: + @echo $(flavours) $(custom_flavours) > $@ + +binary-debs: $(stampdir)/stamp-flavours $(addprefix binary-,$(flavours)) \ + binary-arch-headers + +build-debs: $(addprefix build-,$(flavours)) + +build-arch-deps = build-debs +build-arch-deps += build-custom + +build-arch: $(build-arch-deps) + +binary-arch-deps = binary-debs +binary-arch-deps += binary-custom +binary-arch-deps += binary-udebs + +binary-arch: $(binary-arch-deps) --- linux-2.6.24.orig/debian/rules.d/powerpc.mk +++ linux-2.6.24/debian/rules.d/powerpc.mk @@ -0,0 +1,12 @@ +build_arch = powerpc +header_arch = $(build_arch) +asm_link = $(build_arch) +defconfig = pmac32_defconfig +flavours = powerpc powerpc-smp powerpc64-smp +build_image = vmlinux +kernel_file = $(build_image) +install_file = $(build_image) + +loader = yaboot + +custom_flavours = --- linux-2.6.24.orig/debian/rules.d/5-udebs.mk +++ linux-2.6.24/debian/rules.d/5-udebs.mk @@ -0,0 +1,31 @@ +do-binary-udebs: + dh_testdir + dh_testroot + + # unpack the kernels into a temporary directory + mkdir -p debian/d-i-${arch} + + imagelist=$$(cat kernel-versions | grep ^${arch} | awk '{print $$4}') && \ + for i in $$imagelist; do \ + dpkg -x $$(ls ../linux-image-$$i\_*${arch}.deb) \ + debian/d-i-${arch}; \ + done + + touch ignore-dups + export SOURCEDIR=debian/d-i-${arch} && \ + kernel-wedge install-files && \ + kernel-wedge check + + # Build just the udebs + dilist=$$(dh_listpackages -s | grep "\-di$$") && \ + [ -z "$dilist" ] || \ + for i in $$dilist; do \ + dh_fixperms -p$$i; \ + dh_gencontrol -p$$i; \ + dh_builddeb -p$$i; \ + done + +binary-udebs: binary-debs binary-custom debian/control + if [ "$(disable_d_i)" != "true" ]; then \ + debian/rules do-binary-udebs; \ + fi --- linux-2.6.24.orig/debian/rules.d/hppa.mk +++ linux-2.6.24/debian/rules.d/hppa.mk @@ -0,0 +1,12 @@ +build_arch = parisc +header_arch = $(build_arch) +asm_link = $(build_arch) +defconfig = defconfig +flavours = hppa32 hppa64 +build_image = vmlinux +kernel_file = $(build_image) +install_file = $(build_image) + +no_image_strip = true + +loader = palo --- linux-2.6.24.orig/debian/rules.d/ia64.mk +++ linux-2.6.24/debian/rules.d/ia64.mk @@ -0,0 +1,11 @@ +build_arch = ia64 +header_arch = $(build_arch) +asm_link = $(build_arch) +defconfig = defconfig +flavours = itanium mckinley +build_image = vmlinux +kernel_file = $(build_image) +install_file = vmlinuz +compress_file = yes + +loader = elilo --- linux-2.6.24.orig/debian/rules.d/1-maintainer.mk +++ linux-2.6.24/debian/rules.d/1-maintainer.mk @@ -0,0 +1,107 @@ +# The following targets are for the maintainer only! do no run if you don't +# know what they do. + +.PHONY: printenv updateconfigs printchanges insertchanges startnewrelease diffupstream help + +help: + @echo "These are the targets in addition to the normal debian ones:" + @echo + @echo " printenv : Print some variables used in the build" + @echo + @echo " updateconfigs : Update debian/config/*" + @echo + @echo " editconfigs : Update debian/config/* interactively" + @echo + @echo " printchanges : Print the current changelog entries (from git)" + @echo + @echo " insertchanges : Insert current changelog entries (from git)" + @echo + @echo " startnewrelease : Start a new changelog set" + @echo + @echo " diffupstream : Diff stock kernel code against upstream (git)" + @echo + @echo " prepare-ppa : Prepare a PPA source upload" + @echo + @echo " help : If you are kernel hacking, you need the professional" + @echo " version of this" + @echo + @echo "Environment variables:" + @echo + @echo " NOKERNLOG : Do not add upstream kernel commits to changelog" + @echo " CONCURRENCY_LEVEL=X" + @echo " : Use -jX for kernel compile" + @echo " PRINTSHAS : Include SHAs for commits in changelog" + +ARCH_CONFIGS=i386 amd64 ia64 hppa powerpc sparc + +updateconfigs: + dh_testdir + @for arch in $(ARCH_CONFIGS); do \ + $(SHELL) debian/scripts/misc/oldconfig $$arch; \ + done + rm -rf build + +editconfigs: + dh_testdir + @for arch in $(ARCH_CONFIGS); do \ + $(SHELL) debian/scripts/misc/doconfig $$arch; \ + done + rm -rf build + +printenv: + dh_testdir + @echo "release = $(release)" + @echo "revisions = $(revisions)" + @echo "revision = $(revision)" + @echo "prev_revisions = $(prev_revisions)" + @echo "prev_revision = $(prev_revision)" + @echo "debnum = $(debnum)" + @echo "abinum = $(abinum)" + @echo "gitver = $(gitver)" + @echo "flavours = $(flavours)" + @echo "custom_flavours = $(custom_flavours)" +ifneq ($(SUBLEVEL),) + @echo "SUBLEVEL = $(SUBLEVEL)" +endif + @echo "CONCURRENCY_LEVEL = $(CONCURRENCY_LEVEL)" + +printchanges: + @git-log Ubuntu-$(release)-$(prev_revision)..HEAD | \ + perl -w -f debian/scripts/misc/git-ubuntu-log $(ubuntu_log_opts) + +insertchanges: + @perl -w -f debian/scripts/misc/insert-changes.pl + +diffupstream: + @git-diff-tree -p refs/remotes/linux-2.6/master..HEAD $(shell ls | grep -vE '^(ubuntu|debian|\.git.*)') + +startnewrelease: + dh_testdir + @nextminor=$(shell expr `echo $(revision) | awk -F. '{print $$2}'` + 1); \ + user=$(shell whoami); \ + memyselfandirene="$$(getent passwd $$user | cut -d ":" -f 5 | cut -d "," -f 1)"; \ + now="$(shell date -R)"; \ + echo "Creating new changelog set for $(release)-$(abinum).$$nextminor..."; \ + echo -e "linux ($(release)-$(abinum).$$nextminor) UNRELEASED; urgency=low\n" > debian/changelog.new; \ + echo " CHANGELOG: Do not edit directly. Autogenerated at release." >> \ + debian/changelog.new; \ + echo " CHANGELOG: Use the printchanges target to see the curent changes." \ + >> debian/changelog.new; \ + echo " CHANGELOG: Use the insertchanges target to create the final log." \ + >> debian/changelog.new; \ + echo -e "\n -- $$memyselfandirene <$$user@ubuntu.com> $$now\n" >> \ + debian/changelog.new ; \ + cat debian/changelog >> debian/changelog.new; \ + mv debian/changelog.new debian/changelog + +# +# If $(ppa_file) exists, then only the standard flavours are built for PPA, e.g., +# 386, 386-generic, and amd64-generic. +# +prepare-ppa: + @echo Execute debian/scripts/misc/prepare-ppa-source to prepare an upload + @echo for a PPA build. You must do this outside of debian/rules since it cannot + @echo nest. + +print-ppa-file-name: + @echo $(ppa_file) --- linux-2.6.24.orig/debian/rules.d/0-common-vars.mk +++ linux-2.6.24/debian/rules.d/0-common-vars.mk @@ -0,0 +1,120 @@ +# Rip some version information from our changelog +release := $(shell sed -n '1s/^.*(\(.*\)-.*).*$$/\1/p' debian/changelog) +revisions := $(shell sed -n 's/^linux\ .*($(release)-\(.*\)).*$$/\1/p' debian/changelog | tac) +revision ?= $(word $(words $(revisions)),$(revisions)) +prev_revisions := $(filter-out $(revision),0.0 $(revisions)) +prev_revision := $(word $(words $(prev_revisions)),$(prev_revisions)) + +# This is an internally used mechanism for the daily kernel builds. It +# creates packages who's ABI is suffixed with a minimal representation of +# the current git HEAD sha. If .git/HEAD is not present, then it uses the +# uuidgen program, +# +# AUTOBUILD can also be used by anyone wanting to build a custom kernel +# image, or rebuild the entire set of Ubuntu packages using custom patches +# or configs. +ppa_file := $(CURDIR)/ppa_build_sha +is_ppa_build := $(shell if [ -f $(ppa_file) ] ; then echo yes; fi;) +ifndef AUTOBUILD +AUTOBUILD := $(is_ppa_build) +endif + +# +# This is a way to support some external variables. A good example is +# a local setup for ccache and distcc See LOCAL_ENV_CC and +# LOCAL_ENV_DISTCC_HOSTS in the definition of kmake. +# For example: +# LOCAL_ENV_CC="ccache distcc" +# LOCAL_ENV_DISTCC_HOSTS="localhost 10.0.2.5 10.0.2.221" +# +local_env_file := $(CURDIR)/../.hardy-env +have_local_env := $(shell if [ -f $(local_env_file) ] ; then echo yes; fi;) +ifneq ($(have_local_env),) +include $(local_env_file) +endif + +# +# Set this variable to 'true' in the arch makefile in order to +# avoid building udebs for the debian installer. see lpia.mk as +# an example of an architecture specific override. +# +disable_d_i = no + +export AUTOBUILD +ifeq ($(AUTOBUILD),) +abi_suffix = +else +skipabi = true +skipmodule = true +gitver=$(shell if test -f .git/HEAD; then cat .git/HEAD; else uuidgen; fi) +gitverpre=$(shell echo $(gitver) | cut -b -3) +gitverpost=$(shell echo $(gitver) | cut -b 38-40) +abi_suffix = -$(gitverpre)$(gitverpost) +endif + +ifeq ($(prev_revision),0.0) +skipabi = true +skipmodule = true +endif + +ifneq ($(NOKERNLOG),) +ubuntu_log_opts += --no-kern-log +endif +ifneq ($(PRINTSHAS),) +ubuntu_log_opts += --print-shas +endif + +abinum := $(shell echo $(revision) | sed -e 's/\..*//')$(abisuffix) +prev_abinum := $(shell echo $(prev_revision) | sed -e 's/\..*//')$(abisuffix) +debnum := -$(abinum) + +# We force the sublevel to be exactly what we want. The actual source may +# be an in development git tree. We want to force it here instead of +# committing changes to the top level Makefile +SUBLEVEL := $(shell echo $(release) | awk -F. '{print $$3}') + +export abinum debnum version + +arch := $(shell dpkg-architecture -qDEB_HOST_ARCH) +abidir := $(CURDIR)/debian/abi/$(release)-$(revision)/$(arch) +prev_abidir := $(CURDIR)/debian/abi/$(release)-$(prev_revision)/$(arch) +confdir := $(CURDIR)/debian/config/$(arch) +builddir := $(CURDIR)/debian/build +stampdir := $(CURDIR)/debian/stamps + +# Support parallel= in DEB_BUILD_OPTIONS (see #209008) +COMMA=, +ifneq (,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) + CONCURRENCY_LEVEL := $(subst parallel=,,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) +endif + +ifeq ($(CONCURRENCY_LEVEL),) + # Check the environment + CONCURRENCY_LEVEL := $(shell echo $$CONCURRENCY_LEVEL) + # No? Check if this is on a buildd + ifeq ($(CONCURRENCY_LEVEL),) + ifeq ($(wildcard /CurrentlyBuilding),) + CONCURRENCY_LEVEL := $(shell expr `getconf _NPROCESSORS_ONLN` \* 2) + endif + endif + # Default to hogging them all (and then some) + ifeq ($(CONCURRENCY_LEVEL),) + CONCURRENCY_LEVEL := $(shell expr `getconf _NPROCESSORS_ONLN` \* 2) + endif +endif + +conc_level = -j$(CONCURRENCY_LEVEL) + +# target_flavour is filled in for each step +kmake = make ARCH=$(build_arch) EXTRAVERSION=$(debnum)-$(target_flavour) +kmake += SUBLEVEL=$(SUBLEVEL) +ifneq ($(LOCAL_ENV_CC),) +kmake += CC=$(LOCAL_ENV_CC) DISTCC_HOSTS=$(LOCAL_ENV_DISTCC_HOSTS) +endif + +all_custom_flavours = lpia rt lpiacompat xen openvz + +# Checks if a var is overriden by the custom rules. Called with var and +# flavour as arguments. +custom_override = \ + $(shell if [ -n "$($(1)_$(2))" ]; then echo "$($(1)_$(2))"; else echo "$($(1))"; fi) --- linux-2.6.24.orig/debian/rules.d/i386.mk +++ linux-2.6.24/debian/rules.d/i386.mk @@ -0,0 +1,21 @@ +build_arch = i386 +header_arch = x86_64 +asm_link = x86 +defconfig = defconfig +# +# Only build -386 and -generic for PPA. +# +flavours = 386 generic +flavours += server virtual +build_image = bzImage +kernel_file = arch/$(build_arch)/boot/bzImage +install_file = vmlinuz + +do_debug_image = true + +loader = grub + +# +# No custom binaries for the PPA build. +# +custom_flavours = rt xen openvz --- linux-2.6.24.orig/debian/rules.d/sparc.mk +++ linux-2.6.24/debian/rules.d/sparc.mk @@ -0,0 +1,11 @@ +build_arch = sparc64 +header_arch = $(build_arch) +asm_link = $(build_arch) +defconfig = defconfig +flavours = sparc64 sparc64-smp +build_image = image +kernel_file = arch/$(build_arch)/boot/image +install_file = vmlinuz +compress_file = Yes + +loader = silo --- linux-2.6.24.orig/debian/control.stub.in +++ linux-2.6.24/debian/control.stub.in @@ -0,0 +1,81 @@ +Source: linux +Section: devel +Priority: optional +Maintainer: Ubuntu Kernel Team +Standards-Version: 3.6.1 +Build-Depends: debhelper (>= 3), module-init-tools, kernel-wedge (>= 2.24ubuntu1), gcc-4.1-hppa64 [hppa], binutils-hppa64 [hppa], device-tree-compiler [powerpc], gcc-4.1 [powerpc ia64], gawk [amd64 i386] +Build-Depends-Indep: xmlto, docbook-utils, gs, transfig, bzip2, sharutils + +Package: linux-kernel-devel +Architecture: all +Section: devel +Priority: optional +Depends: build-essential, git-core, gitk, rsync, curl, openssh-client, debhelper, kernel-package, kernel-wedge +Description: Linux kernel hacking dependencies + This is a dummy package that will install all possible packages + required to hack comfortably on the kernel. + +Package: linux-source-PKGVER +Architecture: all +Section: devel +Priority: optional +Provides: linux-source, linux-source-2.6 +Depends: binutils, bzip2, coreutils | fileutils (>= 4.0) +Recommends: libc-dev, gcc, make +Suggests: libncurses-dev | ncurses-dev, kernel-package, libqt3-dev +Description: Linux kernel source for version PKGVER with Ubuntu patches + This package provides the source code for the Linux kernel version PKGVER. + . + You may configure the kernel to your setup by typing "make config" and + following instructions, but you could get ncursesX.X-dev and try "make + menuconfig" for a jazzier, and easier to use interface. There are options + to use QT or GNOME based configuration interfaces, but they need + additional packages to be installed. Also, please read the detailed + documentation in the file + /usr/share/doc/linux-source-PKGVER/README.headers.gz. + . + If you wish to use this package to create a custom Linux kernel, then it + is suggested that you investigate the package kernel-package, which has + been designed to ease the task of creating kernel image packages. + . + If you are simply trying to build third-party modules for your kernel, + you do not want this package. Install the appropriate linux-headers + package instead. + +Package: linux-doc-PKGVER +Architecture: all +Section: doc +Priority: optional +Provides: linux-doc-2.6 +Conflicts: linux-doc-2.6 +Replaces: linux-doc-2.6 +Depends: coreutils | fileutils (>= 4.0) +Description: Linux kernel specific documentation for version PKGVER + This package provides the various readme's in the PKGVER kernel + Documentation/ subdirectory: these typically contain kernel-specific + installation notes for some drivers for example. See + /usr/share/doc/linux-doc-PKGVER/Documentation/00-INDEX for a list of what + is contained in each file. Please read the Changes file, as it contains + information about the problems, which may result by upgrading your + kernel. + +Package: linux-headers-PKGVER-ABINUM +Architecture: all +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0) +Provides: linux-headers, linux-headers-2.6 +Description: Header files related to Linux kernel version PKGVER + This package provides kernel header files for version PKGVER, for sites + that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-PKGVER-ABINUM/debian.README.gz for details + +Package: linux-libc-dev +Architecture: amd64 i386 powerpc sparc ia64 hppa lpia +Conflicts: libc6-dev (<< 2.3.2.ds1-6), libc6.1-dev (<< 2.3.2.ds1-6), dvb-dev (<< 1.0.1-6), amd64-libs-dev (<= 1.1), linux-kernel-headers +Replaces: libc6-dev (<< 2.3.2.ds1-6), libc6.1-dev (<< 2.3.2.ds1-6), dvb-dev (<< 1.0.1-6), linux-kernel-headers +Provides: linux-kernel-headers +Description: Linux Kernel Headers for development + This package provides headers from the Linux kernel. These headers + are used by the installed headers for GNU glibc and other system + libraries. --- linux-2.6.24.orig/debian/config/amd64/config.server +++ linux-2.6.24/debian/config/amd64/config.server @@ -0,0 +1,21 @@ +# +# Config options for config.server automatically generated by splitconfig.pl +# +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_DEADLINE=y +CONFIG_DEFAULT_IOSCHED="deadline" +# CONFIG_EDD_OFF is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_NETLABEL=y +CONFIG_NR_CPUS=64 +# CONFIG_PREEMPT_BKL is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_SCHED_SMT=y +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-4.6-server" --- linux-2.6.24.orig/debian/config/amd64/config.generic +++ linux-2.6.24/debian/config/amd64/config.generic @@ -0,0 +1,20 @@ +# +# Config options for config.generic automatically generated by splitconfig.pl +# +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_EDD_OFF=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_NETLABEL is not set +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT_BKL=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_SCHED_SMT is not set +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-4.6-generic" --- linux-2.6.24.orig/debian/config/amd64/config +++ linux-2.6.24/debian/config/amd64/config @@ -0,0 +1,2988 @@ +# +# Common config options automatically generated by splitconfig.pl +# +CONFIG_3C359=m +CONFIG_60XX_WDT=m +CONFIG_64BIT=y +CONFIG_6PACK=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_8129=y +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_9P_FS=m +CONFIG_ABYSS=m +CONFIG_AC97_BUS=m +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_ADFS is not set +# CONFIG_ACORN_PARTITION_CUMANA is not set +# CONFIG_ACORN_PARTITION_EESOX is not set +CONFIG_ACORN_PARTITION_ICS=y +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_ACPI=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BAY=m +CONFIG_ACPI_BLACKLIST_YEAR=0 +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_CONTAINER=m +CONFIG_ACPI_CUSTOM_DSDT_INITRD=y +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_DOCK=m +CONFIG_ACPI_EC=y +CONFIG_ACPI_FAN=m +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_NUMA=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_PROCFS=y +CONFIG_ACPI_PROCFS_POWER=y +CONFIG_ACPI_PROC_EVENT=y +CONFIG_ACPI_SBS=m +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SYSFS_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_ACPI_VIDEO=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ACT200L_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_ADM8211=m +CONFIG_ADVANTECH_WDT=m +CONFIG_AFFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_AFS_FS=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_AGP=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=m +CONFIG_AGP_SIS=m +CONFIG_AGP_VIA=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_AIRO=m +CONFIG_AIRO_CS=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_ALI_FIR=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_AMD8111_ETH=m +CONFIG_AMIGA_PARTITION=y +CONFIG_ANON_INODES=y +CONFIG_APPLICOM=m +CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_HIBERNATION_HEADER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_ARCH_SUPPORTS_OPROFILE=y +CONFIG_ARCNET=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_RIM_I=m +# CONFIG_ARPD is not set +CONFIG_ASK_IP_FIB_HASH=y +CONFIG_ASUS_LAPTOP=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ATA=m +CONFIG_ATALK=m +CONFIG_ATARI_PARTITION=y +CONFIG_ATA_ACPI=y +CONFIG_ATA_GENERIC=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_ATA_PIIX=m +CONFIG_ATL1=m +CONFIG_ATM=y +CONFIG_ATMEL=m +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_FORE200E=m +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E_MAYBE=m +CONFIG_ATM_FORE200E_PCA=y +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y +CONFIG_ATM_FORE200E_TX_RETRY=16 +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_LANAI=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_TCP=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_ATP=m +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_ARCH=y +CONFIG_AUDIT_TREE=y +CONFIG_AUTOFS4_FS=m +CONFIG_AUTOFS_FS=m +CONFIG_AUXDISPLAY=y +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_B43=m +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PIO=y +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_B43_DEBUG=y +CONFIG_B43_DMA=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +CONFIG_B43_LEDS=y +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_PCI_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_PIO=y +# CONFIG_B43_PIO_MODE is not set +CONFIG_B43_RFKILL=y +CONFIG_B44=m +CONFIG_B44_PCI=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_BACKLIGHT_CARILLO_RANCH=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_PROGEAR=m +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +CONFIG_BATTERY_DS2760=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +CONFIG_BCM43XX_PIO=y +# CONFIG_BCM43XX_PIO_MODE is not set +# CONFIG_BEFS_DEBUG is not set +CONFIG_BEFS_FS=m +CONFIG_BFS_FS=m +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_BITREVERSE=y +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI15X3=m +# CONFIG_BLK_DEV_AMD74XX is not set +CONFIG_BLK_DEV_ATIIXP=m +# CONFIG_BLK_DEV_BSG is not set +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +CONFIG_BLK_DEV_CMD64X=m +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_CRYPTOLOOP=m +# CONFIG_BLK_DEV_CS5520 is not set +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_CY82C693=m +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_DM=m +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_HPT34X=m +CONFIG_BLK_DEV_HPT366=m +CONFIG_BLK_DEV_IDE=m +CONFIG_BLK_DEV_IDEACPI=y +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDEDISK=m +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_BLK_DEV_IDETAPE=m +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_MD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_NS87415=m +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_OPTI621=m +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +CONFIG_BLK_DEV_PDC202XX_OLD=m +# CONFIG_BLK_DEV_PIIX is not set +CONFIG_BLK_DEV_PLATFORM=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_SC1200=m +CONFIG_BLK_DEV_SD=m +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +# CONFIG_BLK_DEV_SVWKS is not set +CONFIG_BLK_DEV_SX8=m +CONFIG_BLK_DEV_TC86C001=m +# CONFIG_BLK_DEV_TRIFLEX is not set +CONFIG_BLK_DEV_TRM290=m +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLOCK=y +CONFIG_BLOCK_COMPAT=y +CONFIG_BNX2=m +CONFIG_BONDING=m +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOUNCE=y +CONFIG_BPQETHER=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_NETFILTER=y +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BROADCOM_PHY=m +CONFIG_BSD_DISKLABEL=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_BT=m +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIVHCI=m +CONFIG_BT_HIDP=m +CONFIG_BT_L2CAP=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_SCO=m +CONFIG_BUG=y +CONFIG_CALGARY_IOMMU=y +CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y +CONFIG_CAPI_AVM=y +CONFIG_CAPI_EICON=y +CONFIG_CAPI_TRACE=y +CONFIG_CARDBUS=y +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_CASSINI=m +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR_ALL is not set +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_CFAG12864B=m +CONFIG_CFAG12864B_RATE=20 +CONFIG_CFG80211=m +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_NS=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_CHR_DEV_OSST=m +CONFIG_CHR_DEV_SCH=m +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_ST=m +CONFIG_CICADA_PHY=m +CONFIG_CIFS=m +# CONFIG_CIFS_DEBUG2 is not set +CONFIG_CIFS_EXPERIMENTAL=y +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_WEAK_PW_HASH=y +# CONFIG_CIFS_XATTR is not set +CONFIG_CISS_SCSI_TAPE=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CODA_FS=m +# CONFIG_CODA_FS_OLD_API is not set +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_COMPUTONE=m +CONFIG_CONFIGFS_FS=m +CONFIG_CONNECTOR=m +CONFIG_CPU5_WDT=m +CONFIG_CPUSETS=y +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_DEBUG is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_TABLE=m +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CRAMFS=y +CONFIG_CRASH_DUMP=y +CONFIG_CRC16=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_CRC_CCITT=m +CONFIG_CRC_ITU_T=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_AES_X86_64=m +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_TWOFISH_X86_64=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_CYCLADES=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +# CONFIG_CYZ_INTR is not set +CONFIG_DAB=y +CONFIG_DAVICOM_PHY=m +CONFIG_DCA=m +CONFIG_DCDBAS=m +CONFIG_DE2104X=m +CONFIG_DE4X5=m +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MUTEXES is not set +CONFIG_DEBUG_RODATA=y +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +CONFIG_DECNET=m +CONFIG_DECNET_NF_GRABULATOR=m +# CONFIG_DECNET_ROUTER is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_BIC is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_HTCP is not set +CONFIG_DEFAULT_IO_DELAY_TYPE=1 +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_RELATIME=y +CONFIG_DEFAULT_RELATIME_VAL=1 +CONFIG_DEFAULT_RENO=y +CONFIG_DEFAULT_TCP_CONG="reno" +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_DELL_RBU=m +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_DEVPORT=y +CONFIG_DEV_APPLETALK=m +# CONFIG_DEV_KMEM is not set +CONFIG_DE_AOC=y +CONFIG_DIGIEPCA=m +CONFIG_DISCONTIGMEM=y +CONFIG_DISCONTIGMEM_MANUAL=y +CONFIG_DISPLAY_SUPPORT=m +CONFIG_DL2K=m +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_DM9102=m +CONFIG_DMADEVICES=y +# CONFIG_DMAR is not set +CONFIG_DMA_ENGINE=y +CONFIG_DMI=y +CONFIG_DMIID=y +CONFIG_DM_CRYPT=m +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_MIRROR=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m +CONFIG_DM_MULTIPATH_HP=m +CONFIG_DM_MULTIPATH_RDAC=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_UEVENT=y +CONFIG_DM_ZERO=m +CONFIG_DNOTIFY=y +CONFIG_DONGLE=y +CONFIG_DRM=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_I915=m +CONFIG_DRM_MGA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_SAVAGE=m +CONFIG_DRM_SIS=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_VIA=m +CONFIG_DRM_VIA_CHROME9=m +CONFIG_DS1682=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DUMMY=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_B2C2_FLEXCOP=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_BT8XX=m +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_PATCH=m +CONFIG_DVB_CAPTURE_DRIVERS=y +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m +# CONFIG_DVB_FE_CUSTOMISE is not set +CONFIG_DVB_ISL6421=m +CONFIG_DVB_L64781=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LNBP21=m +CONFIG_DVB_MT312=m +CONFIG_DVB_MT352=m +CONFIG_DVB_NXT200X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_PLL=m +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_STV0297=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_TUNER_DIB0070=m +CONFIG_DVB_TUNER_MT2060=m +CONFIG_DVB_TUNER_MT2131=m +CONFIG_DVB_TUNER_MT2266=m +CONFIG_DVB_TUNER_QT1010=m +CONFIG_DVB_USB=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_CXUSB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_ZL10353=m +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E1000_NAPI=y +CONFIG_EARLY_PRINTK=y +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_ECRYPT_FS=m +CONFIG_EDAC=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_E752X=m +CONFIG_EDAC_I5000=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_MM_EDAC=m +CONFIG_EDD=y +CONFIG_EEPRO100=m +CONFIG_EEPROM_93CX6=m +CONFIG_EFI_PARTITION=y +CONFIG_EFS_FS=m +CONFIG_ELF_CORE=y +CONFIG_EMBEDDED=y +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +CONFIG_EPIC100=m +CONFIG_EPOLL=y +CONFIG_EQUALIZER=m +CONFIG_ESI_DONGLE=m +CONFIG_EUROTECH_WDT=m +CONFIG_EVENTFD=y +CONFIG_EXPERIMENTAL=y +CONFIG_EXPORTFS=m +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_FAIR_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_FAIR_USER_SCHED is not set +CONFIG_FARSYNC=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_FS=m +# CONFIG_FAULT_INJECTION is not set +CONFIG_FB=y +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_ARC=m +CONFIG_FB_ARK=m +CONFIG_FB_ASILIANT=y +CONFIG_FB_ATY=m +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_CIRRUS=m +CONFIG_FB_CYBER2000=m +CONFIG_FB_DDC=m +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_EFI=y +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_GX=m +CONFIG_FB_GEODE_GX1=m +# CONFIG_FB_GEODE_GX_SET_FBSIZE is not set +CONFIG_FB_GEODE_LX=m +CONFIG_FB_HECUBA=m +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_IMSTT=y +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_KYRO=m +CONFIG_FB_LE80578=m +# CONFIG_FB_MACMODES is not set +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_BACKLIGHT=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_I2C=y +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_PM3=m +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_BACKLIGHT=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_I2C=y +CONFIG_FB_S1D13XXX=m +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_SM501=m +CONFIG_FB_SVGALIB=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_SYS_IMAGEBLIT=m +CONFIG_FB_TILEBLITTING=y +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_UVESA=m +CONFIG_FB_VESA=m +CONFIG_FB_VGA16=m +# CONFIG_FB_VIRTUAL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FDDI=y +CONFIG_FEALNX=m +CONFIG_FIB_RULES=y +# CONFIG_FIREWIRE is not set +CONFIG_FIRMWARE_EDID=y +CONFIG_FIXED_MII_1000_FDX=y +# CONFIG_FIXED_MII_100_FDX is not set +# CONFIG_FIXED_MII_10_FDX is not set +CONFIG_FIXED_MII_AMNT=1 +CONFIG_FIXED_PHY=m +CONFIG_FIX_EARLYCON_MEM=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +# CONFIG_FORCED_INLINING is not set +CONFIG_FRAMEBUFFER_CONSOLE=m +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_FS_MBCACHE=m +CONFIG_FS_POSIX_ACL=y +CONFIG_FTL=m +CONFIG_FUJITSU_LAPTOP=m +CONFIG_FUSE_FS=m +CONFIG_FUSION=y +CONFIG_FUSION_CTL=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_SAS=m +CONFIG_FUSION_SPI=m +CONFIG_FUTEX=y +CONFIG_FW_LOADER=y +CONFIG_GACT_PROB=y +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GART_IOMMU=y +CONFIG_GENERIC_ACL=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_CPU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_GFS2_FS_LOCKING_NOLOCK=m +CONFIG_GIGASET_BASE=m +# CONFIG_GIGASET_DEBUG is not set +CONFIG_GIGASET_M101=m +CONFIG_GIGASET_M105=m +# CONFIG_GIGASET_UNDOCREQ is not set +CONFIG_GIRBIL_DONGLE=m +CONFIG_HAMACHI=m +CONFIG_HAMRADIO=y +CONFIG_HANGCHECK_TIMER=m +CONFIG_HAPPYMEAL=m +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y +CONFIG_HAVE_KVM=y +CONFIG_HDLC=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_X25=m +# CONFIG_HEADERS_CHECK is not set +CONFIG_HERMES=m +CONFIG_HFSPLUS_FS=m +CONFIG_HFS_FS=m +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SMP_POSSIBLE=y +CONFIG_HID=m +CONFIG_HIDRAW=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HID_FF is not set +CONFIG_HID_SUPPORT=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HIPPI=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_BKM_A4T=y +# CONFIG_HISAX_DEBUG is not set +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_ENTERNOW_PCI=y +CONFIG_HISAX_EURO=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HDLC=y +CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_MAX_CARDS=8 +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_NICCY=y +# CONFIG_HISAX_NO_KEYPAD is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_TELES_CS=m +CONFIG_HISAX_W6692=y +CONFIG_HOSTAP=m +CONFIG_HOSTAP_CS=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_PLX=m +CONFIG_HOTPLUG=y +CONFIG_HOTPLUG_CPU=y +CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI_ACPI=m +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m +CONFIG_HOTPLUG_PCI_FAKE=m +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HP100=m +CONFIG_HPET=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_HPET_MMAP=y +# CONFIG_HPET_RTC_IRQ is not set +CONFIG_HPET_TIMER=y +CONFIG_HPFS_FS=m +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_HT_IRQ=y +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_HWMON_VID=m +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_AMD=m +CONFIG_HW_RANDOM_INTEL=m +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_300 is not set +CONFIG_I2C=m +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCA=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +# CONFIG_I2C_DEBUG_CORE is not set +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_BUS=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_EXT_ADAPTEC_DMA64=y +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_PROC=m +CONFIG_I2O_SCSI=m +CONFIG_I6300ESB_WDT=m +CONFIG_I82092=m +# CONFIG_IA32_AOUT is not set +CONFIG_IA32_EMULATION=y +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_IBMOL=m +CONFIG_IBM_ASM=m +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +CONFIG_ICPLUS_PHY=m +CONFIG_IDE=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_IDE_ARM is not set +CONFIG_IDE_GENERIC=m +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_IDE_PROC_FS=y +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IEEE1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_OHCI1394=m +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE80211=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_CRYPT_WEP=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_IFB=m +# CONFIG_IKCONFIG is not set +CONFIG_INET=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET_AH=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_INET_DIAG=y +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_LRO=m +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_INFINIBAND_IPATH=m +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFTL=m +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_INPUT=y +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MOUSE=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_PCSPKR=m +CONFIG_INPUT_POLLDEV=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=m +CONFIG_INPUT_YEALINK=m +CONFIG_INSTRUMENTATION=y +CONFIG_INTEL_IOATDMA=m +# CONFIG_IOMMU_DEBUG is not set +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +# CONFIG_IO_DELAY_0X80 is not set +CONFIG_IO_DELAY_0XED=y +# CONFIG_IO_DELAY_NONE is not set +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_NONE=3 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +# CONFIG_IO_DELAY_UDELAY is not set +CONFIG_IP1000=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IPDDP=m +CONFIG_IPDDP_DECAP=y +CONFIG_IPDDP_ENCAP=y +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_POWEROFF=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPPP_FILTER=y +CONFIG_IPV6=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPW2100=m +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2200=m +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_DCCP=m +CONFIG_IP_DCCP_ACKVEC=y +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_IP_DCCP_TFRC_LIB=m +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_SCTP=m +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_TAB_BITS=12 +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_WRR=m +CONFIG_IRCOMM=m +CONFIG_IRDA=m +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_DEBUG=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_ULTRA=y +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRTTY_SIR=m +CONFIG_ISA_DMA_API=y +CONFIG_ISCSI_TCP=m +CONFIG_ISDN=m +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIDRV=m +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_MAINT=m +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVERSION=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_ISDN_DRV_HISAX=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_MPP=y +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_TTY_FAX=y +CONFIG_ISDN_X25=y +# CONFIG_ISI is not set +CONFIG_ISO9660_FS=m +CONFIG_IT8712F_WDT=m +CONFIG_ITCO_VENDOR_SUPPORT=y +CONFIG_ITCO_WDT=m +# CONFIG_IWLWIFI is not set +CONFIG_IXGB=m +CONFIG_IXGBE=m +# CONFIG_IXGB_NAPI is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +CONFIG_JFS_STATISTICS=y +CONFIG_JOLIET=y +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_K8_NB=y +CONFIG_K8_NUMA=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_KARMA_PARTITION=y +CONFIG_KEXEC=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +CONFIG_KINGSUN_DONGLE=m +CONFIG_KMOD=y +CONFIG_KPROBES=y +CONFIG_KS0108=m +CONFIG_KS0108_DELAY=2 +CONFIG_KS0108_PORT=0x378 +CONFIG_KS959_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +# CONFIG_KTIME_SCALAR is not set +CONFIG_KVM=m +CONFIG_KVM_AMD=m +CONFIG_KVM_INTEL=m +CONFIG_LANMEDIA=m +CONFIG_LAPB=m +CONFIG_LAPBETHER=m +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +# CONFIG_LDM_DEBUG is not set +CONFIG_LDM_PARTITION=y +CONFIG_LEDS_CLASS=m +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LIBCRC32C=m +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_CS=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_USB=m +CONFIG_LITELINK_DONGLE=m +# CONFIG_LKDTM is not set +CONFIG_LLC=y +CONFIG_LLC2=m +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_LOCKD=m +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +CONFIG_LOCK_KERNEL=y +# CONFIG_LOCK_STAT is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_LP_CONSOLE is not set +CONFIG_LSM_MMAP_MIN_ADDR=0 +CONFIG_LXT_PHY=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586MMX is not set +# CONFIG_M586TSC is not set +# CONFIG_M686 is not set +CONFIG_MA600_DONGLE=m +CONFIG_MAC80211=m +# CONFIG_MAC80211_DEBUG is not set +CONFIG_MAC80211_DEBUGFS=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MACHZ_WDT=m +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MACVLAN=m +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_MAC_PARTITION=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_MARKERS is not set +CONFIG_MARVELL_PHY=m +CONFIG_MAX_RAW_DEVS=256 +# CONFIG_MCORE2 is not set +CONFIG_MCP2120_DONGLE=m +# CONFIG_MCRUSOE is not set +CONFIG_MCS_FIR=m +# CONFIG_MCYRIXIII is not set +CONFIG_MD=y +CONFIG_MDIO_BITBANG=m +CONFIG_MD_FAULTY=m +CONFIG_MD_LINEAR=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +# CONFIG_MEFFICEON is not set +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_SAS=m +CONFIG_MFD_SM501=m +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +CONFIG_MICROCODE=m +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_MIGRATION=y +CONFIG_MII=m +CONFIG_MINIX_FS=m +CONFIG_MINIX_SUBPARTITION=y +CONFIG_MISC_DEVICES=y +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +CONFIG_MKISS=m +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_MLX4_INFINIBAND=m +CONFIG_MMC=m +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_SDHCI=m +CONFIG_MMC_SPI=m +CONFIG_MMC_TIFM_SD=m +# CONFIG_MMC_UNSAFE_RESUME is not set +CONFIG_MMC_WBSD=m +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_TRACKPOINT=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_MOXA_INTELLIO=m +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +# CONFIG_MPENTIUM4 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPSC is not set +CONFIG_MSDOS_FS=m +CONFIG_MSDOS_PARTITION=y +CONFIG_MSI_LAPTOP=m +# CONFIG_MSS is not set +CONFIG_MTD=m +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTD_ABSENT=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK2MTD=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_MTD_CFI=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_CHAR=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_CONCAT=m +CONFIG_MTD_DATAFLASH=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_DILNETPC=m +CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000 +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCECC=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCPROBE_ADDRESS=0 +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_L440GX=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTD_NAND=m +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND_IDS=m +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NETSC520=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_2X_PROGRAM=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_SIM=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_OOPS=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_PCI=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PLATRAM=m +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_PNC2000=m +CONFIG_MTD_RAM=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +CONFIG_MTD_REDBOOT_PARTS=m +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +CONFIG_MTD_ROM=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_TS5500=m +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTRR=y +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +CONFIG_MWAVE=m +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MWINCHIPC6 is not set +CONFIG_MYRI10GE=m +CONFIG_NATSEMI=m +CONFIG_NCPFS_EXTRAS=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_PACKET_SIGNING=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_STRONG=y +CONFIG_NCP_FS=m +CONFIG_NE2K_PCI=m +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_NET=y +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETDEVICES=y +CONFIG_NETDEVICES_MULTIQUEUE=y +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NETROM=m +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NETXEN_NIC=m +CONFIG_NET_9P=m +# CONFIG_NET_9P_DEBUG is not set +CONFIG_NET_9P_FD=m +CONFIG_NET_9P_VIRTIO=m +CONFIG_NET_ACT_GACT=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_CLS=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_FW=m +# CONFIG_NET_CLS_IND is not set +# CONFIG_NET_CLS_POLICE is not set +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_DCCPPROBE=m +CONFIG_NET_DMA=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_ETHERNET=y +CONFIG_NET_FC=y +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_NET_IPIP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_NET_PCI=y +CONFIG_NET_PCMCIA=y +CONFIG_NET_PKTGEN=m +CONFIG_NET_POCKET=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_NET_SB1000=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_FIFO=y +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_RR=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_TCPPROBE=m +CONFIG_NET_TULIP=y +CONFIG_NET_VENDOR_3COM=y +CONFIG_NEW_LEDS=y +CONFIG_NFSD=m +CONFIG_NFSD_TCP=y +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NIU=m +CONFIG_NL80211=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +CONFIG_NODES_SHIFT=6 +CONFIG_NONPROMISC_DEVMEM=y +# CONFIG_NORTEL_HERMES is not set +CONFIG_NO_HZ=y +CONFIG_NS83820=m +CONFIG_NSC_FIR=m +CONFIG_NSC_GPIO=m +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_FS=m +# CONFIG_NTFS_RW is not set +CONFIG_NUMA=y +# CONFIG_NUMA_EMU is not set +CONFIG_NVRAM=m +CONFIG_N_HDLC=m +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_OCFS2_DEBUG_MASKLOG=y +CONFIG_OCFS2_FS=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_OPROFILE=m +CONFIG_OSF_PARTITION=y +CONFIG_OUT_OF_LINE_PFN_TO_PAGE=y +CONFIG_P54_COMMON=m +CONFIG_P54_PCI=m +CONFIG_P54_USB=m +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_PARIDE=m +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PG=m +CONFIG_PARIDE_PT=m +CONFIG_PARPORT=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_AX88796=m +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_NOT_PC=y +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_FIFO=y +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_SERIAL=m +CONFIG_PARTITION_ADVANCED=y +CONFIG_PATA_ACPI=m +# CONFIG_PATA_ALI is not set +CONFIG_PATA_AMD=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +# CONFIG_PATA_CMD640_PCI is not set +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CS5520=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +CONFIG_PATA_HPT366=m +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +CONFIG_PATA_HPT3X3=m +# CONFIG_PATA_HPT3X3_DMA is not set +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NETCELL=m +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +CONFIG_PATA_OLDPIIX=m +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PCMCIA=m +CONFIG_PATA_PDC2027X=m +# CONFIG_PATA_PDC_OLD is not set +CONFIG_PATA_PLATFORM=m +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +CONFIG_PC300=m +# CONFIG_PC300TOO is not set +CONFIG_PC300_MLPPP=y +CONFIG_PC8736x_GPIO=m +CONFIG_PC87413_WDT=m +CONFIG_PCCARD=m +CONFIG_PCCARD_NONSTATIC=m +CONFIG_PCI=y +CONFIG_PCI200SYN=m +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIPCWATCHDOG=m +CONFIG_PCI_ATMEL=m +# CONFIG_PCI_DEBUG is not set +CONFIG_PCI_DIRECT=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_HERMES is not set +CONFIG_PCI_LEGACY=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_MSI=y +CONFIG_PCMCIA=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_AXNET=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_IOCTL=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_PD6729=m +CONFIG_PDA_POWER=m +CONFIG_PDC202XX_BURST=y +CONFIG_PDC_ADMA=m +CONFIG_PHANTOM=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m +CONFIG_PHYLIB=m +CONFIG_PHYSICAL_ALIGN=0x200000 +CONFIG_PHYSICAL_START=0x200000 +# CONFIG_PID_NS is not set +CONFIG_PLIP=m +CONFIG_PLIST=y +# CONFIG_PLX_HERMES is not set +CONFIG_PM=y +CONFIG_PM_DEBUG=y +CONFIG_PM_DISABLE_CONSOLE=y +CONFIG_PM_LEGACY=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_STD_PARTITION="" +CONFIG_PM_TRACE=y +# CONFIG_PM_VERBOSE is not set +CONFIG_PNP=y +CONFIG_PNPACPI=y +# CONFIG_PNP_DEBUG is not set +CONFIG_POSIX_MQUEUE=y +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PPDEV=m +CONFIG_PPP=m +CONFIG_PPPOATM=m +CONFIG_PPPOE=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_SYNC_TTY=m +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTER=m +CONFIG_PRINTK=y +CONFIG_PRINTK_TIME=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_PRISM54=m +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_VMCORE=y +CONFIG_PROFILING=y +# CONFIG_PROVE_LOCKING is not set +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_QLA3XXX=m +CONFIG_QNX4FS_FS=m +CONFIG_QSEMI_PHY=m +# CONFIG_QUICKLIST is not set +CONFIG_QUOTA=y +CONFIG_QUOTACTL=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_R3964=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RAID_ATTRS=m +CONFIG_RAW_DRIVER=m +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_FS=m +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_REISERFS_FS_XATTR=y +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_RELAY=y +CONFIG_RELOCATABLE=y +CONFIG_RESOURCES_64BIT=y +CONFIG_RFD_FTL=m +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +CONFIG_RIO=m +# CONFIG_RIO_OLDPCI is not set +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_ROCKETPORT=m +CONFIG_ROMFS_FS=m +CONFIG_ROSE=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT2X00=m +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RT2X00_LIB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT73USB=m +CONFIG_RTC=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_DEBUG is not set +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_TEST=m +CONFIG_RTC_DRV_V3020=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=y +CONFIG_RTL8187=m +CONFIG_RT_MUTEXES=y +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_RXKAD=m +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +# CONFIG_SAMPLES is not set +CONFIG_SATA_AHCI=m +CONFIG_SATA_INIC162X=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_SX4=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SBC8360_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m +CONFIG_SBNI=m +# CONFIG_SBNI_MULTILINE is not set +CONFIG_SC1200_WDT=m +CONFIG_SC520_WDT=m +CONFIG_SC92031=m +# CONFIG_SCHEDSTATS is not set +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_MC=y +CONFIG_SCSI=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_AIC79XX=m +CONFIG_SCSI_AIC7XXX=m +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC94XX=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_SCSI_BUSLOGIC=m +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DMA=y +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_IMM=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_DUMP is not set +# CONFIG_SCSI_IPR_TRACE is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_ISCSI_ATTRS=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_NETLINK=y +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +CONFIG_SCSI_PPA=m +CONFIG_SCSI_PROC_FS=y +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_TGT=m +CONFIG_SCSI_WAIT_SCAN=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SDIO_UART=m +CONFIG_SECCOMP=y +CONFIG_SECURITY=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +# CONFIG_SECURITY_APPARMOR_DISABLE is not set +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_DISABLE=y +# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SEMAPHORE_SLEEPERS=y +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_APPLESMC=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_HDAPS=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_TSL2550=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_SERIO=y +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_I8042=y +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_RAW=m +CONFIG_SERIO_SERPORT=m +CONFIG_SGI_IOC4=m +CONFIG_SGI_PARTITION=y +CONFIG_SHAPER=m +CONFIG_SHMEM=y +CONFIG_SIGMATEL_FIR=m +CONFIG_SIGNALFD=y +CONFIG_SIS190=m +CONFIG_SIS900=m +# CONFIG_SK98LIN is not set +CONFIG_SKFP=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +CONFIG_SLHC=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_SLIP_SMART=y +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_DEBUG_ON is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_SMC_IRCC_FIR=m +CONFIG_SMP=y +CONFIG_SMSC37B787_WDT=m +CONFIG_SMSC_PHY=m +# CONFIG_SND is not set +CONFIG_SOFT_WATCHDOG=m +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_SONYPI_COMPAT=y +CONFIG_SONY_LAPTOP=m +CONFIG_SOUND=m +# CONFIG_SOUND_PRIME is not set +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPECIALIX=m +# CONFIG_SPECIALIX_RTSCTS is not set +CONFIG_SPI=y +CONFIG_SPI_AT25=m +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_MASTER=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SSB=m +CONFIG_SSB_DEBUG=y +CONFIG_SSB_DRIVER_PCICORE=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB_SILENT is not set +CONFIG_SSFDC=m +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_STALDRV=y +CONFIG_STANDALONE=y +CONFIG_STOP_MACHINE=y +CONFIG_STRIP=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_SUNGEM=m +CONFIG_SUNRPC=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_SUN_PARTITION=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SWAP=y +CONFIG_SWIOTLB=y +CONFIG_SX=m +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_CS=m +CONFIG_SYNCLINK_GT=m +CONFIG_SYN_COOKIES=y +CONFIG_SYSCTL=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_SYSV68_PARTITION=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_SYSV_FS=m +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TCG_NSC=m +CONFIG_TCG_TIS=m +CONFIG_TCG_TPM=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_MD5SIG=y +CONFIG_TEHUTI=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_TELCLOCK=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_TEXTSEARCH_KMP=m +CONFIG_THINKPAD_ACPI=m +CONFIG_THINKPAD_ACPI_BAY=y +# CONFIG_THINKPAD_ACPI_DEBUG is not set +CONFIG_TICK_ONESHOT=y +CONFIG_TIFM_7XX1=m +CONFIG_TIFM_CORE=m +CONFIG_TIGON3=m +CONFIG_TIMER_STATS=y +# CONFIG_TINY_SHMEM is not set +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +# CONFIG_TMD_HERMES is not set +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TR=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TULIP=m +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_TUN=m +CONFIG_TUNER_3036=m +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_SIMPLE=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TYPHOON=m +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_DEBUG is not set +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +CONFIG_UID16=y +CONFIG_UIO=m +CONFIG_UIO_CIF=m +CONFIG_ULI526X=m +CONFIG_ULTRIX_PARTITION=y +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_USB=m +CONFIG_USBPCWATCHDOG=m +CONFIG_USB_ACM=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AMD5536UDC=m +CONFIG_USB_AN2720=y +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_ATM=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_BELKIN=y +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_CATC=m +CONFIG_USB_CXACRU=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_DABUSB=m +# CONFIG_USB_DEBUG is not set +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_DSBR=m +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EMI26=m +CONFIG_USB_EMI62=m +CONFIG_USB_EPSON2888=y +CONFIG_USB_ET61X251=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_EZUSB=y +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_GADGET=m +CONFIG_USB_GADGETFS=m +CONFIG_USB_GADGET_AMD5536UDC=y +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_S3C2410 is not set +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_G_SERIAL=m +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_HIDINPUT_POWERBOOK=y +CONFIG_USB_IBMCAM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_IRDA=m +CONFIG_USB_ISP116X_HCD=m +CONFIG_USB_KAWETH=m +CONFIG_USB_KBD=m +CONFIG_USB_KC2190=y +CONFIG_USB_KONICAWC=m +CONFIG_USB_LCD=m +CONFIG_USB_LD=m +CONFIG_USB_LED=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +# CONFIG_USB_MIDI_GADGET is not set +CONFIG_USB_MON=y +CONFIG_USB_MOUSE=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_RNDIS_HOST=m +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OV511 is not set +CONFIG_USB_PEGASUS=m +CONFIG_USB_PERSIST=y +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_PRINTER=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_R8A66597_HCD=m +CONFIG_USB_RIO500=m +CONFIG_USB_RTL8150=m +CONFIG_USB_SE401=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IPW=m +# CONFIG_USB_SERIAL_IR is not set +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_SL811_CS=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SN9C102=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_DATAFAB=y +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STV680=m +CONFIG_USB_SUPPORT=y +CONFIG_USB_SUSPEND=y +# CONFIG_USB_TEST is not set +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_USBNET=m +CONFIG_USB_USS720=m +CONFIG_USB_VICAM=m +CONFIG_USB_W9968CF=m +CONFIG_USB_XUSBATM=m +CONFIG_USB_ZC0301=m +CONFIG_USB_ZD1201=m +CONFIG_USB_ZERO=m +CONFIG_USB_ZR364XX=m +# CONFIG_USER_NS is not set +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VETH=m +CONFIG_VFAT_FS=m +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VGASTATE=m +CONFIG_VGA_CONSOLE=y +CONFIG_VIA_FIR=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_RHINE_NAPI=y +CONFIG_VIA_VELOCITY=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_CX25840=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_DEV=m +# CONFIG_VIDEO_DPC is not set +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_FB_IVTV=m +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_MSP3400=m +# CONFIG_VIDEO_MXB is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_29XXX=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_SAA7191=m +CONFIG_VIDEO_SELECT=y +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_TCM825X=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_VP27SMPX=m +CONFIG_VIDEO_VPX3220=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIRTIO=m +CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_BLK=m +CONFIG_VIRTIO_NET=m +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_RING=m +CONFIG_VIRTUALIZATION=y +CONFIG_VIRT_TO_BUS=y +CONFIG_VITESSE_PHY=m +CONFIG_VLAN_8021Q=m +CONFIG_VLSI_FIR=m +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VORTEX=m +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_VXFS_FS=m +CONFIG_W1=m +CONFIG_W1_CON=y +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_THERM=m +CONFIG_W83627HF_WDT=m +CONFIG_W83697HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_WAN=y +CONFIG_WANXL=m +CONFIG_WAN_ROUTER=m +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_WDC_ALI15X3 is not set +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y +CONFIG_WINBOND_840=m +CONFIG_WINBOND_FIR=m +CONFIG_WIRELESS_EXT=y +CONFIG_WLAN_80211=y +CONFIG_WLAN_PRE80211=y +# CONFIG_WRAPPER_PRINT is not set +CONFIG_X25=m +CONFIG_X25_ASY=m +CONFIG_X86=y +# CONFIG_X86_32 is not set +CONFIG_X86_64=y +CONFIG_X86_64_ACPI_NUMA=y +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +# CONFIG_X86_BIGSMP is not set +CONFIG_X86_CMPXCHG=y +CONFIG_X86_CPUID=m +# CONFIG_X86_ELAN is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_X86_GENERICARCH is not set +CONFIG_X86_GOOD_APIC=y +CONFIG_X86_HT=y +CONFIG_X86_INTERNODE_CACHE_BYTES=128 +CONFIG_X86_IO_APIC=y +CONFIG_X86_L1_CACHE_BYTES=128 +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_MCE=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_MSR=m +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_P4_CLOCKMOD is not set +CONFIG_X86_PC=y +CONFIG_X86_PM_TIMER=y +CONFIG_X86_POWERNOW_K8=m +CONFIG_X86_POWERNOW_K8_ACPI=y +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_SPEEDSTEP_LIB is not set +# CONFIG_X86_SUMMIT is not set +CONFIG_X86_TSC=y +# CONFIG_X86_VISWS is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_VSMP is not set +CONFIG_XFRM=y +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_USER=m +CONFIG_XFS_FS=m +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_QUOTA=y +CONFIG_XFS_RT=y +CONFIG_XFS_SECURITY=y +CONFIG_XOR_BLOCKS=m +CONFIG_YAM=m +CONFIG_YELLOWFIN=m +CONFIG_YENTA=m +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_ZISOFS=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZONE_DMA=y +CONFIG_ZONE_DMA32=y +CONFIG_ZONE_DMA_FLAG=1 --- linux-2.6.24.orig/debian/config/i386/config.server +++ linux-2.6.24/debian/config/i386/config.server @@ -0,0 +1,1957 @@ +# +# Config options for config.server automatically generated by splitconfig.pl +# +CONFIG_3C359=m +CONFIG_3C515=m +CONFIG_60XX_WDT=m +CONFIG_6PACK=m +CONFIG_8139CP=m +CONFIG_8139TOO_8129=y +CONFIG_9P_FS=m +CONFIG_ABYSS=m +CONFIG_AC3200=m +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BAY=m +CONFIG_ACPI_DOCK=m +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_SBS=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_ACPI_VIDEO=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ACT200L_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_ADM8211=m +CONFIG_ADVANTECH_WDT=m +CONFIG_AFFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_AFS_FS=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_AGP_ALI=m +CONFIG_AGP_AMD=m +CONFIG_AGP_AMD64=m +CONFIG_AGP_ATI=m +CONFIG_AGP_EFFICEON=m +CONFIG_AGP_NVIDIA=m +CONFIG_AGP_SIS=m +CONFIG_AGP_SWORKS=m +CONFIG_AGP_VIA=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_AIRO=m +CONFIG_AIRO_CS=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_ALI_FIR=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_AMD8111_ETH=m +CONFIG_APM=m +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_CPU_IDLE is not set +# CONFIG_APM_DISPLAY_BLANK is not set +# CONFIG_APM_DO_ENABLE is not set +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set +CONFIG_APPLICOM=m +CONFIG_APRICOT=m +CONFIG_ARCNET=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_ARCNET_COM20020_ISA=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARLAN=m +CONFIG_ASUS_LAPTOP=m +CONFIG_AT1700=m +CONFIG_ATA_OVER_ETH=m +CONFIG_ATL1=m +CONFIG_ATM=y +CONFIG_ATMEL=m +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_FORE200E=m +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E_MAYBE=m +CONFIG_ATM_FORE200E_PCA=y +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y +CONFIG_ATM_FORE200E_TX_RETRY=16 +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_LANAI=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_NICSTAR=m +# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set +# CONFIG_ATM_NICSTAR_USE_SUNI is not set +CONFIG_ATM_TCP=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_ATP=m +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_B43=m +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PIO=y +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_B43_DEBUG=y +CONFIG_B43_DMA=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +CONFIG_B43_LEDS=y +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_PCI_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_PIO=y +# CONFIG_B43_PIO_MODE is not set +CONFIG_B43_RFKILL=y +CONFIG_B44=m +CONFIG_B44_PCI=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_BACKLIGHT_CARILLO_RANCH=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_PROGEAR=m +CONFIG_BAYCOM_EPP=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +CONFIG_BCM43XX_PIO=y +# CONFIG_BCM43XX_PIO_MODE is not set +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_BLK_DEV_4DRIVES=y +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI14XX=m +CONFIG_BLK_DEV_ALI15X3=m +CONFIG_BLK_DEV_ATIIXP=m +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +CONFIG_BLK_DEV_CMD64X=m +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_CS5535=m +CONFIG_BLK_DEV_CY82C693=m +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_DTC2278=m +CONFIG_BLK_DEV_HPT34X=m +CONFIG_BLK_DEV_HPT366=m +CONFIG_BLK_DEV_HT6560B=m +CONFIG_BLK_DEV_IDE=m +CONFIG_BLK_DEV_IDEACPI=y +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_BLK_DEV_NS87415=m +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_OPTI621=m +CONFIG_BLK_DEV_PDC202XX_OLD=m +CONFIG_BLK_DEV_QD65XX=m +CONFIG_BLK_DEV_SC1200=m +CONFIG_BLK_DEV_SX8=m +CONFIG_BLK_DEV_TC86C001=m +CONFIG_BLK_DEV_TRM290=m +CONFIG_BLK_DEV_UMC8672=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_XD=m +CONFIG_BNX2=m +CONFIG_BPQETHER=m +CONFIG_BROADCOM_PHY=m +CONFIG_BT=m +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIVHCI=m +CONFIG_BT_HIDP=m +CONFIG_BT_L2CAP=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_SCO=m +CONFIG_C101=m +CONFIG_CAPI_AVM=y +CONFIG_CAPI_EICON=y +CONFIG_CAPI_TRACE=y +CONFIG_CARDBUS=y +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_CASSINI=m +CONFIG_CFAG12864B=m +CONFIG_CFAG12864B_RATE=20 +CONFIG_CFG80211=m +CONFIG_CHECK_SIGNATURE=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_CHR_DEV_OSST=m +CONFIG_CHR_DEV_SCH=m +CONFIG_CHR_DEV_ST=m +CONFIG_CICADA_PHY=m +CONFIG_CISS_SCSI_TAPE=y +# CONFIG_COMPUTONE is not set +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_COSA=m +CONFIG_CPU5_WDT=m +CONFIG_CPUSETS=y +CONFIG_CPU_FREQ_TABLE=m +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DEV_PADLOCK=y +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CS5535_GPIO=m +CONFIG_CS89x0=m +CONFIG_CYCLADES=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +# CONFIG_CYZ_INTR is not set +CONFIG_DAB=y +CONFIG_DAVICOM_PHY=m +CONFIG_DE2104X=m +CONFIG_DE4X5=m +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DECNET_NF_GRABULATOR=m +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_DEADLINE=y +CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_DEPCA=m +CONFIG_DE_AOC=y +CONFIG_DIGIEPCA=m +CONFIG_DISPLAY_SUPPORT=m +CONFIG_DL2K=m +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_DM9102=m +CONFIG_DONGLE=y +CONFIG_DRM=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_I915=m +CONFIG_DRM_MGA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_SAVAGE=m +CONFIG_DRM_SIS=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_VIA=m +CONFIG_DRM_VIA_CHROME9=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DTLK=m +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_B2C2_FLEXCOP=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_BT8XX=m +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_PATCH=m +CONFIG_DVB_CAPTURE_DRIVERS=y +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m +# CONFIG_DVB_FE_CUSTOMISE is not set +CONFIG_DVB_ISL6421=m +CONFIG_DVB_L64781=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LNBP21=m +CONFIG_DVB_MT312=m +CONFIG_DVB_MT352=m +CONFIG_DVB_NXT200X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_PLL=m +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_STV0297=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_TUNER_DIB0070=m +CONFIG_DVB_TUNER_MT2060=m +CONFIG_DVB_TUNER_MT2131=m +CONFIG_DVB_TUNER_MT2266=m +CONFIG_DVB_TUNER_QT1010=m +CONFIG_DVB_USB=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_CXUSB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_ZL10353=m +CONFIG_E100=m +CONFIG_E2100=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_EDAC=y +# CONFIG_EDAC_AMD76X is not set +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_E752X=m +CONFIG_EDAC_E7XXX=m +CONFIG_EDAC_I3000=m +CONFIG_EDAC_I5000=m +CONFIG_EDAC_I82860=m +CONFIG_EDAC_I82875P=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_MM_EDAC=m +CONFIG_EDAC_R82600=m +CONFIG_EDD=y +# CONFIG_EDD_OFF is not set +CONFIG_EEPRO100=m +CONFIG_EEXPRESS=m +CONFIG_EEXPRESS_PRO=m +CONFIG_EISA=y +CONFIG_EISA_NAMES=y +CONFIG_EISA_PCI_EISA=y +CONFIG_EISA_VIRTUAL_ROOT=y +CONFIG_EISA_VLB_PRIMING=y +CONFIG_EL1=m +CONFIG_EL16=m +CONFIG_EL2=m +CONFIG_EL3=m +CONFIG_ELMC=m +CONFIG_ELMC_II=m +CONFIG_ELPLUS=m +CONFIG_EPIC100=m +CONFIG_ES3210=m +CONFIG_ESI_DONGLE=m +# CONFIG_ESPSERIAL is not set +CONFIG_ETH16I=m +CONFIG_EUROTECH_WDT=m +CONFIG_EWRK3=m +CONFIG_FARSYNC=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_ARK=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_CYBER2000=m +CONFIG_FB_CYBLA=m +CONFIG_FB_DDC=m +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_GX=m +CONFIG_FB_GEODE_GX1=m +# CONFIG_FB_GEODE_GX_SET_FBSIZE is not set +CONFIG_FB_GEODE_LX=m +CONFIG_FB_HECUBA=m +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_I810=m +# CONFIG_FB_I810_GTF is not set +CONFIG_FB_IMAC=y +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_KYRO=m +CONFIG_FB_LE80578=m +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_BACKLIGHT=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_I2C=y +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_PM3=m +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_BACKLIGHT=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_I2C=y +CONFIG_FB_S1D13XXX=m +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_SM501=m +CONFIG_FB_SVGALIB=m +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FDDI=y +CONFIG_FEALNX=m +CONFIG_FIXED_MII_1000_FDX=y +# CONFIG_FIXED_MII_100_FDX is not set +# CONFIG_FIXED_MII_10_FDX is not set +CONFIG_FIXED_MII_AMNT=1 +CONFIG_FIXED_PHY=m +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +CONFIG_FTL=m +CONFIG_FUJITSU_LAPTOP=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GIGASET_BASE=m +# CONFIG_GIGASET_DEBUG is not set +CONFIG_GIGASET_M101=m +CONFIG_GIGASET_M105=m +# CONFIG_GIGASET_UNDOCREQ is not set +CONFIG_GIRBIL_DONGLE=m +CONFIG_HAMACHI=m +CONFIG_HAMRADIO=y +CONFIG_HAPPYMEAL=m +CONFIG_HDLC=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_X25=m +CONFIG_HERMES=m +CONFIG_HIBERNATION_SMP_POSSIBLE=y +CONFIG_HID=m +CONFIG_HIDRAW=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HID_FF is not set +# CONFIG_HIGHMEM4G is not set +CONFIG_HIGHMEM64G=y +CONFIG_HIPPI=y +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_BKM_A4T=y +# CONFIG_HISAX_DEBUG is not set +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_ENTERNOW_PCI=y +CONFIG_HISAX_EURO=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HDLC=y +CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_MAX_CARDS=8 +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_NICCY=y +# CONFIG_HISAX_NO_KEYPAD is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_TELES_CS=m +CONFIG_HISAX_W6692=y +CONFIG_HOSTAP=m +CONFIG_HOSTAP_CS=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTESS_SV11=m +CONFIG_HOTPLUG_CPU=y +CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI_ACPI=m +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_COMPAQ=m +CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM=y +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m +CONFIG_HOTPLUG_PCI_FAKE=m +CONFIG_HOTPLUG_PCI_IBM=m +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HP100=m +CONFIG_HPET_EMULATE_RTC=y +CONFIG_HPLAN=m +CONFIG_HPLAN_PLUS=m +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_HVC_XEN=y +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_HWMON_VID=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_AMD=m +CONFIG_HW_RANDOM_GEODE=m +CONFIG_HW_RANDOM_VIA=m +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PCA_ISA=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_BUS=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_EXT_ADAPTEC_DMA64=y +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_PROC=m +CONFIG_I2O_SCSI=m +CONFIG_I6300ESB_WDT=m +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_I8K=m +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_IBMLANA=m +CONFIG_IBMLS=m +# CONFIG_IBMMCA_SCSI_DEV_RESET is not set +CONFIG_IBMMCA_SCSI_ORDER_STANDARD=y +CONFIG_IBMOL=m +CONFIG_IBMTR=m +CONFIG_IBM_ASM=m +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_IDE_PROC_FS=y +CONFIG_IEEE1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_OHCI1394=m +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE80211=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_CRYPT_WEP=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFTL=m +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_POLLDEV=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=m +CONFIG_INPUT_WISTRON_BTNS=m +CONFIG_INPUT_YEALINK=m +CONFIG_IPPP_FILTER=y +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPW2100=m +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2200=m +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IRCOMM=m +CONFIG_IRDA=m +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_DEBUG=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_ULTRA=y +CONFIG_IRLAN=m +CONFIG_IRNET=m +# CONFIG_IRQBALANCE is not set +CONFIG_IRTTY_SIR=m +CONFIG_ISA=y +CONFIG_ISAPNP=y +CONFIG_ISDN=m +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIDRV=m +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_MAINT=m +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVERSION=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_B1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_ISDN_DRV_AVMB1_T1ISA=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_ISDN_DRV_HISAX=m +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_MPP=y +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_TTY_FAX=y +CONFIG_ISDN_X25=y +# CONFIG_ISI is not set +# CONFIG_IWLWIFI is not set +CONFIG_IXGB=m +# CONFIG_IXGB_NAPI is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_K8_NB=y +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KINGSUN_DONGLE=m +CONFIG_KS0108=m +CONFIG_KS0108_DELAY=2 +CONFIG_KS0108_PORT=0x378 +CONFIG_KS959_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KVM=m +CONFIG_KVM_AMD=m +CONFIG_KVM_INTEL=m +CONFIG_LANCE=m +CONFIG_LANMEDIA=m +CONFIG_LAPB=m +CONFIG_LAPBETHER=m +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +CONFIG_LEDS_CLASS=m +CONFIG_LEDS_NET48XX=m +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_WRAP=m +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_CS=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_USB=m +CONFIG_LITELINK_DONGLE=m +CONFIG_LLC=y +CONFIG_LNE390=m +CONFIG_LOCK_KERNEL=y +CONFIG_LP486E=m +CONFIG_LTPC=m +CONFIG_LXT_PHY=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +# CONFIG_M486 is not set +# CONFIG_M586 is not set +CONFIG_M686=y +CONFIG_MA600_DONGLE=m +CONFIG_MAC80211=m +# CONFIG_MAC80211_DEBUG is not set +CONFIG_MAC80211_DEBUGFS=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MACHZ_WDT=m +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_MADGEMC=m +CONFIG_MARVELL_PHY=m +# CONFIG_MATH_EMULATION is not set +CONFIG_MCA=y +CONFIG_MCA_LEGACY=y +# CONFIG_MCA_PROC_FS is not set +CONFIG_MCP2120_DONGLE=m +CONFIG_MCS_FIR=m +CONFIG_MDA_CONSOLE=m +CONFIG_MD_RAID10=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_SAS=m +CONFIG_MFD_SM501=m +CONFIG_MINIX_FS=m +CONFIG_MIXCOMWD=m +CONFIG_MKISS=m +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_MLX4_INFINIBAND=m +CONFIG_MMC=m +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_SDHCI=m +CONFIG_MMC_TIFM_SD=m +# CONFIG_MMC_UNSAFE_RESUME is not set +CONFIG_MMC_WBSD=m +CONFIG_MOUSE_APPLETOUCH=m +# CONFIG_MOUSE_ATIXL is not set +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_VSXXXAA=m +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +CONFIG_MSI_LAPTOP=m +CONFIG_MTD=m +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTD_ABSENT=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK2MTD=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_MTD_CFI=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_CHAR=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_CONCAT=m +CONFIG_MTD_DATAFLASH=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_DILNETPC=m +CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000 +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCECC=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCPROBE_ADDRESS=0 +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_L440GX=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTD_NAND=m +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_CS553X=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND_IDS=m +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NETSC520=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_2X_PROGRAM=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_SIM=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_OOPS=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_PCI=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PLATRAM=m +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_PNC2000=m +CONFIG_MTD_RAM=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +CONFIG_MTD_REDBOOT_PARTS=m +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +CONFIG_MTD_ROM=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_TS5500=m +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MWAVE=m +CONFIG_MYRI10GE=m +CONFIG_N2=m +CONFIG_NATSEMI=m +CONFIG_NCPFS_EXTRAS=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_PACKET_SIGNING=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_STRONG=y +CONFIG_NCP_FS=m +CONFIG_NE2000=m +CONFIG_NE2_MCA=m +CONFIG_NE3210=m +CONFIG_NETLABEL=y +CONFIG_NETROM=m +CONFIG_NETXEN_NIC=m +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_SIMP=m +# CONFIG_NET_CLS_POLICE is not set +CONFIG_NET_DCCPPROBE=m +CONFIG_NET_FC=y +CONFIG_NET_ISA=y +CONFIG_NET_PCMCIA=y +CONFIG_NET_POCKET=y +CONFIG_NET_SCH_ATM=m +CONFIG_NET_TCPPROBE=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_RACAL=y +CONFIG_NET_VENDOR_SMC=y +CONFIG_NEW_LEDS=y +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NI52=m +CONFIG_NI65=m +CONFIG_NL80211=y +# CONFIG_NORTEL_HERMES is not set +CONFIG_NO_HZ=y +CONFIG_NR_CPUS=8 +CONFIG_NS83820=m +CONFIG_NSC_FIR=m +CONFIG_NSC_GPIO=m +# CONFIG_NTFS_RW is not set +CONFIG_N_HDLC=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_P54_COMMON=m +CONFIG_P54_PCI=m +CONFIG_P54_USB=m +CONFIG_PARIDE=m +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_BPCK6=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PG=m +CONFIG_PARIDE_PT=m +CONFIG_PARPORT_AX88796=m +CONFIG_PARPORT_NOT_PC=y +CONFIG_PARPORT_PC_FIFO=y +CONFIG_PARPORT_PC_PCMCIA=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PATA_CS5520=m +CONFIG_PATA_EFAR=m +# CONFIG_PATA_ISAPNP is not set +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +# CONFIG_PATA_LEGACY is not set +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NETCELL=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_PCMCIA=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_QDI=m +CONFIG_PATA_RZ1000=m +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_WINBOND=m +# CONFIG_PATA_WINBOND_VLB is not set +CONFIG_PC300=m +# CONFIG_PC300TOO is not set +CONFIG_PC300_MLPPP=y +CONFIG_PC8736x_GPIO=m +CONFIG_PC87413_WDT=m +CONFIG_PCCARD=m +CONFIG_PCCARD_NONSTATIC=m +CONFIG_PCI200SYN=m +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIPCWATCHDOG=m +CONFIG_PCI_ATMEL=m +# CONFIG_PCI_HERMES is not set +CONFIG_PCMCIA=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_AXNET=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_IBMTR=m +CONFIG_PCMCIA_IOCTL=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_PROBE=y +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_PCWATCHDOG=m +CONFIG_PD6729=m +CONFIG_PDC202XX_BURST=y +CONFIG_PDC_ADMA=m +CONFIG_PHANTOM=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m +CONFIG_PLIP=m +# CONFIG_PLX_HERMES is not set +CONFIG_PM_SLEEP_SMP=y +CONFIG_PNPBIOS=y +CONFIG_PNPBIOS_PROC_FS=y +CONFIG_PPPOATM=m +# CONFIG_PREEMPT_BKL is not set +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_NOTIFIERS=y +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PRISM54=m +CONFIG_PROC_PID_CPUSET=y +CONFIG_PROTEON=m +CONFIG_QLA3XXX=m +CONFIG_QSEMI_PHY=m +CONFIG_R3964=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_CADET=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +# CONFIG_RADIO_TYPHOON_PROC_FS is not set +CONFIG_RADIO_ZOLTRIX=m +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +CONFIG_RESOURCES_64BIT=y +CONFIG_RFD_FTL=m +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +# CONFIG_RIO is not set +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_ROCKETPORT=m +CONFIG_ROMFS_FS=m +CONFIG_ROSE=m +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT2X00=m +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RT2X00_LIB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT73USB=m +CONFIG_RTC=y +CONFIG_RTC_CLASS=m +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_TEST=m +CONFIG_RTC_DRV_V3020=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=m +CONFIG_RTL8187=m +CONFIG_RXKAD=m +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +CONFIG_SATA_AHCI=m +CONFIG_SATA_INIC162X=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_SX4=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SBC8360_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m +CONFIG_SBNI=m +# CONFIG_SBNI_MULTILINE is not set +CONFIG_SC1200_WDT=m +CONFIG_SC520_WDT=m +CONFIG_SC92031=m +CONFIG_SCC=m +# CONFIG_SCC_DELAY is not set +# CONFIG_SCC_TRXECHO is not set +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_7000FASST=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AHA1740=m +CONFIG_SCSI_AIC79XX=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_SCSI_AIC94XX=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_DTC3280=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_FD_MCS=m +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_GENERIC_NCR5380=m +CONFIG_SCSI_GENERIC_NCR5380_MMIO=m +CONFIG_SCSI_GENERIC_NCR53C400=y +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_IBMMCA=m +CONFIG_SCSI_IMM=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_DUMP is not set +# CONFIG_SCSI_IPR_TRACE is not set +CONFIG_SCSI_IPS=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_NCR53C406A=m +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 +CONFIG_SCSI_NCR53C8XX_SYNC=5 +CONFIG_SCSI_NCR_D700=m +CONFIG_SCSI_NCR_Q720=m +CONFIG_SCSI_NSP32=m +CONFIG_SCSI_PAS16=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_PSI240I=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SEAGATE=m +CONFIG_SCSI_SIM710=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C416=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_T128=m +CONFIG_SCSI_TGT=m +CONFIG_SCSI_U14_34F=m +CONFIG_SCSI_U14_34F_LINKED_COMMANDS=y +CONFIG_SCSI_U14_34F_MAX_TAGS=8 +CONFIG_SCSI_U14_34F_TAGGED_QUEUE=y +CONFIG_SCSI_ULTRASTOR=m +CONFIG_SCx200=m +CONFIG_SCx200HR_TIMER=m +CONFIG_SCx200_ACB=m +CONFIG_SCx200_GPIO=m +CONFIG_SCx200_I2C=m +CONFIG_SCx200_I2C_SCL=12 +CONFIG_SCx200_I2C_SDA=13 +CONFIG_SCx200_WDT=m +CONFIG_SDIO_UART=m +CONFIG_SDLA=m +CONFIG_SEALEVEL_4021=m +CONFIG_SEEQ8005=m +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_APPLESMC=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_HDAPS=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SERIAL_8250_ACCENT=m +CONFIG_SERIAL_8250_BOCA=m +CONFIG_SERIAL_8250_CS=m +CONFIG_SERIAL_8250_EXAR_ST16C554=m +CONFIG_SERIAL_8250_FOURPORT=m +CONFIG_SERIAL_8250_HUB6=m +CONFIG_SERIAL_8250_MCA=m +CONFIG_SERIAL_JSM=m +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SGI_IOC4=m +CONFIG_SIGMATEL_FIR=m +CONFIG_SIS190=m +CONFIG_SIS900=m +CONFIG_SKFP=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKISA=m +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +CONFIG_SMC9194=m +CONFIG_SMCTR=m +CONFIG_SMC_IRCC_FIR=m +CONFIG_SMP=y +CONFIG_SMSC37B787_WDT=m +CONFIG_SMSC_PHY=m +# CONFIG_SND is not set +CONFIG_SONYPI=m +CONFIG_SONYPI_COMPAT=y +CONFIG_SONY_LAPTOP=m +# CONFIG_SOUND_PRIME is not set +CONFIG_SPECIALIX=m +# CONFIG_SPECIALIX_RTSCTS is not set +CONFIG_SPI=y +CONFIG_SPI_AT25=m +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_MASTER=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_SSB_DRIVER_PCICORE=y +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +CONFIG_SSFDC=m +CONFIG_STALDRV=y +CONFIG_STOP_MACHINE=y +CONFIG_STRIP=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_SUNGEM=m +CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SX=m +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_CS=m +CONFIG_SYNCLINK_GT=m +CONFIG_SYSV68_PARTITION=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TCG_NSC=m +CONFIG_TCG_TIS=m +CONFIG_TCG_TPM=m +CONFIG_TCIC=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_TELCLOCK=m +CONFIG_THINKPAD_ACPI=m +CONFIG_THINKPAD_ACPI_BAY=y +# CONFIG_THINKPAD_ACPI_DEBUG is not set +CONFIG_TIFM_7XX1=m +CONFIG_TIFM_CORE=m +CONFIG_TIGON3=m +CONFIG_TLAN=m +# CONFIG_TMD_HERMES is not set +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_TOSHIBA=m +CONFIG_TOSHIBA_FIR=m +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TR=y +CONFIG_TUNER_3036=m +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_SIMPLE=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TYPHOON=m +CONFIG_ULI526X=m +CONFIG_ULTRA=m +CONFIG_ULTRA32=m +CONFIG_ULTRAMCA=m +CONFIG_USBPCWATCHDOG=m +CONFIG_USB_ACM=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_ARMLINUX=y +CONFIG_USB_ATM=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_BELKIN=y +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_CATC=m +CONFIG_USB_CXACRU=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_DABUSB=m +CONFIG_USB_DSBR=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EMI26=m +CONFIG_USB_EMI62=m +CONFIG_USB_EPSON2888=y +CONFIG_USB_ET61X251=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_EZUSB=y +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_GADGET=m +CONFIG_USB_GADGETFS=m +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_M66592 is not set +CONFIG_USB_GADGET_NET2280=y +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_S3C2410 is not set +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_G_SERIAL=m +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_HIDINPUT_POWERBOOK=y +CONFIG_USB_IBMCAM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_IRDA=m +CONFIG_USB_KAWETH=m +CONFIG_USB_KBD=m +CONFIG_USB_KC2190=y +CONFIG_USB_KONICAWC=m +CONFIG_USB_LCD=m +CONFIG_USB_LD=m +CONFIG_USB_LED=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +# CONFIG_USB_MIDI_GADGET is not set +CONFIG_USB_MON=y +CONFIG_USB_MOUSE=m +CONFIG_USB_NET2280=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_RNDIS_HOST=m +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OV511 is not set +CONFIG_USB_PEGASUS=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_PRINTER=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_RIO500=m +CONFIG_USB_RTL8150=m +CONFIG_USB_SE401=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IPW=m +# CONFIG_USB_SERIAL_IR is not set +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_SL811_CS=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SN9C102=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STV680=m +CONFIG_USB_SUSPEND=y +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_USBNET=m +CONFIG_USB_USS720=m +CONFIG_USB_VICAM=m +CONFIG_USB_W9968CF=m +CONFIG_USB_XUSBATM=m +CONFIG_USB_ZC0301=m +CONFIG_USB_ZD1201=m +CONFIG_USB_ZERO=m +CONFIG_USB_ZR364XX=m +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-4.6-server" +CONFIG_VIA_FIR=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_RHINE_NAPI=y +CONFIG_VIA_VELOCITY=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_CX25840=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_DEV=m +# CONFIG_VIDEO_DPC is not set +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_FB_IVTV=m +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_MSP3400=m +# CONFIG_VIDEO_MXB is not set +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_29XXX=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_SAA7191=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_TCM825X=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_VP27SMPX=m +CONFIG_VIDEO_VPX3220=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VITESSE_PHY=m +CONFIG_VLSI_FIR=m +CONFIG_VORTEX=m +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_THERM=m +CONFIG_W83627HF_WDT=m +CONFIG_W83697HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_WAN=y +CONFIG_WANXL=m +CONFIG_WAN_ROUTER=m +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_WAVELAN=m +CONFIG_WD80x3=m +# CONFIG_WDC_ALI15X3 is not set +CONFIG_WDT=m +CONFIG_WDTPCI=m +CONFIG_WDT_501=y +CONFIG_WDT_501_PCI=y +CONFIG_WINBOND_840=m +CONFIG_WINBOND_FIR=m +CONFIG_WIRELESS_EXT=y +CONFIG_WLAN_80211=y +CONFIG_WLAN_PRE80211=y +CONFIG_X25=m +CONFIG_X25_ASY=m +CONFIG_X86_CMOV=y +CONFIG_X86_CPUFREQ_NFORCE2=m +CONFIG_X86_GOOD_APIC=y +CONFIG_X86_HT=y +CONFIG_X86_PAE=y +CONFIG_X86_SMP=y +CONFIG_X86_SPEEDSTEP_LIB=m +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_TRAMPOLINE=y +CONFIG_X86_TSC=y +CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_XEN=y +CONFIG_XEN_BLKDEV_FRONTEND=m +CONFIG_XEN_NETDEV_FRONTEND=m +CONFIG_YAM=m +CONFIG_YELLOWFIN=m +CONFIG_YENTA=m +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_ZNET=m --- linux-2.6.24.orig/debian/config/i386/config.generic +++ linux-2.6.24/debian/config/i386/config.generic @@ -0,0 +1,1950 @@ +# +# Config options for config.generic automatically generated by splitconfig.pl +# +CONFIG_3C359=m +CONFIG_3C515=m +CONFIG_60XX_WDT=m +CONFIG_6PACK=m +CONFIG_8139CP=m +CONFIG_8139TOO_8129=y +CONFIG_9P_FS=m +CONFIG_ABYSS=m +CONFIG_AC3200=m +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BAY=m +CONFIG_ACPI_DOCK=m +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_SBS=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_ACPI_VIDEO=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ACT200L_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_ADM8211=m +CONFIG_ADVANTECH_WDT=m +CONFIG_AFFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_AFS_FS=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_AGP_ALI=m +CONFIG_AGP_AMD=m +CONFIG_AGP_AMD64=m +CONFIG_AGP_ATI=m +CONFIG_AGP_EFFICEON=m +CONFIG_AGP_NVIDIA=m +CONFIG_AGP_SIS=m +CONFIG_AGP_SWORKS=m +CONFIG_AGP_VIA=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_AIRO=m +CONFIG_AIRO_CS=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_ALI_FIR=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_AMD8111_ETH=m +CONFIG_APM=m +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_CPU_IDLE is not set +# CONFIG_APM_DISPLAY_BLANK is not set +# CONFIG_APM_DO_ENABLE is not set +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set +CONFIG_APPLICOM=m +CONFIG_APRICOT=m +CONFIG_ARCNET=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_ARCNET_COM20020_ISA=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARLAN=m +CONFIG_ASUS_LAPTOP=m +CONFIG_AT1700=m +CONFIG_ATA_OVER_ETH=m +CONFIG_ATL1=m +CONFIG_ATM=y +CONFIG_ATMEL=m +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_FORE200E=m +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E_MAYBE=m +CONFIG_ATM_FORE200E_PCA=y +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y +CONFIG_ATM_FORE200E_TX_RETRY=16 +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_LANAI=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_NICSTAR=m +# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set +# CONFIG_ATM_NICSTAR_USE_SUNI is not set +CONFIG_ATM_TCP=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_ATP=m +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_B43=m +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PIO=y +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_B43_DEBUG=y +CONFIG_B43_DMA=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +CONFIG_B43_LEDS=y +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_PCI_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_PIO=y +# CONFIG_B43_PIO_MODE is not set +CONFIG_B43_RFKILL=y +CONFIG_B44=m +CONFIG_B44_PCI=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_BACKLIGHT_CARILLO_RANCH=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_PROGEAR=m +CONFIG_BAYCOM_EPP=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +CONFIG_BCM43XX_PIO=y +# CONFIG_BCM43XX_PIO_MODE is not set +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_BLK_DEV_4DRIVES=y +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI14XX=m +CONFIG_BLK_DEV_ALI15X3=m +CONFIG_BLK_DEV_ATIIXP=m +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +CONFIG_BLK_DEV_CMD64X=m +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_CS5535=m +CONFIG_BLK_DEV_CY82C693=m +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_DTC2278=m +CONFIG_BLK_DEV_HPT34X=m +CONFIG_BLK_DEV_HPT366=m +CONFIG_BLK_DEV_HT6560B=m +CONFIG_BLK_DEV_IDE=m +CONFIG_BLK_DEV_IDEACPI=y +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_BLK_DEV_NS87415=m +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_OPTI621=m +CONFIG_BLK_DEV_PDC202XX_OLD=m +CONFIG_BLK_DEV_QD65XX=m +CONFIG_BLK_DEV_SC1200=m +CONFIG_BLK_DEV_SX8=m +CONFIG_BLK_DEV_TC86C001=m +CONFIG_BLK_DEV_TRM290=m +CONFIG_BLK_DEV_UMC8672=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_XD=m +CONFIG_BNX2=m +CONFIG_BPQETHER=m +CONFIG_BROADCOM_PHY=m +CONFIG_BT=m +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIVHCI=m +CONFIG_BT_HIDP=m +CONFIG_BT_L2CAP=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_SCO=m +CONFIG_C101=m +CONFIG_CAPI_AVM=y +CONFIG_CAPI_EICON=y +CONFIG_CAPI_TRACE=y +CONFIG_CARDBUS=y +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_CASSINI=m +CONFIG_CFAG12864B=m +CONFIG_CFAG12864B_RATE=20 +CONFIG_CFG80211=m +CONFIG_CHECK_SIGNATURE=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_CHR_DEV_OSST=m +CONFIG_CHR_DEV_SCH=m +CONFIG_CHR_DEV_ST=m +CONFIG_CICADA_PHY=m +CONFIG_CISS_SCSI_TAPE=y +# CONFIG_COMPUTONE is not set +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_COSA=m +CONFIG_CPU5_WDT=m +CONFIG_CPUSETS=y +CONFIG_CPU_FREQ_TABLE=m +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DEV_PADLOCK=y +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CS5535_GPIO=m +CONFIG_CS89x0=m +CONFIG_CYCLADES=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +# CONFIG_CYZ_INTR is not set +CONFIG_DAB=y +CONFIG_DAVICOM_PHY=m +CONFIG_DE2104X=m +CONFIG_DE4X5=m +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DECNET_NF_GRABULATOR=m +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_DEPCA=m +CONFIG_DE_AOC=y +CONFIG_DIGIEPCA=m +CONFIG_DISPLAY_SUPPORT=m +CONFIG_DL2K=m +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_DM9102=m +CONFIG_DONGLE=y +CONFIG_DRM=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_I915=m +CONFIG_DRM_MGA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_SAVAGE=m +CONFIG_DRM_SIS=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_VIA=m +CONFIG_DRM_VIA_CHROME9=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DTLK=m +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_B2C2_FLEXCOP=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_BT8XX=m +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_PATCH=m +CONFIG_DVB_CAPTURE_DRIVERS=y +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m +# CONFIG_DVB_FE_CUSTOMISE is not set +CONFIG_DVB_ISL6421=m +CONFIG_DVB_L64781=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LNBP21=m +CONFIG_DVB_MT312=m +CONFIG_DVB_MT352=m +CONFIG_DVB_NXT200X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_PLL=m +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_STV0297=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_TUNER_DIB0070=m +CONFIG_DVB_TUNER_MT2060=m +CONFIG_DVB_TUNER_MT2131=m +CONFIG_DVB_TUNER_MT2266=m +CONFIG_DVB_TUNER_QT1010=m +CONFIG_DVB_USB=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_CXUSB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_ZL10353=m +CONFIG_E100=m +CONFIG_E2100=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_EDAC=y +# CONFIG_EDAC_AMD76X is not set +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_E752X=m +CONFIG_EDAC_E7XXX=m +CONFIG_EDAC_I3000=m +CONFIG_EDAC_I5000=m +CONFIG_EDAC_I82860=m +CONFIG_EDAC_I82875P=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_MM_EDAC=m +CONFIG_EDAC_R82600=m +CONFIG_EDD=y +CONFIG_EDD_OFF=y +CONFIG_EEPRO100=m +CONFIG_EEXPRESS=m +CONFIG_EEXPRESS_PRO=m +CONFIG_EISA=y +CONFIG_EISA_NAMES=y +CONFIG_EISA_PCI_EISA=y +CONFIG_EISA_VIRTUAL_ROOT=y +CONFIG_EISA_VLB_PRIMING=y +CONFIG_EL1=m +CONFIG_EL16=m +CONFIG_EL2=m +CONFIG_EL3=m +CONFIG_ELMC=m +CONFIG_ELMC_II=m +CONFIG_ELPLUS=m +CONFIG_EPIC100=m +CONFIG_ES3210=m +CONFIG_ESI_DONGLE=m +# CONFIG_ESPSERIAL is not set +CONFIG_ETH16I=m +CONFIG_EUROTECH_WDT=m +CONFIG_EWRK3=m +CONFIG_FARSYNC=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_ARK=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_CYBER2000=m +CONFIG_FB_CYBLA=m +CONFIG_FB_DDC=m +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_GX=m +CONFIG_FB_GEODE_GX1=m +# CONFIG_FB_GEODE_GX_SET_FBSIZE is not set +CONFIG_FB_GEODE_LX=m +CONFIG_FB_HECUBA=m +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_I810=m +# CONFIG_FB_I810_GTF is not set +CONFIG_FB_IMAC=y +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_KYRO=m +CONFIG_FB_LE80578=m +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_BACKLIGHT=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_I2C=y +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_PM3=m +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_BACKLIGHT=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_I2C=y +CONFIG_FB_S1D13XXX=m +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_SM501=m +CONFIG_FB_SVGALIB=m +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FDDI=y +CONFIG_FEALNX=m +CONFIG_FIXED_MII_1000_FDX=y +# CONFIG_FIXED_MII_100_FDX is not set +# CONFIG_FIXED_MII_10_FDX is not set +CONFIG_FIXED_MII_AMNT=1 +CONFIG_FIXED_PHY=m +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +CONFIG_FTL=m +CONFIG_FUJITSU_LAPTOP=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GIGASET_BASE=m +# CONFIG_GIGASET_DEBUG is not set +CONFIG_GIGASET_M101=m +CONFIG_GIGASET_M105=m +# CONFIG_GIGASET_UNDOCREQ is not set +CONFIG_GIRBIL_DONGLE=m +CONFIG_HAMACHI=m +CONFIG_HAMRADIO=y +CONFIG_HAPPYMEAL=m +CONFIG_HDLC=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_X25=m +CONFIG_HERMES=m +CONFIG_HIBERNATION_SMP_POSSIBLE=y +CONFIG_HID=m +CONFIG_HIDRAW=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HID_FF is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIPPI=y +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_BKM_A4T=y +# CONFIG_HISAX_DEBUG is not set +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_ENTERNOW_PCI=y +CONFIG_HISAX_EURO=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HDLC=y +CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_MAX_CARDS=8 +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_NICCY=y +# CONFIG_HISAX_NO_KEYPAD is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_TELES_CS=m +CONFIG_HISAX_W6692=y +CONFIG_HOSTAP=m +CONFIG_HOSTAP_CS=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTESS_SV11=m +CONFIG_HOTPLUG_CPU=y +CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI_ACPI=m +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_COMPAQ=m +CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM=y +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m +CONFIG_HOTPLUG_PCI_FAKE=m +CONFIG_HOTPLUG_PCI_IBM=m +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HP100=m +CONFIG_HPET_EMULATE_RTC=y +CONFIG_HPLAN=m +CONFIG_HPLAN_PLUS=m +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_HWMON_VID=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_AMD=m +CONFIG_HW_RANDOM_GEODE=m +CONFIG_HW_RANDOM_VIA=m +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PCA_ISA=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_BUS=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_PROC=m +CONFIG_I2O_SCSI=m +CONFIG_I6300ESB_WDT=m +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_I8K=m +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_IBMLANA=m +CONFIG_IBMLS=m +# CONFIG_IBMMCA_SCSI_DEV_RESET is not set +CONFIG_IBMMCA_SCSI_ORDER_STANDARD=y +CONFIG_IBMOL=m +CONFIG_IBMTR=m +CONFIG_IBM_ASM=m +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_IDE_PROC_FS=y +CONFIG_IEEE1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_OHCI1394=m +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE80211=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_CRYPT_WEP=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFTL=m +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_POLLDEV=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=m +CONFIG_INPUT_WISTRON_BTNS=m +CONFIG_INPUT_YEALINK=m +CONFIG_IPPP_FILTER=y +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPW2100=m +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2200=m +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IRCOMM=m +CONFIG_IRDA=m +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_DEBUG=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_ULTRA=y +CONFIG_IRLAN=m +CONFIG_IRNET=m +# CONFIG_IRQBALANCE is not set +CONFIG_IRTTY_SIR=m +CONFIG_ISA=y +CONFIG_ISAPNP=y +CONFIG_ISDN=m +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIDRV=m +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_MAINT=m +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVERSION=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_B1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_ISDN_DRV_AVMB1_T1ISA=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_ISDN_DRV_HISAX=m +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_MPP=y +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_TTY_FAX=y +CONFIG_ISDN_X25=y +# CONFIG_ISI is not set +# CONFIG_IWLWIFI is not set +CONFIG_IXGB=m +# CONFIG_IXGB_NAPI is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_K8_NB=y +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KINGSUN_DONGLE=m +CONFIG_KS0108=m +CONFIG_KS0108_DELAY=2 +CONFIG_KS0108_PORT=0x378 +CONFIG_KS959_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KVM=m +CONFIG_KVM_AMD=m +CONFIG_KVM_INTEL=m +CONFIG_LANCE=m +CONFIG_LANMEDIA=m +CONFIG_LAPB=m +CONFIG_LAPBETHER=m +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +CONFIG_LEDS_CLASS=m +CONFIG_LEDS_NET48XX=m +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_WRAP=m +CONFIG_LGUEST=m +# CONFIG_LGUEST_GUEST is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_CS=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_USB=m +CONFIG_LITELINK_DONGLE=m +CONFIG_LLC=y +CONFIG_LNE390=m +CONFIG_LOCK_KERNEL=y +CONFIG_LP486E=m +CONFIG_LTPC=m +CONFIG_LXT_PHY=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +# CONFIG_M486 is not set +CONFIG_M586=y +# CONFIG_M686 is not set +CONFIG_MA600_DONGLE=m +CONFIG_MAC80211=m +# CONFIG_MAC80211_DEBUG is not set +CONFIG_MAC80211_DEBUGFS=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MACHZ_WDT=m +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_MADGEMC=m +CONFIG_MARVELL_PHY=m +# CONFIG_MATH_EMULATION is not set +CONFIG_MCA=y +CONFIG_MCA_LEGACY=y +# CONFIG_MCA_PROC_FS is not set +CONFIG_MCP2120_DONGLE=m +CONFIG_MCS_FIR=m +CONFIG_MDA_CONSOLE=m +CONFIG_MD_RAID10=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_SAS=m +CONFIG_MFD_SM501=m +CONFIG_MINIX_FS=m +CONFIG_MIXCOMWD=m +CONFIG_MKISS=m +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_MLX4_INFINIBAND=m +CONFIG_MMC=m +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_SDHCI=m +CONFIG_MMC_TIFM_SD=m +# CONFIG_MMC_UNSAFE_RESUME is not set +CONFIG_MMC_WBSD=m +CONFIG_MOUSE_APPLETOUCH=m +# CONFIG_MOUSE_ATIXL is not set +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_VSXXXAA=m +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +CONFIG_MSI_LAPTOP=m +CONFIG_MTD=m +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTD_ABSENT=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK2MTD=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_MTD_CFI=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_CHAR=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_CONCAT=m +CONFIG_MTD_DATAFLASH=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_DILNETPC=m +CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000 +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCECC=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCPROBE_ADDRESS=0 +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_L440GX=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTD_NAND=m +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_CS553X=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND_IDS=m +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NETSC520=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_2X_PROGRAM=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_SIM=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_OOPS=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_PCI=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PLATRAM=m +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_PNC2000=m +CONFIG_MTD_RAM=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +CONFIG_MTD_REDBOOT_PARTS=m +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +CONFIG_MTD_ROM=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_TS5500=m +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MWAVE=m +CONFIG_MYRI10GE=m +CONFIG_N2=m +CONFIG_NATSEMI=m +CONFIG_NCPFS_EXTRAS=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_PACKET_SIGNING=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_STRONG=y +CONFIG_NCP_FS=m +CONFIG_NE2000=m +CONFIG_NE2_MCA=m +CONFIG_NE3210=m +# CONFIG_NETLABEL is not set +CONFIG_NETROM=m +CONFIG_NETXEN_NIC=m +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_SIMP=m +# CONFIG_NET_CLS_POLICE is not set +CONFIG_NET_DCCPPROBE=m +CONFIG_NET_FC=y +CONFIG_NET_ISA=y +CONFIG_NET_PCMCIA=y +CONFIG_NET_POCKET=y +CONFIG_NET_SCH_ATM=m +CONFIG_NET_TCPPROBE=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_RACAL=y +CONFIG_NET_VENDOR_SMC=y +CONFIG_NEW_LEDS=y +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NI52=m +CONFIG_NI65=m +CONFIG_NL80211=y +# CONFIG_NORTEL_HERMES is not set +CONFIG_NO_HZ=y +CONFIG_NR_CPUS=8 +CONFIG_NS83820=m +CONFIG_NSC_FIR=m +CONFIG_NSC_GPIO=m +# CONFIG_NTFS_RW is not set +CONFIG_N_HDLC=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_P54_COMMON=m +CONFIG_P54_PCI=m +CONFIG_P54_USB=m +CONFIG_PARIDE=m +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_BPCK6=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PG=m +CONFIG_PARIDE_PT=m +CONFIG_PARPORT_AX88796=m +CONFIG_PARPORT_NOT_PC=y +CONFIG_PARPORT_PC_FIFO=y +CONFIG_PARPORT_PC_PCMCIA=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PATA_CS5520=m +CONFIG_PATA_EFAR=m +# CONFIG_PATA_ISAPNP is not set +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +# CONFIG_PATA_LEGACY is not set +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NETCELL=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_PCMCIA=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_QDI=m +CONFIG_PATA_RZ1000=m +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_WINBOND=m +# CONFIG_PATA_WINBOND_VLB is not set +CONFIG_PC300=m +# CONFIG_PC300TOO is not set +CONFIG_PC300_MLPPP=y +CONFIG_PC8736x_GPIO=m +CONFIG_PC87413_WDT=m +CONFIG_PCCARD=m +CONFIG_PCCARD_NONSTATIC=m +CONFIG_PCI200SYN=m +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIPCWATCHDOG=m +CONFIG_PCI_ATMEL=m +# CONFIG_PCI_HERMES is not set +CONFIG_PCMCIA=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_AXNET=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_IBMTR=m +CONFIG_PCMCIA_IOCTL=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_PROBE=y +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_PCWATCHDOG=m +CONFIG_PD6729=m +CONFIG_PDC202XX_BURST=y +CONFIG_PDC_ADMA=m +CONFIG_PHANTOM=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m +CONFIG_PLIP=m +# CONFIG_PLX_HERMES is not set +CONFIG_PM_SLEEP_SMP=y +CONFIG_PNPBIOS=y +CONFIG_PNPBIOS_PROC_FS=y +CONFIG_PPPOATM=m +CONFIG_PREEMPT_BKL=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_PRISM54=m +CONFIG_PROC_PID_CPUSET=y +CONFIG_PROTEON=m +CONFIG_QLA3XXX=m +CONFIG_QSEMI_PHY=m +CONFIG_R3964=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_CADET=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +# CONFIG_RADIO_TYPHOON_PROC_FS is not set +CONFIG_RADIO_ZOLTRIX=m +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +# CONFIG_RESOURCES_64BIT is not set +CONFIG_RFD_FTL=m +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +# CONFIG_RIO is not set +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_ROCKETPORT=m +CONFIG_ROMFS_FS=m +CONFIG_ROSE=m +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT2X00=m +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RT2X00_LIB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT73USB=m +CONFIG_RTC=y +CONFIG_RTC_CLASS=m +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_TEST=m +CONFIG_RTC_DRV_V3020=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=m +CONFIG_RTL8187=m +CONFIG_RXKAD=m +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +CONFIG_SATA_AHCI=m +CONFIG_SATA_INIC162X=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_SX4=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SBC8360_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m +CONFIG_SBNI=m +# CONFIG_SBNI_MULTILINE is not set +CONFIG_SC1200_WDT=m +CONFIG_SC520_WDT=m +CONFIG_SC92031=m +CONFIG_SCC=m +# CONFIG_SCC_DELAY is not set +# CONFIG_SCC_TRXECHO is not set +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_7000FASST=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AHA1740=m +CONFIG_SCSI_AIC79XX=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_SCSI_AIC94XX=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_DTC3280=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_FD_MCS=m +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_GENERIC_NCR5380=m +CONFIG_SCSI_GENERIC_NCR5380_MMIO=m +CONFIG_SCSI_GENERIC_NCR53C400=y +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_IBMMCA=m +CONFIG_SCSI_IMM=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_DUMP is not set +# CONFIG_SCSI_IPR_TRACE is not set +CONFIG_SCSI_IPS=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_NCR53C406A=m +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 +CONFIG_SCSI_NCR53C8XX_SYNC=5 +CONFIG_SCSI_NCR_D700=m +CONFIG_SCSI_NCR_Q720=m +CONFIG_SCSI_NSP32=m +CONFIG_SCSI_PAS16=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_PSI240I=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SEAGATE=m +CONFIG_SCSI_SIM710=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C416=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_T128=m +CONFIG_SCSI_TGT=m +CONFIG_SCSI_U14_34F=m +CONFIG_SCSI_U14_34F_LINKED_COMMANDS=y +CONFIG_SCSI_U14_34F_MAX_TAGS=8 +CONFIG_SCSI_U14_34F_TAGGED_QUEUE=y +CONFIG_SCSI_ULTRASTOR=m +CONFIG_SCx200=m +CONFIG_SCx200HR_TIMER=m +CONFIG_SCx200_ACB=m +CONFIG_SCx200_GPIO=m +CONFIG_SCx200_I2C=m +CONFIG_SCx200_I2C_SCL=12 +CONFIG_SCx200_I2C_SDA=13 +CONFIG_SCx200_WDT=m +CONFIG_SDIO_UART=m +CONFIG_SDLA=m +CONFIG_SEALEVEL_4021=m +CONFIG_SEEQ8005=m +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_APPLESMC=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_HDAPS=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SERIAL_8250_ACCENT=m +CONFIG_SERIAL_8250_BOCA=m +CONFIG_SERIAL_8250_CS=m +CONFIG_SERIAL_8250_EXAR_ST16C554=m +CONFIG_SERIAL_8250_FOURPORT=m +CONFIG_SERIAL_8250_HUB6=m +CONFIG_SERIAL_8250_MCA=m +CONFIG_SERIAL_JSM=m +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SGI_IOC4=m +CONFIG_SIGMATEL_FIR=m +CONFIG_SIS190=m +CONFIG_SIS900=m +CONFIG_SKFP=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKISA=m +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +CONFIG_SMC9194=m +CONFIG_SMCTR=m +CONFIG_SMC_IRCC_FIR=m +CONFIG_SMP=y +CONFIG_SMSC37B787_WDT=m +CONFIG_SMSC_PHY=m +# CONFIG_SND is not set +CONFIG_SONYPI=m +CONFIG_SONYPI_COMPAT=y +CONFIG_SONY_LAPTOP=m +# CONFIG_SOUND_PRIME is not set +CONFIG_SPECIALIX=m +# CONFIG_SPECIALIX_RTSCTS is not set +CONFIG_SPI=y +CONFIG_SPI_AT25=m +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_MASTER=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_SSB_DRIVER_PCICORE=y +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +CONFIG_SSFDC=m +CONFIG_STALDRV=y +CONFIG_STOP_MACHINE=y +CONFIG_STRIP=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_SUNGEM=m +CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SX=m +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_CS=m +CONFIG_SYNCLINK_GT=m +CONFIG_SYSV68_PARTITION=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TCG_NSC=m +CONFIG_TCG_TIS=m +CONFIG_TCG_TPM=m +CONFIG_TCIC=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_TELCLOCK=m +CONFIG_THINKPAD_ACPI=m +CONFIG_THINKPAD_ACPI_BAY=y +# CONFIG_THINKPAD_ACPI_DEBUG is not set +CONFIG_TIFM_7XX1=m +CONFIG_TIFM_CORE=m +CONFIG_TIGON3=m +CONFIG_TLAN=m +# CONFIG_TMD_HERMES is not set +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_TOSHIBA=m +CONFIG_TOSHIBA_FIR=m +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TR=y +CONFIG_TUNER_3036=m +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_SIMPLE=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TYPHOON=m +CONFIG_ULI526X=m +CONFIG_ULTRA=m +CONFIG_ULTRA32=m +CONFIG_ULTRAMCA=m +CONFIG_USBPCWATCHDOG=m +CONFIG_USB_ACM=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_ARMLINUX=y +CONFIG_USB_ATM=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_BELKIN=y +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_CATC=m +CONFIG_USB_CXACRU=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_DABUSB=m +CONFIG_USB_DSBR=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EMI26=m +CONFIG_USB_EMI62=m +CONFIG_USB_EPSON2888=y +CONFIG_USB_ET61X251=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_EZUSB=y +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_GADGET=m +CONFIG_USB_GADGETFS=m +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_M66592 is not set +CONFIG_USB_GADGET_NET2280=y +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_S3C2410 is not set +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_G_SERIAL=m +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_HIDINPUT_POWERBOOK=y +CONFIG_USB_IBMCAM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_IRDA=m +CONFIG_USB_KAWETH=m +CONFIG_USB_KBD=m +CONFIG_USB_KC2190=y +CONFIG_USB_KONICAWC=m +CONFIG_USB_LCD=m +CONFIG_USB_LD=m +CONFIG_USB_LED=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +# CONFIG_USB_MIDI_GADGET is not set +CONFIG_USB_MON=y +CONFIG_USB_MOUSE=m +CONFIG_USB_NET2280=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_RNDIS_HOST=m +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OV511 is not set +CONFIG_USB_PEGASUS=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_PRINTER=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_RIO500=m +CONFIG_USB_RTL8150=m +CONFIG_USB_SE401=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IPW=m +# CONFIG_USB_SERIAL_IR is not set +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_SL811_CS=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SN9C102=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STV680=m +CONFIG_USB_SUSPEND=y +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_USBNET=m +CONFIG_USB_USS720=m +CONFIG_USB_VICAM=m +CONFIG_USB_W9968CF=m +CONFIG_USB_XUSBATM=m +CONFIG_USB_ZC0301=m +CONFIG_USB_ZD1201=m +CONFIG_USB_ZERO=m +CONFIG_USB_ZR364XX=m +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-4.6-generic" +CONFIG_VIA_FIR=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_RHINE_NAPI=y +CONFIG_VIA_VELOCITY=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_CX25840=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_DEV=m +# CONFIG_VIDEO_DPC is not set +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_FB_IVTV=m +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_MSP3400=m +# CONFIG_VIDEO_MXB is not set +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_29XXX=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_SAA7191=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_TCM825X=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_VP27SMPX=m +CONFIG_VIDEO_VPX3220=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VITESSE_PHY=m +CONFIG_VLSI_FIR=m +CONFIG_VORTEX=m +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_THERM=m +CONFIG_W83627HF_WDT=m +CONFIG_W83697HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_WAN=y +CONFIG_WANXL=m +CONFIG_WAN_ROUTER=m +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_WAVELAN=m +CONFIG_WD80x3=m +# CONFIG_WDC_ALI15X3 is not set +CONFIG_WDT=m +CONFIG_WDTPCI=m +CONFIG_WDT_501=y +CONFIG_WDT_501_PCI=y +CONFIG_WINBOND_840=m +CONFIG_WINBOND_FIR=m +CONFIG_WIRELESS_EXT=y +CONFIG_WLAN_80211=y +CONFIG_WLAN_PRE80211=y +CONFIG_X25=m +CONFIG_X25_ASY=m +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_CPUFREQ_NFORCE2=m +CONFIG_X86_F00F_BUG=y +CONFIG_X86_HT=y +CONFIG_X86_SMP=y +CONFIG_X86_SPEEDSTEP_LIB=m +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_TRAMPOLINE=y +CONFIG_YAM=m +CONFIG_YELLOWFIN=m +CONFIG_YENTA=m +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_ZNET=m --- linux-2.6.24.orig/debian/config/i386/config +++ linux-2.6.24/debian/config/i386/config @@ -0,0 +1,1319 @@ +# +# Common config options automatically generated by splitconfig.pl +# +# CONFIG_4KSTACKS is not set +# CONFIG_64BIT is not set +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_AC97_BUS=m +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_ADFS is not set +# CONFIG_ACORN_PARTITION_CUMANA is not set +# CONFIG_ACORN_PARTITION_EESOX is not set +CONFIG_ACORN_PARTITION_ICS=y +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_ACPI=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BLACKLIST_YEAR=2000 +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_CONTAINER=m +CONFIG_ACPI_CUSTOM_DSDT_INITRD=y +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_EC=y +CONFIG_ACPI_FAN=m +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_PROCFS=y +CONFIG_ACPI_PROCFS_POWER=y +CONFIG_ACPI_PROC_EVENT=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SYSFS_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_ACPI_THERMAL=m +CONFIG_AGP=m +CONFIG_AGP_INTEL=m +CONFIG_AMIGA_PARTITION=y +CONFIG_ANON_INODES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_ARCH_SUPPORTS_OPROFILE=y +# CONFIG_ARPD is not set +CONFIG_ASK_IP_FIB_HASH=y +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ATA=m +CONFIG_ATALK=m +CONFIG_ATARI_PARTITION=y +CONFIG_ATA_ACPI=y +CONFIG_ATA_GENERIC=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_PIIX=m +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +# CONFIG_AUDIT_ARCH is not set +CONFIG_AUDIT_GENERIC=y +CONFIG_AUDIT_TREE=y +CONFIG_AUTOFS4_FS=m +CONFIG_AUTOFS_FS=m +CONFIG_AUXDISPLAY=y +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +CONFIG_BATTERY_DS2760=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BEFS_FS=m +CONFIG_BFS_FS=m +CONFIG_BINFMT_AOUT=m +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_BITREVERSE=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_CRYPTOLOOP=m +# CONFIG_BLK_DEV_CS5520 is not set +CONFIG_BLK_DEV_DM=m +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_MD=m +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_PIIX is not set +CONFIG_BLK_DEV_PLATFORM=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_SD=m +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_UB is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLOCK=y +CONFIG_BONDING=m +CONFIG_BOOT_IOREMAP=y +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOUNCE=y +CONFIG_BRIDGE=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_NETFILTER=y +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BSD_DISKLABEL=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_BUG=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_NS=y +CONFIG_CHR_DEV_SG=m +CONFIG_CIFS=m +# CONFIG_CIFS_DEBUG2 is not set +CONFIG_CIFS_EXPERIMENTAL=y +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_WEAK_PW_HASH=y +# CONFIG_CIFS_XATTR is not set +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CODA_FS=m +# CONFIG_CODA_FS_OLD_API is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_CONFIGFS_FS=m +CONFIG_CONNECTOR=m +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_DEBUG is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CRAMFS=y +CONFIG_CRASH_DUMP=y +CONFIG_CRC16=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_CRC_CCITT=m +CONFIG_CRC_ITU_T=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_AES_586=m +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_DEV_GEODE=m +CONFIG_CRYPTO_DEV_PADLOCK_AES=m +CONFIG_CRYPTO_DEV_PADLOCK_SHA=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_586=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_DCA=m +CONFIG_DCDBAS=m +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MUTEXES is not set +CONFIG_DEBUG_RODATA=y +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +CONFIG_DECNET=m +# CONFIG_DECNET_ROUTER is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_BIC is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_HTCP is not set +CONFIG_DEFAULT_IO_DELAY_TYPE=1 +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_RELATIME=y +CONFIG_DEFAULT_RELATIME_VAL=1 +CONFIG_DEFAULT_RENO=y +CONFIG_DEFAULT_TCP_CONG="reno" +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_DELL_RBU=m +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_DEVPORT=y +CONFIG_DEV_APPLETALK=m +# CONFIG_DEV_KMEM is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_DMADEVICES=y +CONFIG_DMA_ENGINE=y +CONFIG_DMI=y +CONFIG_DMIID=y +CONFIG_DM_CRYPT=m +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_MIRROR=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m +CONFIG_DM_MULTIPATH_HP=m +CONFIG_DM_MULTIPATH_RDAC=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_UEVENT=y +CONFIG_DM_ZERO=m +CONFIG_DNOTIFY=y +CONFIG_DOUBLEFAULT=y +CONFIG_DS1682=m +CONFIG_DUMMY=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_E1000=m +CONFIG_E1000E=m +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E1000_NAPI=y +CONFIG_EARLY_PRINTK=y +CONFIG_ECRYPT_FS=m +CONFIG_EEPROM_93CX6=m +CONFIG_EFI=y +CONFIG_EFI_PARTITION=y +CONFIG_EFI_VARS=y +CONFIG_EFS_FS=m +CONFIG_ELF_CORE=y +CONFIG_EMBEDDED=y +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +CONFIG_EPOLL=y +CONFIG_EQUALIZER=m +CONFIG_EVENTFD=y +CONFIG_EXPERIMENTAL=y +CONFIG_EXPORTFS=m +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_FAIR_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_FAIR_USER_SCHED is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_FS=m +# CONFIG_FAULT_INJECTION is not set +CONFIG_FB=y +CONFIG_FB_ARC=m +CONFIG_FB_ASILIANT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_CIRRUS=m +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_EFI=y +CONFIG_FB_IMSTT=y +# CONFIG_FB_MACMODES is not set +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_SYS_IMAGEBLIT=m +CONFIG_FB_TILEBLITTING=y +CONFIG_FB_UVESA=m +CONFIG_FB_VESA=m +CONFIG_FB_VGA16=m +# CONFIG_FB_VIRTUAL is not set +CONFIG_FIB_RULES=y +# CONFIG_FIREWIRE is not set +CONFIG_FIRMWARE_EDID=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +# CONFIG_FORCED_INLINING is not set +CONFIG_FRAMEBUFFER_CONSOLE=m +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_FS_MBCACHE=m +CONFIG_FS_POSIX_ACL=y +CONFIG_FUSE_FS=m +CONFIG_FUSION=y +CONFIG_FUSION_CTL=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_SAS=m +CONFIG_FUSION_SPI=m +CONFIG_FUTEX=y +CONFIG_FW_LOADER=y +CONFIG_GACT_PROB=y +CONFIG_GAMEPORT=m +CONFIG_GENERIC_ACL=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CMOS_UPDATE=y +# CONFIG_GENERIC_CPU is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_TIME=y +# CONFIG_GENERIC_TIME_VSYSCALL is not set +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_GFS2_FS_LOCKING_NOLOCK=m +CONFIG_HANGCHECK_TIMER=m +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAVE_KVM=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_HFSPLUS_FS=m +CONFIG_HFS_FS=m +CONFIG_HIBERNATION=y +CONFIG_HID_SUPPORT=y +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HOTPLUG=y +CONFIG_HPET=y +CONFIG_HPET_MMAP=y +# CONFIG_HPET_RTC_IRQ is not set +CONFIG_HPET_TIMER=y +CONFIG_HPFS_FS=m +CONFIG_HT_IRQ=y +CONFIG_HVC_DRIVER=y +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM_INTEL=m +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_300 is not set +CONFIG_I2C=m +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCA=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +# CONFIG_I2C_DEBUG_CORE is not set +CONFIG_I2C_PIIX4=m +CONFIG_I2C_TAOS_EVM=m +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +CONFIG_ICPLUS_PHY=m +CONFIG_IDE=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_IDE_ARM is not set +CONFIG_IDE_GENERIC=m +CONFIG_IDE_MAX_HWIFS=4 +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IFB=m +# CONFIG_IKCONFIG is not set +CONFIG_INET=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET_AH=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_INET_DIAG=y +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_LRO=m +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_INPUT=y +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MOUSE=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_PCSPKR=m +CONFIG_INSTRUMENTATION=y +CONFIG_INTEL_IOATDMA=m +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +# CONFIG_IO_DELAY_0X80 is not set +CONFIG_IO_DELAY_0XED=y +# CONFIG_IO_DELAY_NONE is not set +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_NONE=3 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +# CONFIG_IO_DELAY_UDELAY is not set +CONFIG_IP1000=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IPDDP=m +CONFIG_IPDDP_DECAP=y +CONFIG_IPDDP_ENCAP=y +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_POWEROFF=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPV6=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_DCCP=m +CONFIG_IP_DCCP_ACKVEC=y +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_IP_DCCP_TFRC_LIB=m +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_SCTP=m +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_TAB_BITS=12 +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_WRR=m +CONFIG_ISA_DMA_API=y +CONFIG_ISCSI_TCP=m +CONFIG_ISO9660_FS=m +CONFIG_IT8712F_WDT=m +CONFIG_ITCO_VENDOR_SUPPORT=y +CONFIG_ITCO_WDT=m +CONFIG_IXGBE=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +CONFIG_JFS_STATISTICS=y +CONFIG_JOLIET=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_KARMA_PARTITION=y +CONFIG_KEXEC=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +CONFIG_KMOD=y +CONFIG_KPROBES=y +CONFIG_KTIME_SCALAR=y +CONFIG_LBD=y +# CONFIG_LDM_DEBUG is not set +CONFIG_LDM_PARTITION=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LIBCRC32C=m +# CONFIG_LKDTM is not set +CONFIG_LLC2=m +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_LOCKD=m +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +# CONFIG_LOCK_STAT is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_LP_CONSOLE is not set +# CONFIG_LSF is not set +CONFIG_LSM_MMAP_MIN_ADDR=0 +# CONFIG_M386 is not set +# CONFIG_M586MMX is not set +# CONFIG_M586TSC is not set +CONFIG_MACVLAN=m +CONFIG_MAC_PARTITION=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_MARKERS is not set +CONFIG_MAX_RAW_DEVS=256 +# CONFIG_MCORE2 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MCYRIXIII is not set +CONFIG_MD=y +CONFIG_MDIO_BITBANG=m +CONFIG_MD_FAULTY=m +CONFIG_MD_LINEAR=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +# CONFIG_MEFFICEON is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +CONFIG_MICROCODE=m +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_MII=m +CONFIG_MINIX_SUBPARTITION=y +CONFIG_MISC_DEVICES=y +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MOUSE_PS2=m +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPSC is not set +CONFIG_MSDOS_FS=m +CONFIG_MSDOS_PARTITION=y +# CONFIG_MSS is not set +CONFIG_MTRR=y +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MWINCHIPC6 is not set +CONFIG_NE2K_PCI=m +CONFIG_NET=y +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETDEVICES=y +CONFIG_NETDEVICES_MULTIQUEUE=y +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NET_9P=m +# CONFIG_NET_9P_DEBUG is not set +CONFIG_NET_9P_FD=m +CONFIG_NET_9P_VIRTIO=m +CONFIG_NET_ACT_GACT=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_CLS=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_FW=m +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_DMA=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_ETHERNET=y +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_NET_IPIP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_NET_PCI=y +CONFIG_NET_PKTGEN=m +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_NET_SB1000=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_FIFO=y +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_RR=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_TULIP=y +CONFIG_NFSD=m +CONFIG_NFSD_TCP=y +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NIU=m +CONFIG_NLS=y +CONFIG_NLS_ASCII=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +# CONFIG_NOHIGHMEM is not set +CONFIG_NONPROMISC_DEVMEM=y +CONFIG_NR_QUICK=1 +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_FS=m +CONFIG_NVRAM=m +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_OCFS2_DEBUG_MASKLOG=y +CONFIG_OCFS2_FS=m +CONFIG_OPROFILE=m +CONFIG_OSF_PARTITION=y +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_GUEST=y +CONFIG_PARPORT=m +CONFIG_PARPORT_1284=y +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_PC=m +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_PATA_ACPI=m +# CONFIG_PATA_ALI is not set +CONFIG_PATA_AMD=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +# CONFIG_PATA_CMD640_PCI is not set +CONFIG_PATA_CMD64X=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +CONFIG_PATA_CS5536=m +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_HPT366=m +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +CONFIG_PATA_HPT3X3=m +# CONFIG_PATA_HPT3X3_DMA is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC_OLD is not set +CONFIG_PATA_PLATFORM=m +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_VIA=m +CONFIG_PCI=y +CONFIG_PCI_BIOS=y +# CONFIG_PCI_DEBUG is not set +CONFIG_PCI_DIRECT=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_GOANY=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GODIRECT is not set +# CONFIG_PCI_GOMMCONFIG is not set +CONFIG_PCI_LEGACY=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_MSI=y +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_PDA_POWER=m +CONFIG_PHYLIB=m +CONFIG_PHYSICAL_ALIGN=0x100000 +CONFIG_PHYSICAL_START=0x100000 +# CONFIG_PID_NS is not set +CONFIG_PLIST=y +CONFIG_PM=y +CONFIG_PM_DEBUG=y +CONFIG_PM_DISABLE_CONSOLE=y +CONFIG_PM_LEGACY=y +CONFIG_PM_SLEEP=y +CONFIG_PM_STD_PARTITION="" +CONFIG_PM_TRACE=y +# CONFIG_PM_VERBOSE is not set +CONFIG_PNP=y +CONFIG_PNPACPI=y +# CONFIG_PNP_DEBUG is not set +CONFIG_POSIX_MQUEUE=y +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PPDEV=m +CONFIG_PPP=m +CONFIG_PPPOE=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_SYNC_TTY=m +# CONFIG_PREEMPT is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTER=m +CONFIG_PRINTK=y +CONFIG_PRINTK_TIME=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_VMCORE=y +CONFIG_PROFILING=y +# CONFIG_PROVE_LOCKING is not set +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_QNX4FS_FS=m +CONFIG_QUICKLIST=y +CONFIG_QUOTA=y +CONFIG_QUOTACTL=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_RAID_ATTRS=m +CONFIG_RAW_DRIVER=m +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_FS=m +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_REISERFS_FS_XATTR=y +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_RELAY=y +CONFIG_RELOCATABLE=y +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_RT_MUTEXES=y +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_SAMPLES is not set +CONFIG_SBC7240_WDT=m +# CONFIG_SCHEDSTATS is not set +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_SCSI=m +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_BUSLOGIC=m +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_NETLINK=y +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +CONFIG_SCSI_PROC_FS=y +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_WAIT_SCAN=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SECCOMP=y +CONFIG_SECURITY=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +# CONFIG_SECURITY_APPARMOR_DISABLE is not set +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_DISABLE=y +# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SEMAPHORE_SLEEPERS=y +CONFIG_SENSORS_TSL2550=m +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_SERIO_SERPORT=m +CONFIG_SGI_PARTITION=y +CONFIG_SHAPER=m +CONFIG_SHMEM=y +CONFIG_SIGNALFD=y +# CONFIG_SK98LIN is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +CONFIG_SLHC=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_SLIP_SMART=y +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_DEBUG_ON is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_SOFT_WATCHDOG=m +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_SOUND=m +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_SPARSEMEM_STATIC=y +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SSB=m +CONFIG_SSB_DEBUG=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB_SILENT is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_STANDALONE=y +CONFIG_SUNRPC=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_SUNRPC_GSS=m +CONFIG_SUN_PARTITION=y +CONFIG_SUSPEND=y +CONFIG_SWAP=y +CONFIG_SYN_COOKIES=y +CONFIG_SYSCTL=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_SYSV_FS=m +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_MD5SIG=y +CONFIG_TEHUTI=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TICK_ONESHOT=y +CONFIG_TIMER_STATS=y +# CONFIG_TINY_SHMEM is not set +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TULIP=m +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_TUN=m +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_DEBUG is not set +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +CONFIG_UID16=y +CONFIG_UIO=m +CONFIG_UIO_CIF=m +CONFIG_ULTRIX_PARTITION=y +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_USB=m +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_ISP116X_HCD=m +# CONFIG_USB_OTG is not set +CONFIG_USB_PERSIST=y +CONFIG_USB_R8A66597_HCD=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_SUPPORT=y +# CONFIG_USB_TEST is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USER_NS is not set +CONFIG_VETH=m +CONFIG_VFAT_FS=m +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VGASTATE=m +CONFIG_VGA_CONSOLE=y +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_VIDEO_SELECT=y +CONFIG_VIRTIO=m +CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_BLK=m +CONFIG_VIRTIO_NET=m +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_RING=m +CONFIG_VIRTUALIZATION=y +CONFIG_VIRT_TO_BUS=y +CONFIG_VLAN_8021Q=m +CONFIG_VM86=y +CONFIG_VMI=y +# CONFIG_VMSPLIT_1G is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_VXFS_FS=m +CONFIG_W1=m +CONFIG_W1_CON=y +CONFIG_W1_SLAVE_DS2760=m +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_WRAPPER_PRINT is not set +CONFIG_X86=y +CONFIG_X86_32=y +# CONFIG_X86_64 is not set +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +# CONFIG_X86_BIGSMP is not set +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_BSWAP=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_CPUID=m +# CONFIG_X86_ELAN is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_X86_E_POWERSAVER is not set +CONFIG_X86_FIND_SMP_CONFIG=y +CONFIG_X86_GENERIC=y +# CONFIG_X86_GENERICARCH is not set +CONFIG_X86_GX_SUSPMOD=m +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_INVLPG=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_LONGHAUL=m +CONFIG_X86_LONGRUN=m +# CONFIG_X86_MCE is not set +CONFIG_X86_MINIMUM_CPU_FAMILY=4 +CONFIG_X86_MPPARSE=y +CONFIG_X86_MSR=m +# CONFIG_X86_NUMAQ is not set +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_PC=y +CONFIG_X86_PM_TIMER=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=m +CONFIG_X86_POWERNOW_K7_ACPI=y +CONFIG_X86_POWERNOW_K8=m +CONFIG_X86_POWERNOW_K8_ACPI=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_REBOOTFIXUPS=y +CONFIG_X86_SPEEDSTEP_CENTRINO=m +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_ICH=m +CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK=y +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_VSMP is not set +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_XADD=y +CONFIG_XFRM=y +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_USER=m +CONFIG_XFS_FS=m +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_QUOTA=y +CONFIG_XFS_RT=y +CONFIG_XFS_SECURITY=y +CONFIG_XOR_BLOCKS=m +CONFIG_ZISOFS=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZONE_DMA=y +# CONFIG_ZONE_DMA32 is not set +CONFIG_ZONE_DMA_FLAG=1 --- linux-2.6.24.orig/debian/config/i386/config.virtual +++ linux-2.6.24/debian/config/i386/config.virtual @@ -0,0 +1,665 @@ +# +# Config options for config.virtual automatically generated by splitconfig.pl +# +# CONFIG_60XX_WDT is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_9P_FS is not set +# CONFIG_ACENIC is not set +# CONFIG_ACPI_ASUS is not set +# CONFIG_ACPI_BATTERY is not set +# CONFIG_ACPI_DOCK is not set +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_TOSHIBA is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADVANTECH_WDT is not set +CONFIG_AEDSP16_MSS=y +# CONFIG_AEDSP16_SBPRO is not set +# CONFIG_AFFS_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AGP_ALI is not set +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_AMD64 is not set +# CONFIG_AGP_ATI is not set +# CONFIG_AGP_EFFICEON is not set +# CONFIG_AGP_NVIDIA is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_SWORKS is not set +# CONFIG_AGP_VIA is not set +# CONFIG_ALIM1535_WDT is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_APM is not set +# CONFIG_APPLICOM is not set +# CONFIG_ARCNET is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_ATL1 is not set +# CONFIG_ATM is not set +# CONFIG_B44 is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_ATIIXP is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_CS5535 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_IDE=y +# CONFIG_BLK_DEV_IDEACPI is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDEPNP is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_TC86C001 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BNX2 is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BT is not set +# CONFIG_CASSINI is not set +# CONFIG_CFG80211 is not set +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CPU5_WDT is not set +CONFIG_CPUSETS=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DEV_PADLOCK=m +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CS5535_GPIO is not set +# CONFIG_DAB is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_DE2104X is not set +# CONFIG_DE4X5 is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DECNET_NF_GRABULATOR is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_DL2K is not set +# CONFIG_DM9102 is not set +# CONFIG_DRM is not set +# CONFIG_DVB_CORE is not set +# CONFIG_E100 is not set +# CONFIG_ECONET is not set +# CONFIG_EDAC is not set +# CONFIG_EDD is not set +# CONFIG_EEPRO100 is not set +# CONFIG_EPIC100 is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_CYBLA is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_GEODE is not set +# CONFIG_FB_HECUBA is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_I810 is not set +# CONFIG_FB_IMAC is not set +# CONFIG_FB_INTEL is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FDDI is not set +# CONFIG_FEALNX is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_FORCEDETH is not set +# CONFIG_FUSION_LOGGING is not set +# CONFIG_GAMEPORT_EMU10K1 is not set +# CONFIG_GAMEPORT_FM801 is not set +# CONFIG_GAMEPORT_L4 is not set +# CONFIG_GAMEPORT_NS558 is not set +CONFIG_GENERIC_PENDING_IRQ=y +# CONFIG_HAMACHI is not set +# CONFIG_HAMRADIO is not set +# CONFIG_HAPPYMEAL is not set +CONFIG_HIBERNATION_SMP_POSSIBLE=y +# CONFIG_HID is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +# CONFIG_HIPPI is not set +CONFIG_HOTPLUG_CPU=y +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HP100 is not set +CONFIG_HPET_EMULATE_RTC=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_HWMON is not set +CONFIG_HW_RANDOM=m +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_GEODE is not set +# CONFIG_HW_RANDOM_VIA is not set +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_TINY_USB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2O is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_I8K is not set +# CONFIG_IB700_WDT is not set +# CONFIG_IBMASR is not set +# CONFIG_IBM_ASM is not set +# CONFIG_IDE_PROC_FS is not set +# CONFIG_IEEE1394 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +# CONFIG_INFINIBAND is not set +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_ATLAS_BTNS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_WISTRON_BTNS is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IRDA is not set +# CONFIG_IRQBALANCE is not set +# CONFIG_ISA is not set +# CONFIG_ISDN is not set +# CONFIG_IXGB is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KS0108 is not set +# CONFIG_KVM is not set +# CONFIG_LAPB is not set +CONFIG_LGUEST=m +# CONFIG_LGUEST_GUEST is not set +CONFIG_LLC=m +CONFIG_LOCK_KERNEL=y +# CONFIG_LXT_PHY is not set +# CONFIG_M486 is not set +CONFIG_M586=y +# CONFIG_M686 is not set +# CONFIG_MAC80211 is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_MACINTOSH_DRIVERS is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MATH_EMULATION is not set +# CONFIG_MCA is not set +# CONFIG_MD_RAID10 is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MINIX_FS is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_MMC is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_PS2_ALPS is not set +# CONFIG_MOUSE_PS2_LIFEBOOK is not set +# CONFIG_MOUSE_PS2_LOGIPS2PP is not set +# CONFIG_MOUSE_PS2_SYNAPTICS is not set +# CONFIG_MOUSE_PS2_TRACKPOINT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin" +CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin" +CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin" +CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin" +# CONFIG_MTD is not set +# CONFIG_MWAVE is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NATSEMI is not set +# CONFIG_NCP_FS is not set +# CONFIG_NETLABEL is not set +# CONFIG_NETXEN_NIC is not set +CONFIG_NET_ACT_POLICE=y +# CONFIG_NET_ACT_SIMP is not set +CONFIG_NET_CLS_POLICE=y +# CONFIG_NET_DCCPPROBE is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_POCKET is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_NAT_H323 is not set +# CONFIG_NF_NAT_SIP is not set +# CONFIG_NF_NAT_SNMP_BASIC is not set +CONFIG_NO_HZ=y +CONFIG_NR_CPUS=8 +# CONFIG_NS83820 is not set +# CONFIG_NSC_GPIO is not set +CONFIG_NTFS_RW=y +# CONFIG_PARIDE is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_SERIAL is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PC8736x_GPIO is not set +# CONFIG_PC87413_WDT is not set +# CONFIG_PCCARD is not set +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_PHANTOM is not set +# CONFIG_PHONE is not set +# CONFIG_PLIP is not set +CONFIG_PM_SLEEP_SMP=y +CONFIG_PREEMPT_BKL=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_PSS_MIXER=y +# CONFIG_QLA3XXX is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_R3964 is not set +# CONFIG_R8169 is not set +# CONFIG_RESOURCES_64BIT is not set +# CONFIG_RFKILL is not set +# CONFIG_ROMFS_FS is not set +CONFIG_RTC=y +# CONFIG_RTC_CLASS is not set +# CONFIG_S2IO is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SBC8360_WDT is not set +# CONFIG_SBC_EPX_C3_WATCHDOG is not set +# CONFIG_SC1200_WDT is not set +# CONFIG_SC520_WDT is not set +CONFIG_SC6600=y +CONFIG_SC6600_CDROM=4 +CONFIG_SC6600_CDROMBASE=0 +CONFIG_SC6600_JOY=y +# CONFIG_SC92031 is not set +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_TGT is not set +# CONFIG_SCx200 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_SIS190 is not set +# CONFIG_SIS900 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +CONFIG_SMP=y +# CONFIG_SMSC37B787_WDT is not set +# CONFIG_SMSC_PHY is not set +CONFIG_SND=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 +CONFIG_SND_AD1889=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ALS300=m +CONFIG_SND_ALS4000=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +# CONFIG_SND_BT87X_OVERCLOCK is not set +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS5530=m +CONFIG_SND_CS5535AUDIO=m +CONFIG_SND_DARLA20=m +CONFIG_SND_DARLA24=m +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DUMMY=m +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_ECHO3G=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_FM801=m +# CONFIG_SND_FM801_TEA575X_BOOL is not set +CONFIG_SND_GINA20=m +CONFIG_SND_GINA24=m +CONFIG_SND_HDA_CODEC_ANALOG=y +CONFIG_SND_HDA_CODEC_ATIHDMI=y +CONFIG_SND_HDA_CODEC_CMEDIA=y +CONFIG_SND_HDA_CODEC_CONEXANT=y +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_CODEC_SI3054=y +CONFIG_SND_HDA_CODEC_SIGMATEL=y +CONFIG_SND_HDA_CODEC_VIA=y +CONFIG_SND_HDA_GENERIC=y +# CONFIG_SND_HDA_HWDEP is not set +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_POWER_SAVE=y +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_KORG1212_FIRMWARE_IN_KERNEL=y +CONFIG_SND_LAYLA20=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MAESTRO3_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MIA=m +CONFIG_SND_MIXART=m +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_MONA=m +CONFIG_SND_MPU401=m +CONFIG_SND_MPU401_UART=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_NM256=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_PCM=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_PCXHR=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_RTCTIMER=m +CONFIG_SND_SB16_DSP=m +CONFIG_SND_SB_COMMON=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_SOC=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_TIMER=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_USB_USX2Y=m +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_VERBOSE_PROCFS=y +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_VX222=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y +# CONFIG_SONYPI is not set +# CONFIG_SONY_LAPTOP is not set +CONFIG_SOUND_AEDSP16=m +CONFIG_SOUND_DMAP=y +CONFIG_SOUND_KAHLUA=m +CONFIG_SOUND_MPU401=m +CONFIG_SOUND_MSNDCLAS=m +CONFIG_SOUND_MSNDPIN=m +CONFIG_SOUND_MSS=m +CONFIG_SOUND_OSS=m +CONFIG_SOUND_PAS=m +CONFIG_SOUND_PRIME=m +CONFIG_SOUND_PSS=m +CONFIG_SOUND_SB=m +CONFIG_SOUND_SSCAPE=m +# CONFIG_SOUND_TRACEINIT is not set +CONFIG_SOUND_TRIDENT=m +CONFIG_SOUND_TRIX=m +CONFIG_SOUND_UART6850=m +CONFIG_SOUND_VMIDI=m +CONFIG_SOUND_YM3812=m +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_SSB_DRIVER_PCICORE is not set +CONFIG_STOP_MACHINE=y +# CONFIG_SUNDANCE is not set +# CONFIG_SUNGEM is not set +CONFIG_SUSPEND_SMP_POSSIBLE=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_THINKPAD_ACPI is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_TIGON3 is not set +# CONFIG_TLAN is not set +# CONFIG_TOSHIBA is not set +# CONFIG_TR is not set +# CONFIG_ULI526X is not set +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_GADGET is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LIBUSUAL is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-4.6-virtual" +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_MATROX is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83697HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_WAFER_WDT is not set +# CONFIG_WAN is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_WDTPCI is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_X25 is not set +CONFIG_X86_ALIGNMENT_16=y +# CONFIG_X86_CPUFREQ_NFORCE2 is not set +CONFIG_X86_F00F_BUG=y +CONFIG_X86_HT=y +CONFIG_X86_SMP=y +CONFIG_X86_SPEEDSTEP_LIB=y +CONFIG_X86_SPEEDSTEP_SMI=y +CONFIG_X86_TRAMPOLINE=y +# CONFIG_YELLOWFIN is not set --- linux-2.6.24.orig/debian/config/i386/config.386 +++ linux-2.6.24/debian/config/i386/config.386 @@ -0,0 +1,1951 @@ +# +# Config options for config.386 automatically generated by splitconfig.pl +# +CONFIG_3C359=m +CONFIG_3C515=m +CONFIG_60XX_WDT=m +CONFIG_6PACK=m +CONFIG_8139CP=m +CONFIG_8139TOO_8129=y +CONFIG_9P_FS=m +CONFIG_ABYSS=m +CONFIG_AC3200=m +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BAY=m +CONFIG_ACPI_DOCK=m +CONFIG_ACPI_SBS=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_ACPI_VIDEO=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ACT200L_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_ADM8211=m +CONFIG_ADVANTECH_WDT=m +CONFIG_AFFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_AFS_FS=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_AGP_ALI=m +CONFIG_AGP_AMD=m +CONFIG_AGP_AMD64=m +CONFIG_AGP_ATI=m +CONFIG_AGP_EFFICEON=m +CONFIG_AGP_NVIDIA=m +CONFIG_AGP_SIS=m +CONFIG_AGP_SWORKS=m +CONFIG_AGP_VIA=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_AIRO=m +CONFIG_AIRO_CS=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_ALI_FIR=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_AMD8111_ETH=m +CONFIG_APM=m +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_CPU_IDLE is not set +# CONFIG_APM_DISPLAY_BLANK is not set +# CONFIG_APM_DO_ENABLE is not set +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set +CONFIG_APPLICOM=m +CONFIG_APRICOT=m +CONFIG_ARCNET=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_ARCNET_COM20020_ISA=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARLAN=m +CONFIG_ASUS_LAPTOP=m +CONFIG_AT1700=m +CONFIG_ATA_OVER_ETH=m +CONFIG_ATL1=m +CONFIG_ATM=y +CONFIG_ATMEL=m +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_FORE200E=m +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E_MAYBE=m +CONFIG_ATM_FORE200E_PCA=y +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y +CONFIG_ATM_FORE200E_TX_RETRY=16 +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_LANAI=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_NICSTAR=m +# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set +# CONFIG_ATM_NICSTAR_USE_SUNI is not set +CONFIG_ATM_TCP=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_ATP=m +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_B43=m +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PIO=y +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_B43_DEBUG=y +CONFIG_B43_DMA=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +CONFIG_B43_LEDS=y +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_PCI_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_PIO=y +# CONFIG_B43_PIO_MODE is not set +CONFIG_B43_RFKILL=y +CONFIG_B44=m +CONFIG_B44_PCI=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_BACKLIGHT_CARILLO_RANCH=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_PROGEAR=m +CONFIG_BAYCOM_EPP=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +CONFIG_BCM43XX_PIO=y +# CONFIG_BCM43XX_PIO_MODE is not set +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_BLK_DEV_4DRIVES=y +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI14XX=m +CONFIG_BLK_DEV_ALI15X3=m +CONFIG_BLK_DEV_ATIIXP=m +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +CONFIG_BLK_DEV_CMD64X=m +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_CS5535=m +CONFIG_BLK_DEV_CY82C693=m +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_DTC2278=m +CONFIG_BLK_DEV_HPT34X=m +CONFIG_BLK_DEV_HPT366=m +CONFIG_BLK_DEV_HT6560B=m +CONFIG_BLK_DEV_IDE=m +CONFIG_BLK_DEV_IDEACPI=y +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_BLK_DEV_NS87415=m +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_OPTI621=m +CONFIG_BLK_DEV_PDC202XX_OLD=m +CONFIG_BLK_DEV_QD65XX=m +CONFIG_BLK_DEV_SC1200=m +CONFIG_BLK_DEV_SX8=m +CONFIG_BLK_DEV_TC86C001=m +CONFIG_BLK_DEV_TRM290=m +CONFIG_BLK_DEV_UMC8672=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_XD=m +CONFIG_BNX2=m +CONFIG_BPQETHER=m +CONFIG_BROADCOM_PHY=m +CONFIG_BROKEN_ON_SMP=y +CONFIG_BT=m +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIVHCI=m +CONFIG_BT_HIDP=m +CONFIG_BT_L2CAP=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_SCO=m +CONFIG_C101=m +CONFIG_CAPI_AVM=y +CONFIG_CAPI_EICON=y +CONFIG_CAPI_TRACE=y +CONFIG_CARDBUS=y +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_CASSINI=m +CONFIG_CFAG12864B=m +CONFIG_CFAG12864B_RATE=20 +CONFIG_CFG80211=m +CONFIG_CHECK_SIGNATURE=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_CHR_DEV_OSST=m +CONFIG_CHR_DEV_SCH=m +CONFIG_CHR_DEV_ST=m +CONFIG_CICADA_PHY=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_COMPUTONE=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_COSA=m +CONFIG_CPU5_WDT=m +CONFIG_CPU_FREQ_TABLE=m +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DEV_PADLOCK=y +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CS5535_GPIO=m +CONFIG_CS89x0=m +CONFIG_CYCLADES=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +# CONFIG_CYZ_INTR is not set +CONFIG_DAB=y +CONFIG_DAVICOM_PHY=m +CONFIG_DE2104X=m +CONFIG_DE4X5=m +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DECNET_NF_GRABULATOR=m +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_DEPCA=m +CONFIG_DE_AOC=y +CONFIG_DIGIEPCA=m +CONFIG_DISPLAY_SUPPORT=m +CONFIG_DL2K=m +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_DM9102=m +CONFIG_DMASCC=m +CONFIG_DONGLE=y +# CONFIG_DONGLE_OLD is not set +CONFIG_DRM=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_I915=m +CONFIG_DRM_MGA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_SAVAGE=m +CONFIG_DRM_SIS=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_VIA=m +CONFIG_DRM_VIA_CHROME9=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DTLK=m +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_B2C2_FLEXCOP=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_BT8XX=m +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_PATCH=m +CONFIG_DVB_CAPTURE_DRIVERS=y +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m +# CONFIG_DVB_FE_CUSTOMISE is not set +CONFIG_DVB_ISL6421=m +CONFIG_DVB_L64781=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LNBP21=m +CONFIG_DVB_MT312=m +CONFIG_DVB_MT352=m +CONFIG_DVB_NXT200X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_PLL=m +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_STV0297=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_TUNER_DIB0070=m +CONFIG_DVB_TUNER_MT2060=m +CONFIG_DVB_TUNER_MT2131=m +CONFIG_DVB_TUNER_MT2266=m +CONFIG_DVB_TUNER_QT1010=m +CONFIG_DVB_USB=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_CXUSB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_ZL10353=m +CONFIG_E100=m +CONFIG_E2100=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_EDAC=y +# CONFIG_EDAC_AMD76X is not set +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_E752X=m +CONFIG_EDAC_E7XXX=m +CONFIG_EDAC_I3000=m +CONFIG_EDAC_I5000=m +CONFIG_EDAC_I82860=m +CONFIG_EDAC_I82875P=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_MM_EDAC=m +CONFIG_EDAC_R82600=m +CONFIG_EDD=y +CONFIG_EDD_OFF=y +CONFIG_EEPRO100=m +CONFIG_EEXPRESS=m +CONFIG_EEXPRESS_PRO=m +CONFIG_EISA=y +CONFIG_EISA_NAMES=y +CONFIG_EISA_PCI_EISA=y +CONFIG_EISA_VIRTUAL_ROOT=y +CONFIG_EISA_VLB_PRIMING=y +CONFIG_EL1=m +CONFIG_EL16=m +CONFIG_EL2=m +CONFIG_EL3=m +CONFIG_ELMC=m +CONFIG_ELMC_II=m +CONFIG_ELPLUS=m +CONFIG_EPIC100=m +CONFIG_ES3210=m +CONFIG_ESI_DONGLE=m +# CONFIG_ESPSERIAL is not set +CONFIG_ETH16I=m +CONFIG_EUROTECH_WDT=m +CONFIG_EWRK3=m +CONFIG_FARSYNC=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_ARK=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_CYBER2000=m +CONFIG_FB_CYBLA=m +CONFIG_FB_DDC=m +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_GX=m +CONFIG_FB_GEODE_GX1=m +# CONFIG_FB_GEODE_GX_SET_FBSIZE is not set +CONFIG_FB_GEODE_LX=m +CONFIG_FB_HECUBA=m +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_I810=m +# CONFIG_FB_I810_GTF is not set +CONFIG_FB_IMAC=y +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_KYRO=m +CONFIG_FB_LE80578=m +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_BACKLIGHT=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_I2C=y +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_PM3=m +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_BACKLIGHT=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_I2C=y +CONFIG_FB_S1D13XXX=m +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_SM501=m +CONFIG_FB_SVGALIB=m +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FDDI=y +CONFIG_FEALNX=m +CONFIG_FIXED_MII_1000_FDX=y +# CONFIG_FIXED_MII_100_FDX is not set +# CONFIG_FIXED_MII_10_FDX is not set +CONFIG_FIXED_MII_AMNT=1 +CONFIG_FIXED_PHY=m +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +CONFIG_FTL=m +CONFIG_FUJITSU_LAPTOP=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GEN_RTC=m +CONFIG_GEN_RTC_X=y +CONFIG_GIGASET_BASE=m +# CONFIG_GIGASET_DEBUG is not set +CONFIG_GIGASET_M101=m +CONFIG_GIGASET_M105=m +# CONFIG_GIGASET_UNDOCREQ is not set +CONFIG_GIRBIL_DONGLE=m +CONFIG_HAMACHI=m +CONFIG_HAMRADIO=y +CONFIG_HAPPYMEAL=m +CONFIG_HDLC=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_X25=m +CONFIG_HERMES=m +CONFIG_HIBERNATION_UP_POSSIBLE=y +CONFIG_HID=m +CONFIG_HIDRAW=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HID_FF is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIPPI=y +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_BKM_A4T=y +# CONFIG_HISAX_DEBUG is not set +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_ENTERNOW_PCI=y +CONFIG_HISAX_EURO=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HDLC=y +CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_MAX_CARDS=8 +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_NICCY=y +# CONFIG_HISAX_NO_KEYPAD is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_TELES_CS=m +CONFIG_HISAX_W6692=y +CONFIG_HOSTAP=m +CONFIG_HOSTAP_CS=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTESS_SV11=m +CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI_ACPI=m +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_COMPAQ=m +CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM=y +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m +CONFIG_HOTPLUG_PCI_FAKE=m +CONFIG_HOTPLUG_PCI_IBM=m +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HP100=m +CONFIG_HPLAN=m +CONFIG_HPLAN_PLUS=m +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_HWMON_VID=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_AMD=m +CONFIG_HW_RANDOM_GEODE=m +CONFIG_HW_RANDOM_VIA=m +CONFIG_HYSDN=m +CONFIG_HYSDN_CAPI=y +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_ELEKTOR=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PCA_ISA=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_BUS=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_PROC=m +CONFIG_I2O_SCSI=m +CONFIG_I6300ESB_WDT=m +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_I8K=m +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_IBMLANA=m +CONFIG_IBMLS=m +# CONFIG_IBMMCA_SCSI_DEV_RESET is not set +CONFIG_IBMMCA_SCSI_ORDER_STANDARD=y +CONFIG_IBMOL=m +CONFIG_IBMTR=m +CONFIG_IBM_ASM=m +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_IDE_PROC_FS=y +CONFIG_IEEE1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_OHCI1394=m +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE80211=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_CRYPT_WEP=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFTL=m +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_POLLDEV=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=m +CONFIG_INPUT_WISTRON_BTNS=m +# CONFIG_INPUT_YEALINK is not set +CONFIG_IPPP_FILTER=y +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPW2100=m +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2200=m +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IRCOMM=m +CONFIG_IRDA=m +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_DEBUG=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_ULTRA=y +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRPORT_SIR=m +CONFIG_IRTTY_SIR=m +CONFIG_ISA=y +CONFIG_ISAPNP=y +CONFIG_ISDN=m +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIDRV=m +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_MAINT=m +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVERSION=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_B1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_ISDN_DRV_AVMB1_T1ISA=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_ISDN_DRV_HISAX=m +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_LOOP=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_MPP=y +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_TTY_FAX=y +CONFIG_ISDN_X25=y +# CONFIG_ISI is not set +CONFIG_ISTALLION=m +# CONFIG_IWLWIFI is not set +CONFIG_IXGB=m +# CONFIG_IXGB_NAPI is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_K8_NB=y +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KINGSUN_DONGLE=m +CONFIG_KS0108=m +CONFIG_KS0108_DELAY=2 +CONFIG_KS0108_PORT=0x378 +CONFIG_KS959_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KVM=m +CONFIG_KVM_AMD=m +CONFIG_KVM_INTEL=m +CONFIG_LANCE=m +CONFIG_LANMEDIA=m +CONFIG_LAPB=m +CONFIG_LAPBETHER=m +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +CONFIG_LEDS_CLASS=m +CONFIG_LEDS_NET48XX=m +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_WRAP=m +CONFIG_LGUEST=m +# CONFIG_LGUEST_GUEST is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_CS=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_USB=m +CONFIG_LITELINK_DONGLE=m +CONFIG_LLC=y +CONFIG_LNE390=m +CONFIG_LP486E=m +CONFIG_LTPC=m +CONFIG_LXT_PHY=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_M486=y +# CONFIG_M586 is not set +# CONFIG_M686 is not set +CONFIG_MA600_DONGLE=m +CONFIG_MAC80211=m +# CONFIG_MAC80211_DEBUG is not set +CONFIG_MAC80211_DEBUGFS=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MACHZ_WDT=m +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_MADGEMC=m +CONFIG_MARVELL_PHY=m +CONFIG_MATH_EMULATION=y +CONFIG_MCA=y +CONFIG_MCA_LEGACY=y +# CONFIG_MCA_PROC_FS is not set +CONFIG_MCP2120_DONGLE=m +CONFIG_MCS_FIR=m +CONFIG_MDA_CONSOLE=m +CONFIG_MD_RAID10=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_SAS=m +CONFIG_MFD_SM501=m +CONFIG_MINIX_FS=m +CONFIG_MIXCOMWD=m +CONFIG_MKISS=m +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_MLX4_INFINIBAND=m +CONFIG_MMC=m +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_SDHCI=m +CONFIG_MMC_TIFM_SD=m +# CONFIG_MMC_UNSAFE_RESUME is not set +CONFIG_MMC_WBSD=m +CONFIG_MOUSE_APPLETOUCH=m +# CONFIG_MOUSE_ATIXL is not set +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_MOXA_INTELLIO=m +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +CONFIG_MSI_LAPTOP=m +CONFIG_MTD=m +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTD_ABSENT=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK2MTD=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_MTD_CFI=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_CHAR=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_CONCAT=m +CONFIG_MTD_DATAFLASH=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_DILNETPC=m +CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000 +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCECC=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCPROBE_ADDRESS=0 +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_L440GX=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTD_NAND=m +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_CS553X=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND_IDS=m +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NETSC520=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_2X_PROGRAM=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_SIM=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_OOPS=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_PCI=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PLATRAM=m +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_PNC2000=m +CONFIG_MTD_RAM=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +CONFIG_MTD_REDBOOT_PARTS=m +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +CONFIG_MTD_ROM=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_TS5500=m +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MWAVE=m +CONFIG_MYRI10GE=m +CONFIG_N2=m +CONFIG_NATSEMI=m +CONFIG_NCPFS_EXTRAS=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_PACKET_SIGNING=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_STRONG=y +CONFIG_NCP_FS=m +CONFIG_NE2000=m +CONFIG_NE2_MCA=m +CONFIG_NE3210=m +# CONFIG_NETLABEL is not set +CONFIG_NETROM=m +CONFIG_NETXEN_NIC=m +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_SIMP=m +# CONFIG_NET_CLS_POLICE is not set +CONFIG_NET_DCCPPROBE=m +CONFIG_NET_FC=y +CONFIG_NET_ISA=y +CONFIG_NET_PCMCIA=y +CONFIG_NET_POCKET=y +CONFIG_NET_SCH_ATM=m +CONFIG_NET_TCPPROBE=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_RACAL=y +CONFIG_NET_VENDOR_SMC=y +CONFIG_NEW_LEDS=y +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NI5010=m +CONFIG_NI52=m +CONFIG_NI65=m +CONFIG_NL80211=y +# CONFIG_NORTEL_HERMES is not set +# CONFIG_NO_HZ is not set +CONFIG_NS83820=m +CONFIG_NSC_FIR=m +CONFIG_NSC_GPIO=m +# CONFIG_NTFS_RW is not set +CONFIG_N_HDLC=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_P54_COMMON=m +CONFIG_P54_PCI=m +CONFIG_P54_USB=m +CONFIG_PARIDE=m +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_BPCK6=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PG=m +CONFIG_PARIDE_PT=m +CONFIG_PARPORT_AX88796=m +CONFIG_PARPORT_NOT_PC=y +CONFIG_PARPORT_PC_FIFO=y +CONFIG_PARPORT_PC_PCMCIA=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PATA_CS5520=m +CONFIG_PATA_EFAR=m +# CONFIG_PATA_ISAPNP is not set +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +# CONFIG_PATA_LEGACY is not set +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NETCELL=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_PCMCIA=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_QDI=m +CONFIG_PATA_RZ1000=m +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_WINBOND=m +# CONFIG_PATA_WINBOND_VLB is not set +CONFIG_PC300=m +# CONFIG_PC300TOO is not set +CONFIG_PC300_MLPPP=y +CONFIG_PC8736x_GPIO=m +CONFIG_PC87413_WDT=m +CONFIG_PCCARD=m +CONFIG_PCCARD_NONSTATIC=m +CONFIG_PCI200SYN=m +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIPCWATCHDOG=m +CONFIG_PCI_ATMEL=m +# CONFIG_PCI_HERMES is not set +CONFIG_PCMCIA=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_AXNET=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_IBMTR=m +CONFIG_PCMCIA_IOCTL=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_PROBE=y +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_PCMCIA_XIRTULIP=m +CONFIG_PCWATCHDOG=m +CONFIG_PD6729=m +CONFIG_PDC202XX_BURST=y +CONFIG_PDC_ADMA=m +CONFIG_PHANTOM=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m +CONFIG_PLIP=m +# CONFIG_PLX_HERMES is not set +CONFIG_PNPBIOS=y +CONFIG_PNPBIOS_PROC_FS=y +CONFIG_PPPOATM=m +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_PRISM54=m +CONFIG_PROTEON=m +CONFIG_QLA3XXX=m +CONFIG_QSEMI_PHY=m +CONFIG_R3964=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_CADET=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +# CONFIG_RADIO_TYPHOON_PROC_FS is not set +CONFIG_RADIO_ZOLTRIX=m +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +# CONFIG_RESOURCES_64BIT is not set +CONFIG_RFD_FTL=m +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +CONFIG_RIO=m +CONFIG_RIO_OLDPCI=y +CONFIG_RISCOM8=m +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_ROCKETPORT=m +CONFIG_ROMFS_FS=m +CONFIG_ROSE=m +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT2X00=m +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RT2X00_LIB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT73USB=m +CONFIG_RTC=m +CONFIG_RTC_CLASS=m +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_TEST=m +CONFIG_RTC_DRV_V3020=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=m +CONFIG_RTL8187=m +CONFIG_RXKAD=m +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +CONFIG_SATA_AHCI=m +CONFIG_SATA_INIC162X=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_SX4=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SBC8360_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m +CONFIG_SBNI=m +# CONFIG_SBNI_MULTILINE is not set +CONFIG_SC1200_WDT=m +CONFIG_SC520_WDT=m +CONFIG_SC92031=m +CONFIG_SCC=m +# CONFIG_SCC_DELAY is not set +# CONFIG_SCC_TRXECHO is not set +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_7000FASST=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AHA1740=m +CONFIG_SCSI_AIC79XX=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_SCSI_AIC94XX=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_DTC3280=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_FD_MCS=m +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_GENERIC_NCR5380=m +CONFIG_SCSI_GENERIC_NCR5380_MMIO=m +CONFIG_SCSI_GENERIC_NCR53C400=y +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_IBMMCA=m +CONFIG_SCSI_IMM=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_DUMP is not set +# CONFIG_SCSI_IPR_TRACE is not set +CONFIG_SCSI_IPS=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_MCA_53C9X=m +CONFIG_SCSI_NCR53C406A=m +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 +CONFIG_SCSI_NCR53C8XX_SYNC=5 +CONFIG_SCSI_NCR_D700=m +CONFIG_SCSI_NCR_Q720=m +CONFIG_SCSI_NSP32=m +CONFIG_SCSI_PAS16=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_PSI240I=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SEAGATE=m +CONFIG_SCSI_SIM710=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C416=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_T128=m +CONFIG_SCSI_TGT=m +CONFIG_SCSI_U14_34F=m +CONFIG_SCSI_U14_34F_LINKED_COMMANDS=y +CONFIG_SCSI_U14_34F_MAX_TAGS=8 +CONFIG_SCSI_U14_34F_TAGGED_QUEUE=y +CONFIG_SCSI_ULTRASTOR=m +CONFIG_SCx200=m +CONFIG_SCx200HR_TIMER=m +CONFIG_SCx200_ACB=m +CONFIG_SCx200_GPIO=m +CONFIG_SCx200_I2C=m +CONFIG_SCx200_I2C_SCL=12 +CONFIG_SCx200_I2C_SDA=13 +CONFIG_SCx200_WDT=m +CONFIG_SDIO_UART=m +CONFIG_SDLA=m +CONFIG_SEALEVEL_4021=m +CONFIG_SEEQ8005=m +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_APPLESMC=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_HDAPS=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SERIAL_8250_ACCENT=m +CONFIG_SERIAL_8250_BOCA=m +CONFIG_SERIAL_8250_CS=m +CONFIG_SERIAL_8250_EXAR_ST16C554=m +CONFIG_SERIAL_8250_FOURPORT=m +CONFIG_SERIAL_8250_HUB6=m +CONFIG_SERIAL_8250_MCA=m +CONFIG_SERIAL_JSM=m +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SGI_IOC4=m +CONFIG_SIGMATEL_FIR=m +CONFIG_SIS190=m +CONFIG_SIS900=m +CONFIG_SKFP=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKISA=m +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +CONFIG_SMC9194=m +CONFIG_SMCTR=m +CONFIG_SMC_IRCC_FIR=m +# CONFIG_SMP is not set +CONFIG_SMSC37B787_WDT=m +CONFIG_SMSC_PHY=m +# CONFIG_SND is not set +CONFIG_SONYPI=m +CONFIG_SONYPI_COMPAT=y +CONFIG_SONY_LAPTOP=m +# CONFIG_SOUND_PRIME is not set +CONFIG_SPECIALIX=m +# CONFIG_SPECIALIX_RTSCTS is not set +CONFIG_SPI=y +CONFIG_SPI_AT25=m +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_MASTER=y +# CONFIG_SPI_SPIDEV is not set +CONFIG_SPI_TLE62X0=m +CONFIG_SSB_DRIVER_PCICORE=y +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +CONFIG_SSFDC=m +CONFIG_STALDRV=y +CONFIG_STALLION=m +CONFIG_STRIP=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_SUNGEM=m +CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_SUSPEND_UP_POSSIBLE=y +CONFIG_SX=m +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_CS=m +CONFIG_SYNCLINK_GT=m +CONFIG_SYSV68_PARTITION=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TCG_NSC=m +CONFIG_TCG_TIS=m +CONFIG_TCG_TPM=m +CONFIG_TCIC=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_TELCLOCK=m +CONFIG_THINKPAD_ACPI=m +CONFIG_THINKPAD_ACPI_BAY=y +# CONFIG_THINKPAD_ACPI_DEBUG is not set +CONFIG_TIFM_7XX1=m +CONFIG_TIFM_CORE=m +CONFIG_TIGON3=m +CONFIG_TLAN=m +# CONFIG_TMD_HERMES is not set +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_TOSHIBA=m +CONFIG_TOSHIBA_FIR=m +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TR=y +CONFIG_TUNER_3036=m +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_SIMPLE=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TYPHOON=m +CONFIG_ULI526X=m +CONFIG_ULTRA=m +CONFIG_ULTRA32=m +CONFIG_ULTRAMCA=m +CONFIG_USBPCWATCHDOG=m +CONFIG_USB_ACM=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_ARMLINUX=y +CONFIG_USB_ATM=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_BELKIN=y +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_CATC=m +CONFIG_USB_CXACRU=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_DABUSB=m +CONFIG_USB_DSBR=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EMI26=m +CONFIG_USB_EMI62=m +CONFIG_USB_EPSON2888=y +CONFIG_USB_ET61X251=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_EZUSB=y +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_GADGET=m +CONFIG_USB_GADGETFS=m +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_M66592 is not set +CONFIG_USB_GADGET_NET2280=y +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_S3C2410 is not set +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_G_SERIAL=m +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_HIDINPUT_POWERBOOK=y +CONFIG_USB_IBMCAM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_IRDA=m +CONFIG_USB_KAWETH=m +CONFIG_USB_KBD=m +CONFIG_USB_KC2190=y +CONFIG_USB_KONICAWC=m +CONFIG_USB_LCD=m +CONFIG_USB_LD=m +CONFIG_USB_LED=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +# CONFIG_USB_MIDI_GADGET is not set +CONFIG_USB_MON=y +CONFIG_USB_MOUSE=m +CONFIG_USB_NET2280=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_RNDIS_HOST=m +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OV511 is not set +CONFIG_USB_PEGASUS=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_PRINTER=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_RIO500=m +CONFIG_USB_RTL8150=m +CONFIG_USB_SE401=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IPW=m +# CONFIG_USB_SERIAL_IR is not set +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_SL811_CS=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SN9C102=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STV680=m +CONFIG_USB_SUSPEND=y +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_USBNET=m +CONFIG_USB_USS720=m +CONFIG_USB_VICAM=m +CONFIG_USB_W9968CF=m +CONFIG_USB_XUSBATM=m +CONFIG_USB_ZC0301=m +CONFIG_USB_ZD1201=m +CONFIG_USB_ZERO=m +CONFIG_USB_ZR364XX=m +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-4.6-386" +CONFIG_VIA_FIR=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_RHINE_NAPI=y +CONFIG_VIA_VELOCITY=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_CX25840=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_DEV=m +# CONFIG_VIDEO_DPC is not set +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_FB_IVTV=m +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_MSP3400=m +# CONFIG_VIDEO_MXB is not set +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_29XXX=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_SAA7191=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_TCM825X=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_VP27SMPX=m +CONFIG_VIDEO_VPX3220=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VITESSE_PHY=m +CONFIG_VLSI_FIR=m +CONFIG_VORTEX=m +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_THERM=m +CONFIG_W83627HF_WDT=m +CONFIG_W83697HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_WAN=y +CONFIG_WANXL=m +CONFIG_WAN_ROUTER=m +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_WAVELAN=m +CONFIG_WD80x3=m +# CONFIG_WDC_ALI15X3 is not set +CONFIG_WDT=m +CONFIG_WDTPCI=m +CONFIG_WDT_501=y +CONFIG_WDT_501_PCI=y +CONFIG_WINBOND_840=m +CONFIG_WINBOND_FIR=m +CONFIG_WIRELESS_EXT=y +CONFIG_WLAN_80211=y +CONFIG_WLAN_PRE80211=y +CONFIG_X25=m +CONFIG_X25_ASY=m +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_CPUFREQ_NFORCE2=m +CONFIG_X86_F00F_BUG=y +CONFIG_X86_SPEEDSTEP_LIB=m +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_UP_APIC=y +CONFIG_X86_UP_IOAPIC=y +CONFIG_YAM=m +CONFIG_YELLOWFIN=m +CONFIG_YENTA=m +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_ZNET=m --- linux-2.6.24.orig/debian/config/ia64/config.itanium +++ linux-2.6.24/debian/config/ia64/config.itanium @@ -0,0 +1,7 @@ +# +# Config options for config.itanium automatically generated by splitconfig.pl +# +CONFIG_IA64_BRL_EMU=y +CONFIG_IA64_L1_CACHE_SHIFT=6 +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set --- linux-2.6.24.orig/debian/config/ia64/config.mckinley +++ linux-2.6.24/debian/config/ia64/config.mckinley @@ -0,0 +1,6 @@ +# +# Config options for config.mckinley automatically generated by splitconfig.pl +# +CONFIG_IA64_L1_CACHE_SHIFT=7 +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y --- linux-2.6.24.orig/debian/config/ia64/config +++ linux-2.6.24/debian/config/ia64/config @@ -0,0 +1,2540 @@ +# +# Common config options automatically generated by splitconfig.pl +# +CONFIG_3C359=m +CONFIG_64BIT=y +# CONFIG_6PACK is not set +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_8129=y +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_9P_FS=m +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_ACORN_PARTITION=y +CONFIG_ACORN_PARTITION_ADFS=y +# CONFIG_ACORN_PARTITION_CUMANA is not set +CONFIG_ACORN_PARTITION_EESOX=y +CONFIG_ACORN_PARTITION_ICS=y +CONFIG_ACORN_PARTITION_POWERTEC=y +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_ACPI=y +CONFIG_ACPI_BAY=m +CONFIG_ACPI_BLACKLIST_YEAR=0 +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_CONTAINER=m +CONFIG_ACPI_CUSTOM_DSDT_INITRD=y +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_DOCK=m +CONFIG_ACPI_EC=y +CONFIG_ACPI_FAN=m +CONFIG_ACPI_NUMA=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_PROCFS=y +CONFIG_ACPI_PROCFS_POWER=y +CONFIG_ACPI_PROC_EVENT=y +CONFIG_ACPI_SYSFS_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_ACPI_THERMAL=m +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_ADM8211=m +CONFIG_AFFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_AFS_FS=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_AGP=m +CONFIG_AGP_HP_ZX1=m +CONFIG_AGP_I460=m +# CONFIG_AGP_SGI_TIOCA is not set +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_AIRO_CS=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_AMD8111_ETH=m +CONFIG_AMIGA_PARTITION=y +CONFIG_ANON_INODES=y +CONFIG_APPLICOM=m +CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_ARCNET=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_ARCNET_COM20020_PCI=m +# CONFIG_ARCNET_COM90xx is not set +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RAW=m +# CONFIG_ARCNET_RIM_I is not set +# CONFIG_ARPD is not set +CONFIG_ASK_IP_FIB_HASH=y +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ATA=m +CONFIG_ATALK=m +CONFIG_ATARI_PARTITION=y +CONFIG_ATA_ACPI=y +CONFIG_ATA_GENERIC=m +CONFIG_ATA_NONSTANDARD=y +CONFIG_ATA_OVER_ETH=m +CONFIG_ATA_PIIX=m +CONFIG_ATL1=m +# CONFIG_ATM is not set +CONFIG_ATMEL=m +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_ARCH=y +CONFIG_AUDIT_TREE=y +CONFIG_AUTOFS4_FS=m +CONFIG_AUTOFS_FS=m +CONFIG_AUXDISPLAY=y +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_B43=m +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PIO=y +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_B43_DEBUG=y +CONFIG_B43_DMA=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +CONFIG_B43_LEDS=y +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_PCI_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_PIO=y +# CONFIG_B43_PIO_MODE is not set +CONFIG_B43_RFKILL=y +CONFIG_B44=m +CONFIG_B44_PCI=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +CONFIG_BATTERY_DS2760=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +CONFIG_BCM43XX_PIO=y +# CONFIG_BCM43XX_PIO_MODE is not set +# CONFIG_BEFS_DEBUG is not set +CONFIG_BEFS_FS=m +CONFIG_BFS_FS=m +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_BITREVERSE=y +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI15X3=m +CONFIG_BLK_DEV_AMD74XX=m +# CONFIG_BLK_DEV_BSG is not set +CONFIG_BLK_DEV_CMD64X=m +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_CRYPTOLOOP=m +# CONFIG_BLK_DEV_CS5520 is not set +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_CY82C693=m +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_DM=m +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_HPT34X=m +CONFIG_BLK_DEV_HPT366=m +CONFIG_BLK_DEV_IDE=m +CONFIG_BLK_DEV_IDEACPI=y +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDEDISK=m +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_BLK_DEV_IDETAPE=m +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_MD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_NS87415=m +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_OPTI621=m +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +CONFIG_BLK_DEV_PDC202XX_OLD=m +# CONFIG_BLK_DEV_PIIX is not set +CONFIG_BLK_DEV_PLATFORM=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_SC1200=m +CONFIG_BLK_DEV_SD=m +CONFIG_BLK_DEV_SGIIOC4=m +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +# CONFIG_BLK_DEV_SVWKS is not set +CONFIG_BLK_DEV_SX8=m +CONFIG_BLK_DEV_TC86C001=m +# CONFIG_BLK_DEV_TRIFLEX is not set +CONFIG_BLK_DEV_TRM290=m +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLOCK=y +CONFIG_BLOCK_COMPAT=y +CONFIG_BNX2=m +CONFIG_BONDING=m +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOUNCE=y +CONFIG_BPQETHER=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_NETFILTER=y +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BROADCOM_PHY=m +CONFIG_BSD_DISKLABEL=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_BT=m +CONFIG_BT_BNEP=m +# CONFIG_BT_BNEP_MC_FILTER is not set +# CONFIG_BT_BNEP_PROTO_FILTER is not set +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIUART=m +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_H4 is not set +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUSB=m +# CONFIG_BT_HCIUSB_SCO is not set +CONFIG_BT_HCIVHCI=m +CONFIG_BT_HIDP=m +CONFIG_BT_L2CAP=m +CONFIG_BT_RFCOMM=m +# CONFIG_BT_RFCOMM_TTY is not set +CONFIG_BT_SCO=m +CONFIG_BUG=y +CONFIG_CARDBUS=y +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_CASSINI=m +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_CFG80211=m +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_NS=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_CHR_DEV_OSST=m +CONFIG_CHR_DEV_SCH=m +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_ST=m +CONFIG_CICADA_PHY=m +CONFIG_CIFS=m +# CONFIG_CIFS_DEBUG2 is not set +CONFIG_CIFS_EXPERIMENTAL=y +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_WEAK_PW_HASH=y +# CONFIG_CIFS_XATTR is not set +CONFIG_CISS_SCSI_TAPE=y +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CODA_FS=m +CONFIG_CODA_FS_OLD_API=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_COMPUTONE=m +CONFIG_CONFIGFS_FS=m +CONFIG_CONNECTOR=m +CONFIG_CPUSETS=y +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_DEBUG is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_TABLE=m +CONFIG_CRAMFS=y +CONFIG_CRC16=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_CRC_CCITT=m +CONFIG_CRC_ITU_T=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_XTS=m +# CONFIG_CYCLADES is not set +# CONFIG_CYCLADES_SYNC is not set +CONFIG_DAB=y +CONFIG_DAVICOM_PHY=m +CONFIG_DE2104X=m +CONFIG_DE4X5=m +CONFIG_DE600=m +CONFIG_DE620=m +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_VM is not set +CONFIG_DECNET=m +CONFIG_DECNET_NF_GRABULATOR=m +# CONFIG_DECNET_ROUTER is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_BIC is not set +CONFIG_DEFAULT_CFQ=y +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_HTCP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_RELATIME=y +CONFIG_DEFAULT_RELATIME_VAL=1 +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_DEVPORT=y +CONFIG_DEV_APPLETALK=m +# CONFIG_DEV_KMEM is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DISABLE_VHPT is not set +CONFIG_DISCONTIGMEM=y +CONFIG_DISCONTIGMEM_MANUAL=y +CONFIG_DISPLAY_SUPPORT=m +CONFIG_DL2K=m +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_DM9102=m +CONFIG_DMI=y +CONFIG_DMIID=y +CONFIG_DM_CRYPT=m +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_MIRROR=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m +CONFIG_DM_MULTIPATH_HP=m +CONFIG_DM_MULTIPATH_RDAC=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_UEVENT=y +CONFIG_DM_ZERO=m +CONFIG_DNOTIFY=y +# CONFIG_DONGLE is not set +CONFIG_DRM=m +CONFIG_DRM_MGA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_SAVAGE=m +CONFIG_DRM_SIS=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_VIA=m +# CONFIG_DRM_VIA_CHROME9 is not set +CONFIG_DS1682=m +CONFIG_DSCC4=m +# CONFIG_DSCC4_PCISYNC is not set +# CONFIG_DSCC4_PCI_RST is not set +CONFIG_DUMMY=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_B2C2_FLEXCOP=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_BT8XX=m +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_PATCH=m +CONFIG_DVB_CAPTURE_DRIVERS=y +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m +# CONFIG_DVB_FE_CUSTOMISE is not set +CONFIG_DVB_ISL6421=m +CONFIG_DVB_L64781=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LNBP21=m +CONFIG_DVB_MT312=m +CONFIG_DVB_MT352=m +CONFIG_DVB_NXT200X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_PLL=m +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_STV0297=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_TUNER_DIB0070=m +CONFIG_DVB_TUNER_MT2060=m +CONFIG_DVB_TUNER_MT2131=m +CONFIG_DVB_TUNER_MT2266=m +CONFIG_DVB_TUNER_QT1010=m +CONFIG_DVB_USB=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_CXUSB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_ZL10353=m +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E1000_NAPI=y +# CONFIG_ECONET is not set +CONFIG_ECRYPT_FS=m +CONFIG_EEPRO100=m +CONFIG_EEPROM_93CX6=m +CONFIG_EFI=y +CONFIG_EFI_PARTITION=y +CONFIG_EFI_PCDP=y +CONFIG_EFI_RTC=y +CONFIG_EFI_VARS=m +CONFIG_EFS_FS=m +CONFIG_ELF_CORE=y +# CONFIG_EMBEDDED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +CONFIG_EPIC100=m +CONFIG_EPOLL=y +CONFIG_EQUALIZER=m +CONFIG_EVENTFD=y +CONFIG_EXPERIMENTAL=y +CONFIG_EXPORTFS=m +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_FAIR_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_FAIR_USER_SCHED is not set +CONFIG_FARSYNC=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_FS=m +# CONFIG_FAULT_INJECTION is not set +CONFIG_FB=y +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_ARK=m +CONFIG_FB_ASILIANT=y +CONFIG_FB_ATY=m +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_CIRRUS=m +CONFIG_FB_CYBER2000=m +CONFIG_FB_DDC=m +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_IMSTT is not set +CONFIG_FB_KYRO=m +# CONFIG_FB_MACMODES is not set +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_BACKLIGHT=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_I2C=y +CONFIG_FB_PM2=m +# CONFIG_FB_PM2_FIFO_DISCONNECT is not set +CONFIG_FB_PM3=m +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_BACKLIGHT=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_I2C=y +CONFIG_FB_S1D13XXX=m +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_SM501=m +CONFIG_FB_SVGALIB=m +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +CONFIG_FB_TILEBLITTING=y +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_UVESA=m +# CONFIG_FB_VIRTUAL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FDDI=y +CONFIG_FEALNX=m +CONFIG_FIB_RULES=y +# CONFIG_FIREWIRE is not set +CONFIG_FIRMWARE_EDID=y +CONFIG_FIXED_MII_1000_FDX=y +# CONFIG_FIXED_MII_100_FDX is not set +# CONFIG_FIXED_MII_10_FDX is not set +CONFIG_FIXED_MII_AMNT=1 +CONFIG_FIXED_PHY=m +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +# CONFIG_FORCED_INLINING is not set +CONFIG_FORCE_MAX_ZONEORDER=17 +CONFIG_FRAMEBUFFER_CONSOLE=m +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FS_MBCACHE=m +CONFIG_FS_POSIX_ACL=y +CONFIG_FTL=m +CONFIG_FUSE_FS=m +CONFIG_FUSION=y +CONFIG_FUSION_CTL=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y +CONFIG_FUSION_MAX_SGE=40 +CONFIG_FUSION_SAS=m +CONFIG_FUSION_SPI=m +CONFIG_FUTEX=y +CONFIG_FW_LOADER=y +CONFIG_GACT_PROB=y +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GENERIC_ACL=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_GFS2_FS_LOCKING_NOLOCK=m +CONFIG_HAMACHI=m +CONFIG_HAMRADIO=y +CONFIG_HANGCHECK_TIMER=m +# CONFIG_HAPPYMEAL is not set +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y +CONFIG_HAVE_ARCH_NODEDATA_EXTENSION=y +CONFIG_HDLC=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +# CONFIG_HEADERS_CHECK is not set +CONFIG_HERMES=m +CONFIG_HFSPLUS_FS=m +CONFIG_HFS_FS=m +CONFIG_HID=m +CONFIG_HIDRAW=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HID_FF is not set +CONFIG_HID_SUPPORT=y +# CONFIG_HIPPI is not set +CONFIG_HOLES_IN_ZONE=y +CONFIG_HOSTAP=m +CONFIG_HOSTAP_CS=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_PLX=m +CONFIG_HOTPLUG=y +# CONFIG_HOTPLUG_CPU is not set +CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI_ACPI=m +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_FAKE=m +CONFIG_HOTPLUG_PCI_PCIE=m +# CONFIG_HOTPLUG_PCI_SGI is not set +CONFIG_HOTPLUG_PCI_SHPC=m +# CONFIG_HP100 is not set +# CONFIG_HPET is not set +CONFIG_HPFS_FS=m +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_HP_SIMETH is not set +# CONFIG_HP_SIMSERIAL is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_HUGETLB_PAGE_SIZE_VARIABLE=y +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_HWMON_VID=m +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_INTEL=m +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +CONFIG_I2C=m +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCA=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +# CONFIG_I2C_DEBUG_CORE is not set +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_BUS=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_EXT_ADAPTEC_DMA64=y +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_PROC=m +CONFIG_I2O_SCSI=m +CONFIG_I82092=m +CONFIG_IA32_SUPPORT=y +CONFIG_IA64=y +# CONFIG_IA64_ACPI_CPUFREQ is not set +# CONFIG_IA64_CYCLONE is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_ESI is not set +CONFIG_IA64_GENERIC=y +CONFIG_IA64_GRANULE_16MB=y +# CONFIG_IA64_GRANULE_64MB is not set +CONFIG_IA64_HP_AML_NFW=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_HP_ZX1_SWIOTLB is not set +CONFIG_IA64_MCA_RECOVERY=m +CONFIG_IA64_MC_ERR_INJECT=m +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_64KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PALINFO=m +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_IA64_SGI_SN2 is not set +CONFIG_IA64_SGI_SN_XP=m +CONFIG_IA64_UNCACHED_ALLOCATOR=y +CONFIG_IBMOL=m +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +CONFIG_ICPLUS_PHY=m +CONFIG_IDE=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_IDE_ARM is not set +CONFIG_IDE_GENERIC=m +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_IDE_PROC_FS=y +CONFIG_IDE_TASK_IOCTL=y +CONFIG_IEEE1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_OHCI1394=m +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE80211=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_CRYPT_WEP=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_IFB=m +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_INET=y +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_TUNNEL=m +# CONFIG_INET_AH is not set +CONFIG_INET_DCCP_DIAG=m +CONFIG_INET_DIAG=y +# CONFIG_INET_ESP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_LRO=m +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFTL=m +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_INPUT=y +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MOUSE=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_POLLDEV=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_TABLET=y +# CONFIG_INPUT_TOUCHSCREEN is not set +CONFIG_INPUT_UINPUT=m +CONFIG_INPUT_YEALINK=m +CONFIG_INSTRUMENTATION=y +CONFIG_IOSAPIC=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IP1000=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_RT=m +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IPDDP=m +CONFIG_IPDDP_DECAP=y +CONFIG_IPDDP_ENCAP=y +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_POWEROFF=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPV6=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPW2100=m +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2200=m +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_DCCP=m +CONFIG_IP_DCCP_ACKVEC=y +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_IP_DCCP_TFRC_LIB=m +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_SCTP=m +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_TAB_BITS=12 +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_WRR=m +CONFIG_IRCOMM=m +CONFIG_IRDA=m +# CONFIG_IRDA_CACHE_LAST_LSAP is not set +# CONFIG_IRDA_DEBUG is not set +# CONFIG_IRDA_FAST_RR is not set +# CONFIG_IRDA_ULTRA is not set +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRQ_PER_CPU=y +CONFIG_IRTTY_SIR=m +CONFIG_ISCSI_TCP=m +# CONFIG_ISDN is not set +# CONFIG_ISI is not set +CONFIG_ISO9660_FS=m +# CONFIG_IWLWIFI is not set +CONFIG_IXGB=m +CONFIG_IXGBE=m +# CONFIG_IXGB_NAPI is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFS_DEBUG=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +CONFIG_JFS_STATISTICS=y +CONFIG_JOLIET=y +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_IFORCE=m +# CONFIG_JOYSTICK_IFORCE_232 is not set +# CONFIG_JOYSTICK_IFORCE_USB is not set +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_KARMA_PARTITION=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +CONFIG_KINGSUN_DONGLE=m +CONFIG_KMOD=y +CONFIG_KPROBES=y +CONFIG_KS0108=m +CONFIG_KS0108_DELAY=2 +CONFIG_KS0108_PORT=0x378 +CONFIG_KS959_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_LANMEDIA=m +# CONFIG_LAPB is not set +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +CONFIG_LDM_DEBUG=y +CONFIG_LDM_PARTITION=y +CONFIG_LEDS_CLASS=m +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LIBCRC32C=m +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_CS=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_LIBERTAS_USB=m +# CONFIG_LKDTM is not set +CONFIG_LLC=y +CONFIG_LLC2=m +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_LOCK_KERNEL=y +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_LP_CONSOLE is not set +CONFIG_LSM_MMAP_MIN_ADDR=0 +CONFIG_LXT_PHY=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_MAC80211=m +# CONFIG_MAC80211_DEBUG is not set +CONFIG_MAC80211_DEBUGFS=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MACVLAN=m +CONFIG_MAC_PARTITION=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_MARKERS is not set +CONFIG_MARVELL_PHY=m +CONFIG_MAX_RAW_DEVS=256 +CONFIG_MCS_FIR=m +CONFIG_MD=y +CONFIG_MDIO_BITBANG=m +CONFIG_MD_FAULTY=m +CONFIG_MD_LINEAR=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_SAS=m +CONFIG_MFD_SM501=m +CONFIG_MIGRATION=y +CONFIG_MII=m +CONFIG_MINIX_FS=m +CONFIG_MINIX_SUBPARTITION=y +CONFIG_MISC_DEVICES=y +# CONFIG_MKISS is not set +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_MLX4_INFINIBAND=m +# CONFIG_MMC is not set +# CONFIG_MMTIMER is not set +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_TRACKPOINT=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_MOXA_INTELLIO=m +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +CONFIG_MSDOS_FS=m +CONFIG_MSDOS_PARTITION=y +CONFIG_MSPEC=m +# CONFIG_MSS is not set +CONFIG_MTD=m +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTD_ABSENT=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK2MTD=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_MTD_CFI=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_CHAR=m +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_CONCAT=m +CONFIG_MTD_DATAFLASH=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCECC=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCPROBE_ADDRESS=0 +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTD_NAND=m +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND_IDS=m +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_2X_PROGRAM=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_SIM=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_OOPS=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_PCI=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PLATRAM=m +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_RAM=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +CONFIG_MTD_REDBOOT_PARTS=m +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +CONFIG_MTD_ROM=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MYRI10GE=m +CONFIG_NATSEMI=m +CONFIG_NCPFS_EXTRAS=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCP_FS=m +CONFIG_NE2K_PCI=m +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_NET=y +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETDEVICES=y +CONFIG_NETDEVICES_MULTIQUEUE=y +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +# CONFIG_NETLABEL is not set +CONFIG_NETPOLL=y +CONFIG_NETPOLL_TRAP=y +CONFIG_NETROM=m +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NETXEN_NIC=m +CONFIG_NET_9P=m +# CONFIG_NET_9P_DEBUG is not set +CONFIG_NET_9P_FD=m +CONFIG_NET_ACT_GACT=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_CLS=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_FW=m +# CONFIG_NET_CLS_IND is not set +# CONFIG_NET_CLS_POLICE is not set +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_DCCPPROBE=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_ETHERNET=y +CONFIG_NET_FC=y +# CONFIG_NET_IPGRE is not set +CONFIG_NET_IPIP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_NET_PCI=y +CONFIG_NET_PCMCIA=y +CONFIG_NET_PKTGEN=m +CONFIG_NET_POCKET=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_NET_SB1000=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_FIFO=y +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_RR=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_TCPPROBE=m +CONFIG_NET_TULIP=y +CONFIG_NET_VENDOR_3COM=y +CONFIG_NEW_LEDS=y +CONFIG_NFSD=m +CONFIG_NFSD_TCP=y +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_TFTP=m +# CONFIG_NIU is not set +CONFIG_NL80211=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +CONFIG_NODES_SHIFT=8 +# CONFIG_NORTEL_HERMES is not set +CONFIG_NR_CPUS=64 +CONFIG_NR_QUICK=1 +CONFIG_NS83820=m +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_FS=m +# CONFIG_NTFS_RW is not set +CONFIG_NUMA=y +CONFIG_N_HDLC=m +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_OCFS2_DEBUG_MASKLOG=y +CONFIG_OCFS2_FS=m +CONFIG_OPROFILE=m +CONFIG_OSF_PARTITION=y +CONFIG_P54_COMMON=m +CONFIG_P54_PCI=m +CONFIG_P54_USB=m +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_PARIDE=m +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_EPAT=m +CONFIG_PARIDE_EPATC8=y +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PG=m +CONFIG_PARIDE_PT=m +CONFIG_PARPORT=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_AX88796=m +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_NOT_PC=y +CONFIG_PARPORT_PC=m +# CONFIG_PARPORT_PC_FIFO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_SERIAL=m +CONFIG_PARTITION_ADVANCED=y +CONFIG_PATA_ACPI=m +# CONFIG_PATA_ALI is not set +CONFIG_PATA_AMD=m +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +CONFIG_PATA_CS5520=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NETCELL=m +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +CONFIG_PATA_OLDPIIX=m +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PCMCIA=m +CONFIG_PATA_PDC2027X=m +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +CONFIG_PC300=m +# CONFIG_PC300TOO is not set +CONFIG_PC300_MLPPP=y +CONFIG_PCCARD=m +CONFIG_PCCARD_NONSTATIC=m +CONFIG_PCI=y +CONFIG_PCI200SYN=m +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCI_ATMEL=m +# CONFIG_PCI_DEBUG is not set +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_HERMES is not set +CONFIG_PCI_LEGACY=y +# CONFIG_PCI_MSI is not set +CONFIG_PCI_SYSCALL=y +CONFIG_PCMCIA=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_AXNET=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_IOCTL=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_PD6729=m +CONFIG_PDA_POWER=m +# CONFIG_PDC202XX_BURST is not set +CONFIG_PDC_ADMA=m +CONFIG_PERFMON=y +CONFIG_PGTABLE_3=y +# CONFIG_PGTABLE_4 is not set +CONFIG_PHANTOM=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m +CONFIG_PHYLIB=m +# CONFIG_PID_NS is not set +CONFIG_PLIP=m +CONFIG_PLIST=y +# CONFIG_PLX_HERMES is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_DISABLE_CONSOLE=y +CONFIG_PM_LEGACY=y +CONFIG_PNP=y +CONFIG_PNPACPI=y +# CONFIG_PNP_DEBUG is not set +CONFIG_POSIX_MQUEUE=y +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PPDEV=m +CONFIG_PPP=m +CONFIG_PPPOE=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_SYNC_TTY=m +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_BKL=y +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTER=m +CONFIG_PRINTK=y +CONFIG_PRINTK_TIME=y +CONFIG_PRINT_QUOTA_WARNING=y +# CONFIG_PRISM54 is not set +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROFILING=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_QLA3XXX=m +CONFIG_QNX4FS_FS=m +CONFIG_QSEMI_PHY=m +CONFIG_QUICKLIST=y +CONFIG_QUOTA=y +CONFIG_QUOTACTL=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_R3964=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RAID_ATTRS=m +CONFIG_RAW_DRIVER=m +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_FS=m +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_REISERFS_FS_XATTR=y +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_RELAY=y +CONFIG_RESOURCES_64BIT=y +CONFIG_RFD_FTL=m +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +CONFIG_RIO=m +CONFIG_RIO_OLDPCI=y +CONFIG_ROCKETPORT=m +CONFIG_ROMFS_FS=m +CONFIG_ROSE=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT2X00=m +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RT2X00_LIB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT73USB=m +CONFIG_RTC_CLASS=m +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_TEST=m +CONFIG_RTC_DRV_V3020=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=m +CONFIG_RTL8187=m +CONFIG_RT_MUTEXES=y +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_RXKAD=m +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +# CONFIG_SAMPLES is not set +CONFIG_SATA_AHCI=m +CONFIG_SATA_INIC162X=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_SX4=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SC92031=m +# CONFIG_SCHEDSTATS is not set +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +# CONFIG_SCHED_SMT is not set +CONFIG_SCSI=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_AIC79XX=m +CONFIG_SCSI_AIC7XXX=m +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC94XX=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_DC395x=m +# CONFIG_SCSI_DEBUG is not set +CONFIG_SCSI_DMA=y +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +# CONFIG_SCSI_FUTURE_DOMAIN is not set +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_IMM=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_DUMP is not set +# CONFIG_SCSI_IPR_TRACE is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_ISCSI_ATTRS=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PPA=m +CONFIG_SCSI_PROC_FS=y +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_TGT=m +CONFIG_SCSI_WAIT_SCAN=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_MD5 is not set +CONFIG_SCTP_HMAC_NONE=y +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SECURITY=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +# CONFIG_SECURITY_APPARMOR_DISABLE is not set +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_DISABLE=y +# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_TSL2550=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_SERIAL_SGI_IOC3=m +CONFIG_SERIAL_SGI_IOC4=m +CONFIG_SERIAL_SGI_L1_CONSOLE=y +CONFIG_SERIO=y +CONFIG_SERIO_I8042=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_RAW=m +CONFIG_SERIO_SERPORT=m +CONFIG_SGI_IOC3=m +CONFIG_SGI_IOC4=m +CONFIG_SGI_MBCS=m +CONFIG_SGI_PARTITION=y +CONFIG_SGI_SN=y +CONFIG_SGI_SNSC=y +CONFIG_SGI_TIOCX=y +CONFIG_SHAPER=m +CONFIG_SHMEM=y +CONFIG_SIGMATEL_FIR=m +CONFIG_SIGNALFD=y +CONFIG_SIS190=m +CONFIG_SIS900=m +# CONFIG_SK98LIN is not set +CONFIG_SKFP=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +CONFIG_SLHC=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_SLIP_SMART=y +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_DEBUG_ON is not set +CONFIG_SMB_FS=m +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +CONFIG_SMP=y +CONFIG_SMSC_PHY=m +CONFIG_SOLARIS_X86_PARTITION=y +# CONFIG_SOUND is not set +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +# CONFIG_SPECIALIX is not set +CONFIG_SPI=y +CONFIG_SPI_AT25=m +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_MASTER=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SSB=m +CONFIG_SSB_DEBUG=y +CONFIG_SSB_DRIVER_PCICORE=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +CONFIG_SSB_POSSIBLE=y +CONFIG_SSFDC=m +CONFIG_STALDRV=y +CONFIG_STANDALONE=y +CONFIG_STOP_MACHINE=y +CONFIG_STRIP=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_SUNGEM is not set +CONFIG_SUNRPC=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_SUN_PARTITION=y +CONFIG_SWAP=y +CONFIG_SWIOTLB=y +# CONFIG_SX is not set +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_CS=m +CONFIG_SYNCLINK_GT=m +CONFIG_SYN_COOKIES=y +CONFIG_SYSCTL=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_SYSV68_PARTITION=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_SYSV_FS=m +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TCG_NSC=m +CONFIG_TCG_TIS=m +CONFIG_TCG_TPM=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_MD5SIG=y +CONFIG_TEHUTI=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TIFM_7XX1=m +CONFIG_TIFM_CORE=m +CONFIG_TIGON3=m +CONFIG_TIMER_STATS=y +# CONFIG_TINY_SHMEM is not set +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +# CONFIG_TMD_HERMES is not set +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_TMS380TR is not set +CONFIG_TR=y +CONFIG_TULIP=m +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_TUN=m +CONFIG_TUNER_3036=m +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_SIMPLE=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TYPHOON=m +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_DEBUG is not set +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +CONFIG_UIO=m +CONFIG_UIO_CIF=m +CONFIG_ULI526X=m +CONFIG_ULTRIX_PARTITION=y +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_USB=m +CONFIG_USB_ACM=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_AUERSWALD=m +CONFIG_USB_BELKIN=y +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_CATC=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_DABUSB=m +# CONFIG_USB_DEBUG is not set +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_DSBR=m +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EMI26=m +CONFIG_USB_EMI62=m +CONFIG_USB_EPSON2888=y +CONFIG_USB_ET61X251=m +CONFIG_USB_EZUSB=y +CONFIG_USB_FTDI_ELAN=m +# CONFIG_USB_GADGET is not set +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_HIDINPUT_POWERBOOK=y +CONFIG_USB_IBMCAM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_IRDA=m +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_KAWETH=m +CONFIG_USB_KBD=m +CONFIG_USB_KC2190=y +CONFIG_USB_KONICAWC=m +CONFIG_USB_LCD=m +CONFIG_USB_LD=m +CONFIG_USB_LED=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_MON=y +CONFIG_USB_MOUSE=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_RNDIS_HOST=m +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OV511 is not set +CONFIG_USB_PEGASUS=m +# CONFIG_USB_PERSIST is not set +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_PRINTER=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_R8A66597_HCD=m +CONFIG_USB_RIO500=m +CONFIG_USB_RTL8150=m +CONFIG_USB_SE401=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IPW=m +# CONFIG_USB_SERIAL_IR is not set +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_SL811_CS=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SN9C102=m +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_DATAFAB=y +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STV680=m +CONFIG_USB_SUPPORT=y +CONFIG_USB_SUSPEND=y +# CONFIG_USB_TEST is not set +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_USBNET=m +CONFIG_USB_USS720=m +CONFIG_USB_VICAM=m +CONFIG_USB_W9968CF=m +CONFIG_USB_ZC0301=m +CONFIG_USB_ZD1201=m +CONFIG_USB_ZR364XX=m +# CONFIG_USER_NS is not set +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VERSION_SIGNATURE="Unofficial" +CONFIG_VETH=m +CONFIG_VFAT_FS=m +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VGASTATE=m +CONFIG_VGA_CONSOLE=y +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_RHINE_NAPI=y +CONFIG_VIA_VELOCITY=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_CX25840=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_DEV=m +# CONFIG_VIDEO_DPC is not set +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_FB_IVTV=m +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_MSP3400=m +# CONFIG_VIDEO_MXB is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_29XXX=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_SAA7191=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_TCM825X=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_USBVIDEO=m +# CONFIG_VIDEO_USBVISION is not set +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_VP27SMPX=m +CONFIG_VIDEO_VPX3220=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIRTUAL_MEM_MAP=y +CONFIG_VIRT_TO_BUS=y +CONFIG_VITESSE_PHY=m +CONFIG_VLAN_8021Q=m +# CONFIG_VLSI_FIR is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VORTEX=m +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_VXFS_FS=m +CONFIG_W1=m +CONFIG_W1_CON=y +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_THERM=m +CONFIG_WAN=y +CONFIG_WANXL=m +CONFIG_WAN_ROUTER=m +CONFIG_WAN_ROUTER_DRIVERS=m +# CONFIG_WATCHDOG is not set +CONFIG_WDC_ALI15X3=y +CONFIG_WINBOND_840=m +CONFIG_WIRELESS_EXT=y +CONFIG_WLAN_80211=y +CONFIG_WLAN_PRE80211=y +# CONFIG_X25 is not set +CONFIG_XFRM=y +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_USER=m +CONFIG_XFS_FS=m +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_SECURITY=y +CONFIG_XOR_BLOCKS=m +CONFIG_YAM=m +CONFIG_YELLOWFIN=m +CONFIG_YENTA=m +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_ZISOFS=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZONE_DMA=y +CONFIG_ZONE_DMA_FLAG=1 --- linux-2.6.24.orig/debian/config/hppa/config +++ linux-2.6.24/debian/config/hppa/config @@ -0,0 +1,1366 @@ +# +# Common config options automatically generated by splitconfig.pl +# +CONFIG_53C700_LE_ON_BE=y +CONFIG_ACENIC=m +# CONFIG_ADFS_FS is not set +CONFIG_ADM8211=m +# CONFIG_AFFS_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_ANON_INODES=y +# CONFIG_APPLICOM is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_ARCNET is not set +# CONFIG_ARPD is not set +CONFIG_ASK_IP_FIB_HASH=y +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ATA=m +# CONFIG_ATALK is not set +CONFIG_ATA_GENERIC=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_ATA_PIIX=m +# CONFIG_ATM is not set +# CONFIG_ATMEL is not set +CONFIG_AUDIT=y +CONFIG_AUDIT_GENERIC=y +CONFIG_AUXDISPLAY=y +CONFIG_B43=m +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PIO=y +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_B43_DEBUG=y +CONFIG_B43_DMA=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_PCI_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_PIO=y +# CONFIG_B43_PIO_MODE is not set +CONFIG_B43_RFKILL=y +CONFIG_BACKLIGHT_CLASS_DEVICE=m +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +CONFIG_BATTERY_DS2760=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_BITREVERSE=y +# CONFIG_BLK_CPQ_CISS_DA is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +CONFIG_BLK_DEV_4DRIVES=y +# CONFIG_BLK_DEV_AEC62XX is not set +CONFIG_BLK_DEV_ALI14XX=m +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_CRYPTOLOOP=m +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_DM=m +CONFIG_BLK_DEV_DTC2278=m +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_HT6560B=m +CONFIG_BLK_DEV_IDE=m +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDEDISK=m +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDESCSI=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_MD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_NS87415=m +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PIIX is not set +CONFIG_BLK_DEV_PLATFORM=m +CONFIG_BLK_DEV_QD65XX=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_SD=m +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_TC86C001=m +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_UMC8672=m +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLOCK=y +# CONFIG_BONDING is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BRIDGE=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_NETFILTER=y +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BROADCOM_PHY=m +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +# CONFIG_BT is not set +CONFIG_BUG=y +CONFIG_CARDBUS=y +CONFIG_CASSINI=m +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_CFG80211=m +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_NS=y +CONFIG_CHASSIS_LCD_LED=y +CONFIG_CHR_DEV_OSST=m +CONFIG_CHR_DEV_SCH=m +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_ST=m +CONFIG_CICADA_PHY=m +CONFIG_CIFS=m +# CONFIG_CIFS_DEBUG2 is not set +CONFIG_CIFS_EXPERIMENTAL=y +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_WEAK_PW_HASH=y +# CONFIG_CIFS_XATTR is not set +CONFIG_CLS_U32_MARK=y +CONFIG_CLS_U32_PERF=y +# CONFIG_CODA_FS is not set +CONFIG_CONFIGFS_FS=m +CONFIG_CONNECTOR=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_CRC_CCITT=m +CONFIG_CRC_ITU_T=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_DAB=y +CONFIG_DAVICOM_PHY=m +# CONFIG_DE4X5 is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_MUTEXES is not set +CONFIG_DEBUG_RODATA=y +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DECNET is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_BIC is not set +CONFIG_DEFAULT_CFQ=y +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_HTCP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_RELATIME=y +CONFIG_DEFAULT_RELATIME_VAL=1 +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_DEVPORT=y +# CONFIG_DEV_KMEM is not set +# CONFIG_DM9102 is not set +CONFIG_DM_CRYPT=m +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_MIRROR=m +# CONFIG_DM_MULTIPATH is not set +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_UEVENT=y +CONFIG_DM_ZERO=m +CONFIG_DNOTIFY=y +# CONFIG_DRM is not set +# CONFIG_DTLK is not set +CONFIG_DUMMY=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=160 +CONFIG_DUMMY_CONSOLE_ROWS=64 +# CONFIG_DVB_CORE is not set +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E1000_NAPI=y +# CONFIG_ECONET is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EFS_FS is not set +CONFIG_EISA=y +CONFIG_EISA_NAMES=y +CONFIG_EL1=m +CONFIG_EL16=m +CONFIG_EL2=m +CONFIG_EL3=m +CONFIG_ELF_CORE=y +# CONFIG_EMBEDDED is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +CONFIG_EPOLL=y +# CONFIG_EQUALIZER is not set +CONFIG_EVENTFD=y +CONFIG_EXPERIMENTAL=y +CONFIG_EXPORTFS=m +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_FAIR_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_FAIR_USER_SCHED is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_FS=m +# CONFIG_FAULT_INJECTION is not set +# CONFIG_FDDI is not set +CONFIG_FIB_RULES=y +# CONFIG_FIREWIRE is not set +CONFIG_FIXED_MII_1000_FDX=y +# CONFIG_FIXED_MII_100_FDX is not set +# CONFIG_FIXED_MII_10_FDX is not set +CONFIG_FIXED_MII_AMNT=1 +CONFIG_FIXED_PHY=m +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_FORCED_INLINING=y +CONFIG_FS_POSIX_ACL=y +CONFIG_FUSION=y +CONFIG_FUSION_CTL=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_LOGGING=y +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_SAS=m +CONFIG_FUSION_SPI=m +CONFIG_FUTEX=y +CONFIG_FW_LOADER=y +CONFIG_GACT_PROB=y +# CONFIG_GAMEPORT is not set +CONFIG_GENERIC_ACL=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_TIME=y +CONFIG_GEN_RTC=y +CONFIG_GEN_RTC_X=y +CONFIG_GSC=y +CONFIG_GSC_DINO=y +CONFIG_GSC_LASI=y +CONFIG_GSC_WAX=y +# CONFIG_HAMRADIO is not set +CONFIG_HAPPYMEAL=m +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_HERMES=m +# CONFIG_HFSPLUS_FS is not set +# CONFIG_HFS_FS is not set +CONFIG_HIDRAW=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HID_FF is not set +CONFIG_HID_SUPPORT=y +# CONFIG_HIPPI is not set +CONFIG_HOTPLUG=y +# CONFIG_HOTPLUG_PCI is not set +CONFIG_HP100=m +# CONFIG_HPFS_FS is not set +CONFIG_HPPB=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_HW_CONSOLE=y +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_I2C is not set +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_BUS=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_PROC=m +CONFIG_I2O_SCSI=m +CONFIG_I82092=m +CONFIG_I82365=m +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +CONFIG_ICPLUS_PHY=m +CONFIG_IDE=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_IDE_ARM is not set +CONFIG_IDE_GENERIC=m +CONFIG_IDE_PROC_FS=y +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IEEE1394 is not set +CONFIG_IEEE80211=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_CRYPT_WEP=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_IFB=m +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_INET=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET_AH=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_INET_DIAG=y +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_LRO=m +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_TUNNEL=m +# CONFIG_INFINIBAND is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_INPUT=y +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_JOYSTICK is not set +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_POLLDEV=m +# CONFIG_INPUT_TOUCHSCREEN is not set +CONFIG_INSTRUMENTATION=y +CONFIG_IOMMU_CCIO=y +CONFIG_IOMMU_SBA=y +CONFIG_IOSAPIC=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IP1000=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +# CONFIG_IPMI_HANDLER is not set +CONFIG_IPV6=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPW2100=m +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2200=m +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_RADIOTAP=y +# CONFIG_IPX is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_DCCP=m +CONFIG_IP_DCCP_ACKVEC=y +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_IP_DCCP_TFRC_LIB=m +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_SCTP=m +# CONFIG_IP_VS is not set +# CONFIG_IRDA is not set +CONFIG_IRQ_PER_CPU=y +CONFIG_ISA=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISDN is not set +# CONFIG_IWLWIFI is not set +CONFIG_IXGBE=m +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_FS=m +# CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_JOLIET=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_KEYS=y +CONFIG_KMOD=y +# CONFIG_LAPB is not set +CONFIG_LASI_82596=m +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LIBCRC32C=m +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_CS=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_LIBERTAS_USB=m +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_LOCKD_V4=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LXT_PHY=m +CONFIG_MAC80211=m +# CONFIG_MAC80211_DEBUG is not set +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MACVLAN=m +CONFIG_MAGIC_SYSRQ=y +# CONFIG_MARKERS is not set +CONFIG_MARVELL_PHY=m +CONFIG_MD=y +CONFIG_MDIO_BITBANG=m +CONFIG_MD_FAULTY=m +CONFIG_MD_LINEAR=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_SAS=m +CONFIG_MII=m +# CONFIG_MINIX_FS is not set +CONFIG_MISC_DEVICES=y +# CONFIG_MLX4_CORE is not set +# CONFIG_MMC is not set +CONFIG_MMU=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MSDOS_FS=m +CONFIG_MSDOS_PARTITION=y +# CONFIG_MSS is not set +# CONFIG_MTD is not set +# CONFIG_NCP_FS is not set +CONFIG_NET=y +CONFIG_NETDEVICES=y +CONFIG_NETDEVICES_MULTIQUEUE=y +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +# CONFIG_NETLABEL is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NET_9P=m +# CONFIG_NET_9P_DEBUG is not set +CONFIG_NET_9P_FD=m +CONFIG_NET_ACT_GACT=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_CLS=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_IND=y +# CONFIG_NET_CLS_POLICE is not set +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_ETHERNET=y +# CONFIG_NET_FC is not set +CONFIG_NET_IPGRE=m +# CONFIG_NET_IPGRE_BROADCAST is not set +CONFIG_NET_IPIP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_NET_PCI=y +CONFIG_NET_PCMCIA=y +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_POCKET is not set +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_FIFO=y +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_RR=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_TULIP=y +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_RACAL=y +CONFIG_NET_VENDOR_SMC=y +CONFIG_NFSD=m +CONFIG_NFSD_TCP=y +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_TFTP=m +# CONFIG_NI52 is not set +# CONFIG_NIU is not set +CONFIG_NL80211=y +CONFIG_NLS=y +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_CODEPAGE_437=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m +# CONFIG_NORTEL_HERMES is not set +# CONFIG_OCFS2_FS is not set +CONFIG_OPROFILE=m +CONFIG_P54_COMMON=m +CONFIG_P54_PCI=m +CONFIG_P54_USB=m +# CONFIG_PA7100LC is not set +# CONFIG_PA7200 is not set +# CONFIG_PA7300LC is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_PARIDE is not set +CONFIG_PARISC=y +# CONFIG_PARISC_PAGE_SIZE_16KB is not set +CONFIG_PARISC_PAGE_SIZE_4KB=y +# CONFIG_PARISC_PAGE_SIZE_64KB is not set +CONFIG_PARPORT=m +# CONFIG_PARPORT_1284 is not set +CONFIG_PARPORT_AX88796=m +CONFIG_PARPORT_GSC=y +CONFIG_PARPORT_NOT_PC=y +CONFIG_PARPORT_PC=m +# CONFIG_PARPORT_PC_FIFO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_PC_SUPERIO is not set +# CONFIG_PARPORT_SERIAL is not set +# CONFIG_PARTITION_ADVANCED is not set +# CONFIG_PATA_ALI is not set +CONFIG_PATA_AMD=m +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +CONFIG_PATA_CS5520=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +# CONFIG_PATA_LEGACY is not set +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NETCELL=m +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +CONFIG_PATA_OLDPIIX=m +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PCMCIA=m +CONFIG_PATA_PDC2027X=m +# CONFIG_PATA_PDC_OLD is not set +CONFIG_PATA_QDI=m +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +# CONFIG_PATA_WINBOND_VLB is not set +CONFIG_PCCARD=m +CONFIG_PCCARD_NONSTATIC=m +CONFIG_PCI=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_HERMES is not set +CONFIG_PCI_LBA=y +CONFIG_PCI_LEGACY=y +CONFIG_PCMCIA=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_3C589=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_IOCTL=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_PD6729=m +CONFIG_PDA_POWER=m +CONFIG_PDC_ADMA=m +CONFIG_PDC_CHASSIS=y +CONFIG_PDC_CHASSIS_WARN=y +CONFIG_PDC_STABLE=y +CONFIG_PHANTOM=m +# CONFIG_PHONE is not set +CONFIG_PHYLIB=m +# CONFIG_PID_NS is not set +CONFIG_PLIP=m +CONFIG_PLIST=y +# CONFIG_PLX_HERMES is not set +# CONFIG_PNP is not set +CONFIG_POSIX_MQUEUE=y +CONFIG_POWER_SUPPLY=m +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PPDEV is not set +CONFIG_PPP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_PREEMPT is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTK=y +# CONFIG_PRISM54 is not set +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROFILING=y +# CONFIG_QNX4FS_FS is not set +CONFIG_QSEMI_PHY=m +# CONFIG_QUOTA is not set +# CONFIG_R3964 is not set +CONFIG_RADIO_ADAPTERS=y +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +CONFIG_RAID_ATTRS=m +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RELAY=y +CONFIG_RESOURCES_64BIT=y +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +# CONFIG_ROMFS_FS is not set +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT2X00=m +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RT2X00_LIB=m +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT73USB=m +CONFIG_RTL8187=m +CONFIG_RT_MUTEXES=y +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_RXKAD=m +# CONFIG_SAMPLES is not set +CONFIG_SATA_AHCI=m +CONFIG_SATA_INIC162X=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_SX4=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +# CONFIG_SCHEDSTATS is not set +CONFIG_SCHED_DEBUG=y +CONFIG_SCSI=y +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_ACARD is not set +CONFIG_SCSI_ADVANSYS=m +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC94XX=m +CONFIG_SCSI_ARCMSR=m +# CONFIG_SCSI_CONSTANTS is not set +CONFIG_SCSI_DC390T=m +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DEBUG is not set +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +CONFIG_SCSI_HPTIOP=m +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_IN2000 is not set +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_INITIO=m +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_IPS is not set +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_LASI700=m +# CONFIG_SCSI_LOGGING is not set +CONFIG_SCSI_LOWLEVEL=y +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_SCSI_LPFC=m +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_NCR53C406A is not set +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +CONFIG_SCSI_NETLINK=y +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PPA is not set +CONFIG_SCSI_PROC_FS=y +# CONFIG_SCSI_PSI240I is not set +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_QLOGIC_1280=m +# CONFIG_SCSI_QLOGIC_FAS is not set +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SCAN_ASYNC=y +# CONFIG_SCSI_SIM710 is not set +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCSI_SRP=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_STEX=m +# CONFIG_SCSI_SYM53C416 is not set +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +# CONFIG_SCSI_T128 is not set +CONFIG_SCSI_TGT=m +CONFIG_SCSI_WAIT_SCAN=m +CONFIG_SCSI_ZALON=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SECURITY=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +# CONFIG_SECURITY_APPARMOR_DISABLE is not set +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_SELINUX is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_GSC=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_PCI=y +# CONFIG_SERIAL_8250_RSA is not set +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_SGI_IOC4=m +CONFIG_SHMEM=y +CONFIG_SIGNALFD=y +# CONFIG_SK98LIN is not set +CONFIG_SLABINFO=y +CONFIG_SLHC=m +# CONFIG_SLOB is not set +CONFIG_SMB_FS=m +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +CONFIG_SMC9194=m +CONFIG_SMSC_PHY=m +# CONFIG_SOUND is not set +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SSB=m +CONFIG_SSB_DEBUG=y +CONFIG_SSB_DRIVER_PCICORE=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +CONFIG_SSB_POSSIBLE=y +CONFIG_STACK_GROWSUP=y +CONFIG_STANDALONE=y +CONFIG_SUNGEM=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_SUPERIO=y +CONFIG_SWAP=y +# CONFIG_SYN_COOKIES is not set +CONFIG_SYSCTL=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y +# CONFIG_TCG_TPM is not set +CONFIG_TCIC=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_MD5SIG=y +CONFIG_TEHUTI=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TIFM_7XX1=m +CONFIG_TIFM_CORE=m +CONFIG_TIGON3=m +# CONFIG_TINY_SHMEM is not set +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +# CONFIG_TMD_HERMES is not set +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_TR is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_TUN=m +CONFIG_TYPHOON=m +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_UIO=m +CONFIG_UIO_CIF=m +CONFIG_ULTRA=m +CONFIG_ULTRA32=m +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +CONFIG_USB=m +# CONFIG_USB_ACM is not set +CONFIG_USB_ADUTUX=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB_AUERSWALD is not set +CONFIG_USB_BERRY_CHARGE=m +# CONFIG_USB_CATC is not set +CONFIG_USB_CYPRESS_CY7C63=m +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_DABUSB=m +CONFIG_USB_DEBUG=y +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EMI26=m +CONFIG_USB_EMI62=m +# CONFIG_USB_ET61X251 is not set +CONFIG_USB_FTDI_ELAN=m +# CONFIG_USB_GADGET is not set +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_HIDINPUT_POWERBOOK=y +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_IDMOUSE is not set +CONFIG_USB_IOWARRIOR=m +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_KAWETH is not set +CONFIG_USB_KBD=m +# CONFIG_USB_KONICAWC is not set +# CONFIG_USB_LCD is not set +CONFIG_USB_LD=m +# CONFIG_USB_LED is not set +# CONFIG_USB_LEGOTOWER is not set +CONFIG_USB_LIBUSUAL=y +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USB_MON=y +CONFIG_USB_MOUSE=m +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_PEGASUS is not set +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_PWC is not set +# CONFIG_USB_QUICKCAM_MESSENGER is not set +CONFIG_USB_R8A66597_HCD=m +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SISUSBVGA is not set +CONFIG_USB_SL811_CS=m +CONFIG_USB_SL811_HCD=m +# CONFIG_USB_SN9C102 is not set +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_ALAUDA=y +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +CONFIG_USB_STORAGE_KARMA=y +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +CONFIG_USB_STORAGE_USBAT=y +# CONFIG_USB_STV680 is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_U132_HCD=m +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set +# CONFIG_USB_VICAM is not set +# CONFIG_USB_ZC0301 is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USER_NS is not set +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VERSION_SIGNATURE="Unofficial" +CONFIG_VETH=m +CONFIG_VFAT_FS=m +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_BWQCAM is not set +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_VIDEO_CQCAM is not set +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_STRADIS is not set +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +# CONFIG_VIDEO_VIVI is not set +CONFIG_VIRT_TO_BUS=y +CONFIG_VITESSE_PHY=m +CONFIG_VLAN_8021Q=m +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VORTEX=m +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_W1=m +CONFIG_W1_CON=y +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_THERM=m +# CONFIG_WAN is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_WATCHDOG is not set +CONFIG_WD80x3=m +# CONFIG_WINBOND_840 is not set +CONFIG_WIRELESS_EXT=y +CONFIG_WLAN_80211=y +# CONFIG_X25 is not set +CONFIG_XFRM=y +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_USER=m +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +# CONFIG_XFS_SECURITY is not set +CONFIG_XOR_BLOCKS=m +CONFIG_YENTA=m +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_ZLIB_DEFLATE=m +CONFIG_ZONE_DMA_FLAG=0 --- linux-2.6.24.orig/debian/config/hppa/config.hppa32 +++ linux-2.6.24/debian/config/hppa/config.hppa32 @@ -0,0 +1,386 @@ +# +# Config options for config.hppa32 automatically generated by splitconfig.pl +# +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_8129=y +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_9P_FS=m +CONFIG_AC3200=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_AGP=m +CONFIG_AIRO_CS=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_AMD8111_ETH=m +CONFIG_APRICOT=m +# CONFIG_ARLAN is not set +CONFIG_AT1700=m +CONFIG_ATL1=m +CONFIG_AUTOFS4_FS=m +CONFIG_AUTOFS_FS=m +CONFIG_B43_LEDS=y +CONFIG_B44=m +CONFIG_B44_PCI=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +CONFIG_BCM43XX_PIO=y +# CONFIG_BCM43XX_PIO_MODE is not set +CONFIG_BNX2=m +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_CPUSETS=y +CONFIG_CRAMFS=y +CONFIG_CRC16=m +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_DES=y +CONFIG_CS89x0=m +# CONFIG_DE2104X is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_RWLOCK is not set +CONFIG_DEPCA=m +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_DISPLAY_SUPPORT=m +CONFIG_DL2K=m +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_E2100=m +CONFIG_ECRYPT_FS=m +CONFIG_EEPRO100=m +CONFIG_EEXPRESS=m +CONFIG_EEXPRESS_PRO=m +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_EPIC100=m +CONFIG_ES3210=m +CONFIG_ETH16I=m +CONFIG_EWRK3=m +CONFIG_EXT2_FS=m +CONFIG_EXT3_FS=m +CONFIG_FB=y +# CONFIG_FB_3DFX is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_DDC is not set +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MATROX is not set +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_PM2 is not set +CONFIG_FB_PM3=m +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +CONFIG_FB_SM501=m +CONFIG_FB_STI=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +CONFIG_FB_TILEBLITTING=y +# CONFIG_FB_TRIDENT is not set +CONFIG_FB_UVESA=m +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +CONFIG_FEALNX=m +CONFIG_FIRMWARE_EDID=y +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FS_MBCACHE=m +CONFIG_FUSE_FS=m +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_GFS2_FS_LOCKING_NOLOCK=m +CONFIG_HAMACHI=m +CONFIG_HID=m +CONFIG_HIL_MLC=m +CONFIG_HOSTAP=m +CONFIG_HOSTAP_CS=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_PLX=m +CONFIG_HOTPLUG_CPU=y +CONFIG_HPLAN=m +CONFIG_HPLAN_PLUS=m +# CONFIG_HPUX is not set +CONFIG_HP_SDC=m +CONFIG_HP_SDC_RTC=m +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_HWMON_VID=m +CONFIG_HW_RANDOM=y +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MOUSE=y +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_TABLET=y +# CONFIG_INPUT_UINPUT is not set +CONFIG_INPUT_YEALINK=m +CONFIG_ISO9660_FS=m +CONFIG_IXGB=m +# CONFIG_IXGB_NAPI is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_ATKBD_HP_KEYCODES is not set +CONFIG_KEYBOARD_HIL=m +CONFIG_KEYBOARD_HIL_OLD=m +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_STOWAWAY=m +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +CONFIG_KS0108=m +CONFIG_KS0108_DELAY=2 +CONFIG_KS0108_PORT=0x378 +# CONFIG_LBD is not set +CONFIG_LCD_LTV350QV=m +CONFIG_LEDS_CLASS=m +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LNE390=m +CONFIG_LOCKD=y +CONFIG_LOCK_KERNEL=y +# CONFIG_LOGO is not set +CONFIG_LP486E=m +# CONFIG_LP_CONSOLE is not set +# CONFIG_LSF is not set +CONFIG_MAC80211_DEBUGFS=y +CONFIG_MAC80211_LEDS=y +CONFIG_MFD_SM501=m +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_HIL=m +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +CONFIG_MYRI10GE=m +CONFIG_NATSEMI=m +CONFIG_NE2000=m +CONFIG_NE2K_PCI=m +CONFIG_NE3210=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NETXEN_NIC=m +CONFIG_NET_ISA=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_NEW_LEDS=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_FS=y +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_ISO8859_15 is not set +CONFIG_NR_CPUS=32 +CONFIG_NS83820=m +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_FS=m +# CONFIG_NTFS_RW is not set +CONFIG_PA11=y +CONFIG_PA7000=y +# CONFIG_PA8X00 is not set +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_AXNET=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PDC_CONSOLE=y +CONFIG_PPPOE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PREEMPT_BKL=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_PRINTER=m +CONFIG_PRINTK_TIME=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_QLA3XXX=m +CONFIG_QUOTACTL=y +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +# CONFIG_RAW_DRIVER is not set +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_RFKILL_LEDS=y +CONFIG_ROOT_NFS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RT2X00_LIB_DEBUGFS is not set +CONFIG_RTC_CLASS=m +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_TEST=m +CONFIG_RTC_DRV_V3020=m +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=m +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +CONFIG_SC92031=m +# CONFIG_SCSI_AHA152X is not set +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_NSP32=m +CONFIG_SEEQ8005=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SERIAL_8250_ACCENT=m +CONFIG_SERIAL_8250_BOCA=m +CONFIG_SERIAL_8250_EXAR_ST16C554=m +CONFIG_SERIAL_8250_FOURPORT=m +CONFIG_SERIAL_8250_HUB6=m +CONFIG_SERIAL_8250_NR_UARTS=48 +# CONFIG_SERIAL_MUX is not set +CONFIG_SERIO=y +CONFIG_SERIO_GSCPS2=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_RAW=m +# CONFIG_SERIO_SERPORT is not set +CONFIG_SHAPER=m +CONFIG_SIS190=m +CONFIG_SIS900=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +# CONFIG_SLIP_MODE_SLIP6 is not set +CONFIG_SLIP_SMART=y +CONFIG_SLUB=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_DEBUG_ON is not set +CONFIG_SMP=y +CONFIG_SPI=y +CONFIG_SPI_AT25=m +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_MASTER=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_SPLIT_PTLOCK_CPUS=4096 +CONFIG_STI_CONSOLE=y +CONFIG_STOP_MACHINE=y +# CONFIG_STRIP is not set +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_SYNCLINK_CS=m +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_TIMER_STATS=y +CONFIG_TIME_LOW_RES=y +CONFIG_TLAN=m +CONFIG_TULIP=m +# CONFIG_TULIP_MMIO is not set +# CONFIG_UFS_FS is not set +CONFIG_ULI526X=m +CONFIG_UNUSED_SYMBOLS=y +# CONFIG_USB_STORAGE_ONETOUCH is not set +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_RHINE_NAPI=y +CONFIG_VIA_VELOCITY=m +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_VXFS_FS=m +# CONFIG_WAVELAN is not set +CONFIG_WLAN_PRE80211=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_QUOTA=y +CONFIG_YELLOWFIN=m +CONFIG_ZISOFS=y +CONFIG_ZLIB_INFLATE=y --- linux-2.6.24.orig/debian/config/hppa/config.hppa64 +++ linux-2.6.24/debian/config/hppa/config.hppa64 @@ -0,0 +1,173 @@ +# +# Config options for config.hppa64 automatically generated by splitconfig.pl +# +CONFIG_64BIT=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_9P_FS is not set +# CONFIG_AC3200 is not set +CONFIG_ACENIC_OMIT_TIGON_I=y +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AGP is not set +# CONFIG_AIRO_CS is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_APRICOT is not set +CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +# CONFIG_AT1700 is not set +# CONFIG_ATL1 is not set +CONFIG_AUTOFS4_FS=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_B44 is not set +# CONFIG_BCM43XX is not set +CONFIG_BLOCK_COMPAT=y +# CONFIG_BNX2 is not set +CONFIG_BROKEN_ON_SMP=y +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +CONFIG_COMPAT=y +# CONFIG_CRAMFS is not set +# CONFIG_CRC16 is not set +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_DES=m +# CONFIG_CS89x0 is not set +CONFIG_DE2104X=m +# CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEPCA is not set +# CONFIG_DETECT_SOFTLOCKUP is not set +CONFIG_DISCONTIGMEM=y +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_DL2K is not set +# CONFIG_DLM is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_EEPRO100 is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_EPIC100 is not set +# CONFIG_ES3210 is not set +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +# CONFIG_FB is not set +# CONFIG_FEALNX is not set +# CONFIG_FLATMEM_MANUAL is not set +# CONFIG_FORCEDETH is not set +CONFIG_FS_MBCACHE=y +# CONFIG_FUSE_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_HAMACHI is not set +CONFIG_HID=y +# CONFIG_HOSTAP is not set +# CONFIG_HWMON is not set +CONFIG_HW_RANDOM=m +CONFIG_I2O_EXT_ADAPTEC_DMA64=y +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_ISO9660_FS=y +# CONFIG_IXGB is not set +CONFIG_JBD=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y +# CONFIG_KS0108 is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LNE390 is not set +CONFIG_LOCKD=m +CONFIG_MAX_RAW_DEVS=256 +# CONFIG_MFD_SM501 is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_NEW_LEDS is not set +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_FS=m +# CONFIG_NI5010 is not set +CONFIG_NLS_ASCII=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NODES_SHIFT=3 +# CONFIG_NS83820 is not set +# CONFIG_NTFS_FS is not set +CONFIG_PA20=y +# CONFIG_PA7000 is not set +CONFIG_PA8X00=y +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_WL3501 is not set +# CONFIG_PCMCIA_XIRTULIP is not set +# CONFIG_PPPOE is not set +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_MPPE is not set +# CONFIG_PPP_MULTILINK is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREFETCH=y +# CONFIG_PRINTER is not set +# CONFIG_PRINTK_TIME is not set +# CONFIG_QLA3XXX is not set +# CONFIG_R8169 is not set +CONFIG_RAW_DRIVER=y +# CONFIG_REISERFS_FS is not set +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_RTC_CLASS is not set +# CONFIG_S2IO is not set +# CONFIG_SC92031 is not set +# CONFIG_SERIAL_8250_ACCENT is not set +# CONFIG_SERIAL_8250_BOCA is not set +# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set +# CONFIG_SERIAL_8250_FOURPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_8250_NR_UARTS=17 +CONFIG_SERIAL_MUX=y +CONFIG_SERIAL_MUX_CONSOLE=y +# CONFIG_SERIO is not set +# CONFIG_SHAPER is not set +# CONFIG_SIS190 is not set +# CONFIG_SIS900 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +CONFIG_SLAB=y +# CONFIG_SLIP is not set +# CONFIG_SLUB is not set +# CONFIG_SMP is not set +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_STI_CONSOLE is not set +# CONFIG_SUNDANCE is not set +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +# CONFIG_SYNCLINK_CS is not set +# CONFIG_TIMER_STATS is not set +CONFIG_TULIP=y +CONFIG_TULIP_MMIO=y +# CONFIG_UFS_DEBUG is not set +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_ULI526X is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_VXFS_FS is not set +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_ZISOFS is not set +CONFIG_ZLIB_INFLATE=m --- linux-2.6.24.orig/debian/config/sparc/config.sparc64 +++ linux-2.6.24/debian/config/sparc/config.sparc64 @@ -0,0 +1,10 @@ +# +# Config options for config.sparc64 automatically generated by splitconfig.pl +# +CONFIG_BROKEN_ON_SMP=y +CONFIG_ISTALLION=m +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_RIO is not set +CONFIG_RISCOM8=m +# CONFIG_SMP is not set +CONFIG_STALLION=m --- linux-2.6.24.orig/debian/config/sparc/config +++ linux-2.6.24/debian/config/sparc/config @@ -0,0 +1,2120 @@ +# +# Common config options automatically generated by splitconfig.pl +# +CONFIG_64BIT=y +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_8129=y +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_9P_FS=m +CONFIG_AC97_BUS=m +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_ACORN_PARTITION is not set +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADAPTEC_STARFIRE_NAPI=y +# CONFIG_ADFS_FS is not set +CONFIG_ADM8211=m +CONFIG_AFFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_AFS_FS=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC94XX_DEBUG is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_AMIGA_PARTITION is not set +CONFIG_ANON_INODES=y +CONFIG_APPLICOM=m +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_ARCH_NO_VIRT_TO_BUS=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_ARCNET is not set +CONFIG_ARPD=y +CONFIG_ASK_IP_FIB_HASH=y +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ATA=m +CONFIG_ATALK=m +# CONFIG_ATARI_PARTITION is not set +CONFIG_ATA_GENERIC=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_ATA_PIIX=m +CONFIG_ATL1=m +# CONFIG_ATM is not set +CONFIG_ATMEL=m +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_ARCH=y +CONFIG_AUDIT_TREE=y +CONFIG_AUTOFS4_FS=m +CONFIG_AUTOFS_FS=m +CONFIG_AUXDISPLAY=y +CONFIG_B43=m +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PIO=y +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_B43_DEBUG=y +CONFIG_B43_DMA=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +CONFIG_B43_LEDS=y +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_PCI_AUTOSELECT=y +CONFIG_B43_PIO=y +# CONFIG_B43_PIO_MODE is not set +CONFIG_B43_RFKILL=y +# CONFIG_B44 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +CONFIG_BATTERY_DS2760=m +CONFIG_BBC_I2C=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +CONFIG_BCM43XX_PIO=y +# CONFIG_BCM43XX_PIO_MODE is not set +# CONFIG_BEFS_DEBUG is not set +CONFIG_BEFS_FS=m +CONFIG_BFS_FS=m +# CONFIG_BINFMT_AOUT32 is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_ELF32=y +CONFIG_BINFMT_MISC=m +CONFIG_BITREVERSE=y +# CONFIG_BLK_CPQ_CISS_DA is not set +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_3W_XXXX_RAID=m +# CONFIG_BLK_DEV_AEC62XX is not set +CONFIG_BLK_DEV_ALI15X3=m +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_BSG is not set +CONFIG_BLK_DEV_CMD64X=m +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_CS5520 is not set +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_CY82C693=m +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_DM=m +CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_IDE=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDEDISK=m +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_BLK_DEV_IDESCSI is not set +CONFIG_BLK_DEV_IDETAPE=m +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_MD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_NS87415=m +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +CONFIG_BLK_DEV_PDC202XX_OLD=m +# CONFIG_BLK_DEV_PIIX is not set +CONFIG_BLK_DEV_PLATFORM=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_SD=m +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +# CONFIG_BLK_DEV_SVWKS is not set +CONFIG_BLK_DEV_SX8=m +CONFIG_BLK_DEV_TC86C001=m +# CONFIG_BLK_DEV_TRIFLEX is not set +CONFIG_BLK_DEV_TRM290=m +# CONFIG_BLK_DEV_UB is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLOCK=y +CONFIG_BLOCK_COMPAT=y +CONFIG_BNX2=m +CONFIG_BONDING=m +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BRIDGE=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_NETFILTER=y +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BROADCOM_PHY=m +# CONFIG_BSD_DISKLABEL is not set +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +# CONFIG_BT is not set +CONFIG_BUG=y +CONFIG_CASSINI=m +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_CFG80211=m +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_NS=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_CHR_DEV_OSST=m +# CONFIG_CHR_DEV_SCH is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_ST=m +CONFIG_CICADA_PHY=m +CONFIG_CIFS=m +# CONFIG_CIFS_DEBUG2 is not set +CONFIG_CIFS_EXPERIMENTAL=y +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_WEAK_PW_HASH=y +# CONFIG_CIFS_XATTR is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CMDLINE_BOOL is not set +CONFIG_CODA_FS=m +# CONFIG_CODA_FS_OLD_API is not set +CONFIG_COMPAT=y +CONFIG_COMPUTONE=m +CONFIG_CONFIGFS_FS=m +CONFIG_CONNECTOR=m +# CONFIG_CPU_FREQ is not set +CONFIG_CRAMFS=y +CONFIG_CRC16=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_CRC_CCITT=m +CONFIG_CRC_ITU_T=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TEA=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_CYCLADES=m +# CONFIG_CYZ_INTR is not set +CONFIG_DAB=y +CONFIG_DAVICOM_PHY=m +# CONFIG_DE2104X is not set +# CONFIG_DE4X5 is not set +CONFIG_DE600=m +CONFIG_DE620=m +# CONFIG_DEBUG_BOOTMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_DCFLUSH is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +CONFIG_DECNET=m +CONFIG_DECNET_NF_GRABULATOR=m +CONFIG_DECNET_ROUTER=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_BIC is not set +CONFIG_DEFAULT_CFQ=y +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_HTCP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_RELATIME=y +CONFIG_DEFAULT_RELATIME_VAL=1 +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +# CONFIG_DEFXX is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_DEVPORT=y +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DEV_KMEM is not set +CONFIG_DIGIEPCA=m +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_DISPLAY7SEG=m +CONFIG_DISPLAY_SUPPORT=m +CONFIG_DL2K=m +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +# CONFIG_DM9102 is not set +CONFIG_DM_CRYPT=m +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_MIRROR=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m +CONFIG_DM_MULTIPATH_HP=m +CONFIG_DM_MULTIPATH_RDAC=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_UEVENT=y +CONFIG_DM_ZERO=m +CONFIG_DNOTIFY=y +CONFIG_DRM=y +CONFIG_DRM_MGA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_SAVAGE=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_VIA=m +# CONFIG_DRM_VIA_CHROME9 is not set +CONFIG_DS1682=m +CONFIG_DUMMY=m +CONFIG_DUMMY_CONSOLE=y +# CONFIG_DVB_CORE is not set +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E1000_NAPI=y +# CONFIG_ECONET is not set +CONFIG_ECRYPT_FS=m +# CONFIG_EEPRO100 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EFI_PARTITION is not set +CONFIG_EFS_FS=m +CONFIG_ELF_CORE=y +# CONFIG_EMBEDDED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +CONFIG_ENVCTRL=m +CONFIG_EPIC100=m +CONFIG_EPOLL=y +CONFIG_EQUALIZER=m +CONFIG_EVENTFD=y +CONFIG_EXPERIMENTAL=y +CONFIG_EXPORTFS=m +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_POSIX_ACL=y +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_POSIX_ACL=y +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_FAIR_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_FAIR_USER_SCHED is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_FS=m +# CONFIG_FAULT_INJECTION is not set +CONFIG_FB=y +# CONFIG_FB_3DFX is not set +CONFIG_FB_ARK=m +# CONFIG_FB_ASILIANT is not set +CONFIG_FB_ATY=y +CONFIG_FB_ATY128=y +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_BACKLIGHT=y +# CONFIG_FB_BW2 is not set +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_CG14 is not set +# CONFIG_FB_CG3 is not set +CONFIG_FB_CG6=y +# CONFIG_FB_CIRRUS is not set +CONFIG_FB_DDC=y +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_FFB=y +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_LEO is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MATROX is not set +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_BACKLIGHT=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_I2C=y +# CONFIG_FB_P9100 is not set +CONFIG_FB_PM2=y +# CONFIG_FB_PM2_FIFO_DISCONNECT is not set +CONFIG_FB_PM3=m +CONFIG_FB_RADEON=y +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_RADEON_I2C=y +# CONFIG_FB_RIVA is not set +CONFIG_FB_S1D13XXX=m +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SBUS=y +# CONFIG_FB_SIS is not set +CONFIG_FB_SM501=m +CONFIG_FB_SVGALIB=m +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_TCX is not set +CONFIG_FB_TILEBLITTING=y +# CONFIG_FB_TRIDENT is not set +CONFIG_FB_UVESA=m +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_VOODOO1 is not set +CONFIG_FB_VT8623=m +CONFIG_FB_XVR2500=y +CONFIG_FB_XVR500=y +CONFIG_FDDI=y +CONFIG_FEALNX=m +CONFIG_FIB_RULES=y +# CONFIG_FIREWIRE is not set +CONFIG_FIRMWARE_EDID=y +CONFIG_FIXED_MII_1000_FDX=y +# CONFIG_FIXED_MII_100_FDX is not set +# CONFIG_FIXED_MII_10_FDX is not set +CONFIG_FIXED_MII_AMNT=1 +CONFIG_FIXED_PHY=m +# CONFIG_FLATMEM_MANUAL is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +# CONFIG_FONT_SUN12x22 is not set +CONFIG_FONT_SUN8x16=y +# CONFIG_FORCEDETH is not set +# CONFIG_FORCED_INLINING is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FS_MBCACHE=m +CONFIG_FS_POSIX_ACL=y +CONFIG_FUSE_FS=m +CONFIG_FUSION=y +CONFIG_FUSION_CTL=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y +CONFIG_FUSION_MAX_SGE=40 +CONFIG_FUSION_SAS=m +CONFIG_FUSION_SPI=m +CONFIG_FUTEX=y +CONFIG_FW_LOADER=y +CONFIG_GACT_PROB=y +# CONFIG_GAMEPORT is not set +CONFIG_GENERIC_ACL=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_TIME=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_GFS2_FS_LOCKING_NOLOCK=m +# CONFIG_HAMACHI is not set +# CONFIG_HAMRADIO is not set +CONFIG_HAPPYMEAL=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAVE_MEMORY_PRESENT=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_HERMES=m +CONFIG_HFSPLUS_FS=m +CONFIG_HFS_FS=m +CONFIG_HID=m +CONFIG_HIDRAW=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HID_FF is not set +CONFIG_HID_SUPPORT=y +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_HIPPI is not set +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_PLX=m +CONFIG_HOTPLUG=y +# CONFIG_HP100 is not set +CONFIG_HPFS_FS=m +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_HUGETLB_PAGE_SIZE_4MB=y +# CONFIG_HUGETLB_PAGE_SIZE_512K is not set +# CONFIG_HUGETLB_PAGE_SIZE_64K is not set +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_HWMON_VID=m +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +CONFIG_I2C_ALGOPCA=m +CONFIG_I2C_ALGOPCF=m +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_NFORCE2 is not set +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PIIX4=m +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +CONFIG_I2C_SIMTEC=m +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +CONFIG_I2C_STUB=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_TINY_USB=m +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_BUS=m +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_EXT_ADAPTEC_DMA64=y +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_PROC=m +CONFIG_I2O_SCSI=m +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +CONFIG_ICPLUS_PHY=m +CONFIG_IDE=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_IDE_ARM is not set +CONFIG_IDE_GENERIC=m +CONFIG_IDE_PROC_FS=y +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IEEE1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_OHCI1394=m +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE80211=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_CRYPT_WEP=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_IFB=m +# CONFIG_IKCONFIG is not set +CONFIG_INET=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET_AH=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_INET_DIAG=y +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_LRO=m +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_INPUT=y +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +# CONFIG_INPUT_EVBUG is not set +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_FF_MEMLESS=m +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_JOYSTICK is not set +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MOUSE=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_POLLDEV=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_SPARCSPKR=y +CONFIG_INPUT_TABLET=y +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_UINPUT is not set +CONFIG_INPUT_YEALINK=m +CONFIG_INSTRUMENTATION=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IP1000=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_POWEROFF is not set +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPV6=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPW2100=m +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2200=m +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_DCCP=m +CONFIG_IP_DCCP_ACKVEC=y +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_IP_DCCP_TFRC_LIB=m +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_RARP=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_SCTP=m +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_TAB_BITS=12 +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_WRR=m +# CONFIG_IRDA is not set +CONFIG_ISCSI_TCP=m +# CONFIG_ISDN is not set +# CONFIG_ISI is not set +CONFIG_ISO9660_FS=m +# CONFIG_IWLWIFI is not set +CONFIG_IXGB=m +CONFIG_IXGBE=m +CONFIG_IXGB_NAPI=y +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +# CONFIG_JFS_FS is not set +CONFIG_JOLIET=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_KARMA_PARTITION=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_LKKBD=m +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_SUNKBD=y +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +CONFIG_KMOD=y +CONFIG_KPROBES=y +CONFIG_KS0108=m +CONFIG_KS0108_DELAY=2 +CONFIG_KS0108_PORT=0x378 +# CONFIG_LAPB is not set +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +# CONFIG_LDM_PARTITION is not set +CONFIG_LEDS_CLASS=m +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LIBCRC32C=m +CONFIG_LIBERTAS=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_USB=m +# CONFIG_LKDTM is not set +CONFIG_LLC=m +CONFIG_LLC2=m +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_LOCKD=m +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +# CONFIG_LOCK_STAT is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_LP_CONSOLE is not set +CONFIG_LSM_MMAP_MIN_ADDR=0 +CONFIG_LXT_PHY=m +CONFIG_MAC80211=m +# CONFIG_MAC80211_DEBUG is not set +CONFIG_MAC80211_DEBUGFS=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MACVLAN=m +# CONFIG_MAC_PARTITION is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_MARKERS is not set +CONFIG_MARVELL_PHY=m +CONFIG_MAX_RAW_DEVS=256 +CONFIG_MD=y +CONFIG_MDIO_BITBANG=m +CONFIG_MD_FAULTY=m +CONFIG_MD_LINEAR=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_SAS=m +CONFIG_MFD_SM501=m +CONFIG_MII=m +CONFIG_MINIX_FS=m +# CONFIG_MINIX_SUBPARTITION is not set +CONFIG_MISC_DEVICES=y +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_MLX4_INFINIBAND=m +CONFIG_MMC=m +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_SDHCI=m +CONFIG_MMC_SPI=m +CONFIG_MMC_TIFM_SD=m +# CONFIG_MMC_UNSAFE_RESUME is not set +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_TRACKPOINT=y +CONFIG_MOUSE_SERIAL=y +# CONFIG_MOUSE_VSXXXAA is not set +CONFIG_MOXA_INTELLIO=m +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +CONFIG_MSDOS_FS=m +CONFIG_MSDOS_PARTITION=y +CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin" +CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin" +CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin" +CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin" +# CONFIG_MSS is not set +# CONFIG_MTD is not set +CONFIG_MYRI10GE=m +CONFIG_MYRI_SBUS=m +CONFIG_NATSEMI=m +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +CONFIG_NCPFS_NFS_NS=y +# CONFIG_NCPFS_NLS is not set +CONFIG_NCPFS_OS2_NS=y +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_STRONG is not set +CONFIG_NCP_FS=m +CONFIG_NE2K_PCI=m +CONFIG_NET=y +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETDEVICES=y +CONFIG_NETDEVICES_MULTIQUEUE=y +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +# CONFIG_NETLABEL is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NETXEN_NIC=m +CONFIG_NET_9P=m +# CONFIG_NET_9P_DEBUG is not set +CONFIG_NET_9P_FD=m +CONFIG_NET_ACT_GACT=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_CLS=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_FW=m +# CONFIG_NET_CLS_IND is not set +# CONFIG_NET_CLS_POLICE is not set +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_DCCPPROBE=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_ETHERNET=y +CONFIG_NET_FC=y +# CONFIG_NET_IPGRE is not set +CONFIG_NET_IPIP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_NET_PCI=y +# CONFIG_NET_PKTGEN is not set +CONFIG_NET_POCKET=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_FIFO=y +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_RR=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_TCPPROBE=m +CONFIG_NET_TULIP=y +CONFIG_NET_VENDOR_3COM=y +CONFIG_NEW_LEDS=y +CONFIG_NFSD=m +CONFIG_NFSD_TCP=y +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NIU=m +CONFIG_NL80211=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +# CONFIG_NORTEL_HERMES is not set +CONFIG_NO_HZ=y +CONFIG_NR_QUICK=1 +CONFIG_NS83820=m +# CONFIG_NTFS_FS is not set +CONFIG_N_HDLC=m +CONFIG_OBP_FLASH=m +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_OCFS2_DEBUG_MASKLOG=y +CONFIG_OCFS2_FS=m +CONFIG_OF=y +CONFIG_OF_DEVICE=y +# CONFIG_OSF_PARTITION is not set +CONFIG_P54_COMMON=m +CONFIG_P54_PCI=m +CONFIG_P54_USB=m +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_PARIDE is not set +CONFIG_PARPORT=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_AX88796=m +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_NOT_PC=y +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_SUNBPP=m +CONFIG_PARTITION_ADVANCED=y +# CONFIG_PATA_ALI is not set +CONFIG_PATA_AMD=m +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD64X is not set +CONFIG_PATA_CS5520=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NETCELL=m +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +CONFIG_PATA_OLDPIIX=m +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PDC2027X=m +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +CONFIG_PCI=y +CONFIG_PCI_ATMEL=m +# CONFIG_PCI_DEBUG is not set +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_HERMES is not set +CONFIG_PCI_LEGACY=y +# CONFIG_PCI_MSI is not set +CONFIG_PCI_SYSCALL=y +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_PDA_POWER=m +# CONFIG_PDC202XX_BURST is not set +CONFIG_PDC_ADMA=m +CONFIG_PHANTOM=m +# CONFIG_PHONE is not set +CONFIG_PHYLIB=m +# CONFIG_PID_NS is not set +CONFIG_PLIP=m +CONFIG_PLIST=y +# CONFIG_PLX_HERMES is not set +CONFIG_POSIX_MQUEUE=y +CONFIG_POWER_SUPPLY=m +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PPDEV=m +CONFIG_PPP=m +CONFIG_PPPOE=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_SYNC_TTY=m +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTER=m +CONFIG_PRINTK=y +CONFIG_PRINTK_TIME=y +CONFIG_PRINT_QUOTA_WARNING=y +# CONFIG_PRISM54 is not set +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +# CONFIG_PROFILING is not set +CONFIG_PROM_CONSOLE=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=m +CONFIG_QLA3XXX=m +# CONFIG_QNX4FS_FS is not set +CONFIG_QSEMI_PHY=m +CONFIG_QUICKLIST=y +CONFIG_QUOTA=y +CONFIG_QUOTACTL=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_R3964=m +# CONFIG_R8169 is not set +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RAID_ATTRS=m +CONFIG_RAW_DRIVER=m +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_FS=m +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_REISERFS_FS_XATTR=y +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_RELAY=y +CONFIG_RESOURCES_64BIT=y +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +CONFIG_ROCKETPORT=m +CONFIG_ROMFS_FS=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT2X00=m +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RT2X00_LIB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT73USB=m +CONFIG_RTC_CLASS=m +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_TEST=m +CONFIG_RTC_DRV_V3020=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=m +CONFIG_RTL8187=m +CONFIG_RT_MUTEXES=y +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_RXKAD=m +CONFIG_S2IO=m +CONFIG_S2IO_NAPI=y +# CONFIG_SAMPLES is not set +CONFIG_SATA_AHCI=m +CONFIG_SATA_INIC162X=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_SX4=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SBUS=y +CONFIG_SBUSCHAR=y +CONFIG_SC92031=m +# CONFIG_SCHEDSTATS is not set +CONFIG_SCHED_DEBUG=y +CONFIG_SCSI=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AIC79XX=m +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC94XX=m +CONFIG_SCSI_ARCMSR=m +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_DC390T is not set +CONFIG_SCSI_DC395x=m +# CONFIG_SCSI_DEBUG is not set +CONFIG_SCSI_DMA=y +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +# CONFIG_SCSI_FUTURE_DOMAIN is not set +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_IMM=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_DUMP is not set +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPS is not set +CONFIG_SCSI_ISCSI_ATTRS=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +# CONFIG_SCSI_LOGGING is not set +CONFIG_SCSI_LOWLEVEL=y +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PPA=m +CONFIG_SCSI_PROC_FS=y +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_QLOGICPTI=m +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SUNESP=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_TGT=m +CONFIG_SCSI_WAIT_SCAN=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SDIO_UART=m +CONFIG_SECCOMP=y +CONFIG_SECURITY=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +# CONFIG_SECURITY_APPARMOR_DISABLE is not set +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_ROOTPLUG is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_DISABLE=y +# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SENSORS_AD7418=m +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +# CONFIG_SENSORS_ADM1031 is not set +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_EEPROM is not set +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +# CONFIG_SENSORS_GL518SM is not set +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_IBMPEX=m +# CONFIG_SENSORS_IT87 is not set +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +CONFIG_SENSORS_LM87=m +# CONFIG_SENSORS_LM90 is not set +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +# CONFIG_SENSORS_MAX1619 is not set +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_PCA9539=m +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_TSL2550=m +# CONFIG_SENSORS_VIA686A is not set +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83627EHF=m +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83781D is not set +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +# CONFIG_SENSORS_W83L785TS is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_SERIAL_SUNCORE=y +CONFIG_SERIAL_SUNHV=y +CONFIG_SERIAL_SUNSAB=y +CONFIG_SERIAL_SUNSAB_CONSOLE=y +CONFIG_SERIAL_SUNSU=y +CONFIG_SERIAL_SUNSU_CONSOLE=y +CONFIG_SERIAL_SUNZILOG=y +CONFIG_SERIAL_SUNZILOG_CONSOLE=y +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_PARKBD is not set +CONFIG_SERIO_PCIPS2=y +CONFIG_SERIO_RAW=m +CONFIG_SERIO_SERPORT=m +CONFIG_SGI_IOC4=m +# CONFIG_SGI_PARTITION is not set +CONFIG_SHAPER=m +CONFIG_SHMEM=y +CONFIG_SIGNALFD=y +CONFIG_SIS190=m +CONFIG_SIS900=m +# CONFIG_SK98LIN is not set +CONFIG_SKFP=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +CONFIG_SLHC=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +# CONFIG_SLIP_MODE_SLIP6 is not set +CONFIG_SLIP_SMART=y +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_DEBUG_ON is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_SMSC_PHY=m +CONFIG_SND=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 +CONFIG_SND_AD1889=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ALS300=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_BT87X_OVERCLOCK=y +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_DARLA20=m +CONFIG_SND_DARLA24=m +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DUMMY=m +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_ECHO3G=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_GINA20=m +CONFIG_SND_GINA24=m +CONFIG_SND_HDA_CODEC_ANALOG=y +CONFIG_SND_HDA_CODEC_ATIHDMI=y +CONFIG_SND_HDA_CODEC_CMEDIA=y +CONFIG_SND_HDA_CODEC_CONEXANT=y +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_CODEC_SI3054=y +CONFIG_SND_HDA_CODEC_SIGMATEL=y +CONFIG_SND_HDA_CODEC_VIA=y +CONFIG_SND_HDA_GENERIC=y +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_POWER_SAVE=y +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_KORG1212_FIRMWARE_IN_KERNEL=y +CONFIG_SND_LAYLA20=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MAESTRO3_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MIA=m +CONFIG_SND_MIXART=m +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_MONA=m +CONFIG_SND_MPU401=m +CONFIG_SND_MPU401_UART=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_NM256=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_PCM=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_PCXHR=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_SOC=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_SUN_AMD7930=m +CONFIG_SND_SUN_CS4231=m +CONFIG_SND_SUN_DBRI=m +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_TIMER=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_VX222=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y +CONFIG_SOLARIS_EMUL=m +# CONFIG_SOLARIS_X86_PARTITION is not set +CONFIG_SOUND=m +CONFIG_SOUND_MSNDCLAS=m +CONFIG_SOUND_MSNDPIN=m +CONFIG_SOUND_PRIME=m +CONFIG_SOUND_TRIDENT=m +CONFIG_SPARC=y +CONFIG_SPARC32_COMPAT=y +CONFIG_SPARC64=y +# CONFIG_SPARC64_PAGE_SIZE_4MB is not set +# CONFIG_SPARC64_PAGE_SIZE_512KB is not set +# CONFIG_SPARC64_PAGE_SIZE_64KB is not set +CONFIG_SPARC64_PAGE_SIZE_8KB=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_MANUAL=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +# CONFIG_SPECIALIX is not set +CONFIG_SPI=y +CONFIG_SPI_AT25=m +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_MASTER=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SSB=m +CONFIG_SSB_DEBUG=y +CONFIG_SSB_DRIVER_PCICORE=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_POSSIBLE=y +CONFIG_STACKTRACE_SUPPORT=y +# CONFIG_STACK_DEBUG is not set +CONFIG_STALDRV=y +CONFIG_STANDALONE=y +CONFIG_STRIP=m +CONFIG_SUNBMAC=m +CONFIG_SUNDANCE=m +CONFIG_SUNDANCE_MMIO=y +CONFIG_SUNGEM=y +CONFIG_SUNLANCE=m +CONFIG_SUNQE=m +CONFIG_SUNRPC=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_SUNVDC=m +CONFIG_SUNVNET=m +CONFIG_SUN_AUXIO=y +# CONFIG_SUN_BPP is not set +CONFIG_SUN_IO=y +CONFIG_SUN_LDOMS=y +CONFIG_SUN_OPENPROMFS=m +CONFIG_SUN_OPENPROMIO=y +CONFIG_SUN_PARTITION=y +CONFIG_SWAP=y +CONFIG_SX=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_GT=m +CONFIG_SYN_COOKIES=y +CONFIG_SYSCTL=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_SYSV68_PARTITION=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_SYSV_FS=m +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y +CONFIG_TCG_ATMEL=m +CONFIG_TCG_TPM=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_MD5SIG=y +CONFIG_TEHUTI=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TICK_ONESHOT=y +CONFIG_TIFM_7XX1=m +CONFIG_TIFM_CORE=m +CONFIG_TIGON3=m +CONFIG_TIMER_STATS=y +# CONFIG_TINY_SHMEM is not set +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +# CONFIG_TMD_HERMES is not set +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_TR is not set +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TULIP=m +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_NAPI=y +CONFIG_TULIP_NAPI_HW_MITIGATION=y +CONFIG_TUN=m +# CONFIG_TUNER_3036 is not set +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_SIMPLE=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TYPHOON=m +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_DEBUG is not set +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +CONFIG_UID16=y +CONFIG_UIO=m +CONFIG_UIO_CIF=m +CONFIG_ULI526X=m +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_UNUSED_SYMBOLS=y +CONFIG_USB=y +# CONFIG_USB_ACM is not set +CONFIG_USB_ADUTUX=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_AUERSWALD is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_CATC=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_DABUSB=m +# CONFIG_USB_DEBUG is not set +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_DSBR=m +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EMI26=m +CONFIG_USB_EMI62=m +CONFIG_USB_EPSON2888=y +CONFIG_USB_ET61X251=m +CONFIG_USB_FTDI_ELAN=m +# CONFIG_USB_GADGET is not set +CONFIG_USB_HID=m +# CONFIG_USB_HIDDEV is not set +CONFIG_USB_HIDINPUT_POWERBOOK=y +# CONFIG_USB_IBMCAM is not set +CONFIG_USB_IDMOUSE=m +CONFIG_USB_IOWARRIOR=m +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_KAWETH=m +CONFIG_USB_KBD=m +CONFIG_USB_KC2190=y +# CONFIG_USB_KONICAWC is not set +CONFIG_USB_LCD=m +CONFIG_USB_LD=m +CONFIG_USB_LED=m +# CONFIG_USB_LEGOTOWER is not set +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_MON=y +CONFIG_USB_MOUSE=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_RNDIS_HOST=m +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OV511 is not set +CONFIG_USB_PEGASUS=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +# CONFIG_USB_PHIDGETSERVO is not set +CONFIG_USB_PRINTER=m +# CONFIG_USB_PWC is not set +# CONFIG_USB_QUICKCAM_MESSENGER is not set +CONFIG_USB_R8A66597_HCD=m +CONFIG_USB_RIO500=m +CONFIG_USB_RTL8150=m +# CONFIG_USB_SE401 is not set +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_AIRCABLE is not set +CONFIG_USB_SERIAL_AIRPRIME=m +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_CP2101 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_DEBUG is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_GARMIN is not set +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_OMNINET is not set +CONFIG_USB_SERIAL_OPTION=m +# CONFIG_USB_SERIAL_OTI6858 is not set +CONFIG_USB_SERIAL_PL2303=m +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SN9C102=m +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_ALAUDA=y +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +# CONFIG_USB_STORAGE_JUMPSHOT is not set +CONFIG_USB_STORAGE_KARMA=y +# CONFIG_USB_STORAGE_ONETOUCH is not set +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_USBAT=y +# CONFIG_USB_STV680 is not set +CONFIG_USB_SUPPORT=y +# CONFIG_USB_TEST is not set +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_USBNET=m +# CONFIG_USB_USS720 is not set +# CONFIG_USB_VICAM is not set +# CONFIG_USB_W9968CF is not set +CONFIG_USB_ZC0301=m +CONFIG_USB_ZD1201=m +CONFIG_USB_ZR364XX=m +# CONFIG_USER_NS is not set +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VERSION_SIGNATURE="Unofficial" +CONFIG_VETH=m +CONFIG_VFAT_FS=m +CONFIG_VGASTATE=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_RHINE_NAPI=y +CONFIG_VIA_VELOCITY=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_GEN=m +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_BWQCAM is not set +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_VIDEO_CQCAM is not set +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_CX25840=m +# CONFIG_VIDEO_CX88 is not set +CONFIG_VIDEO_DEV=m +# CONFIG_VIDEO_DPC is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_IR_I2C=m +# CONFIG_VIDEO_IVTV is not set +# CONFIG_VIDEO_KS0127 is not set +CONFIG_VIDEO_MSP3400=m +# CONFIG_VIDEO_MXB is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_VIDEO_OV7670=m +# CONFIG_VIDEO_OVCAMCHIP is not set +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_29XXX=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_SAA5246A=m +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA7111 is not set +# CONFIG_VIDEO_SAA7114 is not set +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_OSS=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_SAA7191 is not set +CONFIG_VIDEO_TCM825X=m +# CONFIG_VIDEO_TDA7432 is not set +CONFIG_VIDEO_TDA9840=m +# CONFIG_VIDEO_TDA9875 is not set +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +# CONFIG_VIDEO_TVAUDIO is not set +CONFIG_VIDEO_TVEEPROM=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_VP27SMPX=m +# CONFIG_VIDEO_VPX3220 is not set +# CONFIG_VIDEO_W9966 is not set +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_WM8775=m +CONFIG_VITESSE_PHY=m +CONFIG_VLAN_8021Q=m +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VORTEX=m +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_VXFS_FS is not set +CONFIG_W1=m +CONFIG_W1_CON=y +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_THERM=m +# CONFIG_WAN is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_WATCHDOG is not set +# CONFIG_WDC_ALI15X3 is not set +CONFIG_WINBOND_840=m +CONFIG_WIRELESS_EXT=y +CONFIG_WLAN_80211=y +CONFIG_WLAN_PRE80211=y +# CONFIG_X25 is not set +CONFIG_XFRM=y +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_USER=m +CONFIG_XFS_FS=m +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_SECURITY is not set +CONFIG_XOR_BLOCKS=m +CONFIG_YELLOWFIN=m +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_ZISOFS is not set +CONFIG_ZLIB_DEFLATE=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZONE_DMA_FLAG=0 --- linux-2.6.24.orig/debian/config/sparc/config.sparc64-smp +++ linux-2.6.24/debian/config/sparc/config.sparc64-smp @@ -0,0 +1,16 @@ +# +# Config options for config.sparc64-smp automatically generated by splitconfig.pl +# +CONFIG_CPUSETS=y +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCK_KERNEL=y +CONFIG_NR_CPUS=256 +CONFIG_PATA_CMD640_PCI=m +# CONFIG_PREEMPT_BKL is not set +CONFIG_PROC_PID_CPUSET=y +CONFIG_RIO=m +CONFIG_RIO_OLDPCI=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_SMP=y +CONFIG_STOP_MACHINE=y --- linux-2.6.24.orig/debian/config/powerpc/config.powerpc +++ linux-2.6.24/debian/config/powerpc/config.powerpc @@ -0,0 +1,216 @@ +# +# Config options for config.powerpc automatically generated by splitconfig.pl +# +# CONFIG_40x is not set +# CONFIG_44x is not set +CONFIG_6xx=y +CONFIG_ACT200L_DONGLE_OLD=m +CONFIG_ACTISYS_DONGLE_OLD=m +CONFIG_ADB=y +CONFIG_ADB_CUDA=y +CONFIG_ADB_MACIO=y +CONFIG_ADB_PMU_LED=y +# CONFIG_ADB_PMU_LED_IDE is not set +# CONFIG_ADVANCED_OPTIONS is not set +CONFIG_AEDSP16_MSS=y +# CONFIG_AEDSP16_SBPRO is not set +CONFIG_ANSLCD=m +CONFIG_APM_EMULATION=m +CONFIG_APM_POWER=m +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_NICSTAR=m +# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set +# CONFIG_ATM_NICSTAR_USE_SUNI is not set +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_BATTERY_PMU=m +CONFIG_BAYCOM_EPP=m +# CONFIG_BDI_SWITCH is not set +CONFIG_BLK_CPQ_DA=m +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BMAC=m +CONFIG_BOOT_LOAD=0x00800000 +CONFIG_BRIQ_PANEL=m +CONFIG_BROKEN_ON_SMP=y +CONFIG_CLASSIC32=y +CONFIG_CPU_FREQ_DEBUG=y +CONFIG_CPU_FREQ_PMAC=y +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEVICE_TREE="" +CONFIG_DONGLE_OLD=y +# CONFIG_E200 is not set +# CONFIG_EMBEDDED6xx is not set +CONFIG_ESI_DONGLE_OLD=m +CONFIG_FB_CONTROL=y +CONFIG_FB_CT65550=y +CONFIG_FB_IMSTT=y +CONFIG_FB_PLATINUM=y +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +CONFIG_FB_VALKYRIE=y +CONFIG_FEC_MPC52xx=m +CONFIG_FEC_MPC52xx_MDIO=y +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_FSL_SOC=y +# CONFIG_GENERIC_IOMAP is not set +CONFIG_GENERIC_NVRAM=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_GIRBIL_DONGLE_OLD=m +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_UP_POSSIBLE=y +CONFIG_HIGHMEM=y +CONFIG_HIGHMEM_START=0xfe000000 +# CONFIG_HUGETLB_PAGE is not set +CONFIG_I2C_HYDRA=m +CONFIG_I2C_MPC=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_IBMLS=m +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +CONFIG_INPUT_ADBHID=y +CONFIG_IRPORT_SIR=m +# CONFIG_ISA is not set +CONFIG_ISTALLION=m +CONFIG_KERNEL_START=0xc0000000 +CONFIG_LANMEDIA=m +# CONFIG_LBD is not set +CONFIG_LEDS_CLASS=y +CONFIG_LITELINK_DONGLE_OLD=m +CONFIG_LOWMEM_SIZE=0x30000000 +# CONFIG_LSF is not set +CONFIG_MA600_DONGLE_OLD=m +CONFIG_MACE=m +# CONFIG_MACE_AAUI_PORT is not set +CONFIG_MAC_FLOPPY=m +CONFIG_MCP2120_DONGLE_OLD=m +# CONFIG_MMIO_NVRAM is not set +CONFIG_MPC5200_WDT=m +CONFIG_MV643XX_ETH=m +CONFIG_NVRAM=y +CONFIG_OLD_BELKIN_DONGLE_OLD=m +CONFIG_PARIDE_BPCK6=m +CONFIG_PATA_MPC52xx=m +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_IBMTR=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_XIRTULIP=m +CONFIG_PMAC_APM_EMU=m +CONFIG_PMAC_BACKLIGHT=y +CONFIG_PMAC_BACKLIGHT_LEGACY=y +CONFIG_PMAC_MEDIABAY=y +CONFIG_PM_STD_PARTITION="" +CONFIG_PPC32=y +# CONFIG_PPC601_SYNC_FIX is not set +# CONFIG_PPC64 is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_PPC_970_NAP is not set +CONFIG_PPC_BESTCOMM=m +CONFIG_PPC_BESTCOMM_ATA=m +CONFIG_PPC_BESTCOMM_FEC=m +CONFIG_PPC_BESTCOMM_GEN_BD=m +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +CONFIG_PPC_CHRP=y +CONFIG_PPC_CLOCK=y +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_EFIKA=y +# CONFIG_PPC_INDIRECT_IO is not set +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_PPC_LIB_RHEAP=y +CONFIG_PPC_LITE5200=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_PPC_MPC106=y +CONFIG_PPC_MPC5200=y +# CONFIG_PPC_MPC5200_BUGFIX is not set +CONFIG_PPC_MPC52xx=y +CONFIG_PPC_STD_MMU_32=y +CONFIG_PSS_MIXER=y +CONFIG_RISCOM8=m +# CONFIG_RTAS_ERROR_LOGGING is not set +CONFIG_SC6600=y +CONFIG_SC6600_CDROM=4 +CONFIG_SC6600_CDROMBASE=0 +CONFIG_SC6600_JOY=y +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_BUSLOGIC=m +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_MAC53C94=m +CONFIG_SCSI_MESH=m +CONFIG_SCSI_MESH_RESET_DELAY_MS=4000 +CONFIG_SCSI_MESH_SYNC_RATE=5 +CONFIG_SCSI_NSP32=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +CONFIG_SENSORS_AMS=m +CONFIG_SENSORS_AMS_I2C=y +CONFIG_SENSORS_AMS_PMU=y +CONFIG_SENSORS_M41T00=m +CONFIG_SERIAL_MPC52xx=m +CONFIG_SERIAL_PMACZILOG=m +# CONFIG_SERIAL_PMACZILOG_TTYS is not set +CONFIG_SERIAL_UARTLITE=m +CONFIG_SERIO_I8042=y +# CONFIG_SMP is not set +CONFIG_SOUND_AEDSP16=m +CONFIG_SOUND_DMAP=y +CONFIG_SOUND_KAHLUA=m +CONFIG_SOUND_MPU401=m +CONFIG_SOUND_MSS=m +CONFIG_SOUND_OSS=m +CONFIG_SOUND_PAS=m +CONFIG_SOUND_PSS=m +CONFIG_SOUND_SB=m +CONFIG_SOUND_SSCAPE=m +# CONFIG_SOUND_TRACEINIT is not set +CONFIG_SOUND_TRIX=m +CONFIG_SOUND_UART6850=m +CONFIG_SOUND_VMIDI=m +CONFIG_SOUND_YM3812=m +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPI_MPC52xx_PSC=m +CONFIG_STALLION=m +CONFIG_SUSPEND_UP_POSSIBLE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_TASK_SIZE=0xc0000000 +CONFIG_TAU=y +# CONFIG_TAU_AVERAGE is not set +# CONFIG_TAU_INT is not set +CONFIG_TEKRAM_DONGLE_OLD=m +CONFIG_THERM_ADT746X=m +CONFIG_THERM_WINDTUNNEL=m +CONFIG_TLAN=m +CONFIG_TOSHIBA_FIR=m +# CONFIG_UDBG_RTAS_CONSOLE is not set +# CONFIG_USB_OHCI_HCD_PPC_SOC is not set +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-6.10-powerpc" +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIRT_TO_BUS=y +CONFIG_WANT_DEVICE_TREE=y +CONFIG_WORD_SIZE=32 --- linux-2.6.24.orig/debian/config/powerpc/config +++ linux-2.6.24/debian/config/powerpc/config @@ -0,0 +1,2715 @@ +# +# Common config options automatically generated by splitconfig.pl +# +CONFIG_3C359=m +CONFIG_6PACK=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_8129=y +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_9P_FS=m +CONFIG_ABYSS=m +CONFIG_AC97_BUS=m +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_ADFS is not set +# CONFIG_ACORN_PARTITION_CUMANA is not set +# CONFIG_ACORN_PARTITION_EESOX is not set +CONFIG_ACORN_PARTITION_ICS=y +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_ACT200L_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_ADB_PMU=y +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_ADM8211=m +CONFIG_AFFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_AFS_FS=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_AGP=m +CONFIG_AGP_UNINORTH=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_AIRO=m +CONFIG_AIRO_CS=m +CONFIG_ALI_FIR=m +CONFIG_ALTIVEC=y +# CONFIG_AMD8111E_NAPI is not set +CONFIG_AMD8111_ETH=m +CONFIG_AMIGA_PARTITION=y +CONFIG_ANON_INODES=y +CONFIG_APPLE_AIRPORT=m +CONFIG_APPLICOM=m +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_ARCNET=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_RIM_I=m +# CONFIG_ARPD is not set +CONFIG_ASK_IP_FIB_HASH=y +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ATA=m +CONFIG_ATALK=m +CONFIG_ATARI_PARTITION=y +CONFIG_ATA_GENERIC=m +CONFIG_ATA_OVER_ETH=m +CONFIG_ATA_PIIX=m +CONFIG_ATL1=m +CONFIG_ATM=y +CONFIG_ATMEL=m +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FORE200E=m +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E_MAYBE=m +CONFIG_ATM_FORE200E_PCA=y +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y +CONFIG_ATM_FORE200E_TX_RETRY=16 +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_LANAI=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_TCP=m +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_ARCH=y +CONFIG_AUDIT_TREE=y +CONFIG_AUTOFS4_FS=m +CONFIG_AUTOFS_FS=m +CONFIG_AUXDISPLAY=y +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_B43=m +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PIO=y +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_B43_DEBUG=y +CONFIG_B43_DMA=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +CONFIG_B43_LEDS=y +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_PCI_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_PIO=y +# CONFIG_B43_PIO_MODE is not set +CONFIG_B43_RFKILL=y +CONFIG_B44=m +CONFIG_B44_PCI=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +CONFIG_BATTERY_DS2760=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +CONFIG_BCM43XX_PIO=y +# CONFIG_BCM43XX_PIO_MODE is not set +# CONFIG_BEFS_DEBUG is not set +CONFIG_BEFS_FS=m +CONFIG_BFS_FS=m +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_BITREVERSE=y +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI15X3=m +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_BSG is not set +CONFIG_BLK_DEV_CMD64X=m +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_CRYPTOLOOP=m +# CONFIG_BLK_DEV_CS5520 is not set +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_CY82C693=m +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_DM=m +CONFIG_BLK_DEV_FD=m +CONFIG_BLK_DEV_GENERIC=m +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_HPT34X=m +CONFIG_BLK_DEV_HPT366=m +CONFIG_BLK_DEV_IDE=y +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDEDISK=m +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_IDEDMA_PMAC=y +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_BLK_DEV_IT8213=m +CONFIG_BLK_DEV_IT821X=m +CONFIG_BLK_DEV_JMICRON=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_MD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_NS87415=m +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_PDC202XX_NEW=m +CONFIG_BLK_DEV_PDC202XX_OLD=m +CONFIG_BLK_DEV_PIIX=m +CONFIG_BLK_DEV_PLATFORM=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_SC1200=m +CONFIG_BLK_DEV_SD=m +CONFIG_BLK_DEV_SIIMAGE=m +CONFIG_BLK_DEV_SL82C105=m +CONFIG_BLK_DEV_SLC90E66=m +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_BLK_DEV_SVWKS=m +CONFIG_BLK_DEV_SX8=m +CONFIG_BLK_DEV_TC86C001=m +CONFIG_BLK_DEV_TRIFLEX=m +CONFIG_BLK_DEV_TRM290=m +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLOCK=y +CONFIG_BNX2=m +CONFIG_BONDING=m +# CONFIG_BOOTX_TEXT is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOUNCE=y +CONFIG_BPQETHER=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_NETFILTER=y +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BROADCOM_PHY=m +CONFIG_BSD_DISKLABEL=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_BT=m +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIVHCI=m +CONFIG_BT_HIDP=m +CONFIG_BT_L2CAP=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_SCO=m +CONFIG_BUG=y +CONFIG_CARDBUS=y +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +CONFIG_CASSINI=m +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_CFG80211=m +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_NS=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_CHR_DEV_OSST=m +CONFIG_CHR_DEV_SCH=m +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_ST=m +CONFIG_CICADA_PHY=m +CONFIG_CIFS=m +# CONFIG_CIFS_DEBUG2 is not set +CONFIG_CIFS_EXPERIMENTAL=y +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_WEAK_PW_HASH=y +# CONFIG_CIFS_XATTR is not set +CONFIG_CISS_SCSI_TAPE=y +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CMDLINE_BOOL is not set +CONFIG_CODA_FS=m +# CONFIG_CODA_FS_OLD_API is not set +CONFIG_COMPUTONE=m +CONFIG_CONFIGFS_FS=m +CONFIG_CONNECTOR=m +# CONFIG_CPM2 is not set +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CRAMFS=y +CONFIG_CRC16=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_CRC_CCITT=m +CONFIG_CRC_ITU_T=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_CYCLADES=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +# CONFIG_CYZ_INTR is not set +CONFIG_DAB=y +CONFIG_DAVICOM_PHY=m +CONFIG_DE2104X=m +CONFIG_DE4X5=m +CONFIG_DE600=m +CONFIG_DE620=m +# CONFIG_DEBUGGER is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +CONFIG_DECNET=m +CONFIG_DECNET_NF_GRABULATOR=m +# CONFIG_DECNET_ROUTER is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_BIC is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_HTCP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_RELATIME=y +CONFIG_DEFAULT_RELATIME_VAL=1 +CONFIG_DEFAULT_RENO=y +CONFIG_DEFAULT_TCP_CONG="reno" +# CONFIG_DEFAULT_UIMAGE is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_DEVPORT=y +CONFIG_DEV_APPLETALK=m +# CONFIG_DEV_KMEM is not set +CONFIG_DIGIEPCA=m +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_DISPLAY_SUPPORT=m +CONFIG_DL2K=m +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_DM9102=m +CONFIG_DM_CRYPT=m +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_MIRROR=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m +CONFIG_DM_MULTIPATH_HP=m +CONFIG_DM_MULTIPATH_RDAC=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_UEVENT=y +CONFIG_DM_ZERO=m +CONFIG_DNOTIFY=y +CONFIG_DONGLE=y +CONFIG_DRM=m +CONFIG_DRM_MGA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_SAVAGE=m +CONFIG_DRM_SIS=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_VIA=m +# CONFIG_DRM_VIA_CHROME9 is not set +CONFIG_DS1682=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DUMMY=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_B2C2_FLEXCOP=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_BT8XX=m +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_PATCH=m +CONFIG_DVB_CAPTURE_DRIVERS=y +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m +# CONFIG_DVB_FE_CUSTOMISE is not set +CONFIG_DVB_ISL6421=m +CONFIG_DVB_L64781=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LNBP21=m +CONFIG_DVB_MT312=m +CONFIG_DVB_MT352=m +CONFIG_DVB_NXT200X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_PLL=m +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_STV0297=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_TUNER_DIB0070=m +CONFIG_DVB_TUNER_MT2060=m +CONFIG_DVB_TUNER_MT2131=m +CONFIG_DVB_TUNER_MT2266=m +CONFIG_DVB_TUNER_QT1010=m +CONFIG_DVB_USB=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_CXUSB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_ZL10353=m +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E1000_NAPI=y +CONFIG_EARLY_PRINTK=y +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_ECRYPT_FS=m +CONFIG_EDAC=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_MM_EDAC=m +CONFIG_EEPRO100=m +CONFIG_EEPROM_93CX6=m +# CONFIG_EFI_PARTITION is not set +CONFIG_EFS_FS=m +CONFIG_ELF_CORE=y +# CONFIG_EMBEDDED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +CONFIG_EPIC100=m +CONFIG_EPOLL=y +CONFIG_EQUALIZER=m +CONFIG_ESI_DONGLE=m +CONFIG_EVENTFD=y +CONFIG_EXPERIMENTAL=y +CONFIG_EXPORTFS=m +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_FAIR_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_FAIR_USER_SCHED is not set +CONFIG_FARSYNC=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_FS=m +# CONFIG_FAULT_INJECTION is not set +CONFIG_FB=y +CONFIG_FB_3DFX=y +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_ARK=m +CONFIG_FB_ASILIANT=y +CONFIG_FB_ATY=y +CONFIG_FB_ATY128=y +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_CIRRUS=m +CONFIG_FB_CYBER2000=m +CONFIG_FB_DDC=y +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_IBM_GXT4500=m +CONFIG_FB_KYRO=m +CONFIG_FB_MACMODES=y +CONFIG_FB_MATROX=y +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_BACKLIGHT=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_I2C=y +CONFIG_FB_OF=y +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_PM3=m +CONFIG_FB_RADEON=y +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_BACKLIGHT=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_I2C=y +CONFIG_FB_S1D13XXX=m +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_SM501=m +CONFIG_FB_SVGALIB=m +CONFIG_FB_TILEBLITTING=y +CONFIG_FB_TRIDENT=m +CONFIG_FB_TRIDENT_ACCEL=y +CONFIG_FB_UVESA=m +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FB_VOODOO1=y +CONFIG_FB_VT8623=m +CONFIG_FDDI=y +CONFIG_FEALNX=m +CONFIG_FIB_RULES=y +# CONFIG_FIREWIRE is not set +CONFIG_FIRMWARE_EDID=y +CONFIG_FIXED_MII_1000_FDX=y +# CONFIG_FIXED_MII_100_FDX is not set +# CONFIG_FIXED_MII_10_FDX is not set +CONFIG_FIXED_MII_AMNT=1 +CONFIG_FIXED_PHY=m +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +# CONFIG_FORCED_INLINING is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FSL_ULI1575 is not set +CONFIG_FS_MBCACHE=m +CONFIG_FS_POSIX_ACL=y +CONFIG_FTL=m +CONFIG_FUSE_FS=m +CONFIG_FUSION=y +CONFIG_FUSION_CTL=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_SAS=m +CONFIG_FUSION_SPI=m +CONFIG_FUTEX=y +CONFIG_FW_LOADER=y +CONFIG_GACT_PROB=y +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GENERIC_ACL=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_GFS2_FS_LOCKING_NOLOCK=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_HAMACHI=m +CONFIG_HAMRADIO=y +CONFIG_HAPPYMEAL=m +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HDLC=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_X25=m +# CONFIG_HEADERS_CHECK is not set +CONFIG_HERMES=m +CONFIG_HFSPLUS_FS=m +CONFIG_HFS_FS=m +CONFIG_HID=m +CONFIG_HIDRAW=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HID_FF is not set +CONFIG_HID_SUPPORT=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HIPPI=y +CONFIG_HOSTAP=m +CONFIG_HOSTAP_CS=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_PLX=m +CONFIG_HOTPLUG=y +# CONFIG_HOTPLUG_PCI is not set +CONFIG_HP100=m +CONFIG_HPFS_FS=m +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_HVC_RTAS is not set +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_HWMON_VID=m +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +CONFIG_I2C_ALGOPCA=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +# CONFIG_I2C_DEBUG_CORE is not set +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_POWERMAC=y +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_BUS=m +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_PROC=m +CONFIG_I2O_SCSI=m +CONFIG_I82092=m +CONFIG_IBMOL=m +CONFIG_ICPLUS_PHY=m +CONFIG_IDE=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_IDEPCI_PCIBUS_ORDER=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_IDE_ARM is not set +CONFIG_IDE_GENERIC=m +CONFIG_IDE_PROC_FS=y +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IEEE1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_OHCI1394=m +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE80211=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_CRYPT_WEP=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_IFB=m +# CONFIG_IKCONFIG is not set +CONFIG_INET=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET_AH=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_INET_DIAG=y +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_LRO=m +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFTL=m +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_INPUT=y +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MOUSE=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_PCSPKR=m +CONFIG_INPUT_POLLDEV=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=m +CONFIG_INPUT_YEALINK=m +CONFIG_INSTRUMENTATION=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IP1000=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IPDDP=m +CONFIG_IPDDP_DECAP=y +CONFIG_IPDDP_ENCAP=y +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_POWEROFF=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPV6=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPW2100=m +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2200=m +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_DCCP=m +CONFIG_IP_DCCP_ACKVEC=y +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_IP_DCCP_TFRC_LIB=m +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_SCTP=m +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_TAB_BITS=12 +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_WRR=m +CONFIG_IRCOMM=m +CONFIG_IRDA=m +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_DEBUG=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_ULTRA=y +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRQ_PER_CPU=y +CONFIG_IRTTY_SIR=m +CONFIG_ISA_DMA_API=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISDN is not set +# CONFIG_ISI is not set +CONFIG_ISO9660_FS=m +# CONFIG_IWLWIFI is not set +CONFIG_IXGB=m +CONFIG_IXGBE=m +# CONFIG_IXGB_NAPI is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +CONFIG_JFS_STATISTICS=y +CONFIG_JOLIET=y +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_KARMA_PARTITION=y +CONFIG_KEXEC=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +CONFIG_KINGSUN_DONGLE=m +CONFIG_KMOD=y +CONFIG_KPROBES=y +CONFIG_KS0108=m +CONFIG_KS0108_DELAY=2 +CONFIG_KS0108_PORT=0x378 +CONFIG_KS959_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_LAPB=m +CONFIG_LAPBETHER=m +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +# CONFIG_LDM_DEBUG is not set +CONFIG_LDM_PARTITION=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LIBCRC32C=m +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_CS=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_USB=m +CONFIG_LITELINK_DONGLE=m +# CONFIG_LKDTM is not set +CONFIG_LLC=y +CONFIG_LLC2=m +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_LP_CONSOLE is not set +CONFIG_LSM_MMAP_MIN_ADDR=0 +CONFIG_LXT_PHY=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_MA600_DONGLE=m +CONFIG_MAC80211=m +# CONFIG_MAC80211_DEBUG is not set +CONFIG_MAC80211_DEBUGFS=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MACVLAN=m +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_MAC_PARTITION=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_MARKERS is not set +CONFIG_MARVELL_PHY=m +CONFIG_MAX_RAW_DEVS=256 +CONFIG_MCP2120_DONGLE=m +CONFIG_MCS_FIR=m +CONFIG_MD=y +CONFIG_MDIO_BITBANG=m +CONFIG_MD_FAULTY=m +CONFIG_MD_LINEAR=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_SAS=m +CONFIG_MFD_SM501=m +CONFIG_MII=m +CONFIG_MINIX_FS=m +CONFIG_MINIX_SUBPARTITION=y +CONFIG_MISC_DEVICES=y +CONFIG_MKISS=m +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_MLX4_INFINIBAND=m +CONFIG_MMC=m +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_SDHCI=m +CONFIG_MMC_TIFM_SD=m +# CONFIG_MMC_UNSAFE_RESUME is not set +CONFIG_MMC_WBSD=m +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_TRACKPOINT=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_MOXA_INTELLIO=m +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +CONFIG_MPIC=y +# CONFIG_MPIC_WEIRD is not set +CONFIG_MSDOS_FS=m +CONFIG_MSDOS_PARTITION=y +CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin" +CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin" +CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin" +CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin" +# CONFIG_MSS is not set +CONFIG_MTD=m +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTD_ABSENT=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK2MTD=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_MTD_CFI=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_CHAR=m +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_CONCAT=m +CONFIG_MTD_DATAFLASH=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCECC=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCPROBE_ADDRESS=0 +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTD_NAND=m +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND_IDS=m +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_2X_PROGRAM=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_SIM=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_OOPS=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_PCI=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_OF=m +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PLATRAM=m +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_RAM=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +CONFIG_MTD_REDBOOT_PARTS=m +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +CONFIG_MTD_ROM=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MYRI10GE=m +CONFIG_NATSEMI=m +CONFIG_NCPFS_EXTRAS=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_PACKET_SIGNING=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_STRONG=y +CONFIG_NCP_FS=m +CONFIG_NE2K_PCI=m +CONFIG_NET=y +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETDEVICES=y +CONFIG_NETDEVICES_MULTIQUEUE=y +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +# CONFIG_NETLABEL is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NETROM=m +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NETXEN_NIC=m +CONFIG_NET_9P=m +# CONFIG_NET_9P_DEBUG is not set +CONFIG_NET_9P_FD=m +CONFIG_NET_ACT_GACT=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_CLS=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_FW=m +# CONFIG_NET_CLS_IND is not set +# CONFIG_NET_CLS_POLICE is not set +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_DCCPPROBE=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_ETHERNET=y +CONFIG_NET_FC=y +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_NET_IPIP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_NET_PCI=y +CONFIG_NET_PCMCIA=y +CONFIG_NET_PKTGEN=m +CONFIG_NET_POCKET=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_FIFO=y +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_RR=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_TCPPROBE=m +CONFIG_NET_TULIP=y +CONFIG_NET_VENDOR_3COM=y +CONFIG_NEW_LEDS=y +CONFIG_NFSD=m +CONFIG_NFSD_TCP=y +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_TFTP=m +# CONFIG_NIU is not set +CONFIG_NL80211=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +# CONFIG_NORTEL_HERMES is not set +CONFIG_NO_HZ=y +CONFIG_NS83820=m +CONFIG_NSC_FIR=m +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_FS=m +# CONFIG_NTFS_RW is not set +CONFIG_N_HDLC=m +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_OCFS2_DEBUG_MASKLOG=y +CONFIG_OCFS2_FS=m +CONFIG_OF=y +CONFIG_OF_DEVICE=y +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_OPROFILE=m +CONFIG_OSF_PARTITION=y +CONFIG_P54_COMMON=m +CONFIG_P54_PCI=m +CONFIG_P54_USB=m +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_PARIDE=m +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PG=m +CONFIG_PARIDE_PT=m +CONFIG_PARPORT=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_AX88796=m +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_NOT_PC=y +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_FIFO=y +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_SERIAL=m +CONFIG_PARTITION_ADVANCED=y +# CONFIG_PATA_ALI is not set +CONFIG_PATA_AMD=m +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +CONFIG_PATA_CS5520=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NETCELL=m +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +CONFIG_PATA_OLDPIIX=m +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PCMCIA=m +CONFIG_PATA_PDC2027X=m +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +CONFIG_PC300=m +# CONFIG_PC300TOO is not set +CONFIG_PC300_MLPPP=y +CONFIG_PCCARD=m +CONFIG_PCCARD_NONSTATIC=m +CONFIG_PCI=y +CONFIG_PCI200SYN=m +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIPCWATCHDOG=m +CONFIG_PCI_ATMEL=m +# CONFIG_PCI_DEBUG is not set +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_HERMES is not set +CONFIG_PCI_LEGACY=y +CONFIG_PCI_MSI=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCMCIA=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_AXNET=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_IOCTL=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_PD6729=m +CONFIG_PDA_POWER=m +# CONFIG_PDC202XX_BURST is not set +CONFIG_PDC_ADMA=m +CONFIG_PHANTOM=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m +CONFIG_PHYLIB=m +# CONFIG_PID_NS is not set +CONFIG_PLIP=m +CONFIG_PLIST=y +# CONFIG_PLX_HERMES is not set +CONFIG_PM=y +CONFIG_PMAC_RACKMETER=m +# CONFIG_PM_DEBUG is not set +CONFIG_PM_DISABLE_CONSOLE=y +CONFIG_PM_LEGACY=y +CONFIG_PM_SLEEP=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POWER_SUPPLY=m +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PPC=y +# CONFIG_PPC_82xx is not set +# CONFIG_PPC_83xx is not set +# CONFIG_PPC_86xx is not set +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_EARLY_DEBUG is not set +CONFIG_PPC_FPU=y +CONFIG_PPC_I8259=y +CONFIG_PPC_MERGE=y +CONFIG_PPC_MULTIPLATFORM=y +CONFIG_PPC_NATIVE=y +CONFIG_PPC_OF=y +CONFIG_PPC_PMAC=y +CONFIG_PPC_RTAS=y +CONFIG_PPC_STD_MMU=y +CONFIG_PPC_UDBG_16550=y +CONFIG_PPDEV=m +CONFIG_PPP=m +CONFIG_PPPOATM=m +CONFIG_PPPOE=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_SYNC_TTY=m +# CONFIG_PQ2ADS is not set +# CONFIG_PREEMPT is not set +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTER=m +CONFIG_PRINTK=y +CONFIG_PRINTK_TIME=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_PRISM54=m +CONFIG_PROC_DEVICETREE=y +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROFILING=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_QLA3XXX=m +CONFIG_QNX4FS_FS=m +CONFIG_QSEMI_PHY=m +CONFIG_QUOTA=y +CONFIG_QUOTACTL=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_R3964=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RAID_ATTRS=m +CONFIG_RAW_DRIVER=m +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_FS=m +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_REISERFS_FS_XATTR=y +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_RELAY=y +CONFIG_RESOURCES_64BIT=y +CONFIG_RFD_FTL=m +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +# CONFIG_RIO is not set +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_ROCKETPORT=m +CONFIG_ROMFS_FS=m +CONFIG_ROSE=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT2X00=m +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RT2X00_LIB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT73USB=m +CONFIG_RTAS_PROC=y +CONFIG_RTC_CLASS=m +CONFIG_RTC_DRV_CMOS=m +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_TEST=m +CONFIG_RTC_DRV_V3020=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=m +CONFIG_RTL8187=m +CONFIG_RT_MUTEXES=y +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_RXKAD=m +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +# CONFIG_SAMPLES is not set +CONFIG_SATA_AHCI=m +CONFIG_SATA_INIC162X=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_SX4=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SC92031=m +# CONFIG_SCHEDSTATS is not set +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_SCSI=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AIC79XX=m +CONFIG_SCSI_AIC7XXX=m +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC94XX=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DMA=y +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_IMM=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_DUMP is not set +# CONFIG_SCSI_IPR_TRACE is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_ISCSI_ATTRS=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PPA=m +CONFIG_SCSI_PROC_FS=y +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_TGT=m +CONFIG_SCSI_WAIT_SCAN=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SDIO_UART=m +CONFIG_SECCOMP=y +CONFIG_SECURITY=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +# CONFIG_SECURITY_APPARMOR_DISABLE is not set +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_DISABLE=y +# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_TSL2550=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SERIAL_8250=m +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_PCI=m +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_CORE=m +CONFIG_SERIAL_JSM=m +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_SERIAL_OF_PLATFORM=m +CONFIG_SERIO=y +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_RAW=m +CONFIG_SERIO_SERPORT=m +CONFIG_SGI_IOC4=m +CONFIG_SGI_PARTITION=y +CONFIG_SHAPER=m +CONFIG_SHMEM=y +CONFIG_SIGMATEL_FIR=m +CONFIG_SIGNALFD=y +CONFIG_SIS190=m +CONFIG_SIS900=m +# CONFIG_SK98LIN is not set +CONFIG_SKFP=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +CONFIG_SLHC=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_SLIP_SMART=y +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_DEBUG_ON is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_SMC_IRCC_FIR=m +CONFIG_SMSC_PHY=m +CONFIG_SND=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 +CONFIG_SND_AD1889=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ALS300=m +CONFIG_SND_ALS4000=m +CONFIG_SND_AOA=m +CONFIG_SND_AOA_FABRIC_LAYOUT=m +CONFIG_SND_AOA_ONYX=m +CONFIG_SND_AOA_SOUNDBUS=m +CONFIG_SND_AOA_SOUNDBUS_I2S=m +CONFIG_SND_AOA_TAS=m +CONFIG_SND_AOA_TOONIE=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_BT87X_OVERCLOCK=y +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS5530=m +CONFIG_SND_DARLA20=m +CONFIG_SND_DARLA24=m +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DUMMY=m +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_ECHO3G=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_GINA20=m +CONFIG_SND_GINA24=m +CONFIG_SND_HDA_CODEC_ANALOG=y +CONFIG_SND_HDA_CODEC_ATIHDMI=y +CONFIG_SND_HDA_CODEC_CMEDIA=y +CONFIG_SND_HDA_CODEC_CONEXANT=y +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_CODEC_SI3054=y +CONFIG_SND_HDA_CODEC_SIGMATEL=y +CONFIG_SND_HDA_CODEC_VIA=y +CONFIG_SND_HDA_GENERIC=y +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_POWER_SAVE=y +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_KORG1212_FIRMWARE_IN_KERNEL=y +CONFIG_SND_LAYLA20=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MAESTRO3_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MIA=m +CONFIG_SND_MIXART=m +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_MONA=m +CONFIG_SND_MPU401=m +CONFIG_SND_MPU401_UART=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_NM256=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_PCM=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_PCXHR=m +CONFIG_SND_PDAUDIOCF=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_POWERMAC=m +CONFIG_SND_POWERMAC_AUTO_DRC=y +CONFIG_SND_RAWMIDI=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_SB16_DSP=m +CONFIG_SND_SB_COMMON=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_SOC=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_TIMER=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_USB_USX2Y=m +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_VX222=m +CONFIG_SND_VXPOCKET=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y +CONFIG_SOFT_WATCHDOG=m +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_SOUND=m +CONFIG_SOUND_MSNDCLAS=m +CONFIG_SOUND_MSNDPIN=m +CONFIG_SOUND_PRIME=m +CONFIG_SOUND_TRIDENT=m +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPECIALIX=m +# CONFIG_SPECIALIX_RTSCTS is not set +CONFIG_SPI=y +CONFIG_SPI_AT25=m +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_MASTER=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SSB=m +CONFIG_SSB_DEBUG=y +CONFIG_SSB_DRIVER_PCICORE=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +CONFIG_SSB_POSSIBLE=y +CONFIG_SSFDC=m +CONFIG_STALDRV=y +CONFIG_STANDALONE=y +CONFIG_STRIP=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_SUNGEM=m +CONFIG_SUNRPC=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_SUN_PARTITION=y +CONFIG_SUSPEND=y +CONFIG_SWAP=y +CONFIG_SX=m +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_CS=m +CONFIG_SYNCLINK_GT=m +CONFIG_SYN_COOKIES=y +CONFIG_SYSCTL=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_SYSV68_PARTITION=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_SYSV_FS=m +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y +CONFIG_TCG_ATMEL=m +CONFIG_TCG_TPM=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_MD5SIG=y +CONFIG_TEHUTI=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TICK_ONESHOT=y +CONFIG_TIFM_7XX1=m +CONFIG_TIFM_CORE=m +CONFIG_TIGON3=m +CONFIG_TIMER_STATS=y +# CONFIG_TINY_SHMEM is not set +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +# CONFIG_TMD_HERMES is not set +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TR=y +CONFIG_TULIP=m +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_TUN=m +CONFIG_TUNER_3036=m +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_SIMPLE=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TYPHOON=m +# CONFIG_UCC_SLOW is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_DEBUG is not set +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +CONFIG_UIO=m +CONFIG_UIO_CIF=m +CONFIG_ULI526X=m +CONFIG_ULTRIX_PARTITION=y +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_USB=m +CONFIG_USBPCWATCHDOG=m +CONFIG_USB_ACM=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_ATM=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_BELKIN=y +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_CATC=m +CONFIG_USB_CXACRU=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_DABUSB=m +# CONFIG_USB_DEBUG is not set +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_DSBR=m +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EMI26=m +CONFIG_USB_EMI62=m +CONFIG_USB_EPSON2888=y +CONFIG_USB_ET61X251=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_EZUSB=y +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_GADGET=m +CONFIG_USB_GADGETFS=m +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_M66592 is not set +CONFIG_USB_GADGET_NET2280=y +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_S3C2410 is not set +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_G_SERIAL=m +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_HIDINPUT_POWERBOOK=y +CONFIG_USB_IBMCAM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_IRDA=m +CONFIG_USB_ISP116X_HCD=m +CONFIG_USB_KAWETH=m +CONFIG_USB_KBD=m +CONFIG_USB_KC2190=y +CONFIG_USB_KONICAWC=m +CONFIG_USB_LCD=m +CONFIG_USB_LD=m +CONFIG_USB_LED=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +# CONFIG_USB_MIDI_GADGET is not set +CONFIG_USB_MON=y +CONFIG_USB_MOUSE=m +CONFIG_USB_NET2280=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_RNDIS_HOST=m +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y +CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_HCD_PCI=y +CONFIG_USB_OHCI_HCD_PPC_OF=y +CONFIG_USB_OHCI_HCD_PPC_OF_BE=y +# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OV511 is not set +CONFIG_USB_PEGASUS=m +CONFIG_USB_PERSIST=y +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_PRINTER=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_R8A66597_HCD=m +CONFIG_USB_RIO500=m +CONFIG_USB_RTL8150=m +CONFIG_USB_SE401=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IPW=m +# CONFIG_USB_SERIAL_IR is not set +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_SL811_CS=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SN9C102=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_DATAFAB=y +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STV680=m +CONFIG_USB_SUPPORT=y +CONFIG_USB_SUSPEND=y +# CONFIG_USB_TEST is not set +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_USBNET=m +CONFIG_USB_USS720=m +CONFIG_USB_VICAM=m +CONFIG_USB_W9968CF=m +CONFIG_USB_XUSBATM=m +CONFIG_USB_ZC0301=m +CONFIG_USB_ZD1201=m +CONFIG_USB_ZERO=m +CONFIG_USB_ZR364XX=m +# CONFIG_USER_NS is not set +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VETH=m +CONFIG_VFAT_FS=m +CONFIG_VGASTATE=m +# CONFIG_VGA_CONSOLE is not set +CONFIG_VIA_FIR=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_RHINE_NAPI=y +CONFIG_VIA_VELOCITY=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_CX25840=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_DEV=m +# CONFIG_VIDEO_DPC is not set +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_FB_IVTV=m +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_MSP3400=m +# CONFIG_VIDEO_MXB is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_29XXX=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7134_OSS=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_SAA7191=m +CONFIG_VIDEO_TCM825X=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_VP27SMPX=m +CONFIG_VIDEO_VPX3220=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_WM8775=m +# CONFIG_VIRQ_DEBUG is not set +CONFIG_VITESSE_PHY=m +CONFIG_VLAN_8021Q=m +CONFIG_VLSI_FIR=m +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VORTEX=m +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_VXFS_FS=m +CONFIG_W1=m +CONFIG_W1_CON=y +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_THERM=m +CONFIG_WAN=y +CONFIG_WANXL=m +CONFIG_WAN_ROUTER=m +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_WATCHDOG_RTAS=m +# CONFIG_WDC_ALI15X3 is not set +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y +CONFIG_WINBOND_840=m +CONFIG_WINBOND_FIR=m +CONFIG_WINDFARM=m +CONFIG_WIRELESS_EXT=y +CONFIG_WLAN_80211=y +CONFIG_WLAN_PRE80211=y +CONFIG_X25=m +CONFIG_X25_ASY=m +CONFIG_XFRM=y +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_USER=m +CONFIG_XFS_FS=m +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_QUOTA=y +CONFIG_XFS_RT=y +CONFIG_XFS_SECURITY=y +CONFIG_XOR_BLOCKS=m +CONFIG_YAM=m +CONFIG_YELLOWFIN=m +CONFIG_YENTA=m +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_ZISOFS=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZONE_DMA=y +CONFIG_ZONE_DMA_FLAG=1 --- linux-2.6.24.orig/debian/config/powerpc/config.powerpc-smp +++ linux-2.6.24/debian/config/powerpc/config.powerpc-smp @@ -0,0 +1,206 @@ +# +# Config options for config.powerpc-smp automatically generated by splitconfig.pl +# +# CONFIG_40x is not set +# CONFIG_44x is not set +CONFIG_6xx=y +CONFIG_ADB=y +CONFIG_ADB_CUDA=y +CONFIG_ADB_MACIO=y +CONFIG_ADB_PMU_LED=y +# CONFIG_ADB_PMU_LED_IDE is not set +# CONFIG_ADVANCED_OPTIONS is not set +CONFIG_AEDSP16_MSS=y +# CONFIG_AEDSP16_SBPRO is not set +CONFIG_ANSLCD=m +CONFIG_APM_EMULATION=m +CONFIG_APM_POWER=m +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_NICSTAR=m +# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set +# CONFIG_ATM_NICSTAR_USE_SUNI is not set +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_BATTERY_PMU=m +CONFIG_BAYCOM_EPP=m +# CONFIG_BDI_SWITCH is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_DEV_IDECS=m +CONFIG_BMAC=m +CONFIG_BOOT_LOAD=0x00800000 +CONFIG_BRIQ_PANEL=m +CONFIG_CLASSIC32=y +CONFIG_CPUSETS=y +CONFIG_CPU_FREQ_DEBUG=y +CONFIG_CPU_FREQ_PMAC=y +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_DEVICE_TREE="" +# CONFIG_E200 is not set +CONFIG_FB_CONTROL=y +CONFIG_FB_CT65550=y +CONFIG_FB_IMSTT=y +CONFIG_FB_PLATINUM=y +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +CONFIG_FB_VALKYRIE=y +CONFIG_FEC_MPC52xx=m +CONFIG_FEC_MPC52xx_MDIO=y +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_FSL_SOC=y +# CONFIG_GENERIC_IOMAP is not set +CONFIG_GENERIC_NVRAM=y +CONFIG_GENERIC_TBSYNC=y +CONFIG_HIGHMEM=y +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_I2C_HYDRA=m +CONFIG_I2C_MPC=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_IBMLS=m +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +CONFIG_INPUT_ADBHID=y +# CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_ISA is not set +CONFIG_KERNEL_START=0xc0000000 +CONFIG_LANMEDIA=m +# CONFIG_LBD is not set +CONFIG_LEDS_CLASS=y +CONFIG_LOCK_KERNEL=y +CONFIG_LOWMEM_SIZE=0x30000000 +# CONFIG_LSF is not set +CONFIG_MACE=m +# CONFIG_MACE_AAUI_PORT is not set +CONFIG_MAC_FLOPPY=m +# CONFIG_MMIO_NVRAM is not set +CONFIG_MPC5200_WDT=m +CONFIG_MV643XX_ETH=m +CONFIG_NR_CPUS=4 +CONFIG_NVRAM=y +CONFIG_PARIDE_BPCK6=m +CONFIG_PATA_MPC52xx=m +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_IBMTR=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PMAC_APM_EMU=m +CONFIG_PMAC_BACKLIGHT=y +CONFIG_PMAC_BACKLIGHT_LEGACY=y +CONFIG_PMAC_MEDIABAY=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PPC32=y +# CONFIG_PPC601_SYNC_FIX is not set +# CONFIG_PPC64 is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_PPC_970_NAP is not set +CONFIG_PPC_BESTCOMM=m +CONFIG_PPC_BESTCOMM_ATA=m +CONFIG_PPC_BESTCOMM_FEC=m +# CONFIG_PPC_BESTCOMM_GEN_BD is not set +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +CONFIG_PPC_CHRP=y +CONFIG_PPC_CLOCK=y +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_EFIKA=y +# CONFIG_PPC_INDIRECT_IO is not set +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_PPC_LIB_RHEAP=y +CONFIG_PPC_LITE5200=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_PPC_MPC106=y +CONFIG_PPC_MPC5200=y +# CONFIG_PPC_MPC5200_BUGFIX is not set +CONFIG_PPC_MPC52xx=y +CONFIG_PPC_STD_MMU_32=y +CONFIG_PREEMPT_BKL=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_PSS_MIXER=y +# CONFIG_RTAS_ERROR_LOGGING is not set +CONFIG_SC6600=y +CONFIG_SC6600_CDROM=4 +CONFIG_SC6600_CDROMBASE=0 +CONFIG_SC6600_JOY=y +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_BUSLOGIC=m +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_MAC53C94=m +CONFIG_SCSI_MESH=m +CONFIG_SCSI_MESH_RESET_DELAY_MS=4000 +CONFIG_SCSI_MESH_SYNC_RATE=5 +CONFIG_SCSI_NSP32=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +CONFIG_SENSORS_AMS=m +CONFIG_SENSORS_AMS_I2C=y +CONFIG_SENSORS_AMS_PMU=y +CONFIG_SENSORS_M41T00=m +CONFIG_SERIAL_MPC52xx=m +CONFIG_SERIAL_PMACZILOG=m +# CONFIG_SERIAL_PMACZILOG_TTYS is not set +CONFIG_SERIAL_UARTLITE=m +CONFIG_SERIO_I8042=y +CONFIG_SMP=y +CONFIG_SOUND_AEDSP16=m +CONFIG_SOUND_DMAP=y +CONFIG_SOUND_KAHLUA=m +CONFIG_SOUND_MPU401=m +CONFIG_SOUND_MSS=m +CONFIG_SOUND_OSS=m +CONFIG_SOUND_PAS=m +CONFIG_SOUND_PSS=m +CONFIG_SOUND_SB=m +CONFIG_SOUND_SSCAPE=m +# CONFIG_SOUND_TRACEINIT is not set +CONFIG_SOUND_TRIX=m +CONFIG_SOUND_UART6850=m +CONFIG_SOUND_VMIDI=m +CONFIG_SOUND_YM3812=m +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPI_MPC52xx_PSC=m +CONFIG_STOP_MACHINE=y +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_TASK_SIZE=0xc0000000 +CONFIG_TAU=y +# CONFIG_TAU_AVERAGE is not set +# CONFIG_TAU_INT is not set +CONFIG_THERM_ADT746X=m +CONFIG_THERM_WINDTUNNEL=m +CONFIG_TLAN=m +CONFIG_TOSHIBA_FIR=m +# CONFIG_UDBG_RTAS_CONSOLE is not set +# CONFIG_USB_OHCI_HCD_PPC_SOC is not set +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-6.10-powerpc-smp" +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIRT_TO_BUS=y +CONFIG_WANT_DEVICE_TREE=y +CONFIG_WORD_SIZE=32 --- linux-2.6.24.orig/debian/config/powerpc/config.powerpc64-smp +++ linux-2.6.24/debian/config/powerpc/config.powerpc64-smp @@ -0,0 +1,182 @@ +# +# Config options for config.powerpc64-smp automatically generated by splitconfig.pl +# +CONFIG_64BIT=y +# CONFIG_ADB_PMU_LED is not set +CONFIG_ARCH_HAS_ILOG2_U64=y +CONFIG_ARCH_MEMORY_PROBE=y +CONFIG_ARCH_NO_VIRT_TO_BUS=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ATA_NONSTANDARD=y +CONFIG_AXON_RAM=m +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLOCK_COMPAT=y +# CONFIG_CBE_CPUFREQ is not set +CONFIG_CBE_RAS=y +CONFIG_CBE_THERM=m +CONFIG_COMPAT=y +CONFIG_CPUSETS=y +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_PMAC64=y +# CONFIG_CRASH_DUMP is not set +CONFIG_EDAC_PASEMI=m +CONFIG_EEH=y +CONFIG_EHEA=m +CONFIG_ELECTRA_CF=m +CONFIG_ELECTRA_IDE=m +# CONFIG_FB_IMSTT is not set +CONFIG_FB_PS3=y +CONFIG_FB_PS3_DEFAULT_SIZE_M=18 +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_FOPS=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_FORCE_MAX_ZONEORDER=13 +CONFIG_GELIC_NET=m +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_TBSYNC=y +CONFIG_HANGCHECK_TIMER=m +CONFIG_HAVE_MEMORY_PRESENT=y +# CONFIG_HCALL_STATS is not set +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SMP_POSSIBLE=y +CONFIG_HOTPLUG_CPU=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_HUGETLB_PAGE_SIZE_VARIABLE=y +CONFIG_HVCS=m +CONFIG_HVC_CONSOLE=y +CONFIG_HVC_DRIVER=y +CONFIG_HW_RANDOM_PASEMI=m +CONFIG_I2C_PASEMI=m +CONFIG_I2O_EXT_ADAPTEC_DMA64=y +CONFIG_IBMEBUS=y +CONFIG_IBMVETH=m +CONFIG_IBMVIO=y +CONFIG_IBM_NEW_EMAC=m +# CONFIG_IBM_NEW_EMAC_DEBUG is not set +CONFIG_IBM_NEW_EMAC_EMAC4=y +CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32 +CONFIG_IBM_NEW_EMAC_RGMII=y +CONFIG_IBM_NEW_EMAC_RXB=128 +CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256 +CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0 +CONFIG_IBM_NEW_EMAC_TAH=y +CONFIG_IBM_NEW_EMAC_TXB=64 +CONFIG_IBM_NEW_EMAC_ZMII=y +CONFIG_INFINIBAND_EHCA=m +CONFIG_INFINIBAND_IPATH=m +# CONFIG_IOMMU_VMERGE is not set +# CONFIG_IRQSTACKS is not set +CONFIG_IRQ_ALL_CPUS=y +CONFIG_KERNEL_START=0xc000000000000000 +CONFIG_KEYS_COMPAT=y +CONFIG_LEDS_CLASS=m +CONFIG_LOCK_KERNEL=y +CONFIG_LPARCFG=y +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTPLUG_SPARSE=y +CONFIG_MIGRATION=y +CONFIG_MMC_SPI=m +CONFIG_MMIO_NVRAM=y +CONFIG_MPIC_BROKEN_REGREAD=y +CONFIG_MPIC_U3_HT_IRQS=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_NODES_SHIFT=4 +CONFIG_NODES_SPAN_OTHER_NODES=y +CONFIG_NR_CPUS=32 +CONFIG_NUMA=y +CONFIG_OPROFILE_CELL=y +CONFIG_PASEMI_MAC=m +CONFIG_PATA_PLATFORM=m +CONFIG_PMAC_SMU=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_STD_PARTITION="" +CONFIG_POWER3=y +CONFIG_POWER4=y +# CONFIG_POWER4_ONLY is not set +CONFIG_PPC64=y +CONFIG_PPC64_SWSUSP=y +# CONFIG_PPC_64K_PAGES is not set +CONFIG_PPC_970_NAP=y +CONFIG_PPC_CELL=y +# CONFIG_PPC_CELLEB is not set +CONFIG_PPC_CELL_NATIVE=y +# CONFIG_PPC_CLOCK is not set +CONFIG_PPC_DCR=y +CONFIG_PPC_DCR_MMIO=y +CONFIG_PPC_HAS_HASH_64K=y +CONFIG_PPC_IBM_CELL_BLADE=y +CONFIG_PPC_INDIRECT_IO=y +# CONFIG_PPC_INDIRECT_PCI is not set +# CONFIG_PPC_ISERIES is not set +CONFIG_PPC_MAPLE=y +CONFIG_PPC_MM_SLICES=y +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_MPC5200 is not set +# CONFIG_PPC_MPC52xx is not set +CONFIG_PPC_OF_PLATFORM_PCI=y +CONFIG_PPC_PASEMI=y +CONFIG_PPC_PASEMI_CPUFREQ=y +CONFIG_PPC_PASEMI_IOMMU=y +# CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE is not set +CONFIG_PPC_PASEMI_MDIO=m +CONFIG_PPC_PMAC64=y +CONFIG_PPC_PMI=m +CONFIG_PPC_PS3=y +CONFIG_PPC_PSERIES=y +CONFIG_PPC_SPLPAR=y +CONFIG_PREEMPT_BKL=y +CONFIG_PROC_PID_CPUSET=y +# CONFIG_PS3_ADVANCED is not set +CONFIG_PS3_DISK=m +# CONFIG_PS3_DYNAMIC_DMA is not set +CONFIG_PS3_FLASH=m +CONFIG_PS3_HTAB_SIZE=20 +CONFIG_PS3_PS3AV=y +CONFIG_PS3_ROM=m +CONFIG_PS3_STORAGE=m +CONFIG_PS3_SYS_MANAGER=y +CONFIG_PS3_USE_LPAR_ADDR=y +CONFIG_PS3_VUART=y +CONFIG_RTAS_ERROR_LOGGING=y +CONFIG_RTAS_FLASH=m +CONFIG_SCANLOG=m +CONFIG_SCHED_SMT=y +# CONFIG_SCSI_DC390T is not set +CONFIG_SCSI_IBMVSCSI=m +CONFIG_SCSI_IBMVSCSIS=m +CONFIG_SERIAL_ICOM=m +# CONFIG_SERIAL_PMACZILOG is not set +# CONFIG_SERIO_I8042 is not set +CONFIG_SMP=y +CONFIG_SND_PS3=m +CONFIG_SND_PS3_DEFAULT_START_DELAY=2000 +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPIDER_NET=m +CONFIG_SPU_BASE=y +CONFIG_SPU_FS=m +CONFIG_SPU_FS_64K_LS=y +CONFIG_STOP_MACHINE=y +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_THERM_PM72=m +# CONFIG_TUNE_CELL is not set +CONFIG_U3_DART=y +CONFIG_UDBG_RTAS_CONSOLE=y +CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-6.10-powerpc64-smp" +CONFIG_VIRT_CPU_ACCOUNTING=y +# CONFIG_WANT_DEVICE_TREE is not set +CONFIG_WINDFARM_PM112=m +CONFIG_WINDFARM_PM81=m +CONFIG_WINDFARM_PM91=m +CONFIG_WORD_SIZE=64 +CONFIG_XICS=y --- linux-2.6.24.orig/debian/control +++ linux-2.6.24/debian/control @@ -0,0 +1,839 @@ +Source: linux +Section: devel +Priority: optional +Maintainer: Ubuntu Kernel Team +Standards-Version: 3.6.1 +Build-Depends: debhelper (>= 3), module-init-tools, kernel-wedge (>= 2.24ubuntu1), gcc-4.1-hppa64 [hppa], binutils-hppa64 [hppa], device-tree-compiler [powerpc], gcc-4.1 [powerpc ia64], gawk [amd64 i386] +Build-Depends-Indep: xmlto, docbook-utils, gs, transfig, bzip2, sharutils + +Package: linux-kernel-devel +Architecture: all +Section: devel +Priority: optional +Depends: build-essential, git-core, gitk, rsync, curl, openssh-client, debhelper, kernel-package, kernel-wedge +Description: Linux kernel hacking dependencies + This is a dummy package that will install all possible packages + required to hack comfortably on the kernel. + +Package: linux-source-2.6.24 +Architecture: all +Section: devel +Priority: optional +Provides: linux-source, linux-source-2.6 +Depends: binutils, bzip2, coreutils | fileutils (>= 4.0) +Recommends: libc-dev, gcc, make +Suggests: libncurses-dev | ncurses-dev, kernel-package, libqt3-dev +Description: Linux kernel source for version 2.6.24 with Ubuntu patches + This package provides the source code for the Linux kernel version 2.6.24. + . + You may configure the kernel to your setup by typing "make config" and + following instructions, but you could get ncursesX.X-dev and try "make + menuconfig" for a jazzier, and easier to use interface. There are options + to use QT or GNOME based configuration interfaces, but they need + additional packages to be installed. Also, please read the detailed + documentation in the file + /usr/share/doc/linux-source-2.6.24/README.headers.gz. + . + If you wish to use this package to create a custom Linux kernel, then it + is suggested that you investigate the package kernel-package, which has + been designed to ease the task of creating kernel image packages. + . + If you are simply trying to build third-party modules for your kernel, + you do not want this package. Install the appropriate linux-headers + package instead. + +Package: linux-doc-2.6.24 +Architecture: all +Section: doc +Priority: optional +Provides: linux-doc-2.6 +Conflicts: linux-doc-2.6 +Replaces: linux-doc-2.6 +Depends: coreutils | fileutils (>= 4.0) +Description: Linux kernel specific documentation for version 2.6.24 + This package provides the various readme's in the 2.6.24 kernel + Documentation/ subdirectory: these typically contain kernel-specific + installation notes for some drivers for example. See + /usr/share/doc/linux-doc-2.6.24/Documentation/00-INDEX for a list of what + is contained in each file. Please read the Changes file, as it contains + information about the problems, which may result by upgrading your + kernel. + +Package: linux-headers-2.6.24-27 +Architecture: all +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0) +Provides: linux-headers, linux-headers-2.6 +Description: Header files related to Linux kernel version 2.6.24 + This package provides kernel header files for version 2.6.24, for sites + that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details + +Package: linux-libc-dev +Architecture: amd64 i386 powerpc sparc ia64 hppa lpia +Conflicts: libc6-dev (<< 2.3.2.ds1-6), libc6.1-dev (<< 2.3.2.ds1-6), dvb-dev (<< 1.0.1-6), amd64-libs-dev (<= 1.1), linux-kernel-headers +Replaces: libc6-dev (<< 2.3.2.ds1-6), libc6.1-dev (<< 2.3.2.ds1-6), dvb-dev (<< 1.0.1-6), linux-kernel-headers +Provides: linux-kernel-headers +Description: Linux Kernel Headers for development + This package provides headers from the Linux kernel. These headers + are used by the installed headers for GNU glibc and other system + libraries. + +Package: linux-image-2.6.24-27-386 +Architecture: i386 +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, kvm-api-4, ivtv-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on i386 + This package contains the Linux kernel image for version 2.6.24 on + i386. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Alternate x86 (486 and better) processors. + . + Geared toward desktop systems. + . + You likely do not want to install this package directly. Instead, install + the linux-386 meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-386 +Architecture: i386 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on i386 + This package provides kernel header files for version 2.6.24 on + i386. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-debug-2.6.24-27-386 +Architecture: i386 +Section: devel +Priority: optional +Provides: linux-debug +Description: Linux kernel debug image for version 2.6.24 on i386 + This package provides a kernel debug image for version 2.6.24 on + i386. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. + +Package: linux-image-2.6.24-27-generic +Architecture: i386 amd64 +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, kvm-api-4, redhat-cluster-modules, ivtv-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on x86/x86_64 + This package contains the Linux kernel image for version 2.6.24 on + x86/x86_64. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Generic processors. + . + Geared toward desktop systems. + . + You likely do not want to install this package directly. Instead, install + the linux-generic meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-generic +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on x86/x86_64 + This package provides kernel header files for version 2.6.24 on + x86/x86_64. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-debug-2.6.24-27-generic +Architecture: i386 amd64 +Section: devel +Priority: optional +Provides: linux-debug +Description: Linux kernel debug image for version 2.6.24 on x86/x86_64 + This package provides a kernel debug image for version 2.6.24 on + x86/x86_64. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. + +Package: linux-image-2.6.24-27-hppa32 +Architecture: hppa +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: palo +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on 32-bit HP PA-RISC SMP + This package contains the Linux kernel image for version 2.6.24 on + 32-bit HP PA-RISC SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 32-bit HP PA-RISC SMP processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-hppa32 meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-hppa32 +Architecture: hppa +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, gcc-4.1, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on 32-bit HP PA-RISC SMP + This package provides kernel header files for version 2.6.24 on + 32-bit HP PA-RISC SMP. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-hppa64 +Architecture: hppa +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: palo +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on 64-bit HP PA-RISC SMP + This package contains the Linux kernel image for version 2.6.24 on + 64-bit HP PA-RISC SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 64-bit HP PA-RISC SMP processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-hppa64 meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-hppa64 +Architecture: hppa +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, gcc-4.1-hppa64, binutils-hppa64, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on 64-bit HP PA-RISC SMP + This package provides kernel header files for version 2.6.24 on + 64-bit HP PA-RISC SMP. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-itanium +Architecture: ia64 +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules, ivtv-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: elilo (>= 3.6-1) +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on Itanium SMP + This package contains the Linux kernel image for version 2.6.24 on + Itanium SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Itanium SMP processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-itanium meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-itanium +Architecture: ia64 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, gcc-4.1, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on Itanium SMP + This package provides kernel header files for version 2.6.24 on + Itanium SMP. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-mckinley +Architecture: ia64 +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules, ivtv-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: elilo (>= 3.6-1) +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on Itanium II SMP + This package contains the Linux kernel image for version 2.6.24 on + Itanium II SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Itanium II SMP processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-mckinley meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-mckinley +Architecture: ia64 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, gcc-4.1, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on Itanium II SMP + This package provides kernel header files for version 2.6.24 on + Itanium II SMP. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-powerpc +Architecture: powerpc +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules, ivtv-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: yaboot +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on 32-bit PowerPC + This package contains the Linux kernel image for version 2.6.24 on + 32-bit PowerPC. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 32-bit PowerPC processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-powerpc +Architecture: powerpc +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, gcc-4.1, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on 32-bit PowerPC + This package provides kernel header files for version 2.6.24 on + 32-bit PowerPC. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-powerpc-smp +Architecture: powerpc +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules, ivtv-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: yaboot +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on 32-bit PowerPC SMP + This package contains the Linux kernel image for version 2.6.24 on + 32-bit PowerPC SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 32-bit PowerPC SMP processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc-smp meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-powerpc-smp +Architecture: powerpc +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, gcc-4.1, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on 32-bit PowerPC SMP + This package provides kernel header files for version 2.6.24 on + 32-bit PowerPC SMP. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-powerpc64-smp +Architecture: powerpc +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules, ivtv-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: yaboot +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on 64-bit PowerPC SMP + This package contains the Linux kernel image for version 2.6.24 on + 64-bit PowerPC SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 64-bit PowerPC SMP processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-powerpc64-smp meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-powerpc64-smp +Architecture: powerpc +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, gcc-4.1, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on 64-bit PowerPC SMP + This package provides kernel header files for version 2.6.24 on + 64-bit PowerPC SMP. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-server +Architecture: i386 amd64 +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules, kvm-api-4, ivtv-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on x86/x86_64 + This package contains the Linux kernel image for version 2.6.24 on + x86/x86_64. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Server processors. + . + Geared toward server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-server meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-server +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on x86/x86_64 + This package provides kernel header files for version 2.6.24 on + x86/x86_64. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-debug-2.6.24-27-server +Architecture: i386 amd64 +Section: devel +Priority: optional +Provides: linux-debug +Description: Linux kernel debug image for version 2.6.24 on x86/x86_64 + This package provides a kernel debug image for version 2.6.24 on + x86/x86_64. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. + +Package: linux-image-2.6.24-27-sparc64 +Architecture: sparc +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules, ivtv-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: silo +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on 64-bit UltraSPARC + This package contains the Linux kernel image for version 2.6.24 on + 64-bit UltraSPARC. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 64-bit UltraSPARC processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-sparc64 meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-sparc64 +Architecture: sparc +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on 64-bit UltraSPARC + This package provides kernel header files for version 2.6.24 on + 64-bit UltraSPARC. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-sparc64-smp +Architecture: sparc +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules, ivtv-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: silo +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on 64-bit UltraSPARC SMP + This package contains the Linux kernel image for version 2.6.24 on + 64-bit UltraSPARC SMP. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports 64-bit UltraSPARC SMP processors. + . + Geared toward desktop or server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-sparc64-smp meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-sparc64-smp +Architecture: sparc +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on 64-bit UltraSPARC SMP + This package provides kernel header files for version 2.6.24 on + 64-bit UltraSPARC SMP. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-virtual +Architecture: i386 +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, kvm-api-4, redhat-cluster-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on x86 + This package contains the Linux kernel image for version 2.6.24 on + x86. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Virtual processors. + . + Geared toward virtualised hardware. + . + You likely do not want to install this package directly. Instead, install + the linux-virtual meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-virtual +Architecture: i386 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on x86 + This package provides kernel header files for version 2.6.24 on + x86. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-debug-2.6.24-27-virtual +Architecture: i386 +Section: devel +Priority: optional +Provides: linux-debug +Description: Linux kernel debug image for version 2.6.24 on x86 + This package provides a kernel debug image for version 2.6.24 on + x86. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. + +Package: linux-image-2.6.24-27-lpia +Architecture: lpia +Section: universe/base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, kvm-api-4, redhat-cluster-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on Ubuntu Moblie and Embedded LPIA edition + This package contains the Linux kernel image for version 2.6.24 on + Ubuntu Moblie and Embedded LPIA edition. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports UME processors. + . + UME kernel + . + You likely do not want to install this package directly. Instead, install + the linux-lpia meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-lpia +Architecture: lpia +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on Ubuntu Moblie and Embedded LPIA edition + This package provides kernel header files for version 2.6.24 on + Ubuntu Moblie and Embedded LPIA edition. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-rt +Architecture: i386 amd64 +Section: universe/base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, kvm-api-4, redhat-cluster-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on Ingo Molnar's full real time preemption patch (2.6.24.7-rt27) + This package contains the Linux kernel image for version 2.6.24 on + Ingo Molnar's full real time preemption patch (2.6.24.7-rt27). + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Generic processors. + . + RT kernel + . + You likely do not want to install this package directly. Instead, install + the linux-rt meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-rt +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on Ingo Molnar's full real time preemption patch (2.6.24.7-rt27) + This package provides kernel header files for version 2.6.24 on + Ingo Molnar's full real time preemption patch (2.6.24.7-rt27). + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-lpiacompat +Architecture: lpia +Section: universe/base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, kvm-api-4, redhat-cluster-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on Ubuntu Moblie and Embedded-x86 compat edition + This package contains the Linux kernel image for version 2.6.24 on + Ubuntu Moblie and Embedded-x86 compat edition. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports UME processors. + . + UME kernel + . + You likely do not want to install this package directly. Instead, install + the linux-lpiacompat meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-lpiacompat +Architecture: lpia +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on Ubuntu Moblie and Embedded-x86 compat edition + This package provides kernel header files for version 2.6.24 on + Ubuntu Moblie and Embedded-x86 compat edition. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-xen +Architecture: i386 amd64 +Section: universe/base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, kvm-api-4, redhat-cluster-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: grub +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on This kernel can be used for Xen dom0 and domU + This package contains the Linux kernel image for version 2.6.24 on + This kernel can be used for Xen dom0 and domU. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Generic processors. + . + Xen domO/domU + . + You likely do not want to install this package directly. Instead, install + the linux-xen meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-xen +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on This kernel can be used for Xen dom0 and domU + This package provides kernel header files for version 2.6.24 on + This kernel can be used for Xen dom0 and domU. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. + +Package: linux-image-2.6.24-27-openvz +Architecture: i386 amd64 +Section: universe/base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, kvm-api-4, redhat-cluster-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.24 | linux-source-2.6.24 +Description: Linux kernel image for version 2.6.24 on OpenVZ Virtualization enabled kernel + This package contains the Linux kernel image for version 2.6.24 on + OpenVZ Virtualization enabled kernel. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Generic processors. + . + OpenVZ kernel + . + You likely do not want to install this package directly. Instead, install + the linux-openvz meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.24-27-openvz +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.24-27, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.24 on OpenVZ Virtualization enabled kernel + This package provides kernel header files for version 2.6.24 on + OpenVZ Virtualization enabled kernel. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.24-27/debian.README.gz for details. --- linux-2.6.24.orig/debian/scripts/abi-check +++ linux-2.6.24/debian/scripts/abi-check @@ -0,0 +1,44 @@ +#!/bin/bash -e + +flavour="$1" +prev_abinum="$2" +abinum="$3" +prev_abidir="$4" +abidir="$5" +skipabi="$6" + +echo -n "Checking ABI for $flavour..." + +if [ -f "$prev_abidir/ignore" -o -f "$prev_abidir/$flavour.ignore" -o -n "$skipabi" ]; then + echo "explicitly asked to ignore ABI (probably not good)" + exit +fi + +if [ "$prev_abinum" = "0" -o "$prev_abinum" != "$abinum" ]; then + echo "different ABI numbers, no check needed." + exit +fi + +if [ ! -f "$abidir/$flavour" -o ! -f "$prev_abidir/$flavour" ]; then + echo "previous or current ABI file missing!" + echo " $abidir/$flavour" + echo " $prev_abidir/$flavour" + exit 1 +fi + +if [ "`diff -u $prev_abidir/$flavour $abidir/$flavour | grep ^-[^-] | wc -l`" != "0" ] +then + echo "check FAILED (nice one Tonto, go get the Lone Ranger)" + diff -u $prev_abidir/$flavour $abidir/$flavour + exit 1 +fi + +if [ "`diff -u $prev_abidir/$flavour $abidir/$flavour | grep ^+[^+] | wc -l`" != "0" ] +then + echo "new symbols in ABI (continuing reluctantly)" + diff -u $prev_abidir/$flavour $abidir/$flavour || true + exit +fi + +echo "check PASSED (good job, you saved yourself some work)" +exit --- linux-2.6.24.orig/debian/scripts/link-headers +++ linux-2.6.24/debian/scripts/link-headers @@ -0,0 +1,79 @@ +#!/bin/bash -e + +hdrdir="$1" +symdir="$2" +srcdir="$3" +build_arch="$4" +flavour="$5" + +echo "Symlinking and copying headers for $flavour..." + +# XXX Special case for ppc +if [ "$build_arch" = "powerpc" ]; then + install -d -m755 $hdrdir/arch/powerpc/include + ln -fsn ../../../include/asm-ppc $hdrdir/arch/powerpc/include/asm +fi + +excludes='( -path ./debian -prune -o -path ./.git ) -prune -o' + +# For custom builds, we have to take care of a few things. First, we want +# to check for files to symlink and copy in the srcdir, not the stock src. +# We compare against stock source, copying for files that aren't the same, +# and later symlinking for same files. +if [ -n "$srcdir" ]; then + ( + cd $srcdir + find . $excludes -type f \ + \( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Kbuild*' -o \ + -name '*.sh' -o -name '*.pl' -o -name '*.lds' \) -print + find ./include ./scripts -name .gitignore -prune -o -type f -print + ) | ( + while read file; do + if [ -e "$hdrdir/$file" ]; then + continue + fi + + # If the files are not the same, copy it + if ! cmp -s "$file" "$srcdir/$file"; then + echo $file + fi + done + ) | ( + cd $srcdir + cpio -pd --preserve-modification-time "$hdrdir" + ) +else + srcdir="." +fi + +( +cd $srcdir +find . $excludes -type f \ + \( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Kbuild*' -o \ + -name '*.sh' -o -name '*.pl' -o -name '*.lds' \) -print +find ./include ./scripts -name .gitignore -prune -o -type f -print +find ./include -mindepth 1 -maxdepth 1 $excludes -type d -print +) | ( +while read file; do + dir=$file + lastdir=$file + + if [ -f "$hdrdir/$file" ]; then + continue + fi + + while [ ! -e "$hdrdir/$dir" -a ! -L "$hdrdir/$dir" ]; do + lastdir=$dir + dir=`dirname $dir` + done + # If the last item to exist is a symlink we assume all is good + if [ ! -L "$hdrdir/$dir" ]; then + # Turns things like "./foo" into "../" + deref="`echo -n $lastdir | sed -e 's/^\.//' -e's,/[^/]*,../,g'`" + item="`echo -n $lastdir | sed -e 's/^\.\///'`" + ln -s $deref$symdir/$item $hdrdir/$item + fi +done +) + +exit --- linux-2.6.24.orig/debian/scripts/control-create +++ linux-2.6.24/debian/scripts/control-create @@ -0,0 +1,33 @@ +#!/bin/bash + +stub=debian/control.d/flavour-control.stub +dstub=debian/control.d/flavour-control-debug.stub +vars=$1 + +# Defaults +section_image=base +section_headers=devel + +. $vars + +flavour=$(basename $vars | sed 's/.*\.//') +# Custom is a little different +if [ "$flavour" = "vars" ]; then + flavour=$(basename `dirname $vars`) +fi + +if [ -n "$do_debug" ]; then + stub="$stub $dstub" +fi + +cat $stub | grep -v '^#' | sed \ + -e "s#FLAVOUR#$flavour#g" \ + -e "s#DESC#$desc#g" \ + -e "s#ARCH#$arch#g" \ + -e "s#SUPPORTED#$supported#g" \ + -e "s#TARGET#$target#g" \ + -e "s#BOOTLOADER#$bootloader#g" \ + -e "s#=PROVIDES=#$provides#g" \ + -e "s#SECTION_IMAGE#$section_image#g" \ + -e "s#SECTION_HEADERS#$section_headers#g" \ + -e "s#=HEADER_DEPENDS=#$header_depends#g" --- linux-2.6.24.orig/debian/scripts/module-check +++ linux-2.6.24/debian/scripts/module-check @@ -0,0 +1,119 @@ +#!/usr/bin/perl -w + +$flavour = shift; +$prev_abidir = shift; +$abidir = shift; +$skipmodule = shift; + +print "II: Checking modules for $flavour..."; + +if (-f "$prev_abidir/ignore.modules" + or -f "$prev_abidir/$flavour.ignore.modules") { + print "explicitly ignoring modules\n"; + exit(0); +} + +if (not -f "$abidir/$flavour.modules" or not -f + "$prev_abidir/$flavour.modules") { + print "previous or current modules file missing!\n"; + print " $abidir/$flavour.modules\n"; + print " $prev_abidir/$flavour.modules\n"; + if (defined($skipmodule)) { + exit(0); + } else { + exit(1); + } +} + +print "\n"; + +my %modules; +my %modules_ignore; +my $missing = 0; +my $new = 0; +my $errors = 0; + +# See if we have any ignores +if (-f "$prev_abidir/../modules.ignore") { + my $ignore = 0; + open(IGNORE, "< $prev_abidir/../modules.ignore") or + die "Could not open $prev_abidir/../modules.ignore"; + print " reading modules to ignore..."; + while () { + chomp; + $modules_ignore{$_} = 1; + $ignore++; + } + close(IGNORE); + print "read $ignore modules.\n"; +} + +# Read new modules first +print " reading new modules..."; +$new_count = 0; +open(NEW, "< $abidir/$flavour.modules") or + die "Could not open $abidir/$flavour.modules"; +while () { + chomp; + $modules{$_} = 1; + $new_count++; +} +close(NEW); +print "read $new_count modules.\n"; + +# Now the old modules, checking for missing ones +print " reading old modules..."; +$old_count = 0; +open(OLD, "< $prev_abidir/$flavour.modules") or + die "Could not open $prev_abidir/$flavour.modules"; +while () { + chomp; + if (not defined($modules{$_})) { + print "\n" if not $missing; + $missing++; + if (not defined($modules_ignore{$_})) { + print " MISS: $_\n"; + $errors++; + } else { + print " MISS: $_ (ignored)\n"; + } + } else { + $modules{$_}++; + } + $old_count++; +} +close(OLD); +# Check for new modules +foreach $mod (keys(%modules)) { + if ($modules{$mod} < 2) { + print "\n" if not $missing and not $new; + print " NEW : $mod\n"; + $new++; + } +} +if ($new or $missing) { + print " read $old_count modules : new($new) missing($missing)\n"; +} else { + print "read $old_count modules.\n"; +} + + +# Let's see where we stand... +if ($errors) { + if (defined($skipmodule)) { + print "WW: Explicitly asked to ignore failures (probably not good)\n"; + } else { + print "EE: Missing modules (start begging for mercy)\n"; + exit 1 + } +} + +if ($new) { + print "II: New modules (you've been busy, wipe the poop off your nose)\n"; +} else { + print "II: No new modules (hope you're happy, slacker)\n"; +} + +print "II: Done\n"; + +exit(0); --- linux-2.6.24.orig/debian/scripts/misc/oldconfig +++ linux-2.6.24/debian/scripts/misc/oldconfig @@ -0,0 +1,66 @@ +#!/bin/bash + +# We have to be in the top level kernel source directory +if [ ! -f MAINTAINERS ] || [ ! -f Makefile ]; then + echo "This does not appear to be the kernel source directory." 1>&2 + exit 1 +fi + + +# One arg, and that's it. Just pass an architecture +if [ $# -ne 1 ]; then + echo "Usage: $0 " 1>&2 + exit 1 +fi + +arch="$1" + +case "$arch" in + sparc) kernarch="sparc64" ;; + amd64) kernarch="x86_64" ;; + hppa) kernarch="parisc" ;; + lpia) kernarch="i386" ;; + *) kernarch="$arch" ;; +esac + +confdir="`pwd`/debian/config/$arch" +bindir="`pwd`/debian/scripts/misc" + +# Make sure the architecture exists +if [ ! -d $confdir ]; then + echo "Could not find config directory for $arch" 1>&2 + exit 1 +fi + +echo "Processing $arch ($kernarch) ... " + +configs=$(cd $confdir && ls config.*) + +if [ -f $confdir/config ]; then + for config in $configs; do + case $config in + *) + cat $confdir/config >> $confdir/$config + ;; + esac + done + rm -f $confdir/config +fi + +test -d build || mkdir build +cd build +for config in $configs; do + echo "Running silentoldconfig for $config ... " + + cat $confdir/$config > .config + + make -C ../ O=`pwd` silentoldconfig ARCH=$kernarch + + cat .config > $confdir/$config +done +cd .. + +echo "Running splitconfig.pl ... " +echo + +(cd $confdir ; $bindir/splitconfig.pl) --- linux-2.6.24.orig/debian/scripts/misc/insert-changes.pl +++ linux-2.6.24/debian/scripts/misc/insert-changes.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl -w + +system("make -s -f debian/rules printchanges > debian/changes"); + +open(CHANGELOG, "< debian/changelog") or die "Cannot open changelog"; +open(CHANGES, "< debian/changes") or die "Cannot open new changes"; +open(NEW, "> debian/changelog.new") or die "Cannot open new changelog"; + +$printed = 0; + +while () { + if (/^ CHANGELOG: /) { + next if $printed; + + while () { + print NEW; + } + + $printed = 1; + } else { + print NEW; + } +} + +close(NEW); +close(CHANGES); +close(CHANGELOG); + +rename("debian/changelog.new", "debian/changelog"); +unlink("debian/changes"); --- linux-2.6.24.orig/debian/scripts/misc/getabis +++ linux-2.6.24/debian/scripts/misc/getabis @@ -0,0 +1,86 @@ +#!/bin/bash + +if [ "$#" != "2" ]; then + echo "Usage: $0 " 1>&2 + exit 1 +fi + +ver=$1 +revision=$2 +abi=$(echo $revision | awk -F. '{print $1}') + +verabi=$ver-$abi +verfull=$ver-$revision + +repo="http://archive.ubuntu.com/ubuntu/pool/main/l" +repo_ports="http://ports.ubuntu.com/ubuntu-ports/pool/main/l" +repo_uni="http://archive.ubuntu.com/ubuntu/pool/universe/l" + +WGET="wget --quiet -c" + +abidir="`pwd`/debian/abi/$verfull" +tmpdir="`pwd`/abi-tmp-$verfull" +origdir="`pwd`" + +test -d $tmpdir || mkdir $tmpdir + +getall() { + arch=$1 + shift + + mkdir -p $abidir/$arch + + for sub in $@; do + if [ -f $abidir/$arch/$sub ]; then + echo "Exists: $sub" + continue + fi + echo -n "Fetching $sub..." + filename=linux-image-${verabi}-${sub}_${verfull}_${arch}.deb + cd $tmpdir + if ! [ -f $filename ]; then + $WGET $repo/linux/$filename + fi + if ! [ -f $filename ]; then + $WGET $repo_ports/linux/$filename + fi + if ! [ -f $filename ]; then + $WGET $repo_uni/linux/$filename + fi + if [ "$?" = "0" ]; then + echo -n "extracting..." + dpkg-deb --extract $filename tmp + if [ -f tmp/boot/abi-* ]; then + mv tmp/boot/abi-* $abidir/$arch/$sub + else + echo -n "NO ABI FILE..." + fi + (cd tmp; find lib/modules/$verabi-$sub/kernel -name '*.ko') | \ + sed -e 's/.*\/\([^\/]*\)\.ko/\1/' | sort > \ + $abidir/$arch/$sub.modules + rm -rf tmp $filename + echo "done." + else + echo "FAILED." + fi + cd $origdir + done +} + +# MAIN + +# Setup abi directory +mkdir -p $abidir +echo $abi > $abidir/abiname + +# NOTE: The flavours are hardcoded, because they may have changed from the +# current build. + +getall powerpc powerpc{,-smp,64-smp} +getall amd64 generic server +getall i386 386 generic server virtual +getall sparc sparc64{,-smp} +getall ia64 itanium mckinley +getall hppa hppa32 hppa64 + +rmdir $tmpdir --- linux-2.6.24.orig/debian/scripts/misc/ppa-cron-job +++ linux-2.6.24/debian/scripts/misc/ppa-cron-job @@ -0,0 +1,47 @@ +#!/bin/sh + +# +# Use this script as a template for the daily kernel build cron job. +# You should copy it somewhere outside of the git tree 'cause the whole +# git tree gets removed and recreated. +# +KNAME=hardy +DAILY_BUILD_DIR=${KBDIR:=${HOME}/${KNAME}} +KERNEL_GIT_REPO=${KREPO:=/srv/kernel.ubuntu.com/git/ubuntu/ubuntu-${KNAME}.git} + +# +# Nothing works unless there is a dput configuration. +# +if [ ! -f ${HOME}/.dput.cf ] +then + echo No dput configuration. + exit 1 +fi + +if [ ! -d ${DAILY_BUILD_DIR} ] +then + rm -rf ${DAILY_BUILD_DIR} + mkdir -p ${DAILY_BUILD_DIR} +fi + +# +# Start with a fresh repo. +# +cd ${DAILY_BUILD_DIR} +rm -rf ubuntu-${KNAME} +git clone ${KERNEL_GIT_REPO} + +# +# Remember that the success of prepare-ppa depends on +# this user account having an un-passworded GPG key. +# Otherwise it requires user intervention, e.g., a +# user must enter the GPG key password. +# +rm -f *.changes +(cd ubuntu-${KNAME}; debian/scripts/misc/prepare-ppa-source) + +find . -maxdepth 1 -type f -name "*.changes" | while read f +do + echo dput my-ppa $f +done + --- linux-2.6.24.orig/debian/scripts/misc/splitconfig.pl +++ linux-2.6.24/debian/scripts/misc/splitconfig.pl @@ -0,0 +1,110 @@ +#!/usr/bin/perl -w + +%configs = (); +%common = (); + +print "Reading config's ...\n"; + +opendir(DIR, "."); + +while (defined($config = readdir(DIR))) { + # Only config.* + next if $config !~ /^config\..*/; + # Nothing that is disabled, or remnant + next if $config =~ /.*\.(default|disabled|stub)$/; + # Server config's are standalone + #next if $config =~ /config.server-.*/; + + %{$configs{$config}} = (); + + print " processing $config ... "; + + open(CONFIG, "< $config"); + + while () { + /^#*\s*CONFIG_(\w+)[\s=](.*)$/ or next; + + ${$configs{$config}}{$1} = $2; + + $common{$1} = $2; + } + + close(CONFIG); + + print "done.\n"; +} + +closedir(DIR); + +print "\n"; + +print "Merging lists ... \n"; + +for $config (keys(%configs)) { + my %options = %{$configs{$config}}; + + print " processing $config ... "; + + for $key (keys(%common)) { + next if not defined $common{$key}; + + # If we don't have the common option, then it isn't + # common. If we do have that option, it must have the same + # value (this is where the old split.py was broken). It + # also did the common check while it was parsing files, so + # that there were cases where a non-common option was in + # common anyway (ordering). + if (not defined($options{$key})) { + undef $common{$key}; + } elsif ($common{$key} ne $options{$key}) { + undef $common{$key}; + } + } + + print "done.\n"; +} + +print "\n"; + +print "Creating common config ... "; + +open(COMMON, "> config"); +print COMMON "#\n# Common config options automatically generated by splitconfig.pl\n#\n"; + +for $key (sort(keys(%common))) { + next if not defined $common{$key}; + + if ($common{$key} eq "is not set") { + print COMMON "# CONFIG_$key is not set\n"; + } else { + print COMMON "CONFIG_$key=$common{$key}\n"; + } +} +close(COMMON); + +print "done.\n\n"; + +print "Creating stub configs ...\n"; + +for $config (keys(%configs)) { + my %options = %{$configs{$config}}; + + print " processing $config ... "; + + open(STUB, "> $config"); + print STUB "#\n# Config options for $config automatically generated by splitconfig.pl\n#\n"; + + for $key (sort(keys(%options))) { + next if defined $common{$key}; + + if ($options{$key} eq "is not set") { + print STUB "# CONFIG_$key is not set\n"; + } else { + print STUB "CONFIG_$key=$options{$key}\n"; + } + } + + close(STUB); + + print "done.\n"; +} --- linux-2.6.24.orig/debian/scripts/misc/doconfig +++ linux-2.6.24/debian/scripts/misc/doconfig @@ -0,0 +1,67 @@ +#!/bin/bash + +# We have to be in the top level kernel source directory +if [ ! -f MAINTAINERS ] || [ ! -f Makefile ]; then + echo "This does not appear to be the kernel source directory." 1>&2 + exit 1 +fi + + +# One arg, and that's it. Just pass an architecture +if [ $# -ne 1 ]; then + echo "Usage: $0 " 1>&2 + exit 1 +fi + +arch="$1" + +case "$arch" in + sparc) kernarch="sparc64" ;; + amd64) kernarch="x86_64" ;; + hppa) kernarch="parisc" ;; + lpia) kernarch="i386" ;; + *) kernarch="$arch" ;; +esac + +confdir="`pwd`/debian/config/$arch" +bindir="`pwd`/debian/scripts/misc" + +# Make sure the architecture exists +if [ ! -d $confdir ]; then + echo "Could not find config directory for $arch" 1>&2 + exit 1 +fi + +echo "Processing $arch ($kernarch) ... " + +configs=$(cd $confdir && ls config.*) + +if [ -f $confdir/config ]; then + for config in $configs; do + case $config in + *) + cat $confdir/config >> $confdir/$config + ;; + esac + done + rm -f $confdir/config +fi + +test -d build || mkdir build +cd build +for config in $configs; do + + cat $confdir/$config > .config + + echo About to configure $arch $config + read + make -C ../ O=`pwd` ARCH=$kernarch menuconfig + + cat .config > $confdir/$config +done +cd .. + +echo "Running splitconfig.pl ... " +echo + +(cd $confdir ; $bindir/splitconfig.pl) --- linux-2.6.24.orig/debian/scripts/misc/git-ubuntu-log +++ linux-2.6.24/debian/scripts/misc/git-ubuntu-log @@ -0,0 +1,243 @@ +#!/usr/bin/perl -w + +use strict; +use Text::Wrap; + +my $kernel_auth = "Upstream Kernel Changes"; + +my (%map, @reverts); +my $pstate = 1; +my $no_kern_log = 0; +my $print_shas = 0; +my $first_print = 1; + +while (@ARGV) { + my $opt = $ARGV[0]; + shift; + if ($opt eq "--no-kern-log") { + $no_kern_log = 1; + } elsif ($opt eq "--print-shas") { + $print_shas = 1; + } else { + print STDERR "Unknown options: $opt\n"; + exit(1); + } +} + +sub check_reverts($) { + my ($entry) = @_; + my ($check); + + foreach $check (reverse @reverts) { + my $desc = "Revert \"" . $entry->{'desc'} . "\""; + if ($check->{'desc'} eq $desc) { + @reverts = grep($_->{'desc'} ne $desc, @reverts); + return 1; + } + } + + return 0; +} + +sub add_entry($) { + my ($entry) = @_; + my $key = $entry->{'author'}; + + # store description in array, in email->{desc list} map + if (exists $map{$key}) { + # grab ref + my $obj = $map{$key}; + + # add desc to array + push(@$obj, $entry); + } else { + # create new array, containing 1 item + my @arr = ($entry); + + # store ref to array + $map{$key} = \@arr; + } +} + +sub shortlog_entry($$$$$) { + my ($name, $desc, $bug, $cve, $commit) = @_; + my $entry; + + $desc =~ s#/pub/scm/linux/kernel/git/#/.../#g; + $desc =~ s#\[PATCH\] ##g; + + $desc =~ s#^\s*##g; + $desc =~ s# *UBUNTU: ##g; + + $entry->{'desc'} = $desc; + if ($bug ne '') { + $entry->{'bugno'} = $bug; + } + $entry->{'cve'} = $cve; + $entry->{'commit'} = $commit; + $entry->{'author'} = $name; + + if ($desc =~ /^Revert "/) { + push(@reverts, $entry); + return; + } + + return if check_reverts($entry); + + add_entry($entry); +} + +# sort comparison function +sub by_name($$) { + my ($a, $b) = @_; + + uc($a) cmp uc($b); +} + +sub shortlog_output { + my ($obj, $key, $entry); + + foreach $key (sort by_name keys %map) { + next if $key eq $kernel_auth and $no_kern_log; + + print "\n" unless $first_print; + $first_print = 0; + + # output author + printf " [%s]\n\n", $key; + + # output author's 1-line summaries + $obj = $map{$key}; + foreach $entry (reverse @$obj) { + print wrap(" * ", " ", $entry->{'desc'}) . "\n"; + # For non upstream changes, add other info. + if ($key ne $kernel_auth) { + if ($print_shas) { + print " - GIT-SHA " . $entry->{'commit'} . + "\n"; + } + } + if (defined($entry->{'bugno'})) { + print " - LP: #" . $entry->{'bugno'} . "\n"; + } + if (defined($entry->{'cve'})) { + print " - " . $entry->{'cve'} . "\n"; + } + } + } +} + +sub changelog_input { + my ($author, $desc, $commit, $entry, $cve); + + while () { + # get commit + if ($pstate == 1) { + next unless /^commit (.*)/; + + $commit = $1; + + $pstate++; + } + + # get author and email + elsif ($pstate == 2) { + my ($email); + + next unless /^[Aa]uthor:?\s*(.*?)\s*<(.*)>/; + + $author = $1; + $email = $2; + $desc = undef; + $cve = undef; + + # cset author fixups + if (!$author) { + $author = $email; + } + $pstate++; + } + + # skip to blank line + elsif ($pstate == 3) { + next unless /^\s*$/; + $pstate++; + } + + # skip to non-blank line + elsif ($pstate == 4) { + next unless /^\s*?(.*)/; + my $ignore = 0; + my $bug = undef; + my %bugz = (); + my $k; + + # skip lines that are obviously not + # a 1-line cset description + next if /^\s*From: /; + + chomp; + $desc = $1; + + if ($desc =~ /^ *(Revert "|)UBUNTU:/) { + while () { + $ignore = 1 if /^ *Ignore: yes/i; + if (/^ *Bug: *(#|)(.*)/i) { + foreach $k (split('(,|)*\s*#', $2)) { + $bugz{$k} = 1 if (($k ne '') and ($k =~ /[0-9]+/)); + } + } + elsif (/^ *BugLink: *http.*:\/\/.*\/([0-9]+)/i) { + $bugz{$1} = 1; + } + elsif (/^ *(CVE-.*)/) { + $cve = $1 + } + last if /^commit /; + } + } else { + $author = $kernel_auth; + $ignore = 1 if $desc =~ /Merge /; + while () { + if (/^ *Bug: *(#|)(.*)/i) { + foreach $k (split('(,|)*\s*#', $2)) { + $bugz{$k} = 1 if (($k ne '') and ($k =~ /[0-9]+/)); + } + } + elsif (/^ *BugLink: *http.*:\/\/.*\/([0-9]+)/i) { + $bugz{$1} = 1; + } + elsif (/^ *(CVE-.*)/) { + $cve = $1 + } + last if /^commit /; + } + } + + $bug = join(", #", keys(%bugz)); + if (!$ignore) { + &shortlog_entry($author, $desc, $bug, + $cve, $commit, 0); + } + + $pstate = 1; + if ($_ && /^commit (.*)/) { + $commit = $1; + $pstate++; + } + } + + else { + die "invalid parse state $pstate"; + } + } + + foreach $entry (@reverts) { + add_entry($entry); + } +} + +&changelog_input; +&shortlog_output; + +exit(0); --- linux-2.6.24.orig/debian/stamps/keep-dir +++ linux-2.6.24/debian/stamps/keep-dir @@ -0,0 +1 @@ +Place holder --- linux-2.6.24.orig/debian/binary-custom.d/lpia/rules +++ linux-2.6.24/debian/binary-custom.d/lpia/rules @@ -0,0 +1 @@ +# Nothing special here --- linux-2.6.24.orig/debian/binary-custom.d/lpia/vars +++ linux-2.6.24/debian/binary-custom.d/lpia/vars @@ -0,0 +1,7 @@ +arch="lpia" +supported="UME" +desc="Ubuntu Moblie and Embedded LPIA edition" +target="UME kernel" +bootloader="lilo (>= 19.1) | grub" +provides="kvm-api-4, redhat-cluster-modules" +section_image="universe/base" --- linux-2.6.24.orig/debian/binary-custom.d/lpia/config.lpia +++ linux-2.6.24/debian/binary-custom.d/lpia/config.lpia @@ -0,0 +1,3473 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.24.3 +# Thu Jun 12 15:05:41 2008 +# +# CONFIG_64BIT is not set +CONFIG_X86_32=y +# CONFIG_X86_64 is not set +CONFIG_X86=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_SEMAPHORE_SLEEPERS=y +CONFIG_MMU=y +CONFIG_ZONE_DMA=y +CONFIG_QUICKLIST=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_DMI=y +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME_VSYSCALL is not set +CONFIG_ARCH_SUPPORTS_OPROFILE=y +# CONFIG_ZONE_DMA32 is not set +CONFIG_ARCH_POPULATES_NODE_MAP=y +# CONFIG_AUDIT_ARCH is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_X86_SMP=y +CONFIG_X86_HT=y +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_TRAMPOLINE=y +CONFIG_KTIME_SCALAR=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_VERSION_SIGNATURE="Unofficial" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_TREE=y +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_CGROUPS is not set +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_FAIR_USER_SCHED=y +# CONFIG_FAIR_CGROUP_SCHED is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_LSM_MMAP_MIN_ADDR=0 + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# +# Processor type and features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_SMP=y +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_X86_VSMP is not set +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_GUEST=y +CONFIG_VMI=y +CONFIG_LGUEST_GUEST=y +# CONFIG_M386 is not set +# CONFIG_M486 is not set +CONFIG_M586=y +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MEFFICEON is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_GENERIC_CPU is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_XADD=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_F00F_BUG=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_MINIMUM_CPU_FAMILY=4 +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_NR_CPUS=8 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_BKL=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_MCE=y +# CONFIG_X86_MCE_NONFATAL is not set +# CONFIG_X86_MCE_P4THERMAL is not set +CONFIG_VM86=y +# CONFIG_TOSHIBA is not set +# CONFIG_I8K is not set +CONFIG_X86_REBOOTFIXUPS=y +CONFIG_MICROCODE=m +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m +CONFIG_NOHIGHMEM=y +# CONFIG_HIGHMEM4G is not set +# CONFIG_HIGHMEM64G is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +# CONFIG_X86_PAE is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_SPARSEMEM_STATIC=y +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_NR_QUICK=1 +CONFIG_VIRT_TO_BUS=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +CONFIG_EFI=y +# CONFIG_IRQBALANCE is not set +CONFIG_BOOT_IOREMAP=y +CONFIG_SECCOMP=y +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_KEXEC=y +CONFIG_PHYSICAL_START=0x100000 +CONFIG_RELOCATABLE=y +CONFIG_PHYSICAL_ALIGN=0x100000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_COMPAT_VDSO is not set + +# +# Power management options +# +CONFIG_PM=y +CONFIG_PM_LEGACY=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_VERBOSE is not set +CONFIG_PM_TRACE=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SUSPEND=y +CONFIG_PM_DISABLE_CONSOLE=y +CONFIG_HIBERNATION_SMP_POSSIBLE=y +CONFIG_HIBERNATION=y +CONFIG_PM_STD_PARTITION="" +CONFIG_ACPI=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_PROCFS=y +CONFIG_ACPI_PROCFS_POWER=y +CONFIG_ACPI_SYSFS_POWER=y +CONFIG_ACPI_PROC_EVENT=y +CONFIG_ACPI_AC=y +CONFIG_ACPI_BATTERY=y +CONFIG_ACPI_BUTTON=y +CONFIG_ACPI_VIDEO=y +CONFIG_ACPI_FAN=y +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_BAY=m +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_THERMAL=y +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_ACPI_CUSTOM_DSDT_INITRD=y +CONFIG_ACPI_BLACKLIST_YEAR=2000 +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_SBS=y +# CONFIG_APM is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_POWERNOW_K6 is not set +# CONFIG_X86_POWERNOW_K7 is not set +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_GX_SUSPMOD is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +CONFIG_X86_SPEEDSTEP_ICH=m +# CONFIG_X86_SPEEDSTEP_SMI is not set +# CONFIG_X86_P4_CLOCKMOD is not set +# CONFIG_X86_CPUFREQ_NFORCE2 is not set +# CONFIG_X86_LONGRUN is not set +# CONFIG_X86_LONGHAUL is not set +# CONFIG_X86_E_POWERSAVER is not set + +# +# shared options +# +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_SPEEDSTEP_LIB=m +CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y + +# +# Bus options (PCI etc.) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_LEGACY=y +# CONFIG_PCI_DEBUG is not set +CONFIG_HT_IRQ=y +CONFIG_ISA_DMA_API=y +# CONFIG_ISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set +CONFIG_K8_NB=y +# CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# Executable file formats / Emulations +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=m + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_LRO=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +# CONFIG_DEFAULT_BIC is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_HTCP is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFAULT_RENO=y +CONFIG_DEFAULT_TCP_CONG="reno" +CONFIG_TCP_MD5SIG=y +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_NETWORK_SECMARK=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m + +# +# IP: Netfilter Configuration +# +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_SIP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_RAW=m + +# +# DECnet: Netfilter Configuration +# +CONFIG_DECNET_NF_GRABULATOR=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_IP_DCCP_ACKVEC=y + +# +# DCCP CCIDs Configuration (EXPERIMENTAL) +# +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +CONFIG_IP_DCCP_TFRC_LIB=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 + +# +# DCCP Kernel Hacking +# +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_NET_DCCPPROBE=m +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +CONFIG_ATM=y +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_DECNET=m +# CONFIG_DECNET_ROUTER is not set +CONFIG_LLC=m +CONFIG_LLC2=m +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RR=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +# CONFIG_NET_CLS_POLICE is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +CONFIG_NET_TCPPROBE=m +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m +CONFIG_KINGSUN_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KS959_DONGLE=m + +# +# Old SIR device drivers +# + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +CONFIG_WINBOND_FIR=m +CONFIG_TOSHIBA_FIR=m +CONFIG_SMC_IRCC_FIR=m +CONFIG_ALI_FIR=m +CONFIG_VLSI_FIR=m +CONFIG_VIA_FIR=m +CONFIG_MCS_FIR=m +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIVHCI=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_RXKAD=m +CONFIG_FIB_RULES=y + +# +# Wireless +# +CONFIG_CFG80211=m +CONFIG_NL80211=y +CONFIG_WIRELESS_EXT=y +CONFIG_MAC80211=m +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_DEBUGFS=y +# CONFIG_MAC80211_DEBUG is not set +CONFIG_IEEE80211=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_CRYPT_WEP=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=m +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m +CONFIG_RFD_FTL=m +CONFIG_SSFDC=m +CONFIG_MTD_OOPS=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PNC2000=m +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_TS5500=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_DILNETPC=m +CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000 +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_PLATRAM=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_DATAFLASH=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTD_BLOCK2MTD=m + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCECC=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_IDS=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_CS553X=m +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_2X_PROGRAM=y +CONFIG_MTD_ONENAND_SIM=m + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +CONFIG_MTD_UBI_GLUEBI=y + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_SUPERIO is not set +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_AX88796=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_NOT_PC=y +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +CONFIG_PARIDE=m + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_BPCK6=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_SX8=m +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_VIRTIO_BLK=m +# CONFIG_MISC_DEVICES is not set +CONFIG_EEPROM_93CX6=m +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_BLK_DEV_IDEACPI=y +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +CONFIG_BLK_DEV_PLATFORM=m +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +CONFIG_BLK_DEV_IDEPNP=y + +# +# PCI IDE chipsets support +# +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_GENERIC is not set +CONFIG_BLK_DEV_OPTI621=m +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI15X3=m +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=m +CONFIG_BLK_DEV_ATIIXP=m +CONFIG_BLK_DEV_CMD64X=m +# CONFIG_BLK_DEV_TRIFLEX is not set +CONFIG_BLK_DEV_CY82C693=m +# CONFIG_BLK_DEV_CS5520 is not set +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_CS5535=m +CONFIG_BLK_DEV_HPT34X=m +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=m +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_SC1200=m +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +CONFIG_BLK_DEV_NS87415=m +CONFIG_BLK_DEV_PDC202XX_OLD=m +CONFIG_PDC202XX_BURST=y +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +CONFIG_BLK_DEV_TRM290=m +CONFIG_BLK_DEV_VIA82CXXX=m +CONFIG_BLK_DEV_TC86C001=m +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=m +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SAS_ATA=y +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_SCSI_AIC94XX=m +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPR_DUMP is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_NSP32=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_SRP=m +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_ACPI=y +CONFIG_SATA_AHCI=m +CONFIG_SATA_SVW=m +CONFIG_ATA_PIIX=y +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_PDC_ADMA=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_SX4=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SATA_INIC162X=m +CONFIG_PATA_ACPI=y +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +CONFIG_PATA_CS5520=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +CONFIG_PATA_CS5536=m +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +CONFIG_ATA_GENERIC=y +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +CONFIG_PATA_IT821X=m +CONFIG_PATA_IT8213=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_NETCELL=m +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +# CONFIG_PATA_VIA is not set +CONFIG_PATA_WINBOND=m +# CONFIG_PATA_PLATFORM is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m +CONFIG_DM_MULTIPATH_RDAC=m +CONFIG_DM_MULTIPATH_HP=m +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# Controllers +# +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocols +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +# CONFIG_I2O is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +CONFIG_IFB=m +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_MACVLAN=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_NET_SB1000=m +CONFIG_ARCNET=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_PHYLIB=m + +# +# MII PHY device drivers +# +CONFIG_MARVELL_PHY=m +CONFIG_DAVICOM_PHY=m +CONFIG_QSEMI_PHY=m +CONFIG_LXT_PHY=m +CONFIG_CICADA_PHY=m +CONFIG_VITESSE_PHY=m +CONFIG_SMSC_PHY=m +CONFIG_BROADCOM_PHY=m +CONFIG_ICPLUS_PHY=m +CONFIG_FIXED_PHY=m +# CONFIG_FIXED_MII_10_FDX is not set +# CONFIG_FIXED_MII_100_FDX is not set +CONFIG_FIXED_MII_1000_FDX=y +CONFIG_FIXED_MII_AMNT=1 +CONFIG_MDIO_BITBANG=m +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_ULI526X=m +CONFIG_HP100=m +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_AMD8111_ETH=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_B44=m +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI=y +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +CONFIG_EEPRO100=m +CONFIG_E100=m +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_VIA_RHINE_NAPI is not set +CONFIG_SC92031=m +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_NETDEV_1000=y +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E1000E=m +CONFIG_IP1000=m +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_SIS190=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SK98LIN is not set +CONFIG_VIA_VELOCITY=m +CONFIG_TIGON3=m +CONFIG_BNX2=m +CONFIG_QLA3XXX=m +CONFIG_ATL1=m +CONFIG_NETDEV_10000=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_IXGBE=m +CONFIG_IXGB=m +# CONFIG_IXGB_NAPI is not set +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +CONFIG_MYRI10GE=m +CONFIG_NETXEN_NIC=m +# CONFIG_NIU is not set +# CONFIG_MLX4_CORE is not set +CONFIG_TEHUTI=m +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +CONFIG_WLAN_80211=y +CONFIG_IPW2100=m +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2200=m +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +# CONFIG_IPW2200_DEBUG is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_SDIO=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_AIRO=m +CONFIG_HERMES=m +# CONFIG_PLX_HERMES is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_PCI_HERMES is not set +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m +CONFIG_PRISM54=m +CONFIG_USB_ZD1201=m +CONFIG_RTL8187=m +CONFIG_ADM8211=m +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +CONFIG_P54_PCI=m +# CONFIG_IWLWIFI is not set +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTAP_PCI=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_PIO=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +# CONFIG_BCM43XX_PIO_MODE is not set +CONFIG_B43=m +CONFIG_B43_PCI_AUTOSELECT=y +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_LEDS=y +CONFIG_B43_RFKILL=y +# CONFIG_B43_DEBUG is not set +CONFIG_B43_DMA=y +CONFIG_B43_PIO=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +# CONFIG_B43_PIO_MODE is not set +# CONFIG_B43LEGACY is not set +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_RT2X00=m +CONFIG_RT2X00_LIB=m +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +# CONFIG_RT2X00_DEBUG is not set + +# +# USB Network Adapters +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_WAN is not set +# CONFIG_ATM_DRIVERS is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +CONFIG_PPPOE=m +CONFIG_PPPOATM=m +CONFIG_PPPOL2TP=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLHC=m +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_NET_FC=y +CONFIG_SHAPER=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_VIRTIO_NET=m +# CONFIG_ISDN is not set +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_POLLDEV=m + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=y +CONFIG_INPUT_WISTRON_BTNS=m +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_YEALINK=m +CONFIG_INPUT_UINPUT=m + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_DEV_KMEM is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_MOXA_SMARTIO_NEW is not set +# CONFIG_ISI is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_N_HDLC is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_PRINTER is not set +CONFIG_PPDEV=m +CONFIG_HVC_DRIVER=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPMI_POWEROFF=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_INTEL=m +CONFIG_HW_RANDOM_AMD=m +CONFIG_HW_RANDOM_GEODE=m +CONFIG_HW_RANDOM_VIA=m +CONFIG_NVRAM=m +CONFIG_RTC=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set +# CONFIG_MWAVE is not set +# CONFIG_PC8736x_GPIO is not set +# CONFIG_NSC_GPIO is not set +# CONFIG_CS5535_GPIO is not set +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +CONFIG_HPET=y +# CONFIG_HPET_RTC_IRQ is not set +CONFIG_HPET_MMAP=y +CONFIG_HANGCHECK_TIMER=m +CONFIG_TCG_TPM=m +CONFIG_TCG_TIS=m +CONFIG_TCG_NSC=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +# CONFIG_TELCLOCK is not set +CONFIG_DEVPORT=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=y +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_POULSBO=y +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +CONFIG_I2C_SIMTEC=m +CONFIG_SCx200_ACB=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Miscellaneous I2C Chip support +# +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_DS1682=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_TSL2550=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +CONFIG_SPI_LM70_LLP=m + +# +# SPI Protocol Masters +# +CONFIG_SPI_AT25=m +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_W1=m +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PDA_POWER=m +CONFIG_BATTERY_DS2760=m +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_HDAPS=m +CONFIG_SENSORS_APPLESMC=m +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_THERMAL=y +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_WAFER_WDT=m +CONFIG_I6300ESB_WDT=m +CONFIG_ITCO_WDT=m +CONFIG_ITCO_VENDOR_SUPPORT=y +# CONFIG_IT8712F_WDT is not set +CONFIG_SC1200_WDT=m +CONFIG_PC87413_WDT=m +CONFIG_60XX_WDT=m +CONFIG_SBC8360_WDT=m +# CONFIG_SBC7240_WDT is not set +CONFIG_CPU5_WDT=m +CONFIG_SMSC37B787_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83697HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_MACHZ_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +# CONFIG_SSB_SILENT is not set +# CONFIG_SSB_DEBUG is not set +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_DRIVER_PCICORE=y + +# +# Multifunction device drivers +# +CONFIG_MFD_SM501=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders/decoders and other helper chips +# + +# +# Audio decoders +# +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_VP27SMPX=m + +# +# Video decoders +# +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_TCM825X=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7191=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_VPX3220=m + +# +# Video and audio decoders +# +CONFIG_VIDEO_CX25840=m + +# +# MPEG video encoders +# +CONFIG_VIDEO_CX2341X=m + +# +# Video encoders +# +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m + +# +# Video improvement chips +# +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +# CONFIG_VIDEO_SAA7134_OSS is not set +CONFIG_VIDEO_SAA7134_DVB=m +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_DPC is not set +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_29XXX=y +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_SYSFS=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_USB_VICAM=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_ET61X251=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_USB_W9968CF=m +# CONFIG_USB_OV511 is not set +CONFIG_USB_SE401=m +CONFIG_USB_SN9C102=m +CONFIG_USB_STV680=m +CONFIG_USB_ZC0301=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_ZR364XX=m +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_USB_DSBR=m +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CAPTURE_DRIVERS=y + +# +# Supported SAA7146 based PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +# +# Supported USB Adapters +# +CONFIG_DVB_USB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 + +# +# Supported FlexCopII (B2C2) Adapters +# +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m + +# +# Supported Pluto2 Adapters +# +CONFIG_DVB_PLUTO2=m + +# +# Supported DVB Frontends +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_FE_CUSTOMISE is not set + +# +# DVB-S (satellite) frontends +# +CONFIG_DVB_STV0299=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_TDA10086=m + +# +# DVB-T (terrestrial) frontends +# +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_L64781=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_ZL10353=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m + +# +# DVB-C (cable) frontends +# +CONFIG_DVB_VES1820=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_STV0297=m + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +CONFIG_DVB_NXT200X=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_S5H1409=m + +# +# Tuners/PLL support +# +CONFIG_DVB_PLL=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +CONFIG_DVB_TUNER_QT1010=m +CONFIG_DVB_TUNER_MT2060=m +CONFIG_DVB_TUNER_MT2266=m +CONFIG_DVB_TUNER_MT2131=m +CONFIG_DVB_TUNER_DIB0070=m + +# +# Miscellaneous devices +# +CONFIG_DVB_LNBP21=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_TUA6100=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TUNER_SIMPLE=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_DAB=y +CONFIG_USB_DABUSB=m + +# +# Graphics support +# +CONFIG_AGP=y +CONFIG_AGP_ALI=m +CONFIG_AGP_ATI=m +CONFIG_AGP_AMD=m +CONFIG_AGP_AMD64=m +CONFIG_AGP_INTEL=m +CONFIG_AGP_NVIDIA=m +CONFIG_AGP_SIS=m +CONFIG_AGP_SWORKS=m +CONFIG_AGP_VIA=m +CONFIG_AGP_EFFICEON=m +# CONFIG_DRM is not set +CONFIG_VGASTATE=m +CONFIG_VIDEO_OUTPUT_CONTROL=y +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_DDC=m +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_IMAGEBLIT=m +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_SVGALIB=m +# CONFIG_FB_MACMODES is not set +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +CONFIG_FB_CIRRUS=m +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_CYBER2000=m +# CONFIG_FB_ARC is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_VGA16=m +CONFIG_FB_UVESA=m +CONFIG_FB_VESA=m +CONFIG_FB_EFI=y +CONFIG_FB_IMAC=y +CONFIG_FB_HECUBA=m +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_S1D13XXX=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_I2C=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_BACKLIGHT=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_I2C=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_BACKLIGHT=y +CONFIG_FB_I810=m +# CONFIG_FB_I810_GTF is not set +CONFIG_FB_LE80578=m +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FB_CYBLA=m +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_ARK=m +CONFIG_FB_PM3=m +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_LX=m +CONFIG_FB_GEODE_GX=m +# CONFIG_FB_GEODE_GX_SET_FBSIZE is not set +CONFIG_FB_GEODE_GX1=m +CONFIG_FB_SM501=m +# CONFIG_FB_VIRTUAL is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_PROGEAR=m +CONFIG_BACKLIGHT_CARILLO_RANCH=m + +# +# Display device support +# +CONFIG_DISPLAY_SUPPORT=m + +# +# Display hardware drivers +# + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VIDEO_SELECT=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_LOGO is not set + +# +# Sound +# +CONFIG_SOUND=y + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=y +CONFIG_SND_SEQ_DUMMY=y +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_MPU401=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_SB_COMMON=m +CONFIG_SND_SB16_DSP=m + +# +# PCI devices +# +CONFIG_SND_AD1889=m +CONFIG_SND_ALS300=m +CONFIG_SND_ALS4000=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_BT87X_OVERCLOCK=y +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS5530=m +CONFIG_SND_CS5535AUDIO=m +CONFIG_SND_DARLA20=m +CONFIG_SND_GINA20=m +CONFIG_SND_LAYLA20=m +CONFIG_SND_DARLA24=m +CONFIG_SND_GINA24=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MONA=m +CONFIG_SND_MIA=m +CONFIG_SND_ECHO3G=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_HDA_INTEL=y +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_CODEC_ANALOG=y +CONFIG_SND_HDA_CODEC_SIGMATEL=y +CONFIG_SND_HDA_CODEC_VIA=y +CONFIG_SND_HDA_CODEC_ATIHDMI=y +CONFIG_SND_HDA_CODEC_CONEXANT=y +CONFIG_SND_HDA_CODEC_CMEDIA=y +CONFIG_SND_HDA_CODEC_SI3054=y +CONFIG_SND_HDA_GENERIC=y +CONFIG_SND_HDA_POWER_SAVE=y +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_KORG1212_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MAESTRO3_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_PCXHR=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VX222=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 + +# +# SPI devices +# + +# +# USB devices +# +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_USX2Y=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y + +# +# System on Chip audio support +# +CONFIG_SND_SOC=m + +# +# SoC Audio support for SuperH +# + +# +# Open Sound System +# +CONFIG_SOUND_PRIME=m +CONFIG_SOUND_TRIDENT=m +CONFIG_SOUND_MSNDCLAS=m +CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin" +CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin" +CONFIG_SOUND_MSNDPIN=m +CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin" +CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin" +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +CONFIG_SOUND_DMAP=y +CONFIG_SOUND_SSCAPE=m +CONFIG_SOUND_VMIDI=m +CONFIG_SOUND_TRIX=m +CONFIG_SOUND_MSS=m +CONFIG_SOUND_MPU401=m +CONFIG_SOUND_PAS=m +CONFIG_SOUND_PSS=m +CONFIG_PSS_MIXER=y +CONFIG_SOUND_SB=m +CONFIG_SOUND_YM3812=m +CONFIG_SOUND_UART6850=m +CONFIG_SOUND_AEDSP16=m +CONFIG_SC6600=y +CONFIG_SC6600_JOY=y +CONFIG_SC6600_CDROM=4 +CONFIG_SC6600_CDROMBASE=0 +CONFIG_AEDSP16_MSS=y +# CONFIG_AEDSP16_SBPRO is not set +CONFIG_SOUND_KAHLUA=m +CONFIG_AC97_BUS=m +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set +CONFIG_HIDRAW=y + +# +# USB Input Devices +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT_POWERBOOK=y +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +CONFIG_USB_PERSIST=y +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_HCD_SSB=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_UHCI_HCD=y +CONFIG_USB_U132_HCD=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_R8A66597_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_MON=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +# CONFIG_USB_SERIAL_IR is not set +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_LED=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_IOWARRIOR=m +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# +CONFIG_USB_ATM=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_CXACRU=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_AT91 is not set +CONFIG_USB_GADGET_IUSBC=y +CONFIG_USB_IUSBC=y +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_GADGETFS=m +CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_FILE_STORAGE_TEST=y +CONFIG_USB_G_SERIAL=m +# CONFIG_USB_MIDI_GADGET is not set + +# +# MMC/SD/SDIO support, can only select one arch from MMC and MSS +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_UNSAFE_RESUME=y + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_SDIO_UART=m + +# +# MMC/SD Host Controller Drivers +# +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_RICOH_MMC is not set +# CONFIG_MMC_WBSD is not set +# CONFIG_MMC_TIFM_SD is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MSS is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=m + +# +# LED drivers +# + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +# CONFIG_INFINIBAND is not set +CONFIG_EDAC=y + +# +# Reporting subsystems +# +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_MM_EDAC=m +# CONFIG_EDAC_AMD76X is not set +CONFIG_EDAC_E7XXX=m +CONFIG_EDAC_E752X=m +CONFIG_EDAC_I82875P=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_I3000=m +CONFIG_EDAC_I82860=m +CONFIG_EDAC_R82600=m +CONFIG_EDAC_I5000=m +CONFIG_RTC_LIB=m +CONFIG_RTC_CLASS=m + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_DRV_TEST=m + +# +# I2C RTC drivers +# +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y + +# +# SPI RTC drivers +# +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_MAX6902=m + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_V3020=m + +# +# on-CPU RTC drivers +# +CONFIG_DMADEVICES=y + +# +# DMA Devices +# +CONFIG_INTEL_IOATDMA=m +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +CONFIG_NET_DMA=y +CONFIG_DCA=m +# CONFIG_AUXDISPLAY is not set + +# +# Userspace I/O +# +CONFIG_UIO=m +CONFIG_UIO_CIF=m + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_EFI_VARS=y +# CONFIG_DELL_RBU is not set +# CONFIG_DCDBAS is not set +CONFIG_DMIID=y + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_QUOTACTL=y +CONFIG_DNOTIFY=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=m +CONFIG_GENERIC_ACL=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_EXPERIMENTAL is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +CONFIG_CODA_FS=m +# CONFIG_CODA_FS_OLD_API is not set +CONFIG_AFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_DEFAULT_RELATIME=y +CONFIG_DEFAULT_RELATIME_VAL=1 + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_CUMANA is not set +# CONFIG_ACORN_PARTITION_EESOX is not set +CONFIG_ACORN_PARTITION_ICS=y +# CONFIG_ACORN_PARTITION_ADFS is not set +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_ATARI_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +CONFIG_SGI_PARTITION=y +CONFIG_ULTRIX_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_SYSV68_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_INSTRUMENTATION=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=m +CONFIG_KPROBES=y +# CONFIG_MARKERS is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_PRINTK_TIME=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_FORCED_INLINING is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_LKDTM is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SAMPLES is not set +CONFIG_NONPROMISC_DEVMEM=y +CONFIG_EARLY_PRINTK=y +# CONFIG_WRAPPER_PRINT is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set + +# +# Page alloc debug is incompatible with Software Suspend on i386 +# +# CONFIG_DEBUG_RODATA is not set +# CONFIG_4KSTACKS is not set +CONFIG_X86_FIND_SMP_CONFIG=y +CONFIG_X86_MPPARSE=y +CONFIG_DOUBLEFAULT=y +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +CONFIG_IO_DELAY_TYPE_NONE=3 +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_DEFAULT_IO_DELAY_TYPE=0 + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_TWOFISH_586=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_AES_586=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_PADLOCK=y +CONFIG_CRYPTO_DEV_PADLOCK_AES=m +CONFIG_CRYPTO_DEV_PADLOCK_SHA=m +CONFIG_CRYPTO_DEV_GEODE=m +CONFIG_HAVE_KVM=y +# CONFIG_VIRTUALIZATION is not set +CONFIG_VIRTIO=y +CONFIG_VIRTIO_RING=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=m +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=m +CONFIG_ZLIB_DEFLATE=m +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_DRM_VIA_CHROME9=m --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0023-crown_beach_reboot.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0023-crown_beach_reboot.patch @@ -0,0 +1,22 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/arch/x86/kernel/reboot_32.c b/arch/x86/kernel/reboot_32.c +index bb1a0f8..50c2f11 100644 +--- a/arch/x86/kernel/reboot_32.c ++++ b/arch/x86/kernel/reboot_32.c +@@ -135,6 +135,16 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), + }, + }, ++ { /* Handle problems with rebooting on Intel Crown Beach board */ ++ .callback = set_bios_reboot, ++ .ident = "Intel Crown Beach board", ++ .matches = { ++ /* Currently the DMI info is not customized and indicates ++ * OEM need change that */ ++ DMI_MATCH(DMI_SYS_VENDOR, "To Be Filled By O.E.M."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "To Be Filled By O.E.M."), ++ }, ++ }, + { } + }; + --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0020-ts-doubleclick-workaround.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0020-ts-doubleclick-workaround.patch @@ -0,0 +1,22 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c +index be83516..1a7f0e0 100644 +--- a/drivers/input/mousedev.c ++++ b/drivers/input/mousedev.c +@@ -1009,6 +1009,8 @@ static const struct input_device_id mousedev_ids[] = { + .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) }, + .relbit = { BIT_MASK(REL_WHEEL) }, + }, /* A separate scrollwheel */ ++/* masked for MID device touchscreen double-click issue */ ++#if 0 + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_KEYBIT | +@@ -1018,6 +1020,7 @@ static const struct input_device_id mousedev_ids[] = { + .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, + }, /* A tablet like device, at least touch detection, + two absolute axes */ ++#endif + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_KEYBIT | --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0012-poulsbo_hda_class_id.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0012-poulsbo_hda_class_id.patch @@ -0,0 +1,23 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 01d8f8a..6792eca 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -1490,6 +1490,17 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev) + } + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810); + ++ ++static void __devinit fixup_poulsbo_hda(struct pci_dev* dev) ++{ ++ /* poulsbo A2 HD audio controller has the wrong class type of 604h */ ++ if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) { ++ printk(KERN_INFO "Poulsbo A2 HDA detected, setting PCI class.\n"); ++ dev->class = PCI_CLASS_MULTIMEDIA_AUDIO; ++ } ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_POULSBO_HDA, fixup_poulsbo_hda); ++ + static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) + { + while (f < end) { --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0001-dabney_thermal.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0001-dabney_thermal.patch @@ -0,0 +1,3076 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt +new file mode 100644 +index 0000000..f627016 +--- /dev/null ++++ b/Documentation/thermal/sysfs-api.txt +@@ -0,0 +1,247 @@ ++Generic Thermal Sysfs driver How To ++========================= ++ ++Written by Sujith Thomas , Zhang Rui ++ ++Updated: 2 January 2008 ++ ++Copyright (c) 2008 Intel Corporation ++ ++ ++0. Introduction ++ ++The generic thermal sysfs provides a set of interfaces for thermal zone devices (sensors) ++and thermal cooling devices (fan, processor...) to register with the thermal management ++solution and to be a part of it. ++ ++This how-to focusses on enabling new thermal zone and cooling devices to participate ++in thermal management. ++This solution is platform independent and any type of thermal zone devices and ++cooling devices should be able to make use of the infrastructure. ++ ++The main task of the thermal sysfs driver is to expose thermal zone attributes as well ++as cooling device attributes to the user space. ++An intelligent thermal management application can make decisions based on inputs ++from thermal zone attributes (the current temperature and trip point temperature) ++and throttle appropriate devices. ++ ++[0-*] denotes any positive number starting from 0 ++[1-*] denotes any positive number starting from 1 ++ ++1. thermal sysfs driver interface functions ++ ++1.1 thermal zone device interface ++1.1.1 struct thermal_zone_device *thermal_zone_device_register(char *name, int trips, ++ void *devdata, struct thermal_zone_device_ops *ops) ++ ++ This interface function adds a new thermal zone device (sensor) to ++ /sys/class/thermal folder as thermal_zone[0-*]. ++ It tries to bind all the thermal cooling devices registered at the same time. ++ ++ name: the thermal zone name. ++ trips: the total number of trip points this thermal zone supports. ++ devdata: device private data ++ ops: thermal zone device callbacks. ++ .bind: bind the thermal zone device with a thermal cooling device. ++ .unbind: unbing the thermal zone device with a thermal cooling device. ++ .get_temp: get the current temperature of the thermal zone. ++ .get_mode: get the current mode (user/kernel) of the thermal zone. ++ "kernel" means thermal management is done in kernel. ++ "user" will prevent kernel thermal driver actions upon trip points ++ so that user applications can take charge of thermal management. ++ .set_mode: set the mode (user/kernel) of the thermal zone. ++ .get_trip_type: get the type of certain trip point. ++ .get_trip_temp: get the temperature above which the certain trip point ++ will be fired. ++ ++1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz) ++ ++ This interface function removes the thermal zone device. ++ It deletes the corresponding entry form /sys/class/thermal folder and unbind all ++ the thermal cooling devices it uses. ++ ++1.2 thermal cooling device interface ++1.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name, ++ void *devdata, struct thermal_cooling_device_ops *) ++ ++ This interface function adds a new thermal cooling device (fan/processor/...) to ++ /sys/class/thermal/ folder as cooling_device[0-*]. ++ It tries to bind itself to all the thermal zone devices register at the same time. ++ name: the cooling device name. ++ devdata: device private data. ++ ops: thermal cooling devices callbacks. ++ .get_max_state: get the Maximum throttle state of the cooling device. ++ .get_cur_state: get the Current throttle state of the cooling device. ++ .set_cur_state: set the Current throttle state of the cooling device. ++ ++1.2.2 void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) ++ ++ This interface function remove the thermal cooling device. ++ It deletes the corresponding entry form /sys/class/thermal folder and unbind ++ itself from all the thermal zone devices using it. ++ ++1.3 interface for binding a thermal zone device with a thermal cooling device ++1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, ++ int trip, struct thermal_cooling_device *cdev); ++ ++ This interface function bind a thermal cooling device to the certain trip point ++ of a thermal zone device. ++ This function is usually called in the thermal zone device .bind callback. ++ tz: the thermal zone device ++ cdev: thermal cooling device ++ trip: indicates which trip point the cooling devices is associated with ++ in this thermal zone. ++ ++1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, ++ int trip, struct thermal_cooling_device *cdev); ++ ++ This interface function unbind a thermal cooling device from the certain trip point ++ of a thermal zone device. ++ This function is usually called in the thermal zone device .unbind callback. ++ tz: the thermal zone device ++ cdev: thermal cooling device ++ trip: indicates which trip point the cooling devices is associated with ++ in this thermal zone. ++ ++2. sysfs attributes structure ++ ++RO read only value ++RW read/write value ++ ++All thermal sysfs attributes will be represented under /sys/class/thermal ++/sys/class/thermal/ ++ ++Thermal zone device sys I/F, created once it's registered: ++|thermal_zone[0-*]: ++ |-----type: Type of the thermal zone ++ |-----temp: Current temperature ++ |-----mode: Working mode of the thermal zone ++ |-----trip_point_[0-*]_temp: Trip point temperature ++ |-----trip_point_[0-*]_type: Trip point type ++ ++Thermal cooling device sys I/F, created once it's registered: ++|cooling_device[0-*]: ++ |-----type : Type of the cooling device(processor/fan/...) ++ |-----max_state: Maximum cooling state of the cooling device ++ |-----cur_state: Current cooling state of the cooling device ++ ++ ++These two dynamic attributes are created/removed in pairs. ++They represent the relationship between a thermal zone and its associated cooling device. ++They are created/removed for each ++thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful exection. ++ ++|thermal_zone[0-*] ++ |-----cdev[0-*]: The [0-*]th cooling device in the current thermal zone ++ |-----cdev[0-*]_trip_point: Trip point that cdev[0-*] is associated with ++ ++ ++*************************** ++* Thermal zone attributes * ++*************************** ++ ++type Strings which represent the thermal zone type. ++ This is given by thermal zone driver as part of registration. ++ Eg: "ACPI thermal zone" indicates it's a ACPI thermal device ++ RO ++ Optional ++ ++temp Current temperature as reported by thermal zone (sensor) ++ Unit: degree celsius ++ RO ++ Required ++ ++mode One of the predifned values in [kernel, user] ++ This file gives information about the algorithm ++ that is currently managing the thermal zone. ++ It can be either default kernel based algorithm ++ or user space application. ++ RW ++ Optional ++ kernel = Thermal management in kernel thermal zone driver. ++ user = Preventing kernel thermal zone driver actions upon ++ trip points so that user application can take full ++ charge of the thermal management. ++ ++trip_point_[0-*]_temp The temperature above which trip point will be fired ++ Unit: degree celsius ++ RO ++ Optional ++ ++trip_point_[0-*]_type Strings which indicate the type of the trip point ++ Eg. it can be one of critical, hot, passive, ++ active[0-*] for ACPI thermal zone. ++ RO ++ Optional ++ ++cdev[0-*] Sysfs link to the thermal cooling device node where the sys I/F ++ for cooling device throttling control represents. ++ RO ++ Optional ++ ++cdev[0-*]_trip_point The trip point with which cdev[0-*] is assocated in this thermal zone ++ -1 means the cooling device is not associated with any trip point. ++ RO ++ Optional ++ ++****************************** ++* Cooling device attributes * ++****************************** ++ ++type String which represents the type of device ++ eg: For generic ACPI: this should be "Fan", ++ "Processor" or "LCD" ++ eg. For memory controller device on intel_menlow platform: ++ this should be "Memory controller" ++ RO ++ Optional ++ ++max_state The maximum permissible cooling state of this cooling device. ++ RO ++ Required ++ ++cur_state The current cooling state of this cooling device. ++ the value can any integer numbers between 0 and max_state, ++ cur_state == 0 means no cooling ++ cur_state == max_state means the maximum cooling. ++ RW ++ Required ++ ++3. A simple implementation ++ ++ACPI thermal zone may support multiple trip points like critical/hot/passive/active. ++If an ACPI thermal zone supports critical, passive, active[0] and active[1] at the same time, ++it may register itself as a thermale_zone_device (thermal_zone1) with 4 trip points in all. ++It has one processor and one fan, which are both registered as thermal_cooling_device. ++If the processor is listed in _PSL method, and the fan is listed in _AL0 method, ++the sys I/F structure will be built like this: ++ ++/sys/class/thermal: ++ ++|thermal_zone1: ++ |-----type: ACPI thermal zone ++ |-----temp: 37 ++ |-----mode: kernel ++ |-----trip_point_0_temp: 100 ++ |-----trip_point_0_type: critical ++ |-----trip_point_1_temp: 80 ++ |-----trip_point_1_type: passive ++ |-----trip_point_2_temp: 70 ++ |-----trip_point_2_type: active[0] ++ |-----trip_point_3_temp: 60 ++ |-----trip_point_3_type: active[1] ++ |-----cdev0: --->/sys/class/thermal/cooling_device0 ++ |-----cdev0_trip_point: 1 /* cdev0 can be used for passive */ ++ |-----cdev1: --->/sys/class/thermal/cooling_device3 ++ |-----cdev1_trip_point: 2 /* cdev1 can be used for active[0]*/ ++ ++|cooling_device0: ++ |-----type: Processor ++ |-----max_state: 8 ++ |-----cur_state: 0 ++ ++|cooling_device3: ++ |-----type: Fan ++ |-----max_state: 2 ++ |-----cur_state: 0 ++ +diff --git a/drivers/Kconfig b/drivers/Kconfig +index 3f8a231..d127a9a 100644 +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -58,6 +58,8 @@ source "drivers/power/Kconfig" + + source "drivers/hwmon/Kconfig" + ++source "drivers/thermal/Kconfig" ++ + source "drivers/watchdog/Kconfig" + + source "drivers/ssb/Kconfig" +diff --git a/drivers/Makefile b/drivers/Makefile +index a5cfc61..e0013ee 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -64,6 +64,7 @@ obj-y += i2c/ + obj-$(CONFIG_W1) += w1/ + obj-$(CONFIG_POWER_SUPPLY) += power/ + obj-$(CONFIG_HWMON) += hwmon/ ++obj-$(CONFIG_THERMAL) += thermal/ + obj-$(CONFIG_WATCHDOG) += watchdog/ + obj-$(CONFIG_PHONE) += telephony/ + obj-$(CONFIG_MD) += md/ +diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig +index aa608a2..03bdbf9 100644 +--- a/drivers/acpi/Kconfig ++++ b/drivers/acpi/Kconfig +@@ -186,6 +186,7 @@ config ACPI_HOTPLUG_CPU + config ACPI_THERMAL + tristate "Thermal Zone" + depends on ACPI_PROCESSOR ++ select THERMAL + default y + help + This driver adds support for ACPI thermal zones. Most mobile and +diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c +index f4487c3..34ba7c3 100644 +--- a/drivers/acpi/bus.c ++++ b/drivers/acpi/bus.c +@@ -122,6 +122,31 @@ int acpi_bus_get_status(struct acpi_device *device) + + EXPORT_SYMBOL(acpi_bus_get_status); + ++void acpi_bus_private_data_handler(acpi_handle handle, ++ u32 function, void *context) ++{ ++ return; ++} ++EXPORT_SYMBOL(acpi_bus_private_data_handler); ++ ++int acpi_bus_get_private_data(acpi_handle handle, void **data) ++{ ++ acpi_status status = AE_OK; ++ ++ if (!*data) ++ return -EINVAL; ++ ++ status = acpi_get_data(handle, acpi_bus_private_data_handler, data); ++ if (ACPI_FAILURE(status) || !*data) { ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", ++ handle)); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(acpi_bus_get_private_data); ++ + /* -------------------------------------------------------------------------- + Power Management + -------------------------------------------------------------------------- */ +diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c +index a6e149d..f6e8165 100644 +--- a/drivers/acpi/fan.c ++++ b/drivers/acpi/fan.c +@@ -30,7 +30,7 @@ + #include + #include + #include +- ++#include + #include + #include + +@@ -68,9 +68,55 @@ static struct acpi_driver acpi_fan_driver = { + }, + }; + ++/* thermal cooling device callbacks */ ++static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf) ++{ ++ /* ACPI fan device only support two states: ON/OFF */ ++ return sprintf(buf, "1\n"); ++} ++ ++static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf) ++{ ++ struct acpi_device *device = cdev->devdata; ++ int state; ++ int result; ++ ++ if (!device) ++ return -EINVAL; ++ ++ result = acpi_bus_get_power(device->handle, &state); ++ if (result) ++ return result; ++ ++ return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" : ++ (state == ACPI_STATE_D0 ? "1" : "unknown")); ++} ++ ++static int ++fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) ++{ ++ struct acpi_device *device = cdev->devdata; ++ int result; ++ ++ if (!device || (state != 0 && state != 1)) ++ return -EINVAL; ++ ++ result = acpi_bus_set_power(device->handle, ++ state ? ACPI_STATE_D0 : ACPI_STATE_D3); ++ ++ return result; ++} ++ ++static struct thermal_cooling_device_ops fan_cooling_ops = { ++ .get_max_state = fan_get_max_state, ++ .get_cur_state = fan_get_cur_state, ++ .set_cur_state = fan_set_cur_state, ++}; ++ + /* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ ++#ifdef CONFIG_ACPI_PROCFS + + static struct proc_dir_entry *acpi_fan_dir; + +@@ -171,7 +217,17 @@ static int acpi_fan_remove_fs(struct acpi_device *device) + + return 0; + } ++#else ++static int acpi_fan_add_fs(struct acpi_device *device) ++{ ++ return 0; ++} + ++static int acpi_fan_remove_fs(struct acpi_device *device) ++{ ++ return 0; ++} ++#endif + /* -------------------------------------------------------------------------- + Driver Interface + -------------------------------------------------------------------------- */ +@@ -179,9 +235,8 @@ static int acpi_fan_remove_fs(struct acpi_device *device) + static int acpi_fan_add(struct acpi_device *device) + { + int result = 0; +- struct acpi_fan *fan = NULL; + int state = 0; +- ++ struct thermal_cooling_device *cdev; + + if (!device) + return -EINVAL; +@@ -199,6 +254,25 @@ static int acpi_fan_add(struct acpi_device *device) + acpi_bus_set_power(device->handle, state); + device->flags.force_power_state = 0; + ++ cdev = thermal_cooling_device_register("Fan", device, ++ &fan_cooling_ops); ++ if (cdev) ++ printk(KERN_INFO PREFIX ++ "%s is registered as cooling_device%d\n", ++ device->dev.bus_id, cdev->id); ++ else ++ goto end; ++ acpi_driver_data(device) = cdev; ++ result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj, ++ "thermal_cooling"); ++ if (result) ++ return result; ++ ++ result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj, ++ "device"); ++ if (result) ++ return result; ++ + result = acpi_fan_add_fs(device); + if (result) + goto end; +@@ -208,18 +282,20 @@ static int acpi_fan_add(struct acpi_device *device) + !device->power.state ? "on" : "off"); + + end: +- if (result) +- kfree(fan); +- + return result; + } + + static int acpi_fan_remove(struct acpi_device *device, int type) + { +- if (!device || !acpi_driver_data(device)) ++ struct thermal_cooling_device *cdev = acpi_driver_data(device); ++ ++ if (!device || !cdev) + return -EINVAL; + + acpi_fan_remove_fs(device); ++ sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); ++ sysfs_remove_link(&cdev->device.kobj, "device"); ++ thermal_cooling_device_unregister(cdev); + + return 0; + } +diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c +index c703eab..146b67d 100644 +--- a/drivers/acpi/processor_core.c ++++ b/drivers/acpi/processor_core.c +@@ -672,6 +672,24 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) + + acpi_processor_power_init(pr, device); + ++ pr->cdev = thermal_cooling_device_register("Processor", device, ++ &processor_cooling_ops); ++ if (pr->cdev) ++ printk(KERN_INFO PREFIX ++ "%s is registered as cooling_device%d\n", ++ device->dev.bus_id, pr->cdev->id); ++ else ++ goto end; ++ ++ result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj, ++ "thermal_cooling"); ++ if (result) ++ return result; ++ result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, ++ "device"); ++ if (result) ++ return result; ++ + if (pr->flags.throttling) { + printk(KERN_INFO PREFIX "%s [%s] (supports", + acpi_device_name(device), acpi_device_bid(device)); +@@ -797,6 +815,11 @@ static int acpi_processor_remove(struct acpi_device *device, int type) + + acpi_processor_remove_fs(device); + ++ sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); ++ sysfs_remove_link(&pr->cdev->device.kobj, "device"); ++ thermal_cooling_device_unregister(pr->cdev); ++ pr->cdev = NULL; ++ + processors[pr->id] = NULL; + processor_device_array[pr->id] = NULL; + kfree(pr); +diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c +index 06e6f3f..9cb43f5 100644 +--- a/drivers/acpi/processor_thermal.c ++++ b/drivers/acpi/processor_thermal.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + #include + +@@ -93,6 +94,9 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr) + * _any_ cpufreq driver and not only the acpi-cpufreq driver. + */ + ++#define CPUFREQ_THERMAL_MIN_STEP 0 ++#define CPUFREQ_THERMAL_MAX_STEP 3 ++ + static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS]; + static unsigned int acpi_thermal_cpufreq_is_init = 0; + +@@ -109,8 +113,9 @@ static int acpi_thermal_cpufreq_increase(unsigned int cpu) + if (!cpu_has_cpufreq(cpu)) + return -ENODEV; + +- if (cpufreq_thermal_reduction_pctg[cpu] < 60) { +- cpufreq_thermal_reduction_pctg[cpu] += 20; ++ if (cpufreq_thermal_reduction_pctg[cpu] < ++ CPUFREQ_THERMAL_MAX_STEP) { ++ cpufreq_thermal_reduction_pctg[cpu]++; + cpufreq_update_policy(cpu); + return 0; + } +@@ -123,8 +128,9 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu) + if (!cpu_has_cpufreq(cpu)) + return -ENODEV; + +- if (cpufreq_thermal_reduction_pctg[cpu] > 20) +- cpufreq_thermal_reduction_pctg[cpu] -= 20; ++ if (cpufreq_thermal_reduction_pctg[cpu] > ++ (CPUFREQ_THERMAL_MIN_STEP + 1)) ++ cpufreq_thermal_reduction_pctg[cpu]--; + else + cpufreq_thermal_reduction_pctg[cpu] = 0; + cpufreq_update_policy(cpu); +@@ -143,7 +149,7 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb, + + max_freq = + (policy->cpuinfo.max_freq * +- (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100; ++ (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100; + + cpufreq_verify_within_limits(policy, 0, max_freq); + +@@ -155,6 +161,32 @@ static struct notifier_block acpi_thermal_cpufreq_notifier_block = { + .notifier_call = acpi_thermal_cpufreq_notifier, + }; + ++static int cpufreq_get_max_state(unsigned int cpu) ++{ ++ if (!cpu_has_cpufreq(cpu)) ++ return 0; ++ ++ return CPUFREQ_THERMAL_MAX_STEP; ++} ++ ++static int cpufreq_get_cur_state(unsigned int cpu) ++{ ++ if (!cpu_has_cpufreq(cpu)) ++ return 0; ++ ++ return cpufreq_thermal_reduction_pctg[cpu]; ++} ++ ++static int cpufreq_set_cur_state(unsigned int cpu, int state) ++{ ++ if (!cpu_has_cpufreq(cpu)) ++ return 0; ++ ++ cpufreq_thermal_reduction_pctg[cpu] = state; ++ cpufreq_update_policy(cpu); ++ return 0; ++} ++ + void acpi_thermal_cpufreq_init(void) + { + int i; +@@ -179,6 +211,20 @@ void acpi_thermal_cpufreq_exit(void) + } + + #else /* ! CONFIG_CPU_FREQ */ ++static int cpufreq_get_max_state(unsigned int cpu) ++{ ++ return 0; ++} ++ ++static int cpufreq_get_cur_state(unsigned int cpu) ++{ ++ return 0; ++} ++ ++static int cpufreq_set_cur_state(unsigned int cpu, int state) ++{ ++ return 0; ++} + + static int acpi_thermal_cpufreq_increase(unsigned int cpu) + { +@@ -310,6 +356,84 @@ int acpi_processor_get_limit_info(struct acpi_processor *pr) + return 0; + } + ++/* thermal coolign device callbacks */ ++static int acpi_processor_max_state(struct acpi_processor *pr) ++{ ++ int max_state = 0; ++ ++ /* ++ * There exists four states according to ++ * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3 ++ */ ++ max_state += cpufreq_get_max_state(pr->id); ++ if (pr->flags.throttling) ++ max_state += (pr->throttling.state_count -1); ++ ++ return max_state; ++} ++static int ++processor_get_max_state(struct thermal_cooling_device *cdev, char *buf) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_processor *pr = acpi_driver_data(device); ++ ++ if (!device || !pr) ++ return -EINVAL; ++ ++ return sprintf(buf, "%d\n", acpi_processor_max_state(pr)); ++} ++ ++static int ++processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_processor *pr = acpi_driver_data(device); ++ int cur_state; ++ ++ if (!device || !pr) ++ return -EINVAL; ++ ++ cur_state = cpufreq_get_cur_state(pr->id); ++ if (pr->flags.throttling) ++ cur_state += pr->throttling.state; ++ ++ return sprintf(buf, "%d\n", cur_state); ++} ++ ++static int ++processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_processor *pr = acpi_driver_data(device); ++ int result = 0; ++ int max_pstate; ++ ++ if (!device || !pr) ++ return -EINVAL; ++ ++ max_pstate = cpufreq_get_max_state(pr->id); ++ ++ if (state > acpi_processor_max_state(pr)) ++ return -EINVAL; ++ ++ if (state <= max_pstate) { ++ if (pr->flags.throttling && pr->throttling.state) ++ result = acpi_processor_set_throttling(pr, 0); ++ cpufreq_set_cur_state(pr->id, state); ++ } else { ++ cpufreq_set_cur_state(pr->id, max_pstate); ++ result = acpi_processor_set_throttling(pr, ++ state - max_pstate); ++ } ++ return result; ++} ++ ++struct thermal_cooling_device_ops processor_cooling_ops = { ++ .get_max_state = processor_get_max_state, ++ .get_cur_state = processor_get_cur_state, ++ .set_cur_state = processor_set_cur_state, ++}; ++ + /* /proc interface */ + + static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset) +diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c +index 5f79b44..73f276b 100644 +--- a/drivers/acpi/thermal.c ++++ b/drivers/acpi/thermal.c +@@ -43,7 +43,7 @@ + #include + #include + #include +- ++#include + #include + #include + +@@ -65,9 +65,6 @@ + #define ACPI_THERMAL_MAX_ACTIVE 10 + #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65 + +-#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10) +-#define CELSIUS_TO_KELVIN(t) ((t+273)*10) +- + #define _COMPONENT ACPI_THERMAL_COMPONENT + ACPI_MODULE_NAME("thermal"); + +@@ -195,6 +192,8 @@ struct acpi_thermal { + struct acpi_thermal_trips trips; + struct acpi_handle_list devices; + struct timer_list timer; ++ struct thermal_zone_device *thermal_zone; ++ int tz_enabled; + struct mutex lock; + }; + +@@ -321,173 +320,221 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode) + return 0; + } + +-static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) +-{ +- acpi_status status = AE_OK; +- int i = 0; ++#define ACPI_TRIPS_CRITICAL 0x01 ++#define ACPI_TRIPS_HOT 0x02 ++#define ACPI_TRIPS_PASSIVE 0x04 ++#define ACPI_TRIPS_ACTIVE 0x08 ++#define ACPI_TRIPS_DEVICES 0x10 + ++#define ACPI_TRIPS_REFRESH_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE) ++#define ACPI_TRIPS_REFRESH_DEVICES ACPI_TRIPS_DEVICES + +- if (!tz) +- return -EINVAL; ++#define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \ ++ ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \ ++ ACPI_TRIPS_DEVICES) + +- /* Critical Shutdown (required) */ +- +- status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, +- &tz->trips.critical.temperature); +- if (ACPI_FAILURE(status)) { +- tz->trips.critical.flags.valid = 0; +- ACPI_EXCEPTION((AE_INFO, status, "No critical threshold")); +- return -ENODEV; +- } else { +- tz->trips.critical.flags.valid = 1; +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, +- "Found critical threshold [%lu]\n", +- tz->trips.critical.temperature)); +- } ++/* ++ * This exception is thrown out in two cases: ++ * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid ++ * when re-evaluating the AML code. ++ * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change. ++ * We need to re-bind the cooling devices of a thermal zone when this occurs. ++ */ ++#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str) \ ++do { \ ++ if (flags != ACPI_TRIPS_INIT) \ ++ ACPI_EXCEPTION((AE_INFO, AE_ERROR, \ ++ "ACPI thermal trip point %s changed\n" \ ++ "Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \ ++} while (0) ++ ++static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) ++{ ++ acpi_status status = AE_OK; ++ struct acpi_handle_list devices; ++ int valid = 0; ++ int i; + +- if (tz->trips.critical.flags.valid == 1) { +- if (crt == -1) { ++ /* Critical Shutdown (required) */ ++ if (flag & ACPI_TRIPS_CRITICAL) { ++ status = acpi_evaluate_integer(tz->device->handle, ++ "_CRT", NULL, &tz->trips.critical.temperature); ++ if (ACPI_FAILURE(status)) { + tz->trips.critical.flags.valid = 0; +- } else if (crt > 0) { +- unsigned long crt_k = CELSIUS_TO_KELVIN(crt); +- +- /* +- * Allow override to lower critical threshold +- */ +- if (crt_k < tz->trips.critical.temperature) +- tz->trips.critical.temperature = crt_k; ++ ACPI_EXCEPTION((AE_INFO, status, ++ "No critical threshold")); ++ return -ENODEV; ++ } else { ++ tz->trips.critical.flags.valid = 1; ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, ++ "Found critical threshold [%lu]\n", ++ tz->trips.critical.temperature)); ++ } ++ if (tz->trips.critical.flags.valid == 1) { ++ if (crt == -1) { ++ tz->trips.critical.flags.valid = 0; ++ } else if (crt > 0) { ++ unsigned long crt_k = CELSIUS_TO_KELVIN(crt); ++ /* ++ * Allow override to lower critical threshold ++ */ ++ if (crt_k < tz->trips.critical.temperature) ++ tz->trips.critical.temperature = crt_k; ++ } + } + } + + /* Critical Sleep (optional) */ +- +- status = +- acpi_evaluate_integer(tz->device->handle, "_HOT", NULL, +- &tz->trips.hot.temperature); +- if (ACPI_FAILURE(status)) { +- tz->trips.hot.flags.valid = 0; +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n")); +- } else { +- tz->trips.hot.flags.valid = 1; +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n", +- tz->trips.hot.temperature)); +- } +- +- /* Passive: Processors (optional) */ +- +- if (psv == -1) { +- status = AE_SUPPORT; +- } else if (psv > 0) { +- tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv); +- status = AE_OK; +- } else { ++ if (flag & ACPI_TRIPS_HOT) { + status = acpi_evaluate_integer(tz->device->handle, +- "_PSV", NULL, &tz->trips.passive.temperature); ++ "_HOT", NULL, &tz->trips.hot.temperature); ++ if (ACPI_FAILURE(status)) { ++ tz->trips.hot.flags.valid = 0; ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, ++ "No hot threshold\n")); ++ } else { ++ tz->trips.hot.flags.valid = 1; ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, ++ "Found hot threshold [%lu]\n", ++ tz->trips.critical.temperature)); ++ } + } + +- if (ACPI_FAILURE(status)) { +- tz->trips.passive.flags.valid = 0; +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n")); +- } else { +- tz->trips.passive.flags.valid = 1; +- +- status = +- acpi_evaluate_integer(tz->device->handle, "_TC1", NULL, +- &tz->trips.passive.tc1); +- if (ACPI_FAILURE(status)) +- tz->trips.passive.flags.valid = 0; +- +- status = +- acpi_evaluate_integer(tz->device->handle, "_TC2", NULL, +- &tz->trips.passive.tc2); +- if (ACPI_FAILURE(status)) +- tz->trips.passive.flags.valid = 0; ++ /* Passive (optional) */ ++ if (flag & ACPI_TRIPS_PASSIVE) { ++ valid = tz->trips.passive.flags.valid; ++ if (psv == -1) { ++ status = AE_SUPPORT; ++ } else if (psv > 0) { ++ tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv); ++ status = AE_OK; ++ } else { ++ status = acpi_evaluate_integer(tz->device->handle, ++ "_PSV", NULL, &tz->trips.passive.temperature); ++ } + +- status = +- acpi_evaluate_integer(tz->device->handle, "_TSP", NULL, +- &tz->trips.passive.tsp); + if (ACPI_FAILURE(status)) + tz->trips.passive.flags.valid = 0; +- +- status = +- acpi_evaluate_reference(tz->device->handle, "_PSL", NULL, +- &tz->trips.passive.devices); ++ else { ++ tz->trips.passive.flags.valid = 1; ++ if (flag == ACPI_TRIPS_INIT) { ++ status = acpi_evaluate_integer( ++ tz->device->handle, "_TC1", ++ NULL, &tz->trips.passive.tc1); ++ if (ACPI_FAILURE(status)) ++ tz->trips.passive.flags.valid = 0; ++ status = acpi_evaluate_integer( ++ tz->device->handle, "_TC2", ++ NULL, &tz->trips.passive.tc2); ++ if (ACPI_FAILURE(status)) ++ tz->trips.passive.flags.valid = 0; ++ status = acpi_evaluate_integer( ++ tz->device->handle, "_TSP", ++ NULL, &tz->trips.passive.tsp); ++ if (ACPI_FAILURE(status)) ++ tz->trips.passive.flags.valid = 0; ++ } ++ } ++ } ++ if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) { ++ memset(&devices, 0, sizeof(struct acpi_handle_list)); ++ status = acpi_evaluate_reference(tz->device->handle, "_PSL", ++ NULL, &devices); + if (ACPI_FAILURE(status)) + tz->trips.passive.flags.valid = 0; +- +- if (!tz->trips.passive.flags.valid) +- printk(KERN_WARNING PREFIX "Invalid passive threshold\n"); + else +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, +- "Found passive threshold [%lu]\n", +- tz->trips.passive.temperature)); +- } ++ tz->trips.passive.flags.valid = 1; + +- /* Active: Fans, etc. (optional) */ ++ if (memcmp(&tz->trips.passive.devices, &devices, ++ sizeof(struct acpi_handle_list))) { ++ memcpy(&tz->trips.passive.devices, &devices, ++ sizeof(struct acpi_handle_list)); ++ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); ++ } ++ } ++ if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) { ++ if (valid != tz->trips.passive.flags.valid) ++ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state"); ++ } + ++ /* Active (optional) */ + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { +- + char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; ++ valid = tz->trips.active[i].flags.valid; + + if (act == -1) +- break; /* disable all active trip points */ +- +- status = acpi_evaluate_integer(tz->device->handle, +- name, NULL, &tz->trips.active[i].temperature); +- +- if (ACPI_FAILURE(status)) { +- if (i == 0) /* no active trip points */ ++ break; /* disable all active trip points */ ++ ++ if (flag & ACPI_TRIPS_ACTIVE) { ++ status = acpi_evaluate_integer(tz->device->handle, ++ name, NULL, &tz->trips.active[i].temperature); ++ if (ACPI_FAILURE(status)) { ++ tz->trips.active[i].flags.valid = 0; ++ if (i == 0) ++ break; ++ if (act <= 0) ++ break; ++ if (i == 1) ++ tz->trips.active[0].temperature = ++ CELSIUS_TO_KELVIN(act); ++ else ++ /* ++ * Don't allow override higher than ++ * the next higher trip point ++ */ ++ tz->trips.active[i - 1].temperature = ++ (tz->trips.active[i - 2].temperature < ++ CELSIUS_TO_KELVIN(act) ? ++ tz->trips.active[i - 2].temperature : ++ CELSIUS_TO_KELVIN(act)); + break; +- if (act <= 0) /* no override requested */ +- break; +- if (i == 1) { /* 1 trip point */ +- tz->trips.active[0].temperature = +- CELSIUS_TO_KELVIN(act); +- } else { /* multiple trips */ +- /* +- * Don't allow override higher than +- * the next higher trip point +- */ +- tz->trips.active[i - 1].temperature = +- (tz->trips.active[i - 2].temperature < +- CELSIUS_TO_KELVIN(act) ? +- tz->trips.active[i - 2].temperature : +- CELSIUS_TO_KELVIN(act)); +- } +- break; ++ } else ++ tz->trips.active[i].flags.valid = 1; + } + + name[2] = 'L'; +- status = +- acpi_evaluate_reference(tz->device->handle, name, NULL, +- &tz->trips.active[i].devices); +- if (ACPI_SUCCESS(status)) { +- tz->trips.active[i].flags.valid = 1; +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, +- "Found active threshold [%d]:[%lu]\n", +- i, tz->trips.active[i].temperature)); +- } else +- ACPI_EXCEPTION((AE_INFO, status, +- "Invalid active threshold [%d]", i)); ++ if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) { ++ memset(&devices, 0, sizeof(struct acpi_handle_list)); ++ status = acpi_evaluate_reference(tz->device->handle, ++ name, NULL, &devices); ++ if (ACPI_FAILURE(status)) ++ tz->trips.active[i].flags.valid = 0; ++ else ++ tz->trips.active[i].flags.valid = 1; ++ ++ if (memcmp(&tz->trips.active[i].devices, &devices, ++ sizeof(struct acpi_handle_list))) { ++ memcpy(&tz->trips.active[i].devices, &devices, ++ sizeof(struct acpi_handle_list)); ++ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); ++ } ++ } ++ if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES)) ++ if (valid != tz->trips.active[i].flags.valid) ++ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state"); ++ ++ if (!tz->trips.active[i].flags.valid) ++ break; ++ } ++ ++ if (flag & ACPI_TRIPS_DEVICES) { ++ memset(&devices, 0, sizeof(struct acpi_handle_list)); ++ status = acpi_evaluate_reference(tz->device->handle, "_TZD", ++ NULL, &devices); ++ if (memcmp(&tz->devices, &devices, ++ sizeof(struct acpi_handle_list))) { ++ memcpy(&tz->devices, &devices, ++ sizeof(struct acpi_handle_list)); ++ ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device"); ++ } + } + + return 0; + } + +-static int acpi_thermal_get_devices(struct acpi_thermal *tz) ++static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) + { +- acpi_status status = AE_OK; +- +- +- if (!tz) +- return -EINVAL; +- +- status = +- acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices); +- if (ACPI_FAILURE(status)) +- return -ENODEV; +- +- return 0; ++ return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT); + } + + static int acpi_thermal_critical(struct acpi_thermal *tz) +@@ -732,6 +779,9 @@ static void acpi_thermal_check(void *data) + if (result) + goto unlock; + ++ if (!tz->tz_enabled) ++ goto unlock; ++ + memset(&tz->state, 0, sizeof(tz->state)); + + /* +@@ -825,6 +875,290 @@ static void acpi_thermal_check(void *data) + mutex_unlock(&tz->lock); + } + ++/* sys I/F for generic thermal sysfs support */ ++static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf) ++{ ++ struct acpi_thermal *tz = thermal->devdata; ++ ++ if (!tz) ++ return -EINVAL; ++ ++ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature)); ++} ++ ++static const char enabled[] = "kernel"; ++static const char disabled[] = "user"; ++static int thermal_get_mode(struct thermal_zone_device *thermal, ++ char *buf) ++{ ++ struct acpi_thermal *tz = thermal->devdata; ++ ++ if (!tz) ++ return -EINVAL; ++ ++ return sprintf(buf, "%s\n", tz->tz_enabled ? ++ enabled : disabled); ++} ++ ++static int thermal_set_mode(struct thermal_zone_device *thermal, ++ const char *buf) ++{ ++ struct acpi_thermal *tz = thermal->devdata; ++ int enable; ++ ++ if (!tz) ++ return -EINVAL; ++ ++ /* ++ * enable/disable thermal management from ACPI thermal driver ++ */ ++ if (!strncmp(buf, enabled, sizeof enabled - 1)) ++ enable = 1; ++ else if (!strncmp(buf, disabled, sizeof disabled - 1)) ++ enable = 0; ++ else ++ return -EINVAL; ++ ++ if (enable != tz->tz_enabled) { ++ tz->tz_enabled = enable; ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, ++ "%s ACPI thermal control\n", ++ tz->tz_enabled ? enabled : disabled)); ++ acpi_thermal_check(tz); ++ } ++ return 0; ++} ++ ++static int thermal_get_trip_type(struct thermal_zone_device *thermal, ++ int trip, char *buf) ++{ ++ struct acpi_thermal *tz = thermal->devdata; ++ int i; ++ ++ if (!tz || trip < 0) ++ return -EINVAL; ++ ++ if (tz->trips.critical.flags.valid) { ++ if (!trip) ++ return sprintf(buf, "critical\n"); ++ trip--; ++ } ++ ++ if (tz->trips.hot.flags.valid) { ++ if (!trip) ++ return sprintf(buf, "hot\n"); ++ trip--; ++ } ++ ++ if (tz->trips.passive.flags.valid) { ++ if (!trip) ++ return sprintf(buf, "passive\n"); ++ trip--; ++ } ++ ++ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && ++ tz->trips.active[i].flags.valid; i++) { ++ if (!trip) ++ return sprintf(buf, "active%d\n", i); ++ trip--; ++ } ++ ++ return -EINVAL; ++} ++ ++static int thermal_get_trip_temp(struct thermal_zone_device *thermal, ++ int trip, char *buf) ++{ ++ struct acpi_thermal *tz = thermal->devdata; ++ int i; ++ ++ if (!tz || trip < 0) ++ return -EINVAL; ++ ++ if (tz->trips.critical.flags.valid) { ++ if (!trip) ++ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( ++ tz->trips.critical.temperature)); ++ trip--; ++ } ++ ++ if (tz->trips.hot.flags.valid) { ++ if (!trip) ++ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( ++ tz->trips.hot.temperature)); ++ trip--; ++ } ++ ++ if (tz->trips.passive.flags.valid) { ++ if (!trip) ++ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( ++ tz->trips.passive.temperature)); ++ trip--; ++ } ++ ++ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && ++ tz->trips.active[i].flags.valid; i++) { ++ if (!trip) ++ return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( ++ tz->trips.active[i].temperature)); ++ trip--; ++ } ++ ++ return -EINVAL; ++} ++ ++typedef int (*cb)(struct thermal_zone_device *, int, ++ struct thermal_cooling_device *); ++static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, ++ struct thermal_cooling_device *cdev, ++ cb action) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_thermal *tz = thermal->devdata; ++ struct acpi_device *dev; ++ acpi_status status; ++ acpi_handle handle; ++ int i; ++ int j; ++ int trip = -1; ++ int result = 0; ++ ++ if (tz->trips.critical.flags.valid) ++ trip++; ++ ++ if (tz->trips.hot.flags.valid) ++ trip++; ++ ++ if (tz->trips.passive.flags.valid) { ++ trip++; ++ for (i = 0; i < tz->trips.passive.devices.count; ++ i++) { ++ handle = tz->trips.passive.devices.handles[i]; ++ status = acpi_bus_get_device(handle, &dev); ++ if (ACPI_SUCCESS(status) && (dev == device)) { ++ result = action(thermal, trip, cdev); ++ if (result) ++ goto failed; ++ } ++ } ++ } ++ ++ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { ++ if (!tz->trips.active[i].flags.valid) ++ break; ++ trip++; ++ for (j = 0; ++ j < tz->trips.active[i].devices.count; ++ j++) { ++ handle = tz->trips.active[i].devices.handles[j]; ++ status = acpi_bus_get_device(handle, &dev); ++ if (ACPI_SUCCESS(status) && (dev == device)) { ++ result = action(thermal, trip, cdev); ++ if (result) ++ goto failed; ++ } ++ } ++ } ++ ++ for (i = 0; i < tz->devices.count; i++) { ++ handle = tz->devices.handles[i]; ++ status = acpi_bus_get_device(handle, &dev); ++ if (ACPI_SUCCESS(status) && (dev == device)) { ++ result = action(thermal, -1, cdev); ++ if (result) ++ goto failed; ++ } ++ } ++ ++failed: ++ return result; ++} ++ ++static int ++acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal, ++ struct thermal_cooling_device *cdev) ++{ ++ return acpi_thermal_cooling_device_cb(thermal, cdev, ++ thermal_zone_bind_cooling_device); ++} ++ ++static int ++acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal, ++ struct thermal_cooling_device *cdev) ++{ ++ return acpi_thermal_cooling_device_cb(thermal, cdev, ++ thermal_zone_unbind_cooling_device); ++} ++ ++static struct thermal_zone_device_ops acpi_thermal_zone_ops = { ++ .bind = acpi_thermal_bind_cooling_device, ++ .unbind = acpi_thermal_unbind_cooling_device, ++ .get_temp = thermal_get_temp, ++ .get_mode = thermal_get_mode, ++ .set_mode = thermal_set_mode, ++ .get_trip_type = thermal_get_trip_type, ++ .get_trip_temp = thermal_get_trip_temp, ++}; ++ ++static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) ++{ ++ int trips = 0; ++ int result; ++ acpi_status status; ++ int i; ++ ++ if (tz->trips.critical.flags.valid) ++ trips++; ++ ++ if (tz->trips.hot.flags.valid) ++ trips++; ++ ++ if (tz->trips.passive.flags.valid) ++ trips++; ++ ++ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && ++ tz->trips.active[i].flags.valid; i++, trips++); ++ tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone", ++ trips, tz, &acpi_thermal_zone_ops); ++ if (!tz->thermal_zone) ++ return -ENODEV; ++ ++ result = sysfs_create_link(&tz->device->dev.kobj, ++ &tz->thermal_zone->device.kobj, "thermal_zone"); ++ if (result) ++ return result; ++ ++ result = sysfs_create_link(&tz->thermal_zone->device.kobj, ++ &tz->device->dev.kobj, "device"); ++ if (result) ++ return result; ++ ++ status = acpi_attach_data(tz->device->handle, ++ acpi_bus_private_data_handler, ++ tz->thermal_zone); ++ if (ACPI_FAILURE(status)) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "Error attaching device data\n")); ++ return -ENODEV; ++ } ++ ++ tz->tz_enabled = 1; ++ ++ printk(KERN_INFO PREFIX "%s is registered as thermal_zone%d\n", ++ tz->device->dev.bus_id, tz->thermal_zone->id); ++ return 0; ++} ++ ++static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) ++{ ++ sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone"); ++ sysfs_remove_link(&tz->thermal_zone->device.kobj, "device"); ++ thermal_zone_device_unregister(tz->thermal_zone); ++ tz->thermal_zone = NULL; ++ acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler); ++} ++ ++ + /* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ +@@ -1181,15 +1515,15 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data) + acpi_thermal_check(tz); + break; + case ACPI_THERMAL_NOTIFY_THRESHOLDS: +- acpi_thermal_get_trip_points(tz); ++ acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS); + acpi_thermal_check(tz); + acpi_bus_generate_proc_event(device, event, 0); + acpi_bus_generate_netlink_event(device->pnp.device_class, + device->dev.bus_id, event, 0); + break; + case ACPI_THERMAL_NOTIFY_DEVICES: +- if (tz->flags.devices) +- acpi_thermal_get_devices(tz); ++ acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES); ++ acpi_thermal_check(tz); + acpi_bus_generate_proc_event(device, event, 0); + acpi_bus_generate_netlink_event(device->pnp.device_class, + device->dev.bus_id, event, 0); +@@ -1232,11 +1566,6 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz) + else + acpi_thermal_get_polling_frequency(tz); + +- /* Get devices in this thermal zone [_TZD] (optional) */ +- result = acpi_thermal_get_devices(tz); +- if (!result) +- tz->flags.devices = 1; +- + return 0; + } + +@@ -1260,13 +1589,19 @@ static int acpi_thermal_add(struct acpi_device *device) + strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); + acpi_driver_data(device) = tz; + mutex_init(&tz->lock); ++ ++ + result = acpi_thermal_get_info(tz); + if (result) +- goto end; ++ goto free_memory; ++ ++ result = acpi_thermal_register_thermal_zone(tz); ++ if (result) ++ goto free_memory; + + result = acpi_thermal_add_fs(device); + if (result) +- goto end; ++ goto unregister_thermal_zone; + + init_timer(&tz->timer); + +@@ -1277,19 +1612,21 @@ static int acpi_thermal_add(struct acpi_device *device) + acpi_thermal_notify, tz); + if (ACPI_FAILURE(status)) { + result = -ENODEV; +- goto end; ++ goto remove_fs; + } + + printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n", + acpi_device_name(device), acpi_device_bid(device), + KELVIN_TO_CELSIUS(tz->temperature)); ++ goto end; + +- end: +- if (result) { +- acpi_thermal_remove_fs(device); +- kfree(tz); +- } +- ++remove_fs: ++ acpi_thermal_remove_fs(device); ++unregister_thermal_zone: ++ thermal_zone_device_unregister(tz->thermal_zone); ++free_memory: ++ kfree(tz); ++end: + return result; + } + +@@ -1329,6 +1666,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type) + } + + acpi_thermal_remove_fs(device); ++ acpi_thermal_unregister_thermal_zone(tz); + mutex_destroy(&tz->lock); + kfree(tz); + return 0; +diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c +index 826a52f..c83b76c 100644 +--- a/drivers/acpi/video.c ++++ b/drivers/acpi/video.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -183,6 +184,7 @@ struct acpi_video_device { + struct acpi_device *dev; + struct acpi_video_device_brightness *brightness; + struct backlight_device *backlight; ++ struct thermal_cooling_device *cdev; + struct output_device *output_dev; + }; + +@@ -346,6 +348,54 @@ static struct output_properties acpi_output_properties = { + .set_state = acpi_video_output_set, + .get_status = acpi_video_output_get, + }; ++ ++ ++/* thermal cooling device callbacks */ ++static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_video_device *video = acpi_driver_data(device); ++ ++ return sprintf(buf, "%d\n", video->brightness->count - 3); ++} ++ ++static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_video_device *video = acpi_driver_data(device); ++ unsigned long level; ++ int state; ++ ++ acpi_video_device_lcd_get_level_current(video, &level); ++ for (state = 2; state < video->brightness->count; state++) ++ if (level == video->brightness->levels[state]) ++ return sprintf(buf, "%d\n", ++ video->brightness->count - state - 1); ++ ++ return -EINVAL; ++} ++ ++static int ++video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) ++{ ++ struct acpi_device *device = cdev->devdata; ++ struct acpi_video_device *video = acpi_driver_data(device); ++ int level; ++ ++ if ( state >= video->brightness->count - 2) ++ return -EINVAL; ++ ++ state = video->brightness->count - state; ++ level = video->brightness->levels[state -1]; ++ return acpi_video_device_lcd_set_level(video, level); ++} ++ ++static struct thermal_cooling_device_ops video_cooling_ops = { ++ .get_max_state = video_get_max_state, ++ .get_cur_state = video_get_cur_state, ++ .set_cur_state = video_set_cur_state, ++}; ++ + /* -------------------------------------------------------------------------- + Video Management + -------------------------------------------------------------------------- */ +@@ -664,6 +714,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) + kfree(obj); + + if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){ ++ int result; + static int count = 0; + char *name; + name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); +@@ -676,8 +727,25 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) + device->backlight->props.max_brightness = device->brightness->count-3; + device->backlight->props.brightness = acpi_video_get_brightness(device->backlight); + backlight_update_status(device->backlight); +- + kfree(name); ++ ++ device->cdev = thermal_cooling_device_register("LCD", ++ device->dev, &video_cooling_ops); ++ if (device->cdev) { ++ printk(KERN_INFO PREFIX ++ "%s is registered as cooling_device%d\n", ++ device->dev->dev.bus_id, device->cdev->id); ++ result = sysfs_create_link(&device->dev->dev.kobj, ++ &device->cdev->device.kobj, ++ "thermal_cooling"); ++ if (result) ++ printk(KERN_ERR PREFIX "Create sysfs link\n"); ++ result = sysfs_create_link(&device->cdev->device.kobj, ++ &device->dev->dev.kobj, ++ "device"); ++ if (result) ++ printk(KERN_ERR PREFIX "Create sysfs link\n"); ++ } + } + if (device->cap._DCS && device->cap._DSS){ + static int count = 0; +@@ -1739,6 +1807,14 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) + ACPI_DEVICE_NOTIFY, + acpi_video_device_notify); + backlight_device_unregister(device->backlight); ++ if (device->cdev) { ++ sysfs_remove_link(&device->dev->dev.kobj, ++ "thermal_cooling"); ++ sysfs_remove_link(&device->cdev->device.kobj, ++ "device"); ++ thermal_cooling_device_unregister(device->cdev); ++ device->cdev = NULL; ++ } + video_output_unregister(device->output_dev); + + return 0; +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index b5e67c0..46a131a 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -232,4 +232,14 @@ config ATMEL_SSC + + If unsure, say N. + ++config INTEL_MENLOW ++ tristate "Thermal Management driver for Intel menlow platform" ++ depends on ACPI_THERMAL ++ default n ++ ---help--- ++ ACPI thermal management enhancement driver on ++ Intel Menlow platform. ++ ++ If you are not sure, say N here. ++ + endif # MISC_DEVICES +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index 87f2685..a9e8faf 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -17,3 +17,4 @@ obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o + obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o + obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o + obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o ++obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o +diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c +new file mode 100644 +index 0000000..753dc5f +--- /dev/null ++++ b/drivers/misc/intel_menlow.c +@@ -0,0 +1,527 @@ ++/* ++* intel_menlow.c - Intel menlow Driver for thermal management extension ++* ++* Copyright (C) 2008 Intel Corp ++* Copyright (C) 2008 Sujith Thomas ++* Copyright (C) 2008 Zhang Rui ++* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++* ++* 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; version 2 of the License. ++* ++* This program is distributed in the hope that it will be useful, but ++* WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++* General Public License for more details. ++* ++* You should have received a copy of the GNU General Public License along ++* with this program; if not, write to the Free Software Foundation, Inc., ++* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++* ++* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++* ++* This driver creates the sys I/F for programming the sensors. ++* It also implements the driver for intel menlow memory controller (hardware ++* id is INT0002) which makes use of the platform specific ACPI methods ++* to get/set bandwidth. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Thomas Sujith"); ++MODULE_AUTHOR("Zhang Rui"); ++MODULE_DESCRIPTION("Intel Menlow platform specific driver"); ++MODULE_LICENSE("GPL"); ++ ++/* ++ * Memory controller device control ++ */ ++ ++#define MEMORY_GET_BANDWIDTH "GTHS" ++#define MEMORY_SET_BANDWIDTH "STHS" ++#define MEMORY_ARG_CUR_BANDWIDTH 1 ++#define MEMORY_ARG_MAX_BANDWIDTH 0 ++ ++static int ++memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev, ++ unsigned long *max_state) ++{ ++ struct acpi_device *device = cdev->devdata; ++ acpi_handle handle = device->handle; ++ unsigned long value; ++ struct acpi_object_list arg_list; ++ union acpi_object arg; ++ acpi_status status = AE_OK; ++ ++ arg_list.count = 1; ++ arg_list.pointer = &arg; ++ arg.type = ACPI_TYPE_INTEGER; ++ arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH; ++ status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, ++ &arg_list, &value); ++ if (ACPI_FAILURE(status)) ++ return -EFAULT; ++ ++ *max_state = value - 1; ++ return 0; ++} ++ ++static int ++memory_get_max_bandwidth(struct thermal_cooling_device *cdev, char *buf) ++{ ++ unsigned long value; ++ if (memory_get_int_max_bandwidth(cdev,&value)) ++ return -EINVAL; ++ ++ return sprintf(buf, "%ld\n", value); ++} ++ ++static int ++memory_get_cur_bandwidth(struct thermal_cooling_device *cdev, char *buf) ++{ ++ struct acpi_device *device = cdev->devdata; ++ acpi_handle handle = device->handle; ++ unsigned long value; ++ struct acpi_object_list arg_list; ++ union acpi_object arg; ++ acpi_status status = AE_OK; ++ ++ arg_list.count = 1; ++ arg_list.pointer = &arg; ++ arg.type = ACPI_TYPE_INTEGER; ++ arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH; ++ status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, ++ &arg_list, &value); ++ if (ACPI_FAILURE(status)) ++ return -EFAULT; ++ ++ return sprintf(buf, "%ld\n", value); ++} ++ ++static int ++memory_set_cur_bandwidth(struct thermal_cooling_device *cdev, ++ unsigned int state) ++{ ++ struct acpi_device *device = cdev->devdata; ++ acpi_handle handle = device->handle; ++ struct acpi_object_list arg_list; ++ union acpi_object arg; ++ acpi_status status; ++ int temp; ++ unsigned long max_state; ++ ++ if (memory_get_int_max_bandwidth(cdev,&max_state)) ++ return -EFAULT; ++ ++ if (max_state < 0 || state > max_state) ++ return -EINVAL; ++ ++ arg_list.count = 1; ++ arg_list.pointer = &arg; ++ arg.type = ACPI_TYPE_INTEGER; ++ arg.integer.value = state; ++ ++ status = ++ acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list, ++ (unsigned long *)&temp); ++ ++ printk(KERN_INFO ++ "Bandwidth value was %d: status is %d\n", state, status); ++ if (ACPI_FAILURE(status)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static struct thermal_cooling_device_ops memory_cooling_ops = { ++ .get_max_state = memory_get_max_bandwidth, ++ .get_cur_state = memory_get_cur_bandwidth, ++ .set_cur_state = memory_set_cur_bandwidth, ++}; ++ ++/* ++ * Memory Device Management ++ */ ++static int intel_menlow_memory_add(struct acpi_device *device) ++{ ++ int result = -ENODEV; ++ acpi_status status = AE_OK; ++ acpi_handle dummy; ++ struct thermal_cooling_device *cdev; ++ ++ if (!device) ++ return -EINVAL; ++ ++ status = acpi_get_handle(device->handle, MEMORY_GET_BANDWIDTH, &dummy); ++ if (ACPI_FAILURE(status)) ++ goto end; ++ ++ status = acpi_get_handle(device->handle, MEMORY_SET_BANDWIDTH, &dummy); ++ if (ACPI_FAILURE(status)) ++ goto end; ++ ++ cdev = thermal_cooling_device_register("Memory controller", device, ++ &memory_cooling_ops); ++ acpi_driver_data(device) = cdev; ++ if (!cdev) ++ result = -ENODEV; ++ else { ++ result = ++ sysfs_create_link(&device->dev.kobj, &cdev->device.kobj, ++ "thermal_cooling"); ++ if (result) ++ goto end; ++ result = ++ sysfs_create_link(&cdev->device.kobj, &device->dev.kobj, ++ "device"); ++ if (result) ++ goto end; ++ } ++ ++ end: ++ return result; ++} ++ ++static int intel_menlow_memory_remove(struct acpi_device *device, int type) ++{ ++ struct thermal_cooling_device *cdev = acpi_driver_data(device); ++ ++ if (!device || !cdev) ++ return -EINVAL; ++ ++ sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); ++ sysfs_remove_link(&cdev->device.kobj, "device"); ++ thermal_cooling_device_unregister(cdev); ++ ++ return 0; ++} ++ ++const static struct acpi_device_id intel_menlow_memory_ids[] = { ++ {"INT0002", 0}, ++ {"", 0}, ++}; ++ ++static struct acpi_driver intel_menlow_memory_driver = { ++ .name = "intel_menlow_thermal_control", ++ .ids = intel_menlow_memory_ids, ++ .ops = { ++ .add = intel_menlow_memory_add, ++ .remove = intel_menlow_memory_remove, ++ }, ++}; ++ ++/* ++ * Sensor control on menlow platform ++ */ ++ ++#define THERMAL_AUX0 0 ++#define THERMAL_AUX1 1 ++#define GET_AUX0 "GAX0" ++#define GET_AUX1 "GAX1" ++#define SET_AUX0 "SAX0" ++#define SET_AUX1 "SAX1" ++ ++struct intel_menlow_attribute { ++ struct device_attribute attr; ++ struct device *device; ++ acpi_handle handle; ++ struct list_head node; ++}; ++ ++static LIST_HEAD(intel_menlow_attr_list); ++static DEFINE_MUTEX(intel_menlow_attr_lock); ++ ++/* ++ * sensor_get_auxtrip ++ * ----------------- ++ * get the current auxtrip value from sensor through proprietory ACPI methods ++ * name: Thermalzone name ++ * auxtype : AUX0/AUX1 ++ * buf: syfs buffer ++ */ ++static int sensor_get_auxtrip(acpi_handle handle, int index, int *value) ++{ ++ acpi_status status; ++ ++ if ((index != 0 && index != 1) || !value) ++ return -EINVAL; ++ ++ status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0, ++ NULL, (unsigned long *)value); ++ if (ACPI_FAILURE(status)) ++ return -EIO; ++ ++ return 0; ++} ++ ++/* ++ * sensor_set_auxtrip ++ * ----------------- ++ * set the new auxtrip value to sensor through proprietory ACPI methods ++ * name: Thermalzone name ++ * auxtype : AUX0/AUX1 ++ * buf: syfs buffer ++ */ ++static int sensor_set_auxtrip(acpi_handle handle, int index, int value) ++{ ++ acpi_status status; ++ union acpi_object arg = { ++ ACPI_TYPE_INTEGER ++ }; ++ struct acpi_object_list args = { ++ 1, &arg ++ }; ++ int temp; ++ ++ if (index != 0 && index != 1) ++ return -EINVAL; ++ ++ status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1, ++ NULL, (unsigned long *)&temp); ++ if (ACPI_FAILURE(status)) ++ return -EIO; ++ if ((index && value < temp) || (!index && value > temp)) ++ return -EINVAL; ++ ++ arg.integer.value = value; ++ status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0, ++ &args, (unsigned long *)&temp); ++ if (ACPI_FAILURE(status)) ++ return -EIO; ++ ++ /* do we need to check the return value of SAX0/SAX1 ? */ ++ ++ return 0; ++} ++ ++#define to_intel_menlow_attr(_attr) \ ++ container_of(_attr, struct intel_menlow_attribute, attr) ++ ++static ssize_t aux0_show(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); ++ int value; ++ int result; ++ ++ result = sensor_get_auxtrip(attr->handle, 0, &value); ++ ++ return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); ++} ++ ++static ssize_t aux1_show(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); ++ int value; ++ int result; ++ ++ result = sensor_get_auxtrip(attr->handle, 1, &value); ++ ++ return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); ++} ++ ++static ssize_t aux0_store(struct device *dev, ++ struct device_attribute *dev_attr, ++ const char *buf, size_t count) ++{ ++ struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); ++ int value; ++ int result; ++ ++ /*Sanity check; should be a positive integer */ ++ if (!sscanf(buf, "%d", &value)) ++ return -EINVAL; ++ ++ if (value < 0) ++ return -EINVAL; ++ ++ result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value)); ++ return result ? result : count; ++} ++ ++static ssize_t aux1_store(struct device *dev, ++ struct device_attribute *dev_attr, ++ const char *buf, size_t count) ++{ ++ struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); ++ int value; ++ int result; ++ ++ /*Sanity check; should be a positive integer */ ++ if (!sscanf(buf, "%d", &value)) ++ return -EINVAL; ++ ++ if (value < 0) ++ return -EINVAL; ++ ++ result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value)); ++ return result ? result : count; ++} ++ ++/* BIOS can enable/disable the thermal user application in dabney platform */ ++#define BIOS_ENABLED "\\_TZ.GSTS" ++static ssize_t bios_enabled_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ acpi_status status; ++ unsigned long bios_enabled; ++ ++ status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled); ++ if (ACPI_FAILURE(status)) ++ return -ENODEV; ++ ++ return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled"); ++} ++ ++static int intel_menlow_add_one_attribute(char *name, int mode, void *show, ++ void *store, struct device *dev, ++ acpi_handle handle) ++{ ++ struct intel_menlow_attribute *attr; ++ int result; ++ ++ attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL); ++ if (!attr) ++ return -ENOMEM; ++ ++ attr->attr.attr.name = name; ++ attr->attr.attr.mode = mode; ++ attr->attr.show = show; ++ attr->attr.store = store; ++ attr->device = dev; ++ attr->handle = handle; ++ ++ result = device_create_file(dev, &attr->attr); ++ if (result) ++ return result; ++ ++ mutex_lock(&intel_menlow_attr_lock); ++ list_add_tail(&attr->node, &intel_menlow_attr_list); ++ mutex_unlock(&intel_menlow_attr_lock); ++ ++ return 0; ++} ++ ++static acpi_status ++intel_menlow_register_sensor(acpi_handle handle, u32 lvl, ++ void *context, void **rv) ++{ ++ acpi_status status; ++ acpi_handle dummy; ++ struct thermal_zone_device *thermal; ++ int result; ++ ++ result = acpi_bus_get_private_data(handle, (void **)&thermal); ++ if (result) ++ return 0; ++ ++ /* _TZ must have the AUX0/1 methods */ ++ status = acpi_get_handle(handle, GET_AUX0, &dummy); ++ if (ACPI_FAILURE(status)) ++ goto not_found; ++ ++ status = acpi_get_handle(handle, SET_AUX0, &dummy); ++ if (ACPI_FAILURE(status)) ++ goto not_found; ++ ++ result = intel_menlow_add_one_attribute("aux0", 0644, ++ aux0_show, aux0_store, ++ &thermal->device, handle); ++ if (result) ++ return AE_ERROR; ++ ++ status = acpi_get_handle(handle, GET_AUX1, &dummy); ++ if (ACPI_FAILURE(status)) ++ goto not_found; ++ ++ status = acpi_get_handle(handle, SET_AUX1, &dummy); ++ if (ACPI_FAILURE(status)) ++ goto not_found; ++ ++ result = intel_menlow_add_one_attribute("aux1", 0644, ++ aux1_show, aux1_store, ++ &thermal->device, handle); ++ if (result) ++ return AE_ERROR; ++ ++ /* ++ * create the "dabney_enabled" attribute which means the user app ++ * should be loaded or not ++ */ ++ ++ result = intel_menlow_add_one_attribute("bios_enabled", 0444, ++ bios_enabled_show, NULL, ++ &thermal->device, handle); ++ if (result) ++ return AE_ERROR; ++ ++ not_found: ++ if (status == AE_NOT_FOUND) ++ return AE_OK; ++ else ++ return status; ++} ++ ++static void intel_menlow_unregister_sensor(void) ++{ ++ struct intel_menlow_attribute *pos, *next; ++ ++ mutex_lock(&intel_menlow_attr_lock); ++ list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) { ++ list_del(&pos->node); ++ device_remove_file(pos->device, &pos->attr); ++ kfree(pos); ++ } ++ mutex_unlock(&intel_menlow_attr_lock); ++ ++ return; ++} ++ ++static int __init intel_menlow_module_init(void) ++{ ++ int result = -ENODEV; ++ acpi_status status; ++ unsigned long enable; ++ ++ if (acpi_disabled) ++ return result; ++ ++ /* Looking for the \_TZ.GSTS method */ ++ status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable); ++ if (ACPI_FAILURE(status) || !enable) ++ return -ENODEV; ++ ++ /* Looking for ACPI device MEM0 with hardware id INT0002 */ ++ result = acpi_bus_register_driver(&intel_menlow_memory_driver); ++ if (result) ++ return result; ++ ++ /* Looking for sensors in each ACPI thermal zone */ ++ status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT, ++ ACPI_UINT32_MAX, ++ intel_menlow_register_sensor, NULL, NULL); ++ if (ACPI_FAILURE(status)) ++ result = -ENODEV; ++ ++ return 0; ++} ++ ++static void __exit intel_menlow_module_exit(void) ++{ ++ acpi_bus_unregister_driver(&intel_menlow_memory_driver); ++ intel_menlow_unregister_sensor(); ++} ++ ++module_init(intel_menlow_module_init); ++module_exit(intel_menlow_module_exit); +diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig +new file mode 100644 +index 0000000..b879d27 +--- /dev/null ++++ b/drivers/thermal/Kconfig +@@ -0,0 +1,16 @@ ++# ++# Generic thermal sysfs drivers configuration ++# ++ ++menuconfig THERMAL ++ bool "Generic Thermal sysfs driver" ++ default y ++ help ++ Generic Thermal Sysfs driver offers a generic mechanism for ++ thermal management. Usually it's made up of one or more thermal ++ zone and cooling device. ++ each thermal zone contains its own temperature, trip points, ++ cooling devices. ++ All platforms with ACPI thermal support can use this driver. ++ If you want this support, you should say Y here ++ +diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile +new file mode 100644 +index 0000000..75b4bf2 +--- /dev/null ++++ b/drivers/thermal/Makefile +@@ -0,0 +1,6 @@ ++# ++# Makefile for sensor chip drivers. ++# ++ ++obj-$(CONFIG_THERMAL) += thermal.o ++ +diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal.c +new file mode 100644 +index 0000000..3273e34 +--- /dev/null ++++ b/drivers/thermal/thermal.c +@@ -0,0 +1,714 @@ ++/* ++ * thermal.c - Generic Thermal Management Sysfs support. ++ * ++ * Copyright (C) 2008 Intel Corp ++ * Copyright (C) 2008 Zhang Rui ++ * Copyright (C) 2008 Sujith Thomas ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * 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; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Zhang Rui") ++MODULE_DESCRIPTION("Generic thermal management sysfs support"); ++MODULE_LICENSE("GPL"); ++ ++#define PREFIX "Thermal: " ++ ++struct thermal_cooling_device_instance { ++ int id; ++ char name[THERMAL_NAME_LENGTH]; ++ struct thermal_zone_device *tz; ++ struct thermal_cooling_device *cdev; ++ int trip; ++ char attr_name[THERMAL_NAME_LENGTH]; ++ struct device_attribute attr; ++ struct list_head node; ++}; ++ ++static DEFINE_IDR(thermal_tz_idr); ++static DEFINE_IDR(thermal_cdev_idr); ++static DEFINE_MUTEX(thermal_idr_lock); ++ ++static LIST_HEAD(thermal_tz_list); ++static LIST_HEAD(thermal_cdev_list); ++static DEFINE_MUTEX(thermal_list_lock); ++ ++static int get_idr(struct idr *idr, struct mutex *lock, int *id) ++{ ++ int err; ++ ++ again: ++ if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0)) ++ return -ENOMEM; ++ ++ if (lock) ++ mutex_lock(lock); ++ err = idr_get_new(idr, NULL, id); ++ if (lock) ++ mutex_unlock(lock); ++ if (unlikely(err == -EAGAIN)) ++ goto again; ++ else if (unlikely(err)) ++ return err; ++ ++ *id = *id & MAX_ID_MASK; ++ return 0; ++} ++ ++static void release_idr(struct idr *idr, struct mutex *lock, int id) ++{ ++ if (lock) ++ mutex_lock(lock); ++ idr_remove(idr, id); ++ if (lock) ++ mutex_unlock(lock); ++} ++ ++/* sys I/F for thermal zone */ ++ ++#define to_thermal_zone(_dev) \ ++ container_of(_dev, struct thermal_zone_device, device) ++ ++static ssize_t ++type_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ ++ return sprintf(buf, "%s\n", tz->type); ++} ++ ++static ssize_t ++temp_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ ++ if (!tz->ops->get_temp) ++ return -EPERM; ++ ++ return tz->ops->get_temp(tz, buf); ++} ++ ++static ssize_t ++mode_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ ++ if (!tz->ops->get_mode) ++ return -EPERM; ++ ++ return tz->ops->get_mode(tz, buf); ++} ++ ++static ssize_t ++mode_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ int result; ++ ++ if (!tz->ops->set_mode) ++ return -EPERM; ++ ++ result = tz->ops->set_mode(tz, buf); ++ if (result) ++ return result; ++ ++ return count; ++} ++ ++static ssize_t ++trip_point_type_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ int trip; ++ ++ if (!tz->ops->get_trip_type) ++ return -EPERM; ++ ++ if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) ++ return -EINVAL; ++ ++ return tz->ops->get_trip_type(tz, trip, buf); ++} ++ ++static ssize_t ++trip_point_temp_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ int trip; ++ ++ if (!tz->ops->get_trip_temp) ++ return -EPERM; ++ ++ if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip)) ++ return -EINVAL; ++ ++ return tz->ops->get_trip_temp(tz, trip, buf); ++} ++ ++static DEVICE_ATTR(type, 0444, type_show, NULL); ++static DEVICE_ATTR(temp, 0444, temp_show, NULL); ++static DEVICE_ATTR(mode, 0644, mode_show, mode_store); ++ ++static struct device_attribute trip_point_attrs[] = { ++ __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL), ++ __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL), ++ __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL), ++}; ++ ++#define TRIP_POINT_ATTR_ADD(_dev, _index, result) \ ++do { \ ++ result = device_create_file(_dev, \ ++ &trip_point_attrs[_index * 2]); \ ++ if (result) \ ++ break; \ ++ result = device_create_file(_dev, \ ++ &trip_point_attrs[_index * 2 + 1]); \ ++} while (0) ++ ++#define TRIP_POINT_ATTR_REMOVE(_dev, _index) \ ++do { \ ++ device_remove_file(_dev, &trip_point_attrs[_index * 2]); \ ++ device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ ++} while (0) ++ ++/* sys I/F for cooling device */ ++#define to_cooling_device(_dev) \ ++ container_of(_dev, struct thermal_cooling_device, device) ++ ++static ssize_t ++thermal_cooling_device_type_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct thermal_cooling_device *cdev = to_cooling_device(dev); ++ ++ return sprintf(buf, "%s\n", cdev->type); ++} ++ ++static ssize_t ++thermal_cooling_device_max_state_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct thermal_cooling_device *cdev = to_cooling_device(dev); ++ ++ return cdev->ops->get_max_state(cdev, buf); ++} ++ ++static ssize_t ++thermal_cooling_device_cur_state_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct thermal_cooling_device *cdev = to_cooling_device(dev); ++ ++ return cdev->ops->get_cur_state(cdev, buf); ++} ++ ++static ssize_t ++thermal_cooling_device_cur_state_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct thermal_cooling_device *cdev = to_cooling_device(dev); ++ int state; ++ int result; ++ ++ if (!sscanf(buf, "%d\n", &state)) ++ return -EINVAL; ++ ++ if (state < 0) ++ return -EINVAL; ++ ++ result = cdev->ops->set_cur_state(cdev, state); ++ if (result) ++ return result; ++ return count; ++} ++ ++static struct device_attribute dev_attr_cdev_type = ++ __ATTR(type, 0444, thermal_cooling_device_type_show, NULL); ++static DEVICE_ATTR(max_state, 0444, ++ thermal_cooling_device_max_state_show, NULL); ++static DEVICE_ATTR(cur_state, 0644, ++ thermal_cooling_device_cur_state_show, ++ thermal_cooling_device_cur_state_store); ++ ++static ssize_t ++thermal_cooling_device_trip_point_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct thermal_cooling_device_instance *instance; ++ ++ instance = ++ container_of(attr, struct thermal_cooling_device_instance, attr); ++ ++ if (instance->trip == THERMAL_TRIPS_NONE) ++ return sprintf(buf, "-1\n"); ++ else ++ return sprintf(buf, "%d\n", instance->trip); ++} ++ ++/* Device management */ ++ ++/** ++ * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone ++ * this function is usually called in the thermal zone device .bind callback. ++ * @tz: thermal zone device ++ * @trip: indicates which trip point the cooling devices is ++ * associated with in this thermal zone. ++ * @cdev: thermal cooling device ++ */ ++int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, ++ int trip, ++ struct thermal_cooling_device *cdev) ++{ ++ struct thermal_cooling_device_instance *dev; ++ struct thermal_cooling_device_instance *pos; ++ int result; ++ ++ if (trip >= tz->trips || ++ (trip < 0 && trip != THERMAL_TRIPS_NONE)) ++ return -EINVAL; ++ ++ if (!tz || !cdev) ++ return -EINVAL; ++ ++ dev = ++ kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ dev->tz = tz; ++ dev->cdev = cdev; ++ dev->trip = trip; ++ result = get_idr(&tz->idr, &tz->lock, &dev->id); ++ if (result) ++ goto free_mem; ++ ++ sprintf(dev->name, "cdev%d", dev->id); ++ result = ++ sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name); ++ if (result) ++ goto release_idr; ++ ++ sprintf(dev->attr_name, "cdev%d_trip_point", dev->id); ++ dev->attr.attr.name = dev->attr_name; ++ dev->attr.attr.mode = 0444; ++ dev->attr.show = thermal_cooling_device_trip_point_show; ++ result = device_create_file(&tz->device, &dev->attr); ++ if (result) ++ goto remove_symbol_link; ++ ++ mutex_lock(&tz->lock); ++ list_for_each_entry(pos, &tz->cooling_devices, node) ++ if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) { ++ result = -EEXIST; ++ break; ++ } ++ if (!result) ++ list_add_tail(&dev->node, &tz->cooling_devices); ++ mutex_unlock(&tz->lock); ++ ++ if (!result) ++ return 0; ++ ++ device_remove_file(&tz->device, &dev->attr); ++ remove_symbol_link: ++ sysfs_remove_link(&tz->device.kobj, dev->name); ++ release_idr: ++ release_idr(&tz->idr, &tz->lock, dev->id); ++ free_mem: ++ kfree(dev); ++ return result; ++} ++EXPORT_SYMBOL(thermal_zone_bind_cooling_device); ++ ++/** ++ * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone ++ * this function is usually called in the thermal zone device .unbind callback. ++ * @tz: thermal zone device ++ * @trip: indicates which trip point the cooling devices is ++ * associated with in this thermal zone. ++ * @cdev: thermal cooling device ++ */ ++int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, ++ int trip, ++ struct thermal_cooling_device *cdev) ++{ ++ struct thermal_cooling_device_instance *pos, *next; ++ ++ mutex_lock(&tz->lock); ++ list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) { ++ if (pos->tz == tz && pos->trip == trip ++ && pos->cdev == cdev) { ++ list_del(&pos->node); ++ mutex_unlock(&tz->lock); ++ goto unbind; ++ } ++ } ++ mutex_unlock(&tz->lock); ++ ++ return -ENODEV; ++ ++ unbind: ++ device_remove_file(&tz->device, &pos->attr); ++ sysfs_remove_link(&tz->device.kobj, pos->name); ++ release_idr(&tz->idr, &tz->lock, pos->id); ++ kfree(pos); ++ return 0; ++} ++EXPORT_SYMBOL(thermal_zone_unbind_cooling_device); ++ ++static void thermal_release(struct device *dev) ++{ ++ struct thermal_zone_device *tz; ++ struct thermal_cooling_device *cdev; ++ ++ if (!strncmp(dev->bus_id, "thermal_zone", sizeof "thermal_zone" - 1)) { ++ tz = to_thermal_zone(dev); ++ kfree(tz); ++ } else { ++ cdev = to_cooling_device(dev); ++ kfree(cdev); ++ } ++} ++ ++static struct class thermal_class = { ++ .name = "thermal", ++ .dev_release = thermal_release, ++}; ++ ++/** ++ * thermal_cooling_device_register - register a new thermal cooling device ++ * @type: the thermal cooling device type. ++ * @devdata: device private data. ++ * @ops: standard thermal cooling devices callbacks. ++ */ ++struct thermal_cooling_device *thermal_cooling_device_register(char *type, ++ void *devdata, struct thermal_cooling_device_ops *ops) ++{ ++ struct thermal_cooling_device *cdev; ++ struct thermal_zone_device *pos; ++ int result; ++ ++ if (strlen(type) >= THERMAL_NAME_LENGTH) ++ return NULL; ++ ++ if (!ops || !ops->get_max_state || !ops->get_cur_state || ++ !ops->set_cur_state) ++ return NULL; ++ ++ cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL); ++ if (!cdev) ++ return NULL; ++ ++ result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id); ++ if (result) { ++ kfree(cdev); ++ return NULL; ++ } ++ ++ strcpy(cdev->type, type); ++ cdev->ops = ops; ++ cdev->device.class = &thermal_class; ++ cdev->devdata = devdata; ++ sprintf(cdev->device.bus_id, "cooling_device%d", cdev->id); ++ result = device_register(&cdev->device); ++ if (result) { ++ release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); ++ kfree(cdev); ++ return NULL; ++ } ++ ++ /* sys I/F */ ++ if (type) { ++ result = device_create_file(&cdev->device, ++ &dev_attr_cdev_type); ++ if (result) ++ goto unregister; ++ } ++ ++ result = device_create_file(&cdev->device, &dev_attr_max_state); ++ if (result) ++ goto unregister; ++ ++ result = device_create_file(&cdev->device, &dev_attr_cur_state); ++ if (result) ++ goto unregister; ++ ++ mutex_lock(&thermal_list_lock); ++ list_add(&cdev->node, &thermal_cdev_list); ++ list_for_each_entry(pos, &thermal_tz_list, node) { ++ if (!pos->ops->bind) ++ continue; ++ result = pos->ops->bind(pos, cdev); ++ if (result) ++ break; ++ ++ } ++ mutex_unlock(&thermal_list_lock); ++ ++ if (!result) ++ return cdev; ++ ++ unregister: ++ release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); ++ device_unregister(&cdev->device); ++ return NULL; ++} ++EXPORT_SYMBOL(thermal_cooling_device_register); ++ ++/** ++ * thermal_cooling_device_unregister - removes the registered thermal cooling device ++ * ++ * @cdev: the thermal cooling device to remove. ++ * ++ * thermal_cooling_device_unregister() must be called when the device is no ++ * longer needed. ++ */ ++void thermal_cooling_device_unregister(struct ++ thermal_cooling_device ++ *cdev) ++{ ++ struct thermal_zone_device *tz; ++ struct thermal_cooling_device *pos = NULL; ++ ++ if (!cdev) ++ return; ++ ++ mutex_lock(&thermal_list_lock); ++ list_for_each_entry(pos, &thermal_cdev_list, node) ++ if (pos == cdev) ++ break; ++ if (pos != cdev) { ++ /* thermal cooling device not found */ ++ mutex_unlock(&thermal_list_lock); ++ return; ++ } ++ list_del(&cdev->node); ++ list_for_each_entry(tz, &thermal_tz_list, node) { ++ if (!tz->ops->unbind) ++ continue; ++ tz->ops->unbind(tz, cdev); ++ } ++ mutex_unlock(&thermal_list_lock); ++ if (cdev->type[0]) ++ device_remove_file(&cdev->device, ++ &dev_attr_cdev_type); ++ device_remove_file(&cdev->device, &dev_attr_max_state); ++ device_remove_file(&cdev->device, &dev_attr_cur_state); ++ ++ release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); ++ device_unregister(&cdev->device); ++ return; ++} ++EXPORT_SYMBOL(thermal_cooling_device_unregister); ++ ++/** ++ * thermal_zone_device_register - register a new thermal zone device ++ * @type: the thermal zone device type ++ * @trips: the number of trip points the thermal zone support ++ * @devdata: private device data ++ * @ops: standard thermal zone device callbacks ++ * ++ * thermal_zone_device_unregister() must be called when the device is no ++ * longer needed. ++ */ ++struct thermal_zone_device *thermal_zone_device_register(char *type, ++ int trips, void *devdata, ++ struct thermal_zone_device_ops *ops) ++{ ++ struct thermal_zone_device *tz; ++ struct thermal_cooling_device *pos; ++ int result; ++ int count; ++ ++ if (strlen(type) >= THERMAL_NAME_LENGTH) ++ return NULL; ++ ++ if (trips > THERMAL_MAX_TRIPS || trips < 0) ++ return NULL; ++ ++ if (!ops || !ops->get_temp) ++ return NULL; ++ ++ tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL); ++ if (!tz) ++ return NULL; ++ ++ INIT_LIST_HEAD(&tz->cooling_devices); ++ idr_init(&tz->idr); ++ mutex_init(&tz->lock); ++ result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id); ++ if (result) { ++ kfree(tz); ++ return NULL; ++ } ++ ++ strcpy(tz->type, type); ++ tz->ops = ops; ++ tz->device.class = &thermal_class; ++ tz->devdata = devdata; ++ tz->trips = trips; ++ sprintf(tz->device.bus_id, "thermal_zone%d", tz->id); ++ result = device_register(&tz->device); ++ if (result) { ++ release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); ++ kfree(tz); ++ return NULL; ++ } ++ ++ /* sys I/F */ ++ if (type) { ++ result = device_create_file(&tz->device, &dev_attr_type); ++ if (result) ++ goto unregister; ++ } ++ ++ result = device_create_file(&tz->device, &dev_attr_temp); ++ if (result) ++ goto unregister; ++ ++ if (ops->get_mode) { ++ result = device_create_file(&tz->device, &dev_attr_mode); ++ if (result) ++ goto unregister; ++ } ++ ++ for (count = 0; count < trips; count++) { ++ TRIP_POINT_ATTR_ADD(&tz->device, count, result); ++ if (result) ++ goto unregister; ++ } ++ ++ mutex_lock(&thermal_list_lock); ++ list_add_tail(&tz->node, &thermal_tz_list); ++ if (ops->bind) ++ list_for_each_entry(pos, &thermal_cdev_list, node) { ++ result = ops->bind(tz, pos); ++ if (result) ++ break; ++ } ++ mutex_unlock(&thermal_list_lock); ++ ++ if (!result) ++ return tz; ++ ++ unregister: ++ release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); ++ device_unregister(&tz->device); ++ return NULL; ++} ++EXPORT_SYMBOL(thermal_zone_device_register); ++ ++/** ++ * thermal_device_unregister - removes the registered thermal zone device ++ * ++ * @tz: the thermal zone device to remove ++ */ ++void thermal_zone_device_unregister(struct thermal_zone_device *tz) ++{ ++ struct thermal_cooling_device *cdev; ++ struct thermal_zone_device *pos = NULL; ++ int count; ++ ++ if (!tz) ++ return; ++ ++ mutex_lock(&thermal_list_lock); ++ list_for_each_entry(pos, &thermal_tz_list, node) ++ if (pos == tz) ++ break; ++ if (pos != tz) { ++ /* thermal zone device not found */ ++ mutex_unlock(&thermal_list_lock); ++ return; ++ } ++ list_del(&tz->node); ++ if (tz->ops->unbind) ++ list_for_each_entry(cdev, &thermal_cdev_list, node) ++ tz->ops->unbind(tz, cdev); ++ mutex_unlock(&thermal_list_lock); ++ ++ if (tz->type[0]) ++ device_remove_file(&tz->device, &dev_attr_type); ++ device_remove_file(&tz->device, &dev_attr_temp); ++ if (tz->ops->get_mode) ++ device_remove_file(&tz->device, &dev_attr_mode); ++ ++ for (count = 0; count < tz->trips; count++) ++ TRIP_POINT_ATTR_REMOVE(&tz->device, count); ++ ++ release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); ++ idr_destroy(&tz->idr); ++ mutex_destroy(&tz->lock); ++ device_unregister(&tz->device); ++ return; ++} ++EXPORT_SYMBOL(thermal_zone_device_unregister); ++ ++static int __init thermal_init(void) ++{ ++ int result = 0; ++ ++ result = class_register(&thermal_class); ++ if (result) { ++ idr_destroy(&thermal_tz_idr); ++ idr_destroy(&thermal_cdev_idr); ++ mutex_destroy(&thermal_idr_lock); ++ mutex_destroy(&thermal_list_lock); ++ } ++ return result; ++} ++ ++static void __exit thermal_exit(void) ++{ ++ class_unregister(&thermal_class); ++ idr_destroy(&thermal_tz_idr); ++ idr_destroy(&thermal_cdev_idr); ++ mutex_destroy(&thermal_idr_lock); ++ mutex_destroy(&thermal_list_lock); ++} ++ ++subsys_initcall(thermal_init); ++module_exit(thermal_exit); +diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h +index 7b74b60..2b7eece 100644 +--- a/include/acpi/acpi_bus.h ++++ b/include/acpi/acpi_bus.h +@@ -321,6 +321,8 @@ struct acpi_bus_event { + + extern struct kset acpi_subsys; + extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); ++void acpi_bus_private_data_handler(acpi_handle, u32, void *); ++int acpi_bus_get_private_data(acpi_handle, void **); + /* + * External Functions + */ +diff --git a/include/acpi/processor.h b/include/acpi/processor.h +index 76411b1..0787635 100644 +--- a/include/acpi/processor.h ++++ b/include/acpi/processor.h +@@ -4,7 +4,7 @@ + #include + #include + #include +- ++#include + #include + + #define ACPI_PROCESSOR_BUSY_METRIC 10 +@@ -218,7 +218,7 @@ struct acpi_processor { + struct acpi_processor_performance *performance; + struct acpi_processor_throttling throttling; + struct acpi_processor_limit limit; +- ++ struct thermal_cooling_device *cdev; + /* the _PDC objects for this processor, if any */ + struct acpi_object_list *pdc; + }; +@@ -330,7 +330,7 @@ extern struct cpuidle_driver acpi_idle_driver; + /* in processor_thermal.c */ + int acpi_processor_get_limit_info(struct acpi_processor *pr); + extern struct file_operations acpi_processor_limit_fops; +- ++extern struct thermal_cooling_device_ops processor_cooling_ops; + #ifdef CONFIG_CPU_FREQ + void acpi_thermal_cpufreq_init(void); + void acpi_thermal_cpufreq_exit(void); +diff --git a/include/linux/thermal.h b/include/linux/thermal.h +new file mode 100644 +index 0000000..bba7712 +--- /dev/null ++++ b/include/linux/thermal.h +@@ -0,0 +1,94 @@ ++/* ++ * thermal.h ($Revision: 0 $) ++ * ++ * Copyright (C) 2008 Intel Corp ++ * Copyright (C) 2008 Zhang Rui ++ * Copyright (C) 2008 Sujith Thomas ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * 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; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ */ ++ ++#ifndef __THERMAL_H__ ++#define __THERMAL_H__ ++ ++#include ++#include ++ ++struct thermal_zone_device; ++struct thermal_cooling_device; ++ ++struct thermal_zone_device_ops { ++ int (*bind) (struct thermal_zone_device *, ++ struct thermal_cooling_device *); ++ int (*unbind) (struct thermal_zone_device *, ++ struct thermal_cooling_device *); ++ int (*get_temp) (struct thermal_zone_device *, char *); ++ int (*get_mode) (struct thermal_zone_device *, char *); ++ int (*set_mode) (struct thermal_zone_device *, const char *); ++ int (*get_trip_type) (struct thermal_zone_device *, int, char *); ++ int (*get_trip_temp) (struct thermal_zone_device *, int, char *); ++}; ++ ++struct thermal_cooling_device_ops { ++ int (*get_max_state) (struct thermal_cooling_device *, char *); ++ int (*get_cur_state) (struct thermal_cooling_device *, char *); ++ int (*set_cur_state) (struct thermal_cooling_device *, unsigned int); ++}; ++ ++#define THERMAL_TRIPS_NONE -1 ++#define THERMAL_MAX_TRIPS 10 ++#define THERMAL_NAME_LENGTH 20 ++struct thermal_cooling_device { ++ int id; ++ char type[THERMAL_NAME_LENGTH]; ++ struct device device; ++ void *devdata; ++ struct thermal_cooling_device_ops *ops; ++ struct list_head node; ++}; ++ ++#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \ ++ ((long)t-2732+5)/10 : ((long)t-2732-5)/10) ++#define CELSIUS_TO_KELVIN(t) ((t)*10+2732) ++ ++struct thermal_zone_device { ++ int id; ++ char type[THERMAL_NAME_LENGTH]; ++ struct device device; ++ void *devdata; ++ int trips; ++ struct thermal_zone_device_ops *ops; ++ struct list_head cooling_devices; ++ struct idr idr; ++ struct mutex lock; /* protect cooling devices list */ ++ struct list_head node; ++}; ++ ++struct thermal_zone_device *thermal_zone_device_register(char *, int, void *, ++ struct thermal_zone_device_ops *); ++void thermal_zone_device_unregister(struct thermal_zone_device *); ++ ++int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int, ++ struct thermal_cooling_device *); ++int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int, ++ struct thermal_cooling_device *); ++ ++struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, ++ struct thermal_cooling_device_ops *); ++void thermal_cooling_device_unregister(struct thermal_cooling_device *); ++ ++#endif /* __THERMAL_H__ */ +-- +1.5.6.3 + --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0022-usb_reset_resume_quirk.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0022-usb_reset_resume_quirk.patch @@ -0,0 +1,75 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c +index c51f8e9..1a93989 100644 +--- a/drivers/usb/core/driver.c ++++ b/drivers/usb/core/driver.c +@@ -866,6 +866,9 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg) + return status; + } + ++struct usb_hub; ++void hub_port_logical_disconnect(struct usb_hub *hub, int port1); ++ + /* Caller has locked intf's usb_device's pm_mutex */ + static int usb_resume_interface(struct usb_interface *intf, int reset_resume) + { +@@ -894,9 +897,15 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) + dev_err(&intf->dev, "%s error %d\n", + "reset_resume", status); + } else { +- // status = -EOPNOTSUPP; ++ struct usb_device *udev = interface_to_usbdev(intf); ++ struct usb_device *parent_hdev = udev->parent; ++ /* status = -EOPNOTSUPP; */ + dev_warn(&intf->dev, "no %s for driver %s?\n", + "reset_resume", driver->name); ++ if (parent_hdev) { ++ struct usb_hub *parent_hub = usb_get_intfdata(parent_hdev->actconfig->interface[0]); ++ hub_port_logical_disconnect(parent_hub, udev->portnum); ++ } + } + } else { + if (driver->resume) { +@@ -905,7 +914,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) + dev_err(&intf->dev, "%s error %d\n", + "resume", status); + } else { +- // status = -EOPNOTSUPP; ++ /* status = -EOPNOTSUPP; */ + dev_warn(&intf->dev, "no %s for driver %s?\n", + "resume", driver->name); + } +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index b04d232..ca269bb 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -584,7 +584,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) + * time later khubd will disconnect() any existing usb_device on the port + * and will re-enumerate if there actually is a device attached. + */ +-static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) ++void hub_port_logical_disconnect(struct usb_hub *hub, int port1) + { + dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1); + hub_port_disable(hub, port1, 1); +@@ -601,6 +601,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) + set_bit(port1, hub->change_bits); + kick_khubd(hub); + } ++EXPORT_SYMBOL(hub_port_logical_disconnect); + + /* caller has locked the hub device */ + static int hub_pre_reset(struct usb_interface *intf) +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index d42c561..d5e867d 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -45,6 +45,8 @@ static const struct usb_device_id usb_quirk_list[] = { + /* SKYMEDI USB_DRIVE */ + { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, + ++ /* ASIX Ethernet device */ ++ { USB_DEVICE(0x0b95, 0x1720), .driver_info = USB_QUIRK_RESET_RESUME }, + { } /* terminating entry must be last */ + }; + --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0013-poulsbo_pci_ids.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0013-poulsbo_pci_ids.patch @@ -0,0 +1,26 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h +index 1ee009e..cf03fe8 100644 +--- a/include/linux/pci_ids.h ++++ b/include/linux/pci_ids.h +@@ -2364,6 +2364,20 @@ + #define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0 + #define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2 + #define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601 ++#define PCI_DEVICE_ID_INTEL_POULSBO_HC 0x8100 ++#define PCI_DEVICE_ID_INTEL_POULSBO_PE1 0x8110 ++#define PCI_DEVICE_ID_INTEL_POULSBO_PE2 0x8112 ++#define PCI_DEVICE_ID_INTEL_POULSBO_UC1 0x8114 ++#define PCI_DEVICE_ID_INTEL_POULSBO_UC2 0x8115 ++#define PCI_DEVICE_ID_INTEL_POULSBO_UC3 0x8116 ++#define PCI_DEVICE_ID_INTEL_POULSBO_EC 0x8117 ++#define PCI_DEVICE_ID_INTEL_POULSBO_UT 0x8118 ++#define PCI_DEVICE_ID_INTEL_POULSBO_LPC 0x8119 ++#define PCI_DEVICE_ID_INTEL_POULSBO_IDE 0x811a ++#define PCI_DEVICE_ID_INTEL_POULSBO_HDA 0x811b ++#define PCI_DEVICE_ID_INTEL_POULSBO_SD1 0x811c ++#define PCI_DEVICE_ID_INTEL_POULSBO_SD2 0x811d ++#define PCI_DEVICE_ID_INTEL_POULSBO_SD3 0x811e + #define PCI_DEVICE_ID_INTEL_82454GX 0x84c4 + #define PCI_DEVICE_ID_INTEL_82450GX 0x84c5 + #define PCI_DEVICE_ID_INTEL_82451NX 0x84ca --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0016-poulsbo_ide.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0016-poulsbo_ide.patch @@ -0,0 +1,62 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c +index b406b39..57e4990 100644 +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -214,6 +214,7 @@ static const struct pci_device_id piix_pci_tbl[] = { + /* ICH7/7-R (i945, i975) UDMA 100*/ + { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, ++ { 0x8086, 0x811A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* ICH8 Mobile PATA Controller */ + { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + +@@ -731,6 +732,12 @@ static int ich_pata_cable_detect(struct ata_port *ap) + lap++; + } + ++ /* workaround for Poulsbo PATA controller, this controller's ++ * IOCFG register is "reserved" ++ */ ++ if (pdev->vendor == PCI_VENDOR_ID_INTEL && ++ pdev->device == PCI_DEVICE_ID_INTEL_POULSBO_IDE) ++ return ATA_CBL_PATA80; + /* check BIOS cable detect results */ + mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; + pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); +@@ -752,8 +759,13 @@ static int piix_pata_prereset(struct ata_link *link, unsigned long deadline) + struct ata_port *ap = link->ap; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + +- if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) +- return -ENOENT; ++ /* workaround for Poulsbo PATA controller, this controller's port ++ * enable registers are "reserved" ++ */ ++ if (pdev->vendor != PCI_VENDOR_ID_INTEL || ++ pdev->device != PCI_DEVICE_ID_INTEL_POULSBO_IDE) ++ if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) ++ return -ENOENT; + return ata_std_prereset(link, deadline); + } + +diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c +index 27781d2..6070358 100644 +--- a/drivers/ide/pci/piix.c ++++ b/drivers/ide/pci/piix.c +@@ -438,6 +438,7 @@ static const struct ide_port_info piix_pci_info[] __devinitdata = { + /* 22 */ DECLARE_ICH_DEV("ICH4", ATA_UDMA5), + /* 23 */ DECLARE_ICH_DEV("ESB2", ATA_UDMA5), + /* 24 */ DECLARE_ICH_DEV("ICH8M", ATA_UDMA5), ++ /* 25 */ DECLARE_ICH_DEV("POULSBO", ATA_UDMA5), + }; + + /** +@@ -511,6 +512,7 @@ static const struct pci_device_id piix_pci_tbl[] = { + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1), 22 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 23 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6), 24 }, ++ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_POULSBO_IDE), 25 }, + { 0, }, + }; + MODULE_DEVICE_TABLE(pci, piix_pci_tbl); --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0014-poulsbo_hda.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0014-poulsbo_hda.patch @@ -0,0 +1,196 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c +index 3fa0f97..0b0c0bc 100644 +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -75,6 +75,12 @@ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " + module_param(enable_msi, int, 0); + MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); + ++/* For workaround Poulsbo SI bugs, it affects stream descriptor offset and ++ * corresponding control bits ++ */ ++static int sd_offset_fixup= 0; ++static int sd_bit_fixup=0; ++ + #ifdef CONFIG_SND_HDA_POWER_SAVE + /* power_save option is defined in hda_codec.c */ + +@@ -269,6 +275,10 @@ enum { + #define NVIDIA_HDA_TRANSREG_ADDR 0x4e + #define NVIDIA_HDA_ENABLE_COHBITS 0x0f + ++/* Defines for Intel SCH HDA snoop control */ ++#define INTEL_SCH_HDA_DEVC 0x78 ++#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) ++ + /* + */ + +@@ -788,8 +798,20 @@ static void azx_int_clear(struct azx *chip) + static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) + { + /* enable SIE */ +- azx_writeb(chip, INTCTL, +- azx_readb(chip, INTCTL) | (1 << azx_dev->index)); ++ if (!sd_bit_fixup) { ++ azx_writeb(chip, INTCTL, ++ azx_readb(chip, INTCTL) | (1 << azx_dev->index)); ++ } ++ else { ++ if (azx_dev->index < sd_bit_fixup) { ++ azx_writel(chip, INTCTL, ++ azx_readl(chip, INTCTL) | (1 << azx_dev->index)); ++ } else { ++ azx_writel(chip, INTCTL, ++ azx_readl(chip, INTCTL) | (1 << (azx_dev->index+sd_bit_fixup))); ++ } ++ } ++ + /* set DMA start and interrupt mask */ + azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | + SD_CTL_DMA_START | SD_INT_MASK); +@@ -803,8 +825,18 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) + ~(SD_CTL_DMA_START | SD_INT_MASK)); + azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ + /* disable SIE */ +- azx_writeb(chip, INTCTL, +- azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); ++ if (!sd_bit_fixup) { ++ azx_writeb(chip, INTCTL, ++ azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); ++ } else { ++ if (azx_dev->index < sd_bit_fixup ) { ++ azx_writeb(chip, INTCTL, ++ azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); ++ } else { ++ azx_writeb(chip, INTCTL, ++ azx_readb(chip, INTCTL) & ~(1 << (azx_dev->index+sd_bit_fixup))); ++ } ++ } + } + + +@@ -851,6 +883,7 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg, + + static void azx_init_pci(struct azx *chip) + { ++ unsigned short reg16; + /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) + * TCSEL == Traffic Class Select Register, which sets PCI express QOS + * Ensuring these bits are 0 clears playback static on some HD Audio +@@ -871,6 +904,19 @@ static void azx_init_pci(struct azx *chip) + NVIDIA_HDA_TRANSREG_ADDR, + 0x0f, NVIDIA_HDA_ENABLE_COHBITS); + break; ++ case AZX_DRIVER_ICH: ++ /* For SCH (Poulsbo), enable snoop */ ++ if (chip->pci->device == PCI_DEVICE_ID_INTEL_POULSBO_HDA) { ++ pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, ®16); ++ if (reg16 & INTEL_SCH_HDA_DEVC_NOSNOOP) { ++ pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, \ ++ reg16 & (~INTEL_SCH_HDA_DEVC_NOSNOOP)); ++ pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, ®16); ++ snd_printk(KERN_INFO "HDA snoop disabled, try to enable ... %s\n", \ ++ (reg16 & INTEL_SCH_HDA_DEVC_NOSNOOP)?"Failed":"OK"); ++ } ++ } ++ break; + } + } + +@@ -1467,11 +1513,24 @@ static int __devinit azx_init_stream(struct azx *chip) + struct azx_dev *azx_dev = &chip->azx_dev[i]; + azx_dev->bdl = (u32 *)(chip->bdl.area + off); + azx_dev->bdl_addr = chip->bdl.addr + off; +- azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); + /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ +- azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); +- /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ +- azx_dev->sd_int_sta_mask = 1 << i; ++ if (!sd_bit_fixup) { ++ azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); ++ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); ++ /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ ++ azx_dev->sd_int_sta_mask = 1 << i; ++ } else { ++ if (iposbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); ++ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); ++ azx_dev->sd_int_sta_mask = 1 << i; ++ } else { ++ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80 + sd_offset_fixup); ++ azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + (2+i) * 8); ++ azx_dev->sd_int_sta_mask = 1 << (i+sd_bit_fixup); ++ } ++ } ++ + /* stream tag: must be non-zero and unique */ + azx_dev->index = i; + azx_dev->stream_tag = i + 1; +@@ -1702,9 +1761,11 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, + { + struct azx *chip; + int err; ++ unsigned short stepping; + static struct snd_device_ops ops = { + .dev_free = azx_dev_free, + }; ++ unsigned short gcap; + + *rchip = NULL; + +@@ -1783,10 +1844,41 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, + chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX; + break; + default: +- chip->playback_streams = ICH6_NUM_PLAYBACK; +- chip->capture_streams = ICH6_NUM_CAPTURE; +- chip->playback_index_offset = ICH6_PLAYBACK_INDEX; +- chip->capture_index_offset = ICH6_CAPTURE_INDEX; ++ /* read number of streams from GCAP regiser instead of using ++ * hardcoded value ++ */ ++ gcap = azx_readw(chip, GCAP); ++ if (!gcap) { ++ snd_printk(KERN_ERR "Device has no streams \n"); ++ goto errout; ++ }; ++ chip->playback_streams = (gcap&(0xF<<12))>>12; ++ chip->capture_streams = (gcap&(0xF<<8))>>8; ++ chip->playback_index_offset = (gcap&(0xF<<12))>>12; ++ chip->capture_index_offset = 0; ++ /* do fixup for poulsbo */ ++ if (pci->device == PCI_DEVICE_ID_INTEL_POULSBO_HDA) { ++ snd_printk(KERN_INFO "Do fixup for Poulsbo "); ++ pci_bus_read_config_word(pci->bus, 0, 0x8, &stepping); ++ switch (stepping) { ++ case 0: ++ /* A2 has wrong OSD0 offset and control bits */ ++ snd_printk(KERN_INFO "A2 stepping\n"); ++ sd_offset_fixup = 0x40; ++ sd_bit_fixup = 0x2; ++ break; ++ case 2: ++ case 3: ++ case 4: ++ /* B0/1 and C0 moved OSD0 offset but not control bits */ ++ snd_printk(KERN_INFO "B0/1 or C0 stepping\n"); ++ sd_bit_fixup = 0x2; ++ break; ++ default: ++ snd_printk(KERN_INFO "D0 or newer stepping\n"); ++ break; ++ } ++ } + break; + } + chip->num_streams = chip->playback_streams + chip->capture_streams; +@@ -1936,6 +2028,7 @@ static struct pci_device_id azx_ids[] = { + { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */ + { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ + { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ ++ { 0x8086, 0x811b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* POULSBO */ + { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ + { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ + { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */ --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0017-poulsbo_USBC.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0017-poulsbo_USBC.patch @@ -0,0 +1,3748 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig +index f81d08d..8d71885 100644 +--- a/drivers/usb/gadget/Kconfig ++++ b/drivers/usb/gadget/Kconfig +@@ -324,6 +324,27 @@ config USB_AT91 + depends on USB_GADGET_AT91 + default USB_GADGET + ++config USB_GADGET_IUSBC ++ boolean "Intel USB Client Controller" ++ depends on PCI ++ select USB_GADGET_DUALSPEED ++ help ++ Intel USB client controller is a PCI based USB peripheral controller ++ which supports both full and high speed USB 2.0 data transfers. ++ ++ It has three IN and three OUT configurable endpoints, as well ++ as endpoint zero (for control transfers). ++ ++ Say "y" to link the driver statically, or "m" to build a ++ dynamically linked module called "iusbc" and force all ++ gadget drivers to also be dynamically linked. ++ ++config USB_IUSBC ++ tristate ++ depends on USB_GADGET_IUSBC ++ default USB_GADGET ++ select USB_GADGET_SELECTED ++ + config USB_GADGET_DUMMY_HCD + boolean "Dummy HCD (DEVELOPMENT)" + depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL +diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile +index 904e57b..8e533bf 100644 +--- a/drivers/usb/gadget/Makefile ++++ b/drivers/usb/gadget/Makefile +@@ -17,6 +17,7 @@ obj-$(CONFIG_USB_AT91) += at91_udc.o + obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o + obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o + obj-$(CONFIG_USB_M66592) += m66592-udc.o ++obj-$(CONFIG_USB_IUSBC) += iusbc.o + + # + # USB gadget drivers +diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c +index 9e732bf..15a6dce 100644 +--- a/drivers/usb/gadget/ether.c ++++ b/drivers/usb/gadget/ether.c +@@ -19,7 +19,7 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +-/* #define VERBOSE_DEBUG */ ++#define VERBOSE_DEBUG + + #include + #include +@@ -34,6 +34,10 @@ + + #include "gadget_chips.h" + ++#ifdef CONFIG_USB_GADGET_IUSBC ++#include "iusbc.h" ++#endif ++ + /*-------------------------------------------------------------------------*/ + + /* +@@ -68,7 +72,7 @@ + */ + + #define DRIVER_DESC "Ethernet Gadget" +-#define DRIVER_VERSION "May Day 2005" ++#define DRIVER_VERSION "2.0.0.32L.0010" + + static const char shortname [] = "ether"; + static const char driver_desc [] = DRIVER_DESC; +@@ -239,6 +243,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); + #define DEV_CONFIG_CDC + #endif + ++#ifdef CONFIG_USB_GADGET_IUSBC ++#define DEV_CONFIG_CDC ++#endif ++ + #ifdef CONFIG_USB_GADGET_S3C2410 + #define DEV_CONFIG_CDC + #endif +@@ -1353,11 +1361,31 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); ++ __le16 status = 0; + + /* descriptors just go into the pre-allocated ep0 buffer, + * while config change events may enable network traffic. + */ + req->complete = eth_setup_complete; ++ ++#ifdef CONFIG_USB_GADGET_IUSBC ++ /* software handles get_status in iusbc controller */ ++ if (gadget_is_iusbc(dev->gadget)) { ++ if ((ctrl->bRequest == USB_REQ_GET_STATUS) ++ && (ctrl->bRequestType & USB_DIR_IN) ++ && (ctrl->bRequestType != 0x21)) { ++ struct iusbc *controller = ++ container_of(dev->gadget, ++ struct iusbc, ++ gadget); ++ status = controller->status_d; ++ DEBUG (dev, "status_d: %d\n", status); ++ value = sizeof status; ++ *(u16 *) req->buf = le16_to_cpu(status); ++ } ++ } ++#endif ++ + switch (ctrl->bRequest) { + + case USB_REQ_GET_DESCRIPTOR: +@@ -1421,7 +1449,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) + || !dev->config + || wIndex > 1) + break; +- if (!cdc_active(dev) && wIndex != 0) ++ if (!rndis_active(dev) && !cdc_active(dev) && wIndex != 0) + break; + spin_lock (&dev->lock); + +@@ -1556,9 +1584,9 @@ done_set_intf: + u32 n; + + /* return the result */ +- buf = rndis_get_next_response(dev->rndis_config, &n); ++ buf = rndis_get_next_response (dev->rndis_config, &value); + if (buf) { +- memcpy(req->buf, buf, n); ++ memcpy (req->buf, buf, value); + req->complete = rndis_response_complete; + rndis_free_response(dev->rndis_config, buf); + } +@@ -2639,6 +2667,7 @@ static struct usb_gadget_driver eth_driver = { + + MODULE_DESCRIPTION (DRIVER_DESC); + MODULE_AUTHOR ("David Brownell, Benedikt Spanger"); ++MODULE_VERSION(DRIVER_VERSION); + MODULE_LICENSE ("GPL"); + + +diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c +index 1d174dc..4a48112 100644 +--- a/drivers/usb/gadget/file_storage.c ++++ b/drivers/usb/gadget/file_storage.c +@@ -244,18 +244,23 @@ + + #include "gadget_chips.h" + ++#ifdef CONFIG_USB_GADGET_IUSBC ++#include "iusbc.h" ++#include /* for uevent usage */ ++#endif + + /*-------------------------------------------------------------------------*/ + + #define DRIVER_DESC "File-backed Storage Gadget" + #define DRIVER_NAME "g_file_storage" +-#define DRIVER_VERSION "7 August 2007" ++#define DRIVER_VERSION "2.0.0.32L.0010" + + static const char longname[] = DRIVER_DESC; + static const char shortname[] = DRIVER_NAME; + + MODULE_DESCRIPTION(DRIVER_DESC); + MODULE_AUTHOR("Alan Stern"); ++MODULE_VERSION(DRIVER_VERSION); + MODULE_LICENSE("Dual BSD/GPL"); + + /* Thanks to NetChip Technologies for donating this product ID. +@@ -545,6 +550,7 @@ struct lun { + unsigned int prevent_medium_removal : 1; + unsigned int registered : 1; + unsigned int info_valid : 1; ++ unsigned int switch_flag : 1; + + u32 sense_data; + u32 sense_data_info; +@@ -684,6 +690,7 @@ struct fsg_dev { + unsigned int nluns; + struct lun *luns; + struct lun *curlun; ++ int uevent_flag; + }; + + typedef void (*fsg_routine_t)(struct fsg_dev *); +@@ -1335,11 +1342,27 @@ static int standard_setup_req(struct fsg_dev *fsg, + int value = -EOPNOTSUPP; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); ++ __le16 status = 0; + + /* Usually this just stores reply data in the pre-allocated ep0 buffer, + * but config change events will also reconfigure hardware. */ + switch (ctrl->bRequest) { + ++#ifdef CONFIG_USB_GADGET_IUSBC ++ case USB_REQ_GET_STATUS: ++ /* software handles get_status in iusbc controller */ ++ if (gadget_is_iusbc(fsg->gadget)) { ++ struct iusbc *controller = ++ container_of(fsg->gadget, ++ struct iusbc, ++ gadget); ++ status = controller->status_d; ++ DBG(fsg, "status_d: %d\n", status); ++ value = sizeof status; ++ *(u16 *) req->buf = le16_to_cpu(status); ++ } ++ break; ++#endif + case USB_REQ_GET_DESCRIPTOR: + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | + USB_RECIP_DEVICE)) +@@ -1392,6 +1415,13 @@ get_config: + if (w_value == CONFIG_VALUE || w_value == 0) { + fsg->new_config = w_value; + ++#ifdef CONFIG_USB_GADGET_IUSBC ++ /* for resume from S3 in iusbc controller */ ++ if (gadget_is_iusbc(fsg->gadget)) { ++ fsg->state = FSG_STATE_IDLE; ++ fsg->config = 0; ++ } ++#endif + /* Raise an exception to wipe out previous transaction + * state (queued bufs, etc) and set the new config. */ + raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); +@@ -2853,6 +2883,9 @@ static int do_scsi_command(struct fsg_dev *fsg) + break; + + case SC_TEST_UNIT_READY: ++ i = fsg->cmnd[2]; ++ if (i == 0x55) ++ fsg->curlun->switch_flag = 1; + fsg->data_size_from_cmnd = 0; + reply = check_command(fsg, 6, DATA_DIR_NONE, + 0, 1, +@@ -3357,6 +3390,13 @@ static void handle_exception(struct fsg_dev *fsg) + + case FSG_STATE_CONFIG_CHANGE: + rc = do_set_config(fsg, new_config); ++#ifdef CONFIG_USB_GADGET_IUSBC ++ if (!fsg->uevent_flag){ ++ struct iusbc *_iusbc=container_of(fsg->gadget,struct iusbc,gadget); ++ kobject_uevent(&(_iusbc->pdev->dev.kobj), KOBJ_ONLINE); ++ fsg->uevent_flag=1; ++ } ++#endif + if (fsg->ep0_req_tag != exception_req_tag) + break; + if (rc != 0) // STALL on errors +@@ -3368,6 +3408,13 @@ static void handle_exception(struct fsg_dev *fsg) + case FSG_STATE_DISCONNECT: + fsync_all(fsg); + do_set_config(fsg, 0); // Unconfigured state ++#ifdef CONFIG_USB_GADGET_IUSBC ++ if (fsg->uevent_flag) { ++ struct iusbc *_iusbc=container_of(fsg->gadget,struct iusbc,gadget); ++ kobject_uevent(&(_iusbc->pdev->dev.kobj), KOBJ_OFFLINE); ++ fsg->uevent_flag=0; ++ } ++#endif + break; + + case FSG_STATE_EXIT: +@@ -3585,6 +3632,12 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, + return rc; + } + ++static ssize_t show_switch(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct lun *curlun = dev_to_lun(dev); ++ ++ return sprintf(buf, "%d\n", curlun->switch_flag); ++} + + static ssize_t store_ro(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +@@ -3649,6 +3702,7 @@ static ssize_t store_file(struct device *dev, struct device_attribute *attr, + /* The write permissions and store_xxx pointers are set in fsg_bind() */ + static DEVICE_ATTR(ro, 0444, show_ro, NULL); + static DEVICE_ATTR(file, 0444, show_file, NULL); ++static DEVICE_ATTR(switch, 0444, show_switch, NULL); + + + /*-------------------------------------------------------------------------*/ +@@ -3684,6 +3738,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) + if (curlun->registered) { + device_remove_file(&curlun->dev, &dev_attr_ro); + device_remove_file(&curlun->dev, &dev_attr_file); ++ device_remove_file(&curlun->dev, &dev_attr_switch); + device_unregister(&curlun->dev); + curlun->registered = 0; + } +@@ -3842,6 +3897,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) + + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; ++ curlun->switch_flag = 0; + curlun->ro = mod_data.ro[i]; + curlun->dev.release = lun_release; + curlun->dev.parent = &gadget->dev; +@@ -3857,7 +3913,9 @@ static int __init fsg_bind(struct usb_gadget *gadget) + if ((rc = device_create_file(&curlun->dev, + &dev_attr_ro)) != 0 || + (rc = device_create_file(&curlun->dev, +- &dev_attr_file)) != 0) { ++ &dev_attr_file)) != 0 || ++ (rc = device_create_file(&curlun->dev, ++ &dev_attr_switch)) != 0) { + device_unregister(&curlun->dev); + goto out; + } +diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h +index f7f159c..41b5c9a 100644 +--- a/drivers/usb/gadget/gadget_chips.h ++++ b/drivers/usb/gadget/gadget_chips.h +@@ -147,6 +147,11 @@ + #define gadget_is_m66592(g) 0 + #endif + ++#ifdef CONFIG_USB_GADGET_IUSBC ++#define gadget_is_iusbc(g) !strcmp("iusbc", (g)->name) ++#else ++#define gadget_is_iusbc(g) 0 ++#endif + + // CONFIG_USB_GADGET_SX2 + // CONFIG_USB_GADGET_AU1X00 +@@ -212,5 +217,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) + return 0x20; + else if (gadget_is_m66592(gadget)) + return 0x21; ++ else if (gadget_is_iusbc(gadget)) ++ return 0x99; + return -ENOENT; + } +diff --git a/drivers/usb/gadget/iusbc.c b/drivers/usb/gadget/iusbc.c +new file mode 100644 +index 0000000..345c64b +--- /dev/null ++++ b/drivers/usb/gadget/iusbc.c +@@ -0,0 +1,3120 @@ ++/* ++ * Intel Poulsbo USB Client Controller Driver ++ * Copyright (C) 2006-07, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++ ++ ++#define DEBUG /* messages on error and most fault paths */ ++//#define VERBOSE /* extra debug messages (success too) */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Power management */ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "iusbc.h" ++ ++#define DRIVER_DESC "Intel Poulsbo USB Client Controller Driver" ++#define DRIVER_VERSION "2.0.0.32L.0010" ++ ++#define DMA_ADDR_INVALID (~(dma_addr_t)0) ++ ++static const char driver_name [] = "iusbc"; ++static const char driver_desc [] = DRIVER_DESC; ++ ++static const char *const ep_name [] = { ++ "ep0-in", "ep0-out", ++ "ep1in-bulk", "ep1out-bulk", ++ "ep2in-int", "ep2out-int", ++ "ep3in-iso", "ep3out-iso", ++}; ++ ++ ++/* module parameter */ ++ ++/* force_fullspeed -- device will be forced to full speed operation ++ * default value: 0 for high speed ++ */ ++static int force_fullspeed = 0; ++ ++/* modprobe iusbc force_fullspeed=n" etc */ ++/* XXX: remove this feature due to HW full-speed bug ++ * module_param (force_fullspeed, bool, S_IRUGO); ++ */ ++ ++//#define RNDIS_INIT_HW_BUG ++//#define DMA_DISABLED ++ ++/*-------------------------------------------------------------------------*/ ++/* DEBUGGING */ ++#define xprintk(dev,level,fmt,args...) \ ++ printk(level "%s %s: " fmt , driver_name , \ ++ pci_name(dev->pdev) , ## args) ++ ++#ifdef DEBUG ++#undef DEBUG ++#define DEBUG(dev,fmt,args...) \ ++ xprintk(dev , KERN_DEBUG , fmt , ## args) ++#else ++#define DEBUG(dev,fmt,args...) \ ++ do { } while (0) ++#endif /* DEBUG */ ++ ++ ++#ifdef VERBOSE ++#define VDEBUG DEBUG ++#else ++#define VDEBUG(dev,fmt,args...) \ ++ do { } while (0) ++#endif /* VERBOSE */ ++ ++ ++#define ERROR(dev,fmt,args...) \ ++ xprintk(dev , KERN_ERR , fmt , ## args) ++#define WARN(dev,fmt,args...) \ ++ xprintk(dev , KERN_WARNING , fmt , ## args) ++#define INFO(dev,fmt,args...) \ ++ xprintk(dev , KERN_INFO , fmt , ## args) ++ ++ ++#ifdef VERBOSE ++static inline void print_all_registers(struct iusbc_regs *regs) ++{ ++ unsigned i, j; ++ /* device */ ++ printk(KERN_DEBUG "----Intel USB-C Memory Space Registers----\n"); ++ printk(KERN_DEBUG "Register Length: 0x%x\n", ++ sizeof(struct iusbc_regs)); ++ printk(KERN_DEBUG "gcap=0x%08x\n", readl(®s->gcap)); ++ printk(KERN_DEBUG "dev_sts=0x%08x\n", readl(®s->dev_sts)); ++ printk(KERN_DEBUG "frame=0x%04x\n", readw(®s->frame)); ++ printk(KERN_DEBUG "int_sts=0x%08x\n", readl(®s->int_sts)); ++ printk(KERN_DEBUG "int_ctrl=0x%08x\n", readl(®s->int_ctrl)); ++ printk(KERN_DEBUG "dev_ctrl=0x%08x\n", readl(®s->dev_ctrl)); ++ ++ /* endpoints */ ++ for (i = 0; i < 5; i++) { ++ printk(KERN_DEBUG "ep[%d]_base_low_32=0x%08x\n", ++ i, readl(®s->ep[i].ep_base_low_32)); ++ printk(KERN_DEBUG "ep[%d]_base_hi_32=0x%08x\n", ++ i, readl(®s->ep[i].ep_base_hi_32)); ++ printk(KERN_DEBUG "ep[%d]_len=0x%04x\n", ++ i, readw(®s->ep[i].ep_len)); ++ printk(KERN_DEBUG "ep[%d]_pib=0x%04x\n", ++ i, readw(®s->ep[i].ep_pib)); ++ printk(KERN_DEBUG "ep[%d]_dil=0x%04x\n", ++ i, readw(®s->ep[i].ep_dil)); ++ printk(KERN_DEBUG "ep[%d]_tiq=0x%04x\n", ++ i, readw(®s->ep[i].ep_tiq)); ++ printk(KERN_DEBUG "ep[%d]_max=0x%04x\n", ++ i, readw(®s->ep[i].ep_max)); ++ printk(KERN_DEBUG "ep[%d]_sts=0x%04x\n", ++ i, readw(®s->ep[i].ep_sts)); ++ printk(KERN_DEBUG "ep[%d]_cfg=0x%04x\n", ++ i, readw(®s->ep[i].ep_cfg)); ++ ++ if (1 == i) { /* ep0-out */ ++ printk(KERN_DEBUG "ep-out setup_pkt_sts=0x%02x\n", ++ readb(®s->ep[i].setup_pkt_sts)); ++ for (j = 0; j< 8; j++) { ++ printk(KERN_DEBUG "ep0-out " ++ "setup_pkt[%d]=0x%02x\n", ++ j, readb(®s->ep[i].setup_pkt[j])); ++ } ++ } ++ } ++} ++ ++#endif /* VERBOSE */ ++ ++/*-------------------------------------------------------------------------*/ ++ ++#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out") ++ ++ ++#if defined(CONFIG_USB_GADGET_DEBUG_FILES) || defined (DEBUG) ++static char *type_string(u8 bmAttributes) ++{ ++ switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { ++ case USB_ENDPOINT_XFER_BULK: ++ return "bulk"; ++ case USB_ENDPOINT_XFER_ISOC: ++ return "iso"; ++ case USB_ENDPOINT_XFER_INT: ++ return "int"; ++ }; ++ ++ return "control"; ++} ++#endif ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* configure endpoint, making it usable */ ++static int ++iusbc_ep_enable(struct usb_ep *_ep, ++ const struct usb_endpoint_descriptor *desc) ++{ ++ struct iusbc *dev; ++ struct iusbc_ep *ep; ++ u16 val_16, max; ++ u8 val_8; ++ unsigned long flags; ++ unsigned i; ++ int retval; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ DEBUG(ep->dev, "---> iusbc_ep_enable() \n"); ++ ++ if (!_ep || !desc || _ep->name == "ep0-in" ++ || _ep->name == "ep0-out" ++ || desc->bDescriptorType != USB_DT_ENDPOINT) ++ return -EINVAL; ++ ++ dev = ep->dev; ++ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) ++ return -ESHUTDOWN; ++ ++ /* wMaxPacketSize up to 1024 bytes */ ++ max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff; ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ ep->ep.maxpacket = max; ++ if (!ep->desc) ++ ep->desc = desc; ++ ++ /* ep_reset() has already been called */ ++ ep->stopped = 0; ++ ep->is_in = (USB_DIR_IN & desc->bEndpointAddress) != 0; ++ ++ /* sanity check type, direction, address */ ++ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { ++ case USB_ENDPOINT_XFER_BULK: ++ if ((dev->gadget.speed == USB_SPEED_HIGH ++ && max != 512) ++ || (dev->gadget.speed == USB_SPEED_FULL ++ && max > 64)) { ++ goto done; ++ } ++ break; ++ case USB_ENDPOINT_XFER_INT: ++ if (strstr (ep->ep.name, "-iso")) /* bulk is ok */ ++ goto done; ++ ++ switch (dev->gadget.speed) { ++ case USB_SPEED_HIGH: ++ if (max <= 1024) ++ break; ++ case USB_SPEED_FULL: ++ if (max <= 64) ++ break; ++ default: ++ if (max <= 8) ++ break; ++ goto done; ++ } ++ break; ++ case USB_ENDPOINT_XFER_ISOC: ++ if (strstr (ep->ep.name, "-bulk") ++ || strstr (ep->ep.name, "-int")) ++ goto done; ++ ++ switch (dev->gadget.speed) { ++ case USB_SPEED_HIGH: ++ if (max <= 1024) ++ break; ++ case USB_SPEED_FULL: ++ if (max <= 1023) ++ break; ++ default: ++ goto done; ++ } ++ break; ++ default: ++ goto done; ++ } ++ ++ /* ep_type */ ++ ep->ep_type = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); ++ ++ /* DMA modes, only support Linear Mode now */ ++ if (ep->dev->sg_mode_dma) { ++ ep->dma_mode = SCATTER_GATHER_MODE; ++ } else { ++ ep->dma_mode = LINEAR_MODE; ++ } ++ ++ /* reset ep registers to default value */ ++ i = ep->num; ++ writew(0, &dev->regs->ep[i].ep_cfg); ++ ++ /* set endpoints valid */ ++ val_16 = readw(&dev->regs->ep[i].ep_cfg); ++ val_16 |= INTR_BAD_PID_TYPE ++ | INTR_CRC_ERROR ++ | INTR_FIFO_ERROR ++ | INTR_DMA_ERROR ++ | INTR_TRANS_COMPLETE ++ /* | INTR_PING_NAK_SENT */ ++ | INTR_DMA_IOC ++ | ep->dma_mode << 6 ++ | ep->ep_type << 4 ++ /* | EP_ENABLE */ ++ | EP_VALID; ++ ++ /* will set EP_ENABLE later to start dma */ ++ writew(val_16, &dev->regs->ep[i].ep_cfg); ++ ++ val_16 = readw(&dev->regs->ep[i].ep_cfg); ++ VDEBUG(dev, "%s.ep_cfg = 0x%04x\n", _ep->name, val_16); ++ ++ val_8 = desc->bEndpointAddress; ++ DEBUG(dev, "enabled %s (ep%d%s-%s), max %04x, dma_mode: %02x\n", ++ _ep->name, ++ val_8 & USB_ENDPOINT_NUMBER_MASK, ++ DIR_STRING(val_8), ++ type_string(desc->bmAttributes), ++ max, ++ ep->dma_mode); ++ ++ retval = 0; ++done: ++ spin_unlock_irqrestore(&dev->lock, flags); ++ DEBUG(ep->dev, "<--- iusbc_ep_enable() \n"); ++ return retval; ++} ++ ++ ++static const struct usb_ep_ops iusbc_ep_ops; ++ ++static void ep_reset(struct iusbc_regs __iomem *regs, struct iusbc_ep *ep) ++{ ++ unsigned i = ep->num; ++ ++ /* reset ep values */ ++ ep->stopped = 1; ++ ep->ep.maxpacket = ~0; ++ ep->ep.ops = &iusbc_ep_ops; ++ ++ /* reset ep registers to default value ++ * clear all interrupt and status ++ * clear and reset all DMA FIFOs and state machine ++ * hardware shall minimize power usage ++ */ ++ writew(0, ®s->ep[i].ep_cfg); ++} ++ ++ ++static void nuke(struct iusbc_ep *); ++ ++/* endpoint is no longer usable */ ++static int ++iusbc_ep_disable(struct usb_ep *_ep) ++{ ++ struct iusbc_ep *ep; ++ unsigned long flags; ++ struct iusbc *dev; ++ unsigned i; ++ u16 val_16; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ VDEBUG(ep->dev, "---> iusbc_ep_disable() \n"); ++ ++ if (!_ep || !ep->desc ++ || _ep->name == "ep0-in" ++ || _ep->name == "ep0-out") ++ return -EINVAL; ++ ++ dev = ep->dev; ++ if (dev->ep0state == EP0_SUSPEND) ++ return -EBUSY; ++ ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ nuke(ep); ++ ep_reset(ep->dev->regs, ep); ++ ++ i = ep->num; ++ ++ /* display endpoint configuration register */ ++ val_16 = readw(&dev->regs->ep[i].ep_cfg); ++ VDEBUG(dev, "%s.ep_cfg = 0x%04x\n", _ep->name, val_16); ++ ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ ++ DEBUG(ep->dev, "disabled %s\n", _ep->name); ++ ++ VDEBUG(ep->dev, "<--- iusbc_ep_disable() \n"); ++ ++ return 0; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* allocate a request object to use with this endpoint */ ++static struct usb_request * ++iusbc_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) ++{ ++ struct iusbc_ep *ep; ++ struct iusbc_request *req; ++ struct iusbc_dma *td; ++ ++ if (!_ep) ++ return NULL; ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ VDEBUG(ep->dev, "---> iusbc_alloc_request() \n"); ++ ++ req = kzalloc(sizeof(*req), gfp_flags); ++ if (!req) ++ return NULL; ++ ++ req->req.dma = DMA_ADDR_INVALID; ++ INIT_LIST_HEAD(&req->queue); ++ ++ /* this dma descriptor may be swapped with the previous dummy */ ++ td = pci_pool_alloc(ep->dev->requests, ++ gfp_flags, ++ &req->td_dma); ++ ++ if (!td) { ++ kfree(req); ++ return NULL; ++ } ++ ++ td->dmacount = 0; /* not VALID */ ++ td->dmaaddr = __constant_cpu_to_le32(DMA_ADDR_INVALID); ++ ++ req->td = td; ++ ++ VDEBUG(ep->dev, "alloc request for %s\n", _ep->name); ++ ++ VDEBUG(ep->dev, "<--- iusbc_alloc_request() \n"); ++ ++ return &req->req; ++} ++ ++ ++/* frees a request object */ ++static void ++iusbc_free_request(struct usb_ep *_ep, struct usb_request *_req) ++{ ++ struct iusbc_ep *ep; ++ struct iusbc_request *req; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ VDEBUG(ep->dev, "---> iusbc_free_request() \n"); ++ ++ if (!_ep || !_req) ++ return; ++ ++ req = container_of(_req, struct iusbc_request, req); ++ ++ WARN_ON(!list_empty(&req->queue)); ++ ++ if (req->td) ++ pci_pool_free(ep->dev->requests, req->td, req->td_dma); ++ ++ kfree(req); ++ ++ VDEBUG(ep->dev, "free request for %s\n", _ep->name); ++ ++ VDEBUG(ep->dev, "<--- iusbc_free_request() \n"); ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* allocate an I/O buffer ++ * ++ * dma-coherent memory allocation ++ * ++ * NOTE: the dma_*_coherent() API calls suck. Most implementations are ++ * (a) page-oriented, so small buffers lose big; and (b) asymmetric with ++ * respect to calls with irqs disabled: alloc is safe, free is not. ++ * We currently work around (b), but not (a). ++ */ ++static void * ++iusbc_alloc_buffer( ++ struct usb_ep *_ep, ++ unsigned bytes, ++ dma_addr_t *dma, ++ gfp_t gfp_flags ++) ++{ ++ void *retval; ++ struct iusbc_ep *ep; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ VDEBUG(ep->dev, "---> iusbc_alloc_buffer() \n"); ++ ++ if (!_ep) ++ return NULL; ++ ++ *dma = DMA_ADDR_INVALID; ++ ++ retval = dma_alloc_coherent(&ep->dev->pdev->dev, ++ bytes, dma, gfp_flags); ++ ++ DEBUG(ep->dev, "alloc buffer for %s\n", _ep->name); ++ ++ VDEBUG(ep->dev, "<--- iusbc_alloc_buffer() \n"); ++ ++ return retval; ++} ++ ++ ++static DEFINE_SPINLOCK(buflock); ++static LIST_HEAD(buffers); ++ ++struct free_record { ++ struct list_head list; ++ struct device *dev; ++ unsigned bytes; ++ dma_addr_t dma; ++}; ++ ++ ++static void do_free(unsigned long ignored) ++{ ++#ifdef VERBOSE ++ printk(KERN_DEBUG "---> do_free() \n"); ++#endif ++ ++ spin_lock_irq(&buflock); ++ while (!list_empty(&buffers)) { ++ struct free_record *buf; ++ ++ buf = list_entry(buffers.next, struct free_record, list); ++ list_del(&buf->list); ++ spin_unlock_irq(&buflock); ++ ++ dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma); ++ ++ spin_lock_irq(&buflock); ++ } ++ spin_unlock_irq(&buflock); ++ ++#ifdef VERBOSE ++ printk(KERN_DEBUG "<--- do_free() \n"); ++#endif ++} ++ ++static DECLARE_TASKLET(deferred_free, do_free, 0); ++ ++/* free an I/O buffer */ ++static void ++iusbc_free_buffer( ++ struct usb_ep *_ep, ++ void *address, ++ dma_addr_t dma, ++ unsigned bytes ++) { ++ ++ /* free memory into the right allocator */ ++ if (dma != DMA_ADDR_INVALID) { ++ struct iusbc_ep *ep; ++ struct free_record *buf = address; ++ unsigned long flags; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ VDEBUG(ep->dev, "---> iusbc_free_buffer() \n"); ++ ++ if (!_ep) ++ return; ++ ++ buf->dev = &ep->dev->pdev->dev; ++ buf->bytes = bytes; ++ buf->dma = dma; ++ ++ spin_lock_irqsave(&buflock, flags); ++ list_add_tail(&buf->list, &buffers); ++ tasklet_schedule(&deferred_free); ++ spin_unlock_irqrestore(&buflock, flags); ++ ++ DEBUG(ep->dev, "free buffer for %s\n", _ep->name); ++ VDEBUG(ep->dev, "<--- iusbc_free_buffer() \n"); ++ ++ } else ++ kfree(address); ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* fill out dma descriptor to match a given request */ ++static void ++fill_dma(struct iusbc_ep *ep, struct iusbc_request *req) ++{ ++ struct iusbc_dma *td = req->td; ++ u16 dmacount; ++ ++ VDEBUG(ep->dev, "---> fill_dma() \n"); ++ ++ dmacount = req->req.length; ++ ++ td->dmaaddr = cpu_to_le32(req->req.dma); ++ td->dmacount = cpu_to_le16(dmacount); ++ ++ VDEBUG(ep->dev, "<--- fill_dma() \n"); ++} ++ ++ ++static void start_dma(struct iusbc_ep *ep, struct iusbc_request *req) ++{ ++ u16 val_16; ++ u32 val_32; ++ unsigned i; ++ ++ VDEBUG(ep->dev, "---> start_dma() \n"); ++ ++ i = ep->num; ++ ++ /* init req->td, pointing to the current dummy */ ++ fill_dma(ep, req); ++ ++ /* ep_base_low_32 */ ++ writel(cpu_to_le32(req->req.dma), ++ &ep->dev->regs->ep[i].ep_base_low_32); ++ val_32 = readl(&ep->dev->regs->ep[i].ep_base_low_32); ++ VDEBUG(ep->dev, "%s.ep_base_low_32=0x%08x\n", ++ ep->ep.name, val_32); ++ ++ /* ep_base_hi_32 */ ++ writel(0, &ep->dev->regs->ep[i].ep_base_hi_32); ++ val_32 = readl(&ep->dev->regs->ep[i].ep_base_hi_32); ++ VDEBUG(ep->dev, "%s.ep_base_hi_32=0x%08x\n", ++ ep->ep.name, val_32); ++ ++ writew(le16_to_cpu(req->td->dmacount), &ep->dev->regs->ep[i].ep_len); ++ val_16 = readw(&ep->dev->regs->ep[i].ep_len); ++ VDEBUG(ep->dev, "%s.ep_len=0x%04x\n", ++ ep->ep.name, val_16); ++ ++ /* endpoint maximum transaction size, up to 1024 Bytes */ ++ writew((ep->ep.maxpacket & 0x3ff), ++ &ep->dev->regs->ep[i].ep_max); ++ val_16 = readw(&ep->dev->regs->ep[i].ep_max); ++ VDEBUG(ep->dev, "%s.ep_max=0x%04x\n", ++ ep->ep.name, val_16); ++ ++ /* validate endpoint, enable DMA */ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ val_16 |= EP_VALID | EP_ENABLE; ++ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); ++ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ VDEBUG(ep->dev, "enable %s DMA transfer...\n", ++ ep->ep.name); ++ VDEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ++ ep->ep.name, val_16); ++ ++ VDEBUG(ep->dev, "<--- start_dma() \n"); ++} ++ ++ ++/* queues I/O requests in endpoint queue */ ++static inline void ++queue_dma(struct iusbc_ep *ep, struct iusbc_request *req) ++{ ++ struct iusbc_dma *end; ++ dma_addr_t tmp_dma_addr; ++ ++ VDEBUG(ep->dev, "---> queue_dma() \n"); ++ ++ /* swap new dummy for old, link; fill and maybe activate */ ++ end = ep->dummy; ++ ep->dummy = req->td; ++ req->td = end; ++ ++ tmp_dma_addr = ep->td_dma; ++ ep->td_dma = req->td_dma; ++ req->td_dma = tmp_dma_addr; ++ ++ fill_dma(ep, req); ++ ++ VDEBUG(ep->dev, "<--- queue_dma() \n"); ++} ++ ++ ++static void ++done(struct iusbc_ep *ep, struct iusbc_request *req, int status) ++{ ++ struct iusbc *dev; ++ unsigned stopped = ep->stopped; ++ ++ VDEBUG(ep->dev, "---> done() \n"); ++ ++ list_del_init(&req->queue); ++ ++ if (req->req.status == -EINPROGRESS) ++ req->req.status = status; ++ else ++ status = req->req.status; ++ ++ dev = ep->dev; ++ ++ if (req->mapped) { ++ pci_unmap_single(dev->pdev, req->req.dma, req->req.length, ++ ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); ++ req->req.dma = DMA_ADDR_INVALID; ++ req->mapped = 0; ++ } ++ ++ if (status != -ESHUTDOWN) ++ DEBUG(dev, "complete %s, req %p, stat %d, len %u/%u\n", ++ ep->ep.name, &req->req, status, ++ req->req.actual, req->req.length); ++ ++ /* don't modify queue heads during completion callback */ ++ ep->stopped = 1; ++ ++ /* XXX WORKAROUND: first ep0-out OUT packet HW BUG */ ++#ifdef RNDIS_INIT_HW_BUG ++ if (ep->num == 1) { ++ char *buf; ++ const u8 remote_ndis_initialize_msg[24] = { ++ 0x02, 0x00, 0x00, 0x00, ++ 0x18, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x00, 0x00 ++ }; ++ ++ buf = req->req.buf; ++ ++ /* req->buf haven't been DMAed for hardware bug? */ ++ if ((buf[0] == 0x09) && (buf[1] == 0x02)) { ++ memcpy(buf, remote_ndis_initialize_msg, 24); ++ DEBUG(ep->dev, "WORKAROUND HW BUG: ep0-out OUT\n"); ++ } ++ } ++#endif ++ /* XXX */ ++ ++ spin_unlock(&dev->lock); ++ req->req.complete(&ep->ep, &req->req); ++ spin_lock(&dev->lock); ++ ep->stopped = stopped; ++ ++ VDEBUG(ep->dev, "<--- done() \n"); ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* queues (submits) an I/O requests to an endpoint */ ++static int ++iusbc_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) ++{ ++ struct iusbc_request *req; ++ struct iusbc_ep *ep; ++ struct iusbc *dev; ++ unsigned long flags; ++ u16 val_16; ++ unsigned zlflag = 0; ++ ++ /* always require a cpu-view buffer */ ++ req = container_of(_req, struct iusbc_request, req); ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ dev = ep->dev; ++ VDEBUG(ep->dev, "---> iusbc_queue() \n"); ++ ++ if (dev->ep0state == EP0_DISCONNECT || ep->stopped) ++ return -EINVAL; ++ ++ if (!_req || !_req->complete || !_req->buf ++ || !list_empty(&req->queue)){ ++ VDEBUG(ep->dev, "_req=%p, complete=%p, buf=%p, list_empty=%d\n", ++ _req, _req->complete, ++ _req->buf, ++ list_empty(&req->queue)); ++ return -EINVAL; ++ } ++ ++ if (!_ep || (!ep->desc && ep->num > 1)){ ++ VDEBUG(ep->dev, "ep->desc=%p, ep->num=%d\n", ++ ep->desc, ep->num); ++ return -ESHUTDOWN; ++ } ++ ++ if (dev->ep0state == EP0_DISCONNECT) ++ return -ESHUTDOWN; ++ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) ++ return -ESHUTDOWN; ++ ++ /* can't touch registers when suspended */ ++ if (dev->ep0state == EP0_SUSPEND) ++ return -EBUSY; ++ ++ /* set up dma mapping in case the caller didn't */ ++ if (_req->dma == DMA_ADDR_INVALID) { ++ /* WORKAROUND: WARN_ON(size == 0) */ ++ if (_req->length == 0) { ++ VDEBUG(dev, "req->length: 0->1\n"); ++ zlflag = 1; ++ _req->length++; ++ } ++ ++ _req->dma = pci_map_single(dev->pdev, _req->buf, _req->length, ++ ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); ++ ++ if (zlflag && (_req->length == 1)) { ++ VDEBUG(dev, "req->length: 1->0\n"); ++ zlflag = 0; ++ _req->length = 0; ++ } ++ ++ req->mapped = 1; ++ } ++ ++ DEBUG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08x\n", ++ _ep->name, _req, _req->length, ++ _req->buf, _req->dma); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ ++ _req->status = -EINPROGRESS; ++ _req->actual = 0; ++ ++ /* set ZLP flag for ep0-in, when writting data, ++ * makes the last packet be "short" by adding a zero ++ * length packet as needed ++ */ ++ if (unlikely(ep->num == 0 && ep->is_in)) ++ _req->zero = 1; ++ ++ /* kickstart this I/O queue */ ++ if (list_empty(&ep->queue) && !ep->stopped) { ++ start_dma(ep, req); ++ ++ val_16 = readw(&ep->dev->regs->ep[ep->num].ep_pib); ++ VDEBUG(ep->dev, "after dma, %s.ep_pib = 0x%04x\n", ++ _ep->name, val_16); ++ ++ val_16 = readw(&ep->dev->regs->ep[ep->num].ep_sts); ++ VDEBUG(ep->dev, "after dma, %s.ep_sts = 0x%04x\n", ++ _ep->name, val_16); ++ } else { ++ queue_dma(ep, req); ++ VDEBUG(ep->dev, "%s queue_dma()\n", _ep->name); ++ } ++ ++ if (likely(req != 0)) { ++ list_add_tail(&req->queue, &ep->queue); ++ VDEBUG(ep->dev, "list_add_tail() \n"); ++ } ++ ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ VDEBUG(ep->dev, "<--- iusbc_queue() \n"); ++ ++ return 0; ++} ++ ++ ++static inline void ++dma_done(struct iusbc_ep *ep, struct iusbc_request *req, int status) ++{ ++ unsigned i; ++ VDEBUG(ep->dev, "---> dma_done() \n"); ++ ++ i = ep->num; ++ req->req.actual = readw(&ep->dev->regs->ep[i].ep_pib); ++ VDEBUG(ep->dev, "req->req.actual = %d\n", req->req.actual); ++ ++ done(ep, req, status); ++ ++ VDEBUG(ep->dev, "<--- dma_done() \n"); ++} ++ ++ ++/* restart dma in endpoint */ ++static void restart_dma(struct iusbc_ep *ep) ++{ ++ struct iusbc_request *req; ++ ++ VDEBUG(ep->dev, "---> restart_dma() \n"); ++ ++ if (ep->stopped) ++ return; ++ ++ req = list_entry(ep->queue.next, struct iusbc_request, queue); ++ start_dma(ep, req); ++ ++ VDEBUG(ep->dev, "<--- restart_dma() \n"); ++ ++ return; ++} ++ ++ ++/* dequeue ALL requests */ ++static void nuke(struct iusbc_ep *ep) ++{ ++ struct iusbc_request *req; ++ ++ VDEBUG(ep->dev, "---> nuke() \n"); ++ ++ /* called with spinlock held */ ++ ep->stopped = 1; ++ while (!list_empty(&ep->queue)) { ++ req = list_entry(ep->queue.next, ++ struct iusbc_request, ++ queue); ++ done(ep, req, -ESHUTDOWN); ++ } ++ ++ VDEBUG(ep->dev, "<--- nuke() \n"); ++} ++ ++ ++/* dequeues (cancels, unlinks) an I/O request from an endpoint */ ++static int ++iusbc_dequeue(struct usb_ep *_ep, struct usb_request *_req) ++{ ++ struct iusbc_ep *ep; ++ struct iusbc *dev; ++ struct iusbc_request *req; ++ unsigned long flags; ++ int stopped; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ VDEBUG(ep->dev, "---> iusbc_dequeue() \n"); ++ ++ if (!_ep || (!ep->desc && ep->num > 1) || !_req) ++ return -EINVAL; ++ ++ dev = ep->dev; ++ ++ if (!dev->driver) ++ return -ESHUTDOWN; ++ ++ /* can't touch registers when suspended */ ++ if (dev->ep0state == EP0_SUSPEND) ++ return -EBUSY; ++ ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ stopped = ep->stopped; ++ ++ /* quiesce dma while we patch the queue */ ++ ep->stopped = 1; ++ ++ /* make sure it's still queued on this endpoint */ ++ list_for_each_entry(req, &ep->queue, queue) { ++ if (&req->req == _req) ++ break; ++ } ++ ++ if (&req->req != _req) { ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ return -EINVAL; ++ } ++ ++ /* queue head may be partially complete. */ ++ if (ep->queue.next == &req->queue) { ++ DEBUG(ep->dev, "unlink (%s) dma\n", _ep->name); ++ _req->status = -ECONNRESET; ++ if (likely(ep->queue.next == &req->queue)) { ++ req->td->dmacount = 0; /* invalidate */ ++ dma_done(ep, req, -ECONNRESET); ++ } ++ req = NULL; ++ } ++ ++ if (req) ++ done(ep, req, -ECONNRESET); ++ ++ ep->stopped = stopped; ++ ++ if (!list_empty(&ep->queue) && (!ep->stopped)) { ++ /* resume current request, or start new one */ ++ if (!req) ++ start_dma(ep, list_entry(ep->queue.next, ++ struct iusbc_request, queue)); ++ } ++ ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ ++ VDEBUG(ep->dev, "<--- iusbc_dequeue() \n"); ++ ++ return 0; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void ep0_start(struct iusbc *dev); ++static void ep_ack(struct iusbc_ep *ep); ++static int iusbc_ep_enable(struct usb_ep *_ep, ++ const struct usb_endpoint_descriptor *desc); ++ ++static void clear_halt(struct iusbc_ep *ep) ++{ ++ u16 val_16; ++ unsigned i = ep->num; ++ int rc = 0; ++ struct iusbc_request *req; ++ const struct usb_endpoint_descriptor *desc; ++ ++ DEBUG(ep->dev, "---> clear_halt() \n"); ++ ++ /* validate and enable endpoint */ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ val_16 |= EP_VALID | EP_ENABLE; ++ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); ++ ++ /* re-enable endpoint */ ++ if (i < 2) { /* ep0-in and ep0-out */ ++ ep0_start(ep->dev); ++ } else { ++ spin_unlock_irq(&ep->dev->lock); ++ /* remember ep->desc */ ++ desc = ep->desc; ++ rc = iusbc_ep_enable(&ep->ep, desc); ++ if (rc) { ++ DEBUG(ep->dev, "re-enable error: %d\n", rc); ++ } ++ spin_lock_irq(&ep->dev->lock); ++ } ++ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ DEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); ++ ++ ep->stopped = 0; ++ if (list_empty(&ep->queue)) ++ return; ++ ++ req = list_entry(ep->queue.next, struct iusbc_request,queue); ++ start_dma(ep, req); ++ ++ DEBUG(ep->dev, "<--- clear_halt() \n"); ++} ++ ++ ++static void set_halt(struct iusbc_ep *ep) ++{ ++ u16 val_16; ++ unsigned i = ep->num; ++ ++ DEBUG(ep->dev, "---> set_halt() \n"); ++ ++ /* reset data buffer zero length */ ++ writew(0, &ep->dev->regs->ep[i].ep_len); ++ ++ /* invalidate and disable endpoint */ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ val_16 &= (~EP_VALID & ~EP_ENABLE); ++ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); ++ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ DEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); ++ ++ ep->stopped = 1; ++ ++ DEBUG(ep->dev, "<--- set_halt() \n"); ++} ++ ++ ++static int iusbc_fifo_status(struct usb_ep *_ep); ++ ++/* sets the endpoint halt feature */ ++static int ++iusbc_set_halt(struct usb_ep *_ep, int value) ++{ ++ struct iusbc_ep *ep; ++ unsigned long flags; ++ int retval = 0; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ DEBUG(ep->dev, "---> iusbc_set_halt() \n"); ++ ++ if (!_ep || (!ep->desc && ep->num > 1)) ++ return -EINVAL; ++ ++ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) ++ return -ESHUTDOWN; ++ ++ if (ep->desc && (ep->desc->bmAttributes & 0x03) ++ == USB_ENDPOINT_XFER_ISOC) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ ++ /* transfer requests are still queued */ ++ if (!list_empty(&ep->queue)) ++ retval = -EAGAIN; ++ ++ else if (ep->is_in && value && iusbc_fifo_status(_ep) != 0) { ++ /* FIFO holds bytes, the host hasn't collected */ ++ DEBUG(ep->dev, "%s FIFO holds bytes\n", _ep->name); ++ ++ /* reset position in buffer register */ ++ writew(0, &ep->dev->regs->ep[ep->num].ep_pib); ++ ++ retval = -EAGAIN; ++ } else { ++ DEBUG(ep->dev, "%s %s halt\n", _ep->name, ++ value ? "set" : "clear"); ++ /* set/clear, then synch memory views with the device */ ++ if (value) { ++ if (ep->num < 2) { /* ep0-in/out */ ++ ep->dev->ep0state = EP0_STALL; ++ VDEBUG(ep->dev, "ep0state: EP0_STALL\n"); ++ } else { ++ set_halt(ep); ++ ep_ack(&ep->dev->ep[0]); ++ } ++ } else { ++ clear_halt(ep); ++ ep_ack(&ep->dev->ep[0]); ++ } ++ ++ } ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ ++ DEBUG(ep->dev, "<--- iusbc_set_halt() \n"); ++ ++ return retval; ++} ++ ++ ++/* return number of bytes in fifo, or error */ ++static int ++iusbc_fifo_status(struct usb_ep *_ep) ++{ ++ struct iusbc_ep *ep; ++ unsigned i; ++ u16 nbytes, fifo_size; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ DEBUG(ep->dev, "---> iusbc_fifo_status() \n"); ++ ++ if (!_ep || (!ep->desc && ep->num > 1)) ++ return -ENODEV; ++ ++ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) ++ return -ESHUTDOWN; ++ ++ i = ep->num; ++ fifo_size = readw(&ep->dev->regs->ep[i].ep_len); ++ nbytes = readw(&ep->dev->regs->ep[i].ep_pib); ++ ++ if (nbytes > fifo_size) ++ return -EOVERFLOW; ++ ++ DEBUG(ep->dev, "%s, 0x%04x bytes (%s) in FIFO\n", ++ _ep->name, nbytes, ep->is_in? "IN" : "OUT"); ++ ++ DEBUG(ep->dev, "<--- iusbc_fifo_status() \n"); ++ ++ return nbytes; ++} ++ ++ ++static void ep_nak(struct iusbc_ep *ep); ++ ++/* flushes contents of a fifo */ ++static void ++iusbc_fifo_flush(struct usb_ep *_ep) ++{ ++ struct iusbc_ep *ep; ++ unsigned i; ++ u16 val_16; ++ ++ ep = container_of(_ep, struct iusbc_ep, ep); ++ ++ DEBUG(ep->dev, "---> iusbc_fifo_flush() \n"); ++ ++ if (!_ep || (!ep->desc && ep->num > 1)){ ++ return; ++ } ++ ++ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) ++ return; ++ ++ i = ep->num; ++ ++ /* FIXME: remove it ? */ ++ ep_nak(ep); ++ ++ /* reset position in buffer register */ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_pib); ++ DEBUG(ep->dev, "%s.ep_pib = 0x%04x\n", _ep->name, val_16); ++ writew(0, &ep->dev->regs->ep[i].ep_pib); ++ ++ DEBUG(ep->dev, "<--- iusbc_fifo_flush() \n"); ++} ++ ++static const struct usb_ep_ops iusbc_ep_ops = { ++ ++ /* configure endpoint, making it usable */ ++ .enable = iusbc_ep_enable, ++ ++ /* endpoint is no longer usable */ ++ .disable = iusbc_ep_disable, ++ ++ /* allocate a request object to use with this endpoint */ ++ .alloc_request = iusbc_alloc_request, ++ ++ /* frees a request object */ ++ .free_request = iusbc_free_request, ++ ++ /* allocate an I/O buffer */ ++ /*.alloc_buffer = iusbc_alloc_buffer,*/ ++ ++ /* free an I/O buffer */ ++ /*.free_buffer = iusbc_free_buffer,*/ ++ ++ /* queues (submits) an I/O requests to an endpoint */ ++ .queue = iusbc_queue, ++ ++ /* dequeues (cancels, unlinks) an I/O request from an endpoint */ ++ .dequeue = iusbc_dequeue, ++ ++ /* sets the endpoint halt feature */ ++ .set_halt = iusbc_set_halt, ++ ++ /* return number of bytes in fifo, or error */ ++ .fifo_status = iusbc_fifo_status, ++ ++ /* flushes contents of a fifo */ ++ .fifo_flush = iusbc_fifo_flush, ++}; ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* returns the current frame number */ ++static int iusbc_get_frame(struct usb_gadget *_gadget) ++{ ++ struct iusbc *dev; ++ unsigned long flags; ++ u16 retval; ++ ++ if (!_gadget) ++ return -ENODEV; ++ ++ dev = container_of(_gadget, struct iusbc, gadget); ++ ++ VDEBUG(dev, "---> iusbc_get_frame() \n"); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ retval = readw(&dev->regs->frame); ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ VDEBUG(dev, "<--- iusbc_get_frame() \n"); ++ ++ return retval; ++} ++ ++ ++/* TODO: wakeup host function */ ++/* tries to wake up the host connected to this gadget */ ++static int iusbc_wakeup(struct usb_gadget *_gadget) ++{ ++ struct iusbc *dev; ++ ++ if (!_gadget) ++ return 0; ++ ++ dev = container_of(_gadget, struct iusbc, gadget); ++ ++ VDEBUG(dev, "---> iusbc_wakeup() \n"); ++ ++ /* TODO: spec 4.3 */ ++ ++ VDEBUG(dev, "<--- iusbc_wakeup() \n"); ++ ++ return 0; ++} ++ ++ ++/* software-controlled connect/disconnect to USB host */ ++static int iusbc_pullup(struct usb_gadget *_gadget, int is_on) ++{ ++ struct iusbc *dev; ++ u32 val_32; ++ unsigned long flags; ++ ++ if (!_gadget) ++ return -ENODEV; ++ dev = container_of(_gadget, struct iusbc, gadget); ++ ++ VDEBUG(dev, "---> iusbc_pullup() \n"); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ val_32 = readl(&dev->regs->dev_ctrl); ++ dev->connected = (is_on != 0); ++ if (is_on) ++ val_32 |= CONNECTION_ENABLE; ++ else ++ val_32 &= ~CONNECTION_ENABLE; ++ ++ writel(val_32, &dev->regs->dev_ctrl); ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ VDEBUG(dev, "<--- iusbc_pullup() \n"); ++ ++ return 0; ++} ++ ++ ++static const struct usb_gadget_ops iusbc_ops = { ++ ++ /* returns the current frame number */ ++ .get_frame = iusbc_get_frame, ++ ++ /* TODO */ ++ /* tries to wake up the host connected to this gadget */ ++ .wakeup = iusbc_wakeup, ++ ++ /* software-controlled connect/disconnect to USB host */ ++ .pullup = iusbc_pullup, ++}; ++ ++/*-------------------------------------------------------------------------*/ ++ ++#ifdef CONFIG_USB_GADGET_DEBUG_FILES ++ ++/* "function" sysfs attribute */ ++static ssize_t ++show_function(struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ struct iusbc *dev = dev_get_drvdata(_dev); ++ ++ if (!dev->driver ++ || !dev->driver->function ++ || strlen(dev->driver->function) > PAGE_SIZE) ++ return 0; ++ ++ return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function); ++} ++static DEVICE_ATTR(function, S_IRUGO, show_function, NULL); ++ ++ ++static ssize_t ++show_registers(struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ struct iusbc *dev; ++ char *next; ++ unsigned size; ++ unsigned t; ++ unsigned i; ++ unsigned long flags; ++ const char *name; ++ const char *speed; ++ volatile u32 dev_sts; ++ ++ dev = dev_get_drvdata(_dev); ++ next = buf; ++ size = PAGE_SIZE; ++ spin_lock_irqsave(&dev->lock, flags); ++ ++ if (dev->driver) ++ name = dev->driver->driver.name; ++ else ++ name = "(none)"; ++ ++ dev_sts = readl(&dev->regs->dev_sts); ++ if ((dev->gadget.speed == USB_SPEED_HIGH) && (dev_sts & CONNECTED)) ++ speed = "high speed"; ++ else if ((dev->gadget.speed == USB_SPEED_FULL) && (dev_sts & CONNECTED)) ++ speed = "full speed"; ++ else ++ speed = "unknown speed"; ++ ++ /* device information */ ++ t = scnprintf(next, size, ++ "%s %s - %s\n" ++ "Version: %s\n" ++ "Gadget driver: %s\n" ++ "Speed mode: %s\n", ++ driver_name, pci_name(dev->pdev), driver_desc, ++ DRIVER_VERSION, ++ name, ++ speed); ++ size -= t; ++ next += t; ++ ++ /* device memory space registers */ ++ t = scnprintf(next, size, ++ "\nDevice registers:\n" ++ "\tgcap=0x%08x\n" ++ "\tdev_sts=0x%08x\n" ++ "\tframe=0x%04x\n" ++ "\tint_sts=0x%08x\n" ++ "\tint_ctrl=0x%08x\n" ++ "\tdev_ctrl=0x%08x\n", ++ readl(&dev->regs->gcap), ++ readl(&dev->regs->dev_sts), ++ readw(&dev->regs->frame), ++ readl(&dev->regs->int_sts), ++ readl(&dev->regs->int_ctrl), ++ readl(&dev->regs->dev_ctrl) ++ ); ++ size -= t; ++ next += t; ++ ++ /* endpoints memory space registers */ ++ t = scnprintf(next, size, "\nEndpoints registers:\n"); ++ size -= t; ++ next += t; ++ ++ for (i = 0; i < 5; i++) { ++ struct iusbc_ep *ep; ++ ep = &dev->ep[i]; ++ ++ if (i > 1 && !ep->desc) ++ continue; ++ ++ name = ep->ep.name; ++ t = scnprintf(next, size, ++ "\t%s.ep_base_low_32=0x%08x\n" ++ "\t%s.ep_base_hi_32=0x%08x\n" ++ "\t%s.ep_len=0x%04x\n" ++ "\t%s.ep_pib=0x%04x\n" ++ "\t%s.ep_dil=0x%04x\n" ++ "\t%s.ep_tiq=0x%04x\n" ++ "\t%s.ep_max=0x%04x\n" ++ "\t%s.ep_sts=0x%04x\n" ++ "\t%s.ep_cfg=0x%04x\n", ++ name, readl(&dev->regs->ep[i].ep_base_low_32), ++ name, readl(&dev->regs->ep[i].ep_base_hi_32), ++ name, readw(&dev->regs->ep[i].ep_len), ++ name, readw(&dev->regs->ep[i].ep_pib), ++ name, readw(&dev->regs->ep[i].ep_dil), ++ name, readw(&dev->regs->ep[i].ep_tiq), ++ name, readw(&dev->regs->ep[i].ep_max), ++ name, readw(&dev->regs->ep[i].ep_sts), ++ name, readw(&dev->regs->ep[i].ep_cfg) ++ ); ++ size -= t; ++ next += t; ++ } ++ ++ /* ep0-out setup packet registers */ ++ t = scnprintf(next, size, ++ "\tsetup_pkt_sts=0x%02x\n", ++ readb(&dev->regs->ep[1].setup_pkt_sts) ++ ); ++ size -= t; ++ next += t; ++ ++ for (i = 0; i < 8; i++) { ++ t = scnprintf(next, size, ++ "\tsetup_pkt[%d]=0x%02x\n", ++ i, ++ readb(&dev->regs->ep[1].setup_pkt[i]) ++ ); ++ size -= t; ++ next += t; ++ } ++ ++ /* Irq statistics */ ++ t = scnprintf(next, size, "\nIrq statistics:\n"); ++ size -= t; ++ next += t; ++ ++ for (i = 0; i < 5; i++) { ++ struct iusbc_ep *ep; ++ ep = &dev->ep[i]; ++ ++ if (i && !ep->irqs) ++ continue; ++ ++ t = scnprintf(next, size, ++ "\t%s/%lu\n", ++ ep->ep.name, ep->irqs); ++ size -= t; ++ next += t; ++ } ++ ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ return PAGE_SIZE - size; ++} ++static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); ++ ++ ++static ssize_t ++show_queues(struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ struct iusbc *dev; ++ char *next; ++ unsigned size, i; ++ unsigned long flags; ++ ++ dev = dev_get_drvdata(_dev); ++ next = buf; ++ size = PAGE_SIZE; ++ spin_lock_irqsave(&dev->lock, flags); ++ ++ for (i = 0; i < 5; i++) { ++ struct iusbc_ep *ep = &dev->ep[i]; ++ struct iusbc_request *req; ++ struct iusbc_dma *td; ++ int t; ++ int addr; ++ ++ if (i > 1 && !ep->desc) ++ continue; ++ ++ /* ep0-in, ep0-out */ ++ if (i == 0 || i == 1) { ++ t = scnprintf(next, size, ++ "%s (ep%d%s-%s), " ++ "max %04x, dma_mode: %02x\n", ++ ep->ep.name, ++ 0, ++ ep->is_in ? "in" : "out", ++ "control", ++ ep->ep.maxpacket, ++ ep->dma_mode); ++ } else { ++ addr = ep->desc->bEndpointAddress; ++ t = scnprintf(next, size, ++ "\n%s (ep%d%s-%s), " ++ "max %04x, dma_mode: %02x\n", ++ ep->ep.name, ++ addr & USB_ENDPOINT_NUMBER_MASK, ++ DIR_STRING(addr), ++ type_string(ep->desc->bmAttributes), ++ ep->ep.maxpacket, ++ ep->dma_mode); ++ } ++ ++ if (t <= 0 || t > size) ++ goto done; ++ ++ size -= t; ++ next += t; ++ ++ if (list_empty(&ep->queue)) { ++ t = scnprintf(next, size, "\t(nothing queued)\n"); ++ if (t <= 0 || t > size) ++ goto done; ++ ++ size -= t; ++ next += t; ++ continue; ++ } ++ ++ list_for_each_entry(req, &ep->queue, queue) { ++ t = scnprintf(next, size, ++ "\treq %p, len %u/%u, " ++ "buf %p, dma 0x%08x)\n", ++ &req->req, req->req.actual, ++ req->req.length, req->req.buf, ++ req->req.dma); ++ ++ if (t <= 0 || t > size) ++ goto done; ++ ++ size -= t; ++ next += t; ++ ++ td = req->td; ++ t = scnprintf(next, size, "\ttd 0x%08x, " ++ " count 0x%08x, buf 0x%08x\n", ++ (u32) req->td_dma, ++ le32_to_cpu(td->dmacount), ++ le32_to_cpu(td->dmaaddr)); ++ ++ if (t <= 0 || t > size) ++ goto done; ++ ++ size -= t; ++ next += t; ++ } ++ } ++ ++done: ++ spin_unlock_irqrestore(&dev->lock, flags); ++ return PAGE_SIZE - size; ++} ++static DEVICE_ATTR(queues, S_IRUGO, show_queues, NULL); ++ ++#else ++ ++#define device_create_file(a,b) (0) ++#define device_remove_file(a,b) do { } while (0) ++ ++#endif /*CONFIG_USB_GADGET_DEBUG_FILES */ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* global variable */ ++static struct iusbc *the_controller; ++ ++static void iusbc_reset(struct iusbc *dev) ++{ ++ DEBUG(dev, "---> iusbc_reset() \n"); ++ ++ /* disable irqs */ ++ writel(0, &dev->regs->int_ctrl); ++ ++ /* set device power stauts */ ++ dev->powered = 1; ++ ++ /* set device remote wakeup flag */ ++ dev->enable_wakeup = 0; ++ ++ /* 16 bits status data for GET_STATUS */ ++ dev->status_d = 0; ++ ++ DEBUG(dev, "<--- iusbc_reset() \n"); ++} ++ ++ ++static void iusbc_reinit(struct iusbc *dev) ++{ ++ unsigned i; ++ ++ DEBUG(dev, "---> iusbc_reinit() \n"); ++ ++ INIT_LIST_HEAD(&dev->gadget.ep_list); ++ ++ /* ep0-in */ ++ dev->gadget.ep0 = &dev->ep[0].ep; ++ ++ /* init ep0-in and ep0-out driver_data */ ++ dev->ep[0].ep.driver_data = get_gadget_data(&dev->gadget); ++ dev->ep[1].ep.driver_data = get_gadget_data(&dev->gadget); ++ ++ dev->ep0state = EP0_DISCONNECT; ++ VDEBUG(dev, "ep0state: EP0_DISCONNECT\n"); ++ ++ /* basic endpoint init */ ++ /* 2 ep0, 3 data ep */ ++ for (i = 0; i < 5; i++) { ++ struct iusbc_ep *ep = &dev->ep[i]; ++ ep->dev = dev; ++ ++ INIT_LIST_HEAD(&ep->queue); ++ ++ ep->desc = NULL; ++ ep->num = i; ++ ep->stopped = 1; ++ ep->ep.name = ep_name[i]; ++ ep->ep.maxpacket = ~0; ++ ep->ep.ops = &iusbc_ep_ops; ++ ++ list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); ++ ep_reset(dev->regs, ep); ++ } ++ ++ /* set ep0 maxpacket */ ++ dev->ep[0].ep.maxpacket = 64; /* ep0_in */ ++ dev->ep[1].ep.maxpacket = 64; /* ep0_out */ ++ ++ dev->ep[0].stopped = 0; ++ dev->ep[1].stopped = 0; ++ ++ list_del_init(&dev->ep[0].ep.ep_list); ++ list_del_init(&dev->ep[1].ep.ep_list); ++ ++ DEBUG(dev, "<--- iusbc_reinit() \n"); ++} ++ ++ ++static void ep0_start(struct iusbc *dev) ++{ ++ u16 val_16; ++ u32 val_32; ++ unsigned i; ++ ++ DEBUG(dev, "---> ep0_start() \n"); ++ ++ iusbc_reset(dev); ++ iusbc_reinit(dev); ++ ++ for (i = 0; i < 2; i++) { ++ struct iusbc_ep *ep = &dev->ep[i]; ++ ++ /* ep[0]: ep0-in, ep[1]: ep0-out */ ++ ep->is_in = (i == 0 ? 1 : 0); ++ ++ /* ep0 ep_type */ ++ ep->ep_type = USB_ENDPOINT_XFER_CONTROL; ++ ++ /* linear mode only, control mode is useless */ ++ ep->dma_mode = LINEAR_MODE; ++ ++ /* reset ep0-in/out registers to default value */ ++ writew(0, &dev->regs->ep[i].ep_cfg); ++ ++ /* set ep0-in/out endpoints valid */ ++ val_16 = readw(&dev->regs->ep[i].ep_cfg); ++ val_16 |= INTR_BAD_PID_TYPE ++ | INTR_CRC_ERROR ++ | INTR_FIFO_ERROR ++ | INTR_DMA_ERROR ++ | INTR_TRANS_COMPLETE ++ /* | INTR_PING_NAK_SENT */ ++ | INTR_DMA_IOC ++ | ep->dma_mode << 6 ++ | ep->ep_type << 4 ++ /* | EP_ENABLE */ ++ | EP_VALID; ++ ++ writew(val_16, &dev->regs->ep[i].ep_cfg); ++ ++ val_16 = readw(&dev->regs->ep[i].ep_cfg); ++ DEBUG(dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); ++ ++ DEBUG(dev, "enabled %s (ep0-%s), max %d, dma_mode: %02x\n", ++ ep->ep.name, ++ ep->is_in ? "in" : "out", ++ ep->ep.maxpacket, ep->dma_mode); ++ } ++ ++ /* enable irqs */ ++ val_32 = readl(&dev->regs->int_ctrl); ++ val_32 |= RESET_INTR_ENABLE ++ | CONNECT_INTR_ENABLE ++ | SUSPEND_INTR_ENABLE ++ /* | EP3_OUT_INTR_ENABLE */ ++ /* | EP3_IN_INTR_ENABLE */ ++ /* | EP2_OUT_INTR_ENABLE */ ++ | EP2_IN_INTR_ENABLE ++ | EP1_OUT_INTR_ENABLE ++ | EP1_IN_INTR_ENABLE ++ | EP0_OUT_INTR_ENABLE ++ | EP0_IN_INTR_ENABLE; ++ ++ writel(val_32, &dev->regs->int_ctrl); ++ val_32 = readl(&dev->regs->int_ctrl); ++ DEBUG(dev, "ep0_start: enable irqs, int_ctrl = 0x%08x\n", ++ val_32); ++ ++ dev->ep0state = EP0_IDLE; ++ VDEBUG(dev, "ep0state: EP0_IDLE\n"); ++ ++ DEBUG(dev, "<--- ep0_start() \n"); ++} ++ ++ ++static void iusbc_do_tasklet(unsigned long arg); ++ ++static void device_start(struct iusbc *dev) ++{ ++ u32 val_32; ++ ++ DEBUG(dev, "---> device_start() \n"); ++ ++ /* reset all registers */ ++ writel(0, &dev->regs->dev_ctrl); ++ ++ /* PCI enable: write 1 to DeviceEnable */ ++ writel(DEVICE_ENABLE, &dev->regs->dev_ctrl); ++ /* FIXME: 5 ms is not enough? */ ++ mdelay(5); ++ val_32 = readl(&dev->regs->dev_ctrl); ++ if (!(val_32 & DEVICE_ENABLE)) ++ ERROR(dev, "hardware reset error\n"); ++ ++ /* hardware transfer to running state now */ ++ val_32 |= DEVICE_ENABLE ++ /* | CONNECTION_ENABLE */ ++ | SIGNAL_RESUME ++ | CHARGE_ENABLE; ++ ++ /* module parameter: force_fullspeed */ ++ if (force_fullspeed) { ++ val_32 |= FORCE_FULLSPEED; ++ dev->force_fullspeed = 1; ++ } else { ++ /* disable DMAs in high speed mode */ ++#ifdef DMA_DISABLED ++ val_32 |= DMA1_DISABLED ++ | DMA2_DISABLED ++ | DMA3_DISABLED; ++#endif ++ dev->force_fullspeed = 0; ++ } ++ ++ writel(val_32, &dev->regs->dev_ctrl); ++ val_32 = readl(&dev->regs->dev_ctrl); ++ DEBUG(dev, "dev_ctrl = 0x%08x\n", val_32); ++ ++ /* check device status */ ++ val_32 = readl(&dev->regs->dev_sts); ++ DEBUG(dev, "device_start: dev_sts = 0x%08x\n", val_32); ++ ++ if (val_32 & CONNECTED) { ++ dev->connected = 1; ++ VDEBUG(dev, "device_start: USB attached\n"); ++ } else { ++ dev->connected = 0; ++ VDEBUG(dev, "device_start: USB detached\n"); ++ } ++ ++ if (val_32 & SUSPEND) ++ dev->suspended = 1; ++ else ++ dev->suspended = 0; ++ ++ /* set device reset flag */ ++ dev->is_reset = 0; ++ ++ iusbc_pullup(&dev->gadget, 1); ++ ++ /* init irq tasklet */ ++ tasklet_init(&dev->iusbc_tasklet, ++ iusbc_do_tasklet, (unsigned long) dev); ++ ++ /* enable ep0 and host detection */ ++ ep0_start(dev); ++ ++ DEBUG(dev, "<--- device_start() \n"); ++} ++ ++ ++/* when a driver is successfully registered, it will receive ++ * control requests including set_configuration(), which enables ++ * non-control requests. then usb traffic follows until a ++ * disconnect is reported. then a host may connect again, or ++ * the driver might get unbound. ++ */ ++int usb_gadget_register_driver(struct usb_gadget_driver *driver) ++{ ++ struct iusbc *dev = the_controller; ++ int retval; ++ unsigned i; ++ ++ if (!driver || !driver->bind || !driver->disconnect || !driver->setup) ++ return -EINVAL; ++ ++ if (!dev) ++ return -ENODEV; ++ ++ DEBUG(dev, "---> usb_gadget_register_driver() \n"); ++ ++ if (dev->driver) ++ return -EBUSY; ++ ++ dev->irqs = 0; ++ ++ /* 2 ep0, 3 data eps */ ++ for (i = 0; i < 5; i++) ++ dev->ep[i].irqs = 0; ++ ++ /* hook up the driver ... */ ++ driver->driver.bus = NULL; ++ dev->driver = driver; ++ dev->gadget.dev.driver = &driver->driver; ++ ++ retval = driver->bind(&dev->gadget); ++ if (retval) { ++ DEBUG(dev, "bind to driver %s --> %d\n", ++ driver->driver.name, retval); ++ dev->driver = NULL; ++ dev->gadget.dev.driver = NULL; ++ return retval; ++ } ++ ++ retval = device_create_file(&dev->pdev->dev, &dev_attr_function); ++ if (retval) ++ goto err_unbind; ++ ++ retval = device_create_file(&dev->pdev->dev, &dev_attr_queues); ++ if (retval) ++ goto err_func; ++ ++ device_start(dev); ++ ++ INFO(dev, "register driver: %s\n", driver->driver.name); ++ DEBUG(dev, "<--- usb_gadget_register_driver() \n"); ++ ++ return 0; ++ ++err_func: ++ device_remove_file(&dev->pdev->dev, &dev_attr_function); ++ ++err_unbind: ++ driver->unbind(&dev->gadget); ++ dev->gadget.dev.driver = NULL; ++ dev->driver = NULL; ++ ++ DEBUG(dev, "<--- usb_gadget_register_driver() \n"); ++ ++ return retval; ++} ++EXPORT_SYMBOL(usb_gadget_register_driver); ++ ++ ++static void ++stop_activity(struct iusbc *dev, struct usb_gadget_driver *driver) ++{ ++ unsigned i; ++ ++ DEBUG(dev, "---> stop_activity() \n"); ++ ++ /* don't disconnect if it's not connected */ ++ if (dev->gadget.speed == USB_SPEED_UNKNOWN) ++ driver = NULL; ++ ++ /* stop hardware; prevent new request submissions; ++ * and kill any outstanding requests. ++ */ ++ iusbc_reset(dev); ++ ++ /* we need to mark ep0state to disconnect to avoid upper layer to start ++ * next transfer immediately after the following nuke operation, the ++ * iusbc_queue function need to check ep0state before issue a transfer ++ */ ++ dev->ep0state = EP0_DISCONNECT; ++ ++ /* 2 ep0, 3 data ep */ ++ for (i = 0; i < 5; i++) ++ nuke(&dev->ep[i]); ++ ++ /* report disconnect; the driver is already quiesced */ ++ if (driver) { ++ spin_unlock(&dev->lock); ++ driver->disconnect(&dev->gadget); ++ spin_lock(&dev->lock); ++ } ++ ++ iusbc_reinit(dev); ++ ++ DEBUG(dev, "<--- stop_activity() \n"); ++} ++ ++ ++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ++{ ++ struct iusbc *dev = the_controller; ++ unsigned long flags; ++ ++ DEBUG(dev, "---> usb_gadget_unregister_driver() \n"); ++ ++ if (!dev) ++ return -ENODEV; ++ if (!driver || driver != dev->driver || !driver->unbind) ++ return -EINVAL; ++ ++ /* kill irq tasklet */ ++ tasklet_kill(&dev->iusbc_tasklet); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ stop_activity(dev, driver); ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ iusbc_pullup(&dev->gadget, 0); ++ ++ driver->unbind(&dev->gadget); ++ dev->gadget.dev.driver = NULL; ++ dev->driver = NULL; ++ ++ device_remove_file(&dev->pdev->dev, &dev_attr_function); ++ device_remove_file(&dev->pdev->dev, &dev_attr_queues); ++ ++ INFO(dev, "unregistered driver '%s'\n", driver->driver.name); ++ ++ DEBUG(dev, "<--- usb_gadget_unregister_driver() \n"); ++ ++ return 0; ++} ++EXPORT_SYMBOL(usb_gadget_unregister_driver); ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static struct iusbc_ep * ++get_ep_by_addr(struct iusbc *dev, u16 wIndex) ++{ ++ struct iusbc_ep *ep; ++ ++ if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) ++ return &dev->ep[0]; ++ ++ list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { ++ u8 bEndpointAddress; ++ if (!ep->desc) ++ continue; ++ ++ bEndpointAddress = ep->desc->bEndpointAddress; ++ if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) ++ continue; ++ ++ if ((wIndex & USB_ENDPOINT_NUMBER_MASK) ++ == (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) ++ return ep; ++ } ++ return NULL; ++} ++ ++ ++/* NAK an endpoint */ ++static void ep_nak(struct iusbc_ep *ep) ++{ ++ u16 val_16; ++ unsigned i = ep->num; ++ ++ DEBUG(ep->dev, "---> ep_nak() \n"); ++ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ val_16 &= ~EP_ENABLE; ++ val_16 |= EP_VALID; ++ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); ++ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ VDEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); ++ ++ DEBUG(ep->dev, "<--- ep_nak() \n"); ++} ++ ++ ++/* ACK an out transfer with a zero length packet (ZLP) */ ++static void ep_ack(struct iusbc_ep *ep) ++{ ++ u16 val_16; ++ unsigned i = ep->num; ++ ++ DEBUG(ep->dev, "---> ep_ack() \n"); ++ ++ /* reset data buffer zero length */ ++ writew(0, &ep->dev->regs->ep[i].ep_len); ++ val_16 = readw(&ep->dev->regs->ep[i].ep_len); ++ VDEBUG(ep->dev, "%s.ep_len = 0x%04x\n", ep->ep.name, val_16); ++ ++ /* validate endpoint, enable DMA */ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ val_16 |= (EP_VALID | EP_ENABLE); ++ writew(val_16, &ep->dev->regs->ep[i].ep_cfg); ++ ++ val_16 = readw(&ep->dev->regs->ep[i].ep_cfg); ++ VDEBUG(ep->dev, "enable %s DMA transfer...\n", ep->ep.name); ++ VDEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16); ++ ++ DEBUG(ep->dev, "<--- ep_ack() \n"); ++} ++ ++ ++static void ep0_setup(struct iusbc *dev) ++{ ++ struct usb_ctrlrequest ctrl; ++ struct iusbc_ep *epn; ++ unsigned i, tmp = 0; ++ u8 addr_new, setup_pkt[8]; ++ ++ VDEBUG(dev, "---> ep0_setup() \n"); ++ ++ for (i = 0; i < 8; i++) { ++ setup_pkt[i] = readb(&dev->regs->ep[1].setup_pkt[i]); ++ } ++ ++ /* read SETUP packet and enter DATA stage */ ++ ctrl.bRequestType = setup_pkt[0]; ++ ctrl.bRequest = setup_pkt[1]; ++ ctrl.wValue = cpu_to_le16((setup_pkt[3] << 8) ++ | setup_pkt[2]); ++ ctrl.wIndex = cpu_to_le16((setup_pkt[5] << 8) ++ | setup_pkt[4]); ++ ctrl.wLength = cpu_to_le16((setup_pkt[7] << 8) ++ | setup_pkt[6]); ++ ++ dev->ep[1].stopped = 0; ++ ++ /* data stage direction */ ++ if (ctrl.bRequestType & USB_DIR_IN) { ++ dev->ep0state = EP0_IN; ++ VDEBUG(dev, "ep0state: EP0_IN\n"); ++ } else { ++ dev->ep0state = EP0_OUT; ++ VDEBUG(dev, "ep0state: EP0_OUT\n"); ++ } ++ ++ /* WORKAROUND: for RNDIS */ ++ /* CDC: SEND_ENCAPSULATED_COMMAND */ ++ if ((ctrl.bRequestType == 0x21) && (ctrl.bRequest == 0x00)) { ++ goto delegate; ++ } ++ /* CDC: GET_ENCAPSULATED_COMMAND */ ++ if ((ctrl.bRequestType == 0xa1) && (ctrl.bRequest == 0x01)) { ++ goto delegate; ++ } ++ ++ switch (ctrl.bRequest) { ++ /* GET_STATUS is handled by software */ ++ case USB_REQ_GET_STATUS: ++ DEBUG(dev, "SETUP: USB_REQ_GET_STATUS\n"); ++ switch (ctrl.bRequestType & ++ __constant_cpu_to_le16(USB_RECIP_MASK)) { ++ case USB_RECIP_DEVICE: ++ /* bit 0: USB_DEVICE_SELF_POWERED ++ * bit 1: USB_DEVICE_REMOTE_WAKEUP ++ */ ++ if (dev->enable_wakeup) { ++ dev->status_d = ++ __constant_cpu_to_le16(1 << 1 | 1); ++ } else { ++ dev->status_d = __constant_cpu_to_le16(1); ++ } ++ DEBUG(dev, "device status 0x%04x\n", dev->status_d); ++ break; ++ case USB_RECIP_INTERFACE: ++ /* all bits zero */ ++ dev->status_d = __constant_cpu_to_le16(0); ++ DEBUG(dev, "interface status 0x%04x\n", dev->status_d); ++ break; ++ case USB_RECIP_ENDPOINT: ++ if ((epn = get_ep_by_addr(dev, ++ le16_to_cpu(ctrl.wIndex))) == 0) ++ goto stall; ++ if (epn->stopped) { /* halted */ ++ dev->status_d = __constant_cpu_to_le16(1); ++ } else { ++ dev->status_d = __constant_cpu_to_le16(0); ++ } ++ DEBUG(dev, "%s endpoint status 0x%04x\n", ++ epn->ep.name, dev->status_d); ++ break; ++ } ++ /* GET_STATUS is partially handled in gadget driver */ ++ goto delegate; ++ ++ case USB_REQ_CLEAR_FEATURE: ++ DEBUG(dev, "SETUP: USB_REQ_CLEAR_FEATURE\n"); ++ switch (ctrl.bRequestType) { ++ case USB_RECIP_DEVICE: ++ if (ctrl.wValue == __constant_cpu_to_le16( ++ USB_DEVICE_REMOTE_WAKEUP)) { ++ dev->enable_wakeup = 0; ++ DEBUG(dev, "CLEAR_FEATURE: " ++ "remote wakeup disabled\n"); ++ goto end; ++ } else { ++ DEBUG(dev, "unsupported CLEAR_FEATURE\n"); ++ goto stall; ++ } ++ break; ++ case USB_RECIP_INTERFACE: ++ DEBUG(dev, "unsupported CLEAR_FEATURE\n"); ++ goto stall; ++ case USB_RECIP_ENDPOINT: ++ if (ctrl.wValue != __constant_cpu_to_le16( ++ USB_ENDPOINT_HALT) ++ || le16_to_cpu(ctrl.wLength) != 0) ++ goto stall; ++ if ((epn = get_ep_by_addr(dev, ++ le16_to_cpu(ctrl.wIndex))) == 0) ++ goto stall; ++ clear_halt(epn); ++ ep_ack(&dev->ep[0]); ++ ++ dev->ep0state = EP0_STATUS; ++ VDEBUG(dev, "ep0state: EP0_STATUS\n"); ++ ++ DEBUG(dev, "%s clear halt\n", epn->ep.name); ++ goto end; ++ } ++ break; ++ ++ case USB_REQ_SET_FEATURE: ++ DEBUG (dev, "SETUP: USB_REQ_SET_FEATURE\n"); ++ switch (ctrl.bRequestType) { ++ case USB_RECIP_DEVICE: ++ if (ctrl.wValue == __constant_cpu_to_le16( ++ USB_DEVICE_REMOTE_WAKEUP)) { ++ dev->enable_wakeup = 1; ++ DEBUG(dev, "SET_FEATURE: " ++ "remote wakeup enabled\n"); ++ goto end; ++ } else { ++ DEBUG(dev, "unsupported SET_FEATURE\n"); ++ goto stall; ++ } ++ break; ++ case USB_RECIP_INTERFACE: ++ DEBUG(dev, "unsupported SET_FEATURE\n"); ++ goto stall; ++ case USB_RECIP_ENDPOINT: ++ if (ctrl.wValue != __constant_cpu_to_le16( ++ USB_ENDPOINT_HALT) ++ || le16_to_cpu(ctrl.wLength) != 0) ++ goto stall; ++ if ((epn = get_ep_by_addr(dev, ++ le16_to_cpu(ctrl.wIndex))) == 0) ++ goto stall; ++ set_halt(epn); ++ ep_ack(&dev->ep[0]); ++ ++ DEBUG(dev, "%s set halt\n", epn->ep.name); ++ goto end; ++ } ++ break; ++ ++ case USB_REQ_SET_ADDRESS: ++ /* hw handles set_address, address range: 1-127 */ ++ DEBUG(dev, "SETUP: USB_REQ_SET_ADDRESS\n"); ++ if (setup_pkt[1] == USB_REQ_SET_ADDRESS) { ++ addr_new = le16_to_cpu(ctrl.wValue) & 0x7f; ++ DEBUG(dev, "addr_new = 0x%02x\n", addr_new); ++ ++ /* hardware didn't ACK SET_ADDRESS */ ++ ep_ack(&dev->ep[0]); ++ } ++ goto end; ++ ++ case USB_REQ_GET_DESCRIPTOR: ++ DEBUG(dev, "SETUP: USB_REQ_GET_DESCRIPTOR\n"); ++ goto delegate; ++ ++ case USB_REQ_SET_DESCRIPTOR: ++ DEBUG(dev, "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n"); ++ goto stall; ++ break; ++ ++ case USB_REQ_GET_CONFIGURATION: ++ DEBUG(dev, "SETUP: USB_REQ_GET_CONFIGURATION\n"); ++ goto delegate; ++ ++ case USB_REQ_SET_CONFIGURATION: ++ DEBUG(dev, "SETUP: USB_REQ_SET_CONFIGURATION\n"); ++ goto delegate; ++ ++ case USB_REQ_GET_INTERFACE: ++ DEBUG(dev, "SETUP: USB_REQ_GET_INTERFACE\n"); ++ goto delegate; ++ ++ case USB_REQ_SET_INTERFACE: ++ DEBUG(dev, "SETUP: USB_REQ_SET_INTERFACE\n"); ++ goto delegate; ++ ++ case USB_REQ_SYNCH_FRAME: ++ DEBUG(dev, "SETUP: USB_REQ_SYNCH_FRAME unsupported\n"); ++ goto stall; ++ break; ++ default: ++ /* delegate usb standard requests to the gadget driver. ++ * it may respond after this irq handler returns. ++ */ ++ goto delegate; ++delegate: ++ DEBUG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", ++ ctrl.bRequestType, ctrl.bRequest, ++ le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex), ++ le16_to_cpu(ctrl.wLength)); ++ ++ /* WORKAROUND: for RNDIS */ ++ /* CDC: SEND_ENCAPSULATED_COMMAND */ ++ if ((ctrl.bRequestType == 0x21) ++ && (ctrl.bRequest == 0x00)) { ++ /* CDC: SEND_ENCAPSULATED_COMMAND */ ++ DEBUG(dev, "CDC: SEND_ENCAPSULATED_COMMAND\n"); ++ dev->gadget.ep0 = &dev->ep[1].ep; ++ spin_unlock(&dev->lock); ++ tmp = dev->driver->setup(&dev->gadget, &ctrl); ++ spin_lock(&dev->lock); ++ ++ /* switch back to ep0-in */ ++ dev->gadget.ep0 = &dev->ep[0].ep; ++ ++ /* hardware didn't ACK */ ++ ep_ack(&dev->ep[0]); ++ } else { ++ dev->gadget.ep0 = &dev->ep[0].ep; ++ spin_unlock(&dev->lock); ++ tmp = dev->driver->setup(&dev->gadget, &ctrl); ++ spin_lock(&dev->lock); ++ ++ /* CDC: GET_ENCAPSULATED_COMMAND */ ++ if ((ctrl.bRequestType == 0xa1) ++ && (ctrl.bRequest == 0x01)) { ++ DEBUG(dev, "CDC: GET_ENCAPSULATED_COMMAND\n"); ++ ++ /* hardware didn't ACK */ ++ ep_ack(&dev->ep[1]); ++ } ++ } ++ break; ++ } ++ ++ /* stall ep0-out on error */ ++ if (unlikely(tmp < 0)) { ++stall: ++ DEBUG(dev, "req %02x.%02x protocol STALL; err %d\n", ++ ctrl.bRequestType, ctrl.bRequest, tmp); ++ dev->ep[1].stopped = 1; ++ dev->ep0state = EP0_STALL; ++ VDEBUG(dev, "ep0state: EP0_STALL\n"); ++ } ++end: ++ VDEBUG(dev, "<--- ep0_setup() \n"); ++} ++ ++ ++static void handle_device_irqs(struct iusbc *dev) ++{ ++ u32 stat; ++ volatile u32 dev_sts; ++ unsigned is_connected = 0; ++ ++ DEBUG(dev, "---> handle_device_irqs() \n"); ++ ++ stat = dev->int_sts; ++ ++ /* get device status, set USB speed */ ++ if ((stat & RESET_INTR) || (stat & CONNECT_INTR) ++ || (stat & SUSPEND_INTR)) { ++ /* check device status */ ++ dev_sts = readl(&dev->regs->dev_sts); ++ DEBUG(dev, "handle_device_irqs: dev_sts = 0x%08x\n", ++ dev_sts); ++ ++ if (dev_sts & CONNECTED) { ++ is_connected = 1; ++ DEBUG(dev, "device connected\n"); ++ ++ /* check suspend/resume status now */ ++ if (dev_sts & SUSPEND) ++ dev->suspended = 1; ++ else ++ dev->suspended = 0; ++ ++ /* RATE: high/full speed flag ++ * 1 clock cycle after CONNECT, ++ * read one more time until RATE bit set ++ */ ++ dev_sts = readl(&dev->regs->dev_sts); ++ DEBUG(dev, "read for RATE: dev_sts = 0x%08x\n", ++ dev_sts); ++ if (dev_sts & RATE) { ++ if (dev->force_fullspeed) { ++ dev->gadget.speed = USB_SPEED_FULL; ++ DEBUG(dev, "speed: USB_SPEED_FULL\n"); ++ } else { ++ dev->gadget.speed = USB_SPEED_HIGH; ++ DEBUG(dev, "speed: USB_SPEED_HIGH\n"); ++ } ++ } else { ++ dev->gadget.speed = USB_SPEED_FULL; ++ DEBUG(dev, "speed: USB_SPEED_FULL\n"); ++ } ++ } else { /* disconnected */ ++ is_connected = 0; ++ DEBUG(dev, "device disconnected\n"); ++ } ++ } ++ ++ /* USB reset interrupt indication */ ++ if ((stat & RESET_INTR) && (!dev->is_reset)) { ++ DEBUG(dev, "USB Reset interrupt: stat = 0x%08x\n", stat); ++ /* ACK RESET_INTR */ ++ stat &= ~RESET_INTR; ++ dev->irqs++; ++ VDEBUG(dev, "dev->irqs: %lu\n", dev->irqs); ++ ++ /* set device reset flag */ ++ dev->is_reset = 1; ++ ++ stop_activity(dev, dev->driver); ++ ep0_start(dev); ++ VDEBUG(dev, "reset: ep0_start()\n"); ++ ++ goto end; ++ } ++ ++ ++ /* connect interrupt indication */ ++ if (stat & CONNECT_INTR) { ++ DEBUG(dev, "CONNECT interrupt: stat = 0x%08x\n", stat); ++ /* ACK CONNECT_INTR */ ++ stat &= ~CONNECT_INTR; ++ dev->irqs++; ++ VDEBUG(dev, "dev->irqs: %lu\n", dev->irqs); ++ ++ /* connected status has changed */ ++ if (dev->connected != is_connected) { ++ DEBUG(dev, "connected status has changed\n"); ++ dev->connected = is_connected; ++ if (is_connected) { ++ ep0_start(dev); ++ DEBUG(dev, "connect %s\n", dev->driver->driver.name); ++ } else { /* disconnected */ ++ /* set device reset flag */ ++ dev->is_reset = 0; ++ stop_activity(dev, dev->driver); ++ DEBUG(dev, "disconnect %s\n", dev->driver->driver.name); ++ dev->ep0state = EP0_DISCONNECT; ++ VDEBUG(dev, "ep0state: EP0_DISCONNECT\n"); ++ } ++ } ++ } ++ ++ /* host suspend interrupt indication */ ++ if (stat & SUSPEND_INTR) { ++ DEBUG(dev, "SUSPEND interrupt: stat = 0x%08x\n", stat); ++ /* ACK SUSPEND_INTR */ ++ stat &= ~SUSPEND_INTR; ++ dev->irqs++; ++ VDEBUG(dev, "dev->irqs: %lu\n", dev->irqs); ++ ++ /* call gadget driver suspend/resume routines */ ++ if (dev->suspended) { ++ if (dev->driver->suspend) { ++ spin_unlock(&dev->lock); ++ dev->driver->suspend(&dev->gadget); ++ spin_lock(&dev->lock); ++ } ++ DEBUG(dev, "suspend %s\n", dev->driver->driver.name); ++ } else { ++ if (dev->driver->resume) { ++ spin_unlock(&dev->lock); ++ dev->driver->resume(&dev->gadget); ++ spin_lock(&dev->lock); ++ } ++ DEBUG(dev, "resume %s\n", dev->driver->driver.name); ++ } ++ } ++ ++ /* if haven't USB Reset yet, wait for the next USB reset interrupt */ ++ if (!dev->is_reset) { ++ DEBUG(dev, "Skip other interrupts before RESET\n"); ++ } ++ ++end: ++ VDEBUG(dev, "handle device_irq finish: int_sts = 0x%08x, " ++ "stat = 0x%08x\n", dev->int_sts, stat); ++ ++ VDEBUG(dev, "<--- handle_device_irqs() \n"); ++} ++ ++ ++static void handle_ep0_irqs(struct iusbc *dev) ++{ ++ volatile u16 ep_sts, val_16; ++ u32 stat; ++ u8 setup_pkt_sts; ++ struct iusbc_request *req; ++ ++ VDEBUG(dev, "---> handle_ep0_irqs() \n"); ++ ++ stat = dev->int_sts; ++ VDEBUG(dev, "stat = 0x%08x\n", stat); ++ ++ /* ep0-out interrupt */ ++ if (stat & EP0_OUT_INTR) { ++ dev->ep[1].irqs++; ++ VDEBUG(dev, "%s.irqs = %lu\n", ++ dev->ep[1].ep.name ,dev->ep[1].irqs); ++ ++ ep_sts = readw(&dev->regs->ep[1].ep_sts); ++ VDEBUG(dev, "%s.ep_sts = 0x%04x\n", ++ dev->ep[1].ep.name, ep_sts); ++ ++ /* W1C ep0-out status register */ ++ writew(ep_sts, &dev->regs->ep[1].ep_sts); ++ ++ if ((ep_sts & BAD_PID_TYPE) ++ || (ep_sts & CRC_ERROR) ++ || (ep_sts & FIFO_ERROR) ++ || (ep_sts & DMA_ERROR) ++ || (ep_sts & DMA_IOC)) { ++ DEBUG(dev, "%s error: 0x%04x \n", ++ dev->ep[1].ep.name, ep_sts); ++ } ++ ++ if (ep_sts & TRANS_COMPLETE) { ++ VDEBUG(dev, "handle ep0-out interrupt\n"); ++ ++ setup_pkt_sts = readb(&dev->regs->ep[1].setup_pkt_sts); ++ VDEBUG(dev, "setup_pkt_sts = 0x%02x\n", setup_pkt_sts); ++ /* ep0-out SETUP packet */ ++ if (setup_pkt_sts) { ++ VDEBUG(dev, "ep0-out SETUP packet\n"); ++ ++ /* W1C ep0-out Setup Packet Status Register */ ++ writeb(1, &dev->regs->ep[1].setup_pkt_sts); ++ ++ /* read ep0-out Setup Packet Register ++ * then handle ep0-out SETUP packet ++ */ ++ ep0_setup(dev); ++ } else { ++ /* ep0-out standard OUT packet */ ++ DEBUG(dev, "ep0-out OUT packet\n"); ++ if (!list_empty(&dev->ep[1].queue)) { ++ req = list_entry(dev->ep[1].queue.next, ++ struct iusbc_request, ++ queue); ++ VDEBUG(dev, "dmacount = %d\n", ++ req->td->dmacount); ++ dma_done(&dev->ep[1], req, 0); ++ VDEBUG(dev, "%s dma_done()\n", ++ dev->ep[1].ep.name); ++ } ++ ++ /* handle next standard OUT packet */ ++ if (!list_empty(&dev->ep[1].queue)) { ++ restart_dma(&dev->ep[1]); ++ VDEBUG(dev, "%s restart_dma()\n", ++ dev->ep[1].ep.name); ++ } ++ } ++ } else { ++ /* WORKAROUND: FIFO_ERROR TC=0 */ ++ if (ep_sts & FIFO_ERROR) ++ DEBUG(dev, "ep0-out FIFO_ERROR, TC=0\n"); ++ } ++ ++ /* enable DMA again */ ++ val_16 = readw(&dev->regs->ep[1].ep_cfg); ++ val_16 |= EP_ENABLE; ++ writew(val_16, &dev->regs->ep[1].ep_cfg); ++ ++ val_16 = readw(&dev->regs->ep[1].ep_cfg); ++ VDEBUG(dev, "enable %s DMA transfer...\n", ++ dev->ep[1].ep.name); ++ VDEBUG(dev, "%s EP_ENABLE again, ep_cfg=0x%04x\n", ++ dev->ep[1].ep.name, val_16); ++ } ++ ++ /* ep0-in interrupt */ ++ if (stat & EP0_IN_INTR) { ++ dev->ep[0].irqs++; ++ VDEBUG(dev, "%s.irqs = %lu\n", ++ dev->ep[0].ep.name, dev->ep[0].irqs); ++ ++ ep_sts = readw(&dev->regs->ep[0].ep_sts); ++ VDEBUG(dev, "%s.ep_sts = 0x%04x\n", ++ dev->ep[0].ep.name, ep_sts); ++ ++ /* W1C ep0-in status register */ ++ writew(ep_sts, &dev->regs->ep[0].ep_sts); ++ ++ if ((ep_sts & BAD_PID_TYPE) ++ || (ep_sts & CRC_ERROR) ++ || (ep_sts & FIFO_ERROR) ++ || (ep_sts & DMA_ERROR) ++ || (ep_sts & DMA_IOC)) { ++ DEBUG(dev, "%s error: 0x%04x \n", ++ dev->ep[0].ep.name, ep_sts); ++ } ++ ++ if (ep_sts & TRANS_COMPLETE) { ++ VDEBUG(dev, "handle ep0-in interrupt\n"); ++ if (!list_empty(&dev->ep[0].queue)) { ++ req = list_entry(dev->ep[0].queue.next, ++ struct iusbc_request, ++ queue); ++ VDEBUG(dev, "dmacount = %d\n", req->td->dmacount); ++ dma_done(&dev->ep[0], req, 0); ++ VDEBUG(dev, "%s dma_done()\n", ++ dev->ep[0].ep.name); ++ } ++ ++ /* handle next standard IN packet */ ++ if (!list_empty(&dev->ep[0].queue)) { ++ restart_dma(&dev->ep[0]); ++ VDEBUG(dev, "%s restart_dma()\n", ++ dev->ep[0].ep.name); ++ } ++ } else { ++ if (ep_sts & FIFO_ERROR) ++ DEBUG(dev, "ep0-in FIFO_ERROR, TC=0\n"); ++ } ++ ++ } ++ ++ VDEBUG(dev, "<--- handle_ep0_irqs() \n"); ++} ++ ++ ++static void handle_ep_irqs(struct iusbc *dev) ++{ ++ volatile u16 ep_sts; ++ u32 stat; ++ unsigned i; ++ struct iusbc_request *req; ++ ++ VDEBUG(dev, "---> handle_ep_irqs() \n"); ++ ++ stat = dev->int_sts; ++ VDEBUG(dev, "stat = 0x%08x\n", stat); ++ ++ /* ep1in-bulk, ep1out-bulk and ep2in-int */ ++ for (i = 2; i < 5; i++) { ++ if ((1 << i) & stat) { ++ dev->ep[i].irqs++; ++ ep_sts = readw(&dev->regs->ep[i].ep_sts); ++ if (ep_sts) ++ VDEBUG(dev, "%s.ep_sts = 0x%04x\n", ++ dev->ep[i].ep.name, ep_sts); ++ ++ /* W1C ep status register */ ++ writew(ep_sts, &dev->regs->ep[i].ep_sts); ++ ++ if ((ep_sts & BAD_PID_TYPE) ++ || (ep_sts & CRC_ERROR) ++ || (ep_sts & FIFO_ERROR) ++ || (ep_sts & DMA_ERROR) ++ || (ep_sts & DMA_IOC)) { ++ DEBUG(dev, "%s error: 0x%04x \n", ++ dev->ep[i].ep.name, ep_sts); ++ } ++ ++ if (ep_sts & TRANS_COMPLETE) { ++ VDEBUG(dev, "handle %s interrupt\n", ++ dev->ep[i].ep.name); ++ VDEBUG(dev, "data ep dma TRANS_COMPLETE\n"); ++ if (!list_empty(&dev->ep[i].queue)) { ++ req = list_entry(dev->ep[i].queue.next, ++ struct iusbc_request, ++ queue); ++ VDEBUG(dev, "dmacount = %d\n", ++ req->td->dmacount); ++ dma_done(&dev->ep[i], req, 0); ++ VDEBUG(dev, "%s dma_done()\n", ++ dev->ep[i].ep.name); ++ } ++ ++ /* handle next standard OUT and IN packet */ ++ if (!list_empty(&dev->ep[i].queue)) { ++ restart_dma(&dev->ep[i]); ++ VDEBUG(dev, "%s restart_dma()\n", ++ dev->ep[i].ep.name); ++ } ++ } else { ++ if (ep_sts & FIFO_ERROR) ++ DEBUG(dev, "%s FIFO_ERROR, TC=0\n", ++ dev->ep[i].ep.name); ++ } ++ } ++ } ++ ++ VDEBUG(dev, "<--- handle_ep_irqs() \n"); ++} ++ ++ ++static void iusbc_do_tasklet(unsigned long arg) ++{ ++ u32 val_32; ++ volatile u32 dev_sts; ++ struct iusbc *dev; ++ dev = (struct iusbc *) arg; ++ DEBUG(dev, "---> iusbc_do_tasklet() \n"); ++ ++ spin_lock(&dev->lock); ++ ++ /* disable irqs, will re-enable later */ ++ writel(0, &dev->regs->int_ctrl); ++ ++ /* device-wide reset, connect, suspend */ ++ if (dev->int_sts & (RESET_INTR | CONNECT_INTR | SUSPEND_INTR)) { ++ DEBUG(dev, "iusbc_do_tasklet -> handle_device_irqs\n"); ++ handle_device_irqs(dev); ++ } ++ ++ /* QQQ: disable Full speed mode for D1 hw issues. */ ++ dev_sts = readl(&dev->regs->dev_sts); ++ if ((dev_sts & RATE) && (dev_sts & CONNECTED)) { ++ /* ep0-in/out control requests and interrupt */ ++ if (dev->int_sts & (EP0_IN_INTR | EP0_OUT_INTR)) { ++ DEBUG(dev, "iusbc_do_tasklet -> handle_ep0_irqs\n"); ++ handle_ep0_irqs(dev); ++ } ++ /* data endpoints requests interrupt */ ++ if (dev->int_sts & (EP1_IN_INTR | EP1_OUT_INTR | EP2_IN_INTR)) { ++ DEBUG(dev, "iusbc_do_tasklet -> handle_ep_irqs\n"); ++ handle_ep_irqs(dev); ++ } ++ } else if (dev_sts & CONNECTED) { ++ stop_activity(dev, dev->driver); ++ dev->ep0state = EP0_DISCONNECT; ++ /*iusbc_pullup(&dev->gadget, 0);*/ ++ } ++ ++ /* enable irqs again */ ++ val_32 = 0; ++ val_32 |= RESET_INTR_ENABLE ++ | CONNECT_INTR_ENABLE ++ | SUSPEND_INTR_ENABLE ++ /* | EP3_OUT_INTR_ENABLE */ ++ /* | EP3_IN_INTR_ENABLE */ ++ /* | EP2_OUT_INTR_ENABLE */ ++ | EP2_IN_INTR_ENABLE ++ | EP1_OUT_INTR_ENABLE ++ | EP1_IN_INTR_ENABLE ++ | EP0_OUT_INTR_ENABLE ++ | EP0_IN_INTR_ENABLE; ++ ++ writel(val_32, &dev->regs->int_ctrl); ++ val_32 = readl(&dev->regs->int_ctrl); ++ DEBUG(dev, "enable irqs again in iusbc_do_tasklet(), " ++ "int_ctrl = 0x%08x\n", val_32); ++ ++ spin_unlock(&dev->lock); ++ ++ DEBUG(dev, "<--- iusbc_do_tasklet() \n"); ++} ++ ++ ++static irqreturn_t iusbc_irq(int irq, void *_dev) ++{ ++ struct iusbc *dev = _dev; ++ u32 int_sts, ++ int_ctrl, ++ val_32; ++ ++ VDEBUG(dev, "---> iusbc_irq() \n"); ++ ++ /* interrupt control */ ++ int_ctrl = readl(&dev->regs->int_ctrl); ++ VDEBUG(dev, "int_ctrl = 0x%08x\n", int_ctrl); ++ ++ /* interrupt status */ ++ int_sts = readl(&dev->regs->int_sts); ++ VDEBUG(dev, "int_sts = 0x%08x\n", int_sts); ++ ++ if (!int_sts || !int_ctrl) { ++ VDEBUG(dev, "handle IRQ_NONE\n"); ++ VDEBUG(dev, "<--- iusbc_irq() \n"); ++ return IRQ_NONE; ++ } ++ ++ /* disable irqs, will re-enable later */ ++ writel(0, &dev->regs->int_ctrl); ++ ++ /* W1C interrupt status register */ ++ writel(int_sts, &dev->regs->int_sts); ++ val_32 = readl(&dev->regs->int_sts); ++ VDEBUG(dev, "W1C: regs->int_sts = 0x%08x\n", val_32); ++ ++ /* for iusbc_tasklet */ ++ dev->int_sts = int_sts; ++ ++ /* check device status */ ++ val_32 = readl(&dev->regs->dev_sts); ++ DEBUG(dev, "iusbc_irq: dev_sts = 0x%08x\n", val_32); ++ ++ /* schedule irq tasklet */ ++ tasklet_schedule(&dev->iusbc_tasklet); ++ ++ VDEBUG(dev, "<--- iusbc_irq() \n"); ++ return IRQ_HANDLED; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void gadget_release(struct device *_dev) ++{ ++ struct iusbc *dev; ++#ifdef VERBOSE ++ printk(KERN_DEBUG "---> gadget_release() \n"); ++#endif ++ ++ dev = dev_get_drvdata(_dev); ++ kfree(dev); ++ ++#ifdef VERBOSE ++ printk(KERN_DEBUG "<--- gadget_release() \n"); ++#endif ++} ++ ++ ++/* tear down the binding between this driver and the pci device */ ++static void iusbc_remove(struct pci_dev *pdev) ++{ ++ struct iusbc *dev; ++ ++ dev = pci_get_drvdata(pdev); ++ ++ BUG_ON(dev->driver); ++ ++ VDEBUG(dev, "---> iusbc_remove() \n"); ++ ++ /* then clean up the resources we allocated during probe() */ ++ if (dev->requests) { ++ unsigned i; ++ /* 2 ep0, 3 data ep */ ++ for (i = 0; i < 5; i++) { ++ if (!dev->ep[i].dummy) ++ continue; ++ ++ pci_pool_free(dev->requests, dev->ep[i].dummy, ++ dev->ep[i].td_dma); ++ } ++ pci_pool_destroy(dev->requests); ++ } ++ ++ if (dev->got_irq) ++ free_irq(pdev->irq, dev); ++ ++ if (dev->regs) ++ iounmap(dev->regs); ++ ++ if (dev->region) ++ release_mem_region(pci_resource_start(pdev, 0), ++ pci_resource_len(pdev, 0)); ++ ++ if (dev->enabled) ++ pci_disable_device(pdev); ++ ++ device_unregister(&dev->gadget.dev); ++ device_remove_file(&pdev->dev, &dev_attr_registers); ++ pci_set_drvdata(pdev, NULL); ++ ++ INFO(dev, "unbind\n"); ++ ++ the_controller = NULL; ++ ++ VDEBUG(dev, "<--- iusbc_remove() \n"); ++} ++ ++ ++/* wrap this driver around the specified device, but ++ * don't respond over USB until a gadget driver binds to us. ++ */ ++static int iusbc_probe(struct pci_dev *pdev, const struct pci_device_id *id) ++{ ++ struct iusbc *dev; ++ unsigned long resource, len; ++ void __iomem *base = NULL; ++ int retval; ++ unsigned i; ++ u32 val_32; ++ ++ /* if you want to support more than one controller in a system, ++ * usb_gadget_{register,unregister}_driver() must change. ++ */ ++ if (the_controller) { ++ dev_warn(&pdev->dev, "ignoring\n"); ++ return -EBUSY; ++ } ++ ++ /* alloc, and start init */ ++ dev = kzalloc(sizeof *dev, GFP_KERNEL); ++ if (dev == NULL){ ++ retval = -ENOMEM; ++ goto done; ++ } ++ ++ pci_set_drvdata(pdev, dev); ++ spin_lock_init(&dev->lock); ++ dev->pdev = pdev; ++ ++ DEBUG(dev, "---> iusbc_probe() \n"); ++ ++ dev->gadget.ops = &iusbc_ops; ++ dev->gadget.is_dualspeed = 1; /* support high/full speed */ ++ ++ /* the "gadget" abstracts/virtualizes the controller */ ++ strcpy(dev->gadget.dev.bus_id, "gadget"); ++ dev->gadget.dev.parent = &pdev->dev; ++ dev->gadget.dev.dma_mask = pdev->dev.dma_mask; ++ dev->gadget.dev.release = gadget_release; ++ dev->gadget.name = driver_name; ++ ++ /* now all the pci goodies ... */ ++ if (pci_enable_device(pdev) < 0) { ++ retval = -ENODEV; ++ goto done; ++ } ++ ++ /* WORKAROUND: USB port routing bug */ ++ pci_write_config_byte(pdev, 0x40, 0x82); ++ ++ dev->enabled = 1; ++ ++ /* control register: BAR 0 */ ++ resource = pci_resource_start(pdev, 0); ++ len = pci_resource_len(pdev, 0); ++ if (!request_mem_region(resource, len, driver_name)) { ++ DEBUG(dev, "controller already in use\n"); ++ retval = -EBUSY; ++ goto done; ++ } ++ dev->region = 1; ++ ++ base = ioremap_nocache(resource, len); ++ if (base == NULL) { ++ DEBUG(dev, "can't map memory\n"); ++ retval = -EFAULT; ++ goto done; ++ } ++ dev->regs = (struct iusbc_regs __iomem *) base; ++ ++ /* global capabilities, ep number and dma modes */ ++ val_32 = readl(&dev->regs->gcap); ++ if (val_32 & TRANSFER_MODE_CAP) ++ dev->transfer_mode_dma = 1; ++ ++ if (val_32 & SCATTER_GATHER_MODE_CAP) ++ dev->sg_mode_dma = 1; ++ ++ if (val_32 & LINEAR_MODE_CAP) ++ dev->linear_mode_dma = 1; ++ ++ if (val_32 & CONTROL_MODE_CAP) ++ dev->control_mode_dma = 1; ++ ++ dev->ep_cap = (val_32 >> 28); ++ ++ /* reset all registers */ ++ writel(0, &dev->regs->dev_ctrl); ++ ++ /* init usb client controller device */ ++ iusbc_reset(dev); ++ iusbc_reinit(dev); ++ ++ /* irq setup after old hardware is cleaned up */ ++ if (!pdev->irq) { ++ ERROR(dev, "No IRQ. Check PCI setup!\n"); ++ retval = -ENODEV; ++ goto done; ++ } ++ ++ if (request_irq(pdev->irq, iusbc_irq, IRQF_SHARED, driver_name, dev) ++ != 0) { ++ ERROR(dev, "request interrupt %d failed\n", pdev->irq); ++ retval = -EBUSY; ++ goto done; ++ } ++ dev->got_irq = 1; ++ ++ /* ------------------------------------------------------------------ */ ++ /* DMA setup ++ * NOTE: we know only the 32 LSBs of dma addresses may be nonzero ++ */ ++ dev->requests = pci_pool_create("requests", pdev, ++ sizeof(struct iusbc_dma), ++ 0 /* no alignment requirements */, ++ 0 /* or page-crossing issues */); ++ ++ if (!dev->requests) { ++ DEBUG(dev, "can't get request pool\n"); ++ retval = -ENOMEM; ++ goto done; ++ } ++ ++ /* assgined DMA */ ++ /* 2 ep0, 3 data ep */ ++ for (i = 0; i < 5 ; i++) { ++ struct iusbc_dma *td; ++ td = pci_pool_alloc(dev->requests, ++ GFP_KERNEL, ++ &dev->ep[i].td_dma); ++ ++ if (!td) { ++ DEBUG(dev, "can't get dummy %d\n", i); ++ retval = -ENOMEM; ++ goto done; ++ } ++ ++ td->dmacount = 0; /* not VALID */ ++ td->dmaaddr = __constant_cpu_to_le32(DMA_ADDR_INVALID); ++ ++ dev->ep[i].dummy = td; ++ } ++ ++ /* enables bus-mastering for device dev */ ++ pci_set_master(pdev); ++ ++ /* ------------------------------------------------------------------ */ ++ /* done */ ++ INFO(dev, "%s\n", driver_desc); ++ INFO(dev, "irq %d, pci mem %p\n", pdev->irq, base); ++ INFO(dev, "version: " DRIVER_VERSION "\n"); ++ INFO(dev, "support (max) %d endpoints\n", dev->ep_cap * 2); ++ ++#ifdef VERBOSE ++ /* only for debugging, print mapped memory registers */ ++ VDEBUG(dev, "After iusbc_probe(), print register values:\n"); ++ print_all_registers(dev->regs); ++#endif ++ ++ the_controller = dev; ++ retval = device_register(&dev->gadget.dev); ++ ++ if (retval) ++ goto done; ++ ++ retval = device_create_file(&pdev->dev, &dev_attr_registers); ++ ++ if (retval) ++ goto done; ++ ++ DEBUG(dev, "<--- iusbc_probe() \n"); ++ ++ return 0; ++ ++done: ++ if (dev) ++ iusbc_remove(pdev); ++ ++ DEBUG(dev, "<--- iusbc_probe() \n"); ++ ++ return retval; ++} ++ ++ ++#ifdef CONFIG_PM ++/* client suspend */ ++static int iusbc_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct iusbc *dev; ++ unsigned long flags; ++ ++ dev = pci_get_drvdata(pdev); ++ ++ DEBUG(dev, "---> iusbc_suspend() \n"); ++ ++ tasklet_kill(&dev->iusbc_tasklet); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ stop_activity(dev, dev->driver); ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ iusbc_pullup(&dev->gadget, 0); ++ ++ pci_save_state(pdev); ++ pci_set_power_state(pdev, PCI_D3hot); ++ ++ DEBUG(dev, "<--- iusbc_suspend() \n"); ++ ++ return 0; ++} ++ ++/* client resume */ ++static int iusbc_resume(struct pci_dev *pdev) ++{ ++ struct iusbc *dev; ++ ++ dev = pci_get_drvdata(pdev); ++ ++ DEBUG(dev, "---> iusbc_resume() \n"); ++ ++ pci_set_power_state(pdev, PCI_D0); ++ pci_restore_state(pdev); ++ ++ device_start(dev); ++ ++ DEBUG(dev, "<--- iusbc_resume() \n"); ++ ++ return 0; ++} ++#endif ++ ++ ++static void iusbc_shutdown(struct pci_dev *pdev) ++{ ++ struct iusbc *dev; ++ u32 val_32; ++ ++ dev = pci_get_drvdata(pdev); ++ ++ DEBUG(dev, "---> iusbc_shutdown() \n"); ++ ++ /* disable irqs */ ++ writel(0, &dev->regs->int_ctrl); ++ ++ /* reset all registers */ ++ writel(0, &dev->regs->dev_ctrl); ++ ++ val_32 = readl(&dev->regs->dev_ctrl); ++ DEBUG(dev, "dev_ctrl = 0x%08x\n", val_32); ++ ++ DEBUG(dev, "<--- iusbc_shutdown() \n"); ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static const struct pci_device_id pci_ids [] = { { ++ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0x80), ++ .class_mask = ~0, ++ .vendor = 0x8086, /* Intel */ ++ .device = 0x8118, /* Poulsbo USB Client Controller */ ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++}, { /* end: all zeroes */ } ++}; ++ ++MODULE_DEVICE_TABLE(pci, pci_ids); ++ ++/* pci driver glue; this is a "new style" PCI driver module */ ++static struct pci_driver iusbc_pci_driver = { ++ .name = (char *) driver_name, ++ .id_table = pci_ids, ++ ++ .probe = iusbc_probe, ++ .remove = iusbc_remove, ++ ++#ifdef CONFIG_PM ++ .suspend = iusbc_suspend, ++ .resume = iusbc_resume, ++#endif ++ ++ .shutdown = iusbc_shutdown, ++}; ++ ++ ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_AUTHOR("Xiaochen Shen: xiaochen.shen@intel.com"); ++MODULE_VERSION(DRIVER_VERSION); ++MODULE_LICENSE("GPL"); ++ ++ ++static int __init init(void) ++{ ++ return pci_register_driver(&iusbc_pci_driver); ++} ++module_init(init); ++ ++ ++static void __exit cleanup(void) ++{ ++ /* in case deferred_free tasklet not finished */ ++ spin_lock(&buflock); ++ while (!list_empty(&buffers)) { ++ spin_unlock(&buflock); ++ msleep(1); ++ spin_lock(&buflock); ++ } ++ spin_unlock(&buflock); ++ pci_unregister_driver(&iusbc_pci_driver); ++} ++module_exit(cleanup); ++ +diff --git a/drivers/usb/gadget/iusbc.h b/drivers/usb/gadget/iusbc.h +new file mode 100644 +index 0000000..9e0517b +--- /dev/null ++++ b/drivers/usb/gadget/iusbc.h +@@ -0,0 +1,213 @@ ++/* ++ * Intel Poulsbo USB Client Controller Driver ++ * Copyright (C) 2006-07, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++ ++#include ++ ++/* ++ * MEMORY SPACE REGISTERS ++ */ ++ ++struct iusbc_ep_regs { /* 0x20 bytes */ ++ u32 ep_base_low_32; ++ u32 ep_base_hi_32; ++ u16 ep_len; ++ u16 ep_pib; ++ u16 ep_dil; ++ u16 ep_tiq; ++ u16 ep_max; ++ u16 ep_sts; ++#define BAD_PID_TYPE (1 << 15) ++#define CRC_ERROR (1 << 14) ++#define FIFO_ERROR (1 << 13) ++#define DMA_ERROR (1 << 12) ++#define TRANS_COMPLETE (1 << 11) ++#define PING_NAK_SENT (1 << 10) ++#define DMA_IOC (1 << 9) ++ u16 ep_cfg; ++#define INTR_BAD_PID_TYPE (1 << 15) ++#define INTR_CRC_ERROR (1 << 14) ++#define INTR_FIFO_ERROR (1 << 13) ++#define INTR_DMA_ERROR (1 << 12) ++#define INTR_TRANS_COMPLETE (1 << 11) ++#define INTR_PING_NAK_SENT (1 << 10) ++#define INTR_DMA_IOC (1 << 9) ++#define LINEAR_MODE 0 ++#define SCATTER_GATHER_MODE 1 ++#define TRANSFER_MODE 2 ++#define CONTROL_MODE 3 ++#define EP_ENABLE (1 << 1) ++#define EP_VALID (1 << 0) ++ u8 _unused; ++ u8 setup_pkt_sts; ++#define SETUPPACKET_VALID (1 << 0) ++ u8 setup_pkt[8]; ++} __attribute__ ((packed)); ++ ++ ++struct iusbc_regs { ++ /* offset 0x0000 */ ++ u32 gcap; ++#define DMA_IOC_CAP (1 << 4) ++#define TRANSFER_MODE_CAP (1 << 3) ++#define SCATTER_GATHER_MODE_CAP (1 << 2) ++#define LINEAR_MODE_CAP (1 << 1) ++#define CONTROL_MODE_CAP (1 << 0) ++ u8 _unused0[0x100-0x004]; ++ ++ /* offset 0x0100 */ ++ u32 dev_sts; ++#define RATE (1 << 3) ++#define CONNECTED (1 << 1) ++#define SUSPEND (1 << 0) ++ u16 frame; ++ u8 _unused1[0x10c-0x106]; ++ ++ /* offset 0x010c */ ++ u32 int_sts; ++#define RESET_INTR (1 << 18) ++#define CONNECT_INTR (1 << 17) ++#define SUSPEND_INTR (1 << 16) ++#define EP3_OUT_INTR (1 << 7) ++#define EP3_IN_INTR (1 << 6) ++#define EP2_OUT_INTR (1 << 5) ++#define EP2_IN_INTR (1 << 4) ++#define EP1_OUT_INTR (1 << 3) ++#define EP1_IN_INTR (1 << 2) ++#define EP0_OUT_INTR (1 << 1) ++#define EP0_IN_INTR (1 << 0) ++ u32 int_ctrl; ++#define RESET_INTR_ENABLE (1 << 18) ++#define CONNECT_INTR_ENABLE (1 << 17) ++#define SUSPEND_INTR_ENABLE (1 << 16) ++#define EP3_OUT_INTR_ENABLE (1 << 7) ++#define EP3_IN_INTR_ENABLE (1 << 6) ++#define EP2_OUT_INTR_ENABLE (1 << 5) ++#define EP2_IN_INTR_ENABLE (1 << 4) ++#define EP1_OUT_INTR_ENABLE (1 << 3) ++#define EP1_IN_INTR_ENABLE (1 << 2) ++#define EP0_OUT_INTR_ENABLE (1 << 1) ++#define EP0_IN_INTR_ENABLE (1 << 0) ++ u32 dev_ctrl; ++#define DEVICE_ENABLE (1 << 31) ++#define CONNECTION_ENABLE (1 << 30) ++#define DMA3_DISABLED (1 << 15) ++#define DMA2_DISABLED (1 << 14) ++#define DMA1_DISABLED (1 << 13) ++#define DMA0_DISABLED (1 << 12) ++#define CPU_SET_ADDRESS (1 << 11) ++#define DISABLE_NYET (1 << 9) ++#define TEST_MODE (1 << 8) ++#define SIGNAL_RESUME (1 << 4) ++#define CHARGE_ENABLE (5 << 1) ++#define FORCE_FULLSPEED (1 << 0) ++ u8 _unused2[0x200-0x118]; ++ ++ /* offset: 0x200, 0x220, ..., 0x2e0 */ ++ struct iusbc_ep_regs ep[8]; ++} __attribute__ ((packed)); ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* DRIVER DATA STRUCTURES and UTILITIES */ ++ ++/* FIXME: for scatter/gather mode DMA */ ++struct iusbc_dma { ++ __le16 dmacount; ++ __le32 dmaaddr; /* the buffer */ ++ __le32 dmadesc; /* next dma descriptor */ ++ __le32 _reserved; ++} __attribute__ ((aligned (16))); ++ ++struct iusbc_ep { ++ struct usb_ep ep; ++ struct iusbc_dma *dummy; ++ dma_addr_t td_dma; /* of dummy */ ++ struct iusbc *dev; ++ unsigned long irqs; ++ ++ /* analogous to a host-side qh */ ++ struct list_head queue; ++ const struct usb_endpoint_descriptor *desc; ++ unsigned num : 8, ++ stopped : 1, ++ is_in : 1, ++ dma_mode : 2, ++ ep_type : 2; ++}; ++ ++struct iusbc_request { ++ struct usb_request req; ++ struct iusbc_dma *td; ++ dma_addr_t td_dma; ++ struct list_head queue; ++ unsigned mapped : 1, ++ valid : 1; ++}; ++ ++enum ep0state { ++ EP0_DISCONNECT, /* no host */ ++ EP0_IDLE, /* between STATUS ack and SETUP report */ ++ EP0_IN, EP0_OUT, /* data stage */ ++ EP0_STATUS, /* status stage */ ++ EP0_STALL, /* data or status stages */ ++ EP0_SUSPEND, /* usb suspend */ ++}; ++ ++struct iusbc { ++ /* each pci device provides one gadget, several endpoints */ ++ struct usb_gadget gadget; ++ spinlock_t lock; ++ struct iusbc_ep ep[8]; ++ struct usb_gadget_driver *driver; ++ enum ep0state ep0state; ++ unsigned ep_cap; ++ unsigned enabled : 1, ++ powered : 1, ++ enable_wakeup : 1, ++ force_fullspeed : 1, ++ rate : 1, ++ connected : 1, ++ suspended : 1, ++ got_irq : 1, ++ region : 1, ++ transfer_mode_dma : 1, ++ sg_mode_dma : 1, ++ linear_mode_dma : 1, ++ control_mode_dma : 1, ++ is_reset : 1; ++ ++ /* pci state used to access those endpoints */ ++ struct pci_dev *pdev; ++ struct iusbc_regs __iomem *regs; ++ struct pci_pool *requests; ++ ++ /* statistics... */ ++ unsigned long irqs; ++ ++ /* 16 bits status data for GET_STATUS */ ++ __le16 status_d; ++ ++ /* device irq tasklet */ ++ struct tasklet_struct iusbc_tasklet; ++ ++ /* interrupt status register value */ ++ volatile u32 int_sts; ++}; ++ +diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c +index db1b2bf..d6b7a83 100644 +--- a/drivers/usb/gadget/rndis.c ++++ b/drivers/usb/gadget/rndis.c +@@ -40,7 +40,7 @@ + + #undef RNDIS_PM + #undef RNDIS_WAKEUP +-#undef VERBOSE ++#define VERBOSE + + #include "rndis.h" + +@@ -52,14 +52,14 @@ + * and will be happier if you provide the host_addr module parameter. + */ + +-#if 0 ++#if 1 + #define DBG(str,args...) do { \ + if (rndis_debug) \ + printk(KERN_DEBUG str , ## args ); \ + } while (0) +-static int rndis_debug = 0; ++static int rndis_debug = 2; + +-module_param (rndis_debug, int, 0); ++module_param (rndis_debug, int, S_IRUGO|S_IWUSR); + MODULE_PARM_DESC (rndis_debug, "enable debugging"); + + #else +@@ -586,12 +586,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, + case OID_802_3_MAXIMUM_LIST_SIZE: + DBG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); + /* Multicast base address only */ +- *outbuf = __constant_cpu_to_le32 (1); ++ *outbuf = __constant_cpu_to_le32 (32); + retval = 0; + break; + + case OID_802_3_MAC_OPTIONS: + DBG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__); ++ *outbuf = __constant_cpu_to_le32 (0); ++ retval = 0; + break; + + /* ieee802.3 statistics OIDs (table 4-4) */ +@@ -898,7 +900,7 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf) + + static int rndis_set_response (int configNr, rndis_set_msg_type *buf) + { +- u32 BufLength, BufOffset; ++ u32 BufLength, BufOffset, i; + rndis_set_cmplt_type *resp; + rndis_resp_t *r; + --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0021-legacy-usb-int-fix.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0021-legacy-usb-int-fix.patch @@ -0,0 +1,54 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c +index c225159..b71f504 100644 +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -51,6 +51,17 @@ + #define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ + #define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */ + ++void uhci_clear_usb_int(unsigned long base) ++{ ++ outw(UHCI_USBCMD_HCRESET, base + UHCI_USBCMD); ++ mb(); ++ udelay(5); ++ outw(0, base + UHCI_USBINTR); ++ outw(0, base + UHCI_USBCMD); ++ mb(); ++ return; ++} ++EXPORT_SYMBOL (uhci_clear_usb_int); + + /* + * Make sure the controller is completely inactive, unable to +diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c +index ec98789..0c2b47d 100644 +--- a/drivers/usb/host/uhci-hcd.c ++++ b/drivers/usb/host/uhci-hcd.c +@@ -898,6 +898,18 @@ static const struct pci_device_id uhci_pci_ids[] = { { + + MODULE_DEVICE_TABLE(pci, uhci_pci_ids); + ++extern void uhci_clear_usb_int(unsigned long base); ++static int usb_hcd_resume_early(struct pci_dev *dev) ++{ ++ struct usb_hcd *hcd; ++ struct uhci_hcd *uhci; ++ ++ hcd = pci_get_drvdata(dev); ++ uhci = hcd_to_uhci(hcd); ++ uhci_clear_usb_int(uhci->io_addr); ++ return 0; ++} ++ + static struct pci_driver uhci_pci_driver = { + .name = (char *)hcd_name, + .id_table = uhci_pci_ids, +@@ -907,6 +919,7 @@ static struct pci_driver uhci_pci_driver = { + .shutdown = uhci_shutdown, + + #ifdef CONFIG_PM ++ .resume_early = usb_hcd_resume_early, + .suspend = usb_hcd_pci_suspend, + .resume = usb_hcd_pci_resume, + #endif /* PM */ --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0010-hda_sigmatel.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0010-hda_sigmatel.patch @@ -0,0 +1,379 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c +index 0401223..18bd160 100644 +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -34,6 +34,9 @@ + #include "hda_codec.h" + #include "hda_local.h" + ++#define dbg(f, x...) \ ++ printk(KERN_ALERT " [%s()]: " f "\n", __func__,## x) ++ + #define NUM_CONTROL_ALLOC 32 + #define STAC_HP_EVENT 0x37 + +@@ -54,6 +57,12 @@ enum { + }; + + enum { ++ STAC_9202_REF, ++ STAC_9202_TEST1, ++ STAC_9202_MODELS ++}; ++ ++enum { + STAC_9205_REF, + STAC_9205_DELL_M42, + STAC_9205_DELL_M43, +@@ -171,16 +180,32 @@ static hda_nid_t stac9200_dac_nids[1] = { + 0x02, + }; + ++static hda_nid_t stac9202_adc_nids[1] = { ++ 0x03, ++}; ++ ++static hda_nid_t stac9202_mux_nids[1] = { ++ 0x0f, ++}; ++ ++static hda_nid_t stac9202_dac_nids[1] = { ++ 0x02, ++}; ++ ++static hda_nid_t stac9202_dmic_nids[2] = { ++ 0x15, 0 ++}; ++ + static hda_nid_t stac925x_adc_nids[1] = { +- 0x03, ++ 0x03, + }; + + static hda_nid_t stac925x_mux_nids[1] = { +- 0x0f, ++ 0x0f, + }; + + static hda_nid_t stac925x_dac_nids[1] = { +- 0x02, ++ 0x02, + }; + + #define STAC925X_NUM_DMICS 1 +@@ -222,6 +247,11 @@ static hda_nid_t stac9200_pin_nids[8] = { + 0x0f, 0x10, 0x11, 0x12, + }; + ++static hda_nid_t stac9202_pin_nids[9] = { ++ 0x07, 0x08, 0x0a, 0x0d, ++ 0x0c, 0x0b, 0x10, 0x11, 0x15, ++}; ++ + static hda_nid_t stac925x_pin_nids[8] = { + 0x07, 0x08, 0x0a, 0x0b, + 0x0c, 0x0d, 0x10, 0x11, +@@ -354,6 +384,35 @@ static struct hda_verb stac9200_eapd_init[] = { + {} + }; + ++static struct hda_verb stac9202_core_init[] = { ++ /* set dac0mux for dac converter */ ++ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ {} ++}; ++ ++/* NID 6, the DAC mux, is set to 0, which forces it to uses NID 2 as its input; ++ Not the loopbacks from either the analog (NID 14) nor stereo (NID 7) inputs. ++ ++ NID 15, the DMIC input, has its widget control set to 0x20, which enables it's ++ output into the Azalia link, not the Analog input ++ ++ NID 7, the SPDIF IN pin, set for EAPD; set power amplifier on */ ++ ++static struct hda_verb stac9202_test1_init[] = { ++ /* set dac0mux for dac converter */ ++ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ /* Set pin widgets */ ++ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, ++ /* Set EAPD on SPDIF IN for amp on */ ++ { 0x07, AC_VERB_SET_EAPD_BTLENABLE , 0x02}, ++ /* Set Input MUX for digital input */ ++ { 0x14, AC_VERB_SET_CONNECT_SEL, 0x01}, ++ /* Unmute the Input MUX */ ++ { 0x14, 0x390, 0x00}, ++ { 0x14, 0x3a0, 0x00}, ++ {} ++}; ++ + static struct hda_verb stac925x_core_init[] = { + /* set dac0mux for dac converter */ + { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, +@@ -419,6 +478,60 @@ static struct snd_kcontrol_new stac9200_mixer[] = { + { } /* end */ + }; + ++static struct snd_kcontrol_new stac9202_mixer[] = { ++ HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input Source", ++ .count = 1, ++ .info = stac92xx_mux_enum_info, ++ .get = stac92xx_mux_enum_get, ++ .put = stac92xx_mux_enum_put, ++ }, ++/* ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Digital Input Source", ++ .count = 1, ++ .info = stac92xx_dmux_enum_info, ++ .get = stac92xx_dmux_enum_get, ++ .put = stac92xx_dmux_enum_put, ++ }, ++*/ ++ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), ++ HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), ++ { } /* end */ ++}; ++ ++static struct snd_kcontrol_new stac9202_test1_mixer[] = { ++ HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input Source", ++ .count = 1, ++ .info = stac92xx_mux_enum_info, ++ .get = stac92xx_mux_enum_get, ++ .put = stac92xx_mux_enum_put, ++ }, ++/* ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Digital Input Source", ++ .count = 1, ++ .info = stac92xx_dmux_enum_info, ++ .get = stac92xx_dmux_enum_get, ++ .put = stac92xx_dmux_enum_put, ++ }, ++*/ ++ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), ++ HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), ++ { } /* end */ ++}; ++ + static struct snd_kcontrol_new stac925x_mixer[] = { + STAC_INPUT_SOURCE(1), + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), +@@ -628,6 +741,30 @@ static unsigned int dell9200_m27_pin_configs[8] = { + }; + + ++static unsigned int ref9202_pin_configs[9] = { ++ 0x01c10014, 0x01410013, 0x01210011, 0x01010012, ++ 0x01810022, 0x01a10021, 0x01010031, 0x01310023, 0x01d10024, ++}; ++ ++static unsigned int test19202_pin_configs[9] = { ++ ++ 0x01c100f4, 0x014100f3, 0x01010012, 0x01210011, ++ 0x01210013, 0x01a10023, 0x01010031, 0x01310015, 0x01d10024, ++ ++/* ++ ++ 0x01c100f4, 0x014100f3, 0x01010012, 0x01010011, ++ 0x01810013, 0x01a10023, 0x01010031, 0x01310015, 0x01d10024, ++ ++ 0x01c10014, 0x01410013, 0x01210011, 0x01010012, ++ 0x01810022, 0x01a10021, 0x01010031, 0x01310023, 0x01d10024, ++ ++ 0x70fff100, 0x70fff100, 0x9717f11f, 0x03214011, ++ 0x01810022, 0x01a10021, 0x01010031, 0x01310023, 0x97a00120, ++*/ ++ ++}; ++ + static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { + [STAC_REF] = ref9200_pin_configs, + [STAC_9200_DELL_D21] = dell9200_d21_pin_configs, +@@ -657,6 +794,16 @@ static const char *stac9200_models[STAC_9200_MODELS] = { + [STAC_9200_GATEWAY] = "gateway", + }; + ++static unsigned int *stac9202_brd_tbl[STAC_9202_MODELS] = { ++ [STAC_REF] = ref9202_pin_configs, ++ [STAC_9202_TEST1] = test19202_pin_configs, ++}; ++ ++static const char *stac9202_models[STAC_9202_MODELS] = { ++ [STAC_REF] = "ref", ++ [STAC_9202_TEST1] = "test1", ++}; ++ + static struct snd_pci_quirk stac9200_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, +@@ -731,6 +878,14 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { + {} /* terminator */ + }; + ++static struct snd_pci_quirk stac9202_cfg_tbl[] = { ++ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, ++ "Stac 9202 Ref Config", STAC_REF), ++ SND_PCI_QUIRK(0x8384, 0x7632, ++ "Stac 9202 Test 1", STAC_9202_TEST1), ++ {} ++}; ++ + static unsigned int ref925x_pin_configs[8] = { + 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, + 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e, +@@ -2178,6 +2333,37 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) + return 1; + } + ++static int stac9202_parse_auto_config(struct hda_codec *codec) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ int err; ++ ++ if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) ++ return err; ++ ++ if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) ++ return err; ++ ++ if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0) ++ return err; ++ ++ if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0) ++ return err; ++ ++ if (spec->autocfg.dig_out_pin) ++ spec->multiout.dig_out_nid = 0x05; ++ if (spec->autocfg.dig_in_pin) ++ spec->dig_in_nid = 0x04; ++ ++ if (spec->kctl_alloc) ++ spec->mixers[spec->num_mixers++] = spec->kctl_alloc; ++ ++ spec->input_mux = &spec->private_imux; ++ spec->dinput_mux = &spec->private_dimux; ++ ++ return 1; ++} ++ + /* + * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a + * funky external mute control using GPIO pins. +@@ -2478,7 +2664,7 @@ static int patch_stac9200(struct hda_codec *codec) + return 0; + } + +-static int patch_stac925x(struct hda_codec *codec) ++static int patch_stac9202(struct hda_codec *codec) + { + struct sigmatel_spec *spec; + int err; +@@ -2488,6 +2674,75 @@ static int patch_stac925x(struct hda_codec *codec) + return -ENOMEM; + + codec->spec = spec; ++ spec->num_pins = 9; ++ spec->pin_nids = stac9202_pin_nids; ++ spec->board_config = snd_hda_check_board_config(codec, STAC_9202_MODELS, ++ stac9202_models, ++ stac9202_cfg_tbl); ++ if (spec->board_config < 0) { ++ snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9202, using BIOS defaults\n"); ++ err = stac92xx_save_bios_config_regs(codec); ++ if (err < 0) { ++ stac92xx_free(codec); ++ return err; ++ } ++ spec->pin_configs = spec->bios_pin_configs; ++ } else { ++ spec->pin_configs = stac9202_brd_tbl[spec->board_config]; ++ stac92xx_set_config_regs(codec); ++ } ++ ++ switch (spec->board_config) { ++ case STAC_9202_TEST1: ++ snd_printdd(KERN_INFO "here in test1 %x\n", spec->board_config); ++ spec->multiout.max_channels = 2; ++ spec->multiout.num_dacs = 1; ++ spec->multiout.dac_nids = stac9202_dac_nids; ++ spec->adc_nids = stac9202_adc_nids; ++ spec->mux_nids = stac9202_mux_nids; ++ spec->dmic_nids = stac9202_dmic_nids; ++ spec->num_dmics = 1; ++ spec->num_muxes = 1; ++ spec->init = stac9202_test1_init; ++ spec->mixer = stac9202_test1_mixer; ++ break; ++ default: ++ snd_printdd(KERN_INFO "here in default %x\n", spec->board_config); ++ spec->multiout.max_channels = 2; ++ spec->multiout.num_dacs = 1; ++ spec->multiout.dac_nids = stac9202_dac_nids; ++ spec->adc_nids = stac9202_adc_nids; ++ spec->mux_nids = stac9202_mux_nids; ++ spec->dmic_nids = stac9202_dmic_nids; ++ spec->num_muxes = 1; ++ spec->num_dmics = 1; ++ spec->init = stac9202_core_init; ++ spec->mixer = stac9202_mixer; ++ } ++ ++ err = stac9202_parse_auto_config(codec); ++ if (err < 0) { ++ stac92xx_free(codec); ++ return err; ++ } ++ ++ codec->patch_ops = stac92xx_patch_ops; ++ ++ return 0; ++} ++ ++ ++ ++static int patch_stac925x(struct hda_codec *codec) ++{ ++ struct sigmatel_spec *spec; ++ int err; ++ ++ spec = kzalloc(sizeof(*spec), GFP_KERNEL); ++ if (spec == NULL) ++ return -ENOMEM; ++ ++ codec->spec = spec; + spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); + spec->pin_nids = stac925x_pin_nids; + spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS, +@@ -2530,7 +2785,7 @@ static int patch_stac925x(struct hda_codec *codec) + + spec->init = stac925x_core_init; + spec->mixer = stac925x_mixer; +- ++ + err = stac92xx_parse_auto_config(codec, 0x8, 0x7); + if (!err) { + if (spec->board_config < 0) { +@@ -3083,8 +3338,8 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { + { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, + { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, + { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, +- { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x }, +- { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x }, ++ { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac9202 }, ++ { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac9202 }, + { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x }, + { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x }, + { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x }, --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0018-sdio_crown_beach.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0018-sdio_crown_beach.patch @@ -0,0 +1,149 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c +index b966674..17d1d16 100644 +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -645,6 +645,10 @@ void mmc_rescan(struct work_struct *work) + mmc_claim_host(host); + + mmc_power_up(host); ++ ++ /* add a 25ms delay for SiB workaround */ ++ mmc_delay(25); ++ + mmc_go_idle(host); + + mmc_send_if_cond(host, host->ocr_avail); +diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c +index d5e51b1..962b8be 100644 +--- a/drivers/mmc/core/sdio_cis.c ++++ b/drivers/mmc/core/sdio_cis.c +@@ -151,7 +151,8 @@ static int cistpl_funce(struct mmc_card *card, struct sdio_func *func, + if (ret) { + printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u " + "type %u\n", mmc_hostname(card->host), size, buf[0]); +- return ret; ++ /* masked by feng for 8688 + CB debug . */ ++ /* return ret; */ + } + + return 0; +diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c +index 87a50f4..ba2a699 100644 +--- a/drivers/mmc/core/sdio.c ++++ b/drivers/mmc/core/sdio.c +@@ -332,6 +332,12 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) + if (err) + goto remove; + ++ /* add a workaround for Marvell SDIO dev */ ++ if (card->cis.vendor == 0x2df) { ++ if (card->cis.max_dtr >= 25000000) ++ card->cis.max_dtr = 25000000; ++ } ++ + /* + * No support for high-speed yet, so just set + * the card's maximum speed. +diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c +index 625b92c..f4c62c0 100644 +--- a/drivers/mmc/core/sdio_io.c ++++ b/drivers/mmc/core/sdio_io.c +@@ -546,3 +546,72 @@ void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, + *err_ret = ret; + } + EXPORT_SYMBOL_GPL(sdio_f0_writeb); ++ ++static char* sdio_version[4] = { ++ "version 1.00", ++ "version 1.10", ++ "version 1.20", ++ "version 2.00" ++}; ++ ++static char* sd_phy_version[4] = { ++ "version 1.01", ++ "version 1.10", ++ "version 2.00" ++}; ++ ++void sdio_dump_cccr(struct sdio_func *func) ++{ ++ struct mmc_card *card = func->card; ++ u8 data, val; ++ u8 *str; ++ int i; ++ ++ printk(KERN_INFO "\nStart to dump SDIO CCCR registers:\n"); ++ ++ /* dump sdio version */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); ++ val = (data >> 4) & 0xf; ++ if (val <= 3) ++ printk(KERN_INFO "SDIO Spec: %s\n", sdio_version[val]); ++ else ++ printk(KERN_INFO "This card doesn't comply with any SDIO spec version!!\n"); ++ ++ /* dump sd PHY version */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SD, 0, &data); ++ val = data & 0xf; ++ if (val <= 2) ++ printk(KERN_INFO "SD PHY spec: %s\n", sd_phy_version[val]); ++ else ++ printk(KERN_INFO "This card doesn't comply with any SD PHY spec version!!\n"); ++ ++ /* dump IO Enalbe reg */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IOEx, 0, &data); ++ printk(KERN_INFO "IO Enable Reg: 0x%02x\n", data); ++ ++ /* dump IO Ready reg */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IORx, 0, &data); ++ printk(KERN_INFO "IO Ready Reg: 0x%02x\n", data); ++ ++ /* dump INT Enable reg */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IENx, 0, &data); ++ printk(KERN_INFO "INT Enable Reg: 0x%02x\n", data); ++ ++ /* dump INT Pending reg */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &data); ++ printk(KERN_INFO "INT Pending Reg: 0x%02x\n", data); ++ ++ /* dump Bus Interface reg */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &data); ++ val = data & 0x3; ++ printk(KERN_INFO "Bus Width: %d bit\n", (val ? 4 : 1)); ++ ++ /* dump capability reg */ ++ mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data); ++ printk(KERN_INFO "Multi-Block support: %s\n", (data & SDIO_CCCR_CAP_SMB) ? "YES" : "NO"); ++ printk(KERN_INFO "Suspend/Resume support: %s\n", (data & SDIO_CCCR_CAP_SBS) ? "YES" : "NO"); ++ printk(KERN_INFO "Low Speed Card: %s\n", (data & SDIO_CCCR_CAP_LSC) ? "YES" : "NO"); ++ printk(KERN_INFO "4 bits Low Speed Card: %s\n", (data & SDIO_CCCR_CAP_4BLS) ? "YES" : "NO"); ++} ++EXPORT_SYMBOL_GPL(sdio_dump_cccr); ++ +diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h +index d0c3abe..a5f4bd3 100644 +--- a/include/linux/mmc/core.h ++++ b/include/linux/mmc/core.h +@@ -150,4 +150,20 @@ static inline void mmc_claim_host(struct mmc_host *host) + __mmc_claim_host(host, NULL); + } + ++/* feng add for temply use */ ++#define DBG_2622 1 ++ ++#ifdef DBG_2622 ++#define umd_dbg(f, x...) \ ++ printk(KERN_INFO "[%s()]: " f "\n", __func__,##x) ++#define umd_enter() \ ++ printk(KERN_INFO "[%s()]: enter\n", __func__) ++#define umd_exit() \ ++ printk(KERN_INFO "[%s()]: exit\n", __func__) ++#else ++#define umd_dbg(f, x...) do{} while(0) ++#define umd_enter() do{} while(0) ++#define umd_exit() do{} while(0) ++#endif /* end of DBG_2622 */ ++ + #endif --- linux-2.6.24.orig/debian/binary-custom.d/lpia/patchset/0015-poulsbo_smbus.patch +++ linux-2.6.24/debian/binary-custom.d/lpia/patchset/0015-poulsbo_smbus.patch @@ -0,0 +1,432 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index c466c6c..85abf0a 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -239,6 +239,15 @@ config I2C_PIIX4 + This driver can also be built as a module. If so, the module + will be called i2c-piix4. + ++config I2C_POULSBO ++ tristate "Intel SCH (Poulsbo SMBUS 1.0)" ++ depends on I2C && PCI ++ help ++ If you say yes to this option, support will be included for the Intel ++ SCH ++ Intel POULSBO ++ will be called i2c-sch. ++ + config I2C_IBM_IIC + tristate "IBM PPC 4xx on-chip I2C interface" + depends on IBM_OCP +diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +index 81d43c2..ece538a 100644 +--- a/drivers/i2c/busses/Makefile ++++ b/drivers/i2c/busses/Makefile +@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o + obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o + obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o + obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o ++obj-$(CONFIG_I2C_POULSBO) += i2c-sch.o + obj-$(CONFIG_I2C_PNX) += i2c-pnx.o + obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o + obj-$(CONFIG_I2C_PXA) += i2c-pxa.o +diff --git a/drivers/i2c/busses/i2c-sch.c b/drivers/i2c/busses/i2c-sch.c +new file mode 100644 +index 0000000..8940362 +--- /dev/null ++++ b/drivers/i2c/busses/i2c-sch.c +@@ -0,0 +1,393 @@ ++/* ++ i2c-sch.c - Part of lm_sensors, Linux kernel modules for hardware ++ monitoring ++ Based on piix4.c ++ Copyright (c) 1998 - 2002 Frodo Looijaard and ++ Philip Edelbrock ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++/* ++ Supports: ++ Intel POULSBO ++ ++ Note: we assume there can only be one device, with one SMBus interface. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++struct sd { ++ const unsigned short mfr; ++ const unsigned short dev; ++ const unsigned char fn; ++ const char *name; ++}; ++/* POULSBO SMBus address offsets */ ++#define SMBHSTCNT (0 + poulsbo_smba) ++#define SMBHSTSTS (1 + poulsbo_smba) ++#define SMBHSTADD (4 + poulsbo_smba) /* TSA */ ++#define SMBHSTCMD (5 + poulsbo_smba) ++#define SMBHSTDAT0 (6 + poulsbo_smba) ++#define SMBHSTDAT1 (7 + poulsbo_smba) ++#define SMBBLKDAT (0x20 + poulsbo_smba) ++ ++ ++/* count for request_region */ ++#define SMBIOSIZE 8 ++ ++/* PCI Address Constants */ ++#define SMBBA_SCH 0x040 ++ ++/* Other settings */ ++#define MAX_TIMEOUT 500 ++#define ENABLE_INT9 0 ++ ++/* POULSBO constants */ ++#define POULSBO_QUICK 0x00 ++#define POULSBO_BYTE 0x01 ++#define POULSBO_BYTE_DATA 0x02 ++#define POULSBO_WORD_DATA 0x03 ++#define POULSBO_BLOCK_DATA 0x05 ++ ++/* insmod parameters */ ++ ++/* If force is set to anything different from 0, we forcibly enable the ++ POULSBO. DANGEROUS! */ ++static int force; ++module_param (force, int, 0); ++MODULE_PARM_DESC(force, "Forcibly enable the POULSBO. DANGEROUS!"); ++ ++ ++static int poulsbo_transaction(void); ++ ++static unsigned short poulsbo_smba; ++static struct pci_driver poulsbo_driver; ++static struct i2c_adapter poulsbo_adapter; ++ ++ ++static int __devinit poulsbo_setup(struct pci_dev *POULSBO_dev, ++ const struct pci_device_id *id) ++{ ++ unsigned short smbase; ++ if(POULSBO_dev->device != PCI_DEVICE_ID_INTEL_POULSBO_LPC) { ++ /* match up the function */ ++ if (PCI_FUNC(POULSBO_dev->devfn) != id->driver_data) ++ return -ENODEV; ++ dev_info(&POULSBO_dev->dev, "Found %s device\n", pci_name(POULSBO_dev)); ++ } else { ++ dev_info(&POULSBO_dev->dev, "Found POULSBO SMBUS %s device\n", pci_name(POULSBO_dev)); ++ /* find SMBUS base address */ ++ pci_read_config_word(POULSBO_dev, 0x40, &smbase); ++ dev_info(&POULSBO_dev->dev, "POULSBO SM base = 0x%04x\n", smbase); ++ } ++ ++ ++ /* Determine the address of the SMBus areas */ ++ if(POULSBO_dev->device == PCI_DEVICE_ID_INTEL_POULSBO_LPC) ++ pci_read_config_word(POULSBO_dev, SMBBA_SCH, &poulsbo_smba); ++ else ++ poulsbo_smba=0; ++ ++ poulsbo_smba &= 0xfff0; ++ if(poulsbo_smba == 0) { ++ dev_err(&POULSBO_dev->dev, "SMB base address " ++ "uninitialized - upgrade BIOS or use " ++ "force_addr=0xaddr\n"); ++ return -ENODEV; ++ } ++ ++ if (!request_region(poulsbo_smba, SMBIOSIZE, poulsbo_driver.name)) { ++ dev_err(&POULSBO_dev->dev, "SMB region 0x%x already in use!\n", ++ poulsbo_smba); ++ return -ENODEV; ++ } ++ ++ dev_dbg(&POULSBO_dev->dev, "SMBA = 0x%X\n", poulsbo_smba); ++ ++ return 0; ++} ++ ++/* Another internally used function */ ++static int poulsbo_transaction(void) ++{ ++ int temp; ++ int result = 0; ++ int timeout = 0; ++ ++ dev_dbg(&poulsbo_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " ++ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), ++ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), ++ inb_p(SMBHSTDAT1)); ++ ++ /* Make sure the SMBus host is ready to start transmitting */ ++ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { ++ if(temp == 1) { ++ dev_dbg(&poulsbo_adapter.dev, "Completion (%02x). " ++ "clear...\n", temp); ++ outb_p(temp, SMBHSTSTS); ++ ++ } else if(temp & 0xe) { ++ dev_dbg(&poulsbo_adapter.dev, "SMBus error (%02x). " ++ "Resetting...\n", temp); ++ outb_p(temp, SMBHSTSTS); ++ } ++ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { ++ dev_err(&poulsbo_adapter.dev, "Failed! (%02x)\n", temp); ++ return -1; ++ } else { ++ dev_dbg(&poulsbo_adapter.dev, "Successfull!\n"); ++ } ++ } ++ ++ /* start the transaction by setting bit 4 */ ++ outb_p(inb(SMBHSTCNT) | 0x10, SMBHSTCNT); ++ ++ /* We will always wait for a fraction of a second! (See POULSBO docs errata) */ ++ do { ++ msleep(1); ++ temp = inb_p(SMBHSTSTS); ++ } while ((temp & 0x08) && (timeout++ < MAX_TIMEOUT)); ++ ++ /* If the SMBus is still busy, we give up */ ++ if (timeout >= MAX_TIMEOUT) { ++ dev_err(&poulsbo_adapter.dev, "SMBus Timeout!\n"); ++ result = -1; ++ } ++ ++ if (temp & 0x10) { ++ result = -1; ++ dev_err(&poulsbo_adapter.dev, "Error: Failed bus transaction\n"); ++ } ++ ++ if (temp & 0x08) { ++ result = -1; ++ dev_dbg(&poulsbo_adapter.dev, "Bus collision! SMBus may be " ++ "locked until next hard reset. (sorry!)\n"); ++ /* Clock stops and slave is stuck in mid-transmission */ ++ } ++ ++ if (temp & 0x04) { ++ result = -1; ++ dev_dbg(&poulsbo_adapter.dev, "Error: no response!\n"); ++ } ++ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { ++ if( temp == 0x1) { ++ dev_dbg(&poulsbo_adapter.dev, "post complete!\n"); ++ outb_p(temp, SMBHSTSTS); ++ } ++ else if(temp & 0xe) { ++ dev_dbg(&poulsbo_adapter.dev, "Error: bus, etc!\n"); ++ outb_p(inb(SMBHSTSTS), SMBHSTSTS); ++ } ++ } ++ msleep(1); ++ if ((temp = inb_p(SMBHSTSTS)) & 0xe) { ++ /* BSY, device or bus error */ ++ dev_err(&poulsbo_adapter.dev, "Failed reset at end of " ++ "transaction (%02x), Bus error\n", temp); ++ } ++ dev_dbg(&poulsbo_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " ++ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), ++ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), ++ inb_p(SMBHSTDAT1)); ++ return result; ++} ++ ++/* Return -1 on error. */ ++static s32 poulsbo_access(struct i2c_adapter * adap, u16 addr, ++ unsigned short flags, char read_write, ++ u8 command, int size, union i2c_smbus_data * data) ++{ ++ int i, len; ++ dev_dbg(&poulsbo_adapter.dev,"access size: %d %s\n", size, (read_write)?"READ":"WRITE"); ++ switch (size) { ++ case I2C_SMBUS_PROC_CALL: ++ dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); ++ return -1; ++ case I2C_SMBUS_QUICK: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD); ++ size = POULSBO_QUICK; ++ break; ++ case I2C_SMBUS_BYTE: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD); ++ if (read_write == I2C_SMBUS_WRITE) ++ outb_p(command, SMBHSTCMD); ++ size = POULSBO_BYTE; ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD); ++ outb_p(command, SMBHSTCMD); ++ if (read_write == I2C_SMBUS_WRITE) ++ outb_p(data->byte, SMBHSTDAT0); ++ size = POULSBO_BYTE_DATA; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD); ++ outb_p(command, SMBHSTCMD); ++ if (read_write == I2C_SMBUS_WRITE) { ++ outb_p(data->word & 0xff, SMBHSTDAT0); ++ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); ++ } ++ size = POULSBO_WORD_DATA; ++ break; ++ case I2C_SMBUS_BLOCK_DATA: ++ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), ++ SMBHSTADD); ++ outb_p(command, SMBHSTCMD); ++ if (read_write == I2C_SMBUS_WRITE) { ++ len = data->block[0]; ++ if (len < 0) ++ len = 0; ++ if (len > 32) ++ len = 32; ++ outb_p(len, SMBHSTDAT0); ++ i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ ++ for (i = 1; i <= len; i++) ++ outb_p(data->block[i], SMBBLKDAT); ++ } ++ size = POULSBO_BLOCK_DATA; ++ break; ++ } ++ dev_dbg(&poulsbo_adapter.dev,"write size %d to 0x%04x\n", size, SMBHSTCNT); ++ outb_p((size & 0x7), SMBHSTCNT); ++ ++ if (poulsbo_transaction()) /* Error in transaction */ ++ return -1; ++ ++ if ((read_write == I2C_SMBUS_WRITE) || (size == POULSBO_QUICK)) ++ return 0; ++ ++ ++ switch (size) { ++ case POULSBO_BYTE: /* Where is the result put? I assume here it is in ++ SMBHSTDAT0 but it might just as well be in the ++ SMBHSTCMD. No clue in the docs */ ++ ++ data->byte = inb_p(SMBHSTDAT0); ++ break; ++ case POULSBO_BYTE_DATA: ++ data->byte = inb_p(SMBHSTDAT0); ++ break; ++ case POULSBO_WORD_DATA: ++ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); ++ break; ++ case POULSBO_BLOCK_DATA: ++ data->block[0] = inb_p(SMBHSTDAT0); ++ i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ ++ for (i = 1; i <= data->block[0]; i++) ++ data->block[i] = inb_p(SMBBLKDAT); ++ break; ++ } ++ return 0; ++} ++ ++static u32 poulsbo_func(struct i2c_adapter *adapter) ++{ ++ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | ++ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | ++ I2C_FUNC_SMBUS_BLOCK_DATA; ++} ++ ++static const struct i2c_algorithm smbus_algorithm = { ++ .smbus_xfer = poulsbo_access, ++ .functionality = poulsbo_func, ++}; ++ ++static struct i2c_adapter poulsbo_adapter = { ++ .owner = THIS_MODULE, ++ .class = I2C_CLASS_HWMON, ++ .algo = &smbus_algorithm, ++}; ++ ++static struct pci_device_id poulsbo_ids[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_POULSBO_LPC), ++ .driver_data = 0xf8 }, ++ { 0, } ++}; ++ ++MODULE_DEVICE_TABLE (pci, poulsbo_ids); ++ ++static int __devinit poulsbo_probe(struct pci_dev *dev, ++ const struct pci_device_id *id) ++{ ++ int retval; ++ retval = poulsbo_setup(dev, id); ++ if (retval) ++ return retval; ++ ++ /* set up the driverfs linkage to our parent device */ ++ poulsbo_adapter.dev.parent = &dev->dev; ++ ++ snprintf(poulsbo_adapter.name, I2C_NAME_SIZE, ++ "SMBus POULSBO adapter at %04x", poulsbo_smba); ++ ++ if ((retval = i2c_add_adapter(&poulsbo_adapter))) { ++ dev_err(&dev->dev, "Couldn't register adapter!\n"); ++ release_region(poulsbo_smba, SMBIOSIZE); ++ poulsbo_smba = 0; ++ } ++ ++ return retval; ++} ++ ++static void __devexit poulsbo_remove(struct pci_dev *dev) ++{ ++ if (poulsbo_smba) { ++ i2c_del_adapter(&poulsbo_adapter); ++ release_region(poulsbo_smba, SMBIOSIZE); ++ poulsbo_smba = 0; ++ } ++} ++ ++static struct pci_driver poulsbo_driver = { ++ .name = "poulsbo_smbus", ++ .id_table = poulsbo_ids, ++ .probe = poulsbo_probe, ++ .remove = __devexit_p(poulsbo_remove), ++}; ++ ++static int __init i2c_poulsbo_init(void) ++{ ++ return pci_register_driver(&poulsbo_driver); ++} ++ ++static void __exit i2c_poulsbo_exit(void) ++{ ++ pci_unregister_driver(&poulsbo_driver); ++} ++ ++MODULE_AUTHOR("Jacob Pan "); ++MODULE_DESCRIPTION("POULSBO SMBus driver"); ++MODULE_LICENSE("GPL"); ++ ++module_init(i2c_poulsbo_init); ++module_exit(i2c_poulsbo_exit); --- linux-2.6.24.orig/debian/binary-custom.d/lpiacompat/rules +++ linux-2.6.24/debian/binary-custom.d/lpiacompat/rules @@ -0,0 +1 @@ +# Nothing special here --- linux-2.6.24.orig/debian/binary-custom.d/lpiacompat/vars +++ linux-2.6.24/debian/binary-custom.d/lpiacompat/vars @@ -0,0 +1,7 @@ +arch="lpia" +supported="UME" +desc="Ubuntu Moblie and Embedded-x86 compat edition" +target="UME kernel" +bootloader="lilo (>= 19.1) | grub" +provides="kvm-api-4, redhat-cluster-modules" +section_image="universe/base" --- linux-2.6.24.orig/debian/binary-custom.d/lpiacompat/config.lpia +++ linux-2.6.24/debian/binary-custom.d/lpiacompat/config.lpia @@ -0,0 +1,4119 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.24-16-lpiacompat +# Wed Apr 9 03:44:05 2008 +# +# CONFIG_64BIT is not set +CONFIG_X86_32=y +# CONFIG_X86_64 is not set +CONFIG_X86=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_SEMAPHORE_SLEEPERS=y +CONFIG_MMU=y +CONFIG_ZONE_DMA=y +CONFIG_QUICKLIST=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_DMI=y +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME_VSYSCALL is not set +CONFIG_ARCH_SUPPORTS_OPROFILE=y +# CONFIG_ZONE_DMA32 is not set +CONFIG_ARCH_POPULATES_NODE_MAP=y +# CONFIG_AUDIT_ARCH is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_X86_SMP=y +CONFIG_X86_HT=y +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_TRAMPOLINE=y +CONFIG_KTIME_SCALAR=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_VERSION_SIGNATURE="Unofficial" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_TREE=y +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_CGROUPS is not set +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_FAIR_USER_SCHED=y +# CONFIG_FAIR_CGROUP_SCHED is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBD=y +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_LSM_MMAP_MIN_ADDR=0 + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_PREEMPT_NOTIFIERS=y + +# +# Processor type and features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_SMP=y +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_X86_VSMP is not set +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_GUEST=y +CONFIG_VMI=y +CONFIG_LGUEST_GUEST=y +# CONFIG_M386 is not set +# CONFIG_M486 is not set +CONFIG_M586=y +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MEFFICEON is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_GENERIC_CPU is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_XADD=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_F00F_BUG=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_MINIMUM_CPU_FAMILY=4 +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_NR_CPUS=8 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_BKL=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_MCE is not set +CONFIG_VM86=y +CONFIG_TOSHIBA=m +CONFIG_I8K=m +CONFIG_X86_REBOOTFIXUPS=y +CONFIG_MICROCODE=m +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_HIGHMEM=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_SPARSEMEM_STATIC=y +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_NR_QUICK=1 +CONFIG_VIRT_TO_BUS=y +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +CONFIG_EFI=y +# CONFIG_IRQBALANCE is not set +CONFIG_BOOT_IOREMAP=y +CONFIG_SECCOMP=y +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +CONFIG_PHYSICAL_START=0x100000 +CONFIG_RELOCATABLE=y +CONFIG_PHYSICAL_ALIGN=0x100000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_COMPAT_VDSO is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y + +# +# Power management options +# +CONFIG_PM=y +CONFIG_PM_LEGACY=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_VERBOSE is not set +CONFIG_PM_TRACE=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SUSPEND=y +CONFIG_PM_DISABLE_CONSOLE=y +CONFIG_HIBERNATION_SMP_POSSIBLE=y +CONFIG_HIBERNATION=y +CONFIG_PM_STD_PARTITION="" +CONFIG_THERMAL_SYSFS=m +CONFIG_ACPI=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_PROCFS=y +CONFIG_ACPI_PROCFS_POWER=y +CONFIG_ACPI_SYSFS_POWER=y +CONFIG_ACPI_PROC_EVENT=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_VIDEO=m +CONFIG_ACPI_FAN=m +CONFIG_ACPI_DOCK=m +CONFIG_ACPI_BAY=m +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_ACPI_CUSTOM_DSDT_INITRD=y +CONFIG_ACPI_BLACKLIST_YEAR=2000 +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y +CONFIG_ACPI_CONTAINER=m +CONFIG_ACPI_SBS=m +CONFIG_APM=m +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +# CONFIG_APM_CPU_IDLE is not set +# CONFIG_APM_DISPLAY_BLANK is not set +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=m +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=m +CONFIG_X86_POWERNOW_K7_ACPI=y +CONFIG_X86_POWERNOW_K8=m +CONFIG_X86_POWERNOW_K8_ACPI=y +CONFIG_X86_GX_SUSPMOD=m +CONFIG_X86_SPEEDSTEP_CENTRINO=m +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_ICH=m +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_CPUFREQ_NFORCE2=m +CONFIG_X86_LONGRUN=m +CONFIG_X86_LONGHAUL=m +# CONFIG_X86_E_POWERSAVER is not set + +# +# shared options +# +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_SPEEDSTEP_LIB=m +CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y + +# +# Bus options (PCI etc.) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_PCIEAER=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_LEGACY=y +# CONFIG_PCI_DEBUG is not set +CONFIG_HT_IRQ=y +CONFIG_ISA_DMA_API=y +CONFIG_ISA=y +CONFIG_EISA=y +CONFIG_EISA_VLB_PRIMING=y +CONFIG_EISA_PCI_EISA=y +CONFIG_EISA_VIRTUAL_ROOT=y +CONFIG_EISA_NAMES=y +CONFIG_MCA=y +CONFIG_MCA_LEGACY=y +# CONFIG_MCA_PROC_FS is not set +CONFIG_SCx200=m +CONFIG_SCx200HR_TIMER=m +CONFIG_K8_NB=y +CONFIG_PCCARD=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA=m +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y +CONFIG_CARDBUS=y + +# +# PC-card bridges +# +CONFIG_YENTA=m +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_PD6729=m +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_TCIC=m +CONFIG_PCMCIA_PROBE=y +CONFIG_PCCARD_NONSTATIC=m +CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI_FAKE=m +CONFIG_HOTPLUG_PCI_COMPAQ=m +CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM=y +CONFIG_HOTPLUG_PCI_IBM=m +CONFIG_HOTPLUG_PCI_ACPI=m +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m +CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +CONFIG_HOTPLUG_PCI_SHPC=m + +# +# Executable file formats / Emulations +# +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=m +CONFIG_BINFMT_MISC=m + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_LRO=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_TCP_MD5SIG=y +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_NETLABEL is not set +CONFIG_NETWORK_SECMARK=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m + +# +# IP: Netfilter Configuration +# +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_SIP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_RAW=m + +# +# DECnet: Netfilter Configuration +# +CONFIG_DECNET_NF_GRABULATOR=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_IP_DCCP_ACKVEC=y + +# +# DCCP CCIDs Configuration (EXPERIMENTAL) +# +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +CONFIG_IP_DCCP_TFRC_LIB=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 + +# +# DCCP Kernel Hacking +# +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_NET_DCCPPROBE=m +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +CONFIG_ATM=y +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_DECNET=m +# CONFIG_DECNET_ROUTER is not set +CONFIG_LLC=y +CONFIG_LLC2=m +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_LTPC=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RR=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +# CONFIG_NET_CLS_POLICE is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +CONFIG_NET_TCPPROBE=m +CONFIG_HAMRADIO=y + +# +# Packet Radio protocols +# +CONFIG_AX25=m +# CONFIG_AX25_DAMA_SLAVE is not set +CONFIG_NETROM=m +CONFIG_ROSE=m + +# +# AX.25 network device drivers +# +CONFIG_MKISS=m +CONFIG_6PACK=m +CONFIG_BPQETHER=m +CONFIG_SCC=m +# CONFIG_SCC_DELAY is not set +# CONFIG_SCC_TRXECHO is not set +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_EPP=m +CONFIG_YAM=m +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m +CONFIG_KINGSUN_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KS959_DONGLE=m + +# +# Old SIR device drivers +# + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +CONFIG_WINBOND_FIR=m +CONFIG_TOSHIBA_FIR=m +CONFIG_SMC_IRCC_FIR=m +CONFIG_ALI_FIR=m +CONFIG_VLSI_FIR=m +CONFIG_VIA_FIR=m +CONFIG_MCS_FIR=m +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_RXKAD=m +CONFIG_FIB_RULES=y + +# +# Wireless +# +CONFIG_CFG80211=m +CONFIG_NL80211=y +CONFIG_WIRELESS_EXT=y +CONFIG_MAC80211=m +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_DEBUGFS=y +# CONFIG_MAC80211_DEBUG is not set +CONFIG_IEEE80211=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_CRYPT_WEP=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +CONFIG_NET_9P=m +CONFIG_NET_9P_FD=m +CONFIG_NET_9P_VIRTIO=m +# CONFIG_NET_9P_DEBUG is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=m +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m +CONFIG_RFD_FTL=m +CONFIG_SSFDC=m +CONFIG_MTD_OOPS=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PNC2000=m +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_TS5500=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_DILNETPC=m +CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000 +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_PLATRAM=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_DATAFLASH=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTD_BLOCK2MTD=m + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCECC=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_IDS=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_CS553X=m +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_2X_PROGRAM=y +CONFIG_MTD_ONENAND_SIM=m + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +CONFIG_MTD_UBI_GLUEBI=y + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_AX88796=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_NOT_PC=y +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y +CONFIG_PNPBIOS=y +CONFIG_PNPBIOS_PROC_FS=y +CONFIG_PNPACPI=y + +# +# Sysfs device class support +# +CONFIG_SYSFS_DEV_CLASS=y +CONFIG_FAN_SYSFS=m +CONFIG_MEMORY_SYSFS=m +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_FD=m +CONFIG_BLK_DEV_XD=m +CONFIG_PARIDE=m + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_BPCK6=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_SX8=m +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_VIRTIO_BLK=m +CONFIG_MISC_DEVICES=y +CONFIG_IBM_ASM=m +CONFIG_PHANTOM=m +CONFIG_EEPROM_93CX6=m +CONFIG_SGI_IOC4=m +CONFIG_TIFM_CORE=m +CONFIG_TIFM_7XX1=m +CONFIG_ASUS_LAPTOP=m +CONFIG_FUJITSU_LAPTOP=m +CONFIG_MSI_LAPTOP=m +CONFIG_SONY_LAPTOP=m +CONFIG_SONYPI_COMPAT=y +CONFIG_THINKPAD_ACPI=m +# CONFIG_THINKPAD_ACPI_DEBUG is not set +CONFIG_THINKPAD_ACPI_BAY=y +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_BLK_DEV_IDEACPI=y +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +CONFIG_BLK_DEV_PLATFORM=m +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +CONFIG_BLK_DEV_IDEPNP=y + +# +# PCI IDE chipsets support +# +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_GENERIC is not set +CONFIG_BLK_DEV_OPTI621=m +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI15X3=m +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=m +CONFIG_BLK_DEV_ATIIXP=m +CONFIG_BLK_DEV_CMD64X=m +# CONFIG_BLK_DEV_TRIFLEX is not set +CONFIG_BLK_DEV_CY82C693=m +# CONFIG_BLK_DEV_CS5520 is not set +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_CS5535=m +CONFIG_BLK_DEV_HPT34X=m +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=m +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_SC1200=m +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +CONFIG_BLK_DEV_NS87415=m +CONFIG_BLK_DEV_PDC202XX_OLD=m +CONFIG_PDC202XX_BURST=y +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +CONFIG_BLK_DEV_TRM290=m +CONFIG_BLK_DEV_VIA82CXXX=m +CONFIG_BLK_DEV_TC86C001=m +# CONFIG_IDE_ARM is not set + +# +# Other IDE chipsets support +# + +# +# Note: most of these also require special kernel boot parameters +# +CONFIG_BLK_DEV_4DRIVES=y +CONFIG_BLK_DEV_ALI14XX=m +CONFIG_BLK_DEV_DTC2278=m +CONFIG_BLK_DEV_HT6560B=m +CONFIG_BLK_DEV_QD65XX=m +CONFIG_BLK_DEV_UMC8672=m +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=m +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=m +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SAS_ATA=y +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_7000FASST=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AHA1740=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_SCSI_AIC94XX=m +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_DTC3280=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_FD_MCS=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_GENERIC_NCR5380=m +CONFIG_SCSI_GENERIC_NCR5380_MMIO=m +CONFIG_SCSI_GENERIC_NCR53C400=y +CONFIG_SCSI_IBMMCA=m +CONFIG_IBMMCA_SCSI_ORDER_STANDARD=y +# CONFIG_IBMMCA_SCSI_DEV_RESET is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_NCR53C406A=m +CONFIG_SCSI_NCR_D700=m +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPR_DUMP is not set +CONFIG_SCSI_NCR_Q720=m +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 +CONFIG_SCSI_NCR53C8XX_SYNC=5 +CONFIG_SCSI_PAS16=m +CONFIG_SCSI_PSI240I=m +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_SEAGATE=m +CONFIG_SCSI_SIM710=m +CONFIG_SCSI_SYM53C416=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_T128=m +CONFIG_SCSI_U14_34F=m +CONFIG_SCSI_U14_34F_TAGGED_QUEUE=y +CONFIG_SCSI_U14_34F_LINKED_COMMANDS=y +CONFIG_SCSI_U14_34F_MAX_TAGS=8 +CONFIG_SCSI_ULTRASTOR=m +CONFIG_SCSI_NSP32=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_ATA=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_ACPI=y +CONFIG_SATA_AHCI=m +CONFIG_SATA_SVW=m +CONFIG_ATA_PIIX=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_PDC_ADMA=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_SX4=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SATA_INIC162X=m +CONFIG_PATA_ACPI=m +# CONFIG_PATA_ALI is not set +CONFIG_PATA_AMD=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +# CONFIG_PATA_CMD640_PCI is not set +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CS5520=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +CONFIG_PATA_CS5536=m +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +CONFIG_ATA_GENERIC=m +CONFIG_PATA_HPT366=m +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +CONFIG_PATA_HPT3X3=m +# CONFIG_PATA_HPT3X3_DMA is not set +# CONFIG_PATA_ISAPNP is not set +CONFIG_PATA_IT821X=m +CONFIG_PATA_IT8213=m +CONFIG_PATA_JMICRON=m +# CONFIG_PATA_LEGACY is not set +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_NETCELL=m +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PCMCIA=m +# CONFIG_PATA_PDC_OLD is not set +CONFIG_PATA_QDI=m +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +# CONFIG_PATA_WINBOND_VLB is not set +CONFIG_PATA_PLATFORM=m +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m +CONFIG_DM_MULTIPATH_RDAC=m +CONFIG_DM_MULTIPATH_HP=m +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_SAS=m +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# Controllers +# +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocols +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_I2O=m +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_BUS=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +CONFIG_IFB=m +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_MACVLAN=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_NET_SB1000=m +CONFIG_ARCNET=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_ISA=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_PHYLIB=m + +# +# MII PHY device drivers +# +CONFIG_MARVELL_PHY=m +CONFIG_DAVICOM_PHY=m +CONFIG_QSEMI_PHY=m +CONFIG_LXT_PHY=m +CONFIG_CICADA_PHY=m +CONFIG_VITESSE_PHY=m +CONFIG_SMSC_PHY=m +CONFIG_BROADCOM_PHY=m +CONFIG_ICPLUS_PHY=m +CONFIG_FIXED_PHY=m +# CONFIG_FIXED_MII_10_FDX is not set +# CONFIG_FIXED_MII_100_FDX is not set +CONFIG_FIXED_MII_1000_FDX=y +CONFIG_FIXED_MII_AMNT=1 +CONFIG_MDIO_BITBANG=m +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_ELMC=m +CONFIG_ELMC_II=m +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRAMCA=m +CONFIG_ULTRA=m +CONFIG_ULTRA32=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +CONFIG_NI52=m +CONFIG_NI65=m +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_ULI526X=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_AT1700=m +CONFIG_DEPCA=m +CONFIG_HP100=m +CONFIG_NET_ISA=y +CONFIG_E2100=m +CONFIG_EWRK3=m +CONFIG_EEXPRESS=m +CONFIG_EEXPRESS_PRO=m +CONFIG_HPLAN_PLUS=m +CONFIG_HPLAN=m +CONFIG_LP486E=m +CONFIG_ETH16I=m +CONFIG_NE2000=m +CONFIG_ZNET=m +CONFIG_SEEQ8005=m +CONFIG_NE2_MCA=m +CONFIG_IBMLANA=m +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_AMD8111_ETH=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI=y +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +CONFIG_CS89x0=m +CONFIG_EEPRO100=m +CONFIG_E100=m +CONFIG_LNE390=m +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_NE3210=m +CONFIG_ES3210=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_VIA_RHINE_NAPI is not set +CONFIG_SC92031=m +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_NETDEV_1000=y +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E1000E=m +CONFIG_IP1000=m +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_SIS190=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SK98LIN is not set +CONFIG_VIA_VELOCITY=m +CONFIG_TIGON3=m +CONFIG_BNX2=m +CONFIG_QLA3XXX=m +CONFIG_ATL1=m +CONFIG_NETDEV_10000=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_IXGBE=m +CONFIG_IXGB=m +# CONFIG_IXGB_NAPI is not set +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +CONFIG_MYRI10GE=m +CONFIG_NETXEN_NIC=m +CONFIG_NIU=m +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_TEHUTI=m +CONFIG_TR=y +CONFIG_IBMTR=m +CONFIG_IBMOL=m +CONFIG_IBMLS=m +CONFIG_3C359=m +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +CONFIG_SKISA=m +CONFIG_PROTEON=m +CONFIG_ABYSS=m +CONFIG_MADGEMC=m +CONFIG_SMCTR=m + +# +# Wireless LAN +# +CONFIG_WLAN_PRE80211=y +CONFIG_STRIP=m +CONFIG_ARLAN=m +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_WLAN_80211=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_IPW2100=m +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2200=m +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +# CONFIG_IPW2200_DEBUG is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_CS=m +CONFIG_LIBERTAS_SDIO=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_AIRO=m +CONFIG_HERMES=m +# CONFIG_PLX_HERMES is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_PCI_HERMES is not set +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PRISM54=m +CONFIG_USB_ZD1201=m +CONFIG_RTL8187=m +CONFIG_ADM8211=m +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +CONFIG_P54_PCI=m +# CONFIG_IWLWIFI is not set +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_CS=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_PIO=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +# CONFIG_BCM43XX_PIO_MODE is not set +CONFIG_B43=m +CONFIG_B43_PCI_AUTOSELECT=y +CONFIG_B43_PCICORE_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_LEDS=y +CONFIG_B43_RFKILL=y +# CONFIG_B43_DEBUG is not set +CONFIG_B43_DMA=y +CONFIG_B43_PIO=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +# CONFIG_B43_PIO_MODE is not set +# CONFIG_B43LEGACY is not set +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_RT2X00=m +CONFIG_RT2X00_LIB=m +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +# CONFIG_RT2X00_DEBUG is not set + +# +# USB Network Adapters +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_PCMCIA_IBMTR=m +CONFIG_WAN=y +CONFIG_HOSTESS_SV11=m +CONFIG_COSA=m +CONFIG_LANMEDIA=m +CONFIG_SEALEVEL_4021=m +CONFIG_HDLC=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_X25=m +CONFIG_PCI200SYN=m +CONFIG_WANXL=m +CONFIG_PC300=m +CONFIG_PC300_MLPPP=y + +# +# Cyclades-PC300 MLPPP support is disabled. +# + +# +# Refer to the file README.mlppp, provided by PC300 package. +# +# CONFIG_PC300TOO is not set +CONFIG_N2=m +CONFIG_C101=m +CONFIG_FARSYNC=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_SDLA=m +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +CONFIG_LAPBETHER=m +CONFIG_X25_ASY=m +CONFIG_SBNI=m +# CONFIG_SBNI_MULTILINE is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_TCP=m +CONFIG_ATM_LANAI=m +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_ATM_NICSTAR=m +# CONFIG_ATM_NICSTAR_USE_SUNI is not set +# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_FORE200E_MAYBE=m +CONFIG_ATM_FORE200E_PCA=y +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_FORE200E_TX_RETRY=16 +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E=m +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_FDDI=y +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_SKFP=m +CONFIG_HIPPI=y +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +CONFIG_PPPOE=m +CONFIG_PPPOATM=m +CONFIG_PPPOL2TP=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLHC=m +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_NET_FC=y +CONFIG_SHAPER=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_VIRTIO_NET=m +CONFIG_ISDN=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y +CONFIG_ISDN_X25=y + +# +# ISDN feature submodules +# +CONFIG_ISDN_DIVERSION=m + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_KEYPAD is not set +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_GIGASET_BASE=m +CONFIG_GIGASET_M105=m +CONFIG_GIGASET_M101=m +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_UNDOCREQ is not set +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_CAPI_TRACE=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# +CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_T1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_POLLDEV=m + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_EVBUG=m + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_INPORT=m +# CONFIG_MOUSE_ATIXL is not set +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +CONFIG_INPUT_WISTRON_BTNS=m +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_YEALINK=m +CONFIG_INPUT_UINPUT=m + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_DEV_KMEM is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +CONFIG_ROCKETPORT=m +CONFIG_CYCLADES=m +# CONFIG_CYZ_INTR is not set +CONFIG_DIGIEPCA=m +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +# CONFIG_ISI is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_GT=m +CONFIG_N_HDLC=m +CONFIG_SPECIALIX=m +# CONFIG_SPECIALIX_RTSCTS is not set +CONFIG_SX=m +# CONFIG_RIO is not set +CONFIG_STALDRV=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_CS=m +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_FOURPORT=m +CONFIG_SERIAL_8250_ACCENT=m +CONFIG_SERIAL_8250_BOCA=m +CONFIG_SERIAL_8250_EXAR_ST16C554=m +CONFIG_SERIAL_8250_HUB6=m +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_MCA=m + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +CONFIG_PPDEV=m +CONFIG_HVC_DRIVER=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPMI_POWEROFF=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_INTEL=m +CONFIG_HW_RANDOM_AMD=m +CONFIG_HW_RANDOM_GEODE=m +CONFIG_HW_RANDOM_VIA=m +CONFIG_NVRAM=m +CONFIG_RTC=y +CONFIG_DTLK=m +CONFIG_R3964=m +CONFIG_APPLICOM=m +CONFIG_SONYPI=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_MWAVE=m +CONFIG_SCx200_GPIO=m +CONFIG_PC8736x_GPIO=m +CONFIG_NSC_GPIO=m +CONFIG_CS5535_GPIO=m +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +CONFIG_HPET=y +# CONFIG_HPET_RTC_IRQ is not set +CONFIG_HPET_MMAP=y +CONFIG_HANGCHECK_TIMER=m +CONFIG_TCG_TPM=m +CONFIG_TCG_TIS=m +CONFIG_TCG_NSC=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TELCLOCK=m +CONFIG_DEVPORT=y +CONFIG_I2C=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +CONFIG_I2C_SIMTEC=m +CONFIG_SCx200_I2C=m +CONFIG_SCx200_I2C_SCL=12 +CONFIG_SCx200_I2C_SDA=13 +CONFIG_SCx200_ACB=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m +CONFIG_I2C_PCA_ISA=m + +# +# Miscellaneous I2C Chip support +# +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_DS1682=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_TSL2550=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +CONFIG_SPI_LM70_LLP=m + +# +# SPI Protocol Masters +# +CONFIG_SPI_AT25=m +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_W1=m +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PDA_POWER=m +CONFIG_BATTERY_DS2760=m +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_HDAPS=m +CONFIG_SENSORS_APPLESMC=m +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_WAFER_WDT=m +CONFIG_I6300ESB_WDT=m +CONFIG_ITCO_WDT=m +CONFIG_ITCO_VENDOR_SUPPORT=y +CONFIG_IT8712F_WDT=m +CONFIG_SC1200_WDT=m +CONFIG_SCx200_WDT=m +CONFIG_PC87413_WDT=m +CONFIG_60XX_WDT=m +CONFIG_SBC8360_WDT=m +CONFIG_SBC7240_WDT=m +CONFIG_CPU5_WDT=m +CONFIG_SMSC37B787_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83697HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_MACHZ_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m + +# +# ISA-based Watchdog Cards +# +CONFIG_PCWATCHDOG=m +CONFIG_MIXCOMWD=m +CONFIG_WDT=m +CONFIG_WDT_501=y + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +# CONFIG_SSB_PCMCIAHOST is not set +# CONFIG_SSB_SILENT is not set +# CONFIG_SSB_DEBUG is not set +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_DRIVER_PCICORE=y + +# +# Multifunction device drivers +# +CONFIG_MFD_SM501=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders/decoders and other helper chips +# + +# +# Audio decoders +# +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_VP27SMPX=m + +# +# Video decoders +# +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_TCM825X=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7191=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_VPX3220=m + +# +# Video and audio decoders +# +CONFIG_VIDEO_CX25840=m + +# +# MPEG video encoders +# +CONFIG_VIDEO_CX2341X=m + +# +# Video encoders +# +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m + +# +# Video improvement chips +# +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SAA7134=m +# CONFIG_VIDEO_SAA7134_ALSA is not set +# CONFIG_VIDEO_SAA7134_OSS is not set +CONFIG_VIDEO_SAA7134_DVB=m +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_DPC is not set +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m +# CONFIG_VIDEO_CX88_ALSA is not set +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_29XXX=y +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_SYSFS=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_USB_VICAM=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_ET61X251=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_USB_W9968CF=m +# CONFIG_USB_OV511 is not set +CONFIG_USB_SE401=m +CONFIG_USB_SN9C102=m +CONFIG_USB_STV680=m +CONFIG_USB_ZC0301=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_ZR364XX=m +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +# CONFIG_RADIO_TYPHOON_PROC_FS is not set +CONFIG_RADIO_ZOLTRIX=m +CONFIG_USB_DSBR=m +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CAPTURE_DRIVERS=y + +# +# Supported SAA7146 based PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +# +# Supported USB Adapters +# +CONFIG_DVB_USB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 + +# +# Supported FlexCopII (B2C2) Adapters +# +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m + +# +# Supported Pluto2 Adapters +# +CONFIG_DVB_PLUTO2=m + +# +# Supported DVB Frontends +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_FE_CUSTOMISE is not set + +# +# DVB-S (satellite) frontends +# +CONFIG_DVB_STV0299=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_TDA10086=m + +# +# DVB-T (terrestrial) frontends +# +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_L64781=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_ZL10353=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m + +# +# DVB-C (cable) frontends +# +CONFIG_DVB_VES1820=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_STV0297=m + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +CONFIG_DVB_NXT200X=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_S5H1409=m + +# +# Tuners/PLL support +# +CONFIG_DVB_PLL=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +CONFIG_DVB_TUNER_QT1010=m +CONFIG_DVB_TUNER_MT2060=m +CONFIG_DVB_TUNER_MT2266=m +CONFIG_DVB_TUNER_MT2131=m +CONFIG_DVB_TUNER_DIB0070=m + +# +# Miscellaneous devices +# +CONFIG_DVB_LNBP21=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_TUA6100=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TUNER_SIMPLE=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_DAB=y +CONFIG_USB_DABUSB=m + +# +# Graphics support +# +CONFIG_AGP=m +CONFIG_AGP_ALI=m +CONFIG_AGP_ATI=m +CONFIG_AGP_AMD=m +CONFIG_AGP_AMD64=m +CONFIG_AGP_INTEL=m +CONFIG_AGP_NVIDIA=m +CONFIG_AGP_SIS=m +CONFIG_AGP_SWORKS=m +CONFIG_AGP_VIA=m +CONFIG_AGP_EFFICEON=m +CONFIG_DRM=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_I915=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m +CONFIG_DRM_VIA=m +CONFIG_DRM_SAVAGE=m +CONFIG_VGASTATE=m +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_DDC=m +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_IMAGEBLIT=m +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_SVGALIB=m +# CONFIG_FB_MACMODES is not set +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +CONFIG_FB_CIRRUS=m +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_CYBER2000=m +CONFIG_FB_ARC=m +CONFIG_FB_ASILIANT=y +CONFIG_FB_IMSTT=y +CONFIG_FB_VGA16=m +CONFIG_FB_UVESA=m +CONFIG_FB_VESA=m +CONFIG_FB_EFI=y +CONFIG_FB_IMAC=y +CONFIG_FB_HECUBA=m +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_S1D13XXX=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_I2C=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_BACKLIGHT=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_I2C=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_BACKLIGHT=y +CONFIG_FB_I810=m +# CONFIG_FB_I810_GTF is not set +CONFIG_FB_LE80578=m +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FB_CYBLA=m +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_ARK=m +CONFIG_FB_PM3=m +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_LX=m +CONFIG_FB_GEODE_GX=m +# CONFIG_FB_GEODE_GX_SET_FBSIZE is not set +CONFIG_FB_GEODE_GX1=m +CONFIG_FB_SM501=m +# CONFIG_FB_VIRTUAL is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_PROGEAR=m +CONFIG_BACKLIGHT_CARILLO_RANCH=m + +# +# Display device support +# +CONFIG_DISPLAY_SUPPORT=m + +# +# Display hardware drivers +# + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VIDEO_SELECT=y +CONFIG_MDA_CONSOLE=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=m +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_LOGO is not set + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL4_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_MPU401=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_AD1848_LIB=m +CONFIG_SND_CS4231_LIB=m +CONFIG_SND_SB_COMMON=m +CONFIG_SND_SB8_DSP=m +CONFIG_SND_SB16_DSP=m + +# +# ISA devices +# +CONFIG_SND_ADLIB=m +CONFIG_SND_AD1816A=m +CONFIG_SND_AD1848=m +CONFIG_SND_ALS100=m +CONFIG_SND_AZT2320=m +CONFIG_SND_CMI8330=m +CONFIG_SND_CS4231=m +CONFIG_SND_CS4232=m +CONFIG_SND_CS4236=m +CONFIG_SND_DT019X=m +CONFIG_SND_ES968=m +CONFIG_SND_ES1688=m +CONFIG_SND_ES18XX=m +CONFIG_SND_SC6000=m +CONFIG_SND_GUS_SYNTH=m +CONFIG_SND_GUSCLASSIC=m +CONFIG_SND_GUSEXTREME=m +CONFIG_SND_GUSMAX=m +CONFIG_SND_INTERWAVE=m +CONFIG_SND_INTERWAVE_STB=m +CONFIG_SND_OPL3SA2=m +CONFIG_SND_OPTI92X_AD1848=m +CONFIG_SND_OPTI92X_CS4231=m +CONFIG_SND_OPTI93X=m +CONFIG_SND_MIRO=m +CONFIG_SND_SB8=m +CONFIG_SND_SB16=m +CONFIG_SND_SBAWE=m +CONFIG_SND_SB16_CSP=y +CONFIG_SND_SB16_CSP_FIRMWARE_IN_KERNEL=y +CONFIG_SND_SGALAXY=m +CONFIG_SND_SSCAPE=m +CONFIG_SND_WAVEFRONT=m +CONFIG_SND_WAVEFRONT_FIRMWARE_IN_KERNEL=y + +# +# PCI devices +# +CONFIG_SND_AD1889=m +CONFIG_SND_ALS300=m +CONFIG_SND_ALS4000=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_BT87X_OVERCLOCK=y +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS5530=m +CONFIG_SND_CS5535AUDIO=m +CONFIG_SND_DARLA20=m +CONFIG_SND_GINA20=m +CONFIG_SND_LAYLA20=m +CONFIG_SND_DARLA24=m +CONFIG_SND_GINA24=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MONA=m +CONFIG_SND_MIA=m +CONFIG_SND_ECHO3G=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_CODEC_ANALOG=y +CONFIG_SND_HDA_CODEC_SIGMATEL=y +CONFIG_SND_HDA_CODEC_VIA=y +CONFIG_SND_HDA_CODEC_ATIHDMI=y +CONFIG_SND_HDA_CODEC_CONEXANT=y +CONFIG_SND_HDA_CODEC_CMEDIA=y +CONFIG_SND_HDA_CODEC_SI3054=y +CONFIG_SND_HDA_GENERIC=y +CONFIG_SND_HDA_POWER_SAVE=y +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_KORG1212_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MAESTRO3_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_PCXHR=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VX222=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 + +# +# SPI devices +# + +# +# USB devices +# +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_USX2Y=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y + +# +# PCMCIA devices +# +CONFIG_SND_VXPOCKET=m +CONFIG_SND_PDAUDIOCF=m + +# +# System on Chip audio support +# +CONFIG_SND_SOC=m + +# +# SoC Audio support for SuperH +# + +# +# Open Sound System +# +CONFIG_SOUND_PRIME=m +CONFIG_SOUND_TRIDENT=m +CONFIG_SOUND_MSNDCLAS=m +CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin" +CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin" +CONFIG_SOUND_MSNDPIN=m +CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin" +CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin" +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +CONFIG_SOUND_DMAP=y +CONFIG_SOUND_SSCAPE=m +CONFIG_SOUND_VMIDI=m +CONFIG_SOUND_TRIX=m +CONFIG_SOUND_MSS=m +CONFIG_SOUND_MPU401=m +CONFIG_SOUND_PAS=m +CONFIG_SOUND_PSS=m +CONFIG_PSS_MIXER=y +CONFIG_SOUND_SB=m +CONFIG_SOUND_YM3812=m +CONFIG_SOUND_UART6850=m +CONFIG_SOUND_AEDSP16=m +CONFIG_SC6600=y +CONFIG_SC6600_JOY=y +CONFIG_SC6600_CDROM=4 +CONFIG_SC6600_CDROMBASE=0 +CONFIG_AEDSP16_MSS=y +# CONFIG_AEDSP16_SBPRO is not set +CONFIG_SOUND_KAHLUA=m +CONFIG_AC97_BUS=m +CONFIG_HID_SUPPORT=y +CONFIG_HID=m +# CONFIG_HID_DEBUG is not set +CONFIG_HIDRAW=y + +# +# USB Input Devices +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT_POWERBOOK=y +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_PERSIST is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_ISP116X_HCD=m +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_HCD_SSB=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SL811_CS=m +CONFIG_USB_R8A66597_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_MON=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +# CONFIG_USB_SERIAL_IR is not set +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_LED=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_IOWARRIOR=m +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# +CONFIG_USB_ATM=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_CXACRU=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=m +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +CONFIG_USB_GADGET_NET2280=y +CONFIG_USB_NET2280=m +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_GADGETFS=m +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_G_SERIAL=m +# CONFIG_USB_MIDI_GADGET is not set + +# +# MMC/SD/SDIO support, can only select one arch from MMC and MSS +# +CONFIG_MMC=m +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_SDIO_UART=m + +# +# MMC/SD Host Controller Drivers +# +CONFIG_MMC_SDHCI=m +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_WBSD=m +CONFIG_MMC_TIFM_SD=m +# CONFIG_MSS is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=m + +# +# LED drivers +# +CONFIG_LEDS_NET48XX=m +CONFIG_LEDS_WRAP=m + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_MLX4_INFINIBAND=m +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_ISER=m +CONFIG_EDAC=y + +# +# Reporting subsystems +# +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_MM_EDAC=m +# CONFIG_EDAC_AMD76X is not set +CONFIG_EDAC_E7XXX=m +CONFIG_EDAC_E752X=m +CONFIG_EDAC_I82875P=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_I3000=m +CONFIG_EDAC_I82860=m +CONFIG_EDAC_R82600=m +CONFIG_EDAC_I5000=m +CONFIG_RTC_LIB=m +CONFIG_RTC_CLASS=m + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_DRV_TEST=m + +# +# I2C RTC drivers +# +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y + +# +# SPI RTC drivers +# +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_MAX6902=m + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_V3020=m + +# +# on-CPU RTC drivers +# +CONFIG_DMADEVICES=y + +# +# DMA Devices +# +CONFIG_INTEL_IOATDMA=m +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +CONFIG_NET_DMA=y +CONFIG_DCA=m +CONFIG_AUXDISPLAY=y +CONFIG_KS0108=m +CONFIG_KS0108_PORT=0x378 +CONFIG_KS0108_DELAY=2 +CONFIG_CFAG12864B=m +CONFIG_CFAG12864B_RATE=20 + +# +# Userspace I/O +# +CONFIG_UIO=m +CONFIG_UIO_CIF=m + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_EFI_VARS=y +CONFIG_DELL_RBU=m +CONFIG_DCDBAS=m +CONFIG_DMIID=y + +# +# File systems +# +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=m +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_STATISTICS=y +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_NOLOCK=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_OCFS2_FS=m +CONFIG_OCFS2_DEBUG_MASKLOG=y +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_QUOTACTL=y +CONFIG_DNOTIFY=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=m +CONFIG_GENERIC_ACL=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m + +# +# Miscellaneous filesystems +# +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +CONFIG_CRAMFS=y +CONFIG_VXFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_UFS_DEBUG is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_XPRT_RDMA=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_EXPERIMENTAL is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +CONFIG_CODA_FS=m +# CONFIG_CODA_FS_OLD_API is not set +CONFIG_AFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_9P_FS=m +CONFIG_DEFAULT_RELATIME=y +CONFIG_DEFAULT_RELATIME_VAL=1 + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_CUMANA is not set +# CONFIG_ACORN_PARTITION_EESOX is not set +CONFIG_ACORN_PARTITION_ICS=y +# CONFIG_ACORN_PARTITION_ADFS is not set +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_ATARI_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +CONFIG_SGI_PARTITION=y +CONFIG_ULTRIX_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_SYSV68_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_INSTRUMENTATION=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=m +CONFIG_KPROBES=y +# CONFIG_MARKERS is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_PRINTK_TIME=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_FORCED_INLINING is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_LKDTM is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SAMPLES is not set +CONFIG_NONPROMISC_DEVMEM=y +CONFIG_EARLY_PRINTK=y +# CONFIG_WRAPPER_PRINT is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set + +# +# Page alloc debug is incompatible with Software Suspend on i386 +# +# CONFIG_DEBUG_RODATA is not set +# CONFIG_4KSTACKS is not set +CONFIG_X86_FIND_SMP_CONFIG=y +CONFIG_X86_MPPARSE=y +CONFIG_DOUBLEFAULT=y +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +CONFIG_IO_DELAY_TYPE_NONE=3 +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_DEFAULT_IO_DELAY_TYPE=0 + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +# CONFIG_SECURITY_APPARMOR_DISABLE is not set +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_TWOFISH_586=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_AES_586=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_PADLOCK=y +CONFIG_CRYPTO_DEV_PADLOCK_AES=m +CONFIG_CRYPTO_DEV_PADLOCK_SHA=m +CONFIG_CRYPTO_DEV_GEODE=m +CONFIG_HAVE_KVM=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_INTEL=m +CONFIG_KVM_AMD=m +CONFIG_LGUEST=m +CONFIG_VIRTIO=y +CONFIG_VIRTIO_RING=y +# CONFIG_VIRTIO_PCI is not set +CONFIG_VIRTIO_BALLOON=m + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=m +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_DRM_VIA_CHROME9=m --- linux-2.6.24.orig/debian/binary-custom.d/lpiacompat/patchset/0006-ACPI-thermal-driver-registering-with-generic-thermal.patch +++ linux-2.6.24/debian/binary-custom.d/lpiacompat/patchset/0006-ACPI-thermal-driver-registering-with-generic-thermal.patch @@ -0,0 +1,665 @@ +From bd243e4020f4bbce600330fd074af31973089cca Mon Sep 17 00:00:00 2001 +From: Sujith Thomas +Date: Wed, 12 Dec 2007 11:07:18 +0530 +Subject: [PATCH] ACPI thermal driver registering with generic thermal sysfs driver + +Signed-off-by: Sujith Thomas + +Callbacks for various attributes(critical,hot...) are added +Provided infrastructure for user mode applicatio to take over platform thermal management +--- + drivers/acpi/Kconfig | 5 +- + drivers/acpi/thermal.c | 508 +++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 507 insertions(+), 6 deletions(-) + +diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig +index ac09a5c..b065d16 100644 +--- a/drivers/acpi/Kconfig ++++ b/drivers/acpi/Kconfig +@@ -3,10 +3,11 @@ + # + + menuconfig ACPI +- bool "ACPI (Advanced Configuration and Power Interface) Support" ++ bool "ACPI Support (Advanced Configuration and Power Interface) Support" + depends on !X86_NUMAQ + depends on !X86_VISWS + depends on !IA64_HP_SIM ++ depends on PM || THERMAL_SYSFS + depends on IA64 || X86 + depends on PCI + depends on PM +@@ -181,7 +182,7 @@ config ACPI_HOTPLUG_CPU + + config ACPI_THERMAL + tristate "Thermal Zone" +- depends on ACPI_PROCESSOR ++ depends on THERMAL_SYSFS && ACPI_PROCESSOR + default y + help + This driver adds support for ACPI thermal zones. Most mobile and +diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c +index 5f79b44..417deed 100644 +--- a/drivers/acpi/thermal.c ++++ b/drivers/acpi/thermal.c +@@ -28,6 +28,8 @@ + * TBD: 1. Implement passive cooling hysteresis. + * 2. Enhance passive cooling (CPU) states/limit interface to support + * concepts of 'multiple limiters', upper/lower limits, etc. ++ * Modified: 1. Provide infrastructure from kernel to enable user-space ++ * thermal management algorithm + * + */ + +@@ -46,6 +48,7 @@ + + #include + #include ++#include + + #define ACPI_THERMAL_COMPONENT 0x04000000 + #define ACPI_THERMAL_CLASS "thermal_zone" +@@ -65,9 +68,6 @@ + #define ACPI_THERMAL_MAX_ACTIVE 10 + #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65 + +-#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10) +-#define CELSIUS_TO_KELVIN(t) ((t+273)*10) +- + #define _COMPONENT ACPI_THERMAL_COMPONENT + ACPI_MODULE_NAME("thermal"); + +@@ -99,6 +99,11 @@ static int psv; + module_param(psv, int, 0644); + MODULE_PARM_DESC(psv, "Disable or override all passive trip points."); + ++#define ACPI_THERMAL_GROUP_TZD "thermalzone_devices" ++#define ACPI_THERMAL_GROUP_PSL "passive_devices" ++#define ACPI_THERMAL_GROUP_ALX "active_devices_x" ++#define ACPI_THERMAL_TRIP_ACTIVE "active_x" ++ + static int acpi_thermal_add(struct acpi_device *device); + static int acpi_thermal_remove(struct acpi_device *device, int type); + static int acpi_thermal_resume(struct acpi_device *device); +@@ -196,6 +201,9 @@ struct acpi_thermal { + struct acpi_handle_list devices; + struct timer_list timer; + struct mutex lock; ++ struct thermal_device *td; ++ struct thermal_device_attribute ++ *thermal_device_active_attr[ACPI_THERMAL_MAX_ACTIVE + 1]; + }; + + static const struct file_operations acpi_thermal_state_fops = { +@@ -235,6 +243,11 @@ static const struct file_operations acpi_thermal_polling_fops = { + .release = single_release, + }; + ++static int acpi_thermal_one_group_register(struct acpi_thermal *tz, char *name, ++ struct acpi_handle_list *devices); ++static int acpi_thermal_sysfs_register(struct acpi_thermal *tz); ++static void acpi_thermal_sysfs_unregister(struct acpi_thermal *tz); ++ + /* -------------------------------------------------------------------------- + Thermal Zone Management + -------------------------------------------------------------------------- */ +@@ -757,6 +770,16 @@ static void acpi_thermal_check(void *data) + tz->trips.active[i].temperature); + + /* ++ * Check for user/kernel algo ++ * ------------------------- ++ *If there is a thermal management application in userspace ++ *Or there are non CPU devices in this thermal zone ++ *Kernelspace solution won't handle this ++ */ ++ ++ if (THERMAL_KERNELSPACE == thermal_get_algo_mode()) { ++ ++ /* + * Invoke Policy + * ------------- + * Separated from the above check to allow individual policy to +@@ -770,6 +793,7 @@ static void acpi_thermal_check(void *data) + acpi_thermal_passive(tz); + if (state.active) + acpi_thermal_active(tz); ++ } + + /* + * Calculate State +@@ -1165,6 +1189,47 @@ static int acpi_thermal_remove_fs(struct acpi_device *device) + Driver Interface + -------------------------------------------------------------------------- */ + ++/* ++ * acpi_thermal_one_group_register ++ * ------------------------------ ++ * Registers a group such as _TZD,_PSL,_ALx with thermal_sysfs driver ++ * tz : pointer to the acpi_thermal structure ++ * name : Name of the group ++ * devices : List of devices in this group ++ */ ++static int acpi_thermal_one_group_register(struct acpi_thermal *tz, char *name, ++ struct acpi_handle_list *devices) ++{ ++ int result, i; ++ struct acpi_device *ad; ++ struct thermal_participant *participants; ++ ++ if (!tz || !name || !devices) ++ return -EINVAL; ++ ++ participants = ++ kzalloc(sizeof(struct thermal_participant) * devices->count, ++ GFP_KERNEL); ++ if (!participants) ++ return -ENOMEM; ++ ++ for (i = 0; i < devices->count; i++) { ++ result = acpi_bus_get_device(devices->handles[i], &ad); ++ if (result) { ++ kfree(participants); ++ return result; ++ } ++ participants[i].kobj = &ad->dev.kobj; ++ strlcpy(participants[i].name, ad->pnp.bus_id, KOBJ_NAME_LEN); ++ } ++ ++ result = ++ thermal_group_register(name, tz->td, devices->count, participants); ++ ++ kfree(participants); ++ return result; ++} ++ + static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data) + { + struct acpi_thermal *tz = data; +@@ -1178,18 +1243,33 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data) + + switch (event) { + case ACPI_THERMAL_NOTIFY_TEMPERATURE: ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, ++ "Received event from TZ: %s event type:%x \n", ++ tz->name, event)); + acpi_thermal_check(tz); ++ /*Event for user space algorithm */ ++ thermal_sysfs_generate_event(tz->td, KOBJ_CHANGE); + break; + case ACPI_THERMAL_NOTIFY_THRESHOLDS: ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, ++ "Received event from TZ: %s event type:%x \n", ++ tz->name, event)); + acpi_thermal_get_trip_points(tz); + acpi_thermal_check(tz); ++ thermal_sysfs_generate_event(tz->td, KOBJ_MOVE); + acpi_bus_generate_proc_event(device, event, 0); + acpi_bus_generate_netlink_event(device->pnp.device_class, + device->dev.bus_id, event, 0); + break; + case ACPI_THERMAL_NOTIFY_DEVICES: +- if (tz->flags.devices) ++ if (tz->flags.devices) { ++ thermal_group_unregister(tz->td, ++ ACPI_THERMAL_GROUP_TZD); + acpi_thermal_get_devices(tz); ++ acpi_thermal_one_group_register(tz, ++ ACPI_THERMAL_GROUP_TZD, ++ &tz->devices); ++ } + acpi_bus_generate_proc_event(device, event, 0); + acpi_bus_generate_netlink_event(device->pnp.device_class, + device->dev.bus_id, event, 0); +@@ -1240,6 +1320,419 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz) + return 0; + } + ++static int acpi_thermal_sysfs_get_temperature(void *devdata, ++ struct thermal_device_attribute ++ *attr, int *temperature) ++{ ++ int result; ++ struct acpi_thermal *tz; ++ ++ if (!devdata || !temperature) ++ return -EINVAL; ++ ++ tz = (struct acpi_thermal *)devdata; ++ result = acpi_thermal_get_temperature(tz); ++ ++ if (result) ++ return result; ++ ++ *temperature = KELVIN_TO_CELSIUS(tz->temperature); ++ return 0; ++} ++ ++static int acpi_thermal_sysfs_get_critical(void *devdata, ++ struct thermal_device_attribute ++ *attr, int *critical) ++{ ++ struct acpi_thermal *tz; ++ ++ if (!devdata || !critical) ++ return -EINVAL; ++ ++ tz = (struct acpi_thermal *)devdata; ++ ++ if (tz->trips.critical.flags.valid) { ++ *critical = KELVIN_TO_CELSIUS(tz->trips.critical.temperature); ++ return 0; ++ } ++ ++ return -ENODEV; ++} ++ ++static int acpi_thermal_sysfs_get_hot(void *devdata, ++ struct thermal_device_attribute *attr, ++ int *hot) ++{ ++ struct acpi_thermal *tz; ++ ++ if (!devdata || !hot) ++ return -EINVAL; ++ ++ tz = (struct acpi_thermal *)devdata; ++ ++ if (tz->trips.hot.flags.valid) { ++ *hot = KELVIN_TO_CELSIUS(tz->trips.hot.temperature); ++ return 0; ++ } ++ ++ return -ENODEV; ++} ++ ++static int acpi_thermal_sysfs_get_passive(void *devdata, ++ struct thermal_device_attribute *attr, ++ int *passive) ++{ ++ struct acpi_thermal *tz; ++ ++ if (!devdata || !passive) ++ return -EINVAL; ++ ++ tz = (struct acpi_thermal *)devdata; ++ ++ if (tz->trips.passive.flags.valid) { ++ *passive = KELVIN_TO_CELSIUS(tz->trips.passive.temperature); ++ return 0; ++ } ++ ++ return -ENODEV; ++} ++ ++static int acpi_thermal_sysfs_get_polling_freq(void *devdata, ++ struct thermal_device_attribute ++ *attr, int *polling_freq) ++{ ++ struct acpi_thermal *tz; ++ ++ if (!devdata || !polling_freq) ++ return -EINVAL; ++ ++ tz = (struct acpi_thermal *)devdata; ++ ++ if (tz->polling_frequency) { ++ *polling_freq = tz->polling_frequency / 10; ++ return 0; ++ } ++ ++ return -ENODEV; ++} ++ ++static int acpi_thermal_sysfs_set_cooling_mode(void *devdata, ++ struct thermal_device_attribute ++ *attr, int cooling_mode) ++{ ++ int result; ++ struct acpi_thermal *tz; ++ ++ if (!devdata) ++ return -EINVAL; ++ ++ tz = (struct acpi_thermal *)devdata; ++ ++ if (tz->flags.cooling_mode) { ++ result = acpi_thermal_set_polling(tz, cooling_mode); ++ if (result) ++ return result; ++ ++ acpi_thermal_check(tz); ++ } ++ ++ return -ENODEV; ++} ++ ++/* ++ * acpi_thermal_sysfs_get_state ++ * ------------------------------ ++ * Gets the state of thermal zone which can be OK,critical,hot,passive,active[x] ++ */ ++static int ++acpi_thermal_sysfs_get_state(void *devdata, ++ struct thermal_device_attribute *attr, char *buf) ++{ ++ char *s = buf; ++ struct acpi_thermal *tz; ++ ++ if (!devdata || !buf) ++ return -EINVAL; ++ ++ tz = (struct acpi_thermal *)devdata; ++ ++ if (!tz->state.critical && !tz->state.hot && !tz->state.passive ++ && !tz->state.active) ++ s += sprintf(buf, "ok\n"); ++ else { ++ if (tz->state.critical) ++ s += sprintf(buf, "critical\n"); ++ else if (tz->state.hot) ++ s += sprintf(buf, "hot\n"); ++ else if (tz->state.passive) ++ s += sprintf(buf, "passive\n"); ++ else if (tz->state.active) ++ s += sprintf(buf, "active[%d]\n", ++ tz->state.active_index); ++ } ++ return (s - buf); ++} ++ ++static struct thermal_device_ops acpi_thermal_ops = { ++ .thermal_get_temperature = acpi_thermal_sysfs_get_temperature, ++ .thermal_get_critical = acpi_thermal_sysfs_get_critical, ++ .thermal_get_hot = acpi_thermal_sysfs_get_hot, ++ .thermal_get_passive = acpi_thermal_sysfs_get_passive, ++ .thermal_set_cooling_mode = acpi_thermal_sysfs_set_cooling_mode, ++ .thermal_get_polling_freq = acpi_thermal_sysfs_get_polling_freq, ++ .thermal_get_state = acpi_thermal_sysfs_get_state, ++}; ++ ++/* ++ * acpi_thermal_sysfs_get_activestate ++ * ------------------------------ ++ * Gets the temperature at which active_device[x] will be turned on ++ */ ++static int acpi_thermal_sysfs_get_active(struct thermal_device *td, ++ struct thermal_device_attribute ++ *attrib, char *buf) ++{ ++ const char *attrib_name; ++ int id; ++ char *s = buf; ++ struct acpi_thermal *tz; ++ ++ if (!td || !attrib || !buf) ++ return -EINVAL; ++ ++ tz = (struct acpi_thermal *)td->devdata; ++ attrib_name = attrib->attr.name; ++ ++ if (!sscanf(attrib_name, "active_%d", &id)) ++ return -EINVAL; ++ ++ if (id > ACPI_THERMAL_MAX_ACTIVE) ++ return -EINVAL; ++ ++ s += sprintf(s, "%lu\n", ++ KELVIN_TO_CELSIUS(tz->trips.active[id].temperature)); ++ ++ return (s - buf); ++} ++ ++static ssize_t ++acpi_thermal_tc1_show(struct thermal_device *td, ++ struct thermal_device_attribute *attr, char *buf) ++{ ++ char *s = buf; ++ struct acpi_thermal *tz; ++ ++ if (!td || !attr || !buf) ++ return -EINVAL; ++ ++ tz = (struct acpi_thermal *)td->devdata; ++ ++ if (tz->trips.passive.flags.valid) ++ s += sprintf(s, "%lu\n", tz->trips.passive.tc1); ++ ++ return (s - buf); ++} ++ ++static ssize_t ++acpi_thermal_tc2_show(struct thermal_device *td, ++ struct thermal_device_attribute *attr, char *buf) ++{ ++ char *s = buf; ++ struct acpi_thermal *tz; ++ ++ if (!td || !attr || !buf) ++ return -EINVAL; ++ ++ tz = (struct acpi_thermal *)td->devdata; ++ ++ if (tz->trips.passive.flags.valid) ++ s += sprintf(s, "%lu\n", tz->trips.passive.tc2); ++ ++ return (s - buf); ++} ++ ++static ssize_t ++acpi_thermal_tsp_show(struct thermal_device *td, ++ struct thermal_device_attribute *attr, char *buf) ++{ ++ char *s = buf; ++ struct acpi_thermal *tz; ++ ++ if (!td || !attr || !buf) ++ return -EINVAL; ++ ++ tz = (struct acpi_thermal *)td->devdata; ++ ++ if (tz->trips.passive.flags.valid) ++ s += sprintf(s, "%lu\n", tz->trips.passive.tsp); ++ ++ return (s - buf); ++} ++ ++/*_TC1*/ ++static THERMAL_DEVICE_ATTR(tc1, 0444, acpi_thermal_tc1_show, NULL); ++/*_TC2*/ ++static THERMAL_DEVICE_ATTR(tc2, 0444, acpi_thermal_tc2_show, NULL); ++/*_TSP*/ ++static THERMAL_DEVICE_ATTR(tsp, 0444, acpi_thermal_tsp_show, NULL); ++ ++static struct thermal_device_attribute *thermal_device_attrs[] = { ++ &thermal_device_attr_tc1, ++ &thermal_device_attr_tc2, ++ &thermal_device_attr_tsp, ++ NULL, ++}; ++ ++/* ++ * acpi_thermal_sysfs_register ++ * ---------------------------- ++ * Takes care of registering the zone,_TZD,_PSL,_ALx and extra attributes ++ * with the thermal_sysfs driver. ++ */ ++static int acpi_thermal_sysfs_register(struct acpi_thermal *tz) ++{ ++ int i, j; ++ int result = 0; ++ char *attrib_name[ACPI_THERMAL_MAX_ACTIVE]; ++ struct thermal_device *td; ++ ++ if (!tz) ++ return -EINVAL; ++ ++ /* TZ registration */ ++ td = thermal_device_register(tz->name, tz, &acpi_thermal_ops); ++ if (IS_ERR(td)) ++ return PTR_ERR(td); ++ ++ tz->td = td; ++ ++ /*_PSL group registration */ ++ if (tz->trips.passive.flags.valid) { ++ result = ++ acpi_thermal_one_group_register(tz, ACPI_THERMAL_GROUP_PSL, ++ &tz->trips.passive.devices); ++ if (result) ++ goto end; ++ ++ /*_TC1,_TC2,_TSP attribute registration */ ++ thermal_attribute_register(tz->td, thermal_device_attrs); ++ } ++ ++ /*_TZD registration */ ++ if (tz->flags.devices) { ++ result = ++ acpi_thermal_one_group_register(tz, ACPI_THERMAL_GROUP_TZD, ++ &tz->devices); ++ if (result) ++ goto end; ++ } ++ ++ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { ++ if (tz->trips.active[i].flags.valid) { ++ char *list_name = ACPI_THERMAL_GROUP_ALX; ++ list_name[strlen(ACPI_THERMAL_GROUP_ALX) - 1] = ++ ('0' + i); ++ ++ /*_ALx group registration */ ++ result = ++ acpi_thermal_one_group_register(tz, list_name, ++ &tz->trips. ++ active[i].devices); ++ if (result) { ++ for (j = i - 1; j > 0; j--) { ++ if (tz->trips.active[j].flags.valid) ++ kfree( ++ tz-> ++ thermal_device_active_attr ++ [j]); ++ } ++ goto end; ++ } ++ attrib_name[i] = ACPI_THERMAL_TRIP_ACTIVE; ++ attrib_name[i][strlen(ACPI_THERMAL_TRIP_ACTIVE) - 1] = ++ ('0' + i); ++ ++ tz->thermal_device_active_attr[i] = ++ kzalloc(sizeof(struct thermal_device_attribute), ++ GFP_KERNEL); ++ tz->thermal_device_active_attr[i]->attr.name = ++ attrib_name[i]; ++ tz->thermal_device_active_attr[i]->attr.mode = 0444; ++ tz->thermal_device_active_attr[i]->attr.owner = ++ THIS_MODULE; ++ tz->thermal_device_active_attr[i]->show = ++ acpi_thermal_sysfs_get_active; ++ } ++ } ++ ++ tz->thermal_device_active_attr[i + 1] = NULL; ++ ++ /* _ACx attribute registration */ ++ if (thermal_attribute_register(tz->td ++ , tz->thermal_device_active_attr)) { ++ thermal_attribute_unregister(tz->td, ++ tz->thermal_device_active_attr); ++ ++ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { ++ if (tz->trips.active[i].flags.valid) ++ kfree(tz->thermal_device_active_attr[i]); ++ ++ } ++ } ++ ++end: ++ if (result) ++ thermal_device_unregister(tz->td); ++ ++ ++ return result; ++} ++ ++/* ++ * acpi_thermal_sysfs_unregister ++ * ---------------------------- ++ * Takes care of unregistering the zone,_TZD,_PSL,_ALx and extra attributes ++ * with the thermal_sysfs driver. ++ */ ++static void acpi_thermal_sysfs_unregister(struct acpi_thermal *tz) ++{ ++ int i; ++ ++ if (!tz || !tz->td) ++ return; ++ ++ /*_PSL unregistration with thermal_sysfs driver */ ++ if (tz->trips.passive.flags.valid) { ++ thermal_group_unregister(tz->td, ACPI_THERMAL_GROUP_PSL); ++ ++ /* _TC1,_TC2,_TSP attribute unregistration */ ++ thermal_attribute_unregister(tz->td, thermal_device_attrs); ++ } ++ ++ /*_TZD unregistration with thermal_sysfs driver */ ++ if (tz->flags.devices) ++ thermal_group_unregister(tz->td, ACPI_THERMAL_GROUP_TZD); ++ ++ /* _ACx attribute unregistration */ ++ thermal_attribute_unregister(tz->td, tz->thermal_device_active_attr); ++ ++ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { ++ if (tz->trips.active[i].flags.valid) { ++ char *group_name = ACPI_THERMAL_GROUP_ALX; ++ group_name[strlen(ACPI_THERMAL_GROUP_ALX) - 1] = ++ ('0' + i); ++ ++ /* _ALx group unregistration */ ++ thermal_group_unregister(tz->td, group_name); ++ kfree(tz->thermal_device_active_attr[i]); ++ } ++ } ++ ++ /* Thermal zone un registration */ ++ thermal_device_unregister(tz->td); ++ ++} ++ + static int acpi_thermal_add(struct acpi_device *device) + { + int result = 0; +@@ -1268,6 +1761,10 @@ static int acpi_thermal_add(struct acpi_device *device) + if (result) + goto end; + ++ result = acpi_thermal_sysfs_register(tz); ++ if (result) ++ goto end; ++ + init_timer(&tz->timer); + + acpi_thermal_check(tz); +@@ -1287,6 +1784,7 @@ static int acpi_thermal_add(struct acpi_device *device) + end: + if (result) { + acpi_thermal_remove_fs(device); ++ acpi_thermal_sysfs_unregister(tz); + kfree(tz); + } + +@@ -1329,7 +1827,9 @@ static int acpi_thermal_remove(struct acpi_device *device, int type) + } + + acpi_thermal_remove_fs(device); ++ acpi_thermal_sysfs_unregister(tz); + mutex_destroy(&tz->lock); ++ + kfree(tz); + return 0; + } +-- +1.5.3.7-dirty + --- linux-2.6.24.orig/debian/binary-custom.d/lpiacompat/patchset/0001-Generic-sysfs-thermal-management-driver.patch +++ linux-2.6.24/debian/binary-custom.d/lpiacompat/patchset/0001-Generic-sysfs-thermal-management-driver.patch @@ -0,0 +1,46 @@ +From 59608b6d0fcd56fb1d0080da934cef57126d4f5c Mon Sep 17 00:00:00 2001 +From: Sujith Thomas +Date: Wed, 12 Dec 2007 10:37:33 +0530 +Subject: [PATCH] Generic sysfs thermal management driver + +Signed-off-by: Sujith Thomas +--- + arch/x86/Kconfig | 9 +++++++++ + drivers/base/Makefile | 1 + + 2 files changed, 10 insertions(+), 0 deletions(-) + +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index 391cb18..1a9e3b9 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -1228,6 +1228,15 @@ config ARCH_HIBERNATION_HEADER + + source "kernel/power/Kconfig" + ++config THERMAL_SYSFS ++ tristate "Thermal Management support" ++ default y ++ ---help--- ++ Support thermal management in Sysfs. Thermal devices(sensors) ++ are exposed to sysfs with relevant attributes so that a user app ++ can do thermal management for the platform. ++ ++ + source "drivers/acpi/Kconfig" + + menuconfig APM +diff --git a/drivers/base/Makefile b/drivers/base/Makefile +index b39ea3f..14884cd 100644 +--- a/drivers/base/Makefile ++++ b/drivers/base/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_NUMA) += node.o + obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o + obj-$(CONFIG_SMP) += topology.o + obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o ++obj-$(CONFIG_THERMAL_SYSFS) += thermal_sysfs.o + + ifeq ($(CONFIG_DEBUG_DRIVER),y) + EXTRA_CFLAGS += -DDEBUG +-- +1.5.3.7-dirty + --- linux-2.6.24.orig/debian/binary-custom.d/lpiacompat/patchset/0005-Generic-fan-and-memory-controller-sysfs-class-driver.patch +++ linux-2.6.24/debian/binary-custom.d/lpiacompat/patchset/0005-Generic-fan-and-memory-controller-sysfs-class-driver.patch @@ -0,0 +1,660 @@ +From 4a26addbee545f99828cbc7bee1e2b493c890c75 Mon Sep 17 00:00:00 2001 +From: Sujith Thomas +Date: Wed, 12 Dec 2007 11:00:06 +0530 +Subject: [PATCH] Generic fan and memory controller sysfs class driver + +Signed-off-by: Sujith Thomas + +header files for generic fan and memory_controller sysfs class drivers +Generic fan sysfs driver: exposes state & max_state attributes +Generic memory controller sysfs driver : exposes state & max_state attributes +--- + drivers/sysfsclass/Kconfig | 30 +++++ + drivers/sysfsclass/Makefile | 7 ++ + drivers/sysfsclass/fan_sysfs.c | 210 +++++++++++++++++++++++++++++++++++++ + drivers/sysfsclass/memory_sysfs.c | 208 ++++++++++++++++++++++++++++++++++++ + include/linux/fan.h | 66 ++++++++++++ + include/linux/memory_controller.h | 75 +++++++++++++ + 6 files changed, 596 insertions(+), 0 deletions(-) + create mode 100644 drivers/sysfsclass/Kconfig + create mode 100644 drivers/sysfsclass/Makefile + create mode 100644 drivers/sysfsclass/fan_sysfs.c + create mode 100644 drivers/sysfsclass/memory_sysfs.c + create mode 100644 include/linux/fan.h + create mode 100644 include/linux/memory_controller.h + +diff --git a/drivers/sysfsclass/Kconfig b/drivers/sysfsclass/Kconfig +new file mode 100644 +index 0000000..ea02da6 +--- /dev/null ++++ b/drivers/sysfsclass/Kconfig +@@ -0,0 +1,30 @@ ++ ++menu "Sysfs device class support" ++ ++config SYSFS_DEV_CLASS ++ bool "Sysfs device class support" ++ default y ++ help ++ Say Y to enable sysfs class driver support for the below devices. ++ ++config FAN_SYSFS ++ tristate "Fan class in sysfs" ++ default y ++ depends on SYSFS_DEV_CLASS ++ help ++ This option enables the support for controlling a generic fan ++ from sysfs. Sysfs will have attributes to switch the ++ fan speed into different supported states. ++ ++config MEMORY_SYSFS ++ tristate "Memory class in sysfs" ++ default y ++ depends on SYSFS_DEV_CLASS ++ help ++ This option enables the support for controlling a generic ++ memory controller from sysfs. Sysfs will have attributes ++ to control the bandwidth of memory controller. ++ ++ ++endmenu ++ +diff --git a/drivers/sysfsclass/Makefile b/drivers/sysfsclass/Makefile +new file mode 100644 +index 0000000..293b5b4 +--- /dev/null ++++ b/drivers/sysfsclass/Makefile +@@ -0,0 +1,7 @@ ++# ++# Makefile for the sysfs class device driver support ++# ++ ++ ++obj-$(CONFIG_FAN_SYSFS) += fan_sysfs.o ++obj-$(CONFIG_MEMORY_SYSFS) += memory_sysfs.o +diff --git a/drivers/sysfsclass/fan_sysfs.c b/drivers/sysfsclass/fan_sysfs.c +new file mode 100644 +index 0000000..f345c71 +--- /dev/null ++++ b/drivers/sysfsclass/fan_sysfs.c +@@ -0,0 +1,210 @@ ++/* ++* fan.c - Fan sysfs driver ($Revision: 1 $) ++* ++* Copyright (C) 2006, 2007 Sujith Thomas ++* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++* ++* 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; version 2 of the License. ++* ++* This program is distributed in the hope that it will be useful, but ++* WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++* General Public License for more details. ++* ++* You should have received a copy of the GNU General Public License along ++* with this program; if not, write to the Free Software Foundation, Inc., ++* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++* ++* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++* Sysfs class driver for fan devices. Exposes attributes for get/set ++* fan speed. ++* ++* ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Sujith Thomas"); ++MODULE_DESCRIPTION("Fan sysfs Driver"); ++MODULE_LICENSE("GPL"); ++ ++static ssize_t state_show(struct class_device *cdev, char *buf) ++{ ++ struct fan_device *fd; ++ int result; ++ if (!cdev || !buf) ++ return 0; ++ ++ fd = to_fan_device(cdev); ++ if (fd->ops && fd->ops->get_cur_state) { ++ result = fd->ops->get_cur_state(fd, buf); ++ if (result) ++ return result; ++ } ++ ++ return strlen(buf); ++} ++ ++static ssize_t state_store(struct class_device *cdev, const char *buf, ++ size_t count) ++{ ++ struct fan_device *fd; ++ int result; ++ ++ if (!cdev || !buf) ++ return count; ++ ++ fd = to_fan_device(cdev); ++ if (fd->ops && fd->ops->set_cur_state) { ++ result = fd->ops->set_cur_state(fd, buf); ++ printk("Fan store result is %d\n",result); ++ if (result) ++ return result; ++ } ++ ++ return count; ++} ++ ++static ssize_t max_state_show(struct class_device *cdev, char *buf) ++{ ++ struct fan_device *fd; ++ int result; ++ if (!cdev || !buf) ++ return 0; ++ ++ fd = to_fan_device(cdev); ++ if (fd->ops && fd->ops->get_max_state) { ++ result = fd->ops->get_max_state(fd, buf); ++ if (result) ++ return result; ++ } ++ ++ return strlen(buf); ++} ++ ++static void fan_class_release(struct class_device *dev) ++{ ++ struct fan_device *device = to_fan_device(dev); ++ kfree(device); ++} ++ ++static struct class fan_class = { ++ .name = "fan", ++ .release = fan_class_release, ++}; ++ ++static CLASS_DEVICE_ATTR(state, 0644, state_show, state_store); ++static CLASS_DEVICE_ATTR(max_state, 0444, max_state_show, NULL); ++ ++static const struct class_device_attribute *fd_class_dev_attribs[] = { ++ &class_device_attr_state, ++ &class_device_attr_max_state, ++}; ++ ++/* ++ * fan_device_register ++ * -------------------------------- ++ * Method for registering fan class of devices with sysfs ++ * name: The name that should appear in sysfs ++ * dev : device* on which sysfs folder should appear ++ * devdata : Device private context ++ * ops : List of call back functions for various attributes ++ * Returns either an ++ * ERR_PTR() or a pointer to the newly allocated device. ++ */ ++struct fan_device *fan_device_register(const char *name, ++ struct device *dev, ++ void *devdata, struct fan_ops *ops) ++{ ++ int i, rc; ++ struct fan_device *new_fd; ++ ++ if (!name || !ops) ++ return ERR_PTR(-EINVAL); ++ ++ pr_debug("fan_device_alloc: name=%s\n", name); ++ ++ new_fd = kzalloc(sizeof(struct fan_device), GFP_KERNEL); ++ if (!new_fd) ++ return ERR_PTR(-ENOMEM); ++ ++ new_fd->ops = ops; ++ new_fd->class_dev.class = &fan_class; ++ new_fd->class_dev.dev = dev; ++ strlcpy(new_fd->class_dev.class_id, name, KOBJ_NAME_LEN); ++ class_set_devdata(&new_fd->class_dev, devdata); ++ ++ rc = class_device_register(&new_fd->class_dev); ++ if (rc) { ++ kfree(new_fd); ++ return ERR_PTR(rc); ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(fd_class_dev_attribs); i++) { ++ rc = class_device_create_file(&new_fd->class_dev, ++ fd_class_dev_attribs[i]); ++ if (rc) { ++ while (--i >= 0) ++ class_device_remove_file(&new_fd->class_dev, ++ fd_class_dev_attribs ++ [i]); ++ class_device_unregister(&new_fd->class_dev); ++ /* No need to kfree(new_bd) since release() ++ method was called */ ++ return ERR_PTR(rc); ++ } ++ } ++ ++ return new_fd; ++} ++EXPORT_SYMBOL(fan_device_register); ++ ++/* ++ * fan_device_unregister ++ * ---------------------------------- ++ * Method for unregistering fan devices with sysfs ++ * fd: Pointer to fan device ++ */ ++void fan_device_unregister(struct fan_device *fd) ++{ ++ int i; ++ ++ if (!fd) ++ return; ++ ++ pr_debug("fan_device_unregister: name=%s\n", fd->class_dev.class_id); ++ ++ for (i = 0; i < ARRAY_SIZE(fd_class_dev_attribs); i++) ++ class_device_remove_file(&fd->class_dev, ++ fd_class_dev_attribs[i]); ++ ++ fd->ops = NULL; ++ ++ class_device_unregister(&fd->class_dev); ++} ++EXPORT_SYMBOL(fan_device_unregister); ++ ++static int __init fan_device_init(void) ++{ ++ return class_register(&fan_class); ++} ++ ++static void __exit fan_device_exit(void) ++{ ++ class_unregister(&fan_class); ++} ++ ++/* ++ * if this is compiled into the kernel, we need to ensure that the ++ * class is registered before users of the class try to register lcd's ++ */ ++ ++postcore_initcall(fan_device_init); ++module_exit(fan_device_exit); +diff --git a/drivers/sysfsclass/memory_sysfs.c b/drivers/sysfsclass/memory_sysfs.c +new file mode 100644 +index 0000000..6642336 +--- /dev/null ++++ b/drivers/sysfsclass/memory_sysfs.c +@@ -0,0 +1,208 @@ ++/* ++* memory_controller.c - Memory controller sysfs driver ($Revision: 1 $) ++* ++* Copyright (C) 2006, 2007 Sujith Thomas ++* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++* ++* 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; version 2 of the License. ++* ++* This program is distributed in the hope that it will be useful, but ++* WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++* General Public License for more details. ++* ++* You should have received a copy of the GNU General Public License along ++* with this program; if not, write to the Free Software Foundation, Inc., ++* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++* ++* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++* Sysfs class driver for memory_controller. Exposes attributes for get/set ++* memory bandwidth ++* ++* ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Sujith Thomas"); ++MODULE_DESCRIPTION("Memory controller sysfs Driver"); ++MODULE_LICENSE("GPL"); ++ ++static ssize_t bandwidth_show(struct class_device *cdev, char *buf) ++{ ++ struct memory_controller_device *mc; ++ int result; ++ ++ if (!cdev || !buf) ++ return 0; ++ ++ mc = to_memory_controller_device(cdev); ++ if (mc->ops && mc->ops->get_cur_bandwidth) { ++ result = mc->ops->get_cur_bandwidth(mc, buf); ++ if (result) ++ return result; ++ } ++ ++ return strlen(buf); ++} ++ ++static ssize_t bandwidth_store(struct class_device *cdev, const char *buf, ++ size_t count) ++{ ++ struct memory_controller_device *mc; ++ int result; ++ if (!cdev || !buf) ++ return count; ++ ++ mc = to_memory_controller_device(cdev); ++ if (mc->ops && mc->ops->set_cur_bandwidth) { ++ result = mc->ops->set_cur_bandwidth(mc, buf); ++ if (result) ++ return result; ++ } ++ ++ return count; ++} ++ ++static ssize_t max_bandwidth_show(struct class_device *cdev, char *buf) ++{ ++ struct memory_controller_device *mc; ++ int result; ++ if (!cdev || !buf) ++ return 0; ++ ++ mc = to_memory_controller_device(cdev); ++ if (mc->ops && mc->ops->get_max_bandwidth) { ++ result = mc->ops->get_max_bandwidth(mc, buf); ++ if (result) ++ return result; ++ } ++ ++ return strlen(buf); ++} ++ ++static void memory_controller_class_release(struct class_device *dev) ++{ ++ struct memory_controller_device *device = ++ to_memory_controller_device(dev); ++ kfree(device); ++} ++ ++static struct class memory_controller_class = { ++ .name = "memory_controller", ++ .release = memory_controller_class_release, ++}; ++ ++static CLASS_DEVICE_ATTR(state, 0644, bandwidth_show, bandwidth_store); ++static CLASS_DEVICE_ATTR(max_state, 0444, max_bandwidth_show, NULL); ++ ++static const struct class_device_attribute *mc_class_dev_attribs[] = { ++ &class_device_attr_state, ++ &class_device_attr_max_state, ++}; ++ ++/* ++ * memory_controller_device_register ++ * -------------------------------- ++ * Method for registering memory_controller class of devices with sysfs ++ * name: The name that should appear in sysfs ++ * dev : device* on which sysfs folder should appear ++ * devdata : Device private context ++ * ops : List of call back functions for various attributes ++ * Returns either an ++ * ERR_PTR() or a pointer to the newly allocated device. ++ */ ++struct memory_controller_device * ++memory_controller_device_register(const char *name ++ , struct device *dev ++ , void *devdata ++ , struct memory_controller_ops *ops) ++{ ++ int i, rc; ++ struct memory_controller_device *new_mc; ++ ++ if (!name || !ops) ++ return ERR_PTR(-EINVAL); ++ ++ pr_debug("memory_controller_device_alloc: name=%s\n", name); ++ ++ new_mc = kzalloc(sizeof(struct memory_controller_device), GFP_KERNEL); ++ if (!new_mc) ++ return ERR_PTR(-ENOMEM); ++ ++ new_mc->ops = ops; ++ new_mc->class_dev.class = &memory_controller_class; ++ new_mc->class_dev.dev = dev; ++ strlcpy(new_mc->class_dev.class_id, name, KOBJ_NAME_LEN); ++ class_set_devdata(&new_mc->class_dev, devdata); ++ ++ rc = class_device_register(&new_mc->class_dev); ++ if (rc) { ++ kfree(new_mc); ++ return ERR_PTR(rc); ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(mc_class_dev_attribs); i++) { ++ rc = class_device_create_file(&new_mc->class_dev, ++ mc_class_dev_attribs[i]); ++ if (rc) { ++ while (--i >= 0) ++ class_device_remove_file(&new_mc->class_dev, ++ mc_class_dev_attribs ++ [i]); ++ class_device_unregister(&new_mc->class_dev); ++ /* No need to kfree(new_bd) since release() ++ method was called */ ++ return ERR_PTR(rc); ++ } ++ } ++ ++ return new_mc; ++} ++EXPORT_SYMBOL(memory_controller_device_register); ++ ++/* ++ * memory_controller_device_unregister ++ * ---------------------------------- ++ * Method for unregistering memory_controller devices with sysfs ++ * mc: Pointer to memory_controller device ++ */ ++void memory_controller_device_unregister(struct memory_controller_device *mc) ++{ ++ int i; ++ ++ if (!mc) ++ return; ++ ++ pr_debug("memory_controller_device_unregister: name=%s\n", ++ mc->class_dev.class_id); ++ ++ for (i = 0; i < ARRAY_SIZE(mc_class_dev_attribs); i++) ++ class_device_remove_file(&mc->class_dev, ++ mc_class_dev_attribs[i]); ++ ++ mc->ops = NULL; ++ ++ class_device_unregister(&mc->class_dev); ++} ++EXPORT_SYMBOL(memory_controller_device_unregister); ++ ++static int __init memory_controller_device_init(void) ++{ ++ return class_register(&memory_controller_class); ++} ++ ++static void __exit memory_controller_device_exit(void) ++{ ++ class_unregister(&memory_controller_class); ++} ++ ++module_init(memory_controller_device_init); ++module_exit(memory_controller_device_exit); +diff --git a/include/linux/fan.h b/include/linux/fan.h +new file mode 100644 +index 0000000..dd37067 +--- /dev/null ++++ b/include/linux/fan.h +@@ -0,0 +1,66 @@ ++/* ++* fan.h - Generic fan driver for sysfs ($Revision: 1 $) ++* ++* Copyright (C) 2006, 2007 Sujith Thomas ++* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++* ++* 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; version 2 of the License. ++* ++* This program is distributed in the hope that it will be useful, but ++* WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++* General Public License for more details. ++* ++* You should have received a copy of the GNU General Public License along ++* with this program; if not, write to the Free Software Foundation, Inc., ++* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++* ++* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++* Sysfs class driver for fan devices. Exposes attributes for get/set ++* fan speed. ++* ++* ++*/ ++ ++#include ++ ++struct fan_device; ++ ++struct fan_ops { ++ int (*get_max_state) (struct fan_device *device, char *buf); ++ int (*get_cur_state) (struct fan_device *device, char *buf); ++ int (*set_cur_state) (struct fan_device *device, const char *buf); ++}; ++ ++struct fan_device { ++ struct fan_ops *ops; ++ struct class sysfs_class; /* '/sys/class' entry */ ++ struct class_device class_dev; /*class device entry in sys/class*/ ++}; ++ ++/* ++ * fan_device_register ++ * -------------------------------- ++ * Method for registering fan class of devices with sysfs ++ * name: The name that should appear in sysfs ++ * dev : device* on which sysfs folder should appear ++ * devdata : Device private context ++ * ops : List of call back functions for various attributes ++ * Returns either an ++ * ERR_PTR() or a pointer to the newly allocated device. ++ */ ++struct fan_device *fan_device_register(const char *name, ++ struct device *dev, void *devdata, ++ struct fan_ops *ops); ++ ++/* ++ * fan_device_unregister ++ * ---------------------------------- ++ * Method for unregistering fan devices with sysfs ++ * fd: Pointer to fan device ++ */ ++void fan_device_unregister(struct fan_device *device); ++ ++#define to_fan_device(obj) container_of(obj, struct fan_device, class_dev) +diff --git a/include/linux/memory_controller.h b/include/linux/memory_controller.h +new file mode 100644 +index 0000000..a7564c8 +--- /dev/null ++++ b/include/linux/memory_controller.h +@@ -0,0 +1,75 @@ ++/* ++* memory_controller.h - Generic memory controller driver for sysfs ++* ($Revision: 1 $) ++* ++* Copyright (C) 2006, 2007 Sujith Thomas ++* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++* ++* 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; version 2 of the License. ++* ++* This program is distributed in the hope that it will be useful, but ++* WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++* General Public License for more details. ++* ++* You should have received a copy of the GNU General Public License along ++* with this program; if not, write to the Free Software Foundation, Inc., ++* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++* ++* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++* Sysfs class driver for memory_controller. Exposes attributes for get/set ++* memory bandwidth ++* ++* ++*/ ++ ++#include ++ ++struct memory_controller_device; ++ ++/* Callback functions to the actual memory device driver */ ++struct memory_controller_ops { ++ int (*get_max_bandwidth) (struct memory_controller_device *device, ++ char *buf); ++ int (*get_cur_bandwidth) (struct memory_controller_device *device, ++ char *buf); ++ int (*set_cur_bandwidth) (struct memory_controller_device *device, ++ const char *buf); ++}; ++ ++struct memory_controller_device { ++ struct memory_controller_ops *ops; /* Callback routines */ ++ struct class sysfs_class; /* '/sys/class' entry*/ ++ struct class_device class_dev; /*class device entry in sys/class*/ ++}; ++ ++/* ++ * memory_controller_device_register ++ * -------------------------------- ++ * Method for registering memory_controller class of devices with sysfs ++ * name: The name that should appear in sysfs ++ * dev : device* on which sysfs folder should appear ++ * devdata : Device private context ++ * ops : List of call back functions for various attributes ++ * Returns either an ++ * ERR_PTR() or a pointer to the newly allocated device. ++ */ ++struct memory_controller_device * ++memory_controller_device_register(const char *name ++ , struct device *dev ++ , void *devdata ++ , struct memory_controller_ops *ops); ++ ++/* ++ * memory_controller_device_unregister ++ * ---------------------------------- ++ * Method for unregistering memory_controller devices with sysfs ++ * mc: Pointer to memory_controller device ++ */ ++void memory_controller_device_unregister(struct memory_controller_device ++ *device); ++ ++#define to_memory_controller_device(obj) \ ++container_of(obj, struct memory_controller_device, class_dev) +-- +1.5.3.7-dirty + --- linux-2.6.24.orig/debian/binary-custom.d/lpiacompat/patchset/0004-Documentation-for-thermal-extensions.patch +++ linux-2.6.24/debian/binary-custom.d/lpiacompat/patchset/0004-Documentation-for-thermal-extensions.patch @@ -0,0 +1,219 @@ +From e5654bce3a3fa6b9fd7b3673e5cae97a00f37be6 Mon Sep 17 00:00:00 2001 +From: Sujith Thomas +Date: Wed, 12 Dec 2007 10:55:35 +0530 +Subject: [PATCH] Documentation for thermal extensions + +Signed-off-by: Sujith Thomas + +Documentation for thermal extensions +--- + Documentation/ThermalExtensions.txt | 197 +++++++++++++++++++++++++++++++++++ + 1 files changed, 197 insertions(+), 0 deletions(-) + create mode 100644 Documentation/ThermalExtensions.txt + +diff --git a/Documentation/ThermalExtensions.txt b/Documentation/ThermalExtensions.txt +new file mode 100644 +index 0000000..87e7811 +--- /dev/null ++++ b/Documentation/ThermalExtensions.txt +@@ -0,0 +1,197 @@ ++Thermal extensions How-to ++========================= ++ ++Written by Sujith Thomas ++ ++Updated: 18 October 2007 ++ ++Copyright (c) 2007 Intel Corporation ++ ++ ++0. Introduction ++ ++The thermal extensions provide a set of interfaces for thermal devices (sensors) ++to register with the thermal management solution and to be a part of it. ++This how-to focusses on enabling a new sensor to participate ++in thermal management. ++ ++Thermal extensions expose a set of interfaces for sensor drivers to expose ++their attributes as well as devices associated with this sensor. This solution ++is platform independent and any type of sensor should be able to make use of the ++infrastructure. ++ ++The main task of the thermal extensions is to expose sensor attributes as well ++as thermal events to the user space. In addition, attributes for controlling ++devices associated with a sensor is also exposed through sysfs. An intelligent ++thermal management application can make decisions based on inputs from sensor and ++throttle appropriate devices. ++ ++1. Sysfs directory structure ++ ++ The sysfs entry will be made under /sys/thermal and it will have the ++ following group of attributes. ++ ++ -/sys/thermal/config (thermal management related configuration) ++ -/sys/thermal/ (thermal zone related data) ++ -/sys/thermal// (info about a device in a thermal zone) ++ ++ 1.1 /sys/thermal/config ++ ++ This folder has the following attributes ++ ++ -mode (user = user-space thermal managemnt ; kernel = kernel-space thermal management) ++ -userenabled (0 if kernel is not willing to give control to application else 1) ++ ++ ++ 1.2 /sys/thermal/ ++ ++ The below attributes will appear for all thermal devices (sensors) ++ ++ -critical (critical temperature at which system will shutdown) ++ -hot (temperature at which system will hibernate) ++ -passive (temperature at which passive cooling will be started) ++ -temperature (current temperature) ++ -cooling_mode (active/passive) ++ -polling_freq (frequency at which sensor is polled for temperature changes) ++ -state (ok/critical/hot/passive/active[x]) ++ ++ The below attributes will appear only if Intel's platform sensor ++ driver is loaded. ++ ++ -aux0 (lower AUX value interface for platform sensor driver) ++ -aux1 (upper AUX value interface for platform sensor driver) ++ ++ 1.3 /sys/thermal// ++ ++ 'Group' entry depends on the registration of groups from 'thermal device driver'. ++ In the case of ACPI thermal driver, groups like 'thermalzone_devices', ++ 'active_device' & 'passive_devices' are created and devices are filled on ++ basis of what BIOS reports. ++ ++2. Thermal device interface functions ++ ================================== ++ ++There are a set of interface functions available for 'thermal device driver' to ++register with 'thermal sysfs driver'. 'Thermal device driver' is the driver ++which directly interacts with the sensor and has the list of devices associated ++with this sensor. 'Thermal sysfs driver' is the driver for exposing attributes ++of various sensors to userspace through sysfs. ++ ++2.1 thermal_device_register ++/* ++ * thermal_device_register ++ * ------------------------ ++ * Method for registering thermal devices(sensors) with sysfs ++ * name: The name that should appear in sysfs ++ * devdata : Device private context ++ * ops : List of call back functions for various attributes ++ */ ++ ++ This interface is used by 'Thermal device driver' to make an entry of the new ++ sensor to /sys/thermal folder. This step is mandatory. ++ ++2.2 thermal_group_register ++/* ++ * thermal_group_register ++ * ------------------------ ++ * Method for registering groups such as ACPI _TZD with sysfs ++ * name: The name that should appear in sysfs ++ * td : Device under which this group is to be created ++ * participant_count : No:of participants in this group ++ * participants: Pointer to an array of participants ++ */ ++ This interface is used by 'Thermal device driver' to register a new 'group' ++ of devices. Example for groups are 'active devices' , 'passive devices' etc. ++ This step needs to be done only if there are a set of devices associated ++ with this sensor. ++ ++2.3 thermal_attribute_register ++ /* ++ * thermal_attribute_register ++ * ------------------------ ++ * Method for registering extra attributes with sysfs ++ * td : Device under which attributes should be created ++ * thermal_device_attrs : array of attributes to be added ++ */ ++ This interface is used by 'Thermal device driver' to expose some of extra ++ attributes (other than standard attributes defined in thermal.h) with sysfs. ++ ++2.4 thermal_event_register ++ /* ++ * thermal_event_register ++ * ---------------------- ++ * Register for add/rmv of device/group/participant notification ++ * handler: thermal_event_handler containing callback func pointer ++ * report_type: Set this flag if callbacks needs to be invoked ++ * for existing device/group/participants ++ */ ++ This inteface can be used by any driver to get notification about add/remove ++ of entities like 'thermal device', 'group' or 'devices within a group'. ++ ++2.5 thermal_device_unregister ++ /* ++ * thermal_device_unregister ++ * ------------------------ ++ * Method for unregistering thermal devices(sensors) with sysfs ++ * td: Pointer to thermal_device ++ */ ++ ++2.6 thermal_group_unregister ++ /* ++ * thermal_group_unregister ++ * ------------------------ ++ * Method for unregistering groups within a thermal device ++ * td: Pointer to thermal_device from where the group should be removed ++ * name : Name of the group given during registration ++ */ ++ ++2.7 thermal_attribute_unregister ++ /* ++ * thermal_attribute_unregister ++ * ------------------------ ++ * Method for unregistering extra attributes with sysfs ++ * td : Device under which attributes should be removed ++ * thermal_device_attrs : array of attributes to be removed ++ */ ++ ++2.8 thermal_event_unregister ++ /* ++ * thermal_event_unregister ++ * ---------------------- ++ * UnRegister for add/rmv of device/group/participant notification ++ * handler: thermal_event_handler containing callback func pointer ++ * report_type: Set this flag if callbacks needs to be invoked ++ * for existing device/group/participants ++ */ ++ ++2.9 thermal_sysfs_generate_event ++ /* ++ * thermal_sysfs_generate_event ++ * --------------------------- ++ * Drivers managing thermal devices can invoke this method to notify ++ * user applications about thermal events ++ */ ++ This interface can be used by 'thermal device drivers' to sent a ++ notification about trip point events to the user application. ++ ++2.10 thermal_get_algo_mode ++ /* ++ * thermal_get_algo_mode ++ * ---------------------- ++ * Method to know whether the user mode application has taken over ++ */ ++ ++2.11 thermal_set_userenabled ++ /* ++ * thermal_set_userenabled ++ * ----------------------- ++ * Interface function for platform sensor driver to disble userspace algo ++ * ue: enable / disable userspace algo based on BIOS configuration ++ */ ++ This can be called by any driver to prevent the overriding of thermal ++ management from userspace. One scenario is to call this API based on ++ enable/disable option given in BIOS. ++ ++ ++ ++ +-- +1.5.3.7-dirty + --- linux-2.6.24.orig/debian/binary-custom.d/lpiacompat/patchset/0008-ACPI-fan-driver-registering-with-fan_sysfs-driver.patch +++ linux-2.6.24/debian/binary-custom.d/lpiacompat/patchset/0008-ACPI-fan-driver-registering-with-fan_sysfs-driver.patch @@ -0,0 +1,187 @@ +From 990abc4c7483a92bddfffe16fa5da64f81d89c22 Mon Sep 17 00:00:00 2001 +From: Sujith Thomas +Date: Wed, 12 Dec 2007 11:15:44 +0530 +Subject: [PATCH] ACPI fan driver registering with fan_sysfs driver + +Signed-off-by: Sujith Thomas + +Callbacks for 'state' & 'max_state' attributes +--- + drivers/acpi/Kconfig | 1 + + drivers/acpi/fan.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 107 insertions(+), 1 deletions(-) + +diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig +index b065d16..0ab6c35 100644 +--- a/drivers/acpi/Kconfig ++++ b/drivers/acpi/Kconfig +@@ -146,6 +146,7 @@ config ACPI_VIDEO + + config ACPI_FAN + tristate "Fan" ++ depends on FAN_SYSFS + default y + help + This driver adds support for ACPI fan devices, allowing user-mode +diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c +index a5a5532..00b7574 100644 +--- a/drivers/acpi/fan.c ++++ b/drivers/acpi/fan.c +@@ -33,6 +33,7 @@ + + #include + #include ++#include + + #define ACPI_FAN_COMPONENT 0x00200000 + #define ACPI_FAN_CLASS "fan" +@@ -64,6 +65,83 @@ static struct acpi_driver acpi_fan_driver = { + }, + }; + ++struct acpi_fan { ++ struct acpi_device *device; ++ struct fan_device *fd; ++}; ++ ++/* -------------------------------------------------------------------------- ++ FS Interface (/sys/class/fan) ++ -------------------------------------------------------------------------- */ ++ ++static int acpi_fan_get_max_state(struct fan_device*fd, char*buf) ++{ ++ struct acpi_fan *fan; ++ ++ if (!fd | !buf) ++ return -EINVAL; ++ ++ fan = (struct acpi_fan *)class_get_devdata(&fd->class_dev); ++ ++ /*ACPI states*/ ++ if (fan) ++ buf += sprintf(buf, "%d\n", ACPI_D_STATES_MAX + 1); ++ else ++ buf += sprintf(buf, "%d\n", 0); ++ ++ return 0; ++} ++ ++static int acpi_fan_get_state(struct fan_device *fd, char *buf) ++{ ++ int state = 0; ++ struct acpi_fan *fan; ++ ++ if (!fd | !buf) ++ return -EINVAL; ++ ++ fan = (struct acpi_fan *)class_get_devdata(&fd->class_dev); ++ ++ /*ACPI supports only on/off*/ ++ if (fan) { ++ if (acpi_bus_get_power(fan->device->handle, &state)) ++ return -EFAULT; ++ else ++ buf += sprintf(buf, "%d\n", state); ++ } ++ ++ return 0; ++} ++ ++static int acpi_fan_set_state(struct fan_device *fd, const char *buf) ++{ ++ int state = 0; ++ int result = 0; ++ struct acpi_fan *fan; ++ ++ if (!fd | !buf) ++ return -EINVAL; ++ fan = (struct acpi_fan *)class_get_devdata(&fd->class_dev); ++ ++ if (!sscanf(buf, "%d", &state)) ++ return -EIO; ++ ++ if (state < 0 || state > ACPI_D_STATES_MAX) ++ return -EINVAL; ++ ++ result = acpi_bus_set_power(fan->device->handle, state); ++ if (result) ++ return result; ++ ++ return 0; ++} ++ ++static struct fan_ops acpi_fan_ops = { ++ .get_max_state = acpi_fan_get_max_state, ++ .get_cur_state = acpi_fan_get_state, ++ .set_cur_state = acpi_fan_set_state, ++}; ++ + /* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ +@@ -175,15 +253,23 @@ static int acpi_fan_remove_fs(struct acpi_device *device) + static int acpi_fan_add(struct acpi_device *device) + { + int result = 0; +- struct acpi_fan *fan = NULL; + int state = 0; ++ struct acpi_fan *fan = NULL; ++ struct fan_device *fd = NULL; ++ + + + if (!device) + return -EINVAL; + ++ fan = kzalloc(sizeof(struct acpi_fan), GFP_KERNEL); ++ if (!fan) ++ return -ENOMEM; ++ ++ fan->device = device; + strcpy(acpi_device_name(device), "Fan"); + strcpy(acpi_device_class(device), ACPI_FAN_CLASS); ++ acpi_driver_data(device) = fan; + + result = acpi_bus_get_power(device->handle, &state); + if (result) { +@@ -195,6 +281,16 @@ static int acpi_fan_add(struct acpi_device *device) + if (result) + goto end; + ++ fd = fan_device_register(device->pnp.bus_id, ++ &device->dev, fan, &acpi_fan_ops); ++ ++ if (IS_ERR(fd)) { ++ result = PTR_ERR(fd); ++ goto end; ++ } ++ ++ fan->fd = fd; ++ + printk(KERN_INFO PREFIX "%s [%s] (%s)\n", + acpi_device_name(device), acpi_device_bid(device), + !device->power.state ? "on" : "off"); +@@ -208,11 +304,20 @@ static int acpi_fan_add(struct acpi_device *device) + + static int acpi_fan_remove(struct acpi_device *device, int type) + { ++ struct acpi_fan *fan = NULL; ++ ++ + if (!device || !acpi_driver_data(device)) + return -EINVAL; + ++ fan = acpi_driver_data(device); ++ + acpi_fan_remove_fs(device); + ++ fan_device_unregister(fan->fd); ++ ++ kfree(fan); ++ + return 0; + } + +-- +1.5.3.7-dirty + --- linux-2.6.24.orig/debian/binary-custom.d/lpiacompat/patchset/0003-Generic-fan-and-memory-controller-sysfs-class-driver.patch +++ linux-2.6.24/debian/binary-custom.d/lpiacompat/patchset/0003-Generic-fan-and-memory-controller-sysfs-class-driver.patch @@ -0,0 +1,50 @@ +From 4cebaef75bdf97b58dca37c2b66efe835f7d9c06 Mon Sep 17 00:00:00 2001 +From: Sujith Thomas +Date: Wed, 12 Dec 2007 10:54:14 +0530 +Subject: [PATCH] Generic fan and memory controller sysfs class driver + +Signed-off-by: Sujith Thomas + +Generic sysfs fan driver: Exposes state & max_state attributes +Generic sysfs memory_controller driver : Exposes state & max_state attributes +--- + drivers/Kconfig | 3 ++- + drivers/Makefile | 1 + + 2 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/drivers/Kconfig b/drivers/Kconfig +index f4076d9..b535385 100644 +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -14,6 +14,8 @@ source "drivers/parport/Kconfig" + + source "drivers/pnp/Kconfig" + ++source "drivers/sysfsclass/Kconfig" ++ + source "drivers/block/Kconfig" + + # misc before ide - BLK_DEV_SGIIOC4 depends on SGI_IOC4 +@@ -87,7 +89,6 @@ source "drivers/rtc/Kconfig" + source "drivers/dma/Kconfig" + + source "drivers/dca/Kconfig" +- + source "drivers/auxdisplay/Kconfig" + + source "drivers/kvm/Kconfig" +diff --git a/drivers/Makefile b/drivers/Makefile +index 314f0df..e210b25 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -9,6 +9,7 @@ obj-$(CONFIG_PCI) += pci/ + obj-$(CONFIG_PARISC) += parisc/ + obj-$(CONFIG_RAPIDIO) += rapidio/ + obj-y += video/ ++obj-$(CONFIG_SYSFS_DEV_CLASS) += sysfsclass/ + obj-$(CONFIG_ACPI) += acpi/ + # PnP must come after ACPI since it will eventually need to check if acpi + # was used and do nothing if so +-- +1.5.3.7-dirty + --- linux-2.6.24.orig/debian/binary-custom.d/lpiacompat/patchset/0002-Generic-sysfs-thermal-management-driver.patch +++ linux-2.6.24/debian/binary-custom.d/lpiacompat/patchset/0002-Generic-sysfs-thermal-management-driver.patch @@ -0,0 +1,1465 @@ +From 318e393f719e1af17a91b234ddbbcab34c53ff2c Mon Sep 17 00:00:00 2001 +From: Sujith Thomas +Date: Wed, 12 Dec 2007 10:43:28 +0530 +Subject: [PATCH] Generic sysfs thermal management driver + +Signed-off-by: Sujith Thomas + +In a nutshell this patch provides an infrastructure for userspace application to handle +platform thermal managemetn +Adds a 'Config' folder for user mode application to take over kernel mode algo +--- + drivers/base/thermal_sysfs.c | 1139 ++++++++++++++++++++++++++++++++++++++++++ + include/linux/thermal.h | 294 +++++++++++ + 2 files changed, 1433 insertions(+), 0 deletions(-) + create mode 100644 drivers/base/thermal_sysfs.c + create mode 100644 include/linux/thermal.h + +diff --git a/drivers/base/thermal_sysfs.c b/drivers/base/thermal_sysfs.c +new file mode 100644 +index 0000000..8dd25a1 +--- /dev/null ++++ b/drivers/base/thermal_sysfs.c +@@ -0,0 +1,1139 @@ ++/* ++ * thermal_sysfs.c - Generic sysfs implementation for thermal subsystem ++ * ($Revision: 1 $) ++ * ++ * Copyright (C) 2006, 2007 Sujith Thomas ++ * ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * 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; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * Accepts registration of thermal devices(sensors). ++ * Accepts registration for group of participants associated with this sensor ++ * Accepts registration of extra attributes over the standard attributes. ++ * Issues notification to registered drivers upon registration of new thermal ++ * devices ++ * Adds a 'Config' folder for user mode application to take over kernel mode ++ * algo ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Sujith Thomas"); ++MODULE_DESCRIPTION("Generic thermal sysfs driver"); ++MODULE_LICENSE("GPL"); ++ ++static char *thermal_mode[THERMAL_MAX_MODE] = { ++ "user", ++ "kernel", ++}; ++ ++static struct thermal_config thermalconfig = { ++ .userenabled = THERMAL_USER_ENABLED, ++ .mode = THERMAL_KERNELSPACE, ++}; ++ ++/*Linked list of thermal devices*/ ++static LIST_HEAD(thermal_device_list); ++static LIST_HEAD(thermal_sysfs_event_listener_list); ++ ++/*Lock for accessing thermaldevice linked list*/ ++DEFINE_SPINLOCK(td_list_lock); ++DEFINE_SPINLOCK(el_list_lock); ++ ++#define EVENT_ENABLE 1 ++#define EVENT_DISABLE 0 ++ ++static void __thermal_group_unregister(struct thermal_group *tg, ++ int event_flag); ++static int dispatch_events(int event_type, void *data, const char *query_name); ++ ++/* -------------------------------------------------------------------------- ++ Attribute implementation functions - Thermal config ++----------------------------------------------------------------------------- */ ++static ssize_t userenabled_show(struct thermal_config *tc, char *buf) ++{ ++ char *s = buf; ++ ++ if (!tc || !buf) ++ return -EINVAL; ++ ++ s += sprintf(s, "%d \n", tc->userenabled); ++ ++ return (s - buf); ++} ++ ++static ssize_t mode_show(struct thermal_config *tc, char *buf) ++{ ++ char *s = buf; ++ ++ if (!tc || !buf) ++ return -EINVAL; ++ ++ s += sprintf(s, "%s \n", thermal_mode[tc->mode]); ++ ++ return (s - buf); ++} ++ ++static ssize_t mode_store(struct thermal_config *tc, const char *buf, ++ size_t count) ++{ ++ int i; ++ if (!tc || !buf) ++ return -EINVAL; ++ ++ if (THERMAL_USER_ENABLED == thermalconfig.userenabled) { ++ for (i = 0; i < THERMAL_MAX_MODE; i++) { ++ if (!strncmp ++ (thermal_mode[i], buf, strlen(thermal_mode[i]))) ++ tc->mode = i; ++ } ++ } ++ ++ return count; ++} ++ ++/* -------------------------------------------------------------------------- ++ sysfs Interface - config ++-------------------------------------------------------------------------*/ ++ ++/*Call back function prototypes*/ ++struct thermalconfig_attribute { ++ struct attribute attr; ++ ssize_t(*show) (struct thermal_config *tc, char *buf); ++ ssize_t(*store) (struct thermal_config *tc, const char *buf, ++ size_t count); ++}; ++ ++/*Helper macros for using THERMALCONFIG attributes*/ ++#define THERMALCONFIG_ATTR(_name, _mode, _show, _store) \ ++struct thermalconfig_attribute thermalconfig_attr_##_name = { \ ++ .attr = { \ ++ .name = __stringify(_name), \ ++ .mode = _mode, \ ++ .owner = THIS_MODULE \ ++ }, \ ++ .show = _show, \ ++ .store = _store, \ ++}; ++ ++#define to_thermalconfig_attr(_attr) \ ++ (container_of(_attr, \ ++ struct thermalconfig_attribute, \ ++ attr)) ++ ++#define to_thermal_config(obj) \ ++ container_of(obj, struct thermal_config, kobj) ++ ++/*kobj_type callback function for 'show'*/ ++static ssize_t ++thermalconfig_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) ++{ ++ struct thermal_config *tc = to_thermal_config(kobj); ++ struct thermalconfig_attribute *thermalconfig_attr = ++ to_thermalconfig_attr(attr); ++ ssize_t ret = -EIO; ++ ++ if (thermalconfig_attr->show) ++ ret = thermalconfig_attr->show(tc, buf); ++ ++ return ret; ++} ++ ++/*kobj_type callback function for 'store'*/ ++static ssize_t ++thermalconfig_attr_store(struct kobject *kobj, struct attribute *attr, ++ const char *buf, size_t len) ++{ ++ struct thermal_config *tc = to_thermal_config(kobj); ++ struct thermalconfig_attribute *thermalconfig_attr = ++ to_thermalconfig_attr(attr); ++ ++ ssize_t ret = -EIO; ++ ++ if (thermalconfig_attr->store) ++ ret = thermalconfig_attr->store(tc, buf, len); ++ ++ return ret; ++} ++ ++/*Enable/Disable userspace algo*/ ++static THERMALCONFIG_ATTR(userenabled, 0444, userenabled_show, NULL); ++/*Kernel/user algo in execution*/ ++static THERMALCONFIG_ATTR(mode, 0644, mode_show, mode_store); ++ ++static struct thermalconfig_attribute *thermalconfig_attrs[] = { ++ &thermalconfig_attr_userenabled, ++ &thermalconfig_attr_mode, ++ NULL, ++}; ++ ++static struct attribute *def_attrs[] = { ++ NULL, ++}; ++ ++/*Populate the attributes of thermalconfig kobject*/ ++static void thermalconfig_populate_dir(struct thermal_config *tc) ++{ ++ struct thermalconfig_attribute *attr; ++ int error = 0; ++ int i; ++ ++ for (i = 0; (attr = thermalconfig_attrs[i]) && !error; i++) ++ error = sysfs_create_file(&tc->kobj, &attr->attr); ++ ++} ++ ++/*Call back registration for thermal config*/ ++static struct sysfs_ops thermalconfig_attr_ops = { ++ .show = thermalconfig_attr_show, ++ .store = thermalconfig_attr_store, ++}; ++ ++/*ktype for thermaconfig*/ ++static struct kobj_type ktype_thermalconfig = { ++ .sysfs_ops = &thermalconfig_attr_ops, ++ .default_attrs = def_attrs, ++}; ++ ++/* -------------------------------------------------------------------------- ++ Attribute implementation functions - TZ ++-------------------------------------------------------------------------*/ ++ ++/* ++ * ATTRIB_SHOW ++ * ----------- ++ * Macro which defines sysfs callback routines for each attribute capable of ++ * 'show' ++ * td: Pointer to associated thermal_device ++ * attr: More attribute info ++ * buf: The buffer which needs to be filled by handler ++ */ ++ ++#define ATTRIB_SHOW(name) \ ++static ssize_t name##_show(struct thermal_device *td, \ ++ struct thermal_device_attribute *attr, char *buf) \ ++{ \ ++ char *s = buf;\ ++ int data;\ ++ int result = -EINVAL;\ ++ if (!td || !buf)\ ++ return 0;\ ++ if (td->ops->thermal_get_##name)\ ++ result = td->ops->thermal_get_##name(td->devdata\ ++ , attr, &data);\ ++ if (!result)\ ++ s += sprintf(buf, "%d\n", data);\ ++ return (s - buf);\ ++} \ ++ ++ATTRIB_SHOW(temperature); ++ATTRIB_SHOW(critical); ++ATTRIB_SHOW(hot); ++ATTRIB_SHOW(passive); ++ATTRIB_SHOW(polling_freq); ++ ++static ssize_t state_show(struct thermal_device *td, ++ struct thermal_device_attribute *attr, char *buf) ++{ ++ if (!td || !buf) ++ return -EINVAL; ++ ++ if (td->ops->thermal_get_state) ++ td->ops->thermal_get_state(td->devdata, attr, buf); ++ ++ return strlen(buf); ++} ++ ++static ssize_t cooling_mode_show(struct thermal_device *td, ++ struct thermal_device_attribute *attr, ++ char *buf) ++{ ++ if (!td || !buf) ++ return -EINVAL; ++ ++ /* Reading of actual cooling mode not supportd */ ++ sprintf(buf, "0 - Active; 1 - Pasive\n"); ++ return strlen(buf); ++} ++ ++/* ++ * ATTRIB_STORE ++ * ------------ ++ * Macro which defines sysfs callback routines ++ * for each attribute capable of 'store' ++ * td: Pointer to associated thermal_device ++ * attr: More attribute info ++ * buf: The buffer which contains the input value ++ */ ++#define ATTRIB_STORE(name) \ ++static ssize_t name##_store(struct thermal_device *td\ ++ , struct thermal_device_attribute *attr\ ++ , const char *buf, size_t count) \ ++{ \ ++ int data; \ ++ if (!td || !buf) \ ++ return -EINVAL; \ ++ /*Sanity check; should be integer*/ \ ++ if (!sscanf(buf, "%d", &data)) \ ++ return -EINVAL; \ ++ if (td->ops->thermal_set_##name) \ ++ td->ops->thermal_set_##name(td->devdata, attr, data); \ ++ return count; \ ++} \ ++ ++ATTRIB_STORE(cooling_mode); ++ ++/* -------------------------------------------------------------------------- ++ sysfs Interface - TZ ++----------------------------------------------------------------------------- */ ++ ++/*_CRT*/ ++static THERMAL_DEVICE_ATTR(critical, 0444, critical_show, NULL); ++/*_HOT*/ ++static THERMAL_DEVICE_ATTR(hot, 0444, hot_show, NULL); ++/*_PSV*/ ++static THERMAL_DEVICE_ATTR(passive, 0444, passive_show, NULL); ++/*current temperature*/ ++static THERMAL_DEVICE_ATTR(temperature, 0444, ++ temperature_show, NULL); ++/*current state*/ ++static THERMAL_DEVICE_ATTR(state, 0444, state_show, NULL); ++/*cooling mode*/ ++static THERMAL_DEVICE_ATTR(cooling_mode, 0444, ++ cooling_mode_show, cooling_mode_store); ++/*polliing frequency*/ ++static THERMAL_DEVICE_ATTR(polling_freq, 0444, ++ polling_freq_show, NULL); ++ ++static struct thermal_device_attribute *thermal_device_attrs[] = { ++ &thermal_device_attr_temperature, ++ &thermal_device_attr_critical, ++ &thermal_device_attr_hot, ++ &thermal_device_attr_passive, ++ &thermal_device_attr_cooling_mode, ++ &thermal_device_attr_polling_freq, ++ &thermal_device_attr_state, ++ NULL, ++}; ++ ++/*Populate the attributes of thermal device kobject*/ ++static void thermal_device_populate_dir(struct thermal_device *td) ++{ ++ struct thermal_device_attribute *attr; ++ int error = 0; ++ int i; ++ ++ if (!td) ++ return; ++ ++ for (i = 0; (attr = thermal_device_attrs[i]) && !error; i++) { ++ if (!strcmp(THERMAL_ATTRIB_TEMPERATURE, attr->attr.name)) { ++ if (!td->ops->thermal_get_temperature) ++ continue; ++ } else if (!strcmp(THERMAL_ATTRIB_CRITICAL, attr->attr.name)) { ++ if (!td->ops->thermal_get_critical) ++ continue; ++ } else if (!strcmp(THERMAL_ATTRIB_HOT, attr->attr.name)) { ++ if (!td->ops->thermal_get_hot) ++ continue; ++ } else if (!strcmp(THERMAL_ATTRIB_PASSIVE, attr->attr.name)) { ++ if (!td->ops->thermal_get_passive) ++ continue; ++ } else if (!strcmp(THERMAL_ATTRIB_POLLING_FREQ, ++ attr->attr.name)) { ++ if (!td->ops->thermal_get_polling_freq) ++ continue; ++ } else if (!strcmp(THERMAL_ATTRIB_COOLING_MODE, ++ attr->attr.name)) { ++ if (!td->ops->thermal_set_cooling_mode) ++ continue; ++ } else if (!strcmp(THERMAL_ATTRIB_STATE, attr->attr.name)) { ++ if (!td->ops->thermal_get_state) ++ continue; ++ } ++ ++ error = sysfs_create_file(&td->kobj, &attr->attr); ++ } ++ ++} ++ ++/*kobj_type callback function for 'show'*/ ++static ssize_t ++thermal_device_attr_show(struct kobject *kobj, struct attribute *attr, ++ char *buf) ++{ ++ struct thermal_device *td = to_thermal_device(kobj); ++ struct thermal_device_attribute *thermal_device_attr = ++ to_thermal_device_attr(attr); ++ ssize_t ret = -EIO; ++ ++ /*Call attribute callback function */ ++ if (thermal_device_attr->show) ++ ret = thermal_device_attr->show(td, thermal_device_attr, buf); ++ ++ return ret; ++ ++} ++ ++/*kobj_type callback function for 'store'*/ ++static ssize_t ++thermal_device_attr_store(struct kobject *kobj, struct attribute *attr, ++ const char *buf, size_t len) ++{ ++ struct thermal_device *td = to_thermal_device(kobj); ++ struct thermal_device_attribute *thermal_device_attr = ++ to_thermal_device_attr(attr); ++ ++ ssize_t ret = -EIO; ++ ++ /*Call attribute callback function */ ++ if (thermal_device_attr->store) ++ ret = ++ thermal_device_attr->store(td, thermal_device_attr, buf, ++ len); ++ return ret; ++} ++ ++/*Call back registration for thermaldevice*/ ++static struct sysfs_ops thermal_device_attr_ops = { ++ .show = thermal_device_attr_show, ++ .store = thermal_device_attr_store, ++}; ++ ++/*ktype for thermaldevice*/ ++static struct kobj_type ktype_thermal_device = { ++ .sysfs_ops = &thermal_device_attr_ops, ++ .default_attrs = def_attrs, ++}; ++ ++static decl_subsys(thermal, &ktype_thermal_device, NULL); ++ ++/* -------------------------------------------------------------------------- ++ Register/Unregister functions ++----------------------------------------------------------------------------- */ ++/* ++ * thermal_device_register ++ * ------------------------ ++ * Method for registering thermal devices(sensors) with sysfs ++ * name: The name that should appear in sysfs ++ * devdata : Device private context ++ * ops : List of call back functions for various attributes ++ */ ++struct thermal_device *thermal_device_register(const char *name, ++ void *devdata, ++ struct thermal_device_ops *ops) ++{ ++ int result; ++ struct thermal_device *new_td; ++ struct list_head *entry_td; ++ ++ if (!name || !ops) ++ return ERR_PTR(-EINVAL); ++ ++ /* Check whether there is a thermal device by the same name */ ++ spin_lock(&td_list_lock); ++ list_for_each(entry_td, &thermal_device_list) { ++ struct thermal_device *old_td; ++ old_td = list_entry(entry_td, struct thermal_device, node); ++ if (!strcmp(name, old_td->name)) { ++ spin_unlock(&td_list_lock); ++ return ERR_PTR(-EEXIST); ++ } ++ } ++ spin_unlock(&td_list_lock); ++ ++ pr_debug("thermal_device_alloc: name=%s\n", name); ++ ++ new_td = kzalloc(sizeof(struct thermal_device), GFP_KERNEL); ++ if (!new_td) ++ return ERR_PTR(-ENOMEM); ++ ++ new_td->ops = ops; ++ new_td->devdata = devdata; ++ strlcpy(new_td->name, name, KOBJ_NAME_LEN); ++ ++ INIT_LIST_HEAD(&new_td->group_node); ++ ++ /* kobject registering for thermaldevice */ ++ kobject_set_name(&new_td->kobj, name); ++ kobj_set_kset_s(new_td, thermal_subsys); ++ new_td->kobj.parent = &thermal_subsys.kobj; ++ ++ result = kobject_register(&new_td->kobj); ++ if (result) { ++ kfree(new_td); ++ return ERR_PTR(-EFAULT); ++ } ++ ++ /* Populate the attributes for new thermal device */ ++ thermal_device_populate_dir(new_td); ++ ++ spin_lock(&td_list_lock); ++ list_add(&(new_td->node), &thermal_device_list); ++ spin_unlock(&td_list_lock); ++ ++ /* Notify other drivers about new thermal zone */ ++ dispatch_events(THERMAL_SYSFS_EVENT_ADD_TD, new_td, new_td->name); ++ ++ return new_td; ++} ++EXPORT_SYMBOL(thermal_device_register); ++ ++static int thermal_is_td_exist(struct thermal_device *td) ++{ ++ struct list_head *entry_td; ++ ++ /*Check whether td is a valid registration */ ++ spin_lock(&td_list_lock); ++ list_for_each(entry_td, &thermal_device_list) { ++ struct thermal_device *old_td; ++ old_td = list_entry(entry_td, struct thermal_device, node); ++ if (old_td == td) { ++ spin_unlock(&td_list_lock); ++ return 0; ++ } ++ } ++ spin_unlock(&td_list_lock); ++ return -ENODEV; ++} ++ ++/* ++ * thermal_device_unregister ++ * ------------------------ ++ * Method for unregistering thermal devices(sensors) with sysfs ++ * td: Pointer to thermal_device ++ */ ++int thermal_device_unregister(struct thermal_device *td) ++{ ++ struct list_head *pos, *q; ++ int result; ++ ++ if (!td) ++ return -EINVAL; ++ ++ result = thermal_is_td_exist(td); ++ if (result) ++ return result; ++ ++ spin_lock(&td_list_lock); ++ /* If any group exists for this device unregister those as well */ ++ list_for_each_safe(pos, q, &td->group_node) { ++ struct thermal_group *tg; ++ tg = list_entry(pos, struct thermal_group, node); ++ __thermal_group_unregister(tg, EVENT_ENABLE); ++ } ++ ++ list_del(&(td->node)); ++ spin_unlock(&td_list_lock); ++ ++ /* Notify other drivers about removal of this thermal_device */ ++ dispatch_events(THERMAL_SYSFS_EVENT_RMV_TD, td, td->name); ++ kobject_unregister(&td->kobj); ++ kfree(td); ++ ++ return 0; ++} ++EXPORT_SYMBOL(thermal_device_unregister); ++ ++static int thermal_is_group_exist(struct thermal_device *td, const char *name) ++{ ++ struct list_head *entry_tg; ++ ++ if (!td || !name) ++ return -EINVAL; ++ ++ spin_lock(&td_list_lock); ++ list_for_each(entry_tg, &td->group_node) { ++ struct thermal_group *tg; ++ tg = list_entry(entry_tg, struct thermal_group, node); ++ if (!strcmp(tg->name, name)) { ++ spin_unlock(&td_list_lock); ++ return 0; ++ } ++ } ++ ++ spin_unlock(&td_list_lock); ++ return -ENODEV; ++} ++ ++/* ++ * thermal_group_register ++ * ------------------------ ++ * Method for registering groups such as ACPI _TZD with sysfs ++ * name: The name that should appear in sysfs ++ * td : Device under which this group is to be created ++ * participant_count : No:of participants in this group ++ * participants: Pointer to an array of participants ++ */ ++int thermal_group_register(const char *name, struct thermal_device *td, ++ int participant_count, ++ struct thermal_participant *participant) ++{ ++ int i; ++ int result; ++ struct thermal_group *group; ++ ++ if (!name || !td || thermal_is_td_exist(td) ++ || participant_count <= 0 ++ || (participant_count && !participant)) ++ return -EINVAL; ++ ++ /* Check that group by this name doesn't exist */ ++ result = thermal_is_group_exist(td, name); ++ if (!result) ++ return -EEXIST; ++ ++ group = kzalloc(sizeof(struct thermal_group), GFP_KERNEL); ++ if (!group) ++ return -ENOMEM; ++ ++ /* Fill the thermal_group struct */ ++ strlcpy(group->name, name, KOBJ_NAME_LEN); ++ group->td = td; ++ group->participant_count = participant_count; ++ ++ /* Make an entry under sysfs */ ++ kobject_set_name(&group->kobj, group->name); ++ group->kobj.parent = &group->td->kobj; ++ result = kobject_register(&group->kobj); ++ ++ if (result) { ++ kfree(group); ++ return result; ++ } ++ ++ group->participant = ++ kzalloc(participant_count * sizeof(struct thermal_participant), ++ GFP_KERNEL); ++ ++ if (!group->participant) { ++ kobject_unregister(&group->kobj); ++ kfree(group); ++ return -ENOMEM; ++ } ++ ++ memcpy(group->participant, participant, ++ participant_count * sizeof(struct thermal_participant)); ++ ++ ++ ++ /* Create symbolic links for all the participants to ++ their default exposed location in sysfs */ ++ for (i = 0; i < group->participant_count; i++) { ++ group->participant[i].group = group; ++ if (group->participant[i].kobj) { ++ result = ++ sysfs_create_link(&group->kobj, ++ group->participant[i].kobj, ++ group->participant ++ [i].kobj->k_name); ++ if (result) { ++ kobject_unregister(&group->kobj); ++ kfree(group->participant); ++ kfree(group); ++ return -EFAULT; ++ } else ++ dispatch_events(THERMAL_SYSFS_EVENT_ADD_PART, ++ &group->participant[i], ++ group->participant[i].name); ++ } ++ } ++ ++ spin_lock(&td_list_lock); ++ list_add(&(group->node), &td->group_node); ++ spin_unlock(&td_list_lock); ++ ++ /* Notify other drivers about the creation of new group */ ++ dispatch_events(THERMAL_SYSFS_EVENT_ADD_GRP, group, group->name); ++ return 0; ++} ++EXPORT_SYMBOL(thermal_group_register); ++ ++/* Always will be called with spin locked td_list_lock*/ ++static void __thermal_group_unregister(struct thermal_group *tg, int event_flag) ++{ ++ int j; ++ ++ if (!tg) ++ return; ++ ++ if (EVENT_ENABLE == event_flag) { ++ spin_unlock(&td_list_lock); ++ for (j = 0; j < tg->participant_count; j++) { ++ struct thermal_participant *participant; ++ participant = &tg->participant[j]; ++ dispatch_events(THERMAL_SYSFS_EVENT_RMV_PART, ++ participant, participant->name); ++ } ++ dispatch_events(THERMAL_SYSFS_EVENT_RMV_GRP, tg, tg->name); ++ spin_lock(&td_list_lock); ++ } ++ ++ list_del(&tg->node); ++ kobject_unregister(&tg->kobj); ++ kfree(tg->participant); ++ kfree(tg); ++} ++ ++/* ++ * thermal_group_unregister ++ * ------------------------ ++ * Method for unregistering groups within a thermal device ++ * td: Pointer to thermal_device from where the group should be removed ++ * name : Name of the group given during registration ++ */ ++int thermal_group_unregister(struct thermal_device *td, const char *name) ++{ ++ struct list_head *pos, *q; ++ ++ if (!td || thermal_is_td_exist(td) || !name) ++ return -EINVAL; ++ ++ /* check whether device is already registered */ ++ spin_lock(&td_list_lock); ++ ++ list_for_each_safe(pos, q, &td->group_node) { ++ struct thermal_group *tg; ++ tg = list_entry(pos, struct thermal_group, node); ++ /* Get the matching group */ ++ if (!strcmp(tg->name, name)) { ++ __thermal_group_unregister(tg, EVENT_ENABLE); ++ spin_unlock(&td_list_lock); ++ return 0; ++ } ++ } ++ ++ spin_unlock(&td_list_lock); ++ return -ENODEV; ++} ++EXPORT_SYMBOL(thermal_group_unregister); ++ ++/* ++ * thermal_attribute_register ++ * ------------------------ ++ * Method for registering extra attributes with sysfs ++ * td : Device under which attributes should be created ++ * thermal_device_attrs : array of attributes to be added ++ */ ++int thermal_attribute_register(struct thermal_device *td, ++ struct thermal_device_attribute ++ **thermal_device_attrs) ++{ ++ struct thermal_device_attribute *attr; ++ int result = 0; ++ int i; ++ ++ if (!td || thermal_is_td_exist(td) || !thermal_device_attrs) ++ return -EINVAL; ++ ++ for (i = 0; (attr = thermal_device_attrs[i]) && !result; i++) { ++ result = sysfs_create_file(&td->kobj, &attr->attr); ++ if (result) ++ return result; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(thermal_attribute_register); ++ ++/* ++ * thermal_attribute_unregister ++ * ------------------------ ++ * Method for unregistering extra attributes with sysfs ++ * td : Device under which attributes should be removed ++ * thermal_device_attrs : array of attributes to be removed ++ */ ++int thermal_attribute_unregister(struct thermal_device *td, ++ struct thermal_device_attribute ++ **thermal_device_attrs) ++{ ++ struct thermal_device_attribute *attr; ++ int i; ++ ++ if (!td || thermal_is_td_exist(td) || !thermal_device_attrs) ++ return -EINVAL; ++ ++ for (i = 0; (attr = thermal_device_attrs[i]); i++) ++ sysfs_remove_file(&td->kobj, &attr->attr); ++ ++ ++ return 0; ++} ++EXPORT_SYMBOL(thermal_attribute_unregister); ++ ++/* ++ * dispatch_events ++ * ------------------------ ++ * Go through the list of event listeners and call their handlers ++ * event_typ: as defined in thermal.h ++ * data : payload depending on type of event ++ * query_name : if the event needs to be received from some particular entity ++ */ ++static int dispatch_events(int event_type, void *data, const char *query_name) ++{ ++ struct list_head *entry_el; ++ ++ if (!data) ++ return -EINVAL; ++ ++ spin_lock(&el_list_lock); ++ list_for_each(entry_el, &thermal_sysfs_event_listener_list) { ++ struct thermal_sysfs_event_listener *event_listener; ++ event_listener = ++ list_entry(entry_el, struct thermal_sysfs_event_listener, ++ node); ++ if (event_listener->event_type & event_type) { ++ if (query_name && event_listener->query_name) { ++ if (!strcmp ++ (event_listener->query_name, query_name)) ++ event_listener-> ++ thermal_sysfs_event_handler ++ (event_type, data, ++ event_listener->private); ++ ++ } else { ++ event_listener-> ++ thermal_sysfs_event_handler(event_type, ++ data, ++ event_listener-> ++ private); ++ } ++ } ++ } ++ spin_unlock(&el_list_lock); ++ return 0; ++} ++ ++/* Invoke the handler for each thermal_device which have already registered */ ++int dispatch_existing_td_events(struct thermal_sysfs_event_listener *listener, ++ unsigned int event_type) ++{ ++ struct list_head *pos, *q; ++ ++ if (!listener) ++ return -EINVAL; ++ ++ spin_lock(&td_list_lock); ++ list_for_each_safe(pos, q, &thermal_device_list) { ++ struct thermal_device *old_td; ++ old_td = list_entry(pos, struct thermal_device, node); ++ spin_unlock(&td_list_lock); ++ if (listener->query_name) { ++ if (!strcmp(listener->query_name, old_td->name)) ++ listener-> ++ thermal_sysfs_event_handler(event_type, ++ old_td, ++ listener-> ++ private); ++ ++ } else { ++ listener->thermal_sysfs_event_handler(event_type, ++ old_td, ++ listener-> ++ private); ++ } ++ spin_lock(&td_list_lock); ++ ++ } ++ spin_unlock(&td_list_lock); ++ return 0; ++} ++ ++/* Invoke the handler for each thermal_group which have already registered */ ++int dispatch_existing_group_events(struct thermal_sysfs_event_listener ++ *listener, unsigned int event_type) ++{ ++ struct list_head *pos_td, *pos_tg, *q_td, *q_tg; ++ ++ if (!listener) ++ return -EINVAL; ++ ++ spin_lock(&td_list_lock); ++ list_for_each_safe(pos_td, q_td, &thermal_device_list) { ++ struct thermal_device *old_td; ++ old_td = list_entry(pos_td, struct thermal_device, node); ++ list_for_each_safe(pos_tg, q_tg, &old_td->group_node) { ++ struct thermal_group *tg; ++ tg = list_entry(pos_tg, struct thermal_group, node); ++ spin_unlock(&td_list_lock); ++ if (listener->query_name) { ++ if (!strcmp(listener->query_name, tg->name)) ++ listener-> ++ thermal_sysfs_event_handler ++ (event_type, tg, listener->private); ++ ++ } else { ++ listener-> ++ thermal_sysfs_event_handler(event_type, tg, ++ listener-> ++ private); ++ } ++ spin_lock(&td_list_lock); ++ ++ } ++ } ++ spin_unlock(&td_list_lock); ++ return 0; ++} ++ ++/* Invoke the handler for each thermal_participant ++which have already registered */ ++int dispatch_existing_participant_events(struct thermal_sysfs_event_listener ++ *listener, unsigned int event_type) ++{ ++ struct list_head *pos_td, *pos_tg, *q_td, *q_tg; ++ int j; ++ ++ if (!listener) ++ return -EINVAL; ++ ++ spin_lock(&td_list_lock); ++ list_for_each_safe(pos_td, q_td, &thermal_device_list) { ++ struct thermal_device *old_td; ++ old_td = list_entry(pos_td, struct thermal_device, node); ++ ++ list_for_each_safe(pos_tg, q_tg, &old_td->group_node) { ++ struct thermal_group *tg; ++ tg = list_entry(pos_tg, struct thermal_group, node); ++ ++ for (j = 0; j < tg->participant_count; j++) { ++ struct thermal_participant *participant; ++ participant = &tg->participant[j]; ++ spin_unlock(&td_list_lock); ++ if (listener->query_name) { ++ if (!strcmp ++ (listener->query_name, ++ participant->name)) ++ listener-> ++ thermal_sysfs_event_handler ++ (event_type, participant, ++ listener->private); ++ ++ } else { ++ listener-> ++ thermal_sysfs_event_handler ++ (event_type, participant, ++ listener->private); ++ } ++ spin_lock(&td_list_lock); ++ } ++ ++ } ++ } ++ spin_unlock(&td_list_lock); ++ return 0; ++} ++ ++static int thermal_is_listener_exist(struct thermal_sysfs_event_listener ++ *listener) ++{ ++ struct list_head *entry_el; ++ ++ spin_lock(&el_list_lock); ++ list_for_each(entry_el, &thermal_sysfs_event_listener_list) { ++ struct thermal_sysfs_event_listener *event_listener; ++ event_listener = ++ list_entry(entry_el, struct thermal_sysfs_event_listener, ++ node); ++ if (listener == event_listener) { ++ spin_unlock(&el_list_lock); ++ return 0; ++ } ++ } ++ spin_unlock(&el_list_lock); ++ return -ENODEV; ++} ++ ++/* ++ * thermal_event_register ++ * ---------------------- ++ * Register for add/rmv of device/group/participant notification ++ * handler: thermal_event_handler containing callback func pointer ++ * report_type: Set this flag if callbacks needs to be invoked ++ * for existing device/group/participants ++ */ ++int thermal_event_register(struct thermal_sysfs_event_listener *listener, ++ unsigned int report_type) ++{ ++ unsigned int event_type; ++ if (!listener) ++ return -EINVAL; ++ ++ if (!thermal_is_listener_exist(listener)) ++ return -EEXIST; ++ ++ event_type = listener->event_type; ++ ++ /* Check if the event requested by listener is supported */ ++ if (!(event_type & THERMAL_SYSFS_EVENT_ADD_TD ++ || event_type & THERMAL_SYSFS_EVENT_ADD_GRP ++ || event_type & THERMAL_SYSFS_EVENT_ADD_PART ++ || event_type & THERMAL_SYSFS_EVENT_RMV_TD ++ || event_type & THERMAL_SYSFS_EVENT_RMV_GRP ++ || event_type & THERMAL_SYSFS_EVENT_RMV_PART)) ++ return -EINVAL; ++ ++ ++ spin_lock(&el_list_lock); ++ list_add(&(listener->node), &thermal_sysfs_event_listener_list); ++ spin_unlock(&el_list_lock); ++ ++ if (THERMAL_SYSFS_REPORT_EXISTING == report_type) { ++ if (listener->event_type & THERMAL_SYSFS_EVENT_ADD_TD) ++ dispatch_existing_td_events( ++ listener, ++ THERMAL_SYSFS_EVENT_ADD_TD); ++ ++ ++ if (listener->event_type & THERMAL_SYSFS_EVENT_ADD_GRP) ++ dispatch_existing_group_events( ++ listener, ++ THERMAL_SYSFS_EVENT_ADD_GRP); ++ ++ ++ if (listener->event_type & THERMAL_SYSFS_EVENT_ADD_PART) ++ dispatch_existing_participant_events(listener, ++ THERMAL_SYSFS_EVENT_ADD_PART); ++ ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(thermal_event_register); ++ ++/* ++ * thermal_event_unregister ++ * ---------------------- ++ * UnRegister for add/rmv of device/group/participant notification ++ * handler: thermal_event_handler containing callback func pointer ++ * report_type: Set this flag if callbacks needs to be invoked ++ * for existing device/group/participants ++ */ ++int thermal_event_unregister(struct thermal_sysfs_event_listener *listener, ++ unsigned int report_type) ++{ ++ int result; ++ if (!listener) ++ return -EINVAL; ++ ++ result = thermal_is_listener_exist(listener); ++ if (result) ++ return result; ++ ++ if (THERMAL_SYSFS_REPORT_EXISTING == report_type) { ++ if (listener->event_type & THERMAL_SYSFS_EVENT_RMV_TD) ++ dispatch_existing_td_events(listener, ++ THERMAL_SYSFS_EVENT_RMV_TD); ++ ++ ++ if (listener->event_type & THERMAL_SYSFS_EVENT_RMV_GRP) ++ dispatch_existing_group_events( ++ listener, ++ THERMAL_SYSFS_EVENT_RMV_GRP); ++ ++ ++ if (listener->event_type & THERMAL_SYSFS_EVENT_RMV_PART) ++ dispatch_existing_participant_events( ++ listener, ++ THERMAL_SYSFS_EVENT_RMV_PART); ++ ++ } ++ ++ spin_lock(&el_list_lock); ++ list_del(&listener->node); ++ spin_unlock(&el_list_lock); ++ ++ return 0; ++} ++EXPORT_SYMBOL(thermal_event_unregister); ++ ++/* ++ * thermal_get_algo_mode ++ * ---------------------- ++ * Method to know whether the user mode application has taken over ++ */ ++int thermal_get_algo_mode(void) ++{ ++ return thermalconfig.mode; ++} ++EXPORT_SYMBOL(thermal_get_algo_mode); ++ ++/* ++ * thermal_sysfs_generate_event ++ * --------------------------- ++ * Drivers managing thermal devices can invoke this method to notify ++ * user applications about thermal events ++ */ ++int thermal_sysfs_generate_event(struct thermal_device *td, ++ enum kobject_action action) ++{ ++ return kobject_uevent(&td->kobj, action); ++} ++EXPORT_SYMBOL(thermal_sysfs_generate_event); ++ ++/* ++ * thermal_set_userenabled ++ * ----------------------- ++ * Interface function for platform sensor driver to disable userspace algo ++ * ue: enable / disable userspace algo based on BIOS configuration ++ */ ++int thermal_set_userenabled(enum thermal_userenabled ue) ++{ ++ thermalconfig.userenabled = ue; ++ ++ if (THERMAL_USER_DISABLED == ue) ++ thermalconfig.mode = THERMAL_KERNELSPACE; ++ ++ return 0; ++} ++EXPORT_SYMBOL(thermal_set_userenabled); ++ ++static int __init thermal_sysfs_init(void) ++{ ++ int result = 0; ++ result = subsystem_register(&thermal_subsys); ++ if (result) ++ return result; ++ ++ /* Register the 'Config' folder under sysfs */ ++ kobject_set_name(&thermalconfig.kobj, THERMAL_SYSFS_CONFIG); ++ thermalconfig.kobj.parent = &thermal_subsys.kobj; ++ thermalconfig.kobj.ktype = &ktype_thermalconfig; ++ ++ result = kobject_register(&thermalconfig.kobj); ++ ++ if (result) ++ return result; ++ ++ /* Fill the attributes under 'Config' folder */ ++ thermalconfig_populate_dir(&thermalconfig); ++ ++ return 0; ++} ++ ++static void __exit thermal_sysfs_exit(void) ++{ ++ kobject_unregister(&thermalconfig.kobj); ++ subsystem_unregister(&thermal_subsys); ++} ++ ++postcore_initcall(thermal_sysfs_init); ++module_exit(thermal_sysfs_exit); +diff --git a/include/linux/thermal.h b/include/linux/thermal.h +new file mode 100644 +index 0000000..fb4f224 +--- /dev/null ++++ b/include/linux/thermal.h +@@ -0,0 +1,294 @@ ++/* ++ * thermal.h - Thermal device interface ($Revision: 1 $) ++ * ++ * Copyright (C) 2006, 2007 Sujith Thomas ++ ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * 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; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * Provide infrastructure from kernel to enable user-space ++ * thermal management algorithm ++ * Accepts registration of thermal devices(sensors). ++ * Accepts registration for group of participants associated with this sensor ++ * Accepts registration of extra attributes over the standard attributes. ++ * Issues notification to registered drivers upon registration of new thermal ++ * devices ++ * Adds a 'Config' folder for user mode application to take over kernel mode ++ * algo ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#define KELVIN_TO_CELSIUS(t) \ ++ (long)(((long)t-2732 >= 0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10) ++#define CELSIUS_TO_KELVIN(t) ((t*10) + 2732) ++ ++/* -------------------------------------------------------------------------- ++ Component Driver Interface ++ -------------------------------------------------------------------------- */ ++ ++struct thermal_device; ++ ++/*thermal device attributes*/ ++struct thermal_device_attribute { ++ struct attribute attr; ++ ssize_t(*show) (struct thermal_device *td, ++ struct thermal_device_attribute *attr, char *buf); ++ ssize_t(*store) (struct thermal_device *td, ++ struct thermal_device_attribute *attr, ++ const char *buf, size_t count); ++}; ++ ++/*Helper macros for using THERMAL DEVICE attributes*/ ++#define THERMAL_DEVICE_ATTR(_name, _mode, _show, _store) \ ++struct thermal_device_attribute thermal_device_attr_##_name = { \ ++ .attr = { \ ++ .name = __stringify(_name), \ ++ .mode = _mode, \ ++ .owner = THIS_MODULE, \ ++ }, \ ++ .show = _show, \ ++ .store = _store, \ ++}; ++ ++#define to_thermal_device_attr(_attr) \ ++ (container_of(_attr, \ ++ struct thermal_device_attribute, \ ++ attr)) ++ ++#define to_thermal_device(obj) \ ++ container_of(obj, struct thermal_device, kobj) ++ ++#define THERMAL_ATTRIB_TEMPERATURE "temperature" ++#define THERMAL_ATTRIB_CRITICAL "critical" ++#define THERMAL_ATTRIB_HOT "hot" ++#define THERMAL_ATTRIB_PASSIVE "passive" ++#define THERMAL_ATTRIB_POLLING_FREQ "polling_freq" ++#define THERMAL_ATTRIB_COOLING_MODE "cooling_mode" ++#define THERMAL_ATTRIB_STATE "state" ++ ++/* The attributes which will be displayed for any thermal device */ ++struct thermal_device_ops { ++ int (*thermal_get_temperature) (void *devdata, ++ struct thermal_device_attribute *attr, ++ int *temperature); ++ int (*thermal_get_critical) (void *devdata, ++ struct thermal_device_attribute *attr, ++ int *temperature); ++ int (*thermal_get_hot) (void *devdata, ++ struct thermal_device_attribute *attr, ++ int *temperature); ++ int (*thermal_get_passive) (void *devdata, ++ struct thermal_device_attribute *attr, ++ int *temperature); ++ int (*thermal_set_cooling_mode) (void *devdata, ++ struct thermal_device_attribute *attr, ++ int cooilng_mode); ++ int (*thermal_get_polling_freq) (void *devdata, ++ struct thermal_device_attribute *attr, ++ int *polling_freq); ++ int (*thermal_get_state) (void *devdata, ++ struct thermal_device_attribute *attr, ++ char *buf); ++}; ++ ++/* The participant which may be associated with a sensor ++ For eg: CPU,Fan etc.. */ ++struct thermal_participant { ++ char name[KOBJ_NAME_LEN]; /*Name of the participant*/ ++ struct thermal_group *group; /*Group in which it belongs*/ ++ /*Pointer to kobj associated with default location in sysfs*/ ++ struct kobject *kobj; ++}; ++ ++/* The 'group' of devices associated with a sensor ++ For Eg: passive_devices, active_devices */ ++struct thermal_group { ++ struct list_head node; /*Linked list management*/ ++ char name[KOBJ_NAME_LEN]; /*Name of the group*/ ++ /*Pointer to thermal device which contains this group*/ ++ struct thermal_device *td; ++ int participant_count; /*No:of participants in this group*/ ++ struct thermal_participant *participant;/*Array of participants*/ ++ struct kobject kobj; /* Group's Kobject */ ++}; ++ ++/* The thermal device information */ ++struct thermal_device { ++ struct list_head node; /* Linked list management*/ ++ struct thermal_device_ops *ops; /*Callback routines*/ ++ char name[KOBJ_NAME_LEN]; /* Name of thermal device*/ ++ void *devdata; /* Device's private data*/ ++ /* List of groups associated with this thermal device*/ ++ struct list_head group_node; ++ struct kobject kobj; /* Thermal device's Kobject*/ ++}; ++ ++#define THERMAL_SYSFS_EVENT_ADD_TD 0x01 ++#define THERMAL_SYSFS_EVENT_ADD_GRP 0x02 ++#define THERMAL_SYSFS_EVENT_ADD_PART 0x04 ++#define THERMAL_SYSFS_EVENT_RMV_TD 0x08 ++#define THERMAL_SYSFS_EVENT_RMV_GRP 0x10 ++#define THERMAL_SYSFS_EVENT_RMV_PART 0x20 ++ ++#define THERMAL_SYSFS_REPORT_EXISTING 0x0 ++#define THERMAL_SYSFS_NOREPORT_EXISTING 0x1 ++ ++struct thermal_sysfs_event_listener { ++ struct list_head node; ++ /*Call back function (handler) upon receiving an event */ ++ int (*thermal_sysfs_event_handler) (int event_type ++ , void *sysfs_data ++ , void *private); ++ int event_type; ++ /* Event only from query_name will be notified*/ ++ char *query_name; ++ /* Context of the registering driver*/ ++ void *private; ++ ++}; ++ ++/* -------------------------------------------------------------------------- ++ Configuration Interface ++ -------------------------------------------------------------------------- */ ++ ++#define THERMAL_SYSFS_CONFIG "config" ++ ++#define THERMAL_MAX_MODE 2 ++enum thermal_userenabled { THERMAL_USER_DISABLED, THERMAL_USER_ENABLED }; ++enum thermal_mode { THERMAL_USERSPACE, THERMAL_KERNELSPACE }; ++ ++struct thermal_config { ++ u8 userenabled:1;/* 1 if user application is allowed to take over */ ++ u8 mode:1; /* 0 if userspace algorithm has taken over */ ++ struct kobject kobj; /*Syfs stuff */ ++}; ++ ++/* -------------------------------------------------------------------------- ++ Registration functions ++----------------------------------------------------------------------------- */ ++ ++/* ++ * thermal_device_register ++ * ------------------------ ++ * Method for registering thermal devices(sensors) with sysfs ++ * name: The name that should appear in sysfs ++ * devdata : Device private context ++ * ops : List of call back functions for various attributes ++ */ ++struct thermal_device *thermal_device_register(const char *name, ++ void *devdata, ++ struct thermal_device_ops *ops); ++/* ++ * thermal_group_register ++ * ------------------------ ++ * Method for registering groups such as ACPI _TZD with sysfs ++ * name: The name that should appear in sysfs ++ * td : Device under which this group is to be created ++ * participant_count : No:of participants in this group ++ * participants: Pointer to an array of participants ++ */ ++int thermal_group_register(const char *name, struct thermal_device *td, ++ int participant_count, ++ struct thermal_participant *participant); ++ ++/* ++ * thermal_attribute_register ++ * ------------------------ ++ * Method for registering extra attributes with sysfs ++ * td : Device under which attributes should be created ++ * thermal_device_attrs : array of attributes to be added ++ */ ++int thermal_attribute_register(struct thermal_device *td, ++ struct thermal_device_attribute ++ **thermal_device_attrs); ++ ++/* ++ * thermal_event_register ++ * ---------------------- ++ * Register for add/rmv of device/group/participant notification ++ * handler: thermal_event_handler containing callback func pointer ++ * report_type: Set this flag if callbacks needs to be invoked ++ * for existing device/group/participants ++ */ ++int thermal_event_register(struct thermal_sysfs_event_listener *listener, ++ unsigned int report_type); ++ ++/* ++ * thermal_device_unregister ++ * ------------------------ ++ * Method for unregistering thermal devices(sensors) with sysfs ++ * td: Pointer to thermal_device ++ */ ++int thermal_device_unregister(struct thermal_device *td); ++ ++/* ++ * thermal_group_unregister ++ * ------------------------ ++ * Method for unregistering groups within a thermal device ++ * td: Pointer to thermal_device from where the group should be removed ++ * name : Name of the group given during registration ++ */ ++int thermal_group_unregister(struct thermal_device *td, const char *name); ++ ++/* ++ * thermal_attribute_unregister ++ * ------------------------ ++ * Method for unregistering extra attributes with sysfs ++ * td : Device under which attributes should be removed ++ * thermal_device_attrs : array of attributes to be removed ++ */ ++int thermal_attribute_unregister(struct thermal_device *td, ++ struct thermal_device_attribute ++ **thermal_device_attrs); ++/* ++ * thermal_event_unregister ++ * ---------------------- ++ * UnRegister for add/rmv of device/group/participant notification ++ * handler: thermal_event_handler containing callback func pointer ++ * report_type: Set this flag if callbacks needs to be invoked ++ * for existing device/group/participants ++ */ ++int thermal_event_unregister(struct thermal_sysfs_event_listener *listener, ++ unsigned int report_type); ++/* ++ * thermal_get_algo_mode ++ * ---------------------- ++ * Method to know whether the user mode application has taken over ++ */ ++int thermal_get_algo_mode(void); ++ ++/* ++ * thermal_sysfs_generate_event ++ * --------------------------- ++ * Drivers managing thermal devices can invoke this method to notify ++ * user applications about thermal events ++ */ ++int thermal_sysfs_generate_event(struct thermal_device *td, ++ enum kobject_action action); ++ ++/* ++ * thermal_set_userenabled ++ * ----------------------- ++ * Interface function for platform sensor driver to disble userspace algo ++ * ue: enable / disable userspace algo based on BIOS configuration ++ */ ++int thermal_set_userenabled(enum thermal_userenabled um); +-- +1.5.3.7-dirty + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/rules +++ linux-2.6.24/debian/binary-custom.d/openvz/rules @@ -0,0 +1 @@ +# Nothing special here --- linux-2.6.24.orig/debian/binary-custom.d/openvz/vars +++ linux-2.6.24/debian/binary-custom.d/openvz/vars @@ -0,0 +1,7 @@ +arch="i386 amd64" +supported="Generic" +target="OpenVZ kernel" +desc="OpenVZ Virtualization enabled kernel" +bootloader="lilo (>= 19.1) | grub" +provides="kvm-api-4, redhat-cluster-modules" +section_image="universe/base" --- linux-2.6.24.orig/debian/binary-custom.d/openvz/config.amd64 +++ linux-2.6.24/debian/binary-custom.d/openvz/config.amd64 @@ -0,0 +1,3868 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.24-16-openvz +# Wed Apr 9 21:10:26 2008 +# +CONFIG_64BIT=y +# CONFIG_X86_32 is not set +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_SEMAPHORE_SLEEPERS=y +CONFIG_MMU=y +CONFIG_ZONE_DMA=y +# CONFIG_QUICKLIST is not set +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_DMI=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_ARCH_SUPPORTS_OPROFILE=y +CONFIG_ZONE_DMA32=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_X86_HT=y +# CONFIG_KTIME_SCALAR is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-4.6-server" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_TREE=y +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_NS=y +CONFIG_CPUSETS=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_FAIR_USER_SCHED is not set +# CONFIG_FAIR_CGROUP_SCHED is not set +CONFIG_VZ_FAIRSCHED=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_PROC_PID_CPUSET=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_BLOCK_COMPAT=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_LSM_MMAP_MIN_ADDR=0 + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_PREEMPT_NOTIFIERS=y + +# +# Processor type and features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_SMP=y +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_X86_VSMP is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MEFFICEON is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_L1_CACHE_BYTES=128 +CONFIG_X86_INTERNODE_CACHE_BYTES=128 +CONFIG_X86_CMPXCHG=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_GOOD_APIC=y +CONFIG_X86_TSC=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_GART_IOMMU=y +CONFIG_CALGARY_IOMMU=y +CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y +CONFIG_SWIOTLB=y +CONFIG_NR_CPUS=64 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +# CONFIG_PREEMPT_BKL is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_NMI_WATCHDOG is not set +CONFIG_X86_MCE=y +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_MICROCODE=m +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m +CONFIG_NUMA=y +CONFIG_K8_NUMA=y +CONFIG_X86_64_ACPI_NUMA=y +# CONFIG_NUMA_EMU is not set +CONFIG_NODES_SHIFT=6 +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MIGRATION=y +CONFIG_RESOURCES_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_MTRR=y +CONFIG_SECCOMP=y +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR_ALL is not set +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RELOCATABLE=y +CONFIG_PHYSICAL_ALIGN=0x200000 +CONFIG_HOTPLUG_CPU=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y +CONFIG_OUT_OF_LINE_PFN_TO_PAGE=y + +# +# Power management options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +CONFIG_PM=y +CONFIG_PM_LEGACY=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_VERBOSE is not set +CONFIG_PM_TRACE=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SUSPEND=y +CONFIG_PM_DISABLE_CONSOLE=y +CONFIG_HIBERNATION_SMP_POSSIBLE=y +CONFIG_HIBERNATION=y +CONFIG_PM_STD_PARTITION="" +CONFIG_ACPI=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_PROCFS=y +CONFIG_ACPI_PROCFS_POWER=y +CONFIG_ACPI_SYSFS_POWER=y +CONFIG_ACPI_PROC_EVENT=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_VIDEO=m +CONFIG_ACPI_FAN=m +CONFIG_ACPI_DOCK=m +CONFIG_ACPI_BAY=m +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_NUMA=y +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_ACPI_CUSTOM_DSDT_INITRD=y +CONFIG_ACPI_BLACKLIST_YEAR=0 +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y +CONFIG_ACPI_CONTAINER=m +CONFIG_ACPI_SBS=m + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=m +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_POWERNOW_K8=m +CONFIG_X86_POWERNOW_K8_ACPI=y +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +# CONFIG_X86_SPEEDSTEP_LIB is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y + +# +# Bus options (PCI etc.) +# +CONFIG_PCI=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_DOMAINS=y +# CONFIG_DMAR is not set +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_PCIEAER=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_LEGACY=y +# CONFIG_PCI_DEBUG is not set +CONFIG_HT_IRQ=y +CONFIG_ISA_DMA_API=y +CONFIG_K8_NB=y +CONFIG_PCCARD=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA=m +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y +CONFIG_CARDBUS=y + +# +# PC-card bridges +# +CONFIG_YENTA=m +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_PD6729=m +CONFIG_I82092=m +CONFIG_PCCARD_NONSTATIC=m +CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI_FAKE=m +CONFIG_HOTPLUG_PCI_ACPI=m +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m +CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +CONFIG_HOTPLUG_PCI_SHPC=m + +# +# Executable file formats / Emulations +# +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_IA32_EMULATION=y +# CONFIG_IA32_AOUT is not set +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y + +# +# OpenVZ +# +CONFIG_VE=y +CONFIG_VE_CALLS=m +CONFIG_VZ_GENCALLS=y +CONFIG_VE_NETDEV=m +CONFIG_VE_ETHDEV=m +CONFIG_VZ_DEV=m +CONFIG_VE_IPTABLES=y +CONFIG_VZ_WDOG=m +CONFIG_VZ_CHECKPOINT=m + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_NET_NS=y +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_LRO=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +# CONFIG_DEFAULT_BIC is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_HTCP is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFAULT_RENO=y +CONFIG_DEFAULT_TCP_CONG="reno" +CONFIG_TCP_MD5SIG=y +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_NETWORK_SECMARK=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m + +# +# IP: Netfilter Configuration +# +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_SIP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_RAW=m + +# +# DECnet: Netfilter Configuration +# +CONFIG_DECNET_NF_GRABULATOR=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_IP_DCCP_ACKVEC=y + +# +# DCCP CCIDs Configuration (EXPERIMENTAL) +# +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +CONFIG_IP_DCCP_TFRC_LIB=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 + +# +# DCCP Kernel Hacking +# +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_NET_DCCPPROBE=m +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +CONFIG_ATM=y +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_DECNET=m +# CONFIG_DECNET_ROUTER is not set +CONFIG_LLC=y +CONFIG_LLC2=m +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RR=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +# CONFIG_NET_CLS_POLICE is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +CONFIG_NET_TCPPROBE=m +CONFIG_HAMRADIO=y + +# +# Packet Radio protocols +# +CONFIG_AX25=m +# CONFIG_AX25_DAMA_SLAVE is not set +CONFIG_NETROM=m +CONFIG_ROSE=m + +# +# AX.25 network device drivers +# +CONFIG_MKISS=m +CONFIG_6PACK=m +CONFIG_BPQETHER=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BAYCOM_PAR=m +CONFIG_YAM=m +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m +CONFIG_KINGSUN_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KS959_DONGLE=m + +# +# Old SIR device drivers +# + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +CONFIG_WINBOND_FIR=m +CONFIG_SMC_IRCC_FIR=m +CONFIG_ALI_FIR=m +CONFIG_VLSI_FIR=m +CONFIG_VIA_FIR=m +CONFIG_MCS_FIR=m +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_RXKAD=m +CONFIG_FIB_RULES=y + +# +# Wireless +# +CONFIG_CFG80211=m +CONFIG_NL80211=y +CONFIG_WIRELESS_EXT=y +CONFIG_MAC80211=m +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_DEBUGFS=y +# CONFIG_MAC80211_DEBUG is not set +CONFIG_IEEE80211=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_CRYPT_WEP=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +CONFIG_NET_9P=m +CONFIG_NET_9P_FD=m +CONFIG_NET_9P_VIRTIO=m +# CONFIG_NET_9P_DEBUG is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=m +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m +CONFIG_RFD_FTL=m +CONFIG_SSFDC=m +CONFIG_MTD_OOPS=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PNC2000=m +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_TS5500=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_DILNETPC=m +CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000 +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_PLATRAM=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_DATAFLASH=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTD_BLOCK2MTD=m + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCECC=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_IDS=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_2X_PROGRAM=y +CONFIG_MTD_ONENAND_SIM=m + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +CONFIG_MTD_UBI_GLUEBI=y + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_AX88796=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_NOT_PC=y +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_FD=m +CONFIG_PARIDE=m + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_SX8=m +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_VIRTIO_BLK=m +CONFIG_MISC_DEVICES=y +CONFIG_IBM_ASM=m +CONFIG_PHANTOM=m +CONFIG_EEPROM_93CX6=m +CONFIG_SGI_IOC4=m +CONFIG_TIFM_CORE=m +CONFIG_TIFM_7XX1=m +CONFIG_ASUS_LAPTOP=m +CONFIG_FUJITSU_LAPTOP=m +CONFIG_MSI_LAPTOP=m +CONFIG_SONY_LAPTOP=m +CONFIG_SONYPI_COMPAT=y +CONFIG_THINKPAD_ACPI=m +# CONFIG_THINKPAD_ACPI_DEBUG is not set +CONFIG_THINKPAD_ACPI_BAY=y +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_BLK_DEV_IDEACPI=y +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +CONFIG_BLK_DEV_PLATFORM=m +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +CONFIG_BLK_DEV_IDEPNP=y + +# +# PCI IDE chipsets support +# +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_GENERIC is not set +CONFIG_BLK_DEV_OPTI621=m +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI15X3=m +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=m +CONFIG_BLK_DEV_ATIIXP=m +CONFIG_BLK_DEV_CMD64X=m +# CONFIG_BLK_DEV_TRIFLEX is not set +CONFIG_BLK_DEV_CY82C693=m +# CONFIG_BLK_DEV_CS5520 is not set +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_HPT34X=m +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=m +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_SC1200=m +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +CONFIG_BLK_DEV_NS87415=m +CONFIG_BLK_DEV_PDC202XX_OLD=m +CONFIG_PDC202XX_BURST=y +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +CONFIG_BLK_DEV_TRM290=m +CONFIG_BLK_DEV_VIA82CXXX=m +CONFIG_BLK_DEV_TC86C001=m +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=m +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=m +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SAS_ATA=y +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_SCSI_AIC94XX=m +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPR_DUMP is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_ATA=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_ACPI=y +CONFIG_SATA_AHCI=m +CONFIG_SATA_SVW=m +CONFIG_ATA_PIIX=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_PDC_ADMA=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_SX4=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SATA_INIC162X=m +CONFIG_PATA_ACPI=m +# CONFIG_PATA_ALI is not set +CONFIG_PATA_AMD=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +# CONFIG_PATA_CMD640_PCI is not set +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CS5520=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +CONFIG_ATA_GENERIC=m +CONFIG_PATA_HPT366=m +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +CONFIG_PATA_HPT3X3=m +# CONFIG_PATA_HPT3X3_DMA is not set +CONFIG_PATA_IT821X=m +CONFIG_PATA_IT8213=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_NETCELL=m +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PCMCIA=m +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +CONFIG_PATA_PLATFORM=m +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m +CONFIG_DM_MULTIPATH_RDAC=m +CONFIG_DM_MULTIPATH_HP=m +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_SAS=m +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# Controllers +# +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocols +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_I2O=m +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_EXT_ADAPTEC_DMA64=y +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_BUS=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +CONFIG_IFB=m +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_MACVLAN=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_NET_SB1000=m +CONFIG_ARCNET=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_PHYLIB=m + +# +# MII PHY device drivers +# +CONFIG_MARVELL_PHY=m +CONFIG_DAVICOM_PHY=m +CONFIG_QSEMI_PHY=m +CONFIG_LXT_PHY=m +CONFIG_CICADA_PHY=m +CONFIG_VITESSE_PHY=m +CONFIG_SMSC_PHY=m +CONFIG_BROADCOM_PHY=m +CONFIG_ICPLUS_PHY=m +CONFIG_FIXED_PHY=m +# CONFIG_FIXED_MII_10_FDX is not set +# CONFIG_FIXED_MII_100_FDX is not set +CONFIG_FIXED_MII_1000_FDX=y +CONFIG_FIXED_MII_AMNT=1 +CONFIG_MDIO_BITBANG=m +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_ULI526X=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_HP100=m +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_AMD8111_ETH=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_B44=m +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI=y +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +CONFIG_EEPRO100=m +CONFIG_E100=m +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_RHINE_NAPI=y +CONFIG_SC92031=m +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_NETDEV_1000=y +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E1000E=m +CONFIG_IP1000=m +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_SIS190=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SK98LIN is not set +CONFIG_VIA_VELOCITY=m +CONFIG_TIGON3=m +CONFIG_BNX2=m +CONFIG_QLA3XXX=m +CONFIG_ATL1=m +CONFIG_NETDEV_10000=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_IXGBE=m +CONFIG_IXGB=m +# CONFIG_IXGB_NAPI is not set +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +CONFIG_MYRI10GE=m +CONFIG_NETXEN_NIC=m +CONFIG_NIU=m +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_TEHUTI=m +CONFIG_TR=y +CONFIG_IBMOL=m +CONFIG_3C359=m +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +CONFIG_ABYSS=m + +# +# Wireless LAN +# +CONFIG_WLAN_PRE80211=y +CONFIG_STRIP=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_WLAN_80211=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_IPW2100=m +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2200=m +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +# CONFIG_IPW2200_DEBUG is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_CS=m +CONFIG_LIBERTAS_SDIO=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_AIRO=m +CONFIG_HERMES=m +# CONFIG_PLX_HERMES is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_PCI_HERMES is not set +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PRISM54=m +CONFIG_USB_ZD1201=m +CONFIG_RTL8187=m +CONFIG_ADM8211=m +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +CONFIG_P54_PCI=m +# CONFIG_IWLWIFI is not set +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_CS=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_PIO=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +# CONFIG_BCM43XX_PIO_MODE is not set +CONFIG_B43=m +CONFIG_B43_PCI_AUTOSELECT=y +CONFIG_B43_PCICORE_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_LEDS=y +CONFIG_B43_RFKILL=y +# CONFIG_B43_DEBUG is not set +CONFIG_B43_DMA=y +CONFIG_B43_PIO=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +# CONFIG_B43_PIO_MODE is not set +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_PIO=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_RT2X00=m +CONFIG_RT2X00_LIB=m +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +# CONFIG_RT2X00_DEBUG is not set + +# +# USB Network Adapters +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_WAN=y +CONFIG_LANMEDIA=m +CONFIG_HDLC=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_X25=m +CONFIG_PCI200SYN=m +CONFIG_WANXL=m +CONFIG_PC300=m +CONFIG_PC300_MLPPP=y + +# +# Cyclades-PC300 MLPPP support is disabled. +# + +# +# Refer to the file README.mlppp, provided by PC300 package. +# +# CONFIG_PC300TOO is not set +CONFIG_FARSYNC=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +CONFIG_LAPBETHER=m +CONFIG_X25_ASY=m +CONFIG_SBNI=m +# CONFIG_SBNI_MULTILINE is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_TCP=m +CONFIG_ATM_LANAI=m +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_FORE200E_MAYBE=m +CONFIG_ATM_FORE200E_PCA=y +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_FORE200E_TX_RETRY=16 +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E=m +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_FDDI=y +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_SKFP=m +CONFIG_HIPPI=y +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +CONFIG_PPPOE=m +CONFIG_PPPOATM=m +CONFIG_PPPOL2TP=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLHC=m +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_NET_FC=y +CONFIG_SHAPER=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_VIRTIO_NET=m +CONFIG_ISDN=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y +CONFIG_ISDN_X25=y + +# +# ISDN feature submodules +# +CONFIG_ISDN_DIVERSION=m + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_KEYPAD is not set +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_GIGASET_BASE=m +CONFIG_GIGASET_M105=m +CONFIG_GIGASET_M101=m +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_UNDOCREQ is not set +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_CAPI_TRACE=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# +CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_POLLDEV=m + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_EVBUG=m + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_YEALINK=m +CONFIG_INPUT_UINPUT=m + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_DEV_KMEM is not set +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_COMPUTONE=m +CONFIG_ROCKETPORT=m +CONFIG_CYCLADES=m +# CONFIG_CYZ_INTR is not set +CONFIG_DIGIEPCA=m +CONFIG_MOXA_INTELLIO=m +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +# CONFIG_ISI is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_GT=m +CONFIG_N_HDLC=m +CONFIG_SPECIALIX=m +# CONFIG_SPECIALIX_RTSCTS is not set +CONFIG_SX=m +CONFIG_RIO=m +# CONFIG_RIO_OLDPCI is not set +CONFIG_STALDRV=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_CS=m +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +CONFIG_PPDEV=m +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPMI_POWEROFF=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_INTEL=m +CONFIG_HW_RANDOM_AMD=m +CONFIG_NVRAM=m +CONFIG_RTC=y +CONFIG_R3964=m +CONFIG_APPLICOM=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_MWAVE=m +CONFIG_PC8736x_GPIO=m +CONFIG_NSC_GPIO=m +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +CONFIG_HPET=y +# CONFIG_HPET_RTC_IRQ is not set +CONFIG_HPET_MMAP=y +CONFIG_HANGCHECK_TIMER=m +CONFIG_TCG_TPM=m +CONFIG_TCG_TIS=m +CONFIG_TCG_NSC=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TELCLOCK=m +CONFIG_DEVPORT=y +CONFIG_I2C=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Miscellaneous I2C Chip support +# +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_DS1682=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_TSL2550=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +CONFIG_SPI_LM70_LLP=m + +# +# SPI Protocol Masters +# +CONFIG_SPI_AT25=m +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_W1=m +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PDA_POWER=m +CONFIG_BATTERY_DS2760=m +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_HDAPS=m +CONFIG_SENSORS_APPLESMC=m +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_WAFER_WDT=m +CONFIG_I6300ESB_WDT=m +CONFIG_ITCO_WDT=m +CONFIG_ITCO_VENDOR_SUPPORT=y +CONFIG_IT8712F_WDT=m +CONFIG_SC1200_WDT=m +CONFIG_PC87413_WDT=m +CONFIG_60XX_WDT=m +CONFIG_SBC8360_WDT=m +CONFIG_CPU5_WDT=m +CONFIG_SMSC37B787_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83697HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_MACHZ_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +# CONFIG_SSB_PCMCIAHOST is not set +# CONFIG_SSB_SILENT is not set +# CONFIG_SSB_DEBUG is not set +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_DRIVER_PCICORE=y + +# +# Multifunction device drivers +# +CONFIG_MFD_SM501=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders/decoders and other helper chips +# + +# +# Audio decoders +# +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_VP27SMPX=m + +# +# Video decoders +# +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_TCM825X=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7191=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_VPX3220=m + +# +# Video and audio decoders +# +CONFIG_VIDEO_CX25840=m + +# +# MPEG video encoders +# +CONFIG_VIDEO_CX2341X=m + +# +# Video encoders +# +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m + +# +# Video improvement chips +# +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_OSS=m +CONFIG_VIDEO_SAA7134_DVB=m +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_DPC is not set +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_29XXX=y +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_SYSFS=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_USB_VICAM=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_ET61X251=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_USB_W9968CF=m +# CONFIG_USB_OV511 is not set +CONFIG_USB_SE401=m +CONFIG_USB_SN9C102=m +CONFIG_USB_STV680=m +CONFIG_USB_ZC0301=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_ZR364XX=m +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_USB_DSBR=m +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CAPTURE_DRIVERS=y + +# +# Supported SAA7146 based PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +# +# Supported USB Adapters +# +CONFIG_DVB_USB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 + +# +# Supported FlexCopII (B2C2) Adapters +# +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m + +# +# Supported Pluto2 Adapters +# +CONFIG_DVB_PLUTO2=m + +# +# Supported DVB Frontends +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_FE_CUSTOMISE is not set + +# +# DVB-S (satellite) frontends +# +CONFIG_DVB_STV0299=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_TDA10086=m + +# +# DVB-T (terrestrial) frontends +# +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_L64781=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_ZL10353=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m + +# +# DVB-C (cable) frontends +# +CONFIG_DVB_VES1820=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_STV0297=m + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +CONFIG_DVB_NXT200X=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_S5H1409=m + +# +# Tuners/PLL support +# +CONFIG_DVB_PLL=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +CONFIG_DVB_TUNER_QT1010=m +CONFIG_DVB_TUNER_MT2060=m +CONFIG_DVB_TUNER_MT2266=m +CONFIG_DVB_TUNER_MT2131=m +CONFIG_DVB_TUNER_DIB0070=m + +# +# Miscellaneous devices +# +CONFIG_DVB_LNBP21=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_TUA6100=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TUNER_SIMPLE=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_DAB=y +CONFIG_USB_DABUSB=m + +# +# Graphics support +# +CONFIG_AGP=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=m +CONFIG_AGP_SIS=m +CONFIG_AGP_VIA=m +CONFIG_DRM=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_I915=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m +CONFIG_DRM_VIA=m +CONFIG_DRM_SAVAGE=m +CONFIG_VGASTATE=m +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_DDC=m +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_IMAGEBLIT=m +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_SVGALIB=m +# CONFIG_FB_MACMODES is not set +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +CONFIG_FB_CIRRUS=m +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_CYBER2000=m +CONFIG_FB_ARC=m +CONFIG_FB_ASILIANT=y +CONFIG_FB_IMSTT=y +CONFIG_FB_VGA16=m +CONFIG_FB_UVESA=m +CONFIG_FB_VESA=m +CONFIG_FB_EFI=y +CONFIG_FB_HECUBA=m +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_S1D13XXX=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_I2C=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_BACKLIGHT=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_I2C=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_BACKLIGHT=y +CONFIG_FB_LE80578=m +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_ARK=m +CONFIG_FB_PM3=m +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_LX=m +CONFIG_FB_GEODE_GX=m +# CONFIG_FB_GEODE_GX_SET_FBSIZE is not set +CONFIG_FB_GEODE_GX1=m +CONFIG_FB_SM501=m +# CONFIG_FB_VIRTUAL is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_PROGEAR=m +CONFIG_BACKLIGHT_CARILLO_RANCH=m + +# +# Display device support +# +CONFIG_DISPLAY_SUPPORT=m + +# +# Display hardware drivers +# + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VIDEO_SELECT=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=m +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_LOGO is not set + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_MPU401=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_SB_COMMON=m +CONFIG_SND_SB16_DSP=m + +# +# PCI devices +# +CONFIG_SND_AD1889=m +CONFIG_SND_ALS300=m +CONFIG_SND_ALS4000=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_BT87X_OVERCLOCK=y +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS5530=m +CONFIG_SND_DARLA20=m +CONFIG_SND_GINA20=m +CONFIG_SND_LAYLA20=m +CONFIG_SND_DARLA24=m +CONFIG_SND_GINA24=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MONA=m +CONFIG_SND_MIA=m +CONFIG_SND_ECHO3G=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_CODEC_ANALOG=y +CONFIG_SND_HDA_CODEC_SIGMATEL=y +CONFIG_SND_HDA_CODEC_VIA=y +CONFIG_SND_HDA_CODEC_ATIHDMI=y +CONFIG_SND_HDA_CODEC_CONEXANT=y +CONFIG_SND_HDA_CODEC_CMEDIA=y +CONFIG_SND_HDA_CODEC_SI3054=y +CONFIG_SND_HDA_GENERIC=y +CONFIG_SND_HDA_POWER_SAVE=y +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_KORG1212_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MAESTRO3_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_PCXHR=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VX222=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 + +# +# SPI devices +# + +# +# USB devices +# +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_USX2Y=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y + +# +# PCMCIA devices +# +CONFIG_SND_VXPOCKET=m +CONFIG_SND_PDAUDIOCF=m + +# +# System on Chip audio support +# +CONFIG_SND_SOC=m + +# +# SoC Audio support for SuperH +# + +# +# Open Sound System +# +CONFIG_SOUND_PRIME=m +CONFIG_SOUND_TRIDENT=m +CONFIG_SOUND_MSNDCLAS=m +CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin" +CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin" +CONFIG_SOUND_MSNDPIN=m +CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin" +CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin" +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +CONFIG_SOUND_DMAP=y +CONFIG_SOUND_SSCAPE=m +CONFIG_SOUND_VMIDI=m +CONFIG_SOUND_TRIX=m +CONFIG_SOUND_MSS=m +CONFIG_SOUND_MPU401=m +CONFIG_SOUND_PAS=m +CONFIG_SOUND_PSS=m +CONFIG_PSS_MIXER=y +CONFIG_SOUND_SB=m +CONFIG_SOUND_YM3812=m +CONFIG_SOUND_UART6850=m +CONFIG_SOUND_AEDSP16=m +CONFIG_SC6600=y +CONFIG_SC6600_JOY=y +CONFIG_SC6600_CDROM=4 +CONFIG_SC6600_CDROMBASE=0 +CONFIG_AEDSP16_MSS=y +# CONFIG_AEDSP16_SBPRO is not set +CONFIG_SOUND_KAHLUA=m +CONFIG_AC97_BUS=m +CONFIG_HID_SUPPORT=y +CONFIG_HID=m +# CONFIG_HID_DEBUG is not set +CONFIG_HIDRAW=y + +# +# USB Input Devices +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT_POWERBOOK=y +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_PERSIST is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_ISP116X_HCD=m +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_HCD_SSB=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SL811_CS=m +CONFIG_USB_R8A66597_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_MON=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +# CONFIG_USB_SERIAL_IR is not set +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_LED=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_IOWARRIOR=m +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# +CONFIG_USB_ATM=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_CXACRU=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=m +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_GADGET_AMD5536UDC=y +CONFIG_USB_AMD5536UDC=m +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_GADGETFS=m +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_G_SERIAL=m +# CONFIG_USB_MIDI_GADGET is not set + +# +# MMC/SD/SDIO support, can only select one arch from MMC and MSS +# +CONFIG_MMC=m +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_SDIO_UART=m + +# +# MMC/SD Host Controller Drivers +# +CONFIG_MMC_SDHCI=m +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_WBSD=m +CONFIG_MMC_TIFM_SD=m +CONFIG_MMC_SPI=m +# CONFIG_MSS is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=m + +# +# LED drivers +# + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_IPATH=m +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_MLX4_INFINIBAND=m +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_ISER=m +CONFIG_EDAC=y + +# +# Reporting subsystems +# +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_MM_EDAC=m +CONFIG_EDAC_E752X=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_I5000=m +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_DRV_TEST=m + +# +# I2C RTC drivers +# +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y + +# +# SPI RTC drivers +# +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_MAX6902=m + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_V3020=m + +# +# on-CPU RTC drivers +# +CONFIG_DMADEVICES=y + +# +# DMA Devices +# +CONFIG_INTEL_IOATDMA=m +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +CONFIG_NET_DMA=y +CONFIG_DCA=m +CONFIG_AUXDISPLAY=y +CONFIG_KS0108=m +CONFIG_KS0108_PORT=0x378 +CONFIG_KS0108_DELAY=2 +CONFIG_CFAG12864B=m +CONFIG_CFAG12864B_RATE=20 + +# +# Userspace I/O +# +CONFIG_UIO=m +CONFIG_UIO_CIF=m + +# +# Firmware Drivers +# +CONFIG_EDD=y +# CONFIG_EDD_OFF is not set +CONFIG_DELL_RBU=m +CONFIG_DCDBAS=m +CONFIG_DMIID=y + +# +# File systems +# +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=m +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_STATISTICS=y +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_NOLOCK=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_OCFS2_FS=m +CONFIG_OCFS2_DEBUG_MASKLOG=y +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_QUOTA_COMPAT=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_SIM_FS=m +CONFIG_VZ_QUOTA=m +# CONFIG_VZ_QUOTA_UNLOAD is not set +CONFIG_VZ_QUOTA_UGID=y +CONFIG_QUOTACTL=y +CONFIG_DNOTIFY=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=m +CONFIG_GENERIC_ACL=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_CONFIGFS_FS=m + +# +# Miscellaneous filesystems +# +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +CONFIG_CRAMFS=y +CONFIG_VXFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_UFS_DEBUG is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_XPRT_RDMA=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_EXPERIMENTAL is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +CONFIG_CODA_FS=m +# CONFIG_CODA_FS_OLD_API is not set +CONFIG_AFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_9P_FS=m +CONFIG_DEFAULT_RELATIME=y +CONFIG_DEFAULT_RELATIME_VAL=1 + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_CUMANA is not set +# CONFIG_ACORN_PARTITION_EESOX is not set +CONFIG_ACORN_PARTITION_ICS=y +# CONFIG_ACORN_PARTITION_ADFS is not set +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_ATARI_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +CONFIG_SGI_PARTITION=y +CONFIG_ULTRIX_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_SYSV68_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_INSTRUMENTATION=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=m +CONFIG_KPROBES=y +# CONFIG_MARKERS is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_PRINTK_TIME=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_SYSRQ_DEBUG=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_FORCED_INLINING is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_LKDTM is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SAMPLES is not set +CONFIG_NONPROMISC_DEVMEM=y +CONFIG_EARLY_PRINTK=y +# CONFIG_WRAPPER_PRINT is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_RODATA is not set +# CONFIG_IOMMU_DEBUG is not set +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +CONFIG_IO_DELAY_TYPE_NONE=3 +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_DEFAULT_IO_DELAY_TYPE=0 + +# +# Security options +# + +# +# Grsecurity +# +CONFIG_GRKERNSEC=y + +# +# Executable Protections +# +CONFIG_GRKERNSEC_TPE=y +CONFIG_GRKERNSEC_TPE_ALL=y +# CONFIG_GRKERNSEC_TPE_INVERT is not set +CONFIG_GRKERNSEC_TPE_GID=1005 + +# +# Sysctl support +# +CONFIG_GRKERNSEC_SYSCTL=y +# CONFIG_GRKERNSEC_SYSCTL_ON is not set + +# +# Logging Options +# +CONFIG_GRKERNSEC_FLOODTIME=10 +CONFIG_GRKERNSEC_FLOODBURST=4 +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_TWOFISH_X86_64=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_AES_X86_64=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_HW=y +CONFIG_HAVE_KVM=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_INTEL=m +CONFIG_KVM_AMD=m +CONFIG_VIRTIO=m +CONFIG_VIRTIO_RING=m +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_BALLOON=m + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CHECK_SIGNATURE=y + +# +# User resources +# +CONFIG_BEANCOUNTERS=y +CONFIG_BC_RSS_ACCOUNTING=y +CONFIG_BC_IO_ACCOUNTING=y +CONFIG_BC_IO_SCHED=y +CONFIG_BC_SWAP_ACCOUNTING=y +CONFIG_BC_PROC=y +# CONFIG_BC_DEBUG is not set +CONFIG_DRM_VIA_CHROME9=m --- linux-2.6.24.orig/debian/binary-custom.d/openvz/config.i386 +++ linux-2.6.24/debian/binary-custom.d/openvz/config.i386 @@ -0,0 +1,4194 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.24-16-openvz +# Thu Apr 10 06:21:17 2008 +# +# CONFIG_64BIT is not set +CONFIG_X86_32=y +# CONFIG_X86_64 is not set +CONFIG_X86=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_SEMAPHORE_SLEEPERS=y +CONFIG_MMU=y +CONFIG_ZONE_DMA=y +CONFIG_QUICKLIST=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_DMI=y +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME_VSYSCALL is not set +CONFIG_ARCH_SUPPORTS_OPROFILE=y +# CONFIG_ZONE_DMA32 is not set +CONFIG_ARCH_POPULATES_NODE_MAP=y +# CONFIG_AUDIT_ARCH is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_X86_SMP=y +CONFIG_X86_HT=y +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_TRAMPOLINE=y +CONFIG_KTIME_SCALAR=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-4.6-server" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_TREE=y +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_NS=y +CONFIG_CPUSETS=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_FAIR_USER_SCHED is not set +# CONFIG_FAIR_CGROUP_SCHED is not set +CONFIG_VZ_FAIRSCHED=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_PROC_PID_CPUSET=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBD=y +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_LSM_MMAP_MIN_ADDR=0 + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_PREEMPT_NOTIFIERS=y + +# +# Processor type and features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_SMP=y +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_X86_VSMP is not set +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_GUEST=y +CONFIG_XEN=y +CONFIG_VMI=y +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +CONFIG_M686=y +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MEFFICEON is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_GENERIC_CPU is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_XADD=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_GOOD_APIC=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_TSC=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=4 +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_NR_CPUS=8 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +# CONFIG_PREEMPT_BKL is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_NMI_WATCHDOG is not set +# CONFIG_X86_MCE is not set +CONFIG_VM86=y +CONFIG_TOSHIBA=m +CONFIG_I8K=m +CONFIG_X86_REBOOTFIXUPS=y +CONFIG_MICROCODE=m +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m +# CONFIG_NOHIGHMEM is not set +# CONFIG_HIGHMEM4G is not set +CONFIG_HIGHMEM64G=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_HIGHMEM=y +CONFIG_X86_PAE=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_SPARSEMEM_STATIC=y +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_RESOURCES_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_NR_QUICK=1 +CONFIG_VIRT_TO_BUS=y +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +CONFIG_EFI=y +# CONFIG_IRQBALANCE is not set +CONFIG_BOOT_IOREMAP=y +CONFIG_SECCOMP=y +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +CONFIG_PHYSICAL_START=0x100000 +CONFIG_RELOCATABLE=y +CONFIG_PHYSICAL_ALIGN=0x100000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_COMPAT_VDSO is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y + +# +# Power management options +# +CONFIG_PM=y +CONFIG_PM_LEGACY=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_VERBOSE is not set +CONFIG_PM_TRACE=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SUSPEND=y +CONFIG_PM_DISABLE_CONSOLE=y +CONFIG_HIBERNATION_SMP_POSSIBLE=y +CONFIG_HIBERNATION=y +CONFIG_PM_STD_PARTITION="" +CONFIG_ACPI=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_PROCFS=y +CONFIG_ACPI_PROCFS_POWER=y +CONFIG_ACPI_SYSFS_POWER=y +CONFIG_ACPI_PROC_EVENT=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_VIDEO=m +CONFIG_ACPI_FAN=m +CONFIG_ACPI_DOCK=m +CONFIG_ACPI_BAY=m +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_ACPI_CUSTOM_DSDT_INITRD=y +CONFIG_ACPI_BLACKLIST_YEAR=2000 +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y +CONFIG_ACPI_CONTAINER=m +CONFIG_ACPI_SBS=m +CONFIG_APM=m +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +# CONFIG_APM_CPU_IDLE is not set +# CONFIG_APM_DISPLAY_BLANK is not set +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=m +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=m +CONFIG_X86_POWERNOW_K7_ACPI=y +CONFIG_X86_POWERNOW_K8=m +CONFIG_X86_POWERNOW_K8_ACPI=y +CONFIG_X86_GX_SUSPMOD=m +CONFIG_X86_SPEEDSTEP_CENTRINO=m +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_ICH=m +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_CPUFREQ_NFORCE2=m +CONFIG_X86_LONGRUN=m +CONFIG_X86_LONGHAUL=m +# CONFIG_X86_E_POWERSAVER is not set + +# +# shared options +# +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_SPEEDSTEP_LIB=m +CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y + +# +# Bus options (PCI etc.) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_PCIEAER=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_LEGACY=y +# CONFIG_PCI_DEBUG is not set +CONFIG_HT_IRQ=y +CONFIG_ISA_DMA_API=y +CONFIG_ISA=y +CONFIG_EISA=y +CONFIG_EISA_VLB_PRIMING=y +CONFIG_EISA_PCI_EISA=y +CONFIG_EISA_VIRTUAL_ROOT=y +CONFIG_EISA_NAMES=y +CONFIG_MCA=y +CONFIG_MCA_LEGACY=y +# CONFIG_MCA_PROC_FS is not set +CONFIG_SCx200=m +CONFIG_SCx200HR_TIMER=m +CONFIG_K8_NB=y +CONFIG_PCCARD=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA=m +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y +CONFIG_CARDBUS=y + +# +# PC-card bridges +# +CONFIG_YENTA=m +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_PD6729=m +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_TCIC=m +CONFIG_PCMCIA_PROBE=y +CONFIG_PCCARD_NONSTATIC=m +CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI_FAKE=m +CONFIG_HOTPLUG_PCI_COMPAQ=m +CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM=y +CONFIG_HOTPLUG_PCI_IBM=m +CONFIG_HOTPLUG_PCI_ACPI=m +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m +CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +CONFIG_HOTPLUG_PCI_SHPC=m + +# +# Executable file formats / Emulations +# +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=m +CONFIG_BINFMT_MISC=m + +# +# OpenVZ +# +CONFIG_VE=y +CONFIG_VE_CALLS=m +CONFIG_VZ_GENCALLS=y +CONFIG_VE_NETDEV=m +CONFIG_VE_ETHDEV=m +CONFIG_VZ_DEV=m +CONFIG_VE_IPTABLES=y +CONFIG_VZ_WDOG=m +CONFIG_VZ_CHECKPOINT=m + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_NET_NS=y +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_LRO=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +# CONFIG_DEFAULT_BIC is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_HTCP is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFAULT_RENO=y +CONFIG_DEFAULT_TCP_CONG="reno" +CONFIG_TCP_MD5SIG=y +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_NETWORK_SECMARK=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m + +# +# IP: Netfilter Configuration +# +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_SIP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_RAW=m + +# +# DECnet: Netfilter Configuration +# +CONFIG_DECNET_NF_GRABULATOR=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_IP_DCCP_ACKVEC=y + +# +# DCCP CCIDs Configuration (EXPERIMENTAL) +# +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +CONFIG_IP_DCCP_TFRC_LIB=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 + +# +# DCCP Kernel Hacking +# +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_NET_DCCPPROBE=m +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +CONFIG_ATM=y +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_DECNET=m +# CONFIG_DECNET_ROUTER is not set +CONFIG_LLC=y +CONFIG_LLC2=m +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_LTPC=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RR=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +# CONFIG_NET_CLS_POLICE is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +CONFIG_NET_TCPPROBE=m +CONFIG_HAMRADIO=y + +# +# Packet Radio protocols +# +CONFIG_AX25=m +# CONFIG_AX25_DAMA_SLAVE is not set +CONFIG_NETROM=m +CONFIG_ROSE=m + +# +# AX.25 network device drivers +# +CONFIG_MKISS=m +CONFIG_6PACK=m +CONFIG_BPQETHER=m +CONFIG_SCC=m +# CONFIG_SCC_DELAY is not set +# CONFIG_SCC_TRXECHO is not set +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_EPP=m +CONFIG_YAM=m +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m +CONFIG_KINGSUN_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KS959_DONGLE=m + +# +# Old SIR device drivers +# + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +CONFIG_WINBOND_FIR=m +CONFIG_TOSHIBA_FIR=m +CONFIG_SMC_IRCC_FIR=m +CONFIG_ALI_FIR=m +CONFIG_VLSI_FIR=m +CONFIG_VIA_FIR=m +CONFIG_MCS_FIR=m +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_RXKAD=m +CONFIG_FIB_RULES=y + +# +# Wireless +# +CONFIG_CFG80211=m +CONFIG_NL80211=y +CONFIG_WIRELESS_EXT=y +CONFIG_MAC80211=m +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_DEBUGFS=y +# CONFIG_MAC80211_DEBUG is not set +CONFIG_IEEE80211=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_CRYPT_WEP=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +CONFIG_NET_9P=m +CONFIG_NET_9P_FD=m +CONFIG_NET_9P_VIRTIO=m +# CONFIG_NET_9P_DEBUG is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=m +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m +CONFIG_RFD_FTL=m +CONFIG_SSFDC=m +CONFIG_MTD_OOPS=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PNC2000=m +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_TS5500=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_DILNETPC=m +CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000 +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_PLATRAM=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_DATAFLASH=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTD_BLOCK2MTD=m + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCECC=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_IDS=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_CS553X=m +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_2X_PROGRAM=y +CONFIG_MTD_ONENAND_SIM=m + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +CONFIG_MTD_UBI_GLUEBI=y + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_AX88796=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_NOT_PC=y +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y +CONFIG_PNPBIOS=y +CONFIG_PNPBIOS_PROC_FS=y +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_FD=m +CONFIG_BLK_DEV_XD=m +CONFIG_PARIDE=m + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_BPCK6=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_SX8=m +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_XEN_BLKDEV_FRONTEND=m +CONFIG_VIRTIO_BLK=m +CONFIG_MISC_DEVICES=y +CONFIG_IBM_ASM=m +CONFIG_PHANTOM=m +CONFIG_EEPROM_93CX6=m +CONFIG_SGI_IOC4=m +CONFIG_TIFM_CORE=m +CONFIG_TIFM_7XX1=m +CONFIG_ASUS_LAPTOP=m +CONFIG_FUJITSU_LAPTOP=m +CONFIG_MSI_LAPTOP=m +CONFIG_SONY_LAPTOP=m +CONFIG_SONYPI_COMPAT=y +CONFIG_THINKPAD_ACPI=m +# CONFIG_THINKPAD_ACPI_DEBUG is not set +CONFIG_THINKPAD_ACPI_BAY=y +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_BLK_DEV_IDEACPI=y +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +CONFIG_BLK_DEV_PLATFORM=m +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +CONFIG_BLK_DEV_IDEPNP=y + +# +# PCI IDE chipsets support +# +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_GENERIC is not set +CONFIG_BLK_DEV_OPTI621=m +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI15X3=m +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=m +CONFIG_BLK_DEV_ATIIXP=m +CONFIG_BLK_DEV_CMD64X=m +# CONFIG_BLK_DEV_TRIFLEX is not set +CONFIG_BLK_DEV_CY82C693=m +# CONFIG_BLK_DEV_CS5520 is not set +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_CS5535=m +CONFIG_BLK_DEV_HPT34X=m +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=m +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_SC1200=m +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +CONFIG_BLK_DEV_NS87415=m +CONFIG_BLK_DEV_PDC202XX_OLD=m +CONFIG_PDC202XX_BURST=y +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +CONFIG_BLK_DEV_TRM290=m +CONFIG_BLK_DEV_VIA82CXXX=m +CONFIG_BLK_DEV_TC86C001=m +# CONFIG_IDE_ARM is not set + +# +# Other IDE chipsets support +# + +# +# Note: most of these also require special kernel boot parameters +# +CONFIG_BLK_DEV_4DRIVES=y +CONFIG_BLK_DEV_ALI14XX=m +CONFIG_BLK_DEV_DTC2278=m +CONFIG_BLK_DEV_HT6560B=m +CONFIG_BLK_DEV_QD65XX=m +CONFIG_BLK_DEV_UMC8672=m +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=m +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=m +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SAS_ATA=y +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_7000FASST=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AHA1740=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_SCSI_AIC94XX=m +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_DTC3280=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_FD_MCS=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_GENERIC_NCR5380=m +CONFIG_SCSI_GENERIC_NCR5380_MMIO=m +CONFIG_SCSI_GENERIC_NCR53C400=y +CONFIG_SCSI_IBMMCA=m +CONFIG_IBMMCA_SCSI_ORDER_STANDARD=y +# CONFIG_IBMMCA_SCSI_DEV_RESET is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_NCR53C406A=m +CONFIG_SCSI_NCR_D700=m +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPR_DUMP is not set +CONFIG_SCSI_NCR_Q720=m +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 +CONFIG_SCSI_NCR53C8XX_SYNC=5 +CONFIG_SCSI_PAS16=m +CONFIG_SCSI_PSI240I=m +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_SEAGATE=m +CONFIG_SCSI_SIM710=m +CONFIG_SCSI_SYM53C416=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_T128=m +CONFIG_SCSI_U14_34F=m +CONFIG_SCSI_U14_34F_TAGGED_QUEUE=y +CONFIG_SCSI_U14_34F_LINKED_COMMANDS=y +CONFIG_SCSI_U14_34F_MAX_TAGS=8 +CONFIG_SCSI_ULTRASTOR=m +CONFIG_SCSI_NSP32=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_ATA=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_ACPI=y +CONFIG_SATA_AHCI=m +CONFIG_SATA_SVW=m +CONFIG_ATA_PIIX=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_PDC_ADMA=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_SX4=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SATA_INIC162X=m +CONFIG_PATA_ACPI=m +# CONFIG_PATA_ALI is not set +CONFIG_PATA_AMD=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +# CONFIG_PATA_CMD640_PCI is not set +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CS5520=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +CONFIG_PATA_CS5536=m +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +CONFIG_ATA_GENERIC=m +CONFIG_PATA_HPT366=m +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +CONFIG_PATA_HPT3X3=m +# CONFIG_PATA_HPT3X3_DMA is not set +# CONFIG_PATA_ISAPNP is not set +CONFIG_PATA_IT821X=m +CONFIG_PATA_IT8213=m +CONFIG_PATA_JMICRON=m +# CONFIG_PATA_LEGACY is not set +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_NETCELL=m +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PCMCIA=m +# CONFIG_PATA_PDC_OLD is not set +CONFIG_PATA_QDI=m +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +# CONFIG_PATA_WINBOND_VLB is not set +CONFIG_PATA_PLATFORM=m +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m +CONFIG_DM_MULTIPATH_RDAC=m +CONFIG_DM_MULTIPATH_HP=m +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_SAS=m +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# Controllers +# +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocols +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_I2O=m +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_EXT_ADAPTEC_DMA64=y +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_BUS=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +CONFIG_IFB=m +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_MACVLAN=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_NET_SB1000=m +CONFIG_ARCNET=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_ISA=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_PHYLIB=m + +# +# MII PHY device drivers +# +CONFIG_MARVELL_PHY=m +CONFIG_DAVICOM_PHY=m +CONFIG_QSEMI_PHY=m +CONFIG_LXT_PHY=m +CONFIG_CICADA_PHY=m +CONFIG_VITESSE_PHY=m +CONFIG_SMSC_PHY=m +CONFIG_BROADCOM_PHY=m +CONFIG_ICPLUS_PHY=m +CONFIG_FIXED_PHY=m +# CONFIG_FIXED_MII_10_FDX is not set +# CONFIG_FIXED_MII_100_FDX is not set +CONFIG_FIXED_MII_1000_FDX=y +CONFIG_FIXED_MII_AMNT=1 +CONFIG_MDIO_BITBANG=m +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_ELMC=m +CONFIG_ELMC_II=m +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRAMCA=m +CONFIG_ULTRA=m +CONFIG_ULTRA32=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +CONFIG_NI52=m +CONFIG_NI65=m +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_ULI526X=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_AT1700=m +CONFIG_DEPCA=m +CONFIG_HP100=m +CONFIG_NET_ISA=y +CONFIG_E2100=m +CONFIG_EWRK3=m +CONFIG_EEXPRESS=m +CONFIG_EEXPRESS_PRO=m +CONFIG_HPLAN_PLUS=m +CONFIG_HPLAN=m +CONFIG_LP486E=m +CONFIG_ETH16I=m +CONFIG_NE2000=m +CONFIG_ZNET=m +CONFIG_SEEQ8005=m +CONFIG_NE2_MCA=m +CONFIG_IBMLANA=m +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_AMD8111_ETH=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI=y +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +CONFIG_CS89x0=m +CONFIG_EEPRO100=m +CONFIG_E100=m +CONFIG_LNE390=m +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_NE3210=m +CONFIG_ES3210=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_RHINE_NAPI=y +CONFIG_SC92031=m +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_NETDEV_1000=y +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E1000E=m +CONFIG_IP1000=m +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_SIS190=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SK98LIN is not set +CONFIG_VIA_VELOCITY=m +CONFIG_TIGON3=m +CONFIG_BNX2=m +CONFIG_QLA3XXX=m +CONFIG_ATL1=m +CONFIG_NETDEV_10000=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_IXGBE=m +CONFIG_IXGB=m +# CONFIG_IXGB_NAPI is not set +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +CONFIG_MYRI10GE=m +CONFIG_NETXEN_NIC=m +CONFIG_NIU=m +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_TEHUTI=m +CONFIG_TR=y +CONFIG_IBMTR=m +CONFIG_IBMOL=m +CONFIG_IBMLS=m +CONFIG_3C359=m +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +CONFIG_SKISA=m +CONFIG_PROTEON=m +CONFIG_ABYSS=m +CONFIG_MADGEMC=m +CONFIG_SMCTR=m + +# +# Wireless LAN +# +CONFIG_WLAN_PRE80211=y +CONFIG_STRIP=m +CONFIG_ARLAN=m +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_WLAN_80211=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_IPW2100=m +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2200=m +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +# CONFIG_IPW2200_DEBUG is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_CS=m +CONFIG_LIBERTAS_SDIO=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_AIRO=m +CONFIG_HERMES=m +# CONFIG_PLX_HERMES is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_PCI_HERMES is not set +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PRISM54=m +CONFIG_USB_ZD1201=m +CONFIG_RTL8187=m +CONFIG_ADM8211=m +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +CONFIG_P54_PCI=m +# CONFIG_IWLWIFI is not set +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_CS=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_PIO=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +# CONFIG_BCM43XX_PIO_MODE is not set +CONFIG_B43=m +CONFIG_B43_PCI_AUTOSELECT=y +CONFIG_B43_PCICORE_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_LEDS=y +CONFIG_B43_RFKILL=y +# CONFIG_B43_DEBUG is not set +CONFIG_B43_DMA=y +CONFIG_B43_PIO=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +# CONFIG_B43_PIO_MODE is not set +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_PIO=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_RT2X00=m +CONFIG_RT2X00_LIB=m +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +# CONFIG_RT2X00_DEBUG is not set + +# +# USB Network Adapters +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_PCMCIA_IBMTR=m +CONFIG_WAN=y +CONFIG_HOSTESS_SV11=m +CONFIG_COSA=m +CONFIG_LANMEDIA=m +CONFIG_SEALEVEL_4021=m +CONFIG_HDLC=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_X25=m +CONFIG_PCI200SYN=m +CONFIG_WANXL=m +CONFIG_PC300=m +CONFIG_PC300_MLPPP=y + +# +# Cyclades-PC300 MLPPP support is disabled. +# + +# +# Refer to the file README.mlppp, provided by PC300 package. +# +# CONFIG_PC300TOO is not set +CONFIG_N2=m +CONFIG_C101=m +CONFIG_FARSYNC=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_SDLA=m +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +CONFIG_LAPBETHER=m +CONFIG_X25_ASY=m +CONFIG_SBNI=m +# CONFIG_SBNI_MULTILINE is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_TCP=m +CONFIG_ATM_LANAI=m +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_ATM_NICSTAR=m +# CONFIG_ATM_NICSTAR_USE_SUNI is not set +# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_FORE200E_MAYBE=m +CONFIG_ATM_FORE200E_PCA=y +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_FORE200E_TX_RETRY=16 +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E=m +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_XEN_NETDEV_FRONTEND=m +CONFIG_FDDI=y +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_SKFP=m +CONFIG_HIPPI=y +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +CONFIG_PPPOE=m +CONFIG_PPPOATM=m +CONFIG_PPPOL2TP=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLHC=m +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_NET_FC=y +CONFIG_SHAPER=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_VIRTIO_NET=m +CONFIG_ISDN=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y +CONFIG_ISDN_X25=y + +# +# ISDN feature submodules +# +CONFIG_ISDN_DIVERSION=m + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_KEYPAD is not set +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_GIGASET_BASE=m +CONFIG_GIGASET_M105=m +CONFIG_GIGASET_M101=m +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_UNDOCREQ is not set +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_CAPI_TRACE=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# +CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_T1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_POLLDEV=m + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_EVBUG=m + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_INPORT=m +# CONFIG_MOUSE_ATIXL is not set +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +CONFIG_INPUT_WISTRON_BTNS=m +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_YEALINK=m +CONFIG_INPUT_UINPUT=m + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_DEV_KMEM is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +CONFIG_ROCKETPORT=m +CONFIG_CYCLADES=m +# CONFIG_CYZ_INTR is not set +CONFIG_DIGIEPCA=m +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +# CONFIG_ISI is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_GT=m +CONFIG_N_HDLC=m +CONFIG_SPECIALIX=m +# CONFIG_SPECIALIX_RTSCTS is not set +CONFIG_SX=m +# CONFIG_RIO is not set +CONFIG_STALDRV=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_CS=m +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_FOURPORT=m +CONFIG_SERIAL_8250_ACCENT=m +CONFIG_SERIAL_8250_BOCA=m +CONFIG_SERIAL_8250_EXAR_ST16C554=m +CONFIG_SERIAL_8250_HUB6=m +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_MCA=m + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +CONFIG_PPDEV=m +CONFIG_HVC_DRIVER=y +CONFIG_HVC_XEN=y +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPMI_POWEROFF=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_INTEL=m +CONFIG_HW_RANDOM_AMD=m +CONFIG_HW_RANDOM_GEODE=m +CONFIG_HW_RANDOM_VIA=m +CONFIG_NVRAM=m +CONFIG_RTC=y +CONFIG_DTLK=m +CONFIG_R3964=m +CONFIG_APPLICOM=m +CONFIG_SONYPI=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_MWAVE=m +CONFIG_SCx200_GPIO=m +CONFIG_PC8736x_GPIO=m +CONFIG_NSC_GPIO=m +CONFIG_CS5535_GPIO=m +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +CONFIG_HPET=y +# CONFIG_HPET_RTC_IRQ is not set +CONFIG_HPET_MMAP=y +CONFIG_HANGCHECK_TIMER=m +CONFIG_TCG_TPM=m +CONFIG_TCG_TIS=m +CONFIG_TCG_NSC=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TELCLOCK=m +CONFIG_DEVPORT=y +CONFIG_I2C=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +CONFIG_I2C_SIMTEC=m +CONFIG_SCx200_I2C=m +CONFIG_SCx200_I2C_SCL=12 +CONFIG_SCx200_I2C_SDA=13 +CONFIG_SCx200_ACB=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m +CONFIG_I2C_PCA_ISA=m + +# +# Miscellaneous I2C Chip support +# +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_DS1682=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_TSL2550=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +CONFIG_SPI_LM70_LLP=m + +# +# SPI Protocol Masters +# +CONFIG_SPI_AT25=m +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_W1=m +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PDA_POWER=m +CONFIG_BATTERY_DS2760=m +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_HDAPS=m +CONFIG_SENSORS_APPLESMC=m +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_WAFER_WDT=m +CONFIG_I6300ESB_WDT=m +CONFIG_ITCO_WDT=m +CONFIG_ITCO_VENDOR_SUPPORT=y +CONFIG_IT8712F_WDT=m +CONFIG_SC1200_WDT=m +CONFIG_SCx200_WDT=m +CONFIG_PC87413_WDT=m +CONFIG_60XX_WDT=m +CONFIG_SBC8360_WDT=m +CONFIG_SBC7240_WDT=m +CONFIG_CPU5_WDT=m +CONFIG_SMSC37B787_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83697HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_MACHZ_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m + +# +# ISA-based Watchdog Cards +# +CONFIG_PCWATCHDOG=m +CONFIG_MIXCOMWD=m +CONFIG_WDT=m +CONFIG_WDT_501=y + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +# CONFIG_SSB_PCMCIAHOST is not set +# CONFIG_SSB_SILENT is not set +# CONFIG_SSB_DEBUG is not set +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_DRIVER_PCICORE=y + +# +# Multifunction device drivers +# +CONFIG_MFD_SM501=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders/decoders and other helper chips +# + +# +# Audio decoders +# +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_VP27SMPX=m + +# +# Video decoders +# +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_TCM825X=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7191=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_VPX3220=m + +# +# Video and audio decoders +# +CONFIG_VIDEO_CX25840=m + +# +# MPEG video encoders +# +CONFIG_VIDEO_CX2341X=m + +# +# Video encoders +# +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m + +# +# Video improvement chips +# +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_OSS=m +CONFIG_VIDEO_SAA7134_DVB=m +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_DPC is not set +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_29XXX=y +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_SYSFS=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_USB_VICAM=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_ET61X251=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_USB_W9968CF=m +# CONFIG_USB_OV511 is not set +CONFIG_USB_SE401=m +CONFIG_USB_SN9C102=m +CONFIG_USB_STV680=m +CONFIG_USB_ZC0301=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_ZR364XX=m +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +# CONFIG_RADIO_TYPHOON_PROC_FS is not set +CONFIG_RADIO_ZOLTRIX=m +CONFIG_USB_DSBR=m +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CAPTURE_DRIVERS=y + +# +# Supported SAA7146 based PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +# +# Supported USB Adapters +# +CONFIG_DVB_USB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 + +# +# Supported FlexCopII (B2C2) Adapters +# +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m + +# +# Supported Pluto2 Adapters +# +CONFIG_DVB_PLUTO2=m + +# +# Supported DVB Frontends +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_FE_CUSTOMISE is not set + +# +# DVB-S (satellite) frontends +# +CONFIG_DVB_STV0299=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_TDA10086=m + +# +# DVB-T (terrestrial) frontends +# +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_L64781=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_ZL10353=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m + +# +# DVB-C (cable) frontends +# +CONFIG_DVB_VES1820=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_STV0297=m + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +CONFIG_DVB_NXT200X=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_S5H1409=m + +# +# Tuners/PLL support +# +CONFIG_DVB_PLL=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +CONFIG_DVB_TUNER_QT1010=m +CONFIG_DVB_TUNER_MT2060=m +CONFIG_DVB_TUNER_MT2266=m +CONFIG_DVB_TUNER_MT2131=m +CONFIG_DVB_TUNER_DIB0070=m + +# +# Miscellaneous devices +# +CONFIG_DVB_LNBP21=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_TUA6100=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TUNER_SIMPLE=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_DAB=y +CONFIG_USB_DABUSB=m + +# +# Graphics support +# +CONFIG_AGP=m +CONFIG_AGP_ALI=m +CONFIG_AGP_ATI=m +CONFIG_AGP_AMD=m +CONFIG_AGP_AMD64=m +CONFIG_AGP_INTEL=m +CONFIG_AGP_NVIDIA=m +CONFIG_AGP_SIS=m +CONFIG_AGP_SWORKS=m +CONFIG_AGP_VIA=m +CONFIG_AGP_EFFICEON=m +CONFIG_DRM=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_I915=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m +CONFIG_DRM_VIA=m +CONFIG_DRM_SAVAGE=m +CONFIG_VGASTATE=m +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_DDC=m +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_IMAGEBLIT=m +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_SVGALIB=m +# CONFIG_FB_MACMODES is not set +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +CONFIG_FB_CIRRUS=m +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_CYBER2000=m +CONFIG_FB_ARC=m +CONFIG_FB_ASILIANT=y +CONFIG_FB_IMSTT=y +CONFIG_FB_VGA16=m +CONFIG_FB_UVESA=m +CONFIG_FB_VESA=m +CONFIG_FB_EFI=y +CONFIG_FB_IMAC=y +CONFIG_FB_HECUBA=m +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_S1D13XXX=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_I2C=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_BACKLIGHT=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_I2C=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_BACKLIGHT=y +CONFIG_FB_I810=m +# CONFIG_FB_I810_GTF is not set +CONFIG_FB_LE80578=m +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FB_CYBLA=m +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_ARK=m +CONFIG_FB_PM3=m +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_LX=m +CONFIG_FB_GEODE_GX=m +# CONFIG_FB_GEODE_GX_SET_FBSIZE is not set +CONFIG_FB_GEODE_GX1=m +CONFIG_FB_SM501=m +# CONFIG_FB_VIRTUAL is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_PROGEAR=m +CONFIG_BACKLIGHT_CARILLO_RANCH=m + +# +# Display device support +# +CONFIG_DISPLAY_SUPPORT=m + +# +# Display hardware drivers +# + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VIDEO_SELECT=y +CONFIG_MDA_CONSOLE=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=m +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_LOGO is not set + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL4_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_MPU401=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_AD1848_LIB=m +CONFIG_SND_CS4231_LIB=m +CONFIG_SND_SB_COMMON=m +CONFIG_SND_SB8_DSP=m +CONFIG_SND_SB16_DSP=m + +# +# ISA devices +# +CONFIG_SND_ADLIB=m +CONFIG_SND_AD1816A=m +CONFIG_SND_AD1848=m +CONFIG_SND_ALS100=m +CONFIG_SND_AZT2320=m +CONFIG_SND_CMI8330=m +CONFIG_SND_CS4231=m +CONFIG_SND_CS4232=m +CONFIG_SND_CS4236=m +CONFIG_SND_DT019X=m +CONFIG_SND_ES968=m +CONFIG_SND_ES1688=m +CONFIG_SND_ES18XX=m +CONFIG_SND_SC6000=m +CONFIG_SND_GUS_SYNTH=m +CONFIG_SND_GUSCLASSIC=m +CONFIG_SND_GUSEXTREME=m +CONFIG_SND_GUSMAX=m +CONFIG_SND_INTERWAVE=m +CONFIG_SND_INTERWAVE_STB=m +CONFIG_SND_OPL3SA2=m +CONFIG_SND_OPTI92X_AD1848=m +CONFIG_SND_OPTI92X_CS4231=m +CONFIG_SND_OPTI93X=m +CONFIG_SND_MIRO=m +CONFIG_SND_SB8=m +CONFIG_SND_SB16=m +CONFIG_SND_SBAWE=m +CONFIG_SND_SB16_CSP=y +CONFIG_SND_SB16_CSP_FIRMWARE_IN_KERNEL=y +CONFIG_SND_SGALAXY=m +CONFIG_SND_SSCAPE=m +CONFIG_SND_WAVEFRONT=m +CONFIG_SND_WAVEFRONT_FIRMWARE_IN_KERNEL=y + +# +# PCI devices +# +CONFIG_SND_AD1889=m +CONFIG_SND_ALS300=m +CONFIG_SND_ALS4000=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_BT87X_OVERCLOCK=y +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS5530=m +CONFIG_SND_CS5535AUDIO=m +CONFIG_SND_DARLA20=m +CONFIG_SND_GINA20=m +CONFIG_SND_LAYLA20=m +CONFIG_SND_DARLA24=m +CONFIG_SND_GINA24=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MONA=m +CONFIG_SND_MIA=m +CONFIG_SND_ECHO3G=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_CODEC_ANALOG=y +CONFIG_SND_HDA_CODEC_SIGMATEL=y +CONFIG_SND_HDA_CODEC_VIA=y +CONFIG_SND_HDA_CODEC_ATIHDMI=y +CONFIG_SND_HDA_CODEC_CONEXANT=y +CONFIG_SND_HDA_CODEC_CMEDIA=y +CONFIG_SND_HDA_CODEC_SI3054=y +CONFIG_SND_HDA_GENERIC=y +CONFIG_SND_HDA_POWER_SAVE=y +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_KORG1212_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MAESTRO3_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_PCXHR=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VX222=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 + +# +# SPI devices +# + +# +# USB devices +# +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_USX2Y=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y + +# +# PCMCIA devices +# +CONFIG_SND_VXPOCKET=m +CONFIG_SND_PDAUDIOCF=m + +# +# System on Chip audio support +# +CONFIG_SND_SOC=m + +# +# SoC Audio support for SuperH +# + +# +# Open Sound System +# +CONFIG_SOUND_PRIME=m +CONFIG_SOUND_TRIDENT=m +CONFIG_SOUND_MSNDCLAS=m +CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin" +CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin" +CONFIG_SOUND_MSNDPIN=m +CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin" +CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin" +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +CONFIG_SOUND_DMAP=y +CONFIG_SOUND_SSCAPE=m +CONFIG_SOUND_VMIDI=m +CONFIG_SOUND_TRIX=m +CONFIG_SOUND_MSS=m +CONFIG_SOUND_MPU401=m +CONFIG_SOUND_PAS=m +CONFIG_SOUND_PSS=m +CONFIG_PSS_MIXER=y +CONFIG_SOUND_SB=m +CONFIG_SOUND_YM3812=m +CONFIG_SOUND_UART6850=m +CONFIG_SOUND_AEDSP16=m +CONFIG_SC6600=y +CONFIG_SC6600_JOY=y +CONFIG_SC6600_CDROM=4 +CONFIG_SC6600_CDROMBASE=0 +CONFIG_AEDSP16_MSS=y +# CONFIG_AEDSP16_SBPRO is not set +CONFIG_SOUND_KAHLUA=m +CONFIG_AC97_BUS=m +CONFIG_HID_SUPPORT=y +CONFIG_HID=m +# CONFIG_HID_DEBUG is not set +CONFIG_HIDRAW=y + +# +# USB Input Devices +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT_POWERBOOK=y +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_PERSIST is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_ISP116X_HCD=m +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_HCD_SSB=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SL811_CS=m +CONFIG_USB_R8A66597_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_MON=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +# CONFIG_USB_SERIAL_IR is not set +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_LED=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_IOWARRIOR=m +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# +CONFIG_USB_ATM=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_CXACRU=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=m +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +CONFIG_USB_GADGET_NET2280=y +CONFIG_USB_NET2280=m +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_GADGETFS=m +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_G_SERIAL=m +# CONFIG_USB_MIDI_GADGET is not set + +# +# MMC/SD/SDIO support, can only select one arch from MMC and MSS +# +CONFIG_MMC=m +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_SDIO_UART=m + +# +# MMC/SD Host Controller Drivers +# +CONFIG_MMC_SDHCI=m +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_WBSD=m +CONFIG_MMC_TIFM_SD=m +# CONFIG_MSS is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=m + +# +# LED drivers +# +CONFIG_LEDS_NET48XX=m +CONFIG_LEDS_WRAP=m + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_MLX4_INFINIBAND=m +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_ISER=m +CONFIG_EDAC=y + +# +# Reporting subsystems +# +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_MM_EDAC=m +# CONFIG_EDAC_AMD76X is not set +CONFIG_EDAC_E7XXX=m +CONFIG_EDAC_E752X=m +CONFIG_EDAC_I82875P=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_I3000=m +CONFIG_EDAC_I82860=m +CONFIG_EDAC_R82600=m +CONFIG_EDAC_I5000=m +CONFIG_RTC_LIB=m +CONFIG_RTC_CLASS=m + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_DRV_TEST=m + +# +# I2C RTC drivers +# +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y + +# +# SPI RTC drivers +# +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_MAX6902=m + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_V3020=m + +# +# on-CPU RTC drivers +# +CONFIG_DMADEVICES=y + +# +# DMA Devices +# +CONFIG_INTEL_IOATDMA=m +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +CONFIG_NET_DMA=y +CONFIG_DCA=m +CONFIG_AUXDISPLAY=y +CONFIG_KS0108=m +CONFIG_KS0108_PORT=0x378 +CONFIG_KS0108_DELAY=2 +CONFIG_CFAG12864B=m +CONFIG_CFAG12864B_RATE=20 + +# +# Userspace I/O +# +CONFIG_UIO=m +CONFIG_UIO_CIF=m + +# +# Firmware Drivers +# +CONFIG_EDD=y +# CONFIG_EDD_OFF is not set +CONFIG_EFI_VARS=y +CONFIG_DELL_RBU=m +CONFIG_DCDBAS=m +CONFIG_DMIID=y + +# +# File systems +# +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=m +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_STATISTICS=y +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_NOLOCK=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_OCFS2_FS=m +CONFIG_OCFS2_DEBUG_MASKLOG=y +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_QUOTA_COMPAT=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_SIM_FS=m +CONFIG_VZ_QUOTA=m +# CONFIG_VZ_QUOTA_UNLOAD is not set +CONFIG_VZ_QUOTA_UGID=y +CONFIG_QUOTACTL=y +CONFIG_DNOTIFY=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=m +CONFIG_GENERIC_ACL=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_CONFIGFS_FS=m + +# +# Miscellaneous filesystems +# +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +CONFIG_CRAMFS=y +CONFIG_VXFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_UFS_DEBUG is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_XPRT_RDMA=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_EXPERIMENTAL is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +CONFIG_CODA_FS=m +# CONFIG_CODA_FS_OLD_API is not set +CONFIG_AFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_9P_FS=m +CONFIG_DEFAULT_RELATIME=y +CONFIG_DEFAULT_RELATIME_VAL=1 + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_CUMANA is not set +# CONFIG_ACORN_PARTITION_EESOX is not set +CONFIG_ACORN_PARTITION_ICS=y +# CONFIG_ACORN_PARTITION_ADFS is not set +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_ATARI_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +CONFIG_SGI_PARTITION=y +CONFIG_ULTRIX_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_SYSV68_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_INSTRUMENTATION=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=m +CONFIG_KPROBES=y +# CONFIG_MARKERS is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_PRINTK_TIME=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_SYSRQ_DEBUG=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_FORCED_INLINING is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_LKDTM is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SAMPLES is not set +CONFIG_NONPROMISC_DEVMEM=y +CONFIG_EARLY_PRINTK=y +# CONFIG_WRAPPER_PRINT is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set + +# +# Page alloc debug is incompatible with Software Suspend on i386 +# +# CONFIG_DEBUG_RODATA is not set +# CONFIG_4KSTACKS is not set +CONFIG_X86_FIND_SMP_CONFIG=y +CONFIG_X86_MPPARSE=y +CONFIG_DOUBLEFAULT=y +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +CONFIG_IO_DELAY_TYPE_NONE=3 +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_DEFAULT_IO_DELAY_TYPE=0 + +# +# Security options +# + +# +# Grsecurity +# +CONFIG_GRKERNSEC=y + +# +# Executable Protections +# +CONFIG_GRKERNSEC_TPE=y +CONFIG_GRKERNSEC_TPE_ALL=y +# CONFIG_GRKERNSEC_TPE_INVERT is not set +CONFIG_GRKERNSEC_TPE_GID=1005 + +# +# Sysctl support +# +CONFIG_GRKERNSEC_SYSCTL=y +# CONFIG_GRKERNSEC_SYSCTL_ON is not set + +# +# Logging Options +# +CONFIG_GRKERNSEC_FLOODTIME=10 +CONFIG_GRKERNSEC_FLOODBURST=4 +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_TWOFISH_586=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_AES_586=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_PADLOCK=y +CONFIG_CRYPTO_DEV_PADLOCK_AES=m +CONFIG_CRYPTO_DEV_PADLOCK_SHA=m +CONFIG_CRYPTO_DEV_GEODE=m +CONFIG_HAVE_KVM=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_INTEL=m +CONFIG_KVM_AMD=m +CONFIG_VIRTIO=m +CONFIG_VIRTIO_RING=m +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_BALLOON=m + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=m +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CHECK_SIGNATURE=y + +# +# User resources +# +CONFIG_BEANCOUNTERS=y +CONFIG_BC_RSS_ACCOUNTING=y +CONFIG_BC_IO_ACCOUNTING=y +CONFIG_BC_IO_SCHED=y +CONFIG_BC_SWAP_ACCOUNTING=y +CONFIG_BC_PROC=y +# CONFIG_BC_DEBUG is not set +CONFIG_DRM_VIA_CHROME9=m --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0143-MISC-autofs4-pidns-friendly-oz_mode.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0143-MISC-autofs4-pidns-friendly-oz_mode.patch @@ -0,0 +1,129 @@ +From f36b9627a92ded4bb0f7f2a13aeb086512614633 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 5 Sep 2008 11:36:55 +0400 +Subject: [PATCH] MISC autofs4 pidns friendly oz_mode + +Fix oz_mode detection to prevent autofs daemon hang inside container. + +Switch from pid_t to struct pid of process group. +The same changes as in mainstream commit fa0334f1 for autofs. + +http://bugzilla.openvz.org/show_bug.cgi?id=959 +--- + fs/autofs4/autofs_i.h | 4 ++-- + fs/autofs4/inode.c | 24 ++++++++++++++++++------ + 2 files changed, 20 insertions(+), 8 deletions(-) + +diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h +index 2d4ae40..ac6631f 100644 +--- a/fs/autofs4/autofs_i.h ++++ b/fs/autofs4/autofs_i.h +@@ -98,7 +98,7 @@ struct autofs_sb_info { + u32 magic; + int pipefd; + struct file *pipe; +- pid_t oz_pgrp; ++ struct pid *oz_pgrp; + int catatonic; + int version; + int sub_version; +@@ -131,7 +131,7 @@ static inline struct autofs_info *autofs4_dentry_ino(struct dentry *dentry) + filesystem without "magic".) */ + + static inline int autofs4_oz_mode(struct autofs_sb_info *sbi) { +- return sbi->catatonic || task_pgrp_nr(current) == sbi->oz_pgrp; ++ return sbi->catatonic || task_pgrp(current) == sbi->oz_pgrp; + } + + /* Does a dentry have some pending activity? */ +diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c +index 7f05d6c..246778b 100644 +--- a/fs/autofs4/inode.c ++++ b/fs/autofs4/inode.c +@@ -165,6 +165,8 @@ void autofs4_kill_sb(struct super_block *sb) + /* Clean up and release dangling references */ + autofs4_force_release(sbi); + ++ put_pid(sbi->oz_pgrp); ++ + sb->s_fs_info = NULL; + kfree(sbi); + +@@ -181,7 +183,7 @@ static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt) + return 0; + + seq_printf(m, ",fd=%d", sbi->pipefd); +- seq_printf(m, ",pgrp=%d", sbi->oz_pgrp); ++ seq_printf(m, ",pgrp=%d", pid_vnr(sbi->oz_pgrp)); + seq_printf(m, ",timeout=%lu", sbi->exp_timeout/HZ); + seq_printf(m, ",minproto=%d", sbi->min_proto); + seq_printf(m, ",maxproto=%d", sbi->max_proto); +@@ -226,7 +228,7 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, + + *uid = current->uid; + *gid = current->gid; +- *pgrp = task_pgrp_nr(current); ++ *pgrp = task_pgrp_vnr(current); + + *minproto = AUTOFS_MIN_PROTO_VERSION; + *maxproto = AUTOFS_MAX_PROTO_VERSION; +@@ -311,6 +313,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) + int pipefd; + struct autofs_sb_info *sbi; + struct autofs_info *ino; ++ pid_t pgrp; + + sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); + if (!sbi) +@@ -323,7 +326,6 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) + sbi->pipe = NULL; + sbi->catatonic = 1; + sbi->exp_timeout = 0; +- sbi->oz_pgrp = task_pgrp_nr(current); + sbi->sb = s; + sbi->version = 0; + sbi->sub_version = 0; +@@ -361,7 +363,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) + + /* Can this call block? */ + if (parse_options(data, &pipefd, &root_inode->i_uid, &root_inode->i_gid, +- &sbi->oz_pgrp, &sbi->type, &sbi->min_proto, ++ &pgrp, &sbi->type, &sbi->min_proto, + &sbi->max_proto)) { + printk("autofs: called with bogus options\n"); + goto fail_dput; +@@ -389,12 +391,20 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) + sbi->version = sbi->max_proto; + sbi->sub_version = AUTOFS_PROTO_SUBVERSION; + +- DPRINTK("pipe fd = %d, pgrp = %u", pipefd, sbi->oz_pgrp); ++ DPRINTK("pipe fd = %d, pgrp = %u", pipefd, pgrp); ++ ++ sbi->oz_pgrp = find_get_pid(pgrp); ++ ++ if (!sbi->oz_pgrp) { ++ printk("autofs: could not find process group %d\n", pgrp); ++ goto fail_dput; ++ } ++ + pipe = fget(pipefd); + + if (!pipe) { + printk("autofs: could not open pipe file descriptor\n"); +- goto fail_dput; ++ goto fail_put_pid; + } + if (!pipe->f_op || !pipe->f_op->write) + goto fail_fput; +@@ -415,6 +425,8 @@ fail_fput: + printk("autofs: pipe file descriptor does not contain proper ops\n"); + fput(pipe); + /* fall through */ ++fail_put_pid: ++ put_pid(sbi->oz_pgrp); + fail_dput: + dput(root); + goto fail_free; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0015-NETFILTER-fixup-net.netfilter-sysctl-data-for-VE0-t.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0015-NETFILTER-fixup-net.netfilter-sysctl-data-for-VE0-t.patch @@ -0,0 +1,57 @@ +From c3c7fb30af165743ac4c6418af3ec85324971bbe Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 7 Mar 2008 17:56:41 +0300 +Subject: [PATCH 15/48] NETFILTER: fixup net.netfilter sysctl data for VE0 too + +They were pointing to usual mainline variables, not VE0's +and, thus, e.g, net.netfilter.nf_conntrack_count was always +reporting 0. +--- + net/netfilter/nf_conntrack_standalone.c | 23 ++++++++++------------- + 1 files changed, 10 insertions(+), 13 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c +index fb5e4c9..1f33841 100644 +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -453,19 +453,15 @@ EXPORT_SYMBOL_GPL(nf_ct_log_invalid); + #if defined(CONFIG_SYSCTL) && defined(CONFIG_VE_IPTABLES) + static int nf_conntrack_init_ve_sysctl(struct ve_struct *ve) + { +- if (ve_is_super(ve)) { +- ve_nf_ct_net_table = nf_ct_net_table; +- ve_nf_ct_netfilter_table = nf_ct_netfilter_table; +- ve_nf_ct_sysctl_table = nf_ct_sysctl_table; +- ve_nf_ct_sysctl_header = register_sysctl_table(ve_nf_ct_net_table); +- if (!ve_nf_ct_sysctl_header) +- return -ENOMEM; +- return 0; +- } ++ ve_nf_ct_net_table = nf_ct_net_table; ++ ve_nf_ct_netfilter_table = nf_ct_netfilter_table; ++ ve_nf_ct_sysctl_table = nf_ct_sysctl_table; + +- ve_nf_ct_net_table = clone_sysctl_template(nf_ct_net_table); +- if (ve_nf_ct_net_table == NULL) +- goto out; ++ if (!ve_is_super(ve)) { ++ ve_nf_ct_net_table = clone_sysctl_template(nf_ct_net_table); ++ if (ve_nf_ct_net_table == NULL) ++ goto out; ++ } + + ve_nf_ct_netfilter_table = ve_nf_ct_net_table[0].child; + ve_nf_ct_netfilter_table[1].data = &ve_nf_conntrack_max; +@@ -483,7 +479,8 @@ static int nf_conntrack_init_ve_sysctl(struct ve_struct *ve) + return 0; + + out_unclone: +- free_sysctl_clone(ve_nf_ct_net_table); ++ if (!ve_is_super(ve)) ++ free_sysctl_clone(ve_nf_ct_net_table); + out: + return -ENOMEM; + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0131-VE-stats-percpustat.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0131-VE-stats-percpustat.patch @@ -0,0 +1,134 @@ +From 6f4e06fb71e31e07621390434472a1ce59d667ab Mon Sep 17 00:00:00 2001 +From: Denis Lunev +Date: Thu, 7 Aug 2008 20:54:20 +0400 +Subject: [PATCH 131/131] VE stats percpustat + +Decrease ve_struct size in case of huge NR_CPUS +kstat_lat_pcpu_struct contains array of NR_CPUS elements. +Replace it with alloc_percpu data which helps to keep ve_struct +relatively small and prevents allocation fails of huge order. + +Mostly relevant to IA64, where NR_CPUS=1024 + +Bug #97575 +--- + include/linux/vzstat.h | 8 ++++---- + kernel/sched.c | 7 +++++++ + kernel/ve/ve.c | 5 ++++- + kernel/ve/vecalls.c | 13 ++++++++++++- + 4 files changed, 27 insertions(+), 6 deletions(-) + +Index: kernel/include/linux/vzstat.h +=================================================================== +--- kernel.orig/include/linux/vzstat.h 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/include/linux/vzstat.h 2008-11-24 16:01:59.000000000 +0100 +@@ -36,7 +36,7 @@ + cycles_t avg[3]; + }; + struct kstat_lat_pcpu_struct { +- struct kstat_lat_pcpu_snap_struct cur[NR_CPUS]; ++ struct kstat_lat_pcpu_snap_struct *cur; + cycles_t max_snap; + struct kstat_lat_snap_struct last; + cycles_t avg[3]; +@@ -121,7 +121,7 @@ + { + struct kstat_lat_pcpu_snap_struct *cur; + +- cur = &p->cur[cpu]; ++ cur = per_cpu_ptr(p->cur, cpu); + write_seqcount_begin(&cur->lock); + cur->count++; + if (cur->maxlat < dur) +@@ -152,8 +152,8 @@ + cycles_t m; + + memset(&p->last, 0, sizeof(p->last)); +- for (cpu = 0; cpu < NR_CPUS; cpu++) { +- cur = &p->cur[cpu]; ++ for_each_online_cpu(cpu) { ++ cur = per_cpu_ptr(p->cur, cpu); + do { + i = read_seqcount_begin(&cur->lock); + memcpy(&snap, cur, sizeof(snap)); +Index: kernel/kernel/sched.c +=================================================================== +--- kernel.orig/kernel/sched.c 2008-11-24 15:57:08.000000000 +0100 ++++ kernel/kernel/sched.c 2008-11-24 16:01:59.000000000 +0100 +@@ -385,7 +385,12 @@ + #endif + } + ++#ifdef CONFIG_SMP ++static struct percpu_data kstat_lat_pcpu_stats; ++#endif ++static struct kstat_lat_pcpu_snap_struct kstat_lat_pcpu_stats_data[NR_CPUS]; + struct kernel_stat_glob kstat_glob; ++ + DEFINE_SPINLOCK(kstat_glb_lock); + EXPORT_SYMBOL(kstat_glob); + EXPORT_SYMBOL(kstat_glb_lock); +@@ -7167,6 +7172,8 @@ + int highest_cpu = 0; + int i, j; + ++ kstat_glob.sched_lat.cur = static_percpu_ptr(&kstat_lat_pcpu_stats, ++ kstat_lat_pcpu_stats_data); + for_each_possible_cpu(i) { + struct rt_prio_array *array; + struct rq *rq; +Index: kernel/kernel/ve/ve.c +=================================================================== +--- kernel.orig/kernel/ve/ve.c 2008-11-24 16:00:05.000000000 +0100 ++++ kernel/kernel/ve/ve.c 2008-11-24 16:01:59.000000000 +0100 +@@ -120,9 +120,10 @@ + #ifdef CONFIG_SMP + static struct { + void *ptrs[NR_CPUS]; +-} ve0_cpu_stats; ++} ve0_cpu_stats, ve0_lat_pcpu_stats; + #endif + static struct ve_cpu_stats ve0_cpu_stats_data[NR_CPUS]; ++static struct kstat_lat_pcpu_snap_struct ve0_lat_pcpu_stats_data[NR_CPUS]; + + LIST_HEAD(ve_list_head); + rwlock_t ve_list_lock = RW_LOCK_UNLOCKED; +@@ -147,6 +148,8 @@ + + ve->cpu_stats = static_percpu_ptr(&ve0_cpu_stats, + ve0_cpu_stats_data); ++ ve->sched_lat_ve.cur = static_percpu_ptr(&ve0_lat_pcpu_stats, ++ ve0_lat_pcpu_stats_data); + + list_add(&ve->ve_list, &ve_list_head); + } +Index: kernel/kernel/ve/vecalls.c +=================================================================== +--- kernel.orig/kernel/ve/vecalls.c 2008-11-24 16:01:56.000000000 +0100 ++++ kernel/kernel/ve/vecalls.c 2008-11-24 16:01:59.000000000 +0100 +@@ -1374,13 +1374,24 @@ + static inline int init_ve_cpustats(struct ve_struct *ve) + { + ve->cpu_stats = alloc_percpu(struct ve_cpu_stats); +- return ve->cpu_stats == NULL ? -ENOMEM : 0; ++ if (ve->cpu_stats == NULL) ++ return -ENOMEM; ++ ve->sched_lat_ve.cur = alloc_percpu(struct kstat_lat_pcpu_snap_struct); ++ if (ve->sched_lat_ve.cur == NULL) ++ goto fail; ++ return 0; ++ ++fail: ++ free_percpu(ve->cpu_stats); ++ return -ENOMEM; + } + + static inline void free_ve_cpustats(struct ve_struct *ve) + { + free_percpu(ve->cpu_stats); + ve->cpu_stats = NULL; ++ free_percpu(ve->sched_lat_ve.cur); ++ ve->sched_lat_ve.cur = NULL; + } + + static int alone_in_pgrp(struct task_struct *tsk) --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0069-Expand-VE0-cpu-stats.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0069-Expand-VE0-cpu-stats.patch @@ -0,0 +1,32 @@ +From f293cb5b21c98bc78af5e64b11dbfce603843b27 Mon Sep 17 00:00:00 2001 +From: Pavel Emelianov +Date: Tue, 22 Apr 2008 19:39:43 +0400 +Subject: [PATCH 68/72] Expand VE0 cpu stats + +Stable commit 28680bfb8269703def997e2269caf9bfe2de489c +shrank struct percpu_data from NR_CPUS pointers to just 1, +so space for VE0 cpu statistics (which is allocated very early) +was too small resulting in oops in +account_system_time()/update_ve_cpu_time(). +--- + kernel/ve/ve.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c +index 8a1e8c5..04da442 100644 +--- a/kernel/ve/ve.c ++++ b/kernel/ve/ve.c +@@ -118,7 +118,9 @@ struct ve_struct ve0 = { + EXPORT_SYMBOL(ve0); + + #ifdef CONFIG_SMP +-static struct percpu_data ve0_cpu_stats; ++static struct { ++ void *ptrs[NR_CPUS]; ++} ve0_cpu_stats; + #endif + static struct ve_cpu_stats ve0_cpu_stats_data[NR_CPUS]; + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0022-FAIRSCHED-add-proc-fairsched-proc-fairsched2.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0022-FAIRSCHED-add-proc-fairsched-proc-fairsched2.patch @@ -0,0 +1,347 @@ +From 9eecc52aaa10d1c156a6aee48993ca9f3a3cd166 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Wed, 12 Mar 2008 18:15:29 +0300 +Subject: [PATCH 22/48] FAIRSCHED: add /proc/fairsched , /proc/fairsched2 + +--- + kernel/vzfairsched.c | 327 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 327 insertions(+), 0 deletions(-) + +diff --git a/kernel/vzfairsched.c b/kernel/vzfairsched.c +index c2eae4d..12f4874 100644 +--- a/kernel/vzfairsched.c ++++ b/kernel/vzfairsched.c +@@ -328,3 +328,330 @@ asmlinkage int sys_fairsched_mvpr(pid_t pid, unsigned int nodeid) + return retval; + } + EXPORT_SYMBOL(sys_fairsched_mvpr); ++ ++#ifdef CONFIG_PROC_FS ++ ++/*********************************************************************/ ++/* ++ * proc interface ++ */ ++/*********************************************************************/ ++ ++struct fairsched_node_dump { ++#ifdef CONFIG_VE ++ envid_t veid; ++#endif ++ int id; ++ unsigned weight; ++ unsigned rate; ++ unsigned rate_limited : 1, ++ delayed : 1; ++ fschtag_t start_tag; ++ fschvalue_t value; ++ cycles_t delay; ++ int nr_ready; ++ int nr_runnable; ++ int nr_pcpu; ++ int nr_tasks, nr_runtasks; ++}; ++ ++struct fairsched_dump { ++ int len, compat; ++ struct fairsched_node_dump nodes[0]; ++}; ++ ++static struct fairsched_dump *fairsched_do_dump(int compat) ++{ ++ int nr_nodes; ++ int len, i; ++ struct fairsched_dump *dump; ++ struct fairsched_node *node; ++ struct fairsched_node_dump *p; ++ unsigned long flags; ++ ++start: ++ nr_nodes = (ve_is_super(get_exec_env()) ? fairsched_nr_nodes + 16 : 1); ++ len = sizeof(*dump) + nr_nodes * sizeof(dump->nodes[0]); ++ dump = ub_vmalloc(len); ++ if (dump == NULL) ++ goto out; ++ ++ spin_lock_irqsave(&fairsched_lock, flags); ++ if (ve_is_super(get_exec_env()) && nr_nodes < fairsched_nr_nodes) ++ goto repeat; ++ p = dump->nodes; ++ list_for_each_entry_reverse(node, &fairsched_node_head, nodelist) { ++ if ((char *)p - (char *)dump >= len) ++ break; ++ p->nr_tasks = 0; ++ p->nr_runtasks = 0; ++#ifdef CONFIG_VE ++ if (!ve_accessible(node->owner_env, get_exec_env())) ++ continue; ++ p->veid = node->owner_env->veid; ++ if (compat) { ++ p->nr_tasks = atomic_read(&node->owner_env->pcounter); ++ for_each_online_cpu(i) ++ p->nr_runtasks += ++ VE_CPU_STATS(node->owner_env, i) ++ ->nr_running; ++ if (p->nr_runtasks < 0) ++ p->nr_runtasks = 0; ++ } ++#endif ++ p->id = node->id; ++ p->weight = node->weight; ++ p->rate = node->rate; ++ p->rate_limited = node->rate_limited; ++ p->delayed = node->delayed; ++ p->start_tag = node->start_tag; ++ p->value = node->value; ++ p->delay = node->delay; ++ p->nr_ready = node->nr_ready; ++ p->nr_runnable = node->nr_runnable; ++ p->nr_pcpu = node->nr_pcpu; ++ p++; ++ } ++ dump->len = p - dump->nodes; ++ dump->compat = compat; ++ spin_unlock_irqrestore(&fairsched_lock, flags); ++ ++out: ++ return dump; ++ ++repeat: ++ spin_unlock_irqrestore(&fairsched_lock, flags); ++ vfree(dump); ++ goto start; ++} ++ ++#define FAIRSCHED_PROC_HEADLINES 2 ++ ++#define FAIRSHED_DEBUG " debug" ++ ++#if defined(CONFIG_VE) ++/* ++ * File format is dictated by compatibility reasons. ++ */ ++static int fairsched_seq_show(struct seq_file *m, void *v) ++{ ++ struct fairsched_dump *dump; ++ struct fairsched_node_dump *p; ++ unsigned vid, nid, pid, r; ++ ++ dump = m->private; ++ p = (struct fairsched_node_dump *)((unsigned long)v & ~3UL); ++ if (p - dump->nodes < FAIRSCHED_PROC_HEADLINES) { ++ if (p == dump->nodes) ++ seq_printf(m, "Version: 2.6 debug\n"); ++ else if (p == dump->nodes + 1) ++ seq_printf(m, ++ " veid " ++ " id " ++ " parent " ++ "weight " ++ " rate " ++ "tasks " ++ " run " ++ "cpus" ++ " " ++ "flg " ++ "ready " ++ " start_tag " ++ " value " ++ " delay" ++ "\n"); ++ } else { ++ p -= FAIRSCHED_PROC_HEADLINES; ++ vid = nid = pid = 0; ++ r = (unsigned long)v & 3; ++ if (p == dump->nodes) { ++ if (r == 2) ++ nid = p->id; ++ } else { ++ if (!r) ++ nid = p->id; ++ else if (r == 1) ++ vid = pid = p->id; ++ else ++ vid = p->id, nid = 1; ++ } ++ seq_printf(m, ++ "%10u " ++ "%10u %10u %6u %5u %5u %5u %4u" ++ " " ++ " %c%c %5u %20Lu %20Lu %20Lu" ++ "\n", ++ vid, ++ nid, ++ pid, ++ p->weight, ++ p->rate, ++ p->nr_tasks, ++ p->nr_runtasks, ++ p->nr_pcpu, ++ p->rate_limited ? 'L' : '.', ++ p->delayed ? 'D' : '.', ++ p->nr_ready, ++ (unsigned long long)p->start_tag.t, ++ (unsigned long long)p->value.v, ++ (unsigned long long)p->delay ++ ); ++ } ++ ++ return 0; ++} ++ ++static void *fairsched_seq_start(struct seq_file *m, loff_t *pos) ++{ ++ struct fairsched_dump *dump; ++ unsigned long l; ++ ++ dump = m->private; ++ if (*pos >= dump->len * 3 - 1 + FAIRSCHED_PROC_HEADLINES) ++ return NULL; ++ if (*pos < FAIRSCHED_PROC_HEADLINES) ++ return dump->nodes + *pos; ++ /* guess why... */ ++ l = (unsigned long)(dump->nodes + ++ ((unsigned long)*pos + FAIRSCHED_PROC_HEADLINES * 2 + 1) / 3); ++ l |= ((unsigned long)*pos + FAIRSCHED_PROC_HEADLINES * 2 + 1) % 3; ++ return (void *)l; ++} ++static void *fairsched_seq_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ ++*pos; ++ return fairsched_seq_start(m, pos); ++} ++#endif ++ ++static int fairsched2_seq_show(struct seq_file *m, void *v) ++{ ++ struct fairsched_dump *dump; ++ struct fairsched_node_dump *p; ++ ++ dump = m->private; ++ p = v; ++ if (p - dump->nodes < FAIRSCHED_PROC_HEADLINES) { ++ if (p == dump->nodes) ++ seq_printf(m, "Version: 2.7" FAIRSHED_DEBUG "\n"); ++ else if (p == dump->nodes + 1) ++ seq_printf(m, ++ " id " ++ "weight " ++ " rate " ++ " run " ++ "cpus" ++#ifdef FAIRSHED_DEBUG ++ " " ++ "flg " ++ "ready " ++ " start_tag " ++ " value " ++ " delay" ++#endif ++ "\n"); ++ } else { ++ p -= FAIRSCHED_PROC_HEADLINES; ++ seq_printf(m, ++ "%10u %6u %5u %5u %4u" ++#ifdef FAIRSHED_DEBUG ++ " " ++ " %c%c %5u %20Lu %20Lu %20Lu" ++#endif ++ "\n", ++ p->id, ++ p->weight, ++ p->rate, ++ p->nr_runnable, ++ p->nr_pcpu ++#ifdef FAIRSHED_DEBUG ++ , ++ p->rate_limited ? 'L' : '.', ++ p->delayed ? 'D' : '.', ++ p->nr_ready, ++ (unsigned long long)p->start_tag.t, ++ (unsigned long long)p->value.v, ++ (unsigned long long)p->delay ++#endif ++ ); ++ } ++ ++ return 0; ++} ++ ++static void *fairsched2_seq_start(struct seq_file *m, loff_t *pos) ++{ ++ struct fairsched_dump *dump; ++ ++ dump = m->private; ++ if (*pos >= dump->len + FAIRSCHED_PROC_HEADLINES) ++ return NULL; ++ return dump->nodes + *pos; ++} ++static void *fairsched2_seq_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ ++*pos; ++ return fairsched2_seq_start(m, pos); ++} ++static void fairsched2_seq_stop(struct seq_file *m, void *v) ++{ ++} ++ ++#ifdef CONFIG_VE ++static struct seq_operations fairsched_seq_op = { ++ .start = fairsched_seq_start, ++ .next = fairsched_seq_next, ++ .stop = fairsched2_seq_stop, ++ .show = fairsched_seq_show ++}; ++#endif ++static struct seq_operations fairsched2_seq_op = { ++ .start = fairsched2_seq_start, ++ .next = fairsched2_seq_next, ++ .stop = fairsched2_seq_stop, ++ .show = fairsched2_seq_show ++}; ++static int fairsched_seq_open(struct inode *inode, struct file *file) ++{ ++ int ret; ++ struct seq_file *m; ++ int compat; ++ ++#ifdef CONFIG_VE ++ compat = (file->f_dentry->d_name.len == sizeof("fairsched") - 1); ++ ret = seq_open(file, compat ? &fairsched_seq_op : &fairsched2_seq_op); ++#else ++ compat = 0; ++ ret = seq_open(file, &fairsched2_seq_op); ++#endif ++ if (ret) ++ return ret; ++ m = file->private_data; ++ m->private = fairsched_do_dump(compat); ++ if (m->private == NULL) { ++ seq_release(inode, file); ++ ret = -ENOMEM; ++ } ++ return ret; ++} ++static int fairsched_seq_release(struct inode *inode, struct file *file) ++{ ++ struct seq_file *m; ++ struct fairsched_dump *dump; ++ ++ m = file->private_data; ++ dump = m->private; ++ m->private = NULL; ++ vfree(dump); ++ seq_release(inode, file); ++ return 0; ++} ++static struct file_operations proc_fairsched_operations = { ++ .open = fairsched_seq_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = fairsched_seq_release ++}; ++ ++#endif /* CONFIG_PROC_FS */ +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0026-NETFILTER-fix-uber-memory-leaks-during-nf_conntrack.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0026-NETFILTER-fix-uber-memory-leaks-during-nf_conntrack.patch @@ -0,0 +1,42 @@ +From 0bfe93b674c2af97c3bd729ec127c473d22d0f4d Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 14 Mar 2008 14:40:00 +0300 +Subject: [PATCH 26/48] NETFILTER: fix uber memory leaks during nf_conntrack shutdown + +ve_nf_ct_protos array freeing was skipped during VE stop if it registered +L4 protocols. Also remove generic proto freeing from sysctl freeing code -- +it's definitely not right place. +--- + net/netfilter/nf_conntrack_core.c | 2 +- + net/netfilter/nf_conntrack_proto_generic.c | 2 -- + 2 files changed, 1 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 879dc9e..5271220 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1038,7 +1038,7 @@ skip_ct_cache: + ve_nf_ct_expect_hash = NULL; + atomic_set(&ve_nf_conntrack_count, 0); + ve_nf_conntrack_max = 0; +-// nf_conntrack_proto_fini(); ++ nf_conntrack_proto_fini(); + #ifdef CONFIG_VE_IPTABLES + ve_nf_conntrack_l4proto_generic = NULL; + kfree(ve->_nf_conntrack); +diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c +index 3d00786..9980d3d 100644 +--- a/net/netfilter/nf_conntrack_proto_generic.c ++++ b/net/netfilter/nf_conntrack_proto_generic.c +@@ -128,8 +128,6 @@ void nf_ct_proto_generic_sysctl_cleanup(void) + #endif + free_sysctl_clone(ve_nf_conntrack_l4proto_generic->ctl_table); + ve_nf_conntrack_l4proto_generic->ctl_table = NULL; +- kfree(ve_nf_conntrack_l4proto_generic); +- ve_nf_conntrack_l4proto_generic = NULL; + } + } + EXPORT_SYMBOL(nf_ct_proto_generic_sysctl_cleanup); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0032-NETFILTER-fix-freeing-of-ve_nf_conntrack_l4proto_ge.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0032-NETFILTER-fix-freeing-of-ve_nf_conntrack_l4proto_ge.patch @@ -0,0 +1,27 @@ +From f05b28d968d2de966189a05549c2b01ddedbc6e0 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 14 Mar 2008 19:43:07 +0300 +Subject: [PATCH 32/48] NETFILTER: fix freeing of ve_nf_conntrack_l4proto_generic + +Do it only only on VE stop, not on rmmod, because it's statically allocated +on case of VE0. +--- + net/netfilter/nf_conntrack_proto.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c +index bde6914..c994ecf 100644 +--- a/net/netfilter/nf_conntrack_proto.c ++++ b/net/netfilter/nf_conntrack_proto.c +@@ -362,6 +362,7 @@ void nf_conntrack_proto_fini(void) + ve_nf_ct_protos[i] = NULL; + } + #ifdef CONFIG_VE_IPTABLES +- kfree(ve_nf_conntrack_l4proto_generic); ++ if (!ve_is_super(get_exec_env())) ++ kfree(ve_nf_conntrack_l4proto_generic); + #endif + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0067-Fix-dcache-accounting-interaction-with-SLUB.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0067-Fix-dcache-accounting-interaction-with-SLUB.patch @@ -0,0 +1,88 @@ +From aa10c926328212bb916e1c8e925497881c648dd3 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Tue, 22 Apr 2008 14:47:50 +0400 +Subject: [PATCH 66/67] Fix dcache accounting interaction with SLUB + +SLUB passes allocations greater than PAGE_SIZE/2 directly to page +allocator, so in case of large names there is no cache associated with +them and no ->objuse counter. + +Account for PAGE_SIZE in such cases. + +http://bugzilla.openvz.org/show_bug.cgi?id=878 +--- + include/linux/slab.h | 1 + + kernel/bc/dcache.c | 2 +- + mm/slab.c | 5 +++++ + mm/slub.c | 14 ++++++++++++++ + 4 files changed, 21 insertions(+), 1 deletions(-) + +diff --git a/include/linux/slab.h b/include/linux/slab.h +index 6d1d2f4..8f34584 100644 +--- a/include/linux/slab.h ++++ b/include/linux/slab.h +@@ -83,6 +83,7 @@ int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr); + extern void show_slab_info(void); + int kmem_cache_objuse(struct kmem_cache *cachep); + int kmem_obj_objuse(void *obj); ++int kmem_dname_objuse(void *obj); + unsigned long ub_cache_growth(struct kmem_cache *cachep); + + #ifdef CONFIG_BEANCOUNTERS +diff --git a/kernel/bc/dcache.c b/kernel/bc/dcache.c +index a9114e8..2242d64 100644 +--- a/kernel/bc/dcache.c ++++ b/kernel/bc/dcache.c +@@ -163,7 +163,7 @@ static inline unsigned long d_charge_size(struct dentry *dentry) + /* dentry's d_name is already set to appropriate value (see d_alloc) */ + return kmem_cache_objuse(inode_cachep) + kmem_cache_objuse(dentry_cache) + + (dname_external(dentry) ? +- kmem_obj_objuse((void *)dentry->d_name.name) : 0); ++ kmem_dname_objuse((void *)dentry->d_name.name) : 0); + } + + /* +diff --git a/mm/slab.c b/mm/slab.c +index 4605df4..e4b09a2 100644 +--- a/mm/slab.c ++++ b/mm/slab.c +@@ -755,6 +755,11 @@ int kmem_obj_objuse(void *obj) + return virt_to_cache(obj)->objuse; + } + ++int kmem_dname_objuse(void *obj) ++{ ++ return virt_to_cache(obj)->objuse; ++} ++ + unsigned long ub_cache_growth(struct kmem_cache *cachep) + { + return (cachep->grown - cachep->reaped - cachep->shrunk) +diff --git a/mm/slub.c b/mm/slub.c +index 68cff78..ad0717a 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -362,6 +362,20 @@ int kmem_obj_objuse(void *obj) + + EXPORT_SYMBOL(kmem_obj_objuse); + ++int kmem_dname_objuse(void *obj) ++{ ++ struct kmem_cache *s; ++ ++ /* ++ * Allocations larger than PAGE_SIZE/2 go directly through ++ * __get_free_pages() and aren't associated with any cache. ++ */ ++ s = virt_to_head_page(obj)->slab; ++ if (!s) ++ return PAGE_SIZE; ++ return kmem_cache_objuse(s); ++} ++ + #define page_ubs(pg) (pg->bc.slub_ubs) + + struct user_beancounter **ub_slab_ptr(struct kmem_cache *s, void *obj) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0053-CPT-add-support-for-network-statistics.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0053-CPT-add-support-for-network-statistics.patch @@ -0,0 +1,369 @@ +From b343c030e374d9eb767d27df01e85dd17567f561 Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Wed, 26 Mar 2008 12:12:35 +0300 +Subject: [PATCH 52/67] CPT: add support for network statistics + +In current implementation network statistics are not dumped at all. +This patch allows to save/restore network statistics on all supported network +devices. + +Statistics is restored on current cpu. +--- + drivers/net/venet_core.c | 14 ------ + drivers/net/vzethdev.c | 6 --- + include/linux/cpt_image.h | 33 +++++++++++++++ + include/linux/venet.h | 14 ++++++ + include/linux/veth.h | 6 +++ + kernel/cpt/cpt_net.c | 49 ++++++++++++++++++++++ + kernel/cpt/rst_net.c | 99 +++++++++++++++++++++++++++++++++++++++----- + 7 files changed, 189 insertions(+), 32 deletions(-) + +diff --git a/drivers/net/venet_core.c b/drivers/net/venet_core.c +index 576a0b3..8355627 100644 +--- a/drivers/net/venet_core.c ++++ b/drivers/net/venet_core.c +@@ -53,20 +53,6 @@ struct list_head ip_entry_hash_table[VEIP_HASH_SZ]; + rwlock_t veip_hash_lock = RW_LOCK_UNLOCKED; + LIST_HEAD(veip_lh); + +-struct venet_stats { +- struct net_device_stats stats; +- struct net_device_stats *real_stats; +-}; +- +-static inline struct net_device_stats * +-venet_stats(struct net_device *dev, int cpu) +-{ +- struct venet_stats *stats; +- stats = (struct venet_stats*)dev->priv; +- return per_cpu_ptr(stats->real_stats, cpu); +-} +- +- + #define ip_entry_hash_function(ip) (ntohl(ip) & (VEIP_HASH_SZ - 1)) + + void ip_entry_hash(struct ip_entry_struct *entry, struct veip_struct *veip) +diff --git a/drivers/net/vzethdev.c b/drivers/net/vzethdev.c +index 5fe9fae..2c52593 100644 +--- a/drivers/net/vzethdev.c ++++ b/drivers/net/vzethdev.c +@@ -57,12 +57,6 @@ static LIST_HEAD(veth_hwaddr_list); + static DEFINE_RWLOCK(ve_hwaddr_lock); + static DECLARE_MUTEX(hwaddr_sem); + +-static inline struct net_device_stats * +-veth_stats(struct net_device *dev, int cpuid) +-{ +- return per_cpu_ptr(veth_from_netdev(dev)->real_stats, cpuid); +-} +- + struct net_device * veth_dev_start(char *dev_addr, char *name); + + struct veth_struct *hwaddr_entry_lookup(char *name) +diff --git a/include/linux/cpt_image.h b/include/linux/cpt_image.h +index 045bc1f..158980e 100644 +--- a/include/linux/cpt_image.h ++++ b/include/linux/cpt_image.h +@@ -98,6 +98,7 @@ enum _cpt_object_type + CPT_OBJ_NET_TUNTAP, + CPT_OBJ_NET_HWADDR, + CPT_OBJ_NET_VETH, ++ CPT_OBJ_NET_STATS, + }; + + #define CPT_ALIGN(n) (((n)+7)&~7) +@@ -1524,6 +1525,38 @@ struct cpt_hwaddr_image { + __u8 cpt_dev_addr[32]; + } __attribute__ ((aligned (8))); + ++struct cpt_netstats_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_rx_packets; ++ __u64 cpt_tx_packets; ++ __u64 cpt_rx_bytes; ++ __u64 cpt_tx_bytes; ++ __u64 cpt_rx_errors; ++ __u64 cpt_tx_errors; ++ __u64 cpt_rx_dropped; ++ __u64 cpt_tx_dropped; ++ __u64 cpt_multicast; ++ __u64 cpt_collisions; ++ __u64 cpt_rx_length_errors; ++ __u64 cpt_rx_over_errors; ++ __u64 cpt_rx_crc_errors; ++ __u64 cpt_rx_frame_errors; ++ __u64 cpt_rx_fifo_errors; ++ __u64 cpt_rx_missed_errors; ++ __u64 cpt_tx_aborted_errors; ++ __u64 cpt_tx_carrier_errors; ++ __u64 cpt_tx_fifo_errors; ++ __u64 cpt_tx_heartbeat_errors; ++ __u64 cpt_tx_window_errors; ++ __u64 cpt_rx_compressed; ++ __u64 cpt_tx_compressed; ++ __u64 pad[4]; ++} __attribute__ ((aligned (8))); ++ + struct cpt_ifaddr_image { + __u64 cpt_next; + __u32 cpt_object; +diff --git a/include/linux/venet.h b/include/linux/venet.h +index 3a6903a..14cf89e 100644 +--- a/include/linux/venet.h ++++ b/include/linux/venet.h +@@ -15,11 +15,17 @@ + #include + #include + #include ++#include + + #define VEIP_HASH_SZ 512 + + struct ve_struct; + struct venet_stat; ++struct venet_stats { ++ struct net_device_stats stats; ++ struct net_device_stats *real_stats; ++}; ++ + struct ip_entry_struct + { + struct ve_addr_struct addr; +@@ -39,6 +45,14 @@ struct veip_struct + envid_t veid; + }; + ++static inline struct net_device_stats * ++venet_stats(struct net_device *dev, int cpu) ++{ ++ struct venet_stats *stats; ++ stats = (struct venet_stats*)dev->priv; ++ return per_cpu_ptr(stats->real_stats, cpu); ++} ++ + /* veip_hash_lock should be taken for write by caller */ + void ip_entry_hash(struct ip_entry_struct *entry, struct veip_struct *veip); + /* veip_hash_lock should be taken for write by caller */ +diff --git a/include/linux/veth.h b/include/linux/veth.h +index 9d0273f..34cfe2b 100644 +--- a/include/linux/veth.h ++++ b/include/linux/veth.h +@@ -36,4 +36,10 @@ static inline struct net_device * veth_to_netdev(struct veth_struct *veth) + } + #endif + ++static inline struct net_device_stats * ++veth_stats(struct net_device *dev, int cpuid) ++{ ++ return per_cpu_ptr(veth_from_netdev(dev)->real_stats, cpuid); ++} ++ + #endif +diff --git a/kernel/cpt/cpt_net.c b/kernel/cpt/cpt_net.c +index 4fe5ca7..2926d24 100644 +--- a/kernel/cpt/cpt_net.c ++++ b/kernel/cpt/cpt_net.c +@@ -63,6 +63,53 @@ static void cpt_dump_veth(struct net_device *dev, struct cpt_context * ctx) + return; + } + ++static void cpt_dump_netstats(struct net_device *dev, struct cpt_context * ctx) ++{ ++ struct cpt_netstats_image *n; ++ struct net_device_stats *stats; ++ ++ if (!dev->get_stats) ++ return; ++ ++ n = cpt_get_buf(ctx); ++ stats = dev->get_stats(dev); ++ cpt_open_object(NULL, ctx); ++ ++ n->cpt_next = CPT_NULL; ++ n->cpt_object = CPT_OBJ_NET_STATS; ++ n->cpt_hdrlen = sizeof(*n); ++ n->cpt_content = CPT_CONTENT_VOID; ++ ++ n->cpt_rx_packets = stats->rx_packets; ++ n->cpt_tx_packets = stats->tx_packets; ++ n->cpt_rx_bytes = stats->rx_bytes; ++ n->cpt_tx_bytes = stats->tx_bytes; ++ n->cpt_rx_errors = stats->rx_errors; ++ n->cpt_tx_errors = stats->tx_errors; ++ n->cpt_rx_dropped = stats->rx_dropped; ++ n->cpt_tx_dropped = stats->tx_dropped; ++ n->cpt_multicast = stats->multicast; ++ n->cpt_collisions = stats->collisions; ++ n->cpt_rx_length_errors = stats->rx_length_errors; ++ n->cpt_rx_over_errors = stats->rx_over_errors; ++ n->cpt_rx_crc_errors = stats->rx_crc_errors; ++ n->cpt_rx_frame_errors = stats->rx_frame_errors; ++ n->cpt_rx_fifo_errors = stats->rx_fifo_errors; ++ n->cpt_rx_missed_errors = stats->rx_missed_errors; ++ n->cpt_tx_aborted_errors = stats->tx_aborted_errors; ++ n->cpt_tx_carrier_errors = stats->tx_carrier_errors; ++ n->cpt_tx_fifo_errors = stats->tx_fifo_errors; ++ n->cpt_tx_heartbeat_errors = stats->tx_heartbeat_errors; ++ n->cpt_tx_window_errors = stats->tx_window_errors; ++ n->cpt_rx_compressed = stats->rx_compressed; ++ n->cpt_tx_compressed = stats->tx_compressed; ++ ++ ctx->write(n, sizeof(*n), ctx); ++ cpt_close_object(ctx); ++ cpt_release_buf(ctx); ++ return; ++} ++ + static void cpt_dump_tuntap(struct net_device *dev, struct cpt_context * ctx) + { + #if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) +@@ -144,6 +191,8 @@ int cpt_dump_link(struct cpt_context * ctx) + ctx->write(&hw, sizeof(hw), ctx); + cpt_close_object(ctx); + ++ cpt_dump_netstats(dev, ctx); ++ + cpt_pop_object(&saved_obj, ctx); + + cpt_close_object(ctx); +diff --git a/kernel/cpt/rst_net.c b/kernel/cpt/rst_net.c +index df6b659..2cb47a4 100644 +--- a/kernel/cpt/rst_net.c ++++ b/kernel/cpt/rst_net.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + #include "cpt_obj.h" + #include "cpt_context.h" +@@ -402,6 +403,73 @@ static int rst_restore_veth(loff_t pos, struct net_device *dev, + return err; + } + ++static int rst_restore_netstats(loff_t pos, struct net_device *dev, ++ struct cpt_context * ctx) ++{ ++ struct cpt_netstats_image *n; ++ struct net_device_stats *stats = NULL; ++ struct net_device *lo = get_exec_env()->ve_ns->net_ns->loopback_dev; ++ int err; ++ ++ if (!dev->get_stats) ++ return 0; ++ ++ n = cpt_get_buf(ctx); ++ err = rst_get_object(CPT_OBJ_NET_STATS, pos, n, ctx); ++ if (err) ++ goto out; ++ BUG_ON(sizeof(struct cpt_netstats_image) != n->cpt_hdrlen); ++ preempt_disable(); ++ if (dev == lo) ++ stats = netdev_priv(lo); ++#if defined(CONFIG_VE_ETHDEV) || defined(CONFIG_VE_ETHDEV_MODULE) ++ else if (KSYMREF(veth_open) && dev->open == KSYMREF(veth_open)) ++ stats = veth_stats(dev, smp_processor_id()); ++#endif ++#if defined(CONFIG_VE_NETDEV) || defined(CONFIG_VE_NETDEV_MODULE) ++ else if (dev == get_exec_env()->_venet_dev) ++ stats = venet_stats(dev, smp_processor_id()); ++#endif ++#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) ++ if (dev->open == tun_net_open) ++ stats = &dev->stats; ++#endif ++ if (!stats) { ++ err = -ENODEV; ++ eprintk_ctx("Network device %s is not supported\n", dev->name); ++ goto out; ++ } ++ ++ stats->rx_packets = n->cpt_rx_packets; ++ stats->tx_packets = n->cpt_tx_packets; ++ stats->rx_bytes = n->cpt_rx_bytes; ++ stats->tx_bytes = n->cpt_tx_bytes; ++ stats->rx_errors = n->cpt_rx_errors; ++ stats->tx_errors = n->cpt_tx_errors; ++ stats->rx_dropped = n->cpt_rx_dropped; ++ stats->tx_dropped = n->cpt_tx_dropped; ++ stats->multicast = n->cpt_multicast; ++ stats->collisions = n->cpt_collisions; ++ stats->rx_length_errors = n->cpt_rx_length_errors; ++ stats->rx_over_errors = n->cpt_rx_over_errors; ++ stats->rx_crc_errors = n->cpt_rx_crc_errors; ++ stats->rx_frame_errors = n->cpt_rx_frame_errors; ++ stats->rx_fifo_errors = n->cpt_rx_fifo_errors; ++ stats->rx_missed_errors = n->cpt_rx_missed_errors; ++ stats->tx_aborted_errors = n->cpt_tx_aborted_errors; ++ stats->tx_carrier_errors = n->cpt_tx_carrier_errors; ++ stats->tx_fifo_errors = n->cpt_tx_fifo_errors; ++ stats->tx_heartbeat_errors = n->cpt_tx_heartbeat_errors; ++ stats->tx_window_errors = n->cpt_tx_window_errors; ++ stats->rx_compressed = n->cpt_rx_compressed; ++ stats->tx_compressed = n->cpt_tx_compressed; ++ ++out: ++ preempt_enable(); ++ cpt_release_buf(ctx); ++ return err; ++} ++ + int rst_restore_netdev(struct cpt_context *ctx) + { + struct net *net = get_exec_env()->ve_ns->net_ns; +@@ -486,9 +554,8 @@ int rst_restore_netdev(struct cpt_context *ctx) + if (err) + eprintk_ctx("dev_change_flags err: %d\n", err); + } +- if (pos < sec + di.cpt_next) { ++ while (pos < sec + di.cpt_next) { + struct cpt_object_hdr hdr; +- struct cpt_hwaddr_image hw; + err = ctx->pread(&hdr, sizeof(struct cpt_object_hdr), + ctx, pos); + if (err) +@@ -500,18 +567,26 @@ int rst_restore_netdev(struct cpt_context *ctx) + di.cpt_name, err); + goto out; + } +- pos += hdr.cpt_next; +- } +- /* Restore hardware address */ +- err = rst_get_object(CPT_OBJ_NET_HWADDR, pos, +- &hw, ctx); +- if (err) +- goto out; ++ } else if (hdr.cpt_object == CPT_OBJ_NET_HWADDR) { ++ /* Restore hardware address */ ++ struct cpt_hwaddr_image hw; ++ err = rst_get_object(CPT_OBJ_NET_HWADDR, ++ pos, &hw, ctx); ++ if (err) ++ goto out; + BUG_ON(sizeof(hw.cpt_dev_addr) != + sizeof(dev->dev_addr)); +- memcpy(dev->dev_addr, hw.cpt_dev_addr, +- sizeof(hw.cpt_dev_addr)); +- pos += hw.cpt_next; ++ memcpy(dev->dev_addr, hw.cpt_dev_addr, ++ sizeof(hw.cpt_dev_addr)); ++ } else if (hdr.cpt_object == CPT_OBJ_NET_STATS) { ++ err = rst_restore_netstats(pos, dev, ctx); ++ if (err) { ++ eprintk_ctx("rst stats %s: %d\n", ++ di.cpt_name, err); ++ goto out; ++ } ++ } ++ pos += hdr.cpt_next; + } + } else { + eprintk_ctx("unknown interface 2 %s\n", di.cpt_name); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0088-CPT-udp-sockets-restore.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0088-CPT-udp-sockets-restore.patch @@ -0,0 +1,47 @@ +From aa4f5ce52d18acda1bbe9a30855e044a529f2924 Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Mon, 30 Jun 2008 13:48:49 +0400 +Subject: [PATCH 088/103] CPT udp sockets restore + +Some applications (like ntpd) set on udp sockets sk_reuse to 1. So any other +applications can bind to the same port. During restore we must skip this +check and restore and bind all sockets. On IPv6 we must also force DAD +(Duplicate Address Detection) procedure to be sure that IFA_F_TENTATIVE flag +will be cleared on IPv6 address and socket can be binded to it. + +http://bugzilla.openvz.org/show_bug.cgi?id=784 +--- + net/ipv4/udp.c | 2 +- + net/ipv6/addrconf.c | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index 959ea53..84fd76d 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -206,7 +206,7 @@ gotit: + sk_for_each(sk2, node, head) + if (sk2->sk_hash == snum && + sk2 != sk && +- (!sk2->sk_reuse || !sk->sk_reuse) && ++ (sk->sk_reuse != 2 && (!sk2->sk_reuse || !sk->sk_reuse)) && + ve_accessible_strict(sk2->owner_env, ve) && + (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if + || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index 19ac1e8..85ec6c6 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -2637,7 +2637,8 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) + + if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || + !(ifp->flags&IFA_F_TENTATIVE) || +- ifp->flags & IFA_F_NODAD) { ++ ifp->flags & IFA_F_NODAD || ++ dev->owner_env->disable_net) { + ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); + spin_unlock_bh(&ifp->lock); + read_unlock_bh(&idev->lock); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0058-Add-per-VE-proc-net-tcp6.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0058-Add-per-VE-proc-net-tcp6.patch @@ -0,0 +1,116 @@ +From ae2649d1f4e2249b3854be0570ea5074aa1836cb Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Tue, 1 Apr 2008 18:19:20 +0400 +Subject: [PATCH 57/67] Add per-VE /proc/net/tcp6 + +Required for netstat. +http://bugzilla.openvz.org/show_bug.cgi?id=860 +--- + include/net/tcp.h | 4 ++-- + net/ipv4/tcp_ipv4.c | 12 ++++++------ + net/ipv6/tcp_ipv6.c | 19 +++++++++++++++++-- + 3 files changed, 25 insertions(+), 10 deletions(-) + +Index: kernel/include/net/tcp.h +=================================================================== +--- kernel.orig/include/net/tcp.h 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/include/net/tcp.h 2008-11-24 15:59:46.000000000 +0100 +@@ -1358,8 +1358,8 @@ + struct seq_operations seq_ops; + }; + +-extern int tcp_proc_register(struct tcp_seq_afinfo *afinfo); +-extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo); ++extern int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo); ++extern void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo); + + extern struct request_sock_ops tcp_request_sock_ops; + +Index: kernel/net/ipv4/tcp_ipv4.c +=================================================================== +--- kernel.orig/net/ipv4/tcp_ipv4.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/tcp_ipv4.c 2008-11-24 15:59:46.000000000 +0100 +@@ -2289,7 +2289,7 @@ + goto out; + } + +-int tcp_proc_register(struct tcp_seq_afinfo *afinfo) ++int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo) + { + int rc = 0; + struct proc_dir_entry *p; +@@ -2302,7 +2302,7 @@ + afinfo->seq_fops->llseek = seq_lseek; + afinfo->seq_fops->release = seq_release_private; + +- p = proc_net_fops_create(current->nsproxy->net_ns, afinfo->name, S_IRUGO, afinfo->seq_fops); ++ p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops); + if (p) + p->data = afinfo; + else +@@ -2310,12 +2310,12 @@ + return rc; + } + +-void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo) ++void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo) + { + if (!afinfo) + return; + +- proc_net_remove(current->nsproxy->net_ns, afinfo->name); ++ proc_net_remove(net, afinfo->name); + memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); + } + +@@ -2456,12 +2456,12 @@ + + static int tcp4_proc_net_init(struct net *net) + { +- return tcp_proc_register(&tcp4_seq_afinfo); ++ return tcp_proc_register(net, &tcp4_seq_afinfo); + } + + static void tcp4_proc_net_exit(struct net *net) + { +- tcp_proc_unregister(&tcp4_seq_afinfo); ++ tcp_proc_unregister(net, &tcp4_seq_afinfo); + } + + static struct pernet_operations tcp4_proc_net_ops = { +Index: kernel/net/ipv6/tcp_ipv6.c +=================================================================== +--- kernel.orig/net/ipv6/tcp_ipv6.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv6/tcp_ipv6.c 2008-11-24 15:59:46.000000000 +0100 +@@ -2107,14 +2107,29 @@ + .seq_fops = &tcp6_seq_fops, + }; + ++static int tcp6_proc_net_init(struct net *net) ++{ ++ return tcp_proc_register(net, &tcp6_seq_afinfo); ++} ++ ++static void tcp6_proc_net_exit(struct net *net) ++{ ++ tcp_proc_unregister(net, &tcp6_seq_afinfo); ++} ++ ++static struct pernet_operations tcp6_proc_net_ops = { ++ .init = tcp6_proc_net_init, ++ .exit = tcp6_proc_net_exit, ++}; ++ + int __init tcp6_proc_init(void) + { +- return tcp_proc_register(&tcp6_seq_afinfo); ++ return register_pernet_subsys(&tcp6_proc_net_ops); + } + + void tcp6_proc_exit(void) + { +- tcp_proc_unregister(&tcp6_seq_afinfo); ++ unregister_pernet_subsys(&tcp6_proc_net_ops); + } + #endif + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0074-Linux-2.6.24-ovz005.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0074-Linux-2.6.24-ovz005.patch @@ -0,0 +1,22 @@ +From 483a70883c85acf684ffbd8fa6a4c9bfade878f3 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Thu, 8 May 2008 13:04:01 +0400 +Subject: [PATCH 73/73] Linux 2.6.24-ovz005 + +--- + Makefile | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: kernel/Makefile +=================================================================== +--- kernel.orig/Makefile 2008-11-24 15:59:19.000000000 +0100 ++++ kernel/Makefile 2008-11-24 16:00:18.000000000 +0100 +@@ -3,7 +3,7 @@ + SUBLEVEL = 24 + EXTRAVERSION = .6 + NAME = Err Metey! A Heury Beelge-a Ret! +-VZVERSION = ovz004 ++VZVERSION = ovz005 + + # *DOCUMENTATION* + # To see a list of typical targets execute "make help" --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0001-2.6.24-ovz002.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0001-2.6.24-ovz002.patch @@ -0,0 +1,91581 @@ +Index: kernel/COPYING.SWsoft +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/COPYING.SWsoft 2008-11-24 15:47:45.000000000 +0100 +@@ -0,0 +1,350 @@ ++ ++Nothing in this license should be construed as a grant by SWsoft of any rights ++beyond the rights specified in the GNU General Public License, and nothing in ++this license should be construed as a waiver by SWsoft of its patent, copyright ++and/or trademark rights, beyond the waiver required by the GNU General Public ++License. This license is expressly inapplicable to any product that is not ++within the scope of the GNU General Public License ++ ++---------------------------------------- ++ ++ GNU GENERAL PUBLIC LICENSE ++ Version 2, June 1991 ++ ++ Copyright (C) 1989, 1991 Free Software Foundation, Inc. ++ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++ Preamble ++ ++ The licenses for most software are designed to take away your ++freedom to share and change it. By contrast, the GNU General Public ++License is intended to guarantee your freedom to share and change free ++software--to make sure the software is free for all its users. This ++General Public License applies to most of the Free Software ++Foundation's software and to any other program whose authors commit to ++using it. (Some other Free Software Foundation software is covered by ++the GNU Library General Public License instead.) You can apply it to ++your programs, too. ++ ++ When we speak of free software, we are referring to freedom, not ++price. Our General Public Licenses are designed to make sure that you ++have the freedom to distribute copies of free software (and charge for ++this service if you wish), that you receive source code or can get it ++if you want it, that you can change the software or use pieces of it ++in new free programs; and that you know you can do these things. ++ ++ To protect your rights, we need to make restrictions that forbid ++anyone to deny you these rights or to ask you to surrender the rights. ++These restrictions translate to certain responsibilities for you if you ++distribute copies of the software, or if you modify it. ++ ++ For example, if you distribute copies of such a program, whether ++gratis or for a fee, you must give the recipients all the rights that ++you have. You must make sure that they, too, receive or can get the ++source code. And you must show them these terms so they know their ++rights. ++ ++ We protect your rights with two steps: (1) copyright the software, and ++(2) offer you this license which gives you legal permission to copy, ++distribute and/or modify the software. ++ ++ Also, for each author's protection and ours, we want to make certain ++that everyone understands that there is no warranty for this free ++software. If the software is modified by someone else and passed on, we ++want its recipients to know that what they have is not the original, so ++that any problems introduced by others will not reflect on the original ++authors' reputations. ++ ++ Finally, any free program is threatened constantly by software ++patents. We wish to avoid the danger that redistributors of a free ++program will individually obtain patent licenses, in effect making the ++program proprietary. To prevent this, we have made it clear that any ++patent must be licensed for everyone's free use or not licensed at all. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. ++ ++ GNU GENERAL PUBLIC LICENSE ++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++ 0. This License applies to any program or other work which contains ++a notice placed by the copyright holder saying it may be distributed ++under the terms of this General Public License. The "Program", below, ++refers to any such program or work, and a "work based on the Program" ++means either the Program or any derivative work under copyright law: ++that is to say, a work containing the Program or a portion of it, ++either verbatim or with modifications and/or translated into another ++language. (Hereinafter, translation is included without limitation in ++the term "modification".) Each licensee is addressed as "you". ++ ++Activities other than copying, distribution and modification are not ++covered by this License; they are outside its scope. The act of ++running the Program is not restricted, and the output from the Program ++is covered only if its contents constitute a work based on the ++Program (independent of having been made by running the Program). ++Whether that is true depends on what the Program does. ++ ++ 1. You may copy and distribute verbatim copies of the Program's ++source code as you receive it, in any medium, provided that you ++conspicuously and appropriately publish on each copy an appropriate ++copyright notice and disclaimer of warranty; keep intact all the ++notices that refer to this License and to the absence of any warranty; ++and give any other recipients of the Program a copy of this License ++along with the Program. ++ ++You may charge a fee for the physical act of transferring a copy, and ++you may at your option offer warranty protection in exchange for a fee. ++ ++ 2. You may modify your copy or copies of the Program or any portion ++of it, thus forming a work based on the Program, and copy and ++distribute such modifications or work under the terms of Section 1 ++above, provided that you also meet all of these conditions: ++ ++ a) You must cause the modified files to carry prominent notices ++ stating that you changed the files and the date of any change. ++ ++ b) You must cause any work that you distribute or publish, that in ++ whole or in part contains or is derived from the Program or any ++ part thereof, to be licensed as a whole at no charge to all third ++ parties under the terms of this License. ++ ++ c) If the modified program normally reads commands interactively ++ when run, you must cause it, when started running for such ++ interactive use in the most ordinary way, to print or display an ++ announcement including an appropriate copyright notice and a ++ notice that there is no warranty (or else, saying that you provide ++ a warranty) and that users may redistribute the program under ++ these conditions, and telling the user how to view a copy of this ++ License. (Exception: if the Program itself is interactive but ++ does not normally print such an announcement, your work based on ++ the Program is not required to print an announcement.) ++ ++These requirements apply to the modified work as a whole. If ++identifiable sections of that work are not derived from the Program, ++and can be reasonably considered independent and separate works in ++themselves, then this License, and its terms, do not apply to those ++sections when you distribute them as separate works. But when you ++distribute the same sections as part of a whole which is a work based ++on the Program, the distribution of the whole must be on the terms of ++this License, whose permissions for other licensees extend to the ++entire whole, and thus to each and every part regardless of who wrote it. ++ ++Thus, it is not the intent of this section to claim rights or contest ++your rights to work written entirely by you; rather, the intent is to ++exercise the right to control the distribution of derivative or ++collective works based on the Program. ++ ++In addition, mere aggregation of another work not based on the Program ++with the Program (or with a work based on the Program) on a volume of ++a storage or distribution medium does not bring the other work under ++the scope of this License. ++ ++ 3. You may copy and distribute the Program (or a work based on it, ++under Section 2) in object code or executable form under the terms of ++Sections 1 and 2 above provided that you also do one of the following: ++ ++ a) Accompany it with the complete corresponding machine-readable ++ source code, which must be distributed under the terms of Sections ++ 1 and 2 above on a medium customarily used for software interchange; or, ++ ++ b) Accompany it with a written offer, valid for at least three ++ years, to give any third party, for a charge no more than your ++ cost of physically performing source distribution, a complete ++ machine-readable copy of the corresponding source code, to be ++ distributed under the terms of Sections 1 and 2 above on a medium ++ customarily used for software interchange; or, ++ ++ c) Accompany it with the information you received as to the offer ++ to distribute corresponding source code. (This alternative is ++ allowed only for noncommercial distribution and only if you ++ received the program in object code or executable form with such ++ an offer, in accord with Subsection b above.) ++ ++The source code for a work means the preferred form of the work for ++making modifications to it. For an executable work, complete source ++code means all the source code for all modules it contains, plus any ++associated interface definition files, plus the scripts used to ++control compilation and installation of the executable. However, as a ++special exception, the source code distributed need not include ++anything that is normally distributed (in either source or binary ++form) with the major components (compiler, kernel, and so on) of the ++operating system on which the executable runs, unless that component ++itself accompanies the executable. ++ ++If distribution of executable or object code is made by offering ++access to copy from a designated place, then offering equivalent ++access to copy the source code from the same place counts as ++distribution of the source code, even though third parties are not ++compelled to copy the source along with the object code. ++ ++ 4. You may not copy, modify, sublicense, or distribute the Program ++except as expressly provided under this License. Any attempt ++otherwise to copy, modify, sublicense or distribute the Program is ++void, and will automatically terminate your rights under this License. ++However, parties who have received copies, or rights, from you under ++this License will not have their licenses terminated so long as such ++parties remain in full compliance. ++ ++ 5. You are not required to accept this License, since you have not ++signed it. However, nothing else grants you permission to modify or ++distribute the Program or its derivative works. These actions are ++prohibited by law if you do not accept this License. Therefore, by ++modifying or distributing the Program (or any work based on the ++Program), you indicate your acceptance of this License to do so, and ++all its terms and conditions for copying, distributing or modifying ++the Program or works based on it. ++ ++ 6. Each time you redistribute the Program (or any work based on the ++Program), the recipient automatically receives a license from the ++original licensor to copy, distribute or modify the Program subject to ++these terms and conditions. You may not impose any further ++restrictions on the recipients' exercise of the rights granted herein. ++You are not responsible for enforcing compliance by third parties to ++this License. ++ ++ 7. If, as a consequence of a court judgment or allegation of patent ++infringement or for any other reason (not limited to patent issues), ++conditions are imposed on you (whether by court order, agreement or ++otherwise) that contradict the conditions of this License, they do not ++excuse you from the conditions of this License. If you cannot ++distribute so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you ++may not distribute the Program at all. For example, if a patent ++license would not permit royalty-free redistribution of the Program by ++all those who receive copies directly or indirectly through you, then ++the only way you could satisfy both it and this License would be to ++refrain entirely from distribution of the Program. ++ ++If any portion of this section is held invalid or unenforceable under ++any particular circumstance, the balance of the section is intended to ++apply and the section as a whole is intended to apply in other ++circumstances. ++ ++It is not the purpose of this section to induce you to infringe any ++patents or other property right claims or to contest validity of any ++such claims; this section has the sole purpose of protecting the ++integrity of the free software distribution system, which is ++implemented by public license practices. Many people have made ++generous contributions to the wide range of software distributed ++through that system in reliance on consistent application of that ++system; it is up to the author/donor to decide if he or she is willing ++to distribute software through any other system and a licensee cannot ++impose that choice. ++ ++This section is intended to make thoroughly clear what is believed to ++be a consequence of the rest of this License. ++ ++ 8. If the distribution and/or use of the Program is restricted in ++certain countries either by patents or by copyrighted interfaces, the ++original copyright holder who places the Program under this License ++may add an explicit geographical distribution limitation excluding ++those countries, so that distribution is permitted only in or among ++countries not thus excluded. In such case, this License incorporates ++the limitation as if written in the body of this License. ++ ++ 9. The Free Software Foundation may publish revised and/or new versions ++of the General Public License from time to time. Such new versions will ++be similar in spirit to the present version, but may differ in detail to ++address new problems or concerns. ++ ++Each version is given a distinguishing version number. If the Program ++specifies a version number of this License which applies to it and "any ++later version", you have the option of following the terms and conditions ++either of that version or of any later version published by the Free ++Software Foundation. If the Program does not specify a version number of ++this License, you may choose any version ever published by the Free Software ++Foundation. ++ ++ 10. If you wish to incorporate parts of the Program into other free ++programs whose distribution conditions are different, write to the author ++to ask for permission. For software which is copyrighted by the Free ++Software Foundation, write to the Free Software Foundation; we sometimes ++make exceptions for this. Our decision will be guided by the two goals ++of preserving the free status of all derivatives of our free software and ++of promoting the sharing and reuse of software generally. ++ ++ NO WARRANTY ++ ++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ++REPAIR OR CORRECTION. ++ ++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED ++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY ++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ++POSSIBILITY OF SUCH DAMAGES. ++ ++ END OF TERMS AND CONDITIONS ++ ++ How to Apply These Terms to Your New Programs ++ ++ If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it ++free software which everyone can redistribute and change under these terms. ++ ++ To do so, attach the following notices to the program. It is safest ++to attach them to the start of each source file to most effectively ++convey the exclusion of warranty; and each file should have at least ++the "copyright" line and a pointer to where the full notice is found. ++ ++ ++ Copyright (C) ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++If the program is interactive, make it output a short notice like this ++when it starts in an interactive mode: ++ ++ Gnomovision version 69, Copyright (C) year name of author ++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. ++ This is free software, and you are welcome to redistribute it ++ under certain conditions; type `show c' for details. ++ ++The hypothetical commands `show w' and `show c' should show the appropriate ++parts of the General Public License. Of course, the commands you use may ++be called something other than `show w' and `show c'; they could even be ++mouse-clicks or menu items--whatever suits your program. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the program, if ++necessary. Here is a sample; alter the names: ++ ++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program ++ `Gnomovision' (which makes passes at compilers) written by James Hacker. ++ ++ , 1 April 1989 ++ Ty Coon, President of Vice ++ ++This General Public License does not permit incorporating your program into ++proprietary programs. If your program is a subroutine library, you may ++consider it more useful to permit linking proprietary applications with the ++library. If this is what you want to do, use the GNU Library General ++Public License instead of this License. +Index: kernel/Makefile +=================================================================== +--- kernel.orig/Makefile 2008-11-24 14:18:14.000000000 +0100 ++++ kernel/Makefile 2008-11-24 15:47:45.000000000 +0100 +@@ -3,6 +3,7 @@ + SUBLEVEL = 24 + EXTRAVERSION = .6 + NAME = Err Metey! A Heury Beelge-a Ret! ++VZVERSION = ovz002 + + # *DOCUMENTATION* + # To see a list of typical targets execute "make help" +@@ -355,7 +356,7 @@ + KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) + KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) + +-export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION ++export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION VZVERSION + export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC + export CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE + export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS +@@ -613,7 +614,7 @@ + + + ifeq ($(KBUILD_EXTMOD),) +-core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ ++core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ grsecurity/ + + vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ + $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ +@@ -973,7 +974,8 @@ + echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2; \ + exit 1; \ + fi; \ +- (echo \#define UTS_RELEASE \"$(KERNELRELEASE)\";) ++ (echo \#define UTS_RELEASE \"$(KERNELRELEASE)\"; \ ++ echo \#define VZVERSION \"$(VZVERSION)\";) + endef + + define filechk_version.h +Index: kernel/arch/arm/kernel/smp.c +=================================================================== +--- kernel.orig/arch/arm/kernel/smp.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/arm/kernel/smp.c 2008-11-24 15:47:45.000000000 +0100 +@@ -201,7 +201,7 @@ + local_flush_tlb_all(); + + read_lock(&tasklist_lock); +- for_each_process(p) { ++ for_each_process_all(p) { + if (p->mm) + cpu_clear(cpu, p->mm->cpu_vm_mask); + } +Index: kernel/arch/ia64/Kconfig +=================================================================== +--- kernel.orig/arch/ia64/Kconfig 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/Kconfig 2008-11-24 15:47:45.000000000 +0100 +@@ -570,6 +570,7 @@ + + source "lib/Kconfig" + ++source "kernel/bc/Kconfig" + # + # Use the generic interrupt handling code in kernel/irq/: + # +@@ -596,6 +597,8 @@ + + source "arch/ia64/Kconfig.debug" + ++source "kernel/Kconfig.openvz" ++ + source "security/Kconfig" + + source "crypto/Kconfig" +Index: kernel/arch/ia64/ia32/binfmt_elf32.c +=================================================================== +--- kernel.orig/arch/ia64/ia32/binfmt_elf32.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/ia32/binfmt_elf32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -17,6 +17,8 @@ + #include + #include + ++#include ++ + #include "ia32priv.h" + #include "elfcore32.h" + +@@ -132,6 +134,12 @@ + up_write(¤t->mm->mmap_sem); + } + ++ if (ub_memory_charge(current->mm, PAGE_ALIGN(IA32_LDT_ENTRIES * ++ IA32_LDT_ENTRY_SIZE), ++ VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE, ++ NULL, UB_SOFT)) ++ goto skip; ++ + /* + * Install LDT as anonymous memory. This gives us all-zero segment descriptors + * until a task modifies them via modify_ldt(). +@@ -152,7 +160,12 @@ + } + } + up_write(¤t->mm->mmap_sem); +- } ++ } else ++ ub_memory_uncharge(current->mm, PAGE_ALIGN(IA32_LDT_ENTRIES * ++ IA32_LDT_ENTRY_SIZE), ++ VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE, NULL); ++ ++skip: + + ia64_psr(regs)->ac = 0; /* turn off alignment checking */ + regs->loadrs = 0; +Index: kernel/arch/ia64/kernel/asm-offsets.c +=================================================================== +--- kernel.orig/arch/ia64/kernel/asm-offsets.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/kernel/asm-offsets.c 2008-11-24 15:47:45.000000000 +0100 +@@ -46,11 +46,9 @@ + DEFINE(IA64_TASK_CLEAR_CHILD_TID_OFFSET,offsetof (struct task_struct, clear_child_tid)); + DEFINE(IA64_TASK_GROUP_LEADER_OFFSET, offsetof (struct task_struct, group_leader)); + DEFINE(IA64_TASK_PENDING_OFFSET,offsetof (struct task_struct, pending)); +- DEFINE(IA64_TASK_PID_OFFSET, offsetof (struct task_struct, pid)); + DEFINE(IA64_TASK_REAL_PARENT_OFFSET, offsetof (struct task_struct, real_parent)); + DEFINE(IA64_TASK_SIGHAND_OFFSET,offsetof (struct task_struct, sighand)); + DEFINE(IA64_TASK_SIGNAL_OFFSET,offsetof (struct task_struct, signal)); +- DEFINE(IA64_TASK_TGID_OFFSET, offsetof (struct task_struct, tgid)); + DEFINE(IA64_TASK_THREAD_KSP_OFFSET, offsetof (struct task_struct, thread.ksp)); + DEFINE(IA64_TASK_THREAD_ON_USTACK_OFFSET, offsetof (struct task_struct, thread.on_ustack)); + +Index: kernel/arch/ia64/kernel/entry.S +=================================================================== +--- kernel.orig/arch/ia64/kernel/entry.S 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/kernel/entry.S 2008-11-24 15:47:45.000000000 +0100 +@@ -504,6 +504,74 @@ + br.ret.sptk.many rp + END(clone) + ++GLOBAL_ENTRY(ia64_ret_from_resume) ++ PT_REGS_UNWIND_INFO(0) ++{ /* ++ * Some versions of gas generate bad unwind info if the first instruction of a ++ * procedure doesn't go into the first slot of a bundle. This is a workaround. ++ */ ++ nop.m 0 ++ nop.i 0 ++ /* ++ * We need to call schedule_tail() to complete the scheduling process. ++ * Called by ia64_switch_to() after do_fork()->copy_thread(). r8 contains the ++ * address of the previously executing task. ++ */ ++ br.call.sptk.many rp=ia64_invoke_schedule_tail ++} ++ br.call.sptk.many rp=ia64_invoke_resume ++ ;; ++ adds sp=256,sp ++ ;; ++ /* Return from interrupt, we are all right. */ ++(pNonSys) br ia64_leave_kernel ++ ;; ++ /* Tricky part follows. We must restore correct syscall ++ * register frame before doing normal syscall exit job. ++ * It would the most natural to keep sw->ar_pfs correct, ++ * then we would be here with correct register frame. ++ * Unfortunately, IA64 has a feature. Registers were in backstore ++ * after context switch, and the first br.ret does _NOT_ fetch ++ * output registers. ++ * It is quite natural: look, if caller has output regs in his ++ * frame, they should be consumed. If callee does not have (enough of) ++ * input/local registers (1 in this case), the situation is unusual. ++ * Practical evidence: they are filled with something random crap. ++ * The only case, when this is essential in mainstream kernel ++ * is sys_clone(). The result is that new process gets some kernel ++ * information in its register frame. Which is a security problem, btw. ++ * ++ * So, we set sw->ar_pfs to pretend the whole frame is of local ++ * regs. And we have to repartition the frame it manually, using ++ * information from pt->cr_ifs (the register is invalid in this ++ * case, but it holds correct pfm). ++ */ ++ adds r3=PT(CR_IFS)+16,sp ++ ;; ++ ld8 r2=[r3],-(PT(CR_IFS)-PT(R8)) ++ ;; ++ extr.u r2=r2,0,37 ++ mov r8=ar.ec ++ ;; ++ extr.u r8=r8,0,5 ++ ;; ++ shl r8=r8,52 ++ ;; ++ or r2=r2,r8 ++ ;; ++ mov ar.pfs=r2 ++ ;; ++ movl r2=ia64_leave_syscall ++ ;; ++ mov rp=r2 ++ /* Plus, we should fetch r8 and r10 from pt_regs. Something else? */ ++ ld8 r8=[r3],PT(R10)-PT(R8) ++ ;; ++ ld8 r10=[r3] ++ ;; ++ br.ret.sptk.many rp ++END(ia64_ret_from_resume) ++ + /* + * Invoke a system call, but do some tracing before and after the call. + * We MUST preserve the current register frame throughout this routine +@@ -1167,6 +1235,34 @@ + br.ret.sptk.many rp + END(ia64_invoke_schedule_tail) + ++GLOBAL_ENTRY(ia64_invoke_resume) ++ alloc loc1=ar.pfs,0,3,1,0 ++ mov loc0=rp ++ adds out0=16,sp ++ ;; ++ ld8 r8=[out0] ++ ;; ++ cmp.eq p6,p0=r8,r0 ++ ;; ++(p6) br.cond.sptk 1f ++ ;; ++ mov loc2=gp ++ ;; ++ ld8 r10=[r8],8 ++ ;; ++ ld8 gp=[r8] ++ ;; ++ mov b7=r10 ++ ;; ++ br.call.sptk.many rp=b7 ++ ;; ++ mov gp=loc2 ++1: ++ mov ar.pfs=loc1 ++ mov rp=loc0 ++ br.ret.sptk.many rp ++END(ia64_invoke_resume) ++ + /* + * Setup stack and call do_notify_resume_user(). Note that pSys and pNonSys need to + * be set up by the caller. We declare 8 input registers so the system call +@@ -1588,5 +1684,14 @@ + data8 sys_signalfd + data8 sys_timerfd + data8 sys_eventfd ++.rept 1505-1310 ++ data8 sys_ni_syscall ++.endr ++ data8 sys_getluid // 1505 ++ data8 sys_setluid ++ data8 sys_setublimit ++ data8 sys_ubstat ++ data8 sys_lchmod ++ data8 sys_lutime // 1510 + + .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls +Index: kernel/arch/ia64/kernel/fsys.S +=================================================================== +--- kernel.orig/arch/ia64/kernel/fsys.S 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/kernel/fsys.S 2008-11-24 15:47:45.000000000 +0100 +@@ -57,96 +57,6 @@ + FSYS_RETURN + END(fsys_ni_syscall) + +-ENTRY(fsys_getpid) +- .prologue +- .altrp b6 +- .body +- add r9=TI_FLAGS+IA64_TASK_SIZE,r16 +- ;; +- ld4 r9=[r9] +- add r8=IA64_TASK_TGID_OFFSET,r16 +- ;; +- and r9=TIF_ALLWORK_MASK,r9 +- ld4 r8=[r8] // r8 = current->tgid +- ;; +- cmp.ne p8,p0=0,r9 +-(p8) br.spnt.many fsys_fallback_syscall +- FSYS_RETURN +-END(fsys_getpid) +- +-ENTRY(fsys_getppid) +- .prologue +- .altrp b6 +- .body +- add r17=IA64_TASK_GROUP_LEADER_OFFSET,r16 +- ;; +- ld8 r17=[r17] // r17 = current->group_leader +- add r9=TI_FLAGS+IA64_TASK_SIZE,r16 +- ;; +- +- ld4 r9=[r9] +- add r17=IA64_TASK_REAL_PARENT_OFFSET,r17 // r17 = ¤t->group_leader->real_parent +- ;; +- and r9=TIF_ALLWORK_MASK,r9 +- +-1: ld8 r18=[r17] // r18 = current->group_leader->real_parent +- ;; +- cmp.ne p8,p0=0,r9 +- add r8=IA64_TASK_TGID_OFFSET,r18 // r8 = ¤t->group_leader->real_parent->tgid +- ;; +- +- /* +- * The .acq is needed to ensure that the read of tgid has returned its data before +- * we re-check "real_parent". +- */ +- ld4.acq r8=[r8] // r8 = current->group_leader->real_parent->tgid +-#ifdef CONFIG_SMP +- /* +- * Re-read current->group_leader->real_parent. +- */ +- ld8 r19=[r17] // r19 = current->group_leader->real_parent +-(p8) br.spnt.many fsys_fallback_syscall +- ;; +- cmp.ne p6,p0=r18,r19 // did real_parent change? +- mov r19=0 // i must not leak kernel bits... +-(p6) br.cond.spnt.few 1b // yes -> redo the read of tgid and the check +- ;; +- mov r17=0 // i must not leak kernel bits... +- mov r18=0 // i must not leak kernel bits... +-#else +- mov r17=0 // i must not leak kernel bits... +- mov r18=0 // i must not leak kernel bits... +- mov r19=0 // i must not leak kernel bits... +-#endif +- FSYS_RETURN +-END(fsys_getppid) +- +-ENTRY(fsys_set_tid_address) +- .prologue +- .altrp b6 +- .body +- add r9=TI_FLAGS+IA64_TASK_SIZE,r16 +- ;; +- ld4 r9=[r9] +- tnat.z p6,p7=r32 // check argument register for being NaT +- ;; +- and r9=TIF_ALLWORK_MASK,r9 +- add r8=IA64_TASK_PID_OFFSET,r16 +- add r18=IA64_TASK_CLEAR_CHILD_TID_OFFSET,r16 +- ;; +- ld4 r8=[r8] +- cmp.ne p8,p0=0,r9 +- mov r17=-1 +- ;; +-(p6) st8 [r18]=r32 +-(p7) st8 [r18]=r17 +-(p8) br.spnt.many fsys_fallback_syscall +- ;; +- mov r17=0 // i must not leak kernel bits... +- mov r18=0 // i must not leak kernel bits... +- FSYS_RETURN +-END(fsys_set_tid_address) +- + #if IA64_GTOD_LOCK_OFFSET !=0 + #error fsys_gettimeofday incompatible with changes to struct fsyscall_gtod_data_t + #endif +@@ -718,8 +628,8 @@ + data8 0 // chmod + data8 0 // chown + data8 0 // lseek // 1040 +- data8 fsys_getpid // getpid +- data8 fsys_getppid // getppid ++ data8 0 // getpid ++ data8 0 // getppid + data8 0 // mount + data8 0 // umount + data8 0 // setuid // 1045 +@@ -910,7 +820,7 @@ + data8 0 // futex // 1230 + data8 0 // sched_setaffinity + data8 0 // sched_getaffinity +- data8 fsys_set_tid_address // set_tid_address ++ data8 0 // set_tid_address + data8 0 // fadvise64_64 + data8 0 // tgkill // 1235 + data8 0 // exit_group +Index: kernel/arch/ia64/kernel/head.S +=================================================================== +--- kernel.orig/arch/ia64/kernel/head.S 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/kernel/head.S 2008-11-24 15:47:45.000000000 +0100 +@@ -1011,7 +1011,7 @@ + mov out1 = r11;; + br.call.sptk.many rp = kernel_thread_helper;; + mov out0 = r8 +- br.call.sptk.many rp = sys_exit;; ++ br.call.sptk.many rp = do_exit;; + 1: br.sptk.few 1b // not reached + END(start_kernel_thread) + +Index: kernel/arch/ia64/kernel/ia64_ksyms.c +=================================================================== +--- kernel.orig/arch/ia64/kernel/ia64_ksyms.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/kernel/ia64_ksyms.c 2008-11-24 15:47:45.000000000 +0100 +@@ -78,6 +78,8 @@ + EXPORT_SYMBOL(xor_ia64_5); + #endif + ++EXPORT_SYMBOL(empty_zero_page); ++ + #include + EXPORT_SYMBOL(ia64_pal_call_phys_stacked); + EXPORT_SYMBOL(ia64_pal_call_phys_static); +Index: kernel/arch/ia64/kernel/mca.c +=================================================================== +--- kernel.orig/arch/ia64/kernel/mca.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/kernel/mca.c 2008-11-24 15:47:45.000000000 +0100 +@@ -1551,10 +1551,10 @@ + } + printk("\n\n"); + if (read_trylock(&tasklist_lock)) { +- do_each_thread (g, t) { ++ do_each_thread_all (g, t) { + printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm); + show_stack(t, NULL); +- } while_each_thread (g, t); ++ } while_each_thread_all (g, t); + read_unlock(&tasklist_lock); + } + /* FIXME: This will not restore zapped printk locks. */ +Index: kernel/arch/ia64/kernel/perfmon.c +=================================================================== +--- kernel.orig/arch/ia64/kernel/perfmon.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/kernel/perfmon.c 2008-11-24 15:47:45.000000000 +0100 +@@ -4216,12 +4216,12 @@ + + read_lock(&tasklist_lock); + +- do_each_thread (g, t) { ++ do_each_thread_ve (g, t) { + if (t->thread.pfm_context == ctx) { + ret = 0; + break; + } +- } while_each_thread (g, t); ++ } while_each_thread_ve (g, t); + + read_unlock(&tasklist_lock); + +Index: kernel/arch/ia64/kernel/process.c +=================================================================== +--- kernel.orig/arch/ia64/kernel/process.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/kernel/process.c 2008-11-24 15:47:45.000000000 +0100 +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -369,6 +370,9 @@ + #endif + } + ++extern char ia64_ret_from_resume; ++EXPORT_SYMBOL(ia64_ret_from_resume); ++ + /* + * Copy the state of an ia-64 thread. + * +@@ -442,7 +446,6 @@ + child_ptregs->r12 = user_stack_base + user_stack_size - 16; + child_ptregs->ar_bspstore = user_stack_base; + child_ptregs->ar_rnat = 0; +- child_ptregs->loadrs = 0; + } + } else { + /* +@@ -684,16 +687,25 @@ + return error; + } + ++extern void start_kernel_thread (void); ++EXPORT_SYMBOL(start_kernel_thread); ++ + pid_t + kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) + { +- extern void start_kernel_thread (void); + unsigned long *helper_fptr = (unsigned long *) &start_kernel_thread; + struct { + struct switch_stack sw; + struct pt_regs pt; + } regs; + ++ /* Don't allow kernel_thread() inside VE */ ++ if (!ve_allow_kthreads && !ve_is_super(get_exec_env())) { ++ printk("kernel_thread call inside container\n"); ++ dump_stack(); ++ return -EPERM; ++ } ++ + memset(®s, 0, sizeof(regs)); + regs.pt.cr_iip = helper_fptr[0]; /* set entry point (IP) */ + regs.pt.r1 = helper_fptr[1]; /* set GP */ +Index: kernel/arch/ia64/kernel/ptrace.c +=================================================================== +--- kernel.orig/arch/ia64/kernel/ptrace.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/kernel/ptrace.c 2008-11-24 15:47:45.000000000 +0100 +@@ -7,6 +7,7 @@ + * Derived from the x86 and Alpha versions. + */ + #include ++#include + #include + #include + #include +@@ -100,6 +101,8 @@ + + # undef GET_BITS + } ++EXPORT_SYMBOL(ia64_get_scratch_nat_bits); ++EXPORT_SYMBOL(__ia64_save_fpu); + + /* + * Set the NaT bits for the scratch registers according to NAT and +@@ -456,6 +459,7 @@ + *val = ret; + return 0; + } ++EXPORT_SYMBOL(ia64_peek); + + long + ia64_poke (struct task_struct *child, struct switch_stack *child_stack, +@@ -520,6 +524,7 @@ + *cfmp = cfm; + return (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); + } ++EXPORT_SYMBOL(ia64_get_user_rbs_end); + + /* + * Synchronize (i.e, write) the RSE backing store living in kernel +@@ -757,20 +762,20 @@ + if (write_access) { + nat_bits = *data; + scratch_unat = ia64_put_scratch_nat_bits(pt, nat_bits); +- if (unw_set_ar(info, UNW_AR_UNAT, scratch_unat) < 0) { +- dprintk("ptrace: failed to set ar.unat\n"); +- return -1; +- } ++ if (info->pri_unat_loc) ++ *info->pri_unat_loc = scratch_unat; ++ else ++ info->sw->caller_unat = scratch_unat; + for (regnum = 4; regnum <= 7; ++regnum) { + unw_get_gr(info, regnum, &dummy, &nat); + unw_set_gr(info, regnum, dummy, + (nat_bits >> regnum) & 1); + } + } else { +- if (unw_get_ar(info, UNW_AR_UNAT, &scratch_unat) < 0) { +- dprintk("ptrace: failed to read ar.unat\n"); +- return -1; +- } ++ if (info->pri_unat_loc) ++ scratch_unat = *info->pri_unat_loc; ++ else ++ scratch_unat = info->sw->caller_unat; + nat_bits = ia64_get_scratch_nat_bits(pt, scratch_unat); + for (regnum = 4; regnum <= 7; ++regnum) { + unw_get_gr(info, regnum, &dummy, &nat); +Index: kernel/arch/ia64/kernel/signal.c +=================================================================== +--- kernel.orig/arch/ia64/kernel/signal.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/kernel/signal.c 2008-11-24 15:47:45.000000000 +0100 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -446,6 +447,12 @@ + if (!user_mode(&scr->pt)) + return; + ++ if (try_to_freeze() && !signal_pending(current)) { ++ if ((long) scr->pt.r10 != -1) ++ restart = 0; ++ goto no_signal; ++ } ++ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else +@@ -501,8 +508,10 @@ + if (IS_IA32_PROCESS(&scr->pt)) { + scr->pt.r8 = scr->pt.r1; + scr->pt.cr_iip -= 2; +- } else ++ } else { + ia64_decrement_ip(&scr->pt); ++ scr->pt.r10 = 0; ++ } + restart = 0; /* don't restart twice if handle_signal() fails... */ + } + } +@@ -523,6 +532,7 @@ + } + + /* Did we come from a system call? */ ++no_signal: + if (restart) { + /* Restart the system call - no handlers present */ + if (errno == ERESTARTNOHAND || errno == ERESTARTSYS || errno == ERESTARTNOINTR +@@ -542,6 +552,7 @@ + ia64_decrement_ip(&scr->pt); + if (errno == ERESTART_RESTARTBLOCK) + scr->pt.r15 = __NR_restart_syscall; ++ scr->pt.r10 = 0; + } + } + } +Index: kernel/arch/ia64/kernel/unaligned.c +=================================================================== +--- kernel.orig/arch/ia64/kernel/unaligned.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/kernel/unaligned.c 2008-11-24 15:47:45.000000000 +0100 +@@ -1289,7 +1289,7 @@ + { + static unsigned long count, last_time; + +- if (jiffies - last_time > 5*HZ) ++ if (jiffies - last_time > 60 * HZ) + count = 0; + if (count < 5) { + last_time = jiffies; +Index: kernel/arch/ia64/mm/contig.c +=================================================================== +--- kernel.orig/arch/ia64/mm/contig.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/mm/contig.c 2008-11-24 15:47:45.000000000 +0100 +@@ -94,6 +94,7 @@ + quicklist_total_size()); + printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages()); + } ++EXPORT_SYMBOL(show_mem); + + + /* physical address where the bootmem map is located */ +Index: kernel/arch/ia64/mm/discontig.c +=================================================================== +--- kernel.orig/arch/ia64/mm/discontig.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/mm/discontig.c 2008-11-24 15:47:45.000000000 +0100 +@@ -49,6 +49,7 @@ + static nodemask_t memory_less_mask __initdata; + + pg_data_t *pgdat_list[MAX_NUMNODES]; ++EXPORT_SYMBOL(pgdat_list); + + /* + * To prevent cache aliasing effects, align per-node structures so that they +@@ -567,6 +568,7 @@ + quicklist_total_size()); + printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages()); + } ++EXPORT_SYMBOL(show_mem); + + /** + * call_pernode_memory - use SRAT to call callback functions with node info +Index: kernel/arch/ia64/mm/fault.c +=================================================================== +--- kernel.orig/arch/ia64/mm/fault.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/mm/fault.c 2008-11-24 15:47:45.000000000 +0100 +@@ -148,7 +148,6 @@ + if ((vma->vm_flags & mask) != mask) + goto bad_area; + +- survive: + /* + * If for any reason at all we couldn't handle the fault, make + * sure we exit gracefully rather than endlessly redo the +@@ -274,13 +273,13 @@ + + out_of_memory: + up_read(&mm->mmap_sem); +- if (is_global_init(current)) { +- yield(); +- down_read(&mm->mmap_sem); +- goto survive; +- } +- printk(KERN_CRIT "VM: killing process %s\n", current->comm); +- if (user_mode(regs)) +- do_group_exit(SIGKILL); ++ if (user_mode(regs)) { ++ /* ++ * 0-order allocation always success if something really ++ * fatal not happen: beancounter overdraft or OOM. ++ */ ++ force_sig(SIGKILL, current); ++ return; ++ } + goto no_context; + } +Index: kernel/arch/ia64/mm/init.c +=================================================================== +--- kernel.orig/arch/ia64/mm/init.c 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/ia64/mm/init.c 2008-11-24 15:47:45.000000000 +0100 +@@ -37,6 +37,8 @@ + #include + #include + ++#include ++ + DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); + + extern void ia64_tlb_init (void); +@@ -117,6 +119,10 @@ + + ia64_set_rbs_bot(); + ++ if (ub_memory_charge(current->mm, PAGE_SIZE, VM_DATA_DEFAULT_FLAGS, ++ NULL, UB_SOFT)) ++ goto skip; ++ + /* + * If we're out of memory and kmem_cache_alloc() returns NULL, we simply ignore + * the problem. When the process attempts to write to the register backing store +@@ -133,11 +139,16 @@ + if (insert_vm_struct(current->mm, vma)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); ++ ub_memory_uncharge(current->mm, PAGE_SIZE, ++ VM_DATA_DEFAULT_FLAGS, NULL); + return; + } + up_write(¤t->mm->mmap_sem); +- } ++ } else ++ ub_memory_uncharge(current->mm, PAGE_SIZE, ++ VM_DATA_DEFAULT_FLAGS, NULL); + ++skip: + /* map NaT-page at address zero to speed up speculative dereferencing of NULL: */ + if (!(current->personality & MMAP_PAGE_ZERO)) { + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); +Index: kernel/arch/powerpc/Kconfig +=================================================================== +--- kernel.orig/arch/powerpc/Kconfig 2008-11-18 01:19:41.000000000 +0100 ++++ kernel/arch/powerpc/Kconfig 2008-11-24 15:47:45.000000000 +0100 +@@ -674,10 +674,14 @@ + + source "lib/Kconfig" + ++source "kernel/bc/Kconfig" ++ + source "kernel/Kconfig.instrumentation" + + source "arch/powerpc/Kconfig.debug" + ++source "kernel/Kconfig.openvz" ++ + source "security/Kconfig" + + config KEYS_COMPAT +Index: kernel/arch/powerpc/kernel/misc_32.S +=================================================================== +--- kernel.orig/arch/powerpc/kernel/misc_32.S 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/powerpc/kernel/misc_32.S 2008-11-24 15:47:45.000000000 +0100 +@@ -787,7 +787,7 @@ + * Create a kernel thread + * kernel_thread(fn, arg, flags) + */ +-_GLOBAL(kernel_thread) ++_GLOBAL(ppc_kernel_thread) + stwu r1,-16(r1) + stw r30,8(r1) + stw r31,12(r1) +Index: kernel/arch/powerpc/kernel/misc_64.S +=================================================================== +--- kernel.orig/arch/powerpc/kernel/misc_64.S 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/powerpc/kernel/misc_64.S 2008-11-24 15:47:45.000000000 +0100 +@@ -427,7 +427,7 @@ + * Create a kernel thread + * kernel_thread(fn, arg, flags) + */ +-_GLOBAL(kernel_thread) ++_GLOBAL(ppc_kernel_thread) + std r29,-24(r1) + std r30,-16(r1) + stdu r1,-STACK_FRAME_OVERHEAD(r1) +Index: kernel/arch/powerpc/kernel/process.c +=================================================================== +--- kernel.orig/arch/powerpc/kernel/process.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/powerpc/kernel/process.c 2008-11-24 15:47:45.000000000 +0100 +@@ -48,6 +48,8 @@ + #include + #endif + ++#include ++ + extern unsigned long _get_SP(void); + + #ifndef CONFIG_SMP +@@ -446,8 +448,9 @@ + + printk("NIP: "REG" LR: "REG" CTR: "REG"\n", + regs->nip, regs->link, regs->ctr); +- printk("REGS: %p TRAP: %04lx %s (%s)\n", +- regs, regs->trap, print_tainted(), init_utsname()->release); ++ printk("REGS: %p TRAP: %04lx %s (%s %s)\n", ++ regs, regs->trap, print_tainted(), init_utsname()->release, ++ VZVERSION); + printk("MSR: "REG" ", regs->msr); + printbits(regs->msr, msr_bits); + printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer); +@@ -1015,6 +1018,20 @@ + } + EXPORT_SYMBOL(dump_stack); + ++long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) ++{ ++ extern long ppc_kernel_thread(int (*fn)(void *), void *arg, ++ unsigned long flags); ++ ++ if (!ve_is_super(get_exec_env())) { ++ printk("kernel_thread call inside container\n"); ++ dump_stack(); ++ return -EPERM; ++ } ++ ++ return ppc_kernel_thread(fn, arg, flags); ++} ++ + #ifdef CONFIG_PPC64 + void ppc64_runlatch_on(void) + { +Index: kernel/arch/powerpc/kernel/systbl.S +=================================================================== +--- kernel.orig/arch/powerpc/kernel/systbl.S 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/powerpc/kernel/systbl.S 2008-11-24 15:47:45.000000000 +0100 +@@ -43,5 +43,9 @@ + .p2align 3 + #endif + ++#define SYS_SKIP(from, to) .rept to - from \ ++ SYSCALL(sys_ni_syscall) \ ++ .endr ++ + _GLOBAL(sys_call_table) + #include +Index: kernel/arch/powerpc/kernel/vdso.c +=================================================================== +--- kernel.orig/arch/powerpc/kernel/vdso.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/powerpc/kernel/vdso.c 2008-11-24 15:47:45.000000000 +0100 +@@ -184,7 +184,7 @@ + * vDSO and insert it into the mm struct tree + */ + int arch_setup_additional_pages(struct linux_binprm *bprm, +- int executable_stack) ++ int executable_stack, unsigned long map_adress) + { + struct mm_struct *mm = current->mm; + struct page **vdso_pagelist; +Index: kernel/arch/powerpc/mm/fault.c +=================================================================== +--- kernel.orig/arch/powerpc/mm/fault.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/powerpc/mm/fault.c 2008-11-24 15:47:45.000000000 +0100 +@@ -335,7 +335,6 @@ + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ +- survive: + ret = handle_mm_fault(mm, vma, address, is_write); + if (unlikely(ret & VM_FAULT_ERROR)) { + if (ret & VM_FAULT_OOM) +@@ -375,14 +374,12 @@ + */ + out_of_memory: + up_read(&mm->mmap_sem); +- if (is_global_init(current)) { +- yield(); +- down_read(&mm->mmap_sem); +- goto survive; +- } +- printk("VM: killing process %s\n", current->comm); + if (user_mode(regs)) +- do_group_exit(SIGKILL); ++ /* ++ * 0-order allocation always success if something really ++ * fatal not happen: beancounter overdraft or OOM. Den ++ */ ++ force_sig(SIGKILL, current); + return SIGKILL; + + do_sigbus: +Index: kernel/arch/powerpc/mm/init_64.c +=================================================================== +--- kernel.orig/arch/powerpc/mm/init_64.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/powerpc/mm/init_64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -171,7 +171,7 @@ + "for size: %08x...\n", name, i, size); + pgtable_cache[i] = kmem_cache_create(name, + size, size, +- SLAB_PANIC, ++ SLAB_PANIC|SLAB_UBC|SLAB_NO_CHARGE, + zero_ctor); + } + } +Index: kernel/arch/powerpc/mm/mem.c +=================================================================== +--- kernel.orig/arch/powerpc/mm/mem.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/powerpc/mm/mem.c 2008-11-24 15:47:45.000000000 +0100 +@@ -170,6 +170,7 @@ + printk("%ld pages shared\n", shared); + printk("%ld pages swap cached\n", cached); + } ++EXPORT_SYMBOL(show_mem); + + /* + * Initialize the bootmem system and give it all the memory we +Index: kernel/arch/powerpc/mm/pgtable_32.c +=================================================================== +--- kernel.orig/arch/powerpc/mm/pgtable_32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/powerpc/mm/pgtable_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -82,7 +82,8 @@ + { + pgd_t *ret; + +- ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGDIR_ORDER); ++ ret = (pgd_t *)__get_free_pages(GFP_KERNEL_UBC | __GFP_SOFT_UBC | ++ __GFP_ZERO, PGDIR_ORDER); + return ret; + } + +@@ -116,6 +117,7 @@ + #else + gfp_t flags = GFP_KERNEL | __GFP_REPEAT; + #endif ++ flags |= (__GFP_UBC | __GFP_SOFT_UBC); + + ptepage = alloc_pages(flags, 0); + if (ptepage) +Index: kernel/arch/powerpc/platforms/cell/spu_callbacks.c +=================================================================== +--- kernel.orig/arch/powerpc/platforms/cell/spu_callbacks.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/powerpc/platforms/cell/spu_callbacks.c 2008-11-24 15:47:45.000000000 +0100 +@@ -46,6 +46,8 @@ + #define PPC_SYS_SPU(func) ppc_##func, + #define SYSX_SPU(f, f3264, f32) f, + ++#define SYS_SKIP(from, to) [from ... to] = sys_ni_syscall, ++ + #include + }; + +Index: kernel/arch/ppc/Kconfig +=================================================================== +--- kernel.orig/arch/ppc/Kconfig 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/ppc/Kconfig 2008-11-24 15:47:45.000000000 +0100 +@@ -1321,6 +1321,10 @@ + + source "arch/ppc/Kconfig.debug" + ++source "kernel/Kconfig.openvz" ++ + source "security/Kconfig" + ++source "kernel/bc/Kconfig" ++ + source "crypto/Kconfig" +Index: kernel/arch/ppc/kernel/misc.S +=================================================================== +--- kernel.orig/arch/ppc/kernel/misc.S 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/ppc/kernel/misc.S 2008-11-24 15:47:45.000000000 +0100 +@@ -868,7 +868,7 @@ + * Create a kernel thread + * kernel_thread(fn, arg, flags) + */ +-_GLOBAL(kernel_thread) ++_GLOBAL(ppc_kernel_thread) + stwu r1,-16(r1) + stw r30,8(r1) + stw r31,12(r1) +Index: kernel/arch/ppc/mm/fault.c +=================================================================== +--- kernel.orig/arch/ppc/mm/fault.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/ppc/mm/fault.c 2008-11-24 15:47:45.000000000 +0100 +@@ -249,7 +249,6 @@ + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ +- survive: + fault = handle_mm_fault(mm, vma, address, is_write); + if (unlikely(fault & VM_FAULT_ERROR)) { + if (fault & VM_FAULT_OOM) +@@ -290,14 +289,12 @@ + */ + out_of_memory: + up_read(&mm->mmap_sem); +- if (is_global_init(current)) { +- yield(); +- down_read(&mm->mmap_sem); +- goto survive; +- } +- printk("VM: killing process %s\n", current->comm); + if (user_mode(regs)) +- do_group_exit(SIGKILL); ++ /* ++ * 0-order allocation always success if something really ++ * fatal not happen: beancounter overdraft or OOM. Den ++ */ ++ force_sig(SIGKILL, current); + return SIGKILL; + + do_sigbus: +Index: kernel/arch/ppc/mm/init.c +=================================================================== +--- kernel.orig/arch/ppc/mm/init.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/ppc/mm/init.c 2008-11-24 15:47:45.000000000 +0100 +@@ -131,6 +131,7 @@ + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); + } ++EXPORT_SYMBOL(show_mem); + + /* Free up now-unused memory */ + static void free_sec(unsigned long start, unsigned long end, const char *name) +Index: kernel/arch/ppc/mm/pgtable.c +=================================================================== +--- kernel.orig/arch/ppc/mm/pgtable.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/ppc/mm/pgtable.c 2008-11-24 15:47:45.000000000 +0100 +@@ -83,7 +83,8 @@ + { + pgd_t *ret; + +- ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGDIR_ORDER); ++ ret = (pgd_t *)__get_free_pages(GFP_KERNEL_UBC | __GFP_SOFT_UBC | ++ __GFP_ZERO, PGDIR_ORDER); + return ret; + } + +@@ -117,6 +118,7 @@ + #else + gfp_t flags = GFP_KERNEL | __GFP_REPEAT; + #endif ++ flags |= (__GFP_UBC | __GFP_SOFT_UBC); + + ptepage = alloc_pages(flags, 0); + if (ptepage) +Index: kernel/arch/s390/Kconfig +=================================================================== +--- kernel.orig/arch/s390/Kconfig 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/s390/Kconfig 2008-11-24 15:47:45.000000000 +0100 +@@ -533,8 +533,12 @@ + + source "arch/s390/Kconfig.debug" + ++source "kernel/Kconfig.openvz" ++ + source "security/Kconfig" + + source "crypto/Kconfig" + + source "lib/Kconfig" ++ ++source "kernel/bc/Kconfig" +Index: kernel/arch/s390/kernel/smp.c +=================================================================== +--- kernel.orig/arch/s390/kernel/smp.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/s390/kernel/smp.c 2008-11-24 15:47:45.000000000 +0100 +@@ -430,8 +430,19 @@ + */ + int __cpuinit start_secondary(void *cpuvoid) + { +- /* Setup the cpu */ +- cpu_init(); ++ /* Setup the cpu */ ++ cpu_init(); ++ ++#ifdef CONFIG_VE ++ /* TSC reset. kill whatever might rely on old values */ ++ VE_TASK_INFO(current)->wakeup_stamp = 0; ++ /* ++ * Cosmetic: sleep_time won't be changed afterwards for the idle ++ * thread; keep it 0 rather than -cycles. ++ */ ++ VE_TASK_INFO(idle)->sleep_time = 0; ++#endif ++ + preempt_disable(); + /* Enable TOD clock interrupts on the secondary cpu. */ + init_cpu_timer(); +@@ -677,6 +688,11 @@ + for_each_possible_cpu(cpu) + if (cpu != smp_processor_id()) + smp_create_idle(cpu); ++ ++#ifdef CONFIG_VE ++ /* TSC reset. kill whatever might rely on old values */ ++ VE_TASK_INFO(current)->wakeup_stamp = 0; ++#endif + } + + void __init smp_prepare_boot_cpu(void) +Index: kernel/arch/s390/mm/init.c +=================================================================== +--- kernel.orig/arch/s390/mm/init.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/s390/mm/init.c 2008-11-24 15:47:45.000000000 +0100 +@@ -77,6 +77,7 @@ + global_page_state(NR_SLAB_UNRECLAIMABLE)); + printk("%lu pages pagetables\n", global_page_state(NR_PAGETABLE)); + } ++EXPORT_SYMBOL(show_mem); + + static void __init setup_ro_region(void) + { +Index: kernel/arch/sh64/kernel/process.c +=================================================================== +--- kernel.orig/arch/sh64/kernel/process.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/sh64/kernel/process.c 2008-11-24 15:47:45.000000000 +0100 +@@ -663,7 +663,7 @@ + int len=0; + struct task_struct *p; + read_lock(&tasklist_lock); +- for_each_process(p) { ++ for_each_process_ve(p) { + int pid = p->pid; + struct mm_struct *mm; + if (!pid) continue; +Index: kernel/arch/sparc64/Kconfig +=================================================================== +--- kernel.orig/arch/sparc64/Kconfig 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/sparc64/Kconfig 2008-11-24 15:47:45.000000000 +0100 +@@ -175,6 +175,8 @@ + depends on SMP + default "64" + ++source "kernel/Kconfig.fairsched" ++ + source "drivers/cpufreq/Kconfig" + + config US3_FREQ +@@ -466,8 +468,12 @@ + + source "arch/sparc64/Kconfig.debug" + ++source "kernel/Kconfig.openvz" ++ + source "security/Kconfig" + + source "crypto/Kconfig" + + source "lib/Kconfig" ++ ++source "kernel/bc/Kconfig" +Index: kernel/arch/sparc64/kernel/process.c +=================================================================== +--- kernel.orig/arch/sparc64/kernel/process.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/sparc64/kernel/process.c 2008-11-24 15:47:45.000000000 +0100 +@@ -699,6 +699,13 @@ + { + long retval; + ++ /* Don't allow kernel_thread() inside VE */ ++ if (!ve_is_super(get_exec_env())) { ++ printk("kernel_thread call inside container\n"); ++ dump_stack(); ++ return -EPERM; ++ } ++ + /* If the parent runs before fn(arg) is called by the child, + * the input registers of this function can be clobbered. + * So we stash 'fn' and 'arg' into global registers which +Index: kernel/arch/sparc64/kernel/sparc64_ksyms.c +=================================================================== +--- kernel.orig/arch/sparc64/kernel/sparc64_ksyms.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/sparc64/kernel/sparc64_ksyms.c 2008-11-24 15:47:45.000000000 +0100 +@@ -310,6 +310,7 @@ + EXPORT_SYMBOL(copy_in_user_fixup); + EXPORT_SYMBOL(__strncpy_from_user); + EXPORT_SYMBOL(__clear_user); ++EXPORT_SYMBOL(mem_map_zero); + + /* Various address conversion macros use this. */ + EXPORT_SYMBOL(sparc64_valid_addr_bitmap); +Index: kernel/arch/sparc64/kernel/systbls.S +=================================================================== +--- kernel.orig/arch/sparc64/kernel/systbls.S 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/sparc64/kernel/systbls.S 2008-11-24 15:47:45.000000000 +0100 +@@ -82,6 +82,14 @@ + .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait + /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd, compat_sys_fallocate + ++ .rept 510-303 ++ .word sys_nis_syscall ++ .endr ++ .word sys_getluid /* 510 */ ++ .word sys_setluid ++ .word compat_sys_setublimit ++ .word compat_sys_ubstat ++ + #endif /* CONFIG_COMPAT */ + + /* Now the 64-bit native Linux syscall table. */ +@@ -154,6 +162,15 @@ + .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait + /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate + ++ .rept 510-303 ++ .word sys_nis_syscall ++ .endr ++ .word sys_getluid /* 510 */ ++ .word sys_setluid ++ .word sys_setublimit ++ .word sys_ubstat ++ ++ + #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ + defined(CONFIG_SOLARIS_EMUL_MODULE) + /* Now the 32-bit SunOS syscall table. */ +@@ -272,5 +289,8 @@ + .word sunos_nosys + /*310*/ .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys ++ .rept 520-315 ++ .word sunos_nosys ++ .endr + + #endif +Index: kernel/arch/sparc64/kernel/traps.c +=================================================================== +--- kernel.orig/arch/sparc64/kernel/traps.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/sparc64/kernel/traps.c 2008-11-24 15:47:45.000000000 +0100 +@@ -2229,6 +2229,10 @@ + " \\__U_/\n"); + + printk("%s(%d): %s [#%d]\n", current->comm, task_pid_nr(current), str, ++die_counter); ++ printk("VE:EXCVE %d:%d, CPU %d, VCPU %d:%d\n", ++ VEID(VE_TASK_INFO(current)->owner_env), VEID(get_exec_env()), ++ smp_processor_id(), ++ task_vsched_id(current), task_cpu(current)); + notify_die(DIE_OOPS, str, regs, 0, 255, SIGSEGV); + __asm__ __volatile__("flushw"); + __show_regs(regs); +Index: kernel/arch/sparc64/mm/init.c +=================================================================== +--- kernel.orig/arch/sparc64/mm/init.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/sparc64/mm/init.c 2008-11-24 15:47:45.000000000 +0100 +@@ -434,6 +434,7 @@ + printk(KERN_INFO "%lu pages pagetables\n", + global_page_state(NR_PAGETABLE)); + } ++EXPORT_SYMBOL(show_mem); + + void mmu_info(struct seq_file *m) + { +Index: kernel/arch/x86/Kconfig +=================================================================== +--- kernel.orig/arch/x86/Kconfig 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/Kconfig 2008-11-24 15:47:45.000000000 +0100 +@@ -537,6 +537,14 @@ + depends on X86_32 && X86_VISWS + default y + ++config NMI_WATCHDOG ++ bool "NMI Watchdog" ++ default y ++ help ++ If you say Y here the kernel will activate NMI watchdog by default ++ on boot. You can still activate NMI watchdog via nmi_watchdog ++ command line option even if you say N here. ++ + config X86_MCE + bool "Machine Check Exception" + depends on !X86_VOYAGER +@@ -1603,6 +1611,7 @@ + + endmenu + ++source "kernel/Kconfig.openvz" + + source "net/Kconfig" + +@@ -1623,3 +1632,5 @@ + source "arch/x86/kvm/Kconfig" + + source "lib/Kconfig" ++ ++source "kernel/bc/Kconfig" +Index: kernel/arch/x86/ia32/ia32_binfmt.c +=================================================================== +--- kernel.orig/arch/x86/ia32/ia32_binfmt.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/ia32/ia32_binfmt.c 2008-11-24 15:47:45.000000000 +0100 +@@ -47,7 +47,7 @@ + #define AT_SYSINFO 32 + #define AT_SYSINFO_EHDR 33 + +-int sysctl_vsyscall32 = 1; ++int sysctl_vsyscall32 = 0; + + #undef ARCH_DLINFO + #define ARCH_DLINFO do { \ +@@ -225,9 +225,7 @@ + + static void elf32_init(struct pt_regs *); + +-#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 +-#define arch_setup_additional_pages syscall32_setup_pages +-extern int syscall32_setup_pages(struct linux_binprm *, int exstack); ++extern int arch_setup_additional_pages(struct linux_binprm *, int exstack, unsigned long map_address); + + #include "../../../fs/binfmt_elf.c" + +Index: kernel/arch/x86/ia32/ia32entry.S +=================================================================== +--- kernel.orig/arch/x86/ia32/ia32entry.S 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/ia32/ia32entry.S 2008-11-24 15:47:45.000000000 +0100 +@@ -104,7 +104,8 @@ + pushfq + CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET rflags,0*/ +- movl $VSYSCALL32_SYSEXIT, %r10d ++ GET_THREAD_INFO(%r10) ++ movl threadinfo_sysenter_return(%r10), %r10d + CFI_REGISTER rip,r10 + pushq $__USER32_CS + CFI_ADJUST_CFA_OFFSET 8 +@@ -149,7 +150,7 @@ + popq %rcx /* User %esp */ + CFI_ADJUST_CFA_OFFSET -8 + CFI_REGISTER rsp,rcx +- movl $VSYSCALL32_SYSEXIT,%edx /* User %eip */ ++ movl threadinfo_sysenter_return(%r10),%edx /* User %eip */ + CFI_REGISTER rip,rdx + TRACE_IRQS_ON + swapgs +@@ -514,7 +515,7 @@ + .quad stub32_iopl /* 110 */ + .quad sys_vhangup + .quad quiet_ni_syscall /* old "idle" system call */ +- .quad sys32_vm86_warning /* vm86old */ ++ .quad quiet_ni_syscall /* vm86old */ + .quad compat_sys_wait4 + .quad sys_swapoff /* 115 */ + .quad compat_sys_sysinfo +@@ -567,7 +568,7 @@ + .quad sys_mremap + .quad sys_setresuid16 + .quad sys_getresuid16 /* 165 */ +- .quad sys32_vm86_warning /* vm86 */ ++ .quad quiet_ni_syscall /* vm86 */ + .quad quiet_ni_syscall /* query_module */ + .quad sys_poll + .quad compat_sys_nfsservctl +Index: kernel/arch/x86/ia32/sys_ia32.c +=================================================================== +--- kernel.orig/arch/x86/ia32/sys_ia32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/ia32/sys_ia32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -842,18 +842,6 @@ + advice); + } + +-long sys32_vm86_warning(void) +-{ +- struct task_struct *me = current; +- static char lastcomm[sizeof(me->comm)]; +- if (strncmp(lastcomm, me->comm, sizeof(lastcomm))) { +- compat_printk(KERN_INFO "%s: vm86 mode not supported on 64 bit kernel\n", +- me->comm); +- strncpy(lastcomm, me->comm, sizeof(lastcomm)); +- } +- return -ENOSYS; +-} +- + long sys32_lookup_dcookie(u32 addr_low, u32 addr_high, + char __user * buf, size_t len) + { +Index: kernel/arch/x86/ia32/syscall32.c +=================================================================== +--- kernel.orig/arch/x86/ia32/syscall32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/ia32/syscall32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -10,27 +10,54 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + ++#include ++ + extern unsigned char syscall32_syscall[], syscall32_syscall_end[]; + extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[]; + extern int sysctl_vsyscall32; + +-static struct page *syscall32_pages[1]; ++char *syscall32_page; ++EXPORT_SYMBOL_GPL(syscall32_page); ++struct page *syscall32_pages[1]; ++EXPORT_SYMBOL_GPL(syscall32_pages); + static int use_sysenter = -1; + + struct linux_binprm; + + /* Setup a VMA at program startup for the vsyscall page */ +-int syscall32_setup_pages(struct linux_binprm *bprm, int exstack) ++int syscall32_setup_pages(struct linux_binprm *bprm, int exstack, ++ unsigned long map_address) + { ++ int npages = (__VSYSCALL32_END - __VSYSCALL32_BASE) >> PAGE_SHIFT; + struct mm_struct *mm = current->mm; ++ unsigned long flags; ++ unsigned long addr = map_address ? : __VSYSCALL32_BASE; + int ret; + ++ if (sysctl_vsyscall32 == 0 && map_address == 0) ++ return 0; ++ ++ flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC | VM_MAYWRITE | ++ mm->def_flags; ++ ++ ret = -ENOMEM; ++ if (ub_memory_charge(mm, __VSYSCALL32_END - __VSYSCALL32_BASE, ++ flags, NULL, UB_SOFT)) ++ goto err_charge; ++ + down_write(&mm->mmap_sem); ++ addr = get_unmapped_area(NULL, addr, PAGE_SIZE * npages, 0, ++ MAP_PRIVATE | MAP_FIXED); ++ if (unlikely(addr & ~PAGE_MASK)) { ++ ret = addr; ++ goto err_ins; ++ } + /* + * MAYWRITE to allow gdb to COW and set breakpoints + * +@@ -40,18 +67,27 @@ + * what PC values meant. + */ + /* Could randomize here */ +- ret = install_special_mapping(mm, VSYSCALL32_BASE, PAGE_SIZE, ++ ret = install_special_mapping(mm, addr, PAGE_SIZE * npages, + VM_READ|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| + VM_ALWAYSDUMP, + syscall32_pages); ++ if (ret == 0) { ++ mm->context.vdso = (void *)addr; ++ current_thread_info()->sysenter_return = VSYSCALL32_SYSEXIT; ++ } + up_write(&mm->mmap_sem); ++ if (ret < 0) ++err_ins: ++ ub_memory_uncharge(mm, __VSYSCALL32_END - __VSYSCALL32_BASE, flags, NULL); ++err_charge: + return ret; + } ++EXPORT_SYMBOL_GPL(syscall32_setup_pages); + + static int __init init_syscall32(void) + { +- char *syscall32_page = (void *)get_zeroed_page(GFP_KERNEL); ++ syscall32_page = (void *)get_zeroed_page(GFP_KERNEL); + if (!syscall32_page) + panic("Cannot allocate syscall32 page"); + syscall32_pages[0] = virt_to_page(syscall32_page); +Index: kernel/arch/x86/ia32/vsyscall-sysenter.S +=================================================================== +--- kernel.orig/arch/x86/ia32/vsyscall-sysenter.S 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/ia32/vsyscall-sysenter.S 2008-11-24 15:47:45.000000000 +0100 +@@ -20,9 +20,9 @@ + .Lenter_kernel: + movl %esp,%ebp + sysenter +- .space 7,0x90 ++ .space 23,0x90 + jmp .Lenter_kernel +- /* 16: System call normal return point is here! */ ++ /* 32: System call normal return point is here! */ + pop %ebp + .Lpop_ebp: + pop %edx +Index: kernel/arch/x86/ia32/vsyscall.lds +=================================================================== +--- kernel.orig/arch/x86/ia32/vsyscall.lds 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/ia32/vsyscall.lds 2008-11-24 15:47:45.000000000 +0100 +@@ -4,11 +4,11 @@ + */ + + /* This must match . */ +-VSYSCALL_BASE = 0xffffe000; ++__VSYSCALL_BASE = 0xffffe000; + + SECTIONS + { +- . = VSYSCALL_BASE + SIZEOF_HEADERS; ++ . = __VSYSCALL_BASE + SIZEOF_HEADERS; + + .hash : { *(.hash) } :text + .gnu.hash : { *(.gnu.hash) } +@@ -22,18 +22,18 @@ + For the layouts to match, we need to skip more than enough + space for the dynamic symbol table et al. If this amount + is insufficient, ld -shared will barf. Just increase it here. */ +- . = VSYSCALL_BASE + 0x400; ++ . = __VSYSCALL_BASE + 0x400; + + .text.vsyscall : { *(.text.vsyscall) } :text =0x90909090 + + /* This is an 32bit object and we cannot easily get the offsets + into the 64bit kernel. Just hardcode them here. This assumes + that all the stubs don't need more than 0x100 bytes. */ +- . = VSYSCALL_BASE + 0x500; ++ . = __VSYSCALL_BASE + 0x500; + + .text.sigreturn : { *(.text.sigreturn) } :text =0x90909090 + +- . = VSYSCALL_BASE + 0x600; ++ . = __VSYSCALL_BASE + 0x600; + + .text.rtsigreturn : { *(.text.rtsigreturn) } :text =0x90909090 + +Index: kernel/arch/x86/kernel/asm-offsets_64.c +=================================================================== +--- kernel.orig/arch/x86/kernel/asm-offsets_64.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/asm-offsets_64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -47,6 +47,7 @@ + ENTRY(addr_limit); + ENTRY(preempt_count); + ENTRY(status); ++ ENTRY(sysenter_return); + BLANK(); + #undef ENTRY + #define ENTRY(entry) DEFINE(pda_ ## entry, offsetof(struct x8664_pda, entry)) +Index: kernel/arch/x86/kernel/cpu/mtrr/if.c +=================================================================== +--- kernel.orig/arch/x86/kernel/cpu/mtrr/if.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/cpu/mtrr/if.c 2008-11-24 15:47:45.000000000 +0100 +@@ -427,7 +427,7 @@ + return -ENODEV; + + proc_root_mtrr = +- create_proc_entry("mtrr", S_IWUSR | S_IRUGO, &proc_root); ++ create_proc_entry("mtrr", S_IWUSR | S_IRUGO, NULL); + if (proc_root_mtrr) { + proc_root_mtrr->owner = THIS_MODULE; + proc_root_mtrr->proc_fops = &mtrr_fops; +Index: kernel/arch/x86/kernel/entry_32.S +=================================================================== +--- kernel.orig/arch/x86/kernel/entry_32.S 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/entry_32.S 2008-11-24 15:47:45.000000000 +0100 +@@ -221,6 +221,7 @@ + GET_THREAD_INFO(%ebp) + popl %eax + CFI_ADJUST_CFA_OFFSET -4 ++ret_from_fork_tail: + pushl $0x0202 # Reset kernel eflags + CFI_ADJUST_CFA_OFFSET 4 + popfl +@@ -229,6 +230,25 @@ + CFI_ENDPROC + END(ret_from_fork) + ++ENTRY(i386_ret_from_resume) ++ CFI_STARTPROC ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ call schedule_tail ++ GET_THREAD_INFO(%ebp) ++ popl %eax ++ CFI_ADJUST_CFA_OFFSET -4 ++ movl (%esp),%eax ++ testl %eax,%eax ++ jz 1f ++ pushl %esp ++ call *%eax ++ addl $4,%esp ++1: ++ addl $256,%esp ++ jmp ret_from_fork_tail ++ CFI_ENDPROC ++ + /* + * Return to user mode is not as complex as all this looks, + * but we want the default path for a system call return to +Index: kernel/arch/x86/kernel/entry_64.S +=================================================================== +--- kernel.orig/arch/x86/kernel/entry_64.S 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/entry_64.S 2008-11-24 15:47:45.000000000 +0100 +@@ -160,7 +160,12 @@ + popf # reset kernel eflags + CFI_ADJUST_CFA_OFFSET -4 + call schedule_tail ++ret_from_fork_tail: + GET_THREAD_INFO(%rcx) ++ btr $TIF_RESUME,threadinfo_flags(%rcx) ++ jc x86_64_ret_from_resume ++ ++ret_from_fork_check: + testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx) + jnz rff_trace + rff_action: +@@ -176,6 +181,19 @@ + call syscall_trace_leave + GET_THREAD_INFO(%rcx) + jmp rff_action ++ ++x86_64_ret_from_resume: ++ movq (%rsp),%rax ++ testq %rax,%rax ++ jz 1f ++ movq %rsp,%rdi ++ call *%rax ++1: ++ addq $256,%rsp ++ cmpq $0,ORIG_RAX(%rsp) ++ jge ret_from_fork_tail ++ RESTORE_REST ++ jmp int_ret_from_sys_call + CFI_ENDPROC + END(ret_from_fork) + +@@ -283,7 +301,7 @@ + sysret_signal: + TRACE_IRQS_ON + sti +- testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx ++ testl $(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx + jz 1f + + /* Really a signal */ +@@ -377,7 +395,7 @@ + jmp int_restore_rest + + int_signal: +- testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx ++ testl $(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx + jz 1f + movq %rsp,%rdi # &ptregs -> arg1 + xorl %esi,%esi # oldset -> arg2 +@@ -603,7 +621,7 @@ + jmp retint_check + + retint_signal: +- testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx ++ testl $(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx + jz retint_swapgs + TRACE_IRQS_ON + sti +@@ -960,7 +978,7 @@ + xorl %r9d,%r9d + + # clone now +- call do_fork ++ call do_fork_kthread + movq %rax,RAX(%rsp) + xorl %edi,%edi + +Index: kernel/arch/x86/kernel/ldt_32.c +=================================================================== +--- kernel.orig/arch/x86/kernel/ldt_32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/ldt_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -17,6 +18,8 @@ + #include + #include + ++#include ++ + #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ + static void flush_ldt(void *null) + { +@@ -36,9 +39,9 @@ + oldsize = pc->size; + mincount = (mincount+511)&(~511); + if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE) +- newldt = vmalloc(mincount*LDT_ENTRY_SIZE); ++ newldt = ub_vmalloc(mincount*LDT_ENTRY_SIZE); + else +- newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL); ++ newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL_UBC); + + if (!newldt) + return -ENOMEM; +@@ -102,6 +105,7 @@ + } + return retval; + } ++EXPORT_SYMBOL_GPL(init_new_context); + + /* + * No need to lock the MM as we are the last user +Index: kernel/arch/x86/kernel/ldt_64.c +=================================================================== +--- kernel.orig/arch/x86/kernel/ldt_64.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/ldt_64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -20,6 +21,8 @@ + #include + #include + ++#include ++ + #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ + static void flush_ldt(void *null) + { +@@ -39,9 +42,9 @@ + oldsize = pc->size; + mincount = (mincount+511)&(~511); + if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE) +- newldt = vmalloc(mincount*LDT_ENTRY_SIZE); ++ newldt = ub_vmalloc(mincount*LDT_ENTRY_SIZE); + else +- newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL); ++ newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL_UBC); + + if (!newldt) + return -ENOMEM; +@@ -106,6 +109,7 @@ + } + return retval; + } ++EXPORT_SYMBOL_GPL(init_new_context); + + /* + * +Index: kernel/arch/x86/kernel/nmi_32.c +=================================================================== +--- kernel.orig/arch/x86/kernel/nmi_32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/nmi_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -318,6 +318,21 @@ + + extern void die_nmi(struct pt_regs *, const char *msg); + ++void smp_show_regs(struct pt_regs *regs, void *info) ++{ ++ static DEFINE_SPINLOCK(show_regs_lock); ++ ++ if (regs == NULL) ++ return; ++ ++ spin_lock(&show_regs_lock); ++ bust_spinlocks(1); ++ printk("----------- IPI show regs -----------"); ++ show_regs(regs); ++ bust_spinlocks(0); ++ spin_unlock(&show_regs_lock); ++} ++ + __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) + { + +Index: kernel/arch/x86/kernel/nmi_64.c +=================================================================== +--- kernel.orig/arch/x86/kernel/nmi_64.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/nmi_64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -41,7 +41,12 @@ + atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */ + int panic_on_timeout; + ++#ifdef CONFIG_NMI_WATCHDOG + unsigned int nmi_watchdog = NMI_DEFAULT; ++#else ++unsigned int nmi_watchdog = NMI_NONE; ++#endif ++ + static unsigned int nmi_hz = HZ; + + static DEFINE_PER_CPU(short, wd_enabled); +@@ -354,10 +359,10 @@ + if (!touched && __get_cpu_var(last_irq_sum) == sum) { + /* + * Ayiee, looks like this CPU is stuck ... +- * wait a few IRQs (5 seconds) before doing the oops ... ++ * wait a few IRQs (30 seconds) before doing the oops ... + */ + local_inc(&__get_cpu_var(alert_counter)); +- if (local_read(&__get_cpu_var(alert_counter)) == 5*nmi_hz) ++ if (local_read(&__get_cpu_var(alert_counter)) == 30*nmi_hz) + die_nmi("NMI Watchdog detected LOCKUP on CPU %d\n", regs, + panic_on_timeout); + } else { +@@ -385,15 +390,34 @@ + + static unsigned ignore_nmis; + ++static int dummy_nmi_callback(struct pt_regs * regs, int cpu) ++{ ++ return 0; ++} ++ ++static nmi_callback_t nmi_ipi_callback = dummy_nmi_callback; ++ + asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code) + { + nmi_enter(); + add_pda(__nmi_count,1); +- if (!ignore_nmis) ++ if (!ignore_nmis) { + default_do_nmi(regs); ++ nmi_ipi_callback(regs, smp_processor_id()); ++ } + nmi_exit(); + } + ++void set_nmi_ipi_callback(nmi_callback_t callback) ++{ ++ nmi_ipi_callback = callback; ++} ++ ++void unset_nmi_ipi_callback(void) ++{ ++ nmi_ipi_callback = dummy_nmi_callback; ++} ++ + int do_nmi_callback(struct pt_regs * regs, int cpu) + { + #ifdef CONFIG_SYSCTL +Index: kernel/arch/x86/kernel/process_32.c +=================================================================== +--- kernel.orig/arch/x86/kernel/process_32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/process_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -52,11 +53,15 @@ + #endif + + #include ++#include + + #include + #include + + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); ++EXPORT_SYMBOL(ret_from_fork); ++asmlinkage void i386_ret_from_resume(void) __asm__("i386_ret_from_resume"); ++EXPORT_SYMBOL_GPL(i386_ret_from_resume); + + static int hlt_counter; + +@@ -324,16 +329,17 @@ + } + + printk("\n"); +- printk("Pid: %d, comm: %s %s (%s %.*s)\n", ++ printk("Pid: %d, comm: %s %s (%s %.*s %s)\n", + task_pid_nr(current), current->comm, + print_tainted(), init_utsname()->release, + (int)strcspn(init_utsname()->version, " "), +- init_utsname()->version); ++ init_utsname()->version, VZVERSION); + + printk("EIP: %04x:[<%08lx>] EFLAGS: %08lx CPU: %d\n", + 0xffff & regs->xcs, regs->eip, regs->eflags, + smp_processor_id()); +- print_symbol("EIP is at %s\n", regs->eip); ++ if (decode_call_traces) ++ print_symbol("EIP is at %s\n", regs->eip); + + printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", + regs->eax, regs->ebx, regs->ecx, regs->edx); +@@ -370,6 +376,8 @@ + { + __show_registers(regs, 1); + show_trace(NULL, regs, ®s->esp); ++ if (!decode_call_traces) ++ printk(" EIP: [<%08lx>]\n",regs->eip); + } + + /* +@@ -378,6 +386,7 @@ + * the "args". + */ + extern void kernel_thread_helper(void); ++EXPORT_SYMBOL_GPL(kernel_thread_helper); + + /* + * Create a kernel thread +@@ -386,6 +395,13 @@ + { + struct pt_regs regs; + ++ /* Don't allow kernel_thread() inside VE */ ++ if (!ve_allow_kthreads && !ve_is_super(get_exec_env())) { ++ printk("kernel_thread call inside container\n"); ++ dump_stack(); ++ return -EPERM; ++ } ++ + memset(®s, 0, sizeof(regs)); + + regs.ebx = (unsigned long) fn; +Index: kernel/arch/x86/kernel/process_64.c +=================================================================== +--- kernel.orig/arch/x86/kernel/process_64.c 2008-11-24 14:14:44.000000000 +0100 ++++ kernel/arch/x86/kernel/process_64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -26,12 +26,14 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -52,8 +54,6 @@ + #include + #include + +-asmlinkage extern void ret_from_fork(void); +- + unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED; + + unsigned long boot_option_idle_override = 0; +@@ -324,13 +324,14 @@ + + printk("\n"); + print_modules(); +- printk("Pid: %d, comm: %.20s %s %s %.*s\n", ++ printk("Pid: %d, comm: %.20s %s %s %.*s %s\n", + current->pid, current->comm, print_tainted(), + init_utsname()->release, + (int)strcspn(init_utsname()->version, " "), +- init_utsname()->version); ++ init_utsname()->version, VZVERSION); + printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip); +- printk_address(regs->rip); ++ if (decode_call_traces) ++ printk_address(regs->rip); + printk("RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp, + regs->eflags); + printk("RAX: %016lx RBX: %016lx RCX: %016lx\n", +@@ -378,7 +379,22 @@ + { + printk("CPU %d:", smp_processor_id()); + __show_regs(regs); +- show_trace(NULL, regs, (void *)(regs + 1)); ++ show_trace(NULL, regs, ®s->rsp); ++} ++ ++void smp_show_regs(struct pt_regs *regs, void *data) ++{ ++ static DEFINE_SPINLOCK(show_regs_lock); ++ ++ if (regs == NULL) ++ return; ++ ++ spin_lock(&show_regs_lock); ++ bust_spinlocks(1); ++ printk("----------- IPI show regs -----------\n"); ++ show_regs(regs); ++ bust_spinlocks(0); ++ spin_unlock(&show_regs_lock); + } + + /* +@@ -913,3 +929,20 @@ + sp -= get_random_int() % 8192; + return sp & ~0xf; + } ++ ++long do_fork_kthread(unsigned long clone_flags, ++ unsigned long stack_start, ++ struct pt_regs *regs, ++ unsigned long stack_size, ++ int __user *parent_tidptr, ++ int __user *child_tidptr) ++{ ++ if (ve_allow_kthreads || ve_is_super(get_exec_env())) ++ return do_fork(clone_flags, stack_start, regs, stack_size, ++ parent_tidptr, child_tidptr); ++ ++ /* Don't allow kernel_thread() inside VE */ ++ printk("kernel_thread call inside container\n"); ++ dump_stack(); ++ return -EPERM; ++} +Index: kernel/arch/x86/kernel/ptrace_32.c +=================================================================== +--- kernel.orig/arch/x86/kernel/ptrace_32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/ptrace_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -682,8 +682,11 @@ + return 0; + + /* Fake a debug trap */ +- if (is_singlestep) ++ if (is_singlestep) { ++ set_pn_state(current, entryexit ? PN_STOP_LEAVE : PN_STOP_ENTRY); + send_sigtrap(current, regs, 0); ++ clear_pn_state(current); ++ } + + if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu) + goto out; +Index: kernel/arch/x86/kernel/ptrace_64.c +=================================================================== +--- kernel.orig/arch/x86/kernel/ptrace_64.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/ptrace_64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -616,6 +616,10 @@ + + if ((test_thread_flag(TIF_SYSCALL_TRACE) + || test_thread_flag(TIF_SINGLESTEP)) +- && (current->ptrace & PT_PTRACED)) ++ && (current->ptrace & PT_PTRACED)) { ++ set_pn_state(current, (regs->rax != -ENOSYS) ? ++ PN_STOP_LEAVE : PN_STOP_ENTRY); + syscall_trace(regs); ++ clear_pn_state(current); ++ } + } +Index: kernel/arch/x86/kernel/setup64.c +=================================================================== +--- kernel.orig/arch/x86/kernel/setup64.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/setup64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -293,3 +293,5 @@ + + raw_local_save_flags(kernel_eflags); + } ++ ++EXPORT_SYMBOL_GPL(cpu_gdt_descr); +Index: kernel/arch/x86/kernel/signal_32.c +=================================================================== +--- kernel.orig/arch/x86/kernel/signal_32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/signal_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -587,6 +588,9 @@ + if (!user_mode(regs)) + return; + ++ if (try_to_freeze() && !signal_pending(current)) ++ goto no_signal; ++ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else +@@ -615,6 +619,7 @@ + return; + } + ++no_signal: + /* Did we come from a system call? */ + if (regs->orig_eax >= 0) { + /* Restart the system call - no handlers present */ +Index: kernel/arch/x86/kernel/signal_64.c +=================================================================== +--- kernel.orig/arch/x86/kernel/signal_64.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/signal_64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -403,6 +404,9 @@ + if (!user_mode(regs)) + return; + ++ if (try_to_freeze() && !signal_pending(current)) ++ goto no_signal; ++ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else +@@ -429,6 +433,7 @@ + return; + } + ++no_signal: + /* Did we come from a system call? */ + if ((long)regs->orig_rax >= 0) { + /* Restart the system call - no handlers present */ +Index: kernel/arch/x86/kernel/smp_32.c +=================================================================== +--- kernel.orig/arch/x86/kernel/smp_32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/smp_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -20,6 +20,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -427,6 +428,8 @@ + preempt_enable(); + } + ++EXPORT_SYMBOL(flush_tlb_mm); ++ + void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) + { + struct mm_struct *mm = vma->vm_mm; +@@ -602,6 +605,89 @@ + return 0; + } + ++static DEFINE_SPINLOCK(nmi_call_lock); ++static struct nmi_call_data_struct { ++ smp_nmi_function func; ++ void *info; ++ atomic_t started; ++ atomic_t finished; ++ cpumask_t cpus_called; ++ int wait; ++} *nmi_call_data; ++ ++static int smp_nmi_callback(struct pt_regs * regs, int cpu) ++{ ++ smp_nmi_function func; ++ void *info; ++ int wait; ++ ++ func = nmi_call_data->func; ++ info = nmi_call_data->info; ++ wait = nmi_call_data->wait; ++ ack_APIC_irq(); ++ /* prevent from calling func() multiple times */ ++ if (cpu_test_and_set(cpu, nmi_call_data->cpus_called)) ++ return 0; ++ /* ++ * notify initiating CPU that I've grabbed the data and am ++ * about to execute the function ++ */ ++ mb(); ++ atomic_inc(&nmi_call_data->started); ++ /* at this point the nmi_call_data structure is out of scope */ ++ irq_enter(); ++ func(regs, info); ++ irq_exit(); ++ if (wait) ++ atomic_inc(&nmi_call_data->finished); ++ ++ return 0; ++} ++ ++/* ++ * This function tries to call func(regs, info) on each cpu. ++ * Func must be fast and non-blocking. ++ * May be called with disabled interrupts and from any context. ++ */ ++int smp_nmi_call_function(smp_nmi_function func, void *info, int wait) ++{ ++ struct nmi_call_data_struct data; ++ int cpus; ++ ++ cpus = num_online_cpus() - 1; ++ if (!cpus) ++ return 0; ++ ++ data.func = func; ++ data.info = info; ++ data.wait = wait; ++ atomic_set(&data.started, 0); ++ atomic_set(&data.finished, 0); ++ cpus_clear(data.cpus_called); ++ /* prevent this cpu from calling func if NMI happens */ ++ cpu_set(smp_processor_id(), data.cpus_called); ++ ++ if (!spin_trylock(&nmi_call_lock)) ++ return -1; ++ ++ nmi_call_data = &data; ++ set_nmi_ipi_callback(smp_nmi_callback); ++ mb(); ++ ++ /* Send a message to all other CPUs and wait for them to respond */ ++ send_IPI_allbutself(APIC_DM_NMI); ++ while (atomic_read(&data.started) != cpus) ++ barrier(); ++ ++ unset_nmi_ipi_callback(); ++ if (wait) ++ while (atomic_read(&data.finished) != cpus) ++ barrier(); ++ spin_unlock(&nmi_call_lock); ++ ++ return 0; ++} ++ + static void stop_this_cpu (void * dummy) + { + local_irq_disable(); +Index: kernel/arch/x86/kernel/smp_64.c +=================================================================== +--- kernel.orig/arch/x86/kernel/smp_64.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/smp_64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + /* + * Smarter SMP flushing macros. +@@ -463,6 +464,84 @@ + } + EXPORT_SYMBOL(smp_call_function); + ++static DEFINE_SPINLOCK(nmi_call_lock); ++static struct nmi_call_data_struct { ++ smp_nmi_function func; ++ void *info; ++ atomic_t started; ++ atomic_t finished; ++ cpumask_t cpus_called; ++ int wait; ++} *nmi_call_data; ++ ++static int smp_nmi_callback(struct pt_regs * regs, int cpu) ++{ ++ smp_nmi_function func; ++ void *info; ++ int wait; ++ ++ func = nmi_call_data->func; ++ info = nmi_call_data->info; ++ wait = nmi_call_data->wait; ++ ack_APIC_irq(); ++ /* prevent from calling func() multiple times */ ++ if (cpu_test_and_set(cpu, nmi_call_data->cpus_called)) ++ return 0; ++ /* ++ * notify initiating CPU that I've grabbed the data and am ++ * about to execute the function ++ */ ++ mb(); ++ atomic_inc(&nmi_call_data->started); ++ /* at this point the nmi_call_data structure is out of scope */ ++ irq_enter(); ++ func(regs, info); ++ irq_exit(); ++ if (wait) ++ atomic_inc(&nmi_call_data->finished); ++ ++ return 0; ++} ++ ++int smp_nmi_call_function(smp_nmi_function func, void *info, int wait) ++{ ++ struct nmi_call_data_struct data; ++ int cpus; ++ ++ cpus = num_online_cpus() - 1; ++ if (!cpus) ++ return 0; ++ ++ data.func = func; ++ data.info = info; ++ data.wait = wait; ++ atomic_set(&data.started, 0); ++ atomic_set(&data.finished, 0); ++ cpus_clear(data.cpus_called); ++ /* prevent this cpu from calling func if NMI happens */ ++ cpu_set(smp_processor_id(), data.cpus_called); ++ ++ if (!spin_trylock(&nmi_call_lock)) ++ return -1; ++ ++ nmi_call_data = &data; ++ set_nmi_ipi_callback(smp_nmi_callback); ++ mb(); ++ ++ /* Send a message to all other CPUs and wait for them to respond */ ++ send_IPI_allbutself(APIC_DM_NMI); ++ while (atomic_read(&data.started) != cpus) ++ barrier(); ++ ++ unset_nmi_ipi_callback(); ++ if (wait) ++ while (atomic_read(&data.finished) != cpus) ++ barrier(); ++ spin_unlock(&nmi_call_lock); ++ ++ return 0; ++} ++ + static void stop_this_cpu(void *dummy) + { + local_irq_disable(); +Index: kernel/arch/x86/kernel/smpboot_32.c +=================================================================== +--- kernel.orig/arch/x86/kernel/smpboot_32.c 2008-11-24 14:14:34.000000000 +0100 ++++ kernel/arch/x86/kernel/smpboot_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -800,6 +800,13 @@ + early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); + + idle->thread.eip = (unsigned long) start_secondary; ++ ++#ifdef CONFIG_VE ++ /* Cosmetic: sleep_time won't be changed afterwards for the idle ++ * thread; keep it 0 rather than -cycles. */ ++ VE_TASK_INFO(idle)->sleep_time = 0; ++#endif ++ + /* start_eip had better be page-aligned! */ + start_eip = setup_trampoline(); + +Index: kernel/arch/x86/kernel/syscall_table_32.S +=================================================================== +--- kernel.orig/arch/x86/kernel/syscall_table_32.S 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/syscall_table_32.S 2008-11-24 15:47:45.000000000 +0100 +@@ -324,3 +324,14 @@ + .long sys_timerfd + .long sys_eventfd + .long sys_fallocate ++ .rept 510-(.-sys_call_table)/4 ++ .long sys_ni_syscall ++ .endr ++ .long sys_getluid /* 510 */ ++ .long sys_setluid ++ .long sys_setublimit ++ .long sys_ubstat ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_lchmod /* 516 */ ++ .long sys_lutime +Index: kernel/arch/x86/kernel/sysenter_32.c +=================================================================== +--- kernel.orig/arch/x86/kernel/sysenter_32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/sysenter_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -215,7 +215,10 @@ + */ + extern const char vsyscall_int80_start, vsyscall_int80_end; + extern const char vsyscall_sysenter_start, vsyscall_sysenter_end; +-static struct page *syscall_pages[1]; ++void *syscall_page; ++EXPORT_SYMBOL(syscall_page); ++struct page *syscall_pages[1]; ++EXPORT_SYMBOL_GPL(syscall_pages); + + static void map_compat_vdso(int map) + { +@@ -235,10 +238,10 @@ + + int __init sysenter_setup(void) + { +- void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); + const void *vsyscall; + size_t vsyscall_len; + ++ syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); + syscall_pages[0] = virt_to_page(syscall_page); + + gate_vma_init(); +@@ -261,15 +264,22 @@ + + /* Defined in vsyscall-sysenter.S */ + extern void SYSENTER_RETURN; ++EXPORT_SYMBOL_GPL(SYSENTER_RETURN); + + /* Setup a VMA at program startup for the vsyscall page */ +-int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) ++int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack, ++ unsigned long map_address) + { + struct mm_struct *mm = current->mm; + unsigned long addr; + int ret = 0; + bool compat; + ++ if (unlikely(!vdso_enabled) && map_address == 0) { ++ current->mm->context.vdso = NULL; ++ return 0; ++ } ++ + down_write(&mm->mmap_sem); + + /* Test compat mode once here, in case someone +@@ -281,7 +291,7 @@ + if (compat) + addr = VDSO_HIGH_BASE; + else { +- addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0); ++ addr = get_unmapped_area(NULL, map_address, PAGE_SIZE, 0, 0); + if (IS_ERR_VALUE(addr)) { + ret = addr; + goto up_fail; +@@ -315,6 +325,7 @@ + + return ret; + } ++EXPORT_SYMBOL(arch_setup_additional_pages); + + const char *arch_vma_name(struct vm_area_struct *vma) + { +Index: kernel/arch/x86/kernel/traps_32.c +=================================================================== +--- kernel.orig/arch/x86/kernel/traps_32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/traps_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -58,6 +58,7 @@ + #include + + #include ++#include + + #include "mach_traps.h" + +@@ -220,7 +221,8 @@ + static void print_trace_address(void *data, unsigned long addr) + { + printk("%s [<%08lx>] ", (char *)data, addr); +- print_symbol("%s\n", addr); ++ if (decode_call_traces) ++ print_symbol("%s\n", addr); + touch_nmi_watchdog(); + } + +@@ -236,7 +238,10 @@ + unsigned long * stack, char *log_lvl) + { + dump_trace(task, regs, stack, &print_trace_ops, log_lvl); +- printk("%s =======================\n", log_lvl); ++ if (decode_call_traces) ++ printk("%s =======================\n", log_lvl); ++ else ++ printk("%s ==", log_lvl); + } + + void show_trace(struct task_struct *task, struct pt_regs *regs, +@@ -266,8 +271,13 @@ + printk("\n%s ", log_lvl); + printk("%08lx ", *stack++); + } +- printk("\n%sCall Trace:\n", log_lvl); ++ if (decode_call_traces) ++ printk("\n%s Call Trace:\n", log_lvl); ++ else ++ printk("\n%s Call Trace: ", log_lvl); + show_trace_log_lvl(task, regs, esp, log_lvl); ++ if (!decode_call_traces) ++ printk("\n"); + } + + void show_stack(struct task_struct *task, unsigned long *esp) +@@ -289,6 +299,8 @@ + (int)strcspn(init_utsname()->version, " "), + init_utsname()->version); + show_trace(current, NULL, &stack); ++ if (!decode_call_traces) ++ printk("\n"); + } + + EXPORT_SYMBOL(dump_stack); +@@ -299,8 +311,9 @@ + + print_modules(); + __show_registers(regs, 0); +- printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", ++ printk(KERN_EMERG "Process %.*s (pid: %d, veid: %d, ti=%p task=%p task.ti=%p)", + TASK_COMM_LEN, current->comm, task_pid_nr(current), ++ VEID(current->ve_task_info.owner_env), + current_thread_info(), current, task_thread_info(current)); + /* + * When in-kernel, we also print out the stack and code at the +@@ -351,6 +364,13 @@ + return ud2 == 0x0b0f; + } + ++static void inline check_kernel_csum_bug(void) ++{ ++ if (kernel_text_csum_broken) ++ printk("Kernel code checksum mismatch detected %d times\n", ++ kernel_text_csum_broken); ++} ++ + /* + * This is gone through when something in the kernel has done something bad and + * is about to be terminated. +@@ -420,6 +440,7 @@ + } else + printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); + ++ check_kernel_csum_bug(); + bust_spinlocks(0); + die.lock_owner = -1; + add_taint(TAINT_DIE); +@@ -690,12 +711,27 @@ + printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); + } + +-static DEFINE_SPINLOCK(nmi_print_lock); ++/* ++ * Voyager doesn't implement these ++ */ ++void __attribute__((weak)) smp_show_regs(struct pt_regs *regs, void *info) ++{ ++} + ++#ifdef CONFIG_SMP ++int __attribute__((weak)) ++smp_nmi_call_function(smp_nmi_function func, void *info, int wait) ++{ ++ return 0; ++} ++#endif ++ + void __kprobes die_nmi(struct pt_regs *regs, const char *msg) + { ++ static DEFINE_SPINLOCK(nmi_print_lock); ++ + if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == +- NOTIFY_STOP) ++ NOTIFY_STOP) + return; + + spin_lock(&nmi_print_lock); +@@ -708,6 +744,10 @@ + printk(" on CPU%d, eip %08lx, registers:\n", + smp_processor_id(), regs->eip); + show_registers(regs); ++ smp_nmi_call_function(smp_show_regs, NULL, 1); ++ bust_spinlocks(1); ++ if (!decode_call_traces) ++ show_registers(regs); + console_silent(); + spin_unlock(&nmi_print_lock); + bust_spinlocks(0); +@@ -723,6 +763,13 @@ + do_exit(SIGSEGV); + } + ++static int dummy_nmi_callback(struct pt_regs * regs, int cpu) ++{ ++ return 0; ++} ++ ++static nmi_callback_t nmi_ipi_callback = dummy_nmi_callback; ++ + static __kprobes void default_do_nmi(struct pt_regs * regs) + { + unsigned char reason = 0; +@@ -742,10 +789,15 @@ + */ + if (nmi_watchdog_tick(regs, reason)) + return; +- if (!do_nmi_callback(regs, smp_processor_id())) +-#endif ++ if (!do_nmi_callback(regs, smp_processor_id())) { + unknown_nmi_error(reason, regs); ++ return; ++ } ++#endif ++ if (nmi_ipi_callback != dummy_nmi_callback) ++ return; + ++ unknown_nmi_error(reason, regs); + return; + } + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) +@@ -773,12 +825,24 @@ + + ++nmi_count(cpu); + +- if (!ignore_nmis) ++ if (!ignore_nmis) { + default_do_nmi(regs); ++ nmi_ipi_callback(regs, cpu); ++ } + + nmi_exit(); + } + ++void set_nmi_ipi_callback(nmi_callback_t callback) ++{ ++ nmi_ipi_callback = callback; ++} ++ ++void unset_nmi_ipi_callback(void) ++{ ++ nmi_ipi_callback = dummy_nmi_callback; ++} ++ + void stop_nmi(void) + { + acpi_nmi_disable(); +Index: kernel/arch/x86/kernel/traps_64.c +=================================================================== +--- kernel.orig/arch/x86/kernel/traps_64.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/traps_64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -107,6 +107,11 @@ + char *delim = ":"; + char namebuf[128]; + ++ if (!decode_call_traces) { ++ printk("[<%016lx>]", address); ++ return; ++ } ++ + symname = kallsyms_lookup(address, &symsize, &offset, + &modname, namebuf); + if (!symname) { +@@ -382,7 +387,7 @@ + if (((long) stack & (THREAD_SIZE-1)) == 0) + break; + } +- if (i && ((i % 4) == 0)) ++ if (i && ((i % 4) == 0) && decode_call_traces) + printk("\n"); + printk(" %016lx", *stack++); + touch_nmi_watchdog(); +@@ -421,10 +426,12 @@ + struct task_struct *cur = cpu_pda(cpu)->pcurrent; + + rsp = regs->rsp; +- printk("CPU %d ", cpu); ++ printk("CPU: %d ", cpu); + __show_regs(regs); +- printk("Process %s (pid: %d, threadinfo %p, task %p)\n", +- cur->comm, cur->pid, task_thread_info(cur), cur); ++ printk("Process %s (pid: %d, veid=%d, threadinfo %p, task %p)\n", ++ cur->comm, cur->pid, ++ VEID(VE_TASK_INFO(current)->owner_env), ++ task_thread_info(cur), cur); + + /* + * When in-kernel, we also print out the stack and code at the +Index: kernel/arch/x86/kernel/tsc_sync.c +=================================================================== +--- kernel.orig/arch/x86/kernel/tsc_sync.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/tsc_sync.c 2008-11-24 15:47:45.000000000 +0100 +@@ -145,7 +145,10 @@ + } else { + printk(" passed.\n"); + } +- ++#ifdef CONFIG_VE ++ /* TSC reset. kill whatever might rely on old values */ ++ VE_TASK_INFO(current)->wakeup_stamp = 0; ++#endif + /* + * Let the target continue with the bootup: + */ +Index: kernel/arch/x86/kernel/vsyscall-sigreturn_32.S +=================================================================== +--- kernel.orig/arch/x86/kernel/vsyscall-sigreturn_32.S 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/vsyscall-sigreturn_32.S 2008-11-24 15:47:45.000000000 +0100 +@@ -15,7 +15,7 @@ + */ + + .text +- .org __kernel_vsyscall+32,0x90 ++ .org __kernel_vsyscall+0x100,0x90 + .globl __kernel_sigreturn + .type __kernel_sigreturn,@function + __kernel_sigreturn: +@@ -27,6 +27,7 @@ + .size __kernel_sigreturn,.-.LSTART_sigreturn + + .balign 32 ++ .org __kernel_vsyscall+0x200,0x90 + .globl __kernel_rt_sigreturn + .type __kernel_rt_sigreturn,@function + __kernel_rt_sigreturn: +Index: kernel/arch/x86/kernel/vsyscall-sysenter_32.S +=================================================================== +--- kernel.orig/arch/x86/kernel/vsyscall-sysenter_32.S 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/vsyscall-sysenter_32.S 2008-11-24 15:47:45.000000000 +0100 +@@ -39,12 +39,12 @@ + movl %esp,%ebp + sysenter + +- /* 7: align return point with nop's to make disassembly easier */ +- .space 7,0x90 ++ /* 17: align return point with nop's to make disassembly easier */ ++ .space 13,0x90 + +- /* 14: System call restart point is here! (SYSENTER_RETURN-2) */ ++ /* 30: System call restart point is here! (SYSENTER_RETURN-2) */ + jmp .Lenter_kernel +- /* 16: System call normal return point is here! */ ++ /* 32: System call normal return point is here! */ + .globl SYSENTER_RETURN /* Symbol used by sysenter.c */ + SYSENTER_RETURN: + pop %ebp +Index: kernel/arch/x86/kernel/x8664_ksyms_64.c +=================================================================== +--- kernel.orig/arch/x86/kernel/x8664_ksyms_64.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/kernel/x8664_ksyms_64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -3,12 +3,14 @@ + + #include + #include ++#include + + #include + #include + #include + #include + ++EXPORT_SYMBOL(kernel_execve); + EXPORT_SYMBOL(kernel_thread); + + EXPORT_SYMBOL(__down_failed); +Index: kernel/arch/x86/mm/fault_32.c +=================================================================== +--- kernel.orig/arch/x86/mm/fault_32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/mm/fault_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -279,7 +279,7 @@ + return 0; + } + +-int show_unhandled_signals = 1; ++int show_unhandled_signals = 0; + + /* + * This routine handles page faults. It determines the address, +@@ -420,7 +420,6 @@ + goto bad_area; + } + +- survive: + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo +@@ -593,14 +592,14 @@ + */ + out_of_memory: + up_read(&mm->mmap_sem); +- if (is_global_init(tsk)) { +- yield(); +- down_read(&mm->mmap_sem); +- goto survive; ++ if (error_code & 4) { ++ /* ++ * 0-order allocation always success if something really ++ * fatal not happen: beancounter overdraft or OOM. ++ */ ++ force_sig(SIGKILL, tsk); ++ return; + } +- printk("VM: killing process %s\n", tsk->comm); +- if (error_code & 4) +- do_group_exit(SIGKILL); + goto no_context; + + do_sigbus: +Index: kernel/arch/x86/mm/fault_64.c +=================================================================== +--- kernel.orig/arch/x86/mm/fault_64.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/mm/fault_64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -285,7 +285,7 @@ + return 0; + } + +-int show_unhandled_signals = 1; ++int show_unhandled_signals = 0; + + /* + * This routine handles page faults. It determines the address, +@@ -375,7 +375,6 @@ + if (user_mode_vm(regs)) + error_code |= PF_USER; + +- again: + /* When running in the kernel we expect faults to occur only to + * addresses in user space. All other faults represent errors in the + * kernel and should generate an OOPS. Unfortunately, in the case of an +@@ -487,7 +486,7 @@ + + if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && + printk_ratelimit()) { +- printk( ++ ve_printk(VE_LOG, + "%s%s[%d]: segfault at %lx rip %lx rsp %lx error %lx\n", + tsk->pid > 1 ? KERN_INFO : KERN_EMERG, + tsk->comm, tsk->pid, address, regs->rip, +@@ -537,7 +536,8 @@ + else + printk(KERN_ALERT "Unable to handle kernel paging request"); + printk(" at %016lx RIP: \n" KERN_ALERT,address); +- printk_address(regs->rip); ++ if (decode_call_traces) ++ printk_address(regs->rip); + dump_pagetable(address); + tsk->thread.cr2 = address; + tsk->thread.trap_no = 14; +@@ -554,13 +554,14 @@ + */ + out_of_memory: + up_read(&mm->mmap_sem); +- if (is_global_init(current)) { +- yield(); +- goto again; ++ if (error_code & 4) { ++ /* ++ * 0-order allocation always success if something really ++ * fatal not happen: beancounter overdraft or OOM. ++ */ ++ force_sig(SIGKILL, tsk); ++ return; + } +- printk("VM: killing process %s\n", tsk->comm); +- if (error_code & 4) +- do_group_exit(SIGKILL); + goto no_context; + + do_sigbus: +Index: kernel/arch/x86/mm/hugetlbpage.c +=================================================================== +--- kernel.orig/arch/x86/mm/hugetlbpage.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/mm/hugetlbpage.c 2008-11-24 15:47:45.000000000 +0100 +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -206,6 +207,7 @@ + { + return !!(pmd_val(pmd) & _PAGE_PSE); + } ++EXPORT_SYMBOL(pmd_huge); + + struct page * + follow_huge_pmd(struct mm_struct *mm, unsigned long address, +Index: kernel/arch/x86/mm/init_32.c +=================================================================== +--- kernel.orig/arch/x86/mm/init_32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/mm/init_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -783,7 +783,7 @@ + pmd_cache = kmem_cache_create("pmd", + PTRS_PER_PMD*sizeof(pmd_t), + PTRS_PER_PMD*sizeof(pmd_t), +- SLAB_PANIC, ++ SLAB_PANIC|SLAB_UBC, + pmd_ctor); + } + +Index: kernel/arch/x86/mm/init_64.c +=================================================================== +--- kernel.orig/arch/x86/mm/init_64.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/mm/init_64.c 2008-11-24 15:47:45.000000000 +0100 +@@ -97,6 +97,7 @@ + printk(KERN_INFO "%lu pages shared\n",shared); + printk(KERN_INFO "%lu pages swap cached\n",cached); + } ++EXPORT_SYMBOL(show_mem); + + int after_bootmem; + +Index: kernel/arch/x86/mm/pgtable_32.c +=================================================================== +--- kernel.orig/arch/x86/mm/pgtable_32.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/mm/pgtable_32.c 2008-11-24 15:47:45.000000000 +0100 +@@ -4,9 +4,11 @@ + + #include + #include ++#include + #include + #include + #include ++#include + #include + #include + #include +@@ -71,6 +73,7 @@ + printk(KERN_INFO "%lu pages pagetables\n", + global_page_state(NR_PAGETABLE)); + } ++EXPORT_SYMBOL(show_mem); + + /* + * Associate a virtual page frame with a given physical page frame +@@ -188,9 +191,11 @@ + struct page *pte; + + #ifdef CONFIG_HIGHPTE +- pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT|__GFP_ZERO, 0); ++ pte = alloc_pages(GFP_KERNEL_UBC|__GFP_SOFT_UBC|__GFP_HIGHMEM| ++ __GFP_REPEAT|__GFP_ZERO, 0); + #else +- pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0); ++ pte = alloc_pages(GFP_KERNEL_UBC|__GFP_SOFT_UBC| ++ __GFP_REPEAT|__GFP_ZERO, 0); + #endif + return pte; + } +Index: kernel/arch/x86/vdso/vma.c +=================================================================== +--- kernel.orig/arch/x86/vdso/vma.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/arch/x86/vdso/vma.c 2008-11-24 15:47:45.000000000 +0100 +@@ -4,6 +4,7 @@ + * Subject to the GPL, v.2 + */ + #include ++#include + #include + #include + #include +@@ -100,18 +101,24 @@ + + /* Setup a VMA at program startup for the vsyscall page. + Not called for compat tasks */ +-int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) ++int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack, ++ unsigned long map_address) + { + struct mm_struct *mm = current->mm; + unsigned long addr; + int ret; + unsigned len = round_up(vdso_end - vdso_start, PAGE_SIZE); + +- if (!vdso_enabled) ++ if (!vdso_enabled && map_address == 0) { ++ current->mm->context.vdso = NULL; + return 0; ++ } + + down_write(&mm->mmap_sem); +- addr = vdso_addr(mm->start_stack, len); ++ if (map_address) ++ addr = map_address; ++ else ++ addr = vdso_addr(mm->start_stack, len); + addr = get_unmapped_area(NULL, addr, len, 0, 0); + if (IS_ERR_VALUE(addr)) { + ret = addr; +@@ -131,6 +138,7 @@ + up_write(&mm->mmap_sem); + return ret; + } ++EXPORT_SYMBOL_GPL(arch_setup_additional_pages); + + static __init int vdso_setup(char *s) + { +Index: kernel/block/cfq-iosched.c +=================================================================== +--- kernel.orig/block/cfq-iosched.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/block/cfq-iosched.c 2008-11-24 15:47:45.000000000 +0100 +@@ -11,6 +11,11 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include + + /* + * tunables +@@ -24,6 +29,7 @@ + static int cfq_slice_async = HZ / 25; + static const int cfq_slice_async_rq = 2; + static int cfq_slice_idle = HZ / 125; ++static int cfq_ub_slice = HZ / 2; + + /* + * grace period before allowing idle class to get disk access +@@ -40,13 +46,11 @@ + #define RQ_CIC(rq) ((struct cfq_io_context*)(rq)->elevator_private) + #define RQ_CFQQ(rq) ((rq)->elevator_private2) + +-static struct kmem_cache *cfq_pool; + static struct kmem_cache *cfq_ioc_pool; + + static DEFINE_PER_CPU(unsigned long, ioc_count); + static struct completion *ioc_gone; + +-#define CFQ_PRIO_LISTS IOPRIO_BE_NR + #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) + #define cfq_class_rt(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_RT) + +@@ -55,107 +59,6 @@ + + #define sample_valid(samples) ((samples) > 80) + +-/* +- * Most of our rbtree usage is for sorting with min extraction, so +- * if we cache the leftmost node we don't have to walk down the tree +- * to find it. Idea borrowed from Ingo Molnars CFS scheduler. We should +- * move this into the elevator for the rq sorting as well. +- */ +-struct cfq_rb_root { +- struct rb_root rb; +- struct rb_node *left; +-}; +-#define CFQ_RB_ROOT (struct cfq_rb_root) { RB_ROOT, NULL, } +- +-/* +- * Per block device queue structure +- */ +-struct cfq_data { +- struct request_queue *queue; +- +- /* +- * rr list of queues with requests and the count of them +- */ +- struct cfq_rb_root service_tree; +- unsigned int busy_queues; +- +- int rq_in_driver; +- int sync_flight; +- int hw_tag; +- +- /* +- * idle window management +- */ +- struct timer_list idle_slice_timer; +- struct work_struct unplug_work; +- +- struct cfq_queue *active_queue; +- struct cfq_io_context *active_cic; +- +- /* +- * async queue for each priority case +- */ +- struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR]; +- struct cfq_queue *async_idle_cfqq; +- +- struct timer_list idle_class_timer; +- +- sector_t last_position; +- unsigned long last_end_request; +- +- /* +- * tunables, see top of file +- */ +- unsigned int cfq_quantum; +- unsigned int cfq_fifo_expire[2]; +- unsigned int cfq_back_penalty; +- unsigned int cfq_back_max; +- unsigned int cfq_slice[2]; +- unsigned int cfq_slice_async_rq; +- unsigned int cfq_slice_idle; +- +- struct list_head cic_list; +-}; +- +-/* +- * Per process-grouping structure +- */ +-struct cfq_queue { +- /* reference count */ +- atomic_t ref; +- /* parent cfq_data */ +- struct cfq_data *cfqd; +- /* service_tree member */ +- struct rb_node rb_node; +- /* service_tree key */ +- unsigned long rb_key; +- /* sorted list of pending requests */ +- struct rb_root sort_list; +- /* if fifo isn't expired, next request to serve */ +- struct request *next_rq; +- /* requests queued in sort_list */ +- int queued[2]; +- /* currently allocated requests */ +- int allocated[2]; +- /* pending metadata requests */ +- int meta_pending; +- /* fifo list of requests in sort_list */ +- struct list_head fifo; +- +- unsigned long slice_end; +- long slice_resid; +- +- /* number of requests that are on the dispatch list or inside driver */ +- int dispatched; +- +- /* io prio of this group */ +- unsigned short ioprio, org_ioprio; +- unsigned short ioprio_class, org_ioprio_class; +- +- /* various state flags, see below */ +- unsigned int flags; +-}; +- + enum cfqq_state_flags { + CFQ_CFQQ_FLAG_on_rr = 0, /* on round-robin busy list */ + CFQ_CFQQ_FLAG_wait_request, /* waiting for a request */ +@@ -200,6 +103,67 @@ + static void cfq_dispatch_insert(struct request_queue *, struct request *); + static struct cfq_queue *cfq_get_queue(struct cfq_data *, int, + struct task_struct *, gfp_t); ++static void cfq_put_queue(struct cfq_queue *cfqq); ++ ++static void __cfq_put_async_queues(struct cfq_bc_data *cfq_bc) ++{ ++ int i; ++ ++ for (i = 0; i < CFQ_PRIO_LISTS; i++) { ++ if (cfq_bc->async_cfqq[0][i]) { ++ cfq_put_queue(cfq_bc->async_cfqq[0][i]); ++ cfq_bc->async_cfqq[0][i] = NULL; ++ } ++ if (cfq_bc->async_cfqq[1][i]) { ++ cfq_put_queue(cfq_bc->async_cfqq[1][i]); ++ cfq_bc->async_cfqq[1][i] = NULL; ++ } ++ } ++ if (cfq_bc->async_idle_cfqq) { ++ cfq_put_queue(cfq_bc->async_idle_cfqq); ++ cfq_bc->async_idle_cfqq = NULL; ++ } ++} ++ ++#ifdef CONFIG_BC_IO_SCHED ++static inline struct ub_iopriv *cfqq_ub_iopriv(struct cfq_data *cfqd, int sync) ++{ ++ int mode; ++ ++ mode = sync ? cfqd->virt_mode : cfqd->write_virt_mode; ++ return mode ? &get_io_ub()->iopriv : &get_ub0()->iopriv; ++} ++ ++static inline void cfq_put_async_queues(struct cfq_data *cfqd) ++{ ++ struct user_beancounter *ub; ++ struct cfq_bc_data *cfq_bc; ++ ++ rcu_read_lock(); ++ for_each_beancounter(ub) { ++ write_lock(&ub->iopriv.cfq_bc_list_lock); ++ cfq_bc = __find_cfq_bc(&ub->iopriv, cfqd); ++ if (!cfq_bc) { ++ write_unlock(&ub->iopriv.cfq_bc_list_lock); ++ continue; ++ } ++ __cfq_put_async_queues(cfq_bc); ++ write_unlock(&ub->iopriv.cfq_bc_list_lock); ++ } ++ rcu_read_unlock(); ++} ++#else ++static inline struct ub_iopriv *cfqq_ub_iopriv(struct cfq_data *cfqd, int sync) ++{ ++ return NULL; ++} ++ ++static inline void cfq_put_async_queues(struct cfq_data *cfqd) ++{ ++ __cfq_put_async_queues(&cfqd->cfq_bc); ++} ++#endif ++ + static struct cfq_io_context *cfq_cic_rb_lookup(struct cfq_data *, + struct io_context *); + +@@ -286,6 +250,11 @@ + return 1; + } + ++static inline struct user_beancounter *ub_by_iopriv(struct ub_iopriv *iopriv) ++{ ++ return container_of(iopriv, struct user_beancounter, iopriv); ++} ++ + /* + * Lifted from AS - choose which of rq1 and rq2 that is best served now. + * We choose the request that is closest to the head right now. Distance +@@ -446,11 +415,15 @@ + static void cfq_service_tree_add(struct cfq_data *cfqd, + struct cfq_queue *cfqq, int add_front) + { +- struct rb_node **p = &cfqd->service_tree.rb.rb_node; ++ struct cfq_bc_data *cfq_bc; ++ struct rb_node **p; + struct rb_node *parent = NULL; + unsigned long rb_key; + int left; + ++ cfq_bc = cfqq->cfq_bc; ++ ++ p = &cfq_bc->service_tree.rb.rb_node; + if (!add_front) { + rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies; + rb_key += cfqq->slice_resid; +@@ -465,7 +438,7 @@ + if (rb_key == cfqq->rb_key) + return; + +- cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree); ++ cfq_rb_erase(&cfqq->rb_node, &cfq_bc->service_tree); + } + + left = 1; +@@ -501,11 +474,11 @@ + } + + if (left) +- cfqd->service_tree.left = &cfqq->rb_node; ++ cfq_bc->service_tree.left = &cfqq->rb_node; + + cfqq->rb_key = rb_key; + rb_link_node(&cfqq->rb_node, parent, p); +- rb_insert_color(&cfqq->rb_node, &cfqd->service_tree.rb); ++ rb_insert_color(&cfqq->rb_node, &cfq_bc->service_tree.rb); + } + + /* +@@ -530,6 +503,7 @@ + BUG_ON(cfq_cfqq_on_rr(cfqq)); + cfq_mark_cfqq_on_rr(cfqq); + cfqd->busy_queues++; ++ bc_inc_rqnum(cfqq); + + cfq_resort_rr_list(cfqd, cfqq); + } +@@ -541,14 +515,19 @@ + static inline void + cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) + { ++ struct cfq_bc_data *cfq_bc; ++ + BUG_ON(!cfq_cfqq_on_rr(cfqq)); + cfq_clear_cfqq_on_rr(cfqq); + ++ cfq_bc = cfqq->cfq_bc; ++ + if (!RB_EMPTY_NODE(&cfqq->rb_node)) +- cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree); ++ cfq_rb_erase(&cfqq->rb_node, &cfq_bc->service_tree); + + BUG_ON(!cfqd->busy_queues); + cfqd->busy_queues--; ++ bc_dec_rqnum(cfqq); + } + + /* +@@ -665,8 +644,7 @@ + } + } + +-static int cfq_merge(struct request_queue *q, struct request **req, +- struct bio *bio) ++static int cfq_merge(struct request_queue *q, struct request **req, struct bio *bio) + { + struct cfq_data *cfqd = q->elevator->elevator_data; + struct request *__rq; +@@ -795,7 +773,7 @@ + unsigned long now = jiffies; + + if (time_before(now, end) && +- time_after_eq(now, cfqd->last_end_request)) { ++ time_after_eq(now, cfqd->last_end_request)) { + mod_timer(&cfqd->idle_class_timer, end); + return 1; + } +@@ -809,13 +787,18 @@ + */ + static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd) + { ++ struct cfq_bc_data *cfq_bc; + struct cfq_queue *cfqq; + struct rb_node *n; + +- if (RB_EMPTY_ROOT(&cfqd->service_tree.rb)) ++ cfq_bc = cfqd->active_cfq_bc; ++ if (!cfq_bc) + return NULL; + +- n = cfq_rb_first(&cfqd->service_tree); ++ if (RB_EMPTY_ROOT(&cfq_bc->service_tree.rb)) ++ return NULL; ++ ++ n = cfq_rb_first(&cfq_bc->service_tree); + cfqq = rb_entry(n, struct cfq_queue, rb_node); + + if (cfq_class_idle(cfqq)) { +@@ -837,9 +820,17 @@ + */ + static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd) + { +- struct cfq_queue *cfqq; ++ struct cfq_queue *cfqq = NULL; ++ struct cfq_bc_data *cfq_bc; ++ ++ bc_schedule_active(cfqd); ++ ++ cfq_bc = cfqd->active_cfq_bc; ++ if (!cfq_bc) ++ goto out; + + cfqq = cfq_get_next_queue(cfqd); ++out: + __cfq_set_active_queue(cfqd, cfqq); + return cfqq; + } +@@ -930,6 +921,7 @@ + + cfq_remove_request(rq); + cfqq->dispatched++; ++ cfqq->cfq_bc->on_dispatch++; + elv_dispatch_sort(q, rq); + + if (cfq_cfqq_sync(cfqq)) +@@ -987,7 +979,7 @@ + /* + * The active queue has run out of time, expire it and select new. + */ +- if (cfq_slice_used(cfqq)) ++ if (cfq_slice_used(cfqq) || bc_expired(cfqd)) + goto expire; + + /* +@@ -1085,17 +1077,36 @@ + * Drain our current requests. Used for barriers and when switching + * io schedulers on-the-fly. + */ +-static int cfq_forced_dispatch(struct cfq_data *cfqd) ++static int __cfq_forced_dispatch(struct cfq_bc_data *cfq_bc) + { + int dispatched = 0; + struct rb_node *n; + +- while ((n = cfq_rb_first(&cfqd->service_tree)) != NULL) { ++ while ((n = cfq_rb_first(&cfq_bc->service_tree)) != NULL) { + struct cfq_queue *cfqq = rb_entry(n, struct cfq_queue, rb_node); + + dispatched += __cfq_forced_dispatch_cfqq(cfqq); + } + ++ return dispatched; ++} ++ ++static int cfq_forced_dispatch(struct cfq_data *cfqd) ++{ ++ struct cfq_bc_data *cfq_bc; ++ struct cfq_bc_data *cfq_bc_tmp; ++ int dispatched; ++ ++ dispatched = 0; ++ /* ++ * We use here _safe iterating, because ++ * __cfq_forced_dispatch() produces list_del() implicitly ++ */ ++ list_for_each_entry_safe(cfq_bc, cfq_bc_tmp, ++ &cfqd->act_cfq_bc_head, act_cfq_bc_list) { ++ dispatched += __cfq_forced_dispatch(cfq_bc); ++ } ++ + cfq_slice_expired(cfqd, 0); + + BUG_ON(cfqd->busy_queues); +@@ -1208,6 +1219,10 @@ + smp_wmb(); + cic->key = NULL; + ++ /* ++ * cic->cfqq[ASYNC] is always NULL and the put of async queues ++ * happens on appropriate bc death or device unplug ++ */ + if (cic->cfqq[ASYNC]) { + cfq_exit_cfqq(cfqd, cic->cfqq[ASYNC]); + cic->cfqq[ASYNC] = NULL; +@@ -1327,6 +1342,10 @@ + + spin_lock_irqsave(cfqd->queue->queue_lock, flags); + ++ /* ++ * cic->cfqq[ASYNC] is always NULL, ioprio change ++ * for async queues happens automatically ++ */ + cfqq = cic->cfqq[ASYNC]; + if (cfqq) { + struct cfq_queue *new_cfqq; +@@ -1367,8 +1386,11 @@ + { + struct cfq_queue *cfqq, *new_cfqq = NULL; + struct cfq_io_context *cic; ++ struct ub_iopriv *iopriv; ++ struct cfq_bc_data *cfq_bc = NULL; + + retry: ++ iopriv = cfqq_ub_iopriv(cfqd, is_sync); + cic = cfq_cic_rb_lookup(cfqd, tsk->io_context); + /* cic always exists here */ + cfqq = cic_to_cfqq(cic, is_sync); +@@ -1386,18 +1408,32 @@ + */ + spin_unlock_irq(cfqd->queue->queue_lock); + new_cfqq = kmem_cache_alloc_node(cfq_pool, +- gfp_mask | __GFP_NOFAIL | __GFP_ZERO, ++ gfp_mask|__GFP_NOFAIL|__GFP_ZERO, + cfqd->queue->node); ++ if (new_cfqq) { ++ cfq_bc = bc_findcreate_cfq_bc(iopriv, ++ cfqd, gfp_mask); ++ if (!cfq_bc) { ++ kmem_cache_free(cfq_pool, new_cfqq); ++ new_cfqq = NULL; ++ } ++ } + spin_lock_irq(cfqd->queue->queue_lock); + goto retry; + } else { + cfqq = kmem_cache_alloc_node(cfq_pool, +- gfp_mask | __GFP_ZERO, +- cfqd->queue->node); ++ gfp_mask|__GFP_ZERO, cfqd->queue->node); + if (!cfqq) + goto out; ++ cfq_bc = bc_findcreate_cfq_bc(iopriv, cfqd, gfp_mask); ++ if (!cfq_bc) { ++ kmem_cache_free(cfq_pool, cfqq); ++ cfqq = NULL; ++ goto out; ++ } + } + ++ cfqq->cfq_bc = cfq_bc; + RB_CLEAR_NODE(&cfqq->rb_node); + INIT_LIST_HEAD(&cfqq->fifo); + +@@ -1424,15 +1460,15 @@ + } + + static struct cfq_queue ** +-cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio) ++cfq_async_queue_prio(struct cfq_bc_data *cfq_bc, int ioprio_class, int ioprio) + { + switch(ioprio_class) { + case IOPRIO_CLASS_RT: +- return &cfqd->async_cfqq[0][ioprio]; ++ return &cfq_bc->async_cfqq[0][ioprio]; + case IOPRIO_CLASS_BE: +- return &cfqd->async_cfqq[1][ioprio]; ++ return &cfq_bc->async_cfqq[1][ioprio]; + case IOPRIO_CLASS_IDLE: +- return &cfqd->async_idle_cfqq; ++ return &cfq_bc->async_idle_cfqq; + default: + BUG(); + } +@@ -1446,12 +1482,18 @@ + const int ioprio_class = task_ioprio_class(tsk); + struct cfq_queue **async_cfqq = NULL; + struct cfq_queue *cfqq = NULL; ++ struct cfq_bc_data *cfq_bc; ++ struct ub_iopriv *iopriv; ++ ++ iopriv = cfqq_ub_iopriv(cfqd, is_sync); + + if (!is_sync) { +- async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio); ++ cfq_bc = bc_findcreate_cfq_bc(iopriv, cfqd, gfp_mask); ++ if (!cfq_bc) ++ return NULL; ++ async_cfqq = cfq_async_queue_prio(cfq_bc, ioprio_class, ioprio); + cfqq = *async_cfqq; + } +- + if (!cfqq) { + cfqq = cfq_find_alloc_queue(cfqd, is_sync, tsk, gfp_mask); + if (!cfqq) +@@ -1815,6 +1857,7 @@ + WARN_ON(!cfqq->dispatched); + cfqd->rq_in_driver--; + cfqq->dispatched--; ++ cfqq->cfq_bc->on_dispatch--; + + if (cfq_cfqq_sync(cfqq)) + cfqd->sync_flight--; +@@ -1927,6 +1970,7 @@ + rq->elevator_private = NULL; + rq->elevator_private2 = NULL; + ++ put_beancounter(ub_by_iopriv(cfqq->cfq_bc->ub_iopriv)); + cfq_put_queue(cfqq); + } + } +@@ -1944,14 +1988,19 @@ + const int is_sync = rq_is_sync(rq); + struct cfq_queue *cfqq; + unsigned long flags; ++ struct ub_iopriv *iopriv; ++ struct cfq_bc_data *cfq_bc = NULL; + + might_sleep_if(gfp_mask & __GFP_WAIT); + + cic = cfq_get_io_context(cfqd, gfp_mask); ++ iopriv = cfqq_ub_iopriv(cfqd, is_sync); ++ if (!is_sync) ++ cfq_bc = bc_findcreate_cfq_bc(iopriv, cfqd, gfp_mask); + + spin_lock_irqsave(q->queue_lock, flags); + +- if (!cic) ++ if (!cic || (!is_sync && cfq_bc == NULL)) + goto queue_fail; + + cfqq = cic_to_cfqq(cic, is_sync); +@@ -1972,6 +2021,7 @@ + + rq->elevator_private = cic; + rq->elevator_private2 = cfqq; ++ get_beancounter(ub_by_iopriv(cfqq->cfq_bc->ub_iopriv)); + return 0; + + queue_fail: +@@ -2065,21 +2115,6 @@ + kblockd_flush_work(&cfqd->unplug_work); + } + +-static void cfq_put_async_queues(struct cfq_data *cfqd) +-{ +- int i; +- +- for (i = 0; i < IOPRIO_BE_NR; i++) { +- if (cfqd->async_cfqq[0][i]) +- cfq_put_queue(cfqd->async_cfqq[0][i]); +- if (cfqd->async_cfqq[1][i]) +- cfq_put_queue(cfqd->async_cfqq[1][i]); +- } +- +- if (cfqd->async_idle_cfqq) +- cfq_put_queue(cfqd->async_idle_cfqq); +-} +- + static void cfq_exit_queue(elevator_t *e) + { + struct cfq_data *cfqd = e->elevator_data; +@@ -2106,6 +2141,8 @@ + + cfq_shutdown_timer_wq(cfqd); + ++ bc_cfq_exit_queue(cfqd); ++ + kfree(cfqd); + } + +@@ -2113,11 +2150,19 @@ + { + struct cfq_data *cfqd; + +- cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node); ++ cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL|__GFP_ZERO, q->node); + if (!cfqd) + return NULL; + +- cfqd->service_tree = CFQ_RB_ROOT; ++ INIT_LIST_HEAD(&cfqd->act_cfq_bc_head); ++#ifndef CONFIG_BC_IO_SCHED ++ cfq_init_cfq_bc(&cfqd->cfq_bc); ++ /* ++ * Adding ub0 to active list in order to serve force dispatching ++ * case uniformally. Note, that nobody removes ub0 from this list. ++ */ ++ list_add_tail(&cfqd->cfq_bc.act_cfq_bc_list, &cfqd->act_cfq_bc_head); ++#endif + INIT_LIST_HEAD(&cfqd->cic_list); + + cfqd->queue = q; +@@ -2142,6 +2187,9 @@ + cfqd->cfq_slice[1] = cfq_slice_sync; + cfqd->cfq_slice_async_rq = cfq_slice_async_rq; + cfqd->cfq_slice_idle = cfq_slice_idle; ++ cfqd->cfq_ub_slice = cfq_ub_slice; ++ cfqd->virt_mode = 1; ++ cfqd->write_virt_mode = 1; + + return cfqd; + } +@@ -2206,6 +2254,9 @@ + SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1); + SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1); + SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0); ++SHOW_FUNCTION(cfq_ub_slice_show, cfqd->cfq_ub_slice, 1); ++SHOW_FUNCTION(cfq_virt_mode_show, cfqd->virt_mode, 0); ++SHOW_FUNCTION(cfq_write_virt_mode_show, cfqd->write_virt_mode, 0); + #undef SHOW_FUNCTION + + #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ +@@ -2233,7 +2284,9 @@ + STORE_FUNCTION(cfq_slice_sync_store, &cfqd->cfq_slice[1], 1, UINT_MAX, 1); + STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1); + STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1, UINT_MAX, 0); +-#undef STORE_FUNCTION ++STORE_FUNCTION(cfq_ub_slice_store, &cfqd->cfq_ub_slice, 1, UINT_MAX, 1); ++STORE_FUNCTION(cfq_virt_mode_store, &cfqd->virt_mode, 0, 1, 0); ++STORE_FUNCTION(cfq_write_virt_mode_store, &cfqd->write_virt_mode, 0, 1, 0); + + #define CFQ_ATTR(name) \ + __ATTR(name, S_IRUGO|S_IWUSR, cfq_##name##_show, cfq_##name##_store) +@@ -2248,6 +2301,9 @@ + CFQ_ATTR(slice_async), + CFQ_ATTR(slice_async_rq), + CFQ_ATTR(slice_idle), ++ CFQ_ATTR(ub_slice), ++ CFQ_ATTR(virt_mode), ++ CFQ_ATTR(write_virt_mode), + __ATTR_NULL + }; + +@@ -2271,6 +2327,7 @@ + .elevator_init_fn = cfq_init_queue, + .elevator_exit_fn = cfq_exit_queue, + .trim = cfq_free_io_context, ++ .put_queue = cfq_put_queue, + }, + .elevator_attrs = cfq_attrs, + .elevator_name = "cfq", +Index: kernel/block/elevator.c +=================================================================== +--- kernel.orig/block/elevator.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/block/elevator.c 2008-11-24 15:47:45.000000000 +0100 +@@ -40,6 +40,9 @@ + static DEFINE_SPINLOCK(elv_list_lock); + static LIST_HEAD(elv_list); + ++struct kmem_cache *cfq_pool; ++EXPORT_SYMBOL_GPL(cfq_pool); ++ + /* + * Merge hash stuff. + */ +@@ -987,12 +990,12 @@ + */ + if (e->ops.trim) { + read_lock(&tasklist_lock); +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + task_lock(p); + if (p->io_context) + e->ops.trim(p->io_context); + task_unlock(p); +- } while_each_thread(g, p); ++ } while_each_thread_all(g, p); + read_unlock(&tasklist_lock); + } + +Index: kernel/block/genhd.c +=================================================================== +--- kernel.orig/block/genhd.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/block/genhd.c 2008-11-24 15:47:45.000000000 +0100 +@@ -18,6 +18,7 @@ + #include + + struct kset block_subsys; ++EXPORT_SYMBOL(block_subsys); + static DEFINE_MUTEX(block_subsys_lock); + + /* +Index: kernel/drivers/base/class.c +=================================================================== +--- kernel.orig/drivers/base/class.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/drivers/base/class.c 2008-11-24 15:47:45.000000000 +0100 +@@ -17,6 +17,8 @@ + #include + #include + #include ++#include ++#include + #include "base.h" + + #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) +@@ -71,8 +73,13 @@ + }; + + /* Hotplug events for classes go to the class_obj subsys */ +-static decl_subsys(class, &class_ktype, NULL); ++decl_subsys(class, &class_ktype, NULL); + ++#ifndef CONFIG_VE ++#define visible_class_subsys class_subsys ++#else ++#define visible_class_subsys (*get_exec_env()->class_subsys) ++#endif + + int class_create_file(struct class * cls, const struct class_attribute * attr) + { +@@ -149,7 +156,7 @@ + if (error) + return error; + +- cls->subsys.kobj.kset = &class_subsys; ++ cls->subsys.kobj.kset = &visible_class_subsys; + + error = subsystem_register(&cls->subsys); + if (!error) { +@@ -452,8 +459,13 @@ + .uevent = class_uevent, + }; + +-static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops); ++decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops); + ++#ifndef CONFIG_VE ++#define visible_class_obj_subsys class_obj_subsys ++#else ++#define visible_class_obj_subsys (*get_exec_env()->class_obj_subsys) ++#endif + + static int class_device_add_attrs(struct class_device * cd) + { +@@ -537,7 +549,7 @@ + + void class_device_initialize(struct class_device *class_dev) + { +- kobj_set_kset_s(class_dev, class_obj_subsys); ++ kobj_set_kset_s(class_dev, visible_class_obj_subsys); + kobject_init(&class_dev->kobj); + INIT_LIST_HEAD(&class_dev->node); + } +@@ -851,10 +863,19 @@ + class_put(parent); + } + ++void prepare_sysfs_classes(void) ++{ ++#ifdef CONFIG_VE ++ get_ve0()->class_subsys = &class_subsys; ++ get_ve0()->class_obj_subsys = &class_obj_subsys; ++#endif ++} ++ + int __init classes_init(void) + { + int retval; + ++ prepare_sysfs_classes(); + retval = subsystem_register(&class_subsys); + if (retval) + return retval; +@@ -890,3 +911,6 @@ + + EXPORT_SYMBOL_GPL(class_interface_register); + EXPORT_SYMBOL_GPL(class_interface_unregister); ++ ++EXPORT_SYMBOL(class_subsys); ++EXPORT_SYMBOL(class_obj_subsys); +Index: kernel/drivers/base/core.c +=================================================================== +--- kernel.orig/drivers/base/core.c 2008-11-18 01:19:42.000000000 +0100 ++++ kernel/drivers/base/core.c 2008-11-24 15:47:45.000000000 +0100 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -406,7 +407,12 @@ + */ + + decl_subsys(devices, &device_ktype, &device_uevent_ops); +- ++EXPORT_SYMBOL_GPL(devices_subsys); ++#ifdef CONFIG_VE ++#define ve_devices_subsys (get_exec_env()->devices_subsys) ++#else ++#define ve_devices_subsys (&devices_subsys) ++#endif + + /** + * device_create_file - create sysfs attribute file for device. +@@ -525,7 +531,7 @@ + + void device_initialize(struct device *dev) + { +- kobj_set_kset_s(dev, devices_subsys); ++ dev->kobj.kset = ve_devices_subsys; + kobject_init(&dev->kobj); + klist_init(&dev->klist_children, klist_children_get, + klist_children_put); +@@ -556,12 +562,17 @@ + return NULL; + } + #else ++#ifdef CONFIG_VE ++#include ++#define virtual_dir (get_exec_env()->_virtual_dir) ++#else ++static struct kobject *virtual_dir = NULL; ++#endif ++ + static struct kobject *virtual_device_parent(struct device *dev) + { +- static struct kobject *virtual_dir = NULL; +- + if (!virtual_dir) +- virtual_dir = kobject_add_dir(&devices_subsys.kobj, "virtual"); ++ virtual_dir = kobject_add_dir(&get_exec_env()->devices_subsys->kobj, "virtual"); + + return virtual_dir; + } +@@ -1073,6 +1084,9 @@ + + int __init devices_init(void) + { ++#ifdef CONFIG_VE ++ ve0.devices_subsys = &devices_subsys; ++#endif + return subsystem_register(&devices_subsys); + } + +Index: kernel/drivers/char/pty.c +=================================================================== +--- kernel.orig/drivers/char/pty.c 2008-11-18 01:19:43.000000000 +0100 ++++ kernel/drivers/char/pty.c 2008-11-24 15:47:45.000000000 +0100 +@@ -29,16 +29,30 @@ + #include + #include + ++#include ++ + /* These are global because they are accessed in tty_io.c */ + #ifdef CONFIG_UNIX98_PTYS + struct tty_driver *ptm_driver; +-static struct tty_driver *pts_driver; ++struct tty_driver *pts_driver; ++EXPORT_SYMBOL(ptm_driver); ++EXPORT_SYMBOL(pts_driver); ++ ++void prepare_pty(void) ++{ ++#ifdef CONFIG_VE ++ get_ve0()->ptm_driver = ptm_driver; ++ /* don't clean ptm_driver and co. here, they are used in vecalls.c */ ++#endif ++} + #endif + + static void pty_close(struct tty_struct * tty, struct file * filp) + { + if (!tty) + return; ++ ++ ub_pty_uncharge(tty); + if (tty->driver->subtype == PTY_TYPE_MASTER) { + if (tty->count > 1) + printk("master pty_close: count = %d!!\n", tty->count); +@@ -58,8 +72,12 @@ + if (tty->driver->subtype == PTY_TYPE_MASTER) { + set_bit(TTY_OTHER_CLOSED, &tty->flags); + #ifdef CONFIG_UNIX98_PTYS +- if (tty->driver == ptm_driver) ++ if (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) { ++ struct ve_struct *old_env; ++ old_env = set_exec_env(tty->owner_env); + devpts_pty_kill(tty->index); ++ (void)set_exec_env(old_env); ++ } + #endif + tty_vhangup(tty->link); + } +@@ -209,6 +227,10 @@ + if (tty->link->count != 1) + goto out; + ++ retval = -ENOMEM; ++ if (ub_pty_charge(tty)) ++ goto out; ++ + clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); + set_bit(TTY_THROTTLED, &tty->flags); + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); +@@ -236,7 +258,9 @@ + + /* Traditional BSD devices */ + #ifdef CONFIG_LEGACY_PTYS +-static struct tty_driver *pty_driver, *pty_slave_driver; ++struct tty_driver *pty_driver, *pty_slave_driver; ++EXPORT_SYMBOL(pty_driver); ++EXPORT_SYMBOL(pty_slave_driver); + + static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +@@ -426,6 +450,7 @@ + + pty_table[1].data = &ptm_driver->refcount; + register_sysctl_table(pty_root_table); ++ prepare_pty(); + } + #else + static inline void unix98_pty_init(void) { } +Index: kernel/drivers/char/sysrq.c +=================================================================== +--- kernel.orig/drivers/char/sysrq.c 2008-11-18 01:19:43.000000000 +0100 ++++ kernel/drivers/char/sysrq.c 2008-11-24 15:47:45.000000000 +0100 +@@ -36,6 +36,8 @@ + #include + #include + #include ++#include ++#include + #include + + #include +@@ -199,8 +201,14 @@ + static void sysrq_handle_showregs(int key, struct tty_struct *tty) + { + struct pt_regs *regs = get_irq_regs(); ++ ++ bust_spinlocks(1); + if (regs) + show_regs(regs); ++ bust_spinlocks(0); ++#if defined(__i386__) || defined(__x86_64__) ++ smp_nmi_call_function(smp_show_regs, NULL, 1); ++#endif + } + static struct sysrq_key_op sysrq_showregs_op = { + .handler = sysrq_handle_showregs, +@@ -235,6 +243,7 @@ + static void sysrq_handle_showmem(int key, struct tty_struct *tty) + { + show_mem(); ++ show_slab_info(); + } + static struct sysrq_key_op sysrq_showmem_op = { + .handler = sysrq_handle_showmem, +@@ -250,7 +259,7 @@ + { + struct task_struct *p; + +- for_each_process(p) { ++ for_each_process_all(p) { + if (p->mm && !is_global_init(p)) + /* Not swapper, init nor kernel thread */ + force_sig(sig, p); +@@ -313,7 +322,267 @@ + /* Key Operations table and lock */ + static DEFINE_SPINLOCK(sysrq_key_table_lock); + +-static struct sysrq_key_op *sysrq_key_table[36] = { ++#define SYSRQ_KEY_TABLE_LENGTH 37 ++static struct sysrq_key_op **sysrq_key_table; ++static struct sysrq_key_op *sysrq_default_key_table[]; ++ ++#ifdef CONFIG_SYSRQ_DEBUG ++#define SYSRQ_NAMELEN_MAX 64 ++#define SYSRQ_DUMP_LINES 32 ++ ++static struct sysrq_key_op *sysrq_debug_key_table[]; ++static struct sysrq_key_op *sysrq_input_key_table[]; ++static unsigned long *dump_address; ++static int orig_console_loglevel; ++static void (*sysrq_input_return)(char *) = NULL; ++ ++static void dump_mem(void) ++{ ++ unsigned long value[4]; ++ mm_segment_t old_fs; ++ int line, err; ++ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = 0; ++ ++ for (line = 0; line < SYSRQ_DUMP_LINES; line++) { ++ err |= __get_user(value[0], dump_address++); ++ err |= __get_user(value[1], dump_address++); ++ err |= __get_user(value[2], dump_address++); ++ err |= __get_user(value[3], dump_address++); ++ if (err) { ++ printk("Invalid address %p\n", dump_address - 4); ++ break; ++ } ++#if BITS_PER_LONG == 32 ++ printk("0x%p: %08lx %08lx %08lx %08lx\n", ++ dump_address - 4, ++ value[0], value[1], value[2], value[3]); ++#else ++ printk("0x%p: %016lx %016lx %016lx %016lx\n", ++ dump_address - 4, ++ value[0], value[1], value[2], value[3]); ++#endif ++ } ++ set_fs(old_fs); ++} ++ ++static void write_mem(unsigned long val) ++{ ++ mm_segment_t old_fs; ++ unsigned long old_val; ++ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ if (__get_user(old_val, dump_address)) { ++ printk("Invalid address %p\n", dump_address); ++ goto out; ++ } ++ ++#if BITS_PER_LONG == 32 ++ printk("Changing [%p] from %08lx to %08lx\n", ++ dump_address, old_val, val); ++#else ++ printk("Changing [%p] from %016lx to %016lx\n", ++ dump_address, old_val, val); ++#endif ++ __put_user(val, dump_address); ++out: ++ set_fs(old_fs); ++} ++ ++static void handle_read(int key, struct tty_struct *tty) ++{ ++ static int pos; ++ static int upper_case; ++ static char str[SYSRQ_NAMELEN_MAX]; ++ ++ if (key == 0) { ++ /* actually 0 is not shift only... */ ++ upper_case = 1; ++ return; ++ } ++ ++ if (key == 0x0d || pos == SYSRQ_NAMELEN_MAX - 1) { ++ /* enter */ ++ sysrq_key_table = sysrq_debug_key_table; ++ str[pos] = '\0'; ++ pos = upper_case = 0; ++ printk("\n"); ++ if (sysrq_input_return == NULL) ++ printk("No return handler!!!\n"); ++ else ++ sysrq_input_return(str); ++ return; ++ }; ++ ++ /* check for alowed symbols */ ++ if (key == '-') { ++ if (upper_case) ++ key = '_'; ++ goto correct; ++ }; ++ if (key >= 'a' && key <= 'z') { ++ if (upper_case) ++ key = key - 'a' + 'A'; ++ goto correct; ++ }; ++ if (key >= '0' && key <= '9') ++ goto correct; ++ ++ upper_case = 0; ++ return; ++ ++correct: ++ str[pos] = key; ++ printk("%c", (char)key); ++ pos++; ++ upper_case = 0; ++} ++ ++static struct sysrq_key_op input_read = { ++ .handler = handle_read, ++ .help_msg = "", ++ .action_msg = NULL, ++}; ++ ++static struct sysrq_key_op *sysrq_input_key_table[SYSRQ_KEY_TABLE_LENGTH] = { ++ [0 ... SYSRQ_KEY_TABLE_LENGTH - 1] = &input_read, ++}; ++ ++static void return_dump_mem(char *str) ++{ ++ unsigned long address; ++ char *end; ++ ++ address = simple_strtoul(str, &end, 0); ++ if (*end != '\0') { ++ printk("Bad address [%s]\n", str); ++ return; ++ } ++ ++ dump_address = (unsigned long *)address; ++ dump_mem(); ++} ++ ++static void handle_dump_mem(int key, struct tty_struct *tty) ++{ ++ sysrq_input_return = return_dump_mem; ++ sysrq_key_table = sysrq_input_key_table; ++} ++ ++static struct sysrq_key_op debug_dump_mem = { ++ .handler = handle_dump_mem, ++ .help_msg = "Dump", ++ .action_msg = "Enter address:", ++}; ++ ++static void return_resolve(char *str) ++{ ++ unsigned long address; ++ ++ address = kallsyms_lookup_name(str); ++ printk("%s : %lx\n", str, address); ++ if (address) { ++ dump_address = (unsigned long *)address; ++ printk("Now you can dump it via X\n"); ++ } ++} ++ ++static void handle_resolve(int key, struct tty_struct *tty) ++{ ++ sysrq_input_return = return_resolve; ++ sysrq_key_table = sysrq_input_key_table; ++} ++ ++static struct sysrq_key_op debug_resolve = { ++ .handler = handle_resolve, ++ .help_msg = "Resolve", ++ .action_msg = "Enter symbol name:", ++}; ++ ++static void return_write_mem(char *str) ++{ ++ unsigned long address; ++ unsigned long value; ++ char *end; ++ ++ address = simple_strtoul(str, &end, 0); ++ if (*end != '-') { ++ printk("Bad address in %s\n", str); ++ return; ++ } ++ value = simple_strtoul(end + 1, &end, 0); ++ if (*end != '\0') { ++ printk("Bad value in %s\n", str); ++ return; ++ } ++ ++ dump_address = (unsigned long *)address; ++ write_mem(value); ++} ++ ++static void handle_write_mem(int key, struct tty_struct *tty) ++{ ++ sysrq_input_return = return_write_mem; ++ sysrq_key_table = sysrq_input_key_table; ++} ++ ++static struct sysrq_key_op debug_write_mem = { ++ .handler = handle_write_mem, ++ .help_msg = "Writemem", ++ .action_msg = "Enter address-value:", ++}; ++ ++static void handle_next(int key, struct tty_struct *tty) ++{ ++ dump_mem(); ++} ++ ++static struct sysrq_key_op debug_next = { ++ .handler = handle_next, ++ .help_msg = "neXt", ++ .action_msg = "continuing", ++}; ++ ++static void handle_quit(int key, struct tty_struct *tty) ++{ ++ sysrq_key_table = sysrq_default_key_table; ++ console_loglevel = orig_console_loglevel; ++} ++ ++static struct sysrq_key_op debug_quit = { ++ .handler = handle_quit, ++ .help_msg = "Quit", ++ .action_msg = "Tnahk you for using debugger", ++}; ++ ++static struct sysrq_key_op *sysrq_debug_key_table[SYSRQ_KEY_TABLE_LENGTH] = { ++ [13] = &debug_dump_mem, /* d */ ++ [26] = &debug_quit, /* q */ ++ [27] = &debug_resolve, /* r */ ++ [32] = &debug_write_mem, /* w */ ++ [33] = &debug_next, /* x */ ++}; ++ ++static void sysrq_handle_debug(int key, struct tty_struct *tty) ++{ ++ orig_console_loglevel = console_loglevel; ++ console_loglevel = 8; ++ sysrq_key_table = sysrq_debug_key_table; ++ printk("Welcome sysrq debugging mode\n" ++ "Press H for help\n"); ++} ++ ++static struct sysrq_key_op sysrq_debug_op = { ++ .handler = sysrq_handle_debug, ++ .help_msg = "debuG", ++ .action_msg = "Select desired action", ++}; ++#endif ++ ++static struct sysrq_key_op *sysrq_default_key_table[SYSRQ_KEY_TABLE_LENGTH] = { + &sysrq_loglevel_op, /* 0 */ + &sysrq_loglevel_op, /* 1 */ + &sysrq_loglevel_op, /* 2 */ +@@ -336,7 +605,11 @@ + &sysrq_term_op, /* e */ + &sysrq_moom_op, /* f */ + /* g: May be registered by ppc for kgdb */ ++#ifdef CONFIG_SYSRQ_DEBUG ++ &sysrq_debug_op, /* g */ ++#else + NULL, /* g */ ++#endif + NULL, /* h */ + &sysrq_kill_op, /* i */ + NULL, /* j */ +@@ -358,9 +631,12 @@ + /* x: May be registered on ppc/powerpc for xmon */ + NULL, /* x */ + NULL, /* y */ +- NULL /* z */ ++ NULL, /* z */ ++ NULL, /* for debugger */ + }; + ++static struct sysrq_key_op **sysrq_key_table = sysrq_default_key_table; ++ + /* key2index calculation, -1 on invalid index */ + static int sysrq_key_table_key2index(int key) + { +@@ -370,6 +646,10 @@ + retval = key - '0'; + else if ((key >= 'a') && (key <= 'z')) + retval = key + 10 - 'a'; ++#ifdef CONFIG_SYSRQ_DEBUG ++ else if (key == 0 || key == 0x0d || key == '-') ++ retval = SYSRQ_KEY_TABLE_LENGTH - 1; ++#endif + else + retval = -1; + return retval; +@@ -411,7 +691,6 @@ + spin_lock_irqsave(&sysrq_key_table_lock, flags); + orig_log_level = console_loglevel; + console_loglevel = 7; +- printk(KERN_INFO "SysRq : "); + + op_p = __sysrq_get_key_op(key); + if (op_p) { +@@ -420,16 +699,17 @@ + * should not) and is the invoked operation enabled? + */ + if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { +- printk("%s\n", op_p->action_msg); ++ if (op_p->action_msg) ++ printk("%s\n", op_p->action_msg); + console_loglevel = orig_log_level; + op_p->handler(key, tty); + } else { + printk("This sysrq operation is disabled.\n"); + } + } else { +- printk("HELP : "); ++ printk("SysRq HELP : "); + /* Only print the help msg once per handler */ +- for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) { ++ for (i = 0; i < SYSRQ_KEY_TABLE_LENGTH; i++) { + if (sysrq_key_table[i]) { + int j; + +Index: kernel/drivers/char/tty_io.c +=================================================================== +--- kernel.orig/drivers/char/tty_io.c 2008-11-18 01:19:43.000000000 +0100 ++++ kernel/drivers/char/tty_io.c 2008-11-24 15:47:45.000000000 +0100 +@@ -94,6 +94,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -104,6 +106,7 @@ + + #include + #include ++#include + + #undef TTY_DEBUG_HANGUP + +@@ -128,6 +131,7 @@ + into this file */ + + LIST_HEAD(tty_drivers); /* linked list of tty drivers */ ++EXPORT_SYMBOL(tty_drivers); + + /* Mutex to protect creating and releasing a tty. This is shared with + vt.c for deeply disgusting hack reasons */ +@@ -138,6 +142,15 @@ + extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ + extern int pty_limit; /* Config limit on Unix98 ptys */ + static DEFINE_IDR(allocated_ptys); ++#ifdef CONFIG_VE ++#define __ve_allocated_ptys(ve) (*((ve)->allocated_ptys)) ++#define ve_allocated_ptys __ve_allocated_ptys(get_exec_env()) ++#define ve_ptm_driver (get_exec_env()->ptm_driver) ++#else ++#define __ve_allocated_ptys(ve) allocated_ptys ++#define ve_allocated_ptys allocated_ptys ++#define ve_ptm_driver ptm_driver ++#endif + static DECLARE_MUTEX(allocated_ptys_lock); + static int ptmx_open(struct inode *, struct file *); + #endif +@@ -172,9 +185,20 @@ + * Locking: none + */ + ++void prepare_tty(void) ++{ ++#ifdef CONFIG_VE ++ get_ve0()->allocated_ptys = &allocated_ptys; ++ /* ++ * in this case, tty_register_driver() setups ++ * owner_env correctly right from the bootup ++ */ ++#endif ++} ++ + static struct tty_struct *alloc_tty_struct(void) + { +- return kzalloc(sizeof(struct tty_struct), GFP_KERNEL); ++ return kzalloc(sizeof(struct tty_struct), GFP_KERNEL_UBC); + } + + static void tty_buffer_free_all(struct tty_struct *); +@@ -1148,9 +1172,29 @@ + if (device < base || device >= base + p->num) + continue; + *index = device - base; +- return p; ++#ifdef CONFIG_VE ++ if (in_interrupt()) ++ goto found; ++ if (p->major!=PTY_MASTER_MAJOR && p->major!=PTY_SLAVE_MAJOR ++#ifdef CONFIG_UNIX98_PTYS ++ && (p->majormajor>UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT-1) && ++ (p->majormajor>UNIX98_PTY_SLAVE_MAJOR+UNIX98_PTY_MAJOR_COUNT-1) ++#endif ++ ) ++ goto found; ++ if (ve_is_super(p->owner_env) && ve_is_super(get_exec_env())) ++ goto found; ++ if (!ve_accessible_strict(p->owner_env, get_exec_env())) ++ continue; ++#endif ++ goto found; + } + return NULL; ++ ++found: ++ return p; + } + + /** +@@ -1999,13 +2043,21 @@ + */ + + static int init_dev(struct tty_driver *driver, int idx, +- struct tty_struct **ret_tty) ++ struct tty_struct *i_tty, struct tty_struct **ret_tty) + { + struct tty_struct *tty, *o_tty; + struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc; + struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; ++ struct ve_struct * owner; + int retval = 0; + ++ owner = driver->owner_env; ++ ++ if (i_tty) { ++ tty = i_tty; ++ goto fast_track; ++ } ++ + /* check whether we're reopening an existing tty */ + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { + tty = devpts_get_tty(idx); +@@ -2054,6 +2106,7 @@ + tty->driver = driver; + tty->index = idx; + tty_line_name(driver, idx, tty->name); ++ tty->owner_env = owner; + + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { + tp_loc = &tty->termios; +@@ -2064,14 +2117,14 @@ + } + + if (!*tp_loc) { +- tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); ++ tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL_UBC); + if (!tp) + goto free_mem_out; + *tp = driver->init_termios; + } + + if (!*ltp_loc) { +- ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL); ++ ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL_UBC); + if (!ltp) + goto free_mem_out; + } +@@ -2084,6 +2137,7 @@ + o_tty->driver = driver->other; + o_tty->index = idx; + tty_line_name(driver->other, idx, o_tty->name); ++ o_tty->owner_env = owner; + + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { + o_tp_loc = &o_tty->termios; +@@ -2094,14 +2148,14 @@ + } + + if (!*o_tp_loc) { +- o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); ++ o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL_UBC); + if (!o_tp) + goto free_mem_out; + *o_tp = driver->other->init_termios; + } + + if (!*o_ltp_loc) { +- o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL); ++ o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL_UBC); + if (!o_ltp) + goto free_mem_out; + } +@@ -2118,6 +2172,10 @@ + *o_ltp_loc = o_ltp; + o_tty->termios = *o_tp_loc; + o_tty->termios_locked = *o_ltp_loc; ++#ifdef CONFIG_VE ++ if (driver->other->refcount == 0) ++ (void)get_ve(owner); ++#endif + driver->other->refcount++; + if (driver->subtype == PTY_TYPE_MASTER) + o_tty->count++; +@@ -2142,6 +2200,10 @@ + *ltp_loc = ltp; + tty->termios = *tp_loc; + tty->termios_locked = *ltp_loc; ++#ifdef CONFIG_VE ++ if (driver->refcount == 0) ++ (void)get_ve(owner); ++#endif + /* Compatibility until drivers always set this */ + tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); + tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); +@@ -2266,7 +2328,8 @@ + + tty->magic = 0; + tty->driver->refcount--; +- ++ if (tty->driver->refcount == 0) ++ put_ve(tty->owner_env); + file_list_lock(); + list_del_init(&tty->tty_files); + file_list_unlock(); +@@ -2312,7 +2375,10 @@ + int idx; + char buf[64]; + unsigned long flags; +- ++#ifdef CONFIG_UNIX98_PTYS ++ struct idr *idr_alloced; ++#endif ++ + tty = (struct tty_struct *)filp->private_data; + if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "release_dev")) + return; +@@ -2326,6 +2392,9 @@ + tty->driver->subtype == PTY_TYPE_MASTER); + devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; + o_tty = tty->link; ++#ifdef CONFIG_UNIX98_PTYS ++ idr_alloced = &__ve_allocated_ptys(tty->owner_env); ++#endif + + #ifdef TTY_PARANOIA_CHECK + if (idx < 0 || idx >= tty->driver->num) { +@@ -2572,7 +2641,7 @@ + /* Make this pty number available for reallocation */ + if (devpts) { + down(&allocated_ptys_lock); +- idr_remove(&allocated_ptys, idx); ++ idr_remove(idr_alloced, idx); + up(&allocated_ptys_lock); + } + #endif +@@ -2602,7 +2671,7 @@ + + static int tty_open(struct inode * inode, struct file * filp) + { +- struct tty_struct *tty; ++ struct tty_struct *tty, *c_tty; + int noctty, retval; + struct tty_driver *driver; + int index; +@@ -2615,6 +2684,7 @@ + noctty = filp->f_flags & O_NOCTTY; + index = -1; + retval = 0; ++ c_tty = NULL; + + mutex_lock(&tty_mutex); + +@@ -2626,6 +2696,7 @@ + } + driver = tty->driver; + index = tty->index; ++ c_tty = tty; + filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ + /* noctty = 1; */ + goto got_driver; +@@ -2633,6 +2704,12 @@ + #ifdef CONFIG_VT + if (device == MKDEV(TTY_MAJOR,0)) { + extern struct tty_driver *console_driver; ++#ifdef CONFIG_VE ++ if (!ve_is_super(get_exec_env())) { ++ mutex_unlock(&tty_mutex); ++ return -ENODEV; ++ } ++#endif + driver = console_driver; + index = fg_console; + noctty = 1; +@@ -2640,6 +2717,12 @@ + } + #endif + if (device == MKDEV(TTYAUX_MAJOR,1)) { ++#ifdef CONFIG_VE ++ if (!ve_is_super(get_exec_env())) { ++ mutex_unlock(&tty_mutex); ++ return -ENODEV; ++ } ++#endif + driver = console_device(&index); + if (driver) { + /* Don't let /dev/console block */ +@@ -2657,7 +2740,7 @@ + return -ENODEV; + } + got_driver: +- retval = init_dev(driver, index, &tty); ++ retval = init_dev(driver, index, c_tty, &tty); + mutex_unlock(&tty_mutex); + if (retval) + return retval; +@@ -2738,11 +2821,11 @@ + + /* find a device that is not in use. */ + down(&allocated_ptys_lock); +- if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) { ++ if (!idr_pre_get(&ve_allocated_ptys, GFP_KERNEL)) { + up(&allocated_ptys_lock); + return -ENOMEM; + } +- idr_ret = idr_get_new(&allocated_ptys, NULL, &index); ++ idr_ret = idr_get_new(&ve_allocated_ptys, NULL, &index); + if (idr_ret < 0) { + up(&allocated_ptys_lock); + if (idr_ret == -EAGAIN) +@@ -2750,14 +2833,14 @@ + return -EIO; + } + if (index >= pty_limit) { +- idr_remove(&allocated_ptys, index); ++ idr_remove(&ve_allocated_ptys, index); + up(&allocated_ptys_lock); + return -EIO; + } + up(&allocated_ptys_lock); + + mutex_lock(&tty_mutex); +- retval = init_dev(ptm_driver, index, &tty); ++ retval = init_dev(ve_ptm_driver, index, NULL, &tty); + mutex_unlock(&tty_mutex); + + if (retval) +@@ -2772,7 +2855,7 @@ + goto out1; + + check_tty_count(tty, "tty_open"); +- retval = ptm_driver->open(tty, filp); ++ retval = ve_ptm_driver->open(tty, filp); + if (!retval) { + tty_audit_opening(); + return 0; +@@ -2782,7 +2865,7 @@ + return retval; + out: + down(&allocated_ptys_lock); +- idr_remove(&allocated_ptys, index); ++ idr_remove(&ve_allocated_ptys, index); + up(&allocated_ptys_lock); + return retval; + } +@@ -2988,6 +3071,8 @@ + { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; ++ if (!ve_is_super(get_exec_env())) ++ return -EACCES; + if (file->f_op->write == redirected_tty_write) { + struct file *f; + spin_lock(&redirect_lock); +@@ -3536,7 +3621,7 @@ + /* Now kill any processes that happen to have the + * tty open. + */ +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + if (p->signal->tty == tty) { + printk(KERN_NOTICE "SAK: killed process %d" + " (%s): task_session_nr(p)==tty->session\n", +@@ -3568,7 +3653,7 @@ + spin_unlock(&p->files->file_lock); + } + task_unlock(p); +- } while_each_thread(g, p); ++ } while_each_thread_all(g, p); + read_unlock(&tasklist_lock); + #endif + } +@@ -3914,6 +3999,7 @@ + driver->put_char = tty_default_put_char; + + mutex_lock(&tty_mutex); ++ driver->owner_env = get_exec_env(); + list_add(&driver->tty_drivers, &tty_drivers); + mutex_unlock(&tty_mutex); + +@@ -4107,6 +4193,44 @@ + + vty_init(); + #endif ++ prepare_tty(); + return 0; + } + module_init(tty_init); ++ ++#ifdef CONFIG_UNIX98_PTYS ++struct class *init_ve_tty_class(void) ++{ ++ struct class * ve_tty_class; ++ struct class_device * ve_ptmx_dev_class; ++ ++ ve_tty_class = class_create(THIS_MODULE, "tty"); ++ if (IS_ERR(ve_tty_class)) ++ return ve_tty_class; ++ ++ ve_ptmx_dev_class = class_device_create(ve_tty_class, NULL, ++ MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); ++ if (IS_ERR(ve_ptmx_dev_class)) { ++ class_destroy(ve_tty_class); ++ return (struct class *)ve_ptmx_dev_class; ++ } ++ ++ return ve_tty_class; ++} ++ ++void fini_ve_tty_class(struct class *ve_tty_class) ++{ ++ class_device_destroy(ve_tty_class, MKDEV(TTYAUX_MAJOR, 2)); ++ class_destroy(ve_tty_class); ++} ++#else ++struct class *init_ve_tty_class(void) ++{ ++ return NULL; ++} ++void fini_ve_tty_class(struct class *ve_tty_class) ++{ ++} ++#endif ++EXPORT_SYMBOL(init_ve_tty_class); ++EXPORT_SYMBOL(fini_ve_tty_class); +Index: kernel/drivers/net/Makefile +=================================================================== +--- kernel.orig/drivers/net/Makefile 2008-11-18 01:19:44.000000000 +0100 ++++ kernel/drivers/net/Makefile 2008-11-24 15:47:45.000000000 +0100 +@@ -25,6 +25,10 @@ + obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o + ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o ucc_geth_ethtool.o + ++obj-$(CONFIG_VE_NETDEV) += vznetdev.o ++vznetdev-objs := open_vznet.o venet_core.o ++obj-$(CONFIG_VE_ETHDEV) += vzethdev.o ++ + # + # link order important here + # +Index: kernel/drivers/net/loopback.c +=================================================================== +--- kernel.orig/drivers/net/loopback.c 2008-11-18 01:19:44.000000000 +0100 ++++ kernel/drivers/net/loopback.c 2008-11-24 15:47:45.000000000 +0100 +@@ -136,6 +136,12 @@ + { + struct pcpu_lstats *pcpu_lstats, *lb_stats; + ++#ifdef CONFIG_VE ++ if (unlikely(get_exec_env()->disable_net)) { ++ kfree_skb(skb); ++ return 0; ++ } ++#endif + skb_orphan(skb); + + skb->protocol = eth_type_trans(skb,dev); +@@ -242,7 +248,8 @@ + | NETIF_F_NO_CSUM + | NETIF_F_HIGHDMA + | NETIF_F_LLTX +- | NETIF_F_NETNS_LOCAL; ++ | NETIF_F_NETNS_LOCAL ++ | NETIF_F_VIRTUAL; + dev->ethtool_ops = &loopback_ethtool_ops; + dev->header_ops = ð_header_ops; + dev->init = loopback_dev_init; +Index: kernel/drivers/net/open_vznet.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/drivers/net/open_vznet.c 2008-11-24 15:47:45.000000000 +0100 +@@ -0,0 +1,244 @@ ++/* ++ * open_vznet.c ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++/* ++ * Virtual Networking device used to change VE ownership on packets ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++void veip_stop(struct ve_struct *ve) ++{ ++ struct list_head *p, *tmp; ++ ++ write_lock_irq(&veip_hash_lock); ++ if (ve->veip == NULL) ++ goto unlock; ++ list_for_each_safe(p, tmp, &ve->veip->ip_lh) { ++ struct ip_entry_struct *ptr; ++ ptr = list_entry(p, struct ip_entry_struct, ve_list); ++ ptr->active_env = NULL; ++ list_del(&ptr->ve_list); ++ list_del(&ptr->ip_hash); ++ kfree(ptr); ++ } ++ veip_put(ve->veip); ++ ve->veip = NULL; ++ if (!ve_is_super(ve)) ++ module_put(THIS_MODULE); ++unlock: ++ write_unlock_irq(&veip_hash_lock); ++} ++ ++int veip_start(struct ve_struct *ve) ++{ ++ int err, get; ++ ++ err = 0; ++ write_lock_irq(&veip_hash_lock); ++ get = ve->veip == NULL; ++ ve->veip = veip_findcreate(ve->veid); ++ if (ve->veip == NULL) ++ err = -ENOMEM; ++ write_unlock_irq(&veip_hash_lock); ++ if (err == 0 && get && !ve_is_super(ve)) ++ __module_get(THIS_MODULE); ++ return err; ++} ++ ++int veip_entry_add(struct ve_struct *ve, struct ve_addr_struct *addr) ++{ ++ struct ip_entry_struct *entry, *found; ++ int err; ++ ++ entry = kzalloc(sizeof(struct ip_entry_struct), GFP_KERNEL); ++ if (entry == NULL) ++ return -ENOMEM; ++ ++ if (ve->veip == NULL) { ++ /* This can happen if we load venet AFTER ve was started */ ++ err = veip_start(ve); ++ if (err < 0) ++ goto out; ++ } ++ ++ write_lock_irq(&veip_hash_lock); ++ err = -EADDRINUSE; ++ found = venet_entry_lookup(addr); ++ if (found != NULL) ++ goto out_unlock; ++ ++ entry->active_env = ve; ++ entry->addr = *addr; ++ ip_entry_hash(entry, ve->veip); ++ ++ err = 0; ++ entry = NULL; ++out_unlock: ++ write_unlock_irq(&veip_hash_lock); ++out: ++ if (entry != NULL) ++ kfree(entry); ++ return err; ++} ++ ++int veip_entry_del(envid_t veid, struct ve_addr_struct *addr) ++{ ++ struct ip_entry_struct *found; ++ int err; ++ ++ err = -EADDRNOTAVAIL; ++ write_lock_irq(&veip_hash_lock); ++ found = venet_entry_lookup(addr); ++ if (found == NULL) ++ goto out; ++ if (found->active_env->veid != veid) ++ goto out; ++ ++ err = 0; ++ found->active_env = NULL; ++ ++ list_del(&found->ip_hash); ++ list_del(&found->ve_list); ++ kfree(found); ++out: ++ write_unlock_irq(&veip_hash_lock); ++ return err; ++} ++ ++static int skb_extract_addr(struct sk_buff *skb, ++ struct ve_addr_struct *addr, int dir) ++{ ++ switch (skb->protocol) { ++ case __constant_htons(ETH_P_IP): ++ addr->family = AF_INET; ++ addr->key[0] = 0; ++ addr->key[1] = 0; ++ addr->key[2] = 0; ++ addr->key[3] = (dir ? ip_hdr(skb)->daddr : ip_hdr(skb)->saddr); ++ return 0; ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++ case __constant_htons(ETH_P_IPV6): ++ addr->family = AF_INET6; ++ memcpy(&addr->key, dir ? ++ ipv6_hdr(skb)->daddr.s6_addr32 : ++ ipv6_hdr(skb)->saddr.s6_addr32, ++ sizeof(addr->key)); ++ return 0; ++#endif ++ } ++ ++ return -EAFNOSUPPORT; ++} ++ ++static struct ve_struct *venet_find_ve(struct sk_buff *skb, int dir) ++{ ++ struct ip_entry_struct *entry; ++ struct ve_addr_struct addr; ++ ++ if (skb_extract_addr(skb, &addr, dir) < 0) ++ return NULL; ++ ++ entry = venet_entry_lookup(&addr); ++ if (entry == NULL) ++ return NULL; ++ ++ return entry->active_env; ++} ++ ++int venet_change_skb_owner(struct sk_buff *skb) ++{ ++ struct ve_struct *ve, *ve_old; ++ ++ ve_old = skb->owner_env; ++ ++ read_lock(&veip_hash_lock); ++ if (!ve_is_super(ve_old)) { ++ /* from VE to host */ ++ ve = venet_find_ve(skb, 0); ++ if (ve == NULL) ++ goto out_drop; ++ if (!ve_accessible_strict(ve, ve_old)) ++ goto out_source; ++ skb->owner_env = get_ve0(); ++ } else { ++ /* from host to VE */ ++ ve = venet_find_ve(skb, 1); ++ if (ve == NULL) ++ goto out_drop; ++ skb->owner_env = ve; ++ } ++ read_unlock(&veip_hash_lock); ++ ++ return 0; ++ ++out_drop: ++ read_unlock(&veip_hash_lock); ++ return -ESRCH; ++ ++out_source: ++ read_unlock(&veip_hash_lock); ++ if (net_ratelimit() && skb->protocol == __constant_htons(ETH_P_IP)) { ++ printk(KERN_WARNING "Dropped packet, source wrong " ++ "veid=%u src-IP=%u.%u.%u.%u " ++ "dst-IP=%u.%u.%u.%u\n", ++ skb->owner_env->veid, ++ NIPQUAD(ip_hdr(skb)->saddr), ++ NIPQUAD(ip_hdr(skb)->daddr)); ++ } ++ return -EACCES; ++} ++ ++#ifdef CONFIG_PROC_FS ++int veip_seq_show(struct seq_file *m, void *v) ++{ ++ struct list_head *p; ++ struct ip_entry_struct *entry; ++ char s[40]; ++ ++ p = (struct list_head *)v; ++ if (p == ip_entry_hash_table) { ++ seq_puts(m, "Version: 2.5\n"); ++ return 0; ++ } ++ entry = list_entry(p, struct ip_entry_struct, ip_hash); ++ veaddr_print(s, sizeof(s), &entry->addr); ++ seq_printf(m, "%39s %10u\n", s, 0); ++ return 0; ++} ++#endif ++ ++__exit void veip_cleanup(void) ++{ ++ int i; ++ ++ write_lock_irq(&veip_hash_lock); ++ for (i = 0; i < VEIP_HASH_SZ; i++) ++ while (!list_empty(ip_entry_hash_table + i)) { ++ struct ip_entry_struct *entry; ++ ++ entry = list_first_entry(ip_entry_hash_table + i, ++ struct ip_entry_struct, ip_hash); ++ list_del(&entry->ip_hash); ++ kfree(entry); ++ } ++ write_unlock_irq(&veip_hash_lock); ++} ++ ++MODULE_AUTHOR("SWsoft "); ++MODULE_DESCRIPTION("Virtuozzo Virtual Network Device"); ++MODULE_LICENSE("GPL v2"); +Index: kernel/drivers/net/tun.c +=================================================================== +--- kernel.orig/drivers/net/tun.c 2008-11-18 01:19:44.000000000 +0100 ++++ kernel/drivers/net/tun.c 2008-11-24 15:47:45.000000000 +0100 +@@ -66,6 +66,7 @@ + + #include + #include ++#include + + #ifdef TUN_DEBUG + static int debug; +@@ -73,15 +74,18 @@ + + /* Network device part of the driver */ + +-static LIST_HEAD(tun_dev_list); ++LIST_HEAD(tun_dev_list); ++EXPORT_SYMBOL(tun_dev_list); ++ + static const struct ethtool_ops tun_ethtool_ops; + + /* Net device open. */ +-static int tun_net_open(struct net_device *dev) ++int tun_net_open(struct net_device *dev) + { + netif_start_queue(dev); + return 0; + } ++EXPORT_SYMBOL(tun_net_open); + + /* Net device close. */ + static int tun_net_close(struct net_device *dev) +@@ -94,6 +98,9 @@ + static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct tun_struct *tun = netdev_priv(dev); ++#if 0 ++ struct user_beancounter *ub; ++#endif + + DBG(KERN_INFO "%s: tun_net_xmit %d\n", tun->dev->name, skb->len); + +@@ -118,6 +125,24 @@ + } + } + ++ /* ++ * XXX this code is broken: ++ * See comment in dev_queue_xmit ++ */ ++#if 0 ++ ub = netdev_bc(dev)->exec_ub; ++ if (ub && (skb_bc(skb)->charged == 0)) { ++ unsigned long charge; ++ charge = skb_charge_fullsize(skb); ++ if (charge_beancounter(ub, UB_OTHERSOCKBUF, charge, 1)) ++ goto drop; ++ get_beancounter(ub); ++ skb_bc(skb)->ub = ub; ++ skb_bc(skb)->charged = charge; ++ skb_bc(skb)->resource = UB_OTHERSOCKBUF; ++ } ++#endif ++ + /* Queue packet */ + skb_queue_tail(&tun->readq, skb); + dev->trans_start = jiffies; +@@ -184,7 +209,7 @@ + } + + /* Initialize net device. */ +-static void tun_net_init(struct net_device *dev) ++void tun_net_init(struct net_device *dev) + { + struct tun_struct *tun = netdev_priv(dev); + +@@ -216,6 +241,7 @@ + break; + } + } ++EXPORT_SYMBOL(tun_net_init); + + /* Character device part */ + +@@ -415,11 +441,13 @@ + DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %s\n", + tun->dev->name, print_mac(mac, addr)); + ret = tun_put_user(tun, skb, (struct iovec *) iv, len); ++ /* skb will be uncharged in kfree_skb() */ + kfree_skb(skb); + break; + } else { + DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %s\n", + tun->dev->name, print_mac(mac, addr)); ++ /* skb will be uncharged in kfree_skb() */ + kfree_skb(skb); + continue; + } +@@ -431,7 +459,7 @@ + return ret; + } + +-static void tun_setup(struct net_device *dev) ++void tun_setup(struct net_device *dev) + { + struct tun_struct *tun = netdev_priv(dev); + +@@ -446,7 +474,9 @@ + dev->stop = tun_net_close; + dev->ethtool_ops = &tun_ethtool_ops; + dev->destructor = free_netdev; ++ dev->features |= NETIF_F_VIRTUAL; + } ++EXPORT_SYMBOL(tun_setup); + + static struct tun_struct *tun_get_by_name(const char *name) + { +@@ -454,8 +484,9 @@ + + ASSERT_RTNL(); + list_for_each_entry(tun, &tun_dev_list, list) { +- if (!strncmp(tun->dev->name, name, IFNAMSIZ)) +- return tun; ++ if (ve_accessible_strict(tun->dev->owner_env, get_exec_env()) && ++ !strncmp(tun->dev->name, name, IFNAMSIZ)) ++ return tun; + } + + return NULL; +@@ -477,7 +508,8 @@ + current->euid != tun->owner) || + (tun->group != -1 && + current->egid != tun->group)) && +- !capable(CAP_NET_ADMIN)) ++ !capable(CAP_NET_ADMIN) && ++ !capable(CAP_VE_NET_ADMIN)) + return -EPERM; + } + else if (__dev_get_by_name(&init_net, ifr->ifr_name)) +@@ -488,7 +520,7 @@ + + err = -EINVAL; + +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_NET_ADMIN) && !capable(CAP_VE_NET_ADMIN)) + return -EPERM; + + /* Set dev type */ +@@ -546,6 +578,7 @@ + + file->private_data = tun; + tun->attached = 1; ++ tun->bind_file = file; + + strcpy(ifr->ifr_name, tun->dev->name); + return 0; +@@ -603,6 +636,9 @@ + break; + + case TUNSETPERSIST: ++ /* prohibit persist mode inside VE */ ++ if (!ve_is_super(get_exec_env())) ++ return -EPERM; + /* Disable/Enable persist mode */ + if (arg) + tun->flags |= TUN_PERSIST; +@@ -734,12 +770,13 @@ + return 0; + } + +-static int tun_chr_open(struct inode *inode, struct file * file) ++int tun_chr_open(struct inode *inode, struct file * file) + { + DBG1(KERN_INFO "tunX: tun_chr_open\n"); + file->private_data = NULL; + return 0; + } ++EXPORT_SYMBOL(tun_chr_open); + + static int tun_chr_close(struct inode *inode, struct file *file) + { +Index: kernel/drivers/net/venet_core.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/drivers/net/venet_core.c 2008-11-24 15:47:45.000000000 +0100 +@@ -0,0 +1,826 @@ ++/* ++ * venet_core.c ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++/* ++ * Common part for Virtuozzo virtual network devices ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* For the statistics structure. */ ++#include /* For ARPHRD_ETHER */ ++#include ++#include ++#include ++#include ++#include ++ ++struct list_head ip_entry_hash_table[VEIP_HASH_SZ]; ++rwlock_t veip_hash_lock = RW_LOCK_UNLOCKED; ++LIST_HEAD(veip_lh); ++ ++struct venet_stats { ++ struct net_device_stats stats; ++ struct net_device_stats *real_stats; ++}; ++ ++static inline struct net_device_stats * ++venet_stats(struct net_device *dev, int cpu) ++{ ++ struct venet_stats *stats; ++ stats = (struct venet_stats*)dev->priv; ++ return per_cpu_ptr(stats->real_stats, cpu); ++} ++ ++ ++#define ip_entry_hash_function(ip) (ntohl(ip) & (VEIP_HASH_SZ - 1)) ++ ++void ip_entry_hash(struct ip_entry_struct *entry, struct veip_struct *veip) ++{ ++ list_add(&entry->ip_hash, ++ ip_entry_hash_table + ++ ip_entry_hash_function(entry->addr.key[3])); ++ list_add(&entry->ve_list, &veip->ip_lh); ++} ++ ++void veip_put(struct veip_struct *veip) ++{ ++ if (!list_empty(&veip->ip_lh)) ++ return; ++ if (!list_empty(&veip->src_lh)) ++ return; ++ if (!list_empty(&veip->dst_lh)) ++ return; ++ ++ list_del(&veip->list); ++ kfree(veip); ++} ++ ++struct ip_entry_struct *venet_entry_lookup(struct ve_addr_struct *addr) ++{ ++ struct ip_entry_struct *entry; ++ ++ list_for_each_entry (entry, ip_entry_hash_table + ++ ip_entry_hash_function(addr->key[3]), ip_hash) ++ if (memcmp(&entry->addr, addr, sizeof(*addr)) == 0) ++ return entry; ++ return NULL; ++} ++ ++struct veip_struct *veip_find(envid_t veid) ++{ ++ struct veip_struct *ptr; ++ ++ list_for_each_entry(ptr, &veip_lh, list) { ++ if (ptr->veid != veid) ++ continue; ++ return ptr; ++ } ++ return NULL; ++} ++ ++struct veip_struct *veip_findcreate(envid_t veid) ++{ ++ struct veip_struct *ptr; ++ ++ ptr = veip_find(veid); ++ if (ptr != NULL) ++ return ptr; ++ ++ ptr = kmalloc(sizeof(struct veip_struct), GFP_ATOMIC); ++ if (ptr == NULL) ++ return NULL; ++ memset(ptr, 0, sizeof(struct veip_struct)); ++ INIT_LIST_HEAD(&ptr->ip_lh); ++ INIT_LIST_HEAD(&ptr->src_lh); ++ INIT_LIST_HEAD(&ptr->dst_lh); ++ ptr->veid = veid; ++ list_add(&ptr->list, &veip_lh); ++ return ptr; ++} ++ ++static int convert_sockaddr(struct sockaddr *addr, int addrlen, ++ struct ve_addr_struct *veaddr) ++{ ++ int err; ++ ++ switch (addr->sa_family) { ++ case AF_INET: { ++ struct sockaddr_in *sin; ++ ++ err = -EINVAL; ++ if (addrlen != sizeof(struct sockaddr_in)) ++ break; ++ ++ err = 0; ++ sin = (struct sockaddr_in *)addr; ++ veaddr->family = AF_INET; ++ veaddr->key[0] = 0; ++ veaddr->key[1] = 0; ++ veaddr->key[2] = 0; ++ veaddr->key[3] = sin->sin_addr.s_addr; ++ break; ++ } ++ case AF_INET6: { ++ struct sockaddr_in6 *sin; ++ ++ err = -EINVAL; ++ if (addrlen != sizeof(struct sockaddr_in6)) ++ break; ++ ++ err = 0; ++ sin = (struct sockaddr_in6 *)addr; ++ veaddr->family = AF_INET6; ++ memcpy(veaddr->key, &sin->sin6_addr, sizeof(veaddr->key)); ++ break; ++ } ++ default: ++ err = -EAFNOSUPPORT; ++ } ++ return err; ++} ++ ++int sockaddr_to_veaddr(struct sockaddr __user *uaddr, int addrlen, ++ struct ve_addr_struct *veaddr) ++{ ++ int err; ++ char addr[MAX_SOCK_ADDR]; ++ ++ err = move_addr_to_kernel(uaddr, addrlen, &addr); ++ if (err < 0) ++ goto out; ++ ++ err = convert_sockaddr((struct sockaddr *)&addr, addrlen, veaddr); ++out: ++ return err; ++} ++ ++void veaddr_print(char *str, int len, struct ve_addr_struct *a) ++{ ++ if (a->family == AF_INET) ++ snprintf(str, len, "%u.%u.%u.%u", NIPQUAD(a->key[3])); ++ else ++ snprintf(str, len, "%x:%x:%x:%x:%x:%x:%x:%x", ++ ntohl(a->key[0])>>16, ntohl(a->key[0])&0xFFFF, ++ ntohl(a->key[1])>>16, ntohl(a->key[1])&0xFFFF, ++ ntohl(a->key[2])>>16, ntohl(a->key[2])&0xFFFF, ++ ntohl(a->key[3])>>16, ntohl(a->key[3])&0xFFFF ++ ); ++} ++ ++/* ++ * Device functions ++ */ ++ ++static int venet_open(struct net_device *dev) ++{ ++ if (!ve_is_super(get_exec_env()) && !try_module_get(THIS_MODULE)) ++ return -EBUSY; ++ return 0; ++} ++ ++static int venet_close(struct net_device *master) ++{ ++ if (!ve_is_super(get_exec_env())) ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static void venet_destructor(struct net_device *dev) ++{ ++ struct venet_stats *stats = (struct venet_stats *)dev->priv; ++ if (stats == NULL) ++ return; ++ free_percpu(stats->real_stats); ++ kfree(stats); ++ dev->priv = NULL; ++} ++ ++/* ++ * The higher levels take care of making this non-reentrant (it's ++ * called with bh's disabled). ++ */ ++static int venet_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct net_device_stats *stats; ++ struct net_device *rcv = NULL; ++ int length; ++ ++ stats = venet_stats(dev, smp_processor_id()); ++ if (unlikely(get_exec_env()->disable_net)) ++ goto outf; ++ ++ if (skb->protocol == __constant_htons(ETH_P_IP)) { ++ struct iphdr *iph; ++ iph = ip_hdr(skb); ++ if (MULTICAST(iph->daddr)) ++ goto outf; ++ } else if (skb->protocol == __constant_htons(ETH_P_IPV6)) { ++ struct ipv6hdr *ip6h; ++ ip6h = ipv6_hdr(skb); ++ if (ipv6_addr_is_multicast(&ip6h->daddr)) ++ goto outf; ++ skb_orphan(skb); ++ } else { ++ goto outf; ++ } ++ ++ if (venet_change_skb_owner(skb) < 0) ++ goto outf; ++ ++ if (unlikely(skb->owner_env->disable_net)) ++ goto outf; ++ ++ rcv = skb->owner_env->_venet_dev; ++ if (!rcv) ++ /* VE going down */ ++ goto outf; ++ ++ dev_hold(rcv); ++ ++ if (!(rcv->flags & IFF_UP)) { ++ /* Target VE does not want to receive packets */ ++ dev_put(rcv); ++ goto outf; ++ } ++ ++ skb->pkt_type = PACKET_HOST; ++ skb->dev = rcv; ++ ++ skb_reset_mac_header(skb); ++ memset(skb->data - dev->hard_header_len, 0, dev->hard_header_len); ++ ++ dst_release(skb->dst); ++ skb->dst = NULL; ++#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) ++ nf_conntrack_put(skb->nfct); ++ skb->nfct = NULL; ++#endif ++ length = skb->len; ++ ++ netif_rx(skb); ++ ++ stats->tx_bytes += length; ++ stats->tx_packets++; ++ if (rcv) { ++ struct net_device_stats *rcv_stats; ++ ++ rcv_stats = venet_stats(rcv, smp_processor_id()); ++ rcv_stats->rx_bytes += length; ++ rcv_stats->rx_packets++; ++ dev_put(rcv); ++ } ++ ++ return 0; ++ ++outf: ++ kfree_skb(skb); ++ ++stats->tx_dropped; ++ return 0; ++} ++ ++static struct net_device_stats *get_stats(struct net_device *dev) ++{ ++ int i; ++ struct venet_stats *stats; ++ ++ stats = (struct venet_stats *)dev->priv; ++ memset(&stats->stats, 0, sizeof(struct net_device_stats)); ++ for (i=0; i < NR_CPUS; i++) { ++ struct net_device_stats *dev_stats; ++ ++ if (!cpu_possible(i)) ++ continue; ++ dev_stats = venet_stats(dev, i); ++ stats->stats.rx_bytes += dev_stats->rx_bytes; ++ stats->stats.tx_bytes += dev_stats->tx_bytes; ++ stats->stats.rx_packets += dev_stats->rx_packets; ++ stats->stats.tx_packets += dev_stats->tx_packets; ++ } ++ ++ return &stats->stats; ++} ++ ++/* Initialize the rest of the LOOPBACK device. */ ++int venet_init_dev(struct net_device *dev) ++{ ++ struct venet_stats *stats; ++ ++ dev->hard_start_xmit = venet_xmit; ++ stats = kzalloc(sizeof(struct venet_stats), GFP_KERNEL); ++ if (stats == NULL) ++ goto fail; ++ stats->real_stats = alloc_percpu(struct net_device_stats); ++ if (stats->real_stats == NULL) ++ goto fail_free; ++ dev->priv = stats; ++ ++ dev->get_stats = get_stats; ++ dev->open = venet_open; ++ dev->stop = venet_close; ++ dev->destructor = venet_destructor; ++ ++ /* ++ * Fill in the generic fields of the device structure. ++ */ ++ dev->type = ARPHRD_VOID; ++ dev->hard_header_len = ETH_HLEN; ++ dev->mtu = 1500; /* eth_mtu */ ++ dev->tx_queue_len = 0; ++ ++ memset(dev->broadcast, 0xFF, ETH_ALEN); ++ ++ /* New-style flags. */ ++ dev->flags = IFF_BROADCAST|IFF_NOARP|IFF_POINTOPOINT; ++ return 0; ++ ++fail_free: ++ kfree(stats); ++fail: ++ return -ENOMEM; ++} ++ ++static int ++venet_set_op(struct net_device *dev, u32 data, ++ int (*fop)(struct net_device *, u32)) ++{ ++ ++ struct ve_struct *ve; ++ int ret = 0; ++ ++ read_lock(&ve_list_lock); ++ for_each_ve(ve) { ++ struct ve_struct *ve_old; ++ ++ ve_old = set_exec_env(ve); ++ read_lock(&dev_base_lock); ++ for_each_netdev(ve->ve_ns->net_ns, dev) { ++ if (dev->hard_start_xmit == venet_xmit) ++ ret = fop(dev, data); ++ } ++ read_unlock(&dev_base_lock); ++ set_exec_env(ve_old); ++ ++ if (ret < 0) ++ break; ++ } ++ read_unlock(&ve_list_lock); ++ return ret; ++} ++ ++static unsigned long common_features; ++ ++static int venet_op_set_sg(struct net_device *dev, u32 data) ++{ ++ if (!ve_is_super(get_exec_env())) ++ return -EPERM; ++ ++ if (data) ++ common_features |= NETIF_F_SG; ++ else ++ common_features &= ~NETIF_F_SG; ++ ++ return venet_set_op(dev, data, ethtool_op_set_sg); ++} ++ ++static int venet_op_set_tx_csum(struct net_device *dev, u32 data) ++{ ++ if (!ve_is_super(get_exec_env())) ++ return -EPERM; ++ ++ if (data) ++ common_features |= NETIF_F_IP_CSUM; ++ else ++ common_features &= ~NETIF_F_IP_CSUM; ++ ++ return venet_set_op(dev, data, ethtool_op_set_tx_csum); ++} ++ ++#define venet_op_set_rx_csum venet_op_set_tx_csum ++ ++static struct ethtool_ops venet_ethtool_ops = { ++ .get_sg = ethtool_op_get_sg, ++ .set_sg = venet_op_set_sg, ++ .get_tx_csum = ethtool_op_get_tx_csum, ++ .set_tx_csum = venet_op_set_tx_csum, ++ .get_rx_csum = ethtool_op_get_tx_csum, ++ .set_rx_csum = venet_op_set_rx_csum, ++ .get_tso = ethtool_op_get_tso, ++}; ++ ++static void venet_setup(struct net_device *dev) ++{ ++ dev->init = venet_init_dev; ++ /* ++ * No other features, as they are: ++ * - checksumming is required, and nobody else will done our job ++ */ ++ dev->features |= NETIF_F_VENET | NETIF_F_VIRTUAL | NETIF_F_LLTX | ++ NETIF_F_HIGHDMA | NETIF_F_VLAN_CHALLENGED; ++ ++ dev->features |= common_features; ++ ++ SET_ETHTOOL_OPS(dev, &venet_ethtool_ops); ++} ++ ++#ifdef CONFIG_PROC_FS ++static int veinfo_seq_show(struct seq_file *m, void *v) ++{ ++ struct ve_struct *ve; ++ struct ip_entry_struct *entry; ++ ++ ve = list_entry((struct list_head *)v, struct ve_struct, ve_list); ++ ++ seq_printf(m, "%10u %5u %5u", ve->veid, ++ ve->class_id, atomic_read(&ve->pcounter)); ++ read_lock(&veip_hash_lock); ++ if (ve->veip == NULL) ++ goto unlock; ++ list_for_each_entry (entry, &ve->veip->ip_lh, ve_list) { ++ char addr[40]; ++ ++ if (entry->active_env == NULL) ++ continue; ++ ++ veaddr_print(addr, sizeof(addr), &entry->addr); ++ if (entry->addr.family == AF_INET) ++ seq_printf(m, " %15s", addr); ++ else ++ seq_printf(m, " %39s", addr); ++ } ++unlock: ++ read_unlock(&veip_hash_lock); ++ seq_putc(m, '\n'); ++ return 0; ++} ++ ++static void *ve_seq_start(struct seq_file *m, loff_t *pos) ++{ ++ struct ve_struct *curve; ++ struct list_head *entry; ++ loff_t l; ++ ++ curve = get_exec_env(); ++ read_lock(&ve_list_lock); ++ if (!ve_is_super(curve)) { ++ if (*pos != 0) ++ return NULL; ++ return curve; ++ } ++ ++ l = *pos; ++ list_for_each(entry, &ve_list_head) { ++ if (l == 0) ++ return entry; ++ l--; ++ } ++ return NULL; ++} ++ ++static void *ve_seq_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ struct list_head *entry; ++ ++ entry = (struct list_head *)v; ++ if (!ve_is_super(get_exec_env())) ++ return NULL; ++ (*pos)++; ++ return entry->next == &ve_list_head ? NULL : entry->next; ++} ++ ++static void ve_seq_stop(struct seq_file *m, void *v) ++{ ++ read_unlock(&ve_list_lock); ++} ++ ++ ++static struct seq_operations veinfo_seq_op = { ++ .start = ve_seq_start, ++ .next = ve_seq_next, ++ .stop = ve_seq_stop, ++ .show = veinfo_seq_show, ++}; ++ ++static int veinfo_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &veinfo_seq_op); ++} ++ ++static struct file_operations proc_veinfo_operations = { ++ .open = veinfo_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++static void *veip_seq_start(struct seq_file *m, loff_t *pos) ++{ ++ loff_t l; ++ struct list_head *p; ++ int i; ++ ++ l = *pos; ++ write_lock_irq(&veip_hash_lock); ++ if (l == 0) ++ return ip_entry_hash_table; ++ for (i = 0; i < VEIP_HASH_SZ; i++) { ++ list_for_each(p, ip_entry_hash_table + i) { ++ if (--l == 0) ++ return p; ++ } ++ } ++ return NULL; ++} ++ ++static void *veip_seq_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ struct list_head *p; ++ ++ p = (struct list_head *)v; ++ while (1) { ++ p = p->next; ++ if (p < ip_entry_hash_table || ++ p >= ip_entry_hash_table + VEIP_HASH_SZ) { ++ (*pos)++; ++ return p; ++ } ++ if (++p >= ip_entry_hash_table + VEIP_HASH_SZ) ++ return NULL; ++ } ++ return NULL; ++} ++ ++static void veip_seq_stop(struct seq_file *m, void *v) ++{ ++ write_unlock_irq(&veip_hash_lock); ++} ++ ++static struct seq_operations veip_seq_op = { ++ .start = veip_seq_start, ++ .next = veip_seq_next, ++ .stop = veip_seq_stop, ++ .show = veip_seq_show, ++}; ++ ++static int veip_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &veip_seq_op); ++} ++ ++static struct file_operations proc_veip_operations = { ++ .open = veip_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++#endif ++ ++static int real_ve_ip_map(envid_t veid, int op, struct sockaddr __user *uaddr, ++ int addrlen) ++{ ++ int err; ++ struct ve_struct *ve; ++ struct ve_addr_struct addr; ++ ++ err = -EPERM; ++ if (!capable(CAP_SETVEID)) ++ goto out; ++ ++ err = sockaddr_to_veaddr(uaddr, addrlen, &addr); ++ if (err < 0) ++ goto out; ++ ++ switch (op) ++ { ++ case VE_IP_ADD: ++ ve = get_ve_by_id(veid); ++ err = -ESRCH; ++ if (!ve) ++ goto out; ++ ++ down_read(&ve->op_sem); ++ if (ve->is_running) ++ err = veip_entry_add(ve, &addr); ++ up_read(&ve->op_sem); ++ put_ve(ve); ++ break; ++ ++ case VE_IP_DEL: ++ err = veip_entry_del(veid, &addr); ++ break; ++ default: ++ err = -EINVAL; ++ } ++ ++out: ++ return err; ++} ++ ++int venet_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int err; ++ ++ err = -ENOTTY; ++ switch(cmd) { ++ case VENETCTL_VE_IP_MAP: { ++ struct vzctl_ve_ip_map s; ++ err = -EFAULT; ++ if (copy_from_user(&s, (void __user *)arg, sizeof(s))) ++ break; ++ err = real_ve_ip_map(s.veid, s.op, s.addr, s.addrlen); ++ break; ++ } ++ } ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++int compat_venet_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int err; ++ ++ switch(cmd) { ++ case VENETCTL_COMPAT_VE_IP_MAP: { ++ struct compat_vzctl_ve_ip_map cs; ++ ++ err = -EFAULT; ++ if (copy_from_user(&cs, (void *)arg, sizeof(cs))) ++ break; ++ ++ err = real_ve_ip_map(cs.veid, cs.op, compat_ptr(cs.addr), ++ cs.addrlen); ++ break; ++ } ++ default: ++ err = venet_ioctl(file, cmd, arg); ++ break; ++ } ++ return err; ++} ++#endif ++ ++static struct vzioctlinfo venetcalls = { ++ .type = VENETCTLTYPE, ++ .ioctl = venet_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = compat_venet_ioctl, ++#endif ++ .owner = THIS_MODULE, ++}; ++ ++int venet_dev_start(struct ve_struct *ve) ++{ ++ struct net_device *dev_venet; ++ int err; ++ ++ dev_venet = alloc_netdev(0, "venet%d", venet_setup); ++ if (!dev_venet) ++ return -ENOMEM; ++ dev_venet->nd_net = ve->ve_ns->net_ns; ++ err = dev_alloc_name(dev_venet, dev_venet->name); ++ if (err<0) ++ goto err; ++ if ((err = register_netdev(dev_venet)) != 0) ++ goto err; ++ ve->_venet_dev = dev_venet; ++ return 0; ++err: ++ free_netdev(dev_venet); ++ printk(KERN_ERR "VENET initialization error err=%d\n", err); ++ return err; ++} ++ ++static int venet_start(void *data) ++{ ++ struct ve_struct *env; ++ int err; ++ ++ env = (struct ve_struct *)data; ++ if (env->veip) ++ return -EEXIST; ++ ++ err = veip_start(env); ++ if (err != 0) ++ return err; ++ ++ err = venet_dev_start(env); ++ if (err) ++ goto err_free; ++ return 0; ++ ++err_free: ++ veip_stop(env); ++ return err; ++} ++ ++static void venet_stop(void *data) ++{ ++ struct ve_struct *env; ++ struct net_device *dev; ++ ++ env = (struct ve_struct *)data; ++ veip_stop(env); ++ ++ dev = env->_venet_dev; ++ if (dev == NULL) ++ return; ++ ++ unregister_netdev(dev); ++ env->_venet_dev = NULL; ++ free_netdev(dev); ++} ++ ++static struct ve_hook venet_ve_hook = { ++ .init = venet_start, ++ .fini = venet_stop, ++ .owner = THIS_MODULE, ++ .priority = HOOK_PRIO_NET, ++}; ++ ++__init int venet_init(void) ++{ ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *de; ++#endif ++ int i, err; ++ ++ if (get_ve0()->_venet_dev != NULL) ++ return -EEXIST; ++ ++ for (i = 0; i < VEIP_HASH_SZ; i++) ++ INIT_LIST_HEAD(ip_entry_hash_table + i); ++ ++ err = venet_start(get_ve0()); ++ if (err) ++ return err; ++ ++#ifdef CONFIG_PROC_FS ++ de = create_proc_glob_entry_mod("vz/veinfo", ++ S_IFREG|S_IRUSR, NULL, THIS_MODULE); ++ if (de) ++ de->proc_fops = &proc_veinfo_operations; ++ else ++ printk(KERN_WARNING "venet: can't make veinfo proc entry\n"); ++ ++ de = create_proc_entry_mod("vz/veip", ++ S_IFREG|S_IRUSR, NULL, THIS_MODULE); ++ if (de) ++ de->proc_fops = &proc_veip_operations; ++ else ++ printk(KERN_WARNING "venet: can't make veip proc entry\n"); ++#endif ++ ++ ve_hook_register(VE_SS_CHAIN, &venet_ve_hook); ++ vzioctl_register(&venetcalls); ++ return 0; ++} ++ ++__exit void venet_exit(void) ++{ ++ vzioctl_unregister(&venetcalls); ++ ve_hook_unregister(&venet_ve_hook); ++ ++#ifdef CONFIG_PROC_FS ++ remove_proc_entry("vz/veip", NULL); ++ remove_proc_entry("vz/veinfo", NULL); ++#endif ++ venet_stop(get_ve0()); ++ veip_cleanup(); ++} ++ ++module_init(venet_init); ++module_exit(venet_exit); +Index: kernel/drivers/net/vzethdev.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/drivers/net/vzethdev.c 2008-11-24 15:47:45.000000000 +0100 +@@ -0,0 +1,729 @@ ++/* ++ * veth.c ++ * ++ * Copyright (C) 2006 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++/* ++ * Virtual ethernet device used to change VE ownership on packets ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* For the statistics structure. */ ++#include /* For ARPHRD_ETHER */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++struct veth_struct ++{ ++ struct net_device_stats stats; ++ struct net_device *pair; ++ struct list_head hwaddr_list; ++ struct net_device_stats *real_stats; ++ int allow_mac_change; ++}; ++ ++static LIST_HEAD(veth_hwaddr_list); ++static DEFINE_RWLOCK(ve_hwaddr_lock); ++static DECLARE_MUTEX(hwaddr_sem); ++ ++#define veth_from_netdev(dev) \ ++ ((struct veth_struct *)(netdev_priv(dev))) ++static inline struct net_device * veth_to_netdev(struct veth_struct *veth) ++{ ++ return (struct net_device *)((char *)veth - ((sizeof(struct net_device) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST)); ++} ++ ++static inline struct net_device_stats * ++veth_stats(struct net_device *dev, int cpuid) ++{ ++ return per_cpu_ptr(veth_from_netdev(dev)->real_stats, cpuid); ++} ++ ++struct net_device * veth_dev_start(char *dev_addr, char *name); ++ ++struct veth_struct *hwaddr_entry_lookup(char *name) ++{ ++ struct veth_struct *entry; ++ ++ list_for_each_entry(entry, &veth_hwaddr_list, hwaddr_list) { ++ BUG_ON(entry->pair == NULL); ++ if (strncmp(name, entry->pair->name, IFNAMSIZ) == 0) ++ return entry; ++ } ++ return NULL; ++} ++ ++int veth_entry_add(struct ve_struct *ve, char *dev_addr, char *name, ++ char *dev_addr_ve, char *name_ve) ++{ ++ struct net_device *dev_ve; ++ struct net_device *dev_ve0; ++ struct ve_struct *old_env; ++ char dev_name[IFNAMSIZ]; ++ int err; ++ ++ down(&hwaddr_sem); ++ ++ if (name[0] == '\0') ++ snprintf(dev_name, sizeof(dev_name), "vz%d.%%d", ve->veid); ++ else { ++ memcpy(dev_name, name, IFNAMSIZ - 1); ++ dev_name[IFNAMSIZ - 1] = '\0'; ++ } ++ dev_ve0 = veth_dev_start(dev_addr, dev_name); ++ if (IS_ERR(dev_ve0)) { ++ err = PTR_ERR(dev_ve0); ++ goto err; ++ } ++ ++ old_env = set_exec_env(ve); ++ if (name_ve[0] == '\0') ++ sprintf(dev_name, "eth%%d"); ++ else { ++ memcpy(dev_name, name_ve, IFNAMSIZ - 1); ++ dev_name[IFNAMSIZ - 1] = '\0'; ++ } ++ dev_ve = veth_dev_start(dev_addr_ve, dev_name); ++ if (IS_ERR(dev_ve)) { ++ err = PTR_ERR(dev_ve); ++ goto err_ve; ++ } ++ set_exec_env(old_env); ++ veth_from_netdev(dev_ve)->pair = dev_ve0; ++ veth_from_netdev(dev_ve0)->pair = dev_ve; ++ ++ write_lock(&ve_hwaddr_lock); ++ list_add(&(veth_from_netdev(dev_ve)->hwaddr_list), &veth_hwaddr_list); ++ write_unlock(&ve_hwaddr_lock); ++ ++ up(&hwaddr_sem); ++ return 0; ++ ++err_ve: ++ set_exec_env(old_env); ++ unregister_netdev(dev_ve0); ++err: ++ up(&hwaddr_sem); ++ return err; ++} ++ ++void veth_pair_del(struct ve_struct *env, struct veth_struct *entry) ++{ ++ struct net_device *dev; ++ struct ve_struct *old_env; ++ ++ write_lock(&ve_hwaddr_lock); ++ list_del(&entry->hwaddr_list); ++ write_unlock(&ve_hwaddr_lock); ++ ++ dev = entry->pair; ++ BUG_ON(entry->pair == NULL); ++ ++ veth_from_netdev(dev)->pair = NULL; ++ entry->pair = NULL; ++ rtnl_lock(); ++ old_env = set_exec_env(dev->owner_env); ++ dev_close(dev); ++ ++ /* ++ * Now device from VE0 does not send or receive anything, ++ * i.e. dev->hard_start_xmit won't be called. ++ */ ++ set_exec_env(env); ++ unregister_netdevice(veth_to_netdev(entry)); ++ set_exec_env(dev->owner_env); ++ unregister_netdevice(dev); ++ set_exec_env(old_env); ++ rtnl_unlock(); ++} ++ ++int veth_entry_del(struct ve_struct *ve, char *name) ++{ ++ struct veth_struct *found; ++ int err; ++ ++ err = -ENODEV; ++ down(&hwaddr_sem); ++ found = hwaddr_entry_lookup(name); ++ if (found == NULL) ++ goto out; ++ if (veth_to_netdev(found)->owner_env != ve) ++ goto out; ++ ++ err = 0; ++ veth_pair_del(ve, found); ++ ++out: ++ up(&hwaddr_sem); ++ return err; ++} ++ ++int veth_allow_change_mac(envid_t veid, char *name, int allow) ++{ ++ struct ve_struct *ve; ++ struct veth_struct *found; ++ int err; ++ ++ err = -ESRCH; ++ ve = get_ve_by_id(veid); ++ if (!ve) ++ return err; ++ ++ down_read(&ve->op_sem); ++ if (!ve->is_running) ++ goto out_ve; ++ err = -ENODEV; ++ down(&hwaddr_sem); ++ found = hwaddr_entry_lookup(name); ++ if (found == NULL) ++ goto out_sem; ++ if (veth_to_netdev(found)->owner_env != ve) ++ goto out_sem; ++ ++ err = 0; ++ found->allow_mac_change = allow; ++ ++out_sem: ++ up(&hwaddr_sem); ++out_ve: ++ up_read(&ve->op_sem); ++ put_ve(ve); ++ return err; ++} ++ ++/* ++ * Device functions ++ */ ++ ++static int veth_open(struct net_device *dev) ++{ ++ return 0; ++} ++ ++static int veth_close(struct net_device *master) ++{ ++ return 0; ++} ++ ++static void veth_destructor(struct net_device *dev) ++{ ++ free_percpu(veth_from_netdev(dev)->real_stats); ++ free_netdev(dev); ++} ++ ++static struct net_device_stats *get_stats(struct net_device *dev) ++{ ++ int i; ++ struct net_device_stats *stats; ++ ++ stats = &veth_from_netdev(dev)->stats; ++ memset(stats, 0, sizeof(struct net_device_stats)); ++ for (i = 0; i < NR_CPUS; i++) { ++ struct net_device_stats *dev_stats; ++ ++ if (!cpu_possible(i)) ++ continue; ++ dev_stats = veth_stats(dev, i); ++ stats->rx_bytes += dev_stats->rx_bytes; ++ stats->tx_bytes += dev_stats->tx_bytes; ++ stats->rx_packets += dev_stats->rx_packets; ++ stats->tx_packets += dev_stats->tx_packets; ++ } ++ ++ return stats; ++} ++ ++/* ++ * The higher levels take care of making this non-reentrant (it's ++ * called with bh's disabled). ++ */ ++static int veth_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct net_device_stats *stats; ++ struct net_device *rcv = NULL; ++ struct veth_struct *entry; ++ int length; ++ ++ stats = veth_stats(dev, smp_processor_id()); ++ if (unlikely(get_exec_env()->disable_net)) ++ goto outf; ++ ++ entry = veth_from_netdev(dev); ++ rcv = entry->pair; ++ if (!rcv) ++ /* VE going down */ ++ goto outf; ++ ++ if (!(rcv->flags & IFF_UP)) { ++ /* Target VE does not want to receive packets */ ++ goto outf; ++ } ++ ++ if (unlikely(rcv->owner_env->disable_net)) ++ goto outf; ++ /* Filtering */ ++ if (ve_is_super(dev->owner_env) && ++ !veth_from_netdev(rcv)->allow_mac_change) { ++ /* from VE0 to VEX */ ++ if (ve_is_super(rcv->owner_env)) ++ goto out; ++ if (is_multicast_ether_addr( ++ ((struct ethhdr *)skb->data)->h_dest)) ++ goto out; ++ if (compare_ether_addr(((struct ethhdr *)skb->data)->h_dest, ++ rcv->dev_addr)) ++ goto outf; ++ } else if (!ve_is_super(dev->owner_env) && ++ !entry->allow_mac_change) { ++ /* from VE to VE0 */ ++ if (compare_ether_addr(((struct ethhdr *)skb->data)->h_source, ++ dev->dev_addr)) ++ goto outf; ++ } ++ ++out: ++ skb->owner_env = rcv->owner_env; ++ ++ skb->dev = rcv; ++ skb->pkt_type = PACKET_HOST; ++ skb->protocol = eth_type_trans(skb, rcv); ++ ++ if (skb->protocol != __constant_htons(ETH_P_IP)) ++ skb_orphan(skb); ++ ++ dst_release(skb->dst); ++ skb->dst = NULL; ++#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) ++ nf_conntrack_put(skb->nfct); ++ skb->nfct = NULL; ++#endif ++ length = skb->len; ++ ++ netif_rx(skb); ++ ++ stats->tx_bytes += length; ++ stats->tx_packets++; ++ if (rcv) { ++ struct net_device_stats *rcv_stats; ++ rcv_stats = veth_stats(rcv, smp_processor_id()); ++ rcv_stats->rx_bytes += length; ++ rcv_stats->rx_packets++; ++ } ++ ++ return 0; ++ ++outf: ++ kfree_skb(skb); ++ stats->tx_dropped++; ++ return 0; ++} ++ ++static int veth_set_mac(struct net_device *dev, void *p) ++{ ++ struct sockaddr *addr = p; ++ ++ if (!ve_is_super(dev->owner_env) && ++ !veth_from_netdev(dev)->allow_mac_change) ++ return -EPERM; ++ if (netif_running(dev)) ++ return -EBUSY; ++ if (!is_valid_ether_addr(addr->sa_data)) ++ return -EADDRNOTAVAIL; ++ ++ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); ++ ++ return 0; ++} ++ ++int veth_init_dev(struct net_device *dev) ++{ ++ dev->hard_start_xmit = veth_xmit; ++ dev->get_stats = get_stats; ++ dev->open = veth_open; ++ dev->stop = veth_close; ++ dev->destructor = veth_destructor; ++ ++ ether_setup(dev); ++ dev->set_mac_address = veth_set_mac; ++ ++ /* remove setted by ether_setup() handler */ ++ dev->change_mtu = NULL; ++ ++ dev->tx_queue_len = 0; ++ ++ veth_from_netdev(dev)->real_stats = ++ alloc_percpu(struct net_device_stats); ++ if (veth_from_netdev(dev)->real_stats == NULL) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static int ++veth_set_op(struct net_device *dev, u32 data, ++ int (*fop)(struct net_device *, u32)) ++{ ++ struct net_device *pair; ++ int ret = 0; ++ ++ ret = fop(dev, data); ++ if (ret < 0) ++ goto out; ++ ++ pair = veth_from_netdev(dev)->pair; ++ if (pair) ++ ret = fop(pair, data); ++out: ++ return ret; ++} ++ ++static int veth_op_set_sg(struct net_device *dev, u32 data) ++{ ++ return veth_set_op(dev, data, ethtool_op_set_sg); ++} ++ ++static int veth_op_set_tx_csum(struct net_device *dev, u32 data) ++{ ++ return veth_set_op(dev, data, ethtool_op_set_tx_csum); ++} ++ ++#define veth_op_set_rx_csum veth_op_set_tx_csum ++ ++static struct ethtool_ops veth_ethtool_ops = { ++ .get_sg = ethtool_op_get_sg, ++ .set_sg = veth_op_set_sg, ++ .get_tx_csum = ethtool_op_get_tx_csum, ++ .set_tx_csum = veth_op_set_tx_csum, ++ .get_rx_csum = ethtool_op_get_tx_csum, ++ .set_rx_csum = veth_op_set_rx_csum, ++ .get_tso = ethtool_op_get_tso, ++}; ++ ++static void veth_setup(struct net_device *dev) ++{ ++ dev->init = veth_init_dev; ++ /* ++ * No other features, as they are: ++ * - checksumming is required, and nobody else will done our job ++ */ ++ dev->features |= NETIF_F_VENET | NETIF_F_VIRTUAL | NETIF_F_LLTX | ++ NETIF_F_HIGHDMA; ++ ++ SET_ETHTOOL_OPS(dev, &veth_ethtool_ops); ++} ++ ++#ifdef CONFIG_PROC_FS ++#define ADDR_FMT "%02x:%02x:%02x:%02x:%02x:%02x" ++#define ADDR_ARG(x) (x)[0],(x)[1],(x)[2],(x)[3],(x)[4],(x)[5] ++static int vehwaddr_seq_show(struct seq_file *m, void *v) ++{ ++ struct list_head *p; ++ struct veth_struct *entry; ++ ++ p = (struct list_head *)v; ++ if (p == &veth_hwaddr_list) { ++ seq_puts(m, "Version: 1.0\n"); ++ return 0; ++ } ++ entry = list_entry(p, struct veth_struct, hwaddr_list); ++ seq_printf(m, ADDR_FMT " %16s ", ++ ADDR_ARG(entry->pair->dev_addr), entry->pair->name); ++ seq_printf(m, ADDR_FMT " %16s %10u %5s\n", ++ ADDR_ARG(veth_to_netdev(entry)->dev_addr), ++ veth_to_netdev(entry)->name, ++ VEID(veth_to_netdev(entry)->owner_env), ++ entry->allow_mac_change ? "allow" : "deny"); ++ return 0; ++} ++ ++static void *vehwaddr_seq_start(struct seq_file *m, loff_t *pos) ++{ ++ loff_t l; ++ struct list_head *p; ++ ++ l = *pos; ++ read_lock(&ve_hwaddr_lock); ++ if (l == 0) ++ return &veth_hwaddr_list; ++ list_for_each(p, &veth_hwaddr_list) { ++ if (--l == 0) ++ return p; ++ } ++ return NULL; ++} ++ ++static void *vehwaddr_seq_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ struct list_head *p; ++ ++ p = (struct list_head *)v; ++ (*pos)++; ++ return p->next == &veth_hwaddr_list ? NULL : p->next; ++} ++ ++static void vehwaddr_seq_stop(struct seq_file *m, void *v) ++{ ++ read_unlock(&ve_hwaddr_lock); ++} ++ ++static struct seq_operations vehwaddr_seq_op = { ++ .start = vehwaddr_seq_start, ++ .next = vehwaddr_seq_next, ++ .stop = vehwaddr_seq_stop, ++ .show = vehwaddr_seq_show, ++}; ++ ++static int vehwaddr_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &vehwaddr_seq_op); ++} ++ ++static struct file_operations proc_vehwaddr_operations = { ++ .open = vehwaddr_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++#endif ++ ++int real_ve_hwaddr(envid_t veid, int op, ++ unsigned char *dev_addr, int addrlen, char *name, ++ unsigned char *dev_addr_ve, int addrlen_ve, char *name_ve) ++{ ++ int err; ++ struct ve_struct *ve; ++ char ve_addr[ETH_ALEN]; ++ ++ err = -EPERM; ++ if (!capable(CAP_NET_ADMIN)) ++ goto out; ++ ++ err = -EINVAL; ++ switch (op) { ++ case VE_ETH_ADD: ++ if (addrlen != ETH_ALEN) ++ goto out; ++ if (addrlen_ve != ETH_ALEN && addrlen_ve != 0) ++ goto out; ++ /* If ve addr is not set then we use dev_addr[3] & 0x80 for it */ ++ if (addrlen_ve == 0 && (dev_addr[3] & 0x80)) ++ goto out; ++ if (addrlen_ve == 0) { ++ memcpy(ve_addr, dev_addr, ETH_ALEN); ++ ve_addr[3] |= 0x80; ++ } else { ++ memcpy(ve_addr, dev_addr_ve, ETH_ALEN); ++ } ++ ++ ve = get_ve_by_id(veid); ++ err = -ESRCH; ++ if (!ve) ++ goto out; ++ ++ down_read(&ve->op_sem); ++ if (ve->is_running) ++ err = veth_entry_add(ve, dev_addr, name, ve_addr, name_ve); ++ up_read(&ve->op_sem); ++ put_ve(ve); ++ break; ++ ++ case VE_ETH_DEL: ++ if (name[0] == '\0') ++ goto out; ++ ve = get_ve_by_id(veid); ++ err = -ESRCH; ++ if (!ve) ++ goto out; ++ ++ down_read(&ve->op_sem); ++ if (ve->is_running) ++ err = veth_entry_del(ve, name); ++ up_read(&ve->op_sem); ++ put_ve(ve); ++ break; ++ case VE_ETH_ALLOW_MAC_CHANGE: ++ case VE_ETH_DENY_MAC_CHANGE: ++ err = veth_allow_change_mac(veid, name, ++ op == VE_ETH_ALLOW_MAC_CHANGE); ++ break; ++ } ++ ++out: ++ return err; ++} ++ ++int veth_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int err; ++ ++ err = -ENOTTY; ++ switch(cmd) { ++ case VETHCTL_VE_HWADDR: { ++ struct vzctl_ve_hwaddr s; ++ ++ err = -EFAULT; ++ if (copy_from_user(&s, (void __user *)arg, sizeof(s))) ++ break; ++ err = real_ve_hwaddr(s.veid, s.op, s.dev_addr, s.addrlen, ++ s.dev_name, s.dev_addr_ve, s.addrlen_ve, ++ s.dev_name_ve); ++ } ++ break; ++ } ++ return err; ++} ++ ++static struct vzioctlinfo vethcalls = { ++ .type = VETHCTLTYPE, ++ .ioctl = veth_ioctl, ++ .compat_ioctl = veth_ioctl, ++ .owner = THIS_MODULE, ++}; ++ ++struct net_device * veth_dev_start(char *dev_addr, char *name) ++{ ++ struct net_device *dev; ++ int err; ++ ++ if (!is_valid_ether_addr(dev_addr)) ++ return ERR_PTR(-EADDRNOTAVAIL); ++ ++ dev = alloc_netdev(sizeof(struct veth_struct), name, veth_setup); ++ if (!dev) ++ return ERR_PTR(-ENOMEM); ++ dev->nd_net = get_exec_env()->ve_ns->net_ns; ++ if (strchr(dev->name, '%')) { ++ err = dev_alloc_name(dev, dev->name); ++ if (err < 0) ++ goto err; ++ } ++ if ((err = register_netdev(dev)) != 0) ++ goto err; ++ ++ memcpy(dev->dev_addr, dev_addr, ETH_ALEN); ++ dev->addr_len = ETH_ALEN; ++ ++ return dev; ++err: ++ free_netdev(dev); ++ printk(KERN_ERR "%s initialization error err=%d\n", name, err); ++ return ERR_PTR(err); ++} ++ ++static int veth_start(void *data) ++{ ++ return 0; ++} ++ ++static void veth_stop(void *data) ++{ ++ struct ve_struct *env; ++ struct veth_struct *entry, *tmp; ++ ++ env = (struct ve_struct *)data; ++ down(&hwaddr_sem); ++ list_for_each_entry_safe(entry, tmp, &veth_hwaddr_list, hwaddr_list) ++ if (VEID(env) == VEID(veth_to_netdev(entry)->owner_env)) ++ veth_pair_del(env, entry); ++ up(&hwaddr_sem); ++} ++ ++static struct ve_hook veth_ve_hook = { ++ .init = veth_start, ++ .fini = veth_stop, ++ .owner = THIS_MODULE, ++ .priority = HOOK_PRIO_NET, ++}; ++ ++__init int veth_init(void) ++{ ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *de; ++ ++ de = create_proc_entry_mod("vz/veth", ++ S_IFREG|S_IRUSR, NULL, THIS_MODULE); ++ if (de) ++ de->proc_fops = &proc_vehwaddr_operations; ++ else ++ printk(KERN_WARNING "veth: can't make vehwaddr proc entry\n"); ++#endif ++ ++ ve_hook_register(VE_SS_CHAIN, &veth_ve_hook); ++ vzioctl_register(&vethcalls); ++ KSYMRESOLVE(veth_open); ++ KSYMMODRESOLVE(vzethdev); ++ return 0; ++} ++ ++__exit void veth_exit(void) ++{ ++ struct veth_struct *entry; ++ struct list_head *tmp, *n; ++ struct ve_struct *ve; ++ ++ KSYMMODUNRESOLVE(vzethdev); ++ KSYMUNRESOLVE(veth_open); ++ vzioctl_unregister(&vethcalls); ++ ve_hook_unregister(&veth_ve_hook); ++#ifdef CONFIG_PROC_FS ++ remove_proc_entry("vz/veth", NULL); ++#endif ++ ++ down(&hwaddr_sem); ++ list_for_each_safe(tmp, n, &veth_hwaddr_list) { ++ entry = list_entry(tmp, struct veth_struct, hwaddr_list); ++ ve = get_ve(veth_to_netdev(entry)->owner_env); ++ ++ veth_pair_del(ve, entry); ++ ++ put_ve(ve); ++ } ++ up(&hwaddr_sem); ++} ++ ++module_init(veth_init); ++module_exit(veth_exit); ++ ++MODULE_AUTHOR("Andrey Mirkin "); ++MODULE_DESCRIPTION("Virtuozzo Virtual Ethernet Device"); ++MODULE_LICENSE("GPL v2"); ++ +Index: kernel/drivers/pci/probe.c +=================================================================== +--- kernel.orig/drivers/pci/probe.c 2008-11-18 01:19:44.000000000 +0100 ++++ kernel/drivers/pci/probe.c 2008-11-24 15:47:45.000000000 +0100 +@@ -21,6 +21,7 @@ + EXPORT_SYMBOL(pci_root_buses); + + LIST_HEAD(pci_devices); ++EXPORT_SYMBOL(pci_devices); + + /* + * Some device drivers need know if pci is initiated. +Index: kernel/drivers/sbus/char/bbc_envctrl.c +=================================================================== +--- kernel.orig/drivers/sbus/char/bbc_envctrl.c 2008-11-18 01:19:44.000000000 +0100 ++++ kernel/drivers/sbus/char/bbc_envctrl.c 2008-11-24 15:47:45.000000000 +0100 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include "bbc_i2c.h" + #include "max1617.h" +Index: kernel/drivers/sbus/char/envctrl.c +=================================================================== +--- kernel.orig/drivers/sbus/char/envctrl.c 2008-11-18 01:19:44.000000000 +0100 ++++ kernel/drivers/sbus/char/envctrl.c 2008-11-24 15:47:45.000000000 +0100 +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + #define ENVCTRL_MINOR 162 + +Index: kernel/fs/Kconfig +=================================================================== +--- kernel.orig/fs/Kconfig 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/Kconfig 2008-11-24 15:47:45.000000000 +0100 +@@ -562,6 +562,15 @@ + Note that this behavior is currently deprecated and may go away in + future. Please use notification via netlink socket instead. + ++config QUOTA_COMPAT ++ bool "Compatibility with older quotactl interface" ++ depends on QUOTA ++ help ++ This option enables compatibility layer for older version ++ of quotactl interface with byte granularity (QUOTAON at 0x0100, ++ GETQUOTA at 0x0D00). Interface versions older than that one and ++ with block granularity are still not supported. ++ + config QFMT_V1 + tristate "Old quota format support" + depends on QUOTA +@@ -577,6 +586,39 @@ + This quota format allows using quotas with 32-bit UIDs/GIDs. If you + need this functionality say Y here. + ++config SIM_FS ++ tristate "VPS filesystem" ++ depends on VZ_QUOTA ++ default m ++ help ++ This file system is a part of Virtuozzo. It intoduces a fake ++ superblock and blockdev to VE to hide real device and show ++ statfs results taken from quota. ++ ++config VZ_QUOTA ++ tristate "Virtuozzo Disk Quota support" ++ depends on QUOTA ++ select VZ_DEV ++ default m ++ help ++ Virtuozzo Disk Quota imposes disk quota on directories with their ++ files and subdirectories in total. Such disk quota is used to ++ account and limit disk usage by Virtuozzo VPS, but also may be used ++ separately. ++ ++config VZ_QUOTA_UNLOAD ++ bool "Unloadable Virtuozzo Disk Quota module" ++ depends on VZ_QUOTA=m ++ default n ++ help ++ Make Virtuozzo Disk Quota module unloadable. ++ Doesn't work reliably now. ++ ++config VZ_QUOTA_UGID ++ bool "Per-user and per-group quota in Virtuozzo quota partitions" ++ depends on VZ_QUOTA!=n ++ default y ++ + config QUOTACTL + bool + depends on XFS_QUOTA || QUOTA +Index: kernel/fs/Makefile +=================================================================== +--- kernel.orig/fs/Makefile 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/Makefile 2008-11-24 15:47:45.000000000 +0100 +@@ -52,9 +52,15 @@ + obj-$(CONFIG_QFMT_V1) += quota_v1.o + obj-$(CONFIG_QFMT_V2) += quota_v2.o + obj-$(CONFIG_QUOTACTL) += quota.o ++obj-$(CONFIG_VZ_QUOTA) += vzdquota.o ++vzdquota-y += vzdquot.o vzdq_mgmt.o vzdq_ops.o vzdq_tree.o ++vzdquota-$(CONFIG_VZ_QUOTA_UGID) += vzdq_ugid.o ++vzdquota-$(CONFIG_VZ_QUOTA_UGID) += vzdq_file.o + + obj-$(CONFIG_DNOTIFY) += dnotify.o + ++obj-$(CONFIG_SIM_FS) += simfs.o ++ + obj-$(CONFIG_PROC_FS) += proc/ + obj-y += partitions/ + obj-$(CONFIG_SYSFS) += sysfs/ +Index: kernel/fs/aio.c +=================================================================== +--- kernel.orig/fs/aio.c 2008-11-24 14:14:52.000000000 +0100 ++++ kernel/fs/aio.c 2008-11-24 15:47:45.000000000 +0100 +@@ -43,13 +43,16 @@ + #endif + + /*------ sysctl variables----*/ +-static DEFINE_SPINLOCK(aio_nr_lock); ++DEFINE_SPINLOCK(aio_nr_lock); ++EXPORT_SYMBOL_GPL(aio_nr_lock); + unsigned long aio_nr; /* current system wide number of aio requests */ ++EXPORT_SYMBOL_GPL(aio_nr); + unsigned long aio_max_nr = 0x10000; /* system wide maximum number of aio requests */ + /*----end sysctl variables---*/ + + static struct kmem_cache *kiocb_cachep; +-static struct kmem_cache *kioctx_cachep; ++struct kmem_cache *kioctx_cachep; ++EXPORT_SYMBOL_GPL(kioctx_cachep); + + static struct workqueue_struct *aio_wq; + +@@ -60,7 +63,7 @@ + static DEFINE_SPINLOCK(fput_lock); + static LIST_HEAD(fput_head); + +-static void aio_kick_handler(struct work_struct *); ++void aio_kick_handler(struct work_struct *); + static void aio_queue_work(struct kioctx *); + + /* aio_setup +@@ -290,7 +293,7 @@ + spin_unlock_irq(&ctx->ctx_lock); + } + +-static void wait_for_all_aios(struct kioctx *ctx) ++void wait_for_all_aios(struct kioctx *ctx) + { + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); +@@ -313,6 +316,7 @@ + out: + spin_unlock_irq(&ctx->ctx_lock); + } ++EXPORT_SYMBOL_GPL(wait_for_all_aios); + + /* wait_on_sync_kiocb: + * Waits on the given sync kiocb to complete. +@@ -835,7 +839,7 @@ + * space. + * Run on aiod's context. + */ +-static void aio_kick_handler(struct work_struct *work) ++void aio_kick_handler(struct work_struct *work) + { + struct kioctx *ctx = container_of(work, struct kioctx, wq.work); + mm_segment_t oldfs = get_fs(); +@@ -856,7 +860,7 @@ + if (requeue) + queue_delayed_work(aio_wq, &ctx->wq, 0); + } +- ++EXPORT_SYMBOL_GPL(aio_kick_handler); + + /* + * Called by kick_iocb to queue the kiocb for retry +Index: kernel/fs/autofs/init.c +=================================================================== +--- kernel.orig/fs/autofs/init.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/autofs/init.c 2008-11-24 15:47:45.000000000 +0100 +@@ -25,6 +25,7 @@ + .name = "autofs", + .get_sb = autofs_get_sb, + .kill_sb = autofs_kill_sb, ++ .fs_flags = FS_VIRTUALIZED, + }; + + static int __init init_autofs_fs(void) +Index: kernel/fs/autofs/root.c +=================================================================== +--- kernel.orig/fs/autofs/root.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/autofs/root.c 2008-11-24 15:47:45.000000000 +0100 +@@ -356,7 +356,7 @@ + + /* This allows root to remove symlinks */ + lock_kernel(); +- if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) { ++ if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) && !capable(CAP_VE_SYS_ADMIN)) { + unlock_kernel(); + return -EACCES; + } +@@ -542,7 +542,7 @@ + _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT) + return -ENOTTY; + +- if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) ++ if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) && !capable(CAP_VE_SYS_ADMIN)) + return -EPERM; + + switch(cmd) { +Index: kernel/fs/autofs4/autofs_i.h +=================================================================== +--- kernel.orig/fs/autofs4/autofs_i.h 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/autofs4/autofs_i.h 2008-11-24 15:47:45.000000000 +0100 +@@ -94,6 +94,10 @@ + #define AUTOFS_TYPE_DIRECT 0x0002 + #define AUTOFS_TYPE_OFFSET 0x0004 + ++/* flags for userspace automount daemon */ ++#define AUTOFS_DEAMON_32BIT 0 /* automount is a 32bit process */ ++#define _AUTOFS_DEAMON_32BIT (1 << AUTOFS_DEAMON_32BIT) ++ + struct autofs_sb_info { + u32 magic; + int pipefd; +@@ -114,6 +118,7 @@ + struct autofs_wait_queue *queues; /* Wait queue pointer */ + spinlock_t rehash_lock; + struct list_head rehash_list; ++ u32 flags; /* flags for userspace automount daemon */ + }; + + static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb) +Index: kernel/fs/autofs4/init.c +=================================================================== +--- kernel.orig/fs/autofs4/init.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/autofs4/init.c 2008-11-24 15:47:45.000000000 +0100 +@@ -25,6 +25,7 @@ + .name = "autofs", + .get_sb = autofs_get_sb, + .kill_sb = autofs4_kill_sb, ++ .fs_flags = FS_VIRTUALIZED, + }; + + static int __init init_autofs4_fs(void) +Index: kernel/fs/autofs4/inode.c +=================================================================== +--- kernel.orig/fs/autofs4/inode.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/autofs4/inode.c 2008-11-24 15:47:45.000000000 +0100 +@@ -311,6 +311,7 @@ + int pipefd; + struct autofs_sb_info *sbi; + struct autofs_info *ino; ++ struct task_struct *tsk = current; + + sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); + if (!sbi) +@@ -330,6 +331,12 @@ + sbi->type = 0; + sbi->min_proto = 0; + sbi->max_proto = 0; ++#ifdef __x86_64__ ++ if (task_thread_info(tsk)->flags & _TIF_IA32) { ++ /* mark that automount daemon is 32 bit */ ++ sbi->flags |= _AUTOFS_DEAMON_32BIT; ++ } ++#endif + mutex_init(&sbi->wq_mutex); + spin_lock_init(&sbi->fs_lock); + sbi->queues = NULL; +Index: kernel/fs/autofs4/root.c +=================================================================== +--- kernel.orig/fs/autofs4/root.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/autofs4/root.c 2008-11-24 15:47:45.000000000 +0100 +@@ -762,7 +762,7 @@ + struct autofs_info *p_ino; + + /* This allows root to remove symlinks */ +- if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) ++ if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) && !capable(CAP_VE_SYS_ADMIN)) + return -EACCES; + + if (atomic_dec_and_test(&ino->count)) { +@@ -982,7 +982,7 @@ + _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT) + return -ENOTTY; + +- if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) ++ if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) && !capable(CAP_VE_SYS_ADMIN)) + return -EPERM; + + switch(cmd) { +Index: kernel/fs/autofs4/waitq.c +=================================================================== +--- kernel.orig/fs/autofs4/waitq.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/autofs4/waitq.c 2008-11-24 15:47:45.000000000 +0100 +@@ -102,27 +102,50 @@ + /* Kernel protocol v4 missing and expire packets */ + case autofs_ptype_missing: + { +- struct autofs_packet_missing *mp = &pkt.v4_pkt.missing; ++ if (sbi->flags & _AUTOFS_DEAMON_32BIT) { ++ struct autofs_packet_missing_32bit *mp = &pkt.v4_pkt.missing_32bit; + +- pktsz = sizeof(*mp); ++ pktsz = sizeof(*mp); ++ mp->wait_queue_token = wq->wait_queue_token; ++ mp->len = wq->len; ++ memcpy(mp->name, wq->name, wq->len); ++ mp->name[wq->len] = '\0'; ++ break; ++ } else { ++ struct autofs_packet_missing *mp = &pkt.v4_pkt.missing; ++ ++ pktsz = sizeof(*mp); + +- mp->wait_queue_token = wq->wait_queue_token; +- mp->len = wq->len; +- memcpy(mp->name, wq->name, wq->len); +- mp->name[wq->len] = '\0'; +- break; ++ mp->wait_queue_token = wq->wait_queue_token; ++ mp->len = wq->len; ++ memcpy(mp->name, wq->name, wq->len); ++ mp->name[wq->len] = '\0'; ++ break; ++ } + } + case autofs_ptype_expire_multi: + { +- struct autofs_packet_expire_multi *ep = &pkt.v4_pkt.expire_multi; ++ if (sbi->flags & _AUTOFS_DEAMON_32BIT) { ++ struct autofs_packet_expire_multi_32bit *ep = &pkt.v4_pkt.expire_multi_32bit; ++ ++ pktsz = sizeof(*ep); ++ ++ ep->wait_queue_token = wq->wait_queue_token; ++ ep->len = wq->len; ++ memcpy(ep->name, wq->name, wq->len); ++ ep->name[wq->len] = '\0'; ++ break; ++ } else { ++ struct autofs_packet_expire_multi *ep = &pkt.v4_pkt.expire_multi; + +- pktsz = sizeof(*ep); ++ pktsz = sizeof(*ep); + +- ep->wait_queue_token = wq->wait_queue_token; +- ep->len = wq->len; +- memcpy(ep->name, wq->name, wq->len); +- ep->name[wq->len] = '\0'; +- break; ++ ep->wait_queue_token = wq->wait_queue_token; ++ ep->len = wq->len; ++ memcpy(ep->name, wq->name, wq->len); ++ ep->name[wq->len] = '\0'; ++ break; ++ } + } + /* + * Kernel protocol v5 packet for handling indirect and direct +@@ -133,21 +156,39 @@ + case autofs_ptype_missing_direct: + case autofs_ptype_expire_direct: + { +- struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet; ++ if (sbi->flags & _AUTOFS_DEAMON_32BIT) { ++ struct autofs_v5_packet_32bit *packet = &pkt.v5_pkt.v5_packet_32bit; ++ ++ pktsz = sizeof(*packet); ++ ++ packet->wait_queue_token = wq->wait_queue_token; ++ packet->len = wq->len; ++ memcpy(packet->name, wq->name, wq->len); ++ packet->name[wq->len] = '\0'; ++ packet->dev = wq->dev; ++ packet->ino = wq->ino; ++ packet->uid = wq->uid; ++ packet->gid = wq->gid; ++ packet->pid = wq->pid; ++ packet->tgid = wq->tgid; ++ break; ++ } else { ++ struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet; + +- pktsz = sizeof(*packet); ++ pktsz = sizeof(*packet); + +- packet->wait_queue_token = wq->wait_queue_token; +- packet->len = wq->len; +- memcpy(packet->name, wq->name, wq->len); +- packet->name[wq->len] = '\0'; +- packet->dev = wq->dev; +- packet->ino = wq->ino; +- packet->uid = wq->uid; +- packet->gid = wq->gid; +- packet->pid = wq->pid; +- packet->tgid = wq->tgid; +- break; ++ packet->wait_queue_token = wq->wait_queue_token; ++ packet->len = wq->len; ++ memcpy(packet->name, wq->name, wq->len); ++ packet->name[wq->len] = '\0'; ++ packet->dev = wq->dev; ++ packet->ino = wq->ino; ++ packet->uid = wq->uid; ++ packet->gid = wq->gid; ++ packet->pid = wq->pid; ++ packet->tgid = wq->tgid; ++ break; ++ } + } + default: + printk("autofs4_notify_daemon: bad type %d!\n", type); +Index: kernel/fs/binfmt_aout.c +=================================================================== +--- kernel.orig/fs/binfmt_aout.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/binfmt_aout.c 2008-11-24 15:47:45.000000000 +0100 +@@ -375,14 +375,14 @@ + if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && + (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time2) > 5*HZ) + { +- printk(KERN_NOTICE "executable not page aligned\n"); ++ ve_printk(VE_LOG, KERN_NOTICE "executable not page aligned\n"); + error_time2 = jiffies; + } + + if ((fd_offset & ~PAGE_MASK) != 0 && + (jiffies-error_time) > 5*HZ) + { +- printk(KERN_WARNING ++ ve_printk(VE_LOG, KERN_WARNING + "fd_offset is not page aligned. Please convert program: %s\n", + bprm->file->f_path.dentry->d_name.name); + error_time = jiffies; +@@ -499,7 +499,7 @@ + + if ((jiffies-error_time) > 5*HZ) + { +- printk(KERN_WARNING ++ ve_printk(VE_LOG, KERN_WARNING + "N_TXTOFF is not page aligned. Please convert library: %s\n", + file->f_path.dentry->d_name.name); + error_time = jiffies; +Index: kernel/fs/binfmt_elf.c +=================================================================== +--- kernel.orig/fs/binfmt_elf.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/binfmt_elf.c 2008-11-24 15:47:45.000000000 +0100 +@@ -417,7 +417,7 @@ + eppnt = elf_phdata; + for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { + if (eppnt->p_type == PT_LOAD) { +- int elf_type = MAP_PRIVATE | MAP_DENYWRITE; ++ int elf_type = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECPRIO; + int elf_prot = 0; + unsigned long vaddr = 0; + unsigned long k, map_addr; +@@ -918,7 +918,8 @@ + if (elf_ppnt->p_flags & PF_X) + elf_prot |= PROT_EXEC; + +- elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE; ++ elf_flags = MAP_PRIVATE | MAP_DENYWRITE | ++ MAP_EXECUTABLE | MAP_EXECPRIO; + + vaddr = elf_ppnt->p_vaddr; + if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { +@@ -1059,7 +1060,7 @@ + set_binfmt(&elf_format); + + #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES +- retval = arch_setup_additional_pages(bprm, executable_stack); ++ retval = arch_setup_additional_pages(bprm, executable_stack, 0); + if (retval < 0) { + send_sig(SIGKILL, current, 0); + goto out; +@@ -1658,7 +1659,7 @@ + if (signr) { + struct elf_thread_status *tmp; + rcu_read_lock(); +- do_each_thread(g,p) ++ do_each_thread_ve(g,p) + if (current->mm == p->mm && current != p) { + tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC); + if (!tmp) { +@@ -1668,7 +1669,7 @@ + tmp->thread = p; + list_add(&tmp->list, &thread_list); + } +- while_each_thread(g,p); ++ while_each_thread_ve(g,p); + rcu_read_unlock(); + list_for_each(t, &thread_list) { + struct elf_thread_status *tmp; +Index: kernel/fs/block_dev.c +=================================================================== +--- kernel.orig/fs/block_dev.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/block_dev.c 2008-11-24 15:47:45.000000000 +0100 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include "internal.h" + +@@ -1124,9 +1125,15 @@ + { + struct module *owner = NULL; + struct gendisk *disk; +- int ret = -ENXIO; ++ int ret; + int part; + ++ ret = get_device_perms_ve(S_IFBLK, bdev->bd_dev, ++ file->f_mode & (FMODE_READ | FMODE_WRITE)); ++ if (ret) ++ return ret; ++ ++ ret = -ENXIO; + file->f_mapping = bdev->bd_inode->i_mapping; + lock_kernel(); + disk = get_gendisk(bdev->bd_dev, &part); +@@ -1384,7 +1391,7 @@ + * namespace if possible and return it. Return ERR_PTR(error) + * otherwise. + */ +-struct block_device *lookup_bdev(const char *path) ++struct block_device *lookup_bdev(const char *path, int mode) + { + struct block_device *bdev; + struct inode *inode; +@@ -1402,6 +1409,11 @@ + error = -ENOTBLK; + if (!S_ISBLK(inode->i_mode)) + goto fail; ++ ++ error = get_device_perms_ve(S_IFBLK, inode->i_rdev, mode); ++ if (error) ++ goto fail; ++ + error = -EACCES; + if (nd.mnt->mnt_flags & MNT_NODEV) + goto fail; +@@ -1433,12 +1445,13 @@ + mode_t mode = FMODE_READ; + int error = 0; + +- bdev = lookup_bdev(path); ++ if (!(flags & MS_RDONLY)) ++ mode |= FMODE_WRITE; ++ ++ bdev = lookup_bdev(path, mode); + if (IS_ERR(bdev)) + return bdev; + +- if (!(flags & MS_RDONLY)) +- mode |= FMODE_WRITE; + error = blkdev_get(bdev, mode, 0); + if (error) + return ERR_PTR(error); +@@ -1486,7 +1499,7 @@ + * hold). + */ + shrink_dcache_sb(sb); +- res = invalidate_inodes(sb); ++ res = invalidate_inodes_check(sb, 1); + drop_super(sb); + } + invalidate_bdev(bdev); +Index: kernel/fs/buffer.c +=================================================================== +--- kernel.orig/fs/buffer.c 2008-11-24 14:17:48.000000000 +0100 ++++ kernel/fs/buffer.c 2008-11-24 15:47:46.000000000 +0100 +@@ -698,6 +698,8 @@ + static int __set_page_dirty(struct page *page, + struct address_space *mapping, int warn) + { ++ int acct = 0; ++ + if (unlikely(!mapping)) + return !TestSetPageDirty(page); + +@@ -712,12 +714,14 @@ + __inc_zone_page_state(page, NR_FILE_DIRTY); + __inc_bdi_stat(mapping->backing_dev_info, + BDI_RECLAIMABLE); +- task_io_account_write(PAGE_CACHE_SIZE); ++ acct = 1; + } + radix_tree_tag_set(&mapping->page_tree, + page_index(page), PAGECACHE_TAG_DIRTY); + } + write_unlock_irq(&mapping->tree_lock); ++ if (acct) ++ task_io_account_write(page, PAGE_CACHE_SIZE, 0); + __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); + + return 1; +Index: kernel/fs/char_dev.c +=================================================================== +--- kernel.orig/fs/char_dev.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/char_dev.c 2008-11-24 15:47:46.000000000 +0100 +@@ -22,6 +22,8 @@ + #include + #include + ++#include ++ + #ifdef CONFIG_KMOD + #include + #endif +@@ -363,6 +365,11 @@ + struct cdev *new = NULL; + int ret = 0; + ++ ret = get_device_perms_ve(S_IFCHR, inode->i_rdev, ++ filp->f_mode & (FMODE_READ | FMODE_WRITE)); ++ if (ret) ++ return ret; ++ + spin_lock(&cdev_lock); + p = inode->i_cdev; + if (!p) { +Index: kernel/fs/compat.c +=================================================================== +--- kernel.orig/fs/compat.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/compat.c 2008-11-24 15:47:46.000000000 +0100 +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -50,6 +51,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -72,6 +74,18 @@ + + #include "read_write.h" + ++int ve_compat_printk(int dst, const char *fmt, ...) ++{ ++ va_list ap; ++ int ret; ++ if (!compat_log) ++ return 0; ++ va_start(ap, fmt); ++ ret = ve_vprintk(dst, fmt, ap); ++ va_end(ap); ++ return ret; ++} ++ + /* + * Not all architectures have sys_utime, so implement this in terms + * of sys_utimes. +@@ -243,6 +257,8 @@ + struct kstatfs tmp; + error = vfs_statfs(nd.dentry, &tmp); + if (!error) ++ error = faudit_statfs(nd.mnt->mnt_sb, &tmp); ++ if (!error) + error = put_compat_statfs(buf, &tmp); + path_release(&nd); + } +@@ -261,6 +277,8 @@ + goto out; + error = vfs_statfs(file->f_path.dentry, &tmp); + if (!error) ++ error = faudit_statfs(file->f_vfsmnt->mnt_sb, &tmp); ++ if (!error) + error = put_compat_statfs(buf, &tmp); + fput(file); + out: +@@ -311,6 +329,8 @@ + struct kstatfs tmp; + error = vfs_statfs(nd.dentry, &tmp); + if (!error) ++ error = faudit_statfs(nd.mnt->mnt_sb, &tmp); ++ if (!error) + error = put_compat_statfs64(buf, &tmp); + path_release(&nd); + } +@@ -332,6 +352,8 @@ + goto out; + error = vfs_statfs(file->f_path.dentry, &tmp); + if (!error) ++ error = faudit_statfs(file->f_vfsmnt->mnt_sb, &tmp); ++ if (!error) + error = put_compat_statfs64(buf, &tmp); + fput(file); + out: +@@ -1357,6 +1379,10 @@ + struct file *file; + int retval; + ++ retval = virtinfo_gencall(VIRTINFO_DOEXECVE, NULL); ++ if (retval) ++ return retval; ++ + retval = -ENOMEM; + bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); + if (!bprm) +@@ -1406,6 +1432,11 @@ + if (retval < 0) + goto out; + ++ if (!gr_tpe_allow(file)) { ++ retval = -EACCES; ++ goto out; ++ } ++ + retval = search_binary_handler(bprm, regs); + if (retval >= 0) { + /* execve success */ +Index: kernel/fs/dcache.c +=================================================================== +--- kernel.orig/fs/dcache.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/dcache.c 2008-11-24 15:47:46.000000000 +0100 +@@ -26,13 +26,19 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include ++#include ++#include + #include "internal.h" + ++#include ++#include + + int sysctl_vfs_cache_pressure __read_mostly = 100; + EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); +@@ -42,7 +48,7 @@ + + EXPORT_SYMBOL(dcache_lock); + +-static struct kmem_cache *dentry_cache __read_mostly; ++struct kmem_cache *dentry_cache __read_mostly; + + #define DNAME_INLINE_LEN (sizeof(struct dentry)-offsetof(struct dentry,d_iname)) + +@@ -135,6 +141,7 @@ + + list_del(&dentry->d_u.d_child); + dentry_stat.nr_dentry--; /* For d_free, below */ ++ preempt_enable_no_resched(); + /*drops the locks, at that point nobody can reach this dentry */ + dentry_iput(dentry); + parent = dentry->d_parent; +@@ -169,25 +176,18 @@ + * they too may now get deleted. + * + * no dcache lock, please. ++ * preemption is disabled by the caller. + */ + +-void dput(struct dentry *dentry) ++static void dput_recursive(struct dentry *dentry) + { +- if (!dentry) +- return; +- + repeat: +- if (atomic_read(&dentry->d_count) == 1) +- might_sleep(); + if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock)) +- return; ++ goto out_preempt; + + spin_lock(&dentry->d_lock); +- if (atomic_read(&dentry->d_count)) { +- spin_unlock(&dentry->d_lock); +- spin_unlock(&dcache_lock); +- return; +- } ++ if (atomic_read(&dentry->d_count)) ++ goto out_unlock; + + /* + * AV: ->d_delete() is _NOT_ allowed to block now. +@@ -204,8 +204,11 @@ + list_add(&dentry->d_lru, &dentry_unused); + dentry_stat.nr_unused++; + } ++out_unlock: + spin_unlock(&dentry->d_lock); + spin_unlock(&dcache_lock); ++out_preempt: ++ preempt_enable(); + return; + + unhash_it: +@@ -219,8 +222,23 @@ + dentry_stat.nr_unused--; + } + dentry = d_kill(dentry); +- if (dentry) ++ if (dentry) { ++ preempt_disable(); + goto repeat; ++ } ++} ++ ++void dput(struct dentry *dentry) ++{ ++ if (!dentry) ++ return; ++ ++ if (atomic_read(&dentry->d_count) == 1) ++ might_sleep(); ++ ++ preempt_disable(); ++ ub_dentry_uncharge(dentry); ++ dput_recursive(dentry); + } + + /** +@@ -289,6 +307,8 @@ + dentry_stat.nr_unused--; + list_del_init(&dentry->d_lru); + } ++ ++ ub_dentry_charge_nofail(dentry); + return dentry; + } + +@@ -391,6 +411,7 @@ + static void prune_one_dentry(struct dentry * dentry) + { + __d_drop(dentry); ++ preempt_disable(); + dentry = d_kill(dentry); + + /* +@@ -409,6 +430,7 @@ + dentry_stat.nr_unused--; + } + __d_drop(dentry); ++ preempt_disable(); + dentry = d_kill(dentry); + spin_lock(&dcache_lock); + } +@@ -709,6 +731,8 @@ + + dentry = sb->s_root; + sb->s_root = NULL; ++ /* "/" was also charged in d_alloc_root() */ ++ ub_dentry_uncharge(dentry); + atomic_dec(&dentry->d_count); + shrink_dcache_for_umount_subtree(dentry); + +@@ -871,12 +895,18 @@ + */ + static int shrink_dcache_memory(int nr, gfp_t gfp_mask) + { ++ int res = -1; ++ ++ KSTAT_PERF_ENTER(shrink_dcache) + if (nr) { + if (!(gfp_mask & __GFP_FS)) +- return -1; ++ goto out; + prune_dcache(nr, NULL); + } +- return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; ++ res = (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; ++out: ++ KSTAT_PERF_LEAVE(shrink_dcache) ++ return res; + } + + static struct shrinker dcache_shrinker = { +@@ -899,21 +929,27 @@ + struct dentry *dentry; + char *dname; + ++ dname = NULL; ++ if (name->len > DNAME_INLINE_LEN-1) { ++ dname = kmalloc(name->len + 1, GFP_KERNEL); ++ if (!dname) ++ goto err_name; ++ } ++ ++ ub_dentry_alloc_start(); ++ + dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); + if (!dentry) +- return NULL; ++ goto err_alloc; + +- if (name->len > DNAME_INLINE_LEN-1) { +- dname = kmalloc(name->len + 1, GFP_KERNEL); +- if (!dname) { +- kmem_cache_free(dentry_cache, dentry); +- return NULL; +- } +- } else { ++ preempt_disable(); ++ if (dname == NULL) + dname = dentry->d_iname; +- } + dentry->d_name.name = dname; + ++ if (ub_dentry_alloc(dentry)) ++ goto err_charge; ++ + dentry->d_name.len = name->len; + dentry->d_name.hash = name->hash; + memcpy(dname, name->name, name->len); +@@ -944,12 +980,27 @@ + } + + spin_lock(&dcache_lock); +- if (parent) ++ if (parent) { + list_add(&dentry->d_u.d_child, &parent->d_subdirs); ++ if (parent->d_flags & DCACHE_VIRTUAL) ++ dentry->d_flags |= DCACHE_VIRTUAL; ++ } + dentry_stat.nr_dentry++; + spin_unlock(&dcache_lock); ++ preempt_enable(); ++ ub_dentry_alloc_end(); + + return dentry; ++ ++err_charge: ++ preempt_enable(); ++ kmem_cache_free(dentry_cache, dentry); ++err_alloc: ++ if (name->len > DNAME_INLINE_LEN - 1) ++ kfree(dname); ++ ub_dentry_alloc_end(); ++err_name: ++ return NULL; + } + + struct dentry *d_alloc_name(struct dentry *parent, const char *name) +@@ -1255,12 +1306,12 @@ + unsigned int hash = name->hash; + const unsigned char *str = name->name; + struct hlist_head *head = d_hash(parent,hash); +- struct dentry *found = NULL; + struct hlist_node *node; +- struct dentry *dentry; ++ struct dentry *dentry, *found; + + rcu_read_lock(); + ++ found = NULL; + hlist_for_each_entry_rcu(dentry, node, head, d_hash) { + struct qstr *qstr; + +@@ -1297,6 +1348,8 @@ + if (!d_unhashed(dentry)) { + atomic_inc(&dentry->d_count); + found = dentry; ++ if (ub_dentry_charge(found)) ++ goto charge_failure; + } + spin_unlock(&dentry->d_lock); + break; +@@ -1306,6 +1359,14 @@ + rcu_read_unlock(); + + return found; ++ ++charge_failure: ++ spin_unlock(&found->d_lock); ++ rcu_read_unlock(); ++ /* dentry is now unhashed, just kill it */ ++ dput(found); ++ /* ... and fail lookup */ ++ return NULL; + } + + /** +@@ -1761,7 +1822,33 @@ + } + + /** +- * __d_path - return the path of a dentry ++ * __d_path_add_deleted - prepend "(deleted) " text ++ * @end: a pointer to the character after free space at the beginning of the ++ * buffer ++ * @buflen: remaining free space ++ */ ++static inline char * __d_path_add_deleted(char * end, int buflen) ++{ ++ buflen -= 10; ++ if (buflen < 0) ++ return ERR_PTR(-ENAMETOOLONG); ++ end -= 10; ++ memcpy(end, "(deleted) ", 10); ++ return end; ++} ++ ++/** ++ * d_root_check - checks if dentry is accessible from current's fs root ++ * @dentry: dentry to be verified ++ * @vfsmnt: vfsmnt to which the dentry belongs ++ */ ++int d_root_check(struct dentry *dentry, struct vfsmount *vfsmnt) ++{ ++ return PTR_ERR(d_path(dentry, vfsmnt, NULL, 0)); ++} ++ ++/** ++ * d_path - return the path of a dentry + * @dentry: dentry to report + * @vfsmnt: vfsmnt to which the dentry belongs + * @root: root dentry +@@ -1779,98 +1866,94 @@ + * + * Returns the buffer or an error code. + */ +-char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, +- struct dentry *root, struct vfsmount *rootmnt, +- char *buffer, int buflen, int fail_deleted) +-{ +- int namelen, is_slash, vfsmount_locked = 0; +- +- if (buflen < 2) +- return ERR_PTR(-ENAMETOOLONG); +- buffer += --buflen; +- *buffer = '\0'; ++char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, ++ struct dentry *root, struct vfsmount *rootmnt, ++ char *buffer, int buflen) ++{ ++ char * end = buffer+buflen; ++ char * retval = NULL; ++ int namelen; ++ int deleted; ++ struct vfsmount *oldvfsmnt; ++ ++ oldvfsmnt = vfsmnt; ++ deleted = (!IS_ROOT(dentry) && d_unhashed(dentry)); ++ if (buffer != NULL) { ++ *--end = '\0'; ++ buflen--; + +- spin_lock(&dcache_lock); +- if (!IS_ROOT(dentry) && d_unhashed(dentry)) { +- if (fail_deleted) { +- buffer = ERR_PTR(-ENOENT); +- goto out; +- } +- if (buflen < 10) ++ if (buflen < 1) + goto Elong; +- buflen -= 10; +- buffer -= 10; +- memcpy(buffer, " (deleted)", 10); ++ /* Get '/' right */ ++ retval = end-1; ++ *retval = '/'; + } +- while (dentry != root || vfsmnt != rootmnt) { ++ ++ for (;;) { + struct dentry * parent; + + if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { +- if (!vfsmount_locked) { +- spin_lock(&vfsmount_lock); +- vfsmount_locked = 1; ++ /* root of a tree? */ ++ spin_lock(&vfsmount_lock); ++ if (vfsmnt->mnt_parent == vfsmnt) { ++ spin_unlock(&vfsmount_lock); ++ goto other_root; + } +- if (vfsmnt->mnt_parent == vfsmnt) +- goto global_root; + dentry = vfsmnt->mnt_mountpoint; + vfsmnt = vfsmnt->mnt_parent; + continue; + } + parent = dentry->d_parent; + prefetch(parent); +- namelen = dentry->d_name.len; +- if (buflen < namelen + 1) +- goto Elong; +- buflen -= namelen + 1; +- buffer -= namelen; +- memcpy(buffer, dentry->d_name.name, namelen); +- *--buffer = '/'; ++ if (buffer != NULL) { ++ namelen = dentry->d_name.len; ++ buflen -= namelen + 1; ++ if (buflen < 0) ++ goto Elong; ++ end -= namelen; ++ memcpy(end, dentry->d_name.name, namelen); ++ *--end = '/'; ++ retval = end; ++ } + dentry = parent; + } +- /* Get '/' right. */ +- if (*buffer != '/') +- *--buffer = '/'; ++ /* the given root point is reached */ ++finish: ++ if (buffer != NULL && deleted) ++ retval = __d_path_add_deleted(end, buflen); ++ return retval; + +-out: +- if (vfsmount_locked) +- spin_unlock(&vfsmount_lock); +- spin_unlock(&dcache_lock); +- return buffer; +- +-global_root: ++other_root: + /* +- * We went past the (vfsmount, dentry) we were looking for and have +- * either hit a root dentry, a lazily unmounted dentry, an +- * unconnected dentry, or the file is on a pseudo filesystem. ++ * We traversed the tree upward and reached a root, but the given ++ * lookup terminal point wasn't encountered. It means either that the ++ * dentry is out of our scope or belongs to an abstract space like ++ * sock_mnt or pipe_mnt. Check for it. ++ * ++ * There are different options to check it. ++ * We may assume that any dentry tree is unreachable unless it's ++ * connected to `root' (defined as fs root of init aka child reaper) ++ * and expose all paths that are not connected to it. ++ * The other option is to allow exposing of known abstract spaces ++ * explicitly and hide the path information for other cases. ++ * This approach is more safe, let's take it. 2001/04/22 SAW + */ +- namelen = dentry->d_name.len; +- is_slash = (namelen == 1 && *dentry->d_name.name == '/'); +- if (is_slash || (dentry->d_sb->s_flags & MS_NOUSER)) { +- /* +- * Make sure we won't return a pathname starting with '/'. +- * +- * Historically, we also glue together the root dentry and +- * remaining name for pseudo filesystems like pipefs, which +- * have the MS_NOUSER flag set. This results in pathnames +- * like "pipe:[439336]". +- */ +- if (*buffer == '/') { +- buffer++; +- buflen++; +- } +- if (is_slash) +- goto out; ++ if (!(oldvfsmnt->mnt_sb->s_flags & MS_NOUSER)) ++ return ERR_PTR(-EINVAL); ++ if (buffer != NULL) { ++ namelen = dentry->d_name.len; ++ buflen -= namelen; ++ if (buflen < 0) ++ goto Elong; ++ retval -= namelen-1; /* hit the slash */ ++ memcpy(retval, dentry->d_name.name, namelen); + } +- if (buflen < namelen) +- goto Elong; +- buffer -= namelen; +- memcpy(buffer, dentry->d_name.name, namelen); +- goto out; ++ goto finish; + + Elong: +- buffer = ERR_PTR(-ENAMETOOLONG); +- goto out; ++ return ERR_PTR(-ENAMETOOLONG); + } ++EXPORT_SYMBOL(__d_path); + + static char *__connect_d_path(char *path, char *buffer) + { +@@ -1898,21 +1981,248 @@ + * thus don't need to be hashed. They also don't need a name until a + * user wants to identify the object in /proc/pid/fd/. The little hack + * below allows us to generate a name for these objects on demand: ++ * ++ * pipefs and socketfs methods assume valid buffer, d_root_check() ++ * supplies NULL one for access checks. + */ +- if (dentry->d_op && dentry->d_op->d_dname) ++ if (buf && dentry->d_op && dentry->d_op->d_dname) + return dentry->d_op->d_dname(dentry, buf, buflen); + + read_lock(¤t->fs->lock); + rootmnt = mntget(current->fs->rootmnt); + root = dget(current->fs->root); + read_unlock(¤t->fs->lock); +- res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0); +- res = __connect_d_path(res, buf); ++ spin_lock(&dcache_lock); ++ res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen); ++ spin_unlock(&dcache_lock); + dput(root); + mntput(rootmnt); + return res; + } + ++#ifdef CONFIG_VE ++#include ++#include ++#include ++#include ++#include ++ ++static void mark_sub_tree_virtual(struct dentry *d) ++{ ++ struct dentry *orig_root; ++ ++ orig_root = d; ++ while (1) { ++ spin_lock(&d->d_lock); ++ d->d_flags |= DCACHE_VIRTUAL; ++ spin_unlock(&d->d_lock); ++ ++ if (!list_empty(&d->d_subdirs)) { ++ d = list_entry(d->d_subdirs.next, ++ struct dentry, d_u.d_child); ++ continue; ++ } ++ if (d == orig_root) ++ break; ++ while (d == list_entry(d->d_parent->d_subdirs.prev, ++ struct dentry, d_u.d_child)) { ++ d = d->d_parent; ++ if (d == orig_root) ++ goto out; ++ } ++ d = list_entry(d->d_u.d_child.next, ++ struct dentry, d_u.d_child); ++ } ++out: ++ return; ++} ++ ++void mark_tree_virtual(struct vfsmount *m, struct dentry *d) ++{ ++ struct vfsmount *orig_rootmnt; ++ ++ spin_lock(&dcache_lock); ++ spin_lock(&vfsmount_lock); ++ orig_rootmnt = m; ++ while (1) { ++ mark_sub_tree_virtual(d); ++ if (!list_empty(&m->mnt_mounts)) { ++ m = list_entry(m->mnt_mounts.next, ++ struct vfsmount, mnt_child); ++ d = m->mnt_root; ++ continue; ++ } ++ if (m == orig_rootmnt) ++ break; ++ while (m == list_entry(m->mnt_parent->mnt_mounts.prev, ++ struct vfsmount, mnt_child)) { ++ m = m->mnt_parent; ++ if (m == orig_rootmnt) ++ goto out; ++ } ++ m = list_entry(m->mnt_child.next, ++ struct vfsmount, mnt_child); ++ d = m->mnt_root; ++ } ++out: ++ spin_unlock(&vfsmount_lock); ++ spin_unlock(&dcache_lock); ++} ++EXPORT_SYMBOL(mark_tree_virtual); ++ ++static struct vz_rate_info area_ri = { 20, 10*HZ }; ++#define VE_AREA_ACC_CHECK 0x0001 ++#define VE_AREA_ACC_DENY 0x0002 ++#define VE_AREA_EXEC_CHECK 0x0010 ++#define VE_AREA_EXEC_DENY 0x0020 ++#define VE0_AREA_ACC_CHECK 0x0100 ++#define VE0_AREA_ACC_DENY 0x0200 ++#define VE0_AREA_EXEC_CHECK 0x1000 ++#define VE0_AREA_EXEC_DENY 0x2000 ++int ve_area_access_check = 0; ++ ++static void print_connection_info(struct task_struct *tsk) ++{ ++ struct files_struct *files; ++ struct fdtable *fdt; ++ int fd; ++ ++ files = get_files_struct(tsk); ++ if (!files) ++ return; ++ ++ spin_lock(&files->file_lock); ++ fdt = files_fdtable(files); ++ for (fd = 0; fd < fdt->max_fds; fd++) { ++ struct file *file; ++ struct inode *inode; ++ struct socket *socket; ++ struct sock *sk; ++ struct inet_sock *inet; ++ ++ file = fdt->fd[fd]; ++ if (file == NULL) ++ continue; ++ ++ inode = file->f_dentry->d_inode; ++ if (!S_ISSOCK(inode->i_mode)) ++ continue; ++ ++ socket = SOCKET_I(inode); ++ if (socket == NULL) ++ continue; ++ ++ sk = socket->sk; ++ if ((sk->sk_family != PF_INET && sk->sk_family != PF_INET6) ++ || sk->sk_type != SOCK_STREAM) ++ continue; ++ ++ inet = inet_sk(sk); ++ printk(KERN_ALERT "connection from %u.%u.%u.%u:%u to port %u\n", ++ NIPQUAD(inet->daddr), ntohs(inet->dport), ++ inet->num); ++ } ++ spin_unlock(&files->file_lock); ++ put_files_struct(files); ++} ++ ++static void check_alert(struct vfsmount *vfsmnt, struct dentry *dentry, ++ char *str) ++{ ++ struct task_struct *tsk; ++ unsigned long page; ++ struct super_block *sb; ++ char *p; ++ ++ if (!vz_ratelimit(&area_ri)) ++ return; ++ ++ tsk = current; ++ p = ERR_PTR(-ENOMEM); ++ page = __get_free_page(GFP_KERNEL); ++ if (page) { ++ spin_lock(&dcache_lock); ++ p = __d_path(dentry, vfsmnt, tsk->fs->root, tsk->fs->rootmnt, ++ (char *)page, PAGE_SIZE); ++ spin_unlock(&dcache_lock); ++ } ++ if (IS_ERR(p)) ++ p = "(undefined)"; ++ ++ sb = dentry->d_sb; ++ printk(KERN_ALERT "%s check alert! file:[%s] from %d/%s, dev%x\n" ++ "Task %d/%d[%s] from VE%d, execenv %d\n", ++ str, p, sb->s_type->owner_env->veid, ++ sb->s_type->name, sb->s_dev, ++ tsk->pid, task_pid_vnr(tsk), tsk->comm, ++ VE_TASK_INFO(tsk)->owner_env->veid, ++ get_exec_env()->veid); ++ ++ free_page(page); ++ ++ print_connection_info(tsk); ++ ++ read_lock(&tasklist_lock); ++ tsk = tsk->parent; ++ get_task_struct(tsk); ++ read_unlock(&tasklist_lock); ++ ++ printk(KERN_ALERT "Parent %d/%d[%s] from VE%d\n", ++ tsk->pid, task_pid_vnr(tsk), tsk->comm, ++ VE_TASK_INFO(tsk)->owner_env->veid); ++ ++ print_connection_info(tsk); ++ put_task_struct(tsk); ++ dump_stack(); ++} ++#endif ++ ++int check_area_access_ve(struct dentry *dentry, struct vfsmount *mnt) ++{ ++#ifdef CONFIG_VE ++ int check, alert, deny; ++ ++ if (ve_is_super(get_exec_env())) { ++ check = ve_area_access_check & VE0_AREA_ACC_CHECK; ++ alert = dentry->d_flags & DCACHE_VIRTUAL; ++ deny = ve_area_access_check & VE0_AREA_ACC_DENY; ++ } else { ++ check = ve_area_access_check & VE_AREA_ACC_CHECK; ++ alert = !(dentry->d_flags & DCACHE_VIRTUAL); ++ deny = ve_area_access_check & VE_AREA_ACC_DENY; ++ } ++ ++ if (check && alert) ++ check_alert(mnt, dentry, "Access"); ++ if (deny && alert) ++ return -EACCES; ++#endif ++ return 0; ++} ++ ++int check_area_execute_ve(struct dentry *dentry, struct vfsmount *mnt) ++{ ++#ifdef CONFIG_VE ++ int check, alert, deny; ++ ++ if (ve_is_super(get_exec_env())) { ++ check = ve_area_access_check & VE0_AREA_EXEC_CHECK; ++ alert = dentry->d_flags & DCACHE_VIRTUAL; ++ deny = ve_area_access_check & VE0_AREA_EXEC_DENY; ++ } else { ++ check = ve_area_access_check & VE_AREA_EXEC_CHECK; ++ alert = !(dentry->d_flags & DCACHE_VIRTUAL); ++ deny = ve_area_access_check & VE_AREA_EXEC_DENY; ++ } ++ ++ if (check && alert) ++ check_alert(mnt, dentry, "Exec"); ++ if (deny && alert) ++ return -EACCES; ++#endif ++ return 0; ++} ++ + /* + * Helper function for dentry_operations.d_dname() members + */ +@@ -1969,7 +2279,7 @@ + root = dget(current->fs->root); + read_unlock(¤t->fs->lock); + +- cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1); ++ cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE); + cwd = __connect_d_path(cwd, page); + error = PTR_ERR(cwd); + if (IS_ERR(cwd)) +@@ -2060,10 +2370,12 @@ + goto repeat; + } + atomic_dec(&dentry->d_count); ++ ub_dentry_uncharge_locked(dentry); + } + if (this_parent != root) { + next = this_parent->d_u.d_child.next; + atomic_dec(&this_parent->d_count); ++ ub_dentry_uncharge_locked(this_parent); + this_parent = this_parent->d_parent; + goto resume; + } +Index: kernel/fs/devpts/inode.c +=================================================================== +--- kernel.orig/fs/devpts/inode.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/devpts/inode.c 2008-11-24 15:47:46.000000000 +0100 +@@ -20,19 +20,21 @@ + #include + #include + #include ++#include + + #define DEVPTS_SUPER_MAGIC 0x1cd1 + ++struct devpts_config devpts_config = {.mode = 0600}; ++ ++#ifndef CONFIG_VE + static struct vfsmount *devpts_mnt; + static struct dentry *devpts_root; +- +-static struct { +- int setuid; +- int setgid; +- uid_t uid; +- gid_t gid; +- umode_t mode; +-} config = {.mode = 0600}; ++#define config devpts_config ++#else ++#define devpts_mnt (get_exec_env()->devpts_mnt) ++#define devpts_root (get_exec_env()->devpts_root) ++#define config (*(get_exec_env()->devpts_config)) ++#endif + + enum { + Opt_uid, Opt_gid, Opt_mode, +@@ -84,7 +86,8 @@ + config.mode = option & ~S_IFMT; + break; + default: +- printk(KERN_ERR "devpts: called with bogus options\n"); ++ ve_printk(VE_LOG, KERN_ERR ++ "devpts: called with bogus options\n"); + return -EINVAL; + } + } +@@ -136,13 +139,15 @@ + return get_sb_single(fs_type, flags, data, devpts_fill_super, mnt); + } + +-static struct file_system_type devpts_fs_type = { ++struct file_system_type devpts_fs_type = { + .owner = THIS_MODULE, + .name = "devpts", + .get_sb = devpts_get_sb, + .kill_sb = kill_anon_super, + }; + ++EXPORT_SYMBOL(devpts_fs_type); ++ + /* + * The normal naming convention is simply /dev/pts/; this conforms + * to the System V naming convention +@@ -235,6 +240,7 @@ + + static void __exit exit_devpts_fs(void) + { ++ /* the code is never called, the argument is irrelevant */ + unregister_filesystem(&devpts_fs_type); + mntput(devpts_mnt); + } +Index: kernel/fs/direct-io.c +=================================================================== +--- kernel.orig/fs/direct-io.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/direct-io.c 2008-11-24 15:47:46.000000000 +0100 +@@ -666,7 +666,7 @@ + /* + * Read accounting is performed in submit_bio() + */ +- task_io_account_write(len); ++ task_io_account_write(page, len, 1); + } + + /* +Index: kernel/fs/dquot.c +=================================================================== +--- kernel.orig/fs/dquot.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/dquot.c 2008-11-24 15:47:46.000000000 +0100 +@@ -162,7 +162,9 @@ + struct quota_format_type *actqf; + + spin_lock(&dq_list_lock); +- for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next); ++ for (actqf = quota_formats; ++ actqf && (actqf->qf_fmt_id != id || actqf->qf_ops == NULL); ++ actqf = actqf->qf_next); + if (!actqf || !try_module_get(actqf->qf_owner)) { + int qm; + +Index: kernel/fs/eventpoll.c +=================================================================== +--- kernel.orig/fs/eventpoll.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/eventpoll.c 2008-11-24 15:47:46.000000000 +0100 +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -102,11 +103,6 @@ + + #define EP_UNACTIVE_PTR ((void *) -1L) + +-struct epoll_filefd { +- struct file *file; +- int fd; +-}; +- + /* + * Node that is linked into the "wake_task_list" member of the "struct poll_safewake". + * It is used to keep track on all tasks that are currently inside the wake_up() code +@@ -129,79 +125,6 @@ + spinlock_t lock; + }; + +-/* +- * Each file descriptor added to the eventpoll interface will +- * have an entry of this type linked to the "rbr" RB tree. +- */ +-struct epitem { +- /* RB tree node used to link this structure to the eventpoll RB tree */ +- struct rb_node rbn; +- +- /* List header used to link this structure to the eventpoll ready list */ +- struct list_head rdllink; +- +- /* +- * Works together "struct eventpoll"->ovflist in keeping the +- * single linked chain of items. +- */ +- struct epitem *next; +- +- /* The file descriptor information this item refers to */ +- struct epoll_filefd ffd; +- +- /* Number of active wait queue attached to poll operations */ +- int nwait; +- +- /* List containing poll wait queues */ +- struct list_head pwqlist; +- +- /* The "container" of this item */ +- struct eventpoll *ep; +- +- /* List header used to link this item to the "struct file" items list */ +- struct list_head fllink; +- +- /* The structure that describe the interested events and the source fd */ +- struct epoll_event event; +-}; +- +-/* +- * This structure is stored inside the "private_data" member of the file +- * structure and rapresent the main data sructure for the eventpoll +- * interface. +- */ +-struct eventpoll { +- /* Protect the this structure access */ +- spinlock_t lock; +- +- /* +- * This mutex is used to ensure that files are not removed +- * while epoll is using them. This is held during the event +- * collection loop, the file cleanup path, the epoll file exit +- * code and the ctl operations. +- */ +- struct mutex mtx; +- +- /* Wait queue used by sys_epoll_wait() */ +- wait_queue_head_t wq; +- +- /* Wait queue used by file->poll() */ +- wait_queue_head_t poll_wait; +- +- /* List of ready file descriptors */ +- struct list_head rdllist; +- +- /* RB tree root used to store monitored fd structs */ +- struct rb_root rbr; +- +- /* +- * This is a single linked list that chains all the "struct epitem" that +- * happened while transfering ready events to userspace w/out +- * holding ->lock. +- */ +- struct epitem *ovflist; +-}; +- + /* Wait structure used by the poll hooks */ + struct eppoll_entry { + /* List header used to link this structure to the "struct epitem" */ +@@ -229,7 +152,8 @@ + /* + * This mutex is used to serialize ep_free() and eventpoll_release_file(). + */ +-static struct mutex epmutex; ++struct mutex epmutex; ++EXPORT_SYMBOL_GPL(epmutex); + + /* Safe wake up implementation */ + static struct poll_safewake psw; +@@ -502,10 +426,11 @@ + } + + /* File callbacks that implement the eventpoll file behaviour */ +-static const struct file_operations eventpoll_fops = { ++const struct file_operations eventpoll_fops = { + .release = ep_eventpoll_release, + .poll = ep_eventpoll_poll + }; ++EXPORT_SYMBOL(eventpoll_fops); + + /* Fast test to see if the file is an evenpoll file */ + static inline int is_file_epoll(struct file *f) +@@ -577,7 +502,7 @@ + * are protected by the "mtx" mutex, and ep_find() must be called with + * "mtx" held. + */ +-static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd) ++struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd) + { + int kcmp; + struct rb_node *rbp; +@@ -603,6 +528,7 @@ + + return epir; + } ++EXPORT_SYMBOL_GPL(ep_find); + + /* + * This is the callback that is passed to the wait queue wakeup +@@ -716,7 +642,7 @@ + /* + * Must be called with "mtx" held. + */ +-static int ep_insert(struct eventpoll *ep, struct epoll_event *event, ++int ep_insert(struct eventpoll *ep, struct epoll_event *event, + struct file *tfile, int fd) + { + int error, revents, pwake = 0; +@@ -814,6 +740,7 @@ + error_return: + return error; + } ++EXPORT_SYMBOL(ep_insert); + + /* + * Modify the interest event mask by dropping an event if the new mask +@@ -1109,6 +1036,7 @@ + current, size, error)); + return error; + } ++EXPORT_SYMBOL(sys_epoll_create); + + /* + * The following function implements the controller interface for +Index: kernel/fs/exec.c +=================================================================== +--- kernel.orig/fs/exec.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/exec.c 2008-11-24 15:47:46.000000000 +0100 +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -51,11 +52,14 @@ + #include + #include + #include ++#include + + #include + #include + #include + ++#include ++ + #ifdef CONFIG_KMOD + #include + #endif +@@ -66,6 +70,8 @@ + + /* The maximal length of core_pattern is also specified in sysctl.c */ + ++int sysctl_at_vsyscall; ++ + static LIST_HEAD(formats); + static DEFINE_RWLOCK(binfmt_lock); + +@@ -217,9 +223,13 @@ + struct vm_area_struct *vma = NULL; + struct mm_struct *mm = bprm->mm; + +- bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); ++ if (ub_memory_charge(mm, PAGE_SIZE, VM_STACK_FLAGS | mm->def_flags, ++ NULL, UB_SOFT)) ++ goto fail_charge; ++ ++ bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL_UBC); + if (!vma) +- goto err; ++ goto fail_alloc; + + down_write(&mm->mmap_sem); + vma->vm_mm = mm; +@@ -253,7 +263,9 @@ + bprm->vma = NULL; + kmem_cache_free(vm_area_cachep, vma); + } +- ++fail_alloc: ++ ub_memory_uncharge(mm, PAGE_SIZE, VM_STACK_FLAGS | mm->def_flags, NULL); ++fail_charge: + return err; + } + +@@ -695,10 +707,11 @@ + + EXPORT_SYMBOL(kernel_read); + +-static int exec_mmap(struct mm_struct *mm) ++static int exec_mmap(struct linux_binprm *bprm) + { + struct task_struct *tsk; +- struct mm_struct * old_mm, *active_mm; ++ struct mm_struct *old_mm, *active_mm, *mm; ++ int ret; + + /* Notify parent that we're no longer interested in the old VM */ + tsk = current; +@@ -720,6 +733,10 @@ + return -EINTR; + } + } ++ ++ ret = 0; ++ mm = bprm->mm; ++ mm->vps_dumpable = 1; + task_lock(tsk); + active_mm = tsk->active_mm; + tsk->mm = mm; +@@ -727,14 +744,24 @@ + activate_mm(active_mm, mm); + task_unlock(tsk); + arch_pick_mmap_layout(mm); ++ bprm->mm = NULL; /* We're using it now */ ++ ++#ifdef CONFIG_VZ_GENCALLS ++ if (virtinfo_notifier_call(VITYPE_GENERAL, VIRTINFO_EXECMMAP, ++ bprm) & NOTIFY_FAIL) { ++ /* similar to binfmt_elf */ ++ send_sig(SIGKILL, current, 0); ++ ret = -ENOMEM; ++ } ++#endif + if (old_mm) { + up_read(&old_mm->mmap_sem); + BUG_ON(active_mm != old_mm); + mmput(old_mm); +- return 0; ++ return ret; + } + mmdrop(active_mm); +- return 0; ++ return ret; + } + + /* +@@ -861,6 +888,10 @@ + transfer_pid(leader, tsk, PIDTYPE_PGID); + transfer_pid(leader, tsk, PIDTYPE_SID); + list_replace_rcu(&leader->tasks, &tsk->tasks); ++#ifdef CONFIG_VE ++ list_replace_rcu(&leader->ve_task_info.vetask_list, ++ &tsk->ve_task_info.vetask_list); ++#endif + + tsk->group_leader = tsk; + leader->group_leader = tsk; +@@ -989,12 +1020,10 @@ + /* + * Release all of the old mmap stuff + */ +- retval = exec_mmap(bprm->mm); ++ retval = exec_mmap(bprm); + if (retval) + goto mmap_failed; + +- bprm->mm = NULL; /* We're using it now */ +- + /* This is the point of no return */ + put_files_struct(files); + +@@ -1298,6 +1327,10 @@ + unsigned long env_p; + int retval; + ++ retval = virtinfo_gencall(VIRTINFO_DOEXECVE, NULL); ++ if (retval) ++ return retval; ++ + retval = -ENOMEM; + bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); + if (!bprm) +@@ -1349,6 +1382,11 @@ + goto out; + bprm->argv_len = env_p - bprm->p; + ++ if (!gr_tpe_allow(file)) { ++ retval = -EACCES; ++ goto out; ++ } ++ + retval = search_binary_handler(bprm,regs); + if (retval >= 0) { + /* execve success */ +@@ -1561,7 +1599,7 @@ + goto done; + + rcu_read_lock(); +- for_each_process(g) { ++ for_each_process_ve(g) { + if (g == tsk->group_leader) + continue; + +@@ -1695,7 +1733,7 @@ + /* + * If another thread got here first, or we are not dumpable, bail out. + */ +- if (mm->core_waiters || !get_dumpable(mm)) { ++ if (mm->core_waiters || !get_dumpable(mm) || mm->vps_dumpable != 1) { + up_write(&mm->mmap_sem); + goto fail; + } +Index: kernel/fs/ext2/namei.c +=================================================================== +--- kernel.orig/fs/ext2/namei.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/ext2/namei.c 2008-11-24 15:47:46.000000000 +0100 +@@ -31,6 +31,7 @@ + */ + + #include ++#include + #include "ext2.h" + #include "xattr.h" + #include "acl.h" +@@ -257,6 +258,8 @@ + struct page * page; + int err = -ENOENT; + ++ DQUOT_INIT(inode); ++ + de = ext2_find_entry (dir, dentry, &page); + if (!de) + goto out; +@@ -299,6 +302,9 @@ + struct ext2_dir_entry_2 * old_de; + int err = -ENOENT; + ++ if (new_inode) ++ DQUOT_INIT(new_inode); ++ + old_de = ext2_find_entry (old_dir, old_dentry, &old_page); + if (!old_de) + goto out; +Index: kernel/fs/ext2/super.c +=================================================================== +--- kernel.orig/fs/ext2/super.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/ext2/super.c 2008-11-24 15:47:46.000000000 +0100 +@@ -1377,7 +1377,7 @@ + .name = "ext2", + .get_sb = ext2_get_sb, + .kill_sb = kill_block_super, +- .fs_flags = FS_REQUIRES_DEV, ++ .fs_flags = FS_REQUIRES_DEV | FS_VIRTUALIZED, + }; + + static int __init init_ext2_fs(void) +Index: kernel/fs/ext3/ioctl.c +=================================================================== +--- kernel.orig/fs/ext3/ioctl.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/ext3/ioctl.c 2008-11-24 15:47:46.000000000 +0100 +@@ -79,7 +79,7 @@ + * the relevant capability. + */ + if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) { +- if (!capable(CAP_SYS_RESOURCE)) { ++ if (!capable(CAP_SYS_ADMIN)) { + mutex_unlock(&inode->i_mutex); + return -EPERM; + } +Index: kernel/fs/ext3/namei.c +=================================================================== +--- kernel.orig/fs/ext3/namei.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/ext3/namei.c 2008-11-24 15:47:46.000000000 +0100 +@@ -1355,7 +1355,7 @@ + if (err) + ext3_std_error(dir->i_sb, err); + brelse(bh); +- return 0; ++ return err; + } + + /* +Index: kernel/fs/ext3/super.c +=================================================================== +--- kernel.orig/fs/ext3/super.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/ext3/super.c 2008-11-24 15:47:46.000000000 +0100 +@@ -2869,7 +2869,7 @@ + .name = "ext3", + .get_sb = ext3_get_sb, + .kill_sb = kill_block_super, +- .fs_flags = FS_REQUIRES_DEV, ++ .fs_flags = FS_REQUIRES_DEV | FS_VIRTUALIZED, + }; + + static int __init init_ext3_fs(void) +Index: kernel/fs/ext4/ioctl.c +=================================================================== +--- kernel.orig/fs/ext4/ioctl.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/ext4/ioctl.c 2008-11-24 15:47:46.000000000 +0100 +@@ -79,7 +79,7 @@ + * the relevant capability. + */ + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { +- if (!capable(CAP_SYS_RESOURCE)) { ++ if (!capable(CAP_SYS_ADMIN)) { + mutex_unlock(&inode->i_mutex); + return -EPERM; + } +Index: kernel/fs/fcntl.c +=================================================================== +--- kernel.orig/fs/fcntl.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/fcntl.c 2008-11-24 15:47:46.000000000 +0100 +@@ -192,6 +192,7 @@ + fput(file); + goto out; + } ++EXPORT_SYMBOL_GPL(sys_dup2); + + asmlinkage long sys_dup(unsigned int fildes) + { +@@ -210,6 +211,9 @@ + struct inode * inode = filp->f_path.dentry->d_inode; + int error = 0; + ++ if (!capable(CAP_SYS_RAWIO) && !odirect_enable) ++ arg &= ~O_DIRECT; ++ + /* + * O_APPEND cannot be cleared if the file is marked as append-only + * and the file is open for write. +Index: kernel/fs/file.c +=================================================================== +--- kernel.orig/fs/file.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/file.c 2008-11-24 15:47:46.000000000 +0100 +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -18,6 +19,8 @@ + #include + #include + ++#include ++ + struct fdtable_defer { + spinlock_t lock; + struct work_struct wq; +@@ -35,9 +38,9 @@ + static inline void * alloc_fdmem(unsigned int size) + { + if (size <= PAGE_SIZE) +- return kmalloc(size, GFP_KERNEL); ++ return kmalloc(size, GFP_KERNEL_UBC); + else +- return vmalloc(size); ++ return ub_vmalloc(size); + } + + static inline void free_fdarr(struct fdtable *fdt) +@@ -150,7 +153,7 @@ + if (nr > NR_OPEN) + nr = NR_OPEN; + +- fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL); ++ fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL_UBC); + if (!fdt) + goto out; + fdt->max_fds = nr; +@@ -185,7 +188,7 @@ + * Return <0 error code on error; 1 on successful completion. + * The files->file_lock should be held on entry, and will be held on exit. + */ +-static int expand_fdtable(struct files_struct *files, int nr) ++int expand_fdtable(struct files_struct *files, int nr) + __releases(files->file_lock) + __acquires(files->file_lock) + { +@@ -215,6 +218,7 @@ + } + return 1; + } ++EXPORT_SYMBOL_GPL(expand_fdtable); + + /* + * Expand files. +Index: kernel/fs/file_table.c +=================================================================== +--- kernel.orig/fs/file_table.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/file_table.c 2008-11-24 15:47:46.000000000 +0100 +@@ -20,9 +20,14 @@ + #include + #include + #include ++#include + + #include + ++#include ++#include ++#include ++ + /* sysctl tunables... */ + struct files_stat_struct files_stat = { + .max_files = NR_FILE +@@ -36,12 +41,15 @@ + static inline void file_free_rcu(struct rcu_head *head) + { + struct file *f = container_of(head, struct file, f_u.fu_rcuhead); ++ put_ve(f->owner_env); + kmem_cache_free(filp_cachep, f); + } + + static inline void file_free(struct file *f) + { +- percpu_counter_dec(&nr_files); ++ if (f->f_ub == get_ub0()) ++ percpu_counter_dec(&nr_files); ++ ub_file_uncharge(f); + call_rcu(&f->f_u.fu_rcuhead, file_free_rcu); + } + +@@ -89,11 +97,14 @@ + struct task_struct *tsk; + static int old_max; + struct file * f; ++ int acct; + ++ acct = (get_exec_ub() == get_ub0()); + /* + * Privileged users can go above max_files + */ +- if (get_nr_files() >= files_stat.max_files && !capable(CAP_SYS_ADMIN)) { ++ if (acct && get_nr_files() >= files_stat.max_files && ++ !capable(CAP_SYS_ADMIN)) { + /* + * percpu_counters are inaccurate. Do an expensive check before + * we go and fail. +@@ -106,7 +117,13 @@ + if (f == NULL) + goto fail; + +- percpu_counter_inc(&nr_files); ++ if (ub_file_charge(f)) ++ goto fail_ch; ++ if (acct) ++ percpu_counter_inc(&nr_files); ++ ++ f->owner_env = get_ve(get_exec_env()); ++ + if (security_file_alloc(f)) + goto fail_sec; + +@@ -133,6 +150,10 @@ + file_free(f); + fail: + return NULL; ++ ++fail_ch: ++ kmem_cache_free(filp_cachep, f); ++ return NULL; + } + + EXPORT_SYMBOL(get_empty_filp); +Index: kernel/fs/filesystems.c +=================================================================== +--- kernel.orig/fs/filesystems.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/filesystems.c 2008-11-24 15:47:46.000000000 +0100 +@@ -12,6 +12,9 @@ + #include + #include + #include ++#include /* for 'current' */ ++#include ++#include + #include + + /* +@@ -21,8 +24,8 @@ + * During the unload module must call unregister_filesystem(). + * We can access the fields of list element if: + * 1) spinlock is held or +- * 2) we hold the reference to the module. +- * The latter can be guaranteed by call of try_module_get(); if it ++ * 2) we hold the reference to the element. ++ * The latter can be guaranteed by call of try_filesystem(); if it + * returned 0 we must skip the element, otherwise we got the reference. + * Once the reference is obtained we can drop the spinlock. + */ +@@ -30,24 +33,46 @@ + static struct file_system_type *file_systems; + static DEFINE_RWLOCK(file_systems_lock); + ++int try_get_filesystem(struct file_system_type *fs) ++{ ++ if (try_module_get(fs->owner)) { ++ (void)get_ve(fs->owner_env); ++ return 1; ++ } ++ return 0; ++} ++ + /* WARNING: This can be used only if we _already_ own a reference */ + void get_filesystem(struct file_system_type *fs) + { ++ (void)get_ve(fs->owner_env); + __module_get(fs->owner); + } + + void put_filesystem(struct file_system_type *fs) + { + module_put(fs->owner); ++ put_ve(fs->owner_env); ++} ++ ++static inline int check_ve_fstype(struct file_system_type *p, ++ struct ve_struct *env) ++{ ++ return ((p->fs_flags & FS_VIRTUALIZED) || ++ ve_accessible_strict(p->owner_env, env)); + } + +-static struct file_system_type **find_filesystem(const char *name, unsigned len) ++static struct file_system_type **find_filesystem(const char *name, unsigned len, ++ struct ve_struct *env) + { + struct file_system_type **p; +- for (p=&file_systems; *p; p=&(*p)->next) ++ for (p=&file_systems; *p; p=&(*p)->next) { ++ if (!check_ve_fstype(*p, env)) ++ continue; + if (strlen((*p)->name) == len && + strncmp((*p)->name, name, len) == 0) + break; ++ } + return p; + } + +@@ -73,8 +98,12 @@ + if (fs->next) + return -EBUSY; + INIT_LIST_HEAD(&fs->fs_supers); ++ if (fs->owner_env == NULL) ++ fs->owner_env = get_ve0(); ++ if (fs->proto == NULL) ++ fs->proto = fs; + write_lock(&file_systems_lock); +- p = find_filesystem(fs->name, strlen(fs->name)); ++ p = find_filesystem(fs->name, strlen(fs->name), fs->owner_env); + if (*p) + res = -EBUSY; + else +@@ -118,6 +147,75 @@ + + EXPORT_SYMBOL(unregister_filesystem); + ++#ifdef CONFIG_VE ++int register_ve_fs_type(struct ve_struct *ve, struct file_system_type *template, ++ struct file_system_type **p_fs_type, struct vfsmount **p_mnt) ++{ ++ struct vfsmount *mnt; ++ struct file_system_type *local_fs_type; ++ int ret; ++ ++ local_fs_type = kzalloc(sizeof(*local_fs_type) + sizeof(void *), ++ GFP_KERNEL); ++ if (local_fs_type == NULL) ++ return -ENOMEM; ++ ++ local_fs_type->name = template->name; ++ local_fs_type->fs_flags = template->fs_flags; ++ local_fs_type->get_sb = template->get_sb; ++ local_fs_type->kill_sb = template->kill_sb; ++ local_fs_type->owner = template->owner; ++ local_fs_type->owner_env = ve; ++ local_fs_type->proto = template; ++ ++ get_filesystem(local_fs_type); /* get_ve() inside */ ++ ++ ret = register_filesystem(local_fs_type); ++ if (ret) ++ goto reg_err; ++ ++ if (p_mnt == NULL) ++ goto done; ++ ++ mnt = vfs_kern_mount(local_fs_type, 0, local_fs_type->name, NULL); ++ if (IS_ERR(mnt)) ++ goto mnt_err; ++ ++ *p_mnt = mnt; ++done: ++ *p_fs_type = local_fs_type; ++ return 0; ++ ++mnt_err: ++ ret = PTR_ERR(mnt); ++ unregister_filesystem(local_fs_type); /* does not put */ ++ ++reg_err: ++ put_filesystem(local_fs_type); ++ kfree(local_fs_type); ++ printk(KERN_DEBUG ++ "register_ve_fs_type(\"%s\") err=%d\n", template->name, ret); ++ return ret; ++} ++ ++EXPORT_SYMBOL(register_ve_fs_type); ++ ++void unregister_ve_fs_type(struct file_system_type *local_fs_type, ++ struct vfsmount *local_fs_mount) ++{ ++ if (local_fs_mount == NULL && local_fs_type == NULL) ++ return; ++ ++ unregister_filesystem(local_fs_type); ++ umount_ve_fs_type(local_fs_type); ++ if (local_fs_mount) ++ kern_umount(local_fs_mount); /* alias to mntput, drop our ref */ ++ put_filesystem(local_fs_type); ++} ++ ++EXPORT_SYMBOL(unregister_ve_fs_type); ++#endif ++ + static int fs_index(const char __user * __name) + { + struct file_system_type * tmp; +@@ -131,11 +229,14 @@ + + err = -EINVAL; + read_lock(&file_systems_lock); +- for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) { ++ for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next) { ++ if (!check_ve_fstype(tmp, get_exec_env())) ++ continue; + if (strcmp(tmp->name,name) == 0) { + err = index; + break; + } ++ index++; + } + read_unlock(&file_systems_lock); + putname(name); +@@ -148,9 +249,15 @@ + int len, res; + + read_lock(&file_systems_lock); +- for (tmp = file_systems; tmp; tmp = tmp->next, index--) +- if (index <= 0 && try_module_get(tmp->owner)) +- break; ++ for (tmp = file_systems; tmp; tmp = tmp->next) { ++ if (!check_ve_fstype(tmp, get_exec_env())) ++ continue; ++ if (!index) { ++ if (try_get_filesystem(tmp)) ++ break; ++ } else ++ index--; ++ } + read_unlock(&file_systems_lock); + if (!tmp) + return -EINVAL; +@@ -168,8 +275,9 @@ + int index; + + read_lock(&file_systems_lock); +- for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++) +- ; ++ for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next) ++ if (check_ve_fstype(tmp, get_exec_env())) ++ index++; + read_unlock(&file_systems_lock); + return index; + } +@@ -205,9 +313,10 @@ + read_lock(&file_systems_lock); + tmp = file_systems; + while (tmp && len < PAGE_SIZE - 80) { +- len += sprintf(buf+len, "%s\t%s\n", +- (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", +- tmp->name); ++ if (check_ve_fstype(tmp, get_exec_env())) ++ len += sprintf(buf+len, "%s\t%s\n", ++ (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", ++ tmp->name); + tmp = tmp->next; + } + read_unlock(&file_systems_lock); +@@ -221,14 +330,14 @@ + unsigned len = dot ? dot - name : strlen(name); + + read_lock(&file_systems_lock); +- fs = *(find_filesystem(name, len)); +- if (fs && !try_module_get(fs->owner)) ++ fs = *(find_filesystem(name, len, get_exec_env())); ++ if (fs && !try_get_filesystem(fs)) + fs = NULL; + read_unlock(&file_systems_lock); + if (!fs && (request_module("%.*s", len, name) == 0)) { + read_lock(&file_systems_lock); +- fs = *(find_filesystem(name, len)); +- if (fs && !try_module_get(fs->owner)) ++ fs = *(find_filesystem(name, len, get_exec_env())); ++ if (fs && !try_get_filesystem(fs)) + fs = NULL; + read_unlock(&file_systems_lock); + } +@@ -241,3 +350,5 @@ + } + + EXPORT_SYMBOL(get_fs_type); ++EXPORT_SYMBOL(get_filesystem); ++EXPORT_SYMBOL(put_filesystem); +Index: kernel/fs/fuse/control.c +=================================================================== +--- kernel.orig/fs/fuse/control.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/fuse/control.c 2008-11-24 15:47:46.000000000 +0100 +@@ -10,6 +10,8 @@ + + #include + #include ++#include ++#include + + #define FUSE_CTL_SUPER_MAGIC 0x65735543 + +@@ -17,7 +19,11 @@ + * This is non-NULL when the single instance of the control filesystem + * exists. Protected by fuse_mutex + */ ++#ifdef CONFIG_VE ++#define fuse_control_sb (get_exec_env()->_fuse_control_sb) ++#else + static struct super_block *fuse_control_sb; ++#endif + + static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file) + { +@@ -211,12 +217,51 @@ + .kill_sb = fuse_ctl_kill_sb, + }; + ++#ifdef CONFIG_VE ++static int fuse_ctl_start(void *data) ++{ ++ struct ve_struct *ve; ++ ++ ve = (struct ve_struct *)data; ++ if (ve->fuse_ctl_fs_type != NULL) ++ return -EBUSY; ++ ++ return register_ve_fs_type(ve, &fuse_ctl_fs_type, ++ &ve->fuse_ctl_fs_type, NULL); ++} ++ ++static void fuse_ctl_stop(void *data) ++{ ++ struct ve_struct *ve; ++ ++ ve = (struct ve_struct *)data; ++ if (ve->fuse_ctl_fs_type == NULL) ++ return; ++ ++ unregister_ve_fs_type(ve->fuse_ctl_fs_type, NULL); ++ ve->fuse_ctl_fs_type = NULL; ++} ++ ++static struct ve_hook fuse_ctl_ve_hook = { ++ .init = fuse_ctl_start, ++ .fini = fuse_ctl_stop, ++ .owner = THIS_MODULE, ++ .priority = HOOK_PRIO_FS, ++}; ++#endif ++ + int __init fuse_ctl_init(void) + { +- return register_filesystem(&fuse_ctl_fs_type); ++ int err; ++ ++ err = register_filesystem(&fuse_ctl_fs_type); ++ if (err == 0) ++ ve_hook_register(VE_SS_CHAIN, &fuse_ctl_ve_hook); ++ return err; + } + + void fuse_ctl_cleanup(void) + { ++ ve_hook_unregister(&fuse_ctl_ve_hook); + unregister_filesystem(&fuse_ctl_fs_type); + } +Index: kernel/fs/fuse/fuse_i.h +=================================================================== +--- kernel.orig/fs/fuse/fuse_i.h 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/fuse/fuse_i.h 2008-11-24 15:47:46.000000000 +0100 +@@ -41,7 +41,11 @@ + #define FUSE_ALLOW_OTHER (1 << 1) + + /** List of active connections */ ++#ifdef CONFIG_VE ++#define fuse_conn_list (get_exec_env()->_fuse_conn_list) ++#else + extern struct list_head fuse_conn_list; ++#endif + + /** Global mutex protecting fuse_conn_list and the control filesystem */ + extern struct mutex fuse_mutex; +Index: kernel/fs/fuse/inode.c +=================================================================== +--- kernel.orig/fs/fuse/inode.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/fuse/inode.c 2008-11-24 15:47:46.000000000 +0100 +@@ -18,13 +18,16 @@ + #include + #include + #include ++#include + + MODULE_AUTHOR("Miklos Szeredi "); + MODULE_DESCRIPTION("Filesystem in Userspace"); + MODULE_LICENSE("GPL"); + + static struct kmem_cache *fuse_inode_cachep; ++#ifndef CONFIG_VE + struct list_head fuse_conn_list; ++#endif + DEFINE_MUTEX(fuse_mutex); + + #define FUSE_SUPER_MAGIC 0x65735546 +@@ -819,6 +822,41 @@ + subsystem_unregister(&fuse_subsys); + } + ++#ifdef CONFIG_VE ++static int fuse_start(void *data) ++{ ++ struct ve_struct *ve; ++ ++ ve = (struct ve_struct *)data; ++ if (ve->fuse_fs_type != NULL) ++ return -EBUSY; ++ ++ INIT_LIST_HEAD(&ve->_fuse_conn_list); ++ return register_ve_fs_type(ve, &fuse_fs_type, &ve->fuse_fs_type, NULL); ++} ++ ++static void fuse_stop(void *data) ++{ ++ struct ve_struct *ve; ++ ++ ve = (struct ve_struct *)data; ++ if (ve->fuse_fs_type == NULL) ++ return; ++ ++ unregister_ve_fs_type(ve->fuse_fs_type, NULL); ++ kfree(ve->fuse_fs_type); ++ ve->fuse_fs_type = NULL; ++ BUG_ON(!list_empty(&ve->_fuse_conn_list)); ++} ++ ++static struct ve_hook fuse_ve_hook = { ++ .init = fuse_start, ++ .fini = fuse_stop, ++ .owner = THIS_MODULE, ++ .priority = HOOK_PRIO_FS, ++}; ++#endif ++ + static int __init fuse_init(void) + { + int res; +@@ -843,6 +881,7 @@ + if (res) + goto err_sysfs_cleanup; + ++ ve_hook_register(VE_SS_CHAIN, &fuse_ve_hook); + return 0; + + err_sysfs_cleanup: +@@ -859,6 +898,7 @@ + { + printk(KERN_DEBUG "fuse exit\n"); + ++ ve_hook_unregister(&fuse_ve_hook); + fuse_ctl_cleanup(); + fuse_sysfs_cleanup(); + fuse_fs_cleanup(); +Index: kernel/fs/gfs2/glock.c +=================================================================== +--- kernel.orig/fs/gfs2/glock.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/gfs2/glock.c 2008-11-24 15:47:46.000000000 +0100 +@@ -8,6 +8,7 @@ + */ + + #include ++#include + #include + #include + #include +Index: kernel/fs/inode.c +=================================================================== +--- kernel.orig/fs/inode.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/inode.c 2008-11-24 15:47:46.000000000 +0100 +@@ -8,10 +8,13 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -22,6 +25,7 @@ + #include + #include + #include ++#include + + /* + * This is needed for the following functions: +@@ -97,7 +101,8 @@ + */ + struct inodes_stat_t inodes_stat; + +-static struct kmem_cache * inode_cachep __read_mostly; ++struct kmem_cache * inode_cachep __read_mostly; ++ + + static void wake_up_inode(struct inode *inode) + { +@@ -108,11 +113,13 @@ + wake_up_bit(&inode->i_state, __I_LOCK); + } + ++static struct address_space_operations vfs_empty_aops; ++struct inode_operations vfs_empty_iops; ++static struct file_operations vfs_empty_fops; ++EXPORT_SYMBOL(vfs_empty_iops); ++ + static struct inode *alloc_inode(struct super_block *sb) + { +- static const struct address_space_operations empty_aops; +- static struct inode_operations empty_iops; +- static const struct file_operations empty_fops; + struct inode *inode; + + if (sb->s_op->alloc_inode) +@@ -127,8 +134,8 @@ + inode->i_blkbits = sb->s_blocksize_bits; + inode->i_flags = 0; + atomic_set(&inode->i_count, 1); +- inode->i_op = &empty_iops; +- inode->i_fop = &empty_fops; ++ inode->i_op = &vfs_empty_iops; ++ inode->i_fop = &vfs_empty_fops; + inode->i_nlink = 1; + atomic_set(&inode->i_writecount, 0); + inode->i_size = 0; +@@ -152,15 +159,15 @@ + } + + spin_lock_init(&inode->i_lock); +- lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key); ++ lockdep_set_class(&inode->i_lock, &sb->s_type->proto->i_lock_key); + + mutex_init(&inode->i_mutex); +- lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key); ++ lockdep_set_class(&inode->i_mutex, &sb->s_type->proto->i_mutex_key); + + init_rwsem(&inode->i_alloc_sem); +- lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key); ++ lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->proto->i_alloc_sem_key); + +- mapping->a_ops = &empty_aops; ++ mapping->a_ops = &vfs_empty_aops; + mapping->host = inode; + mapping->flags = 0; + mapping_set_gfp_mask(mapping, GFP_HIGHUSER_PAGECACHE); +@@ -310,13 +317,76 @@ + spin_unlock(&inode_lock); + } + ++static void show_header(struct inode *inode) ++{ ++ struct super_block *sb = inode->i_sb; ++ ++ printk("VFS: Busy inodes after unmount. " ++ "sb = %p, fs type = %s, sb count = %d, " ++ "sb->s_root = %s\n", sb, ++ (sb->s_type != NULL) ? sb->s_type->name : "", ++ sb->s_count, ++ (sb->s_root != NULL) ? ++ (char *)sb->s_root->d_name.name : ""); ++} ++ ++static void show_inode(struct inode *inode) ++{ ++ struct dentry *d; ++ struct vfsmount *mnt; ++ int i; ++ ++ printk("inode = %p, inode->i_count = %d, " ++ "inode->i_nlink = %d, " ++ "inode->i_mode = %d, " ++ "inode->i_state = %ld, " ++ "inode->i_flags = %d, " ++ "inode->i_devices.next = %p, " ++ "inode->i_devices.prev = %p, " ++ "inode->i_ino = %ld\n", ++ inode, ++ atomic_read(&inode->i_count), ++ inode->i_nlink, ++ inode->i_mode, ++ inode->i_state, ++ inode->i_flags, ++ inode->i_devices.next, ++ inode->i_devices.prev, ++ inode->i_ino); ++ printk("inode dump: "); ++ for (i = 0; i < sizeof(*inode); i++) ++ printk("%2.2x ", *((u_char *)inode + i)); ++ printk("\n"); ++ list_for_each_entry(d, &inode->i_dentry, d_alias) { ++ printk(" d_alias %s d_count=%d d_flags=%x\n", ++ d->d_name.name, atomic_read(&d->d_count), d->d_flags); ++ for (i = 0; i < sizeof(*d); i++) ++ printk("%2.2x ", *((u_char *)d + i)); ++ printk("\n"); ++ } ++ ++ spin_lock(&vfsmount_lock); ++ list_for_each_entry(mnt, &get_task_mnt_ns(current)->list, mnt_list) { ++ if (mnt->mnt_sb != inode->i_sb) ++ continue; ++ printk("mnt=%p count=%d flags=%x exp_mask=%x\n", ++ mnt, atomic_read(&mnt->mnt_count), ++ mnt->mnt_flags, ++ mnt->mnt_expiry_mark); ++ for (i = 0; i < sizeof(*mnt); i++) ++ printk("%2.2x ", *((u_char *)mnt + i)); ++ printk("\n"); ++ } ++ spin_unlock(&vfsmount_lock); ++} ++ + /* + * Invalidate all inodes for a device. + */ +-static int invalidate_list(struct list_head *head, struct list_head *dispose) ++static int invalidate_list(struct list_head *head, struct list_head *dispose, int check) + { + struct list_head *next; +- int busy = 0, count = 0; ++ int busy = 0, count = 0, once = 1; + + next = head->next; + for (;;) { +@@ -343,6 +413,14 @@ + continue; + } + busy = 1; ++ ++ if (check) { ++ if (once) { ++ once = 0; ++ show_header(inode); ++ } ++ show_inode(inode); ++ } + } + /* only unused inodes may be cached with i_count zero */ + inodes_stat.nr_unused -= count; +@@ -357,7 +435,7 @@ + * fails because there are busy inodes then a non zero value is returned. + * If the discard is successful all the inodes have been discarded. + */ +-int invalidate_inodes(struct super_block * sb) ++int invalidate_inodes_check(struct super_block * sb, int check) + { + int busy; + LIST_HEAD(throw_away); +@@ -365,7 +443,7 @@ + mutex_lock(&iprune_mutex); + spin_lock(&inode_lock); + inotify_unmount_inodes(&sb->s_inodes); +- busy = invalidate_list(&sb->s_inodes, &throw_away); ++ busy = invalidate_list(&sb->s_inodes, &throw_away, check); + spin_unlock(&inode_lock); + + dispose_list(&throw_away); +@@ -374,7 +452,7 @@ + return busy; + } + +-EXPORT_SYMBOL(invalidate_inodes); ++EXPORT_SYMBOL(invalidate_inodes_check); + + static int can_unuse(struct inode *inode) + { +@@ -464,6 +542,7 @@ + */ + static int shrink_icache_memory(int nr, gfp_t gfp_mask) + { ++ KSTAT_PERF_ENTER(shrink_icache) + if (nr) { + /* + * Nasty deadlock avoidance. We may hold various FS locks, +@@ -474,6 +553,7 @@ + return -1; + prune_icache(nr); + } ++ KSTAT_PERF_LEAVE(shrink_icache) + return (inodes_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; + } + +@@ -585,7 +665,7 @@ + */ + mutex_destroy(&inode->i_mutex); + mutex_init(&inode->i_mutex); +- lockdep_set_class(&inode->i_mutex, &type->i_mutex_dir_key); ++ lockdep_set_class(&inode->i_mutex, &type->proto->i_mutex_dir_key); + } + #endif + /* +Index: kernel/fs/inotify.c +=================================================================== +--- kernel.orig/fs/inotify.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/inotify.c 2008-11-24 15:47:46.000000000 +0100 +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + static atomic_t inotify_cookie; + +@@ -69,19 +70,6 @@ + * inotify_add_watch() to the final put_inotify_watch(). + */ + +-/* +- * struct inotify_handle - represents an inotify instance +- * +- * This structure is protected by the mutex 'mutex'. +- */ +-struct inotify_handle { +- struct idr idr; /* idr mapping wd -> watch */ +- struct mutex mutex; /* protects this bad boy */ +- struct list_head watches; /* list of watches */ +- atomic_t count; /* reference count */ +- u32 last_wd; /* the last wd allocated */ +- const struct inotify_operations *in_ops; /* inotify caller operations */ +-}; + + static inline void get_inotify_handle(struct inotify_handle *ih) + { +@@ -118,6 +106,10 @@ + struct inotify_handle *ih = watch->ih; + + iput(watch->inode); ++ dput(watch->dentry); ++ mntput(watch->mnt); ++ watch->dentry = NULL; ++ watch->mnt = NULL; + ih->in_ops->destroy_watch(watch); + put_inotify_handle(ih); + } +@@ -476,6 +468,8 @@ + INIT_LIST_HEAD(&watch->i_list); + atomic_set(&watch->count, 0); + get_inotify_watch(watch); /* initial get */ ++ watch->dentry = NULL; ++ watch->mnt = NULL; + } + EXPORT_SYMBOL_GPL(inotify_init_watch); + +@@ -616,8 +610,10 @@ + * Caller must ensure it only calls inotify_add_watch() once per watch. + * Calls inotify_handle_get_wd() so may sleep. + */ +-s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch, +- struct inode *inode, u32 mask) ++s32 __inotify_add_watch(struct inotify_handle *ih, ++ struct inotify_watch *watch, ++ struct dentry *d, struct vfsmount *mnt, ++ struct inode * inode, u32 mask) + { + int ret = 0; + int newly_watched; +@@ -645,6 +641,10 @@ + * Save a reference to the inode and bump the ref count to make it + * official. We hold a reference to nameidata, which makes this safe. + */ ++ if (d) { ++ watch->dentry = dget(d); ++ watch->mnt = mntget(mnt); ++ } + watch->inode = igrab(inode); + + /* Add the watch to the handle's and the inode's list */ +@@ -666,6 +666,19 @@ + } + EXPORT_SYMBOL_GPL(inotify_add_watch); + ++s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch, ++ struct inode *inode, u32 mask) ++{ ++ return __inotify_add_watch(ih, watch, NULL, NULL, inode, mask); ++} ++ ++s32 inotify_add_watch_dget(struct inotify_handle *ih, ++ struct inotify_watch *watch, struct dentry *d, ++ struct vfsmount *mnt, u32 mask) ++{ ++ return __inotify_add_watch(ih, watch, d, mnt, d->d_inode, mask); ++} ++ + /** + * inotify_clone_watch - put the watch next to existing one + * @old: already installed watch +Index: kernel/fs/inotify_user.c +=================================================================== +--- kernel.orig/fs/inotify_user.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/inotify_user.c 2008-11-24 15:47:46.000000000 +0100 +@@ -20,6 +20,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -66,46 +67,6 @@ + * first event, or to inotify_destroy(). + */ + +-/* +- * struct inotify_device - represents an inotify instance +- * +- * This structure is protected by the mutex 'mutex'. +- */ +-struct inotify_device { +- wait_queue_head_t wq; /* wait queue for i/o */ +- struct mutex ev_mutex; /* protects event queue */ +- struct mutex up_mutex; /* synchronizes watch updates */ +- struct list_head events; /* list of queued events */ +- atomic_t count; /* reference count */ +- struct user_struct *user; /* user who opened this dev */ +- struct inotify_handle *ih; /* inotify handle */ +- unsigned int queue_size; /* size of the queue (bytes) */ +- unsigned int event_count; /* number of pending events */ +- unsigned int max_events; /* maximum number of events */ +-}; +- +-/* +- * struct inotify_kernel_event - An inotify event, originating from a watch and +- * queued for user-space. A list of these is attached to each instance of the +- * device. In read(), this list is walked and all events that can fit in the +- * buffer are returned. +- * +- * Protected by dev->ev_mutex of the device in which we are queued. +- */ +-struct inotify_kernel_event { +- struct inotify_event event; /* the user-space event */ +- struct list_head list; /* entry in inotify_device's list */ +- char *name; /* filename, if any */ +-}; +- +-/* +- * struct inotify_user_watch - our version of an inotify_watch, we add +- * a reference to the associated inotify_device. +- */ +-struct inotify_user_watch { +- struct inotify_device *dev; /* associated device */ +- struct inotify_watch wdata; /* inotify watch data */ +-}; + + #ifdef CONFIG_SYSCTL + +@@ -361,8 +322,8 @@ + * + * Callers must hold dev->up_mutex. + */ +-static int create_watch(struct inotify_device *dev, struct inode *inode, +- u32 mask) ++int inotify_create_watch(struct inotify_device *dev, struct dentry *d, ++ struct vfsmount *mnt, u32 mask) + { + struct inotify_user_watch *watch; + int ret; +@@ -382,12 +343,13 @@ + atomic_inc(&dev->user->inotify_watches); + + inotify_init_watch(&watch->wdata); +- ret = inotify_add_watch(dev->ih, &watch->wdata, inode, mask); ++ ret = inotify_add_watch_dget(dev->ih, &watch->wdata, d, mnt, mask); + if (ret < 0) + free_inotify_user_watch(&watch->wdata); + + return ret; + } ++EXPORT_SYMBOL(inotify_create_watch); + + /* Device Interface */ + +@@ -527,13 +489,14 @@ + return ret; + } + +-static const struct file_operations inotify_fops = { ++const struct file_operations inotify_fops = { + .poll = inotify_poll, + .read = inotify_read, + .release = inotify_release, + .unlocked_ioctl = inotify_ioctl, + .compat_ioctl = inotify_ioctl, + }; ++EXPORT_SYMBOL(inotify_fops); + + static const struct inotify_operations inotify_user_ops = { + .handle_event = inotify_dev_queue_event, +@@ -610,6 +573,7 @@ + put_unused_fd(fd); + return ret; + } ++EXPORT_SYMBOL(sys_inotify_init); + + asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) + { +@@ -646,7 +610,7 @@ + mutex_lock(&dev->up_mutex); + ret = inotify_find_update_watch(dev->ih, inode, mask); + if (ret == -ENOENT) +- ret = create_watch(dev, inode, mask); ++ ret = inotify_create_watch(dev, nd.dentry, nd.mnt, mask); + mutex_unlock(&dev->up_mutex); + + path_release(&nd); +Index: kernel/fs/ioprio.c +=================================================================== +--- kernel.orig/fs/ioprio.c 2008-11-18 01:19:45.000000000 +0100 ++++ kernel/fs/ioprio.c 2008-11-24 15:47:46.000000000 +0100 +@@ -26,6 +26,8 @@ + #include + #include + #include ++#include ++#include + + static int set_task_ioprio(struct task_struct *task, int ioprio) + { +@@ -61,8 +63,11 @@ + int data = IOPRIO_PRIO_DATA(ioprio); + struct task_struct *p, *g; + struct user_struct *user; +- struct pid *pgrp; + int ret; ++ struct pid *pgrp; ++ ++ if (!ve_is_super(get_exec_env())) ++ return -EPERM; + + switch (class) { + case IOPRIO_CLASS_RT: +@@ -122,17 +127,23 @@ + if (!user) + break; + +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + if (p->uid != who) + continue; + ret = set_task_ioprio(p, ioprio); + if (ret) + goto free_uid; +- } while_each_thread(g, p); ++ } while_each_thread_all(g, p); + free_uid: + if (who) + free_uid(user); + break; ++ case IOPRIO_WHO_UBC: ++ if (class != IOPRIO_CLASS_BE) ++ return -ERANGE; ++ ++ ret = bc_set_ioprio(who, data); ++ break; + default: + ret = -EINVAL; + } +@@ -175,9 +186,9 @@ + { + struct task_struct *g, *p; + struct user_struct *user; +- struct pid *pgrp; + int ret = -ESRCH; + int tmpio; ++ struct pid *pgrp; + + read_lock(&tasklist_lock); + switch (which) { +@@ -213,7 +224,7 @@ + if (!user) + break; + +- do_each_thread(g, p) { ++ do_each_thread_ve(g, p) { + if (p->uid != user->uid) + continue; + tmpio = get_task_ioprio(p); +@@ -223,7 +234,7 @@ + ret = tmpio; + else + ret = ioprio_best(ret, tmpio); +- } while_each_thread(g, p); ++ } while_each_thread_ve(g, p); + + if (who) + free_uid(user); +Index: kernel/fs/lockd/clntproc.c +=================================================================== +--- kernel.orig/fs/lockd/clntproc.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/lockd/clntproc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -159,6 +159,7 @@ + sigset_t oldset; + unsigned long flags; + int status, vers; ++ struct ve_struct *ve; + + vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1; + if (NFS_PROTO(inode)->version > 3) { +@@ -166,16 +167,19 @@ + return -ENOLCK; + } + ++ ve = set_exec_env(NFS_CLIENT(inode)->cl_xprt->owner_env); + rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr)); + host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers, + nfssrv->nfs_client->cl_hostname, + strlen(nfssrv->nfs_client->cl_hostname)); ++ status = -ENOLCK; + if (host == NULL) +- return -ENOLCK; ++ goto fail; + + call = nlm_alloc_call(host); ++ status = -ENOMEM; + if (call == NULL) +- return -ENOMEM; ++ goto fail; + + nlmclnt_locks_init_private(fl, host); + /* Set up the argument struct */ +@@ -217,6 +221,8 @@ + spin_unlock_irqrestore(¤t->sighand->siglock, flags); + + dprintk("lockd: clnt proc returns %d\n", status); ++fail: ++ (void)set_exec_env(ve); + return status; + } + EXPORT_SYMBOL(nlmclnt_proc); +Index: kernel/fs/lockd/host.c +=================================================================== +--- kernel.orig/fs/lockd/host.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/lockd/host.c 2008-11-24 15:47:46.000000000 +0100 +@@ -52,6 +52,7 @@ + struct nlm_host *host; + struct nsm_handle *nsm = NULL; + int hash; ++ struct ve_struct *ve; + + dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT + ", p=%d, v=%d, my role=%s, name=%.*s)\n", +@@ -77,10 +78,14 @@ + * different NLM rpc_clients into one single nlm_host object. + * This would allow us to have one nlm_host per address. + */ ++ ++ ve = get_exec_env(); + chain = &nlm_hosts[hash]; + hlist_for_each_entry(host, pos, chain, h_hash) { + if (!nlm_cmp_addr(&host->h_addr, sin)) + continue; ++ if (!ve_accessible_strict(host->owner_env, ve)) ++ continue; + + /* See if we have an NSM handle for this client */ + if (!nsm) +@@ -140,6 +145,7 @@ + spin_lock_init(&host->h_lock); + INIT_LIST_HEAD(&host->h_granted); + INIT_LIST_HEAD(&host->h_reclaim); ++ host->owner_env = ve; + + if (++nrhosts > NLM_HOST_MAX) + next_gc = 0; +@@ -440,6 +446,52 @@ + next_gc = jiffies + NLM_HOST_COLLECT; + } + ++#ifdef CONFIG_VE ++void ve_nlm_shutdown_hosts(struct ve_struct *ve) ++{ ++ envid_t veid = ve->veid; ++ int i; ++ ++ dprintk("lockd: shutting down host module for ve %d\n", veid); ++ mutex_lock(&nlm_host_mutex); ++ ++ /* Perform a garbage collection pass */ ++ for (i = 0; i < NLM_HOST_NRHASH; i++) { ++ struct nlm_host *host; ++ struct hlist_node *pos; ++ ++ hlist_for_each_entry(host, pos, &nlm_hosts[i], h_hash) { ++ struct rpc_clnt *clnt; ++ ++ if (ve != host->owner_env) ++ continue; ++ ++ hlist_del(&host->h_hash); ++ if (host->h_nsmhandle) ++ host->h_nsmhandle->sm_monitored = 0; ++ dprintk("lockd: delete host %s ve %d\n", host->h_name, ++ veid); ++ if ((clnt = host->h_rpcclnt) != NULL) { ++ if (!list_empty(&clnt->cl_tasks)) { ++ struct rpc_xprt *xprt; ++ ++ printk(KERN_WARNING ++ "lockd: active RPC handle\n"); ++ rpc_killall_tasks(clnt); ++ xprt = clnt->cl_xprt; ++ xprt_disconnect(xprt); ++ xprt->ops->close(xprt); ++ } else ++ rpc_shutdown_client(clnt); ++ } ++ kfree(host); ++ nrhosts--; ++ } ++ } ++ ++ mutex_unlock(&nlm_host_mutex); ++} ++#endif + + /* + * Manage NSM handles +Index: kernel/fs/lockd/svc.c +=================================================================== +--- kernel.orig/fs/lockd/svc.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/lockd/svc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -47,11 +48,12 @@ + EXPORT_SYMBOL(nlmsvc_ops); + + static DEFINE_MUTEX(nlmsvc_mutex); +-static unsigned int nlmsvc_users; +-static pid_t nlmsvc_pid; ++static unsigned int _nlmsvc_users; ++static pid_t _nlmsvc_pid; + static struct svc_serv *nlmsvc_serv; +-int nlmsvc_grace_period; +-unsigned long nlmsvc_timeout; ++int _nlmsvc_grace_period; ++unsigned long _nlmsvc_timeout; ++ + + static DECLARE_COMPLETION(lockd_start_done); + static DECLARE_WAIT_QUEUE_HEAD(lockd_exit); +@@ -179,8 +181,13 @@ + * recvfrom routine. + */ + err = svc_recv(rqstp, timeout); +- if (err == -EAGAIN || err == -EINTR) ++ if (err == -EAGAIN || err == -EINTR) { ++#ifdef CONFIG_VE ++ if (!get_exec_env()->is_running) ++ break; ++#endif + continue; ++ } + if (err < 0) { + printk(KERN_WARNING + "lockd: terminating on error %d\n", +@@ -494,6 +501,29 @@ + return SVC_DENIED; + } + ++#ifdef CONFIG_VE ++extern void ve_nlm_shutdown_hosts(struct ve_struct *ve); ++ ++static int ve_lockd_start(void *data) ++{ ++ return 0; ++} ++ ++static void ve_lockd_stop(void *data) ++{ ++ struct ve_struct *ve = (struct ve_struct *)data; ++ ++ ve_nlm_shutdown_hosts(ve); ++ flush_scheduled_work(); ++} ++ ++static struct ve_hook lockd_hook = { ++ .init = ve_lockd_start, ++ .fini = ve_lockd_stop, ++ .owner = THIS_MODULE, ++ .priority = HOOK_PRIO_FS, ++}; ++#endif + + param_set_min_max(port, int, simple_strtol, 0, 65535) + param_set_min_max(grace_period, unsigned long, simple_strtoul, +@@ -522,12 +552,14 @@ + static int __init init_nlm(void) + { + nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); ++ ve_hook_register(VE_SS_CHAIN, &lockd_hook); + return nlm_sysctl_table ? 0 : -ENOMEM; + } + + static void __exit exit_nlm(void) + { + /* FIXME: delete all NLM clients */ ++ ve_hook_unregister(&lockd_hook); + nlm_shutdown_hosts(); + unregister_sysctl_table(nlm_sysctl_table); + } +Index: kernel/fs/lockd/svcsubs.c +=================================================================== +--- kernel.orig/fs/lockd/svcsubs.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/lockd/svcsubs.c 2008-11-24 15:47:46.000000000 +0100 +@@ -318,6 +318,9 @@ + static int + nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy) + { ++ if (!ve_accessible_strict(host->owner_env, get_exec_env())) ++ return 0; ++ + if (host->h_server) { + /* we are destroying locks even though the client + * hasn't asked us too, so don't unmonitor the +Index: kernel/fs/locks.c +=================================================================== +--- kernel.orig/fs/locks.c 2008-11-24 14:18:06.000000000 +0100 ++++ kernel/fs/locks.c 2008-11-24 15:47:46.000000000 +0100 +@@ -129,6 +129,8 @@ + #include + #include + ++#include ++ + #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) + #define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK) + #define IS_LEASE(fl) (fl->fl_flags & FL_LEASE) +@@ -145,9 +147,25 @@ + static struct kmem_cache *filelock_cache __read_mostly; + + /* Allocate an empty lock structure. */ +-static struct file_lock *locks_alloc_lock(void) ++static struct file_lock *locks_alloc_lock(int charge) + { +- return kmem_cache_alloc(filelock_cache, GFP_KERNEL); ++ struct file_lock *fl; ++ ++ fl = kmem_cache_alloc(filelock_cache, GFP_KERNEL); ++#ifdef CONFIG_BEANCOUNTERS ++ if (fl == NULL) ++ goto out; ++ fl->fl_charged = 0; ++ if (!charge) ++ goto out; ++ if (!ub_flock_charge(fl, 1)) ++ goto out; ++ ++ kmem_cache_free(filelock_cache, fl); ++ fl = NULL; ++out: ++#endif ++ return fl; + } + + static void locks_release_private(struct file_lock *fl) +@@ -172,6 +190,7 @@ + BUG_ON(!list_empty(&fl->fl_block)); + BUG_ON(!list_empty(&fl->fl_link)); + ++ ub_flock_uncharge(fl); + locks_release_private(fl); + kmem_cache_free(filelock_cache, fl); + } +@@ -273,7 +292,7 @@ + if (type < 0) + return type; + +- fl = locks_alloc_lock(); ++ fl = locks_alloc_lock(type != F_UNLCK); + if (fl == NULL) + return -ENOMEM; + +@@ -460,7 +479,7 @@ + /* Allocate a file_lock initialised to this type of lease */ + static struct file_lock *lease_alloc(struct file *filp, int type) + { +- struct file_lock *fl = locks_alloc_lock(); ++ struct file_lock *fl = locks_alloc_lock(1); + int error = -ENOMEM; + + if (fl == NULL) +@@ -746,8 +765,13 @@ + goto find_conflict; + + if (request->fl_type != F_UNLCK) { ++ /* ++ * Nont F_UNLCK request must be already charged in ++ * flock_make_lock(). Actually new_fl must be charged not the ++ * request, but we try to fail earlier. ++ */ + error = -ENOMEM; +- new_fl = locks_alloc_lock(); ++ new_fl = locks_alloc_lock(0); + if (new_fl == NULL) + goto out; + error = 0; +@@ -797,6 +821,10 @@ + } + if (request->fl_flags & FL_ACCESS) + goto out; ++ ++ set_flock_charged(new_fl); ++ unset_flock_charged(request); ++ + locks_copy_lock(new_fl, request); + locks_insert_lock(before, new_fl); + new_fl = NULL; +@@ -828,8 +856,11 @@ + if (!(request->fl_flags & FL_ACCESS) && + (request->fl_type != F_UNLCK || + request->fl_start != 0 || request->fl_end != OFFSET_MAX)) { +- new_fl = locks_alloc_lock(); +- new_fl2 = locks_alloc_lock(); ++ if (request->fl_type != F_UNLCK) ++ new_fl = locks_alloc_lock(1); ++ else ++ new_fl = NULL; ++ new_fl2 = locks_alloc_lock(0); + } + + lock_kernel(); +@@ -963,7 +994,7 @@ + * bail out. + */ + error = -ENOLCK; /* "no luck" */ +- if (right && left == right && !new_fl2) ++ if (right && left == right && !(request->fl_type == F_UNLCK || new_fl2)) + goto out; + + error = 0; +@@ -974,23 +1005,32 @@ + goto out; + } + +- if (!new_fl) { +- error = -ENOLCK; ++ error = -ENOLCK; ++ if (!new_fl) ++ goto out; ++ if (right && (left == right) && ub_flock_charge(new_fl, 1)) + goto out; +- } + locks_copy_lock(new_fl, request); + locks_insert_lock(before, new_fl); + new_fl = NULL; ++ error = 0; + } + if (right) { + if (left == right) { + /* The new lock breaks the old one in two pieces, + * so we have to use the second new lock. + */ ++ error = -ENOLCK; ++ if (added && ub_flock_charge(new_fl2, ++ request->fl_type != F_UNLCK)) ++ goto out; ++ /* FIXME move all fl_charged manipulations in ub code */ ++ set_flock_charged(new_fl2); + left = new_fl2; + new_fl2 = NULL; + locks_copy_lock(left, right); + locks_insert_lock(before, left); ++ error = 0; + } + right->fl_start = request->fl_end + 1; + locks_wake_up_blocks(right); +@@ -1381,7 +1421,7 @@ + goto out; + + error = -ENOMEM; +- new_fl = locks_alloc_lock(); ++ new_fl = locks_alloc_lock(1); + if (new_fl == NULL) + goto out; + +@@ -1615,6 +1655,7 @@ + out: + return error; + } ++EXPORT_SYMBOL_GPL(sys_flock); + + /** + * vfs_test_lock - test file byte range lock +@@ -1635,7 +1676,7 @@ + + static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl) + { +- flock->l_pid = fl->fl_pid; ++ flock->l_pid = pid_to_vpid(fl->fl_pid); + #if BITS_PER_LONG == 32 + /* + * Make sure we can represent the posix lock via +@@ -1657,7 +1698,7 @@ + #if BITS_PER_LONG == 32 + static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl) + { +- flock->l_pid = fl->fl_pid; ++ flock->l_pid = pid_to_vpid(fl->fl_pid); + flock->l_start = fl->fl_start; + flock->l_len = fl->fl_end == OFFSET_MAX ? 0 : + fl->fl_end - fl->fl_start + 1; +@@ -1751,7 +1792,7 @@ + int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, + struct flock __user *l) + { +- struct file_lock *file_lock = locks_alloc_lock(); ++ struct file_lock *file_lock = locks_alloc_lock(0); + struct flock flock; + struct inode *inode; + struct file *f; +@@ -1888,7 +1929,7 @@ + int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, + struct flock64 __user *l) + { +- struct file_lock *file_lock = locks_alloc_lock(); ++ struct file_lock *file_lock = locks_alloc_lock(0); + struct flock64 flock; + struct inode *inode; + struct file *f; +@@ -2105,7 +2146,9 @@ + int id, char *pfx) + { + struct inode *inode = NULL; ++ unsigned int fl_pid; + ++ fl_pid = pid_to_vpid(fl->fl_pid); + if (fl->fl_file != NULL) + inode = fl->fl_file->f_path.dentry->d_inode; + +@@ -2145,16 +2188,16 @@ + } + if (inode) { + #ifdef WE_CAN_BREAK_LSLK_NOW +- seq_printf(f, "%d %s:%ld ", fl->fl_pid, ++ seq_printf(f, "%d %s:%ld ", fl_pid, + inode->i_sb->s_id, inode->i_ino); + #else + /* userspace relies on this representation of dev_t ;-( */ +- seq_printf(f, "%d %02x:%02x:%ld ", fl->fl_pid, ++ seq_printf(f, "%d %02x:%02x:%ld ", fl_pid, + MAJOR(inode->i_sb->s_dev), + MINOR(inode->i_sb->s_dev), inode->i_ino); + #endif + } else { +- seq_printf(f, "%d :0 ", fl->fl_pid); ++ seq_printf(f, "%d :0 ", fl_pid); + } + if (IS_POSIX(fl)) { + if (fl->fl_end == OFFSET_MAX) +@@ -2171,6 +2214,8 @@ + struct file_lock *fl, *bfl; + + fl = list_entry(v, struct file_lock, fl_link); ++ if (!ve_accessible(fl->fl_file->owner_env, get_exec_env())) ++ goto out; + + lock_get_status(f, fl, (long)f->private, ""); + +@@ -2178,6 +2223,7 @@ + lock_get_status(f, bfl, (long)f->private, " ->"); + + f->private++; ++out: + return 0; + } + +@@ -2287,7 +2333,7 @@ + static int __init filelock_init(void) + { + filelock_cache = kmem_cache_create("file_lock_cache", +- sizeof(struct file_lock), 0, SLAB_PANIC, ++ sizeof(struct file_lock), 0, SLAB_PANIC|SLAB_UBC, + init_once); + return 0; + } +Index: kernel/fs/mpage.c +=================================================================== +--- kernel.orig/fs/mpage.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/mpage.c 2008-11-24 15:47:46.000000000 +0100 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + /* + * I/O completion handler for multipage BIOs. +Index: kernel/fs/namei.c +=================================================================== +--- kernel.orig/fs/namei.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/namei.c 2008-11-24 15:47:46.000000000 +0100 +@@ -141,6 +141,7 @@ + { + char *tmp, *result; + ++ /*ub_dentry_checkup();*/ + result = ERR_PTR(-ENOMEM); + tmp = __getname(); + if (tmp) { +@@ -434,6 +435,21 @@ + if (!dentry) + dentry = d_lookup(parent, name); + ++ /* ++ * The revalidation rules are simple: ++ * d_revalidate operation is called when we're about to use a cached ++ * dentry rather than call d_lookup. ++ * d_revalidate method may unhash the dentry itself or return FALSE, in ++ * which case if the dentry can be released d_lookup will be called. ++ * ++ * Additionally, by request of NFS people ++ * (http://linux.bkbits.net:8080/linux-2.4/cset@1.181?nav=index.html|src/|src/fs|related/fs/namei.c) ++ * d_revalidate is called when `/', `.' or `..' are looked up. ++ * Since re-lookup is impossible on them, we introduce a hack and ++ * return an error in this case. ++ * ++ * 2003/02/19 SAW ++ */ + if (dentry && dentry->d_op && dentry->d_op->d_revalidate) + dentry = do_revalidate(dentry, nd); + +@@ -493,6 +509,7 @@ + struct dentry * result; + struct inode *dir = parent->d_inode; + ++repeat: + mutex_lock(&dir->i_mutex); + /* + * First re-do the cached lookup just in case it was created +@@ -539,7 +556,7 @@ + if (result->d_op && result->d_op->d_revalidate) { + result = do_revalidate(result, nd); + if (!result) +- result = ERR_PTR(-ENOENT); ++ goto repeat; + } + return result; + } +@@ -765,6 +782,13 @@ + read_unlock(&fs->lock); + break; + } ++#ifdef CONFIG_VE ++ if (nd->dentry == get_exec_env()->fs_root && ++ nd->mnt == get_exec_env()->fs_rootmnt) { ++ read_unlock(¤t->fs->lock); ++ break; ++ } ++#endif + read_unlock(&fs->lock); + spin_lock(&dcache_lock); + if (nd->dentry != nd->mnt->mnt_root) { +@@ -806,6 +830,10 @@ + if (dentry->d_op && dentry->d_op->d_revalidate) + goto need_revalidate; + done: ++ if ((nd->flags & LOOKUP_STRICT) && d_mountpoint(dentry)) { ++ dput(dentry); ++ return -ENOENT; ++ } + path->mnt = mnt; + path->dentry = dentry; + __follow_mount(path); +@@ -843,6 +871,7 @@ + struct inode *inode; + int err; + unsigned int lookup_flags = nd->flags; ++ int real_components = 0; + + while (*name=='/') + name++; +@@ -912,6 +941,7 @@ + break; + } + /* This does the actual lookups.. */ ++ real_components++; + err = do_lookup(nd, &this, &next); + if (err) + break; +@@ -925,6 +955,9 @@ + goto out_dput; + + if (inode->i_op->follow_link) { ++ err = -ENOENT; ++ if (lookup_flags & LOOKUP_STRICT) ++ goto out_dput; + err = do_follow_link(&next, nd); + if (err) + goto return_err; +@@ -972,6 +1005,7 @@ + break; + inode = next.dentry->d_inode; + if ((lookup_flags & LOOKUP_FOLLOW) ++ && !(lookup_flags & LOOKUP_STRICT) + && inode && inode->i_op && inode->i_op->follow_link) { + err = do_follow_link(&next, nd); + if (err) +@@ -993,26 +1027,40 @@ + nd->last_type = LAST_NORM; + if (this.name[0] != '.') + goto return_base; +- if (this.len == 1) ++ if (this.len == 1) { + nd->last_type = LAST_DOT; +- else if (this.len == 2 && this.name[1] == '.') ++ goto return_reval; ++ } else if (this.len == 2 && this.name[1] == '.') { + nd->last_type = LAST_DOTDOT; +- else +- goto return_base; ++ goto return_reval; ++ } ++return_base: ++ if (!(nd->flags & LOOKUP_NOAREACHECK)) { ++ err = check_area_access_ve(nd->dentry, nd->mnt); ++ if (err) ++ break; ++ } ++ return 0; + return_reval: + /* + * We bypassed the ordinary revalidation routines. + * We may need to check the cached dentry for staleness. + */ +- if (nd->dentry && nd->dentry->d_sb && ++ if (!real_components && nd->dentry && nd->dentry->d_sb && + (nd->dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) { + err = -ESTALE; + /* Note: we do not d_invalidate() */ + if (!nd->dentry->d_op->d_revalidate(nd->dentry, nd)) ++ /* ++ * This lookup is for `/' or `.' or `..'. ++ * The filesystem unhashed the dentry itself ++ * inside d_revalidate (otherwise, d_invalidate ++ * wouldn't succeed). As a special courtesy to ++ * NFS we return an error. 2003/02/19 SAW ++ */ + break; + } +-return_base: +- return 0; ++ goto return_base; + out_dput: + dput_path(&next, nd); + break; +@@ -2019,6 +2067,7 @@ + { + return sys_mknodat(AT_FDCWD, filename, mode, dev); + } ++EXPORT_SYMBOL_GPL(sys_mknod); + + int vfs_mkdir(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt, + int mode) +@@ -2080,6 +2129,7 @@ + { + return sys_mkdirat(AT_FDCWD, pathname, mode); + } ++EXPORT_SYMBOL_GPL(sys_mkdir); + + /* + * We try to drop the dentry early: we should have +@@ -2107,6 +2157,7 @@ + spin_unlock(&dentry->d_lock); + spin_unlock(&dcache_lock); + } ++EXPORT_SYMBOL(sys_symlink); + + int vfs_rmdir(struct inode *dir, struct dentry *dentry,struct vfsmount *mnt) + { +@@ -2188,6 +2239,7 @@ + { + return do_rmdir(AT_FDCWD, pathname); + } ++EXPORT_SYMBOL_GPL(sys_rmdir); + + int vfs_unlink(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt) + { +@@ -2287,6 +2339,7 @@ + { + return do_unlinkat(AT_FDCWD, pathname); + } ++EXPORT_SYMBOL_GPL(sys_unlink); + + int vfs_symlink(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt, + const char *oldname, int mode) +@@ -2451,6 +2504,7 @@ + { + return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0); + } ++EXPORT_SYMBOL(sys_rename); + + /* + * The worst of all namespace operations - renaming directory. "Perverted" +@@ -2567,6 +2621,9 @@ + int is_dir = S_ISDIR(old_dentry->d_inode->i_mode); + const char *old_name; + ++ if (DQUOT_RENAME(old_dentry->d_inode, old_dir, new_dir)) ++ return -EXDEV; ++ + if (old_dentry->d_inode == new_dentry->d_inode) + return 0; + +Index: kernel/fs/namespace.c +=================================================================== +--- kernel.orig/fs/namespace.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/namespace.c 2008-11-24 15:47:46.000000000 +0100 +@@ -32,6 +32,7 @@ + + /* spinlock for vfsmount related operations, inplace of dcache_lock */ + __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); ++EXPORT_SYMBOL(vfsmount_lock); + + static int event; + +@@ -57,6 +58,7 @@ + { + struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); + if (mnt) { ++ mnt->owner = VEID(get_exec_env()); + atomic_set(&mnt->mnt_count, 1); + INIT_LIST_HEAD(&mnt->mnt_hash); + INIT_LIST_HEAD(&mnt->mnt_child); +@@ -68,7 +70,7 @@ + INIT_LIST_HEAD(&mnt->mnt_slave); + if (name) { + int size = strlen(name) + 1; +- char *newname = kmalloc(size, GFP_KERNEL); ++ char *newname = kmalloc(size, GFP_KERNEL_UBC); + if (newname) { + memcpy(newname, name, size); + mnt->mnt_devname = newname; +@@ -344,10 +346,33 @@ + seq_escape(m, s, " \t\n\\"); + } + ++static int prepare_mnt_root_mangle(struct vfsmount *mnt, ++ char **path_buf, char **path) ++{ ++ /* skip FS_NOMOUNT mounts (rootfs) */ ++ if (mnt->mnt_sb->s_flags & MS_NOUSER) ++ return -EACCES; ++ ++ *path_buf = (char *)__get_free_page(GFP_KERNEL); ++ if (!*path_buf) ++ return -ENOMEM; ++ ++ *path = d_path(mnt->mnt_root, mnt, *path_buf, PAGE_SIZE); ++ if (IS_ERR(*path)) { ++ free_page((unsigned long)*path_buf); ++ /* ++ * This means that the file position will be incremented, i.e. ++ * the total number of "invisible" vfsmnt will leak. ++ */ ++ return -EACCES; ++ } ++ return 0; ++} ++ + static int show_vfsmnt(struct seq_file *m, void *v) + { + struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); +- int err = 0; ++ int err; + static struct proc_fs_info { + int flag; + char *str; +@@ -367,10 +392,20 @@ + { 0, NULL } + }; + struct proc_fs_info *fs_infop; ++ char *path_buf, *path; + +- mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); ++ err = prepare_mnt_root_mangle(mnt, &path_buf, &path); ++ if (err < 0) ++ return (err == -EACCES ? 0 : err); ++ ++ if (ve_is_super(get_exec_env()) || ++ !(mnt->mnt_sb->s_type->fs_flags & FS_MANGLE_PROC)) ++ mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); ++ else ++ mangle(m, mnt->mnt_sb->s_type->name); + seq_putc(m, ' '); +- seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); ++ mangle(m, path); ++ free_page((unsigned long) path_buf); + seq_putc(m, ' '); + mangle(m, mnt->mnt_sb->s_type->name); + if (mnt->mnt_sb->s_subtype && mnt->mnt_sb->s_subtype[0]) { +@@ -402,18 +437,27 @@ + static int show_vfsstat(struct seq_file *m, void *v) + { + struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); +- int err = 0; ++ char *path_buf, *path; ++ int err; ++ ++ err = prepare_mnt_root_mangle(mnt, &path_buf, &path); ++ if (err < 0) ++ return (err == -EACCES ? 0 : err); + + /* device */ + if (mnt->mnt_devname) { + seq_puts(m, "device "); +- mangle(m, mnt->mnt_devname); ++ if (ve_is_super(get_exec_env())) ++ mangle(m, mnt->mnt_devname); ++ else ++ mangle(m, mnt->mnt_sb->s_type->name); + } else + seq_puts(m, "no device"); + + /* mount point */ + seq_puts(m, " mounted on "); +- seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); ++ mangle(m, path); ++ free_page((unsigned long)path_buf); + seq_putc(m, ' '); + + /* file system type */ +@@ -512,6 +556,7 @@ + mntput(mnt); + } + } ++EXPORT_SYMBOL(release_mounts); + + void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) + { +@@ -534,6 +579,7 @@ + change_mnt_propagation(p, MS_PRIVATE); + } + } ++EXPORT_SYMBOL(umount_tree); + + static int do_umount(struct vfsmount *mnt, int flags) + { +@@ -621,6 +667,34 @@ + return retval; + } + ++#ifdef CONFIG_VE ++void umount_ve_fs_type(struct file_system_type *local_fs_type) ++{ ++ struct vfsmount *mnt; ++ struct list_head *p, *q; ++ LIST_HEAD(kill); ++ LIST_HEAD(umount_list); ++ ++ down_write(&namespace_sem); ++ spin_lock(&vfsmount_lock); ++ list_for_each_safe(p, q, ¤t->nsproxy->mnt_ns->list) { ++ mnt = list_entry(p, struct vfsmount, mnt_list); ++ if (mnt->mnt_sb->s_type != local_fs_type) ++ continue; ++ list_del(p); ++ list_add(p, &kill); ++ } ++ ++ while (!list_empty(&kill)) { ++ mnt = list_entry(kill.next, struct vfsmount, mnt_list); ++ umount_tree(mnt, 1, &umount_list); ++ } ++ spin_unlock(&vfsmount_lock); ++ up_write(&namespace_sem); ++ release_mounts(&umount_list); ++} ++#endif ++ + /* + * Now umount can handle mount points as well as block devices. + * This is important for filesystems which use unnamed block devices. +@@ -644,7 +718,7 @@ + goto dput_and_out; + + retval = -EPERM; +- if (!capable(CAP_SYS_ADMIN)) ++ if (!capable(CAP_VE_SYS_ADMIN)) + goto dput_and_out; + + retval = do_umount(nd.mnt, flags); +@@ -668,7 +742,7 @@ + + static int mount_is_safe(struct nameidata *nd) + { +- if (capable(CAP_SYS_ADMIN)) ++ if (capable(CAP_VE_SYS_ADMIN)) + return 0; + return -EPERM; + #ifdef notyet +@@ -907,6 +981,8 @@ + + if (nd->dentry != nd->mnt->mnt_root) + return -EINVAL; ++ if (!ve_accessible_veid(nd->mnt->owner, get_exec_env()->veid)) ++ return -EPERM; + + down_write(&namespace_sem); + spin_lock(&vfsmount_lock); +@@ -920,7 +996,8 @@ + /* + * do loopback mount. + */ +-static int do_loopback(struct nameidata *nd, char *old_name, int recurse) ++static int do_loopback(struct nameidata *nd, char *old_name, int recurse, ++ int mnt_flags) + { + struct nameidata old_nd; + struct vfsmount *mnt = NULL; +@@ -950,6 +1027,7 @@ + if (!mnt) + goto out; + ++ mnt->mnt_flags |= mnt_flags; + err = graft_tree(mnt, nd); + if (err) { + LIST_HEAD(umount_list); +@@ -975,8 +1053,9 @@ + { + int err; + struct super_block *sb = nd->mnt->mnt_sb; ++ int bind; + +- if (!capable(CAP_SYS_ADMIN)) ++ if (!capable(CAP_VE_SYS_ADMIN)) + return -EPERM; + + if (!check_mnt(nd->mnt)) +@@ -985,12 +1064,23 @@ + if (nd->dentry != nd->mnt->mnt_root) + return -EINVAL; + ++ if (!ve_accessible_veid(nd->mnt->owner, get_exec_env()->veid)) ++ return -EPERM; ++ ++ /* do not allow to remount bind-mounts with another mountpoint flags */ ++ bind = 0; ++ if (nd->dentry != sb->s_root) { ++ if ((flags & ~(MS_BIND|MS_POSIXACL|MS_NOUSER)) != 0) ++ return -EINVAL; ++ bind = 1; ++ } ++ + down_write(&sb->s_umount); +- err = do_remount_sb(sb, flags, data, 0); ++ err = bind ? 0 : do_remount_sb(sb, flags, data, 0); + if (!err) + nd->mnt->mnt_flags = mnt_flags; + up_write(&sb->s_umount); +- if (!err) ++ if (!err && !bind) + security_sb_post_remount(nd->mnt, flags, data); + return err; + } +@@ -1010,7 +1100,7 @@ + struct nameidata old_nd, parent_nd; + struct vfsmount *p; + int err = 0; +- if (!capable(CAP_SYS_ADMIN)) ++ if (!capable(CAP_VE_SYS_ADMIN)) + return -EPERM; + if (!old_name || !*old_name) + return -EINVAL; +@@ -1018,6 +1108,10 @@ + if (err) + return err; + ++ err = -EPERM; ++ if (!ve_accessible_veid(old_nd.mnt->owner, get_exec_env()->veid)) ++ goto out_nosem; ++ + down_write(&namespace_sem); + while (d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) + ; +@@ -1073,6 +1167,7 @@ + up_write(&namespace_sem); + if (!err) + path_release(&parent_nd); ++out_nosem: + path_release(&old_nd); + return err; + } +@@ -1090,7 +1185,7 @@ + return -EINVAL; + + /* we need capabilities... */ +- if (!capable(CAP_SYS_ADMIN)) ++ if (!capable(CAP_VE_SYS_ADMIN)) + return -EPERM; + + mnt = do_kern_mount(type, flags, name, data); +@@ -1129,6 +1224,10 @@ + + newmnt->mnt_flags = mnt_flags; + ++ /* make this before graft_tree reveals mnt_root to the world... */ ++ if (nd->dentry->d_flags & DCACHE_VIRTUAL) ++ newmnt->mnt_root->d_flags |= DCACHE_VIRTUAL; ++ + if ((err = graft_tree(newmnt, nd))) + goto unlock; + +@@ -1471,7 +1570,7 @@ + retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, + data_page); + else if (flags & MS_BIND) +- retval = do_loopback(&nd, dev_name, flags & MS_REC); ++ retval = do_loopback(&nd, dev_name, flags & MS_REC, mnt_flags); + else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) + retval = do_change_type(&nd, flags); + else if (flags & MS_MOVE) +@@ -1613,6 +1712,7 @@ + free_page(type_page); + return retval; + } ++EXPORT_SYMBOL_GPL(sys_mount); + + /* + * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. +@@ -1664,7 +1764,7 @@ + struct fs_struct *fs; + + read_lock(&tasklist_lock); +- do_each_thread(g, p) { ++ do_each_thread_ve(g, p) { + task_lock(p); + fs = p->fs; + if (fs) { +@@ -1679,7 +1779,7 @@ + put_fs_struct(fs); + } else + task_unlock(p); +- } while_each_thread(g, p); ++ } while_each_thread_ve(g, p); + read_unlock(&tasklist_lock); + } + +@@ -1846,7 +1946,7 @@ + init_rwsem(&namespace_sem); + + mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount), +- 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); ++ 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_UBC, NULL); + + mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); + +@@ -1908,6 +2008,7 @@ + release_mounts(&umount_list); + kfree(ns); + } ++EXPORT_SYMBOL_GPL(__put_mnt_ns); + + char *d_namespace_path(struct dentry *dentry, struct vfsmount *vfsmnt, + char *buf, int buflen) +@@ -1926,7 +2027,7 @@ + mntput(rootmnt); + if (nsrootmnt) + root = dget(nsrootmnt->mnt_root); +- res = __d_path(dentry, vfsmnt, root, nsrootmnt, buf, buflen, 1); ++ res = __d_path(dentry, vfsmnt, root, nsrootmnt, buf, buflen); + dput(root); + mntput(nsrootmnt); + /* Prevent empty path for lazily unmounted filesystems. */ +Index: kernel/fs/nfs/client.c +=================================================================== +--- kernel.orig/fs/nfs/client.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/nfs/client.c 2008-11-24 15:47:46.000000000 +0100 +@@ -116,6 +116,7 @@ + + atomic_set(&clp->cl_count, 1); + clp->cl_cons_state = NFS_CS_INITING; ++ clp->owner_env = get_exec_env(); + + clp->cl_nfsversion = nfsversion; + memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); +@@ -210,7 +211,9 @@ + static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion, int match_port) + { + struct nfs_client *clp; ++ struct ve_struct *ve; + ++ ve = get_exec_env(); + list_for_each_entry(clp, &nfs_client_list, cl_share_link) { + /* Don't match clients that failed to initialise properly */ + if (clp->cl_cons_state < 0) +@@ -220,6 +223,9 @@ + if (clp->cl_nfsversion != nfsversion) + continue; + ++ if (!ve_accessible_strict(clp->owner_env, ve)) ++ continue; ++ + if (memcmp(&clp->cl_addr.sin_addr, &addr->sin_addr, + sizeof(clp->cl_addr.sin_addr)) != 0) + continue; +Index: kernel/fs/nfs/super.c +=================================================================== +--- kernel.orig/fs/nfs/super.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/nfs/super.c 2008-11-24 15:47:46.000000000 +0100 +@@ -48,6 +48,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include + #include +@@ -208,7 +211,8 @@ + .name = "nfs", + .get_sb = nfs_get_sb, + .kill_sb = nfs_kill_super, +- .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, ++ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT| ++ FS_BINARY_MOUNTDATA|FS_VIRTUALIZED, + }; + + struct file_system_type nfs_xdev_fs_type = { +@@ -216,7 +220,8 @@ + .name = "nfs", + .get_sb = nfs_xdev_get_sb, + .kill_sb = nfs_kill_super, +- .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, ++ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT| ++ FS_BINARY_MOUNTDATA|FS_VIRTUALIZED, + }; + + static const struct super_operations nfs_sops = { +@@ -280,6 +285,55 @@ + .seeks = DEFAULT_SEEKS, + }; + ++#ifdef CONFIG_VE ++static int ve_nfs_start(void *data) ++{ ++ return 0; ++} ++ ++static void ve_nfs_stop(void *data) ++{ ++ struct ve_struct *ve; ++ struct super_block *sb; ++ ++ flush_scheduled_work(); ++ ++ ve = (struct ve_struct *)data; ++ /* Basically, on a valid stop we can be here iff NFS was mounted ++ read-only. In such a case client force-stop is not a problem. ++ If we are here and NFS is read-write, we are in a FORCE stop, so ++ force the client to stop. ++ Lock daemon is already dead. ++ Only superblock client remains. Den */ ++ spin_lock(&sb_lock); ++ list_for_each_entry(sb, &super_blocks, s_list) { ++ struct rpc_clnt *clnt; ++ struct rpc_xprt *xprt; ++ if (sb->s_type != &nfs_fs_type) ++ continue; ++ clnt = NFS_SB(sb)->client; ++ if (!ve_accessible_strict(clnt->cl_xprt->owner_env, ve)) ++ continue; ++ clnt->cl_broken = 1; ++ rpc_killall_tasks(clnt); ++ ++ xprt = clnt->cl_xprt; ++ xprt_disconnect(xprt); ++ xprt->ops->close(xprt); ++ } ++ spin_unlock(&sb_lock); ++ ++ flush_scheduled_work(); ++} ++ ++static struct ve_hook nfs_hook = { ++ .init = ve_nfs_start, ++ .fini = ve_nfs_stop, ++ .owner = THIS_MODULE, ++ .priority = HOOK_PRIO_NET_POST, ++}; ++#endif ++ + /* + * Register the NFS filesystems + */ +@@ -300,6 +354,7 @@ + goto error_2; + #endif + register_shrinker(&acl_shrinker); ++ ve_hook_register(VE_SS_CHAIN, &nfs_hook); + return 0; + + #ifdef CONFIG_NFS_V4 +@@ -318,6 +373,7 @@ + void __exit unregister_nfs_fs(void) + { + unregister_shrinker(&acl_shrinker); ++ ve_hook_unregister(&nfs_hook); + #ifdef CONFIG_NFS_V4 + unregister_filesystem(&nfs4_fs_type); + #endif +@@ -561,6 +617,9 @@ + struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb); + struct rpc_clnt *rpc; + ++ /* ++ * FIXME - think over wether this is OK ++ */ + shrink_submounts(vfsmnt, &nfs_automount_list); + + if (!(flags & MNT_FORCE)) +@@ -1353,6 +1412,11 @@ + .mntflags = flags, + }; + int error; ++ struct ve_struct *ve; ++ ++ ve = get_exec_env(); ++ if (!ve_is_super(ve) && !(get_exec_env()->features & VE_FEATURE_NFS)) ++ return -ENODEV; + + /* Validate the mount data */ + error = nfs_validate_mount_data(raw_data, &data, &mntfh, dev_name); +Index: kernel/fs/open.c +=================================================================== +--- kernel.orig/fs/open.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/open.c 2008-11-24 15:47:46.000000000 +0100 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -49,7 +50,21 @@ + + EXPORT_SYMBOL(vfs_statfs); + +-static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf) ++int faudit_statfs(struct super_block *sb, struct kstatfs *buf) ++{ ++ struct faudit_statfs_arg arg; ++ ++ arg.sb = sb; ++ arg.stat = buf; ++ ++ if (virtinfo_notifier_call(VITYPE_FAUDIT, VIRTINFO_FAUDIT_STATFS, &arg) ++ != NOTIFY_DONE) ++ return arg.err; ++ return 0; ++} ++ ++static int vfs_statfs_native(struct dentry *dentry, struct vfsmount *mnt, ++ struct statfs *buf) + { + struct kstatfs st; + int retval; +@@ -58,6 +73,10 @@ + if (retval) + return retval; + ++ retval = faudit_statfs(mnt->mnt_sb, &st); ++ if (retval) ++ return retval; ++ + if (sizeof(*buf) == sizeof(st)) + memcpy(buf, &st, sizeof(st)); + else { +@@ -92,7 +111,8 @@ + return 0; + } + +-static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf) ++static int vfs_statfs64(struct dentry *dentry, struct vfsmount *mnt, ++ struct statfs64 *buf) + { + struct kstatfs st; + int retval; +@@ -101,6 +121,10 @@ + if (retval) + return retval; + ++ retval = faudit_statfs(mnt->mnt_sb, &st); ++ if (retval) ++ return retval; ++ + if (sizeof(*buf) == sizeof(st)) + memcpy(buf, &st, sizeof(st)); + else { +@@ -127,7 +151,7 @@ + error = user_path_walk(path, &nd); + if (!error) { + struct statfs tmp; +- error = vfs_statfs_native(nd.dentry, &tmp); ++ error = vfs_statfs_native(nd.dentry, nd.mnt, &tmp); + if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) + error = -EFAULT; + path_release(&nd); +@@ -146,7 +170,7 @@ + error = user_path_walk(path, &nd); + if (!error) { + struct statfs64 tmp; +- error = vfs_statfs64(nd.dentry, &tmp); ++ error = vfs_statfs64(nd.dentry, nd.mnt, &tmp); + if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) + error = -EFAULT; + path_release(&nd); +@@ -165,7 +189,7 @@ + file = fget(fd); + if (!file) + goto out; +- error = vfs_statfs_native(file->f_path.dentry, &tmp); ++ error = vfs_statfs_native(file->f_path.dentry, file->f_path.mnt, &tmp); + if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) + error = -EFAULT; + fput(file); +@@ -186,7 +210,7 @@ + file = fget(fd); + if (!file) + goto out; +- error = vfs_statfs64(file->f_path.dentry, &tmp); ++ error = vfs_statfs64(file->f_path.dentry, file->f_path.mnt, &tmp); + if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) + error = -EFAULT; + fput(file); +@@ -589,15 +613,20 @@ + return err; + } + +-asmlinkage long sys_fchmodat(int dfd, const char __user *filename, +- mode_t mode) ++static long do_fchmodat(int dfd, const char __user *filename, mode_t mode, ++ int flags) + { + struct nameidata nd; + struct inode * inode; +- int error; ++ int error = -EINVAL; + struct iattr newattrs; ++ int follow; ++ ++ if ((flags & ~AT_SYMLINK_NOFOLLOW) != 0) ++ goto out; + +- error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); ++ follow = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; ++ error = __user_walk_fd(dfd, filename, follow, &nd); + if (error) + goto out; + inode = nd.dentry->d_inode; +@@ -624,6 +653,12 @@ + return error; + } + ++asmlinkage long sys_fchmodat(int dfd, const char __user *filename, ++ mode_t mode) ++{ ++ return do_fchmodat(dfd, filename, mode, 0); ++} ++ + asmlinkage long sys_chmod(const char __user *filename, mode_t mode) + { + return sys_fchmodat(AT_FDCWD, filename, mode); +@@ -681,6 +716,7 @@ + out: + return error; + } ++EXPORT_SYMBOL_GPL(sys_chown); + + asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, + gid_t group, int flag) +@@ -898,6 +934,7 @@ + return filp; + } + ++int odirect_enable = 0; + /* + * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an + * error. +@@ -907,6 +944,9 @@ + int error; + struct file *f; + ++ if (!capable(CAP_SYS_RAWIO) && !odirect_enable) ++ flags &= ~O_DIRECT; ++ + error = -ENFILE; + f = get_empty_filp(); + if (f == NULL) { +@@ -1196,3 +1236,8 @@ + } + + EXPORT_SYMBOL(nonseekable_open); ++ ++asmlinkage long sys_lchmod(char __user * filename, mode_t mode) ++{ ++ return do_fchmodat(AT_FDCWD, filename, mode, AT_SYMLINK_NOFOLLOW); ++} +Index: kernel/fs/partitions/check.c +=================================================================== +--- kernel.orig/fs/partitions/check.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/partitions/check.c 2008-11-24 15:47:46.000000000 +0100 +@@ -130,6 +130,7 @@ + + return buf; + } ++EXPORT_SYMBOL(disk_name); + + const char *bdevname(struct block_device *bdev, char *buf) + { +Index: kernel/fs/pipe.c +=================================================================== +--- kernel.orig/fs/pipe.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/pipe.c 2008-11-24 15:47:46.000000000 +0100 +@@ -21,6 +21,8 @@ + #include + #include + ++#include ++ + /* + * We use a start+len construction, which provides full use of the + * allocated memory. +@@ -477,7 +479,7 @@ + int error, atomic = 1; + + if (!page) { +- page = alloc_page(GFP_HIGHUSER); ++ page = alloc_page(GFP_HIGHUSER | __GFP_UBC); + if (unlikely(!page)) { + ret = ret ? : -ENOMEM; + break; +@@ -857,7 +859,7 @@ + { + struct pipe_inode_info *pipe; + +- pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); ++ pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL_UBC); + if (pipe) { + init_waitqueue_head(&pipe->wait); + pipe->r_counter = pipe->w_counter = 1; +@@ -1075,6 +1077,8 @@ + return error; + } + ++EXPORT_SYMBOL_GPL(do_pipe); ++ + /* + * pipefs should _never_ be mounted by userland - too much of security hassle, + * no real gain from having the whole whorehouse mounted. So we don't need +Index: kernel/fs/proc/array.c +=================================================================== +--- kernel.orig/fs/proc/array.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/proc/array.c 2008-11-24 15:47:46.000000000 +0100 +@@ -79,6 +79,9 @@ + #include + #include + ++#include ++ ++#include + #include + #include + #include "internal.h" +@@ -203,6 +206,19 @@ + put_group_info(group_info); + + buffer += sprintf(buffer, "\n"); ++ ++#ifdef CONFIG_VE ++ if (ve_is_super(get_exec_env())) ++ buffer += sprintf(buffer, ++ "envID:\t%d\n" ++ "VPid:\t%d\n" ++ "PNState:\t%u\n" ++ "StopState:\t%u\n", ++ p->ve_task_info.owner_env->veid, ++ task_pid_vnr(p), ++ p->pn_state, ++ p->stopped_state); ++#endif + return buffer; + } + +@@ -246,10 +262,10 @@ + } + } + +-static inline char *task_sig(struct task_struct *p, char *buffer) ++char *task_sig(struct task_struct *p, char *buffer) + { + unsigned long flags; +- sigset_t pending, shpending, blocked, ignored, caught; ++ sigset_t pending, shpending, blocked, ignored, caught, saved; + int num_threads = 0; + unsigned long qsize = 0; + unsigned long qlim = 0; +@@ -259,12 +275,14 @@ + sigemptyset(&blocked); + sigemptyset(&ignored); + sigemptyset(&caught); ++ sigemptyset(&saved); + + rcu_read_lock(); + if (lock_task_sighand(p, &flags)) { + pending = p->pending.signal; + shpending = p->signal->shared_pending.signal; + blocked = p->blocked; ++ saved = p->saved_sigmask; + collect_sigign_sigcatch(p, &ignored, &caught); + num_threads = atomic_read(&p->signal->count); + qsize = atomic_read(&p->user->sigpending); +@@ -282,6 +300,7 @@ + buffer = render_sigset_t("SigBlk:\t", &blocked, buffer); + buffer = render_sigset_t("SigIgn:\t", &ignored, buffer); + buffer = render_sigset_t("SigCgt:\t", &caught, buffer); ++ buffer = render_sigset_t("SigSvd:\t", &saved, buffer); + + return buffer; + } +@@ -296,6 +315,20 @@ + cap_t(p->cap_effective)); + } + ++#ifdef CONFIG_BEANCOUNTERS ++static inline void ub_dump_task_info(struct task_struct *tsk, ++ char *stsk, int ltsk, char *smm, int lmm) ++{ ++ print_ub_uid(tsk->task_bc.task_ub, stsk, ltsk); ++ task_lock(tsk); ++ if (tsk->mm) ++ print_ub_uid(tsk->mm->mm_ub, smm, lmm); ++ else ++ strncpy(smm, "N/A", lmm); ++ task_unlock(tsk); ++} ++#endif ++ + static inline char *task_context_switch_counts(struct task_struct *p, + char *buffer) + { +@@ -309,6 +342,9 @@ + { + char *orig = buffer; + struct mm_struct *mm = get_task_mm(task); ++#ifdef CONFIG_BEANCOUNTERS ++ char tsk_ub_info[64], mm_ub_info[64]; ++#endif + + buffer = task_name(task, buffer); + buffer = task_state(task, buffer); +@@ -324,6 +360,14 @@ + buffer = task_show_regs(task, buffer); + #endif + buffer = task_context_switch_counts(task, buffer); ++#ifdef CONFIG_BEANCOUNTERS ++ ub_dump_task_info(task, ++ tsk_ub_info, sizeof(tsk_ub_info), ++ mm_ub_info, sizeof(mm_ub_info)); ++ ++ buffer += sprintf(buffer, "TaskUB:\t%s\n", tsk_ub_info); ++ buffer += sprintf(buffer, "MMUB:\t%s\n", mm_ub_info); ++#endif + return buffer - orig; + } + +@@ -406,6 +450,10 @@ + char tcomm[sizeof(task->comm)]; + unsigned long flags; + struct pid_namespace *ns; ++#ifdef CONFIG_BEANCOUNTERS ++ char ub_task_info[64]; ++ char ub_mm_info[64]; ++#endif + + ns = current->nsproxy->pid_ns; + +@@ -486,6 +534,7 @@ + priority = task_prio(task); + nice = task_nice(task); + ++#ifndef CONFIG_VE + /* Temporary variable needed for gcc-2.96 */ + /* convert timespec -> nsec*/ + start_time = +@@ -493,10 +542,25 @@ + + task->real_start_time.tv_nsec; + /* convert nsec -> ticks */ + start_time = nsec_to_clock_t(start_time); ++#else ++ start_time = ve_relative_clock(&task->start_time); ++#endif ++ ++#ifdef CONFIG_BEANCOUNTERS ++ ub_dump_task_info(task, ub_task_info, sizeof(ub_task_info), ++ ub_mm_info, sizeof(ub_mm_info)); ++#endif + + res = sprintf(buffer, "%d (%s) %c %d %d %d %d %d %u %lu \ + %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ +-%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n", ++%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld" ++#ifdef CONFIG_VE ++ " 0 0 0 0 0 0 0 %d %u" ++#endif ++#ifdef CONFIG_BEANCOUNTERS ++ " %s %s" ++#endif ++ "\n", + task_pid_nr_ns(task, ns), + tcomm, + state, +@@ -543,7 +607,16 @@ + task->policy, + (unsigned long long)delayacct_blkio_ticks(task), + cputime_to_clock_t(gtime), +- cputime_to_clock_t(cgtime)); ++ cputime_to_clock_t(cgtime) ++#ifdef CONFIG_VE ++ , task_pid_vnr(task), ++ VEID(VE_TASK_INFO(task)->owner_env) ++#endif ++#ifdef CONFIG_BEANCOUNTERS ++ , ub_task_info, ++ ub_mm_info ++#endif ++ ); + if (mm) + mmput(mm); + return res; +Index: kernel/fs/proc/base.c +=================================================================== +--- kernel.orig/fs/proc/base.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/proc/base.c 2008-11-24 15:47:46.000000000 +0100 +@@ -165,8 +165,11 @@ + } + if (fs) { + read_lock(&fs->lock); +- *mnt = mntget(fs->pwdmnt); +- *dentry = dget(fs->pwd); ++ result = d_root_check(fs->pwd, fs->pwdmnt); ++ if (result == 0) { ++ *mnt = mntget(fs->pwdmnt); ++ *dentry = dget(fs->pwd); ++ } + read_unlock(&fs->lock); + result = 0; + put_fs_struct(fs); +@@ -477,17 +480,19 @@ + static int proc_fd_access_allowed(struct inode *inode) + { + struct task_struct *task; +- int allowed = 0; ++ int err; ++ + /* Allow access to a task's file descriptors if it is us or we + * may use ptrace attach to the process and find out that + * information. + */ ++ err = -ENOENT; + task = get_proc_task(inode); + if (task) { +- allowed = ptrace_may_attach(task); ++ err = (ptrace_may_attach(task) ? 0 : -EACCES); + put_task_struct(task); + } +- return allowed; ++ return err; + } + + static int proc_setattr(struct dentry *dentry, struct iattr *attr) +@@ -916,6 +921,8 @@ + if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) && + oom_adjust != OOM_DISABLE) + return -EINVAL; ++ if (oom_adjust == OOM_DISABLE && !ve_is_super(get_exec_env())) ++ return -EPERM; + if (*end == '\n') + end++; + task = get_proc_task(file->f_path.dentry->d_inode); +@@ -1159,13 +1166,14 @@ + static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) + { + struct inode *inode = dentry->d_inode; +- int error = -EACCES; ++ int error; + + /* We don't need a base pointer in the /proc filesystem */ + path_release(nd); + + /* Are we allowed to snoop on the tasks file descriptors? */ +- if (!proc_fd_access_allowed(inode)) ++ error = proc_fd_access_allowed(inode); ++ if (error < 0) + goto out; + + error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt); +@@ -1203,13 +1211,14 @@ + + static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int buflen) + { +- int error = -EACCES; ++ int error; + struct inode *inode = dentry->d_inode; + struct dentry *de; + struct vfsmount *mnt = NULL; + + /* Are we allowed to snoop on the tasks file descriptors? */ +- if (!proc_fd_access_allowed(inode)) ++ error = proc_fd_access_allowed(inode); ++ if (error < 0) + goto out; + + error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt); +@@ -1253,6 +1262,10 @@ + struct inode * inode; + struct proc_inode *ei; + ++ if (!ve_accessible(task->ve_task_info.owner_env, ++ sb->s_type->owner_env)) ++ return NULL; ++ + /* We need a new inode */ + + inode = new_inode(sb); +@@ -1452,6 +1465,9 @@ + struct files_struct *files = NULL; + struct file *file; + int fd = proc_fd(inode); ++ int err; ++ ++ err = -ENOENT; + + if (task) { + files = get_files_struct(task); +@@ -1464,7 +1480,9 @@ + */ + spin_lock(&files->file_lock); + file = fcheck_files(files, fd); +- if (file) { ++ err = -EACCES; ++ if (file && !d_root_check(file->f_path.dentry, ++ file->f_path.mnt)) { + if (mnt) + *mnt = mntget(file->f_path.mnt); + if (dentry) +@@ -1482,7 +1500,7 @@ + spin_unlock(&files->file_lock); + put_files_struct(files); + } +- return -ENOENT; ++ return err; + } + + static int proc_fd_link(struct inode *inode, struct dentry **dentry, +Index: kernel/fs/proc/generic.c +=================================================================== +--- kernel.orig/fs/proc/generic.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/proc/generic.c 2008-11-24 15:47:46.000000000 +0100 +@@ -10,6 +10,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -33,7 +34,7 @@ + + DEFINE_SPINLOCK(proc_subdir_lock); + +-static int proc_match(int len, const char *name, struct proc_dir_entry *de) ++int proc_match(int len, const char *name, struct proc_dir_entry *de) + { + if (de->namelen != len) + return 0; +@@ -239,6 +240,10 @@ + struct proc_dir_entry *de = PDE(inode); + int error; + ++ if ((iattr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) && ++ LPDE(inode) == GPDE(inode)) ++ return -EPERM; ++ + error = inode_change_ok(inode, iattr); + if (error) + goto out; +@@ -247,9 +252,12 @@ + if (error) + goto out; + +- de->uid = inode->i_uid; +- de->gid = inode->i_gid; +- de->mode = inode->i_mode; ++ if (iattr->ia_valid & ATTR_UID) ++ de->uid = inode->i_uid; ++ if (iattr->ia_valid & ATTR_GID) ++ de->gid = inode->i_gid; ++ if (iattr->ia_valid & ATTR_MODE) ++ de->mode = inode->i_mode; + out: + return error; + } +@@ -275,7 +283,7 @@ + * returns the struct proc_dir_entry for "/proc/tty/driver", and + * returns "serial" in residual. + */ +-static int xlate_proc_name(const char *name, ++static int __xlate_proc_name(struct proc_dir_entry *root, const char *name, + struct proc_dir_entry **ret, const char **residual) + { + const char *cp = name, *next; +@@ -283,8 +291,13 @@ + int len; + int rtn = 0; + ++ if (*ret) { ++ de_get(*ret); ++ return 0; ++ } ++ + spin_lock(&proc_subdir_lock); +- de = &proc_root; ++ de = root; + while (1) { + next = strchr(cp, '/'); + if (!next) +@@ -302,12 +315,29 @@ + cp += len + 1; + } + *residual = cp; +- *ret = de; ++ *ret = de_get(de); + out: + spin_unlock(&proc_subdir_lock); + return rtn; + } + ++#ifndef CONFIG_VE ++#define xlate_proc_loc_name xlate_proc_name ++#else ++static int xlate_proc_loc_name(const char *name, ++ struct proc_dir_entry **ret, const char **residual) ++{ ++ return __xlate_proc_name(get_exec_env()->proc_root, ++ name, ret, residual); ++} ++#endif ++ ++static int xlate_proc_name(const char *name, ++ struct proc_dir_entry **ret, const char **residual) ++{ ++ return __xlate_proc_name(&proc_root, name, ret, residual); ++} ++ + static DEFINE_IDR(proc_inum_idr); + static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ + +@@ -379,6 +409,22 @@ + .d_delete = proc_delete_dentry, + }; + ++static struct proc_dir_entry *__proc_lookup(struct proc_dir_entry *dir, ++ struct dentry *d) ++{ ++ struct proc_dir_entry *de; ++ ++ for (de = dir->subdir; de; de = de->next) { ++ if (de->namelen != d->d_name.len) ++ continue; ++ if (!memcmp(d->d_name.name, de->name, de->namelen)) ++ break; ++ } ++ if (de && de->shadow_proc) ++ de = de->shadow_proc(current, de); ++ return de_get(de); ++} ++ + /* + * Don't create negative dentries here, return -ENOENT by hand + * instead. +@@ -386,41 +432,121 @@ + struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) + { + struct inode *inode = NULL; +- struct proc_dir_entry * de; ++ struct proc_dir_entry *lde, *gde; + int error = -ENOENT; + + lock_kernel(); + spin_lock(&proc_subdir_lock); +- de = PDE(dir); +- if (de) { +- for (de = de->subdir; de ; de = de->next) { +- if (de->namelen != dentry->d_name.len) +- continue; +- if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { +- unsigned int ino; +- +- if (de->shadow_proc) +- de = de->shadow_proc(current, de); +- ino = de->low_ino; +- de_get(de); +- spin_unlock(&proc_subdir_lock); +- error = -EINVAL; +- inode = proc_get_inode(dir->i_sb, ino, de); +- spin_lock(&proc_subdir_lock); +- break; +- } +- } +- } ++ lde = LPDE(dir); ++ if (lde) ++ lde = __proc_lookup(lde, dentry); ++ if (lde && !try_module_get(lde->owner)) { ++ de_put(lde); ++ lde = NULL; ++ } ++#ifdef CONFIG_VE ++ gde = GPDE(dir); ++ if (gde) ++ gde = __proc_lookup(gde, dentry); ++ if (!lde && gde && !try_module_get(gde->owner)) { ++ de_put(gde); ++ gde = NULL; ++ } ++#else ++ gde = NULL; ++#endif + spin_unlock(&proc_subdir_lock); ++ ++ /* ++ * There are following possible cases after lookup: ++ * ++ * lde gde ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * NULL NULL ENOENT ++ * loc NULL found in local tree ++ * loc glob found in both trees ++ * NULL glob found in global tree ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * We initialized inode as follows after lookup: ++ * ++ * inode->lde inode->gde ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * loc NULL in local tree ++ * loc glob both trees ++ * glob glob global tree ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * i.e. inode->lde is always initialized ++ */ ++ ++ if (lde == NULL && gde == NULL) ++ goto out; ++ ++ if (lde != NULL) { ++ de_get(lde); ++ inode = proc_get_inode(dir->i_sb, lde->low_ino, lde); ++ } else { ++ de_get(gde); ++ inode = proc_get_inode(dir->i_sb, gde->low_ino, gde); ++ } ++ ++ /* ++ * We can sleep in proc_get_inode(), but since we have i_sem ++ * being taken, no one can setup GPDE/LPDE on this inode. ++ */ ++ if (!inode) ++ goto out_put; ++ ++#ifdef CONFIG_VE ++ GPDE(inode) = de_get(gde); ++ if (gde) ++ __module_get(gde->owner); ++ ++ /* if dentry is found in both trees and it is a directory ++ * then inode's nlink count must be altered, because local ++ * and global subtrees may differ. ++ * on the other hand, they may intersect, so actual nlink ++ * value is difficult to calculate - upper estimate is used ++ * instead of it. ++ * dentry found in global tree only must not be writable ++ * in non-super ve. ++ */ ++ if (lde && gde && lde != gde && gde->nlink > 1) ++ inode->i_nlink += gde->nlink - 2; ++ if (lde == NULL && !ve_is_super(dir->i_sb->s_type->owner_env)) ++ inode->i_mode &= ~S_IWUGO; ++#endif ++ unlock_kernel(); ++ dentry->d_op = &proc_dentry_operations; ++ d_add(dentry, inode); ++ de_put(lde); ++ de_put(gde); ++ return NULL; ++ ++out_put: ++ if (lde) ++ module_put(lde->owner); ++ else ++ module_put(gde->owner); ++ de_put(lde); ++ de_put(gde); ++out: + unlock_kernel(); ++ return ERR_PTR(error); ++} + +- if (inode) { +- dentry->d_op = &proc_dentry_operations; +- d_add(dentry, inode); +- return NULL; ++static inline int in_tree(struct proc_dir_entry *de, struct proc_dir_entry *dir) ++{ ++ struct proc_dir_entry *gde; ++ ++ for (gde = dir->subdir; gde; gde = gde->next) { ++ if (de->namelen != gde->namelen) ++ continue; ++ if (memcmp(de->name, gde->name, gde->namelen)) ++ continue; ++ return 1; + } +- de_put(de); +- return ERR_PTR(error); ++ return 0; + } + + /* +@@ -470,11 +596,8 @@ + de = de->subdir; + i -= 2; + for (;;) { +- if (!de) { +- ret = 1; +- spin_unlock(&proc_subdir_lock); +- goto out; +- } ++ if (!de) ++ goto chk_global; + if (!i) + break; + de = de->next; +@@ -487,8 +610,9 @@ + /* filldir passes info to user space */ + de_get(de); + spin_unlock(&proc_subdir_lock); +- if (filldir(dirent, de->name, de->namelen, filp->f_pos, +- de->low_ino, de->mode >> 12) < 0) { ++ if (filldir(dirent, de->name, de->namelen, ++ filp->f_pos, de->low_ino, ++ de->mode >> 12) < 0) { + de_put(de); + goto out; + } +@@ -498,6 +622,44 @@ + de_put(de); + de = next; + } while (de); ++chk_global: ++#ifdef CONFIG_VE ++ de = GPDE(inode); ++ if (de == NULL) ++ goto done; ++ ++ de = de->subdir; ++ while (de) { ++ struct proc_dir_entry *tmp; ++ ++ /* skip local names */ ++ if (in_tree(de, LPDE(inode))) { ++ de = de->next; ++ continue; ++ } ++ ++ if (i > 0) { ++ i--; ++ de = de->next; ++ continue; ++ } ++ ++ de_get(de); ++ spin_unlock(&proc_subdir_lock); ++ if (filldir(dirent, de->name, de->namelen, ++ filp->f_pos, de->low_ino, ++ de->mode >> 12) < 0) { ++ de_put(de); ++ goto out; ++ } ++ spin_lock(&proc_subdir_lock); ++ tmp = de->next; ++ de_put(de); ++ filp->f_pos++; ++ de = tmp; ++ } ++done: ++#endif + spin_unlock(&proc_subdir_lock); + } + ret = 1; +@@ -551,7 +713,7 @@ + + spin_lock(&proc_subdir_lock); + dp->next = dir->subdir; +- dp->parent = dir; ++ dp->parent = de_get(dir); + dir->subdir = dp; + spin_unlock(&proc_subdir_lock); + +@@ -570,17 +732,18 @@ + /* make sure name is valid */ + if (!name || !strlen(name)) goto out; + +- if (!(*parent) && xlate_proc_name(name, parent, &fn) != 0) ++ if (xlate_proc_loc_name(name, parent, &fn) != 0) + goto out; + + /* At this point there must not be any '/' characters beyond *fn */ + if (strchr(fn, '/')) +- goto out; ++ goto out_put; + + len = strlen(fn); + + ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL); +- if (!ent) goto out; ++ if (!ent) ++ goto out_put; + + memset(ent, 0, sizeof(struct proc_dir_entry)); + memcpy(((char *) ent) + sizeof(struct proc_dir_entry), fn, len + 1); +@@ -592,8 +755,12 @@ + ent->pde_users = 0; + spin_lock_init(&ent->pde_unload_lock); + ent->pde_unload_completion = NULL; +- out: + return ent; ++ ++out_put: ++ de_put(*parent); ++out: ++ return NULL; + } + + struct proc_dir_entry *proc_symlink(const char *name, +@@ -617,6 +784,7 @@ + kfree(ent); + ent = NULL; + } ++ de_put(parent); + } + return ent; + } +@@ -632,6 +800,7 @@ + kfree(ent); + ent = NULL; + } ++ de_put(parent); + } + return ent; + } +@@ -666,9 +835,28 @@ + kfree(ent); + ent = NULL; + } ++ de_put(parent); + } + return ent; + } ++EXPORT_SYMBOL(remove_proc_glob_entry); ++ ++struct proc_dir_entry *create_proc_glob_entry(const char *name, mode_t mode, ++ struct proc_dir_entry *parent) ++{ ++ const char *path; ++ struct proc_dir_entry *ent; ++ ++ path = name; ++ if (xlate_proc_name(path, &parent, &name) != 0) ++ return NULL; ++ ++ ent = create_proc_entry(name, mode, parent); ++ de_put(parent); ++ return ent; ++} ++ ++EXPORT_SYMBOL(create_proc_glob_entry); + + void free_proc_entry(struct proc_dir_entry *de) + { +@@ -687,15 +875,13 @@ + /* + * Remove a /proc entry and free it if it's not currently in use. + */ +-void remove_proc_entry(const char *name, struct proc_dir_entry *parent) ++static void __remove_proc_entry(const char *name, struct proc_dir_entry *parent) + { + struct proc_dir_entry **p; + struct proc_dir_entry *de; + const char *fn = name; + int len; + +- if (!parent && xlate_proc_name(name, &parent, &fn) != 0) +- goto out; + len = strlen(fn); + + spin_lock(&proc_subdir_lock); +@@ -734,11 +920,42 @@ + parent->nlink--; + de->nlink = 0; + WARN_ON(de->subdir); +- if (atomic_dec_and_test(&de->count)) +- free_proc_entry(de); ++ de_put(parent); ++ de_put(de); + break; + } + spin_unlock(&proc_subdir_lock); +-out: +- return; ++} ++ ++void remove_proc_loc_entry(const char *name, struct proc_dir_entry *parent) ++{ ++ const char *path; ++ ++ path = name; ++ if (xlate_proc_loc_name(path, &parent, &name) != 0) ++ return; ++ ++ __remove_proc_entry(name, parent); ++ de_put(parent); ++} ++ ++void remove_proc_glob_entry(const char *name, struct proc_dir_entry *parent) ++{ ++ const char *path; ++ ++ path = name; ++ if (xlate_proc_name(path, &parent, &name) != 0) ++ return; ++ ++ __remove_proc_entry(name, parent); ++ de_put(parent); ++} ++ ++void remove_proc_entry(const char *name, struct proc_dir_entry *parent) ++{ ++ remove_proc_loc_entry(name, parent); ++#ifdef CONFIG_VE ++ if (ve_is_super(get_exec_env())) ++ remove_proc_glob_entry(name, parent); ++#endif + } +Index: kernel/fs/proc/inode.c +=================================================================== +--- kernel.orig/fs/proc/inode.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/proc/inode.c 2008-11-24 15:47:46.000000000 +0100 +@@ -36,16 +36,13 @@ + void de_put(struct proc_dir_entry *de) + { + if (de) { +- lock_kernel(); + if (!atomic_read(&de->count)) { + printk("de_put: entry %s already free!\n", de->name); +- unlock_kernel(); + return; + } + + if (atomic_dec_and_test(&de->count)) + free_proc_entry(de); +- unlock_kernel(); + } + } + +@@ -62,16 +59,25 @@ + put_pid(PROC_I(inode)->pid); + + /* Let go of any associated proc directory entry */ +- de = PROC_I(inode)->pde; ++ de = LPDE(inode); + if (de) { + if (de->owner) + module_put(de->owner); + de_put(de); + } ++#ifdef CONFIG_VE ++ de = GPDE(inode); ++ if (de) { ++ module_put(de->owner); ++ de_put(de); ++ } ++#endif + clear_inode(inode); + } + ++#ifndef CONFIG_VE + struct vfsmount *proc_mnt; ++#endif + + static void proc_read_inode(struct inode * inode) + { +@@ -94,6 +100,9 @@ + ei->pde = NULL; + inode = &ei->vfs_inode; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; ++#ifdef CONFIG_VE ++ GPDE(inode) = NULL; ++#endif + return inode; + } + +@@ -398,12 +407,9 @@ + { + struct inode * inode; + +- if (de != NULL && !try_module_get(de->owner)) +- goto out_mod; +- + inode = iget(sb, ino); + if (!inode) +- goto out_ino; ++ goto out_mod; + + PROC_I(inode)->fd = 0; + PROC_I(inode)->pde = de; +@@ -436,9 +442,6 @@ + + return inode; + +-out_ino: +- if (de != NULL) +- module_put(de->owner); + out_mod: + return NULL; + } +@@ -463,6 +466,12 @@ + s->s_root = d_alloc_root(root_inode); + if (!s->s_root) + goto out_no_root; ++#ifdef CONFIG_VE ++ LPDE(root_inode) = de_get(get_exec_env()->proc_root); ++ GPDE(root_inode) = &proc_root; ++#else ++ LPDE(root_inode) = &proc_root; ++#endif + return 0; + + out_no_root: +Index: kernel/fs/proc/kmsg.c +=================================================================== +--- kernel.orig/fs/proc/kmsg.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/proc/kmsg.c 2008-11-24 15:47:46.000000000 +0100 +@@ -11,6 +11,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -40,7 +42,7 @@ + + static unsigned int kmsg_poll(struct file *file, poll_table *wait) + { +- poll_wait(file, &log_wait, wait); ++ poll_wait(file, &ve_log_wait, wait); + if (do_syslog(9, NULL, 0)) + return POLLIN | POLLRDNORM; + return 0; +@@ -53,3 +55,4 @@ + .open = kmsg_open, + .release = kmsg_release, + }; ++EXPORT_SYMBOL(proc_kmsg_operations); +Index: kernel/fs/proc/proc_misc.c +=================================================================== +--- kernel.orig/fs/proc/proc_misc.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/proc/proc_misc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -46,6 +47,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -53,8 +55,10 @@ + #include + #include "internal.h" + +-#define LOAD_INT(x) ((x) >> FSHIFT) +-#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) ++#ifdef CONFIG_FAIRSCHED ++#include ++#endif ++ + /* + * Warning: stuff below (imported functions) assumes that its output will fit + * into one page. For some of those functions it may be wrong. Moreover, we +@@ -83,15 +87,30 @@ + { + int a, b, c; + int len; ++ long running, threads; ++ struct ve_struct *ve; + +- a = avenrun[0] + (FIXED_1/200); +- b = avenrun[1] + (FIXED_1/200); +- c = avenrun[2] + (FIXED_1/200); +- len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", ++ ve = get_exec_env(); ++ if (ve_is_super(ve)) { ++ a = avenrun[0] + (FIXED_1/200); ++ b = avenrun[1] + (FIXED_1/200); ++ c = avenrun[2] + (FIXED_1/200); ++ running = nr_running(); ++ threads = nr_threads; ++#ifdef CONFIG_VE ++ } else { ++ a = ve->avenrun[0] + (FIXED_1/200); ++ b = ve->avenrun[1] + (FIXED_1/200); ++ c = ve->avenrun[2] + (FIXED_1/200); ++ running = nr_running_ve(ve); ++ threads = atomic_read(&ve->pcounter); ++#endif ++ } ++ len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%ld %d\n", + LOAD_INT(a), LOAD_FRAC(a), + LOAD_INT(b), LOAD_FRAC(b), + LOAD_INT(c), LOAD_FRAC(c), +- nr_running(), nr_threads, ++ running, threads, + task_active_pid_ns(current)->last_pid); + return proc_calc_metrics(page, start, off, count, eof, len); + } +@@ -106,6 +125,13 @@ + + do_posix_clock_monotonic_gettime(&uptime); + monotonic_to_bootbased(&uptime); ++#ifdef CONFIG_VE ++ if (!ve_is_super(get_exec_env())) { ++ set_normalized_timespec(&uptime, ++ uptime.tv_sec - get_exec_env()->start_timespec.tv_sec, ++ uptime.tv_nsec - get_exec_env()->start_timespec.tv_nsec); ++ } ++#endif + cputime_to_timespec(idletime, &idle); + len = sprintf(page,"%lu.%02lu %lu.%02lu\n", + (unsigned long) uptime.tv_sec, +@@ -119,29 +145,49 @@ + static int meminfo_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) + { +- struct sysinfo i; ++ struct meminfo mi; + int len; +- unsigned long committed; +- unsigned long allowed; ++ unsigned long dummy; + struct vmalloc_info vmi; +- long cached; ++ ++ get_zone_counts(&mi.active, &mi.inactive, &dummy); + + /* + * display in kilobytes. + */ + #define K(x) ((x) << (PAGE_SHIFT - 10)) +- si_meminfo(&i); +- si_swapinfo(&i); +- committed = atomic_read(&vm_committed_space); +- allowed = ((totalram_pages - hugetlb_total_pages()) ++ si_meminfo(&mi.si); ++ si_swapinfo(&mi.si); ++ mi.committed_space = atomic_read(&vm_committed_space); ++ mi.swapcache = total_swapcache_pages; ++ mi.allowed = ((totalram_pages - hugetlb_total_pages()) + * sysctl_overcommit_ratio / 100) + total_swap_pages; + +- cached = global_page_state(NR_FILE_PAGES) - +- total_swapcache_pages - i.bufferram; +- if (cached < 0) +- cached = 0; ++ mi.cache = global_page_state(NR_FILE_PAGES) - ++ total_swapcache_pages - mi.si.bufferram; ++ if (mi.cache < 0) ++ mi.cache = 0; + + get_vmalloc_info(&vmi); ++ mi.vmalloc_used = vmi.used >> PAGE_SHIFT; ++ mi.vmalloc_largest = vmi.largest_chunk >> PAGE_SHIFT; ++ mi.vmalloc_total = VMALLOC_TOTAL >> PAGE_SHIFT; ++ ++ mi.pi.nr_file_dirty = global_page_state(NR_FILE_DIRTY); ++ mi.pi.nr_writeback = global_page_state(NR_WRITEBACK); ++ mi.pi.nr_anon_pages = global_page_state(NR_ANON_PAGES); ++ mi.pi.nr_file_mapped = global_page_state(NR_FILE_MAPPED); ++ mi.pi.nr_slab_rec = global_page_state(NR_SLAB_RECLAIMABLE); ++ mi.pi.nr_slab_unrec = global_page_state(NR_SLAB_UNRECLAIMABLE); ++ mi.pi.nr_pagetable = global_page_state(NR_PAGETABLE); ++ mi.pi.nr_unstable_nfs = global_page_state(NR_UNSTABLE_NFS); ++ mi.pi.nr_bounce = global_page_state(NR_BOUNCE); ++ ++#ifdef CONFIG_BEANCOUNTERS ++ if (virtinfo_notifier_call(VITYPE_GENERAL, VIRTINFO_MEMINFO, &mi) ++ & NOTIFY_FAIL) ++ return -ENOMSG; ++#endif + + /* + * Tagged format, for easy grepping and expansion. +@@ -177,37 +223,37 @@ + "VmallocTotal: %8lu kB\n" + "VmallocUsed: %8lu kB\n" + "VmallocChunk: %8lu kB\n", +- K(i.totalram), +- K(i.freeram), +- K(i.bufferram), +- K(cached), +- K(total_swapcache_pages), +- K(global_page_state(NR_ACTIVE)), +- K(global_page_state(NR_INACTIVE)), ++ K(mi.si.totalram), ++ K(mi.si.freeram), ++ K(mi.si.bufferram), ++ K(mi.cache), ++ K(mi.swapcache), ++ K(mi.active), ++ K(mi.inactive), + #ifdef CONFIG_HIGHMEM +- K(i.totalhigh), +- K(i.freehigh), +- K(i.totalram-i.totalhigh), +- K(i.freeram-i.freehigh), +-#endif +- K(i.totalswap), +- K(i.freeswap), +- K(global_page_state(NR_FILE_DIRTY)), +- K(global_page_state(NR_WRITEBACK)), +- K(global_page_state(NR_ANON_PAGES)), +- K(global_page_state(NR_FILE_MAPPED)), +- K(global_page_state(NR_SLAB_RECLAIMABLE) + +- global_page_state(NR_SLAB_UNRECLAIMABLE)), +- K(global_page_state(NR_SLAB_RECLAIMABLE)), +- K(global_page_state(NR_SLAB_UNRECLAIMABLE)), +- K(global_page_state(NR_PAGETABLE)), +- K(global_page_state(NR_UNSTABLE_NFS)), +- K(global_page_state(NR_BOUNCE)), +- K(allowed), +- K(committed), +- (unsigned long)VMALLOC_TOTAL >> 10, +- vmi.used >> 10, +- vmi.largest_chunk >> 10 ++ K(mi.si.totalhigh), ++ K(mi.si.freehigh), ++ K(mi.si.totalram-mi.si.totalhigh), ++ K(mi.si.freeram-mi.si.freehigh), ++#endif ++ K(mi.si.totalswap), ++ K(mi.si.freeswap), ++ K(mi.pi.nr_file_dirty), ++ K(mi.pi.nr_writeback), ++ K(mi.pi.nr_anon_pages), ++ K(mi.pi.nr_file_mapped), ++ K(mi.pi.nr_slab_rec + ++ mi.pi.nr_slab_unrec), ++ K(mi.pi.nr_slab_rec), ++ K(mi.pi.nr_slab_unrec), ++ K(mi.pi.nr_pagetable), ++ K(mi.pi.nr_unstable_nfs), ++ K(mi.pi.nr_bounce), ++ K(mi.allowed), ++ K(mi.committed_space), ++ K(mi.vmalloc_total), ++ K(mi.vmalloc_used), ++ K(mi.vmalloc_largest) + ); + + len += hugetlb_report_meminfo(page + len); +@@ -451,25 +497,21 @@ + #endif + #endif + +-static int show_stat(struct seq_file *p, void *v) ++static void show_stat_ve0(struct seq_file *p) + { + int i; +- unsigned long jif; + cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; + cputime64_t guest; + u64 sum = 0; +- struct timespec boottime; + unsigned int *per_irq_sum; + + per_irq_sum = kzalloc(sizeof(unsigned int)*NR_IRQS, GFP_KERNEL); + if (!per_irq_sum) +- return -ENOMEM; ++ return; + + user = nice = system = idle = iowait = + irq = softirq = steal = cputime64_zero; + guest = cputime64_zero; +- getboottime(&boottime); +- jif = boottime.tv_sec; + + for_each_possible_cpu(i) { + int j; +@@ -529,9 +571,89 @@ + + for (i = 0; i < NR_IRQS; i++) + seq_printf(p, " %u", per_irq_sum[i]); ++ kfree(per_irq_sum); ++#ifdef CONFIG_VM_EVENT_COUNTERS ++ seq_printf(p, "\nswap %lu %lu\n", ++ vm_events(PSWPIN), vm_events(PSWPOUT)); ++#else ++ seq_printf(p, "\nswap 0 0\n"); ++#endif ++} ++ ++#ifdef CONFIG_VE ++static void show_stat_ve(struct seq_file *p, struct ve_struct *ve) ++{ ++ int i; ++ u64 user, nice, system; ++ cycles_t idle, iowait; ++ cpumask_t ve_cpus; ++ ++ ve_cpu_online_map(ve, &ve_cpus); ++ ++ user = nice = system = idle = iowait = 0; ++ for_each_cpu_mask(i, ve_cpus) { ++ user += VE_CPU_STATS(ve, i)->user; ++ nice += VE_CPU_STATS(ve, i)->nice; ++ system += VE_CPU_STATS(ve, i)->system; ++ idle += ve_sched_get_idle_time(ve, i); ++ iowait += ve_sched_get_iowait_time(ve, i); ++ } ++ ++ seq_printf(p, "cpu %llu %llu %llu %llu %llu 0 0 0\n", ++ (unsigned long long)cputime64_to_clock_t(user), ++ (unsigned long long)cputime64_to_clock_t(nice), ++ (unsigned long long)cputime64_to_clock_t(system), ++ (unsigned long long)cycles_to_clocks(idle), ++ (unsigned long long)cycles_to_clocks(iowait)); ++ ++ for_each_cpu_mask(i, ve_cpus) { ++ user = VE_CPU_STATS(ve, i)->user; ++ nice = VE_CPU_STATS(ve, i)->nice; ++ system = VE_CPU_STATS(ve, i)->system; ++ idle = ve_sched_get_idle_time(ve, i); ++ iowait = ve_sched_get_iowait_time(ve, i); ++ seq_printf(p, "cpu%d %llu %llu %llu %llu %llu 0 0 0\n", ++ i, ++ (unsigned long long)cputime64_to_clock_t(user), ++ (unsigned long long)cputime64_to_clock_t(nice), ++ (unsigned long long)cputime64_to_clock_t(system), ++ (unsigned long long)cycles_to_clocks(idle), ++ (unsigned long long)cycles_to_clocks(iowait)); ++ } ++ seq_printf(p, "intr 0\nswap 0 0\n"); ++} ++#endif ++ ++int show_stat(struct seq_file *p, void *v) ++{ ++ extern unsigned long total_forks; ++ unsigned long seq, jif; ++ struct ve_struct *env; ++ unsigned long __nr_running, __nr_iowait; ++ ++ do { ++ seq = read_seqbegin(&xtime_lock); ++ jif = - wall_to_monotonic.tv_sec; ++ if (wall_to_monotonic.tv_nsec) ++ --jif; ++ } while (read_seqretry(&xtime_lock, seq)); ++ ++ env = get_exec_env(); ++ if (ve_is_super(env)) { ++ show_stat_ve0(p); ++ __nr_running = nr_running(); ++ __nr_iowait = nr_iowait(); ++ } ++#ifdef CONFIG_VE ++ else { ++ show_stat_ve(p, env); ++ __nr_running = nr_running_ve(env); ++ __nr_iowait = nr_iowait_ve(env); ++ } ++#endif + + seq_printf(p, +- "\nctxt %llu\n" ++ "ctxt %llu\n" + "btime %lu\n" + "processes %lu\n" + "procs_running %lu\n" +@@ -539,10 +661,9 @@ + nr_context_switches(), + (unsigned long)jif, + total_forks, +- nr_running(), +- nr_iowait()); ++ __nr_running, ++ __nr_iowait); + +- kfree(per_irq_sum); + return 0; + } + +@@ -630,7 +751,8 @@ + { + int len; + +- len = sprintf(page, "%s\n", saved_command_line); ++ len = sprintf(page, "%s\n", ++ ve_is_super(get_exec_env()) ? saved_command_line : "quiet"); + return proc_calc_metrics(page, start, off, count, eof, len); + } + +@@ -674,11 +796,16 @@ + size_t count, loff_t *ppos) + { + if (count) { +- char c; ++ int i, cnt; ++ char c[32]; + +- if (get_user(c, buf)) ++ cnt = min(count, sizeof(c)); ++ if (copy_from_user(c, buf, cnt)) + return -EFAULT; +- __handle_sysrq(c, NULL, 0); ++ ++ ++ for (i = 0; i < cnt && c[i] != '\n'; i++) ++ __handle_sysrq(c[i], NULL, 0); + } + return count; + } +Index: kernel/fs/proc/proc_net.c +=================================================================== +--- kernel.orig/fs/proc/proc_net.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/proc/proc_net.c 2008-11-24 15:47:46.000000000 +0100 +@@ -31,7 +31,7 @@ + { + struct proc_dir_entry *res; + +- res = create_proc_entry(name, mode, net->proc_net); ++ res = create_proc_entry(name, mode, get_exec_env()->_proc_net); + if (res) + res->proc_fops = fops; + return res; +@@ -40,7 +40,7 @@ + + void proc_net_remove(struct net *net, const char *name) + { +- remove_proc_entry(name, net->proc_net); ++ remove_proc_entry(name, get_exec_env()->_proc_net); + } + EXPORT_SYMBOL_GPL(proc_net_remove); + +@@ -50,68 +50,26 @@ + } + EXPORT_SYMBOL_GPL(get_proc_net); + +-static struct proc_dir_entry *shadow_pde; +- + static struct proc_dir_entry *proc_net_shadow(struct task_struct *task, + struct proc_dir_entry *de) + { + return task->nsproxy->net_ns->proc_net; + } + +-static __net_init int proc_net_ns_init(struct net *net) +-{ +- struct proc_dir_entry *root, *netd, *net_statd; +- int err; +- +- err = -ENOMEM; +- root = kzalloc(sizeof(*root), GFP_KERNEL); +- if (!root) +- goto out; +- +- err = -EEXIST; +- netd = proc_mkdir("net", root); +- if (!netd) +- goto free_root; +- +- err = -EEXIST; +- net_statd = proc_mkdir("stat", netd); +- if (!net_statd) +- goto free_net; +- +- root->data = net; +- netd->data = net; +- net_statd->data = net; +- +- net->proc_net_root = root; +- net->proc_net = netd; +- net->proc_net_stat = net_statd; +- err = 0; +- +-out: +- return err; +-free_net: +- remove_proc_entry("net", root); +-free_root: +- kfree(root); +- goto out; +-} +- +-static __net_exit void proc_net_ns_exit(struct net *net) +-{ +- remove_proc_entry("stat", net->proc_net); +- remove_proc_entry("net", net->proc_net_root); +- kfree(net->proc_net_root); +-} +- +-static struct pernet_operations __net_initdata proc_net_ns_ops = { +- .init = proc_net_ns_init, +- .exit = proc_net_ns_exit, +-}; +- + int __init proc_net_init(void) + { +- shadow_pde = proc_mkdir("net", NULL); +- shadow_pde->shadow_proc = proc_net_shadow; ++ struct proc_dir_entry *pde; ++ ++ pde = proc_mkdir("net", NULL); ++ pde->shadow_proc = proc_net_shadow; ++ init_net.proc_net = pde; ++ ve0._proc_net = pde; ++ pde->data = &init_net; ++ ++ pde = proc_mkdir("stat", pde); ++ init_net.proc_net_stat = pde; ++ ve0._proc_net_stat = pde; ++ pde->data = &init_net; + +- return register_pernet_subsys(&proc_net_ns_ops); ++ return 0; + } +Index: kernel/fs/proc/proc_sysctl.c +=================================================================== +--- kernel.orig/fs/proc/proc_sysctl.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/proc/proc_sysctl.c 2008-11-24 15:47:46.000000000 +0100 +@@ -1,15 +1,15 @@ + /* + * /proc/sys support + */ +- ++#include + #include + #include + #include + #include "internal.h" + + static struct dentry_operations proc_sys_dentry_operations; +-static const struct file_operations proc_sys_file_operations; +-static struct inode_operations proc_sys_inode_operations; ++extern const struct file_operations proc_sys_file_operations; ++extern struct inode_operations proc_sys_inode_operations; + + static void proc_sys_refresh_inode(struct inode *inode, struct ctl_table *table) + { +@@ -440,17 +440,19 @@ + /* I'm lazy and don't distinguish between files and directories, + * until access time. + */ +-static const struct file_operations proc_sys_file_operations = { ++const struct file_operations proc_sys_file_operations = { + .read = proc_sys_read, + .write = proc_sys_write, + .readdir = proc_sys_readdir, + }; ++EXPORT_SYMBOL_GPL(proc_sys_file_operations); + +-static struct inode_operations proc_sys_inode_operations = { ++struct inode_operations proc_sys_inode_operations = { + .lookup = proc_sys_lookup, + .permission = proc_sys_permission, + .setattr = proc_sys_setattr, + }; ++EXPORT_SYMBOL_GPL(proc_sys_inode_operations); + + static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd) + { +@@ -466,13 +468,11 @@ + .d_revalidate = proc_sys_revalidate, + }; + +-static struct proc_dir_entry *proc_sys_root; +- + int proc_sys_init(void) + { +- proc_sys_root = proc_mkdir("sys", NULL); +- proc_sys_root->proc_iops = &proc_sys_inode_operations; +- proc_sys_root->proc_fops = &proc_sys_file_operations; +- proc_sys_root->nlink = 0; ++ ve0.proc_sys_root = proc_mkdir("sys", NULL); ++ ve0.proc_sys_root->proc_iops = &proc_sys_inode_operations; ++ ve0.proc_sys_root->proc_fops = &proc_sys_file_operations; ++ ve0.proc_sys_root->nlink = 0; + return 0; + } +Index: kernel/fs/proc/proc_tty.c +=================================================================== +--- kernel.orig/fs/proc/proc_tty.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/proc/proc_tty.c 2008-11-24 15:47:46.000000000 +0100 +@@ -73,6 +73,9 @@ + dev_t from = MKDEV(p->major, p->minor_start); + dev_t to = from + p->num; + ++ if (!ve_accessible_strict(p->owner_env, get_exec_env())) ++ goto out; ++ + if (&p->tty_drivers == tty_drivers.next) { + /* pseudo-drivers first */ + seq_printf(m, "%-20s /dev/%-8s ", "/dev/tty", "tty"); +@@ -100,6 +103,7 @@ + } + if (from != to) + show_tty_range(m, p, from, to - from); ++out: + return 0; + } + +Index: kernel/fs/proc/root.c +=================================================================== +--- kernel.orig/fs/proc/root.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/proc/root.c 2008-11-24 15:47:46.000000000 +0100 +@@ -45,7 +45,9 @@ + struct super_block *sb; + struct pid_namespace *ns; + struct proc_inode *ei; ++ struct vfsmount *proc_mnt; + ++ proc_mnt = proc_mnt(fs_type->owner_env); + if (proc_mnt) { + /* Seed the root directory with a pid so it doesn't need + * to be special in base.c. I would do this earlier but +@@ -98,12 +100,14 @@ + put_pid_ns(ns); + } + +-static struct file_system_type proc_fs_type = { ++struct file_system_type proc_fs_type = { + .name = "proc", + .get_sb = proc_get_sb, + .kill_sb = proc_kill_sb, + }; + ++EXPORT_SYMBOL(proc_fs_type); ++ + void __init proc_root_init(void) + { + int err = proc_init_inodecache(); +@@ -112,9 +116,9 @@ + err = register_filesystem(&proc_fs_type); + if (err) + return; +- proc_mnt = kern_mount_data(&proc_fs_type, &init_pid_ns); +- err = PTR_ERR(proc_mnt); +- if (IS_ERR(proc_mnt)) { ++ proc_mnt(get_ve0()) = kern_mount_data(&proc_fs_type, &init_pid_ns); ++ err = PTR_ERR(proc_mnt(get_ve0())); ++ if (IS_ERR(proc_mnt(get_ve0()))) { + unregister_filesystem(&proc_fs_type); + return; + } +Index: kernel/fs/proc/task_mmu.c +=================================================================== +--- kernel.orig/fs/proc/task_mmu.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/proc/task_mmu.c 2008-11-24 15:47:46.000000000 +0100 +@@ -95,9 +95,12 @@ + } + + if (vma) { +- *mnt = mntget(vma->vm_file->f_path.mnt); +- *dentry = dget(vma->vm_file->f_path.dentry); +- result = 0; ++ result = d_root_check(vma->vm_file->f_path.dentry, ++ vma->vm_file->f_path.mnt); ++ if (!result) { ++ *mnt = mntget(vma->vm_file->f_path.mnt); ++ *dentry = dget(vma->vm_file->f_path.dentry); ++ } + } + + up_read(&mm->mmap_sem); +Index: kernel/fs/proc/task_nommu.c +=================================================================== +--- kernel.orig/fs/proc/task_nommu.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/proc/task_nommu.c 2008-11-24 15:47:46.000000000 +0100 +@@ -127,9 +127,12 @@ + } + + if (vma) { +- *mnt = mntget(vma->vm_file->f_path.mnt); +- *dentry = dget(vma->vm_file->f_path.dentry); +- result = 0; ++ result = d_root_check(vma->vm_file->f_path.dentry, ++ vma->vm_file->f_path.mnt); ++ if (!result) { ++ *mnt = mntget(vma->vm_file->f_path.mnt); ++ *dentry = dget(vma->vm_file->f_path.dentry); ++ } + } + + up_read(&mm->mmap_sem); +Index: kernel/fs/quota.c +=================================================================== +--- kernel.orig/fs/quota.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/quota.c 2008-11-24 15:47:46.000000000 +0100 +@@ -82,11 +82,11 @@ + if (cmd == Q_GETQUOTA) { + if (((type == USRQUOTA && current->euid != id) || + (type == GRPQUOTA && !in_egroup_p(id))) && +- !capable(CAP_SYS_ADMIN)) ++ !capable(CAP_VE_SYS_ADMIN)) + return -EPERM; + } + else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO) +- if (!capable(CAP_SYS_ADMIN)) ++ if (!capable(CAP_VE_SYS_ADMIN)) + return -EPERM; + + return 0; +@@ -133,10 +133,10 @@ + if (cmd == Q_XGETQUOTA) { + if (((type == XQM_USRQUOTA && current->euid != id) || + (type == XQM_GRPQUOTA && !in_egroup_p(id))) && +- !capable(CAP_SYS_ADMIN)) ++ !capable(CAP_VE_SYS_ADMIN)) + return -EPERM; + } else if (cmd != Q_XGETQSTAT && cmd != Q_XQUOTASYNC) { +- if (!capable(CAP_SYS_ADMIN)) ++ if (!capable(CAP_VE_SYS_ADMIN)) + return -EPERM; + } + +@@ -178,6 +178,8 @@ + continue; + if (!sb_has_quota_enabled(sb, cnt)) + continue; ++ if (!sb_dqopt(sb)->files[cnt]) ++ continue; + mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex, I_MUTEX_QUOTA); + truncate_inode_pages(&sb_dqopt(sb)->files[cnt]->i_data, 0); + mutex_unlock(&sb_dqopt(sb)->files[cnt]->i_mutex); +@@ -208,7 +210,7 @@ + sb->s_count++; + spin_unlock(&sb_lock); + down_read(&sb->s_umount); +- if (sb->s_root && sb->s_qcop->quota_sync) ++ if (sb->s_root && sb->s_qcop && sb->s_qcop->quota_sync) + quota_sync_sb(sb, type); + up_read(&sb->s_umount); + spin_lock(&sb_lock); +@@ -342,7 +344,7 @@ + + if (IS_ERR(tmp)) + return ERR_PTR(PTR_ERR(tmp)); +- bdev = lookup_bdev(tmp); ++ bdev = lookup_bdev(tmp, FMODE_QUOTACTL); + putname(tmp); + if (IS_ERR(bdev)) + return ERR_PTR(PTR_ERR(bdev)); +@@ -357,6 +359,215 @@ + #endif + } + ++#ifdef CONFIG_QUOTA_COMPAT ++ ++#define QC_QUOTAON 0x0100 /* enable quotas */ ++#define QC_QUOTAOFF 0x0200 /* disable quotas */ ++/* GETQUOTA, SETQUOTA and SETUSE which were at 0x0300-0x0500 has now other parameteres */ ++#define QC_SYNC 0x0600 /* sync disk copy of a filesystems quotas */ ++#define QC_SETQLIM 0x0700 /* set limits */ ++/* GETSTATS at 0x0800 is now longer... */ ++#define QC_GETINFO 0x0900 /* get info about quotas - graces, flags... */ ++#define QC_SETINFO 0x0A00 /* set info about quotas */ ++#define QC_SETGRACE 0x0B00 /* set inode and block grace */ ++#define QC_SETFLAGS 0x0C00 /* set flags for quota */ ++#define QC_GETQUOTA 0x0D00 /* get limits and usage */ ++#define QC_SETQUOTA 0x0E00 /* set limits and usage */ ++#define QC_SETUSE 0x0F00 /* set usage */ ++/* 0x1000 used by old RSQUASH */ ++#define QC_GETSTATS 0x1100 /* get collected stats */ ++ ++struct compat_dqblk { ++ unsigned int dqb_ihardlimit; ++ unsigned int dqb_isoftlimit; ++ unsigned int dqb_curinodes; ++ unsigned int dqb_bhardlimit; ++ unsigned int dqb_bsoftlimit; ++ qsize_t dqb_curspace; ++ __kernel_time_t dqb_btime; ++ __kernel_time_t dqb_itime; ++}; ++ ++struct compat_dqinfo { ++ unsigned int dqi_bgrace; ++ unsigned int dqi_igrace; ++ unsigned int dqi_flags; ++ unsigned int dqi_blocks; ++ unsigned int dqi_free_blk; ++ unsigned int dqi_free_entry; ++}; ++ ++struct compat_dqstats { ++ __u32 lookups; ++ __u32 drops; ++ __u32 reads; ++ __u32 writes; ++ __u32 cache_hits; ++ __u32 allocated_dquots; ++ __u32 free_dquots; ++ __u32 syncs; ++ __u32 version; ++}; ++ ++asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t id, void __user *addr); ++static long compat_quotactl(unsigned int cmds, unsigned int type, ++ const char __user *special, qid_t id, ++ void __user *addr) ++{ ++ struct super_block *sb; ++ long ret; ++ ++ sb = NULL; ++ switch (cmds) { ++ case QC_QUOTAON: ++ return sys_quotactl(QCMD(Q_QUOTAON, type), ++ special, id, addr); ++ ++ case QC_QUOTAOFF: ++ return sys_quotactl(QCMD(Q_QUOTAOFF, type), ++ special, id, addr); ++ ++ case QC_SYNC: ++ return sys_quotactl(QCMD(Q_SYNC, type), ++ special, id, addr); ++ ++ case QC_GETQUOTA: { ++ struct if_dqblk idq; ++ struct compat_dqblk cdq; ++ ++ sb = quotactl_block(special); ++ ret = PTR_ERR(sb); ++ if (IS_ERR(sb)) ++ break; ++ ret = check_quotactl_valid(sb, type, Q_GETQUOTA, id); ++ if (ret) ++ break; ++ ret = sb->s_qcop->get_dqblk(sb, type, id, &idq); ++ if (ret) ++ break; ++ cdq.dqb_ihardlimit = idq.dqb_ihardlimit; ++ cdq.dqb_isoftlimit = idq.dqb_isoftlimit; ++ cdq.dqb_curinodes = idq.dqb_curinodes; ++ cdq.dqb_bhardlimit = idq.dqb_bhardlimit; ++ cdq.dqb_bsoftlimit = idq.dqb_bsoftlimit; ++ cdq.dqb_curspace = idq.dqb_curspace; ++ cdq.dqb_btime = idq.dqb_btime; ++ cdq.dqb_itime = idq.dqb_itime; ++ ret = 0; ++ if (copy_to_user(addr, &cdq, sizeof(cdq))) ++ ret = -EFAULT; ++ break; ++ } ++ ++ case QC_SETQUOTA: ++ case QC_SETUSE: ++ case QC_SETQLIM: { ++ struct if_dqblk idq; ++ struct compat_dqblk cdq; ++ ++ sb = quotactl_block(special); ++ ret = PTR_ERR(sb); ++ if (IS_ERR(sb)) ++ break; ++ ret = check_quotactl_valid(sb, type, Q_SETQUOTA, id); ++ if (ret) ++ break; ++ ret = -EFAULT; ++ if (copy_from_user(&cdq, addr, sizeof(cdq))) ++ break; ++ idq.dqb_ihardlimit = cdq.dqb_ihardlimit; ++ idq.dqb_isoftlimit = cdq.dqb_isoftlimit; ++ idq.dqb_curinodes = cdq.dqb_curinodes; ++ idq.dqb_bhardlimit = cdq.dqb_bhardlimit; ++ idq.dqb_bsoftlimit = cdq.dqb_bsoftlimit; ++ idq.dqb_curspace = cdq.dqb_curspace; ++ idq.dqb_valid = 0; ++ if (cmds == QC_SETQUOTA || cmds == QC_SETQLIM) ++ idq.dqb_valid |= QIF_LIMITS; ++ if (cmds == QC_SETQUOTA || cmds == QC_SETUSE) ++ idq.dqb_valid |= QIF_USAGE; ++ ret = sb->s_qcop->set_dqblk(sb, type, id, &idq); ++ break; ++ } ++ ++ case QC_GETINFO: { ++ struct if_dqinfo iinf; ++ struct compat_dqinfo cinf; ++ ++ sb = quotactl_block(special); ++ ret = PTR_ERR(sb); ++ if (IS_ERR(sb)) ++ break; ++ ret = check_quotactl_valid(sb, type, Q_GETQUOTA, id); ++ if (ret) ++ break; ++ ret = sb->s_qcop->get_info(sb, type, &iinf); ++ if (ret) ++ break; ++ cinf.dqi_bgrace = iinf.dqi_bgrace; ++ cinf.dqi_igrace = iinf.dqi_igrace; ++ cinf.dqi_flags = 0; ++ if (iinf.dqi_flags & DQF_INFO_DIRTY) ++ cinf.dqi_flags |= 0x0010; ++ cinf.dqi_blocks = 0; ++ cinf.dqi_free_blk = 0; ++ cinf.dqi_free_entry = 0; ++ ret = 0; ++ if (copy_to_user(addr, &cinf, sizeof(cinf))) ++ ret = -EFAULT; ++ break; ++ } ++ ++ case QC_SETINFO: ++ case QC_SETGRACE: ++ case QC_SETFLAGS: { ++ struct if_dqinfo iinf; ++ struct compat_dqinfo cinf; ++ ++ sb = quotactl_block(special); ++ ret = PTR_ERR(sb); ++ if (IS_ERR(sb)) ++ break; ++ ret = check_quotactl_valid(sb, type, Q_SETINFO, id); ++ if (ret) ++ break; ++ ret = -EFAULT; ++ if (copy_from_user(&cinf, addr, sizeof(cinf))) ++ break; ++ iinf.dqi_bgrace = cinf.dqi_bgrace; ++ iinf.dqi_igrace = cinf.dqi_igrace; ++ iinf.dqi_flags = cinf.dqi_flags; ++ iinf.dqi_valid = 0; ++ if (cmds == QC_SETINFO || cmds == QC_SETGRACE) ++ iinf.dqi_valid |= IIF_BGRACE | IIF_IGRACE; ++ if (cmds == QC_SETINFO || cmds == QC_SETFLAGS) ++ iinf.dqi_valid |= IIF_FLAGS; ++ ret = sb->s_qcop->set_info(sb, type, &iinf); ++ break; ++ } ++ ++ case QC_GETSTATS: { ++ struct compat_dqstats stat; ++ ++ memset(&stat, 0, sizeof(stat)); ++ stat.version = 6*10000+5*100+0; ++ ret = 0; ++ if (copy_to_user(addr, &stat, sizeof(stat))) ++ ret = -EFAULT; ++ break; ++ } ++ ++ default: ++ ret = -ENOSYS; ++ break; ++ } ++ if (sb && !IS_ERR(sb)) ++ drop_super(sb); ++ return ret; ++} ++ ++#endif ++ + /* + * This is the system call interface. This communicates with + * the user-level programs. Currently this only supports diskquota +@@ -372,6 +583,11 @@ + cmds = cmd >> SUBCMDSHIFT; + type = cmd & SUBCMDMASK; + ++#ifdef CONFIG_QUOTA_COMPAT ++ if (cmds >= 0x0100 && cmds < 0x3000) ++ return compat_quotactl(cmds, type, special, id, addr); ++#endif ++ + if (cmds != Q_SYNC || special) { + sb = quotactl_block(special); + if (IS_ERR(sb)) +Index: kernel/fs/read_write.c +=================================================================== +--- kernel.orig/fs/read_write.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/read_write.c 2008-11-24 15:47:46.000000000 +0100 +@@ -21,6 +21,8 @@ + #include + #include + ++#include ++ + const struct file_operations generic_ro_fops = { + .llseek = generic_file_llseek, + .read = do_sync_read, +@@ -354,6 +356,29 @@ + file->f_pos = pos; + } + ++static inline void bc_acct_write(size_t bytes) ++{ ++ struct user_beancounter *ub; ++ ++ if (bytes > 0) { ++ ub = get_exec_ub(); ++ ub_percpu_inc(ub, write); ++ ub_percpu_add(ub, wchar, bytes); ++ } ++} ++ ++static inline void bc_acct_read(size_t bytes) ++{ ++ struct user_beancounter *ub; ++ ++ if (bytes > 0) { ++ ub = get_exec_ub(); ++ ub_percpu_inc(ub, read); ++ ub_percpu_add(ub, rchar, bytes); ++ } ++} ++ ++ + asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) + { + struct file *file; +@@ -366,6 +391,8 @@ + ret = vfs_read(file, buf, count, &pos); + file_pos_write(file, pos); + fput_light(file, fput_needed); ++ ++ bc_acct_read(ret); + } + + return ret; +@@ -384,6 +411,8 @@ + ret = vfs_write(file, buf, count, &pos); + file_pos_write(file, pos); + fput_light(file, fput_needed); ++ ++ bc_acct_write(ret); + } + + return ret; +@@ -405,6 +434,8 @@ + if (file->f_mode & FMODE_PREAD) + ret = vfs_read(file, buf, count, &pos); + fput_light(file, fput_needed); ++ ++ bc_acct_read(ret); + } + + return ret; +@@ -426,6 +457,8 @@ + if (file->f_mode & FMODE_PWRITE) + ret = vfs_write(file, buf, count, &pos); + fput_light(file, fput_needed); ++ ++ bc_acct_write(ret); + } + + return ret; +@@ -673,6 +706,8 @@ + ret = vfs_readv(file, vec, vlen, &pos); + file_pos_write(file, pos); + fput_light(file, fput_needed); ++ ++ bc_acct_read(ret); + } + + if (ret > 0) +@@ -694,6 +729,8 @@ + ret = vfs_writev(file, vec, vlen, &pos); + file_pos_write(file, pos); + fput_light(file, fput_needed); ++ ++ bc_acct_write(ret); + } + + if (ret > 0) +Index: kernel/fs/reiserfs/namei.c +=================================================================== +--- kernel.orig/fs/reiserfs/namei.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/reiserfs/namei.c 2008-11-24 15:47:46.000000000 +0100 +@@ -859,6 +859,9 @@ + INITIALIZE_PATH(path); + struct reiserfs_dir_entry de; + ++ inode = dentry->d_inode; ++ DQUOT_INIT(inode); ++ + /* we will be doing 2 balancings and update 2 stat data, we change quotas + * of the owner of the directory and of the owner of the parent directory. + * The quota structure is possibly deleted only on last iput => outside +@@ -883,8 +886,6 @@ + goto end_rmdir; + } + +- inode = dentry->d_inode; +- + reiserfs_update_inode_transaction(inode); + reiserfs_update_inode_transaction(dir); + +@@ -947,6 +948,7 @@ + unsigned long savelink; + + inode = dentry->d_inode; ++ DQUOT_INIT(inode); + + /* in this transaction we can be doing at max two balancings and update + * two stat datas, we change quotas of the owner of the directory and of +@@ -1254,6 +1256,8 @@ + + old_inode = old_dentry->d_inode; + new_dentry_inode = new_dentry->d_inode; ++ if (new_dentry_inode) ++ DQUOT_INIT(new_dentry_inode); + + // make sure, that oldname still exists and points to an object we + // are going to rename +Index: kernel/fs/select.c +=================================================================== +--- kernel.orig/fs/select.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/select.c 2008-11-24 15:47:46.000000000 +0100 +@@ -26,6 +26,8 @@ + + #include + ++#include ++ + struct poll_table_page { + struct poll_table_page * next; + struct poll_table_entry * entry; +@@ -331,7 +333,8 @@ + if (size > sizeof(stack_fds) / 6) { + /* Not enough space in on-stack array; must use kmalloc */ + ret = -ENOMEM; +- bits = kmalloc(6 * size, GFP_KERNEL); ++ bits = kmalloc(6 * size, size > PAGE_SIZE / 6 ? ++ GFP_KERNEL_UBC : GFP_KERNEL); + if (!bits) + goto out_nofds; + } +@@ -677,7 +680,7 @@ + + len = min(todo, POLLFD_PER_PAGE); + size = sizeof(struct poll_list) + sizeof(struct pollfd) * len; +- walk = walk->next = kmalloc(size, GFP_KERNEL); ++ walk = walk->next = kmalloc(size, GFP_KERNEL_UBC); + if (!walk) { + err = -ENOMEM; + goto out_fds; +@@ -709,7 +712,7 @@ + return err; + } + +-static long do_restart_poll(struct restart_block *restart_block) ++long do_restart_poll(struct restart_block *restart_block) + { + struct pollfd __user *ufds = (struct pollfd __user*)restart_block->arg0; + int nfds = restart_block->arg1; +@@ -725,6 +728,7 @@ + } + return ret; + } ++EXPORT_SYMBOL_GPL(do_restart_poll); + + asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, + long timeout_msecs) +Index: kernel/fs/seq_file.c +=================================================================== +--- kernel.orig/fs/seq_file.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/seq_file.c 2008-11-24 15:47:46.000000000 +0100 +@@ -31,7 +31,7 @@ + struct seq_file *p = file->private_data; + + if (!p) { +- p = kmalloc(sizeof(*p), GFP_KERNEL); ++ p = kmalloc(sizeof(*p), GFP_KERNEL_UBC); + if (!p) + return -ENOMEM; + file->private_data = p; +@@ -86,7 +86,7 @@ + m->version = file->f_version; + /* grab buffer if we didn't have one */ + if (!m->buf) { +- m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); ++ m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL_UBC); + if (!m->buf) + goto Enomem; + } +@@ -120,7 +120,7 @@ + goto Fill; + m->op->stop(m, p); + kfree(m->buf); +- m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); ++ m->buf = kmalloc(m->size <<= 1, GFP_KERNEL_UBC); + if (!m->buf) + goto Enomem; + m->count = 0; +@@ -189,7 +189,7 @@ + return 0; + } + if (!m->buf) { +- m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); ++ m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL_UBC); + if (!m->buf) + return -ENOMEM; + } +@@ -224,7 +224,7 @@ + Eoverflow: + m->op->stop(m, p); + kfree(m->buf); +- m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); ++ m->buf = kmalloc(m->size <<= 1, GFP_KERNEL_UBC); + return !m->buf ? -ENOMEM : -EAGAIN; + } + +@@ -349,6 +349,8 @@ + if (m->count < m->size) { + char *s = m->buf + m->count; + char *p = d_path(dentry, mnt, s, m->size - m->count); ++ if (IS_ERR(p) && PTR_ERR(p) != -ENAMETOOLONG) ++ return 0; + if (!IS_ERR(p)) { + while (s <= p) { + char c = *p++; +@@ -392,7 +394,7 @@ + int single_open(struct file *file, int (*show)(struct seq_file *, void *), + void *data) + { +- struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL); ++ struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL_UBC); + int res = -ENOMEM; + + if (op) { +@@ -436,7 +438,7 @@ + void *private; + struct seq_file *seq; + +- private = kzalloc(psize, GFP_KERNEL); ++ private = kzalloc(psize, GFP_KERNEL_UBC); + if (private == NULL) + goto out; + +Index: kernel/fs/simfs.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/fs/simfs.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,332 @@ ++/* ++ * fs/simfs.c ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define SIMFS_GET_LOWER_FS_SB(sb) sb->s_root->d_sb ++ ++static struct super_operations sim_super_ops; ++ ++static int sim_getattr(struct vfsmount *mnt, struct dentry *dentry, ++ struct kstat *stat) ++{ ++ struct super_block *sb; ++ struct inode *inode; ++ ++ inode = dentry->d_inode; ++ if (!inode->i_op->getattr) { ++ generic_fillattr(inode, stat); ++ if (!stat->blksize) { ++ unsigned blocks; ++ ++ sb = inode->i_sb; ++ blocks = (stat->size + sb->s_blocksize-1) >> ++ sb->s_blocksize_bits; ++ stat->blocks = (sb->s_blocksize / 512) * blocks; ++ stat->blksize = sb->s_blocksize; ++ } ++ } else { ++ int err; ++ ++ err = inode->i_op->getattr(mnt, dentry, stat); ++ if (err) ++ return err; ++ } ++ ++ sb = mnt->mnt_sb; ++ if (sb->s_op == &sim_super_ops) ++ stat->dev = sb->s_dev; ++ return 0; ++} ++ ++static void quota_get_stat(struct super_block *sb, struct kstatfs *buf) ++{ ++ int err; ++ struct dq_stat qstat; ++ struct virt_info_quota q; ++ long free_file, adj_file; ++ s64 blk, free_blk, adj_blk; ++ int bsize_bits; ++ ++ q.super = sb; ++ q.qstat = &qstat; ++ err = virtinfo_notifier_call(VITYPE_QUOTA, VIRTINFO_QUOTA_GETSTAT, &q); ++ if (err != NOTIFY_OK) ++ return; ++ ++ bsize_bits = ffs(buf->f_bsize) - 1; ++ ++ if (qstat.bsoftlimit > qstat.bcurrent) ++ free_blk = (qstat.bsoftlimit - qstat.bcurrent) >> bsize_bits; ++ else ++ free_blk = 0; ++ /* ++ * In the regular case, we always set buf->f_bfree and buf->f_blocks to ++ * the values reported by quota. In case of real disk space shortage, ++ * we adjust the values. We want this adjustment to look as if the ++ * total disk space were reduced, not as if the usage were increased. ++ * -- SAW ++ */ ++ adj_blk = 0; ++ if (buf->f_bfree < free_blk) ++ adj_blk = free_blk - buf->f_bfree; ++ buf->f_bfree = free_blk - adj_blk; ++ ++ if (free_blk < buf->f_bavail) ++ buf->f_bavail = free_blk; ++ ++ blk = (qstat.bsoftlimit >> bsize_bits) - adj_blk; ++ buf->f_blocks = blk > LONG_MAX ? LONG_MAX : blk; ++ ++ free_file = qstat.isoftlimit - qstat.icurrent; ++ if (free_file < 0) ++ free_file = 0; ++ if (buf->f_type == REISERFS_SUPER_MAGIC) ++ /* ++ * reiserfs doesn't initialize f_ffree and f_files values of ++ * kstatfs because it doesn't have an inode limit. ++ */ ++ buf->f_ffree = free_file; ++ adj_file = 0; ++ if (buf->f_ffree < free_file) ++ adj_file = free_file - buf->f_ffree; ++ buf->f_ffree = free_file - adj_file; ++ buf->f_files = qstat.isoftlimit - adj_file; ++} ++ ++static int sim_statfs(struct super_block *sb, struct kstatfs *buf) ++{ ++ int err; ++ struct super_block *lsb; ++ struct kstatfs statbuf; ++ ++ err = 0; ++ if (sb->s_op != &sim_super_ops) ++ return 0; ++ ++ memset(&statbuf, 0, sizeof(statbuf)); ++ lsb = SIMFS_GET_LOWER_FS_SB(sb); ++ ++ err = -ENOSYS; ++ if (lsb && lsb->s_op && lsb->s_op->statfs) ++ err = lsb->s_op->statfs(lsb->s_root, &statbuf); ++ if (err) ++ return err; ++ ++ quota_get_stat(sb, &statbuf); ++ ++ buf->f_files = statbuf.f_files; ++ buf->f_ffree = statbuf.f_ffree; ++ buf->f_blocks = statbuf.f_blocks; ++ buf->f_bfree = statbuf.f_bfree; ++ buf->f_bavail = statbuf.f_bavail; ++ return 0; ++} ++ ++static int sim_systemcall(struct vnotifier_block *me, unsigned long n, ++ void *d, int old_ret) ++{ ++ int err; ++ ++ switch (n) { ++ case VIRTINFO_FAUDIT_STAT: { ++ struct faudit_stat_arg *arg; ++ ++ arg = (struct faudit_stat_arg *)d; ++ err = sim_getattr(arg->mnt, arg->dentry, arg->stat); ++ arg->err = err; ++ } ++ break; ++ case VIRTINFO_FAUDIT_STATFS: { ++ struct faudit_statfs_arg *arg; ++ ++ arg = (struct faudit_statfs_arg *)d; ++ err = sim_statfs(arg->sb, arg->stat); ++ arg->err = err; ++ } ++ break; ++ default: ++ return old_ret; ++ } ++ return (err ? NOTIFY_BAD : NOTIFY_OK); ++} ++ ++static struct inode *sim_quota_root(struct super_block *sb) ++{ ++ return sb->s_root->d_inode; ++} ++ ++/* ++ * NOTE: We need to setup s_bdev field on super block, since sys_quotactl() ++ * does lookup_bdev() and get_super() which are comparing sb->s_bdev. ++ * so this is a MUST if we want unmodified sys_quotactl ++ * to work correctly on /dev/simfs inside VE ++ */ ++static int sim_init_blkdev(struct super_block *sb) ++{ ++ static struct hd_struct fake_hd; ++ struct block_device *blkdev; ++ ++ blkdev = bdget(sb->s_dev); ++ if (blkdev == NULL) ++ return -ENOMEM; ++ ++ blkdev->bd_part = &fake_hd; /* required for bdev_read_only() */ ++ sb->s_bdev = blkdev; ++ ++ return 0; ++} ++ ++static void sim_free_blkdev(struct super_block *sb) ++{ ++ /* set bd_part back to NULL */ ++ sb->s_bdev->bd_part = NULL; ++ bdput(sb->s_bdev); ++} ++ ++static void sim_quota_init(struct super_block *sb) ++{ ++ struct virt_info_quota viq; ++ ++ viq.super = sb; ++ virtinfo_notifier_call(VITYPE_QUOTA, VIRTINFO_QUOTA_ON, &viq); ++} ++ ++static void sim_quota_free(struct super_block *sb) ++{ ++ struct virt_info_quota viq; ++ ++ viq.super = sb; ++ virtinfo_notifier_call(VITYPE_QUOTA, VIRTINFO_QUOTA_OFF, &viq); ++} ++ ++static struct super_operations sim_super_ops = { ++ .get_quota_root = sim_quota_root, ++}; ++ ++static int sim_fill_super(struct super_block *s, void *data) ++{ ++ int err; ++ struct nameidata *nd; ++ ++ err = set_anon_super(s, NULL); ++ if (err) ++ goto out; ++ ++ err = 0; ++ nd = (struct nameidata *)data; ++ s->s_fs_info = mntget(nd->mnt); ++ s->s_root = dget(nd->dentry); ++ s->s_op = &sim_super_ops; ++out: ++ return err; ++} ++ ++static int sim_get_sb(struct file_system_type *type, int flags, ++ const char *dev_name, void *opt, struct vfsmount *mnt) ++{ ++ int err; ++ struct nameidata nd; ++ struct super_block *sb; ++ ++ err = -EINVAL; ++ if (opt == NULL) ++ goto out; ++ ++ err = path_lookup(opt, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd); ++ if (err) ++ goto out; ++ ++ sb = sget(type, NULL, sim_fill_super, &nd); ++ err = PTR_ERR(sb); ++ if (IS_ERR(sb)) ++ goto out_path; ++ ++ err = sim_init_blkdev(sb); ++ if (err) ++ goto out_killsb; ++ ++ sim_quota_init(sb); ++ ++ path_release(&nd); ++ return simple_set_mnt(mnt, sb); ++ ++out_killsb: ++ up_write(&sb->s_umount); ++ deactivate_super(sb); ++out_path: ++ path_release(&nd); ++out: ++ return err; ++} ++ ++static void sim_kill_sb(struct super_block *sb) ++{ ++ dput(sb->s_root); ++ sb->s_root = NULL; ++ mntput((struct vfsmount *)(sb->s_fs_info)); ++ ++ sim_quota_free(sb); ++ sim_free_blkdev(sb); ++ ++ kill_anon_super(sb); ++} ++ ++static struct file_system_type sim_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "simfs", ++ .get_sb = sim_get_sb, ++ .kill_sb = sim_kill_sb, ++ .fs_flags = FS_MANGLE_PROC, ++}; ++ ++static struct vnotifier_block sim_syscalls = { ++ .notifier_call = sim_systemcall, ++}; ++ ++static int __init init_simfs(void) ++{ ++ int err; ++ ++ err = register_filesystem(&sim_fs_type); ++ if (err) ++ return err; ++ ++ virtinfo_notifier_register(VITYPE_FAUDIT, &sim_syscalls); ++ return 0; ++} ++ ++static void __exit exit_simfs(void) ++{ ++ virtinfo_notifier_unregister(VITYPE_FAUDIT, &sim_syscalls); ++ unregister_filesystem(&sim_fs_type); ++} ++ ++MODULE_AUTHOR("SWsoft "); ++MODULE_DESCRIPTION("Open Virtuozzo Simulation of File System"); ++MODULE_LICENSE("GPL v2"); ++ ++module_init(init_simfs); ++module_exit(exit_simfs); +Index: kernel/fs/smbfs/sock.c +=================================================================== +--- kernel.orig/fs/smbfs/sock.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/smbfs/sock.c 2008-11-24 15:47:46.000000000 +0100 +@@ -99,6 +99,7 @@ + + VERBOSE("closing socket %p\n", sock); + sock->sk->sk_data_ready = server->data_ready; ++ sock->sk->sk_user_data = NULL; + server->sock_file = NULL; + fput(file); + } +Index: kernel/fs/stat.c +=================================================================== +--- kernel.orig/fs/stat.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/stat.c 2008-11-24 15:47:46.000000000 +0100 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -41,11 +42,19 @@ + { + struct inode *inode = dentry->d_inode; + int retval; ++ struct faudit_stat_arg arg; + + retval = security_inode_getattr(mnt, dentry); + if (retval) + return retval; + ++ arg.mnt = mnt; ++ arg.dentry = dentry; ++ arg.stat = stat; ++ if (virtinfo_notifier_call(VITYPE_FAUDIT, VIRTINFO_FAUDIT_STAT, &arg) ++ != NOTIFY_DONE) ++ return arg.err; ++ + if (inode->i_op->getattr) + return inode->i_op->getattr(mnt, dentry, stat); + +Index: kernel/fs/super.c +=================================================================== +--- kernel.orig/fs/super.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/super.c 2008-11-24 15:47:46.000000000 +0100 +@@ -37,11 +37,14 @@ + #include + #include + #include ++#include + #include + + + LIST_HEAD(super_blocks); ++EXPORT_SYMBOL_GPL(super_blocks); + DEFINE_SPINLOCK(sb_lock); ++EXPORT_SYMBOL_GPL(sb_lock); + + /** + * alloc_super - create new superblock +@@ -70,13 +73,15 @@ + INIT_LIST_HEAD(&s->s_inodes); + init_rwsem(&s->s_umount); + mutex_init(&s->s_lock); +- lockdep_set_class(&s->s_umount, &type->s_umount_key); ++ lockdep_set_class(&s->s_umount, ++ &type->proto->s_umount_key); + /* + * The locking rules for s_lock are up to the + * filesystem. For example ext3fs has different + * lock ordering than usbfs: + */ +- lockdep_set_class(&s->s_lock, &type->s_lock_key); ++ lockdep_set_class(&s->s_lock, ++ &type->proto->s_lock_key); + down_write(&s->s_umount); + s->s_count = S_BIAS; + atomic_set(&s->s_active, 1); +@@ -300,7 +305,7 @@ + sop->put_super(sb); + + /* Forget any remaining inodes */ +- if (invalidate_inodes(sb)) { ++ if (invalidate_inodes_check(sb, 1)) { + printk("VFS: Busy inodes after unmount of %s. " + "Self-destruct in 5 seconds. Have a nice day...\n", + sb->s_id); +@@ -529,17 +534,26 @@ + spin_unlock(&sb_lock); + return NULL; + } ++EXPORT_SYMBOL(user_get_super); + + asmlinkage long sys_ustat(unsigned dev, struct ustat __user * ubuf) + { ++ dev_t kdev; + struct super_block *s; + struct ustat tmp; + struct kstatfs sbuf; +- int err = -EINVAL; ++ int err; ++ ++ kdev = new_decode_dev(dev); ++ err = get_device_perms_ve(S_IFBLK, kdev, FMODE_READ); ++ if (err) ++ goto out; ++ ++ err = -EINVAL; ++ s = user_get_super(kdev); ++ if (s == NULL) ++ goto out; + +- s = user_get_super(new_decode_dev(dev)); +- if (s == NULL) +- goto out; + err = vfs_statfs(s->s_root, &sbuf); + drop_super(s); + if (err) +@@ -655,6 +669,13 @@ + static struct idr unnamed_dev_idr; + static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */ + ++/* for compatibility with coreutils still unaware of new minor sizes */ ++int unnamed_dev_majors[] = { ++ 0, 144, 145, 146, 242, 243, 244, 245, ++ 246, 247, 248, 249, 250, 251, 252, 253 ++}; ++EXPORT_SYMBOL(unnamed_dev_majors); ++ + int set_anon_super(struct super_block *s, void *data) + { + int dev; +@@ -672,13 +693,13 @@ + else if (error) + return -EAGAIN; + +- if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) { ++ if ((dev & MAX_ID_MASK) >= (1 << MINORBITS)) { + spin_lock(&unnamed_dev_lock); + idr_remove(&unnamed_dev_idr, dev); + spin_unlock(&unnamed_dev_lock); + return -EMFILE; + } +- s->s_dev = MKDEV(0, dev & MINORMASK); ++ s->s_dev = make_unnamed_dev(dev); + return 0; + } + +@@ -686,8 +707,9 @@ + + void kill_anon_super(struct super_block *sb) + { +- int slot = MINOR(sb->s_dev); ++ int slot; + ++ slot = unnamed_dev_idx(sb->s_dev); + generic_shutdown_super(sb); + spin_lock(&unnamed_dev_lock); + idr_remove(&unnamed_dev_idr, slot); +Index: kernel/fs/sync.c +=================================================================== +--- kernel.orig/fs/sync.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/sync.c 2008-11-24 15:47:46.000000000 +0100 +@@ -14,6 +14,10 @@ + #include + #include + ++#include ++ ++#include ++ + #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ + SYNC_FILE_RANGE_WAIT_AFTER) + +@@ -38,7 +42,14 @@ + + asmlinkage long sys_sync(void) + { ++ struct user_beancounter *ub; ++ ++ ub = get_exec_ub(); ++ ub_percpu_inc(ub, sync); ++ + do_sync(1); ++ ++ ub_percpu_inc(ub, sync_done); + return 0; + } + +@@ -80,6 +91,7 @@ + int ret; + int err; + struct address_space *mapping = file->f_mapping; ++ struct user_beancounter *ub; + + if (!file->f_op || !file->f_op->fsync) { + /* Why? We can still call filemap_fdatawrite */ +@@ -87,6 +99,12 @@ + goto out; + } + ++ ub = get_exec_ub(); ++ if (datasync) ++ ub_percpu_inc(ub, fdsync); ++ else ++ ub_percpu_inc(ub, fsync); ++ + ret = filemap_fdatawrite(mapping); + + /* +@@ -101,6 +119,11 @@ + err = filemap_fdatawait(mapping); + if (!ret) + ret = err; ++ ++ if (datasync) ++ ub_percpu_inc(ub, fdsync_done); ++ else ++ ub_percpu_inc(ub, fsync_done); + out: + return ret; + } +@@ -251,12 +274,16 @@ + loff_t endbyte, unsigned int flags) + { + int ret; ++ struct user_beancounter *ub; + + if (!mapping) { + ret = -EINVAL; +- goto out; ++ goto out_noacct; + } + ++ ub = get_exec_ub(); ++ ub_percpu_inc(ub, frsync); ++ + ret = 0; + if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) { + ret = wait_on_page_writeback_range(mapping, +@@ -279,6 +306,8 @@ + endbyte >> PAGE_CACHE_SHIFT); + } + out: ++ ub_percpu_inc(ub, frsync_done); ++out_noacct: + return ret; + } + EXPORT_SYMBOL_GPL(do_sync_mapping_range); +Index: kernel/fs/sysfs/bin.c +=================================================================== +--- kernel.orig/fs/sysfs/bin.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/sysfs/bin.c 2008-11-24 15:47:46.000000000 +0100 +@@ -177,6 +177,9 @@ + struct bin_buffer *bb = NULL; + int error; + ++ if (!ve_sysfs_alowed()) ++ return 0; ++ + /* binary file operations requires both @sd and its parent */ + if (!sysfs_get_active_two(attr_sd)) + return -ENODEV; +@@ -252,6 +255,8 @@ + + void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr) + { ++ if (!ve_sysfs_alowed()) ++ return; + sysfs_hash_and_remove(kobj->sd, attr->attr.name); + } + +Index: kernel/fs/sysfs/dir.c +=================================================================== +--- kernel.orig/fs/sysfs/dir.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/sysfs/dir.c 2008-11-24 15:47:46.000000000 +0100 +@@ -481,6 +481,9 @@ + struct inode *inode; + struct dentry *dentry; + ++ if (!ve_sysfs_alowed()) ++ return; ++ + inode = ilookup(sysfs_sb, sd->s_ino); + if (!inode) + return; +@@ -657,7 +660,7 @@ + if (kobj->parent) + parent_sd = kobj->parent->sd; + else +- parent_sd = &sysfs_root; ++ parent_sd = ve_sysfs_root; + + error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd); + if (!error) +@@ -758,6 +761,9 @@ + { + struct sysfs_dirent *sd = kobj->sd; + ++ if (!ve_sysfs_alowed()) ++ return; ++ + spin_lock(&sysfs_assoc_lock); + kobj->sd = NULL; + spin_unlock(&sysfs_assoc_lock); +@@ -773,6 +779,9 @@ + const char *dup_name = NULL; + int error; + ++ if (!ve_sysfs_alowed()) ++ return 0; ++ + mutex_lock(&sysfs_rename_mutex); + + error = 0; +@@ -841,7 +850,7 @@ + + mutex_lock(&sysfs_rename_mutex); + BUG_ON(!sd->s_parent); +- new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; ++ new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : ve_sysfs_root; + + error = 0; + if (sd->s_parent == new_parent_sd) +Index: kernel/fs/sysfs/file.c +=================================================================== +--- kernel.orig/fs/sysfs/file.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/sysfs/file.c 2008-11-24 15:47:46.000000000 +0100 +@@ -549,6 +549,8 @@ + + int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) + { ++ if (!ve_sysfs_alowed()) ++ return 0; + BUG_ON(!kobj || !kobj->sd || !attr); + + return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR); +@@ -641,16 +643,18 @@ + + void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) + { ++ if (!ve_sysfs_alowed()) ++ return; + sysfs_hash_and_remove(kobj->sd, attr->name); + } + +- + /** + * sysfs_remove_file_from_group - remove an attribute file from a group. + * @kobj: object we're acting for. + * @attr: attribute descriptor. + * @group: group name. + */ ++ + void sysfs_remove_file_from_group(struct kobject *kobj, + const struct attribute *attr, const char *group) + { +Index: kernel/fs/sysfs/group.c +=================================================================== +--- kernel.orig/fs/sysfs/group.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/sysfs/group.c 2008-11-24 15:47:46.000000000 +0100 +@@ -45,6 +45,8 @@ + struct sysfs_dirent *sd; + int error; + ++ if (!ve_sysfs_alowed()) ++ return 0; + BUG_ON(!kobj || !kobj->sd); + + if (grp->name) { +@@ -69,6 +71,9 @@ + struct sysfs_dirent *dir_sd = kobj->sd; + struct sysfs_dirent *sd; + ++ if (!ve_sysfs_alowed()) ++ return; ++ + if (grp->name) { + sd = sysfs_get_dirent(dir_sd, grp->name); + BUG_ON(!sd); +Index: kernel/fs/sysfs/inode.c +=================================================================== +--- kernel.orig/fs/sysfs/inode.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/sysfs/inode.c 2008-11-24 15:47:46.000000000 +0100 +@@ -20,8 +20,6 @@ + #include + #include "sysfs.h" + +-extern struct super_block * sysfs_sb; +- + static const struct address_space_operations sysfs_aops = { + .readpage = simple_readpage, + .write_begin = simple_write_begin, +Index: kernel/fs/sysfs/mount.c +=================================================================== +--- kernel.orig/fs/sysfs/mount.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/sysfs/mount.c 2008-11-24 15:47:46.000000000 +0100 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + + #include "sysfs.h" +@@ -22,8 +23,11 @@ + /* Random magic number */ + #define SYSFS_MAGIC 0x62656572 + +-static struct vfsmount *sysfs_mount; ++#ifndef CONFIG_VE ++struct vfsmount *sysfs_mount; + struct super_block * sysfs_sb = NULL; ++#endif ++ + struct kmem_cache *sysfs_dir_cachep; + + static const struct super_operations sysfs_ops = { +@@ -39,6 +43,13 @@ + .s_ino = 1, + }; + ++static void init_ve0_sysfs_root(void) ++{ ++#ifdef CONFIG_VE ++ get_ve0()->_sysfs_root = &sysfs_root; ++#endif ++} ++ + static int sysfs_fill_super(struct super_block *sb, void *data, int silent) + { + struct inode *inode; +@@ -52,7 +63,7 @@ + sysfs_sb = sb; + + /* get root inode, initialize and unlock it */ +- inode = sysfs_get_inode(&sysfs_root); ++ inode = sysfs_get_inode(ve_sysfs_root); + if (!inode) { + pr_debug("sysfs: could not get root inode\n"); + return -ENOMEM; +@@ -65,7 +76,7 @@ + iput(inode); + return -ENOMEM; + } +- root->d_fsdata = &sysfs_root; ++ root->d_fsdata = ve_sysfs_root; + sb->s_root = root; + return 0; + } +@@ -76,16 +87,19 @@ + return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt); + } + +-static struct file_system_type sysfs_fs_type = { ++struct file_system_type sysfs_fs_type = { + .name = "sysfs", + .get_sb = sysfs_get_sb, + .kill_sb = kill_anon_super, + }; + ++EXPORT_SYMBOL(sysfs_fs_type); ++ + int __init sysfs_init(void) + { + int err = -ENOMEM; + ++ init_ve0_sysfs_root(); + sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache", + sizeof(struct sysfs_dirent), + 0, 0, NULL); +Index: kernel/fs/sysfs/symlink.c +=================================================================== +--- kernel.orig/fs/sysfs/symlink.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/sysfs/symlink.c 2008-11-24 15:47:46.000000000 +0100 +@@ -66,10 +66,13 @@ + struct sysfs_addrm_cxt acxt; + int error; + ++ if (!ve_sysfs_alowed()) ++ return 0; ++ + BUG_ON(!name); + + if (!kobj) +- parent_sd = &sysfs_root; ++ parent_sd = ve_sysfs_root; + else + parent_sd = kobj->sd; + +@@ -121,6 +124,8 @@ + + void sysfs_remove_link(struct kobject * kobj, const char * name) + { ++ if(!ve_sysfs_alowed()) ++ return; + sysfs_hash_and_remove(kobj->sd, name); + } + +Index: kernel/fs/sysfs/sysfs.h +=================================================================== +--- kernel.orig/fs/sysfs/sysfs.h 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/sysfs/sysfs.h 2008-11-24 15:47:46.000000000 +0100 +@@ -8,67 +8,17 @@ + * This file is released under the GPLv2. + */ + +-struct sysfs_open_dirent; +- +-/* type-specific structures for sysfs_dirent->s_* union members */ +-struct sysfs_elem_dir { +- struct kobject *kobj; +- /* children list starts here and goes through sd->s_sibling */ +- struct sysfs_dirent *children; +-}; +- +-struct sysfs_elem_symlink { +- struct sysfs_dirent *target_sd; +-}; +- +-struct sysfs_elem_attr { +- struct attribute *attr; +- struct sysfs_open_dirent *open; +-}; +- +-struct sysfs_elem_bin_attr { +- struct bin_attribute *bin_attr; +-}; +- +-/* +- * sysfs_dirent - the building block of sysfs hierarchy. Each and +- * every sysfs node is represented by single sysfs_dirent. +- * +- * As long as s_count reference is held, the sysfs_dirent itself is +- * accessible. Dereferencing s_elem or any other outer entity +- * requires s_active reference. +- */ +-struct sysfs_dirent { +- atomic_t s_count; +- atomic_t s_active; +- struct sysfs_dirent *s_parent; +- struct sysfs_dirent *s_sibling; +- const char *s_name; +- +- union { +- struct sysfs_elem_dir s_dir; +- struct sysfs_elem_symlink s_symlink; +- struct sysfs_elem_attr s_attr; +- struct sysfs_elem_bin_attr s_bin_attr; +- }; +- +- unsigned int s_flags; +- ino_t s_ino; +- umode_t s_mode; +- struct iattr *s_iattr; +-}; +- +-#define SD_DEACTIVATED_BIAS INT_MIN +- +-#define SYSFS_TYPE_MASK 0x00ff +-#define SYSFS_DIR 0x0001 +-#define SYSFS_KOBJ_ATTR 0x0002 +-#define SYSFS_KOBJ_BIN_ATTR 0x0004 +-#define SYSFS_KOBJ_LINK 0x0008 +-#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) +- +-#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK +-#define SYSFS_FLAG_REMOVED 0x0200 ++#ifndef CONFIG_VE ++extern struct vfsmount *sysfs_mount; ++extern struct super_block *sysfs_sb; ++#define ve_sysfs_alowed() 1 ++#else ++#include ++#include ++#define sysfs_mount (get_exec_env()->sysfs_mnt) ++#define sysfs_sb (get_exec_env()->sysfs_sb) ++#define ve_sysfs_alowed() (sysfs_sb != NULL) ++#endif + + static inline unsigned int sysfs_type(struct sysfs_dirent *sd) + { +@@ -88,8 +38,12 @@ + /* + * mount.c + */ ++#ifdef CONFIG_VE ++#define ve_sysfs_root (get_exec_env()->_sysfs_root) ++#else + extern struct sysfs_dirent sysfs_root; +-extern struct super_block *sysfs_sb; ++#define ve_sysfs_root (&sysfs_root) ++#endif + extern struct kmem_cache *sysfs_dir_cachep; + + /* +Index: kernel/fs/utimes.c +=================================================================== +--- kernel.orig/fs/utimes.c 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/fs/utimes.c 2008-11-24 15:47:46.000000000 +0100 +@@ -57,7 +57,7 @@ + */ + long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags) + { +- int error; ++ int error = -EINVAL; + struct nameidata nd; + struct path path; + struct inode *inode; +@@ -212,3 +212,18 @@ + { + return sys_futimesat(AT_FDCWD, filename, utimes); + } ++ ++asmlinkage long sys_lutime(char __user *filename, struct utimbuf __user *times) ++{ ++ struct timespec tv[2]; ++ ++ if (times) { ++ if (get_user(tv[0].tv_sec, ×->actime) || ++ get_user(tv[1].tv_sec, ×->modtime)) ++ return -EFAULT; ++ tv[0].tv_nsec = 0; ++ tv[1].tv_nsec = 0; ++ } ++ ++ return do_utimes(AT_FDCWD, filename, times ? tv : NULL, AT_SYMLINK_NOFOLLOW); ++} +Index: kernel/fs/vzdq_file.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/fs/vzdq_file.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,909 @@ ++/* ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * This file contains Virtuozzo quota files as proc entry implementation. ++ * It is required for std quota tools to work correctly as they are expecting ++ * aquota.user and aquota.group files. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* ---------------------------------------------------------------------- ++ * ++ * File read operation ++ * ++ * FIXME: functions in this section (as well as many functions in vzdq_ugid.c, ++ * perhaps) abuse vz_quota_sem. ++ * Taking a global semaphore for lengthy and user-controlled operations inside ++ * VPSs is not a good idea in general. ++ * In this case, the reasons for taking this semaphore are completely unclear, ++ * especially taking into account that the only function that has comments ++ * about the necessity to be called under this semaphore ++ * (create_proc_quotafile) is actually called OUTSIDE it. ++ * ++ * --------------------------------------------------------------------- */ ++ ++#define DQBLOCK_SIZE 1024 ++#define DQUOTBLKNUM 21U ++#define DQTREE_DEPTH 4 ++#define TREENUM_2_BLKNUM(num) (((num) + 1) << 1) ++#define ISINDBLOCK(num) ((num)%2 != 0) ++#define FIRST_DATABLK 2 /* first even number */ ++#define LAST_IND_LEVEL (DQTREE_DEPTH - 1) ++#define CONVERT_LEVEL(level) ((level) * (QUOTAID_EBITS/QUOTAID_BBITS)) ++#define GETLEVINDX(ind, lev) (((ind) >> QUOTAID_BBITS*(lev)) \ ++ & QUOTATREE_BMASK) ++ ++#if (QUOTAID_EBITS / QUOTAID_BBITS) != (QUOTATREE_DEPTH / DQTREE_DEPTH) ++#error xBITS and DQTREE_DEPTH does not correspond ++#endif ++ ++#define BLOCK_NOT_FOUND 1 ++ ++/* data for quota file -- one per proc entry */ ++struct quotatree_data { ++ struct list_head list; ++ struct vz_quota_master *qmblk; ++ int type; /* type of the tree */ ++}; ++ ++/* serialized by vz_quota_sem */ ++static LIST_HEAD(qf_data_head); ++ ++static const u_int32_t vzquota_magics[] = V2_INITQMAGICS; ++static const u_int32_t vzquota_versions[] = V2_INITQVERSIONS; ++static const char aquota_user[] = "aquota.user"; ++static const char aquota_group[] = "aquota.group"; ++ ++ ++static inline loff_t get_depoff(int depth) ++{ ++ loff_t res = 1; ++ while (depth) { ++ res += (1 << ((depth - 1)*QUOTAID_EBITS + 1)); ++ depth--; ++ } ++ return res; ++} ++ ++static inline loff_t get_blknum(loff_t num, int depth) ++{ ++ loff_t res; ++ res = (num << 1) + get_depoff(depth); ++ return res; ++} ++ ++static int get_depth(loff_t num) ++{ ++ int i; ++ for (i = 0; i < DQTREE_DEPTH; i++) { ++ if (num >= get_depoff(i) && (i == DQTREE_DEPTH - 1 ++ || num < get_depoff(i + 1))) ++ return i; ++ } ++ return -1; ++} ++ ++static inline loff_t get_offset(loff_t num) ++{ ++ loff_t res, tmp; ++ ++ tmp = get_depth(num); ++ if (tmp < 0) ++ return -1; ++ num -= get_depoff(tmp); ++ BUG_ON(num < 0); ++ res = num >> 1; ++ ++ return res; ++} ++ ++static inline loff_t get_quot_blk_num(struct quotatree_tree *tree, int level) ++{ ++ /* return maximum available block num */ ++ return tree->levels[level].freenum; ++} ++ ++static inline loff_t get_block_num(struct quotatree_tree *tree) ++{ ++ loff_t ind_blk_num, quot_blk_num, max_ind, max_quot; ++ ++ quot_blk_num = get_quot_blk_num(tree, CONVERT_LEVEL(DQTREE_DEPTH) - 1); ++ max_quot = TREENUM_2_BLKNUM(quot_blk_num); ++ ind_blk_num = get_quot_blk_num(tree, CONVERT_LEVEL(DQTREE_DEPTH - 1)); ++ max_ind = (quot_blk_num) ? get_blknum(ind_blk_num, LAST_IND_LEVEL) ++ : get_blknum(ind_blk_num, 0); ++ ++ return (max_ind > max_quot) ? max_ind + 1 : max_quot + 1; ++} ++ ++/* Write quota file header */ ++static int read_header(void *buf, struct quotatree_tree *tree, ++ struct dq_info *dq_ugid_info, int type) ++{ ++ struct v2_disk_dqheader *dqh; ++ struct v2_disk_dqinfo *dq_disk_info; ++ ++ dqh = buf; ++ dq_disk_info = buf + sizeof(struct v2_disk_dqheader); ++ ++ dqh->dqh_magic = vzquota_magics[type]; ++ dqh->dqh_version = vzquota_versions[type]; ++ ++ dq_disk_info->dqi_bgrace = dq_ugid_info[type].bexpire; ++ dq_disk_info->dqi_igrace = dq_ugid_info[type].iexpire; ++ dq_disk_info->dqi_flags = 0; /* no flags */ ++ dq_disk_info->dqi_blocks = get_block_num(tree); ++ dq_disk_info->dqi_free_blk = 0; /* first block in the file */ ++ dq_disk_info->dqi_free_entry = FIRST_DATABLK; ++ ++ return 0; ++} ++ ++static int get_block_child(int depth, struct quotatree_node *p, u_int32_t *buf) ++{ ++ int i, j, lev_num; ++ ++ lev_num = QUOTATREE_DEPTH/DQTREE_DEPTH - 1; ++ for (i = 0; i < BLOCK_SIZE/sizeof(u_int32_t); i++) { ++ struct quotatree_node *next, *parent; ++ ++ parent = p; ++ next = p; ++ for (j = lev_num; j >= 0; j--) { ++ if (!next->blocks[GETLEVINDX(i,j)]) { ++ buf[i] = 0; ++ goto bad_branch; ++ } ++ parent = next; ++ next = next->blocks[GETLEVINDX(i,j)]; ++ } ++ buf[i] = (depth == DQTREE_DEPTH - 1) ? ++ TREENUM_2_BLKNUM(parent->num) ++ : get_blknum(next->num, depth + 1); ++ ++ bad_branch: ++ ; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Write index block to disk (or buffer) ++ * @buf has length 256*sizeof(u_int32_t) bytes ++ */ ++static int read_index_block(int num, u_int32_t *buf, ++ struct quotatree_tree *tree) ++{ ++ struct quotatree_node *p; ++ u_int32_t index; ++ loff_t off; ++ int depth, res; ++ ++ res = BLOCK_NOT_FOUND; ++ index = 0; ++ depth = get_depth(num); ++ off = get_offset(num); ++ if (depth < 0 || off < 0) ++ return -EINVAL; ++ ++ list_for_each_entry(p, &tree->levels[CONVERT_LEVEL(depth)].usedlh, ++ list) { ++ if (p->num >= off) ++ res = 0; ++ if (p->num != off) ++ continue; ++ get_block_child(depth, p, buf); ++ break; ++ } ++ ++ return res; ++} ++ ++static inline void convert_quot_format(struct v2_disk_dqblk *dq, ++ struct vz_quota_ugid *vzq) ++{ ++ dq->dqb_id = vzq->qugid_id; ++ dq->dqb_ihardlimit = vzq->qugid_stat.ihardlimit; ++ dq->dqb_isoftlimit = vzq->qugid_stat.isoftlimit; ++ dq->dqb_curinodes = vzq->qugid_stat.icurrent; ++ dq->dqb_bhardlimit = vzq->qugid_stat.bhardlimit / QUOTABLOCK_SIZE; ++ dq->dqb_bsoftlimit = vzq->qugid_stat.bsoftlimit / QUOTABLOCK_SIZE; ++ dq->dqb_curspace = vzq->qugid_stat.bcurrent; ++ dq->dqb_btime = vzq->qugid_stat.btime; ++ dq->dqb_itime = vzq->qugid_stat.itime; ++} ++ ++static int read_dquot(loff_t num, void *buf, struct quotatree_tree *tree) ++{ ++ int res, i, entries = 0; ++ struct v2_disk_dqdbheader *dq_header; ++ struct quotatree_node *p; ++ struct v2_disk_dqblk *blk = buf + sizeof(struct v2_disk_dqdbheader); ++ ++ res = BLOCK_NOT_FOUND; ++ dq_header = buf; ++ memset(dq_header, 0, sizeof(*dq_header)); ++ ++ list_for_each_entry(p, &(tree->levels[QUOTATREE_DEPTH - 1].usedlh), ++ list) { ++ if (TREENUM_2_BLKNUM(p->num) >= num) ++ res = 0; ++ if (TREENUM_2_BLKNUM(p->num) != num) ++ continue; ++ ++ for (i = 0; i < QUOTATREE_BSIZE; i++) { ++ if (!p->blocks[i]) ++ continue; ++ convert_quot_format(blk + entries, ++ (struct vz_quota_ugid *)p->blocks[i]); ++ entries++; ++ res = 0; ++ } ++ break; ++ } ++ dq_header->dqdh_entries = entries; ++ ++ return res; ++} ++ ++static int read_block(int num, void *buf, struct quotatree_tree *tree, ++ struct dq_info *dq_ugid_info, int magic) ++{ ++ int res; ++ ++ memset(buf, 0, DQBLOCK_SIZE); ++ if (!num) ++ res = read_header(buf, tree, dq_ugid_info, magic); ++ else if (ISINDBLOCK(num)) ++ res = read_index_block(num, (u_int32_t*)buf, tree); ++ else ++ res = read_dquot(num, buf, tree); ++ ++ return res; ++} ++ ++/* ++ * FIXME: this function can handle quota files up to 2GB only. ++ */ ++static int read_proc_quotafile(char *page, char **start, off_t off, int count, ++ int *eof, void *data) ++{ ++ off_t blk_num, blk_off, buf_off; ++ char *tmp; ++ size_t buf_size; ++ struct quotatree_data *qtd; ++ struct quotatree_tree *tree; ++ struct dq_info *dqi; ++ int res; ++ ++ *start = NULL; ++ tmp = kmalloc(DQBLOCK_SIZE, GFP_KERNEL); ++ if (!tmp) ++ return -ENOMEM; ++ ++ qtd = data; ++ down(&vz_quota_sem); ++ down(&qtd->qmblk->dq_sem); ++ ++ res = 0; ++ tree = QUGID_TREE(qtd->qmblk, qtd->type); ++ if (!tree) { ++ *eof = 1; ++ goto out_dq; ++ } ++ ++ dqi = &qtd->qmblk->dq_ugid_info[qtd->type]; ++ ++ buf_off = 0; ++ buf_size = count; ++ blk_num = off / DQBLOCK_SIZE; ++ blk_off = off % DQBLOCK_SIZE; ++ ++ while (buf_size > 0) { ++ off_t len; ++ ++ len = min((size_t)(DQBLOCK_SIZE-blk_off), buf_size); ++ res = read_block(blk_num, tmp, tree, dqi, qtd->type); ++ if (res < 0) ++ goto out_err; ++ if (res == BLOCK_NOT_FOUND) { ++ *eof = 1; ++ break; ++ } ++ memcpy(page + buf_off, tmp + blk_off, len); ++ ++ blk_num++; ++ buf_size -= len; ++ blk_off = 0; ++ buf_off += len; ++ } ++ res = buf_off; ++ ++out_err: ++ *start += count; ++out_dq: ++ up(&qtd->qmblk->dq_sem); ++ up(&vz_quota_sem); ++ kfree(tmp); ++ ++ return res; ++} ++ ++ ++/* ---------------------------------------------------------------------- ++ * ++ * /proc/vz/vzaquota/QID/aquota.* files ++ * ++ * FIXME: this code lacks serialization of read/readdir/lseek. ++ * However, this problem should be fixed after the mainstream issue of what ++ * appears to be non-atomic read and update of file position in sys_read. ++ * ++ * --------------------------------------------------------------------- */ ++ ++static inline unsigned long vzdq_aquot_getino(dev_t dev) ++{ ++ return 0xec000000UL + dev; ++} ++ ++static inline dev_t vzdq_aquot_getidev(struct inode *inode) ++{ ++ return (dev_t)(unsigned long)PROC_I(inode)->op.proc_get_link; ++} ++ ++static inline void vzdq_aquot_setidev(struct inode *inode, dev_t dev) ++{ ++ PROC_I(inode)->op.proc_get_link = (void *)(unsigned long)dev; ++} ++ ++static ssize_t vzdq_aquotf_read(struct file *file, ++ char __user *buf, size_t size, loff_t *ppos) ++{ ++ char *page; ++ size_t bufsize; ++ ssize_t l, l2, copied; ++ char *start; ++ struct inode *inode; ++ struct block_device *bdev; ++ struct super_block *sb; ++ struct quotatree_data data; ++ int eof, err; ++ ++ err = -ENOMEM; ++ page = (char *)__get_free_page(GFP_KERNEL); ++ if (page == NULL) ++ goto out_err; ++ ++ err = -ENODEV; ++ inode = file->f_dentry->d_inode; ++ bdev = bdget(vzdq_aquot_getidev(inode)); ++ if (bdev == NULL) ++ goto out_err; ++ sb = get_super(bdev); ++ bdput(bdev); ++ if (sb == NULL) ++ goto out_err; ++ data.qmblk = vzquota_find_qmblk(sb); ++ data.type = PROC_I(inode)->fd - 1; ++ drop_super(sb); ++ if (data.qmblk == NULL || data.qmblk == VZ_QUOTA_BAD) ++ goto out_err; ++ ++ copied = 0; ++ l = l2 = 0; ++ while (1) { ++ bufsize = min(size, (size_t)PAGE_SIZE); ++ if (bufsize <= 0) ++ break; ++ ++ l = read_proc_quotafile(page, &start, *ppos, bufsize, ++ &eof, &data); ++ if (l <= 0) ++ break; ++ ++ l2 = copy_to_user(buf, page, l); ++ copied += l - l2; ++ if (l2) ++ break; ++ ++ buf += l; ++ size -= l; ++ *ppos += (unsigned long)start; ++ l = l2 = 0; ++ } ++ ++ qmblk_put(data.qmblk); ++ free_page((unsigned long)page); ++ if (copied) ++ return copied; ++ else if (l2) /* last copy_to_user failed */ ++ return -EFAULT; ++ else /* read error or EOF */ ++ return l; ++ ++out_err: ++ if (page != NULL) ++ free_page((unsigned long)page); ++ return err; ++} ++ ++static struct file_operations vzdq_aquotf_file_operations = { ++ .read = &vzdq_aquotf_read, ++}; ++ ++static struct inode_operations vzdq_aquotf_inode_operations = { ++}; ++ ++ ++/* ---------------------------------------------------------------------- ++ * ++ * /proc/vz/vzaquota/QID directory ++ * ++ * --------------------------------------------------------------------- */ ++ ++static int vzdq_aquotq_readdir(struct file *file, void *data, filldir_t filler) ++{ ++ loff_t n; ++ int err; ++ ++ n = file->f_pos; ++ for (err = 0; !err; n++) { ++ /* ppc32 can't cmp 2 long long's in switch, calls __cmpdi2() */ ++ switch ((unsigned long)n) { ++ case 0: ++ err = (*filler)(data, ".", 1, n, ++ file->f_dentry->d_inode->i_ino, ++ DT_DIR); ++ break; ++ case 1: ++ err = (*filler)(data, "..", 2, n, ++ parent_ino(file->f_dentry), DT_DIR); ++ break; ++ case 2: ++ err = (*filler)(data, aquota_user, ++ sizeof(aquota_user)-1, n, ++ file->f_dentry->d_inode->i_ino ++ + USRQUOTA + 1, ++ DT_REG); ++ break; ++ case 3: ++ err = (*filler)(data, aquota_group, ++ sizeof(aquota_group)-1, n, ++ file->f_dentry->d_inode->i_ino ++ + GRPQUOTA + 1, ++ DT_REG); ++ break; ++ default: ++ goto out; ++ } ++ } ++out: ++ file->f_pos = n; ++ return err; ++} ++ ++struct vzdq_aquotq_lookdata { ++ dev_t dev; ++ int type; ++ struct vz_quota_master *qmblk; ++}; ++ ++static int vzdq_aquotq_looktest(struct inode *inode, void *data) ++{ ++ struct vzdq_aquotq_lookdata *d; ++ ++ d = data; ++ return inode->i_op == &vzdq_aquotf_inode_operations && ++ vzdq_aquot_getidev(inode) == d->dev && ++ PROC_I(inode)->fd == d->type + 1; ++} ++ ++static int vzdq_aquotq_lookset(struct inode *inode, void *data) ++{ ++ struct vzdq_aquotq_lookdata *d; ++ struct quotatree_tree *tree; ++ ++ d = data; ++ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; ++ inode->i_ino = vzdq_aquot_getino(d->dev) + d->type + 1; ++ inode->i_mode = S_IFREG | S_IRUSR; ++ inode->i_uid = 0; ++ inode->i_gid = 0; ++ inode->i_nlink = 1; ++ inode->i_op = &vzdq_aquotf_inode_operations; ++ inode->i_fop = &vzdq_aquotf_file_operations; ++ PROC_I(inode)->fd = d->type + 1; ++ vzdq_aquot_setidev(inode, d->dev); ++ ++ /* Setting size */ ++ tree = QUGID_TREE(d->qmblk, PROC_I(inode)->fd - 1); ++ inode->i_size = get_block_num(tree) * 1024; ++ return 0; ++} ++ ++static int vzdq_aquotq_revalidate(struct dentry *vdentry, struct nameidata *nd) ++{ ++ return 0; ++} ++ ++static struct dentry_operations vzdq_aquotq_dentry_operations = { ++ .d_revalidate = &vzdq_aquotq_revalidate, ++}; ++ ++static struct vz_quota_master *find_qmblk_by_dev(dev_t dev) ++{ ++ struct super_block *sb; ++ struct vz_quota_master *qmblk; ++ ++ qmblk = NULL; ++ sb = user_get_super(dev); ++ if (sb != NULL) { ++ qmblk = vzquota_find_qmblk(sb); ++ drop_super(sb); ++ ++ if (qmblk == VZ_QUOTA_BAD) ++ qmblk = NULL; ++ } ++ ++ return qmblk; ++} ++ ++static struct dentry *vzdq_aquotq_lookup(struct inode *dir, ++ struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ struct inode *inode; ++ struct vzdq_aquotq_lookdata d; ++ int k; ++ ++ if (dentry->d_name.len == sizeof(aquota_user)-1) { ++ if (memcmp(dentry->d_name.name, aquota_user, ++ sizeof(aquota_user)-1)) ++ goto out; ++ k = USRQUOTA; ++ } else if (dentry->d_name.len == sizeof(aquota_group)-1) { ++ if (memcmp(dentry->d_name.name, aquota_group, ++ sizeof(aquota_group)-1)) ++ goto out; ++ k = GRPQUOTA; ++ } else ++ goto out; ++ d.dev = vzdq_aquot_getidev(dir); ++ d.type = k; ++ d.qmblk = find_qmblk_by_dev(d.dev); ++ if (d.qmblk == NULL) ++ goto out; ++ ++ inode = iget5_locked(dir->i_sb, dir->i_ino + k + 1, ++ vzdq_aquotq_looktest, vzdq_aquotq_lookset, &d); ++ if (inode == NULL) ++ goto out; ++ unlock_new_inode(inode); ++ dentry->d_op = &vzdq_aquotq_dentry_operations; ++ d_add(dentry, inode); ++ return NULL; ++ ++out: ++ return ERR_PTR(-ENOENT); ++} ++ ++static struct file_operations vzdq_aquotq_file_operations = { ++ .read = &generic_read_dir, ++ .readdir = &vzdq_aquotq_readdir, ++}; ++ ++static struct inode_operations vzdq_aquotq_inode_operations = { ++ .lookup = &vzdq_aquotq_lookup, ++}; ++ ++ ++/* ---------------------------------------------------------------------- ++ * ++ * /proc/vz/vzaquota directory ++ * ++ * --------------------------------------------------------------------- */ ++ ++struct vzdq_aquot_de { ++ struct list_head list; ++ struct vfsmount *mnt; ++}; ++ ++static int vzdq_aquot_buildmntlist(struct ve_struct *ve, ++ struct list_head *head) ++{ ++ struct vfsmount *rmnt, *mnt; ++ struct vzdq_aquot_de *p; ++ int err; ++ ++#ifdef CONFIG_VE ++ rmnt = mntget(ve->fs_rootmnt); ++#else ++ read_lock(¤t->fs->lock); ++ rmnt = mntget(current->fs->rootmnt); ++ read_unlock(¤t->fs->lock); ++#endif ++ mnt = rmnt; ++ spin_lock(&vfsmount_lock); ++ while (1) { ++ list_for_each_entry(p, head, list) { ++ if (p->mnt->mnt_sb == mnt->mnt_sb) ++ goto skip; ++ } ++ ++ err = -ENOMEM; ++ p = kmalloc(sizeof(*p), GFP_ATOMIC); ++ if (p == NULL) ++ goto out; ++ p->mnt = mntget(mnt); ++ list_add_tail(&p->list, head); ++ ++skip: ++ err = 0; ++ if (list_empty(&mnt->mnt_mounts)) { ++ while (1) { ++ if (mnt == rmnt) ++ goto out; ++ if (mnt->mnt_child.next != ++ &mnt->mnt_parent->mnt_mounts) ++ break; ++ mnt = mnt->mnt_parent; ++ } ++ mnt = list_entry(mnt->mnt_child.next, ++ struct vfsmount, mnt_child); ++ } else ++ mnt = list_entry(mnt->mnt_mounts.next, ++ struct vfsmount, mnt_child); ++ } ++out: ++ spin_unlock(&vfsmount_lock); ++ mntput(rmnt); ++ return err; ++} ++ ++static void vzdq_aquot_releasemntlist(struct ve_struct *ve, ++ struct list_head *head) ++{ ++ struct vzdq_aquot_de *p; ++ ++ while (!list_empty(head)) { ++ p = list_entry(head->next, typeof(*p), list); ++ mntput(p->mnt); ++ list_del(&p->list); ++ kfree(p); ++ } ++} ++ ++static int vzdq_aquotd_readdir(struct file *file, void *data, filldir_t filler) ++{ ++ struct ve_struct *ve, *old_ve; ++ struct list_head mntlist; ++ struct vzdq_aquot_de *de; ++ struct super_block *sb; ++ struct vz_quota_master *qmblk; ++ loff_t i, n; ++ char buf[24]; ++ int l, err; ++ ++ i = 0; ++ n = file->f_pos; ++ ve = file->f_dentry->d_sb->s_type->owner_env; ++ old_ve = set_exec_env(ve); ++ ++ INIT_LIST_HEAD(&mntlist); ++#ifdef CONFIG_VE ++ /* ++ * The only reason of disabling readdir for the host system is that ++ * this readdir can be slow and CPU consuming with large number of VPSs ++ * (or just mount points). ++ */ ++ err = ve_is_super(ve); ++#else ++ err = 0; ++#endif ++ if (!err) { ++ err = vzdq_aquot_buildmntlist(ve, &mntlist); ++ if (err) ++ goto out_err; ++ } ++ ++ if (i >= n) { ++ if ((*filler)(data, ".", 1, i, ++ file->f_dentry->d_inode->i_ino, DT_DIR)) ++ goto out_fill; ++ } ++ i++; ++ ++ if (i >= n) { ++ if ((*filler)(data, "..", 2, i, ++ parent_ino(file->f_dentry), DT_DIR)) ++ goto out_fill; ++ } ++ i++; ++ ++ list_for_each_entry (de, &mntlist, list) { ++ sb = de->mnt->mnt_sb; ++ if (get_device_perms_ve(S_IFBLK, sb->s_dev, FMODE_QUOTACTL)) ++ continue; ++ ++ qmblk = vzquota_find_qmblk(sb); ++ if (qmblk == NULL || qmblk == VZ_QUOTA_BAD) ++ continue; ++ ++ qmblk_put(qmblk); ++ i++; ++ if (i <= n) ++ continue; ++ ++ l = sprintf(buf, "%08x", new_encode_dev(sb->s_dev)); ++ if ((*filler)(data, buf, l, i - 1, ++ vzdq_aquot_getino(sb->s_dev), DT_DIR)) ++ break; ++ } ++ ++out_fill: ++ err = 0; ++ file->f_pos = i; ++out_err: ++ vzdq_aquot_releasemntlist(ve, &mntlist); ++ (void)set_exec_env(old_ve); ++ return err; ++} ++ ++static int vzdq_aquotd_looktest(struct inode *inode, void *data) ++{ ++ return inode->i_op == &vzdq_aquotq_inode_operations && ++ vzdq_aquot_getidev(inode) == (dev_t)(unsigned long)data; ++} ++ ++static int vzdq_aquotd_lookset(struct inode *inode, void *data) ++{ ++ dev_t dev; ++ ++ dev = (dev_t)(unsigned long)data; ++ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; ++ inode->i_ino = vzdq_aquot_getino(dev); ++ inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR; ++ inode->i_uid = 0; ++ inode->i_gid = 0; ++ inode->i_nlink = 2; ++ inode->i_op = &vzdq_aquotq_inode_operations; ++ inode->i_fop = &vzdq_aquotq_file_operations; ++ vzdq_aquot_setidev(inode, dev); ++ return 0; ++} ++ ++static struct dentry *vzdq_aquotd_lookup(struct inode *dir, ++ struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ struct ve_struct *ve, *old_ve; ++ const unsigned char *s; ++ int l; ++ dev_t dev; ++ struct inode *inode; ++ ++ ve = dir->i_sb->s_type->owner_env; ++ old_ve = set_exec_env(ve); ++#ifdef CONFIG_VE ++ /* ++ * Lookup is much lighter than readdir, so it can be allowed for the ++ * host system. But it would be strange to be able to do lookup only ++ * without readdir... ++ */ ++ if (ve_is_super(ve)) ++ goto out; ++#endif ++ ++ dev = 0; ++ l = dentry->d_name.len; ++ if (l <= 0) ++ goto out; ++ for (s = dentry->d_name.name; l > 0; s++, l--) { ++ if (!isxdigit(*s)) ++ goto out; ++ if (dev & ~(~0UL >> 4)) ++ goto out; ++ dev <<= 4; ++ if (isdigit(*s)) ++ dev += *s - '0'; ++ else if (islower(*s)) ++ dev += *s - 'a' + 10; ++ else ++ dev += *s - 'A' + 10; ++ } ++ dev = new_decode_dev(dev); ++ ++ if (get_device_perms_ve(S_IFBLK, dev, FMODE_QUOTACTL)) ++ goto out; ++ ++ inode = iget5_locked(dir->i_sb, vzdq_aquot_getino(dev), ++ vzdq_aquotd_looktest, vzdq_aquotd_lookset, ++ (void *)(unsigned long)dev); ++ if (inode == NULL) ++ goto out; ++ unlock_new_inode(inode); ++ ++ d_add(dentry, inode); ++ (void)set_exec_env(old_ve); ++ return NULL; ++ ++out: ++ (void)set_exec_env(old_ve); ++ return ERR_PTR(-ENOENT); ++} ++ ++static struct file_operations vzdq_aquotd_file_operations = { ++ .read = &generic_read_dir, ++ .readdir = &vzdq_aquotd_readdir, ++}; ++ ++static struct inode_operations vzdq_aquotd_inode_operations = { ++ .lookup = &vzdq_aquotd_lookup, ++}; ++ ++ ++/* ---------------------------------------------------------------------- ++ * ++ * Initialization and deinitialization ++ * ++ * --------------------------------------------------------------------- */ ++static ctl_table fs_table[] = { ++ { ++ .ctl_name = FS_DQSTATS, ++ .procname = "quota", ++ .mode = 0555, ++ }, ++ {}, ++}; ++ ++static ctl_table sys_table[] = { ++ { ++ .ctl_name = CTL_FS, ++ .procname = "fs", ++ .mode = 0555, ++ .child = fs_table, ++ }, ++ {}, ++}; ++ ++/* ++ * FIXME: creation of proc entries here is unsafe with respect to module ++ * unloading. ++ */ ++void vzaquota_init(void) ++{ ++ struct proc_dir_entry *de; ++ ++ de = create_proc_glob_entry("vz/vzaquota", ++ S_IFDIR | S_IRUSR | S_IXUSR, NULL); ++ if (de != NULL) { ++ de->proc_iops = &vzdq_aquotd_inode_operations; ++ de->proc_fops = &vzdq_aquotd_file_operations; ++ } else ++ printk("VZDQ: vz/vzaquota creation failed\n"); ++ register_glob_sysctl_table(sys_table); ++} ++ ++void vzaquota_fini(void) ++{ ++ remove_proc_entry("vz/vzaquota", NULL); ++} +Index: kernel/fs/vzdq_mgmt.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/fs/vzdq_mgmt.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,769 @@ ++/* ++ * Copyright (C) 2001, 2002, 2004, 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* ---------------------------------------------------------------------- ++ * Switching quota on. ++ * --------------------------------------------------------------------- */ ++ ++/* ++ * check limits copied from user ++ */ ++int vzquota_check_sane_limits(struct dq_stat *qstat) ++{ ++ int err; ++ ++ err = -EINVAL; ++ ++ /* softlimit must be less then hardlimit */ ++ if (qstat->bsoftlimit > qstat->bhardlimit) ++ goto out; ++ ++ if (qstat->isoftlimit > qstat->ihardlimit) ++ goto out; ++ ++ err = 0; ++out: ++ return err; ++} ++ ++/* ++ * check usage values copied from user ++ */ ++int vzquota_check_sane_values(struct dq_stat *qstat) ++{ ++ int err; ++ ++ err = -EINVAL; ++ ++ /* expiration time must not be set if softlimit was not exceeded */ ++ if (qstat->bcurrent < qstat->bsoftlimit && qstat->btime != 0) ++ goto out; ++ ++ if (qstat->icurrent < qstat->isoftlimit && qstat->itime != 0) ++ goto out; ++ ++ err = vzquota_check_sane_limits(qstat); ++out: ++ return err; ++} ++ ++/* ++ * create new quota master block ++ * this function should: ++ * - copy limits and usage parameters from user buffer; ++ * - allock, initialize quota block and insert it to hash; ++ */ ++static int vzquota_create(unsigned int quota_id, ++ struct vz_quota_stat __user *u_qstat, int compat) ++{ ++ int err; ++ struct vz_quota_stat qstat; ++ struct vz_quota_master *qmblk; ++ ++ down(&vz_quota_sem); ++ ++ err = -EFAULT; ++ if (!compat) { ++ if (copy_from_user(&qstat, u_qstat, sizeof(qstat))) ++ goto out; ++ } else { ++#ifdef CONFIG_COMPAT ++ struct compat_vz_quota_stat cqstat; ++ if (copy_from_user(&cqstat, u_qstat, sizeof(cqstat))) ++ goto out; ++ compat_dqstat2dqstat(&cqstat.dq_stat, &qstat.dq_stat); ++ compat_dqinfo2dqinfo(&cqstat.dq_info, &qstat.dq_info); ++#endif ++ } ++ ++ err = -EINVAL; ++ if (quota_id == 0) ++ goto out; ++ ++ if (vzquota_check_sane_values(&qstat.dq_stat)) ++ goto out; ++ err = 0; ++ qmblk = vzquota_alloc_master(quota_id, &qstat); ++ ++ if (IS_ERR(qmblk)) /* ENOMEM or EEXIST */ ++ err = PTR_ERR(qmblk); ++out: ++ up(&vz_quota_sem); ++ ++ return err; ++} ++ ++/** ++ * vzquota_on - turn quota on ++ * ++ * This function should: ++ * - find and get refcnt of directory entry for quota root and corresponding ++ * mountpoint; ++ * - find corresponding quota block and mark it with given path; ++ * - check quota tree; ++ * - initialize quota for the tree root. ++ */ ++static int vzquota_on(unsigned int quota_id, const char __user *quota_root, ++ char __user *buf) ++{ ++ int err; ++ struct nameidata nd; ++ struct vz_quota_master *qmblk; ++ struct super_block *dqsb; ++ ++ dqsb = NULL; ++ down(&vz_quota_sem); ++ ++ err = -ENOENT; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ err = -EBUSY; ++ if (qmblk->dq_state != VZDQ_STARTING) ++ goto out; ++ ++ err = user_path_walk(quota_root, &nd); ++ if (err) ++ goto out; ++ /* init path must be a directory */ ++ err = -ENOTDIR; ++ if (!S_ISDIR(nd.dentry->d_inode->i_mode)) ++ goto out_path; ++ ++ qmblk->dq_root_dentry = nd.dentry; ++ qmblk->dq_root_mnt = nd.mnt; ++ qmblk->dq_sb = nd.dentry->d_inode->i_sb; ++ err = vzquota_get_super(qmblk->dq_sb); ++ if (err) ++ goto out_super; ++ ++ /* ++ * Serialization with quota initialization and operations is performed ++ * through generation check: generation is memorized before qmblk is ++ * found and compared under inode_qmblk_lock with assignment. ++ * ++ * Note that the dentry tree is shrunk only for high-level logical ++ * serialization, purely as a courtesy to the user: to have consistent ++ * quota statistics, files should be closed etc. on quota on. ++ */ ++ err = vzquota_on_qmblk(qmblk->dq_sb, qmblk->dq_root_dentry->d_inode, ++ qmblk, buf); ++ if (err) ++ goto out_init; ++ qmblk->dq_state = VZDQ_WORKING; ++ ++ up(&vz_quota_sem); ++ return 0; ++ ++out_init: ++ dqsb = qmblk->dq_sb; ++out_super: ++ /* clear for qmblk_put/quota_free_master */ ++ qmblk->dq_sb = NULL; ++ qmblk->dq_root_dentry = NULL; ++ qmblk->dq_root_mnt = NULL; ++out_path: ++ path_release(&nd); ++out: ++ if (dqsb) ++ vzquota_put_super(dqsb); ++ up(&vz_quota_sem); ++ return err; ++} ++ ++ ++/* ---------------------------------------------------------------------- ++ * Switching quota off. ++ * --------------------------------------------------------------------- */ ++ ++/* ++ * destroy quota block by ID ++ */ ++static int vzquota_destroy(unsigned int quota_id) ++{ ++ int err; ++ struct vz_quota_master *qmblk; ++ struct dentry *dentry; ++ struct vfsmount *mnt; ++ ++ down(&vz_quota_sem); ++ ++ err = -ENOENT; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ err = -EBUSY; ++ if (qmblk->dq_state == VZDQ_WORKING) ++ goto out; /* quota_off first */ ++ ++ list_del_init(&qmblk->dq_hash); ++ dentry = qmblk->dq_root_dentry; ++ qmblk->dq_root_dentry = NULL; ++ mnt = qmblk->dq_root_mnt; ++ qmblk->dq_root_mnt = NULL; ++ ++ if (qmblk->dq_sb) ++ vzquota_put_super(qmblk->dq_sb); ++ up(&vz_quota_sem); ++ ++ qmblk_put(qmblk); ++ dput(dentry); ++ mntput(mnt); ++ return 0; ++ ++out: ++ up(&vz_quota_sem); ++ return err; ++} ++ ++/** ++ * vzquota_off - turn quota off ++ */ ++ ++static int __vzquota_sync_list(struct list_head *lh, ++ struct vz_quota_master *qmblk, ++ enum writeback_sync_modes sync_mode) ++{ ++ struct writeback_control wbc; ++ LIST_HEAD(list); ++ struct vz_quota_ilink *qlnk; ++ struct inode *inode; ++ int err, ret; ++ ++ memset(&wbc, 0, sizeof(wbc)); ++ wbc.sync_mode = sync_mode; ++ ++ err = ret = 0; ++ while (!list_empty(lh)) { ++ if (need_resched()) { ++ inode_qmblk_unlock(qmblk->dq_sb); ++ schedule(); ++ inode_qmblk_lock(qmblk->dq_sb); ++ continue; ++ } ++ ++ qlnk = list_first_entry(lh, struct vz_quota_ilink, list); ++ list_move(&qlnk->list, &list); ++ ++ inode = igrab(QLNK_INODE(qlnk)); ++ if (!inode) ++ continue; ++ ++ inode_qmblk_unlock(qmblk->dq_sb); ++ ++ wbc.nr_to_write = LONG_MAX; ++ ret = sync_inode(inode, &wbc); ++ if (ret) ++ err = ret; ++ iput(inode); ++ ++ inode_qmblk_lock(qmblk->dq_sb); ++ } ++ ++ list_splice(&list, lh); ++ return err; ++} ++ ++static int vzquota_sync_list(struct list_head *lh, ++ struct vz_quota_master *qmblk) ++{ ++ (void)__vzquota_sync_list(lh, qmblk, WB_SYNC_NONE); ++ return __vzquota_sync_list(lh, qmblk, WB_SYNC_ALL); ++} ++ ++static int vzquota_sync_inodes(struct vz_quota_master *qmblk) ++{ ++ int err; ++ LIST_HEAD(qlnk_list); ++ ++ list_splice_init(&qmblk->dq_ilink_list, &qlnk_list); ++ err = vzquota_sync_list(&qlnk_list, qmblk); ++ if (!err && !list_empty(&qmblk->dq_ilink_list)) ++ err = -EBUSY; ++ list_splice(&qlnk_list, &qmblk->dq_ilink_list); ++ ++ return err; ++} ++ ++static int vzquota_off(unsigned int quota_id, char __user *buf, int force) ++{ ++ int err, ret; ++ struct vz_quota_master *qmblk; ++ ++ down(&vz_quota_sem); ++ ++ err = -ENOENT; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ err = -EALREADY; ++ if (qmblk->dq_state != VZDQ_WORKING) ++ goto out; ++ ++ inode_qmblk_lock(qmblk->dq_sb); /* protects dq_ilink_list also */ ++ ret = vzquota_sync_inodes(qmblk); ++ inode_qmblk_unlock(qmblk->dq_sb); ++ ++ err = vzquota_off_qmblk(qmblk->dq_sb, qmblk, buf, force); ++ if (err) ++ goto out; ++ ++ err = ret; ++ /* vzquota_destroy will free resources */ ++ qmblk->dq_state = VZDQ_STOPING; ++out: ++ up(&vz_quota_sem); ++ ++ return err; ++} ++ ++ ++/* ---------------------------------------------------------------------- ++ * Other VZQUOTA ioctl's. ++ * --------------------------------------------------------------------- */ ++ ++/* ++ * this function should: ++ * - set new limits/buffer under quota master block lock ++ * - if new softlimit less then usage, then set expiration time ++ * - no need to alloc ugid hash table - we'll do that on demand ++ */ ++int vzquota_update_limit(struct dq_stat *_qstat, ++ struct dq_stat *qstat) ++{ ++ int err; ++ ++ err = -EINVAL; ++ if (vzquota_check_sane_limits(qstat)) ++ goto out; ++ ++ err = 0; ++ ++ /* limits */ ++ _qstat->bsoftlimit = qstat->bsoftlimit; ++ _qstat->bhardlimit = qstat->bhardlimit; ++ /* ++ * If the soft limit is exceeded, administrator can override the moment ++ * when the grace period for limit exceeding ends. ++ * Specifying the moment may be useful if the soft limit is set to be ++ * lower than the current usage. In the latter case, if the grace ++ * period end isn't specified, the grace period will start from the ++ * moment of the first write operation. ++ * There is a race with the user level. Soft limit may be already ++ * exceeded before the limit change, and grace period end calculated by ++ * the kernel will be overriden. User level may check if the limit is ++ * already exceeded, but check and set calls are not atomic. ++ * This race isn't dangerous. Under normal cicrumstances, the ++ * difference between the grace period end calculated by the kernel and ++ * the user level should be not greater than as the difference between ++ * the moments of check and set calls, i.e. not bigger than the quota ++ * timer resolution - 1 sec. ++ */ ++ if (qstat->btime != (time_t)0 && ++ _qstat->bcurrent >= _qstat->bsoftlimit) ++ _qstat->btime = qstat->btime; ++ ++ _qstat->isoftlimit = qstat->isoftlimit; ++ _qstat->ihardlimit = qstat->ihardlimit; ++ if (qstat->itime != (time_t)0 && ++ _qstat->icurrent >= _qstat->isoftlimit) ++ _qstat->itime = qstat->itime; ++ ++out: ++ return err; ++} ++ ++/* ++ * set new quota limits. ++ * this function should: ++ * copy new limits from user level ++ * - find quota block ++ * - set new limits and flags. ++ */ ++static int vzquota_setlimit(unsigned int quota_id, ++ struct vz_quota_stat __user *u_qstat, int compat) ++{ ++ int err; ++ struct vz_quota_stat qstat; ++ struct vz_quota_master *qmblk; ++ ++ down(&vz_quota_sem); /* for hash list protection */ ++ ++ err = -ENOENT; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ err = -EFAULT; ++ if (!compat) { ++ if (copy_from_user(&qstat, u_qstat, sizeof(qstat))) ++ goto out; ++ } else { ++#ifdef CONFIG_COMPAT ++ struct compat_vz_quota_stat cqstat; ++ if (copy_from_user(&cqstat, u_qstat, sizeof(cqstat))) ++ goto out; ++ compat_dqstat2dqstat(&cqstat.dq_stat, &qstat.dq_stat); ++ compat_dqinfo2dqinfo(&cqstat.dq_info, &qstat.dq_info); ++#endif ++ } ++ ++ qmblk_data_write_lock(qmblk); ++ err = vzquota_update_limit(&qmblk->dq_stat, &qstat.dq_stat); ++ if (err == 0) ++ qmblk->dq_info = qstat.dq_info; ++ qmblk_data_write_unlock(qmblk); ++ ++out: ++ up(&vz_quota_sem); ++ return err; ++} ++ ++/* ++ * get quota limits. ++ * very simple - just return stat buffer to user ++ */ ++static int vzquota_getstat(unsigned int quota_id, ++ struct vz_quota_stat __user *u_qstat, int compat) ++{ ++ int err; ++ struct vz_quota_stat qstat; ++ struct vz_quota_master *qmblk; ++ ++ down(&vz_quota_sem); ++ ++ err = -ENOENT; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ qmblk_data_read_lock(qmblk); ++ /* copy whole buffer under lock */ ++ memcpy(&qstat.dq_stat, &qmblk->dq_stat, sizeof(qstat.dq_stat)); ++ memcpy(&qstat.dq_info, &qmblk->dq_info, sizeof(qstat.dq_info)); ++ qmblk_data_read_unlock(qmblk); ++ ++ if (!compat) ++ err = copy_to_user(u_qstat, &qstat, sizeof(qstat)); ++ else { ++#ifdef CONFIG_COMPAT ++ struct compat_vz_quota_stat cqstat; ++ dqstat2compat_dqstat(&qstat.dq_stat, &cqstat.dq_stat); ++ dqinfo2compat_dqinfo(&qstat.dq_info, &cqstat.dq_info); ++ err = copy_to_user(u_qstat, &cqstat, sizeof(cqstat)); ++#endif ++ } ++ if (err) ++ err = -EFAULT; ++ ++out: ++ up(&vz_quota_sem); ++ return err; ++} ++ ++/* ++ * This is a system call to turn per-VE disk quota on. ++ * Note this call is allowed to run ONLY from VE0 ++ */ ++long do_vzquotactl(int cmd, unsigned int quota_id, ++ struct vz_quota_stat __user *qstat, const char __user *ve_root, ++ int compat) ++{ ++ int ret; ++ int force = 0; ++ ++ ret = -EPERM; ++ /* access allowed only from root of VE0 */ ++ if (!capable(CAP_SYS_RESOURCE) || ++ !capable(CAP_SYS_ADMIN)) ++ goto out; ++ ++ switch (cmd) { ++ case VZ_DQ_CREATE: ++ ret = vzquota_create(quota_id, qstat, compat); ++ break; ++ case VZ_DQ_DESTROY: ++ ret = vzquota_destroy(quota_id); ++ break; ++ case VZ_DQ_ON: ++ /* ++ * qstat is just a pointer to userspace buffer to ++ * store busy files path in case of vzquota_on fail ++ */ ++ ret = vzquota_on(quota_id, ve_root, (char *)qstat); ++ break; ++ case VZ_DQ_OFF_FORCED: ++ force = 1; ++ case VZ_DQ_OFF: ++ /* ++ * ve_root is just a pointer to userspace buffer to ++ * store busy files path in case of vzquota_off fail ++ */ ++ ret = vzquota_off(quota_id, (char *)ve_root, force); ++ break; ++ case VZ_DQ_SETLIMIT: ++ ret = vzquota_setlimit(quota_id, qstat, compat); ++ break; ++ case VZ_DQ_GETSTAT: ++ ret = vzquota_getstat(quota_id, qstat, compat); ++ break; ++ ++ default: ++ ret = -EINVAL; ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ ++ ++/* ---------------------------------------------------------------------- ++ * Proc filesystem routines ++ * ---------------------------------------------------------------------*/ ++ ++#if defined(CONFIG_PROC_FS) ++ ++#define QUOTA_UINT_LEN 15 ++#define QUOTA_TIME_LEN_FMT_UINT "%11u" ++#define QUOTA_NUM_LEN_FMT_UINT "%15u" ++#define QUOTA_NUM_LEN_FMT_ULL "%15Lu" ++#define QUOTA_TIME_LEN_FMT_STR "%11s" ++#define QUOTA_NUM_LEN_FMT_STR "%15s" ++#define QUOTA_PROC_MAX_LINE_LEN 2048 ++ ++/* ++ * prints /proc/ve_dq header line ++ */ ++static int print_proc_header(char * buffer) ++{ ++ return sprintf(buffer, ++ "%-11s" ++ QUOTA_NUM_LEN_FMT_STR ++ QUOTA_NUM_LEN_FMT_STR ++ QUOTA_NUM_LEN_FMT_STR ++ QUOTA_TIME_LEN_FMT_STR ++ QUOTA_TIME_LEN_FMT_STR ++ "\n", ++ "qid: path", ++ "usage", "softlimit", "hardlimit", "time", "expire"); ++} ++ ++/* ++ * prints proc master record id, dentry path ++ */ ++static int print_proc_master_id(char * buffer, char * path_buf, ++ struct vz_quota_master * qp) ++{ ++ char *path; ++ int over; ++ ++ path = NULL; ++ switch (qp->dq_state) { ++ case VZDQ_WORKING: ++ if (!path_buf) { ++ path = ""; ++ break; ++ } ++ path = d_path(qp->dq_root_dentry, ++ qp->dq_root_mnt, path_buf, PAGE_SIZE); ++ if (IS_ERR(path)) { ++ path = ""; ++ break; ++ } ++ /* do not print large path, truncate it */ ++ over = strlen(path) - ++ (QUOTA_PROC_MAX_LINE_LEN - 3 - 3 - ++ QUOTA_UINT_LEN); ++ if (over > 0) { ++ path += over - 3; ++ path[0] = path[1] = path[3] = '.'; ++ } ++ break; ++ case VZDQ_STARTING: ++ path = "-- started --"; ++ break; ++ case VZDQ_STOPING: ++ path = "-- stopped --"; ++ break; ++ } ++ ++ return sprintf(buffer, "%u: %s\n", qp->dq_id, path); ++} ++ ++/* ++ * prints struct vz_quota_stat data ++ */ ++static int print_proc_stat(char * buffer, struct dq_stat *qs, ++ struct dq_info *qi) ++{ ++ return sprintf(buffer, ++ "%11s" ++ QUOTA_NUM_LEN_FMT_ULL ++ QUOTA_NUM_LEN_FMT_ULL ++ QUOTA_NUM_LEN_FMT_ULL ++ QUOTA_TIME_LEN_FMT_UINT ++ QUOTA_TIME_LEN_FMT_UINT ++ "\n" ++ "%11s" ++ QUOTA_NUM_LEN_FMT_UINT ++ QUOTA_NUM_LEN_FMT_UINT ++ QUOTA_NUM_LEN_FMT_UINT ++ QUOTA_TIME_LEN_FMT_UINT ++ QUOTA_TIME_LEN_FMT_UINT ++ "\n", ++ "1k-blocks", ++ (unsigned long long)qs->bcurrent >> 10, ++ (unsigned long long)qs->bsoftlimit >> 10, ++ (unsigned long long)qs->bhardlimit >> 10, ++ (unsigned int)qs->btime, ++ (unsigned int)qi->bexpire, ++ "inodes", ++ qs->icurrent, ++ qs->isoftlimit, ++ qs->ihardlimit, ++ (unsigned int)qs->itime, ++ (unsigned int)qi->iexpire); ++} ++ ++ ++/* ++ * for /proc filesystem output ++ */ ++static int vzquota_read_proc(char *page, char **start, off_t off, int count, ++ int *eof, void *data) ++{ ++ int len, i; ++ off_t printed = 0; ++ char *p = page; ++ struct vz_quota_master *qp; ++ struct vz_quota_ilink *ql2; ++ struct list_head *listp; ++ char *path_buf; ++ ++ path_buf = (char*)__get_free_page(GFP_KERNEL); ++ if (path_buf == NULL) ++ return -ENOMEM; ++ ++ len = print_proc_header(p); ++ printed += len; ++ if (off < printed) /* keep header in output */ { ++ *start = p + off; ++ p += len; ++ } ++ ++ down(&vz_quota_sem); ++ ++ /* traverse master hash table for all records */ ++ for (i = 0; i < vzquota_hash_size; i++) { ++ list_for_each(listp, &vzquota_hash_table[i]) { ++ qp = list_entry(listp, ++ struct vz_quota_master, dq_hash); ++ ++ /* Skip other VE's information if not root of VE0 */ ++ if ((!capable(CAP_SYS_ADMIN) || ++ !capable(CAP_SYS_RESOURCE))) { ++ ql2 = INODE_QLNK(current->fs->root->d_inode); ++ if (ql2 == NULL || qp != ql2->qmblk) ++ continue; ++ } ++ /* ++ * Now print the next record ++ */ ++ len = 0; ++ /* we print quotaid and path only in VE0 */ ++ if (capable(CAP_SYS_ADMIN)) ++ len += print_proc_master_id(p+len,path_buf, qp); ++ len += print_proc_stat(p+len, &qp->dq_stat, ++ &qp->dq_info); ++ printed += len; ++ /* skip unnecessary lines */ ++ if (printed <= off) ++ continue; ++ p += len; ++ /* provide start offset */ ++ if (*start == NULL) ++ *start = p + (off - printed); ++ /* have we printed all requested size? */ ++ if (PAGE_SIZE - (p - page) < QUOTA_PROC_MAX_LINE_LEN || ++ (p - *start) >= count) ++ goto out; ++ } ++ } ++ ++ *eof = 1; /* checked all hash */ ++out: ++ up(&vz_quota_sem); ++ ++ len = 0; ++ if (*start != NULL) { ++ len = (p - *start); ++ if (len > count) ++ len = count; ++ } ++ ++ if (path_buf) ++ free_page((unsigned long) path_buf); ++ ++ return len; ++} ++ ++/* ++ * Register procfs read callback ++ */ ++int vzquota_proc_init(void) ++{ ++ struct proc_dir_entry *de; ++ ++ de = create_proc_entry_mod("vz/vzquota", S_IFREG|S_IRUSR, NULL, ++ THIS_MODULE); ++ if (de == NULL) { ++ /* create "vz" subdirectory, if not exist */ ++ de = create_proc_entry("vz", S_IFDIR|S_IRUGO|S_IXUGO, NULL); ++ if (de == NULL) ++ goto out_err; ++ de = create_proc_entry_mod("vzquota", S_IFREG|S_IRUSR, de, ++ THIS_MODULE); ++ if (de == NULL) ++ goto out_err; ++ } ++ de->read_proc = vzquota_read_proc; ++ de->data = NULL; ++ return 0; ++out_err: ++ return -EBUSY; ++} ++ ++void vzquota_proc_release(void) ++{ ++ /* Unregister procfs read callback */ ++ remove_proc_entry("vz/vzquota", NULL); ++} ++ ++#endif +Index: kernel/fs/vzdq_ops.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/fs/vzdq_ops.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,633 @@ ++/* ++ * Copyright (C) 2001, 2002, 2004, 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* ---------------------------------------------------------------------- ++ * Quota superblock operations - helper functions. ++ * --------------------------------------------------------------------- */ ++ ++static inline void vzquota_incr_inodes(struct dq_stat *dqstat, ++ unsigned long number) ++{ ++ dqstat->icurrent += number; ++} ++ ++static inline void vzquota_incr_space(struct dq_stat *dqstat, ++ __u64 number) ++{ ++ dqstat->bcurrent += number; ++} ++ ++static inline void vzquota_decr_inodes(struct dq_stat *dqstat, ++ unsigned long number) ++{ ++ if (dqstat->icurrent > number) ++ dqstat->icurrent -= number; ++ else ++ dqstat->icurrent = 0; ++ if (dqstat->icurrent < dqstat->isoftlimit) ++ dqstat->itime = (time_t) 0; ++} ++ ++static inline void vzquota_decr_space(struct dq_stat *dqstat, ++ __u64 number) ++{ ++ if (dqstat->bcurrent > number) ++ dqstat->bcurrent -= number; ++ else ++ dqstat->bcurrent = 0; ++ if (dqstat->bcurrent < dqstat->bsoftlimit) ++ dqstat->btime = (time_t) 0; ++} ++ ++/* ++ * better printk() message or use /proc/vzquotamsg interface ++ * similar to /proc/kmsg ++ */ ++static inline void vzquota_warn(struct dq_info *dq_info, int dq_id, int flag, ++ const char *fmt) ++{ ++ if (dq_info->flags & flag) /* warning already printed for this ++ masterblock */ ++ return; ++ printk(fmt, dq_id); ++ dq_info->flags |= flag; ++} ++ ++/* ++ * ignore_hardlimit - ++ * ++ * Intended to allow superuser of VE0 to overwrite hardlimits. ++ * ++ * ignore_hardlimit() has a very bad feature: ++ * ++ * writepage() operation for writable mapping of a file with holes ++ * may trigger get_block() with wrong current and as a consequence, ++ * opens a possibility to overcommit hardlimits ++ */ ++/* for the reason above, it is disabled now */ ++static inline int ignore_hardlimit(struct dq_info *dqstat) ++{ ++#if 0 ++ return ve_is_super(get_exec_env()) && ++ capable(CAP_SYS_RESOURCE) && ++ (dqstat->options & VZ_QUOTA_OPT_RSQUASH); ++#else ++ return 0; ++#endif ++} ++ ++static int vzquota_check_inodes(struct dq_info *dq_info, ++ struct dq_stat *dqstat, ++ unsigned long number, int dq_id) ++{ ++ if (number == 0) ++ return QUOTA_OK; ++ ++ if (dqstat->icurrent + number > dqstat->ihardlimit && ++ !ignore_hardlimit(dq_info)) { ++ vzquota_warn(dq_info, dq_id, VZ_QUOTA_INODES, ++ "VZ QUOTA: file hardlimit reached for id=%d\n"); ++ return NO_QUOTA; ++ } ++ ++ if (dqstat->icurrent + number > dqstat->isoftlimit) { ++ if (dqstat->itime == (time_t)0) { ++ vzquota_warn(dq_info, dq_id, 0, ++ "VZ QUOTA: file softlimit exceeded " ++ "for id=%d\n"); ++ dqstat->itime = CURRENT_TIME_SECONDS + ++ dq_info->iexpire; ++ } else if (CURRENT_TIME_SECONDS >= dqstat->itime && ++ !ignore_hardlimit(dq_info)) { ++ vzquota_warn(dq_info, dq_id, VZ_QUOTA_INODES, ++ "VZ QUOTA: file softlimit expired " ++ "for id=%d\n"); ++ return NO_QUOTA; ++ } ++ } ++ ++ return QUOTA_OK; ++} ++ ++static int vzquota_check_space(struct dq_info *dq_info, ++ struct dq_stat *dqstat, ++ __u64 number, int dq_id, char prealloc) ++{ ++ if (number == 0) ++ return QUOTA_OK; ++ ++ if (prealloc == DQUOT_CMD_FORCE) ++ return QUOTA_OK; ++ ++ if (dqstat->bcurrent + number > dqstat->bhardlimit && ++ !ignore_hardlimit(dq_info)) { ++ if (!prealloc) ++ vzquota_warn(dq_info, dq_id, VZ_QUOTA_SPACE, ++ "VZ QUOTA: disk hardlimit reached " ++ "for id=%d\n"); ++ return NO_QUOTA; ++ } ++ ++ if (dqstat->bcurrent + number > dqstat->bsoftlimit) { ++ if (dqstat->btime == (time_t)0) { ++ if (!prealloc) { ++ vzquota_warn(dq_info, dq_id, 0, ++ "VZ QUOTA: disk softlimit exceeded " ++ "for id=%d\n"); ++ dqstat->btime = CURRENT_TIME_SECONDS ++ + dq_info->bexpire; ++ } else { ++ /* ++ * Original Linux quota doesn't allow ++ * preallocation to exceed softlimit so ++ * exceeding will be always printed ++ */ ++ return NO_QUOTA; ++ } ++ } else if (CURRENT_TIME_SECONDS >= dqstat->btime && ++ !ignore_hardlimit(dq_info)) { ++ if (!prealloc) ++ vzquota_warn(dq_info, dq_id, VZ_QUOTA_SPACE, ++ "VZ QUOTA: disk quota " ++ "softlimit expired " ++ "for id=%d\n"); ++ return NO_QUOTA; ++ } ++ } ++ ++ return QUOTA_OK; ++} ++ ++#ifdef CONFIG_VZ_QUOTA_UGID ++static int vzquota_check_ugid_inodes(struct vz_quota_master *qmblk, ++ struct vz_quota_ugid *qugid[], ++ int type, unsigned long number) ++{ ++ struct dq_info *dqinfo; ++ struct dq_stat *dqstat; ++ ++ if (qugid[type] == NULL) ++ return QUOTA_OK; ++ if (qugid[type] == VZ_QUOTA_UGBAD) ++ return NO_QUOTA; ++ ++ if (type == USRQUOTA && !(qmblk->dq_flags & VZDQ_USRQUOTA)) ++ return QUOTA_OK; ++ if (type == GRPQUOTA && !(qmblk->dq_flags & VZDQ_GRPQUOTA)) ++ return QUOTA_OK; ++ if (number == 0) ++ return QUOTA_OK; ++ ++ dqinfo = &qmblk->dq_ugid_info[type]; ++ dqstat = &qugid[type]->qugid_stat; ++ ++ if (dqstat->ihardlimit != 0 && ++ dqstat->icurrent + number > dqstat->ihardlimit) ++ return NO_QUOTA; ++ ++ if (dqstat->isoftlimit != 0 && ++ dqstat->icurrent + number > dqstat->isoftlimit) { ++ if (dqstat->itime == (time_t)0) ++ dqstat->itime = CURRENT_TIME_SECONDS + ++ dqinfo->iexpire; ++ else if (CURRENT_TIME_SECONDS >= dqstat->itime) ++ return NO_QUOTA; ++ } ++ ++ return QUOTA_OK; ++} ++ ++static int vzquota_check_ugid_space(struct vz_quota_master *qmblk, ++ struct vz_quota_ugid *qugid[], ++ int type, __u64 number, char prealloc) ++{ ++ struct dq_info *dqinfo; ++ struct dq_stat *dqstat; ++ ++ if (prealloc == DQUOT_CMD_FORCE) ++ return QUOTA_OK; ++ ++ if (qugid[type] == NULL) ++ return QUOTA_OK; ++ if (qugid[type] == VZ_QUOTA_UGBAD) ++ return NO_QUOTA; ++ ++ if (type == USRQUOTA && !(qmblk->dq_flags & VZDQ_USRQUOTA)) ++ return QUOTA_OK; ++ if (type == GRPQUOTA && !(qmblk->dq_flags & VZDQ_GRPQUOTA)) ++ return QUOTA_OK; ++ if (number == 0) ++ return QUOTA_OK; ++ ++ dqinfo = &qmblk->dq_ugid_info[type]; ++ dqstat = &qugid[type]->qugid_stat; ++ ++ if (dqstat->bhardlimit != 0 && ++ dqstat->bcurrent + number > dqstat->bhardlimit) ++ return NO_QUOTA; ++ ++ if (dqstat->bsoftlimit != 0 && ++ dqstat->bcurrent + number > dqstat->bsoftlimit) { ++ if (dqstat->btime == (time_t)0) { ++ if (!prealloc) ++ dqstat->btime = CURRENT_TIME_SECONDS ++ + dqinfo->bexpire; ++ else ++ /* ++ * Original Linux quota doesn't allow ++ * preallocation to exceed softlimit so ++ * exceeding will be always printed ++ */ ++ return NO_QUOTA; ++ } else if (CURRENT_TIME_SECONDS >= dqstat->btime) ++ return NO_QUOTA; ++ } ++ ++ return QUOTA_OK; ++} ++#endif ++ ++/* ---------------------------------------------------------------------- ++ * Quota superblock operations ++ * --------------------------------------------------------------------- */ ++ ++/* ++ * S_NOQUOTA note. ++ * In the current kernel (2.6.8.1), S_NOQUOTA flag is set only for ++ * - quota file (absent in our case) ++ * - after explicit DQUOT_DROP (earlier than clear_inode) in functions like ++ * filesystem-specific new_inode, before the inode gets outside links. ++ * For the latter case, the only quota operation where care about S_NOQUOTA ++ * might be required is vzquota_drop, but there S_NOQUOTA has already been ++ * checked in DQUOT_DROP(). ++ * So, S_NOQUOTA may be ignored for now in the VZDQ code. ++ * ++ * The above note is not entirely correct. ++ * Both for ext2 and ext3 filesystems, DQUOT_FREE_INODE is called from ++ * delete_inode if new_inode fails (for example, because of inode quota ++ * limits), so S_NOQUOTA check is needed in free_inode. ++ * This seems to be the dark corner of the current quota API. ++ */ ++ ++/* ++ * Initialize quota operations for the specified inode. ++ */ ++static int vzquota_initialize(struct inode *inode, int type) ++{ ++ vzquota_inode_init_call(inode); ++ return 0; /* ignored by caller */ ++} ++ ++/* ++ * Release quota for the specified inode. ++ */ ++static int vzquota_drop(struct inode *inode) ++{ ++ vzquota_inode_drop_call(inode); ++ return 0; /* ignored by caller */ ++} ++ ++/* ++ * Allocate block callback. ++ * ++ * If (prealloc) disk quota exceeding warning is not printed. ++ * See Linux quota to know why. ++ * ++ * Return: ++ * QUOTA_OK == 0 on SUCCESS ++ * NO_QUOTA == 1 if allocation should fail ++ */ ++static int vzquota_alloc_space(struct inode *inode, ++ qsize_t number, int prealloc) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_datast data; ++ int ret = QUOTA_OK; ++ ++ qmblk = vzquota_inode_data(inode, &data); ++ if (qmblk == VZ_QUOTA_BAD) ++ return NO_QUOTA; ++ if (qmblk != NULL) { ++#ifdef CONFIG_VZ_QUOTA_UGID ++ int cnt; ++ struct vz_quota_ugid * qugid[MAXQUOTAS]; ++#endif ++ ++ /* checking first */ ++ ret = vzquota_check_space(&qmblk->dq_info, &qmblk->dq_stat, ++ number, qmblk->dq_id, prealloc); ++ if (ret == NO_QUOTA) ++ goto no_quota; ++#ifdef CONFIG_VZ_QUOTA_UGID ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ qugid[cnt] = INODE_QLNK(inode)->qugid[cnt]; ++ ret = vzquota_check_ugid_space(qmblk, qugid, ++ cnt, number, prealloc); ++ if (ret == NO_QUOTA) ++ goto no_quota; ++ } ++ /* check ok, may increment */ ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ if (qugid[cnt] == NULL) ++ continue; ++ vzquota_incr_space(&qugid[cnt]->qugid_stat, number); ++ } ++#endif ++ vzquota_incr_space(&qmblk->dq_stat, number); ++ vzquota_data_unlock(inode, &data); ++ } ++ ++ inode_add_bytes(inode, number); ++ might_sleep(); ++ return QUOTA_OK; ++ ++no_quota: ++ vzquota_data_unlock(inode, &data); ++ return NO_QUOTA; ++} ++ ++/* ++ * Allocate inodes callback. ++ * ++ * Return: ++ * QUOTA_OK == 0 on SUCCESS ++ * NO_QUOTA == 1 if allocation should fail ++ */ ++static int vzquota_alloc_inode(const struct inode *inode, unsigned long number) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_datast data; ++ int ret = QUOTA_OK; ++ ++ qmblk = vzquota_inode_data((struct inode *)inode, &data); ++ if (qmblk == VZ_QUOTA_BAD) ++ return NO_QUOTA; ++ if (qmblk != NULL) { ++#ifdef CONFIG_VZ_QUOTA_UGID ++ int cnt; ++ struct vz_quota_ugid *qugid[MAXQUOTAS]; ++#endif ++ ++ /* checking first */ ++ ret = vzquota_check_inodes(&qmblk->dq_info, &qmblk->dq_stat, ++ number, qmblk->dq_id); ++ if (ret == NO_QUOTA) ++ goto no_quota; ++#ifdef CONFIG_VZ_QUOTA_UGID ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ qugid[cnt] = INODE_QLNK(inode)->qugid[cnt]; ++ ret = vzquota_check_ugid_inodes(qmblk, qugid, ++ cnt, number); ++ if (ret == NO_QUOTA) ++ goto no_quota; ++ } ++ /* check ok, may increment */ ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ if (qugid[cnt] == NULL) ++ continue; ++ vzquota_incr_inodes(&qugid[cnt]->qugid_stat, number); ++ } ++#endif ++ vzquota_incr_inodes(&qmblk->dq_stat, number); ++ vzquota_data_unlock((struct inode *)inode, &data); ++ } ++ ++ might_sleep(); ++ return QUOTA_OK; ++ ++no_quota: ++ vzquota_data_unlock((struct inode *)inode, &data); ++ return NO_QUOTA; ++} ++ ++/* ++ * Free space callback. ++ */ ++static int vzquota_free_space(struct inode *inode, qsize_t number) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_datast data; ++ ++ qmblk = vzquota_inode_data(inode, &data); ++ if (qmblk == VZ_QUOTA_BAD) ++ return NO_QUOTA; /* isn't checked by the caller */ ++ if (qmblk != NULL) { ++#ifdef CONFIG_VZ_QUOTA_UGID ++ int cnt; ++ struct vz_quota_ugid * qugid; ++#endif ++ ++ vzquota_decr_space(&qmblk->dq_stat, number); ++#ifdef CONFIG_VZ_QUOTA_UGID ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ qugid = INODE_QLNK(inode)->qugid[cnt]; ++ if (qugid == NULL || qugid == VZ_QUOTA_UGBAD) ++ continue; ++ vzquota_decr_space(&qugid->qugid_stat, number); ++ } ++#endif ++ vzquota_data_unlock(inode, &data); ++ } ++ inode_sub_bytes(inode, number); ++ might_sleep(); ++ return QUOTA_OK; ++} ++ ++/* ++ * Free inodes callback. ++ */ ++static int vzquota_free_inode(const struct inode *inode, unsigned long number) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_datast data; ++ ++ qmblk = vzquota_inode_data((struct inode *)inode, &data); ++ if (qmblk == VZ_QUOTA_BAD) ++ return NO_QUOTA; ++ if (qmblk != NULL) { ++#ifdef CONFIG_VZ_QUOTA_UGID ++ int cnt; ++ struct vz_quota_ugid * qugid; ++#endif ++ ++ vzquota_decr_inodes(&qmblk->dq_stat, number); ++#ifdef CONFIG_VZ_QUOTA_UGID ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ qugid = INODE_QLNK(inode)->qugid[cnt]; ++ if (qugid == NULL || qugid == VZ_QUOTA_UGBAD) ++ continue; ++ vzquota_decr_inodes(&qugid->qugid_stat, number); ++ } ++#endif ++ vzquota_data_unlock((struct inode *)inode, &data); ++ } ++ might_sleep(); ++ return QUOTA_OK; ++} ++ ++void vzquota_inode_off(struct inode * inode) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_datast data; ++ ++ /* The call is made through virtinfo, it can be an inode ++ * not controlled by vzquota. ++ */ ++ if (inode->i_sb->dq_op != &vz_quota_operations) ++ return; ++ ++ qmblk = vzquota_inode_data(inode, &data); ++ if (qmblk == VZ_QUOTA_BAD) ++ return; ++ ++ if (qmblk == NULL) { ++ /* Tricky place. If qmblk == NULL, it means that this inode ++ * is not in area controlled by vzquota (except for rare ++ * case of already set S_NOQUOTA). But we have to set ++ * S_NOQUOTA in any case because vzquota can be turned ++ * on later, when this inode is invalid from viewpoint ++ * of vzquota. ++ * ++ * To be safe, we reacquire vzquota lock. ++ */ ++ inode_qmblk_lock(inode->i_sb); ++ inode->i_flags |= S_NOQUOTA; ++ inode_qmblk_unlock(inode->i_sb); ++ return; ++ } else { ++ loff_t bytes = inode_get_bytes(inode); ++#ifdef CONFIG_VZ_QUOTA_UGID ++ int cnt; ++ struct vz_quota_ugid * qugid; ++#endif ++ ++ inode->i_flags |= S_NOQUOTA; ++ ++ vzquota_decr_space(&qmblk->dq_stat, bytes); ++ vzquota_decr_inodes(&qmblk->dq_stat, 1); ++#ifdef CONFIG_VZ_QUOTA_UGID ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ qugid = INODE_QLNK(inode)->qugid[cnt]; ++ if (qugid == NULL || qugid == VZ_QUOTA_UGBAD) ++ continue; ++ vzquota_decr_space(&qugid->qugid_stat, bytes); ++ vzquota_decr_inodes(&qugid->qugid_stat, 1); ++ } ++#endif ++ ++ vzquota_data_unlock(inode, &data); ++ ++ vzquota_inode_drop_call(inode); ++ } ++} ++ ++ ++#ifdef CONFIG_VZ_QUOTA_UGID ++ ++/* ++ * helper function for quota_transfer ++ * check that we can add inode to this quota_id ++ */ ++static int vzquota_transfer_check(struct vz_quota_master *qmblk, ++ struct vz_quota_ugid *qugid[], ++ unsigned int type, __u64 size) ++{ ++ if (vzquota_check_ugid_space(qmblk, qugid, type, size, 0) != QUOTA_OK || ++ vzquota_check_ugid_inodes(qmblk, qugid, type, 1) != QUOTA_OK) ++ return -1; ++ return 0; ++} ++ ++int vzquota_transfer_usage(struct inode *inode, ++ int mask, ++ struct vz_quota_ilink *qlnk) ++{ ++ struct vz_quota_ugid *qugid_old; ++ __u64 space; ++ int i; ++ ++ space = inode_get_bytes(inode); ++ for (i = 0; i < MAXQUOTAS; i++) { ++ if (!(mask & (1 << i))) ++ continue; ++ /* ++ * Do not permit chown a file if its owner does not have ++ * ugid record. This might happen if we somehow exceeded ++ * the UID/GID (e.g. set uglimit less than number of users). ++ */ ++ if (INODE_QLNK(inode)->qugid[i] == VZ_QUOTA_UGBAD) ++ return -1; ++ if (vzquota_transfer_check(qlnk->qmblk, qlnk->qugid, i, space)) ++ return -1; ++ } ++ ++ for (i = 0; i < MAXQUOTAS; i++) { ++ if (!(mask & (1 << i))) ++ continue; ++ qugid_old = INODE_QLNK(inode)->qugid[i]; ++ vzquota_decr_space(&qugid_old->qugid_stat, space); ++ vzquota_decr_inodes(&qugid_old->qugid_stat, 1); ++ vzquota_incr_space(&qlnk->qugid[i]->qugid_stat, space); ++ vzquota_incr_inodes(&qlnk->qugid[i]->qugid_stat, 1); ++ } ++ return 0; ++} ++ ++/* ++ * Transfer the inode between diffent user/group quotas. ++ */ ++static int vzquota_transfer(struct inode *inode, struct iattr *iattr) ++{ ++ return vzquota_inode_transfer_call(inode, iattr) ? ++ NO_QUOTA : QUOTA_OK; ++} ++ ++#else /* CONFIG_VZ_QUOTA_UGID */ ++ ++static int vzquota_transfer(struct inode *inode, struct iattr *iattr) ++{ ++ return QUOTA_OK; ++} ++ ++#endif ++ ++/* ++ * Called under following semaphores: ++ * old_d->d_inode->i_sb->s_vfs_rename_sem ++ * old_d->d_inode->i_sem ++ * new_d->d_inode->i_sem ++ * [not verified --SAW] ++ */ ++static int vzquota_rename(struct inode *inode, ++ struct inode *old_dir, struct inode *new_dir) ++{ ++ return vzquota_rename_check(inode, old_dir, new_dir) ? ++ NO_QUOTA : QUOTA_OK; ++} ++ ++/* ++ * Structure of superblock diskquota operations. ++ */ ++struct dquot_operations vz_quota_operations = { ++ .initialize = vzquota_initialize, ++ .drop = vzquota_drop, ++ .alloc_space = vzquota_alloc_space, ++ .alloc_inode = vzquota_alloc_inode, ++ .free_space = vzquota_free_space, ++ .free_inode = vzquota_free_inode, ++ .transfer = vzquota_transfer, ++ .rename = vzquota_rename, ++}; +Index: kernel/fs/vzdq_tree.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/fs/vzdq_tree.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,286 @@ ++/* ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * This file contains Virtuozzo quota tree implementation ++ */ ++ ++#include ++#include ++#include ++ ++struct quotatree_tree *quotatree_alloc(void) ++{ ++ int l; ++ struct quotatree_tree *tree; ++ ++ tree = kmalloc(sizeof(struct quotatree_tree), GFP_KERNEL); ++ if (tree == NULL) ++ goto out; ++ ++ for (l = 0; l < QUOTATREE_DEPTH; l++) { ++ INIT_LIST_HEAD(&tree->levels[l].usedlh); ++ INIT_LIST_HEAD(&tree->levels[l].freelh); ++ tree->levels[l].freenum = 0; ++ } ++ tree->root = NULL; ++ tree->leaf_num = 0; ++out: ++ return tree; ++} ++ ++static struct quotatree_node * ++quotatree_follow(struct quotatree_tree *tree, quotaid_t id, int level, ++ struct quotatree_find_state *st) ++{ ++ void **block; ++ struct quotatree_node *parent; ++ int l, index; ++ ++ parent = NULL; ++ block = (void **)&tree->root; ++ l = 0; ++ while (l < level && *block != NULL) { ++ index = (id >> QUOTATREE_BSHIFT(l)) & QUOTATREE_BMASK; ++ parent = *block; ++ block = parent->blocks + index; ++ l++; ++ } ++ if (st != NULL) { ++ st->block = block; ++ st->level = l; ++ } ++ ++ return parent; ++} ++ ++void *quotatree_find(struct quotatree_tree *tree, quotaid_t id, ++ struct quotatree_find_state *st) ++{ ++ quotatree_follow(tree, id, QUOTATREE_DEPTH, st); ++ if (st->level == QUOTATREE_DEPTH) ++ return *st->block; ++ else ++ return NULL; ++} ++ ++void *quotatree_leaf_byindex(struct quotatree_tree *tree, unsigned int index) ++{ ++ int i, count; ++ struct quotatree_node *p; ++ void *leaf; ++ ++ if (QTREE_LEAFNUM(tree) <= index) ++ return NULL; ++ ++ count = 0; ++ list_for_each_entry(p, &QTREE_LEAFLVL(tree)->usedlh, list) { ++ for (i = 0; i < QUOTATREE_BSIZE; i++) { ++ leaf = p->blocks[i]; ++ if (leaf == NULL) ++ continue; ++ if (count == index) ++ return leaf; ++ count++; ++ } ++ } ++ return NULL; ++} ++ ++/* returns data leaf (vz_quota_ugid) after _existent_ ugid (@id) ++ * in the tree... */ ++void *quotatree_get_next(struct quotatree_tree *tree, quotaid_t id) ++{ ++ int off; ++ struct quotatree_node *parent, *p; ++ struct list_head *lh; ++ ++ /* get parent refering correct quota tree node of the last level */ ++ parent = quotatree_follow(tree, id, QUOTATREE_DEPTH, NULL); ++ if (!parent) ++ return NULL; ++ ++ off = (id & QUOTATREE_BMASK) + 1; /* next ugid */ ++ lh = &parent->list; ++ do { ++ p = list_entry(lh, struct quotatree_node, list); ++ for ( ; off < QUOTATREE_BSIZE; off++) ++ if (p->blocks[off]) ++ return p->blocks[off]; ++ off = 0; ++ lh = lh->next; ++ } while (lh != &QTREE_LEAFLVL(tree)->usedlh); ++ ++ return NULL; ++} ++ ++int quotatree_insert(struct quotatree_tree *tree, quotaid_t id, ++ struct quotatree_find_state *st, void *data) ++{ ++ struct quotatree_node *p; ++ int l, index; ++ ++ while (st->level < QUOTATREE_DEPTH) { ++ l = st->level; ++ if (!list_empty(&tree->levels[l].freelh)) { ++ p = list_entry(tree->levels[l].freelh.next, ++ struct quotatree_node, list); ++ list_del(&p->list); ++ } else { ++ p = kmalloc(sizeof(struct quotatree_node), GFP_NOFS | __GFP_NOFAIL); ++ if (p == NULL) ++ return -ENOMEM; ++ /* save block number in the l-level ++ * it uses for quota file generation */ ++ p->num = tree->levels[l].freenum++; ++ } ++ list_add(&p->list, &tree->levels[l].usedlh); ++ memset(p->blocks, 0, sizeof(p->blocks)); ++ *st->block = p; ++ ++ index = (id >> QUOTATREE_BSHIFT(l)) & QUOTATREE_BMASK; ++ st->block = p->blocks + index; ++ st->level++; ++ } ++ tree->leaf_num++; ++ *st->block = data; ++ ++ return 0; ++} ++ ++static struct quotatree_node * ++quotatree_remove_ptr(struct quotatree_tree *tree, quotaid_t id, ++ int level) ++{ ++ struct quotatree_node *parent; ++ struct quotatree_find_state st; ++ ++ parent = quotatree_follow(tree, id, level, &st); ++ if (st.level == QUOTATREE_DEPTH) ++ tree->leaf_num--; ++ *st.block = NULL; ++ return parent; ++} ++ ++void quotatree_remove(struct quotatree_tree *tree, quotaid_t id) ++{ ++ struct quotatree_node *p; ++ int level, i; ++ ++ p = quotatree_remove_ptr(tree, id, QUOTATREE_DEPTH); ++ for (level = QUOTATREE_DEPTH - 1; level >= QUOTATREE_CDEPTH; level--) { ++ for (i = 0; i < QUOTATREE_BSIZE; i++) ++ if (p->blocks[i] != NULL) ++ return; ++ list_move(&p->list, &tree->levels[level].freelh); ++ p = quotatree_remove_ptr(tree, id, level); ++ } ++} ++ ++#if 0 ++static void quotatree_walk(struct quotatree_tree *tree, ++ struct quotatree_node *node_start, ++ quotaid_t id_start, ++ int level_start, int level_end, ++ int (*callback)(struct quotatree_tree *, ++ quotaid_t id, ++ int level, ++ void *ptr, ++ void *data), ++ void *data) ++{ ++ struct quotatree_node *p; ++ int l, shift, index; ++ quotaid_t id; ++ struct quotatree_find_state st; ++ ++ p = node_start; ++ l = level_start; ++ shift = (QUOTATREE_DEPTH - l) * QUOTAID_BBITS; ++ id = id_start; ++ index = 0; ++ ++ /* ++ * Invariants: ++ * shift == (QUOTATREE_DEPTH - l) * QUOTAID_BBITS; ++ * id & ((1 << shift) - 1) == 0 ++ * p is l-level node corresponding to id ++ */ ++ do { ++ if (!p) ++ break; ++ ++ if (l < level_end) { ++ for (; index < QUOTATREE_BSIZE; index++) ++ if (p->blocks[index] != NULL) ++ break; ++ if (index < QUOTATREE_BSIZE) { ++ /* descend */ ++ p = p->blocks[index]; ++ l++; ++ shift -= QUOTAID_BBITS; ++ id += (quotaid_t)index << shift; ++ index = 0; ++ continue; ++ } ++ } ++ ++ if ((*callback)(tree, id, l, p, data)) ++ break; ++ ++ /* ascend and to the next node */ ++ p = quotatree_follow(tree, id, l, &st); ++ ++ index = ((id >> shift) & QUOTATREE_BMASK) + 1; ++ l--; ++ shift += QUOTAID_BBITS; ++ id &= ~(((quotaid_t)1 << shift) - 1); ++ } while (l >= level_start); ++} ++#endif ++ ++static void free_list(struct list_head *node_list) ++{ ++ struct quotatree_node *p, *tmp; ++ ++ list_for_each_entry_safe(p, tmp, node_list, list) { ++ list_del(&p->list); ++ kfree(p); ++ } ++} ++ ++static inline void quotatree_free_nodes(struct quotatree_tree *tree) ++{ ++ int i; ++ ++ for (i = 0; i < QUOTATREE_DEPTH; i++) { ++ free_list(&tree->levels[i].usedlh); ++ free_list(&tree->levels[i].freelh); ++ } ++} ++ ++static void quotatree_free_leafs(struct quotatree_tree *tree, ++ void (*dtor)(void *)) ++{ ++ int i; ++ struct quotatree_node *p; ++ ++ list_for_each_entry(p, &QTREE_LEAFLVL(tree)->usedlh, list) { ++ for (i = 0; i < QUOTATREE_BSIZE; i++) { ++ if (p->blocks[i] == NULL) ++ continue; ++ ++ dtor(p->blocks[i]); ++ } ++ } ++} ++ ++void quotatree_free(struct quotatree_tree *tree, void (*dtor)(void *)) ++{ ++ quotatree_free_leafs(tree, dtor); ++ quotatree_free_nodes(tree); ++ kfree(tree); ++} +Index: kernel/fs/vzdq_ugid.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/fs/vzdq_ugid.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,1221 @@ ++/* ++ * Copyright (C) 2002 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * This file contains Virtuozzo UID/GID disk quota implementation ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* ++ * XXX ++ * may be something is needed for sb->s_dquot->info[]? ++ */ ++ ++#define USRQUOTA_MASK (1 << USRQUOTA) ++#define GRPQUOTA_MASK (1 << GRPQUOTA) ++#define QTYPE2MASK(type) (1 << (type)) ++ ++static struct kmem_cache *vz_quota_ugid_cachep; ++ ++/* guard to protect vz_quota_master from destroy in quota_on/off. Also protects ++ * list on the hash table */ ++extern struct semaphore vz_quota_sem; ++ ++inline struct vz_quota_ugid *vzquota_get_ugid(struct vz_quota_ugid *qugid) ++{ ++ if (qugid != VZ_QUOTA_UGBAD) ++ atomic_inc(&qugid->qugid_count); ++ return qugid; ++} ++ ++/* we don't limit users with zero limits */ ++static inline int vzquota_fake_stat(struct dq_stat *stat) ++{ ++ return stat->bhardlimit == 0 && stat->bsoftlimit == 0 && ++ stat->ihardlimit == 0 && stat->isoftlimit == 0; ++} ++ ++/* callback function for quotatree_free() */ ++static inline void vzquota_free_qugid(void *ptr) ++{ ++ kmem_cache_free(vz_quota_ugid_cachep, ptr); ++} ++ ++/* ++ * destroy ugid, if it have zero refcount, limits and usage ++ * must be called under qmblk->dq_sem ++ */ ++void vzquota_put_ugid(struct vz_quota_master *qmblk, ++ struct vz_quota_ugid *qugid) ++{ ++ if (qugid == VZ_QUOTA_UGBAD) ++ return; ++ qmblk_data_read_lock(qmblk); ++ if (atomic_dec_and_test(&qugid->qugid_count) && ++ (qmblk->dq_flags & VZDQUG_FIXED_SET) == 0 && ++ vzquota_fake_stat(&qugid->qugid_stat) && ++ qugid->qugid_stat.bcurrent == 0 && ++ qugid->qugid_stat.icurrent == 0) { ++ quotatree_remove(QUGID_TREE(qmblk, qugid->qugid_type), ++ qugid->qugid_id); ++ qmblk->dq_ugid_count--; ++ vzquota_free_qugid(qugid); ++ } ++ qmblk_data_read_unlock(qmblk); ++} ++ ++/* ++ * Get ugid block by its index, like it would present in array. ++ * In reality, this is not array - this is leafs chain of the tree. ++ * NULL if index is out of range. ++ * qmblk semaphore is required to protect the tree. ++ */ ++static inline struct vz_quota_ugid * ++vzquota_get_byindex(struct vz_quota_master *qmblk, unsigned int index, int type) ++{ ++ return quotatree_leaf_byindex(QUGID_TREE(qmblk, type), index); ++} ++ ++/* ++ * get next element from ugid "virtual array" ++ * ugid must be in current array and this array may not be changed between ++ * two accesses (quaranteed by "stopped" quota state and quota semaphore) ++ * qmblk semaphore is required to protect the tree ++ */ ++static inline struct vz_quota_ugid * ++vzquota_get_next(struct vz_quota_master *qmblk, struct vz_quota_ugid *qugid) ++{ ++ return quotatree_get_next(QUGID_TREE(qmblk, qugid->qugid_type), ++ qugid->qugid_id); ++} ++ ++/* ++ * requires dq_sem ++ */ ++struct vz_quota_ugid *__vzquota_find_ugid(struct vz_quota_master *qmblk, ++ unsigned int quota_id, int type, int flags) ++{ ++ struct vz_quota_ugid *qugid; ++ struct quotatree_tree *tree; ++ struct quotatree_find_state st; ++ ++ tree = QUGID_TREE(qmblk, type); ++ qugid = quotatree_find(tree, quota_id, &st); ++ if (qugid) ++ goto success; ++ ++ /* caller does not want alloc */ ++ if (flags & VZDQUG_FIND_DONT_ALLOC) ++ goto fail; ++ ++ if (flags & VZDQUG_FIND_FAKE) ++ goto doit; ++ ++ /* check limit */ ++ if (qmblk->dq_ugid_count >= qmblk->dq_ugid_max) ++ goto fail; ++ ++ /* see comment at VZDQUG_FIXED_SET define */ ++ if (qmblk->dq_flags & VZDQUG_FIXED_SET) ++ goto fail; ++ ++doit: ++ /* alloc new structure */ ++ qugid = kmem_cache_alloc(vz_quota_ugid_cachep, ++ GFP_NOFS | __GFP_NOFAIL); ++ if (qugid == NULL) ++ goto fail; ++ ++ /* initialize new structure */ ++ qugid->qugid_id = quota_id; ++ memset(&qugid->qugid_stat, 0, sizeof(qugid->qugid_stat)); ++ qugid->qugid_type = type; ++ atomic_set(&qugid->qugid_count, 0); ++ ++ /* insert in tree */ ++ if (quotatree_insert(tree, quota_id, &st, qugid) < 0) ++ goto fail_insert; ++ qmblk->dq_ugid_count++; ++ ++success: ++ vzquota_get_ugid(qugid); ++ return qugid; ++ ++fail_insert: ++ vzquota_free_qugid(qugid); ++fail: ++ return VZ_QUOTA_UGBAD; ++} ++ ++/* ++ * takes dq_sem, may schedule ++ */ ++struct vz_quota_ugid *vzquota_find_ugid(struct vz_quota_master *qmblk, ++ unsigned int quota_id, int type, int flags) ++{ ++ struct vz_quota_ugid *qugid; ++ ++ down(&qmblk->dq_sem); ++ qugid = __vzquota_find_ugid(qmblk, quota_id, type, flags); ++ up(&qmblk->dq_sem); ++ ++ return qugid; ++} ++ ++/* ++ * destroy all ugid records on given quota master ++ */ ++void vzquota_kill_ugid(struct vz_quota_master *qmblk) ++{ ++ BUG_ON((qmblk->dq_gid_tree == NULL && qmblk->dq_uid_tree != NULL) || ++ (qmblk->dq_uid_tree == NULL && qmblk->dq_gid_tree != NULL)); ++ ++ if (qmblk->dq_uid_tree != NULL) { ++ quotatree_free(qmblk->dq_uid_tree, vzquota_free_qugid); ++ quotatree_free(qmblk->dq_gid_tree, vzquota_free_qugid); ++ } ++} ++ ++ ++/* ---------------------------------------------------------------------- ++ * Management interface to ugid quota for (super)users. ++ * --------------------------------------------------------------------- */ ++ ++static int vzquota_initialize2(struct inode *inode, int type) ++{ ++ return QUOTA_OK; ++} ++ ++static int vzquota_drop2(struct inode *inode) ++{ ++ return QUOTA_OK; ++} ++ ++static int vzquota_alloc_space2(struct inode *inode, ++ qsize_t number, int prealloc) ++{ ++ inode_add_bytes(inode, number); ++ return QUOTA_OK; ++} ++ ++static int vzquota_alloc_inode2(const struct inode *inode, unsigned long number) ++{ ++ return QUOTA_OK; ++} ++ ++static int vzquota_free_space2(struct inode *inode, qsize_t number) ++{ ++ inode_sub_bytes(inode, number); ++ return QUOTA_OK; ++} ++ ++static int vzquota_free_inode2(const struct inode *inode, unsigned long number) ++{ ++ return QUOTA_OK; ++} ++ ++static int vzquota_transfer2(struct inode *inode, struct iattr *iattr) ++{ ++ return QUOTA_OK; ++} ++ ++struct dquot_operations vz_quota_operations2 = { ++ .initialize = vzquota_initialize2, ++ .drop = vzquota_drop2, ++ .alloc_space = vzquota_alloc_space2, ++ .alloc_inode = vzquota_alloc_inode2, ++ .free_space = vzquota_free_space2, ++ .free_inode = vzquota_free_inode2, ++ .transfer = vzquota_transfer2, ++}; ++ ++ ++asmlinkage long sys_unlink(const char __user * pathname); ++asmlinkage long sys_rename(const char __user * oldname, ++ const char __user * newname); ++asmlinkage long sys_symlink(const char __user * oldname, ++ const char __user * newname); ++ ++/* called under sb->s_umount semaphore */ ++static int vz_restore_symlink(struct super_block *sb, char *path, int type) ++{ ++ mm_segment_t oldfs; ++ char *newpath; ++ char dest[64]; ++ const char *names[] = { ++ [USRQUOTA] "aquota.user", ++ [GRPQUOTA] "aquota.group" ++ }; ++ int err; ++ ++ newpath = kmalloc(strlen(path) + sizeof(".new"), GFP_KERNEL); ++ if (newpath == NULL) ++ return -ENOMEM; ++ ++ strcpy(newpath, path); ++ strcat(newpath, ".new"); ++ ++ sprintf(dest, "/proc/vz/vzaquota/%08x/%s", ++ new_encode_dev(sb->s_dev), names[type]); ++ ++ /* ++ * Lockdep will learn unneeded dependency while unlink(2): ++ * ->s_umount => ->i_mutex/1 => ->i_mutex ++ * Reverse dependency is, ++ * open_namei() => ->i_mutex => lookup_hash() => __lookup_hash() ++ * => ->lookup() \eq vzdq_aquotq_lookup() => find_qmblk_by_dev() ++ * => user_get_super() => ->s_umount ++ * ++ * However, first set of ->i_mutex'es belong to /, second to /proc . ++ * Right fix is to get rid of vz_restore_symlink(), of course. ++ */ ++ up_read(&sb->s_umount); ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = sys_unlink(newpath); ++ if (err < 0 && err != -ENOENT) ++ goto out_restore; ++ err = sys_symlink(dest, newpath); ++ if (err < 0) ++ goto out_restore; ++ err = sys_rename(newpath, path); ++out_restore: ++ set_fs(oldfs); ++ ++ down_read(&sb->s_umount); ++ /* umounted meanwhile? */ ++ if (err == 0 && !sb->s_root) ++ err = -ENODEV; ++ ++ kfree(newpath); ++ return err; ++} ++ ++/* called under sb->s_umount semaphore */ ++static int vz_quota_on(struct super_block *sb, int type, ++ int format_id, char *path) ++{ ++ struct vz_quota_master *qmblk; ++ int mask, mask2; ++ int err; ++ ++ qmblk = vzquota_find_qmblk(sb); ++ err = -ESRCH; ++ if (qmblk == NULL) ++ goto out; ++ err = -EIO; ++ if (qmblk == VZ_QUOTA_BAD) ++ goto out; ++ ++ err = vz_restore_symlink(sb, path, type); ++ if (err < 0) ++ goto out_put; ++ ++ down(&vz_quota_sem); ++ mask = 0; ++ mask2 = 0; ++ sb->dq_op = &vz_quota_operations2; ++ sb->s_qcop = &vz_quotactl_operations; ++ if (type == USRQUOTA) { ++ mask = DQUOT_USR_ENABLED; ++ mask2 = VZDQ_USRQUOTA; ++ } ++ if (type == GRPQUOTA) { ++ mask = DQUOT_GRP_ENABLED; ++ mask2 = VZDQ_GRPQUOTA; ++ } ++ err = -EBUSY; ++ if (qmblk->dq_flags & mask2) ++ goto out_sem; ++ ++ err = 0; ++ qmblk->dq_flags |= mask2; ++ sb->s_dquot.flags |= mask; ++ ++out_sem: ++ up(&vz_quota_sem); ++out_put: ++ qmblk_put(qmblk); ++out: ++ return err; ++} ++ ++static int vz_quota_off(struct super_block *sb, int type) ++{ ++ struct vz_quota_master *qmblk; ++ int mask2; ++ int err; ++ ++ qmblk = vzquota_find_qmblk(sb); ++ down(&vz_quota_sem); ++ err = -ESRCH; ++ if (qmblk == NULL) ++ goto out; ++ err = -EIO; ++ if (qmblk == VZ_QUOTA_BAD) ++ goto out; ++ ++ mask2 = 0; ++ if (type == USRQUOTA) ++ mask2 = VZDQ_USRQUOTA; ++ if (type == GRPQUOTA) ++ mask2 = VZDQ_GRPQUOTA; ++ err = -EINVAL; ++ if (!(qmblk->dq_flags & mask2)) ++ goto out; ++ ++ qmblk->dq_flags &= ~mask2; ++ err = 0; ++ ++out: ++ up(&vz_quota_sem); ++ if (qmblk != NULL && qmblk != VZ_QUOTA_BAD) ++ qmblk_put(qmblk); ++ return err; ++} ++ ++static int vz_quota_sync(struct super_block *sb, int type) ++{ ++ return 0; /* vz quota is always uptodate */ ++} ++ ++static int vz_get_dqblk(struct super_block *sb, int type, ++ qid_t id, struct if_dqblk *di) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_ugid *ugid; ++ int err; ++ ++ qmblk = vzquota_find_qmblk(sb); ++ down(&vz_quota_sem); ++ err = -ESRCH; ++ if (qmblk == NULL) ++ goto out; ++ err = -EIO; ++ if (qmblk == VZ_QUOTA_BAD) ++ goto out; ++ ++ err = 0; ++ ugid = vzquota_find_ugid(qmblk, id, type, VZDQUG_FIND_DONT_ALLOC); ++ if (ugid != VZ_QUOTA_UGBAD) { ++ qmblk_data_read_lock(qmblk); ++ di->dqb_bhardlimit = ugid->qugid_stat.bhardlimit >> 10; ++ di->dqb_bsoftlimit = ugid->qugid_stat.bsoftlimit >> 10; ++ di->dqb_curspace = ugid->qugid_stat.bcurrent; ++ di->dqb_ihardlimit = ugid->qugid_stat.ihardlimit; ++ di->dqb_isoftlimit = ugid->qugid_stat.isoftlimit; ++ di->dqb_curinodes = ugid->qugid_stat.icurrent; ++ di->dqb_btime = ugid->qugid_stat.btime; ++ di->dqb_itime = ugid->qugid_stat.itime; ++ qmblk_data_read_unlock(qmblk); ++ di->dqb_valid = QIF_ALL; ++ vzquota_put_ugid(qmblk, ugid); ++ } else { ++ memset(di, 0, sizeof(*di)); ++ di->dqb_valid = QIF_ALL; ++ } ++ ++out: ++ up(&vz_quota_sem); ++ if (qmblk != NULL && qmblk != VZ_QUOTA_BAD) ++ qmblk_put(qmblk); ++ return err; ++} ++ ++/* must be called under vz_quota_sem */ ++static int __vz_set_dqblk(struct vz_quota_master *qmblk, ++ int type, qid_t id, struct if_dqblk *di) ++{ ++ struct vz_quota_ugid *ugid; ++ ++ ugid = vzquota_find_ugid(qmblk, id, type, 0); ++ if (ugid == VZ_QUOTA_UGBAD) ++ return -ESRCH; ++ ++ qmblk_data_write_lock(qmblk); ++ /* ++ * Subtle compatibility breakage. ++ * ++ * Some old non-vz kernel quota didn't start grace period ++ * if the new soft limit happens to be below the usage. ++ * Non-vz kernel quota in 2.4.20 starts the grace period ++ * (if it hasn't been started). ++ * Current non-vz kernel performs even more complicated ++ * manipulations... ++ * ++ * Also, current non-vz kernels have inconsistency related to ++ * the grace time start. In regular operations the grace period ++ * is started if the usage is greater than the soft limit (and, ++ * strangely, is cancelled if the usage is less). ++ * However, set_dqblk starts the grace period if the usage is greater ++ * or equal to the soft limit. ++ * ++ * Here we try to mimic the behavior of the current non-vz kernel. ++ */ ++ if (di->dqb_valid & QIF_BLIMITS) { ++ ugid->qugid_stat.bhardlimit = ++ (__u64)di->dqb_bhardlimit << 10; ++ ugid->qugid_stat.bsoftlimit = ++ (__u64)di->dqb_bsoftlimit << 10; ++ if (di->dqb_bsoftlimit == 0 || ++ ugid->qugid_stat.bcurrent < ugid->qugid_stat.bsoftlimit) ++ ugid->qugid_stat.btime = 0; ++ else if (!(di->dqb_valid & QIF_BTIME)) ++ ugid->qugid_stat.btime = CURRENT_TIME_SECONDS ++ + qmblk->dq_ugid_info[type].bexpire; ++ else ++ ugid->qugid_stat.btime = di->dqb_btime; ++ } ++ if (di->dqb_valid & QIF_ILIMITS) { ++ ugid->qugid_stat.ihardlimit = di->dqb_ihardlimit; ++ ugid->qugid_stat.isoftlimit = di->dqb_isoftlimit; ++ if (di->dqb_isoftlimit == 0 || ++ ugid->qugid_stat.icurrent < ugid->qugid_stat.isoftlimit) ++ ugid->qugid_stat.itime = 0; ++ else if (!(di->dqb_valid & QIF_ITIME)) ++ ugid->qugid_stat.itime = CURRENT_TIME_SECONDS ++ + qmblk->dq_ugid_info[type].iexpire; ++ else ++ ugid->qugid_stat.itime = di->dqb_itime; ++ } ++ qmblk_data_write_unlock(qmblk); ++ vzquota_put_ugid(qmblk, ugid); ++ ++ return 0; ++} ++ ++static int vz_set_dqblk(struct super_block *sb, int type, ++ qid_t id, struct if_dqblk *di) ++{ ++ struct vz_quota_master *qmblk; ++ int err; ++ ++ qmblk = vzquota_find_qmblk(sb); ++ down(&vz_quota_sem); ++ err = -ESRCH; ++ if (qmblk == NULL) ++ goto out; ++ err = -EIO; ++ if (qmblk == VZ_QUOTA_BAD) ++ goto out; ++ err = __vz_set_dqblk(qmblk, type, id, di); ++out: ++ up(&vz_quota_sem); ++ if (qmblk != NULL && qmblk != VZ_QUOTA_BAD) ++ qmblk_put(qmblk); ++ return err; ++} ++ ++static int vz_get_dqinfo(struct super_block *sb, int type, ++ struct if_dqinfo *ii) ++{ ++ struct vz_quota_master *qmblk; ++ int err; ++ ++ qmblk = vzquota_find_qmblk(sb); ++ down(&vz_quota_sem); ++ err = -ESRCH; ++ if (qmblk == NULL) ++ goto out; ++ err = -EIO; ++ if (qmblk == VZ_QUOTA_BAD) ++ goto out; ++ ++ err = 0; ++ ii->dqi_bgrace = qmblk->dq_ugid_info[type].bexpire; ++ ii->dqi_igrace = qmblk->dq_ugid_info[type].iexpire; ++ ii->dqi_flags = 0; ++ ii->dqi_valid = IIF_ALL; ++ ++out: ++ up(&vz_quota_sem); ++ if (qmblk != NULL && qmblk != VZ_QUOTA_BAD) ++ qmblk_put(qmblk); ++ return err; ++} ++ ++/* must be called under vz_quota_sem */ ++static int __vz_set_dqinfo(struct vz_quota_master *qmblk, ++ int type, struct if_dqinfo *ii) ++{ ++ if (ii->dqi_valid & IIF_FLAGS) ++ if (ii->dqi_flags & DQF_MASK) ++ return -EINVAL; ++ ++ if (ii->dqi_valid & IIF_BGRACE) ++ qmblk->dq_ugid_info[type].bexpire = ii->dqi_bgrace; ++ if (ii->dqi_valid & IIF_IGRACE) ++ qmblk->dq_ugid_info[type].iexpire = ii->dqi_igrace; ++ return 0; ++} ++ ++static int vz_set_dqinfo(struct super_block *sb, int type, ++ struct if_dqinfo *ii) ++{ ++ struct vz_quota_master *qmblk; ++ int err; ++ ++ qmblk = vzquota_find_qmblk(sb); ++ down(&vz_quota_sem); ++ err = -ESRCH; ++ if (qmblk == NULL) ++ goto out; ++ err = -EIO; ++ if (qmblk == VZ_QUOTA_BAD) ++ goto out; ++ err = __vz_set_dqinfo(qmblk, type, ii); ++out: ++ up(&vz_quota_sem); ++ if (qmblk != NULL && qmblk != VZ_QUOTA_BAD) ++ qmblk_put(qmblk); ++ return err; ++} ++ ++#ifdef CONFIG_QUOTA_COMPAT ++ ++#define Q_GETQUOTI_SIZE 1024 ++ ++#define UGID2DQBLK(dst, src) \ ++ do { \ ++ (dst)->dqb_ihardlimit = (src)->qugid_stat.ihardlimit; \ ++ (dst)->dqb_isoftlimit = (src)->qugid_stat.isoftlimit; \ ++ (dst)->dqb_curinodes = (src)->qugid_stat.icurrent; \ ++ /* in 1K blocks */ \ ++ (dst)->dqb_bhardlimit = (src)->qugid_stat.bhardlimit >> 10; \ ++ /* in 1K blocks */ \ ++ (dst)->dqb_bsoftlimit = (src)->qugid_stat.bsoftlimit >> 10; \ ++ /* in bytes, 64 bit */ \ ++ (dst)->dqb_curspace = (src)->qugid_stat.bcurrent; \ ++ (dst)->dqb_btime = (src)->qugid_stat.btime; \ ++ (dst)->dqb_itime = (src)->qugid_stat.itime; \ ++ } while (0) ++ ++static int vz_get_quoti(struct super_block *sb, int type, qid_t idx, ++ struct v2_disk_dqblk __user *dqblk) ++{ ++ struct vz_quota_master *qmblk; ++ struct v2_disk_dqblk *data, *kbuf; ++ struct vz_quota_ugid *ugid; ++ int count; ++ int err; ++ ++ qmblk = vzquota_find_qmblk(sb); ++ err = -ESRCH; ++ if (qmblk == NULL) ++ goto out; ++ err = -EIO; ++ if (qmblk == VZ_QUOTA_BAD) ++ goto out; ++ ++ err = -ENOMEM; ++ kbuf = vmalloc(Q_GETQUOTI_SIZE * sizeof(*kbuf)); ++ if (!kbuf) ++ goto out; ++ ++ down(&vz_quota_sem); ++ down(&qmblk->dq_sem); ++ for (ugid = vzquota_get_byindex(qmblk, idx, type), count = 0; ++ ugid != NULL && count < Q_GETQUOTI_SIZE; ++ count++) ++ { ++ data = kbuf + count; ++ qmblk_data_read_lock(qmblk); ++ UGID2DQBLK(data, ugid); ++ qmblk_data_read_unlock(qmblk); ++ data->dqb_id = ugid->qugid_id; ++ ++ /* Find next entry */ ++ ugid = vzquota_get_next(qmblk, ugid); ++ BUG_ON(ugid != NULL && ugid->qugid_type != type); ++ } ++ up(&qmblk->dq_sem); ++ up(&vz_quota_sem); ++ ++ err = count; ++ if (copy_to_user(dqblk, kbuf, count * sizeof(*kbuf))) ++ err = -EFAULT; ++ ++ vfree(kbuf); ++out: ++ if (qmblk != NULL && qmblk != VZ_QUOTA_BAD) ++ qmblk_put(qmblk); ++ ++ return err; ++} ++ ++#endif ++ ++struct quotactl_ops vz_quotactl_operations = { ++ .quota_on = vz_quota_on, ++ .quota_off = vz_quota_off, ++ .quota_sync = vz_quota_sync, ++ .get_info = vz_get_dqinfo, ++ .set_info = vz_set_dqinfo, ++ .get_dqblk = vz_get_dqblk, ++ .set_dqblk = vz_set_dqblk, ++#ifdef CONFIG_QUOTA_COMPAT ++ .get_quoti = vz_get_quoti, ++#endif ++}; ++ ++ ++/* ---------------------------------------------------------------------- ++ * Management interface for host system admins. ++ * --------------------------------------------------------------------- */ ++ ++static int quota_ugid_addstat(unsigned int quota_id, unsigned int ugid_size, ++ struct vz_quota_iface __user *u_ugid_buf, int compat) ++{ ++ struct vz_quota_master *qmblk; ++ int ret; ++ ++ down(&vz_quota_sem); ++ ++ ret = -ENOENT; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ ret = -EBUSY; ++ if (qmblk->dq_state != VZDQ_STARTING) ++ goto out; /* working quota doesn't accept new ugids */ ++ ++ ret = 0; ++ /* start to add ugids */ ++ for (ret = 0; ret < ugid_size; ret++) { ++ struct vz_quota_iface ugid_buf; ++ struct vz_quota_ugid *ugid; ++ ++ if (!compat) { ++ if (copy_from_user(&ugid_buf, u_ugid_buf, ++ sizeof(ugid_buf))) ++ break; ++ u_ugid_buf++; /* next user buffer */ ++ } else { ++#ifdef CONFIG_COMPAT ++ struct compat_vz_quota_iface oqif; ++ if (copy_from_user(&oqif, u_ugid_buf, ++ sizeof(oqif))) ++ break; ++ ugid_buf.qi_id = oqif.qi_id; ++ ugid_buf.qi_type = oqif.qi_type; ++ compat_dqstat2dqstat(&oqif.qi_stat, &ugid_buf.qi_stat); ++ u_ugid_buf = (struct vz_quota_iface __user *) ++ (((void *)u_ugid_buf) + sizeof(oqif)); ++#endif ++ } ++ ++ if (ugid_buf.qi_type >= MAXQUOTAS) ++ break; /* bad quota type - this is the only check */ ++ ++ ugid = vzquota_find_ugid(qmblk, ++ ugid_buf.qi_id, ugid_buf.qi_type, 0); ++ if (ugid == VZ_QUOTA_UGBAD) { ++ qmblk->dq_flags |= VZDQUG_FIXED_SET; ++ break; /* limit reached */ ++ } ++ ++ /* update usage/limits ++ * we can copy the data without the lock, because the data ++ * cannot be modified in VZDQ_STARTING state */ ++ ugid->qugid_stat = ugid_buf.qi_stat; ++ ++ vzquota_put_ugid(qmblk, ugid); ++ } ++out: ++ up(&vz_quota_sem); ++ ++ return ret; ++} ++ ++static int quota_ugid_setgrace(unsigned int quota_id, ++ struct dq_info __user u_dq_info[], int compat) ++{ ++ struct vz_quota_master *qmblk; ++ struct dq_info dq_info[MAXQUOTAS]; ++ struct dq_info *target; ++ int err, type; ++ ++ down(&vz_quota_sem); ++ ++ err = -ENOENT; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ err = -EBUSY; ++ if (qmblk->dq_state != VZDQ_STARTING) ++ goto out; /* working quota doesn't accept changing options */ ++ ++ err = -EFAULT; ++ if (!compat) { ++ if (copy_from_user(dq_info, u_dq_info, sizeof(dq_info))) ++ goto out; ++ } else { ++#ifdef CONFIG_COMPAT ++ struct compat_dq_info odqi[MAXQUOTAS]; ++ if (copy_from_user(odqi, u_dq_info, sizeof(odqi))) ++ goto out; ++ for (type = 0; type < MAXQUOTAS; type++) ++ compat_dqinfo2dqinfo(&odqi[type], &dq_info[type]); ++#endif ++ } ++ ++ err = 0; ++ ++ /* update in qmblk */ ++ for (type = 0; type < MAXQUOTAS; type++) { ++ target = &qmblk->dq_ugid_info[type]; ++ target->bexpire = dq_info[type].bexpire; ++ target->iexpire = dq_info[type].iexpire; ++ } ++out: ++ up(&vz_quota_sem); ++ ++ return err; ++} ++ ++static int do_quota_ugid_getstat(struct vz_quota_master *qmblk, int index, int size, ++ struct vz_quota_iface *u_ugid_buf) ++{ ++ int type, count; ++ struct vz_quota_ugid *ugid; ++ ++ if (QTREE_LEAFNUM(qmblk->dq_uid_tree) + ++ QTREE_LEAFNUM(qmblk->dq_gid_tree) ++ <= index) ++ return 0; ++ ++ count = 0; ++ ++ type = index < QTREE_LEAFNUM(qmblk->dq_uid_tree) ? USRQUOTA : GRPQUOTA; ++ if (type == GRPQUOTA) ++ index -= QTREE_LEAFNUM(qmblk->dq_uid_tree); ++ ++ /* loop through ugid and then qgid quota */ ++repeat: ++ for (ugid = vzquota_get_byindex(qmblk, index, type); ++ ugid != NULL && count < size; ++ ugid = vzquota_get_next(qmblk, ugid), count++) ++ { ++ struct vz_quota_iface ugid_buf; ++ ++ /* form interface buffer and send in to user-level */ ++ qmblk_data_read_lock(qmblk); ++ memcpy(&ugid_buf.qi_stat, &ugid->qugid_stat, ++ sizeof(ugid_buf.qi_stat)); ++ qmblk_data_read_unlock(qmblk); ++ ugid_buf.qi_id = ugid->qugid_id; ++ ugid_buf.qi_type = ugid->qugid_type; ++ ++ memcpy(u_ugid_buf, &ugid_buf, sizeof(ugid_buf)); ++ u_ugid_buf++; /* next portion of user buffer */ ++ } ++ ++ if (type == USRQUOTA && count < size) { ++ type = GRPQUOTA; ++ index = 0; ++ goto repeat; ++ } ++ ++ return count; ++} ++ ++static int quota_ugid_getstat(unsigned int quota_id, ++ int index, int size, struct vz_quota_iface __user *u_ugid_buf, ++ int compat) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_iface *k_ugid_buf; ++ int err; ++ ++ if (index < 0 || size < 0) ++ return -EINVAL; ++ ++ if (size > INT_MAX / sizeof(struct vz_quota_iface)) ++ return -EINVAL; ++ ++ k_ugid_buf = vmalloc(size * sizeof(struct vz_quota_iface)); ++ if (k_ugid_buf == NULL) ++ return -ENOMEM; ++ ++ down(&vz_quota_sem); ++ ++ err = -ENOENT; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ down(&qmblk->dq_sem); ++ err = do_quota_ugid_getstat(qmblk, index, size, k_ugid_buf); ++ up(&qmblk->dq_sem); ++ if (err < 0) ++ goto out; ++ ++ if (!compat) { ++ if (copy_to_user(u_ugid_buf, k_ugid_buf, ++ err * sizeof(struct vz_quota_iface))) ++ err = -EFAULT; ++ } else { ++#ifdef CONFIG_COMPAT ++ struct compat_vz_quota_iface oqif; ++ int i; ++ for (i = 0; i < err; i++) { ++ oqif.qi_id = k_ugid_buf[i].qi_id; ++ oqif.qi_type = k_ugid_buf[i].qi_type; ++ dqstat2compat_dqstat(&k_ugid_buf[i].qi_stat, ++ &oqif.qi_stat); ++ if (copy_to_user(u_ugid_buf, &oqif, sizeof(oqif))) ++ err = -EFAULT; ++ u_ugid_buf = (struct vz_quota_iface __user *) ++ (((void *)u_ugid_buf) + sizeof(oqif)); ++ } ++#endif ++ } ++ ++out: ++ up(&vz_quota_sem); ++ vfree(k_ugid_buf); ++ return err; ++} ++ ++static int quota_ugid_getgrace(unsigned int quota_id, ++ struct dq_info __user u_dq_info[], int compat) ++{ ++ struct vz_quota_master *qmblk; ++ struct dq_info dq_info[MAXQUOTAS]; ++ struct dq_info *target; ++ int err, type; ++ ++ down(&vz_quota_sem); ++ ++ err = -ENOENT; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ err = 0; ++ /* update from qmblk */ ++ for (type = 0; type < MAXQUOTAS; type ++) { ++ target = &qmblk->dq_ugid_info[type]; ++ dq_info[type].bexpire = target->bexpire; ++ dq_info[type].iexpire = target->iexpire; ++ dq_info[type].flags = target->flags; ++ } ++ ++ if (!compat) { ++ if (copy_to_user(u_dq_info, dq_info, sizeof(dq_info))) ++ err = -EFAULT; ++ } else { ++#ifdef CONFIG_COMPAT ++ struct compat_dq_info odqi[MAXQUOTAS]; ++ for (type = 0; type < MAXQUOTAS; type ++) ++ dqinfo2compat_dqinfo(&dq_info[type], &odqi[type]); ++ if (copy_to_user(u_dq_info, odqi, sizeof(odqi))) ++ err = -EFAULT; ++#endif ++ } ++out: ++ up(&vz_quota_sem); ++ ++ return err; ++} ++ ++static int quota_ugid_getconfig(unsigned int quota_id, ++ struct vz_quota_ugid_stat __user *info) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_ugid_stat kinfo; ++ int err; ++ ++ down(&vz_quota_sem); ++ ++ err = -ENOENT; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ err = 0; ++ kinfo.limit = qmblk->dq_ugid_max; ++ kinfo.count = qmblk->dq_ugid_count; ++ kinfo.flags = qmblk->dq_flags; ++ ++ if (copy_to_user(info, &kinfo, sizeof(kinfo))) ++ err = -EFAULT; ++out: ++ up(&vz_quota_sem); ++ ++ return err; ++} ++ ++static int quota_ugid_setconfig(unsigned int quota_id, ++ struct vz_quota_ugid_stat __user *info) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_ugid_stat kinfo; ++ int err; ++ ++ down(&vz_quota_sem); ++ ++ err = -ENOENT; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ err = -EFAULT; ++ if (copy_from_user(&kinfo, info, sizeof(kinfo))) ++ goto out; ++ ++ err = 0; ++ qmblk->dq_ugid_max = kinfo.limit; ++ if (qmblk->dq_state == VZDQ_STARTING) { ++ qmblk->dq_flags = kinfo.flags; ++ if (qmblk->dq_flags & VZDQUG_ON) ++ qmblk->dq_flags |= VZDQ_USRQUOTA | VZDQ_GRPQUOTA; ++ } ++ ++out: ++ up(&vz_quota_sem); ++ ++ return err; ++} ++ ++static int quota_ugid_setlimit(unsigned int quota_id, ++ struct vz_quota_ugid_setlimit __user *u_lim) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_ugid_setlimit lim; ++ int err; ++ ++ down(&vz_quota_sem); ++ ++ err = -ESRCH; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ err = -EFAULT; ++ if (copy_from_user(&lim, u_lim, sizeof(lim))) ++ goto out; ++ ++ err = __vz_set_dqblk(qmblk, lim.type, lim.id, &lim.dqb); ++ ++out: ++ up(&vz_quota_sem); ++ ++ return err; ++} ++ ++static int quota_ugid_setinfo(unsigned int quota_id, ++ struct vz_quota_ugid_setinfo __user *u_info) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_ugid_setinfo info; ++ int err; ++ ++ down(&vz_quota_sem); ++ ++ err = -ESRCH; ++ qmblk = vzquota_find_master(quota_id); ++ if (qmblk == NULL) ++ goto out; ++ ++ err = -EFAULT; ++ if (copy_from_user(&info, u_info, sizeof(info))) ++ goto out; ++ ++ err = __vz_set_dqinfo(qmblk, info.type, &info.dqi); ++ ++out: ++ up(&vz_quota_sem); ++ ++ return err; ++} ++ ++/* ++ * This is a system call to maintain UGID quotas ++ * Note this call is allowed to run ONLY from VE0 ++ */ ++long do_vzquotaugidctl(int cmd, unsigned int quota_id, ++ unsigned int ugid_index, unsigned int ugid_size, ++ void *addr, int compat) ++{ ++ int ret; ++ ++ ret = -EPERM; ++ /* access allowed only from root of VE0 */ ++ if (!capable(CAP_SYS_RESOURCE) || ++ !capable(CAP_SYS_ADMIN)) ++ goto out; ++ ++ switch (cmd) { ++ case VZ_DQ_UGID_GETSTAT: ++ ret = quota_ugid_getstat(quota_id, ++ ugid_index, ugid_size, ++ (struct vz_quota_iface __user *)addr, ++ compat); ++ break; ++ case VZ_DQ_UGID_ADDSTAT: ++ ret = quota_ugid_addstat(quota_id, ugid_size, ++ (struct vz_quota_iface __user *) addr, ++ compat); ++ break; ++ case VZ_DQ_UGID_GETGRACE: ++ ret = quota_ugid_getgrace(quota_id, ++ (struct dq_info __user *)addr, compat); ++ break; ++ case VZ_DQ_UGID_SETGRACE: ++ ret = quota_ugid_setgrace(quota_id, ++ (struct dq_info __user *)addr, compat); ++ break; ++ case VZ_DQ_UGID_GETCONFIG: ++ ret = quota_ugid_getconfig(quota_id, ++ (struct vz_quota_ugid_stat __user *) ++ addr); ++ break; ++ case VZ_DQ_UGID_SETCONFIG: ++ ret = quota_ugid_setconfig(quota_id, ++ (struct vz_quota_ugid_stat __user *) ++ addr); ++ break; ++ case VZ_DQ_UGID_SETLIMIT: ++ ret = quota_ugid_setlimit(quota_id, ++ (struct vz_quota_ugid_setlimit __user *) ++ addr); ++ break; ++ case VZ_DQ_UGID_SETINFO: ++ ret = quota_ugid_setinfo(quota_id, ++ (struct vz_quota_ugid_setinfo __user *) ++ addr); ++ break; ++ default: ++ ret = -EINVAL; ++ goto out; ++ } ++out: ++ return ret; ++} ++ ++static void ugid_quota_on_sb(struct super_block *sb) ++{ ++ struct super_block *real_sb; ++ struct vz_quota_master *qmblk; ++ ++ if (!sb->s_op->get_quota_root) ++ return; ++ ++ real_sb = sb->s_op->get_quota_root(sb)->i_sb; ++ if (real_sb->dq_op != &vz_quota_operations) ++ return; ++ ++ sb->dq_op = &vz_quota_operations2; ++ sb->s_qcop = &vz_quotactl_operations; ++ INIT_LIST_HEAD(&sb->s_dquot.info[USRQUOTA].dqi_dirty_list); ++ INIT_LIST_HEAD(&sb->s_dquot.info[GRPQUOTA].dqi_dirty_list); ++ sb->s_dquot.info[USRQUOTA].dqi_format = &vz_quota_empty_v2_format; ++ sb->s_dquot.info[GRPQUOTA].dqi_format = &vz_quota_empty_v2_format; ++ ++ qmblk = vzquota_find_qmblk(sb); ++ if ((qmblk == NULL) || (qmblk == VZ_QUOTA_BAD)) ++ return; ++ down(&vz_quota_sem); ++ if (qmblk->dq_flags & VZDQ_USRQUOTA) ++ sb->s_dquot.flags |= DQUOT_USR_ENABLED; ++ if (qmblk->dq_flags & VZDQ_GRPQUOTA) ++ sb->s_dquot.flags |= DQUOT_GRP_ENABLED; ++ up(&vz_quota_sem); ++ qmblk_put(qmblk); ++} ++ ++static void ugid_quota_off_sb(struct super_block *sb) ++{ ++ /* can't make quota off on mounted super block */ ++ BUG_ON(sb->s_root != NULL); ++} ++ ++static int ugid_notifier_call(struct vnotifier_block *self, ++ unsigned long n, void *data, int old_ret) ++{ ++ struct virt_info_quota *viq; ++ ++ viq = (struct virt_info_quota *)data; ++ ++ switch (n) { ++ case VIRTINFO_QUOTA_ON: ++ ugid_quota_on_sb(viq->super); ++ break; ++ case VIRTINFO_QUOTA_OFF: ++ ugid_quota_off_sb(viq->super); ++ break; ++ case VIRTINFO_QUOTA_GETSTAT: ++ break; ++ default: ++ return old_ret; ++ } ++ return NOTIFY_OK; ++} ++ ++static struct vnotifier_block ugid_notifier_block = { ++ .notifier_call = ugid_notifier_call, ++}; ++ ++/* ---------------------------------------------------------------------- ++ * Init/exit. ++ * --------------------------------------------------------------------- */ ++ ++int vzquota_ugid_init(void) ++{ ++ int err; ++ ++ vz_quota_ugid_cachep = kmem_cache_create("vz_quota_ugid", ++ sizeof(struct vz_quota_ugid), ++ 0, SLAB_HWCACHE_ALIGN, NULL); ++ if (vz_quota_ugid_cachep == NULL) ++ goto err_slab; ++ ++ err = register_quota_format(&vz_quota_empty_v2_format); ++ if (err) ++ goto err_reg; ++ ++ virtinfo_notifier_register(VITYPE_QUOTA, &ugid_notifier_block); ++ return 0; ++ ++err_reg: ++ kmem_cache_destroy(vz_quota_ugid_cachep); ++ return err; ++ ++err_slab: ++ printk(KERN_ERR "Cannot create VZ_QUOTA SLAB cache\n"); ++ return -ENOMEM; ++} ++ ++void vzquota_ugid_release(void) ++{ ++ virtinfo_notifier_unregister(VITYPE_QUOTA, &ugid_notifier_block); ++ unregister_quota_format(&vz_quota_empty_v2_format); ++ ++ kmem_cache_destroy(vz_quota_ugid_cachep); ++} +Index: kernel/fs/vzdquot.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/fs/vzdquot.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,1954 @@ ++/* ++ * Copyright (C) 2001, 2002, 2004, 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * This file contains the core of Virtuozzo disk quota implementation: ++ * maintenance of VZDQ information in inodes, ++ * external interfaces, ++ * module entry. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ---------------------------------------------------------------------- ++ * ++ * Locking ++ * ++ * ---------------------------------------------------------------------- */ ++ ++/* ++ * Serializes on/off and all other do_vzquotactl operations. ++ * Protects qmblk hash. ++ */ ++struct semaphore vz_quota_sem; ++ ++/* ++ * Data access locks ++ * inode_qmblk ++ * protects qmblk pointers in all inodes and qlnk content in general ++ * (but not qmblk content); ++ * also protects related qmblk invalidation procedures; ++ * can't be per-inode because of vzquota_dtree_qmblk complications ++ * and problems with serialization with quota_on, ++ * but can be per-superblock; ++ * qmblk_data ++ * protects qmblk fields (such as current usage) ++ * quota_data ++ * protects charge/uncharge operations, thus, implies ++ * qmblk_data lock and, if CONFIG_VZ_QUOTA_UGID, inode_qmblk lock ++ * (to protect ugid pointers). ++ * ++ * Lock order: ++ * inode_qmblk_lock -> dcache_lock ++ * inode_qmblk_lock -> qmblk_data ++ */ ++static DEFINE_SPINLOCK(vzdq_qmblk_lock); ++ ++inline void inode_qmblk_lock(struct super_block *sb) ++{ ++ spin_lock(&vzdq_qmblk_lock); ++} ++ ++inline void inode_qmblk_unlock(struct super_block *sb) ++{ ++ spin_unlock(&vzdq_qmblk_lock); ++} ++ ++inline void qmblk_data_read_lock(struct vz_quota_master *qmblk) ++{ ++ spin_lock(&qmblk->dq_data_lock); ++} ++ ++inline void qmblk_data_read_unlock(struct vz_quota_master *qmblk) ++{ ++ spin_unlock(&qmblk->dq_data_lock); ++} ++ ++inline void qmblk_data_write_lock(struct vz_quota_master *qmblk) ++{ ++ spin_lock(&qmblk->dq_data_lock); ++} ++ ++inline void qmblk_data_write_unlock(struct vz_quota_master *qmblk) ++{ ++ spin_unlock(&qmblk->dq_data_lock); ++} ++ ++struct quota_format_type vz_quota_empty_v2_format = { ++ .qf_fmt_id = QFMT_VFS_V0, ++ .qf_ops = NULL, ++ .qf_owner = THIS_MODULE, ++}; ++ ++/* ---------------------------------------------------------------------- ++ * ++ * Master hash table handling. ++ * ++ * SMP not safe, serialied by vz_quota_sem within quota syscalls ++ * ++ * --------------------------------------------------------------------- */ ++ ++static struct kmem_cache *vzquota_cachep; ++ ++/* ++ * Hash function. ++ */ ++#define QHASH_BITS 6 ++#define VZ_QUOTA_HASH_SIZE (1 << QHASH_BITS) ++#define QHASH_MASK (VZ_QUOTA_HASH_SIZE - 1) ++ ++struct list_head vzquota_hash_table[VZ_QUOTA_HASH_SIZE]; ++int vzquota_hash_size = VZ_QUOTA_HASH_SIZE; ++ ++static inline int vzquota_hash_func(unsigned int qid) ++{ ++ return (((qid >> QHASH_BITS) ^ qid) & QHASH_MASK); ++} ++ ++/** ++ * vzquota_alloc_master - alloc and instantiate master quota record ++ * ++ * Returns: ++ * pointer to newly created record if SUCCESS ++ * -ENOMEM if out of memory ++ * -EEXIST if record with given quota_id already exist ++ */ ++struct vz_quota_master *vzquota_alloc_master(unsigned int quota_id, ++ struct vz_quota_stat *qstat) ++{ ++ int err; ++ struct vz_quota_master *qmblk; ++ ++ err = -EEXIST; ++ if (vzquota_find_master(quota_id) != NULL) ++ goto out; ++ ++ err = -ENOMEM; ++ qmblk = kmem_cache_alloc(vzquota_cachep, GFP_KERNEL); ++ if (qmblk == NULL) ++ goto out; ++#ifdef CONFIG_VZ_QUOTA_UGID ++ qmblk->dq_uid_tree = quotatree_alloc(); ++ if (!qmblk->dq_uid_tree) ++ goto out_free; ++ ++ qmblk->dq_gid_tree = quotatree_alloc(); ++ if (!qmblk->dq_gid_tree) ++ goto out_free_tree; ++#endif ++ ++ qmblk->dq_state = VZDQ_STARTING; ++ init_MUTEX(&qmblk->dq_sem); ++ spin_lock_init(&qmblk->dq_data_lock); ++ ++ qmblk->dq_id = quota_id; ++ qmblk->dq_stat = qstat->dq_stat; ++ qmblk->dq_info = qstat->dq_info; ++ qmblk->dq_root_dentry = NULL; ++ qmblk->dq_root_mnt = NULL; ++ qmblk->dq_sb = NULL; ++ qmblk->dq_ugid_count = 0; ++ qmblk->dq_ugid_max = 0; ++ qmblk->dq_flags = 0; ++ memset(qmblk->dq_ugid_info, 0, sizeof(qmblk->dq_ugid_info)); ++ INIT_LIST_HEAD(&qmblk->dq_ilink_list); ++ ++ atomic_set(&qmblk->dq_count, 1); ++ ++ /* insert in hash chain */ ++ list_add(&qmblk->dq_hash, ++ &vzquota_hash_table[vzquota_hash_func(quota_id)]); ++ ++ /* success */ ++ return qmblk; ++ ++#ifdef CONFIG_VZ_QUOTA_UGID ++out_free_tree: ++ quotatree_free(qmblk->dq_uid_tree, NULL); ++out_free: ++ kmem_cache_free(vzquota_cachep, qmblk); ++#endif ++out: ++ return ERR_PTR(err); ++} ++ ++static struct vz_quota_master *vzquota_alloc_fake(void) ++{ ++ struct vz_quota_master *qmblk; ++ ++ qmblk = kmem_cache_alloc(vzquota_cachep, GFP_KERNEL); ++ if (qmblk == NULL) ++ return NULL; ++ memset(qmblk, 0, sizeof(*qmblk)); ++ qmblk->dq_state = VZDQ_STOPING; ++ qmblk->dq_flags = VZDQ_NOQUOT; ++ spin_lock_init(&qmblk->dq_data_lock); ++ INIT_LIST_HEAD(&qmblk->dq_ilink_list); ++ atomic_set(&qmblk->dq_count, 1); ++ return qmblk; ++} ++ ++/** ++ * vzquota_find_master - find master record with given id ++ * ++ * Returns qmblk without touching its refcounter. ++ * Called under vz_quota_sem. ++ */ ++struct vz_quota_master *vzquota_find_master(unsigned int quota_id) ++{ ++ int i; ++ struct vz_quota_master *qp; ++ ++ i = vzquota_hash_func(quota_id); ++ list_for_each_entry(qp, &vzquota_hash_table[i], dq_hash) { ++ if (qp->dq_id == quota_id) ++ return qp; ++ } ++ return NULL; ++} ++ ++/** ++ * vzquota_free_master - release resources taken by qmblk, freeing memory ++ * ++ * qmblk is assumed to be already taken out from the hash. ++ * Should be called outside vz_quota_sem. ++ */ ++void vzquota_free_master(struct vz_quota_master *qmblk) ++{ ++#ifdef CONFIG_VZ_QUOTA_UGID ++ vzquota_kill_ugid(qmblk); ++#endif ++ BUG_ON(!list_empty(&qmblk->dq_ilink_list)); ++ kmem_cache_free(vzquota_cachep, qmblk); ++} ++ ++ ++/* ---------------------------------------------------------------------- ++ * ++ * Passing quota information through current ++ * ++ * Used in inode -> qmblk lookup at inode creation stage (since at that ++ * time there are no links between the inode being created and its parent ++ * directory). ++ * ++ * --------------------------------------------------------------------- */ ++ ++#define VZDQ_CUR_MAGIC 0x57d0fee2 ++ ++static inline int vzquota_cur_qmblk_check(void) ++{ ++ return current->magic == VZDQ_CUR_MAGIC; ++} ++ ++static inline struct inode *vzquota_cur_qmblk_fetch(void) ++{ ++ return current->ino; ++} ++ ++static inline void vzquota_cur_qmblk_set(struct inode *data) ++{ ++ struct task_struct *tsk; ++ ++ tsk = current; ++ tsk->magic = VZDQ_CUR_MAGIC; ++ tsk->ino = data; ++} ++ ++#if 0 ++static inline void vzquota_cur_qmblk_reset(void) ++{ ++ current->magic = 0; ++} ++#endif ++ ++ ++/* ---------------------------------------------------------------------- ++ * ++ * Superblock quota operations ++ * ++ * --------------------------------------------------------------------- */ ++ ++/* ++ * Kernel structure abuse. ++ * We use files[0] pointer as an int variable: ++ * reference counter of how many quota blocks uses this superblock. ++ * files[1] is used for generations structure which helps us to track ++ * when traversing of dentries is really required. ++ */ ++#define __VZ_QUOTA_NOQUOTA(sb) sb->s_dquot.vzdq_master ++#define __VZ_QUOTA_TSTAMP(sb) ((struct timeval *)\ ++ &sb->s_dquot.dqio_mutex) ++ ++#if defined(VZ_QUOTA_UNLOAD) ++ ++#define __VZ_QUOTA_SBREF(sb) sb->s_dquot.vzdq_count ++ ++struct dquot_operations *orig_dq_op; ++struct quotactl_ops *orig_dq_cop; ++ ++/** ++ * quota_get_super - account for new a quoted tree under the superblock ++ * ++ * One superblock can have multiple directory subtrees with different VZ ++ * quotas. We keep a counter of such subtrees and set VZ quota operations or ++ * reset the default ones. ++ * ++ * Called under vz_quota_sem (from quota_on). ++ */ ++int vzquota_get_super(struct super_block *sb) ++{ ++ if (sb->dq_op != &vz_quota_operations) { ++ down(&sb->s_dquot.dqonoff_sem); ++ if (sb->s_dquot.flags & (DQUOT_USR_ENABLED|DQUOT_GRP_ENABLED)) { ++ up(&sb->s_dquot.dqonoff_sem); ++ return -EEXIST; ++ } ++ if (orig_dq_op == NULL && sb->dq_op != NULL) ++ orig_dq_op = sb->dq_op; ++ sb->dq_op = &vz_quota_operations; ++ if (orig_dq_cop == NULL && sb->s_qcop != NULL) ++ orig_dq_cop = sb->s_qcop; ++ /* XXX this may race with sys_quotactl */ ++#ifdef CONFIG_VZ_QUOTA_UGID ++ sb->s_qcop = &vz_quotactl_operations; ++#else ++ sb->s_qcop = NULL; ++#endif ++ do_gettimeofday(__VZ_QUOTA_TSTAMP(sb)); ++ memset(&sb->s_dquot.info, 0, sizeof(sb->s_dquot.info)); ++ ++ INIT_LIST_HEAD(&sb->s_dquot.info[USRQUOTA].dqi_dirty_list); ++ INIT_LIST_HEAD(&sb->s_dquot.info[GRPQUOTA].dqi_dirty_list); ++ sb->s_dquot.info[USRQUOTA].dqi_format = &vz_quota_empty_v2_format; ++ sb->s_dquot.info[GRPQUOTA].dqi_format = &vz_quota_empty_v2_format; ++ /* ++ * To get quotaops.h call us we need to mark superblock ++ * as having quota. These flags mark the moment when ++ * our dq_op start to be called. ++ * ++ * The ordering of dq_op and s_dquot.flags assignment ++ * needs to be enforced, but other CPUs do not do rmb() ++ * between s_dquot.flags and dq_op accesses. ++ */ ++ wmb(); synchronize_sched(); ++ sb->s_dquot.flags = DQUOT_USR_ENABLED|DQUOT_GRP_ENABLED; ++ __module_get(THIS_MODULE); ++ up(&sb->s_dquot.dqonoff_sem); ++ } ++ /* protected by vz_quota_sem */ ++ __VZ_QUOTA_SBREF(sb)++; ++ return 0; ++} ++ ++/** ++ * quota_put_super - release superblock when one quota tree goes away ++ * ++ * Called under vz_quota_sem. ++ */ ++void vzquota_put_super(struct super_block *sb) ++{ ++ int count; ++ ++ count = --__VZ_QUOTA_SBREF(sb); ++ if (count == 0) { ++ down(&sb->s_dquot.dqonoff_sem); ++ sb->s_dquot.flags = 0; ++ wmb(); synchronize_sched(); ++ sema_init(&sb->s_dquot.dqio_sem, 1); ++ sb->s_qcop = orig_dq_cop; ++ sb->dq_op = orig_dq_op; ++ inode_qmblk_lock(sb); ++ quota_gen_put(SB_QGEN(sb)); ++ SB_QGEN(sb) = NULL; ++ /* release qlnk's without qmblk */ ++ remove_inode_quota_links_list(&non_vzquota_inodes_lh, ++ sb, NULL); ++ /* ++ * Races with quota initialization: ++ * after this inode_qmblk_unlock all inode's generations are ++ * invalidated, quota_inode_qmblk checks superblock operations. ++ */ ++ inode_qmblk_unlock(sb); ++ /* ++ * Module refcounting: in theory, this is the best place ++ * to call module_put(THIS_MODULE). ++ * In reality, it can't be done because we can't be sure that ++ * other CPUs do not enter our code segment through dq_op ++ * cached long time ago. Quotaops interface isn't supposed to ++ * go into modules currently (that is, into unloadable ++ * modules). By omitting module_put, our module isn't ++ * unloadable. ++ */ ++ up(&sb->s_dquot.dqonoff_sem); ++ } ++} ++ ++#else ++ ++struct vzquota_new_sop { ++ struct super_operations new_op; ++ const struct super_operations *old_op; ++}; ++ ++/** ++ * vzquota_shutdown_super - callback on umount ++ */ ++void vzquota_shutdown_super(struct super_block *sb) ++{ ++ struct vz_quota_master *qmblk; ++ struct vzquota_new_sop *sop; ++ ++ qmblk = __VZ_QUOTA_NOQUOTA(sb); ++ __VZ_QUOTA_NOQUOTA(sb) = NULL; ++ if (qmblk != NULL) ++ qmblk_put(qmblk); ++ sop = container_of(sb->s_op, struct vzquota_new_sop, new_op); ++ sb->s_op = sop->old_op; ++ kfree(sop); ++ if (sb->s_op->put_super != NULL) ++ (*sb->s_op->put_super)(sb); ++} ++ ++/** ++ * vzquota_get_super - account for new a quoted tree under the superblock ++ * ++ * One superblock can have multiple directory subtrees with different VZ ++ * quotas. ++ * ++ * Called under vz_quota_sem (from vzquota_on). ++ */ ++int vzquota_get_super(struct super_block *sb) ++{ ++ struct vz_quota_master *qnew; ++ struct vzquota_new_sop *sop; ++ int err; ++ ++ mutex_lock(&sb->s_dquot.dqonoff_mutex); ++ err = -EEXIST; ++ if ((sb->s_dquot.flags & (DQUOT_USR_ENABLED|DQUOT_GRP_ENABLED)) && ++ sb->dq_op != &vz_quota_operations) ++ goto out_up; ++ ++ /* ++ * This allocation code should be under sb->dq_op check below, but ++ * it doesn't really matter... ++ */ ++ if (__VZ_QUOTA_NOQUOTA(sb) == NULL) { ++ qnew = vzquota_alloc_fake(); ++ if (qnew == NULL) ++ goto out_up; ++ __VZ_QUOTA_NOQUOTA(sb) = qnew; ++ } ++ ++ if (sb->dq_op != &vz_quota_operations) { ++ sop = kmalloc(sizeof(*sop), GFP_KERNEL); ++ if (sop == NULL) { ++ vzquota_free_master(__VZ_QUOTA_NOQUOTA(sb)); ++ __VZ_QUOTA_NOQUOTA(sb) = NULL; ++ goto out_up; ++ } ++ memcpy(&sop->new_op, sb->s_op, sizeof(sop->new_op)); ++ sop->new_op.put_super = &vzquota_shutdown_super; ++ sop->old_op = sb->s_op; ++ sb->s_op = &sop->new_op; ++ ++ sb->dq_op = &vz_quota_operations; ++#ifdef CONFIG_VZ_QUOTA_UGID ++ sb->s_qcop = &vz_quotactl_operations; ++#else ++ sb->s_qcop = NULL; ++#endif ++ do_gettimeofday(__VZ_QUOTA_TSTAMP(sb)); ++ ++ memset(&sb->s_dquot.info, 0, sizeof(sb->s_dquot.info)); ++ /* these 2 list heads are checked in sync_dquots() */ ++ INIT_LIST_HEAD(&sb->s_dquot.info[USRQUOTA].dqi_dirty_list); ++ INIT_LIST_HEAD(&sb->s_dquot.info[GRPQUOTA].dqi_dirty_list); ++ sb->s_dquot.info[USRQUOTA].dqi_format = ++ &vz_quota_empty_v2_format; ++ sb->s_dquot.info[GRPQUOTA].dqi_format = ++ &vz_quota_empty_v2_format; ++ ++ /* ++ * To get quotaops.h to call us we need to mark superblock ++ * as having quota. These flags mark the moment when ++ * our dq_op start to be called. ++ * ++ * The ordering of dq_op and s_dquot.flags assignment ++ * needs to be enforced, but other CPUs do not do rmb() ++ * between s_dquot.flags and dq_op accesses. ++ */ ++ wmb(); synchronize_sched(); ++ sb->s_dquot.flags = DQUOT_USR_ENABLED|DQUOT_GRP_ENABLED; ++ } ++ err = 0; ++ ++out_up: ++ mutex_unlock(&sb->s_dquot.dqonoff_mutex); ++ return err; ++} ++ ++/** ++ * vzquota_put_super - one quota tree less on this superblock ++ * ++ * Called under vz_quota_sem. ++ */ ++void vzquota_put_super(struct super_block *sb) ++{ ++ /* ++ * Even if this put is the last one, ++ * sb->s_dquot.flags can't be cleared, because otherwise vzquota_drop ++ * won't be called and the remaining qmblk references won't be put. ++ */ ++} ++ ++#endif ++ ++ ++/* ---------------------------------------------------------------------- ++ * ++ * Helpers for inode -> qmblk link maintenance ++ * ++ * --------------------------------------------------------------------- */ ++ ++#define __VZ_QUOTA_EMPTY ((void *)0xbdbdbdbd) ++#define VZ_QUOTA_IS_NOQUOTA(qm, sb) ((qm)->dq_flags & VZDQ_NOQUOT) ++#define VZ_QUOTA_EMPTY_IOPS (&vfs_empty_iops) ++extern struct inode_operations vfs_empty_iops; ++ ++static int VZ_QUOTA_IS_ACTUAL(struct inode *inode) ++{ ++ struct vz_quota_master *qmblk; ++ ++ qmblk = INODE_QLNK(inode)->qmblk; ++ if (qmblk == VZ_QUOTA_BAD) ++ return 1; ++ if (qmblk == __VZ_QUOTA_EMPTY) ++ return 0; ++ if (qmblk->dq_flags & VZDQ_NOACT) ++ /* not actual (invalidated) qmblk */ ++ return 0; ++ return 1; ++} ++ ++static inline int vzquota_qlnk_is_empty(struct vz_quota_ilink *qlnk) ++{ ++ return qlnk->qmblk == __VZ_QUOTA_EMPTY; ++} ++ ++static inline void set_qlnk_origin(struct vz_quota_ilink *qlnk, ++ unsigned char origin) ++{ ++ qlnk->origin[0] = qlnk->origin[1]; ++ qlnk->origin[1] = origin; ++} ++ ++static inline void vzquota_qlnk_set_empty(struct vz_quota_ilink *qlnk) ++{ ++ qlnk->qmblk = __VZ_QUOTA_EMPTY; ++ set_qlnk_origin(qlnk, VZ_QUOTAO_SETE); ++} ++ ++void vzquota_qlnk_init(struct vz_quota_ilink *qlnk) ++{ ++ memset(qlnk, 0, sizeof(*qlnk)); ++ INIT_LIST_HEAD(&qlnk->list); ++ vzquota_qlnk_set_empty(qlnk); ++ set_qlnk_origin(qlnk, VZ_QUOTAO_INIT); ++} ++ ++void vzquota_qlnk_destroy(struct vz_quota_ilink *qlnk) ++{ ++ might_sleep(); ++ if (vzquota_qlnk_is_empty(qlnk)) ++ return; ++#if defined(CONFIG_VZ_QUOTA_UGID) ++ if (qlnk->qmblk != NULL && qlnk->qmblk != VZ_QUOTA_BAD) { ++ struct vz_quota_master *qmblk; ++ struct vz_quota_ugid *quid, *qgid; ++ qmblk = qlnk->qmblk; ++ quid = qlnk->qugid[USRQUOTA]; ++ qgid = qlnk->qugid[GRPQUOTA]; ++ if (quid != NULL || qgid != NULL) { ++ down(&qmblk->dq_sem); ++ if (qgid != NULL) ++ vzquota_put_ugid(qmblk, qgid); ++ if (quid != NULL) ++ vzquota_put_ugid(qmblk, quid); ++ up(&qmblk->dq_sem); ++ } ++ } ++#endif ++ if (qlnk->qmblk != NULL && qlnk->qmblk != VZ_QUOTA_BAD) ++ qmblk_put(qlnk->qmblk); ++ set_qlnk_origin(qlnk, VZ_QUOTAO_DESTR); ++} ++ ++/** ++ * vzquota_qlnk_swap - swap inode's and temporary vz_quota_ilink contents ++ * @qlt: temporary ++ * @qli: inode's ++ * ++ * Locking is provided by the caller (depending on the context). ++ * After swap, @qli is inserted into the corresponding dq_ilink_list, ++ * @qlt list is reinitialized. ++ */ ++static void vzquota_qlnk_swap(struct vz_quota_ilink *qlt, ++ struct vz_quota_ilink *qli) ++{ ++ struct vz_quota_master *qb; ++ struct vz_quota_ugid *qu; ++ int i; ++ ++ qb = qlt->qmblk; ++ qlt->qmblk = qli->qmblk; ++ qli->qmblk = qb; ++ list_del_init(&qli->list); ++ if (qb != __VZ_QUOTA_EMPTY && qb != VZ_QUOTA_BAD) ++ list_add(&qli->list, &qb->dq_ilink_list); ++ INIT_LIST_HEAD(&qlt->list); ++ set_qlnk_origin(qli, VZ_QUOTAO_SWAP); ++ ++ for (i = 0; i < MAXQUOTAS; i++) { ++ qu = qlt->qugid[i]; ++ qlt->qugid[i] = qli->qugid[i]; ++ qli->qugid[i] = qu; ++ } ++} ++ ++/** ++ * vzquota_qlnk_reinit_locked - destroy qlnk content, called under locks ++ * ++ * Called under dcache_lock and inode_qmblk locks. ++ * Returns 1 if locks were dropped inside, 0 if atomic. ++ */ ++static int vzquota_qlnk_reinit_locked(struct vz_quota_ilink *qlnk, ++ struct inode *inode) ++{ ++ if (vzquota_qlnk_is_empty(qlnk)) ++ return 0; ++ if (qlnk->qmblk == VZ_QUOTA_BAD) { ++ vzquota_qlnk_set_empty(qlnk); ++ set_qlnk_origin(qlnk, VZ_QUOTAO_RE_LOCK); ++ return 0; ++ } ++ spin_unlock(&dcache_lock); ++ inode_qmblk_unlock(inode->i_sb); ++ vzquota_qlnk_destroy(qlnk); ++ vzquota_qlnk_init(qlnk); ++ inode_qmblk_lock(inode->i_sb); ++ spin_lock(&dcache_lock); ++ return 1; ++} ++ ++#if defined(CONFIG_VZ_QUOTA_UGID) ++/** ++ * vzquota_qlnk_reinit_attr - destroy and reinit qlnk content ++ * ++ * Similar to vzquota_qlnk_reinit_locked, called under different locks. ++ */ ++static int vzquota_qlnk_reinit_attr(struct vz_quota_ilink *qlnk, ++ struct inode *inode, ++ struct vz_quota_master *qmblk) ++{ ++ if (vzquota_qlnk_is_empty(qlnk)) ++ return 0; ++ /* may be optimized if qlnk->qugid all NULLs */ ++ qmblk_data_write_unlock(qmblk); ++ inode_qmblk_unlock(inode->i_sb); ++ vzquota_qlnk_destroy(qlnk); ++ vzquota_qlnk_init(qlnk); ++ inode_qmblk_lock(inode->i_sb); ++ qmblk_data_write_lock(qmblk); ++ return 1; ++} ++#endif ++ ++/** ++ * vzquota_qlnk_fill - fill vz_quota_ilink content ++ * @qlnk: vz_quota_ilink to fill ++ * @inode: inode for which @qlnk is filled (i_sb, i_uid, i_gid) ++ * @qmblk: qmblk to which this @qlnk will belong ++ * ++ * Called under dcache_lock and inode_qmblk locks. ++ * Returns 1 if locks were dropped inside, 0 if atomic. ++ * @qlnk is expected to be empty. ++ */ ++static int vzquota_qlnk_fill(struct vz_quota_ilink *qlnk, ++ struct inode *inode, ++ struct vz_quota_master *qmblk) ++{ ++ if (qmblk != VZ_QUOTA_BAD) ++ qmblk_get(qmblk); ++ qlnk->qmblk = qmblk; ++ ++#if defined(CONFIG_VZ_QUOTA_UGID) ++ if (qmblk != VZ_QUOTA_BAD && ++ !VZ_QUOTA_IS_NOQUOTA(qmblk, inode->i_sb) && ++ (qmblk->dq_flags & VZDQUG_ON)) { ++ struct vz_quota_ugid *quid, *qgid; ++ ++ spin_unlock(&dcache_lock); ++ inode_qmblk_unlock(inode->i_sb); ++ ++ down(&qmblk->dq_sem); ++ quid = __vzquota_find_ugid(qmblk, inode->i_uid, USRQUOTA, 0); ++ qgid = __vzquota_find_ugid(qmblk, inode->i_gid, GRPQUOTA, 0); ++ up(&qmblk->dq_sem); ++ ++ inode_qmblk_lock(inode->i_sb); ++ spin_lock(&dcache_lock); ++ qlnk->qugid[USRQUOTA] = quid; ++ qlnk->qugid[GRPQUOTA] = qgid; ++ return 1; ++ } ++#endif ++ ++ return 0; ++} ++ ++#if defined(CONFIG_VZ_QUOTA_UGID) ++/** ++ * vzquota_qlnk_fill_attr - fill vz_quota_ilink content for uid, gid ++ * ++ * This function is a helper for vzquota_transfer, and differs from ++ * vzquota_qlnk_fill only by locking. ++ */ ++static int vzquota_qlnk_fill_attr(struct vz_quota_ilink *qlnk, ++ struct inode *inode, ++ struct iattr *iattr, ++ int mask, ++ struct vz_quota_master *qmblk) ++{ ++ qmblk_get(qmblk); ++ qlnk->qmblk = qmblk; ++ ++ if (mask) { ++ struct vz_quota_ugid *quid, *qgid; ++ ++ quid = qgid = NULL; /* to make gcc happy */ ++ if (!(mask & (1 << USRQUOTA))) ++ quid = vzquota_get_ugid(INODE_QLNK(inode)-> ++ qugid[USRQUOTA]); ++ if (!(mask & (1 << GRPQUOTA))) ++ qgid = vzquota_get_ugid(INODE_QLNK(inode)-> ++ qugid[GRPQUOTA]); ++ ++ qmblk_data_write_unlock(qmblk); ++ inode_qmblk_unlock(inode->i_sb); ++ ++ down(&qmblk->dq_sem); ++ if (mask & (1 << USRQUOTA)) ++ quid = __vzquota_find_ugid(qmblk, iattr->ia_uid, ++ USRQUOTA, 0); ++ if (mask & (1 << GRPQUOTA)) ++ qgid = __vzquota_find_ugid(qmblk, iattr->ia_gid, ++ GRPQUOTA, 0); ++ up(&qmblk->dq_sem); ++ ++ inode_qmblk_lock(inode->i_sb); ++ qmblk_data_write_lock(qmblk); ++ qlnk->qugid[USRQUOTA] = quid; ++ qlnk->qugid[GRPQUOTA] = qgid; ++ return 1; ++ } ++ ++ return 0; ++} ++#endif ++ ++/** ++ * __vzquota_inode_init - make sure inode's qlnk is initialized ++ * ++ * May be called if qlnk is already initialized, detects this situation itself. ++ * Called under inode_qmblk_lock. ++ */ ++static void __vzquota_inode_init(struct inode *inode, unsigned char origin) ++{ ++ if (inode->i_dquot[USRQUOTA] == NODQUOT) { ++ vzquota_qlnk_init(INODE_QLNK(inode)); ++ inode->i_dquot[USRQUOTA] = (void *)~(unsigned long)NODQUOT; ++ } ++ set_qlnk_origin(INODE_QLNK(inode), origin); ++} ++ ++/** ++ * vzquota_inode_drop - destroy VZ quota information in the inode ++ * ++ * Inode must not be externally accessible or dirty. ++ */ ++static void vzquota_inode_drop(struct inode *inode) ++{ ++ struct vz_quota_ilink qlnk; ++ ++ vzquota_qlnk_init(&qlnk); ++ inode_qmblk_lock(inode->i_sb); ++ vzquota_qlnk_swap(&qlnk, INODE_QLNK(inode)); ++ set_qlnk_origin(INODE_QLNK(inode), VZ_QUOTAO_DRCAL); ++ inode->i_dquot[USRQUOTA] = NODQUOT; ++ inode_qmblk_unlock(inode->i_sb); ++ vzquota_qlnk_destroy(&qlnk); ++} ++ ++/** ++ * vzquota_inode_qmblk_set - initialize inode's qlnk ++ * @inode: inode to be initialized ++ * @qmblk: quota master block to which this inode should belong (may be BAD) ++ * @qlnk: placeholder to store data to resolve locking issues ++ * ++ * Returns 1 if locks were dropped and rechecks possibly needed, 0 otherwise. ++ * Called under dcache_lock and inode_qmblk locks. ++ * @qlnk will be destroyed in the caller chain. ++ * ++ * It is not mandatory to restart parent checks since quota on/off currently ++ * shrinks dentry tree and checks that there are not outside references. ++ * But if at some time that shink is removed, restarts will be required. ++ * Additionally, the restarts prevent inconsistencies if the dentry tree ++ * changes (inode is moved). This is not a big deal, but anyway... ++ */ ++static int vzquota_inode_qmblk_set(struct inode *inode, ++ struct vz_quota_master *qmblk, ++ struct vz_quota_ilink *qlnk) ++{ ++ if (qmblk == NULL) { ++ printk(KERN_ERR "VZDQ: NULL in set, orig {%u, %u}, " ++ "dev %s, inode %lu, fs %s\n", ++ INODE_QLNK(inode)->origin[0], ++ INODE_QLNK(inode)->origin[1], ++ inode->i_sb->s_id, inode->i_ino, ++ inode->i_sb->s_type->name); ++ printk(KERN_ERR "current %d (%s), VE %d\n", ++ current->pid, current->comm, ++ VEID(get_exec_env())); ++ dump_stack(); ++ qmblk = VZ_QUOTA_BAD; ++ } ++ while (1) { ++ if (vzquota_qlnk_is_empty(qlnk) && ++ vzquota_qlnk_fill(qlnk, inode, qmblk)) ++ return 1; ++ if (qlnk->qmblk == qmblk) ++ break; ++ if (vzquota_qlnk_reinit_locked(qlnk, inode)) ++ return 1; ++ } ++ vzquota_qlnk_swap(qlnk, INODE_QLNK(inode)); ++ set_qlnk_origin(INODE_QLNK(inode), VZ_QUOTAO_QSET); ++ return 0; ++} ++ ++ ++/* ---------------------------------------------------------------------- ++ * ++ * vzquota_inode_qmblk (inode -> qmblk lookup) parts ++ * ++ * --------------------------------------------------------------------- */ ++ ++static int vzquota_dparents_check_attach(struct inode *inode) ++{ ++ if (!list_empty(&inode->i_dentry)) ++ return 0; ++ printk(KERN_ERR "VZDQ: no parent for " ++ "dev %s, inode %lu, fs %s\n", ++ inode->i_sb->s_id, ++ inode->i_ino, ++ inode->i_sb->s_type->name); ++ return -1; ++} ++ ++static struct inode *vzquota_dparents_check_actual(struct inode *inode) ++{ ++ struct dentry *de; ++ ++ list_for_each_entry(de, &inode->i_dentry, d_alias) { ++ if (de->d_parent == de) /* detached dentry, perhaps */ ++ continue; ++ /* first access to parent, make sure its qlnk initialized */ ++ __vzquota_inode_init(de->d_parent->d_inode, VZ_QUOTAO_ACT); ++ if (!VZ_QUOTA_IS_ACTUAL(de->d_parent->d_inode)) ++ return de->d_parent->d_inode; ++ } ++ return NULL; ++} ++ ++static struct vz_quota_master *vzquota_dparents_check_same(struct inode *inode) ++{ ++ struct dentry *de; ++ struct vz_quota_master *qmblk; ++ ++ qmblk = NULL; ++ list_for_each_entry(de, &inode->i_dentry, d_alias) { ++ if (de->d_parent == de) /* detached dentry, perhaps */ ++ continue; ++ if (qmblk == NULL) { ++ qmblk = INODE_QLNK(de->d_parent->d_inode)->qmblk; ++ continue; ++ } ++ if (INODE_QLNK(de->d_parent->d_inode)->qmblk != qmblk) { ++ printk(KERN_WARNING "VZDQ: multiple quotas for " ++ "dev %s, inode %lu, fs %s\n", ++ inode->i_sb->s_id, ++ inode->i_ino, ++ inode->i_sb->s_type->name); ++ qmblk = VZ_QUOTA_BAD; ++ break; ++ } ++ } ++ if (qmblk == NULL) { ++ printk(KERN_WARNING "VZDQ: not attached to tree, " ++ "dev %s, inode %lu, fs %s\n", ++ inode->i_sb->s_id, ++ inode->i_ino, ++ inode->i_sb->s_type->name); ++ qmblk = VZ_QUOTA_BAD; ++ } ++ return qmblk; ++} ++ ++static void vzquota_dbranch_actualize(struct inode *inode, ++ struct inode *refinode) ++{ ++ struct inode *pinode; ++ struct vz_quota_master *qmblk; ++ struct vz_quota_ilink qlnk; ++ ++ vzquota_qlnk_init(&qlnk); ++ ++start: ++ if (inode == inode->i_sb->s_root->d_inode) { ++ /* filesystem root */ ++ atomic_inc(&inode->i_count); ++ do { ++ qmblk = __VZ_QUOTA_NOQUOTA(inode->i_sb); ++ } while (vzquota_inode_qmblk_set(inode, qmblk, &qlnk)); ++ goto out; ++ } ++ ++ if (!vzquota_dparents_check_attach(inode)) { ++ pinode = vzquota_dparents_check_actual(inode); ++ if (pinode != NULL) { ++ inode = pinode; ++ goto start; ++ } ++ } ++ ++ atomic_inc(&inode->i_count); ++ while (1) { ++ if (VZ_QUOTA_IS_ACTUAL(inode)) /* actualized without us */ ++ break; ++ /* ++ * Need to check parents again if we have slept inside ++ * vzquota_inode_qmblk_set() in the loop. ++ * If the state of parents is different, just return and repeat ++ * the actualizing process again from the inode passed to ++ * vzquota_inode_qmblk_recalc(). ++ */ ++ if (!vzquota_dparents_check_attach(inode)) { ++ if (vzquota_dparents_check_actual(inode) != NULL) ++ break; ++ qmblk = vzquota_dparents_check_same(inode); ++ } else ++ qmblk = VZ_QUOTA_BAD; ++ if (!vzquota_inode_qmblk_set(inode, qmblk, &qlnk)){/* success */ ++ set_qlnk_origin(INODE_QLNK(inode), VZ_QUOTAO_ACT); ++ break; ++ } ++ } ++ ++out: ++ spin_unlock(&dcache_lock); ++ inode_qmblk_unlock(refinode->i_sb); ++ vzquota_qlnk_destroy(&qlnk); ++ iput(inode); ++ inode_qmblk_lock(refinode->i_sb); ++ spin_lock(&dcache_lock); ++} ++ ++static void vzquota_dtree_qmblk_recalc(struct inode *inode, ++ struct vz_quota_ilink *qlnk) ++{ ++ struct inode *pinode; ++ struct vz_quota_master *qmblk; ++ ++ if (inode == inode->i_sb->s_root->d_inode) { ++ /* filesystem root */ ++ do { ++ qmblk = __VZ_QUOTA_NOQUOTA(inode->i_sb); ++ } while (vzquota_inode_qmblk_set(inode, qmblk, qlnk)); ++ return; ++ } ++ ++start: ++ if (VZ_QUOTA_IS_ACTUAL(inode)) ++ return; ++ /* ++ * Here qmblk is (re-)initialized for all ancestors. ++ * This is not a very efficient procedure, but it guarantees that ++ * the quota tree is consistent (that is, the inode doesn't have two ++ * ancestors with different qmblk). ++ */ ++ if (!vzquota_dparents_check_attach(inode)) { ++ pinode = vzquota_dparents_check_actual(inode); ++ if (pinode != NULL) { ++ vzquota_dbranch_actualize(pinode, inode); ++ goto start; ++ } ++ qmblk = vzquota_dparents_check_same(inode); ++ } else ++ qmblk = VZ_QUOTA_BAD; ++ ++ if (vzquota_inode_qmblk_set(inode, qmblk, qlnk)) ++ goto start; ++ set_qlnk_origin(INODE_QLNK(inode), VZ_QUOTAO_DTREE); ++} ++ ++static void vzquota_det_qmblk_recalc(struct inode *inode, ++ struct vz_quota_ilink *qlnk) ++{ ++ struct inode *parent; ++ struct vz_quota_master *qmblk; ++ char *msg; ++ int cnt; ++ time_t timeout; ++ ++ cnt = 0; ++ parent = NULL; ++start: ++ /* ++ * qmblk of detached inodes shouldn't be considered as not actual. ++ * They are not in any dentry tree, so quota on/off shouldn't affect ++ * them. ++ */ ++ if (!vzquota_qlnk_is_empty(INODE_QLNK(inode))) ++ return; ++ ++ timeout = 3; ++ qmblk = __VZ_QUOTA_NOQUOTA(inode->i_sb); ++ /* ++ * Scenario: ++ * open ++ * unlink ++ * quotaon ++ * generic_delete_inode ++ * ++ * This is the first time vzquota sees inode. inode is outside of ++ * vzquota area of interest, otherwise quotaon would have got -EBUSY ++ * due to shrink_dcache_parent(). ++ * inode is almost completely destroyed, so don't intervene. ++ * ++ * dev@: ++ * However, there is a small race here... ++ * dput() first removes itself from all the lists, ++ * so shrink_dcache_parent() can succeed while dentry_iput is not ++ * done yet. ++ */ ++ if (inode->i_state & I_FREEING) ++ goto set; ++ ++ msg = "detached inode not in creation"; ++ if (inode->i_op != VZ_QUOTA_EMPTY_IOPS) ++ goto fail; ++ qmblk = VZ_QUOTA_BAD; ++ msg = "unexpected creation context"; ++ if (!vzquota_cur_qmblk_check()) ++ goto fail; ++ timeout = 0; ++ parent = vzquota_cur_qmblk_fetch(); ++ msg = "uninitialized parent"; ++ if (vzquota_qlnk_is_empty(INODE_QLNK(parent))) ++ goto fail; ++ msg = "parent not in tree"; ++ if (list_empty(&parent->i_dentry)) ++ goto fail; ++ msg = "parent has 0 refcount"; ++ if (!atomic_read(&parent->i_count)) ++ goto fail; ++ msg = "parent has different sb"; ++ if (parent->i_sb != inode->i_sb) ++ goto fail; ++ if (!VZ_QUOTA_IS_ACTUAL(parent)) { ++ vzquota_dbranch_actualize(parent, inode); ++ goto start; ++ } ++ ++ qmblk = INODE_QLNK(parent)->qmblk; ++set: ++ if (vzquota_inode_qmblk_set(inode, qmblk, qlnk)) ++ goto start; ++ set_qlnk_origin(INODE_QLNK(inode), VZ_QUOTAO_DET); ++ return; ++ ++fail: ++ { ++ struct timeval tv, tvo; ++ do_gettimeofday(&tv); ++ memcpy(&tvo, __VZ_QUOTA_TSTAMP(inode->i_sb), sizeof(tvo)); ++ tv.tv_sec -= tvo.tv_sec; ++ if (tv.tv_usec < tvo.tv_usec) { ++ tv.tv_sec--; ++ tv.tv_usec += USEC_PER_SEC - tvo.tv_usec; ++ } else ++ tv.tv_usec -= tvo.tv_usec; ++ if (tv.tv_sec < timeout) ++ goto set; ++ printk(KERN_ERR "VZDQ: %s, orig {%u, %u}," ++ " dev %s, inode %lu, fs %s\n", ++ msg, ++ INODE_QLNK(inode)->origin[0], ++ INODE_QLNK(inode)->origin[1], ++ inode->i_sb->s_id, inode->i_ino, ++ inode->i_sb->s_type->name); ++ printk(KERN_ERR "i_count %u, ", atomic_read(&inode->i_count)); ++ printk(KERN_ERR "i_mode %o, ", inode->i_mode); ++ printk(KERN_ERR "i_state %lx, ", inode->i_state); ++ printk(KERN_ERR "i_flags %x\n", inode->i_flags); ++ printk(KERN_ERR "i_op %p, vfs_empty_iops %p, " ++ "i_fop %p, i_mapping %p\n", ++ inode->i_op, &vfs_empty_iops, ++ inode->i_fop, inode->i_mapping); ++ if (!cnt++) { ++ printk(KERN_ERR "current %d (%s), VE %d," ++ " time %ld.%06ld\n", ++ current->pid, current->comm, ++ VEID(get_exec_env()), ++ tv.tv_sec, (long)tv.tv_usec); ++ dump_stack(); ++ } ++ if (parent != NULL) ++ printk(KERN_ERR "VZDQ: parent of %lu is %lu\n", ++ inode->i_ino, parent->i_ino); ++ } ++ goto set; ++} ++ ++static void vzquota_inode_qmblk_recalc(struct inode *inode, ++ struct vz_quota_ilink *qlnk) ++{ ++ spin_lock(&dcache_lock); ++ if (!list_empty(&inode->i_dentry)) ++ vzquota_dtree_qmblk_recalc(inode, qlnk); ++ else ++ vzquota_det_qmblk_recalc(inode, qlnk); ++ spin_unlock(&dcache_lock); ++} ++ ++/** ++ * vzquota_inode_qmblk - obtain inode's qmblk ++ * ++ * Returns qmblk with refcounter taken, %NULL if not under ++ * VZ quota or %VZ_QUOTA_BAD. ++ * ++ * FIXME: This function should be removed when vzquota_find_qmblk / ++ * get_quota_root / vzquota_dstat code is cleaned up. ++ */ ++struct vz_quota_master *vzquota_inode_qmblk(struct inode *inode) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_ilink qlnk; ++ ++ might_sleep(); ++ ++ if (inode->i_sb->dq_op != &vz_quota_operations) ++ return NULL; ++#if defined(VZ_QUOTA_UNLOAD) ++#error Make sure qmblk does not disappear ++#endif ++ ++ vzquota_qlnk_init(&qlnk); ++ inode_qmblk_lock(inode->i_sb); ++ __vzquota_inode_init(inode, VZ_QUOTAO_INICAL); ++ ++ if (vzquota_qlnk_is_empty(INODE_QLNK(inode)) || ++ !VZ_QUOTA_IS_ACTUAL(inode)) ++ vzquota_inode_qmblk_recalc(inode, &qlnk); ++ ++ qmblk = INODE_QLNK(inode)->qmblk; ++ if (qmblk != VZ_QUOTA_BAD) { ++ if (!VZ_QUOTA_IS_NOQUOTA(qmblk, inode->i_sb)) ++ qmblk_get(qmblk); ++ else ++ qmblk = NULL; ++ } ++ ++ inode_qmblk_unlock(inode->i_sb); ++ vzquota_qlnk_destroy(&qlnk); ++ return qmblk; ++} ++ ++/** ++ * vzquota_find_qmblk - helper to emulate quota on virtual filesystems ++ * ++ * This function finds a quota master block corresponding to the root of ++ * a virtual filesystem. ++ * Returns a quota master block with reference taken, or %NULL if not under ++ * quota, or %VZ_QUOTA_BAD if quota inconsistency is found (and all allocation ++ * operations will fail). ++ * ++ * Note: this function uses vzquota_inode_qmblk(). ++ * The latter is a rather confusing function: it returns qmblk that used to be ++ * on the inode some time ago (without guarantee that it still has any ++ * relations to the inode). So, vzquota_find_qmblk() leaves it up to the ++ * caller to think whether the inode could have changed its qmblk and what to ++ * do in that case. ++ * Currently, the callers appear to not care :( ++ */ ++struct vz_quota_master *vzquota_find_qmblk(struct super_block *sb) ++{ ++ struct inode *qrinode; ++ struct vz_quota_master *qmblk; ++ ++ qmblk = NULL; ++ qrinode = NULL; ++ if (sb->s_op->get_quota_root != NULL) ++ qrinode = sb->s_op->get_quota_root(sb); ++ if (qrinode != NULL) ++ qmblk = vzquota_inode_qmblk(qrinode); ++ return qmblk; ++} ++ ++/* ---------------------------------------------------------------------- ++ * ++ * Calls from quota operations ++ * ++ * --------------------------------------------------------------------- */ ++ ++/** ++ * vzquota_inode_init_call - call from DQUOT_INIT ++ */ ++void vzquota_inode_init_call(struct inode *inode) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_datast data; ++ ++ /* initializes inode's quota inside */ ++ qmblk = vzquota_inode_data(inode, &data); ++ if (qmblk != NULL && qmblk != VZ_QUOTA_BAD) ++ vzquota_data_unlock(inode, &data); ++ ++ /* ++ * The check is needed for repeated new_inode() calls from a single ++ * ext3 call like create or mkdir in case of -ENOSPC. ++ */ ++ spin_lock(&dcache_lock); ++ if (!list_empty(&inode->i_dentry)) ++ vzquota_cur_qmblk_set(inode); ++ spin_unlock(&dcache_lock); ++} ++ ++/** ++ * vzquota_inode_drop_call - call from DQUOT_DROP ++ */ ++void vzquota_inode_drop_call(struct inode *inode) ++{ ++ vzquota_inode_drop(inode); ++} ++ ++/** ++ * vzquota_inode_data - initialize (if nec.) and lock inode quota ptrs ++ * @inode: the inode ++ * @data: storage space ++ * ++ * Returns: qmblk is NULL or VZ_QUOTA_BAD or actualized qmblk. ++ * On return if qmblk is neither NULL nor VZ_QUOTA_BAD: ++ * qmblk in inode's qlnk is the same as returned, ++ * ugid pointers inside inode's qlnk are valid, ++ * some locks are taken (and should be released by vzquota_data_unlock). ++ * If qmblk is NULL or VZ_QUOTA_BAD, locks are NOT taken. ++ */ ++struct vz_quota_master *vzquota_inode_data(struct inode *inode, ++ struct vz_quota_datast *data) ++{ ++ struct vz_quota_master *qmblk; ++ ++ might_sleep(); ++ ++ vzquota_qlnk_init(&data->qlnk); ++ inode_qmblk_lock(inode->i_sb); ++ if (unlikely(inode->i_flags & S_NOQUOTA)) { ++ inode_qmblk_unlock(inode->i_sb); ++ return NULL; ++ } ++ __vzquota_inode_init(inode, VZ_QUOTAO_INICAL); ++ ++ if (vzquota_qlnk_is_empty(INODE_QLNK(inode)) || ++ !VZ_QUOTA_IS_ACTUAL(inode)) ++ vzquota_inode_qmblk_recalc(inode, &data->qlnk); ++ ++ qmblk = INODE_QLNK(inode)->qmblk; ++ if (qmblk != VZ_QUOTA_BAD) { ++ if (!VZ_QUOTA_IS_NOQUOTA(qmblk, inode->i_sb)) { ++ /* ++ * Note that in the current implementation, ++ * inode_qmblk_lock can theoretically be dropped here. ++ * This place is serialized with quota_off because ++ * quota_off fails when there are extra dentry ++ * references and syncs inodes before removing quota ++ * information from them. ++ * However, quota usage information should stop being ++ * updated immediately after vzquota_off. ++ */ ++ qmblk_data_write_lock(qmblk); ++ } else { ++ inode_qmblk_unlock(inode->i_sb); ++ qmblk = NULL; ++ } ++ } else { ++ inode_qmblk_unlock(inode->i_sb); ++ } ++ return qmblk; ++} ++ ++void vzquota_data_unlock(struct inode *inode, ++ struct vz_quota_datast *data) ++{ ++ qmblk_data_write_unlock(INODE_QLNK(inode)->qmblk); ++ inode_qmblk_unlock(inode->i_sb); ++ vzquota_qlnk_destroy(&data->qlnk); ++} ++ ++#if defined(CONFIG_VZ_QUOTA_UGID) ++/** ++ * vzquota_inode_transfer_call - call from vzquota_transfer ++ */ ++int vzquota_inode_transfer_call(struct inode *inode, struct iattr *iattr) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_datast data; ++ struct vz_quota_ilink qlnew; ++ int mask; ++ int ret; ++ ++ might_sleep(); ++ vzquota_qlnk_init(&qlnew); ++start: ++ qmblk = vzquota_inode_data(inode, &data); ++ ret = NO_QUOTA; ++ if (qmblk == VZ_QUOTA_BAD) ++ goto out_destr; ++ ret = QUOTA_OK; ++ if (qmblk == NULL) ++ goto out_destr; ++ qmblk_get(qmblk); ++ ++ ret = QUOTA_OK; ++ if (!(qmblk->dq_flags & VZDQUG_ON)) ++ /* no ugid quotas */ ++ goto out_unlock; ++ ++ mask = 0; ++ if ((iattr->ia_valid & ATTR_UID) && iattr->ia_uid != inode->i_uid) ++ mask |= 1 << USRQUOTA; ++ if ((iattr->ia_valid & ATTR_GID) && iattr->ia_gid != inode->i_gid) ++ mask |= 1 << GRPQUOTA; ++ while (1) { ++ if (vzquota_qlnk_is_empty(&qlnew) && ++ vzquota_qlnk_fill_attr(&qlnew, inode, iattr, mask, qmblk)) ++ break; ++ if (qlnew.qmblk == INODE_QLNK(inode)->qmblk && ++ qlnew.qmblk == qmblk) ++ goto finish; ++ if (vzquota_qlnk_reinit_attr(&qlnew, inode, qmblk)) ++ break; ++ } ++ ++ /* prepare for restart */ ++ vzquota_data_unlock(inode, &data); ++ qmblk_put(qmblk); ++ goto start; ++ ++finish: ++ /* all references obtained successfully */ ++ ret = vzquota_transfer_usage(inode, mask, &qlnew); ++ if (!ret) { ++ vzquota_qlnk_swap(&qlnew, INODE_QLNK(inode)); ++ set_qlnk_origin(INODE_QLNK(inode), VZ_QUOTAO_TRANS); ++ } ++out_unlock: ++ vzquota_data_unlock(inode, &data); ++ qmblk_put(qmblk); ++out_destr: ++ vzquota_qlnk_destroy(&qlnew); ++ return ret; ++} ++#endif ++ ++int vzquota_rename_check(struct inode *inode, ++ struct inode *old_dir, struct inode *new_dir) ++{ ++ struct vz_quota_master *qmblk; ++ struct vz_quota_ilink qlnk1, qlnk2, qlnk3; ++ int c, ret; ++ ++ if (inode->i_sb != old_dir->i_sb || inode->i_sb != new_dir->i_sb) ++ return -1; ++ ++ might_sleep(); ++ ++ vzquota_qlnk_init(&qlnk1); ++ vzquota_qlnk_init(&qlnk2); ++ vzquota_qlnk_init(&qlnk3); ++ inode_qmblk_lock(inode->i_sb); ++ __vzquota_inode_init(inode, VZ_QUOTAO_INICAL); ++ __vzquota_inode_init(old_dir, VZ_QUOTAO_INICAL); ++ __vzquota_inode_init(new_dir, VZ_QUOTAO_INICAL); ++ ++ do { ++ c = 0; ++ if (vzquota_qlnk_is_empty(INODE_QLNK(inode)) || ++ !VZ_QUOTA_IS_ACTUAL(inode)) { ++ vzquota_inode_qmblk_recalc(inode, &qlnk1); ++ c++; ++ } ++ if (vzquota_qlnk_is_empty(INODE_QLNK(new_dir)) || ++ !VZ_QUOTA_IS_ACTUAL(new_dir)) { ++ vzquota_inode_qmblk_recalc(new_dir, &qlnk2); ++ c++; ++ } ++ } while (c); ++ ++ ret = 0; ++ qmblk = INODE_QLNK(inode)->qmblk; ++ if (qmblk != INODE_QLNK(new_dir)->qmblk) { ++ ret = -1; ++ while (vzquota_qlnk_is_empty(INODE_QLNK(old_dir)) || ++ !VZ_QUOTA_IS_ACTUAL(old_dir)) ++ vzquota_inode_qmblk_recalc(old_dir, &qlnk3); ++ if (qmblk != VZ_QUOTA_BAD && ++ !VZ_QUOTA_IS_NOQUOTA(qmblk, inode->i_sb) && ++ qmblk->dq_root_dentry->d_inode == inode && ++ VZ_QUOTA_IS_NOQUOTA(INODE_QLNK(new_dir)->qmblk, ++ inode->i_sb) && ++ VZ_QUOTA_IS_NOQUOTA(INODE_QLNK(old_dir)->qmblk, ++ inode->i_sb)) ++ /* quota root rename is allowed */ ++ ret = 0; ++ } ++ ++ inode_qmblk_unlock(inode->i_sb); ++ vzquota_qlnk_destroy(&qlnk3); ++ vzquota_qlnk_destroy(&qlnk2); ++ vzquota_qlnk_destroy(&qlnk1); ++ return ret; ++} ++ ++/* ++ * Scan parent subdirs and find busy dentries names/path ++ * @parent: parent dentry ++ * @buf: buffer to store path. ++ */ ++static void vzdquota_read_busy_dentries(struct dentry * parent, ++ struct vfsmount *vfsmnt, char *buf, int buflen) ++{ ++ struct dentry *this_parent = parent; ++ struct list_head *next; ++ char *res, *end, *start; ++ struct vfsmount *rootmnt; ++ struct dentry *root; ++ int len; ++ ++ if (!buf || buflen <= 0) ++ return; ++ ++ /* From d_path() ... */ ++ read_lock(¤t->fs->lock); ++ rootmnt = mntget(current->fs->rootmnt); ++ root = dget(current->fs->root); ++ read_unlock(¤t->fs->lock); ++ ++ spin_lock(&dcache_lock); ++ ++ end = buf + buflen; ++ start = buf; ++repeat: ++ next = this_parent->d_subdirs.next; ++resume: ++ while (next != &this_parent->d_subdirs) { ++ struct list_head *tmp = next; ++ struct dentry *dentry; ++ int subdirs; ++ ++ dentry = list_entry(tmp, struct dentry, d_u.d_child); ++ next = tmp->next; ++ subdirs = !list_empty(&dentry->d_subdirs); ++ ++ if (atomic_read(&dentry->d_count) && !subdirs) { ++ if (!buflen) ++ goto out; ++ /* ++ * Note: __d_path will store filename at the ++ * end of buf. ++ */ ++ res = __d_path(dentry, vfsmnt, root, rootmnt, ++ buf, buflen); ++ /* Exit if name is too long */ ++ if (IS_ERR(res)) ++ goto out; ++ ++ /* ++ * Move the string obtained by __d_path, ++ * behind the last dentry path in buf. ++ */ ++ len = end - res; ++ BUG_ON(len <= 0); ++ ++ memmove(buf, res, len); ++ ++ /* Trick: replace \0 by \n */ ++ if (buf != start) ++ *(char *)(buf - 1) = '\n'; ++ ++ buf += len; ++ buflen -= len; ++ } ++ ++ /* ++ * Descend a level if the d_subdirs list is non-empty. ++ */ ++ if (subdirs) { ++ this_parent = dentry; ++ goto repeat; ++ } ++ } ++ /* ++ * All done at this level ... ascend and resume the search. ++ */ ++ if (this_parent != parent) { ++ next = this_parent->d_u.d_child.next; ++ this_parent = this_parent->d_parent; ++ goto resume; ++ } ++out: ++ /* From d_path() ... */ ++ spin_unlock(&dcache_lock); ++ dput(root); ++ mntput(rootmnt); ++} ++ ++/* ---------------------------------------------------------------------- ++ * ++ * qmblk-related parts of on/off operations ++ * ++ * --------------------------------------------------------------------- */ ++ ++/** ++ * vzquota_check_dtree - check dentry tree if quota on/off is allowed ++ * ++ * This function doesn't allow quota to be turned on/off if some dentries in ++ * the tree have external references. ++ * In addition to technical reasons, it enforces user-space correctness: ++ * current usage (taken from or reported to the user space) can be meaningful ++ * and accurate only if the tree is not being modified. ++ * Side effect: additional vfsmount structures referencing the tree (bind ++ * mounts of tree nodes to some other places) are not allowed at on/off time. ++ * ++ * Store busy dentries path to the buf (if passed) in case of vzquota_off ++ * ioctl fail. ++ */ ++int vzquota_check_dtree(struct vz_quota_master *qmblk, int off, ++ char *buf, int buflen) ++{ ++ struct dentry *dentry; ++ int err, count; ++ ++ err = -EBUSY; ++ dentry = qmblk->dq_root_dentry; ++ ++ if (d_unhashed(dentry) && dentry != dentry->d_sb->s_root) ++ goto unhashed; ++ ++ /* attempt to shrink */ ++ if (!list_empty(&dentry->d_subdirs)) { ++ spin_unlock(&dcache_lock); ++ inode_qmblk_unlock(dentry->d_sb); ++ shrink_dcache_parent(dentry); ++ inode_qmblk_lock(dentry->d_sb); ++ spin_lock(&dcache_lock); ++ if (!list_empty(&dentry->d_subdirs)) { ++ spin_unlock(&dcache_lock); ++ vzdquota_read_busy_dentries(dentry, qmblk->dq_root_mnt, ++ buf, buflen); ++ spin_lock(&dcache_lock); ++ goto out; ++ } ++ ++ count = 1; ++ if (dentry == dentry->d_sb->s_root) ++ count += 2; /* sb and mnt refs */ ++ if (atomic_read(&dentry->d_count) < count) { ++ printk(KERN_ERR "%s: too small count %d vs %d.\n", ++ __FUNCTION__, ++ atomic_read(&dentry->d_count), count); ++ goto out; ++ } ++ if (atomic_read(&dentry->d_count) > count) ++ goto out; ++ } ++ ++ err = 0; ++out: ++ return err; ++ ++unhashed: ++ /* ++ * Quota root is removed. ++ * Allow to turn quota off, but not on. ++ */ ++ if (off) ++ err = 0; ++ goto out; ++} ++ ++int vzquota_on_qmblk(struct super_block *sb, struct inode *inode, ++ struct vz_quota_master *qmblk, char __user *ubuf) ++{ ++ struct vz_quota_ilink qlnk; ++ struct vz_quota_master *qold, *qnew; ++ int err; ++ char *buf; ++ ++ buf = (ubuf != NULL) ? (char *)__get_free_page(GFP_KERNEL) : NULL; ++ ++ might_sleep(); ++ ++ qold = NULL; ++ qnew = vzquota_alloc_fake(); ++ if (qnew == NULL) { ++ free_page((unsigned long)buf); ++ return -ENOMEM; ++ } ++ ++ vzquota_qlnk_init(&qlnk); ++ inode_qmblk_lock(sb); ++ __vzquota_inode_init(inode, VZ_QUOTAO_INICAL); ++ ++ spin_lock(&dcache_lock); ++ while (1) { ++ err = vzquota_check_dtree(qmblk, 0, buf, PAGE_SIZE); ++ if (err) ++ break; ++ if (!vzquota_inode_qmblk_set(inode, qmblk, &qlnk)) ++ break; ++ } ++ set_qlnk_origin(INODE_QLNK(inode), VZ_QUOTAO_ON); ++ spin_unlock(&dcache_lock); ++ ++ if (!err) { ++ qold = __VZ_QUOTA_NOQUOTA(sb); ++ qold->dq_flags |= VZDQ_NOACT; ++ __VZ_QUOTA_NOQUOTA(sb) = qnew; ++ } ++ ++ inode_qmblk_unlock(sb); ++ vzquota_qlnk_destroy(&qlnk); ++ if (qold != NULL) ++ qmblk_put(qold); ++ ++ if (buf) { ++ (void)copy_to_user(ubuf, buf, PAGE_SIZE); ++ free_page((unsigned long)buf); ++ } ++ return err; ++} ++ ++int vzquota_off_qmblk(struct super_block *sb, struct vz_quota_master *qmblk, ++ char __user *ubuf, int force) ++{ ++ int ret; ++ char *buf; ++ ++ buf = (ubuf != NULL) ? (char *)__get_free_page(GFP_KERNEL) : NULL; ++ ++ ret = 0; ++ inode_qmblk_lock(sb); ++ ++ spin_lock(&dcache_lock); ++ if (vzquota_check_dtree(qmblk, 1, buf, PAGE_SIZE) && !force) ++ ret = -EBUSY; ++ spin_unlock(&dcache_lock); ++ ++ if (!ret) ++ qmblk->dq_flags |= VZDQ_NOACT | VZDQ_NOQUOT; ++ inode_qmblk_unlock(sb); ++ ++ if (buf) { ++ (void)copy_to_user(ubuf, buf, PAGE_SIZE); ++ free_page((unsigned long)buf); ++ } ++ return ret; ++} ++ ++ ++/* ---------------------------------------------------------------------- ++ * ++ * External interfaces ++ * ++ * ---------------------------------------------------------------------*/ ++ ++static int vzquota_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int err; ++ ++ switch (cmd) { ++ case VZCTL_QUOTA_NEW_CTL: { ++ struct vzctl_quotactl qb; ++ ++ err = -EFAULT; ++ if (copy_from_user(&qb, (void __user *)arg, sizeof(qb))) ++ break; ++ err = do_vzquotactl(qb.cmd, qb.quota_id, ++ qb.qstat, qb.ve_root, 0); ++ break; ++ } ++#ifdef CONFIG_VZ_QUOTA_UGID ++ case VZCTL_QUOTA_UGID_CTL: { ++ struct vzctl_quotaugidctl qub; ++ ++ err = -EFAULT; ++ if (copy_from_user(&qub, (void __user *)arg, sizeof(qub))) ++ break; ++ err = do_vzquotaugidctl(qub.cmd, qub.quota_id, ++ qub.ugid_index, qub.ugid_size, qub.addr, 0); ++ break; ++ } ++#endif ++ default: ++ err = -ENOTTY; ++ } ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++static int compat_vzquota_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int err; ++ ++ switch (cmd) { ++ case VZCTL_COMPAT_QUOTA_CTL: { ++ struct compat_vzctl_quotactl cs; ++ ++ err = -EFAULT; ++ if (copy_from_user(&cs, (void *)arg, sizeof(cs))) ++ break; ++ err = do_vzquotactl(cs.cmd, cs.quota_id, ++ compat_ptr(cs.qstat), ++ compat_ptr(cs.ve_root), 1); ++ break; ++ } ++#ifdef CONFIG_VZ_QUOTA_UGID ++ case VZCTL_COMPAT_QUOTA_UGID_CTL: { ++ struct compat_vzctl_quotaugidctl cs; ++ ++ err = -EFAULT; ++ if (copy_from_user(&cs, (void *)arg, sizeof(cs))) ++ break; ++ ++ err = do_vzquotaugidctl(cs.cmd, cs.quota_id, cs.ugid_index, ++ cs.ugid_size, compat_ptr(cs.addr), 1); ++ break; ++ } ++#endif ++ default: ++ err = -ENOIOCTLCMD; ++ } ++ return err; ++} ++#endif ++ ++static struct vzioctlinfo vzdqcalls = { ++ .type = VZDQCTLTYPE, ++ .ioctl = vzquota_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = compat_vzquota_ioctl, ++#endif ++ .owner = THIS_MODULE, ++}; ++ ++/** ++ * vzquota_dstat - get quota usage info for virtual superblock ++ */ ++static int vzquota_dstat(struct super_block *super, struct dq_stat *qstat) ++{ ++ struct vz_quota_master *qmblk; ++ ++ qmblk = vzquota_find_qmblk(super); ++ if (qmblk == NULL) ++ return -ENOENT; ++ if (qmblk == VZ_QUOTA_BAD) { ++ memset(qstat, 0, sizeof(*qstat)); ++ return 0; ++ } ++ ++ qmblk_data_read_lock(qmblk); ++ memcpy(qstat, &qmblk->dq_stat, sizeof(*qstat)); ++ qmblk_data_read_unlock(qmblk); ++ qmblk_put(qmblk); ++ return 0; ++} ++ ++ ++/* ---------------------------------------------------------------------- ++ * ++ * Init/exit helpers ++ * ++ * ---------------------------------------------------------------------*/ ++ ++static int vzquota_cache_init(void) ++{ ++ int i; ++ ++ vzquota_cachep = kmem_cache_create("vz_quota_master", ++ sizeof(struct vz_quota_master), ++ 0, SLAB_HWCACHE_ALIGN, NULL); ++ if (vzquota_cachep == NULL) { ++ printk(KERN_ERR "Cannot create VZ_QUOTA SLAB cache\n"); ++ goto nomem2; ++ } ++ for (i = 0; i < VZ_QUOTA_HASH_SIZE; i++) ++ INIT_LIST_HEAD(&vzquota_hash_table[i]); ++ ++ return 0; ++ ++nomem2: ++ return -ENOMEM; ++} ++ ++static void vzquota_cache_release(void) ++{ ++ int i; ++ ++ /* sanity check */ ++ for (i = 0; i < VZ_QUOTA_HASH_SIZE; i++) ++ if (!list_empty(&vzquota_hash_table[i])) ++ BUG(); ++ ++ /* release caches */ ++ kmem_cache_destroy(vzquota_cachep); ++ vzquota_cachep = NULL; ++} ++ ++static int quota_notifier_call(struct vnotifier_block *self, ++ unsigned long n, void *data, int err) ++{ ++ struct virt_info_quota *viq; ++ struct super_block *sb; ++ ++ viq = (struct virt_info_quota *)data; ++ switch (n) { ++ case VIRTINFO_QUOTA_ON: ++ err = NOTIFY_BAD; ++ if (!try_module_get(THIS_MODULE)) ++ break; ++ sb = viq->super; ++ memset(&sb->s_dquot.info, 0, sizeof(sb->s_dquot.info)); ++ INIT_LIST_HEAD(&sb->s_dquot.info[USRQUOTA].dqi_dirty_list); ++ INIT_LIST_HEAD(&sb->s_dquot.info[GRPQUOTA].dqi_dirty_list); ++ err = NOTIFY_OK; ++ break; ++ case VIRTINFO_QUOTA_OFF: ++ module_put(THIS_MODULE); ++ err = NOTIFY_OK; ++ break; ++ case VIRTINFO_QUOTA_GETSTAT: ++ err = NOTIFY_BAD; ++ if (vzquota_dstat(viq->super, viq->qstat)) ++ break; ++ err = NOTIFY_OK; ++ break; ++ case VIRTINFO_QUOTA_DISABLE: ++ err = NOTIFY_OK; ++ vzquota_inode_off((struct inode *)data); ++ break; ++ } ++ return err; ++} ++ ++struct vnotifier_block quota_notifier_block = { ++ .notifier_call = quota_notifier_call, ++ .priority = INT_MAX, ++}; ++ ++/* ---------------------------------------------------------------------- ++ * ++ * Init/exit procedures ++ * ++ * ---------------------------------------------------------------------*/ ++ ++static int __init vzquota_init(void) ++{ ++ int err; ++ ++ if ((err = vzquota_cache_init()) != 0) ++ goto out_cache; ++ ++ if ((err = vzquota_proc_init()) != 0) ++ goto out_proc; ++ ++#ifdef CONFIG_VZ_QUOTA_UGID ++ if ((err = vzquota_ugid_init()) != 0) ++ goto out_ugid; ++#endif ++ ++ init_MUTEX(&vz_quota_sem); ++ vzioctl_register(&vzdqcalls); ++ virtinfo_notifier_register(VITYPE_QUOTA, "a_notifier_block); ++#if defined(CONFIG_VZ_QUOTA_UGID) && defined(CONFIG_PROC_FS) ++ vzaquota_init(); ++#endif ++ ++ return 0; ++ ++#ifdef CONFIG_VZ_QUOTA_UGID ++out_ugid: ++ vzquota_proc_release(); ++#endif ++out_proc: ++ vzquota_cache_release(); ++out_cache: ++ return err; ++} ++ ++#if defined(VZ_QUOTA_UNLOAD) ++static void __exit vzquota_release(void) ++{ ++ virtinfo_notifier_unregister(VITYPE_QUOTA, "a_notifier_block); ++ vzioctl_unregister(&vzdqcalls); ++#ifdef CONFIG_VZ_QUOTA_UGID ++#ifdef CONFIG_PROC_FS ++ vzaquota_fini(); ++#endif ++ vzquota_ugid_release(); ++#endif ++ vzquota_proc_release(); ++ vzquota_cache_release(); ++} ++#endif ++ ++MODULE_AUTHOR("SWsoft "); ++MODULE_DESCRIPTION("Virtuozzo Disk Quota"); ++MODULE_LICENSE("GPL v2"); ++ ++module_init(vzquota_init) ++#if defined(VZ_QUOTA_UNLOAD) ++module_exit(vzquota_release) ++#endif +Index: kernel/grsecurity/Kconfig +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/grsecurity/Kconfig 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,129 @@ ++# ++# grecurity configuration ++# ++ ++menu "Grsecurity" ++ ++config GRKERNSEC ++ bool "Grsecurity" ++ help ++ If you say Y here, you will be able to configure many features ++ that will enhance the security of your system. It is highly ++ recommended that you say Y here and read through the help ++ for each option so that you fully understand the features and ++ can evaluate their usefulness for your machine. ++ ++menu "Executable Protections" ++depends on GRKERNSEC ++ ++config GRKERNSEC_TPE ++ bool "Trusted Path Execution (TPE)" ++ help ++ If you say Y here, you will be able to choose a gid to add to the ++ supplementary groups of users you want to mark as "untrusted." ++ These users will not be able to execute any files that are not in ++ root-owned directories writable only by root. If the sysctl option ++ is enabled, a sysctl option with name "tpe" is created. ++ ++config GRKERNSEC_TPE_ALL ++ bool "Partially restrict non-root users" ++ depends on GRKERNSEC_TPE ++ help ++ If you say Y here, All non-root users other than the ones in the ++ group specified in the main TPE option will only be allowed to ++ execute files in directories they own that are not group or ++ world-writable, or in directories owned by root and writable only by ++ root. If the sysctl option is enabled, a sysctl option with name ++ "tpe_restrict_all" is created. ++ ++config GRKERNSEC_TPE_INVERT ++ bool "Invert GID option" ++ depends on GRKERNSEC_TPE ++ help ++ If you say Y here, the group you specify in the TPE configuration will ++ decide what group TPE restrictions will be *disabled* for. This ++ option is useful if you want TPE restrictions to be applied to most ++ users on the system. ++ ++config GRKERNSEC_TPE_GID ++ int "GID for untrusted users" ++ depends on GRKERNSEC_TPE && !GRKERNSEC_TPE_INVERT ++ default 1005 ++ help ++ If you have selected the "Invert GID option" above, setting this ++ GID determines what group TPE restrictions will be *disabled* for. ++ If you have not selected the "Invert GID option" above, setting this ++ GID determines what group TPE restrictions will be *enabled* for. ++ If the sysctl option is enabled, a sysctl option with name "tpe_gid" ++ is created. ++ ++config GRKERNSEC_TPE_GID ++ int "GID for trusted users" ++ depends on GRKERNSEC_TPE && GRKERNSEC_TPE_INVERT ++ default 1005 ++ help ++ If you have selected the "Invert GID option" above, setting this ++ GID determines what group TPE restrictions will be *disabled* for. ++ If you have not selected the "Invert GID option" above, setting this ++ GID determines what group TPE restrictions will be *enabled* for. ++ If the sysctl option is enabled, a sysctl option with name "tpe_gid" ++ is created. ++ ++endmenu ++menu "Sysctl support" ++depends on GRKERNSEC && SYSCTL ++ ++config GRKERNSEC_SYSCTL ++ bool "Sysctl support" ++ help ++ If you say Y here, you will be able to change the options that ++ grsecurity runs with at bootup, without having to recompile your ++ kernel. You can echo values to files in /proc/sys/kernel/grsecurity ++ to enable (1) or disable (0) various features. All the sysctl entries ++ are mutable until the "grsec_lock" entry is set to a non-zero value. ++ All features enabled in the kernel configuration are disabled at boot ++ if you do not say Y to the "Turn on features by default" option. ++ All options should be set at startup, and the grsec_lock entry should ++ be set to a non-zero value after all the options are set. ++ *THIS IS EXTREMELY IMPORTANT* ++ ++config GRKERNSEC_SYSCTL_ON ++ bool "Turn on features by default" ++ depends on GRKERNSEC_SYSCTL ++ help ++ If you say Y here, instead of having all features enabled in the ++ kernel configuration disabled at boot time, the features will be ++ enabled at boot time. It is recommended you say Y here unless ++ there is some reason you would want all sysctl-tunable features to ++ be disabled by default. As mentioned elsewhere, it is important ++ to enable the grsec_lock entry once you have finished modifying ++ the sysctl entries. ++ ++endmenu ++ ++menu "Logging Options" ++depends on GRKERNSEC ++ ++config GRKERNSEC_FLOODTIME ++ int "Seconds in between log messages (minimum)" ++ default 10 ++ help ++ This option allows you to enforce the number of seconds between ++ grsecurity log messages. The default should be suitable for most ++ people, however, if you choose to change it, choose a value small enough ++ to allow informative logs to be produced, but large enough to ++ prevent flooding. ++ ++config GRKERNSEC_FLOODBURST ++ int "Number of messages in a burst (maximum)" ++ default 4 ++ help ++ This option allows you to choose the maximum number of messages allowed ++ within the flood time interval you chose in a separate option. The ++ default should be suitable for most people, however if you find that ++ many of your logs are being interpreted as flooding, you may want to ++ raise this value. ++ ++endmenu ++ ++endmenu +Index: kernel/grsecurity/Makefile +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/grsecurity/Makefile 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,15 @@ ++# grsecurity's ACL system was originally written in 2001 by Michael Dalton ++# during 2001-2005 it has been completely redesigned by Brad Spengler ++# into an RBAC system ++# ++# All code in this directory and various hooks inserted throughout the kernel ++# are copyright Brad Spengler, and released under the GPL v2 or higher ++ ++obj-y = grsec_tpe.o grsec_sysctl.o ++ ++obj-$(CONFIG_GRKERNSEC) += grsec_init.o gracl.o grsec_log.o ++ ++ifndef CONFIG_GRKERNSEC ++obj-y += grsec_disabled.o ++endif ++ +Index: kernel/grsecurity/gracl.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/grsecurity/gracl.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,137 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++extern char *gr_shared_page[4]; ++ ++static char * ++gen_full_path(struct dentry *dentry, struct vfsmount *vfsmnt, ++ struct dentry *root, struct vfsmount *rootmnt, char *buf, int buflen) ++{ ++ char *end = buf + buflen; ++ char *retval; ++ int namelen = 0; ++ ++ *--end = '\0'; ++ ++ retval = end - 1; ++ *retval = '/'; ++ ++ if (dentry == root && vfsmnt == rootmnt) ++ return retval; ++ if (dentry != vfsmnt->mnt_root && !IS_ROOT(dentry)) { ++ namelen = strlen(dentry->d_name.name); ++ buflen -= namelen; ++ if (buflen < 2) ++ goto err; ++ if (dentry->d_parent != root || vfsmnt != rootmnt) ++ buflen--; ++ } ++ ++ retval = __d_path(dentry->d_parent, vfsmnt, root, rootmnt, buf, buflen); ++ if (unlikely(IS_ERR(retval))) ++err: ++ retval = strcpy(buf, ""); ++ else if (namelen != 0) { ++ end = buf + buflen - 1; // accounts for null termination ++ if (dentry->d_parent != root || vfsmnt != rootmnt) ++ *end++ = '/'; // accounted for above with buflen-- ++ memcpy(end, dentry->d_name.name, namelen); ++ } ++ ++ return retval; ++} ++ ++static char * ++d_real_path(const struct dentry *dentry, const struct vfsmount *vfsmnt, ++ char *buf, int buflen) ++{ ++ char *res; ++ struct dentry *root; ++ struct vfsmount *rootmnt; ++ ++ /* we can't use real_root, real_root_mnt, because they belong only to the RBAC system */ ++#ifdef CONFIG_VE ++ /* Don't use child_reaper, because it's VE0 process */ ++ root = dget(get_exec_env()->fs_root); ++ rootmnt = mntget(get_exec_env()->fs_rootmnt); ++#else ++ read_lock(&child_reaper->fs->lock); ++ root = dget(child_reaper->fs->root); ++ rootmnt = mntget(child_reaper->fs->rootmnt); ++ read_unlock(&child_reaper->fs->lock); ++#endif ++ ++ spin_lock(&dcache_lock); ++ res = gen_full_path((struct dentry *)dentry, (struct vfsmount *)vfsmnt, root, rootmnt, buf, buflen); ++ spin_unlock(&dcache_lock); ++ ++ dput(root); ++ mntput(rootmnt); ++ return res; ++} ++ ++char * ++gr_to_filename(const struct dentry *dentry, const struct vfsmount *mnt) ++{ ++ return d_real_path(dentry, mnt, per_cpu_ptr(gr_shared_page[0], smp_processor_id()), ++ PAGE_SIZE); ++} ++ ++char * ++gr_to_filename2(const struct dentry *dentry, const struct vfsmount *mnt) ++{ ++ return d_real_path(dentry, mnt, per_cpu_ptr(gr_shared_page[2], smp_processor_id()), ++ PAGE_SIZE); ++} ++ ++char * ++gr_to_filename3(const struct dentry *dentry, const struct vfsmount *mnt) ++{ ++ return d_real_path(dentry, mnt, per_cpu_ptr(gr_shared_page[3], smp_processor_id()), ++ PAGE_SIZE); ++} ++ ++int ++gr_acl_handle_mmap(const struct file *file, const unsigned long prot) ++{ ++ if (unlikely(!file || !(prot & PROT_EXEC))) ++ return 1; ++ ++ if (!gr_tpe_allow(file)) ++ return 0; ++ return 1; ++} ++ ++int ++gr_acl_handle_mprotect(const struct file *file, const unsigned long prot) ++{ ++ if (unlikely(!file || !(prot & PROT_EXEC))) ++ return 1; ++ ++ if (!gr_tpe_allow(file)) ++ return 0; ++ return 1; ++} +Index: kernel/grsecurity/grsec_disabled.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/grsecurity/grsec_disabled.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,39 @@ ++#include ++#include ++#include ++ ++void ++gr_copy_label(struct task_struct *tsk) ++{ ++ return; ++} ++ ++int ++gr_acl_handle_mmap(const struct file *file, const unsigned long prot, ++ unsigned int *vm_flags) ++{ ++ return 1; ++} ++ ++void ++grsecurity_init(void) ++{ ++ return; ++} ++ ++void ++gr_acl_handle_exit(void) ++{ ++ return; ++} ++ ++int ++gr_acl_handle_mprotect(const struct file *file, const unsigned long prot) ++{ ++ return 1; ++} ++ ++void grsecurity_setup(void) ++{ ++} ++EXPORT_SYMBOL(grsecurity_setup); +Index: kernel/grsecurity/grsec_init.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/grsecurity/grsec_init.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,89 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_VE ++#include ++#else ++int grsec_enable_tpe; ++int grsec_tpe_gid; ++int grsec_enable_tpe_all; ++int grsec_lock; ++#endif ++ ++spinlock_t grsec_alert_lock = SPIN_LOCK_UNLOCKED; ++ ++unsigned long grsec_alert_wtime = 0; ++unsigned long grsec_alert_fyet = 0; ++ ++spinlock_t grsec_audit_lock = SPIN_LOCK_UNLOCKED; ++ ++char *gr_shared_page[4]; ++ ++char *gr_alert_log_fmt; ++char *gr_audit_log_fmt; ++ ++char *gr_alert_log_buf; ++char *gr_audit_log_buf; ++ ++void grsecurity_setup(void) ++{ ++#if !defined(CONFIG_GRKERNSEC_SYSCTL) || defined(CONFIG_GRKERNSEC_SYSCTL_ON) ++#ifndef CONFIG_GRKERNSEC_SYSCTL ++ grsec_lock = 1; ++#endif ++#ifdef CONFIG_GRKERNSEC_TPE ++ grsec_enable_tpe = 1; ++ grsec_tpe_gid = CONFIG_GRKERNSEC_TPE_GID; ++#ifdef CONFIG_GRKERNSEC_TPE_ALL ++ grsec_enable_tpe_all = 1; ++#endif ++#endif ++#endif ++} ++EXPORT_SYMBOL(grsecurity_setup); ++ ++void ++grsecurity_init(void) ++{ ++ int j; ++ /* create the per-cpu shared pages */ ++ ++ for (j = 0; j < 4; j++) { ++ gr_shared_page[j] = (char *)__alloc_percpu(PAGE_SIZE); ++ if (gr_shared_page[j] == NULL) { ++ panic("Unable to allocate grsecurity shared page"); ++ return; ++ } ++ } ++ ++ /* allocate log buffers */ ++ gr_alert_log_fmt = kmalloc(512, GFP_KERNEL); ++ if (!gr_alert_log_fmt) { ++ panic("Unable to allocate grsecurity alert log format buffer"); ++ return; ++ } ++ gr_audit_log_fmt = kmalloc(512, GFP_KERNEL); ++ if (!gr_audit_log_fmt) { ++ panic("Unable to allocate grsecurity audit log format buffer"); ++ return; ++ } ++ gr_alert_log_buf = (char *) get_zeroed_page(GFP_KERNEL); ++ if (!gr_alert_log_buf) { ++ panic("Unable to allocate grsecurity alert log buffer"); ++ return; ++ } ++ gr_audit_log_buf = (char *) get_zeroed_page(GFP_KERNEL); ++ if (!gr_audit_log_buf) { ++ panic("Unable to allocate grsecurity audit log buffer"); ++ return; ++ } ++ grsecurity_setup(); ++ ++ return; ++} +Index: kernel/grsecurity/grsec_log.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/grsecurity/grsec_log.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,122 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define BEGIN_LOCKS(x) \ ++ if (x != GR_DO_AUDIT) \ ++ spin_lock(&grsec_alert_lock); \ ++ else \ ++ spin_lock(&grsec_audit_lock) ++ ++#define END_LOCKS(x) \ ++ if (x != GR_DO_AUDIT) \ ++ spin_unlock(&grsec_alert_lock); \ ++ else \ ++ spin_unlock(&grsec_audit_lock); ++ ++enum { ++ FLOODING, ++ NO_FLOODING ++}; ++ ++extern char *gr_alert_log_fmt; ++extern char *gr_audit_log_fmt; ++extern char *gr_alert_log_buf; ++extern char *gr_audit_log_buf; ++ ++static int gr_log_start(int audit) ++{ ++ char *loglevel = (audit == GR_DO_AUDIT) ? KERN_INFO : KERN_ALERT; ++ char *fmt = (audit == GR_DO_AUDIT) ? gr_audit_log_fmt : gr_alert_log_fmt; ++ char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf; ++ ++ if (audit == GR_DO_AUDIT) ++ goto set_fmt; ++ ++ if (!grsec_alert_wtime || jiffies - grsec_alert_wtime > CONFIG_GRKERNSEC_FLOODTIME * HZ) { ++ grsec_alert_wtime = jiffies; ++ grsec_alert_fyet = 0; ++ } else if ((jiffies - grsec_alert_wtime < CONFIG_GRKERNSEC_FLOODTIME * HZ) && (grsec_alert_fyet < CONFIG_GRKERNSEC_FLOODBURST)) { ++ grsec_alert_fyet++; ++ } else if (grsec_alert_fyet == CONFIG_GRKERNSEC_FLOODBURST) { ++ grsec_alert_wtime = jiffies; ++ grsec_alert_fyet++; ++ ve_printk(VE_LOG, KERN_ALERT "grsec: more alerts, logging disabled for %d seconds\n", CONFIG_GRKERNSEC_FLOODTIME); ++ return FLOODING; ++ } else return FLOODING; ++ ++set_fmt: ++ memset(buf, 0, PAGE_SIZE); ++ sprintf(fmt, "%s%s", loglevel, "grsec: "); ++ strcpy(buf, fmt); ++ ++ return NO_FLOODING; ++} ++ ++static void gr_log_middle(int audit, const char *msg, va_list ap) ++{ ++ char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf; ++ unsigned int len = strlen(buf); ++ ++ vsnprintf(buf + len, PAGE_SIZE - len - 1, msg, ap); ++ ++ return; ++} ++ ++static void gr_log_middle_varargs(int audit, const char *msg, ...) ++{ ++ char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf; ++ unsigned int len = strlen(buf); ++ va_list ap; ++ ++ va_start(ap, msg); ++ vsnprintf(buf + len, PAGE_SIZE - len - 1, msg, ap); ++ va_end(ap); ++ ++ return; ++} ++ ++static void gr_log_end(int audit) ++{ ++ char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf; ++ unsigned int len = strlen(buf); ++ ++ snprintf(buf + len, PAGE_SIZE - len - 1, DEFAULTSECMSG, DEFAULTSECARGS(current)); ++ ve_printk(VE_LOG, "%s\n", buf); ++ ++ return; ++} ++ ++void gr_log_varargs(int audit, const char *msg, int argtypes, ...) ++{ ++ int logtype; ++ struct dentry *dentry; ++ struct vfsmount *mnt; ++ va_list ap; ++ ++ BEGIN_LOCKS(audit); ++ logtype = gr_log_start(audit); ++ if (logtype == FLOODING) { ++ END_LOCKS(audit); ++ return; ++ } ++ va_start(ap, argtypes); ++ switch (argtypes) { ++ /* ++ * Only GR_FILENAME is now supported in VZ ++ */ ++ case GR_FILENAME: ++ dentry = va_arg(ap, struct dentry *); ++ mnt = va_arg(ap, struct vfsmount *); ++ gr_log_middle_varargs(audit, msg, gr_to_filename(dentry, mnt)); ++ break; ++ default: ++ gr_log_middle(audit, msg, ap); ++ } ++ va_end(ap); ++ gr_log_end(audit); ++ END_LOCKS(audit); ++} +Index: kernel/grsecurity/grsec_sysctl.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/grsecurity/grsec_sysctl.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,85 @@ ++#include ++#include ++#include ++#include ++#include ++ ++int ++gr_handle_sysctl_mod(const char *dirname, const char *name, const int op) ++{ ++#ifdef CONFIG_GRKERNSEC_SYSCTL ++ if (!strcmp(dirname, "grsecurity") && grsec_lock && (op & 002)) { ++ gr_log_str(GR_DONT_AUDIT, GR_SYSCTL_MSG, name); ++ return -EACCES; ++ } ++#endif ++ return 0; ++} ++ ++#ifdef CONFIG_GRKERNSEC_SYSCTL ++static int grsec_proc_dointvec(ctl_table *ctl, int write, struct file * filp, ++ void __user *buffer, size_t *lenp, loff_t *ppos) ++{ ++ int ret; ++#ifdef CONFIG_VE ++ struct ctl_table fake_table; ++ struct ve_struct *env = get_exec_env(); ++ ++ if (!ve_is_super(env)) { ++ memcpy(&fake_table, ctl, sizeof(struct ctl_table)); ++ fake_table.data = (char *)((unsigned long)&env->grsec + ++ (unsigned long)ctl->data - ++ (unsigned long)&get_ve0()->grsec); ++ ctl = &fake_table; ++ } ++#endif ++ ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); ++ return ret; ++} ++ ++enum {GS_TPE = 1, GS_TPE_GID, GS_TPE_ALL, GS_LOCK}; ++ ++ctl_table grsecurity_table[] = { ++#ifdef CONFIG_GRKERNSEC_TPE ++ { ++ .ctl_name = GS_TPE, ++ .procname = "tpe", ++ .data = &ve0.grsec.enable_tpe, ++ .maxlen = sizeof(int), ++ .mode = 0600, ++ .proc_handler = &grsec_proc_dointvec, ++ .virt_handler = 1, ++ }, ++ { ++ .ctl_name = GS_TPE_GID, ++ .procname = "tpe_gid", ++ .data = &ve0.grsec.tpe_gid, ++ .maxlen = sizeof(int), ++ .mode = 0600, ++ .proc_handler = &grsec_proc_dointvec, ++ .virt_handler = 1, ++ }, ++#endif ++#ifdef CONFIG_GRKERNSEC_TPE_ALL ++ { ++ .ctl_name = GS_TPE_ALL, ++ .procname = "tpe_restrict_all", ++ .data = &ve0.grsec.enable_tpe_all, ++ .maxlen = sizeof(int), ++ .mode = 0600, ++ .proc_handler = &grsec_proc_dointvec, ++ .virt_handler = 1, ++ }, ++#endif ++ { ++ .ctl_name = GS_LOCK, ++ .procname = "grsec_lock", ++ .data = &ve0.grsec.lock, ++ .maxlen = sizeof(int), ++ .mode = 0600, ++ .proc_handler = &grsec_proc_dointvec, ++ .virt_handler = 1, ++ }, ++ { .ctl_name = 0 } ++}; ++#endif +Index: kernel/grsecurity/grsec_tpe.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/grsecurity/grsec_tpe.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,37 @@ ++#include ++#include ++#include ++#include ++#include ++ ++extern int gr_acl_tpe_check(void); ++ ++int ++gr_tpe_allow(const struct file *file) ++{ ++#ifdef CONFIG_GRKERNSEC_TPE ++ struct inode *inode = file->f_dentry->d_parent->d_inode; ++ ++ if (current->uid && ((grsec_enable_tpe && ++#ifdef CONFIG_GRKERNSEC_TPE_INVERT ++ !in_group_p(grsec_tpe_gid) ++#else ++ in_group_p(grsec_tpe_gid) ++#endif ++ )) && ++ (inode->i_uid || (!inode->i_uid && ((inode->i_mode & S_IWGRP) || ++ (inode->i_mode & S_IWOTH))))) { ++ gr_log_fs_generic(GR_DONT_AUDIT, GR_EXEC_TPE_MSG, file->f_dentry, file->f_vfsmnt); ++ return 0; ++ } ++#ifdef CONFIG_GRKERNSEC_TPE_ALL ++ if (current->uid && grsec_enable_tpe && grsec_enable_tpe_all && ++ ((inode->i_uid && (inode->i_uid != current->uid)) || ++ (inode->i_mode & S_IWGRP) || (inode->i_mode & S_IWOTH))) { ++ gr_log_fs_generic(GR_DONT_AUDIT, GR_EXEC_TPE_MSG, file->f_dentry, file->f_vfsmnt); ++ return 0; ++ } ++#endif ++#endif ++ return 1; ++} +Index: kernel/include/asm-ia64/mman.h +=================================================================== +--- kernel.orig/include/asm-ia64/mman.h 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/include/asm-ia64/mman.h 2008-11-24 15:47:46.000000000 +0100 +@@ -18,6 +18,7 @@ + #define MAP_NORESERVE 0x04000 /* don't check for reservations */ + #define MAP_POPULATE 0x08000 /* populate (prefault) pagetables */ + #define MAP_NONBLOCK 0x10000 /* do not block on IO */ ++#define MAP_EXECPRIO 0x20000 /* soft ubc charge */ + + #define MCL_CURRENT 1 /* lock all current mappings */ + #define MCL_FUTURE 2 /* lock all future mappings */ +Index: kernel/include/asm-ia64/pgalloc.h +=================================================================== +--- kernel.orig/include/asm-ia64/pgalloc.h 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/include/asm-ia64/pgalloc.h 2008-11-24 15:47:46.000000000 +0100 +@@ -20,11 +20,13 @@ + #include + #include + ++#include ++ + #include + + static inline pgd_t *pgd_alloc(struct mm_struct *mm) + { +- return quicklist_alloc(0, GFP_KERNEL, NULL); ++ return quicklist_alloc(0, GFP_KERNEL_UBC|__GFP_SOFT_UBC, NULL); + } + + static inline void pgd_free(pgd_t * pgd) +@@ -41,7 +43,7 @@ + + static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) + { +- return quicklist_alloc(0, GFP_KERNEL, NULL); ++ return quicklist_alloc(0, GFP_KERNEL_UBC|__GFP_SOFT_UBC, NULL); + } + + static inline void pud_free(pud_t * pud) +@@ -59,7 +61,7 @@ + + static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) + { +- return quicklist_alloc(0, GFP_KERNEL, NULL); ++ return quicklist_alloc(0, GFP_KERNEL_UBC|__GFP_SOFT_UBC, NULL); + } + + static inline void pmd_free(pmd_t * pmd) +@@ -84,7 +86,7 @@ + static inline struct page *pte_alloc_one(struct mm_struct *mm, + unsigned long addr) + { +- void *pg = quicklist_alloc(0, GFP_KERNEL, NULL); ++ void *pg = quicklist_alloc(0, GFP_KERNEL_UBC|__GFP_SOFT_UBC, NULL); + return pg ? virt_to_page(pg) : NULL; + } + +Index: kernel/include/asm-ia64/processor.h +=================================================================== +--- kernel.orig/include/asm-ia64/processor.h 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/include/asm-ia64/processor.h 2008-11-24 15:47:46.000000000 +0100 +@@ -297,7 +297,7 @@ + regs->loadrs = 0; \ + regs->r8 = get_dumpable(current->mm); /* set "don't zap registers" flag */ \ + regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \ +- if (unlikely(!get_dumpable(current->mm))) { \ ++ if (unlikely(!get_dumpable(current->mm) || !current->mm->vps_dumpable)) { \ + /* \ + * Zap scratch regs to avoid leaking bits between processes with different \ + * uid/privileges. \ +Index: kernel/include/asm-ia64/unistd.h +=================================================================== +--- kernel.orig/include/asm-ia64/unistd.h 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/include/asm-ia64/unistd.h 2008-11-24 15:47:46.000000000 +0100 +@@ -299,11 +299,17 @@ + #define __NR_signalfd 1307 + #define __NR_timerfd 1308 + #define __NR_eventfd 1309 ++#define __NR_getluid 1505 ++#define __NR_setluid 1506 ++#define __NR_setublimit 1507 ++#define __NR_ubstat 1508 ++#define __NR_lchmod 1509 ++#define __NR_lutime 1510 + + #ifdef __KERNEL__ + + +-#define NR_syscalls 286 /* length of syscall table */ ++#define NR_syscalls 487 /* length of syscall table */ + + /* + * The following defines stop scripts/checksyscalls.sh from complaining about +Index: kernel/include/asm-powerpc/elf.h +=================================================================== +--- kernel.orig/include/asm-powerpc/elf.h 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/include/asm-powerpc/elf.h 2008-11-24 15:47:46.000000000 +0100 +@@ -280,7 +280,8 @@ + #define ARCH_HAS_SETUP_ADDITIONAL_PAGES + struct linux_binprm; + extern int arch_setup_additional_pages(struct linux_binprm *bprm, +- int executable_stack); ++ int executable_stack, ++ unsigned long map_address); + #define VDSO_AUX_ENT(a,b) NEW_AUX_ENT(a,b); + + /* +Index: kernel/include/asm-powerpc/mman.h +=================================================================== +--- kernel.orig/include/asm-powerpc/mman.h 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/include/asm-powerpc/mman.h 2008-11-24 15:47:46.000000000 +0100 +@@ -23,5 +23,6 @@ + + #define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ + #define MAP_NONBLOCK 0x10000 /* do not block on IO */ ++#define MAP_EXECPRIO 0x20000 /* do soft ubc charge */ + + #endif /* _ASM_POWERPC_MMAN_H */ +Index: kernel/include/asm-powerpc/pgalloc-64.h +=================================================================== +--- kernel.orig/include/asm-powerpc/pgalloc-64.h 2008-11-18 01:19:46.000000000 +0100 ++++ kernel/include/asm-powerpc/pgalloc-64.h 2008-11-24 15:47:46.000000000 +0100 +@@ -22,7 +22,8 @@ + + static inline pgd_t *pgd_alloc(struct mm_struct *mm) + { +- return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL); ++ return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], ++ GFP_KERNEL_UBC | __GFP_SOFT_UBC); + } + + static inline void pgd_free(pgd_t *pgd) +@@ -37,7 +38,7 @@ + static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) + { + return kmem_cache_alloc(pgtable_cache[PUD_CACHE_NUM], +- GFP_KERNEL|__GFP_REPEAT); ++ GFP_KERNEL_UBC|__GFP_SOFT_UBC|__GFP_REPEAT); + } + + static inline void pud_free(pud_t *pud) +@@ -81,16 +82,21 @@ + kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd); + } + ++static inline pte_t *do_pte_alloc(gfp_t flags) ++{ ++ return (pte_t *)__get_free_page(flags); ++} ++ + static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, + unsigned long address) + { +- return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO); ++ return do_pte_alloc(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO); + } + + static inline struct page *pte_alloc_one(struct mm_struct *mm, + unsigned long address) + { +- pte_t *pte = pte_alloc_one_kernel(mm, address); ++ pte_t *pte = do_pte_alloc(GFP_KERNEL_UBC | __GFP_SOFT_UBC | __GFP_ZERO); + return pte ? virt_to_page(pte) : NULL; + } + +Index: kernel/include/asm-powerpc/systbl.h +=================================================================== +--- kernel.orig/include/asm-powerpc/systbl.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-powerpc/systbl.h 2008-11-24 15:47:46.000000000 +0100 +@@ -313,3 +313,8 @@ + SYSCALL_SPU(eventfd) + COMPAT_SYS_SPU(sync_file_range2) + COMPAT_SYS(fallocate) ++SYS_SKIP(302, 409) ++SYSCALL(getluid) /* 410 */ ++SYSCALL(setluid) ++SYSCALL(setublimit) ++SYSCALL(ubstat) +Index: kernel/include/asm-powerpc/unistd.h +=================================================================== +--- kernel.orig/include/asm-powerpc/unistd.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-powerpc/unistd.h 2008-11-24 15:47:46.000000000 +0100 +@@ -333,9 +333,14 @@ + #define __NR_sync_file_range2 308 + #define __NR_fallocate 309 + ++#define __NR_getluid 410 ++#define __NR_setluid 411 ++#define __NR_setublimit 412 ++#define __NR_ubstat 413 ++ + #ifdef __KERNEL__ + +-#define __NR_syscalls 310 ++#define __NR_syscalls 414 + + #define __NR__exit __NR_exit + #define NR_syscalls __NR_syscalls +Index: kernel/include/asm-sparc64/mman.h +=================================================================== +--- kernel.orig/include/asm-sparc64/mman.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-sparc64/mman.h 2008-11-24 15:47:46.000000000 +0100 +@@ -21,6 +21,7 @@ + + #define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ + #define MAP_NONBLOCK 0x10000 /* do not block on IO */ ++#define MAP_EXECPRIO 0x20000 /* do soft ubc charge */ + + /* XXX Need to add flags to SunOS's mctl, mlockall, and madvise system + * XXX calls. +Index: kernel/include/asm-sparc64/pgalloc.h +=================================================================== +--- kernel.orig/include/asm-sparc64/pgalloc.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-sparc64/pgalloc.h 2008-11-24 15:47:46.000000000 +0100 +@@ -17,7 +17,7 @@ + + static inline pgd_t *pgd_alloc(struct mm_struct *mm) + { +- return quicklist_alloc(0, GFP_KERNEL, NULL); ++ return quicklist_alloc(0, GFP_KERNEL_UBC, NULL); + } + + static inline void pgd_free(pgd_t *pgd) +@@ -29,7 +29,7 @@ + + static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) + { +- return quicklist_alloc(0, GFP_KERNEL, NULL); ++ return quicklist_alloc(0, GFP_KERNEL_UBC|__GFP_REPEAT, NULL); + } + + static inline void pmd_free(pmd_t *pmd) +@@ -46,7 +46,7 @@ + static inline struct page *pte_alloc_one(struct mm_struct *mm, + unsigned long address) + { +- void *pg = quicklist_alloc(0, GFP_KERNEL, NULL); ++ void *pg = quicklist_alloc(0, GFP_KERNEL_UBC|__GFP_REPEAT, NULL); + return pg ? virt_to_page(pg) : NULL; + } + +Index: kernel/include/asm-sparc64/thread_info.h +=================================================================== +--- kernel.orig/include/asm-sparc64/thread_info.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-sparc64/thread_info.h 2008-11-24 15:47:46.000000000 +0100 +@@ -162,14 +162,14 @@ + struct thread_info *ret; \ + \ + ret = (struct thread_info *) \ +- __get_free_pages(GFP_KERNEL, __THREAD_INFO_ORDER); \ ++ __get_free_pages(GFP_KERNEL_UBC, __THREAD_INFO_ORDER);\ + if (ret) \ + memset(ret, 0, PAGE_SIZE<<__THREAD_INFO_ORDER); \ + ret; \ + }) + #else + #define alloc_thread_info(tsk) \ +- ((struct thread_info *)__get_free_pages(GFP_KERNEL, __THREAD_INFO_ORDER)) ++ ((struct thread_info *)__get_free_pages(GFP_KERNEL_UBC, __THREAD_INFO_ORDER)) + #endif + + #define free_thread_info(ti) \ +@@ -236,6 +236,7 @@ + #define TIF_ABI_PENDING 12 + #define TIF_MEMDIE 13 + #define TIF_POLLING_NRFLAG 14 ++#define TIF_FREEZE 15 /* Freeze request (atomic PF_FREEZE) */ + + #define _TIF_SYSCALL_TRACE (1< +-# define STACK_TOP TASK_SIZE ++# define STACK_TOP (TASK_SIZE - PAGE_SIZE) /* +1 page for vdso */ + # ifdef CONFIG_X86_32 + # define STACK_TOP_MAX STACK_TOP + # else +Index: kernel/include/asm-x86/elf.h +=================================================================== +--- kernel.orig/include/asm-x86/elf.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-x86/elf.h 2008-11-24 15:47:46.000000000 +0100 +@@ -262,7 +262,7 @@ + /* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */ + + #define ARCH_DLINFO \ +-do if (vdso_enabled) { \ ++do if (vdso_enabled && sysctl_at_vsyscall) { \ + NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \ + } while (0) +@@ -283,7 +283,8 @@ + + #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 + extern int arch_setup_additional_pages(struct linux_binprm *bprm, +- int executable_stack); ++ int executable_stack, ++ unsigned long map_address); + + #endif /* __KERNEL__ */ + +Index: kernel/include/asm-x86/ia32.h +=================================================================== +--- kernel.orig/include/asm-x86/ia32.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-x86/ia32.h 2008-11-24 15:47:46.000000000 +0100 +@@ -156,7 +156,7 @@ + char f_fpack[6]; + }; + +-#define IA32_STACK_TOP IA32_PAGE_OFFSET ++#define IA32_STACK_TOP (IA32_PAGE_OFFSET - PAGE_SIZE * 2) + + #ifdef __KERNEL__ + struct user_desc; +Index: kernel/include/asm-x86/mman.h +=================================================================== +--- kernel.orig/include/asm-x86/mman.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-x86/mman.h 2008-11-24 15:47:46.000000000 +0100 +@@ -12,6 +12,7 @@ + #define MAP_NORESERVE 0x4000 /* don't check for reservations */ + #define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ + #define MAP_NONBLOCK 0x10000 /* do not block on IO */ ++#define MAP_EXECPRIO 0x20000 /* soft ubc charge */ + + #define MCL_CURRENT 1 /* lock all current mappings */ + #define MCL_FUTURE 2 /* lock all future mappings */ +Index: kernel/include/asm-x86/nmi_32.h +=================================================================== +--- kernel.orig/include/asm-x86/nmi_32.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-x86/nmi_32.h 2008-11-24 15:47:46.000000000 +0100 +@@ -25,6 +25,10 @@ + extern int reserve_evntsel_nmi(unsigned int); + extern void release_evntsel_nmi(unsigned int); + ++typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu); ++void set_nmi_ipi_callback(nmi_callback_t callback); ++void unset_nmi_ipi_callback(void); ++ + extern void setup_apic_nmi_watchdog (void *); + extern void stop_apic_nmi_watchdog (void *); + extern void disable_timer_nmi_watchdog(void); +@@ -33,7 +37,7 @@ + + extern atomic_t nmi_active; + extern unsigned int nmi_watchdog; +-#define NMI_DISABLED -1 ++#define NMI_DISABLED -1 + #define NMI_NONE 0 + #define NMI_IO_APIC 1 + #define NMI_LOCAL_APIC 2 +Index: kernel/include/asm-x86/nmi_64.h +=================================================================== +--- kernel.orig/include/asm-x86/nmi_64.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-x86/nmi_64.h 2008-11-24 15:47:46.000000000 +0100 +@@ -35,6 +35,11 @@ + } + + #endif /* CONFIG_PM */ ++ ++typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu); ++void set_nmi_ipi_callback(nmi_callback_t callback); ++void unset_nmi_ipi_callback(void); ++ + + extern void default_do_nmi(struct pt_regs *); + extern void die_nmi(char *str, struct pt_regs *regs, int do_panic); +Index: kernel/include/asm-x86/pgalloc_64.h +=================================================================== +--- kernel.orig/include/asm-x86/pgalloc_64.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-x86/pgalloc_64.h 2008-11-24 15:47:46.000000000 +0100 +@@ -25,12 +25,14 @@ + + static inline pmd_t *pmd_alloc_one (struct mm_struct *mm, unsigned long addr) + { +- return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); ++ return (pmd_t *)get_zeroed_page(GFP_KERNEL_UBC|__GFP_REPEAT| ++ __GFP_SOFT_UBC); + } + + static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) + { +- return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); ++ return (pud_t *)get_zeroed_page(GFP_KERNEL_UBC|__GFP_REPEAT| ++ __GFP_SOFT_UBC); + } + + static inline void pud_free (pud_t *pud) +@@ -60,7 +62,8 @@ + static inline pgd_t *pgd_alloc(struct mm_struct *mm) + { + unsigned boundary; +- pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT); ++ pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL_UBC|__GFP_REPEAT| ++ __GFP_SOFT_UBC); + if (!pgd) + return NULL; + pgd_list_add(pgd); +@@ -91,7 +94,8 @@ + + static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) + { +- void *p = (void *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); ++ void *p = (void *)get_zeroed_page(GFP_KERNEL_UBC|__GFP_REPEAT| ++ __GFP_SOFT_UBC); + if (!p) + return NULL; + return virt_to_page(p); +Index: kernel/include/asm-x86/processor_64.h +=================================================================== +--- kernel.orig/include/asm-x86/processor_64.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-x86/processor_64.h 2008-11-24 15:47:46.000000000 +0100 +@@ -143,7 +143,7 @@ + /* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +-#define IA32_PAGE_OFFSET ((current->personality & ADDR_LIMIT_3GB) ? 0xc0000000 : 0xFFFFe000) ++#define IA32_PAGE_OFFSET 0xc0000000 + + #define TASK_SIZE (test_thread_flag(TIF_IA32) ? IA32_PAGE_OFFSET : TASK_SIZE64) + #define TASK_SIZE_OF(child) ((test_tsk_thread_flag(child, TIF_IA32)) ? IA32_PAGE_OFFSET : TASK_SIZE64) +Index: kernel/include/asm-x86/thread_info_32.h +=================================================================== +--- kernel.orig/include/asm-x86/thread_info_32.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-x86/thread_info_32.h 2008-11-24 15:47:46.000000000 +0100 +@@ -96,10 +96,10 @@ + /* thread information allocation */ + #ifdef CONFIG_DEBUG_STACK_USAGE + #define alloc_thread_info(tsk) ((struct thread_info *) \ +- __get_free_pages(GFP_KERNEL| __GFP_ZERO, get_order(THREAD_SIZE))) ++ __get_free_pages(GFP_KERNEL_UBC| __GFP_ZERO, get_order(THREAD_SIZE))) + #else + #define alloc_thread_info(tsk) ((struct thread_info *) \ +- __get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE))) ++ __get_free_pages(GFP_KERNEL_UBC, get_order(THREAD_SIZE))) + #endif + + #define free_thread_info(info) free_pages((unsigned long)(info), get_order(THREAD_SIZE)) +Index: kernel/include/asm-x86/thread_info_64.h +=================================================================== +--- kernel.orig/include/asm-x86/thread_info_64.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/asm-x86/thread_info_64.h 2008-11-24 15:47:46.000000000 +0100 +@@ -33,6 +33,7 @@ + + mm_segment_t addr_limit; + struct restart_block restart_block; ++ void *sysenter_return; + }; + #endif + +@@ -78,14 +79,15 @@ + ({ \ + struct thread_info *ret; \ + \ +- ret = ((struct thread_info *) __get_free_pages(GFP_KERNEL,THREAD_ORDER)); \ ++ ret = ((struct thread_info *) __get_free_pages(GFP_KERNEL_UBC,\ ++ THREAD_ORDER)); \ + if (ret) \ + memset(ret, 0, THREAD_SIZE); \ + ret; \ + }) + #else + #define alloc_thread_info(tsk) \ +- ((struct thread_info *) __get_free_pages(GFP_KERNEL,THREAD_ORDER)) ++ ((struct thread_info *) __get_free_pages(GFP_KERNEL_UBC,THREAD_ORDER)) + #endif + + #define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER) +@@ -123,6 +125,7 @@ + #define TIF_DEBUG 21 /* uses debug registers */ + #define TIF_IO_BITMAP 22 /* uses I/O bitmap */ + #define TIF_FREEZE 23 /* is freezing for suspend */ ++#define TIF_RESUME 24 + + #define _TIF_SYSCALL_TRACE (1<mm->context.vdso) + #define VSYSCALL32_END (VSYSCALL32_BASE + PAGE_SIZE) + #define VSYSCALL32_EHDR ((const struct elf32_hdr *) VSYSCALL32_BASE) + ++#define __VSYSCALL32_BASE ((unsigned long)(IA32_PAGE_OFFSET - PAGE_SIZE)) ++#define __VSYSCALL32_END (__VSYSCALL32_BASE + PAGE_SIZE) ++ + #define VSYSCALL32_VSYSCALL ((void *)VSYSCALL32_BASE + 0x400) +-#define VSYSCALL32_SYSEXIT ((void *)VSYSCALL32_BASE + 0x410) ++#define VSYSCALL32_SYSEXIT ((void *)VSYSCALL32_BASE + 0x420) + #define VSYSCALL32_SIGRETURN ((void __user *)VSYSCALL32_BASE + 0x500) + #define VSYSCALL32_RTSIGRETURN ((void __user *)VSYSCALL32_BASE + 0x600) + #endif +Index: kernel/include/bc/beancounter.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/beancounter.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,451 @@ ++/* ++ * include/bc/beancounter.h ++ * ++ * Copyright (C) 1999-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * Andrey Savochkin saw@sw-soft.com ++ * ++ */ ++ ++#ifndef _LINUX_BEANCOUNTER_H ++#define _LINUX_BEANCOUNTER_H ++ ++/* ++ * Generic ratelimiting stuff. ++ */ ++ ++struct ub_rate_info { ++ int burst; ++ int interval; /* jiffy_t per event */ ++ int bucket; /* kind of leaky bucket */ ++ unsigned long last; /* last event */ ++}; ++ ++/* Return true if rate limit permits. */ ++int ub_ratelimit(struct ub_rate_info *); ++ ++ ++/* ++ * This magic is used to distinuish user beancounter and pages beancounter ++ * in struct page. page_ub and page_bc are placed in union and MAGIC ++ * ensures us that we don't use pbc as ubc in ub_page_uncharge(). ++ */ ++#define UB_MAGIC 0x62756275 ++ ++/* ++ * Resource list. ++ */ ++ ++#define UB_KMEMSIZE 0 /* Unswappable kernel memory size including ++ * struct task, page directories, etc. ++ */ ++#define UB_LOCKEDPAGES 1 /* Mlock()ed pages. */ ++#define UB_PRIVVMPAGES 2 /* Total number of pages, counting potentially ++ * private pages as private and used. ++ */ ++#define UB_SHMPAGES 3 /* IPC SHM segment size. */ ++#define UB_DUMMY 4 /* Dummy resource (compatibility) */ ++#define UB_NUMPROC 5 /* Number of processes. */ ++#define UB_PHYSPAGES 6 /* All resident pages, for swapout guarantee. */ ++#define UB_VMGUARPAGES 7 /* Guarantee for memory allocation, ++ * checked against PRIVVMPAGES. ++ */ ++#define UB_OOMGUARPAGES 8 /* Guarantees against OOM kill. ++ * Only limit is used, no accounting. ++ */ ++#define UB_NUMTCPSOCK 9 /* Number of TCP sockets. */ ++#define UB_NUMFLOCK 10 /* Number of file locks. */ ++#define UB_NUMPTY 11 /* Number of PTYs. */ ++#define UB_NUMSIGINFO 12 /* Number of siginfos. */ ++#define UB_TCPSNDBUF 13 /* Total size of tcp send buffers. */ ++#define UB_TCPRCVBUF 14 /* Total size of tcp receive buffers. */ ++#define UB_OTHERSOCKBUF 15 /* Total size of other socket ++ * send buffers (all buffers for PF_UNIX). ++ */ ++#define UB_DGRAMRCVBUF 16 /* Total size of other socket ++ * receive buffers. ++ */ ++#define UB_NUMOTHERSOCK 17 /* Number of other sockets. */ ++#define UB_DCACHESIZE 18 /* Size of busy dentry/inode cache. */ ++#define UB_NUMFILE 19 /* Number of open files. */ ++ ++#define UB_RESOURCES_COMPAT 24 ++ ++/* Add new resources here */ ++ ++#define UB_NUMXTENT 23 ++#define UB_RESOURCES 24 ++ ++#define UB_UNUSEDPRIVVM (UB_RESOURCES + 0) ++#define UB_TMPFSPAGES (UB_RESOURCES + 1) ++#define UB_SWAPPAGES (UB_RESOURCES + 2) ++#define UB_HELDPAGES (UB_RESOURCES + 3) ++ ++struct ubparm { ++ /* ++ * A barrier over which resource allocations are failed gracefully. ++ * If the amount of consumed memory is over the barrier further sbrk() ++ * or mmap() calls fail, the existing processes are not killed. ++ */ ++ unsigned long barrier; ++ /* hard resource limit */ ++ unsigned long limit; ++ /* consumed resources */ ++ unsigned long held; ++ /* maximum amount of consumed resources through the last period */ ++ unsigned long maxheld; ++ /* minimum amount of consumed resources through the last period */ ++ unsigned long minheld; ++ /* count of failed charges */ ++ unsigned long failcnt; ++}; ++ ++/* ++ * Kernel internal part. ++ */ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * UB_MAXVALUE is essentially LONG_MAX declared in a cross-compiling safe form. ++ */ ++#define UB_MAXVALUE ( (1UL << (sizeof(unsigned long)*8-1)) - 1) ++ ++ ++/* ++ * Resource management structures ++ * Serialization issues: ++ * beancounter list management is protected via ub_hash_lock ++ * task pointers are set only for current task and only once ++ * refcount is managed atomically ++ * value and limit comparison and change are protected by per-ub spinlock ++ */ ++ ++struct page_beancounter; ++struct task_beancounter; ++struct sock_beancounter; ++ ++struct page_private { ++ unsigned long ubp_unused_privvmpages; ++ unsigned long ubp_tmpfs_respages; ++ unsigned long ubp_swap_pages; ++ unsigned long long ubp_held_pages; ++}; ++ ++struct sock_private { ++ unsigned long ubp_rmem_thres; ++ unsigned long ubp_wmem_pressure; ++ unsigned long ubp_maxadvmss; ++ unsigned long ubp_rmem_pressure; ++ int ubp_tw_count; ++#define UB_RMEM_EXPAND 0 ++#define UB_RMEM_KEEP 1 ++#define UB_RMEM_SHRINK 2 ++ struct list_head ubp_other_socks; ++ struct list_head ubp_tcp_socks; ++ atomic_t ubp_orphan_count; ++}; ++ ++struct ub_percpu_struct { ++ unsigned long unmap; ++ unsigned long swapin; ++#ifdef CONFIG_BC_IO_ACCOUNTING ++ unsigned long long bytes_wrote; ++ unsigned long long bytes_read; ++ unsigned long long bytes_cancelled; ++#endif ++#ifdef CONFIG_BC_DEBUG_KMEM ++ long pages_charged; ++ long vmalloc_charged; ++ long pbcs; ++#endif ++ unsigned long sync; ++ unsigned long sync_done; ++ ++ unsigned long fsync; ++ unsigned long fsync_done; ++ ++ unsigned long fdsync; ++ unsigned long fdsync_done; ++ ++ unsigned long frsync; ++ unsigned long frsync_done; ++ ++ unsigned long write; ++ unsigned long read; ++ unsigned long long wchar; ++ unsigned long long rchar; ++}; ++ ++struct user_beancounter ++{ ++ unsigned long ub_magic; ++ atomic_t ub_refcount; ++ struct list_head ub_list; ++ struct hlist_node ub_hash; ++ ++ union { ++ struct rcu_head rcu; ++ struct execute_work cleanup; ++ }; ++ ++ spinlock_t ub_lock; ++ uid_t ub_uid; ++ ++ struct ub_rate_info ub_limit_rl; ++ int ub_oom_noproc; ++ ++ struct page_private ppriv; ++#define ub_unused_privvmpages ppriv.ubp_unused_privvmpages ++#define ub_tmpfs_respages ppriv.ubp_tmpfs_respages ++#define ub_swap_pages ppriv.ubp_swap_pages ++#define ub_held_pages ppriv.ubp_held_pages ++ struct sock_private spriv; ++#define ub_rmem_thres spriv.ubp_rmem_thres ++#define ub_maxadvmss spriv.ubp_maxadvmss ++#define ub_rmem_pressure spriv.ubp_rmem_pressure ++#define ub_wmem_pressure spriv.ubp_wmem_pressure ++#define ub_tcp_sk_list spriv.ubp_tcp_socks ++#define ub_other_sk_list spriv.ubp_other_socks ++#define ub_orphan_count spriv.ubp_orphan_count ++#define ub_tw_count spriv.ubp_tw_count ++ struct ub_iopriv iopriv; ++ ++ struct user_beancounter *parent; ++ void *private_data; ++ unsigned long ub_aflags; ++ ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *proc; ++#endif ++ ++ /* resources statistic and settings */ ++ struct ubparm ub_parms[UB_RESOURCES]; ++ /* resources statistic for last interval */ ++ struct ubparm ub_store[UB_RESOURCES]; ++ ++ struct ub_percpu_struct *ub_percpu; ++#ifdef CONFIG_BC_IO_ACCOUNTING ++ /* these are protected with pb_lock */ ++ unsigned long long bytes_wrote; ++ unsigned long long bytes_dirtied; ++ unsigned long long bytes_dirty_missed; ++ unsigned long io_pb_held; ++#endif ++#ifdef CONFIG_BC_DEBUG_KMEM ++ struct list_head ub_cclist; ++#endif ++}; ++ ++enum ub_severity { UB_HARD, UB_SOFT, UB_FORCE }; ++ ++#define UB_AFLAG_NOTIF_PAGEIN 0 ++ ++static inline ++struct user_beancounter *top_beancounter(struct user_beancounter *ub) ++{ ++ while (ub->parent != NULL) ++ ub = ub->parent; ++ return ub; ++} ++ ++static inline int ub_barrier_hit(struct user_beancounter *ub, int resource) ++{ ++ return ub->ub_parms[resource].held > ub->ub_parms[resource].barrier; ++} ++ ++static inline int ub_hfbarrier_hit(struct user_beancounter *ub, int resource) ++{ ++ return (ub->ub_parms[resource].held > ++ ((ub->ub_parms[resource].barrier) >> 1)); ++} ++ ++static inline int ub_barrier_farnr(struct user_beancounter *ub, int resource) ++{ ++ struct ubparm *p; ++ p = ub->ub_parms + resource; ++ return p->held <= (p->barrier >> 3); ++} ++ ++static inline int ub_barrier_farsz(struct user_beancounter *ub, int resource) ++{ ++ struct ubparm *p; ++ p = ub->ub_parms + resource; ++ return p->held <= (p->barrier >> 3) && p->barrier >= 1024 * 1024; ++} ++ ++#ifndef CONFIG_BEANCOUNTERS ++ ++#define ub_percpu_add(ub, f, v) do { } while (0) ++#define ub_percpu_sub(ub, f, v) do { } while (0) ++#define ub_percpu_inc(ub, f) do { } while (0) ++#define ub_percpu_dec(ub, f) do { } while (0) ++ ++#define mm_ub(mm) (NULL) ++ ++extern inline struct user_beancounter *get_beancounter_byuid ++ (uid_t uid, int create) { return NULL; } ++extern inline struct user_beancounter *get_beancounter ++ (struct user_beancounter *ub) { return NULL; } ++extern inline void put_beancounter(struct user_beancounter *ub) { } ++ ++static inline void ub_init_late(void) { }; ++static inline void ub_init_early(void) { }; ++ ++static inline int charge_beancounter(struct user_beancounter *ub, ++ int resource, unsigned long val, ++ enum ub_severity strict) { return 0; } ++static inline void uncharge_beancounter(struct user_beancounter *ub, ++ int resource, unsigned long val) { } ++ ++#else /* CONFIG_BEANCOUNTERS */ ++ ++#define ub_percpu_add(ub, field, v) do { \ ++ per_cpu_ptr(ub->ub_percpu, get_cpu())->field += (v); \ ++ put_cpu(); \ ++ } while (0) ++#define ub_percpu_inc(ub, field) ub_percpu_add(ub, field, 1) ++ ++#define ub_percpu_sub(ub, field, v) do { \ ++ per_cpu_ptr(ub->ub_percpu, get_cpu())->field -= (v); \ ++ put_cpu(); \ ++ } while (0) ++#define ub_percpu_dec(ub, field) ub_percpu_sub(ub, field, 1) ++ ++#define mm_ub(mm) ((mm)->mm_ub) ++/* ++ * Charge/uncharge operations ++ */ ++ ++extern int __charge_beancounter_locked(struct user_beancounter *ub, ++ int resource, unsigned long val, enum ub_severity strict); ++ ++extern void __uncharge_beancounter_locked(struct user_beancounter *ub, ++ int resource, unsigned long val); ++ ++extern void put_beancounter_safe(struct user_beancounter *ub); ++extern void __put_beancounter(struct user_beancounter *ub); ++ ++extern void uncharge_warn(struct user_beancounter *ub, int resource, ++ unsigned long val, unsigned long held); ++ ++extern const char *ub_rnames[]; ++/* ++ * Put a beancounter reference ++ */ ++ ++static inline void put_beancounter(struct user_beancounter *ub) ++{ ++ if (unlikely(ub == NULL)) ++ return; ++ ++ /* FIXME - optimize not to disable interrupts and make call */ ++ __put_beancounter(ub); ++} ++ ++/* fast put, refcount can't reach zero */ ++static inline void __put_beancounter_batch(struct user_beancounter *ub, int n) ++{ ++ atomic_sub(n, &ub->ub_refcount); ++} ++ ++static inline void put_beancounter_batch(struct user_beancounter *ub, int n) ++{ ++ if (n > 1) ++ __put_beancounter_batch(ub, n - 1); ++ __put_beancounter(ub); ++} ++ ++/* ++ * Create a new beancounter reference ++ */ ++extern struct user_beancounter *get_beancounter_byuid(uid_t uid, int create); ++ ++static inline ++struct user_beancounter *get_beancounter(struct user_beancounter *ub) ++{ ++ if (unlikely(ub == NULL)) ++ return NULL; ++ ++ atomic_inc(&ub->ub_refcount); ++ return ub; ++} ++ ++static inline ++struct user_beancounter *get_beancounter_rcu(struct user_beancounter *ub) ++{ ++ return atomic_inc_not_zero(&ub->ub_refcount) ? ub : NULL; ++} ++ ++static inline void get_beancounter_batch(struct user_beancounter *ub, int n) ++{ ++ atomic_add(n, &ub->ub_refcount); ++} ++ ++extern struct user_beancounter *get_subbeancounter_byid( ++ struct user_beancounter *, ++ int id, int create); ++ ++extern void ub_init_late(void); ++extern void ub_init_early(void); ++ ++extern int print_ub_uid(struct user_beancounter *ub, char *buf, int size); ++ ++/* ++ * Resource charging ++ * Change user's account and compare against limits ++ */ ++ ++static inline void ub_adjust_maxheld(struct user_beancounter *ub, int resource) ++{ ++ if (ub->ub_parms[resource].maxheld < ub->ub_parms[resource].held) ++ ub->ub_parms[resource].maxheld = ub->ub_parms[resource].held; ++ if (ub->ub_parms[resource].minheld > ub->ub_parms[resource].held) ++ ub->ub_parms[resource].minheld = ub->ub_parms[resource].held; ++} ++ ++int charge_beancounter(struct user_beancounter *ub, int resource, ++ unsigned long val, enum ub_severity strict); ++void uncharge_beancounter(struct user_beancounter *ub, int resource, ++ unsigned long val); ++void __charge_beancounter_notop(struct user_beancounter *ub, int resource, ++ unsigned long val); ++void __uncharge_beancounter_notop(struct user_beancounter *ub, int resource, ++ unsigned long val); ++ ++static inline void charge_beancounter_notop(struct user_beancounter *ub, ++ int resource, unsigned long val) ++{ ++ if (ub->parent != NULL) ++ __charge_beancounter_notop(ub, resource, val); ++} ++ ++static inline void uncharge_beancounter_notop(struct user_beancounter *ub, ++ int resource, unsigned long val) ++{ ++ if (ub->parent != NULL) ++ __uncharge_beancounter_notop(ub, resource, val); ++} ++ ++#endif /* CONFIG_BEANCOUNTERS */ ++ ++#ifndef CONFIG_BC_RSS_ACCOUNTING ++static inline void ub_ini_pbc(void) { } ++#else ++extern void ub_init_pbc(void); ++#endif ++#endif /* __KERNEL__ */ ++#endif /* _LINUX_BEANCOUNTER_H */ +Index: kernel/include/bc/dcache.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/dcache.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,49 @@ ++/* ++ * include/bc/dcache.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __BC_DCACHE_H_ ++#define __BC_DCACHE_H_ ++ ++#include ++ ++/* ++ * UB_DCACHESIZE accounting ++ */ ++ ++struct dentry_beancounter ++{ ++ /* ++ * d_inuse = ++ * + ++ * ++ * ++ * d_inuse == -1 means that dentry is unused ++ * state change -1 => 0 causes charge ++ * state change 0 => -1 causes uncharge ++ */ ++ atomic_t d_inuse; ++ /* charged size, including name length if name is not inline */ ++ unsigned long d_ubsize; ++ struct user_beancounter *d_ub; ++}; ++ ++#ifdef CONFIG_BEANCOUNTERS ++#define ub_dget_testone(d) (atomic_inc_and_test(&(d)->dentry_bc.d_inuse)) ++#define ub_dput_testzero(d) (atomic_add_negative(-1, &(d)->dentry_bc.d_inuse)) ++#define INUSE_INIT 0 ++ ++extern int ub_dentry_on; ++extern void ub_dentry_checkup(void); ++#else ++#define ub_dget_testone(d) (0) ++#define ub_dput_testzero(d) (0) ++#define ub_dentry_checkup() do { } while (0) ++#endif ++#endif +Index: kernel/include/bc/dcache_op.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/dcache_op.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,100 @@ ++/* ++ * include/bc/dcache_op.h ++ * ++ * Copyright (C) 2006 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __BC_DCACHE_OP_H_ ++#define __BC_DCACHE_OP_H_ ++ ++struct dentry; ++ ++#ifdef CONFIG_BEANCOUNTERS ++ ++#include ++#include ++#include ++ ++extern int ub_dentry_alloc_barrier; ++extern spinlock_t dcache_lock; ++ ++static inline int ub_dentry_alloc(struct dentry *d) ++{ ++ extern int __ub_dentry_alloc(struct dentry *); ++ ++ if (!ub_dentry_on) ++ return 0; ++ return __ub_dentry_alloc(d); ++} ++ ++static inline void ub_dentry_alloc_start(void) ++{ ++ extern void __ub_dentry_alloc_start(void); ++ ++ if (ub_dentry_alloc_barrier) ++ __ub_dentry_alloc_start(); ++} ++ ++static inline void ub_dentry_alloc_end(void) ++{ ++ extern void __ub_dentry_alloc_end(void); ++ ++ if (current->task_bc.dentry_alloc) ++ __ub_dentry_alloc_end(); ++} ++ ++static inline int ub_dentry_charge(struct dentry *d) ++{ ++ extern int __ub_dentry_charge(struct dentry *); ++ ++ if (!ub_dentry_on) ++ return 0; ++ return __ub_dentry_charge(d); ++} ++ ++static inline void ub_dentry_charge_nofail(struct dentry *d) ++{ ++ extern void __ub_dentry_charge_nofail(struct dentry *); ++ ++ if (!ub_dentry_on) ++ return; ++ __ub_dentry_charge_nofail(d); ++} ++ ++static inline void ub_dentry_uncharge_locked(struct dentry *d) ++{ ++ extern void __ub_dentry_uncharge(struct dentry *); ++ ++ if (!ub_dentry_on) ++ return; ++ __ub_dentry_uncharge(d); ++} ++ ++static inline void ub_dentry_uncharge(struct dentry *d) ++{ ++ extern void __ub_dentry_uncharge(struct dentry *); ++ ++ if (!ub_dentry_on) ++ return; ++ spin_lock(&dcache_lock); ++ __ub_dentry_uncharge(d); ++ spin_unlock(&dcache_lock); ++} ++ ++#else /* CONFIG_BEANCOUNTERS */ ++ ++static inline int ub_dentry_alloc(struct dentry *d) { return 0; } ++static inline void ub_dentry_alloc_start(void) { } ++static inline void ub_dentry_alloc_end(void) { } ++static inline int ub_dentry_charge(struct dentry *d) { return 0; } ++static inline void ub_dentry_charge_nofail(struct dentry *d) { } ++static inline void ub_dentry_uncharge_locked(struct dentry *d) { } ++static inline void ub_dentry_uncharge(struct dentry *d) { } ++ ++#endif /* CONFIG_BEANCOUNTERS */ ++ ++#endif /* __dcache_op.h_ */ +Index: kernel/include/bc/debug.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/debug.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,109 @@ ++/* ++ * include/bc/debug.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __BC_DEBUG_H_ ++#define __BC_DEBUG_H_ ++ ++/* ++ * general debugging ++ */ ++ ++#define UBD_ALLOC 0x1 ++#define UBD_CHARGE 0x2 ++#define UBD_LIMIT 0x4 ++#define UBD_TRACE 0x8 ++ ++/* ++ * ub_net debugging ++ */ ++ ++#define UBD_NET_SOCKET 0x10 ++#define UBD_NET_SLEEP 0x20 ++#define UBD_NET_SEND 0x40 ++#define UBD_NET_RECV 0x80 ++ ++/* ++ * Main routines ++ */ ++ ++#define UB_DEBUG (0) ++#define DEBUG_RESOURCE (0ULL) ++ ++#define ub_dbg_cond(__cond, __str, args...) \ ++ do { \ ++ if ((__cond) != 0) \ ++ printk(__str, ##args); \ ++ } while(0) ++ ++#define ub_debug(__section, __str, args...) \ ++ ub_dbg_cond(UB_DEBUG & (__section), __str, ##args) ++ ++#define ub_debug_resource(__resource, __str, args...) \ ++ ub_dbg_cond((UB_DEBUG & UBD_CHARGE) && \ ++ (DEBUG_RESOURCE & (1 << (__resource))), \ ++ __str, ##args) ++ ++#if UB_DEBUG & UBD_TRACE ++#define ub_debug_trace(__cond, __b, __r) \ ++ do { \ ++ static struct ub_rate_info ri = { __b, __r }; \ ++ if ((__cond) != 0 && ub_ratelimit(&ri)) \ ++ dump_stack(); \ ++ } while(0) ++#else ++#define ub_debug_trace(__cond, __burst, __rate) ++#endif ++ ++#ifdef CONFIG_BC_DEBUG_KMEM ++#include ++ ++struct user_beancounter; ++struct ub_cache_counter { ++ struct list_head ulist; ++ struct ub_cache_counter *next; ++ struct user_beancounter *ub; ++ struct kmem_cache *cachep; ++ unsigned long counter; ++}; ++ ++extern spinlock_t cc_lock; ++extern void init_cache_counters(void); ++extern void ub_free_counters(struct user_beancounter *); ++extern void ub_kmemcache_free(struct kmem_cache *cachep); ++ ++struct vm_struct; ++#define inc_vmalloc_charged(vm, flags) do { \ ++ if (flags & __GFP_UBC) \ ++ ub_percpu_add(get_exec_ub(), vmalloc_charged, \ ++ vm->nr_pages); \ ++ } while (0) ++#define dec_vmalloc_charged(vm) do { \ ++ struct user_beancounter *ub; \ ++ ub = page_ub(vm->pages[0]); \ ++ if (ub != NULL) \ ++ ub_percpu_sub(ub, vmalloc_charged, \ ++ vm->nr_pages); \ ++ } while (0) ++ ++#define inc_pbc_count(ub) ub_percpu_inc(ub, pbcs) ++#define dec_pbc_count(ub) ub_percpu_dec(ub, pbcs) ++#else ++#define init_cache_counters() do { } while (0) ++#define inc_vmalloc_charged(vm, f) do { } while (0) ++#define dec_vmalloc_charged(vm) do { } while (0) ++ ++#define inc_pbc_count(ub) do { } while (0) ++#define dec_pbc_count(ub) do { } while (0) ++ ++#define ub_free_counters(ub) do { } while (0) ++#define ub_kmemcache_free(cachep) do { } while (0) ++#endif ++ ++#endif +Index: kernel/include/bc/decl.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/decl.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,41 @@ ++/* ++ * include/bc/decl.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __BC_DECL_H_ ++#define __BC_DECL_H_ ++ ++#ifdef __KERNEL__ ++ ++/* ++ * Naming convension: ++ * ub__ ++ */ ++ ++#ifdef CONFIG_BEANCOUNTERS ++ ++#define UB_DECLARE_FUNC(ret_type, decl) extern ret_type decl; ++#define UB_DECLARE_VOID_FUNC(decl) extern void decl; ++ ++#else /* CONFIG_BEANCOUNTERS */ ++ ++#define UB_DECLARE_FUNC(ret_type, decl) \ ++ static inline ret_type decl \ ++ { \ ++ return (ret_type)0; \ ++ } ++#define UB_DECLARE_VOID_FUNC(decl) \ ++ static inline void decl \ ++ { \ ++ } ++ ++#endif /* CONFIG_BEANCOUNTERS */ ++#endif ++ ++#endif +Index: kernel/include/bc/hash.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/hash.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,36 @@ ++/* ++ * include/bc/hash.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef _LINUX_UBHASH_H ++#define _LINUX_UBHASH_H ++ ++#ifdef __KERNEL__ ++ ++#define UB_HASH_SIZE 256 ++ ++extern struct hlist_head ub_hash[]; ++extern spinlock_t ub_hash_lock; ++extern struct list_head ub_list_head; ++ ++#ifdef CONFIG_BEANCOUNTERS ++ ++/* ++ * Iterate over beancounters ++ * @__ubp - beancounter ptr ++ * Can use break :) ++ */ ++#define for_each_beancounter(__ubp) \ ++ list_for_each_entry_rcu(__ubp, &ub_list_head, ub_list) \ ++ ++#define bc_hash_entry(ptr) hlist_entry(ptr, struct user_beancounter, ub_hash) ++ ++#endif /* CONFIG_BEANCOUNTERS */ ++#endif /* __KERNEL__ */ ++#endif /* _LINUX_UBHASH_H */ +Index: kernel/include/bc/io_acct.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/io_acct.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,113 @@ ++/* ++ * include/bc/io_acct.h ++ * ++ * Copyright (C) 2006 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * Pavel Emelianov ++ * ++ */ ++ ++#ifndef __UB_IO_ACCT_H_ ++#define __UB_IO_ACCT_H_ ++ ++#ifdef CONFIG_BC_IO_ACCOUNTING ++#include ++#include ++ ++#define page_iopb(page) ({ \ ++ struct page_beancounter *pb; \ ++ pb = page_pbc(page); \ ++ rmb(); \ ++ pb; \ ++ }) ++ ++/* ++ * IO ub is required in task context only, so if exec_ub is set ++ * to NULL this means that uses doesn't need to charge some ++ * resources. nevertheless IO activity must be accounted, so we ++ * account it to current's task beancounter. ++ */ ++ ++static inline struct user_beancounter *get_io_ub(void) ++{ ++ struct user_beancounter *ub; ++ ++ ub = get_exec_ub(); ++ if (unlikely(ub == NULL)) ++ ub = get_task_ub(current); ++ ++ return top_beancounter(ub); ++} ++ ++extern struct page_beancounter **page_pblist(struct page *); ++ ++extern void ub_io_save_context(struct page *, size_t); ++extern void ub_io_release_context(struct page *pg, size_t size); ++ ++#define PAGE_IO_MARK (0x1UL) ++ ++static inline struct page_beancounter *iopb_to_pb(struct page_beancounter *pb) ++{ ++ if (!((unsigned long)pb & PAGE_IO_MARK)) ++ return NULL; ++ ++ return (struct page_beancounter *)((unsigned long)pb & ~PAGE_IO_MARK); ++} ++ ++static inline void ub_io_account_read(size_t bytes) ++{ ++ ub_percpu_add(get_io_ub(), bytes_read, bytes); ++} ++ ++static inline void ub_io_account_write(size_t bytes) ++{ ++ ub_percpu_add(get_io_ub(), bytes_wrote, bytes); ++} ++ ++static inline void ub_io_account_dirty(struct page *page, size_t bytes) ++{ ++ ub_io_save_context(page, bytes); ++} ++ ++static inline void ub_io_account_write_cancelled(size_t bytes) ++{ ++ ub_percpu_add(get_io_ub(), bytes_cancelled, bytes); ++} ++ ++void ub_init_io(struct kmem_cache *); ++#else /* BC_IO_ACCOUNTING */ ++#define page_iopb(page) (NULL) ++#define page_pblist(page) (&page_pbc(page)) ++ ++static inline void ub_io_release_context(struct page *pg, size_t bytes) ++{ ++} ++ ++static inline void ub_io_account_dirty(struct page *p, size_t bytes) ++{ ++} ++ ++static inline void ub_io_account_read(size_t bytes) ++{ ++} ++ ++static inline void ub_io_account_write(size_t bytes) ++{ ++} ++ ++static inline void ub_io_account_write_cancelled(size_t bytes) ++{ ++} ++ ++static inline void ub_init_io(struct kmem_cache *pb_cachep) { }; ++#endif ++ ++#ifdef CONFIG_BC_DEBUG_IO ++extern void ub_io_release_debug(struct page *pg); ++#else ++#define ub_io_release_debug(pg) do { } while (0) ++#endif ++#endif +Index: kernel/include/bc/io_prio.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/io_prio.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,82 @@ ++/* ++ * include/bc/io_prio.h ++ * ++ * Copyright (C) 2007 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * Vasily Tarasov ++ * ++ */ ++ ++#ifndef _UB_IO_PRIO_H ++#define _UB_IO_PRIO_H ++ ++#include ++#include ++#include ++ ++#define UB_IOPRIO_MIN 0 ++#define UB_IOPRIO_MAX IOPRIO_BE_NR ++#define UB_IOPRIO_BASE 4 ++ ++struct ub_iopriv { ++ struct list_head cfq_bc_head; ++ rwlock_t cfq_bc_list_lock; ++ ++ unsigned int ioprio; ++}; ++ ++struct cfq_data; ++struct cfq_queue; ++ ++#ifdef CONFIG_BC_IO_SCHED ++extern void bc_init_ioprio(struct ub_iopriv *); ++extern void bc_fini_ioprio(struct ub_iopriv *); ++extern struct cfq_bc_data * bc_find_cfq_bc(struct ub_iopriv *, ++ struct cfq_data *); ++extern struct cfq_bc_data * bc_findcreate_cfq_bc(struct ub_iopriv *, ++ struct cfq_data *, gfp_t gfp_mask); ++extern void bc_cfq_exit_queue(struct cfq_data *); ++extern int bc_expired(struct cfq_data *); ++extern void bc_schedule_active(struct cfq_data *); ++extern void bc_inc_rqnum(struct cfq_queue *); ++extern void bc_dec_rqnum(struct cfq_queue *); ++extern unsigned long bc_set_ioprio(int, int); ++extern struct cfq_bc_data * ++__find_cfq_bc(struct ub_iopriv *iopriv, struct cfq_data *cfqd); ++extern struct user_beancounter *bc_io_switch_context(struct page *); ++extern void bc_io_restore_context(struct user_beancounter *); ++#else ++#include ++static inline void bc_init_ioprio(struct ub_iopriv *iopriv) { ; } ++static inline void bc_fini_ioprio(struct ub_iopriv *iopriv) { ; } ++static inline struct cfq_bc_data * ++bc_findcreate_cfq_bc(struct ub_iopriv *iopriv, ++ struct cfq_data *cfqd, gfp_t mask) ++{ ++ return &cfqd->cfq_bc; ++} ++static inline void bc_cfq_exit_queue(struct cfq_data *cfqd) { ; } ++static inline int bc_expired(struct cfq_data *cfqd) { return 0; } ++static inline void bc_schedule_active(struct cfq_data *cfqd) ++{ ++ cfqd->active_cfq_bc = &cfqd->cfq_bc; ++} ++static inline void bc_inc_rqnum(struct cfq_queue *cfqq) { ; } ++static inline void bc_dec_rqnum(struct cfq_queue *cfqq) { ; } ++static inline unsigned long bc_set_ioprio(int ubid, int ioprio) ++{ ++ return -EINVAL; ++} ++static inline struct cfq_bc_data * ++__find_cfq_bc(struct ub_iopriv *iopriv, struct cfq_data *cfqd) ++{ ++ return &cfqd->cfq_bc; ++} ++static inline struct user_beancounter * ++bc_io_switch_context(struct page *page) { return NULL; } ++static inline void bc_io_restore_context(struct user_beancounter *ub) { ; } ++#endif /* CONFIG_BC_IO_SCHED */ ++#endif /* _UB_IO_PRIO_H */ +Index: kernel/include/bc/kmem.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/kmem.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,69 @@ ++/* ++ * include/bc/kmem.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __UB_SLAB_H_ ++#define __UB_SLAB_H_ ++ ++#include ++#include ++ ++/* ++ * UB_KMEMSIZE accounting ++ */ ++ ++#ifdef CONFIG_BC_DEBUG_ITEMS ++#define CHARGE_ORDER(__o) (1 << (__o)) ++#define CHARGE_SIZE(__s) 1 ++#else ++#define CHARGE_ORDER(__o) (PAGE_SIZE << (__o)) ++#define CHARGE_SIZE(__s) (__s) ++#endif ++ ++#ifdef CONFIG_BEANCOUNTERS ++#define page_ub(__page) ((__page)->bc.page_ub) ++#else ++#define page_ub(__page) NULL ++#endif ++ ++struct mm_struct; ++struct page; ++struct kmem_cache; ++ ++UB_DECLARE_FUNC(struct user_beancounter *, vmalloc_ub(void *obj)) ++UB_DECLARE_FUNC(struct user_beancounter *, mem_ub(void *obj)) ++ ++UB_DECLARE_FUNC(int, ub_kmemsize_charge(struct user_beancounter *ub, ++ unsigned long size, enum ub_severity strict)) ++UB_DECLARE_VOID_FUNC(ub_kmemsize_uncharge(struct user_beancounter *ub, ++ unsigned long size)) ++ ++UB_DECLARE_FUNC(int, ub_page_charge(struct page *page, int order, gfp_t mask)) ++UB_DECLARE_VOID_FUNC(ub_page_uncharge(struct page *page, int order)) ++UB_DECLARE_FUNC(int, ub_slab_charge(struct kmem_cache *cachep, ++ void *objp, gfp_t flags)) ++UB_DECLARE_VOID_FUNC(ub_slab_uncharge(struct kmem_cache *cachep, void *obj)) ++ ++#ifdef CONFIG_BEANCOUNTERS ++static inline int should_charge(struct kmem_cache *cachep, gfp_t flags) ++{ ++ if (!(cachep->flags & SLAB_UBC)) ++ return 0; ++ if ((cachep->flags & SLAB_NO_CHARGE) && !(flags & __GFP_UBC)) ++ return 0; ++ return 1; ++} ++ ++#define should_uncharge(cachep) should_charge(cachep, __GFP_UBC) ++#else ++#define should_charge(cache, f) 0 ++#define should_uncharge(cache) 0 ++#endif ++ ++#endif /* __UB_SLAB_H_ */ +Index: kernel/include/bc/misc.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/misc.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,55 @@ ++/* ++ * include/bc/misc.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __BC_MISC_H_ ++#define __BC_MISC_H_ ++ ++#include ++ ++struct tty_struct; ++struct file; ++struct file_lock; ++struct sigqueue; ++ ++UB_DECLARE_FUNC(int, ub_file_charge(struct file *f)) ++UB_DECLARE_VOID_FUNC(ub_file_uncharge(struct file *f)) ++UB_DECLARE_FUNC(int, ub_flock_charge(struct file_lock *fl, int hard)) ++UB_DECLARE_VOID_FUNC(ub_flock_uncharge(struct file_lock *fl)) ++UB_DECLARE_FUNC(int, ub_siginfo_charge(struct sigqueue *q, ++ struct user_beancounter *ub)) ++UB_DECLARE_VOID_FUNC(ub_siginfo_uncharge(struct sigqueue *q)) ++UB_DECLARE_FUNC(int, ub_task_charge(struct task_struct *parent, ++ struct task_struct *task)) ++UB_DECLARE_VOID_FUNC(ub_task_uncharge(struct task_struct *task)) ++UB_DECLARE_VOID_FUNC(ub_task_put(struct task_struct *task)) ++UB_DECLARE_FUNC(int, ub_pty_charge(struct tty_struct *tty)) ++UB_DECLARE_VOID_FUNC(ub_pty_uncharge(struct tty_struct *tty)) ++ ++#ifdef CONFIG_BEANCOUNTERS ++#define set_flock_charged(fl) do { (fl)->fl_charged = 1; } while (0) ++#define unset_flock_charged(fl) do { \ ++ WARN_ON((fl)->fl_charged == 0); \ ++ (fl)->fl_charged = 0; \ ++ } while (0) ++#define set_mm_ub(mm, tsk) do { \ ++ (mm)->mm_ub = get_beancounter(tsk ? \ ++ tsk->task_bc.task_ub : get_exec_ub()); \ ++ } while (0) ++#define put_mm_ub(mm) do { \ ++ put_beancounter((mm)->mm_ub); \ ++ (mm)->mm_ub = NULL; \ ++ } while (0) ++#else ++#define set_flock_charged(fl) do { } while (0) ++#define unset_flock_charged(fl) do { } while (0) ++#define set_mm_ub(mm, tsk) do { } while (0) ++#define put_mm_ub(mm) do { } while (0) ++#endif ++#endif +Index: kernel/include/bc/net.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/net.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,215 @@ ++/* ++ * include/bc/net.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __BC_NET_H_ ++#define __BC_NET_H_ ++ ++/* ++ * UB_NUMXXXSOCK, UB_XXXBUF accounting ++ */ ++ ++#include ++#include ++#include ++ ++#define bid2sid(__bufid) \ ++ ((__bufid) == UB_TCPSNDBUF ? UB_NUMTCPSOCK : UB_NUMOTHERSOCK) ++ ++#define SOCK_MIN_UBCSPACE ((int)((2048 - sizeof(struct skb_shared_info)) & \ ++ ~(SMP_CACHE_BYTES-1))) ++#define SOCK_MIN_UBCSPACE_CH skb_charge_size(SOCK_MIN_UBCSPACE) ++ ++static inline int ub_skb_alloc_bc(struct sk_buff *skb, gfp_t gfp_mask) ++{ ++#ifdef CONFIG_BEANCOUNTERS ++ memset(skb_bc(skb), 0, sizeof(struct skb_beancounter)); ++#endif ++ return 0; ++} ++ ++static inline void ub_skb_free_bc(struct sk_buff *skb) ++{ ++} ++ ++#define IS_TCP_SOCK(__family, __type) \ ++ (((__family) == PF_INET || (__family) == PF_INET6) && (__type) == SOCK_STREAM) ++ ++/* number of sockets */ ++UB_DECLARE_FUNC(int, ub_sock_charge(struct sock *sk, int family, int type)) ++UB_DECLARE_FUNC(int, ub_tcp_sock_charge(struct sock *sk)) ++UB_DECLARE_FUNC(int, ub_other_sock_charge(struct sock *sk)) ++UB_DECLARE_VOID_FUNC(ub_sock_uncharge(struct sock *sk)) ++ ++/* management of queue for send space */ ++UB_DECLARE_FUNC(long, ub_sock_wait_for_space(struct sock *sk, long timeo, ++ unsigned long size)) ++UB_DECLARE_VOID_FUNC(ub_sock_snd_queue_add(struct sock *sk, int resource, ++ unsigned long size)) ++UB_DECLARE_VOID_FUNC(ub_sock_sndqueuedel(struct sock *sk)) ++ ++/* send space */ ++UB_DECLARE_FUNC(int, ub_sock_make_wreserv(struct sock *sk, int bufid, ++ unsigned long size)) ++UB_DECLARE_FUNC(int, ub_sock_get_wreserv(struct sock *sk, int bufid, ++ unsigned long size)) ++UB_DECLARE_VOID_FUNC(ub_sock_ret_wreserv(struct sock *sk, int bufid, ++ unsigned long size, unsigned long ressize)) ++UB_DECLARE_FUNC(int, ub_sock_tcp_chargesend(struct sock *sk, ++ struct sk_buff *skb, enum ub_severity strict)) ++UB_DECLARE_VOID_FUNC(ub_sock_tcp_unchargesend(struct sock *sk, ++ unsigned long size)) ++UB_DECLARE_FUNC(int, ub_sock_tcp_chargepage(struct sock *sk)) ++UB_DECLARE_VOID_FUNC(ub_sock_tcp_detachpage(struct sock *sk)) ++ ++UB_DECLARE_FUNC(int, ub_nlrcvbuf_charge(struct sk_buff *skb, struct sock *sk)) ++ ++/* receive space */ ++UB_DECLARE_FUNC(int, ub_sockrcvbuf_charge(struct sock *sk, struct sk_buff *skb)) ++UB_DECLARE_FUNC(int, ub_sock_tcp_chargerecv(struct sock *sk, ++ struct sk_buff *skb, enum ub_severity strict)) ++ ++/* skb destructor */ ++UB_DECLARE_VOID_FUNC(ub_skb_uncharge(struct sk_buff *skb)) ++ ++static inline int ub_sock_makewres_other(struct sock *sk, unsigned long size) ++{ ++ return ub_sock_make_wreserv(sk, UB_OTHERSOCKBUF, size); ++} ++ ++static inline int ub_sock_makewres_tcp(struct sock *sk, unsigned long size) ++{ ++ return ub_sock_make_wreserv(sk, UB_TCPSNDBUF, size); ++} ++ ++UB_DECLARE_FUNC(int, ub_sock_getwres_other(struct sock *sk, ++ unsigned long size)) ++ ++static inline int ub_sock_getwres_tcp(struct sock *sk, unsigned long size) ++{ ++ return ub_sock_get_wreserv(sk, UB_TCPSNDBUF, size); ++} ++ ++UB_DECLARE_VOID_FUNC(ub_sock_retwres_other(struct sock *sk, ++ unsigned long size, unsigned long ressize)) ++ ++static inline void ub_sock_retwres_tcp(struct sock *sk, unsigned long size, ++ unsigned long ressize) ++{ ++ ub_sock_ret_wreserv(sk, UB_TCPSNDBUF, size, ressize); ++} ++ ++static inline void ub_sock_sndqueueadd_other(struct sock *sk, unsigned long sz) ++{ ++ ub_sock_snd_queue_add(sk, UB_OTHERSOCKBUF, sz); ++} ++ ++static inline void ub_sock_sndqueueadd_tcp(struct sock *sk, unsigned long sz) ++{ ++ ub_sock_snd_queue_add(sk, UB_TCPSNDBUF, sz); ++} ++ ++static inline int ub_tcpsndbuf_charge(struct sock *sk, ++ struct sk_buff *skb) ++{ ++ return ub_sock_tcp_chargesend(sk, skb, UB_HARD); ++} ++ ++static inline int ub_tcpsndbuf_charge_forced(struct sock *sk, ++ struct sk_buff *skb) ++{ ++ return ub_sock_tcp_chargesend(sk, skb, UB_FORCE); ++} ++ ++static inline int ub_tcprcvbuf_charge(struct sock *sk, struct sk_buff *skb) ++{ ++ return ub_sock_tcp_chargerecv(sk, skb, UB_SOFT); ++} ++ ++static inline int ub_tcprcvbuf_charge_forced(struct sock *sk, ++ struct sk_buff *skb) ++{ ++ return ub_sock_tcp_chargerecv(sk, skb, UB_FORCE); ++} ++ ++/* Charge size */ ++static inline unsigned long skb_charge_datalen(unsigned long chargesize) ++{ ++#ifdef CONFIG_BEANCOUNTERS ++ unsigned long slabsize; ++ ++ chargesize -= sizeof(struct sk_buff); ++ slabsize = 64; ++ do { ++ slabsize <<= 1; ++ } while (slabsize <= chargesize); ++ ++ slabsize >>= 1; ++ return (slabsize - sizeof(struct skb_shared_info)) & ++ ~(SMP_CACHE_BYTES-1); ++#else ++ return 0; ++#endif ++} ++ ++static inline unsigned long skb_charge_size_gen(unsigned long size) ++{ ++#ifdef CONFIG_BEANCOUNTERS ++ unsigned int slabsize; ++ ++ size = SKB_DATA_ALIGN(size) + sizeof(struct skb_shared_info); ++ slabsize = 32; /* min size is 64 because of skb_shared_info */ ++ do { ++ slabsize <<= 1; ++ } while (slabsize < size); ++ ++ return slabsize + sizeof(struct sk_buff); ++#else ++ return 0; ++#endif ++ ++} ++ ++static inline unsigned long skb_charge_size_const(unsigned long size) ++{ ++#ifdef CONFIG_BEANCOUNTERS ++ unsigned int ret; ++ if (SKB_DATA_ALIGN(size) + sizeof(struct skb_shared_info) <= 64) ++ ret = 64 + sizeof(struct sk_buff); ++ else if (SKB_DATA_ALIGN(size) + sizeof(struct skb_shared_info) <= 128) ++ ret = 128 + sizeof(struct sk_buff); ++ else if (SKB_DATA_ALIGN(size) + sizeof(struct skb_shared_info) <= 256) ++ ret = 256 + sizeof(struct sk_buff); ++ else if (SKB_DATA_ALIGN(size) + sizeof(struct skb_shared_info) <= 512) ++ ret = 512 + sizeof(struct sk_buff); ++ else if (SKB_DATA_ALIGN(size) + sizeof(struct skb_shared_info) <= 1024) ++ ret = 1024 + sizeof(struct sk_buff); ++ else if (SKB_DATA_ALIGN(size) + sizeof(struct skb_shared_info) <= 2048) ++ ret = 2048 + sizeof(struct sk_buff); ++ else if (SKB_DATA_ALIGN(size) + sizeof(struct skb_shared_info) <= 4096) ++ ret = 4096 + sizeof(struct sk_buff); ++ else ++ ret = skb_charge_size_gen(size); ++ return ret; ++#else ++ return 0; ++#endif ++} ++ ++ ++#define skb_charge_size(__size) \ ++ (__builtin_constant_p(__size) ? \ ++ skb_charge_size_const(__size) : \ ++ skb_charge_size_gen(__size)) ++ ++UB_DECLARE_FUNC(int, skb_charge_fullsize(struct sk_buff *skb)) ++UB_DECLARE_VOID_FUNC(ub_skb_set_charge(struct sk_buff *skb, ++ struct sock *sk, unsigned long size, int res)) ++ ++#endif +Index: kernel/include/bc/oom_kill.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/oom_kill.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,26 @@ ++#include ++#include ++ ++UB_DECLARE_FUNC(int, ub_oom_lock(void)) ++UB_DECLARE_FUNC(struct user_beancounter *, ub_oom_select_worst(void)) ++UB_DECLARE_VOID_FUNC(ub_oom_mm_killed(struct user_beancounter *ub)) ++UB_DECLARE_VOID_FUNC(ub_oom_unlock(void)) ++UB_DECLARE_VOID_FUNC(ub_out_of_memory(struct user_beancounter *ub)) ++UB_DECLARE_VOID_FUNC(ub_oom_task_dead(struct task_struct *tsk)) ++UB_DECLARE_FUNC(int, ub_oom_task_skip(struct user_beancounter *ub, ++ struct task_struct *tsk)) ++ ++#ifdef CONFIG_BEANCOUNTERS ++extern int oom_generation; ++extern int oom_kill_counter; ++#define ub_oom_start() do { \ ++ current->task_bc.oom_generation = oom_generation; \ ++ } while (0) ++#define ub_oom_task_killed(p) do { \ ++ oom_kill_counter++; \ ++ wake_up_process(p); \ ++ } while (0) ++#else ++#define ub_oom_start() do { } while (0) ++#define ub_oom_task_killed(p) do { } while (0) ++#endif +Index: kernel/include/bc/proc.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/proc.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,40 @@ ++/* ++ * include/bc/proc.h ++ * ++ * Copyright (C) 2006 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __UB_PROC_H_ ++#define __UB_PROC_H_ ++ ++#include ++ ++struct bc_proc_entry { ++ char *name; ++ union { ++ int (*show)(struct seq_file *, void *); ++ struct file_operations *fops; ++ } u; ++ struct bc_proc_entry *next; ++ int cookie; ++}; ++ ++struct user_beancounter; ++ ++void bc_register_proc_entry(struct bc_proc_entry *); ++void bc_register_proc_root_entry(struct bc_proc_entry *); ++ ++static inline struct user_beancounter *seq_beancounter(struct seq_file *f) ++{ ++ return (struct user_beancounter *)(f->private); ++} ++ ++extern const char *bc_proc_lu_fmt; ++extern const char *bc_proc_lu_lfmt; ++extern const char *bc_proc_llu_fmt; ++extern const char *bc_proc_lu_lu_fmt; ++#endif +Index: kernel/include/bc/rss_pages.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/rss_pages.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,57 @@ ++/* ++ * include/bc/rss_pages.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __RSS_PAGES_H_ ++#define __RSS_PAGES_H_ ++ ++/* ++ * Page_beancounters ++ */ ++ ++struct page; ++struct user_beancounter; ++ ++#define PB_MAGIC 0x62700001UL ++ ++struct page_beancounter { ++ unsigned long pb_magic; ++ struct page *page; ++ struct user_beancounter *ub; ++ union { ++ struct page_beancounter *next_hash; ++ struct page_beancounter *page_pb_list; ++ }; ++ union { ++ unsigned refcount; ++ unsigned io_debug; ++ }; ++ union { ++ struct list_head page_list; ++ struct list_head io_list; ++ }; ++}; ++ ++#define PB_REFCOUNT_BITS 24 ++#define PB_SHIFT_GET(c) ((c) >> PB_REFCOUNT_BITS) ++#define PB_SHIFT_INC(c) ((c) += (1 << PB_REFCOUNT_BITS)) ++#define PB_SHIFT_DEC(c) ((c) -= (1 << PB_REFCOUNT_BITS)) ++#define PB_COUNT_GET(c) ((c) & ((1 << PB_REFCOUNT_BITS) - 1)) ++#define PB_COUNT_INC(c) ((c)++) ++#define PB_COUNT_DEC(c) ((c)--) ++#define PB_REFCOUNT_MAKE(s, c) (((s) << PB_REFCOUNT_BITS) + (c)) ++ ++#define page_pbc(__page) ((__page)->bc.page_pb) ++ ++extern spinlock_t pb_lock; ++ ++struct address_space; ++extern int is_shmem_mapping(struct address_space *); ++ ++#endif +Index: kernel/include/bc/sock.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/sock.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,47 @@ ++/* ++ * include/bc/sock.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __BC_SOCK_H_ ++#define __BC_SOCK_H_ ++ ++#include ++ ++struct sock; ++struct sk_buff; ++ ++struct skb_beancounter { ++ struct user_beancounter *ub; ++ unsigned long charged:27, resource:5; ++}; ++ ++struct sock_beancounter { ++ struct user_beancounter *ub; ++ /* ++ * poll_reserv accounts space already charged for future sends. ++ * It is required to make poll agree with sendmsg. ++ * Additionally, it makes real charges (with taking bc spinlock) ++ * in the send path rarer, speeding networking up. ++ * For TCP (only): changes are protected by socket lock (not bc!) ++ * For all proto: may be read without serialization in poll. ++ */ ++ unsigned long poll_reserv; ++ unsigned long forw_space; ++ /* fields below are protected by bc spinlock */ ++ unsigned long ub_waitspc; /* space waiting for */ ++ unsigned long ub_wcharged; ++ struct list_head ub_sock_list; ++}; ++ ++#define sock_bc(__sk) (&(__sk)->sk_bc) ++#define skb_bc(__skb) (&(__skb)->skb_bc) ++#define skbc_sock(__skbc) (container_of(__skbc, struct sock, sk_bc)) ++#define sock_has_ubc(__sk) (sock_bc(__sk)->ub != NULL) ++ ++#endif +Index: kernel/include/bc/sock_orphan.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/sock_orphan.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,106 @@ ++/* ++ * include/bc/sock_orphan.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __BC_SOCK_ORPHAN_H_ ++#define __BC_SOCK_ORPHAN_H_ ++ ++#include ++ ++#include "bc/beancounter.h" ++#include "bc/net.h" ++ ++ ++static inline atomic_t *__ub_get_orphan_count_ptr(struct sock *sk) ++{ ++#ifdef CONFIG_BEANCOUNTERS ++ if (sock_has_ubc(sk)) ++ return &sock_bc(sk)->ub->ub_orphan_count; ++#endif ++ return sk->sk_prot->orphan_count; ++} ++ ++static inline void ub_inc_orphan_count(struct sock *sk) ++{ ++ atomic_inc(__ub_get_orphan_count_ptr(sk)); ++} ++ ++static inline void ub_dec_orphan_count(struct sock *sk) ++{ ++ atomic_dec(__ub_get_orphan_count_ptr(sk)); ++} ++ ++static inline int ub_get_orphan_count(struct sock *sk) ++{ ++ return atomic_read(__ub_get_orphan_count_ptr(sk)); ++} ++ ++extern int __ub_too_many_orphans(struct sock *sk, int count); ++static inline int ub_too_many_orphans(struct sock *sk, int count) ++{ ++#ifdef CONFIG_BEANCOUNTERS ++ if (__ub_too_many_orphans(sk, count)) ++ return 1; ++#endif ++ return (ub_get_orphan_count(sk) > sysctl_tcp_max_orphans || ++ (sk->sk_wmem_queued > SOCK_MIN_SNDBUF && ++ atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2])); ++} ++ ++#include ++ ++struct inet_timewait_sock; ++ ++static inline void ub_timewait_mod(struct inet_timewait_sock *tw, int incdec) ++{ ++#ifdef CONFIG_BEANCOUNTERS ++ struct user_beancounter *ub; ++ ++ ub = slab_ub(tw); ++ if (ub != NULL) ++ ub->ub_tw_count += incdec; ++#endif ++} ++ ++static inline int __ub_timewait_check(struct sock *sk) ++{ ++#ifdef CONFIG_BEANCOUNTERS ++ struct user_beancounter *ub; ++ unsigned long mem_max, mem; ++ int tw_count; ++ ++ ub = sock_bc(sk)->ub; ++ if (ub == NULL) ++ return 1; ++ ++ tw_count = ub->ub_tw_count; ++ mem_max = sysctl_tcp_max_tw_kmem_fraction * ++ ((ub->ub_parms[UB_KMEMSIZE].limit >> 10) + 1); ++ mem = kmem_cache_objuse(sk->sk_prot_creator->twsk_prot->twsk_slab); ++ mem *= tw_count; ++ return tw_count < sysctl_tcp_max_tw_buckets_ub && mem < mem_max; ++#else ++ return 1; ++#endif ++} ++ ++#define ub_timewait_inc(tw, twdr) do { \ ++ if ((twdr)->ub_managed) \ ++ ub_timewait_mod(tw, 1); \ ++ } while (0) ++ ++#define ub_timewait_dec(tw, twdr) do { \ ++ if ((twdr)->ub_managed) \ ++ ub_timewait_mod(tw, -1); \ ++ } while (0) ++ ++#define ub_timewait_check(sk, twdr) ((!(twdr)->ub_managed) || \ ++ __ub_timewait_check(sk)) ++ ++#endif +Index: kernel/include/bc/statd.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/statd.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,70 @@ ++/* ++ * include/bc/statd.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __BC_STATD_H_ ++#define __BC_STATD_H_ ++ ++/* sys_ubstat commands list */ ++#define UBSTAT_READ_ONE 0x010000 ++#define UBSTAT_READ_ALL 0x020000 ++#define UBSTAT_READ_FULL 0x030000 ++#define UBSTAT_UBLIST 0x040000 ++#define UBSTAT_UBPARMNUM 0x050000 ++#define UBSTAT_GETTIME 0x060000 ++ ++#define UBSTAT_CMD(func) ((func) & 0xF0000) ++#define UBSTAT_PARMID(func) ((func) & 0x0FFFF) ++ ++#define TIME_MAX_SEC (LONG_MAX / HZ) ++#define TIME_MAX_JIF (TIME_MAX_SEC * HZ) ++ ++typedef unsigned long ubstattime_t; ++ ++typedef struct { ++ ubstattime_t start_time; ++ ubstattime_t end_time; ++ ubstattime_t cur_time; ++} ubgettime_t; ++ ++typedef struct { ++ long maxinterval; ++ int signum; ++} ubnotifrq_t; ++ ++typedef struct { ++ unsigned long maxheld; ++ unsigned long failcnt; ++} ubstatparm_t; ++ ++typedef struct { ++ unsigned long barrier; ++ unsigned long limit; ++ unsigned long held; ++ unsigned long maxheld; ++ unsigned long minheld; ++ unsigned long failcnt; ++ unsigned long __unused1; ++ unsigned long __unused2; ++} ubstatparmf_t; ++ ++typedef struct { ++ ubstattime_t start_time; ++ ubstattime_t end_time; ++ ubstatparmf_t param[0]; ++} ubstatfull_t; ++ ++#ifdef __KERNEL__ ++struct ub_stat_notify { ++ struct list_head list; ++ struct task_struct *task; ++ int signum; ++}; ++#endif ++#endif +Index: kernel/include/bc/task.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/task.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,69 @@ ++/* ++ * include/bc/task.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __BC_TASK_H_ ++#define __BC_TASK_H_ ++ ++struct user_beancounter; ++ ++ ++#ifdef CONFIG_BEANCOUNTERS ++struct task_beancounter { ++ struct user_beancounter *exec_ub; ++ struct user_beancounter *saved_ub; ++ struct user_beancounter *task_ub; ++ struct user_beancounter *fork_sub; ++ unsigned long file_precharged, file_quant, file_count; ++ unsigned long kmem_precharged; ++ char dentry_alloc, pgfault_handle; ++ void *task_fnode, *task_freserv; ++ unsigned long oom_generation; ++ unsigned long task_data[4]; ++ unsigned long pgfault_allot; ++}; ++ ++#define get_task_ub(__task) ((__task)->task_bc.task_ub) ++ ++extern struct user_beancounter ub0; ++#define get_ub0() (&ub0) ++ ++#define ub_save_context(t) do { \ ++ t->task_bc.saved_ub = t->task_bc.exec_ub; \ ++ t->task_bc.exec_ub = get_ub0(); \ ++ } while (0) ++#define ub_restore_context(t) do { \ ++ t->task_bc.exec_ub = t->task_bc.saved_ub; \ ++ } while (0) ++ ++#define get_exec_ub() (current->task_bc.exec_ub) ++#define set_exec_ub(__newub) \ ++({ \ ++ struct user_beancounter *old; \ ++ struct task_beancounter *tbc; \ ++ \ ++ tbc = ¤t->task_bc; \ ++ old = tbc->exec_ub; \ ++ tbc->exec_ub = __newub; \ ++ old; \ ++}) ++ ++void ub_init_task_bc(struct task_beancounter *); ++ ++#else /* CONFIG_BEANCOUNTERS */ ++ ++#define get_ub0() (NULL) ++#define get_exec_ub() (NULL) ++#define get_task_ub(task) (NULL) ++#define set_exec_ub(__ub) (NULL) ++#define ub_save_context(t) do { } while (0) ++#define ub_restore_context(t) do { } while (0) ++ ++#endif /* CONFIG_BEANCOUNTERS */ ++#endif /* __task.h_ */ +Index: kernel/include/bc/tcp.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/tcp.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,76 @@ ++/* ++ * include/bc/tcp.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __BC_TCP_H_ ++#define __BC_TCP_H_ ++ ++/* ++ * UB_NUMXXXSOCK, UB_XXXBUF accounting ++ */ ++ ++#include ++#include ++ ++static inline void ub_tcp_update_maxadvmss(struct sock *sk) ++{ ++#ifdef CONFIG_BEANCOUNTERS ++ if (!sock_has_ubc(sk)) ++ return; ++ if (sock_bc(sk)->ub->ub_maxadvmss >= tcp_sk(sk)->advmss) ++ return; ++ ++ sock_bc(sk)->ub->ub_maxadvmss = ++ skb_charge_size(MAX_HEADER + sizeof(struct iphdr) ++ + sizeof(struct tcphdr) + tcp_sk(sk)->advmss); ++#endif ++} ++ ++static inline int ub_tcp_rmem_allows_expand(struct sock *sk) ++{ ++ if (tcp_memory_pressure) ++ return 0; ++#ifdef CONFIG_BEANCOUNTERS ++ if (sock_has_ubc(sk)) { ++ struct user_beancounter *ub; ++ ++ ub = sock_bc(sk)->ub; ++ if (ub->ub_rmem_pressure == UB_RMEM_EXPAND) ++ return 1; ++ if (ub->ub_rmem_pressure == UB_RMEM_SHRINK) ++ return 0; ++ return sk->sk_rcvbuf <= ub->ub_rmem_thres; ++ } ++#endif ++ return 1; ++} ++ ++static inline int ub_tcp_memory_pressure(struct sock *sk) ++{ ++ if (tcp_memory_pressure) ++ return 1; ++#ifdef CONFIG_BEANCOUNTERS ++ if (sock_has_ubc(sk)) ++ return sock_bc(sk)->ub->ub_rmem_pressure != UB_RMEM_EXPAND; ++#endif ++ return 0; ++} ++ ++static inline int ub_tcp_shrink_rcvbuf(struct sock *sk) ++{ ++ if (tcp_memory_pressure) ++ return 1; ++#ifdef CONFIG_BEANCOUNTERS ++ if (sock_has_ubc(sk)) ++ return sock_bc(sk)->ub->ub_rmem_pressure == UB_RMEM_SHRINK; ++#endif ++ return 0; ++} ++ ++#endif +Index: kernel/include/bc/vmpages.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/bc/vmpages.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,152 @@ ++/* ++ * include/bc/vmpages.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __UB_PAGES_H_ ++#define __UB_PAGES_H_ ++ ++#include ++#include ++#include ++ ++/* ++ * Check whether vma has private or copy-on-write mapping. ++ * Should match checks in ub_protected_charge(). ++ */ ++#define VM_UB_PRIVATE(__flags, __file) \ ++ ( ((__flags) & VM_WRITE) ? \ ++ (__file) == NULL || !((__flags) & VM_SHARED) : \ ++ 0 \ ++ ) ++ ++/* Mprotect charging result */ ++#define PRIVVM_ERROR -1 ++#define PRIVVM_NO_CHARGE 0 /* UB_DECLARE_FUNC retval with ubc off */ ++#define PRIVVM_TO_PRIVATE 1 ++#define PRIVVM_TO_SHARED 2 ++ ++UB_DECLARE_FUNC(int, ub_protected_charge(struct mm_struct *mm, ++ unsigned long size, ++ unsigned long newflags, ++ struct vm_area_struct *vma)) ++ ++UB_DECLARE_VOID_FUNC(ub_unused_privvm_add(struct mm_struct *mm, ++ struct vm_area_struct *vma, ++ unsigned long num)) ++#define ub_unused_privvm_inc(mm, vma) ub_unused_privvm_add(mm, vma, 1) ++UB_DECLARE_VOID_FUNC(ub_unused_privvm_sub(struct mm_struct *mm, ++ struct vm_area_struct *vma, ++ unsigned long num)) ++#define ub_unused_privvm_dec(mm, vma) ub_unused_privvm_sub(mm, vma, 1) ++ ++UB_DECLARE_VOID_FUNC(__ub_unused_privvm_dec(struct mm_struct *mm, ++ long sz)) ++ ++UB_DECLARE_FUNC(int, ub_memory_charge(struct mm_struct *mm, ++ unsigned long size, ++ unsigned vm_flags, ++ struct file *vm_file, ++ int strict)) ++UB_DECLARE_VOID_FUNC(ub_memory_uncharge(struct mm_struct *mm, ++ unsigned long size, ++ unsigned vm_flags, ++ struct file *vm_file)) ++ ++struct shmem_inode_info; ++UB_DECLARE_FUNC(int, ub_shmpages_charge(struct shmem_inode_info *i, ++ unsigned long sz)) ++UB_DECLARE_VOID_FUNC(ub_shmpages_uncharge(struct shmem_inode_info *i, ++ unsigned long sz)) ++UB_DECLARE_VOID_FUNC(ub_tmpfs_respages_inc(struct shmem_inode_info *shi)) ++UB_DECLARE_VOID_FUNC(ub_tmpfs_respages_sub(struct shmem_inode_info *shi, ++ unsigned long size)) ++#define ub_tmpfs_respages_dec(shi) ub_tmpfs_respages_sub(shi, 1) ++ ++#ifdef CONFIG_BEANCOUNTERS ++#define shmi_ub_set(shi, ub) do { \ ++ (shi)->shmi_ub = get_beancounter(ub); \ ++ } while (0) ++#define shmi_ub_put(shi) do { \ ++ put_beancounter((shi)->shmi_ub); \ ++ (shi)->shmi_ub = NULL; \ ++ } while (0) ++#else ++#define shmi_ub_set(shi, ub) do { } while (0) ++#define shmi_ub_put(shi) do { } while (0) ++#endif ++ ++UB_DECLARE_FUNC(int, ub_locked_charge(struct mm_struct *mm, ++ unsigned long size)) ++UB_DECLARE_VOID_FUNC(ub_locked_uncharge(struct mm_struct *mm, ++ unsigned long size)) ++UB_DECLARE_FUNC(int, ub_lockedshm_charge(struct shmem_inode_info *shi, ++ unsigned long size)) ++UB_DECLARE_VOID_FUNC(ub_lockedshm_uncharge(struct shmem_inode_info *shi, ++ unsigned long size)) ++ ++UB_DECLARE_FUNC(unsigned long, pages_in_vma_range(struct vm_area_struct *vma, ++ unsigned long addr, unsigned long end)) ++#define pages_in_vma(vma) (pages_in_vma_range(vma, \ ++ vma->vm_start, vma->vm_end)) ++ ++#define UB_PAGE_WEIGHT_SHIFT 24 ++#define UB_PAGE_WEIGHT (1 << UB_PAGE_WEIGHT_SHIFT) ++ ++struct page_beancounter; ++#define PBC_COPY_SAME ((struct page_beancounter *) 1) ++ ++/* Mprotect charging result */ ++#define PRIVVM_ERROR -1 ++#define PRIVVM_NO_CHARGE 0 ++#define PRIVVM_TO_PRIVATE 1 ++#define PRIVVM_TO_SHARED 2 ++ ++extern void fastcall __ub_update_physpages(struct user_beancounter *ub); ++extern void fastcall __ub_update_oomguarpages(struct user_beancounter *ub); ++extern void fastcall __ub_update_privvm(struct user_beancounter *ub); ++ ++#ifdef CONFIG_BC_RSS_ACCOUNTING ++#define PB_DECLARE_FUNC(ret, decl) UB_DECLARE_FUNC(ret, decl) ++#define PB_DECLARE_VOID_FUNC(decl) UB_DECLARE_VOID_FUNC(decl) ++#else ++#define PB_DECLARE_FUNC(ret, decl) static inline ret decl {return (ret)0;} ++#define PB_DECLARE_VOID_FUNC(decl) static inline void decl { } ++#endif ++ ++PB_DECLARE_FUNC(int, pb_alloc(struct page_beancounter **pbc)) ++PB_DECLARE_FUNC(int, pb_alloc_list(struct page_beancounter **pbc, int num)) ++PB_DECLARE_FUNC(int, pb_alloc_all(struct page_beancounter **pbc)) ++PB_DECLARE_VOID_FUNC(pb_add_ref(struct page *page, ++ struct mm_struct *mm, ++ struct page_beancounter **pbc)) ++PB_DECLARE_VOID_FUNC(pb_dup_ref(struct page *page, ++ struct mm_struct *mm, ++ struct page_beancounter **pbc)) ++PB_DECLARE_VOID_FUNC(pb_free_list(struct page_beancounter **pb)) ++PB_DECLARE_VOID_FUNC(pb_free(struct page_beancounter **pb)) ++PB_DECLARE_VOID_FUNC(pb_remove_ref(struct page *page, ++ struct mm_struct *mm)) ++ ++PB_DECLARE_FUNC(struct user_beancounter *, pb_grab_page_ub(struct page *page)) ++#endif ++ ++#ifdef CONFIG_BC_SWAP_ACCOUNTING ++#define SWP_DECLARE_FUNC(ret, decl) UB_DECLARE_FUNC(ret, decl) ++#define SWP_DECLARE_VOID_FUNC(decl) UB_DECLARE_VOID_FUNC(decl) ++#else ++#define SWP_DECLARE_FUNC(ret, decl) static inline ret decl {return (ret)0;} ++#define SWP_DECLARE_VOID_FUNC(decl) static inline void decl { } ++#endif ++ ++struct swap_info_struct; ++SWP_DECLARE_FUNC(int, ub_swap_init(struct swap_info_struct *si, pgoff_t n)) ++SWP_DECLARE_VOID_FUNC(ub_swap_fini(struct swap_info_struct *si)) ++SWP_DECLARE_VOID_FUNC(ub_swapentry_inc(struct swap_info_struct *si, pgoff_t n, ++ struct user_beancounter *ub)) ++SWP_DECLARE_VOID_FUNC(ub_swapentry_dec(struct swap_info_struct *si, pgoff_t n)) +Index: kernel/include/linux/aio.h +=================================================================== +--- kernel.orig/include/linux/aio.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/aio.h 2008-11-24 15:47:46.000000000 +0100 +@@ -245,4 +245,8 @@ + extern unsigned long aio_nr; + extern unsigned long aio_max_nr; + ++void wait_for_all_aios(struct kioctx *ctx); ++extern struct kmem_cache *kioctx_cachep; ++extern void aio_kick_handler(struct work_struct *); ++ + #endif /* __LINUX__AIO_H */ +Index: kernel/include/linux/auto_fs.h +=================================================================== +--- kernel.orig/include/linux/auto_fs.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/auto_fs.h 2008-11-24 15:47:46.000000000 +0100 +@@ -51,6 +51,8 @@ + typedef unsigned long autofs_wqt_t; + #endif + ++typedef __u32 autofs_wqt_t_32bit; ++ + /* Packet types */ + #define autofs_ptype_missing 0 /* Missing entry (mount request) */ + #define autofs_ptype_expire 1 /* Expire entry (umount request) */ +@@ -67,6 +69,13 @@ + char name[NAME_MAX+1]; + }; + ++struct autofs_packet_missing_32bit { ++ struct autofs_packet_hdr hdr; ++ autofs_wqt_t_32bit wait_queue_token; ++ int len; ++ char name[NAME_MAX+1]; ++} __attribute__ ((__packed__)); ++ + /* v3 expire (via ioctl) */ + struct autofs_packet_expire { + struct autofs_packet_hdr hdr; +@@ -74,6 +83,13 @@ + char name[NAME_MAX+1]; + }; + ++/* v3 expire (via ioctl) for 32 bit userspace daemon and x68_64 kernel */ ++struct autofs_packet_expire_32bit { ++ struct autofs_packet_hdr hdr; ++ int len; ++ char name[NAME_MAX+1]; ++} __attribute__ ((__packed__)); ++ + #define AUTOFS_IOC_READY _IO(0x93,0x60) + #define AUTOFS_IOC_FAIL _IO(0x93,0x61) + #define AUTOFS_IOC_CATATONIC _IO(0x93,0x62) +Index: kernel/include/linux/auto_fs4.h +=================================================================== +--- kernel.orig/include/linux/auto_fs4.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/auto_fs4.h 2008-11-24 15:47:46.000000000 +0100 +@@ -59,11 +59,22 @@ + char name[NAME_MAX+1]; + }; + ++/* v4 multi expire (via pipe) for 32 bit userspace daemon and x68_64 kernel */ ++struct autofs_packet_expire_multi_32bit { ++ struct autofs_packet_hdr hdr; ++ autofs_wqt_t_32bit wait_queue_token; ++ int len; ++ char name[NAME_MAX+1]; ++} __attribute__ ((__packed__)); ++ + union autofs_packet_union { + struct autofs_packet_hdr hdr; + struct autofs_packet_missing missing; ++ struct autofs_packet_missing_32bit missing_32bit; + struct autofs_packet_expire expire; ++ struct autofs_packet_expire_32bit expire_32bit; + struct autofs_packet_expire_multi expire_multi; ++ struct autofs_packet_expire_multi_32bit expire_multi_32bit; + }; + + /* autofs v5 common packet struct */ +@@ -80,6 +91,20 @@ + char name[NAME_MAX+1]; + }; + ++/* autofs v5 packet struct for 32 bit userspace daemon and x68_64 kernel*/ ++struct autofs_v5_packet_32bit { ++ struct autofs_packet_hdr hdr; ++ autofs_wqt_t_32bit wait_queue_token; ++ __u32 dev; ++ __u64 ino; ++ __u32 uid; ++ __u32 gid; ++ __u32 pid; ++ __u32 tgid; ++ __u32 len; ++ char name[NAME_MAX+1]; ++} __attribute__ ((__packed__)); ++ + typedef struct autofs_v5_packet autofs_packet_missing_indirect_t; + typedef struct autofs_v5_packet autofs_packet_expire_indirect_t; + typedef struct autofs_v5_packet autofs_packet_missing_direct_t; +@@ -88,6 +113,7 @@ + union autofs_v5_packet_union { + struct autofs_packet_hdr hdr; + struct autofs_v5_packet v5_packet; ++ struct autofs_v5_packet_32bit v5_packet_32bit; + autofs_packet_missing_indirect_t missing_indirect; + autofs_packet_expire_indirect_t expire_indirect; + autofs_packet_missing_direct_t missing_direct; +Index: kernel/include/linux/capability.h +=================================================================== +--- kernel.orig/include/linux/capability.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/capability.h 2008-11-24 15:47:46.000000000 +0100 +@@ -61,6 +61,7 @@ + }; + + #ifdef __KERNEL__ ++#include + + /* #define STRICT_CAP_T_TYPECHECKS */ + +@@ -163,12 +164,9 @@ + + #define CAP_NET_BROADCAST 11 + +-/* Allow interface configuration */ + /* Allow administration of IP firewall, masquerading and accounting */ + /* Allow setting debug option on sockets */ + /* Allow modification of routing tables */ +-/* Allow setting arbitrary process / process group ownership on +- sockets */ + /* Allow binding to any address for transparent proxying */ + /* Allow setting TOS (type of service) */ + /* Allow setting promiscuous mode */ +@@ -199,6 +197,7 @@ + #define CAP_SYS_MODULE 16 + + /* Allow ioperm/iopl access */ ++/* Allow O_DIRECT access */ + /* Allow sending USB messages to any device via /proc/bus/usb */ + + #define CAP_SYS_RAWIO 17 +@@ -217,24 +216,19 @@ + + /* Allow configuration of the secure attention key */ + /* Allow administration of the random device */ +-/* Allow examination and configuration of disk quotas */ + /* Allow configuring the kernel's syslog (printk behaviour) */ + /* Allow setting the domainname */ + /* Allow setting the hostname */ + /* Allow calling bdflush() */ +-/* Allow mount() and umount(), setting up new smb connection */ ++/* Allow setting up new smb connection */ + /* Allow some autofs root ioctls */ + /* Allow nfsservctl */ + /* Allow VM86_REQUEST_IRQ */ + /* Allow to read/write pci config on alpha */ + /* Allow irix_prctl on mips (setstacksize) */ + /* Allow flushing all cache on m68k (sys_cacheflush) */ +-/* Allow removing semaphores */ +-/* Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores +- and shared memory */ + /* Allow locking/unlocking of shared memory segment */ + /* Allow turning swap on/off */ +-/* Allow forged pids on socket credentials passing */ + /* Allow setting readahead and flushing buffers on block devices */ + /* Allow setting geometry in floppy driver */ + /* Allow turning DMA on/off in xd driver */ +@@ -252,6 +246,8 @@ + arbitrary SCSI commands */ + /* Allow setting encryption key on loopback filesystem */ + /* Allow setting zone reclaim policy */ ++/* Modify data journaling mode on ext[34] filesystem (uses journaling ++ resources) */ + + #define CAP_SYS_ADMIN 21 + +@@ -271,7 +267,7 @@ + /* Override resource limits. Set resource limits. */ + /* Override quota limits. */ + /* Override reserved space on ext2 filesystem */ +-/* Modify data journaling mode on ext3 filesystem (uses journaling ++/* Modify data journaling mode on ext[34] filesystem (uses journaling + resources) */ + /* NOTE: ext2 honors fsuid when checking for resource overrides, so + you can override using fsuid too */ +@@ -307,8 +303,59 @@ + + #define CAP_SETFCAP 31 + ++/* ++ * Important note: VZ capabilities do intersect with CAP_AUDIT ++ * this is due to compatibility reasons. Nothing bad. ++ * Both VZ and Audit/SELinux caps are disabled in VPSs. ++ */ ++ ++/* Allow access to all information. In the other case some structures will be ++ hiding to ensure different Virtual Environment non-interaction on the same ++ node */ ++#define CAP_SETVEID 29 ++ ++#define CAP_VE_ADMIN 30 ++ + #ifdef __KERNEL__ + ++#ifdef CONFIG_VE ++ ++/* Replacement for CAP_NET_ADMIN: ++ delegated rights to the Virtual environment of its network administration. ++ For now the following rights have been delegated: ++ ++ Allow setting arbitrary process / process group ownership on sockets ++ Allow interface configuration ++ */ ++#define CAP_VE_NET_ADMIN CAP_VE_ADMIN ++ ++/* Replacement for CAP_SYS_ADMIN: ++ delegated rights to the Virtual environment of its administration. ++ For now the following rights have been delegated: ++ */ ++/* Allow mount/umount/remount */ ++/* Allow examination and configuration of disk quotas */ ++/* Allow removing semaphores */ ++/* Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores ++ and shared memory */ ++/* Allow locking/unlocking of shared memory segment */ ++/* Allow forged pids on socket credentials passing */ ++ ++#define CAP_VE_SYS_ADMIN CAP_VE_ADMIN ++#else ++#define CAP_VE_NET_ADMIN CAP_NET_ADMIN ++#define CAP_VE_SYS_ADMIN CAP_SYS_ADMIN ++#endif ++ ++/* ++ * Bounding set ++ */ ++#ifdef CONFIG_VE ++#define cap_bset (get_exec_env()->ve_cap_bset) ++#else ++extern kernel_cap_t cap_bset; ++#endif ++ + /* + * Internal kernel functions only + */ +@@ -367,13 +414,23 @@ + #define cap_issubset(a,set) (!(cap_t(a) & ~cap_t(set))) + + #define cap_clear(c) do { cap_t(c) = 0; } while(0) ++#ifndef CONFIG_VE + #define cap_set_full(c) do { cap_t(c) = ~0; } while(0) ++#else ++#define cap_set_full(c) \ ++ do { \ ++ cap_t(c) = ve_is_super(get_exec_env()) ? \ ++ ~0 : \ ++ cap_bset; \ ++ } while(0) ++#endif + #define cap_mask(c,mask) do { cap_t(c) &= cap_t(mask); } while(0) + + #define cap_is_fs_cap(c) (CAP_TO_MASK(c) & CAP_FS_MASK) + + int capable(int cap); + int __capable(struct task_struct *t, int cap); ++extern spinlock_t task_capability_lock; + + #endif /* __KERNEL__ */ + +Index: kernel/include/linux/cfq-iosched.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/cfq-iosched.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,151 @@ ++#ifndef _LINUX_CFQ_IOSCHED_H ++#define _LINUX_CFQ_IOSCHED_H ++ ++#include ++#include ++#include ++ ++extern struct kmem_cache *cfq_pool; ++ ++#define CFQ_PRIO_LISTS IOPRIO_BE_NR ++ ++/* ++ * Most of our rbtree usage is for sorting with min extraction, so ++ * if we cache the leftmost node we don't have to walk down the tree ++ * to find it. Idea borrowed from Ingo Molnars CFS scheduler. We should ++ * move this into the elevator for the rq sorting as well. ++ */ ++struct cfq_rb_root { ++ struct rb_root rb; ++ struct rb_node *left; ++}; ++#define CFQ_RB_ROOT (struct cfq_rb_root) { RB_ROOT, NULL, } ++ ++/* ++ * Per (Device, UBC) queue data ++ */ ++struct cfq_bc_data { ++ /* for ub.iopriv->cfq_bc_head */ ++ struct list_head cfq_bc_list; ++ /* for cfqd->act_cfq_bc_head */ ++ struct list_head act_cfq_bc_list; ++ ++ struct cfq_data *cfqd; ++ struct ub_iopriv *ub_iopriv; ++ ++ /* ++ * rr list of queues with requests and the count of them ++ */ ++ struct cfq_rb_root service_tree; ++ ++ int cur_prio; ++ int cur_end_prio; ++ ++ unsigned long rqnum; ++ unsigned long on_dispatch; ++ ++ /* ++ * async queue for each priority case ++ */ ++ struct cfq_queue *async_cfqq[2][CFQ_PRIO_LISTS]; ++ struct cfq_queue *async_idle_cfqq; ++}; ++ ++/* ++ * Per block device queue structure ++ */ ++struct cfq_data { ++ struct request_queue *queue; ++ ++#ifndef CONFIG_BC_IO_SCHED ++ struct cfq_bc_data cfq_bc; ++#endif ++ unsigned int busy_queues; ++ ++ int rq_in_driver; ++ int sync_flight; ++ int hw_tag; ++ ++ /* ++ * idle window management ++ */ ++ struct timer_list idle_slice_timer; ++ struct work_struct unplug_work; ++ ++ struct cfq_queue *active_queue; ++ struct cfq_io_context *active_cic; ++ ++ struct timer_list idle_class_timer; ++ ++ sector_t last_position; ++ unsigned long last_end_request; ++ ++ /* ++ * tunables, see top of file ++ */ ++ unsigned int cfq_quantum; ++ unsigned int cfq_fifo_expire[2]; ++ unsigned int cfq_back_penalty; ++ unsigned int cfq_back_max; ++ unsigned int cfq_slice[2]; ++ unsigned int cfq_slice_async_rq; ++ unsigned int cfq_slice_idle; ++ ++ struct list_head cic_list; ++ ++ /* list of ub that have requests */ ++ struct list_head act_cfq_bc_head; ++ /* ub that owns a timeslice at the moment */ ++ struct cfq_bc_data *active_cfq_bc; ++ unsigned int cfq_ub_slice; ++ unsigned long slice_end; ++ int virt_mode; ++ int write_virt_mode; ++}; ++ ++/* ++ * Per process-grouping structure ++ */ ++struct cfq_queue { ++ /* reference count */ ++ atomic_t ref; ++ /* parent cfq_data */ ++ struct cfq_data *cfqd; ++ /* service_tree member */ ++ struct rb_node rb_node; ++ /* service_tree key */ ++ unsigned long rb_key; ++ /* sorted list of pending requests */ ++ struct rb_root sort_list; ++ /* if fifo isn't expired, next request to serve */ ++ struct request *next_rq; ++ /* requests queued in sort_list */ ++ int queued[2]; ++ /* currently allocated requests */ ++ int allocated[2]; ++ /* pending metadata requests */ ++ int meta_pending; ++ /* fifo list of requests in sort_list */ ++ struct list_head fifo; ++ ++ unsigned long slice_end; ++ long slice_resid; ++ ++ /* number of requests that are on the dispatch list or inside driver */ ++ int dispatched; ++ ++ /* io prio of this group */ ++ unsigned short ioprio, org_ioprio; ++ unsigned short ioprio_class, org_ioprio_class; ++ ++ /* various state flags, see below */ ++ unsigned int flags; ++ ++ struct cfq_bc_data *cfq_bc; ++}; ++ ++static void inline cfq_init_cfq_bc(struct cfq_bc_data *cfq_bc) ++{ ++ cfq_bc->service_tree = CFQ_RB_ROOT; ++} ++#endif /* _LINUX_CFQ_IOSCHED_H */ +Index: kernel/include/linux/compat.h +=================================================================== +--- kernel.orig/include/linux/compat.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/compat.h 2008-11-24 15:47:46.000000000 +0100 +@@ -233,6 +233,7 @@ + asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); + + extern int compat_printk(const char *fmt, ...); ++extern int ve_compat_printk(int dst, const char *fmt, ...); + extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); + + asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, +Index: kernel/include/linux/console.h +=================================================================== +--- kernel.orig/include/linux/console.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/console.h 2008-11-24 15:47:46.000000000 +0100 +@@ -147,4 +147,22 @@ + #define VESA_HSYNC_SUSPEND 2 + #define VESA_POWERDOWN 3 + ++ ++#include ++#include ++#include ++ ++struct printk_aligned { ++ int v; ++} ____cacheline_aligned; ++extern struct printk_aligned printk_no_wake_var[NR_CPUS]; ++#define __printk_no_wake (printk_no_wake_var[smp_processor_id()].v) ++#define printk_no_wake ({ \ ++ int v; \ ++ preempt_disable(); \ ++ v = __printk_no_wake; \ ++ preempt_enable_no_resched(); \ ++ v; \ ++ }) ++ + #endif /* _LINUX_CONSOLE_H */ +Index: kernel/include/linux/cpt_image.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/cpt_image.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,1705 @@ ++/* ++ * ++ * include/linux/cpt_image.h ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __CPT_IMAGE_H_ ++#define __CPT_IMAGE_H_ 1 ++ ++#define CPT_NULL (~0ULL) ++#define CPT_NOINDEX (~0U) ++ ++/* ++ * Image file layout. ++ * ++ * - major header ++ * - sections[] ++ * ++ * Each section is: ++ * - section header ++ * - array of objects ++ * ++ * All data records are arch independent, 64 bit aligned. ++ */ ++ ++enum _cpt_object_type ++{ ++ CPT_OBJ_TASK = 0, ++ CPT_OBJ_MM, ++ CPT_OBJ_FS, ++ CPT_OBJ_FILES, ++ CPT_OBJ_FILE, ++ CPT_OBJ_SIGHAND_STRUCT, ++ CPT_OBJ_SIGNAL_STRUCT, ++ CPT_OBJ_TTY, ++ CPT_OBJ_SOCKET, ++ CPT_OBJ_SYSVSEM_UNDO, ++ CPT_OBJ_NAMESPACE, ++ CPT_OBJ_SYSV_SHM, ++ CPT_OBJ_INODE, ++ CPT_OBJ_UBC, ++ CPT_OBJ_SLM_SGREG, ++ CPT_OBJ_SLM_REGOBJ, ++ CPT_OBJ_SLM_MM, ++ CPT_OBJ_MAX, ++ /* The objects above are stored in memory while checkpointing */ ++ ++ CPT_OBJ_VMA = 1024, ++ CPT_OBJ_FILEDESC, ++ CPT_OBJ_SIGHANDLER, ++ CPT_OBJ_SIGINFO, ++ CPT_OBJ_LASTSIGINFO, ++ CPT_OBJ_SYSV_SEM, ++ CPT_OBJ_SKB, ++ CPT_OBJ_FLOCK, ++ CPT_OBJ_OPENREQ, ++ CPT_OBJ_VFSMOUNT, ++ CPT_OBJ_TRAILER, ++ CPT_OBJ_SYSVSEM_UNDO_REC, ++ CPT_OBJ_NET_DEVICE, ++ CPT_OBJ_NET_IFADDR, ++ CPT_OBJ_NET_ROUTE, ++ CPT_OBJ_NET_CONNTRACK, ++ CPT_OBJ_NET_CONNTRACK_EXPECT, ++ CPT_OBJ_AIO_CONTEXT, ++ CPT_OBJ_VEINFO, ++ CPT_OBJ_EPOLL, ++ CPT_OBJ_EPOLL_FILE, ++ CPT_OBJ_SKFILTER, ++ CPT_OBJ_SIGALTSTACK, ++ CPT_OBJ_SOCK_MCADDR, ++ CPT_OBJ_BIND_MNT, ++ CPT_OBJ_SYSVMSG, ++ CPT_OBJ_SYSVMSG_MSG, ++ ++ CPT_OBJ_X86_REGS = 4096, ++ CPT_OBJ_X86_64_REGS, ++ CPT_OBJ_PAGES, ++ CPT_OBJ_COPYPAGES, ++ CPT_OBJ_REMAPPAGES, ++ CPT_OBJ_LAZYPAGES, ++ CPT_OBJ_NAME, ++ CPT_OBJ_BITS, ++ CPT_OBJ_REF, ++ CPT_OBJ_ITERPAGES, ++ CPT_OBJ_ITERYOUNGPAGES, ++ CPT_OBJ_VSYSCALL, ++ CPT_OBJ_IA64_REGS, ++ CPT_OBJ_INOTIFY, ++ CPT_OBJ_INOTIFY_WATCH, ++ CPT_OBJ_INOTIFY_EVENT, ++ CPT_OBJ_TASK_AUX, ++ CPT_OBJ_NET_TUNTAP, ++}; ++ ++#define CPT_ALIGN(n) (((n)+7)&~7) ++ ++struct cpt_major_hdr ++{ ++ __u8 cpt_signature[4]; /* Magic number */ ++ __u16 cpt_hdrlen; /* Length of this header */ ++ __u16 cpt_image_version; /* Format of this file */ ++#define CPT_VERSION_MINOR(a) ((a) & 0xf) ++#define CPT_VERSION_8 0 ++#define CPT_VERSION_9 0x100 ++#define CPT_VERSION_9_1 0x101 ++#define CPT_VERSION_16 0x200 ++#define CPT_VERSION_18 0x300 ++#define CPT_VERSION_20 0x400 ++#define CPT_VERSION_24 0x500 ++ __u16 cpt_os_arch; /* Architecture */ ++#define CPT_OS_ARCH_I386 0 ++#define CPT_OS_ARCH_EMT64 1 ++#define CPT_OS_ARCH_IA64 2 ++ __u16 __cpt_pad1; ++ __u32 cpt_ve_features; /* VE features */ ++ __u32 cpt_ve_features2; /* VE features */ ++ __u16 cpt_pagesize; /* Page size used by OS */ ++ __u16 cpt_hz; /* HZ used by OS */ ++ __u64 cpt_start_jiffies64; /* Jiffies */ ++ __u32 cpt_start_sec; /* Seconds */ ++ __u32 cpt_start_nsec; /* Nanoseconds */ ++ __u32 cpt_cpu_caps[4]; /* CPU capabilities */ ++ __u32 cpt_kernel_config[4]; /* Kernel config */ ++ __u64 cpt_iptables_mask; /* Used netfilter modules */ ++} __attribute__ ((aligned (8))); ++ ++#define CPT_SIGNATURE0 0x79 ++#define CPT_SIGNATURE1 0x1c ++#define CPT_SIGNATURE2 0x01 ++#define CPT_SIGNATURE3 0x63 ++ ++/* CPU capabilities */ ++#define CPT_CPU_X86_CMOV 0 ++#define CPT_CPU_X86_FXSR 1 ++#define CPT_CPU_X86_SSE 2 ++#define CPT_CPU_X86_SSE2 3 ++#define CPT_CPU_X86_MMX 4 ++#define CPT_CPU_X86_3DNOW 5 ++#define CPT_CPU_X86_3DNOW2 6 ++#define CPT_CPU_X86_SEP 7 ++#define CPT_CPU_X86_EMT64 8 ++#define CPT_CPU_X86_IA64 9 ++#define CPT_CPU_X86_SYSCALL 10 ++#define CPT_CPU_X86_SYSCALL32 11 ++#define CPT_CPU_X86_SEP32 12 ++ ++/* Unsupported features */ ++#define CPT_EXTERNAL_PROCESS 16 ++#define CPT_NAMESPACES 17 ++#define CPT_SCHEDULER_POLICY 18 ++#define CPT_PTRACED_FROM_VE0 19 ++#define CPT_UNSUPPORTED_FSTYPE 20 ++#define CPT_BIND_MOUNT 21 ++#define CPT_UNSUPPORTED_NETDEV 22 ++#define CPT_UNSUPPORTED_MISC 23 ++ ++/* This mask is used to determine whether VE ++ has some unsupported features or not */ ++#define CPT_UNSUPPORTED_MASK 0xffff0000UL ++ ++#define CPT_KERNEL_CONFIG_PAE 0 ++ ++struct cpt_section_hdr ++{ ++ __u64 cpt_next; ++ __u32 cpt_section; ++ __u16 cpt_hdrlen; ++ __u16 cpt_align; ++} __attribute__ ((aligned (8))); ++ ++enum ++{ ++ CPT_SECT_ERROR, /* Error section, content is string */ ++ CPT_SECT_VEINFO, ++ CPT_SECT_FILES, /* Files. Content is array of file objects */ ++ CPT_SECT_TASKS, ++ CPT_SECT_MM, ++ CPT_SECT_FILES_STRUCT, ++ CPT_SECT_FS, ++ CPT_SECT_SIGHAND_STRUCT, ++ CPT_SECT_TTY, ++ CPT_SECT_SOCKET, ++ CPT_SECT_NAMESPACE, ++ CPT_SECT_SYSVSEM_UNDO, ++ CPT_SECT_INODE, /* Inodes with i->i_nlink==0 and ++ * deleted dentires with inodes not ++ * referenced inside dumped process. ++ */ ++ CPT_SECT_SYSV_SHM, ++ CPT_SECT_SYSV_SEM, ++ CPT_SECT_ORPHANS, ++ CPT_SECT_NET_DEVICE, ++ CPT_SECT_NET_IFADDR, ++ CPT_SECT_NET_ROUTE, ++ CPT_SECT_NET_IPTABLES, ++ CPT_SECT_NET_CONNTRACK, ++ CPT_SECT_NET_CONNTRACK_VE0, ++ CPT_SECT_UTSNAME, ++ CPT_SECT_TRAILER, ++ CPT_SECT_UBC, ++ CPT_SECT_SLM_SGREGS, ++ CPT_SECT_SLM_REGOBJS, ++/* Due to silly mistake we cannot index sections beyond this value */ ++#define CPT_SECT_MAX_INDEX (CPT_SECT_SLM_REGOBJS+1) ++ CPT_SECT_EPOLL, ++ CPT_SECT_VSYSCALL, ++ CPT_SECT_INOTIFY, ++ CPT_SECT_SYSV_MSG, ++ CPT_SECT_MAX ++}; ++ ++struct cpt_major_tail ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_lazypages; ++ __u32 cpt_64bit; ++ __u64 cpt_sections[CPT_SECT_MAX_INDEX]; ++ __u32 cpt_nsect; ++ __u8 cpt_signature[4]; /* Magic number */ ++} __attribute__ ((aligned (8))); ++ ++ ++/* Common object header. */ ++struct cpt_object_hdr ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++} __attribute__ ((aligned (8))); ++ ++enum _cpt_content_type { ++ CPT_CONTENT_VOID, ++ CPT_CONTENT_ARRAY, ++ CPT_CONTENT_DATA, ++ CPT_CONTENT_NAME, ++ ++ CPT_CONTENT_STACK, ++ CPT_CONTENT_X86_FPUSTATE_OLD, ++ CPT_CONTENT_X86_FPUSTATE, ++ CPT_CONTENT_MM_CONTEXT, ++ CPT_CONTENT_SEMARRAY, ++ CPT_CONTENT_SEMUNDO, ++ CPT_CONTENT_NLMARRAY, ++ CPT_CONTENT_MAX ++}; ++ ++/* CPT_OBJ_BITS: encode array of bytes */ ++struct cpt_obj_bits ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_size; ++ __u32 __cpt_pad1; ++} __attribute__ ((aligned (8))); ++ ++/* CPT_OBJ_REF: a reference to another object */ ++struct cpt_obj_ref ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_pos; ++} __attribute__ ((aligned (8))); ++ ++/* CPT_OBJ_VEINFO: various ve specific data */ ++struct cpt_veinfo_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ /* ipc ctls */ ++ __u32 shm_ctl_max; ++ __u32 shm_ctl_all; ++ __u32 shm_ctl_mni; ++ __u32 msg_ctl_max; ++ __u32 msg_ctl_mni; ++ __u32 msg_ctl_mnb; ++ __u32 sem_ctl_arr[4]; ++ ++ /* start time */ ++ __u64 start_timespec_delta; ++ __u64 start_jiffies_delta; ++ ++ /* later extension */ ++ __u32 last_pid; ++ __u32 pad1; ++ __u64 reserved[8]; ++} __attribute__ ((aligned (8))); ++ ++/* CPT_OBJ_FILE: one struct file */ ++struct cpt_file_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_flags; ++ __u32 cpt_mode; ++ __u64 cpt_pos; ++ __u32 cpt_uid; ++ __u32 cpt_gid; ++ ++ __u32 cpt_i_mode; ++ __u32 cpt_lflags; ++#define CPT_DENTRY_DELETED 1 ++#define CPT_DENTRY_ROOT 2 ++#define CPT_DENTRY_CLONING 4 ++#define CPT_DENTRY_PROC 8 ++#define CPT_DENTRY_EPOLL 0x10 ++#define CPT_DENTRY_REPLACED 0x20 ++#define CPT_DENTRY_INOTIFY 0x40 ++#define CPT_DENTRY_FUTEX 0x80 ++#define CPT_DENTRY_TUNTAP 0x100 ++ __u64 cpt_inode; ++ __u64 cpt_priv; ++ ++ __u32 cpt_fown_fd; ++ __u32 cpt_fown_pid; ++#define CPT_FOWN_STRAY_PID 0 ++ __u32 cpt_fown_uid; ++ __u32 cpt_fown_euid; ++ __u32 cpt_fown_signo; ++ __u32 __cpt_pad1; ++} __attribute__ ((aligned (8))); ++/* Followed by file name, encoded as CPT_OBJ_NAME */ ++ ++struct cpt_epoll_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_file; ++} __attribute__ ((aligned (8))); ++/* Followed by array of struct cpt_epoll_file */ ++ ++struct cpt_epoll_file_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_file; ++ __u32 cpt_fd; ++ __u32 cpt_events; ++ __u64 cpt_data; ++ __u32 cpt_revents; ++ __u32 cpt_ready; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_inotify_wd_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_wd; ++ __u32 cpt_mask; ++} __attribute__ ((aligned (8))); ++/* Followed by cpt_file_image of inode to watch */ ++ ++struct cpt_inotify_ev_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_wd; ++ __u32 cpt_mask; ++ __u32 cpt_cookie; ++ __u32 cpt_namelen; ++} __attribute__ ((aligned (8))); ++/* Followed by name */ ++ ++struct cpt_inotify_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_file; ++ __u32 cpt_user; ++ __u32 cpt_max_events; ++ __u32 cpt_last_wd; ++ __u32 __cpt_pad1; ++} __attribute__ ((aligned (8))); ++/* Followed by array of struct cpt_inotify_wd_image and cpt_inotify_ev_image */ ++ ++ ++/* CPT_OBJ_FILEDESC: one file descriptor */ ++struct cpt_fd_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_fd; ++ __u32 cpt_flags; ++#define CPT_FD_FLAG_CLOSEEXEC 1 ++ __u64 cpt_file; ++} __attribute__ ((aligned (8))); ++ ++/* CPT_OBJ_FILES: one files_struct */ ++struct cpt_files_struct_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_index; ++ __u32 cpt_max_fds; ++ __u32 cpt_next_fd; ++ __u32 __cpt_pad1; ++} __attribute__ ((aligned (8))); ++/* Followed by array of cpt_fd_image */ ++ ++/* CPT_OBJ_FS: one fs_struct */ ++struct cpt_fs_struct_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_umask; ++ __u32 __cpt_pad1; ++} __attribute__ ((aligned (8))); ++/* Followed by two/three CPT_OBJ_FILENAME for root, pwd and, optionally, altroot */ ++ ++/* CPT_OBJ_INODE: one struct inode */ ++struct cpt_inode_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_dev; ++ __u64 cpt_ino; ++ __u32 cpt_mode; ++ __u32 cpt_nlink; ++ __u32 cpt_uid; ++ __u32 cpt_gid; ++ __u64 cpt_rdev; ++ __u64 cpt_size; ++ __u64 cpt_blksize; ++ __u64 cpt_atime; ++ __u64 cpt_mtime; ++ __u64 cpt_ctime; ++ __u64 cpt_blocks; ++ __u32 cpt_sb; ++ __u32 __cpt_pad1; ++} __attribute__ ((aligned (8))); ++ ++/* CPT_OBJ_VFSMOUNT: one vfsmount */ ++struct cpt_vfsmount_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_mntflags; ++#define CPT_MNT_BIND 0x80000000 ++#define CPT_MNT_EXT 0x40000000 ++ __u32 cpt_flags; ++} __attribute__ ((aligned (8))); ++ ++ ++struct cpt_flock_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_owner; ++ __u32 cpt_pid; ++ __u64 cpt_start; ++ __u64 cpt_end; ++ __u32 cpt_flags; ++ __u32 cpt_type; ++} __attribute__ ((aligned (8))); ++ ++ ++struct cpt_tty_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_flags; ++ __u32 cpt_link; ++ __u32 cpt_index; ++ __u32 cpt_drv_type; ++ __u32 cpt_drv_subtype; ++ __u32 cpt_drv_flags; ++ __u8 cpt_packet; ++ __u8 cpt_stopped; ++ __u8 cpt_hw_stopped; ++ __u8 cpt_flow_stopped; ++ ++ __u32 cpt_canon_data; ++ __u32 cpt_canon_head; ++ __u32 cpt_canon_column; ++ __u32 cpt_column; ++ __u8 cpt_ctrl_status; ++ __u8 cpt_erasing; ++ __u8 cpt_lnext; ++ __u8 cpt_icanon; ++ __u8 cpt_raw; ++ __u8 cpt_real_raw; ++ __u8 cpt_closing; ++ __u8 __cpt_pad1; ++ __u16 cpt_minimum_to_wake; ++ __u16 __cpt_pad2; ++ __u32 cpt_pgrp; ++ __u32 cpt_session; ++ __u32 cpt_c_line; ++ __u8 cpt_name[64]; ++ __u16 cpt_ws_row; ++ __u16 cpt_ws_col; ++ __u16 cpt_ws_prow; ++ __u16 cpt_ws_pcol; ++ __u8 cpt_c_cc[32]; ++ __u32 cpt_c_iflag; ++ __u32 cpt_c_oflag; ++ __u32 cpt_c_cflag; ++ __u32 cpt_c_lflag; ++ __u32 cpt_read_flags[4096/32]; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_sock_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_file; ++ __u32 cpt_parent; ++ __u32 cpt_index; ++ ++ __u64 cpt_ssflags; ++ __u16 cpt_type; ++ __u16 cpt_family; ++ __u8 cpt_sstate; ++ __u8 cpt_passcred; ++ __u8 cpt_state; ++ __u8 cpt_reuse; ++ ++ __u8 cpt_zapped; ++ __u8 cpt_shutdown; ++ __u8 cpt_userlocks; ++ __u8 cpt_no_check; ++ __u8 cpt_debug; ++ __u8 cpt_rcvtstamp; ++ __u8 cpt_localroute; ++ __u8 cpt_protocol; ++ ++ __u32 cpt_err; ++ __u32 cpt_err_soft; ++ ++ __u16 cpt_max_ack_backlog; ++ __u16 __cpt_pad1; ++ __u32 cpt_priority; ++ ++ __u32 cpt_rcvlowat; ++ __u32 cpt_bound_dev_if; ++ ++ __u64 cpt_rcvtimeo; ++ __u64 cpt_sndtimeo; ++ __u32 cpt_rcvbuf; ++ __u32 cpt_sndbuf; ++ __u64 cpt_flags; ++ __u64 cpt_lingertime; ++ __u32 cpt_peer_pid; ++ __u32 cpt_peer_uid; ++ ++ __u32 cpt_peer_gid; ++ __u32 cpt_laddrlen; ++ __u32 cpt_laddr[128/4]; ++ __u32 cpt_raddrlen; ++ __u32 cpt_raddr[128/4]; ++ /* AF_UNIX */ ++ __u32 cpt_peer; ++ ++ __u8 cpt_socketpair; ++ __u8 cpt_deleted; ++ __u16 __cpt_pad4; ++ __u32 __cpt_pad5; ++/* ++ struct sk_filter *sk_filter; ++ */ ++ ++ __u64 cpt_stamp; ++ __u32 cpt_daddr; ++ __u16 cpt_dport; ++ __u16 cpt_sport; ++ ++ __u32 cpt_saddr; ++ __u32 cpt_rcv_saddr; ++ ++ __u32 cpt_uc_ttl; ++ __u32 cpt_tos; ++ ++ __u32 cpt_cmsg_flags; ++ __u32 cpt_mc_index; ++ ++ __u32 cpt_mc_addr; ++/* ++ struct ip_options *opt; ++ */ ++ __u8 cpt_hdrincl; ++ __u8 cpt_mc_ttl; ++ __u8 cpt_mc_loop; ++ __u8 cpt_pmtudisc; ++ ++ __u8 cpt_recverr; ++ __u8 cpt_freebind; ++ __u16 cpt_idcounter; ++ __u32 cpt_cork_flags; ++ ++ __u32 cpt_cork_fragsize; ++ __u32 cpt_cork_length; ++ __u32 cpt_cork_addr; ++ __u32 cpt_cork_saddr; ++ __u32 cpt_cork_daddr; ++ __u32 cpt_cork_oif; ++ ++ __u32 cpt_udp_pending; ++ __u32 cpt_udp_corkflag; ++ __u16 cpt_udp_encap; ++ __u16 cpt_udp_len; ++ __u32 __cpt_pad7; ++ ++ __u64 cpt_saddr6[2]; ++ __u64 cpt_rcv_saddr6[2]; ++ __u64 cpt_daddr6[2]; ++ __u32 cpt_flow_label6; ++ __u32 cpt_frag_size6; ++ __u32 cpt_hop_limit6; ++ __u32 cpt_mcast_hops6; ++ ++ __u32 cpt_mcast_oif6; ++ __u8 cpt_rxopt6; ++ __u8 cpt_mc_loop6; ++ __u8 cpt_recverr6; ++ __u8 cpt_sndflow6; ++ ++ __u8 cpt_pmtudisc6; ++ __u8 cpt_ipv6only6; ++ __u8 cpt_mapped; ++ __u8 __cpt_pad8; ++ __u32 cpt_pred_flags; ++ ++ __u32 cpt_rcv_nxt; ++ __u32 cpt_snd_nxt; ++ ++ __u32 cpt_snd_una; ++ __u32 cpt_snd_sml; ++ ++ __u32 cpt_rcv_tstamp; ++ __u32 cpt_lsndtime; ++ ++ __u8 cpt_tcp_header_len; ++ __u8 cpt_ack_pending; ++ __u8 cpt_quick; ++ __u8 cpt_pingpong; ++ __u8 cpt_blocked; ++ __u8 __cpt_pad9; ++ __u16 __cpt_pad10; ++ ++ __u32 cpt_ato; ++ __u32 cpt_ack_timeout; ++ ++ __u32 cpt_lrcvtime; ++ __u16 cpt_last_seg_size; ++ __u16 cpt_rcv_mss; ++ ++ __u32 cpt_snd_wl1; ++ __u32 cpt_snd_wnd; ++ ++ __u32 cpt_max_window; ++ __u32 cpt_pmtu_cookie; ++ ++ __u32 cpt_mss_cache; ++ __u16 cpt_mss_cache_std; ++ __u16 cpt_mss_clamp; ++ ++ __u16 cpt_ext_header_len; ++ __u16 cpt_ext2_header_len; ++ __u8 cpt_ca_state; ++ __u8 cpt_retransmits; ++ __u8 cpt_reordering; ++ __u8 cpt_frto_counter; ++ ++ __u32 cpt_frto_highmark; ++ __u8 cpt_adv_cong; ++ __u8 cpt_defer_accept; ++ __u8 cpt_backoff; ++ __u8 __cpt_pad11; ++ ++ __u32 cpt_srtt; ++ __u32 cpt_mdev; ++ ++ __u32 cpt_mdev_max; ++ __u32 cpt_rttvar; ++ ++ __u32 cpt_rtt_seq; ++ __u32 cpt_rto; ++ ++ __u32 cpt_packets_out; ++ __u32 cpt_left_out; ++ ++ __u32 cpt_retrans_out; ++ __u32 cpt_snd_ssthresh; ++ ++ __u32 cpt_snd_cwnd; ++ __u16 cpt_snd_cwnd_cnt; ++ __u16 cpt_snd_cwnd_clamp; ++ ++ __u32 cpt_snd_cwnd_used; ++ __u32 cpt_snd_cwnd_stamp; ++ ++ __u32 cpt_timeout; ++ __u32 cpt_ka_timeout; ++ ++ __u32 cpt_rcv_wnd; ++ __u32 cpt_rcv_wup; ++ ++ __u32 cpt_write_seq; ++ __u32 cpt_pushed_seq; ++ ++ __u32 cpt_copied_seq; ++ __u8 cpt_tstamp_ok; ++ __u8 cpt_wscale_ok; ++ __u8 cpt_sack_ok; ++ __u8 cpt_saw_tstamp; ++ ++ __u8 cpt_snd_wscale; ++ __u8 cpt_rcv_wscale; ++ __u8 cpt_nonagle; ++ __u8 cpt_keepalive_probes; ++ __u32 cpt_rcv_tsval; ++ ++ __u32 cpt_rcv_tsecr; ++ __u32 cpt_ts_recent; ++ ++ __u64 cpt_ts_recent_stamp; ++ __u16 cpt_user_mss; ++ __u8 cpt_dsack; ++ __u8 cpt_eff_sacks; ++ __u32 cpt_sack_array[2*5]; ++ __u32 cpt_window_clamp; ++ ++ __u32 cpt_rcv_ssthresh; ++ __u8 cpt_probes_out; ++ __u8 cpt_num_sacks; ++ __u16 cpt_advmss; ++ ++ __u8 cpt_syn_retries; ++ __u8 cpt_ecn_flags; ++ __u16 cpt_prior_ssthresh; ++ __u32 cpt_lost_out; ++ ++ __u32 cpt_sacked_out; ++ __u32 cpt_fackets_out; ++ ++ __u32 cpt_high_seq; ++ __u32 cpt_retrans_stamp; ++ ++ __u32 cpt_undo_marker; ++ __u32 cpt_undo_retrans; ++ ++ __u32 cpt_urg_seq; ++ __u16 cpt_urg_data; ++ __u8 cpt_pending; ++ __u8 cpt_urg_mode; ++ ++ __u32 cpt_snd_up; ++ __u32 cpt_keepalive_time; ++ ++ __u32 cpt_keepalive_intvl; ++ __u32 cpt_linger2; ++ ++ __u32 cpt_rcvrtt_rtt; ++ __u32 cpt_rcvrtt_seq; ++ ++ __u32 cpt_rcvrtt_time; ++ __u32 __cpt_pad12; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_sockmc_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u16 cpt_family; ++ __u16 cpt_mode; ++ __u32 cpt_ifindex; ++ __u32 cpt_mcaddr[4]; ++} __attribute__ ((aligned (8))); ++/* Followed by array of source addresses, each zero padded to 16 bytes */ ++ ++struct cpt_openreq_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_rcv_isn; ++ __u32 cpt_snt_isn; ++ ++ __u16 cpt_rmt_port; ++ __u16 cpt_mss; ++ __u8 cpt_family; ++ __u8 cpt_retrans; ++ __u8 cpt_snd_wscale; ++ __u8 cpt_rcv_wscale; ++ ++ __u8 cpt_tstamp_ok; ++ __u8 cpt_sack_ok; ++ __u8 cpt_wscale_ok; ++ __u8 cpt_ecn_ok; ++ __u8 cpt_acked; ++ __u8 __cpt_pad1; ++ __u16 __cpt_pad2; ++ ++ __u32 cpt_window_clamp; ++ __u32 cpt_rcv_wnd; ++ __u32 cpt_ts_recent; ++ __u32 cpt_iif; ++ __u64 cpt_expires; ++ ++ __u64 cpt_loc_addr[2]; ++ __u64 cpt_rmt_addr[2]; ++/* ++ struct ip_options *opt; ++ */ ++ ++} __attribute__ ((aligned (8))); ++ ++struct cpt_skb_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_owner; ++ __u32 cpt_queue; ++#define CPT_SKB_NQ 0 ++#define CPT_SKB_RQ 1 ++#define CPT_SKB_WQ 2 ++#define CPT_SKB_OFOQ 3 ++ ++ __u64 cpt_stamp; ++ __u32 cpt_len; ++ __u32 cpt_hspace; ++ __u32 cpt_tspace; ++ __u32 cpt_h; ++ __u32 cpt_nh; ++ __u32 cpt_mac; ++ ++ __u64 cpt_cb[5]; ++ __u32 cpt_mac_len; ++ __u32 cpt_csum; ++ __u8 cpt_local_df; ++ __u8 cpt_pkt_type; ++ __u8 cpt_ip_summed; ++ __u8 __cpt_pad1; ++ __u32 cpt_priority; ++ __u16 cpt_protocol; ++ __u16 cpt_security; ++ __u16 cpt_gso_segs; ++ __u16 cpt_gso_size; ++} __attribute__ ((aligned (8))); ++ ++ ++struct cpt_sysvshm_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_key; ++ __u64 cpt_uid; ++ __u64 cpt_gid; ++ __u64 cpt_cuid; ++ __u64 cpt_cgid; ++ __u64 cpt_mode; ++ __u64 cpt_seq; ++ ++ __u32 cpt_id; ++ __u32 cpt_mlockuser; ++ __u64 cpt_segsz; ++ __u64 cpt_atime; ++ __u64 cpt_ctime; ++ __u64 cpt_dtime; ++ __u64 cpt_creator; ++ __u64 cpt_last; ++} __attribute__ ((aligned (8))); ++ ++ ++struct cpt_sysvsem_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_key; ++ __u64 cpt_uid; ++ __u64 cpt_gid; ++ __u64 cpt_cuid; ++ __u64 cpt_cgid; ++ __u64 cpt_mode; ++ __u64 cpt_seq; ++ __u32 cpt_id; ++ __u32 __cpt_pad1; ++ ++ __u64 cpt_otime; ++ __u64 cpt_ctime; ++} __attribute__ ((aligned (8))); ++/* Content is array of pairs semval/sempid */ ++ ++struct cpt_sysvsem_undo_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_id; ++ __u32 cpt_nsem; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_sysvmsg_msg_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_type; ++ __u64 cpt_size; ++} __attribute__ ((aligned (8))); ++ ++ ++struct cpt_sysvmsg_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_key; ++ __u64 cpt_uid; ++ __u64 cpt_gid; ++ __u64 cpt_cuid; ++ __u64 cpt_cgid; ++ __u64 cpt_mode; ++ __u64 cpt_seq; ++ __u32 cpt_id; ++ __u32 __cpt_pad1; ++ ++ __u64 cpt_stime; ++ __u64 cpt_rtime; ++ __u64 cpt_ctime; ++ __u64 cpt_last_sender; ++ __u64 cpt_last_receiver; ++ __u64 cpt_qbytes; ++} __attribute__ ((aligned (8))); ++/* Content is array of sysv msg */ ++ ++ ++struct cpt_mm_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_start_code; ++ __u64 cpt_end_code; ++ __u64 cpt_start_data; ++ __u64 cpt_end_data; ++ __u64 cpt_start_brk; ++ __u64 cpt_brk; ++ __u64 cpt_start_stack; ++ __u64 cpt_start_arg; ++ __u64 cpt_end_arg; ++ __u64 cpt_start_env; ++ __u64 cpt_end_env; ++ __u64 cpt_def_flags; ++ __u64 cpt_mmub; ++ __u8 cpt_dumpable; ++ __u8 cpt_vps_dumpable; ++ __u8 cpt_used_hugetlb; ++ __u8 __cpt_pad; ++ __u32 cpt_vdso; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_page_block ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_start; ++ __u64 cpt_end; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_remappage_block ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_start; ++ __u64 cpt_end; ++ __u64 cpt_pgoff; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_copypage_block ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_start; ++ __u64 cpt_end; ++ __u64 cpt_source; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_lazypage_block ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_start; ++ __u64 cpt_end; ++ __u64 cpt_index; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_iterpage_block ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_start; ++ __u64 cpt_end; ++} __attribute__ ((aligned (8))); ++/* Followed by array of PFNs */ ++ ++struct cpt_vma_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_file; ++ __u32 cpt_type; ++#define CPT_VMA_TYPE_0 0 ++#define CPT_VMA_TYPE_SHM 1 ++#define CPT_VMA_VDSO 2 ++ __u32 cpt_anonvma; ++ __u64 cpt_anonvmaid; ++ ++ __u64 cpt_start; ++ __u64 cpt_end; ++ __u64 cpt_flags; ++ __u64 cpt_pgprot; ++ __u64 cpt_pgoff; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_aio_ctx_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_max_reqs; ++ __u32 cpt_ring_pages; ++ __u32 cpt_tail; ++ __u32 cpt_nr; ++ __u64 cpt_mmap_base; ++ /* Data (io_event's) and struct aio_ring are stored in user space VM */ ++} __attribute__ ((aligned (8))); ++ ++ ++/* Format of MM section. ++ * ++ * It is array of MM objects (mm_struct). Each MM object is ++ * header, encoding mm_struct, followed by array of VMA objects. ++ * Each VMA consists of VMA header, encoding vm_area_struct, and ++ * if the VMA contains copied pages, the header is followed by ++ * array of tuples start-end each followed by data. ++ * ++ * ATTN: no block/page alignment. Only 64bit alignment. This might be not good? ++ */ ++ ++struct cpt_restart_block { ++ __u64 fn; ++#define CPT_RBL_0 0 ++#define CPT_RBL_NANOSLEEP 1 ++#define CPT_RBL_COMPAT_NANOSLEEP 2 ++#define CPT_RBL_POLL 3 ++#define CPT_RBL_FUTEX_WAIT 4 ++ __u64 arg0; ++ __u64 arg1; ++ __u64 arg2; ++ __u64 arg3; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_siginfo_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_qflags; ++ __u32 cpt_signo; ++ __u32 cpt_errno; ++ __u32 cpt_code; ++ ++ __u64 cpt_sigval; ++ __u32 cpt_pid; ++ __u32 cpt_uid; ++ __u64 cpt_utime; ++ __u64 cpt_stime; ++ ++ __u64 cpt_user; ++} __attribute__ ((aligned (8))); ++ ++/* Portable presentaions for segment registers */ ++ ++#define CPT_SEG_ZERO 0 ++#define CPT_SEG_TLS1 1 ++#define CPT_SEG_TLS2 2 ++#define CPT_SEG_TLS3 3 ++#define CPT_SEG_USER32_DS 4 ++#define CPT_SEG_USER32_CS 5 ++#define CPT_SEG_USER64_DS 6 ++#define CPT_SEG_USER64_CS 7 ++#define CPT_SEG_LDT 256 ++ ++struct cpt_x86_regs ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_debugreg[8]; ++ __u32 cpt_fs; ++ __u32 cpt_gs; ++ ++ __u32 cpt_ebx; ++ __u32 cpt_ecx; ++ __u32 cpt_edx; ++ __u32 cpt_esi; ++ __u32 cpt_edi; ++ __u32 cpt_ebp; ++ __u32 cpt_eax; ++ __u32 cpt_xds; ++ __u32 cpt_xes; ++ __u32 cpt_orig_eax; ++ __u32 cpt_eip; ++ __u32 cpt_xcs; ++ __u32 cpt_eflags; ++ __u32 cpt_esp; ++ __u32 cpt_xss; ++ __u32 pad; ++}; ++ ++struct cpt_x86_64_regs ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_debugreg[8]; ++ ++ __u64 cpt_fsbase; ++ __u64 cpt_gsbase; ++ __u32 cpt_fsindex; ++ __u32 cpt_gsindex; ++ __u32 cpt_ds; ++ __u32 cpt_es; ++ ++ __u64 cpt_r15; ++ __u64 cpt_r14; ++ __u64 cpt_r13; ++ __u64 cpt_r12; ++ __u64 cpt_rbp; ++ __u64 cpt_rbx; ++ __u64 cpt_r11; ++ __u64 cpt_r10; ++ __u64 cpt_r9; ++ __u64 cpt_r8; ++ __u64 cpt_rax; ++ __u64 cpt_rcx; ++ __u64 cpt_rdx; ++ __u64 cpt_rsi; ++ __u64 cpt_rdi; ++ __u64 cpt_orig_rax; ++ __u64 cpt_rip; ++ __u64 cpt_cs; ++ __u64 cpt_eflags; ++ __u64 cpt_rsp; ++ __u64 cpt_ss; ++}; ++ ++struct cpt_ia64_regs ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 gr[128]; ++ __u64 fr[256]; ++ __u64 br[8]; ++ __u64 nat[2]; ++ ++ __u64 ar_bspstore; ++ __u64 num_regs; ++ __u64 loadrs; ++ __u64 ar_bsp; ++ __u64 ar_unat; ++ __u64 ar_pfs; ++ __u64 ar_ccv; ++ __u64 ar_fpsr; ++ __u64 ar_csd; ++ __u64 ar_ssd; ++ __u64 ar_ec; ++ __u64 ar_lc; ++ __u64 ar_rsc; ++ __u64 ar_rnat; ++ ++ __u64 cr_iip; ++ __u64 cr_ipsr; ++ ++ __u64 cfm; ++ __u64 pr; ++ ++ __u64 ibr[8]; ++ __u64 dbr[8]; ++}; ++ ++ ++struct cpt_task_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_state; ++ __u64 cpt_flags; ++ __u64 cpt_ptrace; ++ __u32 cpt_prio; ++ __u32 cpt_static_prio; ++ __u32 cpt_policy; ++ __u32 cpt_rt_priority; ++ ++ /* struct thread_info */ ++ __u64 cpt_exec_domain; ++ __u64 cpt_thrflags; ++ __u64 cpt_thrstatus; ++ __u64 cpt_addr_limit; ++ ++ __u64 cpt_personality; ++ ++ __u64 cpt_mm; ++ __u64 cpt_files; ++ __u64 cpt_fs; ++ __u64 cpt_signal; ++ __u64 cpt_sighand; ++ __u64 cpt_sigblocked; ++ __u64 cpt_sigrblocked; ++ __u64 cpt_sigpending; ++ __u64 cpt_namespace; ++ __u64 cpt_sysvsem_undo; ++ __u32 cpt_pid; ++ __u32 cpt_tgid; ++ __u32 cpt_ppid; ++ __u32 cpt_rppid; ++ __u32 cpt_pgrp; ++ __u32 cpt_session; ++ __u32 cpt_old_pgrp; ++ __u32 __cpt_pad; ++ __u32 cpt_leader; ++ __u8 cpt_pn_state; ++ __u8 cpt_stopped_state; ++ __u8 cpt_sigsuspend_state; ++ __u8 cpt_64bit; ++ __u64 cpt_set_tid; ++ __u64 cpt_clear_tid; ++ __u32 cpt_exit_code; ++ __u32 cpt_exit_signal; ++ __u32 cpt_pdeath_signal; ++ __u32 cpt_user; ++ __u32 cpt_uid; ++ __u32 cpt_euid; ++ __u32 cpt_suid; ++ __u32 cpt_fsuid; ++ __u32 cpt_gid; ++ __u32 cpt_egid; ++ __u32 cpt_sgid; ++ __u32 cpt_fsgid; ++ __u32 cpt_ngids; ++ __u32 cpt_gids[32]; ++ __u8 cpt_prctl_uac; ++ __u8 cpt_prctl_fpemu; ++ __u16 __cpt_pad1; ++ __u64 cpt_ecap; ++ __u64 cpt_icap; ++ __u64 cpt_pcap; ++ __u8 cpt_comm[16]; ++ __u64 cpt_tls[3]; ++ struct cpt_restart_block cpt_restart; ++ __u64 cpt_it_real_value; /* V8: jiffies, V9..: nsec */ ++ __u64 cpt_it_real_incr; /* V8: jiffies, V9..: nsec */ ++ __u64 cpt_it_prof_value; ++ __u64 cpt_it_prof_incr; ++ __u64 cpt_it_virt_value; ++ __u64 cpt_it_virt_incr; ++ ++ __u16 cpt_used_math; ++ __u8 cpt_keepcap; ++ __u8 cpt_did_exec; ++ __u32 cpt_ptrace_message; ++ ++ __u64 cpt_utime; ++ __u64 cpt_stime; ++ __u64 cpt_starttime; /* V8: jiffies, V9...: timespec */ ++ __u64 cpt_nvcsw; ++ __u64 cpt_nivcsw; ++ __u64 cpt_min_flt; ++ __u64 cpt_maj_flt; ++ ++ __u64 cpt_sigsuspend_blocked; ++ __u64 cpt_cutime, cpt_cstime; ++ __u64 cpt_cnvcsw, cpt_cnivcsw; ++ __u64 cpt_cmin_flt, cpt_cmaj_flt; ++ ++#define CPT_RLIM_NLIMITS 16 ++ __u64 cpt_rlim_cur[CPT_RLIM_NLIMITS]; ++ __u64 cpt_rlim_max[CPT_RLIM_NLIMITS]; ++ ++ __u64 cpt_task_ub; ++ __u64 cpt_exec_ub; ++ __u64 cpt_mm_ub; ++ __u64 cpt_fork_sub; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_sigaltstack_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_stack; ++ __u32 cpt_stacksize; ++ __u32 __cpt_pad1; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_task_aux_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_robust_list; ++ __u64 __cpt_future[16]; ++} __attribute__ ((aligned (8))); ++ ++ ++struct cpt_signal_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_leader; ++ __u8 cpt_pgrp_type; ++ __u8 cpt_old_pgrp_type; ++ __u8 cpt_session_type; ++#define CPT_PGRP_NORMAL 0 ++#define CPT_PGRP_ORPHAN 1 ++#define CPT_PGRP_STRAY 2 ++ __u8 __cpt_pad1; ++ __u64 cpt_pgrp; ++ __u64 cpt_old_pgrp; ++ __u64 cpt_session; ++ __u64 cpt_sigpending; ++ __u64 cpt_ctty; ++ ++ __u32 cpt_curr_target; ++ __u32 cpt_group_exit; ++ __u32 cpt_group_exit_code; ++ __u32 cpt_group_exit_task; ++ __u32 cpt_notify_count; ++ __u32 cpt_group_stop_count; ++ __u32 cpt_stop_state; ++ __u32 __cpt_pad2; ++ ++ __u64 cpt_utime, cpt_stime, cpt_cutime, cpt_cstime; ++ __u64 cpt_nvcsw, cpt_nivcsw, cpt_cnvcsw, cpt_cnivcsw; ++ __u64 cpt_min_flt, cpt_maj_flt, cpt_cmin_flt, cpt_cmaj_flt; ++ ++ __u64 cpt_rlim_cur[CPT_RLIM_NLIMITS]; ++ __u64 cpt_rlim_max[CPT_RLIM_NLIMITS]; ++} __attribute__ ((aligned (8))); ++/* Followed by list of posix timers. */ ++ ++struct cpt_sighand_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++} __attribute__ ((aligned (8))); ++/* Followed by list of sighandles. */ ++ ++struct cpt_sighandler_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_signo; ++ __u32 __cpt_pad1; ++ __u64 cpt_handler; ++ __u64 cpt_restorer; ++ __u64 cpt_flags; ++ __u64 cpt_mask; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_netdev_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_index; ++ __u32 cpt_flags; ++ __u8 cpt_name[16]; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_tuntap_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_owner; ++ __u32 cpt_attached; ++ __u64 cpt_flags; ++ __u64 cpt_bindfile; ++ __u64 cpt_if_flags; ++ __u8 cpt_dev_addr[6]; ++ __u16 cpt_pad; ++ __u32 cpt_chr_filter[2]; ++ __u32 cpt_net_filter[2]; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_ifaddr_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_index; ++ __u8 cpt_family; ++ __u8 cpt_masklen; ++ __u8 cpt_flags; ++ __u8 cpt_scope; ++ __u32 cpt_address[4]; ++ __u32 cpt_peer[4]; ++ __u32 cpt_broadcast[4]; ++ __u8 cpt_label[16]; ++ __u32 cpt_valid_lft; ++ __u32 cpt_prefered_lft; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_ipct_tuple ++{ ++ __u32 cpt_src; ++ __u16 cpt_srcport; ++ __u16 __cpt_pad1; ++ ++ __u32 cpt_dst; ++ __u16 cpt_dstport; ++ __u8 cpt_protonum; ++ __u8 cpt_dir; /* TEMPORARY HACK TO VALIDATE CODE */ ++} __attribute__ ((aligned (8))); ++ ++struct cpt_nat_manip ++{ ++ __u8 cpt_direction; ++ __u8 cpt_hooknum; ++ __u8 cpt_maniptype; ++ __u8 __cpt_pad1; ++ ++ __u32 cpt_manip_addr; ++ __u16 cpt_manip_port; ++ __u16 __cpt_pad2; ++ __u32 __cpt_pad3; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_nat_seq ++{ ++ __u32 cpt_correction_pos; ++ __u32 cpt_offset_before; ++ __u32 cpt_offset_after; ++ __u32 __cpt_pad1; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_ip_connexpect_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_timeout; ++ __u32 cpt_sibling_conntrack; /* Index of child conntrack */ ++ __u32 cpt_seq; /* id in 2.6.15 */ ++ ++ struct cpt_ipct_tuple cpt_ct_tuple; /* NU 2.6.15 */ ++ struct cpt_ipct_tuple cpt_tuple; ++ struct cpt_ipct_tuple cpt_mask; ++ ++ /* union ip_conntrack_expect_help. Used by ftp, irc, amanda */ ++ __u32 cpt_help[3]; /* NU 2.6.15 */ ++ __u16 cpt_manip_proto; ++ __u8 cpt_dir; ++ __u8 cpt_flags; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_ip_conntrack_image ++{ ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ struct cpt_ipct_tuple cpt_tuple[2]; ++ __u64 cpt_status; ++ __u64 cpt_timeout; ++ __u32 cpt_index; ++ __u8 cpt_ct_helper; ++ __u8 cpt_nat_helper; ++ __u16 cpt_pad1; ++ ++ /* union ip_conntrack_proto. Used by tcp and icmp. */ ++ __u32 cpt_proto_data[12]; ++ ++ /* union ip_conntrack_help. Used by ftp and pptp helper. ++ * We do not support pptp... ++ */ ++ __u32 cpt_help_data[6]; ++ ++ /* nat info */ ++ __u32 cpt_initialized; /* NU 2.6.15 */ ++ __u32 cpt_num_manips; /* NU 2.6.15 */ ++ struct cpt_nat_manip cpt_nat_manips[6]; /* NU 2.6.15 */ ++ ++ struct cpt_nat_seq cpt_nat_seq[2]; ++ ++ __u32 cpt_masq_index; ++ __u32 cpt_id; ++ __u32 cpt_mark; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_ubparm ++{ ++ __u64 barrier; ++ __u64 limit; ++ __u64 held; ++ __u64 maxheld; ++ __u64 minheld; ++ __u64 failcnt; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_beancounter_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u64 cpt_parent; ++ __u32 cpt_id; ++ __u32 __cpt_pad; ++ struct cpt_ubparm cpt_parms[32 * 2]; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_slm_sgreg_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_size; ++ __u32 __cpt_pad1; ++ __u32 cpt_id; ++ __u16 cpt_resource; ++ __u8 cpt_regname[32]; ++ __u8 __cpt_pad2[2]; ++} __attribute__ ((aligned (8))); ++ ++struct cpt_slm_obj_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_size; ++ __u32 __cpt_pad1; ++} __attribute__ ((aligned (8))); ++ ++#ifdef __KERNEL__ ++ ++static inline void __user * cpt_ptr_import(__u64 ptr) ++{ ++ return (void*)(unsigned long)ptr; ++} ++ ++static inline __u64 cpt_ptr_export(void __user *ptr) ++{ ++ return (__u64)(unsigned long)ptr; ++} ++ ++static inline void cpt_sigset_import(sigset_t *sig, __u64 ptr) ++{ ++ memcpy(sig, &ptr, sizeof(*sig)); ++} ++ ++static inline __u64 cpt_sigset_export(sigset_t *sig) ++{ ++ return *(__u64*)sig; ++} ++ ++static inline __u64 cpt_timespec_export(struct timespec *tv) ++{ ++ return (((u64)tv->tv_sec) << 32) + tv->tv_nsec; ++} ++ ++static inline void cpt_timespec_import(struct timespec *tv, __u64 val) ++{ ++ tv->tv_sec = val>>32; ++ tv->tv_nsec = (val&0xFFFFFFFF); ++} ++ ++static inline __u64 cpt_timeval_export(struct timeval *tv) ++{ ++ return (((u64)tv->tv_sec) << 32) + tv->tv_usec; ++} ++ ++static inline void cpt_timeval_import(struct timeval *tv, __u64 val) ++{ ++ tv->tv_sec = val>>32; ++ tv->tv_usec = (val&0xFFFFFFFF); ++} ++ ++#endif ++ ++#endif /* __CPT_IMAGE_H_ */ +Index: kernel/include/linux/cpt_ioctl.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/cpt_ioctl.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,43 @@ ++/* ++ * ++ * include/linux/cpt_ioctl.h ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef _CPT_IOCTL_H_ ++#define _CPT_IOCTL_H_ 1 ++ ++#include ++#include ++ ++#define CPTCTLTYPE '-' ++#define CPT_SET_DUMPFD _IOW(CPTCTLTYPE, 1, int) ++#define CPT_SET_STATUSFD _IOW(CPTCTLTYPE, 2, int) ++#define CPT_SET_LOCKFD _IOW(CPTCTLTYPE, 3, int) ++#define CPT_SET_VEID _IOW(CPTCTLTYPE, 4, int) ++#define CPT_SUSPEND _IO(CPTCTLTYPE, 5) ++#define CPT_DUMP _IO(CPTCTLTYPE, 6) ++#define CPT_UNDUMP _IO(CPTCTLTYPE, 7) ++#define CPT_RESUME _IO(CPTCTLTYPE, 8) ++#define CPT_KILL _IO(CPTCTLTYPE, 9) ++#define CPT_JOIN_CONTEXT _IO(CPTCTLTYPE, 10) ++#define CPT_GET_CONTEXT _IOW(CPTCTLTYPE, 11, unsigned int) ++#define CPT_PUT_CONTEXT _IO(CPTCTLTYPE, 12) ++#define CPT_SET_PAGEINFDIN _IOW(CPTCTLTYPE, 13, int) ++#define CPT_SET_PAGEINFDOUT _IOW(CPTCTLTYPE, 14, int) ++#define CPT_PAGEIND _IO(CPTCTLTYPE, 15) ++#define CPT_VMPREP _IOW(CPTCTLTYPE, 16, int) ++#define CPT_SET_LAZY _IOW(CPTCTLTYPE, 17, int) ++#define CPT_SET_CPU_FLAGS _IOW(CPTCTLTYPE, 18, unsigned int) ++#define CPT_TEST_CAPS _IOW(CPTCTLTYPE, 19, unsigned int) ++#define CPT_TEST_VECAPS _IOW(CPTCTLTYPE, 20, unsigned int) ++#define CPT_SET_ERRORFD _IOW(CPTCTLTYPE, 21, int) ++ ++#define CPT_ITER _IOW(CPTCTLTYPE, 23, int) ++ ++#endif +Index: kernel/include/linux/dcache.h +=================================================================== +--- kernel.orig/include/linux/dcache.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/dcache.h 2008-11-24 15:47:46.000000000 +0100 +@@ -9,6 +9,8 @@ + #include + #include + ++#include ++ + struct nameidata; + struct vfsmount; + +@@ -111,6 +113,9 @@ + struct dcookie_struct *d_cookie; /* cookie, if any */ + #endif + int d_mounted; ++#ifdef CONFIG_BEANCOUNTERS ++ struct dentry_beancounter dentry_bc; ++#endif + unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */ + }; + +@@ -174,9 +179,13 @@ + + #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ + #define DCACHE_UNHASHED 0x0010 ++#define DCACHE_VIRTUAL 0x0100 /* ve accessible */ ++ ++extern void mark_tree_virtual(struct vfsmount *m, struct dentry *d); + + #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched */ + ++extern struct kmem_cache *dentry_cache; + extern spinlock_t dcache_lock; + extern seqlock_t rename_lock; + +@@ -300,9 +309,12 @@ + */ + extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); + +-extern char *__d_path(struct dentry *, struct vfsmount *, struct dentry *, +- struct vfsmount *, char *, int, int); ++extern int d_root_check(struct dentry *, struct vfsmount *); ++ + extern char * d_path(struct dentry *, struct vfsmount *, char *, int); ++extern char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, ++ struct dentry *root, struct vfsmount *rootmnt, ++ char *buffer, int buflen); + + /* Allocation counts.. */ + +@@ -322,6 +334,12 @@ + static inline struct dentry *dget(struct dentry *dentry) + { + if (dentry) { ++#ifdef CONFIG_BEANCOUNTERS ++ preempt_disable(); ++ if (ub_dentry_on && ub_dget_testone(dentry)) ++ BUG(); ++ preempt_enable_no_resched(); ++#endif + BUG_ON(!atomic_read(&dentry->d_count)); + atomic_inc(&dentry->d_count); + } +@@ -365,6 +383,8 @@ + + extern int sysctl_vfs_cache_pressure; + ++extern int check_area_access_ve(struct dentry *, struct vfsmount *); ++extern int check_area_execute_ve(struct dentry *, struct vfsmount *); + #endif /* __KERNEL__ */ + + #endif /* __LINUX_DCACHE_H */ +Index: kernel/include/linux/device.h +=================================================================== +--- kernel.orig/include/linux/device.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/device.h 2008-11-24 15:47:46.000000000 +0100 +@@ -279,6 +279,8 @@ + dev->class_data = data; + } + ++extern struct class net_class; ++ + + extern int __must_check class_device_register(struct class_device *); + extern void class_device_unregister(struct class_device *); +Index: kernel/include/linux/devpts_fs.h +=================================================================== +--- kernel.orig/include/linux/devpts_fs.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/devpts_fs.h 2008-11-24 15:47:46.000000000 +0100 +@@ -21,6 +21,16 @@ + struct tty_struct *devpts_get_tty(int number); /* get tty structure */ + void devpts_pty_kill(int number); /* unlink */ + ++struct devpts_config { ++ int setuid; ++ int setgid; ++ uid_t uid; ++ gid_t gid; ++ umode_t mode; ++}; ++ ++extern struct devpts_config devpts_config; ++extern struct file_system_type devpts_fs_type; + #else + + /* Dummy stubs in the no-pty case */ +Index: kernel/include/linux/elevator.h +=================================================================== +--- kernel.orig/include/linux/elevator.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/elevator.h 2008-11-24 15:47:46.000000000 +0100 +@@ -56,6 +56,11 @@ + elevator_init_fn *elevator_init_fn; + elevator_exit_fn *elevator_exit_fn; + void (*trim)(struct io_context *); ++ /* In original cfq design task holds a cfqq refcount and puts it ++ * on exit via io context. Now async cfqqs are hold by UB, ++ * so we need somehow to put these queues. Use this function. ++ */ ++ void (*put_queue)(struct cfq_queue *); + }; + + #define ELV_NAME_MAX (16) +Index: kernel/include/linux/elfcore.h +=================================================================== +--- kernel.orig/include/linux/elfcore.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/elfcore.h 2008-11-24 15:47:46.000000000 +0100 +@@ -7,6 +7,8 @@ + #include + #include + ++extern int sysctl_at_vsyscall; ++ + struct elf_siginfo + { + int si_signo; /* signal number */ +Index: kernel/include/linux/eventpoll.h +=================================================================== +--- kernel.orig/include/linux/eventpoll.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/eventpoll.h 2008-11-24 15:47:46.000000000 +0100 +@@ -60,6 +60,88 @@ + spin_lock_init(&file->f_ep_lock); + } + ++struct epoll_filefd { ++ struct file *file; ++ int fd; ++}; ++ ++/* ++ * This structure is stored inside the "private_data" member of the file ++ * structure and rapresent the main data sructure for the eventpoll ++ * interface. ++ */ ++struct eventpoll { ++ /* Protect the this structure access */ ++ spinlock_t lock; ++ ++ /* ++ * This mutex is used to ensure that files are not removed ++ * while epoll is using them. This is held during the event ++ * collection loop, the file cleanup path, the epoll file exit ++ * code and the ctl operations. ++ */ ++ struct mutex mtx; ++ ++ /* Wait queue used by sys_epoll_wait() */ ++ wait_queue_head_t wq; ++ ++ /* Wait queue used by file->poll() */ ++ wait_queue_head_t poll_wait; ++ ++ /* List of ready file descriptors */ ++ struct list_head rdllist; ++ ++ /* RB tree root used to store monitored fd structs */ ++ struct rb_root rbr; ++ ++ /* ++ * This is a single linked list that chains all the "struct epitem" that ++ * happened while transfering ready events to userspace w/out ++ * holding ->lock. ++ */ ++ struct epitem *ovflist; ++}; ++ ++/* ++ * Each file descriptor added to the eventpoll interface will ++ * have an entry of this type linked to the "rbr" RB tree. ++ */ ++struct epitem { ++ /* RB tree node used to link this structure to the eventpoll RB tree */ ++ struct rb_node rbn; ++ ++ /* List header used to link this structure to the eventpoll ready list */ ++ struct list_head rdllink; ++ ++ /* ++ * Works together "struct eventpoll"->ovflist in keeping the ++ * single linked chain of items. ++ */ ++ struct epitem *next; ++ ++ /* The file descriptor information this item refers to */ ++ struct epoll_filefd ffd; ++ ++ /* Number of active wait queue attached to poll operations */ ++ int nwait; ++ ++ /* List containing poll wait queues */ ++ struct list_head pwqlist; ++ ++ /* The "container" of this item */ ++ struct eventpoll *ep; ++ ++ /* List header used to link this item to the "struct file" items list */ ++ struct list_head fllink; ++ ++ /* The structure that describe the interested events and the source fd */ ++ struct epoll_event event; ++}; ++ ++extern struct semaphore epsem; ++struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd); ++int ep_insert(struct eventpoll *ep, struct epoll_event *event, ++ struct file *tfile, int fd); + + /* Used to release the epoll bits inside the "struct file" */ + void eventpoll_release_file(struct file *file); +@@ -92,6 +174,8 @@ + eventpoll_release_file(file); + } + ++extern struct mutex epmutex; ++ + #else + + static inline void eventpoll_init_file(struct file *file) {} +Index: kernel/include/linux/faudit.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/faudit.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,45 @@ ++/* ++ * include/linux/faudit.h ++ * ++ * Copyright (C) 2005 SWSoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __FAUDIT_H_ ++#define __FAUDIT_H_ ++ ++#include ++ ++struct vfsmount; ++struct dentry; ++struct super_block; ++struct kstatfs; ++struct kstat; ++struct pt_regs; ++ ++struct faudit_regs_arg { ++ int err; ++ struct pt_regs *regs; ++}; ++ ++struct faudit_stat_arg { ++ int err; ++ struct vfsmount *mnt; ++ struct dentry *dentry; ++ struct kstat *stat; ++}; ++ ++struct faudit_statfs_arg { ++ int err; ++ struct super_block *sb; ++ struct kstatfs *stat; ++}; ++ ++#define VIRTINFO_FAUDIT (0) ++#define VIRTINFO_FAUDIT_STAT (VIRTINFO_FAUDIT + 0) ++#define VIRTINFO_FAUDIT_STATFS (VIRTINFO_FAUDIT + 1) ++ ++#endif +Index: kernel/include/linux/fs.h +=================================================================== +--- kernel.orig/include/linux/fs.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/fs.h 2008-11-24 15:47:46.000000000 +0100 +@@ -49,6 +49,7 @@ + extern struct inodes_stat_t inodes_stat; + + extern int leases_enable, lease_break_time; ++extern int odirect_enable; + + #ifdef CONFIG_DNOTIFY + extern int dir_notify_enable; +@@ -68,6 +69,7 @@ + #define FMODE_LSEEK 4 + #define FMODE_PREAD 8 + #define FMODE_PWRITE FMODE_PREAD /* These go hand in hand */ ++#define FMODE_QUOTACTL 4 + + /* File is being opened for execution. Primary users of this flag are + distributed filesystems that can use it to achieve correct ETXTBUSY +@@ -93,6 +95,8 @@ + #define FS_REQUIRES_DEV 1 + #define FS_BINARY_MOUNTDATA 2 + #define FS_HAS_SUBTYPE 4 ++#define FS_VIRTUALIZED 64 /* Can mount this fstype inside ve */ ++#define FS_MANGLE_PROC 128 /* hide some /proc/mounts info inside VE */ + #define FS_REVAL_DOT 16384 /* Check the paths ".", ".." for staleness */ + #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() + * during rename() internally. +@@ -357,6 +361,9 @@ + * Includes for diskquotas. + */ + #include ++#if defined(CONFIG_VZ_QUOTA) || defined(CONFIG_VZ_QUOTA_MODULE) ++#include ++#endif + + /** + * enum positive_aop_returns - aop return codes with specific semantics +@@ -616,6 +623,9 @@ + #ifdef CONFIG_QUOTA + struct dquot *i_dquot[MAXQUOTAS]; + #endif ++#if defined(CONFIG_VZ_QUOTA) || defined(CONFIG_VZ_QUOTA_MODULE) ++ struct vz_quota_ilink i_qlnk; ++#endif + struct list_head i_devices; + union { + struct pipe_inode_info *i_pipe; +@@ -671,6 +681,8 @@ + extern void inode_double_lock(struct inode *inode1, struct inode *inode2); + extern void inode_double_unlock(struct inode *inode1, struct inode *inode2); + ++extern struct kmem_cache *inode_cachep; ++ + /* + * NOTE: in a 32bit arch with a preemptable kernel and + * an UP compile the i_size_read/write must be atomic +@@ -787,6 +799,7 @@ + struct fown_struct f_owner; + unsigned int f_uid, f_gid; + struct file_ra_state f_ra; ++ struct user_beancounter *f_ub; + + u64 f_version; + #ifdef CONFIG_SECURITY +@@ -801,7 +814,9 @@ + spinlock_t f_ep_lock; + #endif /* #ifdef CONFIG_EPOLL */ + struct address_space *f_mapping; ++ struct ve_struct *owner_env; + }; ++ + extern spinlock_t files_lock; + #define file_list_lock() spin_lock(&files_lock); + #define file_list_unlock() spin_unlock(&files_lock); +@@ -867,6 +882,9 @@ + struct file *fl_file; + unsigned char fl_flags; + unsigned char fl_type; ++#ifdef CONFIG_BEANCOUNTERS ++ unsigned char fl_charged; ++#endif + loff_t fl_start; + loff_t fl_end; + +@@ -1183,6 +1201,7 @@ + int (*setlease)(struct file *, long, struct file_lock **); + int (*fgetattr)(struct file *, struct kstat *); + int (*fsetattr)(struct file *, struct iattr *); ++ struct file * (*get_host)(struct file *); + }; + + struct inode_operations { +@@ -1256,6 +1275,7 @@ + #ifdef CONFIG_QUOTA + ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); + ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); ++ struct inode *(*get_quota_root)(struct super_block *); + #endif + }; + +@@ -1415,8 +1435,14 @@ + struct lock_class_key i_mutex_key; + struct lock_class_key i_mutex_dir_key; + struct lock_class_key i_alloc_sem_key; ++ ++ struct file_system_type *proto; ++ struct ve_struct *owner_env; + }; + ++void get_filesystem(struct file_system_type *fs); ++void put_filesystem(struct file_system_type *fs); ++ + extern int get_sb_bdev(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, + int (*fill_super)(struct super_block *, void *, int), +@@ -1457,9 +1483,14 @@ + extern int unregister_filesystem(struct file_system_type *); + extern struct vfsmount *kern_mount_data(struct file_system_type *, void *data); + #define kern_mount(type) kern_mount_data(type, NULL) ++extern int register_ve_fs_type(struct ve_struct *, struct file_system_type *, ++ struct file_system_type **, struct vfsmount **); ++extern void unregister_ve_fs_type(struct file_system_type *, struct vfsmount *); ++extern void umount_ve_fs_type(struct file_system_type *local_fs_type); + extern int may_umount_tree(struct vfsmount *); + extern int may_umount(struct vfsmount *); + extern void umount_tree(struct vfsmount *, int, struct list_head *); ++#define kern_umount mntput + extern void release_mounts(struct list_head *); + extern long do_mount(char *, char *, char *, unsigned long, void *); + extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); +@@ -1469,6 +1500,7 @@ + extern void drop_collected_mounts(struct vfsmount *); + + extern int vfs_statfs(struct dentry *, struct kstatfs *); ++extern int faudit_statfs(struct super_block *, struct kstatfs *); + + /* /sys/fs */ + extern struct kset fs_subsys; +@@ -1608,7 +1640,7 @@ + #define BLKDEV_MAJOR_HASH_SIZE 255 + extern const char *__bdevname(dev_t, char *buffer); + extern const char *bdevname(struct block_device *bdev, char *buffer); +-extern struct block_device *lookup_bdev(const char *); ++extern struct block_device *lookup_bdev(const char *, int mode); + extern struct block_device *open_bdev_excl(const char *, int, void *); + extern void close_bdev_excl(struct block_device *); + extern void blkdev_show(struct seq_file *,off_t); +@@ -1643,7 +1675,8 @@ + extern int __invalidate_device(struct block_device *); + extern int invalidate_partition(struct gendisk *, int); + #endif +-extern int invalidate_inodes(struct super_block *); ++extern int invalidate_inodes_check(struct super_block *, int check); ++#define invalidate_inodes(sb) invalidate_inodes_check(sb, 0) + unsigned long __invalidate_mapping_pages(struct address_space *mapping, + pgoff_t start, pgoff_t end, + bool be_atomic); +@@ -2087,10 +2120,20 @@ + { } + #endif /* CONFIG_SECURITY */ + ++static inline void *file_private(struct file *file) ++{ ++ struct file *host = file; ++ ++ while (host->f_op->get_host) { ++ host = host->f_op->get_host(host); ++ BUG_ON(host->f_mapping != file->f_mapping); ++ } ++ return host->private_data; ++} ++ + struct ctl_table; + int proc_nr_files(struct ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos); + +- + #endif /* __KERNEL__ */ + #endif /* _LINUX_FS_H */ +Index: kernel/include/linux/futex.h +=================================================================== +--- kernel.orig/include/linux/futex.h 2008-11-24 14:14:38.000000000 +0100 ++++ kernel/include/linux/futex.h 2008-11-24 15:47:46.000000000 +0100 +@@ -110,7 +110,7 @@ + #ifdef __KERNEL__ + long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout, + u32 __user *uaddr2, u32 val2, u32 val3); +- ++long futex_wait_restart(struct restart_block *restart); + extern int + handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi); + +Index: kernel/include/linux/genhd.h +=================================================================== +--- kernel.orig/include/linux/genhd.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/genhd.h 2008-11-24 15:47:46.000000000 +0100 +@@ -435,6 +435,7 @@ + return bdget(MKDEV(disk->major, disk->first_minor) + index); + } + ++extern struct kset block_subsys; + #endif + + #else /* CONFIG_BLOCK */ +Index: kernel/include/linux/gfp.h +=================================================================== +--- kernel.orig/include/linux/gfp.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/gfp.h 2008-11-24 15:47:46.000000000 +0100 +@@ -50,20 +50,25 @@ + #define __GFP_THISNODE ((__force gfp_t)0x40000u)/* No fallback, no policies */ + #define __GFP_RECLAIMABLE ((__force gfp_t)0x80000u) /* Page is reclaimable */ + #define __GFP_MOVABLE ((__force gfp_t)0x100000u) /* Page is movable */ ++#define __GFP_UBC ((__force gfp_t)0x200000u)/* charge kmem in buddy and slab */ ++#define __GFP_SOFT_UBC ((__force gfp_t)0x400000u)/* use soft charging */ + +-#define __GFP_BITS_SHIFT 21 /* Room for 21 __GFP_FOO bits */ ++#define __GFP_BITS_SHIFT 23 /* Room for __GFP_FOO bits */ + #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) + + /* This equals 0, but use constants in case they ever change */ + #define GFP_NOWAIT (GFP_ATOMIC & ~__GFP_HIGH) + /* GFP_ATOMIC means both !wait (__GFP_WAIT not set) and use emergency pool */ + #define GFP_ATOMIC (__GFP_HIGH) ++#define GFP_ATOMIC_UBC (__GFP_HIGH | __GFP_UBC) + #define GFP_NOIO (__GFP_WAIT) + #define GFP_NOFS (__GFP_WAIT | __GFP_IO) + #define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS) ++#define GFP_KERNEL_UBC (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_UBC) + #define GFP_TEMPORARY (__GFP_WAIT | __GFP_IO | __GFP_FS | \ + __GFP_RECLAIMABLE) + #define GFP_USER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL) ++#define GFP_USER_UBC (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | __GFP_UBC) + #define GFP_HIGHUSER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \ + __GFP_HIGHMEM) + #define GFP_HIGHUSER_MOVABLE (__GFP_WAIT | __GFP_IO | __GFP_FS | \ +Index: kernel/include/linux/grinternal.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/grinternal.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,91 @@ ++#ifndef __GRINTERNAL_H ++#define __GRINTERNAL_H ++ ++#ifdef CONFIG_GRKERNSEC ++ ++#include ++ ++extern char *gr_to_filename(const struct dentry *dentry, ++ const struct vfsmount *mnt); ++extern char *gr_to_filename2(const struct dentry *dentry, ++ const struct vfsmount *mnt); ++extern char *gr_to_filename3(const struct dentry *dentry, ++ const struct vfsmount *mnt); ++ ++#ifdef CONFIG_VE ++#include ++#define grsec_enable_tpe (get_exec_env()->grsec.enable_tpe) ++#define grsec_tpe_gid (get_exec_env()->grsec.tpe_gid) ++#define grsec_enable_tpe_all (get_exec_env()->grsec.enable_tpe_all) ++#define grsec_lock (get_exec_env()->grsec.lock) ++#else ++extern int grsec_enable_tpe; ++extern int grsec_tpe_gid; ++extern int grsec_enable_tpe_all; ++extern int grsec_lock; ++#endif ++ ++extern spinlock_t grsec_alert_lock; ++extern unsigned long grsec_alert_wtime; ++extern unsigned long grsec_alert_fyet; ++ ++extern spinlock_t grsec_audit_lock; ++ ++#define gr_task_fullpath(tsk) ("") ++ ++#define gr_parent_task_fullpath(tsk) ("") ++ ++#define DEFAULTSECARGS(task) gr_task_fullpath(task), task->comm, \ ++ task->pid, task->uid, \ ++ task->euid, task->gid, task->egid, \ ++ gr_parent_task_fullpath(task), \ ++ task->parent->comm, task->parent->pid, \ ++ task->parent->uid, task->parent->euid, \ ++ task->parent->gid, task->parent->egid ++ ++enum { ++ GR_DO_AUDIT, ++ GR_DONT_AUDIT, ++ GR_DONT_AUDIT_GOOD ++}; ++ ++enum { ++ GR_TTYSNIFF, ++ GR_RBAC, ++ GR_RBAC_STR, ++ GR_STR_RBAC, ++ GR_RBAC_MODE2, ++ GR_RBAC_MODE3, ++ GR_FILENAME, ++ GR_NOARGS, ++ GR_ONE_INT, ++ GR_ONE_INT_TWO_STR, ++ GR_ONE_STR, ++ GR_STR_INT, ++ GR_TWO_INT, ++ GR_THREE_INT, ++ GR_FIVE_INT_TWO_STR, ++ GR_TWO_STR, ++ GR_THREE_STR, ++ GR_FOUR_STR, ++ GR_STR_FILENAME, ++ GR_FILENAME_STR, ++ GR_FILENAME_TWO_INT, ++ GR_FILENAME_TWO_INT_STR, ++ GR_TEXTREL, ++ GR_PTRACE, ++ GR_RESOURCE, ++ GR_CAP, ++ GR_SIG, ++ GR_CRASH1, ++ GR_CRASH2, ++ GR_PSACCT ++}; ++ ++#define gr_log_fs_generic(audit, msg, dentry, mnt) gr_log_varargs(audit, msg, GR_FILENAME, dentry, mnt) ++#define gr_log_str(audit, msg, str) gr_log_varargs(audit, msg, GR_ONE_STR, str) ++ ++extern void gr_log_varargs(int audit, const char *msg, int argtypes, ...); ++ ++#endif ++#endif +Index: kernel/include/linux/grmsg.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/grmsg.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,3 @@ ++#define DEFAULTSECMSG "%.256s[%.16s:%d] uid/euid:%u/%u gid/egid:%u/%u, parent %.256s[%.16s:%d] uid/euid:%u/%u gid/egid:%u/%u" ++#define GR_EXEC_TPE_MSG "denied untrusted exec of %.950s by " ++#define GR_SYSCTL_MSG "denied modification of grsecurity sysctl value : %.32s by " +Index: kernel/include/linux/grsecurity.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/grsecurity.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,13 @@ ++#ifndef GR_SECURITY_H ++#define GR_SECURITY_H ++#include ++ ++extern int gr_tpe_allow(const struct file *file); ++extern void gr_copy_label(struct task_struct *tsk); ++extern int gr_acl_handle_mmap(const struct file *file, ++ const unsigned long prot); ++extern int gr_acl_handle_mprotect(const struct file *file, ++ const unsigned long prot); ++extern void gr_acl_handle_exit(void); ++ ++#endif +Index: kernel/include/linux/hardirq.h +=================================================================== +--- kernel.orig/include/linux/hardirq.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/hardirq.h 2008-11-24 15:47:46.000000000 +0100 +@@ -7,6 +7,9 @@ + #include + #include + ++#include ++#include ++ + /* + * We put the hardirq and softirq counter into the preemption + * counter. The bitmask has the following meaning: +@@ -113,6 +116,24 @@ + } + #endif + ++#define save_context() do { \ ++ struct task_struct *tsk; \ ++ if (hardirq_count() == HARDIRQ_OFFSET) { \ ++ tsk = current; \ ++ ve_save_context(tsk); \ ++ ub_save_context(tsk); \ ++ } \ ++ } while (0) ++ ++#define restore_context() do { \ ++ struct task_struct *tsk; \ ++ if (hardirq_count() == HARDIRQ_OFFSET) { \ ++ tsk = current; \ ++ ve_restore_context(tsk); \ ++ ub_restore_context(tsk); \ ++ } \ ++ } while (0) ++ + /* + * It is safe to do non-atomic ops on ->hardirq_context, + * because NMI handlers may not preempt and the ops are +@@ -123,6 +144,7 @@ + do { \ + account_system_vtime(current); \ + add_preempt_count(HARDIRQ_OFFSET); \ ++ save_context(); \ + trace_hardirq_enter(); \ + } while (0) + +@@ -138,6 +160,7 @@ + do { \ + trace_hardirq_exit(); \ + account_system_vtime(current); \ ++ restore_context(); \ + sub_preempt_count(HARDIRQ_OFFSET); \ + } while (0) + +Index: kernel/include/linux/hrtimer.h +=================================================================== +--- kernel.orig/include/linux/hrtimer.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/hrtimer.h 2008-11-24 15:47:46.000000000 +0100 +@@ -304,6 +304,9 @@ + const enum hrtimer_mode mode, + const clockid_t clockid); + extern long hrtimer_nanosleep_restart(struct restart_block *restart_block); ++#ifdef CONFIG_COMPAT ++long compat_nanosleep_restart(struct restart_block *restart); ++#endif + + extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, + struct task_struct *tsk); +Index: kernel/include/linux/if_bridge.h +=================================================================== +--- kernel.orig/include/linux/if_bridge.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/if_bridge.h 2008-11-24 15:47:46.000000000 +0100 +@@ -44,6 +44,7 @@ + #define BRCTL_SET_PORT_PRIORITY 16 + #define BRCTL_SET_PATH_COST 17 + #define BRCTL_GET_FDB_ENTRIES 18 ++#define BRCTL_SET_VIA_ORIG_DEV 19 + + #define BR_STATE_DISABLED 0 + #define BR_STATE_LISTENING 1 +@@ -72,6 +73,7 @@ + __u32 tcn_timer_value; + __u32 topology_change_timer_value; + __u32 gc_timer_value; ++ __u8 via_phys_dev; + }; + + struct __port_info +@@ -104,9 +106,12 @@ + + #include + ++#define BR_ALREADY_SEEN 1 ++ + extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); + extern struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p, + struct sk_buff *skb); ++extern int (*br_hard_xmit_hook)(struct sk_buff *skb, struct net_bridge_port *port); + extern int (*br_should_route_hook)(struct sk_buff *skb); + + #endif +Index: kernel/include/linux/if_tun.h +=================================================================== +--- kernel.orig/include/linux/if_tun.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/if_tun.h 2008-11-24 15:47:46.000000000 +0100 +@@ -18,10 +18,14 @@ + #ifndef __IF_TUN_H + #define __IF_TUN_H + ++#include ++#include ++ + /* Uncomment to enable debugging */ + /* #define TUN_DEBUG 1 */ + + #ifdef __KERNEL__ ++#include + + #ifdef TUN_DEBUG + #define DBG if(tun->debug)printk +@@ -35,6 +39,7 @@ + struct list_head list; + unsigned long flags; + int attached; ++ void *bind_file; + uid_t owner; + gid_t group; + +@@ -92,4 +97,10 @@ + }; + #define TUN_PKT_STRIP 0x0001 + ++extern int tun_net_open(struct net_device *dev); ++extern int tun_chr_open(struct inode *inode, struct file * file); ++extern void tun_net_init(struct net_device *dev); ++extern void tun_setup(struct net_device *dev); ++extern struct list_head tun_dev_list; ++ + #endif /* __IF_TUN_H */ +Index: kernel/include/linux/if_vlan.h +=================================================================== +--- kernel.orig/include/linux/if_vlan.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/if_vlan.h 2008-11-24 15:47:46.000000000 +0100 +@@ -79,6 +79,9 @@ + struct hlist_node hlist; /* linked list */ + struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS]; + struct rcu_head rcu; ++#ifdef CONFIG_VE ++ struct ve_struct *owner; ++#endif + }; + + static inline struct net_device *vlan_group_get_device(struct vlan_group *vg, int vlan_id) +Index: kernel/include/linux/inetdevice.h +=================================================================== +--- kernel.orig/include/linux/inetdevice.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/inetdevice.h 2008-11-24 15:47:46.000000000 +0100 +@@ -18,6 +18,12 @@ + }; + + extern struct ipv4_devconf ipv4_devconf; ++extern struct ipv4_devconf ipv4_devconf_dflt; ++#if defined(CONFIG_VE) && defined(CONFIG_INET) ++#define ve_ipv4_devconf (*(get_exec_env()->_ipv4_devconf)) ++#else ++#define ve_ipv4_devconf ipv4_devconf ++#endif + + struct in_device + { +@@ -44,7 +50,7 @@ + }; + + #define IPV4_DEVCONF(cnf, attr) ((cnf).data[NET_IPV4_CONF_ ## attr - 1]) +-#define IPV4_DEVCONF_ALL(attr) IPV4_DEVCONF(ipv4_devconf, attr) ++#define IPV4_DEVCONF_ALL(attr) IPV4_DEVCONF(ve_ipv4_devconf, attr) + + static inline int ipv4_devconf_get(struct in_device *in_dev, int index) + { +@@ -136,6 +142,7 @@ + extern __be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope); + extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, __be32 mask); + extern void inet_forward_change(void); ++extern void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy); + + static __inline__ int inet_ifa_match(__be32 addr, struct in_ifaddr *ifa) + { +@@ -204,6 +211,16 @@ + #define __in_dev_put(idev) atomic_dec(&(idev)->refcnt) + #define in_dev_hold(idev) atomic_inc(&(idev)->refcnt) + ++struct ve_struct; ++#ifdef CONFIG_INET ++extern int devinet_sysctl_init(struct ve_struct *); ++extern void devinet_sysctl_fini(struct ve_struct *); ++extern void devinet_sysctl_free(struct ve_struct *); ++#else ++static inline int devinet_sysctl_init(struct ve_struct *ve) { return 0; } ++static inline void devinet_sysctl_fini(struct ve_struct *ve) { ; } ++static inline void devinet_sysctl_free(struct ve_struct *ve) { ; } ++#endif + #endif /* __KERNEL__ */ + + static __inline__ __be32 inet_make_mask(int logmask) +Index: kernel/include/linux/init_task.h +=================================================================== +--- kernel.orig/include/linux/init_task.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/init_task.h 2008-11-24 15:47:46.000000000 +0100 +@@ -69,10 +69,17 @@ + .rlim = INIT_RLIMITS, \ + } + ++#ifdef CONFIG_VE ++/* one for ve0, one for init_task */ ++#define INIT_NSPROXY_COUNT ATOMIC_INIT(2) ++#else ++#define INIT_NSPROXY_COUNT ATOMIC_INIT(1) ++#endif ++ + extern struct nsproxy init_nsproxy; + #define INIT_NSPROXY(nsproxy) { \ + .pid_ns = &init_pid_ns, \ +- .count = ATOMIC_INIT(1), \ ++ .count = INIT_NSPROXY_COUNT, \ + .uts_ns = &init_uts_ns, \ + .mnt_ns = NULL, \ + INIT_NET_NS(net_ns) \ +Index: kernel/include/linux/inotify.h +=================================================================== +--- kernel.orig/include/linux/inotify.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/inotify.h 2008-11-24 15:47:46.000000000 +0100 +@@ -67,6 +67,7 @@ + + #include + #include ++#include + + /* + * struct inotify_watch - represents a watch request on a specific inode +@@ -84,6 +85,8 @@ + struct list_head i_list; /* entry in inode's list */ + atomic_t count; /* reference count */ + struct inotify_handle *ih; /* associated inotify handle */ ++ struct dentry *dentry; ++ struct vfsmount *mnt; + struct inode *inode; /* associated inode */ + __s32 wd; /* watch descriptor */ + __u32 mask; /* event mask for this watch */ +@@ -120,6 +123,8 @@ + u32); + extern __s32 inotify_add_watch(struct inotify_handle *, struct inotify_watch *, + struct inode *, __u32); ++extern __s32 inotify_add_watch_dget(struct inotify_handle *, struct inotify_watch *, ++ struct dentry *, struct vfsmount *, __u32); + extern __s32 inotify_clone_watch(struct inotify_watch *, struct inotify_watch *); + extern void inotify_evict_watch(struct inotify_watch *); + extern int inotify_rm_watch(struct inotify_handle *, struct inotify_watch *); +@@ -129,6 +134,66 @@ + extern void get_inotify_watch(struct inotify_watch *); + extern void put_inotify_watch(struct inotify_watch *); + ++/* ++ * struct inotify_handle - represents an inotify instance ++ * ++ * This structure is protected by the mutex 'mutex'. ++ */ ++struct inotify_handle { ++ struct idr idr; /* idr mapping wd -> watch */ ++ struct mutex mutex; /* protects this bad boy */ ++ struct list_head watches; /* list of watches */ ++ atomic_t count; /* reference count */ ++ u32 last_wd; /* the last wd allocated */ ++ const struct inotify_operations *in_ops; /* inotify caller operations */ ++}; ++ ++ ++/* ++ * struct inotify_device - represents an inotify instance ++ * ++ * This structure is protected by the mutex 'mutex'. ++ */ ++struct inotify_device { ++ wait_queue_head_t wq; /* wait queue for i/o */ ++ struct mutex ev_mutex; /* protects event queue */ ++ struct mutex up_mutex; /* synchronizes watch updates */ ++ struct list_head events; /* list of queued events */ ++ atomic_t count; /* reference count */ ++ struct user_struct *user; /* user who opened this dev */ ++ struct inotify_handle *ih; /* inotify handle */ ++ unsigned int queue_size; /* size of the queue (bytes) */ ++ unsigned int event_count; /* number of pending events */ ++ unsigned int max_events; /* maximum number of events */ ++}; ++ ++/* ++ * struct inotify_kernel_event - An inotify event, originating from a watch and ++ * queued for user-space. A list of these is attached to each instance of the ++ * device. In read(), this list is walked and all events that can fit in the ++ * buffer are returned. ++ * ++ * Protected by dev->ev_mutex of the device in which we are queued. ++ */ ++struct inotify_kernel_event { ++ struct inotify_event event; /* the user-space event */ ++ struct list_head list; /* entry in inotify_device's list */ ++ char *name; /* filename, if any */ ++}; ++ ++/* ++ * struct inotify_user_watch - our version of an inotify_watch, we add ++ * a reference to the associated inotify_device. ++ */ ++struct inotify_user_watch { ++ struct inotify_device *dev; /* associated device */ ++ struct inotify_watch wdata; /* inotify watch data */ ++}; ++ ++int inotify_create_watch(struct inotify_device *dev, struct dentry *d, ++ struct vfsmount *mnt, u32 mask); ++ ++ + #else + + static inline void inotify_d_instantiate(struct dentry *dentry, +Index: kernel/include/linux/ioprio.h +=================================================================== +--- kernel.orig/include/linux/ioprio.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/ioprio.h 2008-11-24 15:47:46.000000000 +0100 +@@ -38,6 +38,7 @@ + IOPRIO_WHO_PROCESS = 1, + IOPRIO_WHO_PGRP, + IOPRIO_WHO_USER, ++ IOPRIO_WHO_UBC = 1000, + }; + + /* +Index: kernel/include/linux/ipv6.h +=================================================================== +--- kernel.orig/include/linux/ipv6.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/ipv6.h 2008-11-24 15:47:46.000000000 +0100 +@@ -457,12 +457,13 @@ + #define inet_v6_ipv6only(__sk) 0 + #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ + +-#define INET6_MATCH(__sk, __hash, __saddr, __daddr, __ports, __dif)\ ++#define INET6_MATCH(__sk, __hash, __saddr, __daddr, __ports, __dif,__ve)\ + (((__sk)->sk_hash == (__hash)) && \ + ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ + ((__sk)->sk_family == AF_INET6) && \ + ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \ + ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \ ++ ve_accessible_strict((__sk)->owner_env, (__ve)) && \ + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) + + #endif /* __KERNEL__ */ +Index: kernel/include/linux/kdev_t.h +=================================================================== +--- kernel.orig/include/linux/kdev_t.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/kdev_t.h 2008-11-24 15:47:46.000000000 +0100 +@@ -87,6 +87,57 @@ + return dev & 0x3ffff; + } + ++#define UNNAMED_MAJOR_COUNT 16 ++ ++#if UNNAMED_MAJOR_COUNT > 1 ++ ++extern int unnamed_dev_majors[UNNAMED_MAJOR_COUNT]; ++ ++static inline dev_t make_unnamed_dev(int idx) ++{ ++ /* ++ * Here we transfer bits from 8 to 8+log2(UNNAMED_MAJOR_COUNT) of the ++ * unnamed device index into major number. ++ */ ++ return MKDEV(unnamed_dev_majors[(idx >> 8) & (UNNAMED_MAJOR_COUNT - 1)], ++ idx & ~((UNNAMED_MAJOR_COUNT - 1) << 8)); ++} ++ ++static inline int unnamed_dev_idx(dev_t dev) ++{ ++ int i; ++ for (i = 0; i < UNNAMED_MAJOR_COUNT && ++ MAJOR(dev) != unnamed_dev_majors[i]; i++); ++ return MINOR(dev) | (i << 8); ++} ++ ++static inline int is_unnamed_dev(dev_t dev) ++{ ++ int i; ++ for (i = 0; i < UNNAMED_MAJOR_COUNT && ++ MAJOR(dev) != unnamed_dev_majors[i]; i++); ++ return i < UNNAMED_MAJOR_COUNT; ++} ++ ++#else /* UNNAMED_MAJOR_COUNT */ ++ ++static inline dev_t make_unnamed_dev(int idx) ++{ ++ return MKDEV(0, idx); ++} ++ ++static inline int unnamed_dev_idx(dev_t dev) ++{ ++ return MINOR(dev); ++} ++ ++static inline int is_unnamed_dev(dev_t dev) ++{ ++ return MAJOR(dev) == 0; ++} ++ ++#endif /* UNNAMED_MAJOR_COUNT */ ++ + #else /* __KERNEL__ */ + + /* +Index: kernel/include/linux/kernel.h +=================================================================== +--- kernel.orig/include/linux/kernel.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/kernel.h 2008-11-24 15:47:46.000000000 +0100 +@@ -182,6 +182,12 @@ + extern int log_buf_get_len(void); + extern int log_buf_read(int idx); + extern int log_buf_copy(char *dest, int idx, int len); ++ ++asmlinkage int ve_vprintk(int dst, const char *fmt, va_list args) ++ __attribute__ ((format (printf, 2, 0))); ++asmlinkage int ve_printk(int, const char * fmt, ...) ++ __attribute__ ((format (printf, 2, 3))); ++void prepare_printk(void); + #else + static inline int vprintk(const char *s, va_list args) + __attribute__ ((format (printf, 1, 0))); +@@ -192,8 +198,22 @@ + static inline int log_buf_get_len(void) { return 0; } + static inline int log_buf_read(int idx) { return 0; } + static inline int log_buf_copy(char *dest, int idx, int len) { return 0; } ++ ++static inline int ve_printk(int d, const char *s, ...) ++ __attribute__ ((format (printf, 2, 3))); ++static inline int ve_printk(int d, const char *s, ...) ++{ ++ return 0; ++} ++static inline void prepare_printk(void) ++{ ++} + #endif + ++#define VE0_LOG 1 ++#define VE_LOG 2 ++#define VE_LOG_BOTH (VE0_LOG | VE_LOG) ++ + unsigned long int_sqrt(unsigned long); + + extern int printk_ratelimit(void); +@@ -201,9 +221,14 @@ + extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, + unsigned int interval_msec); + ++extern int console_silence_loglevel; ++ + static inline void console_silent(void) + { +- console_loglevel = 0; ++ if (console_loglevel > console_silence_loglevel) { ++ printk(KERN_EMERG "console shuts up ...\n"); ++ console_loglevel = 0; ++ } + } + + static inline void console_verbose(void) +@@ -217,8 +242,10 @@ + extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in progress */ + extern int panic_timeout; + extern int panic_on_oops; ++extern int decode_call_traces; + extern int panic_on_unrecovered_nmi; + extern int tainted; ++extern int kernel_text_csum_broken; + extern const char *print_tainted(void); + extern void add_taint(unsigned); + +Index: kernel/include/linux/kobject.h +=================================================================== +--- kernel.orig/include/linux/kobject.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/kobject.h 2008-11-24 15:47:46.000000000 +0100 +@@ -55,6 +55,8 @@ + KOBJ_REMOVE, + KOBJ_CHANGE, + KOBJ_MOVE, ++ KOBJ_START, ++ KOBJ_STOP, + KOBJ_ONLINE, + KOBJ_OFFLINE, + KOBJ_MAX +@@ -202,6 +204,9 @@ + /* The global /sys/hypervisor/ subsystem */ + extern struct kset hypervisor_subsys; + ++extern struct kset class_obj_subsys; ++extern struct kset class_subsys; ++ + /* + * Helpers for setting the kset of registered objects. + * Often, a registered object belongs to a kset embedded in a +Index: kernel/include/linux/lockd/lockd.h +=================================================================== +--- kernel.orig/include/linux/lockd/lockd.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/lockd/lockd.h 2008-11-24 15:47:46.000000000 +0100 +@@ -61,6 +61,7 @@ + struct list_head h_granted; /* Locks in GRANTED state */ + struct list_head h_reclaim; /* Locks in RECLAIM state */ + struct nsm_handle * h_nsmhandle; /* NSM status handle */ ++ struct ve_struct * owner_env; /* VE owning the host */ + }; + + struct nsm_handle { +@@ -151,8 +152,11 @@ + #ifdef CONFIG_LOCKD_V4 + extern struct svc_procedure nlmsvc_procedures4[]; + #endif +-extern int nlmsvc_grace_period; +-extern unsigned long nlmsvc_timeout; ++ ++#include ++extern int _nlmsvc_grace_period; ++extern unsigned long _nlmsvc_timeout; ++ + extern int nsm_use_hostnames; + + /* +Index: kernel/include/linux/major.h +=================================================================== +--- kernel.orig/include/linux/major.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/major.h 2008-11-24 15:47:46.000000000 +0100 +@@ -170,4 +170,7 @@ + + #define VIOTAPE_MAJOR 230 + ++#define UNNAMED_EXTRA_MAJOR 130 ++#define UNNAMED_EXTRA_MAJOR_COUNT 120 ++ + #endif +Index: kernel/include/linux/mm.h +=================================================================== +--- kernel.orig/include/linux/mm.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/mm.h 2008-11-24 15:47:46.000000000 +0100 +@@ -661,15 +661,7 @@ + + extern void show_free_areas(void); + +-#ifdef CONFIG_SHMEM +-int shmem_lock(struct file *file, int lock, struct user_struct *user); +-#else +-static inline int shmem_lock(struct file *file, int lock, +- struct user_struct *user) +-{ +- return 0; +-} +-#endif ++#define shmem_nopage filemap_nopage + struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags); + + int shmem_zero_setup(struct vm_area_struct *); +@@ -710,7 +702,9 @@ + void free_pgtables(struct mmu_gather **tlb, struct vm_area_struct *start_vma, + unsigned long floor, unsigned long ceiling); + int copy_page_range(struct mm_struct *dst, struct mm_struct *src, +- struct vm_area_struct *vma); ++ struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma); ++int __copy_page_range(struct vm_area_struct *dst_vma, struct vm_area_struct *vma, ++ unsigned long addr, size_t size); + void unmap_mapping_range(struct address_space *mapping, + loff_t const holebegin, loff_t const holelen, int even_cows); + +Index: kernel/include/linux/mm_types.h +=================================================================== +--- kernel.orig/include/linux/mm_types.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/mm_types.h 2008-11-24 15:47:46.000000000 +0100 +@@ -88,6 +88,13 @@ + void *virtual; /* Kernel virtual address (NULL if + not kmapped, ie. highmem) */ + #endif /* WANT_PAGE_VIRTUAL */ ++#ifdef CONFIG_BEANCOUNTERS ++ union { ++ struct user_beancounter *page_ub; ++ struct page_beancounter *page_pb; ++ struct user_beancounter **slub_ubs; ++ } bc; ++#endif + }; + + /* +@@ -212,6 +219,9 @@ + + unsigned long flags; /* Must use atomic bitops to access the bits */ + ++ unsigned int vps_dumpable:2; ++ unsigned int oom_killed:1; ++ + /* coredumping support */ + int core_waiters; + struct completion *core_startup_done, core_done; +@@ -219,6 +229,9 @@ + /* aio bits */ + rwlock_t ioctx_list_lock; + struct kioctx *ioctx_list; ++#ifdef CONFIG_BEANCOUNTERS ++ struct user_beancounter *mm_ub; ++#endif + }; + + #endif /* _LINUX_MM_TYPES_H */ +Index: kernel/include/linux/mman.h +=================================================================== +--- kernel.orig/include/linux/mman.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/mman.h 2008-11-24 15:47:46.000000000 +0100 +@@ -61,6 +61,9 @@ + calc_vm_flag_bits(unsigned long flags) + { + return _calc_vm_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN ) | ++#ifdef MAP_GROWSUP ++ _calc_vm_trans(flags, MAP_GROWSUP, VM_GROWSUP ) | ++#endif + _calc_vm_trans(flags, MAP_DENYWRITE, VM_DENYWRITE ) | + _calc_vm_trans(flags, MAP_EXECUTABLE, VM_EXECUTABLE) | + _calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ); +Index: kernel/include/linux/mnt_namespace.h +=================================================================== +--- kernel.orig/include/linux/mnt_namespace.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/mnt_namespace.h 2008-11-24 15:47:46.000000000 +0100 +@@ -16,6 +16,8 @@ + + extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, + struct fs_struct *); ++extern struct rw_semaphore namespace_sem; ++ + extern void __put_mnt_ns(struct mnt_namespace *ns); + + static inline void put_mnt_ns(struct mnt_namespace *ns) +Index: kernel/include/linux/mount.h +=================================================================== +--- kernel.orig/include/linux/mount.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/mount.h 2008-11-24 15:47:46.000000000 +0100 +@@ -61,6 +61,7 @@ + atomic_t mnt_count; + int mnt_expiry_mark; /* true if marked for expiry */ + int mnt_pinned; ++ unsigned owner; + }; + + static inline struct vfsmount *mntget(struct vfsmount *mnt) +Index: kernel/include/linux/msg.h +=================================================================== +--- kernel.orig/include/linux/msg.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/msg.h 2008-11-24 15:47:46.000000000 +0100 +@@ -97,6 +97,14 @@ + extern long do_msgrcv(int msqid, long *pmtype, void __user *mtext, + size_t msgsz, long msgtyp, int msgflg); + ++int sysvipc_walk_msg(int (*func)(int, struct msg_queue*, void *), void *arg); ++int sysvipc_setup_msg(key_t key, int msqid, int msgflg); ++int sysv_msg_store(struct msg_msg *msg, ++ int (*store)(void * src, int len, int offset, void * data), ++ int len, void * data); ++struct msg_msg *sysv_msg_load(int (*load)(void * dst, int len, int offset, ++ void * data), int len, void * data); ++ + #endif /* __KERNEL__ */ + + #endif /* _LINUX_MSG_H */ +Index: kernel/include/linux/namei.h +=================================================================== +--- kernel.orig/include/linux/namei.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/namei.h 2008-11-24 15:47:46.000000000 +0100 +@@ -61,6 +61,8 @@ + #define LOOKUP_CREATE (0x0200) + #define LOOKUP_ACCESS (0x0400) + #define LOOKUP_CHDIR (0x0800) ++#define LOOKUP_NOAREACHECK (0x1000) /* no area check on lookup */ ++#define LOOKUP_STRICT (0x2000) /* no symlinks or other filesystems */ + + extern int FASTCALL(__user_walk(const char __user *, unsigned, struct nameidata *)); + extern int FASTCALL(__user_walk_fd(int dfd, const char __user *, unsigned, struct nameidata *)); +Index: kernel/include/linux/netdevice.h +=================================================================== +--- kernel.orig/include/linux/netdevice.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/netdevice.h 2008-11-24 15:47:46.000000000 +0100 +@@ -280,6 +280,11 @@ + __LINK_STATE_QDISC_RUNNING, + }; + ++struct netdev_bc { ++ struct user_beancounter *exec_ub, *owner_ub; ++}; ++ ++#define netdev_bc(dev) (&(dev)->dev_bc) + + /* + * This structure holds at boot time configured netdevice settings. They +@@ -514,6 +519,10 @@ + #define NETIF_F_GSO_ROBUST (SKB_GSO_DODGY << NETIF_F_GSO_SHIFT) + #define NETIF_F_TSO_ECN (SKB_GSO_TCP_ECN << NETIF_F_GSO_SHIFT) + #define NETIF_F_TSO6 (SKB_GSO_TCPV6 << NETIF_F_GSO_SHIFT) ++/* device is venet device */ ++#define NETIF_F_VENET (1 << (NETIF_F_GSO_SHIFT - 1)) ++/* can be registered inside VE */ ++#define NETIF_F_VIRTUAL (1 << (NETIF_F_GSO_SHIFT - 2)) + + /* List of features with software fallbacks. */ + #define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6) +@@ -716,6 +725,9 @@ + /* macvlan */ + struct macvlan_port *macvlan_port; + ++ struct ve_struct *owner_env; /* Owner VE of the interface */ ++ struct netdev_bc dev_bc; ++ + /* class/net/name entry */ + struct device dev; + /* space for optional statistics and wireless sysfs groups */ +@@ -730,6 +742,20 @@ + }; + #define to_net_dev(d) container_of(d, struct net_device, dev) + ++#define NETDEV_HASHBITS 8 ++#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS) ++ ++static inline struct hlist_head *dev_name_hash(struct net *net, const char *name) ++{ ++ unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ)); ++ return &net->dev_name_head[hash & ((1 << NETDEV_HASHBITS) - 1)]; ++} ++ ++static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) ++{ ++ return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)]; ++} ++ + #define NETDEV_ALIGN 32 + #define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1) + +@@ -1092,6 +1118,9 @@ + extern unsigned dev_get_flags(const struct net_device *); + extern int dev_change_flags(struct net_device *, unsigned); + extern int dev_change_name(struct net_device *, char *); ++int __dev_change_net_namespace(struct net_device *, struct net *, const char *, ++ struct ve_struct *src_ve, struct ve_struct *dst_ve, ++ struct user_beancounter *exec_ub); + extern int dev_change_net_namespace(struct net_device *, + struct net *, const char *); + extern int dev_set_mtu(struct net_device *, int); +@@ -1453,6 +1482,18 @@ + + extern int netdev_compute_features(unsigned long all, unsigned long one); + ++#if defined(CONFIG_VE) && defined(CONFIG_NET) ++static inline int ve_is_dev_movable(struct net_device *dev) ++{ ++ return !(dev->features & NETIF_F_VIRTUAL); ++} ++#else ++static inline int ve_is_dev_movable(struct net_device *dev) ++{ ++ return 0; ++} ++#endif ++ + static inline int net_gso_ok(int features, int gso_type) + { + int feature = gso_type << NETIF_F_GSO_SHIFT; +Index: kernel/include/linux/netfilter.h +=================================================================== +--- kernel.orig/include/linux/netfilter.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/netfilter.h 2008-11-24 15:47:46.000000000 +0100 +@@ -126,7 +126,13 @@ + extern struct ctl_table nf_net_ipv4_netfilter_sysctl_path[]; + #endif /* CONFIG_SYSCTL */ + ++#ifdef CONFIG_VE_IPTABLES ++#define ve_nf_hooks \ ++ ((struct list_head (*)[NF_MAX_HOOKS])(get_exec_env()->_nf_hooks)) ++#else + extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; ++#define ve_nf_hooks nf_hooks ++#endif + + /* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will + * disappear once iptables is replaced with pkttables. Please DO NOT use them +@@ -204,7 +210,7 @@ + if (!cond) + return 1; + #ifndef CONFIG_NETFILTER_DEBUG +- if (list_empty(&nf_hooks[pf][hook])) ++ if (list_empty(&ve_nf_hooks[pf][hook])) + return 1; + #endif + return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh); +Index: kernel/include/linux/netfilter/x_tables.h +=================================================================== +--- kernel.orig/include/linux/netfilter/x_tables.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/netfilter/x_tables.h 2008-11-24 15:47:46.000000000 +0100 +@@ -259,6 +259,7 @@ + { + /* Size per table */ + unsigned int size; ++ unsigned int alloc_size; + /* Number of entries: FIXME. --RR */ + unsigned int number; + /* Initial number of entries. Needed for module usage count */ +@@ -293,6 +294,10 @@ + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); + extern void *xt_unregister_table(struct xt_table *table); ++extern struct xt_table *virt_xt_register_table(struct xt_table *table, ++ struct xt_table_info *bootstrap, ++ struct xt_table_info *newinfo); ++extern void *virt_xt_unregister_table(struct xt_table *table); + + extern struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +Index: kernel/include/linux/netfilter/xt_hashlimit.h +=================================================================== +--- kernel.orig/include/linux/netfilter/xt_hashlimit.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/netfilter/xt_hashlimit.h 2008-11-24 15:47:46.000000000 +0100 +@@ -37,4 +37,10 @@ + struct xt_hashlimit_info *master; + } u; + }; ++ ++struct ve_xt_hashlimit { ++ struct hlist_head hashlimit_htables; ++ struct proc_dir_entry *hashlimit_procdir4; ++ struct proc_dir_entry *hashlimit_procdir6; ++}; + #endif /*_XT_HASHLIMIT_H*/ +Index: kernel/include/linux/netfilter_ipv4/ip_tables.h +=================================================================== +--- kernel.orig/include/linux/netfilter_ipv4/ip_tables.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/netfilter_ipv4/ip_tables.h 2008-11-24 15:47:46.000000000 +0100 +@@ -292,7 +292,7 @@ + #include + extern void ipt_init(void) __init; + +-extern int ipt_register_table(struct xt_table *table, ++extern struct xt_table *ipt_register_table(struct xt_table *table, + const struct ipt_replace *repl); + extern void ipt_unregister_table(struct xt_table *table); + +Index: kernel/include/linux/netfilter_ipv4/ipt_recent.h +=================================================================== +--- kernel.orig/include/linux/netfilter_ipv4/ipt_recent.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/netfilter_ipv4/ipt_recent.h 2008-11-24 15:47:46.000000000 +0100 +@@ -24,4 +24,10 @@ + u_int8_t side; + }; + ++struct ve_ipt_recent { ++ struct list_head tables; ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *proc_dir; ++#endif ++}; + #endif /*_IPT_RECENT_H*/ +Index: kernel/include/linux/netfilter_ipv6/ip6_tables.h +=================================================================== +--- kernel.orig/include/linux/netfilter_ipv6/ip6_tables.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/netfilter_ipv6/ip6_tables.h 2008-11-24 15:47:46.000000000 +0100 +@@ -333,7 +333,7 @@ + #include + extern void ip6t_init(void) __init; + +-extern int ip6t_register_table(struct xt_table *table, ++extern struct xt_table *ip6t_register_table(struct xt_table *table, + const struct ip6t_replace *repl); + extern void ip6t_unregister_table(struct xt_table *table); + extern unsigned int ip6t_do_table(struct sk_buff *skb, +Index: kernel/include/linux/nfcalls.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/nfcalls.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,188 @@ ++/* ++ * include/linux/nfcalls.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef _LINUX_NFCALLS_H ++#define _LINUX_NFCALLS_H ++ ++#include ++ ++#ifdef CONFIG_MODULES ++extern struct module no_module; ++ ++#define DECL_KSYM_MODULE(name) \ ++ extern struct module *vz_mod_##name ++ ++#define INIT_KSYM_MODULE(name) \ ++ struct module *vz_mod_##name = &no_module; \ ++ EXPORT_SYMBOL(vz_mod_##name) ++ ++static inline void __vzksym_modresolve(struct module **modp, struct module *mod) ++{ ++ /* ++ * we want to be sure, that pointer updates are visible first: ++ * 1. wmb() is here only for piece of sure ++ * (note, no rmb() in KSYMSAFECALL) ++ * 2. synchronize_sched() guarantees that updates are visible ++ * on all cpus and allows us to remove rmb() in KSYMSAFECALL ++ */ ++ wmb(); synchronize_sched(); ++ *modp = mod; ++ /* just to be sure, our changes are visible as soon as possible */ ++ wmb(); synchronize_sched(); ++} ++ ++static inline void __vzksym_modunresolve(struct module **modp) ++{ ++ /* ++ * try_module_get() in KSYMSAFECALL should fail at this moment since ++ * THIS_MODULE in in unloading state (we should be called from fini), ++ * no need to syncronize pointers/ve_module updates. ++ */ ++ *modp = &no_module; ++ /* ++ * synchronize_sched() guarantees here that we see ++ * updated module pointer before the module really gets away ++ */ ++ synchronize_sched(); ++} ++ ++static inline int __vzksym_module_get(struct module *mod) ++{ ++ /* ++ * we want to avoid rmb(), so use synchronize_sched() in KSYMUNRESOLVE ++ * and smp_read_barrier_depends() here... ++ */ ++ smp_read_barrier_depends(); /* for module loading */ ++ if (!try_module_get(mod)) ++ return -EBUSY; ++ ++ return 0; ++} ++ ++static inline void __vzksym_module_put(struct module *mod) ++{ ++ module_put(mod); ++} ++#else ++#define DECL_KSYM_MODULE(name) ++#define INIT_KSYM_MODULE(name) ++#define __vzksym_modresolve(modp, mod) ++#define __vzksym_modunresolve(modp) ++#define __vzksym_module_get(mod) 0 ++#define __vzksym_module_put(mod) ++#endif ++ ++#define __KSYMERRCALL(err, type, mod, name, args) \ ++({ \ ++ type ret = (type)err; \ ++ if (!__vzksym_module_get(vz_mod_##mod)) { \ ++ if (vz_##name) \ ++ ret = ((*vz_##name)args); \ ++ __vzksym_module_put(vz_mod_##mod); \ ++ } \ ++ ret; \ ++}) ++ ++#define __KSYMSAFECALL_VOID(mod, name, args) \ ++ do { \ ++ if (!__vzksym_module_get(vz_mod_##mod)) { \ ++ if (vz_##name) \ ++ ((*vz_##name)args); \ ++ __vzksym_module_put(vz_mod_##mod); \ ++ } \ ++ } while (0) ++ ++#define DECL_KSYM_CALL(type, name, args) \ ++ extern type (*vz_##name) args ++#define INIT_KSYM_CALL(type, name, args) \ ++ type (*vz_##name) args; \ ++EXPORT_SYMBOL(vz_##name) ++ ++#define KSYMERRCALL(err, mod, name, args) \ ++ __KSYMERRCALL(err, int, mod, name, args) ++#define KSYMSAFECALL(type, mod, name, args) \ ++ __KSYMERRCALL(0, type, mod, name, args) ++#define KSYMSAFECALL_VOID(mod, name, args) \ ++ __KSYMSAFECALL_VOID(mod, name, args) ++#define KSYMREF(name) vz_##name ++ ++/* should be called _after_ KSYMRESOLVE's */ ++#define KSYMMODRESOLVE(name) \ ++ __vzksym_modresolve(&vz_mod_##name, THIS_MODULE) ++#define KSYMMODUNRESOLVE(name) \ ++ __vzksym_modunresolve(&vz_mod_##name) ++ ++#define KSYMRESOLVE(name) \ ++ vz_##name = &name ++#define KSYMUNRESOLVE(name) \ ++ vz_##name = NULL ++ ++#if defined(CONFIG_VE) ++DECL_KSYM_MODULE(ip_tables); ++DECL_KSYM_MODULE(ip6_tables); ++DECL_KSYM_MODULE(iptable_filter); ++DECL_KSYM_MODULE(ip6table_filter); ++DECL_KSYM_MODULE(iptable_mangle); ++DECL_KSYM_MODULE(ip6table_mangle); ++DECL_KSYM_MODULE(ip_conntrack); ++DECL_KSYM_MODULE(nf_conntrack); ++DECL_KSYM_MODULE(nf_conntrack_ipv4); ++DECL_KSYM_MODULE(nf_conntrack_ipv6); ++DECL_KSYM_MODULE(xt_conntrack); ++DECL_KSYM_MODULE(ip_nat); ++DECL_KSYM_MODULE(nf_nat); ++DECL_KSYM_MODULE(iptable_nat); ++ ++struct sk_buff; ++ ++DECL_KSYM_CALL(int, init_netfilter, (void)); ++DECL_KSYM_CALL(int, init_iptables, (void)); ++DECL_KSYM_CALL(int, init_ip6tables, (void)); ++DECL_KSYM_CALL(int, init_iptable_filter, (void)); ++DECL_KSYM_CALL(int, init_ip6table_filter, (void)); ++DECL_KSYM_CALL(int, init_iptable_mangle, (void)); ++DECL_KSYM_CALL(int, init_ip6table_mangle, (void)); ++DECL_KSYM_CALL(int, init_iptable_conntrack, (void)); ++DECL_KSYM_CALL(int, nf_conntrack_init_ve, (void)); ++DECL_KSYM_CALL(int, init_nf_ct_l3proto_ipv4, (void)); ++DECL_KSYM_CALL(int, init_nf_ct_l3proto_ipv6, (void)); ++DECL_KSYM_CALL(int, nf_nat_init, (void)); ++DECL_KSYM_CALL(int, init_iptable_nat, (void)); ++DECL_KSYM_CALL(int, init_nftable_nat, (void)); ++DECL_KSYM_CALL(int, nf_nat_init, (void)); ++DECL_KSYM_CALL(void, fini_iptable_nat, (void)); ++DECL_KSYM_CALL(void, fini_nftable_nat, (void)); ++DECL_KSYM_CALL(void, nf_nat_cleanup, (void)); ++DECL_KSYM_CALL(void, fini_iptable_conntrack, (void)); ++DECL_KSYM_CALL(void, nf_conntrack_cleanup_ve, (void)); ++DECL_KSYM_CALL(void, fini_nf_ct_l3proto_ipv4, (void)); ++DECL_KSYM_CALL(void, fini_nf_ct_l3proto_ipv6, (void)); ++DECL_KSYM_CALL(void, fini_iptable_filter, (void)); ++DECL_KSYM_CALL(void, fini_ip6table_filter, (void)); ++DECL_KSYM_CALL(void, fini_iptable_mangle, (void)); ++DECL_KSYM_CALL(void, fini_ip6table_mangle, (void)); ++DECL_KSYM_CALL(void, fini_iptables, (void)); ++DECL_KSYM_CALL(void, fini_ip6tables, (void)); ++DECL_KSYM_CALL(void, fini_netfilter, (void)); ++ ++#include ++#endif ++ ++#if defined(CONFIG_VE_ETHDEV) || defined(CONFIG_VE_ETHDEV_MODULE) ++DECL_KSYM_MODULE(vzethdev); ++DECL_KSYM_CALL(int, veth_open, (struct net_device *dev)); ++#endif ++ ++#if defined(CONFIG_VE_CALLS) || defined(CONFIG_VE_CALLS_MODULE) ++DECL_KSYM_MODULE(vzmon); ++DECL_KSYM_CALL(void, real_do_env_free, (struct ve_struct *env)); ++#endif ++ ++#endif /* _LINUX_NFCALLS_H */ +Index: kernel/include/linux/nfs_fs_sb.h +=================================================================== +--- kernel.orig/include/linux/nfs_fs_sb.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/nfs_fs_sb.h 2008-11-24 15:47:46.000000000 +0100 +@@ -65,6 +65,7 @@ + char cl_ipaddr[16]; + unsigned char cl_id_uniquifier; + #endif ++ struct ve_struct *owner_env; + }; + + /* +Index: kernel/include/linux/notifier.h +=================================================================== +--- kernel.orig/include/linux/notifier.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/notifier.h 2008-11-24 15:47:46.000000000 +0100 +@@ -149,8 +149,9 @@ + + #define NOTIFY_DONE 0x0000 /* Don't care */ + #define NOTIFY_OK 0x0001 /* Suits me */ ++#define NOTIFY_FAIL 0x0002 /* Reject */ + #define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ +-#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) ++#define NOTIFY_BAD (NOTIFY_STOP_MASK|NOTIFY_FAIL) + /* Bad/Veto action */ + /* + * Clean way to return from the notifier and stop further calls. +Index: kernel/include/linux/nsproxy.h +=================================================================== +--- kernel.orig/include/linux/nsproxy.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/nsproxy.h 2008-11-24 15:47:46.000000000 +0100 +@@ -66,6 +66,7 @@ + void exit_task_namespaces(struct task_struct *tsk); + void switch_task_namespaces(struct task_struct *tsk, struct nsproxy *new); + void free_nsproxy(struct nsproxy *ns); ++struct mnt_namespace * get_task_mnt_ns(struct task_struct *tsk); + int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **, + struct fs_struct *); + +@@ -76,9 +77,10 @@ + } + } + +-static inline void get_nsproxy(struct nsproxy *ns) ++static inline struct nsproxy *get_nsproxy(struct nsproxy *ns) + { + atomic_inc(&ns->count); ++ return ns; + } + + #ifdef CONFIG_CGROUP_NS +Index: kernel/include/linux/page-flags.h +=================================================================== +--- kernel.orig/include/linux/page-flags.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/page-flags.h 2008-11-24 15:47:46.000000000 +0100 +@@ -93,6 +93,8 @@ + /* PG_readahead is only used for file reads; PG_reclaim is only for writes */ + #define PG_readahead PG_reclaim /* Reminder to do async read-ahead */ + ++#define PG_checkpointed 21 /* Page transferred */ ++ + /* PG_owner_priv_1 users should have descriptive aliases */ + #define PG_checked PG_owner_priv_1 /* Used by some filesystems */ + #define PG_pinned PG_owner_priv_1 /* Xen pinned pagetable */ +@@ -260,6 +262,8 @@ + #define SetPageUncached(page) set_bit(PG_uncached, &(page)->flags) + #define ClearPageUncached(page) clear_bit(PG_uncached, &(page)->flags) + ++#define ClearPageCheckpointed(page) clear_bit(PG_checkpointed, &(page)->flags) ++ + struct page; /* forward declaration */ + + extern void cancel_dirty_page(struct page *page, unsigned int account_size); +Index: kernel/include/linux/percpu.h +=================================================================== +--- kernel.orig/include/linux/percpu.h 2008-11-24 14:17:47.000000000 +0100 ++++ kernel/include/linux/percpu.h 2008-11-24 15:47:46.000000000 +0100 +@@ -49,6 +49,13 @@ + (__typeof__(ptr))__p->ptrs[(cpu)]; \ + }) + ++#define static_percpu_ptr(sptr, sptrs) ({ \ ++ int i; \ ++ for (i = 0; i < NR_CPUS; i++) \ ++ (sptr)->ptrs[i] = &(sptrs)[i]; \ ++ (void *)__percpu_disguise(sptr); \ ++ }) ++ + extern void *percpu_populate(void *__pdata, size_t size, gfp_t gfp, int cpu); + extern void percpu_depopulate(void *__pdata, int cpu); + extern int __percpu_populate_mask(void *__pdata, size_t size, gfp_t gfp, +@@ -60,6 +67,7 @@ + #else /* CONFIG_SMP */ + + #define percpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); }) ++#define static_percpu_ptr(sptr, sptrs) (&sptrs[0]) + + static inline void percpu_depopulate(void *__pdata, int cpu) + { +Index: kernel/include/linux/pid.h +=================================================================== +--- kernel.orig/include/linux/pid.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/pid.h 2008-11-24 15:47:46.000000000 +0100 +@@ -59,6 +59,9 @@ + atomic_t count; + /* lists of tasks that use this pid */ + struct hlist_head tasks[PIDTYPE_MAX]; ++#ifdef CONFIG_BEANCOUNTERS ++ struct user_beancounter *ub; ++#endif + struct rcu_head rcu; + int level; + struct upid numbers[1]; +@@ -119,9 +122,12 @@ + extern struct pid *find_get_pid(int nr); + extern struct pid *find_ge_pid(int nr, struct pid_namespace *); + +-extern struct pid *alloc_pid(struct pid_namespace *ns); ++extern struct pid *alloc_pid(struct pid_namespace *ns, pid_t vpid); + extern void FASTCALL(free_pid(struct pid *pid)); ++extern int pid_ns_attach_init(struct pid_namespace *, struct task_struct *); ++extern int pid_ns_attach_task(struct pid_namespace *, struct task_struct *); + extern void zap_pid_ns_processes(struct pid_namespace *pid_ns); ++pid_t pid_to_vpid(pid_t nr); + + /* + * the helpers to get the pid's id seen from different namespaces +Index: kernel/include/linux/poll.h +=================================================================== +--- kernel.orig/include/linux/poll.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/poll.h 2008-11-24 15:47:46.000000000 +0100 +@@ -117,6 +117,7 @@ + extern int do_select(int n, fd_set_bits *fds, s64 *timeout); + extern int do_sys_poll(struct pollfd __user * ufds, unsigned int nfds, + s64 *timeout); ++long do_restart_poll(struct restart_block *restart_block); + + #endif /* KERNEL */ + +Index: kernel/include/linux/proc_fs.h +=================================================================== +--- kernel.orig/include/linux/proc_fs.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/proc_fs.h 2008-11-24 15:47:46.000000000 +0100 +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + #include + + struct net; +@@ -100,6 +101,8 @@ + + extern struct proc_dir_entry proc_root; + extern struct proc_dir_entry *proc_root_fs; ++extern struct file_system_type proc_fs_type; ++ + extern struct proc_dir_entry *proc_bus; + extern struct proc_dir_entry *proc_root_driver; + extern struct proc_dir_entry *proc_root_kcore; +@@ -124,7 +127,17 @@ + + extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, + struct proc_dir_entry *parent); ++extern struct proc_dir_entry *create_proc_glob_entry(const char *name, ++ mode_t mode, ++ struct proc_dir_entry *parent); + extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent); ++extern void remove_proc_glob_entry(const char *name, struct proc_dir_entry *parent); ++ ++#ifdef CONFIG_VE ++#define proc_mnt(ve) (ve->proc_mnt) ++#else ++#define proc_mnt(ve) (proc_mnt) ++#endif + + extern struct vfsmount *proc_mnt; + struct pid_namespace; +@@ -202,12 +215,22 @@ + const char *name, mode_t mode, const struct file_operations *fops); + extern void proc_net_remove(struct net *net, const char *name); + ++static inline struct proc_dir_entry *proc_glob_fops_create(const char *name, ++ mode_t mode, const struct file_operations *fops) ++{ ++ struct proc_dir_entry *res = create_proc_glob_entry(name, mode, NULL); ++ if (res) ++ res->proc_fops = fops; ++ return res; ++} ++ + #else + + #define proc_root_driver NULL + #define proc_bus NULL + + #define proc_net_fops_create(net, name, mode, fops) ({ (void)(mode), NULL; }) ++#define proc_glob_fops_create(name, mode, fops) ({ (void)(mode), NULL; }) + static inline void proc_net_remove(struct net *net, const char *name) {} + + static inline void proc_flush_task(struct task_struct *task) +@@ -216,6 +239,8 @@ + + static inline struct proc_dir_entry *create_proc_entry(const char *name, + mode_t mode, struct proc_dir_entry *parent) { return NULL; } ++static inline struct proc_dir_entry *create_proc_glob_entry(const char *name, ++ mode_t mode, struct proc_dir_entry *parent) { return NULL; } + + #define remove_proc_entry(name, parent) do {} while (0) + +@@ -248,6 +273,48 @@ + + #endif /* CONFIG_PROC_FS */ + ++static inline struct proc_dir_entry *create_proc_entry_mod(const char *name, ++ mode_t mode, ++ struct proc_dir_entry *parent, ++ struct module *owner) ++{ ++ struct proc_dir_entry *ent; ++ ++ /* ++ * lock_kernel() here protects against proc_lookup() ++ * which can find this freshly created entry w/o owner being set. ++ * this can lead to module being put more times then getted. ++ */ ++ lock_kernel(); ++ ent = create_proc_entry(name, mode, parent); ++ if (ent) ++ ent->owner = owner; ++ unlock_kernel(); ++ ++ return ent; ++} ++ ++static inline struct proc_dir_entry *create_proc_glob_entry_mod(const char *name, ++ mode_t mode, ++ struct proc_dir_entry *parent, ++ struct module *owner) ++{ ++ struct proc_dir_entry *ent; ++ ++ /* ++ * lock_kernel() here protects against proc_lookup() ++ * which can find this freshly created entry w/o owner being set. ++ * this can lead to module being put more times then getted. ++ */ ++ lock_kernel(); ++ ent = create_proc_glob_entry(name, mode, parent); ++ if (ent) ++ ent->owner = owner; ++ unlock_kernel(); ++ ++ return ent; ++} ++ + #if !defined(CONFIG_PROC_KCORE) + static inline void kclist_add(struct kcore_list *new, void *addr, size_t size) + { +@@ -294,4 +361,11 @@ + #endif + }; + ++#define LPDE(inode) (PROC_I((inode))->pde) ++#ifdef CONFIG_VE ++#define GPDE(inode) (*(struct proc_dir_entry **)(&(inode)->i_pipe)) ++#endif ++ ++int proc_match(int len, const char *name, struct proc_dir_entry *de); ++ + #endif /* _LINUX_PROC_FS_H */ +Index: kernel/include/linux/quota.h +=================================================================== +--- kernel.orig/include/linux/quota.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/quota.h 2008-11-24 15:47:46.000000000 +0100 +@@ -164,6 +164,10 @@ + #include + #include + ++#include ++ ++extern spinlock_t dq_data_lock; ++ + #include + #include + #include +@@ -274,6 +278,8 @@ + int (*release_dqblk)(struct dquot *dquot); /* Called when last reference to dquot is being dropped */ + }; + ++struct inode; ++struct iattr; + /* Operations working with dquots */ + struct dquot_operations { + int (*initialize) (struct inode *, int); +@@ -288,9 +294,11 @@ + int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */ + int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */ + int (*write_info) (struct super_block *, int); /* Write of quota "superblock" */ ++ int (*rename) (struct inode *, struct inode *, struct inode *); + }; + + /* Operations handling requests from userspace */ ++struct v2_disk_dqblk; + struct quotactl_ops { + int (*quota_on)(struct super_block *, int, int, char *); + int (*quota_off)(struct super_block *, int); +@@ -303,6 +311,10 @@ + int (*set_xstate)(struct super_block *, unsigned int, int); + int (*get_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *); + int (*set_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *); ++#ifdef CONFIG_QUOTA_COMPAT ++ int (*get_quoti)(struct super_block *, int, unsigned int, ++ struct v2_disk_dqblk __user *); ++#endif + }; + + struct quota_format_type { +@@ -323,6 +335,10 @@ + struct inode *files[MAXQUOTAS]; /* inodes of quotafiles */ + struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ + struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ ++#if defined(CONFIG_VZ_QUOTA) || defined(CONFIG_VZ_QUOTA_MODULE) ++ struct vz_quota_master *vzdq_master; ++ int vzdq_count; ++#endif + }; + + /* Inline would be better but we need to dereference super_block which is not defined yet */ +Index: kernel/include/linux/quotaops.h +=================================================================== +--- kernel.orig/include/linux/quotaops.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/quotaops.h 2008-11-24 15:47:46.000000000 +0100 +@@ -170,6 +170,19 @@ + return 0; + } + ++static __inline__ int DQUOT_RENAME(struct inode *inode, ++ struct inode *old_dir, struct inode *new_dir) ++{ ++ struct dquot_operations *q_op; ++ ++ q_op = inode->i_sb->dq_op; ++ if (q_op && q_op->rename) { ++ if (q_op->rename(inode, old_dir, new_dir) == NO_QUOTA) ++ return 1; ++ } ++ return 0; ++} ++ + /* The following two functions cannot be called inside a transaction */ + #define DQUOT_SYNC(sb) sync_dquots(sb, -1) + +@@ -196,6 +209,7 @@ + #define DQUOT_SYNC(sb) do { } while(0) + #define DQUOT_OFF(sb) do { } while(0) + #define DQUOT_TRANSFER(inode, iattr) (0) ++#define DQUOT_RENAME(inode, old_dir, new_dir) (0) + static inline int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) + { + inode_add_bytes(inode, nr); +Index: kernel/include/linux/rmap.h +=================================================================== +--- kernel.orig/include/linux/rmap.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/rmap.h 2008-11-24 15:47:46.000000000 +0100 +@@ -73,6 +73,8 @@ + void page_add_new_anon_rmap(struct page *, struct vm_area_struct *, unsigned long); + void page_add_file_rmap(struct page *); + void page_remove_rmap(struct page *, struct vm_area_struct *); ++struct anon_vma *page_lock_anon_vma(struct page *page); ++void page_unlock_anon_vma(struct anon_vma *anon_vma); + + #ifdef CONFIG_DEBUG_VM + void page_dup_rmap(struct page *page, struct vm_area_struct *vma, unsigned long address); +Index: kernel/include/linux/sched.h +=================================================================== +--- kernel.orig/include/linux/sched.h 2008-11-24 14:17:45.000000000 +0100 ++++ kernel/include/linux/sched.h 2008-11-24 15:47:46.000000000 +0100 +@@ -28,6 +28,9 @@ + #define CLONE_NEWPID 0x20000000 /* New pid namespace */ + #define CLONE_NEWNET 0x40000000 /* New network namespace */ + ++/* mask of clones which are disabled in OpenVZ VEs */ ++#define CLONE_NAMESPACES_MASK (CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET) ++ + /* + * Scheduling policies + */ +@@ -92,6 +95,8 @@ + + #include + ++#include ++ + struct exec_domain; + struct futex_pi_state; + struct bio; +@@ -126,15 +131,38 @@ + load += n*(FIXED_1-exp); \ + load >>= FSHIFT; + ++#define LOAD_INT(x) ((x) >> FSHIFT) ++#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) ++ + extern unsigned long total_forks; + extern int nr_threads; + DECLARE_PER_CPU(unsigned long, process_counts); + extern int nr_processes(void); + extern unsigned long nr_running(void); ++extern unsigned long nr_sleeping(void); ++extern unsigned long nr_stopped(void); + extern unsigned long nr_uninterruptible(void); + extern unsigned long nr_active(void); + extern unsigned long nr_iowait(void); + extern unsigned long weighted_cpuload(const int cpu); ++extern atomic_t nr_dead; ++extern unsigned long nr_zombie; ++ ++#ifdef CONFIG_VE ++struct ve_struct; ++extern unsigned long nr_running_ve(struct ve_struct *); ++extern unsigned long nr_iowait_ve(struct ve_struct *); ++extern unsigned long nr_uninterruptible_ve(struct ve_struct *); ++extern cycles_t ve_sched_get_idle_time(struct ve_struct *ve, int cpu); ++extern cycles_t ve_sched_get_iowait_time(struct ve_struct *ve, int cpu); ++void ve_sched_attach(struct ve_struct *envid); ++#else ++#define nr_running_ve(ve) 0 ++#define nr_iowait_ve(ve) 0 ++#define nr_uninterruptible_ve(ve) 0 ++#define ve_sched_get_idle_time(ve, cpu) 0 ++#define ve_sched_get_iowait_time(ve, cpu) 0 ++#endif + + struct seq_file; + struct cfs_rq; +@@ -242,6 +270,7 @@ + } + + extern void show_regs(struct pt_regs *); ++extern void smp_show_regs(struct pt_regs *, void *); + + /* + * TASK is a pointer to the task whose backtrace we want to see (or NULL for current +@@ -389,6 +418,9 @@ + unsigned long ac_minflt, ac_majflt; + }; + ++#include ++#include ++ + /* + * NOTE! "signal_struct" does not have it's own + * locking, because a shared signal_struct always +@@ -985,6 +1017,7 @@ + /* ??? */ + unsigned int personality; + unsigned did_exec:1; ++ unsigned did_ve_enter:1; + pid_t pid; + pid_t tgid; + +@@ -1173,6 +1206,14 @@ + struct rcu_head rcu; + + /* ++ * state tracking for suspend ++ * FIXME - ptrace is completely rewritten in this kernel ++ * so set_pn_state() is not set in many places correctyl ++ */ ++ __u8 pn_state; ++ __u8 stopped_state:1; ++ ++ /* + * cache last used pipe for splice + */ + struct pipe_inode_info *splice_pipe; +@@ -1188,6 +1229,16 @@ + struct latency_record latency_record[LT_SAVECOUNT]; + #endif + struct list_head *scm_work_list; ++#ifdef CONFIG_BEANCOUNTERS ++ struct task_beancounter task_bc; ++#endif ++#ifdef CONFIG_VE ++ struct ve_task_info ve_task_info; ++#endif ++#if defined(CONFIG_VZ_QUOTA) || defined(CONFIG_VZ_QUOTA_MODULE) ++ unsigned long magic; ++ struct inode *ino; ++#endif + }; + + /* +@@ -1363,6 +1414,43 @@ + __put_task_struct(t); + } + ++#ifndef CONFIG_VE ++#define set_pn_state(tsk, state) do { } while(0) ++#define clear_pn_state(tsk) do { } while(0) ++#define set_stop_state(tsk) do { } while(0) ++#define clear_stop_state(tsk) do { } while(0) ++#else ++#define PN_STOP_TF 1 /* was not in 2.6.8 */ ++#define PN_STOP_TF_RT 2 /* was not in 2.6.8 */ ++#define PN_STOP_ENTRY 3 ++#define PN_STOP_FORK 4 ++#define PN_STOP_VFORK 5 ++#define PN_STOP_SIGNAL 6 ++#define PN_STOP_EXIT 7 ++#define PN_STOP_EXEC 8 ++#define PN_STOP_LEAVE 9 ++ ++static inline void set_pn_state(struct task_struct *tsk, int state) ++{ ++ tsk->pn_state = state; ++} ++ ++static inline void clear_pn_state(struct task_struct *tsk) ++{ ++ tsk->pn_state = 0; ++} ++ ++static inline void set_stop_state(struct task_struct *tsk) ++{ ++ tsk->stopped_state = 1; ++} ++ ++static inline void clear_stop_state(struct task_struct *tsk) ++{ ++ tsk->stopped_state = 0; ++} ++#endif ++ + /* + * Per process flags + */ +@@ -1379,6 +1467,7 @@ + #define PF_MEMALLOC 0x00000800 /* Allocating memory */ + #define PF_FLUSHER 0x00001000 /* responsible for disk writeback */ + #define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */ ++#define PF_EXIT_RESTART 0x00004000 /* do_exit() restarted, see do_exit() */ + #define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */ + #define PF_FROZEN 0x00010000 /* frozen for system suspend */ + #define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */ +@@ -1441,6 +1530,21 @@ + extern unsigned long long + task_sched_runtime(struct task_struct *task); + ++static inline unsigned long cycles_to_clocks(cycles_t cycles) ++{ ++ extern unsigned long cycles_per_clock; ++ do_div(cycles, cycles_per_clock); ++ return cycles; ++} ++ ++static inline u64 cycles_to_jiffies(cycles_t cycles) ++{ ++ extern unsigned long cycles_per_jiffy; ++ do_div(cycles, cycles_per_jiffy); ++ return cycles; ++} ++ ++ + /* sched_exec is called by processes performing an exec */ + #ifdef CONFIG_SMP + extern void sched_exec(void); +@@ -1570,6 +1674,9 @@ + extern void free_uid(struct user_struct *); + extern void switch_uid(struct user_struct *); + extern void release_uids(struct user_namespace *ns); ++extern int set_user(uid_t uid, int dumpclear); ++extern void set_special_pids(pid_t session, pid_t pgrp); ++extern void __set_special_pids(pid_t session, pid_t pgrp); + + #include + +@@ -1701,6 +1808,13 @@ + + extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *); + extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *); ++extern long do_fork_pid(unsigned long clone_flags, ++ unsigned long stack_start, ++ struct pt_regs *regs, ++ unsigned long stack_size, ++ int __user *parent_tidptr, ++ int __user *child_tidptr, ++ long pid0); + struct task_struct *fork_idle(int); + + extern void set_task_comm(struct task_struct *tsk, char *from); +@@ -1715,19 +1829,19 @@ + #define remove_parent(p) list_del_init(&(p)->sibling) + #define add_parent(p) list_add_tail(&(p)->sibling,&(p)->parent->children) + +-#define next_task(p) list_entry(rcu_dereference((p)->tasks.next), struct task_struct, tasks) ++#define next_task_all(p) list_entry(rcu_dereference((p)->tasks.next), struct task_struct, tasks) + +-#define for_each_process(p) \ +- for (p = &init_task ; (p = next_task(p)) != &init_task ; ) ++#define for_each_process_all(p) \ ++ for (p = &init_task ; (p = next_task_all(p)) != &init_task ; ) + + /* + * Careful: do_each_thread/while_each_thread is a double loop so + * 'break' will not work as expected - use goto instead. + */ +-#define do_each_thread(g, t) \ +- for (g = t = &init_task ; (g = t = next_task(g)) != &init_task ; ) do ++#define do_each_thread_all(g, t) \ ++ for (g = t = &init_task ; (g = t = next_task_all(g)) != &init_task ; ) do + +-#define while_each_thread(g, t) \ ++#define while_each_thread_all(g, t) \ + while ((t = next_thread(t)) != g) + + /* de_thread depends on thread_group_leader not being a pid based check */ +@@ -1752,8 +1866,15 @@ + + static inline struct task_struct *next_thread(const struct task_struct *p) + { +- return list_entry(rcu_dereference(p->thread_group.next), ++ struct task_struct *tsk; ++ ++ tsk = list_entry(rcu_dereference(p->thread_group.next), + struct task_struct, thread_group); ++#ifdef CONFIG_VE ++ /* all threads should belong to ONE ve! */ ++ BUG_ON(VE_TASK_INFO(tsk)->owner_env != VE_TASK_INFO(p)->owner_env); ++#endif ++ return tsk; + } + + static inline int thread_group_empty(struct task_struct *p) +@@ -1793,6 +1914,98 @@ + spin_unlock_irqrestore(&tsk->sighand->siglock, *flags); + } + ++#ifndef CONFIG_VE ++ ++#define for_each_process_ve(p) for_each_process_all(p) ++#define do_each_thread_ve(g, t) do_each_thread_all(g, t) ++#define while_each_thread_ve(g, t) while_each_thread_all(g, t) ++#define first_task_ve() next_task_ve(&init_task) ++#define __first_task_ve(owner) next_task_ve(&init_task) ++#define __next_task_ve(owner, p) next_task_ve(p) ++#define next_task_ve(p) \ ++ (next_task_all(p) != &init_task ? next_task_all(p) : NULL) ++ ++#define ve_is_super(env) 1 ++#define ve_accessible(target, owner) 1 ++#define ve_accessible_strict(target, owner) 1 ++#define ve_accessible_veid(target, owner) 1 ++#define ve_accessible_strict_veid(target, owner) 1 ++ ++#define VEID(ve) 0 ++ ++#else /* CONFIG_VE */ ++ ++#include ++ ++#define ve_is_super(env) ((env) == get_ve0()) ++ ++#define ve_accessible_strict(target, owner) ((target) == (owner)) ++static inline int ve_accessible(struct ve_struct *target, ++ struct ve_struct *owner) ++{ ++ return ve_is_super(owner) || ve_accessible_strict(target, owner); ++} ++ ++#define ve_accessible_strict_veid(target, owner) ((target) == (owner)) ++static inline int ve_accessible_veid(envid_t target, envid_t owner) ++{ ++ return get_ve0()->veid == owner || ++ ve_accessible_strict_veid(target, owner); ++} ++ ++#define VEID(ve) (ve->veid) ++ ++static inline struct task_struct *ve_lh2task(struct ve_struct *ve, ++ struct list_head *lh) ++{ ++ return lh == &ve->vetask_lh ? NULL : ++ list_entry(lh, struct task_struct, ve_task_info.vetask_list); ++} ++ ++static inline struct task_struct *__first_task_ve(struct ve_struct *ve) ++{ ++ struct task_struct *tsk; ++ ++ if (unlikely(ve_is_super(ve))) { ++ tsk = next_task_all(&init_task); ++ if (tsk == &init_task) ++ tsk = NULL; ++ } else { ++ tsk = ve_lh2task(ve, rcu_dereference(ve->vetask_lh.next)); ++ } ++ return tsk; ++} ++ ++static inline struct task_struct *__next_task_ve(struct ve_struct *ve, ++ struct task_struct *tsk) ++{ ++ if (unlikely(ve_is_super(ve))) { ++ tsk = next_task_all(tsk); ++ if (tsk == &init_task) ++ tsk = NULL; ++ } else { ++ BUG_ON(tsk->ve_task_info.owner_env != ve); ++ tsk = ve_lh2task(ve, rcu_dereference(tsk-> ++ ve_task_info.vetask_list.next)); ++ } ++ return tsk; ++} ++ ++#define first_task_ve() __first_task_ve(get_exec_env()) ++#define next_task_ve(p) __next_task_ve(get_exec_env(), p) ++/* no one uses prev_task_ve(), copy next_task_ve() if needed */ ++ ++#define for_each_process_ve(p) \ ++ for (p = first_task_ve(); p != NULL ; p = next_task_ve(p)) ++ ++#define do_each_thread_ve(g, t) \ ++ for (g = t = first_task_ve() ; g != NULL; g = t = next_task_ve(g)) do ++ ++#define while_each_thread_ve(g, t) \ ++ while ((t = next_thread(t)) != g) ++ ++#endif /* CONFIG_VE */ ++ + #ifndef __HAVE_THREAD_FUNCTIONS + + #define task_thread_info(task) ((struct thread_info *)(task)->stack) +Index: kernel/include/linux/security.h +=================================================================== +--- kernel.orig/include/linux/security.h 2008-11-24 14:18:05.000000000 +0100 ++++ kernel/include/linux/security.h 2008-11-24 15:47:46.000000000 +0100 +@@ -34,11 +34,6 @@ + #include + #include + +-/* +- * Bounding set +- */ +-extern kernel_cap_t cap_bset; +- + extern unsigned securebits; + + struct ctl_table; +Index: kernel/include/linux/sem.h +=================================================================== +--- kernel.orig/include/linux/sem.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/sem.h 2008-11-24 15:47:46.000000000 +0100 +@@ -154,6 +154,9 @@ + } + #endif + ++int sysvipc_walk_sem(int (*func)(int, struct sem_array*, void *), void *arg); ++int sysvipc_setup_sem(key_t key, int semid, size_t size, int semflg); ++ + #endif /* __KERNEL__ */ + + #endif /* _LINUX_SEM_H */ +Index: kernel/include/linux/shm.h +=================================================================== +--- kernel.orig/include/linux/shm.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/shm.h 2008-11-24 15:47:46.000000000 +0100 +@@ -110,6 +110,9 @@ + } + #endif + ++int sysvipc_walk_shm(int (*func)(struct shmid_kernel*, void *), void *arg); ++struct file * sysvipc_setup_shm(key_t key, int shmid, size_t size, int shmflg); ++ + #endif /* __KERNEL__ */ + + #endif /* _LINUX_SHM_H_ */ +Index: kernel/include/linux/shmem_fs.h +=================================================================== +--- kernel.orig/include/linux/shmem_fs.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/shmem_fs.h 2008-11-24 15:47:46.000000000 +0100 +@@ -23,6 +23,9 @@ + struct posix_acl *i_acl; + struct posix_acl *i_default_acl; + #endif ++#ifdef CONFIG_BEANCOUNTERS ++ struct user_beancounter *shmi_ub; ++#endif + }; + + struct shmem_sb_info { +@@ -60,4 +63,6 @@ + } + #endif /* CONFIG_TMPFS_POSIX_ACL */ + ++extern struct file_system_type tmpfs_fs_type; ++ + #endif +Index: kernel/include/linux/signal.h +=================================================================== +--- kernel.orig/include/linux/signal.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/signal.h 2008-11-24 15:47:46.000000000 +0100 +@@ -6,6 +6,8 @@ + + #ifdef __KERNEL__ + #include ++#include ++#include + + /* + * Real Time signals may be queued. +@@ -16,6 +18,9 @@ + int flags; + siginfo_t info; + struct user_struct *user; ++#ifdef CONFIG_BEANCOUNTERS ++ struct user_beancounter *sig_ub; ++#endif + }; + + /* flags values. */ +@@ -371,6 +376,8 @@ + (!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \ + (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL) + ++extern struct kmem_cache *sigqueue_cachep; ++ + #endif /* __KERNEL__ */ + + #endif /* _LINUX_SIGNAL_H */ +Index: kernel/include/linux/skbuff.h +=================================================================== +--- kernel.orig/include/linux/skbuff.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/skbuff.h 2008-11-24 15:47:46.000000000 +0100 +@@ -247,6 +247,8 @@ + * @secmark: security marking + */ + ++#include ++ + struct sk_buff { + /* These two members must be first. */ + struct sk_buff *next; +@@ -289,7 +291,13 @@ + ipvs_property:1, + nf_trace:1; + __be16 protocol; +- ++#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE) ++ __u8 brmark; ++#endif ++#ifdef CONFIG_VE ++ unsigned int accounted:1; ++ unsigned int redirected:1; ++#endif + void (*destructor)(struct sk_buff *skb); + #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) + struct nf_conntrack *nfct; +@@ -330,6 +338,8 @@ + *data; + unsigned int truesize; + atomic_t users; ++ struct skb_beancounter skb_bc; ++ struct ve_struct *owner_env; + }; + + #ifdef __KERNEL__ +@@ -337,6 +347,7 @@ + * Handling routines are only of interest to the kernel + */ + #include ++#include + + #include + +@@ -1258,6 +1269,8 @@ + */ + static inline void skb_orphan(struct sk_buff *skb) + { ++ ub_skb_uncharge(skb); ++ + if (skb->destructor) + skb->destructor(skb); + skb->destructor = NULL; +@@ -1764,6 +1777,26 @@ + { } + #endif + ++#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE) ++static inline void skb_copy_brmark(struct sk_buff *to, const struct sk_buff *from) ++{ ++ to->brmark = from->brmark; ++} ++ ++static inline void skb_init_brmark(struct sk_buff *skb) ++{ ++ skb->brmark = 0; ++} ++#else ++static inline void skb_copy_brmark(struct sk_buff *to, const struct sk_buff *from) ++{ ++} ++ ++static inline void skb_init_brmark(struct sk_buff *skb) ++{ ++} ++#endif ++ + static inline void skb_set_queue_mapping(struct sk_buff *skb, u16 queue_mapping) + { + #ifdef CONFIG_NETDEVICES_MULTIQUEUE +Index: kernel/include/linux/slab.h +=================================================================== +--- kernel.orig/include/linux/slab.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/slab.h 2008-11-24 15:47:46.000000000 +0100 +@@ -46,6 +46,26 @@ + (unsigned long)ZERO_SIZE_PTR) + + /* ++ * allocation rules: __GFP_UBC 0 ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * cache (SLAB_UBC) charge charge ++ * (usual caches: mm, vma, task_struct, ...) ++ * ++ * cache (SLAB_UBC | SLAB_NO_CHARGE) charge --- ++ * (ub_kmalloc) (kmalloc) ++ * ++ * cache (no UB flags) BUG() --- ++ * (nonub caches, mempools) ++ * ++ * pages charge --- ++ * (ub_vmalloc, (vmalloc, ++ * poll, fdsets, ...) non-ub allocs) ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ */ ++#define SLAB_UBC 0x20000000UL /* alloc space for ubs ... */ ++#define SLAB_NO_CHARGE 0x40000000UL /* ... but don't charge */ ++ ++/* + * struct kmem_cache related prototypes + */ + void __init kmem_cache_init(void); +@@ -60,7 +80,20 @@ + unsigned int kmem_cache_size(struct kmem_cache *); + const char *kmem_cache_name(struct kmem_cache *); + int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr); +- ++extern void show_slab_info(void); ++int kmem_cache_objuse(struct kmem_cache *cachep); ++int kmem_obj_objuse(void *obj); ++int kmem_cache_walk_objects(struct kmem_cache *cachep, int (*fun)(void *obj)); ++unsigned long ub_cache_growth(struct kmem_cache *cachep); ++ ++#ifdef CONFIG_BEANCOUNTERS ++void kmem_mark_nocharge(struct kmem_cache *cachep); ++struct user_beancounter **ub_slab_ptr(struct kmem_cache *cachep, void *obj); ++struct user_beancounter *slab_ub(void *obj); ++#else ++static inline void kmem_mark_nocharge(struct kmem_cache *cachep) { } ++static inline struct user_beancounter *slab_ub(void *obj) { return NULL; } ++#endif + /* + * Please use this macro to create slab caches. Simply specify the + * name of the structure and maybe some flags that are listed above. +Index: kernel/include/linux/slab_def.h +=================================================================== +--- kernel.orig/include/linux/slab_def.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/slab_def.h 2008-11-24 15:47:46.000000000 +0100 +@@ -15,6 +15,111 @@ + #include /* kmalloc_sizes.h needs L1_CACHE_BYTES */ + #include + ++/* ++ * DEBUG - 1 for kmem_cache_create() to honour; SLAB_RED_ZONE & SLAB_POISON. ++ * 0 for faster, smaller code (especially in the critical paths). ++ * ++ * STATS - 1 to collect stats for /proc/slabinfo. ++ * 0 for faster, smaller code (especially in the critical paths). ++ * ++ * FORCED_DEBUG - 1 enables SLAB_RED_ZONE and SLAB_POISON (if possible) ++ */ ++ ++#ifdef CONFIG_DEBUG_SLAB ++#define SLAB_DEBUG 1 ++#define SLAB_STATS 1 ++#define SLAB_FORCED_DEBUG 1 ++#else ++#define SLAB_DEBUG 0 ++#define SLAB_STATS 0 ++#define SLAB_FORCED_DEBUG 0 ++#endif ++ ++/* ++ * struct kmem_cache ++ * ++ * manages a cache. ++ */ ++ ++struct kmem_cache { ++/* 1) per-cpu data, touched during every alloc/free */ ++ struct array_cache *array[NR_CPUS]; ++/* 2) Cache tunables. Protected by cache_chain_mutex */ ++ unsigned int batchcount; ++ unsigned int limit; ++ unsigned int shared; ++ ++ unsigned int buffer_size; ++ u32 reciprocal_buffer_size; ++/* 3) touched by every alloc & free from the backend */ ++ ++ unsigned int flags; /* constant flags */ ++ unsigned int num; /* # of objs per slab */ ++ ++/* 4) cache_grow/shrink */ ++ /* order of pgs per slab (2^n) */ ++ unsigned int gfporder; ++ ++ /* force GFP flags, e.g. GFP_DMA */ ++ gfp_t gfpflags; ++ ++ size_t colour; /* cache colouring range */ ++ unsigned int colour_off; /* colour offset */ ++ struct kmem_cache *slabp_cache; ++ unsigned int slab_size; ++ unsigned int dflags; /* dynamic flags */ ++ ++ /* constructor func */ ++ void (*ctor) (struct kmem_cache *, void *); ++ ++/* 5) cache creation/removal */ ++ const char *name; ++ struct list_head next; ++ ++/* 6) statistics */ ++ unsigned long grown; ++ unsigned long reaped; ++ unsigned long shrunk; ++#if SLAB_STATS ++ unsigned long num_active; ++ unsigned long num_allocations; ++ unsigned long high_mark; ++ unsigned long errors; ++ unsigned long max_freeable; ++ unsigned long node_allocs; ++ unsigned long node_frees; ++ unsigned long node_overflow; ++ atomic_t allochit; ++ atomic_t allocmiss; ++ atomic_t freehit; ++ atomic_t freemiss; ++#endif ++#if SLAB_DEBUG ++ /* ++ * If debugging is enabled, then the allocator can add additional ++ * fields and/or padding to every object. buffer_size contains the total ++ * object size including these internal fields, the following two ++ * variables contain the offset to the user object and its size. ++ */ ++ int obj_offset; ++ int obj_size; ++#endif ++#ifdef CONFIG_BEANCOUNTERS ++ int objuse; ++#endif ++ /* ++ * We put nodelists[] at the end of kmem_cache, because we want to size ++ * this array to nr_node_ids slots instead of MAX_NUMNODES ++ * (see kmem_cache_init()) ++ * We still use [MAX_NUMNODES] and not [1] or [0] because cache_cache ++ * is statically defined, so we reserve the max number of nodes. ++ */ ++ struct kmem_list3 *nodelists[MAX_NUMNODES]; ++ /* ++ * Do not add fields after nodelists[] ++ */ ++}; ++ + /* Size description struct for general caches. */ + struct cache_sizes { + size_t cs_size; +@@ -24,6 +129,7 @@ + #endif + }; + extern struct cache_sizes malloc_sizes[]; ++extern int malloc_cache_num; + + void *kmem_cache_alloc(struct kmem_cache *, gfp_t); + void *__kmalloc(size_t size, gfp_t flags); +@@ -48,6 +154,8 @@ + __you_cannot_kmalloc_that_much(); + } + found: ++ if (flags & __GFP_UBC) ++ i += malloc_cache_num; + #ifdef CONFIG_ZONE_DMA + if (flags & GFP_DMA) + return kmem_cache_alloc(malloc_sizes[i].cs_dmacachep, +Index: kernel/include/linux/slub_def.h +=================================================================== +--- kernel.orig/include/linux/slub_def.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/slub_def.h 2008-11-24 15:47:46.000000000 +0100 +@@ -58,6 +58,10 @@ + struct kobject kobj; /* For sysfs */ + #endif + ++#ifdef CONFIG_BEANCOUNTERS ++ atomic_t grown; ++ int objuse; ++#endif + #ifdef CONFIG_NUMA + int defrag_ratio; + struct kmem_cache_node *node[MAX_NUMNODES]; +@@ -86,6 +90,19 @@ + */ + extern struct kmem_cache kmalloc_caches[PAGE_SHIFT]; + ++#ifdef CONFIG_BEANCOUNTERS ++extern struct kmem_cache ub_kmalloc_caches[KMALLOC_SHIFT_HIGH + 1]; ++static inline struct kmem_cache *__kmalloc_cache(gfp_t f, int idx) ++{ ++ return (f & __GFP_UBC) ? &ub_kmalloc_caches[idx] : &kmalloc_caches[idx]; ++} ++#else ++static inline struct kmem_cache *__kmalloc_cache(gfp_t flags, int idx) ++{ ++ return &kmalloc_caches[idx]; ++} ++#endif ++ + /* + * Sorry that the following has to be that ugly but some versions of GCC + * have trouble with constant propagation and loops. +@@ -142,14 +159,14 @@ + * This ought to end up with a global pointer to the right cache + * in kmalloc_caches. + */ +-static __always_inline struct kmem_cache *kmalloc_slab(size_t size) ++static __always_inline struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags) + { + int index = kmalloc_index(size); + + if (index == 0) + return NULL; + +- return &kmalloc_caches[index]; ++ return __kmalloc_cache(flags, index); + } + + #ifdef CONFIG_ZONE_DMA +@@ -170,7 +187,7 @@ + get_order(size)); + + if (!(flags & SLUB_DMA)) { +- struct kmem_cache *s = kmalloc_slab(size); ++ struct kmem_cache *s = kmalloc_slab(size, flags); + + if (!s) + return ZERO_SIZE_PTR; +@@ -189,7 +206,7 @@ + { + if (__builtin_constant_p(size) && + size <= PAGE_SIZE / 2 && !(flags & SLUB_DMA)) { +- struct kmem_cache *s = kmalloc_slab(size); ++ struct kmem_cache *s = kmalloc_slab(size, flags); + + if (!s) + return ZERO_SIZE_PTR; +Index: kernel/include/linux/smp.h +=================================================================== +--- kernel.orig/include/linux/smp.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/smp.h 2008-11-24 15:47:46.000000000 +0100 +@@ -10,6 +10,9 @@ + + extern void cpu_idle(void); + ++struct pt_regs; ++typedef void (*smp_nmi_function)(struct pt_regs *regs, void *info); ++ + #ifdef CONFIG_SMP + + #include +@@ -49,6 +52,8 @@ + */ + extern void smp_cpus_done(unsigned int max_cpus); + ++extern int smp_nmi_call_function(smp_nmi_function func, void *info, int wait); ++ + /* + * Call a function on all other processors + */ +@@ -111,6 +116,12 @@ + #define smp_call_function_mask(mask, func, info, wait) \ + (up_smp_call_function(func, info)) + ++static inline int smp_nmi_call_function(smp_nmi_function func, ++ void *info, int wait) ++{ ++ return 0; ++} ++ + #endif /* !SMP */ + + /* +Index: kernel/include/linux/socket.h +=================================================================== +--- kernel.orig/include/linux/socket.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/socket.h 2008-11-24 15:47:46.000000000 +0100 +@@ -297,6 +297,16 @@ + #define IPX_TYPE 1 + + #ifdef __KERNEL__ ++ ++#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - ++ 16 for IP, 16 for IPX, ++ 24 for IPv6, ++ about 80 for AX.25 ++ must be at least one bigger than ++ the AF_UNIX size (see net/unix/af_unix.c ++ :unix_mkname()). ++ */ ++ + extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); + extern int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, + int offset, int len); +@@ -310,6 +320,8 @@ + extern int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ulen); + extern int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr); + extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); ++extern int vz_security_family_check(int family); ++extern int vz_security_protocol_check(int protocol); + + #endif + #endif /* not kernel and not glibc */ +Index: kernel/include/linux/sunrpc/clnt.h +=================================================================== +--- kernel.orig/include/linux/sunrpc/clnt.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/sunrpc/clnt.h 2008-11-24 15:47:46.000000000 +0100 +@@ -44,6 +44,7 @@ + cl_intr : 1,/* interruptible */ + cl_discrtry : 1,/* disconnect before retry */ + cl_autobind : 1;/* use getport() */ ++ unsigned int cl_broken : 1;/* no responce for too long */ + + struct rpc_rtt * cl_rtt; /* RTO estimator data */ + +@@ -55,6 +56,7 @@ + struct rpc_clnt * cl_parent; /* Points to parent of clones */ + struct rpc_rtt cl_rtt_default; + struct rpc_program * cl_program; ++ unsigned long cl_pr_time; + char cl_inline_name[32]; + }; + +Index: kernel/include/linux/sunrpc/xprt.h +=================================================================== +--- kernel.orig/include/linux/sunrpc/xprt.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/sunrpc/xprt.h 2008-11-24 15:47:46.000000000 +0100 +@@ -24,6 +24,14 @@ + #define RPC_MAX_SLOT_TABLE (128U) + + /* ++ * Grand abort timeout (stop the client if occures) ++ */ ++extern int xprt_abort_timeout; ++ ++#define RPC_MIN_ABORT_TIMEOUT 300 ++#define RPC_MAX_ABORT_TIMEOUT INT_MAX ++ ++/* + * This describes a timeout strategy + */ + struct rpc_timeout { +@@ -119,6 +127,7 @@ + struct rpc_xprt { + struct kref kref; /* Reference count */ + struct rpc_xprt_ops * ops; /* transport methods */ ++ struct ve_struct * owner_env; /* VE owner of mount */ + + struct rpc_timeout timeout; /* timeout parms */ + struct sockaddr_storage addr; /* server address */ +Index: kernel/include/linux/swap.h +=================================================================== +--- kernel.orig/include/linux/swap.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/swap.h 2008-11-24 15:47:46.000000000 +0100 +@@ -17,6 +17,7 @@ + #define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */ + #define SWAP_FLAG_PRIO_MASK 0x7fff + #define SWAP_FLAG_PRIO_SHIFT 0 ++#define SWAP_FLAG_READONLY 0x40000000 /* set if swap is read-only */ + + static inline int current_is_kswapd(void) + { +@@ -92,6 +93,7 @@ + struct sysinfo; + struct writeback_control; + struct zone; ++struct user_beancounter; + + /* + * A swap extent maps a range of a swapfile's PAGE_SIZE pages onto a range of +@@ -121,6 +123,7 @@ + SWP_ACTIVE = (SWP_USED | SWP_WRITEOK), + /* add others here before... */ + SWP_SCANNING = (1 << 8), /* refcount in scan_swap_map */ ++ SWP_READONLY = (1 << 2), + }; + + #define SWAP_CLUSTER_MAX 32 +@@ -131,6 +134,7 @@ + /* + * The in-memory structure used to track swap areas. + */ ++struct user_beancounter; + struct swap_info_struct { + unsigned int flags; + int prio; /* swap priority */ +@@ -148,6 +152,9 @@ + unsigned int max; + unsigned int inuse_pages; + int next; /* next entry on swap list */ ++#ifdef CONFIG_BC_SWAP_ACCOUNTING ++ struct user_beancounter **swap_ubs; ++#endif + }; + + struct swap_list_t { +@@ -155,9 +162,19 @@ + int next; /* swapfile to be used next */ + }; + ++extern struct swap_list_t swap_list; ++extern struct swap_info_struct swap_info[MAX_SWAPFILES]; ++ + /* Swap 50% full? Release swapcache more aggressively.. */ + #define vm_swap_full() (nr_swap_pages*2 < total_swap_pages) + ++/* linux/mm/oom_kill.c */ ++extern void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order); ++extern int register_oom_notifier(struct notifier_block *nb); ++extern int unregister_oom_notifier(struct notifier_block *nb); ++extern int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, const char *message); ++extern struct task_struct *oom_select_bad_process(struct user_beancounter *ub); ++ + /* linux/mm/memory.c */ + extern void swapin_readahead(swp_entry_t, unsigned long, struct vm_area_struct *); + +@@ -224,6 +241,9 @@ + extern void show_swap_cache_info(void); + extern int add_to_swap(struct page *, gfp_t); + extern void __delete_from_swap_cache(struct page *); ++extern int add_to_swap_cache(struct page *page, swp_entry_t entry); ++extern int __add_to_swap_cache(struct page *page, ++ swp_entry_t entry, gfp_t gfp_mask); + extern void delete_from_swap_cache(struct page *); + extern int move_to_swap_cache(struct page *, swp_entry_t); + extern int move_from_swap_cache(struct page *, unsigned long, +@@ -237,7 +257,7 @@ + extern long total_swap_pages; + extern unsigned int nr_swapfiles; + extern void si_swapinfo(struct sysinfo *); +-extern swp_entry_t get_swap_page(void); ++extern swp_entry_t get_swap_page(struct user_beancounter *); + extern swp_entry_t get_swap_page_of_type(int); + extern int swap_duplicate(swp_entry_t); + extern int valid_swaphandles(swp_entry_t, unsigned long *); +@@ -250,6 +270,7 @@ + extern struct swap_info_struct *get_swap_info_struct(unsigned); + extern int can_share_swap_page(struct page *); + extern int remove_exclusive_swap_page(struct page *); ++extern int try_to_remove_exclusive_swap_page(struct page *); + struct backing_dev_info; + + extern spinlock_t swap_lock; +@@ -350,7 +371,7 @@ + return 0; + } + +-static inline swp_entry_t get_swap_page(void) ++static inline swp_entry_t get_swap_page(struct user_beancounter *ub) + { + swp_entry_t entry; + entry.val = 0; +Index: kernel/include/linux/sysctl.h +=================================================================== +--- kernel.orig/include/linux/sysctl.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/sysctl.h 2008-11-24 15:47:46.000000000 +0100 +@@ -159,6 +159,9 @@ + KERN_SETUID_DUMPABLE=69, /* int: behaviour of dumps for setuid core */ + KERN_SPIN_RETRY=70, /* int: number of spinlock retries */ + KERN_ACPI_VIDEO_FLAGS=71, /* int: flags for setting up video after ACPI sleep */ ++#ifdef CONFIG_GRKERNSEC_SYSCTL ++ KERN_GRSECURITY=98, /* grsecurity */ ++#endif + KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */ + KERN_COMPAT_LOG=73, /* int: print compat layer messages */ + KERN_MAX_LOCK_DEPTH=74, +@@ -948,6 +951,7 @@ + extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev); + extern void sysctl_head_finish(struct ctl_table_header *prev); + extern int sysctl_perm(struct ctl_table *table, int op); ++extern int ve_allow_kthreads; + + typedef struct ctl_table ctl_table; + +@@ -1036,6 +1040,8 @@ + */ + + /* A sysctl table is an array of struct ctl_table: */ ++struct ve_struct; ++ + struct ctl_table + { + int ctl_name; /* Binary ID */ +@@ -1049,6 +1055,8 @@ + ctl_handler *strategy; /* Callback function for all r/w */ + void *extra1; + void *extra2; ++ struct ve_struct *owner_env; ++ int virt_handler; + }; + + /* struct ctl_table_header is used to maintain dynamic lists of +@@ -1062,10 +1070,14 @@ + }; + + struct ctl_table_header *register_sysctl_table(struct ctl_table * table); ++struct ctl_table_header *register_glob_sysctl_table(struct ctl_table * table); + + void unregister_sysctl_table(struct ctl_table_header * table); + int sysctl_check_table(struct ctl_table *table); + ++ctl_table *clone_sysctl_template(ctl_table *tmpl); ++void free_sysctl_clone(ctl_table *clone); ++ + #else /* __KERNEL__ */ + + #endif /* __KERNEL__ */ +Index: kernel/include/linux/sysfs.h +=================================================================== +--- kernel.orig/include/linux/sysfs.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/sysfs.h 2008-11-24 15:47:46.000000000 +0100 +@@ -19,6 +19,7 @@ + + struct kobject; + struct module; ++struct sysfs_open_dirent; + + /* FIXME + * The *owner field is no longer used, but leave around +@@ -76,6 +77,66 @@ + ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t); + }; + ++/* type-specific structures for sysfs_dirent->s_* union members */ ++struct sysfs_elem_dir { ++ struct kobject *kobj; ++ /* children list starts here and goes through sd->s_sibling */ ++ struct sysfs_dirent *children; ++}; ++ ++struct sysfs_elem_symlink { ++ struct sysfs_dirent *target_sd; ++}; ++ ++struct sysfs_elem_attr { ++ struct attribute *attr; ++ struct sysfs_open_dirent *open; ++}; ++ ++struct sysfs_elem_bin_attr { ++ struct bin_attribute *bin_attr; ++}; ++ ++/* ++ * sysfs_dirent - the building block of sysfs hierarchy. Each and ++ * every sysfs node is represented by single sysfs_dirent. ++ * ++ * As long as s_count reference is held, the sysfs_dirent itself is ++ * accessible. Dereferencing s_elem or any other outer entity ++ * requires s_active reference. ++ */ ++struct sysfs_dirent { ++ atomic_t s_count; ++ atomic_t s_active; ++ struct sysfs_dirent *s_parent; ++ struct sysfs_dirent *s_sibling; ++ const char *s_name; ++ ++ union { ++ struct sysfs_elem_dir s_dir; ++ struct sysfs_elem_symlink s_symlink; ++ struct sysfs_elem_attr s_attr; ++ struct sysfs_elem_bin_attr s_bin_attr; ++ }; ++ ++ unsigned int s_flags; ++ ino_t s_ino; ++ umode_t s_mode; ++ struct iattr *s_iattr; ++}; ++ ++#define SD_DEACTIVATED_BIAS INT_MIN ++ ++#define SYSFS_TYPE_MASK 0x00ff ++#define SYSFS_DIR 0x0001 ++#define SYSFS_KOBJ_ATTR 0x0002 ++#define SYSFS_KOBJ_BIN_ATTR 0x0004 ++#define SYSFS_KOBJ_LINK 0x0008 ++#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) ++ ++#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK ++#define SYSFS_FLAG_REMOVED 0x0200 ++ + #ifdef CONFIG_SYSFS + + int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), +@@ -114,6 +175,8 @@ + + extern int __must_check sysfs_init(void); + ++extern struct file_system_type sysfs_fs_type; ++ + #else /* CONFIG_SYSFS */ + + static inline int sysfs_schedule_callback(struct kobject *kobj, +Index: kernel/include/linux/task_io_accounting_ops.h +=================================================================== +--- kernel.orig/include/linux/task_io_accounting_ops.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/task_io_accounting_ops.h 2008-11-24 15:47:46.000000000 +0100 +@@ -5,10 +5,12 @@ + #define __TASK_IO_ACCOUNTING_OPS_INCLUDED + + #include ++#include + + #ifdef CONFIG_TASK_IO_ACCOUNTING + static inline void task_io_account_read(size_t bytes) + { ++ ub_io_account_read(bytes); + current->ioac.read_bytes += bytes; + } + +@@ -21,8 +23,14 @@ + return p->ioac.read_bytes >> 9; + } + +-static inline void task_io_account_write(size_t bytes) ++static inline void task_io_account_write(struct page *page, size_t bytes, ++ int sync) + { ++ if (sync) ++ ub_io_account_write(bytes); ++ else ++ ub_io_account_dirty(page, bytes); ++ + current->ioac.write_bytes += bytes; + } + +@@ -37,6 +45,7 @@ + + static inline void task_io_account_cancelled_write(size_t bytes) + { ++ ub_io_account_write_cancelled(bytes); + current->ioac.cancelled_write_bytes += bytes; + } + +@@ -56,7 +65,8 @@ + return 0; + } + +-static inline void task_io_account_write(size_t bytes) ++static inline void task_io_account_write(struct page *page, size_t bytes, ++ int sync) + { + } + +Index: kernel/include/linux/tty.h +=================================================================== +--- kernel.orig/include/linux/tty.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/tty.h 2008-11-24 15:47:46.000000000 +0100 +@@ -241,6 +241,7 @@ + spinlock_t read_lock; + /* If the tty has a pending do_SAK, queue it here - akpm */ + struct work_struct SAK_work; ++ struct ve_struct *owner_env; + }; + + /* tty magic number */ +@@ -270,6 +271,7 @@ + #define TTY_HUPPED 18 /* Post driver->hangup() */ + #define TTY_FLUSHING 19 /* Flushing to ldisc in progress */ + #define TTY_FLUSHPENDING 20 /* Queued buffer flush pending */ ++#define TTY_CHARGED 21 /* Charged as ub resource */ + + #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) + +Index: kernel/include/linux/tty_driver.h +=================================================================== +--- kernel.orig/include/linux/tty_driver.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/tty_driver.h 2008-11-24 15:47:46.000000000 +0100 +@@ -222,8 +222,19 @@ + unsigned int set, unsigned int clear); + + struct list_head tty_drivers; ++ struct ve_struct *owner_env; + }; + ++#ifdef CONFIG_UNIX98_PTYS ++extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ ++extern struct tty_driver *pts_driver; /* Unix98 pty slaves; for /dev/ptmx */ ++#endif ++ ++#ifdef CONFIG_LEGACY_PTYS ++extern struct tty_driver *pty_driver; ++extern struct tty_driver *pty_slave_driver; ++#endif ++ + extern struct list_head tty_drivers; + + struct tty_driver *alloc_tty_driver(int lines); +@@ -231,6 +242,9 @@ + void tty_set_operations(struct tty_driver *driver, + const struct tty_operations *op); + ++struct class *init_ve_tty_class(void); ++void fini_ve_tty_class(struct class *ve_tty_class); ++ + /* tty driver magic number */ + #define TTY_DRIVER_MAGIC 0x5402 + +Index: kernel/include/linux/types.h +=================================================================== +--- kernel.orig/include/linux/types.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/types.h 2008-11-24 15:47:46.000000000 +0100 +@@ -29,6 +29,11 @@ + typedef __kernel_clockid_t clockid_t; + typedef __kernel_mqd_t mqd_t; + ++#ifndef __ENVID_T_DEFINED__ ++typedef unsigned envid_t; ++#define __ENVID_T_DEFINED__ ++#endif ++ + #ifdef __KERNEL__ + typedef _Bool bool; + +Index: kernel/include/linux/utsname.h +=================================================================== +--- kernel.orig/include/linux/utsname.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/utsname.h 2008-11-24 15:47:46.000000000 +0100 +@@ -42,6 +42,7 @@ + struct new_utsname name; + }; + extern struct uts_namespace init_uts_ns; ++extern struct new_utsname virt_utsname; + + static inline void get_uts_ns(struct uts_namespace *ns) + { +Index: kernel/include/linux/ve.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/ve.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,407 @@ ++/* ++ * include/linux/ve.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef _LINUX_VE_H ++#define _LINUX_VE_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef VZMON_DEBUG ++# define VZTRACE(fmt,args...) \ ++ printk(KERN_DEBUG fmt, ##args) ++#else ++# define VZTRACE(fmt,args...) ++#endif /* VZMON_DEBUG */ ++ ++struct tty_driver; ++struct devpts_config; ++struct task_struct; ++struct new_utsname; ++struct file_system_type; ++struct icmp_mib; ++struct ip_mib; ++struct tcp_mib; ++struct udp_mib; ++struct linux_mib; ++struct fib_info; ++struct fib_rule; ++struct veip_struct; ++struct ve_monitor; ++struct nsproxy; ++struct ve_sit_tunnels; ++ ++#if defined(CONFIG_VE) && defined(CONFIG_INET) ++struct fib_table; ++#ifdef CONFIG_VE_IPTABLES ++struct xt_table; ++struct nf_conn; ++ ++#define FRAG6Q_HASHSZ 64 ++ ++struct ve_nf_conntrack { ++ struct hlist_head *_bysource; ++ struct nf_nat_protocol **_nf_nat_protos; ++ int _nf_nat_vmalloced; ++ struct xt_table *_nf_nat_table; ++ struct nf_conntrack_l3proto *_nf_nat_l3proto; ++ atomic_t _nf_conntrack_count; ++ int _nf_conntrack_max; ++ struct hlist_head *_nf_conntrack_hash; ++ int _nf_conntrack_checksum; ++ int _nf_conntrack_vmalloc; ++ struct hlist_head _unconfirmed; ++ struct hlist_head *_nf_ct_expect_hash; ++ unsigned int _nf_ct_expect_vmalloc; ++ unsigned int _nf_ct_expect_max; ++ struct hlist_head *_nf_ct_helper_hash; ++ unsigned int _nf_ct_helper_vmalloc; ++ struct inet_frags _nf_frags6; ++ struct inet_frags_ctl _nf_frags6_ctl; ++#ifdef CONFIG_SYSCTL ++ /* l4 stuff: */ ++ unsigned long _nf_ct_icmp_timeout; ++ unsigned long _nf_ct_icmpv6_timeout; ++ unsigned int _nf_ct_udp_timeout; ++ unsigned int _nf_ct_udp_timeout_stream; ++ unsigned int _nf_ct_generic_timeout; ++ unsigned int _nf_ct_log_invalid; ++ unsigned int _nf_ct_tcp_timeout_max_retrans; ++ int _nf_ct_tcp_be_liberal; ++ int _nf_ct_tcp_loose; ++ int _nf_ct_tcp_max_retrans; ++ unsigned int _nf_ct_tcp_timeouts[10]; ++ struct ctl_table_header *_icmp_sysctl_header; ++ unsigned int _tcp_sysctl_table_users; ++ struct ctl_table_header *_tcp_sysctl_header; ++ unsigned int _udp_sysctl_table_users; ++ struct ctl_table_header *_udp_sysctl_header; ++ struct ctl_table_header *_icmpv6_sysctl_header; ++ struct ctl_table_header *_generic_sysctl_header; ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ struct ctl_table_header *_icmp_compat_sysctl_header; ++ struct ctl_table_header *_tcp_compat_sysctl_header; ++ struct ctl_table_header *_udp_compat_sysctl_header; ++ struct ctl_table_header *_generic_compat_sysctl_header; ++#endif ++ /* l4 protocols sysctl tables: */ ++ struct nf_conntrack_l4proto *_nf_conntrack_l4proto_icmp; ++ struct nf_conntrack_l4proto *_nf_conntrack_l4proto_tcp4; ++ struct nf_conntrack_l4proto *_nf_conntrack_l4proto_icmpv6; ++ struct nf_conntrack_l4proto *_nf_conntrack_l4proto_tcp6; ++ struct nf_conntrack_l4proto *_nf_conntrack_l4proto_udp4; ++ struct nf_conntrack_l4proto *_nf_conntrack_l4proto_udp6; ++ struct nf_conntrack_l4proto *_nf_conntrack_l4proto_generic; ++ struct nf_conntrack_l4proto **_nf_ct_protos[PF_MAX]; ++ /* l3 protocols sysctl tables: */ ++ struct nf_conntrack_l3proto *_nf_conntrack_l3proto_ipv4; ++ struct nf_conntrack_l3proto *_nf_conntrack_l3proto_ipv6; ++ struct nf_conntrack_l3proto *_nf_ct_l3protos[AF_MAX]; ++ /* sysctl standalone stuff: */ ++ struct ctl_table_header *_nf_ct_sysctl_header; ++ ctl_table *_nf_ct_sysctl_table; ++ ctl_table *_nf_ct_netfilter_table; ++ ctl_table *_nf_ct_net_table; ++ ctl_table *_ip_ct_net_table; ++ ctl_table *_ip_ct_netfilter_table; ++ struct ctl_table_header *_ip_ct_sysctl_header; ++ int _nf_ct_log_invalid_proto_min; ++ int _nf_ct_log_invalid_proto_max; ++#endif /* CONFIG_SYSCTL */ ++}; ++#endif ++#endif ++ ++struct ve_cpu_stats { ++ cycles_t idle_time; ++ cycles_t iowait_time; ++ cycles_t strt_idle_time; ++ cycles_t used_time; ++ seqcount_t stat_lock; ++ int nr_running; ++ int nr_unint; ++ int nr_iowait; ++ cputime64_t user; ++ cputime64_t nice; ++ cputime64_t system; ++} ____cacheline_aligned; ++ ++struct ve_ipt_recent; ++struct ve_xt_hashlimit; ++ ++struct ve_struct { ++ struct list_head ve_list; ++ ++ envid_t veid; ++ struct list_head vetask_lh; ++ /* capability bounding set */ ++ kernel_cap_t ve_cap_bset; ++ atomic_t pcounter; ++ /* ref counter to ve from ipc */ ++ atomic_t counter; ++ unsigned int class_id; ++ struct rw_semaphore op_sem; ++ int is_running; ++ int is_locked; ++ atomic_t suspend; ++ /* see vzcalluser.h for VE_FEATURE_XXX definitions */ ++ __u64 features; ++ ++/* VE's root */ ++ struct vfsmount *fs_rootmnt; ++ struct dentry *fs_root; ++ ++/* sysctl */ ++ struct list_head sysctl_lh; ++ struct ctl_table_header *uts_header; ++ struct file_system_type *proc_fstype; ++ struct vfsmount *proc_mnt; ++ struct proc_dir_entry *proc_root; ++ struct proc_dir_entry *proc_sys_root; ++ struct proc_dir_entry *_proc_net; ++ struct proc_dir_entry *_proc_net_stat; ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++ struct proc_dir_entry *_proc_net_devsnmp6; ++#endif ++ ++/* BSD pty's */ ++#ifdef CONFIG_LEGACY_PTYS ++ struct tty_driver *pty_driver; ++ struct tty_driver *pty_slave_driver; ++#endif ++#ifdef CONFIG_UNIX98_PTYS ++ struct tty_driver *ptm_driver; ++ struct tty_driver *pts_driver; ++ struct idr *allocated_ptys; ++ struct file_system_type *devpts_fstype; ++ struct vfsmount *devpts_mnt; ++ struct dentry *devpts_root; ++ struct devpts_config *devpts_config; ++#endif ++ ++ struct ve_nfs_context *nfs_context; ++ ++ struct file_system_type *shmem_fstype; ++ struct vfsmount *shmem_mnt; ++#ifdef CONFIG_SYSFS ++ struct file_system_type *sysfs_fstype; ++ struct vfsmount *sysfs_mnt; ++ struct super_block *sysfs_sb; ++ struct sysfs_dirent *_sysfs_root; ++#endif ++#ifndef CONFIG_SYSFS_DEPRECATED ++ struct kobject *_virtual_dir; ++#endif ++ struct kset *class_subsys; ++ struct kset *class_obj_subsys; ++ struct kset *devices_subsys; ++ struct class *tty_class; ++ ++#ifdef CONFIG_NET ++ struct class *net_class; ++#ifdef CONFIG_INET ++ struct ipv4_devconf *_ipv4_devconf; ++ struct ipv4_devconf *_ipv4_devconf_dflt; ++ struct ctl_table_header *forward_header; ++ struct ctl_table *forward_table; ++ unsigned long rt_flush_required; ++ struct neigh_table *ve_arp_tbl; ++ struct ve_sit_tunnels *_sit_tunnels; ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++ struct ipv6_devconf *_ipv6_devconf; ++ struct ipv6_devconf *_ipv6_devconf_dflt; ++ struct neigh_table *ve_nd_tbl; ++#endif ++#endif ++#endif ++#if defined(CONFIG_VE_NETDEV) || defined (CONFIG_VE_NETDEV_MODULE) ++ struct veip_struct *veip; ++ struct net_device *_venet_dev; ++#endif ++ ++/* per VE CPU stats*/ ++ struct timespec start_timespec; ++ u64 start_jiffies; /* Deprecated */ ++ cycles_t start_cycles; ++ unsigned long avenrun[3]; /* loadavg data */ ++ ++ cycles_t cpu_used_ve; ++ struct kstat_lat_pcpu_struct sched_lat_ve; ++ ++#ifdef CONFIG_INET ++ struct hlist_head *_fib_info_hash; ++ struct hlist_head *_fib_info_laddrhash; ++ int _fib_hash_size; ++ int _fib_info_cnt; ++ ++ struct fib_rule *_local_rule; ++ struct list_head _fib_rules; ++ /* XXX: why a magic constant? */ ++#ifdef CONFIG_IP_MULTIPLE_TABLES ++ struct hlist_head _fib_table_hash[256]; ++#else ++ struct hlist_head _fib_table_hash[1]; ++ struct fib_table *_main_table; ++ struct fib_table *_local_table; ++#endif ++ struct icmp_mib *_icmp_statistics[2]; ++ struct icmpmsg_mib *_icmpmsg_statistics[2]; ++ struct ipstats_mib *_ip_statistics[2]; ++ struct tcp_mib *_tcp_statistics[2]; ++ struct udp_mib *_udp_statistics[2]; ++ struct udp_mib *_udplite_statistics[2]; ++ struct linux_mib *_net_statistics[2]; ++ struct venet_stat *stat; ++#ifdef CONFIG_VE_IPTABLES ++/* core/netfilter.c virtualization */ ++ void *_nf_hooks; ++ struct xt_table *_ve_ipt_filter_pf; /* packet_filter struct */ ++ struct xt_table *_ve_ip6t_filter_pf; ++ struct xt_table *_ipt_mangle_table; ++ struct xt_table *_ip6t_mangle_table; ++ struct list_head _xt_tables[NPROTO]; ++ ++ __u64 _iptables_modules; ++ struct ve_nf_conntrack *_nf_conntrack; ++ struct ve_ipt_recent *_ipt_recent; ++ struct ve_xt_hashlimit *_xt_hashlimit; ++#endif /* CONFIG_VE_IPTABLES */ ++ ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++#ifdef CONFIG_IPV6_MULTIPLE_TABLES ++ struct hlist_head _fib6_table_hash[256]; ++ struct fib6_table *_fib6_local_table; ++#else ++ struct hlist_head _fib6_table_hash[1]; ++#endif ++ struct fib6_table *_fib6_table; ++ struct ipstats_mib *_ipv6_statistics[2]; ++ struct icmpv6_mib *_icmpv6_statistics[2]; ++ struct icmpv6msg_mib *_icmpv6msg_statistics[2]; ++ struct udp_mib *_udp_stats_in6[2]; ++ struct udp_mib *_udplite_stats_in6[2]; ++#endif ++#endif ++ wait_queue_head_t *_log_wait; ++ unsigned long *_log_start; ++ unsigned long *_log_end; ++ unsigned long *_logged_chars; ++ char *log_buf; ++#define VE_DEFAULT_LOG_BUF_LEN 4096 ++ ++ struct ve_cpu_stats *cpu_stats; ++ unsigned long down_at; ++ struct list_head cleanup_list; ++#if defined(CONFIG_FUSE_FS) || defined(CONFIG_FUSE_FS_MODULE) ++ struct list_head _fuse_conn_list; ++ struct super_block *_fuse_control_sb; ++ ++ struct file_system_type *fuse_fs_type; ++ struct file_system_type *fuse_ctl_fs_type; ++#endif ++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ++ struct proc_dir_entry *_proc_vlan_dir; ++ struct proc_dir_entry *_proc_vlan_conf; ++#endif ++ unsigned long jiffies_fixup; ++ unsigned char disable_net; ++ struct ve_monitor *monitor; ++ struct proc_dir_entry *monitor_proc; ++ unsigned long meminfo_val; ++ ++#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE) \ ++ || defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE) ++ unsigned int _nlmsvc_users; ++ pid_t _nlmsvc_pid; ++ int _nlmsvc_grace_period; ++ unsigned long _nlmsvc_timeout; ++#endif ++ ++ struct nsproxy *ve_ns; ++#ifdef CONFIG_GRKERNSEC ++ struct { ++ int lock; ++#ifdef CONFIG_GRKERNSEC_TPE ++ int enable_tpe; ++ int tpe_gid; ++#ifdef CONFIG_GRKERNSEC_TPE_ALL ++ int enable_tpe_all; ++#endif ++#endif /*CONFIG_GRKERNSEC_TPE */ ++ } grsec; ++#endif /* CONFIG_GRKERNSEC */ ++}; ++ ++#define VE_CPU_STATS(ve, cpu) (per_cpu_ptr((ve)->cpu_stats, cpu)) ++ ++extern int nr_ve; ++ ++#ifdef CONFIG_VE ++ ++void do_update_load_avg_ve(void); ++void do_env_free(struct ve_struct *ptr); ++ ++static inline struct ve_struct *get_ve(struct ve_struct *ptr) ++{ ++ if (ptr != NULL) ++ atomic_inc(&ptr->counter); ++ return ptr; ++} ++ ++static inline void put_ve(struct ve_struct *ptr) ++{ ++ if (ptr && atomic_dec_and_test(&ptr->counter)) { ++ if (atomic_read(&ptr->pcounter) > 0) ++ BUG(); ++ if (ptr->is_running) ++ BUG(); ++ do_env_free(ptr); ++ } ++} ++ ++static inline void pget_ve(struct ve_struct *ptr) ++{ ++ atomic_inc(&ptr->pcounter); ++} ++ ++void ve_cleanup_schedule(struct ve_struct *); ++static inline void pput_ve(struct ve_struct *ptr) ++{ ++ if (unlikely(atomic_dec_and_test(&ptr->pcounter))) ++ ve_cleanup_schedule(ptr); ++} ++ ++extern spinlock_t ve_cleanup_lock; ++extern struct list_head ve_cleanup_list; ++extern struct task_struct *ve_cleanup_thread; ++ ++extern unsigned long long ve_relative_clock(struct timespec * ts); ++ ++#ifdef CONFIG_FAIRSCHED ++#define ve_cpu_online_map(ve, mask) fairsched_cpu_online_map(ve->veid, mask) ++#else ++#define ve_cpu_online_map(ve, mask) do { *(mask) = cpu_online_map; } while (0) ++#endif ++#else /* CONFIG_VE */ ++#define ve_utsname system_utsname ++#define get_ve(ve) (NULL) ++#define put_ve(ve) do { } while (0) ++#define pget_ve(ve) do { } while (0) ++#define pput_ve(ve) do { } while (0) ++#endif /* CONFIG_VE */ ++ ++#endif /* _LINUX_VE_H */ +Index: kernel/include/linux/ve_nfs.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/ve_nfs.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,29 @@ ++/* ++ * linux/include/ve_nfs.h ++ * ++ * VE context for NFS ++ * ++ * Copyright (C) 2007 SWsoft ++ */ ++ ++#ifndef __VE_NFS_H__ ++#define __VE_NFS_H__ ++ ++#ifdef CONFIG_VE ++ ++#include ++ ++#define NFS_CTX_FIELD(arg) (get_exec_env()->_##arg) ++ ++#define nlmsvc_grace_period NFS_CTX_FIELD(nlmsvc_grace_period) ++#define nlmsvc_timeout NFS_CTX_FIELD(nlmsvc_timeout) ++#define nlmsvc_users NFS_CTX_FIELD(nlmsvc_users) ++#define nlmsvc_pid NFS_CTX_FIELD(nlmsvc_pid) ++#else ++#define nlmsvc_grace_period _nlmsvc_timeout ++#define nlmsvc_timeout _nlmsvc_grace_period ++#define nlmsvc_pid _nlmsvc_pid ++#define nlmsvc_timeout _nlmsvc_timeout ++#endif ++ ++#endif +Index: kernel/include/linux/ve_proto.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/ve_proto.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,89 @@ ++/* ++ * include/linux/ve_proto.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __VE_H__ ++#define __VE_H__ ++ ++#ifdef CONFIG_VE ++ ++struct ve_struct; ++ ++#ifdef CONFIG_INET ++void ip_fragment_cleanup(struct ve_struct *envid); ++void tcp_v4_kill_ve_sockets(struct ve_struct *envid); ++#ifdef CONFIG_VE_NETDEV ++int venet_init(void); ++#endif ++#else ++static inline void ip_fragment_cleanup(struct ve_struct *ve) { ; } ++#endif ++ ++extern struct list_head ve_list_head; ++#define for_each_ve(ve) list_for_each_entry((ve), &ve_list_head, ve_list) ++extern rwlock_t ve_list_lock; ++extern struct ve_struct *get_ve_by_id(envid_t); ++extern struct ve_struct *__find_ve_by_id(envid_t); ++ ++struct env_create_param3; ++extern int real_env_create(envid_t veid, unsigned flags, u32 class_id, ++ struct env_create_param3 *data, int datalen); ++extern void ve_move_task(struct task_struct *, struct ve_struct *); ++ ++int set_device_perms_ve(envid_t veid, unsigned type, dev_t dev, unsigned mask); ++int get_device_perms_ve(int dev_type, dev_t dev, int access_mode); ++void clean_device_perms_ve(envid_t veid); ++extern struct file_operations proc_devperms_ops; ++ ++enum { ++ VE_SS_CHAIN, ++ ++ VE_MAX_CHAINS ++}; ++ ++typedef int ve_hook_init_fn(void *data); ++typedef void ve_hook_fini_fn(void *data); ++ ++struct ve_hook ++{ ++ ve_hook_init_fn *init; ++ ve_hook_fini_fn *fini; ++ struct module *owner; ++ ++ /* Functions are called in ascending priority */ ++ int priority; ++ ++ /* Private part */ ++ struct list_head list; ++}; ++ ++enum { ++ HOOK_PRIO_DEFAULT = 0, ++ ++ HOOK_PRIO_FS = HOOK_PRIO_DEFAULT, ++ ++ HOOK_PRIO_NET_PRE, ++ HOOK_PRIO_NET, ++ HOOK_PRIO_NET_POST, ++ ++ HOOK_PRIO_AFTERALL = INT_MAX ++}; ++ ++extern int ve_hook_iterate_init(int chain, void *data); ++extern void ve_hook_iterate_fini(int chain, void *data); ++ ++extern void ve_hook_register(int chain, struct ve_hook *vh); ++extern void ve_hook_unregister(struct ve_hook *vh); ++#else /* CONFIG_VE */ ++#define ve_hook_register(ch, vh) do { } while (0) ++#define ve_hook_unregister(ve) do { } while (0) ++ ++#define get_device_perms_ve(t, d, a) (0) ++#endif /* CONFIG_VE */ ++#endif +Index: kernel/include/linux/ve_task.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/ve_task.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,68 @@ ++/* ++ * include/linux/ve_task.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __VE_TASK_H__ ++#define __VE_TASK_H__ ++ ++#include ++#include ++ ++struct ve_task_info { ++/* virtualization */ ++ struct ve_struct *owner_env; ++ struct ve_struct *exec_env; ++ struct ve_struct *saved_env; ++ struct list_head vetask_list; ++ struct dentry *glob_proc_dentry; ++/* statistics: scheduling latency */ ++ cycles_t sleep_time; ++ cycles_t sched_time; ++ cycles_t sleep_stamp; ++ cycles_t wakeup_stamp; ++ seqcount_t wakeup_lock; ++}; ++ ++#define VE_TASK_INFO(task) (&(task)->ve_task_info) ++#define VE_TASK_LIST_2_TASK(lh) \ ++ list_entry(lh, struct task_struct, ve_task_info.vetask_list) ++ ++#ifdef CONFIG_VE ++extern struct ve_struct ve0; ++#define get_ve0() (&ve0) ++ ++#define ve_save_context(t) do { \ ++ t->ve_task_info.saved_env = \ ++ t->ve_task_info.exec_env; \ ++ t->ve_task_info.exec_env = get_ve0(); \ ++ } while (0) ++#define ve_restore_context(t) do { \ ++ t->ve_task_info.exec_env = \ ++ t->ve_task_info.saved_env; \ ++ } while (0) ++ ++#define get_exec_env() (current->ve_task_info.exec_env) ++#define set_exec_env(ve) ({ \ ++ struct ve_task_info *vi; \ ++ struct ve_struct *old; \ ++ \ ++ vi = ¤t->ve_task_info; \ ++ old = vi->exec_env; \ ++ vi->exec_env = ve; \ ++ old; \ ++ }) ++#else ++#define get_ve0() (NULL) ++#define get_exec_env() (NULL) ++#define set_exec_env(new_env) (NULL) ++#define ve_save_context(t) do { } while (0) ++#define ve_restore_context(t) do { } while (0) ++#endif ++ ++#endif /* __VE_TASK_H__ */ +Index: kernel/include/linux/veip.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/veip.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,15 @@ ++#ifndef __VE_IP_H_ ++#define __VE_IP_H_ ++ ++struct ve_addr_struct { ++ int family; ++ __u32 key[4]; ++}; ++ ++struct sockaddr; ++ ++extern void veaddr_print(char *, int, struct ve_addr_struct *); ++extern int sockaddr_to_veaddr(struct sockaddr __user *uaddr, int addrlen, ++ struct ve_addr_struct *veaddr); ++ ++#endif +Index: kernel/include/linux/venet.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/venet.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,72 @@ ++/* ++ * include/linux/venet.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef _VENET_H ++#define _VENET_H ++ ++#include ++#include ++#include ++#include ++ ++#define VEIP_HASH_SZ 512 ++ ++struct ve_struct; ++struct venet_stat; ++struct ip_entry_struct ++{ ++ struct ve_addr_struct addr; ++ struct ve_struct *active_env; ++ struct venet_stat *stat; ++ struct veip_struct *veip; ++ struct list_head ip_hash; ++ struct list_head ve_list; ++}; ++ ++struct veip_struct ++{ ++ struct list_head src_lh; ++ struct list_head dst_lh; ++ struct list_head ip_lh; ++ struct list_head list; ++ envid_t veid; ++}; ++ ++/* veip_hash_lock should be taken for write by caller */ ++void ip_entry_hash(struct ip_entry_struct *entry, struct veip_struct *veip); ++/* veip_hash_lock should be taken for write by caller */ ++void ip_entry_unhash(struct ip_entry_struct *entry); ++/* veip_hash_lock should be taken for read by caller */ ++struct ip_entry_struct *venet_entry_lookup(struct ve_addr_struct *); ++ ++/* veip_hash_lock should be taken for read by caller */ ++struct veip_struct *veip_find(envid_t veid); ++/* veip_hash_lock should be taken for write by caller */ ++struct veip_struct *veip_findcreate(envid_t veid); ++/* veip_hash_lock should be taken for write by caller */ ++void veip_put(struct veip_struct *veip); ++ ++extern struct list_head veip_lh; ++ ++int veip_start(struct ve_struct *ve); ++void veip_stop(struct ve_struct *ve); ++__exit void veip_cleanup(void); ++int veip_entry_add(struct ve_struct *ve, struct ve_addr_struct *addr); ++int veip_entry_del(envid_t veid, struct ve_addr_struct *addr); ++int venet_change_skb_owner(struct sk_buff *skb); ++ ++extern struct list_head ip_entry_hash_table[]; ++extern rwlock_t veip_hash_lock; ++ ++#ifdef CONFIG_PROC_FS ++int veip_seq_show(struct seq_file *m, void *v); ++#endif ++ ++#endif +Index: kernel/include/linux/veprintk.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/veprintk.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,38 @@ ++/* ++ * include/linux/veprintk.h ++ * ++ * Copyright (C) 2006 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __VE_PRINTK_H__ ++#define __VE_PRINTK_H__ ++ ++#ifdef CONFIG_VE ++ ++#define ve_log_wait (*(get_exec_env()->_log_wait)) ++#define ve_log_start (*(get_exec_env()->_log_start)) ++#define ve_log_end (*(get_exec_env()->_log_end)) ++#define ve_logged_chars (*(get_exec_env()->_logged_chars)) ++#define ve_log_buf (get_exec_env()->log_buf) ++#define ve_log_buf_len (ve_is_super(get_exec_env()) ? \ ++ log_buf_len : VE_DEFAULT_LOG_BUF_LEN) ++#define VE_LOG_BUF_MASK (ve_log_buf_len - 1) ++#define VE_LOG_BUF(idx) (ve_log_buf[(idx) & VE_LOG_BUF_MASK]) ++ ++#else ++ ++#define ve_log_wait log_wait ++#define ve_log_start log_start ++#define ve_log_end log_end ++#define ve_logged_chars logged_chars ++#define ve_log_buf log_buf ++#define ve_log_buf_len log_buf_len ++#define VE_LOG_BUF_MASK LOG_BUF_MASK ++#define VE_LOG_BUF(idx) LOG_BUF(idx) ++ ++#endif /* CONFIG_VE */ ++#endif /* __VE_PRINTK_H__ */ +Index: kernel/include/linux/virtinfo.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/virtinfo.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,99 @@ ++/* ++ * include/linux/virtinfo.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __LINUX_VIRTINFO_H ++#define __LINUX_VIRTINFO_H ++ ++#include ++#include ++#include ++ ++struct vnotifier_block ++{ ++ int (*notifier_call)(struct vnotifier_block *self, ++ unsigned long, void *, int); ++ struct vnotifier_block *next; ++ int priority; ++}; ++ ++extern struct semaphore virtinfo_sem; ++void __virtinfo_notifier_register(int type, struct vnotifier_block *nb); ++void virtinfo_notifier_register(int type, struct vnotifier_block *nb); ++void virtinfo_notifier_unregister(int type, struct vnotifier_block *nb); ++int virtinfo_notifier_call(int type, unsigned long n, void *data); ++ ++struct page_info { ++ unsigned long nr_file_dirty; ++ unsigned long nr_writeback; ++ unsigned long nr_anon_pages; ++ unsigned long nr_file_mapped; ++ unsigned long nr_slab_rec; ++ unsigned long nr_slab_unrec; ++ unsigned long nr_pagetable; ++ unsigned long nr_unstable_nfs; ++ unsigned long nr_bounce; ++}; ++ ++struct meminfo { ++ struct sysinfo si; ++ struct page_info pi; ++ unsigned long active, inactive; ++ unsigned long cache, swapcache; ++ unsigned long committed_space; ++ unsigned long allowed; ++ unsigned long vmalloc_total, vmalloc_used, vmalloc_largest; ++}; ++ ++#define VIRTINFO_MEMINFO 0 ++#define VIRTINFO_ENOUGHMEM 1 ++#define VIRTINFO_DOFORK 2 ++#define VIRTINFO_DOEXIT 3 ++#define VIRTINFO_DOEXECVE 4 ++#define VIRTINFO_DOFORKRET 5 ++#define VIRTINFO_DOFORKPOST 6 ++#define VIRTINFO_EXIT 7 ++#define VIRTINFO_EXITMMAP 8 ++#define VIRTINFO_EXECMMAP 9 ++#define VIRTINFO_OUTOFMEM 10 ++#define VIRTINFO_PAGEIN 11 ++#define VIRTINFO_SYSINFO 12 ++#define VIRTINFO_NEWUBC 13 ++#define VIRTINFO_VMSTAT 14 ++ ++enum virt_info_types { ++ VITYPE_GENERAL, ++ VITYPE_FAUDIT, ++ VITYPE_QUOTA, ++ VITYPE_SCP, ++ ++ VIRT_TYPES ++}; ++ ++#ifdef CONFIG_VZ_GENCALLS ++ ++static inline int virtinfo_gencall(unsigned long n, void *data) ++{ ++ int r; ++ ++ r = virtinfo_notifier_call(VITYPE_GENERAL, n, data); ++ if (r & NOTIFY_FAIL) ++ return -ENOBUFS; ++ if (r & NOTIFY_OK) ++ return -ERESTARTNOINTR; ++ return 0; ++} ++ ++#else ++ ++#define virtinfo_gencall(n, data) 0 ++ ++#endif ++ ++#endif /* __LINUX_VIRTINFO_H */ +Index: kernel/include/linux/virtinfoscp.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/virtinfoscp.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,21 @@ ++#ifndef __VIRTINFO_SCP_H__ ++#define __VIRTINFO_SCP_H__ ++ ++/* ++ * Dump and restore operations are non-symmetric. ++ * With respect to finish/fail hooks, 2 dump hooks are called from ++ * different proc operations, but restore hooks are called from a single one. ++ */ ++#define VIRTINFO_SCP_COLLECT 0x10 ++#define VIRTINFO_SCP_DUMP 0x11 ++#define VIRTINFO_SCP_DMPFIN 0x12 ++#define VIRTINFO_SCP_RSTCHECK 0x13 ++#define VIRTINFO_SCP_RESTORE 0x14 ++#define VIRTINFO_SCP_RSTFAIL 0x15 ++ ++#define VIRTINFO_SCP_RSTTSK 0x20 ++#define VIRTINFO_SCP_RSTMM 0x21 ++ ++#define VIRTNOTIFY_CHANGE 0x100 ++ ++#endif /* __VIRTINFO_SCP_H__ */ +Index: kernel/include/linux/vmalloc.h +=================================================================== +--- kernel.orig/include/linux/vmalloc.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/vmalloc.h 2008-11-24 15:47:46.000000000 +0100 +@@ -22,6 +22,10 @@ + #define IOREMAP_MAX_ORDER (7 + PAGE_SHIFT) /* 128 pages */ + #endif + ++/* align size to 2^n page boundary */ ++#define POWER2_PAGE_ALIGN(size) \ ++ ((typeof(size))(1UL << (PAGE_SHIFT + get_order(size)))) ++ + struct vm_struct { + /* keep next,addr,size together to speedup lookups */ + struct vm_struct *next; +@@ -37,12 +41,16 @@ + * Highlevel APIs for driver use + */ + extern void *vmalloc(unsigned long size); ++extern void *ub_vmalloc(unsigned long size); + extern void *vmalloc_user(unsigned long size); + extern void *vmalloc_node(unsigned long size, int node); ++extern void *ub_vmalloc_node(unsigned long size, int node); + extern void *vmalloc_exec(unsigned long size); + extern void *vmalloc_32(unsigned long size); + extern void *vmalloc_32_user(unsigned long size); + extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot); ++extern void *vmalloc_best(unsigned long size); ++extern void *ub_vmalloc_best(unsigned long size); + extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, + pgprot_t prot); + extern void vfree(void *addr); +@@ -68,6 +76,9 @@ + extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags); + extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, + unsigned long start, unsigned long end); ++extern struct vm_struct * get_vm_area_best(unsigned long size, ++ unsigned long flags); ++extern void vprintstat(void); + extern struct vm_struct *get_vm_area_node(unsigned long size, + unsigned long flags, int node, + gfp_t gfp_mask); +Index: kernel/include/linux/vmstat.h +=================================================================== +--- kernel.orig/include/linux/vmstat.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/linux/vmstat.h 2008-11-24 15:47:46.000000000 +0100 +@@ -79,6 +79,7 @@ + put_cpu(); + } + ++extern unsigned long vm_events(enum vm_event_item i); + extern void all_vm_events(unsigned long *); + #ifdef CONFIG_HOTPLUG + extern void vm_events_fold_cpu(int cpu); +Index: kernel/include/linux/vzcalluser.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/vzcalluser.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,242 @@ ++/* ++ * include/linux/vzcalluser.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef _LINUX_VZCALLUSER_H ++#define _LINUX_VZCALLUSER_H ++ ++#include ++#include ++ ++#define KERN_VZ_PRIV_RANGE 51 ++ ++#ifndef __ENVID_T_DEFINED__ ++typedef unsigned envid_t; ++#define __ENVID_T_DEFINED__ ++#endif ++ ++#ifndef __KERNEL__ ++#define __user ++#endif ++ ++/* ++ * VE management ioctls ++ */ ++ ++struct vzctl_old_env_create { ++ envid_t veid; ++ unsigned flags; ++#define VE_CREATE 1 /* Create VE, VE_ENTER added automatically */ ++#define VE_EXCLUSIVE 2 /* Fail if exists */ ++#define VE_ENTER 4 /* Enter existing VE */ ++#define VE_TEST 8 /* Test if VE exists */ ++#define VE_LOCK 16 /* Do not allow entering created VE */ ++#define VE_SKIPLOCK 32 /* Allow entering embrion VE */ ++ __u32 addr; ++}; ++ ++struct vzctl_mark_env_to_down { ++ envid_t veid; ++}; ++ ++struct vzctl_setdevperms { ++ envid_t veid; ++ unsigned type; ++#define VE_USE_MAJOR 010 /* Test MAJOR supplied in rule */ ++#define VE_USE_MINOR 030 /* Test MINOR supplied in rule */ ++#define VE_USE_MASK 030 /* Testing mask, VE_USE_MAJOR|VE_USE_MINOR */ ++ unsigned dev; ++ unsigned mask; ++}; ++ ++struct vzctl_ve_netdev { ++ envid_t veid; ++ int op; ++#define VE_NETDEV_ADD 1 ++#define VE_NETDEV_DEL 2 ++ char __user *dev_name; ++}; ++ ++struct vzctl_ve_meminfo { ++ envid_t veid; ++ unsigned long val; ++}; ++ ++/* these masks represent modules */ ++#define VE_IP_IPTABLES_MOD (1U<<0) ++#define VE_IP_FILTER_MOD (1U<<1) ++#define VE_IP_MANGLE_MOD (1U<<2) ++#define VE_IP_CONNTRACK_MOD (1U<<14) ++#define VE_IP_CONNTRACK_FTP_MOD (1U<<15) ++#define VE_IP_CONNTRACK_IRC_MOD (1U<<16) ++#define VE_IP_NAT_MOD (1U<<20) ++#define VE_IP_NAT_FTP_MOD (1U<<21) ++#define VE_IP_NAT_IRC_MOD (1U<<22) ++#define VE_IP_IPTABLES6_MOD (1U<<26) ++#define VE_IP_FILTER6_MOD (1U<<27) ++#define VE_IP_MANGLE6_MOD (1U<<28) ++#define VE_IP_IPTABLE_NAT_MOD (1U<<29) ++#define VE_NF_CONNTRACK_MOD (1U<<30) ++ ++/* these masks represent modules with their dependences */ ++#define VE_IP_IPTABLES (VE_IP_IPTABLES_MOD) ++#define VE_IP_FILTER (VE_IP_FILTER_MOD \ ++ | VE_IP_IPTABLES) ++#define VE_IP_MANGLE (VE_IP_MANGLE_MOD \ ++ | VE_IP_IPTABLES) ++#define VE_IP_IPTABLES6 (VE_IP_IPTABLES6_MOD) ++#define VE_IP_FILTER6 (VE_IP_FILTER6_MOD | VE_IP_IPTABLES6) ++#define VE_IP_MANGLE6 (VE_IP_MANGLE6_MOD | VE_IP_IPTABLES6) ++#define VE_NF_CONNTRACK (VE_NF_CONNTRACK_MOD | VE_IP_IPTABLES) ++#define VE_IP_CONNTRACK (VE_IP_CONNTRACK_MOD \ ++ | VE_IP_IPTABLES) ++#define VE_IP_CONNTRACK_FTP (VE_IP_CONNTRACK_FTP_MOD \ ++ | VE_IP_CONNTRACK) ++#define VE_IP_CONNTRACK_IRC (VE_IP_CONNTRACK_IRC_MOD \ ++ | VE_IP_CONNTRACK) ++#define VE_IP_NAT (VE_IP_NAT_MOD \ ++ | VE_IP_CONNTRACK) ++#define VE_IP_NAT_FTP (VE_IP_NAT_FTP_MOD \ ++ | VE_IP_NAT | VE_IP_CONNTRACK_FTP) ++#define VE_IP_NAT_IRC (VE_IP_NAT_IRC_MOD \ ++ | VE_IP_NAT | VE_IP_CONNTRACK_IRC) ++#define VE_IP_IPTABLE_NAT (VE_IP_IPTABLE_NAT_MOD | VE_IP_CONNTRACK) ++ ++/* safe iptables mask to be used by default */ ++#define VE_IP_DEFAULT \ ++ (VE_IP_IPTABLES | \ ++ VE_IP_FILTER | VE_IP_MANGLE) ++ ++#define VE_IPT_CMP(x,y) (((x) & (y)) == (y)) ++ ++struct vzctl_env_create_cid { ++ envid_t veid; ++ unsigned flags; ++ __u32 class_id; ++}; ++ ++struct vzctl_env_create { ++ envid_t veid; ++ unsigned flags; ++ __u32 class_id; ++}; ++ ++struct env_create_param { ++ __u64 iptables_mask; ++}; ++ ++#define VZCTL_ENV_CREATE_DATA_MINLEN sizeof(struct env_create_param) ++ ++struct env_create_param2 { ++ __u64 iptables_mask; ++ __u64 feature_mask; ++ __u32 total_vcpus; /* 0 - don't care, same as in host */ ++}; ++ ++struct env_create_param3 { ++ __u64 iptables_mask; ++ __u64 feature_mask; ++ __u32 total_vcpus; ++ __u32 pad; ++ __u64 known_features; ++}; ++ ++#define VE_FEATURE_SYSFS (1ULL << 0) ++#define VE_FEATURE_NFS (1ULL << 1) ++#define VE_FEATURE_DEF_PERMS (1ULL << 2) ++ ++#define VE_FEATURES_OLD (VE_FEATURE_SYSFS) ++#define VE_FEATURES_DEF (VE_FEATURE_SYSFS | \ ++ VE_FEATURE_DEF_PERMS) ++ ++typedef struct env_create_param3 env_create_param_t; ++#define VZCTL_ENV_CREATE_DATA_MAXLEN sizeof(env_create_param_t) ++ ++struct vzctl_env_create_data { ++ envid_t veid; ++ unsigned flags; ++ __u32 class_id; ++ env_create_param_t __user *data; ++ int datalen; ++}; ++ ++struct vz_load_avg { ++ int val_int; ++ int val_frac; ++}; ++ ++struct vz_cpu_stat { ++ unsigned long user_jif; ++ unsigned long nice_jif; ++ unsigned long system_jif; ++ unsigned long uptime_jif; ++ __u64 idle_clk; ++ __u64 strv_clk; ++ __u64 uptime_clk; ++ struct vz_load_avg avenrun[3]; /* loadavg data */ ++}; ++ ++struct vzctl_cpustatctl { ++ envid_t veid; ++ struct vz_cpu_stat __user *cpustat; ++}; ++ ++#define VZCTLTYPE '.' ++#define VZCTL_OLD_ENV_CREATE _IOW(VZCTLTYPE, 0, \ ++ struct vzctl_old_env_create) ++#define VZCTL_MARK_ENV_TO_DOWN _IOW(VZCTLTYPE, 1, \ ++ struct vzctl_mark_env_to_down) ++#define VZCTL_SETDEVPERMS _IOW(VZCTLTYPE, 2, \ ++ struct vzctl_setdevperms) ++#define VZCTL_ENV_CREATE_CID _IOW(VZCTLTYPE, 4, \ ++ struct vzctl_env_create_cid) ++#define VZCTL_ENV_CREATE _IOW(VZCTLTYPE, 5, \ ++ struct vzctl_env_create) ++#define VZCTL_GET_CPU_STAT _IOW(VZCTLTYPE, 6, \ ++ struct vzctl_cpustatctl) ++#define VZCTL_ENV_CREATE_DATA _IOW(VZCTLTYPE, 10, \ ++ struct vzctl_env_create_data) ++#define VZCTL_VE_NETDEV _IOW(VZCTLTYPE, 11, \ ++ struct vzctl_ve_netdev) ++#define VZCTL_VE_MEMINFO _IOW(VZCTLTYPE, 13, \ ++ struct vzctl_ve_meminfo) ++ ++#ifdef __KERNEL__ ++#ifdef CONFIG_COMPAT ++#include ++ ++struct compat_vzctl_ve_netdev { ++ envid_t veid; ++ int op; ++ compat_uptr_t dev_name; ++}; ++ ++struct compat_vzctl_ve_meminfo { ++ envid_t veid; ++ compat_ulong_t val; ++}; ++ ++struct compat_vzctl_env_create_data { ++ envid_t veid; ++ unsigned flags; ++ __u32 class_id; ++ compat_uptr_t data; ++ int datalen; ++}; ++ ++#define VZCTL_COMPAT_ENV_CREATE_DATA _IOW(VZCTLTYPE, 10, \ ++ struct compat_vzctl_env_create_data) ++#define VZCTL_COMPAT_VE_NETDEV _IOW(VZCTLTYPE, 11, \ ++ struct compat_vzctl_ve_netdev) ++#define VZCTL_COMPAT_VE_MEMINFO _IOW(VZCTLTYPE, 13, \ ++ struct compat_vzctl_ve_meminfo) ++#endif ++#endif ++ ++#endif +Index: kernel/include/linux/vzctl.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/vzctl.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,30 @@ ++/* ++ * include/linux/vzctl.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef _LINUX_VZCTL_H ++#define _LINUX_VZCTL_H ++ ++#include ++ ++struct module; ++struct inode; ++struct file; ++struct vzioctlinfo { ++ unsigned type; ++ int (*ioctl)(struct file *, unsigned int, unsigned long); ++ int (*compat_ioctl)(struct file *, unsigned int, unsigned long); ++ struct module *owner; ++ struct list_head list; ++}; ++ ++extern void vzioctl_register(struct vzioctlinfo *inf); ++extern void vzioctl_unregister(struct vzioctlinfo *inf); ++ ++#endif +Index: kernel/include/linux/vzctl_quota.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/vzctl_quota.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,74 @@ ++/* ++ * include/linux/vzctl_quota.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __LINUX_VZCTL_QUOTA_H__ ++#define __LINUX_VZCTL_QUOTA_H__ ++ ++#include ++ ++#ifndef __KERNEL__ ++#define __user ++#endif ++ ++/* ++ * Quota management ioctl ++ */ ++ ++struct vz_quota_stat; ++struct vzctl_quotactl { ++ int cmd; ++ unsigned int quota_id; ++ struct vz_quota_stat __user *qstat; ++ char __user *ve_root; ++}; ++ ++struct vzctl_quotaugidctl { ++ int cmd; /* subcommand */ ++ unsigned int quota_id; /* quota id where it applies to */ ++ unsigned int ugid_index;/* for reading statistic. index of first ++ uid/gid record to read */ ++ unsigned int ugid_size; /* size of ugid_buf array */ ++ void *addr; /* user-level buffer */ ++}; ++ ++#define VZDQCTLTYPE '+' ++#define VZCTL_QUOTA_DEPR_CTL _IOWR(VZDQCTLTYPE, 1, \ ++ struct vzctl_quotactl) ++#define VZCTL_QUOTA_NEW_CTL _IOWR(VZDQCTLTYPE, 2, \ ++ struct vzctl_quotactl) ++#define VZCTL_QUOTA_UGID_CTL _IOWR(VZDQCTLTYPE, 3, \ ++ struct vzctl_quotaugidctl) ++ ++#ifdef __KERNEL__ ++#ifdef CONFIG_COMPAT ++struct compat_vzctl_quotactl { ++ int cmd; ++ unsigned int quota_id; ++ compat_uptr_t qstat; ++ compat_uptr_t ve_root; ++}; ++ ++struct compat_vzctl_quotaugidctl { ++ int cmd; /* subcommand */ ++ unsigned int quota_id; /* quota id where it applies to */ ++ unsigned int ugid_index;/* for reading statistic. index of first ++ uid/gid record to read */ ++ unsigned int ugid_size; /* size of ugid_buf array */ ++ compat_uptr_t addr; /* user-level buffer */ ++}; ++ ++#define VZCTL_COMPAT_QUOTA_CTL _IOWR(VZDQCTLTYPE, 2, \ ++ struct compat_vzctl_quotactl) ++#define VZCTL_COMPAT_QUOTA_UGID_CTL _IOWR(VZDQCTLTYPE, 3, \ ++ struct compat_vzctl_quotaugidctl) ++#endif ++#endif ++ ++#endif /* __LINUX_VZCTL_QUOTA_H__ */ +Index: kernel/include/linux/vzctl_venet.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/vzctl_venet.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,51 @@ ++/* ++ * include/linux/vzctl_venet.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef _VZCTL_VENET_H ++#define _VZCTL_VENET_H ++ ++#include ++#include ++#include ++ ++#ifndef __ENVID_T_DEFINED__ ++typedef unsigned envid_t; ++#define __ENVID_T_DEFINED__ ++#endif ++ ++struct vzctl_ve_ip_map { ++ envid_t veid; ++ int op; ++#define VE_IP_ADD 1 ++#define VE_IP_DEL 2 ++ struct sockaddr *addr; ++ int addrlen; ++}; ++ ++#define VENETCTLTYPE '(' ++ ++#define VENETCTL_VE_IP_MAP _IOW(VENETCTLTYPE, 3, \ ++ struct vzctl_ve_ip_map) ++ ++#ifdef __KERNEL__ ++#ifdef CONFIG_COMPAT ++struct compat_vzctl_ve_ip_map { ++ envid_t veid; ++ int op; ++ compat_uptr_t addr; ++ int addrlen; ++}; ++ ++#define VENETCTL_COMPAT_VE_IP_MAP _IOW(VENETCTLTYPE, 3, \ ++ struct compat_vzctl_ve_ip_map) ++#endif ++#endif ++ ++#endif +Index: kernel/include/linux/vzctl_veth.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/vzctl_veth.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,42 @@ ++/* ++ * include/linux/vzctl_veth.h ++ * ++ * Copyright (C) 2006 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef _VZCTL_VETH_H ++#define _VZCTL_VETH_H ++ ++#include ++#include ++ ++#ifndef __ENVID_T_DEFINED__ ++typedef unsigned envid_t; ++#define __ENVID_T_DEFINED__ ++#endif ++ ++struct vzctl_ve_hwaddr { ++ envid_t veid; ++ int op; ++#define VE_ETH_ADD 1 ++#define VE_ETH_DEL 2 ++#define VE_ETH_ALLOW_MAC_CHANGE 3 ++#define VE_ETH_DENY_MAC_CHANGE 4 ++ unsigned char dev_addr[6]; ++ int addrlen; ++ char dev_name[16]; ++ unsigned char dev_addr_ve[6]; ++ int addrlen_ve; ++ char dev_name_ve[16]; ++}; ++ ++#define VETHCTLTYPE '[' ++ ++#define VETHCTL_VE_HWADDR _IOW(VETHCTLTYPE, 3, \ ++ struct vzctl_ve_hwaddr) ++ ++#endif +Index: kernel/include/linux/vzdq_tree.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/vzdq_tree.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,99 @@ ++/* ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * This file contains Virtuozzo disk quota tree definition ++ */ ++ ++#ifndef _VZDQ_TREE_H ++#define _VZDQ_TREE_H ++ ++#include ++#include ++ ++typedef unsigned int quotaid_t; ++#define QUOTAID_BITS 32 ++#define QUOTAID_BBITS 4 ++#define QUOTAID_EBITS 8 ++ ++#if QUOTAID_EBITS % QUOTAID_BBITS ++#error Quota bit assumption failure ++#endif ++ ++#define QUOTATREE_BSIZE (1 << QUOTAID_BBITS) ++#define QUOTATREE_BMASK (QUOTATREE_BSIZE - 1) ++#define QUOTATREE_DEPTH ((QUOTAID_BITS + QUOTAID_BBITS - 1) \ ++ / QUOTAID_BBITS) ++#define QUOTATREE_EDEPTH ((QUOTAID_BITS + QUOTAID_EBITS - 1) \ ++ / QUOTAID_EBITS) ++#define QUOTATREE_BSHIFT(lvl) ((QUOTATREE_DEPTH - (lvl) - 1) * QUOTAID_BBITS) ++ ++/* ++ * Depth of keeping unused node (not inclusive). ++ * 0 means release all nodes including root, ++ * QUOTATREE_DEPTH means never release nodes. ++ * Current value: release all nodes strictly after QUOTATREE_EDEPTH ++ * (measured in external shift units). ++ */ ++#define QUOTATREE_CDEPTH (QUOTATREE_DEPTH \ ++ - 2 * QUOTATREE_DEPTH / QUOTATREE_EDEPTH \ ++ + 1) ++ ++/* ++ * Levels 0..(QUOTATREE_DEPTH-1) are tree nodes. ++ * On level i the maximal number of nodes is 2^(i*QUOTAID_BBITS), ++ * and each node contains 2^QUOTAID_BBITS pointers. ++ * Level 0 is a (single) tree root node. ++ * ++ * Nodes of level (QUOTATREE_DEPTH-1) contain pointers to caller's data. ++ * Nodes of lower levels contain pointers to nodes. ++ * ++ * Double pointer in array of i-level node, pointing to a (i+1)-level node ++ * (such as inside quotatree_find_state) are marked by level (i+1), not i. ++ * Level 0 double pointer is a pointer to root inside tree struct. ++ * ++ * The tree is permanent, i.e. all index blocks allocated are keeped alive to ++ * preserve the blocks numbers in the quota file tree to keep its changes ++ * locally. ++ */ ++struct quotatree_node { ++ struct list_head list; ++ quotaid_t num; ++ void *blocks[QUOTATREE_BSIZE]; ++}; ++ ++struct quotatree_level { ++ struct list_head usedlh, freelh; ++ quotaid_t freenum; ++}; ++ ++struct quotatree_tree { ++ struct quotatree_level levels[QUOTATREE_DEPTH]; ++ struct quotatree_node *root; ++ unsigned int leaf_num; ++}; ++ ++struct quotatree_find_state { ++ void **block; ++ int level; ++}; ++ ++/* number of leafs (objects) and leaf level of the tree */ ++#define QTREE_LEAFNUM(tree) ((tree)->leaf_num) ++#define QTREE_LEAFLVL(tree) (&(tree)->levels[QUOTATREE_DEPTH - 1]) ++ ++struct quotatree_tree *quotatree_alloc(void); ++void *quotatree_find(struct quotatree_tree *tree, quotaid_t id, ++ struct quotatree_find_state *st); ++int quotatree_insert(struct quotatree_tree *tree, quotaid_t id, ++ struct quotatree_find_state *st, void *data); ++void quotatree_remove(struct quotatree_tree *tree, quotaid_t id); ++void quotatree_free(struct quotatree_tree *tree, void (*dtor)(void *)); ++void *quotatree_get_next(struct quotatree_tree *tree, quotaid_t id); ++void *quotatree_leaf_byindex(struct quotatree_tree *tree, unsigned int index); ++ ++#endif /* _VZDQ_TREE_H */ ++ +Index: kernel/include/linux/vzevent.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/vzevent.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,13 @@ ++#ifndef __LINUX_VZ_EVENT_H__ ++#define __LINUX_VZ_EVENT_H__ ++ ++#if defined(CONFIG_VZ_EVENT) || defined(CONFIG_VZ_EVENT_MODULE) ++extern int vzevent_send(int msg, const char *attrs_fmt, ...); ++#else ++static inline int vzevent_send(int msg, const char *attrs_fmt, ...) ++{ ++ return 0; ++} ++#endif ++ ++#endif /* __LINUX_VZ_EVENT_H__ */ +Index: kernel/include/linux/vzquota.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/vzquota.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,380 @@ ++/* ++ * ++ * Copyright (C) 2001-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * This file contains Virtuozzo disk quota implementation ++ */ ++ ++#ifndef _VZDQUOTA_H ++#define _VZDQUOTA_H ++ ++#include ++#include ++ ++/* vzquotactl syscall commands */ ++#define VZ_DQ_CREATE 5 /* create quota master block */ ++#define VZ_DQ_DESTROY 6 /* destroy qmblk */ ++#define VZ_DQ_ON 7 /* mark dentry with already created qmblk */ ++#define VZ_DQ_OFF 8 /* remove mark, don't destroy qmblk */ ++#define VZ_DQ_SETLIMIT 9 /* set new limits */ ++#define VZ_DQ_GETSTAT 10 /* get usage statistic */ ++#define VZ_DQ_OFF_FORCED 11 /* forced off */ ++/* set of syscalls to maintain UGID quotas */ ++#define VZ_DQ_UGID_GETSTAT 1 /* get usage/limits for ugid(s) */ ++#define VZ_DQ_UGID_ADDSTAT 2 /* set usage/limits statistic for ugid(s) */ ++#define VZ_DQ_UGID_GETGRACE 3 /* get expire times */ ++#define VZ_DQ_UGID_SETGRACE 4 /* set expire times */ ++#define VZ_DQ_UGID_GETCONFIG 5 /* get ugid_max limit, cnt, flags of qmblk */ ++#define VZ_DQ_UGID_SETCONFIG 6 /* set ugid_max limit, flags of qmblk */ ++#define VZ_DQ_UGID_SETLIMIT 7 /* set ugid B/I limits */ ++#define VZ_DQ_UGID_SETINFO 8 /* set ugid info */ ++ ++/* common structure for vz and ugid quota */ ++struct dq_stat { ++ /* blocks limits */ ++ __u64 bhardlimit; /* absolute limit in bytes */ ++ __u64 bsoftlimit; /* preferred limit in bytes */ ++ time_t btime; /* time limit for excessive disk use */ ++ __u64 bcurrent; /* current bytes count */ ++ /* inodes limits */ ++ __u32 ihardlimit; /* absolute limit on allocated inodes */ ++ __u32 isoftlimit; /* preferred inode limit */ ++ time_t itime; /* time limit for excessive inode use */ ++ __u32 icurrent; /* current # allocated inodes */ ++}; ++ ++/* One second resolution for grace times */ ++#define CURRENT_TIME_SECONDS (get_seconds()) ++ ++/* Values for dq_info->flags */ ++#define VZ_QUOTA_INODES 0x01 /* inodes limit warning printed */ ++#define VZ_QUOTA_SPACE 0x02 /* space limit warning printed */ ++ ++struct dq_info { ++ time_t bexpire; /* expire timeout for excessive disk use */ ++ time_t iexpire; /* expire timeout for excessive inode use */ ++ unsigned flags; /* see previos defines */ ++}; ++ ++struct vz_quota_stat { ++ struct dq_stat dq_stat; ++ struct dq_info dq_info; ++}; ++ ++/* UID/GID interface record - for user-kernel level exchange */ ++struct vz_quota_iface { ++ unsigned int qi_id; /* UID/GID this applies to */ ++ unsigned int qi_type; /* USRQUOTA|GRPQUOTA */ ++ struct dq_stat qi_stat; /* limits, options, usage stats */ ++}; ++ ++#ifdef CONFIG_COMPAT ++#include ++struct compat_dq_stat { ++ /* blocks limits */ ++ __u64 bhardlimit; /* absolute limit in bytes */ ++ __u64 bsoftlimit; /* preferred limit in bytes */ ++ compat_time_t btime; /* time limit for excessive disk use */ ++ __u64 bcurrent; /* current bytes count */ ++ /* inodes limits */ ++ __u32 ihardlimit; /* absolute limit on allocated inodes */ ++ __u32 isoftlimit; /* preferred inode limit */ ++ compat_time_t itime; /* time limit for excessive inode use */ ++ __u32 icurrent; /* current # allocated inodes */ ++}; ++ ++struct compat_dq_info { ++ compat_time_t bexpire; /* expire timeout for excessive disk use */ ++ compat_time_t iexpire; /* expire timeout for excessive inode use */ ++ unsigned flags; /* see previos defines */ ++}; ++ ++struct compat_vz_quota_stat { ++ struct compat_dq_stat dq_stat; ++ struct compat_dq_info dq_info; ++}; ++ ++struct compat_vz_quota_iface { ++ unsigned int qi_id; /* UID/GID this applies to */ ++ unsigned int qi_type; /* USRQUOTA|GRPQUOTA */ ++ struct compat_dq_stat qi_stat; /* limits, options, usage stats */ ++}; ++ ++static inline void compat_dqstat2dqstat(struct compat_dq_stat *odqs, ++ struct dq_stat *dqs) ++{ ++ dqs->bhardlimit = odqs->bhardlimit; ++ dqs->bsoftlimit = odqs->bsoftlimit; ++ dqs->bcurrent = odqs->bcurrent; ++ dqs->btime = odqs->btime; ++ ++ dqs->ihardlimit = odqs->ihardlimit; ++ dqs->isoftlimit = odqs->isoftlimit; ++ dqs->icurrent = odqs->icurrent; ++ dqs->itime = odqs->itime; ++} ++ ++static inline void compat_dqinfo2dqinfo(struct compat_dq_info *odqi, ++ struct dq_info *dqi) ++{ ++ dqi->bexpire = odqi->bexpire; ++ dqi->iexpire = odqi->iexpire; ++ dqi->flags = odqi->flags; ++} ++ ++static inline void dqstat2compat_dqstat(struct dq_stat *dqs, ++ struct compat_dq_stat *odqs) ++{ ++ odqs->bhardlimit = dqs->bhardlimit; ++ odqs->bsoftlimit = dqs->bsoftlimit; ++ odqs->bcurrent = dqs->bcurrent; ++ odqs->btime = (compat_time_t)dqs->btime; ++ ++ odqs->ihardlimit = dqs->ihardlimit; ++ odqs->isoftlimit = dqs->isoftlimit; ++ odqs->icurrent = dqs->icurrent; ++ odqs->itime = (compat_time_t)dqs->itime; ++} ++ ++static inline void dqinfo2compat_dqinfo(struct dq_info *dqi, ++ struct compat_dq_info *odqi) ++{ ++ odqi->bexpire = (compat_time_t)dqi->bexpire; ++ odqi->iexpire = (compat_time_t)dqi->iexpire; ++ odqi->flags = dqi->flags; ++} ++#endif ++ ++/* values for flags and dq_flags */ ++/* this flag is set if the userspace has been unable to provide usage ++ * information about all ugids ++ * if the flag is set, we don't allocate new UG quota blocks (their ++ * current usage is unknown) or free existing UG quota blocks (not to ++ * lose information that this block is ok) */ ++#define VZDQUG_FIXED_SET 0x01 ++/* permit to use ugid quota */ ++#define VZDQUG_ON 0x02 ++#define VZDQ_USRQUOTA 0x10 ++#define VZDQ_GRPQUOTA 0x20 ++#define VZDQ_NOACT 0x1000 /* not actual */ ++#define VZDQ_NOQUOT 0x2000 /* not under quota tree */ ++ ++struct vz_quota_ugid_stat { ++ unsigned int limit; /* max amount of ugid records */ ++ unsigned int count; /* amount of ugid records */ ++ unsigned int flags; ++}; ++ ++struct vz_quota_ugid_setlimit { ++ unsigned int type; /* quota type (USR/GRP) */ ++ unsigned int id; /* ugid */ ++ struct if_dqblk dqb; /* limits info */ ++}; ++ ++struct vz_quota_ugid_setinfo { ++ unsigned int type; /* quota type (USR/GRP) */ ++ struct if_dqinfo dqi; /* grace info */ ++}; ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Values for dq_info flags */ ++#define VZ_QUOTA_INODES 0x01 /* inodes limit warning printed */ ++#define VZ_QUOTA_SPACE 0x02 /* space limit warning printed */ ++ ++/* values for dq_state */ ++#define VZDQ_STARTING 0 /* created, not turned on yet */ ++#define VZDQ_WORKING 1 /* quota created, turned on */ ++#define VZDQ_STOPING 2 /* created, turned on and off */ ++ ++/* master quota record - one per veid */ ++struct vz_quota_master { ++ struct list_head dq_hash; /* next quota in hash list */ ++ atomic_t dq_count; /* inode reference count */ ++ unsigned int dq_flags; /* see VZDQUG_FIXED_SET */ ++ unsigned int dq_state; /* see values above */ ++ unsigned int dq_id; /* VEID this applies to */ ++ struct dq_stat dq_stat; /* limits, grace, usage stats */ ++ struct dq_info dq_info; /* grace times and flags */ ++ spinlock_t dq_data_lock; /* for dq_stat */ ++ ++ struct semaphore dq_sem; /* semaphore to protect ++ ugid tree */ ++ ++ struct list_head dq_ilink_list; /* list of vz_quota_ilink */ ++ struct quotatree_tree *dq_uid_tree; /* vz_quota_ugid tree for UIDs */ ++ struct quotatree_tree *dq_gid_tree; /* vz_quota_ugid tree for GIDs */ ++ unsigned int dq_ugid_count; /* amount of ugid records */ ++ unsigned int dq_ugid_max; /* max amount of ugid records */ ++ struct dq_info dq_ugid_info[MAXQUOTAS]; /* ugid grace times */ ++ ++ struct dentry *dq_root_dentry;/* dentry of fs tree */ ++ struct vfsmount *dq_root_mnt; /* vfsmnt of this dentry */ ++ struct super_block *dq_sb; /* superblock of our quota root */ ++}; ++ ++/* UID/GID quota record - one per pair (quota_master, uid or gid) */ ++struct vz_quota_ugid { ++ unsigned int qugid_id; /* UID/GID this applies to */ ++ struct dq_stat qugid_stat; /* limits, options, usage stats */ ++ int qugid_type; /* USRQUOTA|GRPQUOTA */ ++ atomic_t qugid_count; /* reference count */ ++}; ++ ++#define VZ_QUOTA_UGBAD ((struct vz_quota_ugid *)0xfeafea11) ++ ++struct vz_quota_datast { ++ struct vz_quota_ilink qlnk; ++}; ++ ++#define VIRTINFO_QUOTA_GETSTAT 0 ++#define VIRTINFO_QUOTA_ON 1 ++#define VIRTINFO_QUOTA_OFF 2 ++#define VIRTINFO_QUOTA_DISABLE 3 ++ ++struct virt_info_quota { ++ struct super_block *super; ++ struct dq_stat *qstat; ++}; ++ ++/* ++ * Interface to VZ quota core ++ */ ++#define INODE_QLNK(inode) (&(inode)->i_qlnk) ++#define QLNK_INODE(qlnk) container_of((qlnk), struct inode, i_qlnk) ++ ++#define VZ_QUOTA_BAD ((struct vz_quota_master *)0xefefefef) ++ ++#define VZ_QUOTAO_SETE 1 ++#define VZ_QUOTAO_INIT 2 ++#define VZ_QUOTAO_DESTR 3 ++#define VZ_QUOTAO_SWAP 4 ++#define VZ_QUOTAO_INICAL 5 ++#define VZ_QUOTAO_DRCAL 6 ++#define VZ_QUOTAO_QSET 7 ++#define VZ_QUOTAO_TRANS 8 ++#define VZ_QUOTAO_ACT 9 ++#define VZ_QUOTAO_DTREE 10 ++#define VZ_QUOTAO_DET 11 ++#define VZ_QUOTAO_ON 12 ++#define VZ_QUOTAO_RE_LOCK 13 ++ ++#define DQUOT_CMD_ALLOC 0 ++#define DQUOT_CMD_PREALLOC 1 ++#define DQUOT_CMD_CHECK 12 ++#define DQUOT_CMD_FORCE 13 ++ ++extern struct semaphore vz_quota_sem; ++void inode_qmblk_lock(struct super_block *sb); ++void inode_qmblk_unlock(struct super_block *sb); ++void qmblk_data_read_lock(struct vz_quota_master *qmblk); ++void qmblk_data_read_unlock(struct vz_quota_master *qmblk); ++void qmblk_data_write_lock(struct vz_quota_master *qmblk); ++void qmblk_data_write_unlock(struct vz_quota_master *qmblk); ++ ++/* for quota operations */ ++void vzquota_inode_init_call(struct inode *inode); ++void vzquota_inode_drop_call(struct inode *inode); ++int vzquota_inode_transfer_call(struct inode *, struct iattr *); ++struct vz_quota_master *vzquota_inode_data(struct inode *inode, ++ struct vz_quota_datast *); ++void vzquota_data_unlock(struct inode *inode, struct vz_quota_datast *); ++int vzquota_rename_check(struct inode *inode, ++ struct inode *old_dir, struct inode *new_dir); ++struct vz_quota_master *vzquota_inode_qmblk(struct inode *inode); ++/* for second-level quota */ ++struct vz_quota_master *vzquota_find_qmblk(struct super_block *); ++/* for management operations */ ++struct vz_quota_master *vzquota_alloc_master(unsigned int quota_id, ++ struct vz_quota_stat *qstat); ++void vzquota_free_master(struct vz_quota_master *); ++struct vz_quota_master *vzquota_find_master(unsigned int quota_id); ++int vzquota_on_qmblk(struct super_block *sb, struct inode *inode, ++ struct vz_quota_master *qmblk, char __user *buf); ++int vzquota_off_qmblk(struct super_block *sb, struct vz_quota_master *qmblk, ++ char __user *buf, int force); ++int vzquota_get_super(struct super_block *sb); ++void vzquota_put_super(struct super_block *sb); ++ ++static inline struct vz_quota_master *qmblk_get(struct vz_quota_master *qmblk) ++{ ++ if (!atomic_read(&qmblk->dq_count)) ++ BUG(); ++ atomic_inc(&qmblk->dq_count); ++ return qmblk; ++} ++ ++static inline void __qmblk_put(struct vz_quota_master *qmblk) ++{ ++ atomic_dec(&qmblk->dq_count); ++} ++ ++static inline void qmblk_put(struct vz_quota_master *qmblk) ++{ ++ if (!atomic_dec_and_test(&qmblk->dq_count)) ++ return; ++ vzquota_free_master(qmblk); ++} ++ ++extern struct list_head vzquota_hash_table[]; ++extern int vzquota_hash_size; ++ ++/* ++ * Interface to VZ UGID quota ++ */ ++extern struct quotactl_ops vz_quotactl_operations; ++extern struct dquot_operations vz_quota_operations2; ++extern struct quota_format_type vz_quota_empty_v2_format; ++ ++#define QUGID_TREE(qmblk, type) (((type) == USRQUOTA) ? \ ++ qmblk->dq_uid_tree : \ ++ qmblk->dq_gid_tree) ++ ++#define VZDQUG_FIND_DONT_ALLOC 1 ++#define VZDQUG_FIND_FAKE 2 ++struct vz_quota_ugid *vzquota_find_ugid(struct vz_quota_master *qmblk, ++ unsigned int quota_id, int type, int flags); ++struct vz_quota_ugid *__vzquota_find_ugid(struct vz_quota_master *qmblk, ++ unsigned int quota_id, int type, int flags); ++struct vz_quota_ugid *vzquota_get_ugid(struct vz_quota_ugid *qugid); ++void vzquota_put_ugid(struct vz_quota_master *qmblk, ++ struct vz_quota_ugid *qugid); ++void vzquota_kill_ugid(struct vz_quota_master *qmblk); ++int vzquota_ugid_init(void); ++void vzquota_ugid_release(void); ++int vzquota_transfer_usage(struct inode *inode, int mask, ++ struct vz_quota_ilink *qlnk); ++void vzquota_inode_off(struct inode *inode); ++ ++long do_vzquotaugidctl(int cmd, unsigned int quota_id, ++ unsigned int ugid_index, unsigned int ugid_size, ++ void *addr, int compat); ++ ++/* ++ * Other VZ quota parts ++ */ ++extern struct dquot_operations vz_quota_operations; ++ ++long do_vzquotactl(int cmd, unsigned int quota_id, ++ struct vz_quota_stat __user *qstat, const char __user *ve_root, ++ int compat); ++int vzquota_proc_init(void); ++void vzquota_proc_release(void); ++struct vz_quota_master *vzquota_find_qmblk(struct super_block *); ++extern struct semaphore vz_quota_sem; ++ ++void vzaquota_init(void); ++void vzaquota_fini(void); ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _VZDQUOTA_H */ +Index: kernel/include/linux/vzquota_qlnk.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/vzquota_qlnk.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,25 @@ ++/* ++ * include/linux/vzquota_qlnk.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef _VZDQUOTA_QLNK_H ++#define _VZDQUOTA_QLNK_H ++ ++struct vz_quota_master; ++struct vz_quota_ugid; ++ ++/* inode link, used to track inodes using quota via dq_ilink_list */ ++struct vz_quota_ilink { ++ struct vz_quota_master *qmblk; ++ struct vz_quota_ugid *qugid[MAXQUOTAS]; ++ struct list_head list; ++ unsigned char origin[2]; ++}; ++ ++#endif /* _VZDQUOTA_QLNK_H */ +Index: kernel/include/linux/vzratelimit.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/vzratelimit.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,28 @@ ++/* ++ * include/linux/vzratelimit.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __VZ_RATELIMIT_H__ ++#define __VZ_RATELIMIT_H__ ++ ++/* ++ * Generic ratelimiting stuff. ++ */ ++ ++struct vz_rate_info { ++ int burst; ++ int interval; /* jiffy_t per event */ ++ int bucket; /* kind of leaky bucket */ ++ unsigned long last; /* last event */ ++}; ++ ++/* Return true if rate limit permits. */ ++int vz_ratelimit(struct vz_rate_info *p); ++ ++#endif /* __VZ_RATELIMIT_H__ */ +Index: kernel/include/linux/vzstat.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/vzstat.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,182 @@ ++/* ++ * include/linux/vzstat.h ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __VZSTAT_H__ ++#define __VZSTAT_H__ ++ ++struct swap_cache_info_struct { ++ unsigned long add_total; ++ unsigned long del_total; ++ unsigned long find_success; ++ unsigned long find_total; ++ unsigned long noent_race; ++ unsigned long exist_race; ++ unsigned long remove_race; ++}; ++ ++struct kstat_lat_snap_struct { ++ cycles_t maxlat, totlat; ++ unsigned long count; ++}; ++struct kstat_lat_pcpu_snap_struct { ++ cycles_t maxlat, totlat; ++ unsigned long count; ++ seqcount_t lock; ++} ____cacheline_aligned_in_smp; ++ ++struct kstat_lat_struct { ++ struct kstat_lat_snap_struct cur, last; ++ cycles_t avg[3]; ++}; ++struct kstat_lat_pcpu_struct { ++ struct kstat_lat_pcpu_snap_struct cur[NR_CPUS]; ++ cycles_t max_snap; ++ struct kstat_lat_snap_struct last; ++ cycles_t avg[3]; ++}; ++ ++struct kstat_perf_snap_struct { ++ cycles_t wall_tottime, cpu_tottime; ++ cycles_t wall_maxdur, cpu_maxdur; ++ unsigned long count; ++}; ++struct kstat_perf_struct { ++ struct kstat_perf_snap_struct cur, last; ++}; ++ ++struct kstat_zone_avg { ++ unsigned long free_pages_avg[3], ++ nr_active_avg[3], ++ nr_inactive_avg[3]; ++}; ++ ++#define KSTAT_ALLOCSTAT_NR 5 ++ ++struct kernel_stat_glob { ++ unsigned long nr_unint_avg[3]; ++ ++ unsigned long alloc_fails[KSTAT_ALLOCSTAT_NR]; ++ struct kstat_lat_struct alloc_lat[KSTAT_ALLOCSTAT_NR]; ++ struct kstat_lat_pcpu_struct sched_lat; ++ struct kstat_lat_struct swap_in; ++ ++ struct kstat_perf_struct ttfp, cache_reap, ++ refill_inact, shrink_icache, shrink_dcache; ++ ++ struct kstat_zone_avg zone_avg[3]; /* MAX_NR_ZONES */ ++} ____cacheline_aligned; ++ ++extern struct kernel_stat_glob kstat_glob ____cacheline_aligned; ++extern spinlock_t kstat_glb_lock; ++ ++#ifdef CONFIG_VE ++#define KSTAT_PERF_ENTER(name) \ ++ unsigned long flags; \ ++ cycles_t start, sleep_time; \ ++ \ ++ start = get_cycles(); \ ++ sleep_time = VE_TASK_INFO(current)->sleep_time; \ ++ ++#define KSTAT_PERF_LEAVE(name) \ ++ spin_lock_irqsave(&kstat_glb_lock, flags); \ ++ kstat_glob.name.cur.count++; \ ++ start = get_cycles() - start; \ ++ if (kstat_glob.name.cur.wall_maxdur < start) \ ++ kstat_glob.name.cur.wall_maxdur = start;\ ++ kstat_glob.name.cur.wall_tottime += start; \ ++ start -= VE_TASK_INFO(current)->sleep_time - \ ++ sleep_time; \ ++ if (kstat_glob.name.cur.cpu_maxdur < start) \ ++ kstat_glob.name.cur.cpu_maxdur = start; \ ++ kstat_glob.name.cur.cpu_tottime += start; \ ++ spin_unlock_irqrestore(&kstat_glb_lock, flags); \ ++ ++#else ++#define KSTAT_PERF_ENTER(name) ++#define KSTAT_PERF_LEAVE(name) ++#endif ++ ++/* ++ * Add another statistics reading. ++ * Serialization is the caller's due. ++ */ ++static inline void KSTAT_LAT_ADD(struct kstat_lat_struct *p, ++ cycles_t dur) ++{ ++ p->cur.count++; ++ if (p->cur.maxlat < dur) ++ p->cur.maxlat = dur; ++ p->cur.totlat += dur; ++} ++ ++static inline void KSTAT_LAT_PCPU_ADD(struct kstat_lat_pcpu_struct *p, int cpu, ++ cycles_t dur) ++{ ++ struct kstat_lat_pcpu_snap_struct *cur; ++ ++ cur = &p->cur[cpu]; ++ write_seqcount_begin(&cur->lock); ++ cur->count++; ++ if (cur->maxlat < dur) ++ cur->maxlat = dur; ++ cur->totlat += dur; ++ write_seqcount_end(&cur->lock); ++} ++ ++/* ++ * Move current statistics to last, clear last. ++ * Serialization is the caller's due. ++ */ ++static inline void KSTAT_LAT_UPDATE(struct kstat_lat_struct *p) ++{ ++ cycles_t m; ++ memcpy(&p->last, &p->cur, sizeof(p->last)); ++ p->cur.maxlat = 0; ++ m = p->last.maxlat; ++ CALC_LOAD(p->avg[0], EXP_1, m) ++ CALC_LOAD(p->avg[1], EXP_5, m) ++ CALC_LOAD(p->avg[2], EXP_15, m) ++} ++ ++static inline void KSTAT_LAT_PCPU_UPDATE(struct kstat_lat_pcpu_struct *p) ++{ ++ unsigned i, cpu; ++ struct kstat_lat_pcpu_snap_struct snap, *cur; ++ cycles_t m; ++ ++ memset(&p->last, 0, sizeof(p->last)); ++ for (cpu = 0; cpu < NR_CPUS; cpu++) { ++ cur = &p->cur[cpu]; ++ do { ++ i = read_seqcount_begin(&cur->lock); ++ memcpy(&snap, cur, sizeof(snap)); ++ } while (read_seqcount_retry(&cur->lock, i)); ++ /* ++ * read above and this update of maxlat is not atomic, ++ * but this is OK, since it happens rarely and losing ++ * a couple of peaks is not essential. xemul ++ */ ++ cur->maxlat = 0; ++ ++ p->last.count += snap.count; ++ p->last.totlat += snap.totlat; ++ if (p->last.maxlat < snap.maxlat) ++ p->last.maxlat = snap.maxlat; ++ } ++ ++ m = (p->last.maxlat > p->max_snap ? p->last.maxlat : p->max_snap); ++ CALC_LOAD(p->avg[0], EXP_1, m); ++ CALC_LOAD(p->avg[1], EXP_5, m); ++ CALC_LOAD(p->avg[2], EXP_15, m); ++ /* reset max_snap to calculate it correctly next time */ ++ p->max_snap = 0; ++} ++ ++#endif /* __VZSTAT_H__ */ +Index: kernel/include/net/addrconf.h +=================================================================== +--- kernel.orig/include/net/addrconf.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/addrconf.h 2008-11-24 15:47:46.000000000 +0100 +@@ -246,5 +246,19 @@ + extern void if6_proc_exit(void); + #endif + ++int addrconf_ifdown(struct net_device *dev, int how); ++int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, ++ __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft); ++ ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++int addrconf_sysctl_init(struct ve_struct *ve); ++void addrconf_sysctl_fini(struct ve_struct *ve); ++void addrconf_sysctl_free(struct ve_struct *ve); ++#else ++#define addrconf_sysctl_init(ve) (0) ++#define addrconf_sysctl_fini(ve) do { } while (0) ++#define addrconf_sysctl_free(ve) do { } while (0) ++#endif ++ + #endif + #endif +Index: kernel/include/net/af_unix.h +=================================================================== +--- kernel.orig/include/net/af_unix.h 2008-11-24 14:08:46.000000000 +0100 ++++ kernel/include/net/af_unix.h 2008-11-24 15:47:46.000000000 +0100 +@@ -10,6 +10,7 @@ + extern void unix_notinflight(struct file *fp); + extern void unix_gc(void); + extern void wait_for_unix_gc(void); ++extern void unix_destruct_fds(struct sk_buff *skb); + + #define UNIX_HASH_SIZE 256 + +Index: kernel/include/net/arp.h +=================================================================== +--- kernel.orig/include/net/arp.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/arp.h 2008-11-24 15:47:46.000000000 +0100 +@@ -7,7 +7,12 @@ + + #define HAVE_ARP_CREATE + +-extern struct neigh_table arp_tbl; ++#if defined(CONFIG_VE) && defined(CONFIG_INET) ++#define arp_tbl (*(get_exec_env()->ve_arp_tbl)) ++#else ++extern struct neigh_table global_arp_tbl; ++#define arp_tbl global_arp_tbl ++#endif + + extern void arp_init(void); + extern int arp_find(unsigned char *haddr, struct sk_buff *skb); +Index: kernel/include/net/flow.h +=================================================================== +--- kernel.orig/include/net/flow.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/flow.h 2008-11-24 15:47:46.000000000 +0100 +@@ -10,6 +10,7 @@ + #include + #include + ++struct ve_struct; + struct flowi { + int oif; + int iif; +@@ -77,6 +78,9 @@ + #define fl_icmp_code uli_u.icmpt.code + #define fl_ipsec_spi uli_u.spi + #define fl_mh_type uli_u.mht.type ++#ifdef CONFIG_VE ++ struct ve_struct *owner_env; ++#endif + __u32 secid; /* used by xfrm; see secid.txt */ + } __attribute__((__aligned__(BITS_PER_LONG/8))); + +Index: kernel/include/net/icmp.h +=================================================================== +--- kernel.orig/include/net/icmp.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/icmp.h 2008-11-24 15:47:46.000000000 +0100 +@@ -31,15 +31,24 @@ + extern struct icmp_err icmp_err_convert[]; + DECLARE_SNMP_STAT(struct icmp_mib, icmp_statistics); + DECLARE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics); +-#define ICMP_INC_STATS(field) SNMP_INC_STATS(icmp_statistics, field) +-#define ICMP_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmp_statistics, field) +-#define ICMP_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmp_statistics, field) +-#define ICMPMSGOUT_INC_STATS(field) SNMP_INC_STATS(icmpmsg_statistics, field+256) +-#define ICMPMSGOUT_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmpmsg_statistics, field+256) +-#define ICMPMSGOUT_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmpmsg_statistics, field+256) +-#define ICMPMSGIN_INC_STATS(field) SNMP_INC_STATS(icmpmsg_statistics, field) +-#define ICMPMSGIN_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmpmsg_statistics, field) +-#define ICMPMSGIN_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmpmsg_statistics, field) ++ ++#if defined(CONFIG_VE) && defined(CONFIG_INET) ++#define ve_icmp_statistics (get_exec_env()->_icmp_statistics) ++#define ve_icmpmsg_statistics (get_exec_env()->_icmpmsg_statistics) ++#else ++#define ve_icmp_statistics icmp_statistics ++#define ve_icmpmsg_statistics icmpmsg_statistics ++#endif ++ ++#define ICMP_INC_STATS(field) SNMP_INC_STATS(ve_icmp_statistics, field) ++#define ICMP_INC_STATS_BH(field) SNMP_INC_STATS_BH(ve_icmp_statistics, field) ++#define ICMP_INC_STATS_USER(field) SNMP_INC_STATS_USER(ve_icmp_statistics, field) ++#define ICMPMSGOUT_INC_STATS(field) SNMP_INC_STATS(ve_icmpmsg_statistics, field+256) ++#define ICMPMSGOUT_INC_STATS_BH(field) SNMP_INC_STATS_BH(ve_icmpmsg_statistics, field+256) ++#define ICMPMSGOUT_INC_STATS_USER(field) SNMP_INC_STATS_USER(ve_icmpmsg_statistics, field+256) ++#define ICMPMSGIN_INC_STATS(field) SNMP_INC_STATS(ve_icmpmsg_statistics, field) ++#define ICMPMSGIN_INC_STATS_BH(field) SNMP_INC_STATS_BH(ve_icmpmsg_statistics, field) ++#define ICMPMSGIN_INC_STATS_USER(field) SNMP_INC_STATS_USER(ve_icmpmsg_statistics, field) + + struct dst_entry; + struct net_proto_family; +Index: kernel/include/net/if_inet6.h +=================================================================== +--- kernel.orig/include/net/if_inet6.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/if_inet6.h 2008-11-24 15:47:46.000000000 +0100 +@@ -194,7 +194,14 @@ + struct rcu_head rcu; + }; + +-extern struct ipv6_devconf ipv6_devconf; ++extern struct ipv6_devconf global_ipv6_devconf; ++extern struct ipv6_devconf global_ipv6_devconf_dflt; ++ ++#ifdef CONFIG_VE ++#define ve_ipv6_devconf (*(get_exec_env()->_ipv6_devconf)) ++#else ++#define ve_ipv6_devconf global_ipv6_devconf ++#endif + + static inline void ipv6_eth_mc_map(struct in6_addr *addr, char *buf) + { +Index: kernel/include/net/inet6_hashtables.h +=================================================================== +--- kernel.orig/include/net/inet6_hashtables.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/inet6_hashtables.h 2008-11-24 15:47:46.000000000 +0100 +@@ -29,9 +29,10 @@ + + /* I have no idea if this is a good hash for v6 or not. -DaveM */ + static inline unsigned int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport, +- const struct in6_addr *faddr, const __be16 fport) ++ const struct in6_addr *faddr, const __be16 fport, ++ const envid_t veid) + { +- u32 ports = (lport ^ (__force u16)fport); ++ u32 ports = (lport ^ (__force u16)fport) ^ (veid ^ (veid >> 16)); + + return jhash_3words((__force u32)laddr->s6_addr32[3], + (__force u32)faddr->s6_addr32[3], +@@ -46,7 +47,7 @@ + const struct in6_addr *faddr = &np->daddr; + const __u16 lport = inet->num; + const __be16 fport = inet->dport; +- return inet6_ehashfn(laddr, lport, faddr, fport); ++ return inet6_ehashfn(laddr, lport, faddr, fport, VEID(sk->owner_env)); + } + + extern void __inet6_hash(struct inet_hashinfo *hashinfo, struct sock *sk); +Index: kernel/include/net/inet_frag.h +=================================================================== +--- kernel.orig/include/net/inet_frag.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/inet_frag.h 2008-11-24 15:47:46.000000000 +0100 +@@ -16,6 +16,10 @@ + #define COMPLETE 4 + #define FIRST_IN 2 + #define LAST_IN 1 ++ ++#ifdef CONFIG_VE ++ struct ve_struct *owner_ve; ++#endif + }; + + #define INETFRAGS_HASHSZ 64 +Index: kernel/include/net/inet_hashtables.h +=================================================================== +--- kernel.orig/include/net/inet_hashtables.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/inet_hashtables.h 2008-11-24 15:47:46.000000000 +0100 +@@ -74,6 +74,7 @@ + * ports are created in O(1) time? I thought so. ;-) -DaveM + */ + struct inet_bind_bucket { ++ struct ve_struct *owner_env; + unsigned short port; + signed short fastreuse; + struct hlist_node node; +@@ -195,37 +196,43 @@ + extern struct inet_bind_bucket * + inet_bind_bucket_create(struct kmem_cache *cachep, + struct inet_bind_hashbucket *head, +- const unsigned short snum); ++ const unsigned short snum, ++ struct ve_struct *env); + extern void inet_bind_bucket_destroy(struct kmem_cache *cachep, + struct inet_bind_bucket *tb); + +-static inline int inet_bhashfn(const __u16 lport, const int bhash_size) ++static inline int inet_bhashfn(const __u16 lport, const int bhash_size, ++ unsigned veid) + { +- return lport & (bhash_size - 1); ++ return ((lport + (veid ^ (veid >> 16))) & (bhash_size - 1)); + } + + extern void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, + const unsigned short snum); + + /* These can have wildcards, don't try too hard. */ +-static inline int inet_lhashfn(const unsigned short num) ++static inline int inet_lhashfn(const unsigned short num, unsigned veid) + { +- return num & (INET_LHTABLE_SIZE - 1); ++ return ((num + (veid ^ (veid >> 16))) & (INET_LHTABLE_SIZE - 1)); + } + + static inline int inet_sk_listen_hashfn(const struct sock *sk) + { +- return inet_lhashfn(inet_sk(sk)->num); ++ return inet_lhashfn(inet_sk(sk)->num, VEID(sk->owner_env)); + } + + /* Caller must disable local BH processing. */ + static inline void __inet_inherit_port(struct inet_hashinfo *table, + struct sock *sk, struct sock *child) + { +- const int bhash = inet_bhashfn(inet_sk(child)->num, table->bhash_size); +- struct inet_bind_hashbucket *head = &table->bhash[bhash]; ++ int bhash; ++ struct inet_bind_hashbucket *head; + struct inet_bind_bucket *tb; + ++ bhash = inet_bhashfn(inet_sk(child)->num, table->bhash_size, ++ VEID(child->owner_env)); ++ head = &table->bhash[bhash]; ++ + spin_lock(&head->lock); + tb = inet_csk(sk)->icsk_bind_hash; + sk_add_bind_node(child, &tb->owners); +@@ -365,25 +372,25 @@ + (((__force __u64)(__be32)(__daddr)) << 32) | \ + ((__force __u64)(__be32)(__saddr))); + #endif /* __BIG_ENDIAN */ +-#define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ ++#define INET_MATCH_ALLVE(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ + (((__sk)->sk_hash == (__hash)) && \ + ((*((__addrpair *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \ + ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) +-#define INET_TW_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ ++#define INET_TW_MATCH_ALLVE(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ + (((__sk)->sk_hash == (__hash)) && \ + ((*((__addrpair *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ + ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) + #else /* 32-bit arch */ + #define INET_ADDR_COOKIE(__name, __saddr, __daddr) +-#define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif) \ ++#define INET_MATCH_ALLVE(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif) \ + (((__sk)->sk_hash == (__hash)) && \ + (inet_sk(__sk)->daddr == (__saddr)) && \ + (inet_sk(__sk)->rcv_saddr == (__daddr)) && \ + ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) +-#define INET_TW_MATCH(__sk, __hash,__cookie, __saddr, __daddr, __ports, __dif) \ ++#define INET_TW_MATCH_ALLVE(__sk, __hash,__cookie, __saddr, __daddr, __ports, __dif) \ + (((__sk)->sk_hash == (__hash)) && \ + (inet_twsk(__sk)->tw_daddr == (__saddr)) && \ + (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \ +@@ -391,6 +398,18 @@ + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) + #endif /* 64-bit arch */ + ++#define INET_MATCH(__sk, __hash, __cookie, __saddr, \ ++ __daddr, __ports, __dif, __ve) \ ++ (INET_MATCH_ALLVE((__sk), (__hash), (__cookie), (__saddr), \ ++ (__daddr), (__ports), (__dif)) \ ++ && ve_accessible_strict((__sk)->owner_env, (__ve))) ++ ++#define INET_TW_MATCH(__sk, __hash, __cookie, __saddr, \ ++ __daddr, __ports, __dif, __ve) \ ++ (INET_TW_MATCH_ALLVE((__sk), (__hash), (__cookie), (__saddr), \ ++ (__daddr), (__ports), (__dif)) \ ++ && ve_accessible_strict(inet_twsk(__sk)->tw_owner_env, VEID(__ve))) ++ + /* + * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so we need + * not check it for lookups anymore, thanks Alexey. -DaveM +@@ -410,20 +429,22 @@ + /* Optimize here for direct hit, only listening connections can + * have wildcards anyways. + */ +- unsigned int hash = inet_ehashfn(daddr, hnum, saddr, sport); ++ struct ve_struct *ve = get_exec_env(); ++ unsigned int hash = inet_ehashfn(daddr, hnum, saddr, sport, VEID(ve)); + struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); + rwlock_t *lock = inet_ehash_lockp(hashinfo, hash); + + prefetch(head->chain.first); + read_lock(lock); + sk_for_each(sk, node, &head->chain) { +- if (INET_MATCH(sk, hash, acookie, saddr, daddr, ports, dif)) ++ if (INET_MATCH(sk, hash, acookie, saddr, daddr, ++ ports, dif, ve)) + goto hit; /* You sunk my battleship! */ + } + + /* Must check for a TIME_WAIT'er before going to listener hash. */ + sk_for_each(sk, node, &head->twchain) { +- if (INET_TW_MATCH(sk, hash, acookie, saddr, daddr, ports, dif)) ++ if (INET_TW_MATCH(sk, hash, acookie, saddr, daddr, ports, dif, ve)) + goto hit; + } + sk = NULL; +Index: kernel/include/net/inet_sock.h +=================================================================== +--- kernel.orig/include/net/inet_sock.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/inet_sock.h 2008-11-24 15:47:46.000000000 +0100 +@@ -173,10 +173,11 @@ + extern void build_ehash_secret(void); + + static inline unsigned int inet_ehashfn(const __be32 laddr, const __u16 lport, +- const __be32 faddr, const __be16 fport) ++ const __be32 faddr, const __be16 fport, ++ const envid_t veid) + { + return jhash_3words((__force __u32) laddr, +- (__force __u32) faddr, ++ (__force __u32) faddr ^ (veid ^ (veid >> 16)), + ((__u32) lport) << 16 | (__force __u32)fport, + inet_ehash_secret); + } +@@ -187,8 +188,9 @@ + const __u16 lport = inet->num; + const __be32 faddr = inet->daddr; + const __be16 fport = inet->dport; ++ envid_t veid = VEID(sk->owner_env); + +- return inet_ehashfn(laddr, lport, faddr, fport); ++ return inet_ehashfn(laddr, lport, faddr, fport, veid); + } + + +Index: kernel/include/net/inet_timewait_sock.h +=================================================================== +--- kernel.orig/include/net/inet_timewait_sock.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/inet_timewait_sock.h 2008-11-24 15:47:46.000000000 +0100 +@@ -81,6 +81,7 @@ + struct inet_hashinfo *hashinfo; + int sysctl_tw_recycle; + int sysctl_max_tw_buckets; ++ int ub_managed; + }; + + extern void inet_twdr_hangman(unsigned long data); +@@ -134,6 +135,7 @@ + unsigned long tw_ttd; + struct inet_bind_bucket *tw_tb; + struct hlist_node tw_death_node; ++ envid_t tw_owner_env; + }; + + static inline void inet_twsk_add_node(struct inet_timewait_sock *tw, +Index: kernel/include/net/ip.h +=================================================================== +--- kernel.orig/include/net/ip.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/ip.h 2008-11-24 15:47:46.000000000 +0100 +@@ -157,16 +157,28 @@ + + extern struct ipv4_config ipv4_config; + DECLARE_SNMP_STAT(struct ipstats_mib, ip_statistics); +-#define IP_INC_STATS(field) SNMP_INC_STATS(ip_statistics, field) +-#define IP_INC_STATS_BH(field) SNMP_INC_STATS_BH(ip_statistics, field) +-#define IP_INC_STATS_USER(field) SNMP_INC_STATS_USER(ip_statistics, field) +-#define IP_ADD_STATS_BH(field, val) SNMP_ADD_STATS_BH(ip_statistics, field, val) ++ ++#ifdef CONFIG_VE ++#define ve_ip_statistics (get_exec_env()->_ip_statistics) ++#else ++#define ve_ip_statistics ip_statistics ++#endif ++#define IP_INC_STATS(field) SNMP_INC_STATS(ve_ip_statistics, field) ++#define IP_INC_STATS_BH(field) SNMP_INC_STATS_BH(ve_ip_statistics, field) ++#define IP_INC_STATS_USER(field) SNMP_INC_STATS_USER(ve_ip_statistics, field) ++#define IP_ADD_STATS_BH(field, val) SNMP_ADD_STATS_BH(ve_ip_statistics, field, val) ++ + DECLARE_SNMP_STAT(struct linux_mib, net_statistics); +-#define NET_INC_STATS(field) SNMP_INC_STATS(net_statistics, field) +-#define NET_INC_STATS_BH(field) SNMP_INC_STATS_BH(net_statistics, field) +-#define NET_INC_STATS_USER(field) SNMP_INC_STATS_USER(net_statistics, field) +-#define NET_ADD_STATS_BH(field, adnd) SNMP_ADD_STATS_BH(net_statistics, field, adnd) +-#define NET_ADD_STATS_USER(field, adnd) SNMP_ADD_STATS_USER(net_statistics, field, adnd) ++#if defined(CONFIG_VE) && defined(CONFIG_INET) ++#define ve_net_statistics (get_exec_env()->_net_statistics) ++#else ++#define ve_net_statistics net_statistics ++#endif ++#define NET_INC_STATS(field) SNMP_INC_STATS(ve_net_statistics, field) ++#define NET_INC_STATS_BH(field) SNMP_INC_STATS_BH(ve_net_statistics, field) ++#define NET_INC_STATS_USER(field) SNMP_INC_STATS_USER(ve_net_statistics, field) ++#define NET_ADD_STATS_BH(field, adnd) SNMP_ADD_STATS_BH(ve_net_statistics, field, adnd) ++#define NET_ADD_STATS_USER(field, adnd) SNMP_ADD_STATS_USER(ve_net_statistics, field, adnd) + + extern unsigned long snmp_fold_field(void *mib[], int offt); + extern int snmp_mib_init(void *ptr[2], size_t mibsize, size_t mibalign); +@@ -393,4 +405,11 @@ + + extern struct ctl_table ipv4_table[]; + ++#ifdef CONFIG_SYSCTL ++extern int ipv4_sysctl_forward(ctl_table *ctl, int write, struct file * filp, ++ void __user *buffer, size_t *lenp, loff_t *ppos); ++extern int ipv4_sysctl_forward_strategy(ctl_table *table, int __user *name, ++ int nlen, void __user *oldval, size_t __user *oldlenp, ++ void __user *newval, size_t newlen); ++#endif + #endif /* _IP_H */ +Index: kernel/include/net/ip6_fib.h +=================================================================== +--- kernel.orig/include/net/ip6_fib.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/ip6_fib.h 2008-11-24 15:47:46.000000000 +0100 +@@ -116,6 +116,8 @@ + return ((struct rt6_info *)dst)->rt6i_idev; + } + ++extern struct list_head fib6_table_list; ++ + struct fib6_walker_t + { + struct fib6_walker_t *prev, *next; +@@ -164,6 +166,7 @@ + u32 tb6_id; + rwlock_t tb6_lock; + struct fib6_node tb6_root; ++ struct ve_struct *owner_env; + }; + + #define RT6_TABLE_UNSPEC RT_TABLE_UNSPEC +@@ -220,6 +223,8 @@ + extern void fib6_gc_cleanup(void); + + extern void fib6_init(void); ++extern void fib6_tables_init(void); ++extern void fib6_tables_cleanup(void); + + extern void fib6_rules_init(void); + extern void fib6_rules_cleanup(void); +Index: kernel/include/net/ip6_route.h +=================================================================== +--- kernel.orig/include/net/ip6_route.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/ip6_route.h 2008-11-24 15:47:46.000000000 +0100 +@@ -162,5 +162,13 @@ + return rt->rt6i_flags & RTF_LOCAL; + } + ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++int init_ve_route6(struct ve_struct *ve); ++void fini_ve_route6(struct ve_struct *ve); ++#else ++#define init_ve_route6(ve) (0) ++#define fini_ve_route6(ve) do { } while (0) ++#endif ++ + #endif + #endif +Index: kernel/include/net/ip_fib.h +=================================================================== +--- kernel.orig/include/net/ip_fib.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/ip_fib.h 2008-11-24 15:47:46.000000000 +0100 +@@ -153,10 +153,23 @@ + unsigned char tb_data[0]; + }; + ++struct fn_zone; ++struct fn_hash { ++ struct fn_zone *fn_zones[33]; ++ struct fn_zone *fn_zone_list; ++}; ++ + #ifndef CONFIG_IP_MULTIPLE_TABLES + +-extern struct fib_table *ip_fib_local_table; +-extern struct fib_table *ip_fib_main_table; ++#ifdef CONFIG_VE ++#define ip_fib_local_table get_exec_env()->_local_table ++#define ip_fib_main_table get_exec_env()->_main_table ++#else ++extern struct fib_table *__ip_fib_local_table; ++extern struct fib_table *__ip_fib_main_table; ++#define ip_fib_local_table __ip_fib_local_table ++#define ip_fib_main_table __ip_fib_main_table ++#endif + + static inline struct fib_table *fib_get_table(u32 id) + { +@@ -200,6 +213,10 @@ + extern struct fib_table *fib_get_table(u32 id); + extern void fib_select_default(const struct flowi *flp, struct fib_result *res); + ++extern int fib_rules_create(void); ++extern void fib_rules_destroy(void); ++extern int fib4_rules_dump(struct sk_buff *skb, struct netlink_callback *cb); ++ + #endif /* CONFIG_IP_MULTIPLE_TABLES */ + + /* Exported by fib_frontend.c */ +@@ -220,6 +237,15 @@ + /* Exported by fib_hash.c */ + extern struct fib_table *fib_hash_init(u32 id); + ++#if defined(CONFIG_VE) && defined(CONFIG_INET) ++struct ve_struct; ++extern int init_ve_route(struct ve_struct *ve); ++extern void fini_ve_route(struct ve_struct *ve); ++#else ++#define init_ve_route(ve) 0 ++#define fini_ve_route(ve) do { } while (0) ++#endif ++ + static inline void fib_combine_itag(u32 *itag, struct fib_result *res) + { + #ifdef CONFIG_NET_CLS_ROUTE +Index: kernel/include/net/ipv6.h +=================================================================== +--- kernel.orig/include/net/ipv6.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/ipv6.h 2008-11-24 15:47:46.000000000 +0100 +@@ -117,7 +117,7 @@ + struct inet6_dev *_idev = (idev); \ + if (likely(_idev != NULL)) \ + SNMP_INC_STATS##modifier((_idev)->stats.statname, (field)); \ +- SNMP_INC_STATS##modifier(statname##_statistics, (field)); \ ++ SNMP_INC_STATS##modifier(ve_##statname##_statistics, (field)); \ + }) + + #define _DEVADD(statname, modifier, idev, field, val) \ +@@ -125,9 +125,22 @@ + struct inet6_dev *_idev = (idev); \ + if (likely(_idev != NULL)) \ + SNMP_ADD_STATS##modifier((_idev)->stats.statname, (field), (val)); \ +- SNMP_ADD_STATS##modifier(statname##_statistics, (field), (val));\ ++ SNMP_ADD_STATS##modifier(ve_##statname##_statistics, (field), (val));\ + }) + ++#ifdef CONFIG_VE ++#define ve_ipv6_statistics (get_exec_env()->_ipv6_statistics) ++#define ve_icmpv6_statistics (get_exec_env()->_icmpv6_statistics) ++#define ve_icmpv6msg_statistics (get_exec_env()->_icmpv6msg_statistics) ++#define ve_udp_stats_in6 (get_exec_env()->_udp_stats_in6) ++#define ve_udplite_stats_in6 (get_exec_env()->_udplite_stats_in6) ++#else ++#define ve_ipv6_statistics ipv6_statistics ++#define ve_icmpv6_statistics icmpv6_statistics ++#define ve_icmpv6msg_statistics icmpv6msg_statistics ++#define ve_udplite_stats_in6 udplite_stats_in6 ++#endif ++ + /* MIBs */ + DECLARE_SNMP_STAT(struct ipstats_mib, ipv6_statistics); + +@@ -167,11 +180,29 @@ + DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6); + DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6); + #define UDP6_INC_STATS_BH(field, is_udplite) do { \ +- if (is_udplite) SNMP_INC_STATS_BH(udplite_stats_in6, field); \ +- else SNMP_INC_STATS_BH(udp_stats_in6, field); } while(0) ++ if (is_udplite) SNMP_INC_STATS_BH(ve_udplite_stats_in6, field); \ ++ else SNMP_INC_STATS_BH(ve_udp_stats_in6, field); } while(0) + #define UDP6_INC_STATS_USER(field, is_udplite) do { \ +- if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field); \ +- else SNMP_INC_STATS_USER(udp_stats_in6, field); } while(0) ++ if (is_udplite) SNMP_INC_STATS_USER(ve_udplite_stats_in6, field); \ ++ else SNMP_INC_STATS_USER(ve_udp_stats_in6, field); } while(0) ++ ++int snmp6_register_dev(struct inet6_dev *idev); ++int snmp6_unregister_dev(struct inet6_dev *idev); ++int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign); ++void snmp6_mib_free(void *ptr[2]); ++ ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++int ve_snmp_proc_init(struct ve_struct *ve); ++void ve_snmp_proc_fini(struct ve_struct *ve); ++#else ++static inline int ve_snmp_proc_init(struct ve_struct *ve) ++{ ++ return 0; ++} ++static inline void ve_snmp_proc_fini(struct ve_struct *ve) ++{ ++} ++#endif + + struct ip6_ra_chain + { +Index: kernel/include/net/ndisc.h +=================================================================== +--- kernel.orig/include/net/ndisc.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/ndisc.h 2008-11-24 15:47:46.000000000 +0100 +@@ -52,7 +52,12 @@ + struct net_proto_family; + struct sk_buff; + +-extern struct neigh_table nd_tbl; ++#ifdef CONFIG_VE ++#define nd_tbl (*(get_exec_env()->ve_nd_tbl)) ++#else ++#define nd_tbl global_nd_tbl ++extern struct neigh_table global_nd_tbl; ++#endif + + struct nd_msg { + struct icmp6hdr icmph; +@@ -130,6 +135,7 @@ + extern void inet6_ifinfo_notify(int event, + struct inet6_dev *idev); + ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + static inline struct neighbour * ndisc_get_neigh(struct net_device *dev, struct in6_addr *addr) + { + +@@ -138,6 +144,7 @@ + + return NULL; + } ++#endif + + + #endif /* __KERNEL__ */ +Index: kernel/include/net/neighbour.h +=================================================================== +--- kernel.orig/include/net/neighbour.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/neighbour.h 2008-11-24 15:47:46.000000000 +0100 +@@ -161,6 +161,8 @@ + atomic_t entries; + rwlock_t lock; + unsigned long last_rand; ++ struct ve_struct *owner_env; ++ struct user_beancounter *owner_ub; + struct kmem_cache *kmem_cachep; + struct neigh_statistics *stats; + struct neighbour **hash_buckets; +@@ -180,8 +182,8 @@ + #define NEIGH_UPDATE_F_ISROUTER 0x40000000 + #define NEIGH_UPDATE_F_ADMIN 0x80000000 + +-extern void neigh_table_init(struct neigh_table *tbl); +-extern void neigh_table_init_no_netlink(struct neigh_table *tbl); ++extern int neigh_table_init(struct neigh_table *tbl); ++extern int neigh_table_init_no_netlink(struct neigh_table *tbl); + extern int neigh_table_clear(struct neigh_table *tbl); + extern struct neighbour * neigh_lookup(struct neigh_table *tbl, + const void *pkey, +Index: kernel/include/net/net_namespace.h +=================================================================== +--- kernel.orig/include/net/net_namespace.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/net_namespace.h 2008-11-24 15:47:46.000000000 +0100 +@@ -29,6 +29,13 @@ + struct list_head dev_base_head; + struct hlist_head *dev_name_head; + struct hlist_head *dev_index_head; ++ ++ int ifindex; ++ ++#ifdef CONFIG_VE ++ struct completion *sysfs_completion; ++ struct ve_struct *owner_ve; ++#endif + }; + + #ifdef CONFIG_NET +Index: kernel/include/net/netfilter/ipv4/nf_conntrack_ipv4.h +=================================================================== +--- kernel.orig/include/net/netfilter/ipv4/nf_conntrack_ipv4.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/netfilter/ipv4/nf_conntrack_ipv4.h 2008-11-24 15:47:46.000000000 +0100 +@@ -18,8 +18,18 @@ + extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4; + extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp; + ++#if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) + extern int nf_conntrack_ipv4_compat_init(void); + extern void nf_conntrack_ipv4_compat_fini(void); ++#else ++static inline int nf_conntrack_ipv4_compat_init(void) ++{ ++ return 0; ++} ++static inline void nf_conntrack_ipv4_compat_fini(void) ++{ ++} ++#endif + + extern void need_ipv4_conntrack(void); + +Index: kernel/include/net/netfilter/nf_conntrack.h +=================================================================== +--- kernel.orig/include/net/netfilter/nf_conntrack.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/netfilter/nf_conntrack.h 2008-11-24 15:47:46.000000000 +0100 +@@ -27,6 +27,10 @@ + + #include + ++#ifdef CONFIG_VE_IPTABLES ++#include ++#endif ++ + /* per conntrack: protocol private data */ + union nf_conntrack_proto { + /* insert conntrack proto private data here */ +@@ -92,6 +96,10 @@ + #include + #include + ++#ifdef CONFIG_VE_IPTABLES ++#include ++#endif ++ + struct nf_conn + { + /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, +@@ -129,6 +137,10 @@ + + /* Extensions */ + struct nf_ct_ext *ext; ++ ++#ifdef CONFIG_VE_IPTABLES ++ struct ve_struct *ct_owner_env; ++#endif + }; + + static inline struct nf_conn * +@@ -183,6 +195,11 @@ + + extern void nf_conntrack_flush(void); + ++struct nf_conntrack_helper * nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple); ++void nf_ct_helper_put(struct nf_conntrack_helper *helper); ++ ++struct nf_conntrack_helper * __nf_conntrack_helper_find_byname(const char *name); ++ + extern int nf_ct_get_tuplepr(const struct sk_buff *skb, + unsigned int nhoff, + u_int16_t l3num, +@@ -231,7 +248,8 @@ + extern void nf_conntrack_free(struct nf_conn *ct); + extern struct nf_conn * + nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, +- const struct nf_conntrack_tuple *repl); ++ const struct nf_conntrack_tuple *repl, ++ struct user_beancounter *); + + /* It's confirmed if it is, or has been in the hash table. */ + static inline int nf_ct_is_confirmed(struct nf_conn *ct) +@@ -254,6 +272,8 @@ + extern int nf_conntrack_checksum; + extern atomic_t nf_conntrack_count; + extern int nf_conntrack_max; ++extern int nf_conntrack_disable_ve0; ++extern int ip_conntrack_disable_ve0; + + DECLARE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat); + #define NF_CT_STAT_INC(count) (__get_cpu_var(nf_conntrack_stat).count++) +Index: kernel/include/net/netfilter/nf_conntrack_core.h +=================================================================== +--- kernel.orig/include/net/netfilter/nf_conntrack_core.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/netfilter/nf_conntrack_core.h 2008-11-24 15:47:46.000000000 +0100 +@@ -62,6 +62,47 @@ + + extern int __nf_conntrack_confirm(struct sk_buff *skb); + ++#if defined(CONFIG_VE_IPTABLES) ++#include ++#define ve_nf_conntrack_hash (get_exec_env()->_nf_conntrack->_nf_conntrack_hash) ++#define ve_nf_conntrack_vmalloc (get_exec_env()->_nf_conntrack->_nf_conntrack_vmalloc) ++#define ve_unconfirmed (get_exec_env()->_nf_conntrack->_unconfirmed) ++#else ++#define ve_nf_conntrack_hash nf_conntrack_hash ++#define ve_nf_conntrack_vmalloc nf_conntrack_vmalloc ++#define ve_unconfirmed unconfirmed ++#endif /* CONFIG_VE_IPTABLES */ ++ ++#if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) ++#define ve_nf_ct_sysctl_header \ ++ (get_exec_env()->_nf_conntrack->_nf_ct_sysctl_header) ++#define ve_nf_ct_sysctl_table \ ++ (get_exec_env()->_nf_conntrack->_nf_ct_sysctl_table) ++#define ve_nf_ct_netfilter_table \ ++ (get_exec_env()->_nf_conntrack->_nf_ct_netfilter_table) ++#define ve_nf_ct_net_table \ ++ (get_exec_env()->_nf_conntrack->_nf_ct_net_table) ++extern void nf_ct_proto_generic_sysctl_cleanup(void); ++extern int nf_ct_proto_generic_sysctl_init(void); ++#else ++#define ve_nf_ct_sysctl_header nf_ct_sysctl_header ++#define ve_nf_ct_sysctl_table nf_ct_sysctl_table ++#define ve_nf_ct_netfilter_table nf_ct_netfilter_table ++#define ve_nf_ct_net_table nf_ct_net_table ++static inline int nf_ct_proto_generic_sysctl_init(void) ++{ ++ return 0; ++} ++static inline void nf_ct_proto_generic_sysctl_cleanup(void) ++{ ++} ++#endif /* CONFIG_VE_IPTABLES */ ++ ++#if defined(CONFIG_VE_IPTABLES) ++extern int nf_conntrack_init_ve(void); ++extern void nf_conntrack_cleanup_ve(void); ++#endif /* CONFIG_VE_IPTABLES */ ++ + /* Confirm a connection: returns NF_DROP if packet must be dropped. */ + static inline int nf_conntrack_confirm(struct sk_buff *skb) + { +Index: kernel/include/net/netfilter/nf_conntrack_ecache.h +=================================================================== +--- kernel.orig/include/net/netfilter/nf_conntrack_ecache.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/netfilter/nf_conntrack_ecache.h 2008-11-24 15:47:46.000000000 +0100 +@@ -34,6 +34,9 @@ + struct nf_conn *ct = (struct nf_conn *)skb->nfct; + struct nf_conntrack_ecache *ecache; + ++ if (!ve_is_super(get_exec_env())) ++ return; ++ + local_bh_disable(); + ecache = &__get_cpu_var(nf_conntrack_ecache); + if (ct != ecache->ct) +@@ -45,7 +48,7 @@ + static inline void nf_conntrack_event(enum ip_conntrack_events event, + struct nf_conn *ct) + { +- if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) ++ if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct) && ve_is_super(get_exec_env())) + atomic_notifier_call_chain(&nf_conntrack_chain, event, ct); + } + +@@ -57,7 +60,8 @@ + nf_ct_expect_event(enum ip_conntrack_expect_events event, + struct nf_conntrack_expect *exp) + { +- atomic_notifier_call_chain(&nf_ct_expect_chain, event, exp); ++ if (ve_is_super(get_exec_env())) ++ atomic_notifier_call_chain(&nf_ct_expect_chain, event, exp); + } + + #else /* CONFIG_NF_CONNTRACK_EVENTS */ +Index: kernel/include/net/netfilter/nf_conntrack_expect.h +=================================================================== +--- kernel.orig/include/net/netfilter/nf_conntrack_expect.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/netfilter/nf_conntrack_expect.h 2008-11-24 15:47:46.000000000 +0100 +@@ -9,6 +9,14 @@ + extern struct hlist_head *nf_ct_expect_hash; + extern unsigned int nf_ct_expect_hsize; + extern unsigned int nf_ct_expect_max; ++#ifdef CONFIG_VE_IPTABLES ++#include ++#define ve_nf_ct_expect_hash (get_exec_env()->_nf_conntrack->_nf_ct_expect_hash) ++#define ve_nf_ct_expect_max (get_exec_env()->_nf_conntrack->_nf_ct_expect_max) ++#else ++#define ve_nf_ct_expect_hash nf_ct_expect_hash ++#define ve_nf_ct_expect_max nf_ct_expect_max ++#endif + + struct nf_conntrack_expect + { +Index: kernel/include/net/netfilter/nf_conntrack_l3proto.h +=================================================================== +--- kernel.orig/include/net/netfilter/nf_conntrack_l3proto.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/netfilter/nf_conntrack_l3proto.h 2008-11-24 15:47:46.000000000 +0100 +@@ -56,6 +56,9 @@ + */ + int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb); + ++ /* Called when a conntrack entry is destroyed */ ++ void (*destroy)(struct nf_conn *conntrack); ++ + /* + * Called before tracking. + * *dataoff: offset of protocol header (TCP, UDP,...) in skb +@@ -81,6 +84,39 @@ + struct module *me; + }; + ++/* virtualization of l3 protocol's sysctl tables: */ ++#if defined(CONFIG_VE_IPTABLES) ++#include ++#define ve_nf_ct3 (get_exec_env()->_nf_conntrack) ++#endif ++ ++#if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) ++#define ve_nf_ct_l3protos ve_nf_ct3->_nf_ct_l3protos ++#define ve_nf_conntrack_l3proto_ipv4 (ve_nf_ct3->_nf_conntrack_l3proto_ipv4) ++#define ve_nf_conntrack_l3proto_ipv6 (ve_nf_ct3->_nf_conntrack_l3proto_ipv6) ++#define ve_nf_conntrack_max (ve_nf_ct3->_nf_conntrack_max) ++#define ve_nf_conntrack_count (ve_nf_ct3->_nf_conntrack_count) ++#define ve_nf_conntrack_checksum (ve_nf_ct3->_nf_conntrack_checksum) ++#define ve_nf_ct_frag6_timeout (ve_nf_ct3->_nf_frags6_ctl.timeout) ++#define ve_nf_ct_frag6_low_thresh (ve_nf_ct3->_nf_frags6_ctl.low_thresh) ++#define ve_nf_ct_frag6_high_thresh (ve_nf_ct3->_nf_frags6_ctl.high_thresh) ++#else /* !CONFIG_VE_IPTABLES || !CONFIG_SYSCTL: */ ++#define ve_nf_ct_l3protos nf_ct_l3protos ++#define ve_nf_conntrack_l3proto_ipv4 &nf_conntrack_l3proto_ipv4 ++#define ve_nf_conntrack_l3proto_ipv6 &nf_conntrack_l3proto_ipv6 ++#define ve_nf_conntrack_max nf_conntrack_max ++#define ve_nf_conntrack_count nf_conntrack_count ++#define ve_nf_conntrack_checksum nf_conntrack_checksum ++#define ve_nf_ct_frag6_timeout nf_ct_frag6_timeout ++#define ve_nf_ct_frag6_low_thresh nf_ct_frag6_low_thresh ++#define ve_nf_ct_frag6_high_thresh nf_ct_frag6_high_thresh ++#endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ ++ ++extern int init_nf_ct_l3proto_ipv4(void); ++extern void fini_nf_ct_l3proto_ipv4(void); ++extern int init_nf_ct_l3proto_ipv6(void); ++extern void fini_nf_ct_l3proto_ipv6(void); ++ + extern struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX]; + + /* Protocol registration. */ +@@ -97,7 +133,11 @@ + { + if (unlikely(l3proto >= AF_MAX)) + return &nf_conntrack_l3proto_generic; +- return rcu_dereference(nf_ct_l3protos[l3proto]); ++#ifdef CONFIG_VE_IPTABLES ++ if (!get_exec_env()->_nf_conntrack) ++ return &nf_conntrack_l3proto_generic; ++#endif ++ return rcu_dereference(ve_nf_ct_l3protos[l3proto]); + } + + #endif /*_NF_CONNTRACK_L3PROTO_H*/ +Index: kernel/include/net/netfilter/nf_conntrack_l4proto.h +=================================================================== +--- kernel.orig/include/net/netfilter/nf_conntrack_l4proto.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/netfilter/nf_conntrack_l4proto.h 2008-11-24 15:47:46.000000000 +0100 +@@ -99,6 +99,7 @@ + extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; + + #define MAX_NF_CT_PROTO 256 ++extern struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX]; + + extern struct nf_conntrack_l4proto * + __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto); +@@ -119,16 +120,142 @@ + struct nf_conntrack_tuple *t); + extern const struct nla_policy nf_ct_port_nla_policy[]; + ++#ifdef CONFIG_SYSCTL + /* Log invalid packets */ + extern unsigned int nf_ct_log_invalid; ++#endif ++ ++#ifdef CONFIG_VE_IPTABLES ++#include ++#define ve_nf_ct4 (get_exec_env()->_nf_conntrack) ++#endif ++ ++#if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) ++ ++#define ve_nf_ct_protos (ve_nf_ct4->_nf_ct_protos) ++#define ve_nf_conntrack_l4proto_icmp (ve_nf_ct4->_nf_conntrack_l4proto_icmp) ++#define ve_nf_conntrack_l4proto_icmpv6 \ ++ (ve_nf_ct4->_nf_conntrack_l4proto_icmpv6) ++#define ve_nf_conntrack_l4proto_tcp4 (ve_nf_ct4->_nf_conntrack_l4proto_tcp4) ++#define ve_nf_conntrack_l4proto_tcp6 (ve_nf_ct4->_nf_conntrack_l4proto_tcp6) ++#define ve_nf_conntrack_l4proto_udp4 (ve_nf_ct4->_nf_conntrack_l4proto_udp4) ++#define ve_nf_conntrack_l4proto_udp6 (ve_nf_ct4->_nf_conntrack_l4proto_udp6) ++#define ve_nf_conntrack_l4proto_generic \ ++ (ve_nf_ct4->_nf_conntrack_l4proto_generic) ++#define ve_nf_ct_log_invalid (ve_nf_ct4->_nf_ct_log_invalid) ++/* TCP: */ ++#define ve_nf_ct_tcp_timeouts (ve_nf_ct4->_nf_ct_tcp_timeouts) ++#define ve_nf_ct_tcp_timeout_max_retrans \ ++ (ve_nf_ct4->_nf_ct_tcp_timeout_max_retrans) ++#define ve_nf_ct_tcp_max_retrans (ve_nf_ct4->_nf_ct_tcp_max_retrans) ++#define ve_nf_ct_tcp_loose (ve_nf_ct4->_nf_ct_tcp_loose) ++#define ve_nf_ct_tcp_be_liberal (ve_nf_ct4->_nf_ct_tcp_be_liberal) ++#define ve_tcp_sysctl_table_users (ve_nf_ct4->_tcp_sysctl_table_users) ++#define ve_tcp_sysctl_header (ve_nf_ct4->_tcp_sysctl_header) ++#define ve_tcp_compat_sysctl_header (ve_nf_ct4->_tcp_compat_sysctl_header) ++/* UDP: */ ++#define ve_nf_ct_udp_timeout (ve_nf_ct4->_nf_ct_udp_timeout) ++#define ve_nf_ct_udp_timeout_stream (ve_nf_ct4->_nf_ct_udp_timeout_stream) ++#define ve_udp_sysctl_table_users (ve_nf_ct4->_udp_sysctl_table_users) ++#define ve_udp_sysctl_header (ve_nf_ct4->_udp_sysctl_header) ++#define ve_udp_compat_sysctl_header (ve_nf_ct4->_udp_compat_sysctl_header) ++/* ICMP: */ ++#define ve_nf_ct_icmp_timeout (ve_nf_ct4->_nf_ct_icmp_timeout) ++#define ve_icmp_sysctl_header (ve_nf_ct4->_icmp_sysctl_header) ++#define ve_icmp_compat_sysctl_header (ve_nf_ct4->_icmp_compat_sysctl_header) ++/* ICMPV6: */ ++#define ve_nf_ct_icmpv6_timeout (ve_nf_ct4->_nf_ct_icmpv6_timeout) ++#define ve_icmpv6_sysctl_header (ve_nf_ct4->_icmpv6_sysctl_header) ++/* GENERIC: */ ++#define ve_nf_ct_generic_timeout (ve_nf_ct4->_nf_ct_generic_timeout) ++#define ve_generic_sysctl_header (ve_nf_ct4->_generic_sysctl_header) ++#define ve_generic_compat_sysctl_header (ve_nf_ct4->_generic_compat_sysctl_header) ++ ++extern void nf_ct_proto_icmp_sysctl_cleanup(void); ++extern int nf_ct_proto_icmp_sysctl_init(void); ++extern void nf_ct_proto_icmpv6_sysctl_cleanup(void); ++extern int nf_ct_proto_icmpv6_sysctl_init(void); ++extern void nf_ct_proto_tcp_sysctl_cleanup(void); ++extern int nf_ct_proto_tcp_sysctl_init(void); ++extern void nf_ct_proto_udp_sysctl_cleanup(void); ++extern int nf_ct_proto_udp_sysctl_init(void); ++ ++#else /* !CONFIG_VE_IPTABLES || !CONFIG_SYSCTL: */ ++ ++#define ve_nf_ct_protos nf_ct_protos ++#define ve_nf_conntrack_l4proto_icmp &nf_conntrack_l4proto_icmp ++#define ve_nf_conntrack_l4proto_icmpv6 &nf_conntrack_l4proto_icmpv6 ++#define ve_nf_conntrack_l4proto_tcp4 &nf_conntrack_l4proto_tcp4 ++#define ve_nf_conntrack_l4proto_tcp6 &nf_conntrack_l4proto_tcp6 ++#define ve_nf_conntrack_l4proto_udp4 &nf_conntrack_l4proto_udp4 ++#define ve_nf_conntrack_l4proto_udp6 &nf_conntrack_l4proto_udp6 ++#define ve_nf_conntrack_l4proto_generic &nf_conntrack_l4proto_generic ++ ++#if defined(CONFIG_SYSCTL) ++ ++#define ve_nf_ct_log_invalid nf_ct_log_invalid ++/* TCP: */ ++#define ve_nf_ct_tcp_timeouts *tcp_timeouts ++#define ve_nf_ct_tcp_timeout_max_retrans \ ++ nf_ct_tcp_timeout_max_retrans ++#define ve_nf_ct_tcp_max_retrans nf_ct_tcp_max_retrans ++#define ve_nf_ct_tcp_loose nf_ct_tcp_loose ++#define ve_nf_ct_tcp_be_liberal nf_ct_tcp_be_liberal ++#define ve_tcp_sysctl_table_users tcp_sysctl_table_users ++#define ve_tcp_sysctl_header tcp_sysctl_header ++/* UDP:*/ ++#define ve_nf_ct_udp_timeout nf_ct_udp_timeout ++#define ve_nf_ct_udp_timeout_stream nf_ct_udp_timeout_stream ++#define ve_udp_sysctl_table_users udp_sysctl_table_users ++#define ve_udp_sysctl_header udp_sysctl_header ++/* ICMP: */ ++#define ve_nf_ct_icmp_timeout nf_ct_icmp_timeout ++#define ve_icmp_sysctl_header icmp_sysctl_header ++/* ICMPV6: */ ++#define ve_nf_ct_icmpv6_timeout nf_ct_icmpv6_timeout ++#define ve_icmpv6_sysctl_header icmpv6_sysctl_header ++/* GENERIC: */ ++#define ve_nf_ct_generic_timeout nf_ct_generic_timeout ++#define ve_generic_sysctl_header generic_sysctl_header ++#endif /* CONFIG_SYSCTL */ ++ ++static inline int nf_ct_proto_icmp_sysctl_init(void) ++{ ++ return 0; ++} ++static inline void nf_ct_proto_icmp_sysctl_cleanup(void) ++{ ++} ++static inline int nf_ct_proto_tcp_sysctl_init(void) ++{ ++ return 0; ++} ++static inline void nf_ct_proto_tcp_sysctl_cleanup(void) ++{ ++} ++static inline int nf_ct_proto_udp_sysctl_init(void) ++{ ++ return 0; ++} ++static inline void nf_ct_proto_udp_sysctl_cleanup(void) ++{ ++} ++static inline int nf_ct_proto_icmpv6_sysctl_init(void) ++{ ++ return 0; ++} ++static inline void nf_ct_proto_icmpv6_sysctl_cleanup(void) ++{ ++} ++#endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ + + #ifdef CONFIG_SYSCTL + #ifdef DEBUG_INVALID_PACKETS + #define LOG_INVALID(proto) \ +- (nf_ct_log_invalid == (proto) || nf_ct_log_invalid == IPPROTO_RAW) ++ (ve_nf_ct_log_invalid == (proto) || ve_nf_ct_log_invalid == IPPROTO_RAW) + #else + #define LOG_INVALID(proto) \ +- ((nf_ct_log_invalid == (proto) || nf_ct_log_invalid == IPPROTO_RAW) \ ++ ((ve_nf_ct_log_invalid == (proto) || ve_nf_ct_log_invalid == IPPROTO_RAW) \ + && net_ratelimit()) + #endif + #else +Index: kernel/include/net/netfilter/nf_nat.h +=================================================================== +--- kernel.orig/include/net/netfilter/nf_nat.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/netfilter/nf_nat.h 2008-11-24 15:47:46.000000000 +0100 +@@ -84,6 +84,7 @@ + /* Is this tuple already taken? (not by us)*/ + extern int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, + const struct nf_conn *ignored_conntrack); ++extern void ip_nat_hash_conntrack(struct nf_conn *ct); + + static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct) + { +Index: kernel/include/net/netfilter/nf_nat_rule.h +=================================================================== +--- kernel.orig/include/net/netfilter/nf_nat_rule.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/netfilter/nf_nat_rule.h 2008-11-24 15:47:46.000000000 +0100 +@@ -4,7 +4,7 @@ + #include + #include + +-extern int nf_nat_rule_init(void) __init; ++extern int nf_nat_rule_init(void); + extern void nf_nat_rule_cleanup(void); + extern int nf_nat_rule_find(struct sk_buff *skb, + unsigned int hooknum, +Index: kernel/include/net/netlink_sock.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/net/netlink_sock.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,23 @@ ++#ifndef __NET_NETLINK_SOCK_H ++#define __NET_NETLINK_SOCK_H ++ ++struct netlink_sock { ++ /* struct sock has to be the first member of netlink_sock */ ++ struct sock sk; ++ u32 pid; ++ u32 dst_pid; ++ u32 dst_group; ++ u32 flags; ++ u32 subscriptions; ++ u32 ngroups; ++ unsigned long *groups; ++ unsigned long state; ++ wait_queue_head_t wait; ++ struct netlink_callback *cb; ++ struct mutex *cb_mutex; ++ struct mutex cb_def_mutex; ++ void (*netlink_rcv)(struct sk_buff *skb); ++ struct module *module; ++}; ++ ++#endif /* __NET_NETLINK_SOCK_H */ +Index: kernel/include/net/route.h +=================================================================== +--- kernel.orig/include/net/route.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/route.h 2008-11-24 15:47:46.000000000 +0100 +@@ -135,6 +135,7 @@ + #define IPTOS_RT_MASK (IPTOS_TOS_MASK & ~3) + + extern const __u8 ip_tos2prio[16]; ++extern int ip_rt_src_check; + + static inline char rt_tos2priority(u8 tos) + { +@@ -201,4 +202,14 @@ + + extern ctl_table ipv4_route_table[]; + ++#ifdef CONFIG_SYSCTL ++extern int ipv4_flush_delay; ++extern int ipv4_sysctl_rtcache_flush(ctl_table *ctl, int write, ++ struct file *filp, void __user *buffer, size_t *lenp, ++ loff_t *ppos); ++extern int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, ++ int __user *name, int nlen, void __user *oldval, ++ size_t __user *oldlenp, void __user *newval, ++ size_t newlen); ++#endif + #endif /* _ROUTE_H */ +Index: kernel/include/net/sock.h +=================================================================== +--- kernel.orig/include/net/sock.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/sock.h 2008-11-24 15:47:46.000000000 +0100 +@@ -58,6 +58,8 @@ + #include + #include + ++#include ++ + /* + * This structure really needs to be cleaned up. + * Most of it is for TCP, and not used by any of +@@ -263,6 +265,8 @@ + int (*sk_backlog_rcv)(struct sock *sk, + struct sk_buff *skb); + void (*sk_destruct)(struct sock *sk); ++ struct sock_beancounter sk_bc; ++ struct ve_struct *owner_env; + }; + + /* +@@ -498,6 +502,8 @@ + }) + + extern int sk_stream_wait_connect(struct sock *sk, long *timeo_p); ++extern int __sk_stream_wait_memory(struct sock *sk, long *timeo_p, ++ unsigned long amount); + extern int sk_stream_wait_memory(struct sock *sk, long *timeo_p); + extern void sk_stream_wait_close(struct sock *sk, long timeo_p); + extern int sk_stream_error(struct sock *sk, int flags, int err); +@@ -768,8 +774,11 @@ + + static inline int sk_stream_rmem_schedule(struct sock *sk, struct sk_buff *skb) + { +- return (int)skb->truesize <= sk->sk_forward_alloc || +- sk_stream_mem_schedule(sk, skb->truesize, 1); ++ if ((int)skb->truesize > sk->sk_forward_alloc && ++ !sk_stream_mem_schedule(sk, skb->truesize, 1)) ++ /* The situation is bad according to mainstream. Den */ ++ return 0; ++ return ub_tcprcvbuf_charge(sk, skb) == 0; + } + + static inline int sk_stream_wmem_schedule(struct sock *sk, int size) +@@ -855,6 +864,11 @@ + unsigned long size, + int noblock, + int *errcode); ++extern struct sk_buff *sock_alloc_send_skb2(struct sock *sk, ++ unsigned long size, ++ unsigned long size2, ++ int noblock, ++ int *errcode); + extern void *sock_kmalloc(struct sock *sk, int size, + gfp_t priority); + extern void sock_kfree_s(struct sock *sk, void *mem, int size); +@@ -1153,6 +1167,7 @@ + + static inline void skb_set_owner_w(struct sk_buff *skb, struct sock *sk) + { ++ WARN_ON(skb->destructor); + sock_hold(sk); + skb->sk = sk; + skb->destructor = sock_wfree; +@@ -1161,6 +1176,7 @@ + + static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk) + { ++ WARN_ON(skb->destructor); + skb->sk = sk; + skb->destructor = sock_rfree; + atomic_add(skb->truesize, &sk->sk_rmem_alloc); +Index: kernel/include/net/tcp.h +=================================================================== +--- kernel.orig/include/net/tcp.h 2008-11-24 14:18:13.000000000 +0100 ++++ kernel/include/net/tcp.h 2008-11-24 15:47:46.000000000 +0100 +@@ -42,6 +42,13 @@ + #include + + #include ++#include ++ ++#define TCP_PAGE(sk) (sk->sk_sndmsg_page) ++#define TCP_OFF(sk) (sk->sk_sndmsg_off) ++ ++#define TW_WSCALE_MASK 0x0f ++#define TW_WSCALE_SPEC 0x10 + + extern struct inet_hashinfo tcp_hashinfo; + +@@ -218,7 +225,9 @@ + extern int sysctl_tcp_wmem[3]; + extern int sysctl_tcp_rmem[3]; + extern int sysctl_tcp_app_win; ++#ifndef sysctl_tcp_adv_win_scale + extern int sysctl_tcp_adv_win_scale; ++#endif + extern int sysctl_tcp_tw_reuse; + extern int sysctl_tcp_frto; + extern int sysctl_tcp_frto_response; +@@ -233,6 +242,10 @@ + extern int sysctl_tcp_workaround_signed_windows; + extern int sysctl_tcp_slow_start_after_idle; + extern int sysctl_tcp_max_ssthresh; ++extern int sysctl_tcp_use_sg; ++extern int sysctl_tcp_max_tw_kmem_fraction; ++extern int sysctl_tcp_max_tw_buckets_ub; ++ + + extern atomic_t tcp_memory_allocated; + extern atomic_t tcp_sockets_allocated; +@@ -265,12 +278,17 @@ + extern struct proto tcp_prot; + + DECLARE_SNMP_STAT(struct tcp_mib, tcp_statistics); +-#define TCP_INC_STATS(field) SNMP_INC_STATS(tcp_statistics, field) +-#define TCP_INC_STATS_BH(field) SNMP_INC_STATS_BH(tcp_statistics, field) +-#define TCP_INC_STATS_USER(field) SNMP_INC_STATS_USER(tcp_statistics, field) +-#define TCP_DEC_STATS(field) SNMP_DEC_STATS(tcp_statistics, field) +-#define TCP_ADD_STATS_BH(field, val) SNMP_ADD_STATS_BH(tcp_statistics, field, val) +-#define TCP_ADD_STATS_USER(field, val) SNMP_ADD_STATS_USER(tcp_statistics, field, val) ++#if defined(CONFIG_VE) && defined(CONFIG_INET) ++#define ve_tcp_statistics (get_exec_env()->_tcp_statistics) ++#else ++#define ve_tcp_statistics tcp_statistics ++#endif ++#define TCP_INC_STATS(field) SNMP_INC_STATS(ve_tcp_statistics, field) ++#define TCP_INC_STATS_BH(field) SNMP_INC_STATS_BH(ve_tcp_statistics, field) ++#define TCP_INC_STATS_USER(field) SNMP_INC_STATS_USER(ve_tcp_statistics, field) ++#define TCP_DEC_STATS(field) SNMP_DEC_STATS(ve_tcp_statistics, field) ++#define TCP_ADD_STATS_BH(field, val) SNMP_ADD_STATS_BH(ve_tcp_statistics, field, val) ++#define TCP_ADD_STATS_USER(field, val) SNMP_ADD_STATS_USER(ve_tcp_statistics, field, val) + + extern void tcp_v4_err(struct sk_buff *skb, u32); + +@@ -533,7 +551,11 @@ + * to use only the low 32-bits of jiffies and hide the ugly + * casts with the following macro. + */ ++#ifdef CONFIG_VE ++#define tcp_time_stamp ((__u32)(jiffies + get_exec_env()->jiffies_fixup)) ++#else + #define tcp_time_stamp ((__u32)(jiffies)) ++#endif + + /* This is what the send packet queuing engine uses to pass + * TCP per-packet control information to the transmission +Index: kernel/include/net/udp.h +=================================================================== +--- kernel.orig/include/net/udp.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/include/net/udp.h 2008-11-24 15:47:46.000000000 +0100 +@@ -138,16 +138,29 @@ + char __user *optval, int optlen, + int (*push_pending_frames)(struct sock *)); + ++static inline int udp_hashfn(u16 num, unsigned veid) ++{ ++ return ((num + (veid ^ (veid >> 16))) & (UDP_HTABLE_SIZE - 1)); ++} ++ + DECLARE_SNMP_STAT(struct udp_mib, udp_statistics); + /* + * SNMP statistics for UDP and UDP-Lite + */ ++#ifdef CONFIG_VE ++#define ve_udp_statistics (get_exec_env()->_udp_statistics) ++#define ve_udplite_statistics (get_exec_env()->_udplite_statistics) ++#else ++#define ve_udp_statistics udp_statistics ++#define ve_udplite_statistics udplite_statistics ++#endif ++ + #define UDP_INC_STATS_USER(field, is_udplite) do { \ +- if (is_udplite) SNMP_INC_STATS_USER(udplite_statistics, field); \ +- else SNMP_INC_STATS_USER(udp_statistics, field); } while(0) ++ if (is_udplite) SNMP_INC_STATS_USER(ve_udplite_statistics, field); \ ++ else SNMP_INC_STATS_USER(ve_udp_statistics, field); } while(0) + #define UDP_INC_STATS_BH(field, is_udplite) do { \ +- if (is_udplite) SNMP_INC_STATS_BH(udplite_statistics, field); \ +- else SNMP_INC_STATS_BH(udp_statistics, field); } while(0) ++ if (is_udplite) SNMP_INC_STATS_BH(ve_udplite_statistics, field); \ ++ else SNMP_INC_STATS_BH(ve_udp_statistics, field); } while(0) + + /* /proc */ + struct udp_seq_afinfo { +Index: kernel/init/Kconfig +=================================================================== +--- kernel.orig/init/Kconfig 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/init/Kconfig 2008-11-24 15:47:46.000000000 +0100 +@@ -208,7 +208,7 @@ + + config TASK_IO_ACCOUNTING + bool "Enable per-task storage I/O accounting (EXPERIMENTAL)" +- depends on TASK_XACCT ++ depends on TASK_XACCT && BEANCOUNTERS + help + Collect information on the number of bytes of storage I/O which this + task has caused. +@@ -347,6 +347,7 @@ + + config FAIR_USER_SCHED + bool "user id" ++ depends on !VE + help + This option will choose userid as the basis for grouping + tasks, thus providing equal CPU bandwidth to each user. +Index: kernel/init/calibrate.c +=================================================================== +--- kernel.orig/init/calibrate.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/init/calibrate.c 2008-11-24 15:47:46.000000000 +0100 +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -107,6 +108,60 @@ + static unsigned long __devinit calibrate_delay_direct(void) {return 0;} + #endif + ++unsigned long cycles_per_jiffy, cycles_per_clock; ++ ++static __devinit void calibrate_cycles(void) ++{ ++ unsigned long ticks; ++ cycles_t time; ++ ++ ticks = jiffies; ++ while (ticks == jiffies) ++ /* nothing */; ++ time = get_cycles(); ++ ticks = jiffies; ++ while (ticks == jiffies) ++ /* nothing */; ++ ++ time = get_cycles() - time; ++ cycles_per_jiffy = time; ++ if ((time >> 32) != 0) { ++ printk("CPU too fast! timings are incorrect\n"); ++ cycles_per_jiffy = -1; ++ } ++} ++ ++EXPORT_SYMBOL(cycles_per_jiffy); ++EXPORT_SYMBOL(cycles_per_clock); ++ ++static __devinit void calc_cycles_per_jiffy(void) ++{ ++#if 0 ++ extern unsigned long fast_gettimeoffset_quotient; ++ unsigned long low, high; ++ ++ if (fast_gettimeoffset_quotient != 0) { ++ __asm__("divl %2" ++ :"=a" (low), "=d" (high) ++ :"r" (fast_gettimeoffset_quotient), ++ "0" (0), "1" (1000000/HZ)); ++ ++ cycles_per_jiffy = low; ++ } ++#endif ++ if (cycles_per_jiffy == 0) ++ calibrate_cycles(); ++ ++ if (cycles_per_jiffy == 0) { ++ printk(KERN_WARNING "Cycles are stuck! " ++ "Some statistics will not be available."); ++ /* to prevent division by zero in cycles_to_(clocks|jiffies) */ ++ cycles_per_jiffy = 1; ++ cycles_per_clock = 1; ++ } else ++ cycles_per_clock = cycles_per_jiffy * (HZ / CLOCKS_PER_SEC); ++} ++ + /* + * This is the number of bits of precision for the loops_per_jiffy. Each + * bit takes on average 1.5/HZ seconds. This (like the original) is a little +@@ -172,4 +227,6 @@ + printk(KERN_CONT "%lu.%02lu BogoMIPS (lpj=%lu)\n", + loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy); ++ ++ calc_cycles_per_jiffy(); + } +Index: kernel/init/main.c +=================================================================== +--- kernel.orig/init/main.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/init/main.c 2008-11-24 15:47:46.000000000 +0100 +@@ -58,6 +58,8 @@ + #include + #include + ++#include ++ + #include + #include + #include +@@ -105,10 +107,25 @@ + #ifdef CONFIG_TC + extern void tc_init(void); + #endif ++extern void grsecurity_init(void); + + enum system_states system_state; + EXPORT_SYMBOL(system_state); + ++#ifdef CONFIG_VE ++extern void init_ve_system(void); ++extern void init_ve0(void); ++extern void prepare_ve0_process(struct task_struct *tsk); ++extern void prepare_ve0_proc_root(void); ++extern void prepare_ve0_sysctl(void); ++#else ++#define init_ve_system() do { } while (0) ++#define init_ve0() do { } while (0) ++#define prepare_ve0_process(tsk) do { } while (0) ++#define prepare_ve0_proc_root() do { } while (0) ++#define prepare_ve0_sysctl() do { } while (0) ++#endif ++ + /* + * Boot command-line arguments + */ +@@ -515,6 +532,9 @@ + + smp_setup_processor_id(); + ++ prepare_ve0_process(&init_task); ++ init_ve0(); ++ + /* + * Need to run as early as possible, to initialize the + * lockdep hash: +@@ -532,6 +552,7 @@ + * enable them + */ + lock_kernel(); ++ ub_init_early(); + tick_init(); + boot_cpu_init(); + page_address_init(); +@@ -627,6 +648,7 @@ + #endif + fork_init(num_physpages); + proc_caches_init(); ++ ub_init_late(); + buffer_init(); + unnamed_dev_init(); + key_init(); +@@ -637,6 +659,8 @@ + /* rootfs populating might need page-writeback */ + page_writeback_init(); + #ifdef CONFIG_PROC_FS ++ prepare_ve0_proc_root(); ++ prepare_ve0_sysctl(); + proc_root_init(); + #endif + cgroup_init(); +@@ -651,6 +675,10 @@ + #endif + acpi_early_init(); /* before LAPIC and SMP init */ + ++#ifdef CONFIG_BC_RSS_ACCOUNTING ++ ub_init_pbc(); ++#endif ++ + /* Do the rest non-__init'ed, we're now alive */ + rest_init(); + } +@@ -735,6 +763,8 @@ + */ + static void __init do_basic_setup(void) + { ++ init_ve_system(); ++ + /* drivers will send hotplug events */ + init_workqueues(); + usermodehelper_init(); +@@ -854,6 +884,8 @@ + prepare_namespace(); + } + ++ grsecurity_init(); ++ + /* + * Ok, we have completed the initial bootup, and + * we're essentially up and running. Get rid of the +Index: kernel/init/version.c +=================================================================== +--- kernel.orig/init/version.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/init/version.c 2008-11-24 15:47:46.000000000 +0100 +@@ -33,6 +33,12 @@ + }; + EXPORT_SYMBOL_GPL(init_uts_ns); + ++struct new_utsname virt_utsname = { ++ /* we need only this field */ ++ .release = UTS_RELEASE, ++}; ++EXPORT_SYMBOL(virt_utsname); ++ + /* FIXED STRINGS! Don't touch! */ + const char linux_banner[] = + "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" +Index: kernel/ipc/ipc_sysctl.c +=================================================================== +--- kernel.orig/ipc/ipc_sysctl.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/ipc/ipc_sysctl.c 2008-11-24 15:47:46.000000000 +0100 +@@ -102,6 +102,7 @@ + .mode = 0644, + .proc_handler = proc_ipc_doulongvec_minmax, + .strategy = sysctl_ipc_data, ++ .virt_handler = 1, + }, + { + .ctl_name = KERN_SHMALL, +@@ -111,6 +112,7 @@ + .mode = 0644, + .proc_handler = proc_ipc_doulongvec_minmax, + .strategy = sysctl_ipc_data, ++ .virt_handler = 1, + }, + { + .ctl_name = KERN_SHMMNI, +@@ -120,6 +122,7 @@ + .mode = 0644, + .proc_handler = proc_ipc_dointvec, + .strategy = sysctl_ipc_data, ++ .virt_handler = 1, + }, + { + .ctl_name = KERN_MSGMAX, +@@ -129,6 +132,7 @@ + .mode = 0644, + .proc_handler = proc_ipc_dointvec, + .strategy = sysctl_ipc_data, ++ .virt_handler = 1, + }, + { + .ctl_name = KERN_MSGMNI, +@@ -138,6 +142,7 @@ + .mode = 0644, + .proc_handler = proc_ipc_dointvec, + .strategy = sysctl_ipc_data, ++ .virt_handler = 1, + }, + { + .ctl_name = KERN_MSGMNB, +@@ -147,6 +152,7 @@ + .mode = 0644, + .proc_handler = proc_ipc_dointvec, + .strategy = sysctl_ipc_data, ++ .virt_handler = 1, + }, + { + .ctl_name = KERN_SEM, +@@ -156,6 +162,7 @@ + .mode = 0644, + .proc_handler = proc_ipc_dointvec, + .strategy = sysctl_ipc_data, ++ .virt_handler = 1, + }, + {} + }; +@@ -172,7 +179,7 @@ + + static int __init ipc_sysctl_init(void) + { +- register_sysctl_table(ipc_root_table); ++ register_glob_sysctl_table(ipc_root_table); + return 0; + } + +Index: kernel/ipc/msg.c +=================================================================== +--- kernel.orig/ipc/msg.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/ipc/msg.c 2008-11-24 15:47:46.000000000 +0100 +@@ -184,6 +184,7 @@ + int id, retval; + key_t key = params->key; + int msgflg = params->flg; ++ int msqid = params->id; + + msq = ipc_rcu_alloc(sizeof(*msq)); + if (!msq) +@@ -202,7 +203,7 @@ + /* + * ipc_addid() locks msq + */ +- id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); ++ id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni, msqid); + if (id < 0) { + security_msg_queue_free(msq); + ipc_rcu_putref(msq); +@@ -324,6 +325,7 @@ + + msg_params.key = key; + msg_params.flg = msgflg; ++ msg_params.id = -1; + + return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params); + } +@@ -552,7 +554,7 @@ + + err = -EPERM; + if (current->euid != ipcp->cuid && +- current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) ++ current->euid != ipcp->uid && !capable(CAP_VE_SYS_ADMIN)) + /* We _could_ check for CAP_CHOWN above, but we don't */ + goto out_unlock_up; + +@@ -968,3 +970,55 @@ + msq->q_ctime); + } + #endif ++ ++#ifdef CONFIG_VE ++#include ++ ++int sysvipc_setup_msg(key_t key, int msqid, int msgflg) ++{ ++ struct ipc_namespace *ns; ++ struct ipc_ops msg_ops; ++ struct ipc_params msg_params; ++ ++ ns = current->nsproxy->ipc_ns; ++ ++ msg_ops.getnew = newque; ++ msg_ops.associate = msg_security; ++ msg_ops.more_checks = NULL; ++ ++ msg_params.key = key; ++ msg_params.flg = msgflg | IPC_CREAT; ++ msg_params.id = msqid; ++ ++ return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params); ++} ++EXPORT_SYMBOL_GPL(sysvipc_setup_msg); ++ ++int sysvipc_walk_msg(int (*func)(int i, struct msg_queue*, void *), void *arg) ++{ ++ int err = 0; ++ struct msg_queue * msq; ++ struct ipc_namespace *ns; ++ int next_id; ++ int total, in_use; ++ ++ ns = current->nsproxy->ipc_ns; ++ ++ down_write(&msg_ids(ns).rw_mutex); ++ in_use = msg_ids(ns).in_use; ++ for (total = 0, next_id = 0; total < in_use; next_id++) { ++ msq = idr_find(&msg_ids(ns).ipcs_idr, next_id); ++ if (msq == NULL) ++ continue; ++ ipc_lock_by_ptr(&msq->q_perm); ++ err = func(msg_buildid(next_id, msq->q_perm.seq), msq, arg); ++ msg_unlock(msq); ++ if (err) ++ break; ++ total++; ++ } ++ up_write(&msg_ids(ns).rw_mutex); ++ return err; ++} ++EXPORT_SYMBOL_GPL(sysvipc_walk_msg); ++#endif +Index: kernel/ipc/msgutil.c +=================================================================== +--- kernel.orig/ipc/msgutil.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/ipc/msgutil.c 2008-11-24 15:47:46.000000000 +0100 +@@ -8,6 +8,7 @@ + * See the file COPYING for more details. + */ + ++#include + #include + #include + #include +@@ -17,6 +18,8 @@ + + #include "util.h" + ++#include ++ + struct msg_msgseg { + struct msg_msgseg* next; + /* the next part of the message follows immediately */ +@@ -25,52 +28,53 @@ + #define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg)) + #define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg)) + +-struct msg_msg *load_msg(const void __user *src, int len) ++struct msg_msg *sysv_msg_load(int (*load)(void * dst, int len, int offset, ++ void * data), int len, void * data) + { + struct msg_msg *msg; + struct msg_msgseg **pseg; + int err; + int alen; ++ int offset = 0; + + alen = len; + if (alen > DATALEN_MSG) + alen = DATALEN_MSG; + +- msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL); ++ msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL_UBC); + if (msg == NULL) + return ERR_PTR(-ENOMEM); + + msg->next = NULL; + msg->security = NULL; + +- if (copy_from_user(msg + 1, src, alen)) { ++ if (load(msg + 1, alen, offset, data)) { + err = -EFAULT; + goto out_err; + } + + len -= alen; +- src = ((char __user *)src) + alen; ++ offset += alen; + pseg = &msg->next; + while (len > 0) { + struct msg_msgseg *seg; + alen = len; + if (alen > DATALEN_SEG) + alen = DATALEN_SEG; +- seg = kmalloc(sizeof(*seg) + alen, +- GFP_KERNEL); ++ seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL_UBC); + if (seg == NULL) { + err = -ENOMEM; + goto out_err; + } + *pseg = seg; + seg->next = NULL; +- if (copy_from_user(seg + 1, src, alen)) { ++ if (load(seg + 1, alen, offset, data)) { + err = -EFAULT; + goto out_err; + } + pseg = &seg->next; + len -= alen; +- src = ((char __user *)src) + alen; ++ offset += alen; + } + + err = security_msg_msg_alloc(msg); +@@ -83,33 +87,58 @@ + free_msg(msg); + return ERR_PTR(err); + } ++EXPORT_SYMBOL_GPL(sysv_msg_load); + +-int store_msg(void __user *dest, struct msg_msg *msg, int len) ++static int do_load_msg(void * dst, int len, int offset, void * data) ++{ ++ return copy_from_user(dst, data + offset, len); ++} ++ ++struct msg_msg *load_msg(const void __user *src, int len) ++{ ++ return sysv_msg_load(do_load_msg, len, (void*)src); ++} ++ ++int sysv_msg_store(struct msg_msg *msg, ++ int (*store)(void * src, int len, int offset, void * data), ++ int len, void * data) + { + int alen; ++ int offset = 0; + struct msg_msgseg *seg; +- ++ + alen = len; + if (alen > DATALEN_MSG) + alen = DATALEN_MSG; +- if (copy_to_user(dest, msg + 1, alen)) ++ if (store(msg + 1, alen, offset, data)) + return -1; + + len -= alen; +- dest = ((char __user *)dest) + alen; ++ offset += alen; + seg = msg->next; + while (len > 0) { + alen = len; + if (alen > DATALEN_SEG) + alen = DATALEN_SEG; +- if (copy_to_user(dest, seg + 1, alen)) ++ if (store(seg + 1, alen, offset, data)) + return -1; + len -= alen; +- dest = ((char __user *)dest) + alen; ++ offset += alen; + seg = seg->next; + } + return 0; + } ++EXPORT_SYMBOL_GPL(sysv_msg_store); ++ ++static int do_store_msg(void * src, int len, int offset, void * data) ++{ ++ return copy_to_user(data + offset, src, len); ++} ++ ++int store_msg(void __user *dest, struct msg_msg *msg, int len) ++{ ++ return sysv_msg_store(msg, do_store_msg, len, dest); ++} + + void free_msg(struct msg_msg *msg) + { +Index: kernel/ipc/sem.c +=================================================================== +--- kernel.orig/ipc/sem.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/ipc/sem.c 2008-11-24 15:47:46.000000000 +0100 +@@ -86,6 +86,8 @@ + #include + #include "util.h" + ++#include ++ + #define sem_ids(ns) (*((ns)->ids[IPC_SEM_IDS])) + + #define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) +@@ -259,6 +261,7 @@ + key_t key = params->key; + int nsems = params->u.nsems; + int semflg = params->flg; ++ int semid = params->id; + + if (!nsems) + return -EINVAL; +@@ -282,7 +285,7 @@ + return retval; + } + +- id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); ++ id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni, semid); + if (id < 0) { + security_sem_free(sma); + ipc_rcu_putref(sma); +@@ -347,6 +350,7 @@ + sem_params.key = key; + sem_params.flg = semflg; + sem_params.u.nsems = nsems; ++ sem_params.id = -1; + + return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params); + } +@@ -925,7 +929,7 @@ + goto out_unlock; + } + if (current->euid != ipcp->cuid && +- current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) { ++ current->euid != ipcp->uid && !capable(CAP_VE_SYS_ADMIN)) { + err=-EPERM; + goto out_unlock; + } +@@ -1016,7 +1020,7 @@ + + undo_list = current->sysvsem.undo_list; + if (!undo_list) { +- undo_list = kzalloc(sizeof(*undo_list), GFP_KERNEL); ++ undo_list = kzalloc(sizeof(*undo_list), GFP_KERNEL_UBC); + if (undo_list == NULL) + return -ENOMEM; + spin_lock_init(&undo_list->lock); +@@ -1074,7 +1078,8 @@ + ipc_rcu_getref(sma); + sem_unlock(sma); + +- new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL); ++ new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, ++ GFP_KERNEL_UBC); + if (!new) { + ipc_lock_by_ptr(&sma->sem_perm); + ipc_rcu_putref(sma); +@@ -1134,7 +1139,7 @@ + if (nsops > ns->sc_semopm) + return -E2BIG; + if(nsops > SEMOPM_FAST) { +- sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL); ++ sops = kmalloc(sizeof(*sops)*nsops, GFP_KERNEL_UBC); + if(sops==NULL) + return -ENOMEM; + } +@@ -1415,3 +1420,57 @@ + sma->sem_ctime); + } + #endif ++ ++#ifdef CONFIG_VE ++#include ++ ++int sysvipc_setup_sem(key_t key, int semid, size_t size, int semflg) ++{ ++ struct ipc_namespace *ns; ++ struct ipc_ops sem_ops; ++ struct ipc_params sem_params; ++ ++ ns = current->nsproxy->ipc_ns; ++ ++ sem_ops.getnew = newary; ++ sem_ops.associate = sem_security; ++ sem_ops.more_checks = sem_more_checks; ++ ++ sem_params.key = key; ++ sem_params.flg = semflg | IPC_CREAT; ++ sem_params.u.nsems = size; ++ sem_params.id = semid; ++ ++ return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params); ++} ++EXPORT_SYMBOL_GPL(sysvipc_setup_sem); ++ ++int sysvipc_walk_sem(int (*func)(int i, struct sem_array*, void *), void *arg) ++{ ++ int err = 0; ++ struct sem_array *sma; ++ struct ipc_namespace *ns; ++ int next_id; ++ int total, in_use; ++ ++ ns = current->nsproxy->ipc_ns; ++ ++ down_write(&sem_ids(ns).rw_mutex); ++ in_use = sem_ids(ns).in_use; ++ for (total = 0, next_id = 0; total < in_use; next_id++) { ++ sma = idr_find(&sem_ids(ns).ipcs_idr, next_id); ++ if (sma == NULL) ++ continue; ++ ipc_lock_by_ptr(&sma->sem_perm); ++ err = func(sem_buildid(next_id, sma->sem_perm.seq), sma, arg); ++ sem_unlock(sma); ++ if (err) ++ break; ++ total++; ++ } ++ up_write(&sem_ids(ns).rw_mutex); ++ return err; ++} ++EXPORT_SYMBOL_GPL(sysvipc_walk_sem); ++EXPORT_SYMBOL_GPL(exit_sem); ++#endif +Index: kernel/ipc/shm.c +=================================================================== +--- kernel.orig/ipc/shm.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/ipc/shm.c 2008-11-24 15:47:46.000000000 +0100 +@@ -38,9 +38,13 @@ + #include + #include + #include ++#include + + #include + ++#include ++#include ++ + #include "util.h" + + struct shm_file_data { +@@ -185,9 +189,10 @@ + ipc_rmid(&shm_ids(ns), &s->shm_perm); + } + +-static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp) ++static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp, ++ int reqid) + { +- return ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); ++ return ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni, reqid); + } + + +@@ -207,6 +212,48 @@ + shm_unlock(shp); + } + ++static int shmem_lock(struct shmid_kernel *shp, int lock, ++ struct user_struct *user) ++{ ++ struct file *file = shp->shm_file; ++ struct inode *inode = file->f_path.dentry->d_inode; ++ struct shmem_inode_info *info = SHMEM_I(inode); ++ unsigned long size; ++ ++ size = shp->shm_segsz + PAGE_SIZE - 1; ++ ++#ifdef CONFIG_SHMEM ++ spin_lock(&info->lock); ++ if (lock && !(info->flags & VM_LOCKED)) { ++ if (ub_lockedshm_charge(info, size) < 0) ++ goto out_ch; ++ ++ if (!user_shm_lock(inode->i_size, user)) ++ goto out_user; ++ info->flags |= VM_LOCKED; ++ } ++ if (!lock && (info->flags & VM_LOCKED) && user) { ++ ub_lockedshm_uncharge(info, size); ++ user_shm_unlock(inode->i_size, user); ++ info->flags &= ~VM_LOCKED; ++ } ++ spin_unlock(&info->lock); ++ return 0; ++ ++out_user: ++ ub_lockedshm_uncharge(info, size); ++out_ch: ++ spin_unlock(&info->lock); ++ return -ENOMEM; ++#else ++ if (lock && ub_lockedshm_charge(info, size)) ++ return -ENOMEM; ++ if (!lock) ++ ub_lockedshm_uncharge(info, size); ++ return 0; ++#endif ++} ++ + /* + * shm_destroy - free the struct shmid_kernel + * +@@ -222,7 +269,7 @@ + shm_rmid(ns, shp); + shm_unlock(shp); + if (!is_file_hugepages(shp->shm_file)) +- shmem_lock(shp->shm_file, 0, shp->mlock_user); ++ shmem_lock(shp, 0, shp->mlock_user); + else + user_shm_unlock(shp->shm_file->f_path.dentry->d_inode->i_size, + shp->mlock_user); +@@ -385,11 +432,12 @@ + key_t key = params->key; + int shmflg = params->flg; + size_t size = params->u.size; ++ int shmid = params->id; + int error; + struct shmid_kernel *shp; + int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT; + struct file * file; +- char name[13]; ++ char name[64]; + int id; + + if (size < SHMMIN || size > ns->shm_ctlmax) +@@ -413,7 +461,7 @@ + return error; + } + +- sprintf (name, "SYSV%08x", key); ++ snprintf (name, sizeof(name), "VE%d-SYSV%08x", VEID(get_exec_env()), key); + if (shmflg & SHM_HUGETLB) { + /* hugetlb_file_setup takes care of mlock user accounting */ + file = hugetlb_file_setup(name, size); +@@ -433,7 +481,7 @@ + if (IS_ERR(file)) + goto no_file; + +- id = shm_addid(ns, shp); ++ id = shm_addid(ns, shp, shmid); + if (id < 0) { + error = id; + goto no_id; +@@ -507,6 +555,7 @@ + shm_params.key = key; + shm_params.flg = shmflg; + shm_params.u.size = size; ++ shm_params.id = -1; + + return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params); + } +@@ -785,14 +834,14 @@ + if(cmd==SHM_LOCK) { + struct user_struct * user = current->user; + if (!is_file_hugepages(shp->shm_file)) { +- err = shmem_lock(shp->shm_file, 1, user); ++ err = shmem_lock(shp, 1, user); + if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){ + shp->shm_perm.mode |= SHM_LOCKED; + shp->mlock_user = user; + } + } + } else if (!is_file_hugepages(shp->shm_file)) { +- shmem_lock(shp->shm_file, 0, shp->mlock_user); ++ shmem_lock(shp, 0, shp->mlock_user); + shp->shm_perm.mode &= ~SHM_LOCKED; + shp->mlock_user = NULL; + } +@@ -824,7 +873,7 @@ + + if (current->euid != shp->shm_perm.uid && + current->euid != shp->shm_perm.cuid && +- !capable(CAP_SYS_ADMIN)) { ++ !capable(CAP_VE_SYS_ADMIN)) { + err=-EPERM; + goto out_unlock_up; + } +@@ -864,7 +913,7 @@ + err=-EPERM; + if (current->euid != shp->shm_perm.uid && + current->euid != shp->shm_perm.cuid && +- !capable(CAP_SYS_ADMIN)) { ++ !capable(CAP_VE_SYS_ADMIN)) { + goto out_unlock_up; + } + +@@ -1177,3 +1226,67 @@ + shp->shm_ctim); + } + #endif ++ ++#ifdef CONFIG_VE ++#include ++ ++struct file * sysvipc_setup_shm(key_t key, int shmid, size_t size, int shmflg) ++{ ++ struct ipc_namespace *ns; ++ struct ipc_ops shm_ops; ++ struct ipc_params shm_params; ++ struct shmid_kernel *shp; ++ struct file *file; ++ int rv; ++ ++ ns = current->nsproxy->ipc_ns; ++ ++ shm_ops.getnew = newseg; ++ shm_ops.associate = shm_security; ++ shm_ops.more_checks = shm_more_checks; ++ ++ shm_params.key = key; ++ shm_params.flg = shmflg | IPC_CREAT; ++ shm_params.u.size = size; ++ shm_params.id = shmid; ++ ++ rv = ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params); ++ if (rv < 0) ++ return ERR_PTR(rv); ++ shp = shm_lock(ns, rv); ++ BUG_ON(IS_ERR(shp)); ++ file = shp->shm_file; ++ get_file(file); ++ shm_unlock(shp); ++ return file; ++} ++EXPORT_SYMBOL_GPL(sysvipc_setup_shm); ++ ++int sysvipc_walk_shm(int (*func)(struct shmid_kernel*, void *), void *arg) ++{ ++ int err = 0; ++ struct shmid_kernel* shp; ++ struct ipc_namespace *ns; ++ int next_id; ++ int total, in_use; ++ ++ ns = current->nsproxy->ipc_ns; ++ ++ down_write(&shm_ids(ns).rw_mutex); ++ in_use = shm_ids(ns).in_use; ++ for (total = 0, next_id = 0; total < in_use; next_id++) { ++ shp = idr_find(&shm_ids(ns).ipcs_idr, next_id); ++ if (shp == NULL) ++ continue; ++ ipc_lock_by_ptr(&shp->shm_perm); ++ err = func(shp, arg); ++ shm_unlock(shp); ++ if (err) ++ break; ++ total++; ++ } ++ up_write(&shm_ids(ns).rw_mutex); ++ return err; ++} ++EXPORT_SYMBOL_GPL(sysvipc_walk_shm); ++#endif +Index: kernel/ipc/util.c +=================================================================== +--- kernel.orig/ipc/util.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/ipc/util.c 2008-11-24 15:47:46.000000000 +0100 +@@ -36,6 +36,8 @@ + + #include + ++#include ++ + #include "util.h" + + struct ipc_proc_iface { +@@ -258,6 +260,7 @@ + * @ids: IPC identifier set + * @new: new IPC permission set + * @size: limit for the number of used ids ++ * @reqid: if >= 0, get this id exactly. If -1 -- don't care. + * + * Add an entry 'new' to the IPC ids idr. The permissions object is + * initialised and the first free entry is set up and the id assigned +@@ -267,10 +270,18 @@ + * Called with ipc_ids.rw_mutex held as a writer. + */ + +-int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) ++int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size, int reqid) + { + int id, err; + ++ if (reqid >= 0) { ++ id = reqid % SEQ_MULTIPLIER; ++ err = idr_get_new_above(&ids->ipcs_idr, new, id, &id); ++ if (err || id != (reqid % SEQ_MULTIPLIER)) ++ return -1; ++ goto found; ++ } ++ + if (size > IPCMNI) + size = IPCMNI; + +@@ -280,15 +291,19 @@ + err = idr_get_new(&ids->ipcs_idr, new, &id); + if (err) + return err; +- ++found: + ids->in_use++; + + new->cuid = new->uid = current->euid; + new->gid = new->cgid = current->egid; + +- new->seq = ids->seq++; +- if(ids->seq > ids->seq_max) +- ids->seq = 0; ++ if (reqid >= 0) { ++ new->seq = reqid/SEQ_MULTIPLIER; ++ } else { ++ new->seq = ids->seq++; ++ if(ids->seq > ids->seq_max) ++ ids->seq = 0; ++ } + + spin_lock_init(&new->lock); + new->deleted = 0; +@@ -455,9 +470,9 @@ + { + void* out; + if(size > PAGE_SIZE) +- out = vmalloc(size); ++ out = ub_vmalloc(size); + else +- out = kmalloc(size, GFP_KERNEL); ++ out = kmalloc(size, GFP_KERNEL_UBC); + return out; + } + +@@ -540,14 +555,14 @@ + * workqueue if necessary (for vmalloc). + */ + if (rcu_use_vmalloc(size)) { +- out = vmalloc(HDRLEN_VMALLOC + size); ++ out = ub_vmalloc(HDRLEN_VMALLOC + size); + if (out) { + out += HDRLEN_VMALLOC; + container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 1; + container_of(out, struct ipc_rcu_hdr, data)->refcount = 1; + } + } else { +- out = kmalloc(HDRLEN_KMALLOC + size, GFP_KERNEL); ++ out = kmalloc(HDRLEN_KMALLOC + size, GFP_KERNEL_UBC); + if (out) { + out += HDRLEN_KMALLOC; + container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 0; +Index: kernel/ipc/util.h +=================================================================== +--- kernel.orig/ipc/util.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/ipc/util.h 2008-11-24 15:47:46.000000000 +0100 +@@ -47,6 +47,7 @@ + size_t size; /* for shared memories */ + int nsems; /* for semaphores */ + } u; /* holds the getnew() specific param */ ++ int id; + }; + + /* +@@ -82,7 +83,7 @@ + #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER) + + /* must be called with ids->rw_mutex acquired for writing */ +-int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); ++int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int, int); + + /* must be called with ids->rw_mutex acquired for reading */ + int ipc_get_maxid(struct ipc_ids *); +Index: kernel/kernel/Kconfig.openvz +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/Kconfig.openvz 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,80 @@ ++# Copyright (C) 2005 SWsoft ++# All rights reserved. ++# Licensing governed by "linux/COPYING.SWsoft" file. ++ ++menu "OpenVZ" ++ ++config VE ++ bool "Virtual Environment support" ++ default y ++ select PID_NS ++ select NET_NS ++ select USER_NS ++ help ++ This option adds support of virtual Linux running on the original box ++ with fully supported virtual network driver, tty subsystem and ++ configurable access for hardware and other resources. ++ ++config VE_CALLS ++ tristate "VE calls interface" ++ depends on VE ++ select VZ_DEV ++ default m ++ help ++ This option controls how to build vzmon code containing VE calls. ++ By default it's build in module vzmon.o ++ ++config VZ_GENCALLS ++ bool ++ default y ++ ++config VE_NETDEV ++ tristate "VE network device" ++ depends on VE_CALLS && NET ++ select VZ_DEV ++ default m ++ help ++ This option controls whether to build venet device. This is a ++ common interface for networking in VE. ++ ++config VE_ETHDEV ++ tristate "Virtual ethernet device" ++ depends on VE_CALLS && NET ++ select VZ_DEV ++ default m ++ help ++ This option controls whether to build virtual ethernet device. ++ ++config VZ_DEV ++ tristate "VE device" ++ default m ++ help ++ This option adds support of vzdev device, which is used by ++ user-space applications to control Virtual Environments. ++ ++config VE_IPTABLES ++ bool "VE netfiltering" ++ depends on VE && VE_NETDEV && INET && NETFILTER ++ default y ++ help ++ This option controls whether to build VE netfiltering code. ++ ++config VZ_WDOG ++ tristate "VE watchdog module" ++ depends on VE_CALLS ++ default m ++ help ++ This option controls building of vzwdog module, which dumps ++ a lot of useful system info on console periodically. ++ ++config VZ_CHECKPOINT ++ tristate "Checkpointing & restoring Virtual Environments" ++ depends on VE_CALLS && INET ++ select PM_SLEEP ++ default m ++ help ++ This option adds two modules, "cpt" and "rst", which allow ++ to save a running Virtual Environment and restore it ++ on another host (live migration) or on the same host (checkpointing). ++ ++endmenu +Index: kernel/kernel/Makefile +=================================================================== +--- kernel.orig/kernel/Makefile 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/Makefile 2008-11-24 15:47:46.000000000 +0100 +@@ -14,6 +14,10 @@ + obj-$(CONFIG_SYSCTL) += sysctl_check.o + obj-$(CONFIG_STACKTRACE) += stacktrace.o + obj-y += time/ ++obj-$(CONFIG_BEANCOUNTERS) += bc/ ++obj-y += ve/ ++obj-$(CONFIG_VZ_CHECKPOINT) += cpt/ ++ + obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o + obj-$(CONFIG_LOCKDEP) += lockdep.o + ifeq ($(CONFIG_PROC_FS),y) +Index: kernel/kernel/audit.c +=================================================================== +--- kernel.orig/kernel/audit.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/audit.c 2008-11-24 15:47:46.000000000 +0100 +@@ -586,6 +586,9 @@ + char *ctx; + u32 len; + ++ if (!ve_is_super(skb->owner_env)) ++ return -ECONNREFUSED; ++ + err = audit_netlink_ok(skb, msg_type); + if (err) + return err; +Index: kernel/kernel/auditfilter.c +=================================================================== +--- kernel.orig/kernel/auditfilter.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/auditfilter.c 2008-11-24 15:47:46.000000000 +0100 +@@ -167,7 +167,7 @@ + inotify_init_watch(&parent->wdata); + /* grab a ref so inotify watch hangs around until we take audit_filter_mutex */ + get_inotify_watch(&parent->wdata); +- wd = inotify_add_watch(audit_ih, &parent->wdata, ndp->dentry->d_inode, ++ wd = inotify_add_watch_dget(audit_ih, &parent->wdata, ndp->dentry, ndp->mnt, + AUDIT_IN_WATCH); + if (wd < 0) { + audit_free_parent(&parent->wdata); +Index: kernel/kernel/bc/Kconfig +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/Kconfig 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,111 @@ ++# ++# User resources part (UBC) ++# ++# Copyright (C) 2005 SWsoft ++# All rights reserved. ++# ++# Licensing governed by "linux/COPYING.SWsoft" file. ++ ++menu "User resources" ++ ++config BEANCOUNTERS ++ bool "Enable user resource accounting" ++ default y ++ help ++ This patch provides accounting and allows to configure ++ limits for user's consumption of exhaustible system resources. ++ The most important resource controlled by this patch is unswappable ++ memory (either mlock'ed or used by internal kernel structures and ++ buffers). The main goal of this patch is to protect processes ++ from running short of important resources because of an accidental ++ misbehavior of processes or malicious activity aiming to ``kill'' ++ the system. It's worth to mention that resource limits configured ++ by setrlimit(2) do not give an acceptable level of protection ++ because they cover only small fraction of resources and work on a ++ per-process basis. Per-process accounting doesn't prevent malicious ++ users from spawning a lot of resource-consuming processes. ++ ++config BC_RSS_ACCOUNTING ++ bool "Account physical memory usage" ++ default y ++ depends on BEANCOUNTERS ++ help ++ This allows to estimate per beancounter physical memory usage. ++ Implemented alghorithm accounts shared pages of memory as well, ++ dividing them by number of beancounter which use the page. ++ ++config BC_IO_ACCOUNTING ++ bool "Account disk IO" ++ default y ++ depends on BC_RSS_ACCOUNTING ++ help ++ When on this option allows seeing disk IO activity caused by ++ tasks from each UB ++ ++config BC_IO_SCHED ++ bool "UBC I/O priority" ++ default y ++ depends on BC_IO_ACCOUNTING && IOSCHED_CFQ ++ help ++ This option controls whether to build CFQ I/O scheduler ++ with support of UBC I/O priority. ++ ++config BC_SWAP_ACCOUNTING ++ bool "Account swap usage" ++ default y ++ depends on BEANCOUNTERS ++ help ++ This allows accounting of swap usage. ++ ++config BC_PROC ++ bool "Report resource usage in /proc" ++ default y ++ depends on BEANCOUNTERS ++ help ++ Allows a system administrator to inspect resource accounts and limits. ++ ++config BC_DEBUG ++ bool "User resources debug features" ++ default n ++ depends on BEANCOUNTERS ++ help ++ Enables to setup debug features for user resource accounting ++ ++config BC_DEBUG_IO ++ bool "Debug IO accounting" ++ default y ++ depends on BC_DEBUG && BC_IO_ACCOUNTING ++ help ++ Debugging for IO accointing. ++ ++config BC_DEBUG_KMEM ++ bool "Debug kmemsize with cache counters" ++ default n ++ depends on BC_DEBUG ++ help ++ Adds /proc/user_beancounters_debug entry to get statistics ++ about cache usage of each beancounter ++ ++config BC_KEEP_UNUSED ++ bool "Keep unused beancounter alive" ++ default y ++ depends on BC_DEBUG ++ help ++ If on, unused beancounters are kept on the hash and maxheld value ++ can be looked through. ++ ++config BC_DEBUG_ITEMS ++ bool "Account resources in items rather than in bytes" ++ default y ++ depends on BC_DEBUG ++ help ++ When true some of the resources (e.g. kmemsize) are accounted ++ in items instead of bytes. ++ ++config BC_UNLIMITED ++ bool "Use unlimited ubc settings" ++ default y ++ depends on BC_DEBUG ++ help ++ When ON all limits and barriers are set to max values. ++endmenu +Index: kernel/kernel/bc/Makefile +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/Makefile 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,16 @@ ++# ++# User resources part (UBC) ++# ++# Copyright (C) 2005 SWsoft ++# All rights reserved. ++# ++# Licensing governed by "linux/COPYING.SWsoft" file. ++ ++obj-y := sys.o beancounter.o dcache.o kmem.o misc.o \ ++ vm_pages.o statd.o oom_kill.o ++ ++obj-$(CONFIG_NET) += net.o ++obj-$(CONFIG_BC_RSS_ACCOUNTING) += rss_pages.o ++obj-$(CONFIG_BC_PROC) += proc.o ++obj-$(CONFIG_BC_IO_ACCOUNTING) += io_acct.o ++obj-$(CONFIG_BC_IO_SCHED) += io_prio.o +Index: kernel/kernel/bc/beancounter.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/beancounter.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,676 @@ ++/* ++ * linux/kernel/bc/beancounter.c ++ * ++ * Copyright (C) 1998 Alan Cox ++ * 1998-2000 Andrey V. Savochkin ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * TODO: ++ * - more intelligent limit check in mremap(): currently the new size is ++ * charged and _then_ old size is uncharged ++ * (almost done: !move_vma case is completely done, ++ * move_vma in its current implementation requires too many conditions to ++ * do things right, because it may be not only expansion, but shrinking ++ * also, plus do_munmap will require an additional parameter...) ++ * - problem: bad pmd page handling ++ * - consider /proc redesign ++ * - TCP/UDP ports ++ * + consider whether __charge_beancounter_locked should be inline ++ * ++ * Changes: ++ * 1999/08/17 Marcelo Tosatti ++ * - Set "barrier" and "limit" parts of limits atomically. ++ * 1999/10/06 Marcelo Tosatti ++ * - setublimit system call. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++static struct kmem_cache *ub_cachep; ++static struct user_beancounter default_beancounter; ++struct user_beancounter ub0; ++EXPORT_SYMBOL_GPL(ub0); ++ ++const char *ub_rnames[] = { ++ "kmemsize", /* 0 */ ++ "lockedpages", ++ "privvmpages", ++ "shmpages", ++ "dummy", ++ "numproc", /* 5 */ ++ "physpages", ++ "vmguarpages", ++ "oomguarpages", ++ "numtcpsock", ++ "numflock", /* 10 */ ++ "numpty", ++ "numsiginfo", ++ "tcpsndbuf", ++ "tcprcvbuf", ++ "othersockbuf", /* 15 */ ++ "dgramrcvbuf", ++ "numothersock", ++ "dcachesize", ++ "numfile", ++ "dummy", /* 20 */ ++ "dummy", ++ "dummy", ++ "numiptent", ++ "unused_privvmpages", /* UB_RESOURCES */ ++ "tmpfs_respages", ++ "swap_pages", ++ "held_pages", ++}; ++ ++static void init_beancounter_struct(struct user_beancounter *ub); ++static void init_beancounter_store(struct user_beancounter *ub); ++static void init_beancounter_nolimits(struct user_beancounter *ub); ++ ++int print_ub_uid(struct user_beancounter *ub, char *buf, int size) ++{ ++ if (ub->parent != NULL) ++ return snprintf(buf, size, "%u.%u", ++ ub->parent->ub_uid, ub->ub_uid); ++ else ++ return snprintf(buf, size, "%u", ub->ub_uid); ++} ++EXPORT_SYMBOL(print_ub_uid); ++ ++#define ub_hash_fun(x) ((((x) >> 8) ^ (x)) & (UB_HASH_SIZE - 1)) ++#define ub_subhash_fun(p, id) ub_hash_fun((p)->ub_uid + (id) * 17) ++struct hlist_head ub_hash[UB_HASH_SIZE]; ++DEFINE_SPINLOCK(ub_hash_lock); ++LIST_HEAD(ub_list_head); /* protected by ub_hash_lock */ ++EXPORT_SYMBOL(ub_hash); ++EXPORT_SYMBOL(ub_hash_lock); ++EXPORT_SYMBOL(ub_list_head); ++ ++/* ++ * Per user resource beancounting. Resources are tied to their luid. ++ * The resource structure itself is tagged both to the process and ++ * the charging resources (a socket doesn't want to have to search for ++ * things at irq time for example). Reference counters keep things in ++ * hand. ++ * ++ * The case where a user creates resource, kills all his processes and ++ * then starts new ones is correctly handled this way. The refcounters ++ * will mean the old entry is still around with resource tied to it. ++ */ ++ ++static inline void free_ub(struct user_beancounter *ub) ++{ ++ free_percpu(ub->ub_percpu); ++ kmem_cache_free(ub_cachep, ub); ++} ++ ++static inline struct user_beancounter *bc_lookup_hash(struct hlist_head *hash, ++ uid_t uid, struct user_beancounter *parent) ++{ ++ struct user_beancounter *ub; ++ struct hlist_node *ptr; ++ ++ hlist_for_each_entry (ub, ptr, hash, ub_hash) ++ if (ub->ub_uid == uid && ub->parent == parent) ++ return get_beancounter(ub); ++ ++ return NULL; ++} ++ ++struct user_beancounter *get_beancounter_byuid(uid_t uid, int create) ++{ ++ struct user_beancounter *new_ub, *ub; ++ unsigned long flags; ++ struct hlist_head *hash; ++ ++ hash = &ub_hash[ub_hash_fun(uid)]; ++ new_ub = NULL; ++retry: ++ spin_lock_irqsave(&ub_hash_lock, flags); ++ ub = bc_lookup_hash(hash, uid, NULL); ++ if (ub != NULL) { ++ spin_unlock_irqrestore(&ub_hash_lock, flags); ++ ++ if (new_ub != NULL) ++ free_ub(new_ub); ++ return ub; ++ } ++ ++ if (!create) { ++ /* no ub found */ ++ spin_unlock_irqrestore(&ub_hash_lock, flags); ++ return NULL; ++ } ++ ++ if (new_ub != NULL) { ++ list_add_rcu(&new_ub->ub_list, &ub_list_head); ++ hlist_add_head(&new_ub->ub_hash, hash); ++ spin_unlock_irqrestore(&ub_hash_lock, flags); ++ return new_ub; ++ } ++ spin_unlock_irqrestore(&ub_hash_lock, flags); ++ ++ /* alloc new ub */ ++ new_ub = (struct user_beancounter *)kmem_cache_alloc(ub_cachep, ++ GFP_KERNEL); ++ if (new_ub == NULL) ++ return NULL; ++ ++ ub_debug(UBD_ALLOC, "Creating ub %p\n", new_ub); ++ memcpy(new_ub, &default_beancounter, sizeof(*new_ub)); ++ init_beancounter_struct(new_ub); ++ new_ub->ub_percpu = alloc_percpu(struct ub_percpu_struct); ++ if (new_ub->ub_percpu == NULL) ++ goto fail_free; ++ new_ub->ub_uid = uid; ++ goto retry; ++ ++fail_free: ++ kmem_cache_free(ub_cachep, new_ub); ++ return NULL; ++} ++EXPORT_SYMBOL(get_beancounter_byuid); ++ ++struct user_beancounter *get_subbeancounter_byid(struct user_beancounter *p, ++ int id, int create) ++{ ++ struct user_beancounter *new_ub, *ub; ++ unsigned long flags; ++ struct hlist_head *hash; ++ ++ hash = &ub_hash[ub_subhash_fun(p, id)]; ++ new_ub = NULL; ++retry: ++ spin_lock_irqsave(&ub_hash_lock, flags); ++ ub = bc_lookup_hash(hash, id, p); ++ if (ub != NULL) { ++ spin_unlock_irqrestore(&ub_hash_lock, flags); ++ ++ if (new_ub != NULL) { ++ put_beancounter(new_ub->parent); ++ free_ub(new_ub); ++ } ++ return ub; ++ } ++ ++ if (!create) { ++ /* no ub found */ ++ spin_unlock_irqrestore(&ub_hash_lock, flags); ++ return NULL; ++ } ++ ++ if (new_ub != NULL) { ++ list_add_rcu(&new_ub->ub_list, &ub_list_head); ++ hlist_add_head(&new_ub->ub_hash, hash); ++ spin_unlock_irqrestore(&ub_hash_lock, flags); ++ return new_ub; ++ } ++ spin_unlock_irqrestore(&ub_hash_lock, flags); ++ ++ /* alloc new ub */ ++ new_ub = (struct user_beancounter *)kmem_cache_alloc(ub_cachep, ++ GFP_KERNEL); ++ if (new_ub == NULL) ++ return NULL; ++ ++ ub_debug(UBD_ALLOC, "Creating sub %p\n", new_ub); ++ memset(new_ub, 0, sizeof(*new_ub)); ++ init_beancounter_nolimits(new_ub); ++ init_beancounter_store(new_ub); ++ init_beancounter_struct(new_ub); ++ new_ub->ub_percpu = alloc_percpu(struct ub_percpu_struct); ++ if (new_ub->ub_percpu == NULL) ++ goto fail_free; ++ new_ub->ub_uid = id; ++ new_ub->parent = get_beancounter(p); ++ goto retry; ++ ++fail_free: ++ kmem_cache_free(ub_cachep, new_ub); ++ return NULL; ++} ++EXPORT_SYMBOL(get_subbeancounter_byid); ++ ++static void put_warn(struct user_beancounter *ub) ++{ ++ char id[64]; ++ ++ print_ub_uid(ub, id, sizeof(id)); ++ printk(KERN_ERR "UB: Bad refcount (%d) on put of %s (%p)\n", ++ atomic_read(&ub->ub_refcount), id, ub); ++} ++ ++#ifdef CONFIG_BC_KEEP_UNUSED ++#define release_beancounter(ub) do { } while (0) ++#else ++static int verify_res(struct user_beancounter *ub, int resource, ++ unsigned long held) ++{ ++ char id[64]; ++ ++ if (likely(held == 0)) ++ return 1; ++ ++ print_ub_uid(ub, id, sizeof(id)); ++ printk(KERN_WARNING "Ub %s helds %lu in %s on put\n", ++ id, held, ub_rnames[resource]); ++ return 0; ++} ++ ++static inline void bc_verify_held(struct user_beancounter *ub) ++{ ++ int i, clean; ++ ++ clean = 1; ++ for (i = 0; i < UB_RESOURCES; i++) ++ clean &= verify_res(ub, i, ub->ub_parms[i].held); ++ ++ clean &= verify_res(ub, UB_UNUSEDPRIVVM, ub->ub_unused_privvmpages); ++ clean &= verify_res(ub, UB_TMPFSPAGES, ub->ub_tmpfs_respages); ++ clean &= verify_res(ub, UB_SWAPPAGES, ub->ub_swap_pages); ++ clean &= verify_res(ub, UB_HELDPAGES, (unsigned long)ub->ub_held_pages); ++ ++ ub_debug_trace(!clean, 5, 60*HZ); ++} ++ ++static void bc_free_rcu(struct rcu_head *rcu) ++{ ++ struct user_beancounter *ub; ++ ++ ub = container_of(rcu, struct user_beancounter, rcu); ++ free_ub(ub); ++} ++ ++static void delayed_release_beancounter(struct work_struct *w) ++{ ++ struct user_beancounter *ub, *parent; ++ unsigned long flags; ++ ++ ub = container_of(w, struct user_beancounter, cleanup.work); ++again: ++ local_irq_save(flags); ++ if (!atomic_dec_and_lock(&ub->ub_refcount, &ub_hash_lock)) { ++ /* raced with get_beancounter_byuid */ ++ local_irq_restore(flags); ++ return; ++ } ++ ++ hlist_del(&ub->ub_hash); ++ list_del_rcu(&ub->ub_list); ++ spin_unlock_irqrestore(&ub_hash_lock, flags); ++ ++ bc_verify_held(ub); ++ ub_free_counters(ub); ++ bc_fini_ioprio(&ub->iopriv); ++ parent = ub->parent; ++ ++ call_rcu(&ub->rcu, bc_free_rcu); ++ if (parent) { ++ ub = parent; ++ goto again; ++ } ++} ++ ++static inline void release_beancounter(struct user_beancounter *ub) ++{ ++ struct execute_work *ew; ++ ++ ew = &ub->cleanup; ++ INIT_WORK(&ew->work, delayed_release_beancounter); ++ schedule_work(&ew->work); ++} ++#endif ++ ++void __put_beancounter(struct user_beancounter *ub) ++{ ++ unsigned long flags; ++ ++ /* equevalent to atomic_dec_and_lock_irqsave() */ ++ local_irq_save(flags); ++ if (likely(!atomic_dec_and_lock(&ub->ub_refcount, &ub_hash_lock))) { ++ if (unlikely(atomic_read(&ub->ub_refcount) < 0)) ++ put_warn(ub); ++ local_irq_restore(flags); ++ return; ++ } ++ ++ if (unlikely(ub == get_ub0())) { ++ printk(KERN_ERR "Trying to put ub0\n"); ++ spin_unlock_irqrestore(&ub_hash_lock, flags); ++ return; ++ } ++ ++ /* prevent get_beancounter_byuid + put_beancounter() reentrance */ ++ atomic_inc(&ub->ub_refcount); ++ spin_unlock_irqrestore(&ub_hash_lock, flags); ++ ++ release_beancounter(ub); ++} ++EXPORT_SYMBOL(__put_beancounter); ++ ++void put_beancounter_safe(struct user_beancounter *ub) ++{ ++ synchronize_rcu(); ++ __put_beancounter(ub); ++} ++EXPORT_SYMBOL(put_beancounter_safe); ++ ++/* ++ * Generic resource charging stuff ++ */ ++ ++int __charge_beancounter_locked(struct user_beancounter *ub, ++ int resource, unsigned long val, enum ub_severity strict) ++{ ++ ub_debug_resource(resource, "Charging %lu for %d of %p with %lu\n", ++ val, resource, ub, ub->ub_parms[resource].held); ++ /* ++ * ub_value <= UB_MAXVALUE, value <= UB_MAXVALUE, and only one addition ++ * at the moment is possible so an overflow is impossible. ++ */ ++ ub->ub_parms[resource].held += val; ++ ++ switch (strict) { ++ case UB_HARD: ++ if (ub->ub_parms[resource].held > ++ ub->ub_parms[resource].barrier) ++ break; ++ case UB_SOFT: ++ if (ub->ub_parms[resource].held > ++ ub->ub_parms[resource].limit) ++ break; ++ case UB_FORCE: ++ ub_adjust_maxheld(ub, resource); ++ return 0; ++ default: ++ BUG(); ++ } ++ ++ if (strict == UB_SOFT && ub_ratelimit(&ub->ub_limit_rl)) ++ printk(KERN_INFO "Fatal resource shortage: %s, UB %d.\n", ++ ub_rnames[resource], ub->ub_uid); ++ ub->ub_parms[resource].failcnt++; ++ ub->ub_parms[resource].held -= val; ++ return -ENOMEM; ++} ++ ++int charge_beancounter(struct user_beancounter *ub, ++ int resource, unsigned long val, enum ub_severity strict) ++{ ++ int retval; ++ struct user_beancounter *p, *q; ++ unsigned long flags; ++ ++ retval = -EINVAL; ++ if (val > UB_MAXVALUE) ++ goto out; ++ ++ local_irq_save(flags); ++ for (p = ub; p != NULL; p = p->parent) { ++ spin_lock(&p->ub_lock); ++ retval = __charge_beancounter_locked(p, resource, val, strict); ++ spin_unlock(&p->ub_lock); ++ if (retval) ++ goto unroll; ++ } ++out_restore: ++ local_irq_restore(flags); ++out: ++ return retval; ++ ++unroll: ++ for (q = ub; q != p; q = q->parent) { ++ spin_lock(&q->ub_lock); ++ __uncharge_beancounter_locked(q, resource, val); ++ spin_unlock(&q->ub_lock); ++ } ++ goto out_restore; ++} ++ ++EXPORT_SYMBOL(charge_beancounter); ++ ++void __charge_beancounter_notop(struct user_beancounter *ub, ++ int resource, unsigned long val) ++{ ++ struct user_beancounter *p; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ for (p = ub; p->parent != NULL; p = p->parent) { ++ spin_lock(&p->ub_lock); ++ __charge_beancounter_locked(p, resource, val, UB_FORCE); ++ spin_unlock(&p->ub_lock); ++ } ++ local_irq_restore(flags); ++} ++ ++EXPORT_SYMBOL(__charge_beancounter_notop); ++ ++void uncharge_warn(struct user_beancounter *ub, int resource, ++ unsigned long val, unsigned long held) ++{ ++ char id[64]; ++ ++ print_ub_uid(ub, id, sizeof(id)); ++ printk(KERN_ERR "Uncharging too much %lu h %lu, res %s ub %s\n", ++ val, held, ub_rnames[resource], id); ++ ub_debug_trace(1, 10, 10*HZ); ++} ++ ++void __uncharge_beancounter_locked(struct user_beancounter *ub, ++ int resource, unsigned long val) ++{ ++ ub_debug_resource(resource, "Uncharging %lu for %d of %p with %lu\n", ++ val, resource, ub, ub->ub_parms[resource].held); ++ if (ub->ub_parms[resource].held < val) { ++ uncharge_warn(ub, resource, ++ val, ub->ub_parms[resource].held); ++ val = ub->ub_parms[resource].held; ++ } ++ ub->ub_parms[resource].held -= val; ++} ++ ++void uncharge_beancounter(struct user_beancounter *ub, ++ int resource, unsigned long val) ++{ ++ unsigned long flags; ++ struct user_beancounter *p; ++ ++ for (p = ub; p != NULL; p = p->parent) { ++ spin_lock_irqsave(&p->ub_lock, flags); ++ __uncharge_beancounter_locked(p, resource, val); ++ spin_unlock_irqrestore(&p->ub_lock, flags); ++ } ++} ++ ++EXPORT_SYMBOL(uncharge_beancounter); ++ ++void __uncharge_beancounter_notop(struct user_beancounter *ub, ++ int resource, unsigned long val) ++{ ++ struct user_beancounter *p; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ for (p = ub; p->parent != NULL; p = p->parent) { ++ spin_lock(&p->ub_lock); ++ __uncharge_beancounter_locked(p, resource, val); ++ spin_unlock(&p->ub_lock); ++ } ++ local_irq_restore(flags); ++} ++ ++EXPORT_SYMBOL(__uncharge_beancounter_notop); ++ ++ ++/* ++ * Rate limiting stuff. ++ */ ++int ub_ratelimit(struct ub_rate_info *p) ++{ ++ unsigned long cjif, djif; ++ unsigned long flags; ++ static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED; ++ long new_bucket; ++ ++ spin_lock_irqsave(&ratelimit_lock, flags); ++ cjif = jiffies; ++ djif = cjif - p->last; ++ if (djif < p->interval) { ++ if (p->bucket >= p->burst) { ++ spin_unlock_irqrestore(&ratelimit_lock, flags); ++ return 0; ++ } ++ p->bucket++; ++ } else { ++ new_bucket = p->bucket - (djif / (unsigned)p->interval); ++ if (new_bucket < 0) ++ new_bucket = 0; ++ p->bucket = new_bucket + 1; ++ } ++ p->last = cjif; ++ spin_unlock_irqrestore(&ratelimit_lock, flags); ++ return 1; ++} ++EXPORT_SYMBOL(ub_ratelimit); ++ ++ ++/* ++ * Initialization ++ * ++ * struct user_beancounter contains ++ * - limits and other configuration settings, ++ * with a copy stored for accounting purposes, ++ * - structural fields: lists, spinlocks and so on. ++ * ++ * Before these parts are initialized, the structure should be memset ++ * to 0 or copied from a known clean structure. That takes care of a lot ++ * of fields not initialized explicitly. ++ */ ++ ++static void init_beancounter_struct(struct user_beancounter *ub) ++{ ++ ub->ub_magic = UB_MAGIC; ++ atomic_set(&ub->ub_refcount, 1); ++ spin_lock_init(&ub->ub_lock); ++ INIT_LIST_HEAD(&ub->ub_tcp_sk_list); ++ INIT_LIST_HEAD(&ub->ub_other_sk_list); ++#ifdef CONFIG_BC_DEBUG_KMEM ++ INIT_LIST_HEAD(&ub->ub_cclist); ++#endif ++ bc_init_ioprio(&ub->iopriv); ++} ++ ++static void init_beancounter_store(struct user_beancounter *ub) ++{ ++ int k; ++ ++ for (k = 0; k < UB_RESOURCES; k++) { ++ memcpy(&ub->ub_store[k], &ub->ub_parms[k], ++ sizeof(struct ubparm)); ++ } ++} ++ ++static void init_beancounter_nolimits(struct user_beancounter *ub) ++{ ++ int k; ++ ++ for (k = 0; k < UB_RESOURCES; k++) { ++ ub->ub_parms[k].limit = UB_MAXVALUE; ++ /* FIXME: whether this is right for physpages and guarantees? */ ++ ub->ub_parms[k].barrier = UB_MAXVALUE; ++ } ++ ++ /* FIXME: set unlimited rate? */ ++ ub->ub_limit_rl.burst = 4; ++ ub->ub_limit_rl.interval = 300*HZ; ++} ++ ++static void init_beancounter_syslimits(struct user_beancounter *ub) ++{ ++ unsigned long mp; ++ extern int max_threads; ++ int k; ++ ++ mp = num_physpages; ++ ub->ub_parms[UB_KMEMSIZE].limit = ++ mp > (192*1024*1024 >> PAGE_SHIFT) ? ++ 32*1024*1024 : (mp << PAGE_SHIFT) / 6; ++ ub->ub_parms[UB_LOCKEDPAGES].limit = 8; ++ ub->ub_parms[UB_PRIVVMPAGES].limit = UB_MAXVALUE; ++ ub->ub_parms[UB_SHMPAGES].limit = 64; ++ ub->ub_parms[UB_NUMPROC].limit = max_threads / 2; ++ ub->ub_parms[UB_NUMTCPSOCK].limit = 1024; ++ ub->ub_parms[UB_TCPSNDBUF].limit = 1024*4*1024; /* 4k per socket */ ++ ub->ub_parms[UB_TCPRCVBUF].limit = 1024*6*1024; /* 6k per socket */ ++ ub->ub_parms[UB_NUMOTHERSOCK].limit = 256; ++ ub->ub_parms[UB_DGRAMRCVBUF].limit = 256*4*1024; /* 4k per socket */ ++ ub->ub_parms[UB_OTHERSOCKBUF].limit = 256*8*1024; /* 8k per socket */ ++ ub->ub_parms[UB_NUMFLOCK].limit = 1024; ++ ub->ub_parms[UB_NUMPTY].limit = 16; ++ ub->ub_parms[UB_NUMSIGINFO].limit = 1024; ++ ub->ub_parms[UB_DCACHESIZE].limit = 1024*1024; ++ ub->ub_parms[UB_NUMFILE].limit = 1024; ++ ++ for (k = 0; k < UB_RESOURCES; k++) ++ ub->ub_parms[k].barrier = ub->ub_parms[k].limit; ++ ++ ub->ub_limit_rl.burst = 4; ++ ub->ub_limit_rl.interval = 300*HZ; ++} ++ ++#ifdef CONFIG_SMP ++static struct percpu_data ub0_percpu; ++#endif ++static struct ub_percpu_struct ub0_percpu_data[NR_CPUS]; ++ ++void __init ub_init_early(void) ++{ ++ struct user_beancounter *ub; ++ ++ init_cache_counters(); ++ ub = get_ub0(); ++ memset(ub, 0, sizeof(*ub)); ++ ub->ub_uid = 0; ++ init_beancounter_nolimits(ub); ++ init_beancounter_store(ub); ++ init_beancounter_struct(ub); ++ ub->ub_percpu = static_percpu_ptr(&ub0_percpu, ub0_percpu_data); ++ ++ memset(¤t->task_bc, 0, sizeof(struct task_beancounter)); ++ (void)set_exec_ub(ub); ++ current->task_bc.task_ub = get_beancounter(ub); ++ __charge_beancounter_locked(ub, UB_NUMPROC, 1, UB_FORCE); ++ current->task_bc.fork_sub = get_beancounter(ub); ++ ub_init_task_bc(¤t->task_bc); ++ init_mm.mm_ub = get_beancounter(ub); ++ ++ hlist_add_head(&ub->ub_hash, &ub_hash[ub->ub_uid]); ++ list_add(&ub->ub_list, &ub_list_head); ++} ++ ++void __init ub_init_late(void) ++{ ++ ub_cachep = kmem_cache_create("user_beancounters", ++ sizeof(struct user_beancounter), ++ 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); ++ ++ memset(&default_beancounter, 0, sizeof(default_beancounter)); ++#ifdef CONFIG_BC_UNLIMITED ++ init_beancounter_nolimits(&default_beancounter); ++#else ++ init_beancounter_syslimits(&default_beancounter); ++#endif ++ init_beancounter_store(&default_beancounter); ++ init_beancounter_struct(&default_beancounter); ++} +Index: kernel/kernel/bc/dcache.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/dcache.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,562 @@ ++/* ++ * kernel/bc/dcache.c ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * Locking ++ * traverse dcache_lock d_lock ++ * ub_dentry_charge + - + ++ * ub_dentry_uncharge + + - ++ * ub_dentry_charge_nofail + + - ++ * ++ * d_inuse changes are atomic, with special handling of "not in use" <-> ++ * "in use" (-1 <-> 0) transitions. We have two sources of non-atomicity ++ * here: (1) in many operations we need to change d_inuse of both dentry and ++ * its parent, and (2) on state transitions we need to adjust the account. ++ * ++ * Regarding (1): we do not have (and do not want) a single lock covering all ++ * operations, so in general it's impossible to get a consistent view of ++ * a tree with respect to d_inuse counters (except by swsuspend). It also ++ * means if a dentry with d_inuse of 0 gets one new in-use child and loses ++ * one, it's d_inuse counter will go either 0 -> 1 -> 0 path or 0 -> -1 -> 0, ++ * and we can't say which way. ++ * Note that path -1 -> 0 -> -1 can't turn into -1 -> -2 -> -1, since ++ * uncharge can be done only after return from charge (with d_genocide being ++ * the only apparent exception). ++ * Regarding (2): there is a similar uncertainty with the dcache account. ++ * If the account is equal to the limit, one more dentry is started to be ++ * used and one is put, the account will either hit the limit (and an error ++ * will be returned), or decrement will happen before increment. ++ * ++ * These races do not really matter. ++ * The only things we want are: ++ * - if a system is suspenede with no in-use dentries, all d_inuse counters ++ * should be correct (-1); ++ * - d_inuse counters should always be >= -1. ++ * This holds if ->parent references are accessed and maintained properly. ++ * In subtle moments (like d_move) dentries exchanging their parents should ++ * both be in-use. At d_genocide time, lookups and charges are assumed to be ++ * impossible. ++ */ ++ ++/* ++ * Hierarchical accounting ++ * UB argument must NOT be NULL ++ */ ++ ++static int do_charge_dcache(struct user_beancounter *ub, unsigned long size, ++ enum ub_severity sv) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ if (__charge_beancounter_locked(ub, UB_KMEMSIZE, CHARGE_SIZE(size), sv)) ++ goto out_mem; ++ if (__charge_beancounter_locked(ub, UB_DCACHESIZE, size, sv)) ++ goto out_dcache; ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ return 0; ++ ++out_dcache: ++ __uncharge_beancounter_locked(ub, UB_KMEMSIZE, CHARGE_SIZE(size)); ++out_mem: ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ return -ENOMEM; ++} ++ ++static void do_uncharge_dcache(struct user_beancounter *ub, ++ unsigned long size) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ __uncharge_beancounter_locked(ub, UB_KMEMSIZE, CHARGE_SIZE(size)); ++ __uncharge_beancounter_locked(ub, UB_DCACHESIZE, size); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++static int charge_dcache(struct user_beancounter *ub, unsigned long size, ++ enum ub_severity sv) ++{ ++ struct user_beancounter *p, *q; ++ ++ for (p = ub; p != NULL; p = p->parent) { ++ if (do_charge_dcache(p, size, sv)) ++ goto unroll; ++ } ++ return 0; ++ ++unroll: ++ for (q = ub; q != p; q = q->parent) ++ do_uncharge_dcache(q, size); ++ return -ENOMEM; ++} ++ ++void uncharge_dcache(struct user_beancounter *ub, unsigned long size) ++{ ++ for (; ub != NULL; ub = ub->parent) ++ do_uncharge_dcache(ub, size); ++} ++ ++/* ++ * Simple helpers to do maintain account and d_ub field. ++ */ ++ ++static inline int d_charge(struct dentry_beancounter *d_bc) ++{ ++ struct user_beancounter *ub; ++ ++ ub = get_beancounter(get_exec_ub()); ++ if (charge_dcache(ub, d_bc->d_ubsize, UB_SOFT)) { ++ put_beancounter(ub); ++ return -1; ++ } ++ d_bc->d_ub = ub; ++ return 0; ++} ++ ++static inline void d_forced_charge(struct dentry_beancounter *d_bc) ++{ ++ struct user_beancounter *ub; ++ ++ ub = get_beancounter(get_exec_ub()); ++ charge_dcache(ub, d_bc->d_ubsize, UB_FORCE); ++ d_bc->d_ub = ub; ++} ++ ++/* ++ * Minor helpers ++ */ ++ ++extern struct kmem_cache *dentry_cache; ++extern struct kmem_cache *inode_cachep; ++static struct rw_semaphore ub_dentry_alloc_sem; ++ ++static inline unsigned long d_charge_size(struct dentry *dentry) ++{ ++ /* dentry's d_name is already set to appropriate value (see d_alloc) */ ++ return kmem_cache_objuse(inode_cachep) + kmem_cache_objuse(dentry_cache) + ++ (dname_external(dentry) ? ++ kmem_obj_objuse((void *)dentry->d_name.name) : 0); ++} ++ ++/* ++ * Entry points from dcache.c ++ */ ++ ++/* ++ * Set initial d_inuse on d_alloc. ++ * Called with no locks, preemption disabled. ++ */ ++int __ub_dentry_alloc(struct dentry *dentry) ++{ ++ struct dentry_beancounter *d_bc; ++ ++ d_bc = &dentry->dentry_bc; ++ d_bc->d_ub = get_beancounter(get_exec_ub()); ++ atomic_set(&d_bc->d_inuse, INUSE_INIT); /* see comment in dcache.h */ ++ d_bc->d_ubsize = d_charge_size(dentry); ++ ++ if (charge_dcache(d_bc->d_ub, d_bc->d_ubsize, UB_HARD)) ++ goto failure; ++ return 0; ++ ++failure: ++ put_beancounter(d_bc->d_ub); ++ d_bc->d_ub = NULL; ++ return -ENOMEM; ++} ++void __ub_dentry_alloc_start(void) ++{ ++ down_read(&ub_dentry_alloc_sem); ++ current->task_bc.dentry_alloc = 1; ++} ++ ++void __ub_dentry_alloc_end(void) ++{ ++ current->task_bc.dentry_alloc = 0; ++ up_read(&ub_dentry_alloc_sem); ++} ++ ++/* ++ * It is assumed that parent is already in use, so traverse upwards is ++ * limited to one ancestor only. ++ * Called under d_lock and rcu_read_lock. ++ */ ++int __ub_dentry_charge(struct dentry *dentry) ++{ ++ struct dentry_beancounter *d_bc; ++ struct dentry *parent; ++ int ret; ++ ++ if (ub_dget_testone(dentry)) { ++ d_bc = &dentry->dentry_bc; ++ /* state transition -1 => 0 */ ++ if (d_charge(d_bc)) ++ goto failure; ++ ++ if (dentry != dentry->d_parent) { ++ parent = dentry->d_parent; ++ if (ub_dget_testone(parent)) ++ BUG(); ++ } ++ } ++ return 0; ++ ++failure: ++ /* ++ * Here we would like to fail the lookup. ++ * It is not easy: if d_lookup fails, callers expect that a dentry ++ * with the given name doesn't exist, and create a new one. ++ * So, first we forcedly charge for this dentry. ++ * Then try to remove it from cache safely. If it turns out to be ++ * possible, we can return error. ++ */ ++ d_forced_charge(d_bc); ++ ++ if (dentry != dentry->d_parent) { ++ parent = dentry->d_parent; ++ if (ub_dget_testone(parent)) ++ BUG(); ++ } ++ ++ ret = 0; ++ if (spin_trylock(&dcache_lock)) { ++ if (!list_empty(&dentry->d_subdirs)) { ++ spin_unlock(&dentry->d_lock); ++ spin_unlock(&dcache_lock); ++ rcu_read_unlock(); ++ shrink_dcache_parent(dentry); ++ rcu_read_lock(); ++ spin_lock(&dcache_lock); ++ spin_lock(&dentry->d_lock); ++ } ++ if (atomic_read(&dentry->d_count) == 1) { ++ __d_drop(dentry); ++ ret = -1; ++ } ++ spin_unlock(&dcache_lock); ++ } ++ ++ return ret; ++} ++ ++/* ++ * Go up in the tree decreasing d_inuse. ++ * Called under dcache_lock. ++ */ ++void __ub_dentry_uncharge(struct dentry *dentry) ++{ ++ struct dentry *parent; ++ struct user_beancounter *ub; ++ unsigned long size; ++ ++ /* go up until state doesn't change or and root is reached */ ++ size = dentry->dentry_bc.d_ubsize; ++ ub = dentry->dentry_bc.d_ub; ++ while (ub_dput_testzero(dentry)) { ++ /* state transition 0 => -1 */ ++ uncharge_dcache(ub, size); ++ put_beancounter(ub); ++ ++ parent = dentry->d_parent; ++ if (dentry == parent) ++ break; ++ ++ dentry = parent; ++ size = dentry->dentry_bc.d_ubsize; ++ ub = dentry->dentry_bc.d_ub; ++ } ++} ++ ++/* ++ * Forced charge for __dget_locked, where API doesn't allow to return error. ++ * Called under dcache_lock. ++ */ ++void __ub_dentry_charge_nofail(struct dentry *dentry) ++{ ++ struct dentry *parent; ++ ++ while (ub_dget_testone(dentry)) { ++ /* state transition -1 => 0 */ ++ d_forced_charge(&dentry->dentry_bc); ++ ++ parent = dentry->d_parent; ++ if (dentry == parent) ++ break; ++ dentry = parent; ++ } ++} ++ ++/* ++ * Adaptive accounting ++ */ ++ ++int ub_dentry_on = 1; ++int ub_dentry_alloc_barrier; ++EXPORT_SYMBOL(ub_dentry_on); ++ ++static DEFINE_PER_CPU(int, checkcnt); ++static unsigned long checklowat = 0; ++static unsigned long checkhiwat = ULONG_MAX; ++ ++static int sysctl_ub_dentry_chk = 10; ++#define sysctl_ub_lowat sysctl_ub_watermark[0] ++#define sysctl_ub_hiwat sysctl_ub_watermark[1] ++static DECLARE_RWSEM(ub_dentry_alloc_sem); ++/* 1024th of lowmem size */ ++static unsigned int sysctl_ub_watermark[2] = {0, 100}; ++ ++ ++static int ub_dentry_acctinit(struct dentry *dentry) ++{ ++ struct dentry_beancounter *d_bc; ++ ++ d_bc = &dentry->dentry_bc; ++ d_bc->d_ub = NULL; ++ atomic_set(&d_bc->d_inuse, -1); ++#if 0 ++ if (dname_external(dentry)) { ++ struct page *page; ++ page = virt_to_page(dentry->d_name.name); ++ if (!PageSlab(page) || page_get_cache(page) == NULL) { ++ printk("Problem with name, dentry %p, parent %p, " ++ "name %p len %d\n", ++ dentry, dentry->d_parent, ++ dentry->d_name.name, ++ dentry->d_name.len); ++ printk(" de %p name %.10s\n", ++ dentry, dentry->d_name.name); ++ d_bc->d_ubsize = 0; ++ return 0; ++ } ++ } ++#endif ++ d_bc->d_ubsize = d_charge_size(dentry); ++ return 0; ++} ++ ++static int ub_dentry_acctcount(struct dentry *dentry) ++{ ++ struct dentry_beancounter *d_bc; ++ struct dentry *child; ++ int count; ++ ++ count = 0; ++ list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) ++ count++; ++ ++ d_bc = &dentry->dentry_bc; ++ count = atomic_read(&dentry->d_count) - count; ++ if (count) { ++ __ub_dentry_charge_nofail(dentry); ++ if (count > 1) ++ atomic_add(count - 1, &d_bc->d_inuse); ++ } ++ ++ return 0; ++} ++ ++static int ub_dentry_acctdrop(struct dentry *dentry) ++{ ++ struct dentry_beancounter *d_bc; ++ ++ d_bc = &dentry->dentry_bc; ++ if (atomic_read(&d_bc->d_inuse) < 0) ++ return 0; ++ atomic_set(&d_bc->d_inuse, -1); ++ uncharge_dcache(d_bc->d_ub, d_bc->d_ubsize); ++ put_beancounter(d_bc->d_ub); ++ return 0; ++} ++ ++static inline int ub_dentry_walk(int (*fun)(struct dentry *d)) ++{ ++ return kmem_cache_walk_objects(dentry_cache, ++ (int (*)(void *))fun); ++} ++ ++static int ub_dentry_accton(void *data) ++{ ++ struct user_beancounter *ub; ++ int err; ++ ++ ub = get_exec_ub(); ++ set_exec_ub(get_ub0()); ++ err = ub_dentry_walk(&ub_dentry_acctinit); ++ if (!err) ++ err = ub_dentry_walk(&ub_dentry_acctcount); ++ set_exec_ub(ub); ++ if (err == 0) ++ ub_dentry_on = 1; ++ return err; ++} ++ ++static int ub_dentry_acctoff(void *data) ++{ ++ int ret; ++ ret = ub_dentry_walk(&ub_dentry_acctdrop); ++ if (ret == 0) ++ ub_dentry_on = 0; ++ return ret; ++} ++ ++/* ++ * Main function turning dcache accounting on and off. ++ * Called with preemption disabled (for caller's convenience). ++ */ ++static void ub_dentry_switch(int onoff, unsigned long pages, int (*fun)(void *)) ++{ ++ static char *s[] = { "off", "on" }; ++ unsigned long start_jiffies; ++ int err, tm; ++ ++ start_jiffies = jiffies; ++ preempt_enable(); ++ ub_dentry_alloc_barrier = 1; ++ /* ensure ub_dentry_alloc_barrier is visible on all CPUs */ ++ mb(); ++ synchronize_rcu(); ++ down_write(&ub_dentry_alloc_sem); ++ if (ub_dentry_on == onoff) ++ goto done; ++ ++ printk("UBC: preparing to turn dcache accounting %s, " ++ "size %lu pages, watermarks %lu %lu\n", ++ s[onoff], pages, checklowat, checkhiwat); ++ err = stop_machine_run(fun, NULL, NR_CPUS); ++ if (err) { ++ printk(KERN_ERR "UBC: ERROR: dcache accounting switch %d\n", ++ err); ++ preempt_disable(); ++ checklowat = 0; ++ checkhiwat = ULONG_MAX; ++ sysctl_ub_dentry_chk = INT_MAX; ++ preempt_enable(); ++ } else { ++ tm = jiffies_to_msecs(jiffies - start_jiffies); ++ printk("UBC: turning dcache accounting %s succeeded, " ++ "usage %lu, time %u.%03u\n", ++ s[onoff], ++ get_ub0()->ub_parms[UB_DCACHESIZE].held, ++ tm / 1000, tm % 1000); ++ } ++ ++done: ++ ub_dentry_alloc_barrier = 0; ++ up_write(&ub_dentry_alloc_sem); ++ preempt_disable(); ++} ++ ++void ub_dentry_checkup(void) ++{ ++ int *p; ++ unsigned long pages; ++ ++ preempt_disable(); ++ p = &__get_cpu_var(checkcnt); ++ if (++*p > sysctl_ub_dentry_chk) { ++ *p = 0; ++ pages = ub_cache_growth(dentry_cache); ++ if (ub_dentry_on) { ++ if (pages < checklowat) ++ ub_dentry_switch(0, pages, &ub_dentry_acctoff); ++ } else { ++ if (pages >= checkhiwat) ++ ub_dentry_switch(1, pages, &ub_dentry_accton); ++ } ++ } ++ preempt_enable(); ++} ++ ++static void ub_dentry_set_limits(unsigned long pages, unsigned long cap) ++{ ++ down_write(&ub_dentry_alloc_sem); ++ preempt_disable(); ++ checklowat = (pages >> 10) * sysctl_ub_lowat; ++ checkhiwat = (pages >> 10) * sysctl_ub_hiwat; ++ if (checkhiwat > cap) { ++ checkhiwat = cap; ++ checklowat = cap / sysctl_ub_hiwat * sysctl_ub_lowat; ++ } ++ preempt_enable(); ++ up_write(&ub_dentry_alloc_sem); ++} ++ ++static int ub_dentry_proc_handler(ctl_table *ctl, int write, struct file *filp, ++ void __user *buffer, size_t *lenp, loff_t *ppos) ++{ ++ int r; ++ ++ r = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); ++ if (!r && write) ++ ub_dentry_set_limits(totalram_pages - totalhigh_pages, ++ ULONG_MAX); ++ return r; ++} ++ ++static ctl_table ub_dentry_sysctl_table[] = { ++ { ++ .procname = "dentry_check", ++ .data = &sysctl_ub_dentry_chk, ++ .maxlen = sizeof(sysctl_ub_dentry_chk), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, ++ { ++ .procname = "dentry_watermark", ++ .data = &sysctl_ub_lowat, ++ .maxlen = sizeof(sysctl_ub_lowat) * 2, ++ .mode = 0644, ++ .proc_handler = ub_dentry_proc_handler, ++ }, ++ { .ctl_name = 0 } ++}; ++static ctl_table ub_dentry_sysctl_root[] = { ++ { ++ .procname = "ubc", ++ .mode = 0555, ++ .child = ub_dentry_sysctl_table, ++ }, ++ { .ctl_name = 0 } ++}; ++ ++static int __init ub_dentry_init(void) ++{ ++ /* ++ * Initial watermarks are limited, to limit walk time. ++ * 384MB translates into 0.8 sec on PIII 866MHz. ++ */ ++ ub_dentry_set_limits(totalram_pages - totalhigh_pages, ++ 384 * 1024 * 1024 / PAGE_SIZE); ++ if (register_sysctl_table(ub_dentry_sysctl_root) == NULL) ++ return -ENOMEM; ++ return 0; ++} ++__initcall(ub_dentry_init); +Index: kernel/kernel/bc/io_acct.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/io_acct.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,514 @@ ++/* ++ * kernel/bc/io_acct.c ++ * ++ * Copyright (C) 2006 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * Pavel Emelianov ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++static struct mempool_s *pb_pool; ++ ++#define PB_MIN_IO (1024) ++ ++static inline struct page_beancounter *io_pb_alloc(void) ++{ ++ return mempool_alloc(pb_pool, GFP_ATOMIC); ++} ++ ++static inline void io_pb_free(struct page_beancounter *pb) ++{ ++ mempool_free(pb, pb_pool); ++} ++ ++struct page_beancounter **page_pblist(struct page *page) ++{ ++ struct page_beancounter **pb, *iopb; ++ ++ pb = &page_pbc(page); ++ iopb = iopb_to_pb(*pb); ++ ++ return iopb == NULL ? pb : &iopb->page_pb_list; ++} ++ ++/* ++ * We save the context page was set dirty to use it later ++ * when the real write starts. If the page is mapped then ++ * IO pb is stores like this: ++ * ++ * Before saving: ++ * ++ * +- page -------+ ++ * | ... | ++ * | page_pb +---+ ++ * +--------------+ | +-----+ +-----+ +-----+ ++ * +-> | pb1 | -> | pb2 | - ... -> | pbN | -+ ++ * +-----+ +-----+ +-----+ | ++ * ^ | ++ * +---------------------------------+ ++ * ++ * After saving: ++ * ++ * +- page -------+ +- io pb ------+ ++ * | ... | | ... | ++ * | page_pb +----> | page_pb_list +-+ ++ * +--------------+ +--------------+ | ++ * | ++ * +-------------------+ ++ * | ++ * | +-----+ +-----+ +-----+ ++ * +-> | pb1 | -> | pb2 | - ... -> | pbN | -+ ++ * +-----+ +-----+ +-----+ | ++ * ^ | ++ * +---------------------------------+ ++ * ++ * And the page_pblist(...) function returns pointer to the place that ++ * points to this pbX ring. ++ */ ++ ++#ifdef CONFIG_BC_DEBUG_IO ++static LIST_HEAD(pb_io_list); ++static unsigned long anon_pages, not_released; ++ ++static inline void io_debug_save(struct page_beancounter *pb, ++ struct page_beancounter *mpb) ++{ ++ pb->io_debug = (mpb == NULL); ++ list_add(&pb->io_list, &pb_io_list); ++} ++ ++static inline void io_debug_release(struct page_beancounter *pb) ++{ ++ list_del(&pb->io_list); ++} ++ ++void ub_io_release_debug(struct page *page) ++{ ++ struct page_beancounter *pb; ++ static int once = 0; ++ ++ pb = page_pbc(page); ++ if (likely(iopb_to_pb(pb) == NULL)) ++ return; ++ ++ if (!once) { ++ printk("BUG: Page has an IO bc but is not expectd to\n"); ++ dump_stack(); ++ once = 1; ++ } ++ ++ spin_lock(&pb_lock); ++ not_released++; ++ pb = iopb_to_pb(pb); ++ page_pbc(page) = NULL; ++ io_debug_release(pb); ++ pb->ub->io_pb_held--; ++ spin_unlock(&pb_lock); ++ ++ put_beancounter(pb->ub); ++ io_pb_free(pb); ++} ++ ++static inline int io_debug_precheck_save(struct page *page) ++{ ++ if (unlikely(PageAnon(page))) { ++ anon_pages++; ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static inline int io_debug_precheck_release(struct page *page) ++{ ++ return 0; ++} ++#else ++#define io_debug_save(pb, mpb) do { } while (0) ++#define io_debug_release(pb) do { } while (0) ++#define io_debug_precheck_save(page) (0) ++#define io_debug_precheck_release(p) (0) ++#endif ++ ++static inline void set_page_io(struct page *page, struct page_beancounter *pb, ++ struct page_beancounter *mapped_pb) ++{ ++ unsigned long val; ++ ++ val = (unsigned long)pb | PAGE_IO_MARK; ++ pb->page = page; ++ ++ page_pbc(page) = (struct page_beancounter *)val; ++ io_debug_save(pb, mapped_pb); ++ pb->ub->io_pb_held++; ++} ++ ++static inline void put_page_io(struct page *page, struct page_beancounter *pb) ++{ ++ pb->ub->io_pb_held--; ++ io_debug_release(pb); ++ page_pbc(page) = pb->page_pb_list; ++} ++ ++void ub_io_save_context(struct page *page, size_t bytes_dirtied) ++{ ++ struct user_beancounter *ub; ++ struct page_beancounter *pb, *mapped_pb, *io_pb; ++ ++ if (unlikely(in_interrupt())) { ++ WARN_ON_ONCE(1); ++ return; ++ } ++ ++ /* ++ * FIXME - this can happen from atomic context and ++ * it's probably not that good to loose some requests ++ */ ++ ++ pb = io_pb_alloc(); ++ io_pb = NULL; ++ ++ spin_lock(&pb_lock); ++ if (io_debug_precheck_save(page)) ++ goto out_unlock; ++ ++ mapped_pb = page_pbc(page); ++ io_pb = iopb_to_pb(mapped_pb); ++ if (io_pb != NULL) { ++ /* ++ * this page has an IO - release it and force a new one ++ * We could also race with page cleaning - see below ++ */ ++ mapped_pb = io_pb->page_pb_list; ++ put_page_io(page, io_pb); ++ } ++ ++ /* ++ * If the page is mapped we must save the context ++ * it maps to. If the page isn't mapped we use current ++ * context as this is a regular write. ++ */ ++ ++ if (mapped_pb != NULL) ++ ub = top_beancounter(mapped_pb->ub); ++ else ++ ub = get_io_ub(); ++ ++ if (!PageDirty(page)) { ++ /* ++ * race with clear_page_dirty(_for_io) - account ++ * writes for ub_io_release_context() ++ */ ++ if (io_pb != NULL) ++ io_pb->ub->bytes_wrote += PAGE_CACHE_SIZE; ++ if (pb != NULL) ++ io_pb_free(pb); ++ goto out_unlock; ++ } ++ ++ if (pb == NULL) { ++ ub->bytes_dirty_missed += bytes_dirtied; ++ goto out_unlock; ++ } ++ ++ /* ++ * the page may become clean here, but the context will be seen ++ * in ub_io_release_context() ++ */ ++ ++ pb->ub = get_beancounter(ub); ++ pb->page_pb_list = mapped_pb; ++ ub->bytes_dirtied += bytes_dirtied; ++ ++ set_page_io(page, pb, mapped_pb); ++ ++out_unlock: ++ spin_unlock(&pb_lock); ++ ++ if (io_pb != NULL) { ++ put_beancounter(io_pb->ub); ++ io_pb_free(io_pb); ++ } ++} ++ ++void ub_io_release_context(struct page *page, size_t wrote) ++{ ++ struct page_beancounter *pb; ++ ++ if (io_debug_precheck_release(page)) ++ return; ++ ++ if (unlikely(in_interrupt())) { ++ WARN_ON_ONCE(1); ++ return; ++ } ++ ++ spin_lock(&pb_lock); ++ pb = iopb_to_pb(page_pbc(page)); ++ if (unlikely(pb == NULL)) ++ /* ++ * this may happen if we failed to allocate ++ * context in ub_io_save_context or raced with it ++ */ ++ goto out_unlock; ++ ++ if (wrote) ++ pb->ub->bytes_wrote += wrote; ++ ++ put_page_io(page, pb); ++out_unlock: ++ spin_unlock(&pb_lock); ++ ++ if (pb != NULL) { ++ put_beancounter(pb->ub); ++ io_pb_free(pb); ++ } ++} ++ ++void __init ub_init_io(struct kmem_cache *pb_cachep) ++{ ++ pb_pool = mempool_create_slab_pool(PB_MIN_IO, pb_cachep); ++ if (pb_pool == NULL) ++ panic("Can't create pb_pool"); ++} ++ ++#ifdef CONFIG_PROC_FS ++#define in_flight(var) (var > var##_done ? var - var##_done : 0) ++ ++static int bc_ioacct_show(struct seq_file *f, void *v) ++{ ++ int i; ++ unsigned long long read, write, cancel; ++ unsigned long sync, sync_done; ++ unsigned long fsync, fsync_done; ++ unsigned long fdsync, fdsync_done; ++ unsigned long frsync, frsync_done; ++ unsigned long reads, writes; ++ unsigned long long rchar, wchar; ++ struct user_beancounter *ub; ++ ++ ub = seq_beancounter(f); ++ ++ read = write = cancel = 0; ++ sync = sync_done = fsync = fsync_done = ++ fdsync = fdsync_done = frsync = frsync_done = 0; ++ reads = writes = 0; ++ rchar = wchar = 0; ++ for_each_online_cpu(i) { ++ struct ub_percpu_struct *ub_percpu; ++ ub_percpu = per_cpu_ptr(ub->ub_percpu, i); ++ ++ read += ub_percpu->bytes_read; ++ write += ub_percpu->bytes_wrote; ++ cancel += ub_percpu->bytes_cancelled; ++ ++ sync += ub_percpu->sync; ++ fsync += ub_percpu->fsync; ++ fdsync += ub_percpu->fdsync; ++ frsync += ub_percpu->frsync; ++ sync_done += ub_percpu->sync_done; ++ fsync_done += ub_percpu->fsync_done; ++ fdsync_done += ub_percpu->fdsync_done; ++ frsync_done += ub_percpu->frsync_done; ++ ++ reads += ub_percpu->read; ++ writes += ub_percpu->write; ++ rchar += ub_percpu->rchar; ++ wchar += ub_percpu->wchar; ++ } ++ ++ seq_printf(f, bc_proc_llu_fmt, "read", read); ++ seq_printf(f, bc_proc_llu_fmt, "write", ub->bytes_wrote + write); ++ seq_printf(f, bc_proc_llu_fmt, "dirty", ub->bytes_dirtied); ++ seq_printf(f, bc_proc_llu_fmt, "cancel", cancel); ++ seq_printf(f, bc_proc_llu_fmt, "missed", ub->bytes_dirty_missed); ++ ++ seq_printf(f, bc_proc_lu_lfmt, "syncs_total", sync); ++ seq_printf(f, bc_proc_lu_lfmt, "fsyncs_total", fsync); ++ seq_printf(f, bc_proc_lu_lfmt, "fdatasyncs_total", fdsync); ++ seq_printf(f, bc_proc_lu_lfmt, "range_syncs_total", frsync); ++ ++ seq_printf(f, bc_proc_lu_lfmt, "syncs_active", in_flight(sync)); ++ seq_printf(f, bc_proc_lu_lfmt, "fsyncs_active", in_flight(fsync)); ++ seq_printf(f, bc_proc_lu_lfmt, "fdatasyncs_active", in_flight(fsync)); ++ seq_printf(f, bc_proc_lu_lfmt, "range_syncs_active", in_flight(frsync)); ++ ++ seq_printf(f, bc_proc_lu_lfmt, "vfs_reads", reads); ++ seq_printf(f, bc_proc_llu_fmt, "vfs_read_chars", rchar); ++ seq_printf(f, bc_proc_lu_lfmt, "vfs_writes", writes); ++ seq_printf(f, bc_proc_llu_fmt, "vfs_write_chars", wchar); ++ ++ seq_printf(f, bc_proc_lu_lfmt, "io_pbs", ub->io_pb_held); ++ return 0; ++} ++ ++static struct bc_proc_entry bc_ioacct_entry = { ++ .name = "ioacct", ++ .u.show = bc_ioacct_show, ++}; ++ ++#ifdef CONFIG_BC_DEBUG_IO ++#define PTR_SIZE (int)(sizeof(void *) * 2) ++#define INT_SIZE (int)(sizeof(int) * 2) ++ ++static int bc_io_show(struct seq_file *f, void *v) ++{ ++ struct list_head *lh; ++ struct page_beancounter *pb; ++ struct page *pg; ++ ++ lh = (struct list_head *)v; ++ if (lh == &pb_io_list) { ++ seq_printf(f, "Races: anon %lu missed %lu\n", ++ anon_pages, not_released); ++ ++ seq_printf(f, "%-*s %-1s %-*s %-4s %*s %*s " ++ "%-*s %-*s %-1s %-*s %-*s\n", ++ PTR_SIZE, "pb", "", ++ PTR_SIZE, "page", "flg", ++ INT_SIZE, "cnt", INT_SIZE, "mcnt", ++ PTR_SIZE, "pb_list", ++ PTR_SIZE, "page_pb", "", ++ PTR_SIZE, "mapping", ++ INT_SIZE, "ub"); ++ return 0; ++ } ++ ++ pb = list_entry(lh, struct page_beancounter, io_list); ++ pg = pb->page; ++ seq_printf(f, "%p %c %p %c%c%c%c %*d %*d %p %p %c %p %d\n", ++ pb, pb->io_debug ? 'e' : 'm', pg, ++ PageDirty(pg) ? 'D' : 'd', ++ PageAnon(pg) ? 'A' : 'a', ++ PageWriteback(pg) ? 'W' : 'w', ++ PageLocked(pg) ? 'L' : 'l', ++ INT_SIZE, page_count(pg), ++ INT_SIZE, page_mapcount(pg), ++ pb->page_pb_list, page_pbc(pg), ++ iopb_to_pb(page_pbc(pg)) == pb ? ' ' : '!', ++ pg->mapping, pb->ub->ub_uid); ++ return 0; ++} ++ ++static void *bc_io_start(struct seq_file *f, loff_t *ppos) ++{ ++ loff_t pos; ++ struct list_head *lh; ++ ++ pos = *ppos; ++ spin_lock(&pb_lock); ++ if (pos == 0) ++ return &pb_io_list; ++ ++ list_for_each (lh, &pb_io_list) ++ if (pos-- == 1) ++ return lh; ++ return NULL; ++} ++ ++static void *bc_io_next(struct seq_file *f, void *v, loff_t *ppos) ++{ ++ struct list_head *lh; ++ ++ (*ppos)++; ++ lh = (struct list_head *)v; ++ return lh->next == &pb_io_list ? NULL : lh->next; ++} ++ ++static void bc_io_stop(struct seq_file *f, void *v) ++{ ++ spin_unlock(&pb_lock); ++} ++ ++static struct seq_operations bc_io_seq_ops = { ++ .start = bc_io_start, ++ .next = bc_io_next, ++ .stop = bc_io_stop, ++ .show = bc_io_show, ++}; ++ ++static int bc_io_open(struct inode *inode, struct file *filp) ++{ ++ if (!(capable(CAP_DAC_OVERRIDE) && capable(CAP_DAC_READ_SEARCH))) ++ return -EACCES; ++ ++ return seq_open(filp, &bc_io_seq_ops); ++} ++static struct file_operations bc_io_debug_ops = { ++ .open = bc_io_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++static struct bc_proc_entry bc_ioacct_debug_entry = { ++ .name = "ioacct_debug", ++ .u.fops = &bc_io_debug_ops, ++}; ++#endif ++ ++static int bc_ioacct_notify(struct vnotifier_block *self, ++ unsigned long event, void *arg, int old_ret) ++{ ++ struct user_beancounter *ub; ++ unsigned long *vm_events; ++ unsigned long long bin, bout; ++ int i; ++ ++ if (event != VIRTINFO_VMSTAT) ++ return old_ret; ++ ++ ub = top_beancounter(get_exec_ub()); ++ if (ub == get_ub0()) ++ return old_ret; ++ ++ /* Think over: do we need to account here bytes_dirty_missed? */ ++ bout = ub->bytes_wrote; ++ bin = 0; ++ for_each_online_cpu(i) { ++ bout += per_cpu_ptr(ub->ub_percpu, i)->bytes_wrote; ++ bin += per_cpu_ptr(ub->ub_percpu, i)->bytes_read; ++ } ++ ++ /* convert to Kbytes */ ++ bout >>= 10; ++ bin >>= 10; ++ ++ vm_events = ((unsigned long *)arg) + NR_VM_ZONE_STAT_ITEMS; ++ vm_events[PGPGOUT] = (unsigned long)bout; ++ vm_events[PGPGIN] = (unsigned long)bin; ++ return NOTIFY_OK; ++} ++ ++static struct vnotifier_block bc_ioacct_nb = { ++ .notifier_call = bc_ioacct_notify, ++}; ++ ++static int __init bc_ioacct_init(void) ++{ ++#ifdef CONFIG_BC_DEBUG_IO ++ bc_register_proc_root_entry(&bc_ioacct_debug_entry); ++#endif ++ bc_register_proc_entry(&bc_ioacct_entry); ++ ++ virtinfo_notifier_register(VITYPE_GENERAL, &bc_ioacct_nb); ++ return 0; ++} ++ ++late_initcall(bc_ioacct_init); ++#endif +Index: kernel/kernel/bc/io_prio.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/io_prio.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,288 @@ ++/* ++ * kernel/bc/io_prio.c ++ * ++ * Copyright (C) 2007 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * Vasily Tarasov ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct cfq_bc_data *__find_cfq_bc(struct ub_iopriv *iopriv, ++ struct cfq_data *cfqd) ++{ ++ struct cfq_bc_data *cfq_bc; ++ ++ list_for_each_entry(cfq_bc, &iopriv->cfq_bc_head, cfq_bc_list) ++ if (cfq_bc->cfqd == cfqd) ++ return cfq_bc; ++ ++ return NULL; ++} ++ ++struct cfq_bc_data *bc_find_cfq_bc(struct ub_iopriv *iopriv, ++ struct cfq_data *cfqd) ++{ ++ struct cfq_bc_data *cfq_bc; ++ unsigned long flags; ++ ++ read_lock_irqsave(&iopriv->cfq_bc_list_lock, flags); ++ cfq_bc = __find_cfq_bc(iopriv, cfqd); ++ read_unlock_irqrestore(&iopriv->cfq_bc_list_lock, flags); ++ return cfq_bc; ++} ++struct cfq_bc_data *bc_findcreate_cfq_bc(struct ub_iopriv *iopriv, ++ struct cfq_data *cfqd, gfp_t gfp_mask) ++{ ++ struct cfq_bc_data *cfq_bc_new; ++ struct cfq_bc_data *cfq_bc; ++ unsigned long flags; ++ ++ cfq_bc = bc_find_cfq_bc(iopriv, cfqd); ++ if (cfq_bc) ++ return cfq_bc; ++ ++ cfq_bc_new = kzalloc(sizeof(*cfq_bc_new), gfp_mask); ++ if (!cfq_bc_new) ++ return NULL; ++ ++ cfq_init_cfq_bc(cfq_bc_new); ++ cfq_bc_new->cfqd = cfqd; ++ cfq_bc_new->ub_iopriv = iopriv; ++ ++ write_lock_irqsave(&iopriv->cfq_bc_list_lock, flags); ++ cfq_bc = __find_cfq_bc(iopriv, cfqd); ++ if (cfq_bc) ++ kfree(cfq_bc_new); ++ else { ++ list_add_tail(&cfq_bc_new->cfq_bc_list, ++ &iopriv->cfq_bc_head); ++ cfq_bc = cfq_bc_new; ++ } ++ write_unlock_irqrestore(&iopriv->cfq_bc_list_lock, flags); ++ ++ return cfq_bc; ++} ++ ++void bc_init_ioprio(struct ub_iopriv *iopriv) ++{ ++ INIT_LIST_HEAD(&iopriv->cfq_bc_head); ++ rwlock_init(&iopriv->cfq_bc_list_lock); ++ iopriv->ioprio = UB_IOPRIO_BASE; ++} ++ ++static void inline bc_cfq_bc_check_empty(struct cfq_bc_data *cfq_bc) ++{ ++ BUG_ON(!RB_EMPTY_ROOT(&cfq_bc->service_tree.rb)); ++} ++ ++static void bc_release_cfq_bc(struct cfq_bc_data *cfq_bc) ++{ ++ struct cfq_data *cfqd; ++ elevator_t *eq; ++ int i; ++ ++ cfqd = cfq_bc->cfqd; ++ eq = cfqd->queue->elevator; ++ ++ for (i = 0; i < CFQ_PRIO_LISTS; i++) { ++ if (cfq_bc->async_cfqq[0][i]) { ++ eq->ops->put_queue(cfq_bc->async_cfqq[0][i]); ++ cfq_bc->async_cfqq[0][i] = NULL; ++ } ++ if (cfq_bc->async_cfqq[1][i]) { ++ eq->ops->put_queue(cfq_bc->async_cfqq[1][i]); ++ cfq_bc->async_cfqq[1][i] = NULL; ++ } ++ } ++ if (cfq_bc->async_idle_cfqq) { ++ eq->ops->put_queue(cfq_bc->async_idle_cfqq); ++ cfq_bc->async_idle_cfqq = NULL; ++ } ++ /* ++ * Note: this cfq_bc is already not in active list, ++ * but can be still pointed from cfqd as active. ++ */ ++ cfqd->active_cfq_bc = NULL; ++ ++ bc_cfq_bc_check_empty(cfq_bc); ++ list_del(&cfq_bc->cfq_bc_list); ++ kfree(cfq_bc); ++} ++ ++void bc_fini_ioprio(struct ub_iopriv *iopriv) ++{ ++ struct cfq_bc_data *cfq_bc; ++ struct cfq_bc_data *cfq_bc_tmp; ++ unsigned long flags; ++ spinlock_t *queue_lock; ++ ++ /* ++ * Don't get cfq_bc_list_lock since ub is already dead, ++ * but async cfqqs are still in hash list, consequently ++ * queue_lock should be hold. ++ */ ++ list_for_each_entry_safe(cfq_bc, cfq_bc_tmp, ++ &iopriv->cfq_bc_head, cfq_bc_list) { ++ queue_lock = cfq_bc->cfqd->queue->queue_lock; ++ spin_lock_irqsave(queue_lock, flags); ++ bc_release_cfq_bc(cfq_bc); ++ spin_unlock_irqrestore(queue_lock, flags); ++ } ++} ++ ++void bc_cfq_exit_queue(struct cfq_data *cfqd) ++{ ++ struct cfq_bc_data *cfq_bc; ++ struct user_beancounter *ub; ++ ++ local_irq_disable(); ++ for_each_beancounter(ub) { ++ write_lock(&ub->iopriv.cfq_bc_list_lock); ++ cfq_bc = __find_cfq_bc(&ub->iopriv, cfqd); ++ if (!cfq_bc) { ++ write_unlock(&ub->iopriv.cfq_bc_list_lock); ++ continue; ++ } ++ bc_release_cfq_bc(cfq_bc); ++ write_unlock(&ub->iopriv.cfq_bc_list_lock); ++ } ++ local_irq_enable(); ++} ++ ++int bc_expired(struct cfq_data *cfqd) ++{ ++ return time_after(jiffies, cfqd->slice_end) ? 1 : 0; ++} ++ ++static inline int bc_empty(struct cfq_bc_data *cfq_bc) ++{ ++ /* ++ * consider BC as empty only if there is no requests ++ * in elevator _and_ in driver ++ */ ++ if (!cfq_bc->rqnum && !cfq_bc->on_dispatch) ++ return 1; ++ ++ return 0; ++} ++ ++static inline unsigned long bc_time_slice_by_ioprio(unsigned int ioprio, ++ unsigned int base_slice) ++{ ++ return base_slice + ++ (base_slice * (ioprio - UB_IOPRIO_MIN)) ++ / (UB_IOPRIO_MAX - UB_IOPRIO_MIN - 1); ++} ++ ++static inline void bc_set_active(struct cfq_data *cfqd) ++{ ++ if (list_empty(&cfqd->act_cfq_bc_head)) { ++ cfqd->active_cfq_bc = NULL; ++ return; ++ } ++ ++ cfqd->active_cfq_bc = list_first_entry(&cfqd->act_cfq_bc_head, ++ struct cfq_bc_data, act_cfq_bc_list); ++ list_move_tail(&cfqd->active_cfq_bc->act_cfq_bc_list, ++ &cfqd->act_cfq_bc_head); ++ cfqd->slice_end = jiffies + ++ bc_time_slice_by_ioprio(cfqd->active_cfq_bc->ub_iopriv->ioprio, ++ cfqd->cfq_ub_slice); ++} ++ ++void bc_schedule_active(struct cfq_data *cfqd) ++{ ++ if (bc_expired(cfqd) || !cfqd->active_cfq_bc || ++ !cfqd->active_cfq_bc->rqnum) ++ bc_set_active(cfqd); ++} ++ ++void bc_inc_rqnum(struct cfq_queue *cfqq) ++{ ++ struct cfq_bc_data *cfq_bc; ++ ++ cfq_bc = cfqq->cfq_bc; ++ ++ if (!cfq_bc->rqnum) ++ list_add_tail(&cfq_bc->act_cfq_bc_list, ++ &cfqq->cfqd->act_cfq_bc_head); ++ ++ cfq_bc->rqnum++; ++} ++ ++void bc_dec_rqnum(struct cfq_queue *cfqq) ++{ ++ struct cfq_bc_data *cfq_bc; ++ ++ cfq_bc = cfqq->cfq_bc; ++ ++ cfq_bc->rqnum--; ++ ++ if (!cfq_bc->rqnum) ++ list_del(&cfq_bc->act_cfq_bc_list); ++} ++ ++unsigned long bc_set_ioprio(int ubid, int ioprio) ++{ ++ struct user_beancounter *ub; ++ ++ if (ioprio < UB_IOPRIO_MIN || ioprio >= UB_IOPRIO_MAX) ++ return -ERANGE; ++ ++ ub = get_beancounter_byuid(ubid, 0); ++ if (!ub) ++ return -ESRCH; ++ ++ ub->iopriv.ioprio = ioprio; ++ put_beancounter(ub); ++ ++ return 0; ++} ++ ++struct user_beancounter *bc_io_switch_context(struct page *page) ++{ ++ struct page_beancounter *pb; ++ struct user_beancounter *old_ub = NULL; ++ ++ pb = page_iopb(page); ++ pb = iopb_to_pb(pb); ++ if (pb) { ++ get_beancounter(pb->ub); ++ old_ub = set_exec_ub(pb->ub); ++ } ++ ++ return old_ub; ++} ++ ++void bc_io_restore_context(struct user_beancounter *ub) ++{ ++ struct user_beancounter *old_ub; ++ ++ if (ub) { ++ old_ub = set_exec_ub(ub); ++ put_beancounter(old_ub); ++ } ++} ++ ++EXPORT_SYMBOL(bc_io_switch_context); ++EXPORT_SYMBOL(bc_io_restore_context); ++EXPORT_SYMBOL(__find_cfq_bc); ++EXPORT_SYMBOL(bc_fini_ioprio); ++EXPORT_SYMBOL(bc_init_ioprio); ++EXPORT_SYMBOL(bc_findcreate_cfq_bc); ++EXPORT_SYMBOL(bc_cfq_exit_queue); ++EXPORT_SYMBOL(bc_expired); ++EXPORT_SYMBOL(bc_schedule_active); ++EXPORT_SYMBOL(bc_inc_rqnum); ++EXPORT_SYMBOL(bc_dec_rqnum); +Index: kernel/kernel/bc/kmem.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/kmem.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,406 @@ ++/* ++ * kernel/bc/kmem.c ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Initialization ++ */ ++ ++/* ++ * Slab accounting ++ */ ++ ++#ifdef CONFIG_BC_DEBUG_KMEM ++ ++#define CC_HASH_SIZE 1024 ++static struct ub_cache_counter *cc_hash[CC_HASH_SIZE]; ++spinlock_t cc_lock; ++ ++static void __free_cache_counters(struct user_beancounter *ub, ++ struct kmem_cache *cachep) ++{ ++ struct ub_cache_counter *cc, **pprev, *del; ++ int i; ++ unsigned long flags; ++ ++ del = NULL; ++ spin_lock_irqsave(&cc_lock, flags); ++ for (i = 0; i < CC_HASH_SIZE; i++) { ++ pprev = &cc_hash[i]; ++ cc = cc_hash[i]; ++ while (cc != NULL) { ++ if (cc->ub != ub && cc->cachep != cachep) { ++ pprev = &cc->next; ++ cc = cc->next; ++ continue; ++ } ++ ++ list_del(&cc->ulist); ++ *pprev = cc->next; ++ cc->next = del; ++ del = cc; ++ cc = *pprev; ++ } ++ } ++ spin_unlock_irqrestore(&cc_lock, flags); ++ ++ while (del != NULL) { ++ cc = del->next; ++ kfree(del); ++ del = cc; ++ } ++} ++ ++void ub_free_counters(struct user_beancounter *ub) ++{ ++ __free_cache_counters(ub, NULL); ++} ++ ++void ub_kmemcache_free(struct kmem_cache *cachep) ++{ ++ __free_cache_counters(NULL, cachep); ++} ++ ++void __init init_cache_counters(void) ++{ ++ memset(cc_hash, 0, CC_HASH_SIZE * sizeof(cc_hash[0])); ++ spin_lock_init(&cc_lock); ++} ++ ++#define cc_hash_fun(ub, cachep) ( \ ++ (((unsigned long)(ub) >> L1_CACHE_SHIFT) ^ \ ++ ((unsigned long)(ub) >> (BITS_PER_LONG / 2)) ^ \ ++ ((unsigned long)(cachep) >> L1_CACHE_SHIFT) ^ \ ++ ((unsigned long)(cachep) >> (BITS_PER_LONG / 2)) \ ++ ) & (CC_HASH_SIZE - 1)) ++ ++static int change_slab_charged(struct user_beancounter *ub, ++ struct kmem_cache *cachep, long val) ++{ ++ struct ub_cache_counter *cc, *new_cnt, **pprev; ++ unsigned long flags; ++ ++ new_cnt = NULL; ++again: ++ spin_lock_irqsave(&cc_lock, flags); ++ cc = cc_hash[cc_hash_fun(ub, cachep)]; ++ while (cc) { ++ if (cc->ub == ub && cc->cachep == cachep) ++ goto found; ++ cc = cc->next; ++ } ++ ++ if (new_cnt != NULL) ++ goto insert; ++ ++ spin_unlock_irqrestore(&cc_lock, flags); ++ ++ new_cnt = kmalloc(sizeof(*new_cnt), GFP_ATOMIC); ++ if (new_cnt == NULL) ++ return -ENOMEM; ++ ++ new_cnt->counter = 0; ++ new_cnt->ub = ub; ++ new_cnt->cachep = cachep; ++ goto again; ++ ++insert: ++ pprev = &cc_hash[cc_hash_fun(ub, cachep)]; ++ new_cnt->next = *pprev; ++ *pprev = new_cnt; ++ list_add(&new_cnt->ulist, &ub->ub_cclist); ++ cc = new_cnt; ++ new_cnt = NULL; ++ ++found: ++ cc->counter += val; ++ spin_unlock_irqrestore(&cc_lock, flags); ++ if (new_cnt) ++ kfree(new_cnt); ++ return 0; ++} ++ ++static inline int inc_slab_charged(struct user_beancounter *ub, ++ struct kmem_cache *cachep) ++{ ++ return change_slab_charged(ub, cachep, 1); ++} ++ ++static inline void dec_slab_charged(struct user_beancounter *ub, ++ struct kmem_cache *cachep) ++{ ++ if (change_slab_charged(ub, cachep, -1) < 0) ++ BUG(); ++} ++ ++#include ++ ++#define inc_pages_charged(ub, order) ub_percpu_add(ub, \ ++ pages_charged, 1 << order) ++#define dec_pages_charged(ub, order) ub_percpu_sub(ub, \ ++ pages_charged, 1 << order) ++ ++#ifdef CONFIG_PROC_FS ++static int bc_kmem_debug_show(struct seq_file *f, void *v) ++{ ++ struct user_beancounter *ub; ++ struct ub_cache_counter *cc; ++ long pages, vmpages, pbc; ++ int i; ++ ++ ub = seq_beancounter(f); ++ ++ pages = vmpages = pbc = 0; ++ for_each_online_cpu(i) { ++ pages += per_cpu_ptr(ub->ub_percpu, i)->pages_charged; ++ vmpages += per_cpu_ptr(ub->ub_percpu, i)->vmalloc_charged; ++ pbc += per_cpu_ptr(ub->ub_percpu, i)->pbcs; ++ } ++ if (pages < 0) ++ pages = 0; ++ if (vmpages < 0) ++ vmpages = 0; ++ ++ seq_printf(f, bc_proc_lu_lu_fmt, "pages", pages, PAGE_SIZE); ++ seq_printf(f, bc_proc_lu_lu_fmt, "vmalloced", vmpages, PAGE_SIZE); ++ seq_printf(f, bc_proc_lu_lu_fmt, "pbcs", pbc, ++ sizeof(struct page_beancounter)); ++ ++ spin_lock_irq(&cc_lock); ++ list_for_each_entry (cc, &ub->ub_cclist, ulist) { ++ struct kmem_cache *cachep; ++ ++ cachep = cc->cachep; ++ seq_printf(f, bc_proc_lu_lu_fmt, ++ kmem_cache_name(cachep), ++ cc->counter, ++ kmem_cache_objuse(cachep)); ++ } ++ spin_unlock_irq(&cc_lock); ++ return 0; ++} ++ ++static struct bc_proc_entry bc_kmem_debug_entry = { ++ .name = "kmem_debug", ++ .u.show = bc_kmem_debug_show, ++}; ++ ++static int __init bc_kmem_debug_init(void) ++{ ++ bc_register_proc_entry(&bc_kmem_debug_entry); ++ return 0; ++} ++ ++late_initcall(bc_kmem_debug_init); ++#endif ++ ++#else ++#define inc_slab_charged(ub, cache) (0) ++#define dec_slab_charged(ub, cache) do { } while (0) ++#define inc_pages_charged(ub, cache) do { } while (0) ++#define dec_pages_charged(ub, cache) do { } while (0) ++#endif ++ ++#define UB_KMEM_QUANT (PAGE_SIZE * 4) ++ ++/* called with IRQ disabled */ ++int ub_kmemsize_charge(struct user_beancounter *ub, ++ unsigned long size, ++ enum ub_severity strict) ++{ ++ struct task_beancounter *tbc; ++ ++ tbc = ¤t->task_bc; ++ if (ub != tbc->task_ub || size > UB_KMEM_QUANT) ++ goto just_charge; ++ if (tbc->kmem_precharged >= size) { ++ tbc->kmem_precharged -= size; ++ return 0; ++ } ++ ++ if (charge_beancounter(ub, UB_KMEMSIZE, UB_KMEM_QUANT, UB_HARD) == 0) { ++ tbc->kmem_precharged += UB_KMEM_QUANT - size; ++ return 0; ++ } ++ ++just_charge: ++ return charge_beancounter(ub, UB_KMEMSIZE, size, strict); ++} ++ ++/* called with IRQ disabled */ ++void ub_kmemsize_uncharge(struct user_beancounter *ub, ++ unsigned long size) ++{ ++ struct task_beancounter *tbc; ++ ++ if (size > UB_MAXVALUE) { ++ printk("ub_kmemsize_uncharge: size %lu\n", size); ++ dump_stack(); ++ } ++ ++ tbc = ¤t->task_bc; ++ if (ub != tbc->task_ub) ++ goto just_uncharge; ++ ++ tbc->kmem_precharged += size; ++ if (tbc->kmem_precharged < UB_KMEM_QUANT * 2) ++ return; ++ size = tbc->kmem_precharged - UB_KMEM_QUANT; ++ tbc->kmem_precharged -= size; ++ ++just_uncharge: ++ uncharge_beancounter(ub, UB_KMEMSIZE, size); ++} ++ ++/* called with IRQ disabled */ ++int ub_slab_charge(struct kmem_cache *cachep, void *objp, gfp_t flags) ++{ ++ unsigned int size; ++ struct user_beancounter *ub; ++ ++ ub = get_beancounter(get_exec_ub()); ++ if (ub == NULL) ++ return 0; ++ ++ size = CHARGE_SIZE(kmem_cache_objuse(cachep)); ++ if (ub_kmemsize_charge(ub, size, ++ (flags & __GFP_SOFT_UBC ? UB_SOFT : UB_HARD))) ++ goto out_err; ++ ++ if (inc_slab_charged(ub, cachep) < 0) { ++ ub_kmemsize_uncharge(ub, size); ++ goto out_err; ++ } ++ *ub_slab_ptr(cachep, objp) = ub; ++ return 0; ++ ++out_err: ++ put_beancounter(ub); ++ return -ENOMEM; ++} ++ ++/* called with IRQ disabled */ ++void ub_slab_uncharge(struct kmem_cache *cachep, void *objp) ++{ ++ unsigned int size; ++ struct user_beancounter **ub_ref; ++ ++ ub_ref = ub_slab_ptr(cachep, objp); ++ if (*ub_ref == NULL) ++ return; ++ ++ dec_slab_charged(*ub_ref, cachep); ++ size = CHARGE_SIZE(kmem_cache_objuse(cachep)); ++ ub_kmemsize_uncharge(*ub_ref, size); ++ put_beancounter(*ub_ref); ++ *ub_ref = NULL; ++} ++ ++/* ++ * Pages accounting ++ */ ++ ++int ub_page_charge(struct page *page, int order, gfp_t mask) ++{ ++ struct user_beancounter *ub; ++ unsigned long flags; ++ ++ ub = NULL; ++ if (!(mask & __GFP_UBC)) ++ goto out; ++ ++ ub = get_beancounter(get_exec_ub()); ++ if (ub == NULL) ++ goto out; ++ ++ local_irq_save(flags); ++ if (ub_kmemsize_charge(ub, CHARGE_ORDER(order), ++ (mask & __GFP_SOFT_UBC ? UB_SOFT : UB_HARD))) ++ goto err; ++ ++ inc_pages_charged(ub, order); ++ local_irq_restore(flags); ++out: ++ BUG_ON(page_ub(page) != NULL); ++ page_ub(page) = ub; ++ return 0; ++ ++err: ++ local_irq_restore(flags); ++ BUG_ON(page_ub(page) != NULL); ++ put_beancounter(ub); ++ return -ENOMEM; ++} ++ ++void ub_page_uncharge(struct page *page, int order) ++{ ++ struct user_beancounter *ub; ++ unsigned long flags; ++ ++ ub = page_ub(page); ++ if (ub == NULL) ++ return; ++ ++ BUG_ON(ub->ub_magic != UB_MAGIC); ++ dec_pages_charged(ub, order); ++ local_irq_save(flags); ++ ub_kmemsize_uncharge(ub, CHARGE_ORDER(order)); ++ local_irq_restore(flags); ++ put_beancounter(ub); ++ page_ub(page) = NULL; ++} ++ ++/* ++ * takes init_mm.page_table_lock ++ * some outer lock to protect pages from vmalloced area must be held ++ */ ++struct user_beancounter *vmalloc_ub(void *obj) ++{ ++ struct page *pg; ++ ++ pg = vmalloc_to_page(obj); ++ if (pg == NULL) ++ return NULL; ++ ++ return page_ub(pg); ++} ++ ++EXPORT_SYMBOL(vmalloc_ub); ++ ++struct user_beancounter *mem_ub(void *obj) ++{ ++ struct user_beancounter *ub; ++ ++ if ((unsigned long)obj >= VMALLOC_START && ++ (unsigned long)obj < VMALLOC_END) ++ ub = vmalloc_ub(obj); ++ else ++ ub = slab_ub(obj); ++ ++ return ub; ++} ++ ++EXPORT_SYMBOL(mem_ub); +Index: kernel/kernel/bc/misc.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/misc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,455 @@ ++/* ++ * kernel/bc/misc.c ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define UB_FILE_MINQUANT 3 ++#define UB_FILE_MAXQUANT 10 ++#define UB_FILE_INIQUANT 4 ++ ++static unsigned long ub_file_precharge(struct task_beancounter *task_bc, ++ struct user_beancounter *ub, unsigned long *kmemsize); ++ ++extern struct kmem_cache *filp_cachep; ++ ++static inline unsigned long ub_file_kmemsize(unsigned long nr) ++{ ++ return CHARGE_SIZE(kmem_cache_objuse(filp_cachep)) * nr; ++} ++ ++/* ++ * Task staff ++ */ ++ ++static void init_task_sub(struct task_struct *parent, ++ struct task_struct *tsk, ++ struct task_beancounter *old_bc) ++{ ++ struct task_beancounter *new_bc; ++ struct user_beancounter *sub; ++ ++ new_bc = &tsk->task_bc; ++ sub = old_bc->fork_sub; ++ new_bc->fork_sub = get_beancounter(sub); ++ new_bc->task_fnode = NULL; ++ new_bc->task_freserv = old_bc->task_freserv; ++ old_bc->task_freserv = NULL; ++ memset(&new_bc->task_data, 0, sizeof(new_bc->task_data)); ++ new_bc->pgfault_handle = 0; ++ new_bc->pgfault_allot = 0; ++} ++ ++void ub_init_task_bc(struct task_beancounter *tbc) ++{ ++ tbc->file_precharged = 0; ++ tbc->file_quant = UB_FILE_INIQUANT; ++ tbc->file_count = 0; ++ ++ tbc->kmem_precharged = 0; ++ tbc->dentry_alloc = 0; ++} ++ ++int ub_task_charge(struct task_struct *parent, struct task_struct *task) ++{ ++ struct task_beancounter *old_bc; ++ struct task_beancounter *new_bc; ++ struct user_beancounter *ub, *pub; ++ unsigned long file_nr, kmemsize; ++ unsigned long flags; ++ ++ old_bc = &parent->task_bc; ++ ub = old_bc->fork_sub; ++ new_bc = &task->task_bc; ++ new_bc->task_ub = get_beancounter(ub); ++ new_bc->exec_ub = get_beancounter(ub); ++ ++ pub = top_beancounter(ub); ++ spin_lock_irqsave(&pub->ub_lock, flags); ++ if (unlikely(__charge_beancounter_locked(pub, UB_NUMPROC, ++ 1, UB_HARD) < 0)) ++ goto out_numproc; ++ ++ ub_init_task_bc(new_bc); ++ file_nr = ub_file_precharge(new_bc, pub, &kmemsize); ++ spin_unlock_irqrestore(&pub->ub_lock, flags); ++ ++ charge_beancounter_notop(ub, UB_NUMPROC, 1); ++ if (likely(file_nr)) { ++ charge_beancounter_notop(ub, UB_NUMFILE, file_nr); ++ charge_beancounter_notop(ub, UB_KMEMSIZE, kmemsize); ++ } ++ ++ init_task_sub(parent, task, old_bc); ++ return 0; ++ ++out_numproc: ++ spin_unlock_irqrestore(&pub->ub_lock, flags); ++ __put_beancounter_batch(ub, 2); ++ return -ENOMEM; ++} ++ ++extern atomic_t dbgpre; ++ ++void ub_task_uncharge(struct task_struct *task) ++{ ++ struct task_beancounter *task_bc; ++ struct user_beancounter *pub; ++ unsigned long file_nr, file_kmemsize; ++ unsigned long flags; ++ ++ task_bc = &task->task_bc; ++ pub = top_beancounter(task_bc->task_ub); ++ spin_lock_irqsave(&pub->ub_lock, flags); ++ __uncharge_beancounter_locked(pub, UB_NUMPROC, 1); ++ file_nr = task_bc->file_precharged; ++ if (likely(file_nr)) ++ __uncharge_beancounter_locked(pub, ++ UB_NUMFILE, file_nr); ++ ++ /* see comment in ub_file_charge */ ++ task_bc->file_precharged = 0; ++ file_kmemsize = ub_file_kmemsize(file_nr); ++ if (likely(file_kmemsize)) ++ __uncharge_beancounter_locked(pub, ++ UB_KMEMSIZE, file_kmemsize); ++ spin_unlock_irqrestore(&pub->ub_lock, flags); ++ ++ uncharge_beancounter_notop(task_bc->task_ub, UB_NUMPROC, 1); ++ if (likely(file_nr)) { ++ uncharge_beancounter_notop(task_bc->task_ub, ++ UB_NUMFILE, file_nr); ++ __put_beancounter_batch(task_bc->task_ub, file_nr); ++ } ++ if (likely(file_kmemsize)) ++ uncharge_beancounter_notop(task_bc->task_ub, ++ UB_KMEMSIZE, file_kmemsize); ++} ++ ++void ub_task_put(struct task_struct *task) ++{ ++ struct task_beancounter *task_bc; ++ struct user_beancounter *pub; ++ unsigned long kmemsize, flags; ++ ++ task_bc = &task->task_bc; ++ ++ pub = top_beancounter(task_bc->task_ub); ++ spin_lock_irqsave(&pub->ub_lock, flags); ++ kmemsize = task_bc->kmem_precharged; ++ task_bc->kmem_precharged = 0; ++ if (likely(kmemsize)) ++ __uncharge_beancounter_locked(pub, UB_KMEMSIZE, kmemsize); ++ spin_unlock_irqrestore(&pub->ub_lock, flags); ++ if (likely(kmemsize)) ++ uncharge_beancounter_notop(task_bc->task_ub, UB_KMEMSIZE, kmemsize); ++ ++ put_beancounter(task_bc->exec_ub); ++ put_beancounter(task_bc->task_ub); ++ put_beancounter(task_bc->fork_sub); ++ /* can't be freed elsewhere, failures possible in the middle of fork */ ++ if (task_bc->task_freserv != NULL) ++ kfree(task_bc->task_freserv); ++ ++ task_bc->exec_ub = (struct user_beancounter *)0xdeadbcbc; ++ task_bc->task_ub = (struct user_beancounter *)0xdead100c; ++ BUG_ON(task_bc->kmem_precharged != 0); ++} ++ ++/* ++ * Files and file locks. ++ */ ++/* ++ * For NUMFILE, we do not take a lock and call charge function ++ * for every file. We try to charge in batches, keeping local reserve on ++ * task. For experimental purposes, batch size is adaptive and depends ++ * on numfile barrier, number of processes, and the history of successes and ++ * failures of batch charges. ++ * ++ * Per-task fields have the following meaning ++ * file_precharged number of files charged to beancounter in advance, ++ * file_quant logarithm of batch size ++ * file_count counter of charge successes, to reduce batch size ++ * fluctuations. ++ */ ++static unsigned long ub_file_precharge(struct task_beancounter *task_bc, ++ struct user_beancounter *ub, unsigned long *kmemsize) ++{ ++ unsigned long n, kmem; ++ ++ n = 1UL << task_bc->file_quant; ++ if (ub->ub_parms[UB_NUMPROC].held > ++ (ub->ub_parms[UB_NUMFILE].barrier >> ++ task_bc->file_quant)) ++ goto nopre; ++ if (unlikely(__charge_beancounter_locked(ub, UB_NUMFILE, n, UB_HARD))) ++ goto nopre; ++ kmem = ub_file_kmemsize(n); ++ if (unlikely(__charge_beancounter_locked(ub, UB_KMEMSIZE, ++ kmem, UB_HARD))) ++ goto nopre_kmem; ++ ++ task_bc->file_precharged += n; ++ get_beancounter_batch(task_bc->task_ub, n); ++ task_bc->file_count++; ++ if (task_bc->file_quant < UB_FILE_MAXQUANT && ++ task_bc->file_count >= task_bc->file_quant) { ++ task_bc->file_quant++; ++ task_bc->file_count = 0; ++ } ++ *kmemsize = kmem; ++ return n; ++ ++nopre_kmem: ++ __uncharge_beancounter_locked(ub, UB_NUMFILE, n); ++nopre: ++ if (task_bc->file_quant > UB_FILE_MINQUANT) ++ task_bc->file_quant--; ++ task_bc->file_count = 0; ++ return 0; ++} ++ ++int ub_file_charge(struct file *f) ++{ ++ struct user_beancounter *ub, *pub; ++ struct task_beancounter *task_bc; ++ unsigned long file_nr, kmem; ++ unsigned long flags; ++ int err; ++ ++ task_bc = ¤t->task_bc; ++ ub = get_exec_ub(); ++ if (unlikely(ub != task_bc->task_ub)) ++ goto just_charge; ++ ++ if (likely(task_bc->file_precharged > 0)) { ++ /* ++ * files are put via RCU in 2.6.16 so during ++ * this decrement an IRQ can happen and called ++ * ub_files_uncharge() will mess file_precharged ++ * ++ * ub_task_uncharge() is called via RCU also so no ++ * protection is needed there ++ * ++ * Xemul ++ */ ++ ++ local_irq_save(flags); ++ task_bc->file_precharged--; ++ local_irq_restore(flags); ++ ++ f->f_ub = ub; ++ return 0; ++ } ++ ++ pub = top_beancounter(ub); ++ spin_lock_irqsave(&pub->ub_lock, flags); ++ file_nr = ub_file_precharge(task_bc, pub, &kmem); ++ if (unlikely(!file_nr)) ++ goto last_try; ++ spin_unlock(&pub->ub_lock); ++ task_bc->file_precharged--; ++ local_irq_restore(flags); ++ ++ charge_beancounter_notop(ub, UB_NUMFILE, file_nr); ++ charge_beancounter_notop(ub, UB_KMEMSIZE, kmem); ++ f->f_ub = ub; ++ return 0; ++ ++just_charge: ++ pub = top_beancounter(ub); ++ spin_lock_irqsave(&pub->ub_lock, flags); ++last_try: ++ kmem = ub_file_kmemsize(1); ++ err = __charge_beancounter_locked(pub, UB_NUMFILE, 1, UB_HARD); ++ if (likely(!err)) { ++ err = __charge_beancounter_locked(pub, UB_KMEMSIZE, ++ kmem, UB_HARD); ++ if (unlikely(err)) ++ __uncharge_beancounter_locked(pub, UB_NUMFILE, 1); ++ } ++ spin_unlock_irqrestore(&pub->ub_lock, flags); ++ if (likely(!err)) { ++ charge_beancounter_notop(ub, UB_NUMFILE, 1); ++ charge_beancounter_notop(ub, UB_KMEMSIZE, kmem); ++ f->f_ub = get_beancounter(ub); ++ } ++ return err; ++} ++ ++void ub_file_uncharge(struct file *f) ++{ ++ struct user_beancounter *ub, *pub; ++ struct task_beancounter *task_bc; ++ unsigned long nr; ++ ++ ub = f->f_ub; ++ task_bc = ¤t->task_bc; ++ if (likely(ub == task_bc->task_ub)) { ++ task_bc->file_precharged++; ++ pub = top_beancounter(ub); ++ if (ub_barrier_farnr(pub, UB_NUMFILE) && ++ ub_barrier_farsz(pub, UB_KMEMSIZE)) ++ return; ++ if (task_bc->file_precharged < (1UL << task_bc->file_quant)) ++ return; ++ nr = task_bc->file_precharged ++ - (1UL << (task_bc->file_quant - 1)); ++ task_bc->file_precharged -= nr; ++ __put_beancounter_batch(ub, nr); ++ uncharge_beancounter(ub, UB_NUMFILE, nr); ++ uncharge_beancounter(ub, UB_KMEMSIZE, ub_file_kmemsize(nr)); ++ } else { ++ uncharge_beancounter(ub, UB_NUMFILE, 1); ++ uncharge_beancounter(ub, UB_KMEMSIZE, ub_file_kmemsize(1)); ++ put_beancounter(ub); ++ } ++} ++ ++int ub_flock_charge(struct file_lock *fl, int hard) ++{ ++ struct user_beancounter *ub; ++ int err; ++ ++ /* No need to get_beancounter here since it's already got in slab */ ++ ub = slab_ub(fl); ++ if (ub == NULL) ++ return 0; ++ ++ err = charge_beancounter(ub, UB_NUMFLOCK, 1, hard ? UB_HARD : UB_SOFT); ++ if (!err) ++ fl->fl_charged = 1; ++ return err; ++} ++ ++void ub_flock_uncharge(struct file_lock *fl) ++{ ++ struct user_beancounter *ub; ++ ++ /* Ub will be put in slab */ ++ ub = slab_ub(fl); ++ if (ub == NULL || !fl->fl_charged) ++ return; ++ ++ uncharge_beancounter(ub, UB_NUMFLOCK, 1); ++ fl->fl_charged = 0; ++} ++ ++/* ++ * Signal handling ++ */ ++ ++static int do_ub_siginfo_charge(struct user_beancounter *ub, ++ unsigned long size) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ if (__charge_beancounter_locked(ub, UB_KMEMSIZE, size, UB_HARD)) ++ goto out_kmem; ++ ++ if (__charge_beancounter_locked(ub, UB_NUMSIGINFO, 1, UB_HARD)) ++ goto out_num; ++ ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ return 0; ++ ++out_num: ++ __uncharge_beancounter_locked(ub, UB_KMEMSIZE, size); ++out_kmem: ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ return -ENOMEM; ++} ++ ++static void do_ub_siginfo_uncharge(struct user_beancounter *ub, ++ unsigned long size) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ __uncharge_beancounter_locked(ub, UB_KMEMSIZE, size); ++ __uncharge_beancounter_locked(ub, UB_NUMSIGINFO, 1); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++int ub_siginfo_charge(struct sigqueue *sq, struct user_beancounter *ub) ++{ ++ unsigned long size; ++ struct user_beancounter *p, *q; ++ ++ size = CHARGE_SIZE(kmem_obj_objuse(sq)); ++ for (p = ub; p != NULL; p = p->parent) { ++ if (do_ub_siginfo_charge(p, size)) ++ goto unroll; ++ } ++ ++ sq->sig_ub = get_beancounter(ub); ++ return 0; ++ ++unroll: ++ for (q = ub; q != p; q = q->parent) ++ do_ub_siginfo_uncharge(q, size); ++ return -ENOMEM; ++} ++EXPORT_SYMBOL(ub_siginfo_charge); ++ ++void ub_siginfo_uncharge(struct sigqueue *sq) ++{ ++ unsigned long size; ++ struct user_beancounter *ub, *p; ++ ++ p = ub = sq->sig_ub; ++ sq->sig_ub = NULL; ++ size = CHARGE_SIZE(kmem_obj_objuse(sq)); ++ for (; ub != NULL; ub = ub->parent) ++ do_ub_siginfo_uncharge(ub, size); ++ put_beancounter(p); ++} ++ ++/* ++ * PTYs ++ */ ++ ++int ub_pty_charge(struct tty_struct *tty) ++{ ++ struct user_beancounter *ub; ++ int retval; ++ ++ ub = slab_ub(tty); ++ retval = 0; ++ if (ub && tty->driver->subtype == PTY_TYPE_MASTER && ++ !test_bit(TTY_CHARGED, &tty->flags)) { ++ retval = charge_beancounter(ub, UB_NUMPTY, 1, UB_HARD); ++ if (!retval) ++ set_bit(TTY_CHARGED, &tty->flags); ++ } ++ return retval; ++} ++ ++void ub_pty_uncharge(struct tty_struct *tty) ++{ ++ struct user_beancounter *ub; ++ ++ ub = slab_ub(tty); ++ if (ub && tty->driver->subtype == PTY_TYPE_MASTER && ++ test_bit(TTY_CHARGED, &tty->flags)) { ++ uncharge_beancounter(ub, UB_NUMPTY, 1); ++ clear_bit(TTY_CHARGED, &tty->flags); ++ } ++} +Index: kernel/kernel/bc/net.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/net.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,1150 @@ ++/* ++ * linux/kernel/bc/net.c ++ * ++ * Copyright (C) 1998-2004 Andrey V. Savochkin ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * TODO: ++ * - sizeof(struct inode) charge ++ * = tcp_mem_schedule() feedback based on ub limits ++ * + measures so that one socket won't exhaust all send buffers, ++ * see bug in bugzilla ++ * = sk->socket check for NULL in snd_wakeups ++ * (tcp_write_space checks for NULL itself) ++ * + in tcp_close(), orphaned socket abortion should be based on ubc ++ * resources (same in tcp_out_of_resources) ++ * Beancounter should also have separate orphaned socket counter... ++ * + for rcv, in-order segment should be accepted ++ * if only barrier is exceeded ++ * = tcp_rmem_schedule() feedback based on ub limits ++ * - repair forward_alloc mechanism for receive buffers ++ * It's idea is that some buffer space is pre-charged so that receive fast ++ * path doesn't need to take spinlocks and do other heavy stuff ++ * + tcp_prune_queue actions based on ub limits ++ * + window adjustments depending on available buffers for receive ++ * - window adjustments depending on available buffers for send ++ * + race around usewreserv ++ * + avoid allocating new page for each tiny-gram, see letter from ANK ++ * + rename ub_sock_lock ++ * + sk->sleep wait queue probably can be used for all wakeups, and ++ * sk->ub_wait is unnecessary ++ * + for UNIX sockets, the current algorithm will lead to ++ * UB_UNIX_MINBUF-sized messages only for non-blocking case ++ * - charge for af_packet sockets ++ * + all datagram sockets should be charged to NUMUNIXSOCK ++ * - we do not charge for skb copies and clones staying in device queues ++ * + live-lock if number of sockets is big and buffer limits are small ++ * [diff-ubc-dbllim3] ++ * - check that multiple readers/writers on the same socket won't cause fatal ++ * consequences ++ * - check allocation/charge orders ++ * + There is potential problem with callback_lock. In *snd_wakeup we take ++ * beancounter first, in sock_def_error_report - callback_lock first. ++ * then beancounter. This is not a problem if callback_lock taken ++ * readonly, but anyway... ++ * - SKB_CHARGE_SIZE doesn't include the space wasted by slab allocator ++ * General kernel problems: ++ * - in tcp_sendmsg(), if allocation fails, non-blocking sockets with ASYNC ++ * notification won't get signals ++ * - datagram_poll looks racy ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* by some reason it is not used currently */ ++#define UB_SOCK_MAINTAIN_WMEMPRESSURE 0 ++ ++ ++/* Skb truesize definition. Bad place. Den */ ++ ++static inline int skb_chargesize_head(struct sk_buff *skb) ++{ ++ return skb_charge_size(skb_end_pointer(skb) - skb->head + ++ sizeof(struct skb_shared_info)); ++} ++ ++int skb_charge_fullsize(struct sk_buff *skb) ++{ ++ int chargesize; ++ struct sk_buff *skbfrag; ++ ++ chargesize = skb_chargesize_head(skb) + ++ PAGE_SIZE * skb_shinfo(skb)->nr_frags; ++ if (likely(skb_shinfo(skb)->frag_list == NULL)) ++ return chargesize; ++ for (skbfrag = skb_shinfo(skb)->frag_list; ++ skbfrag != NULL; ++ skbfrag = skbfrag->next) { ++ chargesize += skb_charge_fullsize(skbfrag); ++ } ++ return chargesize; ++} ++EXPORT_SYMBOL(skb_charge_fullsize); ++ ++static int ub_sock_makewreserv_locked(struct sock *sk, ++ int bufid, unsigned long size); ++ ++int __ub_too_many_orphans(struct sock *sk, int count) ++{ ++ struct user_beancounter *ub; ++ ++ if (sock_has_ubc(sk)) { ++ ub = top_beancounter(sock_bc(sk)->ub); ++ if (count >= ub->ub_parms[UB_NUMTCPSOCK].barrier >> 2) ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ * Queueing ++ */ ++ ++static void ub_sock_snd_wakeup(struct user_beancounter *ub) ++{ ++ struct list_head *p; ++ struct sock *sk; ++ struct sock_beancounter *skbc; ++ struct socket *sock; ++ unsigned long added; ++ ++ while (!list_empty(&ub->ub_other_sk_list)) { ++ p = ub->ub_other_sk_list.next; ++ skbc = list_entry(p, struct sock_beancounter, ub_sock_list); ++ sk = skbc_sock(skbc); ++ ++ added = 0; ++ sock = sk->sk_socket; ++ if (sock == NULL) { ++ /* sk being destroyed */ ++ list_del_init(&skbc->ub_sock_list); ++ continue; ++ } ++ ++ ub_debug(UBD_NET_SLEEP, ++ "Checking queue, waiting %lu, reserv %lu\n", ++ skbc->ub_waitspc, skbc->poll_reserv); ++ added = -skbc->poll_reserv; ++ if (ub_sock_makewreserv_locked(sk, UB_OTHERSOCKBUF, ++ skbc->ub_waitspc)) ++ break; ++ added += skbc->poll_reserv; ++ ++ list_del_init(&skbc->ub_sock_list); ++ ++ /* ++ * See comments in ub_tcp_snd_wakeup. ++ * Locking note: both unix_write_space and ++ * sock_def_write_space take callback_lock themselves. ++ * We take it here just to be on the safe side and to ++ * act the same way as ub_tcp_snd_wakeup does. ++ */ ++ sock_hold(sk); ++ read_lock(&sk->sk_callback_lock); ++ spin_unlock(&ub->ub_lock); ++ ++ sk->sk_write_space(sk); ++ read_unlock(&sk->sk_callback_lock); ++ ++ if (skbc->ub != ub && added) ++ charge_beancounter_notop(skbc->ub, ++ UB_OTHERSOCKBUF, added); ++ sock_put(sk); ++ ++ spin_lock(&ub->ub_lock); ++ } ++} ++ ++static void ub_tcp_snd_wakeup(struct user_beancounter *ub) ++{ ++ struct list_head *p; ++ struct sock *sk; ++ struct sock_beancounter *skbc; ++ struct socket *sock; ++ unsigned long added; ++ ++ while (!list_empty(&ub->ub_tcp_sk_list)) { ++ p = ub->ub_tcp_sk_list.next; ++ skbc = list_entry(p, struct sock_beancounter, ub_sock_list); ++ sk = skbc_sock(skbc); ++ ++ added = 0; ++ sock = sk->sk_socket; ++ if (sock == NULL) { ++ /* sk being destroyed */ ++ list_del_init(&skbc->ub_sock_list); ++ continue; ++ } ++ ++ ub_debug(UBD_NET_SLEEP, ++ "Checking queue, waiting %lu, reserv %lu\n", ++ skbc->ub_waitspc, skbc->poll_reserv); ++ added = -skbc->poll_reserv; ++ if (ub_sock_makewreserv_locked(sk, UB_TCPSNDBUF, ++ skbc->ub_waitspc)) ++ break; ++ added += skbc->poll_reserv; ++ ++ list_del_init(&skbc->ub_sock_list); ++ ++ /* ++ * Send async notifications and wake up. ++ * Locking note: we get callback_lock here because ++ * tcp_write_space is over-optimistic about calling context ++ * (socket lock is presumed). So we get the lock here although ++ * it belongs to the callback. ++ */ ++ sock_hold(sk); ++ read_lock(&sk->sk_callback_lock); ++ spin_unlock(&ub->ub_lock); ++ ++ sk->sk_write_space(sk); ++ read_unlock(&sk->sk_callback_lock); ++ ++ if (skbc->ub != ub && added) ++ charge_beancounter_notop(skbc->ub, UB_TCPSNDBUF, added); ++ sock_put(sk); ++ ++ spin_lock(&ub->ub_lock); ++ } ++} ++ ++void ub_sock_snd_queue_add(struct sock *sk, int res, unsigned long size) ++{ ++ unsigned long flags; ++ struct sock_beancounter *skbc; ++ struct user_beancounter *ub; ++ unsigned long added_reserv; ++ ++ if (!sock_has_ubc(sk)) ++ return; ++ ++ skbc = sock_bc(sk); ++ ub = top_beancounter(skbc->ub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ ub_debug(UBD_NET_SLEEP, "attempt to charge for %lu\n", size); ++ added_reserv = -skbc->poll_reserv; ++ if (!ub_sock_makewreserv_locked(sk, res, size)) { ++ /* ++ * It looks a bit hackish, but it is compatible with both ++ * wait_for_xx_ubspace and poll. ++ * This __set_current_state is equivalent to a wakeup event ++ * right after spin_unlock_irqrestore. ++ */ ++ __set_current_state(TASK_RUNNING); ++ added_reserv += skbc->poll_reserv; ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ if (added_reserv) ++ charge_beancounter_notop(skbc->ub, res, added_reserv); ++ return; ++ } ++ ++ ub_debug(UBD_NET_SLEEP, "Adding sk to queue\n"); ++ skbc->ub_waitspc = size; ++ if (!list_empty(&skbc->ub_sock_list)) { ++ ub_debug(UBD_NET_SOCKET, ++ "re-adding socket to beancounter %p.\n", ub); ++ goto out; ++ } ++ ++ switch (res) { ++ case UB_TCPSNDBUF: ++ list_add_tail(&skbc->ub_sock_list, ++ &ub->ub_tcp_sk_list); ++ break; ++ case UB_OTHERSOCKBUF: ++ list_add_tail(&skbc->ub_sock_list, ++ &ub->ub_other_sk_list); ++ break; ++ default: ++ BUG(); ++ } ++out: ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++EXPORT_SYMBOL(ub_sock_snd_queue_add); ++ ++long ub_sock_wait_for_space(struct sock *sk, long timeo, unsigned long size) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ ++ add_wait_queue(sk->sk_sleep, &wait); ++ for (;;) { ++ if (signal_pending(current)) ++ break; ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (!ub_sock_make_wreserv(sk, UB_OTHERSOCKBUF, size)) ++ break; ++ ++ if (sk->sk_shutdown & SEND_SHUTDOWN) ++ break; ++ if (sk->sk_err) ++ break; ++ ub_sock_snd_queue_add(sk, UB_OTHERSOCKBUF, size); ++ timeo = schedule_timeout(timeo); ++ } ++ __set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sk_sleep, &wait); ++ return timeo; ++} ++ ++void ub_sock_sndqueuedel(struct sock *sk) ++{ ++ struct user_beancounter *ub; ++ struct sock_beancounter *skbc; ++ unsigned long flags; ++ ++ if (!sock_has_ubc(sk)) ++ return; ++ skbc = sock_bc(sk); ++ ++ /* race with write_space callback of other socket */ ++ ub = top_beancounter(skbc->ub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ list_del_init(&skbc->ub_sock_list); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++/* ++ * Helpers ++ */ ++ ++static inline void __ub_skb_set_charge(struct sk_buff *skb, struct sock *sk, ++ unsigned long size, int resource) ++{ ++ skb_bc(skb)->ub = sock_bc(sk)->ub; ++ skb_bc(skb)->charged = size; ++ skb_bc(skb)->resource = resource; ++} ++ ++void ub_skb_set_charge(struct sk_buff *skb, struct sock *sk, ++ unsigned long size, int resource) ++{ ++ if (!sock_has_ubc(sk)) ++ return; ++ ++ if (sock_bc(sk)->ub == NULL) ++ BUG(); ++ ++ __ub_skb_set_charge(skb, sk, size, resource); ++ ++ /* Ugly. Ugly. Skb in sk writequeue can live without ref to sk */ ++ if (skb->sk == NULL) ++ skb->sk = sk; ++} ++ ++EXPORT_SYMBOL(ub_skb_set_charge); ++ ++static inline void ub_skb_set_uncharge(struct sk_buff *skb) ++{ ++ skb_bc(skb)->ub = NULL; ++ skb_bc(skb)->charged = 0; ++ skb_bc(skb)->resource = 0; ++} ++ ++static void ub_update_rmem_thres(struct sock_beancounter *skub) ++{ ++ struct user_beancounter *ub; ++ ++ if (skub && skub->ub) { ++ ub = top_beancounter(skub->ub); ++ ub->ub_rmem_thres = ub->ub_parms[UB_TCPRCVBUF].barrier / ++ (ub->ub_parms[UB_NUMTCPSOCK].held + 1); ++ } ++} ++ ++static inline void ub_sock_wcharge_dec(struct sock *sk, ++ unsigned long chargesize) ++{ ++ /* The check sk->sk_family != PF_NETLINK is made as the skb is ++ * queued to the kernel end of socket while changed to the user one. ++ * Den */ ++ if (unlikely(sock_bc(sk)->ub_wcharged) && sk->sk_family != PF_NETLINK) { ++ if (sock_bc(sk)->ub_wcharged > chargesize) ++ sock_bc(sk)->ub_wcharged -= chargesize; ++ else ++ sock_bc(sk)->ub_wcharged = 0; ++ } ++} ++ ++/* ++ * Charge socket number ++ */ ++ ++static inline void sk_alloc_beancounter(struct sock *sk) ++{ ++ struct sock_beancounter *skbc; ++ ++ skbc = sock_bc(sk); ++ memset(skbc, 0, sizeof(struct sock_beancounter)); ++} ++ ++static inline void sk_free_beancounter(struct sock *sk) ++{ ++} ++ ++static int __sock_charge(struct sock *sk, int res) ++{ ++ struct sock_beancounter *skbc; ++ struct user_beancounter *cub, *ub; ++ unsigned long added_reserv, added_forw; ++ unsigned long flags; ++ ++ cub = get_exec_ub(); ++ if (unlikely(cub == NULL)) ++ return 0; ++ ++ sk_alloc_beancounter(sk); ++ skbc = sock_bc(sk); ++ INIT_LIST_HEAD(&skbc->ub_sock_list); ++ ++ ub = top_beancounter(cub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ if (unlikely(__charge_beancounter_locked(ub, res, 1, UB_HARD) < 0)) ++ goto out_limit; ++ ++ added_reserv = 0; ++ added_forw = 0; ++ if (res == UB_NUMTCPSOCK) { ++ added_reserv = skb_charge_size(MAX_TCP_HEADER + ++ 1500 - sizeof(struct iphdr) - ++ sizeof(struct tcphdr)); ++ added_reserv *= 4; ++ ub->ub_parms[UB_TCPSNDBUF].held += added_reserv; ++ if (!ub_barrier_farsz(ub, UB_TCPSNDBUF)) { ++ ub->ub_parms[UB_TCPSNDBUF].held -= added_reserv; ++ added_reserv = 0; ++ } ++ skbc->poll_reserv = added_reserv; ++ ++ added_forw = SK_STREAM_MEM_QUANTUM * 4; ++ ub->ub_parms[UB_TCPRCVBUF].held += added_forw; ++ if (!ub_barrier_farsz(ub, UB_TCPRCVBUF)) { ++ ub->ub_parms[UB_TCPRCVBUF].held -= added_forw; ++ added_forw = 0; ++ } ++ skbc->forw_space = added_forw; ++ } ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ ++ charge_beancounter_notop(cub, res, 1); ++ if (added_reserv) ++ charge_beancounter_notop(cub, UB_TCPSNDBUF, added_reserv); ++ if (added_forw) ++ charge_beancounter_notop(cub, UB_TCPRCVBUF, added_forw); ++ ++ skbc->ub = get_beancounter(cub); ++ return 0; ++ ++out_limit: ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ sk_free_beancounter(sk); ++ return -ENOMEM; ++} ++ ++int ub_tcp_sock_charge(struct sock *sk) ++{ ++ int ret; ++ ++ ret = __sock_charge(sk, UB_NUMTCPSOCK); ++ ub_update_rmem_thres(sock_bc(sk)); ++ ++ return ret; ++} ++ ++int ub_other_sock_charge(struct sock *sk) ++{ ++ return __sock_charge(sk, UB_NUMOTHERSOCK); ++} ++ ++EXPORT_SYMBOL(ub_other_sock_charge); ++ ++int ub_sock_charge(struct sock *sk, int family, int type) ++{ ++ return (IS_TCP_SOCK(family, type) ? ++ ub_tcp_sock_charge(sk) : ub_other_sock_charge(sk)); ++} ++ ++EXPORT_SYMBOL(ub_sock_charge); ++ ++/* ++ * Uncharge socket number ++ */ ++ ++void ub_sock_uncharge(struct sock *sk) ++{ ++ int is_tcp_sock; ++ unsigned long flags; ++ struct sock_beancounter *skbc; ++ struct user_beancounter *ub; ++ unsigned long reserv, forw; ++ ++ if (unlikely(!sock_has_ubc(sk))) ++ return; ++ ++ is_tcp_sock = IS_TCP_SOCK(sk->sk_family, sk->sk_type); ++ skbc = sock_bc(sk); ++ ub_debug(UBD_NET_SOCKET, "Calling ub_sock_uncharge on %p\n", sk); ++ ++ ub = top_beancounter(skbc->ub); ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ if (!list_empty(&skbc->ub_sock_list)) { ++ ub_debug(UBD_NET_SOCKET, ++ "ub_sock_uncharge: removing from ub(%p) queue.\n", ++ skbc); ++ list_del_init(&skbc->ub_sock_list); ++ } ++ ++ reserv = skbc->poll_reserv; ++ forw = skbc->forw_space; ++ __uncharge_beancounter_locked(ub, ++ (is_tcp_sock ? UB_TCPSNDBUF : UB_OTHERSOCKBUF), ++ reserv); ++ if (forw) ++ __uncharge_beancounter_locked(ub, ++ (is_tcp_sock ? UB_TCPRCVBUF : UB_DGRAMRCVBUF), ++ forw); ++ __uncharge_beancounter_locked(ub, ++ (is_tcp_sock ? UB_NUMTCPSOCK : UB_NUMOTHERSOCK), 1); ++ ++ ub_sock_wcharge_dec(sk, reserv); ++ if (unlikely(skbc->ub_wcharged)) ++ printk(KERN_WARNING ++ "ub_sock_uncharge: wch=%lu for ub %p (%d).\n", ++ skbc->ub_wcharged, skbc->ub, skbc->ub->ub_uid); ++ skbc->poll_reserv = 0; ++ skbc->forw_space = 0; ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ ++ uncharge_beancounter_notop(skbc->ub, ++ (is_tcp_sock ? UB_TCPSNDBUF : UB_OTHERSOCKBUF), ++ reserv); ++ if (forw) ++ uncharge_beancounter_notop(skbc->ub, ++ (is_tcp_sock ? UB_TCPRCVBUF : UB_DGRAMRCVBUF), ++ forw); ++ uncharge_beancounter_notop(skbc->ub, ++ (is_tcp_sock ? UB_NUMTCPSOCK : UB_NUMOTHERSOCK), 1); ++ ++ put_beancounter(skbc->ub); ++ sk_free_beancounter(sk); ++} ++ ++/* ++ * Special case for netlink_dump - (un)charges precalculated size ++ */ ++ ++int ub_nlrcvbuf_charge(struct sk_buff *skb, struct sock *sk) ++{ ++ int ret; ++ unsigned long chargesize; ++ ++ if (unlikely(!sock_has_ubc(sk))) ++ return 0; ++ ++ chargesize = skb_charge_fullsize(skb); ++ ret = charge_beancounter(sock_bc(sk)->ub, ++ UB_DGRAMRCVBUF, chargesize, UB_HARD); ++ if (ret < 0) ++ return ret; ++ ub_skb_set_charge(skb, sk, chargesize, UB_DGRAMRCVBUF); ++ return ret; ++} ++ ++/* ++ * Poll reserve accounting ++ * ++ * This is the core of socket buffer management (along with queueing/wakeup ++ * functions. The rest of buffer accounting either call these functions, or ++ * repeat parts of their logic for some simpler cases. ++ */ ++ ++static int ub_sock_makewreserv_locked(struct sock *sk, ++ int bufid, unsigned long size) ++{ ++ unsigned long wcharge_added; ++ struct sock_beancounter *skbc; ++ struct user_beancounter *ub; ++ ++ skbc = sock_bc(sk); ++ if (skbc->poll_reserv >= size) /* no work to be done */ ++ goto out; ++ ++ ub = top_beancounter(skbc->ub); ++ ub->ub_parms[bufid].held += size - skbc->poll_reserv; ++ ++ wcharge_added = 0; ++ /* ++ * Logic: ++ * 1) when used memory hits barrier, we set wmem_pressure; ++ * wmem_pressure is reset under barrier/2; ++ * between barrier/2 and barrier we limit per-socket buffer growth; ++ * 2) each socket is guaranteed to get (limit-barrier)/maxsockets ++ * calculated on the base of memory eaten after the barrier is hit ++ */ ++ skbc = sock_bc(sk); ++#if UB_SOCK_MAINTAIN_WMEMPRESSURE ++ if (!ub_hfbarrier_hit(ub, bufid)) { ++ if (ub->ub_wmem_pressure) ++ ub_debug(UBD_NET_SEND, "makewres: pressure -> 0 " ++ "sk %p sz %lu pr %lu hd %lu wc %lu sb %d.\n", ++ sk, size, skbc->poll_reserv, ++ ub->ub_parms[bufid].held, ++ skbc->ub_wcharged, sk->sk_sndbuf); ++ ub->ub_wmem_pressure = 0; ++ } ++#endif ++ if (ub_barrier_hit(ub, bufid)) { ++#if UB_SOCK_MAINTAIN_WMEMPRESSURE ++ if (!ub->ub_wmem_pressure) ++ ub_debug(UBD_NET_SEND, "makewres: pressure -> 1 " ++ "sk %p sz %lu pr %lu hd %lu wc %lu sb %d.\n", ++ sk, size, skbc->poll_reserv, ++ ub->ub_parms[bufid].held, ++ skbc->ub_wcharged, sk->sk_sndbuf); ++ ub->ub_wmem_pressure = 1; ++#endif ++ if (sk->sk_family == PF_NETLINK) ++ goto unroll; ++ wcharge_added = size - skbc->poll_reserv; ++ skbc->ub_wcharged += wcharge_added; ++ if (skbc->ub_wcharged * ub->ub_parms[bid2sid(bufid)].limit + ++ ub->ub_parms[bufid].barrier > ++ ub->ub_parms[bufid].limit) ++ goto unroll_wch; ++ } ++ if (ub->ub_parms[bufid].held > ub->ub_parms[bufid].limit) ++ goto unroll; ++ ++ ub_adjust_maxheld(ub, bufid); ++ skbc->poll_reserv = size; ++out: ++ return 0; ++ ++unroll_wch: ++ skbc->ub_wcharged -= wcharge_added; ++unroll: ++ ub_debug(UBD_NET_SEND, ++ "makewres: deny " ++ "sk %p sz %lu pr %lu hd %lu wc %lu sb %d.\n", ++ sk, size, skbc->poll_reserv, ub->ub_parms[bufid].held, ++ skbc->ub_wcharged, sk->sk_sndbuf); ++ ub->ub_parms[bufid].failcnt++; ++ ub->ub_parms[bufid].held -= size - skbc->poll_reserv; ++ ++ if (sk->sk_socket != NULL) { ++ set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); ++ set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); ++ } ++ return -ENOMEM; ++} ++ ++int ub_sock_make_wreserv(struct sock *sk, int bufid, unsigned long size) ++{ ++ struct sock_beancounter *skbc; ++ struct user_beancounter *ub; ++ unsigned long flags; ++ unsigned long added_reserv; ++ int err; ++ ++ skbc = sock_bc(sk); ++ ++ /* ++ * This function provides that there is sufficient reserve upon return ++ * only if sk has only one user. We can check poll_reserv without ++ * serialization and avoid locking if the reserve already exists. ++ */ ++ if (unlikely(!sock_has_ubc(sk)) || likely(skbc->poll_reserv >= size)) ++ return 0; ++ ++ ub = top_beancounter(skbc->ub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ added_reserv = -skbc->poll_reserv; ++ err = ub_sock_makewreserv_locked(sk, bufid, size); ++ added_reserv += skbc->poll_reserv; ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ ++ if (added_reserv) ++ charge_beancounter_notop(skbc->ub, bufid, added_reserv); ++ ++ return err; ++} ++ ++EXPORT_SYMBOL(ub_sock_make_wreserv); ++ ++int ub_sock_get_wreserv(struct sock *sk, int bufid, unsigned long size) ++{ ++ struct sock_beancounter *skbc; ++ ++ if (unlikely(!sock_has_ubc(sk))) ++ return 0; ++ ++ /* optimize for the case if socket has sufficient reserve */ ++ ub_sock_make_wreserv(sk, bufid, size); ++ skbc = sock_bc(sk); ++ if (likely(skbc->poll_reserv >= size)) { ++ skbc->poll_reserv -= size; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++EXPORT_SYMBOL(ub_sock_get_wreserv); ++ ++static void ub_sock_do_ret_wreserv(struct sock *sk, int bufid, ++ unsigned long size, unsigned long ressize) ++{ ++ struct sock_beancounter *skbc; ++ struct user_beancounter *ub; ++ unsigned long extra; ++ unsigned long flags; ++ ++ skbc = sock_bc(sk); ++ ub = top_beancounter(skbc->ub); ++ ++ extra = 0; ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ skbc->poll_reserv += size; ++ if (skbc->poll_reserv > ressize) { ++ extra = skbc->poll_reserv - ressize; ++ ub_sock_wcharge_dec(sk, extra); ++ skbc->poll_reserv = ressize; ++ ++ __uncharge_beancounter_locked(ub, bufid, extra); ++ if (bufid == UB_TCPSNDBUF) ++ ub_tcp_snd_wakeup(ub); ++ else ++ ub_sock_snd_wakeup(ub); ++ } ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ ++ if (extra) ++ uncharge_beancounter_notop(skbc->ub, bufid, extra); ++} ++ ++void ub_sock_ret_wreserv(struct sock *sk, int bufid, ++ unsigned long size, unsigned long ressize) ++{ ++ struct sock_beancounter *skbc; ++ struct user_beancounter *ub; ++ ++ if (unlikely(!sock_has_ubc(sk))) ++ return; ++ ++ skbc = sock_bc(sk); ++ ub = top_beancounter(skbc->ub); ++ /* check if the reserve can be kept */ ++ if (ub_barrier_farsz(ub, bufid)) { ++ skbc->poll_reserv += size; ++ return; ++ } ++ ub_sock_do_ret_wreserv(sk, bufid, size, ressize); ++} ++ ++/* ++ * UB_DGRAMRCVBUF ++ */ ++ ++int ub_sockrcvbuf_charge(struct sock *sk, struct sk_buff *skb) ++{ ++ unsigned long chargesize; ++ ++ if (unlikely(!sock_has_ubc(sk))) ++ return 0; ++ ++ chargesize = skb_charge_fullsize(skb); ++ if (charge_beancounter(sock_bc(sk)->ub, UB_DGRAMRCVBUF, ++ chargesize, UB_HARD)) ++ return -ENOMEM; ++ ++ ub_skb_set_charge(skb, sk, chargesize, UB_DGRAMRCVBUF); ++ return 0; ++} ++ ++EXPORT_SYMBOL(ub_sockrcvbuf_charge); ++ ++static void ub_sockrcvbuf_uncharge(struct sk_buff *skb) ++{ ++ uncharge_beancounter(skb_bc(skb)->ub, UB_DGRAMRCVBUF, ++ skb_bc(skb)->charged); ++ ub_skb_set_uncharge(skb); ++} ++ ++/* ++ * UB_TCPRCVBUF ++ */ ++ ++int ub_sock_tcp_chargerecv(struct sock *sk, struct sk_buff *skb, ++ enum ub_severity strict) ++{ ++ int retval; ++ unsigned long flags; ++ struct user_beancounter *ub; ++ struct sock_beancounter *skbc; ++ unsigned long chargesize; ++ ++ if (unlikely(!sock_has_ubc(sk))) ++ return 0; ++ skbc = sock_bc(sk); ++ ++ chargesize = skb_charge_fullsize(skb); ++ if (likely(skbc->forw_space >= chargesize)) { ++ skbc->forw_space -= chargesize; ++ __ub_skb_set_charge(skb, sk, chargesize, UB_TCPRCVBUF); ++ return 0; ++ } ++ ++ /* ++ * Memory pressure reactions: ++ * 1) set UB_RMEM_KEEP (clearing UB_RMEM_EXPAND) ++ * 2) set UB_RMEM_SHRINK and tcp_clamp_window() ++ * tcp_collapse_queues() if rmem_alloc > rcvbuf ++ * 3) drop OFO, tcp_purge_ofo() ++ * 4) drop all. ++ * Currently, we do #2 and #3 at once (which means that current ++ * collapsing of OFO queue in tcp_collapse_queues() is a waste of time, ++ * for example...) ++ * On memory pressure we jump from #0 to #3, and when the pressure ++ * subsides, to #1. ++ */ ++ retval = 0; ++ ub = top_beancounter(sock_bc(sk)->ub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ ub->ub_parms[UB_TCPRCVBUF].held += chargesize; ++ if (ub->ub_parms[UB_TCPRCVBUF].held > ++ ub->ub_parms[UB_TCPRCVBUF].barrier && ++ strict != UB_FORCE) ++ goto excess; ++ ub_adjust_maxheld(ub, UB_TCPRCVBUF); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ ++out: ++ if (retval == 0) { ++ charge_beancounter_notop(sock_bc(sk)->ub, UB_TCPRCVBUF, ++ chargesize); ++ ub_skb_set_charge(skb, sk, chargesize, UB_TCPRCVBUF); ++ } ++ return retval; ++ ++excess: ++ ub->ub_rmem_pressure = UB_RMEM_SHRINK; ++ if (strict == UB_HARD) ++ retval = -ENOMEM; ++ if (ub->ub_parms[UB_TCPRCVBUF].held > ub->ub_parms[UB_TCPRCVBUF].limit) ++ retval = -ENOMEM; ++ /* ++ * We try to leave numsock*maxadvmss as a reserve for sockets not ++ * queueing any data yet (if the difference between the barrier and the ++ * limit is enough for this reserve). ++ */ ++ if (ub->ub_parms[UB_TCPRCVBUF].held + ++ ub->ub_parms[UB_NUMTCPSOCK].limit * ub->ub_maxadvmss ++ > ub->ub_parms[UB_TCPRCVBUF].limit && ++ atomic_read(&sk->sk_rmem_alloc)) ++ retval = -ENOMEM; ++ if (retval) { ++ ub->ub_parms[UB_TCPRCVBUF].held -= chargesize; ++ ub->ub_parms[UB_TCPRCVBUF].failcnt++; ++ } ++ ub_adjust_maxheld(ub, UB_TCPRCVBUF); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ goto out; ++} ++EXPORT_SYMBOL(ub_sock_tcp_chargerecv); ++ ++static void ub_tcprcvbuf_uncharge(struct sk_buff *skb) ++{ ++ unsigned long flags; ++ unsigned long held, bar; ++ int prev_pres; ++ struct user_beancounter *ub; ++ ++ ub = top_beancounter(skb_bc(skb)->ub); ++ if (ub_barrier_farsz(ub, UB_TCPRCVBUF)) { ++ sock_bc(skb->sk)->forw_space += skb_bc(skb)->charged; ++ ub_skb_set_uncharge(skb); ++ return; ++ } ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ if (ub->ub_parms[UB_TCPRCVBUF].held < skb_bc(skb)->charged) { ++ printk(KERN_ERR "Uncharging %d for tcprcvbuf of %p with %lu\n", ++ skb_bc(skb)->charged, ++ ub, ub->ub_parms[UB_TCPRCVBUF].held); ++ /* ass-saving bung */ ++ skb_bc(skb)->charged = ub->ub_parms[UB_TCPRCVBUF].held; ++ } ++ ub->ub_parms[UB_TCPRCVBUF].held -= skb_bc(skb)->charged; ++ held = ub->ub_parms[UB_TCPRCVBUF].held; ++ bar = ub->ub_parms[UB_TCPRCVBUF].barrier; ++ prev_pres = ub->ub_rmem_pressure; ++ if (held <= bar - (bar >> 2)) ++ ub->ub_rmem_pressure = UB_RMEM_EXPAND; ++ else if (held <= bar) ++ ub->ub_rmem_pressure = UB_RMEM_KEEP; ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ ++ uncharge_beancounter_notop(skb_bc(skb)->ub, UB_TCPRCVBUF, ++ skb_bc(skb)->charged); ++ ub_skb_set_uncharge(skb); ++} ++ ++ ++/* ++ * UB_OTHERSOCKBUF and UB_TCPSNDBUF ++ */ ++ ++static void ub_socksndbuf_uncharge(struct sk_buff *skb) ++{ ++ unsigned long flags; ++ struct user_beancounter *ub, *cub; ++ unsigned long chargesize; ++ ++ cub = skb_bc(skb)->ub; ++ ub = top_beancounter(cub); ++ chargesize = skb_bc(skb)->charged; ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ __uncharge_beancounter_locked(ub, UB_OTHERSOCKBUF, chargesize); ++ if (skb->sk != NULL && sock_has_ubc(skb->sk)) ++ ub_sock_wcharge_dec(skb->sk, chargesize); ++ ub_sock_snd_wakeup(ub); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ ++ uncharge_beancounter_notop(cub, UB_OTHERSOCKBUF, chargesize); ++ ub_skb_set_uncharge(skb); ++} ++ ++/* expected to be called under socket lock */ ++static void ub_tcpsndbuf_uncharge(struct sk_buff *skb) ++{ ++ /* ++ * ub_sock_ret_wreserv call is abused here, we just want to uncharge ++ * skb size. However, to reduce duplication of the code doing ++ * ub_hfbarrier_hit check, ub_wcharged reduction, and wakeup we call ++ * a function that already does all of this. 2006/04/27 SAW ++ */ ++ ub_sock_ret_wreserv(skb->sk, UB_TCPSNDBUF, skb_bc(skb)->charged, ++ sock_bc(skb->sk)->poll_reserv); ++ ub_skb_set_uncharge(skb); ++} ++ ++void ub_skb_uncharge(struct sk_buff *skb) ++{ ++ switch (skb_bc(skb)->resource) { ++ case UB_TCPSNDBUF: ++ ub_tcpsndbuf_uncharge(skb); ++ break; ++ case UB_TCPRCVBUF: ++ ub_tcprcvbuf_uncharge(skb); ++ break; ++ case UB_DGRAMRCVBUF: ++ ub_sockrcvbuf_uncharge(skb); ++ break; ++ case UB_OTHERSOCKBUF: ++ ub_socksndbuf_uncharge(skb); ++ break; ++ } ++} ++ ++EXPORT_SYMBOL(ub_skb_uncharge); /* due to skb_orphan()/conntracks */ ++ ++/* ++ * Other sock reserve managment ++ */ ++ ++int ub_sock_getwres_other(struct sock *sk, unsigned long size) ++{ ++ struct sock_beancounter *skbc; ++ struct user_beancounter *ub; ++ unsigned long flags; ++ unsigned long added_reserv; ++ int err; ++ ++ if (unlikely(!sock_has_ubc(sk))) ++ return 0; ++ ++ /* ++ * Nothing except beancounter lock protects skbc->poll_reserv. ++ * So, take the lock and do the job. ++ * Dances with added_reserv repeat ub_sock_make_wreserv. ++ */ ++ skbc = sock_bc(sk); ++ ub = top_beancounter(skbc->ub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ added_reserv = -skbc->poll_reserv; ++ err = ub_sock_makewreserv_locked(sk, UB_OTHERSOCKBUF, size); ++ added_reserv += skbc->poll_reserv; ++ if (!err) ++ skbc->poll_reserv -= size; ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ ++ if (added_reserv) ++ charge_beancounter_notop(skbc->ub, UB_OTHERSOCKBUF, added_reserv); ++ ++ return err; ++} ++EXPORT_SYMBOL(ub_sock_getwres_other); ++ ++void ub_sock_retwres_other(struct sock *sk, ++ unsigned long size, unsigned long ressize) ++{ ++ if (unlikely(!sock_has_ubc(sk))) ++ return; ++ ++ ub_sock_do_ret_wreserv(sk, UB_OTHERSOCKBUF, size, ressize); ++} ++ ++/* ++ * TCP send buffers accouting. Paged part ++ */ ++ ++int ub_sock_tcp_chargepage(struct sock *sk) ++{ ++ struct sock_beancounter *skbc; ++ unsigned long extra; ++ int err; ++ ++ if (unlikely(!sock_has_ubc(sk))) ++ return 0; ++ ++ skbc = sock_bc(sk); ++ ub_sock_make_wreserv(sk, UB_TCPSNDBUF, PAGE_SIZE); ++ if (likely(skbc->poll_reserv >= PAGE_SIZE)) { ++ skbc->poll_reserv -= PAGE_SIZE; ++ return 0; ++ } ++ ++ /* ++ * Ok, full page is not available. ++ * However, this function must succeed if poll previously indicated ++ * that write is possible. We better make a forced charge here ++ * than reserve a whole page in poll. ++ */ ++ err = ub_sock_make_wreserv(sk, UB_TCPSNDBUF, SOCK_MIN_UBCSPACE); ++ if (unlikely(err < 0)) ++ goto out; ++ if (skbc->poll_reserv < PAGE_SIZE) { ++ extra = PAGE_SIZE - skbc->poll_reserv; ++ err = charge_beancounter(skbc->ub, UB_TCPSNDBUF, extra, ++ UB_FORCE); ++ if (err < 0) ++ goto out; ++ skbc->poll_reserv += extra; ++ } ++ skbc->poll_reserv -= PAGE_SIZE; ++ return 0; ++ ++out: ++ return err; ++} ++ ++void ub_sock_tcp_detachpage(struct sock *sk) ++{ ++ struct sk_buff *skb; ++ ++ if (unlikely(!sock_has_ubc(sk))) ++ return; ++ ++ /* The page is just detached from socket. The last skb in queue ++ with paged part holds referrence to it */ ++ skb = skb_peek_tail(&sk->sk_write_queue); ++ if (skb == NULL) { ++ /* If the queue is empty - all data is sent and page is about ++ to be freed */ ++ ub_sock_ret_wreserv(sk, UB_TCPSNDBUF, PAGE_SIZE, ++ sock_bc(sk)->poll_reserv); ++ } else { ++ /* Last skb is a good aproximation for a last skb with ++ paged part */ ++ skb_bc(skb)->charged += PAGE_SIZE; ++ } ++} ++ ++/* ++ * TCPSNDBUF charge functions below are called in the following cases: ++ * - sending of SYN, SYN-ACK, FIN, the latter charge is forced by ++ * some technical reasons in TCP code; ++ * - fragmentation of TCP packets. ++ * These functions are allowed but not required to use poll_reserv. ++ * Originally, these functions didn't do that, since it didn't make ++ * any sense. Now, since poll_reserv now has a function of general reserve, ++ * they use it. ++ */ ++int ub_sock_tcp_chargesend(struct sock *sk, struct sk_buff *skb, ++ enum ub_severity strict) ++{ ++ int ret; ++ unsigned long chargesize; ++ struct sock_beancounter *skbc; ++ struct user_beancounter *ub; ++ unsigned long flags; ++ ++ if (unlikely(!sock_has_ubc(sk))) ++ return 0; ++ ++ skbc = sock_bc(sk); ++ chargesize = skb_charge_fullsize(skb); ++ if (likely(skbc->poll_reserv >= chargesize)) { ++ skbc->poll_reserv -= chargesize; ++ __ub_skb_set_charge(skb, sk, chargesize, UB_TCPSNDBUF); ++ /* XXX hack, see ub_skb_set_charge */ ++ skb->sk = sk; ++ return 0; ++ } ++ ++ ub = top_beancounter(skbc->ub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ ret = __charge_beancounter_locked(ub, UB_TCPSNDBUF, ++ chargesize, strict); ++ /* ++ * Note: this check is not equivalent of the corresponding check ++ * in makewreserv. It's similar in spirit, but an equivalent check ++ * would be too long and complicated here. ++ */ ++ if (!ret && ub_barrier_hit(ub, UB_TCPSNDBUF)) ++ skbc->ub_wcharged += chargesize; ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ if (likely(!ret)) { ++ charge_beancounter_notop(skbc->ub, UB_TCPSNDBUF, chargesize); ++ ub_skb_set_charge(skb, sk, chargesize, UB_TCPSNDBUF); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(ub_sock_tcp_chargesend); ++ ++void ub_sock_tcp_unchargesend(struct sock *sk, unsigned long size) ++{ ++ if (unlikely(!sock_has_ubc(sk))) ++ return; ++ /* see ub_tcpsndbuf_uncharge */ ++ ub_sock_ret_wreserv(sk, UB_TCPSNDBUF, size, sock_bc(sk)->poll_reserv); ++} ++ ++/* ++ * Initialization ++ */ ++ ++int __init skbc_cache_init(void) ++{ ++ return 0; ++} +Index: kernel/kernel/bc/oom_kill.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/oom_kill.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,200 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define UB_OOM_TIMEOUT (5 * HZ) ++ ++int oom_generation; ++int oom_kill_counter; ++static DEFINE_SPINLOCK(oom_lock); ++static DECLARE_WAIT_QUEUE_HEAD(oom_wq); ++ ++static inline int ub_oom_completed(struct task_struct *tsk) ++{ ++ if (test_tsk_thread_flag(tsk, TIF_MEMDIE)) ++ /* we were oom killed - just die */ ++ return 1; ++ if (tsk->task_bc.oom_generation != oom_generation) ++ /* some task was succesfully killed */ ++ return 1; ++ return 0; ++} ++ ++static void ub_clear_oom(void) ++{ ++ struct user_beancounter *ub; ++ ++ rcu_read_lock(); ++ for_each_beancounter(ub) ++ ub->ub_oom_noproc = 0; ++ rcu_read_unlock(); ++} ++ ++/* Called with cpuset_lock held */ ++int ub_oom_lock(void) ++{ ++ int timeout; ++ DEFINE_WAIT(oom_w); ++ struct task_struct *tsk; ++ ++ tsk = current; ++ ++ spin_lock(&oom_lock); ++ if (!oom_kill_counter) ++ goto out_do_oom; ++ ++ timeout = UB_OOM_TIMEOUT; ++ while (1) { ++ if (ub_oom_completed(tsk)) { ++ spin_unlock(&oom_lock); ++ return -EINVAL; ++ } ++ ++ if (timeout == 0) ++ break; ++ ++ __set_current_state(TASK_UNINTERRUPTIBLE); ++ add_wait_queue(&oom_wq, &oom_w); ++ spin_unlock(&oom_lock); ++ cpuset_unlock(); ++ ++ timeout = schedule_timeout(timeout); ++ ++ cpuset_lock(); ++ spin_lock(&oom_lock); ++ remove_wait_queue(&oom_wq, &oom_w); ++ } ++ ++out_do_oom: ++ ub_clear_oom(); ++ return 0; ++} ++ ++static inline long ub_current_overdraft(struct user_beancounter *ub) ++{ ++ return ub->ub_parms[UB_OOMGUARPAGES].held + ++ ((ub->ub_parms[UB_KMEMSIZE].held ++ + ub->ub_parms[UB_TCPSNDBUF].held ++ + ub->ub_parms[UB_TCPRCVBUF].held ++ + ub->ub_parms[UB_OTHERSOCKBUF].held ++ + ub->ub_parms[UB_DGRAMRCVBUF].held) ++ >> PAGE_SHIFT) - ub->ub_parms[UB_OOMGUARPAGES].barrier; ++} ++ ++int ub_oom_task_skip(struct user_beancounter *ub, struct task_struct *tsk) ++{ ++ struct user_beancounter *mm_ub; ++ ++ if (ub == NULL) ++ return 0; ++ ++ task_lock(tsk); ++ if (tsk->mm == NULL) ++ mm_ub = NULL; ++ else ++ mm_ub = tsk->mm->mm_ub; ++ ++ while (mm_ub != NULL && mm_ub != ub) ++ mm_ub = mm_ub->parent; ++ task_unlock(tsk); ++ ++ return mm_ub != ub; ++} ++ ++struct user_beancounter *ub_oom_select_worst(void) ++{ ++ struct user_beancounter *ub, *walkp; ++ long ub_maxover; ++ ++ ub_maxover = 0; ++ ub = NULL; ++ ++ rcu_read_lock(); ++ for_each_beancounter (walkp) { ++ long ub_overdraft; ++ ++ if (walkp->parent != NULL) ++ continue; ++ if (walkp->ub_oom_noproc) ++ continue; ++ ++ ub_overdraft = ub_current_overdraft(walkp); ++ if (ub_overdraft > ub_maxover && get_beancounter_rcu(walkp)) { ++ put_beancounter(ub); ++ ub = walkp; ++ ub_maxover = ub_overdraft; ++ } ++ } ++ ++ if (ub) ++ ub->ub_oom_noproc = 1; ++ rcu_read_unlock(); ++ ++ return ub; ++} ++ ++void ub_oom_mm_killed(struct user_beancounter *ub) ++{ ++ static struct ub_rate_info ri = { 5, 60*HZ }; ++ ++ /* increment is serialized with oom_lock */ ++ ub->ub_parms[UB_OOMGUARPAGES].failcnt++; ++ ++ if (ub_ratelimit(&ri)) ++ show_mem(); ++} ++ ++void ub_oom_unlock(void) ++{ ++ spin_unlock(&oom_lock); ++} ++ ++void ub_oom_task_dead(struct task_struct *tsk) ++{ ++ spin_lock(&oom_lock); ++ oom_kill_counter = 0; ++ oom_generation++; ++ ++ printk("OOM killed process %s (pid=%d, ve=%d) exited, " ++ "free=%lu gen=%d.\n", ++ tsk->comm, tsk->pid, VEID(tsk->ve_task_info.owner_env), ++ nr_free_pages(), oom_generation); ++ /* if there is time to sleep in ub_oom_lock -> sleep will continue */ ++ wake_up_all(&oom_wq); ++ spin_unlock(&oom_lock); ++} ++ ++void ub_out_of_memory(struct user_beancounter *scope) ++{ ++ struct user_beancounter *ub; ++ struct task_struct *p; ++ ++ cpuset_lock(); ++ spin_lock(&oom_lock); ++ ub_clear_oom(); ++ ub = get_beancounter(scope); ++ ++ read_lock(&tasklist_lock); ++retry: ++ p = oom_select_bad_process(ub); ++ if (p == NULL || PTR_ERR(p) == -1UL) ++ goto unlock; ++ ++ if (oom_kill_process(p, (gfp_t)-1, -1, "UB Out of memory")) ++ goto retry; ++ ++ put_beancounter(ub); ++ ++unlock: ++ read_unlock(&tasklist_lock); ++ spin_unlock(&oom_lock); ++ cpuset_unlock(); ++} ++EXPORT_SYMBOL(ub_out_of_memory); +Index: kernel/kernel/bc/proc.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/proc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,680 @@ ++/* ++ * kernel/bc/proc.c ++ * ++ * Copyright (C) 2006 OpenVZ. SWsoft Inc. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* Generic output formats */ ++#if BITS_PER_LONG == 32 ++const char *bc_proc_lu_fmt = "\t%-20s %10lu\n"; ++const char *bc_proc_lu_lfmt = "\t%-20s %21lu\n"; ++const char *bc_proc_llu_fmt = "\t%-20s %21llu\n"; ++const char *bc_proc_lu_lu_fmt = "\t%-20s %10lu %10lu\n"; ++#else ++const char *bc_proc_lu_fmt = "\t%-20s %21lu\n"; ++const char *bc_proc_lu_lfmt = "\t%-20s %21lu\n"; ++const char *bc_proc_llu_fmt = "\t%-20s %21llu\n"; ++const char *bc_proc_lu_lu_fmt = "\t%-20s %21lu %21lu\n"; ++#endif ++ ++#if BITS_PER_LONG == 32 ++static const char *head_fmt = "%10s %-12s %10s %10s %10s %10s %10s\n"; ++static const char *res_fmt = "%10s %-12s %10lu %10lu %10lu %10lu %10lu\n"; ++#else ++static const char *head_fmt = "%10s %-12s %20s %20s %20s %20s %20s\n"; ++static const char *res_fmt = "%10s %-12s %20lu %20lu %20lu %20lu %20lu\n"; ++#endif ++ ++static void ub_show_res(struct seq_file *f, struct user_beancounter *ub, ++ int r, int show_uid) ++{ ++ int len; ++ char ub_uid[64]; ++ ++ if (show_uid && r == 0) { ++ len = print_ub_uid(ub, ub_uid, sizeof(ub_uid) - 2); ++ ub_uid[len] = ':'; ++ ub_uid[len + 1] = '\0'; ++ } else ++ strcpy(ub_uid, ""); ++ ++ seq_printf(f, res_fmt, ub_uid, ub_rnames[r], ++ ub->ub_parms[r].held, ++ ub->ub_parms[r].maxheld, ++ ub->ub_parms[r].barrier, ++ ub->ub_parms[r].limit, ++ ub->ub_parms[r].failcnt); ++} ++ ++static void __show_resources(struct seq_file *f, struct user_beancounter *ub, ++ int show_uid) ++{ ++ int i; ++ ++ for (i = 0; i < UB_RESOURCES_COMPAT; i++) ++ if (strcmp(ub_rnames[i], "dummy") != 0) ++ ub_show_res(f, ub, i, show_uid); ++ ++ for (i = UB_RESOURCES_COMPAT; i < UB_RESOURCES; i++) ++ ub_show_res(f, ub, i, show_uid); ++} ++ ++static int bc_resources_show(struct seq_file *f, void *v) ++{ ++ __show_resources(f, seq_beancounter(f), 0); ++ return 0; ++} ++ ++static struct bc_proc_entry bc_resources_entry = { ++ .name = "resources", ++ .u.show = bc_resources_show, ++}; ++ ++static int bc_debug_show(struct seq_file *f, void *v) ++{ ++ struct user_beancounter *ub; ++ char buf[64]; ++ ++ ub = seq_beancounter(f); ++ print_ub_uid(ub, buf, sizeof(buf)); ++ seq_printf(f, "uid: %s\n", buf); ++ seq_printf(f, "ref: %d\n", atomic_read(&ub->ub_refcount)); ++ ++ seq_printf(f, "bc: %p\n", ub); ++ seq_printf(f, "par: %p\n", ub->parent); ++ seq_printf(f, "priv: %p\n", ub->private_data); ++ return 0; ++} ++ ++static struct bc_proc_entry bc_debug_entry = { ++ .name = "debug", ++ .u.show = bc_debug_show, ++}; ++ ++static int ub_show(struct seq_file *f, void *v) ++{ ++ int i; ++ ++ for (i = 0; i < UB_RESOURCES_COMPAT; i++) ++ ub_show_res(f, (struct user_beancounter *)v, i, 1); ++ return 0; ++} ++ ++static int res_show(struct seq_file *f, void *v) ++{ ++ __show_resources(f, (struct user_beancounter *)v, 1); ++ return 0; ++} ++ ++static int ub_accessible(struct user_beancounter *exec, ++ struct user_beancounter *target) ++{ ++ struct user_beancounter *p, *q; ++ ++ p = top_beancounter(exec); ++ q = top_beancounter(target); ++ ++ return (p == get_ub0() || p == q); ++} ++ ++static void ub_show_header(struct seq_file *f) ++{ ++ seq_printf(f, "Version: 2.5\n"); ++ seq_printf(f, head_fmt, "uid", "resource", ++ "held", "maxheld", "barrier", "limit", "failcnt"); ++} ++ ++static void *ub_start(struct seq_file *f, loff_t *ppos) ++{ ++ struct user_beancounter *ub; ++ struct user_beancounter *exec_ub; ++ unsigned long pos; ++ ++ pos = *ppos; ++ if (pos == 0) ++ ub_show_header(f); ++ ++ exec_ub = get_exec_ub(); ++ ++ rcu_read_lock(); ++ for_each_beancounter(ub) { ++ if (ub->parent != NULL) ++ continue; ++ if (!ub_accessible(exec_ub, ub)) ++ continue; ++ if (pos-- == 0) ++ return ub; ++ } ++ return NULL; ++} ++ ++static void *ub_next(struct seq_file *f, void *v, loff_t *ppos) ++{ ++ struct user_beancounter *ub; ++ struct list_head *entry; ++ struct user_beancounter *exec_ub; ++ ++ exec_ub = get_exec_ub(); ++ ub = (struct user_beancounter *)v; ++ ++ entry = &ub->ub_list; ++ ++ list_for_each_continue_rcu(entry, &ub_list_head) { ++ ub = list_entry(entry, struct user_beancounter, ub_list); ++ if (ub->parent != NULL) ++ continue; ++ if (!ub_accessible(exec_ub, ub)) ++ continue; ++ ++ (*ppos)++; ++ return ub; ++ } ++ return NULL; ++} ++ ++static void ub_stop(struct seq_file *f, void *v) ++{ ++ rcu_read_unlock(); ++} ++ ++static struct seq_operations ub_seq_ops = { ++ .start = ub_start, ++ .next = ub_next, ++ .stop = ub_stop, ++ .show = ub_show, ++}; ++ ++static int ub_open(struct inode *inode, struct file *filp) ++{ ++ if (!(capable(CAP_DAC_OVERRIDE) && capable(CAP_DAC_READ_SEARCH))) ++ return -EACCES; ++ ++ return seq_open(filp, &ub_seq_ops); ++} ++ ++static struct file_operations ub_file_operations = { ++ .open = ub_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++static struct seq_operations res_seq_ops = { ++ .start = ub_start, ++ .next = ub_next, ++ .stop = ub_stop, ++ .show = res_show, ++}; ++ ++static int res_open(struct inode *inode, struct file *filp) ++{ ++ if (!(capable(CAP_DAC_OVERRIDE) && capable(CAP_DAC_READ_SEARCH))) ++ return -EACCES; ++ ++ return seq_open(filp, &res_seq_ops); ++} ++ ++static struct file_operations resources_operations = { ++ .open = res_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++static struct bc_proc_entry bc_all_resources_entry = { ++ .name = "resources", ++ .u.fops = &resources_operations, ++}; ++ ++/* ++ * Generic showing stuff ++ */ ++ ++static int cookies, num_entries; ++static struct bc_proc_entry *bc_entries __read_mostly; ++static struct bc_proc_entry *bc_root_entries __read_mostly; ++static DEFINE_SPINLOCK(bc_entries_lock); ++static struct proc_dir_entry *bc_proc_root; ++ ++void bc_register_proc_entry(struct bc_proc_entry *e) ++{ ++ spin_lock(&bc_entries_lock); ++ e->cookie = ++cookies; ++ e->next = bc_entries; ++ bc_entries = e; ++ num_entries++; ++ spin_unlock(&bc_entries_lock); ++} ++ ++EXPORT_SYMBOL(bc_register_proc_entry); ++ ++void bc_register_proc_root_entry(struct bc_proc_entry *e) ++{ ++ spin_lock(&bc_entries_lock); ++ e->cookie = ++cookies; ++ e->next = bc_root_entries; ++ bc_root_entries = e; ++ bc_proc_root->nlink++; ++ spin_unlock(&bc_entries_lock); ++} ++ ++EXPORT_SYMBOL(bc_register_proc_root_entry); ++ ++/* ++ * small helpers ++ */ ++ ++static inline unsigned long bc_make_ino(struct user_beancounter *ub) ++{ ++ unsigned long ret; ++ ++ ret = 0xbc000000; ++ if (ub->parent) ++ ret |= ((ub->parent->ub_uid) << 4); ++ ret |= (ub->ub_uid + 1); ++ return ret; ++} ++ ++static inline unsigned long bc_make_file_ino(struct bc_proc_entry *de) ++{ ++ return 0xbe000000 + de->cookie; ++} ++ ++static int bc_d_delete(struct dentry *d) ++{ ++ return 1; ++} ++ ++static void bc_d_release(struct dentry *d) ++{ ++ put_beancounter((struct user_beancounter *)d->d_fsdata); ++} ++ ++static struct inode_operations bc_entry_iops; ++static struct file_operations bc_entry_fops; ++static struct dentry_operations bc_dentry_ops = { ++ .d_delete = bc_d_delete, ++ .d_release = bc_d_release, ++}; ++ ++/* ++ * common directory operations' helpers ++ */ ++ ++static int bc_readdir(struct file *file, filldir_t filler, void *data, ++ struct user_beancounter *parent) ++{ ++ int err = 0; ++ loff_t pos, filled; ++ struct user_beancounter *ub, *prev; ++ struct bc_proc_entry *pde; ++ ++ if (!(capable(CAP_DAC_OVERRIDE) && capable(CAP_DAC_READ_SEARCH))) ++ return -EPERM; ++ ++ pos = file->f_pos; ++ if (pos == 0) { ++ err = (*filler)(data, ".", 1, pos, ++ file->f_dentry->d_inode->i_ino, DT_DIR); ++ if (err < 0) { ++ err = 0; ++ goto out; ++ } ++ pos++; ++ } ++ ++ if (pos == 1) { ++ err = (*filler)(data, "..", 2, pos, ++ parent_ino(file->f_dentry), DT_DIR); ++ if (err < 0) { ++ err = 0; ++ goto out; ++ } ++ pos++; ++ } ++ ++ filled = 2; ++ for (pde = (parent == NULL ? bc_root_entries : bc_entries); ++ pde != NULL; pde = pde->next) { ++ if (filled++ < pos) ++ continue; ++ ++ err = (*filler)(data, pde->name, strlen(pde->name), pos, ++ bc_make_file_ino(pde), DT_REG); ++ if (err < 0) { ++ err = 0; ++ goto out; ++ } ++ pos++; ++ } ++ ++ rcu_read_lock(); ++ prev = NULL; ++ ub = list_entry(&ub_list_head, struct user_beancounter, ub_list); ++ while (1) { ++ int len; ++ unsigned long ino; ++ char buf[64]; ++ ++ ub = list_entry(rcu_dereference(ub->ub_list.next), ++ struct user_beancounter, ub_list); ++ if (&ub->ub_list == &ub_list_head) ++ break; ++ ++ if (ub->parent != parent) ++ continue; ++ ++ if (filled++ < pos) ++ continue; ++ ++ if (!get_beancounter_rcu(ub)) ++ continue; ++ ++ rcu_read_unlock(); ++ put_beancounter(prev); ++ ++ len = print_ub_uid(ub, buf, sizeof(buf)); ++ ino = bc_make_ino(ub); ++ ++ err = (*filler)(data, buf, len, pos, ino, DT_DIR); ++ if (err < 0) { ++ err = 0; ++ put_beancounter(ub); ++ goto out; ++ } ++ ++ rcu_read_lock(); ++ prev = ub; ++ pos++; ++ } ++ rcu_read_unlock(); ++ put_beancounter(prev); ++out: ++ file->f_pos = pos; ++ return err; ++} ++ ++static int bc_looktest(struct inode *ino, void *data) ++{ ++ return ino->i_op == &bc_entry_iops && ino->i_private == data; ++} ++ ++static int bc_lookset(struct inode *ino, void *data) ++{ ++ struct user_beancounter *ub; ++ ++ ub = (struct user_beancounter *)data; ++ ino->i_private = data; ++ ino->i_ino = bc_make_ino(ub); ++ ino->i_fop = &bc_entry_fops; ++ ino->i_op = &bc_entry_iops; ++ ino->i_mode = S_IFDIR | S_IRUSR | S_IXUGO; ++ /* subbeancounters are not included, but who cares? */ ++ ino->i_nlink = num_entries + 2; ++ ino->i_gid = 0; ++ ino->i_uid = 0; ++ return 0; ++} ++ ++static struct dentry *bc_lookup(struct user_beancounter *ub, struct inode *dir, ++ struct dentry *dentry) ++{ ++ struct inode *ino; ++ ++ ino = iget5_locked(dir->i_sb, ub->ub_uid, bc_looktest, bc_lookset, ub); ++ if (ino == NULL) ++ goto out_put; ++ ++ unlock_new_inode(ino); ++ dentry->d_op = &bc_dentry_ops; ++ dentry->d_fsdata = ub; ++ d_add(dentry, ino); ++ return NULL; ++ ++out_put: ++ put_beancounter(ub); ++ return ERR_PTR(-ENOENT); ++} ++ ++/* ++ * files (bc_proc_entry) manipulations ++ */ ++ ++static struct dentry *bc_lookup_file(struct inode *dir, ++ struct dentry *dentry, struct bc_proc_entry *root, ++ int (*test)(struct inode *, void *), ++ int (*set)(struct inode *, void *)) ++{ ++ struct bc_proc_entry *pde; ++ struct inode *ino; ++ ++ for (pde = root; pde != NULL; pde = pde->next) ++ if (strcmp(pde->name, dentry->d_name.name) == 0) ++ break; ++ ++ if (pde == NULL) ++ return ERR_PTR(-ESRCH); ++ ++ ino = iget5_locked(dir->i_sb, pde->cookie, test, set, pde); ++ if (ino == NULL) ++ return ERR_PTR(-ENOENT); ++ ++ unlock_new_inode(ino); ++ dentry->d_op = &bc_dentry_ops; ++ d_add(dentry, ino); ++ return NULL; ++} ++ ++static int bc_file_open(struct inode *ino, struct file *filp) ++{ ++ struct bc_proc_entry *de; ++ struct user_beancounter *ub; ++ ++ de = (struct bc_proc_entry *)ino->i_private; ++ ub = (struct user_beancounter *)filp->f_dentry->d_parent->d_fsdata; ++ BUG_ON(ub->ub_magic != UB_MAGIC); ++ ++ /* ++ * ub can't disappear: we hold d_parent, he holds the beancounter ++ */ ++ return single_open(filp, de->u.show, ub); ++} ++ ++static struct file_operations bc_file_ops = { ++ .open = bc_file_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int bc_looktest_entry(struct inode *ino, void *data) ++{ ++ return ino->i_fop == &bc_file_ops && ino->i_private == data; ++} ++ ++static int bc_lookset_entry(struct inode *ino, void *data) ++{ ++ struct bc_proc_entry *de; ++ ++ de = (struct bc_proc_entry *)data; ++ ino->i_private = data; ++ ino->i_ino = bc_make_file_ino(de); ++ ino->i_fop = &bc_file_ops, ++ ino->i_mode = S_IFREG | S_IRUSR; ++ ino->i_nlink = 1; ++ ino->i_gid = 0; ++ ino->i_uid = 0; ++ return 0; ++} ++ ++static inline struct dentry *bc_lookup_files(struct inode *dir, ++ struct dentry *de) ++{ ++ return bc_lookup_file(dir, de, bc_entries, ++ bc_looktest_entry, bc_lookset_entry); ++} ++ ++static int bc_looktest_root_entry(struct inode *ino, void *data) ++{ ++ struct bc_proc_entry *de; ++ ++ de = (struct bc_proc_entry *)data; ++ return ino->i_fop == de->u.fops && ino->i_private == data; ++} ++ ++static int bc_lookset_root_entry(struct inode *ino, void *data) ++{ ++ struct bc_proc_entry *de; ++ ++ de = (struct bc_proc_entry *)data; ++ ino->i_private = data; ++ ino->i_ino = bc_make_file_ino(de); ++ ino->i_fop = de->u.fops; ++ ino->i_mode = S_IFREG | S_IRUSR; ++ ino->i_nlink = 1; ++ ino->i_gid = 0; ++ ino->i_uid = 0; ++ return 0; ++} ++ ++static inline struct dentry *bc_lookup_root_files(struct inode *dir, ++ struct dentry *de) ++{ ++ return bc_lookup_file(dir, de, bc_root_entries, ++ bc_looktest_root_entry, bc_lookset_root_entry); ++} ++ ++/* ++ * /proc/bc/.../ directory operations ++ */ ++ ++static int bc_entry_readdir(struct file *file, void *data, filldir_t filler) ++{ ++ return bc_readdir(file, filler, data, ++ (struct user_beancounter *)file->f_dentry->d_fsdata); ++} ++ ++static struct dentry *bc_entry_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ int id; ++ char *end; ++ struct user_beancounter *par, *ub; ++ struct dentry *de; ++ ++ if (!(capable(CAP_DAC_OVERRIDE) && capable(CAP_DAC_READ_SEARCH))) ++ return ERR_PTR(-EPERM); ++ ++ de = bc_lookup_files(dir, dentry); ++ if (de != ERR_PTR(-ESRCH)) ++ return de; ++ ++ id = simple_strtol(dentry->d_name.name, &end, 10); ++ if (*end != '.') ++ return ERR_PTR(-ENOENT); ++ ++ par = (struct user_beancounter *)dir->i_private; ++ if (par->ub_uid != id) ++ return ERR_PTR(-ENOENT); ++ ++ id = simple_strtol(end + 1, &end, 10); ++ if (*end != '\0') ++ return ERR_PTR(-ENOENT); ++ ++ ub = get_subbeancounter_byid(par, id, 0); ++ if (ub == NULL) ++ return ERR_PTR(-ENOENT); ++ ++ return bc_lookup(ub, dir, dentry); ++} ++ ++static struct file_operations bc_entry_fops = { ++ .read = generic_read_dir, ++ .readdir = bc_entry_readdir, ++}; ++ ++static struct inode_operations bc_entry_iops = { ++ .lookup = bc_entry_lookup, ++}; ++ ++/* ++ * /proc/bc directory operations ++ */ ++ ++static int bc_root_readdir(struct file *file, void *data, filldir_t filler) ++{ ++ return bc_readdir(file, filler, data, NULL); ++} ++ ++static struct dentry *bc_root_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ int id; ++ char *end; ++ struct user_beancounter *ub; ++ struct dentry *de; ++ ++ if (!(capable(CAP_DAC_OVERRIDE) && capable(CAP_DAC_READ_SEARCH))) ++ return ERR_PTR(-EPERM); ++ ++ de = bc_lookup_root_files(dir, dentry); ++ if (de != ERR_PTR(-ESRCH)) ++ return de; ++ ++ id = simple_strtol(dentry->d_name.name, &end, 10); ++ if (*end != '\0') ++ return ERR_PTR(-ENOENT); ++ ++ ub = get_beancounter_byuid(id, 0); ++ if (ub == NULL) ++ return ERR_PTR(-ENOENT); ++ ++ return bc_lookup(ub, dir, dentry); ++} ++ ++static struct file_operations bc_root_fops = { ++ .read = generic_read_dir, ++ .readdir = bc_root_readdir, ++}; ++ ++static struct inode_operations bc_root_iops = { ++ .lookup = bc_root_lookup, ++}; ++ ++static int __init ub_init_proc(void) ++{ ++ struct proc_dir_entry *entry; ++ ++ bc_proc_root = create_proc_entry("bc", ++ S_IFDIR | S_IRUGO | S_IXUGO, NULL); ++ if (bc_proc_root == NULL) ++ panic("Can't create /proc/bc entry"); ++ ++ bc_proc_root->proc_fops = &bc_root_fops; ++ bc_proc_root->proc_iops = &bc_root_iops; ++ ++ bc_register_proc_entry(&bc_resources_entry); ++#ifdef CONFIG_UBC_DEBUG ++ bc_register_proc_entry(&bc_debug_entry); ++#endif ++ bc_register_proc_root_entry(&bc_all_resources_entry); ++ ++ entry = create_proc_glob_entry("user_beancounters", S_IRUGO, NULL); ++ entry->proc_fops = &ub_file_operations; ++ return 0; ++} ++ ++core_initcall(ub_init_proc); +Index: kernel/kernel/bc/rss_pages.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/rss_pages.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,437 @@ ++/* ++ * kernel/bc/rss_pages.c ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++static struct kmem_cache *pb_cachep; ++spinlock_t pb_lock = SPIN_LOCK_UNLOCKED; ++static struct page_beancounter **pb_hash_table; ++static unsigned int pb_hash_mask; ++ ++/* ++ * Auxiliary staff ++ */ ++ ++static inline struct page_beancounter *next_page_pb(struct page_beancounter *p) ++{ ++ return list_entry(p->page_list.next, struct page_beancounter, ++ page_list); ++} ++ ++static inline struct page_beancounter *prev_page_pb(struct page_beancounter *p) ++{ ++ return list_entry(p->page_list.prev, struct page_beancounter, ++ page_list); ++} ++ ++/* ++ * Held pages manipulation ++ */ ++static inline void set_held_pages(struct user_beancounter *bc) ++{ ++ /* all three depend on ub_held_pages */ ++ __ub_update_physpages(bc); ++ __ub_update_oomguarpages(bc); ++ __ub_update_privvm(bc); ++} ++ ++static inline void do_dec_held_pages(struct user_beancounter *ub, int value) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ ub->ub_held_pages -= value; ++ set_held_pages(ub); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++static void dec_held_pages(struct user_beancounter *ub, int value) ++{ ++ for (; ub != NULL; ub = ub->parent) ++ do_dec_held_pages(ub, value); ++} ++ ++static inline void do_inc_held_pages(struct user_beancounter *ub, int value) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ ub->ub_held_pages += value; ++ set_held_pages(ub); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++static void inc_held_pages(struct user_beancounter *ub, int value) ++{ ++ for (; ub != NULL; ub = ub->parent) ++ do_inc_held_pages(ub, value); ++} ++ ++/* ++ * Alloc - free ++ */ ++ ++inline int pb_alloc(struct page_beancounter **pbc) ++{ ++ *pbc = kmem_cache_alloc(pb_cachep, GFP_KERNEL); ++ if (*pbc != NULL) { ++ (*pbc)->next_hash = NULL; ++ (*pbc)->pb_magic = PB_MAGIC; ++ } ++ return (*pbc == NULL); ++} ++ ++inline void pb_free(struct page_beancounter **pb) ++{ ++ if (*pb != NULL) { ++ kmem_cache_free(pb_cachep, *pb); ++ *pb = NULL; ++ } ++} ++ ++void pb_free_list(struct page_beancounter **p_pb) ++{ ++ struct page_beancounter *list, *pb; ++ ++ list = *p_pb; ++ if (list == PBC_COPY_SAME) ++ return; ++ ++ while (list) { ++ pb = list; ++ list = list->next_hash; ++ pb_free(&pb); ++ } ++ *p_pb = NULL; ++} ++ ++/* ++ * head -> -> -> ... ++ */ ++static int __alloc_list(struct page_beancounter **head, int num) ++{ ++ struct page_beancounter *pb; ++ ++ while (num > 0) { ++ if (pb_alloc(&pb)) ++ return -1; ++ pb->next_hash = *head; ++ *head = pb; ++ num--; ++ } ++ ++ return num; ++} ++ ++/* ++ * Ensure that the list contains at least num elements. ++ * p_pb points to an initialized list, may be of the zero length. ++ * ++ * mm->page_table_lock should be held ++ */ ++int pb_alloc_list(struct page_beancounter **p_pb, int num) ++{ ++ struct page_beancounter *list; ++ ++ for (list = *p_pb; list != NULL && num; list = list->next_hash, num--); ++ if (!num) ++ return 0; ++ ++ /* ++ * *p_pb(after) *p_pb (before) ++ * \ \ ++ * -...-> -> ... ++ */ ++ if (__alloc_list(p_pb, num) < 0) ++ goto nomem; ++ return 0; ++ ++nomem: ++ pb_free_list(p_pb); ++ return -ENOMEM; ++} ++ ++/* ++ * Allocates a page_beancounter for each ++ * user_beancounter in a hash ++ */ ++int pb_alloc_all(struct page_beancounter **pbs) ++{ ++ int need_alloc; ++ struct user_beancounter *ub; ++ ++ need_alloc = 0; ++ rcu_read_lock(); ++ for_each_beancounter(ub) ++ need_alloc++; ++ rcu_read_unlock(); ++ ++ if (!__alloc_list(pbs, need_alloc)) ++ return 0; ++ ++ pb_free_list(pbs); ++ return -ENOMEM; ++} ++ ++/* ++ * Hash routines ++ */ ++ ++static inline int pb_hash(struct user_beancounter *ub, struct page *page) ++{ ++ return (page_to_pfn(page) + (ub->ub_uid << 10)) & pb_hash_mask; ++} ++ ++/* pb_lock should be held */ ++static inline void insert_pb(struct page_beancounter *p, struct page *page, ++ struct user_beancounter *ub, int hash) ++{ ++ p->page = page; ++ p->ub = get_beancounter(ub); ++ p->next_hash = pb_hash_table[hash]; ++ pb_hash_table[hash] = p; ++ inc_pbc_count(ub); ++} ++ ++/* ++ * Heart ++ */ ++ ++static int __pb_dup_ref(struct page *page, struct user_beancounter *bc, ++ int hash) ++{ ++ struct page_beancounter *p; ++ ++ for (p = pb_hash_table[hash]; ++ p != NULL && (p->page != page || p->ub != bc); ++ p = p->next_hash); ++ if (p == NULL) ++ return -1; ++ ++ PB_COUNT_INC(p->refcount); ++ return 0; ++} ++ ++static void __pb_add_ref(struct page *page, struct user_beancounter *bc, ++ struct page_beancounter **ppb, int hash) ++{ ++ struct page_beancounter *head, *p, **hp; ++ int shift; ++ ++ p = *ppb; ++ *ppb = p->next_hash; ++ ++ insert_pb(p, page, bc, hash); ++ hp = page_pblist(page); ++ head = *hp; ++ ++ if (head != NULL) { ++ /* ++ * Move the first element to the end of the list. ++ * List head (pb_head) is set to the next entry. ++ * Note that this code works even if head is the only element ++ * on the list (because it's cyclic). ++ */ ++ BUG_ON(head->pb_magic != PB_MAGIC); ++ *hp = next_page_pb(head); ++ PB_SHIFT_INC(head->refcount); ++ shift = PB_SHIFT_GET(head->refcount); ++ /* ++ * Update user beancounter, the share of head has been changed. ++ * Note that the shift counter is taken after increment. ++ */ ++ dec_held_pages(head->ub, UB_PAGE_WEIGHT >> shift); ++ /* add the new page beancounter to the end of the list */ ++ head = *hp; ++ list_add_tail(&p->page_list, &head->page_list); ++ } else { ++ *hp = p; ++ shift = 0; ++ INIT_LIST_HEAD(&p->page_list); ++ } ++ ++ p->refcount = PB_REFCOUNT_MAKE(shift, 1); ++ /* update user beancounter for the new page beancounter */ ++ inc_held_pages(bc, UB_PAGE_WEIGHT >> shift); ++} ++ ++void pb_add_ref(struct page *page, struct mm_struct *mm, ++ struct page_beancounter **p_pb) ++{ ++ int hash; ++ struct user_beancounter *bc; ++ ++ bc = mm->mm_ub; ++ if (bc == NULL) ++ return; ++ ++ if (!PageAnon(page) && is_shmem_mapping(page->mapping)) ++ return; ++ ++ hash = pb_hash(bc, page); ++ ++ spin_lock(&pb_lock); ++ if (__pb_dup_ref(page, bc, hash)) ++ __pb_add_ref(page, bc, p_pb, hash); ++ spin_unlock(&pb_lock); ++} ++ ++void pb_dup_ref(struct page *page, struct mm_struct *mm, ++ struct page_beancounter **p_pb) ++{ ++ int hash; ++ struct user_beancounter *bc; ++ ++ bc = mm->mm_ub; ++ if (bc == NULL) ++ return; ++ ++ if (!PageAnon(page) && is_shmem_mapping(page->mapping)) ++ return; ++ ++ hash = pb_hash(bc, page); ++ ++ spin_lock(&pb_lock); ++ if (*page_pblist(page) == NULL) ++ /* ++ * pages like ZERO_PAGE must not be accounted in pbc ++ * so on fork we just skip them ++ */ ++ goto out_unlock; ++ ++ if (unlikely(*p_pb != PBC_COPY_SAME)) ++ __pb_add_ref(page, bc, p_pb, hash); ++ else if (unlikely(__pb_dup_ref(page, bc, hash))) ++ WARN_ON(1); ++out_unlock: ++ spin_unlock(&pb_lock); ++} ++ ++void pb_remove_ref(struct page *page, struct mm_struct *mm) ++{ ++ int hash; ++ struct user_beancounter *bc; ++ struct page_beancounter *p, **q, *f; ++ int shift, shiftt; ++ ++ bc = mm->mm_ub; ++ if (bc == NULL) ++ return; ++ ++ if (!PageAnon(page) && is_shmem_mapping(page->mapping)) ++ return; ++ ++ hash = pb_hash(bc, page); ++ ++ spin_lock(&pb_lock); ++ for (q = pb_hash_table + hash, p = *q; ++ p != NULL && (p->page != page || p->ub != bc); ++ q = &p->next_hash, p = *q); ++ if (p == NULL) ++ goto out_unlock; ++ ++ PB_COUNT_DEC(p->refcount); ++ if (PB_COUNT_GET(p->refcount)) ++ /* ++ * More references from the same user beancounter exist. ++ * Nothing needs to be done. ++ */ ++ goto out_unlock; ++ ++ /* remove from the hash list */ ++ f = p; ++ *q = p->next_hash; ++ ++ shift = PB_SHIFT_GET(p->refcount); ++ ++ dec_held_pages(p->ub, UB_PAGE_WEIGHT >> shift); ++ ++ q = page_pblist(page); ++ if (*q == p) { ++ if (list_empty(&p->page_list)) { ++ *q = NULL; ++ goto out_free; ++ } ++ ++ *q = next_page_pb(p); ++ } ++ list_del(&p->page_list); ++ ++ /* Now balance the list. Move the tail and adjust its shift counter. */ ++ p = prev_page_pb(*q); ++ shiftt = PB_SHIFT_GET(p->refcount); ++ *q = p; ++ PB_SHIFT_DEC(p->refcount); ++ ++ inc_held_pages(p->ub, UB_PAGE_WEIGHT >> shiftt); ++ ++ /* ++ * If the shift counter of the moved beancounter is different from the ++ * removed one's, repeat the procedure for one more tail beancounter ++ */ ++ if (shiftt > shift) { ++ p = prev_page_pb(*q); ++ *q = p; ++ PB_SHIFT_DEC(p->refcount); ++ inc_held_pages(p->ub, UB_PAGE_WEIGHT >> shiftt); ++ } ++out_free: ++ dec_pbc_count(f->ub); ++ spin_unlock(&pb_lock); ++ ++ put_beancounter(f->ub); ++ pb_free(&f); ++ return; ++ ++out_unlock: ++ spin_unlock(&pb_lock); ++} ++ ++struct user_beancounter *pb_grab_page_ub(struct page *page) ++{ ++ struct page_beancounter *pb; ++ struct user_beancounter *ub; ++ ++ spin_lock(&pb_lock); ++ pb = *page_pblist(page); ++ ub = (pb == NULL ? ERR_PTR(-EINVAL) : ++ get_beancounter(pb->ub)); ++ spin_unlock(&pb_lock); ++ return ub; ++} ++ ++void __init ub_init_pbc(void) ++{ ++ unsigned long hash_size; ++ ++ pb_cachep = kmem_cache_create("page_beancounter", ++ sizeof(struct page_beancounter), 0, ++ SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); ++ hash_size = num_physpages >> 2; ++ for (pb_hash_mask = 1; ++ (hash_size & pb_hash_mask) != hash_size; ++ pb_hash_mask = (pb_hash_mask << 1) + 1); ++ hash_size = pb_hash_mask + 1; ++ printk(KERN_INFO "Page beancounter hash is %lu entries.\n", hash_size); ++ pb_hash_table = vmalloc(hash_size * sizeof(struct page_beancounter *)); ++ memset(pb_hash_table, 0, hash_size * sizeof(struct page_beancounter *)); ++ ++ ub_init_io(pb_cachep); ++} +Index: kernel/kernel/bc/statd.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/statd.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,453 @@ ++/* ++ * kernel/bc/statd.c ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++static spinlock_t ubs_notify_lock = SPIN_LOCK_UNLOCKED; ++static LIST_HEAD(ubs_notify_list); ++static long ubs_min_interval; ++static ubstattime_t ubs_start_time, ubs_end_time; ++static struct timer_list ubs_timer; ++ ++static int ubstat_get_list(void __user *buf, long size) ++{ ++ int retval; ++ struct user_beancounter *ub, *ubp; ++ long *page, *ptr, *end; ++ int len; ++ ++ page = (long *)__get_free_page(GFP_KERNEL); ++ if (page == NULL) ++ return -ENOMEM; ++ ++ retval = 0; ++ ubp = NULL; ++ ptr = page; ++ end = page + PAGE_SIZE / sizeof(*ptr); ++ ++ spin_lock_irq(&ub_hash_lock); ++ for_each_beancounter(ub) { ++ if (ub->parent != NULL) ++ continue; ++ *ptr++ = ub->ub_uid; ++ if (ptr != end) ++ continue; ++ ++ get_beancounter(ub); ++ spin_unlock_irq(&ub_hash_lock); ++ ++ put_beancounter(ubp); ++ ubp = ub; ++ ++ len = min_t(long, (ptr - page) * sizeof(*ptr), size); ++ if (copy_to_user(buf, page, len)) { ++ retval = -EFAULT; ++ goto out_put; ++ } ++ retval += len; ++ if (len < PAGE_SIZE) ++ goto out_put; ++ buf += len; ++ size -= len; ++ ++ ptr = page; ++ end = page + PAGE_SIZE / sizeof(*ptr); ++ ++ spin_lock_irq(&ub_hash_lock); ++ } ++ spin_unlock_irq(&ub_hash_lock); ++ ++ put_beancounter(ubp); ++ size = min_t(long, (ptr - page) * sizeof(*ptr), size); ++ if (size > 0 && copy_to_user(buf, page, size)) { ++ retval = -EFAULT; ++ goto out_put; ++ } ++ retval += size; ++ ++out_put: ++ put_beancounter(ubp); ++ free_page((unsigned long)page); ++ return retval; ++} ++ ++static int ubstat_gettime(void __user *buf, long size) ++{ ++ ubgettime_t data; ++ int retval; ++ ++ spin_lock(&ubs_notify_lock); ++ data.start_time = ubs_start_time; ++ data.end_time = ubs_end_time; ++ data.cur_time = ubs_start_time + (jiffies - ubs_start_time * HZ) / HZ; ++ spin_unlock(&ubs_notify_lock); ++ ++ retval = min_t(long, sizeof(data), size); ++ if (copy_to_user(buf, &data, retval)) ++ retval = -EFAULT; ++ return retval; ++} ++ ++static int ubstat_do_read_one(struct user_beancounter *ub, int res, void *kbuf) ++{ ++ struct { ++ ubstattime_t start_time; ++ ubstattime_t end_time; ++ ubstatparm_t param[1]; ++ } *data; ++ ++ data = kbuf; ++ data->start_time = ubs_start_time; ++ data->end_time = ubs_end_time; ++ ++ data->param[0].maxheld = ub->ub_store[res].maxheld; ++ data->param[0].failcnt = ub->ub_store[res].failcnt; ++ ++ return sizeof(*data); ++} ++ ++static int ubstat_do_read_all(struct user_beancounter *ub, void *kbuf, int size) ++{ ++ int wrote; ++ struct { ++ ubstattime_t start_time; ++ ubstattime_t end_time; ++ ubstatparm_t param[UB_RESOURCES]; ++ } *data; ++ int resource; ++ ++ data = kbuf; ++ data->start_time = ubs_start_time; ++ data->end_time = ubs_end_time; ++ wrote = sizeof(data->start_time) + sizeof(data->end_time); ++ ++ for (resource = 0; resource < UB_RESOURCES; resource++) { ++ if (size < wrote + sizeof(data->param[resource])) ++ break; ++ data->param[resource].maxheld = ub->ub_store[resource].maxheld; ++ data->param[resource].failcnt = ub->ub_store[resource].failcnt; ++ wrote += sizeof(data->param[resource]); ++ } ++ ++ return wrote; ++} ++ ++static int ubstat_do_read_full(struct user_beancounter *ub, void *kbuf, ++ int size) ++{ ++ int wrote; ++ struct { ++ ubstattime_t start_time; ++ ubstattime_t end_time; ++ ubstatparmf_t param[UB_RESOURCES]; ++ } *data; ++ int resource; ++ ++ data = kbuf; ++ data->start_time = ubs_start_time; ++ data->end_time = ubs_end_time; ++ wrote = sizeof(data->start_time) + sizeof(data->end_time); ++ ++ for (resource = 0; resource < UB_RESOURCES; resource++) { ++ if (size < wrote + sizeof(data->param[resource])) ++ break; ++ /* The beginning of ubstatparmf_t matches struct ubparm. */ ++ memcpy(&data->param[resource], &ub->ub_store[resource], ++ sizeof(ub->ub_store[resource])); ++ data->param[resource].__unused1 = 0; ++ data->param[resource].__unused2 = 0; ++ wrote += sizeof(data->param[resource]); ++ } ++ return wrote; ++} ++ ++static int ubstat_get_stat(struct user_beancounter *ub, long cmd, ++ void __user *buf, long size) ++{ ++ void *kbuf; ++ int retval; ++ ++ kbuf = (void *)__get_free_page(GFP_KERNEL); ++ if (kbuf == NULL) ++ return -ENOMEM; ++ ++ spin_lock(&ubs_notify_lock); ++ switch (UBSTAT_CMD(cmd)) { ++ case UBSTAT_READ_ONE: ++ retval = -EINVAL; ++ if (UBSTAT_PARMID(cmd) >= UB_RESOURCES) ++ break; ++ retval = ubstat_do_read_one(ub, ++ UBSTAT_PARMID(cmd), kbuf); ++ break; ++ case UBSTAT_READ_ALL: ++ retval = ubstat_do_read_all(ub, kbuf, PAGE_SIZE); ++ break; ++ case UBSTAT_READ_FULL: ++ retval = ubstat_do_read_full(ub, kbuf, PAGE_SIZE); ++ break; ++ default: ++ retval = -EINVAL; ++ } ++ spin_unlock(&ubs_notify_lock); ++ ++ if (retval > 0) { ++ retval = min_t(long, retval, size); ++ if (copy_to_user(buf, kbuf, retval)) ++ retval = -EFAULT; ++ } ++ ++ free_page((unsigned long)kbuf); ++ return retval; ++} ++ ++static int ubstat_handle_notifrq(ubnotifrq_t *req) ++{ ++ int retval; ++ struct ub_stat_notify *new_notify; ++ struct list_head *entry; ++ struct task_struct *tsk_to_free; ++ ++ new_notify = kmalloc(sizeof(new_notify), GFP_KERNEL); ++ if (new_notify == NULL) ++ return -ENOMEM; ++ ++ tsk_to_free = NULL; ++ INIT_LIST_HEAD(&new_notify->list); ++ ++ spin_lock(&ubs_notify_lock); ++ list_for_each(entry, &ubs_notify_list) { ++ struct ub_stat_notify *notify; ++ ++ notify = list_entry(entry, struct ub_stat_notify, list); ++ if (notify->task == current) { ++ kfree(new_notify); ++ new_notify = notify; ++ break; ++ } ++ } ++ ++ retval = -EINVAL; ++ if (req->maxinterval < 1) ++ goto out_unlock; ++ if (req->maxinterval > TIME_MAX_SEC) ++ req->maxinterval = TIME_MAX_SEC; ++ if (req->maxinterval < ubs_min_interval) { ++ unsigned long dif; ++ ++ ubs_min_interval = req->maxinterval; ++ dif = (ubs_timer.expires - jiffies + HZ - 1) / HZ; ++ if (dif > req->maxinterval) ++ mod_timer(&ubs_timer, ++ ubs_timer.expires - ++ (dif - req->maxinterval) * HZ); ++ } ++ ++ if (entry != &ubs_notify_list) { ++ list_del(&new_notify->list); ++ tsk_to_free = new_notify->task; ++ } ++ if (req->signum) { ++ new_notify->task = current; ++ get_task_struct(new_notify->task); ++ new_notify->signum = req->signum; ++ list_add(&new_notify->list, &ubs_notify_list); ++ } else ++ kfree(new_notify); ++ retval = 0; ++out_unlock: ++ spin_unlock(&ubs_notify_lock); ++ if (tsk_to_free != NULL) ++ put_task_struct(tsk_to_free); ++ return retval; ++} ++ ++/* ++ * former sys_ubstat ++ */ ++long do_ubstat(int func, unsigned long arg1, unsigned long arg2, ++ void __user *buf, long size) ++{ ++ int retval; ++ struct user_beancounter *ub; ++ ++ if (func == UBSTAT_UBPARMNUM) ++ return UB_RESOURCES; ++ if (func == UBSTAT_UBLIST) ++ return ubstat_get_list(buf, size); ++ if (!(capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH))) ++ return -EPERM; ++ ++ if (func == UBSTAT_GETTIME) { ++ retval = ubstat_gettime(buf, size); ++ goto notify; ++ } ++ ++ ub = get_exec_ub(); ++ if (ub != NULL && ub->ub_uid == arg1) ++ get_beancounter(ub); ++ else /* FIXME must be if (ve_is_super) */ ++ ub = get_beancounter_byuid(arg1, 0); ++ ++ if (ub == NULL) ++ return -ESRCH; ++ ++ retval = ubstat_get_stat(ub, func, buf, size); ++ put_beancounter(ub); ++notify: ++ /* Handle request for notification */ ++ if (retval >= 0) { ++ ubnotifrq_t notifrq; ++ int err; ++ ++ err = -EFAULT; ++ if (!copy_from_user(¬ifrq, (void __user *)arg2, ++ sizeof(notifrq))) ++ err = ubstat_handle_notifrq(¬ifrq); ++ if (err) ++ retval = err; ++ } ++ ++ return retval; ++} ++ ++static void ubstat_save_onestat(struct user_beancounter *ub) ++{ ++ int resource; ++ ++ /* called with local irq disabled */ ++ spin_lock(&ub->ub_lock); ++ for (resource = 0; resource < UB_RESOURCES; resource++) { ++ memcpy(&ub->ub_store[resource], &ub->ub_parms[resource], ++ sizeof(struct ubparm)); ++ ub->ub_parms[resource].minheld = ++ ub->ub_parms[resource].maxheld = ++ ub->ub_parms[resource].held; ++ } ++ spin_unlock(&ub->ub_lock); ++} ++ ++static void ubstat_save_statistics(void) ++{ ++ unsigned long flags; ++ struct user_beancounter *ub; ++ ++ local_irq_save(flags); ++ for_each_beancounter (ub) ++ ubstat_save_onestat(ub); ++ local_irq_restore(flags); ++} ++ ++static void ubstatd_timeout(unsigned long __data) ++{ ++ struct task_struct *p; ++ ++ p = (struct task_struct *) __data; ++ wake_up_process(p); ++} ++ ++/* ++ * Safe wrapper for send_sig. It prevents a race with release_task ++ * for sighand. ++ * Should be called under tasklist_lock. ++ */ ++static void task_send_sig(struct ub_stat_notify *notify) ++{ ++ if (likely(notify->task->sighand != NULL)) ++ send_sig(notify->signum, notify->task, 1); ++} ++ ++static inline void do_notifies(void) ++{ ++ LIST_HEAD(notif_free_list); ++ struct ub_stat_notify *notify; ++ struct ub_stat_notify *tmp; ++ ++ spin_lock(&ubs_notify_lock); ++ ubs_start_time = ubs_end_time; ++ /* ++ * the expression below relies on time being unsigned long and ++ * arithmetic promotion rules ++ */ ++ ubs_end_time += (ubs_timer.expires - ubs_start_time * HZ) / HZ; ++ mod_timer(&ubs_timer, ubs_timer.expires + ubs_min_interval * HZ); ++ ubs_min_interval = TIME_MAX_SEC; ++ /* save statistics accumulated for the interval */ ++ ubstat_save_statistics(); ++ /* send signals */ ++ read_lock(&tasklist_lock); ++ while (!list_empty(&ubs_notify_list)) { ++ notify = list_entry(ubs_notify_list.next, ++ struct ub_stat_notify, list); ++ task_send_sig(notify); ++ list_del(¬ify->list); ++ list_add(¬ify->list, ¬if_free_list); ++ } ++ read_unlock(&tasklist_lock); ++ spin_unlock(&ubs_notify_lock); ++ ++ list_for_each_entry_safe(notify, tmp, ¬if_free_list, list) { ++ put_task_struct(notify->task); ++ kfree(notify); ++ } ++} ++ ++/* ++ * Kernel thread ++ */ ++static int ubstatd(void *unused) ++{ ++ /* daemonize call will take care of signals */ ++ daemonize("ubstatd"); ++ ++ ubs_timer.data = (unsigned long)current; ++ ubs_timer.function = ubstatd_timeout; ++ add_timer(&ubs_timer); ++ ++ while (1) { ++ set_task_state(current, TASK_INTERRUPTIBLE); ++ if (time_after(ubs_timer.expires, jiffies)) { ++ schedule(); ++ try_to_freeze(); ++ continue; ++ } ++ ++ __set_task_state(current, TASK_RUNNING); ++ do_notifies(); ++ } ++ return 0; ++} ++ ++static int __init ubstatd_init(void) ++{ ++ init_timer(&ubs_timer); ++ ubs_timer.expires = TIME_MAX_JIF; ++ ubs_min_interval = TIME_MAX_SEC; ++ ubs_start_time = ubs_end_time = 0; ++ ++ kernel_thread(ubstatd, NULL, 0); ++ return 0; ++} ++ ++module_init(ubstatd_init); +Index: kernel/kernel/bc/sys.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/sys.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,173 @@ ++/* ++ * kernel/bc/sys.c ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++/* ++ * The (rather boring) getluid syscall ++ */ ++asmlinkage long sys_getluid(void) ++{ ++ struct user_beancounter *ub; ++ ++ ub = get_exec_ub(); ++ if (ub == NULL) ++ return -EINVAL; ++ ++ return ub->ub_uid; ++} ++ ++/* ++ * The setluid syscall ++ */ ++asmlinkage long sys_setluid(uid_t uid) ++{ ++ struct user_beancounter *ub; ++ struct task_beancounter *task_bc; ++ int error; ++ ++ task_bc = ¤t->task_bc; ++ ++ /* You may not disown a setluid */ ++ error = -EINVAL; ++ if (uid == (uid_t)-1) ++ goto out; ++ ++ /* You may only set an ub as root */ ++ error = -EPERM; ++ if (!capable(CAP_SETUID)) ++ goto out; ++ /* ++ * The ub once set is irrevocable to all ++ * unless it's set from ve0. ++ */ ++ if (!ve_is_super(get_exec_env())) ++ goto out; ++ ++ /* Ok - set up a beancounter entry for this user */ ++ error = -ENOBUFS; ++ ub = get_beancounter_byuid(uid, 1); ++ if (ub == NULL) ++ goto out; ++ ++ ub_debug(UBD_ALLOC | UBD_LIMIT, "setluid, bean %p (count %d) " ++ "for %.20s pid %d\n", ++ ub, atomic_read(&ub->ub_refcount), ++ current->comm, current->pid); ++ /* install bc */ ++ error = virtinfo_notifier_call(VITYPE_GENERAL, VIRTINFO_NEWUBC, ub); ++ if (!(error & NOTIFY_FAIL)) { ++ put_beancounter(task_bc->exec_ub); ++ task_bc->exec_ub = ub; ++ if (!(error & NOTIFY_OK)) { ++ put_beancounter(task_bc->fork_sub); ++ task_bc->fork_sub = get_beancounter(ub); ++ } ++ error = 0; ++ } else { ++ put_beancounter(ub); ++ error = -ENOBUFS; ++ } ++out: ++ return error; ++} ++ ++long do_setublimit(uid_t uid, unsigned long resource, ++ unsigned long *new_limits) ++{ ++ int error; ++ unsigned long flags; ++ struct user_beancounter *ub; ++ ++ error = -EPERM; ++ if(!capable(CAP_SYS_RESOURCE)) ++ goto out; ++ ++ if (!ve_is_super(get_exec_env())) ++ goto out; ++ ++ error = -EINVAL; ++ if (resource >= UB_RESOURCES) ++ goto out; ++ ++ error = -EINVAL; ++ if (new_limits[0] > UB_MAXVALUE || new_limits[1] > UB_MAXVALUE) ++ goto out; ++ ++ error = -ENOENT; ++ ub = get_beancounter_byuid(uid, 0); ++ if (ub == NULL) { ++ ub_debug(UBD_LIMIT, "No login bc for uid %d\n", uid); ++ goto out; ++ } ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ ub->ub_parms[resource].barrier = new_limits[0]; ++ ub->ub_parms[resource].limit = new_limits[1]; ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ ++ put_beancounter(ub); ++ ++ error = 0; ++out: ++ return error; ++} ++ ++/* ++ * The setbeanlimit syscall ++ */ ++asmlinkage long sys_setublimit(uid_t uid, unsigned long resource, ++ unsigned long __user *limits) ++{ ++ unsigned long new_limits[2]; ++ ++ if (copy_from_user(&new_limits, limits, sizeof(new_limits))) ++ return -EFAULT; ++ ++ return do_setublimit(uid, resource, new_limits); ++} ++ ++extern long do_ubstat(int func, unsigned long arg1, unsigned long arg2, ++ void __user *buf, long size); ++asmlinkage long sys_ubstat(int func, unsigned long arg1, unsigned long arg2, ++ void __user *buf, long size) ++{ ++ if (!ve_is_super(get_exec_env())) ++ return -EPERM; ++ ++ return do_ubstat(func, arg1, arg2, buf, size); ++} ++ ++#ifdef CONFIG_COMPAT ++asmlinkage long compat_sys_setublimit(uid_t uid, int resource, ++ unsigned int __user *limits) ++{ ++ unsigned int u_new_limits[2]; ++ unsigned long new_limits[2]; ++ ++ if (copy_from_user(&u_new_limits, limits, sizeof(u_new_limits))) ++ return -EFAULT; ++ ++ new_limits[0] = u_new_limits[0]; ++ new_limits[1] = u_new_limits[1]; ++ ++ return do_setublimit(uid, resource, new_limits); ++} ++ ++asmlinkage long compat_sys_ubstat(int func, unsigned int arg1, ++ unsigned int arg2, compat_uptr_t *buf, long size) ++{ ++ return sys_ubstat(func, arg1, arg2, buf, size); ++} ++#endif +Index: kernel/kernel/bc/vm_pages.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/bc/vm_pages.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,549 @@ ++/* ++ * kernel/bc/vm_pages.c ++ * ++ * Copyright (C) 2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++static inline unsigned long pages_in_pte_range(struct vm_area_struct *vma, ++ pmd_t *pmd, unsigned long addr, unsigned long end, ++ unsigned long *ret) ++{ ++ pte_t *pte; ++ spinlock_t *ptl; ++ ++ pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); ++ do { ++ if (!pte_none(*pte) && pte_present(*pte)) ++ (*ret)++; ++ } while (pte++, addr += PAGE_SIZE, (addr != end)); ++ pte_unmap_unlock(pte - 1, ptl); ++ ++ return addr; ++} ++ ++static inline unsigned long pages_in_pmd_range(struct vm_area_struct *vma, ++ pud_t *pud, unsigned long addr, unsigned long end, ++ unsigned long *ret) ++{ ++ pmd_t *pmd; ++ unsigned long next; ++ ++ pmd = pmd_offset(pud, addr); ++ do { ++ next = pmd_addr_end(addr, end); ++ if (pmd_none_or_clear_bad(pmd)) ++ continue; ++ next = pages_in_pte_range(vma, pmd, addr, next, ret); ++ } while (pmd++, addr = next, (addr != end)); ++ ++ return addr; ++} ++ ++static inline unsigned long pages_in_pud_range(struct vm_area_struct *vma, ++ pgd_t *pgd, unsigned long addr, unsigned long end, ++ unsigned long *ret) ++{ ++ pud_t *pud; ++ unsigned long next; ++ ++ pud = pud_offset(pgd, addr); ++ do { ++ next = pud_addr_end(addr, end); ++ if (pud_none_or_clear_bad(pud)) ++ continue; ++ next = pages_in_pmd_range(vma, pud, addr, next, ret); ++ } while (pud++, addr = next, (addr != end)); ++ ++ return addr; ++} ++ ++unsigned long pages_in_vma_range(struct vm_area_struct *vma, ++ unsigned long addr, unsigned long end) ++{ ++ pgd_t *pgd; ++ unsigned long next; ++ unsigned long ret; ++ ++ ret = 0; ++ BUG_ON(addr >= end); ++ pgd = pgd_offset(vma->vm_mm, addr); ++ do { ++ next = pgd_addr_end(addr, end); ++ if (pgd_none_or_clear_bad(pgd)) ++ continue; ++ next = pages_in_pud_range(vma, pgd, addr, next, &ret); ++ } while (pgd++, addr = next, (addr != end)); ++ return ret; ++} ++ ++void fastcall __ub_update_physpages(struct user_beancounter *ub) ++{ ++ ub->ub_parms[UB_PHYSPAGES].held = ub->ub_tmpfs_respages ++ + (ub->ub_held_pages >> UB_PAGE_WEIGHT_SHIFT); ++ ub_adjust_maxheld(ub, UB_PHYSPAGES); ++} ++ ++void fastcall __ub_update_oomguarpages(struct user_beancounter *ub) ++{ ++ ub->ub_parms[UB_OOMGUARPAGES].held = ++ ub->ub_parms[UB_PHYSPAGES].held + ub->ub_swap_pages; ++ ub_adjust_maxheld(ub, UB_OOMGUARPAGES); ++} ++ ++void fastcall __ub_update_privvm(struct user_beancounter *ub) ++{ ++ ub->ub_parms[UB_PRIVVMPAGES].held = ++ (ub->ub_held_pages >> UB_PAGE_WEIGHT_SHIFT) ++ + ub->ub_unused_privvmpages ++ + ub->ub_parms[UB_SHMPAGES].held; ++ ub_adjust_maxheld(ub, UB_PRIVVMPAGES); ++} ++ ++static inline int __charge_privvm_locked(struct user_beancounter *ub, ++ unsigned long s, enum ub_severity strict) ++{ ++ if (__charge_beancounter_locked(ub, UB_PRIVVMPAGES, s, strict) < 0) ++ return -ENOMEM; ++ ++ ub->ub_unused_privvmpages += s; ++ return 0; ++} ++ ++static void __unused_privvm_dec_locked(struct user_beancounter *ub, ++ long size) ++{ ++ /* catch possible overflow */ ++ if (ub->ub_unused_privvmpages < size) { ++ uncharge_warn(ub, UB_UNUSEDPRIVVM, ++ size, ub->ub_unused_privvmpages); ++ size = ub->ub_unused_privvmpages; ++ } ++ ub->ub_unused_privvmpages -= size; ++ __ub_update_privvm(ub); ++} ++ ++void __ub_unused_privvm_dec(struct mm_struct *mm, long size) ++{ ++ unsigned long flags; ++ struct user_beancounter *ub; ++ ++ ub = mm->mm_ub; ++ if (ub == NULL) ++ return; ++ ++ ub = top_beancounter(ub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ __unused_privvm_dec_locked(ub, size); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++void ub_unused_privvm_sub(struct mm_struct *mm, ++ struct vm_area_struct *vma, unsigned long count) ++{ ++ if (VM_UB_PRIVATE(vma->vm_flags, vma->vm_file)) ++ __ub_unused_privvm_dec(mm, count); ++} ++ ++void ub_unused_privvm_add(struct mm_struct *mm, ++ struct vm_area_struct *vma, unsigned long size) ++{ ++ unsigned long flags; ++ struct user_beancounter *ub; ++ ++ ub = mm->mm_ub; ++ if (ub == NULL || !VM_UB_PRIVATE(vma->vm_flags, vma->vm_file)) ++ return; ++ ++ ub = top_beancounter(ub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ ub->ub_unused_privvmpages += size; ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++int ub_protected_charge(struct mm_struct *mm, unsigned long size, ++ unsigned long newflags, struct vm_area_struct *vma) ++{ ++ unsigned long flags; ++ struct file *file; ++ struct user_beancounter *ub; ++ ++ ub = mm->mm_ub; ++ if (ub == NULL) ++ return PRIVVM_NO_CHARGE; ++ ++ flags = vma->vm_flags; ++ if (!((newflags ^ flags) & VM_WRITE)) ++ return PRIVVM_NO_CHARGE; ++ ++ file = vma->vm_file; ++ if (!VM_UB_PRIVATE(newflags | VM_WRITE, file)) ++ return PRIVVM_NO_CHARGE; ++ ++ if (flags & VM_WRITE) ++ return PRIVVM_TO_SHARED; ++ ++ ub = top_beancounter(ub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ if (__charge_privvm_locked(ub, size, UB_SOFT) < 0) ++ goto err; ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ return PRIVVM_TO_PRIVATE; ++ ++err: ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ return PRIVVM_ERROR; ++} ++ ++int ub_memory_charge(struct mm_struct *mm, unsigned long size, ++ unsigned vm_flags, struct file *vm_file, int sv) ++{ ++ struct user_beancounter *ub, *ubl; ++ unsigned long flags; ++ ++ ub = mm->mm_ub; ++ if (ub == NULL) ++ return 0; ++ ++ size >>= PAGE_SHIFT; ++ if (size > UB_MAXVALUE) ++ return -EINVAL; ++ ++ BUG_ON(sv != UB_SOFT && sv != UB_HARD); ++ ++ if (vm_flags & VM_LOCKED) { ++ if (charge_beancounter(ub, UB_LOCKEDPAGES, size, sv)) ++ goto out_err; ++ } ++ if (VM_UB_PRIVATE(vm_flags, vm_file)) { ++ ubl = top_beancounter(ub); ++ spin_lock_irqsave(&ubl->ub_lock, flags); ++ if (__charge_privvm_locked(ubl, size, sv)) ++ goto out_private; ++ spin_unlock_irqrestore(&ubl->ub_lock, flags); ++ } ++ return 0; ++ ++out_private: ++ spin_unlock_irqrestore(&ubl->ub_lock, flags); ++ if (vm_flags & VM_LOCKED) ++ uncharge_beancounter(ub, UB_LOCKEDPAGES, size); ++out_err: ++ return -ENOMEM; ++} ++ ++void ub_memory_uncharge(struct mm_struct *mm, unsigned long size, ++ unsigned vm_flags, struct file *vm_file) ++{ ++ struct user_beancounter *ub; ++ unsigned long flags; ++ ++ ub = mm->mm_ub; ++ if (ub == NULL) ++ return; ++ ++ size >>= PAGE_SHIFT; ++ ++ if (vm_flags & VM_LOCKED) ++ uncharge_beancounter(ub, UB_LOCKEDPAGES, size); ++ if (VM_UB_PRIVATE(vm_flags, vm_file)) { ++ ub = top_beancounter(ub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ __unused_privvm_dec_locked(ub, size); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ } ++} ++ ++int ub_locked_charge(struct mm_struct *mm, unsigned long size) ++{ ++ struct user_beancounter *ub; ++ ++ ub = mm->mm_ub; ++ if (ub == NULL) ++ return 0; ++ ++ return charge_beancounter(ub, UB_LOCKEDPAGES, ++ size >> PAGE_SHIFT, UB_HARD); ++} ++ ++void ub_locked_uncharge(struct mm_struct *mm, unsigned long size) ++{ ++ struct user_beancounter *ub; ++ ++ ub = mm->mm_ub; ++ if (ub == NULL) ++ return; ++ ++ uncharge_beancounter(ub, UB_LOCKEDPAGES, size >> PAGE_SHIFT); ++} ++ ++int ub_lockedshm_charge(struct shmem_inode_info *shi, unsigned long size) ++{ ++ struct user_beancounter *ub; ++ ++ ub = shi->shmi_ub; ++ if (ub == NULL) ++ return 0; ++ ++ return charge_beancounter(ub, UB_LOCKEDPAGES, ++ size >> PAGE_SHIFT, UB_HARD); ++} ++ ++void ub_lockedshm_uncharge(struct shmem_inode_info *shi, unsigned long size) ++{ ++ struct user_beancounter *ub; ++ ++ ub = shi->shmi_ub; ++ if (ub == NULL) ++ return; ++ ++ uncharge_beancounter(ub, UB_LOCKEDPAGES, size >> PAGE_SHIFT); ++} ++ ++ ++static inline void do_ub_tmpfs_respages_inc(struct user_beancounter *ub) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ ub->ub_tmpfs_respages++; ++ __ub_update_physpages(ub); ++ __ub_update_oomguarpages(ub); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++void ub_tmpfs_respages_inc(struct shmem_inode_info *shi) ++{ ++ struct user_beancounter *ub; ++ ++ for (ub = shi->shmi_ub; ub != NULL; ub = ub->parent) ++ do_ub_tmpfs_respages_inc(ub); ++} ++ ++static inline void do_ub_tmpfs_respages_sub(struct user_beancounter *ub, ++ unsigned long size) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ /* catch possible overflow */ ++ if (ub->ub_tmpfs_respages < size) { ++ uncharge_warn(ub, UB_TMPFSPAGES, ++ size, ub->ub_tmpfs_respages); ++ size = ub->ub_tmpfs_respages; ++ } ++ ub->ub_tmpfs_respages -= size; ++ /* update values what is the most interesting */ ++ __ub_update_physpages(ub); ++ __ub_update_oomguarpages(ub); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++void ub_tmpfs_respages_sub(struct shmem_inode_info *shi, ++ unsigned long size) ++{ ++ struct user_beancounter *ub; ++ ++ for (ub = shi->shmi_ub; ub != NULL; ub = ub->parent) ++ do_ub_tmpfs_respages_sub(ub, size); ++} ++ ++int ub_shmpages_charge(struct shmem_inode_info *shi, unsigned long size) ++{ ++ int ret; ++ unsigned long flags; ++ struct user_beancounter *ub; ++ ++ ub = shi->shmi_ub; ++ if (ub == NULL) ++ return 0; ++ ++ ub = top_beancounter(ub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ ret = __charge_beancounter_locked(ub, UB_SHMPAGES, size, UB_HARD); ++ if (ret == 0) ++ __ub_update_privvm(ub); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++ return ret; ++} ++ ++void ub_shmpages_uncharge(struct shmem_inode_info *shi, unsigned long size) ++{ ++ unsigned long flags; ++ struct user_beancounter *ub; ++ ++ ub = shi->shmi_ub; ++ if (ub == NULL) ++ return; ++ ++ ub = top_beancounter(ub); ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ __uncharge_beancounter_locked(ub, UB_SHMPAGES, size); ++ __ub_update_privvm(ub); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++#ifdef CONFIG_BC_SWAP_ACCOUNTING ++static inline void do_ub_swapentry_inc(struct user_beancounter *ub) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ ub->ub_swap_pages++; ++ __ub_update_oomguarpages(ub); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++void ub_swapentry_inc(struct swap_info_struct *si, pgoff_t num, ++ struct user_beancounter *ub) ++{ ++ si->swap_ubs[num] = get_beancounter(ub); ++ for (; ub != NULL; ub = ub->parent) ++ do_ub_swapentry_inc(ub); ++} ++EXPORT_SYMBOL(ub_swapentry_inc); ++ ++static inline void do_ub_swapentry_dec(struct user_beancounter *ub) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ub->ub_lock, flags); ++ if (ub->ub_swap_pages <= 0) ++ uncharge_warn(ub, UB_SWAPPAGES, 1, ub->ub_swap_pages); ++ else ++ ub->ub_swap_pages--; ++ __ub_update_oomguarpages(ub); ++ spin_unlock_irqrestore(&ub->ub_lock, flags); ++} ++ ++void ub_swapentry_dec(struct swap_info_struct *si, pgoff_t num) ++{ ++ struct user_beancounter *ub, *ubp; ++ ++ ub = si->swap_ubs[num]; ++ si->swap_ubs[num] = NULL; ++ for (ubp = ub; ubp != NULL; ubp = ubp->parent) ++ do_ub_swapentry_dec(ubp); ++ put_beancounter(ub); ++} ++EXPORT_SYMBOL(ub_swapentry_dec); ++ ++int ub_swap_init(struct swap_info_struct *si, pgoff_t num) ++{ ++ struct user_beancounter **ubs; ++ ++ ubs = vmalloc(num * sizeof(struct user_beancounter *)); ++ if (ubs == NULL) ++ return -ENOMEM; ++ ++ memset(ubs, 0, num * sizeof(struct user_beancounter *)); ++ si->swap_ubs = ubs; ++ return 0; ++} ++ ++void ub_swap_fini(struct swap_info_struct *si) ++{ ++ if (si->swap_ubs) { ++ vfree(si->swap_ubs); ++ si->swap_ubs = NULL; ++ } ++} ++#endif ++ ++static int vmguar_enough_memory(struct vnotifier_block *self, ++ unsigned long event, void *arg, int old_ret) ++{ ++ struct user_beancounter *ub; ++ ++ if (event != VIRTINFO_ENOUGHMEM) ++ return old_ret; ++ /* ++ * If it's a kernel thread, don't care about it. ++ * Added in order aufsd to run smoothly over ramfs. ++ */ ++ if (!current->mm) ++ return NOTIFY_DONE; ++ ++ ub = top_beancounter(current->mm->mm_ub); ++ if (ub->ub_parms[UB_PRIVVMPAGES].held > ++ ub->ub_parms[UB_VMGUARPAGES].barrier) ++ return old_ret; ++ ++ return NOTIFY_OK; ++} ++ ++static struct vnotifier_block vmguar_notifier_block = { ++ .notifier_call = vmguar_enough_memory ++}; ++ ++static int __init init_vmguar_notifier(void) ++{ ++ virtinfo_notifier_register(VITYPE_GENERAL, &vmguar_notifier_block); ++ return 0; ++} ++ ++static void __exit fini_vmguar_notifier(void) ++{ ++ virtinfo_notifier_unregister(VITYPE_GENERAL, &vmguar_notifier_block); ++} ++ ++module_init(init_vmguar_notifier); ++module_exit(fini_vmguar_notifier); ++ ++#ifdef CONFIG_PROC_FS ++static int bc_vmaux_show(struct seq_file *f, void *v) ++{ ++ struct user_beancounter *ub; ++ unsigned long swap, unmap; ++ int i; ++ ++ ub = seq_beancounter(f); ++ ++ swap = unmap = 0; ++ for_each_online_cpu(i) { ++ swap += per_cpu_ptr(ub->ub_percpu, i)->swapin; ++ unmap += per_cpu_ptr(ub->ub_percpu, i)->unmap; ++ } ++ ++ seq_printf(f, bc_proc_lu_fmt, ub_rnames[UB_UNUSEDPRIVVM], ++ ub->ub_unused_privvmpages); ++ seq_printf(f, bc_proc_lu_fmt, ub_rnames[UB_TMPFSPAGES], ++ ub->ub_tmpfs_respages); ++ seq_printf(f, bc_proc_lu_fmt, ub_rnames[UB_SWAPPAGES], ++ ub->ub_swap_pages); ++ ++ seq_printf(f, bc_proc_lu_fmt, "swapin", swap); ++ seq_printf(f, bc_proc_lu_fmt, "unmap", unmap); ++ return 0; ++} ++static struct bc_proc_entry bc_vmaux_entry = { ++ .name = "vmaux", ++ .u.show = bc_vmaux_show, ++}; ++ ++static int __init bc_vmaux_init(void) ++{ ++ bc_register_proc_entry(&bc_vmaux_entry); ++ return 0; ++} ++ ++late_initcall(bc_vmaux_init); ++#endif +Index: kernel/kernel/capability.c +=================================================================== +--- kernel.orig/kernel/capability.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/capability.c 2008-11-24 15:47:46.000000000 +0100 +@@ -10,16 +10,23 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + ++#ifndef CONFIG_VE ++kernel_cap_t cap_bset = CAP_INIT_EFF_SET; ++EXPORT_SYMBOL(cap_bset); ++#endif ++ + /* + * This lock protects task->cap_* for all tasks including current. + * Locking rule: acquire this prior to tasklist_lock. + */ +-static DEFINE_SPINLOCK(task_capability_lock); ++DEFINE_SPINLOCK(task_capability_lock); ++EXPORT_SYMBOL(task_capability_lock); + + /* + * For sys_getproccap() and sys_setproccap(), any of the three +@@ -99,7 +106,7 @@ + pgrp = find_vpid(pgrp_nr); + do_each_pid_task(pgrp, PIDTYPE_PGID, g) { + target = g; +- while_each_thread(g, target) { ++ while_each_thread_ve(g, target) { + if (!security_capset_check(target, effective, + inheritable, + permitted)) { +@@ -129,7 +136,7 @@ + int ret = -EPERM; + int found = 0; + +- do_each_thread(g, target) { ++ do_each_thread_ve(g, target) { + if (target == current || is_container_init(target->group_leader)) + continue; + found = 1; +@@ -138,7 +145,7 @@ + continue; + ret = 0; + security_capset_set(target, effective, inheritable, permitted); +- } while_each_thread(g, target); ++ } while_each_thread_ve(g, target); + + if (!found) + ret = 0; +Index: kernel/kernel/cgroup.c +=================================================================== +--- kernel.orig/kernel/cgroup.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/cgroup.c 2008-11-24 15:47:46.000000000 +0100 +@@ -1686,12 +1686,12 @@ + struct task_struct *p, *g; + write_lock(&css_set_lock); + use_task_css_set_links = 1; +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + task_lock(p); + if (list_empty(&p->cg_list)) + list_add(&p->cg_list, &p->cgroups->tasks); + task_unlock(p); +- } while_each_thread(g, p); ++ } while_each_thread_all(g, p); + write_unlock(&css_set_lock); + } + read_lock(&css_set_lock); +@@ -2229,9 +2229,9 @@ + struct task_struct *g, *p; + + read_lock(&tasklist_lock); +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + ss->fork(ss, p); +- } while_each_thread(g, p); ++ } while_each_thread_all(g, p); + read_unlock(&tasklist_lock); + } + +@@ -2577,9 +2577,6 @@ + again: + root = subsys->root; + if (root == &rootnode) { +- printk(KERN_INFO +- "Not cloning cgroup for unused subsystem %s\n", +- subsys->name); + mutex_unlock(&cgroup_mutex); + return 0; + } +Index: kernel/kernel/compat.c +=================================================================== +--- kernel.orig/kernel/compat.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/compat.c 2008-11-24 15:47:46.000000000 +0100 +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -40,7 +41,7 @@ + __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; + } + +-static long compat_nanosleep_restart(struct restart_block *restart) ++long compat_nanosleep_restart(struct restart_block *restart) + { + struct compat_timespec __user *rmtp; + struct timespec rmt; +@@ -64,6 +65,7 @@ + + return ret; + } ++EXPORT_SYMBOL_GPL(compat_nanosleep_restart); + + asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, + struct compat_timespec __user *rmtp) +Index: kernel/kernel/configs.c +=================================================================== +--- kernel.orig/kernel/configs.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/configs.c 2008-11-24 15:47:46.000000000 +0100 +@@ -79,8 +79,7 @@ + struct proc_dir_entry *entry; + + /* create the current config file */ +- entry = create_proc_entry("config.gz", S_IFREG | S_IRUGO, +- &proc_root); ++ entry = create_proc_entry("config.gz", S_IFREG | S_IRUGO, NULL); + if (!entry) + return -ENOMEM; + +Index: kernel/kernel/cpt/Makefile +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/Makefile 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,53 @@ ++# ++# ++# kernel/cpt/Makefile ++# ++# Copyright (C) 2000-2005 SWsoft ++# All rights reserved. ++# ++# Licensing governed by "linux/COPYING.SWsoft" file. ++ ++obj-$(CONFIG_VZ_CHECKPOINT) += vzcpt.o vzrst.o ++ ++vzcpt-objs := cpt_proc.o cpt_dump.o cpt_obj.o cpt_context.o cpt_process.o \ ++ cpt_mm.o cpt_files.o cpt_kernel.o \ ++ cpt_socket.o cpt_socket_in.o cpt_tty.o cpt_sysvipc.o cpt_net.o \ ++ cpt_conntrack.o cpt_epoll.o ++ ++vzrst-objs := rst_proc.o rst_undump.o rst_context.o rst_process.o \ ++ rst_mm.o rst_files.o \ ++ rst_socket.o rst_socket_in.o rst_tty.o rst_sysvipc.o rst_net.o \ ++ rst_conntrack.o rst_epoll.o ++ ++ifeq ($(CONFIG_BEANCOUNTERS), y) ++vzcpt-objs += cpt_ubc.o ++vzrst-objs += rst_ubc.o ++endif ++ ++ifeq ($(CONFIG_INOTIFY_USER), y) ++vzcpt-objs += cpt_inotify.o ++vzrst-objs += rst_inotify.o ++endif ++ ++vzrst-objs += cpt_exports.o ++ ++ifeq ($(CONFIG_VZ_CHECKPOINT), m) ++vzrst-objs += cpt_obj.o cpt_kernel.o ++endif ++ ++ifeq ($(CONFIG_VZ_CHECKPOINT_ITER), y) ++vzcpt-objs += cpt_iterative.o ++vzrst-objs += rst_iterative.o ++endif ++ ++ifeq ($(CONFIG_VZ_CHECKPOINT_LAZY), y) ++vzcpt-objs += cpt_pagein.o ++vzrst-objs += rst_pagein.o ++endif ++ ++ifeq ($(CONFIG_X86_64), y) ++vzcpt-objs += cpt_x8664.o ++ifeq ($(CONFIG_VZ_CHECKPOINT), m) ++vzrst-objs += cpt_x8664.o ++endif ++endif +Index: kernel/kernel/cpt/cpt_conntrack.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_conntrack.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,365 @@ ++/* ++ * ++ * kernel/cpt/cpt_conntrack.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined(CONFIG_VE_IPTABLES) && \ ++ (defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)) ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++ ++ ++/* How does it work? ++ * ++ * Network is disabled, so new conntrack entries will not appear. ++ * However, some of them can disappear because of timeouts. ++ * ++ * So, we take read_lock, collect all required information atomically, ++ * essentially, creating parallel "refcount" structures holding pointers. ++ * We delete conntrack timers as well, so the structures cannot disappear ++ * after releasing the lock. Now, after releasing lock we can dump everything ++ * safely. And on exit we restore timers to their original values. ++ * ++ * Note, this approach is not going to work in VE0. ++ */ ++ ++struct ct_holder ++{ ++ struct ct_holder *next; ++ struct ip_conntrack_tuple_hash *cth; ++ int index; ++}; ++ ++static void encode_tuple(struct cpt_ipct_tuple *v, struct ip_conntrack_tuple *tuple) ++{ ++ v->cpt_dst = tuple->dst.ip; ++ v->cpt_dstport = tuple->dst.u.all; ++ v->cpt_protonum = tuple->dst.protonum; ++ v->cpt_dir = tuple->dst.dir; ++ ++ v->cpt_src = tuple->src.ip; ++ v->cpt_srcport = tuple->src.u.all; ++} ++ ++static int dump_one_expect(struct cpt_ip_connexpect_image *v, ++ struct ip_conntrack_expect *exp, ++ int sibling, cpt_context_t *ctx) ++{ ++ int err = 0; ++ ++ v->cpt_next = sizeof(*v); ++ v->cpt_object = CPT_OBJ_NET_CONNTRACK_EXPECT; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_VOID; ++ ++ encode_tuple(&v->cpt_tuple, &exp->tuple); ++ encode_tuple(&v->cpt_mask, &exp->mask); ++ v->cpt_sibling_conntrack = sibling; ++ v->cpt_flags = exp->flags; ++ v->cpt_seq = exp->id; ++ v->cpt_dir = 0; ++ v->cpt_manip_proto = 0; ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ v->cpt_manip_proto = exp->saved_proto.all; ++ v->cpt_dir = exp->dir; ++#endif ++ v->cpt_timeout = 0; ++ if (exp->master->helper->timeout) ++ v->cpt_timeout = exp->timeout.expires - jiffies; ++ return err; ++} ++ ++/* NOTE. We use one page to dump list of expectations. This may be not enough ++ * in theory. In practice there is only one expectation per conntrack record. ++ * Moreover, taking into account that _ALL_ of expecations are saved in one ++ * global list, which is looked up each incoming/outpging packet, the system ++ * would be severely dead when even one conntrack would have so much of ++ * expectations. Shortly, I am not going to repair this. ++ */ ++ ++static int dump_expect_list(struct ip_conntrack *ct, struct ct_holder *list, ++ cpt_context_t *ctx) ++{ ++ int err = 0; ++ unsigned long pg; ++ struct cpt_ip_connexpect_image *v; ++ struct ip_conntrack_expect *exp; ++ ++ if (ct->expecting == 0) ++ return err; ++ if (ct->expecting*sizeof(struct cpt_ip_connexpect_image) > PAGE_SIZE) ++ return -ENOBUFS; ++ ++ pg = __get_free_page(GFP_KERNEL); ++ if (!pg) ++ return -ENOMEM; ++ v = (struct cpt_ip_connexpect_image *)pg; ++ ++ read_lock_bh(&ip_conntrack_lock); ++ list_for_each_entry(exp, &ve_ip_conntrack_expect_list, list) { ++ int sibling; ++ ++ if (exp->master != ct) ++ continue; ++ ++ if (ct->helper == NULL) { ++ eprintk_ctx("conntrack: no helper and non-trivial expectation\n"); ++ err = -EINVAL; ++ break; ++ } ++ ++ sibling = 0; ++#if 0 ++ /* That's all? No need to calculate sibling? */ ++ if (exp->sibling) { ++ struct ct_holder *c; ++ for (c = list; c; c = c->next) { ++ if (tuplehash_to_ctrack(c->cth) == exp->sibling) { ++ sibling = c->index; ++ break; ++ } ++ } ++ /* NOTE: exp->sibling could be not "confirmed" and, hence, ++ * out of hash table. We should just ignore such a sibling, ++ * the connection is going to be retried, the packet ++ * apparently was lost somewhere. ++ */ ++ if (sibling == 0) ++ dprintk_ctx("sibling conntrack is not found\n"); ++ } ++#endif ++ ++ /* If the expectation still does not have exp->sibling ++ * and timer is not running, it is about to die on another ++ * cpu. Skip it. */ ++ if (!sibling && ++ ct->helper->timeout && ++ !timer_pending(&exp->timeout)) { ++ dprintk_ctx("conntrack: expectation: no timer\n"); ++ continue; ++ } ++ ++ err = dump_one_expect(v, exp, sibling, ctx); ++ if (err) ++ break; ++ ++ v++; ++ } ++ read_unlock_bh(&ip_conntrack_lock); ++ ++ if (err == 0 && (unsigned long)v != pg) ++ ctx->write((void*)pg, (unsigned long)v - pg, ctx); ++ ++ free_page(pg); ++ return err; ++} ++ ++static int dump_one_ct(struct ct_holder *c, struct ct_holder *list, ++ cpt_context_t *ctx) ++{ ++ struct ip_conntrack_tuple_hash *h = c->cth; ++ struct ip_conntrack *ct = tuplehash_to_ctrack(h); ++ struct cpt_ip_conntrack_image v; ++ int err = 0; ++ ++ if (sizeof(v.cpt_proto_data) != sizeof(ct->proto)) { ++ eprintk_ctx("conntrack module ct->proto version mismatch\n"); ++ return -EINVAL; ++ } ++ ++ cpt_open_object(NULL, ctx); ++ ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_NET_CONNTRACK; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_ARRAY; ++ ++ read_lock_bh(&ip_conntrack_lock); ++ v.cpt_status = ct->status; ++ v.cpt_timeout = ct->timeout.expires - jiffies; ++ v.cpt_ct_helper = (ct->helper != NULL); ++ v.cpt_index = c->index; ++ v.cpt_id = ct->id; ++ v.cpt_mark = 0; ++#if defined(CONFIG_IP_NF_CONNTRACK_MARK) ++ v.cpt_mark = ct->mark; ++#endif ++ encode_tuple(&v.cpt_tuple[0], &ct->tuplehash[0].tuple); ++ encode_tuple(&v.cpt_tuple[1], &ct->tuplehash[1].tuple); ++ memcpy(&v.cpt_proto_data, &ct->proto, sizeof(v.cpt_proto_data)); ++ memcpy(&v.cpt_help_data, &ct->help, sizeof(v.cpt_help_data)); ++ ++ v.cpt_masq_index = 0; ++ v.cpt_initialized = 0; ++ v.cpt_num_manips = 0; ++ v.cpt_nat_helper = 0; ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ ++ defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) ++ v.cpt_masq_index = ct->nat.masq_index; ++#endif ++ /* "help" data is used by pptp, difficult to support */ ++ v.cpt_nat_seq[0].cpt_correction_pos = ct->nat.info.seq[0].correction_pos; ++ v.cpt_nat_seq[0].cpt_offset_before = ct->nat.info.seq[0].offset_before; ++ v.cpt_nat_seq[0].cpt_offset_after = ct->nat.info.seq[0].offset_after; ++ v.cpt_nat_seq[1].cpt_correction_pos = ct->nat.info.seq[1].correction_pos; ++ v.cpt_nat_seq[1].cpt_offset_before = ct->nat.info.seq[1].offset_before; ++ v.cpt_nat_seq[1].cpt_offset_after = ct->nat.info.seq[1].offset_after; ++#endif ++ read_unlock_bh(&ip_conntrack_lock); ++ ++ ctx->write(&v, sizeof(v), ctx); ++ ++ err = dump_expect_list(ct, list, ctx); ++ ++ cpt_close_object(ctx); ++ return err; ++} ++ ++int cpt_dump_ip_conntrack(cpt_context_t * ctx) ++{ ++ struct ct_holder *ct_list = NULL; ++ struct ct_holder *c, **cp; ++ int err = 0; ++ int index = 0; ++ int idx; ++ ++ if (get_exec_env()->_ip_conntrack == NULL) ++ return 0; ++ ++ for (idx = atomic_read(&(get_exec_env()->_ip_conntrack->_ip_conntrack_count)); idx >= 0; idx--) { ++ c = kmalloc(sizeof(struct ct_holder), GFP_KERNEL); ++ if (c == NULL) { ++ err = -ENOMEM; ++ goto done; ++ } ++ memset(c, 0, sizeof(struct ct_holder)); ++ c->next = ct_list; ++ ct_list = c; ++ } ++ ++ c = ct_list; ++ ++ read_lock_bh(&ip_conntrack_lock); ++ for (idx = 0; idx < ip_conntrack_htable_size; idx++) { ++ struct ip_conntrack_tuple_hash *h; ++ list_for_each_entry(h, &ve_ip_conntrack_hash[idx], list) { ++ /* Skip reply tuples, they are covered by original ++ * direction. */ ++ if (DIRECTION(h)) ++ continue; ++ ++ /* Oops, we have not enough of holders... ++ * It is impossible. */ ++ if (unlikely(c == NULL)) { ++ read_unlock_bh(&ip_conntrack_lock); ++ eprintk_ctx("unexpected conntrack appeared\n"); ++ err = -ENOMEM; ++ goto done; ++ } ++ ++ /* If timer is not running, it means that it ++ * has just been scheduled on another cpu. ++ * We should skip this conntrack, it is about to be ++ * destroyed. */ ++ if (!del_timer(&tuplehash_to_ctrack(h)->timeout)) { ++ dprintk_ctx("conntrack: no timer\n"); ++ continue; ++ } ++ ++ /* Timer is deleted. refcnt is _not_ decreased. ++ * We are going to restore the timer on exit ++ * from this function. */ ++ c->cth = h; ++ c->index = ++index; ++ c = c->next; ++ } ++ } ++ read_unlock_bh(&ip_conntrack_lock); ++ ++ /* No conntracks? Good. */ ++ if (index == 0) ++ goto done; ++ ++ /* Comb the list a little. */ ++ cp = &ct_list; ++ while ((c = *cp) != NULL) { ++ /* Discard unused entries; they can appear, if some ++ * entries were timed out since we preallocated the list. ++ */ ++ if (c->cth == NULL) { ++ *cp = c->next; ++ kfree(c); ++ continue; ++ } ++ ++ /* Move conntracks attached to expectations to the beginning ++ * of the list. */ ++ if (tuplehash_to_ctrack(c->cth)->master && c != ct_list) { ++ *cp = c->next; ++ c->next = ct_list; ++ ct_list = c; ++ dprintk_ctx("conntrack: %d moved in list\n", c->index); ++ continue; ++ } ++ cp = &c->next; ++ } ++ ++ cpt_open_section(ctx, CPT_SECT_NET_CONNTRACK); ++ ++ for (c = ct_list; c; c = c->next) { ++ err = dump_one_ct(c, ct_list, ctx); ++ if (err) ++ goto done; ++ } ++ ++ cpt_close_section(ctx); ++ ++done: ++ while ((c = ct_list) != NULL) { ++ ct_list = c->next; ++ if (c->cth) { ++ /* Restore timer. refcnt is preserved. */ ++ add_timer(&tuplehash_to_ctrack(c->cth)->timeout); ++ } ++ kfree(c); ++ } ++ return err; ++} ++ ++#endif +Index: kernel/kernel/cpt/cpt_context.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_context.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,257 @@ ++/* ++ * ++ * kernel/cpt/cpt_context.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++ ++ ++static void file_write(const void *addr, size_t count, struct cpt_context *ctx) ++{ ++ mm_segment_t oldfs; ++ ssize_t err = -EBADF; ++ struct file *file = ctx->file; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ if (file) ++ err = file->f_op->write(file, addr, count, &file->f_pos); ++ set_fs(oldfs); ++ if (err != count && !ctx->write_error) ++ ctx->write_error = err < 0 ? err : -EIO; ++} ++ ++static void file_pwrite(void *addr, size_t count, struct cpt_context *ctx, loff_t pos) ++{ ++ mm_segment_t oldfs; ++ ssize_t err = -EBADF; ++ struct file *file = ctx->file; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ if (file) ++ err = file->f_op->write(file, addr, count, &pos); ++ set_fs(oldfs); ++ if (err != count && !ctx->write_error) ++ ctx->write_error = err < 0 ? err : -EIO; ++} ++ ++static void file_align(struct cpt_context *ctx) ++{ ++ struct file *file = ctx->file; ++ ++ if (file) ++ file->f_pos = CPT_ALIGN(file->f_pos); ++} ++ ++void cpt_context_init(struct cpt_context *ctx) ++{ ++ int i; ++ ++ memset(ctx, 0, sizeof(*ctx)); ++ ++ init_MUTEX(&ctx->main_sem); ++ ctx->refcount = 1; ++ ++ ctx->current_section = -1; ++ ctx->current_object = -1; ++ ctx->pagesize = PAGE_SIZE; ++ ctx->write = file_write; ++ ctx->pwrite = file_pwrite; ++ ctx->align = file_align; ++ for (i=0; i < CPT_SECT_MAX; i++) ++ ctx->sections[i] = CPT_NULL; ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ init_completion(&ctx->pgin_notify); ++#endif ++ cpt_object_init(ctx); ++} ++ ++int cpt_open_dumpfile(struct cpt_context *ctx) ++{ ++ ctx->tmpbuf = (char*)__get_free_page(GFP_KERNEL); ++ if (ctx->tmpbuf == NULL) ++ return -ENOMEM; ++ __cpt_release_buf(ctx); ++ return 0; ++} ++ ++int cpt_close_dumpfile(struct cpt_context *ctx) ++{ ++ if (ctx->file) { ++ fput(ctx->file); ++ ctx->file = NULL; ++ } ++ if (ctx->tmpbuf) { ++ free_page((unsigned long)ctx->tmpbuf); ++ ctx->tmpbuf = NULL; ++ } ++ if (ctx->write_error) ++ eprintk_ctx("error while writing dump file: %d\n", ctx->write_error); ++ return ctx->write_error; ++} ++ ++int cpt_major_hdr_out(struct cpt_context *ctx) ++{ ++ struct cpt_major_hdr hdr; ++ ++ if (ctx->file == NULL) ++ return 0; ++ ++ memset(&hdr, 0, sizeof(hdr)); ++ hdr.cpt_signature[0] = CPT_SIGNATURE0; ++ hdr.cpt_signature[1] = CPT_SIGNATURE1; ++ hdr.cpt_signature[2] = CPT_SIGNATURE2; ++ hdr.cpt_signature[3] = CPT_SIGNATURE3; ++ hdr.cpt_hdrlen = sizeof(hdr); ++ hdr.cpt_image_version = CPT_VERSION_20; ++#ifdef CONFIG_X86_64 ++ hdr.cpt_os_arch = CPT_OS_ARCH_EMT64; ++#elif defined(CONFIG_X86_32) ++ hdr.cpt_os_arch = CPT_OS_ARCH_I386; ++#elif defined(CONFIG_IA64) ++ hdr.cpt_os_arch = CPT_OS_ARCH_IA64; ++#else ++#error Arch is not supported ++#endif ++ hdr.cpt_ve_features = (__u32)ctx->features; ++ hdr.cpt_ve_features2 = (__u32)(ctx->features>>32); ++ hdr.cpt_pagesize = (__u16)PAGE_SIZE; ++ hdr.cpt_hz = HZ; ++ hdr.cpt_start_jiffies64 = ctx->virt_jiffies64; ++ hdr.cpt_start_sec = ctx->start_time.tv_sec; ++ hdr.cpt_start_nsec = ctx->start_time.tv_nsec; ++ hdr.cpt_cpu_caps[0] = ctx->src_cpu_flags; ++ hdr.cpt_kernel_config[0] = ctx->kernel_config_flags; ++ hdr.cpt_iptables_mask = ctx->iptables_mask; ++ ++ ctx->write(&hdr, sizeof(hdr), ctx); ++ return 0; ++} ++ ++int cpt_close_section(struct cpt_context *ctx) ++{ ++ if (ctx->file && ctx->current_section >= 0) { ++ __u64 next = ctx->file->f_pos - ctx->current_section; ++ ctx->pwrite(&next, 8, ctx, ctx->current_section); ++ ctx->current_section = -1; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(cpt_close_section); ++ ++int cpt_open_section(struct cpt_context *ctx, __u32 type) ++{ ++ struct cpt_section_hdr hdr; ++ ++ if (ctx->file == NULL) ++ return 0; ++ ++ cpt_close_section(ctx); ++ ++ ctx->current_section = ctx->file->f_pos; ++ ctx->sections[type] = ctx->current_section; ++ ++ hdr.cpt_next = 0; ++ hdr.cpt_section = type; ++ hdr.cpt_hdrlen = sizeof(hdr); ++ hdr.cpt_align = 0; ++ ctx->write(&hdr, sizeof(hdr), ctx); ++ ++ return 0; ++} ++EXPORT_SYMBOL(cpt_open_section); ++ ++ ++int cpt_close_object(struct cpt_context *ctx) ++{ ++ if (ctx->file && ctx->current_object >= 0) { ++ __u64 next = ctx->file->f_pos - ctx->current_object; ++ ctx->pwrite(&next, 8, ctx, ctx->current_object); ++ ctx->current_object = -1; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(cpt_close_object); ++ ++int cpt_open_object(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ if (ctx->file == NULL) ++ return 0; ++ ++ cpt_close_object(ctx); ++ ++ ctx->current_object = ctx->file->f_pos; ++ if (obj) ++ cpt_obj_setpos(obj, ctx->current_object, ctx); ++ ++ return 0; ++} ++EXPORT_SYMBOL(cpt_open_object); ++ ++int cpt_push_object(loff_t *saved, struct cpt_context *ctx) ++{ ++ if (ctx->file) { ++ *saved = ctx->current_object; ++ ctx->current_object = ctx->file->f_pos; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(cpt_push_object); ++ ++int cpt_pop_object(loff_t *saved, struct cpt_context *ctx) ++{ ++ ctx->current_object = *saved; ++ return 0; ++} ++EXPORT_SYMBOL(cpt_pop_object); ++ ++int cpt_dump_tail(struct cpt_context *ctx) ++{ ++ struct cpt_major_tail hdr; ++ int i; ++ ++ if (ctx->file == NULL) ++ return 0; ++ ++ cpt_open_section(ctx, CPT_SECT_TRAILER); ++ memset(&hdr, 0, sizeof(hdr)); ++ hdr.cpt_next = sizeof(hdr); ++ hdr.cpt_object = CPT_OBJ_TRAILER; ++ hdr.cpt_hdrlen = sizeof(hdr); ++ hdr.cpt_content = CPT_CONTENT_VOID; ++ hdr.cpt_lazypages = 0; ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ hdr.cpt_lazypages = ctx->lazypages; ++#endif ++ hdr.cpt_64bit = ctx->tasks64; ++ hdr.cpt_signature[0] = CPT_SIGNATURE0; ++ hdr.cpt_signature[1] = CPT_SIGNATURE1; ++ hdr.cpt_signature[2] = CPT_SIGNATURE2; ++ hdr.cpt_signature[3] = CPT_SIGNATURE3; ++ hdr.cpt_nsect = CPT_SECT_MAX_INDEX; ++ for (i = 0; i < CPT_SECT_MAX_INDEX; i++) ++ hdr.cpt_sections[i] = ctx->sections[i]; ++ ++ ctx->write(&hdr, sizeof(hdr), ctx); ++ cpt_close_section(ctx); ++ return 0; ++} +Index: kernel/kernel/cpt/cpt_context.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_context.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,215 @@ ++#include ++#include ++#include ++ ++#define CPT_CTX_ERROR -1 ++#define CPT_CTX_IDLE 0 ++#define CPT_CTX_SUSPENDING 1 ++#define CPT_CTX_SUSPENDED 2 ++#define CPT_CTX_DUMPING 3 ++#define CPT_CTX_UNDUMPING 4 ++#define CPT_CTX_UNDUMPED 5 ++ ++#define CPT_TID(tsk) task_pid_nr(tsk), task_pid_vnr(tsk), (tsk)->comm ++#define CPT_FID "%d,%d(%s)" ++ ++ ++typedef struct cpt_context ++{ ++ struct list_head ctx_list; ++ int refcount; ++ int ctx_state; ++ int objcount; ++ int sticky; ++ struct semaphore main_sem; ++ ++ struct file *errorfile; ++ struct file *statusfile; ++ struct file *lockfile; ++ ++ int errno; ++ char *error_msg; ++ loff_t err_offset; ++ ++ struct file *file; ++ char *tmpbuf; ++ int pagesize; ++#ifdef CONFIG_VZ_CHECKPOINT_ITER ++ int iter_done; ++ void *iter_dir; ++ struct user_beancounter *iter_ub; ++#endif ++ loff_t current_section; ++ loff_t current_object; ++ ++ loff_t sections[CPT_SECT_MAX]; ++ ++ __u32 errormask; ++ __u32 write_error; ++ ++ struct list_head object_array[CPT_OBJ_MAX]; ++ ++ void (*write)(const void *addr, size_t count, struct cpt_context *ctx); ++ void (*pwrite)(void *addr, size_t count, struct cpt_context *ctx, loff_t pos); ++ ssize_t (*read)(void *addr, size_t count, struct cpt_context *ctx); ++ ssize_t (*pread)(void *addr, size_t count, struct cpt_context *ctx, loff_t pos); ++ void (*align)(struct cpt_context *ctx); ++ int ve_id; ++ int contextid; ++ struct timespec cpt_monotonic_time; /* Host monotonic time at the moment of cpt/rst ++ * corresponging to start_time */ ++ __u64 virt_jiffies64; /* Virtual jiffies64. It is == cpt_jiffies64 when ++ * VE did not migrate. */ ++ struct timespec start_time; ++ struct timespec delta_time; ++ __s64 delta_nsec; ++ int image_version; ++ __u16 image_arch; ++ __u64 iptables_mask; ++ __u64 features; ++ ++#define CPT_ANONVMA_HBITS (sizeof(void*) == 4 ? 10 : 9) ++#define CPT_ANONVMA_HSIZE (1<ve_id, ##arg) ++ ++#define wprintk(a...) cpt_printk(2, "CPT WRN: " a) ++#define wprintk_ctx(f, arg...) wprintk("%p,%u: " f, ctx, ctx->ve_id, ##arg) ++ ++#define eprintk(a...) cpt_printk(1, "CPT ERR: " a) ++#define eprintk_ctx(f, arg...) \ ++do { \ ++ eprintk("%p,%u :" f, ctx, ctx->ve_id, ##arg); \ ++ if (ctx->error_msg && ctx->err_offset < PAGE_SIZE) \ ++ ctx->err_offset += snprintf((char*)(ctx->error_msg + \ ++ ctx->err_offset), \ ++ PAGE_SIZE - ctx->err_offset, \ ++ "Error: " f, ##arg); \ ++} while(0) ++ ++#define CPT_TMPBUF_FREE 0x789adf12 ++#define CPT_TMPBUF_BUSY 0xabcd9876 ++ ++static inline void *cpt_get_buf(cpt_context_t *ctx) ++{ ++ void *buf = ctx->tmpbuf; ++ ++ BUG_ON(*(u32*)(buf + PAGE_SIZE - 4) != CPT_TMPBUF_FREE); ++ *(u32*)(buf + PAGE_SIZE - 4) = CPT_TMPBUF_BUSY; ++ return buf; ++} ++ ++static inline void __cpt_release_buf(cpt_context_t *ctx) ++{ ++ void *buf = ctx->tmpbuf; ++ ++ *(u32*)(buf + PAGE_SIZE - 4) = CPT_TMPBUF_FREE; ++} ++ ++static inline void cpt_release_buf(cpt_context_t *ctx) ++{ ++ void *buf = ctx->tmpbuf; ++ ++ BUG_ON(*(u32*)(buf + PAGE_SIZE - 4) != CPT_TMPBUF_BUSY); ++ *(u32*)(buf + PAGE_SIZE - 4) = CPT_TMPBUF_FREE; ++} ++ ++static inline void cpt_flush_error(cpt_context_t *ctx) ++{ ++ mm_segment_t oldfs; ++ ++ if (ctx->errorfile && ctx->error_msg && ctx->err_offset) { ++ if (ctx->errorfile->f_op && ctx->errorfile->f_op->write) { ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ctx->errorfile->f_op->write(ctx->errorfile, ++ ctx->error_msg, ctx->err_offset, ++ &ctx->errorfile->f_pos); ++ set_fs(oldfs); ++ } ++ ctx->error_msg[0] = 0; ++ ctx->err_offset = 0; ++ } ++} +Index: kernel/kernel/cpt/cpt_dump.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_dump.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,1238 @@ ++/* ++ * ++ * kernel/cpt/cpt_dump.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_dump.h" ++#include "cpt_files.h" ++#include "cpt_mm.h" ++#include "cpt_process.h" ++#include "cpt_net.h" ++#include "cpt_socket.h" ++#include "cpt_ubc.h" ++#include "cpt_kernel.h" ++ ++ ++static int vps_child_level(struct task_struct *root, struct task_struct *c) ++{ ++ int level = 0; ++ int veid = VE_TASK_INFO(c)->owner_env->veid; ++ ++ while (VE_TASK_INFO(c)->owner_env->veid == veid) { ++ if (c->pid != c->tgid) ++ c = c->group_leader; ++ if (c == root) ++ return level; ++ ++ c = c->parent; ++ level++; ++ } ++ return -1; ++} ++ ++static inline int freezable(struct task_struct * p) ++{ ++ if (p->exit_state) ++ return 0; ++ ++ switch (p->state) { ++ case EXIT_ZOMBIE: ++ case EXIT_DEAD: ++ case TASK_STOPPED: ++#if TASK_TRACED != TASK_STOPPED ++ case TASK_TRACED: ++#endif ++ return 0; ++ default: ++ return 1; ++ } ++} ++ ++static void wake_ve(cpt_context_t *ctx) ++{ ++ struct task_struct *p, *g; ++ ++ do_each_thread_ve(g, p) { ++ spin_lock_irq(&p->sighand->siglock); ++ if (p->flags & PF_FROZEN) { ++ p->flags &= ~PF_FROZEN; ++ wake_up_process(p); ++ } ++ spin_unlock_irq(&p->sighand->siglock); ++ } while_each_thread_ve(g, p); ++} ++ ++/* ++ * Some comment is necessary about PF_FREEZE,PF_FROZEN,TIF_FREEZE... ++ * ++ * SWSUSP uses PF_FREEZE flag in tsk->flags raising it in context ++ * of another process. Apparently, it is unacceptable on SMP. ++ * Let's take freeze_processes() in kernel/power/process.c as an example. ++ * Unserialized modifications tsk->flags easily ++ * (believe or not, but it happens with probability of almost 100% :-)) ++ * creates the situation when setting PF_FREEZE in freeze_processes(), ++ * which quickly spins raising PF_FREEZE of all the processes, ++ * _clears_ PF_FROZEN just set in refrigerator(), so that suspend deadlocks. ++ * ++ * So, to make things clean, we require that those flags may be modified ++ * only under tsk->sighand->siglock, which is quite natural because PF_FREEZE ++ * is just a kind of signal. ++ * ++ * It is not enough, because we are still not allowed to change tsk->flags ++ * in context of another process, we can corrupt another flags, when the process ++ * running on another cpu modifies them. So, we use TIF_FREEZE in thread flags, ++ * which can be changed atomically. ++ * ++ * PF_FROZEN also changes in context of another process, but this happens ++ * only when the process is already in refrigerator() which does not modify ++ * tsk->flags. ++ */ ++ ++static int check_process_external(struct task_struct *p) ++{ ++ if (pid_alive(p)) { ++ if (p->pids[PIDTYPE_PID].pid->level == 0) ++ return PIDTYPE_PID; ++ if (p->pids[PIDTYPE_PGID].pid->level == 0) ++ return PIDTYPE_PGID; ++ if (p->pids[PIDTYPE_SID].pid->level == 0) ++ return PIDTYPE_SID; ++ } ++ ++ return PIDTYPE_MAX; ++} ++ ++enum ++{ ++ OBSTACLE_NOGO = -1, ++ OBSTACLE_TIMEOUT = -2, ++ OBSTACLE_TRYAGAIN = -3, ++}; ++ ++#define SUSPEND_TIMEOUT (10UL*HZ) ++ ++static int vps_stop_tasks(struct cpt_context *ctx) ++{ ++ unsigned long start_time = jiffies; ++ unsigned long target, timeout; ++ struct task_struct *p, *g; ++ int todo; ++ int round = 0; ++ ++ do_gettimespec(&ctx->start_time); ++ do_posix_clock_monotonic_gettime(&ctx->cpt_monotonic_time); ++ ctx->virt_jiffies64 = get_jiffies_64() + get_exec_env()->jiffies_fixup; ++ ++ read_lock(&tasklist_lock); ++ ++ atomic_inc(&get_exec_env()->suspend); ++ timeout = HZ/5; ++ target = jiffies + timeout; ++ ++ for(;;) { ++ struct task_struct *root; ++ todo = 0; ++ ++ root = find_task_by_vpid(1); ++ if (!root) { ++ read_unlock(&tasklist_lock); ++ eprintk_ctx("cannot find ve init\n"); ++ atomic_dec(&get_exec_env()->suspend); ++ return -ESRCH; ++ } ++ ++ do_each_thread_ve(g, p) { ++ if (vps_child_level(root, p) >= 0) { ++ switch (check_process_external(p)) { ++ case PIDTYPE_PID: ++ eprintk_ctx("external process %d/%d(%s) inside CT (e.g. vzctl enter or vzctl exec).\n", ++ task_pid_vnr(p), p->pid, p->comm); ++ todo = OBSTACLE_NOGO; ++ goto out; ++ case PIDTYPE_PGID: ++ eprintk_ctx("external process group %d/%d(%s) inside CT " ++ "(e.g. vzctl enter or vzctl exec).\n", ++ task_pgrp_vnr(p), p->pid, p->comm); ++ todo = OBSTACLE_NOGO; ++ goto out; ++ case PIDTYPE_SID: ++ eprintk_ctx("external process session %d/%d(%s) inside CT " ++ "(e.g. vzctl enter or vzctl exec).\n", ++ task_session_vnr(p), p->pid, p->comm); ++ todo = OBSTACLE_NOGO; ++ goto out; ++ } ++ if (p->vfork_done) { ++ /* Task between vfork()...exec() ++ * cannot be frozen, because parent ++ * wait in uninterruptible state. ++ * So, we do nothing, waiting for ++ * exec(), unless: ++ */ ++ if (p->state == TASK_STOPPED || ++ p->state == TASK_TRACED) { ++ eprintk_ctx("task " CPT_FID " is stopped while vfork(). " ++ "Checkpointing is impossible.\n", ++ CPT_TID(p)); ++ todo = OBSTACLE_NOGO; ++ /* It is fatal, _user_ stopped ++ * vfork()ing task, so that we ++ * cannot suspend now. ++ */ ++ } else { ++ todo = OBSTACLE_TRYAGAIN; ++ } ++ goto out; ++ } ++ if (p->signal->group_exit_task && ++ p->signal->notify_count) { ++ /* exec() waits for threads' death */ ++ wprintk_ctx("task " CPT_FID " waits for threads' death\n", CPT_TID(p)); ++ todo = OBSTACLE_TRYAGAIN; ++ goto out; ++ } ++ if (p->state == TASK_TRACED ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) ++ && !p->stopped_state ++#endif ++ ) { ++ int ptrace_id = p->pn_state; ++ /* Debugger waits for signal. */ ++ switch (ptrace_id) { ++ case PN_STOP_TF: ++ case PN_STOP_TF_RT: ++ case PN_STOP_ENTRY: ++ case PN_STOP_FORK: ++ case PN_STOP_VFORK: ++ case PN_STOP_SIGNAL: ++ case PN_STOP_EXIT: ++ case PN_STOP_LEAVE: ++ break; ++ default: ++ eprintk_ctx("task " CPT_FID " is stopped by debugger while %d.\n", CPT_TID(p), ptrace_id); ++ todo = OBSTACLE_NOGO; ++ goto out; ++ } ++ } ++#ifdef CONFIG_UTRACE ++ if (check_utrace(p, root, ctx)) { ++ eprintk_ctx("task " CPT_FID " is utraced. Checkpointing is impossible.\n", CPT_TID(p)); ++ todo = OBSTACLE_NOGO; ++ goto out; ++ } ++#endif ++ if (p->flags & PF_NOFREEZE) { ++ eprintk_ctx("task " CPT_FID " is unfreezable. Checkpointing is impossible.\n", CPT_TID(p)); ++ todo = OBSTACLE_NOGO; ++ goto out; ++ } ++ ++ if (!freezable(p)) ++ continue; ++ ++ spin_lock_irq(&p->sighand->siglock); ++ if (!(p->flags & PF_FROZEN)) { ++ set_tsk_thread_flag(p, TIF_FREEZE); ++ signal_wake_up(p, 0); ++ } ++ spin_unlock_irq(&p->sighand->siglock); ++ ++ if (p->flags & PF_FROZEN) { ++ if (p->state != TASK_UNINTERRUPTIBLE) ++ printk("Holy Crap 1 %ld " CPT_FID "\n", p->state, CPT_TID(p)); ++ continue; ++ } ++ ++ if (round == 10) ++ wprintk_ctx(CPT_FID " is running\n", CPT_TID(p)); ++ ++ todo++; ++ } else { ++ if (p != current) { ++ eprintk_ctx("foreign process %d/%d(%s) inside CT (e.g. vzctl enter or vzctl exec).\n", ++ task_pid_vnr(p), task_pid_nr(p), p->comm); ++ todo = OBSTACLE_NOGO; ++ goto out; ++ } ++ } ++ } while_each_thread_ve(g, p); ++ ++ if (todo > 0) { ++ /* No visible obstacles, but VE did not freeze ++ * for timeout. Interrupt suspend, if it is major ++ * timeout or signal; if it is minor timeout ++ * we will wake VE and restart suspend. ++ */ ++ if (time_after(jiffies, start_time + SUSPEND_TIMEOUT) ++ || signal_pending(current)) ++ todo = OBSTACLE_TIMEOUT; ++ else if (time_after(jiffies, target)) ++ todo = OBSTACLE_TRYAGAIN; ++ } ++ ++out: ++ if (todo < 0) { ++ atomic_dec(&get_exec_env()->suspend); ++ ++ wake_ve(ctx); ++ ++#if 0 ++ /* This is sign of failure of printk(), which is not ++ * ours. So, no prefixes. */ ++ printk(">\n"); ++#endif ++ } ++ ++ read_unlock(&tasklist_lock); ++ ++ if (!todo) { ++ atomic_dec(&get_exec_env()->suspend); ++ return 0; ++ } ++ ++ switch (todo) { ++ case OBSTACLE_NOGO: ++ eprintk_ctx("suspend is impossible now.\n"); ++ return -EAGAIN; ++ ++ case OBSTACLE_TIMEOUT: ++ eprintk_ctx("interrupted or timed out.\n"); ++ return -EINTR; ++ ++ case OBSTACLE_TRYAGAIN: ++ if (time_after(jiffies, start_time + SUSPEND_TIMEOUT) || ++ signal_pending(current)) { ++ wprintk_ctx("suspend timed out\n"); ++ return -EAGAIN; ++ } ++ ++ wprintk_ctx("minor suspend timeout (%lu) expired, " ++ "trying again\n", timeout); ++ ++ /* Try again. VE is awake, give it some time to run. */ ++ current->state = TASK_INTERRUPTIBLE; ++ schedule_timeout(HZ); ++ ++ /* After a short wait restart suspend ++ * with longer timeout */ ++ atomic_inc(&get_exec_env()->suspend); ++ timeout = min(timeout<<1, SUSPEND_TIMEOUT); ++ target = jiffies + timeout; ++ break; ++ ++ default: ++ if (round > 0) { ++ /* VE is partially frozen, give processes ++ * a chance to enter to refrigerator(). */ ++ current->state = TASK_INTERRUPTIBLE; ++ schedule_timeout(HZ/20); ++ } else { ++ yield(); ++ } ++ } ++ ++ read_lock(&tasklist_lock); ++ round++; ++ } ++} ++ ++static int cpt_unlock_ve(struct cpt_context *ctx) ++{ ++ struct ve_struct *env; ++ ++ env = get_ve_by_id(ctx->ve_id); ++ if (!env) ++ return -ESRCH; ++ down_write(&env->op_sem); ++ env->is_locked = 0; ++ up_write(&env->op_sem); ++ put_ve(env); ++ return 0; ++} ++ ++int cpt_resume(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ virtinfo_notifier_call(VITYPE_SCP, VIRTINFO_SCP_DMPFIN, ctx); ++ ++ cpt_unlock_sockets(ctx); ++ ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ if (ctx->pgin_task) { ++ wait_for_completion(&ctx->pgin_notify); ++ put_task_struct(ctx->pgin_task); ++ ctx->pgin_task = NULL; ++ } ++#endif ++ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ struct task_struct *tsk = obj->o_obj; ++ ++ spin_lock_irq(&tsk->sighand->siglock); ++ if (tsk->flags & PF_FROZEN) { ++ tsk->flags &= ~PF_FROZEN; ++ wake_up_process(tsk); ++ } else if (freezable(tsk)) { ++ eprintk_ctx("strange, %s not frozen\n", tsk->comm ); ++ } ++ spin_unlock_irq(&tsk->sighand->siglock); ++ put_task_struct(tsk); ++ } ++ ++ cpt_resume_network(ctx); ++ ++ cpt_unlock_ve(ctx); ++ ++ cpt_finish_ubc(ctx); ++ cpt_object_destroy(ctx); ++ return 0; ++} ++ ++int cpt_kill(struct cpt_context *ctx) ++{ ++ int err = 0; ++ struct ve_struct *env; ++ cpt_object_t *obj; ++ struct task_struct *root_task = NULL; ++ long delay; ++ ++ if (!ctx->ve_id) ++ return -EINVAL; ++ ++ env = get_ve_by_id(ctx->ve_id); ++ if (!env) ++ return -ESRCH; ++ ++ /* from here cpt_kill succeeds */ ++ virtinfo_notifier_call(VITYPE_SCP, VIRTINFO_SCP_DMPFIN, ctx); ++ ++ if (current->ve_task_info.owner_env == env) { ++ wprintk_ctx("attempt to kill ve from inside, escaping...\n"); ++ ve_move_task(current, get_ve0()); ++ } ++ ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ if (ctx->pgin_task) { ++ wait_for_completion(&ctx->pgin_notify); ++ put_task_struct(ctx->pgin_task); ++ ctx->pgin_task = NULL; ++ } ++#endif ++ ++ cpt_kill_sockets(ctx); ++ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ struct task_struct *tsk = obj->o_obj; ++ ++ if (tsk->exit_state) { ++ put_task_struct(tsk); ++ continue; ++ } ++ ++ if (task_pid_vnr(tsk) == 1) { ++ root_task = tsk; ++ continue; ++ } ++ ++ tsk->robust_list = NULL; ++#ifdef CONFIG_COMPAT ++ tsk->compat_robust_list = NULL; ++#endif ++ tsk->clear_child_tid = NULL; ++ ++ if (tsk->ptrace) { ++ write_lock_irq(&tasklist_lock); ++ tsk->ptrace = 0; ++ if (!list_empty(&tsk->ptrace_list)) { ++ list_del_init(&tsk->ptrace_list); ++ remove_parent(tsk); ++ tsk->parent = tsk->parent; ++ add_parent(tsk); ++ } ++ write_unlock_irq(&tasklist_lock); ++ } ++ ++ send_sig(SIGKILL, tsk, 1); ++ ++ spin_lock_irq(&tsk->sighand->siglock); ++ sigfillset(&tsk->blocked); ++ sigdelsetmask(&tsk->blocked, sigmask(SIGKILL)); ++ set_tsk_thread_flag(tsk, TIF_SIGPENDING); ++ if (tsk->flags & PF_FROZEN) ++ tsk->flags &= ~PF_FROZEN; ++ spin_unlock_irq(&tsk->sighand->siglock); ++ ++ wake_up_process(tsk); ++ put_task_struct(tsk); ++ } ++ ++ yield(); ++ ++ if (root_task != NULL) { ++ send_sig(SIGKILL, root_task, 1); ++ ++ spin_lock_irq(&root_task->sighand->siglock); ++ sigfillset(&root_task->blocked); ++ sigdelsetmask(&root_task->blocked, sigmask(SIGKILL)); ++ set_tsk_thread_flag(root_task, TIF_SIGPENDING); ++ clear_tsk_thread_flag(root_task, TIF_FREEZE); ++ if (root_task->flags & PF_FROZEN) ++ root_task->flags &= ~PF_FROZEN; ++ spin_unlock_irq(&root_task->sighand->siglock); ++ ++ wake_up_process(root_task); ++ put_task_struct(root_task); ++ } ++ ++ cpt_finish_ubc(ctx); ++ cpt_object_destroy(ctx); ++ ++ delay = 1; ++ while (atomic_read(&env->counter) != 1) { ++ if (signal_pending(current)) ++ break; ++ current->state = TASK_INTERRUPTIBLE; ++ delay = (delay < HZ) ? (delay << 1) : HZ; ++ schedule_timeout(delay); ++ } ++ put_ve(env); ++ ++ return err; ++} ++ ++#ifdef CONFIG_BEANCOUNTERS ++static void collect_task_ubc(struct task_struct *t, struct cpt_context *ctx) ++{ ++ struct task_beancounter *tbc; ++ ++ tbc = &(t->task_bc); ++ cpt_add_ubc(tbc->exec_ub, ctx); ++ cpt_add_ubc(tbc->task_ub, ctx); ++ cpt_add_ubc(tbc->fork_sub, ctx); ++} ++#else ++static void inline collect_task_ubc(struct task_struct *t, ++ struct cpt_context *ctx) ++{ return; } ++#endif ++ ++static cpt_object_t * remember_task(struct task_struct * child, ++ cpt_object_t * head, cpt_context_t * ctx) ++{ ++ cpt_object_t *cobj; ++ ++ if (freezable(child) && !(child->flags&PF_FROZEN)) { ++ eprintk_ctx("process " CPT_FID " is not frozen\n", CPT_TID(child)); ++ put_task_struct(child); ++ return NULL; ++ } ++ ++ if (lookup_cpt_object(CPT_OBJ_TASK, child, ctx)) BUG(); ++ if ((cobj = alloc_cpt_object(GFP_KERNEL, ctx)) == NULL) { ++ put_task_struct(child); ++ return NULL; ++ } ++ cobj->o_count = 1; ++ cpt_obj_setobj(cobj, child, ctx); ++ insert_cpt_object(CPT_OBJ_TASK, cobj, head, ctx); ++ collect_task_ubc(child, ctx); ++ return cobj; ++} ++ ++static int vps_collect_tasks(struct cpt_context *ctx) ++{ ++ int err = -ESRCH; ++ cpt_object_t *obj; ++ struct task_struct *root; ++ read_lock(&tasklist_lock); ++ root = find_task_by_vpid(1); ++ if (root) ++ get_task_struct(root); ++ read_unlock(&tasklist_lock); ++ ++ if (!root) { ++ err = -ESRCH; ++ eprintk_ctx("vps_collect_tasks: cannot find root\n"); ++ goto out; ++ } ++ ++ if ((obj = alloc_cpt_object(GFP_KERNEL, ctx)) == NULL) { ++ put_task_struct(root); ++ return -ENOMEM; ++ } ++ obj->o_count = 1; ++ cpt_obj_setobj(obj, root, ctx); ++ intern_cpt_object(CPT_OBJ_TASK, obj, ctx); ++ collect_task_ubc(root, ctx); ++ ++ /* Collect process subtree recursively */ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ cpt_object_t *head = obj; ++ struct task_struct *tsk = obj->o_obj; ++ struct task_struct *child; ++ ++ if (freezable(tsk) && !(tsk->flags&PF_FROZEN)) { ++ eprintk_ctx("process " CPT_FID " is not frozen\n", CPT_TID(tsk)); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (tsk->state == TASK_RUNNING) ++ printk("Holy Crap 2 %ld " CPT_FID "\n", tsk->state, CPT_TID(tsk)); ++ ++ wait_task_inactive(tsk); ++ ++ err = check_task_state(tsk, ctx); ++ if (err) ++ goto out; ++ ++ if (tsk->pid == tsk->tgid) { ++ child = tsk; ++ for (;;) { ++ read_lock(&tasklist_lock); ++ child = next_thread(child); ++ if (child != tsk) ++ get_task_struct(child); ++ read_unlock(&tasklist_lock); ++ ++ if (child == tsk) ++ break; ++ ++ if (child->parent != tsk->parent) { ++ put_task_struct(child); ++ eprintk_ctx("illegal thread structure, kernel bug\n"); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if ((head = remember_task(child, head, ctx)) == NULL) { ++ eprintk_ctx("task obj allocation failure\n"); ++ err = -ENOMEM; ++ goto out; ++ } ++ } ++ } ++ ++ /* About locking. VE is frozen. But lists of children ++ * may change at least for init, when entered task reparents ++ * to init and when reparented task exits. If we take care ++ * of this case, we still can unlock while scanning ++ * tasklists. ++ */ ++ read_lock(&tasklist_lock); ++ list_for_each_entry(child, &tsk->children, sibling) { ++ if (child->parent != tsk) ++ continue; ++ if (child->pid != child->tgid) ++ continue; ++ get_task_struct(child); ++ read_unlock(&tasklist_lock); ++ ++ if ((head = remember_task(child, head, ctx)) == NULL) { ++ eprintk_ctx("task obj allocation failure\n"); ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ read_lock(&tasklist_lock); ++ } ++ ++ list_for_each_entry(child, &tsk->ptrace_children, ptrace_list) { ++ if (child->parent != tsk) ++ continue; ++ if (child->pid != child->tgid) ++ continue; ++ get_task_struct(child); ++ read_unlock(&tasklist_lock); ++ ++ if ((head = remember_task(child, head, ctx)) == NULL) { ++ eprintk_ctx("task obj allocation failure\n"); ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ read_lock(&tasklist_lock); ++ } ++ read_unlock(&tasklist_lock); ++ } ++ ++ return 0; ++ ++out: ++ while (!list_empty(&ctx->object_array[CPT_OBJ_TASK])) { ++ struct list_head *head = ctx->object_array[CPT_OBJ_TASK].next; ++ cpt_object_t *obj = list_entry(head, cpt_object_t, o_list); ++ struct task_struct *tsk; ++ ++ list_del(head); ++ tsk = obj->o_obj; ++ put_task_struct(tsk); ++ free_cpt_object(obj, ctx); ++ } ++ return err; ++} ++ ++static int cpt_collect(struct cpt_context *ctx) ++{ ++ int err; ++ ++ if ((err = cpt_collect_mm(ctx)) != 0) ++ return err; ++ ++ if ((err = cpt_collect_sysv(ctx)) != 0) ++ return err; ++ ++ if ((err = cpt_collect_files(ctx)) != 0) ++ return err; ++ ++ if ((err = cpt_collect_fs(ctx)) != 0) ++ return err; ++ ++ if ((err = cpt_collect_namespace(ctx)) != 0) ++ return err; ++ ++ if ((err = cpt_collect_signals(ctx)) != 0) ++ return err; ++ ++ if (virtinfo_notifier_call(VITYPE_SCP, ++ VIRTINFO_SCP_COLLECT, ctx) & NOTIFY_FAIL) ++ return -ECHRNG; ++ ++ return 0; ++} ++ ++static int cpt_dump_veinfo(cpt_context_t *ctx) ++{ ++ struct cpt_veinfo_image *i = cpt_get_buf(ctx); ++ struct ve_struct *ve; ++ struct timespec delta; ++ struct ipc_namespace *ns; ++ ++ cpt_open_section(ctx, CPT_SECT_VEINFO); ++ cpt_open_object(NULL, ctx); ++ ++ memset(i, 0, sizeof(*i)); ++ ++ i->cpt_next = CPT_NULL; ++ i->cpt_object = CPT_OBJ_VEINFO; ++ i->cpt_hdrlen = sizeof(*i); ++ i->cpt_content = CPT_CONTENT_VOID; ++ ++ ve = get_exec_env(); ++ ns = ve->ve_ns->ipc_ns; ++ ++ if (ns->shm_ctlall > 0xFFFFFFFFU) ++ i->shm_ctl_all = 0xFFFFFFFFU; ++ if (ns->shm_ctlmax > 0xFFFFFFFFU) ++ i->shm_ctl_max = 0xFFFFFFFFU; ++ i->shm_ctl_mni = ns->shm_ctlmni; ++ ++ i->msg_ctl_max = ns->msg_ctlmax; ++ i->msg_ctl_mni = ns->msg_ctlmni; ++ i->msg_ctl_mnb = ns->msg_ctlmnb; ++ ++ BUILD_BUG_ON(sizeof(ns->sem_ctls) != sizeof(i->sem_ctl_arr)); ++ i->sem_ctl_arr[0] = ns->sem_ctls[0]; ++ i->sem_ctl_arr[1] = ns->sem_ctls[1]; ++ i->sem_ctl_arr[2] = ns->sem_ctls[2]; ++ i->sem_ctl_arr[3] = ns->sem_ctls[3]; ++ ++ do_posix_clock_monotonic_gettime(&delta); ++ _set_normalized_timespec(&delta, ++ delta.tv_sec - ve->start_timespec.tv_sec, ++ delta.tv_nsec - ve->start_timespec.tv_nsec); ++ i->start_timespec_delta = cpt_timespec_export(&delta); ++ i->start_jiffies_delta = get_jiffies_64() - ve->start_jiffies; ++ ++ i->last_pid = ve->ve_ns->pid_ns->last_pid; ++ ++ ctx->write(i, sizeof(*i), ctx); ++ cpt_release_buf(ctx); ++ cpt_close_object(ctx); ++ cpt_close_section(ctx); ++ return 0; ++} ++ ++static int cpt_dump_utsname(cpt_context_t *ctx) ++{ ++ int len; ++ struct cpt_object_hdr o; ++ struct ve_struct *ve; ++ struct uts_namespace *ns; ++ ++ cpt_open_section(ctx, CPT_SECT_UTSNAME); ++ ++ ve = get_exec_env(); ++ ns = ve->ve_ns->uts_ns; ++ ++ cpt_open_object(NULL, ctx); ++ len = strlen(ns->name.nodename); ++ o.cpt_next = CPT_NULL; ++ o.cpt_object = CPT_OBJ_NAME; ++ o.cpt_hdrlen = sizeof(o); ++ o.cpt_content = CPT_CONTENT_NAME; ++ ++ ctx->write(&o, sizeof(o), ctx); ++ ctx->write(ns->name.nodename, len+1, ctx); ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ ++ cpt_open_object(NULL, ctx); ++ len = strlen(ns->name.domainname); ++ o.cpt_next = CPT_NULL; ++ o.cpt_object = CPT_OBJ_NAME; ++ o.cpt_hdrlen = sizeof(o); ++ o.cpt_content = CPT_CONTENT_NAME; ++ ++ ctx->write(&o, sizeof(o), ctx); ++ ctx->write(ns->name.domainname, len+1, ctx); ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ ++ cpt_close_section(ctx); ++ return 0; ++} ++ ++#ifndef CONFIG_IA64 ++static int cpt_dump_vsyscall(cpt_context_t *ctx) ++{ ++ struct cpt_page_block *pgb = cpt_get_buf(ctx); ++ ++ cpt_open_section(ctx, CPT_SECT_VSYSCALL); ++ cpt_open_object(NULL, ctx); ++ ++ pgb->cpt_next = CPT_NULL; ++ pgb->cpt_object = CPT_OBJ_VSYSCALL; ++ pgb->cpt_hdrlen = sizeof(*pgb); ++ pgb->cpt_content = CPT_CONTENT_DATA; ++ pgb->cpt_start = cpt_ptr_export(vsyscall_addr); ++ pgb->cpt_end = pgb->cpt_start + PAGE_SIZE; ++ ++ ctx->write(pgb, sizeof(*pgb), ctx); ++ cpt_release_buf(ctx); ++ ++ ctx->write(vsyscall_addr, PAGE_SIZE, ctx); ++ ++ cpt_close_object(ctx); ++ cpt_close_section(ctx); ++ return 0; ++} ++#endif ++ ++int cpt_dump(struct cpt_context *ctx) ++{ ++ struct ve_struct *oldenv, *env; ++ struct nsproxy *old_ns; ++ int err, err2 = 0; ++ ++ if (!ctx->ve_id) ++ return -EINVAL; ++ ++ env = get_ve_by_id(ctx->ve_id); ++ if (!env) ++ return -ESRCH; ++ ++ down_read(&env->op_sem); ++ err = -ESRCH; ++ if (!env->is_running) ++ goto out_noenv; ++ if (!env->is_locked) ++ goto out_noenv; ++ ++ oldenv = set_exec_env(env); ++ old_ns = current->nsproxy; ++ current->nsproxy = env->ve_ns; ++ ++ /* Phase 2: real checkpointing */ ++ err = cpt_open_dumpfile(ctx); ++ if (err) ++ goto out; ++ ++ cpt_major_hdr_out(ctx); ++ ++ if (!err) ++ err = cpt_dump_veinfo(ctx); ++ if (!err) ++ err = cpt_dump_ubc(ctx); ++ if (!err) ++ err = cpt_dump_files(ctx); ++ if (!err) ++ err = cpt_dump_files_struct(ctx); ++ if (!err) ++ err = cpt_dump_fs_struct(ctx); ++ /* netdevices should be dumped after dumping open files ++ as we need to restore netdevice binding to /dev/net/tun file */ ++ if (!err) ++ err = cpt_dump_ifinfo(ctx); ++ if (!err) ++ err = cpt_dump_namespace(ctx); ++ if (!err) ++ err = cpt_dump_sighand(ctx); ++ if (!err) ++ err = cpt_dump_vm(ctx); ++ if (!err) ++ err = cpt_dump_sysvsem(ctx); ++ if (!err) ++ err = cpt_dump_sysvmsg(ctx); ++ if (!err) ++ err = cpt_dump_tasks(ctx); ++ if (!err) ++ err = cpt_dump_orphaned_sockets(ctx); ++#if defined(CONFIG_VE_IPTABLES) && \ ++ (defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)) ++ if (!err) ++ err = cpt_dump_ip_conntrack(ctx); ++#endif ++ if (!err) { ++ if (virtinfo_notifier_call(VITYPE_SCP, ++ VIRTINFO_SCP_DUMP, ctx) & NOTIFY_FAIL) ++ err = -ECHRNG; ++ } ++ if (!err) ++ err = cpt_dump_utsname(ctx); ++ ++#ifndef CONFIG_IA64 ++ if (!err) ++ err = cpt_dump_vsyscall(ctx); ++#endif ++ ++ if (!err) ++ err = cpt_dump_tail(ctx); ++ ++ err2 = cpt_close_dumpfile(ctx); ++ ++out: ++ current->nsproxy = old_ns; ++ set_exec_env(oldenv); ++out_noenv: ++ up_read(&env->op_sem); ++ put_ve(env); ++ return err ? : err2; ++} ++ ++int cpt_vps_suspend(struct cpt_context *ctx) ++{ ++ struct ve_struct *oldenv, *env; ++ struct nsproxy *old_ns; ++ int err = 0; ++ ++ ctx->kernel_config_flags = test_kernel_config(); ++ cpt_object_init(ctx); ++ ++ if (!ctx->ve_id) { ++ env = get_exec_env(); ++ if (env == get_ve0()) ++ return -EINVAL; ++ wprintk("undefined ve_id\n"); ++ ctx->ve_id = env->veid; ++ get_ve(env); ++ } else { ++ env = get_ve_by_id(ctx->ve_id); ++ if (!env) ++ return -ESRCH; ++ } ++ ++#ifdef CONFIG_VE_IPTABLES ++ ctx->iptables_mask = env->_iptables_modules; ++#endif ++ ctx->features = env->features; ++ ++ down_write(&env->op_sem); ++ err = -ESRCH; ++ if (!env->is_running) ++ goto out_noenv; ++ ++ err = -EBUSY; ++ if (env->is_locked) ++ goto out_noenv; ++ env->is_locked = 1; ++ downgrade_write(&env->op_sem); ++ ++ oldenv = set_exec_env(env); ++ old_ns = current->nsproxy; ++ current->nsproxy = env->ve_ns; ++ ++ /* Phase 0: find and stop all the tasks */ ++ if ((err = vps_stop_tasks(ctx)) != 0) ++ goto out; ++ ++ if ((err = cpt_suspend_network(ctx)) != 0) ++ goto out_wake; ++ ++ /* At the moment all the state is frozen. We do not need to lock ++ * the state, which can be changed only if the tasks are running. ++ */ ++ ++ /* Phase 1: collect task tree */ ++ if ((err = vps_collect_tasks(ctx)) != 0) ++ goto out_wake; ++ ++ /* Phase 1': collect all the resources */ ++ if ((err = cpt_collect(ctx)) != 0) ++ goto out; ++ ++out: ++ current->nsproxy = old_ns; ++ set_exec_env(oldenv); ++ up_read(&env->op_sem); ++ put_ve(env); ++ return err; ++ ++out_noenv: ++ up_write(&env->op_sem); ++ put_ve(env); ++ return err; ++ ++out_wake: ++ read_lock(&tasklist_lock); ++ wake_ve(ctx); ++ read_unlock(&tasklist_lock); ++ goto out; ++} ++ ++static void check_unsupported_netdevices(struct cpt_context *ctx, __u32 *caps) ++{ ++ struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net_device *dev; ++ ++ read_lock(&dev_base_lock); ++ for_each_netdev(net, dev) { ++ if (dev != net->loopback_dev ++#if defined(CONFIG_VE_ETHDEV) || defined(CONFIG_VE_ETHDEV_MODULE) ++ && !(KSYMREF(veth_open) && dev->open == KSYMREF(veth_open)) ++#endif ++#if defined(CONFIG_VE_NETDEV) || defined(CONFIG_VE_NETDEV_MODULE) ++ && dev != get_exec_env()->_venet_dev ++#endif ++#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) ++ && dev->open != tun_net_open ++#endif ++ ) { ++ eprintk_ctx("unsupported netdevice %s\n", dev->name); ++ *caps |= (1<flags & _TIF_IA32)) ++ *caps |= flags & ((1<mm && p->mm->context.vdso) { ++ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) ++ *caps |= flags & (1<mm && p->mm->context.vdso) ++ *caps |= flags & (1<= 0) { ++ switch (check_process_external(p)) { ++ case PIDTYPE_PID: ++ eprintk_ctx("external process %d/%d(%s) inside CT (e.g. vzctl enter or vzctl exec).\n", task_pid_vnr(p), p->pid, p->comm); ++ *caps |= (1<pid, p->comm); ++ *caps |= (1<pid, p->comm); ++ *caps |= (1<pid, p->comm); ++ *caps |= (1<nsproxy) { ++ ns = p->nsproxy->mnt_ns; ++ if (ns) ++ get_mnt_ns(ns); ++ } ++ task_unlock(p); ++ if (ns) { ++ if (ns != current->nsproxy->mnt_ns) { ++ eprintk_ctx("namespaces are not supported: process %d/%d(%s)\n", task_pid_vnr(p), p->pid, p->comm); ++ *caps |= (1<policy != SCHED_NORMAL) { ++ eprintk_ctx("scheduler policy is not supported %d/%d(%s)\n", task_pid_vnr(p), p->pid, p->comm); ++ *caps |= (1<pid, virt_pid(p), p->comm); ++ *caps |= (1<list) { ++ struct vfsmount *mnt = list_entry(p, struct vfsmount, mnt_list); ++ ++ path = __d_path(mnt->mnt_root, mnt, ++ env->fs_root, env->fs_rootmnt, ++ path_buf, PAGE_SIZE); ++ if (IS_ERR(path)) ++ continue; ++ ++ if (check_one_vfsmount(mnt)) { ++ eprintk_ctx("Unsupported filesystem %s\n", mnt->mnt_sb->s_type->name); ++ *caps |= (1<ve_id) ++ return -EINVAL; ++ ++ env = get_ve_by_id(ctx->ve_id); ++ if (env == NULL) ++ return -ESRCH; ++ ++ *caps = flags & (1<nsproxy; ++ current->nsproxy = env->ve_ns; ++ ++ check_unsupported_netdevices(ctx, caps); ++ ++ read_lock(&tasklist_lock); ++ root = find_task_by_vpid(1); ++ if (!root) { ++ read_unlock(&tasklist_lock); ++ eprintk_ctx("cannot find ve init\n"); ++ err = -ESRCH; ++ goto out; ++ } ++ get_task_struct(root); ++ for (p = __first_task_ve(env); p != NULL ; p = __next_task_ve(env, p)) ++ check_one_process(ctx, caps, flags, env, root, p); ++ read_unlock(&tasklist_lock); ++ ++ task_lock(root); ++ n = NULL; ++ if (root->nsproxy) { ++ n = root->nsproxy->mnt_ns; ++ if (n) ++ get_mnt_ns(n); ++ } ++ task_unlock(root); ++ if (n) { ++ char *path_buf; ++ ++ path_buf = (char *) __get_free_page(GFP_KERNEL); ++ if (!path_buf) { ++ put_mnt_ns(n); ++ err = -ENOMEM; ++ goto out_root; ++ } ++ ++ check_unsupported_mounts(ctx, caps, env, n, path_buf); ++ ++ free_page((unsigned long) path_buf); ++ put_mnt_ns(n); ++ } ++ ++ err = 0; ++ ++out_root: ++ put_task_struct(root); ++out: ++ current->nsproxy = old_ns; ++ set_exec_env(old_env); ++ put_ve(env); ++ ++ return err; ++} +Index: kernel/kernel/cpt/cpt_dump.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_dump.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,16 @@ ++int cpt_dump(struct cpt_context *cpt); ++int rst_undump(struct cpt_context *cpt); ++int cpt_suspend(struct cpt_context *cpt); ++int cpt_resume(struct cpt_context *cpt); ++int cpt_kill(struct cpt_context *cpt); ++int rst_clean(struct cpt_context *cpt); ++int rst_resume(struct cpt_context *cpt); ++int rst_kill(struct cpt_context *cpt); ++ ++int cpt_freeze_one(pid_t pid, int freeze); ++int cpt_vps_suspend(struct cpt_context *ctx); ++int vps_rst_undump(struct cpt_context *ctx); ++ ++int cpt_vps_caps(struct cpt_context *ctx, __u32 *caps); ++ ++int cpt_check_unsupported(struct task_struct *tsk, struct cpt_context *ctx); +Index: kernel/kernel/cpt/cpt_epoll.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_epoll.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,115 @@ ++/* ++ * ++ * kernel/cpt/cpt_epoll.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_mm.h" ++#include "cpt_files.h" ++#include "cpt_kernel.h" ++#include "cpt_fsmagic.h" ++#include "cpt_syscalls.h" ++ ++extern struct file_operations eventpoll_fops; ++ ++int cpt_dump_epolldev(cpt_object_t *obj, cpt_context_t *ctx) ++{ ++ int err = 0; ++ struct file *file = obj->o_obj; ++ struct eventpoll *ep; ++ struct rb_node *rbp; ++ struct cpt_epoll_image ei; ++ ++ if (file->f_op != &eventpoll_fops) { ++ eprintk_ctx("bad epoll file\n"); ++ return -EINVAL; ++ } ++ ++ ep = file->private_data; ++ ++ /* eventpoll.c does not protect open /proc/N/fd, silly. ++ * Opener will get an invalid file with uninitialized private_data ++ */ ++ if (unlikely(ep == NULL)) { ++ eprintk_ctx("bad epoll device\n"); ++ return -EINVAL; ++ } ++ ++ cpt_open_object(NULL, ctx); ++ ++ ei.cpt_next = CPT_NULL; ++ ei.cpt_object = CPT_OBJ_EPOLL; ++ ei.cpt_hdrlen = sizeof(ei); ++ ei.cpt_content = CPT_CONTENT_ARRAY; ++ ei.cpt_file = obj->o_pos; ++ ++ ctx->write(&ei, sizeof(ei), ctx); ++ ++ mutex_lock(&epmutex); ++ for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) { ++ loff_t saved_obj; ++ cpt_object_t *tobj; ++ struct cpt_epoll_file_image efi; ++ struct epitem *epi; ++ epi = rb_entry(rbp, struct epitem, rbn); ++ tobj = lookup_cpt_object(CPT_OBJ_FILE, epi->ffd.file, ctx); ++ if (tobj == NULL) { ++ eprintk_ctx("epoll device refers to an external file\n"); ++ err = -EBUSY; ++ break; ++ } ++ cpt_push_object(&saved_obj, ctx); ++ cpt_open_object(NULL, ctx); ++ ++ efi.cpt_next = CPT_NULL; ++ efi.cpt_object = CPT_OBJ_EPOLL_FILE; ++ efi.cpt_hdrlen = sizeof(efi); ++ efi.cpt_content = CPT_CONTENT_VOID; ++ efi.cpt_file = tobj->o_pos; ++ efi.cpt_fd = epi->ffd.fd; ++ efi.cpt_events = epi->event.events; ++ efi.cpt_data = epi->event.data; ++ efi.cpt_revents = 0; ++ efi.cpt_ready = 0; ++ if (!list_empty(&epi->rdllink)) ++ efi.cpt_ready = 1; ++ ++ ctx->write(&efi, sizeof(efi), ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ } ++ mutex_unlock(&epmutex); ++ ++ cpt_close_object(ctx); ++ ++ return err; ++} ++ +Index: kernel/kernel/cpt/cpt_exports.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_exports.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,13 @@ ++#include ++#include ++ ++#include "cpt_obj.h" ++ ++EXPORT_SYMBOL(alloc_cpt_object); ++EXPORT_SYMBOL(intern_cpt_object); ++EXPORT_SYMBOL(insert_cpt_object); ++EXPORT_SYMBOL(__cpt_object_add); ++EXPORT_SYMBOL(cpt_object_add); ++EXPORT_SYMBOL(cpt_object_get); ++EXPORT_SYMBOL(lookup_cpt_object); ++EXPORT_SYMBOL(lookup_cpt_obj_bypos); +Index: kernel/kernel/cpt/cpt_files.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_files.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,1614 @@ ++/* ++ * ++ * kernel/cpt/cpt_files.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_mm.h" ++#include "cpt_files.h" ++#include "cpt_socket.h" ++#include "cpt_kernel.h" ++#include "cpt_fsmagic.h" ++#include "cpt_syscalls.h" ++ ++void cpt_printk_dentry(struct dentry *d, struct vfsmount *mnt) ++{ ++ char *path; ++ unsigned long pg = __get_free_page(GFP_KERNEL); ++ ++ if (!pg) ++ return; ++ ++ path = d_path(d, mnt, (char *)pg, PAGE_SIZE); ++ ++ if (!IS_ERR(path)) ++ eprintk("<%s>", path); ++ free_page(pg); ++} ++ ++int cpt_verify_overmount(char *path, struct dentry *d, struct vfsmount *mnt, ++ cpt_context_t *ctx) ++{ ++ if (path[0] == '/' && !(!IS_ROOT(d) && d_unhashed(d))) { ++ struct nameidata nd; ++ if (path_lookup(path, 0, &nd)) { ++ eprintk_ctx("d_path cannot be looked up %s\n", path); ++ return -EINVAL; ++ } ++ if (nd.dentry != d || nd.mnt != mnt) { ++ eprintk_ctx("d_path is invisible %s\n", path); ++ path_release(&nd); ++ return -EINVAL; ++ } ++ path_release(&nd); ++ } ++ return 0; ++} ++ ++static int ++cpt_replaced(struct dentry * de, struct vfsmount *mnt, cpt_context_t * ctx) ++{ ++ int result = 0; ++ ++#if defined(CONFIG_VZFS_FS) || defined(CONFIG_VZFS_FS_MODULE) ++ char *path; ++ unsigned long pg; ++ struct dentry * renamed_dentry; ++ ++ if (de->d_sb->s_magic != FSMAGIC_VEFS) ++ return 0; ++ if (de->d_inode->i_nlink != 0 || ++ atomic_read(&de->d_inode->i_writecount) > 0) ++ return 0; ++ ++ renamed_dentry = vefs_replaced_dentry(de); ++ if (renamed_dentry == NULL) ++ return 0; ++ ++ pg = __get_free_page(GFP_KERNEL); ++ if (!pg) ++ return 0; ++ ++ path = d_path(de, mnt, (char *)pg, PAGE_SIZE); ++ if (!IS_ERR(path)) { ++ int len; ++ struct nameidata nd; ++ ++ len = pg + PAGE_SIZE - 1 - (unsigned long)path; ++ if (len >= sizeof("(deleted) ") - 1 && ++ !memcmp(path, "(deleted) ", sizeof("(deleted) ") - 1)) { ++ len -= sizeof("(deleted) ") - 1; ++ path += sizeof("(deleted) ") - 1; ++ } ++ ++ if (path_lookup(path, 0, &nd) == 0) { ++ if (mnt == nd.mnt && ++ vefs_is_renamed_dentry(nd.dentry, renamed_dentry)) ++ result = 1; ++ path_release(&nd); ++ } ++ } ++ free_page(pg); ++#endif ++ return result; ++} ++ ++static int cpt_dump_dentry(struct dentry *d, struct vfsmount *mnt, ++ int replaced, cpt_context_t *ctx) ++{ ++ int len; ++ char *path; ++ char *pg = cpt_get_buf(ctx); ++ loff_t saved; ++ ++ path = d_path(d, mnt, pg, PAGE_SIZE); ++ len = PTR_ERR(path); ++ ++ if (IS_ERR(path)) { ++ struct cpt_object_hdr o; ++ char tmp[1]; ++ ++ /* VZ changes d_path() to return EINVAL, when path ++ * is not supposed to be visible inside VE. ++ * This changes behaviour of d_path() comparing ++ * to mainstream kernel, f.e. d_path() fails ++ * on any kind of shared memory. Maybe, there are ++ * another cases, but I am aware only about this one. ++ * So, we just ignore error on shmem mounts and proceed. ++ * Otherwise, checkpointing is prohibited because ++ * of reference to an invisible file. ++ */ ++ if (len != -EINVAL || ++ mnt != get_exec_env()->shmem_mnt) ++ eprintk_ctx("d_path err=%d\n", len); ++ else ++ len = 0; ++ ++ cpt_push_object(&saved, ctx); ++ cpt_open_object(NULL, ctx); ++ o.cpt_next = CPT_NULL; ++ o.cpt_object = CPT_OBJ_NAME; ++ o.cpt_hdrlen = sizeof(o); ++ o.cpt_content = CPT_CONTENT_NAME; ++ tmp[0] = 0; ++ ++ ctx->write(&o, sizeof(o), ctx); ++ ctx->write(tmp, 1, ctx); ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved, ctx); ++ ++ __cpt_release_buf(ctx); ++ return len; ++ } else { ++ struct cpt_object_hdr o; ++ ++ len = pg + PAGE_SIZE - 1 - path; ++ if (replaced && ++ len >= sizeof("(deleted) ") - 1 && ++ !memcmp(path, "(deleted) ", sizeof("(deleted) ") - 1)) { ++ len -= sizeof("(deleted) ") - 1; ++ path += sizeof("(deleted) ") - 1; ++ } ++ o.cpt_next = CPT_NULL; ++ o.cpt_object = CPT_OBJ_NAME; ++ o.cpt_hdrlen = sizeof(o); ++ o.cpt_content = CPT_CONTENT_NAME; ++ path[len] = 0; ++ ++ if (cpt_verify_overmount(path, d, mnt, ctx)) { ++ __cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ ++ cpt_push_object(&saved, ctx); ++ cpt_open_object(NULL, ctx); ++ ctx->write(&o, sizeof(o), ctx); ++ ctx->write(path, len+1, ctx); ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved, ctx); ++ __cpt_release_buf(ctx); ++ } ++ return 0; ++} ++ ++int cpt_dump_string(const char *s, struct cpt_context *ctx) ++{ ++ int len; ++ struct cpt_object_hdr o; ++ ++ cpt_open_object(NULL, ctx); ++ len = strlen(s); ++ o.cpt_next = CPT_NULL; ++ o.cpt_object = CPT_OBJ_NAME; ++ o.cpt_hdrlen = sizeof(o); ++ o.cpt_content = CPT_CONTENT_NAME; ++ ++ ctx->write(&o, sizeof(o), ctx); ++ ctx->write(s, len+1, ctx); ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ return 0; ++} ++ ++static int ++cpt_dump_filename(struct file *file, int replaced, cpt_context_t *ctx) ++{ ++ return cpt_dump_dentry(file->f_dentry, file->f_vfsmnt, replaced, ctx); ++} ++ ++int cpt_dump_inode(struct dentry *d, struct vfsmount *mnt, struct cpt_context *ctx) ++{ ++ int err; ++ struct cpt_inode_image *v = cpt_get_buf(ctx); ++ struct kstat sbuf; ++ ++ v->cpt_next = sizeof(*v); ++ v->cpt_object = CPT_OBJ_INODE; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ if ((err = vfs_getattr(mnt, d, &sbuf)) != 0) { ++ cpt_release_buf(ctx); ++ return err; ++ } ++ ++ v->cpt_dev = d->d_inode->i_sb->s_dev; ++ v->cpt_ino = d->d_inode->i_ino; ++ v->cpt_mode = sbuf.mode; ++ v->cpt_nlink = sbuf.nlink; ++ v->cpt_uid = sbuf.uid; ++ v->cpt_gid = sbuf.gid; ++ v->cpt_rdev = d->d_inode->i_rdev; ++ v->cpt_size = sbuf.size; ++ v->cpt_atime = cpt_timespec_export(&sbuf.atime); ++ v->cpt_mtime = cpt_timespec_export(&sbuf.mtime); ++ v->cpt_ctime = cpt_timespec_export(&sbuf.ctime); ++ v->cpt_blksize = sbuf.blksize; ++ v->cpt_blocks = sbuf.blocks; ++ v->cpt_sb = d->d_inode->i_sb->s_magic; ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ return 0; ++} ++ ++int cpt_collect_files(cpt_context_t * ctx) ++{ ++ int err; ++ cpt_object_t *obj; ++ int index = 0; ++ ++ /* Collect process fd sets */ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ struct task_struct *tsk = obj->o_obj; ++ if (tsk->files && cpt_object_add(CPT_OBJ_FILES, tsk->files, ctx) == NULL) ++ return -ENOMEM; ++ } ++ ++ /* Collect files from fd sets */ ++ for_each_object(obj, CPT_OBJ_FILES) { ++ int fd; ++ struct files_struct *f = obj->o_obj; ++ ++ cpt_obj_setindex(obj, index++, ctx); ++ ++ if (obj->o_count != atomic_read(&f->count)) { ++ eprintk_ctx("files_struct is referenced outside %d %d\n", obj->o_count, atomic_read(&f->count)); ++ return -EBUSY; ++ } ++ ++ for (fd = 0; fd < f->fdt->max_fds; fd++) { ++ struct file *file = fcheck_files(f, fd); ++ if (file && cpt_object_add(CPT_OBJ_FILE, file, ctx) == NULL) ++ return -ENOMEM; ++ } ++ } ++ ++ /* Collect files queued by AF_UNIX sockets. */ ++ if ((err = cpt_collect_passedfds(ctx)) < 0) ++ return err; ++ ++ /* OK. At this point we should count all the references. */ ++ for_each_object(obj, CPT_OBJ_FILE) { ++ struct file *file = obj->o_obj; ++ struct file *parent; ++ cpt_object_t *ino_obj; ++ ++ if (obj->o_count != atomic_read(&file->f_count)) { ++ eprintk_ctx("file struct is referenced outside %d %d\n", obj->o_count, atomic_read(&file->f_count)); ++ cpt_printk_dentry(file->f_dentry, file->f_vfsmnt); ++ return -EBUSY; ++ } ++ ++ switch (file->f_dentry->d_inode->i_sb->s_magic) { ++ case FSMAGIC_FUTEX: ++ case FSMAGIC_MQUEUE: ++ case FSMAGIC_BDEV: ++#ifndef CONFIG_INOTIFY_USER ++ case FSMAGIC_INOTIFY: ++#endif ++ eprintk_ctx("file on unsupported FS: magic %08lx\n", file->f_dentry->d_inode->i_sb->s_magic); ++ return -EBUSY; ++ } ++ ++ /* Collect inode. It is necessary mostly to resolve deleted ++ * hard links. */ ++ ino_obj = cpt_object_add(CPT_OBJ_INODE, file->f_dentry->d_inode, ctx); ++ if (ino_obj == NULL) ++ return -ENOMEM; ++ ++ parent = ino_obj->o_parent; ++ if (!parent || (!IS_ROOT(parent->f_dentry) && d_unhashed(parent->f_dentry))) ++ ino_obj->o_parent = file; ++ ++ if (S_ISCHR(file->f_dentry->d_inode->i_mode)) { ++ int maj = imajor(file->f_dentry->d_inode); ++ if (maj == PTY_MASTER_MAJOR || ++ (maj >= UNIX98_PTY_MASTER_MAJOR && ++ maj < UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) || ++ maj == PTY_SLAVE_MAJOR || ++ maj == UNIX98_PTY_SLAVE_MAJOR || ++ maj == TTYAUX_MAJOR) { ++ err = cpt_collect_tty(file, ctx); ++ if (err) ++ return err; ++ } ++ } ++ ++ if (S_ISSOCK(file->f_dentry->d_inode->i_mode)) { ++ err = cpt_collect_socket(file, ctx); ++ if (err) ++ return err; ++ } ++ } ++ ++ err = cpt_index_sockets(ctx); ++ ++ return err; ++} ++ ++/* /dev/ptmx is special, all the files share one inode, but real tty backend ++ * is attached via file->private_data. ++ */ ++ ++static inline int is_cloning_inode(struct inode *ino) ++{ ++ return S_ISCHR(ino->i_mode) && ++ ino->i_rdev == MKDEV(TTYAUX_MAJOR,2); ++} ++ ++static int dump_one_flock(struct file_lock *fl, int owner, struct cpt_context *ctx) ++{ ++ pid_t pid; ++ struct cpt_flock_image *v = cpt_get_buf(ctx); ++ ++ v->cpt_next = sizeof(*v); ++ v->cpt_object = CPT_OBJ_FLOCK; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_VOID; ++ ++ v->cpt_owner = owner; ++ ++ pid = fl->fl_pid; ++ if (pid) { ++ pid = pid_to_vpid(fl->fl_pid); ++ if (pid == -1) { ++ if (!(fl->fl_flags&FL_FLOCK)) { ++ eprintk_ctx("posix lock from another container?\n"); ++ cpt_release_buf(ctx); ++ return -EBUSY; ++ } ++ pid = 0; ++ } ++ } ++ ++ v->cpt_pid = pid; ++ v->cpt_start = fl->fl_start; ++ v->cpt_end = fl->fl_end; ++ v->cpt_flags = fl->fl_flags; ++ v->cpt_type = fl->fl_type; ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ return 0; ++} ++ ++ ++int cpt_dump_flock(struct file *file, struct cpt_context *ctx) ++{ ++ int err = 0; ++ struct file_lock *fl; ++ ++ lock_kernel(); ++ for (fl = file->f_dentry->d_inode->i_flock; ++ fl; fl = fl->fl_next) { ++ if (file != fl->fl_file) ++ continue; ++ if (fl->fl_flags & FL_LEASE) { ++ eprintk_ctx("lease lock is not supported\n"); ++ err = -EINVAL; ++ break; ++ } ++ if (fl->fl_flags & FL_POSIX) { ++ cpt_object_t *obj; ++ obj = lookup_cpt_object(CPT_OBJ_FILES, fl->fl_owner, ctx); ++ if (obj) { ++ dump_one_flock(fl, obj->o_index, ctx); ++ continue; ++ } else { ++ eprintk_ctx("unknown lock owner %p\n", fl->fl_owner); ++ err = -EINVAL; ++ } ++ } ++ if (fl->fl_flags & FL_FLOCK) { ++ dump_one_flock(fl, -1, ctx); ++ continue; ++ } ++ } ++ unlock_kernel(); ++ return err; ++} ++ ++static int dump_one_file(cpt_object_t *obj, struct file *file, cpt_context_t *ctx) ++{ ++ int err = 0; ++ cpt_object_t *iobj; ++ struct cpt_file_image *v = cpt_get_buf(ctx); ++ struct kstat sbuf; ++ int replaced = 0; ++ ++ cpt_open_object(obj, ctx); ++ ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_FILE; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ v->cpt_flags = file->f_flags; ++ v->cpt_mode = file->f_mode; ++ v->cpt_pos = file->f_pos; ++ v->cpt_uid = file->f_uid; ++ v->cpt_gid = file->f_gid; ++ ++ vfs_getattr(file->f_vfsmnt, file->f_dentry, &sbuf); ++ ++ v->cpt_i_mode = sbuf.mode; ++ v->cpt_lflags = 0; ++ if (IS_ROOT(file->f_dentry)) ++ v->cpt_lflags |= CPT_DENTRY_ROOT; ++ else if (d_unhashed(file->f_dentry)) { ++ if (cpt_replaced(file->f_dentry, file->f_vfsmnt, ctx)) { ++ v->cpt_lflags |= CPT_DENTRY_REPLACED; ++ replaced = 1; ++ } else { ++ v->cpt_lflags |= CPT_DENTRY_DELETED; ++ } ++ } ++ if (is_cloning_inode(file->f_dentry->d_inode)) ++ v->cpt_lflags |= CPT_DENTRY_CLONING; ++ if (file->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_PROC) ++ v->cpt_lflags |= CPT_DENTRY_PROC; ++ v->cpt_inode = CPT_NULL; ++ if (!(v->cpt_lflags & CPT_DENTRY_REPLACED)) { ++ iobj = lookup_cpt_object(CPT_OBJ_INODE, file->f_dentry->d_inode, ctx); ++ if (iobj) ++ v->cpt_inode = iobj->o_pos; ++ } ++ v->cpt_priv = CPT_NULL; ++ v->cpt_fown_fd = -1; ++ if (S_ISCHR(v->cpt_i_mode)) { ++ iobj = lookup_cpt_object(CPT_OBJ_TTY, file->private_data, ctx); ++ if (iobj) { ++ v->cpt_priv = iobj->o_pos; ++ if (file->f_flags&FASYNC) ++ v->cpt_fown_fd = cpt_tty_fasync(file, ctx); ++ } ++#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) ++ if (file->f_op && file->f_op->open == tun_chr_open) ++ v->cpt_lflags |= CPT_DENTRY_TUNTAP; ++#endif ++ } ++ if (S_ISSOCK(v->cpt_i_mode)) { ++ if (obj->o_index < 0) { ++ eprintk_ctx("BUG: no socket index\n"); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ v->cpt_priv = obj->o_index; ++ if (file->f_flags&FASYNC) ++ v->cpt_fown_fd = cpt_socket_fasync(file, ctx); ++ } ++ if (file->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_EPOLL) { ++ v->cpt_priv = file->f_dentry->d_inode->i_ino; ++ v->cpt_lflags |= CPT_DENTRY_EPOLL; ++ } ++ if (file->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_INOTIFY) { ++ v->cpt_priv = file->f_dentry->d_inode->i_ino; ++ v->cpt_lflags |= CPT_DENTRY_INOTIFY; ++ } ++ ++ v->cpt_fown_pid = (file->f_owner.pid == NULL ? ++ CPT_FOWN_STRAY_PID : pid_vnr(file->f_owner.pid)); ++ v->cpt_fown_uid = file->f_owner.uid; ++ v->cpt_fown_euid = file->f_owner.euid; ++ v->cpt_fown_signo = file->f_owner.signum; ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++ if (!S_ISSOCK(v->cpt_i_mode)) { ++ err = cpt_dump_filename(file, replaced, ctx); ++ if (err) ++ return err; ++ if ((file->f_mode & FMODE_WRITE) && ++ file->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_VEFS) ++ vefs_track_notify(file->f_dentry, 1); ++ } ++ ++ if (file->f_dentry->d_inode->i_flock) ++ err = cpt_dump_flock(file, ctx); ++ ++ cpt_close_object(ctx); ++ ++ return err; ++} ++ ++/* About this weird function... Crappy code dealing with SYSV shared memory ++ * defines TMPFS inode and file with f_op doing only mmap. So... ++ * Maybe, this is wrong and leaks something. It is clear access to ++ * SYSV shmem via mmap is quite unusual and impossible from user space. ++ */ ++static int dump_content_shm(struct file *file, struct cpt_context *ctx) ++{ ++ struct cpt_obj_bits *v; ++ loff_t saved_pos; ++ unsigned long addr; ++ ++ addr = do_mmap_pgoff(file, 0, file->f_dentry->d_inode->i_size, ++ PROT_READ, MAP_SHARED, 0); ++ if (IS_ERR((void*)addr)) ++ return PTR_ERR((void*)addr); ++ ++ cpt_push_object(&saved_pos, ctx); ++ cpt_open_object(NULL, ctx); ++ v = cpt_get_buf(ctx); ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_BITS; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_DATA; ++ v->cpt_size = file->f_dentry->d_inode->i_size; ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ctx->write((void*)addr, file->f_dentry->d_inode->i_size, ctx); ++ ctx->align(ctx); ++ do_munmap(current->mm, addr, file->f_dentry->d_inode->i_size); ++ ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_pos, ctx); ++ return 0; ++} ++ ++static int data_is_zero(char *addr, int len) ++{ ++ int i; ++ unsigned long zerolong = 0; ++ ++ for (i=0; if_op == NULL) ++ return -EINVAL; ++ ++ do_read = file->f_op->read; ++ if (file->f_op == &shmem_file_operations) { ++ do_read = file->f_dentry->d_inode->i_fop->read; ++ cpt_dump_content_sysvshm(file, ctx); ++ if (!do_read) { ++ wprintk_ctx("TMPFS is not configured?\n"); ++ return dump_content_shm(file, ctx); ++ } ++ } ++ ++ if (!(file->f_mode & FMODE_READ) || ++ (file->f_flags & O_DIRECT)) { ++ file = dentry_open(dget(file->f_dentry), ++ mntget(file->f_vfsmnt), O_RDONLY); ++ if (IS_ERR(file)) { ++ cpt_printk_dentry(file->f_dentry, file->f_vfsmnt); ++ eprintk_ctx("cannot reopen file for read %ld\n", PTR_ERR(file)); ++ return PTR_ERR(file); ++ } ++ } else { ++ atomic_inc(&file->f_count); ++ } ++ ++ for (;;) { ++ mm_segment_t oldfs; ++ int err; ++ ++ (void)cpt_get_buf(ctx); ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ err = do_read(file, ctx->tmpbuf, PAGE_SIZE, &pos); ++ set_fs(oldfs); ++ if (err < 0) { ++ eprintk_ctx("dump_content_regular: do_read: %d", err); ++ fput(file); ++ __cpt_release_buf(ctx); ++ return err; ++ } ++ if (err == 0) { ++ __cpt_release_buf(ctx); ++ break; ++ } ++ if (data_is_zero(ctx->tmpbuf, err)) { ++ if (obj_opened != CPT_NULL) { ++ ctx->pwrite(&pgb.cpt_end, 8, ctx, obj_opened + offsetof(struct cpt_page_block, cpt_end)); ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_pos, ctx); ++ obj_opened = CPT_NULL; ++ } ++ } else { ++ if (obj_opened == CPT_NULL) { ++ cpt_push_object(&saved_pos, ctx); ++ cpt_open_object(NULL, ctx); ++ obj_opened = ctx->file->f_pos; ++ pgb.cpt_next = CPT_NULL; ++ pgb.cpt_object = CPT_OBJ_PAGES; ++ pgb.cpt_hdrlen = sizeof(pgb); ++ pgb.cpt_content = CPT_CONTENT_DATA; ++ pgb.cpt_start = pos - err; ++ pgb.cpt_end = pgb.cpt_start; ++ ctx->write(&pgb, sizeof(pgb), ctx); ++ } ++ ctx->write(ctx->tmpbuf, err, ctx); ++ pgb.cpt_end += err; ++ } ++ __cpt_release_buf(ctx); ++ } ++ ++ fput(file); ++ ++ if (obj_opened != CPT_NULL) { ++ ctx->pwrite(&pgb.cpt_end, 8, ctx, obj_opened + offsetof(struct cpt_page_block, cpt_end)); ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_pos, ctx); ++ obj_opened = CPT_NULL; ++ } ++ return 0; ++} ++ ++ ++static int dump_content_chrdev(struct file *file, struct cpt_context *ctx) ++{ ++ struct inode *ino = file->f_dentry->d_inode; ++ int maj; ++ ++ maj = imajor(ino); ++ if (maj == MEM_MAJOR) { ++ /* Well, OK. */ ++ return 0; ++ } ++ if (maj == PTY_MASTER_MAJOR || ++ (maj >= UNIX98_PTY_MASTER_MAJOR && ++ maj < UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) || ++ maj == PTY_SLAVE_MAJOR || ++ maj == UNIX98_PTY_SLAVE_MAJOR || ++ maj == TTYAUX_MAJOR) { ++ return cpt_dump_content_tty(file, ctx); ++ } ++#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) ++ if (file->f_op && file->f_op->open == tun_chr_open) ++ return 0; ++#endif ++ eprintk_ctx("unsupported chrdev %d/%d\n", maj, iminor(ino)); ++ return -EINVAL; ++} ++ ++static int dump_content_blkdev(struct file *file, struct cpt_context *ctx) ++{ ++ struct inode *ino = file->f_dentry->d_inode; ++ ++ /* We are not going to transfer them. */ ++ eprintk_ctx("unsupported blkdev %d/%d\n", imajor(ino), iminor(ino)); ++ return -EINVAL; ++} ++ ++static int dump_content_fifo(struct file *file, struct cpt_context *ctx) ++{ ++ struct inode *ino = file->f_dentry->d_inode; ++ cpt_object_t *obj; ++ loff_t saved_pos; ++ int readers; ++ int writers; ++ int anon = 0; ++ ++ mutex_lock(&ino->i_mutex); ++ readers = ino->i_pipe->readers; ++ writers = ino->i_pipe->writers; ++ for_each_object(obj, CPT_OBJ_FILE) { ++ struct file *file1 = obj->o_obj; ++ if (file1->f_dentry->d_inode == ino) { ++ if (file1->f_mode & FMODE_READ) ++ readers--; ++ if (file1->f_mode & FMODE_WRITE) ++ writers--; ++ } ++ } ++ mutex_unlock(&ino->i_mutex); ++ if (readers || writers) { ++ struct dentry *dr = file->f_dentry->d_sb->s_root; ++ if (dr->d_name.len == 7 && memcmp(dr->d_name.name,"pipefs:",7) == 0) ++ anon = 1; ++ ++ if (anon) { ++ eprintk_ctx("pipe has %d/%d external readers/writers\n", readers, writers); ++ return -EBUSY; ++ } ++ /* If fifo has external readers/writers, we are in troubles. ++ * If the buffer is not empty, we must move its content. ++ * But if the fifo is owned by a service, we cannot do ++ * this. See? ++ * ++ * For now we assume, that if fifo is opened by another ++ * process, we do not own it and, hence, migrate without ++ * data. ++ */ ++ return 0; ++ } ++ ++ /* OK, we must save fifo state. No semaphores required. */ ++ ++ if (ino->i_pipe->nrbufs) { ++ struct cpt_obj_bits *v = cpt_get_buf(ctx); ++ struct pipe_inode_info *info; ++ int count, buf, nrbufs; ++ ++ mutex_lock(&ino->i_mutex); ++ info = ino->i_pipe; ++ count = 0; ++ buf = info->curbuf; ++ nrbufs = info->nrbufs; ++ while (--nrbufs >= 0) { ++ if (!info->bufs[buf].ops->can_merge) { ++ mutex_unlock(&ino->i_mutex); ++ eprintk_ctx("unknown format of pipe buffer\n"); ++ return -EINVAL; ++ } ++ count += info->bufs[buf].len; ++ buf = (buf+1) & (PIPE_BUFFERS-1); ++ } ++ ++ if (!count) { ++ mutex_unlock(&ino->i_mutex); ++ return 0; ++ } ++ ++ cpt_push_object(&saved_pos, ctx); ++ cpt_open_object(NULL, ctx); ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_BITS; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_DATA; ++ v->cpt_size = count; ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++ count = 0; ++ buf = info->curbuf; ++ nrbufs = info->nrbufs; ++ while (--nrbufs >= 0) { ++ struct pipe_buffer *b = info->bufs + buf; ++ /* need to ->pin first? */ ++ void * addr = b->ops->map(info, b, 0); ++ ctx->write(addr + b->offset, b->len, ctx); ++ b->ops->unmap(info, b, addr); ++ buf = (buf+1) & (PIPE_BUFFERS-1); ++ } ++ ++ mutex_unlock(&ino->i_mutex); ++ ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_pos, ctx); ++ } ++ ++ return 0; ++} ++ ++static int dump_content_socket(struct file *file, struct cpt_context *ctx) ++{ ++ return 0; ++} ++ ++struct cpt_dirent { ++ unsigned long ino; ++ char *name; ++ int namelen; ++ int found; ++}; ++ ++static int cpt_filldir(void * __buf, const char * name, int namelen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct cpt_dirent * dirent = __buf; ++ ++ if ((ino == dirent->ino) && (namelen < PAGE_SIZE - 1)) { ++ memcpy(dirent->name, name, namelen); ++ dirent->name[namelen] = '\0'; ++ dirent->namelen = namelen; ++ dirent->found = 1; ++ return 1; ++ } ++ return 0; ++} ++ ++static int find_linked_dentry(struct dentry *d, struct vfsmount *mnt, ++ struct inode *ino, struct cpt_context *ctx) ++{ ++ int err = -EBUSY; ++ struct file *f = NULL; ++ struct cpt_dirent entry; ++ struct dentry *de, *found = NULL; ++ ++ dprintk_ctx("deleted reference to existing inode, try to find file\n"); ++ /* 1. Try to find not deleted dentry in ino->i_dentry list */ ++ spin_lock(&dcache_lock); ++ list_for_each_entry(de, &ino->i_dentry, d_alias) { ++ if (!IS_ROOT(de) && d_unhashed(de)) ++ continue; ++ found = de; ++ dget_locked(found); ++ break; ++ } ++ spin_unlock(&dcache_lock); ++ if (found) { ++ err = cpt_dump_dentry(found, mnt, 0, ctx); ++ dput(found); ++ if (!err) { ++ dprintk_ctx("dentry found in aliases\n"); ++ return 0; ++ } ++ } ++ ++ /* 2. Try to find file in current dir */ ++ de = dget_parent(d); ++ if (!de) ++ return -EINVAL; ++ ++ mntget(mnt); ++ f = dentry_open(de, mnt, O_RDONLY); ++ if (IS_ERR(f)) ++ return PTR_ERR(f); ++ ++ entry.ino = ino->i_ino; ++ entry.name = cpt_get_buf(ctx); ++ entry.found = 0; ++ err = vfs_readdir(f, cpt_filldir, &entry); ++ if (err || !entry.found) { ++ err = err ? err : -ENOENT; ++ goto err_readdir; ++ } ++ ++ found = lookup_one_len(entry.name, de, entry.namelen); ++ if (IS_ERR(found)) { ++ err = PTR_ERR(found); ++ goto err_readdir; ++ } ++ ++ err = -ENOENT; ++ if (found->d_inode != ino) ++ goto err_lookup; ++ ++ dprintk_ctx("dentry found in dir\n"); ++ __cpt_release_buf(ctx); ++ err = cpt_dump_dentry(found, mnt, 0, ctx); ++ ++err_lookup: ++ dput(found); ++err_readdir: ++ fput(f); ++ __cpt_release_buf(ctx); ++ return err; ++} ++ ++static int dump_one_inode(struct file *file, struct dentry *d, ++ struct vfsmount *mnt, struct cpt_context *ctx) ++{ ++ int err = 0; ++ struct inode *ino = d->d_inode; ++ cpt_object_t *iobj; ++ int dump_it = 0; ++ ++ iobj = lookup_cpt_object(CPT_OBJ_INODE, ino, ctx); ++ if (!iobj) ++ return -EINVAL; ++ ++ if (iobj->o_pos >= 0) ++ return 0; ++ ++ if ((!IS_ROOT(d) && d_unhashed(d)) && ++ !cpt_replaced(d, mnt, ctx)) ++ dump_it = 1; ++ if (!S_ISREG(ino->i_mode) && !S_ISDIR(ino->i_mode)) { ++ /* One more bug in epoll: invalid inode mode. ++ * What a load of crap... ++ */ ++ if (ino->i_sb->s_magic == FSMAGIC_EPOLL && ++ (ino->i_mode & S_IFMT) == 0) ++ return 0; ++ dump_it = 1; ++ } ++ ++ if (!dump_it) ++ return 0; ++ ++ cpt_open_object(iobj, ctx); ++ cpt_dump_inode(d, mnt, ctx); ++ ++ if (!IS_ROOT(d) && d_unhashed(d)) { ++ struct file *parent; ++ parent = iobj->o_parent; ++ if (!parent || ++ (!IS_ROOT(parent->f_dentry) && d_unhashed(parent->f_dentry))) { ++ /* Inode is not deleted, but it does not ++ * have references from inside checkpointed ++ * process group. */ ++ if (ino->i_nlink != 0) { ++ err = find_linked_dentry(d, mnt, ino, ctx); ++ if (err) { ++ eprintk_ctx("deleted reference to existing inode, checkpointing is impossible: %d\n", err); ++ return -EBUSY; ++ } ++ if (S_ISREG(ino->i_mode) || S_ISDIR(ino->i_mode)) ++ dump_it = 0; ++ } ++ } else { ++ /* Refer to _another_ file name. */ ++ err = cpt_dump_filename(parent, 0, ctx); ++ if (err) ++ return err; ++ if (S_ISREG(ino->i_mode) || S_ISDIR(ino->i_mode)) ++ dump_it = 0; ++ } ++ } ++ if (dump_it) { ++ if (S_ISREG(ino->i_mode)) { ++ if ((err = dump_content_regular(file, ctx)) != 0) { ++ eprintk_ctx("dump_content_regular "); ++ cpt_printk_dentry(d, mnt); ++ } ++ } else if (S_ISDIR(ino->i_mode)) { ++ /* We cannot do anything. The directory should be ++ * empty, so it is not a big deal. ++ */ ++ } else if (S_ISCHR(ino->i_mode)) { ++ err = dump_content_chrdev(file, ctx); ++ } else if (S_ISBLK(ino->i_mode)) { ++ err = dump_content_blkdev(file, ctx); ++ } else if (S_ISFIFO(ino->i_mode)) { ++ err = dump_content_fifo(file, ctx); ++ } else if (S_ISSOCK(ino->i_mode)) { ++ err = dump_content_socket(file, ctx); ++ } else { ++ eprintk_ctx("unknown inode mode %o, magic 0x%lx\n", ino->i_mode & S_IFMT, ino->i_sb->s_magic); ++ err = -EINVAL; ++ } ++ } ++ cpt_close_object(ctx); ++ ++ return err; ++} ++ ++int cpt_dump_files(struct cpt_context *ctx) ++{ ++ int epoll_nr, inotify_nr; ++ cpt_object_t *obj; ++ ++ cpt_open_section(ctx, CPT_SECT_TTY); ++ for_each_object(obj, CPT_OBJ_TTY) { ++ int err; ++ ++ if ((err = cpt_dump_tty(obj, ctx)) != 0) ++ return err; ++ } ++ cpt_close_section(ctx); ++ ++ cpt_open_section(ctx, CPT_SECT_INODE); ++ for_each_object(obj, CPT_OBJ_FILE) { ++ struct file *file = obj->o_obj; ++ int err; ++ ++ if ((err = dump_one_inode(file, file->f_dentry, ++ file->f_vfsmnt, ctx)) != 0) ++ return err; ++ } ++ for_each_object(obj, CPT_OBJ_FS) { ++ struct fs_struct *fs = obj->o_obj; ++ int err; ++ ++ if (fs->root && ++ (err = dump_one_inode(NULL, fs->root, fs->rootmnt, ctx)) != 0) ++ return err; ++ if (fs->pwd && ++ (err = dump_one_inode(NULL, fs->pwd, fs->pwdmnt, ctx)) != 0) ++ return err; ++ if (fs->altroot && ++ (err = dump_one_inode(NULL, fs->altroot, fs->altrootmnt, ctx)) != 0) ++ return err; ++ } ++ cpt_close_section(ctx); ++ ++ epoll_nr = 0; ++ inotify_nr = 0; ++ cpt_open_section(ctx, CPT_SECT_FILES); ++ for_each_object(obj, CPT_OBJ_FILE) { ++ struct file *file = obj->o_obj; ++ int err; ++ ++ if ((err = dump_one_file(obj, file, ctx)) != 0) ++ return err; ++ if (file->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_EPOLL) ++ epoll_nr++; ++ if (file->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_INOTIFY) ++ inotify_nr++; ++ } ++ cpt_close_section(ctx); ++ ++ if (epoll_nr) { ++ cpt_open_section(ctx, CPT_SECT_EPOLL); ++ for_each_object(obj, CPT_OBJ_FILE) { ++ struct file *file = obj->o_obj; ++ if (file->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_EPOLL) { ++ int err; ++ if ((err = cpt_dump_epolldev(obj, ctx)) != 0) ++ return err; ++ } ++ } ++ cpt_close_section(ctx); ++ } ++ ++ if (inotify_nr) { ++ cpt_open_section(ctx, CPT_SECT_INOTIFY); ++ for_each_object(obj, CPT_OBJ_FILE) { ++ struct file *file = obj->o_obj; ++ if (file->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_INOTIFY) { ++ int err = -EINVAL; ++#ifdef CONFIG_INOTIFY_USER ++ if ((err = cpt_dump_inotify(obj, ctx)) != 0) ++#endif ++ return err; ++ } ++ } ++ cpt_close_section(ctx); ++ } ++ ++ cpt_open_section(ctx, CPT_SECT_SOCKET); ++ for_each_object(obj, CPT_OBJ_SOCKET) { ++ int err; ++ ++ if ((err = cpt_dump_socket(obj, obj->o_obj, obj->o_index, -1, ctx)) != 0) ++ return err; ++ } ++ cpt_close_section(ctx); ++ ++ return 0; ++} ++ ++static int dump_filedesc(int fd, struct file *file, ++ struct files_struct *f, struct cpt_context *ctx) ++{ ++ struct cpt_fd_image *v = cpt_get_buf(ctx); ++ cpt_object_t *obj; ++ ++ cpt_open_object(NULL, ctx); ++ ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_FILEDESC; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_VOID; ++ ++ v->cpt_fd = fd; ++ obj = lookup_cpt_object(CPT_OBJ_FILE, file, ctx); ++ if (!obj) BUG(); ++ v->cpt_file = obj->o_pos; ++ v->cpt_flags = 0; ++ if (FD_ISSET(fd, f->fdt->close_on_exec)) ++ v->cpt_flags = CPT_FD_FLAG_CLOSEEXEC; ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ cpt_close_object(ctx); ++ ++ return 0; ++} ++ ++static int dump_one_file_struct(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ struct files_struct *f = obj->o_obj; ++ struct cpt_files_struct_image *v = cpt_get_buf(ctx); ++ int fd; ++ loff_t saved_obj; ++ ++ cpt_open_object(obj, ctx); ++ ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_FILES; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ v->cpt_index = obj->o_index; ++ v->cpt_max_fds = f->fdt->max_fds; ++ v->cpt_next_fd = f->next_fd; ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++ cpt_push_object(&saved_obj, ctx); ++ for (fd = 0; fd < f->fdt->max_fds; fd++) { ++ struct file *file = fcheck_files(f, fd); ++ if (file) ++ dump_filedesc(fd, file, f, ctx); ++ } ++ cpt_pop_object(&saved_obj, ctx); ++ ++ cpt_close_object(ctx); ++ ++ return 0; ++} ++ ++int cpt_dump_files_struct(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ cpt_open_section(ctx, CPT_SECT_FILES_STRUCT); ++ ++ for_each_object(obj, CPT_OBJ_FILES) { ++ int err; ++ ++ if ((err = dump_one_file_struct(obj, ctx)) != 0) ++ return err; ++ } ++ ++ cpt_close_section(ctx); ++ return 0; ++} ++ ++int cpt_collect_fs(cpt_context_t * ctx) ++{ ++ cpt_object_t *obj; ++ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ struct task_struct *tsk = obj->o_obj; ++ if (tsk->fs) { ++ if (cpt_object_add(CPT_OBJ_FS, tsk->fs, ctx) == NULL) ++ return -ENOMEM; ++ if (tsk->fs->pwd && ++ cpt_object_add(CPT_OBJ_INODE, tsk->fs->pwd->d_inode, ctx) == NULL) ++ return -ENOMEM; ++ if (tsk->fs->root && ++ cpt_object_add(CPT_OBJ_INODE, tsk->fs->root->d_inode, ctx) == NULL) ++ return -ENOMEM; ++ if (tsk->fs->altroot && ++ cpt_object_add(CPT_OBJ_INODE, tsk->fs->altroot->d_inode, ctx) == NULL) ++ return -ENOMEM; ++ } ++ } ++ return 0; ++} ++ ++int cpt_dump_dir(struct dentry *d, struct vfsmount *mnt, struct cpt_context *ctx) ++{ ++ struct file file; ++ ++ memset(&file, 0, sizeof(file)); ++ ++ file.f_dentry = d; ++ file.f_vfsmnt = mnt; ++ file.f_mode = FMODE_READ|FMODE_PREAD|FMODE_LSEEK; ++ return dump_one_file(NULL, &file, ctx); ++} ++ ++static int dump_one_fs(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ struct fs_struct *fs = obj->o_obj; ++ struct cpt_fs_struct_image *v = cpt_get_buf(ctx); ++ loff_t saved_obj; ++ int err; ++ ++ cpt_open_object(obj, ctx); ++ ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_FS; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ v->cpt_umask = fs->umask; ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++ cpt_push_object(&saved_obj, ctx); ++ err = cpt_dump_dir(fs->root, fs->rootmnt, ctx); ++ if (!err) ++ err = cpt_dump_dir(fs->pwd, fs->pwdmnt, ctx); ++ if (!err && fs->altroot) ++ err = cpt_dump_dir(fs->altroot, fs->altrootmnt, ctx); ++ ++ cpt_pop_object(&saved_obj, ctx); ++ ++ cpt_close_object(ctx); ++ ++ return err; ++} ++ ++int cpt_dump_fs_struct(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ cpt_open_section(ctx, CPT_SECT_FS); ++ ++ for_each_object(obj, CPT_OBJ_FS) { ++ int err; ++ ++ if ((err = dump_one_fs(obj, ctx)) != 0) ++ return err; ++ } ++ ++ cpt_close_section(ctx); ++ return 0; ++} ++ ++static int check_one_namespace(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ int err = 0; ++ struct mnt_namespace *n = obj->o_obj; ++ struct list_head *p; ++ char *path_buf, *path; ++ ++ path_buf = (char *) __get_free_page(GFP_KERNEL); ++ if (!path_buf) ++ return -ENOMEM; ++ ++ down_read(&namespace_sem); ++ list_for_each(p, &n->list) { ++ struct vfsmount *mnt = list_entry(p, struct vfsmount, mnt_list); ++ ++ path = d_path(mnt->mnt_root, mnt, path_buf, PAGE_SIZE); ++ if (IS_ERR(path)) ++ continue; ++ ++ if (check_one_vfsmount(mnt)) { ++ eprintk_ctx("unsupported fs type %s\n", mnt->mnt_sb->s_type->name); ++ err = -EINVAL; ++ break; ++ } ++ } ++ up_read(&namespace_sem); ++ ++ free_page((unsigned long) path_buf); ++ ++ return err; ++} ++ ++int cpt_collect_namespace(cpt_context_t * ctx) ++{ ++ cpt_object_t *obj; ++ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ struct task_struct *tsk = obj->o_obj; ++ if (tsk->nsproxy && tsk->nsproxy->mnt_ns && ++ cpt_object_add(CPT_OBJ_NAMESPACE, ++ tsk->nsproxy->mnt_ns, ctx) == NULL) ++ return -ENOMEM; ++ } ++ ++ for_each_object(obj, CPT_OBJ_NAMESPACE) { ++ int err; ++ if ((err = check_one_namespace(obj, ctx)) != 0) ++ return err; ++ } ++ ++ return 0; ++} ++ ++struct args_t ++{ ++ int* pfd; ++ char* path; ++}; ++ ++static int dumptmpfs(void *arg) ++{ ++ int i; ++ struct args_t *args = arg; ++ int *pfd = args->pfd; ++ int fd0, fd2; ++ char *path = args->path; ++ char *argv[] = { "tar", "-c", "-S", "--numeric-owner", path, NULL }; ++ ++ i = real_env_create(VEID(get_exec_env()), VE_ENTER|VE_SKIPLOCK, 2, NULL, 0); ++ if (i < 0) { ++ eprintk("cannot enter ve to dump tmpfs\n"); ++ module_put(THIS_MODULE); ++ return 255 << 8; ++ } ++ ++ if (pfd[1] != 1) ++ sc_dup2(pfd[1], 1); ++ set_fs(KERNEL_DS); ++ fd0 = sc_open("/dev/null", O_RDONLY, 0); ++ fd2 = sc_open("/dev/null", O_WRONLY, 0); ++ if (fd0 < 0 || fd2 < 0) { ++ eprintk("can not open /dev/null for tar: %d %d\n", fd0, fd2); ++ module_put(THIS_MODULE); ++ return 255 << 8; ++ } ++ if (fd0 != 0) ++ sc_dup2(fd0, 0); ++ if (fd2 != 2) ++ sc_dup2(fd2, 2); ++ ++ for (i = 3; i < current->files->fdt->max_fds; i++) { ++ sc_close(i); ++ } ++ ++ module_put(THIS_MODULE); ++ ++ i = sc_execve("/bin/tar", argv, NULL); ++ eprintk("failed to exec /bin/tar: %d\n", i); ++ return 255 << 8; ++} ++ ++static int cpt_dump_tmpfs(char *path, struct cpt_context *ctx) ++{ ++ int err; ++ int pid; ++ int pfd[2]; ++ struct file *f; ++ struct cpt_object_hdr v; ++ char buf[16]; ++ int n; ++ loff_t saved_obj; ++ struct args_t args; ++ int status; ++ mm_segment_t oldfs; ++ sigset_t ignore, blocked; ++ ++ err = sc_pipe(pfd); ++ if (err < 0) ++ return err; ++ args.pfd = pfd; ++ args.path = path; ++ ignore.sig[0] = CPT_SIG_IGNORE_MASK; ++ sigprocmask(SIG_BLOCK, &ignore, &blocked); ++ err = pid = local_kernel_thread(dumptmpfs, (void*)&args, ++ SIGCHLD | CLONE_VFORK, 0); ++ if (err < 0) { ++ eprintk_ctx("tmpfs local_kernel_thread: %d\n", err); ++ goto out; ++ } ++ f = fget(pfd[0]); ++ sc_close(pfd[1]); ++ sc_close(pfd[0]); ++ ++ cpt_push_object(&saved_obj, ctx); ++ cpt_open_object(NULL, ctx); ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_NAME; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_NAME; ++ ++ ctx->write(&v, sizeof(v), ctx); ++ ++ do { ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ n = f->f_op->read(f, buf, sizeof(buf), &f->f_pos); ++ set_fs(oldfs); ++ if (n > 0) ++ ctx->write(buf, n, ctx); ++ } while (n > 0); ++ ++ fput(f); ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ if ((err = sc_waitx(pid, 0, &status)) < 0) ++ eprintk_ctx("wait4: %d\n", err); ++ else if ((status & 0x7f) == 0) { ++ err = (status & 0xff00) >> 8; ++ if (err != 0) { ++ eprintk_ctx("tar exited with %d\n", err); ++ err = -EINVAL; ++ } ++ } else { ++ eprintk_ctx("tar terminated\n"); ++ err = -EINVAL; ++ } ++ set_fs(oldfs); ++ sigprocmask(SIG_SETMASK, &blocked, NULL); ++ ++ buf[0] = 0; ++ ctx->write(buf, 1, ctx); ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ return n ? : err; ++ ++out: ++ if (pfd[1] >= 0) ++ sc_close(pfd[1]); ++ if (pfd[0] >= 0) ++ sc_close(pfd[0]); ++ sigprocmask(SIG_SETMASK, &blocked, NULL); ++ return err; ++} ++ ++static int loopy_root(struct vfsmount *mnt) ++{ ++ struct list_head *p; ++ ++ list_for_each(p, &mnt->mnt_ns->list) { ++ struct vfsmount * m = list_entry(p, struct vfsmount, mnt_list); ++ if (m == mnt) ++ return 0; ++ if (m->mnt_sb == mnt->mnt_sb) ++ return 1; ++ } ++ /* Cannot happen */ ++ return 0; ++} ++ ++static int cpt_dump_bind_mnt(struct vfsmount * mnt, cpt_context_t * ctx) ++{ ++ struct list_head *p; ++ int err = -EINVAL; ++ ++ /* One special case: mount --bind /a /a */ ++ if (mnt->mnt_root == mnt->mnt_mountpoint) ++ return cpt_dump_dentry(mnt->mnt_root, mnt, 0, ctx); ++ ++ list_for_each_prev(p, &mnt->mnt_list) { ++ struct vfsmount * m; ++ ++ if (p == &mnt->mnt_ns->list) ++ break; ++ ++ m = list_entry(p, struct vfsmount, mnt_list); ++ ++ if (m->mnt_sb != mnt->mnt_sb) ++ continue; ++ ++ err = cpt_dump_dentry(mnt->mnt_root, m, 0, ctx); ++ if (err == 0) ++ break; ++ } ++ return err; ++} ++ ++static int dump_vfsmount(struct vfsmount *mnt, struct cpt_context *ctx) ++{ ++ int err = 0; ++ struct cpt_vfsmount_image v; ++ loff_t saved_obj; ++ char *path_buf, *path; ++ ++ path_buf = (char *) __get_free_page(GFP_KERNEL); ++ if (!path_buf) ++ return -ENOMEM; ++ ++ path = d_path(mnt->mnt_root, mnt, path_buf, PAGE_SIZE); ++ if (IS_ERR(path)) { ++ free_page((unsigned long) path_buf); ++ return PTR_ERR(path) == -EINVAL ? 0 : PTR_ERR(path); ++ } ++ ++ cpt_open_object(NULL, ctx); ++ ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_VFSMOUNT; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_ARRAY; ++ ++ v.cpt_mntflags = mnt->mnt_flags; ++ if (top_beancounter(slab_ub(mnt)) != top_beancounter(get_exec_ub())) { ++ v.cpt_mntflags |= CPT_MNT_EXT; ++ } else { ++ if (mnt->mnt_root != mnt->mnt_sb->s_root || loopy_root(mnt)) ++ v.cpt_mntflags |= CPT_MNT_BIND; ++ } ++ v.cpt_flags = mnt->mnt_sb->s_flags; ++ ++ ctx->write(&v, sizeof(v), ctx); ++ ++ cpt_push_object(&saved_obj, ctx); ++ cpt_dump_string(mnt->mnt_devname ? : "none", ctx); ++ cpt_dump_string(path, ctx); ++ cpt_dump_string(mnt->mnt_sb->s_type->name, ctx); ++ ++ if (v.cpt_mntflags & CPT_MNT_BIND) ++ err = cpt_dump_bind_mnt(mnt, ctx); ++ else if (!(v.cpt_mntflags & CPT_MNT_EXT) && ++ strcmp(mnt->mnt_sb->s_type->name, "tmpfs") == 0) { ++ mntget(mnt); ++ up_read(&namespace_sem); ++ err = cpt_dump_tmpfs(path, ctx); ++ down_read(&namespace_sem); ++ if (!err) { ++ if (list_empty(&mnt->mnt_list)) ++ err = -EBUSY; ++ } ++ mntput(mnt); ++ } ++ ++ cpt_pop_object(&saved_obj, ctx); ++ ++ cpt_close_object(ctx); ++ if (!err && mnt->mnt_sb->s_magic == FSMAGIC_VEFS) ++ vefs_track_force_stop(mnt->mnt_sb); ++ ++ free_page((unsigned long) path_buf); ++ ++ return err; ++} ++ ++static int dump_one_namespace(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ struct mnt_namespace *n = obj->o_obj; ++ struct cpt_object_hdr v; ++ struct list_head *p; ++ loff_t saved_obj; ++ int err = 0; ++ ++ cpt_open_object(obj, ctx); ++ ++ v.cpt_next = -1; ++ v.cpt_object = CPT_OBJ_NAMESPACE; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_ARRAY; ++ ++ ctx->write(&v, sizeof(v), ctx); ++ ++ cpt_push_object(&saved_obj, ctx); ++ ++ down_read(&namespace_sem); ++ list_for_each(p, &n->list) { ++ err = dump_vfsmount(list_entry(p, struct vfsmount, mnt_list), ctx); ++ if (err) ++ break; ++ } ++ up_read(&namespace_sem); ++ ++ cpt_pop_object(&saved_obj, ctx); ++ ++ cpt_close_object(ctx); ++ ++ return err; ++} ++ ++int cpt_dump_namespace(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ cpt_open_section(ctx, CPT_SECT_NAMESPACE); ++ ++ for_each_object(obj, CPT_OBJ_NAMESPACE) { ++ int err; ++ ++ if ((err = dump_one_namespace(obj, ctx)) != 0) ++ return err; ++ } ++ ++ cpt_close_section(ctx); ++ return 0; ++} +Index: kernel/kernel/cpt/cpt_files.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_files.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,71 @@ ++int cpt_collect_files(cpt_context_t *); ++int cpt_collect_fs(cpt_context_t *); ++int cpt_collect_namespace(cpt_context_t *); ++int cpt_collect_sysvsem_undo(cpt_context_t *); ++int cpt_collect_tty(struct file *, cpt_context_t *); ++int cpt_dump_files(struct cpt_context *ctx); ++int cpt_dump_files_struct(struct cpt_context *ctx); ++int cpt_dump_fs_struct(struct cpt_context *ctx); ++int cpt_dump_content_sysvshm(struct file *file, struct cpt_context *ctx); ++int cpt_dump_content_tty(struct file *file, struct cpt_context *ctx); ++int cpt_dump_tty(cpt_object_t *, struct cpt_context *ctx); ++struct file * rst_sysv_shm(loff_t pos, struct cpt_context *ctx); ++struct file * rst_open_tty(struct cpt_file_image *fi, struct cpt_inode_image *ii, unsigned flags, struct cpt_context *ctx); ++__u32 cpt_tty_fasync(struct file *file, struct cpt_context *ctx); ++ ++int rst_posix_locks(struct cpt_context *ctx); ++ ++struct file *rst_file(loff_t pos, int fd, struct cpt_context *ctx); ++int rst_files_complete(struct cpt_task_image *ti, struct cpt_context *ctx); ++__u32 rst_files_flag(struct cpt_task_image *ti, struct cpt_context *ctx); ++int rst_fs_complete(struct cpt_task_image *ti, struct cpt_context *ctx); ++int rst_restore_fs(struct cpt_context *ctx); ++ ++int cpt_collect_sysv(cpt_context_t *); ++int cpt_dump_sysvsem(struct cpt_context *ctx); ++int cpt_dump_sysvmsg(struct cpt_context *ctx); ++int rst_sysv_ipc(struct cpt_context *ctx); ++int rst_semundo_complete(struct cpt_task_image *ti, struct cpt_context *ctx); ++__u32 rst_semundo_flag(struct cpt_task_image *ti, struct cpt_context *ctx); ++ ++int cpt_dump_namespace(struct cpt_context *ctx); ++int rst_root_namespace(struct cpt_context *ctx); ++ ++int rst_stray_files(struct cpt_context *ctx); ++int rst_tty_jobcontrol(struct cpt_context *ctx); ++ ++void rst_flush_filejobs(struct cpt_context *); ++int rst_do_filejobs(struct cpt_context *); ++ ++int rst_eventpoll(struct cpt_context *); ++struct file *cpt_open_epolldev(struct cpt_file_image *fi, ++ unsigned flags, ++ struct cpt_context *ctx); ++int cpt_dump_epolldev(cpt_object_t *obj, struct cpt_context *); ++ ++int cpt_dump_dir(struct dentry *d, struct vfsmount *mnt, struct cpt_context *ctx); ++int cpt_get_dentry(struct dentry **dp, struct vfsmount **mp, ++ loff_t *pos, struct cpt_context *ctx); ++ ++int cpt_dump_inotify(cpt_object_t *obj, cpt_context_t *ctx); ++int rst_inotify(cpt_context_t *ctx); ++struct file *rst_open_inotify(struct cpt_file_image *fi, ++ unsigned flags, ++ struct cpt_context *ctx); ++ ++ ++int cpt_verify_overmount(char *path, struct dentry *d, struct vfsmount *mnt, ++ cpt_context_t *ctx); ++ ++#define check_one_vfsmount(mnt) \ ++ (strcmp(mnt->mnt_sb->s_type->name, "rootfs") != 0 && \ ++ strcmp(mnt->mnt_sb->s_type->name, "ext3") != 0 && \ ++ strcmp(mnt->mnt_sb->s_type->name, "ext2") != 0 && \ ++ strcmp(mnt->mnt_sb->s_type->name, "simfs") != 0 && \ ++ strcmp(mnt->mnt_sb->s_type->name, "unionfs") != 0 && \ ++ strcmp(mnt->mnt_sb->s_type->name, "tmpfs") != 0 && \ ++ strcmp(mnt->mnt_sb->s_type->name, "devpts") != 0 && \ ++ strcmp(mnt->mnt_sb->s_type->name, "proc") != 0 && \ ++ strcmp(mnt->mnt_sb->s_type->name, "sysfs") != 0) ++ ++extern const struct file_operations shmem_file_operations; +Index: kernel/kernel/cpt/cpt_fsmagic.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_fsmagic.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,17 @@ ++/* Collected from kernel sources. */ ++ ++#define FSMAGIC_TMPFS 0x01021994 ++#define FSMAGIC_PIPEFS 0x50495045 ++#define FSMAGIC_SOCKFS 0x534F434B ++#define FSMAGIC_PFMFS 0xa0b4d889 ++#define FSMAGIC_BDEV 0x62646576 ++#define FSMAGIC_EPOLL 0x03111965 ++#define FSMAGIC_FUTEX 0x0BAD1DEA ++#define FSMAGIC_INOTIFY 0x2BAD1DEA ++#define FSMAGIC_MQUEUE 0x19800202 ++#define FSMAGIC_PROC 0x9fa0 ++#define FSMAGIC_DEVPTS 0x1CD1 ++#define FSMAGIC_AUTOFS 0x0187 ++#define FSMAGIC_EXT2 0xEF53 ++#define FSMAGIC_REISER 0x52654973 ++#define FSMAGIC_VEFS 0x565a4653 +Index: kernel/kernel/cpt/cpt_inotify.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_inotify.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,144 @@ ++/* ++ * ++ * kernel/cpt/cpt_inotify.c ++ * ++ * Copyright (C) 2000-2007 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_mm.h" ++#include "cpt_files.h" ++#include "cpt_kernel.h" ++#include "cpt_fsmagic.h" ++#include "cpt_syscalls.h" ++ ++extern struct file_operations inotify_fops; ++ ++int cpt_dump_inotify(cpt_object_t *obj, cpt_context_t *ctx) ++{ ++ int err = 0; ++ struct file *file = obj->o_obj; ++ struct inotify_device *dev; ++ struct inotify_watch *watch; ++ struct inotify_kernel_event *kev; ++ struct cpt_inotify_image ii; ++ ++ if (file->f_op != &inotify_fops) { ++ eprintk_ctx("bad inotify file\n"); ++ return -EINVAL; ++ } ++ ++ dev = file->private_data; ++ ++ /* inotify_user.c does not protect open /proc/N/fd, silly. ++ * Opener will get an invalid file with uninitialized private_data ++ */ ++ if (unlikely(dev == NULL)) { ++ eprintk_ctx("bad inotify dev\n"); ++ return -EINVAL; ++ } ++ ++ cpt_open_object(NULL, ctx); ++ ++ ii.cpt_next = CPT_NULL; ++ ii.cpt_object = CPT_OBJ_INOTIFY; ++ ii.cpt_hdrlen = sizeof(ii); ++ ii.cpt_content = CPT_CONTENT_ARRAY; ++ ii.cpt_file = obj->o_pos; ++ ii.cpt_user = dev->user->uid; ++ ii.cpt_max_events = dev->max_events; ++ ii.cpt_last_wd = dev->ih->last_wd; ++ ++ ctx->write(&ii, sizeof(ii), ctx); ++ ++ mutex_lock(&dev->ih->mutex); ++ list_for_each_entry(watch, &dev->ih->watches, h_list) { ++ loff_t saved_obj; ++ loff_t saved_obj2; ++ struct cpt_inotify_wd_image wi; ++ ++ cpt_push_object(&saved_obj, ctx); ++ cpt_open_object(NULL, ctx); ++ ++ wi.cpt_next = CPT_NULL; ++ wi.cpt_object = CPT_OBJ_INOTIFY_WATCH; ++ wi.cpt_hdrlen = sizeof(wi); ++ wi.cpt_content = CPT_CONTENT_ARRAY; ++ wi.cpt_wd = watch->wd; ++ wi.cpt_mask = watch->mask; ++ ++ ctx->write(&wi, sizeof(wi), ctx); ++ ++ cpt_push_object(&saved_obj2, ctx); ++ err = cpt_dump_dir(watch->dentry, watch->mnt, ctx); ++ cpt_pop_object(&saved_obj2, ctx); ++ if (err) ++ break; ++ ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ } ++ mutex_unlock(&dev->ih->mutex); ++ ++ if (err) ++ return err; ++ ++ mutex_lock(&dev->ev_mutex); ++ list_for_each_entry(kev, &dev->events, list) { ++ loff_t saved_obj; ++ struct cpt_inotify_ev_image ei; ++ ++ cpt_push_object(&saved_obj, ctx); ++ cpt_open_object(NULL, ctx); ++ ++ ei.cpt_next = CPT_NULL; ++ ei.cpt_object = CPT_OBJ_INOTIFY_EVENT; ++ ei.cpt_hdrlen = sizeof(ei); ++ ei.cpt_content = CPT_CONTENT_NAME; ++ ei.cpt_wd = kev->event.wd; ++ ei.cpt_mask = kev->event.mask; ++ ei.cpt_cookie = kev->event.cookie; ++ ei.cpt_namelen = kev->name ? strlen(kev->name) : 0; ++ ++ ctx->write(&ei, sizeof(ei), ctx); ++ ++ if (kev->name) { ++ ctx->write(kev->name, ei.cpt_namelen+1, ctx); ++ ctx->align(ctx); ++ } ++ ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ } ++ mutex_unlock(&dev->ev_mutex); ++ ++ cpt_close_object(ctx); ++ ++ return err; ++} +Index: kernel/kernel/cpt/cpt_kernel.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_kernel.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,177 @@ ++/* ++ * ++ * kernel/cpt/cpt_kernel.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#define __KERNEL_SYSCALLS__ 1 ++ ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_X86 ++#include ++#endif ++#include ++ ++#include "cpt_kernel.h" ++#include "cpt_syscalls.h" ++ ++int debug_level = 1; ++ ++#ifdef CONFIG_X86_32 ++ ++/* ++ * Create a kernel thread ++ */ ++extern void kernel_thread_helper(void); ++int asm_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags, pid_t pid) ++{ ++ struct pt_regs regs; ++ ++ memset(®s, 0, sizeof(regs)); ++ ++ regs.ebx = (unsigned long) fn; ++ regs.edx = (unsigned long) arg; ++ ++ regs.xds = __USER_DS; ++ regs.xes = __USER_DS; ++ regs.xfs = __KERNEL_PERCPU; ++ regs.orig_eax = -1; ++ regs.eip = (unsigned long) kernel_thread_helper; ++ regs.xcs = __KERNEL_CS | get_kernel_rpl(); ++ regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; ++ ++ /* Ok, create the new process.. */ ++ return do_fork_pid(flags | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL, pid); ++} ++#endif ++ ++#ifdef CONFIG_IA64 ++pid_t ++asm_kernel_thread (int (*fn)(void *), void *arg, unsigned long flags, pid_t pid) ++{ ++ extern void start_kernel_thread (void); ++ unsigned long *helper_fptr = (unsigned long *) &start_kernel_thread; ++ struct { ++ struct switch_stack sw; ++ struct pt_regs pt; ++ } regs; ++ ++ memset(®s, 0, sizeof(regs)); ++ regs.pt.cr_iip = helper_fptr[0]; /* set entry point (IP) */ ++ regs.pt.r1 = helper_fptr[1]; /* set GP */ ++ regs.pt.r9 = (unsigned long) fn; /* 1st argument */ ++ regs.pt.r11 = (unsigned long) arg; /* 2nd argument */ ++ /* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read. */ ++ regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN; ++ regs.pt.cr_ifs = 1UL << 63; /* mark as valid, empty frame */ ++ regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR); ++ regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET; ++ regs.sw.pr = (1 << 2 /*PRED_KERNEL_STACK*/); ++ return do_fork_pid(flags | CLONE_UNTRACED, 0, ®s.pt, 0, NULL, NULL, pid); ++} ++#endif ++ ++int local_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags, pid_t pid) ++{ ++ pid_t ret; ++ ++ if (current->fs == NULL) { ++ /* do_fork_pid() hates processes without fs, oopses. */ ++ printk("CPT BUG: local_kernel_thread: current->fs==NULL\n"); ++ return -EINVAL; ++ } ++ if (!try_module_get(THIS_MODULE)) ++ return -EBUSY; ++ ret = asm_kernel_thread(fn, arg, flags, pid); ++ if (ret < 0) ++ module_put(THIS_MODULE); ++ return ret; ++} ++ ++#ifdef __i386__ ++int __execve(const char *file, char **argv, char **envp) ++{ ++ long res; ++ __asm__ volatile ("int $0x80" ++ : "=a" (res) ++ : "0" (__NR_execve),"b" ((long)(file)),"c" ((long)(argv)), ++ "d" ((long)(envp)) : "memory"); ++ return (int)res; ++} ++#endif ++ ++int sc_execve(char *cmd, char **argv, char **env) ++{ ++ int ret; ++#ifndef __i386__ ++ ret = kernel_execve(cmd, argv, env); ++#else ++ ret = __execve(cmd, argv, env); ++#endif ++ return ret; ++} ++ ++unsigned int test_cpu_caps(void) ++{ ++ unsigned int flags = 0; ++ ++#ifdef CONFIG_X86 ++ if (boot_cpu_has(X86_FEATURE_CMOV)) ++ flags |= 1 << CPT_CPU_X86_CMOV; ++ if (cpu_has_fxsr) ++ flags |= 1 << CPT_CPU_X86_FXSR; ++ if (cpu_has_xmm) ++ flags |= 1 << CPT_CPU_X86_SSE; ++#ifndef CONFIG_X86_64 ++ if (cpu_has_xmm2) ++#endif ++ flags |= 1 << CPT_CPU_X86_SSE2; ++ if (cpu_has_mmx) ++ flags |= 1 << CPT_CPU_X86_MMX; ++ if (boot_cpu_has(X86_FEATURE_3DNOW)) ++ flags |= 1 << CPT_CPU_X86_3DNOW; ++ if (boot_cpu_has(X86_FEATURE_3DNOWEXT)) ++ flags |= 1 << CPT_CPU_X86_3DNOW2; ++ if (boot_cpu_has(X86_FEATURE_SYSCALL)) ++ flags |= 1 << CPT_CPU_X86_SYSCALL; ++#ifdef CONFIG_X86_64 ++ if (boot_cpu_has(X86_FEATURE_SYSCALL) && ++ boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) ++ flags |= 1 << CPT_CPU_X86_SYSCALL32; ++#endif ++ if (boot_cpu_has(X86_FEATURE_SEP) ++#ifdef CONFIG_X86_64 ++ && boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ++#endif ++ ) ++ flags |= ((1 << CPT_CPU_X86_SEP) | (1 << CPT_CPU_X86_SEP32)); ++#ifdef CONFIG_X86_64 ++ flags |= 1 << CPT_CPU_X86_EMT64; ++#endif ++#endif ++#ifdef CONFIG_IA64 ++ flags |= 1 << CPT_CPU_X86_IA64; ++ flags |= 1 << CPT_CPU_X86_FXSR; ++#endif ++ return flags; ++} ++ ++unsigned int test_kernel_config(void) ++{ ++ unsigned int flags = 0; ++#ifdef CONFIG_X86 ++#if defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64) ++ flags |= 1 << CPT_KERNEL_CONFIG_PAE; ++#endif ++#endif ++ return flags; ++} +Index: kernel/kernel/cpt/cpt_kernel.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_kernel.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,95 @@ ++/* Interface to kernel vars which we had to _add_. */ ++ ++#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20) ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) ++#define TASK_TRACED TASK_STOPPED ++#define unix_peer(sk) ((sk)->sk_pair) ++#define page_mapcount(pg) ((pg)->mapcount) ++#else ++#define unix_peer(sk) (unix_sk(sk)->peer) ++#endif ++ ++#ifdef CONFIG_IA64 ++#define cpu_has_fxsr 1 ++#endif ++ ++#define CPT_SIG_IGNORE_MASK (\ ++ (1 << (SIGCONT - 1)) | (1 << (SIGCHLD - 1)) | \ ++ (1 << (SIGWINCH - 1)) | (1 << (SIGURG - 1))) ++ ++static inline void do_gettimespec(struct timespec *ts) ++{ ++ struct timeval tv; ++ do_gettimeofday(&tv); ++ ts->tv_sec = tv.tv_sec; ++ ts->tv_nsec = tv.tv_usec*1000; ++} ++ ++int local_kernel_thread(int (*fn)(void *), ++ void * arg, ++ unsigned long flags, ++ pid_t pid); ++int asm_kernel_thread(int (*fn)(void *), ++ void * arg, ++ unsigned long flags, ++ pid_t pid); ++ ++#if defined(CONFIG_VZFS_FS) || defined(CONFIG_VZFS_FS_MODULE) ++void vefs_track_force_stop(struct super_block *super); ++ ++void vefs_track_notify(struct dentry *vdentry, int track_cow); ++ ++struct dentry * vefs_replaced_dentry(struct dentry *de); ++int vefs_is_renamed_dentry(struct dentry *vde, struct dentry *pde); ++#else ++static inline void vefs_track_force_stop(struct super_block *super) { }; ++ ++static inline void vefs_track_notify(struct dentry *vdentry, int track_cow) { }; ++#endif ++ ++unsigned int test_cpu_caps(void); ++unsigned int test_kernel_config(void); ++ ++#define test_one_flag_old(src, dst, flag, message, ret) \ ++if (src & (1 << flag)) \ ++ if (!(dst & (1 << flag))) { \ ++ wprintk("Destination cpu does not have " message "\n"); \ ++ ret = 1; \ ++ } ++#define test_one_flag(src, dst, flag, message, ret) \ ++if (src & (1 << flag)) \ ++ if (!(dst & (1 << flag))) { \ ++ eprintk_ctx("Destination cpu does not have " message "\n"); \ ++ ret = 1; \ ++ } ++ ++static inline void ++_set_normalized_timespec(struct timespec *ts, time_t sec, long nsec) ++{ ++ while (nsec >= NSEC_PER_SEC) { ++ nsec -= NSEC_PER_SEC; ++ ++sec; ++ } ++ while (nsec < 0) { ++ nsec += NSEC_PER_SEC; ++ --sec; ++ } ++ ts->tv_sec = sec; ++ ts->tv_nsec = nsec; ++} ++ ++static inline struct timespec ++_ns_to_timespec(const s64 nsec) ++{ ++ struct timespec ts; ++ ++ if (!nsec) ++ return (struct timespec) {0, 0}; ++ ++ ts.tv_sec = div_long_long_rem_signed(nsec, NSEC_PER_SEC, &ts.tv_nsec); ++ if (unlikely(nsec < 0)) ++ _set_normalized_timespec(&ts, ts.tv_sec, ts.tv_nsec); ++ ++ return ts; ++} +Index: kernel/kernel/cpt/cpt_mm.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_mm.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,915 @@ ++/* ++ * ++ * kernel/cpt/cpt_mm.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_X86 ++#include ++#endif ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_mm.h" ++#include "cpt_kernel.h" ++#include "cpt_fsmagic.h" ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++#include "cpt_pagein.h" ++#endif ++#include "cpt_ubc.h" ++ ++static int collect_one_aio_ctx(struct mm_struct *mm, struct kioctx *aio_ctx, ++ cpt_context_t *ctx) ++{ ++ if (!list_empty(&aio_ctx->run_list)) { ++ /* This is impossible at least with kernel 2.6.8.1 or 2.6.16 */ ++ eprintk_ctx("run list is not empty, cannot suspend AIO\n"); ++ return -EBUSY; ++ } ++ ++ /* Wait for pending IOCBs. Linux AIO is mostly _fake_. ++ * It is actually synchronous, except for direct IO and ++ * some funny raw USB things, which cannot happen inside VE. ++ * However, we do this for future. ++ * ++ * Later note: in 2.6.16 we may allow O_DIRECT, so that ++ * it is not meaningless code. ++ */ ++ wait_for_all_aios(aio_ctx); ++ ++ if (!list_empty(&aio_ctx->run_list) || ++ !list_empty(&aio_ctx->active_reqs) || ++ aio_ctx->reqs_active) { ++ eprintk_ctx("were not able to suspend AIO\n"); ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++static int collect_one_mm(struct mm_struct *mm, cpt_context_t * ctx) ++{ ++ struct vm_area_struct *vma; ++ ++ for (vma = mm->mmap; vma; vma = vma->vm_next) { ++ if (vma->vm_file) { ++ if (cpt_object_add(CPT_OBJ_FILE, vma->vm_file, ctx) == NULL) ++ return -ENOMEM; ++ } ++ } ++#ifdef CONFIG_BEANCOUNTERS ++ if (cpt_add_ubc(mm->mm_ub, ctx) == NULL) ++ return -ENOMEM; ++#endif ++ ++ if (mm->ioctx_list) { ++ struct kioctx *aio_ctx; ++ int err; ++ ++ for (aio_ctx = mm->ioctx_list; aio_ctx; aio_ctx = aio_ctx->next) ++ if ((err = collect_one_aio_ctx(mm, aio_ctx, ctx)) != 0) ++ return err; ++ } ++ ++ return 0; ++} ++ ++int cpt_collect_mm(cpt_context_t * ctx) ++{ ++ cpt_object_t *obj; ++ int err; ++ int index; ++ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ struct task_struct *tsk = obj->o_obj; ++ if (tsk->mm && cpt_object_add(CPT_OBJ_MM, tsk->mm, ctx) == NULL) ++ return -ENOMEM; ++ } ++ ++ index = 1; ++ for_each_object(obj, CPT_OBJ_MM) { ++ struct mm_struct *mm = obj->o_obj; ++ if (obj->o_count != atomic_read(&mm->mm_users)) { ++ eprintk_ctx("mm_struct is referenced outside %d %d\n", obj->o_count, atomic_read(&mm->mm_users)); ++ return -EAGAIN; ++ } ++ cpt_obj_setindex(obj, index++, ctx); ++ ++ if ((err = collect_one_mm(mm, ctx)) != 0) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int zcnt, scnt, scnt0, ucnt; ++ ++/* Function where_is_anon_page() returns address of a anonymous page in mm ++ * of already dumped process. This happens f.e. after fork(). We do not use ++ * this right now, just keep statistics, it is diffucult to restore such state, ++ * but the most direct use is to save space in dumped image. */ ++ ++ ++static inline unsigned long ++vma_address0(struct page *page, struct vm_area_struct *vma) ++{ ++ pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); ++ unsigned long address; ++ ++ address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT); ++ if (unlikely(address < vma->vm_start || address >= vma->vm_end)) ++ address |= 1; ++ return address; ++} ++ ++static int really_this_one(struct vm_area_struct *vma, unsigned long address, ++ struct page *page) ++{ ++ struct mm_struct *mm = vma->vm_mm; ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ spinlock_t *ptl; ++ int result; ++ ++ pgd = pgd_offset(mm, address); ++ if (unlikely(!pgd_present(*pgd))) ++ return 0; ++ ++ pud = pud_offset(pgd, address); ++ if (!pud_present(*pud)) ++ return 0; ++ ++ pmd = pmd_offset(pud, address); ++ if (unlikely(!pmd_present(*pmd))) ++ return 0; ++ ++ result = 0; ++ pte = pte_offset_map(pmd, address); ++ if (!pte_present(*pte)) { ++ pte_unmap(pte); ++ return 0; ++ } ++ ++ ptl = pte_lockptr(mm, pmd); ++ spin_lock(ptl); ++ if (pte_present(*pte) && page_to_pfn(page) == pte_pfn(*pte)) ++ result = 1; ++ pte_unmap_unlock(pte, ptl); ++ return result; ++} ++ ++static loff_t where_is_anon_page(cpt_object_t *mmobj, unsigned long mapaddr, ++ struct page *page, cpt_context_t * ctx) ++{ ++ loff_t mmptr = CPT_NULL; ++ struct anon_vma *anon_vma; ++ struct vm_area_struct *vma; ++ int idx = mmobj->o_index; ++ ++ if (!PageAnon(page)) ++ return CPT_NULL; ++ ++ anon_vma = page_lock_anon_vma(page); ++ if (!anon_vma) ++ return CPT_NULL; ++ ++ list_for_each_entry(vma, &anon_vma->head, anon_vma_node) { ++ unsigned long addr = vma_address0(page, vma); ++ cpt_object_t *obj; ++ ++ /* We do not try to support mremapped regions (addr != mapaddr), ++ * only mmaps directly inherited via fork(). ++ * With this limitation we may check self-consistency of ++ * vmas (vm_start, vm_pgoff, anon_vma) before ++ * doing __copy_page_range() in rst_mm. ++ */ ++ if (mmobj->o_obj != vma->vm_mm && addr == mapaddr) { ++ obj = lookup_cpt_object(CPT_OBJ_MM, vma->vm_mm, ctx); ++ if (obj && obj->o_pos != CPT_NULL && obj->o_index < idx) { ++ if (really_this_one(vma, addr, page)) { ++ mmptr = obj->o_pos; ++ idx = obj->o_index; ++ } ++ } ++ } ++ } ++ page_unlock_anon_vma(anon_vma); ++ ++ return mmptr; ++} ++ ++struct page_area ++{ ++ int type; ++ unsigned long start; ++ unsigned long end; ++ pgoff_t pgoff; ++ loff_t mm; ++ __u64 list[16]; ++}; ++ ++struct page_desc ++{ ++ int type; ++ pgoff_t index; ++ loff_t mm; ++ int shared; ++}; ++ ++enum { ++ PD_ABSENT, ++ PD_COPY, ++ PD_ZERO, ++ PD_CLONE, ++ PD_FUNKEY, ++ PD_LAZY, ++ PD_ITER, ++ PD_ITERYOUNG, ++}; ++ ++/* 0: page can be obtained from backstore, or still not mapped anonymous page, ++ or something else, which does not requre copy. ++ 1: page requires copy ++ 2: page requres copy but its content is zero. Quite useless. ++ 3: wp page is shared after fork(). It is to be COWed when modified. ++ 4: page is something unsupported... We copy it right now. ++ */ ++ ++ ++ ++static void page_get_desc(cpt_object_t *mmobj, ++ struct vm_area_struct *vma, unsigned long addr, ++ struct page_desc *pdesc, cpt_context_t * ctx) ++{ ++ struct mm_struct *mm = vma->vm_mm; ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *ptep, pte; ++ spinlock_t *ptl; ++ struct page *pg = NULL; ++ pgoff_t linear_index = (addr - vma->vm_start)/PAGE_SIZE + vma->vm_pgoff; ++ ++ pdesc->index = linear_index; ++ pdesc->shared = 0; ++ pdesc->mm = CPT_NULL; ++ ++ if (vma->vm_flags & VM_IO) { ++ pdesc->type = PD_ABSENT; ++ return; ++ } ++ ++ pgd = pgd_offset(mm, addr); ++ if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) ++ goto out_absent; ++ pud = pud_offset(pgd, addr); ++ if (pud_none(*pud) || unlikely(pud_bad(*pud))) ++ goto out_absent; ++ pmd = pmd_offset(pud, addr); ++ if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) ++ goto out_absent; ++#ifdef CONFIG_X86 ++ if (pmd_huge(*pmd)) { ++ eprintk_ctx("page_huge\n"); ++ goto out_unsupported; ++ } ++#endif ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++retry: ++#endif ++ ptep = pte_offset_map_lock(mm, pmd, addr, &ptl); ++ pte = *ptep; ++ pte_unmap(ptep); ++ ++ if (pte_none(pte)) ++ goto out_absent_unlock; ++ ++ if (!pte_present(pte)) { ++ if (pte_file(pte)) { ++ pdesc->index = pte_to_pgoff(pte); ++ goto out_absent_unlock; ++ } ++ if (vma->vm_flags & VM_SHARED) { ++ /* It is impossible: shared mappings cannot be in swap */ ++ eprintk_ctx("shared mapping is not present: %08lx@%Ld\n", addr, mmobj->o_pos); ++ goto out_unsupported_unlock; ++ } ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ /* Otherwise it is in swap. */ ++ if (!ctx->lazy_vm) { ++ int err; ++ /* If lazy transfer is not enabled, ++ * raise it from swap now, so that we ++ * save at least when the page is shared. ++ */ ++ spin_unlock(ptl); ++ err = handle_mm_fault(mm, vma, addr, 0); ++ if (err == VM_FAULT_SIGBUS) ++ goto out_absent; ++ if (err == VM_FAULT_OOM) ++ goto out_absent; ++ err = 0; ++ goto retry; ++ } ++#endif ++ pdesc->type = PD_LAZY; ++ goto out_unlock; ++ } ++ ++ if ((pg = vm_normal_page(vma, addr, pte)) == NULL) { ++ pdesc->type = PD_COPY; ++ goto out_unlock; ++ } ++ ++ get_page(pg); ++ spin_unlock(ptl); ++ ++ if (pg->mapping && !PageAnon(pg)) { ++ if (vma->vm_file == NULL) { ++ eprintk_ctx("pg->mapping!=NULL for fileless vma: %08lx\n", addr); ++ goto out_unsupported; ++ } ++ if (vma->vm_file->f_mapping != pg->mapping) { ++ eprintk_ctx("pg->mapping!=f_mapping: %08lx %p %p %Ld\n", ++ addr, vma->vm_file->f_mapping, pg->mapping, ++ mmobj->o_pos); ++ goto out_unsupported; ++ } ++ pdesc->index = (pg->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT)); ++ /* Page is in backstore. For us it is like ++ * it is not present. ++ */ ++ goto out_absent; ++ } ++ ++ if (PageReserved(pg)) { ++ /* Special case: ZERO_PAGE is used, when an ++ * anonymous page is accessed but not written. */ ++ if (pg == ZERO_PAGE(addr)) { ++ if (pte_write(pte)) { ++ eprintk_ctx("not funny already, writable ZERO_PAGE\n"); ++ goto out_unsupported; ++ } ++ zcnt++; ++ goto out_absent; ++ } ++ eprintk_ctx("reserved page %lu at %08lx@%Ld\n", pg->index, ++ addr, mmobj->o_pos); ++ goto out_unsupported; ++ } ++ ++ if (pg == ZERO_PAGE(addr)) { ++ wprintk_ctx("that's how it works now\n"); ++ } ++ ++ if (!pg->mapping) { ++ eprintk_ctx("page without mapping at %08lx@%Ld\n", addr, ++ mmobj->o_pos); ++ goto out_unsupported; ++ } ++ ++ if (pg->mapping && page_mapcount(pg) > 1) { ++ pdesc->shared = 1; ++ pdesc->mm = where_is_anon_page(mmobj, addr, pg, ctx); ++ if (pdesc->mm != CPT_NULL) { ++ scnt0++; ++ pdesc->type = PD_CLONE; ++ goto out_put; ++ } else { ++ scnt++; ++ } ++ } ++#ifdef CONFIG_VZ_CHECKPOINT_ITER ++ if (ctx->iter_done && ++ test_bit(PG_checkpointed, &pg->flags)) { ++ if (pte_write(pte)) { ++ wprintk_ctx("writable PG_checkpointed page\n"); ++ } ++ pdesc->index = page_to_pfn(pg); ++ pdesc->type = pte_young(pte) ? PD_ITERYOUNG : PD_ITER; ++ goto out_put; ++ } ++#endif ++ pdesc->type = pte_young(pte) ? PD_COPY : PD_LAZY; ++ ++out_put: ++ if (pg) ++ put_page(pg); ++ return; ++ ++out_unlock: ++ spin_unlock(ptl); ++ goto out_put; ++ ++out_absent_unlock: ++ spin_unlock(ptl); ++out_absent: ++ pdesc->type = PD_ABSENT; ++ goto out_put; ++ ++out_unsupported_unlock: ++ spin_unlock(ptl); ++out_unsupported: ++ ucnt++; ++ pdesc->type = PD_FUNKEY; ++ goto out_put; ++} ++ ++/* ATTN: We give "current" to get_user_pages(). This is wrong, but get_user_pages() ++ * does not really need this thing. It just stores some page fault stats there. ++ * ++ * BUG: some archs (f.e. sparc64, but not Intel*) require flush cache pages ++ * before accessing vma. ++ */ ++void dump_pages(struct vm_area_struct *vma, unsigned long start, ++ unsigned long end, struct cpt_context *ctx) ++{ ++#define MAX_PAGE_BATCH 16 ++ struct page *pg[MAX_PAGE_BATCH]; ++ int npages = (end - start)/PAGE_SIZE; ++ int count = 0; ++ ++ while (count < npages) { ++ int copy = npages - count; ++ int n; ++ ++ if (copy > MAX_PAGE_BATCH) ++ copy = MAX_PAGE_BATCH; ++ n = get_user_pages(current, vma->vm_mm, start, copy, ++ 0, 1, pg, NULL); ++ if (n == copy) { ++ int i; ++ for (i=0; iwrite(maddr, PAGE_SIZE, ctx); ++ kunmap(pg[i]); ++ } ++ } else { ++ eprintk_ctx("get_user_pages fault"); ++ for ( ; n > 0; n--) ++ page_cache_release(pg[n-1]); ++ return; ++ } ++ start += n*PAGE_SIZE; ++ count += n; ++ for ( ; n > 0; n--) ++ page_cache_release(pg[n-1]); ++ } ++ return; ++} ++ ++int dump_page_block(struct vm_area_struct *vma, struct cpt_page_block *pgb, ++ int copy, ++ struct cpt_context *ctx) ++{ ++ loff_t saved_object; ++ ++ cpt_push_object(&saved_object, ctx); ++ ++ pgb->cpt_object = (copy != PD_LAZY) ? CPT_OBJ_PAGES : CPT_OBJ_LAZYPAGES; ++ pgb->cpt_hdrlen = sizeof(*pgb); ++ pgb->cpt_content = (copy == PD_COPY || copy == PD_LAZY) ? CPT_CONTENT_DATA : CPT_CONTENT_VOID; ++ ++ ctx->write(pgb, sizeof(*pgb), ctx); ++ if (copy == PD_COPY || copy == PD_LAZY) ++ dump_pages(vma, pgb->cpt_start, pgb->cpt_end, ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_object, ctx); ++ return 0; ++} ++ ++int dump_remappage_block(struct vm_area_struct *vma, struct page_area *pa, ++ struct cpt_context *ctx) ++{ ++ struct cpt_remappage_block pgb; ++ loff_t saved_object; ++ ++ cpt_push_object(&saved_object, ctx); ++ ++ pgb.cpt_object = CPT_OBJ_REMAPPAGES; ++ pgb.cpt_hdrlen = sizeof(pgb); ++ pgb.cpt_content = CPT_CONTENT_VOID; ++ pgb.cpt_start = pa->start; ++ pgb.cpt_end = pa->end; ++ pgb.cpt_pgoff = pa->pgoff - (pa->end-pa->start)/PAGE_SIZE + 1; ++ ++ ctx->write(&pgb, sizeof(pgb), ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_object, ctx); ++ return 0; ++} ++ ++int dump_copypage_block(struct vm_area_struct *vma, struct page_area *pa, ++ struct cpt_context *ctx) ++{ ++ struct cpt_copypage_block pgb; ++ loff_t saved_object; ++ ++ cpt_push_object(&saved_object, ctx); ++ ++ pgb.cpt_object = CPT_OBJ_COPYPAGES; ++ pgb.cpt_hdrlen = sizeof(pgb); ++ pgb.cpt_content = CPT_CONTENT_VOID; ++ pgb.cpt_start = pa->start; ++ pgb.cpt_end = pa->end; ++ pgb.cpt_source = pa->mm; ++ ++ ctx->write(&pgb, sizeof(pgb), ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_object, ctx); ++ return 0; ++} ++ ++int dump_lazypage_block(struct vm_area_struct *vma, struct page_area *pa, ++ cpt_context_t *ctx) ++{ ++ struct cpt_lazypage_block pgb; ++ loff_t saved_object; ++ ++ cpt_push_object(&saved_object, ctx); ++ ++ pgb.cpt_object = CPT_OBJ_LAZYPAGES; ++ pgb.cpt_hdrlen = sizeof(pgb); ++ pgb.cpt_content = CPT_CONTENT_VOID; ++ pgb.cpt_start = pa->start; ++ pgb.cpt_end = pa->end; ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ pgb.cpt_index = cpt_alloc_pgin_index(vma, pa->start, ++ (pa->end-pa->start)/PAGE_SIZE, ctx); ++#endif ++ ctx->write(&pgb, sizeof(pgb), ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_object, ctx); ++ return 0; ++} ++ ++int dump_iterpage_block(struct vm_area_struct *vma, struct page_area *pa, ++ cpt_context_t *ctx) ++{ ++ struct cpt_iterpage_block pgb; ++ loff_t saved_object; ++ ++ cpt_push_object(&saved_object, ctx); ++ ++ pgb.cpt_object = pa->type == PD_ITER ? CPT_OBJ_ITERPAGES : ++ CPT_OBJ_ITERYOUNGPAGES; ++ pgb.cpt_hdrlen = sizeof(pgb); ++ pgb.cpt_content = CPT_CONTENT_VOID; ++ pgb.cpt_start = pa->start; ++ pgb.cpt_end = pa->end; ++ ctx->write(&pgb, sizeof(pgb), ctx); ++ ++ ctx->write(pa->list, 8*((pa->end-pa->start)/PAGE_SIZE), ctx); ++ ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_object, ctx); ++ return 0; ++} ++ ++ ++static int can_expand(struct page_area *pa, struct page_desc *pd) ++{ ++ if (pa->start == pa->end) ++ return 1; ++ if (pa->type != pd->type) ++ return 0; ++ if (pa->type == PD_ITER || pa->type == PD_ITERYOUNG) { ++ if (pa->end - pa->start >= PAGE_SIZE*16) ++ return 0; ++ pa->list[(pa->end - pa->start)/PAGE_SIZE] = pd->index; ++ } ++ if (pa->type == PD_ABSENT) ++ return pd->index == pa->pgoff + 1; ++ if (pa->type == PD_CLONE) ++ return pd->mm == pa->mm; ++ return 1; ++} ++ ++static int dump_one_vma(cpt_object_t *mmobj, ++ struct vm_area_struct *vma, struct cpt_context *ctx) ++{ ++ struct cpt_vma_image *v = cpt_get_buf(ctx); ++ unsigned long addr; ++ loff_t saved_object; ++ struct cpt_page_block pgb; ++ struct page_area pa; ++ int cloned_pages = 0; ++ ++ cpt_push_object(&saved_object, ctx); ++ ++ v->cpt_object = CPT_OBJ_VMA; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ v->cpt_start = vma->vm_start; ++ v->cpt_end = vma->vm_end; ++ v->cpt_flags = vma->vm_flags; ++ if (vma->vm_flags&VM_HUGETLB) { ++ eprintk_ctx("huge TLB VMAs are still not supported\n"); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ v->cpt_pgprot = vma->vm_page_prot.pgprot; ++ v->cpt_pgoff = vma->vm_pgoff; ++ v->cpt_file = CPT_NULL; ++#ifndef CONFIG_IA64 ++ if ((void *)vma->vm_start == vma->vm_mm->context.vdso && ++ vma->vm_ops == &special_mapping_vmops) ++ v->cpt_type = CPT_VMA_VDSO; ++ else ++#endif ++ v->cpt_type = CPT_VMA_TYPE_0; ++ v->cpt_anonvma = 0; ++ ++ /* We have to remember what VMAs are bound to one anon_vma. ++ * So, we store an identifier of group of VMAs. It is handy ++ * to use absolute address of anon_vma as this identifier. */ ++ v->cpt_anonvmaid = (unsigned long)vma->anon_vma; ++ ++ if (vma->vm_file) { ++ struct file *filp; ++ cpt_object_t *obj = lookup_cpt_object(CPT_OBJ_FILE, vma->vm_file, ctx); ++ if (obj == NULL) BUG(); ++ filp = obj->o_obj; ++ if (filp->f_op && ++ filp->f_op->read == NULL && ++ filp->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_TMPFS) ++ v->cpt_type = CPT_VMA_TYPE_SHM; ++ v->cpt_file = obj->o_pos; ++ } ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ if (v->cpt_type == CPT_VMA_VDSO) ++ goto out; ++ ++ pa.type = PD_ABSENT; ++ pa.pgoff = vma->vm_pgoff; ++ pa.mm = CPT_NULL; ++ pa.start = vma->vm_start; ++ pa.end = vma->vm_start; ++ ++ for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) { ++ struct page_desc pd; ++ ++ page_get_desc(mmobj, vma, addr, &pd, ctx); ++ cloned_pages += pd.shared; ++ ++ if (pd.type == PD_FUNKEY) { ++ eprintk_ctx("dump_one_vma: funkey page\n"); ++ return -EINVAL; ++ } ++ ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ if (pd.type == PD_LAZY && ++ (ctx->lazy_vm == 0 || (vma->vm_flags&VM_LOCKED))) ++ pd.type = PD_COPY; ++#else ++ if (pd.type == PD_LAZY) ++ pd.type = PD_COPY; ++#endif ++ ++ if (!can_expand(&pa, &pd)) { ++ if (pa.type == PD_COPY || ++ pa.type == PD_ZERO) { ++ pgb.cpt_start = pa.start; ++ pgb.cpt_end = pa.end; ++ dump_page_block(vma, &pgb, pa.type, ctx); ++ } else if (pa.type == PD_CLONE) { ++ dump_copypage_block(vma, &pa, ctx); ++ cloned_pages++; ++ } else if (pa.type == PD_LAZY) { ++ dump_lazypage_block(vma, &pa, ctx); ++ } else if (pa.type == PD_ITER || pa.type == PD_ITERYOUNG) { ++ dump_iterpage_block(vma, &pa, ctx); ++ cloned_pages++; ++ } else if (pa.type == PD_ABSENT && ++ pa.pgoff != (pa.end - vma->vm_start)/PAGE_SIZE + vma->vm_pgoff - 1) { ++ dump_remappage_block(vma, &pa, ctx); ++ } ++ pa.start = addr; ++ } ++ pa.type = pd.type; ++ pa.end = addr + PAGE_SIZE; ++ pa.pgoff = pd.index; ++ if (addr == pa.start) ++ pa.list[0] = pd.index; ++ pa.mm = pd.mm; ++ } ++ ++ if (pa.end > pa.start) { ++ if (pa.type == PD_COPY || ++ pa.type == PD_ZERO) { ++ pgb.cpt_start = pa.start; ++ pgb.cpt_end = pa.end; ++ dump_page_block(vma, &pgb, pa.type, ctx); ++ } else if (pa.type == PD_CLONE) { ++ dump_copypage_block(vma, &pa, ctx); ++ cloned_pages++; ++ } else if (pa.type == PD_LAZY) { ++ dump_lazypage_block(vma, &pa, ctx); ++ } else if (pa.type == PD_ITER || pa.type == PD_ITERYOUNG) { ++ dump_iterpage_block(vma, &pa, ctx); ++ cloned_pages++; ++ } else if (pa.type == PD_ABSENT && ++ pa.pgoff != (pa.end - vma->vm_start)/PAGE_SIZE + vma->vm_pgoff - 1) { ++ dump_remappage_block(vma, &pa, ctx); ++ } ++ } ++ ++ if (cloned_pages) { ++ __u32 anonvma = 1; ++ loff_t anonpos = ctx->current_object + offsetof(struct cpt_vma_image, cpt_anonvma); ++ ctx->pwrite(&anonvma, 4, ctx, anonpos); ++ } ++ ++out: ++ cpt_close_object(ctx); ++ ++ cpt_pop_object(&saved_object, ctx); ++ ++ return 0; ++} ++ ++static int dump_one_aio_ctx(struct mm_struct *mm, struct kioctx *aio_ctx, ++ cpt_context_t *ctx) ++{ ++ loff_t saved_object; ++ struct cpt_aio_ctx_image aimg; ++ ++ if (!list_empty(&aio_ctx->run_list) || ++ !list_empty(&aio_ctx->active_reqs) || ++ aio_ctx->reqs_active) { ++ eprintk_ctx("AIO is active after suspend\n"); ++ return -EBUSY; ++ } ++ ++ cpt_push_object(&saved_object, ctx); ++ ++ aimg.cpt_next = CPT_ALIGN(sizeof(aimg)); ++ aimg.cpt_object = CPT_OBJ_AIO_CONTEXT; ++ aimg.cpt_hdrlen = sizeof(aimg); ++ aimg.cpt_content = CPT_CONTENT_ARRAY; ++ ++ aimg.cpt_max_reqs = aio_ctx->max_reqs; ++ aimg.cpt_ring_pages = aio_ctx->ring_info.nr_pages; ++ aimg.cpt_nr = aio_ctx->ring_info.nr; ++ aimg.cpt_tail = aio_ctx->ring_info.tail; ++ aimg.cpt_mmap_base = aio_ctx->ring_info.mmap_base; ++ ++ ctx->write(&aimg, sizeof(aimg), ctx); ++ ++ cpt_pop_object(&saved_object, ctx); ++ return 0; ++} ++ ++static int dump_one_mm(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ struct mm_struct *mm = obj->o_obj; ++ struct vm_area_struct *vma; ++ struct cpt_mm_image *v = cpt_get_buf(ctx); ++ ++ cpt_open_object(obj, ctx); ++ ++ v->cpt_next = -1; ++ v->cpt_object = CPT_OBJ_MM; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ v->cpt_start_code = mm->start_code; ++ v->cpt_end_code = mm->end_code; ++ v->cpt_start_data = mm->start_data; ++ v->cpt_end_data = mm->end_data; ++ v->cpt_start_brk = mm->start_brk; ++ v->cpt_brk = mm->brk; ++ v->cpt_start_stack = mm->start_stack; ++ v->cpt_start_arg = mm->arg_start; ++ v->cpt_end_arg = mm->arg_end; ++ v->cpt_start_env = mm->env_start; ++ v->cpt_end_env = mm->env_end; ++ v->cpt_def_flags = mm->def_flags; ++#ifdef CONFIG_BEANCOUNTERS ++ v->cpt_mmub = cpt_lookup_ubc(mm->mm_ub, ctx); ++#endif ++ /* FIXME when coredump mask exceeds 8 bits */ ++ WARN_ON(mm->flags >> 8); ++ v->cpt_dumpable = mm->flags; ++ v->cpt_vps_dumpable = mm->vps_dumpable; ++ v->cpt_used_hugetlb = 0; /* not used */ ++#ifndef CONFIG_IA64 ++ v->cpt_vdso = (__u32)(unsigned long)mm->context.vdso; ++#endif ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++#ifdef CONFIG_X86 ++ if (mm->context.size) { ++ loff_t saved_object; ++ struct cpt_obj_bits b; ++ int size; ++ ++ dprintk_ctx("nontrivial LDT\n"); ++ ++ cpt_push_object(&saved_object, ctx); ++ ++ cpt_open_object(NULL, ctx); ++ b.cpt_next = CPT_NULL; ++ b.cpt_object = CPT_OBJ_BITS; ++ b.cpt_hdrlen = sizeof(b); ++ b.cpt_content = CPT_CONTENT_MM_CONTEXT; ++ b.cpt_size = mm->context.size*LDT_ENTRY_SIZE; ++ ++ ctx->write(&b, sizeof(b), ctx); ++ ++ size = mm->context.size*LDT_ENTRY_SIZE; ++ ++#if defined(CONFIG_X86_64) || defined(CONFIG_XEN) || \ ++ LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++ ctx->write(mm->context.ldt, size, ctx); ++#else ++ for (i = 0; i < size; i += PAGE_SIZE) { ++ int nr = i / PAGE_SIZE, bytes; ++ char *kaddr = kmap(mm->context.ldt_pages[nr]); ++ ++ bytes = size - i; ++ if (bytes > PAGE_SIZE) ++ bytes = PAGE_SIZE; ++ ctx->write(kaddr, bytes, ctx); ++ kunmap(mm->context.ldt_pages[nr]); ++ } ++#endif ++ ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_object, ctx); ++ } ++#endif ++ ++ for (vma = mm->mmap; vma; vma = vma->vm_next) { ++ int err; ++ ++ if ((err = dump_one_vma(obj, vma, ctx)) != 0) ++ return err; ++ } ++ ++ if (mm->ioctx_list) { ++ struct kioctx *aio_ctx; ++ int err; ++ ++ for (aio_ctx = mm->ioctx_list; aio_ctx; aio_ctx = aio_ctx->next) ++ if ((err = dump_one_aio_ctx(mm, aio_ctx, ctx)) != 0) ++ return err; ++ } ++ ++ cpt_close_object(ctx); ++ ++ return 0; ++} ++ ++int cpt_dump_vm(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ scnt = scnt0 = zcnt = 0; ++ ++ cpt_open_section(ctx, CPT_SECT_MM); ++ ++ for_each_object(obj, CPT_OBJ_MM) { ++ int err; ++ ++ if ((err = dump_one_mm(obj, ctx)) != 0) ++ return err; ++ } ++ ++ cpt_close_section(ctx); ++ ++ if (scnt) ++ dprintk_ctx("cpt_dump_vm: %d shared private anon pages\n", scnt); ++ if (scnt0) ++ dprintk_ctx("cpt_dump_vm: %d anon pages are cloned\n", scnt0); ++ if (zcnt) ++ dprintk_ctx("cpt_dump_vm: %d silly pages canceled\n", zcnt); ++ return 0; ++} +Index: kernel/kernel/cpt/cpt_mm.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_mm.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,43 @@ ++int cpt_collect_mm(cpt_context_t *); ++ ++int cpt_dump_vm(struct cpt_context *ctx); ++ ++__u32 rst_mm_flag(struct cpt_task_image *ti, struct cpt_context *ctx); ++int rst_mm_basic(cpt_object_t *obj, struct cpt_task_image *ti, struct cpt_context *ctx); ++int rst_mm_complete(struct cpt_task_image *ti, struct cpt_context *ctx); ++ ++int cpt_mm_prepare(unsigned long veid); ++ ++int cpt_free_pgin_dir(struct cpt_context *); ++int cpt_start_pagein(struct cpt_context *); ++int rst_setup_pagein(struct cpt_context *); ++int rst_complete_pagein(struct cpt_context *, int); ++int rst_pageind(struct cpt_context *); ++int cpt_iteration(cpt_context_t *ctx); ++int rst_iteration(cpt_context_t *ctx); ++void rst_drop_iter_dir(cpt_context_t *ctx); ++int rst_iter(struct vm_area_struct *vma, u64 pfn, ++ unsigned long addr, cpt_context_t * ctx); ++ ++int rst_swapoff(struct cpt_context *); ++ ++#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES ++struct linux_binprm; ++extern int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack, ++ unsigned long map_address); ++#endif ++ ++#ifdef CONFIG_X86_64 ++extern char *syscall32_page; ++#define vsyscall_addr syscall32_page ++#define CPT_SYSENTER_RETURN VSYSCALL32_SYSEXIT ++#elif defined(CONFIG_X86_32) ++extern void *syscall_page; ++extern struct vm_operations_struct syscall_vm_ops; ++extern void SYSENTER_RETURN; ++#define vsyscall_addr syscall_page ++#define CPT_SYSENTER_RETURN (current->mm->context.vdso + \ ++ (unsigned long)&SYSENTER_RETURN) ++#endif ++ ++extern struct vm_operations_struct special_mapping_vmops; +Index: kernel/kernel/cpt/cpt_net.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_net.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,518 @@ ++/* ++ * ++ * kernel/cpt/cpt_net.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_kernel.h" ++#include "cpt_syscalls.h" ++ ++static void cpt_dump_tuntap(struct net_device *dev, struct cpt_context * ctx) ++{ ++#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) ++ struct cpt_tuntap_image v; ++ struct tun_struct *tun; ++ cpt_object_t *obj; ++ ++ if (dev->open != tun_net_open) ++ return; ++ ++ tun = netdev_priv(dev); ++ cpt_open_object(NULL, ctx); ++ ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_NET_TUNTAP; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_VOID; ++ ++ v.cpt_owner = tun->owner; ++ v.cpt_flags = tun->flags; ++ v.cpt_attached = tun->attached; ++ ++ if (tun->bind_file) { ++ obj = lookup_cpt_object(CPT_OBJ_FILE, tun->bind_file, ctx); ++ BUG_ON(!obj); ++ v.cpt_bindfile = obj->o_pos; ++ } ++ ++ v.cpt_if_flags = tun->if_flags; ++ BUG_ON(sizeof(v.cpt_dev_addr) != sizeof(tun->dev_addr)); ++ memcpy(v.cpt_dev_addr, tun->dev_addr, sizeof(v.cpt_dev_addr)); ++ BUG_ON(sizeof(v.cpt_chr_filter) != sizeof(tun->chr_filter)); ++ memcpy(v.cpt_chr_filter, tun->chr_filter, sizeof(v.cpt_chr_filter)); ++ BUG_ON(sizeof(v.cpt_net_filter) != sizeof(tun->net_filter)); ++ memcpy(v.cpt_net_filter, tun->net_filter, sizeof(v.cpt_net_filter)); ++ ctx->write(&v, sizeof(v), ctx); ++ cpt_close_object(ctx); ++#endif ++ return; ++} ++ ++int cpt_dump_link(struct cpt_context * ctx) ++{ ++ struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net_device *dev; ++ ++ cpt_open_section(ctx, CPT_SECT_NET_DEVICE); ++ for_each_netdev(net, dev) { ++ struct cpt_netdev_image v; ++ loff_t saved_obj; ++ ++ cpt_open_object(NULL, ctx); ++ ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_NET_DEVICE; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_ARRAY; ++ ++ v.cpt_index = dev->ifindex; ++ v.cpt_flags = dev->flags; ++ memcpy(v.cpt_name, dev->name, IFNAMSIZ); ++ ctx->write(&v, sizeof(v), ctx); ++ ++ cpt_push_object(&saved_obj, ctx); ++ cpt_dump_tuntap(dev, ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ ++ cpt_close_object(ctx); ++ ++ if (dev != net->loopback_dev ++#if defined(CONFIG_VE_ETHDEV) || defined(CONFIG_VE_ETHDEV_MODULE) ++ && !(KSYMREF(veth_open) && dev->open == KSYMREF(veth_open)) ++#endif ++#if defined(CONFIG_VE_NETDEV) || defined(CONFIG_VE_NETDEV_MODULE) ++ && dev != get_exec_env()->_venet_dev ++#endif ++#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) ++ && dev->open != tun_net_open ++#endif ++ ) { ++ eprintk_ctx("unsupported netdevice %s\n", dev->name); ++ cpt_close_section(ctx); ++ return -EBUSY; ++ } ++ } ++ cpt_close_section(ctx); ++ return 0; ++} ++ ++int cpt_suspend_network(struct cpt_context *ctx) ++{ ++ get_exec_env()->disable_net = 1; ++ synchronize_net(); ++ return 0; ++} ++ ++int cpt_resume_network(struct cpt_context *ctx) ++{ ++ struct ve_struct *env; ++ env = get_ve_by_id(ctx->ve_id); ++ if (!env) ++ return -ESRCH; ++ env->disable_net = 0; ++ put_ve(env); ++ return 0; ++} ++ ++int cpt_dump_ifaddr(struct cpt_context * ctx) ++{ ++ struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net_device *dev; ++ ++ cpt_open_section(ctx, CPT_SECT_NET_IFADDR); ++ for_each_netdev(net, dev) { ++ struct in_device *idev = in_dev_get(dev); ++ struct in_ifaddr *ifa; ++ ++ if (!idev) ++ continue; ++ ++ for (ifa = idev->ifa_list; ifa; ifa = ifa->ifa_next) { ++ struct cpt_ifaddr_image v; ++ cpt_open_object(NULL, ctx); ++ ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_NET_IFADDR; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_VOID; ++ ++ v.cpt_index = dev->ifindex; ++ v.cpt_family = AF_INET; ++ v.cpt_masklen = ifa->ifa_prefixlen; ++ v.cpt_flags = ifa->ifa_flags; ++ v.cpt_scope = ifa->ifa_scope; ++ memset(&v.cpt_address, 0, sizeof(v.cpt_address)); ++ memset(&v.cpt_peer, 0, sizeof(v.cpt_peer)); ++ memset(&v.cpt_broadcast, 0, sizeof(v.cpt_broadcast)); ++ v.cpt_address[0] = ifa->ifa_local; ++ v.cpt_peer[0] = ifa->ifa_address; ++ v.cpt_broadcast[0] = ifa->ifa_broadcast; ++ memcpy(v.cpt_label, ifa->ifa_label, IFNAMSIZ); ++ ctx->write(&v, sizeof(v), ctx); ++ cpt_close_object(ctx); ++ } ++ in_dev_put(idev); ++ } ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ for_each_netdev(net, dev) { ++ struct inet6_dev *idev = in6_dev_get(dev); ++ struct inet6_ifaddr *ifa; ++ ++ if (!idev) ++ continue; ++ ++ for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) { ++ struct cpt_ifaddr_image v; ++ ++ if (dev == net->loopback_dev && ++ ifa->prefix_len == 128 && ++ ifa->addr.s6_addr32[0] == 0 && ++ ifa->addr.s6_addr32[1] == 0 && ++ ifa->addr.s6_addr32[2] == 0 && ++ ifa->addr.s6_addr32[3] == htonl(1)) ++ continue; ++ ++ cpt_open_object(NULL, ctx); ++ ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_NET_IFADDR; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_VOID; ++ ++ v.cpt_index = dev->ifindex; ++ v.cpt_family = AF_INET6; ++ v.cpt_masklen = ifa->prefix_len; ++ v.cpt_flags = ifa->flags; ++ v.cpt_scope = ifa->scope; ++ v.cpt_valid_lft = ifa->valid_lft; ++ v.cpt_prefered_lft = ifa->prefered_lft; ++ memcpy(&v.cpt_address, &ifa->addr, 16); ++ memcpy(&v.cpt_peer, &ifa->addr, 16); ++ memset(&v.cpt_broadcast, 0, sizeof(v.cpt_broadcast)); ++ memcpy(v.cpt_label, dev->name, IFNAMSIZ); ++ ctx->write(&v, sizeof(v), ctx); ++ cpt_close_object(ctx); ++ } ++ in6_dev_put(idev); ++ } ++#endif ++ cpt_close_section(ctx); ++ return 0; ++} ++ ++static int cpt_dump_route(struct cpt_context * ctx) ++{ ++ int err; ++ struct socket *sock; ++ struct msghdr msg; ++ struct iovec iov; ++ struct { ++ struct nlmsghdr nlh; ++ struct rtgenmsg g; ++ } req; ++ struct sockaddr_nl nladdr; ++ struct cpt_object_hdr v; ++ mm_segment_t oldfs; ++ char *pg; ++ ++ err = sock_create_kern(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, &sock); ++ if (err) ++ return err; ++ ++ memset(&nladdr, 0, sizeof(nladdr)); ++ nladdr.nl_family = AF_NETLINK; ++ ++ req.nlh.nlmsg_len = sizeof(req); ++ req.nlh.nlmsg_type = RTM_GETROUTE; ++ req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; ++ req.nlh.nlmsg_pid = 0; ++ req.g.rtgen_family = AF_INET; ++ ++ iov.iov_base=&req; ++ iov.iov_len=sizeof(req); ++ msg.msg_name=&nladdr; ++ msg.msg_namelen=sizeof(nladdr); ++ msg.msg_iov=&iov; ++ msg.msg_iovlen=1; ++ msg.msg_control=NULL; ++ msg.msg_controllen=0; ++ msg.msg_flags=MSG_DONTWAIT; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ err = sock_sendmsg(sock, &msg, sizeof(req)); ++ set_fs(oldfs); ++ ++ if (err < 0) ++ goto out_sock; ++ ++ pg = (char*)__get_free_page(GFP_KERNEL); ++ if (pg == NULL) { ++ err = -ENOMEM; ++ goto out_sock; ++ } ++ ++ cpt_open_section(ctx, CPT_SECT_NET_ROUTE); ++ cpt_open_object(NULL, ctx); ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_NET_ROUTE; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_NLMARRAY; ++ ++ ctx->write(&v, sizeof(v), ctx); ++ ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++restart: ++#endif ++ for (;;) { ++ struct nlmsghdr *h; ++ ++ iov.iov_base = pg; ++ iov.iov_len = PAGE_SIZE; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ err = sock_recvmsg(sock, &msg, PAGE_SIZE, MSG_DONTWAIT); ++ set_fs(oldfs); ++ ++ if (err < 0) ++ goto out_sock_pg; ++ if (msg.msg_flags & MSG_TRUNC) { ++ err = -ENOBUFS; ++ goto out_sock_pg; ++ } ++ ++ h = (struct nlmsghdr*)pg; ++ while (NLMSG_OK(h, err)) { ++ if (h->nlmsg_type == NLMSG_DONE) { ++ err = 0; ++ goto done; ++ } ++ if (h->nlmsg_type == NLMSG_ERROR) { ++ struct nlmsgerr *errm = (struct nlmsgerr*)NLMSG_DATA(h); ++ err = errm->error; ++ eprintk_ctx("NLMSG error: %d\n", errm->error); ++ goto done; ++ } ++ if (h->nlmsg_type != RTM_NEWROUTE) { ++ eprintk_ctx("NLMSG: %d\n", h->nlmsg_type); ++ err = -EINVAL; ++ goto done; ++ } ++ ctx->write(h, NLMSG_ALIGN(h->nlmsg_len), ctx); ++ h = NLMSG_NEXT(h, err); ++ } ++ if (err) { ++ eprintk_ctx("!!!Remnant of size %d %d %d\n", err, h->nlmsg_len, h->nlmsg_type); ++ err = -EINVAL; ++ break; ++ } ++ } ++done: ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ if (!err && req.g.rtgen_family == AF_INET) { ++ req.g.rtgen_family = AF_INET6; ++ iov.iov_base=&req; ++ iov.iov_len=sizeof(req); ++ msg.msg_name=&nladdr; ++ msg.msg_namelen=sizeof(nladdr); ++ msg.msg_iov=&iov; ++ msg.msg_iovlen=1; ++ msg.msg_control=NULL; ++ msg.msg_controllen=0; ++ msg.msg_flags=MSG_DONTWAIT; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ err = sock_sendmsg(sock, &msg, sizeof(req)); ++ set_fs(oldfs); ++ ++ if (err > 0) ++ goto restart; ++ } ++#endif ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ cpt_close_section(ctx); ++ ++out_sock_pg: ++ free_page((unsigned long)pg); ++out_sock: ++ sock_release(sock); ++ return err; ++} ++ ++static int dumpfn(void *arg) ++{ ++ int i; ++ int *pfd = arg; ++ char *argv[] = { "iptables-save", "-c", NULL }; ++ ++ i = real_env_create(VEID(get_exec_env()), VE_ENTER|VE_SKIPLOCK, 2, NULL, 0); ++ if (i < 0) { ++ eprintk("cannot enter ve to dump iptables\n"); ++ module_put(THIS_MODULE); ++ return 255 << 8; ++ } ++ ++ if (pfd[1] != 1) ++ sc_dup2(pfd[1], 1); ++ ++ for (i=0; ifiles->fdt->max_fds; i++) { ++ if (i != 1) ++ sc_close(i); ++ } ++ ++ module_put(THIS_MODULE); ++ ++ set_fs(KERNEL_DS); ++ i = sc_execve("/sbin/iptables-save", argv, NULL); ++ if (i == -ENOENT) ++ i = sc_execve("/usr/sbin/iptables-save", argv, NULL); ++ eprintk("failed to exec iptables-save: %d\n", i); ++ return 255 << 8; ++} ++ ++ ++static int cpt_dump_iptables(struct cpt_context * ctx) ++{ ++ int err = 0; ++#ifdef CONFIG_VE_IPTABLES ++ int pid; ++ int pfd[2]; ++ struct file *f; ++ struct cpt_object_hdr v; ++ char buf[16]; ++ loff_t pos; ++ int n; ++ int status; ++ mm_segment_t oldfs; ++ sigset_t ignore, blocked; ++ ++ if (!(get_exec_env()->_iptables_modules & VE_IP_IPTABLES_MOD)) ++ return 0; ++ ++ err = sc_pipe(pfd); ++ if (err < 0) { ++ eprintk_ctx("sc_pipe: %d\n", err); ++ return err; ++ } ++ ignore.sig[0] = CPT_SIG_IGNORE_MASK; ++ sigprocmask(SIG_BLOCK, &ignore, &blocked); ++ err = pid = local_kernel_thread(dumpfn, (void*)pfd, SIGCHLD, 0); ++ if (err < 0) { ++ eprintk_ctx("local_kernel_thread: %d\n", err); ++ goto out; ++ } ++ ++ f = fget(pfd[0]); ++ sc_close(pfd[1]); ++ sc_close(pfd[0]); ++ ++ cpt_open_section(ctx, CPT_SECT_NET_IPTABLES); ++ ++ cpt_open_object(NULL, ctx); ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_NAME; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_NAME; ++ ++ ctx->write(&v, sizeof(v), ctx); ++ ++ pos = ctx->file->f_pos; ++ do { ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ n = f->f_op->read(f, buf, sizeof(buf), &f->f_pos); ++ set_fs(oldfs); ++ if (n > 0) ++ ctx->write(buf, n, ctx); ++ } while (n > 0); ++ ++ if (n < 0) ++ eprintk_ctx("read: %d\n", n); ++ ++ fput(f); ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ if ((err = sc_waitx(pid, 0, &status)) < 0) ++ eprintk_ctx("wait4: %d\n", err); ++ else if ((status & 0x7f) == 0) { ++ err = (status & 0xff00) >> 8; ++ if (err != 0) { ++ eprintk_ctx("iptables-save exited with %d\n", err); ++ err = -EINVAL; ++ } ++ } else { ++ eprintk_ctx("iptables-save terminated\n"); ++ err = -EINVAL; ++ } ++ set_fs(oldfs); ++ sigprocmask(SIG_SETMASK, &blocked, NULL); ++ ++ if (ctx->file->f_pos != pos) { ++ buf[0] = 0; ++ ctx->write(buf, 1, ctx); ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ cpt_close_section(ctx); ++ } else { ++ pos = ctx->current_section; ++ cpt_close_object(ctx); ++ cpt_close_section(ctx); ++ ctx->sections[CPT_SECT_NET_IPTABLES] = CPT_NULL; ++ ctx->file->f_pos = pos; ++ } ++ return n ? : err; ++ ++out: ++ if (pfd[1] >= 0) ++ sc_close(pfd[1]); ++ if (pfd[0] >= 0) ++ sc_close(pfd[0]); ++ sigprocmask(SIG_SETMASK, &blocked, NULL); ++#endif ++ return err; ++} ++ ++int cpt_dump_ifinfo(struct cpt_context * ctx) ++{ ++ int err; ++ ++ rtnl_lock(); ++ err = cpt_dump_link(ctx); ++ if (!err) ++ err = cpt_dump_ifaddr(ctx); ++ rtnl_unlock(); ++ if (!err) ++ err = cpt_dump_route(ctx); ++ if (!err) ++ err = cpt_dump_iptables(ctx); ++ return err; ++} +Index: kernel/kernel/cpt/cpt_net.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_net.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,7 @@ ++int cpt_dump_ifinfo(struct cpt_context *ctx); ++int rst_restore_net(struct cpt_context *ctx); ++int cpt_suspend_network(struct cpt_context *ctx); ++int cpt_resume_network(struct cpt_context *ctx); ++int rst_resume_network(struct cpt_context *ctx); ++int cpt_dump_ip_conntrack(struct cpt_context *ctx); ++int rst_restore_ip_conntrack(struct cpt_context * ctx); +Index: kernel/kernel/cpt/cpt_obj.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_obj.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,162 @@ ++/* ++ * ++ * kernel/cpt/cpt_obj.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++ ++cpt_object_t *alloc_cpt_object(int gfp, struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ obj = kmalloc(sizeof(cpt_object_t), gfp); ++ if (obj) { ++ INIT_LIST_HEAD(&obj->o_list); ++ INIT_LIST_HEAD(&obj->o_hash); ++ INIT_LIST_HEAD(&obj->o_alist); ++ obj->o_count = 1; ++ obj->o_pos = CPT_NULL; ++ obj->o_lock = 0; ++ obj->o_parent = NULL; ++ obj->o_index = CPT_NOINDEX; ++ obj->o_obj = NULL; ++ obj->o_image = NULL; ++ ctx->objcount++; ++ } ++ return obj; ++} ++ ++void free_cpt_object(cpt_object_t *obj, cpt_context_t *ctx) ++{ ++ list_del(&obj->o_alist); ++ kfree(obj); ++ ctx->objcount--; ++} ++ ++void intern_cpt_object(enum _cpt_object_type type, cpt_object_t *obj, cpt_context_t *ctx) ++{ ++ list_add_tail(&obj->o_list, &ctx->object_array[type]); ++} ++ ++void insert_cpt_object(enum _cpt_object_type type, cpt_object_t *obj, ++ cpt_object_t *head, cpt_context_t *ctx) ++{ ++ list_add(&obj->o_list, &head->o_list); ++} ++ ++cpt_object_t * __cpt_object_add(enum _cpt_object_type type, void *p, ++ unsigned gfp_mask, cpt_context_t *ctx) ++{ ++ cpt_object_t *obj; ++ ++ obj = lookup_cpt_object(type, p, ctx); ++ ++ if (obj) { ++ obj->o_count++; ++ return obj; ++ } ++ ++ if ((obj = alloc_cpt_object(gfp_mask, ctx)) != NULL) { ++ if (p) ++ cpt_obj_setobj(obj, p, ctx); ++ intern_cpt_object(type, obj, ctx); ++ return obj; ++ } ++ return NULL; ++} ++ ++cpt_object_t * cpt_object_add(enum _cpt_object_type type, void *p, cpt_context_t *ctx) ++{ ++ return __cpt_object_add(type, p, GFP_KERNEL, ctx); ++} ++ ++cpt_object_t * cpt_object_get(enum _cpt_object_type type, void *p, cpt_context_t *ctx) ++{ ++ cpt_object_t *obj; ++ ++ obj = lookup_cpt_object(type, p, ctx); ++ ++ if (obj) ++ obj->o_count++; ++ ++ return obj; ++} ++ ++int cpt_object_init(cpt_context_t *ctx) ++{ ++ int i; ++ ++ for (i=0; iobject_array[i]); ++ } ++ return 0; ++} ++ ++int cpt_object_destroy(cpt_context_t *ctx) ++{ ++ int i; ++ ++ for (i=0; iobject_array[i])) { ++ struct list_head *head = ctx->object_array[i].next; ++ cpt_object_t *obj = list_entry(head, cpt_object_t, o_list); ++ list_del(head); ++ if (obj->o_image) ++ kfree(obj->o_image); ++ free_cpt_object(obj, ctx); ++ } ++ } ++ if (ctx->objcount != 0) ++ eprintk_ctx("BUG: ctx->objcount=%d\n", ctx->objcount); ++ return 0; ++} ++ ++cpt_object_t *lookup_cpt_object(enum _cpt_object_type type, void *p, struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ for_each_object(obj, type) { ++ if (obj->o_obj == p) ++ return obj; ++ } ++ return NULL; ++} ++ ++cpt_object_t *lookup_cpt_obj_bypos(enum _cpt_object_type type, loff_t pos, struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ for_each_object(obj, type) { ++ if (obj->o_pos == pos) ++ return obj; ++ } ++ return NULL; ++} ++ ++cpt_object_t *lookup_cpt_obj_byindex(enum _cpt_object_type type, __u32 index, struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ for_each_object(obj, type) { ++ if (obj->o_index == index) ++ return obj; ++ } ++ return NULL; ++} +Index: kernel/kernel/cpt/cpt_obj.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_obj.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,62 @@ ++#ifndef __CPT_OBJ_H_ ++#define __CPT_OBJ_H_ 1 ++ ++#include ++#include ++ ++typedef struct _cpt_object ++{ ++ struct list_head o_list; ++ struct list_head o_hash; ++ int o_count; ++ int o_index; ++ int o_lock; ++ loff_t o_pos; ++ loff_t o_ppos; ++ void *o_obj; ++ void *o_image; ++ void *o_parent; ++ struct list_head o_alist; ++} cpt_object_t; ++ ++struct cpt_context; ++ ++#define for_each_object(obj, type) list_for_each_entry(obj, &ctx->object_array[type], o_list) ++ ++ ++extern cpt_object_t *alloc_cpt_object(int gfp, struct cpt_context *ctx); ++extern void free_cpt_object(cpt_object_t *obj, struct cpt_context *ctx); ++ ++cpt_object_t *lookup_cpt_object(enum _cpt_object_type type, void *p, struct cpt_context *ctx); ++cpt_object_t *lookup_cpt_obj_bypos(enum _cpt_object_type type, loff_t pos, struct cpt_context *ctx); ++cpt_object_t *lookup_cpt_obj_byindex(enum _cpt_object_type type, __u32 index, struct cpt_context *ctx); ++ ++static inline void cpt_obj_setpos(cpt_object_t *cpt, loff_t pos, struct cpt_context *ctx) ++{ ++ cpt->o_pos = pos; ++ /* Add to pos hash table */ ++} ++ ++static inline void cpt_obj_setobj(cpt_object_t *cpt, void *ptr, struct cpt_context *ctx) ++{ ++ cpt->o_obj = ptr; ++ /* Add to hash table */ ++} ++ ++static inline void cpt_obj_setindex(cpt_object_t *cpt, __u32 index, struct cpt_context *ctx) ++{ ++ cpt->o_index = index; ++ /* Add to index hash table */ ++} ++ ++ ++extern void intern_cpt_object(enum _cpt_object_type type, cpt_object_t *obj, struct cpt_context *ctx); ++extern void insert_cpt_object(enum _cpt_object_type type, cpt_object_t *obj, cpt_object_t *head, struct cpt_context *ctx); ++extern cpt_object_t *cpt_object_add(enum _cpt_object_type type, void *p, struct cpt_context *ctx); ++extern cpt_object_t *__cpt_object_add(enum _cpt_object_type type, void *p, unsigned int gfp_mask, struct cpt_context *ctx); ++extern cpt_object_t *cpt_object_get(enum _cpt_object_type type, void *p, struct cpt_context *ctx); ++ ++extern int cpt_object_init(struct cpt_context *ctx); ++extern int cpt_object_destroy(struct cpt_context *ctx); ++ ++#endif /* __CPT_OBJ_H_ */ +Index: kernel/kernel/cpt/cpt_proc.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_proc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,596 @@ ++/* ++ * ++ * kernel/cpt/cpt_proc.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_dump.h" ++#include "cpt_mm.h" ++#include "cpt_kernel.h" ++ ++MODULE_AUTHOR("Alexey Kuznetsov "); ++MODULE_LICENSE("GPL"); ++ ++/* List of contexts and lock protecting the list */ ++static struct list_head cpt_context_list; ++static spinlock_t cpt_context_lock; ++ ++static int proc_read(char *buffer, char **start, off_t offset, ++ int length, int *eof, void *data) ++{ ++ off_t pos = 0; ++ off_t begin = 0; ++ int len = 0; ++ cpt_context_t *ctx; ++ ++ len += sprintf(buffer, "Ctx Id VE State\n"); ++ ++ spin_lock(&cpt_context_lock); ++ ++ list_for_each_entry(ctx, &cpt_context_list, ctx_list) { ++ len += sprintf(buffer+len,"%p %08x %-8u %d", ++ ctx, ++ ctx->contextid, ++ ctx->ve_id, ++ ctx->ctx_state ++ ); ++ ++ buffer[len++] = '\n'; ++ ++ pos = begin+len; ++ if (pos < offset) { ++ len = 0; ++ begin = pos; ++ } ++ if (pos > offset+length) ++ goto done; ++ } ++ *eof = 1; ++ ++done: ++ spin_unlock(&cpt_context_lock); ++ *start = buffer + (offset - begin); ++ len -= (offset - begin); ++ if(len > length) ++ len = length; ++ if(len < 0) ++ len = 0; ++ return len; ++} ++ ++void cpt_context_release(cpt_context_t *ctx) ++{ ++ list_del(&ctx->ctx_list); ++ spin_unlock(&cpt_context_lock); ++ ++ if (ctx->ctx_state > 0) ++ cpt_resume(ctx); ++ ctx->ctx_state = CPT_CTX_ERROR; ++ ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ if (ctx->pgin_task) ++ put_task_struct(ctx->pgin_task); ++ if (ctx->pgin_dir) ++ cpt_free_pgin_dir(ctx); ++ if (ctx->pagein_file_out) ++ fput(ctx->pagein_file_out); ++ if (ctx->pagein_file_in) ++ fput(ctx->pagein_file_in); ++#endif ++ if (ctx->objcount) ++ eprintk_ctx("%d objects leaked\n", ctx->objcount); ++ if (ctx->file) ++ fput(ctx->file); ++ cpt_flush_error(ctx); ++ if (ctx->errorfile) { ++ fput(ctx->errorfile); ++ ctx->errorfile = NULL; ++ } ++ if (ctx->error_msg) { ++ free_page((unsigned long)ctx->error_msg); ++ ctx->error_msg = NULL; ++ } ++ if (ctx->statusfile) ++ fput(ctx->statusfile); ++ if (ctx->lockfile) ++ fput(ctx->lockfile); ++ kfree(ctx); ++ ++ spin_lock(&cpt_context_lock); ++} ++ ++static void __cpt_context_put(cpt_context_t *ctx) ++{ ++ if (!--ctx->refcount) ++ cpt_context_release(ctx); ++} ++ ++static void cpt_context_put(cpt_context_t *ctx) ++{ ++ spin_lock(&cpt_context_lock); ++ __cpt_context_put(ctx); ++ spin_unlock(&cpt_context_lock); ++} ++ ++cpt_context_t * cpt_context_open(void) ++{ ++ cpt_context_t *ctx; ++ ++ if ((ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)) != NULL) { ++ cpt_context_init(ctx); ++ spin_lock(&cpt_context_lock); ++ list_add_tail(&ctx->ctx_list, &cpt_context_list); ++ spin_unlock(&cpt_context_lock); ++ ctx->error_msg = (char*)__get_free_page(GFP_KERNEL); ++ if (ctx->error_msg != NULL) ++ ctx->error_msg[0] = 0; ++ } ++ return ctx; ++} ++ ++static cpt_context_t * cpt_context_lookup(unsigned int contextid) ++{ ++ cpt_context_t *ctx; ++ ++ spin_lock(&cpt_context_lock); ++ list_for_each_entry(ctx, &cpt_context_list, ctx_list) { ++ if (ctx->contextid == contextid) { ++ ctx->refcount++; ++ spin_unlock(&cpt_context_lock); ++ return ctx; ++ } ++ } ++ spin_unlock(&cpt_context_lock); ++ return NULL; ++} ++ ++int cpt_context_lookup_veid(unsigned int veid) ++{ ++ cpt_context_t *ctx; ++ ++ spin_lock(&cpt_context_lock); ++ list_for_each_entry(ctx, &cpt_context_list, ctx_list) { ++ if (ctx->ve_id == veid && ctx->ctx_state > 0) { ++ spin_unlock(&cpt_context_lock); ++ return 1; ++ } ++ } ++ spin_unlock(&cpt_context_lock); ++ return 0; ++} ++ ++static int cpt_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) ++{ ++ int err = 0; ++ cpt_context_t *ctx; ++ struct file *dfile = NULL; ++ int try; ++ ++ unlock_kernel(); ++ ++ if (cmd == CPT_VMPREP) { ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ err = cpt_mm_prepare(arg); ++#else ++ err = -EINVAL; ++#endif ++ goto out_lock; ++ } ++ ++ if (cmd == CPT_TEST_CAPS) { ++ unsigned int src_flags, dst_flags = arg; ++ ++ err = 0; ++ src_flags = test_cpu_caps(); ++ test_one_flag_old(src_flags, dst_flags, CPT_CPU_X86_CMOV, "cmov", err); ++ test_one_flag_old(src_flags, dst_flags, CPT_CPU_X86_FXSR, "fxsr", err); ++ test_one_flag_old(src_flags, dst_flags, CPT_CPU_X86_SSE, "sse", err); ++ test_one_flag_old(src_flags, dst_flags, CPT_CPU_X86_SSE2, "sse2", err); ++ test_one_flag_old(src_flags, dst_flags, CPT_CPU_X86_MMX, "mmx", err); ++ test_one_flag_old(src_flags, dst_flags, CPT_CPU_X86_3DNOW, "3dnow", err); ++ test_one_flag_old(src_flags, dst_flags, CPT_CPU_X86_3DNOW2, "3dnowext", err); ++ test_one_flag_old(src_flags, dst_flags, CPT_CPU_X86_SEP, "sysenter", err); ++ goto out_lock; ++ } ++ ++ if (cmd == CPT_JOIN_CONTEXT || cmd == CPT_PUT_CONTEXT) { ++ cpt_context_t *old_ctx; ++ ++ ctx = NULL; ++ if (cmd == CPT_JOIN_CONTEXT) { ++ err = -ENOENT; ++ ctx = cpt_context_lookup(arg); ++ if (!ctx) ++ goto out_lock; ++ } ++ ++ spin_lock(&cpt_context_lock); ++ old_ctx = (cpt_context_t*)file->private_data; ++ file->private_data = ctx; ++ ++ if (old_ctx) { ++ if (cmd == CPT_PUT_CONTEXT && old_ctx->sticky) { ++ old_ctx->sticky = 0; ++ old_ctx->refcount--; ++ } ++ __cpt_context_put(old_ctx); ++ } ++ spin_unlock(&cpt_context_lock); ++ err = 0; ++ goto out_lock; ++ } ++ ++ spin_lock(&cpt_context_lock); ++ ctx = (cpt_context_t*)file->private_data; ++ if (ctx) ++ ctx->refcount++; ++ spin_unlock(&cpt_context_lock); ++ ++ if (!ctx) { ++ cpt_context_t *old_ctx; ++ ++ err = -ENOMEM; ++ ctx = cpt_context_open(); ++ if (!ctx) ++ goto out_lock; ++ ++ spin_lock(&cpt_context_lock); ++ old_ctx = (cpt_context_t*)file->private_data; ++ if (!old_ctx) { ++ ctx->refcount++; ++ file->private_data = ctx; ++ } else { ++ old_ctx->refcount++; ++ } ++ if (old_ctx) { ++ __cpt_context_put(ctx); ++ ctx = old_ctx; ++ } ++ spin_unlock(&cpt_context_lock); ++ } ++ ++ if (cmd == CPT_GET_CONTEXT) { ++ unsigned int contextid = (unsigned int)arg; ++ ++ if (ctx->contextid && ctx->contextid != contextid) { ++ err = -EINVAL; ++ goto out_nosem; ++ } ++ if (!ctx->contextid) { ++ cpt_context_t *c1 = cpt_context_lookup(contextid); ++ if (c1) { ++ cpt_context_put(c1); ++ err = -EEXIST; ++ goto out_nosem; ++ } ++ ctx->contextid = contextid; ++ } ++ spin_lock(&cpt_context_lock); ++ if (!ctx->sticky) { ++ ctx->sticky = 1; ++ ctx->refcount++; ++ } ++ spin_unlock(&cpt_context_lock); ++ goto out_nosem; ++ } ++ ++ down(&ctx->main_sem); ++ ++ err = -EBUSY; ++ if (ctx->ctx_state < 0) ++ goto out; ++ ++ err = 0; ++ switch (cmd) { ++ case CPT_SET_DUMPFD: ++ if (ctx->ctx_state == CPT_CTX_DUMPING) { ++ err = -EBUSY; ++ break; ++ } ++ if (arg >= 0) { ++ err = -EBADF; ++ dfile = fget(arg); ++ if (dfile == NULL) ++ break; ++ if (dfile->f_op == NULL || ++ dfile->f_op->write == NULL) { ++ fput(dfile); ++ break; ++ } ++ err = 0; ++ } ++ if (ctx->file) ++ fput(ctx->file); ++ ctx->file = dfile; ++ break; ++ case CPT_SET_ERRORFD: ++ if (arg >= 0) { ++ dfile = fget(arg); ++ if (dfile == NULL) { ++ err = -EBADF; ++ break; ++ } ++ } ++ if (ctx->errorfile) ++ fput(ctx->errorfile); ++ ctx->errorfile = dfile; ++ break; ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ case CPT_SET_PAGEINFDIN: ++ if (arg >= 0) { ++ dfile = fget(arg); ++ if (dfile == NULL) { ++ err = -EBADF; ++ break; ++ } ++ } ++ if (ctx->pagein_file_in) ++ fput(ctx->pagein_file_in); ++ ctx->pagein_file_in = dfile; ++ break; ++ case CPT_SET_PAGEINFDOUT: ++ if (arg >= 0) { ++ dfile = fget(arg); ++ if (dfile == NULL) { ++ err = -EBADF; ++ break; ++ } ++ } ++ if (ctx->pagein_file_out) ++ fput(ctx->pagein_file_out); ++ ctx->pagein_file_out = dfile; ++ break; ++ case CPT_SET_LAZY: ++ ctx->lazy_vm = arg; ++ break; ++ case CPT_ITER: ++ err = cpt_iteration(ctx); ++ break; ++ case CPT_PAGEIND: ++ err = cpt_start_pagein(ctx); ++ break; ++#endif ++ case CPT_SET_VEID: ++ if (ctx->ctx_state > 0) { ++ err = -EBUSY; ++ break; ++ } ++ ctx->ve_id = arg; ++ break; ++ case CPT_SET_CPU_FLAGS: ++ if (ctx->ctx_state > 0) { ++ err = -EBUSY; ++ break; ++ } ++ ctx->dst_cpu_flags = arg; ++ ctx->src_cpu_flags = test_cpu_caps(); ++ break; ++ case CPT_SUSPEND: ++ if (cpt_context_lookup_veid(ctx->ve_id) || ++ ctx->ctx_state > 0) { ++ err = -EBUSY; ++ break; ++ } ++ ctx->ctx_state = CPT_CTX_SUSPENDING; ++ try = 0; ++ do { ++ err = cpt_vps_suspend(ctx); ++ if (err) ++ cpt_resume(ctx); ++ if (err == -EAGAIN) ++ msleep(1000); ++ try++; ++ } while (err == -EAGAIN && try < 3); ++ if (err) { ++ ctx->ctx_state = CPT_CTX_IDLE; ++ } else { ++ ctx->ctx_state = CPT_CTX_SUSPENDED; ++ } ++ break; ++ case CPT_DUMP: ++ if (!ctx->ctx_state) { ++ err = -ENOENT; ++ break; ++ } ++ if (!ctx->file) { ++ err = -EBADF; ++ break; ++ } ++ err = cpt_dump(ctx); ++ break; ++ case CPT_RESUME: ++ if (ctx->ctx_state == CPT_CTX_IDLE) { ++ err = -ENOENT; ++ break; ++ } ++ err = cpt_resume(ctx); ++ if (!err) ++ ctx->ctx_state = CPT_CTX_IDLE; ++ break; ++ case CPT_KILL: ++ if (ctx->ctx_state == CPT_CTX_IDLE) { ++ err = -ENOENT; ++ break; ++ } ++ err = cpt_kill(ctx); ++ if (!err) ++ ctx->ctx_state = CPT_CTX_IDLE; ++ break; ++ case CPT_TEST_VECAPS: ++ { ++ __u32 dst_flags = arg; ++ __u32 src_flags; ++ ++ err = cpt_vps_caps(ctx, &src_flags); ++ if (err) ++ break; ++ ++ test_one_flag(src_flags, dst_flags, CPT_CPU_X86_CMOV, "cmov", err); ++ test_one_flag(src_flags, dst_flags, CPT_CPU_X86_FXSR, "fxsr", err); ++ test_one_flag(src_flags, dst_flags, CPT_CPU_X86_SSE, "sse", err); ++ test_one_flag(src_flags, dst_flags, CPT_CPU_X86_SSE2, "sse2", err); ++ test_one_flag(src_flags, dst_flags, CPT_CPU_X86_MMX, "mmx", err); ++ test_one_flag(src_flags, dst_flags, CPT_CPU_X86_3DNOW, "3dnow", err); ++ test_one_flag(src_flags, dst_flags, CPT_CPU_X86_3DNOW2, "3dnowext", err); ++ test_one_flag(src_flags, dst_flags, CPT_CPU_X86_SEP, "sysenter", err); ++ test_one_flag(src_flags, dst_flags, CPT_CPU_X86_EMT64, "emt64", err); ++ test_one_flag(src_flags, dst_flags, CPT_CPU_X86_IA64, "ia64", err); ++ test_one_flag(src_flags, dst_flags, CPT_CPU_X86_SYSCALL, "syscall", err); ++ test_one_flag(src_flags, dst_flags, CPT_CPU_X86_SYSCALL32, "syscall32", err); ++ if (src_flags & CPT_UNSUPPORTED_MASK) ++ err = 2; ++ break; ++ } ++ default: ++ err = -EINVAL; ++ break; ++ } ++ ++out: ++ cpt_flush_error(ctx); ++ up(&ctx->main_sem); ++out_nosem: ++ cpt_context_put(ctx); ++out_lock: ++ lock_kernel(); ++ if (err == -ERESTARTSYS || err == -ERESTARTNOINTR || ++ err == -ERESTARTNOHAND || err == -ERESTART_RESTARTBLOCK) ++ err = -EINTR; ++ return err; ++} ++ ++static int cpt_open(struct inode *inode, struct file *file) ++{ ++ if (!try_module_get(THIS_MODULE)) ++ return -EBUSY; ++ ++ return 0; ++} ++ ++static int cpt_release(struct inode * inode, struct file * file) ++{ ++ cpt_context_t *ctx; ++ ++ spin_lock(&cpt_context_lock); ++ ctx = (cpt_context_t*)file->private_data; ++ file->private_data = NULL; ++ ++ if (ctx) ++ __cpt_context_put(ctx); ++ spin_unlock(&cpt_context_lock); ++ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++ ++static struct file_operations cpt_fops = { ++ .owner = THIS_MODULE, ++ .open = cpt_open, ++ .release = cpt_release, ++ .ioctl = cpt_ioctl, ++}; ++ ++static struct proc_dir_entry *proc_ent; ++ ++static struct ctl_table_header *ctl_header; ++ ++static ctl_table debug_table[] = { ++ { ++ .ctl_name = 9475, ++ .procname = "cpt", ++ .data = &debug_level, ++ .maxlen = sizeof(debug_level), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++ { .ctl_name = 0 } ++}; ++static ctl_table root_table[] = { ++ { ++ .ctl_name = CTL_DEBUG, ++ .procname = "debug", ++ .mode = 0555, ++ .child = debug_table, ++ }, ++ { .ctl_name = 0 } ++}; ++ ++static int __init init_cpt(void) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ ctl_header = register_sysctl_table(root_table); ++ if (!ctl_header) ++ goto err_mon; ++ ++ spin_lock_init(&cpt_context_lock); ++ INIT_LIST_HEAD(&cpt_context_list); ++ ++ err = -EINVAL; ++ proc_ent = create_proc_entry_mod("cpt", 0600, NULL, THIS_MODULE); ++ if (!proc_ent) ++ goto err_out; ++ ++ cpt_fops.read = proc_ent->proc_fops->read; ++ cpt_fops.write = proc_ent->proc_fops->write; ++ cpt_fops.llseek = proc_ent->proc_fops->llseek; ++ proc_ent->proc_fops = &cpt_fops; ++ ++ proc_ent->read_proc = proc_read; ++ proc_ent->data = NULL; ++ proc_ent->owner = THIS_MODULE; ++ return 0; ++ ++err_out: ++ unregister_sysctl_table(ctl_header); ++err_mon: ++ return err; ++} ++module_init(init_cpt); ++ ++static void __exit exit_cpt(void) ++{ ++ remove_proc_entry("cpt", NULL); ++ unregister_sysctl_table(ctl_header); ++ ++ spin_lock(&cpt_context_lock); ++ while (!list_empty(&cpt_context_list)) { ++ cpt_context_t *ctx; ++ ctx = list_entry(cpt_context_list.next, cpt_context_t, ctx_list); ++ ++ if (!ctx->sticky) ++ ctx->refcount++; ++ ctx->sticky = 0; ++ ++ BUG_ON(ctx->refcount != 1); ++ ++ __cpt_context_put(ctx); ++ } ++ spin_unlock(&cpt_context_lock); ++} ++module_exit(exit_cpt); +Index: kernel/kernel/cpt/cpt_process.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_process.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,1371 @@ ++/* ++ * ++ * kernel/cpt/cpt_process.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_ubc.h" ++#include "cpt_process.h" ++#include "cpt_kernel.h" ++ ++#ifdef CONFIG_X86_32 ++#undef task_pt_regs ++#define task_pt_regs(t) ((struct pt_regs *)((t)->thread.esp0) - 1) ++#endif ++ ++int check_task_state(struct task_struct *tsk, struct cpt_context *ctx) ++{ ++#ifdef CONFIG_X86_64 ++ if (!(task_thread_info(tsk)->flags&_TIF_IA32)) { ++ if (task_pt_regs(tsk)->rip >= VSYSCALL_START && ++ task_pt_regs(tsk)->rip < VSYSCALL_END) { ++ eprintk_ctx(CPT_FID "cannot be checkpointied while vsyscall, try later\n", CPT_TID(tsk)); ++ return -EAGAIN; ++ } ++ } ++#endif ++ return 0; ++} ++ ++#ifdef CONFIG_X86 ++ ++static u32 encode_segment(u32 segreg) ++{ ++ segreg &= 0xFFFF; ++ ++ if (segreg == 0) ++ return CPT_SEG_ZERO; ++ if ((segreg & 3) != 3) { ++ wprintk("Invalid RPL of a segment reg %x\n", segreg); ++ return CPT_SEG_ZERO; ++ } ++ ++ /* LDT descriptor, it is just an index to LDT array */ ++ if (segreg & 4) ++ return CPT_SEG_LDT + (segreg >> 3); ++ ++ /* TLS descriptor. */ ++ if ((segreg >> 3) >= GDT_ENTRY_TLS_MIN && ++ (segreg >> 3) <= GDT_ENTRY_TLS_MAX) ++ return CPT_SEG_TLS1 + ((segreg>>3) - GDT_ENTRY_TLS_MIN); ++ ++ /* One of standard desriptors */ ++#ifdef CONFIG_X86_64 ++ if (segreg == __USER32_DS) ++ return CPT_SEG_USER32_DS; ++ if (segreg == __USER32_CS) ++ return CPT_SEG_USER32_CS; ++ if (segreg == __USER_DS) ++ return CPT_SEG_USER64_DS; ++ if (segreg == __USER_CS) ++ return CPT_SEG_USER64_CS; ++#else ++ if (segreg == __USER_DS) ++ return CPT_SEG_USER32_DS; ++ if (segreg == __USER_CS) ++ return CPT_SEG_USER32_CS; ++#endif ++ wprintk("Invalid segment reg %x\n", segreg); ++ return CPT_SEG_ZERO; ++} ++ ++#ifdef CONFIG_X86_64 ++static void xlate_ptregs_64_to_32(struct cpt_x86_regs *d, struct pt_regs *s, ++ struct task_struct *tsk) ++{ ++ d->cpt_ebp = s->rbp; ++ d->cpt_ebx = s->rbx; ++ d->cpt_eax = s->rax; ++ d->cpt_ecx = s->rcx; ++ d->cpt_edx = s->rdx; ++ d->cpt_esi = s->rsi; ++ d->cpt_edi = s->rdi; ++ d->cpt_orig_eax = s->orig_rax; ++ d->cpt_eip = s->rip; ++ d->cpt_xcs = encode_segment(s->cs); ++ d->cpt_eflags = s->eflags; ++ d->cpt_esp = s->rsp; ++ d->cpt_xss = encode_segment(s->ss); ++ d->cpt_xds = encode_segment(tsk->thread.ds); ++ d->cpt_xes = encode_segment(tsk->thread.es); ++} ++ ++static int dump_registers(struct task_struct *tsk, struct cpt_context *ctx) ++{ ++ cpt_open_object(NULL, ctx); ++ ++ if (task_thread_info(tsk)->flags & _TIF_IA32) { ++ struct cpt_x86_regs ri; ++ ri.cpt_next = sizeof(ri); ++ ri.cpt_object = CPT_OBJ_X86_REGS; ++ ri.cpt_hdrlen = sizeof(ri); ++ ri.cpt_content = CPT_CONTENT_VOID; ++ ++ ri.cpt_debugreg[0] = tsk->thread.debugreg0; ++ ri.cpt_debugreg[1] = tsk->thread.debugreg1; ++ ri.cpt_debugreg[2] = tsk->thread.debugreg2; ++ ri.cpt_debugreg[3] = tsk->thread.debugreg3; ++ ri.cpt_debugreg[4] = 0; ++ ri.cpt_debugreg[5] = 0; ++ ri.cpt_debugreg[6] = tsk->thread.debugreg6; ++ ri.cpt_debugreg[7] = tsk->thread.debugreg7; ++ ri.cpt_fs = encode_segment(tsk->thread.fsindex); ++ ri.cpt_gs = encode_segment(tsk->thread.gsindex); ++ ++ xlate_ptregs_64_to_32(&ri, task_pt_regs(tsk), tsk); ++ ++ ctx->write(&ri, sizeof(ri), ctx); ++ } else { ++ struct cpt_x86_64_regs ri; ++ ri.cpt_next = sizeof(ri); ++ ri.cpt_object = CPT_OBJ_X86_64_REGS; ++ ri.cpt_hdrlen = sizeof(ri); ++ ri.cpt_content = CPT_CONTENT_VOID; ++ ++ ri.cpt_fsbase = tsk->thread.fs; ++ ri.cpt_gsbase = tsk->thread.gs; ++ ri.cpt_fsindex = encode_segment(tsk->thread.fsindex); ++ ri.cpt_gsindex = encode_segment(tsk->thread.gsindex); ++ ri.cpt_ds = encode_segment(tsk->thread.ds); ++ ri.cpt_es = encode_segment(tsk->thread.es); ++ ri.cpt_debugreg[0] = tsk->thread.debugreg0; ++ ri.cpt_debugreg[1] = tsk->thread.debugreg1; ++ ri.cpt_debugreg[2] = tsk->thread.debugreg2; ++ ri.cpt_debugreg[3] = tsk->thread.debugreg3; ++ ri.cpt_debugreg[4] = 0; ++ ri.cpt_debugreg[5] = 0; ++ ri.cpt_debugreg[6] = tsk->thread.debugreg6; ++ ri.cpt_debugreg[7] = tsk->thread.debugreg7; ++ ++ memcpy(&ri.cpt_r15, task_pt_regs(tsk), sizeof(struct pt_regs)); ++ ++ ri.cpt_cs = encode_segment(task_pt_regs(tsk)->cs); ++ ri.cpt_ss = encode_segment(task_pt_regs(tsk)->ss); ++ ++ ctx->write(&ri, sizeof(ri), ctx); ++ ++ } ++ cpt_close_object(ctx); ++ ++ return 0; ++} ++ ++#else ++ ++static int dump_registers(struct task_struct *tsk, struct cpt_context *ctx) ++{ ++ struct cpt_x86_regs ri; ++ struct pt_regs *pt_regs; ++ ++ cpt_open_object(NULL, ctx); ++ ++ ri.cpt_next = sizeof(ri); ++ ri.cpt_object = CPT_OBJ_X86_REGS; ++ ri.cpt_hdrlen = sizeof(ri); ++ ri.cpt_content = CPT_CONTENT_VOID; ++ ++ ri.cpt_debugreg[0] = tsk->thread.debugreg[0]; ++ ri.cpt_debugreg[1] = tsk->thread.debugreg[1]; ++ ri.cpt_debugreg[2] = tsk->thread.debugreg[2]; ++ ri.cpt_debugreg[3] = tsk->thread.debugreg[3]; ++ ri.cpt_debugreg[4] = tsk->thread.debugreg[4]; ++ ri.cpt_debugreg[5] = tsk->thread.debugreg[5]; ++ ri.cpt_debugreg[6] = tsk->thread.debugreg[6]; ++ ri.cpt_debugreg[7] = tsk->thread.debugreg[7]; ++ ++ pt_regs = task_pt_regs(tsk); ++ ++ ri.cpt_fs = encode_segment(pt_regs->xfs); ++ ri.cpt_gs = encode_segment(tsk->thread.gs); ++ ++ ri.cpt_ebx = pt_regs->ebx; ++ ri.cpt_ecx = pt_regs->ecx; ++ ri.cpt_edx = pt_regs->edx; ++ ri.cpt_esi = pt_regs->esi; ++ ri.cpt_edi = pt_regs->edi; ++ ri.cpt_ebp = pt_regs->ebp; ++ ri.cpt_eax = pt_regs->eax; ++ ri.cpt_xds = pt_regs->xds; ++ ri.cpt_xes = pt_regs->xes; ++ ri.cpt_orig_eax = pt_regs->orig_eax; ++ ri.cpt_eip = pt_regs->eip; ++ ri.cpt_xcs = pt_regs->xcs; ++ ri.cpt_eflags = pt_regs->eflags; ++ ri.cpt_esp = pt_regs->esp; ++ ri.cpt_xss = pt_regs->xss; ++ ++ ri.cpt_xcs = encode_segment(pt_regs->xcs); ++ ri.cpt_xss = encode_segment(pt_regs->xss); ++ ri.cpt_xds = encode_segment(pt_regs->xds); ++ ri.cpt_xes = encode_segment(pt_regs->xes); ++ ++ ctx->write(&ri, sizeof(ri), ctx); ++ cpt_close_object(ctx); ++ ++ return 0; ++} ++#endif ++#endif ++ ++#ifdef CONFIG_IA64 ++ ++/* ++ PMD? ++ */ ++ ++#define _C(x) do { if ((err = (x)) < 0) { printk("atm:" CPT_FID #x " %d\n", \ ++ CPT_TID(tsk), err); return -EINVAL; } } while (0) ++ ++static int ass_to_mouth(struct cpt_ia64_regs *r, struct task_struct *tsk, ++ struct cpt_context *ctx) ++{ ++ int err; ++ struct unw_frame_info info; ++ struct ia64_fpreg fpval; ++ int i; ++ ++ unw_init_from_blocked_task(&info, tsk); ++ _C(unw_unwind_to_user(&info)); ++ ++ /* NAT_BITS */ ++ do { ++ unsigned long scratch_unat; ++ ++ scratch_unat = info.sw->caller_unat; ++ if (info.pri_unat_loc) ++ scratch_unat = *info.pri_unat_loc; ++ ++ r->nat[0] = ia64_get_scratch_nat_bits(task_pt_regs(tsk), scratch_unat); ++ /* Just to be on safe side. */ ++ r->nat[0] &= 0xFFFFFFFFUL; ++ } while (0); ++ ++ /* R4-R7 */ ++ for (i = 4; i <= 7; i++) { ++ char nat = 0; ++ _C(unw_access_gr(&info, i, &r->gr[i], &nat, 0)); ++ r->nat[0] |= (nat != 0) << i; ++ } ++ ++ /* B1-B5 */ ++ for (i = 1; i <= 5; i++) { ++ _C(unw_access_br(&info, i, &r->br[i], 0)); ++ } ++ ++ /* AR_EC, AR_LC */ ++ _C(unw_access_ar(&info, UNW_AR_EC, &r->ar_ec, 0)); ++ _C(unw_access_ar(&info, UNW_AR_LC, &r->ar_lc, 0)); ++ ++ /* F2..F5, F16..F31 */ ++ for (i = 2; i <= 5; i++) { ++ _C(unw_get_fr(&info, i, &fpval)); ++ memcpy(&r->fr[i*2], &fpval, 16); ++ } ++ for (i = 16; i <= 31; i++) { ++ _C(unw_get_fr(&info, i, &fpval)); ++ memcpy(&r->fr[i*2], &fpval, 16); ++ } ++ return 0; ++} ++ ++#undef _C ++ ++static int dump_registers(struct task_struct *tsk, struct cpt_context *ctx) ++{ ++ int err; ++ unsigned long pg; ++ struct cpt_ia64_regs *r; ++ struct ia64_psr *psr; ++ struct switch_stack *sw; ++ struct pt_regs *pt; ++ void *krbs = (void *)tsk + IA64_RBS_OFFSET; ++ unsigned long reg; ++ ++ if (tsk->exit_state) ++ return 0; ++ ++ pt = task_pt_regs(tsk); ++ ++ sw = (struct switch_stack *) (tsk->thread.ksp + 16); ++ ++ if ((pg = __get_free_page(GFP_KERNEL)) == 0) ++ return -ENOMEM; ++ ++ r = (void*)pg; ++ /* To catch if we forgot some register */ ++ memset(r, 0xA5, sizeof(*r)); ++ ++ r->gr[0] = 0; ++ r->fr[0] = r->fr[1] = 0; ++ r->fr[2] = 0x8000000000000000UL; ++ r->fr[3] = 0xffff; ++ ++ r->nat[0] = r->nat[1] = 0; ++ ++ err = ass_to_mouth(r, tsk, ctx); ++ if (err) { ++ printk("ass_to_mouth error %d\n", err); ++ goto out; ++ } ++ ++ /* gr 1,2-3,8-11,12-13,14,15,16-31 are on pt_regs */ ++ memcpy(&r->gr[1], &pt->r1, 8*(2-1)); ++ memcpy(&r->gr[2], &pt->r2, 8*(4-2)); ++ memcpy(&r->gr[8], &pt->r8, 8*(12-8)); ++ memcpy(&r->gr[12], &pt->r12, 8*(14-12)); ++ memcpy(&r->gr[14], &pt->r14, 8*(15-14)); ++ memcpy(&r->gr[15], &pt->r15, 8*(16-15)); ++ memcpy(&r->gr[16], &pt->r16, 8*(32-16)); ++ ++ r->br[0] = pt->b0; ++ r->br[6] = pt->b6; ++ r->br[7] = pt->b7; ++ ++ r->ar_bspstore = pt->ar_bspstore; ++ r->ar_unat = pt->ar_unat; ++ r->ar_pfs = pt->ar_pfs; ++ r->ar_ccv = pt->ar_ccv; ++ r->ar_fpsr = pt->ar_fpsr; ++ r->ar_csd = pt->ar_csd; ++ r->ar_ssd = pt->ar_ssd; ++ r->ar_rsc = pt->ar_rsc; ++ ++ r->cr_iip = pt->cr_iip; ++ r->cr_ipsr = pt->cr_ipsr; ++ ++ r->pr = pt->pr; ++ ++ r->cfm = pt->cr_ifs; ++ r->ar_rnat = pt->ar_rnat; ++ ++ /* fpregs 6..9,10..11 are in pt_regs */ ++ memcpy(&r->fr[2*6], &pt->f6, 16*(10-6)); ++ memcpy(&r->fr[2*10], &pt->f10, 16*(12-10)); ++ /* fpreg 12..15 are on switch stack */ ++ memcpy(&r->fr[2*12], &sw->f12, 16*(16-12)); ++ /* fpregs 32...127 */ ++ psr = ia64_psr(task_pt_regs(tsk)); ++ preempt_disable(); ++ if (ia64_is_local_fpu_owner(tsk) && psr->mfh) { ++ psr->mfh = 0; ++ tsk->thread.flags |= IA64_THREAD_FPH_VALID; ++ ia64_save_fpu(&tsk->thread.fph[0]); ++ } ++ preempt_enable(); ++ memcpy(&r->fr[32*2], tsk->thread.fph, 16*(128-32)); ++ ++ if (tsk->thread.flags & IA64_THREAD_DBG_VALID) { ++ memcpy(r->ibr, tsk->thread.ibr, sizeof(r->ibr)); ++ memcpy(r->dbr, tsk->thread.dbr, sizeof(r->ibr)); ++ } else { ++ memset(r->ibr, 0, sizeof(r->ibr)); ++ memset(r->dbr, 0, sizeof(r->dbr)); ++ } ++ ++ r->loadrs = pt->loadrs; ++ r->num_regs = ia64_rse_num_regs(krbs, krbs + 8*(pt->loadrs >> 19)); ++ if ((long)pt->cr_ifs > 0) ++ r->num_regs += (pt->cr_ifs & 0x7f); ++ ++ if (r->num_regs > 96) { ++ eprintk_ctx(CPT_FID " too much RSE regs %lu\n", ++ CPT_TID(tsk), r->num_regs); ++ return -EINVAL; ++ } ++ ++ for (reg = 0; reg < r->num_regs; reg++) { ++ unsigned long *ptr = ia64_rse_skip_regs(krbs, reg); ++ unsigned long *rnatp = ia64_rse_rnat_addr(ptr); ++ ++ r->gr[32+reg] = *ptr; ++ ++ if ((unsigned long)rnatp >= sw->ar_bspstore) ++ rnatp = &sw->ar_rnat; ++ if (*rnatp & (1UL<nat[0] |= (1UL<<(reg+32)); ++ else ++ r->nat[1] |= (1UL<<(reg-32)); ++ } ++ } ++ if (r->nat[0] | r->nat[1]) ++ wprintk_ctx(CPT_FID " nat bits %lx%016lx\n", CPT_TID(tsk), ++ r->nat[1], r->nat[0]); ++ ++ cpt_open_object(NULL, ctx); ++ r->cpt_next = sizeof(*r); ++ r->cpt_object = CPT_OBJ_IA64_REGS; ++ r->cpt_hdrlen = sizeof(*r); ++ r->cpt_content = CPT_CONTENT_VOID; ++ ctx->write(r, sizeof(*r), ctx); ++ cpt_close_object(ctx); ++ err = 0; ++ ++out: ++ free_page(pg); ++ return err; ++} ++#endif ++ ++static int dump_kstack(struct task_struct *tsk, struct cpt_context *ctx) ++{ ++ struct cpt_obj_bits hdr; ++ unsigned long size; ++ void *start; ++ ++ cpt_open_object(NULL, ctx); ++ ++#ifdef CONFIG_X86_64 ++ size = tsk->thread.rsp0 - tsk->thread.rsp; ++ start = (void*)tsk->thread.rsp; ++#elif defined(CONFIG_X86_32) ++ size = tsk->thread.esp0 - tsk->thread.esp; ++ start = (void*)tsk->thread.esp; ++#elif defined(CONFIG_IA64) ++ size = (unsigned long)(task_pt_regs(tsk)+1) - tsk->thread.ksp; ++ start = (void*)tsk->thread.ksp; ++#else ++#error Arch is not supported ++#endif ++ ++ hdr.cpt_next = sizeof(hdr) + CPT_ALIGN(size); ++ hdr.cpt_object = CPT_OBJ_BITS; ++ hdr.cpt_hdrlen = sizeof(hdr); ++ hdr.cpt_content = CPT_CONTENT_STACK; ++ hdr.cpt_size = size; ++ ++ ctx->write(&hdr, sizeof(hdr), ctx); ++ ctx->write(start, size, ctx); ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ return 0; ++} ++ ++#ifdef CONFIG_X86 ++/* Formats of i387_fxsave_struct are the same for x86_64 ++ * and i386. Plain luck. */ ++ ++static int dump_fpustate(struct task_struct *tsk, struct cpt_context *ctx) ++{ ++ struct cpt_obj_bits hdr; ++ unsigned long size; ++ int type; ++ ++ cpt_open_object(NULL, ctx); ++ ++ type = CPT_CONTENT_X86_FPUSTATE; ++ size = sizeof(struct i387_fxsave_struct); ++#ifndef CONFIG_X86_64 ++ if (!cpu_has_fxsr) { ++ size = sizeof(struct i387_fsave_struct); ++ type = CPT_CONTENT_X86_FPUSTATE_OLD; ++ } ++#endif ++ ++ hdr.cpt_next = sizeof(hdr) + CPT_ALIGN(size); ++ hdr.cpt_object = CPT_OBJ_BITS; ++ hdr.cpt_hdrlen = sizeof(hdr); ++ hdr.cpt_content = type; ++ hdr.cpt_size = size; ++ ++ ctx->write(&hdr, sizeof(hdr), ctx); ++ ctx->write(&tsk->thread.i387, size, ctx); ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_IA64 ++ ++static int dump_fpustate(struct task_struct *tsk, struct cpt_context *ctx) ++{ ++ return 0; ++} ++#endif ++ ++static int encode_siginfo(struct cpt_siginfo_image *si, siginfo_t *info) ++{ ++ si->cpt_signo = info->si_signo; ++ si->cpt_errno = info->si_errno; ++ si->cpt_code = info->si_code; ++ ++ switch(si->cpt_code & __SI_MASK) { ++ case __SI_TIMER: ++ si->cpt_pid = info->si_tid; ++ si->cpt_uid = info->si_overrun; ++ si->cpt_sigval = cpt_ptr_export(info->_sifields._timer._sigval.sival_ptr); ++ si->cpt_utime = info->si_sys_private; ++ break; ++ case __SI_POLL: ++ si->cpt_pid = info->si_band; ++ si->cpt_uid = info->si_fd; ++ break; ++ case __SI_FAULT: ++ si->cpt_sigval = cpt_ptr_export(info->si_addr); ++#ifdef __ARCH_SI_TRAPNO ++ si->cpt_pid = info->si_trapno; ++#endif ++ break; ++ case __SI_CHLD: ++ si->cpt_pid = info->si_pid; ++ si->cpt_uid = info->si_uid; ++ si->cpt_sigval = info->si_status; ++ si->cpt_stime = info->si_stime; ++ si->cpt_utime = info->si_utime; ++ break; ++ case __SI_KILL: ++ case __SI_RT: ++ case __SI_MESGQ: ++ default: ++ si->cpt_pid = info->si_pid; ++ si->cpt_uid = info->si_uid; ++ si->cpt_sigval = cpt_ptr_export(info->si_ptr); ++ break; ++ } ++ return 0; ++} ++ ++static int dump_sigqueue(struct sigpending *list, struct cpt_context *ctx) ++{ ++ struct sigqueue *q; ++ loff_t saved_obj; ++ ++ if (list_empty(&list->list)) ++ return 0; ++ ++ cpt_push_object(&saved_obj, ctx); ++ list_for_each_entry(q, &list->list, list) { ++ struct cpt_siginfo_image si; ++ ++ si.cpt_next = sizeof(si); ++ si.cpt_object = CPT_OBJ_SIGINFO; ++ si.cpt_hdrlen = sizeof(si); ++ si.cpt_content = CPT_CONTENT_VOID; ++ ++ si.cpt_qflags = q->flags; ++ si.cpt_user = q->user->uid; ++ ++ if (encode_siginfo(&si, &q->info)) ++ return -EINVAL; ++ ++ ctx->write(&si, sizeof(si), ctx); ++ } ++ cpt_pop_object(&saved_obj, ctx); ++ return 0; ++} ++ ++ ++ ++static int dump_one_signal_struct(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ struct signal_struct *sig = obj->o_obj; ++ struct cpt_signal_image *v = cpt_get_buf(ctx); ++ struct task_struct *tsk; ++ int i; ++ ++ cpt_open_object(obj, ctx); ++ ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_SIGNAL_STRUCT; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ if (sig->__pgrp <= 0) { ++ eprintk_ctx("bad pgid\n"); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ v->cpt_pgrp_type = CPT_PGRP_NORMAL; ++ read_lock(&tasklist_lock); ++ tsk = find_task_by_pid(sig->__pgrp); ++ if (tsk == NULL) ++ v->cpt_pgrp_type = CPT_PGRP_ORPHAN; ++ read_unlock(&tasklist_lock); ++ v->cpt_pgrp = pid_to_vpid(sig->__pgrp); ++ ++ v->cpt_old_pgrp = 0; ++/* if (!sig->tty_old_pgrp) { ++ eprintk_ctx("bad tty_old_pgrp\n"); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ }*/ ++ if (sig->tty_old_pgrp) { ++ v->cpt_old_pgrp_type = CPT_PGRP_NORMAL; ++ read_lock(&tasklist_lock); ++ tsk = pid_task(sig->tty_old_pgrp, PIDTYPE_PID); ++ if (tsk == NULL) { ++ v->cpt_old_pgrp_type = CPT_PGRP_ORPHAN; ++ tsk = pid_task(sig->tty_old_pgrp, PIDTYPE_PGID); ++ } ++ read_unlock(&tasklist_lock); ++ if (tsk == NULL) { ++ eprintk_ctx("tty_old_pgrp does not exist anymore\n"); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ v->cpt_old_pgrp = pid_vnr(sig->tty_old_pgrp); ++ if ((int)v->cpt_old_pgrp < 0) { ++ dprintk_ctx("stray tty_old_pgrp %d\n", pid_nr(sig->tty_old_pgrp)); ++ v->cpt_old_pgrp = -1; ++ v->cpt_old_pgrp_type = CPT_PGRP_STRAY; ++ } ++ } ++ ++ if (sig->__session <= 0) { ++ eprintk_ctx("bad session\n"); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ v->cpt_session_type = CPT_PGRP_NORMAL; ++ read_lock(&tasklist_lock); ++ tsk = find_task_by_pid(sig->__session); ++ if (tsk == NULL) ++ v->cpt_session_type = CPT_PGRP_ORPHAN; ++ read_unlock(&tasklist_lock); ++ v->cpt_session = pid_to_vpid(sig->__session); ++ ++ v->cpt_leader = sig->leader; ++ v->cpt_ctty = CPT_NULL; ++ if (sig->tty) { ++ cpt_object_t *cobj = lookup_cpt_object(CPT_OBJ_TTY, sig->tty, ctx); ++ if (cobj) ++ v->cpt_ctty = cobj->o_pos; ++ else { ++ eprintk_ctx("controlling tty is not found\n"); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ } ++ memcpy(&v->cpt_sigpending, &sig->shared_pending.signal, 8); ++ ++ v->cpt_curr_target = 0; ++ if (sig->curr_target) ++ v->cpt_curr_target = task_pid_vnr(sig->curr_target); ++ v->cpt_group_exit = ((sig->flags & SIGNAL_GROUP_EXIT) != 0); ++ v->cpt_group_exit_code = sig->group_exit_code; ++ v->cpt_group_exit_task = 0; ++ if (sig->group_exit_task) ++ v->cpt_group_exit_task = task_pid_vnr(sig->group_exit_task); ++ v->cpt_notify_count = sig->notify_count; ++ v->cpt_group_stop_count = sig->group_stop_count; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) ++ v->cpt_utime = sig->utime; ++ v->cpt_stime = sig->stime; ++ v->cpt_cutime = sig->cutime; ++ v->cpt_cstime = sig->cstime; ++ v->cpt_nvcsw = sig->nvcsw; ++ v->cpt_nivcsw = sig->nivcsw; ++ v->cpt_cnvcsw = sig->cnvcsw; ++ v->cpt_cnivcsw = sig->cnivcsw; ++ v->cpt_min_flt = sig->min_flt; ++ v->cpt_maj_flt = sig->maj_flt; ++ v->cpt_cmin_flt = sig->cmin_flt; ++ v->cpt_cmaj_flt = sig->cmaj_flt; ++ ++ if (RLIM_NLIMITS > CPT_RLIM_NLIMITS) ++ __asm__("undefined\n"); ++ ++ for (i=0; icpt_rlim_cur[i] = sig->rlim[i].rlim_cur; ++ v->cpt_rlim_max[i] = sig->rlim[i].rlim_max; ++ } else { ++ v->cpt_rlim_cur[i] = CPT_NULL; ++ v->cpt_rlim_max[i] = CPT_NULL; ++ } ++ } ++#endif ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++ dump_sigqueue(&sig->shared_pending, ctx); ++ ++ cpt_close_object(ctx); ++ return 0; ++} ++ ++int cpt_check_unsupported(struct task_struct *tsk, cpt_context_t *ctx) ++{ ++ if (tsk->splice_pipe) { ++ eprintk_ctx("splice is used by " CPT_FID "\n", CPT_TID(tsk)); ++ return -EBUSY; ++ } ++#ifdef CONFIG_KEYS ++ if (tsk->request_key_auth || tsk->thread_keyring) { ++ eprintk_ctx("keys are used by " CPT_FID "\n", CPT_TID(tsk)); ++ return -EBUSY; ++ } ++#endif ++#ifdef CONFIG_NUMA ++ if (tsk->mempolicy) { ++ eprintk_ctx("NUMA mempolicy is used by " CPT_FID "\n", CPT_TID(tsk)); ++ return -EBUSY; ++ } ++#endif ++#ifdef CONFIG_TUX ++ if (tsk->tux_info) { ++ eprintk_ctx("TUX is used by " CPT_FID "\n", CPT_TID(tsk)); ++ return -EBUSY; ++ } ++#endif ++ return 0; ++} ++ ++static int dump_one_process(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ struct task_struct *tsk = obj->o_obj; ++ int last_thread; ++ struct cpt_task_image *v = cpt_get_buf(ctx); ++ cpt_object_t *tobj; ++ cpt_object_t *tg_obj; ++ loff_t saved_obj; ++ int i; ++ int err; ++ struct timespec delta; ++ struct mm_struct * tsk_mm; ++ struct files_struct * tsk_files; ++ struct fs_struct * tsk_fs; ++ struct mnt_namespace * tsk_ns; ++ ++ cpt_open_object(obj, ctx); ++ ++ v->cpt_signal = CPT_NULL; ++ tg_obj = lookup_cpt_object(CPT_OBJ_SIGNAL_STRUCT, tsk->signal, ctx); ++ if (!tg_obj) BUG(); ++ ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_TASK; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ v->cpt_state = tsk->state; ++ if (tsk->state == EXIT_ZOMBIE) { ++ eprintk_ctx("invalid zombie state on" CPT_FID "\n", CPT_TID(tsk)); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } else if (tsk->state == EXIT_DEAD) { ++ if (tsk->exit_state != EXIT_DEAD && ++ tsk->exit_state != EXIT_ZOMBIE) { ++ eprintk_ctx("invalid exit_state %d on" CPT_FID "\n", tsk->exit_state, CPT_TID(tsk)); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ } ++ if (tsk->exit_state) { ++ v->cpt_state = tsk->exit_state; ++ if (tsk->state != EXIT_DEAD) { ++ eprintk_ctx("invalid tsk->state %ld/%d on" CPT_FID "\n", ++ tsk->state, tsk->exit_state, CPT_TID(tsk)); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ } ++ if (cpt_check_unsupported(tsk, ctx)) { ++ cpt_release_buf(ctx); ++ return -EBUSY; ++ } ++ ++ v->cpt_flags = tsk->flags&~(PF_FROZEN|PF_EXIT_RESTART); ++ v->cpt_ptrace = tsk->ptrace; ++ v->cpt_prio = tsk->prio; ++ v->cpt_exit_code = tsk->exit_code; ++ v->cpt_exit_signal = tsk->exit_signal; ++ v->cpt_pdeath_signal = tsk->pdeath_signal; ++ v->cpt_static_prio = tsk->static_prio; ++ v->cpt_rt_priority = tsk->rt_priority; ++ v->cpt_policy = tsk->policy; ++ if (v->cpt_policy != SCHED_NORMAL) { ++ eprintk_ctx("scheduler policy is not supported %d/%d(%s)\n", task_pid_vnr(tsk), tsk->pid, tsk->comm); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ ++ /* Unpleasant moment. When leader of thread group exits, ++ * it remains in zombie state until all the group exits. ++ * We save not-NULL pointers to process mm/files/fs, so ++ * that we can restore this thread group. ++ */ ++ tsk_mm = tsk->mm; ++ tsk_files = tsk->files; ++ tsk_fs = tsk->fs; ++ tsk_ns = tsk->nsproxy ? tsk->nsproxy->mnt_ns : NULL; ++ ++ if (tsk->exit_state && !thread_group_empty(tsk) && ++ thread_group_leader(tsk)) { ++ struct task_struct * p = tsk; ++ ++ read_lock(&tasklist_lock); ++ do { ++ if (p->mm) ++ tsk_mm = p->mm; ++ if (p->files) ++ tsk_files = p->files; ++ if (p->fs) ++ tsk_fs = p->fs; ++ if (p->nsproxy && p->nsproxy->mnt_ns) ++ tsk_ns = p->nsproxy->mnt_ns; ++ p = next_thread(p); ++ } while (p != tsk); ++ read_unlock(&tasklist_lock); ++ } ++ ++ v->cpt_mm = CPT_NULL; ++ if (tsk_mm) { ++ tobj = lookup_cpt_object(CPT_OBJ_MM, tsk_mm, ctx); ++ if (!tobj) BUG(); ++ v->cpt_mm = tobj->o_pos; ++ } ++ v->cpt_files = CPT_NULL; ++ if (tsk_files) { ++ tobj = lookup_cpt_object(CPT_OBJ_FILES, tsk_files, ctx); ++ if (!tobj) BUG(); ++ v->cpt_files = tobj->o_pos; ++ } ++ v->cpt_fs = CPT_NULL; ++ if (tsk_fs) { ++ tobj = lookup_cpt_object(CPT_OBJ_FS, tsk_fs, ctx); ++ if (!tobj) BUG(); ++ v->cpt_fs = tobj->o_pos; ++ } ++ v->cpt_namespace = CPT_NULL; ++ if (tsk_ns) { ++ tobj = lookup_cpt_object(CPT_OBJ_NAMESPACE, tsk_ns, ctx); ++ if (!tobj) BUG(); ++ v->cpt_namespace = tobj->o_pos; ++ ++ if (tsk_ns != current->nsproxy->mnt_ns) ++ eprintk_ctx("namespaces are not supported:" ++ "process " CPT_FID "\n", CPT_TID(tsk)); ++ } ++ v->cpt_sysvsem_undo = CPT_NULL; ++ if (tsk->sysvsem.undo_list && !tsk->exit_state) { ++ tobj = lookup_cpt_object(CPT_OBJ_SYSVSEM_UNDO, tsk->sysvsem.undo_list, ctx); ++ if (!tobj) BUG(); ++ v->cpt_sysvsem_undo = tobj->o_pos; ++ } ++ v->cpt_sighand = CPT_NULL; ++ if (tsk->sighand) { ++ tobj = lookup_cpt_object(CPT_OBJ_SIGHAND_STRUCT, tsk->sighand, ctx); ++ if (!tobj) BUG(); ++ v->cpt_sighand = tobj->o_pos; ++ } ++ v->cpt_sigblocked = cpt_sigset_export(&tsk->blocked); ++ v->cpt_sigrblocked = cpt_sigset_export(&tsk->real_blocked); ++ v->cpt_sigsuspend_blocked = cpt_sigset_export(&tsk->saved_sigmask); ++ ++ v->cpt_pid = task_pid_vnr(tsk); ++ v->cpt_tgid = task_tgid_vnr(tsk); ++ v->cpt_ppid = 0; ++ if (tsk->parent) { ++ if (tsk->parent != tsk->real_parent && ++ !lookup_cpt_object(CPT_OBJ_TASK, tsk->parent, ctx)) { ++ eprintk_ctx("task %d/%d(%s) is ptraced from ve0\n", tsk->pid, task_pid_vnr(tsk), tsk->comm); ++ cpt_release_buf(ctx); ++ return -EBUSY; ++ } ++ v->cpt_ppid = task_pid_vnr(tsk->parent); ++ } ++ v->cpt_rppid = tsk->real_parent ? task_pid_vnr(tsk->real_parent) : 0; ++ v->cpt_pgrp = task_pgrp_vnr(tsk); ++ v->cpt_session = task_session_vnr(tsk); ++ v->cpt_old_pgrp = 0; ++ if (tsk->signal->tty_old_pgrp) ++ v->cpt_old_pgrp = pid_vnr(tsk->signal->tty_old_pgrp); ++ v->cpt_leader = tsk->group_leader ? task_pid_vnr(tsk->group_leader) : 0; ++ v->cpt_set_tid = (unsigned long)tsk->set_child_tid; ++ v->cpt_clear_tid = (unsigned long)tsk->clear_child_tid; ++ memcpy(v->cpt_comm, tsk->comm, 16); ++ v->cpt_user = tsk->user->uid; ++ v->cpt_uid = tsk->uid; ++ v->cpt_euid = tsk->euid; ++ v->cpt_suid = tsk->suid; ++ v->cpt_fsuid = tsk->fsuid; ++ v->cpt_gid = tsk->gid; ++ v->cpt_egid = tsk->egid; ++ v->cpt_sgid = tsk->sgid; ++ v->cpt_fsgid = tsk->fsgid; ++ v->cpt_ngids = 0; ++ if (tsk->group_info && tsk->group_info->ngroups != 0) { ++ int i = tsk->group_info->ngroups; ++ if (i > 32) { ++ /* Shame... I did a simplified version and _forgot_ ++ * about this. Later, later. */ ++ eprintk_ctx("too many of groups " CPT_FID "\n", CPT_TID(tsk)); ++ return -EINVAL; ++ } ++ v->cpt_ngids = i; ++ for (i--; i>=0; i--) ++ v->cpt_gids[i] = tsk->group_info->small_block[i]; ++ } ++ v->cpt_prctl_uac = 0; ++ v->cpt_prctl_fpemu = 0; ++ v->__cpt_pad1 = 0; ++#ifdef CONFIG_IA64 ++ v->cpt_prctl_uac = (tsk->thread.flags & IA64_THREAD_UAC_MASK) >> IA64_THREAD_UAC_SHIFT; ++ v->cpt_prctl_fpemu = (tsk->thread.flags & IA64_THREAD_FPEMU_MASK) >> IA64_THREAD_FPEMU_SHIFT; ++#endif ++ memcpy(&v->cpt_ecap, &tsk->cap_effective, 8); ++ memcpy(&v->cpt_icap, &tsk->cap_inheritable, 8); ++ memcpy(&v->cpt_pcap, &tsk->cap_permitted, 8); ++ v->cpt_keepcap = tsk->keep_capabilities; ++ ++ v->cpt_did_exec = tsk->did_exec; ++ v->cpt_exec_domain = -1; ++ v->cpt_thrflags = task_thread_info(tsk)->flags & ~(1<cpt_64bit = 0; ++#ifdef CONFIG_X86_64 ++ /* Clear x86_64 specific flags */ ++ v->cpt_thrflags &= ~(_TIF_FORK|_TIF_ABI_PENDING|_TIF_IA32); ++ if (!(task_thread_info(tsk)->flags & _TIF_IA32)) { ++ ctx->tasks64++; ++ v->cpt_64bit = 1; ++ } ++#endif ++#ifdef CONFIG_IA64 ++ /* Clear ia64 specific flags */ ++ //// v->cpt_thrflags &= ~(_TIF_FORK|_TIF_ABI_PENDING|_TIF_IA32); ++ if (!IS_IA32_PROCESS(task_pt_regs(tsk))) { ++ ctx->tasks64++; ++ v->cpt_64bit = 1; ++ } ++#endif ++ v->cpt_thrstatus = task_thread_info(tsk)->status; ++ v->cpt_addr_limit = -1; ++ ++ v->cpt_personality = tsk->personality; ++ ++#ifdef CONFIG_X86 ++ for (i=0; i=3) { ++ eprintk_ctx("too many tls descs\n"); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++#ifndef CONFIG_X86_64 ++ v->cpt_tls[i] = (((u64)tsk->thread.tls_array[i].b)<<32) + tsk->thread.tls_array[i].a; ++#else ++ v->cpt_tls[i] = tsk->thread.tls_array[i]; ++#endif ++ } ++#endif ++ ++ v->cpt_restart.fn = CPT_RBL_0; ++ if (task_thread_info(tsk)->restart_block.fn != task_thread_info(current)->restart_block.fn) { ++ struct restart_block *rb = &task_thread_info(tsk)->restart_block; ++ ktime_t e; ++ ++ if (rb->fn == hrtimer_nanosleep_restart) { ++ v->cpt_restart.fn = CPT_RBL_NANOSLEEP; ++ ++ e.tv64 = ((u64)rb->arg3 << 32) | (u64)rb->arg2; ++ e = ktime_sub(e, timespec_to_ktime(ctx->cpt_monotonic_time)); ++ v->cpt_restart.arg0 = rb->arg0; ++ v->cpt_restart.arg1 = rb->arg1; ++ v->cpt_restart.arg2 = ktime_to_ns(e); ++ v->cpt_restart.arg3 = 0; ++ dprintk_ctx(CPT_FID " %Lu\n", CPT_TID(tsk), (unsigned long long)v->cpt_restart.arg0); ++ goto continue_dump; ++ } ++#if defined(CONFIG_X86_64) && defined(CONFIG_COMPAT) ++ if (rb->fn == compat_nanosleep_restart) { ++ v->cpt_restart.fn = CPT_RBL_COMPAT_NANOSLEEP; ++ ++ e.tv64 = ((u64)rb->arg3 << 32) | (u64)rb->arg2; ++ e = ktime_sub(e, timespec_to_ktime(ctx->cpt_monotonic_time)); ++ v->cpt_restart.arg0 = rb->arg0; ++ v->cpt_restart.arg1 = rb->arg1; ++ v->cpt_restart.arg2 = ktime_to_ns(e); ++ v->cpt_restart.arg3 = 0; ++ dprintk_ctx(CPT_FID " %Lu\n", CPT_TID(tsk), (unsigned long long)v->cpt_restart.arg0); ++ goto continue_dump; ++ } ++#endif ++ if (rb->fn == do_restart_poll) { ++ u64 timeout_jiffies; ++ ++ timeout_jiffies = ((u64)rb->arg3 << 32)|(u64)rb->arg2; ++ e.tv64 = timeout_jiffies * TICK_NSEC; ++ ++ v->cpt_restart.fn = CPT_RBL_POLL; ++ v->cpt_restart.arg0 = rb->arg0; ++ v->cpt_restart.arg1 = rb->arg1; ++ v->cpt_restart.arg2 = ktime_to_ns(e); ++ v->cpt_restart.arg3 = 0; ++ dprintk_ctx(CPT_FID " %Lu\n", CPT_TID(tsk), (unsigned long long)v->cpt_restart.arg0); ++ goto continue_dump; ++ } ++ if (rb->fn == futex_wait_restart) { ++ v->cpt_restart.fn = CPT_RBL_FUTEX_WAIT; ++ ++ e.tv64 = rb->futex.time; ++ e = ktime_sub(e, timespec_to_ktime(ctx->cpt_monotonic_time)); ++ v->cpt_restart.arg0 = (unsigned long)rb->futex.uaddr; ++ v->cpt_restart.arg1 = rb->futex.val; ++ v->cpt_restart.arg2 = ktime_to_ns(e); ++ v->cpt_restart.arg3 = rb->futex.flags; ++ goto continue_dump; ++ } ++ eprintk_ctx("unknown restart block %p\n", rb->fn); ++ return -EINVAL; ++ } ++ ++continue_dump: ++ v->cpt_it_real_incr = 0; ++ v->cpt_it_prof_incr = 0; ++ v->cpt_it_virt_incr = 0; ++ v->cpt_it_real_value = 0; ++ v->cpt_it_prof_value = 0; ++ v->cpt_it_virt_value = 0; ++ if (thread_group_leader(tsk) && tsk->exit_state == 0) { ++ ktime_t rem; ++ ++ v->cpt_it_real_incr = ktime_to_ns(tsk->signal->it_real_incr); ++ v->cpt_it_prof_incr = tsk->signal->it_prof_incr; ++ v->cpt_it_virt_incr = tsk->signal->it_virt_incr; ++ ++ rem = hrtimer_get_remaining(&tsk->signal->real_timer); ++ ++ if (hrtimer_active(&tsk->signal->real_timer)) { ++ if (rem.tv64 <= 0) ++ rem.tv64 = NSEC_PER_USEC; ++ v->cpt_it_real_value = ktime_to_ns(rem); ++ dprintk("cpt itimer " CPT_FID " %Lu\n", CPT_TID(tsk), (unsigned long long)v->cpt_it_real_value); ++ } ++ v->cpt_it_prof_value = tsk->signal->it_prof_expires; ++ v->cpt_it_virt_value = tsk->signal->it_virt_expires; ++ } ++ v->cpt_used_math = (tsk_used_math(tsk) != 0); ++ ++ if (tsk->notifier) { ++ eprintk_ctx("task notifier is in use: process %d/%d(%s)\n", task_pid_vnr(tsk), tsk->pid, tsk->comm); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ ++ v->cpt_utime = tsk->utime; ++ v->cpt_stime = tsk->stime; ++ delta = tsk->start_time; ++ _set_normalized_timespec(&delta, ++ delta.tv_sec - get_exec_env()->start_timespec.tv_sec, ++ delta.tv_nsec - get_exec_env()->start_timespec.tv_nsec); ++ v->cpt_starttime = cpt_timespec_export(&delta); ++ v->cpt_nvcsw = tsk->nvcsw; ++ v->cpt_nivcsw = tsk->nivcsw; ++ v->cpt_min_flt = tsk->min_flt; ++ v->cpt_maj_flt = tsk->maj_flt; ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,8) ++ v->cpt_cutime = tsk->cutime; ++ v->cpt_cstime = tsk->cstime; ++ v->cpt_cnvcsw = tsk->cnvcsw; ++ v->cpt_cnivcsw = tsk->cnivcsw; ++ v->cpt_cmin_flt = tsk->cmin_flt; ++ v->cpt_cmaj_flt = tsk->cmaj_flt; ++ ++ if (RLIM_NLIMITS > CPT_RLIM_NLIMITS) ++ __asm__("undefined\n"); ++ ++ for (i=0; icpt_rlim_cur[i] = tsk->rlim[i].rlim_cur; ++ v->cpt_rlim_max[i] = tsk->rlim[i].rlim_max; ++ } else { ++ v->cpt_rlim_cur[i] = CPT_NULL; ++ v->cpt_rlim_max[i] = CPT_NULL; ++ } ++ } ++#else ++ v->cpt_cutime = tsk->signal->cutime; ++ v->cpt_cstime = tsk->signal->cstime; ++ v->cpt_cnvcsw = tsk->signal->cnvcsw; ++ v->cpt_cnivcsw = tsk->signal->cnivcsw; ++ v->cpt_cmin_flt = tsk->signal->cmin_flt; ++ v->cpt_cmaj_flt = tsk->signal->cmaj_flt; ++ ++ if (RLIM_NLIMITS > CPT_RLIM_NLIMITS) ++ __asm__("undefined\n"); ++ ++ for (i=0; icpt_rlim_cur[i] = tsk->signal->rlim[i].rlim_cur; ++ v->cpt_rlim_max[i] = tsk->signal->rlim[i].rlim_max; ++ } else { ++ v->cpt_rlim_cur[i] = CPT_NULL; ++ v->cpt_rlim_max[i] = CPT_NULL; ++ } ++ } ++#endif ++ ++#ifdef CONFIG_BEANCOUNTERS ++ if (tsk->mm) ++ v->cpt_mm_ub = cpt_lookup_ubc(tsk->mm->mm_ub, ctx); ++ else ++ v->cpt_mm_ub = CPT_NULL; ++ v->cpt_task_ub = cpt_lookup_ubc(tsk->task_bc.task_ub, ctx); ++ v->cpt_exec_ub = cpt_lookup_ubc(tsk->task_bc.exec_ub, ctx); ++ v->cpt_fork_sub = cpt_lookup_ubc(tsk->task_bc.fork_sub, ctx); ++#endif ++ ++ v->cpt_ptrace_message = tsk->ptrace_message; ++ v->cpt_pn_state = tsk->pn_state; ++ v->cpt_stopped_state = tsk->stopped_state; ++ v->cpt_sigsuspend_state = 0; ++ ++#ifdef CONFIG_X86_32 ++ if (tsk->thread.vm86_info) { ++ eprintk_ctx("vm86 task is running\n"); ++ cpt_release_buf(ctx); ++ return -EBUSY; ++ } ++#endif ++ ++ v->cpt_sigpending = cpt_sigset_export(&tsk->pending.signal); ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++ cpt_push_object(&saved_obj, ctx); ++ dump_kstack(tsk, ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ ++ cpt_push_object(&saved_obj, ctx); ++ err = dump_registers(tsk, ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ if (err) ++ return err; ++ ++ if (tsk_used_math(tsk)) { ++ cpt_push_object(&saved_obj, ctx); ++ dump_fpustate(tsk, ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ } ++ ++ if (tsk->last_siginfo) { ++ struct cpt_siginfo_image si; ++ cpt_push_object(&saved_obj, ctx); ++ ++ si.cpt_next = sizeof(si); ++ si.cpt_object = CPT_OBJ_LASTSIGINFO; ++ si.cpt_hdrlen = sizeof(si); ++ si.cpt_content = CPT_CONTENT_VOID; ++ ++ if (encode_siginfo(&si, tsk->last_siginfo)) ++ return -EINVAL; ++ ++ ctx->write(&si, sizeof(si), ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ } ++ ++ if (tsk->sas_ss_size) { ++ struct cpt_sigaltstack_image si; ++ cpt_push_object(&saved_obj, ctx); ++ ++ si.cpt_next = sizeof(si); ++ si.cpt_object = CPT_OBJ_SIGALTSTACK; ++ si.cpt_hdrlen = sizeof(si); ++ si.cpt_content = CPT_CONTENT_VOID; ++ ++ si.cpt_stack = tsk->sas_ss_sp; ++ si.cpt_stacksize = tsk->sas_ss_size; ++ ++ ctx->write(&si, sizeof(si), ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ } ++ ++ if (tsk->robust_list ++#ifdef CONFIG_COMPAT ++ || tsk->compat_robust_list ++#endif ++ ) { ++ struct cpt_task_aux_image ai; ++ cpt_push_object(&saved_obj, ctx); ++ ++ ai.cpt_next = sizeof(ai); ++ ai.cpt_object = CPT_OBJ_TASK_AUX; ++ ai.cpt_hdrlen = sizeof(ai); ++ ai.cpt_content = CPT_CONTENT_VOID; ++ ++ ai.cpt_robust_list = (unsigned long)tsk->robust_list; ++#ifdef CONFIG_X86_64 ++#ifdef CONFIG_COMPAT ++ if (task_thread_info(tsk)->flags & _TIF_IA32) ++ ai.cpt_robust_list = (unsigned long)tsk->compat_robust_list; ++#endif ++#endif ++ ctx->write(&ai, sizeof(ai), ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ } ++ ++ dump_sigqueue(&tsk->pending, ctx); ++ ++ last_thread = 1; ++ read_lock(&tasklist_lock); ++ do { ++ struct task_struct * next = next_thread(tsk); ++ if (next != tsk && !thread_group_leader(next)) ++ last_thread = 0; ++ } while (0); ++ read_unlock(&tasklist_lock); ++ ++ if (last_thread) { ++ struct task_struct *prev_tsk; ++ int err; ++ loff_t pos = ctx->file->f_pos; ++ ++ cpt_push_object(&saved_obj, ctx); ++ err = dump_one_signal_struct(tg_obj, ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ if (err) ++ return err; ++ ++ prev_tsk = tsk; ++ for (;;) { ++ if (prev_tsk->tgid == tsk->tgid) { ++ loff_t tg_pos; ++ ++ tg_pos = obj->o_pos + offsetof(struct cpt_task_image, cpt_signal); ++ ctx->pwrite(&pos, sizeof(pos), ctx, tg_pos); ++ if (thread_group_leader(prev_tsk)) ++ break; ++ } ++ ++ if (obj->o_list.prev == &ctx->object_array[CPT_OBJ_TASK]) { ++ eprintk_ctx("bug: thread group leader is lost\n"); ++ return -EINVAL; ++ } ++ ++ obj = list_entry(obj->o_list.prev, cpt_object_t, o_list); ++ prev_tsk = obj->o_obj; ++ } ++ } ++ ++ cpt_close_object(ctx); ++ return 0; ++} ++ ++int cpt_dump_tasks(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ cpt_open_section(ctx, CPT_SECT_TASKS); ++ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ int err; ++ ++ if ((err = dump_one_process(obj, ctx)) != 0) ++ return err; ++ } ++ ++ cpt_close_section(ctx); ++ return 0; ++} ++ ++int cpt_collect_signals(cpt_context_t *ctx) ++{ ++ cpt_object_t *obj; ++ ++ /* Collect process fd sets */ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ struct task_struct *tsk = obj->o_obj; ++ if (tsk->signal && !list_empty(&tsk->signal->posix_timers)) { ++ eprintk_ctx("task %d/%d(%s) uses posix timers\n", tsk->pid, task_pid_vnr(tsk), tsk->comm); ++ return -EBUSY; ++ } ++ if (tsk->signal && cpt_object_add(CPT_OBJ_SIGNAL_STRUCT, tsk->signal, ctx) == NULL) ++ return -ENOMEM; ++ if (tsk->sighand && cpt_object_add(CPT_OBJ_SIGHAND_STRUCT, tsk->sighand, ctx) == NULL) ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++ ++static int dump_one_sighand_struct(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ struct sighand_struct *sig = obj->o_obj; ++ struct cpt_sighand_image *v = cpt_get_buf(ctx); ++ int i; ++ ++ cpt_open_object(obj, ctx); ++ ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_SIGHAND_STRUCT; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++ for (i=0; i< _NSIG; i++) { ++ if (sig->action[i].sa.sa_handler != SIG_DFL || ++ sig->action[i].sa.sa_flags) { ++ loff_t saved_obj; ++ struct cpt_sighandler_image *o = cpt_get_buf(ctx); ++ ++ cpt_push_object(&saved_obj, ctx); ++ cpt_open_object(NULL, ctx); ++ ++ o->cpt_next = CPT_NULL; ++ o->cpt_object = CPT_OBJ_SIGHANDLER; ++ o->cpt_hdrlen = sizeof(*o); ++ o->cpt_content = CPT_CONTENT_VOID; ++ ++ o->cpt_signo = i; ++ o->cpt_handler = (unsigned long)sig->action[i].sa.sa_handler; ++ o->cpt_restorer = 0; ++#ifdef CONFIG_X86 ++ o->cpt_restorer = (unsigned long)sig->action[i].sa.sa_restorer; ++#endif ++ o->cpt_flags = sig->action[i].sa.sa_flags; ++ memcpy(&o->cpt_mask, &sig->action[i].sa.sa_mask, 8); ++ ctx->write(o, sizeof(*o), ctx); ++ cpt_release_buf(ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ } ++ } ++ ++ cpt_close_object(ctx); ++ return 0; ++} ++ ++int cpt_dump_sighand(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ cpt_open_section(ctx, CPT_SECT_SIGHAND_STRUCT); ++ ++ for_each_object(obj, CPT_OBJ_SIGHAND_STRUCT) { ++ int err; ++ ++ if ((err = dump_one_sighand_struct(obj, ctx)) != 0) ++ return err; ++ } ++ ++ cpt_close_section(ctx); ++ return 0; ++} +Index: kernel/kernel/cpt/cpt_process.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_process.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,13 @@ ++int cpt_collect_signals(cpt_context_t *); ++int cpt_dump_signal(struct cpt_context *); ++int cpt_dump_sighand(struct cpt_context *); ++int cpt_dump_tasks(struct cpt_context *); ++ ++int rst_signal_complete(struct cpt_task_image *ti, int *exiting, struct cpt_context *ctx); ++__u32 rst_signal_flag(struct cpt_task_image *ti, struct cpt_context *ctx); ++ ++int rst_restore_process(struct cpt_context *ctx); ++int rst_process_linkage(struct cpt_context *ctx); ++ ++int check_task_state(struct task_struct *tsk, struct cpt_context *ctx); ++struct pid *alloc_vpid_safe(pid_t vnr); +Index: kernel/kernel/cpt/cpt_socket.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_socket.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,787 @@ ++/* ++ * ++ * kernel/cpt/cpt_socket.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_mm.h" ++#include "cpt_socket.h" ++#include "cpt_files.h" ++#include "cpt_kernel.h" ++ ++static int dump_rqueue(int owner, struct sock *sk, struct cpt_context *ctx); ++ ++ ++/* Sockets are quite different of another kinds of files. ++ * There is one simplification: only one struct file can refer to a socket, ++ * so we could store information about socket directly in section FILES as ++ * a description of a file and append f.e. array of not-yet-accepted ++ * connections of listening socket as array of auxiliary data. ++ * ++ * Complications are: ++ * 1. TCP sockets can be orphans. We have to relocate orphans as well, ++ * so we have to create special section for orphans. ++ * 2. AF_UNIX sockets are distinguished objects: set of links between ++ * AF_UNIX sockets is quite arbitrary. ++ * A. Each socket can refers to many of files due to FD passing. ++ * B. Each socket except for connected ones can have in queue skbs ++ * sent by any of sockets. ++ * ++ * 2A is relatively easy: after our tasks are frozen we make an additional ++ * recursive pass throgh set of collected files and get referenced to ++ * FD passed files. After end of recursion, all the files are treated ++ * in the same way. All they will be stored in section FILES. ++ * ++ * 2B. We have to resolve all those references at some point. ++ * It is the place where pipe-like approach to image fails. ++ * ++ * All this makes socket checkpointing quite chumbersome. ++ * Right now we collect all the sockets and assign some numeric index value ++ * to each of them. The socket section is separate and put after section FILES, ++ * so section FILES refers to sockets by index, section SOCKET refers to FILES ++ * as usual by position in image. All the refs inside socket section are ++ * by index. When restoring we read socket section, create objects to hold ++ * mappings index <-> pos. At the second pass we open sockets (simultaneosly ++ * with their pairs) and create FILE objects. ++ */ ++ ++ ++/* ====== FD passing ====== */ ++ ++/* Almost nobody does FD passing via AF_UNIX sockets, nevertheless we ++ * have to implement this. A problem is that in general case we receive ++ * skbs from an unknown context, so new files can arrive to checkpointed ++ * set of processes even after they are stopped. Well, we are going just ++ * to ignore unknown fds while doing real checkpointing. It is fair because ++ * links outside checkpointed set are going to fail anyway. ++ * ++ * ATTN: the procedure is recursive. We linearize the recursion adding ++ * newly found files to the end of file list, so they will be analyzed ++ * in the same loop. ++ */ ++ ++static int collect_one_passedfd(struct file *file, cpt_context_t * ctx) ++{ ++ struct inode *inode = file->f_dentry->d_inode; ++ struct socket *sock; ++ struct sock *sk; ++ struct sk_buff *skb; ++ ++ if (!S_ISSOCK(inode->i_mode)) ++ return -ENOTSOCK; ++ ++ sock = &container_of(inode, struct socket_alloc, vfs_inode)->socket; ++ ++ if (sock->ops->family != AF_UNIX) ++ return 0; ++ ++ sk = sock->sk; ++ ++ /* Subtle locking issue. skbs cannot be removed while ++ * we are scanning, because all the processes are stopped. ++ * They still can be added to tail of queue. Locking while ++ * we dereference skb->next is enough to resolve this. ++ * See above about collision with skbs added after we started ++ * checkpointing. ++ */ ++ ++ skb = skb_peek(&sk->sk_receive_queue); ++ while (skb && skb != (struct sk_buff*)&sk->sk_receive_queue) { ++ if (UNIXCB(skb).fp && skb->sk && ++ (!sock_flag(skb->sk, SOCK_DEAD) || unix_peer(sk) == skb->sk)) { ++ struct scm_fp_list *fpl = UNIXCB(skb).fp; ++ int i; ++ ++ for (i = fpl->count-1; i >= 0; i--) { ++ if (cpt_object_add(CPT_OBJ_FILE, fpl->fp[i], ctx) == NULL) ++ return -ENOMEM; ++ } ++ } ++ ++ spin_lock_irq(&sk->sk_receive_queue.lock); ++ skb = skb->next; ++ spin_unlock_irq(&sk->sk_receive_queue.lock); ++ } ++ ++ return 0; ++} ++ ++int cpt_collect_passedfds(cpt_context_t * ctx) ++{ ++ cpt_object_t *obj; ++ ++ for_each_object(obj, CPT_OBJ_FILE) { ++ struct file *file = obj->o_obj; ++ ++ if (S_ISSOCK(file->f_dentry->d_inode->i_mode)) { ++ int err; ++ ++ if ((err = collect_one_passedfd(file, ctx)) < 0) ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ====== End of FD passing ====== */ ++ ++/* Must be called under bh_lock_sock() */ ++ ++void clear_backlog(struct sock *sk) ++{ ++ struct sk_buff *skb = sk->sk_backlog.head; ++ ++ sk->sk_backlog.head = sk->sk_backlog.tail = NULL; ++ while (skb) { ++ struct sk_buff *next = skb->next; ++ ++ skb->next = NULL; ++ kfree_skb(skb); ++ skb = next; ++ } ++} ++ ++void release_sock_nobacklog(struct sock *sk) ++{ ++ spin_lock_bh(&(sk->sk_lock.slock)); ++ clear_backlog(sk); ++ sk->sk_lock.owned = 0; ++ if (waitqueue_active(&(sk->sk_lock.wq))) ++ wake_up(&(sk->sk_lock.wq)); ++ spin_unlock_bh(&(sk->sk_lock.slock)); ++} ++ ++int cpt_dump_skb(int type, int owner, struct sk_buff *skb, ++ struct cpt_context *ctx) ++{ ++ struct cpt_skb_image *v = cpt_get_buf(ctx); ++ loff_t saved_obj; ++ struct timeval tmptv; ++ ++ cpt_push_object(&saved_obj, ctx); ++ cpt_open_object(NULL, ctx); ++ ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_SKB; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ v->cpt_owner = owner; ++ v->cpt_queue = type; ++ skb_get_timestamp(skb, &tmptv); ++ v->cpt_stamp = cpt_timeval_export(&tmptv); ++ v->cpt_hspace = skb->data - skb->head; ++ v->cpt_tspace = skb->end - skb->tail; ++ v->cpt_h = skb_transport_header(skb) - skb->head; ++ v->cpt_nh = skb_network_header(skb) - skb->head; ++ v->cpt_mac = skb_mac_header(skb) - skb->head; ++ BUILD_BUG_ON(sizeof(skb->cb) < sizeof(v->cpt_cb)); ++ memcpy(v->cpt_cb, skb->cb, sizeof(v->cpt_cb)); ++ if (sizeof(skb->cb) > sizeof(v->cpt_cb)) { ++ int i; ++ for (i=sizeof(v->cpt_cb); icb); i++) { ++ if (skb->cb[i]) { ++ wprintk_ctx("dirty skb cb"); ++ break; ++ } ++ } ++ } ++ v->cpt_len = skb->len; ++ v->cpt_mac_len = skb->mac_len; ++ v->cpt_csum = skb->csum; ++ v->cpt_local_df = skb->local_df; ++ v->cpt_pkt_type = skb->pkt_type; ++ v->cpt_ip_summed = skb->ip_summed; ++ v->cpt_priority = skb->priority; ++ v->cpt_protocol = skb->protocol; ++ v->cpt_security = 0; ++ v->cpt_gso_segs = skb_shinfo(skb)->gso_segs; ++ v->cpt_gso_size = skb_shinfo(skb)->gso_size; ++ if (skb_shinfo(skb)->gso_type) { ++ eprintk_ctx("skb ufo is not supported\n"); ++ return -EINVAL; ++ } ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++ if (skb->len + (skb->data - skb->head) > 0) { ++ struct cpt_obj_bits ob; ++ loff_t saved_obj2; ++ ++ cpt_push_object(&saved_obj2, ctx); ++ cpt_open_object(NULL, ctx); ++ ob.cpt_next = CPT_NULL; ++ ob.cpt_object = CPT_OBJ_BITS; ++ ob.cpt_hdrlen = sizeof(ob); ++ ob.cpt_content = CPT_CONTENT_DATA; ++ ob.cpt_size = skb->len + v->cpt_hspace; ++ ++ ctx->write(&ob, sizeof(ob), ctx); ++ ++ ctx->write(skb->head, (skb->data-skb->head) + (skb->len-skb->data_len), ctx); ++ if (skb->data_len) { ++ int offset = skb->len - skb->data_len; ++ while (offset < skb->len) { ++ int copy = skb->len - offset; ++ if (copy > PAGE_SIZE) ++ copy = PAGE_SIZE; ++ (void)cpt_get_buf(ctx); ++ if (skb_copy_bits(skb, offset, ctx->tmpbuf, copy)) ++ BUG(); ++ ctx->write(ctx->tmpbuf, copy, ctx); ++ __cpt_release_buf(ctx); ++ offset += copy; ++ } ++ } ++ ++ ctx->align(ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_obj2, ctx); ++ } ++ ++ if (skb->sk && skb->sk->sk_family == AF_UNIX) { ++ struct scm_fp_list *fpl = UNIXCB(skb).fp; ++ ++ if (fpl) { ++ int i; ++ ++ for (i = 0; i < fpl->count; i++) { ++ struct cpt_fd_image v; ++ cpt_object_t *obj; ++ loff_t saved_obj2; ++ ++ obj = lookup_cpt_object(CPT_OBJ_FILE, fpl->fp[i], ctx); ++ ++ if (!obj) { ++ eprintk_ctx("lost passed FD\n"); ++ return -EINVAL; ++ } ++ ++ cpt_push_object(&saved_obj2, ctx); ++ cpt_open_object(NULL, ctx); ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_FILEDESC; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_VOID; ++ ++ v.cpt_fd = i; ++ v.cpt_file = obj->o_pos; ++ v.cpt_flags = 0; ++ ctx->write(&v, sizeof(v), ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_obj2, ctx); ++ } ++ } ++ } ++ ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ return 0; ++} ++ ++static int dump_rqueue(int idx, struct sock *sk, struct cpt_context *ctx) ++{ ++ struct sk_buff *skb; ++ struct sock *sk_cache = NULL; ++ ++ skb = skb_peek(&sk->sk_receive_queue); ++ while (skb && skb != (struct sk_buff*)&sk->sk_receive_queue) { ++ int err; ++ ++ if (sk->sk_family == AF_UNIX) { ++ cpt_object_t *obj; ++ if (skb->sk != sk_cache) { ++ idx = -1; ++ sk_cache = NULL; ++ obj = lookup_cpt_object(CPT_OBJ_SOCKET, skb->sk, ctx); ++ if (obj) { ++ idx = obj->o_index; ++ sk_cache = skb->sk; ++ } else if (unix_peer(sk) != skb->sk) ++ goto next_skb; ++ } ++ } ++ ++ err = cpt_dump_skb(CPT_SKB_RQ, idx, skb, ctx); ++ if (err) ++ return err; ++ ++next_skb: ++ spin_lock_irq(&sk->sk_receive_queue.lock); ++ skb = skb->next; ++ spin_unlock_irq(&sk->sk_receive_queue.lock); ++ } ++ return 0; ++} ++ ++static int dump_wqueue(int idx, struct sock *sk, struct cpt_context *ctx) ++{ ++ struct sk_buff *skb; ++ ++ skb = skb_peek(&sk->sk_write_queue); ++ while (skb && skb != (struct sk_buff*)&sk->sk_write_queue) { ++ int err = cpt_dump_skb(CPT_SKB_WQ, idx, skb, ctx); ++ if (err) ++ return err; ++ ++ spin_lock_irq(&sk->sk_write_queue.lock); ++ skb = skb->next; ++ spin_unlock_irq(&sk->sk_write_queue.lock); ++ } ++ return 0; ++} ++ ++void cpt_dump_sock_attr(struct sock *sk, cpt_context_t *ctx) ++{ ++ loff_t saved_obj; ++ if (sk->sk_filter) { ++ struct cpt_obj_bits v; ++ ++ cpt_push_object(&saved_obj, ctx); ++ cpt_open_object(NULL, ctx); ++ ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_SKFILTER; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_DATA; ++ v.cpt_size = sk->sk_filter->len*sizeof(struct sock_filter); ++ ++ ctx->write(&v, sizeof(v), ctx); ++ ctx->write(sk->sk_filter->insns, v.cpt_size, ctx); ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ } ++ if (sk->sk_family == AF_INET || sk->sk_family == AF_INET6) { ++ cpt_push_object(&saved_obj, ctx); ++ cpt_dump_mcfilter(sk, ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ } ++} ++ ++/* Dump socket content */ ++ ++int cpt_dump_socket(cpt_object_t *obj, struct sock *sk, int index, int parent, struct cpt_context *ctx) ++{ ++ struct cpt_sock_image *v = cpt_get_buf(ctx); ++ struct socket *sock; ++ struct timeval tmptv; ++ ++ cpt_open_object(obj, ctx); ++ ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_SOCKET; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ v->cpt_file = CPT_NULL; ++ sock = sk->sk_socket; ++ if (sock && sock->file) { ++ cpt_object_t *tobj; ++ tobj = lookup_cpt_object(CPT_OBJ_FILE, sock->file, ctx); ++ if (tobj) ++ v->cpt_file = tobj->o_pos; ++ } ++ v->cpt_index = index; ++ v->cpt_parent = parent; ++ ++ if (sk->sk_family == AF_INET || sk->sk_family == AF_INET6) { ++ if (sock && !obj->o_lock) { ++ lockdep_off(); ++ lock_sock(sk); ++ lockdep_on(); ++ obj->o_lock = 1; ++ } ++ } ++ ++ /* Some bits stored in inode */ ++ v->cpt_ssflags = sock ? sock->flags : 0; ++ v->cpt_sstate = sock ? sock->state : 0; ++ v->cpt_passcred = sock ? test_bit(SOCK_PASSCRED, &sock->flags) : 0; ++ ++ /* Common data */ ++ v->cpt_family = sk->sk_family; ++ v->cpt_type = sk->sk_type; ++ v->cpt_state = sk->sk_state; ++ v->cpt_reuse = sk->sk_reuse; ++ v->cpt_zapped = sock_flag(sk, SOCK_ZAPPED); ++ v->cpt_shutdown = sk->sk_shutdown; ++ v->cpt_userlocks = sk->sk_userlocks; ++ v->cpt_no_check = sk->sk_no_check; ++ v->cpt_zapped = sock_flag(sk, SOCK_DBG); ++ v->cpt_rcvtstamp = sock_flag(sk, SOCK_RCVTSTAMP); ++ v->cpt_localroute = sock_flag(sk, SOCK_LOCALROUTE); ++ v->cpt_protocol = sk->sk_protocol; ++ v->cpt_err = sk->sk_err; ++ v->cpt_err_soft = sk->sk_err_soft; ++ v->cpt_max_ack_backlog = sk->sk_max_ack_backlog; ++ v->cpt_priority = sk->sk_priority; ++ v->cpt_rcvlowat = sk->sk_rcvlowat; ++ v->cpt_rcvtimeo = CPT_NULL; ++ if (sk->sk_rcvtimeo != MAX_SCHEDULE_TIMEOUT) ++ v->cpt_rcvtimeo = sk->sk_rcvtimeo > INT_MAX ? INT_MAX : sk->sk_rcvtimeo; ++ v->cpt_sndtimeo = CPT_NULL; ++ if (sk->sk_sndtimeo != MAX_SCHEDULE_TIMEOUT) ++ v->cpt_sndtimeo = sk->sk_sndtimeo > INT_MAX ? INT_MAX : sk->sk_sndtimeo; ++ v->cpt_rcvbuf = sk->sk_rcvbuf; ++ v->cpt_sndbuf = sk->sk_sndbuf; ++ v->cpt_bound_dev_if = sk->sk_bound_dev_if; ++ v->cpt_flags = sk->sk_flags; ++ v->cpt_lingertime = CPT_NULL; ++ if (sk->sk_lingertime != MAX_SCHEDULE_TIMEOUT) ++ v->cpt_lingertime = sk->sk_lingertime > INT_MAX ? INT_MAX : sk->sk_lingertime; ++ v->cpt_peer_pid = sk->sk_peercred.pid; ++ v->cpt_peer_uid = sk->sk_peercred.uid; ++ v->cpt_peer_gid = sk->sk_peercred.gid; ++ tmptv = ktime_to_timeval(sk->sk_stamp); ++ v->cpt_stamp = cpt_timeval_export(&tmptv); ++ ++ v->cpt_peer = -1; ++ v->cpt_socketpair = 0; ++ v->cpt_deleted = 0; ++ ++ v->cpt_laddrlen = 0; ++ if (sock) { ++ int alen = sizeof(v->cpt_laddr); ++ int err = sock->ops->getname(sock, (struct sockaddr*)&v->cpt_laddr, &alen, 0); ++ if (err) { ++ cpt_release_buf(ctx); ++ return err; ++ } ++ v->cpt_laddrlen = alen; ++ } ++ v->cpt_raddrlen = 0; ++ if (sock) { ++ int alen = sizeof(v->cpt_raddr); ++ int err = sock->ops->getname(sock, (struct sockaddr*)&v->cpt_raddr, &alen, 2); ++ if (!err) ++ v->cpt_raddrlen = alen; ++ } ++ ++ if (sk->sk_family == AF_UNIX) { ++ if (unix_sk(sk)->dentry) { ++ struct dentry *d = unix_sk(sk)->dentry; ++ v->cpt_deleted = !IS_ROOT(d) && d_unhashed(d); ++ if (!v->cpt_deleted) { ++ int err = 0; ++ char *path; ++ unsigned long pg = __get_free_page(GFP_KERNEL); ++ ++ if (!pg) { ++ cpt_release_buf(ctx); ++ return -ENOMEM; ++ } ++ ++ path = d_path(d, unix_sk(sk)->mnt, (char *)pg, PAGE_SIZE); ++ ++ if (!IS_ERR(path)) { ++ int len = strlen(path); ++ if (len < 126) { ++ strcpy(((char*)v->cpt_laddr)+2, path); ++ v->cpt_laddrlen = len + 2; ++ } else { ++ wprintk_ctx("af_unix path is too long: %s (%s)\n", path, ((char*)v->cpt_laddr)+2); ++ } ++ err = cpt_verify_overmount(path, d, unix_sk(sk)->mnt, ctx); ++ } else { ++ eprintk_ctx("cannot get path of an af_unix socket\n"); ++ err = PTR_ERR(path); ++ } ++ free_page(pg); ++ if (err) { ++ cpt_release_buf(ctx); ++ return err; ++ } ++ } ++ } ++ ++ /* If the socket is connected, find its peer. If peer is not ++ * in our table, the socket is connected to external process ++ * and we consider it disconnected. ++ */ ++ if (unix_peer(sk)) { ++ cpt_object_t *pobj; ++ pobj = lookup_cpt_object(CPT_OBJ_SOCKET, unix_peer(sk), ctx); ++ if (pobj) ++ v->cpt_peer = pobj->o_index; ++ else ++ v->cpt_shutdown = SHUTDOWN_MASK; ++ ++ if (unix_peer(unix_peer(sk)) == sk) ++ v->cpt_socketpair = 1; ++ } ++ ++ /* If the socket shares address with another socket it is ++ * child of some listening socket. Find and record it. */ ++ if (unix_sk(sk)->addr && ++ atomic_read(&unix_sk(sk)->addr->refcnt) > 1 && ++ sk->sk_state != TCP_LISTEN) { ++ cpt_object_t *pobj; ++ for_each_object(pobj, CPT_OBJ_SOCKET) { ++ struct sock *psk = pobj->o_obj; ++ if (psk->sk_family == AF_UNIX && ++ psk->sk_state == TCP_LISTEN && ++ unix_sk(psk)->addr == unix_sk(sk)->addr) { ++ v->cpt_parent = pobj->o_index; ++ break; ++ } ++ } ++ } ++ } ++ ++ if (sk->sk_family == AF_INET || sk->sk_family == AF_INET6) ++ cpt_dump_socket_in(v, sk, ctx); ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++ cpt_dump_sock_attr(sk, ctx); ++ ++ dump_rqueue(index, sk, ctx); ++ if (sk->sk_family == AF_INET || sk->sk_family == AF_INET6) { ++ dump_wqueue(index, sk, ctx); ++ cpt_dump_ofo_queue(index, sk, ctx); ++ } ++ ++ if ((sk->sk_family == AF_INET || sk->sk_family == AF_INET6) ++ && sk->sk_state == TCP_LISTEN) ++ cpt_dump_synwait_queue(sk, index, ctx); ++ ++ cpt_close_object(ctx); ++ ++ if ((sk->sk_family == AF_INET || sk->sk_family == AF_INET6) ++ && sk->sk_state == TCP_LISTEN) ++ cpt_dump_accept_queue(sk, index, ctx); ++ ++ return 0; ++} ++ ++int cpt_dump_orphaned_sockets(struct cpt_context *ctx) ++{ ++ int i; ++ ++ cpt_open_section(ctx, CPT_SECT_ORPHANS); ++ ++ for (i = 0; i < tcp_hashinfo.ehash_size; i++) { ++ struct sock *sk; ++ struct hlist_node *node; ++ rwlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, i); ++retry: ++ read_lock_bh(lock); ++ sk_for_each(sk, node, &tcp_hashinfo.ehash[i].chain) { ++ ++ if (sk->owner_env != get_exec_env()) ++ continue; ++ if (sk->sk_socket) ++ continue; ++ if (!sock_flag(sk, SOCK_DEAD)) ++ continue; ++ if (lookup_cpt_object(CPT_OBJ_SOCKET, sk, ctx)) ++ continue; ++ sock_hold(sk); ++ read_unlock_bh(lock); ++ ++ local_bh_disable(); ++ bh_lock_sock(sk); ++ if (sock_owned_by_user(sk)) ++ eprintk_ctx("BUG: sk locked by whom?\n"); ++ sk->sk_lock.owned = 1; ++ bh_unlock_sock(sk); ++ local_bh_enable(); ++ ++ cpt_dump_socket(NULL, sk, -1, -1, ctx); ++ ++ local_bh_disable(); ++ bh_lock_sock(sk); ++ sk->sk_lock.owned = 0; ++ clear_backlog(sk); ++ tcp_done(sk); ++ bh_unlock_sock(sk); ++ local_bh_enable(); ++ sock_put(sk); ++ ++ goto retry; ++ } ++ read_unlock_bh(lock); ++ } ++ cpt_close_section(ctx); ++ return 0; ++} ++ ++static int can_dump(struct sock *sk, cpt_context_t *ctx) ++{ ++ switch (sk->sk_family) { ++ case AF_NETLINK: ++ if (((struct netlink_sock *)sk)->cb) { ++ eprintk_ctx("netlink socket has active callback\n"); ++ return 0; ++ } ++ break; ++ } ++ return 1; ++} ++ ++/* We are not going to block suspend when we have external AF_UNIX connections. ++ * But we cannot stop feed of new packets/connections to our environment ++ * from outside. Taking into account that it is intrincically unreliable, ++ * we collect some amount of data, but when checkpointing/restoring we ++ * are going to drop everything, which does not make sense: skbs sent ++ * by outside processes, connections from outside etc. etc. ++ */ ++ ++/* The first pass. When we see socket referenced by a file, we just ++ * add it to socket table */ ++int cpt_collect_socket(struct file *file, cpt_context_t * ctx) ++{ ++ cpt_object_t *obj; ++ struct socket *sock; ++ struct sock *sk; ++ ++ if (!S_ISSOCK(file->f_dentry->d_inode->i_mode)) ++ return -ENOTSOCK; ++ sock = &container_of(file->f_dentry->d_inode, struct socket_alloc, vfs_inode)->socket; ++ sk = sock->sk; ++ if (!can_dump(sk, ctx)) ++ return -EAGAIN; ++ if ((obj = cpt_object_add(CPT_OBJ_SOCKET, sk, ctx)) == NULL) ++ return -ENOMEM; ++ obj->o_parent = file; ++ ++ return 0; ++} ++ ++/* ++ * We should end with table containing: ++ * * all sockets opened by our processes in the table. ++ * * all the sockets queued in listening queues on _our_ listening sockets, ++ * which are connected to our opened sockets. ++ */ ++ ++static int collect_one_unix_listening_sock(cpt_object_t *obj, cpt_context_t * ctx) ++{ ++ struct sock *sk = obj->o_obj; ++ cpt_object_t *cobj; ++ struct sk_buff *skb; ++ ++ skb = skb_peek(&sk->sk_receive_queue); ++ while (skb && skb != (struct sk_buff*)&sk->sk_receive_queue) { ++ struct sock *lsk = skb->sk; ++ if (unix_peer(lsk) && ++ lookup_cpt_object(CPT_OBJ_SOCKET, unix_peer(lsk), ctx)) { ++ if ((cobj = cpt_object_add(CPT_OBJ_SOCKET, lsk, ctx)) == NULL) ++ return -ENOMEM; ++ cobj->o_parent = obj->o_parent; ++ } ++ spin_lock_irq(&sk->sk_receive_queue.lock); ++ skb = skb->next; ++ spin_unlock_irq(&sk->sk_receive_queue.lock); ++ } ++ ++ return 0; ++} ++ ++int cpt_index_sockets(cpt_context_t * ctx) ++{ ++ cpt_object_t *obj; ++ unsigned long index = 0; ++ ++ /* Collect not-yet-accepted children of listening sockets. */ ++ for_each_object(obj, CPT_OBJ_SOCKET) { ++ struct sock *sk = obj->o_obj; ++ ++ if (sk->sk_state != TCP_LISTEN) ++ continue; ++ ++ if (sk->sk_family == AF_UNIX) ++ collect_one_unix_listening_sock(obj, ctx); ++ } ++ ++ /* Assign indices to all the sockets. */ ++ for_each_object(obj, CPT_OBJ_SOCKET) { ++ struct sock *sk = obj->o_obj; ++ cpt_obj_setindex(obj, index++, ctx); ++ ++ if (sk->sk_socket && sk->sk_socket->file) { ++ cpt_object_t *tobj; ++ tobj = lookup_cpt_object(CPT_OBJ_FILE, sk->sk_socket->file, ctx); ++ if (tobj) ++ cpt_obj_setindex(tobj, obj->o_index, ctx); ++ } ++ } ++ ++ return 0; ++} ++ ++void cpt_unlock_sockets(cpt_context_t * ctx) ++{ ++ cpt_object_t *obj; ++ ++ lockdep_off(); ++ for_each_object(obj, CPT_OBJ_SOCKET) { ++ struct sock *sk = obj->o_obj; ++ if (sk && obj->o_lock) { ++ if (sk->sk_socket) ++ release_sock(sk); ++ } ++ } ++ lockdep_on(); ++} ++ ++void cpt_kill_sockets(cpt_context_t * ctx) ++{ ++ cpt_object_t *obj; ++ ++ for_each_object(obj, CPT_OBJ_SOCKET) { ++ struct sock *sk = obj->o_obj; ++ if (sk && obj->o_lock) { ++ struct ve_struct *old_env; ++ old_env = set_exec_env(sk->owner_env); ++ cpt_kill_socket(sk, ctx); ++ if (sk->sk_socket) ++ release_sock_nobacklog(sk); ++ set_exec_env(old_env); ++ } ++ } ++} ++ ++__u32 cpt_socket_fasync(struct file *file, struct cpt_context *ctx) ++{ ++ struct fasync_struct *fa; ++ struct inode *inode = file->f_dentry->d_inode; ++ struct socket *sock; ++ ++ sock = &container_of(inode, struct socket_alloc, vfs_inode)->socket; ++ ++ for (fa = sock->fasync_list; fa; fa = fa->fa_next) { ++ if (fa->fa_file == file) ++ return fa->fa_fd; ++ } ++ return -1; ++} +Index: kernel/kernel/cpt/cpt_socket.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_socket.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,33 @@ ++struct sock; ++ ++int cpt_collect_passedfds(cpt_context_t *); ++int cpt_index_sockets(cpt_context_t *); ++int cpt_collect_socket(struct file *, cpt_context_t *); ++int cpt_dump_socket(cpt_object_t *obj, struct sock *sk, int index, int parent, struct cpt_context *ctx); ++int cpt_dump_accept_queue(struct sock *sk, int index, struct cpt_context *ctx); ++int cpt_dump_synwait_queue(struct sock *sk, int index, struct cpt_context *ctx); ++int rst_sockets(struct cpt_context *ctx); ++int rst_sockets_complete(struct cpt_context *ctx); ++int cpt_dump_orphaned_sockets(struct cpt_context *ctx); ++ ++int rst_sock_attr(loff_t *pos_p, struct sock *sk, cpt_context_t *ctx); ++struct sk_buff * rst_skb(loff_t *pos_p, __u32 *owner, __u32 *queue, struct cpt_context *ctx); ++ ++void cpt_unlock_sockets(cpt_context_t *); ++void cpt_kill_sockets(cpt_context_t *); ++ ++ ++int cpt_kill_socket(struct sock *, cpt_context_t *); ++int cpt_dump_socket_in(struct cpt_sock_image *, struct sock *, struct cpt_context*); ++int rst_socket_in(struct cpt_sock_image *si, loff_t pos, struct sock *, struct cpt_context *ctx); ++__u32 cpt_socket_fasync(struct file *file, struct cpt_context *ctx); ++int cpt_attach_accept(struct sock *lsk, struct sock *sk, cpt_context_t *); ++int rst_restore_synwait_queue(struct sock *sk, struct cpt_sock_image *si, loff_t pos, struct cpt_context *ctx); ++int cpt_dump_ofo_queue(int idx, struct sock *sk, struct cpt_context *ctx); ++int cpt_dump_skb(int type, int owner, struct sk_buff *skb, struct cpt_context *ctx); ++int cpt_dump_mcfilter(struct sock *sk, struct cpt_context *ctx); ++ ++int rst_sk_mcfilter_in(struct sock *sk, struct cpt_sockmc_image *v, ++ loff_t pos, cpt_context_t *ctx); ++int rst_sk_mcfilter_in6(struct sock *sk, struct cpt_sockmc_image *v, ++ loff_t pos, cpt_context_t *ctx); +Index: kernel/kernel/cpt/cpt_socket_in.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_socket_in.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,449 @@ ++/* ++ * ++ * kernel/cpt/cpt_socket_in.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_mm.h" ++#include "cpt_socket.h" ++#include "cpt_kernel.h" ++ ++static inline __u32 jiffies_export(unsigned long tmo) ++{ ++ __s32 delta = (long)(tmo - jiffies); ++ return delta; ++} ++ ++static inline __u32 tcp_jiffies_export(__u32 tmo) ++{ ++ __s32 delta = tmo - tcp_time_stamp; ++ return delta; ++} ++ ++int cpt_dump_ofo_queue(int idx, struct sock *sk, struct cpt_context *ctx) ++{ ++ struct sk_buff *skb; ++ struct tcp_sock *tp; ++ ++ if (sk->sk_type != SOCK_STREAM || sk->sk_protocol != IPPROTO_TCP) ++ return 0; ++ ++ tp = tcp_sk(sk); ++ ++ skb = skb_peek(&tp->out_of_order_queue); ++ while (skb && skb != (struct sk_buff*)&tp->out_of_order_queue) { ++ int err; ++ ++ err = cpt_dump_skb(CPT_SKB_OFOQ, idx, skb, ctx); ++ if (err) ++ return err; ++ ++ spin_lock_irq(&tp->out_of_order_queue.lock); ++ skb = skb->next; ++ spin_unlock_irq(&tp->out_of_order_queue.lock); ++ } ++ return 0; ++} ++ ++static int cpt_dump_socket_tcp(struct cpt_sock_image *si, struct sock *sk, ++ struct cpt_context *ctx) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ si->cpt_pred_flags = tp->pred_flags; ++ si->cpt_rcv_nxt = tp->rcv_nxt; ++ si->cpt_snd_nxt = tp->snd_nxt; ++ si->cpt_snd_una = tp->snd_una; ++ si->cpt_snd_sml = tp->snd_sml; ++ si->cpt_rcv_tstamp = tcp_jiffies_export(tp->rcv_tstamp); ++ si->cpt_lsndtime = tcp_jiffies_export(tp->lsndtime); ++ si->cpt_tcp_header_len = tp->tcp_header_len; ++ si->cpt_ack_pending = inet_csk(sk)->icsk_ack.pending; ++ si->cpt_quick = inet_csk(sk)->icsk_ack.quick; ++ si->cpt_pingpong = inet_csk(sk)->icsk_ack.pingpong; ++ si->cpt_blocked = inet_csk(sk)->icsk_ack.blocked; ++ si->cpt_ato = inet_csk(sk)->icsk_ack.ato; ++ si->cpt_ack_timeout = jiffies_export(inet_csk(sk)->icsk_ack.timeout); ++ si->cpt_lrcvtime = tcp_jiffies_export(inet_csk(sk)->icsk_ack.lrcvtime); ++ si->cpt_last_seg_size = inet_csk(sk)->icsk_ack.last_seg_size; ++ si->cpt_rcv_mss = inet_csk(sk)->icsk_ack.rcv_mss; ++ si->cpt_snd_wl1 = tp->snd_wl1; ++ si->cpt_snd_wnd = tp->snd_wnd; ++ si->cpt_max_window = tp->max_window; ++ si->cpt_pmtu_cookie = inet_csk(sk)->icsk_pmtu_cookie; ++ si->cpt_mss_cache = tp->mss_cache; ++ si->cpt_mss_cache_std = tp->mss_cache; /* FIXMW was tp->mss_cache_std */ ++ si->cpt_mss_clamp = tp->rx_opt.mss_clamp; ++ si->cpt_ext_header_len = inet_csk(sk)->icsk_ext_hdr_len; ++ si->cpt_ext2_header_len = 0; ++ si->cpt_ca_state = inet_csk(sk)->icsk_ca_state; ++ si->cpt_retransmits = inet_csk(sk)->icsk_retransmits; ++ si->cpt_reordering = tp->reordering; ++ si->cpt_frto_counter = tp->frto_counter; ++ si->cpt_frto_highmark = tp->frto_highmark; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9) ++ // // si->cpt_adv_cong = tp->adv_cong; ++#endif ++ si->cpt_defer_accept = inet_csk(sk)->icsk_accept_queue.rskq_defer_accept; ++ si->cpt_backoff = inet_csk(sk)->icsk_backoff; ++ si->cpt_srtt = tp->srtt; ++ si->cpt_mdev = tp->mdev; ++ si->cpt_mdev_max = tp->mdev_max; ++ si->cpt_rttvar = tp->rttvar; ++ si->cpt_rtt_seq = tp->rtt_seq; ++ si->cpt_rto = inet_csk(sk)->icsk_rto; ++ si->cpt_packets_out = tp->packets_out; ++ si->cpt_left_out = tp->sacked_out + tp->lost_out; ++ si->cpt_retrans_out = tp->retrans_out; ++ si->cpt_lost_out = tp->lost_out; ++ si->cpt_sacked_out = tp->sacked_out; ++ si->cpt_fackets_out = tp->fackets_out; ++ si->cpt_snd_ssthresh = tp->snd_ssthresh; ++ si->cpt_snd_cwnd = tp->snd_cwnd; ++ si->cpt_snd_cwnd_cnt = tp->snd_cwnd_cnt; ++ si->cpt_snd_cwnd_clamp = tp->snd_cwnd_clamp; ++ si->cpt_snd_cwnd_used = tp->snd_cwnd_used; ++ si->cpt_snd_cwnd_stamp = tcp_jiffies_export(tp->snd_cwnd_stamp); ++ si->cpt_timeout = jiffies_export(inet_csk(sk)->icsk_timeout); ++ si->cpt_ka_timeout = 0; ++ si->cpt_rcv_wnd = tp->rcv_wnd; ++ si->cpt_rcv_wup = tp->rcv_wup; ++ si->cpt_write_seq = tp->write_seq; ++ si->cpt_pushed_seq = tp->pushed_seq; ++ si->cpt_copied_seq = tp->copied_seq; ++ si->cpt_tstamp_ok = tp->rx_opt.tstamp_ok; ++ si->cpt_wscale_ok = tp->rx_opt.wscale_ok; ++ si->cpt_sack_ok = tp->rx_opt.sack_ok; ++ si->cpt_saw_tstamp = tp->rx_opt.saw_tstamp; ++ si->cpt_snd_wscale = tp->rx_opt.snd_wscale; ++ si->cpt_rcv_wscale = tp->rx_opt.rcv_wscale; ++ si->cpt_nonagle = tp->nonagle; ++ si->cpt_keepalive_probes = tp->keepalive_probes; ++ si->cpt_rcv_tsval = tp->rx_opt.rcv_tsval; ++ si->cpt_rcv_tsecr = tp->rx_opt.rcv_tsecr; ++ si->cpt_ts_recent = tp->rx_opt.ts_recent; ++ si->cpt_ts_recent_stamp = tp->rx_opt.ts_recent_stamp; ++ si->cpt_user_mss = tp->rx_opt.user_mss; ++ si->cpt_dsack = tp->rx_opt.dsack; ++ si->cpt_eff_sacks = tp->rx_opt.eff_sacks; ++ si->cpt_sack_array[0] = tp->duplicate_sack[0].start_seq; ++ si->cpt_sack_array[1] = tp->duplicate_sack[0].end_seq; ++ si->cpt_sack_array[2] = tp->selective_acks[0].start_seq; ++ si->cpt_sack_array[3] = tp->selective_acks[0].end_seq; ++ si->cpt_sack_array[4] = tp->selective_acks[1].start_seq; ++ si->cpt_sack_array[5] = tp->selective_acks[1].end_seq; ++ si->cpt_sack_array[6] = tp->selective_acks[2].start_seq; ++ si->cpt_sack_array[7] = tp->selective_acks[2].end_seq; ++ si->cpt_sack_array[8] = tp->selective_acks[3].start_seq; ++ si->cpt_sack_array[9] = tp->selective_acks[3].end_seq; ++ si->cpt_window_clamp = tp->window_clamp; ++ si->cpt_rcv_ssthresh = tp->rcv_ssthresh; ++ si->cpt_probes_out = inet_csk(sk)->icsk_probes_out; ++ si->cpt_num_sacks = tp->rx_opt.num_sacks; ++ si->cpt_advmss = tp->advmss; ++ si->cpt_syn_retries = inet_csk(sk)->icsk_syn_retries; ++ si->cpt_ecn_flags = tp->ecn_flags; ++ si->cpt_prior_ssthresh = tp->prior_ssthresh; ++ si->cpt_high_seq = tp->high_seq; ++ si->cpt_retrans_stamp = tp->retrans_stamp; ++ si->cpt_undo_marker = tp->undo_marker; ++ si->cpt_undo_retrans = tp->undo_retrans; ++ si->cpt_urg_seq = tp->urg_seq; ++ si->cpt_urg_data = tp->urg_data; ++ si->cpt_pending = inet_csk(sk)->icsk_pending; ++ si->cpt_urg_mode = tp->urg_mode; ++ si->cpt_snd_up = tp->snd_up; ++ si->cpt_keepalive_time = tp->keepalive_time; ++ si->cpt_keepalive_intvl = tp->keepalive_intvl; ++ si->cpt_linger2 = tp->linger2; ++ ++ if (sk->sk_state != TCP_LISTEN && ++ sk->sk_state != TCP_CLOSE && ++ sock_flag(sk, SOCK_KEEPOPEN)) { ++ si->cpt_ka_timeout = jiffies_export(sk->sk_timer.expires); ++ } ++ ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ { ++ extern struct inet_connection_sock_af_ops ipv6_mapped; ++ if (sk->sk_family == AF_INET6 && ++ inet_csk(sk)->icsk_af_ops == &ipv6_mapped) ++ si->cpt_mapped = 1; ++ } ++#endif ++ ++ return 0; ++} ++ ++ ++int cpt_dump_socket_in(struct cpt_sock_image *si, struct sock *sk, ++ struct cpt_context *ctx) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ struct ipv6_pinfo *np = inet6_sk(sk); ++ ++ if (sk->sk_family == AF_INET) { ++ struct sockaddr_in *sin = ((struct sockaddr_in*)si->cpt_laddr); ++ sin->sin_family = AF_INET; ++ sin->sin_port = inet->sport; ++ sin->sin_addr.s_addr = inet->rcv_saddr; ++ si->cpt_laddrlen = sizeof(*sin); ++ } else if (sk->sk_family == AF_INET6) { ++ struct sockaddr_in6 *sin6 = ((struct sockaddr_in6*)si->cpt_laddr); ++ sin6->sin6_family = AF_INET6; ++ sin6->sin6_port = inet->sport; ++ memcpy(&sin6->sin6_addr, &np->rcv_saddr, 16); ++ si->cpt_laddrlen = sizeof(*sin6); ++ } ++ if (!inet->num) ++ si->cpt_laddrlen = 0; ++ ++ si->cpt_daddr = inet->daddr; ++ si->cpt_dport = inet->dport; ++ si->cpt_saddr = inet->saddr; ++ si->cpt_rcv_saddr = inet->rcv_saddr; ++ si->cpt_sport = inet->sport; ++ si->cpt_uc_ttl = inet->uc_ttl; ++ si->cpt_tos = inet->tos; ++ si->cpt_cmsg_flags = inet->cmsg_flags; ++ si->cpt_mc_index = inet->mc_index; ++ si->cpt_mc_addr = inet->mc_addr; ++ si->cpt_hdrincl = inet->hdrincl; ++ si->cpt_mc_ttl = inet->mc_ttl; ++ si->cpt_mc_loop = inet->mc_loop; ++ si->cpt_pmtudisc = inet->pmtudisc; ++ si->cpt_recverr = inet->recverr; ++ si->cpt_freebind = inet->freebind; ++ si->cpt_idcounter = inet->id; ++ ++ si->cpt_cork_flags = inet->cork.flags; ++ si->cpt_cork_fragsize = 0; ++ si->cpt_cork_length = inet->cork.length; ++ si->cpt_cork_addr = inet->cork.addr; ++ si->cpt_cork_saddr = inet->cork.fl.fl4_src; ++ si->cpt_cork_daddr = inet->cork.fl.fl4_dst; ++ si->cpt_cork_oif = inet->cork.fl.oif; ++ if (inet->cork.rt) { ++ si->cpt_cork_fragsize = inet->cork.fragsize; ++ si->cpt_cork_saddr = inet->cork.rt->fl.fl4_src; ++ si->cpt_cork_daddr = inet->cork.rt->fl.fl4_dst; ++ si->cpt_cork_oif = inet->cork.rt->fl.oif; ++ } ++ ++ if (sk->sk_type == SOCK_DGRAM && sk->sk_protocol == IPPROTO_UDP) { ++ struct udp_sock *up = udp_sk(sk); ++ si->cpt_udp_pending = up->pending; ++ si->cpt_udp_corkflag = up->corkflag; ++ si->cpt_udp_encap = up->encap_type; ++ si->cpt_udp_len = up->len; ++ } ++ ++ if (sk->sk_family == AF_INET6) { ++ memcpy(si->cpt_saddr6, &np->saddr, 16); ++ memcpy(si->cpt_rcv_saddr6, &np->rcv_saddr, 16); ++ memcpy(si->cpt_daddr6, &np->daddr, 16); ++ si->cpt_flow_label6 = np->flow_label; ++ si->cpt_frag_size6 = np->frag_size; ++ si->cpt_hop_limit6 = np->hop_limit; ++ si->cpt_mcast_hops6 = np->mcast_hops; ++ si->cpt_mcast_oif6 = np->mcast_oif; ++ si->cpt_rxopt6 = np->rxopt.all; ++ si->cpt_mc_loop6 = np->mc_loop; ++ si->cpt_recverr6 = np->recverr; ++ si->cpt_sndflow6 = np->sndflow; ++ si->cpt_pmtudisc6 = np->pmtudisc; ++ si->cpt_ipv6only6 = np->ipv6only; ++ si->cpt_mapped = 0; ++ } ++ ++ if (sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP) ++ cpt_dump_socket_tcp(si, sk, ctx); ++ ++ return 0; ++} ++ ++int cpt_dump_accept_queue(struct sock *sk, int index, struct cpt_context *ctx) ++{ ++ struct request_sock *req; ++ ++ for (req=inet_csk(sk)->icsk_accept_queue.rskq_accept_head; req; req=req->dl_next) ++ cpt_dump_socket(NULL, req->sk, -1, index, ctx); ++ return 0; ++} ++ ++ ++static int dump_openreq(struct request_sock *req, struct sock *sk, int index, ++ struct cpt_context *ctx) ++{ ++ struct cpt_openreq_image *v = cpt_get_buf(ctx); ++ ++ cpt_open_object(NULL, ctx); ++ ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_OPENREQ; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_VOID; ++ ++ v->cpt_rcv_isn = tcp_rsk(req)->rcv_isn; ++ v->cpt_snt_isn = tcp_rsk(req)->snt_isn; ++ v->cpt_rmt_port = inet_rsk(req)->rmt_port; ++ v->cpt_mss = req->mss; ++ // // v->cpt_family = (req->class == &or_ipv4 ? AF_INET : AF_INET6); ++ v->cpt_retrans = req->retrans; ++ v->cpt_snd_wscale = inet_rsk(req)->snd_wscale; ++ v->cpt_rcv_wscale = inet_rsk(req)->rcv_wscale; ++ v->cpt_tstamp_ok = inet_rsk(req)->tstamp_ok; ++ v->cpt_sack_ok = inet_rsk(req)->sack_ok; ++ v->cpt_wscale_ok = inet_rsk(req)->wscale_ok; ++ v->cpt_ecn_ok = inet_rsk(req)->ecn_ok; ++ v->cpt_acked = inet_rsk(req)->acked; ++ v->cpt_window_clamp = req->window_clamp; ++ v->cpt_rcv_wnd = req->rcv_wnd; ++ v->cpt_ts_recent = req->ts_recent; ++ v->cpt_expires = jiffies_export(req->expires); ++ ++ if (v->cpt_family == AF_INET) { ++ memcpy(v->cpt_loc_addr, &inet_rsk(req)->loc_addr, 4); ++ memcpy(v->cpt_rmt_addr, &inet_rsk(req)->rmt_addr, 4); ++ } else { ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ memcpy(v->cpt_loc_addr, &inet6_rsk(req)->loc_addr, 16); ++ memcpy(v->cpt_rmt_addr, &inet6_rsk(req)->rmt_addr, 16); ++ v->cpt_iif = inet6_rsk(req)->iif; ++#endif ++ } ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++ cpt_close_object(ctx); ++ return 0; ++} ++ ++int cpt_dump_synwait_queue(struct sock *sk, int index, struct cpt_context *ctx) ++{ ++ struct inet_connection_sock *icsk; ++ struct listen_sock *lopt; ++ struct request_sock *req; ++ int nr_entries; ++ int i; ++ ++ icsk = inet_csk(sk); ++ lopt = icsk->icsk_accept_queue.listen_opt; ++ nr_entries = icsk->icsk_accept_queue.listen_opt->nr_table_entries; ++ ++ for (i=0; i < nr_entries; i++) { ++ for (req=lopt->syn_table[i]; req; req=req->dl_next) { ++ loff_t saved_obj; ++ cpt_push_object(&saved_obj, ctx); ++ dump_openreq(req, sk, index, ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ } ++ } ++ return 0; ++} ++ ++ ++int cpt_kill_socket(struct sock *sk, cpt_context_t * ctx) ++{ ++ if (sk->sk_state != TCP_CLOSE && ++ (sk->sk_family == AF_INET || sk->sk_family == AF_INET6) && ++ sk->sk_protocol == IPPROTO_TCP) { ++ if (sk->sk_state != TCP_LISTEN) ++ tcp_set_state(sk, TCP_CLOSE); ++ else ++ sk->sk_prot->disconnect(sk, 0); ++ } ++ return 0; ++} ++ ++int cpt_dump_mcfilter(struct sock *sk, cpt_context_t *ctx) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ struct ip_mc_socklist *iml; ++ ++ for (iml = inet->mc_list; iml; iml = iml->next) { ++ struct cpt_sockmc_image smi; ++ int scnt = 0; ++ int i; ++ ++ if (iml->sflist) ++ scnt = iml->sflist->sl_count*16; ++ ++ smi.cpt_next = sizeof(smi) + scnt; ++ smi.cpt_object = CPT_OBJ_SOCK_MCADDR; ++ smi.cpt_hdrlen = sizeof(smi); ++ smi.cpt_content = CPT_CONTENT_DATA; ++ ++ smi.cpt_family = AF_INET; ++ smi.cpt_mode = iml->sfmode; ++ smi.cpt_ifindex = iml->multi.imr_ifindex; ++ memset(&smi.cpt_mcaddr, 0, sizeof(smi.cpt_mcaddr)); ++ smi.cpt_mcaddr[0] = iml->multi.imr_multiaddr.s_addr; ++ ++ ctx->write(&smi, sizeof(smi), ctx); ++ ++ for (i = 0; i < scnt; i++) { ++ u32 addr[4]; ++ memset(&addr, 0, sizeof(addr)); ++ addr[0] = iml->sflist->sl_addr[i]; ++ ctx->write(&addr, sizeof(addr), ctx); ++ } ++ } ++ ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++ if (sk->sk_family == AF_INET6) { ++ struct ipv6_mc_socklist *mcl; ++ struct ipv6_pinfo *np = inet6_sk(sk); ++ ++ for (mcl = np->ipv6_mc_list; mcl; mcl = mcl->next) { ++ struct cpt_sockmc_image smi; ++ int scnt = 0; ++ int i; ++ ++ if (mcl->sflist) ++ scnt = mcl->sflist->sl_count*16; ++ ++ smi.cpt_next = sizeof(smi) + scnt; ++ smi.cpt_object = CPT_OBJ_SOCK_MCADDR; ++ smi.cpt_hdrlen = sizeof(smi); ++ smi.cpt_content = CPT_CONTENT_DATA; ++ ++ smi.cpt_family = AF_INET6; ++ smi.cpt_mode = mcl->sfmode; ++ smi.cpt_ifindex = mcl->ifindex; ++ memcpy(&smi.cpt_mcaddr, &mcl->addr, sizeof(smi.cpt_mcaddr)); ++ ++ ctx->write(&smi, sizeof(smi), ctx); ++ for (i = 0; i < scnt; i++) ++ ctx->write(&mcl->sflist->sl_addr[i], 16, ctx); ++ } ++ } ++#endif ++ return 0; ++} +Index: kernel/kernel/cpt/cpt_syscalls.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_syscalls.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,100 @@ ++#include ++#include ++#include ++ ++#define WRAP(c, args) return sys_##c args ++#define WRAP2(c, args) int err; mm_segment_t oldfs; \ ++ oldfs = get_fs(); set_fs(KERNEL_DS); \ ++ err = sys_##c args ;\ ++ set_fs(oldfs); \ ++ return err ++ ++static inline int sc_close(int fd) ++{ ++ WRAP(close, (fd)); ++} ++ ++static inline int sc_dup2(int fd1, int fd2) ++{ ++ WRAP(dup2, (fd1, fd2)); ++} ++ ++static inline int sc_unlink(char *name) ++{ ++ WRAP2(unlink, (name)); ++} ++ ++static inline int sc_pipe(int *pfd) ++{ ++ return do_pipe(pfd); ++} ++ ++static inline int sc_mknod(char *name, int mode, int dev) ++{ ++ WRAP2(mknod, (name, mode, dev)); ++} ++ ++static inline int sc_chmod(char *name, int mode) ++{ ++ WRAP2(mkdir, (name, mode)); ++} ++ ++static inline int sc_chown(char *name, int uid, int gid) ++{ ++ WRAP2(chown, (name, uid, gid)); ++} ++ ++static inline int sc_mkdir(char *name, int mode) ++{ ++ WRAP2(mkdir, (name, mode)); ++} ++ ++static inline int sc_rmdir(char *name) ++{ ++ WRAP2(rmdir, (name)); ++} ++ ++static inline int sc_mount(char *mntdev, char *mntpnt, char *type, unsigned long flags) ++{ ++ WRAP2(mount, (mntdev ? : "none", mntpnt, type, flags, NULL)); ++} ++ ++static inline int sc_mprotect(unsigned long start, size_t len, ++ unsigned long prot) ++{ ++ WRAP(mprotect, (start, len, prot)); ++} ++ ++static inline int sc_mlock(unsigned long start, size_t len) ++{ ++ WRAP(mlock, (start, len)); ++} ++ ++static inline int sc_munlock(unsigned long start, size_t len) ++{ ++ WRAP(munlock, (start, len)); ++} ++ ++static inline int sc_remap_file_pages(unsigned long start, size_t len, ++ unsigned long prot, unsigned long pgoff, ++ unsigned long flags) ++{ ++ WRAP(remap_file_pages, (start, len, prot, pgoff, flags)); ++} ++ ++static inline int sc_waitx(int pid, int opt, int *stat_addr) ++{ ++ WRAP(wait4, (pid, stat_addr, opt, NULL)); ++} ++ ++static inline int sc_flock(int fd, int flags) ++{ ++ WRAP(flock, (fd, flags)); ++} ++ ++static inline int sc_open(char* path, int flags, int mode) ++{ ++ WRAP(open, (path, flags, mode)); ++} ++ ++extern int sc_execve(char *cms, char **argv, char **env); +Index: kernel/kernel/cpt/cpt_sysvipc.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_sysvipc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,403 @@ ++/* ++ * ++ * kernel/cpt/cpt_sysvipc.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_kernel.h" ++ ++struct _warg { ++ struct file *file; ++ struct cpt_sysvshm_image *v; ++}; ++ ++static int dump_one_shm(struct shmid_kernel *shp, void *arg) ++{ ++ struct _warg *warg = arg; ++ struct cpt_sysvshm_image *v = (struct cpt_sysvshm_image *)warg->v; ++ ++ if (shp->shm_file != warg->file) ++ return 0; ++ ++ v->cpt_key = shp->shm_perm.key; ++ v->cpt_uid = shp->shm_perm.uid; ++ v->cpt_gid = shp->shm_perm.gid; ++ v->cpt_cuid = shp->shm_perm.cuid; ++ v->cpt_cgid = shp->shm_perm.cgid; ++ v->cpt_mode = shp->shm_perm.mode; ++ v->cpt_seq = shp->shm_perm.seq; ++ ++ v->cpt_id = shp->shm_perm.id; ++ v->cpt_segsz = shp->shm_segsz; ++ v->cpt_atime = shp->shm_atim; ++ v->cpt_ctime = shp->shm_ctim; ++ v->cpt_dtime = shp->shm_dtim; ++ v->cpt_creator = shp->shm_cprid; ++ v->cpt_last = shp->shm_lprid; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9) ++ v->cpt_mlockuser = shp->mlock_user ? shp->mlock_user->uid : -1; ++#else ++ v->cpt_mlockuser = -1; ++#endif ++ return 1; ++} ++ ++int cpt_dump_content_sysvshm(struct file *file, struct cpt_context *ctx) ++{ ++ struct cpt_sysvshm_image *v = cpt_get_buf(ctx); ++ struct _warg warg; ++ ++ v->cpt_next = sizeof(*v); ++ v->cpt_object = CPT_OBJ_SYSV_SHM; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_VOID; ++ ++ warg.file = file; ++ warg.v = v; ++ if (sysvipc_walk_shm(dump_one_shm, &warg) == 0) { ++ cpt_release_buf(ctx); ++ return -ESRCH; ++ } ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ return 0; ++} ++ ++ ++int match_sem(int id, struct sem_array *sema, void *arg) ++{ ++ if (id != (unsigned long)arg) ++ return 0; ++ return sema->sem_nsems + 1; ++} ++ ++static int get_sem_nsem(int id, cpt_context_t *ctx) ++{ ++ int res; ++ res = sysvipc_walk_sem(match_sem, (void*)(unsigned long)id); ++ if (res > 0) ++ return res - 1; ++ eprintk_ctx("get_sem_nsem: SYSV semaphore %d not found\n", id); ++ return -ESRCH; ++} ++ ++static int dump_one_semundo(struct sem_undo *su, struct cpt_context *ctx) ++{ ++ struct cpt_sysvsem_undo_image v; ++ loff_t saved_obj; ++ ++ cpt_open_object(NULL, ctx); ++ ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_SYSVSEM_UNDO_REC; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_SEMUNDO; ++ v.cpt_id = su->semid; ++ v.cpt_nsem = get_sem_nsem(su->semid, ctx); ++ if ((int)v.cpt_nsem < 0) ++ return -ESRCH; ++ ++ ctx->write(&v, sizeof(v), ctx); ++ ++ cpt_push_object(&saved_obj, ctx); ++ ctx->write(su->semadj, v.cpt_nsem*sizeof(short), ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ ++ cpt_close_object(ctx); ++ return 0; ++} ++ ++struct sem_warg { ++ int last_id; ++ struct cpt_sysvsem_image *v; ++}; ++ ++static int dump_one_sem(int id, struct sem_array *sma, void *arg) ++{ ++ struct sem_warg * warg = (struct sem_warg *)arg; ++ struct cpt_sysvsem_image *v = warg->v; ++ int i; ++ ++ if (warg->last_id != -1) { ++ if ((id % IPCMNI) <= warg->last_id) ++ return 0; ++ } ++ ++ v->cpt_next = sizeof(*v); ++ v->cpt_object = CPT_OBJ_SYSV_SEM; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_SEMARRAY; ++ ++ v->cpt_key = sma->sem_perm.key; ++ v->cpt_uid = sma->sem_perm.uid; ++ v->cpt_gid = sma->sem_perm.gid; ++ v->cpt_cuid = sma->sem_perm.cuid; ++ v->cpt_cgid = sma->sem_perm.cgid; ++ v->cpt_mode = sma->sem_perm.mode; ++ v->cpt_seq = sma->sem_perm.seq; ++ ++ v->cpt_id = id; ++ v->cpt_ctime = sma->sem_ctime; ++ v->cpt_otime = sma->sem_otime; ++ ++ for (i=0; isem_nsems; i++) { ++ struct { ++ __u32 semval; ++ __u32 sempid; ++ } *s = (void*)v + v->cpt_next; ++ if (v->cpt_next >= PAGE_SIZE - sizeof(*s)) ++ return -EINVAL; ++ s->semval = sma->sem_base[i].semval; ++ s->sempid = sma->sem_base[i].sempid; ++ v->cpt_next += sizeof(*s); ++ } ++ ++ warg->last_id = id % IPCMNI; ++ return 1; ++} ++ ++ ++int cpt_dump_sysvsem(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ struct sem_warg warg; ++ ++ /* Dumping semaphores is quite tricky because we cannot ++ * write to dump file under lock inside sysvipc_walk_sem(). ++ */ ++ cpt_open_section(ctx, CPT_SECT_SYSV_SEM); ++ warg.last_id = -1; ++ warg.v = cpt_get_buf(ctx); ++ for (;;) { ++ if (sysvipc_walk_sem(dump_one_sem, &warg) <= 0) ++ break; ++ ctx->write(warg.v, warg.v->cpt_next, ctx); ++ } ++ cpt_release_buf(ctx); ++ cpt_close_section(ctx); ++ ++ cpt_open_section(ctx, CPT_SECT_SYSVSEM_UNDO); ++ for_each_object(obj, CPT_OBJ_SYSVSEM_UNDO) { ++ struct sem_undo_list *semu = obj->o_obj; ++ struct sem_undo *su; ++ struct cpt_object_hdr v; ++ loff_t saved_obj; ++ ++ cpt_open_object(obj, ctx); ++ ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_SYSVSEM_UNDO; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_ARRAY; ++ ++ ctx->write(&v, sizeof(v), ctx); ++ ++ cpt_push_object(&saved_obj, ctx); ++ for (su = semu->proc_list; su; su = su->proc_next) { ++ if (su->semid != -1) { ++ int err; ++ err = dump_one_semundo(su, ctx); ++ if (err < 0) ++ return err; ++ } ++ } ++ cpt_pop_object(&saved_obj, ctx); ++ ++ cpt_close_object(ctx); ++ } ++ cpt_close_section(ctx); ++ return 0; ++} ++ ++struct msg_warg { ++ int last_id; ++ struct msg_queue *msq; ++ struct cpt_sysvmsg_image *v; ++}; ++ ++static int dump_one_msg(int id, struct msg_queue *msq, void *arg) ++{ ++ struct msg_warg * warg = (struct msg_warg *)arg; ++ struct cpt_sysvmsg_image *v = warg->v; ++ ++ if (warg->last_id != -1) { ++ if ((id % IPCMNI) <= warg->last_id) ++ return 0; ++ } ++ ++ v->cpt_next = sizeof(*v); ++ v->cpt_object = CPT_OBJ_SYSVMSG; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ v->cpt_key = msq->q_perm.key; ++ v->cpt_uid = msq->q_perm.uid; ++ v->cpt_gid = msq->q_perm.gid; ++ v->cpt_cuid = msq->q_perm.cuid; ++ v->cpt_cgid = msq->q_perm.cgid; ++ v->cpt_mode = msq->q_perm.mode; ++ v->cpt_seq = msq->q_perm.seq; ++ ++ v->cpt_id = id; ++ v->cpt_stime = msq->q_stime; ++ v->cpt_rtime = msq->q_rtime; ++ v->cpt_ctime = msq->q_ctime; ++ v->cpt_last_sender = msq->q_lspid; ++ v->cpt_last_receiver = msq->q_lrpid; ++ v->cpt_qbytes = msq->q_qbytes; ++ ++ warg->msq = msq; ++ warg->last_id = id % IPCMNI; ++ return 1; ++} ++ ++static int do_store(void * src, int len, int offset, void * data) ++{ ++ cpt_context_t * ctx = data; ++ ctx->write(src, len, ctx); ++ return 0; ++} ++ ++static void cpt_dump_one_sysvmsg(struct msg_msg *m, cpt_context_t * ctx) ++{ ++ loff_t saved_obj; ++ struct cpt_sysvmsg_msg_image mv; ++ ++ cpt_open_object(NULL, ctx); ++ mv.cpt_next = CPT_NULL; ++ mv.cpt_object = CPT_OBJ_SYSVMSG_MSG; ++ mv.cpt_hdrlen = sizeof(mv); ++ mv.cpt_content = CPT_CONTENT_DATA; ++ ++ mv.cpt_type = m->m_type; ++ mv.cpt_size = m->m_ts; ++ ++ ctx->write(&mv, sizeof(mv), ctx); ++ ++ cpt_push_object(&saved_obj, ctx); ++ sysv_msg_store(m, do_store, m->m_ts, ctx); ++ cpt_pop_object(&saved_obj, ctx); ++ cpt_close_object(ctx); ++} ++ ++int cpt_dump_sysvmsg(struct cpt_context *ctx) ++{ ++ struct msg_warg warg; ++ ++ /* Dumping msg queues is tricky because we cannot ++ * write to dump file under lock inside sysvipc_walk_msg(). ++ * ++ * And even worse, we have to access msg list in an unserialized ++ * context. It is fragile. But VE is still frozen, remember? ++ */ ++ cpt_open_section(ctx, CPT_SECT_SYSV_MSG); ++ warg.last_id = -1; ++ warg.v = cpt_get_buf(ctx); ++ for (;;) { ++ loff_t saved_obj; ++ struct msg_msg * m; ++ ++ if (sysvipc_walk_msg(dump_one_msg, &warg) <= 0) ++ break; ++ ++ cpt_open_object(NULL, ctx); ++ ++ ctx->write(warg.v, warg.v->cpt_next, ctx); ++ ++ cpt_push_object(&saved_obj, ctx); ++ list_for_each_entry(m, &warg.msq->q_messages, m_list) { ++ cpt_dump_one_sysvmsg(m, ctx); ++ } ++ cpt_pop_object(&saved_obj, ctx); ++ ++ cpt_close_object(ctx); ++ } ++ cpt_release_buf(ctx); ++ cpt_close_section(ctx); ++ return 0; ++} ++ ++static int cpt_collect_sysvsem_undo(cpt_context_t *ctx) ++{ ++ cpt_object_t *obj; ++ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ struct task_struct *tsk = obj->o_obj; ++ if (tsk->exit_state) { ++ /* ipc/sem.c forgets to clear tsk->sysvsem.undo_list ++ * on exit. Grrr... */ ++ continue; ++ } ++ if (tsk->sysvsem.undo_list && ++ cpt_object_add(CPT_OBJ_SYSVSEM_UNDO, tsk->sysvsem.undo_list, ctx) == NULL) ++ return -ENOMEM; ++ } ++ ++ for_each_object(obj, CPT_OBJ_SYSVSEM_UNDO) { ++ struct sem_undo_list *semu = obj->o_obj; ++ ++ if (atomic_read(&semu->refcnt) != obj->o_count) { ++ eprintk_ctx("sem_undo_list is referenced outside %d %d\n", obj->o_count, atomic_read(&semu->refcnt)); ++ return -EBUSY; ++ } ++ } ++ return 0; ++} ++ ++static int collect_one_shm(struct shmid_kernel *shp, void *arg) ++{ ++ cpt_context_t *ctx = arg; ++ ++ if (__cpt_object_add(CPT_OBJ_FILE, shp->shm_file, GFP_ATOMIC, ctx) == NULL) ++ return -ENOMEM; ++ return 0; ++} ++ ++int cpt_collect_sysvshm(cpt_context_t * ctx) ++{ ++ int err; ++ ++ err = sysvipc_walk_shm(collect_one_shm, ctx); ++ ++ return err < 0 ? err : 0; ++} ++ ++int cpt_collect_sysv(cpt_context_t * ctx) ++{ ++ int err; ++ ++ err = cpt_collect_sysvsem_undo(ctx); ++ if (err) ++ return err; ++ err = cpt_collect_sysvshm(ctx); ++ if (err) ++ return err; ++ ++ return 0; ++} +Index: kernel/kernel/cpt/cpt_tty.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_tty.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,215 @@ ++/* ++ * ++ * kernel/cpt/cpt_tty.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++ ++/* We must support at least N_TTY. */ ++ ++int cpt_dump_content_tty(struct file *file, struct cpt_context *ctx) ++{ ++ struct tty_struct *tty = file->private_data; ++ cpt_object_t *obj; ++ struct cpt_obj_ref o; ++ loff_t saved_pos; ++ ++ obj = lookup_cpt_object(CPT_OBJ_TTY, tty, ctx); ++ if (!obj) ++ return -EINVAL; ++ ++ cpt_push_object(&saved_pos, ctx); ++ ++ o.cpt_next = sizeof(o); ++ o.cpt_object = CPT_OBJ_REF; ++ o.cpt_hdrlen = sizeof(o); ++ o.cpt_content = CPT_CONTENT_VOID; ++ o.cpt_pos = obj->o_pos; ++ ctx->write(&o, sizeof(o), ctx); ++ ++ cpt_pop_object(&saved_pos, ctx); ++ ++ return 0; ++} ++ ++int cpt_collect_tty(struct file *file, cpt_context_t * ctx) ++{ ++ struct tty_struct *tty = file->private_data; ++ ++ if (tty) { ++ if (cpt_object_add(CPT_OBJ_TTY, tty, ctx) == NULL) ++ return -ENOMEM; ++ if (tty->link) { ++ cpt_object_t *obj; ++ ++ obj = cpt_object_add(CPT_OBJ_TTY, tty->link, ctx); ++ if (obj == NULL) ++ return -ENOMEM; ++ /* Undo o_count, tty->link is not a reference */ ++ obj->o_count--; ++ } ++ } ++ return 0; ++} ++ ++int cpt_dump_tty(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ struct tty_struct *tty = obj->o_obj; ++ struct cpt_tty_image *v; ++ ++ if (tty->link) { ++ if (lookup_cpt_object(CPT_OBJ_TTY, tty->link, ctx) == NULL) { ++ eprintk_ctx("orphan pty %s %d\n", tty->name, tty->driver->subtype == PTY_TYPE_SLAVE); ++ return -EINVAL; ++ } ++ if (tty->link->link != tty) { ++ eprintk_ctx("bad pty pair\n"); ++ return -EINVAL; ++ } ++ if (tty->driver->type == TTY_DRIVER_TYPE_PTY && ++ tty->driver->subtype == PTY_TYPE_SLAVE && ++ tty->link->count) ++ obj->o_count++; ++ } ++ if (obj->o_count != tty->count) { ++ eprintk_ctx("tty %s is referenced outside %d %d\n", tty->name, obj->o_count, tty->count); ++ return -EBUSY; ++ } ++ ++ cpt_open_object(obj, ctx); ++ ++ v = cpt_get_buf(ctx); ++ v->cpt_next = -1; ++ v->cpt_object = CPT_OBJ_TTY; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_ARRAY; ++ ++ v->cpt_index = tty->index; ++ v->cpt_link = -1; ++ if (tty->link) ++ v->cpt_link = tty->link->index; ++ v->cpt_drv_type = tty->driver->type; ++ v->cpt_drv_subtype = tty->driver->subtype; ++ v->cpt_drv_flags = tty->driver->flags; ++ v->cpt_packet = tty->packet; ++ v->cpt_stopped = tty->stopped; ++ v->cpt_hw_stopped = tty->hw_stopped; ++ v->cpt_flow_stopped = tty->flow_stopped; ++ v->cpt_flags = tty->flags; ++ v->cpt_ctrl_status = tty->ctrl_status; ++ v->cpt_canon_data = tty->canon_data; ++ v->cpt_canon_head = tty->canon_head - tty->read_tail; ++ v->cpt_canon_column = tty->canon_column; ++ v->cpt_column = tty->column; ++ v->cpt_erasing = tty->erasing; ++ v->cpt_lnext = tty->lnext; ++ v->cpt_icanon = tty->icanon; ++ v->cpt_raw = tty->raw; ++ v->cpt_real_raw = tty->real_raw; ++ v->cpt_closing = tty->closing; ++ v->cpt_minimum_to_wake = tty->minimum_to_wake; ++ v->cpt_pgrp = 0; ++ if (tty->pgrp) { ++ v->cpt_pgrp = pid_vnr(tty->pgrp); ++ if ((int)v->cpt_pgrp < 0) { ++ dprintk_ctx("cannot map tty->pgrp %d -> %d\n", pid_vnr(tty->pgrp), (int)v->cpt_pgrp); ++ v->cpt_pgrp = -1; ++ } ++ } ++ v->cpt_session = 0; ++ if (tty->session) { ++ v->cpt_session = pid_vnr(tty->session); ++ if ((int)v->cpt_session < 0) { ++ eprintk_ctx("cannot map tty->session %d -> %d\n", pid_nr(tty->session), (int)v->cpt_session); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ } ++ memcpy(v->cpt_name, tty->name, 64); ++ v->cpt_ws_row = tty->winsize.ws_row; ++ v->cpt_ws_col = tty->winsize.ws_col; ++ v->cpt_ws_prow = tty->winsize.ws_ypixel; ++ v->cpt_ws_pcol = tty->winsize.ws_xpixel; ++ if (tty->termios == NULL) { ++ eprintk_ctx("NULL termios"); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ v->cpt_c_line = tty->termios->c_line; ++ v->cpt_c_iflag = tty->termios->c_iflag; ++ v->cpt_c_oflag = tty->termios->c_oflag; ++ v->cpt_c_cflag = tty->termios->c_cflag; ++ v->cpt_c_lflag = tty->termios->c_lflag; ++ memcpy(v->cpt_c_cc, tty->termios->c_cc, NCCS); ++ if (NCCS < 32) ++ memset(v->cpt_c_cc + NCCS, 255, 32 - NCCS); ++ memcpy(v->cpt_read_flags, tty->read_flags, sizeof(v->cpt_read_flags)); ++ ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++ if (tty->read_buf && tty->read_cnt) { ++ struct cpt_obj_bits *v = cpt_get_buf(ctx); ++ loff_t saved_pos; ++ ++ cpt_push_object(&saved_pos, ctx); ++ cpt_open_object(NULL, ctx); ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_BITS; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_DATA; ++ v->cpt_size = tty->read_cnt; ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_release_buf(ctx); ++ ++ if (tty->read_cnt) { ++ int n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail); ++ ctx->write(tty->read_buf + tty->read_tail, n, ctx); ++ if (tty->read_cnt > n) ++ ctx->write(tty->read_buf, tty->read_cnt-n, ctx); ++ ctx->align(ctx); ++ } ++ ++ cpt_close_object(ctx); ++ cpt_pop_object(&saved_pos, ctx); ++ } ++ ++ cpt_close_object(ctx); ++ ++ return 0; ++} ++ ++__u32 cpt_tty_fasync(struct file *file, struct cpt_context *ctx) ++{ ++ struct tty_struct * tty; ++ struct fasync_struct *fa; ++ ++ tty = (struct tty_struct *)file->private_data; ++ ++ for (fa = tty->fasync; fa; fa = fa->fa_next) { ++ if (fa->fa_file == file) ++ return fa->fa_fd; ++ } ++ return -1; ++} +Index: kernel/kernel/cpt/cpt_ubc.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_ubc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,132 @@ ++/* ++ * ++ * kernel/cpt/cpt_ubc.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++ ++cpt_object_t *cpt_add_ubc(struct user_beancounter *bc, struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ obj = cpt_object_add(CPT_OBJ_UBC, bc, ctx); ++ if (obj != NULL) { ++ if (obj->o_count == 1) ++ get_beancounter(bc); ++ if (bc->parent != NULL && obj->o_parent == NULL) ++ obj->o_parent = cpt_add_ubc(bc->parent, ctx); ++ } ++ return obj; ++} ++ ++__u64 cpt_lookup_ubc(struct user_beancounter *bc, struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ obj = lookup_cpt_object(CPT_OBJ_UBC, bc, ctx); ++ if (obj == NULL) { ++ char buf[48]; ++ print_ub_uid(bc, buf, sizeof(buf)); ++ eprintk("CPT: unknown ub %s (%p)\n", buf, bc); ++ dump_stack(); ++ return CPT_NULL; ++ } ++ return obj->o_pos; ++} ++ ++static void dump_one_bc_parm(struct cpt_ubparm *dmp, struct ubparm *prm, ++ int held) ++{ ++ dmp->barrier = (prm->barrier < UB_MAXVALUE ? prm->barrier : CPT_NULL); ++ dmp->limit = (prm->limit < UB_MAXVALUE ? prm->limit : CPT_NULL); ++ dmp->held = (held ? prm->held : CPT_NULL); ++ dmp->maxheld = prm->maxheld; ++ dmp->minheld = prm->minheld; ++ dmp->failcnt = prm->failcnt; ++} ++ ++static int dump_one_bc(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ struct user_beancounter *bc; ++ struct cpt_beancounter_image *v; ++ int i; ++ ++ bc = obj->o_obj; ++ v = cpt_get_buf(ctx); ++ ++ v->cpt_next = CPT_NULL; ++ v->cpt_object = CPT_OBJ_UBC; ++ v->cpt_hdrlen = sizeof(*v); ++ v->cpt_content = CPT_CONTENT_VOID; ++ ++ if (obj->o_parent != NULL) ++ v->cpt_parent = ((cpt_object_t *)obj->o_parent)->o_pos; ++ else ++ v->cpt_parent = CPT_NULL; ++ v->cpt_id = (obj->o_parent != NULL) ? bc->ub_uid : 0; ++ for (i = 0; i < UB_RESOURCES; i++) { ++ dump_one_bc_parm(v->cpt_parms + i * 2, bc->ub_parms + i, 0); ++ dump_one_bc_parm(v->cpt_parms + i * 2 + 1, bc->ub_store + i, 1); ++ } ++ memset(v->cpt_parms + UB_RESOURCES * 2, 0, ++ sizeof(v->cpt_parms) ++ - UB_RESOURCES * 2 * sizeof(v->cpt_parms[0])); ++ ++ cpt_open_object(obj, ctx); ++ ctx->write(v, sizeof(*v), ctx); ++ cpt_close_object(ctx); ++ ++ cpt_release_buf(ctx); ++ return 0; ++} ++ ++int cpt_dump_ubc(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ int skipped; ++ int top; ++ ++ cpt_open_section(ctx, CPT_SECT_UBC); ++ ++ do { ++ skipped = 0; ++ top = 0; ++ for_each_object(obj, CPT_OBJ_UBC) { ++ if (obj->o_parent == NULL) ++ top++; ++ if (obj->o_pos != CPT_NULL) ++ continue; ++ if (obj->o_parent != NULL && ++ ((cpt_object_t *)obj->o_parent)->o_pos == CPT_NULL) ++ skipped++; ++ else ++ dump_one_bc(obj, ctx); ++ } ++ } while (skipped && (top < 2)); ++ ++ cpt_close_section(ctx); ++ if (top > 1) { ++ eprintk_ctx("More than one top level ub exist"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++void cpt_finish_ubc(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ for_each_object(obj, CPT_OBJ_UBC) ++ put_beancounter(obj->o_obj); ++} +Index: kernel/kernel/cpt/cpt_ubc.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_ubc.h 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,23 @@ ++#ifdef CONFIG_BEANCOUNTERS ++cpt_object_t *cpt_add_ubc(struct user_beancounter *bc, struct cpt_context *ctx); ++__u64 cpt_lookup_ubc(struct user_beancounter *bc, struct cpt_context *ctx); ++int cpt_dump_ubc(struct cpt_context *ctx); ++ ++struct user_beancounter *rst_lookup_ubc(__u64 pos, struct cpt_context *ctx); ++int rst_undump_ubc(struct cpt_context *ctx); ++ ++void cpt_finish_ubc(struct cpt_context *ctx); ++void rst_finish_ubc(struct cpt_context *ctx); ++void copy_one_ubparm(struct ubparm *from, struct ubparm *to, int bc_parm_id); ++void set_one_ubparm_to_max(struct ubparm *ubprm, int bc_parm_id); ++#else ++static int inline cpt_dump_ubc(struct cpt_context *ctx) ++{ return 0; } ++static int inline rst_undump_ubc(struct cpt_context *ctx) ++{ return 0; } ++static void inline cpt_finish_ubc(struct cpt_context *ctx) ++{ return; } ++static void inline rst_finish_ubc(struct cpt_context *ctx) ++{ return; } ++#endif ++ +Index: kernel/kernel/cpt/cpt_x8664.S +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/cpt_x8664.S 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,67 @@ ++#define ASSEMBLY 1 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ .code64 ++ ++ .macro FAKE_STACK_FRAME child_rip ++ /* push in order ss, rsp, eflags, cs, rip */ ++ xorq %rax, %rax ++ pushq %rax /* ss */ ++ pushq %rax /* rsp */ ++ pushq $(1<<9) /* eflags - interrupts on */ ++ pushq $__KERNEL_CS /* cs */ ++ pushq \child_rip /* rip */ ++ pushq %rax /* orig rax */ ++ .endm ++ ++ .macro UNFAKE_STACK_FRAME ++ addq $8*6, %rsp ++ .endm ++ ++ENTRY(asm_kernel_thread) ++ CFI_STARTPROC ++ FAKE_STACK_FRAME $child_rip ++ SAVE_ALL ++ ++ # rdi: flags, rsi: usp, rdx: will be &pt_regs ++ movq %rdx,%rdi ++ orq $0x00800000,%rdi ++ movq $-1, %rsi ++ movq %rsp, %rdx ++ ++ xorl %r8d,%r8d ++ xorl %r9d,%r9d ++ pushq %rcx ++ call do_fork_pid ++ addq $8, %rsp ++ /* call do_fork */ ++ movq %rax,RAX(%rsp) ++ xorl %edi,%edi ++ RESTORE_ALL ++ UNFAKE_STACK_FRAME ++ ret ++ CFI_ENDPROC ++ENDPROC(asm_kernel_thread) ++ ++child_rip: ++ pushq $0 # fake return address ++ CFI_STARTPROC ++ movq %rdi, %rax ++ movq %rsi, %rdi ++ call *%rax ++ movq %rax, %rdi ++ call do_exit ++ CFI_ENDPROC ++ENDPROC(child_rip) ++ +Index: kernel/kernel/cpt/rst_conntrack.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_conntrack.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,283 @@ ++/* ++ * ++ * kernel/cpt/rst_conntrack.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined(CONFIG_VE_IPTABLES) && \ ++ (defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)) ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ASSERT_READ_LOCK(x) do { } while (0) ++#define ASSERT_WRITE_LOCK(x) do { } while (0) ++ ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++ ++struct ct_holder ++{ ++ struct ct_holder *next; ++ struct ip_conntrack *ct; ++ int index; ++}; ++ ++static void decode_tuple(struct cpt_ipct_tuple *v, struct ip_conntrack_tuple *tuple, int dir) ++{ ++ tuple->dst.ip = v->cpt_dst; ++ tuple->dst.u.all = v->cpt_dstport; ++ tuple->dst.protonum = v->cpt_protonum; ++ tuple->dst.dir = v->cpt_dir; ++ if (dir != tuple->dst.dir) ++ wprintk("dir != tuple->dst.dir\n"); ++ ++ tuple->src.ip = v->cpt_src; ++ tuple->src.u.all = v->cpt_srcport; ++} ++ ++ ++static int undump_expect_list(struct ip_conntrack *ct, ++ struct cpt_ip_conntrack_image *ci, ++ loff_t pos, struct ct_holder *ct_list, ++ cpt_context_t *ctx) ++{ ++ loff_t end; ++ int err; ++ ++ end = pos + ci->cpt_next; ++ pos += ci->cpt_hdrlen; ++ while (pos < end) { ++ struct cpt_ip_connexpect_image v; ++ struct ip_conntrack_expect *exp; ++ struct ip_conntrack *sibling; ++ ++ err = rst_get_object(CPT_OBJ_NET_CONNTRACK_EXPECT, pos, &v, ctx); ++ if (err) ++ return err; ++ ++ sibling = NULL; ++ if (v.cpt_sibling_conntrack) { ++ struct ct_holder *c; ++ ++ for (c = ct_list; c; c = c->next) { ++ if (c->index == v.cpt_sibling_conntrack) { ++ sibling = c->ct; ++ break; ++ } ++ } ++ if (!sibling) { ++ eprintk_ctx("lost sibling of expectation\n"); ++ return -EINVAL; ++ } ++ } ++ ++ write_lock_bh(&ip_conntrack_lock); ++ ++ /* It is possible. Helper module could be just unregistered, ++ * if expectation were on the list, it would be destroyed. */ ++ if (ct->helper == NULL) { ++ write_unlock_bh(&ip_conntrack_lock); ++ dprintk_ctx("conntrack: no helper and non-trivial expectation\n"); ++ continue; ++ } ++ ++ exp = ip_conntrack_expect_alloc(NULL); ++ if (exp == NULL) { ++ write_unlock_bh(&ip_conntrack_lock); ++ return -ENOMEM; ++ } ++ ++ if (ct->helper->timeout && !del_timer(&exp->timeout)) { ++ /* Dying already. We can do nothing. */ ++ write_unlock_bh(&ip_conntrack_lock); ++ dprintk_ctx("conntrack expectation is dying\n"); ++ continue; ++ } ++ ++ decode_tuple(&v.cpt_tuple, &exp->tuple, 0); ++ decode_tuple(&v.cpt_mask, &exp->mask, 0); ++ ++ exp->master = ct; ++ nf_conntrack_get(&ct->ct_general); ++ ip_conntrack_expect_insert(exp); ++#if 0 ++ if (sibling) { ++ exp->sibling = sibling; ++ sibling->master = exp; ++ LIST_DELETE(&ve_ip_conntrack_expect_list, exp); ++ ct->expecting--; ++ nf_conntrack_get(&master_ct(sibling)->infos[0]); ++ } else ++#endif ++ if (ct->helper->timeout) { ++ exp->timeout.expires = jiffies + v.cpt_timeout; ++ add_timer(&exp->timeout); ++ } ++ write_unlock_bh(&ip_conntrack_lock); ++ ++ pos += v.cpt_next; ++ } ++ return 0; ++} ++ ++static int undump_one_ct(struct cpt_ip_conntrack_image *ci, loff_t pos, ++ struct ct_holder **ct_list, cpt_context_t *ctx) ++{ ++ int err = 0; ++ struct ip_conntrack *conntrack; ++ struct ct_holder *c; ++ struct ip_conntrack_tuple orig, repl; ++ ++ c = kmalloc(sizeof(struct ct_holder), GFP_KERNEL); ++ if (c == NULL) ++ return -ENOMEM; ++ ++ decode_tuple(&ci->cpt_tuple[0], &orig, 0); ++ decode_tuple(&ci->cpt_tuple[1], &repl, 1); ++ ++ conntrack = ip_conntrack_alloc(&orig, &repl, get_exec_env()->_ip_conntrack->ub); ++ if (!conntrack || IS_ERR(conntrack)) { ++ kfree(c); ++ return -ENOMEM; ++ } ++ ++ c->ct = conntrack; ++ c->next = *ct_list; ++ *ct_list = c; ++ c->index = ci->cpt_index; ++ ++ decode_tuple(&ci->cpt_tuple[0], &conntrack->tuplehash[0].tuple, 0); ++ decode_tuple(&ci->cpt_tuple[1], &conntrack->tuplehash[1].tuple, 1); ++ ++ conntrack->status = ci->cpt_status; ++ ++ memcpy(&conntrack->proto, ci->cpt_proto_data, sizeof(conntrack->proto)); ++ memcpy(&conntrack->help, ci->cpt_help_data, sizeof(conntrack->help)); ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ ++ defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) ++ conntrack->nat.masq_index = ci->cpt_masq_index; ++#endif ++ if (ci->cpt_initialized) { ++ conntrack->nat.info.seq[0].correction_pos = ci->cpt_nat_seq[0].cpt_correction_pos; ++ conntrack->nat.info.seq[0].offset_before = ci->cpt_nat_seq[0].cpt_offset_before; ++ conntrack->nat.info.seq[0].offset_after = ci->cpt_nat_seq[0].cpt_offset_after; ++ conntrack->nat.info.seq[1].correction_pos = ci->cpt_nat_seq[1].cpt_correction_pos; ++ conntrack->nat.info.seq[1].offset_before = ci->cpt_nat_seq[1].cpt_offset_before; ++ conntrack->nat.info.seq[1].offset_after = ci->cpt_nat_seq[1].cpt_offset_after; ++ } ++ if (conntrack->status & IPS_NAT_DONE_MASK) ++ ip_nat_hash_conntrack(conntrack); ++#endif ++ ++ if (ci->cpt_ct_helper) { ++ conntrack->helper = ip_conntrack_helper_find_get(&conntrack->tuplehash[1].tuple); ++ if (conntrack->helper == NULL) { ++ eprintk_ctx("conntrack: cannot find helper, some module is not loaded\n"); ++ err = -EINVAL; ++ } ++ } ++ ++ ip_conntrack_hash_insert(conntrack); ++ conntrack->timeout.expires = jiffies + ci->cpt_timeout; ++ ++ if (err == 0 && ci->cpt_next > ci->cpt_hdrlen) ++ err = undump_expect_list(conntrack, ci, pos, *ct_list, ctx); ++ ++ return err; ++} ++ ++int rst_restore_ip_conntrack(struct cpt_context * ctx) ++{ ++ int err = 0; ++ loff_t sec = ctx->sections[CPT_SECT_NET_CONNTRACK]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ struct cpt_ip_conntrack_image ci; ++ struct ct_holder *c; ++ struct ct_holder *ct_list = NULL; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ if (sizeof(ci.cpt_proto_data) != sizeof(union ip_conntrack_proto)) { ++ eprintk_ctx("conntrack module ct->proto version mismatch\n"); ++ return -EINVAL; ++ } ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_NET_CONNTRACK || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ err = rst_get_object(CPT_OBJ_NET_CONNTRACK, sec, &ci, ctx); ++ if (err) ++ break; ++ err = undump_one_ct(&ci, sec, &ct_list, ctx); ++ if (err) ++ break; ++ sec += ci.cpt_next; ++ } ++ ++ while ((c = ct_list) != NULL) { ++ ct_list = c->next; ++ if (c->ct) ++ add_timer(&c->ct->timeout); ++ kfree(c); ++ } ++ ++ return err; ++} ++ ++#else ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++ ++int rst_restore_ip_conntrack(struct cpt_context * ctx) ++{ ++ if (ctx->sections[CPT_SECT_NET_CONNTRACK] != CPT_NULL) ++ return -EINVAL; ++ return 0; ++} ++ ++#endif +Index: kernel/kernel/cpt/rst_context.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_context.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,323 @@ ++/* ++ * ++ * kernel/cpt/rst_context.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++ ++static ssize_t file_read(void *addr, size_t count, struct cpt_context *ctx) ++{ ++ mm_segment_t oldfs; ++ ssize_t err = -EBADF; ++ struct file *file = ctx->file; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ if (file) ++ err = file->f_op->read(file, addr, count, &file->f_pos); ++ set_fs(oldfs); ++ if (err != count) ++ return err >= 0 ? -EIO : err; ++ return 0; ++} ++ ++static ssize_t file_pread(void *addr, size_t count, struct cpt_context *ctx, loff_t pos) ++{ ++ mm_segment_t oldfs; ++ ssize_t err = -EBADF; ++ struct file *file = ctx->file; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ if (file) ++ err = file->f_op->read(file, addr, count, &pos); ++ set_fs(oldfs); ++ if (err != count) ++ return err >= 0 ? -EIO : err; ++ return 0; ++} ++ ++static void file_align(struct cpt_context *ctx) ++{ ++ struct file *file = ctx->file; ++ ++ if (file) ++ file->f_pos = CPT_ALIGN(file->f_pos); ++} ++ ++int rst_get_section(int type, struct cpt_context *ctx, loff_t *start, loff_t *end) ++{ ++ struct cpt_section_hdr hdr; ++ int err; ++ loff_t pos; ++ ++ pos = ctx->sections[type]; ++ *start = *end = pos; ++ ++ if (pos != CPT_NULL) { ++ if ((err = ctx->pread(&hdr, sizeof(hdr), ctx, pos)) != 0) ++ return err; ++ if (hdr.cpt_section != type || hdr.cpt_hdrlen < sizeof(hdr)) ++ return -EINVAL; ++ *start = pos + hdr.cpt_hdrlen; ++ *end = pos + hdr.cpt_next; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(rst_get_section); ++ ++void rst_context_init(struct cpt_context *ctx) ++{ ++ int i; ++ ++ memset(ctx, 0, sizeof(*ctx)); ++ ++ init_MUTEX(&ctx->main_sem); ++ ctx->refcount = 1; ++ ++ ctx->current_section = -1; ++ ctx->current_object = -1; ++ ctx->pagesize = PAGE_SIZE; ++ ctx->read = file_read; ++ ctx->pread = file_pread; ++ ctx->align = file_align; ++ for (i=0; i < CPT_SECT_MAX; i++) ++ ctx->sections[i] = CPT_NULL; ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ init_completion(&ctx->pgin_notify); ++#endif ++ cpt_object_init(ctx); ++} ++ ++static int parse_sections(loff_t start, loff_t end, cpt_context_t *ctx) ++{ ++ struct cpt_section_hdr h; ++ ++ while (start < end) { ++ int err; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, start); ++ if (err) ++ return err; ++ if (h.cpt_hdrlen < sizeof(h) || ++ h.cpt_next < h.cpt_hdrlen || ++ start + h.cpt_next > end) ++ return -EINVAL; ++ if (h.cpt_section >= CPT_SECT_MAX) ++ return -EINVAL; ++ ctx->sections[h.cpt_section] = start; ++ start += h.cpt_next; ++ } ++ return 0; ++} ++ ++int rst_open_dumpfile(struct cpt_context *ctx) ++{ ++ int err; ++ struct cpt_major_tail *v; ++ struct cpt_major_hdr h; ++ unsigned long size; ++ ++ err = -EBADF; ++ if (!ctx->file) ++ goto err_out; ++ ++ err = -ENOMEM; ++ ctx->tmpbuf = (char*)__get_free_page(GFP_KERNEL); ++ if (ctx->tmpbuf == NULL) ++ goto err_out; ++ __cpt_release_buf(ctx); ++ ++ size = ctx->file->f_dentry->d_inode->i_size; ++ ++ if (size & 7) { ++ err = -EINVAL; ++ goto err_out; ++ } ++ if (size < sizeof(struct cpt_major_hdr) + ++ sizeof(struct cpt_major_tail)) { ++ err = -EINVAL; ++ goto err_out; ++ } ++ err = ctx->pread(&h, sizeof(h), ctx, 0); ++ if (err) { ++ eprintk_ctx("too short image 1 %d\n", err); ++ goto err_out; ++ } ++ if (h.cpt_signature[0] != CPT_SIGNATURE0 || ++ h.cpt_signature[1] != CPT_SIGNATURE1 || ++ h.cpt_signature[2] != CPT_SIGNATURE2 || ++ h.cpt_signature[3] != CPT_SIGNATURE3) { ++ err = -EINVAL; ++ goto err_out; ++ } ++ if (h.cpt_hz != HZ) { ++ err = -EINVAL; ++ eprintk_ctx("HZ mismatch: %d != %d\n", h.cpt_hz, HZ); ++ goto err_out; ++ } ++ ctx->virt_jiffies64 = h.cpt_start_jiffies64; ++ ctx->start_time.tv_sec = h.cpt_start_sec; ++ ctx->start_time.tv_nsec = h.cpt_start_nsec; ++ ctx->kernel_config_flags = h.cpt_kernel_config[0]; ++ ctx->iptables_mask = h.cpt_iptables_mask; ++ if (h.cpt_image_version > CPT_VERSION_20 || ++ CPT_VERSION_MINOR(h.cpt_image_version) > 1) { ++ eprintk_ctx("Unknown image version: %x. Can't restore.\n", ++ h.cpt_image_version); ++ err = -EINVAL; ++ goto err_out; ++ } ++ ctx->image_version = h.cpt_image_version; ++ ctx->features = (__u64)((__u64)h.cpt_ve_features2<<32 | h.cpt_ve_features); ++ ctx->image_arch = h.cpt_os_arch; ++ ++ v = cpt_get_buf(ctx); ++ err = ctx->pread(v, sizeof(*v), ctx, size - sizeof(*v)); ++ if (err) { ++ eprintk_ctx("too short image 2 %d\n", err); ++ cpt_release_buf(ctx); ++ goto err_out; ++ } ++ if (v->cpt_signature[0] != CPT_SIGNATURE0 || ++ v->cpt_signature[1] != CPT_SIGNATURE1 || ++ v->cpt_signature[2] != CPT_SIGNATURE2 || ++ v->cpt_signature[3] != CPT_SIGNATURE3 || ++ v->cpt_nsect != CPT_SECT_MAX_INDEX) { ++ err = -EINVAL; ++ cpt_release_buf(ctx); ++ goto err_out; ++ } ++ if ((err = parse_sections(h.cpt_hdrlen, size - sizeof(*v) - sizeof(struct cpt_section_hdr), ctx)) < 0) { ++ cpt_release_buf(ctx); ++ goto err_out; ++ } ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ ctx->lazypages = v->cpt_lazypages; ++#endif ++ ctx->tasks64 = v->cpt_64bit; ++ cpt_release_buf(ctx); ++ return 0; ++ ++err_out: ++ if (ctx->tmpbuf) { ++ free_page((unsigned long)ctx->tmpbuf); ++ ctx->tmpbuf = NULL; ++ } ++ return err; ++} ++ ++void rst_close_dumpfile(struct cpt_context *ctx) ++{ ++ if (ctx->file) { ++ fput(ctx->file); ++ ctx->file = NULL; ++ } ++ if (ctx->tmpbuf) { ++ free_page((unsigned long)ctx->tmpbuf); ++ ctx->tmpbuf = NULL; ++ } ++} ++ ++int _rst_get_object(int type, loff_t pos, void *tmp, int size, struct cpt_context *ctx) ++{ ++ int err; ++ struct cpt_object_hdr *hdr = tmp; ++ err = ctx->pread(hdr, sizeof(struct cpt_object_hdr), ctx, pos); ++ if (err) ++ return err; ++ if (type > 0 && type != hdr->cpt_object) ++ return -EINVAL; ++ if (hdr->cpt_hdrlen > hdr->cpt_next) ++ return -EINVAL; ++ if (hdr->cpt_hdrlen < sizeof(struct cpt_object_hdr)) ++ return -EINVAL; ++ if (size < sizeof(*hdr)) ++ return -EINVAL; ++ if (size > hdr->cpt_hdrlen) ++ size = hdr->cpt_hdrlen; ++ if (size > sizeof(*hdr)) ++ err = ctx->pread(hdr+1, size - sizeof(*hdr), ++ ctx, pos + sizeof(*hdr)); ++ return err; ++} ++EXPORT_SYMBOL(_rst_get_object); ++ ++void * __rst_get_object(int type, loff_t pos, struct cpt_context *ctx) ++{ ++ int err; ++ void *tmp; ++ struct cpt_object_hdr hdr; ++ err = ctx->pread(&hdr, sizeof(hdr), ctx, pos); ++ if (err) ++ return NULL; ++ if (type > 0 && type != hdr.cpt_object) ++ return NULL; ++ if (hdr.cpt_hdrlen > hdr.cpt_next) ++ return NULL; ++ if (hdr.cpt_hdrlen < sizeof(struct cpt_object_hdr)) ++ return NULL; ++ tmp = kmalloc(hdr.cpt_hdrlen, GFP_KERNEL); ++ if (!tmp) ++ return NULL; ++ err = ctx->pread(tmp, hdr.cpt_hdrlen, ctx, pos); ++ if (!err) ++ return tmp; ++ kfree(tmp); ++ return NULL; ++} ++EXPORT_SYMBOL(__rst_get_object); ++ ++__u8 *__rst_get_name(loff_t *pos_p, struct cpt_context *ctx) ++{ ++ int err; ++ struct cpt_object_hdr hdr; ++ __u8 *name; ++ ++ err = rst_get_object(CPT_OBJ_NAME, *pos_p, &hdr, ctx); ++ if (err) ++ return NULL; ++ if (hdr.cpt_next - hdr.cpt_hdrlen > PAGE_SIZE) ++ return NULL; ++ name = (void*)__get_free_page(GFP_KERNEL); ++ if (!name) ++ return NULL; ++ err = ctx->pread(name, hdr.cpt_next - hdr.cpt_hdrlen, ++ ctx, *pos_p + hdr.cpt_hdrlen); ++ if (err) { ++ free_page((unsigned long)name); ++ return NULL; ++ } ++ *pos_p += hdr.cpt_next; ++ return name; ++} ++ ++__u8 *rst_get_name(loff_t pos, struct cpt_context *ctx) ++{ ++ return __rst_get_name(&pos, ctx); ++} ++ ++void rst_put_name(__u8 *name, struct cpt_context *ctx) ++{ ++ unsigned long addr = (unsigned long)name; ++ ++ if (addr) ++ free_page(addr&~(PAGE_SIZE-1)); ++} +Index: kernel/kernel/cpt/rst_epoll.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_epoll.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,170 @@ ++/* ++ * ++ * kernel/cpt/rst_epoll.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_mm.h" ++#include "cpt_files.h" ++#include "cpt_kernel.h" ++#include "cpt_fsmagic.h" ++#include "cpt_syscalls.h" ++ ++/* Those funcations are static in fs/eventpoll.c */ ++extern struct file_operations eventpoll_fops; ++extern int ep_insert(struct eventpoll *ep, struct epoll_event *event, ++ struct file *tfile, int fd); ++extern struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd); ++extern void ep_release_epitem(struct epitem *epi); ++ ++ ++struct file *cpt_open_epolldev(struct cpt_file_image *fi, ++ unsigned flags, ++ struct cpt_context *ctx) ++{ ++ struct file *file; ++ int efd; ++ ++ /* Argument "size" is ignored, use just 1 */ ++ efd = sys_epoll_create(1); ++ if (efd < 0) ++ return ERR_PTR(efd); ++ ++ file = fget(efd); ++ sys_close(efd); ++ return file; ++} ++ ++static int restore_one_epoll(cpt_object_t *obj, ++ loff_t pos, ++ struct cpt_epoll_image *ebuf, ++ cpt_context_t *ctx) ++{ ++ int err = 0; ++ loff_t endpos; ++ struct file *file = obj->o_obj; ++ struct eventpoll *ep; ++ ++ if (file->f_op != &eventpoll_fops) { ++ eprintk_ctx("bad epoll file\n"); ++ return -EINVAL; ++ } ++ ++ ep = file->private_data; ++ ++ if (unlikely(ep == NULL)) { ++ eprintk_ctx("bad epoll device\n"); ++ return -EINVAL; ++ } ++ ++ endpos = pos + ebuf->cpt_next; ++ pos += ebuf->cpt_hdrlen; ++ while (pos < endpos) { ++ struct cpt_epoll_file_image efi; ++ struct epoll_event epds; ++ ++ cpt_object_t *tobj; ++ ++ err = rst_get_object(CPT_OBJ_EPOLL_FILE, pos, &efi, ctx); ++ if (err) ++ return err; ++ tobj = lookup_cpt_obj_bypos(CPT_OBJ_FILE, efi.cpt_file, ctx); ++ if (!tobj) { ++ eprintk_ctx("epoll file not found\n"); ++ return -EINVAL; ++ } ++ epds.events = efi.cpt_events; ++ epds.data = efi.cpt_data; ++ mutex_lock(&ep->mtx); ++ err = ep_insert(ep, &epds, tobj->o_obj, efi.cpt_fd); ++ if (!err) { ++ struct epitem *epi; ++ epi = ep_find(ep, tobj->o_obj, efi.cpt_fd); ++ if (epi) { ++ if (efi.cpt_ready) { ++ unsigned long flags; ++ spin_lock_irqsave(&ep->lock, flags); ++ if (list_empty(&epi->rdllink)) ++ list_add_tail(&epi->rdllink, &ep->rdllist); ++ spin_unlock_irqrestore(&ep->lock, flags); ++ } ++ } ++ } ++ mutex_unlock(&ep->mtx); ++ if (err) ++ break; ++ pos += efi.cpt_next; ++ } ++ return err; ++} ++ ++int rst_eventpoll(cpt_context_t *ctx) ++{ ++ int err; ++ loff_t sec = ctx->sections[CPT_SECT_EPOLL]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_EPOLL || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ cpt_object_t *obj; ++ struct cpt_epoll_image *ebuf = cpt_get_buf(ctx); ++ err = rst_get_object(CPT_OBJ_EPOLL, sec, ebuf, ctx); ++ if (err) { ++ cpt_release_buf(ctx); ++ return err; ++ } ++ obj = lookup_cpt_obj_bypos(CPT_OBJ_FILE, ebuf->cpt_file, ctx); ++ if (obj == NULL) { ++ eprintk_ctx("cannot find epoll file object\n"); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ err = restore_one_epoll(obj, sec, ebuf, ctx); ++ cpt_release_buf(ctx); ++ if (err) ++ return err; ++ sec += ebuf->cpt_next; ++ } ++ ++ return 0; ++ ++} +Index: kernel/kernel/cpt/rst_files.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_files.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,1656 @@ ++/* ++ * ++ * kernel/cpt/rst_files.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_mm.h" ++#include "cpt_files.h" ++#include "cpt_kernel.h" ++#include "cpt_fsmagic.h" ++ ++#include "cpt_syscalls.h" ++ ++ ++struct filejob { ++ struct filejob *next; ++ int pid; ++ loff_t fdi; ++}; ++ ++static int rst_filejob_queue(loff_t pos, cpt_context_t *ctx) ++{ ++ struct filejob *j; ++ ++ j = kmalloc(sizeof(*j), GFP_KERNEL); ++ if (j == NULL) ++ return -ENOMEM; ++ j->pid = current->pid; ++ j->fdi = pos; ++ j->next = ctx->filejob_queue; ++ ctx->filejob_queue = j; ++ return 0; ++} ++ ++static void _anon_pipe_buf_release(struct pipe_inode_info *pipe, ++ struct pipe_buffer *buf) ++{ ++ struct page *page = buf->page; ++ ++ /* ++ * If nobody else uses this page, and we don't already have a ++ * temporary page, let's keep track of it as a one-deep ++ * allocation cache. (Otherwise just release our reference to it) ++ */ ++ if (page_count(page) == 1 && !pipe->tmp_page) ++ pipe->tmp_page = page; ++ else ++ page_cache_release(page); ++ ++ module_put(THIS_MODULE); ++} ++ ++static void *_anon_pipe_buf_map(struct pipe_inode_info *pipe, ++ struct pipe_buffer *buf, int atomic) ++{ ++ if (atomic) { ++ buf->flags |= PIPE_BUF_FLAG_ATOMIC; ++ return kmap_atomic(buf->page, KM_USER0); ++ } ++ ++ return kmap(buf->page); ++} ++ ++static void _anon_pipe_buf_unmap(struct pipe_inode_info *pipe, ++ struct pipe_buffer *buf, void *map_data) ++{ ++ if (buf->flags & PIPE_BUF_FLAG_ATOMIC) { ++ buf->flags &= ~PIPE_BUF_FLAG_ATOMIC; ++ kunmap_atomic(map_data, KM_USER0); ++ } else ++ kunmap(buf->page); ++} ++ ++static int _anon_pipe_buf_steal(struct pipe_inode_info *pipe, ++ struct pipe_buffer *buf) ++{ ++ struct page *page = buf->page; ++ ++ if (page_count(page) == 1) { ++ lock_page(page); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static void _anon_pipe_buf_get(struct pipe_inode_info *info, struct pipe_buffer *buf) ++{ ++ page_cache_get(buf->page); ++} ++ ++static int _anon_pipe_buf_confirm(struct pipe_inode_info *info, struct pipe_buffer *buf) ++{ ++ return 0; ++} ++ ++static struct pipe_buf_operations _anon_pipe_buf_ops = { ++ .can_merge = 1, ++ .map = _anon_pipe_buf_map, ++ .unmap = _anon_pipe_buf_unmap, ++ .release = _anon_pipe_buf_release, ++ .confirm = _anon_pipe_buf_confirm, ++ .get = _anon_pipe_buf_get, ++ .steal = _anon_pipe_buf_steal, ++}; ++ ++/* Sorta ugly... Multiple readers/writers of named pipe rewrite buffer ++ * many times. We need to mark it in CPT_OBJ_INODE table in some way. ++ */ ++static int fixup_pipe_data(struct file *file, struct cpt_file_image *fi, ++ struct cpt_context *ctx) ++{ ++ struct inode *ino = file->f_dentry->d_inode; ++ struct cpt_inode_image ii; ++ struct cpt_obj_bits b; ++ struct pipe_inode_info *info; ++ int err; ++ int count; ++ ++ if (!S_ISFIFO(ino->i_mode)) { ++ eprintk_ctx("fixup_pipe_data: not a pipe %Ld\n", (long long)fi->cpt_inode); ++ return -EINVAL; ++ } ++ if (fi->cpt_inode == CPT_NULL) ++ return 0; ++ ++ err = rst_get_object(CPT_OBJ_INODE, fi->cpt_inode, &ii, ctx); ++ if (err) ++ return err; ++ ++ if (ii.cpt_next <= ii.cpt_hdrlen) ++ return 0; ++ ++ err = rst_get_object(CPT_OBJ_BITS, fi->cpt_inode + ii.cpt_hdrlen, &b, ctx); ++ if (err) ++ return err; ++ ++ if (b.cpt_size == 0) ++ return 0; ++ ++ mutex_lock(&ino->i_mutex); ++ info = ino->i_pipe; ++ if (info->nrbufs) { ++ mutex_unlock(&ino->i_mutex); ++ eprintk("pipe buffer is restored already\n"); ++ return -EINVAL; ++ } ++ info->curbuf = 0; ++ count = 0; ++ while (count < b.cpt_size) { ++ struct pipe_buffer *buf = info->bufs + info->nrbufs; ++ void * addr; ++ int chars; ++ ++ chars = b.cpt_size - count; ++ if (chars > PAGE_SIZE) ++ chars = PAGE_SIZE; ++ if (!try_module_get(THIS_MODULE)) { ++ err = -EBUSY; ++ break; ++ } ++ ++ buf->page = alloc_page(GFP_HIGHUSER); ++ if (buf->page == NULL) { ++ err = -ENOMEM; ++ break; ++ } ++ buf->ops = &_anon_pipe_buf_ops; ++ buf->offset = 0; ++ buf->len = chars; ++ info->nrbufs++; ++ addr = kmap(buf->page); ++ err = ctx->pread(addr, chars, ctx, ++ fi->cpt_inode + ii.cpt_hdrlen + b.cpt_hdrlen + count); ++ if (err) ++ break; ++ count += chars; ++ } ++ mutex_unlock(&ino->i_mutex); ++ ++ return err; ++} ++ ++static int make_flags(struct cpt_file_image *fi) ++{ ++ int flags = O_NOFOLLOW; ++ switch (fi->cpt_mode&(FMODE_READ|FMODE_WRITE)) { ++ case FMODE_READ|FMODE_WRITE: ++ flags |= O_RDWR; break; ++ case FMODE_WRITE: ++ flags |= O_WRONLY; break; ++ case FMODE_READ: ++ flags |= O_RDONLY; break; ++ default: break; ++ } ++ flags |= fi->cpt_flags&~(O_ACCMODE|O_CREAT|O_TRUNC|O_EXCL|FASYNC); ++ flags |= O_NONBLOCK|O_NOCTTY; ++ return flags; ++} ++ ++static struct file *open_pipe(char *name, ++ struct cpt_file_image *fi, ++ unsigned flags, ++ struct cpt_context *ctx) ++{ ++ int err; ++ cpt_object_t *obj; ++ struct cpt_inode_image ii; ++ struct file *rf, *wf; ++ ++ err = rst_get_object(CPT_OBJ_INODE, fi->cpt_inode, &ii, ctx); ++ if (err) ++ return ERR_PTR(err); ++ ++ if (ii.cpt_sb == FSMAGIC_PIPEFS) { ++ int pfd[2]; ++ ++ if ((err = sc_pipe(pfd)) < 0) ++ return ERR_PTR(err); ++ ++ rf = fcheck(pfd[0]); ++ wf = fcheck(pfd[1]); ++ get_file(rf); ++ get_file(wf); ++ sc_close(pfd[0]); ++ sc_close(pfd[1]); ++ ++ if (fi->cpt_mode&FMODE_READ) { ++ struct file *tf; ++ tf = wf; wf = rf; rf = tf; ++ } ++ } else { ++ if (fi->cpt_mode&FMODE_READ) { ++ rf = filp_open(name, flags, 0); ++ if (IS_ERR(rf)) { ++ dprintk_ctx("filp_open\n"); ++ return rf; ++ } ++ dprintk_ctx(CPT_FID "open RDONLY fifo ino %Ld %p %x\n", CPT_TID(current), ++ (long long)fi->cpt_inode, rf, rf->f_dentry->d_inode->i_mode); ++ return rf; ++ } ++ ++ dprintk_ctx(CPT_FID "open WRONLY fifo ino %Ld\n", CPT_TID(current), (long long)fi->cpt_inode); ++ ++ rf = filp_open(name, O_RDWR|O_NONBLOCK, 0); ++ if (IS_ERR(rf)) ++ return rf; ++ wf = dentry_open(dget(rf->f_dentry), ++ mntget(rf->f_vfsmnt), flags); ++ } ++ ++ /* Add pipe inode to obj table. */ ++ obj = cpt_object_add(CPT_OBJ_INODE, wf->f_dentry->d_inode, ctx); ++ if (obj == NULL) { ++ fput(rf); fput(wf); ++ return ERR_PTR(-ENOMEM); ++ } ++ cpt_obj_setpos(obj, fi->cpt_inode, ctx); ++ obj->o_parent = rf; ++ ++ /* Add another side of pipe to obj table, it will not be used ++ * (o_pos = PT_NULL), another processes opeining pipe will find ++ * inode and open it with dentry_open(). */ ++ obj = cpt_object_add(CPT_OBJ_FILE, rf, ctx); ++ if (obj == NULL) { ++ fput(wf); ++ return ERR_PTR(-ENOMEM); ++ } ++ return wf; ++} ++ ++static struct file *open_special(struct cpt_file_image *fi, ++ unsigned flags, ++ int deleted, ++ struct cpt_context *ctx) ++{ ++ struct cpt_inode_image *ii; ++ struct file *file; ++ ++ /* Directories and named pipes are not special actually */ ++ if (S_ISDIR(fi->cpt_i_mode) || S_ISFIFO(fi->cpt_i_mode)) ++ return NULL; ++ ++ /* No support for block devices at the moment. */ ++ if (S_ISBLK(fi->cpt_i_mode)) ++ return ERR_PTR(-EINVAL); ++ ++ if (S_ISSOCK(fi->cpt_i_mode)) { ++ eprintk_ctx("bug: socket is not open\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ /* Support only (some) character devices at the moment. */ ++ if (!S_ISCHR(fi->cpt_i_mode)) ++ return ERR_PTR(-EINVAL); ++ ++ ii = __rst_get_object(CPT_OBJ_INODE, fi->cpt_inode, ctx); ++ if (ii == NULL) ++ return ERR_PTR(-ENOMEM); ++ ++ /* Do not worry about this right now. /dev/null,zero,*random are here. ++ * To prohibit at least /dev/mem? ++ */ ++ if (MAJOR(ii->cpt_rdev) == MEM_MAJOR) { ++ kfree(ii); ++ return NULL; ++ } ++ ++ /* /dev/net/tun will be opened by caller */ ++ if (fi->cpt_lflags & CPT_DENTRY_TUNTAP) { ++ kfree(ii); ++ return NULL; ++ } ++ ++ file = rst_open_tty(fi, ii, flags, ctx); ++ kfree(ii); ++ return file; ++} ++ ++static int restore_posix_lock(struct file *file, struct cpt_flock_image *fli, cpt_context_t *ctx) ++{ ++ struct file_lock lock; ++ cpt_object_t *obj; ++ ++ memset(&lock, 0, sizeof(lock)); ++ lock.fl_type = fli->cpt_type; ++ lock.fl_flags = fli->cpt_flags & ~FL_SLEEP; ++ lock.fl_start = fli->cpt_start; ++ lock.fl_end = fli->cpt_end; ++ obj = lookup_cpt_obj_byindex(CPT_OBJ_FILES, fli->cpt_owner, ctx); ++ if (!obj) { ++ eprintk_ctx("unknown lock owner %d\n", (int)fli->cpt_owner); ++ return -EINVAL; ++ } ++ lock.fl_owner = obj->o_obj; ++ lock.fl_pid = vpid_to_pid(fli->cpt_pid); ++ if (lock.fl_pid < 0) { ++ eprintk_ctx("unknown lock pid %d\n", lock.fl_pid); ++ return -EINVAL; ++ } ++ lock.fl_file = file; ++ ++ if (lock.fl_owner == NULL) ++ eprintk_ctx("no lock owner\n"); ++ return posix_lock_file(file, &lock, NULL); ++} ++ ++static int restore_flock(struct file *file, struct cpt_flock_image *fli, ++ cpt_context_t *ctx) ++{ ++ int cmd, err, fd; ++ fd = get_unused_fd(); ++ if (fd < 0) { ++ eprintk_ctx("BSD flock cannot be restored\n"); ++ return fd; ++ } ++ get_file(file); ++ fd_install(fd, file); ++ if (fli->cpt_type == F_RDLCK) { ++ cmd = LOCK_SH; ++ } else if (fli->cpt_type == F_WRLCK) { ++ cmd = LOCK_EX; ++ } else { ++ eprintk_ctx("flock flavor is unknown: %u\n", fli->cpt_type); ++ sc_close(fd); ++ return -EINVAL; ++ } ++ ++ err = sc_flock(fd, LOCK_NB | cmd); ++ sc_close(fd); ++ return err; ++} ++ ++ ++static int fixup_posix_locks(struct file *file, ++ struct cpt_file_image *fi, ++ loff_t pos, struct cpt_context *ctx) ++{ ++ int err; ++ loff_t end; ++ struct cpt_flock_image fli; ++ ++ end = pos + fi->cpt_next; ++ pos += fi->cpt_hdrlen; ++ while (pos < end) { ++ err = rst_get_object(-1, pos, &fli, ctx); ++ if (err) ++ return err; ++ if (fli.cpt_object == CPT_OBJ_FLOCK && ++ (fli.cpt_flags&FL_POSIX)) { ++ err = restore_posix_lock(file, &fli, ctx); ++ if (err) ++ return err; ++ dprintk_ctx("posix lock restored\n"); ++ } ++ pos += fli.cpt_next; ++ } ++ return 0; ++} ++ ++int rst_posix_locks(struct cpt_context *ctx) ++{ ++ int err; ++ cpt_object_t *obj; ++ ++ for_each_object(obj, CPT_OBJ_FILE) { ++ struct file *file = obj->o_obj; ++ struct cpt_file_image fi; ++ ++ if (obj->o_pos == CPT_NULL) ++ continue; ++ ++ err = rst_get_object(CPT_OBJ_FILE, obj->o_pos, &fi, ctx); ++ if (err < 0) ++ return err; ++ if (fi.cpt_next > fi.cpt_hdrlen) ++ fixup_posix_locks(file, &fi, obj->o_pos, ctx); ++ } ++ return 0; ++} ++ ++static int fixup_flocks(struct file *file, ++ struct cpt_file_image *fi, ++ loff_t pos, struct cpt_context *ctx) ++{ ++ int err; ++ loff_t end; ++ struct cpt_flock_image fli; ++ ++ end = pos + fi->cpt_next; ++ pos += fi->cpt_hdrlen; ++ while (pos < end) { ++ err = rst_get_object(-1, pos, &fli, ctx); ++ if (err) ++ return err; ++ if (fli.cpt_object == CPT_OBJ_FLOCK && ++ (fli.cpt_flags&FL_FLOCK)) { ++ err = restore_flock(file, &fli, ctx); ++ if (err) ++ return err; ++ dprintk_ctx("bsd lock restored\n"); ++ } ++ pos += fli.cpt_next; ++ } ++ return 0; ++} ++ ++ ++static int fixup_reg_data(struct file *file, loff_t pos, loff_t end, ++ struct cpt_context *ctx) ++{ ++ int err; ++ struct cpt_page_block pgb; ++ ssize_t (*do_write)(struct file *, const char __user *, size_t, loff_t *ppos); ++ ++ do_write = file->f_op->write; ++ if (do_write == NULL) { ++ eprintk_ctx("no write method. Cannot restore contents of the file.\n"); ++ return -EINVAL; ++ } ++ ++ atomic_inc(&file->f_count); ++ ++ while (pos < end) { ++ loff_t opos; ++ loff_t ipos; ++ int count; ++ ++ err = rst_get_object(CPT_OBJ_PAGES, pos, &pgb, ctx); ++ if (err) ++ goto out; ++ dprintk_ctx("restoring file data block: %08x-%08x\n", ++ (__u32)pgb.cpt_start, (__u32)pgb.cpt_end); ++ ipos = pos + pgb.cpt_hdrlen; ++ opos = pgb.cpt_start; ++ count = pgb.cpt_end-pgb.cpt_start; ++ while (count > 0) { ++ mm_segment_t oldfs; ++ int copy = count; ++ ++ if (copy > PAGE_SIZE) ++ copy = PAGE_SIZE; ++ (void)cpt_get_buf(ctx); ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ err = ctx->pread(ctx->tmpbuf, copy, ctx, ipos); ++ set_fs(oldfs); ++ if (err) { ++ __cpt_release_buf(ctx); ++ goto out; ++ } ++ if (!(file->f_mode & FMODE_WRITE) || ++ (file->f_flags&O_DIRECT)) { ++ fput(file); ++ file = dentry_open(dget(file->f_dentry), ++ mntget(file->f_vfsmnt), O_WRONLY); ++ if (IS_ERR(file)) { ++ __cpt_release_buf(ctx); ++ return PTR_ERR(file); ++ } ++ } ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ ipos += copy; ++ err = do_write(file, ctx->tmpbuf, copy, &opos); ++ set_fs(oldfs); ++ __cpt_release_buf(ctx); ++ if (err != copy) { ++ if (err >= 0) ++ err = -EIO; ++ goto out; ++ } ++ count -= copy; ++ } ++ pos += pgb.cpt_next; ++ } ++ err = 0; ++ ++out: ++ fput(file); ++ return err; ++} ++ ++ ++static int fixup_file_content(struct file **file_p, struct cpt_file_image *fi, ++ struct cpt_inode_image *ii, ++ struct cpt_context *ctx) ++{ ++ int err; ++ struct file *file = *file_p; ++ struct iattr newattrs; ++ ++ if (!S_ISREG(fi->cpt_i_mode)) ++ return 0; ++ ++ if (file == NULL) { ++ file = shmem_file_setup("dev/zero", ii->cpt_size, 0); ++ if (IS_ERR(file)) ++ return PTR_ERR(file); ++ *file_p = file; ++ } ++ ++ if (ii->cpt_next > ii->cpt_hdrlen) { ++ struct cpt_object_hdr hdr; ++ err = ctx->pread(&hdr, sizeof(struct cpt_object_hdr), ctx, fi->cpt_inode+ii->cpt_hdrlen); ++ if (err) ++ return err; ++ if (hdr.cpt_object == CPT_OBJ_PAGES) { ++ err = fixup_reg_data(file, fi->cpt_inode+ii->cpt_hdrlen, ++ fi->cpt_inode+ii->cpt_next, ctx); ++ if (err) ++ return err; ++ } ++ } ++ ++ mutex_lock(&file->f_dentry->d_inode->i_mutex); ++ /* stage 1 - update size like do_truncate does */ ++ newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; ++ newattrs.ia_size = ii->cpt_size; ++ cpt_timespec_import(&newattrs.ia_ctime, ii->cpt_ctime); ++ err = notify_change(file->f_dentry, NULL, &newattrs); ++ if (err) ++ goto out; ++ ++ /* stage 2 - update times, owner and mode */ ++ newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ++ ATTR_ATIME_SET | ATTR_MTIME_SET | ++ ATTR_MODE | ATTR_UID | ATTR_GID; ++ newattrs.ia_uid = ii->cpt_uid; ++ newattrs.ia_gid = ii->cpt_gid; ++ newattrs.ia_mode = file->f_dentry->d_inode->i_mode & S_IFMT; ++ newattrs.ia_mode |= (ii->cpt_mode & ~S_IFMT); ++ cpt_timespec_import(&newattrs.ia_atime, ii->cpt_atime); ++ cpt_timespec_import(&newattrs.ia_mtime, ii->cpt_mtime); ++ err = notify_change(file->f_dentry, NULL, &newattrs); ++ ++out: ++ mutex_unlock(&file->f_dentry->d_inode->i_mutex); ++ return err; ++} ++ ++static int fixup_file_flags(struct file *file, struct cpt_file_image *fi, ++ int was_dentry_open, loff_t pos, ++ cpt_context_t *ctx) ++{ ++ if (fi->cpt_pos != file->f_pos) { ++ int err = -ESPIPE; ++ if (file->f_op->llseek) ++ err = file->f_op->llseek(file, fi->cpt_pos, 0); ++ if (err < 0) { ++ dprintk_ctx("file %Ld lseek %Ld - %Ld\n", ++ (long long)pos, ++ (long long)file->f_pos, ++ (long long)fi->cpt_pos); ++ file->f_pos = fi->cpt_pos; ++ } ++ } ++ file->f_uid = fi->cpt_uid; ++ file->f_gid = fi->cpt_gid; ++ file->f_owner.pid = 0; ++ if (fi->cpt_fown_pid != CPT_FOWN_STRAY_PID) { ++ file->f_owner.pid = find_get_pid(fi->cpt_fown_pid); ++ if (file->f_owner.pid == NULL) { ++ wprintk_ctx("fixup_file_flags: owner %d does not exist anymore\n", ++ fi->cpt_fown_pid); ++ return -EINVAL; ++ } ++ } ++ file->f_owner.uid = fi->cpt_fown_uid; ++ file->f_owner.euid = fi->cpt_fown_euid; ++ file->f_owner.signum = fi->cpt_fown_signo; ++ ++ if (file->f_mode != fi->cpt_mode) { ++ if (was_dentry_open && ++ ((file->f_mode^fi->cpt_mode)&(FMODE_PREAD|FMODE_LSEEK))) { ++ file->f_mode &= ~(FMODE_PREAD|FMODE_LSEEK); ++ file->f_mode |= fi->cpt_mode&(FMODE_PREAD|FMODE_LSEEK); ++ } ++ if (file->f_mode != fi->cpt_mode) ++ wprintk_ctx("file %ld mode mismatch %08x %08x\n", (long)pos, file->f_mode, fi->cpt_mode); ++ } ++ if (file->f_flags != fi->cpt_flags) { ++ if (!(fi->cpt_flags&O_NOFOLLOW)) ++ file->f_flags &= ~O_NOFOLLOW; ++ if ((file->f_flags^fi->cpt_flags)&O_NONBLOCK) { ++ file->f_flags &= ~O_NONBLOCK; ++ file->f_flags |= fi->cpt_flags&O_NONBLOCK; ++ } ++ if (fi->cpt_flags&FASYNC) { ++ if (fi->cpt_fown_fd == -1) { ++ wprintk_ctx("No fd for FASYNC\n"); ++ return -EINVAL; ++ } else if (file->f_op && file->f_op->fasync) { ++ if (file->f_op->fasync(fi->cpt_fown_fd, file, 1) < 0) { ++ wprintk_ctx("FASYNC problem\n"); ++ return -EINVAL; ++ } else { ++ file->f_flags |= FASYNC; ++ } ++ } ++ } ++ if (file->f_flags != fi->cpt_flags) { ++ eprintk_ctx("file %ld flags mismatch %08x %08x\n", (long)pos, file->f_flags, fi->cpt_flags); ++ return -EINVAL; ++ } ++ } ++ return 0; ++} ++ ++static struct file * ++open_deleted(char *name, unsigned flags, struct cpt_file_image *fi, ++ struct cpt_inode_image *ii, cpt_context_t *ctx) ++{ ++ struct file * file; ++ char *suffix = NULL; ++ int attempt = 0; ++ int tmp_pass = 0; ++ mode_t mode = fi->cpt_i_mode; ++ ++ /* Strip (deleted) part... */ ++ if (strlen(name) > strlen(" (deleted)")) { ++ if (strcmp(name + strlen(name) - strlen(" (deleted)"), " (deleted)") == 0) { ++ suffix = &name[strlen(name) - strlen(" (deleted)")]; ++ *suffix = 0; ++ } else if (memcmp(name, "(deleted) ", strlen("(deleted) ")) == 0) { ++ memmove(name, name + strlen("(deleted) "), strlen(name) - strlen(" (deleted)") + 1); ++ suffix = name + strlen(name); ++ } ++ } ++ ++try_again: ++ for (;;) { ++ if (attempt) { ++ if (attempt > 1000) { ++ eprintk_ctx("open_deleted: failed after %d attempts\n", attempt); ++ return ERR_PTR(-EEXIST); ++ } ++ if (suffix == NULL) { ++ eprintk_ctx("open_deleted: no suffix\n"); ++ return ERR_PTR(-EEXIST); ++ } ++ sprintf(suffix, ".%08x", (unsigned)((xtime.tv_nsec>>10)+attempt)); ++ } ++ attempt++; ++ ++ if (S_ISFIFO(mode)) { ++ int err; ++ err = sc_mknod(name, S_IFIFO|(mode&017777), 0); ++ if (err == -EEXIST) ++ continue; ++ if (err < 0 && !tmp_pass) ++ goto change_dir; ++ if (err < 0) ++ return ERR_PTR(err); ++ file = open_pipe(name, fi, flags, ctx); ++ sc_unlink(name); ++ } else if (S_ISCHR(mode)) { ++ int err; ++ err = sc_mknod(name, S_IFCHR|(mode&017777), new_encode_dev(ii->cpt_rdev)); ++ if (err == -EEXIST) ++ continue; ++ if (err < 0 && !tmp_pass) ++ goto change_dir; ++ if (err < 0) ++ return ERR_PTR(err); ++ file = filp_open(name, flags, mode&017777); ++ sc_unlink(name); ++ } else if (S_ISDIR(mode)) { ++ int err; ++ err = sc_mkdir(name, mode&017777); ++ if (err == -EEXIST) ++ continue; ++ if (err < 0 && !tmp_pass) ++ goto change_dir; ++ if (err < 0) ++ return ERR_PTR(err); ++ file = filp_open(name, flags, mode&017777); ++ sc_rmdir(name); ++ } else { ++ file = filp_open(name, O_CREAT|O_EXCL|flags, mode&017777); ++ if (IS_ERR(file)) { ++ if (PTR_ERR(file) == -EEXIST) ++ continue; ++ if (!tmp_pass) ++ goto change_dir; ++ } else { ++ sc_unlink(name); ++ } ++ } ++ break; ++ } ++ ++ if (IS_ERR(file)) { ++ eprintk_ctx("filp_open %s: %ld\n", name, PTR_ERR(file)); ++ return file; ++ } else { ++ dprintk_ctx("deleted file created as %s, %p, %x\n", name, file, file->f_dentry->d_inode->i_mode); ++ } ++ return file; ++ ++change_dir: ++ sprintf(name, "/tmp/rst%u", current->pid); ++ suffix = name + strlen(name); ++ attempt = 1; ++ tmp_pass = 1; ++ goto try_again; ++} ++ ++struct file *rst_file(loff_t pos, int fd, struct cpt_context *ctx) ++{ ++ int err; ++ int was_dentry_open = 0; ++ cpt_object_t *obj; ++ cpt_object_t *iobj; ++ struct cpt_file_image fi; ++ __u8 *name = NULL; ++ struct file *file; ++ int flags; ++ ++ obj = lookup_cpt_obj_bypos(CPT_OBJ_FILE, pos, ctx); ++ if (obj) { ++ file = obj->o_obj; ++ if (obj->o_index >= 0) { ++ dprintk_ctx("file is attached to a socket\n"); ++ err = rst_get_object(CPT_OBJ_FILE, pos, &fi, ctx); ++ if (err < 0) ++ goto err_out; ++ fixup_file_flags(file, &fi, 0, pos, ctx); ++ } ++ get_file(file); ++ return file; ++ } ++ ++ err = rst_get_object(CPT_OBJ_FILE, pos, &fi, ctx); ++ if (err < 0) ++ goto err_out; ++ ++ flags = make_flags(&fi); ++ ++ /* Easy way, inode has been already open. */ ++ if (fi.cpt_inode != CPT_NULL && ++ !(fi.cpt_lflags & CPT_DENTRY_CLONING) && ++ (iobj = lookup_cpt_obj_bypos(CPT_OBJ_INODE, fi.cpt_inode, ctx)) != NULL && ++ iobj->o_parent) { ++ struct file *filp = iobj->o_parent; ++ file = dentry_open(dget(filp->f_dentry), ++ mntget(filp->f_vfsmnt), flags); ++ dprintk_ctx("rst_file: file obtained by dentry_open\n"); ++ was_dentry_open = 1; ++ goto map_file; ++ } ++ ++ if (fi.cpt_next > fi.cpt_hdrlen) ++ name = rst_get_name(pos + sizeof(fi), ctx); ++ ++ if (!name) { ++ eprintk_ctx("no name for file?\n"); ++ err = -EINVAL; ++ goto err_out; ++ } ++ ++ if (fi.cpt_lflags & CPT_DENTRY_DELETED) { ++ struct cpt_inode_image ii; ++ if (fi.cpt_inode == CPT_NULL) { ++ eprintk_ctx("deleted file and no inode.\n"); ++ err = -EINVAL; ++ goto err_out; ++ } ++ ++ err = rst_get_object(CPT_OBJ_INODE, fi.cpt_inode, &ii, ctx); ++ if (err) ++ goto err_out; ++ ++ if (ii.cpt_next > ii.cpt_hdrlen) { ++ struct cpt_object_hdr hdr; ++ err = ctx->pread(&hdr, sizeof(hdr), ctx, ++ fi.cpt_inode + ii.cpt_hdrlen); ++ if (err) ++ goto err_out; ++ if (hdr.cpt_object == CPT_OBJ_NAME) { ++ rst_put_name(name, ctx); ++ name = rst_get_name(fi.cpt_inode+ii.cpt_hdrlen, ++ ctx); ++ if (!name) { ++ eprintk_ctx("no name for link?\n"); ++ err = -EINVAL; ++ goto err_out; ++ } ++ goto open_file; ++ } ++ } ++ ++ /* One very special case... */ ++ if (S_ISREG(fi.cpt_i_mode) && ++ (!name[0] || strcmp(name, "/dev/zero (deleted)") == 0)) { ++ /* MAP_ANON|MAP_SHARED mapping. ++ * kernel makes this damn ugly way, when file which ++ * is passed to mmap by user does not match ++ * file finally attached to VMA. Ok, rst_mm ++ * has to take care of this. Otherwise, it will fail. ++ */ ++ file = NULL; ++ } else if (S_ISREG(fi.cpt_i_mode) || ++ S_ISCHR(fi.cpt_i_mode) || ++ S_ISFIFO(fi.cpt_i_mode) || ++ S_ISDIR(fi.cpt_i_mode)) { ++ if (S_ISCHR(fi.cpt_i_mode)) { ++ file = open_special(&fi, flags, 1, ctx); ++ if (file != NULL) ++ goto map_file; ++ } ++ file = open_deleted(name, flags, &fi, &ii, ctx); ++ if (IS_ERR(file)) ++ goto out; ++ } else { ++ eprintk_ctx("not a regular deleted file.\n"); ++ err = -EINVAL; ++ goto err_out; ++ } ++ ++ err = fixup_file_content(&file, &fi, &ii, ctx); ++ if (err) ++ goto err_put; ++ goto map_file; ++ } else { ++open_file: ++ if (!name[0]) { ++ eprintk_ctx("empty name for file?\n"); ++ err = -EINVAL; ++ goto err_out; ++ } ++ if ((fi.cpt_lflags & CPT_DENTRY_EPOLL) && ++ (file = cpt_open_epolldev(&fi, flags, ctx)) != NULL) ++ goto map_file; ++#ifdef CONFIG_INOTIFY_USER ++ if ((fi.cpt_lflags & CPT_DENTRY_INOTIFY) && ++ (file = rst_open_inotify(&fi, flags, ctx)) != NULL) ++ goto map_file; ++#else ++ if (fi.cpt_lflags & CPT_DENTRY_INOTIFY) { ++ err = -EINVAL; ++ goto err_out; ++ } ++#endif ++ if (S_ISFIFO(fi.cpt_i_mode) && ++ (file = open_pipe(name, &fi, flags, ctx)) != NULL) ++ goto map_file; ++ if (!S_ISREG(fi.cpt_i_mode) && ++ (file = open_special(&fi, flags, 0, ctx)) != NULL) ++ goto map_file; ++ } ++ ++ file = filp_open(name, flags, 0); ++ ++map_file: ++ if (!IS_ERR(file)) { ++ fixup_file_flags(file, &fi, was_dentry_open, pos, ctx); ++ ++ if (S_ISFIFO(fi.cpt_i_mode) && !was_dentry_open) { ++ err = fixup_pipe_data(file, &fi, ctx); ++ if (err) ++ goto err_put; ++ } ++ ++ /* This is very special hack. Logically, cwd/root are ++ * nothing but open directories. Nevertheless, this causes ++ * failures of restores, when number of open files in VE ++ * is close to limit. So, if it is rst_file() of cwd/root ++ * (fd = -2) and the directory is not deleted, we skip ++ * adding files to object table. If the directory is ++ * not unlinked, this cannot cause any problems. ++ */ ++ if (fd != -2 || ++ !S_ISDIR(file->f_dentry->d_inode->i_mode) || ++ (fi.cpt_lflags & CPT_DENTRY_DELETED)) { ++ obj = cpt_object_get(CPT_OBJ_FILE, file, ctx); ++ if (!obj) { ++ obj = cpt_object_add(CPT_OBJ_FILE, file, ctx); ++ if (obj) ++ get_file(file); ++ } ++ if (obj) ++ cpt_obj_setpos(obj, pos, ctx); ++ ++ obj = cpt_object_add(CPT_OBJ_INODE, file->f_dentry->d_inode, ctx); ++ if (obj) { ++ cpt_obj_setpos(obj, fi.cpt_inode, ctx); ++ if (!obj->o_parent || !(fi.cpt_lflags & CPT_DENTRY_DELETED)) ++ obj->o_parent = file; ++ } ++ } ++ ++ if (fi.cpt_next > fi.cpt_hdrlen) { ++ err = fixup_flocks(file, &fi, pos, ctx); ++ if (err) ++ goto err_put; ++ } ++ } else { ++ if (fi.cpt_lflags & CPT_DENTRY_PROC) { ++ dprintk_ctx("rst_file /proc delayed\n"); ++ file = NULL; ++ } else if (name) ++ eprintk_ctx("can't open file %s\n", name); ++ } ++ ++out: ++ if (name) ++ rst_put_name(name, ctx); ++ return file; ++ ++err_put: ++ if (file) ++ fput(file); ++err_out: ++ if (name) ++ rst_put_name(name, ctx); ++ return ERR_PTR(err); ++} ++ ++ ++__u32 rst_files_flag(struct cpt_task_image *ti, struct cpt_context *ctx) ++{ ++ __u32 flag = 0; ++ ++ if (ti->cpt_files == CPT_NULL || ++ lookup_cpt_obj_bypos(CPT_OBJ_FILES, ti->cpt_files, ctx)) ++ flag |= CLONE_FILES; ++ if (ti->cpt_fs == CPT_NULL || ++ lookup_cpt_obj_bypos(CPT_OBJ_FS, ti->cpt_fs, ctx)) ++ flag |= CLONE_FS; ++ return flag; ++} ++ ++static void local_close_files(struct files_struct * files) ++{ ++ int i, j; ++ ++ j = 0; ++ for (;;) { ++ unsigned long set; ++ i = j * __NFDBITS; ++ if (i >= files->fdt->max_fds) ++ break; ++ set = files->fdt->open_fds->fds_bits[j]; ++ while (set) { ++ if (set & 1) { ++ struct file * file = xchg(&files->fdt->fd[i], NULL); ++ if (file) ++ filp_close(file, files); ++ } ++ i++; ++ set >>= 1; ++ } ++ files->fdt->open_fds->fds_bits[j] = 0; ++ files->fdt->close_on_exec->fds_bits[j] = 0; ++ j++; ++ } ++} ++ ++extern int expand_fdtable(struct files_struct *files, int nr); ++ ++ ++int rst_files_complete(struct cpt_task_image *ti, struct cpt_context *ctx) ++{ ++ struct cpt_files_struct_image fi; ++ struct files_struct *f = current->files; ++ cpt_object_t *obj; ++ loff_t pos, endpos; ++ int err; ++ ++ if (ti->cpt_files == CPT_NULL) { ++ current->files = NULL; ++ if (f) ++ put_files_struct(f); ++ return 0; ++ } ++ ++ obj = lookup_cpt_obj_bypos(CPT_OBJ_FILES, ti->cpt_files, ctx); ++ if (obj) { ++ if (obj->o_obj != f) { ++ put_files_struct(f); ++ f = obj->o_obj; ++ atomic_inc(&f->count); ++ current->files = f; ++ } ++ return 0; ++ } ++ ++ err = rst_get_object(CPT_OBJ_FILES, ti->cpt_files, &fi, ctx); ++ if (err) ++ return err; ++ ++ local_close_files(f); ++ ++ if (fi.cpt_max_fds > f->fdt->max_fds) { ++ spin_lock(&f->file_lock); ++ err = expand_fdtable(f, fi.cpt_max_fds-1); ++ spin_unlock(&f->file_lock); ++ if (err < 0) ++ return err; ++ } ++ ++ pos = ti->cpt_files + fi.cpt_hdrlen; ++ endpos = ti->cpt_files + fi.cpt_next; ++ while (pos < endpos) { ++ struct cpt_fd_image fdi; ++ struct file *filp; ++ ++ err = rst_get_object(CPT_OBJ_FILEDESC, pos, &fdi, ctx); ++ if (err) ++ return err; ++ filp = rst_file(fdi.cpt_file, fdi.cpt_fd, ctx); ++ if (IS_ERR(filp)) { ++ eprintk_ctx("rst_file: %ld %Lu\n", PTR_ERR(filp), ++ (long long)fdi.cpt_file); ++ return PTR_ERR(filp); ++ } ++ if (filp == NULL) { ++ int err = rst_filejob_queue(pos, ctx); ++ if (err) ++ return err; ++ } else { ++ if (fdi.cpt_fd >= f->fdt->max_fds) BUG(); ++ f->fdt->fd[fdi.cpt_fd] = filp; ++ FD_SET(fdi.cpt_fd, f->fdt->open_fds); ++ if (fdi.cpt_flags&CPT_FD_FLAG_CLOSEEXEC) ++ FD_SET(fdi.cpt_fd, f->fdt->close_on_exec); ++ } ++ pos += fdi.cpt_next; ++ } ++ f->next_fd = fi.cpt_next_fd; ++ ++ obj = cpt_object_add(CPT_OBJ_FILES, f, ctx); ++ if (obj) { ++ cpt_obj_setpos(obj, ti->cpt_files, ctx); ++ cpt_obj_setindex(obj, fi.cpt_index, ctx); ++ } ++ return 0; ++} ++ ++int rst_do_filejobs(cpt_context_t *ctx) ++{ ++ struct filejob *j; ++ ++ while ((j = ctx->filejob_queue) != NULL) { ++ int err; ++ struct task_struct *tsk; ++ struct cpt_fd_image fdi; ++ struct file *filp; ++ ++ read_lock(&tasklist_lock); ++ tsk = find_task_by_vpid(j->pid); ++ if (tsk) ++ get_task_struct(tsk); ++ read_unlock(&tasklist_lock); ++ if (!tsk) ++ return -EINVAL; ++ ++ err = rst_get_object(CPT_OBJ_FILEDESC, j->fdi, &fdi, ctx); ++ if (err) { ++ put_task_struct(tsk); ++ return err; ++ } ++ ++ if (fdi.cpt_fd >= tsk->files->fdt->max_fds) BUG(); ++ if (tsk->files->fdt->fd[fdi.cpt_fd] || ++ FD_ISSET(fdi.cpt_fd, tsk->files->fdt->open_fds)) { ++ eprintk_ctx("doing filejob %Ld: fd is busy\n", j->fdi); ++ put_task_struct(tsk); ++ return -EBUSY; ++ } ++ ++ filp = rst_file(fdi.cpt_file, fdi.cpt_fd, ctx); ++ if (IS_ERR(filp)) { ++ eprintk_ctx("rst_do_filejobs: 1: %ld %Lu\n", PTR_ERR(filp), (unsigned long long)fdi.cpt_file); ++ put_task_struct(tsk); ++ return PTR_ERR(filp); ++ } ++ if (fdi.cpt_fd >= tsk->files->fdt->max_fds) BUG(); ++ tsk->files->fdt->fd[fdi.cpt_fd] = filp; ++ FD_SET(fdi.cpt_fd, tsk->files->fdt->open_fds); ++ if (fdi.cpt_flags&CPT_FD_FLAG_CLOSEEXEC) ++ FD_SET(fdi.cpt_fd, tsk->files->fdt->close_on_exec); ++ ++ dprintk_ctx("filejob %Ld done\n", j->fdi); ++ ++ put_task_struct(tsk); ++ ctx->filejob_queue = j->next; ++ kfree(j); ++ } ++ return 0; ++} ++ ++void rst_flush_filejobs(cpt_context_t *ctx) ++{ ++ struct filejob *j; ++ ++ while ((j = ctx->filejob_queue) != NULL) { ++ ctx->filejob_queue = j->next; ++ kfree(j); ++ } ++} ++ ++int rst_fs_complete(struct cpt_task_image *ti, struct cpt_context *ctx) ++{ ++ struct fs_struct *f = current->fs; ++ cpt_object_t *obj; ++ ++ if (ti->cpt_fs == CPT_NULL) { ++ exit_fs(current); ++ return 0; ++ } ++ ++ obj = lookup_cpt_obj_bypos(CPT_OBJ_FS, ti->cpt_fs, ctx); ++ if (obj) { ++ if (obj->o_obj != f) { ++ exit_fs(current); ++ f = obj->o_obj; ++ atomic_inc(&f->count); ++ current->fs = f; ++ } ++ return 0; ++ } ++ ++ /* Do _not_ restore root. Image contains absolute pathnames. ++ * So, we fix it in context of rst process. ++ */ ++ ++ obj = cpt_object_add(CPT_OBJ_FS, f, ctx); ++ if (obj) ++ cpt_obj_setpos(obj, ti->cpt_fs, ctx); ++ ++ return 0; ++} ++ ++int cpt_get_dentry(struct dentry **dp, struct vfsmount **mp, ++ loff_t *pos, struct cpt_context *ctx) ++{ ++ struct cpt_file_image fi; ++ struct file * file; ++ int err; ++ ++ err = rst_get_object(CPT_OBJ_FILE, *pos, &fi, ctx); ++ if (err) ++ return err; ++ ++ file = rst_file(*pos, -2, ctx); ++ if (IS_ERR(file)) ++ return PTR_ERR(file); ++ ++ *dp = dget(file->f_dentry); ++ *mp = mntget(file->f_vfsmnt); ++ *pos += fi.cpt_next; ++ fput(file); ++ return 0; ++} ++ ++static void __set_fs_root(struct fs_struct *fs, struct vfsmount *mnt, ++ struct dentry *dentry) ++{ ++ struct dentry *old_root; ++ struct vfsmount *old_rootmnt; ++ write_lock(&fs->lock); ++ old_root = fs->root; ++ old_rootmnt = fs->rootmnt; ++ fs->rootmnt = mnt; ++ fs->root = dentry; ++ write_unlock(&fs->lock); ++ if (old_root) { ++ dput(old_root); ++ mntput(old_rootmnt); ++ } ++} ++ ++static void __set_fs_pwd(struct fs_struct *fs, struct vfsmount *mnt, ++ struct dentry *dentry) ++{ ++ struct dentry *old_pwd; ++ struct vfsmount *old_pwdmnt; ++ ++ write_lock(&fs->lock); ++ old_pwd = fs->pwd; ++ old_pwdmnt = fs->pwdmnt; ++ fs->pwdmnt = mnt; ++ fs->pwd = dentry; ++ write_unlock(&fs->lock); ++ ++ if (old_pwd) { ++ dput(old_pwd); ++ mntput(old_pwdmnt); ++ } ++} ++ ++ ++int rst_restore_fs(struct cpt_context *ctx) ++{ ++ loff_t pos; ++ cpt_object_t *obj; ++ int err = 0; ++ ++ for_each_object(obj, CPT_OBJ_FS) { ++ struct cpt_fs_struct_image fi; ++ struct fs_struct *fs = obj->o_obj; ++ int i; ++ struct dentry *d[3]; ++ struct vfsmount *m[3]; ++ ++ err = rst_get_object(CPT_OBJ_FS, obj->o_pos, &fi, ctx); ++ if (err) ++ return err; ++ ++ fs->umask = fi.cpt_umask; ++ ++ pos = obj->o_pos + fi.cpt_hdrlen; ++ d[0] = d[1] = d[2] = NULL; ++ m[0] = m[1] = m[2] = NULL; ++ i = 0; ++ while (pos < obj->o_pos + fi.cpt_next && i<3) { ++ err = cpt_get_dentry(d+i, m+i, &pos, ctx); ++ if (err) { ++ eprintk_ctx("cannot get_dir: %d", err); ++ for (--i; i >= 0; i--) { ++ if (d[i]) ++ dput(d[i]); ++ if (m[i]) ++ mntput(m[i]); ++ } ++ return err; ++ } ++ i++; ++ } ++ if (d[0]) ++ __set_fs_root(fs, m[0], d[0]); ++ if (d[1]) ++ __set_fs_pwd(fs, m[1], d[1]); ++ if (d[2]) { ++ struct dentry *olddentry; ++ struct vfsmount *oldmnt; ++ write_lock(&fs->lock); ++ oldmnt = fs->altrootmnt; ++ olddentry = fs->altroot; ++ fs->altrootmnt = m[2]; ++ fs->altroot = d[2]; ++ write_unlock(&fs->lock); ++ ++ if (olddentry) { ++ dput(olddentry); ++ mntput(oldmnt); ++ } ++ } ++ } ++ return err; ++} ++ ++int do_one_mount(char *mntpnt, char *mnttype, char *mntbind, ++ unsigned long flags, unsigned long mnt_flags, ++ struct cpt_context *ctx) ++{ ++ int err; ++ ++ if (mntbind && (strcmp(mntbind, "/") == 0 || strcmp(mntbind, "") == 0)) ++ mntbind = NULL; ++ ++ if (mntbind) ++ flags |= MS_BIND; ++ /* Join per-mountpoint flags with global flags */ ++ if (mnt_flags & MNT_NOSUID) ++ flags |= MS_NOSUID; ++ if (mnt_flags & MNT_NODEV) ++ flags |= MS_NODEV; ++ if (mnt_flags & MNT_NOEXEC) ++ flags |= MS_NOEXEC; ++ ++ err = sc_mount(mntbind, mntpnt, mnttype, flags); ++ if (err < 0) { ++ eprintk_ctx("%d mounting %s %s %08lx\n", err, mntpnt, mnttype, flags); ++ return err; ++ } ++ return 0; ++} ++ ++static int undumptmpfs(void *arg) ++{ ++ int i; ++ int *pfd = arg; ++ int fd1, fd2, err; ++ char *argv[] = { "tar", "x", "-C", "/", "-S", NULL }; ++ ++ if (pfd[0] != 0) ++ sc_dup2(pfd[0], 0); ++ ++ set_fs(KERNEL_DS); ++ fd1 = sc_open("/dev/null", O_WRONLY, 0); ++ fd2 = sc_open("/dev/null", O_WRONLY, 0); ++try: ++ if (fd1 < 0 || fd2 < 0) { ++ if (fd1 == -ENOENT && fd2 == -ENOENT) { ++ err = sc_mknod("/dev/null", S_IFCHR|0666, ++ new_encode_dev((MEM_MAJOR<files->fdt->max_fds; i++) ++ sc_close(i); ++ ++ module_put(THIS_MODULE); ++ ++ i = sc_execve("/bin/tar", argv, NULL); ++ eprintk("failed to exec /bin/tar: %d\n", i); ++ return 255 << 8; ++} ++ ++static int rst_restore_tmpfs(loff_t *pos, struct cpt_context * ctx) ++{ ++ int err; ++ int pfd[2]; ++ struct file *f; ++ struct cpt_object_hdr v; ++ int n; ++ loff_t end; ++ int pid; ++ int status; ++ mm_segment_t oldfs; ++ sigset_t ignore, blocked; ++ ++ err = rst_get_object(CPT_OBJ_NAME, *pos, &v, ctx); ++ if (err < 0) ++ return err; ++ ++ err = sc_pipe(pfd); ++ if (err < 0) ++ return err; ++ ignore.sig[0] = CPT_SIG_IGNORE_MASK; ++ sigprocmask(SIG_BLOCK, &ignore, &blocked); ++ pid = err = local_kernel_thread(undumptmpfs, (void*)pfd, SIGCHLD, 0); ++ if (err < 0) { ++ eprintk_ctx("tmpfs local_kernel_thread: %d\n", err); ++ goto out; ++ } ++ f = fget(pfd[1]); ++ sc_close(pfd[1]); ++ sc_close(pfd[0]); ++ ++ ctx->file->f_pos = *pos + v.cpt_hdrlen; ++ end = *pos + v.cpt_next; ++ *pos += v.cpt_next; ++ do { ++ char buf[16]; ++ ++ n = end - ctx->file->f_pos; ++ if (n > sizeof(buf)) ++ n = sizeof(buf); ++ ++ if (ctx->read(buf, n, ctx)) ++ break; ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ f->f_op->write(f, buf, n, &f->f_pos); ++ set_fs(oldfs); ++ } while (ctx->file->f_pos < end); ++ ++ fput(f); ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ if ((err = sc_waitx(pid, 0, &status)) < 0) ++ eprintk_ctx("wait4: %d\n", err); ++ else if ((status & 0x7f) == 0) { ++ err = (status & 0xff00) >> 8; ++ if (err != 0) { ++ eprintk_ctx("tar exited with %d\n", err); ++ err = -EINVAL; ++ } ++ } else { ++ eprintk_ctx("tar terminated\n"); ++ err = -EINVAL; ++ } ++ set_fs(oldfs); ++ sigprocmask(SIG_SETMASK, &blocked, NULL); ++ ++ return err; ++ ++out: ++ if (pfd[1] >= 0) ++ sc_close(pfd[1]); ++ if (pfd[0] >= 0) ++ sc_close(pfd[0]); ++ sigprocmask(SIG_SETMASK, &blocked, NULL); ++ return err; ++} ++ ++int check_ext_mount(char *mntpnt, char *mnttype, struct cpt_context *ctx) ++{ ++ struct mnt_namespace *n; ++ struct list_head *p; ++ struct vfsmount *t; ++ char *path, *path_buf; ++ int ret; ++ ++ n = current->nsproxy->mnt_ns; ++ ret = -ENOENT; ++ path_buf = cpt_get_buf(ctx); ++ down_read(&namespace_sem); ++ list_for_each(p, &n->list) { ++ t = list_entry(p, struct vfsmount, mnt_list); ++ path = d_path(t->mnt_root, t, path_buf, PAGE_SIZE); ++ if (IS_ERR(path)) ++ continue; ++ if (!strcmp(path, mntpnt) && ++ !strcmp(t->mnt_sb->s_type->name, mnttype)) { ++ ret = 0; ++ break; ++ } ++ } ++ up_read(&namespace_sem); ++ __cpt_release_buf(ctx); ++ return ret; ++} ++ ++int restore_one_vfsmount(struct cpt_vfsmount_image *mi, loff_t pos, struct cpt_context *ctx) ++{ ++ int err; ++ loff_t endpos; ++ ++ endpos = pos + mi->cpt_next; ++ pos += mi->cpt_hdrlen; ++ ++ while (pos < endpos) { ++ char *mntdev; ++ char *mntpnt; ++ char *mnttype; ++ char *mntbind; ++ ++ mntdev = __rst_get_name(&pos, ctx); ++ mntpnt = __rst_get_name(&pos, ctx); ++ mnttype = __rst_get_name(&pos, ctx); ++ mntbind = NULL; ++ if (mi->cpt_mntflags & CPT_MNT_BIND) ++ mntbind = __rst_get_name(&pos, ctx); ++ err = -EINVAL; ++ if (mnttype && mntpnt) { ++ err = 0; ++ if (!(mi->cpt_mntflags & CPT_MNT_EXT) && ++ strcmp(mntpnt, "/")) { ++ err = do_one_mount(mntpnt, mnttype, mntbind, ++ mi->cpt_flags, ++ mi->cpt_mntflags, ctx); ++ if (!err && ++ strcmp(mnttype, "tmpfs") == 0 && ++ !(mi->cpt_mntflags & (CPT_MNT_BIND))) ++ err = rst_restore_tmpfs(&pos, ctx); ++ } else if (mi->cpt_mntflags & CPT_MNT_EXT) { ++ err = check_ext_mount(mntpnt, mnttype, ctx); ++ if (err) ++ eprintk_ctx("mount point is missing: %s\n", mntpnt); ++ } ++ } ++ if (mntdev) ++ rst_put_name(mntdev, ctx); ++ if (mntpnt) ++ rst_put_name(mntpnt, ctx); ++ if (mnttype) ++ rst_put_name(mnttype, ctx); ++ if (mntbind) ++ rst_put_name(mntbind, ctx); ++ if (err) ++ return err; ++ } ++ return 0; ++} ++ ++int restore_one_namespace(loff_t pos, loff_t endpos, struct cpt_context *ctx) ++{ ++ int err; ++ struct cpt_vfsmount_image mi; ++ ++ while (pos < endpos) { ++ err = rst_get_object(CPT_OBJ_VFSMOUNT, pos, &mi, ctx); ++ if (err) ++ return err; ++ err = restore_one_vfsmount(&mi, pos, ctx); ++ if (err) ++ return err; ++ pos += mi.cpt_next; ++ } ++ return 0; ++} ++ ++int rst_root_namespace(struct cpt_context *ctx) ++{ ++ int err; ++ loff_t sec = ctx->sections[CPT_SECT_NAMESPACE]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ struct cpt_object_hdr sbuf; ++ int done = 0; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_NAMESPACE || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ err = rst_get_object(CPT_OBJ_NAMESPACE, sec, &sbuf, ctx); ++ if (err) ++ return err; ++ if (done) { ++ eprintk_ctx("multiple namespaces are not supported\n"); ++ break; ++ } ++ done++; ++ err = restore_one_namespace(sec+sbuf.cpt_hdrlen, sec+sbuf.cpt_next, ctx); ++ if (err) ++ return err; ++ sec += sbuf.cpt_next; ++ } ++ ++ return 0; ++} ++ ++int rst_stray_files(struct cpt_context *ctx) ++{ ++ int err = 0; ++ loff_t sec = ctx->sections[CPT_SECT_FILES]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_FILES || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ struct cpt_object_hdr sbuf; ++ cpt_object_t *obj; ++ ++ err = _rst_get_object(CPT_OBJ_FILE, sec, &sbuf, sizeof(sbuf), ctx); ++ if (err) ++ break; ++ ++ obj = lookup_cpt_obj_bypos(CPT_OBJ_FILE, sec, ctx); ++ if (!obj) { ++ struct file *file; ++ ++ dprintk_ctx("stray file %Ld\n", sec); ++ ++ file = rst_sysv_shm(sec, ctx); ++ ++ if (IS_ERR(file)) { ++ eprintk_ctx("rst_stray_files: %ld\n", PTR_ERR(file)); ++ return PTR_ERR(file); ++ } else { ++ fput(file); ++ } ++ } ++ sec += sbuf.cpt_next; ++ } ++ ++ return err; ++} +Index: kernel/kernel/cpt/rst_inotify.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_inotify.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,198 @@ ++/* ++ * ++ * kernel/cpt/rst_inotify.c ++ * ++ * Copyright (C) 2000-2007 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_mm.h" ++#include "cpt_files.h" ++#include "cpt_kernel.h" ++#include "cpt_fsmagic.h" ++#include "cpt_syscalls.h" ++ ++extern struct file_operations inotify_fops; ++ ++struct file *rst_open_inotify(struct cpt_file_image *fi, ++ unsigned flags, ++ struct cpt_context *ctx) ++{ ++ struct file *file; ++ int fd; ++ ++ fd = sys_inotify_init(); ++ if (fd < 0) ++ return ERR_PTR(fd); ++ ++ file = fget(fd); ++ sys_close(fd); ++ return file; ++} ++ ++static int restore_one_inotify(cpt_object_t *obj, ++ loff_t pos, ++ struct cpt_inotify_image *ibuf, ++ cpt_context_t *ctx) ++{ ++ int err = 0; ++ loff_t endpos; ++ struct file *file = obj->o_obj; ++ struct inotify_device *dev; ++ ++ if (file->f_op != &inotify_fops) { ++ eprintk_ctx("bad inotify file\n"); ++ return -EINVAL; ++ } ++ ++ dev = file->private_data; ++ ++ if (unlikely(dev == NULL)) { ++ eprintk_ctx("bad inotify device\n"); ++ return -EINVAL; ++ } ++ ++ endpos = pos + ibuf->cpt_next; ++ pos += ibuf->cpt_hdrlen; ++ while (pos < endpos) { ++ union { ++ struct cpt_inotify_wd_image wi; ++ struct cpt_inotify_ev_image ei; ++ } u; ++ ++ err = rst_get_object(-1, pos, &u, ctx); ++ if (err) { ++ eprintk_ctx("rst_get_object: %d\n", err); ++ return err; ++ } ++ if (u.wi.cpt_object == CPT_OBJ_INOTIFY_WATCH) { ++ struct dentry *d; ++ struct vfsmount *mnt; ++ loff_t fpos = pos + u.wi.cpt_hdrlen; ++ ++ err = cpt_get_dentry(&d, &mnt, &fpos, ctx); ++ if (err) { ++ eprintk_ctx("cpt_get_dentry: %d\n", err); ++ return err; ++ } ++ ++ mutex_lock(&dev->up_mutex); ++ dev->ih->last_wd = u.wi.cpt_wd - 1; ++ err = inotify_create_watch(dev, d, mnt, u.wi.cpt_mask); ++ dev->ih->last_wd = ibuf->cpt_last_wd; ++ if (err != u.wi.cpt_wd) { ++ eprintk_ctx("wrong inotify descriptor %u %u\n", err, u.wi.cpt_wd); ++ if (err >= 0) ++ err = -EINVAL; ++ } else ++ err = 0; ++ mutex_unlock(&dev->up_mutex); ++ dput(d); ++ mntput(mnt); ++ if (err) ++ break; ++ } else if (u.wi.cpt_object == CPT_OBJ_INOTIFY_EVENT) { ++ struct inotify_user_watch dummy_watch; ++ struct inotify_watch *w; ++ char *name = NULL; ++ ++ if (u.ei.cpt_namelen) { ++ name = kmalloc(u.ei.cpt_namelen+1, GFP_KERNEL); ++ if (name == NULL) { ++ err = -ENOMEM; ++ break; ++ } ++ name[u.ei.cpt_namelen] = 0; ++ err = ctx->pread(name, u.ei.cpt_namelen, ctx, pos + u.ei.cpt_hdrlen); ++ if (err) { ++ kfree(name); ++ break; ++ } ++ } ++ ++ w = &dummy_watch.wdata; ++ dummy_watch.dev = dev; ++ atomic_set(&w->count, 2); ++ ++ /* Trick to avoid destruction due to exit event */ ++ if (u.ei.cpt_mask & (IN_IGNORED | IN_ONESHOT)) ++ atomic_inc(&w->count); ++ dev->ih->in_ops->handle_event(w, u.ei.cpt_wd, u.ei.cpt_mask, ++ u.ei.cpt_cookie, name, NULL); ++ if (name) ++ kfree(name); ++ } else { ++ eprintk_ctx("bad object: %u\n", u.wi.cpt_object); ++ err = -EINVAL; ++ break; ++ } ++ pos += u.wi.cpt_next; ++ } ++ return err; ++} ++ ++int rst_inotify(cpt_context_t *ctx) ++{ ++ int err; ++ loff_t sec = ctx->sections[CPT_SECT_INOTIFY]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_INOTIFY || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ cpt_object_t *obj; ++ struct cpt_inotify_image ibuf; ++ ++ err = rst_get_object(CPT_OBJ_INOTIFY, sec, &ibuf, ctx); ++ if (err) ++ return err; ++ obj = lookup_cpt_obj_bypos(CPT_OBJ_FILE, ibuf.cpt_file, ctx); ++ if (obj == NULL) { ++ eprintk_ctx("cannot find inotify file object\n"); ++ return -EINVAL; ++ } ++ err = restore_one_inotify(obj, sec, &ibuf, ctx); ++ if (err) ++ return err; ++ sec += ibuf.cpt_next; ++ } ++ ++ return 0; ++ ++} +Index: kernel/kernel/cpt/rst_mm.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_mm.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,1144 @@ ++/* ++ * ++ * kernel/cpt/rst_mm.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_X86 ++#include ++#include ++#endif ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_VE ++#include ++#include ++#endif ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_files.h" ++#include "cpt_ubc.h" ++#include "cpt_mm.h" ++#include "cpt_kernel.h" ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++#include "cpt_pagein.h" ++#endif ++ ++#include "cpt_syscalls.h" ++ ++#define __PAGE_NX (1ULL<<63) ++ ++static unsigned long make_prot(struct cpt_vma_image *vmai) ++{ ++ unsigned long prot = 0; ++ ++ if (vmai->cpt_flags&VM_READ) ++ prot |= PROT_READ; ++ if (vmai->cpt_flags&VM_WRITE) ++ prot |= PROT_WRITE; ++ if (vmai->cpt_flags&VM_EXEC) ++ prot |= PROT_EXEC; ++ if (vmai->cpt_flags&VM_GROWSDOWN) ++ prot |= PROT_GROWSDOWN; ++ if (vmai->cpt_flags&VM_GROWSUP) ++ prot |= PROT_GROWSUP; ++ return prot; ++} ++ ++static unsigned long make_flags(struct cpt_vma_image *vmai) ++{ ++ unsigned long flags = MAP_FIXED; ++ ++ if (vmai->cpt_flags&(VM_SHARED|VM_MAYSHARE)) ++ flags |= MAP_SHARED; ++ else ++ flags |= MAP_PRIVATE; ++ ++ if (vmai->cpt_file == CPT_NULL) ++ flags |= MAP_ANONYMOUS; ++ if (vmai->cpt_flags&VM_GROWSDOWN) ++ flags |= MAP_GROWSDOWN; ++#ifdef MAP_GROWSUP ++ if (vmai->cpt_flags&VM_GROWSUP) ++ flags |= MAP_GROWSUP; ++#endif ++ if (vmai->cpt_flags&VM_DENYWRITE) ++ flags |= MAP_DENYWRITE; ++ if (vmai->cpt_flags&VM_EXECUTABLE) ++ flags |= MAP_EXECUTABLE; ++ if (!(vmai->cpt_flags&VM_ACCOUNT)) ++ flags |= MAP_NORESERVE; ++ return flags; ++} ++ ++#ifdef CONFIG_X86 ++#if !defined(CONFIG_X86_64) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) \ ++ && !defined(CONFIG_XEN) ++static int __alloc_ldt(mm_context_t *pc, int mincount) ++{ ++ int oldsize, newsize, nr; ++ ++ if (mincount <= pc->size) ++ return 0; ++ /* ++ * LDT got larger - reallocate if necessary. ++ */ ++ oldsize = pc->size; ++ mincount = (mincount+511)&(~511); ++ newsize = mincount*LDT_ENTRY_SIZE; ++ for (nr = 0; nr * PAGE_SIZE < newsize; nr++) { ++ BUG_ON(nr * PAGE_SIZE >= 64*1024); ++ if (!pc->ldt_pages[nr]) { ++ pc->ldt_pages[nr] = alloc_page(GFP_HIGHUSER|__GFP_UBC); ++ if (!pc->ldt_pages[nr]) ++ goto nomem; ++ clear_highpage(pc->ldt_pages[nr]); ++ } ++ } ++ pc->size = mincount; ++ return 0; ++ ++nomem: ++ while (--nr >= 0) ++ __free_page(pc->ldt_pages[nr]); ++ pc->size = 0; ++ return -ENOMEM; ++} ++ ++static int do_rst_ldt(struct cpt_obj_bits *li, loff_t pos, struct cpt_context *ctx) ++{ ++ struct mm_struct *mm = current->mm; ++ int i; ++ int err; ++ int size; ++ ++ err = __alloc_ldt(&mm->context, li->cpt_size/LDT_ENTRY_SIZE); ++ if (err) ++ return err; ++ ++ size = mm->context.size*LDT_ENTRY_SIZE; ++ ++ for (i = 0; i < size; i += PAGE_SIZE) { ++ int nr = i / PAGE_SIZE, bytes; ++ char *kaddr = kmap(mm->context.ldt_pages[nr]); ++ ++ bytes = size - i; ++ if (bytes > PAGE_SIZE) ++ bytes = PAGE_SIZE; ++ err = ctx->pread(kaddr, bytes, ctx, pos + li->cpt_hdrlen + i); ++ kunmap(mm->context.ldt_pages[nr]); ++ if (err) ++ return err; ++ } ++ ++ load_LDT(&mm->context); ++ return 0; ++} ++ ++#else ++ ++static int do_rst_ldt(struct cpt_obj_bits *li, loff_t pos, struct cpt_context *ctx) ++{ ++ struct mm_struct *mm = current->mm; ++ int oldsize = mm->context.size; ++ void *oldldt; ++ void *newldt; ++ int err; ++ ++ if (li->cpt_size > PAGE_SIZE) ++ newldt = vmalloc(li->cpt_size); ++ else ++ newldt = kmalloc(li->cpt_size, GFP_KERNEL); ++ ++ if (!newldt) ++ return -ENOMEM; ++ ++ err = ctx->pread(newldt, li->cpt_size, ctx, pos + li->cpt_hdrlen); ++ if (err) ++ return err; ++ ++ oldldt = mm->context.ldt; ++ mm->context.ldt = newldt; ++ mm->context.size = li->cpt_size/LDT_ENTRY_SIZE; ++ ++ load_LDT(&mm->context); ++ ++ if (oldsize) { ++ if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE) ++ vfree(oldldt); ++ else ++ kfree(oldldt); ++ } ++ return 0; ++} ++#endif ++#endif ++ ++static int ++restore_aio_ring(struct kioctx *aio_ctx, struct cpt_aio_ctx_image *aimg) ++{ ++ struct aio_ring_info *info = &aio_ctx->ring_info; ++ unsigned nr_events = aio_ctx->max_reqs; ++ unsigned long size; ++ int nr_pages; ++ ++ /* We recalculate parameters of the ring exactly like ++ * fs/aio.c does and then compare calculated values ++ * with ones, stored in dump. They must be the same. */ ++ ++ nr_events += 2; ++ ++ size = sizeof(struct aio_ring); ++ size += sizeof(struct io_event) * nr_events; ++ nr_pages = (size + PAGE_SIZE-1) >> PAGE_SHIFT; ++ ++ if (nr_pages != aimg->cpt_ring_pages) ++ return -EINVAL; ++ ++ info->nr_pages = nr_pages; ++ ++ nr_events = (PAGE_SIZE * nr_pages - sizeof(struct aio_ring)) / sizeof(struct io_event); ++ ++ if (nr_events != aimg->cpt_nr) ++ return -EINVAL; ++ ++ info->nr = 0; ++ info->ring_pages = info->internal_pages; ++ if (nr_pages > AIO_RING_PAGES) { ++ info->ring_pages = kmalloc(sizeof(struct page *) * nr_pages, GFP_KERNEL); ++ if (!info->ring_pages) ++ return -ENOMEM; ++ memset(info->ring_pages, 0, sizeof(struct page *) * nr_pages); ++ } ++ ++ info->mmap_size = nr_pages * PAGE_SIZE; ++ ++ /* This piece of shit is not entirely my fault. Kernel aio.c makes ++ * something odd mmap()ping some pages and then pinning them. ++ * I guess it is just some mud remained of failed attempt to show ring ++ * to user space. The result is odd. :-) Immediately after ++ * creation of AIO context, kernel shares those pages with user ++ * and user can read and even write there. But after the first ++ * fork, pages are marked COW with evident consequences. ++ * I remember, I did the same mistake in the first version ++ * of mmapped packet socket, luckily that crap never reached ++ * mainstream. ++ * ++ * So, what are we going to do? I can simulate this odd behaviour ++ * exactly, but I am not insane yet. For now just take the pages ++ * from user space. Alternatively, we could keep kernel copy ++ * in AIO context image, which would be more correct. ++ * ++ * What is wrong now? If the pages are COWed, ring is transferred ++ * incorrectly. ++ */ ++ down_read(¤t->mm->mmap_sem); ++ info->mmap_base = aimg->cpt_mmap_base; ++ info->nr_pages = get_user_pages(current, current->mm, ++ info->mmap_base, nr_pages, ++ 1, 0, info->ring_pages, NULL); ++ up_read(¤t->mm->mmap_sem); ++ ++ if (unlikely(info->nr_pages != nr_pages)) { ++ int i; ++ ++ for (i=0; inr_pages; i++) ++ put_page(info->ring_pages[i]); ++ if (info->ring_pages && info->ring_pages != info->internal_pages) ++ kfree(info->ring_pages); ++ return -EFAULT; ++ } ++ ++ aio_ctx->user_id = info->mmap_base; ++ ++ info->nr = nr_events; ++ info->tail = aimg->cpt_tail; ++ ++ return 0; ++} ++ ++static int do_rst_aio(struct cpt_aio_ctx_image *aimg, loff_t pos, cpt_context_t *ctx) ++{ ++ int err; ++ struct kioctx *aio_ctx; ++ extern spinlock_t aio_nr_lock; ++ ++ aio_ctx = kmem_cache_alloc(kioctx_cachep, GFP_KERNEL); ++ if (!aio_ctx) ++ return -ENOMEM; ++ ++ memset(aio_ctx, 0, sizeof(*aio_ctx)); ++ aio_ctx->max_reqs = aimg->cpt_max_reqs; ++ ++ if ((err = restore_aio_ring(aio_ctx, aimg)) < 0) { ++ kmem_cache_free(kioctx_cachep, aio_ctx); ++ eprintk_ctx("AIO %Ld restore_aio_ring: %d\n", pos, err); ++ return err; ++ } ++ ++ aio_ctx->mm = current->mm; ++ atomic_inc(&aio_ctx->mm->mm_count); ++ atomic_set(&aio_ctx->users, 1); ++ spin_lock_init(&aio_ctx->ctx_lock); ++ spin_lock_init(&aio_ctx->ring_info.ring_lock); ++ init_waitqueue_head(&aio_ctx->wait); ++ INIT_LIST_HEAD(&aio_ctx->active_reqs); ++ INIT_LIST_HEAD(&aio_ctx->run_list); ++ INIT_WORK(&aio_ctx->wq.work, aio_kick_handler); ++ ++ spin_lock(&aio_nr_lock); ++ aio_nr += aio_ctx->max_reqs; ++ spin_unlock(&aio_nr_lock); ++ ++ write_lock(&aio_ctx->mm->ioctx_list_lock); ++ aio_ctx->next = aio_ctx->mm->ioctx_list; ++ aio_ctx->mm->ioctx_list = aio_ctx; ++ write_unlock(&aio_ctx->mm->ioctx_list_lock); ++ ++ return 0; ++} ++ ++struct anonvma_map ++{ ++ struct hlist_node list; ++ struct anon_vma *avma; ++ __u64 id; ++}; ++ ++static int verify_create_anonvma(struct mm_struct *mm, ++ struct cpt_vma_image *vmai, ++ cpt_context_t *ctx) ++{ ++ struct anon_vma *avma = NULL; ++ struct anon_vma *new_avma; ++ struct vm_area_struct *vma; ++ int h; ++ ++ if (!ctx->anonvmas) { ++ if (CPT_ANONVMA_HSIZE*sizeof(struct hlist_head) > PAGE_SIZE) ++ return -EINVAL; ++ if ((ctx->anonvmas = (void*)__get_free_page(GFP_KERNEL)) == NULL) ++ return -ENOMEM; ++ for (h = 0; h < CPT_ANONVMA_HSIZE; h++) ++ INIT_HLIST_HEAD(&ctx->anonvmas[h]); ++ } else { ++ struct anonvma_map *map; ++ struct hlist_node *elem; ++ ++ h = hash_long((unsigned long)vmai->cpt_anonvmaid, CPT_ANONVMA_HBITS); ++ hlist_for_each_entry(map, elem, &ctx->anonvmas[h], list) { ++ if (map->id == vmai->cpt_anonvmaid) { ++ avma = map->avma; ++ break; ++ } ++ } ++ } ++ ++ down_read(&mm->mmap_sem); ++ if ((vma = find_vma(mm, vmai->cpt_start)) == NULL) { ++ up_read(&mm->mmap_sem); ++ return -ESRCH; ++ } ++ if (vma->vm_start != vmai->cpt_start) { ++ up_read(&mm->mmap_sem); ++ eprintk_ctx("vma start mismatch\n"); ++ return -EINVAL; ++ } ++ if (vma->vm_pgoff != vmai->cpt_pgoff) { ++ dprintk_ctx("vma pgoff mismatch, fixing\n"); ++ if (vma->vm_file || (vma->vm_flags&(VM_SHARED|VM_MAYSHARE))) { ++ eprintk_ctx("cannot fixup vma pgoff\n"); ++ up_read(&mm->mmap_sem); ++ return -EINVAL; ++ } ++ vma->vm_pgoff = vmai->cpt_pgoff; ++ } ++ ++ if (!vma->anon_vma) { ++ if (avma) { ++ vma->anon_vma = avma; ++ anon_vma_link(vma); ++ } else { ++ int err; ++ ++ err = anon_vma_prepare(vma); ++ ++ if (err) { ++ up_read(&mm->mmap_sem); ++ return err; ++ } ++ } ++ } else { ++ /* Note, we _can_ arrive to the situation, when two ++ * different anonvmaid's point to one anon_vma, this happens ++ * f.e. when mmap() merged new area to previous one and ++ * they will share one anon_vma even if they did not on ++ * original host. ++ * ++ * IT IS OK. To all that I understand, we may merge all ++ * the anon_vma's and rmap can scan all the huge list of vmas ++ * searching for page. It is just "suboptimal". ++ * ++ * Real disaster would happen, if vma already got an anon_vma ++ * with different id. It is very rare case, kernel does the ++ * best efforts to merge anon_vmas when some attributes are ++ * different. In this case we will fall to copying memory. ++ */ ++ if (avma && vma->anon_vma != avma) { ++ up_read(&mm->mmap_sem); ++ wprintk_ctx("anon_vma mismatch\n"); ++ return 0; ++ } ++ } ++ ++ new_avma = vma->anon_vma; ++ up_read(&mm->mmap_sem); ++ ++ if (!avma) { ++ struct anonvma_map *map; ++ ++ if (!new_avma) ++ return -EINVAL; ++ ++ if ((map = kmalloc(sizeof(*map), GFP_KERNEL)) == NULL) ++ return -ENOMEM; ++ ++ map->id = vmai->cpt_anonvmaid; ++ map->avma = new_avma; ++ h = hash_long((unsigned long)vmai->cpt_anonvmaid, CPT_ANONVMA_HBITS); ++ hlist_add_head(&map->list, &ctx->anonvmas[h]); ++ } ++ return 0; ++} ++ ++static int copy_mm_pages(struct mm_struct *src, unsigned long start, ++ unsigned long end) ++{ ++ int err; ++ ++ for (; start < end; start += PAGE_SIZE) { ++ struct page *page; ++ struct page *spage; ++ void *maddr, *srcaddr; ++ ++ err = get_user_pages(current, current->mm, ++ start, 1, 1, 1, &page, NULL); ++ if (err == 0) ++ err = -EFAULT; ++ if (err < 0) ++ return err; ++ ++ err = get_user_pages(current, src, ++ start, 1, 0, 1, &spage, NULL); ++ ++ if (err == 0) ++ err = -EFAULT; ++ if (err < 0) { ++ page_cache_release(page); ++ return err; ++ } ++ ++ srcaddr = kmap(spage); ++ maddr = kmap(page); ++ memcpy(maddr, srcaddr, PAGE_SIZE); ++ set_page_dirty_lock(page); ++ kunmap(page); ++ kunmap(spage); ++ page_cache_release(page); ++ page_cache_release(spage); ++ } ++ return 0; ++} ++ ++static int do_rst_vma(struct cpt_vma_image *vmai, loff_t vmapos, loff_t mmpos, struct cpt_context *ctx) ++{ ++ int err = 0; ++ unsigned long addr; ++ struct mm_struct *mm = current->mm; ++ struct vm_area_struct *vma; ++ struct file *file = NULL; ++ unsigned long prot; ++ int checked = 0; ++ ++ if (vmai->cpt_type == CPT_VMA_VDSO) { ++ if (ctx->vdso == NULL) { ++#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES ++ err = arch_setup_additional_pages(NULL, 0, ++ vmai->cpt_start); ++#endif ++ goto out; ++ } ++ } ++ ++ prot = make_prot(vmai); ++ ++ if (vmai->cpt_file != CPT_NULL) { ++ if (vmai->cpt_type == CPT_VMA_TYPE_0) { ++ file = rst_file(vmai->cpt_file, -1, ctx); ++ if (IS_ERR(file)) { ++ eprintk_ctx("do_rst_vma: rst_file: %Ld\n", (unsigned long long)vmai->cpt_file); ++ return PTR_ERR(file); ++ } ++ } else if (vmai->cpt_type == CPT_VMA_TYPE_SHM) { ++ file = rst_sysv_shm(vmai->cpt_file, ctx); ++ if (IS_ERR(file)) ++ return PTR_ERR(file); ++ } ++ } ++ ++ down_write(&mm->mmap_sem); ++ addr = do_mmap_pgoff(file, vmai->cpt_start, ++ vmai->cpt_end-vmai->cpt_start, ++ prot, make_flags(vmai), ++ vmai->cpt_pgoff); ++ ++ if (addr != vmai->cpt_start) { ++ up_write(&mm->mmap_sem); ++ ++ err = -EINVAL; ++ if (IS_ERR((void*)addr)) ++ err = addr; ++ goto out; ++ } ++ ++ vma = find_vma(mm, vmai->cpt_start); ++ if (vma == NULL) { ++ up_write(&mm->mmap_sem); ++ eprintk_ctx("cannot find mmapped vma\n"); ++ err = -ESRCH; ++ goto out; ++ } ++ ++ /* do_mmap_pgoff() can merge new area to previous one (not to the next, ++ * we mmap in order, the rest of mm is still unmapped). This can happen ++ * f.e. if flags are to be adjusted later, or if we had different ++ * anon_vma on two adjacent regions. Split it by brute force. */ ++ if (vma->vm_start != vmai->cpt_start) { ++ dprintk_ctx("vma %Ld merged, split\n", vmapos); ++ err = split_vma(mm, vma, (unsigned long)vmai->cpt_start, 0); ++ if (err) { ++ up_write(&mm->mmap_sem); ++ eprintk_ctx("cannot split vma\n"); ++ goto out; ++ } ++ } ++ up_write(&mm->mmap_sem); ++ ++ if (vmai->cpt_anonvma && vmai->cpt_anonvmaid) { ++ err = verify_create_anonvma(mm, vmai, ctx); ++ if (err) { ++ eprintk_ctx("cannot verify_create_anonvma %Ld\n", vmapos); ++ goto out; ++ } ++ } ++ ++ if (vmai->cpt_type == CPT_VMA_VDSO) { ++ struct page *page; ++ void *maddr; ++ ++ err = get_user_pages(current, current->mm, ++ (unsigned long)vmai->cpt_start, ++ 1, 1, 1, &page, NULL); ++ if (err == 0) ++ err = -EFAULT; ++ if (err < 0) { ++ eprintk_ctx("can't get vdso: get_user_pages: %d\n", err); ++ goto out; ++ } ++ err = 0; ++ maddr = kmap(page); ++ memcpy(maddr, ctx->vdso, PAGE_SIZE); ++ set_page_dirty_lock(page); ++ kunmap(page); ++ page_cache_release(page); ++ goto out; ++ } ++ ++ if (vmai->cpt_next > vmai->cpt_hdrlen) { ++ loff_t offset = vmapos + vmai->cpt_hdrlen; ++ ++ do { ++ union { ++ struct cpt_page_block pb; ++ struct cpt_remappage_block rpb; ++ struct cpt_copypage_block cpb; ++ struct cpt_lazypage_block lpb; ++ struct cpt_iterpage_block ipb; ++ } u; ++ loff_t pos; ++ ++ err = rst_get_object(-1, offset, &u, ctx); ++ if (err) { ++ eprintk_ctx("vma fix object: %d\n", err); ++ goto out; ++ } ++ if (u.rpb.cpt_object == CPT_OBJ_REMAPPAGES) { ++ err = sc_remap_file_pages(u.rpb.cpt_start, ++ u.rpb.cpt_end-u.rpb.cpt_start, ++ 0, u.rpb.cpt_pgoff, 0); ++ if (err < 0) { ++ eprintk_ctx("remap_file_pages: %d (%08x,%u,%u)\n", err, ++ (__u32)u.rpb.cpt_start, (__u32)(u.rpb.cpt_end-u.rpb.cpt_start), ++ (__u32)u.rpb.cpt_pgoff); ++ goto out; ++ } ++ offset += u.rpb.cpt_next; ++ continue; ++ } else if (u.cpb.cpt_object == CPT_OBJ_LAZYPAGES) { ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ unsigned long ptr = u.lpb.cpt_start; ++ ++ down_read(&mm->mmap_sem); ++ if ((vma = find_vma(mm, u.lpb.cpt_start)) == NULL) { ++ up_read(&mm->mmap_sem); ++ eprintk_ctx("lost vm_area_struct\n"); ++ err = -ESRCH; ++ goto out; ++ } ++ err = anon_vma_prepare(vma); ++ if (err) { ++ up_read(&mm->mmap_sem); ++ goto out; ++ } ++ while (ptr < u.lpb.cpt_end) { ++ err = rst_pagein(vma, u.lpb.cpt_index + (ptr-u.lpb.cpt_start)/PAGE_SIZE, ++ ptr, ctx); ++ if (err) ++ break; ++ ptr += PAGE_SIZE; ++ } ++ up_read(&mm->mmap_sem); ++#else ++ err = -EINVAL; ++#endif ++ if (err) ++ goto out; ++ offset += u.cpb.cpt_next; ++ continue; ++ } else if (u.cpb.cpt_object == CPT_OBJ_COPYPAGES) { ++ struct vm_area_struct *vma, *vma1; ++ struct mm_struct *src; ++ struct anon_vma *src_anon; ++ cpt_object_t *mobj; ++ ++ if (!vmai->cpt_anonvmaid) { ++ err = -EINVAL; ++ eprintk_ctx("CPT_OBJ_COPYPAGES in !anonvma\n"); ++ goto out; ++ } ++ ++ mobj = lookup_cpt_obj_bypos(CPT_OBJ_MM, u.cpb.cpt_source, ctx); ++ if (!mobj) { ++ eprintk_ctx("lost mm_struct to clone pages from\n"); ++ err = -ESRCH; ++ goto out; ++ } ++ src = mobj->o_obj; ++ ++ down_read(&src->mmap_sem); ++ src_anon = NULL; ++ vma1 = find_vma(src, u.cpb.cpt_start); ++ if (vma1) ++ src_anon = vma1->anon_vma; ++ up_read(&src->mmap_sem); ++ ++ if (!vma1) { ++ eprintk_ctx("lost src vm_area_struct\n"); ++ err = -ESRCH; ++ goto out; ++ } ++ ++ down_read(&mm->mmap_sem); ++ if ((vma = find_vma(mm, u.cpb.cpt_start)) == NULL) { ++ up_read(&mm->mmap_sem); ++ eprintk_ctx("lost vm_area_struct\n"); ++ err = -ESRCH; ++ goto out; ++ } ++ ++ if (!src_anon || ++ !vma->anon_vma || ++ vma->anon_vma != src_anon || ++ vma->vm_start - vma1->vm_start != ++ (vma->vm_pgoff - vma1->vm_pgoff) << PAGE_SHIFT) { ++ up_read(&mm->mmap_sem); ++ wprintk_ctx("anon_vma mismatch in vm_area_struct %Ld\n", vmapos); ++ err = copy_mm_pages(mobj->o_obj, ++ u.cpb.cpt_start, ++ u.cpb.cpt_end); ++ } else { ++ err = __copy_page_range(vma, vma1, ++ u.cpb.cpt_start, ++ u.cpb.cpt_end-u.cpb.cpt_start); ++ up_read(&mm->mmap_sem); ++ } ++ if (err) { ++ eprintk_ctx("clone_page_range: %d (%08x,%u,%ld)\n", err, ++ (__u32)u.cpb.cpt_start, (__u32)(u.cpb.cpt_end-u.cpb.cpt_start), ++ (long)u.cpb.cpt_source); ++ goto out; ++ } ++ ++ offset += u.cpb.cpt_next; ++ continue; ++ } else if (u.pb.cpt_object == CPT_OBJ_ITERPAGES || ++ u.pb.cpt_object == CPT_OBJ_ITERYOUNGPAGES ++ ) { ++#ifdef CONFIG_VZ_CHECKPOINT_ITER ++ unsigned long ptr = u.lpb.cpt_start; ++ u64 page_pos[16]; ++ pos = offset + sizeof(u.pb); ++ ++ err = ctx->pread(&page_pos, ++ 8*(u.lpb.cpt_end-ptr)/PAGE_SIZE, ++ ctx, ++ pos); ++ if (err) { ++ eprintk_ctx("Oops\n"); ++ goto out; ++ } ++ ++ down_read(&mm->mmap_sem); ++ if ((vma = find_vma(mm, u.lpb.cpt_start)) == NULL) { ++ up_read(&mm->mmap_sem); ++ eprintk_ctx("lost vm_area_struct\n"); ++ err = -ESRCH; ++ goto out; ++ } ++ err = anon_vma_prepare(vma); ++ if (err) { ++ up_read(&mm->mmap_sem); ++ goto out; ++ } ++ while (ptr < u.lpb.cpt_end) { ++ err = rst_iter(vma, ++ page_pos[(ptr-u.lpb.cpt_start)/PAGE_SIZE], ++ ptr, ++ ctx); ++ if (err) ++ break; ++ ptr += PAGE_SIZE; ++ } ++ if (u.pb.cpt_object == CPT_OBJ_ITERYOUNGPAGES) { ++ make_pages_present((unsigned long)u.lpb.cpt_start, ++ (unsigned long)u.lpb.cpt_end); ++ } ++ up_read(&mm->mmap_sem); ++#else ++ err = -EINVAL; ++#endif ++ if (err) ++ goto out; ++ offset += u.cpb.cpt_next; ++ continue; ++ } ++ if (u.pb.cpt_object != CPT_OBJ_PAGES) { ++ eprintk_ctx("unknown vma fix object %d\n", u.pb.cpt_object); ++ err = -EINVAL; ++ goto out; ++ } ++ pos = offset + sizeof(u.pb); ++ if (!(vmai->cpt_flags&VM_ACCOUNT) && !(prot&PROT_WRITE)) { ++ /* I guess this is get_user_pages() messed things, ++ * this happens f.e. when gdb inserts breakpoints. ++ */ ++ int i; ++ for (i=0; i<(u.pb.cpt_end-u.pb.cpt_start)/PAGE_SIZE; i++) { ++ struct page *page; ++ void *maddr; ++ err = get_user_pages(current, current->mm, ++ (unsigned long)u.pb.cpt_start + i*PAGE_SIZE, ++ 1, 1, 1, &page, NULL); ++ if (err == 0) ++ err = -EFAULT; ++ if (err < 0) { ++ eprintk_ctx("get_user_pages: %d\n", err); ++ goto out; ++ } ++ err = 0; ++ maddr = kmap(page); ++ if (u.pb.cpt_content == CPT_CONTENT_VOID) { ++ memset(maddr, 0, PAGE_SIZE); ++ } else if (u.pb.cpt_content == CPT_CONTENT_DATA) { ++ err = ctx->pread(maddr, PAGE_SIZE, ++ ctx, pos + i*PAGE_SIZE); ++ if (err) { ++ kunmap(page); ++ goto out; ++ } ++ } else { ++ err = -EINVAL; ++ kunmap(page); ++ goto out; ++ } ++ set_page_dirty_lock(page); ++ kunmap(page); ++ page_cache_release(page); ++ } ++ } else { ++ if (!(prot&PROT_WRITE)) ++ sc_mprotect(vmai->cpt_start, vmai->cpt_end-vmai->cpt_start, prot | PROT_WRITE); ++ if (u.pb.cpt_content == CPT_CONTENT_VOID) { ++ int i; ++ for (i=0; i<(u.pb.cpt_end-u.pb.cpt_start)/sizeof(unsigned long); i++) { ++ err = __put_user(0UL, ((unsigned long __user*)(unsigned long)u.pb.cpt_start) + i); ++ if (err) { ++ eprintk_ctx("__put_user 2 %d\n", err); ++ goto out; ++ } ++ } ++ } else if (u.pb.cpt_content == CPT_CONTENT_DATA) { ++ loff_t tpos = pos; ++ err = ctx->file->f_op->read(ctx->file, cpt_ptr_import(u.pb.cpt_start), ++ u.pb.cpt_end-u.pb.cpt_start, ++ &tpos); ++ if (err != u.pb.cpt_end-u.pb.cpt_start) { ++ if (err >= 0) ++ err = -EIO; ++ goto out; ++ } ++ } else { ++ err = -EINVAL; ++ goto out; ++ } ++ if (!(prot&PROT_WRITE)) ++ sc_mprotect(vmai->cpt_start, vmai->cpt_end-vmai->cpt_start, prot); ++ } ++ err = 0; ++ offset += u.pb.cpt_next; ++ } while (offset < vmapos + vmai->cpt_next); ++ } ++ ++check: ++ do { ++ struct vm_area_struct *vma; ++ down_read(&mm->mmap_sem); ++ vma = find_vma(mm, addr); ++ if (vma) { ++ if ((vma->vm_flags^vmai->cpt_flags)&VM_READHINTMASK) { ++ VM_ClearReadHint(vma); ++ vma->vm_flags |= vmai->cpt_flags&VM_READHINTMASK; ++ } ++ if ((vma->vm_flags^vmai->cpt_flags)&VM_LOCKED) { ++ dprintk_ctx("fixing up VM_LOCKED %Ld\n", vmapos); ++ up_read(&mm->mmap_sem); ++ if (vma->vm_flags&VM_LOCKED) ++ err = sc_munlock(vmai->cpt_start, vmai->cpt_end-vmai->cpt_start); ++ else ++ err = sc_mlock(vmai->cpt_start, vmai->cpt_end-vmai->cpt_start); ++ /* When mlock fails with EFAULT, it means ++ * that it could not bring in pages. ++ * It can happen after mlock() on unreadable ++ * VMAs. But VMA is correctly locked, ++ * so that this error can be ignored. */ ++ if (err == -EFAULT) ++ err = 0; ++ if (err) ++ goto out; ++ goto check; ++ } ++ if ((vma->vm_page_prot.pgprot^vmai->cpt_pgprot)&~__PAGE_NX) ++ wprintk_ctx("VMA %08lx@%ld pgprot mismatch %08Lx %08Lx\n", addr, (long)vmapos, ++ (unsigned long long)vma->vm_page_prot.pgprot, ++ (unsigned long long)vmai->cpt_pgprot); ++#if defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64) ++ if (((vma->vm_page_prot.pgprot^vmai->cpt_pgprot)&__PAGE_NX) && ++ (ctx->kernel_config_flags&CPT_KERNEL_CONFIG_PAE)) ++ wprintk_ctx("VMA %08lx@%ld pgprot mismatch %08Lx %08Lx\n", addr, (long)vmapos, ++ (__u64)vma->vm_page_prot.pgprot, (__u64)vmai->cpt_pgprot); ++#endif ++ if (vma->vm_flags != vmai->cpt_flags) { ++ unsigned long x = vma->vm_flags ^ vmai->cpt_flags; ++ if (x & VM_EXEC) { ++ /* Crap. On i386 this is OK. ++ * It is impossible to make via mmap/mprotect ++ * exec.c clears VM_EXEC on stack. */ ++ vma->vm_flags &= ~VM_EXEC; ++ } else if ((x & VM_ACCOUNT) && !checked) { ++ checked = 1; ++ if (!(prot&PROT_WRITE)) { ++ up_read(&mm->mmap_sem); ++ sc_mprotect(vmai->cpt_start, vmai->cpt_end-vmai->cpt_start, prot | PROT_WRITE); ++ sc_mprotect(vmai->cpt_start, vmai->cpt_end-vmai->cpt_start, prot); ++ goto check; ++ } ++ wprintk_ctx("VMA %08lx@%ld flag mismatch %08x %08x\n", addr, (long)vmapos, ++ (__u32)vma->vm_flags, (__u32)vmai->cpt_flags); ++ } else { ++ wprintk_ctx("VMA %08lx@%ld flag mismatch %08x %08x\n", addr, (long)vmapos, ++ (__u32)vma->vm_flags, (__u32)vmai->cpt_flags); ++ } ++ } ++ } else { ++ wprintk_ctx("no VMA for %08lx@%ld\n", addr, (long)vmapos); ++ } ++ up_read(&mm->mmap_sem); ++ } while (0); ++ ++out: ++ if (file) ++ fput(file); ++ return err; ++} ++ ++#ifndef CONFIG_IA64 ++#define TASK_UNMAP_START 0 ++#else ++/* On IA64 the first page is a special VM_IO|VM_RESERVED mapping ++ * used to accelerate speculative dereferences of NULL pointer. */ ++#define TASK_UNMAP_START PAGE_SIZE ++#endif ++ ++static int do_rst_mm(struct cpt_mm_image *vmi, loff_t pos, struct cpt_context *ctx) ++{ ++ int err = 0; ++ unsigned int def_flags; ++ struct mm_struct *mm = current->mm; ++#ifdef CONFIG_BEANCOUNTERS ++ struct user_beancounter *bc; ++#endif ++ ++ down_write(&mm->mmap_sem); ++ do_munmap(mm, TASK_UNMAP_START, TASK_SIZE-TASK_UNMAP_START); ++ ++#ifdef CONFIG_BEANCOUNTERS ++ /* ++ * MM beancounter is usually correct from the fork time, ++ * but not for init, for example. ++ * Luckily, mm_ub can be changed for a completely empty MM. ++ */ ++ bc = rst_lookup_ubc(vmi->cpt_mmub, ctx); ++ err = virtinfo_notifier_call(VITYPE_SCP, VIRTINFO_SCP_RSTMM, bc); ++ if (err & NOTIFY_FAIL) { ++ up_write(&mm->mmap_sem); ++ return -ECHRNG; ++ } ++ if ((err & VIRTNOTIFY_CHANGE) && bc != mm->mm_ub) { ++ struct user_beancounter *old_bc; ++ ++ old_bc = mm->mm_ub; ++ mm->mm_ub = bc; ++ bc = old_bc; ++ } ++ err = 0; ++ put_beancounter(bc); ++#endif ++ ++ mm->start_code = vmi->cpt_start_code; ++ mm->end_code = vmi->cpt_end_code; ++ mm->start_data = vmi->cpt_start_data; ++ mm->end_data = vmi->cpt_end_data; ++ mm->start_brk = vmi->cpt_start_brk; ++ mm->brk = vmi->cpt_brk; ++ mm->start_stack = vmi->cpt_start_stack; ++ mm->arg_start = vmi->cpt_start_arg; ++ mm->arg_end = vmi->cpt_end_arg; ++ mm->env_start = vmi->cpt_start_env; ++ mm->env_end = vmi->cpt_end_env; ++ mm->def_flags = 0; ++ def_flags = vmi->cpt_def_flags; ++ ++ mm->flags = vmi->cpt_dumpable; ++ if (ctx->image_version < CPT_VERSION_24) ++ mm->flags |= MMF_DUMP_FILTER_DEFAULT << MMF_DUMPABLE_BITS; ++ ++ mm->vps_dumpable = vmi->cpt_vps_dumpable; ++#ifndef CONFIG_IA64 ++ if (ctx->image_version >= CPT_VERSION_9) { ++ mm->context.vdso = cpt_ptr_import(vmi->cpt_vdso); ++ current_thread_info()->sysenter_return = CPT_SYSENTER_RETURN; ++ } ++#endif ++ ++#if 0 /* def CONFIG_HUGETLB_PAGE*/ ++/* NB: ? */ ++ int used_hugetlb; ++#endif ++ up_write(&mm->mmap_sem); ++ ++ if (vmi->cpt_next > vmi->cpt_hdrlen) { ++ loff_t offset = pos + vmi->cpt_hdrlen; ++ do { ++ union { ++ struct cpt_vma_image vmai; ++ struct cpt_aio_ctx_image aioi; ++ struct cpt_obj_bits bits; ++ } u; ++ err = rst_get_object(-1, offset, &u, ctx); ++ if (err) ++ goto out; ++ if (u.vmai.cpt_object == CPT_OBJ_VMA) { ++#ifdef CONFIG_IA64 ++ //// Later... ++ if (u.vmai.cpt_start) ++#endif ++ err = do_rst_vma(&u.vmai, offset, pos, ctx); ++ if (err) ++ goto out; ++#ifdef CONFIG_X86 ++ } else if (u.bits.cpt_object == CPT_OBJ_BITS && ++ u.bits.cpt_content == CPT_CONTENT_MM_CONTEXT) { ++ err = do_rst_ldt(&u.bits, offset, ctx); ++ if (err) ++ goto out; ++#endif ++ } else if (u.aioi.cpt_object == CPT_OBJ_AIO_CONTEXT) { ++ err = do_rst_aio(&u.aioi, offset, ctx); ++ if (err) ++ goto out; ++ } else { ++ eprintk_ctx("unknown object %u in mm image\n", u.vmai.cpt_object); ++ err = -EINVAL; ++ goto out; ++ } ++ offset += u.vmai.cpt_next; ++ } while (offset < pos + vmi->cpt_next); ++ } ++ ++ down_write(&mm->mmap_sem); ++ mm->def_flags = def_flags; ++ up_write(&mm->mmap_sem); ++ ++ ++out: ++ return err; ++} ++ ++extern void exit_mm(struct task_struct * tsk); ++ ++int rst_mm_complete(struct cpt_task_image *ti, struct cpt_context *ctx) ++{ ++ int err = 0; ++ cpt_object_t *mobj; ++ void *tmp = (void*)__get_free_page(GFP_KERNEL); ++ struct cpt_mm_image *vmi = (struct cpt_mm_image *)tmp; ++ ++ if (!tmp) ++ return -ENOMEM; ++ ++ if (ti->cpt_mm == CPT_NULL) { ++ if (current->mm) { ++ virtinfo_notifier_call(VITYPE_GENERAL, VIRTINFO_EXIT, ++ current); ++ exit_mm(current); ++ } ++ goto out; ++ } ++ ++ mobj = lookup_cpt_obj_bypos(CPT_OBJ_MM, ti->cpt_mm, ctx); ++ if (mobj) { ++ if (current->mm != mobj->o_obj) BUG(); ++ goto out; ++ } ++ ++ if (current->mm == NULL) { ++ struct mm_struct *mm = mm_alloc(); ++ if (mm == NULL) { ++ err = -ENOMEM; ++ goto out; ++ } ++ err = init_new_context(current, mm); ++ if (err) { ++ mmdrop(mm); ++ goto out; ++ } ++ current->mm = mm; ++ } ++ ++ if ((err = rst_get_object(CPT_OBJ_MM, ti->cpt_mm, vmi, ctx)) != 0) ++ goto out; ++ if ((err = do_rst_mm(vmi, ti->cpt_mm, ctx)) != 0) { ++ eprintk_ctx("do_rst_mm %Ld\n", (unsigned long long)ti->cpt_mm); ++ goto out; ++ } ++ err = -ENOMEM; ++ mobj = cpt_object_add(CPT_OBJ_MM, current->mm, ctx); ++ if (mobj != NULL) { ++ err = 0; ++ cpt_obj_setpos(mobj, ti->cpt_mm, ctx); ++ } ++ ++out: ++ if (tmp) ++ free_page((unsigned long)tmp); ++ return err; ++} ++ ++/* This is part of mm setup, made in parent context. Mostly, it is the place, ++ * where we graft mm of another process to child. ++ */ ++ ++int rst_mm_basic(cpt_object_t *obj, struct cpt_task_image *ti, struct cpt_context *ctx) ++{ ++ struct task_struct *tsk = obj->o_obj; ++ cpt_object_t *mobj; ++ ++ /* Task without mm. Just get rid of this. */ ++ if (ti->cpt_mm == CPT_NULL) { ++ if (tsk->mm) { ++ virtinfo_notifier_call(VITYPE_GENERAL, VIRTINFO_EXIT, ++ tsk); ++ mmput(tsk->mm); ++ tsk->mm = NULL; ++ } ++ return 0; ++ } ++ ++ mobj = lookup_cpt_obj_bypos(CPT_OBJ_MM, ti->cpt_mm, ctx); ++ if (mobj) { ++ struct mm_struct *newmm = mobj->o_obj; ++ /* Good, the MM is already created. */ ++ if (newmm == tsk->mm) { ++ /* Already done by clone(). */ ++ return 0; ++ } ++ mmput(tsk->mm); ++ atomic_inc(&newmm->mm_users); ++ tsk->mm = newmm; ++ tsk->active_mm = newmm; ++ } ++ return 0; ++} ++ ++/* We use CLONE_VM when mm of child is going to be shared with parent. ++ * Otherwise mm is copied. ++ */ ++ ++__u32 rst_mm_flag(struct cpt_task_image *ti, struct cpt_context *ctx) ++{ ++ if (ti->cpt_mm == CPT_NULL || ++ lookup_cpt_obj_bypos(CPT_OBJ_MM, ti->cpt_mm, ctx)) ++ return CLONE_VM; ++ return 0; ++} +Index: kernel/kernel/cpt/rst_net.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_net.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,580 @@ ++/* ++ * ++ * kernel/cpt/rst_net.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_kernel.h" ++#include "cpt_net.h" ++#include "cpt_files.h" ++ ++#include "cpt_syscalls.h" ++ ++extern struct in_ifaddr *inet_alloc_ifa(void); ++extern int inet_insert_ifa(struct in_ifaddr *ifa); ++extern struct in_device *inetdev_init(struct net_device *dev); ++ ++int rst_restore_ifaddr(struct cpt_context *ctx) ++{ ++ struct net *net = get_exec_env()->ve_ns->net_ns; ++ int err; ++ loff_t sec = ctx->sections[CPT_SECT_NET_IFADDR]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ struct cpt_ifaddr_image di; ++ struct net_device *dev; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_NET_IFADDR || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ int cindex = -1; ++ int err; ++ err = rst_get_object(CPT_OBJ_NET_IFADDR, sec, &di, ctx); ++ if (err) ++ return err; ++ cindex = di.cpt_index; ++ rtnl_lock(); ++ dev = __dev_get_by_index(net, cindex); ++ if (dev && di.cpt_family == AF_INET) { ++ struct in_device *in_dev; ++ struct in_ifaddr *ifa; ++ if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) ++ in_dev = inetdev_init(dev); ++ ifa = inet_alloc_ifa(); ++ if (ifa) { ++ ifa->ifa_local = di.cpt_address[0]; ++ ifa->ifa_address = di.cpt_peer[0]; ++ ifa->ifa_broadcast = di.cpt_broadcast[0]; ++ ifa->ifa_prefixlen = di.cpt_masklen; ++ ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen); ++ ifa->ifa_flags = di.cpt_flags; ++ ifa->ifa_scope = di.cpt_scope; ++ memcpy(ifa->ifa_label, di.cpt_label, IFNAMSIZ); ++ in_dev_hold(in_dev); ++ ifa->ifa_dev = in_dev; ++ err = inet_insert_ifa(ifa); ++ if (err && err != -EEXIST) { ++ rtnl_unlock(); ++ eprintk_ctx("add ifaddr err %d for %d %s\n", err, di.cpt_index, di.cpt_label); ++ return err; ++ } ++ } ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ } else if (dev && di.cpt_family == AF_INET6) { ++ __u32 prefered_lft; ++ __u32 valid_lft; ++ prefered_lft = (di.cpt_flags & IFA_F_DEPRECATED) ? ++ 0 : di.cpt_prefered_lft; ++ valid_lft = (di.cpt_flags & IFA_F_PERMANENT) ? ++ 0xFFFFFFFF : di.cpt_valid_lft; ++ err = inet6_addr_add(dev->ifindex, ++ (struct in6_addr *)di.cpt_address, ++ di.cpt_masklen, 0, ++ prefered_lft, ++ valid_lft); ++ if (err && err != -EEXIST) { ++ rtnl_unlock(); ++ eprintk_ctx("add ifaddr err %d for %d %s\n", err, di.cpt_index, di.cpt_label); ++ return err; ++ } ++#endif ++ } else { ++ rtnl_unlock(); ++ eprintk_ctx("unknown ifaddr 2 for %d\n", di.cpt_index); ++ return -EINVAL; ++ } ++ rtnl_unlock(); ++ sec += di.cpt_next; ++ } ++ return 0; ++} ++ ++static int rewrite_rtmsg(struct nlmsghdr *nlh, struct cpt_context *ctx) ++{ ++ int min_len = NLMSG_LENGTH(sizeof(struct rtmsg)); ++ struct rtmsg *rtm = NLMSG_DATA(nlh); ++ __u32 prefix0 = 0; ++ ++ if (nlh->nlmsg_len > min_len) { ++ int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); ++ struct rtattr *rta = (void*)nlh + NLMSG_ALIGN(min_len); ++ ++ while (RTA_OK(rta, attrlen)) { ++ if (rta->rta_type == RTA_DST) { ++ prefix0 = *(__u32*)RTA_DATA(rta); ++ } ++ rta = RTA_NEXT(rta, attrlen); ++ } ++ } ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ if (rtm->rtm_family == AF_INET6) { ++ if (rtm->rtm_type == RTN_LOCAL) ++ return 2; ++ if (rtm->rtm_flags & RTM_F_CLONED) ++ return 2; ++ if (rtm->rtm_protocol == RTPROT_UNSPEC || ++ rtm->rtm_protocol == RTPROT_RA || ++ rtm->rtm_protocol == RTPROT_REDIRECT || ++ rtm->rtm_protocol == RTPROT_KERNEL) ++ return 2; ++ if (rtm->rtm_protocol == RTPROT_BOOT && ++ ((rtm->rtm_dst_len == 8 && prefix0 == htonl(0xFF000000)) || ++ (rtm->rtm_dst_len == 64 && prefix0 == htonl(0xFE800000)))) ++ return 2; ++ } ++#endif ++ return rtm->rtm_protocol == RTPROT_KERNEL; ++} ++ ++int rst_restore_route(struct cpt_context *ctx) ++{ ++ int err; ++ struct socket *sock; ++ struct msghdr msg; ++ struct iovec iov; ++ struct sockaddr_nl nladdr; ++ mm_segment_t oldfs; ++ loff_t sec = ctx->sections[CPT_SECT_NET_ROUTE]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ struct cpt_object_hdr v; ++ char *pg; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_NET_ROUTE || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ if (h.cpt_hdrlen >= h.cpt_next) ++ return 0; ++ ++ sec += h.cpt_hdrlen; ++ err = rst_get_object(CPT_OBJ_NET_ROUTE, sec, &v, ctx); ++ if (err < 0) ++ return err; ++ ++ err = sock_create_kern(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, &sock); ++ if (err) ++ return err; ++ ++ pg = (char*)__get_free_page(GFP_KERNEL); ++ if (pg == NULL) { ++ err = -ENOMEM; ++ goto out_sock; ++ } ++ ++ memset(&nladdr, 0, sizeof(nladdr)); ++ nladdr.nl_family = AF_NETLINK; ++ ++ endsec = sec + v.cpt_next; ++ sec += v.cpt_hdrlen; ++ ++ while (sec < endsec) { ++ struct nlmsghdr *n; ++ struct nlmsghdr nh; ++ int kernel_flag; ++ ++ if (endsec - sec < sizeof(nh)) ++ break; ++ ++ err = ctx->pread(&nh, sizeof(nh), ctx, sec); ++ if (err) ++ goto out_sock_pg; ++ if (nh.nlmsg_len < sizeof(nh) || nh.nlmsg_len > PAGE_SIZE || ++ endsec - sec < nh.nlmsg_len) { ++ err = -EINVAL; ++ goto out_sock_pg; ++ } ++ err = ctx->pread(pg, nh.nlmsg_len, ctx, sec); ++ if (err) ++ goto out_sock_pg; ++ ++ n = (struct nlmsghdr*)pg; ++ n->nlmsg_flags = NLM_F_REQUEST|NLM_F_APPEND|NLM_F_CREATE; ++ ++ err = rewrite_rtmsg(n, ctx); ++ if (err < 0) ++ goto out_sock_pg; ++ kernel_flag = err; ++ ++ if (kernel_flag == 2) ++ goto do_next; ++ ++ iov.iov_base=n; ++ iov.iov_len=nh.nlmsg_len; ++ msg.msg_name=&nladdr; ++ msg.msg_namelen=sizeof(nladdr); ++ msg.msg_iov=&iov; ++ msg.msg_iovlen=1; ++ msg.msg_control=NULL; ++ msg.msg_controllen=0; ++ msg.msg_flags=MSG_DONTWAIT; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ err = sock_sendmsg(sock, &msg, nh.nlmsg_len); ++ set_fs(oldfs); ++ ++ if (err < 0) ++ goto out_sock_pg; ++ err = 0; ++ ++ iov.iov_base=pg; ++ iov.iov_len=PAGE_SIZE; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ err = sock_recvmsg(sock, &msg, PAGE_SIZE, MSG_DONTWAIT); ++ set_fs(oldfs); ++ if (err != -EAGAIN) { ++ if (err == NLMSG_LENGTH(sizeof(struct nlmsgerr)) && ++ n->nlmsg_type == NLMSG_ERROR) { ++ struct nlmsgerr *e = NLMSG_DATA(n); ++ if (e->error != -EEXIST || !kernel_flag) ++ eprintk_ctx("NLMERR: %d\n", e->error); ++ } else { ++ eprintk_ctx("Res: %d %d\n", err, n->nlmsg_type); ++ } ++ } ++do_next: ++ err = 0; ++ sec += NLMSG_ALIGN(nh.nlmsg_len); ++ } ++ ++out_sock_pg: ++ free_page((unsigned long)pg); ++out_sock: ++ sock_release(sock); ++ return err; ++} ++ ++int rst_resume_network(struct cpt_context *ctx) ++{ ++ struct ve_struct *env; ++ ++ env = get_ve_by_id(ctx->ve_id); ++ if (!env) ++ return -ESRCH; ++ env->disable_net = 0; ++ put_ve(env); ++ return 0; ++} ++ ++/* We do not restore skb queue, just reinit it */ ++static int rst_restore_tuntap(loff_t pos, struct cpt_netdev_image *di, ++ struct cpt_context *ctx) ++{ ++ int err = -ENODEV; ++#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) ++ struct cpt_tuntap_image ti; ++ struct net_device *dev; ++ struct file *bind_file = NULL; ++ struct tun_struct *tun; ++ ++ pos += di->cpt_hdrlen; ++ err = rst_get_object(CPT_OBJ_NET_TUNTAP, pos, &ti, ctx); ++ if (err) ++ return err; ++ ++ if (ti.cpt_bindfile) { ++ bind_file = rst_file(ti.cpt_bindfile, -1, ctx); ++ if (IS_ERR(bind_file)) { ++ eprintk_ctx("rst_restore_tuntap:" ++ "rst_file: %Ld\n", ++ (unsigned long long)ti.cpt_bindfile); ++ return PTR_ERR(bind_file); ++ } ++ } ++ ++ rtnl_lock(); ++ err = -ENOMEM; ++ dev = alloc_netdev(sizeof(struct tun_struct), di->cpt_name, tun_setup); ++ if (!dev) ++ goto out; ++ ++ tun = netdev_priv(dev); ++ ++ tun->dev = dev; ++ tun->owner = ti.cpt_owner; ++ tun->flags = ti.cpt_flags; ++ tun->attached = ti.cpt_attached; ++ tun->if_flags = ti.cpt_if_flags; ++ tun_net_init(dev); ++ BUG_ON(sizeof(ti.cpt_dev_addr) != sizeof(tun->dev_addr)); ++ memcpy(tun->dev_addr, ti.cpt_dev_addr, sizeof(ti.cpt_dev_addr)); ++ BUG_ON(sizeof(ti.cpt_chr_filter) != sizeof(tun->chr_filter)); ++ memcpy(tun->chr_filter, ti.cpt_chr_filter, sizeof(ti.cpt_chr_filter)); ++ BUG_ON(sizeof(ti.cpt_net_filter) != sizeof(tun->net_filter)); ++ memcpy(tun->net_filter, ti.cpt_net_filter, sizeof(ti.cpt_net_filter)); ++ ++ err = register_netdevice(dev); ++ if (err < 0) { ++ free_netdev(dev); ++ eprintk_ctx("failed to register tun/tap net device\n"); ++ goto out; ++ } ++ list_add(&tun->list, &tun_dev_list); ++ ++ bind_file->private_data = tun; ++ tun->bind_file = bind_file; ++ ++out: ++ fput(bind_file); ++ rtnl_unlock(); ++#endif ++ return err; ++} ++ ++int rst_restore_netdev(struct cpt_context *ctx) ++{ ++ struct net *net = get_exec_env()->ve_ns->net_ns; ++ int err; ++ loff_t sec = ctx->sections[CPT_SECT_NET_DEVICE]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ struct cpt_netdev_image di; ++ struct net_device *dev; ++ ++ get_exec_env()->disable_net = 1; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_NET_DEVICE || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ int err; ++ struct net_device *dev_new; ++ err = rst_get_object(CPT_OBJ_NET_DEVICE, sec, &di, ctx); ++ if (err) ++ return err; ++ ++ if (di.cpt_next > sizeof(di)) { ++ err = rst_restore_tuntap(sec, &di, ctx); ++ if (err) ++ return err; ++ } ++ ++ rtnl_lock(); ++ dev = __dev_get_by_name(net, di.cpt_name); ++ if (dev) { ++ if (dev->ifindex != di.cpt_index) { ++ dev_new = __dev_get_by_index(net, di.cpt_index); ++ if (!dev_new) { ++ write_lock_bh(&dev_base_lock); ++ hlist_del(&dev->index_hlist); ++ if (dev->iflink == dev->ifindex) ++ dev->iflink = di.cpt_index; ++ dev->ifindex = di.cpt_index; ++ hlist_add_head(&dev->index_hlist, ++ dev_index_hash(net, dev->ifindex)); ++ write_unlock_bh(&dev_base_lock); ++ } else { ++ write_lock_bh(&dev_base_lock); ++ hlist_del(&dev->index_hlist); ++ hlist_del(&dev_new->index_hlist); ++ if (dev_new->iflink == dev_new->ifindex) ++ dev_new->iflink = dev->ifindex; ++ dev_new->ifindex = dev->ifindex; ++ if (dev->iflink == dev->ifindex) ++ dev->iflink = di.cpt_index; ++ dev->ifindex = di.cpt_index; ++ hlist_add_head(&dev->index_hlist, ++ dev_index_hash(net, dev->ifindex)); ++ hlist_add_head(&dev_new->index_hlist, ++ dev_index_hash(net, dev_new->ifindex)); ++ write_unlock_bh(&dev_base_lock); ++ } ++ } ++ if (di.cpt_flags^dev->flags) { ++ err = dev_change_flags(dev, di.cpt_flags); ++ if (err) ++ eprintk_ctx("dev_change_flags err: %d\n", err); ++ } ++ } else { ++ eprintk_ctx("unknown interface 2 %s\n", di.cpt_name); ++ } ++ rtnl_unlock(); ++ sec += di.cpt_next; ++ } ++ return 0; ++} ++ ++static int dumpfn(void *arg) ++{ ++ int i; ++ int *pfd = arg; ++ char *argv[] = { "iptables-restore", "-c", NULL }; ++ ++ if (pfd[0] != 0) ++ sc_dup2(pfd[0], 0); ++ ++ for (i=1; ifiles->fdt->max_fds; i++) ++ sc_close(i); ++ ++ module_put(THIS_MODULE); ++ ++ set_fs(KERNEL_DS); ++ i = sc_execve("/sbin/iptables-restore", argv, NULL); ++ if (i == -ENOENT) ++ i = sc_execve("/usr/sbin/iptables-restore", argv, NULL); ++ eprintk("failed to exec iptables-restore: %d\n", i); ++ return 255 << 8; ++} ++ ++static int rst_restore_iptables(struct cpt_context * ctx) ++{ ++ int err; ++ int pfd[2]; ++ struct file *f; ++ struct cpt_object_hdr v; ++ int n; ++ struct cpt_section_hdr h; ++ loff_t sec = ctx->sections[CPT_SECT_NET_IPTABLES]; ++ loff_t end; ++ int pid; ++ int status; ++ mm_segment_t oldfs; ++ sigset_t ignore, blocked; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_NET_IPTABLES || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ if (h.cpt_hdrlen == h.cpt_next) ++ return 0; ++ if (h.cpt_hdrlen > h.cpt_next) ++ return -EINVAL; ++ sec += h.cpt_hdrlen; ++ err = rst_get_object(CPT_OBJ_NAME, sec, &v, ctx); ++ if (err < 0) ++ return err; ++ ++ err = sc_pipe(pfd); ++ if (err < 0) ++ return err; ++ ignore.sig[0] = CPT_SIG_IGNORE_MASK; ++ sigprocmask(SIG_BLOCK, &ignore, &blocked); ++ pid = err = local_kernel_thread(dumpfn, (void*)pfd, SIGCHLD, 0); ++ if (err < 0) { ++ eprintk_ctx("iptables local_kernel_thread: %d\n", err); ++ goto out; ++ } ++ f = fget(pfd[1]); ++ sc_close(pfd[1]); ++ sc_close(pfd[0]); ++ ++ ctx->file->f_pos = sec + v.cpt_hdrlen; ++ end = sec + v.cpt_next; ++ do { ++ char *p; ++ char buf[16]; ++ ++ n = end - ctx->file->f_pos; ++ if (n > sizeof(buf)) ++ n = sizeof(buf); ++ ++ if (ctx->read(buf, n, ctx)) ++ break; ++ if ((p = memchr(buf, 0, n)) != NULL) ++ n = p - buf; ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ f->f_op->write(f, buf, n, &f->f_pos); ++ set_fs(oldfs); ++ } while (ctx->file->f_pos < end); ++ ++ fput(f); ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ if ((err = sc_waitx(pid, 0, &status)) < 0) ++ eprintk_ctx("wait4: %d\n", err); ++ else if ((status & 0x7f) == 0) { ++ err = (status & 0xff00) >> 8; ++ if (err != 0) { ++ eprintk_ctx("iptables-restore exited with %d\n", err); ++ err = -EINVAL; ++ } ++ } else { ++ eprintk_ctx("iptables-restore terminated\n"); ++ err = -EINVAL; ++ } ++ set_fs(oldfs); ++ sigprocmask(SIG_SETMASK, &blocked, NULL); ++ ++ return err; ++ ++out: ++ if (pfd[1] >= 0) ++ sc_close(pfd[1]); ++ if (pfd[0] >= 0) ++ sc_close(pfd[0]); ++ sigprocmask(SIG_SETMASK, &blocked, NULL); ++ return err; ++} ++ ++int rst_restore_net(struct cpt_context *ctx) ++{ ++ int err; ++ ++ err = rst_restore_netdev(ctx); ++ if (!err) ++ err = rst_restore_ifaddr(ctx); ++ if (!err) ++ err = rst_restore_route(ctx); ++ if (!err) ++ err = rst_restore_iptables(ctx); ++ if (!err) ++ err = rst_restore_ip_conntrack(ctx); ++ return err; ++} +Index: kernel/kernel/cpt/rst_proc.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_proc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,581 @@ ++/* ++ * ++ * kernel/cpt/rst_proc.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_dump.h" ++#include "cpt_files.h" ++#include "cpt_mm.h" ++#include "cpt_kernel.h" ++ ++MODULE_AUTHOR("Alexey Kuznetsov "); ++MODULE_LICENSE("GPL"); ++ ++/* List of contexts and lock protecting the list */ ++static struct list_head cpt_context_list; ++static spinlock_t cpt_context_lock; ++ ++static int proc_read(char *buffer, char **start, off_t offset, ++ int length, int *eof, void *data) ++{ ++ off_t pos = 0; ++ off_t begin = 0; ++ int len = 0; ++ cpt_context_t *ctx; ++ ++ len += sprintf(buffer, "Ctx Id VE State\n"); ++ ++ spin_lock(&cpt_context_lock); ++ ++ list_for_each_entry(ctx, &cpt_context_list, ctx_list) { ++ len += sprintf(buffer+len,"%p %08x %-8u %d", ++ ctx, ++ ctx->contextid, ++ ctx->ve_id, ++ ctx->ctx_state ++ ); ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ len += pagein_info_printf(buffer+len, ctx); ++#endif ++ ++ buffer[len++] = '\n'; ++ ++ pos = begin+len; ++ if (pos < offset) { ++ len = 0; ++ begin = pos; ++ } ++ if (pos > offset+length) ++ goto done; ++ } ++ *eof = 1; ++ ++done: ++ spin_unlock(&cpt_context_lock); ++ *start = buffer + (offset - begin); ++ len -= (offset - begin); ++ if(len > length) ++ len = length; ++ if(len < 0) ++ len = 0; ++ return len; ++} ++ ++void rst_context_release(cpt_context_t *ctx) ++{ ++ list_del(&ctx->ctx_list); ++ spin_unlock(&cpt_context_lock); ++ ++ if (ctx->ctx_state > 0) ++ rst_resume(ctx); ++ ctx->ctx_state = CPT_CTX_ERROR; ++ ++ rst_close_dumpfile(ctx); ++ ++ if (ctx->anonvmas) { ++ int h; ++ for (h = 0; h < CPT_ANONVMA_HSIZE; h++) { ++ while (!hlist_empty(&ctx->anonvmas[h])) { ++ struct hlist_node *elem = ctx->anonvmas[h].first; ++ hlist_del(elem); ++ kfree(elem); ++ } ++ } ++ free_page((unsigned long)ctx->anonvmas); ++ } ++ cpt_flush_error(ctx); ++ if (ctx->errorfile) { ++ fput(ctx->errorfile); ++ ctx->errorfile = NULL; ++ } ++ if (ctx->error_msg) { ++ free_page((unsigned long)ctx->error_msg); ++ ctx->error_msg = NULL; ++ } ++#ifdef CONFIG_VZ_CHECKPOINT_ITER ++ rst_drop_iter_dir(ctx); ++#endif ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ if (ctx->pagein_file_out) ++ fput(ctx->pagein_file_out); ++ if (ctx->pagein_file_in) ++ fput(ctx->pagein_file_in); ++ if (ctx->pgin_task) ++ put_task_struct(ctx->pgin_task); ++#endif ++ if (ctx->filejob_queue) ++ rst_flush_filejobs(ctx); ++ if (ctx->vdso) ++ free_page((unsigned long)ctx->vdso); ++ if (ctx->objcount) ++ eprintk_ctx("%d objects leaked\n", ctx->objcount); ++ kfree(ctx); ++ ++ spin_lock(&cpt_context_lock); ++} ++ ++static void __cpt_context_put(cpt_context_t *ctx) ++{ ++ if (!--ctx->refcount) ++ rst_context_release(ctx); ++} ++ ++static void cpt_context_put(cpt_context_t *ctx) ++{ ++ spin_lock(&cpt_context_lock); ++ __cpt_context_put(ctx); ++ spin_unlock(&cpt_context_lock); ++} ++ ++cpt_context_t * rst_context_open(void) ++{ ++ cpt_context_t *ctx; ++ ++ if ((ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)) != NULL) { ++ rst_context_init(ctx); ++ spin_lock(&cpt_context_lock); ++ list_add_tail(&ctx->ctx_list, &cpt_context_list); ++ spin_unlock(&cpt_context_lock); ++ ctx->error_msg = (char*)__get_free_page(GFP_KERNEL); ++ if (ctx->error_msg != NULL) ++ ctx->error_msg[0] = 0; ++ } ++ return ctx; ++} ++ ++void rst_report_error(int err, cpt_context_t *ctx) ++{ ++ if (ctx->statusfile) { ++ mm_segment_t oldfs; ++ int status = 7 /* VZ_ENVCREATE_ERROR */; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ if (ctx->statusfile->f_op && ctx->statusfile->f_op->write) ++ ctx->statusfile->f_op->write(ctx->statusfile, (char*)&status, sizeof(status), &ctx->statusfile->f_pos); ++ set_fs(oldfs); ++ fput(ctx->statusfile); ++ ctx->statusfile = NULL; ++ } ++} ++ ++ ++static cpt_context_t * cpt_context_lookup(unsigned int ctxid) ++{ ++ cpt_context_t *ctx; ++ ++ spin_lock(&cpt_context_lock); ++ list_for_each_entry(ctx, &cpt_context_list, ctx_list) { ++ if (ctx->contextid == ctxid) { ++ ctx->refcount++; ++ spin_unlock(&cpt_context_lock); ++ return ctx; ++ } ++ } ++ spin_unlock(&cpt_context_lock); ++ return NULL; ++} ++ ++static int rst_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) ++{ ++ int err = 0; ++ cpt_context_t *ctx; ++ struct file *dfile = NULL; ++ ++ unlock_kernel(); ++ ++ if (cmd == CPT_TEST_CAPS) { ++ err = test_cpu_caps(); ++ goto out_lock; ++ } ++ ++ if (cmd == CPT_JOIN_CONTEXT || cmd == CPT_PUT_CONTEXT) { ++ cpt_context_t *old_ctx; ++ ++ ctx = NULL; ++ if (cmd == CPT_JOIN_CONTEXT) { ++ err = -ENOENT; ++ ctx = cpt_context_lookup(arg); ++ if (!ctx) ++ goto out_lock; ++ } ++ ++ spin_lock(&cpt_context_lock); ++ old_ctx = (cpt_context_t*)file->private_data; ++ file->private_data = ctx; ++ ++ if (old_ctx) { ++ if (cmd == CPT_PUT_CONTEXT && old_ctx->sticky) { ++ old_ctx->sticky = 0; ++ old_ctx->refcount--; ++ } ++ __cpt_context_put(old_ctx); ++ } ++ spin_unlock(&cpt_context_lock); ++ err = 0; ++ goto out_lock; ++ } ++ ++ spin_lock(&cpt_context_lock); ++ ctx = (cpt_context_t*)file->private_data; ++ if (ctx) ++ ctx->refcount++; ++ spin_unlock(&cpt_context_lock); ++ ++ if (!ctx) { ++ cpt_context_t *old_ctx; ++ ++ err = -ENOMEM; ++ ctx = rst_context_open(); ++ if (!ctx) ++ goto out_lock; ++ ++ spin_lock(&cpt_context_lock); ++ old_ctx = (cpt_context_t*)file->private_data; ++ if (!old_ctx) { ++ ctx->refcount++; ++ file->private_data = ctx; ++ } else { ++ old_ctx->refcount++; ++ } ++ if (old_ctx) { ++ __cpt_context_put(ctx); ++ ctx = old_ctx; ++ } ++ spin_unlock(&cpt_context_lock); ++ } ++ ++ if (cmd == CPT_GET_CONTEXT) { ++ unsigned int contextid = (unsigned int)arg; ++ ++ err = -EINVAL; ++ if (ctx->contextid && ctx->contextid != contextid) ++ goto out_nosem; ++ if (!ctx->contextid) { ++ cpt_context_t *c1 = cpt_context_lookup(contextid); ++ if (c1) { ++ cpt_context_put(c1); ++ err = -EEXIST; ++ goto out_nosem; ++ } ++ ctx->contextid = contextid; ++ } ++ spin_lock(&cpt_context_lock); ++ if (!ctx->sticky) { ++ ctx->sticky = 1; ++ ctx->refcount++; ++ } ++ spin_unlock(&cpt_context_lock); ++ err = 0; ++ goto out_nosem; ++ } ++ ++ down(&ctx->main_sem); ++ ++ err = -EBUSY; ++ if (ctx->ctx_state < 0) ++ goto out; ++ ++ err = 0; ++ switch (cmd) { ++ case CPT_SET_DUMPFD: ++ if (ctx->ctx_state > 0) { ++ err = -EBUSY; ++ break; ++ } ++ if (arg >= 0) { ++ err = -EBADF; ++ dfile = fget(arg); ++ if (dfile == NULL) ++ break; ++ if (dfile->f_op == NULL || ++ dfile->f_op->read == NULL) { ++ fput(dfile); ++ break; ++ } ++ err = 0; ++ } ++ if (ctx->file) ++ fput(ctx->file); ++ ctx->file = dfile; ++ break; ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ case CPT_SET_PAGEINFDIN: ++ if (ctx->ctx_state > 0) { ++ err = -EBUSY; ++ break; ++ } ++ if (arg >= 0) { ++ dfile = fget(arg); ++ if (dfile == NULL) { ++ err = -EBADF; ++ break; ++ } ++ } ++ if (ctx->pagein_file_in) ++ fput(ctx->pagein_file_in); ++ ctx->pagein_file_in = dfile; ++ break; ++ case CPT_SET_PAGEINFDOUT: ++ if (ctx->ctx_state > 0) { ++ err = -EBUSY; ++ break; ++ } ++ if (arg >= 0) { ++ dfile = fget(arg); ++ if (dfile == NULL) { ++ err = -EBADF; ++ break; ++ } ++ } ++ if (ctx->pagein_file_out) ++ fput(ctx->pagein_file_out); ++ ctx->pagein_file_out = dfile; ++ break; ++ case CPT_PAGEIND: ++ err = rst_pageind(ctx); ++ break; ++#endif ++#ifdef CONFIG_VZ_CHECKPOINT_ITER ++ case CPT_ITER: ++ err = rst_iteration(ctx); ++ break; ++#endif ++ case CPT_SET_LOCKFD: ++ if (ctx->ctx_state > 0) { ++ err = -EBUSY; ++ break; ++ } ++ if (arg >= 0) { ++ dfile = fget(arg); ++ if (dfile == NULL) { ++ err = -EBADF; ++ break; ++ } ++ } ++ if (ctx->lockfile) ++ fput(ctx->lockfile); ++ ctx->lockfile = dfile; ++ break; ++ case CPT_SET_STATUSFD: ++ if (ctx->ctx_state > 0) { ++ err = -EBUSY; ++ break; ++ } ++ if (arg >= 0) { ++ dfile = fget(arg); ++ if (dfile == NULL) { ++ err = -EBADF; ++ break; ++ } ++ } ++ if (ctx->statusfile) ++ fput(ctx->statusfile); ++ ctx->statusfile = dfile; ++ break; ++ case CPT_SET_ERRORFD: ++ if (arg >= 0) { ++ dfile = fget(arg); ++ if (dfile == NULL) { ++ err = -EBADF; ++ break; ++ } ++ } ++ if (ctx->errorfile) ++ fput(ctx->errorfile); ++ ctx->errorfile = dfile; ++ break; ++ case CPT_SET_VEID: ++ if (ctx->ctx_state > 0) { ++ err = -EBUSY; ++ break; ++ } ++ ctx->ve_id = arg; ++ break; ++ case CPT_UNDUMP: ++ if (ctx->ctx_state > 0) { ++ err = -ENOENT; ++ break; ++ } ++ ctx->ctx_state = CPT_CTX_UNDUMPING; ++ err = vps_rst_undump(ctx); ++ if (err) { ++ rst_report_error(err, ctx); ++ if (rst_kill(ctx) == 0) ++ ctx->ctx_state = CPT_CTX_IDLE; ++ } else { ++ ctx->ctx_state = CPT_CTX_UNDUMPED; ++ } ++ break; ++ case CPT_RESUME: ++ if (!ctx->ctx_state) { ++ err = -ENOENT; ++ break; ++ } ++ err = rst_resume(ctx); ++ if (!err) ++ ctx->ctx_state = CPT_CTX_IDLE; ++ break; ++ case CPT_KILL: ++ if (!ctx->ctx_state) { ++ err = -ENOENT; ++ break; ++ } ++ err = rst_kill(ctx); ++ if (!err) ++ ctx->ctx_state = CPT_CTX_IDLE; ++ break; ++ default: ++ err = -EINVAL; ++ break; ++ } ++ ++out: ++ cpt_flush_error(ctx); ++ up(&ctx->main_sem); ++out_nosem: ++ cpt_context_put(ctx); ++out_lock: ++ lock_kernel(); ++ if (err == -ERESTARTSYS || err == -ERESTARTNOINTR || ++ err == -ERESTARTNOHAND || err == -ERESTART_RESTARTBLOCK) ++ err = -EINTR; ++ return err; ++} ++ ++static int rst_open(struct inode * inode, struct file * file) ++{ ++ if (!try_module_get(THIS_MODULE)) ++ return -EBUSY; ++ ++ return 0; ++} ++ ++static int rst_release(struct inode * inode, struct file * file) ++{ ++ cpt_context_t *ctx; ++ ++ spin_lock(&cpt_context_lock); ++ ctx = (cpt_context_t*)file->private_data; ++ file->private_data = NULL; ++ if (ctx) ++ __cpt_context_put(ctx); ++ spin_unlock(&cpt_context_lock); ++ ++ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static struct file_operations rst_fops = ++{ ++ .owner = THIS_MODULE, ++ .ioctl = rst_ioctl, ++ .open = rst_open, ++ .release = rst_release, ++}; ++ ++ ++static struct proc_dir_entry *proc_ent; ++extern void *schedule_tail_p; ++extern void schedule_tail_hook(void); ++ ++static struct ctl_table_header *ctl_header; ++ ++static ctl_table debug_table[] = { ++ { ++ .ctl_name = 9476, ++ .procname = "rst", ++ .data = &debug_level, ++ .maxlen = sizeof(debug_level), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++ { .ctl_name = 0 } ++}; ++static ctl_table root_table[] = { ++ { ++ .ctl_name = CTL_DEBUG, ++ .procname = "debug", ++ .mode = 0555, ++ .child = debug_table, ++ }, ++ { .ctl_name = 0 } ++}; ++ ++static int __init init_rst(void) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ ctl_header = register_sysctl_table(root_table); ++ if (!ctl_header) ++ goto err_mon; ++ ++ spin_lock_init(&cpt_context_lock); ++ INIT_LIST_HEAD(&cpt_context_list); ++ ++ err = -EINVAL; ++ proc_ent = create_proc_entry_mod("rst", 0600, NULL, THIS_MODULE); ++ if (!proc_ent) ++ goto err_out; ++ ++ rst_fops.read = proc_ent->proc_fops->read; ++ rst_fops.write = proc_ent->proc_fops->write; ++ rst_fops.llseek = proc_ent->proc_fops->llseek; ++ proc_ent->proc_fops = &rst_fops; ++ ++ proc_ent->read_proc = proc_read; ++ proc_ent->data = NULL; ++ proc_ent->owner = THIS_MODULE; ++ return 0; ++ ++err_out: ++ unregister_sysctl_table(ctl_header); ++err_mon: ++ return err; ++} ++module_init(init_rst); ++ ++static void __exit exit_rst(void) ++{ ++ remove_proc_entry("rst", NULL); ++ unregister_sysctl_table(ctl_header); ++ ++ spin_lock(&cpt_context_lock); ++ while (!list_empty(&cpt_context_list)) { ++ cpt_context_t *ctx; ++ ctx = list_entry(cpt_context_list.next, cpt_context_t, ctx_list); ++ ++ if (!ctx->sticky) ++ ctx->refcount++; ++ ctx->sticky = 0; ++ ++ BUG_ON(ctx->refcount != 1); ++ ++ __cpt_context_put(ctx); ++ } ++ spin_unlock(&cpt_context_lock); ++} ++module_exit(exit_rst); +Index: kernel/kernel/cpt/rst_process.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_process.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,1627 @@ ++/* ++ * ++ * kernel/cpt/rst_process.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_X86 ++#include ++#endif ++#include ++ ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_files.h" ++#include "cpt_mm.h" ++#include "cpt_ubc.h" ++#include "cpt_process.h" ++#include "cpt_kernel.h" ++ ++ ++#define HOOK_RESERVE 256 ++ ++struct resume_info ++{ ++ asmlinkage void (*hook)(struct resume_info *); ++ unsigned long hooks; ++#define HOOK_TID 0 ++#define HOOK_CONT 1 ++#define HOOK_LSI 2 ++#define HOOK_RESTART 3 ++ unsigned long tid_ptrs[2]; ++ siginfo_t last_siginfo; ++}; ++ ++#ifdef CONFIG_X86_32 ++ ++#define IN_SYSCALL(regs) ((long)(regs)->orig_eax >= 0) ++#define IN_ERROR(regs) ((long)(regs)->eax < 0) ++#define SYSCALL_ERRNO(regs) (-(long)((regs)->eax)) ++#define SYSCALL_RETVAL(regs) ((regs)->eax) ++#define SYSCALL_NR(regs) ((regs)->orig_eax) ++ ++#define SYSCALL_SETRET(regs,val) do { (regs)->eax = (val); } while (0) ++ ++#define SYSCALL_RESTART2(regs,new) do { (regs)->eax = (new); \ ++ (regs)->eip -= 2; } while (0) ++ ++#define syscall_is(tsk,regs,name) (SYSCALL_NR(regs) == __NR_##name) ++ ++/* In new kernels task_pt_regs() is define to something inappropriate */ ++#undef task_pt_regs ++#define task_pt_regs(t) ((struct pt_regs *)((t)->thread.esp0) - 1) ++ ++#elif defined(CONFIG_X86_64) ++ ++#define IN_SYSCALL(regs) ((long)(regs)->orig_rax >= 0) ++#define IN_ERROR(regs) ((long)(regs)->rax < 0) ++#define SYSCALL_ERRNO(regs) (-(long)((regs)->rax)) ++#define SYSCALL_RETVAL(regs) ((regs)->rax) ++#define SYSCALL_NR(regs) ((regs)->orig_rax) ++ ++#define SYSCALL_SETRET(regs,val) do { (regs)->rax = (val); } while (0) ++ ++#define SYSCALL_RESTART2(regs,new) do { (regs)->rax = (new); \ ++ (regs)->rip -= 2; } while (0) ++ ++#define __NR32_restart_syscall 0 ++#define __NR32_rt_sigtimedwait 177 ++#define __NR32_pause 29 ++#define __NR32_futex 240 ++ ++#define syscall_is(tsk,regs,name) ((!(task_thread_info(tsk)->flags&_TIF_IA32) && \ ++ SYSCALL_NR(regs) == __NR_##name) || \ ++ ((task_thread_info(tsk)->flags&_TIF_IA32) && \ ++ SYSCALL_NR(regs) == __NR32_##name)) ++ ++#elif defined (CONFIG_IA64) ++ ++#define IN_SYSCALL(regs) ((long)(regs)->cr_ifs >= 0) ++#define IN_ERROR(regs) ((long)(regs)->r10 == -1) ++#define SYSCALL_ERRNO(regs) ((regs)->r10 == -1 ? (long)((regs)->r8) : 0) ++#define SYSCALL_RETVAL(regs) ((regs)->r8) ++#define SYSCALL_NR(regs) ((regs)->cr_ifs >= 0 ? (regs)->r15 : -1) ++ ++#define SYSCALL_SETRET(regs,val) do { (regs)->r8 = (val); } while (0) ++ ++#define SYSCALL_RESTART2(regs,new) do { (regs)->r15 = (new); \ ++ (regs)->r10 = 0; \ ++ ia64_decrement_ip(regs); } while (0) ++ ++#define syscall_is(tsk,regs,name) (SYSCALL_NR(regs) == __NR_##name) ++ ++#else ++ ++#error This arch is not supported ++ ++#endif ++ ++#define SYSCALL_RESTART(regs) SYSCALL_RESTART2(regs, SYSCALL_NR(regs)) ++ ++pid_t vpid_to_pid(pid_t nr) ++{ ++ pid_t vnr; ++ struct pid *pid; ++ ++ rcu_read_lock(); ++ pid = find_vpid(nr); ++ vnr = (pid == NULL ? -1 : pid->numbers[0].nr); ++ rcu_read_unlock(); ++ return vnr; ++} ++ ++static void decode_siginfo(siginfo_t *info, struct cpt_siginfo_image *si) ++{ ++ memset(info, 0, sizeof(*info)); ++ switch(si->cpt_code & __SI_MASK) { ++ case __SI_TIMER: ++ info->si_tid = si->cpt_pid; ++ info->si_overrun = si->cpt_uid; ++ info->_sifields._timer._sigval.sival_ptr = cpt_ptr_import(si->cpt_sigval); ++ info->si_sys_private = si->cpt_utime; ++ break; ++ case __SI_POLL: ++ info->si_band = si->cpt_pid; ++ info->si_fd = si->cpt_uid; ++ break; ++ case __SI_FAULT: ++ info->si_addr = cpt_ptr_import(si->cpt_sigval); ++#ifdef __ARCH_SI_TRAPNO ++ info->si_trapno = si->cpt_pid; ++#endif ++ break; ++ case __SI_CHLD: ++ info->si_pid = si->cpt_pid; ++ info->si_uid = si->cpt_uid; ++ info->si_status = si->cpt_sigval; ++ info->si_stime = si->cpt_stime; ++ info->si_utime = si->cpt_utime; ++ break; ++ case __SI_KILL: ++ case __SI_RT: ++ case __SI_MESGQ: ++ default: ++ info->si_pid = si->cpt_pid; ++ info->si_uid = si->cpt_uid; ++ info->si_ptr = cpt_ptr_import(si->cpt_sigval); ++ break; ++ } ++ info->si_signo = si->cpt_signo; ++ info->si_errno = si->cpt_errno; ++ info->si_code = si->cpt_code; ++} ++ ++static int restore_sigqueue(struct task_struct *tsk, ++ struct sigpending *queue, unsigned long start, ++ unsigned long end) ++{ ++ while (start < end) { ++ struct cpt_siginfo_image *si = (struct cpt_siginfo_image *)start; ++ if (si->cpt_object == CPT_OBJ_SIGINFO) { ++ struct sigqueue *q = NULL; ++ struct user_struct *up; ++ ++ up = alloc_uid(get_exec_env()->ve_ns->user_ns, si->cpt_user); ++ if (!up) ++ return -ENOMEM; ++ q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC); ++ if (!q) { ++ free_uid(up); ++ return -ENOMEM; ++ } ++ if (ub_siginfo_charge(q, get_exec_ub())) { ++ kmem_cache_free(sigqueue_cachep, q); ++ free_uid(up); ++ return -ENOMEM; ++ } ++ ++ INIT_LIST_HEAD(&q->list); ++ /* Preallocated elements (posix timers) are not ++ * supported yet. It is safe to replace them with ++ * a private one. */ ++ q->flags = 0; ++ q->user = up; ++ atomic_inc(&q->user->sigpending); ++ ++ decode_siginfo(&q->info, si); ++ list_add_tail(&q->list, &queue->list); ++ } ++ start += si->cpt_next; ++ } ++ return 0; ++} ++ ++int rst_process_linkage(cpt_context_t *ctx) ++{ ++ cpt_object_t *obj; ++ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ struct task_struct *tsk = obj->o_obj; ++ struct cpt_task_image *ti = obj->o_image; ++ ++ if (tsk == NULL) { ++ eprintk_ctx("task %u(%s) is missing\n", ti->cpt_pid, ti->cpt_comm); ++ return -EINVAL; ++ } ++ ++ if (task_pgrp_vnr(tsk) != ti->cpt_pgrp) { ++ struct pid *pid; ++ ++ pid = get_pid(find_vpid(ti->cpt_pgrp)); ++ if (!pid) { ++ eprintk_ctx("illegal PGRP " CPT_FID "\n", CPT_TID(tsk)); ++ return -EINVAL; ++ } ++ ++ write_lock_irq(&tasklist_lock); ++ if (task_pgrp_nr(tsk) != pid_nr(pid)) { ++ detach_pid(tsk, PIDTYPE_PGID); ++ set_task_pgrp(tsk, pid_nr(pid)); ++ if (thread_group_leader(tsk)) { ++ get_pid(pid); ++ attach_pid(tsk, PIDTYPE_PGID, pid); ++ } ++ } ++ write_unlock_irq(&tasklist_lock); ++ if (task_pgrp_nr(tsk) != pid_nr(pid)) { ++ put_pid(pid); ++ eprintk_ctx("cannot set PGRP " CPT_FID "\n", CPT_TID(tsk)); ++ return -EINVAL; ++ } ++ put_pid(pid); ++ } ++ if (task_session_vnr(tsk) != ti->cpt_session) { ++ struct pid *pid; ++ ++ pid = get_pid(find_vpid(ti->cpt_session)); ++ if (!pid) { ++ eprintk_ctx("illegal SID " CPT_FID "\n", CPT_TID(tsk)); ++ return -EINVAL; ++ } ++ ++ write_lock_irq(&tasklist_lock); ++ if (task_session_nr(tsk) != pid_nr(pid)) { ++ detach_pid(tsk, PIDTYPE_SID); ++ set_task_session(tsk, pid_nr(pid)); ++ if (thread_group_leader(tsk)) { ++ get_pid(pid); ++ attach_pid(tsk, PIDTYPE_SID, pid); ++ } ++ } ++ write_unlock_irq(&tasklist_lock); ++ if (task_session_nr(tsk) != pid_nr(pid)) { ++ put_pid(pid); ++ eprintk_ctx("cannot set SID " CPT_FID "\n", CPT_TID(tsk)); ++ return -EINVAL; ++ } ++ put_pid(pid); ++ } ++ if (ti->cpt_old_pgrp > 0 && !tsk->signal->tty_old_pgrp) { ++ struct pid *pid; ++ ++ pid = get_pid(find_vpid(ti->cpt_old_pgrp)); ++ if (!pid) { ++ eprintk_ctx("illegal OLD_PGRP " CPT_FID "\n", CPT_TID(tsk)); ++ return -EINVAL; ++ } ++ tsk->signal->tty_old_pgrp = pid; ++ } ++ } ++ ++ return 0; ++} ++ ++struct pid *alloc_vpid_safe(pid_t vnr) ++{ ++ struct pid *pid; ++ ++ pid = alloc_pid(current->nsproxy->pid_ns, vnr); ++ if (!pid) ++ pid = get_pid(find_vpid(vnr)); ++ return pid; ++} ++ ++static int ++restore_one_signal_struct(struct cpt_task_image *ti, int *exiting, cpt_context_t *ctx) ++{ ++ int err; ++ struct cpt_signal_image *si = cpt_get_buf(ctx); ++ ++ current->signal->tty = NULL; ++ ++ err = rst_get_object(CPT_OBJ_SIGNAL_STRUCT, ti->cpt_signal, si, ctx); ++ if (err) { ++ cpt_release_buf(ctx); ++ return err; ++ } ++ ++ if (task_pgrp_vnr(current) != si->cpt_pgrp) { ++ struct pid * pid = NULL, *free = NULL; ++ ++ if (si->cpt_pgrp_type == CPT_PGRP_ORPHAN) { ++#if 0 ++ if (!is_virtual_pid(si->cpt_pgrp)) { ++ eprintk_ctx("external process group " CPT_FID, CPT_TID(current)); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++#endif ++ pid = alloc_vpid_safe(si->cpt_pgrp); ++ free = pid; ++ } ++ write_lock_irq(&tasklist_lock); ++ if (pid != NULL) { ++ if (task_pgrp_nr(current) != pid_nr(pid)) { ++ detach_pid(current, PIDTYPE_PGID); ++ set_task_pgrp(current, pid_nr(pid)); ++ if (thread_group_leader(current)) { ++ attach_pid(current, PIDTYPE_PGID, pid); ++ free = NULL; ++ } ++ } ++ } ++ write_unlock_irq(&tasklist_lock); ++ if (free != NULL) ++ free_pid(free); ++ } ++ ++ current->signal->tty_old_pgrp = NULL; ++ if ((int)si->cpt_old_pgrp > 0) { ++ if (si->cpt_old_pgrp_type == CPT_PGRP_STRAY) { ++ current->signal->tty_old_pgrp = ++ alloc_pid(current->nsproxy->pid_ns, 0); ++ if (!current->signal->tty_old_pgrp) { ++ eprintk_ctx("failed to allocate stray tty_old_pgrp\n"); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ } else { ++ current->signal->tty_old_pgrp = ++ alloc_vpid_safe(si->cpt_old_pgrp); ++ if (!current->signal->tty_old_pgrp) { ++ dprintk_ctx("forward old tty PGID\n"); ++ current->signal->tty_old_pgrp = NULL; ++ } ++ } ++ } ++ ++ if (task_session_vnr(current) != si->cpt_session) { ++ struct pid * pid = NULL, *free = NULL; ++ ++ if (si->cpt_session_type == CPT_PGRP_ORPHAN) { ++#if 0 ++ if (!is_virtual_pid(si->cpt_session)) { ++ eprintk_ctx("external process session " CPT_FID, CPT_TID(current)); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++#endif ++ pid = alloc_vpid_safe(si->cpt_session); ++ free = pid; ++ } ++ write_lock_irq(&tasklist_lock); ++ if (pid == NULL) ++ pid = find_vpid(si->cpt_session); ++ if (pid != NULL) { ++ if (task_session_nr(current) != pid_nr(pid)) { ++ detach_pid(current, PIDTYPE_SID); ++ set_task_session(current, pid_nr(pid)); ++ if (thread_group_leader(current)) { ++ attach_pid(current, PIDTYPE_SID, pid); ++ free = NULL; ++ } ++ } ++ } ++ write_unlock_irq(&tasklist_lock); ++ if (free != NULL) ++ free_pid(free); ++ } ++ ++ cpt_sigset_import(¤t->signal->shared_pending.signal, si->cpt_sigpending); ++ current->signal->leader = si->cpt_leader; ++ if (si->cpt_ctty != CPT_NULL) { ++ cpt_object_t *obj = lookup_cpt_obj_bypos(CPT_OBJ_TTY, si->cpt_ctty, ctx); ++ if (obj) { ++ struct tty_struct *tty = obj->o_obj; ++ if (!tty->session || tty->session == ++ task_session(current)) { ++ tty->session = task_session(current); ++ current->signal->tty = tty; ++ } else { ++ wprintk_ctx("tty session mismatch\n"); ++ } ++ } ++ } ++ ++ if (si->cpt_curr_target) ++ current->signal->curr_target = find_task_by_vpid(si->cpt_curr_target); ++ current->signal->flags = 0; ++ *exiting = si->cpt_group_exit; ++ current->signal->group_exit_code = si->cpt_group_exit_code; ++ if (si->cpt_group_exit_task) { ++ current->signal->group_exit_task = find_task_by_vpid(si->cpt_group_exit_task); ++ if (current->signal->group_exit_task == NULL) { ++ eprintk_ctx("oops, group_exit_task=NULL, pid=%u\n", si->cpt_group_exit_task); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ } ++ current->signal->notify_count = si->cpt_notify_count; ++ current->signal->group_stop_count = si->cpt_group_stop_count; ++ ++ if (si->cpt_next > si->cpt_hdrlen) { ++ char *buf = kmalloc(si->cpt_next - si->cpt_hdrlen, GFP_KERNEL); ++ if (buf == NULL) { ++ cpt_release_buf(ctx); ++ return -ENOMEM; ++ } ++ err = ctx->pread(buf, si->cpt_next - si->cpt_hdrlen, ctx, ++ ti->cpt_signal + si->cpt_hdrlen); ++ if (err) { ++ kfree(buf); ++ cpt_release_buf(ctx); ++ return err; ++ } ++ restore_sigqueue(current, ++ ¤t->signal->shared_pending, (unsigned long)buf, ++ (unsigned long)buf + si->cpt_next - si->cpt_hdrlen); ++ kfree(buf); ++ } ++ cpt_release_buf(ctx); ++ return 0; ++} ++ ++int restore_one_sighand_struct(struct cpt_task_image *ti, struct cpt_context *ctx) ++{ ++ int err; ++ struct cpt_sighand_image si; ++ int i; ++ loff_t pos, endpos; ++ ++ err = rst_get_object(CPT_OBJ_SIGHAND_STRUCT, ti->cpt_sighand, &si, ctx); ++ if (err) ++ return err; ++ ++ for (i=0; i<_NSIG; i++) { ++ current->sighand->action[i].sa.sa_handler = SIG_DFL; ++#ifndef CONFIG_IA64 ++ current->sighand->action[i].sa.sa_restorer = 0; ++#endif ++ current->sighand->action[i].sa.sa_flags = 0; ++ memset(¤t->sighand->action[i].sa.sa_mask, 0, sizeof(sigset_t)); ++ } ++ ++ pos = ti->cpt_sighand + si.cpt_hdrlen; ++ endpos = ti->cpt_sighand + si.cpt_next; ++ while (pos < endpos) { ++ struct cpt_sighandler_image shi; ++ ++ err = rst_get_object(CPT_OBJ_SIGHANDLER, pos, &shi, ctx); ++ if (err) ++ return err; ++ current->sighand->action[shi.cpt_signo].sa.sa_handler = (void*)(unsigned long)shi.cpt_handler; ++#ifndef CONFIG_IA64 ++ current->sighand->action[shi.cpt_signo].sa.sa_restorer = (void*)(unsigned long)shi.cpt_restorer; ++#endif ++ current->sighand->action[shi.cpt_signo].sa.sa_flags = shi.cpt_flags; ++ cpt_sigset_import(¤t->sighand->action[shi.cpt_signo].sa.sa_mask, shi.cpt_mask); ++ pos += shi.cpt_next; ++ } ++ ++ return 0; ++} ++ ++ ++__u32 rst_signal_flag(struct cpt_task_image *ti, struct cpt_context *ctx) ++{ ++ __u32 flag = 0; ++ ++ if (lookup_cpt_obj_bypos(CPT_OBJ_SIGNAL_STRUCT, ti->cpt_signal, ctx)) ++ flag |= CLONE_THREAD; ++ if (ti->cpt_sighand == CPT_NULL || ++ lookup_cpt_obj_bypos(CPT_OBJ_SIGHAND_STRUCT, ti->cpt_sighand, ctx)) ++ flag |= CLONE_SIGHAND; ++ return flag; ++} ++ ++int ++rst_signal_complete(struct cpt_task_image *ti, int * exiting, cpt_context_t *ctx) ++{ ++ int err; ++ cpt_object_t *obj; ++ ++ if (ti->cpt_signal == CPT_NULL || ti->cpt_sighand == CPT_NULL) { ++ return -EINVAL; ++ } ++ ++ obj = lookup_cpt_obj_bypos(CPT_OBJ_SIGHAND_STRUCT, ti->cpt_sighand, ctx); ++ if (obj) { ++ struct sighand_struct *sig = current->sighand; ++ if (obj->o_obj != sig) { ++ return -EINVAL; ++ } ++ } else { ++ obj = cpt_object_add(CPT_OBJ_SIGHAND_STRUCT, current->sighand, ctx); ++ if (obj == NULL) ++ return -ENOMEM; ++ cpt_obj_setpos(obj, ti->cpt_sighand, ctx); ++ err = restore_one_sighand_struct(ti, ctx); ++ if (err) ++ return err; ++ } ++ ++ ++ obj = lookup_cpt_obj_bypos(CPT_OBJ_SIGNAL_STRUCT, ti->cpt_signal, ctx); ++ if (obj) { ++ struct signal_struct *sig = current->signal; ++ if (obj->o_obj != sig) { ++ return -EINVAL; ++ } ++/* if (current->signal) { ++ pid_t session; ++ ++ session = process_session(current); ++ set_process_vgroup(current, session); ++ set_signal_vsession(current->signal, session); ++ }*/ ++ } else { ++ obj = cpt_object_add(CPT_OBJ_SIGNAL_STRUCT, current->signal, ctx); ++ if (obj == NULL) ++ return -ENOMEM; ++ cpt_obj_setpos(obj, ti->cpt_signal, ctx); ++ err = restore_one_signal_struct(ti, exiting, ctx); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_X86 ++static u32 decode_segment(u32 segid) ++{ ++ if (segid == CPT_SEG_ZERO) ++ return 0; ++ ++ /* TLS descriptors */ ++ if (segid <= CPT_SEG_TLS3) ++ return ((GDT_ENTRY_TLS_MIN + segid-CPT_SEG_TLS1)<<3) + 3; ++ ++ /* LDT descriptor, it is just an index to LDT array */ ++ if (segid >= CPT_SEG_LDT) ++ return ((segid - CPT_SEG_LDT) << 3) | 7; ++ ++ /* Check for one of standard descriptors */ ++#ifdef CONFIG_X86_64 ++ if (segid == CPT_SEG_USER32_DS) ++ return __USER32_DS; ++ if (segid == CPT_SEG_USER32_CS) ++ return __USER32_CS; ++ if (segid == CPT_SEG_USER64_DS) ++ return __USER_DS; ++ if (segid == CPT_SEG_USER64_CS) ++ return __USER_CS; ++#else ++ if (segid == CPT_SEG_USER32_DS) ++ return __USER_DS; ++ if (segid == CPT_SEG_USER32_CS) ++ return __USER_CS; ++#endif ++ wprintk("Invalid segment reg %d\n", segid); ++ return 0; ++} ++#endif ++ ++#if defined (CONFIG_IA64) ++void ia64_decrement_ip (struct pt_regs *regs) ++{ ++ unsigned long w0, ri = ia64_psr(regs)->ri - 1; ++ ++ if (ia64_psr(regs)->ri == 0) { ++ regs->cr_iip -= 16; ++ ri = 2; ++ get_user(w0, (char __user *) regs->cr_iip + 0); ++ if (((w0 >> 1) & 0xf) == 2) { ++ /* ++ * rfi'ing to slot 2 of an MLX bundle causes ++ * an illegal operation fault. We don't want ++ * that to happen... ++ */ ++ ri = 1; ++ } ++ } ++ ia64_psr(regs)->ri = ri; ++} ++#endif ++ ++static void rst_child_tid(unsigned long *child_tids) ++{ ++ dprintk("rct: " CPT_FID "\n", CPT_TID(current)); ++ current->clear_child_tid = (void*)child_tids[0]; ++ current->set_child_tid = (void*)child_tids[1]; ++} ++ ++static void rst_last_siginfo(void) ++{ ++ int signr; ++ siginfo_t *info = current->last_siginfo; ++ struct pt_regs *regs = task_pt_regs(current); ++ struct k_sigaction *ka; ++ int ptrace_id; ++ ++ dprintk("rlsi: " CPT_FID "\n", CPT_TID(current)); ++ ++ spin_lock_irq(¤t->sighand->siglock); ++ current->last_siginfo = NULL; ++ recalc_sigpending(); ++ ++ ptrace_id = current->pn_state; ++ clear_pn_state(current); ++ ++ switch (ptrace_id) { ++ case PN_STOP_TF: ++ case PN_STOP_TF_RT: ++ /* frame_*signal */ ++ dprintk("SIGTRAP %u/%u(%s) %u/%u %u %ld %u %lu\n", ++ task_pid_vnr(current), current->pid, current->comm, ++ info->si_signo, info->si_code, ++ current->exit_code, SYSCALL_NR(regs), ++ current->ptrace, current->ptrace_message); ++ goto out; ++ case PN_STOP_ENTRY: ++ case PN_STOP_LEAVE: ++ /* do_syscall_trace */ ++ spin_unlock_irq(¤t->sighand->siglock); ++ dprintk("ptrace do_syscall_trace: %d %d\n", ptrace_id, current->exit_code); ++ if (current->exit_code) { ++ send_sig(current->exit_code, current, 1); ++ current->exit_code = 0; ++ } ++ if (IN_SYSCALL(regs)) { ++ if (ptrace_id == PN_STOP_ENTRY ++#ifdef CONFIG_X86 ++ && SYSCALL_ERRNO(regs) == ENOSYS ++#endif ++ ) ++ SYSCALL_RESTART(regs); ++ else if (IN_ERROR(regs) && ++ syscall_is(current, regs, rt_sigtimedwait) && ++ (SYSCALL_ERRNO(regs) == EAGAIN || ++ SYSCALL_ERRNO(regs) == EINTR)) ++ SYSCALL_RESTART(regs); ++ } ++ return; ++ case PN_STOP_FORK: ++ /* fork */ ++ SYSCALL_SETRET(regs, current->ptrace_message); ++ dprintk("ptrace fork returns pid %ld\n", SYSCALL_RETVAL(regs)); ++ goto out; ++ case PN_STOP_VFORK: ++ /* after vfork */ ++ SYSCALL_SETRET(regs, current->ptrace_message); ++ dprintk("ptrace after vfork returns pid %ld\n", SYSCALL_RETVAL(regs)); ++ goto out; ++ case PN_STOP_SIGNAL: ++ /* normal case : dequeue signal */ ++ break; ++ case PN_STOP_EXIT: ++ dprintk("ptrace exit caught\n"); ++ current->ptrace &= ~PT_TRACE_EXIT; ++ spin_unlock_irq(¤t->sighand->siglock); ++ module_put(THIS_MODULE); ++ complete_and_exit(NULL, current->ptrace_message); ++ BUG(); ++ case PN_STOP_EXEC: ++ eprintk("ptrace after exec caught: must not happen\n"); ++ BUG(); ++ default: ++ eprintk("ptrace with unknown identity %d\n", ptrace_id); ++ BUG(); ++ } ++ ++ signr = current->exit_code; ++ if (signr == 0) { ++ dprintk("rlsi: canceled signal %d\n", info->si_signo); ++ goto out; ++ } ++ current->exit_code = 0; ++ ++ if (signr != info->si_signo) { ++ info->si_signo = signr; ++ info->si_errno = 0; ++ info->si_code = SI_USER; ++ info->si_pid = task_pid_vnr(current->parent); ++ info->si_uid = current->parent->uid; ++ } ++ ++ /* If the (new) signal is now blocked, requeue it. */ ++ if (sigismember(¤t->blocked, signr)) { ++ dprintk("going to requeue signal %d\n", signr); ++ goto out_resend_sig; ++ } ++ ++ ka = ¤t->sighand->action[signr-1]; ++ if (ka->sa.sa_handler == SIG_IGN) { ++ dprintk("going to resend signal %d (ignored)\n", signr); ++ goto out; ++ } ++ if (ka->sa.sa_handler != SIG_DFL) { ++ dprintk("going to resend signal %d (not SIG_DFL)\n", signr); ++ goto out_resend_sig; ++ } ++ if (signr == SIGCONT || ++ signr == SIGCHLD || ++ signr == SIGWINCH || ++ signr == SIGURG || ++ current->pid == 1) ++ goto out; ++ ++ /* All the rest, which we cannot handle are requeued. */ ++ dprintk("going to resend signal %d (sigh)\n", signr); ++out_resend_sig: ++ spin_unlock_irq(¤t->sighand->siglock); ++ send_sig_info(signr, info, current); ++ return; ++ ++out: ++ spin_unlock_irq(¤t->sighand->siglock); ++} ++ ++static void rst_finish_stop(void) ++{ ++ /* ... ++ * do_signal() -> ++ * get_signal_to_deliver() -> ++ * do_signal_stop() -> ++ * finish_stop() ++ * ++ * Normally after SIGCONT it will dequeue the next signal. If no signal ++ * is found, do_signal restarts syscall unconditionally. ++ * Otherwise signal handler is pushed on user stack. ++ */ ++ ++ dprintk("rfs: " CPT_FID "\n", CPT_TID(current)); ++ ++ clear_stop_state(current); ++ current->exit_code = 0; ++} ++ ++static void rst_restart_sys(void) ++{ ++ struct pt_regs *regs = task_pt_regs(current); ++ ++ /* This hook is supposed to be executed, when we have ++ * to complete some interrupted syscall. ++ */ ++ dprintk("rrs: " CPT_FID "\n", CPT_TID(current)); ++ ++ if (!IN_SYSCALL(regs) || !IN_ERROR(regs)) ++ return; ++ ++#ifdef __NR_pause ++ if (syscall_is(current,regs,pause)) { ++ if (SYSCALL_ERRNO(regs) == ERESTARTNOHAND) { ++ current->state = TASK_INTERRUPTIBLE; ++ schedule(); ++ } ++ } else ++#else ++ /* On this arch pause() is simulated with sigsuspend(). */ ++ if (syscall_is(current,regs,rt_sigsuspend)) { ++ if (SYSCALL_ERRNO(regs) == ERESTARTNOHAND) { ++ current->state = TASK_INTERRUPTIBLE; ++ schedule(); ++ } ++ } else ++#endif ++ if (syscall_is(current,regs,rt_sigtimedwait)) { ++ if (SYSCALL_ERRNO(regs) == EAGAIN || ++ SYSCALL_ERRNO(regs) == EINTR) { ++ SYSCALL_RESTART(regs); ++ } ++ } else if (syscall_is(current,regs,futex)) { ++ if (SYSCALL_ERRNO(regs) == EINTR && ++ !signal_pending(current)) { ++ SYSCALL_RESTART(regs); ++ } ++ } ++ ++ if (!signal_pending(current) && ++ !test_thread_flag(TIF_RESTORE_SIGMASK)) { ++ if (SYSCALL_ERRNO(regs) == ERESTARTSYS || ++ SYSCALL_ERRNO(regs) == ERESTARTNOINTR || ++ SYSCALL_ERRNO(regs) == ERESTARTNOHAND) { ++ SYSCALL_RESTART(regs); ++ } else if (SYSCALL_ERRNO(regs) == ERESTART_RESTARTBLOCK) { ++ int new = __NR_restart_syscall; ++#ifdef CONFIG_X86_64 ++ if (task_thread_info(current)->flags&_TIF_IA32) ++ new = __NR32_restart_syscall; ++#endif ++ SYSCALL_RESTART2(regs, new); ++ } ++ } ++} ++ ++#ifdef CONFIG_X86_32 ++ ++static int restore_registers(struct task_struct *tsk, struct pt_regs *regs, ++ struct cpt_task_image *ti, struct cpt_x86_regs *b, ++ struct resume_info **rip, struct cpt_context *ctx) ++{ ++ extern char i386_ret_from_resume; ++ ++ if (b->cpt_object != CPT_OBJ_X86_REGS) ++ return -EINVAL; ++ ++ tsk->thread.esp = (unsigned long) regs; ++ tsk->thread.esp0 = (unsigned long) (regs+1); ++ tsk->thread.eip = (unsigned long) &i386_ret_from_resume; ++ ++ tsk->thread.gs = decode_segment(b->cpt_gs); ++ tsk->thread.debugreg[0] = b->cpt_debugreg[0]; ++ tsk->thread.debugreg[1] = b->cpt_debugreg[1]; ++ tsk->thread.debugreg[2] = b->cpt_debugreg[2]; ++ tsk->thread.debugreg[3] = b->cpt_debugreg[3]; ++ tsk->thread.debugreg[4] = b->cpt_debugreg[4]; ++ tsk->thread.debugreg[5] = b->cpt_debugreg[5]; ++ tsk->thread.debugreg[6] = b->cpt_debugreg[6]; ++ tsk->thread.debugreg[7] = b->cpt_debugreg[7]; ++ ++ regs->ebx = b->cpt_ebx; ++ regs->ecx = b->cpt_ecx; ++ regs->edx = b->cpt_edx; ++ regs->esi = b->cpt_esi; ++ regs->edi = b->cpt_edi; ++ regs->ebp = b->cpt_ebp; ++ regs->eax = b->cpt_eax; ++ regs->xds = b->cpt_xds; ++ regs->xes = b->cpt_xes; ++ regs->orig_eax = b->cpt_orig_eax; ++ regs->eip = b->cpt_eip; ++ regs->xcs = b->cpt_xcs; ++ regs->eflags = b->cpt_eflags; ++ regs->esp = b->cpt_esp; ++ regs->xss = b->cpt_xss; ++ ++ regs->xcs = decode_segment(b->cpt_xcs); ++ regs->xss = decode_segment(b->cpt_xss); ++ regs->xds = decode_segment(b->cpt_xds); ++ regs->xes = decode_segment(b->cpt_xes); ++ regs->xfs = decode_segment(b->cpt_fs); ++ ++ tsk->thread.esp -= HOOK_RESERVE; ++ memset((void*)tsk->thread.esp, 0, HOOK_RESERVE); ++ *rip = (void*)tsk->thread.esp; ++ ++ return 0; ++} ++ ++#elif defined(CONFIG_X86_64) ++ ++static void xlate_ptregs_32_to_64(struct pt_regs *d, struct cpt_x86_regs *s) ++{ ++ memset(d, 0, sizeof(struct pt_regs)); ++ d->rbp = s->cpt_ebp; ++ d->rbx = s->cpt_ebx; ++ d->rax = (s32)s->cpt_eax; ++ d->rcx = s->cpt_ecx; ++ d->rdx = s->cpt_edx; ++ d->rsi = s->cpt_esi; ++ d->rdi = s->cpt_edi; ++ d->orig_rax = (s32)s->cpt_orig_eax; ++ d->rip = s->cpt_eip; ++ d->cs = s->cpt_xcs; ++ d->eflags = s->cpt_eflags; ++ d->rsp = s->cpt_esp; ++ d->ss = s->cpt_xss; ++} ++ ++static int restore_registers(struct task_struct *tsk, struct pt_regs *regs, ++ struct cpt_task_image *ti, struct cpt_obj_bits *hdr, ++ struct resume_info **rip, struct cpt_context *ctx) ++{ ++ if (hdr->cpt_object == CPT_OBJ_X86_64_REGS) { ++ struct cpt_x86_64_regs *b = (void*)hdr; ++ ++ tsk->thread.rsp = (unsigned long) regs; ++ tsk->thread.rsp0 = (unsigned long) (regs+1); ++ ++ tsk->thread.fs = b->cpt_fsbase; ++ tsk->thread.gs = b->cpt_gsbase; ++ tsk->thread.fsindex = decode_segment(b->cpt_fsindex); ++ tsk->thread.gsindex = decode_segment(b->cpt_gsindex); ++ tsk->thread.ds = decode_segment(b->cpt_ds); ++ tsk->thread.es = decode_segment(b->cpt_es); ++ tsk->thread.debugreg0 = b->cpt_debugreg[0]; ++ tsk->thread.debugreg1 = b->cpt_debugreg[1]; ++ tsk->thread.debugreg2 = b->cpt_debugreg[2]; ++ tsk->thread.debugreg3 = b->cpt_debugreg[3]; ++ tsk->thread.debugreg6 = b->cpt_debugreg[6]; ++ tsk->thread.debugreg7 = b->cpt_debugreg[7]; ++ ++ memcpy(regs, &b->cpt_r15, sizeof(struct pt_regs)); ++ ++ tsk->thread.userrsp = regs->rsp; ++ regs->cs = decode_segment(b->cpt_cs); ++ regs->ss = decode_segment(b->cpt_ss); ++ } else if (hdr->cpt_object == CPT_OBJ_X86_REGS) { ++ struct cpt_x86_regs *b = (void*)hdr; ++ ++ tsk->thread.rsp = (unsigned long) regs; ++ tsk->thread.rsp0 = (unsigned long) (regs+1); ++ ++ tsk->thread.fs = 0; ++ tsk->thread.gs = 0; ++ tsk->thread.fsindex = decode_segment(b->cpt_fs); ++ tsk->thread.gsindex = decode_segment(b->cpt_gs); ++ tsk->thread.debugreg0 = b->cpt_debugreg[0]; ++ tsk->thread.debugreg1 = b->cpt_debugreg[1]; ++ tsk->thread.debugreg2 = b->cpt_debugreg[2]; ++ tsk->thread.debugreg3 = b->cpt_debugreg[3]; ++ tsk->thread.debugreg6 = b->cpt_debugreg[6]; ++ tsk->thread.debugreg7 = b->cpt_debugreg[7]; ++ ++ xlate_ptregs_32_to_64(regs, b); ++ ++ tsk->thread.userrsp = regs->rsp; ++ regs->cs = decode_segment(b->cpt_xcs); ++ regs->ss = decode_segment(b->cpt_xss); ++ tsk->thread.ds = decode_segment(b->cpt_xds); ++ tsk->thread.es = decode_segment(b->cpt_xes); ++ } else { ++ return -EINVAL; ++ } ++ ++ tsk->thread.rsp -= HOOK_RESERVE; ++ memset((void*)tsk->thread.rsp, 0, HOOK_RESERVE); ++ *rip = (void*)tsk->thread.rsp; ++ return 0; ++} ++ ++#elif defined(CONFIG_IA64) ++ ++#define MASK(nbits) ((1UL << (nbits)) - 1) /* mask with NBITS bits set */ ++ ++#define PUT_BITS(first, last, nat) \ ++ ({ \ ++ unsigned long bit = ia64_unat_pos(&pt->r##first); \ ++ unsigned long nbits = (last - first + 1); \ ++ unsigned long mask = MASK(nbits) << first; \ ++ long dist; \ ++ if (bit < first) \ ++ dist = 64 + bit - first; \ ++ else \ ++ dist = bit - first; \ ++ ia64_rotl(nat & mask, dist); \ ++ }) ++ ++unsigned long ++ia64_put_scratch_nat_bits (struct pt_regs *pt, unsigned long nat) ++{ ++ unsigned long scratch_unat; ++ ++ /* ++ * Registers that are stored consecutively in struct pt_regs ++ * can be handled in parallel. If the register order in ++ * struct_pt_regs changes, this code MUST be updated. ++ */ ++ scratch_unat = PUT_BITS( 1, 1, nat); ++ scratch_unat |= PUT_BITS( 2, 3, nat); ++ scratch_unat |= PUT_BITS(12, 13, nat); ++ scratch_unat |= PUT_BITS(14, 14, nat); ++ scratch_unat |= PUT_BITS(15, 15, nat); ++ scratch_unat |= PUT_BITS( 8, 11, nat); ++ scratch_unat |= PUT_BITS(16, 31, nat); ++ ++ return scratch_unat; ++ ++} ++ ++static unsigned long ++ia64_put_saved_nat_bits (struct switch_stack *pt, unsigned long nat) ++{ ++ unsigned long scratch_unat; ++ ++ scratch_unat = PUT_BITS( 4, 7, nat); ++ ++ return scratch_unat; ++ ++} ++ ++#undef PUT_BITS ++ ++ ++static int restore_registers(struct task_struct *tsk, struct pt_regs *pt, ++ struct cpt_task_image *ti, ++ struct cpt_ia64_regs *r, ++ struct resume_info **rip, ++ struct cpt_context *ctx) ++{ ++ extern char ia64_ret_from_resume; ++ struct switch_stack *sw; ++ struct resume_info *ri; ++ struct ia64_psr *psr = ia64_psr(pt); ++ void *krbs = (void *)tsk + IA64_RBS_OFFSET; ++ unsigned long reg; ++ ++ if (r->cpt_object != CPT_OBJ_IA64_REGS) ++ return -EINVAL; ++ ++ if (r->num_regs > 96) { ++ eprintk(CPT_FID " too much RSE regs %lu\n", ++ CPT_TID(tsk), r->num_regs); ++ return -EINVAL; ++ } ++ ++ *rip = ri = ((void*)pt) - HOOK_RESERVE; ++ sw = ((struct switch_stack *) ri) - 1; ++ ++ memmove(sw, (void*)tsk->thread.ksp + 16, sizeof(struct switch_stack)); ++ memset(ri, 0, HOOK_RESERVE); ++ ++ /* gr 1,2-3,8-11,12-13,14,15,16-31 are on pt_regs */ ++ memcpy(&pt->r1, &r->gr[1], 8*(2-1)); ++ memcpy(&pt->r2, &r->gr[2], 8*(4-2)); ++ memcpy(&pt->r8, &r->gr[8], 8*(12-8)); ++ memcpy(&pt->r12, &r->gr[12], 8*(14-12)); ++ memcpy(&pt->r14, &r->gr[14], 8*(15-14)); ++ memcpy(&pt->r15, &r->gr[15], 8*(16-15)); ++ memcpy(&pt->r16, &r->gr[16], 8*(32-16)); ++ ++ pt->b0 = r->br[0]; ++ pt->b6 = r->br[6]; ++ pt->b7 = r->br[7]; ++ ++ pt->ar_bspstore = r->ar_bspstore; ++ pt->ar_unat = r->ar_unat; ++ pt->ar_pfs = r->ar_pfs; ++ pt->ar_ccv = r->ar_ccv; ++ pt->ar_fpsr = r->ar_fpsr; ++ pt->ar_csd = r->ar_csd; ++ pt->ar_ssd = r->ar_ssd; ++ pt->ar_rsc = r->ar_rsc; ++ ++ pt->cr_iip = r->cr_iip; ++ pt->cr_ipsr = r->cr_ipsr; ++ ++ pt->pr = r->pr; ++ ++ pt->cr_ifs = r->cfm; ++ ++ /* fpregs 6..9,10..11 are in pt_regs */ ++ memcpy(&pt->f6, &r->fr[2*6], 16*(10-6)); ++ memcpy(&pt->f10, &r->fr[2*10], 16*(12-10)); ++ /* fpreg 12..15 are on switch stack */ ++ memcpy(&sw->f12, &r->fr[2*12], 16*(16-12)); ++ /* fpregs 32...127 */ ++ tsk->thread.flags |= IA64_THREAD_FPH_VALID; ++ memcpy(tsk->thread.fph, &r->fr[32*2], 16*(128-32)); ++ ia64_drop_fpu(tsk); ++ psr->dfh = 1; ++ ++ memcpy(&sw->r4, &r->gr[4], 8*(8-4)); ++ memcpy(&sw->b1, &r->br[1], 8*(6-1)); ++ sw->ar_lc = r->ar_lc; ++ ++ memcpy(&sw->f2, &r->fr[2*2], 16*(6-2)); ++ memcpy(&sw->f16, &r->fr[2*16], 16*(32-16)); ++ ++ sw->caller_unat = 0; ++ sw->ar_fpsr = pt->ar_fpsr; ++ sw->ar_unat = 0; ++ if (r->nat[0] & 0xFFFFFF0FUL) ++ sw->caller_unat = ia64_put_scratch_nat_bits(pt, r->nat[0]); ++ if (r->nat[0] & 0xF0) ++ sw->ar_unat = ia64_put_saved_nat_bits(sw, r->nat[0]); ++ ++ sw->ar_bspstore = (unsigned long)ia64_rse_skip_regs(krbs, r->num_regs); ++ memset(krbs, 0, (void*)sw->ar_bspstore - krbs); ++ sw->ar_rnat = 0; ++ sw->ar_pfs = 0; ++ ++ /* This is tricky. When we are in syscall, we have frame ++ * of output register (sometimes, plus one input reg sometimes). ++ * It is not so easy to restore such frame, RSE optimizes ++ * and does not fetch those regs from backstore. So, we restore ++ * the whole frame as local registers, and then repartition it ++ * in ia64_ret_from_resume(). ++ */ ++ if ((long)pt->cr_ifs >= 0) { ++ unsigned long out = (r->cfm&0x7F) - ((r->cfm>>7)&0x7F); ++ sw->ar_pfs = out | (out<<7); ++ } ++ if (r->ar_ec) ++ sw->ar_pfs |= (r->ar_ec & 0x3F) << 52; ++ ++ for (reg = 0; reg < r->num_regs; reg++) { ++ unsigned long *ptr = ia64_rse_skip_regs(krbs, reg); ++ unsigned long *rnatp; ++ unsigned long set_rnat = 0; ++ ++ *ptr = r->gr[32+reg]; ++ ++ if (reg < 32) ++ set_rnat = (r->nat[0] & (1UL<<(reg+32))); ++ else ++ set_rnat = (r->nat[1] & (1UL<<(reg-32))); ++ ++ if (set_rnat) { ++ rnatp = ia64_rse_rnat_addr(ptr); ++ if ((unsigned long)rnatp >= sw->ar_bspstore) ++ rnatp = &sw->ar_rnat; ++ *rnatp |= (1UL<b0 = (unsigned long) &ia64_ret_from_resume; ++ tsk->thread.ksp = (unsigned long) sw - 16; ++ ++#define PRED_LEAVE_SYSCALL 1 /* TRUE iff leave from syscall */ ++#define PRED_KERNEL_STACK 2 /* returning to kernel-stacks? */ ++#define PRED_USER_STACK 3 /* returning to user-stacks? */ ++#define PRED_SYSCALL 4 /* inside a system call? */ ++#define PRED_NON_SYSCALL 5 /* complement of PRED_SYSCALL */ ++ ++ pt->loadrs = r->loadrs; ++ sw->pr = 0; ++ sw->pr &= ~(1UL << PRED_LEAVE_SYSCALL); ++ sw->pr &= ~((1UL << PRED_SYSCALL) | (1UL << PRED_NON_SYSCALL)); ++ sw->pr &= ~(1UL << PRED_KERNEL_STACK); ++ sw->pr |= (1UL << PRED_USER_STACK); ++ if ((long)pt->cr_ifs < 0) { ++ sw->pr |= (1UL << PRED_NON_SYSCALL); ++ } else { ++ sw->pr |= ((1UL << PRED_SYSCALL) | (1UL << PRED_LEAVE_SYSCALL)); ++ } ++ ++ return 0; ++} ++#endif ++ ++asmlinkage void rst_resume_work(struct resume_info *ri) ++{ ++ if (ri->hooks & (1<tid_ptrs); ++ if (ri->hooks & (1<hooks & (1<hooks & (1<thread.i387.fxsave.mxcsr &= 0x0000ffbf; ++#endif ++} ++ ++int rst_restore_process(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ struct task_struct *tsk = obj->o_obj; ++ struct cpt_task_image *ti = obj->o_image; ++ struct pt_regs * regs; ++ struct cpt_object_hdr *b; ++ struct cpt_siginfo_image *lsi = NULL; ++ struct group_info *gids, *ogids; ++ struct resume_info *ri = NULL; ++ int i; ++ int err = 0; ++#ifdef CONFIG_BEANCOUNTERS ++ struct task_beancounter *tbc; ++ struct user_beancounter *new_bc, *old_bc; ++#endif ++ ++ if (tsk == NULL) { ++ eprintk_ctx("oops, task %d/%s is missing\n", ti->cpt_pid, ti->cpt_comm); ++ return -EFAULT; ++ } ++ ++ wait_task_inactive(tsk); ++#ifdef CONFIG_BEANCOUNTERS ++ tbc = &tsk->task_bc; ++ new_bc = rst_lookup_ubc(ti->cpt_exec_ub, ctx); ++ err = virtinfo_notifier_call(VITYPE_SCP, ++ VIRTINFO_SCP_RSTTSK, new_bc); ++ if (err & NOTIFY_FAIL) { ++ put_beancounter(new_bc); ++ return -ECHRNG; ++ } ++ old_bc = tbc->exec_ub; ++ if ((err & VIRTNOTIFY_CHANGE) && old_bc != new_bc) { ++ dprintk(" *** replacing ub %p by %p for %p (%d %s)\n", ++ old_bc, new_bc, tsk, ++ tsk->pid, tsk->comm); ++ tbc->exec_ub = new_bc; ++ new_bc = old_bc; ++ } ++ put_beancounter(new_bc); ++#endif ++ regs = task_pt_regs(tsk); ++ ++ if (!tsk->exit_state) { ++ tsk->lock_depth = -1; ++#ifdef CONFIG_PREEMPT ++ task_thread_info(tsk)->preempt_count--; ++#endif ++ } ++ ++ if (tsk->static_prio != ti->cpt_static_prio) ++ set_user_nice(tsk, PRIO_TO_NICE((s32)ti->cpt_static_prio)); ++ ++ cpt_sigset_import(&tsk->blocked, ti->cpt_sigblocked); ++ cpt_sigset_import(&tsk->real_blocked, ti->cpt_sigrblocked); ++ cpt_sigset_import(&tsk->saved_sigmask, ti->cpt_sigsuspend_blocked); ++ cpt_sigset_import(&tsk->pending.signal, ti->cpt_sigpending); ++ ++ tsk->uid = ti->cpt_uid; ++ tsk->euid = ti->cpt_euid; ++ tsk->suid = ti->cpt_suid; ++ tsk->fsuid = ti->cpt_fsuid; ++ tsk->gid = ti->cpt_gid; ++ tsk->egid = ti->cpt_egid; ++ tsk->sgid = ti->cpt_sgid; ++ tsk->fsgid = ti->cpt_fsgid; ++#ifdef CONFIG_IA64 ++ SET_UNALIGN_CTL(tsk, ti->cpt_prctl_uac); ++ SET_FPEMU_CTL(tsk, ti->cpt_prctl_fpemu); ++#endif ++ memcpy(&tsk->cap_effective, &ti->cpt_ecap, sizeof(tsk->cap_effective)); ++ memcpy(&tsk->cap_inheritable, &ti->cpt_icap, sizeof(tsk->cap_inheritable)); ++ memcpy(&tsk->cap_permitted, &ti->cpt_pcap, sizeof(tsk->cap_permitted)); ++ tsk->keep_capabilities = (ti->cpt_keepcap != 0); ++ tsk->did_exec = (ti->cpt_did_exec != 0); ++ gids = groups_alloc(ti->cpt_ngids); ++ ogids = tsk->group_info; ++ if (gids) { ++ int i; ++ for (i=0; i<32; i++) ++ gids->small_block[i] = ti->cpt_gids[i]; ++ tsk->group_info = gids; ++ } ++ if (ogids) ++ put_group_info(ogids); ++ tsk->utime = ti->cpt_utime; ++ tsk->stime = ti->cpt_stime; ++ if (ctx->image_version == CPT_VERSION_8) ++ tsk->start_time = _ns_to_timespec(ti->cpt_starttime*TICK_NSEC); ++ else ++ cpt_timespec_import(&tsk->start_time, ti->cpt_starttime); ++ _set_normalized_timespec(&tsk->start_time, ++ tsk->start_time.tv_sec + ++ VE_TASK_INFO(tsk)->owner_env->start_timespec.tv_sec, ++ tsk->start_time.tv_nsec + ++ VE_TASK_INFO(tsk)->owner_env->start_timespec.tv_nsec); ++ ++ tsk->nvcsw = ti->cpt_nvcsw; ++ tsk->nivcsw = ti->cpt_nivcsw; ++ tsk->min_flt = ti->cpt_min_flt; ++ tsk->maj_flt = ti->cpt_maj_flt; ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,8) ++ tsk->cutime = ti->cpt_cutime; ++ tsk->cstime = ti->cpt_cstime; ++ tsk->cnvcsw = ti->cpt_cnvcsw; ++ tsk->cnivcsw = ti->cpt_cnivcsw; ++ tsk->cmin_flt = ti->cpt_cmin_flt; ++ tsk->cmaj_flt = ti->cpt_cmaj_flt; ++ ++ BUILD_BUG_ON(RLIM_NLIMITS > CPT_RLIM_NLIMITS); ++ ++ for (i=0; irlim[i].rlim_cur = ti->cpt_rlim_cur[i]; ++ tsk->rlim[i].rlim_max = ti->cpt_rlim_max[i]; ++ } ++#else ++ if (thread_group_leader(tsk) && tsk->signal) { ++ tsk->signal->utime = ti->cpt_utime; ++ tsk->signal->stime = ti->cpt_stime; ++ tsk->signal->cutime = ti->cpt_cutime; ++ tsk->signal->cstime = ti->cpt_cstime; ++ tsk->signal->nvcsw = ti->cpt_nvcsw; ++ tsk->signal->nivcsw = ti->cpt_nivcsw; ++ tsk->signal->cnvcsw = ti->cpt_cnvcsw; ++ tsk->signal->cnivcsw = ti->cpt_cnivcsw; ++ tsk->signal->min_flt = ti->cpt_min_flt; ++ tsk->signal->maj_flt = ti->cpt_maj_flt; ++ tsk->signal->cmin_flt = ti->cpt_cmin_flt; ++ tsk->signal->cmaj_flt = ti->cpt_cmaj_flt; ++ ++ for (i=0; isignal->rlim[i].rlim_cur = ti->cpt_rlim_cur[i]; ++ tsk->signal->rlim[i].rlim_max = ti->cpt_rlim_max[i]; ++ } ++ } ++#endif ++ ++#ifdef CONFIG_X86 ++ for (i=0; i<3; i++) { ++ if (i >= GDT_ENTRY_TLS_ENTRIES) { ++ eprintk_ctx("too many tls descs\n"); ++ } else { ++#ifndef CONFIG_X86_64 ++ tsk->thread.tls_array[i].a = ti->cpt_tls[i]&0xFFFFFFFF; ++ tsk->thread.tls_array[i].b = ti->cpt_tls[i]>>32; ++#else ++ tsk->thread.tls_array[i] = ti->cpt_tls[i]; ++#endif ++ } ++ } ++#endif ++ ++ clear_stopped_child_used_math(tsk); ++ ++ b = (void *)(ti+1); ++ while ((void*)b < ((void*)ti) + ti->cpt_next) { ++ /* Siginfo objects are at the end of obj array */ ++ if (b->cpt_object == CPT_OBJ_SIGINFO) { ++ struct ve_struct *env = set_exec_env(VE_TASK_INFO(tsk)->owner_env); ++ restore_sigqueue(tsk, &tsk->pending, (unsigned long)b, (unsigned long)ti + ti->cpt_next); ++ set_exec_env(env); ++ break; ++ } ++ ++ switch (b->cpt_object) { ++#ifdef CONFIG_X86 ++ case CPT_OBJ_BITS: ++ if (b->cpt_content == CPT_CONTENT_X86_FPUSTATE && ++ cpu_has_fxsr) { ++ memcpy(&tsk->thread.i387, ++ (void*)b + b->cpt_hdrlen, ++ sizeof(struct i387_fxsave_struct)); ++ rst_apply_mxcsr_mask(tsk); ++ if (ti->cpt_used_math) ++ set_stopped_child_used_math(tsk); ++ } ++#ifndef CONFIG_X86_64 ++ else if (b->cpt_content == CPT_CONTENT_X86_FPUSTATE_OLD && ++ !cpu_has_fxsr) { ++ memcpy(&tsk->thread.i387, ++ (void*)b + b->cpt_hdrlen, ++ sizeof(struct i387_fsave_struct)); ++ if (ti->cpt_used_math) ++ set_stopped_child_used_math(tsk); ++ } ++#endif ++ break; ++#endif ++ case CPT_OBJ_LASTSIGINFO: ++ lsi = (void*)b; ++ break; ++ case CPT_OBJ_X86_REGS: ++ case CPT_OBJ_X86_64_REGS: ++ case CPT_OBJ_IA64_REGS: ++ if (restore_registers(tsk, regs, ti, (void*)b, &ri, ctx)) { ++ eprintk_ctx("cannot restore registers: image is corrupted\n"); ++ return -EINVAL; ++ } ++ break; ++ case CPT_OBJ_SIGALTSTACK: { ++ struct cpt_sigaltstack_image *sas; ++ sas = (struct cpt_sigaltstack_image *)b; ++ tsk->sas_ss_sp = sas->cpt_stack; ++ tsk->sas_ss_size = sas->cpt_stacksize; ++ break; ++ } ++ case CPT_OBJ_TASK_AUX: { ++ struct cpt_task_aux_image *ai; ++ ai = (struct cpt_task_aux_image *)b; ++ tsk->robust_list = cpt_ptr_import(ai->cpt_robust_list); ++#ifdef CONFIG_X86_64 ++#ifdef CONFIG_COMPAT ++ if (task_thread_info(tsk)->flags&_TIF_IA32) { ++ tsk->robust_list = (void __user *)NULL; ++ tsk->compat_robust_list = cpt_ptr_import(ai->cpt_robust_list); ++ } ++#endif ++#endif ++ break; ++ } ++ } ++ b = ((void*)b) + b->cpt_next; ++ } ++ ++ if (ri == NULL && !(ti->cpt_state & (EXIT_ZOMBIE|EXIT_DEAD))) { ++ eprintk_ctx("missing register info\n"); ++ return -EINVAL; ++ } ++ ++ if (ti->cpt_ppid != ti->cpt_rppid) { ++ struct task_struct *parent; ++ struct ve_struct *env = set_exec_env(VE_TASK_INFO(tsk)->owner_env); ++ write_lock_irq(&tasklist_lock); ++ parent = find_task_by_vpid(ti->cpt_ppid); ++ if (parent && parent != tsk->parent) { ++ list_add(&tsk->ptrace_list, &tsk->parent->ptrace_children); ++ remove_parent(tsk); ++ tsk->parent = parent; ++ add_parent(tsk); ++ } ++ write_unlock_irq(&tasklist_lock); ++ set_exec_env(env); ++ } ++ ++ tsk->ptrace_message = ti->cpt_ptrace_message; ++ tsk->pn_state = ti->cpt_pn_state; ++ tsk->stopped_state = ti->cpt_stopped_state; ++ task_thread_info(tsk)->flags = ti->cpt_thrflags; ++ ++ /* The image was created with kernel < 2.6.16, while ++ * task hanged in sigsuspend -> do_signal. ++ * ++ * FIXME! This needs more brain efforts... ++ */ ++ if (ti->cpt_sigsuspend_state) { ++ task_thread_info(tsk)->flags |= _TIF_RESTORE_SIGMASK; ++ } ++ ++#ifdef CONFIG_X86_64 ++ task_thread_info(tsk)->flags |= _TIF_FORK | _TIF_RESUME; ++ if (!ti->cpt_64bit) ++ task_thread_info(tsk)->flags |= _TIF_IA32; ++#endif ++ ++#ifdef CONFIG_X86_32 ++ do { ++ if (regs->orig_eax == __NR__newselect && regs->edi) { ++ struct timeval tv; ++ if (access_process_vm(tsk, regs->edi, &tv, ++ sizeof(tv), 0) != sizeof(tv)) { ++ wprintk_ctx("task %d/%d(%s): Error 1 in access_process_vm: edi %ld\n", ++ task_pid_vnr(tsk), tsk->pid, tsk->comm, ++ regs->edi); ++ break; ++ } ++ dprintk_ctx("task %d/%d(%s): Old timeval in newselect: %ld.%ld\n", ++ task_pid_vnr(tsk), tsk->pid, tsk->comm, ++ tv.tv_sec, tv.tv_usec); ++ tv.tv_sec -= ctx->delta_time.tv_sec; ++ if (tv.tv_usec < ctx->delta_time.tv_nsec / 1000) { ++ tv.tv_usec += 1000000 - ctx->delta_time.tv_nsec / 1000; ++ tv.tv_sec--; ++ } else { ++ tv.tv_usec -= ctx->delta_time.tv_nsec / 1000; ++ } ++ if (tv.tv_sec < 0) { ++ tv.tv_sec = 0; ++ tv.tv_usec = 0; ++ } ++ dprintk_ctx("task %d/%d(%s): New timeval in newselect: %ld.%ld\n", ++ task_pid_vnr(tsk), tsk->pid, tsk->comm, ++ tv.tv_sec, tv.tv_usec); ++ if (access_process_vm(tsk, regs->edi, &tv, ++ sizeof(tv), 1) != sizeof(tv)) { ++ wprintk_ctx("task %d/%d(%s): Error 1 in access_process_vm write: edi %ld\n", ++ task_pid_vnr(tsk), tsk->pid, tsk->comm, regs->edi); ++ } ++ ++ } else if (regs->orig_eax == __NR_select && regs->edi) { ++ struct { ++ unsigned long n; ++ fd_set __user *inp, *outp, *exp; ++ struct timeval __user *tvp; ++ } a; ++ struct timeval tv; ++ if (access_process_vm(tsk, regs->ebx, &a, ++ sizeof(a), 0) != sizeof(a)) { ++ wprintk_ctx("task %d: Error 2 in access_process_vm\n", tsk->pid); ++ break; ++ } ++ if (access_process_vm(tsk, (unsigned long)a.tvp, ++ &tv, sizeof(tv), 0) != sizeof(tv)) { ++ wprintk_ctx("task %d: Error 3 in access_process_vm\n", tsk->pid); ++ break; ++ } ++ dprintk_ctx("task %d: Old timeval in select: %ld.%ld\n", ++ tsk->pid, tv.tv_sec, tv.tv_usec); ++ tv.tv_sec -= ctx->delta_time.tv_sec; ++ if (tv.tv_usec < ctx->delta_time.tv_nsec / 1000) { ++ tv.tv_usec += 1000000 - ctx->delta_time.tv_nsec / 1000; ++ tv.tv_sec--; ++ } else { ++ tv.tv_usec -= ctx->delta_time.tv_nsec / 1000; ++ } ++ if (tv.tv_sec < 0) { ++ tv.tv_sec = 0; ++ tv.tv_usec = 0; ++ } ++ dprintk_ctx("task %d: New timeval in select: %ld.%ld\n", ++ tsk->pid, tv.tv_sec, tv.tv_usec); ++ if (access_process_vm(tsk, (unsigned long)a.tvp, ++ &tv, sizeof(tv), 1) != sizeof(tv)) { ++ wprintk_ctx("task %d: Error 3 in access_process_vm write\n", tsk->pid); ++ } ++ } ++ } while (0); ++#endif ++ ++ if (ri && IN_SYSCALL(regs) && IN_ERROR(regs)) { ++ switch (SYSCALL_ERRNO(regs)) { ++ case ERESTARTSYS: ++ case ERESTARTNOINTR: ++ case ERESTARTNOHAND: ++ case ERESTART_RESTARTBLOCK: ++ case EAGAIN: ++ case EINTR: ++ ri->hooks |= (1<pn_state)) { ++ /* ... -> ptrace_notify() ++ * or ++ * ... -> do_signal() -> get_signal_to_deliver() -> ++ * ptrace stop ++ */ ++ tsk->last_siginfo = &ri->last_siginfo; ++ ri->hooks |= (1<last_siginfo, lsi); ++ } ++ ++ tsk->ptrace = ti->cpt_ptrace; ++ tsk->flags = ti->cpt_flags & ~PF_FROZEN; ++ clear_tsk_thread_flag(tsk, TIF_FREEZE); ++ tsk->exit_signal = ti->cpt_exit_signal; ++ ++ if (ri && tsk->stopped_state) { ++ dprintk_ctx("finish_stop\n"); ++ if (ti->cpt_state != TASK_STOPPED) ++ eprintk_ctx("Hellooo, state is %u\n", (unsigned)ti->cpt_state); ++ ri->hooks |= (1<cpt_set_tid || ti->cpt_clear_tid)) { ++ ri->hooks |= (1<tid_ptrs[0] = ti->cpt_clear_tid; ++ ri->tid_ptrs[1] = ti->cpt_set_tid; ++ dprintk_ctx("settids\n"); ++ } ++ ++ if (ri && ri->hooks && ++ !(ti->cpt_state & (EXIT_ZOMBIE|EXIT_DEAD))) { ++ if (try_module_get(THIS_MODULE)) ++ ri->hook = rst_resume_work; ++ } ++ ++ if (ti->cpt_state == TASK_TRACED) ++ tsk->state = TASK_TRACED; ++ else if (ti->cpt_state & (EXIT_ZOMBIE|EXIT_DEAD)) { ++ tsk->signal->it_virt_expires = 0; ++ tsk->signal->it_prof_expires = 0; ++ if (tsk->state != EXIT_DEAD) ++ eprintk_ctx("oops, schedule() did not make us dead\n"); ++ } ++ ++ if (thread_group_leader(tsk) && ++ ti->cpt_it_real_value && ++ !(ti->cpt_state & (EXIT_ZOMBIE|EXIT_DEAD))) { ++ ktime_t val; ++ s64 nsec; ++ ++ nsec = ti->cpt_it_real_value; ++ val.tv64 = 0; ++ ++ if (ctx->image_version < CPT_VERSION_9) ++ nsec *= TICK_NSEC; ++ ++ val = ktime_add_ns(val, nsec - ctx->delta_nsec); ++ if (val.tv64 <= 0) ++ val.tv64 = NSEC_PER_USEC; ++ dprintk("rst itimer " CPT_FID " +%Ld %Lu\n", CPT_TID(tsk), ++ (long long)val.tv64, ++ (unsigned long long)ti->cpt_it_real_value); ++ ++ spin_lock_irq(&tsk->sighand->siglock); ++ if (hrtimer_try_to_cancel(&tsk->signal->real_timer) >= 0) { ++ /* FIXME. Check!!!! */ ++ hrtimer_start(&tsk->signal->real_timer, val, HRTIMER_MODE_REL); ++ } else { ++ wprintk_ctx("Timer clash. Impossible?\n"); ++ } ++ spin_unlock_irq(&tsk->sighand->siglock); ++ ++ dprintk_ctx("itimer " CPT_FID " +%Lu\n", CPT_TID(tsk), ++ (unsigned long long)val.tv64); ++ } ++ ++ module_put(THIS_MODULE); ++ } ++ return 0; ++} +Index: kernel/kernel/cpt/rst_socket.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_socket.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,918 @@ ++/* ++ * ++ * kernel/cpt/rst_socket.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_mm.h" ++#include "cpt_files.h" ++#include "cpt_socket.h" ++#include "cpt_kernel.h" ++ ++#include "cpt_syscalls.h" ++ ++ ++static int setup_sock_common(struct sock *sk, struct cpt_sock_image *si, ++ loff_t pos, struct cpt_context *ctx) ++{ ++ struct timeval tmptv; ++ ++ if (sk->sk_socket) { ++ sk->sk_socket->flags = si->cpt_ssflags; ++ sk->sk_socket->state = si->cpt_sstate; ++ } ++ sk->sk_reuse = si->cpt_reuse; ++ sk->sk_shutdown = si->cpt_shutdown; ++ sk->sk_userlocks = si->cpt_userlocks; ++ sk->sk_no_check = si->cpt_no_check; ++ sock_reset_flag(sk, SOCK_DBG); ++ if (si->cpt_debug) ++ sock_set_flag(sk, SOCK_DBG); ++ sock_reset_flag(sk, SOCK_RCVTSTAMP); ++ if (si->cpt_rcvtstamp) ++ sock_set_flag(sk, SOCK_RCVTSTAMP); ++ sock_reset_flag(sk, SOCK_LOCALROUTE); ++ if (si->cpt_localroute) ++ sock_set_flag(sk, SOCK_LOCALROUTE); ++ sk->sk_protocol = si->cpt_protocol; ++ sk->sk_err = si->cpt_err; ++ sk->sk_err_soft = si->cpt_err_soft; ++ sk->sk_priority = si->cpt_priority; ++ sk->sk_rcvlowat = si->cpt_rcvlowat; ++ sk->sk_rcvtimeo = si->cpt_rcvtimeo; ++ if (si->cpt_rcvtimeo == CPT_NULL) ++ sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; ++ sk->sk_sndtimeo = si->cpt_sndtimeo; ++ if (si->cpt_sndtimeo == CPT_NULL) ++ sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; ++ sk->sk_rcvbuf = si->cpt_rcvbuf; ++ sk->sk_sndbuf = si->cpt_sndbuf; ++ sk->sk_bound_dev_if = si->cpt_bound_dev_if; ++ sk->sk_flags = si->cpt_flags; ++ sk->sk_lingertime = si->cpt_lingertime; ++ if (si->cpt_lingertime == CPT_NULL) ++ sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT; ++ sk->sk_peercred.pid = si->cpt_peer_pid; ++ sk->sk_peercred.uid = si->cpt_peer_uid; ++ sk->sk_peercred.gid = si->cpt_peer_gid; ++ cpt_timeval_import(&tmptv, si->cpt_stamp); ++ sk->sk_stamp = timeval_to_ktime(tmptv); ++ return 0; ++} ++ ++static struct file *sock_mapfile(struct socket *sock) ++{ ++ int fd = sock_map_fd(sock); ++ ++ if (fd >= 0) { ++ struct file *file = sock->file; ++ get_file(file); ++ sc_close(fd); ++ return file; ++ } ++ return ERR_PTR(fd); ++} ++ ++/* Assumption is that /tmp exists and writable. ++ * In previous versions we assumed that listen() will autobind ++ * the socket. It does not do this for AF_UNIX by evident reason: ++ * socket in abstract namespace is accessible, unlike socket bound ++ * to deleted FS object. ++ */ ++ ++static int ++select_deleted_name(char * name, cpt_context_t *ctx) ++{ ++ int i; ++ ++ for (i=0; i<100; i++) { ++ struct nameidata nd; ++ unsigned int rnd = net_random(); ++ ++ sprintf(name, "/tmp/SOCK.%08x", rnd); ++ ++ if (path_lookup(name, 0, &nd) != 0) ++ return 0; ++ ++ path_release(&nd); ++ } ++ ++ eprintk_ctx("failed to allocate deleted socket inode\n"); ++ return -ELOOP; ++} ++ ++static int ++bind_unix_socket(struct socket *sock, struct cpt_sock_image *si, ++ cpt_context_t *ctx) ++{ ++ int err; ++ char *name; ++ struct sockaddr* addr; ++ int addrlen; ++ struct sockaddr_un sun; ++ struct nameidata nd; ++ ++ if ((addrlen = si->cpt_laddrlen) <= 2) ++ return 0; ++ ++ nd.dentry = NULL; ++ name = ((char*)si->cpt_laddr) + 2; ++ addr = (struct sockaddr *)si->cpt_laddr; ++ ++ if (name[0]) { ++ if (path_lookup(name, 0, &nd)) ++ nd.dentry = NULL; ++ ++ if (si->cpt_deleted) { ++ if (nd.dentry == NULL && ++ sock->ops->bind(sock, addr, addrlen) == 0) { ++ sc_unlink(name); ++ return 0; ++ } ++ ++ addr = (struct sockaddr*)&sun; ++ addr->sa_family = AF_UNIX; ++ name = ((char*)addr) + 2; ++ err = select_deleted_name(name, ctx); ++ if (err) ++ goto out; ++ addrlen = 2 + strlen(name); ++ } else if (nd.dentry) { ++ if (!S_ISSOCK(nd.dentry->d_inode->i_mode)) { ++ eprintk_ctx("bind_unix_socket: not a socket dentry\n"); ++ err = -EINVAL; ++ goto out; ++ } ++ sc_unlink(name); ++ } ++ } ++ ++ err = sock->ops->bind(sock, addr, addrlen); ++ ++ if (!err && name[0]) { ++ if (nd.dentry) { ++ sc_chown(name, nd.dentry->d_inode->i_uid, ++ nd.dentry->d_inode->i_gid); ++ sc_chmod(name, nd.dentry->d_inode->i_mode); ++ } ++ if (si->cpt_deleted) ++ sc_unlink(name); ++ } ++ ++out: ++ if (nd.dentry) ++ path_release(&nd); ++ return err; ++} ++ ++static int fixup_unix_address(struct socket *sock, struct cpt_sock_image *si, ++ struct cpt_context *ctx) ++{ ++ struct sock *sk = sock->sk; ++ cpt_object_t *obj; ++ struct sock *parent; ++ ++ if (sk->sk_family != AF_UNIX || sk->sk_state == TCP_LISTEN) ++ return 0; ++ ++ if (si->cpt_parent == -1) ++ return bind_unix_socket(sock, si, ctx); ++ ++ obj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, si->cpt_parent, ctx); ++ if (!obj) ++ return 0; ++ ++ parent = obj->o_obj; ++ if (unix_sk(parent)->addr) { ++ if (unix_sk(sk)->addr && ++ atomic_dec_and_test(&unix_sk(sk)->addr->refcnt)) ++ kfree(unix_sk(sk)->addr); ++ atomic_inc(&unix_sk(parent)->addr->refcnt); ++ unix_sk(sk)->addr = unix_sk(parent)->addr; ++ } ++ return 0; ++} ++ ++static int generic_restore_queues(struct sock *sk, struct cpt_sock_image *si, ++ loff_t pos, struct cpt_context *ctx) ++{ ++ loff_t endpos; ++ ++ pos = pos + si->cpt_hdrlen; ++ endpos = pos + si->cpt_next; ++ while (pos < endpos) { ++ struct sk_buff *skb; ++ __u32 type; ++ ++ skb = rst_skb(&pos, NULL, &type, ctx); ++ if (IS_ERR(skb)) { ++ if (PTR_ERR(skb) == -EINVAL) { ++ int err; ++ ++ err = rst_sock_attr(&pos, sk, ctx); ++ if (err) ++ return err; ++ } ++ return PTR_ERR(skb); ++ } ++ ++ if (type == CPT_SKB_RQ) { ++ skb_set_owner_r(skb, sk); ++ skb_queue_tail(&sk->sk_receive_queue, skb); ++ } else { ++ wprintk_ctx("strange socket queue type %u\n", type); ++ kfree_skb(skb); ++ } ++ } ++ return 0; ++} ++ ++static int open_socket(cpt_object_t *obj, struct cpt_sock_image *si, ++ struct cpt_context *ctx) ++{ ++ int err; ++ struct socket *sock; ++ struct socket *sock2 = NULL; ++ struct file *file; ++ cpt_object_t *fobj; ++ cpt_object_t *pobj = NULL; ++ ++ err = sock_create_kern(si->cpt_family, si->cpt_type, si->cpt_protocol, ++ &sock); ++ if (err) ++ return err; ++ ++ if (si->cpt_socketpair) { ++ err = sock_create_kern(si->cpt_family, si->cpt_type, ++ si->cpt_protocol, &sock2); ++ if (err) ++ goto err_out; ++ ++ err = sock->ops->socketpair(sock, sock2); ++ if (err < 0) ++ goto err_out; ++ ++ /* Socketpair with a peer outside our environment. ++ * So, we create real half-open pipe and do not worry ++ * about dead end anymore. */ ++ if (si->cpt_peer == -1) { ++ sock_release(sock2); ++ sock2 = NULL; ++ } ++ } ++ ++ cpt_obj_setobj(obj, sock->sk, ctx); ++ ++ if (si->cpt_file != CPT_NULL) { ++ file = sock_mapfile(sock); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto err_out; ++ ++ err = -ENOMEM; ++ ++ obj->o_parent = file; ++ ++ if ((fobj = cpt_object_add(CPT_OBJ_FILE, file, ctx)) == NULL) ++ goto err_out; ++ cpt_obj_setpos(fobj, si->cpt_file, ctx); ++ cpt_obj_setindex(fobj, si->cpt_index, ctx); ++ } ++ ++ if (sock2) { ++ struct file *file2; ++ ++ pobj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, si->cpt_peer, ctx); ++ if (!pobj) BUG(); ++ if (pobj->o_obj) BUG(); ++ cpt_obj_setobj(pobj, sock2->sk, ctx); ++ ++ if (pobj->o_ppos != CPT_NULL) { ++ file2 = sock_mapfile(sock2); ++ err = PTR_ERR(file2); ++ if (IS_ERR(file2)) ++ goto err_out; ++ ++ err = -ENOMEM; ++ if ((fobj = cpt_object_add(CPT_OBJ_FILE, file2, ctx)) == NULL) ++ goto err_out; ++ cpt_obj_setpos(fobj, pobj->o_ppos, ctx); ++ cpt_obj_setindex(fobj, si->cpt_peer, ctx); ++ ++ pobj->o_parent = file2; ++ } ++ } ++ ++ setup_sock_common(sock->sk, si, obj->o_pos, ctx); ++ if (sock->sk->sk_family == AF_INET || sock->sk->sk_family == AF_INET6) { ++ int saved_reuse = sock->sk->sk_reuse; ++ ++ inet_sk(sock->sk)->freebind = 1; ++ sock->sk->sk_reuse = 2; ++ if (si->cpt_laddrlen) { ++ err = sock->ops->bind(sock, (struct sockaddr *)&si->cpt_laddr, si->cpt_laddrlen); ++ if (err) { ++ dprintk_ctx("binding failed: %d, do not worry\n", err); ++ } ++ } ++ sock->sk->sk_reuse = saved_reuse; ++ rst_socket_in(si, obj->o_pos, sock->sk, ctx); ++ } else if (sock->sk->sk_family == AF_NETLINK) { ++ struct sockaddr_nl *nl = (struct sockaddr_nl *)&si->cpt_laddr; ++ if (nl->nl_pid) { ++ err = sock->ops->bind(sock, (struct sockaddr *)&si->cpt_laddr, si->cpt_laddrlen); ++ if (err) { ++ eprintk_ctx("AF_NETLINK binding failed: %d\n", err); ++ } ++ } ++ if (si->cpt_raddrlen && nl->nl_pid) { ++ err = sock->ops->connect(sock, (struct sockaddr *)&si->cpt_raddr, si->cpt_raddrlen, O_NONBLOCK); ++ if (err) { ++ eprintk_ctx("oops, AF_NETLINK connect failed: %d\n", err); ++ } ++ } ++ generic_restore_queues(sock->sk, si, obj->o_pos, ctx); ++ } else if (sock->sk->sk_family == PF_PACKET) { ++ struct sockaddr_ll *ll = (struct sockaddr_ll *)&si->cpt_laddr; ++ if (ll->sll_protocol || ll->sll_ifindex) { ++ int alen = si->cpt_laddrlen; ++ if (alen < sizeof(struct sockaddr_ll)) ++ alen = sizeof(struct sockaddr_ll); ++ err = sock->ops->bind(sock, (struct sockaddr *)&si->cpt_laddr, alen); ++ if (err) { ++ eprintk_ctx("AF_PACKET binding failed: %d\n", err); ++ } ++ } ++ generic_restore_queues(sock->sk, si, obj->o_pos, ctx); ++ } ++ fixup_unix_address(sock, si, ctx); ++ ++ if (sock2) { ++ err = rst_get_object(CPT_OBJ_SOCKET, pobj->o_pos, si, ctx); ++ if (err) ++ return err; ++ setup_sock_common(sock2->sk, si, pobj->o_pos, ctx); ++ fixup_unix_address(sock2, si, ctx); ++ } ++ ++ if ((sock->sk->sk_family == AF_INET || sock->sk->sk_family == AF_INET6) ++ && (int)si->cpt_parent != -1) { ++ cpt_object_t *lobj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, si->cpt_parent, ctx); ++ if (lobj && cpt_attach_accept(lobj->o_obj, sock->sk, ctx) == 0) ++ sock->sk = NULL; ++ } ++ ++ ++ if (si->cpt_file == CPT_NULL && sock->sk && ++ sock->sk->sk_family == AF_INET) { ++ struct sock *sk = sock->sk; ++ ++ if (sk) { ++ sock->sk = NULL; ++ ++ local_bh_disable(); ++ bh_lock_sock(sk); ++ if (sock_owned_by_user(sk)) ++ eprintk_ctx("oops, sock is locked by user\n"); ++ ++ sock_hold(sk); ++ sock_orphan(sk); ++ ub_inc_orphan_count(sk); ++ bh_unlock_sock(sk); ++ local_bh_enable(); ++ sock_put(sk); ++ dprintk_ctx("orphaning socket %p\n", sk); ++ } ++ } ++ ++ if (si->cpt_file == CPT_NULL && sock->sk == NULL) ++ sock_release(sock); ++ ++ return 0; ++ ++err_out: ++ if (sock2) ++ sock_release(sock2); ++ sock_release(sock); ++ return err; ++} ++ ++static int open_listening_socket(loff_t pos, struct cpt_sock_image *si, ++ struct cpt_context *ctx) ++{ ++ int err; ++ struct socket *sock; ++ struct file *file; ++ cpt_object_t *obj, *fobj; ++ ++ err = sock_create_kern(si->cpt_family, si->cpt_type, si->cpt_protocol, ++ &sock); ++ if (err) { ++ eprintk_ctx("open_listening_socket: sock_create_kern: %d\n", err); ++ return err; ++ } ++ ++ sock->sk->sk_reuse = 2; ++ sock->sk->sk_bound_dev_if = si->cpt_bound_dev_if; ++ ++ if (sock->sk->sk_family == AF_UNIX) { ++ err = bind_unix_socket(sock, si, ctx); ++ } else if (si->cpt_laddrlen) { ++ if (sock->sk->sk_family == AF_INET || sock->sk->sk_family == AF_INET6) ++ inet_sk(sock->sk)->freebind = 1; ++ ++ err = sock->ops->bind(sock, (struct sockaddr *)&si->cpt_laddr, si->cpt_laddrlen); ++ ++ if (err) { ++ eprintk_ctx("open_listening_socket: bind: %d\n", err); ++ goto err_out; ++ } ++ } ++ ++ err = sock->ops->listen(sock, si->cpt_max_ack_backlog); ++ if (err) { ++ eprintk_ctx("open_listening_socket: listen: %d, %Ld, %d\n", err, pos, si->cpt_deleted); ++ goto err_out; ++ } ++ ++ /* Now we may access socket body directly and fixup all the things. */ ++ ++ file = sock_mapfile(sock); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) { ++ eprintk_ctx("open_listening_socket: map: %d\n", err); ++ goto err_out; ++ } ++ ++ err = -ENOMEM; ++ if ((fobj = cpt_object_add(CPT_OBJ_FILE, file, ctx)) == NULL) ++ goto err_out; ++ if ((obj = cpt_object_add(CPT_OBJ_SOCKET, sock->sk, ctx)) == NULL) ++ goto err_out; ++ cpt_obj_setpos(obj, pos, ctx); ++ cpt_obj_setindex(obj, si->cpt_index, ctx); ++ obj->o_parent = file; ++ cpt_obj_setpos(fobj, si->cpt_file, ctx); ++ cpt_obj_setindex(fobj, si->cpt_index, ctx); ++ ++ setup_sock_common(sock->sk, si, pos, ctx); ++ ++ if (si->cpt_family == AF_INET || si->cpt_family == AF_INET6) ++ rst_restore_synwait_queue(sock->sk, si, pos, ctx); ++ ++ return 0; ++ ++err_out: ++ sock_release(sock); ++ return err; ++} ++ ++static int ++rst_sock_attr_mcfilter(loff_t *pos_p, struct sock *sk, cpt_context_t *ctx) ++{ ++ int err; ++ loff_t pos = *pos_p; ++ struct cpt_sockmc_image v; ++ ++ err = rst_get_object(CPT_OBJ_SOCK_MCADDR, pos, &v, ctx); ++ if (err) ++ return err; ++ ++ *pos_p += v.cpt_next; ++ ++ if (v.cpt_family == AF_INET) ++ return rst_sk_mcfilter_in(sk, &v, pos, ctx); ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++ else if (v.cpt_family == AF_INET6) ++ return rst_sk_mcfilter_in6(sk, &v, pos, ctx); ++#endif ++ else ++ return -EAFNOSUPPORT; ++} ++ ++ ++static int ++rst_sock_attr_skfilter(loff_t *pos_p, struct sock *sk, cpt_context_t *ctx) ++{ ++ int err; ++ struct sk_filter *fp, *old_fp; ++ loff_t pos = *pos_p; ++ struct cpt_obj_bits v; ++ ++ err = rst_get_object(CPT_OBJ_SKFILTER, pos, &v, ctx); ++ if (err) ++ return err; ++ ++ *pos_p += v.cpt_next; ++ ++ if (v.cpt_size % sizeof(struct sock_filter)) ++ return -EINVAL; ++ ++ fp = sock_kmalloc(sk, v.cpt_size+sizeof(*fp), GFP_KERNEL_UBC); ++ if (fp == NULL) ++ return -ENOMEM; ++ atomic_set(&fp->refcnt, 1); ++ fp->len = v.cpt_size/sizeof(struct sock_filter); ++ ++ err = ctx->pread(fp->insns, v.cpt_size, ctx, pos+v.cpt_hdrlen); ++ if (err) { ++ sk_filter_uncharge(sk, fp); ++ return err; ++ } ++ ++ old_fp = sk->sk_filter; ++ sk->sk_filter = fp; ++ if (old_fp) ++ sk_filter_uncharge(sk, old_fp); ++ return 0; ++} ++ ++ ++int rst_sock_attr(loff_t *pos_p, struct sock *sk, cpt_context_t *ctx) ++{ ++ int err; ++ loff_t pos = *pos_p; ++ ++ err = rst_sock_attr_skfilter(pos_p, sk, ctx); ++ if (err && pos == *pos_p) ++ err = rst_sock_attr_mcfilter(pos_p, sk, ctx); ++ return err; ++} ++ ++struct sk_buff * rst_skb(loff_t *pos_p, __u32 *owner, __u32 *queue, struct cpt_context *ctx) ++{ ++ int err; ++ struct sk_buff *skb; ++ struct cpt_skb_image v; ++ loff_t pos = *pos_p; ++ struct scm_fp_list *fpl = NULL; ++ struct timeval tmptv; ++ ++ err = rst_get_object(CPT_OBJ_SKB, pos, &v, ctx); ++ if (err) ++ return ERR_PTR(err); ++ *pos_p = pos + v.cpt_next; ++ ++ if (owner) ++ *owner = v.cpt_owner; ++ if (queue) ++ *queue = v.cpt_queue; ++ ++ skb = alloc_skb(v.cpt_len + v.cpt_hspace + v.cpt_tspace, GFP_KERNEL); ++ if (skb == NULL) ++ return ERR_PTR(-ENOMEM); ++ skb_reserve(skb, v.cpt_hspace); ++ skb_put(skb, v.cpt_len); ++#ifdef NET_SKBUFF_DATA_USES_OFFSET ++ skb->transport_header = v.cpt_h; ++ skb->network_header = v.cpt_nh; ++ skb->mac_header = v.cpt_mac; ++#else ++ skb->transport_header = skb->head + v.cpt_h; ++ skb->network_header = skb->head + v.cpt_nh; ++ skb->mac_header = skb->head + v.cpt_mac; ++#endif ++ BUILD_BUG_ON(sizeof(skb->cb) < sizeof(v.cpt_cb)); ++ memcpy(skb->cb, v.cpt_cb, sizeof(v.cpt_cb)); ++ skb->mac_len = v.cpt_mac_len; ++ ++ skb->csum = v.cpt_csum; ++ skb->local_df = v.cpt_local_df; ++ skb->pkt_type = v.cpt_pkt_type; ++ skb->ip_summed = v.cpt_ip_summed; ++ skb->priority = v.cpt_priority; ++ skb->protocol = v.cpt_protocol; ++ cpt_timeval_import(&tmptv, v.cpt_stamp); ++ skb->tstamp = timeval_to_ktime(tmptv); ++ ++ skb_shinfo(skb)->gso_segs = v.cpt_gso_segs; ++ skb_shinfo(skb)->gso_size = v.cpt_gso_size; ++ if (ctx->image_version == 0) { ++ skb_shinfo(skb)->gso_segs = 1; ++ skb_shinfo(skb)->gso_size = 0; ++ } ++ ++ if (v.cpt_next > v.cpt_hdrlen) { ++ pos = pos + v.cpt_hdrlen; ++ while (pos < *pos_p) { ++ union { ++ struct cpt_obj_bits b; ++ struct cpt_fd_image f; ++ } u; ++ ++ err = rst_get_object(-1, pos, &u, ctx); ++ if (err) { ++ kfree_skb(skb); ++ return ERR_PTR(err); ++ } ++ if (u.b.cpt_object == CPT_OBJ_BITS) { ++ if (u.b.cpt_size != v.cpt_hspace + skb->len) { ++ eprintk_ctx("invalid skb image %u != %u + %u\n", u.b.cpt_size, v.cpt_hspace, skb->len); ++ kfree_skb(skb); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ err = ctx->pread(skb->head, u.b.cpt_size, ctx, pos+u.b.cpt_hdrlen); ++ if (err) { ++ kfree_skb(skb); ++ return ERR_PTR(err); ++ } ++ } else if (u.f.cpt_object == CPT_OBJ_FILEDESC) { ++ if (!fpl) { ++ fpl = kmalloc(sizeof(struct scm_fp_list), ++ GFP_KERNEL_UBC); ++ if (!fpl) { ++ kfree_skb(skb); ++ return ERR_PTR(-ENOMEM); ++ } ++ fpl->count = 0; ++ UNIXCB(skb).fp = fpl; ++ } ++ fpl->fp[fpl->count] = rst_file(u.f.cpt_file, -1, ctx); ++ if (!IS_ERR(fpl->fp[fpl->count])) ++ fpl->count++; ++ } ++ pos += u.b.cpt_next; ++ } ++ } ++ ++ return skb; ++} ++ ++static int restore_unix_rqueue(struct sock *sk, struct cpt_sock_image *si, ++ loff_t pos, struct cpt_context *ctx) ++{ ++ loff_t endpos; ++ ++ pos = pos + si->cpt_hdrlen; ++ endpos = pos + si->cpt_next; ++ while (pos < endpos) { ++ struct sk_buff *skb; ++ struct sock *owner_sk; ++ __u32 owner; ++ ++ skb = rst_skb(&pos, &owner, NULL, ctx); ++ if (IS_ERR(skb)) { ++ if (PTR_ERR(skb) == -EINVAL) { ++ int err; ++ ++ err = rst_sock_attr(&pos, sk, ctx); ++ if (err) ++ return err; ++ } ++ return PTR_ERR(skb); ++ } ++ ++ owner_sk = unix_peer(sk); ++ if (owner != -1) { ++ cpt_object_t *pobj; ++ pobj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, owner, ctx); ++ if (pobj == NULL) { ++ eprintk_ctx("orphan af_unix skb?\n"); ++ kfree_skb(skb); ++ continue; ++ } ++ owner_sk = pobj->o_obj; ++ } ++ if (owner_sk == NULL) { ++ dprintk_ctx("orphan af_unix skb 2?\n"); ++ kfree_skb(skb); ++ continue; ++ } ++ skb_set_owner_w(skb, owner_sk); ++ if (UNIXCB(skb).fp) ++ skb->destructor = unix_destruct_fds; ++ skb_queue_tail(&sk->sk_receive_queue, skb); ++ if (sk->sk_state == TCP_LISTEN) { ++ struct socket *sock = skb->sk->sk_socket; ++ if (sock == NULL) BUG(); ++ if (sock->file) BUG(); ++ skb->sk->sk_socket = NULL; ++ skb->sk->sk_sleep = NULL; ++ sock->sk = NULL; ++ sock_release(sock); ++ } ++ } ++ return 0; ++} ++ ++ ++/* All the sockets are created before we start to open files */ ++ ++int rst_sockets(struct cpt_context *ctx) ++{ ++ int err; ++ loff_t sec = ctx->sections[CPT_SECT_SOCKET]; ++ loff_t endsec; ++ cpt_object_t *obj; ++ struct cpt_section_hdr h; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) { ++ eprintk_ctx("rst_sockets: ctx->pread: %d\n", err); ++ return err; ++ } ++ if (h.cpt_section != CPT_SECT_SOCKET || h.cpt_hdrlen < sizeof(h)) { ++ eprintk_ctx("rst_sockets: hdr err\n"); ++ return -EINVAL; ++ } ++ ++ /* The first pass: we create socket index and open listening sockets. */ ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ struct cpt_sock_image *sbuf = cpt_get_buf(ctx); ++ err = rst_get_object(CPT_OBJ_SOCKET, sec, sbuf, ctx); ++ if (err) { ++ eprintk_ctx("rst_sockets: rst_get_object: %d\n", err); ++ cpt_release_buf(ctx); ++ return err; ++ } ++ if (sbuf->cpt_state == TCP_LISTEN) { ++ err = open_listening_socket(sec, sbuf, ctx); ++ cpt_release_buf(ctx); ++ if (err) { ++ eprintk_ctx("rst_sockets: open_listening_socket: %d\n", err); ++ return err; ++ } ++ } else { ++ cpt_release_buf(ctx); ++ obj = alloc_cpt_object(GFP_KERNEL, ctx); ++ if (obj == NULL) ++ return -ENOMEM; ++ cpt_obj_setindex(obj, sbuf->cpt_index, ctx); ++ cpt_obj_setpos(obj, sec, ctx); ++ obj->o_ppos = sbuf->cpt_file; ++ intern_cpt_object(CPT_OBJ_SOCKET, obj, ctx); ++ } ++ sec += sbuf->cpt_next; ++ } ++ ++ /* Pass 2: really restore sockets */ ++ for_each_object(obj, CPT_OBJ_SOCKET) { ++ struct cpt_sock_image *sbuf; ++ if (obj->o_obj != NULL) ++ continue; ++ sbuf = cpt_get_buf(ctx); ++ err = rst_get_object(CPT_OBJ_SOCKET, obj->o_pos, sbuf, ctx); ++ if (err) { ++ eprintk_ctx("rst_sockets: rst_get_object: %d\n", err); ++ cpt_release_buf(ctx); ++ return err; ++ } ++ if (sbuf->cpt_state == TCP_LISTEN) BUG(); ++ err = open_socket(obj, sbuf, ctx); ++ cpt_release_buf(ctx); ++ if (err) { ++ eprintk_ctx("rst_sockets: open_socket: %d\n", err); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++int rst_orphans(struct cpt_context *ctx) ++{ ++ int err; ++ loff_t sec = ctx->sections[CPT_SECT_ORPHANS]; ++ loff_t endsec; ++ cpt_object_t *obj; ++ struct cpt_section_hdr h; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_ORPHANS || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ struct cpt_sock_image *sbuf = cpt_get_buf(ctx); ++ err = rst_get_object(CPT_OBJ_SOCKET, sec, sbuf, ctx); ++ if (err) { ++ cpt_release_buf(ctx); ++ return err; ++ } ++ obj = alloc_cpt_object(GFP_KERNEL, ctx); ++ if (obj == NULL) { ++ cpt_release_buf(ctx); ++ return -ENOMEM; ++ } ++ obj->o_pos = sec; ++ obj->o_ppos = sbuf->cpt_file; ++ err = open_socket(obj, sbuf, ctx); ++ dprintk_ctx("Restoring orphan: %d\n", err); ++ free_cpt_object(obj, ctx); ++ cpt_release_buf(ctx); ++ if (err) ++ return err; ++ sec += sbuf->cpt_next; ++ } ++ ++ return 0; ++} ++ ++ ++/* Pass 3: I understand, this is not funny already :-), ++ * but we have to do another pass to establish links between ++ * not-paired AF_UNIX SOCK_DGRAM sockets and to restore AF_UNIX ++ * skb queues with proper skb->sk links. ++ * ++ * This could be made at the end of rst_sockets(), but we defer ++ * restoring af_unix queues up to the end of restoring files to ++ * make restoring passed FDs cleaner. ++ */ ++ ++int rst_sockets_complete(struct cpt_context *ctx) ++{ ++ int err; ++ cpt_object_t *obj; ++ ++ for_each_object(obj, CPT_OBJ_SOCKET) { ++ struct cpt_sock_image *sbuf; ++ struct sock *sk = obj->o_obj; ++ struct sock *peer; ++ ++ if (!sk) BUG(); ++ ++ if (sk->sk_family != AF_UNIX) ++ continue; ++ ++ sbuf = cpt_get_buf(ctx); ++ err = rst_get_object(CPT_OBJ_SOCKET, obj->o_pos, sbuf, ctx); ++ if (err) { ++ cpt_release_buf(ctx); ++ return err; ++ } ++ ++ if (sbuf->cpt_next > sbuf->cpt_hdrlen) ++ restore_unix_rqueue(sk, sbuf, obj->o_pos, ctx); ++ ++ cpt_release_buf(ctx); ++ ++ if (sk->sk_type == SOCK_DGRAM && unix_peer(sk) == NULL) { ++ cpt_object_t *pobj; ++ ++ sbuf = cpt_get_buf(ctx); ++ err = rst_get_object(CPT_OBJ_SOCKET, obj->o_pos, sbuf, ctx); ++ if (err) { ++ cpt_release_buf(ctx); ++ return err; ++ } ++ ++ if (sbuf->cpt_peer != -1) { ++ pobj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, sbuf->cpt_peer, ctx); ++ if (pobj) { ++ peer = pobj->o_obj; ++ sock_hold(peer); ++ unix_peer(sk) = peer; ++ } ++ } ++ cpt_release_buf(ctx); ++ } ++ } ++ ++ rst_orphans(ctx); ++ ++ return 0; ++} ++ +Index: kernel/kernel/cpt/rst_socket_in.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_socket_in.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,487 @@ ++/* ++ * ++ * kernel/cpt/rst_socket_in.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_mm.h" ++#include "cpt_socket.h" ++#include "cpt_kernel.h" ++ ++static inline unsigned long jiffies_import(__u32 tmo) ++{ ++ __s32 delta = tmo; ++ return jiffies + (long)delta; ++} ++ ++static inline __u32 tcp_jiffies_import(__u32 tmo) ++{ ++ return ((__u32)jiffies) + tmo; ++} ++ ++ ++static int restore_queues(struct sock *sk, struct cpt_sock_image *si, ++ loff_t pos, struct cpt_context *ctx) ++{ ++ loff_t endpos; ++ ++ pos = pos + si->cpt_hdrlen; ++ endpos = pos + si->cpt_next; ++ while (pos < endpos) { ++ struct sk_buff *skb; ++ __u32 type; ++ ++ skb = rst_skb(&pos, NULL, &type, ctx); ++ if (IS_ERR(skb)) { ++ if (PTR_ERR(skb) == -EINVAL) { ++ int err; ++ ++ err = rst_sock_attr(&pos, sk, ctx); ++ if (err) ++ return err; ++ } ++ return PTR_ERR(skb); ++ } ++ ++ if (sk->sk_type == SOCK_STREAM) { ++ if (type == CPT_SKB_RQ) { ++ sk_stream_set_owner_r(skb, sk); ++ ub_tcprcvbuf_charge_forced(sk, skb); ++ skb_queue_tail(&sk->sk_receive_queue, skb); ++ } else if (type == CPT_SKB_OFOQ) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ sk_stream_set_owner_r(skb, sk); ++ ub_tcprcvbuf_charge_forced(sk, skb); ++ skb_queue_tail(&tp->out_of_order_queue, skb); ++ } else if (type == CPT_SKB_WQ) { ++ sk->sk_wmem_queued += skb->truesize; ++ sk->sk_forward_alloc -= skb->truesize; ++ ub_tcpsndbuf_charge_forced(sk, skb); ++ skb_queue_tail(&sk->sk_write_queue, skb); ++ } else { ++ wprintk_ctx("strange stream queue type %u\n", type); ++ kfree_skb(skb); ++ } ++ } else { ++ if (type == CPT_SKB_RQ) { ++ skb_set_owner_r(skb, sk); ++ skb_queue_tail(&sk->sk_receive_queue, skb); ++ } else if (type == CPT_SKB_WQ) { ++ struct inet_sock *inet = inet_sk(sk); ++ if (inet->cork.fragsize) { ++ skb_set_owner_w(skb, sk); ++ skb_queue_tail(&sk->sk_write_queue, skb); ++ } else { ++ eprintk_ctx("cork skb is dropped\n"); ++ kfree_skb(skb); ++ } ++ } else { ++ wprintk_ctx("strange dgram queue type %u\n", type); ++ kfree_skb(skb); ++ } ++ } ++ } ++ return 0; ++} ++ ++static struct sock *find_parent(__u16 sport, cpt_context_t *ctx) ++{ ++ cpt_object_t *obj; ++ for_each_object(obj, CPT_OBJ_SOCKET) { ++ struct sock *sk = obj->o_obj; ++ if (sk && ++ sk->sk_state == TCP_LISTEN && ++ (sk->sk_family == AF_INET || sk->sk_family == AF_INET6) && ++ inet_sk(sk)->sport == sport) ++ return sk; ++ } ++ return NULL; ++} ++ ++static int rst_socket_tcp(struct cpt_sock_image *si, loff_t pos, struct sock *sk, ++ struct cpt_context *ctx) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct sk_buff *skb; ++ tp->pred_flags = si->cpt_pred_flags; ++ tp->rcv_nxt = si->cpt_rcv_nxt; ++ tp->snd_nxt = si->cpt_snd_nxt; ++ tp->snd_una = si->cpt_snd_una; ++ tp->snd_sml = si->cpt_snd_sml; ++ tp->rcv_tstamp = tcp_jiffies_import(si->cpt_rcv_tstamp); ++ tp->lsndtime = tcp_jiffies_import(si->cpt_lsndtime); ++ tp->tcp_header_len = si->cpt_tcp_header_len; ++ inet_csk(sk)->icsk_ack.pending = si->cpt_ack_pending; ++ inet_csk(sk)->icsk_ack.quick = si->cpt_quick; ++ inet_csk(sk)->icsk_ack.pingpong = si->cpt_pingpong; ++ inet_csk(sk)->icsk_ack.blocked = si->cpt_blocked; ++ inet_csk(sk)->icsk_ack.ato = si->cpt_ato; ++ inet_csk(sk)->icsk_ack.timeout = jiffies_import(si->cpt_ack_timeout); ++ inet_csk(sk)->icsk_ack.lrcvtime = tcp_jiffies_import(si->cpt_lrcvtime); ++ inet_csk(sk)->icsk_ack.last_seg_size = si->cpt_last_seg_size; ++ inet_csk(sk)->icsk_ack.rcv_mss = si->cpt_rcv_mss; ++ tp->snd_wl1 = si->cpt_snd_wl1; ++ tp->snd_wnd = si->cpt_snd_wnd; ++ tp->max_window = si->cpt_max_window; ++ inet_csk(sk)->icsk_pmtu_cookie = si->cpt_pmtu_cookie; ++ tp->mss_cache = si->cpt_mss_cache; ++ tp->rx_opt.mss_clamp = si->cpt_mss_clamp; ++ inet_csk(sk)->icsk_ext_hdr_len = si->cpt_ext_header_len; ++ inet_csk(sk)->icsk_ca_state = si->cpt_ca_state; ++ inet_csk(sk)->icsk_retransmits = si->cpt_retransmits; ++ tp->reordering = si->cpt_reordering; ++ tp->frto_counter = si->cpt_frto_counter; ++ tp->frto_highmark = si->cpt_frto_highmark; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) ++ // // tp->adv_cong = si->cpt_adv_cong; ++#endif ++ inet_csk(sk)->icsk_accept_queue.rskq_defer_accept = si->cpt_defer_accept; ++ inet_csk(sk)->icsk_backoff = si->cpt_backoff; ++ tp->srtt = si->cpt_srtt; ++ tp->mdev = si->cpt_mdev; ++ tp->mdev_max = si->cpt_mdev_max; ++ tp->rttvar = si->cpt_rttvar; ++ tp->rtt_seq = si->cpt_rtt_seq; ++ inet_csk(sk)->icsk_rto = si->cpt_rto; ++ tp->packets_out = si->cpt_packets_out; ++ tp->retrans_out = si->cpt_retrans_out; ++ tp->lost_out = si->cpt_lost_out; ++ tp->sacked_out = si->cpt_sacked_out; ++ tp->fackets_out = si->cpt_fackets_out; ++ tp->snd_ssthresh = si->cpt_snd_ssthresh; ++ tp->snd_cwnd = si->cpt_snd_cwnd; ++ tp->snd_cwnd_cnt = si->cpt_snd_cwnd_cnt; ++ tp->snd_cwnd_clamp = si->cpt_snd_cwnd_clamp; ++ tp->snd_cwnd_used = si->cpt_snd_cwnd_used; ++ tp->snd_cwnd_stamp = tcp_jiffies_import(si->cpt_snd_cwnd_stamp); ++ inet_csk(sk)->icsk_timeout = tcp_jiffies_import(si->cpt_timeout); ++ tp->rcv_wnd = si->cpt_rcv_wnd; ++ tp->rcv_wup = si->cpt_rcv_wup; ++ tp->write_seq = si->cpt_write_seq; ++ tp->pushed_seq = si->cpt_pushed_seq; ++ tp->copied_seq = si->cpt_copied_seq; ++ tp->rx_opt.tstamp_ok = si->cpt_tstamp_ok; ++ tp->rx_opt.wscale_ok = si->cpt_wscale_ok; ++ tp->rx_opt.sack_ok = si->cpt_sack_ok; ++ tp->rx_opt.saw_tstamp = si->cpt_saw_tstamp; ++ tp->rx_opt.snd_wscale = si->cpt_snd_wscale; ++ tp->rx_opt.rcv_wscale = si->cpt_rcv_wscale; ++ tp->nonagle = si->cpt_nonagle; ++ tp->keepalive_probes = si->cpt_keepalive_probes; ++ tp->rx_opt.rcv_tsval = si->cpt_rcv_tsval; ++ tp->rx_opt.rcv_tsecr = si->cpt_rcv_tsecr; ++ tp->rx_opt.ts_recent = si->cpt_ts_recent; ++ tp->rx_opt.ts_recent_stamp = si->cpt_ts_recent_stamp; ++ tp->rx_opt.user_mss = si->cpt_user_mss; ++ tp->rx_opt.dsack = si->cpt_dsack; ++ tp->rx_opt.eff_sacks = si->cpt_num_sacks; ++ tp->duplicate_sack[0].start_seq = si->cpt_sack_array[0]; ++ tp->duplicate_sack[0].end_seq = si->cpt_sack_array[1]; ++ tp->selective_acks[0].start_seq = si->cpt_sack_array[2]; ++ tp->selective_acks[0].end_seq = si->cpt_sack_array[3]; ++ tp->selective_acks[1].start_seq = si->cpt_sack_array[4]; ++ tp->selective_acks[1].end_seq = si->cpt_sack_array[5]; ++ tp->selective_acks[2].start_seq = si->cpt_sack_array[6]; ++ tp->selective_acks[2].end_seq = si->cpt_sack_array[7]; ++ tp->selective_acks[3].start_seq = si->cpt_sack_array[8]; ++ tp->selective_acks[3].end_seq = si->cpt_sack_array[9]; ++ ++ tp->window_clamp = si->cpt_window_clamp; ++ tp->rcv_ssthresh = si->cpt_rcv_ssthresh; ++ inet_csk(sk)->icsk_probes_out = si->cpt_probes_out; ++ tp->rx_opt.num_sacks = si->cpt_num_sacks; ++ tp->advmss = si->cpt_advmss; ++ inet_csk(sk)->icsk_syn_retries = si->cpt_syn_retries; ++ tp->ecn_flags = si->cpt_ecn_flags; ++ tp->prior_ssthresh = si->cpt_prior_ssthresh; ++ tp->high_seq = si->cpt_high_seq; ++ tp->retrans_stamp = si->cpt_retrans_stamp; ++ tp->undo_marker = si->cpt_undo_marker; ++ tp->undo_retrans = si->cpt_undo_retrans; ++ tp->urg_seq = si->cpt_urg_seq; ++ tp->urg_data = si->cpt_urg_data; ++ inet_csk(sk)->icsk_pending = si->cpt_pending; ++ tp->urg_mode = si->cpt_urg_mode; ++ tp->snd_up = si->cpt_snd_up; ++ tp->keepalive_time = si->cpt_keepalive_time; ++ tp->keepalive_intvl = si->cpt_keepalive_intvl; ++ tp->linger2 = si->cpt_linger2; ++ ++ sk->sk_send_head = NULL; ++ for (skb = skb_peek(&sk->sk_write_queue); ++ skb && skb != (struct sk_buff*)&sk->sk_write_queue; ++ skb = skb->next) { ++ if (!after(tp->snd_nxt, TCP_SKB_CB(skb)->seq)) { ++ sk->sk_send_head = skb; ++ break; ++ } ++ } ++ ++ if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN) { ++ struct inet_sock *inet = inet_sk(sk); ++ if (inet->num == 0) { ++ cpt_object_t *lobj = NULL; ++ ++ if ((int)si->cpt_parent != -1) ++ lobj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, si->cpt_parent, ctx); ++ ++ if (lobj && lobj->o_obj) { ++ inet->num = ntohs(inet->sport); ++ local_bh_disable(); ++ __inet_inherit_port(&tcp_hashinfo, lobj->o_obj, sk); ++ local_bh_enable(); ++ dprintk_ctx("port inherited from parent\n"); ++ } else { ++ struct sock *lsk = find_parent(inet->sport, ctx); ++ if (lsk) { ++ inet->num = ntohs(inet->sport); ++ local_bh_disable(); ++ __inet_inherit_port(&tcp_hashinfo, lsk, sk); ++ local_bh_enable(); ++ dprintk_ctx("port inherited\n"); ++ } else { ++ eprintk_ctx("we are kinda lost...\n"); ++ } ++ } ++ } ++ ++ sk->sk_prot->hash(sk); ++ ++ if (inet_csk(sk)->icsk_ack.pending&ICSK_ACK_TIMER) ++ sk_reset_timer(sk, &inet_csk(sk)->icsk_delack_timer, inet_csk(sk)->icsk_ack.timeout); ++ if (inet_csk(sk)->icsk_pending) ++ sk_reset_timer(sk, &inet_csk(sk)->icsk_retransmit_timer, ++ inet_csk(sk)->icsk_timeout); ++ if (sock_flag(sk, SOCK_KEEPOPEN)) { ++ unsigned long expires = jiffies_import(si->cpt_ka_timeout); ++ if (time_after(jiffies, expires)) ++ expires = jiffies + HZ; ++ sk_reset_timer(sk, &sk->sk_timer, expires); ++ } ++ } ++ ++ return 0; ++} ++ ++ ++int rst_socket_in(struct cpt_sock_image *si, loff_t pos, struct sock *sk, ++ struct cpt_context *ctx) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ ++ lock_sock(sk); ++ ++ sk->sk_state = si->cpt_state; ++ ++ inet->daddr = si->cpt_daddr; ++ inet->dport = si->cpt_dport; ++ inet->saddr = si->cpt_saddr; ++ inet->rcv_saddr = si->cpt_rcv_saddr; ++ inet->sport = si->cpt_sport; ++ inet->uc_ttl = si->cpt_uc_ttl; ++ inet->tos = si->cpt_tos; ++ inet->cmsg_flags = si->cpt_cmsg_flags; ++ inet->mc_index = si->cpt_mc_index; ++ inet->mc_addr = si->cpt_mc_addr; ++ inet->hdrincl = si->cpt_hdrincl; ++ inet->mc_ttl = si->cpt_mc_ttl; ++ inet->mc_loop = si->cpt_mc_loop; ++ inet->pmtudisc = si->cpt_pmtudisc; ++ inet->recverr = si->cpt_recverr; ++ inet->freebind = si->cpt_freebind; ++ inet->id = si->cpt_idcounter; ++ ++ inet->cork.flags = si->cpt_cork_flags; ++ inet->cork.fragsize = si->cpt_cork_fragsize; ++ inet->cork.length = si->cpt_cork_length; ++ inet->cork.addr = si->cpt_cork_addr; ++ inet->cork.fl.fl4_src = si->cpt_cork_saddr; ++ inet->cork.fl.fl4_dst = si->cpt_cork_daddr; ++ inet->cork.fl.oif = si->cpt_cork_oif; ++ if (inet->cork.fragsize) { ++ if (ip_route_output_key(&inet->cork.rt, &inet->cork.fl)) { ++ eprintk_ctx("failed to restore cork route\n"); ++ inet->cork.fragsize = 0; ++ } ++ } ++ ++ if (sk->sk_type == SOCK_DGRAM && sk->sk_protocol == IPPROTO_UDP) { ++ struct udp_sock *up = udp_sk(sk); ++ up->pending = si->cpt_udp_pending; ++ up->corkflag = si->cpt_udp_corkflag; ++ up->encap_type = si->cpt_udp_encap; ++ up->len = si->cpt_udp_len; ++ } ++ ++ if (sk->sk_family == AF_INET6) { ++ struct ipv6_pinfo *np = inet6_sk(sk); ++ ++ memcpy(&np->saddr, si->cpt_saddr6, 16); ++ memcpy(&np->rcv_saddr, si->cpt_rcv_saddr6, 16); ++ memcpy(&np->daddr, si->cpt_daddr6, 16); ++ np->flow_label = si->cpt_flow_label6; ++ np->frag_size = si->cpt_frag_size6; ++ np->hop_limit = si->cpt_hop_limit6; ++ np->mcast_hops = si->cpt_mcast_hops6; ++ np->mcast_oif = si->cpt_mcast_oif6; ++ np->rxopt.all = si->cpt_rxopt6; ++ np->mc_loop = si->cpt_mc_loop6; ++ np->recverr = si->cpt_recverr6; ++ np->sndflow = si->cpt_sndflow6; ++ np->pmtudisc = si->cpt_pmtudisc6; ++ np->ipv6only = si->cpt_ipv6only6; ++ ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++ if (si->cpt_mapped) { ++ extern struct inet_connection_sock_af_ops ipv6_mapped; ++ if (sk->sk_type == SOCK_STREAM && ++ sk->sk_protocol == IPPROTO_TCP) { ++ inet_csk(sk)->icsk_af_ops = &ipv6_mapped; ++ sk->sk_backlog_rcv = tcp_v4_do_rcv; ++ } ++ } ++#endif ++ } ++ ++ restore_queues(sk, si, pos, ctx); ++ ++ if (sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP) ++ rst_socket_tcp(si, pos, sk, ctx); ++ ++ release_sock(sk); ++ return 0; ++} ++ ++int cpt_attach_accept(struct sock *lsk, struct sock *sk, cpt_context_t *ctx) ++{ ++ struct request_sock *req; ++ ++ if (lsk->sk_state != TCP_LISTEN) ++ return -EINVAL; ++ ++ req = reqsk_alloc(&tcp_request_sock_ops); ++ if (!req) ++ return -ENOMEM; ++ ++ sk->sk_socket = NULL; ++ sk->sk_sleep = NULL; ++ inet_csk_reqsk_queue_add(lsk, req, sk); ++ return 0; ++} ++ ++int rst_restore_synwait_queue(struct sock *sk, struct cpt_sock_image *si, ++ loff_t pos, struct cpt_context *ctx) ++{ ++ int err; ++ loff_t end = si->cpt_next; ++ ++ pos += si->cpt_hdrlen; ++ while (pos < end) { ++ struct cpt_openreq_image oi; ++ ++ err = rst_get_object(CPT_OBJ_OPENREQ, pos, &oi, ctx); ++ if (err) { ++ err = rst_sock_attr(&pos, sk, ctx); ++ if (err) ++ return err; ++ continue; ++ } ++ ++ if (oi.cpt_object == CPT_OBJ_OPENREQ) { ++ struct request_sock *req = reqsk_alloc(&tcp_request_sock_ops); ++ if (req == NULL) ++ return -ENOMEM; ++ ++ memset(req, 0, sizeof(*req)); ++ tcp_rsk(req)->rcv_isn = oi.cpt_rcv_isn; ++ tcp_rsk(req)->snt_isn = oi.cpt_snt_isn; ++ inet_rsk(req)->rmt_port = oi.cpt_rmt_port; ++ req->mss = oi.cpt_mss; ++ req->retrans = oi.cpt_retrans; ++ inet_rsk(req)->snd_wscale = oi.cpt_snd_wscale; ++ inet_rsk(req)->rcv_wscale = oi.cpt_rcv_wscale; ++ inet_rsk(req)->tstamp_ok = oi.cpt_tstamp_ok; ++ inet_rsk(req)->sack_ok = oi.cpt_sack_ok; ++ inet_rsk(req)->wscale_ok = oi.cpt_wscale_ok; ++ inet_rsk(req)->ecn_ok = oi.cpt_ecn_ok; ++ inet_rsk(req)->acked = oi.cpt_acked; ++ req->window_clamp = oi.cpt_window_clamp; ++ req->rcv_wnd = oi.cpt_rcv_wnd; ++ req->ts_recent = oi.cpt_ts_recent; ++ req->expires = jiffies_import(oi.cpt_expires); ++ ++ if (oi.cpt_family == AF_INET) { ++ memcpy(&inet_rsk(req)->loc_addr, oi.cpt_loc_addr, 4); ++ memcpy(&inet_rsk(req)->rmt_addr, oi.cpt_rmt_addr, 4); ++ inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); ++ } else { ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ memcpy(&inet6_rsk(req)->loc_addr, oi.cpt_loc_addr, 16); ++ memcpy(&inet6_rsk(req)->rmt_addr, oi.cpt_rmt_addr, 16); ++ inet6_rsk(req)->iif = oi.cpt_iif; ++ inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); ++#endif ++ } ++ } ++ pos += oi.cpt_next; ++ } ++ return 0; ++} ++ ++int rst_sk_mcfilter_in(struct sock *sk, struct cpt_sockmc_image *v, ++ loff_t pos, cpt_context_t *ctx) ++{ ++ struct ip_mreqn imr; ++ ++ if (v->cpt_mode || v->cpt_next != v->cpt_hdrlen) { ++ eprintk_ctx("IGMPv3 is still not supported\n"); ++ return -EINVAL; ++ } ++ ++ memset(&imr, 0, sizeof(imr)); ++ imr.imr_ifindex = v->cpt_ifindex; ++ imr.imr_multiaddr.s_addr = v->cpt_mcaddr[0]; ++ return ip_mc_join_group(sk, &imr); ++} ++ ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++int rst_sk_mcfilter_in6(struct sock *sk, struct cpt_sockmc_image *v, ++ loff_t pos, cpt_context_t *ctx) ++{ ++ ++ if (v->cpt_mode || v->cpt_next != v->cpt_hdrlen) { ++ eprintk_ctx("IGMPv3 is still not supported\n"); ++ return -EINVAL; ++ } ++ ++ return ipv6_sock_mc_join(sk, v->cpt_ifindex, ++ (struct in6_addr*)v->cpt_mcaddr); ++} ++#endif +Index: kernel/kernel/cpt/rst_sysvipc.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_sysvipc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,554 @@ ++/* ++ * ++ * kernel/cpt/rst_sysvipc.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_kernel.h" ++ ++struct _warg { ++ struct file *file; ++ struct cpt_sysvshm_image *v; ++}; ++ ++static int fixup_one_shm(struct shmid_kernel *shp, void *arg) ++{ ++ struct _warg *warg = arg; ++ ++ if (shp->shm_file != warg->file) ++ return 0; ++ if (shp->shm_nattch) ++ return -EEXIST; ++ ++ shp->shm_perm.uid = warg->v->cpt_uid; ++ shp->shm_perm.gid = warg->v->cpt_gid; ++ shp->shm_perm.cuid = warg->v->cpt_cuid; ++ shp->shm_perm.cgid = warg->v->cpt_cgid; ++ shp->shm_perm.mode = warg->v->cpt_mode; ++ ++ shp->shm_atim = warg->v->cpt_atime; ++ shp->shm_dtim = warg->v->cpt_dtime; ++ shp->shm_ctim = warg->v->cpt_ctime; ++ shp->shm_cprid = warg->v->cpt_creator; ++ shp->shm_lprid = warg->v->cpt_last; ++ ++ /* TODO: fix shp->mlock_user? */ ++ return 1; ++} ++ ++static int fixup_shm(struct file *file, struct cpt_sysvshm_image *v) ++{ ++ struct _warg warg; ++ ++ warg.file = file; ++ warg.v = v; ++ ++ return sysvipc_walk_shm(fixup_one_shm, &warg); ++} ++ ++static int fixup_shm_data(struct file *file, loff_t pos, loff_t end, ++ struct cpt_context *ctx) ++{ ++ struct cpt_page_block pgb; ++ ssize_t (*do_write)(struct file *, const char __user *, size_t, loff_t *ppos); ++ ++ do_write = file->f_dentry->d_inode->i_fop->write; ++ if (do_write == NULL) { ++ eprintk_ctx("No TMPFS? Cannot restore content of SYSV SHM\n"); ++ return -EINVAL; ++ } ++ ++ while (pos < end) { ++ loff_t opos; ++ loff_t ipos; ++ int count; ++ int err; ++ ++ err = rst_get_object(CPT_OBJ_PAGES, pos, &pgb, ctx); ++ if (err) ++ return err; ++ dprintk_ctx("restoring SHM block: %08x-%08x\n", ++ (__u32)pgb.cpt_start, (__u32)pgb.cpt_end); ++ ipos = pos + pgb.cpt_hdrlen; ++ opos = pgb.cpt_start; ++ count = pgb.cpt_end-pgb.cpt_start; ++ while (count > 0) { ++ mm_segment_t oldfs; ++ int copy = count; ++ ++ if (copy > PAGE_SIZE) ++ copy = PAGE_SIZE; ++ (void)cpt_get_buf(ctx); ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ err = ctx->pread(ctx->tmpbuf, copy, ctx, ipos); ++ set_fs(oldfs); ++ if (err) { ++ __cpt_release_buf(ctx); ++ return err; ++ } ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ ipos += copy; ++ err = do_write(file, ctx->tmpbuf, copy, &opos); ++ set_fs(oldfs); ++ __cpt_release_buf(ctx); ++ if (err != copy) { ++ eprintk_ctx("write() failure\n"); ++ if (err >= 0) ++ err = -EIO; ++ return err; ++ } ++ count -= copy; ++ } ++ pos += pgb.cpt_next; ++ } ++ return 0; ++} ++ ++struct file * rst_sysv_shm(loff_t pos, struct cpt_context *ctx) ++{ ++ struct file *file; ++ int err; ++ loff_t dpos, epos; ++ union { ++ struct cpt_file_image fi; ++ struct cpt_sysvshm_image shmi; ++ struct cpt_inode_image ii; ++ } u; ++ ++ err = rst_get_object(CPT_OBJ_FILE, pos, &u.fi, ctx); ++ if (err < 0) ++ goto err_out; ++ pos = u.fi.cpt_inode; ++ err = rst_get_object(CPT_OBJ_INODE, pos, &u.ii, ctx); ++ if (err < 0) ++ goto err_out; ++ dpos = pos + u.ii.cpt_hdrlen; ++ epos = pos + u.ii.cpt_next; ++ err = rst_get_object(CPT_OBJ_SYSV_SHM, pos + u.ii.cpt_hdrlen, &u.shmi, ctx); ++ if (err < 0) ++ goto err_out; ++ dpos += u.shmi.cpt_next; ++ ++ file = sysvipc_setup_shm(u.shmi.cpt_key, u.shmi.cpt_id, ++ u.shmi.cpt_segsz, u.shmi.cpt_mode); ++ if (!IS_ERR(file)) { ++ err = fixup_shm(file, &u.shmi); ++ if (err != -EEXIST && dpos < epos) ++ err = fixup_shm_data(file, dpos, epos, ctx); ++ } ++ ++ return file; ++ ++err_out: ++ return ERR_PTR(err); ++} ++ ++static int attach_one_undo(int semid, struct sem_array *sma, void *arg) ++{ ++ struct sem_undo *su = arg; ++ struct sem_undo_list *undo_list = current->sysvsem.undo_list; ++ ++ if (semid != su->semid) ++ return 0; ++ ++ su->proc_next = undo_list->proc_list; ++ undo_list->proc_list = su; ++ ++ su->id_next = sma->undo; ++ sma->undo = su; ++ ++ return 1; ++} ++ ++static int attach_undo(struct sem_undo *su) ++{ ++ return sysvipc_walk_sem(attach_one_undo, su); ++} ++ ++static int do_rst_semundo(struct cpt_object_hdr *sui, loff_t pos, struct cpt_context *ctx) ++{ ++ int err; ++ struct sem_undo_list *undo_list; ++ ++ if (current->sysvsem.undo_list) { ++ eprintk_ctx("Funny undo_list\n"); ++ return 0; ++ } ++ ++ undo_list = kzalloc(sizeof(struct sem_undo_list), GFP_KERNEL_UBC); ++ if (undo_list == NULL) ++ return -ENOMEM; ++ ++ atomic_set(&undo_list->refcnt, 1); ++ spin_lock_init(&undo_list->lock); ++ current->sysvsem.undo_list = undo_list; ++ ++ if (sui->cpt_next > sui->cpt_hdrlen) { ++ loff_t offset = pos + sui->cpt_hdrlen; ++ do { ++ struct sem_undo *new; ++ struct cpt_sysvsem_undo_image spi; ++ err = rst_get_object(CPT_OBJ_SYSVSEM_UNDO_REC, offset, &spi, ctx); ++ if (err) ++ goto out; ++ new = kmalloc(sizeof(struct sem_undo) + ++ sizeof(short)*spi.cpt_nsem, ++ GFP_KERNEL_UBC); ++ if (!new) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ memset(new, 0, sizeof(struct sem_undo) + sizeof(short)*spi.cpt_nsem); ++ new->semadj = (short *) &new[1]; ++ new->semid = spi.cpt_id; ++ err = ctx->pread(new->semadj, spi.cpt_nsem*sizeof(short), ctx, offset + spi.cpt_hdrlen); ++ if (err) { ++ kfree(new); ++ goto out; ++ } ++ err = attach_undo(new); ++ if (err <= 0) { ++ if (err == 0) ++ err = -ENOENT; ++ kfree(new); ++ goto out; ++ } ++ offset += spi.cpt_next; ++ } while (offset < pos + sui->cpt_next); ++ } ++ err = 0; ++ ++out: ++ return err; ++} ++ ++__u32 rst_semundo_flag(struct cpt_task_image *ti, struct cpt_context *ctx) ++{ ++ __u32 flag = 0; ++ ++#if 0 ++ if (ti->cpt_sysvsem_undo == CPT_NULL || ++ lookup_cpt_obj_bypos(CPT_OBJ_SYSVSEM_UNDO, ti->cpt_sysvsem_undo)) ++ flag |= CLONE_SYSVSEM; ++#endif ++ return flag; ++} ++ ++int rst_semundo_complete(struct cpt_task_image *ti, struct cpt_context *ctx) ++{ ++ int err; ++ struct sem_undo_list *f = current->sysvsem.undo_list; ++ cpt_object_t *obj; ++ struct cpt_object_hdr sui; ++ ++ if (ti->cpt_sysvsem_undo == CPT_NULL) { ++ exit_sem(current); ++ return 0; ++ } ++ ++ obj = lookup_cpt_obj_bypos(CPT_OBJ_SYSVSEM_UNDO, ti->cpt_sysvsem_undo, ctx); ++ if (obj) { ++ if (obj->o_obj != f) { ++ exit_sem(current); ++ f = obj->o_obj; ++ atomic_inc(&f->refcnt); ++ current->sysvsem.undo_list = f; ++ } ++ return 0; ++ } ++ ++ if ((err = rst_get_object(CPT_OBJ_SYSVSEM_UNDO, ti->cpt_sysvsem_undo, &sui, ctx)) != 0) ++ goto out; ++ ++ if ((err = do_rst_semundo(&sui, ti->cpt_sysvsem_undo, ctx)) != 0) ++ goto out; ++ ++ err = -ENOMEM; ++ obj = cpt_object_add(CPT_OBJ_SYSVSEM_UNDO, f, ctx); ++ if (obj) { ++ err = 0; ++ cpt_obj_setpos(obj, ti->cpt_sysvsem_undo, ctx); ++ } ++ ++ return 0; ++ ++out: ++ return err; ++} ++ ++struct _sarg { ++ int semid; ++ struct cpt_sysvsem_image *v; ++ __u32 *arr; ++}; ++ ++static int fixup_one_sem(int semid, struct sem_array *sma, void *arg) ++{ ++ struct _sarg *warg = arg; ++ ++ if (semid != warg->semid) ++ return 0; ++ ++ sma->sem_perm.uid = warg->v->cpt_uid; ++ sma->sem_perm.gid = warg->v->cpt_gid; ++ sma->sem_perm.cuid = warg->v->cpt_cuid; ++ sma->sem_perm.cgid = warg->v->cpt_cgid; ++ sma->sem_perm.mode = warg->v->cpt_mode; ++ sma->sem_perm.seq = warg->v->cpt_seq; ++ ++ sma->sem_ctime = warg->v->cpt_ctime; ++ sma->sem_otime = warg->v->cpt_otime; ++ memcpy(sma->sem_base, warg->arr, sma->sem_nsems*8); ++ return 1; ++} ++ ++static int fixup_sem(int semid, struct cpt_sysvsem_image *v, __u32 *arr) ++{ ++ struct _sarg warg; ++ ++ warg.semid = semid; ++ warg.v = v; ++ warg.arr = arr; ++ ++ return sysvipc_walk_sem(fixup_one_sem, &warg); ++} ++ ++ ++static int restore_sem(loff_t pos, struct cpt_sysvsem_image *si, ++ struct cpt_context *ctx) ++{ ++ int err; ++ __u32 *arr; ++ int nsems = (si->cpt_next - si->cpt_hdrlen)/8; ++ ++ arr = kmalloc(nsems*8, GFP_KERNEL); ++ if (!arr) ++ return -ENOMEM; ++ ++ err = ctx->pread(arr, nsems*8, ctx, pos+si->cpt_hdrlen); ++ if (err) ++ goto out; ++ err = sysvipc_setup_sem(si->cpt_key, si->cpt_id, nsems, si->cpt_mode); ++ if (err < 0) { ++ eprintk_ctx("SEM 3\n"); ++ goto out; ++ } ++ err = fixup_sem(si->cpt_id, si, arr); ++ if (err == 0) ++ err = -ESRCH; ++ if (err > 0) ++ err = 0; ++out: ++ kfree(arr); ++ return err; ++} ++ ++static int rst_sysv_sem(struct cpt_context *ctx) ++{ ++ int err; ++ loff_t sec = ctx->sections[CPT_SECT_SYSV_SEM]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ struct cpt_sysvsem_image sbuf; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_SYSV_SEM || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ int err; ++ err = rst_get_object(CPT_OBJ_SYSV_SEM, sec, &sbuf, ctx); ++ if (err) ++ return err; ++ err = restore_sem(sec, &sbuf, ctx); ++ if (err) ++ return err; ++ sec += sbuf.cpt_next; ++ } ++ return 0; ++} ++ ++struct _marg { ++ int msqid; ++ struct cpt_sysvmsg_image *v; ++ struct msg_queue *m; ++}; ++ ++static int fixup_one_msg(int msqid, struct msg_queue *msq, void *arg) ++{ ++ struct _marg *warg = arg; ++ ++ if (msqid != warg->msqid) ++ return 0; ++ ++ msq->q_perm.uid = warg->v->cpt_uid; ++ msq->q_perm.gid = warg->v->cpt_gid; ++ msq->q_perm.cuid = warg->v->cpt_cuid; ++ msq->q_perm.cgid = warg->v->cpt_cgid; ++ msq->q_perm.mode = warg->v->cpt_mode; ++ msq->q_perm.seq = warg->v->cpt_seq; ++ ++ msq->q_stime = warg->v->cpt_stime; ++ msq->q_rtime = warg->v->cpt_rtime; ++ msq->q_ctime = warg->v->cpt_ctime; ++ msq->q_lspid = warg->v->cpt_last_sender; ++ msq->q_lrpid = warg->v->cpt_last_receiver; ++ msq->q_qbytes = warg->v->cpt_qbytes; ++ ++ warg->m = msq; ++ return 1; ++} ++ ++struct _larg ++{ ++ cpt_context_t * ctx; ++ loff_t pos; ++}; ++ ++static int do_load_msg(void * dst, int len, int offset, void * data) ++{ ++ struct _larg * arg = data; ++ return arg->ctx->pread(dst, len, arg->ctx, arg->pos + offset); ++} ++ ++static int fixup_msg(int msqid, struct cpt_sysvmsg_image *v, loff_t pos, ++ cpt_context_t * ctx) ++{ ++ int err; ++ struct _marg warg; ++ loff_t endpos = pos + v->cpt_next; ++ struct ipc_namespace *ns = current->nsproxy->ipc_ns; ++ ++ pos += v->cpt_hdrlen; ++ ++ warg.msqid = msqid; ++ warg.v = v; ++ ++ err = sysvipc_walk_msg(fixup_one_msg, &warg); ++ if (err <= 0) ++ return err; ++ ++ while (pos < endpos) { ++ struct cpt_sysvmsg_msg_image mi; ++ struct msg_msg *m; ++ struct _larg data = { ++ .ctx = ctx ++ }; ++ ++ err = rst_get_object(CPT_OBJ_SYSVMSG_MSG, pos, &mi, ctx); ++ if (err) ++ return err; ++ data.pos = pos + mi.cpt_hdrlen; ++ m = sysv_msg_load(do_load_msg, mi.cpt_size, &data); ++ if (IS_ERR(m)) ++ return PTR_ERR(m); ++ m->m_type = mi.cpt_type; ++ m->m_ts = mi.cpt_size; ++ list_add_tail(&m->m_list, &warg.m->q_messages); ++ warg.m->q_cbytes += m->m_ts; ++ warg.m->q_qnum++; ++ atomic_add(m->m_ts, &ns->msg_bytes); ++ atomic_inc(&ns->msg_hdrs); ++ ++ pos += mi.cpt_next; ++ } ++ return 1; ++} ++ ++static int restore_msg(loff_t pos, struct cpt_sysvmsg_image *si, ++ struct cpt_context *ctx) ++{ ++ int err; ++ ++ err = sysvipc_setup_msg(si->cpt_key, si->cpt_id, si->cpt_mode); ++ if (err < 0) { ++ eprintk_ctx("MSG 3\n"); ++ goto out; ++ } ++ err = fixup_msg(si->cpt_id, si, pos, ctx); ++ if (err == 0) ++ err = -ESRCH; ++ if (err > 0) ++ err = 0; ++out: ++ return err; ++} ++ ++static int rst_sysv_msg(struct cpt_context *ctx) ++{ ++ int err; ++ loff_t sec = ctx->sections[CPT_SECT_SYSV_MSG]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ struct cpt_sysvmsg_image sbuf; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_SYSV_MSG || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ int err; ++ err = rst_get_object(CPT_OBJ_SYSVMSG, sec, &sbuf, ctx); ++ if (err) ++ return err; ++ err = restore_msg(sec, &sbuf, ctx); ++ if (err) ++ return err; ++ sec += sbuf.cpt_next; ++ } ++ return 0; ++} ++ ++ ++int rst_sysv_ipc(struct cpt_context *ctx) ++{ ++ int err; ++ ++ err = rst_sysv_sem(ctx); ++ if (!err) ++ err = rst_sysv_msg(ctx); ++ ++ return err; ++} +Index: kernel/kernel/cpt/rst_tty.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_tty.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,379 @@ ++/* ++ * ++ * kernel/cpt/rst_tty.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_mm.h" ++#include "cpt_process.h" ++#include "cpt_files.h" ++#include "cpt_kernel.h" ++ ++static int pty_setup(struct tty_struct *stty, loff_t pos, ++ struct cpt_tty_image *pi, struct cpt_context *ctx) ++{ ++ unsigned long flags; ++ ++ stty->pgrp = NULL; ++ stty->session = NULL; ++ stty->packet = pi->cpt_packet; ++ stty->stopped = pi->cpt_stopped; ++ stty->hw_stopped = pi->cpt_hw_stopped; ++ stty->flow_stopped = pi->cpt_flow_stopped; ++#define DONOT_CHANGE ((1<flags & DONOT_CHANGE; ++ stty->flags = flags | (pi->cpt_flags & ~DONOT_CHANGE); ++ stty->ctrl_status = pi->cpt_ctrl_status; ++ stty->winsize.ws_row = pi->cpt_ws_row; ++ stty->winsize.ws_col = pi->cpt_ws_col; ++ stty->winsize.ws_ypixel = pi->cpt_ws_prow; ++ stty->winsize.ws_xpixel = pi->cpt_ws_pcol; ++ stty->canon_column = pi->cpt_canon_column; ++ stty->column = pi->cpt_column; ++ stty->raw = pi->cpt_raw; ++ stty->real_raw = pi->cpt_real_raw; ++ stty->erasing = pi->cpt_erasing; ++ stty->lnext = pi->cpt_lnext; ++ stty->icanon = pi->cpt_icanon; ++ stty->closing = pi->cpt_closing; ++ stty->minimum_to_wake = pi->cpt_minimum_to_wake; ++ ++ stty->termios->c_iflag = pi->cpt_c_iflag; ++ stty->termios->c_oflag = pi->cpt_c_oflag; ++ stty->termios->c_lflag = pi->cpt_c_lflag; ++ stty->termios->c_cflag = pi->cpt_c_cflag; ++ memcpy(&stty->termios->c_cc, &pi->cpt_c_cc, NCCS); ++ memcpy(stty->read_flags, pi->cpt_read_flags, sizeof(stty->read_flags)); ++ ++ if (pi->cpt_next > pi->cpt_hdrlen) { ++ int err; ++ struct cpt_obj_bits b; ++ err = rst_get_object(CPT_OBJ_BITS, pos + pi->cpt_hdrlen, &b, ctx); ++ if (err) ++ return err; ++ if (b.cpt_size == 0) ++ return 0; ++ err = ctx->pread(stty->read_buf, b.cpt_size, ctx, pos + pi->cpt_hdrlen + b.cpt_hdrlen); ++ if (err) ++ return err; ++ ++ spin_lock_irq(&stty->read_lock); ++ stty->read_tail = 0; ++ stty->read_cnt = b.cpt_size; ++ stty->read_head = b.cpt_size; ++ stty->canon_head = stty->read_tail + pi->cpt_canon_head; ++ stty->canon_data = pi->cpt_canon_data; ++ spin_unlock_irq(&stty->read_lock); ++ } ++ ++ return 0; ++} ++ ++/* Find slave/master tty in image, when we already know master/slave. ++ * It might be optimized, of course. */ ++static loff_t find_pty_pair(struct tty_struct *stty, loff_t pos, struct cpt_tty_image *pi, struct cpt_context *ctx) ++{ ++ int err; ++ loff_t sec = ctx->sections[CPT_SECT_TTY]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ struct cpt_tty_image *pibuf; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return CPT_NULL; ++ if (h.cpt_section != CPT_SECT_TTY || h.cpt_hdrlen < sizeof(h)) ++ return CPT_NULL; ++ pibuf = kmalloc(sizeof(*pibuf), GFP_KERNEL); ++ if (pibuf == NULL) { ++ eprintk_ctx("cannot allocate buffer\n"); ++ return CPT_NULL; ++ } ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ if (rst_get_object(CPT_OBJ_TTY, sec, pibuf, ctx)) ++ return CPT_NULL; ++ if (pibuf->cpt_index == pi->cpt_index && ++ !((pi->cpt_drv_flags^pibuf->cpt_drv_flags)&TTY_DRIVER_DEVPTS_MEM) && ++ pos != sec) { ++ pty_setup(stty, sec, pibuf, ctx); ++ return sec; ++ } ++ sec += pibuf->cpt_next; ++ } ++ kfree(pibuf); ++ return CPT_NULL; ++} ++ ++static int fixup_tty_attrs(struct cpt_inode_image *ii, struct file *master, ++ struct cpt_context *ctx) ++{ ++ int err; ++ struct iattr newattrs; ++ struct dentry *d = master->f_dentry; ++ ++ newattrs.ia_valid = ATTR_UID|ATTR_GID|ATTR_MODE; ++ newattrs.ia_uid = ii->cpt_uid; ++ newattrs.ia_gid = ii->cpt_gid; ++ newattrs.ia_mode = ii->cpt_mode; ++ ++ mutex_lock(&d->d_inode->i_mutex); ++ err = notify_change(d, NULL, &newattrs); ++ mutex_unlock(&d->d_inode->i_mutex); ++ ++ return err; ++} ++ ++/* NOTE: "portable", but ugly thing. To allocate /dev/pts/N, we open ++ * /dev/ptmx until we get pty with desired index. ++ */ ++ ++struct file *ptmx_open(int index, unsigned int flags) ++{ ++ struct file *file; ++ struct file **stack = NULL; ++ int depth = 0; ++ ++ for (;;) { ++ struct tty_struct *tty; ++ ++ file = filp_open("/dev/ptmx", flags|O_NONBLOCK|O_NOCTTY|O_RDWR, 0); ++ if (IS_ERR(file)) ++ break; ++ tty = file->private_data; ++ if (tty->index == index) ++ break; ++ ++ if (depth == PAGE_SIZE/sizeof(struct file *)) { ++ fput(file); ++ file = ERR_PTR(-EBUSY); ++ break; ++ } ++ if (stack == NULL) { ++ stack = (struct file **)__get_free_page(GFP_KERNEL); ++ if (!stack) { ++ fput(file); ++ file = ERR_PTR(-ENOMEM); ++ break; ++ } ++ } ++ stack[depth] = file; ++ depth++; ++ } ++ while (depth > 0) { ++ depth--; ++ fput(stack[depth]); ++ } ++ if (stack) ++ free_page((unsigned long)stack); ++ return file; ++} ++ ++ ++struct file * rst_open_tty(struct cpt_file_image *fi, struct cpt_inode_image *ii, ++ unsigned flags, struct cpt_context *ctx) ++{ ++ int err; ++ cpt_object_t *obj; ++ struct file *master, *slave; ++ struct tty_struct *stty; ++ struct cpt_tty_image *pi; ++ static char *a = "pqrstuvwxyzabcde"; ++ static char *b = "0123456789abcdef"; ++ char pairname[16]; ++ unsigned master_flags, slave_flags; ++ ++ if (fi->cpt_priv == CPT_NULL) ++ return ERR_PTR(-EINVAL); ++ ++ obj = lookup_cpt_obj_bypos(CPT_OBJ_TTY, fi->cpt_priv, ctx); ++ if (obj && obj->o_parent) { ++ dprintk_ctx("obtained pty as pair to existing\n"); ++ master = obj->o_parent; ++ stty = master->private_data; ++ ++ if (stty->driver->subtype == PTY_TYPE_MASTER && ++ (stty->driver->flags&TTY_DRIVER_DEVPTS_MEM)) { ++ wprintk_ctx("cloning ptmx\n"); ++ get_file(master); ++ return master; ++ } ++ ++ master = dentry_open(dget(master->f_dentry), ++ mntget(master->f_vfsmnt), flags); ++ if (!IS_ERR(master)) { ++ stty = master->private_data; ++ if (stty->driver->subtype != PTY_TYPE_MASTER) ++ fixup_tty_attrs(ii, master, ctx); ++ } ++ return master; ++ } ++ ++ pi = cpt_get_buf(ctx); ++ err = rst_get_object(CPT_OBJ_TTY, fi->cpt_priv, pi, ctx); ++ if (err) { ++ cpt_release_buf(ctx); ++ return ERR_PTR(err); ++ } ++ ++ master_flags = slave_flags = 0; ++ if (pi->cpt_drv_subtype == PTY_TYPE_MASTER) ++ master_flags = flags; ++ else ++ slave_flags = flags; ++ ++ /* ++ * Open pair master/slave. ++ */ ++ if (pi->cpt_drv_flags&TTY_DRIVER_DEVPTS_MEM) { ++ master = ptmx_open(pi->cpt_index, master_flags); ++ } else { ++ sprintf(pairname, "/dev/pty%c%c", a[pi->cpt_index/16], b[pi->cpt_index%16]); ++ master = filp_open(pairname, master_flags|O_NONBLOCK|O_NOCTTY|O_RDWR, 0); ++ } ++ if (IS_ERR(master)) { ++ eprintk_ctx("filp_open master: %Ld %ld\n", (long long)fi->cpt_priv, PTR_ERR(master)); ++ cpt_release_buf(ctx); ++ return master; ++ } ++ stty = master->private_data; ++ clear_bit(TTY_PTY_LOCK, &stty->flags); ++ if (pi->cpt_drv_flags&TTY_DRIVER_DEVPTS_MEM) ++ sprintf(pairname, "/dev/pts/%d", stty->index); ++ else ++ sprintf(pairname, "/dev/tty%c%c", a[stty->index/16], b[stty->index%16]); ++ slave = filp_open(pairname, slave_flags|O_NONBLOCK|O_NOCTTY|O_RDWR, 0); ++ if (IS_ERR(slave)) { ++ eprintk_ctx("filp_open slave %s: %ld\n", pairname, PTR_ERR(slave)); ++ fput(master); ++ cpt_release_buf(ctx); ++ return slave; ++ } ++ ++ if (pi->cpt_drv_subtype != PTY_TYPE_MASTER) ++ fixup_tty_attrs(ii, slave, ctx); ++ ++ cpt_object_add(CPT_OBJ_TTY, master->private_data, ctx); ++ cpt_object_add(CPT_OBJ_TTY, slave->private_data, ctx); ++ cpt_object_add(CPT_OBJ_FILE, master, ctx); ++ cpt_object_add(CPT_OBJ_FILE, slave, ctx); ++ ++ if (pi->cpt_drv_subtype == PTY_TYPE_MASTER) { ++ loff_t pos; ++ obj = lookup_cpt_object(CPT_OBJ_TTY, master->private_data, ctx); ++ obj->o_parent = master; ++ cpt_obj_setpos(obj, fi->cpt_priv, ctx); ++ pty_setup(stty, fi->cpt_priv, pi, ctx); ++ ++ obj = lookup_cpt_object(CPT_OBJ_TTY, slave->private_data, ctx); ++ obj->o_parent = slave; ++ pos = find_pty_pair(stty->link, fi->cpt_priv, pi, ctx); ++ cpt_obj_setpos(obj, pos, ctx); ++ ++ obj = lookup_cpt_object(CPT_OBJ_FILE, slave, ctx); ++ cpt_obj_setpos(obj, CPT_NULL, ctx); ++ get_file(master); ++ cpt_release_buf(ctx); ++ return master; ++ } else { ++ loff_t pos; ++ obj = lookup_cpt_object(CPT_OBJ_TTY, slave->private_data, ctx); ++ obj->o_parent = slave; ++ cpt_obj_setpos(obj, fi->cpt_priv, ctx); ++ pty_setup(stty->link, fi->cpt_priv, pi, ctx); ++ ++ obj = lookup_cpt_object(CPT_OBJ_TTY, master->private_data, ctx); ++ obj->o_parent = master; ++ pos = find_pty_pair(stty, fi->cpt_priv, pi, ctx); ++ cpt_obj_setpos(obj, pos, ctx); ++ ++ obj = lookup_cpt_object(CPT_OBJ_FILE, master, ctx); ++ cpt_obj_setpos(obj, CPT_NULL, ctx); ++ get_file(slave); ++ cpt_release_buf(ctx); ++ return slave; ++ } ++} ++ ++int rst_tty_jobcontrol(struct cpt_context *ctx) ++{ ++ int err; ++ loff_t sec = ctx->sections[CPT_SECT_TTY]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_TTY || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ cpt_object_t *obj; ++ struct cpt_tty_image *pibuf = cpt_get_buf(ctx); ++ ++ if (rst_get_object(CPT_OBJ_TTY, sec, pibuf, ctx)) { ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ ++ obj = lookup_cpt_obj_bypos(CPT_OBJ_TTY, sec, ctx); ++ if (obj) { ++ struct tty_struct *stty = obj->o_obj; ++ if ((int)pibuf->cpt_pgrp > 0) { ++ stty->pgrp = alloc_vpid_safe(pibuf->cpt_pgrp); ++ if (!stty->pgrp) ++ dprintk_ctx("unknown tty pgrp %d\n", pibuf->cpt_pgrp); ++ } else if (pibuf->cpt_pgrp) { ++ stty->pgrp = alloc_pid(current->nsproxy->pid_ns, ++ 0); ++ if (!stty->pgrp) { ++ eprintk_ctx("cannot allocate stray tty->pgrp"); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++ } ++ if ((int)pibuf->cpt_session > 0) { ++ struct pid *sess; ++ sess = alloc_vpid_safe(pibuf->cpt_session); ++ if (!sess) { ++ dprintk_ctx("unknown tty session %d\n", pibuf->cpt_session); ++ } else if (!stty->session) { ++ stty->session = sess; ++ } ++ } ++ } ++ sec += pibuf->cpt_next; ++ cpt_release_buf(ctx); ++ } ++ return 0; ++} +Index: kernel/kernel/cpt/rst_ubc.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_ubc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,131 @@ ++/* ++ * ++ * kernel/cpt/rst_ubc.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++ ++struct user_beancounter *rst_lookup_ubc(__u64 pos, struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ obj = lookup_cpt_obj_bypos(CPT_OBJ_UBC, pos, ctx); ++ if (obj == NULL) { ++ eprintk("RST: unknown ub @%Ld\n", (long long)pos); ++ return get_beancounter(get_exec_ub()); ++ } ++ return get_beancounter(obj->o_obj); ++} ++ ++void copy_one_ubparm(struct ubparm *from, struct ubparm *to, int bc_parm_id) ++{ ++ to[bc_parm_id].barrier = from[bc_parm_id].barrier; ++ to[bc_parm_id].limit = from[bc_parm_id].limit; ++} ++ ++void set_one_ubparm_to_max(struct ubparm *ubprm, int bc_parm_id) ++{ ++ ubprm[bc_parm_id].barrier = UB_MAXVALUE; ++ ubprm[bc_parm_id].limit = UB_MAXVALUE; ++} ++ ++static void restore_one_bc_parm(struct cpt_ubparm *dmp, struct ubparm *prm, ++ int held) ++{ ++ prm->barrier = (dmp->barrier == CPT_NULL ? UB_MAXVALUE : dmp->barrier); ++ prm->limit = (dmp->limit == CPT_NULL ? UB_MAXVALUE : dmp->limit); ++ if (held) ++ prm->held = dmp->held; ++ prm->maxheld = dmp->maxheld; ++ prm->minheld = dmp->minheld; ++ prm->failcnt = dmp->failcnt; ++} ++ ++static int restore_one_bc(struct cpt_beancounter_image *v, ++ cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ struct user_beancounter *bc; ++ cpt_object_t *pobj; ++ int i; ++ ++ if (v->cpt_parent != CPT_NULL) { ++ pobj = lookup_cpt_obj_bypos(CPT_OBJ_UBC, v->cpt_parent, ctx); ++ if (pobj == NULL) ++ return -ESRCH; ++ bc = get_subbeancounter_byid(pobj->o_obj, v->cpt_id, 1); ++ } else { ++ bc = get_exec_ub(); ++ while (bc->parent) ++ bc = bc->parent; ++ get_beancounter(bc); ++ } ++ if (bc == NULL) ++ return -ENOMEM; ++ obj->o_obj = bc; ++ ++ if (ctx->image_version < CPT_VERSION_18 && ++ CPT_VERSION_MINOR(ctx->image_version) < 1) ++ goto out; ++ ++ for (i = 0; i < UB_RESOURCES; i++) { ++ restore_one_bc_parm(v->cpt_parms + i * 2, bc->ub_parms + i, 0); ++ restore_one_bc_parm(v->cpt_parms + i * 2 + 1, ++ bc->ub_store + i, 1); ++ } ++ ++out: ++ if (!bc->parent) ++ for (i = 0; i < UB_RESOURCES; i++) ++ copy_one_ubparm(bc->ub_parms, ctx->saved_ubc, i); ++ ++ return 0; ++} ++ ++int rst_undump_ubc(struct cpt_context *ctx) ++{ ++ loff_t start, end; ++ struct cpt_beancounter_image *v; ++ cpt_object_t *obj; ++ int err; ++ ++ err = rst_get_section(CPT_SECT_UBC, ctx, &start, &end); ++ if (err) ++ return err; ++ ++ while (start < end) { ++ v = cpt_get_buf(ctx); ++ err = rst_get_object(CPT_OBJ_UBC, start, v, ctx); ++ if (err) { ++ cpt_release_buf(ctx); ++ return err; ++ } ++ ++ obj = alloc_cpt_object(GFP_KERNEL, ctx); ++ cpt_obj_setpos(obj, start, ctx); ++ intern_cpt_object(CPT_OBJ_UBC, obj, ctx); ++ ++ restore_one_bc(v, obj, ctx); ++ ++ cpt_release_buf(ctx); ++ start += v->cpt_next; ++ } ++ return 0; ++} ++ ++void rst_finish_ubc(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ ++ for_each_object(obj, CPT_OBJ_UBC) ++ put_beancounter(obj->o_obj); ++} +Index: kernel/kernel/cpt/rst_undump.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/cpt/rst_undump.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,1005 @@ ++/* ++ * ++ * kernel/cpt/rst_undump.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_X86 ++#include ++#endif ++#include ++#include ++#include ++#include ++ ++#include "cpt_obj.h" ++#include "cpt_context.h" ++#include "cpt_files.h" ++#include "cpt_mm.h" ++#include "cpt_process.h" ++#include "cpt_socket.h" ++#include "cpt_net.h" ++#include "cpt_ubc.h" ++#include "cpt_kernel.h" ++ ++static int rst_utsname(cpt_context_t *ctx); ++ ++ ++struct thr_context { ++ struct completion init_complete; ++ struct completion task_done; ++ int error; ++ struct cpt_context *ctx; ++ cpt_object_t *tobj; ++}; ++ ++static int rst_clone_children(cpt_object_t *obj, struct cpt_context *ctx); ++ ++static int vps_rst_veinfo(struct cpt_context *ctx) ++{ ++ int err; ++ struct cpt_veinfo_image *i; ++ struct ve_struct *ve; ++ struct timespec delta; ++ loff_t start, end; ++ struct ipc_namespace *ns; ++ ++ err = rst_get_section(CPT_SECT_VEINFO, ctx, &start, &end); ++ if (err) ++ goto out; ++ ++ i = cpt_get_buf(ctx); ++ memset(i, 0, sizeof(*i)); ++ err = rst_get_object(CPT_OBJ_VEINFO, start, i, ctx); ++ if (err) ++ goto out_rel; ++ ++ ve = get_exec_env(); ++ ns = ve->ve_ns->ipc_ns; ++ ++ /* Damn. Fatal mistake, these two values are size_t! */ ++ ns->shm_ctlall = i->shm_ctl_all ? : 0xFFFFFFFFU; ++ ns->shm_ctlmax = i->shm_ctl_max ? : 0xFFFFFFFFU; ++ ns->shm_ctlmni = i->shm_ctl_mni; ++ ++ ns->msg_ctlmax = i->msg_ctl_max; ++ ns->msg_ctlmni = i->msg_ctl_mni; ++ ns->msg_ctlmnb = i->msg_ctl_mnb; ++ ++ BUILD_BUG_ON(sizeof(ns->sem_ctls) != sizeof(i->sem_ctl_arr)); ++ ns->sem_ctls[0] = i->sem_ctl_arr[0]; ++ ns->sem_ctls[1] = i->sem_ctl_arr[1]; ++ ns->sem_ctls[2] = i->sem_ctl_arr[2]; ++ ns->sem_ctls[3] = i->sem_ctl_arr[3]; ++ ++ cpt_timespec_import(&delta, i->start_timespec_delta); ++ _set_normalized_timespec(&ve->start_timespec, ++ ve->start_timespec.tv_sec - delta.tv_sec, ++ ve->start_timespec.tv_nsec - delta.tv_nsec); ++ ve->start_jiffies -= i->start_jiffies_delta; ++ // // FIXME: what??? ++ // // ve->start_cycles -= (s64)i->start_jiffies_delta * cycles_per_jiffy; ++ ++ ctx->last_vpid = i->last_pid; ++ ++ err = 0; ++out_rel: ++ cpt_release_buf(ctx); ++out: ++ return err; ++} ++ ++static int vps_rst_reparent_root(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ int err; ++ struct env_create_param3 param; ++ ++ do_posix_clock_monotonic_gettime(&ctx->cpt_monotonic_time); ++ do_gettimespec(&ctx->delta_time); ++ ++ _set_normalized_timespec(&ctx->delta_time, ++ ctx->delta_time.tv_sec - ctx->start_time.tv_sec, ++ ctx->delta_time.tv_nsec - ctx->start_time.tv_nsec); ++ ctx->delta_nsec = (s64)ctx->delta_time.tv_sec*NSEC_PER_SEC + ctx->delta_time.tv_nsec; ++ if (ctx->delta_nsec < 0) { ++ wprintk_ctx("Wall time is behind source by %Ld ns, " ++ "time sensitive applications can misbehave\n", (long long)-ctx->delta_nsec); ++ } ++ ++ _set_normalized_timespec(&ctx->cpt_monotonic_time, ++ ctx->cpt_monotonic_time.tv_sec - ctx->delta_time.tv_sec, ++ ctx->cpt_monotonic_time.tv_nsec - ctx->delta_time.tv_nsec); ++ ++ memset(¶m, 0, sizeof(param)); ++ param.iptables_mask = ctx->iptables_mask; ++ param.feature_mask = ctx->features; ++ ++ /* feature_mask is set as required - pretend we know everything */ ++ param.known_features = (ctx->image_version < CPT_VERSION_18) ? ++ VE_FEATURES_OLD : ~(__u64)0; ++ ++ err = real_env_create(ctx->ve_id, VE_CREATE|VE_LOCK, 2, ++ ¶m, sizeof(param)); ++ if (err < 0) ++ eprintk_ctx("real_env_create: %d\n", err); ++ ++ get_exec_env()->jiffies_fixup = ++ (ctx->delta_time.tv_sec < 0 ? ++ 0 : timespec_to_jiffies(&ctx->delta_time)) - ++ (unsigned long)(get_jiffies_64() - ctx->virt_jiffies64); ++ dprintk_ctx("JFixup %ld %Ld\n", get_exec_env()->jiffies_fixup, ++ (long long)ctx->delta_nsec); ++ return err < 0 ? err : 0; ++} ++ ++static int hook(void *arg) ++{ ++ struct thr_context *thr_ctx = arg; ++ struct cpt_context *ctx; ++ cpt_object_t *tobj; ++ struct cpt_task_image *ti; ++ int err = 0; ++ int exiting = 0; ++ ++ current->state = TASK_UNINTERRUPTIBLE; ++ complete(&thr_ctx->init_complete); ++ schedule(); ++ ++ ctx = thr_ctx->ctx; ++ tobj = thr_ctx->tobj; ++ ti = tobj->o_image; ++ ++ current->fs->umask = 0; ++ ++ if (ti->cpt_pid == 1) { ++#ifdef CONFIG_BEANCOUNTERS ++ struct user_beancounter *bc; ++#endif ++ ++ err = vps_rst_reparent_root(tobj, ctx); ++ ++ if (err) { ++ rst_report_error(err, ctx); ++ goto out; ++ } ++ ++ memcpy(&cap_bset, &ti->cpt_ecap, sizeof(kernel_cap_t)); ++ ++ if (ctx->statusfile) { ++ fput(ctx->statusfile); ++ ctx->statusfile = NULL; ++ } ++ ++ if (ctx->lockfile) { ++ char b; ++ mm_segment_t oldfs; ++ err = -EINVAL; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ if (ctx->lockfile->f_op && ctx->lockfile->f_op->read) ++ err = ctx->lockfile->f_op->read(ctx->lockfile, &b, 1, &ctx->lockfile->f_pos); ++ set_fs(oldfs); ++ fput(ctx->lockfile); ++ ctx->lockfile = NULL; ++ } ++ ++ if (err) { ++ eprintk_ctx("CPT: lock fd is closed incorrectly: %d\n", err); ++ goto out; ++ } ++ err = vps_rst_veinfo(ctx); ++ if (err) { ++ eprintk_ctx("rst_veinfo: %d\n", err); ++ goto out; ++ } ++ ++ err = rst_utsname(ctx); ++ if (err) { ++ eprintk_ctx("rst_utsname: %d\n", err); ++ goto out; ++ } ++ ++ err = rst_root_namespace(ctx); ++ if (err) { ++ eprintk_ctx("rst_namespace: %d\n", err); ++ goto out; ++ } ++ ++ if ((err = rst_restore_net(ctx)) != 0) { ++ eprintk_ctx("rst_restore_net: %d\n", err); ++ goto out; ++ } ++ ++ err = rst_sockets(ctx); ++ if (err) { ++ eprintk_ctx("rst_sockets: %d\n", err); ++ goto out; ++ } ++ err = rst_sysv_ipc(ctx); ++ if (err) { ++ eprintk_ctx("rst_sysv_ipc: %d\n", err); ++ goto out; ++ } ++#ifdef CONFIG_BEANCOUNTERS ++ bc = get_exec_ub(); ++ set_one_ubparm_to_max(bc->ub_parms, UB_KMEMSIZE); ++ set_one_ubparm_to_max(bc->ub_parms, UB_NUMPROC); ++ set_one_ubparm_to_max(bc->ub_parms, UB_NUMFILE); ++ set_one_ubparm_to_max(bc->ub_parms, UB_DCACHESIZE); ++#endif ++ } ++ ++ do { ++ if (current->user->uid != ti->cpt_user) { ++ struct user_struct *u; ++ ++ u = alloc_uid(get_exec_env()->ve_ns->user_ns, ti->cpt_user); ++ if (!u) { ++ eprintk_ctx("alloc_user\n"); ++ } else { ++ switch_uid(u); ++ } ++ } ++ } while (0); ++ ++ if ((err = rst_mm_complete(ti, ctx)) != 0) { ++ eprintk_ctx("rst_mm: %d\n", err); ++ goto out; ++ } ++ ++ if ((err = rst_files_complete(ti, ctx)) != 0) { ++ eprintk_ctx("rst_files: %d\n", err); ++ goto out; ++ } ++ ++ if ((err = rst_fs_complete(ti, ctx)) != 0) { ++ eprintk_ctx("rst_fs: %d\n", err); ++ goto out; ++ } ++ ++ if ((err = rst_semundo_complete(ti, ctx)) != 0) { ++ eprintk_ctx("rst_semundo: %d\n", err); ++ goto out; ++ } ++ ++ if ((err = rst_signal_complete(ti, &exiting, ctx)) != 0) { ++ eprintk_ctx("rst_signal: %d\n", err); ++ goto out; ++ } ++ ++ if (ti->cpt_personality != 0) ++ __set_personality(ti->cpt_personality); ++ ++#ifdef CONFIG_X86_64 ++ /* 32bit app from 32bit OS, won't have PER_LINUX32 set... :/ */ ++ if (!ti->cpt_64bit) ++ __set_personality(PER_LINUX32); ++#endif ++ ++ current->set_child_tid = NULL; ++ current->clear_child_tid = NULL; ++ current->flags &= ~(PF_FORKNOEXEC|PF_SUPERPRIV); ++ current->flags |= ti->cpt_flags&(PF_FORKNOEXEC|PF_SUPERPRIV); ++ current->exit_code = ti->cpt_exit_code; ++ current->pdeath_signal = ti->cpt_pdeath_signal; ++ ++ if (ti->cpt_restart.fn != CPT_RBL_0) { ++ if (ti->cpt_restart.fn == CPT_RBL_NANOSLEEP ++#ifdef CONFIG_COMPAT ++ || ti->cpt_restart.fn == CPT_RBL_COMPAT_NANOSLEEP ++#endif ++ ) { ++ struct restart_block *rb; ++ ktime_t e; ++ ++ e.tv64 = 0; ++ ++ if (ctx->image_version >= CPT_VERSION_20) ++ e = ktime_add_ns(e, ti->cpt_restart.arg2); ++ else if (ctx->image_version >= CPT_VERSION_9) ++ e = ktime_add_ns(e, ti->cpt_restart.arg0); ++ else ++ e = ktime_add_ns(e, ti->cpt_restart.arg0*TICK_NSEC); ++ if (e.tv64 < 0) ++ e.tv64 = TICK_NSEC; ++ e = ktime_add(e, timespec_to_ktime(ctx->cpt_monotonic_time)); ++ ++ rb = &task_thread_info(current)->restart_block; ++ if (ti->cpt_restart.fn == CPT_RBL_NANOSLEEP) ++ rb->fn = hrtimer_nanosleep_restart; ++#ifdef CONFIG_COMPAT ++ else ++ rb->fn = compat_nanosleep_restart; ++#endif ++ if (ctx->image_version >= CPT_VERSION_20) { ++ rb->arg0 = ti->cpt_restart.arg0; ++ rb->arg1 = ti->cpt_restart.arg1; ++ rb->arg2 = e.tv64 & 0xFFFFFFFF; ++ rb->arg3 = e.tv64 >> 32; ++ } else if (ctx->image_version >= CPT_VERSION_9) { ++ rb->arg0 = ti->cpt_restart.arg2; ++ rb->arg1 = ti->cpt_restart.arg3; ++ rb->arg2 = e.tv64 & 0xFFFFFFFF; ++ rb->arg3 = e.tv64 >> 32; ++ } else { ++ rb->arg0 = ti->cpt_restart.arg1; ++ rb->arg1 = CLOCK_MONOTONIC; ++ rb->arg2 = e.tv64 & 0xFFFFFFFF; ++ rb->arg3 = e.tv64 >> 32; ++ } ++ } else if (ti->cpt_restart.fn == CPT_RBL_POLL) { ++ struct restart_block *rb; ++ ktime_t e; ++ struct timespec ts; ++ unsigned long timeout_jiffies; ++ ++ e.tv64 = 0; ++ e = ktime_add_ns(e, ti->cpt_restart.arg2); ++ e = ktime_sub(e, timespec_to_ktime(ctx->delta_time)); ++ ts = ns_to_timespec(ktime_to_ns(e)); ++ timeout_jiffies = timespec_to_jiffies(&ts); ++ ++ rb = &task_thread_info(current)->restart_block; ++ rb->fn = do_restart_poll; ++ rb->arg0 = ti->cpt_restart.arg0; ++ rb->arg1 = ti->cpt_restart.arg1; ++ rb->arg2 = timeout_jiffies & 0xFFFFFFFF; ++ rb->arg3 = (u64)timeout_jiffies >> 32; ++ } else if (ti->cpt_restart.fn == CPT_RBL_FUTEX_WAIT) { ++ struct restart_block *rb; ++ ktime_t e; ++ ++ e.tv64 = 0; ++ e = ktime_add_ns(e, ti->cpt_restart.arg2); ++ e = ktime_add(e, timespec_to_ktime(ctx->cpt_monotonic_time)); ++ ++ rb = &task_thread_info(current)->restart_block; ++ rb->fn = futex_wait_restart; ++ rb->futex.uaddr = (void *)(unsigned long)ti->cpt_restart.arg0; ++ rb->futex.val = ti->cpt_restart.arg1; ++ rb->futex.time = e.tv64; ++ rb->futex.flags = ti->cpt_restart.arg3; ++ } else ++ eprintk_ctx("unknown restart block\n"); ++ } ++ ++ if (thread_group_leader(current)) { ++ current->signal->it_real_incr.tv64 = 0; ++ if (ctx->image_version >= CPT_VERSION_9) { ++ current->signal->it_real_incr = ++ ktime_add_ns(current->signal->it_real_incr, ti->cpt_it_real_incr); ++ } else { ++ current->signal->it_real_incr = ++ ktime_add_ns(current->signal->it_real_incr, ti->cpt_it_real_incr*TICK_NSEC); ++ } ++ current->signal->it_prof_incr = ti->cpt_it_prof_incr; ++ current->signal->it_virt_incr = ti->cpt_it_virt_incr; ++ current->signal->it_prof_expires = ti->cpt_it_prof_value; ++ current->signal->it_virt_expires = ti->cpt_it_virt_value; ++ } ++ ++ err = rst_clone_children(tobj, ctx); ++ if (err) { ++ eprintk_ctx("rst_clone_children\n"); ++ goto out; ++ } ++ ++ if (exiting) ++ current->signal->flags |= SIGNAL_GROUP_EXIT; ++ ++ if (ti->cpt_pid == 1) { ++ if ((err = rst_process_linkage(ctx)) != 0) { ++ eprintk_ctx("rst_process_linkage: %d\n", err); ++ goto out; ++ } ++ if ((err = rst_do_filejobs(ctx)) != 0) { ++ eprintk_ctx("rst_do_filejobs: %d\n", err); ++ goto out; ++ } ++ if ((err = rst_eventpoll(ctx)) != 0) { ++ eprintk_ctx("rst_eventpoll: %d\n", err); ++ goto out; ++ } ++#ifdef CONFIG_INOTIFY_USER ++ if ((err = rst_inotify(ctx)) != 0) { ++ eprintk_ctx("rst_inotify: %d\n", err); ++ goto out; ++ } ++#endif ++ if ((err = rst_sockets_complete(ctx)) != 0) { ++ eprintk_ctx("rst_sockets_complete: %d\n", err); ++ goto out; ++ } ++ if ((err = rst_stray_files(ctx)) != 0) { ++ eprintk_ctx("rst_stray_files: %d\n", err); ++ goto out; ++ } ++ if ((err = rst_posix_locks(ctx)) != 0) { ++ eprintk_ctx("rst_posix_locks: %d\n", err); ++ goto out; ++ } ++ if ((err = rst_tty_jobcontrol(ctx)) != 0) { ++ eprintk_ctx("rst_tty_jobcontrol: %d\n", err); ++ goto out; ++ } ++ if ((err = rst_restore_fs(ctx)) != 0) { ++ eprintk_ctx("rst_restore_fs: %d\n", err); ++ goto out; ++ } ++ if (virtinfo_notifier_call(VITYPE_SCP, ++ VIRTINFO_SCP_RESTORE, ctx) & NOTIFY_FAIL) { ++ err = -ECHRNG; ++ eprintk_ctx("scp_restore failed\n"); ++ goto out; ++ } ++ if (ctx->last_vpid) ++ get_exec_env()->ve_ns->pid_ns->last_pid = ++ ctx->last_vpid; ++ } ++ ++out: ++ thr_ctx->error = err; ++ complete(&thr_ctx->task_done); ++ ++ if (!err && (ti->cpt_state & (EXIT_ZOMBIE|EXIT_DEAD))) { ++ current->flags |= PF_EXIT_RESTART; ++ do_exit(ti->cpt_exit_code); ++ } else { ++ __set_current_state(TASK_UNINTERRUPTIBLE); ++ } ++ ++ schedule(); ++ ++ dprintk_ctx("leaked through %d/%d %p\n", task_pid_nr(current), task_pid_vnr(current), current->mm); ++ ++ module_put(THIS_MODULE); ++ complete_and_exit(NULL, 0); ++ return 0; ++} ++ ++#if 0 ++static void set_task_ubs(struct cpt_task_image *ti, struct cpt_context *ctx) ++{ ++ struct task_beancounter *tbc; ++ ++ tbc = task_bc(current); ++ ++ put_beancounter(tbc->fork_sub); ++ tbc->fork_sub = rst_lookup_ubc(ti->cpt_task_ub, ctx); ++ if (ti->cpt_mm_ub != CPT_NULL) { ++ put_beancounter(tbc->exec_ub); ++ tbc->exec_ub = rst_lookup_ubc(ti->cpt_mm_ub, ctx); ++ } ++} ++#endif ++ ++static int create_root_task(cpt_object_t *obj, struct cpt_context *ctx, ++ struct thr_context *thr_ctx) ++{ ++ struct task_struct *tsk; ++ int pid; ++ ++ thr_ctx->ctx = ctx; ++ thr_ctx->error = 0; ++ init_completion(&thr_ctx->init_complete); ++ init_completion(&thr_ctx->task_done); ++#if 0 ++ set_task_ubs(obj->o_image, ctx); ++#endif ++ ++ pid = local_kernel_thread(hook, thr_ctx, 0, 0); ++ if (pid < 0) ++ return pid; ++ read_lock(&tasklist_lock); ++ tsk = find_task_by_vpid(pid); ++ if (tsk) ++ get_task_struct(tsk); ++ read_unlock(&tasklist_lock); ++ if (tsk == NULL) ++ return -ESRCH; ++ cpt_obj_setobj(obj, tsk, ctx); ++ thr_ctx->tobj = obj; ++ return 0; ++} ++ ++static int rst_basic_init_task(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ struct task_struct *tsk = obj->o_obj; ++ struct cpt_task_image *ti = obj->o_image; ++ ++ memcpy(tsk->comm, ti->cpt_comm, sizeof(tsk->comm)); ++ rst_mm_basic(obj, ti, ctx); ++ return 0; ++} ++ ++static int make_baby(cpt_object_t *cobj, ++ struct cpt_task_image *pi, ++ struct cpt_context *ctx) ++{ ++ unsigned long flags; ++ struct cpt_task_image *ci = cobj->o_image; ++ struct thr_context thr_ctx; ++ struct task_struct *tsk; ++ pid_t pid; ++ struct fs_struct *tfs = NULL; ++ ++ flags = rst_mm_flag(ci, ctx) | rst_files_flag(ci, ctx) ++ | rst_signal_flag(ci, ctx) | rst_semundo_flag(ci, ctx); ++ if (ci->cpt_rppid != pi->cpt_pid) { ++ flags |= CLONE_THREAD|CLONE_PARENT; ++ if (ci->cpt_signal != pi->cpt_signal || ++ !(flags&CLONE_SIGHAND) || ++ (!(flags&CLONE_VM) && pi->cpt_mm != CPT_NULL)) { ++ eprintk_ctx("something is wrong with threads: %d %d %d %Ld %Ld %08lx\n", ++ (int)ci->cpt_pid, (int)ci->cpt_rppid, (int)pi->cpt_pid, ++ (long long)ci->cpt_signal, (long long)pi->cpt_signal, flags ++ ); ++ return -EINVAL; ++ } ++ } ++ ++ thr_ctx.ctx = ctx; ++ thr_ctx.error = 0; ++ init_completion(&thr_ctx.init_complete); ++ init_completion(&thr_ctx.task_done); ++ thr_ctx.tobj = cobj; ++ ++#if 0 ++ set_task_ubs(ci, ctx); ++#endif ++ ++ if (current->fs == NULL) { ++ tfs = get_exec_env()->ve_ns->pid_ns->child_reaper->fs; ++ if (tfs == NULL) ++ return -EINVAL; ++ atomic_inc(&tfs->count); ++ current->fs = tfs; ++ } ++ pid = local_kernel_thread(hook, &thr_ctx, flags, ci->cpt_pid); ++ if (tfs) { ++ current->fs = NULL; ++ atomic_dec(&tfs->count); ++ } ++ if (pid < 0) ++ return pid; ++ ++ read_lock(&tasklist_lock); ++ tsk = find_task_by_vpid(pid); ++ if (tsk) ++ get_task_struct(tsk); ++ read_unlock(&tasklist_lock); ++ if (tsk == NULL) ++ return -ESRCH; ++ cpt_obj_setobj(cobj, tsk, ctx); ++ thr_ctx.tobj = cobj; ++ wait_for_completion(&thr_ctx.init_complete); ++ wait_task_inactive(cobj->o_obj); ++ rst_basic_init_task(cobj, ctx); ++ ++ /* clone() increases group_stop_count if it was not zero and ++ * CLONE_THREAD was asked. Undo. ++ */ ++ if (current->signal->group_stop_count && (flags & CLONE_THREAD)) { ++ if (tsk->signal != current->signal) BUG(); ++ current->signal->group_stop_count--; ++ } ++ ++ wake_up_process(tsk); ++ wait_for_completion(&thr_ctx.task_done); ++ wait_task_inactive(tsk); ++ ++ return thr_ctx.error; ++} ++ ++static int rst_clone_children(cpt_object_t *obj, struct cpt_context *ctx) ++{ ++ int err = 0; ++ struct cpt_task_image *ti = obj->o_image; ++ cpt_object_t *cobj; ++ ++ for_each_object(cobj, CPT_OBJ_TASK) { ++ struct cpt_task_image *ci = cobj->o_image; ++ if (cobj == obj) ++ continue; ++ if ((ci->cpt_rppid == ti->cpt_pid && ci->cpt_tgid == ci->cpt_pid) || ++ (ci->cpt_leader == ti->cpt_pid && ++ ci->cpt_tgid != ci->cpt_pid && ci->cpt_pid != 1)) { ++ err = make_baby(cobj, ti, ctx); ++ if (err) { ++ eprintk_ctx("make_baby: %d\n", err); ++ return err; ++ } ++ } ++ } ++ return 0; ++} ++ ++static int read_task_images(struct cpt_context *ctx) ++{ ++ int err; ++ loff_t start, end; ++ ++ err = rst_get_section(CPT_SECT_TASKS, ctx, &start, &end); ++ if (err) ++ return err; ++ ++ while (start < end) { ++ cpt_object_t *obj; ++ struct cpt_task_image *ti = cpt_get_buf(ctx); ++ ++ err = rst_get_object(CPT_OBJ_TASK, start, ti, ctx); ++ if (err) { ++ cpt_release_buf(ctx); ++ return err; ++ } ++#if 0 ++ if (ti->cpt_pid != 1 && !__is_virtual_pid(ti->cpt_pid)) { ++ eprintk_ctx("BUG: pid %d is not virtual\n", ti->cpt_pid); ++ cpt_release_buf(ctx); ++ return -EINVAL; ++ } ++#endif ++ obj = alloc_cpt_object(GFP_KERNEL, ctx); ++ cpt_obj_setpos(obj, start, ctx); ++ intern_cpt_object(CPT_OBJ_TASK, obj, ctx); ++ obj->o_image = kmalloc(ti->cpt_next, GFP_KERNEL); ++ if (obj->o_image == NULL) { ++ cpt_release_buf(ctx); ++ return -ENOMEM; ++ } ++ memcpy(obj->o_image, ti, sizeof(*ti)); ++ err = ctx->pread(obj->o_image + sizeof(*ti), ++ ti->cpt_next - sizeof(*ti), ctx, start + sizeof(*ti)); ++ cpt_release_buf(ctx); ++ if (err) ++ return err; ++ start += ti->cpt_next; ++ } ++ return 0; ++} ++ ++ ++static int vps_rst_restore_tree(struct cpt_context *ctx) ++{ ++ int err; ++ cpt_object_t *obj; ++ struct thr_context thr_ctx_root; ++ ++ err = read_task_images(ctx); ++ if (err) ++ return err; ++ ++ err = rst_undump_ubc(ctx); ++ if (err) ++ return err; ++ ++ if (virtinfo_notifier_call(VITYPE_SCP, ++ VIRTINFO_SCP_RSTCHECK, ctx) & NOTIFY_FAIL) ++ return -ECHRNG; ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ err = rst_setup_pagein(ctx); ++ if (err) ++ return err; ++#endif ++ for_each_object(obj, CPT_OBJ_TASK) { ++ err = create_root_task(obj, ctx, &thr_ctx_root); ++ if (err) ++ return err; ++ ++ wait_for_completion(&thr_ctx_root.init_complete); ++ wait_task_inactive(obj->o_obj); ++ rst_basic_init_task(obj, ctx); ++ ++ wake_up_process(obj->o_obj); ++ wait_for_completion(&thr_ctx_root.task_done); ++ wait_task_inactive(obj->o_obj); ++ err = thr_ctx_root.error; ++ if (err) ++ return err; ++ break; ++ } ++ ++ return err; ++} ++ ++#ifndef CONFIG_IA64 ++int rst_read_vdso(struct cpt_context *ctx) ++{ ++ int err; ++ loff_t start, end; ++ struct cpt_page_block *pgb; ++ ++ ctx->vdso = NULL; ++ err = rst_get_section(CPT_SECT_VSYSCALL, ctx, &start, &end); ++ if (err) ++ return err; ++ if (start == CPT_NULL) ++ return 0; ++ if (end < start + sizeof(*pgb) + PAGE_SIZE) ++ return -EINVAL; ++ ++ pgb = cpt_get_buf(ctx); ++ err = rst_get_object(CPT_OBJ_VSYSCALL, start, pgb, ctx); ++ if (err) { ++ goto err_buf; ++ } ++ ctx->vdso = (char*)__get_free_page(GFP_KERNEL); ++ if (ctx->vdso == NULL) { ++ err = -ENOMEM; ++ goto err_buf; ++ } ++ err = ctx->pread(ctx->vdso, PAGE_SIZE, ctx, start + sizeof(*pgb)); ++ if (err) ++ goto err_page; ++ if (!memcmp(ctx->vdso, vsyscall_addr, PAGE_SIZE)) { ++ free_page((unsigned long)ctx->vdso); ++ ctx->vdso = NULL; ++ } ++ ++ cpt_release_buf(ctx); ++ return 0; ++err_page: ++ free_page((unsigned long)ctx->vdso); ++ ctx->vdso = NULL; ++err_buf: ++ cpt_release_buf(ctx); ++ return err; ++} ++#endif ++ ++int vps_rst_undump(struct cpt_context *ctx) ++{ ++ int err; ++ unsigned long umask; ++ ++ err = rst_open_dumpfile(ctx); ++ if (err) ++ return err; ++ ++ if (ctx->tasks64) { ++#if defined(CONFIG_IA64) ++ if (ctx->image_arch != CPT_OS_ARCH_IA64) ++#elif defined(CONFIG_X86_64) ++ if (ctx->image_arch != CPT_OS_ARCH_EMT64) ++#else ++ if (1) ++#endif ++ { ++ eprintk_ctx("Cannot restore 64 bit container on this architecture\n"); ++ return -EINVAL; ++ } ++ } ++ ++ umask = current->fs->umask; ++ current->fs->umask = 0; ++ ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ err = rst_setup_pagein(ctx); ++#endif ++#ifndef CONFIG_IA64 ++ if (err == 0) ++ err = rst_read_vdso(ctx); ++#endif ++ if (err == 0) ++ err = vps_rst_restore_tree(ctx); ++ ++ if (err == 0) ++ err = rst_restore_process(ctx); ++ ++ if (err) ++ virtinfo_notifier_call(VITYPE_SCP, ++ VIRTINFO_SCP_RSTFAIL, ctx); ++ ++ current->fs->umask = umask; ++ ++ return err; ++} ++ ++static int rst_unlock_ve(struct cpt_context *ctx) ++{ ++ struct ve_struct *env; ++ ++ env = get_ve_by_id(ctx->ve_id); ++ if (!env) ++ return -ESRCH; ++ down_write(&env->op_sem); ++ env->is_locked = 0; ++ up_write(&env->op_sem); ++ put_ve(env); ++ return 0; ++} ++ ++int recalc_sigpending_tsk(struct task_struct *t); ++ ++int rst_resume(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ int err = 0; ++#ifdef CONFIG_BEANCOUNTERS ++ struct user_beancounter *bc; ++#endif ++ ++ for_each_object(obj, CPT_OBJ_FILE) { ++ struct file *file = obj->o_obj; ++ ++ fput(file); ++ } ++ ++#ifdef CONFIG_BEANCOUNTERS ++ bc = get_beancounter_byuid(ctx->ve_id, 0); ++ BUG_ON(!bc); ++ copy_one_ubparm(ctx->saved_ubc, bc->ub_parms, UB_KMEMSIZE); ++ copy_one_ubparm(ctx->saved_ubc, bc->ub_parms, UB_NUMPROC); ++ copy_one_ubparm(ctx->saved_ubc, bc->ub_parms, UB_NUMFILE); ++ copy_one_ubparm(ctx->saved_ubc, bc->ub_parms, UB_DCACHESIZE); ++ put_beancounter(bc); ++#endif ++ ++ rst_resume_network(ctx); ++ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ struct task_struct *tsk = obj->o_obj; ++ struct cpt_task_image *ti = obj->o_image; ++ ++ if (!tsk) ++ continue; ++ ++ if (ti->cpt_state == TASK_UNINTERRUPTIBLE) { ++ dprintk_ctx("task %d/%d(%s) is started\n", task_pid_vnr(tsk), tsk->pid, tsk->comm); ++ ++ /* Weird... If a signal is sent to stopped task, ++ * nobody makes recalc_sigpending(). We have to do ++ * this by hands after wake_up_process(). ++ * if we did this before a signal could arrive before ++ * wake_up_process() and stall. ++ */ ++ spin_lock_irq(&tsk->sighand->siglock); ++ if (!signal_pending(tsk)) ++ recalc_sigpending_tsk(tsk); ++ spin_unlock_irq(&tsk->sighand->siglock); ++ ++ wake_up_process(tsk); ++ } else { ++ if (ti->cpt_state == TASK_STOPPED || ++ ti->cpt_state == TASK_TRACED) { ++ set_task_state(tsk, ti->cpt_state); ++ } ++ } ++ put_task_struct(tsk); ++ } ++ ++ rst_unlock_ve(ctx); ++ ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ rst_complete_pagein(ctx, 0); ++#endif ++ ++ rst_finish_ubc(ctx); ++ cpt_object_destroy(ctx); ++ ++ return err; ++} ++ ++int rst_kill(struct cpt_context *ctx) ++{ ++ cpt_object_t *obj; ++ int err = 0; ++ ++ for_each_object(obj, CPT_OBJ_FILE) { ++ struct file *file = obj->o_obj; ++ ++ fput(file); ++ } ++ ++ for_each_object(obj, CPT_OBJ_TASK) { ++ struct task_struct *tsk = obj->o_obj; ++ ++ if (tsk == NULL) ++ continue; ++ ++ if (tsk->exit_state == 0) { ++ send_sig(SIGKILL, tsk, 1); ++ ++ spin_lock_irq(&tsk->sighand->siglock); ++ sigfillset(&tsk->blocked); ++ sigdelsetmask(&tsk->blocked, sigmask(SIGKILL)); ++ set_tsk_thread_flag(tsk, TIF_SIGPENDING); ++ clear_tsk_thread_flag(tsk, TIF_FREEZE); ++ if (tsk->flags & PF_FROZEN) ++ tsk->flags &= ~PF_FROZEN; ++ spin_unlock_irq(&tsk->sighand->siglock); ++ ++ wake_up_process(tsk); ++ } ++ ++ put_task_struct(tsk); ++ } ++ ++#ifdef CONFIG_VZ_CHECKPOINT_LAZY ++ rst_complete_pagein(ctx, 1); ++#endif ++ ++ rst_finish_ubc(ctx); ++ cpt_object_destroy(ctx); ++ ++ return err; ++} ++ ++static int rst_utsname(cpt_context_t *ctx) ++{ ++ int err; ++ loff_t sec = ctx->sections[CPT_SECT_UTSNAME]; ++ loff_t endsec; ++ struct cpt_section_hdr h; ++ struct cpt_object_hdr o; ++ struct ve_struct *ve; ++ struct uts_namespace *ns; ++ int i; ++ ++ if (sec == CPT_NULL) ++ return 0; ++ ++ err = ctx->pread(&h, sizeof(h), ctx, sec); ++ if (err) ++ return err; ++ if (h.cpt_section != CPT_SECT_UTSNAME || h.cpt_hdrlen < sizeof(h)) ++ return -EINVAL; ++ ++ ve = get_exec_env(); ++ ns = ve->ve_ns->uts_ns; ++ ++ i = 0; ++ endsec = sec + h.cpt_next; ++ sec += h.cpt_hdrlen; ++ while (sec < endsec) { ++ int len; ++ char *ptr; ++ err = rst_get_object(CPT_OBJ_NAME, sec, &o, ctx); ++ if (err) ++ return err; ++ len = o.cpt_next - o.cpt_hdrlen; ++ if (len > __NEW_UTS_LEN + 1) ++ return -ENAMETOOLONG; ++ switch (i) { ++ case 0: ++ ptr = ns->name.nodename; break; ++ case 1: ++ ptr = ns->name.domainname; break; ++ default: ++ return -EINVAL; ++ } ++ err = ctx->pread(ptr, len, ctx, sec+o.cpt_hdrlen); ++ if (err) ++ return err; ++ i++; ++ sec += o.cpt_next; ++ } ++ ++ return 0; ++} +Index: kernel/kernel/cpu.c +=================================================================== +--- kernel.orig/kernel/cpu.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/cpu.c 2008-11-24 15:47:46.000000000 +0100 +@@ -92,7 +92,7 @@ + struct task_struct *p; + + write_lock_irq(&tasklist_lock); +- for_each_process(p) { ++ for_each_process_all(p) { + if (task_cpu(p) == cpu && + (!cputime_eq(p->utime, cputime_zero) || + !cputime_eq(p->stime, cputime_zero))) +Index: kernel/kernel/exit.c +=================================================================== +--- kernel.orig/kernel/exit.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/exit.c 2008-11-24 15:47:46.000000000 +0100 +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -42,8 +43,13 @@ + #include + #include /* for audit_free() */ + #include ++#include + #include + #include ++#include ++ ++#include ++#include + + #include + #include +@@ -52,7 +58,7 @@ + + extern void sem_exit (void); + +-static void exit_mm(struct task_struct * tsk); ++void exit_mm(struct task_struct * tsk); + + static void __unhash_process(struct task_struct *p) + { +@@ -63,6 +69,9 @@ + detach_pid(p, PIDTYPE_SID); + + list_del_rcu(&p->tasks); ++#ifdef CONFIG_VE ++ list_del_rcu(&p->ve_task_info.vetask_list); ++#endif + __get_cpu_var(process_counts)--; + } + list_del_rcu(&p->thread_group); +@@ -153,6 +162,8 @@ + ptrace_unlink(p); + BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children)); + __exit_signal(p); ++ nr_zombie--; ++ atomic_inc(&nr_dead); + + /* + * If we are the last non-leader member of the thread +@@ -177,6 +188,8 @@ + + write_unlock_irq(&tasklist_lock); + release_thread(p); ++ ub_task_uncharge(p); ++ pput_ve(p->ve_task_info.owner_env); + call_rcu(&p->rcu, delayed_put_task_struct); + + p = leader; +@@ -307,16 +320,17 @@ + if (task_pgrp_nr(curr) != pgrp) { + detach_pid(curr, PIDTYPE_PGID); + set_task_pgrp(curr, pgrp); +- attach_pid(curr, PIDTYPE_PGID, find_pid(pgrp)); ++ attach_pid(curr, PIDTYPE_PGID, find_pid_ns(pgrp, &init_pid_ns)); + } + } + +-static void set_special_pids(pid_t session, pid_t pgrp) ++void set_special_pids(pid_t session, pid_t pgrp) + { + write_lock_irq(&tasklist_lock); + __set_special_pids(session, pgrp); + write_unlock_irq(&tasklist_lock); + } ++EXPORT_SYMBOL(set_special_pids); + + /* + * Let kernel threads use this to say that they +@@ -554,13 +568,17 @@ + * Turn us into a lazy TLB process if we + * aren't already.. + */ +-static void exit_mm(struct task_struct * tsk) ++void exit_mm(struct task_struct * tsk) + { + struct mm_struct *mm = tsk->mm; + + mm_release(tsk, mm); + if (!mm) + return; ++ ++ if (test_tsk_thread_flag(tsk, TIF_MEMDIE)) ++ mm->oom_killed = 1; ++ + /* + * Serialize with any possible pending coredump. + * We must hold mmap_sem around checking core_waiters +@@ -591,6 +609,7 @@ + task_unlock(tsk); + mmput(mm); + } ++EXPORT_SYMBOL_GPL(exit_mm); + + static void + reparent_thread(struct task_struct *p, struct task_struct *father, int traced) +@@ -817,6 +836,9 @@ + && !capable(CAP_KILL)) + tsk->exit_signal = SIGCHLD; + ++ if (tsk->exit_signal != -1 && t == init_pid_ns.child_reaper) ++ /* We dont want people slaying init. */ ++ tsk->exit_signal = SIGCHLD; + + /* If something other than our normal parent is ptracing us, then + * send it a SIGCHLD instead of honoring exit_signal. exit_signal +@@ -833,6 +855,7 @@ + if (tsk->exit_signal == -1 && likely(!tsk->ptrace)) + state = EXIT_DEAD; + tsk->exit_state = state; ++ nr_zombie++; + + if (thread_group_leader(tsk) && + tsk->signal->notify_count < 0 && +@@ -881,7 +904,6 @@ + + if (tsk->nsproxy->pid_ns == &init_pid_ns) + panic("Attempted to kill init!"); +- + /* + * @tsk is the last thread in the 'cgroup-init' and is exiting. + * Terminate all remaining processes in the namespace and reap them +@@ -905,6 +927,7 @@ + * perform the role of the child_reaper. + */ + zap_pid_ns_processes(tsk->nsproxy->pid_ns); ++ (void)virtinfo_gencall(VIRTINFO_DOEXIT, NULL); + } + + fastcall NORET_TYPE void do_exit(long code) +@@ -975,12 +998,14 @@ + } + acct_collect(code, group_dead); + #ifdef CONFIG_FUTEX +- if (unlikely(tsk->robust_list)) +- exit_robust_list(tsk); ++ if (!(tsk->flags & PF_EXIT_RESTART)) { ++ if (unlikely(tsk->robust_list)) ++ exit_robust_list(tsk); + #ifdef CONFIG_COMPAT +- if (unlikely(tsk->compat_robust_list)) +- compat_exit_robust_list(tsk); ++ if (unlikely(tsk->compat_robust_list)) ++ compat_exit_robust_list(tsk); + #endif ++ } + #endif + if (group_dead) + tty_audit_exit(); +@@ -1009,8 +1034,16 @@ + if (tsk->binfmt) + module_put(tsk->binfmt->module); + +- proc_exit_connector(tsk); +- exit_notify(tsk); ++ if (!(tsk->flags & PF_EXIT_RESTART)) { ++ proc_exit_connector(tsk); ++ exit_notify(tsk); ++ } else { ++ write_lock_irq(&tasklist_lock); ++ tsk->exit_state = EXIT_ZOMBIE; ++ nr_zombie++; ++ write_unlock_irq(&tasklist_lock); ++ exit_task_namespaces(tsk); ++ } + #ifdef CONFIG_NUMA + mpol_free(tsk->mempolicy); + tsk->mempolicy = NULL; +@@ -1740,6 +1773,7 @@ + prevent_tail_call(ret); + return ret; + } ++EXPORT_SYMBOL_GPL(sys_wait4); + + #ifdef __ARCH_WANT_SYS_WAITPID + +Index: kernel/kernel/fork.c +=================================================================== +--- kernel.orig/kernel/fork.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/fork.c 2008-11-24 15:47:46.000000000 +0100 +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -25,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -51,6 +53,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -59,11 +62,16 @@ + #include + #include + ++#include ++#include ++#include ++ + /* + * Protected counters by write_lock_irq(&tasklist_lock) + */ + unsigned long total_forks; /* Handle normal Linux uptimes. */ + int nr_threads; /* The idle threads do not count.. */ ++EXPORT_SYMBOL(nr_threads); + + int max_threads; /* tunable limit on nr_threads */ + +@@ -71,6 +79,8 @@ + + __cacheline_aligned DEFINE_RWLOCK(tasklist_lock); /* outer */ + ++EXPORT_SYMBOL(tasklist_lock); ++ + int nr_processes(void) + { + int cpu; +@@ -121,15 +131,22 @@ + WARN_ON(atomic_read(&tsk->usage)); + WARN_ON(tsk == current); + ++ ub_task_put(tsk); + security_task_free(tsk); + free_uid(tsk->user); + put_group_info(tsk->group_info); + delayacct_tsk_free(tsk); + ++#ifdef CONFIG_VE ++ put_ve(VE_TASK_INFO(tsk)->owner_env); ++ atomic_dec(&nr_dead); ++#endif + if (!profile_handoff_task(tsk)) + free_task(tsk); + } + ++EXPORT_SYMBOL_GPL(__put_task_struct); ++ + void __init fork_init(unsigned long mempages) + { + #ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR +@@ -139,7 +156,7 @@ + /* create a slab on which task_structs can be allocated */ + task_struct_cachep = + kmem_cache_create("task_struct", sizeof(struct task_struct), +- ARCH_MIN_TASKALIGN, SLAB_PANIC, NULL); ++ ARCH_MIN_TASKALIGN, SLAB_PANIC|SLAB_UBC, NULL); + #endif + + /* +@@ -243,7 +260,12 @@ + -pages); + continue; + } ++ + charge = 0; ++ if (ub_memory_charge(mm, mpnt->vm_end - mpnt->vm_start, ++ mpnt->vm_flags & ~VM_LOCKED, ++ mpnt->vm_file, UB_HARD)) ++ goto fail_noch; + if (mpnt->vm_flags & VM_ACCOUNT) { + unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + if (security_vm_enough_memory(len)) +@@ -290,7 +312,7 @@ + rb_parent = &tmp->vm_rb; + + mm->map_count++; +- retval = copy_page_range(mm, oldmm, mpnt); ++ retval = copy_page_range(mm, oldmm, tmp, mpnt); + + if (tmp->vm_ops && tmp->vm_ops->open) + tmp->vm_ops->open(tmp); +@@ -309,6 +331,9 @@ + fail_nomem_policy: + kmem_cache_free(vm_area_cachep, tmp); + fail_nomem: ++ ub_memory_uncharge(mm, mpnt->vm_end - mpnt->vm_start, ++ mpnt->vm_flags & ~VM_LOCKED, mpnt->vm_file); ++fail_noch: + retval = -ENOMEM; + vm_unacct_memory(charge); + goto out; +@@ -339,7 +364,8 @@ + + #include + +-static struct mm_struct * mm_init(struct mm_struct * mm) ++static struct mm_struct * mm_init(struct mm_struct * mm, ++ struct task_struct *tsk) + { + atomic_set(&mm->mm_users, 1); + atomic_set(&mm->mm_count, 1); +@@ -356,11 +382,14 @@ + mm->ioctx_list = NULL; + mm->free_area_cache = TASK_UNMAPPED_BASE; + mm->cached_hole_size = ~0UL; ++ set_mm_ub(mm, tsk); + + if (likely(!mm_alloc_pgd(mm))) { + mm->def_flags = 0; + return mm; + } ++ ++ put_mm_ub(mm); + free_mm(mm); + return NULL; + } +@@ -375,10 +404,11 @@ + mm = allocate_mm(); + if (mm) { + memset(mm, 0, sizeof(*mm)); +- mm = mm_init(mm); ++ mm = mm_init(mm, NULL); + } + return mm; + } ++EXPORT_SYMBOL_GPL(mm_alloc); + + /* + * Called when the last reference to the mm +@@ -390,6 +420,7 @@ + BUG_ON(mm == &init_mm); + mm_free_pgd(mm); + destroy_context(mm); ++ put_mm_ub(mm); + free_mm(mm); + } + EXPORT_SYMBOL_GPL(__mmdrop); +@@ -410,6 +441,9 @@ + spin_unlock(&mmlist_lock); + } + put_swap_token(mm); ++ (void) virtinfo_gencall(VIRTINFO_EXITMMAP, mm); ++ if (mm->oom_killed) ++ ub_oom_task_dead(current); + mmdrop(mm); + } + } +@@ -510,7 +544,7 @@ + mm->token_priority = 0; + mm->last_interval = 0; + +- if (!mm_init(mm)) ++ if (!mm_init(mm, tsk)) + goto fail_nomem; + + if (init_new_context(tsk, mm)) +@@ -537,6 +571,7 @@ + * because it calls destroy_context() + */ + mm_free_pgd(mm); ++ put_mm_ub(mm); + free_mm(mm); + return NULL; + } +@@ -976,14 +1011,19 @@ + struct pt_regs *regs, + unsigned long stack_size, + int __user *child_tidptr, +- struct pid *pid) ++ struct pid *pid, pid_t vpid) + { + int retval; + struct task_struct *p; + int cgroup_callbacks_done = 0; + ++#ifdef CONFIG_VE ++ if (clone_flags & CLONE_NAMESPACES_MASK) ++ return ERR_PTR(-EINVAL); ++#else + if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) + return ERR_PTR(-EINVAL); ++#endif + + /* + * Thread groups must share signals as well, and detached threads +@@ -1011,6 +1051,9 @@ + + rt_mutex_init_task(p); + ++ if (ub_task_charge(current, p)) ++ goto bad_fork_charge; ++ + #ifdef CONFIG_TRACE_IRQFLAGS + DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled); + DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); +@@ -1154,7 +1197,7 @@ + + if (pid != &init_struct_pid) { + retval = -ENOMEM; +- pid = alloc_pid(task_active_pid_ns(p)); ++ pid = alloc_pid(task_active_pid_ns(p), vpid); + if (!pid) + goto bad_fork_cleanup_namespaces; + +@@ -1261,7 +1304,7 @@ + * thread can't slip out of an OOM kill (or normal SIGKILL). + */ + recalc_sigpending(); +- if (signal_pending(current)) { ++ if (signal_pending(current) && !vpid) { + spin_unlock(¤t->sighand->siglock); + write_unlock_irq(&tasklist_lock); + retval = -ERESTARTNOINTR; +@@ -1302,13 +1345,23 @@ + set_task_session(p, task_session_nr(current)); + attach_pid(p, PIDTYPE_PGID, task_pgrp(current)); + attach_pid(p, PIDTYPE_SID, task_session(current)); ++ + list_add_tail_rcu(&p->tasks, &init_task.tasks); ++#ifdef CONFIG_VE ++ list_add_tail_rcu(&p->ve_task_info.vetask_list, ++ &p->ve_task_info.owner_env->vetask_lh); ++#endif + __get_cpu_var(process_counts)++; + } + attach_pid(p, PIDTYPE_PID, pid); + nr_threads++; + } ++ (void)get_ve(p->ve_task_info.owner_env); ++ pget_ve(p->ve_task_info.owner_env); + ++#ifdef CONFIG_VE ++ seqcount_init(&p->ve_task_info.wakeup_lock); ++#endif + total_forks++; + spin_unlock(¤t->sighand->siglock); + write_unlock_irq(&tasklist_lock); +@@ -1356,6 +1409,9 @@ + atomic_dec(&p->user->processes); + free_uid(p->user); + bad_fork_free: ++ ub_task_uncharge(p); ++ ub_task_put(p); ++bad_fork_charge: + free_task(p); + fork_out: + return ERR_PTR(retval); +@@ -1373,7 +1429,7 @@ + struct pt_regs regs; + + task = copy_process(CLONE_VM, 0, idle_regs(®s), 0, NULL, +- &init_struct_pid); ++ &init_struct_pid, 0); + if (!IS_ERR(task)) + init_idle(task, cpu); + +@@ -1402,17 +1458,22 @@ + * It copies the process, and if successful kick-starts + * it and waits for it to finish using the VM if required. + */ +-long do_fork(unsigned long clone_flags, ++long do_fork_pid(unsigned long clone_flags, + unsigned long stack_start, + struct pt_regs *regs, + unsigned long stack_size, + int __user *parent_tidptr, +- int __user *child_tidptr) ++ int __user *child_tidptr, ++ long vpid) + { + struct task_struct *p; + int trace = 0; + long nr; + ++ nr = virtinfo_gencall(VIRTINFO_DOFORK, (void *)clone_flags); ++ if (nr) ++ return nr; ++ + if (unlikely(current->ptrace)) { + trace = fork_traceflag (clone_flags); + if (trace) +@@ -1420,7 +1481,7 @@ + } + + p = copy_process(clone_flags, stack_start, regs, stack_size, +- child_tidptr, NULL); ++ child_tidptr, NULL, vpid); + /* + * Do this prior waking up the new thread - the thread pointer + * might get invalid after that point, if the thread exits quickly. +@@ -1452,6 +1513,8 @@ + set_tsk_thread_flag(p, TIF_SIGPENDING); + } + ++ (void)virtinfo_gencall(VIRTINFO_DOFORKRET, p); ++ + if (!(clone_flags & CLONE_STOPPED)) + wake_up_new_task(p, clone_flags); + else +@@ -1474,6 +1537,8 @@ + } else { + nr = PTR_ERR(p); + } ++ ++ (void)virtinfo_gencall(VIRTINFO_DOFORKPOST, (void *)(long)nr); + return nr; + } + +@@ -1489,27 +1554,40 @@ + init_waitqueue_head(&sighand->signalfd_wqh); + } + ++EXPORT_SYMBOL(do_fork_pid); ++ ++long do_fork(unsigned long clone_flags, ++ unsigned long stack_start, ++ struct pt_regs *regs, ++ unsigned long stack_size, ++ int __user *parent_tidptr, ++ int __user *child_tidptr) ++{ ++ return do_fork_pid(clone_flags, stack_start, regs, stack_size, ++ parent_tidptr, child_tidptr, 0); ++} ++ + void __init proc_caches_init(void) + { + sighand_cachep = kmem_cache_create("sighand_cache", + sizeof(struct sighand_struct), 0, +- SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU, ++ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU|SLAB_UBC, + sighand_ctor); + signal_cachep = kmem_cache_create("signal_cache", + sizeof(struct signal_struct), 0, +- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); ++ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_UBC, NULL); + files_cachep = kmem_cache_create("files_cache", + sizeof(struct files_struct), 0, +- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); ++ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_UBC, NULL); + fs_cachep = kmem_cache_create("fs_cache", + sizeof(struct fs_struct), 0, +- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); ++ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_UBC, NULL); + vm_area_cachep = kmem_cache_create("vm_area_struct", + sizeof(struct vm_area_struct), 0, +- SLAB_PANIC, NULL); ++ SLAB_PANIC|SLAB_UBC, NULL); + mm_cachep = kmem_cache_create("mm_struct", + sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN, +- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); ++ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_UBC, NULL); + } + + /* +@@ -1659,6 +1737,10 @@ + CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWUSER| + CLONE_NEWNET)) + goto bad_unshare_out; ++#ifdef CONFIG_VE ++ if (unshare_flags & CLONE_NAMESPACES_MASK) ++ goto bad_unshare_out; ++#endif + + if ((err = unshare_thread(unshare_flags))) + goto bad_unshare_out; +@@ -1672,9 +1754,11 @@ + goto bad_unshare_cleanup_vm; + if ((err = unshare_semundo(unshare_flags, &new_ulist))) + goto bad_unshare_cleanup_fd; ++#ifndef CONFIG_VE + if ((err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy, + new_fs))) + goto bad_unshare_cleanup_semundo; ++#endif + + if (new_fs || new_mm || new_fd || new_ulist || new_nsproxy) { + +@@ -1712,7 +1796,9 @@ + if (new_nsproxy) + put_nsproxy(new_nsproxy); + ++#ifndef CONFIG_VE + bad_unshare_cleanup_semundo: ++#endif + bad_unshare_cleanup_fd: + if (new_fd) + put_files_struct(new_fd); +Index: kernel/kernel/futex.c +=================================================================== +--- kernel.orig/kernel/futex.c 2008-11-24 14:14:38.000000000 +0100 ++++ kernel/kernel/futex.c 2008-11-24 15:47:46.000000000 +0100 +@@ -1157,8 +1157,6 @@ + */ + #define FLAGS_SHARED 1 + +-static long futex_wait_restart(struct restart_block *restart); +- + static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared, + u32 val, ktime_t *abs_time) + { +@@ -1313,7 +1311,7 @@ + } + + +-static long futex_wait_restart(struct restart_block *restart) ++long futex_wait_restart(struct restart_block *restart) + { + u32 __user *uaddr = (u32 __user *)restart->futex.uaddr; + struct rw_semaphore *fshared = NULL; +@@ -1325,6 +1323,7 @@ + fshared = ¤t->mm->mmap_sem; + return (long)futex_wait(uaddr, fshared, restart->futex.val, &t); + } ++EXPORT_SYMBOL_GPL(futex_wait_restart); + + + /* +Index: kernel/kernel/futex_compat.c +=================================================================== +--- kernel.orig/kernel/futex_compat.c 2008-11-24 14:14:38.000000000 +0100 ++++ kernel/kernel/futex_compat.c 2008-11-24 15:47:46.000000000 +0100 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include + +Index: kernel/kernel/hrtimer.c +=================================================================== +--- kernel.orig/kernel/hrtimer.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/hrtimer.c 2008-11-24 15:47:46.000000000 +0100 +@@ -1347,6 +1347,7 @@ + /* The other values in restart are already filled in */ + return -ERESTART_RESTARTBLOCK; + } ++EXPORT_SYMBOL_GPL(hrtimer_nanosleep_restart); + + long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, + const enum hrtimer_mode mode, const clockid_t clockid) +Index: kernel/kernel/kmod.c +=================================================================== +--- kernel.orig/kernel/kmod.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/kmod.c 2008-11-24 15:47:46.000000000 +0100 +@@ -77,6 +77,10 @@ + #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ + static int kmod_loop_msg; + ++ /* Don't allow request_module() inside VE. */ ++ if (!ve_is_super(get_exec_env())) ++ return -EPERM; ++ + va_start(args, fmt); + ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); + va_end(args); +@@ -453,6 +457,9 @@ + DECLARE_COMPLETION_ONSTACK(done); + int retval = 0; + ++ if (!ve_is_super(get_exec_env())) ++ return -EPERM; ++ + helper_lock(); + if (sub_info->path[0] == '\0') + goto out; +Index: kernel/kernel/kprobes.c +=================================================================== +--- kernel.orig/kernel/kprobes.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/kprobes.c 2008-11-24 15:47:46.000000000 +0100 +@@ -106,14 +106,14 @@ + ret = freeze_processes(); + if (ret == 0) { + struct task_struct *p, *q; +- do_each_thread(p, q) { ++ do_each_thread_all(p, q) { + if (p != current && p->state == TASK_RUNNING && + p->pid != 0) { + printk("Check failed: %s is running\n",p->comm); + ret = -1; + goto loop_end; + } +- } while_each_thread(p, q); ++ } while_each_thread_all(p, q); + } + loop_end: + thaw_processes(); +Index: kernel/kernel/lockdep.c +=================================================================== +--- kernel.orig/kernel/lockdep.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/lockdep.c 2008-11-24 15:47:46.000000000 +0100 +@@ -3182,7 +3182,7 @@ + if (count != 10) + printk(" locked it.\n"); + +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + /* + * It's not reliable to print a task's held locks + * if it's not sleeping (or if it's not the current +@@ -3195,7 +3195,7 @@ + if (!unlock) + if (read_trylock(&tasklist_lock)) + unlock = 1; +- } while_each_thread(g, p); ++ } while_each_thread_all(g, p); + + printk("\n"); + printk("=============================================\n\n"); +Index: kernel/kernel/module.c +=================================================================== +--- kernel.orig/kernel/module.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/module.c 2008-11-24 15:47:46.000000000 +0100 +@@ -2349,6 +2349,8 @@ + static void *m_start(struct seq_file *m, loff_t *pos) + { + mutex_lock(&module_mutex); ++ if (!ve_is_super(get_exec_env())) ++ return NULL; + return seq_list_start(&modules, *pos); + } + +Index: kernel/kernel/nsproxy.c +=================================================================== +--- kernel.orig/kernel/nsproxy.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/nsproxy.c 2008-11-24 15:47:46.000000000 +0100 +@@ -26,6 +26,14 @@ + + struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); + ++void get_task_namespaces(struct task_struct *tsk) ++{ ++ struct nsproxy *ns = tsk->nsproxy; ++ if (ns) { ++ get_nsproxy(ns); ++ } ++} ++ + /* + * creates a copy of "orig" with refcount 1. + */ +@@ -132,12 +140,12 @@ + if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | + CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET))) + return 0; +- ++#ifndef CONFIG_VE + if (!capable(CAP_SYS_ADMIN)) { + err = -EPERM; + goto out; + } +- ++#endif + new_ns = create_new_namespaces(flags, tsk, tsk->fs); + if (IS_ERR(new_ns)) { + err = PTR_ERR(new_ns); +@@ -156,6 +164,7 @@ + put_nsproxy(old_ns); + return err; + } ++EXPORT_SYMBOL_GPL(copy_namespaces); + + void free_nsproxy(struct nsproxy *ns) + { +@@ -172,6 +181,22 @@ + put_net(ns->net_ns); + kmem_cache_free(nsproxy_cachep, ns); + } ++EXPORT_SYMBOL_GPL(free_nsproxy); ++ ++struct mnt_namespace * get_task_mnt_ns(struct task_struct *tsk) ++{ ++ struct mnt_namespace *mnt_ns = NULL; ++ ++ task_lock(tsk); ++ if (tsk->nsproxy) ++ mnt_ns = tsk->nsproxy->mnt_ns; ++ if (mnt_ns) ++ get_mnt_ns(mnt_ns); ++ task_unlock(tsk); ++ ++ return mnt_ns; ++} ++EXPORT_SYMBOL(get_task_mnt_ns); + + /* + * Called from unshare. Unshare all the namespaces part of nsproxy. +Index: kernel/kernel/panic.c +=================================================================== +--- kernel.orig/kernel/panic.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/panic.c 2008-11-24 15:47:46.000000000 +0100 +@@ -28,6 +28,8 @@ + static DEFINE_SPINLOCK(pause_on_oops_lock); + + int panic_timeout; ++int kernel_text_csum_broken; ++EXPORT_SYMBOL(kernel_text_csum_broken); + + ATOMIC_NOTIFIER_HEAD(panic_notifier_list); + +@@ -160,7 +162,8 @@ + { + static char buf[20]; + if (tainted) { +- snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c", ++ snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c", ++ kernel_text_csum_broken ? 'B' : ' ', + tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G', + tainted & TAINT_FORCED_MODULE ? 'F' : ' ', + tainted & TAINT_UNSAFE_SMP ? 'S' : ' ', +Index: kernel/kernel/pid.c +=================================================================== +--- kernel.orig/kernel/pid.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/pid.c 2008-11-24 15:47:46.000000000 +0100 +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -39,6 +40,7 @@ + #define pid_hashfn(nr, ns) \ + hash_long((unsigned long)nr + (unsigned long)ns, pidhash_shift) + static struct hlist_head *pid_hash; ++ + static int pidhash_shift; + struct pid init_struct_pid = INIT_STRUCT_PID; + static struct kmem_cache *pid_ns_cachep; +@@ -120,6 +122,7 @@ + clear_bit(offset, map->page); + atomic_inc(&map->nr_free); + } ++EXPORT_SYMBOL_GPL(free_pidmap); + + static int alloc_pidmap(struct pid_namespace *pid_ns) + { +@@ -181,6 +184,36 @@ + return -1; + } + ++static int set_pidmap(struct pid_namespace *pid_ns, pid_t pid) ++{ ++ int offset; ++ struct pidmap *map; ++ ++ offset = pid & BITS_PER_PAGE_MASK; ++ map = &pid_ns->pidmap[pid/BITS_PER_PAGE]; ++ if (unlikely(!map->page)) { ++ void *page = kzalloc(PAGE_SIZE, GFP_KERNEL); ++ /* ++ * Free the page if someone raced with us ++ * installing it: ++ */ ++ spin_lock_irq(&pidmap_lock); ++ if (map->page) ++ kfree(page); ++ else ++ map->page = page; ++ spin_unlock_irq(&pidmap_lock); ++ if (unlikely(!map->page)) ++ return -ENOMEM; ++ } ++ ++ if (test_and_set_bit(offset, map->page)) ++ return -EBUSY; ++ ++ atomic_dec(&map->nr_free); ++ return pid; ++} ++ + static int next_pidmap(struct pid_namespace *pid_ns, int last) + { + int offset; +@@ -198,6 +231,7 @@ + } + return -1; + } ++EXPORT_SYMBOL_GPL(alloc_pidmap); + + fastcall void put_pid(struct pid *pid) + { +@@ -230,21 +264,25 @@ + spin_lock_irqsave(&pidmap_lock, flags); + for (i = 0; i <= pid->level; i++) + hlist_del_rcu(&pid->numbers[i].pid_chain); +- spin_unlock_irqrestore(&pidmap_lock, flags); ++ spin_unlock(&pidmap_lock); ++ ub_kmemsize_uncharge(pid->ub, pid->numbers[pid->level].ns->pid_cachep->objuse); ++ local_irq_restore(flags); + + for (i = 0; i <= pid->level; i++) + free_pidmap(pid->numbers[i].ns, pid->numbers[i].nr); +- ++ put_beancounter(pid->ub); + call_rcu(&pid->rcu, delayed_put_pid); + } ++EXPORT_SYMBOL_GPL(free_pid); + +-struct pid *alloc_pid(struct pid_namespace *ns) ++struct pid *alloc_pid(struct pid_namespace *ns, pid_t vpid) + { + struct pid *pid; + enum pid_type type; + int i, nr; + struct pid_namespace *tmp; + struct upid *upid; ++ struct user_beancounter *ub; + + pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL); + if (!pid) +@@ -252,7 +290,10 @@ + + tmp = ns; + for (i = ns->level; i >= 0; i--) { +- nr = alloc_pidmap(tmp); ++ if (vpid != 0 && i == ns->level) ++ nr = set_pidmap(tmp, vpid); ++ else ++ nr = alloc_pidmap(tmp); + if (nr < 0) + goto out_free; + +@@ -267,7 +308,16 @@ + for (type = 0; type < PIDTYPE_MAX; ++type) + INIT_HLIST_HEAD(&pid->tasks[type]); + ++#ifdef CONFIG_BEANCOUNTERS ++ ub = get_exec_ub(); ++ local_irq_disable(); ++ if (ub_kmemsize_charge(ub, ns->pid_cachep->objuse, UB_HARD)) ++ goto out_enable; ++ pid->ub = get_beancounter(ub); ++ spin_lock(&pidmap_lock); ++#else + spin_lock_irq(&pidmap_lock); ++#endif + for (i = ns->level; i >= 0; i--) { + upid = &pid->numbers[i]; + hlist_add_head_rcu(&upid->pid_chain, +@@ -278,6 +328,9 @@ + out: + return pid; + ++out_enable: ++ local_irq_enable(); ++ put_pid_ns(ns); + out_free: + for (i++; i <= ns->level; i++) + free_pidmap(pid->numbers[i].ns, pid->numbers[i].nr); +@@ -286,6 +339,7 @@ + pid = NULL; + goto out; + } ++EXPORT_SYMBOL_GPL(alloc_pid); + + struct pid * fastcall find_pid_ns(int nr, struct pid_namespace *ns) + { +@@ -328,6 +382,7 @@ + + return 0; + } ++EXPORT_SYMBOL_GPL(attach_pid); + + void fastcall detach_pid(struct task_struct *task, enum pid_type type) + { +@@ -347,6 +402,7 @@ + + free_pid(pid); + } ++EXPORT_SYMBOL_GPL(detach_pid); + + /* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */ + void fastcall transfer_pid(struct task_struct *old, struct task_struct *new, +@@ -368,6 +424,7 @@ + } + return result; + } ++EXPORT_SYMBOL_GPL(pid_task); + + /* + * Must be called under rcu_read_lock() or with tasklist_lock read-held. +@@ -624,6 +681,197 @@ + } + #endif /* CONFIG_PID_NS */ + ++/* ++ * this is a dirty ugly hack. ++ */ ++ ++static void reattach_pid(struct task_struct *tsk, enum pid_type type, ++ struct pid *pid) ++{ ++ int i; ++ struct pid *old_pid; ++ struct pid_link *link; ++ struct upid *upid; ++ ++ link = &tsk->pids[type]; ++ old_pid = link->pid; ++ ++ hlist_del_rcu(&link->node); ++ link->pid = pid; ++ hlist_add_head_rcu(&link->node, &pid->tasks[type]); ++ ++ if (type != PIDTYPE_PID) { ++ for (i = PIDTYPE_MAX; --i >= 0; ) ++ if (!hlist_empty(&old_pid->tasks[i])) ++ return; ++ ++ for (i = 0; i < pid->level; i++) ++ hlist_del_rcu(&old_pid->numbers[i].pid_chain); ++ } else { ++ for (i = PIDTYPE_MAX; --i >= 0; ) ++ if (!hlist_empty(&old_pid->tasks[i])) ++ BUG(); ++ ++ for (i = 0; i < pid->level; i++) ++ hlist_replace_rcu(&old_pid->numbers[i].pid_chain, ++ &pid->numbers[i].pid_chain); ++ ++ upid = &pid->numbers[pid->level]; ++ hlist_add_head_rcu(&upid->pid_chain, ++ &pid_hash[pid_hashfn(upid->nr, upid->ns)]); ++ } ++ ++ call_rcu(&old_pid->rcu, delayed_put_pid); ++} ++ ++static int __pid_ns_attach_task(struct pid_namespace *ns, ++ struct task_struct *tsk, pid_t nr) ++{ ++ struct pid *pid; ++ enum pid_type type; ++ unsigned long old_size, new_size; ++ ++ pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL); ++ if (!pid) ++ goto out; ++ ++ if (nr == 0) ++ nr = alloc_pidmap(ns); ++ else ++ nr = set_pidmap(ns, nr); ++ ++ if (nr < 0) ++ goto out_free; ++ ++ memcpy(pid, task_pid(tsk), ++ sizeof(struct pid) + (ns->level - 1) * sizeof(struct upid)); ++ get_pid_ns(ns); ++ pid->level++; ++ BUG_ON(pid->level != ns->level); ++ pid->numbers[pid->level].nr = nr; ++ pid->numbers[pid->level].ns = ns; ++ atomic_set(&pid->count, 1); ++ for (type = 0; type < PIDTYPE_MAX; ++type) ++ INIT_HLIST_HEAD(&pid->tasks[type]); ++ ++ old_size = pid->numbers[pid->level - 1].ns->pid_cachep->objuse; ++ new_size = pid->numbers[pid->level].ns->pid_cachep->objuse; ++ local_irq_disable(); ++ /* ++ * Depending on sizeof(struct foo), cache flags (redzoning, etc) ++ * and actual CPU (cacheline_size() jump from 64 to 128 bytes after ++ * CPU detection) new size can very well be smaller than old size. ++ */ ++ if (new_size > old_size) { ++ if (ub_kmemsize_charge(pid->ub, new_size - old_size, UB_HARD) < 0) ++ goto out_enable; ++ } else ++ ub_kmemsize_uncharge(pid->ub, old_size - new_size); ++ ++ write_lock(&tasklist_lock); ++ ++ spin_lock(&pidmap_lock); ++ reattach_pid(tsk, PIDTYPE_SID, pid); ++ set_task_session(tsk, pid_nr(pid)); ++ reattach_pid(tsk, PIDTYPE_PGID, pid); ++ tsk->signal->__pgrp = pid_nr(pid); ++ current->signal->tty_old_pgrp = NULL; ++ ++ reattach_pid(tsk, PIDTYPE_PID, pid); ++ spin_unlock(&pidmap_lock); ++ ++ write_unlock_irq(&tasklist_lock); ++ ++ return 0; ++ ++out_enable: ++ local_irq_enable(); ++ put_pid_ns(ns); ++out_free: ++ kmem_cache_free(ns->pid_cachep, pid); ++out: ++ return -ENOMEM; ++} ++ ++int pid_ns_attach_task(struct pid_namespace *ns, struct task_struct *tsk) ++{ ++ return __pid_ns_attach_task(ns, tsk, 0); ++} ++EXPORT_SYMBOL_GPL(pid_ns_attach_task); ++ ++int pid_ns_attach_init(struct pid_namespace *ns, struct task_struct *tsk) ++{ ++ int err; ++ ++ err = __pid_ns_attach_task(ns, tsk, 1); ++ if (err < 0) ++ return err; ++ ++ ns->child_reaper = tsk; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(pid_ns_attach_init); ++ ++#ifdef CONFIG_VE ++static noinline void show_lost_task(struct task_struct *p) ++{ ++ extern char * task_sig(struct task_struct *p, char *buffer); ++ char buf[512]; ++ ++ task_sig(p, buf); ++ printk("Lost task: %d/%s/%p\nSignals:%s\n", p->pid, p->comm, p, buf); ++} ++ ++static void zap_ve_processes(struct ve_struct *env) ++{ ++ /* ++ * Here the VE changes its state into "not running". ++ * op_sem taken for write is a barrier to all VE manipulations from ++ * ioctl: it waits for operations currently in progress and blocks all ++ * subsequent operations until is_running is set to 0 and op_sem is ++ * released. ++ */ ++ down_write(&env->op_sem); ++ env->is_running = 0; ++ up_write(&env->op_sem); ++ ++ /* wait for all init childs exit */ ++ while (atomic_read(&env->pcounter) > 1) { ++ struct task_struct *g, *p; ++ long delay = 1; ++ ++ if (sys_wait4(-1, NULL, __WALL | WNOHANG, NULL) > 0) ++ continue; ++ /* it was ENOCHLD or no more children somehow */ ++ if (atomic_read(&env->pcounter) == 1) ++ break; ++ ++ /* clear all signals to avoid wakeups */ ++ if (signal_pending(current)) ++ flush_signals(current); ++ /* we have child without signal sent */ ++ __set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(delay); ++ delay = (delay < HZ) ? (delay << 1) : HZ; ++ read_lock(&tasklist_lock); ++ do_each_thread_ve(g, p) { ++ if (p != current) { ++ /* ++ * by that time no processes other then entered ++ * may exist in the VE. if some were missed by ++ * zap_pid_ns_processes() this was a BUG ++ */ ++ if (!p->did_ve_enter) ++ show_lost_task(p); ++ ++ force_sig_specific(SIGKILL, p); ++ } ++ } while_each_thread_ve(g, p); ++ read_unlock(&tasklist_lock); ++ } ++} ++#endif ++ + void zap_pid_ns_processes(struct pid_namespace *pid_ns) + { + int nr; +@@ -655,12 +903,25 @@ + rc = sys_wait4(-1, NULL, __WALL, NULL); + } while (rc != -ECHILD); + +- ++#ifdef CONFIG_VE ++ zap_ve_processes(get_exec_env()); ++#endif + /* Child reaper for the pid namespace is going away */ + pid_ns->child_reaper = NULL; + return; + } + ++pid_t pid_to_vpid(pid_t nr) ++{ ++ struct pid *pid; ++ ++ pid = find_pid(nr); ++ if (pid) ++ return pid->numbers[pid->level].nr; ++ return -1; ++} ++EXPORT_SYMBOL_GPL(pid_to_vpid); ++ + /* + * The pid hash table is scaled according to the amount of memory in the + * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or +Index: kernel/kernel/posix-cpu-timers.c +=================================================================== +--- kernel.orig/kernel/posix-cpu-timers.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/posix-cpu-timers.c 2008-11-24 15:47:46.000000000 +0100 +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + static int check_clock(const clockid_t which_clock) + { +Index: kernel/kernel/posix-timers.c +=================================================================== +--- kernel.orig/kernel/posix-timers.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/posix-timers.c 2008-11-24 15:47:46.000000000 +0100 +@@ -31,6 +31,8 @@ + * POSIX clocks & timers + */ + #include ++#include ++#include + #include + #include + #include +@@ -47,6 +49,9 @@ + #include + #include + #include ++#include ++ ++#include + + /* + * Management arrays for POSIX timers. Timers are kept in slab memory +@@ -241,8 +246,8 @@ + register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic); + + posix_timers_cache = kmem_cache_create("posix_timers_cache", +- sizeof (struct k_itimer), 0, SLAB_PANIC, +- NULL); ++ sizeof (struct k_itimer), 0, ++ SLAB_PANIC|SLAB_UBC, NULL); + idr_init(&posix_timers_id); + return 0; + } +@@ -298,6 +303,13 @@ + + int posix_timer_event(struct k_itimer *timr,int si_private) + { ++ int ret; ++ struct ve_struct *ve; ++ struct user_beancounter *ub; ++ ++ ve = set_exec_env(timr->it_process->ve_task_info.owner_env); ++ ub = set_exec_ub(timr->it_process->task_bc.task_ub); ++ + memset(&timr->sigq->info, 0, sizeof(siginfo_t)); + timr->sigq->info.si_sys_private = si_private; + /* Send signal to the process that owns this timer.*/ +@@ -310,11 +322,11 @@ + + if (timr->it_sigev_notify & SIGEV_THREAD_ID) { + struct task_struct *leader; +- int ret = send_sigqueue(timr->it_sigev_signo, timr->sigq, ++ ret = send_sigqueue(timr->it_sigev_signo, timr->sigq, + timr->it_process); + + if (likely(ret >= 0)) +- return ret; ++ goto out; + + timr->it_sigev_notify = SIGEV_SIGNAL; + leader = timr->it_process->group_leader; +@@ -322,8 +334,12 @@ + timr->it_process = leader; + } + +- return send_group_sigqueue(timr->it_sigev_signo, timr->sigq, ++ ret = send_group_sigqueue(timr->it_sigev_signo, timr->sigq, + timr->it_process); ++out: ++ (void)set_exec_ub(ub); ++ (void)set_exec_env(ve); ++ return ret; + } + EXPORT_SYMBOL_GPL(posix_timer_event); + +Index: kernel/kernel/power/process.c +=================================================================== +--- kernel.orig/kernel/power/process.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/power/process.c 2008-11-24 15:47:46.000000000 +0100 +@@ -14,6 +14,8 @@ + #include + #include + ++static atomic_t global_suspend = ATOMIC_INIT(0); ++ + /* + * Timeout for stopping processes + */ +@@ -26,7 +28,9 @@ + { + if ((p == current) || + (p->flags & PF_NOFREEZE) || +- (p->exit_state != 0)) ++ (p->exit_state != 0) || ++ (p->state == TASK_STOPPED) || ++ (p->state == TASK_TRACED)) + return 0; + return 1; + } +@@ -50,6 +54,24 @@ + processes around? */ + long save; + ++#if defined(CONFIG_VZ_CHECKPOINT) || defined(CONFIG_VZ_CHECKPOINT_MODULE) ++ save = current->state; ++ current->state = TASK_UNINTERRUPTIBLE; ++ ++ spin_lock_irq(¤t->sighand->siglock); ++ if (test_and_clear_thread_flag(TIF_FREEZE)) { ++ recalc_sigpending(); /* We sent fake signal, clean it up */ ++ current->flags |= PF_FROZEN; ++ } else { ++ /* Freeze request could be canceled before we entered ++ * refrigerator(). In this case we do nothing. */ ++ current->state = save; ++ } ++ spin_unlock_irq(¤t->sighand->siglock); ++ ++ while (current->flags & PF_FROZEN) ++ schedule(); ++#else + task_lock(current); + if (freezing(current)) { + frozen_process(); +@@ -71,6 +93,7 @@ + break; + schedule(); + } ++#endif + pr_debug("%s left refrigerator\n", current->comm); + __set_current_state(save); + } +@@ -178,7 +201,7 @@ + do { + todo = 0; + read_lock(&tasklist_lock); +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + if (frozen(p) || !freezeable(p)) + continue; + +@@ -192,7 +215,7 @@ + + if (!freezer_should_skip(p)) + todo++; +- } while_each_thread(g, p); ++ } while_each_thread_all(g, p); + read_unlock(&tasklist_lock); + yield(); /* Yield is okay here */ + if (time_after(jiffies, end_time)) +@@ -216,13 +239,13 @@ + elapsed_csecs / 100, elapsed_csecs % 100, todo); + show_state(); + read_lock(&tasklist_lock); +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + task_lock(p); + if (freezing(p) && !freezer_should_skip(p)) + printk(KERN_ERR " %s\n", p->comm); + cancel_freezing(p); + task_unlock(p); +- } while_each_thread(g, p); ++ } while_each_thread_all(g, p); + read_unlock(&tasklist_lock); + } else { + printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100, +@@ -239,6 +262,7 @@ + { + int error; + ++ atomic_inc(&global_suspend); + printk("Freezing user space processes ... "); + error = try_to_freeze_tasks(FREEZER_USER_SPACE); + if (error) +@@ -253,6 +277,7 @@ + Exit: + BUG_ON(in_atomic()); + printk("\n"); ++ atomic_dec(&global_suspend); + return error; + } + +@@ -261,15 +286,17 @@ + struct task_struct *g, *p; + + read_lock(&tasklist_lock); +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + if (!freezeable(p)) + continue; + + if (!p->mm == thaw_user_space) + continue; + +- thaw_process(p); +- } while_each_thread(g, p); ++ if (!thaw_process(p)) ++ printk(KERN_WARNING " Strange, %s not stopped\n", ++ p->comm ); ++ } while_each_thread_all(g, p); + read_unlock(&tasklist_lock); + } + +Index: kernel/kernel/printk.c +=================================================================== +--- kernel.orig/kernel/printk.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/printk.c 2008-11-24 15:47:46.000000000 +0100 +@@ -31,7 +31,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + + #include +@@ -54,6 +56,9 @@ + DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ + }; + ++struct printk_aligned printk_no_wake_var[NR_CPUS]; ++EXPORT_SYMBOL(printk_no_wake_var); ++ + /* + * Low level drivers may need that to know if they can schedule in + * their unblank() callback or not. So let's export it. +@@ -84,7 +89,7 @@ + * It is also used in interesting ways to provide interlocking in + * release_console_sem(). + */ +-static DEFINE_SPINLOCK(logbuf_lock); ++DEFINE_SPINLOCK(logbuf_lock); + + #define LOG_BUF_MASK (log_buf_len-1) + #define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK]) +@@ -115,6 +120,7 @@ + + /* Flag: console code may call schedule() */ + static int console_may_schedule; ++int console_silence_loglevel; + + #ifdef CONFIG_PRINTK + +@@ -123,6 +129,19 @@ + static int log_buf_len = __LOG_BUF_LEN; + static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */ + ++static int __init setup_console_silencelevel(char *str) ++{ ++ int level; ++ ++ if (get_option(&str, &level) != 1) ++ return 0; ++ ++ console_silence_loglevel = level; ++ return 1; ++} ++ ++__setup("silencelevel=", setup_console_silencelevel); ++ + static int __init log_buf_len_setup(char *str) + { + unsigned long size = memparse(str, &str); +@@ -293,6 +312,9 @@ + char c; + int error = 0; + ++ if (!ve_is_super(get_exec_env()) && (type == 6 || type == 7)) ++ goto out; ++ + error = security_syslog(type); + if (error) + return error; +@@ -313,15 +335,15 @@ + error = -EFAULT; + goto out; + } +- error = wait_event_interruptible(log_wait, +- (log_start - log_end)); ++ error = wait_event_interruptible(ve_log_wait, ++ (ve_log_start - ve_log_end)); + if (error) + goto out; + i = 0; + spin_lock_irq(&logbuf_lock); +- while (!error && (log_start != log_end) && i < len) { +- c = LOG_BUF(log_start); +- log_start++; ++ while (!error && (ve_log_start != ve_log_end) && i < len) { ++ c = VE_LOG_BUF(ve_log_start); ++ ve_log_start++; + spin_unlock_irq(&logbuf_lock); + error = __put_user(c,buf); + buf++; +@@ -347,15 +369,17 @@ + error = -EFAULT; + goto out; + } ++ if (ve_log_buf == NULL) ++ goto out; + count = len; +- if (count > log_buf_len) +- count = log_buf_len; ++ if (count > ve_log_buf_len) ++ count = ve_log_buf_len; + spin_lock_irq(&logbuf_lock); +- if (count > logged_chars) +- count = logged_chars; ++ if (count > ve_logged_chars) ++ count = ve_logged_chars; + if (do_clear) +- logged_chars = 0; +- limit = log_end; ++ ve_logged_chars = 0; ++ limit = ve_log_end; + /* + * __put_user() could sleep, and while we sleep + * printk() could overwrite the messages +@@ -364,9 +388,9 @@ + */ + for (i = 0; i < count && !error; i++) { + j = limit-1-i; +- if (j + log_buf_len < log_end) ++ if (j + ve_log_buf_len < ve_log_end) + break; +- c = LOG_BUF(j); ++ c = VE_LOG_BUF(j); + spin_unlock_irq(&logbuf_lock); + error = __put_user(c,&buf[count-1-i]); + cond_resched(); +@@ -390,7 +414,7 @@ + } + break; + case 5: /* Clear ring buffer */ +- logged_chars = 0; ++ ve_logged_chars = 0; + break; + case 6: /* Disable logging to console */ + console_loglevel = minimum_console_loglevel; +@@ -402,16 +426,19 @@ + error = -EINVAL; + if (len < 1 || len > 8) + goto out; ++ error = 0; ++ /* VE has no console, so return success */ ++ if (!ve_is_super(get_exec_env())) ++ goto out; + if (len < minimum_console_loglevel) + len = minimum_console_loglevel; + console_loglevel = len; +- error = 0; + break; + case 9: /* Number of chars in the log buffer */ +- error = log_end - log_start; ++ error = ve_log_end - ve_log_start; + break; + case 10: /* Size of the log buffer */ +- error = log_buf_len; ++ error = ve_log_buf_len; + break; + default: + error = -EINVAL; +@@ -522,16 +549,18 @@ + + static void emit_log_char(char c) + { +- LOG_BUF(log_end) = c; +- log_end++; +- if (log_end - log_start > log_buf_len) +- log_start = log_end - log_buf_len; +- if (log_end - con_start > log_buf_len) +- con_start = log_end - log_buf_len; +- if (logged_chars < log_buf_len) +- logged_chars++; ++ VE_LOG_BUF(ve_log_end) = c; ++ ve_log_end++; ++ if (ve_log_end - ve_log_start > ve_log_buf_len) ++ ve_log_start = ve_log_end - ve_log_buf_len; ++ if (ve_is_super(get_exec_env()) && ve_log_end - con_start > ve_log_buf_len) ++ con_start = ve_log_end - ve_log_buf_len; ++ if (ve_logged_chars < ve_log_buf_len) ++ ve_logged_chars++; + } + ++static unsigned long do_release_console_sem(unsigned long *flags); ++ + /* + * Zap console related locks when oopsing. Only zap at most once + * every 10 seconds, to leave time for slow consoles to print a +@@ -613,6 +642,30 @@ + * printf(3) + */ + ++static inline int ve_log_init(void) ++{ ++#ifdef CONFIG_VE ++ if (ve_log_buf != NULL) ++ return 0; ++ ++ if (ve_is_super(get_exec_env())) { ++ ve0._log_wait = &log_wait; ++ ve0._log_start = &log_start; ++ ve0._log_end = &log_end; ++ ve0._logged_chars = &logged_chars; ++ ve0.log_buf = log_buf; ++ return 0; ++ } ++ ++ ve_log_buf = kmalloc(ve_log_buf_len, GFP_ATOMIC); ++ if (!ve_log_buf) ++ return -ENOMEM; ++ ++ memset(ve_log_buf, 0, ve_log_buf_len); ++#endif ++ return 0; ++} ++ + asmlinkage int printk(const char *fmt, ...) + { + va_list args; +@@ -628,13 +681,14 @@ + /* cpu currently holding logbuf_lock */ + static volatile unsigned int printk_cpu = UINT_MAX; + +-asmlinkage int vprintk(const char *fmt, va_list args) ++asmlinkage int __vprintk(const char *fmt, va_list args) + { + unsigned long flags; + int printed_len; + char *p; + static char printk_buf[1024]; + static int log_level_unknown = 1; ++ int err, need_wake; + + boot_delay_msec(); + +@@ -650,6 +704,12 @@ + spin_lock(&logbuf_lock); + printk_cpu = smp_processor_id(); + ++ err = ve_log_init(); ++ if (err) { ++ spin_unlock_irqrestore(&logbuf_lock, flags); ++ return err; ++ } ++ + /* Emit the output into the temporary buffer */ + printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args); + +@@ -710,7 +770,26 @@ + log_level_unknown = 1; + } + +- if (!down_trylock(&console_sem)) { ++ if (!ve_is_super(get_exec_env())) { ++ need_wake = (ve_log_start != ve_log_end); ++ spin_unlock_irqrestore(&logbuf_lock, flags); ++ if (!oops_in_progress && need_wake) ++ wake_up_interruptible(&ve_log_wait); ++ } else if (__printk_no_wake) { ++ /* ++ * A difficult case, created by the console semaphore mess... ++ * All wakeups are omitted. ++ */ ++ if (!atomic_add_negative(-1, &console_sem.count)) { ++ console_locked = 1; ++ console_may_schedule = 0; ++ do_release_console_sem(&flags); ++ console_locked = 0; ++ console_may_schedule = 0; ++ } ++ atomic_inc(&console_sem.count); ++ spin_unlock_irqrestore(&logbuf_lock, flags); ++ } else if (!down_trylock(&console_sem)) { + /* + * We own the drivers. We can drop the spinlock and + * let release_console_sem() print the text, maybe ... +@@ -753,6 +832,63 @@ + EXPORT_SYMBOL(printk); + EXPORT_SYMBOL(vprintk); + ++static struct timer_list conswakeup_timer; ++static void conswakeup_timer_call(unsigned long dumy) ++{ ++ if (!down_trylock(&console_sem)) { ++ console_locked = 1; ++ console_may_schedule = 0; ++ release_console_sem(); ++ } ++ mod_timer(&conswakeup_timer, jiffies + 5 * HZ); ++} ++ ++static int __init conswakeup_init(void) ++{ ++ init_timer(&conswakeup_timer); ++ conswakeup_timer.function = &conswakeup_timer_call; ++ conswakeup_timer.expires = jiffies + 5 * HZ; ++ add_timer(&conswakeup_timer); ++ return 0; ++} ++console_initcall(conswakeup_init); ++ ++asmlinkage int vprintk(const char *fmt, va_list args) ++{ ++ int i; ++ struct ve_struct *env; ++ ++ env = set_exec_env(get_ve0()); ++ i = __vprintk(fmt, args); ++ (void)set_exec_env(env); ++ return i; ++} ++ ++asmlinkage int ve_vprintk(int dst, const char *fmt, va_list args) ++{ ++ int printed_len; ++ ++ printed_len = 0; ++ if (ve_is_super(get_exec_env()) || (dst & VE0_LOG)) ++ printed_len = vprintk(fmt, args); ++ if (!ve_is_super(get_exec_env()) && (dst & VE_LOG)) ++ printed_len = __vprintk(fmt, args); ++ return printed_len; ++} ++ ++asmlinkage int ve_printk(int dst, const char *fmt, ...) ++{ ++ va_list args; ++ int printed_len; ++ ++ va_start(args, fmt); ++ printed_len = ve_vprintk(dst, fmt, args); ++ va_end(args); ++ return printed_len; ++} ++EXPORT_SYMBOL(ve_printk); ++ ++ + #else + + asmlinkage long sys_syslog(int type, char __user *buf, int len) +@@ -950,31 +1086,40 @@ + * + * release_console_sem() may be called from any context. + */ +-void release_console_sem(void) ++static unsigned long do_release_console_sem(unsigned long *flags) + { +- unsigned long flags; + unsigned long _con_start, _log_end; + unsigned long wake_klogd = 0; + + if (console_suspended) { + up(&secondary_console_sem); +- return; ++ goto out; + } + + console_may_schedule = 0; + + for ( ; ; ) { +- spin_lock_irqsave(&logbuf_lock, flags); + wake_klogd |= log_start - log_end; + if (con_start == log_end) + break; /* Nothing to print */ + _con_start = con_start; + _log_end = log_end; + con_start = log_end; /* Flush */ +- spin_unlock(&logbuf_lock); ++ spin_unlock_irqrestore(&logbuf_lock, *flags); + call_console_drivers(_con_start, _log_end); +- local_irq_restore(flags); ++ spin_lock_irqsave(&logbuf_lock, *flags); + } ++out: ++ return wake_klogd; ++} ++ ++void release_console_sem(void) ++{ ++ unsigned long flags; ++ unsigned long wake_klogd; ++ ++ spin_lock_irqsave(&logbuf_lock, flags); ++ wake_klogd = do_release_console_sem(&flags); + console_locked = 0; + up(&console_sem); + spin_unlock_irqrestore(&logbuf_lock, flags); +@@ -1285,6 +1430,36 @@ + } + EXPORT_SYMBOL(printk_ratelimit); + ++/* ++ * Rate limiting stuff. ++ */ ++int vz_ratelimit(struct vz_rate_info *p) ++{ ++ unsigned long cjif, djif; ++ unsigned long flags; ++ static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED; ++ long new_bucket; ++ ++ spin_lock_irqsave(&ratelimit_lock, flags); ++ cjif = jiffies; ++ djif = cjif - p->last; ++ if (djif < p->interval) { ++ if (p->bucket >= p->burst) { ++ spin_unlock_irqrestore(&ratelimit_lock, flags); ++ return 0; ++ } ++ p->bucket++; ++ } else { ++ new_bucket = p->bucket - (djif / (unsigned)p->interval); ++ if (new_bucket < 0) ++ new_bucket = 0; ++ p->bucket = new_bucket + 1; ++ } ++ p->last = cjif; ++ spin_unlock_irqrestore(&ratelimit_lock, flags); ++ return 1; ++} ++ + /** + * printk_timed_ratelimit - caller-controlled printk ratelimiting + * @caller_jiffies: pointer to caller's state +Index: kernel/kernel/ptrace.c +=================================================================== +--- kernel.orig/kernel/ptrace.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/ptrace.c 2008-11-24 15:47:46.000000000 +0100 +@@ -131,6 +131,8 @@ + * or halting the specified task is impossible. + */ + int dumpable = 0; ++ int vps_dumpable = 0; ++ + /* Don't let security modules deny introspection */ + if (task == current) + return 0; +@@ -142,11 +144,17 @@ + (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) + return -EPERM; + smp_rmb(); +- if (task->mm) ++ if (task->mm) { + dumpable = get_dumpable(task->mm); ++ vps_dumpable = (task->mm->vps_dumpable == 1); ++ } ++ + if (!dumpable && !capable(CAP_SYS_PTRACE)) + return -EPERM; +- ++ if (!vps_dumpable && !ve_is_super(get_exec_env())) ++ return -EPERM; ++ if (!ve_accessible(VE_TASK_INFO(task)->owner_env, get_exec_env())) ++ return -EPERM; + return security_ptrace(current, task); + } + +@@ -199,6 +207,8 @@ + retval = __ptrace_may_attach(task); + if (retval) + goto bad; ++ if (task->mm->vps_dumpable == 2) ++ goto bad; + + /* Go */ + task->ptrace |= PT_PTRACED | ((task->real_parent != current) +@@ -294,6 +304,7 @@ + } + return copied; + } ++EXPORT_SYMBOL_GPL(access_process_vm); + + static int ptrace_setoptions(struct task_struct *child, long data) + { +Index: kernel/kernel/sched.c +=================================================================== +--- kernel.orig/kernel/sched.c 2008-11-24 14:17:45.000000000 +0100 ++++ kernel/kernel/sched.c 2008-11-24 15:47:46.000000000 +0100 +@@ -310,6 +310,9 @@ + */ + unsigned long nr_uninterruptible; + ++ unsigned long nr_sleeping; ++ unsigned long nr_stopped; ++ + struct task_struct *curr, *idle; + unsigned long next_balance; + struct mm_struct *prev_mm; +@@ -379,6 +382,11 @@ + #endif + } + ++struct kernel_stat_glob kstat_glob; ++DEFINE_SPINLOCK(kstat_glb_lock); ++EXPORT_SYMBOL(kstat_glob); ++EXPORT_SYMBOL(kstat_glb_lock); ++ + /* + * Update the per-runqueue clock, as finegrained as the platform can give + * us, but without assuming monotonicity, etc.: +@@ -631,6 +639,217 @@ + spin_unlock_irqrestore(&rq->lock, *flags); + } + ++#ifdef CONFIG_VE ++static inline void ve_nr_iowait_inc(struct ve_struct *ve, int cpu) ++{ ++ VE_CPU_STATS(ve, cpu)->nr_iowait++; ++} ++ ++static inline void ve_nr_iowait_dec(struct ve_struct *ve, int cpu) ++{ ++ VE_CPU_STATS(ve, cpu)->nr_iowait--; ++} ++ ++static inline void ve_nr_unint_inc(struct ve_struct *ve, int cpu) ++{ ++ VE_CPU_STATS(ve, cpu)->nr_unint++; ++} ++ ++static inline void ve_nr_unint_dec(struct ve_struct *ve, int cpu) ++{ ++ VE_CPU_STATS(ve, cpu)->nr_unint--; ++} ++ ++#define cycles_after(a, b) ((long long)(b) - (long long)(a) < 0) ++ ++cycles_t ve_sched_get_idle_time(struct ve_struct *ve, int cpu) ++{ ++ struct ve_cpu_stats *ve_stat; ++ unsigned v; ++ cycles_t strt, ret, cycles; ++ ++ ve_stat = VE_CPU_STATS(ve, cpu); ++ do { ++ v = read_seqcount_begin(&ve_stat->stat_lock); ++ ret = ve_stat->idle_time; ++ strt = ve_stat->strt_idle_time; ++ if (strt && nr_uninterruptible_ve(ve) == 0) { ++ cycles = get_cycles(); ++ if (cycles_after(cycles, strt)) ++ ret += cycles - strt; ++ } ++ } while (read_seqcount_retry(&ve_stat->stat_lock, v)); ++ return ret; ++} ++EXPORT_SYMBOL(ve_sched_get_idle_time); ++ ++cycles_t ve_sched_get_iowait_time(struct ve_struct *ve, int cpu) ++{ ++ struct ve_cpu_stats *ve_stat; ++ unsigned v; ++ cycles_t strt, ret, cycles; ++ ++ ve_stat = VE_CPU_STATS(ve, cpu); ++ do { ++ v = read_seqcount_begin(&ve_stat->stat_lock); ++ ret = ve_stat->iowait_time; ++ strt = ve_stat->strt_idle_time; ++ if (strt && nr_iowait_ve(ve) > 0) { ++ cycles = get_cycles(); ++ if (cycles_after(cycles, strt)) ++ ret += cycles - strt; ++ } ++ } while (read_seqcount_retry(&ve_stat->stat_lock, v)); ++ return ret; ++} ++EXPORT_SYMBOL(ve_sched_get_iowait_time); ++ ++static void ve_stop_idle(struct ve_struct *ve, unsigned int cpu, cycles_t cycles) ++{ ++ struct ve_cpu_stats *ve_stat; ++ ++ ve_stat = VE_CPU_STATS(ve, cpu); ++ ++ write_seqcount_begin(&ve_stat->stat_lock); ++ if (ve_stat->strt_idle_time) { ++ if (cycles_after(cycles, ve_stat->strt_idle_time)) { ++ if (nr_iowait_ve(ve) == 0) ++ ve_stat->idle_time += ++ cycles - ve_stat->strt_idle_time; ++ else ++ ve_stat->iowait_time += ++ cycles - ve_stat->strt_idle_time; ++ } ++ ve_stat->strt_idle_time = 0; ++ } ++ write_seqcount_end(&ve_stat->stat_lock); ++} ++ ++static void ve_strt_idle(struct ve_struct *ve, unsigned int cpu, cycles_t cycles) ++{ ++ struct ve_cpu_stats *ve_stat; ++ ++ ve_stat = VE_CPU_STATS(ve, cpu); ++ ++ write_seqcount_begin(&ve_stat->stat_lock); ++ ve_stat->strt_idle_time = cycles; ++ write_seqcount_end(&ve_stat->stat_lock); ++} ++ ++static inline void ve_nr_running_inc(struct ve_struct *ve, int cpu, cycles_t cycles) ++{ ++ if (++VE_CPU_STATS(ve, cpu)->nr_running == 1) ++ ve_stop_idle(ve, cpu, cycles); ++} ++ ++static inline void ve_nr_running_dec(struct ve_struct *ve, int cpu, cycles_t cycles) ++{ ++ if (--VE_CPU_STATS(ve, cpu)->nr_running == 0) ++ ve_strt_idle(ve, cpu, cycles); ++} ++ ++void ve_sched_attach(struct ve_struct *target_ve) ++{ ++ struct task_struct *tsk; ++ unsigned int cpu; ++ cycles_t cycles; ++ ++ tsk = current; ++ preempt_disable(); ++ cycles = get_cycles(); ++ cpu = task_cpu(tsk); ++ ve_nr_running_dec(VE_TASK_INFO(tsk)->owner_env, cpu, cycles); ++ ve_nr_running_inc(target_ve, cpu, cycles); ++ preempt_enable(); ++} ++EXPORT_SYMBOL(ve_sched_attach); ++ ++static inline void write_wakeup_stamp(struct task_struct *p, cycles_t cyc) ++{ ++ struct ve_task_info *ti; ++ ++ ti = VE_TASK_INFO(p); ++ write_seqcount_begin(&ti->wakeup_lock); ++ ti->wakeup_stamp = cyc; ++ write_seqcount_end(&ti->wakeup_lock); ++} ++ ++static inline void update_sched_lat(struct task_struct *t, cycles_t cycles) ++{ ++ int cpu; ++ cycles_t ve_wstamp; ++ ++ /* safe due to runqueue lock */ ++ cpu = smp_processor_id(); ++ ve_wstamp = t->ve_task_info.wakeup_stamp; ++ ++ if (ve_wstamp && cycles > ve_wstamp) { ++ KSTAT_LAT_PCPU_ADD(&kstat_glob.sched_lat, ++ cpu, cycles - ve_wstamp); ++ KSTAT_LAT_PCPU_ADD(&t->ve_task_info.exec_env->sched_lat_ve, ++ cpu, cycles - ve_wstamp); ++ } ++} ++ ++static inline void update_ve_task_info(struct task_struct *prev, cycles_t cycles) ++{ ++#ifdef CONFIG_FAIRSCHED ++ if (prev != this_pcpu()->idle) { ++#else ++ if (prev != this_rq()->idle) { ++#endif ++ VE_CPU_STATS(prev->ve_task_info.owner_env, ++ smp_processor_id())->used_time += ++ cycles - prev->ve_task_info.sched_time; ++ ++ prev->ve_task_info.sched_time = cycles; ++ } ++} ++#else ++static inline void ve_nr_running_inc(struct ve_struct, int cpu, cycles_t cycles) ++{ ++} ++ ++static inline void ve_nr_running_dec(struct ve_struct, int cpu, cycles_t cycles) ++{ ++} ++ ++static inline void ve_nr_iowait_inc(struct ve_struct *ve, int cpu) ++{ ++} ++ ++static inline void ve_nr_iowait_dec(struct ve_struct *ve, int cpu) ++{ ++} ++ ++static inline void ve_nr_unint_inc(struct ve_struct *ve, int cpu) ++{ ++} ++ ++static inline void ve_nr_unint_dec(struct ve_struct *ve, int cpu) ++{ ++} ++ ++static inline void update_ve_task_info(struct task_struct *prev, cycles_t cycles) ++{ ++} ++#endif ++ ++struct task_nrs_struct { ++ long nr_running; ++ long nr_unint; ++ long nr_stopped; ++ long nr_sleeping; ++ long nr_iowait; ++ long long nr_switches; ++} ____cacheline_aligned_in_smp; ++ ++unsigned long nr_zombie = 0; /* protected by tasklist_lock */ ++EXPORT_SYMBOL(nr_zombie); ++ ++atomic_t nr_dead = ATOMIC_INIT(0); ++EXPORT_SYMBOL(nr_dead); ++ + /* + * this_rq_lock - lock this runqueue and disable interrupts. + */ +@@ -1046,11 +1265,21 @@ + */ + static void activate_task(struct rq *rq, struct task_struct *p, int wakeup) + { +- if (p->state == TASK_UNINTERRUPTIBLE) ++ cycles_t cycles; ++ ++#ifdef CONFIG_VE ++ cycles = get_cycles(); ++ write_wakeup_stamp(p, cycles); ++ p->ve_task_info.sleep_time += cycles; ++#endif ++ if (p->state == TASK_UNINTERRUPTIBLE) { + rq->nr_uninterruptible--; ++ ve_nr_unint_dec(VE_TASK_INFO(p)->owner_env, task_cpu(p)); ++ } + + enqueue_task(rq, p, wakeup); + inc_nr_running(p, rq); ++ ve_nr_running_inc(VE_TASK_INFO(p)->owner_env, task_cpu(p), cycles); + } + + /* +@@ -1058,6 +1287,30 @@ + */ + static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep) + { ++ cycles_t cycles; ++#ifdef CONFIG_VE ++ unsigned int cpu, pcpu; ++ struct ve_struct *ve; ++ ++ cycles = get_cycles(); ++ cpu = task_cpu(p); ++ pcpu = smp_processor_id(); ++ ve = p->ve_task_info.owner_env; ++ ++ p->ve_task_info.sleep_time -= cycles; ++#endif ++ if (p->state == TASK_UNINTERRUPTIBLE) { ++ ve_nr_unint_inc(ve, cpu); ++ } ++ if (p->state == TASK_INTERRUPTIBLE) { ++ rq->nr_sleeping++; ++ } ++ if (p->state == TASK_STOPPED) { ++ rq->nr_stopped++; ++ } ++ ++ ve_nr_running_dec(VE_TASK_INFO(p)->owner_env, cpu, cycles); ++ + if (p->state == TASK_UNINTERRUPTIBLE) + rq->nr_uninterruptible++; + +@@ -1263,6 +1516,7 @@ + break; + } + } ++EXPORT_SYMBOL_GPL(wait_task_inactive); + + /*** + * kick_process - kick a running thread to enter/exit the kernel +@@ -1782,6 +2036,10 @@ + /* Want to start with kernel preemption disabled. */ + task_thread_info(p)->preempt_count = 1; + #endif ++#ifdef CONFIG_VE ++ /* cosmetic: sleep till wakeup below */ ++ p->ve_task_info.sleep_time -= get_cycles(); ++#endif + put_cpu(); + } + +@@ -1812,6 +2070,8 @@ + */ + p->sched_class->task_new(rq, p); + inc_nr_running(p, rq); ++ ve_nr_running_inc(VE_TASK_INFO(p)->owner_env, task_cpu(p), ++ get_cycles()); + } + check_preempt_curr(rq, p); + task_rq_unlock(rq, &flags); +@@ -1964,6 +2224,7 @@ + if (current->set_child_tid) + put_user(task_pid_vnr(current), current->set_child_tid); + } ++EXPORT_SYMBOL_GPL(schedule_tail); + + /* + * context_switch - switch to the new MM and the new +@@ -2034,6 +2295,7 @@ + + return sum; + } ++EXPORT_SYMBOL(nr_running); + + unsigned long nr_uninterruptible(void) + { +@@ -2051,6 +2313,7 @@ + + return sum; + } ++EXPORT_SYMBOL(nr_uninterruptible); + + unsigned long long nr_context_switches(void) + { +@@ -2062,6 +2325,7 @@ + + return sum; + } ++EXPORT_SYMBOL(nr_context_switches); + + unsigned long nr_iowait(void) + { +@@ -2072,6 +2336,7 @@ + + return sum; + } ++EXPORT_SYMBOL(nr_iowait); + + unsigned long nr_active(void) + { +@@ -2088,6 +2353,72 @@ + return running + uninterruptible; + } + ++unsigned long nr_stopped(void) ++{ ++ unsigned long i, sum = 0; ++ ++ for_each_online_cpu(i) ++ sum += cpu_rq(i)->nr_stopped; ++ if (unlikely((long)sum < 0)) ++ sum = 0; ++ return sum; ++} ++EXPORT_SYMBOL(nr_stopped); ++ ++unsigned long nr_sleeping(void) ++{ ++ unsigned long i, sum = 0; ++ ++ for_each_online_cpu(i) ++ sum += cpu_rq(i)->nr_sleeping; ++ if (unlikely((long)sum < 0)) ++ sum = 0; ++ return sum; ++} ++EXPORT_SYMBOL(nr_sleeping); ++ ++#ifdef CONFIG_VE ++unsigned long nr_running_ve(struct ve_struct *ve) ++{ ++ int i; ++ long sum = 0; ++ cpumask_t ve_cpus; ++ ++ ve_cpu_online_map(ve, &ve_cpus); ++ for_each_cpu_mask(i, ve_cpus) ++ sum += VE_CPU_STATS(ve, i)->nr_running; ++ return (unsigned long)(sum < 0 ? 0 : sum); ++} ++EXPORT_SYMBOL(nr_running_ve); ++ ++unsigned long nr_uninterruptible_ve(struct ve_struct *ve) ++{ ++ int i; ++ long sum = 0; ++ cpumask_t ve_cpus; ++ ++ sum = 0; ++ ve_cpu_online_map(ve, &ve_cpus); ++ for_each_cpu_mask(i, ve_cpus) ++ sum += VE_CPU_STATS(ve, i)->nr_unint; ++ return (unsigned long)(sum < 0 ? 0 : sum); ++} ++EXPORT_SYMBOL(nr_uninterruptible_ve); ++ ++unsigned long nr_iowait_ve(struct ve_struct *ve) ++{ ++ int i; ++ long sum = 0; ++ cpumask_t ve_cpus; ++ ++ ve_cpu_online_map(ve, &ve_cpus); ++ for_each_cpu_mask(i, ve_cpus) ++ sum += VE_CPU_STATS(ve, i)->nr_iowait; ++ return (unsigned long)(sum < 0 ? 0 : sum); ++} ++EXPORT_SYMBOL(nr_iowait_ve); ++#endif ++ + /* + * Update rq->cpu_load[] statistics. This function is usually called every + * scheduler tick (TICK_NSEC). +@@ -2118,6 +2449,16 @@ + } + } + ++#ifdef CONFIG_VE ++#define update_ve_cpu_time(p, time, tick) \ ++ do { \ ++ VE_CPU_STATS((p)->ve_task_info.owner_env, \ ++ task_cpu(p))->time += tick; \ ++ } while (0) ++#else ++#define update_ve_cpu_time(p, time, tick) do { } while (0) ++#endif ++ + #ifdef CONFIG_SMP + + /* +@@ -2241,8 +2582,15 @@ + static void pull_task(struct rq *src_rq, struct task_struct *p, + struct rq *this_rq, int this_cpu) + { ++ struct ve_struct *ve; ++ cycles_t cycles = get_cycles(); ++ ++ ve = VE_TASK_INFO(p)->owner_env; ++ + deactivate_task(src_rq, p, 0); ++ ve_nr_running_dec(ve, task_cpu(p), cycles); + set_task_cpu(p, this_cpu); ++ ve_nr_running_inc(ve, task_cpu(p), cycles); + activate_task(this_rq, p, 0); + /* + * Note that idle threads have a prio of MAX_PRIO, for this test +@@ -3408,10 +3756,13 @@ + + /* Add user time to cpustat. */ + tmp = cputime_to_cputime64(cputime); +- if (TASK_NICE(p) > 0) ++ if (TASK_NICE(p) > 0) { + cpustat->nice = cputime64_add(cpustat->nice, tmp); +- else ++ update_ve_cpu_time(p, nice, tmp); ++ } else { + cpustat->user = cputime64_add(cpustat->user, tmp); ++ update_ve_cpu_time(p, user, tmp); ++ } + } + + /* +@@ -3463,6 +3814,7 @@ + + /* Add system time to cpustat. */ + tmp = cputime_to_cputime64(cputime); ++ update_ve_cpu_time(p, system, tmp); + if (hardirq_count() - hardirq_offset) + cpustat->irq = cputime64_add(cpustat->irq, tmp); + else if (softirq_count()) +@@ -3706,13 +4058,33 @@ + sched_info_switch(prev, next); + + if (likely(prev != next)) { ++ cycles_t cycles = get_cycles(); ++ + rq->nr_switches++; + rq->curr = next; + ++*switch_count; + ++#ifdef CONFIG_VE ++ prev->ve_task_info.sleep_stamp = cycles; ++ if (prev->state == TASK_RUNNING && prev != this_rq()->idle) ++ write_wakeup_stamp(prev, cycles); ++ update_sched_lat(next, cycles); ++ ++ /* because next & prev are protected with ++ * runqueue lock we may not worry about ++ * wakeup_stamp and sched_time protection ++ * (same thing in 'else' branch below) ++ */ ++ update_ve_task_info(prev, cycles); ++ next->ve_task_info.sched_time = cycles; ++ write_wakeup_stamp(next, 0); ++#endif ++ + context_switch(rq, prev, next); /* unlocks the rq */ +- } else ++ } else { ++ update_ve_task_info(prev, get_cycles()); + spin_unlock_irq(&rq->lock); ++ } + + if (unlikely(reacquire_kernel_lock(current) < 0)) { + cpu = smp_processor_id(); +@@ -4327,7 +4699,7 @@ + /* + * Allow unprivileged RT tasks to decrease priority: + */ +- if (!capable(CAP_SYS_NICE)) { ++ if (!capable(CAP_SYS_ADMIN)) { + if (rt_policy(policy)) { + unsigned long rlim_rtprio; + +@@ -4802,10 +5174,15 @@ + void __sched io_schedule(void) + { + struct rq *rq = &__raw_get_cpu_var(runqueues); ++#ifdef CONFIG_VE ++ struct ve_struct *ve = current->ve_task_info.owner_env; ++#endif + + delayacct_blkio_start(); + atomic_inc(&rq->nr_iowait); ++ ve_nr_iowait_inc(ve, task_cpu(current)); + schedule(); ++ ve_nr_iowait_dec(ve, task_cpu(current)); + atomic_dec(&rq->nr_iowait); + delayacct_blkio_end(); + } +@@ -4815,10 +5192,15 @@ + { + struct rq *rq = &__raw_get_cpu_var(runqueues); + long ret; ++#ifdef CONFIG_VE ++ struct ve_struct *ve = current->ve_task_info.owner_env; ++#endif + + delayacct_blkio_start(); + atomic_inc(&rq->nr_iowait); ++ ve_nr_iowait_inc(ve, task_cpu(current)); + ret = schedule_timeout(timeout); ++ ve_nr_iowait_dec(ve, task_cpu(current)); + atomic_dec(&rq->nr_iowait); + delayacct_blkio_end(); + return ret; +@@ -4939,17 +5321,7 @@ + state = p->state ? __ffs(p->state) + 1 : 0; + printk(KERN_INFO "%-13.13s %c", p->comm, + state < sizeof(stat_nam) - 1 ? stat_nam[state] : '?'); +-#if BITS_PER_LONG == 32 +- if (state == TASK_RUNNING) +- printk(KERN_CONT " running "); +- else +- printk(KERN_CONT " %08lx ", thread_saved_pc(p)); +-#else +- if (state == TASK_RUNNING) +- printk(KERN_CONT " running task "); +- else +- printk(KERN_CONT " %016lx ", thread_saved_pc(p)); +-#endif ++ printk(KERN_CONT " %p ", p); + #ifdef CONFIG_DEBUG_STACK_USAGE + { + unsigned long *n = end_of_stack(p); +@@ -4971,13 +5343,13 @@ + + #if BITS_PER_LONG == 32 + printk(KERN_INFO +- " task PC stack pid father\n"); ++ " task taskaddr stack pid father\n"); + #else + printk(KERN_INFO +- " task PC stack pid father\n"); ++ " task taskaddr stack pid father\n"); + #endif + read_lock(&tasklist_lock); +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + /* + * reset the NMI-timeout, listing all files on a slow + * console might take alot of time: +@@ -4985,7 +5357,7 @@ + touch_nmi_watchdog(); + if (!state_filter || (p->state & state_filter)) + show_task(p); +- } while_each_thread(g, p); ++ } while_each_thread_all(g, p); + + touch_all_softlockup_watchdogs(); + +@@ -5333,13 +5705,13 @@ + + read_lock(&tasklist_lock); + +- do_each_thread(t, p) { ++ do_each_thread_all(t, p) { + if (p == current) + continue; + + if (task_cpu(p) == src_cpu) + move_task_off_dead_cpu(src_cpu, p); +- } while_each_thread(t, p); ++ } while_each_thread_all(t, p); + + read_unlock(&tasklist_lock); + } +@@ -6931,7 +7303,7 @@ + struct rq *rq; + + read_lock_irq(&tasklist_lock); +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + /* + * Only normalize user tasks: + */ +@@ -6963,7 +7335,7 @@ + + __task_rq_unlock(rq); + spin_unlock_irqrestore(&p->pi_lock, flags); +- } while_each_thread(g, p); ++ } while_each_thread_all(g, p); + + read_unlock_irq(&tasklist_lock); + } +Index: kernel/kernel/sched_debug.c +=================================================================== +--- kernel.orig/kernel/sched_debug.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/sched_debug.c 2008-11-24 15:47:46.000000000 +0100 +@@ -91,12 +91,12 @@ + + read_lock_irqsave(&tasklist_lock, flags); + +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + if (!p->se.on_rq || task_cpu(p) != rq_cpu) + continue; + + print_task(m, rq, p); +- } while_each_thread(g, p); ++ } while_each_thread_all(g, p); + + read_unlock_irqrestore(&tasklist_lock, flags); + } +Index: kernel/kernel/signal.c +=================================================================== +--- kernel.orig/kernel/signal.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/signal.c 2008-11-24 15:47:46.000000000 +0100 +@@ -31,15 +31,34 @@ + #include + #include + #include ++#include + #include "audit.h" /* audit_signal_info() */ + + /* + * SLAB caches for signal bits. + */ + +-static struct kmem_cache *sigqueue_cachep; ++struct kmem_cache *sigqueue_cachep; ++EXPORT_SYMBOL(sigqueue_cachep); + + ++static int sig_ve_ignored(int sig, struct siginfo *info, struct task_struct *t) ++{ ++ struct ve_struct *ve; ++ ++ /* always allow signals from the kernel */ ++ if (info == SEND_SIG_FORCED || ++ (!is_si_special(info) && SI_FROMKERNEL(info))) ++ return 0; ++ ++ ve = current->ve_task_info.owner_env; ++ if (ve->ve_ns->pid_ns->child_reaper != t) ++ return 0; ++ if (ve_is_super(get_exec_env())) ++ return 0; ++ return !sig_user_defined(t, sig) || sig_kernel_only(sig); ++} ++ + static int sig_ignored(struct task_struct *t, int sig) + { + void __user * handler; +@@ -96,7 +115,7 @@ + + #define PENDING(p,b) has_pending_signals(&(p)->signal, (b)) + +-static int recalc_sigpending_tsk(struct task_struct *t) ++int recalc_sigpending_tsk(struct task_struct *t) + { + if (t->signal->group_stop_count > 0 || + PENDING(&t->pending, &t->blocked) || +@@ -121,6 +140,7 @@ + if (recalc_sigpending_tsk(t)) + signal_wake_up(t, 0); + } ++EXPORT_SYMBOL_GPL(recalc_sigpending_tsk); + + void recalc_sigpending(void) + { +@@ -179,8 +199,13 @@ + atomic_inc(&user->sigpending); + if (override_rlimit || + atomic_read(&user->sigpending) <= +- t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur) ++ t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur) { + q = kmem_cache_alloc(sigqueue_cachep, flags); ++ if (q && ub_siginfo_charge(q, get_task_ub(t))) { ++ kmem_cache_free(sigqueue_cachep, q); ++ q = NULL; ++ } ++ } + if (unlikely(q == NULL)) { + atomic_dec(&user->sigpending); + } else { +@@ -197,6 +222,7 @@ + return; + atomic_dec(&q->user->sigpending); + free_uid(q->user); ++ ub_siginfo_uncharge(q); + kmem_cache_free(sigqueue_cachep, q); + } + +@@ -345,7 +371,18 @@ + static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, + siginfo_t *info) + { +- int sig = next_signal(pending, mask); ++ int sig = 0; ++ ++ /* SIGKILL must have priority, otherwise it is quite easy ++ * to create an unkillable process, sending sig < SIGKILL ++ * to self */ ++ if (unlikely(sigismember(&pending->signal, SIGKILL))) { ++ if (!sigismember(mask, SIGKILL)) ++ sig = SIGKILL; ++ } ++ ++ if (likely(!sig)) ++ sig = next_signal(pending, mask); + + if (sig) { + if (current->notifier) { +@@ -468,6 +505,7 @@ + if (!wake_up_state(t, mask)) + kick_process(t); + } ++EXPORT_SYMBOL_GPL(signal_wake_up); + + /* + * Remove signals in mask from the pending set and queue. +@@ -908,7 +946,7 @@ + do { + sigaddset(&t->pending.signal, SIGKILL); + signal_wake_up(t, 1); +- } while_each_thread(p, t); ++ } while_each_thread_all(p, t); + return; + } + +@@ -930,7 +968,7 @@ + do { + p->signal->group_stop_count++; + signal_wake_up(t, t == p); +- } while_each_thread(p, t); ++ } while_each_thread_all(p, t); + return; + } + +@@ -1025,7 +1063,8 @@ + if (!ret && sig) { + ret = -ESRCH; + if (lock_task_sighand(p, &flags)) { +- ret = __group_send_sig_info(sig, info, p); ++ ret = sig_ve_ignored(sig, info, p) ? 0 : ++ __group_send_sig_info(sig, info, p); + unlock_task_sighand(p, &flags); + } + } +@@ -1149,7 +1188,7 @@ + struct task_struct * p; + + read_lock(&tasklist_lock); +- for_each_process(p) { ++ for_each_process_ve(p) { + if (task_pid_vnr(p) > 1 && + !same_thread_group(p, current)) { + int err = group_send_sig_info(sig, info, p); +@@ -1446,6 +1485,14 @@ + BUG_ON(!tsk->ptrace && + (tsk->group_leader != tsk || !thread_group_empty(tsk))); + ++#ifdef CONFIG_VE ++ /* Allow to send only SIGCHLD from VE */ ++ if (sig != SIGCHLD && ++ tsk->ve_task_info.owner_env != ++ tsk->parent->ve_task_info.owner_env) ++ sig = SIGCHLD; ++#endif ++ + info.si_signo = sig; + info.si_errno = 0; + /* +@@ -1684,7 +1731,9 @@ + } + + do { ++ set_stop_state(current); + schedule(); ++ clear_stop_state(current); + } while (try_to_freeze()); + /* + * Now we don't run again until continued. +@@ -1793,8 +1842,6 @@ + sigset_t *mask = ¤t->blocked; + int signr = 0; + +- try_to_freeze(); +- + relock: + spin_lock_irq(¤t->sighand->siglock); + for (;;) { +@@ -2246,8 +2293,10 @@ + */ + if (!error && sig && p->sighand) { + spin_lock_irq(&p->sighand->siglock); +- handle_stop_signal(sig, p); +- error = specific_send_sig_info(sig, &info, p); ++ if (!sig_ve_ignored(sig, &info, p)) { ++ handle_stop_signal(sig, p); ++ error = specific_send_sig_info(sig, &info, p); ++ } + spin_unlock_irq(&p->sighand->siglock); + } + } +@@ -2604,5 +2653,5 @@ + + void __init signals_init(void) + { +- sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC); ++ sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC|SLAB_UBC); + } +Index: kernel/kernel/softirq.c +=================================================================== +--- kernel.orig/kernel/softirq.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/softirq.c 2008-11-24 15:47:46.000000000 +0100 +@@ -20,6 +20,8 @@ + #include + #include + ++#include ++ + #include + /* + - No shared variables, all the data are CPU local. +@@ -207,10 +209,14 @@ + + asmlinkage void __do_softirq(void) + { ++ struct user_beancounter *ub; + struct softirq_action *h; + __u32 pending; + int max_restart = MAX_SOFTIRQ_RESTART; + int cpu; ++ struct ve_struct *envid; ++ ++ envid = set_exec_env(get_ve0()); + + pending = local_softirq_pending(); + account_system_vtime(current); +@@ -227,6 +233,7 @@ + + h = softirq_vec; + ++ ub = set_exec_ub(get_ub0()); + do { + if (pending & 1) { + h->action(h); +@@ -235,6 +242,7 @@ + h++; + pending >>= 1; + } while (pending); ++ (void)set_exec_ub(ub); + + local_irq_disable(); + +@@ -248,6 +256,7 @@ + trace_softirq_exit(); + + account_system_vtime(current); ++ (void)set_exec_env(envid); + _local_bh_enable(); + } + +@@ -298,6 +307,7 @@ + { + account_system_vtime(current); + trace_hardirq_exit(); ++ restore_context(); + sub_preempt_count(IRQ_EXIT_OFFSET); + if (!in_interrupt() && local_softirq_pending()) + invoke_softirq(); +Index: kernel/kernel/stop_machine.c +=================================================================== +--- kernel.orig/kernel/stop_machine.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/stop_machine.c 2008-11-24 15:47:46.000000000 +0100 +@@ -9,7 +9,7 @@ + #include + #include + #include +- ++#include + #include + #include + #include +@@ -63,7 +63,7 @@ + /* Yield in first stage: migration threads need to + * help our sisters onto their CPUs. */ + if (!prepared && !irqs_disabled) +- yield(); ++ msleep(10); + else + cpu_relax(); + } +@@ -109,7 +109,7 @@ + + /* Wait for them all to come to life. */ + while (atomic_read(&stopmachine_thread_ack) != stopmachine_num_threads) +- yield(); ++ msleep(10); + + /* If some failed, kill them all. */ + if (ret < 0) { +Index: kernel/kernel/sys.c +=================================================================== +--- kernel.orig/kernel/sys.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/sys.c 2008-11-24 15:47:46.000000000 +0100 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -33,6 +34,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -106,6 +108,102 @@ + + void (*pm_power_off_prepare)(void); + ++DECLARE_MUTEX(virtinfo_sem); ++EXPORT_SYMBOL(virtinfo_sem); ++static struct vnotifier_block *virtinfo_chain[VIRT_TYPES]; ++ ++void __virtinfo_notifier_register(int type, struct vnotifier_block *nb) ++{ ++ struct vnotifier_block **p; ++ ++ for (p = &virtinfo_chain[type]; ++ *p != NULL && nb->priority < (*p)->priority; ++ p = &(*p)->next); ++ nb->next = *p; ++ smp_wmb(); ++ *p = nb; ++} ++ ++EXPORT_SYMBOL(__virtinfo_notifier_register); ++ ++void virtinfo_notifier_register(int type, struct vnotifier_block *nb) ++{ ++ down(&virtinfo_sem); ++ __virtinfo_notifier_register(type, nb); ++ up(&virtinfo_sem); ++} ++ ++EXPORT_SYMBOL(virtinfo_notifier_register); ++ ++struct virtinfo_cnt_struct { ++ volatile unsigned long exit[NR_CPUS]; ++ volatile unsigned long entry; ++}; ++static DEFINE_PER_CPU(struct virtinfo_cnt_struct, virtcnt); ++ ++void virtinfo_notifier_unregister(int type, struct vnotifier_block *nb) ++{ ++ struct vnotifier_block **p; ++ int entry_cpu, exit_cpu; ++ unsigned long cnt, ent; ++ ++ down(&virtinfo_sem); ++ for (p = &virtinfo_chain[type]; *p != nb; p = &(*p)->next); ++ *p = nb->next; ++ smp_mb(); ++ ++ for_each_cpu_mask(entry_cpu, cpu_possible_map) { ++ while (1) { ++ cnt = 0; ++ for_each_cpu_mask(exit_cpu, cpu_possible_map) ++ cnt += ++ per_cpu(virtcnt, entry_cpu).exit[exit_cpu]; ++ smp_rmb(); ++ ent = per_cpu(virtcnt, entry_cpu).entry; ++ if (cnt == ent) ++ break; ++ __set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_timeout(HZ / 100); ++ } ++ } ++ up(&virtinfo_sem); ++} ++ ++EXPORT_SYMBOL(virtinfo_notifier_unregister); ++ ++int virtinfo_notifier_call(int type, unsigned long n, void *data) ++{ ++ int ret; ++ int entry_cpu, exit_cpu; ++ struct vnotifier_block *nb; ++ ++ entry_cpu = get_cpu(); ++ per_cpu(virtcnt, entry_cpu).entry++; ++ smp_wmb(); ++ put_cpu(); ++ ++ nb = virtinfo_chain[type]; ++ ret = NOTIFY_DONE; ++ while (nb) ++ { ++ ret = nb->notifier_call(nb, n, data, ret); ++ if(ret & NOTIFY_STOP_MASK) { ++ ret &= ~NOTIFY_STOP_MASK; ++ break; ++ } ++ nb = nb->next; ++ } ++ ++ exit_cpu = get_cpu(); ++ smp_wmb(); ++ per_cpu(virtcnt, entry_cpu).exit[exit_cpu]++; ++ put_cpu(); ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL(virtinfo_notifier_call); ++ + static int set_one_prio(struct task_struct *p, int niceval, int error) + { + int no_nice; +@@ -165,7 +263,7 @@ + pgrp = task_pgrp(current); + do_each_pid_task(pgrp, PIDTYPE_PGID, p) { + error = set_one_prio(p, niceval, error); +- } while_each_pid_task(pgrp, PIDTYPE_PGID, p); ++ } while_each_pid_task(who, PIDTYPE_PGID, p); + break; + case PRIO_USER: + user = current->user; +@@ -175,10 +273,10 @@ + if ((who != current->uid) && !(user = find_user(who))) + goto out_unlock; /* No processes for this user */ + +- do_each_thread(g, p) ++ do_each_thread_ve(g, p) + if (p->uid == who) + error = set_one_prio(p, niceval, error); +- while_each_thread(g, p); ++ while_each_thread_ve(g, p); + if (who != current->uid) + free_uid(user); /* For find_user() */ + break; +@@ -227,7 +325,7 @@ + niceval = 20 - task_nice(p); + if (niceval > retval) + retval = niceval; +- } while_each_pid_task(pgrp, PIDTYPE_PGID, p); ++ } while_each_pid_task(who, PIDTYPE_PGID, p); + break; + case PRIO_USER: + user = current->user; +@@ -237,13 +335,13 @@ + if ((who != current->uid) && !(user = find_user(who))) + goto out_unlock; /* No processes for this user */ + +- do_each_thread(g, p) ++ do_each_thread_ve(g, p) + if (p->uid == who) { + niceval = 20 - task_nice(p); + if (niceval > retval) + retval = niceval; + } +- while_each_thread(g, p); ++ while_each_thread_ve(g, p); + if (who != current->uid) + free_uid(user); /* for find_user() */ + break; +@@ -377,6 +475,25 @@ + magic2 != LINUX_REBOOT_MAGIC2C)) + return -EINVAL; + ++#ifdef CONFIG_VE ++ if (!ve_is_super(get_exec_env())) ++ switch (cmd) { ++ case LINUX_REBOOT_CMD_RESTART: ++ case LINUX_REBOOT_CMD_HALT: ++ case LINUX_REBOOT_CMD_POWER_OFF: ++ case LINUX_REBOOT_CMD_RESTART2: ++ force_sig(SIGKILL, ++ get_exec_env()->ve_ns->pid_ns->child_reaper); ++ ++ case LINUX_REBOOT_CMD_CAD_ON: ++ case LINUX_REBOOT_CMD_CAD_OFF: ++ return 0; ++ ++ default: ++ return -EINVAL; ++ } ++#endif ++ + /* Instead of trying to make the power_off code look like + * halt when pm_power_off is not set do it the easy way. + */ +@@ -558,7 +675,7 @@ + return 0; + } + +-static int set_user(uid_t new_ruid, int dumpclear) ++int set_user(uid_t new_ruid, int dumpclear) + { + struct user_struct *new_user; + +@@ -582,6 +699,7 @@ + current->uid = new_ruid; + return 0; + } ++EXPORT_SYMBOL(set_user); + + /* + * Unprivileged users may change the real uid to the effective uid +@@ -862,8 +980,27 @@ + return old_fsgid; + } + ++#ifdef CONFIG_VE ++unsigned long long ve_relative_clock(struct timespec * ts) ++{ ++ unsigned long long offset = 0; ++ ++ if (ts->tv_sec > get_exec_env()->start_timespec.tv_sec || ++ (ts->tv_sec == get_exec_env()->start_timespec.tv_sec && ++ ts->tv_nsec >= get_exec_env()->start_timespec.tv_nsec)) ++ offset = (unsigned long long)(ts->tv_sec - ++ get_exec_env()->start_timespec.tv_sec) * NSEC_PER_SEC ++ + ts->tv_nsec - get_exec_env()->start_timespec.tv_nsec; ++ return nsec_to_clock_t(offset); ++} ++#endif ++ + asmlinkage long sys_times(struct tms __user * tbuf) + { ++#ifdef CONFIG_VE ++ struct timespec now; ++#endif ++ + /* + * In the SMP world we might just be unlucky and have one of + * the times increment as we use it. Since the value is an +@@ -897,7 +1034,13 @@ + if (copy_to_user(tbuf, &tmp, sizeof(struct tms))) + return -EFAULT; + } ++#ifndef CONFIG_VE + return (long) jiffies_64_to_clock_t(get_jiffies_64()); ++#else ++ /* Compare to calculation in fs/proc/array.c */ ++ do_posix_clock_monotonic_gettime(&now); ++ return ve_relative_clock(&now); ++#endif + } + + /* +@@ -1074,6 +1217,7 @@ + + spin_lock(&group_leader->sighand->siglock); + group_leader->signal->tty = NULL; ++ group_leader->signal->tty_old_pgrp = 0; + spin_unlock(&group_leader->sighand->siglock); + + err = task_pgrp_vnr(group_leader); +@@ -1358,7 +1502,7 @@ + int errno; + char tmp[__NEW_UTS_LEN]; + +- if (!capable(CAP_SYS_ADMIN)) ++ if (!capable(CAP_VE_SYS_ADMIN)) + return -EPERM; + if (len < 0 || len > __NEW_UTS_LEN) + return -EINVAL; +@@ -1403,7 +1547,7 @@ + int errno; + char tmp[__NEW_UTS_LEN]; + +- if (!capable(CAP_SYS_ADMIN)) ++ if (!capable(CAP_VE_SYS_ADMIN)) + return -EPERM; + if (len < 0 || len > __NEW_UTS_LEN) + return -EINVAL; +Index: kernel/kernel/sys_ni.c +=================================================================== +--- kernel.orig/kernel/sys_ni.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/sys_ni.c 2008-11-24 15:47:46.000000000 +0100 +@@ -157,3 +157,7 @@ + cond_syscall(compat_sys_signalfd); + cond_syscall(compat_sys_timerfd); + cond_syscall(sys_eventfd); ++cond_syscall(sys_getluid); ++cond_syscall(sys_setluid); ++cond_syscall(sys_setublimit); ++cond_syscall(sys_ubstat); +Index: kernel/kernel/sysctl.c +=================================================================== +--- kernel.orig/kernel/sysctl.c 2008-11-24 14:14:49.000000000 +0100 ++++ kernel/kernel/sysctl.c 2008-11-24 15:47:46.000000000 +0100 +@@ -25,6 +25,9 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + #include +@@ -60,6 +63,8 @@ + static int deprecated_sysctl_warning(struct __sysctl_args *args); + + #if defined(CONFIG_SYSCTL) ++extern int gr_handle_sysctl_mod(const char *dirname, const char *name, ++ const int op); + + /* External variables not in a header file. */ + extern int C_A_D; +@@ -71,6 +76,7 @@ + extern int max_threads; + extern int core_uses_pid; + extern int suid_dumpable; ++extern int sysctl_at_vsyscall; + extern char core_pattern[]; + extern int pid_max; + extern int min_free_kbytes; +@@ -82,6 +88,7 @@ + extern int compat_log; + extern int maps_protect; + extern int sysctl_stat_interval; ++extern int ve_area_access_check; /* fs/namei.c */ + extern int audit_argv_kb; + extern int latencytop_enabled; + +@@ -105,6 +112,8 @@ + + static int ngroups_max = NGROUPS_MAX; + ++int ve_allow_kthreads = 1; ++EXPORT_SYMBOL(ve_allow_kthreads); + #ifdef CONFIG_KMOD + extern char modprobe_path[]; + #endif +@@ -118,6 +127,8 @@ + extern int scons_pwroff; + #endif + ++extern int alloc_fail_warn; ++ + #ifdef __hppa__ + extern int pwrsw_enabled; + extern int unaligned_enabled; +@@ -132,6 +143,7 @@ + #endif + + extern int sysctl_hz_timer; ++int decode_call_traces = 1; + + #ifdef CONFIG_BSD_PROCESS_ACCT + extern int acct_parm[]; +@@ -140,6 +152,10 @@ + #ifdef CONFIG_IA64 + extern int no_unaligned_warning; + #endif ++#ifdef CONFIG_VE ++int glob_ve_meminfo = 0; ++EXPORT_SYMBOL(glob_ve_meminfo); ++#endif + + #ifdef CONFIG_RT_MUTEXES + extern int max_lock_depth; +@@ -175,6 +191,7 @@ + #ifdef HAVE_ARCH_PICK_MMAP_LAYOUT + int sysctl_legacy_va_layout; + #endif ++extern ctl_table grsecurity_table[]; + + extern int prove_locking; + extern int lock_stat; +@@ -397,7 +414,7 @@ + #ifdef CONFIG_SECURITY_CAPABILITIES + { + .procname = "cap-bound", +- .data = &cap_bset, ++ .data = NULL, + .maxlen = sizeof(kernel_cap_t), + .mode = 0600, + .proc_handler = &proc_dointvec_bset, +@@ -448,6 +465,20 @@ + .proc_handler = &proc_dointvec, + }, + #endif ++ { ++ .procname = "silence-level", ++ .data = &console_silence_loglevel, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, ++ { ++ .procname = "alloc_fail_warn", ++ .data = &alloc_fail_warn, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, + #ifdef __hppa__ + { + .ctl_name = KERN_HPPA_PWRSW, +@@ -620,6 +651,15 @@ + .extra1 = &pid_max_min, + .extra2 = &pid_max_max, + }, ++#ifdef CONFIG_VE ++ { ++ .procname = "ve_meminfo", ++ .data = &glob_ve_meminfo, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++#endif + { + .ctl_name = KERN_PANIC_ON_OOPS, + .procname = "panic_on_oops", +@@ -795,6 +835,14 @@ + .proc_handler = &proc_dostring, + .strategy = &sysctl_string, + }, ++#ifdef CONFIG_GRKERNSEC_SYSCTL ++ { ++ .ctl_name = KERN_GRSECURITY, ++ .procname = "grsecurity", ++ .mode = 0500, ++ .child = grsecurity_table, ++ }, ++#endif + /* + * NOTE: do not add new entries to this table unless you have read + * Documentation/sysctl/ctl_unnumbered.txt +@@ -1261,6 +1309,20 @@ + .child = binfmt_misc_table, + }, + #endif ++ { ++ .procname = "vsyscall", ++ .data = &sysctl_at_vsyscall, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++ { ++ .procname = "odirect_enable", ++ .data = &odirect_enable, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, + /* + * NOTE: do not add new entries to this table unless you have read + * Documentation/sysctl/ctl_unnumbered.txt +@@ -1269,6 +1331,13 @@ + }; + + static struct ctl_table debug_table[] = { ++ { ++ .procname = "decode_call_traces", ++ .data = &decode_call_traces, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, + #if defined(CONFIG_X86) || defined(CONFIG_PPC) + { + .ctl_name = CTL_UNNUMBERED, +@@ -1340,14 +1409,26 @@ + { + struct ctl_table_header *head; + struct list_head *tmp; ++ struct ve_struct *ve; ++ ++ ve = get_exec_env(); + spin_lock(&sysctl_lock); + if (prev) { + tmp = &prev->ctl_entry; + unuse_table(prev); + goto next; + } ++#ifdef CONFIG_VE ++ tmp = ve->sysctl_lh.next; ++#else + tmp = &root_table_header.ctl_entry; ++#endif + for (;;) { ++#ifdef CONFIG_VE ++ if (tmp == &ve->sysctl_lh) ++ /* second pass over global variables */ ++ tmp = &root_table_header.ctl_entry; ++#endif + head = list_entry(tmp, struct ctl_table_header, ctl_entry); + + if (!use_table(head)) +@@ -1457,10 +1538,17 @@ + int sysctl_perm(struct ctl_table *table, int op) + { + int error; ++ int mode = table->mode; ++ ++ if (table->procname && table->parent && gr_handle_sysctl_mod(table->parent->procname, table->procname, op)) ++ return -EACCES; + error = security_sysctl(table, op); + if (error) + return error; +- return test_perm(table->mode, op); ++ if (!ve_accessible(table->owner_env, get_exec_env()) && ++ !table->virt_handler) ++ mode &= ~0222; /* disable write access */ ++ return test_perm(mode, op); + } + + #ifdef CONFIG_SYSCTL_SYSCALL +@@ -1497,6 +1585,36 @@ + return -ENOTDIR; + } + ++int __do_sysctl_strategy (void *data, ctl_table *table, ++ int __user *name, int nlen, ++ void __user *oldval, size_t __user *oldlenp, ++ void __user *newval, size_t newlen) { ++ size_t len; ++ ++ if (oldval && oldlenp) { ++ if (get_user(len, oldlenp)) ++ return -EFAULT; ++ if (len) { ++ if (len > table->maxlen) ++ len = table->maxlen; ++ if (copy_to_user(oldval, data, len)) ++ return -EFAULT; ++ if (put_user(len, oldlenp)) ++ return -EFAULT; ++ } ++ } ++ ++ if (newval && newlen) { ++ len = newlen; ++ if (len > table->maxlen) ++ len = table->maxlen; ++ if (copy_from_user(data, newval, len)) ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ + /* Perform the actual read/write of a sysctl table entry. */ + int do_sysctl_strategy (struct ctl_table *table, + int __user *name, int nlen, +@@ -1620,9 +1738,11 @@ + * This routine returns %NULL on a failure to register, and a pointer + * to the table header on success. + */ +-struct ctl_table_header *register_sysctl_table(struct ctl_table * table) ++static struct ctl_table_header *__register_sysctl_table(struct list_head *lh, ++ struct ctl_table * table) + { + struct ctl_table_header *tmp; ++ + tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL); + if (!tmp) + return NULL; +@@ -1636,11 +1756,76 @@ + return NULL; + } + spin_lock(&sysctl_lock); +- list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); ++ list_add_tail(&tmp->ctl_entry, lh); + spin_unlock(&sysctl_lock); + return tmp; + } + ++struct ctl_table_header *register_sysctl_table(struct ctl_table * table) ++{ ++ struct list_head *lh; ++ ++#ifdef CONFIG_VE ++ lh = &get_exec_env()->sysctl_lh; ++#else ++ lh = &root_table_header.ctl_entry; ++#endif ++ return __register_sysctl_table(lh, table); ++} ++ ++#ifdef CONFIG_VE ++struct ctl_table_header *register_glob_sysctl_table(struct ctl_table *table) ++{ ++ return __register_sysctl_table(&root_table_header.ctl_entry, table); ++} ++EXPORT_SYMBOL(register_glob_sysctl_table); ++#endif ++ ++void free_sysctl_clone(ctl_table *clone) ++{ ++ int i; ++ ++ for (i = 0; clone[i].ctl_name != 0; i++) ++ if (clone[i].child != NULL) ++ free_sysctl_clone(clone[i].child); ++ ++ kfree(clone); ++} ++ ++ctl_table *clone_sysctl_template(ctl_table *tmpl) ++{ ++ int i, nr; ++ ctl_table *clone; ++ ++ nr = 0; ++ while (tmpl[nr].ctl_name != 0 || tmpl[nr].procname) ++ nr++; ++ nr++; ++ ++ clone = kmemdup(tmpl, nr * sizeof(ctl_table), GFP_KERNEL); ++ if (clone == NULL) ++ return NULL; ++ ++ for (i = 0; i < nr; i++) { ++ clone[i].owner_env = get_exec_env(); ++ if (tmpl[i].child == NULL) ++ continue; ++ ++ clone[i].child = clone_sysctl_template(tmpl[i].child); ++ if (clone[i].child == NULL) ++ goto unroll; ++ } ++ return clone; ++ ++unroll: ++ for (i--; i >= 0; i--) ++ if (clone[i].child != NULL) ++ free_sysctl_clone(clone[i].child); ++ ++ kfree(clone); ++ return NULL; ++} ++ + /** + * unregister_sysctl_table - unregister a sysctl table hierarchy + * @header: the header returned from register_sysctl_table +@@ -1671,6 +1856,14 @@ + { + } + ++ctl_table * clone_sysctl_template(ctl_table *tmpl, int nr) ++{ ++ return NULL; ++} ++ ++void free_sysctl_clone(ctl_table *tmpl) ++{ ++} + #endif /* CONFIG_SYSCTL */ + + /* +@@ -1962,13 +2155,19 @@ + { + int op; + +- if (write && !capable(CAP_SYS_MODULE)) { ++ struct ve_struct *ve; ++ ++ ve = get_exec_env(); ++ ++ /* For VE's root writing to VE's cap-bound is prohibited */ ++ if ((ve_is_super(ve) && write && !capable(CAP_SYS_MODULE)) || ++ (!ve_is_super(ve) && (!capable(CAP_VE_ADMIN) || write))) { + return -EPERM; + } + + op = is_global_init(current) ? OP_SET : OP_AND; +- return do_proc_dointvec(table,write,filp,buffer,lenp,ppos, +- do_proc_dointvec_bset_conv,&op); ++ return __do_proc_dointvec(&cap_bset, table, write, filp, ++ buffer, lenp, ppos, do_proc_dointvec_bset_conv, &op); + } + #endif /* def CONFIG_SECURITY_CAPABILITIES */ + +@@ -2731,3 +2930,5 @@ + EXPORT_SYMBOL(sysctl_string); + EXPORT_SYMBOL(sysctl_data); + EXPORT_SYMBOL(unregister_sysctl_table); ++EXPORT_SYMBOL(clone_sysctl_template); ++EXPORT_SYMBOL(free_sysctl_clone); +Index: kernel/kernel/sysctl_check.c +=================================================================== +--- kernel.orig/kernel/sysctl_check.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/sysctl_check.c 2008-11-24 15:47:46.000000000 +0100 +@@ -1459,6 +1459,7 @@ + int sysctl_check_table(struct ctl_table *table) + { + int error = 0; ++ return 0; + for (; table->ctl_name || table->procname; table++) { + const char *fail = NULL; + +Index: kernel/kernel/taskstats.c +=================================================================== +--- kernel.orig/kernel/taskstats.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/taskstats.c 2008-11-24 15:47:46.000000000 +0100 +@@ -183,7 +183,7 @@ + + if (!tsk) { + rcu_read_lock(); +- tsk = find_task_by_pid(pid); ++ tsk = find_task_by_vpid(pid); + if (tsk) + get_task_struct(tsk); + rcu_read_unlock(); +@@ -230,7 +230,7 @@ + */ + rcu_read_lock(); + if (!first) +- first = find_task_by_pid(tgid); ++ first = find_task_by_vpid(tgid); + + if (!first || !lock_task_sighand(first, &flags)) + goto out; +@@ -254,7 +254,7 @@ + + stats->nvcsw += tsk->nvcsw; + stats->nivcsw += tsk->nivcsw; +- } while_each_thread(first, tsk); ++ } while_each_thread_all(first, tsk); + + unlock_task_sighand(first, &flags); + rc = 0; +Index: kernel/kernel/time.c +=================================================================== +--- kernel.orig/kernel/time.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/time.c 2008-11-24 15:47:46.000000000 +0100 +@@ -577,12 +577,14 @@ + unsigned long clock_t_to_jiffies(unsigned long x) + { + #if (HZ % USER_HZ)==0 ++ WARN_ON((long)x < 0); + if (x >= ~0UL / (HZ / USER_HZ)) + return ~0UL; + return x * (HZ / USER_HZ); + #else + u64 jif; + ++ WARN_ON((long)x < 0); + /* Don't worry about loss of precision here .. */ + if (x >= ~0UL / HZ * USER_HZ) + return ~0UL; +@@ -597,6 +599,7 @@ + + u64 jiffies_64_to_clock_t(u64 x) + { ++ WARN_ON((s64)x < 0); + #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 + do_div(x, HZ / USER_HZ); + #else +@@ -615,6 +618,7 @@ + + u64 nsec_to_clock_t(u64 x) + { ++ WARN_ON((s64)x < 0); + #if (NSEC_PER_SEC % USER_HZ) == 0 + do_div(x, (NSEC_PER_SEC / USER_HZ)); + #elif (USER_HZ % 512) == 0 +Index: kernel/kernel/time/timekeeping.c +=================================================================== +--- kernel.orig/kernel/time/timekeeping.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/time/timekeeping.c 2008-11-24 15:47:46.000000000 +0100 +@@ -43,6 +43,7 @@ + * used instead. + */ + struct timespec xtime __attribute__ ((aligned (16))); ++EXPORT_SYMBOL_GPL(xtime); + struct timespec wall_to_monotonic __attribute__ ((aligned (16))); + static unsigned long total_sleep_time; /* seconds */ + +Index: kernel/kernel/timer.c +=================================================================== +--- kernel.orig/kernel/timer.c 2008-11-24 14:17:45.000000000 +0100 ++++ kernel/kernel/timer.c 2008-11-24 15:47:46.000000000 +0100 +@@ -37,6 +37,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -663,7 +665,11 @@ + spin_unlock_irq(&base->lock); + { + int preempt_count = preempt_count(); ++ struct ve_struct *ve; ++ ++ ve = set_exec_env(get_ve0()); + fn(data); ++ (void)set_exec_env(ve); + if (preempt_count != preempt_count()) { + printk(KERN_WARNING "huh, entered %p " + "with preempt_count %08x, exited" +@@ -880,6 +886,37 @@ + * calc_load - given tick count, update the avenrun load estimates. + * This is called while holding a write_lock on xtime_lock. + */ ++ ++ ++#ifdef CONFIG_VE ++static void calc_load_ve(void) ++{ ++ unsigned long flags, nr_unint, nr_active; ++ struct ve_struct *ve; ++ ++ read_lock(&ve_list_lock); ++ for_each_ve(ve) { ++ nr_active = nr_running_ve(ve) + nr_uninterruptible_ve(ve); ++ nr_active *= FIXED_1; ++ ++ CALC_LOAD(ve->avenrun[0], EXP_1, nr_active); ++ CALC_LOAD(ve->avenrun[1], EXP_5, nr_active); ++ CALC_LOAD(ve->avenrun[2], EXP_15, nr_active); ++ } ++ read_unlock(&ve_list_lock); ++ ++ nr_unint = nr_uninterruptible() * FIXED_1; ++ spin_lock_irqsave(&kstat_glb_lock, flags); ++ CALC_LOAD(kstat_glob.nr_unint_avg[0], EXP_1, nr_unint); ++ CALC_LOAD(kstat_glob.nr_unint_avg[1], EXP_5, nr_unint); ++ CALC_LOAD(kstat_glob.nr_unint_avg[2], EXP_15, nr_unint); ++ spin_unlock_irqrestore(&kstat_glb_lock, flags); ++ ++} ++#else ++#define calc_load_ve() do { } while (0) ++#endif ++ + static inline void calc_load(unsigned long ticks) + { + unsigned long active_tasks; /* fixed-point */ +@@ -892,6 +929,7 @@ + CALC_LOAD(avenrun[0], EXP_1, active_tasks); + CALC_LOAD(avenrun[1], EXP_5, active_tasks); + CALC_LOAD(avenrun[2], EXP_15, active_tasks); ++ calc_load_ve(); + count += LOAD_FREQ; + } while (count < 0); + } +@@ -1130,11 +1168,12 @@ + unsigned long mem_total, sav_total; + unsigned int mem_unit, bitcount; + unsigned long seq; ++ unsigned long *__avenrun; ++ struct timespec tp; + + memset(info, 0, sizeof(struct sysinfo)); + + do { +- struct timespec tp; + seq = read_seqbegin(&xtime_lock); + + /* +@@ -1152,18 +1191,34 @@ + tp.tv_nsec = tp.tv_nsec - NSEC_PER_SEC; + tp.tv_sec++; + } +- info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0); +- +- info->loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT); +- info->loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT); +- info->loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT); ++ } while (read_seqretry(&xtime_lock, seq)); + ++ if (ve_is_super(get_exec_env())) { ++ info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0); ++ __avenrun = &avenrun[0]; + info->procs = nr_threads; +- } while (read_seqretry(&xtime_lock, seq)); ++ } ++#ifdef CONFIG_VE ++ else { ++ struct ve_struct *ve; ++ ve = get_exec_env(); ++ __avenrun = &ve->avenrun[0]; ++ info->procs = atomic_read(&ve->pcounter); ++ info->uptime = tp.tv_sec - ve->start_timespec.tv_sec; ++ } ++#endif ++ info->loads[0] = __avenrun[0] << (SI_LOAD_SHIFT - FSHIFT); ++ info->loads[1] = __avenrun[1] << (SI_LOAD_SHIFT - FSHIFT); ++ info->loads[2] = __avenrun[2] << (SI_LOAD_SHIFT - FSHIFT); + + si_meminfo(info); + si_swapinfo(info); + ++#ifdef CONFIG_BEANCOUNTERS ++ if (virtinfo_notifier_call(VITYPE_GENERAL, VIRTINFO_SYSINFO, info) ++ & NOTIFY_FAIL) ++ return -ENOMSG; ++#endif + /* + * If the sum of all the available memory (i.e. ram + swap) + * is less than can be stored in a 32 bit unsigned long then +Index: kernel/kernel/user.c +=================================================================== +--- kernel.orig/kernel/user.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/user.c 2008-11-24 15:47:46.000000000 +0100 +@@ -318,6 +318,7 @@ + else + local_irq_restore(flags); + } ++EXPORT_SYMBOL_GPL(free_uid); + + struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid) + { +@@ -406,6 +407,7 @@ + + return up; + } ++EXPORT_SYMBOL_GPL(alloc_uid); + + void switch_uid(struct user_struct *new_user) + { +@@ -436,6 +438,7 @@ + free_uid(old_user); + suid_keys(current); + } ++EXPORT_SYMBOL_GPL(switch_uid); + + void release_uids(struct user_namespace *ns) + { +@@ -467,7 +470,7 @@ + int n; + + uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct), +- 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); ++ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_UBC, NULL); + + for(n = 0; n < UIDHASH_SZ; ++n) + INIT_HLIST_HEAD(init_user_ns.uidhash_table + n); +Index: kernel/kernel/utsname_sysctl.c +=================================================================== +--- kernel.orig/kernel/utsname_sysctl.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/kernel/utsname_sysctl.c 2008-11-24 15:47:46.000000000 +0100 +@@ -27,6 +27,10 @@ + down_read(&uts_sem); + else + down_write(&uts_sem); ++ ++ if (strcmp(table->procname, "virt_osrelease") == 0) ++ return virt_utsname.release; ++ + return which; + } + +@@ -115,6 +119,7 @@ + .mode = 0644, + .proc_handler = proc_do_uts_string, + .strategy = sysctl_uts_string, ++ .virt_handler = 1, + }, + { + .ctl_name = KERN_DOMAINNAME, +@@ -124,6 +129,14 @@ + .mode = 0644, + .proc_handler = proc_do_uts_string, + .strategy = sysctl_uts_string, ++ .virt_handler = 1, ++ }, { ++ .procname = "virt_osrelease", ++ .data = virt_utsname.release, ++ .maxlen = sizeof(virt_utsname.release), ++ .mode = 0644, ++ .proc_handler = &proc_do_uts_string, ++ .strategy = sysctl_uts_string, + }, + {} + }; +@@ -140,7 +153,7 @@ + + static int __init utsname_sysctl_init(void) + { +- register_sysctl_table(uts_root_table); ++ register_glob_sysctl_table(uts_root_table); + return 0; + } + +Index: kernel/kernel/ve/Makefile +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/ve/Makefile 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,16 @@ ++# ++# ++# kernel/ve/Makefile ++# ++# Copyright (C) 2000-2005 SWsoft ++# All rights reserved. ++# ++# Licensing governed by "linux/COPYING.SWsoft" file. ++ ++obj-$(CONFIG_VE) = ve.o veowner.o hooks.o devperms.o ++obj-$(CONFIG_VZ_WDOG) += vzwdog.o ++obj-$(CONFIG_VE_CALLS) += vzmon.o ++ ++vzmon-objs = vecalls.o ++ ++obj-$(CONFIG_VZ_DEV) += vzdev.o +Index: kernel/kernel/ve/devperms.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/ve/devperms.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,418 @@ ++/* ++ * linux/kernel/ve/devperms.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ * Devices permissions routines, ++ * character and block devices separately ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Rules applied in the following order: ++ * MAJOR!=0, MINOR!=0 ++ * MAJOR!=0, MINOR==0 ++ * MAJOR==0, MINOR==0 ++ */ ++ ++struct devperms_struct { ++ dev_t dev; /* device id */ ++ unsigned char mask; ++ unsigned type; ++ envid_t veid; ++ ++ struct hlist_node hash; ++ struct rcu_head rcu; ++}; ++ ++static struct devperms_struct default_major_perms[] = { ++ { ++ MKDEV(UNIX98_PTY_MASTER_MAJOR, 0), ++ S_IROTH | S_IWOTH, ++ S_IFCHR, ++ }, ++ { ++ MKDEV(UNIX98_PTY_SLAVE_MAJOR, 0), ++ S_IROTH | S_IWOTH, ++ S_IFCHR, ++ }, ++ { ++ MKDEV(PTY_MASTER_MAJOR, 0), ++ S_IROTH | S_IWOTH, ++ S_IFCHR, ++ }, ++ { ++ MKDEV(PTY_SLAVE_MAJOR, 0), ++ S_IROTH | S_IWOTH, ++ S_IFCHR, ++ }, ++}; ++ ++static struct devperms_struct default_minor_perms[] = { ++ { ++ MKDEV(MEM_MAJOR, 3), /* null */ ++ S_IROTH | S_IWOTH, ++ S_IFCHR, ++ }, ++ { ++ MKDEV(MEM_MAJOR, 5), /* zero */ ++ S_IROTH | S_IWOTH, ++ S_IFCHR, ++ }, ++ { ++ MKDEV(MEM_MAJOR, 7), /* full */ ++ S_IROTH | S_IWOTH, ++ S_IFCHR, ++ }, ++ { ++ MKDEV(TTYAUX_MAJOR, 0), /* tty */ ++ S_IROTH | S_IWOTH, ++ S_IFCHR, ++ }, ++ { ++ MKDEV(TTYAUX_MAJOR, 2), /* ptmx */ ++ S_IROTH | S_IWOTH, ++ S_IFCHR, ++ }, ++ { ++ MKDEV(MEM_MAJOR, 8), /* random */ ++ S_IROTH, ++ S_IFCHR, ++ }, ++ { ++ MKDEV(MEM_MAJOR, 9), /* urandom */ ++ S_IROTH, ++ S_IFCHR ++ }, ++}; ++ ++static struct devperms_struct default_deny_perms = { ++ MKDEV(0, 0), ++ 0, ++ S_IFCHR, ++}; ++ ++static inline struct devperms_struct *find_default_devperms(int type, dev_t dev) ++{ ++ int i; ++ ++ /* XXX all defaults perms are S_IFCHR */ ++ if (type != S_IFCHR) ++ return &default_deny_perms; ++ ++ for (i = 0; i < ARRAY_SIZE(default_minor_perms); i++) ++ if (MAJOR(dev) == MAJOR(default_minor_perms[i].dev) && ++ MINOR(dev) == MINOR(default_minor_perms[i].dev)) ++ return &default_minor_perms[i]; ++ ++ for (i = 0; i < ARRAY_SIZE(default_major_perms); i++) ++ if (MAJOR(dev) == MAJOR(default_major_perms[i].dev)) ++ return &default_major_perms[i]; ++ ++ return &default_deny_perms; ++} ++ ++#define DEVPERMS_HASH_SZ 512 ++#define devperms_hashfn(id, dev) \ ++ ( (id << 5) ^ (id >> 5) ^ (MAJOR(dev)) ^ MINOR(dev) ) & \ ++ (DEVPERMS_HASH_SZ - 1) ++ ++static DEFINE_SPINLOCK(devperms_hash_lock); ++static struct hlist_head devperms_hash[DEVPERMS_HASH_SZ]; ++ ++static inline struct devperms_struct *find_devperms(envid_t veid, ++ int type, ++ dev_t dev) ++{ ++ struct hlist_head *table; ++ struct devperms_struct *perms; ++ struct hlist_node *h; ++ ++ table = &devperms_hash[devperms_hashfn(veid, dev)]; ++ hlist_for_each_entry_rcu (perms, h, table, hash) ++ if (perms->type == type && perms->veid == veid && ++ MAJOR(perms->dev) == MAJOR(dev) && ++ MINOR(perms->dev) == MINOR(dev)) ++ return perms; ++ ++ return NULL; ++} ++ ++static void free_devperms(struct rcu_head *rcu) ++{ ++ struct devperms_struct *perms; ++ ++ perms = container_of(rcu, struct devperms_struct, rcu); ++ kfree(perms); ++} ++ ++/* API calls */ ++ ++void clean_device_perms_ve(envid_t veid) ++{ ++ int i; ++ struct devperms_struct *p; ++ struct hlist_node *n, *tmp; ++ ++ spin_lock(&devperms_hash_lock); ++ for (i = 0; i < DEVPERMS_HASH_SZ; i++) ++ hlist_for_each_entry_safe (p, n, tmp, &devperms_hash[i], hash) ++ if (p->veid == veid) { ++ hlist_del_rcu(&p->hash); ++ call_rcu(&p->rcu, free_devperms); ++ } ++ spin_unlock(&devperms_hash_lock); ++} ++ ++EXPORT_SYMBOL(clean_device_perms_ve); ++ ++/* ++ * Mode is a mask of ++ * FMODE_READ for read access (configurable by S_IROTH) ++ * FMODE_WRITE for write access (configurable by S_IWOTH) ++ * FMODE_QUOTACTL for quotactl access (configurable by S_IXGRP) ++ */ ++ ++int get_device_perms_ve(int dev_type, dev_t dev, int access_mode) ++{ ++ struct devperms_struct *p; ++ struct ve_struct *ve; ++ envid_t veid; ++ char mask; ++ ++ ve = get_exec_env(); ++ veid = ve->veid; ++ rcu_read_lock(); ++ ++ p = find_devperms(veid, dev_type | VE_USE_MINOR, dev); ++ if (p != NULL) ++ goto end; ++ ++ p = find_devperms(veid, dev_type | VE_USE_MAJOR, MKDEV(MAJOR(dev),0)); ++ if (p != NULL) ++ goto end; ++ ++ p = find_devperms(veid, dev_type, MKDEV(0,0)); ++ if (p != NULL) ++ goto end; ++ ++ if (ve->features & VE_FEATURE_DEF_PERMS) { ++ p = find_default_devperms(dev_type, dev); ++ if (p != NULL) ++ goto end; ++ } ++ ++ rcu_read_unlock(); ++ return -ENODEV; ++ ++end: ++ mask = p->mask; ++ rcu_read_unlock(); ++ ++ access_mode = "\000\004\002\006\010\014\012\016"[access_mode]; ++ return ((mask & access_mode) == access_mode) ? 0 : -EACCES; ++} ++ ++EXPORT_SYMBOL(get_device_perms_ve); ++ ++int set_device_perms_ve(envid_t veid, unsigned type, dev_t dev, unsigned mask) ++{ ++ struct devperms_struct *perms, *new_perms; ++ struct hlist_head *htable; ++ ++ new_perms = kmalloc(sizeof(struct devperms_struct), GFP_KERNEL); ++ ++ spin_lock(&devperms_hash_lock); ++ perms = find_devperms(veid, type, dev); ++ if (perms != NULL) { ++ kfree(new_perms); ++ perms->mask = mask & S_IALLUGO; ++ } else { ++ switch (type & VE_USE_MASK) { ++ case 0: ++ dev = 0; ++ break; ++ case VE_USE_MAJOR: ++ dev = MKDEV(MAJOR(dev),0); ++ break; ++ } ++ ++ new_perms->veid = veid; ++ new_perms->dev = dev; ++ new_perms->type = type; ++ new_perms->mask = mask & S_IALLUGO; ++ ++ htable = &devperms_hash[devperms_hashfn(new_perms->veid, ++ new_perms->dev)]; ++ hlist_add_head_rcu(&new_perms->hash, htable); ++ } ++ spin_unlock(&devperms_hash_lock); ++ return 0; ++} ++ ++EXPORT_SYMBOL(set_device_perms_ve); ++ ++#ifdef CONFIG_PROC_FS ++static int devperms_seq_show(struct seq_file *m, void *v) ++{ ++ struct devperms_struct *dp; ++ char dev_s[32], type_c; ++ unsigned use, type; ++ dev_t dev; ++ ++ dp = (struct devperms_struct *)v; ++ if (dp == (struct devperms_struct *)1L) { ++ seq_printf(m, "Version: 2.7\n"); ++ return 0; ++ } ++ ++ use = dp->type & VE_USE_MASK; ++ type = dp->type & S_IFMT; ++ dev = dp->dev; ++ ++ if ((use | VE_USE_MINOR) == use) ++ snprintf(dev_s, sizeof(dev_s), "%d:%d", MAJOR(dev), MINOR(dev)); ++ else if ((use | VE_USE_MAJOR) == use) ++ snprintf(dev_s, sizeof(dev_s), "%d:*", MAJOR(dp->dev)); ++ else ++ snprintf(dev_s, sizeof(dev_s), "*:*"); ++ ++ if (type == S_IFCHR) ++ type_c = 'c'; ++ else if (type == S_IFBLK) ++ type_c = 'b'; ++ else ++ type_c = '?'; ++ ++ seq_printf(m, "%10u %c %03o %s\n", dp->veid, type_c, dp->mask, dev_s); ++ return 0; ++} ++ ++static void *devperms_seq_start(struct seq_file *m, loff_t *pos) ++{ ++ loff_t cpos; ++ long slot; ++ struct devperms_struct *dp; ++ struct hlist_node *h; ++ ++ cpos = *pos; ++ rcu_read_lock(); ++ ++ if (cpos-- == 0) ++ return (void *)1L; ++ ++ for (slot = 0; slot < DEVPERMS_HASH_SZ; slot++) ++ hlist_for_each_entry_rcu (dp, h, &devperms_hash[slot], hash) ++ if (cpos-- == 0) { ++ m->private = (void *)slot; ++ return dp; ++ } ++ return NULL; ++} ++ ++static void *devperms_seq_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ long slot; ++ struct hlist_node *next; ++ struct devperms_struct *dp; ++ ++ dp = (struct devperms_struct *)v; ++ ++ if (unlikely(dp == (struct devperms_struct *)1L)) ++ slot = 0; ++ else { ++ next = rcu_dereference(dp->hash.next); ++ if (next != NULL) ++ goto out; ++ ++ slot = (long)m->private + 1; ++ } ++ ++ for (; slot < DEVPERMS_HASH_SZ; slot++) { ++ next = rcu_dereference(devperms_hash[slot].first); ++ if (next == NULL) ++ continue; ++ ++ m->private = (void *)slot; ++ goto out; ++ } ++ return NULL; ++ ++out: ++ (*pos)++; ++ return hlist_entry(next, struct devperms_struct, hash); ++} ++ ++static void devperms_seq_stop(struct seq_file *m, void *v) ++{ ++ rcu_read_unlock(); ++} ++ ++static struct seq_operations devperms_seq_op = { ++ .start = devperms_seq_start, ++ .next = devperms_seq_next, ++ .stop = devperms_seq_stop, ++ .show = devperms_seq_show, ++}; ++ ++static int devperms_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &devperms_seq_op); ++} ++ ++struct file_operations proc_devperms_ops = { ++ .open = devperms_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++EXPORT_SYMBOL(proc_devperms_ops); ++#endif ++ ++/* Initialisation */ ++ ++static struct devperms_struct original_perms[] = ++{ ++ { ++ MKDEV(0,0), ++ S_IROTH | S_IWOTH, ++ S_IFCHR, ++ 0, ++ }, ++ { ++ MKDEV(0,0), ++ S_IXGRP | S_IROTH | S_IWOTH, ++ S_IFBLK, ++ 0, ++ }, ++}; ++ ++static int __init init_devperms_hash(void) ++{ ++ hlist_add_head(&original_perms[0].hash, ++ &devperms_hash[devperms_hashfn(0, ++ original_perms[0].dev)]); ++ hlist_add_head(&original_perms[1].hash, ++ &devperms_hash[devperms_hashfn(0, ++ original_perms[1].dev)]); ++ return 0; ++} ++ ++core_initcall(init_devperms_hash); +Index: kernel/kernel/ve/hooks.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/ve/hooks.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,114 @@ ++/* ++ * linux/kernel/ve/hooks.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct list_head ve_hooks[VE_MAX_CHAINS]; ++static DECLARE_RWSEM(ve_hook_sem); ++ ++void ve_hook_register(int chain, struct ve_hook *vh) ++{ ++ struct list_head *lh; ++ struct ve_hook *tmp; ++ ++ BUG_ON(chain > VE_MAX_CHAINS); ++ ++ down_write(&ve_hook_sem); ++ list_for_each(lh, &ve_hooks[chain]) { ++ tmp = list_entry(lh, struct ve_hook, list); ++ if (vh->priority < tmp->priority) ++ break; ++ } ++ ++ list_add_tail(&vh->list, lh); ++ up_write(&ve_hook_sem); ++} ++ ++EXPORT_SYMBOL(ve_hook_register); ++ ++void ve_hook_unregister(struct ve_hook *vh) ++{ ++ down_write(&ve_hook_sem); ++ list_del(&vh->list); ++ up_write(&ve_hook_sem); ++} ++ ++EXPORT_SYMBOL(ve_hook_unregister); ++ ++static inline int ve_hook_init(struct ve_hook *vh, struct ve_struct *ve) ++{ ++ int err; ++ ++ err = 0; ++ if (try_module_get(vh->owner)) { ++ err = vh->init(ve); ++ module_put(vh->owner); ++ } ++ return err; ++} ++ ++static inline void ve_hook_fini(struct ve_hook *vh, struct ve_struct *ve) ++{ ++ if (vh->fini != NULL && try_module_get(vh->owner)) { ++ vh->fini(ve); ++ module_put(vh->owner); ++ } ++} ++ ++int ve_hook_iterate_init(int chain, void *ve) ++{ ++ struct ve_hook *vh; ++ int err; ++ ++ err = 0; ++ ++ down_read(&ve_hook_sem); ++ list_for_each_entry(vh, &ve_hooks[chain], list) ++ if ((err = ve_hook_init(vh, ve)) < 0) ++ break; ++ ++ if (err) ++ list_for_each_entry_continue_reverse(vh, &ve_hooks[chain], list) ++ ve_hook_fini(vh, ve); ++ ++ up_read(&ve_hook_sem); ++ return err; ++} ++ ++EXPORT_SYMBOL(ve_hook_iterate_init); ++ ++void ve_hook_iterate_fini(int chain, void *ve) ++{ ++ struct ve_hook *vh; ++ ++ down_read(&ve_hook_sem); ++ list_for_each_entry_reverse(vh, &ve_hooks[chain], list) ++ ve_hook_fini(vh, ve); ++ up_read(&ve_hook_sem); ++} ++ ++EXPORT_SYMBOL(ve_hook_iterate_fini); ++ ++static int __init ve_hooks_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < VE_MAX_CHAINS; i++) ++ INIT_LIST_HEAD(&ve_hooks[i]); ++ return 0; ++} ++ ++core_initcall(ve_hooks_init); ++ +Index: kernel/kernel/ve/ve.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/ve/ve.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,161 @@ ++/* ++ * linux/kernel/ve/ve.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++/* ++ * 've.c' helper file performing VE sub-system initialization ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++unsigned long vz_rstamp = 0x37e0f59d; ++ ++#ifdef CONFIG_MODULES ++struct module no_module = { .state = MODULE_STATE_GOING }; ++EXPORT_SYMBOL(no_module); ++#endif ++ ++INIT_KSYM_MODULE(ip_tables); ++INIT_KSYM_MODULE(ip6_tables); ++INIT_KSYM_MODULE(iptable_filter); ++INIT_KSYM_MODULE(ip6table_filter); ++INIT_KSYM_MODULE(iptable_mangle); ++INIT_KSYM_MODULE(ip6table_mangle); ++INIT_KSYM_MODULE(ip_conntrack); ++INIT_KSYM_MODULE(nf_conntrack); ++INIT_KSYM_MODULE(nf_conntrack_ipv4); ++INIT_KSYM_MODULE(nf_conntrack_ipv6); ++INIT_KSYM_MODULE(ip_nat); ++INIT_KSYM_MODULE(nf_nat); ++INIT_KSYM_MODULE(iptable_nat); ++ ++INIT_KSYM_CALL(int, init_netfilter, (void)); ++INIT_KSYM_CALL(int, init_iptables, (void)); ++INIT_KSYM_CALL(int, init_ip6tables, (void)); ++INIT_KSYM_CALL(int, init_iptable_filter, (void)); ++INIT_KSYM_CALL(int, init_ip6table_filter, (void)); ++INIT_KSYM_CALL(int, init_iptable_mangle, (void)); ++INIT_KSYM_CALL(int, init_ip6table_mangle, (void)); ++INIT_KSYM_CALL(int, init_iptable_conntrack, (void)); ++INIT_KSYM_CALL(int, nf_conntrack_init_ve, (void)); ++INIT_KSYM_CALL(int, init_nf_ct_l3proto_ipv4, (void)); ++INIT_KSYM_CALL(int, init_nf_ct_l3proto_ipv6, (void)); ++INIT_KSYM_CALL(int, nf_nat_init, (void)); ++INIT_KSYM_CALL(int, init_iptable_nat, (void)); ++INIT_KSYM_CALL(void, fini_iptable_nat, (void)); ++INIT_KSYM_CALL(int, init_nftable_nat, (void)); ++INIT_KSYM_CALL(void, fini_nftable_nat, (void)); ++INIT_KSYM_CALL(void, nf_nat_cleanup, (void)); ++INIT_KSYM_CALL(void, fini_iptable_conntrack, (void)); ++INIT_KSYM_CALL(void, nf_conntrack_cleanup_ve, (void)); ++INIT_KSYM_CALL(void, fini_nf_ct_l3proto_ipv4, (void)); ++INIT_KSYM_CALL(void, fini_nf_ct_l3proto_ipv6, (void)); ++INIT_KSYM_CALL(void, fini_ip6table_filter, (void)); ++INIT_KSYM_CALL(void, fini_iptable_filter, (void)); ++INIT_KSYM_CALL(void, fini_ip6table_mangle, (void)); ++INIT_KSYM_CALL(void, fini_iptable_mangle, (void)); ++INIT_KSYM_CALL(void, fini_ip6tables, (void)); ++INIT_KSYM_CALL(void, fini_iptables, (void)); ++INIT_KSYM_CALL(void, fini_netfilter, (void)); ++ ++#if defined(CONFIG_VE_CALLS_MODULE) || defined(CONFIG_VE_CALLS) ++INIT_KSYM_MODULE(vzmon); ++INIT_KSYM_CALL(void, real_do_env_free, (struct ve_struct *env)); ++ ++void do_env_free(struct ve_struct *env) ++{ ++ KSYMSAFECALL_VOID(vzmon, real_do_env_free, (env)); ++} ++EXPORT_SYMBOL(do_env_free); ++#endif ++ ++#if defined(CONFIG_VE_ETHDEV) || defined(CONFIG_VE_ETHDEV_MODULE) ++INIT_KSYM_MODULE(vzethdev); ++INIT_KSYM_CALL(int, veth_open, (struct net_device *dev)); ++#endif ++ ++struct ve_struct ve0 = { ++ .ve_list = LIST_HEAD_INIT(ve0.ve_list), ++ .vetask_lh = LIST_HEAD_INIT(ve0.vetask_lh), ++ .start_jiffies = INITIAL_JIFFIES, ++#ifdef CONFIG_UNIX98_PTYS ++ .devpts_config = &devpts_config, ++#endif ++ .ve_ns = &init_nsproxy, ++ .is_running = 1, ++ .op_sem = __RWSEM_INITIALIZER(ve0.op_sem), ++}; ++ ++EXPORT_SYMBOL(ve0); ++ ++#ifdef CONFIG_SMP ++static struct percpu_data ve0_cpu_stats; ++#endif ++static struct ve_cpu_stats ve0_cpu_stats_data[NR_CPUS]; ++ ++LIST_HEAD(ve_list_head); ++rwlock_t ve_list_lock = RW_LOCK_UNLOCKED; ++ ++LIST_HEAD(ve_cleanup_list); ++DEFINE_SPINLOCK(ve_cleanup_lock); ++struct task_struct *ve_cleanup_thread; ++ ++EXPORT_SYMBOL(ve_list_lock); ++EXPORT_SYMBOL(ve_list_head); ++EXPORT_SYMBOL(ve_cleanup_lock); ++EXPORT_SYMBOL(ve_cleanup_list); ++EXPORT_SYMBOL(ve_cleanup_thread); ++ ++void init_ve0(void) ++{ ++ struct ve_struct *ve; ++ ++ ve = get_ve0(); ++ (void)get_ve(ve); ++ atomic_set(&ve->pcounter, 1); ++ ++ ve->cpu_stats = static_percpu_ptr(&ve0_cpu_stats, ++ ve0_cpu_stats_data); ++ ++ list_add(&ve->ve_list, &ve_list_head); ++} ++ ++void ve_cleanup_schedule(struct ve_struct *ve) ++{ ++ BUG_ON(ve_cleanup_thread == NULL); ++ ++ spin_lock(&ve_cleanup_lock); ++ list_add_tail(&ve->cleanup_list, &ve_cleanup_list); ++ spin_unlock(&ve_cleanup_lock); ++ ++ wake_up_process(ve_cleanup_thread); ++} +Index: kernel/kernel/ve/vecalls.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/ve/vecalls.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,2742 @@ ++/* ++ * linux/kernel/ve/vecalls.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ */ ++ ++/* ++ * 'vecalls.c' is file with basic VE support. It provides basic primities ++ * along with initialization script ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#ifdef CONFIG_FAIRSCHED ++#include ++#endif ++ ++#include ++#include ++#include ++ ++int nr_ve = 1; /* One VE always exists. Compatibility with vestat */ ++EXPORT_SYMBOL(nr_ve); ++ ++static int do_env_enter(struct ve_struct *ve, unsigned int flags); ++static int alloc_ve_tty_drivers(struct ve_struct* ve); ++static void free_ve_tty_drivers(struct ve_struct* ve); ++static int register_ve_tty_drivers(struct ve_struct* ve); ++static void unregister_ve_tty_drivers(struct ve_struct* ve); ++static int init_ve_tty_drivers(struct ve_struct *); ++static void fini_ve_tty_drivers(struct ve_struct *); ++static void clear_termios(struct tty_driver* driver ); ++#ifdef CONFIG_INET ++static void ve_mapped_devs_cleanup(struct ve_struct *ve); ++#endif ++ ++static void vecalls_exit(void); ++extern void grsecurity_setup(void); ++ ++struct ve_struct *__find_ve_by_id(envid_t veid) ++{ ++ struct ve_struct *ve; ++ ++ for_each_ve(ve) { ++ if (ve->veid == veid) ++ return ve; ++ } ++ return NULL; ++} ++EXPORT_SYMBOL(__find_ve_by_id); ++ ++struct ve_struct *get_ve_by_id(envid_t veid) ++{ ++ struct ve_struct *ve; ++ read_lock(&ve_list_lock); ++ ve = __find_ve_by_id(veid); ++ get_ve(ve); ++ read_unlock(&ve_list_lock); ++ return ve; ++} ++EXPORT_SYMBOL(get_ve_by_id); ++ ++/* ++ * real_put_ve() MUST be used instead of put_ve() inside vecalls. ++ */ ++void real_do_env_free(struct ve_struct *ve); ++static inline void real_put_ve(struct ve_struct *ve) ++{ ++ if (ve && atomic_dec_and_test(&ve->counter)) { ++ if (atomic_read(&ve->pcounter) > 0) ++ BUG(); ++ if (ve->is_running) ++ BUG(); ++ real_do_env_free(ve); ++ } ++} ++ ++static int ve_get_cpu_stat(envid_t veid, struct vz_cpu_stat __user *buf) ++{ ++ struct ve_struct *ve; ++ struct vz_cpu_stat *vstat; ++ int retval; ++ int i, cpu; ++ unsigned long tmp; ++ ++ if (!ve_is_super(get_exec_env()) && (veid != get_exec_env()->veid)) ++ return -EPERM; ++ if (veid == 0) ++ return -ESRCH; ++ ++ vstat = kzalloc(sizeof(*vstat), GFP_KERNEL); ++ if (!vstat) ++ return -ENOMEM; ++ ++ retval = -ESRCH; ++ read_lock(&ve_list_lock); ++ ve = __find_ve_by_id(veid); ++ if (ve == NULL) ++ goto out_unlock; ++ for_each_online_cpu(cpu) { ++ struct ve_cpu_stats *st; ++ ++ st = VE_CPU_STATS(ve, cpu); ++ vstat->user_jif += (unsigned long)cputime64_to_clock_t(st->user); ++ vstat->nice_jif += (unsigned long)cputime64_to_clock_t(st->nice); ++ vstat->system_jif += (unsigned long)cputime64_to_clock_t(st->system); ++ vstat->idle_clk += ve_sched_get_idle_time(ve, cpu); ++ } ++ vstat->uptime_clk = get_cycles() - ve->start_cycles; ++ vstat->uptime_jif = (unsigned long)cputime64_to_clock_t( ++ get_jiffies_64() - ve->start_jiffies); ++ for (i = 0; i < 3; i++) { ++ tmp = ve->avenrun[i] + (FIXED_1/200); ++ vstat->avenrun[i].val_int = LOAD_INT(tmp); ++ vstat->avenrun[i].val_frac = LOAD_FRAC(tmp); ++ } ++ read_unlock(&ve_list_lock); ++ ++ retval = 0; ++ if (copy_to_user(buf, vstat, sizeof(*vstat))) ++ retval = -EFAULT; ++out_free: ++ kfree(vstat); ++ return retval; ++ ++out_unlock: ++ read_unlock(&ve_list_lock); ++ goto out_free; ++} ++ ++static int real_setdevperms(envid_t veid, unsigned type, ++ dev_t dev, unsigned mask) ++{ ++ struct ve_struct *ve; ++ int err; ++ ++ if (!capable(CAP_SETVEID) || veid == 0) ++ return -EPERM; ++ ++ if ((ve = get_ve_by_id(veid)) == NULL) ++ return -ESRCH; ++ ++ down_read(&ve->op_sem); ++ err = -ESRCH; ++ if (ve->is_running) ++ err = set_device_perms_ve(veid, type, dev, mask); ++ up_read(&ve->op_sem); ++ real_put_ve(ve); ++ return err; ++} ++ ++/********************************************************************** ++ ********************************************************************** ++ * ++ * VE start: subsystems ++ * ++ ********************************************************************** ++ **********************************************************************/ ++ ++#ifdef CONFIG_INET ++#include ++#include ++#include ++#include ++ ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++static int init_fini_ve_mibs6(struct ve_struct *ve, int fini) ++{ ++ if (fini) ++ goto fini; ++ ++ if (!(ve->_ipv6_statistics[0] = alloc_percpu(struct ipstats_mib))) ++ goto out1; ++ if (!(ve->_ipv6_statistics[1] = alloc_percpu(struct ipstats_mib))) ++ goto out2; ++ if (!(ve->_icmpv6_statistics[0] = alloc_percpu(struct icmpv6_mib))) ++ goto out3; ++ if (!(ve->_icmpv6_statistics[1] = alloc_percpu(struct icmpv6_mib))) ++ goto out4; ++ if (!(ve->_icmpv6msg_statistics[0] = alloc_percpu(struct icmpv6msg_mib))) ++ goto out5; ++ if (!(ve->_icmpv6msg_statistics[1] = alloc_percpu(struct icmpv6msg_mib))) ++ goto out6; ++ if (!(ve->_udp_stats_in6[0] = alloc_percpu(struct udp_mib))) ++ goto out7; ++ if (!(ve->_udp_stats_in6[1] = alloc_percpu(struct udp_mib))) ++ goto out8; ++ if (!(ve->_udplite_stats_in6[0] = alloc_percpu(struct udp_mib))) ++ goto out9; ++ if (!(ve->_udplite_stats_in6[1] = alloc_percpu(struct udp_mib))) ++ goto out10; ++ return 0; ++ ++fini: ++ free_percpu(ve->_udplite_stats_in6[1]); ++out10: ++ free_percpu(ve->_udplite_stats_in6[0]); ++out9: ++ free_percpu(ve->_udp_stats_in6[1]); ++out8: ++ free_percpu(ve->_udp_stats_in6[0]); ++out7: ++ free_percpu(ve->_icmpv6msg_statistics[1]); ++out6: ++ free_percpu(ve->_icmpv6msg_statistics[0]); ++out5: ++ free_percpu(ve->_icmpv6_statistics[1]); ++out4: ++ free_percpu(ve->_icmpv6_statistics[0]); ++out3: ++ free_percpu(ve->_ipv6_statistics[1]); ++out2: ++ free_percpu(ve->_ipv6_statistics[0]); ++out1: ++ return -ENOMEM; ++} ++#else ++static int init_fini_ve_mibs6(struct ve_struct *ve, int fini) { return 0; } ++#endif ++ ++static int init_fini_ve_mibs(struct ve_struct *ve, int fini) ++{ ++ if (fini) ++ goto fini; ++ if (!(ve->_net_statistics[0] = alloc_percpu(struct linux_mib))) ++ goto out1; ++ if (!(ve->_net_statistics[1] = alloc_percpu(struct linux_mib))) ++ goto out2; ++ if (!(ve->_ip_statistics[0] = alloc_percpu(struct ipstats_mib))) ++ goto out3; ++ if (!(ve->_ip_statistics[1] = alloc_percpu(struct ipstats_mib))) ++ goto out4; ++ if (!(ve->_icmp_statistics[0] = alloc_percpu(struct icmp_mib))) ++ goto out5; ++ if (!(ve->_icmp_statistics[1] = alloc_percpu(struct icmp_mib))) ++ goto out6; ++ if (!(ve->_icmpmsg_statistics[0] = alloc_percpu(struct icmpmsg_mib))) ++ goto out7; ++ if (!(ve->_icmpmsg_statistics[1] = alloc_percpu(struct icmpmsg_mib))) ++ goto out8; ++ if (!(ve->_tcp_statistics[0] = alloc_percpu(struct tcp_mib))) ++ goto out9; ++ if (!(ve->_tcp_statistics[1] = alloc_percpu(struct tcp_mib))) ++ goto out10; ++ if (!(ve->_udp_statistics[0] = alloc_percpu(struct udp_mib))) ++ goto out11; ++ if (!(ve->_udp_statistics[1] = alloc_percpu(struct udp_mib))) ++ goto out12; ++ if (!(ve->_udplite_statistics[0] = alloc_percpu(struct udp_mib))) ++ goto out13; ++ if (!(ve->_udplite_statistics[1] = alloc_percpu(struct udp_mib))) ++ goto out14; ++ if (init_fini_ve_mibs6(ve, fini)) ++ goto out15; ++ return 0; ++ ++fini: ++ init_fini_ve_mibs6(ve, fini); ++out15: ++ free_percpu(ve->_udplite_statistics[1]); ++out14: ++ free_percpu(ve->_udplite_statistics[0]); ++out13: ++ free_percpu(ve->_udp_statistics[1]); ++out12: ++ free_percpu(ve->_udp_statistics[0]); ++out11: ++ free_percpu(ve->_tcp_statistics[1]); ++out10: ++ free_percpu(ve->_tcp_statistics[0]); ++out9: ++ free_percpu(ve->_icmpmsg_statistics[1]); ++out8: ++ free_percpu(ve->_icmpmsg_statistics[0]); ++out7: ++ free_percpu(ve->_icmp_statistics[1]); ++out6: ++ free_percpu(ve->_icmp_statistics[0]); ++out5: ++ free_percpu(ve->_ip_statistics[1]); ++out4: ++ free_percpu(ve->_ip_statistics[0]); ++out3: ++ free_percpu(ve->_net_statistics[1]); ++out2: ++ free_percpu(ve->_net_statistics[0]); ++out1: ++ return -ENOMEM; ++} ++ ++static inline int init_ve_mibs(struct ve_struct *ve) ++{ ++ return init_fini_ve_mibs(ve, 0); ++} ++ ++static inline void fini_ve_mibs(struct ve_struct *ve) ++{ ++ (void)init_fini_ve_mibs(ve, 1); ++} ++#else ++#define init_ve_mibs(ve) (0) ++#define fini_ve_mibs(ve) do { } while (0) ++#endif ++ ++static int prepare_proc_root(struct ve_struct *ve) ++{ ++ struct proc_dir_entry *de; ++ ++ de = kzalloc(sizeof(struct proc_dir_entry) + 6, GFP_KERNEL); ++ if (de == NULL) ++ return -ENOMEM; ++ ++ memcpy(de + 1, "/proc", 6); ++ de->name = (char *)(de + 1); ++ de->namelen = 5; ++ de->mode = S_IFDIR | S_IRUGO | S_IXUGO; ++ de->nlink = 2; ++ atomic_set(&de->count, 1); ++ ++ ve->proc_root = de; ++ return 0; ++} ++ ++#ifdef CONFIG_PROC_FS ++static int init_ve_proc(struct ve_struct *ve) ++{ ++ int err; ++ struct proc_dir_entry *de; ++ ++ err = prepare_proc_root(ve); ++ if (err) ++ goto out_root; ++ ++ err = register_ve_fs_type(ve, &proc_fs_type, ++ &ve->proc_fstype, &ve->proc_mnt); ++ if (err) ++ goto out_reg; ++ ++ err = -ENOMEM; ++ de = create_proc_entry("kmsg", S_IRUSR, NULL); ++ if (!de) ++ goto out_kmsg; ++ de->proc_fops = &proc_kmsg_operations; ++ ++ /* create necessary /proc subdirs in VE local proc tree */ ++ err = -ENOMEM; ++ de = create_proc_entry("vz", S_IFDIR|S_IRUGO|S_IXUGO, NULL); ++ if (!de) ++ goto out_vz; ++ ++ ve->_proc_net = proc_mkdir("net", NULL); ++ if (!ve->_proc_net) ++ goto out_net; ++ ve->_proc_net_stat = proc_mkdir("stat", ve->_proc_net); ++ if (!ve->_proc_net_stat) ++ goto out_net_stat; ++ ++ if (ve_snmp_proc_init(ve)) ++ goto out_snmp; ++ ++ ve->ve_ns->pid_ns->proc_mnt = mntget(ve->proc_mnt); ++ return 0; ++ ++out_snmp: ++ remove_proc_entry("stat", ve->_proc_net); ++out_net_stat: ++ remove_proc_entry("net", NULL); ++out_net: ++ remove_proc_entry("vz", NULL); ++out_vz: ++ remove_proc_entry("kmsg", NULL); ++out_kmsg: ++ unregister_ve_fs_type(ve->proc_fstype, ve->proc_mnt); ++ ve->proc_mnt = NULL; ++out_reg: ++ /* proc_fstype and proc_root are freed in real_put_ve -> free_ve_proc */ ++ ; ++out_root: ++ return err; ++} ++ ++static void fini_ve_proc(struct ve_struct *ve) ++{ ++ ve_snmp_proc_fini(ve); ++ remove_proc_entry("stat", ve->_proc_net); ++ remove_proc_entry("net", NULL); ++ remove_proc_entry("vz", NULL); ++ remove_proc_entry("kmsg", NULL); ++ unregister_ve_fs_type(ve->proc_fstype, ve->proc_mnt); ++ ve->proc_mnt = NULL; ++} ++ ++static void free_ve_proc(struct ve_struct *ve) ++{ ++ /* proc filesystem frees proc_dir_entries on remove_proc_entry() only, ++ so we check that everything was removed and not lost */ ++ if (ve->proc_root && ve->proc_root->subdir) { ++ struct proc_dir_entry *p = ve->proc_root; ++ printk(KERN_WARNING "CT: %d: proc entry /proc", ve->veid); ++ while ((p = p->subdir) != NULL) ++ printk("/%s", p->name); ++ printk(" is not removed!\n"); ++ } ++ ++ kfree(ve->proc_root); ++ kfree(ve->proc_fstype); ++ ++ ve->proc_fstype = NULL; ++ ve->proc_root = NULL; ++} ++#else ++#define init_ve_proc(ve) (0) ++#define fini_ve_proc(ve) do { } while (0) ++#define free_ve_proc(ve) do { } while (0) ++#endif ++ ++extern const struct file_operations proc_sys_file_operations; ++extern struct inode_operations proc_sys_inode_operations; ++ ++#ifdef CONFIG_SYSCTL ++static int init_ve_sysctl(struct ve_struct *ve) ++{ ++ int err; ++ ++#ifdef CONFIG_PROC_FS ++ err = -ENOMEM; ++ ve->proc_sys_root = proc_mkdir("sys", NULL); ++ if (ve->proc_sys_root == NULL) ++ goto out_proc; ++ ve->proc_sys_root->proc_iops = &proc_sys_inode_operations; ++ ve->proc_sys_root->proc_fops = &proc_sys_file_operations; ++ ve->proc_sys_root->nlink = 0; ++#endif ++ INIT_LIST_HEAD(&ve->sysctl_lh); ++ ++ err = devinet_sysctl_init(ve); ++ if (err) ++ goto out_dev; ++ ++ err = addrconf_sysctl_init(ve); ++ if (err) ++ goto out_dev6; ++ ++ return 0; ++ ++out_dev6: ++ devinet_sysctl_fini(ve); ++out_dev: ++#ifdef CONFIG_PROC_FS ++ remove_proc_entry("sys", NULL); ++out_proc: ++#endif ++ return err; ++} ++ ++static void fini_ve_sysctl(struct ve_struct *ve) ++{ ++ addrconf_sysctl_fini(ve); ++ devinet_sysctl_fini(ve); ++ remove_proc_entry("sys", NULL); ++} ++ ++static void free_ve_sysctl(struct ve_struct *ve) ++{ ++ addrconf_sysctl_free(ve); ++ devinet_sysctl_free(ve); ++} ++#else ++#define init_ve_sysctl(ve) (0) ++#define fini_ve_sysctl(ve) do { } while (0) ++#define free_ve_sysctl(ve) do { } while (0) ++#endif ++ ++#ifdef CONFIG_UNIX98_PTYS ++#include ++ ++/* ++ * DEVPTS needs a virtualization: each environment should see each own list of ++ * pseudo-terminals. ++ * To implement it we need to have separate devpts superblocks for each ++ * VE, and each VE should mount its own one. ++ * Thus, separate vfsmount structures are required. ++ * To minimize intrusion into vfsmount lookup code, separate file_system_type ++ * structures are created. ++ * ++ * In addition to this, patch fo character device itself is required, as file ++ * system itself is used only for MINOR/MAJOR lookup. ++ */ ++ ++static int init_ve_devpts(struct ve_struct *ve) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ ve->devpts_config = kzalloc(sizeof(struct devpts_config), GFP_KERNEL); ++ if (ve->devpts_config == NULL) ++ goto out; ++ ++ ve->devpts_config->mode = 0600; ++ err = register_ve_fs_type(ve, &devpts_fs_type, ++ &ve->devpts_fstype, &ve->devpts_mnt); ++ if (err) { ++ kfree(ve->devpts_config); ++ ve->devpts_config = NULL; ++ } ++out: ++ return err; ++} ++ ++static void fini_ve_devpts(struct ve_struct *ve) ++{ ++ unregister_ve_fs_type(ve->devpts_fstype, ve->devpts_mnt); ++ /* devpts_fstype is freed in real_put_ve -> free_ve_filesystems */ ++ ve->devpts_mnt = NULL; ++ kfree(ve->devpts_config); ++ ve->devpts_config = NULL; ++} ++#else ++#define init_ve_devpts(ve) (0) ++#define fini_ve_devpts(ve) do { } while (0) ++#endif ++ ++static int init_ve_shmem(struct ve_struct *ve) ++{ ++ return register_ve_fs_type(ve, ++ &tmpfs_fs_type, ++ &ve->shmem_fstype, ++ &ve->shmem_mnt); ++} ++ ++static void fini_ve_shmem(struct ve_struct *ve) ++{ ++ unregister_ve_fs_type(ve->shmem_fstype, ve->shmem_mnt); ++ /* shmem_fstype is freed in real_put_ve -> free_ve_filesystems */ ++ ve->shmem_mnt = NULL; ++} ++ ++static inline int init_ve_sysfs_root(struct ve_struct *ve) ++{ ++ struct sysfs_dirent *sysfs_root; ++ ++ sysfs_root = kzalloc(sizeof(struct sysfs_dirent), GFP_KERNEL); ++ if (sysfs_root == NULL) ++ return -ENOMEM; ++ sysfs_root->s_name = ""; ++ atomic_set(&sysfs_root->s_count, 1); ++ sysfs_root->s_flags = SYSFS_DIR; ++ sysfs_root->s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; ++ sysfs_root->s_ino = 1; ++ ++ ve->_sysfs_root = sysfs_root; ++ return 0; ++} ++ ++#if defined(CONFIG_NET) && defined(CONFIG_SYSFS) ++extern struct device_attribute ve_net_class_attributes[]; ++static inline int init_ve_netclass(struct ve_struct *ve) ++{ ++ struct class *nc; ++ int err; ++ ++ nc = kzalloc(sizeof(*nc), GFP_KERNEL); ++ if (!nc) ++ return -ENOMEM; ++ ++ nc->name = net_class.name; ++ nc->dev_release = net_class.dev_release; ++ nc->uevent = net_class.uevent; ++ nc->dev_attrs = ve_net_class_attributes; ++ ++ err = class_register(nc); ++ if (!err) { ++ ve->net_class = nc; ++ return 0; ++ } ++ kfree(nc); ++ return err; ++} ++ ++static inline void fini_ve_netclass(struct ve_struct *ve) ++{ ++ class_unregister(ve->net_class); ++ kfree(ve->net_class); ++ ve->net_class = NULL; ++} ++#else ++static inline int init_ve_netclass(struct ve_struct *ve) { return 0; } ++static inline void fini_ve_netclass(struct ve_struct *ve) { ; } ++#endif ++ ++extern struct kset devices_subsys; ++ ++static int init_ve_sysfs(struct ve_struct *ve) ++{ ++ struct kset *subsys; ++ int err; ++ ++#ifdef CONFIG_SYSFS ++ err = 0; ++ if (ve->features & VE_FEATURE_SYSFS) { ++ err = init_ve_sysfs_root(ve); ++ if (err != 0) ++ goto out; ++ err = register_ve_fs_type(ve, ++ &sysfs_fs_type, ++ &ve->sysfs_fstype, ++ &ve->sysfs_mnt); ++ } ++ if (err != 0) ++ goto out_fs_type; ++#endif ++ err = -ENOMEM; ++ subsys = kzalloc(sizeof(*subsys), GFP_KERNEL); ++ ve->class_obj_subsys = subsys; ++ if (subsys == NULL) ++ goto out_class_obj; ++ /* ick, this is ugly, the things we go through to keep from showing up ++ * in sysfs... */ ++ subsys->kobj.k_name = kstrdup(class_obj_subsys.kobj.k_name, GFP_KERNEL); ++ if (!subsys->kobj.k_name) ++ goto out_subsys1; ++ subsys->ktype = class_obj_subsys.ktype; ++ subsys->uevent_ops = class_obj_subsys.uevent_ops; ++ kset_init(subsys); ++ if (!subsys->kobj.parent) ++ subsys->kobj.parent = &subsys->kobj; ++ ++ subsys = kzalloc(sizeof(*subsys), GFP_KERNEL); ++ ve->class_subsys = subsys; ++ if (subsys == NULL) ++ goto out_class_subsys; ++ /* ick, this is ugly, the things we go through to keep from showing up ++ * in sysfs... */ ++ subsys->kobj.k_name = kstrdup(class_subsys.kobj.k_name, GFP_KERNEL); ++ if (!subsys->kobj.k_name) ++ goto out_subsys2; ++ subsys->ktype = class_subsys.ktype; ++ subsys->uevent_ops = class_subsys.uevent_ops; ++ ++ err = subsystem_register(subsys); ++ if (err != 0) ++ goto out_register; ++ ++ subsys = kzalloc(sizeof(*subsys), GFP_KERNEL); ++ ve->devices_subsys = subsys; ++ if (!subsys) ++ goto out_subsys3; ++ subsys->kobj.k_name = kstrdup(devices_subsys.kobj.k_name, GFP_KERNEL); ++ if (!subsys->kobj.k_name) ++ goto out_subsys4; ++ subsys->ktype = devices_subsys.ktype; ++ subsys->uevent_ops = devices_subsys.uevent_ops; ++ ++ err = subsystem_register(subsys); ++ if (err < 0) ++ goto out_register2; ++ ++ err = init_ve_netclass(ve); ++ if (err) ++ goto out_nc; ++ ++ ve->tty_class = init_ve_tty_class(); ++ if (IS_ERR(ve->tty_class)) { ++ err = PTR_ERR(ve->tty_class); ++ ve->tty_class = NULL; ++ goto out_tty_class_register; ++ } ++ ++ return err; ++ ++out_tty_class_register: ++ fini_ve_netclass(ve); ++out_nc: ++ subsystem_unregister(ve->devices_subsys); ++out_register2: ++ kfree(ve->devices_subsys->kobj.k_name); ++out_subsys4: ++ kfree(ve->devices_subsys); ++out_subsys3: ++ subsystem_unregister(ve->class_subsys); ++out_register: ++ kfree(ve->class_subsys->kobj.k_name); ++out_subsys2: ++ kfree(ve->class_subsys); ++out_class_subsys: ++ kfree(ve->class_obj_subsys->kobj.k_name); ++out_subsys1: ++ kfree(ve->class_obj_subsys); ++out_class_obj: ++#ifdef CONFIG_SYSFS ++ unregister_ve_fs_type(ve->sysfs_fstype, ve->sysfs_mnt); ++ /* sysfs_fstype is freed in real_put_ve -> free_ve_filesystems */ ++out_fs_type: ++ kfree(ve->_sysfs_root); ++ ve->_sysfs_root = NULL; ++#endif ++ ve->class_subsys = NULL; ++ ve->class_obj_subsys = NULL; ++out: ++ return err; ++} ++ ++static void fini_ve_sysfs(struct ve_struct *ve) ++{ ++ fini_ve_tty_class(ve->tty_class); ++ fini_ve_netclass(ve); ++ subsystem_unregister(ve->devices_subsys); ++ subsystem_unregister(ve->class_subsys); ++ kfree(ve->devices_subsys->kobj.k_name); ++ kfree(ve->class_subsys->kobj.k_name); ++ kfree(ve->class_obj_subsys->kobj.k_name); ++ kfree(ve->devices_subsys); ++ kfree(ve->class_subsys); ++ kfree(ve->class_obj_subsys); ++ ++ ve->class_subsys = NULL; ++ ve->class_obj_subsys = NULL; ++#ifdef CONFIG_SYSFS ++ unregister_ve_fs_type(ve->sysfs_fstype, ve->sysfs_mnt); ++ ve->sysfs_mnt = NULL; ++ kfree(ve->_sysfs_root); ++ ve->_sysfs_root = NULL; ++ /* sysfs_fstype is freed in real_put_ve -> free_ve_filesystems */ ++#endif ++} ++ ++static void free_ve_filesystems(struct ve_struct *ve) ++{ ++#ifdef CONFIG_SYSFS ++ kfree(ve->sysfs_fstype); ++ ve->sysfs_fstype = NULL; ++#endif ++ kfree(ve->shmem_fstype); ++ ve->shmem_fstype = NULL; ++ ++ kfree(ve->devpts_fstype); ++ ve->devpts_fstype = NULL; ++ ++ free_ve_proc(ve); ++} ++ ++static int init_printk(struct ve_struct *ve) ++{ ++ struct ve_prep_printk { ++ wait_queue_head_t log_wait; ++ unsigned long log_start; ++ unsigned long log_end; ++ unsigned long logged_chars; ++ } *tmp; ++ ++ tmp = kzalloc(sizeof(struct ve_prep_printk), GFP_KERNEL); ++ if (!tmp) ++ return -ENOMEM; ++ ++ init_waitqueue_head(&tmp->log_wait); ++ ve->_log_wait = &tmp->log_wait; ++ ve->_log_start = &tmp->log_start; ++ ve->_log_end = &tmp->log_end; ++ ve->_logged_chars = &tmp->logged_chars; ++ /* ve->log_buf will be initialized later by ve_log_init() */ ++ return 0; ++} ++ ++static void fini_printk(struct ve_struct *ve) ++{ ++ /* ++ * there is no spinlock protection here because nobody can use ++ * log_buf at the moments when this code is called. ++ */ ++ kfree(ve->log_buf); ++ kfree(ve->_log_wait); ++} ++ ++static void fini_venet(struct ve_struct *ve) ++{ ++#ifdef CONFIG_INET ++ tcp_v4_kill_ve_sockets(ve); ++ ve_mapped_devs_cleanup(ve); ++ synchronize_net(); ++#endif ++} ++ ++static int init_ve_sched(struct ve_struct *ve) ++{ ++#ifdef CONFIG_FAIRSCHED ++ int err; ++ ++ /* ++ * We refuse to switch to an already existing node since nodes ++ * keep a pointer to their ve_struct... ++ */ ++ err = sys_fairsched_mknod(0, 1, ve->veid); ++ if (err < 0) { ++ printk(KERN_WARNING "Can't create fairsched node %d\n", ++ ve->veid); ++ return err; ++ } ++ err = sys_fairsched_mvpr(current->pid, ve->veid); ++ if (err) { ++ printk(KERN_WARNING "Can't switch to fairsched node %d\n", ++ ve->veid); ++ if (sys_fairsched_rmnod(ve->veid)) ++ printk(KERN_ERR "Can't clean fairsched node %d\n", ++ ve->veid); ++ return err; ++ } ++#endif ++ ve_sched_attach(ve); ++ return 0; ++} ++ ++static void fini_ve_sched(struct ve_struct *ve) ++{ ++#ifdef CONFIG_FAIRSCHED ++ if (task_vsched_id(current) == ve->veid) ++ if (sys_fairsched_mvpr(current->pid, fairsched_init_node.id)) ++ printk(KERN_WARNING "Can't leave fairsched node %d\n", ++ ve->veid); ++ if (sys_fairsched_rmnod(ve->veid)) ++ printk(KERN_ERR "Can't remove fairsched node %d\n", ++ ve->veid); ++#endif ++} ++ ++/* ++ * Namespaces ++ */ ++ ++static inline int init_ve_namespaces(struct ve_struct *ve, ++ struct nsproxy **old) ++{ ++ int err; ++ struct task_struct *tsk; ++ struct nsproxy *cur; ++ ++ tsk = current; ++ cur = tsk->nsproxy; ++ ++ err = copy_namespaces(CLONE_NAMESPACES_MASK & ~CLONE_NEWNET, tsk); ++ if (err < 0) ++ return err; ++ ++ ve->ve_ns = get_nsproxy(tsk->nsproxy); ++ memcpy(ve->ve_ns->uts_ns->name.release, virt_utsname.release, ++ sizeof(virt_utsname.release)); ++ *old = cur; ++ return 0; ++} ++ ++static inline void fini_ve_namespaces(struct ve_struct *ve, ++ struct nsproxy *old) ++{ ++ struct task_struct *tsk = current; ++ struct nsproxy *tmp; ++ ++ if (old) { ++ tmp = tsk->nsproxy; ++ tsk->nsproxy = get_nsproxy(old); ++ put_nsproxy(tmp); ++ tmp = ve->ve_ns; ++ ve->ve_ns = get_nsproxy(old); ++ put_nsproxy(tmp); ++ } else { ++ put_nsproxy(ve->ve_ns); ++ ve->ve_ns = NULL; ++ } ++} ++ ++static int init_ve_netns(struct ve_struct *ve, struct nsproxy **old) ++{ ++ int err; ++ struct task_struct *tsk; ++ struct nsproxy *cur; ++ ++ tsk = current; ++ cur = tsk->nsproxy; ++ ++ err = copy_namespaces(CLONE_NEWNET, tsk); ++ if (err < 0) ++ return err; ++ ++ put_nsproxy(ve->ve_ns); ++ ve->ve_ns = get_nsproxy(tsk->nsproxy); ++ *old = cur; ++ return 0; ++} ++ ++static inline void switch_ve_namespaces(struct ve_struct *ve, ++ struct task_struct *tsk) ++{ ++ struct nsproxy *old_ns; ++ struct nsproxy *new_ns; ++ ++ BUG_ON(tsk != current); ++ old_ns = tsk->nsproxy; ++ new_ns = ve->ve_ns; ++ ++ if (old_ns != new_ns) { ++ tsk->nsproxy = get_nsproxy(new_ns); ++ put_nsproxy(old_ns); ++ } ++} ++ ++static __u64 get_ve_features(env_create_param_t *data, int datalen) ++{ ++ __u64 known_features; ++ ++ if (datalen < sizeof(struct env_create_param3)) ++ /* this version of vzctl is aware of VE_FEATURES_OLD only */ ++ known_features = VE_FEATURES_OLD; ++ else ++ known_features = data->known_features; ++ ++ /* ++ * known features are set as required ++ * yet unknown features are set as in VE_FEATURES_DEF ++ */ ++ return (data->feature_mask & known_features) | ++ (VE_FEATURES_DEF & ~known_features); ++} ++ ++static int init_ve_struct(struct ve_struct *ve, envid_t veid, ++ u32 class_id, env_create_param_t *data, int datalen) ++{ ++ (void)get_ve(ve); ++ ve->veid = veid; ++ ve->class_id = class_id; ++ ve->features = get_ve_features(data, datalen); ++ INIT_LIST_HEAD(&ve->vetask_lh); ++ init_rwsem(&ve->op_sem); ++ ++ ve->start_timespec = current->start_time; ++ /* The value is wrong, but it is never compared to process ++ * start times */ ++ ve->start_jiffies = get_jiffies_64(); ++ ve->start_cycles = get_cycles(); ++ ++ return 0; ++} ++ ++/********************************************************************** ++ ********************************************************************** ++ * ++ * /proc/meminfo virtualization ++ * ++ ********************************************************************** ++ **********************************************************************/ ++static int ve_set_meminfo(envid_t veid, unsigned long val) ++{ ++#ifdef CONFIG_BEANCOUNTERS ++ struct ve_struct *ve; ++ ++ ve = get_ve_by_id(veid); ++ if (!ve) ++ return -EINVAL; ++ ++ ve->meminfo_val = val; ++ real_put_ve(ve); ++ return 0; ++#else ++ return -ENOTTY; ++#endif ++} ++ ++static int init_ve_meminfo(struct ve_struct *ve) ++{ ++ ve->meminfo_val = 0; ++ return 0; ++} ++ ++static inline void fini_ve_meminfo(struct ve_struct *ve) ++{ ++} ++ ++static void set_ve_root(struct ve_struct *ve, struct task_struct *tsk) ++{ ++ read_lock(&tsk->fs->lock); ++ ve->fs_rootmnt = tsk->fs->rootmnt; ++ ve->fs_root = tsk->fs->root; ++ read_unlock(&tsk->fs->lock); ++ mark_tree_virtual(ve->fs_rootmnt, ve->fs_root); ++} ++ ++static void set_ve_caps(struct ve_struct *ve, struct task_struct *tsk) ++{ ++ /* required for real_setdevperms from register_ve_ above */ ++ memcpy(&ve->ve_cap_bset, &tsk->cap_effective, sizeof(kernel_cap_t)); ++ cap_lower(ve->ve_cap_bset, CAP_SETVEID); ++} ++ ++static int ve_list_add(struct ve_struct *ve) ++{ ++ write_lock_irq(&ve_list_lock); ++ if (__find_ve_by_id(ve->veid) != NULL) ++ goto err_exists; ++ ++ list_add(&ve->ve_list, &ve_list_head); ++ nr_ve++; ++ write_unlock_irq(&ve_list_lock); ++ return 0; ++ ++err_exists: ++ write_unlock_irq(&ve_list_lock); ++ return -EEXIST; ++} ++ ++static void ve_list_del(struct ve_struct *ve) ++{ ++ write_lock_irq(&ve_list_lock); ++ list_del(&ve->ve_list); ++ nr_ve--; ++ write_unlock_irq(&ve_list_lock); ++} ++ ++static void set_task_ve_caps(struct task_struct *tsk, struct ve_struct *ve) ++{ ++ spin_lock(&task_capability_lock); ++ cap_mask(tsk->cap_effective, ve->ve_cap_bset); ++ cap_mask(tsk->cap_inheritable, ve->ve_cap_bset); ++ cap_mask(tsk->cap_permitted, ve->ve_cap_bset); ++ spin_unlock(&task_capability_lock); ++} ++ ++void ve_move_task(struct task_struct *tsk, struct ve_struct *new) ++{ ++ struct ve_struct *old; ++ ++ might_sleep(); ++ BUG_ON(tsk != current); ++ BUG_ON(!(thread_group_leader(tsk) && thread_group_empty(tsk))); ++ ++ /* this probihibts ptracing of task entered to VE from host system */ ++ tsk->mm->vps_dumpable = 0; ++ /* setup capabilities before enter */ ++ set_task_ve_caps(tsk, new); ++ ++ old = tsk->ve_task_info.owner_env; ++ tsk->ve_task_info.owner_env = new; ++ tsk->ve_task_info.exec_env = new; ++ ++ write_lock_irq(&tasklist_lock); ++ list_del_rcu(&tsk->ve_task_info.vetask_list); ++ write_unlock_irq(&tasklist_lock); ++ ++ synchronize_rcu(); ++ ++ write_lock_irq(&tasklist_lock); ++ list_add_tail_rcu(&tsk->ve_task_info.vetask_list, ++ &new->vetask_lh); ++ write_unlock_irq(&tasklist_lock); ++ ++ atomic_dec(&old->pcounter); ++ real_put_ve(old); ++ ++ atomic_inc(&new->pcounter); ++ get_ve(new); ++} ++ ++EXPORT_SYMBOL(ve_move_task); ++ ++#ifdef CONFIG_VE_IPTABLES ++extern int init_netfilter(void); ++extern void fini_netfilter(void); ++#define init_ve_netfilter() init_netfilter() ++#define fini_ve_netfilter() fini_netfilter() ++ ++#define KSYMIPTINIT(mask, ve, full_mask, mod, name, args) \ ++({ \ ++ int ret = 0; \ ++ if (VE_IPT_CMP(mask, full_mask) && \ ++ VE_IPT_CMP((ve)->_iptables_modules, \ ++ full_mask & ~(full_mask##_MOD))) { \ ++ ret = KSYMERRCALL(1, mod, name, args); \ ++ if (ret == 0) \ ++ (ve)->_iptables_modules |= \ ++ full_mask##_MOD; \ ++ if (ret == 1) \ ++ ret = 0; \ ++ } \ ++ ret; \ ++}) ++ ++#define KSYMIPTFINI(mask, full_mask, mod, name, args) \ ++({ \ ++ if (VE_IPT_CMP(mask, full_mask##_MOD)) \ ++ KSYMSAFECALL_VOID(mod, name, args); \ ++}) ++ ++ ++static int do_ve_iptables(struct ve_struct *ve, __u64 init_mask, ++ int init_or_cleanup) ++{ ++ int err; ++ ++ /* Remove when userspace will start supplying IPv6-related bits. */ ++ init_mask &= ~VE_IP_IPTABLES6; ++ init_mask &= ~VE_IP_FILTER6; ++ init_mask &= ~VE_IP_MANGLE6; ++ init_mask &= ~VE_IP_IPTABLE_NAT_MOD; ++ init_mask &= ~VE_NF_CONNTRACK_MOD; ++ if ((init_mask & VE_IP_IPTABLES) == VE_IP_IPTABLES) ++ init_mask |= VE_IP_IPTABLES6; ++ if ((init_mask & VE_IP_FILTER) == VE_IP_FILTER) ++ init_mask |= VE_IP_FILTER6; ++ if ((init_mask & VE_IP_MANGLE) == VE_IP_MANGLE) ++ init_mask |= VE_IP_MANGLE6; ++ if ((init_mask & VE_IP_NAT) == VE_IP_NAT) ++ init_mask |= VE_IP_IPTABLE_NAT; ++ ++ if ((init_mask & VE_IP_CONNTRACK) == VE_IP_CONNTRACK) ++ init_mask |= VE_NF_CONNTRACK; ++ ++ err = 0; ++ if (!init_or_cleanup) ++ goto cleanup; ++ ++ /* init part */ ++#if defined(CONFIG_IP_NF_IPTABLES) || \ ++ defined(CONFIG_IP_NF_IPTABLES_MODULE) ++ err = KSYMIPTINIT(init_mask, ve, VE_IP_IPTABLES, ++ ip_tables, init_iptables, ()); ++ if (err < 0) ++ goto err_iptables; ++#endif ++#if defined(CONFIG_IP6_NF_IPTABLES) || \ ++ defined(CONFIG_IP6_NF_IPTABLES_MODULE) ++ err = KSYMIPTINIT(init_mask, ve, VE_IP_IPTABLES6, ++ ip6_tables, init_ip6tables, ()); ++ if (err < 0) ++ goto err_ip6tables; ++#endif ++#if defined(CONFIG_NF_CONNTRACK_IPV4) || \ ++ defined(CONFIG_NF_CONNTRACK_IPV4_MODULE) ++ err = KSYMIPTINIT(init_mask, ve, VE_NF_CONNTRACK, ++ nf_conntrack, nf_conntrack_init_ve, ()); ++ if (err < 0) ++ goto err_nf_conntrack; ++ ++ err = KSYMIPTINIT(init_mask, ve, VE_IP_CONNTRACK, ++ nf_conntrack_ipv4, init_nf_ct_l3proto_ipv4, ()); ++ if (err < 0) ++ goto err_nf_conntrack_ipv4; ++#endif ++#if defined(CONFIG_NF_NAT) || \ ++ defined(CONFIG_NF_NAT_MODULE) ++ err = KSYMIPTINIT(init_mask, ve, VE_IP_NAT, ++ nf_nat, nf_nat_init, ()); ++ if (err < 0) ++ goto err_nftable_nat; ++ err = KSYMIPTINIT(init_mask, ve, VE_IP_IPTABLE_NAT, ++ iptable_nat, init_nftable_nat, ()); ++ if (err < 0) ++ goto err_nftable_nat2; ++#endif ++#if defined(CONFIG_IP_NF_FILTER) || \ ++ defined(CONFIG_IP_NF_FILTER_MODULE) ++ err = KSYMIPTINIT(init_mask, ve, VE_IP_FILTER, ++ iptable_filter, init_iptable_filter, ()); ++ if (err < 0) ++ goto err_iptable_filter; ++#endif ++#if defined(CONFIG_IP6_NF_FILTER) || \ ++ defined(CONFIG_IP6_NF_FILTER_MODULE) ++ err = KSYMIPTINIT(init_mask, ve, VE_IP_FILTER6, ++ ip6table_filter, init_ip6table_filter, ()); ++ if (err < 0) ++ goto err_ip6table_filter; ++#endif ++#if defined(CONFIG_IP_NF_MANGLE) || \ ++ defined(CONFIG_IP_NF_MANGLE_MODULE) ++ err = KSYMIPTINIT(init_mask, ve, VE_IP_MANGLE, ++ iptable_mangle, init_iptable_mangle, ()); ++ if (err < 0) ++ goto err_iptable_mangle; ++#endif ++#if defined(CONFIG_IP6_NF_MANGLE) || \ ++ defined(CONFIG_IP6_NF_MANGLE_MODULE) ++ err = KSYMIPTINIT(init_mask, ve, VE_IP_MANGLE6, ++ ip6table_mangle, init_ip6table_mangle, ()); ++ if (err < 0) ++ goto err_ip6table_mangle; ++#endif ++ return 0; ++ ++/* ------------------------------------------------------------------------- */ ++ ++cleanup: ++#if defined(CONFIG_IP6_NF_MANGLE) || \ ++ defined(CONFIG_IP6_NF_MANGLE_MODULE) ++ KSYMIPTFINI(ve->_iptables_modules, VE_IP_MANGLE6, ++ ip6table_mangle, fini_ip6table_mangle, ()); ++err_ip6table_mangle: ++#endif ++#if defined(CONFIG_IP_NF_MANGLE) || \ ++ defined(CONFIG_IP_NF_MANGLE_MODULE) ++ KSYMIPTFINI(ve->_iptables_modules, VE_IP_MANGLE, ++ iptable_mangle, fini_iptable_mangle, ()); ++err_iptable_mangle: ++#endif ++#if defined(CONFIG_IP6_NF_FILTER) || \ ++ defined(CONFIG_IP6_NF_FILTER_MODULE) ++ KSYMIPTFINI(ve->_iptables_modules, VE_IP_FILTER6, ++ ip6table_filter, fini_ip6table_filter, ()); ++err_ip6table_filter: ++#endif ++#if defined(CONFIG_IP_NF_FILTER) || \ ++ defined(CONFIG_IP_NF_FILTER_MODULE) ++ KSYMIPTFINI(ve->_iptables_modules, VE_IP_FILTER, ++ iptable_filter, fini_iptable_filter, ()); ++err_iptable_filter: ++#endif ++#if defined(CONFIG_NF_NAT) || \ ++ defined(CONFIG_NF_NAT_MODULE) ++ KSYMIPTFINI(ve->_iptables_modules, VE_IP_IPTABLE_NAT, ++ iptable_nat, fini_nftable_nat, ()); ++err_nftable_nat2: ++ KSYMIPTFINI(ve->_iptables_modules, VE_IP_NAT, ++ nf_nat, nf_nat_cleanup, ()); ++err_nftable_nat: ++#endif ++#if defined(CONFIG_NF_CONNTRACK_IPV4) || \ ++ defined(CONFIG_NF_CONNTRACK_IPV4_MODULE) ++ KSYMIPTFINI(ve->_iptables_modules, VE_IP_CONNTRACK, ++ nf_conntrack_ipv4, fini_nf_ct_l3proto_ipv4, ()); ++err_nf_conntrack_ipv4: ++ KSYMIPTFINI(ve->_iptables_modules, VE_NF_CONNTRACK, ++ nf_conntrack, nf_conntrack_cleanup_ve, ()); ++err_nf_conntrack: ++#endif ++#if defined(CONFIG_IP6_NF_IPTABLES) || \ ++ defined(CONFIG_IP6_NF_IPTABLES_MODULE) ++ KSYMIPTFINI(ve->_iptables_modules, VE_IP_IPTABLES6, ++ ip6_tables, fini_ip6tables, ()); ++err_ip6tables: ++#endif ++#if defined(CONFIG_IP_NF_IPTABLES) || \ ++ defined(CONFIG_IP_NF_IPTABLES_MODULE) ++ KSYMIPTFINI(ve->_iptables_modules, VE_IP_IPTABLES, ++ ip_tables, fini_iptables, ()); ++err_iptables: ++#endif ++ ve->_iptables_modules = 0; ++ ++ return err; ++} ++ ++static inline int init_ve_iptables(struct ve_struct *ve, __u64 init_mask) ++{ ++ return do_ve_iptables(ve, init_mask, 1); ++} ++ ++static inline void fini_ve_iptables(struct ve_struct *ve, __u64 init_mask) ++{ ++ (void)do_ve_iptables(ve, init_mask, 0); ++} ++ ++#else ++#define init_ve_iptables(x, y) (0) ++#define fini_ve_iptables(x, y) do { } while (0) ++#define init_ve_netfilter() (0) ++#define fini_ve_netfilter() do { } while (0) ++#endif ++ ++static inline int init_ve_cpustats(struct ve_struct *ve) ++{ ++ ve->cpu_stats = alloc_percpu(struct ve_cpu_stats); ++ return ve->cpu_stats == NULL ? -ENOMEM : 0; ++} ++ ++static inline void free_ve_cpustats(struct ve_struct *ve) ++{ ++ free_percpu(ve->cpu_stats); ++ ve->cpu_stats = NULL; ++} ++ ++static int alone_in_pgrp(struct task_struct *tsk) ++{ ++ struct task_struct *p; ++ int alone = 0; ++ ++ read_lock(&tasklist_lock); ++ do_each_pid_task(task_pid(tsk), PIDTYPE_PGID, p) { ++ if (p != tsk) ++ goto out; ++ } while_each_pid_task(task_pid(tsk), PIDTYPE_PGID, p); ++ do_each_pid_task(task_pid(tsk), PIDTYPE_SID, p) { ++ if (p != tsk) ++ goto out; ++ } while_each_pid_task(task_pid(tsk), PIDTYPE_SID, p); ++ alone = 1; ++out: ++ read_unlock(&tasklist_lock); ++ return alone; ++} ++ ++static int do_env_create(envid_t veid, unsigned int flags, u32 class_id, ++ env_create_param_t *data, int datalen) ++{ ++ struct task_struct *tsk; ++ struct ve_struct *old; ++ struct ve_struct *old_exec; ++ struct ve_struct *ve; ++ __u64 init_mask; ++ int err; ++ struct nsproxy *old_ns, *old_ns_net; ++ DECLARE_COMPLETION_ONSTACK(sysfs_completion); ++ ++ tsk = current; ++ old = VE_TASK_INFO(tsk)->owner_env; ++ ++ if (!thread_group_leader(tsk) || !thread_group_empty(tsk)) ++ return -EINVAL; ++ ++ if (tsk->signal->tty) { ++ printk("ERR: CT init has controlling terminal\n"); ++ return -EINVAL; ++ } ++ if (task_pgrp(tsk) != task_pid(tsk) || ++ task_session(tsk) != task_pid(tsk)) { ++ int may_setsid; ++ ++ read_lock(&tasklist_lock); ++ may_setsid = !tsk->signal->leader && ++ !find_task_by_pid_type_ns(PIDTYPE_PGID, task_pid_nr(tsk), &init_pid_ns); ++ read_unlock(&tasklist_lock); ++ ++ if (!may_setsid) { ++ printk("ERR: CT init is process group leader\n"); ++ return -EINVAL; ++ } ++ } ++ /* Check that the process is not a leader of non-empty group/session. ++ * If it is, we cannot virtualize its PID and must fail. */ ++ if (!alone_in_pgrp(tsk)) { ++ printk("ERR: CT init is not alone in process group\n"); ++ return -EINVAL; ++ } ++ ++ ++ VZTRACE("%s: veid=%d classid=%d pid=%d\n", ++ __FUNCTION__, veid, class_id, current->pid); ++ ++ err = -ENOMEM; ++ ve = kzalloc(sizeof(struct ve_struct), GFP_KERNEL); ++ if (ve == NULL) ++ goto err_struct; ++ ++ init_ve_struct(ve, veid, class_id, data, datalen); ++ __module_get(THIS_MODULE); ++ down_write(&ve->op_sem); ++ if (flags & VE_LOCK) ++ ve->is_locked = 1; ++ ++ /* ++ * this should be done before adding to list ++ * because if calc_load_ve finds this ve in ++ * list it will be very surprised ++ */ ++ if ((err = init_ve_cpustats(ve)) < 0) ++ goto err_cpu_stats; ++ ++ if ((err = ve_list_add(ve)) < 0) ++ goto err_exist; ++ ++ /* this should be done before context switching */ ++ if ((err = init_printk(ve)) < 0) ++ goto err_log_wait; ++ ++ old_exec = set_exec_env(ve); ++ ++ if ((err = init_ve_sched(ve)) < 0) ++ goto err_sched; ++ ++ set_ve_root(ve, tsk); ++ ++ if ((err = init_ve_sysfs(ve))) ++ goto err_sysfs; ++ ++ if ((err = init_ve_mibs(ve))) ++ goto err_mibs; ++ ++ if ((err = init_ve_namespaces(ve, &old_ns))) ++ goto err_ns; ++ ++ if ((err = init_ve_proc(ve))) ++ goto err_proc; ++ ++ if ((err = init_ve_sysctl(ve))) ++ goto err_sysctl; ++ ++ if ((err = init_ve_route(ve)) < 0) ++ goto err_route; ++ ++ if ((err = init_ve_route6(ve)) < 0) ++ goto err_route6; ++ ++ if ((err = init_ve_netns(ve, &old_ns_net))) ++ goto err_netns; ++ ++ if ((err = init_ve_tty_drivers(ve)) < 0) ++ goto err_tty; ++ ++ if ((err = init_ve_shmem(ve))) ++ goto err_shmem; ++ ++ if ((err = init_ve_devpts(ve))) ++ goto err_devpts; ++ ++ if((err = init_ve_meminfo(ve))) ++ goto err_meminf; ++ ++ set_ve_caps(ve, tsk); ++ ++ /* It is safe to initialize netfilter here as routing initialization and ++ interface setup will be done below. This means that NO skb can be ++ passed inside. Den */ ++ /* iptables ve initialization for non ve0; ++ ve0 init is in module_init */ ++ if ((err = init_ve_netfilter()) < 0) ++ goto err_netfilter; ++ ++ init_mask = data ? data->iptables_mask : VE_IP_DEFAULT; ++ if ((err = init_ve_iptables(ve, init_mask)) < 0) ++ goto err_iptables; ++ ++ if ((err = pid_ns_attach_init(ve->ve_ns->pid_ns, tsk)) < 0) ++ goto err_vpid; ++ ++ if ((err = ve_hook_iterate_init(VE_SS_CHAIN, ve)) < 0) ++ goto err_ve_hook; ++ ++ put_nsproxy(old_ns); ++ put_nsproxy(old_ns_net); ++ ++ /* finally: set vpids and move inside */ ++ ve_move_task(tsk, ve); ++ grsecurity_setup(); ++ ++ ve->is_running = 1; ++ up_write(&ve->op_sem); ++ ++ printk(KERN_INFO "CT: %d: started\n", veid); ++ return veid; ++ ++err_ve_hook: ++ mntget(ve->proc_mnt); ++err_vpid: ++ fini_venet(ve); ++ fini_ve_iptables(ve, init_mask); ++err_iptables: ++ fini_ve_netfilter(); ++err_netfilter: ++ fini_ve_meminfo(ve); ++err_meminf: ++ fini_ve_devpts(ve); ++err_devpts: ++ fini_ve_shmem(ve); ++err_shmem: ++ fini_ve_tty_drivers(ve); ++err_tty: ++ ve->ve_ns->net_ns->sysfs_completion = &sysfs_completion; ++ fini_ve_namespaces(ve, old_ns_net); ++ put_nsproxy(old_ns_net); ++ wait_for_completion(&sysfs_completion); ++err_netns: ++ fini_ve_route6(ve); ++err_route6: ++ fini_ve_route(ve); ++err_route: ++ fini_ve_sysctl(ve); ++err_sysctl: ++ /* ++ * If process hasn't become VE's init, proc_mnt won't be put during ++ * pidns death, so this mntput by hand is needed. If it has, we ++ * compensate with mntget above. ++ */ ++ mntput(ve->proc_mnt); ++ fini_ve_proc(ve); ++err_proc: ++ /* free_ve_utsname() is called inside real_put_ve() */ ++ fini_ve_namespaces(ve, old_ns); ++ put_nsproxy(old_ns); ++ /* ++ * We need to compensate, because fini_ve_namespaces() assumes ++ * ve->ve_ns will continue to be used after, but VE will be freed soon ++ * (in kfree() sense). ++ */ ++ put_nsproxy(ve->ve_ns); ++err_ns: ++ clean_device_perms_ve(ve->veid); ++ fini_ve_mibs(ve); ++err_mibs: ++ fini_ve_sysfs(ve); ++err_sysfs: ++ /* It is safe to restore current->envid here because ++ * ve_fairsched_detach does not use current->envid. */ ++ /* Really fairsched code uses current->envid in sys_fairsched_mknod ++ * only. It is correct if sys_fairsched_mknod is called from ++ * userspace. If sys_fairsched_mknod is called from ++ * ve_fairsched_attach, then node->envid and node->parent_node->envid ++ * are explicitly set to valid value after the call. */ ++ /* FIXME */ ++ VE_TASK_INFO(tsk)->owner_env = old; ++ VE_TASK_INFO(tsk)->exec_env = old_exec; ++ ++ fini_ve_sched(ve); ++err_sched: ++ (void)set_exec_env(old_exec); ++ ++ /* we can jump here having incorrect envid */ ++ VE_TASK_INFO(tsk)->owner_env = old; ++ fini_printk(ve); ++err_log_wait: ++ /* cpustats will be freed in do_env_free */ ++ ve_list_del(ve); ++ up_write(&ve->op_sem); ++ ++ real_put_ve(ve); ++err_struct: ++ printk(KERN_INFO "CT: %d: failed to start with err=%d\n", veid, err); ++ return err; ++ ++err_exist: ++ free_ve_cpustats(ve); ++err_cpu_stats: ++ kfree(ve); ++ goto err_struct; ++} ++ ++ ++/********************************************************************** ++ ********************************************************************** ++ * ++ * VE start/stop callbacks ++ * ++ ********************************************************************** ++ **********************************************************************/ ++ ++int real_env_create(envid_t veid, unsigned flags, u32 class_id, ++ env_create_param_t *data, int datalen) ++{ ++ int status; ++ struct ve_struct *ve; ++ ++ if (!flags) { ++ status = get_exec_env()->veid; ++ goto out; ++ } ++ ++ status = -EPERM; ++ if (!capable(CAP_SETVEID)) ++ goto out; ++ ++ status = -EINVAL; ++ if ((flags & VE_TEST) && (flags & (VE_ENTER|VE_CREATE))) ++ goto out; ++ ++ status = -EINVAL; ++ ve = get_ve_by_id(veid); ++ if (ve) { ++ if (flags & VE_TEST) { ++ status = 0; ++ goto out_put; ++ } ++ if (flags & VE_EXCLUSIVE) { ++ status = -EACCES; ++ goto out_put; ++ } ++ if (flags & VE_CREATE) { ++ flags &= ~VE_CREATE; ++ flags |= VE_ENTER; ++ } ++ } else { ++ if (flags & (VE_TEST|VE_ENTER)) { ++ status = -ESRCH; ++ goto out; ++ } ++ } ++ ++ if (flags & VE_CREATE) { ++ status = do_env_create(veid, flags, class_id, data, datalen); ++ goto out; ++ } else if (flags & VE_ENTER) ++ status = do_env_enter(ve, flags); ++ ++ /* else: returning EINVAL */ ++ ++out_put: ++ real_put_ve(ve); ++out: ++ return status; ++} ++EXPORT_SYMBOL(real_env_create); ++ ++static int do_env_enter(struct ve_struct *ve, unsigned int flags) ++{ ++ struct task_struct *tsk = current; ++ int err; ++ ++ VZTRACE("%s: veid=%d\n", __FUNCTION__, ve->veid); ++ ++ err = -EBUSY; ++ down_read(&ve->op_sem); ++ if (!ve->is_running) ++ goto out_up; ++ if (ve->is_locked && !(flags & VE_SKIPLOCK)) ++ goto out_up; ++ err = -EINVAL; ++ if (!thread_group_leader(tsk) || !thread_group_empty(tsk)) ++ goto out_up; ++ ++#ifdef CONFIG_FAIRSCHED ++ err = sys_fairsched_mvpr(current->pid, ve->veid); ++ if (err) ++ goto out_up; ++#endif ++ ve_sched_attach(ve); ++ switch_ve_namespaces(ve, tsk); ++ ve_move_task(current, ve); ++ ++ /* Check that the process is not a leader of non-empty group/session. ++ * If it is, we cannot virtualize its PID. Do not fail, just leave ++ * it non-virtual. ++ */ ++ if (alone_in_pgrp(tsk) && !(flags & VE_SKIPLOCK)) ++ pid_ns_attach_task(ve->ve_ns->pid_ns, tsk); ++ ++ /* Unlike VE_CREATE, we do not setsid() in VE_ENTER. ++ * Process is allowed to be in an external group/session. ++ * If user space callers wants, it will do setsid() after ++ * VE_ENTER. ++ */ ++ err = VE_TASK_INFO(tsk)->owner_env->veid; ++ tsk->did_ve_enter = 1; ++ ++out_up: ++ up_read(&ve->op_sem); ++ return err; ++} ++ ++static void env_cleanup(struct ve_struct *ve) ++{ ++ struct ve_struct *old_ve; ++ DECLARE_COMPLETION_ONSTACK(sysfs_completion); ++ ++ VZTRACE("real_do_env_cleanup\n"); ++ ++ down_read(&ve->op_sem); ++ old_ve = set_exec_env(ve); ++ ++ ve_hook_iterate_fini(VE_SS_CHAIN, ve); ++ ++ fini_venet(ve); ++ ++ /* no new packets in flight beyond this point */ ++ /* skb hold dst_entry, and in turn lies in the ip fragment queue */ ++ ip_fragment_cleanup(ve); ++ ++ /* kill iptables */ ++ /* No skb belonging to VE can exist at this point as unregister_netdev ++ is an operation awaiting until ALL skb's gone */ ++ fini_ve_iptables(ve, ve->_iptables_modules); ++ fini_ve_netfilter(); ++ ++ fini_ve_sched(ve); ++ clean_device_perms_ve(ve->veid); ++ ++ fini_ve_devpts(ve); ++ fini_ve_shmem(ve); ++ unregister_ve_tty_drivers(ve); ++ fini_ve_meminfo(ve); ++ ++ ve->ve_ns->net_ns->sysfs_completion = &sysfs_completion; ++ fini_ve_namespaces(ve, NULL); ++ wait_for_completion(&sysfs_completion); ++ fini_ve_route(ve); ++ fini_ve_route6(ve); ++ fini_ve_mibs(ve); ++ fini_ve_sysctl(ve); ++ fini_ve_proc(ve); ++ fini_ve_sysfs(ve); ++ ++ (void)set_exec_env(old_ve); ++ fini_printk(ve); /* no printk can happen in ve context anymore */ ++ ++ ve_list_del(ve); ++ up_read(&ve->op_sem); ++ ++ real_put_ve(ve); ++} ++ ++static DECLARE_COMPLETION(vzmond_complete); ++static volatile int stop_vzmond; ++ ++static int vzmond_helper(void *arg) ++{ ++ char name[18]; ++ struct ve_struct *ve; ++ ++ ve = (struct ve_struct *)arg; ++ snprintf(name, sizeof(name), "vzmond/%d", ve->veid); ++ daemonize(name); ++ env_cleanup(ve); ++ module_put_and_exit(0); ++} ++ ++static void do_pending_env_cleanups(void) ++{ ++ int err; ++ struct ve_struct *ve; ++ ++ spin_lock(&ve_cleanup_lock); ++ while (1) { ++ if (list_empty(&ve_cleanup_list) || need_resched()) ++ break; ++ ++ ve = list_first_entry(&ve_cleanup_list, ++ struct ve_struct, cleanup_list); ++ list_del(&ve->cleanup_list); ++ spin_unlock(&ve_cleanup_lock); ++ ++ __module_get(THIS_MODULE); ++ err = kernel_thread(vzmond_helper, (void *)ve, 0); ++ if (err < 0) { ++ env_cleanup(ve); ++ module_put(THIS_MODULE); ++ } ++ ++ spin_lock(&ve_cleanup_lock); ++ } ++ spin_unlock(&ve_cleanup_lock); ++} ++ ++static inline int have_pending_cleanups(void) ++{ ++ return !list_empty(&ve_cleanup_list); ++} ++ ++static int vzmond(void *arg) ++{ ++ daemonize("vzmond"); ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ while (!stop_vzmond || have_pending_cleanups()) { ++ schedule(); ++ try_to_freeze(); ++ if (signal_pending(current)) ++ flush_signals(current); ++ ++ do_pending_env_cleanups(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (have_pending_cleanups()) ++ __set_current_state(TASK_RUNNING); ++ } ++ ++ __set_task_state(current, TASK_RUNNING); ++ complete_and_exit(&vzmond_complete, 0); ++} ++ ++static int __init init_vzmond(void) ++{ ++ int pid; ++ struct task_struct *tsk; ++ ++ pid = kernel_thread(vzmond, NULL, 0); ++ if (pid > 0) { ++ tsk = find_task_by_pid(pid); ++ BUG_ON(tsk == NULL); ++ ve_cleanup_thread = tsk; ++ } ++ return pid; ++} ++ ++static void fini_vzmond(void) ++{ ++ stop_vzmond = 1; ++ wake_up_process(ve_cleanup_thread); ++ wait_for_completion(&vzmond_complete); ++ ve_cleanup_thread = NULL; ++ WARN_ON(!list_empty(&ve_cleanup_list)); ++} ++ ++void real_do_env_free(struct ve_struct *ve) ++{ ++ VZTRACE("real_do_env_free\n"); ++ ++ free_ve_tty_drivers(ve); ++ free_ve_sysctl(ve); /* free per ve sysctl data */ ++ free_ve_filesystems(ve); ++ free_ve_cpustats(ve); ++ printk(KERN_INFO "CT: %d: stopped\n", VEID(ve)); ++ kfree(ve); ++ ++ module_put(THIS_MODULE); ++} ++EXPORT_SYMBOL(real_do_env_free); ++ ++ ++/********************************************************************** ++ ********************************************************************** ++ * ++ * VE TTY handling ++ * ++ ********************************************************************** ++ **********************************************************************/ ++ ++static struct tty_driver *alloc_ve_tty_driver(struct tty_driver *base, ++ struct ve_struct *ve) ++{ ++ size_t size; ++ struct tty_driver *driver; ++ ++ driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL_UBC); ++ if (!driver) ++ goto out; ++ ++ memcpy(driver, base, sizeof(struct tty_driver)); ++ ++ driver->driver_state = NULL; ++ ++ size = base->num * 3 * sizeof(void *); ++ if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) { ++ void **p; ++ p = kzalloc(size, GFP_KERNEL_UBC); ++ if (!p) ++ goto out_free; ++ ++ driver->ttys = (struct tty_struct **)p; ++ driver->termios = (struct ktermios **)(p + driver->num); ++ driver->termios_locked = (struct ktermios **) ++ (p + driver->num * 2); ++ } else { ++ driver->ttys = NULL; ++ driver->termios = NULL; ++ driver->termios_locked = NULL; ++ } ++ ++ driver->owner_env = ve; ++ driver->flags |= TTY_DRIVER_INSTALLED; ++ driver->refcount = 0; ++ ++ return driver; ++ ++out_free: ++ kfree(driver); ++out: ++ return NULL; ++} ++ ++static void free_ve_tty_driver(struct tty_driver *driver) ++{ ++ if (!driver) ++ return; ++ ++ clear_termios(driver); ++ kfree(driver->ttys); ++ kfree(driver); ++} ++ ++static int alloc_ve_tty_drivers(struct ve_struct* ve) ++{ ++#ifdef CONFIG_LEGACY_PTYS ++ /* Traditional BSD devices */ ++ ve->pty_driver = alloc_ve_tty_driver(pty_driver, ve); ++ if (!ve->pty_driver) ++ goto out_mem; ++ ++ ve->pty_slave_driver = alloc_ve_tty_driver(pty_slave_driver, ve); ++ if (!ve->pty_slave_driver) ++ goto out_mem; ++ ++ ve->pty_driver->other = ve->pty_slave_driver; ++ ve->pty_slave_driver->other = ve->pty_driver; ++#endif ++ ++#ifdef CONFIG_UNIX98_PTYS ++ ve->ptm_driver = alloc_ve_tty_driver(ptm_driver, ve); ++ if (!ve->ptm_driver) ++ goto out_mem; ++ ++ ve->pts_driver = alloc_ve_tty_driver(pts_driver, ve); ++ if (!ve->pts_driver) ++ goto out_mem; ++ ++ ve->ptm_driver->other = ve->pts_driver; ++ ve->pts_driver->other = ve->ptm_driver; ++ ++ ve->allocated_ptys = kmalloc(sizeof(*ve->allocated_ptys), ++ GFP_KERNEL_UBC); ++ if (!ve->allocated_ptys) ++ goto out_mem; ++ idr_init(ve->allocated_ptys); ++#endif ++ return 0; ++ ++out_mem: ++ free_ve_tty_drivers(ve); ++ return -ENOMEM; ++} ++ ++static void free_ve_tty_drivers(struct ve_struct* ve) ++{ ++#ifdef CONFIG_LEGACY_PTYS ++ free_ve_tty_driver(ve->pty_driver); ++ free_ve_tty_driver(ve->pty_slave_driver); ++ ve->pty_driver = ve->pty_slave_driver = NULL; ++#endif ++#ifdef CONFIG_UNIX98_PTYS ++ free_ve_tty_driver(ve->ptm_driver); ++ free_ve_tty_driver(ve->pts_driver); ++ kfree(ve->allocated_ptys); ++ ve->ptm_driver = ve->pts_driver = NULL; ++ ve->allocated_ptys = NULL; ++#endif ++} ++ ++static inline void __register_tty_driver(struct tty_driver *driver) ++{ ++ list_add(&driver->tty_drivers, &tty_drivers); ++} ++ ++static inline void __unregister_tty_driver(struct tty_driver *driver) ++{ ++ if (!driver) ++ return; ++ list_del(&driver->tty_drivers); ++} ++ ++static int register_ve_tty_drivers(struct ve_struct* ve) ++{ ++ mutex_lock(&tty_mutex); ++#ifdef CONFIG_UNIX98_PTYS ++ __register_tty_driver(ve->ptm_driver); ++ __register_tty_driver(ve->pts_driver); ++#endif ++#ifdef CONFIG_LEGACY_PTYS ++ __register_tty_driver(ve->pty_driver); ++ __register_tty_driver(ve->pty_slave_driver); ++#endif ++ mutex_unlock(&tty_mutex); ++ ++ return 0; ++} ++ ++static void unregister_ve_tty_drivers(struct ve_struct* ve) ++{ ++ VZTRACE("unregister_ve_tty_drivers\n"); ++ ++ mutex_lock(&tty_mutex); ++#ifdef CONFIG_LEGACY_PTYS ++ __unregister_tty_driver(ve->pty_driver); ++ __unregister_tty_driver(ve->pty_slave_driver); ++#endif ++#ifdef CONFIG_UNIX98_PTYS ++ __unregister_tty_driver(ve->ptm_driver); ++ __unregister_tty_driver(ve->pts_driver); ++#endif ++ mutex_unlock(&tty_mutex); ++} ++ ++static int init_ve_tty_drivers(struct ve_struct *ve) ++{ ++ int err; ++ ++ if ((err = alloc_ve_tty_drivers(ve))) ++ goto err_ttyalloc; ++ if ((err = register_ve_tty_drivers(ve))) ++ goto err_ttyreg; ++ return 0; ++ ++err_ttyreg: ++ free_ve_tty_drivers(ve); ++err_ttyalloc: ++ return err; ++} ++ ++static void fini_ve_tty_drivers(struct ve_struct *ve) ++{ ++ unregister_ve_tty_drivers(ve); ++ free_ve_tty_drivers(ve); ++} ++ ++/* ++ * Free the termios and termios_locked structures because ++ * we don't want to get memory leaks when modular tty ++ * drivers are removed from the kernel. ++ */ ++static void clear_termios(struct tty_driver *driver) ++{ ++ int i; ++ struct ktermios *tp; ++ ++ if (driver->termios == NULL) ++ return; ++ for (i = 0; i < driver->num; i++) { ++ tp = driver->termios[i]; ++ if (tp) { ++ driver->termios[i] = NULL; ++ kfree(tp); ++ } ++ tp = driver->termios_locked[i]; ++ if (tp) { ++ driver->termios_locked[i] = NULL; ++ kfree(tp); ++ } ++ } ++} ++ ++ ++/********************************************************************** ++ ********************************************************************** ++ * ++ * Pieces of VE network ++ * ++ ********************************************************************** ++ **********************************************************************/ ++ ++#ifdef CONFIG_NET ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++static int ve_dev_add(envid_t veid, char *dev_name) ++{ ++ struct net_device *dev; ++ struct ve_struct *dst_ve; ++ struct net *dst_net; ++ int err = -ESRCH; ++ ++ dst_ve = get_ve_by_id(veid); ++ if (dst_ve == NULL) ++ goto out; ++ ++ dst_net = dst_ve->ve_ns->net_ns; ++ ++ rtnl_lock(); ++ read_lock(&dev_base_lock); ++ dev = __dev_get_by_name(&init_net, dev_name); ++ read_unlock(&dev_base_lock); ++ if (dev == NULL) ++ goto out_unlock; ++ ++ err = __dev_change_net_namespace(dev, dst_net, dev_name, ++ get_ve0(), dst_ve, get_exec_ub()); ++out_unlock: ++ rtnl_unlock(); ++ real_put_ve(dst_ve); ++ ++ if (dev == NULL) ++ printk(KERN_WARNING "%s: device %s not found\n", ++ __func__, dev_name); ++out: ++ return err; ++} ++ ++static int ve_dev_del(envid_t veid, char *dev_name) ++{ ++ struct net_device *dev; ++ struct ve_struct *src_ve; ++ struct net *src_net; ++ int err = -ESRCH; ++ ++ src_ve = get_ve_by_id(veid); ++ if (src_ve == NULL) ++ goto out; ++ ++ src_net = src_ve->ve_ns->net_ns; ++ ++ rtnl_lock(); ++ ++ read_lock(&dev_base_lock); ++ dev = __dev_get_by_name(src_net, dev_name); ++ read_unlock(&dev_base_lock); ++ if (dev == NULL) ++ goto out_unlock; ++ ++ err = __dev_change_net_namespace(dev, &init_net, dev_name, ++ src_ve, get_ve0(), netdev_bc(dev)->owner_ub); ++out_unlock: ++ rtnl_unlock(); ++ real_put_ve(src_ve); ++ ++ if (dev == NULL) ++ printk(KERN_WARNING "%s: device %s not found\n", ++ __func__, dev_name); ++out: ++ return err; ++} ++ ++int real_ve_dev_map(envid_t veid, int op, char *dev_name) ++{ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ switch (op) { ++ case VE_NETDEV_ADD: ++ return ve_dev_add(veid, dev_name); ++ case VE_NETDEV_DEL: ++ return ve_dev_del(veid, dev_name); ++ default: ++ return -EINVAL; ++ } ++} ++ ++static void ve_mapped_devs_cleanup(struct ve_struct *ve) ++{ ++ struct net *net = ve->ve_ns->net_ns; ++ struct net_device *dev, *next; ++ int rv; ++ ++ rtnl_lock(); ++ for_each_netdev_safe(net, dev, next) { ++ /* Ignore unmoveable devices (i.e. loopback) */ ++ if (dev->features & NETIF_F_NETNS_LOCAL) ++ continue; ++ ++ rv = __dev_change_net_namespace(dev, &init_net, dev->name, ++ ve, get_ve0(), netdev_bc(dev)->owner_ub); ++ if (rv < 0) ++ unregister_netdevice(dev); ++ } ++ rtnl_unlock(); ++} ++ ++ ++/********************************************************************** ++ ********************************************************************** ++ * ++ * VE information via /proc ++ * ++ ********************************************************************** ++ **********************************************************************/ ++#ifdef CONFIG_PROC_FS ++#if BITS_PER_LONG == 32 ++#define VESTAT_LINE_WIDTH (6 * 11 + 6 * 21) ++#define VESTAT_LINE_FMT "%10u %10lu %10lu %10lu %10Lu %20Lu %20Lu %20Lu %20Lu %20Lu %20Lu %10lu\n" ++#define VESTAT_HEAD_FMT "%10s %10s %10s %10s %10s %20s %20s %20s %20s %20s %20s %10s\n" ++#else ++#define VESTAT_LINE_WIDTH (12 * 21) ++#define VESTAT_LINE_FMT "%20u %20lu %20lu %20lu %20Lu %20Lu %20Lu %20Lu %20Lu %20Lu %20Lu %20lu\n" ++#define VESTAT_HEAD_FMT "%20s %20s %20s %20s %20s %20s %20s %20s %20s %20s %20s %20s\n" ++#endif ++ ++static int vestat_seq_show(struct seq_file *m, void *v) ++{ ++ struct list_head *entry; ++ struct ve_struct *ve; ++ struct ve_struct *curve; ++ int cpu; ++ unsigned long user_ve, nice_ve, system_ve; ++ unsigned long long uptime; ++ cycles_t uptime_cycles, idle_time, strv_time, used; ++ ++ entry = (struct list_head *)v; ++ ve = list_entry(entry, struct ve_struct, ve_list); ++ ++ curve = get_exec_env(); ++ if (entry == ve_list_head.next || ++ (!ve_is_super(curve) && ve == curve)) { ++ /* print header */ ++ seq_printf(m, "%-*s\n", ++ VESTAT_LINE_WIDTH - 1, ++ "Version: 2.2"); ++ seq_printf(m, VESTAT_HEAD_FMT, "VEID", ++ "user", "nice", "system", ++ "uptime", "idle", ++ "strv", "uptime", "used", ++ "maxlat", "totlat", "numsched"); ++ } ++ ++ if (ve == get_ve0()) ++ return 0; ++ ++ user_ve = nice_ve = system_ve = 0; ++ idle_time = strv_time = used = 0; ++ ++ for_each_online_cpu(cpu) { ++ struct ve_cpu_stats *st; ++ ++ st = VE_CPU_STATS(ve, cpu); ++ user_ve += st->user; ++ nice_ve += st->nice; ++ system_ve += st->system; ++ used += st->used_time; ++ idle_time += ve_sched_get_idle_time(ve, cpu); ++ } ++ uptime_cycles = get_cycles() - ve->start_cycles; ++ uptime = get_jiffies_64() - ve->start_jiffies; ++ ++ seq_printf(m, VESTAT_LINE_FMT, ve->veid, ++ user_ve, nice_ve, system_ve, ++ (unsigned long long)uptime, ++ (unsigned long long)idle_time, ++ (unsigned long long)strv_time, ++ (unsigned long long)uptime_cycles, ++ (unsigned long long)used, ++ (unsigned long long)ve->sched_lat_ve.last.maxlat, ++ (unsigned long long)ve->sched_lat_ve.last.totlat, ++ ve->sched_lat_ve.last.count); ++ return 0; ++} ++ ++static void *ve_seq_start(struct seq_file *m, loff_t *pos) ++{ ++ struct ve_struct *curve; ++ struct list_head *entry; ++ loff_t l; ++ ++ curve = get_exec_env(); ++ read_lock(&ve_list_lock); ++ if (!ve_is_super(curve)) { ++ if (*pos != 0) ++ return NULL; ++ return curve; ++ } ++ ++ l = *pos; ++ list_for_each(entry, &ve_list_head) { ++ if (l == 0) ++ return entry; ++ l--; ++ } ++ return NULL; ++} ++ ++static void *ve_seq_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ struct list_head *entry; ++ ++ entry = (struct list_head *)v; ++ if (!ve_is_super(get_exec_env())) ++ return NULL; ++ (*pos)++; ++ return entry->next == &ve_list_head ? NULL : entry->next; ++} ++ ++static void ve_seq_stop(struct seq_file *m, void *v) ++{ ++ read_unlock(&ve_list_lock); ++} ++ ++static struct seq_operations vestat_seq_op = { ++ .start = ve_seq_start, ++ .next = ve_seq_next, ++ .stop = ve_seq_stop, ++ .show = vestat_seq_show ++}; ++ ++static int vestat_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &vestat_seq_op); ++} ++ ++static struct file_operations proc_vestat_operations = { ++ .open = vestat_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release ++}; ++ ++static int vz_version_show(struct seq_file *file, void* v) ++{ ++ static const char ver[] = VZVERSION "\n"; ++ ++ return seq_puts(file, ver); ++} ++ ++static int vz_version_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, vz_version_show, NULL); ++} ++ ++static struct file_operations proc_vz_version_oparations = { ++ .open = vz_version_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static inline unsigned long ve_used_mem(struct user_beancounter *ub) ++{ ++ extern int glob_ve_meminfo; ++ return glob_ve_meminfo ? ub->ub_parms[UB_OOMGUARPAGES].held : ++ ub->ub_parms[UB_PRIVVMPAGES].held ; ++} ++ ++static inline void ve_mi_replace(struct meminfo *mi) ++{ ++#ifdef CONFIG_BEANCOUNTERS ++ struct user_beancounter *ub; ++ unsigned long meminfo_val; ++ unsigned long nodettram; ++ unsigned long usedmem; ++ ++ meminfo_val = get_exec_env()->meminfo_val; ++ ++ if(!meminfo_val) ++ return; /* No virtualization */ ++ ++ nodettram = mi->si.totalram; ++ ub = current->mm->mm_ub; ++ usedmem = ve_used_mem(ub); ++ ++ memset(mi, 0, sizeof(*mi)); ++ ++ mi->si.totalram = (meminfo_val > nodettram) ? ++ nodettram : meminfo_val; ++ mi->si.freeram = (mi->si.totalram > usedmem) ? ++ (mi->si.totalram - usedmem) : 0; ++#else ++ return; ++#endif ++} ++ ++static int meminfo_call(struct vnotifier_block *self, ++ unsigned long event, void *arg, int old_ret) ++{ ++ if (event != VIRTINFO_MEMINFO) ++ return old_ret; ++ ++ ve_mi_replace((struct meminfo *)arg); ++ ++ return NOTIFY_OK; ++} ++ ++ ++static struct vnotifier_block meminfo_notifier_block = { ++ .notifier_call = meminfo_call ++}; ++ ++static int __init init_vecalls_proc(void) ++{ ++ struct proc_dir_entry *de; ++ ++ de = create_proc_glob_entry_mod("vz/vestat", ++ S_IFREG|S_IRUSR, NULL, THIS_MODULE); ++ if (de == NULL) { ++ /* create "vz" subdirectory, if not exist */ ++ (void) create_proc_glob_entry("vz", ++ S_IFDIR|S_IRUGO|S_IXUGO, NULL); ++ de = create_proc_glob_entry_mod("vz/vestat", ++ S_IFREG|S_IRUSR, NULL, THIS_MODULE); ++ } ++ if (de) ++ de->proc_fops = &proc_vestat_operations; ++ else ++ printk(KERN_WARNING ++ "VZMON: can't make vestat proc entry\n"); ++ ++ de = create_proc_entry_mod("vz/devperms", S_IFREG | S_IRUSR, NULL, ++ THIS_MODULE); ++ if (de) ++ de->proc_fops = &proc_devperms_ops; ++ else ++ printk(KERN_WARNING ++ "VZMON: can't make devperms proc entry\n"); ++ ++ ++ de = create_proc_entry_mod("vz/version", S_IFREG | 0444, NULL, ++ THIS_MODULE); ++ if (de) ++ de->proc_fops = &proc_vz_version_oparations; ++ else ++ printk(KERN_WARNING ++ "VZMON: can't make version proc entry\n"); ++ ++ virtinfo_notifier_register(VITYPE_GENERAL, &meminfo_notifier_block); ++ ++ return 0; ++} ++ ++static void fini_vecalls_proc(void) ++{ ++ remove_proc_entry("vz/version", NULL); ++ remove_proc_entry("vz/devperms", NULL); ++ remove_proc_entry("vz/vestat", NULL); ++ virtinfo_notifier_unregister(VITYPE_GENERAL, &meminfo_notifier_block); ++} ++#else ++#define init_vecalls_proc() (0) ++#define fini_vecalls_proc() do { } while (0) ++#endif /* CONFIG_PROC_FS */ ++ ++ ++/********************************************************************** ++ ********************************************************************** ++ * ++ * User ctl ++ * ++ ********************************************************************** ++ **********************************************************************/ ++ ++int vzcalls_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int err; ++ ++ err = -ENOTTY; ++ switch(cmd) { ++ case VZCTL_MARK_ENV_TO_DOWN: { ++ /* Compatibility issue */ ++ err = 0; ++ } ++ break; ++ case VZCTL_SETDEVPERMS: { ++ /* Device type was mistakenly declared as dev_t ++ * in the old user-kernel interface. ++ * That's wrong, dev_t is a kernel internal type. ++ * I use `unsigned' not having anything better in mind. ++ * 2001/08/11 SAW */ ++ struct vzctl_setdevperms s; ++ err = -EFAULT; ++ if (copy_from_user(&s, (void __user *)arg, sizeof(s))) ++ break; ++ err = real_setdevperms(s.veid, s.type, ++ new_decode_dev(s.dev), s.mask); ++ } ++ break; ++#ifdef CONFIG_INET ++ case VZCTL_VE_NETDEV: { ++ struct vzctl_ve_netdev d; ++ char *s; ++ err = -EFAULT; ++ if (copy_from_user(&d, (void __user *)arg, sizeof(d))) ++ break; ++ err = -ENOMEM; ++ s = kmalloc(IFNAMSIZ+1, GFP_KERNEL); ++ if (s == NULL) ++ break; ++ err = -EFAULT; ++ if (strncpy_from_user(s, d.dev_name, IFNAMSIZ) > 0) { ++ s[IFNAMSIZ] = 0; ++ err = real_ve_dev_map(d.veid, d.op, s); ++ } ++ kfree(s); ++ } ++ break; ++#endif ++ case VZCTL_ENV_CREATE: { ++ struct vzctl_env_create s; ++ err = -EFAULT; ++ if (copy_from_user(&s, (void __user *)arg, sizeof(s))) ++ break; ++ err = real_env_create(s.veid, s.flags, s.class_id, ++ NULL, 0); ++ } ++ break; ++ case VZCTL_ENV_CREATE_DATA: { ++ struct vzctl_env_create_data s; ++ env_create_param_t *data; ++ err = -EFAULT; ++ if (copy_from_user(&s, (void __user *)arg, sizeof(s))) ++ break; ++ err=-EINVAL; ++ if (s.datalen < VZCTL_ENV_CREATE_DATA_MINLEN || ++ s.datalen > VZCTL_ENV_CREATE_DATA_MAXLEN || ++ s.data == 0) ++ break; ++ err = -ENOMEM; ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) ++ break; ++ ++ err = -EFAULT; ++ if (copy_from_user(data, (void __user *)s.data, ++ s.datalen)) ++ goto free_data; ++ err = real_env_create(s.veid, s.flags, s.class_id, ++ data, s.datalen); ++free_data: ++ kfree(data); ++ } ++ break; ++ case VZCTL_GET_CPU_STAT: { ++ struct vzctl_cpustatctl s; ++ err = -EFAULT; ++ if (copy_from_user(&s, (void __user *)arg, sizeof(s))) ++ break; ++ err = ve_get_cpu_stat(s.veid, s.cpustat); ++ } ++ break; ++ case VZCTL_VE_MEMINFO: { ++ struct vzctl_ve_meminfo s; ++ err = -EFAULT; ++ if (copy_from_user(&s, (void __user *)arg, sizeof(s))) ++ break; ++ err = ve_set_meminfo(s.veid, s.val); ++ } ++ break; ++ } ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++int compat_vzcalls_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ int err; ++ ++ switch(cmd) { ++ case VZCTL_GET_CPU_STAT: { ++ /* FIXME */ ++ } ++ case VZCTL_COMPAT_ENV_CREATE_DATA: { ++ struct compat_vzctl_env_create_data cs; ++ struct vzctl_env_create_data __user *s; ++ ++ s = compat_alloc_user_space(sizeof(*s)); ++ err = -EFAULT; ++ if (copy_from_user(&cs, (void *)arg, sizeof(cs))) ++ break; ++ ++ if (put_user(cs.veid, &s->veid) || ++ put_user(cs.flags, &s->flags) || ++ put_user(cs.class_id, &s->class_id) || ++ put_user(compat_ptr(cs.data), &s->data) || ++ put_user(cs.datalen, &s->datalen)) ++ break; ++ err = vzcalls_ioctl(file, VZCTL_ENV_CREATE_DATA, ++ (unsigned long)s); ++ break; ++ } ++#ifdef CONFIG_NET ++ case VZCTL_COMPAT_VE_NETDEV: { ++ struct compat_vzctl_ve_netdev cs; ++ struct vzctl_ve_netdev __user *s; ++ ++ s = compat_alloc_user_space(sizeof(*s)); ++ err = -EFAULT; ++ if (copy_from_user(&cs, (void *)arg, sizeof(cs))) ++ break; ++ ++ if (put_user(cs.veid, &s->veid) || ++ put_user(cs.op, &s->op) || ++ put_user(compat_ptr(cs.dev_name), &s->dev_name)) ++ break; ++ err = vzcalls_ioctl(file, VZCTL_VE_NETDEV, (unsigned long)s); ++ break; ++ } ++#endif ++ case VZCTL_COMPAT_VE_MEMINFO: { ++ struct compat_vzctl_ve_meminfo cs; ++ err = -EFAULT; ++ if (copy_from_user(&cs, (void *)arg, sizeof(cs))) ++ break; ++ err = ve_set_meminfo(cs.veid, cs.val); ++ break; ++ } ++ default: ++ err = vzcalls_ioctl(file, cmd, arg); ++ break; ++ } ++ return err; ++} ++#endif ++ ++static struct vzioctlinfo vzcalls = { ++ .type = VZCTLTYPE, ++ .ioctl = vzcalls_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = compat_vzcalls_ioctl, ++#endif ++ .owner = THIS_MODULE, ++}; ++ ++ ++/********************************************************************** ++ ********************************************************************** ++ * ++ * Init/exit stuff ++ * ++ ********************************************************************** ++ **********************************************************************/ ++ ++static int __init init_vecalls_symbols(void) ++{ ++ KSYMRESOLVE(real_do_env_free); ++ KSYMMODRESOLVE(vzmon); ++ return 0; ++} ++ ++static void fini_vecalls_symbols(void) ++{ ++ KSYMMODUNRESOLVE(vzmon); ++ KSYMUNRESOLVE(real_do_env_free); ++} ++ ++static inline __init int init_vecalls_ioctls(void) ++{ ++ vzioctl_register(&vzcalls); ++ return 0; ++} ++ ++static inline void fini_vecalls_ioctls(void) ++{ ++ vzioctl_unregister(&vzcalls); ++} ++ ++#ifdef CONFIG_SYSCTL ++static struct ctl_table_header *table_header; ++ ++static ctl_table kernel_table[] = { ++ { ++ .procname = "ve_allow_kthreads", ++ .data = &ve_allow_kthreads, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++ { 0 } ++}; ++ ++static ctl_table root_table[] = { ++ {CTL_KERN, "kernel", NULL, 0, 0555, kernel_table}, ++ { 0 } ++}; ++ ++static int init_vecalls_sysctl(void) ++{ ++ table_header = register_sysctl_table(root_table); ++ if (!table_header) ++ return -ENOMEM ; ++ return 0; ++} ++ ++static void fini_vecalls_sysctl(void) ++{ ++ unregister_sysctl_table(table_header); ++} ++#else ++static int init_vecalls_sysctl(void) { return 0; } ++static void fini_vecalls_sysctl(void) { ; } ++#endif ++ ++static int __init vecalls_init(void) ++{ ++ int err; ++ ++ err = init_vecalls_sysctl(); ++ if (err) ++ goto out_vzmond; ++ ++ err = init_vzmond(); ++ if (err < 0) ++ goto out_sysctl; ++ ++ err = init_vecalls_symbols(); ++ if (err < 0) ++ goto out_sym; ++ ++ err = init_vecalls_proc(); ++ if (err < 0) ++ goto out_proc; ++ ++ err = init_vecalls_ioctls(); ++ if (err < 0) ++ goto out_ioctls; ++ ++ return 0; ++ ++out_ioctls: ++ fini_vecalls_proc(); ++out_proc: ++ fini_vecalls_symbols(); ++out_sym: ++ fini_vzmond(); ++out_sysctl: ++ fini_vecalls_sysctl(); ++out_vzmond: ++ return err; ++} ++ ++static void vecalls_exit(void) ++{ ++ fini_vecalls_ioctls(); ++ fini_vecalls_proc(); ++ fini_vecalls_symbols(); ++ fini_vzmond(); ++ fini_vecalls_sysctl(); ++} ++ ++MODULE_AUTHOR("SWsoft "); ++MODULE_DESCRIPTION("Virtuozzo Control"); ++MODULE_LICENSE("GPL v2"); ++ ++module_init(vecalls_init) ++module_exit(vecalls_exit) +Index: kernel/kernel/ve/veowner.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/ve/veowner.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,237 @@ ++/* ++ * kernel/ve/veowner.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++void prepare_ve0_process(struct task_struct *tsk) ++{ ++ VE_TASK_INFO(tsk)->exec_env = get_ve0(); ++ VE_TASK_INFO(tsk)->owner_env = get_ve0(); ++ VE_TASK_INFO(tsk)->sleep_time = 0; ++ VE_TASK_INFO(tsk)->wakeup_stamp = 0; ++ VE_TASK_INFO(tsk)->sched_time = 0; ++ seqcount_init(&VE_TASK_INFO(tsk)->wakeup_lock); ++ ++ if (tsk->pid) { ++ list_add_rcu(&tsk->ve_task_info.vetask_list, ++ &get_ve0()->vetask_lh); ++ atomic_inc(&get_ve0()->pcounter); ++ } ++} ++ ++/* ++ * ------------------------------------------------------------------------ ++ * proc entries ++ * ------------------------------------------------------------------------ ++ */ ++ ++#ifdef CONFIG_PROC_FS ++static void proc_move(struct proc_dir_entry *ddir, ++ struct proc_dir_entry *sdir, ++ const char *name) ++{ ++ struct proc_dir_entry **p, *q; ++ int len; ++ ++ len = strlen(name); ++ for (p = &sdir->subdir, q = *p; q != NULL; p = &q->next, q = *p) ++ if (proc_match(len, name, q)) ++ break; ++ if (q == NULL) ++ return; ++ *p = q->next; ++ q->parent = ddir; ++ q->next = ddir->subdir; ++ ddir->subdir = q; ++} ++static void prepare_proc_misc(void) ++{ ++ static char *table[] = { ++ "loadavg", ++ "uptime", ++ "meminfo", ++ "version", ++ "stat", ++ "filesystems", ++ "locks", ++ "swaps", ++ "mounts", ++ "net", ++ "cpuinfo", ++ "sysvipc", ++ "sys", ++ "fs", ++ "vz", ++ "cmdline", ++ "vmstat", ++ "modules", ++ NULL, ++ }; ++ char **p; ++ ++ for (p = table; *p != NULL; p++) ++ proc_move(&proc_root, ve0.proc_root, *p); ++} ++int prepare_proc(void) ++{ ++ struct ve_struct *envid; ++ struct proc_dir_entry *de; ++ struct proc_dir_entry *ve_root; ++ ++ envid = set_exec_env(&ve0); ++ ve_root = ve0.proc_root->subdir; ++ /* move the whole tree to be visible in VE0 only */ ++ ve0.proc_root->subdir = proc_root.subdir; ++ for (de = ve0.proc_root->subdir; de->next != NULL; de = de->next) ++ de->parent = ve0.proc_root; ++ de->parent = ve0.proc_root; ++ de->next = ve_root; ++ ++ /* move back into the global scope some specific entries */ ++ proc_root.subdir = NULL; ++ prepare_proc_misc(); ++ proc_mkdir("vz", NULL); ++#ifdef CONFIG_SYSVIPC ++ proc_mkdir("sysvipc", NULL); ++#endif ++ proc_root_fs = proc_mkdir("fs", NULL); ++ /* XXX proc_tty_init(); */ ++ ++ /* XXX process inodes */ ++ ++ (void)set_exec_env(envid); ++ ++ (void)create_proc_glob_entry("vz", S_IFDIR|S_IRUGO|S_IXUGO, NULL); ++ return 0; ++} ++ ++static struct proc_dir_entry ve0_proc_root = { ++ .name = "/proc", ++ .namelen = 5, ++ .mode = S_IFDIR | S_IRUGO | S_IXUGO, ++ .nlink = 2 ++}; ++ ++void prepare_ve0_proc_root(void) ++{ ++ ve0.proc_root = &ve0_proc_root; ++} ++#endif ++ ++/* ++ * ------------------------------------------------------------------------ ++ * Virtualized sysctl ++ * ------------------------------------------------------------------------ ++ */ ++extern int ve_area_access_check; ++#ifdef CONFIG_INET ++static ctl_table vz_ipv4_route_table[] = { ++ { ++ .procname = "src_check", ++ .data = &ip_rt_src_check, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, ++ { 0 } ++}; ++static ctl_table vz_ipv4_table[] = { ++ {NET_IPV4_ROUTE, "route", NULL, 0, 0555, vz_ipv4_route_table}, ++ { 0 } ++}; ++static ctl_table vz_net_table[] = { ++ {NET_IPV4, "ipv4", NULL, 0, 0555, vz_ipv4_table}, ++ { 0 } ++}; ++#endif ++static ctl_table vz_fs_table[] = { ++ { ++ .procname = "ve-area-access-check", ++ .data = &ve_area_access_check, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, ++ { 0 } ++}; ++static ctl_table root_table2[] = { ++#ifdef CONFIG_INET ++ {CTL_NET, "net", NULL, 0, 0555, vz_net_table}, ++#endif ++ {CTL_FS, "fs", NULL, 0, 0555, vz_fs_table}, ++ { 0 } ++}; ++int prepare_sysctl(void) ++{ ++ struct ve_struct *envid; ++ ++ envid = set_exec_env(&ve0); ++ register_sysctl_table(root_table2); ++ (void)set_exec_env(envid); ++ return 0; ++} ++ ++void prepare_ve0_sysctl(void) ++{ ++ INIT_LIST_HEAD(&ve0.sysctl_lh); ++} ++ ++/* ++ * ------------------------------------------------------------------------ ++ * XXX init_ve_system ++ * ------------------------------------------------------------------------ ++ */ ++ ++void init_ve_system(void) ++{ ++ struct task_struct *init_entry; ++ struct ve_struct *ve; ++ ++ ve = get_ve0(); ++ ++ init_entry = init_pid_ns.child_reaper; ++ /* if ve_move_task to VE0 (e.g. in cpt code) * ++ * occurs, ve_cap_bset on VE0 is required */ ++ ve->ve_cap_bset = CAP_INIT_EFF_SET; ++ ++#ifdef CONFIG_INET ++ ve->_ipv4_devconf = &ipv4_devconf; ++ ve->_ipv4_devconf_dflt = &ipv4_devconf_dflt; ++#endif ++ ++ read_lock(&init_entry->fs->lock); ++ ve->fs_rootmnt = init_entry->fs->rootmnt; ++ ve->fs_root = init_entry->fs->root; ++ read_unlock(&init_entry->fs->lock); ++ ++ /* common prepares */ ++#ifdef CONFIG_PROC_FS ++ prepare_proc(); ++#endif ++ prepare_sysctl(); ++} +Index: kernel/kernel/ve/vzdev.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/ve/vzdev.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,154 @@ ++/* ++ * kernel/ve/vzdev.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define VZCTL_MAJOR 126 ++#define VZCTL_NAME "vzctl" ++ ++MODULE_AUTHOR("SWsoft "); ++MODULE_DESCRIPTION("Virtuozzo Interface"); ++MODULE_LICENSE("GPL v2"); ++ ++static LIST_HEAD(ioctls); ++static spinlock_t ioctl_lock = SPIN_LOCK_UNLOCKED; ++ ++static struct vzioctlinfo *vzctl_get_handler(unsigned int cmd) ++{ ++ struct vzioctlinfo *h; ++ ++ spin_lock(&ioctl_lock); ++ list_for_each_entry(h, &ioctls, list) { ++ if (h->type == _IOC_TYPE(cmd)) ++ goto found; ++ } ++ h = NULL; ++found: ++ if (h && !try_module_get(h->owner)) ++ h = NULL; ++ spin_unlock(&ioctl_lock); ++ return h; ++} ++ ++static void vzctl_put_handler(struct vzioctlinfo *h) ++{ ++ if (!h) ++ return; ++ ++ module_put(h->owner); ++} ++ ++long vzctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct vzioctlinfo *h; ++ int err; ++ ++ err = -ENOTTY; ++ h = vzctl_get_handler(cmd); ++ if (h && h->ioctl) ++ err = (*h->ioctl)(file, cmd, arg); ++ vzctl_put_handler(h); ++ ++ return err; ++} ++ ++long compat_vzctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct vzioctlinfo *h; ++ int err; ++ ++ err = -ENOIOCTLCMD; ++ h = vzctl_get_handler(cmd); ++ if (h && h->compat_ioctl) ++ err = (*h->compat_ioctl)(file, cmd, arg); ++ vzctl_put_handler(h); ++ ++ return err; ++} ++ ++void vzioctl_register(struct vzioctlinfo *inf) ++{ ++ spin_lock(&ioctl_lock); ++ list_add(&inf->list, &ioctls); ++ spin_unlock(&ioctl_lock); ++} ++EXPORT_SYMBOL(vzioctl_register); ++ ++void vzioctl_unregister(struct vzioctlinfo *inf) ++{ ++ spin_lock(&ioctl_lock); ++ list_del_init(&inf->list); ++ spin_unlock(&ioctl_lock); ++} ++EXPORT_SYMBOL(vzioctl_unregister); ++ ++/* ++ * Init/exit stuff. ++ */ ++static struct file_operations vzctl_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = vzctl_ioctl, ++ .compat_ioctl = compat_vzctl_ioctl, ++}; ++ ++static struct class *vzctl_class; ++ ++static void __exit vzctl_exit(void) ++{ ++ class_device_destroy(vzctl_class, MKDEV(VZCTL_MAJOR, 0)); ++ class_destroy(vzctl_class); ++ unregister_chrdev(VZCTL_MAJOR, VZCTL_NAME); ++} ++ ++static int __init vzctl_init(void) ++{ ++ int ret; ++ struct class_device *class_err; ++ ++ ret = register_chrdev(VZCTL_MAJOR, VZCTL_NAME, &vzctl_fops); ++ if (ret < 0) ++ goto out; ++ ++ vzctl_class = class_create(THIS_MODULE, "vzctl"); ++ if (IS_ERR(vzctl_class)) { ++ ret = PTR_ERR(vzctl_class); ++ goto out_cleandev; ++ } ++ ++ class_err = class_device_create(vzctl_class, NULL, MKDEV(VZCTL_MAJOR, 0), ++ NULL, VZCTL_NAME); ++ if (IS_ERR(class_err)) { ++ ret = PTR_ERR(class_err); ++ goto out_rmclass; ++ } ++ ++ goto out; ++ ++out_rmclass: ++ class_destroy(vzctl_class); ++out_cleandev: ++ unregister_chrdev(VZCTL_MAJOR, VZCTL_NAME); ++out: ++ return ret; ++} ++ ++module_init(vzctl_init) ++module_exit(vzctl_exit); +Index: kernel/kernel/ve/vzevent.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/ve/vzevent.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,125 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define NETLINK_UEVENT 31 ++#define VZ_EVGRP_ALL 0x01 ++ ++/* ++ * NOTE: the original idea was to send events via kobject_uevent(), ++ * however, it turns out that it has negative consequences like ++ * start of /sbin/hotplug which tries to react on our events in inadequate manner. ++ */ ++ ++static struct sock *vzev_sock; ++ ++static char *action_to_string(int action) ++{ ++ switch (action) { ++ case KOBJ_MOUNT: ++ return "ve-mount"; ++ case KOBJ_UMOUNT: ++ return "ve-umount"; ++ case KOBJ_START: ++ return "ve-start"; ++ case KOBJ_STOP: ++ return "ve-stop"; ++ default: ++ return NULL; ++ } ++} ++ ++static int do_vzevent_send(int event, char *msg, int len) ++{ ++ struct sk_buff *skb; ++ char *buf, *action; ++ int alen; ++ ++ action = action_to_string(event); ++ alen = strlen(action); ++ ++ skb = alloc_skb(len + 1 + alen, GFP_KERNEL); ++ if (!skb) ++ return -ENOMEM; ++ ++ buf = skb_put(skb, len + 1 + alen); ++ memcpy(buf, action, alen); ++ buf[alen] = '@'; ++ memcpy(buf + alen + 1, msg, len); ++ (void)netlink_broadcast(vzev_sock, skb, 0, VZ_EVGRP_ALL, GFP_KERNEL); ++ return 0; ++} ++ ++int vzevent_send(int event, const char *attrs_fmt, ...) ++{ ++ va_list args; ++ int len, err; ++ struct ve_struct *ve; ++ char *page; ++ ++ err = -ENOMEM; ++ page = (char *)__get_free_page(GFP_KERNEL); ++ if (!page) ++ goto out; ++ ++ va_start(args, attrs_fmt); ++ len = vscnprintf(page, PAGE_SIZE, attrs_fmt, args); ++ va_end(args); ++ ++ ve = set_exec_env(get_ve0()); ++ err = do_vzevent_send(event, page, len); ++ (void)set_exec_env(ve); ++ free_page((unsigned long)page); ++out: ++ return err; ++} ++EXPORT_SYMBOL(vzevent_send); ++ ++static int ve_start(void *data) ++{ ++ struct ve_struct *ve; ++ ++ ve = (struct ve_struct *)data; ++ vzevent_send(KOBJ_START, "%d", ve->veid); ++ return 0; ++} ++ ++static void ve_stop(void *data) ++{ ++ struct ve_struct *ve; ++ ++ ve = (struct ve_struct *)data; ++ vzevent_send(KOBJ_STOP, "%d", ve->veid); ++} ++ ++static struct ve_hook ve_start_stop_hook = { ++ .init = ve_start, ++ .fini = ve_stop, ++ .owner = THIS_MODULE, ++ .priority = HOOK_PRIO_AFTERALL, ++}; ++ ++static int __init init_vzevent(void) ++{ ++ vzev_sock = netlink_kernel_create(NETLINK_UEVENT, 0, NULL, THIS_MODULE); ++ if (vzev_sock == NULL) ++ return -ENOMEM; ++ ve_hook_register(VE_SS_CHAIN, &ve_start_stop_hook); ++ return 0; ++} ++ ++static void __exit exit_vzevent(void) ++{ ++ ve_hook_unregister(&ve_start_stop_hook); ++ sock_release(vzev_sock->sk_socket); ++} ++ ++MODULE_LICENSE("GPL"); ++ ++module_init(init_vzevent); ++module_exit(exit_vzevent); +Index: kernel/kernel/ve/vzwdog.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/ve/vzwdog.c 2008-11-24 15:47:46.000000000 +0100 +@@ -0,0 +1,281 @@ ++/* ++ * kernel/ve/vzwdog.c ++ * ++ * Copyright (C) 2000-2005 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Staff regading kernel thread polling VE validity */ ++static int sleep_timeout = 60; ++static struct task_struct *wdog_thread_tsk; ++ ++extern void show_mem(void); ++ ++static struct file *intr_file; ++static char page[PAGE_SIZE]; ++ ++static void parse_irq_list(int len) ++{ ++ int i, k, skip; ++ for (i = 0; i < len; ) { ++ k = i; ++ while (i < len && page[i] != '\n' && page[i] != ':') ++ i++; ++ skip = 0; ++ if (i < len && page[i] != '\n') { ++ i++; /* skip ':' */ ++ while (i < len && (page[i] == ' ' || page[i] == '0')) ++ i++; ++ skip = (i < len && (page[i] < '0' || page[i] > '9')); ++ while (i < len && page[i] != '\n') ++ i++; ++ } ++ if (!skip) ++ printk("%.*s\n", i - k, page + k); ++ if (i < len) ++ i++; /* skip '\n' */ ++ } ++} ++ ++extern loff_t vfs_llseek(struct file *file, loff_t, int); ++extern ssize_t vfs_read(struct file *file, char __user *, size_t, loff_t *); ++extern struct file *filp_open(const char *filename, int flags, int mode); ++extern int filp_close(struct file *filp, fl_owner_t id); ++static void show_irq_list(void) ++{ ++ mm_segment_t fs; ++ int r; ++ ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ vfs_llseek(intr_file, 0, 0); ++ r = vfs_read(intr_file, (void __user *)page, sizeof(page), ++ &intr_file->f_pos); ++ set_fs(fs); ++ ++ if (r > 0) ++ parse_irq_list(r); ++} ++ ++static void show_alloc_latency(void) ++{ ++ static const char *alloc_descr[KSTAT_ALLOCSTAT_NR] = { ++ "A0", ++ "L0", ++ "H0", ++ "L1", ++ "H1" ++ }; ++ int i; ++ ++ printk("lat: "); ++ for (i = 0; i < KSTAT_ALLOCSTAT_NR; i++) { ++ struct kstat_lat_struct *p; ++ cycles_t maxlat, avg0, avg1, avg2; ++ ++ p = &kstat_glob.alloc_lat[i]; ++ spin_lock_irq(&kstat_glb_lock); ++ maxlat = p->last.maxlat; ++ avg0 = p->avg[0]; ++ avg1 = p->avg[1]; ++ avg2 = p->avg[2]; ++ spin_unlock_irq(&kstat_glb_lock); ++ ++ printk("%s %Lu (%Lu %Lu %Lu)", ++ alloc_descr[i], ++ (unsigned long long)maxlat, ++ (unsigned long long)avg0, ++ (unsigned long long)avg1, ++ (unsigned long long)avg2); ++ } ++ printk("\n"); ++} ++ ++static void show_schedule_latency(void) ++{ ++ struct kstat_lat_pcpu_struct *p; ++ cycles_t maxlat, totlat, avg0, avg1, avg2; ++ unsigned long count; ++ ++ p = &kstat_glob.sched_lat; ++ spin_lock_irq(&kstat_glb_lock); ++ maxlat = p->last.maxlat; ++ totlat = p->last.totlat; ++ count = p->last.count; ++ avg0 = p->avg[0]; ++ avg1 = p->avg[1]; ++ avg2 = p->avg[2]; ++ spin_unlock_irq(&kstat_glb_lock); ++ ++ printk("sched lat: %Lu/%Lu/%lu (%Lu %Lu %Lu)\n", ++ (unsigned long long)maxlat, ++ (unsigned long long)totlat, ++ count, ++ (unsigned long long)avg0, ++ (unsigned long long)avg1, ++ (unsigned long long)avg2); ++} ++ ++static void show_header(void) ++{ ++ struct timeval tv; ++ ++ do_gettimeofday(&tv); ++ preempt_disable(); ++ printk("*** VZWDOG 1.14: time %lu.%06lu uptime %Lu CPU %d ***\n", ++ tv.tv_sec, (long)tv.tv_usec, ++ (unsigned long long)get_jiffies_64(), ++ smp_processor_id()); ++#ifdef CONFIG_FAIRSCHED ++ printk("*** cycles_per_jiffy %lu jiffies_per_second %u ***\n", ++ cycles_per_jiffy, HZ); ++#else ++ printk("*** jiffies_per_second %u ***\n", HZ); ++#endif ++ preempt_enable(); ++} ++ ++static void show_pgdatinfo(void) ++{ ++ pg_data_t *pgdat; ++ ++ printk("pgdat:"); ++ for_each_online_pgdat(pgdat) { ++ printk(" %d: %lu,%lu,%lu", ++ pgdat->node_id, ++ pgdat->node_start_pfn, ++ pgdat->node_present_pages, ++ pgdat->node_spanned_pages); ++#ifdef CONFIG_FLAT_NODE_MEM_MAP ++ printk(",%p", pgdat->node_mem_map); ++#endif ++ } ++ printk("\n"); ++} ++ ++static void show_diskio(void) ++{ ++ struct gendisk *gd; ++ char buf[BDEVNAME_SIZE]; ++ ++ printk("disk_io: "); ++ ++ list_for_each_entry(gd, &block_subsys.list, kobj.entry) { ++ char *name; ++ name = disk_name(gd, 0, buf); ++ if ((strlen(name) > 4) && (strncmp(name, "loop", 4) == 0) && ++ isdigit(name[4])) ++ continue; ++ if ((strlen(name) > 3) && (strncmp(name, "ram", 3) == 0) && ++ isdigit(name[3])) ++ continue; ++ printk("(%u,%u) %s r(%lu %lu %lu) w(%lu %lu %lu)\n", ++ gd->major, gd->first_minor, ++ name, ++ disk_stat_read(gd, ios[READ]), ++ disk_stat_read(gd, sectors[READ]), ++ disk_stat_read(gd, merges[READ]), ++ disk_stat_read(gd, ios[WRITE]), ++ disk_stat_read(gd, sectors[WRITE]), ++ disk_stat_read(gd, merges[WRITE])); ++ } ++ ++ printk("\n"); ++} ++ ++static void show_nrprocs(void) ++{ ++ unsigned long _nr_running, _nr_sleeping, ++ _nr_unint, _nr_zombie, _nr_dead, _nr_stopped; ++ ++ _nr_running = nr_running(); ++ _nr_unint = nr_uninterruptible(); ++ _nr_sleeping = nr_sleeping(); ++ _nr_zombie = nr_zombie; ++ _nr_dead = atomic_read(&nr_dead); ++ _nr_stopped = nr_stopped(); ++ ++ printk("VEnum: %d, proc R %lu, S %lu, D %lu, " ++ "Z %lu, X %lu, T %lu (tot %d)\n", ++ nr_ve, _nr_running, _nr_sleeping, _nr_unint, ++ _nr_zombie, _nr_dead, _nr_stopped, nr_threads); ++} ++ ++static void wdog_print(void) ++{ ++ show_header(); ++ show_irq_list(); ++ show_pgdatinfo(); ++ show_mem(); ++ show_diskio(); ++ show_schedule_latency(); ++ show_alloc_latency(); ++ show_nrprocs(); ++} ++ ++static int wdog_loop(void* data) ++{ ++ while (1) { ++ wdog_print(); ++ try_to_freeze(); ++ ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ if (kthread_should_stop()) ++ break; ++ schedule_timeout(sleep_timeout*HZ); ++ } ++ return 0; ++} ++ ++static int __init wdog_init(void) ++{ ++ struct file *file; ++ ++ file = filp_open("/proc/interrupts", 0, 0); ++ if (IS_ERR(file)) ++ return PTR_ERR(file); ++ intr_file = file; ++ ++ wdog_thread_tsk = kthread_run(wdog_loop, NULL, "vzwdog"); ++ if (IS_ERR(wdog_thread_tsk)) { ++ filp_close(intr_file, NULL); ++ return -EBUSY; ++ } ++ return 0; ++} ++ ++static void __exit wdog_exit(void) ++{ ++ kthread_stop(wdog_thread_tsk); ++ filp_close(intr_file, NULL); ++} ++ ++module_param(sleep_timeout, int, 0660); ++MODULE_AUTHOR("SWsoft "); ++MODULE_DESCRIPTION("Virtuozzo WDOG"); ++MODULE_LICENSE("GPL v2"); ++ ++module_init(wdog_init) ++module_exit(wdog_exit) +Index: kernel/lib/Kconfig.debug +=================================================================== +--- kernel.orig/lib/Kconfig.debug 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/lib/Kconfig.debug 2008-11-24 15:47:46.000000000 +0100 +@@ -79,6 +79,14 @@ + exported to $(INSTALL_HDR_PATH) (usually 'usr/include' in + your build tree), to make sure they're suitable. + ++config SYSRQ_DEBUG ++ bool "Debugging via sysrq keys" ++ depends on MAGIC_SYSRQ ++ help ++ Say Y if you want to extend functionality of magic key. It will ++ provide you with some debugging facilities such as dumping and ++ writing memory, resolving symbols and some other. ++ + config DEBUG_KERNEL + bool "Kernel debugging" + help +Index: kernel/lib/bust_spinlocks.c +=================================================================== +--- kernel.orig/lib/bust_spinlocks.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/lib/bust_spinlocks.c 2008-11-24 15:47:46.000000000 +0100 +@@ -12,10 +12,13 @@ + #include + #include + #include +- ++#include + + void __attribute__((weak)) bust_spinlocks(int yes) + { ++ if (printk_no_wake) ++ return; ++ + if (yes) { + ++oops_in_progress; + } else { +Index: kernel/lib/kobject.c +=================================================================== +--- kernel.orig/lib/kobject.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/lib/kobject.c 2008-11-24 15:47:46.000000000 +0100 +@@ -558,7 +558,7 @@ + INIT_LIST_HEAD(&k->list); + spin_lock_init(&k->list_lock); + } +- ++EXPORT_SYMBOL(kset_init); + + /** + * kset_add - add a kset object to the hierarchy. +@@ -632,6 +632,14 @@ + return ret; + } + ++/** ++ * subsystem_register - register a subsystem. ++ * @s: the subsystem we're registering. ++ * ++ * Once we register the subsystem, we want to make sure that ++ * the kset points back to this subsystem for correct usage of ++ * the rwsem. ++ */ + int subsystem_register(struct kset *s) + { + return kset_register(s); +Index: kernel/lib/kobject_uevent.c +=================================================================== +--- kernel.orig/lib/kobject_uevent.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/lib/kobject_uevent.c 2008-11-24 15:47:46.000000000 +0100 +@@ -36,6 +36,8 @@ + [KOBJ_REMOVE] = "remove", + [KOBJ_CHANGE] = "change", + [KOBJ_MOVE] = "move", ++ [KOBJ_START] = "start", ++ [KOBJ_STOP] = "stop", + [KOBJ_ONLINE] = "online", + [KOBJ_OFFLINE] = "offline", + }; +Index: kernel/mm/filemap.c +=================================================================== +--- kernel.orig/mm/filemap.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/filemap.c 2008-11-24 15:47:46.000000000 +0100 +@@ -42,6 +42,8 @@ + + #include + ++#include ++ + static ssize_t + generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, + loff_t offset, unsigned long nr_segs); +@@ -121,6 +123,7 @@ + + radix_tree_delete(&mapping->page_tree, page->index); + page->mapping = NULL; ++ ub_io_release_debug(page); + mapping->nrpages--; + __dec_zone_page_state(page, NR_FILE_PAGES); + BUG_ON(page_mapped(page)); +Index: kernel/mm/filemap_xip.c +=================================================================== +--- kernel.orig/mm/filemap_xip.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/filemap_xip.c 2008-11-24 15:47:46.000000000 +0100 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + /* + * We do use our own empty page to avoid interference with other users +@@ -195,6 +196,8 @@ + flush_cache_page(vma, address, pte_pfn(*pte)); + pteval = ptep_clear_flush(vma, address, pte); + page_remove_rmap(page, vma); ++ pb_remove_ref(page, mm); ++ ub_unused_privvm_inc(mm, vma); + dec_mm_counter(mm, file_rss); + BUG_ON(pte_dirty(pteval)); + pte_unmap_unlock(pte, ptl); +Index: kernel/mm/fremap.c +=================================================================== +--- kernel.orig/mm/fremap.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/fremap.c 2008-11-24 15:47:46.000000000 +0100 +@@ -20,6 +20,8 @@ + #include + #include + ++#include ++ + static void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) + { +@@ -35,6 +37,7 @@ + if (pte_dirty(pte)) + set_page_dirty(page); + page_remove_rmap(page, vma); ++ pb_remove_ref(page, mm); + page_cache_release(page); + update_hiwater_rss(mm); + dec_mm_counter(mm, file_rss); +@@ -61,8 +64,10 @@ + if (!pte) + goto out; + +- if (!pte_none(*pte)) ++ if (!pte_none(*pte)) { + zap_pte(mm, vma, addr, pte); ++ ub_unused_privvm_inc(mm, vma); ++ } + + set_pte_at(mm, addr, pte, pgoff_to_pte(pgoff)); + /* +@@ -237,4 +242,5 @@ + + return err; + } ++EXPORT_SYMBOL_GPL(sys_remap_file_pages); + +Index: kernel/mm/memory.c +=================================================================== +--- kernel.orig/mm/memory.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/memory.c 2008-11-24 15:47:46.000000000 +0100 +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -50,6 +51,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -60,6 +62,11 @@ + #include + #include + ++#include ++#include ++#include ++#include ++ + #ifndef CONFIG_NEED_MULTIPLE_NODES + /* use the per-pgdat data instead for discontigmem - mbligh */ + unsigned long max_mapnr; +@@ -103,18 +110,21 @@ + pgd_ERROR(*pgd); + pgd_clear(pgd); + } ++EXPORT_SYMBOL_GPL(pgd_clear_bad); + + void pud_clear_bad(pud_t *pud) + { + pud_ERROR(*pud); + pud_clear(pud); + } ++EXPORT_SYMBOL_GPL(pud_clear_bad); + + void pmd_clear_bad(pmd_t *pmd) + { + pmd_ERROR(*pmd); + pmd_clear(pmd); + } ++EXPORT_SYMBOL_GPL(pmd_clear_bad); + + /* + * Note: this doesn't free the actual pages themselves. That +@@ -314,6 +324,7 @@ + spin_unlock(&mm->page_table_lock); + return 0; + } ++EXPORT_SYMBOL_GPL(__pte_alloc); + + int __pte_alloc_kernel(pmd_t *pmd, unsigned long address) + { +@@ -414,6 +425,7 @@ + */ + return pfn_to_page(pfn); + } ++EXPORT_SYMBOL_GPL(vm_normal_page); + + /* + * copy one vm_area from one task to the other. Assumes the page tables +@@ -424,7 +436,7 @@ + static inline void + copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, + pte_t *dst_pte, pte_t *src_pte, struct vm_area_struct *vma, +- unsigned long addr, int *rss) ++ unsigned long addr, int *rss, struct page_beancounter **pbc) + { + unsigned long vm_flags = vma->vm_flags; + pte_t pte = *src_pte; +@@ -479,6 +491,7 @@ + if (page) { + get_page(page); + page_dup_rmap(page, vma, addr); ++ pb_dup_ref(page, dst_mm, pbc); + rss[!!PageAnon(page)]++; + } + +@@ -486,20 +499,35 @@ + set_pte_at(dst_mm, addr, dst_pte, pte); + } + ++#define pte_ptrs(a) (PTRS_PER_PTE - ((a >> PAGE_SHIFT)&(PTRS_PER_PTE - 1))) ++#ifdef CONFIG_BEANCOUNTERS ++#define same_ub(mm1, mm2) ((mm1)->mm_ub == (mm2)->mm_ub) ++#else ++#define same_ub(mm1, mm2) 1 ++#endif ++ + static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm, +- pmd_t *dst_pmd, pmd_t *src_pmd, struct vm_area_struct *vma, ++ pmd_t *dst_pmd, pmd_t *src_pmd, ++ struct vm_area_struct *dst_vma, ++ struct vm_area_struct *vma, + unsigned long addr, unsigned long end) + { + pte_t *src_pte, *dst_pte; + spinlock_t *src_ptl, *dst_ptl; + int progress = 0; +- int rss[2]; ++ int rss[2], rss_tot; ++ struct page_beancounter *pbc; ++ int err; + ++ err = -ENOMEM; ++ pbc = same_ub(src_mm, dst_mm) ? PBC_COPY_SAME : NULL; + again: ++ if (pbc != PBC_COPY_SAME && pb_alloc_list(&pbc, pte_ptrs(addr))) ++ goto out; + rss[1] = rss[0] = 0; + dst_pte = pte_alloc_map_lock(dst_mm, dst_pmd, addr, &dst_ptl); + if (!dst_pte) +- return -ENOMEM; ++ goto out; + src_pte = pte_offset_map_nested(src_pmd, addr); + src_ptl = pte_lockptr(src_mm, src_pmd); + spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING); +@@ -521,23 +549,32 @@ + progress++; + continue; + } +- copy_one_pte(dst_mm, src_mm, dst_pte, src_pte, vma, addr, rss); ++ copy_one_pte(dst_mm, src_mm, dst_pte, src_pte, vma, addr, rss, ++ &pbc); + progress += 8; + } while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end); + + arch_leave_lazy_mmu_mode(); + spin_unlock(src_ptl); + pte_unmap_nested(src_pte - 1); ++ rss_tot = rss[0] + rss[1]; ++ ub_unused_privvm_sub(dst_mm, dst_vma, rss_tot); + add_mm_rss(dst_mm, rss[0], rss[1]); + pte_unmap_unlock(dst_pte - 1, dst_ptl); + cond_resched(); + if (addr != end) + goto again; +- return 0; ++ ++ err = 0; ++out: ++ pb_free_list(&pbc); ++ return err; + } + + static inline int copy_pmd_range(struct mm_struct *dst_mm, struct mm_struct *src_mm, +- pud_t *dst_pud, pud_t *src_pud, struct vm_area_struct *vma, ++ pud_t *dst_pud, pud_t *src_pud, ++ struct vm_area_struct *dst_vma, ++ struct vm_area_struct *vma, + unsigned long addr, unsigned long end) + { + pmd_t *src_pmd, *dst_pmd; +@@ -552,14 +589,16 @@ + if (pmd_none_or_clear_bad(src_pmd)) + continue; + if (copy_pte_range(dst_mm, src_mm, dst_pmd, src_pmd, +- vma, addr, next)) ++ dst_vma, vma, addr, next)) + return -ENOMEM; + } while (dst_pmd++, src_pmd++, addr = next, addr != end); + return 0; + } + + static inline int copy_pud_range(struct mm_struct *dst_mm, struct mm_struct *src_mm, +- pgd_t *dst_pgd, pgd_t *src_pgd, struct vm_area_struct *vma, ++ pgd_t *dst_pgd, pgd_t *src_pgd, ++ struct vm_area_struct *dst_vma, ++ struct vm_area_struct *vma, + unsigned long addr, unsigned long end) + { + pud_t *src_pud, *dst_pud; +@@ -574,19 +613,21 @@ + if (pud_none_or_clear_bad(src_pud)) + continue; + if (copy_pmd_range(dst_mm, src_mm, dst_pud, src_pud, +- vma, addr, next)) ++ dst_vma, vma, addr, next)) + return -ENOMEM; + } while (dst_pud++, src_pud++, addr = next, addr != end); + return 0; + } + +-int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm, +- struct vm_area_struct *vma) ++int __copy_page_range(struct vm_area_struct *dst_vma, ++ struct vm_area_struct *vma, ++ unsigned long addr, size_t size) + { ++ struct mm_struct *dst_mm = dst_vma->vm_mm; ++ struct mm_struct *src_mm = vma->vm_mm; + pgd_t *src_pgd, *dst_pgd; + unsigned long next; +- unsigned long addr = vma->vm_start; +- unsigned long end = vma->vm_end; ++ unsigned long end = addr + size; + + /* + * Don't copy ptes where a page fault will fill them correctly. +@@ -609,11 +650,22 @@ + if (pgd_none_or_clear_bad(src_pgd)) + continue; + if (copy_pud_range(dst_mm, src_mm, dst_pgd, src_pgd, +- vma, addr, next)) ++ dst_vma, vma, addr, next)) + return -ENOMEM; + } while (dst_pgd++, src_pgd++, addr = next, addr != end); + return 0; + } ++EXPORT_SYMBOL_GPL(__copy_page_range); ++ ++int copy_page_range(struct mm_struct *dst, struct mm_struct *src, ++ struct vm_area_struct *dst_vma, struct vm_area_struct *vma) ++{ ++ if (dst_vma->vm_mm != dst) ++ BUG(); ++ if (vma->vm_mm != src) ++ BUG(); ++ return __copy_page_range(dst_vma, vma, vma->vm_start, vma->vm_end-vma->vm_start); ++} + + static unsigned long zap_pte_range(struct mmu_gather *tlb, + struct vm_area_struct *vma, pmd_t *pmd, +@@ -625,6 +677,7 @@ + spinlock_t *ptl; + int file_rss = 0; + int anon_rss = 0; ++ int rss; + + pte = pte_offset_map_lock(mm, pmd, addr, &ptl); + arch_enter_lazy_mmu_mode(); +@@ -679,6 +732,7 @@ + file_rss--; + } + page_remove_rmap(page, vma); ++ pb_remove_ref(page, mm); + tlb_remove_page(tlb, page); + continue; + } +@@ -693,6 +747,8 @@ + pte_clear_not_present_full(mm, addr, pte, tlb->fullmm); + } while (pte++, addr += PAGE_SIZE, (addr != end && *zap_work > 0)); + ++ rss = -(file_rss + anon_rss); ++ ub_unused_privvm_add(mm, vma, rss); + add_mm_rss(mm, file_rss, anon_rss); + arch_leave_lazy_mmu_mode(); + pte_unmap_unlock(pte - 1, ptl); +@@ -1581,6 +1637,7 @@ + int reuse = 0, ret = 0; + int page_mkwrite = 0; + struct page *dirty_page = NULL; ++ struct page_beancounter *pbc; + + old_page = vm_normal_page(vma, address, orig_pte); + if (!old_page) +@@ -1640,6 +1697,7 @@ + flush_cache_page(vma, address, pte_pfn(orig_pte)); + entry = pte_mkyoung(orig_pte); + entry = maybe_mkwrite(pte_mkdirty(entry), vma); ++ ClearPageCheckpointed(old_page); + if (ptep_set_access_flags(vma, address, page_table, entry,1)) + update_mmu_cache(vma, address, entry); + ret |= VM_FAULT_WRITE; +@@ -1653,6 +1711,9 @@ + gotten: + pte_unmap_unlock(page_table, ptl); + ++ if (unlikely(pb_alloc(&pbc))) ++ goto oom_nopb; ++ + if (unlikely(anon_vma_prepare(vma))) + goto oom; + VM_BUG_ON(old_page == ZERO_PAGE(0)); +@@ -1668,12 +1729,15 @@ + if (likely(pte_same(*page_table, orig_pte))) { + if (old_page) { + page_remove_rmap(old_page, vma); ++ pb_remove_ref(old_page, mm); + if (!PageAnon(old_page)) { + dec_mm_counter(mm, file_rss); + inc_mm_counter(mm, anon_rss); + } +- } else ++ } else { ++ ub_unused_privvm_dec(mm, vma); + inc_mm_counter(mm, anon_rss); ++ } + flush_cache_page(vma, address, pte_pfn(orig_pte)); + entry = mk_pte(new_page, vma->vm_page_prot); + entry = maybe_mkwrite(pte_mkdirty(entry), vma); +@@ -1688,6 +1752,7 @@ + update_mmu_cache(vma, address, entry); + lru_cache_add_active(new_page); + page_add_new_anon_rmap(new_page, vma, address); ++ pb_add_ref(new_page, mm, &pbc); + + /* Free the old page.. */ + new_page = old_page; +@@ -1697,6 +1762,7 @@ + page_cache_release(new_page); + if (old_page) + page_cache_release(old_page); ++ pb_free(&pbc); + unlock: + pte_unmap_unlock(page_table, ptl); + if (dirty_page) { +@@ -1717,6 +1783,8 @@ + } + return ret; + oom: ++ pb_free(&pbc); ++oom_nopb: + if (old_page) + page_cache_release(old_page); + return VM_FAULT_OOM; +@@ -2087,10 +2155,16 @@ + swp_entry_t entry; + pte_t pte; + int ret = 0; ++ struct page_beancounter *pbc; ++ cycles_t start; + + if (!pte_unmap_same(mm, pmd, page_table, orig_pte)) +- goto out; ++ goto out_nostat; ++ ++ if (unlikely(pb_alloc(&pbc))) ++ return VM_FAULT_OOM; + ++ start = get_cycles(); + entry = pte_to_swp_entry(orig_pte); + if (is_migration_entry(entry)) { + migration_entry_wait(mm, pmd, address); +@@ -2138,6 +2212,7 @@ + /* The page isn't present yet, go ahead with the fault. */ + + inc_mm_counter(mm, anon_rss); ++ ub_percpu_inc(mm->mm_ub, swapin); + pte = mk_pte(page, vma->vm_page_prot); + if (write_access && can_share_swap_page(page)) { + pte = maybe_mkwrite(pte_mkdirty(pte), vma); +@@ -2147,10 +2222,11 @@ + flush_icache_page(vma, page); + set_pte_at(mm, address, page_table, pte); + page_add_anon_rmap(page, vma, address); ++ pb_add_ref(page, mm, &pbc); ++ ub_unused_privvm_dec(mm, vma); + + swap_free(entry); +- if (vm_swap_full()) +- remove_exclusive_swap_page(page); ++ try_to_remove_exclusive_swap_page(page); + unlock_page(page); + + if (write_access) { +@@ -2166,9 +2242,15 @@ + unlock: + pte_unmap_unlock(page_table, ptl); + out: ++ pb_free(&pbc); ++ spin_lock_irq(&kstat_glb_lock); ++ KSTAT_LAT_ADD(&kstat_glob.swap_in, get_cycles() - start); ++ spin_unlock_irq(&kstat_glb_lock); ++out_nostat: + return ret; + out_nomap: + pte_unmap_unlock(page_table, ptl); ++ pb_free(&pbc); + unlock_page(page); + page_cache_release(page); + return ret; +@@ -2186,10 +2268,14 @@ + struct page *page; + spinlock_t *ptl; + pte_t entry; ++ struct page_beancounter *pbc; + + /* Allocate our own private page. */ + pte_unmap(page_table); + ++ if (unlikely(pb_alloc(&pbc))) ++ goto oom_nopb; ++ + if (unlikely(anon_vma_prepare(vma))) + goto oom; + page = alloc_zeroed_user_highpage_movable(vma, address); +@@ -2205,17 +2291,22 @@ + inc_mm_counter(mm, anon_rss); + lru_cache_add_active(page); + page_add_new_anon_rmap(page, vma, address); ++ pb_add_ref(page, mm, &pbc); ++ ub_unused_privvm_dec(mm, vma); + set_pte_at(mm, address, page_table, entry); + + /* No need to invalidate - it was non-present before */ + update_mmu_cache(vma, address, entry); + unlock: ++ pb_free(&pbc); + pte_unmap_unlock(page_table, ptl); + return 0; + release: + page_cache_release(page); + goto unlock; + oom: ++ pb_free(&pbc); ++oom_nopb: + return VM_FAULT_OOM; + } + +@@ -2242,6 +2333,7 @@ + pte_t entry; + int anon = 0; + struct page *dirty_page = NULL; ++ struct page_beancounter *pbc; + struct vm_fault vmf; + int ret; + int page_mkwrite = 0; +@@ -2253,6 +2345,9 @@ + + BUG_ON(vma->vm_flags & VM_PFNMAP); + ++ if (unlikely(pb_alloc(&pbc))) ++ goto oom_nopb; ++ + if (likely(vma->vm_ops->fault)) { + ret = vma->vm_ops->fault(vma, &vmf); + if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) +@@ -2263,9 +2358,9 @@ + vmf.page = vma->vm_ops->nopage(vma, address & PAGE_MASK, &ret); + /* no page was available -- either SIGBUS or OOM */ + if (unlikely(vmf.page == NOPAGE_SIGBUS)) +- return VM_FAULT_SIGBUS; ++ goto bus_nopg; + else if (unlikely(vmf.page == NOPAGE_OOM)) +- return VM_FAULT_OOM; ++ goto oom_nopg; + } + + /* +@@ -2341,6 +2436,8 @@ + */ + /* Only go through if we didn't race with anybody else... */ + if (likely(pte_same(*page_table, orig_pte))) { ++ struct user_beancounter *ub; ++ + flush_icache_page(vma, page); + entry = mk_pte(page, vma->vm_page_prot); + if (flags & FAULT_FLAG_WRITE) +@@ -2358,6 +2455,25 @@ + get_page(dirty_page); + } + } ++ ub = page_ub(page); ++ if (ub != NULL && ++#ifdef CONFIG_BC_IO_ACCOUNTING ++ !((unsigned long)ub & PAGE_IO_MARK) && ++#endif ++ ub->ub_magic == UB_MAGIC) { ++ /* ++ * WOW: Page was already charged as page_ub. This may ++ * happens for example then some driver export its low ++ * memory pages to user space. We can't account page as ++ * page_ub and page_bp at the same time. So uncharge ++ * page from UB counter. ++ */ ++ WARN_ON_ONCE(1); ++ ub_page_uncharge(page, 0); ++ } ++ ++ pb_add_ref(page, mm, &pbc); ++ ub_unused_privvm_dec(mm, vma); + + /* no need to invalidate: a not-present page won't be cached */ + update_mmu_cache(vma, address, entry); +@@ -2382,8 +2498,15 @@ + set_page_dirty_balance(dirty_page, page_mkwrite); + put_page(dirty_page); + } +- ++ pb_free(&pbc); + return ret; ++bus_nopg: ++ pb_free(&pbc); ++ return VM_FAULT_SIGBUS; ++oom_nopg: ++ pb_free(&pbc); ++oom_nopb: ++ return VM_FAULT_OOM; + } + + static int do_linear_fault(struct mm_struct *mm, struct vm_area_struct *vma, +@@ -2561,6 +2684,27 @@ + pmd_t *pmd; + pte_t *pte; + ++#ifdef CONFIG_VZ_GENCALLS ++ do { ++ int ret; ++#ifdef CONFIG_BEANCOUNTERS ++ struct task_beancounter *tbc; ++ ++ tbc = ¤t->task_bc; ++ if (!test_bit(UB_AFLAG_NOTIF_PAGEIN, &mm->mm_ub->ub_aflags) && ++ tbc->pgfault_allot) { ++ tbc->pgfault_allot--; ++ break; /* skip notifier */ ++ } ++#endif ++ ret = virtinfo_notifier_call(VITYPE_GENERAL, VIRTINFO_PAGEIN, ++ (void *)1); ++ if (ret & NOTIFY_FAIL) ++ return VM_FAULT_SIGBUS; ++ if (ret & NOTIFY_OK) ++ return VM_FAULT_MINOR; /* retry */ ++ } while (0); ++#endif + __set_current_state(TASK_RUNNING); + + count_vm_event(PGFAULT); +@@ -2603,6 +2747,8 @@ + } + #endif /* __PAGETABLE_PUD_FOLDED */ + ++EXPORT_SYMBOL_GPL(__pud_alloc); ++ + #ifndef __PAGETABLE_PMD_FOLDED + /* + * Allocate page middle directory. +@@ -2631,6 +2777,8 @@ + } + #endif /* __PAGETABLE_PMD_FOLDED */ + ++EXPORT_SYMBOL_GPL(__pmd_alloc); ++ + int make_pages_present(unsigned long addr, unsigned long end) + { + int ret, len, write; +@@ -2650,6 +2798,8 @@ + return ret == len ? 0 : -1; + } + ++EXPORT_SYMBOL(make_pages_present); ++ + /* + * Map a vmalloc()-space virtual address to the physical page. + */ +Index: kernel/mm/mempolicy.c +=================================================================== +--- kernel.orig/mm/mempolicy.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/mempolicy.c 2008-11-24 15:47:46.000000000 +0100 +@@ -89,6 +89,7 @@ + #include + #include + #include ++#include + + #include + #include +Index: kernel/mm/mempool.c +=================================================================== +--- kernel.orig/mm/mempool.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/mempool.c 2008-11-24 15:47:46.000000000 +0100 +@@ -77,6 +77,8 @@ + init_waitqueue_head(&pool->wait); + pool->alloc = alloc_fn; + pool->free = free_fn; ++ if (alloc_fn == mempool_alloc_slab) ++ kmem_mark_nocharge((struct kmem_cache *)pool_data); + + /* + * First pre-allocate the guaranteed number of buffers. +@@ -118,6 +120,7 @@ + unsigned long flags; + + BUG_ON(new_min_nr <= 0); ++ gfp_mask &= ~__GFP_UBC; + + spin_lock_irqsave(&pool->lock, flags); + if (new_min_nr <= pool->min_nr) { +@@ -211,6 +214,7 @@ + gfp_mask |= __GFP_NOMEMALLOC; /* don't allocate emergency reserves */ + gfp_mask |= __GFP_NORETRY; /* don't loop in __alloc_pages */ + gfp_mask |= __GFP_NOWARN; /* failures are OK */ ++ gfp_mask &= ~__GFP_UBC; + + gfp_temp = gfp_mask & ~(__GFP_WAIT|__GFP_IO); + +Index: kernel/mm/mlock.c +=================================================================== +--- kernel.orig/mm/mlock.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/mlock.c 2008-11-24 15:47:46.000000000 +0100 +@@ -8,10 +8,12 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include + + int can_do_mlock(void) + { +@@ -36,6 +38,14 @@ + goto out; + } + ++ if (newflags & VM_LOCKED) { ++ ret = ub_locked_charge(mm, end - start); ++ if (ret < 0) { ++ *prev = vma; ++ goto out; ++ } ++ } ++ + pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); + *prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma, + vma->vm_file, pgoff, vma_policy(vma)); +@@ -49,13 +59,13 @@ + if (start != vma->vm_start) { + ret = split_vma(mm, vma, start, 1); + if (ret) +- goto out; ++ goto out_uncharge; + } + + if (end != vma->vm_end) { + ret = split_vma(mm, vma, end, 0); + if (ret) +- goto out; ++ goto out_uncharge; + } + + success: +@@ -74,13 +84,19 @@ + pages = -pages; + if (!(newflags & VM_IO)) + ret = make_pages_present(start, end); +- } ++ } else ++ ub_locked_uncharge(mm, end - start); + + mm->locked_vm -= pages; + out: + if (ret == -ENOMEM) + ret = -EAGAIN; + return ret; ++ ++out_uncharge: ++ if (newflags & VM_LOCKED) ++ ub_locked_uncharge(mm, end - start); ++ goto out; + } + + static int do_mlock(unsigned long start, size_t len, int on) +@@ -157,6 +173,7 @@ + up_write(¤t->mm->mmap_sem); + return error; + } ++EXPORT_SYMBOL_GPL(sys_mlock); + + asmlinkage long sys_munlock(unsigned long start, size_t len) + { +@@ -169,6 +186,7 @@ + up_write(¤t->mm->mmap_sem); + return ret; + } ++EXPORT_SYMBOL_GPL(sys_munlock); + + static int do_mlockall(int flags) + { +Index: kernel/mm/mmap.c +=================================================================== +--- kernel.orig/mm/mmap.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/mmap.c 2008-11-24 15:47:46.000000000 +0100 +@@ -26,6 +26,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -36,9 +38,12 @@ + #define arch_mmap_check(addr, len, flags) (0) + #endif + ++#include ++ + static void unmap_region(struct mm_struct *mm, + struct vm_area_struct *vma, struct vm_area_struct *prev, + unsigned long start, unsigned long end); ++static unsigned long __do_brk(unsigned long addr, unsigned long len, int soft); + + /* + * WARNING: the debugging will use recursive algorithms so never enable this +@@ -100,6 +105,18 @@ + + vm_acct_memory(pages); + ++#ifdef CONFIG_BEANCOUNTERS ++ switch (virtinfo_notifier_call(VITYPE_GENERAL, VIRTINFO_ENOUGHMEM, ++ (void *)pages) ++ & (NOTIFY_OK | NOTIFY_FAIL)) { ++ case NOTIFY_OK: ++ return 0; ++ case NOTIFY_FAIL: ++ vm_unacct_memory(pages); ++ return -ENOMEM; ++ } ++#endif ++ + /* + * Sometimes we want to use more memory than we have + */ +@@ -224,6 +241,9 @@ + struct vm_area_struct *next = vma->vm_next; + + might_sleep(); ++ ++ ub_memory_uncharge(vma->vm_mm, vma->vm_end - vma->vm_start, ++ vma->vm_flags, vma->vm_file); + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +@@ -271,7 +291,7 @@ + goto out; + + /* Ok, looks good - let it rip. */ +- if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk) ++ if (__do_brk(oldbrk, newbrk-oldbrk, UB_HARD) != oldbrk) + goto out; + set_brk: + mm->brk = brk; +@@ -910,7 +930,7 @@ + prot |= PROT_EXEC; + + if (!len) +- return -EINVAL; ++ return addr; + + if (!(flags & MAP_FIXED)) + addr = round_hint_to_min(addr); +@@ -1026,6 +1046,9 @@ + if (error) + return error; + ++ if (!gr_acl_handle_mmap(file, prot)) ++ return -EACCES; ++ + return mmap_region(file, addr, len, flags, vm_flags, pgoff, + accountable); + } +@@ -1076,6 +1099,7 @@ + struct rb_node **rb_link, *rb_parent; + unsigned long charged = 0; + struct inode *inode = file ? file->f_path.dentry->d_inode : NULL; ++ unsigned long ub_charged = 0; + + /* Clear old maps */ + error = -ENOMEM; +@@ -1107,6 +1131,11 @@ + } + } + ++ if (ub_memory_charge(mm, len, vm_flags, file, ++ (flags & MAP_EXECPRIO ? UB_SOFT : UB_HARD))) ++ goto charge_error; ++ ub_charged = 1; ++ + /* + * Can we just expand an old private anonymous mapping? + * The VM_SHARED test is necessary because shmem_zero_setup +@@ -1122,7 +1151,8 @@ + * specific mapper. the address has already been validated, but + * not unmapped, but the maps are removed from the list. + */ +- vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); ++ vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL | ++ (flags & MAP_EXECPRIO ? __GFP_SOFT_UBC : 0)); + if (!vma) { + error = -ENOMEM; + goto unacct_error; +@@ -1150,6 +1180,19 @@ + error = file->f_op->mmap(file, vma); + if (error) + goto unmap_and_free_vma; ++ if (vm_flags != vma->vm_flags) { ++ /* ++ * ->vm_flags has been changed in f_op->mmap method. ++ * We have to recharge ub memory. ++ */ ++ ub_memory_uncharge(mm, len, vm_flags, file); ++ if (ub_memory_charge(mm, len, vma->vm_flags, file, ++ (flags & MAP_EXECPRIO ? UB_SOFT : UB_HARD))) { ++ ub_charged = 0; ++ error = -ENOMEM; ++ goto unmap_and_free_vma; ++ } ++ } + } else if (vm_flags & VM_SHARED) { + error = shmem_zero_setup(vma); + if (error) +@@ -1214,6 +1257,9 @@ + free_vma: + kmem_cache_free(vm_area_cachep, vma); + unacct_error: ++ if (ub_charged) ++ ub_memory_uncharge(mm, len, vm_flags, file); ++charge_error: + if (charged) + vm_unacct_memory(charged); + return error; +@@ -1536,12 +1582,16 @@ + if (is_hugepage_only_range(vma->vm_mm, new_start, size)) + return -EFAULT; + ++ if (ub_memory_charge(mm, grow << PAGE_SHIFT, vma->vm_flags, ++ vma->vm_file, UB_SOFT)) ++ goto fail_charge; ++ + /* + * Overcommit.. This must be the final test, as it will + * update security statistics. + */ + if (security_vm_enough_memory(grow)) +- return -ENOMEM; ++ goto fail_sec; + + /* Ok, everything looks good - let it rip */ + mm->total_vm += grow; +@@ -1549,6 +1599,11 @@ + mm->locked_vm += grow; + vm_stat_account(mm, vma->vm_flags, vma->vm_file, grow); + return 0; ++ ++fail_sec: ++ ub_memory_uncharge(mm, grow << PAGE_SHIFT, vma->vm_flags, vma->vm_file); ++fail_charge: ++ return -ENOMEM; + } + + #if defined(CONFIG_STACK_GROWSUP) || defined(CONFIG_IA64) +@@ -1829,6 +1884,7 @@ + + return 0; + } ++EXPORT_SYMBOL_GPL(split_vma); + + /* Munmap is split into 2 main parts -- this part which finds + * what needs doing, and the areas themselves, which do the +@@ -1922,7 +1978,7 @@ + * anonymous maps. eventually we may be able to do some + * brk-specific accounting here. + */ +-unsigned long do_brk(unsigned long addr, unsigned long len) ++static unsigned long __do_brk(unsigned long addr, unsigned long len, int soft) + { + struct mm_struct * mm = current->mm; + struct vm_area_struct * vma, * prev; +@@ -1988,8 +2044,11 @@ + if (mm->map_count > sysctl_max_map_count) + return -ENOMEM; + ++ if (ub_memory_charge(mm, len, flags, NULL, soft)) ++ goto fail_charge; ++ + if (security_vm_enough_memory(len >> PAGE_SHIFT)) +- return -ENOMEM; ++ goto fail_sec; + + /* Can we just expand an old private anonymous mapping? */ + if (vma_merge(mm, prev, addr, addr + len, flags, +@@ -1999,11 +2058,10 @@ + /* + * create a vma struct for an anonymous mapping + */ +- vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); +- if (!vma) { +- vm_unacct_memory(len >> PAGE_SHIFT); +- return -ENOMEM; +- } ++ vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL | ++ (soft == UB_SOFT ? __GFP_SOFT_UBC : 0)); ++ if (!vma) ++ goto fail_alloc; + + vma->vm_mm = mm; + vma->vm_start = addr; +@@ -2019,8 +2077,19 @@ + make_pages_present(addr, addr + len); + } + return addr; ++ ++fail_alloc: ++ vm_unacct_memory(len >> PAGE_SHIFT); ++fail_sec: ++ ub_memory_uncharge(mm, len, flags, NULL); ++fail_charge: ++ return -ENOMEM; + } + ++unsigned long do_brk(unsigned long addr, unsigned long len) ++{ ++ return __do_brk(addr, len, UB_SOFT); ++} + EXPORT_SYMBOL(do_brk); + + /* Release all mmaps. */ +@@ -2187,10 +2256,11 @@ + { + } + +-static struct vm_operations_struct special_mapping_vmops = { ++struct vm_operations_struct special_mapping_vmops = { + .close = special_mapping_close, + .nopage = special_mapping_nopage, + }; ++EXPORT_SYMBOL_GPL(special_mapping_vmops); + + /* + * Called with mm->mmap_sem held for writing. +Index: kernel/mm/mmzone.c +=================================================================== +--- kernel.orig/mm/mmzone.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/mmzone.c 2008-11-24 15:47:46.000000000 +0100 +@@ -13,6 +13,7 @@ + { + return NODE_DATA(first_online_node); + } ++EXPORT_SYMBOL(first_online_pgdat); /* June 2006 */ + + struct pglist_data *next_online_pgdat(struct pglist_data *pgdat) + { +@@ -22,6 +23,7 @@ + return NULL; + return NODE_DATA(nid); + } ++EXPORT_SYMBOL(next_online_pgdat); /* June 2006 */ + + /* + * next_zone - helper magic for for_each_zone() +Index: kernel/mm/mprotect.c +=================================================================== +--- kernel.orig/mm/mprotect.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/mprotect.c 2008-11-24 15:47:46.000000000 +0100 +@@ -9,6 +9,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -21,11 +22,14 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + ++#include ++ + static void change_pte_range(struct mm_struct *mm, pmd_t *pmd, + unsigned long addr, unsigned long end, pgprot_t newprot, + int dirty_accountable) +@@ -137,6 +141,8 @@ + unsigned long charged = 0; + pgoff_t pgoff; + int error; ++ unsigned long ch_size; ++ int ch_dir; + int dirty_accountable = 0; + + if (newflags == oldflags) { +@@ -144,6 +150,12 @@ + return 0; + } + ++ error = -ENOMEM; ++ ch_size = nrpages - pages_in_vma_range(vma, start, end); ++ ch_dir = ub_protected_charge(mm, ch_size, newflags, vma); ++ if (ch_dir == PRIVVM_ERROR) ++ goto fail_ch; ++ + /* + * If we make a private mapping writable we increase our commit; + * but (without finer accounting) cannot reduce our commit if we +@@ -156,7 +168,7 @@ + if (!(oldflags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))) { + charged = nrpages; + if (security_vm_enough_memory(charged)) +- return -ENOMEM; ++ goto fail_sec; + newflags |= VM_ACCOUNT; + } + } +@@ -204,10 +216,16 @@ + change_protection(vma, start, end, vma->vm_page_prot, dirty_accountable); + vm_stat_account(mm, oldflags, vma->vm_file, -nrpages); + vm_stat_account(mm, newflags, vma->vm_file, nrpages); ++ if (ch_dir == PRIVVM_TO_SHARED) ++ __ub_unused_privvm_dec(mm, ch_size); + return 0; + + fail: + vm_unacct_memory(charged); ++fail_sec: ++ if (ch_dir == PRIVVM_TO_PRIVATE) ++ __ub_unused_privvm_dec(mm, ch_size); ++fail_ch: + return error; + } + +@@ -269,6 +287,11 @@ + if (start > vma->vm_start) + prev = vma; + ++ if (!gr_acl_handle_mprotect(vma->vm_file, prot)) { ++ error = -EACCES; ++ goto out; ++ } ++ + for (nstart = start ; ; ) { + unsigned long newflags; + +@@ -309,3 +332,4 @@ + up_write(¤t->mm->mmap_sem); + return error; + } ++EXPORT_SYMBOL_GPL(sys_mprotect); +Index: kernel/mm/mremap.c +=================================================================== +--- kernel.orig/mm/mremap.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/mremap.c 2008-11-24 15:47:46.000000000 +0100 +@@ -23,6 +23,8 @@ + #include + #include + ++#include ++ + static pmd_t *get_old_pmd(struct mm_struct *mm, unsigned long addr) + { + pgd_t *pgd; +@@ -167,17 +169,21 @@ + unsigned long hiwater_vm; + int split = 0; + ++ if (ub_memory_charge(mm, new_len, vm_flags, ++ vma->vm_file, UB_HARD)) ++ goto err; ++ + /* + * We'd prefer to avoid failure later on in do_munmap: + * which may split one vma into three before unmapping. + */ + if (mm->map_count >= sysctl_max_map_count - 3) +- return -ENOMEM; ++ goto err_nomem; + + new_pgoff = vma->vm_pgoff + ((old_addr - vma->vm_start) >> PAGE_SHIFT); + new_vma = copy_vma(&vma, new_addr, new_len, new_pgoff); + if (!new_vma) +- return -ENOMEM; ++ goto err_nomem; + + moved_len = move_page_tables(vma, old_addr, new_vma, new_addr, old_len); + if (moved_len < old_len) { +@@ -236,7 +242,13 @@ + new_addr + new_len); + } + +- return new_addr; ++ if (new_addr != -ENOMEM) ++ return new_addr; ++ ++err_nomem: ++ ub_memory_uncharge(mm, new_len, vm_flags, vma->vm_file); ++err: ++ return -ENOMEM; + } + + static struct vm_area_struct *vma_to_resize(unsigned long addr, +@@ -436,7 +448,15 @@ + if (old_len == vma->vm_end - addr) { + /* can we just expand the current mapping? */ + if (vma_expandable(vma, new_len - old_len)) { +- int pages = (new_len - old_len) >> PAGE_SHIFT; ++ unsigned long len; ++ int pages; ++ ++ len = new_len - old_len; ++ pages = len >> PAGE_SHIFT; ++ ret = -ENOMEM; ++ if (ub_memory_charge(mm, len, vma->vm_flags, ++ vma->vm_file, UB_HARD)) ++ goto out; + + vma_adjust(vma, vma->vm_start, + addr + new_len, vma->vm_pgoff, NULL); +Index: kernel/mm/oom_kill.c +=================================================================== +--- kernel.orig/mm/oom_kill.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/oom_kill.c 2008-11-24 15:47:46.000000000 +0100 +@@ -19,6 +19,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -26,6 +28,9 @@ + #include + #include + ++#include ++#include ++ + int sysctl_panic_on_oom; + int sysctl_oom_kill_allocating_task; + static DEFINE_SPINLOCK(zone_scan_mutex); +@@ -194,15 +199,15 @@ + * + * (not docbooked, we don't want this one cluttering up the manual) + */ +-static struct task_struct *select_bad_process(unsigned long *ppoints) ++struct task_struct *oom_select_bad_process(struct user_beancounter *ub) + { + struct task_struct *g, *p; + struct task_struct *chosen = NULL; + struct timespec uptime; +- *ppoints = 0; ++ unsigned long chosen_points = 0; + + do_posix_clock_monotonic_gettime(&uptime); +- do_each_thread(g, p) { ++ do_each_thread_all(g, p) { + unsigned long points; + + /* +@@ -214,6 +219,8 @@ + /* skip the init task */ + if (is_global_init(p)) + continue; ++ if (ub_oom_task_skip(ub, p)) ++ continue; + + /* + * This task already has access to memory reserves and is +@@ -242,18 +249,18 @@ + return ERR_PTR(-1UL); + + chosen = p; +- *ppoints = ULONG_MAX; ++ chosen_points = ULONG_MAX; + } + + if (p->oomkilladj == OOM_DISABLE) + continue; + + points = badness(p, uptime.tv_sec); +- if (points > *ppoints || !chosen) { ++ if (points > chosen_points || !chosen) { + chosen = p; +- *ppoints = points; ++ chosen_points = points; + } +- } while_each_thread(g, p); ++ } while_each_thread_all(g, p); + + return chosen; + } +@@ -290,13 +297,16 @@ + set_tsk_thread_flag(p, TIF_MEMDIE); + + force_sig(SIGKILL, p); ++ ub_oom_task_killed(p); + } + + static int oom_kill_task(struct task_struct *p) + { + struct mm_struct *mm; ++ struct user_beancounter *ub; + struct task_struct *g, *q; + ++ task_lock(p); + mm = p->mm; + + /* WARNING: mm may not be dereferenced since we did not obtain its +@@ -308,16 +318,21 @@ + * However, this is of no concern to us. + */ + +- if (mm == NULL) ++ if (mm == NULL) { ++ task_unlock(p); + return 1; ++ } ++ ++ ub = get_beancounter(mm_ub(mm)); ++ task_unlock(p); + + /* + * Don't kill the process if any threads are set to OOM_DISABLE + */ +- do_each_thread(g, q) { ++ do_each_thread_all(g, q) { + if (q->mm == mm && q->oomkilladj == OOM_DISABLE) + return 1; +- } while_each_thread(g, q); ++ } while_each_thread_all(g, q); + + __oom_kill_task(p, 1); + +@@ -326,16 +341,18 @@ + * but are in a different thread group. Don't let them have access + * to memory reserves though, otherwise we might deplete all memory. + */ +- do_each_thread(g, q) { ++ do_each_thread_all(g, q) { + if (q->mm == mm && !same_thread_group(q, p)) + force_sig(SIGKILL, q); +- } while_each_thread(g, q); ++ } while_each_thread_all(g, q); + ++ ub_oom_mm_killed(ub); ++ put_beancounter(ub); + return 0; + } + +-static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, +- unsigned long points, const char *message) ++int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, ++ const char *message) + { + struct task_struct *c; + +@@ -356,8 +373,8 @@ + return 0; + } + +- printk(KERN_ERR "%s: kill process %d (%s) score %li or a child\n", +- message, task_pid_nr(p), p->comm, points); ++ printk(KERN_ERR "%s: kill process %d (%s) or a child\n", ++ message, task_pid_nr(p), p->comm); + + /* Try to kill a child first */ + list_for_each_entry(c, &p->children, sibling) { +@@ -445,9 +462,9 @@ + void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order) + { + struct task_struct *p; +- unsigned long points = 0; + unsigned long freed = 0; + enum oom_constraint constraint; ++ struct user_beancounter *ub; + + blocking_notifier_call_chain(&oom_notify_list, 0, &freed); + if (freed > 0) +@@ -457,16 +474,34 @@ + if (sysctl_panic_on_oom == 2) + panic("out of memory. Compulsory panic_on_oom is selected.\n"); + ++ if (virtinfo_notifier_call(VITYPE_GENERAL, VIRTINFO_OUTOFMEM, NULL) ++ & (NOTIFY_OK | NOTIFY_FAIL)) ++ return; ++ ++ ub = NULL; ++ if (ub_oom_lock()) ++ goto out_oom_lock; ++ ++ read_lock(&tasklist_lock); ++ ++ if (printk_ratelimit()) { ++ printk(KERN_WARNING "%s invoked oom-killer: " ++ "gfp_mask=0x%x, order=%d, oomkilladj=%d\n", ++ current->comm, gfp_mask, order, current->oomkilladj); ++ dump_stack(); ++ show_mem(); ++ show_slab_info(); ++ } ++ + /* + * Check if there were limitations on the allocation (only relevant for + * NUMA) that may require different handling. + */ + constraint = constrained_alloc(zonelist, gfp_mask); +- read_lock(&tasklist_lock); + + switch (constraint) { + case CONSTRAINT_MEMORY_POLICY: +- oom_kill_process(current, gfp_mask, order, points, ++ oom_kill_process(current, gfp_mask, order, + "No available memory (MPOL_BIND)"); + break; + +@@ -476,27 +511,33 @@ + /* Fall-through */ + case CONSTRAINT_CPUSET: + if (sysctl_oom_kill_allocating_task) { +- oom_kill_process(current, gfp_mask, order, points, ++ oom_kill_process(current, gfp_mask, order, + "Out of memory (oom_kill_allocating_task)"); + break; + } + retry: ++ put_beancounter(ub); ++ + /* + * Rambo mode: Shoot down a process and hope it solves whatever + * issues we may have. + */ +- p = select_bad_process(&points); ++ ub = ub_oom_select_worst(); ++ p = oom_select_bad_process(ub); + + if (PTR_ERR(p) == -1UL) + goto out; + + /* Found nothing?!?! Either we hang forever, or we panic. */ + if (!p) { ++ if (ub != NULL) ++ goto retry; + read_unlock(&tasklist_lock); ++ ub_oom_unlock(); + panic("Out of memory and no killable processes...\n"); + } + +- if (oom_kill_process(p, gfp_mask, order, points, ++ if (oom_kill_process(p, gfp_mask, order, + "Out of memory")) + goto retry; + +@@ -505,7 +546,10 @@ + + out: + read_unlock(&tasklist_lock); ++ ub_oom_unlock(); ++ put_beancounter(ub); + ++out_oom_lock: + /* + * Give "p" a good chance of killing itself before we + * retry to allocate memory unless "p" is current +Index: kernel/mm/page-writeback.c +=================================================================== +--- kernel.orig/mm/page-writeback.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/page-writeback.c 2008-11-24 15:47:46.000000000 +0100 +@@ -35,6 +35,9 @@ + #include + #include + ++#include ++#include ++ + /* + * The maximum number of pages to writeout in a single bdflush/kupdate + * operation. We do this so we don't hold I_SYNC against an inode for +@@ -822,6 +825,7 @@ + scanned = 1; + for (i = 0; i < nr_pages; i++) { + struct page *page = pvec.pages[i]; ++ struct user_beancounter *old_ub; + + /* + * At this point we hold neither mapping->tree_lock nor +@@ -852,7 +856,9 @@ + continue; + } + ++ old_ub = bc_io_switch_context(page); + ret = (*writepage)(page, wbc, data); ++ bc_io_restore_context(old_ub); + + if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE)) { + unlock_page(page); +@@ -948,12 +954,15 @@ + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 1, + }; ++ struct user_beancounter *old_ub; + + BUG_ON(!PageLocked(page)); + + if (wait) + wait_on_page_writeback(page); + ++ old_ub = bc_io_switch_context(page); ++ + if (clear_page_dirty_for_io(page)) { + page_cache_get(page); + ret = mapping->a_ops->writepage(page, &wbc); +@@ -966,6 +975,9 @@ + } else { + unlock_page(page); + } ++ ++ bc_io_restore_context(old_ub); ++ + return ret; + } + EXPORT_SYMBOL(write_one_page); +@@ -997,6 +1009,9 @@ + */ + int __set_page_dirty_nobuffers(struct page *page) + { ++ int acct; ++ ++ acct = 0; + if (!TestSetPageDirty(page)) { + struct address_space *mapping = page_mapping(page); + struct address_space *mapping2; +@@ -1004,6 +1019,7 @@ + if (!mapping) + return 1; + ++ acct = 0; + write_lock_irq(&mapping->tree_lock); + mapping2 = page_mapping(page); + if (mapping2) { /* Race with truncate? */ +@@ -1013,12 +1029,14 @@ + __inc_zone_page_state(page, NR_FILE_DIRTY); + __inc_bdi_stat(mapping->backing_dev_info, + BDI_RECLAIMABLE); +- task_io_account_write(PAGE_CACHE_SIZE); ++ acct = 1; + } + radix_tree_tag_set(&mapping->page_tree, + page_index(page), PAGECACHE_TAG_DIRTY); + } + write_unlock_irq(&mapping->tree_lock); ++ if (acct) ++ task_io_account_write(page, PAGE_CACHE_SIZE, 0); + if (mapping->host) { + /* !PageAnon && !swapper_space */ + __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); +@@ -1157,6 +1175,7 @@ + dec_zone_page_state(page, NR_FILE_DIRTY); + dec_bdi_stat(mapping->backing_dev_info, + BDI_RECLAIMABLE); ++ ub_io_release_context(page, PAGE_CACHE_SIZE); + return 1; + } + return 0; +Index: kernel/mm/page_alloc.c +=================================================================== +--- kernel.orig/mm/page_alloc.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/page_alloc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -48,6 +48,9 @@ + #include + #include "internal.h" + ++#include ++#include ++ + /* + * Array of node states. + */ +@@ -99,6 +102,7 @@ + 32, + }; + ++EXPORT_SYMBOL(nr_swap_pages); + EXPORT_SYMBOL(totalram_pages); + + static char * const zone_names[MAX_NR_ZONES] = { +@@ -464,8 +468,11 @@ + 1 << PG_reserved | + 1 << PG_buddy )))) + bad_page(page); +- if (PageDirty(page)) ++ if (PageDirty(page)) { ++ ub_io_release_context(page, 0); + __ClearPageDirty(page); ++ } else ++ ub_io_release_debug(page); + /* + * For now, we report if PG_reserved was found set, but do not + * clear it, and do not free the page. But we shall soon need +@@ -528,6 +535,7 @@ + arch_free_page(page, order); + kernel_map_pages(page, 1 << order, 0); + ++ ub_page_uncharge(page, order); + local_irq_save(flags); + __count_vm_events(PGFREE, 1 << order); + free_one_page(page_zone(page), page, order); +@@ -624,7 +632,8 @@ + + page->flags &= ~(1 << PG_uptodate | 1 << PG_error | 1 << PG_readahead | + 1 << PG_referenced | 1 << PG_arch_1 | +- 1 << PG_owner_priv_1 | 1 << PG_mappedtodisk); ++ 1 << PG_owner_priv_1 | 1 << PG_mappedtodisk | ++ 1 << PG_checkpointed); + set_page_private(page, 0); + set_page_refcounted(page); + +@@ -1002,6 +1011,7 @@ + kernel_map_pages(page, 1, 0); + + pcp = &zone_pcp(zone, get_cpu())->pcp[cold]; ++ ub_page_uncharge(page, 0); + local_irq_save(flags); + __count_vm_event(PGFREE); + list_add(&page->lru, &pcp->list); +@@ -1448,6 +1458,31 @@ + return page; + } + ++extern unsigned long cycles_per_jiffy; ++static void __alloc_collect_stats(gfp_t gfp_mask, unsigned int order, ++ struct page *page, cycles_t time) ++{ ++#ifdef CONFIG_VE ++ int ind; ++ unsigned long flags; ++ ++ time = (jiffies - time) * cycles_per_jiffy; ++ if (!(gfp_mask & __GFP_WAIT)) ++ ind = 0; ++ else if (!(gfp_mask & __GFP_HIGHMEM)) ++ ind = (order > 0 ? 2 : 1); ++ else ++ ind = (order > 0 ? 4 : 3); ++ spin_lock_irqsave(&kstat_glb_lock, flags); ++ KSTAT_LAT_ADD(&kstat_glob.alloc_lat[ind], time); ++ if (!page) ++ kstat_glob.alloc_fails[ind]++; ++ spin_unlock_irqrestore(&kstat_glb_lock, flags); ++#endif ++} ++ ++int alloc_fail_warn; ++ + /* + * This is the 'heart' of the zoned buddy allocator. + */ +@@ -1463,6 +1498,7 @@ + int do_retry; + int alloc_flags; + int did_some_progress; ++ cycles_t start; + + might_sleep_if(wait); + +@@ -1480,6 +1516,7 @@ + return NULL; + } + ++ start = jiffies; + page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, order, + zonelist, ALLOC_WMARK_LOW|ALLOC_CPUSET); + if (page) +@@ -1622,19 +1659,32 @@ + do_retry = 1; + } + if (do_retry) { ++ if (total_swap_pages > 0 && nr_swap_pages == 0) { ++ out_of_memory(zonelist, gfp_mask, order); ++ goto restart; ++ } + congestion_wait(WRITE, HZ/50); + goto rebalance; + } + + nopage: +- if (!(gfp_mask & __GFP_NOWARN) && printk_ratelimit()) { ++ __alloc_collect_stats(gfp_mask, order, NULL, start); ++ if (alloc_fail_warn && !(gfp_mask & __GFP_NOWARN) && ++ printk_ratelimit()) { + printk(KERN_WARNING "%s: page allocation failure." + " order:%d, mode:0x%x\n", + p->comm, order, gfp_mask); + dump_stack(); + show_mem(); + } ++ return NULL; ++ + got_pg: ++ __alloc_collect_stats(gfp_mask, order, page, start); ++ if (ub_page_charge(page, order, gfp_mask)) { ++ __free_pages(page, order); ++ page = NULL; ++ } + return page; + } + +@@ -1702,6 +1752,18 @@ + + EXPORT_SYMBOL(free_pages); + ++unsigned int nr_free_lowpages (void) ++{ ++ pg_data_t *pgdat; ++ unsigned int pages = 0; ++ ++ for_each_online_pgdat(pgdat) ++ pages += zone_page_state(&pgdat->node_zones[ZONE_NORMAL], NR_FREE_PAGES); ++ ++ return pages; ++} ++EXPORT_SYMBOL(nr_free_lowpages); ++ + static unsigned int nr_free_zone_pages(int offset) + { + /* Just pick one node, since fallback list is circular */ +Index: kernel/mm/rmap.c +=================================================================== +--- kernel.orig/mm/rmap.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/rmap.c 2008-11-24 15:47:46.000000000 +0100 +@@ -50,6 +50,9 @@ + #include + #include + ++#include ++#include ++ + #include + + struct kmem_cache *anon_vma_cachep; +@@ -93,6 +96,7 @@ + } + return 0; + } ++EXPORT_SYMBOL_GPL(anon_vma_prepare); + + void __anon_vma_merge(struct vm_area_struct *vma, struct vm_area_struct *next) + { +@@ -118,6 +122,7 @@ + spin_unlock(&anon_vma->lock); + } + } ++EXPORT_SYMBOL_GPL(anon_vma_link); + + void anon_vma_unlink(struct vm_area_struct *vma) + { +@@ -149,14 +154,14 @@ + void __init anon_vma_init(void) + { + anon_vma_cachep = kmem_cache_create("anon_vma", sizeof(struct anon_vma), +- 0, SLAB_DESTROY_BY_RCU|SLAB_PANIC, anon_vma_ctor); ++ 0, SLAB_DESTROY_BY_RCU|SLAB_PANIC|SLAB_UBC, anon_vma_ctor); + } + + /* + * Getting a lock on a stable anon_vma from a page off the LRU is + * tricky: page_lock_anon_vma rely on RCU to guard against the races. + */ +-static struct anon_vma *page_lock_anon_vma(struct page *page) ++struct anon_vma *page_lock_anon_vma(struct page *page) + { + struct anon_vma *anon_vma; + unsigned long anon_mapping; +@@ -175,12 +180,14 @@ + rcu_read_unlock(); + return NULL; + } ++EXPORT_SYMBOL_GPL(page_lock_anon_vma); + +-static void page_unlock_anon_vma(struct anon_vma *anon_vma) ++void page_unlock_anon_vma(struct anon_vma *anon_vma) + { + spin_unlock(&anon_vma->lock); + rcu_read_unlock(); + } ++EXPORT_SYMBOL_GPL(page_unlock_anon_vma); + + /* + * At what user virtual address is page expected in @vma? +@@ -644,6 +651,13 @@ + page_clear_dirty(page); + set_page_dirty(page); + } ++ ++ /* ++ * Well, when a page is unmapped, we cannot keep PG_checkpointed ++ * flag, it is not accessible via process VM and we have no way ++ * to reset its state ++ */ ++ ClearPageCheckpointed(page); + __dec_zone_page_state(page, + PageAnon(page) ? NR_ANON_PAGES : NR_FILE_MAPPED); + } +@@ -735,6 +749,9 @@ + + + page_remove_rmap(page, vma); ++ ub_unused_privvm_inc(mm, vma); ++ ub_percpu_inc(mm->mm_ub, unmap); ++ pb_remove_ref(page, mm); + page_cache_release(page); + + out_unmap: +@@ -825,6 +842,9 @@ + set_page_dirty(page); + + page_remove_rmap(page, vma); ++ ub_percpu_inc(mm->mm_ub, unmap); ++ pb_remove_ref(page, mm); ++ ub_unused_privvm_inc(mm, vma); + page_cache_release(page); + dec_mm_counter(mm, file_rss); + (*mapcount)--; +Index: kernel/mm/shmem.c +=================================================================== +--- kernel.orig/mm/shmem.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/shmem.c 2008-11-24 15:47:46.000000000 +0100 +@@ -54,6 +54,8 @@ + #include + #include + ++#include ++ + /* This magic number is used in glibc for posix shared memory */ + #define TMPFS_MAGIC 0x01021994 + +@@ -181,7 +183,7 @@ + + static const struct super_operations shmem_ops; + static const struct address_space_operations shmem_aops; +-static const struct file_operations shmem_file_operations; ++const struct file_operations shmem_file_operations; + static const struct inode_operations shmem_inode_operations; + static const struct inode_operations shmem_dir_inode_operations; + static const struct inode_operations shmem_special_inode_operations; +@@ -220,7 +222,7 @@ + * + * It has to be called with the spinlock held. + */ +-static void shmem_recalc_inode(struct inode *inode) ++static void shmem_recalc_inode(struct inode *inode, long swp_freed) + { + struct shmem_inode_info *info = SHMEM_I(inode); + long freed; +@@ -230,6 +232,8 @@ + info->alloced -= freed; + shmem_unacct_blocks(info->flags, freed); + shmem_free_blocks(inode, freed); ++ if (freed > swp_freed) ++ ub_tmpfs_respages_sub(info, freed - swp_freed); + } + } + +@@ -335,6 +339,11 @@ + struct page *page = kmap_atomic_to_page(entry); + set_page_private(page, page_private(page) + incdec); + } ++ ++ if (incdec == 1) ++ ub_tmpfs_respages_dec(info); ++ else ++ ub_tmpfs_respages_inc(info); + } + + /* +@@ -351,14 +360,24 @@ + struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); + struct page *page = NULL; + swp_entry_t *entry; ++ unsigned long ub_val; + + if (sgp != SGP_WRITE && + ((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) + return ERR_PTR(-EINVAL); + ++ ub_val = 0; ++ if (info->next_index <= index) { ++ ub_val = index + 1 - info->next_index; ++ if (ub_shmpages_charge(info, ub_val)) ++ return ERR_PTR(-ENOSPC); ++ } ++ + while (!(entry = shmem_swp_entry(info, index, &page))) { +- if (sgp == SGP_READ) +- return shmem_swp_map(ZERO_PAGE(0)); ++ if (sgp == SGP_READ) { ++ entry = shmem_swp_map(ZERO_PAGE(0)); ++ goto out; ++ } + /* + * Test free_blocks against 1 not 0, since we have 1 data + * page (and perhaps indirect index pages) yet to allocate: +@@ -368,7 +387,8 @@ + spin_lock(&sbinfo->stat_lock); + if (sbinfo->free_blocks <= 1) { + spin_unlock(&sbinfo->stat_lock); +- return ERR_PTR(-ENOSPC); ++ entry = ERR_PTR(-ENOSPC); ++ goto out; + } + sbinfo->free_blocks--; + inode->i_blocks += BLOCKS_PER_PAGE; +@@ -376,31 +396,43 @@ + } + + spin_unlock(&info->lock); +- page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping)); ++ page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping) | ++ __GFP_UBC); + if (page) + set_page_private(page, 0); + spin_lock(&info->lock); + + if (!page) { +- shmem_free_blocks(inode, 1); +- return ERR_PTR(-ENOMEM); ++ entry = ERR_PTR(-ENOMEM); ++ goto out_block; + } + if (sgp != SGP_WRITE && + ((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) { + entry = ERR_PTR(-EINVAL); +- break; ++ goto out_dir; + } +- if (info->next_index <= index) ++ if (info->next_index <= index) { ++ ub_val = 0; + info->next_index = index + 1; ++ } + } + if (page) { + /* another task gave its page, or truncated the file */ + shmem_free_blocks(inode, 1); + shmem_dir_free(page); + } +- if (info->next_index <= index && !IS_ERR(entry)) ++ if (info->next_index <= index) + info->next_index = index + 1; + return entry; ++ ++out_dir: ++ shmem_dir_free(page); ++out_block: ++ shmem_free_blocks(inode, 1); ++out: ++ if (ub_val) ++ ub_shmpages_uncharge(info, ub_val); ++ return entry; + } + + /* +@@ -509,6 +541,7 @@ + return; + + spin_lock(&info->lock); ++ ub_shmpages_uncharge(info, info->next_index - idx); + info->flags |= SHMEM_TRUNCATE; + if (likely(end == (loff_t) -1)) { + limit = info->next_index; +@@ -695,7 +728,7 @@ + info->swapped -= nr_swaps_freed; + if (nr_pages_to_free) + shmem_free_blocks(inode, nr_pages_to_free); +- shmem_recalc_inode(inode); ++ shmem_recalc_inode(inode, nr_swaps_freed); + spin_unlock(&info->lock); + + /* +@@ -782,6 +815,7 @@ + sbinfo->free_inodes++; + spin_unlock(&sbinfo->stat_lock); + } ++ shmi_ub_put(info); + clear_inode(inode); + } + +@@ -903,6 +937,12 @@ + return found; + } + ++#ifdef CONFIG_BEANCOUNTERS ++#define shm_get_swap_page(info) (get_swap_page((info)->shmi_ub)) ++#else ++#define shm_get_swap_page(info) (get_swap_page(NULL)) ++#endif ++ + /* + * Move the page from the page cache to the swap cache. + */ +@@ -938,12 +978,12 @@ + info = SHMEM_I(inode); + if (info->flags & VM_LOCKED) + goto redirty; +- swap = get_swap_page(); ++ swap = shm_get_swap_page(info); + if (!swap.val) + goto redirty; + + spin_lock(&info->lock); +- shmem_recalc_inode(inode); ++ shmem_recalc_inode(inode, 0); + if (index >= info->next_index) { + BUG_ON(!(info->flags & SHMEM_TRUNCATE)); + goto unlock; +@@ -1140,7 +1180,7 @@ + goto failed; + + spin_lock(&info->lock); +- shmem_recalc_inode(inode); ++ shmem_recalc_inode(inode, 0); + entry = shmem_swp_alloc(info, idx, sgp); + if (IS_ERR(entry)) { + spin_unlock(&info->lock); +@@ -1309,6 +1349,7 @@ + clear_highpage(filepage); + flush_dcache_page(filepage); + SetPageUptodate(filepage); ++ ub_tmpfs_respages_inc(info); + } + done: + if (*pagep != filepage) { +@@ -1420,6 +1461,7 @@ + inode->i_generation = get_seconds(); + info = SHMEM_I(inode); + memset(info, 0, (char *)inode - (char *)info); ++ shmi_ub_set(info, get_exec_ub()); + spin_lock_init(&info->lock); + INIT_LIST_HEAD(&info->swaplist); + +@@ -2371,7 +2413,7 @@ + .migratepage = migrate_page, + }; + +-static const struct file_operations shmem_file_operations = { ++const struct file_operations shmem_file_operations = { + .mmap = shmem_mmap, + #ifdef CONFIG_TMPFS + .llseek = generic_file_llseek, +@@ -2382,6 +2424,7 @@ + .splice_write = generic_file_splice_write, + #endif + }; ++EXPORT_SYMBOL_GPL(shmem_file_operations); + + static const struct inode_operations shmem_inode_operations = { + .truncate = shmem_truncate, +@@ -2450,6 +2493,10 @@ + #endif + }; + ++int is_shmem_mapping(struct address_space *map) ++{ ++ return (map != NULL && map->a_ops == &shmem_aops); ++} + + static int shmem_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) +@@ -2457,13 +2504,19 @@ + return get_sb_nodev(fs_type, flags, data, shmem_fill_super, mnt); + } + +-static struct file_system_type tmpfs_fs_type = { ++struct file_system_type tmpfs_fs_type = { + .owner = THIS_MODULE, + .name = "tmpfs", + .get_sb = shmem_get_sb, + .kill_sb = kill_litter_super, + }; ++EXPORT_SYMBOL(tmpfs_fs_type); ++ ++#ifdef CONFIG_VE ++#define shm_mnt (get_exec_env()->shmem_mnt) ++#else + static struct vfsmount *shm_mnt; ++#endif + + static int __init init_tmpfs(void) + { +@@ -2504,6 +2557,36 @@ + } + module_init(init_tmpfs) + ++static inline int shm_charge_ahead(struct inode *inode) ++{ ++#ifdef CONFIG_BEANCOUNTERS ++ struct shmem_inode_info *info = SHMEM_I(inode); ++ unsigned long idx; ++ swp_entry_t *entry; ++ ++ if (!inode->i_size) ++ return 0; ++ idx = (inode->i_size - 1) >> PAGE_CACHE_SHIFT; ++ /* ++ * Just touch info to allocate space for entry and ++ * make all UBC checks ++ */ ++ spin_lock(&info->lock); ++ entry = shmem_swp_alloc(info, idx, SGP_CACHE); ++ if (IS_ERR(entry)) ++ goto err; ++ shmem_swp_unmap(entry); ++ spin_unlock(&info->lock); ++ return 0; ++ ++err: ++ spin_unlock(&info->lock); ++ return PTR_ERR(entry); ++#else ++ return 0; ++#endif ++} ++ + /* + * shmem_file_setup - get an unlinked file living in tmpfs + * +@@ -2551,6 +2634,9 @@ + d_instantiate(dentry, inode); + inode->i_size = size; + inode->i_nlink = 0; /* It is unlinked */ ++ error = shm_charge_ahead(inode); ++ if (error) ++ goto close_file; + init_file(file, shm_mnt, dentry, FMODE_WRITE | FMODE_READ, + &shmem_file_operations); + return file; +@@ -2563,6 +2649,7 @@ + shmem_unacct_size(flags, size); + return ERR_PTR(error); + } ++EXPORT_SYMBOL_GPL(shmem_file_setup); + + /* + * shmem_zero_setup - setup a shared anonymous mapping +@@ -2580,6 +2667,8 @@ + + if (vma->vm_file) + fput(vma->vm_file); ++ else if (vma->vm_flags & VM_WRITE) ++ __ub_unused_privvm_dec(vma->vm_mm, size >> PAGE_SHIFT); + vma->vm_file = file; + vma->vm_ops = &shmem_vm_ops; + return 0; +Index: kernel/mm/slab.c +=================================================================== +--- kernel.orig/mm/slab.c 2008-11-24 14:17:45.000000000 +0100 ++++ kernel/mm/slab.c 2008-11-24 15:47:46.000000000 +0100 +@@ -110,30 +110,14 @@ + #include + #include + #include ++#include ++#include + + #include + #include + #include + +-/* +- * DEBUG - 1 for kmem_cache_create() to honour; SLAB_RED_ZONE & SLAB_POISON. +- * 0 for faster, smaller code (especially in the critical paths). +- * +- * STATS - 1 to collect stats for /proc/slabinfo. +- * 0 for faster, smaller code (especially in the critical paths). +- * +- * FORCED_DEBUG - 1 enables SLAB_RED_ZONE and SLAB_POISON (if possible) +- */ +- +-#ifdef CONFIG_DEBUG_SLAB +-#define DEBUG 1 +-#define STATS 1 +-#define FORCED_DEBUG 1 +-#else +-#define DEBUG 0 +-#define STATS 0 +-#define FORCED_DEBUG 0 +-#endif ++#include + + /* Shouldn't this be in a header file somewhere? */ + #define BYTES_PER_WORD sizeof(void *) +@@ -172,18 +156,20 @@ + #endif + + /* Legal flag mask for kmem_cache_create(). */ +-#if DEBUG ++#if SLAB_DEBUG + # define CREATE_MASK (SLAB_RED_ZONE | \ + SLAB_POISON | SLAB_HWCACHE_ALIGN | \ + SLAB_CACHE_DMA | \ + SLAB_STORE_USER | \ + SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \ +- SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD) ++ SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD | \ ++ SLAB_UBC | SLAB_NO_CHARGE) + #else + # define CREATE_MASK (SLAB_HWCACHE_ALIGN | \ + SLAB_CACHE_DMA | \ + SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \ +- SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD) ++ SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD | \ ++ SLAB_UBC | SLAB_NO_CHARGE) + #endif + + /* +@@ -372,87 +358,6 @@ + MAKE_LIST((cachep), (&(ptr)->slabs_free), slabs_free, nodeid); \ + } while (0) + +-/* +- * struct kmem_cache +- * +- * manages a cache. +- */ +- +-struct kmem_cache { +-/* 1) per-cpu data, touched during every alloc/free */ +- struct array_cache *array[NR_CPUS]; +-/* 2) Cache tunables. Protected by cache_chain_mutex */ +- unsigned int batchcount; +- unsigned int limit; +- unsigned int shared; +- +- unsigned int buffer_size; +- u32 reciprocal_buffer_size; +-/* 3) touched by every alloc & free from the backend */ +- +- unsigned int flags; /* constant flags */ +- unsigned int num; /* # of objs per slab */ +- +-/* 4) cache_grow/shrink */ +- /* order of pgs per slab (2^n) */ +- unsigned int gfporder; +- +- /* force GFP flags, e.g. GFP_DMA */ +- gfp_t gfpflags; +- +- size_t colour; /* cache colouring range */ +- unsigned int colour_off; /* colour offset */ +- struct kmem_cache *slabp_cache; +- unsigned int slab_size; +- unsigned int dflags; /* dynamic flags */ +- +- /* constructor func */ +- void (*ctor)(struct kmem_cache *, void *); +- +-/* 5) cache creation/removal */ +- const char *name; +- struct list_head next; +- +-/* 6) statistics */ +-#if STATS +- unsigned long num_active; +- unsigned long num_allocations; +- unsigned long high_mark; +- unsigned long grown; +- unsigned long reaped; +- unsigned long errors; +- unsigned long max_freeable; +- unsigned long node_allocs; +- unsigned long node_frees; +- unsigned long node_overflow; +- atomic_t allochit; +- atomic_t allocmiss; +- atomic_t freehit; +- atomic_t freemiss; +-#endif +-#if DEBUG +- /* +- * If debugging is enabled, then the allocator can add additional +- * fields and/or padding to every object. buffer_size contains the total +- * object size including these internal fields, the following two +- * variables contain the offset to the user object and its size. +- */ +- int obj_offset; +- int obj_size; +-#endif +- /* +- * We put nodelists[] at the end of kmem_cache, because we want to size +- * this array to nr_node_ids slots instead of MAX_NUMNODES +- * (see kmem_cache_init()) +- * We still use [MAX_NUMNODES] and not [1] or [0] because cache_cache +- * is statically defined, so we reserve the max number of nodes. +- */ +- struct kmem_list3 *nodelists[MAX_NUMNODES]; +- /* +- * Do not add fields after nodelists[] +- */ +-}; +- + #define CFLGS_OFF_SLAB (0x80000000UL) + #define OFF_SLAB(x) ((x)->flags & CFLGS_OFF_SLAB) + +@@ -467,12 +372,14 @@ + #define REAPTIMEOUT_CPUC (2*HZ) + #define REAPTIMEOUT_LIST3 (4*HZ) + +-#if STATS ++#define STATS_INC_GROWN(x) ((x)->grown++) ++#define STATS_ADD_REAPED(x,y) ((x)->reaped += (y)) ++#define STATS_INC_SHRUNK(x) ((x)->shrunk++) ++ ++#if SLAB_STATS + #define STATS_INC_ACTIVE(x) ((x)->num_active++) + #define STATS_DEC_ACTIVE(x) ((x)->num_active--) + #define STATS_INC_ALLOCED(x) ((x)->num_allocations++) +-#define STATS_INC_GROWN(x) ((x)->grown++) +-#define STATS_ADD_REAPED(x,y) ((x)->reaped += (y)) + #define STATS_SET_HIGH(x) \ + do { \ + if ((x)->num_active > (x)->high_mark) \ +@@ -495,8 +402,6 @@ + #define STATS_INC_ACTIVE(x) do { } while (0) + #define STATS_DEC_ACTIVE(x) do { } while (0) + #define STATS_INC_ALLOCED(x) do { } while (0) +-#define STATS_INC_GROWN(x) do { } while (0) +-#define STATS_ADD_REAPED(x,y) do { } while (0) + #define STATS_SET_HIGH(x) do { } while (0) + #define STATS_INC_ERR(x) do { } while (0) + #define STATS_INC_NODEALLOCS(x) do { } while (0) +@@ -509,7 +414,7 @@ + #define STATS_INC_FREEMISS(x) do { } while (0) + #endif + +-#if DEBUG ++#if SLAB_DEBUG + + /* + * memory layout of objects: +@@ -641,6 +546,8 @@ + #define CACHE(x) { .cs_size = (x) }, + #include + CACHE(ULONG_MAX) ++#include ++ CACHE(ULONG_MAX) + #undef CACHE + }; + EXPORT_SYMBOL(malloc_sizes); +@@ -654,10 +561,17 @@ + static struct cache_names __initdata cache_names[] = { + #define CACHE(x) { .name = "size-" #x, .name_dma = "size-" #x "(DMA)" }, + #include ++ {NULL,}, ++#undef CACHE ++#define CACHE(x) { .name = "size-" #x "(UBC)", .name_dma = "size-" #x "(DMA,UBC)" }, ++#include + {NULL,} + #undef CACHE + }; + ++int malloc_cache_num; ++EXPORT_SYMBOL(malloc_cache_num); ++ + static struct arraycache_init initarray_cache __initdata = + { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; + static struct arraycache_init initarray_generic = +@@ -735,6 +649,7 @@ + */ + static DEFINE_MUTEX(cache_chain_mutex); + static struct list_head cache_chain; ++static spinlock_t cache_chain_lock; + + /* + * chicken and egg problem: delay the per-cpu array allocation +@@ -767,7 +682,9 @@ + { + struct cache_sizes *csizep = malloc_sizes; + +-#if DEBUG ++ if (gfpflags & __GFP_UBC) ++ csizep += malloc_cache_num; ++#if SLAB_DEBUG + /* This happens if someone tries to call + * kmem_cache_create(), or __kmalloc(), before + * the generic caches are initialized. +@@ -797,9 +714,192 @@ + return __find_general_cachep(size, gfpflags); + } + +-static size_t slab_mgmt_size(size_t nr_objs, size_t align) ++static inline kmem_bufctl_t *slab_bufctl(struct slab *slabp) ++{ ++ return (kmem_bufctl_t *) (slabp + 1); ++} ++ ++#ifdef CONFIG_BEANCOUNTERS ++#define init_slab_ubps(cachep, slabp) do { \ ++ if (!((cachep)->flags & SLAB_UBC)) \ ++ break; \ ++ memset(slab_ubcs(cachep, slabp), 0, \ ++ (cachep)->num * sizeof(void *)); \ ++ } while (0) ++ ++#define UB_ALIGN(flags) (flags & SLAB_UBC ? sizeof(void *) : 1) ++#define UB_EXTRA(flags) (flags & SLAB_UBC ? sizeof(void *) : 0) ++#define set_cache_objuse(cachep) do { \ ++ (cachep)->objuse = ((PAGE_SIZE << (cachep)->gfporder) + \ ++ (cachep)->num - 1) / (cachep)->num; \ ++ if (!OFF_SLAB(cachep)) \ ++ break; \ ++ (cachep)->objuse += ((cachep)->slabp_cache->objuse + \ ++ (cachep)->num - 1) / (cachep)->num; \ ++ } while (0) ++ ++void kmem_mark_nocharge(struct kmem_cache *cachep) ++{ ++ cachep->flags |= SLAB_NO_CHARGE; ++} ++ ++int kmem_cache_objuse(struct kmem_cache *cachep) ++{ ++ return cachep->objuse; ++} ++ ++EXPORT_SYMBOL(kmem_cache_objuse); ++ ++int kmem_obj_objuse(void *obj) ++{ ++ return virt_to_cache(obj)->objuse; ++} ++ ++static void kmem_cache_free_block(struct kmem_cache *cachep, ++ struct kmem_list3 *l3, void **objpp, ++ int nr_objects, int node); ++ ++static int kmem_cache_walk_node(struct kmem_cache *cachep, int node, ++ int (*fun)(void *)) ++{ ++ struct array_cache *ac; ++ struct slab *slabp; ++ char *objp; ++ int cpu, i, sz, r, n; ++ struct kmem_list3 *l3; ++ unsigned long map[PAGE_SIZE / sizeof(struct dentry) ++ / BITS_PER_LONG + 1]; ++ ++ if (cachep->num >= sizeof(map) * 8) ++ return -E2BIG; ++ ++ l3 = cachep->nodelists[node]; ++ /* drain all CPU caches to have up-to-date free map */ ++ ++#ifdef CONFIG_NUMA ++ /* walk through all nodes and drain alien caches */ ++ for_each_online_node (n) { ++ if (!cachep->nodelists[n]->alien) ++ continue; ++ ac = cachep->nodelists[n]->alien[node]; ++ if (!ac) ++ continue; ++ kmem_cache_free_block(cachep, cachep->nodelists[node], ++ ac->entry, ac->avail, node); ++ ac->avail = 0; ++ } ++#endif ++ ++ ac = l3->shared; ++ kmem_cache_free_block(cachep, l3, ac->entry, ac->avail, node); ++ ac->avail = 0; ++ for_each_online_cpu(cpu) { ++ ac = cachep->array[cpu]; ++ n = cpu_to_node(cpu); ++ kmem_cache_free_block(cachep, cachep->nodelists[n], ++ ac->entry, ac->avail, n); ++ ac->avail = 0; ++ } ++ ++ list_for_each_entry(slabp, &l3->slabs_full, list) { ++ touch_nmi_watchdog(); ++ for (i = 0, objp = slabp->s_mem; ++ i < cachep->num; ++ i++, objp += cachep->buffer_size) { ++#if SLAB_DEBUG ++ objp += cachep->obj_offset; ++#endif ++ r = (*fun)(objp); ++ if (r) ++ return r; ++ } ++ } ++ ++ list_for_each_entry(slabp, &l3->slabs_partial, list) { ++ touch_nmi_watchdog(); ++ memset(map, 0xff, sizeof(map)); ++ for (i = slabp->free, r = 0; ++ i != BUFCTL_END; ++ i = slab_bufctl(slabp)[i], r++) { ++ if (r > cachep->num) ++ return -1; ++ __clear_bit(i, map); ++ } ++ sz = sizeof(map) * BITS_PER_LONG; ++ for (i = find_first_bit(map, sz); ++ i < cachep->num; ++ i = find_next_bit(map, sz, i + 1)) { ++ objp = slabp->s_mem + i * cachep->buffer_size; ++#if SLAB_DEBUG ++ objp += cachep->obj_offset; ++#endif ++ r = (*fun)(objp); ++ if (r) ++ return r; ++ } ++ } ++ ++ return 0; ++} ++ ++int kmem_cache_walk_objects(struct kmem_cache *cachep, int (*fun)(void *)) ++{ ++ int node; ++ int err; ++ ++ for_each_online_node (node) ++ if ((err = kmem_cache_walk_node(cachep, node, fun)) != 0) ++ return err; ++ ++ return 0; ++} ++ ++unsigned long ub_cache_growth(struct kmem_cache *cachep) ++{ ++ return (cachep->grown - cachep->reaped - cachep->shrunk) ++ << cachep->gfporder; ++} ++ ++#define slab_ubcs(cachep, slabp) ((struct user_beancounter **)\ ++ (ALIGN((unsigned long)(slab_bufctl(slabp) + (cachep)->num),\ ++ sizeof(void *)))) ++ ++struct user_beancounter **ub_slab_ptr(struct kmem_cache *cachep, void *obj) ++{ ++ struct slab *slabp; ++ int objnr; ++ ++ BUG_ON(!(cachep->flags & SLAB_UBC)); ++ slabp = virt_to_slab(obj); ++ objnr = (obj - slabp->s_mem) / cachep->buffer_size; ++ return slab_ubcs(cachep, slabp) + objnr; ++} ++ ++struct user_beancounter *slab_ub(void *obj) + { +- return ALIGN(sizeof(struct slab)+nr_objs*sizeof(kmem_bufctl_t), align); ++ return *ub_slab_ptr(virt_to_cache(obj), obj); ++} ++ ++EXPORT_SYMBOL(slab_ub); ++ ++#else ++#define UB_ALIGN(flags) 1 ++#define UB_EXTRA(flags) 0 ++#define set_cache_objuse(c) do { } while (0) ++#define init_slab_ubps(c, s) do { } while (0) ++#endif ++ ++static size_t slab_mgmt_size_noalign(size_t nr_objs, int flags) ++{ ++ size_t size_noub; ++ ++ size_noub = sizeof(struct slab) + nr_objs * sizeof(kmem_bufctl_t); ++ return ALIGN(size_noub, UB_ALIGN(flags)) + nr_objs * UB_EXTRA(flags); ++} ++ ++static size_t slab_mgmt_size(size_t nr_objs, size_t align, int flags) ++{ ++ return ALIGN(slab_mgmt_size_noalign(nr_objs, flags), align); + } + + /* +@@ -844,20 +944,23 @@ + * into account. + */ + nr_objs = (slab_size - sizeof(struct slab)) / +- (buffer_size + sizeof(kmem_bufctl_t)); ++ (buffer_size + sizeof(kmem_bufctl_t) + ++ UB_EXTRA(flags)); + + /* + * This calculated number will be either the right + * amount, or one greater than what we want. + */ +- if (slab_mgmt_size(nr_objs, align) + nr_objs*buffer_size +- > slab_size) ++ if (slab_mgmt_size(nr_objs, align, flags) + ++ nr_objs * buffer_size > slab_size) + nr_objs--; ++ BUG_ON(slab_mgmt_size(nr_objs, align, flags) + ++ nr_objs * buffer_size > slab_size); + + if (nr_objs > SLAB_LIMIT) + nr_objs = SLAB_LIMIT; + +- mgmt_size = slab_mgmt_size(nr_objs, align); ++ mgmt_size = slab_mgmt_size(nr_objs, align, flags); + } + *num = nr_objs; + *left_over = slab_size - nr_objs*buffer_size - mgmt_size; +@@ -1408,6 +1511,7 @@ + cachep->nodelists[nodeid] = ptr; + local_irq_enable(); + } ++static int offslab_limit; + + /* + * For setting up all the kmem_list3s for cache whose buffer_size is same as +@@ -1481,6 +1585,7 @@ + + /* 1) create the cache_cache */ + INIT_LIST_HEAD(&cache_chain); ++ spin_lock_init(&cache_chain_lock); + list_add(&cache_cache.next, &cache_chain); + cache_cache.colour_off = cache_line_size(); + cache_cache.array[smp_processor_id()] = &initarray_cache.cache; +@@ -1492,7 +1597,7 @@ + */ + cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) + + nr_node_ids * sizeof(struct kmem_list3 *); +-#if DEBUG ++#if SLAB_DEBUG + cache_cache.obj_size = cache_cache.buffer_size; + #endif + cache_cache.buffer_size = ALIGN(cache_cache.buffer_size, +@@ -1539,6 +1644,7 @@ + + slab_early_init = 0; + ++ for (i = 0; i < 2; i++) { + while (sizes->cs_size != ULONG_MAX) { + /* + * For performance, all the general caches are L1 aligned. +@@ -1551,21 +1657,30 @@ + sizes->cs_cachep = kmem_cache_create(names->name, + sizes->cs_size, + ARCH_KMALLOC_MINALIGN, +- ARCH_KMALLOC_FLAGS|SLAB_PANIC, ++ ARCH_KMALLOC_FLAGS|SLAB_PANIC| ++ (i ? SLAB_UBC : 0)|SLAB_NO_CHARGE, + NULL); + } ++ if (!(OFF_SLAB(sizes->cs_cachep))) ++ offslab_limit = sizes->cs_size; + #ifdef CONFIG_ZONE_DMA +- sizes->cs_dmacachep = kmem_cache_create( +- names->name_dma, ++ sizes->cs_dmacachep = kmem_cache_create(names->name_dma, + sizes->cs_size, + ARCH_KMALLOC_MINALIGN, + ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA| ++ (i ? SLAB_UBC : 0) | SLAB_NO_CHARGE| + SLAB_PANIC, + NULL); + #endif + sizes++; + names++; + } ++ ++ sizes++; ++ names++; ++ if (!i) ++ malloc_cache_num = sizes - malloc_sizes; ++ } + /* 4) Replace the bootstrap head arrays */ + { + struct array_cache *ptr; +@@ -1735,7 +1850,7 @@ + kmem_cache_free(cachep->slabp_cache, slab_rcu); + } + +-#if DEBUG ++#if SLAB_DEBUG + + #ifdef CONFIG_DEBUG_PAGEALLOC + static void store_stackinfo(struct kmem_cache *cachep, unsigned long *addr, +@@ -1812,7 +1927,7 @@ + } + #endif + +-#if DEBUG ++#if SLAB_DEBUG + + static void print_objinfo(struct kmem_cache *cachep, void *objp, int lines) + { +@@ -1905,7 +2020,7 @@ + } + #endif + +-#if DEBUG ++#if SLAB_DEBUG + /** + * slab_destroy_objs - destroy a slab and its objects + * @cachep: cache pointer being destroyed +@@ -2013,7 +2128,6 @@ + static size_t calculate_slab_order(struct kmem_cache *cachep, + size_t size, size_t align, unsigned long flags) + { +- unsigned long offslab_limit; + size_t left_over = 0; + int gfporder; + +@@ -2026,15 +2140,10 @@ + continue; + + if (flags & CFLGS_OFF_SLAB) { +- /* +- * Max number of objs-per-slab for caches which +- * use off-slab slabs. Needed to avoid a possible +- * looping condition in cache_grow(). +- */ +- offslab_limit = size - sizeof(struct slab); +- offslab_limit /= sizeof(kmem_bufctl_t); ++ int slab_size; + +- if (num > offslab_limit) ++ slab_size = slab_mgmt_size_noalign(num, flags); ++ if (slab_size > offslab_limit) + break; + } + +@@ -2197,9 +2306,9 @@ + } + } + +-#if DEBUG ++#if SLAB_DEBUG + WARN_ON(strchr(name, ' ')); /* It confuses parsers */ +-#if FORCED_DEBUG ++#if SLAB_FORCED_DEBUG + /* + * Enable redzoning and last user accounting, except for caches with + * large objects, if the increased size would increase the object size +@@ -2284,7 +2393,7 @@ + if (!cachep) + goto oops; + +-#if DEBUG ++#if SLAB_DEBUG + cachep->obj_size = size; + + /* +@@ -2306,7 +2415,7 @@ + else + size += BYTES_PER_WORD; + } +-#if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC) ++#if SLAB_FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC) + if (size >= malloc_sizes[INDEX_L3 + 1].cs_size + && cachep->obj_size > cache_line_size() && size < PAGE_SIZE) { + cachep->obj_offset += PAGE_SIZE - size; +@@ -2338,8 +2447,7 @@ + cachep = NULL; + goto oops; + } +- slab_size = ALIGN(cachep->num * sizeof(kmem_bufctl_t) +- + sizeof(struct slab), align); ++ slab_size = slab_mgmt_size(cachep->num, align, flags); + + /* + * If the slab has been placed off-slab, and we have enough space then +@@ -2352,8 +2460,7 @@ + + if (flags & CFLGS_OFF_SLAB) { + /* really off slab. No need for manual alignment */ +- slab_size = +- cachep->num * sizeof(kmem_bufctl_t) + sizeof(struct slab); ++ slab_size = slab_mgmt_size_noalign(cachep->num, flags); + } + + cachep->colour_off = cache_line_size(); +@@ -2390,7 +2497,10 @@ + } + + /* cache setup completed, link it into the list */ ++ spin_lock(&cache_chain_lock); + list_add(&cachep->next, &cache_chain); ++ spin_unlock(&cache_chain_lock); ++ set_cache_objuse(cachep); + oops: + if (!cachep && (flags & SLAB_PANIC)) + panic("kmem_cache_create(): failed to create slab `%s'\n", +@@ -2400,7 +2510,7 @@ + } + EXPORT_SYMBOL(kmem_cache_create); + +-#if DEBUG ++#if SLAB_DEBUG + static void check_irq_off(void) + { + BUG_ON(!irqs_disabled()); +@@ -2496,10 +2606,11 @@ + } + + slabp = list_entry(p, struct slab, list); +-#if DEBUG ++#if SLAB_DEBUG + BUG_ON(slabp->inuse); + #endif + list_del(&slabp->list); ++ STATS_INC_SHRUNK(cache); + /* + * Safe to drop the lock. The slab is no longer linked + * to the cache. +@@ -2579,10 +2690,14 @@ + /* + * the chain is never empty, cache_cache is never destroyed + */ ++ spin_lock(&cache_chain_lock); + list_del(&cachep->next); ++ spin_unlock(&cache_chain_lock); + if (__cache_shrink(cachep)) { + slab_error(cachep, "Can't free all objects"); ++ spin_lock(&cache_chain_lock); + list_add(&cachep->next, &cache_chain); ++ spin_unlock(&cache_chain_lock); + mutex_unlock(&cache_chain_mutex); + return; + } +@@ -2590,6 +2705,8 @@ + if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU)) + synchronize_rcu(); + ++ ++ ub_kmemcache_free(cachep); + __kmem_cache_destroy(cachep); + mutex_unlock(&cache_chain_mutex); + } +@@ -2615,7 +2732,8 @@ + if (OFF_SLAB(cachep)) { + /* Slab management obj is off-slab. */ + slabp = kmem_cache_alloc_node(cachep->slabp_cache, +- local_flags & ~GFP_THISNODE, nodeid); ++ local_flags & (~(__GFP_UBC | GFP_THISNODE)), ++ nodeid); + if (!slabp) + return NULL; + } else { +@@ -2626,14 +2744,10 @@ + slabp->colouroff = colour_off; + slabp->s_mem = objp + colour_off; + slabp->nodeid = nodeid; ++ init_slab_ubps(cachep, slabp); + return slabp; + } + +-static inline kmem_bufctl_t *slab_bufctl(struct slab *slabp) +-{ +- return (kmem_bufctl_t *) (slabp + 1); +-} +- + static void cache_init_objs(struct kmem_cache *cachep, + struct slab *slabp) + { +@@ -2641,7 +2755,7 @@ + + for (i = 0; i < cachep->num; i++) { + void *objp = index_to_obj(cachep, slabp, i); +-#if DEBUG ++#if SLAB_DEBUG + /* need to poison the objs? */ + if (cachep->flags & SLAB_POISON) + poison_obj(cachep, objp, POISON_FREE); +@@ -2700,7 +2814,7 @@ + + slabp->inuse++; + next = slab_bufctl(slabp)[slabp->free]; +-#if DEBUG ++#if SLAB_DEBUG + slab_bufctl(slabp)[slabp->free] = BUFCTL_FREE; + WARN_ON(slabp->nodeid != nodeid); + #endif +@@ -2714,7 +2828,7 @@ + { + unsigned int objnr = obj_to_index(cachep, slabp, objp); + +-#if DEBUG ++#if SLAB_DEBUG + /* Verify that the slab belongs to the intended node */ + WARN_ON(slabp->nodeid != nodeid); + +@@ -2802,7 +2916,7 @@ + * 'nodeid'. + */ + if (!objp) +- objp = kmem_getpages(cachep, local_flags, nodeid); ++ objp = kmem_getpages(cachep, local_flags & ~__GFP_UBC, nodeid); + if (!objp) + goto failed; + +@@ -2836,7 +2950,7 @@ + return 0; + } + +-#if DEBUG ++#if SLAB_DEBUG + + /* + * Perform extra freeing checks: +@@ -3049,12 +3163,12 @@ + gfp_t flags) + { + might_sleep_if(flags & __GFP_WAIT); +-#if DEBUG ++#if SLAB_DEBUG + kmem_flagcheck(cachep, flags); + #endif + } + +-#if DEBUG ++#if SLAB_DEBUG + static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep, + gfp_t flags, void *objp, void *caller) + { +@@ -3466,9 +3580,14 @@ + cache_alloc_debugcheck_before(cachep, flags); + local_irq_save(save_flags); + objp = __do_cache_alloc(cachep, flags); +- local_irq_restore(save_flags); + objp = cache_alloc_debugcheck_after(cachep, flags, objp, caller); + prefetchw(objp); ++ if (objp && should_charge(cachep, flags) && ++ ub_slab_charge(cachep, objp, flags)) { ++ kmem_cache_free(cachep, objp); ++ objp = NULL; ++ } ++ local_irq_restore(save_flags); + + if (unlikely((flags & __GFP_ZERO) && objp)) + memset(objp, 0, obj_size(cachep)); +@@ -3502,6 +3621,7 @@ + /* fixup slab chains */ + if (slabp->inuse == 0) { + if (l3->free_objects > l3->free_limit) { ++ STATS_INC_SHRUNK(cachep); + l3->free_objects -= cachep->num; + /* No need to drop any previously held + * lock here, even if we have a off-slab slab +@@ -3523,6 +3643,19 @@ + } + } + ++static void kmem_cache_free_block(struct kmem_cache *cachep, struct kmem_list3 *l3, ++ void **objpp, int nr_objects, int node) ++{ ++ unsigned long flags; ++ ++ if (!nr_objects) ++ return; ++ ++ spin_lock_irqsave(&l3->list_lock, flags); ++ free_block(cachep, objpp, nr_objects, node); ++ spin_unlock_irqrestore(&l3->list_lock, flags); ++} ++ + static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac) + { + int batchcount; +@@ -3530,7 +3663,7 @@ + int node = numa_node_id(); + + batchcount = ac->batchcount; +-#if DEBUG ++#if SLAB_DEBUG + BUG_ON(!batchcount || batchcount > ac->avail); + #endif + check_irq_off(); +@@ -3551,7 +3684,7 @@ + + free_block(cachep, ac->entry, batchcount, node); + free_done: +-#if STATS ++#if SLAB_STATS + { + int i = 0; + struct list_head *p; +@@ -3585,6 +3718,9 @@ + check_irq_off(); + objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0)); + ++ if (should_uncharge(cachep)) ++ ub_slab_uncharge(cachep, objp); ++ + /* + * Skip calling cache_free_alien() when the platform is not numa. + * This will avoid cache misses that happen while accessing slabp (which +@@ -3991,7 +4127,7 @@ + if (cachep->buffer_size <= PAGE_SIZE && num_possible_cpus() > 1) + shared = 8; + +-#if DEBUG ++#if SLAB_DEBUG + /* + * With debugging enabled, large batchcount lead to excessively long + * periods with disabled local interrupts. Limit the batchcount +@@ -4059,6 +4195,7 @@ + /* Give up. Setup the next iteration. */ + goto out; + ++ {KSTAT_PERF_ENTER(cache_reap) + list_for_each_entry(searchp, &cache_chain, next) { + check_irq_on(); + +@@ -4099,6 +4236,7 @@ + check_irq_on(); + mutex_unlock(&cache_chain_mutex); + next_reap_node(); ++ KSTAT_PERF_LEAVE(cache_reap)} + out: + /* Set up the next iteration */ + schedule_delayed_work(work, round_jiffies_relative(REAPTIMEOUT_CPUC)); +@@ -4112,7 +4250,7 @@ + * Output format version, so at least we can change it + * without _too_ many complaints. + */ +-#if STATS ++#if SLAB_STATS + seq_puts(m, "slabinfo - version: 2.1 (statistics)\n"); + #else + seq_puts(m, "slabinfo - version: 2.1\n"); +@@ -4121,14 +4259,82 @@ + " "); + seq_puts(m, " : tunables "); + seq_puts(m, " : slabdata "); +-#if STATS ++#if SLAB_STATS + seq_puts(m, " : globalstat " +- " "); ++ " "); + seq_puts(m, " : cpustat "); + #endif + seq_putc(m, '\n'); + } + ++#define SHOW_TOP_SLABS 10 ++ ++static unsigned long get_cache_size(struct kmem_cache *cachep) ++{ ++ unsigned long flags; ++ unsigned long slabs; ++ struct kmem_list3 *l3; ++ struct list_head *lh; ++ int node; ++ ++ slabs = 0; ++ ++ for_each_online_node (node) { ++ l3 = cachep->nodelists[node]; ++ if (l3 == NULL) ++ continue; ++ ++ spin_lock_irqsave(&l3->list_lock, flags); ++ list_for_each (lh, &l3->slabs_full) ++ slabs++; ++ list_for_each (lh, &l3->slabs_partial) ++ slabs++; ++ list_for_each (lh, &l3->slabs_free) ++ slabs++; ++ spin_unlock_irqrestore(&l3->list_lock, flags); ++ } ++ ++ return slabs * (PAGE_SIZE << cachep->gfporder) + ++ (OFF_SLAB(cachep) ? ++ cachep->slabp_cache->buffer_size * slabs : 0); ++} ++ ++void show_slab_info(void) ++{ ++ int i, j; ++ unsigned long size; ++ struct kmem_cache *ptr; ++ unsigned long sizes[SHOW_TOP_SLABS]; ++ struct kmem_cache *top[SHOW_TOP_SLABS]; ++ ++ memset(top, 0, sizeof(top)); ++ memset(sizes, 0, sizeof(sizes)); ++ ++ printk("Top %d caches:\n", SHOW_TOP_SLABS); ++ ++ spin_lock(&cache_chain_lock); ++ list_for_each_entry (ptr, &cache_chain, next) { ++ size = get_cache_size(ptr); ++ ++ j = 0; ++ for (i = 1; i < SHOW_TOP_SLABS; i++) ++ if (sizes[i] < sizes[j]) ++ j = i; ++ ++ if (size > sizes[j]) { ++ sizes[j] = size; ++ top[j] = ptr; ++ } ++ } ++ ++ for (i = 0; i < SHOW_TOP_SLABS; i++) ++ if (top[i]) ++ printk("%-21s: size %10lu objsize %10u\n", ++ top[i]->name, sizes[i], ++ top[i]->buffer_size); ++ spin_unlock(&cache_chain_lock); ++} ++ + static void *s_start(struct seq_file *m, loff_t *pos) + { + loff_t n = *pos; +@@ -4207,19 +4413,20 @@ + if (error) + printk(KERN_ERR "slab: cache %s error: %s\n", name, error); + +- seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", ++ seq_printf(m, "%-21s %6lu %6lu %6u %4u %4d", + name, active_objs, num_objs, cachep->buffer_size, + cachep->num, (1 << cachep->gfporder)); + seq_printf(m, " : tunables %4u %4u %4u", + cachep->limit, cachep->batchcount, cachep->shared); + seq_printf(m, " : slabdata %6lu %6lu %6lu", + active_slabs, num_slabs, shared_avail); +-#if STATS ++#if SLAB_STATS + { /* list3 stats */ + unsigned long high = cachep->high_mark; + unsigned long allocs = cachep->num_allocations; + unsigned long grown = cachep->grown; + unsigned long reaped = cachep->reaped; ++ unsigned long shrunk = cachep->shrunk; + unsigned long errors = cachep->errors; + unsigned long max_freeable = cachep->max_freeable; + unsigned long node_allocs = cachep->node_allocs; +@@ -4227,9 +4434,10 @@ + unsigned long overflows = cachep->node_overflow; + + seq_printf(m, " : globalstat %7lu %6lu %5lu %4lu \ +- %4lu %4lu %4lu %4lu %4lu", allocs, high, grown, ++ %4lu %4lu %4lu %4lu %4lu %4lu", ++ allocs, high, grown, + reaped, errors, max_freeable, node_allocs, +- node_frees, overflows); ++ node_frees, overflows, shrunk); + } + /* cpu stats */ + { +Index: kernel/mm/slub.c +=================================================================== +--- kernel.orig/mm/slub.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/slub.c 2008-11-24 15:47:46.000000000 +0100 +@@ -22,6 +22,8 @@ + #include + #include + ++#include ++ + /* + * Lock order: + * 1. slab_lock(page) +@@ -186,9 +188,11 @@ + + /* + * Set of flags that will prevent slab merging ++ * ++ * FIXME - think over how to allow merging accountable slubs + */ + #define SLUB_NEVER_MERGE (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \ +- SLAB_TRACE | SLAB_DESTROY_BY_RCU) ++ SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_UBC) + + #define SLUB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \ + SLAB_CACHE_DMA) +@@ -326,6 +330,136 @@ + return (p - addr) / s->size; + } + ++#ifdef CONFIG_BEANCOUNTERS ++static inline void inc_cache_grown(struct kmem_cache *s) ++{ ++ atomic_inc(&s->grown); ++} ++ ++static inline void dec_cache_grown(struct kmem_cache *s) ++{ ++ atomic_dec(&s->grown); ++} ++ ++unsigned long ub_cache_growth(struct kmem_cache *cachep) ++{ ++ return atomic_read(&cachep->grown) << cachep->order; ++} ++ ++static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu); ++ ++static int kmem_cache_walk_page(struct page *pg, struct kmem_cache *s, ++ int (*fun)(void *)) ++{ ++ int r; ++ void *p, *start; ++ DECLARE_BITMAP(map, s->objects); ++ ++ start = page_address(pg); ++ ++ bitmap_zero(map, s->objects); ++ for_each_free_object(p, s, pg->freelist) ++ set_bit(slab_index(p, s, start), map); ++ ++ for_each_object(p, s, start) ++ if (!test_bit(slab_index(p, s, start), map)) { ++ r = fun(p); ++ if (r) ++ return r; ++ } ++ ++ return 0; ++} ++ ++int kmem_cache_walk_objects(struct kmem_cache *s, int (*fun)(void *)) ++{ ++ int i; ++ ++ /* run under stopachine only, so no locks at all */ ++ ++ for_each_online_cpu(i) ++ __flush_cpu_slab(s, i); ++ ++ for_each_online_node(i) { ++ int r; ++ struct page *page; ++ struct kmem_cache_node *n; ++ ++ n = get_node(s, i); ++ ++ list_for_each_entry(page, &n->partial, lru) { ++ r = kmem_cache_walk_page(page, s, fun); ++ if (r) ++ return r; ++ } ++ ++ list_for_each_entry(page, &n->full, lru) { ++ r = kmem_cache_walk_page(page, s, fun); ++ if (r) ++ return r; ++ } ++ } ++ ++ return 0; ++} ++ ++int kmem_cache_objuse(struct kmem_cache *cachep) ++{ ++ return cachep->objuse; ++} ++ ++EXPORT_SYMBOL(kmem_cache_objuse); ++ ++int kmem_obj_objuse(void *obj) ++{ ++ return kmem_cache_objuse(virt_to_head_page(obj)->slab); ++} ++ ++EXPORT_SYMBOL(kmem_obj_objuse); ++ ++#define page_ubs(pg) (pg->bc.slub_ubs) ++ ++struct user_beancounter **ub_slab_ptr(struct kmem_cache *s, void *obj) ++{ ++ struct page *pg; ++ ++ BUG_ON(!(s->flags & SLAB_UBC)); ++ pg = virt_to_head_page(obj); ++ return page_ubs(pg) + slab_index(obj, s, page_address(pg)); ++} ++ ++EXPORT_SYMBOL(ub_slab_ptr); ++ ++struct user_beancounter *slab_ub(void *obj) ++{ ++ struct page *pg; ++ ++ pg = virt_to_head_page(obj); ++ BUG_ON(!(pg->slab->flags & SLAB_UBC)); ++ return page_ubs(pg)[slab_index(obj, pg->slab, page_address(pg))]; ++} ++ ++EXPORT_SYMBOL(slab_ub); ++ ++void kmem_mark_nocharge(struct kmem_cache *cachep) ++{ ++ cachep->flags |= SLAB_NO_CHARGE; ++} ++#else ++static inline void inc_cache_grown(struct kmem_cache *s) ++{ ++} ++ ++static inline void dec_cache_grown(struct kmem_cache *s) ++{ ++} ++#endif ++ ++void show_slab_info(void) ++{ ++ /* FIXME - show it */ ++} ++ + #ifdef CONFIG_SLUB_DEBUG + /* + * Debug settings: +@@ -1042,6 +1176,8 @@ + struct page * page; + int pages = 1 << s->order; + ++ flags &= ~__GFP_UBC; ++ + if (s->order) + flags |= __GFP_COMP; + +@@ -1064,9 +1200,12 @@ + NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE, + pages); + ++ inc_cache_grown(s); + return page; + } + ++static void __free_slab(struct kmem_cache *s, struct page *page); ++ + static void setup_object(struct kmem_cache *s, struct page *page, + void *object) + { +@@ -1090,6 +1229,18 @@ + if (!page) + goto out; + ++#ifdef CONFIG_BEANCOUNTERS ++ if (s->flags & SLAB_UBC) { ++ BUG_ON(page_ubs(page) != NULL); ++ page_ubs(page) = kzalloc(s->objects * sizeof(void *), ++ flags & ~__GFP_UBC); ++ if (page_ubs(page) == NULL) { ++ __free_slab(s, page); ++ page = NULL; ++ goto out; ++ } ++ } ++#endif + n = get_node(s, page_to_nid(page)); + if (n) + atomic_long_inc(&n->nr_slabs); +@@ -1137,6 +1288,13 @@ + NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE, + - pages); + ++#ifdef CONFIG_BEANCOUNTERS ++ if (page_ubs(page) != NULL) { ++ BUG_ON(!(s->flags & SLAB_UBC)); ++ kfree(page_ubs(page)); ++ page_ubs(page) = NULL; ++ } ++#endif + __free_pages(page, s->order); + } + +@@ -1159,6 +1317,8 @@ + call_rcu(head, rcu_free_slab); + } else + __free_slab(s, page); ++ ++ dec_cache_grown(s); + } + + static void discard_slab(struct kmem_cache *s, struct page *page) +@@ -1556,6 +1716,13 @@ + object = c->freelist; + c->freelist = object[c->offset]; + } ++ ++ if (object && should_charge(s, gfpflags) && ++ ub_slab_charge(s, object, gfpflags)) { ++ kmem_cache_free(s, object); ++ object = NULL; ++ } ++ + local_irq_restore(flags); + + if (unlikely((gfpflags & __GFP_ZERO) && object)) +@@ -1656,6 +1823,10 @@ + + local_irq_save(flags); + debug_check_no_locks_freed(object, s->objsize); ++ ++ if (should_uncharge(s)) ++ ub_slab_uncharge(s, x); ++ + c = get_cpu_slab(s, smp_processor_id()); + if (likely(page == c->page && c->node >= 0)) { + object[c->offset] = c->freelist; +@@ -2208,6 +2379,9 @@ + #ifdef CONFIG_NUMA + s->defrag_ratio = 100; + #endif ++#ifdef CONFIG_BEANCOUNTERS ++ s->objuse = s->size + (sizeof(struct page) / s->objects); ++#endif + if (!init_kmem_cache_nodes(s, gfpflags & ~SLUB_DMA)) + goto error; + +@@ -2334,6 +2508,10 @@ + + struct kmem_cache kmalloc_caches[PAGE_SHIFT] __cacheline_aligned; + EXPORT_SYMBOL(kmalloc_caches); ++#ifdef CONFIG_BEANCOUNTERS ++struct kmem_cache ub_kmalloc_caches[KMALLOC_SHIFT_HIGH + 1] __cacheline_aligned; ++EXPORT_SYMBOL(ub_kmalloc_caches); ++#endif + + #ifdef CONFIG_ZONE_DMA + static struct kmem_cache *kmalloc_caches_dma[PAGE_SHIFT]; +@@ -2379,6 +2557,11 @@ + { + unsigned int flags = 0; + ++ if (gfp_flags & __GFP_UBC) { ++ flags = SLAB_UBC | SLAB_NO_CHARGE; ++ gfp_flags &= ~__GFP_UBC; ++ } ++ + if (gfp_flags & SLUB_DMA) + flags = SLAB_CACHE_DMA; + +@@ -2506,11 +2689,14 @@ + index = fls(size - 1); + + #ifdef CONFIG_ZONE_DMA +- if (unlikely((flags & SLUB_DMA))) ++ if (unlikely((flags & SLUB_DMA))) { ++ BUG_ON(flags & __GFP_UBC); + return dma_kmalloc_cache(index, flags); ++ } + + #endif +- return &kmalloc_caches[index]; ++ ++ return __kmalloc_cache(flags, index); + } + + void *__kmalloc(size_t size, gfp_t flags) +@@ -2815,6 +3001,11 @@ + create_kmalloc_cache(&kmalloc_caches[0], "kmem_cache_node", + sizeof(struct kmem_cache_node), GFP_KERNEL); + kmalloc_caches[0].refcount = -1; ++#ifdef CONFIG_BEANCOUNTERS ++ create_kmalloc_cache(&ub_kmalloc_caches[0], "kmem_cache_node_ubc", ++ sizeof(struct kmem_cache_node), GFP_KERNEL_UBC); ++ ub_kmalloc_caches[0].refcount = -1; ++#endif + caches++; + + hotplug_memory_notifier(slab_memory_callback, 1); +@@ -2827,17 +3018,29 @@ + if (KMALLOC_MIN_SIZE <= 64) { + create_kmalloc_cache(&kmalloc_caches[1], + "kmalloc-96", 96, GFP_KERNEL); ++#ifdef CONFIG_BEANCOUNTERS ++ create_kmalloc_cache(&ub_kmalloc_caches[1], ++ "kmalloc-96-ubc", 96, GFP_KERNEL_UBC); ++#endif + caches++; + } + if (KMALLOC_MIN_SIZE <= 128) { + create_kmalloc_cache(&kmalloc_caches[2], + "kmalloc-192", 192, GFP_KERNEL); ++#ifdef CONFIG_BEANCOUNTERS ++ create_kmalloc_cache(&ub_kmalloc_caches[2], ++ "kmalloc-192-ubc", 192, GFP_KERNEL_UBC); ++#endif + caches++; + } + + for (i = KMALLOC_SHIFT_LOW; i < PAGE_SHIFT; i++) { + create_kmalloc_cache(&kmalloc_caches[i], + "kmalloc", 1 << i, GFP_KERNEL); ++#ifdef CONFIG_BEANCOUNTERS ++ create_kmalloc_cache(&ub_kmalloc_caches[i], ++ "kmalloc-ubc", 1 << i, GFP_KERNEL_UBC); ++#endif + caches++; + } + +@@ -2862,9 +3065,14 @@ + slab_state = UP; + + /* Provide the correct kmalloc names now that the caches are up */ +- for (i = KMALLOC_SHIFT_LOW; i < PAGE_SHIFT; i++) ++ for (i = KMALLOC_SHIFT_LOW; i < PAGE_SHIFT; i++) { + kmalloc_caches[i]. name = + kasprintf(GFP_KERNEL, "kmalloc-%d", 1 << i); ++#ifdef CONFIG_BEANCOUNTERS ++ ub_kmalloc_caches[i].name = ++ kasprintf(GFP_KERNEL, "kmalloc-%d-ubc", 1 << i); ++#endif ++ } + + #ifdef CONFIG_SMP + register_cpu_notifier(&slab_notifier); +@@ -3992,6 +4200,8 @@ + *p++ = 'a'; + if (s->flags & SLAB_DEBUG_FREE) + *p++ = 'F'; ++ if (s->flags & SLAB_UBC) ++ *p++ = 'b'; + if (p != name + 1) + *p++ = '-'; + p += sprintf(p, "%07d", s->size); +Index: kernel/mm/swap.c +=================================================================== +--- kernel.orig/mm/swap.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/swap.c 2008-11-24 15:47:46.000000000 +0100 +@@ -221,6 +221,7 @@ + __pagevec_lru_add_active(pvec); + put_cpu_var(lru_add_active_pvecs); + } ++EXPORT_SYMBOL(lru_cache_add_active); + + /* + * Drain pages out of the cpu's pagevecs. +@@ -256,6 +257,8 @@ + put_cpu(); + } + ++EXPORT_SYMBOL(lru_add_drain); ++ + #ifdef CONFIG_NUMA + static void lru_add_drain_per_cpu(struct work_struct *dummy) + { +Index: kernel/mm/swap_state.c +=================================================================== +--- kernel.orig/mm/swap_state.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/swap_state.c 2008-11-24 15:47:46.000000000 +0100 +@@ -19,6 +19,9 @@ + + #include + ++#include ++#include ++ + /* + * swapper_space is a fiction, retained to simplify the path through + * vmscan's shrink_page_list, to make sync_page look nicer, and to allow +@@ -43,6 +46,7 @@ + .i_mmap_nonlinear = LIST_HEAD_INIT(swapper_space.i_mmap_nonlinear), + .backing_dev_info = &swap_backing_dev_info, + }; ++EXPORT_SYMBOL(swapper_space); + + #define INC_CACHE_INFO(x) do { swap_cache_info.x++; } while (0) + +@@ -53,14 +57,18 @@ + unsigned long find_total; + unsigned long noent_race; + unsigned long exist_race; ++ unsigned long remove_race; + } swap_cache_info; ++EXPORT_SYMBOL(swap_cache_info); + + void show_swap_cache_info(void) + { +- printk("Swap cache: add %lu, delete %lu, find %lu/%lu, race %lu+%lu\n", ++ printk("Swap cache: add %lu, delete %lu, find %lu/%lu, " ++ "race %lu+%lu+%lu\n", + swap_cache_info.add_total, swap_cache_info.del_total, + swap_cache_info.find_success, swap_cache_info.find_total, +- swap_cache_info.noent_race, swap_cache_info.exist_race); ++ swap_cache_info.noent_race, swap_cache_info.exist_race, ++ swap_cache_info.remove_race); + printk("Free swap = %lukB\n", nr_swap_pages << (PAGE_SHIFT - 10)); + printk("Total swap = %lukB\n", total_swap_pages << (PAGE_SHIFT - 10)); + } +@@ -69,8 +77,7 @@ + * __add_to_swap_cache resembles add_to_page_cache on swapper_space, + * but sets SwapCache flag and private instead of mapping and index. + */ +-static int __add_to_swap_cache(struct page *page, swp_entry_t entry, +- gfp_t gfp_mask) ++int __add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask) + { + int error; + +@@ -95,7 +102,9 @@ + return error; + } + +-static int add_to_swap_cache(struct page *page, swp_entry_t entry) ++EXPORT_SYMBOL(__add_to_swap_cache); ++ ++int add_to_swap_cache(struct page *page, swp_entry_t entry) + { + int error; + +@@ -120,6 +129,8 @@ + return 0; + } + ++EXPORT_SYMBOL(add_to_swap_cache); ++ + /* + * This must be called only on pages that have + * been verified to be in the swap cache. +@@ -154,7 +165,14 @@ + BUG_ON(!PageLocked(page)); + + for (;;) { +- entry = get_swap_page(); ++ struct user_beancounter *ub; ++ ++ ub = pb_grab_page_ub(page); ++ if (IS_ERR(ub)) ++ return 0; ++ ++ entry = get_swap_page(ub); ++ put_beancounter(ub); + if (!entry.val) + return 0; + +@@ -240,6 +258,7 @@ + delete_from_swap_cache(page); + /* shift page from clean_pages to dirty_pages list */ + ClearPageDirty(page); ++ ub_io_release_debug(page); + set_page_dirty(page); + } + return err; +@@ -255,10 +274,13 @@ + */ + static inline void free_swap_cache(struct page *page) + { +- if (PageSwapCache(page) && !TestSetPageLocked(page)) { ++ if (!PageSwapCache(page)) ++ return; ++ if (!TestSetPageLocked(page)) { + remove_exclusive_swap_page(page); + unlock_page(page); +- } ++ } else ++ INC_CACHE_INFO(remove_race); + } + + /* +@@ -368,3 +390,5 @@ + page_cache_release(new_page); + return found_page; + } ++ ++EXPORT_SYMBOL(read_swap_cache_async); +Index: kernel/mm/swapfile.c +=================================================================== +--- kernel.orig/mm/swapfile.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/swapfile.c 2008-11-24 15:47:46.000000000 +0100 +@@ -32,6 +32,8 @@ + #include + #include + ++#include ++ + DEFINE_SPINLOCK(swap_lock); + unsigned int nr_swapfiles; + long total_swap_pages; +@@ -43,8 +45,12 @@ + static const char Unused_offset[] = "Unused swap offset entry "; + + struct swap_list_t swap_list = {-1, -1}; ++struct swap_info_struct swap_info[MAX_SWAPFILES]; + +-static struct swap_info_struct swap_info[MAX_SWAPFILES]; ++EXPORT_SYMBOL(total_swap_pages); ++EXPORT_SYMBOL(swap_lock); ++EXPORT_SYMBOL(swap_list); ++EXPORT_SYMBOL(swap_info); + + static DEFINE_MUTEX(swapon_mutex); + +@@ -171,7 +177,7 @@ + return 0; + } + +-swp_entry_t get_swap_page(void) ++swp_entry_t get_swap_page(struct user_beancounter *ub) + { + struct swap_info_struct *si; + pgoff_t offset; +@@ -192,6 +198,8 @@ + wrapped++; + } + ++ if (si->flags & SWP_READONLY) ++ continue; + if (!si->highest_bit) + continue; + if (!(si->flags & SWP_WRITEOK)) +@@ -201,6 +209,7 @@ + offset = scan_swap_map(si); + if (offset) { + spin_unlock(&swap_lock); ++ ub_swapentry_inc(si, offset, ub); + return swp_entry(type, offset); + } + next = swap_list.next; +@@ -212,6 +221,8 @@ + return (swp_entry_t) {0}; + } + ++EXPORT_SYMBOL(get_swap_page); ++ + swp_entry_t get_swap_page_of_type(int type) + { + struct swap_info_struct *si; +@@ -219,7 +230,7 @@ + + spin_lock(&swap_lock); + si = swap_info + type; +- if (si->flags & SWP_WRITEOK) { ++ if (si->flags & SWP_WRITEOK && !(si->flags & SWP_READONLY)) { + nr_swap_pages--; + offset = scan_swap_map(si); + if (offset) { +@@ -276,6 +287,7 @@ + count--; + p->swap_map[offset] = count; + if (!count) { ++ ub_swapentry_dec(p, offset); + if (offset < p->lowest_bit) + p->lowest_bit = offset; + if (offset > p->highest_bit) +@@ -304,6 +316,8 @@ + } + } + ++EXPORT_SYMBOL(swap_free); ++ + /* + * How many references to page are currently swapped out? + */ +@@ -385,6 +399,55 @@ + return retval; + } + ++int try_to_remove_exclusive_swap_page(struct page *page) ++{ ++ int retval; ++ struct swap_info_struct * p; ++ swp_entry_t entry; ++ ++ BUG_ON(PagePrivate(page)); ++ BUG_ON(!PageLocked(page)); ++ ++ if (!PageSwapCache(page)) ++ return 0; ++ if (PageWriteback(page)) ++ return 0; ++ if (page_count(page) != 2) /* 2: us + cache */ ++ return 0; ++ ++ entry.val = page->private; ++ p = swap_info_get(entry); ++ if (!p) ++ return 0; ++ ++ if (!vm_swap_full() && ++ (p->flags & (SWP_ACTIVE|SWP_READONLY)) == SWP_ACTIVE) { ++ spin_unlock(&swap_lock); ++ return 0; ++ } ++ ++ /* Is the only swap cache user the cache itself? */ ++ retval = 0; ++ if (p->swap_map[swp_offset(entry)] == 1) { ++ /* Recheck the page count with the swapcache lock held.. */ ++ write_lock_irq(&swapper_space.tree_lock); ++ if ((page_count(page) == 2) && !PageWriteback(page)) { ++ __delete_from_swap_cache(page); ++ SetPageDirty(page); ++ retval = 1; ++ } ++ write_unlock_irq(&swapper_space.tree_lock); ++ } ++ spin_unlock(&swap_lock); ++ ++ if (retval) { ++ swap_free(entry); ++ page_cache_release(page); ++ } ++ ++ return retval; ++} ++ + /* + * Free the swap entry like above, but also try to + * free the page cache entry if it is the last user. +@@ -424,6 +487,7 @@ + page_cache_release(page); + } + } ++EXPORT_SYMBOL(free_swap_and_cache); + + #ifdef CONFIG_HIBERNATION + /* +@@ -507,11 +571,17 @@ + * force COW, vm_page_prot omits write permission from any private vma. + */ + static void unuse_pte(struct vm_area_struct *vma, pte_t *pte, +- unsigned long addr, swp_entry_t entry, struct page *page) ++ unsigned long addr, swp_entry_t entry, struct page *page, ++ struct page_beancounter **pb) + { +- inc_mm_counter(vma->vm_mm, anon_rss); ++ struct mm_struct *mm; ++ ++ mm = vma->vm_mm; ++ inc_mm_counter(mm, anon_rss); ++ ub_unused_privvm_dec(mm, vma); ++ pb_add_ref(page, mm, pb); + get_page(page); +- set_pte_at(vma->vm_mm, addr, pte, ++ set_pte_at(mm, addr, pte, + pte_mkold(mk_pte(page, vma->vm_page_prot))); + page_add_anon_rmap(page, vma, addr); + swap_free(entry); +@@ -524,7 +594,8 @@ + + static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd, + unsigned long addr, unsigned long end, +- swp_entry_t entry, struct page *page) ++ swp_entry_t entry, struct page *page, ++ struct page_beancounter **pb) + { + pte_t swp_pte = swp_entry_to_pte(entry); + pte_t *pte; +@@ -538,7 +609,7 @@ + * Test inline before going to call unuse_pte. + */ + if (unlikely(pte_same(*pte, swp_pte))) { +- unuse_pte(vma, pte++, addr, entry, page); ++ unuse_pte(vma, pte++, addr, entry, page, pb); + found = 1; + break; + } +@@ -549,7 +620,8 @@ + + static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud, + unsigned long addr, unsigned long end, +- swp_entry_t entry, struct page *page) ++ swp_entry_t entry, struct page *page, ++ struct page_beancounter **pb) + { + pmd_t *pmd; + unsigned long next; +@@ -559,7 +631,7 @@ + next = pmd_addr_end(addr, end); + if (pmd_none_or_clear_bad(pmd)) + continue; +- if (unuse_pte_range(vma, pmd, addr, next, entry, page)) ++ if (unuse_pte_range(vma, pmd, addr, next, entry, page, pb)) + return 1; + } while (pmd++, addr = next, addr != end); + return 0; +@@ -567,7 +639,8 @@ + + static inline int unuse_pud_range(struct vm_area_struct *vma, pgd_t *pgd, + unsigned long addr, unsigned long end, +- swp_entry_t entry, struct page *page) ++ swp_entry_t entry, struct page *page, ++ struct page_beancounter **pb) + { + pud_t *pud; + unsigned long next; +@@ -577,14 +650,15 @@ + next = pud_addr_end(addr, end); + if (pud_none_or_clear_bad(pud)) + continue; +- if (unuse_pmd_range(vma, pud, addr, next, entry, page)) ++ if (unuse_pmd_range(vma, pud, addr, next, entry, page, pb)) + return 1; + } while (pud++, addr = next, addr != end); + return 0; + } + + static int unuse_vma(struct vm_area_struct *vma, +- swp_entry_t entry, struct page *page) ++ swp_entry_t entry, struct page *page, ++ struct page_beancounter **pb) + { + pgd_t *pgd; + unsigned long addr, end, next; +@@ -605,14 +679,15 @@ + next = pgd_addr_end(addr, end); + if (pgd_none_or_clear_bad(pgd)) + continue; +- if (unuse_pud_range(vma, pgd, addr, next, entry, page)) ++ if (unuse_pud_range(vma, pgd, addr, next, entry, page, pb)) + return 1; + } while (pgd++, addr = next, addr != end); + return 0; + } + + static int unuse_mm(struct mm_struct *mm, +- swp_entry_t entry, struct page *page) ++ swp_entry_t entry, struct page *page, ++ struct page_beancounter **pb) + { + struct vm_area_struct *vma; + +@@ -627,7 +702,7 @@ + lock_page(page); + } + for (vma = mm->mmap; vma; vma = vma->vm_next) { +- if (vma->anon_vma && unuse_vma(vma, entry, page)) ++ if (vma->anon_vma && unuse_vma(vma, entry, page, pb)) + break; + } + up_read(&mm->mmap_sem); +@@ -693,6 +768,7 @@ + int retval = 0; + int reset_overflow = 0; + int shmem; ++ struct page_beancounter *pb; + + /* + * When searching mms for an entry, a good strategy is to +@@ -744,6 +820,13 @@ + break; + } + ++ pb = NULL; ++ if (pb_alloc_all(&pb)) { ++ page_cache_release(page); ++ retval = -ENOMEM; ++ break; ++ } ++ + /* + * Don't hold on to start_mm if it looks like exiting. + */ +@@ -766,6 +849,20 @@ + lock_page(page); + wait_on_page_writeback(page); + ++ /* If read failed we cannot map not-uptodate page to ++ * user space. Actually, we are in serious troubles, ++ * we do not even know what process to kill. So, the only ++ * variant remains: to stop swapoff() and allow someone ++ * to kill processes to zap invalid pages. ++ */ ++ if (unlikely(!PageUptodate(page))) { ++ pb_free_list(&pb); ++ unlock_page(page); ++ page_cache_release(page); ++ retval = -EIO; ++ break; ++ } ++ + /* + * Remove all references to entry. + * Whenever we reach init_mm, there's no address space +@@ -777,7 +874,7 @@ + if (start_mm == &init_mm) + shmem = shmem_unuse(entry, page); + else +- retval = unuse_mm(start_mm, entry, page); ++ retval = unuse_mm(start_mm, entry, page, &pb); + } + if (*swap_map > 1) { + int set_start_mm = (*swap_map >= swcount); +@@ -807,7 +904,7 @@ + set_start_mm = 1; + shmem = shmem_unuse(entry, page); + } else +- retval = unuse_mm(mm, entry, page); ++ retval = unuse_mm(mm, entry, page, &pb); + if (set_start_mm && *swap_map < swcount) { + mmput(new_start_mm); + atomic_inc(&mm->mm_users); +@@ -821,6 +918,8 @@ + mmput(start_mm); + start_mm = new_start_mm; + } ++ ++ pb_free_list(&pb); + if (retval) { + unlock_page(page); + page_cache_release(page); +@@ -1183,6 +1282,10 @@ + int i, type, prev; + int err; + ++ /* VE admin check is just to be on the safe side, the admin may affect ++ * swaps only if he has access to special, i.e. if he has been granted ++ * access to the block device or if the swap file is in the area ++ * visible to him. */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + +@@ -1282,6 +1385,7 @@ + spin_unlock(&swap_lock); + mutex_unlock(&swapon_mutex); + vfree(swap_map); ++ ub_swap_fini(p); + inode = mapping->host; + if (S_ISBLK(inode->i_mode)) { + struct block_device *bdev = I_BDEV(inode); +@@ -1301,6 +1405,8 @@ + return err; + } + ++EXPORT_SYMBOL(sys_swapoff); ++ + #ifdef CONFIG_PROC_FS + /* iterator */ + static void *swap_start(struct seq_file *swap, loff_t *pos) +@@ -1635,9 +1741,16 @@ + goto bad_swap; + } + ++ if (ub_swap_init(p, maxpages)) { ++ error = -ENOMEM; ++ goto bad_swap; ++ } ++ + mutex_lock(&swapon_mutex); + spin_lock(&swap_lock); + p->flags = SWP_ACTIVE; ++ if (swap_flags & SWAP_FLAG_READONLY) ++ p->flags |= SWP_READONLY; + nr_swap_pages += nr_good_pages; + total_swap_pages += nr_good_pages; + +@@ -1697,6 +1810,8 @@ + return error; + } + ++EXPORT_SYMBOL(sys_swapon); ++ + void si_swapinfo(struct sysinfo *val) + { + unsigned int i; +@@ -1756,6 +1871,8 @@ + goto out; + } + ++EXPORT_SYMBOL(swap_duplicate); ++ + struct swap_info_struct * + get_swap_info_struct(unsigned type) + { +Index: kernel/mm/truncate.c +=================================================================== +--- kernel.orig/mm/truncate.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/truncate.c 2008-11-24 15:47:46.000000000 +0100 +@@ -77,6 +77,7 @@ + BDI_RECLAIMABLE); + if (account_size) + task_io_account_cancelled_write(account_size); ++ ub_io_release_context(page, account_size); + } + } + } +Index: kernel/mm/vmalloc.c +=================================================================== +--- kernel.orig/mm/vmalloc.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/vmalloc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -20,6 +20,9 @@ + #include + #include + ++#include ++#include ++ + + DEFINE_RWLOCK(vmlist_lock); + struct vm_struct *vmlist; +@@ -280,6 +283,70 @@ + return tmp; + } + ++struct vm_struct * get_vm_area_best(unsigned long size, unsigned long flags) ++{ ++ unsigned long addr, best_addr, delta, best_delta; ++ struct vm_struct **p, **best_p, *tmp, *area; ++ ++ area = kmalloc(sizeof(*area), GFP_KERNEL); ++ if (!area) ++ return NULL; ++ ++ size += PAGE_SIZE; /* one-page gap at the end */ ++ addr = VMALLOC_START; ++ best_addr = 0UL; ++ best_p = NULL; ++ best_delta = PAGE_ALIGN(VMALLOC_END) - VMALLOC_START; ++ ++ write_lock(&vmlist_lock); ++ for (p = &vmlist; (tmp = *p) && ++ (tmp->addr <= (void *)PAGE_ALIGN(VMALLOC_END)); ++ p = &tmp->next) { ++ if ((unsigned long)tmp->addr < addr) ++ continue; ++ if ((size + addr) < addr) ++ break; ++ delta = (unsigned long) tmp->addr - (size + addr); ++ if (delta < best_delta) { ++ best_delta = delta; ++ best_addr = addr; ++ best_p = p; ++ } ++ addr = tmp->size + (unsigned long)tmp->addr; ++ if (addr > VMALLOC_END-size) ++ break; ++ } ++ ++ if (!tmp || (tmp->addr > (void *)PAGE_ALIGN(VMALLOC_END))) { ++ /* check free area after list end */ ++ delta = (unsigned long) PAGE_ALIGN(VMALLOC_END) - (size + addr); ++ if (delta < best_delta) { ++ best_delta = delta; ++ best_addr = addr; ++ best_p = p; ++ } ++ } ++ if (best_addr) { ++ area->flags = flags; ++ /* allocate at the end of this area */ ++ area->addr = (void *)(best_addr + best_delta); ++ area->size = size; ++ area->next = *best_p; ++ area->pages = NULL; ++ area->nr_pages = 0; ++ area->phys_addr = 0; ++ *best_p = area; ++ /* check like in __vunmap */ ++ WARN_ON((PAGE_SIZE - 1) & (unsigned long)area->addr); ++ } else { ++ kfree(area); ++ area = NULL; ++ } ++ write_unlock(&vmlist_lock); ++ ++ return area; ++} ++ + /* Caller must hold vmlist_lock */ + static struct vm_struct *__remove_vm_area(void *addr) + { +@@ -319,7 +386,7 @@ + return v; + } + +-static void __vunmap(void *addr, int deallocate_pages) ++static void __vunmap(void *addr, int deallocate_pages, int uncharge) + { + struct vm_struct *area; + +@@ -345,6 +412,8 @@ + if (deallocate_pages) { + int i; + ++ if (uncharge) ++ dec_vmalloc_charged(area); + for (i = 0; i < area->nr_pages; i++) { + BUG_ON(!area->pages[i]); + __free_page(area->pages[i]); +@@ -373,7 +442,7 @@ + void vfree(void *addr) + { + BUG_ON(in_interrupt()); +- __vunmap(addr, 1); ++ __vunmap(addr, 1, 1); + } + EXPORT_SYMBOL(vfree); + +@@ -389,7 +458,7 @@ + void vunmap(void *addr) + { + BUG_ON(in_interrupt()); +- __vunmap(addr, 0); ++ __vunmap(addr, 0, 0); + } + EXPORT_SYMBOL(vunmap); + +@@ -464,10 +533,12 @@ + + if (map_vm_area(area, prot, &pages)) + goto fail; ++ ++ inc_vmalloc_charged(area, gfp_mask); + return area->addr; + + fail: +- vfree(area->addr); ++ __vunmap(area->addr, 1, 0); + return NULL; + } + +@@ -509,6 +580,21 @@ + } + EXPORT_SYMBOL(__vmalloc); + ++static void *____vmalloc(unsigned long size, gfp_t mask, pgprot_t prot) ++{ ++ struct vm_struct *area; ++ ++ size = PAGE_ALIGN(size); ++ if (!size || (size >> PAGE_SHIFT) > num_physpages) ++ return NULL; ++ ++ area = get_vm_area_best(size, VM_ALLOC); ++ if (!area) ++ return NULL; ++ ++ return __vmalloc_area_node(area, mask, prot, -1); ++} ++ + /** + * vmalloc - allocate virtually contiguous memory + * @size: allocation size +@@ -524,6 +610,26 @@ + } + EXPORT_SYMBOL(vmalloc); + ++void *ub_vmalloc(unsigned long size) ++{ ++ return __vmalloc(size, GFP_KERNEL_UBC | __GFP_HIGHMEM, PAGE_KERNEL); ++} ++EXPORT_SYMBOL(ub_vmalloc); ++ ++void *vmalloc_best(unsigned long size) ++{ ++ return ____vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); ++} ++ ++EXPORT_SYMBOL(vmalloc_best); ++ ++void *ub_vmalloc_best(unsigned long size) ++{ ++ return ____vmalloc(size, GFP_KERNEL_UBC | __GFP_HIGHMEM, PAGE_KERNEL); ++} ++ ++EXPORT_SYMBOL(ub_vmalloc_best); ++ + /** + * vmalloc_user - allocate zeroed virtually contiguous memory for userspace + * @size: allocation size +@@ -564,6 +670,12 @@ + } + EXPORT_SYMBOL(vmalloc_node); + ++void *ub_vmalloc_node(unsigned long size, int node) ++{ ++ return __vmalloc_node(size, GFP_KERNEL_UBC | __GFP_HIGHMEM, PAGE_KERNEL, node); ++} ++EXPORT_SYMBOL(ub_vmalloc_node); ++ + #ifndef PAGE_KERNEL_EXEC + # define PAGE_KERNEL_EXEC PAGE_KERNEL + #endif +@@ -823,3 +935,37 @@ + kfree(area); + } + EXPORT_SYMBOL_GPL(free_vm_area); ++ ++void vprintstat(void) ++{ ++ struct vm_struct *p, *last_p = NULL; ++ unsigned long addr, size, free_size, max_free_size; ++ int num; ++ ++ addr = VMALLOC_START; ++ size = max_free_size = 0; ++ num = 0; ++ ++ read_lock(&vmlist_lock); ++ for (p = vmlist; p; p = p->next) { ++ free_size = (unsigned long)p->addr - addr; ++ if (free_size > max_free_size) ++ max_free_size = free_size; ++ addr = (unsigned long)p->addr + p->size; ++ size += p->size; ++ ++num; ++ last_p = p; ++ } ++ if (last_p) { ++ free_size = VMALLOC_END - ++ ((unsigned long)last_p->addr + last_p->size); ++ if (free_size > max_free_size) ++ max_free_size = free_size; ++ } ++ read_unlock(&vmlist_lock); ++ ++ printk("VMALLOC Used: %luKB Total: %luKB Entries: %d\n" ++ " Max_Free: %luKB Start: %lx End: %lx\n", ++ size/1024, (VMALLOC_END - VMALLOC_START)/1024, num, ++ max_free_size/1024, VMALLOC_START, VMALLOC_END); ++} +Index: kernel/mm/vmscan.c +=================================================================== +--- kernel.orig/mm/vmscan.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/vmscan.c 2008-11-24 15:47:46.000000000 +0100 +@@ -38,10 +38,14 @@ + #include + #include + ++#include ++#include ++ + #include + #include + + #include ++#include + + #include "internal.h" + +@@ -161,6 +165,9 @@ + if (scanned == 0) + scanned = SWAP_CLUSTER_MAX; + ++ if (unlikely(test_tsk_thread_flag(current, TIF_MEMDIE))) ++ return 1; ++ + if (!down_read_trylock(&shrinker_rwsem)) + return 1; /* Assume we'll be able to shrink next time */ + +@@ -195,6 +202,9 @@ + int shrink_ret; + int nr_before; + ++ if (unlikely(test_tsk_thread_flag(current, TIF_MEMDIE))) ++ goto done; ++ + nr_before = (*shrinker->shrink)(0, gfp_mask); + shrink_ret = (*shrinker->shrink)(this_scan, gfp_mask); + if (shrink_ret == -1) +@@ -209,6 +219,7 @@ + + shrinker->nr += total_scan; + } ++done: + up_read(&shrinker_rwsem); + return ret; + } +@@ -322,6 +333,7 @@ + */ + if (PagePrivate(page)) { + if (try_to_free_buffers(page)) { ++ ub_io_release_context(page, 0); + ClearPageDirty(page); + printk("%s: orphaned page\n", __FUNCTION__); + return PAGE_CLEAN; +@@ -1016,6 +1028,7 @@ + reclaim_mapped = 1; + } + ++ {KSTAT_PERF_ENTER(refill_inact) + lru_add_drain(); + spin_lock_irq(&zone->lru_lock); + pgmoved = isolate_lru_pages(nr_pages, &zone->active_list, +@@ -1095,6 +1108,7 @@ + spin_unlock_irq(&zone->lru_lock); + + pagevec_release(&pvec); ++ KSTAT_PERF_LEAVE(refill_inact)} + } + + /* +@@ -1133,6 +1147,8 @@ + nr_to_scan = min(nr_active, + (unsigned long)sc->swap_cluster_max); + nr_active -= nr_to_scan; ++ if (unlikely(test_tsk_thread_flag(current, TIF_MEMDIE))) ++ goto done; + shrink_active_list(nr_to_scan, zone, sc, priority); + } + +@@ -1140,12 +1156,15 @@ + nr_to_scan = min(nr_inactive, + (unsigned long)sc->swap_cluster_max); + nr_inactive -= nr_to_scan; ++ if (unlikely(test_tsk_thread_flag(current, TIF_MEMDIE))) ++ goto done; + nr_reclaimed += shrink_inactive_list(nr_to_scan, zone, + sc); + } + } + + throttle_vm_writeout(sc->gfp_mask); ++done: + return nr_reclaimed; + } + +@@ -1189,6 +1208,9 @@ + sc->all_unreclaimable = 0; + + nr_reclaimed += shrink_zone(priority, zone, sc); ++ ++ if (unlikely(test_tsk_thread_flag(current, TIF_MEMDIE))) ++ break; + } + return nr_reclaimed; + } +@@ -1224,8 +1246,10 @@ + .order = order, + }; + ++ KSTAT_PERF_ENTER(ttfp); + count_vm_event(ALLOCSTALL); + ++ ub_oom_start(); + for (i = 0; zones[i] != NULL; i++) { + struct zone *zone = zones[i]; + +@@ -1265,6 +1289,11 @@ + sc.may_writepage = 1; + } + ++ if (unlikely(test_tsk_thread_flag(current, TIF_MEMDIE))) { ++ ret = 1; ++ goto out; ++ } ++ + /* Take a nap, wait for some writeback to complete */ + if (sc.nr_scanned && priority < DEF_PRIORITY - 2) + congestion_wait(WRITE, HZ/10); +@@ -1290,6 +1319,7 @@ + + zone->prev_priority = priority; + } ++ KSTAT_PERF_LEAVE(ttfp); + return ret; + } + +Index: kernel/mm/vmstat.c +=================================================================== +--- kernel.orig/mm/vmstat.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/mm/vmstat.c 2008-11-24 15:47:46.000000000 +0100 +@@ -14,6 +14,40 @@ + #include + #include + #include ++#include ++ ++void __get_zone_counts(unsigned long *active, unsigned long *inactive, ++ unsigned long *free, struct pglist_data *pgdat) ++{ ++ struct zone *zones = pgdat->node_zones; ++ int i; ++ ++ *active = 0; ++ *inactive = 0; ++ *free = 0; ++ for (i = 0; i < MAX_NR_ZONES; i++) { ++ *active += zone_page_state(&zones[i], NR_ACTIVE); ++ *inactive += zone_page_state(&zones[i], NR_INACTIVE); ++ *free += zone_page_state(&zones[i], NR_FREE_PAGES); ++ } ++} ++ ++void get_zone_counts(unsigned long *active, ++ unsigned long *inactive, unsigned long *free) ++{ ++ struct pglist_data *pgdat; ++ ++ *active = 0; ++ *inactive = 0; ++ *free = 0; ++ for_each_online_pgdat(pgdat) { ++ unsigned long l, m, n; ++ __get_zone_counts(&l, &m, &n, pgdat); ++ *active += l; ++ *inactive += m; ++ *free += n; ++ } ++} + + #ifdef CONFIG_VM_EVENT_COUNTERS + DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}}; +@@ -41,6 +75,20 @@ + } + } + ++unsigned long vm_events(enum vm_event_item i) ++{ ++ int cpu; ++ unsigned long sum; ++ struct vm_event_state *st; ++ ++ sum = 0; ++ for_each_online_cpu(cpu) { ++ st = &per_cpu(vm_event_states, cpu); ++ sum += st->event[i]; ++ } ++ ++ return (sum < 0 ? 0 : sum); ++} + /* + * Accumulate the vm event counters across all CPUs. + * The result is unavoidably approximate - it can change +@@ -733,30 +781,40 @@ + unsigned long *v; + #ifdef CONFIG_VM_EVENT_COUNTERS + unsigned long *e; ++#define VMSTAT_BUFSIZE (NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long) + \ ++ sizeof(struct vm_event_state)) ++#else ++#define VMSTAT_BUFSIZE (NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long)) + #endif + int i; + + if (*pos >= ARRAY_SIZE(vmstat_text)) + return NULL; + +-#ifdef CONFIG_VM_EVENT_COUNTERS +- v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long) +- + sizeof(struct vm_event_state), GFP_KERNEL); +-#else +- v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long), +- GFP_KERNEL); +-#endif ++ v = kmalloc(VMSTAT_BUFSIZE, GFP_KERNEL); + m->private = v; + if (!v) + return ERR_PTR(-ENOMEM); +- for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) +- v[i] = global_page_state(i); ++ ++ if (ve_is_super(get_exec_env())) { ++ for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) ++ v[i] = global_page_state(i); + #ifdef CONFIG_VM_EVENT_COUNTERS +- e = v + NR_VM_ZONE_STAT_ITEMS; +- all_vm_events(e); +- e[PGPGIN] /= 2; /* sectors -> kbytes */ +- e[PGPGOUT] /= 2; +-#endif ++ e = v + NR_VM_ZONE_STAT_ITEMS; ++ all_vm_events(e); ++ e[PGPGIN] /= 2; /* sectors -> kbytes */ ++ e[PGPGOUT] /= 2; ++#endif ++ } else ++ memset(v, 0, VMSTAT_BUFSIZE); ++ ++ if (virtinfo_notifier_call(VITYPE_GENERAL, ++ VIRTINFO_VMSTAT, v) & NOTIFY_FAIL) { ++ kfree(v); ++ m->private = NULL; ++ return ERR_PTR(-ENOMSG); ++ } ++ + return v + *pos; + } + +Index: kernel/net/8021q/vlan.c +=================================================================== +--- kernel.orig/net/8021q/vlan.c 2008-11-24 14:17:57.000000000 +0100 ++++ kernel/net/8021q/vlan.c 2008-11-24 15:47:46.000000000 +0100 +@@ -33,6 +33,9 @@ + #include + #include + ++#include ++#include ++ + #include + #include "vlan.h" + #include "vlanproc.h" +@@ -68,6 +71,44 @@ + .func = vlan_skb_recv, /* VLAN receive method */ + }; + ++#ifdef CONFIG_VE ++static int vlan_start(void *data) ++{ ++ int err; ++ ++ err = vlan_proc_init(); ++ if (err < 0) ++ goto out_proc; ++ ++ __module_get(THIS_MODULE); ++ return 0; ++ ++out_proc: ++ return err; ++} ++ ++static void vlan_stop(void *data) ++{ ++ struct ve_struct *ve; ++ ++ ve = (struct ve_struct *)data; ++ if (ve->_proc_vlan_dir == NULL) ++ return; ++ ++ vlan_proc_cleanup(); ++ ve->_proc_vlan_conf = NULL; ++ ve->_proc_vlan_dir = NULL; ++ module_put(THIS_MODULE); ++} ++ ++static struct ve_hook vlan_ve_hook = { ++ .init = vlan_start, ++ .fini = vlan_stop, ++ .owner = THIS_MODULE, ++ .priority = HOOK_PRIO_NET_POST, ++}; ++#endif ++ + /* End of global variables definitions. */ + + /* +@@ -106,6 +147,7 @@ + goto err2; + + vlan_ioctl_set(vlan_ioctl_handler); ++ ve_hook_register(VE_SS_CHAIN, &vlan_ve_hook); + return 0; + + err2: +@@ -124,6 +166,7 @@ + { + int i; + ++ ve_hook_unregister(&vlan_ve_hook); + vlan_ioctl_set(NULL); + vlan_netlink_fini(); + +@@ -147,14 +190,16 @@ + module_exit(vlan_cleanup_module); + + /* Must be invoked with RCU read lock (no preempt) */ +-static struct vlan_group *__vlan_find_group(int real_dev_ifindex) ++static struct vlan_group *__vlan_find_group(int real_dev_ifindex, ++ struct ve_struct *ve) + { + struct vlan_group *grp; + struct hlist_node *n; + int hash = vlan_grp_hashfn(real_dev_ifindex); + + hlist_for_each_entry_rcu(grp, n, &vlan_group_hash[hash], hlist) { +- if (grp->real_dev_ifindex == real_dev_ifindex) ++ if (grp->real_dev_ifindex == real_dev_ifindex && ++ ve_accessible_strict(ve, grp->owner)) + return grp; + } + +@@ -168,7 +213,8 @@ + struct net_device *__find_vlan_dev(struct net_device *real_dev, + unsigned short VID) + { +- struct vlan_group *grp = __vlan_find_group(real_dev->ifindex); ++ struct vlan_group *grp = __vlan_find_group(real_dev->ifindex, ++ real_dev->owner_env); + + if (grp) + return vlan_group_get_device(grp, VID); +@@ -191,14 +237,14 @@ + unsigned int size; + unsigned int i; + +- grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL); ++ grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL_UBC); + if (!grp) + return NULL; + + size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN; + + for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) { +- grp->vlan_devices_arrays[i] = kzalloc(size, GFP_KERNEL); ++ grp->vlan_devices_arrays[i] = kzalloc(size, GFP_KERNEL_UBC); + if (!grp->vlan_devices_arrays[i]) + goto err; + } +@@ -242,7 +288,7 @@ + return -EINVAL; + + ASSERT_RTNL(); +- grp = __vlan_find_group(real_dev_ifindex); ++ grp = __vlan_find_group(real_dev_ifindex, real_dev->owner_env); + + ret = 0; + +@@ -282,6 +328,9 @@ + + hlist_del_rcu(&grp->hlist); + ++ put_ve(grp->owner); ++ grp->owner = NULL; ++ + /* Free the group, after all cpu's are done. */ + call_rcu(&grp->rcu, vlan_rcu_free); + +@@ -388,6 +437,8 @@ + new_dev->do_ioctl = vlan_dev_ioctl; + + memset(new_dev->broadcast, 0, ETH_ALEN); ++ if (!ve_is_super(get_exec_env())) ++ new_dev->features |= NETIF_F_VIRTUAL; + } + + static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev) +@@ -455,7 +506,7 @@ + struct vlan_group *grp, *ngrp = NULL; + int err; + +- grp = __vlan_find_group(real_dev->ifindex); ++ grp = __vlan_find_group(real_dev->ifindex, real_dev->owner_env); + if (!grp) { + ngrp = grp = vlan_group_alloc(real_dev->ifindex); + if (!grp) +@@ -609,13 +660,12 @@ + static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr) + { + struct net_device *dev = ptr; +- struct vlan_group *grp = __vlan_find_group(dev->ifindex); ++ struct vlan_group *grp; + int i, flgs; + struct net_device *vlandev; ++ struct ve_struct *env; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- ++ grp = __vlan_find_group(dev->ifindex, dev->owner_env); + if (!grp) + goto out; + +@@ -692,7 +742,9 @@ + ret = unregister_vlan_dev(dev, + VLAN_DEV_INFO(vlandev)->vlan_id); + ++ env = set_exec_env(vlandev->owner_env); + unregister_netdevice(vlandev); ++ set_exec_env(env); + + /* Group was destroyed? */ + if (ret == 1) +@@ -705,6 +757,17 @@ + return NOTIFY_DONE; + } + ++static inline int vlan_check_caps(void) ++{ ++ if (capable(CAP_NET_ADMIN)) ++ return 1; ++#ifdef CONFIG_VE ++ if (capable(CAP_VE_NET_ADMIN)) ++ return 1; ++#endif ++ return 0; ++} ++ + /* + * VLAN IOCTL handler. + * o execute requested action or pass command to the device driver +@@ -752,7 +815,7 @@ + switch (args.cmd) { + case SET_VLAN_INGRESS_PRIORITY_CMD: + err = -EPERM; +- if (!capable(CAP_NET_ADMIN)) ++ if (!vlan_check_caps()) + break; + vlan_dev_set_ingress_priority(dev, + args.u.skb_priority, +@@ -762,7 +825,7 @@ + + case SET_VLAN_EGRESS_PRIORITY_CMD: + err = -EPERM; +- if (!capable(CAP_NET_ADMIN)) ++ if (!vlan_check_caps()) + break; + err = vlan_dev_set_egress_priority(dev, + args.u.skb_priority, +@@ -771,7 +834,7 @@ + + case SET_VLAN_FLAG_CMD: + err = -EPERM; +- if (!capable(CAP_NET_ADMIN)) ++ if (!vlan_check_caps()) + break; + err = vlan_dev_set_vlan_flag(dev, + args.u.flag, +@@ -780,7 +843,7 @@ + + case SET_VLAN_NAME_TYPE_CMD: + err = -EPERM; +- if (!capable(CAP_NET_ADMIN)) ++ if (!vlan_check_caps()) + break; + if ((args.u.name_type >= 0) && + (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) { +@@ -793,14 +856,14 @@ + + case ADD_VLAN_CMD: + err = -EPERM; +- if (!capable(CAP_NET_ADMIN)) ++ if (!vlan_check_caps()) + break; + err = register_vlan_device(dev, args.u.VID); + break; + + case DEL_VLAN_CMD: + err = -EPERM; +- if (!capable(CAP_NET_ADMIN)) ++ if (!vlan_check_caps()) + break; + err = unregister_vlan_device(dev); + break; +Index: kernel/net/8021q/vlan_dev.c +=================================================================== +--- kernel.orig/net/8021q/vlan_dev.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/8021q/vlan_dev.c 2008-11-24 15:47:46.000000000 +0100 +@@ -453,6 +453,7 @@ + + int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) + { ++ struct ve_struct *env; + struct net_device_stats *stats = vlan_dev_get_stats(dev); + struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); + +@@ -507,13 +508,17 @@ + stats->tx_bytes += skb->len; + + skb->dev = VLAN_DEV_INFO(dev)->real_dev; ++ skb->owner_env = skb->dev->owner_env; ++ env = set_exec_env(skb->owner_env); + dev_queue_xmit(skb); ++ set_exec_env(env); + + return 0; + } + + int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) + { ++ struct ve_struct *env; + struct net_device_stats *stats = vlan_dev_get_stats(dev); + unsigned short veth_TCI; + +@@ -531,7 +536,10 @@ + stats->tx_bytes += skb->len; + + skb->dev = VLAN_DEV_INFO(dev)->real_dev; ++ skb->owner_env = skb->dev->owner_env; ++ env = set_exec_env(skb->owner_env); + dev_queue_xmit(skb); ++ set_exec_env(env); + + return 0; + } +Index: kernel/net/8021q/vlanproc.c +=================================================================== +--- kernel.orig/net/8021q/vlanproc.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/8021q/vlanproc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -115,13 +115,21 @@ + * /proc/net/vlan + */ + ++#ifdef CONFIG_VE ++#define proc_vlan_dir (get_exec_env()->_proc_vlan_dir) ++#else + static struct proc_dir_entry *proc_vlan_dir; ++#endif + + /* + * /proc/net/vlan/config + */ + ++#ifdef CONFIG_VE ++#define proc_vlan_conf (get_exec_env()->_proc_vlan_conf) ++#else + static struct proc_dir_entry *proc_vlan_conf; ++#endif + + /* Strings */ + static const char *vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = { +@@ -155,7 +163,7 @@ + * Create /proc/net/vlan entries + */ + +-int __init vlan_proc_init(void) ++int vlan_proc_init(void) + { + proc_vlan_dir = proc_mkdir(name_root, init_net.proc_net); + if (proc_vlan_dir) { +Index: kernel/net/9p/trans_fd.c +=================================================================== +--- kernel.orig/net/9p/trans_fd.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/9p/trans_fd.c 2008-11-24 15:47:46.000000000 +0100 +@@ -459,14 +459,7 @@ + + return 1; + } +- +-static void __exit p9_trans_fd_exit(void) { +- printk(KERN_ERR "Removal of 9p transports not implemented\n"); +- BUG(); +-} +- + module_init(p9_trans_fd_init); +-module_exit(p9_trans_fd_exit); + + MODULE_AUTHOR("Latchesar Ionkov "); + MODULE_AUTHOR("Eric Van Hensbergen "); +Index: kernel/net/Kconfig +=================================================================== +--- kernel.orig/net/Kconfig 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/Kconfig 2008-11-24 15:47:46.000000000 +0100 +@@ -30,7 +30,7 @@ + config NET_NS + bool "Network namespace support" + default n +- depends on EXPERIMENTAL && !SYSFS ++ depends on EXPERIMENTAL + help + Allow user space to create what appear to be multiple instances + of the network stack. +Index: kernel/net/bridge/br.c +=================================================================== +--- kernel.orig/net/bridge/br.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/bridge/br.c 2008-11-24 15:47:46.000000000 +0100 +@@ -55,6 +55,7 @@ + + brioctl_set(br_ioctl_deviceless_stub); + br_handle_frame_hook = br_handle_frame; ++ br_hard_xmit_hook = br_xmit; + + br_fdb_get_hook = br_fdb_get; + br_fdb_put_hook = br_fdb_put; +@@ -89,6 +90,7 @@ + br_fdb_put_hook = NULL; + + br_handle_frame_hook = NULL; ++ br_hard_xmit_hook = NULL; + br_fdb_fini(); + } + +Index: kernel/net/bridge/br_device.c +=================================================================== +--- kernel.orig/net/bridge/br_device.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/bridge/br_device.c 2008-11-24 15:47:46.000000000 +0100 +@@ -40,16 +40,47 @@ + skb_reset_mac_header(skb); + skb_pull(skb, ETH_HLEN); + ++ skb->brmark = BR_ALREADY_SEEN; ++ + if (dest[0] & 1) + br_flood_deliver(br, skb); + else if ((dst = __br_fdb_get(br, dest)) != NULL) +- br_deliver(dst->dst, skb); ++ br_deliver(dst->dst, skb, 1); + else + br_flood_deliver(br, skb); + + return 0; + } + ++int br_xmit(struct sk_buff *skb, struct net_bridge_port *port) ++{ ++ struct net_bridge *br = port->br; ++ const unsigned char *dest = skb->data; ++ struct net_bridge_fdb_entry *dst; ++ ++ if (!br->via_phys_dev) ++ return 0; ++ ++ br->statistics.tx_packets++; ++ br->statistics.tx_bytes += skb->len; ++ ++ skb_reset_mac_header(skb); ++ skb_pull(skb, ETH_HLEN); ++ ++ skb->brmark = BR_ALREADY_SEEN; ++ ++ if (dest[0] & 1) ++ br_xmit_deliver(br, port, skb); ++ else if ((dst = __br_fdb_get(br, dest)) != NULL) ++ br_deliver(dst->dst, skb, 0); ++ else ++ br_xmit_deliver(br, port, skb); ++ ++ skb_push(skb, ETH_HLEN); ++ ++ return 0; ++} ++ + static int br_dev_open(struct net_device *dev) + { + struct net_bridge *br = netdev_priv(dev); +Index: kernel/net/bridge/br_forward.c +=================================================================== +--- kernel.orig/net/bridge/br_forward.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/bridge/br_forward.c 2008-11-24 15:47:46.000000000 +0100 +@@ -78,14 +78,24 @@ + } + + /* called with rcu_read_lock */ +-void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) ++void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb, int free) + { + if (should_deliver(to, skb)) { ++ if (!free) { ++ struct sk_buff *skb2; ++ ++ if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { ++ to->br->statistics.tx_dropped++; ++ return; ++ } ++ skb = skb2; ++ } + __br_deliver(to, skb); + return; + } + +- kfree_skb(skb); ++ if (free) ++ kfree_skb(skb); + } + + /* called with rcu_read_lock */ +@@ -101,6 +111,7 @@ + + /* called under bridge lock */ + static void br_flood(struct net_bridge *br, struct sk_buff *skb, ++ int free, + void (*__packet_hook)(const struct net_bridge_port *p, + struct sk_buff *skb)) + { +@@ -132,18 +143,41 @@ + return; + } + +- kfree_skb(skb); ++ if (free) ++ kfree_skb(skb); + } + + + /* called with rcu_read_lock */ + void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb) + { +- br_flood(br, skb, __br_deliver); ++ br_flood(br, skb, 1, __br_deliver); ++} ++ ++/* called with rcu_read_lock */ ++void br_xmit_deliver(struct net_bridge *br, struct net_bridge_port *port, ++ struct sk_buff *skb) ++{ ++ struct net_bridge_port *p; ++ ++ list_for_each_entry_rcu(p, &br->port_list, list) { ++ if (p == port) ++ continue; ++ if (should_deliver(p, skb)) { ++ struct sk_buff *skb2; ++ ++ if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { ++ br->statistics.tx_dropped++; ++ return; ++ } ++ __br_deliver(p, skb2); ++ } ++ } + } + + /* called under bridge lock */ + void br_flood_forward(struct net_bridge *br, struct sk_buff *skb) + { +- br_flood(br, skb, __br_forward); ++ skb->brmark = BR_ALREADY_SEEN; ++ br_flood(br, skb, 1, __br_forward); + } +Index: kernel/net/bridge/br_if.c +=================================================================== +--- kernel.orig/net/bridge/br_if.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/bridge/br_if.c 2008-11-24 15:47:46.000000000 +0100 +@@ -14,6 +14,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -160,6 +161,11 @@ + { + struct net_bridge_port *p, *n; + ++ if (br->master_dev) { ++ dev_put(br->master_dev); ++ br->master_dev = NULL; ++ } ++ + list_for_each_entry_safe(p, n, &br->port_list, list) { + del_nbp(p); + } +@@ -303,7 +309,7 @@ + int ret = 0; + + rtnl_lock(); +- dev = __dev_get_by_name(&init_net, name); ++ dev = __dev_get_by_name(current->nsproxy->net_ns, name); + if (dev == NULL) + ret = -ENXIO; /* Could not find device */ + +@@ -403,6 +409,10 @@ + if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) && + (br->dev->flags & IFF_UP)) + br_stp_enable_port(p); ++ if (!(dev->features & NETIF_F_VIRTUAL)) { ++ dev_hold(dev); ++ br->master_dev = dev; ++ } + spin_unlock_bh(&br->lock); + + br_ifinfo_notify(RTM_NEWLINK, p); +@@ -434,6 +444,16 @@ + spin_lock_bh(&br->lock); + br_stp_recalculate_bridge_id(br); + br_features_recompute(br); ++ if (br->master_dev == dev) { ++ br->master_dev = NULL; ++ dev_put(dev); ++ list_for_each_entry(p, &br->port_list, list) ++ if (!(p->dev->features & NETIF_F_VIRTUAL)) { ++ dev_hold(p->dev); ++ br->master_dev = p->dev; ++ break; ++ } ++ } + spin_unlock_bh(&br->lock); + + return 0; +@@ -444,7 +464,7 @@ + struct net_device *dev, *nxt; + + rtnl_lock(); +- for_each_netdev_safe(&init_net, dev, nxt) ++ for_each_netdev_safe(current->nsproxy->net_ns, dev, nxt) + if (dev->priv_flags & IFF_EBRIDGE) + del_br(dev->priv); + rtnl_unlock(); +Index: kernel/net/bridge/br_input.c +=================================================================== +--- kernel.orig/net/bridge/br_input.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/bridge/br_input.c 2008-11-24 15:47:46.000000000 +0100 +@@ -24,13 +24,20 @@ + + static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) + { +- struct net_device *indev; ++ struct net_device *indev, *outdev; + + br->statistics.rx_packets++; + br->statistics.rx_bytes += skb->len; + + indev = skb->dev; +- skb->dev = br->dev; ++ if (!br->via_phys_dev) ++ skb->dev = br->dev; ++ else { ++ skb->brmark = BR_ALREADY_SEEN; ++ outdev = br->master_dev; ++ if (outdev) ++ skb->dev = outdev; ++ } + + NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, + netif_receive_skb); +@@ -58,7 +65,7 @@ + /* The packet skb2 goes to the local host (NULL to skip). */ + skb2 = NULL; + +- if (br->dev->flags & IFF_PROMISC) ++ if ((br->dev->flags & IFF_PROMISC) && !br->via_phys_dev) + skb2 = skb; + + dst = NULL; +@@ -156,6 +163,9 @@ + } + /* fall through */ + case BR_STATE_LEARNING: ++ if (skb->brmark == BR_ALREADY_SEEN) ++ return 0; ++ + if (!compare_ether_addr(p->br->dev->dev_addr, dest)) + skb->pkt_type = PACKET_HOST; + +Index: kernel/net/bridge/br_ioctl.c +=================================================================== +--- kernel.orig/net/bridge/br_ioctl.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/bridge/br_ioctl.c 2008-11-24 15:47:46.000000000 +0100 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -28,7 +29,7 @@ + struct net_device *dev; + int i = 0; + +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(current->nsproxy->net_ns, dev) { + if (i >= num) + break; + if (dev->priv_flags & IFF_EBRIDGE) +@@ -91,7 +92,7 @@ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + +- dev = dev_get_by_index(&init_net, ifindex); ++ dev = dev_get_by_index(current->nsproxy->net_ns, ifindex); + if (dev == NULL) + return -EINVAL; + +@@ -142,6 +143,7 @@ + b.root_port = br->root_port; + + b.stp_enabled = (br->stp_enabled != BR_NO_STP); ++ b.via_phys_dev = br->via_phys_dev; + b.ageing_time = jiffies_to_clock_t(br->ageing_time); + b.hello_timer_value = br_timer_value(&br->hello_timer); + b.tcn_timer_value = br_timer_value(&br->tcn_timer); +@@ -258,6 +260,13 @@ + br_stp_set_enabled(br, args[1]); + return 0; + ++ case BRCTL_SET_VIA_ORIG_DEV: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ br->via_phys_dev = args[1] ? 1 : 0; ++ return 0; ++ + case BRCTL_SET_BRIDGE_PRIORITY: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; +Index: kernel/net/bridge/br_netlink.c +=================================================================== +--- kernel.orig/net/bridge/br_netlink.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/bridge/br_netlink.c 2008-11-24 15:47:46.000000000 +0100 +@@ -11,6 +11,7 @@ + */ + + #include ++#include + #include + #include + #include "br_private.h" +@@ -111,7 +112,7 @@ + int idx; + + idx = 0; +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(current->nsproxy->net_ns, dev) { + /* not a bridge port */ + if (dev->br_port == NULL || idx < cb->args[0]) + goto skip; +@@ -156,7 +157,7 @@ + if (new_state > BR_STATE_BLOCKING) + return -EINVAL; + +- dev = __dev_get_by_index(&init_net, ifm->ifi_index); ++ dev = __dev_get_by_index(current->nsproxy->net_ns, ifm->ifi_index); + if (!dev) + return -ENODEV; + +Index: kernel/net/bridge/br_notify.c +=================================================================== +--- kernel.orig/net/bridge/br_notify.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/bridge/br_notify.c 2008-11-24 15:47:46.000000000 +0100 +@@ -37,9 +37,6 @@ + struct net_bridge_port *p = dev->br_port; + struct net_bridge *br; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + /* not a port of a bridge */ + if (p == NULL) + return NOTIFY_DONE; +Index: kernel/net/bridge/br_private.h +=================================================================== +--- kernel.orig/net/bridge/br_private.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/bridge/br_private.h 2008-11-24 15:47:46.000000000 +0100 +@@ -90,6 +90,8 @@ + spinlock_t lock; + struct list_head port_list; + struct net_device *dev; ++ struct net_device *master_dev; ++ unsigned char via_phys_dev; + struct net_device_stats statistics; + spinlock_t hash_lock; + struct hlist_head hash[BR_HASH_SIZE]; +@@ -139,6 +141,7 @@ + /* br_device.c */ + extern void br_dev_setup(struct net_device *dev); + extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev); ++extern int br_xmit(struct sk_buff *skb, struct net_bridge_port *port); + + /* br_fdb.c */ + extern int br_fdb_init(void); +@@ -165,12 +168,13 @@ + + /* br_forward.c */ + extern void br_deliver(const struct net_bridge_port *to, +- struct sk_buff *skb); ++ struct sk_buff *skb, int free); + extern int br_dev_queue_push_xmit(struct sk_buff *skb); + extern void br_forward(const struct net_bridge_port *to, + struct sk_buff *skb); + extern int br_forward_finish(struct sk_buff *skb); + extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb); ++extern void br_xmit_deliver(struct net_bridge *br, struct net_bridge_port *port, struct sk_buff *skb); + extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb); + + /* br_if.c */ +Index: kernel/net/bridge/br_stp_bpdu.c +=================================================================== +--- kernel.orig/net/bridge/br_stp_bpdu.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/bridge/br_stp_bpdu.c 2008-11-24 15:47:46.000000000 +0100 +@@ -142,9 +142,6 @@ + struct net_bridge *br; + const unsigned char *buf; + +- if (dev->nd_net != &init_net) +- goto err; +- + if (!p) + goto err; + +Index: kernel/net/bridge/br_sysfs_br.c +=================================================================== +--- kernel.orig/net/bridge/br_sysfs_br.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/bridge/br_sysfs_br.c 2008-11-24 15:47:46.000000000 +0100 +@@ -172,6 +172,27 @@ + static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, + store_stp_state); + ++static ssize_t show_via_phys_dev_state(struct device *cd, ++ struct device_attribute *attr, char *buf) ++{ ++ struct net_bridge *br = to_bridge(cd); ++ return sprintf(buf, "%d\n", br->via_phys_dev); ++} ++ ++static void set_via_phys_dev_state(struct net_bridge *br, unsigned long val) ++{ ++ br->via_phys_dev = val; ++} ++ ++static ssize_t store_via_phys_dev_state(struct device *cd, ++ struct device_attribute *attr, const char *buf, size_t len) ++{ ++ return store_bridge_parm(cd, buf, len, set_via_phys_dev_state); ++} ++ ++static DEVICE_ATTR(via_phys_dev, S_IRUGO | S_IWUSR, show_via_phys_dev_state, ++ store_via_phys_dev_state); ++ + static ssize_t show_priority(struct device *d, struct device_attribute *attr, + char *buf) + { +@@ -340,6 +361,7 @@ + &dev_attr_max_age.attr, + &dev_attr_ageing_time.attr, + &dev_attr_stp_state.attr, ++ &dev_attr_via_phys_dev.attr, + &dev_attr_priority.attr, + &dev_attr_bridge_id.attr, + &dev_attr_root_id.attr, +Index: kernel/net/bridge/netfilter/ebt_among.c +=================================================================== +--- kernel.orig/net/bridge/netfilter/ebt_among.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/bridge/netfilter/ebt_among.c 2008-11-24 15:47:46.000000000 +0100 +@@ -176,7 +176,7 @@ + unsigned int datalen) + { + struct ebt_among_info *info = (struct ebt_among_info *) data; +- int expected_length = sizeof(struct ebt_among_info); ++ int expected_length = EBT_ALIGN(sizeof(struct ebt_among_info)); + const struct ebt_mac_wormhash *wh_dst, *wh_src; + int err; + +@@ -185,7 +185,7 @@ + expected_length += ebt_mac_wormhash_size(wh_dst); + expected_length += ebt_mac_wormhash_size(wh_src); + +- if (datalen != EBT_ALIGN(expected_length)) { ++ if (datalen != expected_length) { + printk(KERN_WARNING + "ebtables: among: wrong size: %d " + "against expected %d, rounded to %Zd\n", +Index: kernel/net/core/datagram.c +=================================================================== +--- kernel.orig/net/core/datagram.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/core/datagram.c 2008-11-24 15:47:46.000000000 +0100 +@@ -56,6 +56,8 @@ + #include + #include + ++#include ++ + /* + * Is a socket 'connection oriented' ? + */ +@@ -502,6 +504,7 @@ + { + struct sock *sk = sock->sk; + unsigned int mask; ++ int no_ubc_space; + + poll_wait(file, sk->sk_sleep, wait); + mask = 0; +@@ -511,8 +514,14 @@ + mask |= POLLERR; + if (sk->sk_shutdown & RCV_SHUTDOWN) + mask |= POLLRDHUP; +- if (sk->sk_shutdown == SHUTDOWN_MASK) ++ if (sk->sk_shutdown == SHUTDOWN_MASK) { ++ no_ubc_space = 0; + mask |= POLLHUP; ++ } else { ++ no_ubc_space = ub_sock_makewres_other(sk, SOCK_MIN_UBCSPACE_CH); ++ if (no_ubc_space) ++ ub_sock_sndqueueadd_other(sk, SOCK_MIN_UBCSPACE_CH); ++ } + + /* readable? */ + if (!skb_queue_empty(&sk->sk_receive_queue) || +@@ -529,7 +538,7 @@ + } + + /* writable? */ +- if (sock_writeable(sk)) ++ if (!no_ubc_space && sock_writeable(sk)) + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + else + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); +Index: kernel/net/core/dev.c +=================================================================== +--- kernel.orig/net/core/dev.c 2008-11-24 14:17:56.000000000 +0100 ++++ kernel/net/core/dev.c 2008-11-24 15:47:46.000000000 +0100 +@@ -122,6 +122,9 @@ + + #include "net-sysfs.h" + ++#include ++#include ++ + /* + * The list of packet types we will receive (as opposed to discard) + * and the routines to invoke. +@@ -196,20 +199,6 @@ + + EXPORT_SYMBOL(dev_base_lock); + +-#define NETDEV_HASHBITS 8 +-#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS) +- +-static inline struct hlist_head *dev_name_hash(struct net *net, const char *name) +-{ +- unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ)); +- return &net->dev_name_head[hash & ((1 << NETDEV_HASHBITS) - 1)]; +-} +- +-static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) +-{ +- return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)]; +-} +- + /* Device list insertion */ + static int list_netdevice(struct net_device *dev) + { +@@ -672,7 +661,7 @@ + + ASSERT_RTNL(); + +- for_each_netdev(&init_net, dev) ++ for_each_netdev(net, dev) + if (dev->type == type && + !memcmp(dev->dev_addr, ha, dev->addr_len)) + return dev; +@@ -1210,6 +1199,8 @@ + return raw_notifier_call_chain(&netdev_chain, val, dev); + } + ++EXPORT_SYMBOL(call_netdevice_notifiers); ++ + /* When > 0 there are consumers of rx skb time stamps */ + static atomic_t netstamp_needed = ATOMIC_INIT(0); + +@@ -1530,6 +1521,23 @@ + return 0; + } + ++#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE) ++int (*br_hard_xmit_hook)(struct sk_buff *skb, struct net_bridge_port *port); ++static __inline__ int bridge_hard_start_xmit(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ struct net_bridge_port *port; ++ ++ if (((port = rcu_dereference(dev->br_port)) == NULL) || ++ (skb->brmark == BR_ALREADY_SEEN)) ++ return 0; ++ ++ return br_hard_xmit_hook(skb, port); ++} ++#else ++#define bridge_hard_start_xmit(skb, dev) (0) ++#endif ++ + int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) + { + if (likely(!skb->next)) { +@@ -1543,6 +1551,8 @@ + goto gso; + } + ++ bridge_hard_start_xmit(skb, dev); ++ + return dev->hard_start_xmit(skb, dev); + } + +@@ -1553,6 +1563,9 @@ + + skb->next = nskb->next; + nskb->next = NULL; ++ ++ bridge_hard_start_xmit(skb, dev); ++ + rc = dev->hard_start_xmit(nskb, dev); + if (unlikely(rc)) { + nskb->next = skb->next; +@@ -2021,6 +2034,7 @@ + struct net_device *orig_dev; + int ret = NET_RX_DROP; + __be16 type; ++ struct ve_struct *old_ve; + + /* if we've gotten here through NAPI, check netpoll */ + if (netpoll_receive_skb(skb)) +@@ -2043,6 +2057,16 @@ + skb_reset_transport_header(skb); + skb->mac_len = skb->network_header - skb->mac_header; + ++#ifdef CONFIG_VE ++ /* ++ * Skb might be alloced in another VE context, than its device works. ++ * So, set the correct owner_env. ++ */ ++ skb->owner_env = skb->dev->owner_env; ++ BUG_ON(skb->owner_env == NULL); ++#endif ++ old_ve = set_exec_env(skb->owner_env); ++ + pt_prev = NULL; + + rcu_read_lock(); +@@ -2098,6 +2122,7 @@ + + out: + rcu_read_unlock(); ++ (void)set_exec_env(old_ve); + return ret; + } + +@@ -2757,8 +2782,11 @@ + dev->flags &= ~IFF_PROMISC; + else + dev->flags |= IFF_PROMISC; ++ /* Promiscous mode on these devices does not mean anything */ ++ if (dev->flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) ++ return; + if (dev->flags != old_flags) { +- printk(KERN_INFO "device %s %s promiscuous mode\n", ++ ve_printk(VE_LOG, KERN_INFO "device %s %s promiscuous mode\n", + dev->name, (dev->flags & IFF_PROMISC) ? "entered" : + "left"); + audit_log(current->audit_context, GFP_ATOMIC, +@@ -3423,11 +3451,20 @@ + * - require strict serialization. + * - do not return a value + */ ++ case SIOCSIFMTU: ++ case SIOCSIFHWADDR: + case SIOCSIFFLAGS: ++ if (!capable(CAP_NET_ADMIN) && ++ !capable(CAP_VE_NET_ADMIN)) ++ return -EPERM; ++ dev_load(net, ifr.ifr_name); ++ rtnl_lock(); ++ ret = dev_ifsioc(net, &ifr, cmd); ++ rtnl_unlock(); ++ return ret; ++ + case SIOCSIFMETRIC: +- case SIOCSIFMTU: + case SIOCSIFMAP: +- case SIOCSIFHWADDR: + case SIOCSIFSLAVE: + case SIOCADDMULTI: + case SIOCDELMULTI: +@@ -3494,12 +3531,11 @@ + */ + static int dev_new_index(struct net *net) + { +- static int ifindex; + for (;;) { +- if (++ifindex <= 0) +- ifindex = 1; +- if (!__dev_get_by_index(net, ifindex)) +- return ifindex; ++ if (++net->ifindex <= 0) ++ net->ifindex = 1; ++ if (!__dev_get_by_index(net, net->ifindex)) ++ return net->ifindex; + } + } + +@@ -3602,6 +3638,10 @@ + BUG_ON(!dev->nd_net); + net = dev->nd_net; + ++ ret = -EPERM; ++ if (!ve_is_super(get_exec_env()) && ve_is_dev_movable(dev)) ++ goto out; ++ + spin_lock_init(&dev->queue_lock); + spin_lock_init(&dev->_xmit_lock); + netdev_set_lockdep_class(&dev->_xmit_lock, dev->type); +@@ -3698,6 +3738,10 @@ + + set_bit(__LINK_STATE_PRESENT, &dev->state); + ++ dev->owner_env = get_exec_env(); ++ netdev_bc(dev)->owner_ub = get_beancounter(get_exec_ub()); ++ netdev_bc(dev)->exec_ub = get_beancounter(get_exec_ub()); ++ + dev_init_scheduler(dev); + dev_hold(dev); + list_netdevice(dev); +@@ -3831,6 +3875,7 @@ + void netdev_run_todo(void) + { + struct list_head list; ++ struct ve_struct *old_ve; + + /* Need to guard against multiple cpu's getting out of order. */ + mutex_lock(&net_todo_run_mutex); +@@ -3848,6 +3893,7 @@ + list_replace_init(&net_todo_list, &list); + spin_unlock(&net_todo_list_lock); + ++ old_ve = get_exec_env(); + while (!list_empty(&list)) { + struct net_device *dev + = list_entry(list.next, struct net_device, todo_list); +@@ -3860,6 +3906,7 @@ + continue; + } + ++ (void)set_exec_env(dev->owner_env); + dev->reg_state = NETREG_UNREGISTERED; + + netdev_wait_allrefs(dev); +@@ -3870,13 +3917,21 @@ + BUG_TRAP(!dev->ip6_ptr); + BUG_TRAP(!dev->dn_ptr); + ++ put_beancounter(netdev_bc(dev)->exec_ub); ++ put_beancounter(netdev_bc(dev)->owner_ub); ++ netdev_bc(dev)->exec_ub = NULL; ++ netdev_bc(dev)->owner_ub = NULL; ++ ++ /* It must be the very last action, ++ * after this 'dev' may point to freed up memory. ++ */ + if (dev->destructor) + dev->destructor(dev); + + /* Free network device */ + kobject_put(&dev->dev.kobj); + } +- ++ (void)set_exec_env(old_ve); + out: + mutex_unlock(&net_todo_run_mutex); + } +@@ -3912,7 +3967,7 @@ + ~NETDEV_ALIGN_CONST; + alloc_size += sizeof_priv + NETDEV_ALIGN_CONST; + +- p = kzalloc(alloc_size, GFP_KERNEL); ++ p = kzalloc(alloc_size, GFP_KERNEL_UBC); + if (!p) { + printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n"); + return NULL; +@@ -4023,11 +4078,15 @@ + * Callers must hold the rtnl semaphore. + */ + +-int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) ++int __dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat, ++ struct ve_struct *src_ve, struct ve_struct *dst_ve, ++ struct user_beancounter *exec_ub) + { + char buf[IFNAMSIZ]; + const char *destname; + int err; ++ struct ve_struct *cur_ve; ++ struct user_beancounter *tmp_ub; + + ASSERT_RTNL(); + +@@ -4078,6 +4137,11 @@ + err = -ENODEV; + unlist_netdevice(dev); + ++ dev->owner_env = dst_ve; ++ tmp_ub = netdev_bc(dev)->exec_ub; ++ netdev_bc(dev)->exec_ub = get_beancounter(exec_ub); ++ put_beancounter(tmp_ub); ++ + synchronize_net(); + + /* Shutdown queueing discipline. */ +@@ -4086,7 +4150,9 @@ + /* Notify protocols, that we are about to destroy + this device. They should clean all the things. + */ ++ cur_ve = set_exec_env(src_ve); + call_netdevice_notifiers(NETDEV_UNREGISTER, dev); ++ (void)set_exec_env(cur_ve); + + /* + * Flush the unicast and multicast chains +@@ -4116,7 +4182,9 @@ + list_netdevice(dev); + + /* Notify protocols, that a new device appeared. */ ++ cur_ve = set_exec_env(dst_ve); + call_netdevice_notifiers(NETDEV_REGISTER, dev); ++ (void)set_exec_env(cur_ve); + + synchronize_net(); + err = 0; +@@ -4124,6 +4192,14 @@ + return err; + } + ++int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) ++{ ++ struct ve_struct *ve = get_exec_env(); ++ struct user_beancounter *ub = get_exec_ub(); ++ ++ return __dev_change_net_namespace(dev, net, pat, ve, ve, ub); ++} ++ + static int dev_cpu_callback(struct notifier_block *nfb, + unsigned long action, + void *ocpu) +@@ -4322,7 +4398,7 @@ + int i; + struct hlist_head *hash; + +- hash = kmalloc(sizeof(*hash) * NETDEV_HASHENTRIES, GFP_KERNEL); ++ hash = kmalloc(sizeof(*hash) * NETDEV_HASHENTRIES, GFP_KERNEL_UBC); + if (hash != NULL) + for (i = 0; i < NETDEV_HASHENTRIES; i++) + INIT_HLIST_HEAD(&hash[i]); +@@ -4464,6 +4540,7 @@ + EXPORT_SYMBOL(dev_valid_name); + EXPORT_SYMBOL(dev_add_pack); + EXPORT_SYMBOL(dev_alloc_name); ++EXPORT_SYMBOL(__dev_change_net_namespace); + EXPORT_SYMBOL(dev_close); + EXPORT_SYMBOL(dev_get_by_flags); + EXPORT_SYMBOL(dev_get_by_index); +@@ -4495,6 +4572,7 @@ + + #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) + EXPORT_SYMBOL(br_handle_frame_hook); ++EXPORT_SYMBOL(br_hard_xmit_hook); + EXPORT_SYMBOL(br_fdb_get_hook); + EXPORT_SYMBOL(br_fdb_put_hook); + #endif +Index: kernel/net/core/dst.c +=================================================================== +--- kernel.orig/net/core/dst.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/core/dst.c 2008-11-24 15:47:46.000000000 +0100 +@@ -278,11 +278,11 @@ + if (!unregister) { + dst->input = dst->output = dst_discard; + } else { +- dst->dev = init_net.loopback_dev; ++ dst->dev = dst->dev->nd_net->loopback_dev; + dev_hold(dst->dev); + dev_put(dev); + if (dst->neighbour && dst->neighbour->dev == dev) { +- dst->neighbour->dev = init_net.loopback_dev; ++ dst->neighbour->dev = dst->dev; + dev_put(dev); + dev_hold(dst->neighbour->dev); + } +@@ -294,12 +294,10 @@ + struct net_device *dev = ptr; + struct dst_entry *dst, *last = NULL; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + switch (event) { + case NETDEV_UNREGISTER: + case NETDEV_DOWN: ++ dst_gc_task(NULL); + mutex_lock(&dst_gc_mutex); + for (dst = dst_busy_list; dst; dst = dst->next) { + last = dst; +Index: kernel/net/core/ethtool.c +=================================================================== +--- kernel.orig/net/core/ethtool.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/core/ethtool.c 2008-11-24 15:47:46.000000000 +0100 +@@ -815,7 +815,7 @@ + case ETHTOOL_GPFLAGS: + break; + default: +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_NET_ADMIN) && !capable(CAP_VE_NET_ADMIN)) + return -EPERM; + } + +Index: kernel/net/core/fib_rules.c +=================================================================== +--- kernel.orig/net/core/fib_rules.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/core/fib_rules.c 2008-11-24 15:47:46.000000000 +0100 +@@ -23,7 +23,7 @@ + { + struct fib_rule *r; + +- r = kzalloc(ops->rule_size, GFP_KERNEL); ++ r = kzalloc(ops->rule_size, GFP_KERNEL_UBC); + if (r == NULL) + return -ENOMEM; + +@@ -245,7 +245,7 @@ + if (err < 0) + goto errout; + +- rule = kzalloc(ops->rule_size, GFP_KERNEL); ++ rule = kzalloc(ops->rule_size, GFP_KERNEL_UBC); + if (rule == NULL) { + err = -ENOMEM; + goto errout; +@@ -621,9 +621,6 @@ + struct net_device *dev = ptr; + struct fib_rules_ops *ops; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + ASSERT_RTNL(); + rcu_read_lock(); + +Index: kernel/net/core/filter.c +=================================================================== +--- kernel.orig/net/core/filter.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/core/filter.c 2008-11-24 15:47:46.000000000 +0100 +@@ -425,7 +425,7 @@ + if (fprog->filter == NULL) + return -EINVAL; + +- fp = sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL); ++ fp = sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL_UBC); + if (!fp) + return -ENOMEM; + if (copy_from_user(fp->insns, fprog->filter, fsize)) { +Index: kernel/net/core/neighbour.c +=================================================================== +--- kernel.orig/net/core/neighbour.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/core/neighbour.c 2008-11-24 15:47:46.000000000 +0100 +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #ifdef CONFIG_SYSCTL + #include + #endif +@@ -35,6 +36,7 @@ + #include + #include + #include ++#include + + #define NEIGH_DEBUG 1 + +@@ -252,6 +254,7 @@ + int entries; + + entries = atomic_inc_return(&tbl->entries) - 1; ++ n = ERR_PTR(-ENOBUFS); + if (entries >= tbl->gc_thresh3 || + (entries >= tbl->gc_thresh2 && + time_after(now, tbl->last_flush + 5 * HZ))) { +@@ -262,7 +265,7 @@ + + n = kmem_cache_zalloc(tbl->kmem_cachep, GFP_ATOMIC); + if (!n) +- goto out_entries; ++ goto out_nomem; + + skb_queue_head_init(&n->arp_queue); + rwlock_init(&n->lock); +@@ -281,6 +284,8 @@ + out: + return n; + ++out_nomem: ++ n = ERR_PTR(-ENOMEM); + out_entries: + atomic_dec(&tbl->entries); + goto out; +@@ -393,12 +398,11 @@ + u32 hash_val; + int key_len = tbl->key_len; + int error; +- struct neighbour *n1, *rc, *n = neigh_alloc(tbl); ++ struct neighbour *n1, *rc, *n; + +- if (!n) { +- rc = ERR_PTR(-ENOBUFS); ++ rc = n = neigh_alloc(tbl); ++ if (IS_ERR(n)) + goto out; +- } + + memcpy(n->primary_key, pkey, key_len); + n->dev = dev; +@@ -644,6 +648,8 @@ + struct neigh_table *tbl = (struct neigh_table *)arg; + struct neighbour *n, **np; + unsigned long expire, now = jiffies; ++ struct ve_struct *env = set_exec_env(tbl->owner_env); ++ struct user_beancounter *ub = set_exec_ub(tbl->owner_ub); + + NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs); + +@@ -708,6 +714,8 @@ + mod_timer(&tbl->gc_timer, now + expire); + + write_unlock(&tbl->lock); ++ set_exec_ub(ub); ++ set_exec_env(env); + } + + static __inline__ int neigh_max_probes(struct neighbour *n) +@@ -735,6 +743,11 @@ + struct neighbour *neigh = (struct neighbour *)arg; + unsigned state; + int notify = 0; ++ struct ve_struct *env; ++ struct user_beancounter *ub; ++ ++ env = set_exec_env(neigh->dev->owner_env); ++ ub = set_exec_ub(netdev_bc(neigh->dev)->exec_ub); + + write_lock(&neigh->lock); + +@@ -838,6 +851,8 @@ + neigh_update_notify(neigh); + + neigh_release(neigh); ++ (void)set_exec_ub(ub); ++ (void)set_exec_env(env); + } + + int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) +@@ -1212,6 +1227,9 @@ + unsigned long now = jiffies; + struct sk_buff *skb; + ++ struct ve_struct *env = set_exec_env(tbl->owner_env); ++ struct user_beancounter *ub = set_exec_ub(tbl->owner_ub); ++ + spin_lock(&tbl->proxy_queue.lock); + + skb = tbl->proxy_queue.next; +@@ -1223,6 +1241,7 @@ + skb = skb->next; + if (tdif <= 0) { + struct net_device *dev = back->dev; ++ + __skb_unlink(back, &tbl->proxy_queue); + if (tbl->proxy_redo && netif_running(dev)) + tbl->proxy_redo(back); +@@ -1230,6 +1249,7 @@ + kfree_skb(back); + + dev_put(dev); ++ + } else if (!sched_next || tdif < sched_next) + sched_next = tdif; + } +@@ -1237,6 +1257,8 @@ + if (sched_next) + mod_timer(&tbl->proxy_timer, jiffies + sched_next); + spin_unlock(&tbl->proxy_queue.lock); ++ (void)set_exec_ub(ub); ++ (void)set_exec_env(env); + } + + void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, +@@ -1333,12 +1355,15 @@ + + static struct lock_class_key neigh_table_proxy_queue_class; + +-void neigh_table_init_no_netlink(struct neigh_table *tbl) ++int neigh_table_init_no_netlink(struct neigh_table *tbl) + { + unsigned long now = jiffies; + unsigned long phsize; + ++ atomic_set(&tbl->entries, 0); ++ tbl->hash_chain_gc = 0; + atomic_set(&tbl->parms.refcnt, 1); ++ tbl->parms.next = NULL; + INIT_RCU_HEAD(&tbl->parms.rcu_head); + tbl->parms.reachable_time = + neigh_rand_reach_time(tbl->parms.base_reachable_time); +@@ -1346,18 +1371,26 @@ + if (!tbl->kmem_cachep) + tbl->kmem_cachep = + kmem_cache_create(tbl->id, tbl->entry_size, 0, +- SLAB_HWCACHE_ALIGN|SLAB_PANIC, ++ SLAB_HWCACHE_ALIGN|SLAB_UBC, + NULL); ++ if (!tbl->kmem_cachep) ++ return -ENOMEM; ++ + tbl->stats = alloc_percpu(struct neigh_statistics); + if (!tbl->stats) +- panic("cannot create neighbour cache statistics"); ++ return -ENOMEM; ++ ++ tbl->owner_env = get_ve(get_exec_env()); ++ tbl->owner_ub = get_beancounter(get_exec_ub()); + + #ifdef CONFIG_PROC_FS +- tbl->pde = create_proc_entry(tbl->id, 0, init_net.proc_net_stat); +- if (!tbl->pde) +- panic("cannot create neighbour proc dir entry"); +- tbl->pde->proc_fops = &neigh_stat_seq_fops; +- tbl->pde->data = tbl; ++ if (ve_is_super(get_exec_env())) { ++ tbl->pde = create_proc_entry(tbl->id, 0, init_net.proc_net_stat); ++ if (!tbl->pde) ++ panic("cannot create neighbour proc dir entry"); ++ tbl->pde->proc_fops = &neigh_stat_seq_fops; ++ tbl->pde->data = tbl; ++ } + #endif + + tbl->hash_mask = 1; +@@ -1367,7 +1400,7 @@ + tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL); + + if (!tbl->hash_buckets || !tbl->phash_buckets) +- panic("cannot allocate neighbour cache hashes"); ++ goto nomem; + + get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd)); + +@@ -1386,15 +1419,38 @@ + + tbl->last_flush = now; + tbl->last_rand = now + tbl->parms.reachable_time * 20; ++ return 0; ++ ++nomem: ++ if (tbl->hash_buckets) { ++ neigh_hash_free(tbl->hash_buckets, tbl->hash_mask + 1); ++ tbl->hash_buckets = NULL; ++ } ++ if (tbl->phash_buckets) { ++ kfree(tbl->phash_buckets); ++ tbl->phash_buckets = NULL; ++ } ++ if (tbl->stats) { ++ free_percpu(tbl->stats); ++ tbl->stats = NULL; ++ } ++ put_beancounter(tbl->owner_ub); ++ put_ve(tbl->owner_env); ++ return -ENOMEM; + } + +-void neigh_table_init(struct neigh_table *tbl) ++int neigh_table_init(struct neigh_table *tbl) + { + struct neigh_table *tmp; ++ int err; + +- neigh_table_init_no_netlink(tbl); ++ err = neigh_table_init_no_netlink(tbl); ++ if (err) ++ return err; + write_lock(&neigh_tbl_lock); + for (tmp = neigh_tables; tmp; tmp = tmp->next) { ++ if (!ve_accessible_strict(tmp->owner_env, get_exec_env())) ++ continue; + if (tmp->family == tbl->family) + break; + } +@@ -1407,6 +1463,7 @@ + "family %d\n", tbl->family); + dump_stack(); + } ++ return 0; + } + + int neigh_table_clear(struct neigh_table *tbl) +@@ -1420,6 +1477,15 @@ + neigh_ifdown(tbl, NULL); + if (atomic_read(&tbl->entries)) + printk(KERN_CRIT "neighbour leakage\n"); ++#ifdef CONFIG_PROC_FS ++ if (ve_is_super(get_exec_env())) { ++ char name[strlen(tbl->id) + sizeof("net/stat/")]; ++ strcpy(name, "net/stat/"); ++ strcat(name, tbl->id); ++ remove_proc_glob_entry(name, NULL); ++ } ++#endif ++ + write_lock(&neigh_tbl_lock); + for (tp = &neigh_tables; *tp; tp = &(*tp)->next) { + if (*tp == tbl) { +@@ -1440,8 +1506,13 @@ + free_percpu(tbl->stats); + tbl->stats = NULL; + +- kmem_cache_destroy(tbl->kmem_cachep); +- tbl->kmem_cachep = NULL; ++ if (ve_is_super(get_exec_env())) { ++ kmem_cache_destroy(tbl->kmem_cachep); ++ tbl->kmem_cachep = NULL; ++ } ++ ++ put_beancounter(tbl->owner_ub); ++ put_ve(tbl->owner_env); + + return 0; + } +@@ -1477,6 +1548,8 @@ + + if (tbl->family != ndm->ndm_family) + continue; ++ if (!ve_accessible_strict(tbl->owner_env, get_exec_env())) ++ continue; + read_unlock(&neigh_tbl_lock); + + if (nla_len(dst_attr) < tbl->key_len) +@@ -1549,6 +1622,8 @@ + + if (tbl->family != ndm->ndm_family) + continue; ++ if (!ve_accessible_strict(tbl->owner_env, get_exec_env())) ++ continue; + read_unlock(&neigh_tbl_lock); + + if (nla_len(tb[NDA_DST]) < tbl->key_len) +@@ -1816,6 +1891,9 @@ + if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) + continue; + ++ if (!ve_accessible_strict(tbl->owner_env, get_exec_env())) ++ continue; ++ + if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) + break; + } +@@ -2056,6 +2134,8 @@ + s_t = cb->args[0]; + + for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) { ++ if (!ve_accessible_strict(tbl->owner_env, get_exec_env())) ++ continue; + if (t < s_t || (family && tbl->family != family)) + continue; + if (t > s_t) +Index: kernel/net/core/net-sysfs.c +=================================================================== +--- kernel.orig/net/core/net-sysfs.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/core/net-sysfs.c 2008-11-24 15:47:46.000000000 +0100 +@@ -238,6 +238,27 @@ + {} + }; + ++#ifdef CONFIG_VE ++struct device_attribute ve_net_class_attributes[] = { ++ __ATTR(addr_len, S_IRUGO, show_addr_len, NULL), ++ __ATTR(iflink, S_IRUGO, show_iflink, NULL), ++ __ATTR(ifindex, S_IRUGO, show_ifindex, NULL), ++ __ATTR(features, S_IRUGO, show_features, NULL), ++ __ATTR(type, S_IRUGO, show_type, NULL), ++ __ATTR(link_mode, S_IRUGO, show_link_mode, NULL), ++ __ATTR(address, S_IRUGO, show_address, NULL), ++ __ATTR(broadcast, S_IRUGO, show_broadcast, NULL), ++ __ATTR(carrier, S_IRUGO, show_carrier, NULL), ++ __ATTR(dormant, S_IRUGO, show_dormant, NULL), ++ __ATTR(operstate, S_IRUGO, show_operstate, NULL), ++ __ATTR(mtu, S_IRUGO, show_mtu, NULL), ++ __ATTR(flags, S_IRUGO, show_flags, NULL), ++ __ATTR(tx_queue_len, S_IRUGO, show_tx_queue_len, NULL), ++ {} ++}; ++EXPORT_SYMBOL(ve_net_class_attributes); ++#endif ++ + /* Show a given an attribute in the statistics group */ + static ssize_t netstat_show(const struct device *d, + struct device_attribute *attr, char *buf, +@@ -431,7 +452,7 @@ + kfree((char *)dev - dev->padded); + } + +-static struct class net_class = { ++struct class net_class = { + .name = "net", + .dev_release = netdev_release, + #ifdef CONFIG_SYSFS +@@ -441,6 +462,13 @@ + .dev_uevent = netdev_uevent, + #endif + }; ++EXPORT_SYMBOL(net_class); ++ ++#ifndef CONFIG_VE ++#define visible_net_class net_class ++#else ++#define visible_net_class (*get_exec_env()->net_class) ++#endif + + /* Delete sysfs entries but hold kobject reference until after all + * netdev references are gone. +@@ -460,7 +488,7 @@ + struct attribute_group **groups = net->sysfs_groups; + + device_initialize(dev); +- dev->class = &net_class; ++ dev->class = &visible_net_class; + dev->platform_data = net; + dev->groups = groups; + +@@ -480,7 +508,15 @@ + return device_add(dev); + } + ++void prepare_sysfs_netdev(void) ++{ ++#ifdef CONFIG_VE ++ get_ve0()->net_class = &net_class; ++#endif ++} ++ + int netdev_kobject_init(void) + { ++ prepare_sysfs_netdev(); + return class_register(&net_class); + } +Index: kernel/net/core/net_namespace.c +=================================================================== +--- kernel.orig/net/core/net_namespace.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/core/net_namespace.c 2008-11-24 15:47:46.000000000 +0100 +@@ -1,6 +1,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -66,6 +67,8 @@ + + static void net_free(struct net *net) + { ++ struct completion *sysfs_completion; ++ + if (!net) + return; + +@@ -75,7 +78,10 @@ + return; + } + ++ sysfs_completion = net->sysfs_completion; + kmem_cache_free(net_cachep, net); ++ if (sysfs_completion) ++ complete(sysfs_completion); + } + + struct net *copy_net_ns(unsigned long flags, struct net *old_net) +@@ -92,7 +98,13 @@ + new_net = net_alloc(); + if (!new_net) + goto out; +- ++#ifdef CONFIG_VE ++ new_net->owner_ve = get_exec_env(); ++ new_net->proc_net = get_exec_env()->_proc_net; ++ new_net->proc_net->data = new_net; ++ new_net->proc_net_stat = get_exec_env()->_proc_net_stat; ++ new_net->proc_net_stat->data = new_net; ++#endif + mutex_lock(&net_mutex); + err = setup_net(new_net); + if (err) +@@ -118,6 +130,7 @@ + { + struct pernet_operations *ops; + struct net *net; ++ struct ve_struct *old_ve; + + net = container_of(work, struct net, work); + +@@ -128,11 +141,13 @@ + list_del(&net->list); + rtnl_unlock(); + ++ old_ve = set_exec_env(net->owner_ve); + /* Run all of the network namespace exit methods */ + list_for_each_entry_reverse(ops, &pernet_list, list) { + if (ops->exit) + ops->exit(net); + } ++ (void)set_exec_env(old_ve); + + mutex_unlock(&net_mutex); + +Index: kernel/net/core/rtnetlink.c +=================================================================== +--- kernel.orig/net/core/rtnetlink.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/core/rtnetlink.c 2008-11-24 15:47:46.000000000 +0100 +@@ -1207,6 +1207,8 @@ + if (rtnl_msg_handlers[idx] == NULL || + rtnl_msg_handlers[idx][type].dumpit == NULL) + continue; ++ if (vz_security_family_check(idx)) ++ continue; + if (idx > s_idx) + memset(&cb->args[0], 0, sizeof(cb->args)); + if (rtnl_msg_handlers[idx][type].dumpit(skb, cb)) +@@ -1265,13 +1267,13 @@ + return 0; + + family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family; +- if (family >= NPROTO) ++ if (family >= NPROTO || vz_security_family_check(family)) + return -EAFNOSUPPORT; + + sz_idx = type>>2; + kind = type&3; + +- if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) ++ if (kind != 2 && security_netlink_recv(skb, CAP_VE_NET_ADMIN)) + return -EPERM; + + if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { +@@ -1326,9 +1328,6 @@ + { + struct net_device *dev = ptr; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + switch (event) { + case NETDEV_UNREGISTER: + rtmsg_ifinfo(RTM_DELLINK, dev, ~0U); +Index: kernel/net/core/scm.c +=================================================================== +--- kernel.orig/net/core/scm.c 2008-11-24 14:08:46.000000000 +0100 ++++ kernel/net/core/scm.c 2008-11-24 15:47:46.000000000 +0100 +@@ -36,6 +36,7 @@ + #include + #include + ++#include + + /* + * Only allow a user to send credentials, that they could set with +@@ -44,7 +45,9 @@ + + static __inline__ int scm_check_creds(struct ucred *creds) + { +- if ((creds->pid == task_tgid_vnr(current) || capable(CAP_SYS_ADMIN)) && ++ if ((creds->pid == task_tgid_vnr(current) || ++ creds->pid == current->tgid || ++ capable(CAP_VE_SYS_ADMIN)) && + ((creds->uid == current->uid || creds->uid == current->euid || + creds->uid == current->suid) || capable(CAP_SETUID)) && + ((creds->gid == current->gid || creds->gid == current->egid || +@@ -71,7 +74,7 @@ + + if (!fpl) + { +- fpl = kmalloc(sizeof(struct scm_fp_list), GFP_KERNEL); ++ fpl = kmalloc(sizeof(struct scm_fp_list), GFP_KERNEL_UBC); + if (!fpl) + return -ENOMEM; + *fplp = fpl; +@@ -299,7 +302,7 @@ + if (!fpl) + return NULL; + +- new_fpl = kmalloc(sizeof(*fpl), GFP_KERNEL); ++ new_fpl = kmalloc(sizeof(*fpl), GFP_KERNEL_UBC); + if (new_fpl) { + INIT_LIST_HEAD(&new_fpl->list); + for (i=fpl->count-1; i>=0; i--) +Index: kernel/net/core/skbuff.c +=================================================================== +--- kernel.orig/net/core/skbuff.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/core/skbuff.c 2008-11-24 15:47:46.000000000 +0100 +@@ -66,6 +66,8 @@ + #include + #include + ++#include ++ + #include "kmap_skb.h" + + static struct kmem_cache *skbuff_head_cache __read_mostly; +@@ -158,6 +160,10 @@ + if (!skb) + goto out; + ++ if (ub_skb_alloc_bc(skb, gfp_mask & ~__GFP_DMA)) ++ goto nobc; ++ ++ /* Get the DATA. Size must match skb_add_mtu(). */ + size = SKB_DATA_ALIGN(size); + data = kmalloc_node_track_caller(size + sizeof(struct skb_shared_info), + gfp_mask, node); +@@ -174,6 +180,7 @@ + skb->data = data; + skb_reset_tail_pointer(skb); + skb->end = skb->tail + size; ++ skb->owner_env = get_exec_env(); + /* make sure we initialize shinfo sequentially */ + shinfo = skb_shinfo(skb); + atomic_set(&shinfo->dataref, 1); +@@ -196,6 +203,8 @@ + out: + return skb; + nodata: ++ ub_skb_free_bc(skb); ++nobc: + kmem_cache_free(cache, skb); + skb = NULL; + goto out; +@@ -280,6 +289,7 @@ + struct sk_buff *other; + atomic_t *fclone_ref; + ++ ub_skb_free_bc(skb); + switch (skb->fclone) { + case SKB_FCLONE_UNAVAILABLE: + kmem_cache_free(skbuff_head_cache, skb); +@@ -313,6 +323,7 @@ + #ifdef CONFIG_XFRM + secpath_put(skb->sp); + #endif ++ ub_skb_uncharge(skb); + if (skb->destructor) { + WARN_ON(in_irq()); + skb->destructor(skb); +@@ -402,6 +413,11 @@ + new->tc_verd = old->tc_verd; + #endif + #endif ++#ifdef CONFIG_VE ++ new->accounted = old->accounted; ++ new->redirected = old->redirected; ++#endif ++ skb_copy_brmark(new, old); + skb_copy_secmark(new, old); + } + +@@ -419,6 +435,10 @@ + n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len; + n->cloned = 1; + n->nohdr = 0; ++ C(owner_env); ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ C(brmark); ++#endif + n->destructor = NULL; + C(iif); + C(tail); +@@ -428,6 +448,11 @@ + C(truesize); + atomic_set(&n->users, 1); + ++#ifdef CONFIG_VE ++ C(accounted); ++ C(redirected); ++#endif ++ + atomic_inc(&(skb_shinfo(skb)->dataref)); + skb->cloned = 1; + +@@ -483,6 +508,10 @@ + n->fclone = SKB_FCLONE_UNAVAILABLE; + } + ++ if (ub_skb_alloc_bc(n, gfp_mask)) { ++ kmem_cache_free(skbuff_head_cache, n); ++ return NULL; ++ } + return __skb_clone(n, skb); + } + +Index: kernel/net/core/sock.c +=================================================================== +--- kernel.orig/net/core/sock.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/core/sock.c 2008-11-24 15:47:46.000000000 +0100 +@@ -125,6 +125,9 @@ + #include + #include + ++#include ++#include ++ + #include + + #ifdef CONFIG_INET +@@ -249,7 +252,7 @@ + static char warncomm[TASK_COMM_LEN]; + if (strcmp(warncomm, current->comm) && warned < 5) { + strcpy(warncomm, current->comm); +- printk(KERN_WARNING "process `%s' is using obsolete " ++ ve_printk(VE_LOG, KERN_WARNING "process `%s' is using obsolete " + "%s SO_BSDCOMPAT\n", warncomm, name); + warned++; + } +@@ -278,6 +281,10 @@ + goto out; + } + ++ err = ub_sockrcvbuf_charge(sk, skb); ++ if (err < 0) ++ goto out; ++ + err = sk_filter(sk, skb); + if (err) + goto out; +@@ -911,6 +918,7 @@ + slab = prot->slab; + + security_sk_free(sk); ++ ub_sock_uncharge(sk); + if (slab != NULL) + kmem_cache_free(slab, sk); + else +@@ -940,6 +948,7 @@ + */ + sk->sk_prot = sk->sk_prot_creator = prot; + sock_lock_init(sk); ++ sk->owner_env = get_exec_env(); + sk->sk_net = get_net(net); + } + +@@ -1014,14 +1023,11 @@ + if (filter != NULL) + sk_filter_charge(newsk, filter); + +- if (unlikely(xfrm_sk_clone_policy(newsk))) { +- /* It is still raw copy of parent, so invalidate +- * destructor and make plain sk_free() */ +- newsk->sk_destruct = NULL; +- sk_free(newsk); +- newsk = NULL; +- goto out; +- } ++ if (ub_sock_charge(newsk, newsk->sk_family, newsk->sk_type) < 0) ++ goto out_err; ++ ++ if (unlikely(xfrm_sk_clone_policy(newsk))) ++ goto out_err; + + newsk->sk_err = 0; + newsk->sk_priority = 0; +@@ -1045,14 +1051,23 @@ + if (newsk->sk_prot->sockets_allocated) + atomic_inc(newsk->sk_prot->sockets_allocated); + } +-out: + return newsk; ++ ++out_err: ++ /* It is still raw copy of parent, so invalidate ++ * destructor and make plain sk_free() */ ++ sock_reset_flag(newsk, SOCK_TIMESTAMP); ++ newsk->sk_destruct = NULL; ++ sk_free(newsk); ++ return NULL; + } + + EXPORT_SYMBOL_GPL(sk_clone); + + void sk_setup_caps(struct sock *sk, struct dst_entry *dst) + { ++ extern int sysctl_tcp_use_sg; ++ + __sk_dst_set(sk, dst); + sk->sk_route_caps = dst->dev->features; + if (sk->sk_route_caps & NETIF_F_GSO) +@@ -1063,6 +1078,8 @@ + else + sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; + } ++ if (!sysctl_tcp_use_sg) ++ sk->sk_route_caps &= ~NETIF_F_SG; + } + EXPORT_SYMBOL_GPL(sk_setup_caps); + +@@ -1221,11 +1238,9 @@ + /* + * Generic send/receive buffer handlers + */ +- +-static struct sk_buff *sock_alloc_send_pskb(struct sock *sk, +- unsigned long header_len, +- unsigned long data_len, +- int noblock, int *errcode) ++struct sk_buff *sock_alloc_send_skb2(struct sock *sk, unsigned long size, ++ unsigned long size2, int noblock, ++ int *errcode) + { + struct sk_buff *skb; + gfp_t gfp_mask; +@@ -1246,46 +1261,35 @@ + if (sk->sk_shutdown & SEND_SHUTDOWN) + goto failure; + +- if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { +- skb = alloc_skb(header_len, gfp_mask); +- if (skb) { +- int npages; +- int i; +- +- /* No pages, we're done... */ +- if (!data_len) +- break; +- +- npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT; +- skb->truesize += data_len; +- skb_shinfo(skb)->nr_frags = npages; +- for (i = 0; i < npages; i++) { +- struct page *page; +- skb_frag_t *frag; +- +- page = alloc_pages(sk->sk_allocation, 0); +- if (!page) { +- err = -ENOBUFS; +- skb_shinfo(skb)->nr_frags = i; +- kfree_skb(skb); +- goto failure; +- } +- +- frag = &skb_shinfo(skb)->frags[i]; +- frag->page = page; +- frag->page_offset = 0; +- frag->size = (data_len >= PAGE_SIZE ? +- PAGE_SIZE : +- data_len); +- data_len -= PAGE_SIZE; +- } ++ if (ub_sock_getwres_other(sk, skb_charge_size(size))) { ++ if (size2 < size) { ++ size = size2; ++ continue; ++ } ++ set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); ++ err = -EAGAIN; ++ if (!timeo) ++ goto failure; ++ if (signal_pending(current)) ++ goto interrupted; ++ timeo = ub_sock_wait_for_space(sk, timeo, ++ skb_charge_size(size)); ++ continue; ++ } + ++ if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { ++ skb = alloc_skb(size, gfp_mask); ++ if (skb) + /* Full success... */ + break; +- } ++ ub_sock_retwres_other(sk, skb_charge_size(size), ++ SOCK_MIN_UBCSPACE_CH); + err = -ENOBUFS; + goto failure; + } ++ ub_sock_retwres_other(sk, ++ skb_charge_size(size), ++ SOCK_MIN_UBCSPACE_CH); + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + err = -EAGAIN; +@@ -1296,6 +1300,7 @@ + timeo = sock_wait_for_wmem(sk, timeo); + } + ++ ub_skb_set_charge(skb, sk, skb_charge_size(size), UB_OTHERSOCKBUF); + skb_set_owner_w(skb, sk); + return skb; + +@@ -1305,11 +1310,12 @@ + *errcode = err; + return NULL; + } ++EXPORT_SYMBOL(sock_alloc_send_skb2); + + struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, + int noblock, int *errcode) + { +- return sock_alloc_send_pskb(sk, size, 0, noblock, errcode); ++ return sock_alloc_send_skb2(sk, size, size, noblock, errcode); + } + + static void __lock_sock(struct sock *sk) +@@ -1621,10 +1627,12 @@ + __lock_sock(sk); + sk->sk_lock.owned = 1; + spin_unlock(&sk->sk_lock.slock); ++#if !defined(CONFIG_VZ_CHECKPOINT) && !defined(CONFIG_VZ_CHECKPOINT_MODULE) + /* + * The sk_lock has mutex_lock() semantics here: + */ + mutex_acquire(&sk->sk_lock.dep_map, subclass, 0, _RET_IP_); ++#endif + local_bh_enable(); + } + +@@ -1632,11 +1640,12 @@ + + void fastcall release_sock(struct sock *sk) + { ++#if !defined(CONFIG_VZ_CHECKPOINT) && !defined(CONFIG_VZ_CHECKPOINT_MODULE) + /* + * The sk_lock has mutex_unlock() semantics: + */ + mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_); +- ++#endif + spin_lock_bh(&sk->sk_lock.slock); + if (sk->sk_backlog.tail) + __release_sock(sk); +@@ -1863,7 +1872,7 @@ + + if (alloc_slab) { + prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0, +- SLAB_HWCACHE_ALIGN, NULL); ++ SLAB_HWCACHE_ALIGN|SLAB_UBC, NULL); + + if (prot->slab == NULL) { + printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n", +@@ -1881,7 +1890,7 @@ + sprintf(request_sock_slab_name, mask, prot->name); + prot->rsk_prot->slab = kmem_cache_create(request_sock_slab_name, + prot->rsk_prot->obj_size, 0, +- SLAB_HWCACHE_ALIGN, NULL); ++ SLAB_HWCACHE_ALIGN|SLAB_UBC, NULL); + + if (prot->rsk_prot->slab == NULL) { + printk(KERN_CRIT "%s: Can't create request sock SLAB cache!\n", +@@ -1902,7 +1911,7 @@ + prot->twsk_prot->twsk_slab = + kmem_cache_create(timewait_sock_slab_name, + prot->twsk_prot->twsk_obj_size, +- 0, SLAB_HWCACHE_ALIGN, ++ 0, SLAB_HWCACHE_ALIGN|SLAB_UBC, + NULL); + if (prot->twsk_prot->twsk_slab == NULL) + goto out_free_timewait_sock_slab_name; +@@ -2058,10 +2067,26 @@ + .release = seq_release, + }; + ++static int proto_net_init(struct net *net) ++{ ++ if (!proc_net_fops_create(net, "protocols", S_IRUGO, &proto_seq_fops)) ++ return -ENOBUFS; ++ return 0; ++} ++ ++static void proto_net_exit(struct net *net) ++{ ++ proc_net_remove(net, "protocols"); ++} ++ ++static struct pernet_operations proto_net_ops = { ++ .init = proto_net_init, ++ .exit = proto_net_exit, ++}; ++ + static int __init proto_init(void) + { +- /* register /proc/net/protocols */ +- return proc_net_fops_create(&init_net, "protocols", S_IRUGO, &proto_seq_fops) == NULL ? -ENOBUFS : 0; ++ return register_pernet_subsys(&proto_net_ops); + } + + subsys_initcall(proto_init); +Index: kernel/net/core/stream.c +=================================================================== +--- kernel.orig/net/core/stream.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/core/stream.c 2008-11-24 15:47:46.000000000 +0100 +@@ -111,8 +111,10 @@ + * sk_stream_wait_memory - Wait for more memory for a socket + * @sk: socket to wait for memory + * @timeo_p: for how long ++ * @amount - amount of memory to wait for (in UB space!) + */ +-int sk_stream_wait_memory(struct sock *sk, long *timeo_p) ++int __sk_stream_wait_memory(struct sock *sk, long *timeo_p, ++ unsigned long amount) + { + int err = 0; + long vm_wait = 0; +@@ -134,8 +136,11 @@ + if (signal_pending(current)) + goto do_interrupted; + clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); +- if (sk_stream_memory_free(sk) && !vm_wait) +- break; ++ if (amount == 0) { ++ if (sk_stream_memory_free(sk) && !vm_wait) ++ break; ++ } else ++ ub_sock_sndqueueadd_tcp(sk, amount); + + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + sk->sk_write_pending++; +@@ -144,6 +149,8 @@ + sk_stream_memory_free(sk) && + vm_wait); + sk->sk_write_pending--; ++ if (amount > 0) ++ ub_sock_sndqueuedel(sk); + + if (vm_wait) { + vm_wait -= current_timeo; +@@ -170,6 +177,10 @@ + goto out; + } + ++int sk_stream_wait_memory(struct sock *sk, long *timeo_p) ++{ ++ return __sk_stream_wait_memory(sk, timeo_p, 0); ++} + EXPORT_SYMBOL(sk_stream_wait_memory); + + void sk_stream_rfree(struct sk_buff *skb) +Index: kernel/net/dccp/ipv6.c +=================================================================== +--- kernel.orig/net/dccp/ipv6.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/dccp/ipv6.c 2008-11-24 15:47:46.000000000 +0100 +@@ -574,6 +574,8 @@ + __ip6_dst_store(newsk, dst, NULL, NULL); + newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM | + NETIF_F_TSO); ++ if (!sysctl_tcp_use_sg) ++ newsk->sk_route_caps &= ~NETIF_F_SG; + newdp6 = (struct dccp6_sock *)newsk; + newinet = inet_sk(newsk); + newinet->pinet6 = &newdp6->inet6; +Index: kernel/net/dccp/minisocks.c +=================================================================== +--- kernel.orig/net/dccp/minisocks.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/dccp/minisocks.c 2008-11-24 15:47:46.000000000 +0100 +@@ -19,6 +19,8 @@ + #include + #include + ++#include ++ + #include "ackvec.h" + #include "ccid.h" + #include "dccp.h" +@@ -56,7 +58,8 @@ + { + struct inet_timewait_sock *tw = NULL; + +- if (dccp_death_row.tw_count < dccp_death_row.sysctl_max_tw_buckets) ++ if (dccp_death_row.tw_count < dccp_death_row.sysctl_max_tw_buckets && ++ ub_timewait_check(sk, &dccp_death_row)) + tw = inet_twsk_alloc(sk, state); + + if (tw != NULL) { +Index: kernel/net/decnet/netfilter/dn_rtmsg.c +=================================================================== +--- kernel.orig/net/decnet/netfilter/dn_rtmsg.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/decnet/netfilter/dn_rtmsg.c 2008-11-24 15:47:46.000000000 +0100 +@@ -107,7 +107,7 @@ + if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) + return; + +- if (security_netlink_recv(skb, CAP_NET_ADMIN)) ++ if (security_netlink_recv(skb, CAP_VE_NET_ADMIN)) + RCV_SKB_FAIL(-EPERM); + + /* Eventually we might send routing messages too */ +Index: kernel/net/ipv4/af_inet.c +=================================================================== +--- kernel.orig/net/ipv4/af_inet.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/af_inet.c 2008-11-24 15:47:46.000000000 +0100 +@@ -115,6 +115,7 @@ + #ifdef CONFIG_IP_MROUTE + #include + #endif ++#include + + DEFINE_SNMP_STAT(struct linux_mib, net_statistics) __read_mostly; + +@@ -253,9 +254,6 @@ + int try_loading_module = 0; + int err; + +- if (net != &init_net) +- return -EAFNOSUPPORT; +- + if (sock->type != SOCK_RAW && + sock->type != SOCK_DGRAM && + !inet_ehash_secret) +@@ -310,6 +308,10 @@ + goto out_rcu_unlock; + } + ++ err = vz_security_protocol_check(answer->protocol); ++ if (err < 0) ++ goto out_rcu_unlock; ++ + err = -EPERM; + if (answer->capability > 0 && !capable(answer->capability)) + goto out_rcu_unlock; +@@ -327,6 +329,13 @@ + if (sk == NULL) + goto out; + ++ err = -ENOBUFS; ++ if (ub_sock_charge(sk, PF_INET, sock->type)) ++ goto out_sk_free; ++ /* if charge was successful, sock_init_data() MUST be called to ++ * set sk->sk_type. otherwise sk will be uncharged to wrong resource ++ */ ++ + err = 0; + sk->sk_no_check = answer_no_check; + if (INET_PROTOSW_REUSE & answer_flags) +@@ -384,6 +393,9 @@ + out_rcu_unlock: + rcu_read_unlock(); + goto out; ++out_sk_free: ++ sk_free(sk); ++ return err; + } + + +@@ -398,6 +410,9 @@ + + if (sk) { + long timeout; ++ struct ve_struct *saved_env; ++ ++ saved_env = set_exec_env(sk->owner_env); + + /* Applications forget to leave groups before exiting */ + ip_mc_drop_socket(sk); +@@ -415,6 +430,8 @@ + timeout = sk->sk_lingertime; + sock->sk = NULL; + sk->sk_prot->close(sk, timeout); ++ ++ (void)set_exec_env(saved_env); + } + return 0; + } +@@ -1290,31 +1307,31 @@ + + static int __init init_ipv4_mibs(void) + { +- if (snmp_mib_init((void **)net_statistics, ++ if (snmp_mib_init((void **)ve_net_statistics, + sizeof(struct linux_mib), + __alignof__(struct linux_mib)) < 0) + goto err_net_mib; +- if (snmp_mib_init((void **)ip_statistics, ++ if (snmp_mib_init((void **)ve_ip_statistics, + sizeof(struct ipstats_mib), + __alignof__(struct ipstats_mib)) < 0) + goto err_ip_mib; +- if (snmp_mib_init((void **)icmp_statistics, ++ if (snmp_mib_init((void **)ve_icmp_statistics, + sizeof(struct icmp_mib), + __alignof__(struct icmp_mib)) < 0) + goto err_icmp_mib; +- if (snmp_mib_init((void **)icmpmsg_statistics, ++ if (snmp_mib_init((void **)ve_icmpmsg_statistics, + sizeof(struct icmpmsg_mib), + __alignof__(struct icmpmsg_mib)) < 0) + goto err_icmpmsg_mib; +- if (snmp_mib_init((void **)tcp_statistics, ++ if (snmp_mib_init((void **)ve_tcp_statistics, + sizeof(struct tcp_mib), + __alignof__(struct tcp_mib)) < 0) + goto err_tcp_mib; +- if (snmp_mib_init((void **)udp_statistics, ++ if (snmp_mib_init((void **)ve_udp_statistics, + sizeof(struct udp_mib), + __alignof__(struct udp_mib)) < 0) + goto err_udp_mib; +- if (snmp_mib_init((void **)udplite_statistics, ++ if (snmp_mib_init((void **)ve_udplite_statistics, + sizeof(struct udp_mib), + __alignof__(struct udp_mib)) < 0) + goto err_udplite_mib; +@@ -1324,17 +1341,17 @@ + return 0; + + err_udplite_mib: +- snmp_mib_free((void **)udp_statistics); ++ snmp_mib_free((void **)ve_udp_statistics); + err_udp_mib: +- snmp_mib_free((void **)tcp_statistics); ++ snmp_mib_free((void **)ve_tcp_statistics); + err_tcp_mib: +- snmp_mib_free((void **)icmpmsg_statistics); ++ snmp_mib_free((void **)ve_icmpmsg_statistics); + err_icmpmsg_mib: +- snmp_mib_free((void **)icmp_statistics); ++ snmp_mib_free((void **)ve_icmp_statistics); + err_icmp_mib: +- snmp_mib_free((void **)ip_statistics); ++ snmp_mib_free((void **)ve_ip_statistics); + err_ip_mib: +- snmp_mib_free((void **)net_statistics); ++ snmp_mib_free((void **)ve_net_statistics); + err_net_mib: + return -ENOMEM; + } +Index: kernel/net/ipv4/arp.c +=================================================================== +--- kernel.orig/net/ipv4/arp.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/arp.c 2008-11-24 15:47:46.000000000 +0100 +@@ -84,6 +84,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -170,7 +171,7 @@ + .queue_xmit = dev_queue_xmit, + }; + +-struct neigh_table arp_tbl = { ++struct neigh_table global_arp_tbl = { + .family = AF_INET, + .entry_size = sizeof(struct neighbour) + 4, + .key_len = 4, +@@ -179,7 +180,7 @@ + .proxy_redo = parp_redo, + .id = "arp_cache", + .parms = { +- .tbl = &arp_tbl, ++ .tbl = &global_arp_tbl, + .base_reachable_time = 30 * HZ, + .retrans_time = 1 * HZ, + .gc_staletime = 60 * HZ, +@@ -914,9 +915,6 @@ + { + struct arphdr *arp; + +- if (dev->nd_net != &init_net) +- goto freeskb; +- + /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ + if (!pskb_may_pull(skb, (sizeof(struct arphdr) + + (2 * dev->addr_len) + +@@ -963,7 +961,7 @@ + if (mask && mask != htonl(0xFFFFFFFF)) + return -EINVAL; + if (!dev && (r->arp_flags & ATF_COM)) { +- dev = dev_getbyhwaddr(&init_net, r->arp_ha.sa_family, r->arp_ha.sa_data); ++ dev = dev_getbyhwaddr(get_exec_env()->ve_ns->net_ns, r->arp_ha.sa_family, r->arp_ha.sa_data); + if (!dev) + return -ENODEV; + } +@@ -1128,7 +1126,8 @@ + switch (cmd) { + case SIOCDARP: + case SIOCSARP: +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_NET_ADMIN) && ++ !capable(CAP_VE_NET_ADMIN)) + return -EPERM; + case SIOCGARP: + err = copy_from_user(&r, arg, sizeof(struct arpreq)); +@@ -1151,7 +1150,7 @@ + rtnl_lock(); + if (r.arp_dev[0]) { + err = -ENODEV; +- if ((dev = __dev_get_by_name(&init_net, r.arp_dev)) == NULL) ++ if ((dev = __dev_get_by_name(get_exec_env()->ve_ns->net_ns, r.arp_dev)) == NULL) + goto out; + + /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ +@@ -1187,9 +1186,6 @@ + { + struct net_device *dev = ptr; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + switch (event) { + case NETDEV_CHANGEADDR: + neigh_changeaddr(&arp_tbl, dev); +@@ -1225,18 +1221,69 @@ + .func = arp_rcv, + }; + +-static int arp_proc_init(void); ++static const struct file_operations arp_seq_fops; + +-void __init arp_init(void) ++static int arp_net_init(struct net *net) + { +- neigh_table_init(&arp_tbl); ++ struct ve_struct *ve = get_exec_env(); ++ int err; + +- dev_add_pack(&arp_packet_type); +- arp_proc_init(); ++ ve->ve_arp_tbl = kmemdup(ve0.ve_arp_tbl, sizeof(struct neigh_table), ++ GFP_KERNEL); ++ if (ve->ve_arp_tbl == NULL) ++ return -ENOMEM; ++ ++ ve->ve_arp_tbl->parms.tbl = ve->ve_arp_tbl; ++ err = neigh_table_init(ve->ve_arp_tbl); ++ if (err) ++ goto out_free; + #ifdef CONFIG_SYSCTL +- neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, ++ err = neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, + NET_IPV4_NEIGH, "ipv4", NULL, NULL); ++ if (err) ++ goto out_uninit; ++#endif ++ if (!proc_net_fops_create(net, "arp", S_IRUGO, &arp_seq_fops)) ++ goto out_deregister; ++ err = 0; ++out: ++ return err; ++ ++out_deregister: ++#ifdef CONFIG_SYSCTL ++ neigh_sysctl_unregister(&ve->ve_arp_tbl->parms); ++out_uninit: ++#endif ++ neigh_table_clear(ve->ve_arp_tbl); ++out_free: ++ kfree(ve->ve_arp_tbl); ++ ve->ve_arp_tbl = NULL; ++ goto out; ++} ++ ++static void arp_net_exit(struct net *net) ++{ ++ struct ve_struct *ve = get_exec_env(); ++ ++ proc_net_remove(net, "arp"); ++#ifdef CONFIG_SYSCTL ++ neigh_sysctl_unregister(&ve->ve_arp_tbl->parms); + #endif ++ neigh_table_clear(ve->ve_arp_tbl); ++ kfree(ve->ve_arp_tbl); ++ ve->ve_arp_tbl = NULL; ++} ++ ++static struct pernet_operations arp_net_ops = { ++ .init = arp_net_init, ++ .exit = arp_net_exit, ++}; ++ ++void __init arp_init(void) ++{ ++ get_ve0()->ve_arp_tbl = &global_arp_tbl; ++ register_pernet_subsys(&arp_net_ops); ++ dev_add_pack(&arp_packet_type); + register_netdevice_notifier(&arp_netdev_notifier); + } + +@@ -1370,21 +1417,6 @@ + .llseek = seq_lseek, + .release = seq_release_private, + }; +- +-static int __init arp_proc_init(void) +-{ +- if (!proc_net_fops_create(&init_net, "arp", S_IRUGO, &arp_seq_fops)) +- return -ENOMEM; +- return 0; +-} +- +-#else /* CONFIG_PROC_FS */ +- +-static int __init arp_proc_init(void) +-{ +- return 0; +-} +- + #endif /* CONFIG_PROC_FS */ + + EXPORT_SYMBOL(arp_broken_ops); +@@ -1392,7 +1424,7 @@ + EXPORT_SYMBOL(arp_create); + EXPORT_SYMBOL(arp_xmit); + EXPORT_SYMBOL(arp_send); +-EXPORT_SYMBOL(arp_tbl); ++EXPORT_SYMBOL(global_arp_tbl); + + #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) + EXPORT_SYMBOL(clip_tbl_hook); +Index: kernel/net/ipv4/devinet.c +=================================================================== +--- kernel.orig/net/ipv4/devinet.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/devinet.c 2008-11-24 15:47:46.000000000 +0100 +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -72,7 +73,7 @@ + }, + }; + +-static struct ipv4_devconf ipv4_devconf_dflt = { ++struct ipv4_devconf ipv4_devconf_dflt = { + .data = { + [NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1, + [NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1, +@@ -82,7 +83,7 @@ + }, + }; + +-#define IPV4_DEVCONF_DFLT(attr) IPV4_DEVCONF(ipv4_devconf_dflt, attr) ++#define IPV4_DEVCONF_DFLT(attr) IPV4_DEVCONF(ve_ipv4_devconf_dflt, attr) + + static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = { + [IFA_LOCAL] = { .type = NLA_U32 }, +@@ -94,8 +95,14 @@ + + static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); + ++#ifdef CONFIG_VE ++#define ve_ipv4_devconf_dflt (*(get_exec_env()->_ipv4_devconf_dflt)) ++#else ++#define ve_ipv4_devconf_dflt ipv4_devconf_dflt ++#endif ++ + static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); +-static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, ++void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, + int destroy); + #ifdef CONFIG_SYSCTL + static void devinet_sysctl_register(struct in_device *in_dev, +@@ -105,9 +112,9 @@ + + /* Locks all the inet devices. */ + +-static struct in_ifaddr *inet_alloc_ifa(void) ++struct in_ifaddr *inet_alloc_ifa(void) + { +- struct in_ifaddr *ifa = kzalloc(sizeof(*ifa), GFP_KERNEL); ++ struct in_ifaddr *ifa = kzalloc(sizeof(*ifa), GFP_KERNEL_UBC); + + if (ifa) { + INIT_RCU_HEAD(&ifa->rcu_head); +@@ -115,6 +122,7 @@ + + return ifa; + } ++EXPORT_SYMBOL_GPL(inet_alloc_ifa); + + static void inet_rcu_free_ifa(struct rcu_head *head) + { +@@ -147,7 +155,7 @@ + } + } + +-static struct in_device *inetdev_init(struct net_device *dev) ++struct in_device *inetdev_init(struct net_device *dev) + { + struct in_device *in_dev; + +@@ -188,6 +196,7 @@ + in_dev = NULL; + goto out; + } ++EXPORT_SYMBOL_GPL(inetdev_init); + + static void in_dev_rcu_put(struct rcu_head *head) + { +@@ -329,7 +338,7 @@ + inet_free_ifa(ifa1); + } + +-static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, ++void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, + int destroy) + { + __inet_del_ifa(in_dev, ifap, destroy, NULL, 0); +@@ -387,7 +396,7 @@ + return 0; + } + +-static int inet_insert_ifa(struct in_ifaddr *ifa) ++int inet_insert_ifa(struct in_ifaddr *ifa) + { + return __inet_insert_ifa(ifa, NULL, 0); + } +@@ -418,7 +427,7 @@ + struct net_device *dev; + struct in_device *in_dev = NULL; + read_lock(&dev_base_lock); +- dev = __dev_get_by_index(&init_net, ifindex); ++ dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifindex); + if (dev) + in_dev = in_dev_get(dev); + read_unlock(&dev_base_lock); +@@ -438,6 +447,7 @@ + } endfor_ifa(in_dev); + return NULL; + } ++EXPORT_SYMBOL_GPL(inet_insert_ifa); + + static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) + { +@@ -504,7 +514,7 @@ + goto errout; + } + +- dev = __dev_get_by_index(&init_net, ifm->ifa_index); ++ dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifm->ifa_index); + if (dev == NULL) { + err = -ENODEV; + goto errout; +@@ -608,6 +618,7 @@ + char *colon; + int ret = -EFAULT; + int tryaddrmatch = 0; ++ struct net *net = get_exec_env()->ve_ns->net_ns; + + /* + * Fetch the caller's info block into kernel space +@@ -625,7 +636,7 @@ + *colon = 0; + + #ifdef CONFIG_KMOD +- dev_load(&init_net, ifr.ifr_name); ++ dev_load(net, ifr.ifr_name); + #endif + + switch (cmd) { +@@ -644,7 +655,7 @@ + + case SIOCSIFFLAGS: + ret = -EACCES; +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_VE_NET_ADMIN)) + goto out; + break; + case SIOCSIFADDR: /* Set interface address (and family) */ +@@ -652,7 +663,7 @@ + case SIOCSIFDSTADDR: /* Set the destination address */ + case SIOCSIFNETMASK: /* Set the netmask for the interface */ + ret = -EACCES; +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_VE_NET_ADMIN)) + goto out; + ret = -EINVAL; + if (sin->sin_family != AF_INET) +@@ -666,7 +677,7 @@ + rtnl_lock(); + + ret = -ENODEV; +- if ((dev = __dev_get_by_name(&init_net, ifr.ifr_name)) == NULL) ++ if ((dev = __dev_get_by_name(net, ifr.ifr_name)) == NULL) + goto done; + + if (colon) +@@ -906,7 +917,7 @@ + */ + read_lock(&dev_base_lock); + rcu_read_lock(); +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { + if ((in_dev = __in_dev_get_rcu(dev)) == NULL) + continue; + +@@ -985,7 +996,7 @@ + + read_lock(&dev_base_lock); + rcu_read_lock(); +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { + if ((in_dev = __in_dev_get_rcu(dev))) { + addr = confirm_addr_indev(in_dev, dst, local, scope); + if (addr) +@@ -1048,9 +1059,6 @@ + struct net_device *dev = ptr; + struct in_device *in_dev = __in_dev_get_rtnl(dev); + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + ASSERT_RTNL(); + + if (!in_dev) { +@@ -1182,7 +1190,7 @@ + + s_ip_idx = ip_idx = cb->args[1]; + idx = 0; +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { + if (idx < s_idx) + goto cont; + if (idx > s_idx) +@@ -1241,7 +1249,7 @@ + struct net_device *dev; + + read_lock(&dev_base_lock); +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { + struct in_device *in_dev; + rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); +@@ -1326,11 +1334,10 @@ + struct net_device *dev; + int on = IPV4_DEVCONF_ALL(FORWARDING); + +- IPV4_DEVCONF_ALL(ACCEPT_REDIRECTS) = !on; + IPV4_DEVCONF_DFLT(FORWARDING) = on; + + read_lock(&dev_base_lock); +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { + struct in_device *in_dev; + rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); +@@ -1489,28 +1496,19 @@ + }, + }; + +-static void devinet_sysctl_register(struct in_device *in_dev, +- struct ipv4_devconf *p) ++static struct devinet_sysctl_table *__devinet_sysctl_register(char *dev_name, ++ int ifindex, struct ipv4_devconf *p) + { + int i; +- struct net_device *dev = in_dev ? in_dev->dev : NULL; +- struct devinet_sysctl_table *t = kmemdup(&devinet_sysctl, sizeof(*t), +- GFP_KERNEL); +- char *dev_name = NULL; ++ struct devinet_sysctl_table *t; + ++ t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL); + if (!t) +- return; ++ goto out; + for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) { + t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf; + t->devinet_vars[i].extra1 = p; +- } +- +- if (dev) { +- dev_name = dev->name; +- t->devinet_dev[0].ctl_name = dev->ifindex; +- } else { +- dev_name = "default"; +- t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT; ++ t->devinet_vars[i].owner_env = get_exec_env(); + } + + /* +@@ -1520,8 +1518,9 @@ + */ + dev_name = kstrdup(dev_name, GFP_KERNEL); + if (!dev_name) +- goto free; ++ goto out_free_table; + ++ t->devinet_dev[0].ctl_name = ifindex; + t->devinet_dev[0].procname = dev_name; + t->devinet_dev[0].child = t->devinet_vars; + t->devinet_conf_dir[0].child = t->devinet_dev; +@@ -1530,17 +1529,37 @@ + + t->sysctl_header = register_sysctl_table(t->devinet_root_dir); + if (!t->sysctl_header) +- goto free_procname; ++ goto out_free_procname; + +- p->sysctl = t; +- return; ++ return t; + + /* error path */ +- free_procname: ++out_free_procname: + kfree(dev_name); +- free: ++out_free_table: + kfree(t); +- return; ++out: ++ return NULL; ++} ++ ++static void devinet_sysctl_register(struct in_device *in_dev, ++ struct ipv4_devconf *p) ++{ ++ struct net_device *dev; ++ char *dev_name; ++ int ifindex; ++ ++ dev = in_dev ? in_dev->dev : NULL; ++ ++ if (dev) { ++ dev_name = dev->name; ++ ifindex = dev->ifindex; ++ } else { ++ dev_name = "default"; ++ ifindex = NET_PROTO_CONF_DEFAULT; ++ } ++ ++ p->sysctl = __devinet_sysctl_register(dev_name, ifindex, p); + } + + static void devinet_sysctl_unregister(struct ipv4_devconf *p) +@@ -1553,8 +1572,176 @@ + kfree(t); + } + } ++ ++#ifdef CONFIG_VE ++static ctl_table net_sysctl_tables[] = { ++ /* 0: net */ ++ { ++ .ctl_name = CTL_NET, ++ .procname = "net", ++ .mode = 0555, ++ .child = &net_sysctl_tables[2], ++ }, ++ { .ctl_name = 0, }, ++ /* 2: net/ipv4 */ ++ { ++ .ctl_name = NET_IPV4, ++ .procname = "ipv4", ++ .mode = 0555, ++ .child = &net_sysctl_tables[4], ++ }, ++ { .ctl_name = 0, }, ++ /* 4, 5: net/ipv4/[vars] */ ++ { ++ .ctl_name = NET_IPV4_FORWARD, ++ .procname = "ip_forward", ++ .data = &ipv4_devconf.data[NET_IPV4_CONF_FORWARDING-1], ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &ipv4_sysctl_forward, ++ .strategy = &ipv4_sysctl_forward_strategy, ++ }, ++ { ++ .ctl_name = NET_IPV4_ROUTE, ++ .procname = "route", ++ .maxlen = 0, ++ .mode = 0555, ++ .child = &net_sysctl_tables[7], ++ }, ++ { .ctl_name = 0 }, ++ /* 7: net/ipv4/route/flush */ ++ { ++ .ctl_name = NET_IPV4_ROUTE_FLUSH, ++ .procname = "flush", ++ .data = NULL, /* setuped below */ ++ .maxlen = sizeof(int), ++ .mode = 0200, ++ .proc_handler = &ipv4_sysctl_rtcache_flush, ++ .strategy = &ipv4_sysctl_rtcache_flush_strategy, ++ }, ++ { .ctl_name = 0 }, ++}; ++ ++static int ip_forward_sysctl_register(struct ve_struct *ve, ++ struct ipv4_devconf *p) ++{ ++ struct ctl_table_header *hdr; ++ ctl_table *root, *ipv4_table, *route_table; ++ ++ root = clone_sysctl_template(net_sysctl_tables); ++ if (root == NULL) ++ goto out; ++ ++ ipv4_table = root->child->child; ++ ipv4_table[0].data = &p->data[NET_IPV4_CONF_FORWARDING - 1]; ++ ++ route_table = ipv4_table[1].child; ++ route_table[0].data = &ipv4_flush_delay; ++ ++ hdr = register_sysctl_table(root); ++ if (hdr == NULL) ++ goto out_free; ++ ++ ve->forward_header = hdr; ++ ve->forward_table = root; ++ return 0; ++ ++out_free: ++ free_sysctl_clone(root); ++out: ++ return -ENOMEM; ++} ++ ++static inline void ip_forward_sysctl_unregister(struct ve_struct *ve) ++{ ++ unregister_sysctl_table(ve->forward_header); ++ ve->forward_header = NULL; ++} ++ ++static inline void ip_forward_sysctl_free(struct ve_struct *ve) ++{ ++ if (ve->forward_table == NULL) ++ return; ++ ++ free_sysctl_clone(ve->forward_table); ++ ve->forward_table = NULL; ++} ++#endif + #endif + ++int devinet_sysctl_init(struct ve_struct *ve) ++{ ++ int err = 0; ++#ifdef CONFIG_SYSCTL ++#ifdef CONFIG_VE ++ struct ipv4_devconf *conf, *conf_def; ++ ++ err = -ENOMEM; ++ ++ conf = kmalloc(sizeof(*conf), GFP_KERNEL); ++ if (!conf) ++ goto err1; ++ ++ memcpy(conf, &ipv4_devconf, sizeof(*conf)); ++ conf->sysctl = __devinet_sysctl_register("all", ++ NET_PROTO_CONF_ALL, conf); ++ if (!conf->sysctl) ++ goto err2; ++ ++ conf_def = kmalloc(sizeof(*conf_def), GFP_KERNEL); ++ if (!conf_def) ++ goto err3; ++ ++ memcpy(conf_def, &ipv4_devconf_dflt, sizeof(*conf_def)); ++ conf_def->sysctl = __devinet_sysctl_register("default", ++ NET_PROTO_CONF_DEFAULT, conf_def); ++ if (!conf_def->sysctl) ++ goto err4; ++ ++ err = ip_forward_sysctl_register(ve, conf); ++ if (err) ++ goto err5; ++ ++ ve->_ipv4_devconf = conf; ++ ve->_ipv4_devconf_dflt = conf_def; ++ return 0; ++ ++err5: ++ devinet_sysctl_unregister(conf_def); ++err4: ++ kfree(conf_def); ++err3: ++ devinet_sysctl_unregister(conf); ++err2: ++ kfree(conf); ++err1: ++#endif ++#endif ++ return err; ++} ++ ++void devinet_sysctl_fini(struct ve_struct *ve) ++{ ++#ifdef CONFIG_SYSCTL ++#ifdef CONFIG_VE ++ ip_forward_sysctl_unregister(ve); ++ devinet_sysctl_unregister(ve->_ipv4_devconf); ++ devinet_sysctl_unregister(ve->_ipv4_devconf_dflt); ++#endif ++#endif ++} ++ ++void devinet_sysctl_free(struct ve_struct *ve) ++{ ++#ifdef CONFIG_SYSCTL ++#ifdef CONFIG_VE ++ ip_forward_sysctl_free(ve); ++ kfree(ve->_ipv4_devconf); ++ kfree(ve->_ipv4_devconf_dflt); ++#endif ++#endif ++} ++ + void __init devinet_init(void) + { + register_gifconf(PF_INET, inet_gifconf); +@@ -1566,7 +1753,8 @@ + #ifdef CONFIG_SYSCTL + devinet_sysctl.sysctl_header = + register_sysctl_table(devinet_sysctl.devinet_root_dir); +- devinet_sysctl_register(NULL, &ipv4_devconf_dflt); ++ __devinet_sysctl_register("default", NET_PROTO_CONF_DEFAULT, ++ &ipv4_devconf_dflt); + #endif + } + +@@ -1575,3 +1763,7 @@ + EXPORT_SYMBOL(inetdev_by_index); + EXPORT_SYMBOL(register_inetaddr_notifier); + EXPORT_SYMBOL(unregister_inetaddr_notifier); ++EXPORT_SYMBOL(inet_del_ifa); ++EXPORT_SYMBOL(devinet_sysctl_init); ++EXPORT_SYMBOL(devinet_sysctl_fini); ++EXPORT_SYMBOL(devinet_sysctl_free); +Index: kernel/net/ipv4/fib_frontend.c +=================================================================== +--- kernel.orig/net/ipv4/fib_frontend.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/fib_frontend.c 2008-11-24 15:47:46.000000000 +0100 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -51,13 +52,18 @@ + + static struct sock *fibnl; + ++#ifdef CONFIG_VE ++#define fib_table_hash (get_exec_env()->_fib_table_hash) ++#else ++static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; ++#endif ++ + #ifndef CONFIG_IP_MULTIPLE_TABLES + +-struct fib_table *ip_fib_local_table; +-struct fib_table *ip_fib_main_table; ++struct fib_table *__ip_fib_local_table; ++struct fib_table *__ip_fib_main_table; + + #define FIB_TABLE_HASHSZ 1 +-static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; + + static void __init fib4_rules_init(void) + { +@@ -67,10 +73,10 @@ + hlist_add_head_rcu(&ip_fib_main_table->tb_hlist, &fib_table_hash[0]); + } + #else +- + #define FIB_TABLE_HASHSZ 256 +-static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; ++#endif + ++#ifdef CONFIG_IP_MULTIPLE_TABLES + struct fib_table *fib_new_table(u32 id) + { + struct fib_table *tb; +@@ -217,7 +223,8 @@ + + if (fib_lookup(&fl, &res)) + goto last_resort; +- if (res.type != RTN_UNICAST) ++ if (res.type != RTN_UNICAST && ++ (!(dev->features & NETIF_F_VENET) || res.type != RTN_LOCAL)) + goto e_inval_res; + *spec_dst = FIB_RES_PREFSRC(res); + fib_combine_itag(itag, &res); +@@ -345,7 +352,7 @@ + colon = strchr(devname, ':'); + if (colon) + *colon = 0; +- dev = __dev_get_by_name(&init_net, devname); ++ dev = __dev_get_by_name(get_exec_env()->ve_ns->net_ns, devname); + if (!dev) + return -ENODEV; + cfg->fc_oif = dev->ifindex; +@@ -418,7 +425,7 @@ + switch (cmd) { + case SIOCADDRT: /* Add a route */ + case SIOCDELRT: /* Delete a route */ +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_VE_NET_ADMIN)) + return -EPERM; + + if (copy_from_user(&rt, arg, sizeof(rt))) +@@ -869,9 +876,6 @@ + struct net_device *dev = ptr; + struct in_device *in_dev = __in_dev_get_rtnl(dev); + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + if (event == NETDEV_UNREGISTER) { + fib_disable_ip(dev, 2); + return NOTIFY_DONE; +Index: kernel/net/ipv4/fib_hash.c +=================================================================== +--- kernel.orig/net/ipv4/fib_hash.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/fib_hash.c 2008-11-24 15:47:46.000000000 +0100 +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -72,11 +73,6 @@ + * can be cheaper than memory lookup, so that FZ_* macros are used. + */ + +-struct fn_hash { +- struct fn_zone *fn_zones[33]; +- struct fn_zone *fn_zone_list; +-}; +- + static inline u32 fn_hash(__be32 key, struct fn_zone *fz) + { + u32 h = ntohl(key)>>(32 - fz->fz_order); +@@ -635,7 +631,7 @@ + return -ESRCH; + } + +-static int fn_flush_list(struct fn_zone *fz, int idx) ++static int fn_flush_list(struct fn_zone *fz, int idx, int destroy) + { + struct hlist_head *head = &fz->fz_hash[idx]; + struct hlist_node *node, *n; +@@ -650,7 +646,9 @@ + list_for_each_entry_safe(fa, fa_node, &f->fn_alias, fa_list) { + struct fib_info *fi = fa->fa_info; + +- if (fi && (fi->fib_flags&RTNH_F_DEAD)) { ++ if (fi == NULL) ++ continue; ++ if (destroy || (fi->fib_flags&RTNH_F_DEAD)) { + write_lock_bh(&fib_hash_lock); + list_del(&fa->fa_list); + if (list_empty(&f->fn_alias)) { +@@ -672,7 +670,7 @@ + return found; + } + +-static int fn_hash_flush(struct fib_table *tb) ++static int __fn_hash_flush(struct fib_table *tb, int destroy) + { + struct fn_hash *table = (struct fn_hash *) tb->tb_data; + struct fn_zone *fz; +@@ -682,11 +680,85 @@ + int i; + + for (i = fz->fz_divisor - 1; i >= 0; i--) +- found += fn_flush_list(fz, i); ++ found += fn_flush_list(fz, i, destroy); + } + return found; + } + ++static int fn_hash_flush(struct fib_table *tb) ++{ ++ return __fn_hash_flush(tb, 0); ++} ++ ++#ifdef CONFIG_VE ++static void fn_free_zones(struct fib_table *tb) ++{ ++ struct fn_hash *table = (struct fn_hash *) tb->tb_data; ++ struct fn_zone *fz; ++ ++ while ((fz = table->fn_zone_list) != NULL) { ++ table->fn_zone_list = fz->fz_next; ++ fz_hash_free(fz->fz_hash, fz->fz_divisor); ++ kfree(fz); ++ } ++} ++ ++void fib_hash_destroy(struct fib_table *tb) ++{ ++ __fn_hash_flush(tb, 1); ++ fn_free_zones(tb); ++ kfree(tb); ++} ++ ++/* ++ * Initialization of virtualized networking subsystem. ++ */ ++int init_ve_route(struct ve_struct *ve) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ve->_fib_table_hash); i++) ++ INIT_HLIST_HEAD(&ve->_fib_table_hash[i]); ++ ++#ifdef CONFIG_IP_MULTIPLE_TABLES ++ return fib_rules_create(); ++#else ++ ve->_local_table = fib_hash_init(RT_TABLE_LOCAL); ++ if (!ve->_local_table) ++ return -ENOMEM; ++ ve->_main_table = fib_hash_init(RT_TABLE_MAIN); ++ if (!ve->_main_table) { ++ fib_hash_destroy(ve->_local_table); ++ return -ENOMEM; ++ } ++ ++ hlist_add_head_rcu(&ve->_local_table->tb_hlist, ++ &ve->_fib_table_hash[0]); ++ hlist_add_head_rcu(&ve->_main_table->tb_hlist, ++ &ve->_fib_table_hash[0]); ++ return 0; ++#endif ++} ++ ++void fini_ve_route(struct ve_struct *ve) ++{ ++ unsigned int bytes; ++#ifdef CONFIG_IP_MULTIPLE_TABLES ++ fib_rules_destroy(); ++#else ++ fib_hash_destroy(ve->_local_table); ++ fib_hash_destroy(ve->_main_table); ++#endif ++ bytes = ve->_fib_hash_size * sizeof(struct hlist_head *); ++ fib_hash_free(ve->_fib_info_hash, bytes); ++ fib_hash_free(ve->_fib_info_laddrhash, bytes); ++ ve->_fib_info_hash = ve->_fib_info_laddrhash = NULL; ++} ++ ++EXPORT_SYMBOL(init_ve_route); ++EXPORT_SYMBOL(fini_ve_route); ++#endif ++ + + static inline int + fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb, +@@ -776,7 +848,7 @@ + return skb->len; + } + +-#ifdef CONFIG_IP_MULTIPLE_TABLES ++#if defined(CONFIG_IP_MULTIPLE_TABLES) || defined(CONFIG_VE) + struct fib_table * fib_hash_init(u32 id) + #else + struct fib_table * __init fib_hash_init(u32 id) +@@ -786,14 +858,14 @@ + + if (fn_hash_kmem == NULL) + fn_hash_kmem = kmem_cache_create("ip_fib_hash", +- sizeof(struct fib_node), +- 0, SLAB_HWCACHE_ALIGN, ++ sizeof(struct fib_node), 0, ++ SLAB_HWCACHE_ALIGN|SLAB_UBC, + NULL); + + if (fn_alias_kmem == NULL) + fn_alias_kmem = kmem_cache_create("ip_fib_alias", +- sizeof(struct fib_alias), +- 0, SLAB_HWCACHE_ALIGN, ++ sizeof(struct fib_alias), 0, ++ SLAB_HWCACHE_ALIGN|SLAB_UBC, + NULL); + + tb = kmalloc(sizeof(struct fib_table) + sizeof(struct fn_hash), +@@ -1067,13 +1139,28 @@ + .release = seq_release_private, + }; + +-int __init fib_proc_init(void) ++static int fib_proc_net_init(struct net *net) + { +- if (!proc_net_fops_create(&init_net, "route", S_IRUGO, &fib_seq_fops)) ++ if (!proc_net_fops_create(net, "route", S_IRUGO, &fib_seq_fops)) + return -ENOMEM; + return 0; + } + ++static void fib_proc_net_exit(struct net *net) ++{ ++ proc_net_remove(net, "route"); ++} ++ ++static struct pernet_operations fib_proc_net_ops = { ++ .init = fib_proc_net_init, ++ .exit = fib_proc_net_exit, ++}; ++ ++int __init fib_proc_init(void) ++{ ++ return register_pernet_subsys(&fib_proc_net_ops); ++} ++ + void __init fib_proc_exit(void) + { + proc_net_remove(&init_net, "route"); +Index: kernel/net/ipv4/fib_lookup.h +=================================================================== +--- kernel.orig/net/ipv4/fib_lookup.h 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/fib_lookup.h 2008-11-24 15:47:46.000000000 +0100 +@@ -37,5 +37,6 @@ + extern int fib_detect_death(struct fib_info *fi, int order, + struct fib_info **last_resort, + int *last_idx, int *dflt); ++void fib_hash_free(struct hlist_head *hash, int bytes); + + #endif /* _FIB_LOOKUP_H */ +Index: kernel/net/ipv4/fib_rules.c +=================================================================== +--- kernel.orig/net/ipv4/fib_rules.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/fib_rules.c 2008-11-24 15:47:46.000000000 +0100 +@@ -49,6 +49,85 @@ + #endif + }; + ++#ifdef CONFIG_VE ++#define local_rule (*(get_exec_env()->_local_rule)) ++#define fib4_rules (get_exec_env()->_fib_rules) ++#else ++#define local_rule loc_rule ++static LIST_HEAD(fib4_rules); ++#endif ++ ++#if defined(CONFIG_VE_CALLS) || defined(CONFIG_VE_CALLS_MODULE) ++#ifdef CONFIG_VE ++static inline void init_rule_struct(struct fib_rule *r, ++ u32 pref, unsigned char table, unsigned char action) ++{ ++ memset(r, 0, sizeof(struct fib_rule)); ++ atomic_set(&r->refcnt, 1); ++ r->pref = pref; ++ r->table = table; ++ r->action = action; ++} ++#endif ++ ++int fib_rules_create(void) ++{ ++#ifdef CONFIG_VE ++ struct fib_rule *default_rule, *main_rule, *loc_rule; ++ ++ default_rule = kmalloc(sizeof(struct fib_rule), GFP_KERNEL_UBC); ++ if (default_rule == NULL) ++ goto out_def; ++ ++ main_rule = kmalloc(sizeof(struct fib_rule), GFP_KERNEL_UBC); ++ if (main_rule == NULL) ++ goto out_main; ++ ++ loc_rule = kmalloc(sizeof(struct fib_rule), GFP_KERNEL_UBC); ++ if (loc_rule == NULL) ++ goto out_loc; ++ ++ init_rule_struct(default_rule, 0x7FFF, RT_TABLE_DEFAULT, RTN_UNICAST); ++ init_rule_struct(main_rule, 0x7FFE, RT_TABLE_MAIN, RTN_UNICAST); ++ init_rule_struct(loc_rule, 0, RT_TABLE_LOCAL, RTN_UNICAST); ++ ++ INIT_LIST_HEAD(&fib4_rules); ++ list_add_tail(&loc_rule->list, &fib4_rules); ++ list_add_tail(&main_rule->list, &fib4_rules); ++ list_add_tail(&default_rule->list, &fib4_rules); ++ get_exec_env()->_local_rule = loc_rule; ++ ++ return 0; ++ ++out_loc: ++ kfree(main_rule); ++out_main: ++ kfree(default_rule); ++out_def: ++ return -1; ++#else ++ return 0; ++#endif ++} ++ ++void fib_rules_destroy(void) ++{ ++#ifdef CONFIG_VE ++ struct fib_rule *r; ++ struct list_head *pos, *tmp; ++ ++ rtnl_lock(); ++ list_for_each_safe (pos, tmp, &fib4_rules) { ++ r = list_entry(pos, struct fib_rule, list); ++ ++ list_del_rcu(pos); ++ fib_rule_put(r); ++ } ++ rtnl_unlock(); ++#endif ++} ++#endif ++ + #ifdef CONFIG_NET_CLS_ROUTE + u32 fib_rules_tclass(struct fib_result *res) + { +Index: kernel/net/ipv4/fib_semantics.c +=================================================================== +--- kernel.orig/net/ipv4/fib_semantics.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/fib_semantics.c 2008-11-24 15:47:46.000000000 +0100 +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -32,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -55,6 +57,24 @@ + static unsigned int fib_hash_size; + static unsigned int fib_info_cnt; + ++void prepare_fib_info(void) ++{ ++#ifdef CONFIG_VE ++ get_ve0()->_fib_info_hash = fib_info_hash; ++ get_ve0()->_fib_info_laddrhash = fib_info_laddrhash; ++ get_ve0()->_fib_hash_size = fib_hash_size; ++ get_ve0()->_fib_info_cnt = fib_info_cnt; ++#endif ++} ++ ++#ifdef CONFIG_VE ++#define fib_info_hash (get_exec_env()->_fib_info_hash) ++#define fib_info_laddrhash (get_exec_env()->_fib_info_laddrhash) ++#define fib_hash_size (get_exec_env()->_fib_hash_size) ++#define fib_info_cnt (get_exec_env()->_fib_info_cnt) ++#endif ++ ++ + #define DEVINDEX_HASHBITS 8 + #define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS) + static struct hlist_head fib_info_devhash[DEVINDEX_HASHSIZE]; +@@ -234,13 +254,15 @@ + return NULL; + } + +-static inline unsigned int fib_devindex_hashfn(unsigned int val) ++static inline unsigned int fib_devindex_hashfn(unsigned int val, ++ envid_t veid) + { + unsigned int mask = DEVINDEX_HASHSIZE - 1; + + return (val ^ + (val >> DEVINDEX_HASHBITS) ^ +- (val >> (DEVINDEX_HASHBITS * 2))) & mask; ++ (val >> (DEVINDEX_HASHBITS * 2)) ^ ++ (veid ^ (veid >> 16))) & mask; + } + + /* Check, that the gateway is already configured. +@@ -256,7 +278,7 @@ + + spin_lock(&fib_info_lock); + +- hash = fib_devindex_hashfn(dev->ifindex); ++ hash = fib_devindex_hashfn(dev->ifindex, VEID(dev->owner_env)); + head = &fib_info_devhash[hash]; + hlist_for_each_entry(nh, node, head, nh_hash) { + if (nh->nh_dev == dev && +@@ -533,7 +555,7 @@ + return -EINVAL; + if (inet_addr_type(nh->nh_gw) != RTN_UNICAST) + return -EINVAL; +- if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL) ++ if ((dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, nh->nh_oif)) == NULL) + return -ENODEV; + if (!(dev->flags&IFF_UP)) + return -ENETDOWN; +@@ -611,7 +633,7 @@ + __get_free_pages(GFP_KERNEL, get_order(bytes)); + } + +-static void fib_hash_free(struct hlist_head *hash, int bytes) ++void fib_hash_free(struct hlist_head *hash, int bytes) + { + if (!hash) + return; +@@ -799,7 +821,7 @@ + if (nhs != 1 || nh->nh_gw) + goto err_inval; + nh->nh_scope = RT_SCOPE_NOWHERE; +- nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif); ++ nh->nh_dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, fi->fib_nh->nh_oif); + err = -ENODEV; + if (nh->nh_dev == NULL) + goto failure; +@@ -842,7 +864,8 @@ + + if (!nh->nh_dev) + continue; +- hash = fib_devindex_hashfn(nh->nh_dev->ifindex); ++ hash = fib_devindex_hashfn(nh->nh_dev->ifindex, ++ VEID(nh->nh_dev->owner_env)); + head = &fib_info_devhash[hash]; + hlist_add_head(&nh->nh_hash, head); + } endfor_nexthops(fi) +@@ -1054,7 +1077,8 @@ + + if (dev) { + struct fib_info *prev_fi = NULL; +- unsigned int hash = fib_devindex_hashfn(dev->ifindex); ++ unsigned int hash = fib_devindex_hashfn(dev->ifindex, ++ VEID(dev->owner_env)); + struct hlist_head *head = &fib_info_devhash[hash]; + struct hlist_node *node; + struct fib_nh *nh; +@@ -1119,7 +1143,7 @@ + return 0; + + prev_fi = NULL; +- hash = fib_devindex_hashfn(dev->ifindex); ++ hash = fib_devindex_hashfn(dev->ifindex, VEID(dev->owner_env)); + head = &fib_info_devhash[hash]; + ret = 0; + +Index: kernel/net/ipv4/icmp.c +=================================================================== +--- kernel.orig/net/ipv4/icmp.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/icmp.c 2008-11-24 15:47:46.000000000 +0100 +@@ -69,6 +69,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -513,7 +514,7 @@ + struct net_device *dev = NULL; + + if (rt->fl.iif && sysctl_icmp_errors_use_inbound_ifaddr) +- dev = dev_get_by_index(&init_net, rt->fl.iif); ++ dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, rt->fl.iif); + + if (dev) { + saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK); +Index: kernel/net/ipv4/igmp.c +=================================================================== +--- kernel.orig/net/ipv4/igmp.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/igmp.c 2008-11-24 15:47:46.000000000 +0100 +@@ -83,6 +83,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2291,8 +2292,9 @@ + struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); + + state->in_dev = NULL; +- for_each_netdev(&init_net, state->dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, state->dev) { + struct in_device *in_dev; ++ + in_dev = in_dev_get(state->dev); + if (!in_dev) + continue; +@@ -2438,8 +2440,9 @@ + + state->idev = NULL; + state->im = NULL; +- for_each_netdev(&init_net, state->dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, state->dev) { + struct in_device *idev; ++ + idev = in_dev_get(state->dev); + if (unlikely(idev == NULL)) + continue; +@@ -2581,11 +2584,34 @@ + .release = seq_release_private, + }; + +-int __init igmp_mc_proc_init(void) ++static int igmp_net_init(struct net *net) + { +- proc_net_fops_create(&init_net, "igmp", S_IRUGO, &igmp_mc_seq_fops); +- proc_net_fops_create(&init_net, "mcfilter", S_IRUGO, &igmp_mcf_seq_fops); ++ if (!proc_net_fops_create(net, "igmp", S_IRUGO, &igmp_mc_seq_fops)) ++ goto out_igmp; ++ if (!proc_net_fops_create(net, "mcfilter", S_IRUGO, &igmp_mcf_seq_fops)) ++ goto out_mcfilter; + return 0; ++ ++out_mcfilter: ++ proc_net_remove(net, "igmp"); ++out_igmp: ++ return -ENOMEM; ++} ++ ++static void igmp_net_exit(struct net *net) ++{ ++ proc_net_remove(net, "igmp"); ++ proc_net_remove(net, "mcfilter"); ++} ++ ++static struct pernet_operations igmp_net_ops = { ++ .init = igmp_net_init, ++ .exit = igmp_net_exit, ++}; ++ ++int __init igmp_mc_proc_init(void) ++{ ++ return register_pernet_subsys(&igmp_net_ops); + } + #endif + +Index: kernel/net/ipv4/inet_connection_sock.c +=================================================================== +--- kernel.orig/net/ipv4/inet_connection_sock.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/inet_connection_sock.c 2008-11-24 15:47:46.000000000 +0100 +@@ -24,6 +24,9 @@ + #include + #include + ++#include ++#include ++ + #ifdef INET_CSK_DEBUG + const char inet_csk_timer_bug_msg[] = "inet_csk BUG: unknown timer value\n"; + EXPORT_SYMBOL(inet_csk_timer_bug_msg); +@@ -58,6 +61,7 @@ + sk_for_each_bound(sk2, node, &tb->owners) { + if (sk != sk2 && + !inet_v6_ipv6only(sk2) && ++ ve_accessible_strict(sk->owner_env, sk2->owner_env) && + (!sk->sk_bound_dev_if || + !sk2->sk_bound_dev_if || + sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { +@@ -87,7 +91,9 @@ + struct hlist_node *node; + struct inet_bind_bucket *tb; + int ret; ++ struct ve_struct *env; + ++ env = sk->owner_env; + local_bh_disable(); + if (!snum) { + int remaining, rover, low, high; +@@ -97,11 +103,15 @@ + rover = net_random() % remaining + low; + + do { +- head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)]; ++ head = &hashinfo->bhash[inet_bhashfn(rover, ++ hashinfo->bhash_size, VEID(env))]; + spin_lock(&head->lock); +- inet_bind_bucket_for_each(tb, node, &head->chain) ++ inet_bind_bucket_for_each(tb, node, &head->chain) { ++ if (!ve_accessible_strict(tb->owner_env, env)) ++ continue; + if (tb->port == rover) + goto next; ++ } + break; + next: + spin_unlock(&head->lock); +@@ -124,11 +134,15 @@ + */ + snum = rover; + } else { +- head = &hashinfo->bhash[inet_bhashfn(snum, hashinfo->bhash_size)]; ++ head = &hashinfo->bhash[inet_bhashfn(snum, ++ hashinfo->bhash_size, VEID(env))]; + spin_lock(&head->lock); +- inet_bind_bucket_for_each(tb, node, &head->chain) ++ inet_bind_bucket_for_each(tb, node, &head->chain) { ++ if (!ve_accessible_strict(tb->owner_env, env)) ++ continue; + if (tb->port == snum) + goto tb_found; ++ } + } + tb = NULL; + goto tb_not_found; +@@ -147,7 +161,7 @@ + } + tb_not_found: + ret = 1; +- if (!tb && (tb = inet_bind_bucket_create(hashinfo->bind_bucket_cachep, head, snum)) == NULL) ++ if (!tb && (tb = inet_bind_bucket_create(hashinfo->bind_bucket_cachep, head, snum, env)) == NULL) + goto fail_unlock; + if (hlist_empty(&tb->owners)) { + if (sk->sk_reuse && sk->sk_state != TCP_LISTEN) +@@ -555,7 +569,7 @@ + + sk_refcnt_debug_release(sk); + +- atomic_dec(sk->sk_prot->orphan_count); ++ ub_dec_orphan_count(sk); + sock_put(sk); + } + +@@ -635,7 +649,7 @@ + + sock_orphan(child); + +- atomic_inc(sk->sk_prot->orphan_count); ++ ub_inc_orphan_count(sk); + + inet_csk_destroy_sock(child); + +Index: kernel/net/ipv4/inet_diag.c +=================================================================== +--- kernel.orig/net/ipv4/inet_diag.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/inet_diag.c 2008-11-24 15:47:46.000000000 +0100 +@@ -708,7 +708,9 @@ + struct inet_diag_req *r = NLMSG_DATA(cb->nlh); + const struct inet_diag_handler *handler; + struct inet_hashinfo *hashinfo; ++ struct ve_struct *ve; + ++ ve = get_exec_env(); + handler = inet_diag_lock_handler(cb->nlh->nlmsg_type); + if (IS_ERR(handler)) + goto unlock; +@@ -731,6 +733,8 @@ + sk_for_each(sk, node, &hashinfo->listening_hash[i]) { + struct inet_sock *inet = inet_sk(sk); + ++ if (!ve_accessible(sk->owner_env, ve)) ++ continue; + if (num < s_num) { + num++; + continue; +@@ -792,6 +796,8 @@ + sk_for_each(sk, node, &head->chain) { + struct inet_sock *inet = inet_sk(sk); + ++ if (!ve_accessible(sk->owner_env, ve)) ++ continue; + if (num < s_num) + goto next_normal; + if (!(r->idiag_states & (1 << sk->sk_state))) +@@ -816,6 +822,8 @@ + inet_twsk_for_each(tw, node, + &head->twchain) { + ++ if (!ve_accessible_veid(tw->tw_owner_env, VEID(ve))) ++ continue; + if (num < s_num) + goto next_dying; + if (r->id.idiag_sport != tw->tw_sport && +Index: kernel/net/ipv4/inet_fragment.c +=================================================================== +--- kernel.orig/net/ipv4/inet_fragment.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/inet_fragment.c 2008-11-24 15:47:46.000000000 +0100 +@@ -224,7 +224,9 @@ + setup_timer(&q->timer, f->frag_expire, (unsigned long)q); + spin_lock_init(&q->lock); + atomic_set(&q->refcnt, 1); +- ++#ifdef CONFIG_VE ++ q->owner_ve = get_exec_env(); ++#endif + return q; + } + +Index: kernel/net/ipv4/inet_hashtables.c +=================================================================== +--- kernel.orig/net/ipv4/inet_hashtables.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/inet_hashtables.c 2008-11-24 15:47:46.000000000 +0100 +@@ -29,7 +29,8 @@ + */ + struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep, + struct inet_bind_hashbucket *head, +- const unsigned short snum) ++ const unsigned short snum, ++ struct ve_struct *ve) + { + struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, GFP_ATOMIC); + +@@ -37,6 +38,7 @@ + tb->port = snum; + tb->fastreuse = 0; + INIT_HLIST_HEAD(&tb->owners); ++ tb->owner_env = ve; + hlist_add_head(&tb->node, &head->chain); + } + return tb; +@@ -66,10 +68,13 @@ + */ + static void __inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk) + { +- const int bhash = inet_bhashfn(inet_sk(sk)->num, hashinfo->bhash_size); +- struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash]; ++ int bhash; ++ struct inet_bind_hashbucket *head; + struct inet_bind_bucket *tb; + ++ bhash = inet_bhashfn(inet_sk(sk)->num, hashinfo->bhash_size, ++ VEID(sk->owner_env)); ++ head = &hashinfo->bhash[bhash]; + spin_lock(&head->lock); + tb = inet_csk(sk)->icsk_bind_hash; + __sk_del_bind_node(sk); +@@ -132,10 +137,14 @@ + struct sock *result = NULL, *sk; + const struct hlist_node *node; + int hiscore = -1; ++ struct ve_struct *env; + ++ env = get_exec_env(); + sk_for_each(sk, node, head) { + const struct inet_sock *inet = inet_sk(sk); + ++ if (!ve_accessible_strict(sk->owner_env, env)) ++ continue; + if (inet->num == hnum && !ipv6_only_sock(sk)) { + const __be32 rcv_saddr = inet->rcv_saddr; + int score = sk->sk_family == PF_INET ? 1 : 0; +@@ -168,13 +177,16 @@ + { + struct sock *sk = NULL; + const struct hlist_head *head; ++ struct ve_struct *env; + ++ env = get_exec_env(); + read_lock(&hashinfo->lhash_lock); +- head = &hashinfo->listening_hash[inet_lhashfn(hnum)]; ++ head = &hashinfo->listening_hash[inet_lhashfn(hnum, VEID(env))]; + if (!hlist_empty(head)) { + const struct inet_sock *inet = inet_sk((sk = __sk_head(head))); + + if (inet->num == hnum && !sk->sk_node.next && ++ ve_accessible_strict(sk->owner_env, env) && + (!inet->rcv_saddr || inet->rcv_saddr == daddr) && + (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) && + !sk->sk_bound_dev_if) +@@ -193,7 +205,8 @@ + /* called with local bh disabled */ + static int __inet_check_established(struct inet_timewait_death_row *death_row, + struct sock *sk, __u16 lport, +- struct inet_timewait_sock **twp) ++ struct inet_timewait_sock **twp, ++ struct ve_struct *ve) + { + struct inet_hashinfo *hinfo = death_row->hashinfo; + struct inet_sock *inet = inet_sk(sk); +@@ -202,7 +215,7 @@ + int dif = sk->sk_bound_dev_if; + INET_ADDR_COOKIE(acookie, saddr, daddr) + const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport); +- unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport); ++ unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport, VEID(ve)); + struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); + rwlock_t *lock = inet_ehash_lockp(hinfo, hash); + struct sock *sk2; +@@ -216,7 +229,8 @@ + sk_for_each(sk2, node, &head->twchain) { + tw = inet_twsk(sk2); + +- if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) { ++ if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ++ ports, dif, ve)) { + if (twsk_unique(sk, sk2, twp)) + goto unique; + else +@@ -227,7 +241,8 @@ + + /* And established part... */ + sk_for_each(sk2, node, &head->chain) { +- if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) ++ if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ++ ports, dif, ve)) + goto not_unique; + } + +@@ -278,7 +293,9 @@ + struct inet_bind_hashbucket *head; + struct inet_bind_bucket *tb; + int ret; ++ struct ve_struct *ve; + ++ ve = sk->owner_env; + if (!snum) { + int i, remaining, low, high, port; + static u32 hint; +@@ -292,7 +309,7 @@ + local_bh_disable(); + for (i = 1; i <= remaining; i++) { + port = low + (i + offset) % remaining; +- head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)]; ++ head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size, VEID(ve))]; + spin_lock(&head->lock); + + /* Does not bother with rcv_saddr checks, +@@ -300,19 +317,21 @@ + * unique enough. + */ + inet_bind_bucket_for_each(tb, node, &head->chain) { +- if (tb->port == port) { ++ if (tb->port == port && ++ ve_accessible_strict(tb->owner_env, ve)) { + BUG_TRAP(!hlist_empty(&tb->owners)); + if (tb->fastreuse >= 0) + goto next_port; + if (!__inet_check_established(death_row, + sk, port, +- &tw)) ++ &tw, ve)) + goto ok; + goto next_port; + } + } + +- tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, head, port); ++ tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, ++ head, port, ve); + if (!tb) { + spin_unlock(&head->lock); + break; +@@ -320,7 +339,7 @@ + tb->fastreuse = -1; + goto ok; + +- next_port: ++ next_port: + spin_unlock(&head->lock); + } + local_bh_enable(); +@@ -347,7 +366,7 @@ + goto out; + } + +- head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size)]; ++ head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size, VEID(ve))]; + tb = inet_csk(sk)->icsk_bind_hash; + spin_lock_bh(&head->lock); + if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { +@@ -357,7 +376,7 @@ + } else { + spin_unlock(&head->lock); + /* No definite answer... Walk to established hash table */ +- ret = __inet_check_established(death_row, sk, snum, NULL); ++ ret = __inet_check_established(death_row, sk, snum, NULL, ve); + out: + local_bh_enable(); + return ret; +Index: kernel/net/ipv4/inet_timewait_sock.c +=================================================================== +--- kernel.orig/net/ipv4/inet_timewait_sock.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/inet_timewait_sock.c 2008-11-24 15:47:46.000000000 +0100 +@@ -13,6 +13,8 @@ + #include + #include + ++#include ++ + /* Must be called with locally disabled BHs. */ + static void __inet_twsk_kill(struct inet_timewait_sock *tw, + struct inet_hashinfo *hashinfo) +@@ -32,7 +34,8 @@ + write_unlock(lock); + + /* Disassociate with bind bucket. */ +- bhead = &hashinfo->bhash[inet_bhashfn(tw->tw_num, hashinfo->bhash_size)]; ++ bhead = &hashinfo->bhash[inet_bhashfn(tw->tw_num, ++ hashinfo->bhash_size, tw->tw_owner_env)]; + spin_lock(&bhead->lock); + tb = tw->tw_tb; + __hlist_del(&tw->tw_bind_node); +@@ -65,7 +68,8 @@ + Note, that any socket with inet->num != 0 MUST be bound in + binding cache, even if it is closed. + */ +- bhead = &hashinfo->bhash[inet_bhashfn(inet->num, hashinfo->bhash_size)]; ++ bhead = &hashinfo->bhash[inet_bhashfn(inet->num, ++ hashinfo->bhash_size, tw->tw_owner_env)]; + spin_lock(&bhead->lock); + tw->tw_tb = icsk->icsk_bind_hash; + BUG_TRAP(icsk->icsk_bind_hash); +@@ -89,9 +93,14 @@ + + struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int state) + { +- struct inet_timewait_sock *tw = +- kmem_cache_alloc(sk->sk_prot_creator->twsk_prot->twsk_slab, +- GFP_ATOMIC); ++ struct user_beancounter *ub; ++ struct inet_timewait_sock *tw; ++ ++ ub = set_exec_ub(sock_bc(sk)->ub); ++ tw = kmem_cache_alloc(sk->sk_prot_creator->twsk_prot->twsk_slab, ++ GFP_ATOMIC); ++ (void)set_exec_ub(ub); ++ + if (tw != NULL) { + const struct inet_sock *inet = inet_sk(sk); + +@@ -139,6 +148,7 @@ + rescan: + inet_twsk_for_each_inmate(tw, node, &twdr->cells[slot]) { + __inet_twsk_del_dead_node(tw); ++ ub_timewait_dec(tw, twdr); + spin_unlock(&twdr->death_lock); + __inet_twsk_kill(tw, twdr->hashinfo); + inet_twsk_put(tw); +@@ -237,6 +247,7 @@ + { + spin_lock(&twdr->death_lock); + if (inet_twsk_del_dead_node(tw)) { ++ ub_timewait_dec(tw, twdr); + inet_twsk_put(tw); + if (--twdr->tw_count == 0) + del_timer(&twdr->tw_timer); +@@ -283,9 +294,10 @@ + spin_lock(&twdr->death_lock); + + /* Unlink it, if it was scheduled */ +- if (inet_twsk_del_dead_node(tw)) ++ if (inet_twsk_del_dead_node(tw)) { ++ ub_timewait_dec(tw, twdr); + twdr->tw_count--; +- else ++ } else + atomic_inc(&tw->tw_refcnt); + + if (slot >= INET_TWDR_RECYCLE_SLOTS) { +@@ -321,6 +333,7 @@ + + hlist_add_head(&tw->tw_death_node, list); + ++ ub_timewait_inc(tw, twdr); + if (twdr->tw_count++ == 0) + mod_timer(&twdr->tw_timer, jiffies + twdr->period); + spin_unlock(&twdr->death_lock); +@@ -355,6 +368,7 @@ + &twdr->twcal_row[slot]) { + __inet_twsk_del_dead_node(tw); + __inet_twsk_kill(tw, twdr->hashinfo); ++ ub_timewait_dec(tw, twdr); + inet_twsk_put(tw); + killed++; + } +Index: kernel/net/ipv4/ip_forward.c +=================================================================== +--- kernel.orig/net/ipv4/ip_forward.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/ip_forward.c 2008-11-24 15:47:46.000000000 +0100 +@@ -93,6 +93,24 @@ + goto drop; + } + ++ /* ++ * We try to optimize forwarding of VE packets: ++ * do not decrement TTL (and so save skb_cow) ++ * during forwarding of outgoing pkts from VE. ++ * For incoming pkts we still do ttl decr, ++ * since such skb is not cloned and does not require ++ * actual cow. So, there is at least one place ++ * in pkts path with mandatory ttl decr, that is ++ * sufficient to prevent routing loops. ++ */ ++ iph = ip_hdr(skb); ++ if ( ++#ifdef CONFIG_IP_ROUTE_NAT ++ (rt->rt_flags & RTCF_NAT) == 0 && /* no NAT mangling expected */ ++#endif /* and */ ++ (skb->dev->features & NETIF_F_VENET)) /* src is VENET device */ ++ goto no_ttl_decr; ++ + /* We are about to mangle packet. Copy it! */ + if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+rt->u.dst.header_len)) + goto drop; +@@ -101,6 +119,8 @@ + /* Decrease ttl after skb cow done */ + ip_decrease_ttl(iph); + ++no_ttl_decr: ++ + /* + * We now generate an ICMP HOST REDIRECT giving the route + * we calculated. +Index: kernel/net/ipv4/ip_fragment.c +=================================================================== +--- kernel.orig/net/ipv4/ip_fragment.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/ip_fragment.c 2008-11-24 15:47:46.000000000 +0100 +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -138,7 +139,8 @@ + qp->saddr == arg->iph->saddr && + qp->daddr == arg->iph->daddr && + qp->protocol == arg->iph->protocol && +- qp->user == arg->user); ++ qp->user == arg->user && ++ q->owner_ve == get_exec_env()); + } + + /* Memory Tracking Functions. */ +@@ -206,9 +208,12 @@ + */ + static void ip_expire(unsigned long arg) + { ++ struct inet_frag_queue *q = (struct inet_frag_queue *)arg; + struct ipq *qp; ++ struct ve_struct *old_ve; + +- qp = container_of((struct inet_frag_queue *) arg, struct ipq, q); ++ qp = container_of(q, struct ipq, q); ++ old_ve = set_exec_env(q->owner_ve); + + spin_lock(&qp->q.lock); + +@@ -223,7 +228,7 @@ + if ((qp->q.last_in&FIRST_IN) && qp->q.fragments != NULL) { + struct sk_buff *head = qp->q.fragments; + /* Send an ICMP "Fragment Reassembly Timeout" message. */ +- if ((head->dev = dev_get_by_index(&init_net, qp->iif)) != NULL) { ++ if ((head->dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, qp->iif)) != NULL) { + icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); + dev_put(head->dev); + } +@@ -231,6 +236,8 @@ + out: + spin_unlock(&qp->q.lock); + ipq_put(qp); ++ ++ (void)set_exec_env(old_ve); + } + + /* Find the correct entry in the "incomplete datagrams" queue for +@@ -535,6 +542,7 @@ + clone->csum = 0; + clone->ip_summed = head->ip_summed; + atomic_add(clone->truesize, &ip4_frags.mem); ++ clone->owner_env = head->owner_env; + } + + skb_shinfo(head)->frag_list = head->next; +@@ -607,6 +615,49 @@ + return -ENOMEM; + } + ++#ifdef CONFIG_VE ++/* XXX */ ++void ip_fragment_cleanup(struct ve_struct *ve) ++{ ++ int i, progress; ++ ++ /* All operations with fragment queues are performed from NET_RX/TX ++ * soft interrupts or from timer context. --Den */ ++ local_bh_disable(); ++ do { ++ progress = 0; ++ for (i = 0; i < INETFRAGS_HASHSZ; i++) { ++ struct ipq *qp; ++ struct hlist_node *p, *n; ++ ++ if (hlist_empty(&ip4_frags.hash[i])) ++ continue; ++inner_restart: ++ read_lock(&ip4_frags.lock); ++ hlist_for_each_entry_safe(qp, p, n, ++ &ip4_frags.hash[i], q.list) { ++ if (!ve_accessible_strict(qp->q.owner_ve, ve)) ++ continue; ++ atomic_inc(&qp->q.refcnt); ++ read_unlock(&ip4_frags.lock); ++ ++ spin_lock(&qp->q.lock); ++ if (!(qp->q.last_in & COMPLETE)) ++ ipq_kill(qp); ++ spin_unlock(&qp->q.lock); ++ ++ ipq_put(qp); ++ progress = 1; ++ goto inner_restart; ++ } ++ read_unlock(&ip4_frags.lock); ++ } ++ } while (progress); ++ local_bh_enable(); ++} ++EXPORT_SYMBOL(ip_fragment_cleanup); ++#endif ++ + void __init ipfrag_init(void) + { + ip4_frags.ctl = &ip4_frags_ctl; +Index: kernel/net/ipv4/ip_gre.c +=================================================================== +--- kernel.orig/net/ipv4/ip_gre.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/ip_gre.c 2008-11-24 15:47:46.000000000 +0100 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -262,7 +263,7 @@ + int i; + for (i=1; i<100; i++) { + sprintf(name, "gre%d", i); +- if (__dev_get_by_name(&init_net, name) == NULL) ++ if (__dev_get_by_name(get_exec_env()->ve_ns->net_ns, name) == NULL) + break; + } + if (i==100) +@@ -1210,7 +1211,7 @@ + } + + if (!tdev && tunnel->parms.link) +- tdev = __dev_get_by_index(&init_net, tunnel->parms.link); ++ tdev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, tunnel->parms.link); + + if (tdev) { + hlen = tdev->hard_header_len; +Index: kernel/net/ipv4/ip_input.c +=================================================================== +--- kernel.orig/net/ipv4/ip_input.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/ip_input.c 2008-11-24 15:47:46.000000000 +0100 +@@ -197,6 +197,8 @@ + + static int ip_local_deliver_finish(struct sk_buff *skb) + { ++ if (skb->destructor) ++ skb_orphan(skb); + __skb_pull(skb, ip_hdrlen(skb)); + + /* Point into the IP datagram, just past the header. */ +@@ -380,9 +382,6 @@ + struct iphdr *iph; + u32 len; + +- if (dev->nd_net != &init_net) +- goto drop; +- + /* When the interface is in promisc. mode, drop all the crap + * that it receives, do not try to analyse it. + */ +Index: kernel/net/ipv4/ip_output.c +=================================================================== +--- kernel.orig/net/ipv4/ip_output.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/ip_output.c 2008-11-24 15:47:46.000000000 +0100 +@@ -1344,12 +1344,13 @@ + char data[40]; + } replyopts; + struct ipcm_cookie ipc; +- __be32 daddr; ++ __be32 saddr, daddr; + struct rtable *rt = (struct rtable*)skb->dst; + + if (ip_options_echo(&replyopts.opt, skb)) + return; + ++ saddr = ip_hdr(skb)->daddr; + daddr = ipc.addr = rt->rt_src; + ipc.opt = NULL; + +@@ -1364,7 +1365,7 @@ + struct flowi fl = { .oif = arg->bound_dev_if, + .nl_u = { .ip4_u = + { .daddr = daddr, +- .saddr = rt->rt_spec_dst, ++ .saddr = saddr, + .tos = RT_TOS(ip_hdr(skb)->tos) } }, + /* Not quite clean, but right. */ + .uli_u = { .ports = +Index: kernel/net/ipv4/ip_sockglue.c +=================================================================== +--- kernel.orig/net/ipv4/ip_sockglue.c 2008-11-24 14:14:31.000000000 +0100 ++++ kernel/net/ipv4/ip_sockglue.c 2008-11-24 15:47:46.000000000 +0100 +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -595,7 +596,7 @@ + dev_put(dev); + } + } else +- dev = __dev_get_by_index(&init_net, mreq.imr_ifindex); ++ dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, mreq.imr_ifindex); + + + err = -EADDRNOTAVAIL; +Index: kernel/net/ipv4/ipconfig.c +=================================================================== +--- kernel.orig/net/ipv4/ipconfig.c 2008-11-24 14:14:32.000000000 +0100 ++++ kernel/net/ipv4/ipconfig.c 2008-11-24 15:47:46.000000000 +0100 +@@ -185,19 +185,20 @@ + struct ic_device *d, **last; + struct net_device *dev; + unsigned short oflags; ++ struct net *net = get_exec_env()->ve_ns->net_ns; + + last = &ic_first_dev; + rtnl_lock(); + + /* bring loopback device up first */ +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(net, dev) { + if (!(dev->flags & IFF_LOOPBACK)) + continue; + if (dev_change_flags(dev, dev->flags | IFF_UP) < 0) + printk(KERN_ERR "IP-Config: Failed to open %s\n", dev->name); + } + +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(net, dev) { + if (dev->flags & IFF_LOOPBACK) + continue; + if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) : +@@ -430,9 +431,6 @@ + unsigned char *sha, *tha; /* s for "source", t for "target" */ + struct ic_device *d; + +- if (dev->nd_net != &init_net) +- goto drop; +- + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) + return NET_RX_DROP; + +@@ -842,9 +840,6 @@ + struct ic_device *d; + int len, ext_len; + +- if (dev->nd_net != &init_net) +- goto drop; +- + /* Perform verifications before taking the lock. */ + if (skb->pkt_type == PACKET_OTHERHOST) + goto drop; +Index: kernel/net/ipv4/ipip.c +=================================================================== +--- kernel.orig/net/ipv4/ipip.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/ipip.c 2008-11-24 15:47:46.000000000 +0100 +@@ -100,6 +100,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -225,7 +226,7 @@ + int i; + for (i=1; i<100; i++) { + sprintf(name, "tunl%d", i); +- if (__dev_get_by_name(&init_net, name) == NULL) ++ if (__dev_get_by_name(get_exec_env()->ve_ns->net_ns, name) == NULL) + break; + } + if (i==100) +@@ -820,7 +821,7 @@ + } + + if (!tdev && tunnel->parms.link) +- tdev = __dev_get_by_index(&init_net, tunnel->parms.link); ++ tdev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, tunnel->parms.link); + + if (tdev) { + dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); +Index: kernel/net/ipv4/ipmr.c +=================================================================== +--- kernel.orig/net/ipv4/ipmr.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/ipmr.c 2008-11-24 15:47:46.000000000 +0100 +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -123,9 +124,10 @@ + static + struct net_device *ipmr_new_tunnel(struct vifctl *v) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + struct net_device *dev; + +- dev = __dev_get_by_name(&init_net, "tunl0"); ++ dev = __dev_get_by_name(net, "tunl0"); + + if (dev) { + int err; +@@ -149,7 +151,7 @@ + + dev = NULL; + +- if (err == 0 && (dev = __dev_get_by_name(&init_net, p.name)) != NULL) { ++ if (err == 0 && (dev = __dev_get_by_name(net, p.name)) != NULL) { + dev->flags |= IFF_MULTICAST; + + in_dev = __in_dev_get_rtnl(dev); +@@ -1087,9 +1089,6 @@ + struct vif_device *v; + int ct; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + if (event != NETDEV_UNREGISTER) + return NOTIFY_DONE; + v=&vif_table[0]; +Index: kernel/net/ipv4/ipvs/ip_vs_conn.c +=================================================================== +--- kernel.orig/net/ipv4/ipvs/ip_vs_conn.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/ipvs/ip_vs_conn.c 2008-11-24 15:47:46.000000000 +0100 +@@ -920,7 +920,7 @@ + /* Allocate ip_vs_conn slab cache */ + ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn", + sizeof(struct ip_vs_conn), 0, +- SLAB_HWCACHE_ALIGN, NULL); ++ SLAB_HWCACHE_ALIGN|SLAB_UBC, NULL); + if (!ip_vs_conn_cachep) { + vfree(ip_vs_conn_tab); + return -ENOMEM; +Index: kernel/net/ipv4/ipvs/ip_vs_core.c +=================================================================== +--- kernel.orig/net/ipv4/ipvs/ip_vs_core.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/ipvs/ip_vs_core.c 2008-11-24 15:47:46.000000000 +0100 +@@ -909,6 +909,10 @@ + * Big tappo: only PACKET_HOST (neither loopback nor mcasts) + * ... don't know why 1st test DOES NOT include 2nd (?) + */ ++ /* ++ * VZ: the question above is right. ++ * The second test is superfluous. ++ */ + if (unlikely(skb->pkt_type != PACKET_HOST + || skb->dev->flags & IFF_LOOPBACK || skb->sk)) { + IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n", +Index: kernel/net/ipv4/ipvs/ip_vs_sync.c +=================================================================== +--- kernel.orig/net/ipv4/ipvs/ip_vs_sync.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/ipvs/ip_vs_sync.c 2008-11-24 15:47:46.000000000 +0100 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -404,7 +405,7 @@ + struct net_device *dev; + struct inet_sock *inet = inet_sk(sk); + +- if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL) ++ if ((dev = __dev_get_by_name(get_exec_env()->ve_ns->net_ns, ifname)) == NULL) + return -ENODEV; + + if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) +@@ -425,11 +426,12 @@ + */ + static int set_sync_mesg_maxlen(int sync_state) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + struct net_device *dev; + int num; + + if (sync_state == IP_VS_STATE_MASTER) { +- if ((dev = __dev_get_by_name(&init_net, ip_vs_master_mcast_ifn)) == NULL) ++ if ((dev = __dev_get_by_name(net, ip_vs_master_mcast_ifn)) == NULL) + return -ENODEV; + + num = (dev->mtu - sizeof(struct iphdr) - +@@ -440,7 +442,7 @@ + IP_VS_DBG(7, "setting the maximum length of sync sending " + "message %d.\n", sync_send_mesg_maxlen); + } else if (sync_state == IP_VS_STATE_BACKUP) { +- if ((dev = __dev_get_by_name(&init_net, ip_vs_backup_mcast_ifn)) == NULL) ++ if ((dev = __dev_get_by_name(net, ip_vs_backup_mcast_ifn)) == NULL) + return -ENODEV; + + sync_recv_mesg_maxlen = dev->mtu - +@@ -468,7 +470,7 @@ + memset(&mreq, 0, sizeof(mreq)); + memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr)); + +- if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL) ++ if ((dev = __dev_get_by_name(get_exec_env()->ve_ns->net_ns, ifname)) == NULL) + return -ENODEV; + if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) + return -EINVAL; +@@ -489,7 +491,7 @@ + __be32 addr; + struct sockaddr_in sin; + +- if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL) ++ if ((dev = __dev_get_by_name(get_exec_env()->ve_ns->net_ns, ifname)) == NULL) + return -ENODEV; + + addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); +Index: kernel/net/ipv4/netfilter/ip_queue.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/ip_queue.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/ip_queue.c 2008-11-24 15:47:46.000000000 +0100 +@@ -502,7 +502,7 @@ + if (type <= IPQM_BASE) + return; + +- if (security_netlink_recv(skb, CAP_NET_ADMIN)) ++ if (security_netlink_recv(skb, CAP_VE_NET_ADMIN)) + RCV_SKB_FAIL(-EPERM); + + write_lock_bh(&queue_lock); +@@ -532,8 +532,12 @@ + static void + ipq_rcv_skb(struct sk_buff *skb) + { ++ struct ve_struct *old_ve; ++ + mutex_lock(&ipqnl_mutex); ++ old_ve = set_exec_env(skb->owner_env); + __ipq_rcv_skb(skb); ++ (void)set_exec_env(old_ve); + mutex_unlock(&ipqnl_mutex); + } + +@@ -543,9 +547,6 @@ + { + struct net_device *dev = ptr; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + /* Drop any packets associated with the downed device */ + if (event == NETDEV_DOWN) + ipq_dev_drop(dev->ifindex); +@@ -565,7 +566,7 @@ + if (event == NETLINK_URELEASE && + n->protocol == NETLINK_FIREWALL && n->pid) { + write_lock_bh(&queue_lock); +- if ((n->net == &init_net) && (n->pid == peer_pid)) ++ if (n->pid == peer_pid) + __ipq_reset(); + write_unlock_bh(&queue_lock); + } +Index: kernel/net/ipv4/netfilter/ip_tables.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/ip_tables.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/ip_tables.c 2008-11-24 15:47:46.000000000 +0100 +@@ -23,9 +23,11 @@ + #include + #include + #include ++#include + + #include + #include ++#include + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Netfilter Core Team "); +@@ -482,8 +484,8 @@ + int visited = e->comefrom & (1 << hook); + + if (e->comefrom & (1 << NF_IP_NUMHOOKS)) { +- printk("iptables: loop hook %u pos %u %08X.\n", +- hook, pos, e->comefrom); ++ ve_printk(VE_LOG, "iptables: loop hook %u pos " ++ "%u %08X.\n", hook, pos, e->comefrom); + return 0; + } + e->comefrom +@@ -504,6 +506,13 @@ + return 0; + } + ++ if (t->verdict < -NF_MAX_VERDICT - 1) { ++ duprintf("mark_source_chains: bad " ++ "negative verdict (%i)\n", ++ t->verdict); ++ return 0; ++ } ++ + /* Return: backtrack through the last + big jump. */ + do { +@@ -925,7 +934,7 @@ + (other than comefrom, which userspace doesn't care + about). */ + countersize = sizeof(struct xt_counters) * private->number; +- counters = vmalloc_node(countersize, numa_node_id()); ++ counters = ub_vmalloc_node(countersize, numa_node_id()); + + if (counters == NULL) + return ERR_PTR(-ENOMEM); +@@ -1254,7 +1263,7 @@ + void *loc_cpu_old_entry; + + ret = 0; +- counters = vmalloc(num_counters * sizeof(struct xt_counters)); ++ counters = ub_vmalloc_best(num_counters * sizeof(struct xt_counters)); + if (!counters) { + ret = -ENOMEM; + goto out; +@@ -1433,7 +1442,7 @@ + if (len != size + num_counters * sizeof(struct xt_counters)) + return -EINVAL; + +- paddc = vmalloc_node(len - size, numa_node_id()); ++ paddc = ub_vmalloc_node(len - size, numa_node_id()); + if (!paddc) + return -ENOMEM; + +@@ -1778,18 +1787,18 @@ + } + + /* Check hooks all assigned */ +- for (i = 0; i < NF_IP_NUMHOOKS; i++) { ++ for (j = 0; j < NF_IP_NUMHOOKS; j++) { + /* Only hooks which are valid */ +- if (!(valid_hooks & (1 << i))) ++ if (!(valid_hooks & (1 << j))) + continue; +- if (info->hook_entry[i] == 0xFFFFFFFF) { ++ if (info->hook_entry[j] == 0xFFFFFFFF) { + duprintf("Invalid hook entry %u %u\n", +- i, hook_entries[i]); ++ j, hook_entries[j]); + goto out_unlock; + } +- if (info->underflow[i] == 0xFFFFFFFF) { ++ if (info->underflow[j] == 0xFFFFFFFF) { + duprintf("Invalid underflow %u %u\n", +- i, underflows[i]); ++ j, underflows[j]); + goto out_unlock; + } + } +@@ -1800,9 +1809,9 @@ + goto out_unlock; + + newinfo->number = number; +- for (i = 0; i < NF_IP_NUMHOOKS; i++) { +- newinfo->hook_entry[i] = info->hook_entry[i]; +- newinfo->underflow[i] = info->underflow[i]; ++ for (j = 0; j < NF_IP_NUMHOOKS; j++) { ++ newinfo->hook_entry[j] = info->hook_entry[j]; ++ newinfo->underflow[j] = info->underflow[j]; + } + entry1 = newinfo->entries[raw_smp_processor_id()]; + pos = entry1; +@@ -1908,15 +1917,22 @@ + return ret; + } + ++static int do_ipt_set_ctl(struct sock *, int, void __user *, unsigned int); ++ + static int + compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, + unsigned int len) + { + int ret; + +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_NET_ADMIN) && !capable(CAP_VE_NET_ADMIN)) + return -EPERM; + ++#ifdef CONFIG_VE_IPTABLES ++ if (!get_exec_env()->_xt_tables[AF_INET].next) ++ return -ENOENT; ++#endif ++ + switch (cmd) { + case IPT_SO_SET_REPLACE: + ret = compat_do_replace(user, len); +@@ -1927,8 +1943,7 @@ + break; + + default: +- duprintf("do_ipt_set_ctl: unknown request %i\n", cmd); +- ret = -EINVAL; ++ ret = do_ipt_set_ctl(sk, cmd, user, len); + } + + return ret; +@@ -2029,9 +2044,14 @@ + { + int ret; + +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_NET_ADMIN) && !capable(CAP_VE_NET_ADMIN)) + return -EPERM; + ++#ifdef CONFIG_VE_IPTABLES ++ if (!get_exec_env()->_xt_tables[AF_INET].next) ++ return -ENOENT; ++#endif ++ + switch (cmd) { + case IPT_SO_GET_INFO: + ret = get_info(user, len, 1); +@@ -2051,9 +2071,14 @@ + { + int ret; + +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_NET_ADMIN) && !capable(CAP_VE_NET_ADMIN)) + return -EPERM; + ++#ifdef CONFIG_VE_IPTABLES ++ if (!get_exec_env()->_xt_tables[AF_INET].next) ++ return -ENOENT; ++#endif ++ + switch (cmd) { + case IPT_SO_SET_REPLACE: + ret = do_replace(user, len); +@@ -2076,9 +2101,14 @@ + { + int ret; + +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_NET_ADMIN) && !capable(CAP_VE_NET_ADMIN)) + return -EPERM; + ++#ifdef CONFIG_VE_IPTABLES ++ if (!get_exec_env()->_xt_tables[AF_INET].next) ++ return -ENOENT; ++#endif ++ + switch (cmd) { + case IPT_SO_GET_INFO: + ret = get_info(user, len, 0); +@@ -2122,17 +2152,18 @@ + return ret; + } + +-int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl) ++struct xt_table *ipt_register_table(struct xt_table *table, ++ const struct ipt_replace *repl) + { + int ret; + struct xt_table_info *newinfo; + static struct xt_table_info bootstrap +- = { 0, 0, 0, { 0 }, { 0 }, { } }; ++ = { 0, 0, 0, 0, { 0 }, { 0 }, { } }; + void *loc_cpu_entry; + + newinfo = xt_alloc_table_info(repl->size); + if (!newinfo) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); + + /* choose the copy on our node/cpu + * but dont care of preemption +@@ -2147,28 +2178,30 @@ + repl->underflow); + if (ret != 0) { + xt_free_table_info(newinfo); +- return ret; ++ return ERR_PTR(ret); + } + +- ret = xt_register_table(table, &bootstrap, newinfo); +- if (ret != 0) { ++ table = virt_xt_register_table(table, &bootstrap, newinfo); ++ if (IS_ERR(table)) + xt_free_table_info(newinfo); +- return ret; +- } + +- return 0; ++ return table; + } + + void ipt_unregister_table(struct xt_table *table) + { + struct xt_table_info *private; + void *loc_cpu_entry; ++ struct module *me; + +- private = xt_unregister_table(table); ++ me = table->me; ++ private = virt_xt_unregister_table(table); + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries[raw_smp_processor_id()]; + IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL); ++ if (private->number > private->initial_entries) ++ module_put(me); + xt_free_table_info(private); + } + +@@ -2275,12 +2308,30 @@ + .checkentry = icmp_checkentry, + }; + ++static int init_iptables(void) ++{ ++#ifdef CONFIG_VE_IPTABLES ++ if (get_exec_env()->_xt_tables[AF_INET].next != NULL) ++ return -EEXIST; ++#endif ++ ++ return xt_proto_init(AF_INET); ++} ++ ++static void fini_iptables(void) ++{ ++#ifdef CONFIG_VE_IPTABLES ++ get_exec_env()->_xt_tables[AF_INET].next = NULL; ++#endif ++ xt_proto_fini(AF_INET); ++} ++ + static int __init ip_tables_init(void) + { + int ret; + +- ret = xt_proto_init(AF_INET); +- if (ret < 0) ++ ret = init_iptables(); ++ if (ret) + goto err1; + + /* Noone else will be downing sem now, so we won't sleep */ +@@ -2299,6 +2350,10 @@ + if (ret < 0) + goto err5; + ++ KSYMRESOLVE(init_iptables); ++ KSYMRESOLVE(fini_iptables); ++ KSYMMODRESOLVE(ip_tables); ++ + printk(KERN_INFO "ip_tables: (C) 2000-2006 Netfilter Core Team\n"); + return 0; + +@@ -2309,24 +2364,25 @@ + err3: + xt_unregister_target(&ipt_standard_target); + err2: +- xt_proto_fini(AF_INET); ++ fini_iptables(); + err1: + return ret; + } + + static void __exit ip_tables_fini(void) + { ++ KSYMMODUNRESOLVE(ip_tables); ++ KSYMUNRESOLVE(init_iptables); ++ KSYMUNRESOLVE(fini_iptables); + nf_unregister_sockopt(&ipt_sockopts); +- + xt_unregister_match(&icmp_matchstruct); + xt_unregister_target(&ipt_error_target); + xt_unregister_target(&ipt_standard_target); +- +- xt_proto_fini(AF_INET); ++ fini_iptables(); + } + + EXPORT_SYMBOL(ipt_register_table); + EXPORT_SYMBOL(ipt_unregister_table); + EXPORT_SYMBOL(ipt_do_table); +-module_init(ip_tables_init); ++subsys_initcall(ip_tables_init); + module_exit(ip_tables_fini); +Index: kernel/net/ipv4/netfilter/ipt_CLUSTERIP.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/ipt_CLUSTERIP.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/ipt_CLUSTERIP.c 2008-11-24 15:47:46.000000000 +0100 +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -401,7 +402,7 @@ + return false; + } + +- dev = dev_get_by_name(&init_net, e->ip.iniface); ++ dev = dev_get_by_name(get_exec_env()->ve_ns->net_ns, e->ip.iniface); + if (!dev) { + printk(KERN_WARNING "CLUSTERIP: no such interface %s\n", e->ip.iniface); + return false; +Index: kernel/net/ipv4/netfilter/ipt_LOG.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/ipt_LOG.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/ipt_LOG.c 2008-11-24 15:47:46.000000000 +0100 +@@ -46,32 +46,32 @@ + + ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); + if (ih == NULL) { +- printk("TRUNCATED"); ++ ve_printk(VE_LOG, "TRUNCATED"); + return; + } + + /* Important fields: + * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ + /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ +- printk("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ", ++ ve_printk(VE_LOG, "SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ", + NIPQUAD(ih->saddr), NIPQUAD(ih->daddr)); + + /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ +- printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", ++ ve_printk(VE_LOG, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", + ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, + ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); + + /* Max length: 6 "CE DF MF " */ + if (ntohs(ih->frag_off) & IP_CE) +- printk("CE "); ++ ve_printk(VE_LOG, "CE "); + if (ntohs(ih->frag_off) & IP_DF) +- printk("DF "); ++ ve_printk(VE_LOG, "DF "); + if (ntohs(ih->frag_off) & IP_MF) +- printk("MF "); ++ ve_printk(VE_LOG, "MF "); + + /* Max length: 11 "FRAG:65535 " */ + if (ntohs(ih->frag_off) & IP_OFFSET) +- printk("FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); ++ ve_printk(VE_LOG, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); + + if ((logflags & IPT_LOG_IPOPT) + && ih->ihl * 4 > sizeof(struct iphdr)) { +@@ -82,15 +82,15 @@ + op = skb_header_pointer(skb, iphoff+sizeof(_iph), + optsize, _opt); + if (op == NULL) { +- printk("TRUNCATED"); ++ ve_printk(VE_LOG, "TRUNCATED"); + return; + } + + /* Max length: 127 "OPT (" 15*4*2chars ") " */ +- printk("OPT ("); ++ ve_printk(VE_LOG, "OPT ("); + for (i = 0; i < optsize; i++) +- printk("%02X", op[i]); +- printk(") "); ++ ve_printk(VE_LOG, "%02X", op[i]); ++ ve_printk(VE_LOG, ") "); + } + + switch (ih->protocol) { +@@ -99,7 +99,7 @@ + const struct tcphdr *th; + + /* Max length: 10 "PROTO=TCP " */ +- printk("PROTO=TCP "); ++ ve_printk(VE_LOG, "PROTO=TCP "); + + if (ntohs(ih->frag_off) & IP_OFFSET) + break; +@@ -108,41 +108,41 @@ + th = skb_header_pointer(skb, iphoff + ih->ihl * 4, + sizeof(_tcph), &_tcph); + if (th == NULL) { +- printk("INCOMPLETE [%u bytes] ", ++ ve_printk(VE_LOG, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + /* Max length: 20 "SPT=65535 DPT=65535 " */ +- printk("SPT=%u DPT=%u ", ++ ve_printk(VE_LOG, "SPT=%u DPT=%u ", + ntohs(th->source), ntohs(th->dest)); + /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ + if (logflags & IPT_LOG_TCPSEQ) +- printk("SEQ=%u ACK=%u ", ++ ve_printk(VE_LOG, "SEQ=%u ACK=%u ", + ntohl(th->seq), ntohl(th->ack_seq)); + /* Max length: 13 "WINDOW=65535 " */ +- printk("WINDOW=%u ", ntohs(th->window)); ++ ve_printk(VE_LOG, "WINDOW=%u ", ntohs(th->window)); + /* Max length: 9 "RES=0x3F " */ +- printk("RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); ++ ve_printk(VE_LOG, "RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); + /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ + if (th->cwr) +- printk("CWR "); ++ ve_printk(VE_LOG, "CWR "); + if (th->ece) +- printk("ECE "); ++ ve_printk(VE_LOG, "ECE "); + if (th->urg) +- printk("URG "); ++ ve_printk(VE_LOG, "URG "); + if (th->ack) +- printk("ACK "); ++ ve_printk(VE_LOG, "ACK "); + if (th->psh) +- printk("PSH "); ++ ve_printk(VE_LOG, "PSH "); + if (th->rst) +- printk("RST "); ++ ve_printk(VE_LOG, "RST "); + if (th->syn) +- printk("SYN "); ++ ve_printk(VE_LOG, "SYN "); + if (th->fin) +- printk("FIN "); ++ ve_printk(VE_LOG, "FIN "); + /* Max length: 11 "URGP=65535 " */ +- printk("URGP=%u ", ntohs(th->urg_ptr)); ++ ve_printk(VE_LOG, "URGP=%u ", ntohs(th->urg_ptr)); + + if ((logflags & IPT_LOG_TCPOPT) + && th->doff * 4 > sizeof(struct tcphdr)) { +@@ -155,15 +155,15 @@ + iphoff+ih->ihl*4+sizeof(_tcph), + optsize, _opt); + if (op == NULL) { +- printk("TRUNCATED"); ++ ve_printk(VE_LOG, "TRUNCATED"); + return; + } + + /* Max length: 127 "OPT (" 15*4*2chars ") " */ +- printk("OPT ("); ++ ve_printk(VE_LOG, "OPT ("); + for (i = 0; i < optsize; i++) +- printk("%02X", op[i]); +- printk(") "); ++ ve_printk(VE_LOG, "%02X", op[i]); ++ ve_printk(VE_LOG, ") "); + } + break; + } +@@ -174,9 +174,9 @@ + + if (ih->protocol == IPPROTO_UDP) + /* Max length: 10 "PROTO=UDP " */ +- printk("PROTO=UDP " ); ++ ve_printk(VE_LOG, "PROTO=UDP " ); + else /* Max length: 14 "PROTO=UDPLITE " */ +- printk("PROTO=UDPLITE "); ++ ve_printk(VE_LOG, "PROTO=UDPLITE "); + + if (ntohs(ih->frag_off) & IP_OFFSET) + break; +@@ -185,13 +185,13 @@ + uh = skb_header_pointer(skb, iphoff+ih->ihl*4, + sizeof(_udph), &_udph); + if (uh == NULL) { +- printk("INCOMPLETE [%u bytes] ", ++ ve_printk(VE_LOG, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + /* Max length: 20 "SPT=65535 DPT=65535 " */ +- printk("SPT=%u DPT=%u LEN=%u ", ++ ve_printk(VE_LOG, "SPT=%u DPT=%u LEN=%u ", + ntohs(uh->source), ntohs(uh->dest), + ntohs(uh->len)); + break; +@@ -218,7 +218,7 @@ + [ICMP_ADDRESSREPLY] = 12 }; + + /* Max length: 11 "PROTO=ICMP " */ +- printk("PROTO=ICMP "); ++ ve_printk(VE_LOG, "PROTO=ICMP "); + + if (ntohs(ih->frag_off) & IP_OFFSET) + break; +@@ -227,19 +227,19 @@ + ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, + sizeof(_icmph), &_icmph); + if (ich == NULL) { +- printk("INCOMPLETE [%u bytes] ", ++ ve_printk(VE_LOG, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + /* Max length: 18 "TYPE=255 CODE=255 " */ +- printk("TYPE=%u CODE=%u ", ich->type, ich->code); ++ ve_printk(VE_LOG, "TYPE=%u CODE=%u ", ich->type, ich->code); + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + if (ich->type <= NR_ICMP_TYPES + && required_len[ich->type] + && skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { +- printk("INCOMPLETE [%u bytes] ", ++ ve_printk(VE_LOG, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } +@@ -248,19 +248,19 @@ + case ICMP_ECHOREPLY: + case ICMP_ECHO: + /* Max length: 19 "ID=65535 SEQ=65535 " */ +- printk("ID=%u SEQ=%u ", ++ ve_printk(VE_LOG, "ID=%u SEQ=%u ", + ntohs(ich->un.echo.id), + ntohs(ich->un.echo.sequence)); + break; + + case ICMP_PARAMETERPROB: + /* Max length: 14 "PARAMETER=255 " */ +- printk("PARAMETER=%u ", ++ ve_printk(VE_LOG, "PARAMETER=%u ", + ntohl(ich->un.gateway) >> 24); + break; + case ICMP_REDIRECT: + /* Max length: 24 "GATEWAY=255.255.255.255 " */ +- printk("GATEWAY=%u.%u.%u.%u ", ++ ve_printk(VE_LOG, "GATEWAY=%u.%u.%u.%u ", + NIPQUAD(ich->un.gateway)); + /* Fall through */ + case ICMP_DEST_UNREACH: +@@ -268,16 +268,16 @@ + case ICMP_TIME_EXCEEDED: + /* Max length: 3+maxlen */ + if (!iphoff) { /* Only recurse once. */ +- printk("["); ++ ve_printk(VE_LOG, "["); + dump_packet(info, skb, + iphoff + ih->ihl*4+sizeof(_icmph)); +- printk("] "); ++ ve_printk(VE_LOG, "] "); + } + + /* Max length: 10 "MTU=65535 " */ + if (ich->type == ICMP_DEST_UNREACH + && ich->code == ICMP_FRAG_NEEDED) +- printk("MTU=%u ", ntohs(ich->un.frag.mtu)); ++ ve_printk(VE_LOG, "MTU=%u ", ntohs(ich->un.frag.mtu)); + } + break; + } +@@ -290,19 +290,19 @@ + break; + + /* Max length: 9 "PROTO=AH " */ +- printk("PROTO=AH "); ++ ve_printk(VE_LOG, "PROTO=AH "); + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + ah = skb_header_pointer(skb, iphoff+ih->ihl*4, + sizeof(_ahdr), &_ahdr); + if (ah == NULL) { +- printk("INCOMPLETE [%u bytes] ", ++ ve_printk(VE_LOG, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + /* Length: 15 "SPI=0xF1234567 " */ +- printk("SPI=0x%x ", ntohl(ah->spi)); ++ ve_printk(VE_LOG, "SPI=0x%x ", ntohl(ah->spi)); + break; + } + case IPPROTO_ESP: { +@@ -310,7 +310,7 @@ + const struct ip_esp_hdr *eh; + + /* Max length: 10 "PROTO=ESP " */ +- printk("PROTO=ESP "); ++ ve_printk(VE_LOG, "PROTO=ESP "); + + if (ntohs(ih->frag_off) & IP_OFFSET) + break; +@@ -319,25 +319,25 @@ + eh = skb_header_pointer(skb, iphoff+ih->ihl*4, + sizeof(_esph), &_esph); + if (eh == NULL) { +- printk("INCOMPLETE [%u bytes] ", ++ ve_printk(VE_LOG, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + /* Length: 15 "SPI=0xF1234567 " */ +- printk("SPI=0x%x ", ntohl(eh->spi)); ++ ve_printk(VE_LOG, "SPI=0x%x ", ntohl(eh->spi)); + break; + } + /* Max length: 10 "PROTO 255 " */ + default: +- printk("PROTO=%u ", ih->protocol); ++ ve_printk(VE_LOG, "PROTO=%u ", ih->protocol); + } + + /* Max length: 15 "UID=4294967295 " */ + if ((logflags & IPT_LOG_UID) && !iphoff && skb->sk) { + read_lock_bh(&skb->sk->sk_callback_lock); + if (skb->sk->sk_socket && skb->sk->sk_socket->file) +- printk("UID=%u ", skb->sk->sk_socket->file->f_uid); ++ ve_printk(VE_LOG, "UID=%u ", skb->sk->sk_socket->file->f_uid); + read_unlock_bh(&skb->sk->sk_callback_lock); + } + +@@ -379,7 +379,7 @@ + loginfo = &default_loginfo; + + spin_lock_bh(&log_lock); +- printk("<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, ++ ve_printk(VE_LOG, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, + prefix, + in ? in->name : "", + out ? out->name : ""); +@@ -390,30 +390,30 @@ + + physindev = skb->nf_bridge->physindev; + if (physindev && in != physindev) +- printk("PHYSIN=%s ", physindev->name); ++ ve_printk(VE_LOG, "PHYSIN=%s ", physindev->name); + physoutdev = skb->nf_bridge->physoutdev; + if (physoutdev && out != physoutdev) +- printk("PHYSOUT=%s ", physoutdev->name); ++ ve_printk(VE_LOG, "PHYSOUT=%s ", physoutdev->name); + } + #endif + + if (in && !out) { + /* MAC logging for input chain only. */ +- printk("MAC="); ++ ve_printk(VE_LOG, "MAC="); + if (skb->dev && skb->dev->hard_header_len + && skb->mac_header != skb->network_header) { + int i; + const unsigned char *p = skb_mac_header(skb); + for (i = 0; i < skb->dev->hard_header_len; i++,p++) +- printk("%02x%c", *p, ++ ve_printk(VE_LOG, "%02x%c", *p, + i==skb->dev->hard_header_len - 1 + ? ' ':':'); + } else +- printk(" "); ++ ve_printk(VE_LOG, " "); + } + + dump_packet(loginfo, skb, 0); +- printk("\n"); ++ ve_printk(VE_LOG, "\n"); + spin_unlock_bh(&log_lock); + } + +Index: kernel/net/ipv4/netfilter/ipt_MASQUERADE.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/ipt_MASQUERADE.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/ipt_MASQUERADE.c 2008-11-24 15:47:46.000000000 +0100 +@@ -103,6 +103,7 @@ + return nf_nat_setup_info(ct, &newrange, hooknum); + } + ++#if 0 + static int + device_cmp(struct nf_conn *i, void *ifindex) + { +@@ -125,9 +126,6 @@ + { + const struct net_device *dev = ptr; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + if (event == NETDEV_DOWN) { + /* Device was downed. Search entire table for + conntracks which were associated with that device, +@@ -165,6 +163,7 @@ + static struct notifier_block masq_inet_notifier = { + .notifier_call = masq_inet_event, + }; ++#endif + + static struct xt_target masquerade __read_mostly = { + .name = "MASQUERADE", +@@ -183,12 +182,16 @@ + + ret = xt_register_target(&masquerade); + ++#if 0 ++/* These notifiers are unnecessary and may ++ lead to oops in virtual environments */ + if (ret == 0) { + /* Register for device down reports */ + register_netdevice_notifier(&masq_dev_notifier); + /* Register IP address change reports */ + register_inetaddr_notifier(&masq_inet_notifier); + } ++#endif + + return ret; + } +@@ -196,8 +199,8 @@ + static void __exit ipt_masquerade_fini(void) + { + xt_unregister_target(&masquerade); +- unregister_netdevice_notifier(&masq_dev_notifier); +- unregister_inetaddr_notifier(&masq_inet_notifier); ++/* unregister_netdevice_notifier(&masq_dev_notifier); ++ unregister_inetaddr_notifier(&masq_inet_notifier);*/ + } + + module_init(ipt_masquerade_init); +Index: kernel/net/ipv4/netfilter/ipt_REDIRECT.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/ipt_REDIRECT.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/ipt_REDIRECT.c 2008-11-24 15:47:46.000000000 +0100 +@@ -77,8 +77,13 @@ + + rcu_read_lock(); + indev = __in_dev_get_rcu(skb->dev); +- if (indev && (ifa = indev->ifa_list)) ++ if (indev && (ifa = indev->ifa_list)) { ++ /* because of venet device specific, we should use ++ * second ifa in the list */ ++ if (IN_LOOPBACK(ntohl(ifa->ifa_local)) && ifa->ifa_next) ++ ifa = ifa->ifa_next; + newdst = ifa->ifa_local; ++ } + rcu_read_unlock(); + + if (!newdst) +Index: kernel/net/ipv4/netfilter/ipt_REJECT.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/ipt_REJECT.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/ipt_REJECT.c 2008-11-24 15:47:46.000000000 +0100 +@@ -221,13 +221,13 @@ + const struct ipt_entry *e = e_void; + + if (rejinfo->with == IPT_ICMP_ECHOREPLY) { +- printk("ipt_REJECT: ECHOREPLY no longer supported.\n"); ++ ve_printk(VE_LOG, "ipt_REJECT: ECHOREPLY no longer supported.\n"); + return false; + } else if (rejinfo->with == IPT_TCP_RESET) { + /* Must specify that it's a TCP packet */ + if (e->ip.proto != IPPROTO_TCP + || (e->ip.invflags & XT_INV_PROTO)) { +- printk("ipt_REJECT: TCP_RESET invalid for non-tcp\n"); ++ ve_printk(VE_LOG, "ipt_REJECT: TCP_RESET invalid for non-tcp\n"); + return false; + } + } +Index: kernel/net/ipv4/netfilter/ipt_TOS.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/ipt_TOS.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/ipt_TOS.c 2008-11-24 15:47:46.000000000 +0100 +@@ -57,7 +57,7 @@ + && tos != IPTOS_RELIABILITY + && tos != IPTOS_MINCOST + && tos != IPTOS_NORMALSVC) { +- printk(KERN_WARNING "TOS: bad tos value %#x\n", tos); ++ ve_printk(VE_LOG, KERN_WARNING "TOS: bad tos value %#x\n", tos); + return false; + } + return true; +Index: kernel/net/ipv4/netfilter/ipt_recent.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/ipt_recent.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/ipt_recent.c 2008-11-24 15:47:46.000000000 +0100 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -52,6 +53,19 @@ + MODULE_PARM_DESC(ip_list_uid,"owner of /proc/net/ipt_recent/* files"); + MODULE_PARM_DESC(ip_list_gid,"owning group of /proc/net/ipt_recent/* files"); + ++#include ++ ++#if defined(CONFIG_VE_IPTABLES) ++#define tables (get_exec_env()->_ipt_recent->tables) ++#define proc_dir (get_exec_env()->_ipt_recent->proc_dir) ++#else ++static LIST_HEAD(tables); ++static struct proc_dir_entry *proc_dir; ++#endif /* CONFIG_VE_IPTABLES */ ++ ++static int init_ipt_recent(struct ve_struct *ve); ++static void fini_ipt_recent(struct ve_struct *ve); ++ + struct recent_entry { + struct list_head list; + struct list_head lru_list; +@@ -74,12 +88,10 @@ + struct list_head iphash[0]; + }; + +-static LIST_HEAD(tables); + static DEFINE_SPINLOCK(recent_lock); + static DEFINE_MUTEX(recent_mutex); + + #ifdef CONFIG_PROC_FS +-static struct proc_dir_entry *proc_dir; + static const struct file_operations recent_fops; + #endif + +@@ -256,6 +268,9 @@ + strnlen(info->name, IPT_RECENT_NAME_LEN) == IPT_RECENT_NAME_LEN) + return false; + ++ if (init_ipt_recent(get_exec_env())) ++ return 0; ++ + mutex_lock(&recent_mutex); + t = recent_table_lookup(info->name); + if (t != NULL) { +@@ -298,6 +313,13 @@ + { + const struct ipt_recent_info *info = matchinfo; + struct recent_table *t; ++ struct ve_struct *ve; ++ ++ ve = get_exec_env(); ++#ifdef CONFIG_VE_IPTABLES ++ if (!ve->_ipt_recent) ++ return; ++#endif + + mutex_lock(&recent_mutex); + t = recent_table_lookup(info->name); +@@ -312,6 +334,8 @@ + kfree(t); + } + mutex_unlock(&recent_mutex); ++ if (!ve_is_super(ve) && list_empty(&tables)) ++ fini_ipt_recent(ve); + } + + #ifdef CONFIG_PROC_FS +@@ -465,6 +489,47 @@ + .me = THIS_MODULE, + }; + ++static int init_ipt_recent(struct ve_struct *ve) ++{ ++ int err = 0; ++ ++#ifdef CONFIG_VE_IPTABLES ++ if (ve->_ipt_recent) ++ return 0; ++ ++ ve->_ipt_recent = kzalloc(sizeof(struct ve_ipt_recent), GFP_KERNEL); ++ if (!ve->_ipt_recent) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ INIT_LIST_HEAD(&tables); ++#endif ++#ifdef CONFIG_PROC_FS ++ if (err) ++ return err; ++ proc_dir = proc_mkdir("ipt_recent", ve->ve_ns->net_ns->proc_net); ++ if (proc_dir == NULL) { ++ err = -ENOMEM; ++ goto out_mem; ++ } ++#endif ++out: ++ return err; ++out_mem: ++ kfree(ve->_ipt_recent); ++ goto out; ++} ++ ++static void fini_ipt_recent(struct ve_struct *ve) ++{ ++ remove_proc_entry("ipt_recent", ve->ve_ns->net_ns->proc_net); ++#ifdef CONFIG_VE_IPTABLES ++ kfree(ve->_ipt_recent); ++ ve->_ipt_recent = NULL; ++#endif ++} ++ + static int __init ipt_recent_init(void) + { + int err; +@@ -474,25 +539,24 @@ + ip_list_hash_size = 1 << fls(ip_list_tot); + + err = xt_register_match(&recent_match); +-#ifdef CONFIG_PROC_FS + if (err) + return err; +- proc_dir = proc_mkdir("ipt_recent", init_net.proc_net); +- if (proc_dir == NULL) { ++ ++ err = init_ipt_recent(&ve0); ++ if (err) { + xt_unregister_match(&recent_match); +- err = -ENOMEM; ++ return err; + } +-#endif +- return err; ++ ++ return 0; + } + + static void __exit ipt_recent_exit(void) + { + BUG_ON(!list_empty(&tables)); ++ ++ fini_ipt_recent(&ve0); + xt_unregister_match(&recent_match); +-#ifdef CONFIG_PROC_FS +- remove_proc_entry("ipt_recent", init_net.proc_net); +-#endif + } + + module_init(ipt_recent_init); +Index: kernel/net/ipv4/netfilter/iptable_filter.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/iptable_filter.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/iptable_filter.c 2008-11-24 15:47:46.000000000 +0100 +@@ -12,6 +12,7 @@ + + #include + #include ++#include + #include + #include + +@@ -19,6 +20,13 @@ + MODULE_AUTHOR("Netfilter Core Team "); + MODULE_DESCRIPTION("iptables filter table"); + ++#ifdef CONFIG_VE_IPTABLES ++#include ++#define ve_packet_filter (get_exec_env()->_ve_ipt_filter_pf) ++#else ++#define ve_packet_filter &packet_filter ++#endif ++ + #define FILTER_VALID_HOOKS ((1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)) + + static struct +@@ -26,7 +34,7 @@ + struct ipt_replace repl; + struct ipt_standard entries[3]; + struct ipt_error term; +-} initial_table __initdata = { ++} initial_table = { + .repl = { + .name = "filter", + .valid_hooks = FILTER_VALID_HOOKS, +@@ -67,7 +75,7 @@ + const struct net_device *out, + int (*okfn)(struct sk_buff *)) + { +- return ipt_do_table(skb, hook, in, out, &packet_filter); ++ return ipt_do_table(skb, hook, in, out, ve_packet_filter); + } + + static unsigned int +@@ -86,7 +94,7 @@ + return NF_ACCEPT; + } + +- return ipt_do_table(skb, hook, in, out, &packet_filter); ++ return ipt_do_table(skb, hook, in, out, ve_packet_filter); + } + + static struct nf_hook_ops ipt_ops[] = { +@@ -117,22 +125,19 @@ + static int forward = NF_ACCEPT; + module_param(forward, bool, 0000); + +-static int __init iptable_filter_init(void) ++int init_iptable_filter(void) + { + int ret; +- +- if (forward < 0 || forward > NF_MAX_VERDICT) { +- printk("iptables forward must be 0 or 1\n"); +- return -EINVAL; +- } +- +- /* Entry 1 is the FORWARD hook */ +- initial_table.entries[1].target.verdict = -forward - 1; ++ struct ipt_table *tmp_filter; + + /* Register table */ +- ret = ipt_register_table(&packet_filter, &initial_table.repl); +- if (ret < 0) +- return ret; ++ tmp_filter = ipt_register_table(&packet_filter, ++ &initial_table.repl); ++ if (IS_ERR(tmp_filter)) ++ return PTR_ERR(tmp_filter); ++#ifdef CONFIG_VE_IPTABLES ++ ve_packet_filter = tmp_filter; ++#endif + + /* Register hooks */ + ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); +@@ -142,14 +147,50 @@ + return ret; + + cleanup_table: +- ipt_unregister_table(&packet_filter); ++ ipt_unregister_table(ve_packet_filter); ++#ifdef CONFIG_VE_IPTABLES ++ ve_packet_filter = NULL; ++#endif + return ret; + } + +-static void __exit iptable_filter_fini(void) ++void fini_iptable_filter(void) + { + nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); +- ipt_unregister_table(&packet_filter); ++ ipt_unregister_table(ve_packet_filter); ++#ifdef CONFIG_VE_IPTABLES ++ ve_packet_filter = NULL; ++#endif ++} ++ ++static int __init iptable_filter_init(void) ++{ ++ int err; ++ ++ if (forward < 0 || forward > NF_MAX_VERDICT) { ++ printk("iptables forward must be 0 or 1\n"); ++ return -EINVAL; ++ } ++ ++ /* Entry 1 is the FORWARD hook */ ++ initial_table.entries[1].target.verdict = -forward - 1; ++ ++ err = init_iptable_filter(); ++ if (err < 0) ++ return err; ++ ++ KSYMRESOLVE(init_iptable_filter); ++ KSYMRESOLVE(fini_iptable_filter); ++ KSYMMODRESOLVE(iptable_filter); ++ return 0; ++} ++ ++static void __exit iptable_filter_fini(void) ++{ ++ KSYMMODUNRESOLVE(iptable_filter); ++ KSYMUNRESOLVE(init_iptable_filter); ++ KSYMUNRESOLVE(fini_iptable_filter); ++ fini_iptable_filter(); + } + + module_init(iptable_filter_init); +Index: kernel/net/ipv4/netfilter/iptable_mangle.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/iptable_mangle.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/iptable_mangle.c 2008-11-24 15:47:46.000000000 +0100 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -33,7 +34,7 @@ + struct ipt_replace repl; + struct ipt_standard entries[5]; + struct ipt_error term; +-} initial_table __initdata = { ++} initial_table = { + .repl = { + .name = "mangle", + .valid_hooks = MANGLE_VALID_HOOKS, +@@ -72,6 +73,13 @@ + .af = AF_INET, + }; + ++#ifdef CONFIG_VE_IPTABLES ++#include ++#define ve_packet_mangler (get_exec_env()->_ipt_mangle_table) ++#else ++#define ve_packet_mangler &packet_mangler ++#endif ++ + /* The work comes in here from netfilter.c. */ + static unsigned int + ipt_route_hook(unsigned int hook, +@@ -80,7 +88,7 @@ + const struct net_device *out, + int (*okfn)(struct sk_buff *)) + { +- return ipt_do_table(skb, hook, in, out, &packet_mangler); ++ return ipt_do_table(skb, hook, in, out, ve_packet_mangler); + } + + static unsigned int +@@ -112,7 +120,7 @@ + daddr = iph->daddr; + tos = iph->tos; + +- ret = ipt_do_table(skb, hook, in, out, &packet_mangler); ++ ret = ipt_do_table(skb, hook, in, out, ve_packet_mangler); + /* Reroute for ANY change. */ + if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) { + iph = ip_hdr(skb); +@@ -166,14 +174,19 @@ + }, + }; + +-static int __init iptable_mangle_init(void) ++int init_iptable_mangle(void) + { + int ret; ++ struct ipt_table *tmp_mangler; + + /* Register table */ +- ret = ipt_register_table(&packet_mangler, &initial_table.repl); +- if (ret < 0) +- return ret; ++ tmp_mangler = ipt_register_table(&packet_mangler, ++ &initial_table.repl); ++ if (IS_ERR(tmp_mangler)) ++ return PTR_ERR(tmp_mangler); ++#ifdef CONFIG_VE_IPTABLES ++ ve_packet_mangler = tmp_mangler; ++#endif + + /* Register hooks */ + ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); +@@ -183,14 +196,42 @@ + return ret; + + cleanup_table: +- ipt_unregister_table(&packet_mangler); ++ ipt_unregister_table(ve_packet_mangler); ++#ifdef CONFIG_VE_IPTABLES ++ ve_packet_mangler = NULL; ++#endif + return ret; + } + +-static void __exit iptable_mangle_fini(void) ++void fini_iptable_mangle(void) + { + nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); +- ipt_unregister_table(&packet_mangler); ++ ipt_unregister_table(ve_packet_mangler); ++#ifdef CONFIG_VE_IPTABLES ++ ve_packet_mangler = NULL; ++#endif ++} ++ ++static int __init iptable_mangle_init(void) ++{ ++ int err; ++ ++ err = init_iptable_mangle(); ++ if (err < 0) ++ return err; ++ ++ KSYMRESOLVE(init_iptable_mangle); ++ KSYMRESOLVE(fini_iptable_mangle); ++ KSYMMODRESOLVE(iptable_mangle); ++ return 0; ++} ++ ++static void __exit iptable_mangle_fini(void) ++{ ++ KSYMMODUNRESOLVE(iptable_mangle); ++ KSYMUNRESOLVE(init_iptable_mangle); ++ KSYMUNRESOLVE(fini_iptable_mangle); ++ fini_iptable_mangle(); + } + + module_init(iptable_mangle_init); +Index: kernel/net/ipv4/netfilter/iptable_raw.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/iptable_raw.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/iptable_raw.c 2008-11-24 15:47:46.000000000 +0100 +@@ -93,12 +93,13 @@ + + static int __init iptable_raw_init(void) + { ++ struct xt_table *tmp; + int ret; + + /* Register table */ +- ret = ipt_register_table(&packet_raw, &initial_table.repl); +- if (ret < 0) +- return ret; ++ tmp = ipt_register_table(&packet_raw, &initial_table.repl); ++ if (IS_ERR(tmp)) ++ return PTR_ERR(tmp); + + /* Register hooks */ + ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); +Index: kernel/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 2008-11-24 15:47:46.000000000 +0100 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -426,82 +427,214 @@ + MODULE_ALIAS("ip_conntrack"); + MODULE_LICENSE("GPL"); + +-static int __init nf_conntrack_l3proto_ipv4_init(void) ++#ifdef CONFIG_VE_IPTABLES ++#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) ++static void nf_ct_proto_ipv4_sysctl_cleanup(void) + { +- int ret = 0; ++ if (!ve_is_super(get_exec_env())) { ++ free_sysctl_clone(ve_nf_conntrack_l3proto_ipv4->ctl_table); ++ ve_nf_conntrack_l3proto_ipv4->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l3proto_ipv4); ++ ve_nf_conntrack_l3proto_ipv4 = NULL; ++ } ++} + +- need_conntrack(); ++static int nf_ct_proto_ipv4_sysctl_init(void) ++{ ++ struct nf_conntrack_l3proto *ipv4 = ve_nf_conntrack_l3proto_ipv4; + +- ret = nf_register_sockopt(&so_getorigdst); +- if (ret < 0) { +- printk(KERN_ERR "Unable to register netfilter socket option\n"); +- return ret; +- } ++ ipv4->ctl_table_header = NULL; ++ ipv4->ctl_table_path = nf_net_ipv4_netfilter_sysctl_path; ++ ipv4->ctl_table = clone_sysctl_template(ip_ct_sysctl_table); ++ if (ipv4->ctl_table == NULL) ++ return -ENOMEM; ++ ++ ipv4->ctl_table[0].data = &ve_nf_conntrack_max; ++ ipv4->ctl_table[1].data = &ve_nf_conntrack_count; ++ ipv4->ctl_table[3].data = &ve_nf_conntrack_checksum; ++ ipv4->ctl_table[4].data = &ve_nf_ct_log_invalid; ++ ++ return 0; ++} ++#else ++static inline int nf_ct_proto_ipv4_sysctl_init(void) ++{ ++ return 0; ++} ++static inline void nf_ct_proto_ipv4_sysctl_cleanup(void) ++{ ++} ++#endif /* SYSCTL && NF_CONNTRACK_PROC_COMPAT */ ++ ++/* ++ * Functions init/fini_nf_ct_l3proto_ipv4 glue distributed nf_conntrack ++ * virtualization efforts. They are to be called from 2 places: ++ * ++ * 1) on loading/unloading module nf_conntrack_ipv4 from ++ * nf_conntrack_l3proto_ipv4_init/fini ++ * 2) on start/stop ve - from do_ve_iptables ++ */ ++static int nf_ct_proto_ipv4_init(void) ++{ ++ struct nf_conntrack_l3proto *ipv4; ++ ++ if (ve_is_super(get_exec_env())) { ++ ipv4 = &nf_conntrack_l3proto_ipv4; ++ goto out; ++ } ++ ipv4 = kmemdup(&nf_conntrack_l3proto_ipv4, ++ sizeof(struct nf_conntrack_l3proto), GFP_KERNEL); ++ if (!ipv4) ++ return -ENOMEM; ++out: ++ ve_nf_conntrack_l3proto_ipv4 = ipv4; ++ return 0; ++} ++#endif ++ ++int init_nf_ct_l3proto_ipv4(void) ++{ ++ int ret = -ENOMEM; ++ ++#ifdef CONFIG_VE_IPTABLES ++ if (!ve_is_super(get_exec_env())) ++ __module_get(THIS_MODULE); ++ ++ ret = nf_ct_proto_ipv4_init(); ++ if (ret < 0) ++ goto err_out; ++ ret = nf_ct_proto_ipv4_sysctl_init(); ++ if (ret < 0) ++ goto no_mem_ipv4; ++ ret = nf_ct_proto_tcp_sysctl_init(); ++ if (ret < 0) ++ goto no_mem_tcp; ++ ret = nf_ct_proto_udp_sysctl_init(); ++ if (ret < 0) ++ goto no_mem_udp; ++ ret = nf_ct_proto_icmp_sysctl_init(); ++ if (ret < 0) ++ goto no_mem_icmp; ++#endif /* CONFIG_VE_IPTABLES */ + +- ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp4); ++ ret = nf_conntrack_l4proto_register(ve_nf_conntrack_l4proto_tcp4); + if (ret < 0) { + printk("nf_conntrack_ipv4: can't register tcp.\n"); +- goto cleanup_sockopt; ++ goto cleanup_sys; + } + +- ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp4); ++ ret = nf_conntrack_l4proto_register(ve_nf_conntrack_l4proto_udp4); + if (ret < 0) { + printk("nf_conntrack_ipv4: can't register udp.\n"); +- goto cleanup_tcp; ++ goto unreg_tcp; + } + +- ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmp); ++ ret = nf_conntrack_l4proto_register(ve_nf_conntrack_l4proto_icmp); + if (ret < 0) { + printk("nf_conntrack_ipv4: can't register icmp.\n"); +- goto cleanup_udp; ++ goto unreg_udp; + } + +- ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv4); ++ ret = nf_conntrack_l3proto_register(ve_nf_conntrack_l3proto_ipv4); + if (ret < 0) { + printk("nf_conntrack_ipv4: can't register ipv4\n"); +- goto cleanup_icmp; ++ goto unreg_icmp; + } + + ret = nf_register_hooks(ipv4_conntrack_ops, + ARRAY_SIZE(ipv4_conntrack_ops)); + if (ret < 0) { + printk("nf_conntrack_ipv4: can't register hooks.\n"); +- goto cleanup_ipv4; ++ goto unreg_ipv4; + } +-#if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) + ret = nf_conntrack_ipv4_compat_init(); + if (ret < 0) +- goto cleanup_hooks; +-#endif ++ goto unreg_hooks; ++ return 0; ++ ++unreg_hooks: ++ nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); ++unreg_ipv4: ++ nf_conntrack_l3proto_unregister(ve_nf_conntrack_l3proto_ipv4); ++unreg_icmp: ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_icmp); ++unreg_udp: ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_udp4); ++unreg_tcp: ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_tcp4); ++cleanup_sys: ++#ifdef CONFIG_VE_IPTABLES ++no_mem_icmp: ++ nf_ct_proto_udp_sysctl_cleanup(); ++no_mem_udp: ++ nf_ct_proto_tcp_sysctl_cleanup(); ++no_mem_tcp: ++ nf_ct_proto_ipv4_sysctl_cleanup(); ++no_mem_ipv4: ++err_out: ++ if (!ve_is_super(get_exec_env())) ++ module_put(THIS_MODULE); ++#endif /* CONFIG_VE_IPTABLES */ + return ret; +-#if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) +- cleanup_hooks: ++} ++EXPORT_SYMBOL(init_nf_ct_l3proto_ipv4); ++ ++void fini_nf_ct_l3proto_ipv4(void) ++{ ++ nf_conntrack_ipv4_compat_fini(); + nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); +-#endif +- cleanup_ipv4: +- nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); +- cleanup_icmp: +- nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp); +- cleanup_udp: +- nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp4); +- cleanup_tcp: +- nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp4); ++ nf_conntrack_l3proto_unregister(ve_nf_conntrack_l3proto_ipv4); ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_icmp); ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_udp4); ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_tcp4); ++ ++#ifdef CONFIG_VE_IPTABLES ++ nf_ct_proto_icmp_sysctl_cleanup(); ++ nf_ct_proto_udp_sysctl_cleanup(); ++ nf_ct_proto_tcp_sysctl_cleanup(); ++ nf_ct_proto_ipv4_sysctl_cleanup(); ++ if (!ve_is_super(get_exec_env())) ++ module_put(THIS_MODULE); ++#endif /* CONFIG_VE_IPTABLES */ ++} ++EXPORT_SYMBOL(fini_nf_ct_l3proto_ipv4); ++ ++static int nf_conntrack_l3proto_ipv4_init(void) ++{ ++ int ret = 0; ++ ++ need_conntrack(); ++ ++ ret = nf_register_sockopt(&so_getorigdst); ++ if (ret < 0) { ++ printk(KERN_ERR "Unable to register netfilter socket option\n"); ++ return ret; ++ } ++ ++ ret = init_nf_ct_l3proto_ipv4(); ++ if (ret < 0) { ++ printk(KERN_ERR "Unable to initialize netfilter protocols\n"); ++ goto cleanup_sockopt; ++ } ++ KSYMRESOLVE(init_nf_ct_l3proto_ipv4); ++ KSYMRESOLVE(fini_nf_ct_l3proto_ipv4); ++ KSYMMODRESOLVE(nf_conntrack_ipv4); ++ return ret; ++ + cleanup_sockopt: + nf_unregister_sockopt(&so_getorigdst); + return ret; + } + +-static void __exit nf_conntrack_l3proto_ipv4_fini(void) ++static void nf_conntrack_l3proto_ipv4_fini(void) + { + synchronize_net(); +-#if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) +- nf_conntrack_ipv4_compat_fini(); +-#endif +- nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); +- nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); +- nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp); +- nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp4); +- nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp4); ++ ++ KSYMMODUNRESOLVE(nf_conntrack_ipv4); ++ KSYMUNRESOLVE(init_nf_ct_l3proto_ipv4); ++ KSYMUNRESOLVE(fini_nf_ct_l3proto_ipv4); ++ ++ fini_nf_ct_l3proto_ipv4(); + nf_unregister_sockopt(&so_getorigdst); + } + +Index: kernel/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c 2008-11-24 15:47:46.000000000 +0100 +@@ -9,7 +9,9 @@ + */ + #include + #include ++#include + #include ++#include + #include + #include + +@@ -43,8 +45,8 @@ + for (st->bucket = 0; + st->bucket < nf_conntrack_htable_size; + st->bucket++) { +- if (!hlist_empty(&nf_conntrack_hash[st->bucket])) +- return nf_conntrack_hash[st->bucket].first; ++ if (!hlist_empty(&ve_nf_conntrack_hash[st->bucket])) ++ return ve_nf_conntrack_hash[st->bucket].first; + } + return NULL; + } +@@ -58,7 +60,7 @@ + while (head == NULL) { + if (++st->bucket >= nf_conntrack_htable_size) + return NULL; +- head = nf_conntrack_hash[st->bucket].first; ++ head = ve_nf_conntrack_hash[st->bucket].first; + } + return head; + } +@@ -196,8 +198,8 @@ + struct ct_expect_iter_state *st = seq->private; + + for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) { +- if (!hlist_empty(&nf_ct_expect_hash[st->bucket])) +- return nf_ct_expect_hash[st->bucket].first; ++ if (!hlist_empty(&ve_nf_ct_expect_hash[st->bucket])) ++ return ve_nf_ct_expect_hash[st->bucket].first; + } + return NULL; + } +@@ -211,7 +213,7 @@ + while (head == NULL) { + if (++st->bucket >= nf_ct_expect_hsize) + return NULL; +- head = nf_ct_expect_hash[st->bucket].first; ++ head = ve_nf_ct_expect_hash[st->bucket].first; + } + return head; + } +@@ -326,7 +328,7 @@ + + static int ct_cpu_seq_show(struct seq_file *seq, void *v) + { +- unsigned int nr_conntracks = atomic_read(&nf_conntrack_count); ++ unsigned int nr_conntracks = atomic_read(&ve_nf_conntrack_count); + struct ip_conntrack_stat *st = v; + + if (v == SEQ_START_TOKEN) { +@@ -377,39 +379,104 @@ + .release = seq_release_private, + }; + +-int __init nf_conntrack_ipv4_compat_init(void) ++#ifdef CONFIG_VE_IPTABLES ++#define ve_ip_ct_net_table (get_exec_env()->_nf_conntrack->_ip_ct_net_table) ++#define ve_ip_ct_netfilter_table (get_exec_env()->_nf_conntrack->_ip_ct_netfilter_table) ++#define ve_ip_ct_sysctl_header (get_exec_env()->_nf_conntrack->_ip_ct_sysctl_header) ++#else ++#define ve_ip_ct_net_table ip_ct_net_table ++#define ve_ip_ct_netfilter_table ip_ct_netfilter_table ++#define ve_ip_ct_sysctl_header ip_ct_sysctl_header ++#endif ++ ++static ctl_table ip_ct_netfilter_table[] = { ++ { ++ .procname = "ip_conntrack_max", ++ .data = &nf_conntrack_max, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, ++ {} ++}; ++ ++static ctl_table ip_ct_ipv4_table[] = { ++ { ++ .ctl_name = NET_IPV4, ++ .procname = "ipv4", ++ .mode = 0555, ++ .child = ip_ct_netfilter_table, ++ }, ++ {} ++}; ++ ++static ctl_table ip_ct_net_table[] = { ++ { ++ .ctl_name = CTL_NET, ++ .procname = "net", ++ .mode = 0555, ++ .child = ip_ct_ipv4_table, ++ }, ++ {} ++}; ++ ++int nf_conntrack_ipv4_compat_init(void) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + struct proc_dir_entry *proc, *proc_exp, *proc_stat; + +- proc = proc_net_fops_create(&init_net, "ip_conntrack", 0440, &ct_file_ops); ++ proc = proc_net_fops_create(net, "ip_conntrack", 0440, &ct_file_ops); + if (!proc) + goto err1; + +- proc_exp = proc_net_fops_create(&init_net, "ip_conntrack_expect", 0440, ++ proc_exp = proc_net_fops_create(net, "ip_conntrack_expect", 0440, + &ip_exp_file_ops); + if (!proc_exp) + goto err2; + +- proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, init_net.proc_net_stat); ++ proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, net->proc_net_stat); + if (!proc_stat) + goto err3; + + proc_stat->proc_fops = &ct_cpu_seq_fops; + proc_stat->owner = THIS_MODULE; + ++ if (ve_is_super(get_exec_env())) { ++ ve_ip_ct_net_table = ip_ct_net_table; ++ } else { ++ ve_ip_ct_net_table = clone_sysctl_template(ip_ct_net_table); ++ if (!ve_ip_ct_net_table) ++ goto err4; ++ } ++ ve_ip_ct_netfilter_table = ve_ip_ct_net_table[0].child[0].child; ++ ve_ip_ct_netfilter_table[0].data = &ve_nf_conntrack_max; ++ ve_ip_ct_sysctl_header = register_sysctl_table(ve_ip_ct_net_table); ++ if (!ve_ip_ct_sysctl_header) ++ goto err5; ++ + return 0; + ++err5: ++ if (!ve_is_super(get_exec_env())) ++ free_sysctl_clone(ve_ip_ct_net_table); ++err4: ++ remove_proc_entry("ip_conntrack", net->proc_net_stat); + err3: +- proc_net_remove(&init_net, "ip_conntrack_expect"); ++ proc_net_remove(net, "ip_conntrack_expect"); + err2: +- proc_net_remove(&init_net, "ip_conntrack"); ++ proc_net_remove(net, "ip_conntrack"); + err1: + return -ENOMEM; + } + +-void __exit nf_conntrack_ipv4_compat_fini(void) ++void nf_conntrack_ipv4_compat_fini(void) + { +- remove_proc_entry("ip_conntrack", init_net.proc_net_stat); +- proc_net_remove(&init_net, "ip_conntrack_expect"); +- proc_net_remove(&init_net, "ip_conntrack"); ++ struct net *net = get_exec_env()->ve_ns->net_ns; ++ ++ unregister_sysctl_table(ve_ip_ct_sysctl_header); ++ if (!ve_is_super(get_exec_env())) ++ free_sysctl_clone(ve_ip_ct_net_table); ++ remove_proc_entry("ip_conntrack", net->proc_net_stat); ++ proc_net_remove(net, "ip_conntrack_expect"); ++ proc_net_remove(net, "ip_conntrack"); + } +Index: kernel/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/nf_conntrack_proto_icmp.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/nf_conntrack_proto_icmp.c 2008-11-24 15:47:46.000000000 +0100 +@@ -7,6 +7,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -19,7 +20,7 @@ + #include + #include + +-static unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ; ++unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ; + + static int icmp_pkt_to_tuple(const struct sk_buff *skb, + unsigned int dataoff, +@@ -99,7 +100,7 @@ + } else { + atomic_inc(&ct->proto.icmp.count); + nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb); +- nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout); ++ nf_ct_refresh_acct(ct, ctinfo, skb, ve_nf_ct_icmp_timeout); + } + + return NF_ACCEPT; +@@ -156,7 +157,7 @@ + /* Ordinarily, we'd expect the inverted tupleproto, but it's + been preserved inside the ICMP. */ + if (!nf_ct_invert_tuple(&innertuple, &origtuple, +- &nf_conntrack_l3proto_ipv4, innerproto)) { ++ ve_nf_conntrack_l3proto_ipv4, innerproto)) { + pr_debug("icmp_error_message: no match\n"); + return -NF_ACCEPT; + } +@@ -334,3 +335,66 @@ + #endif + #endif + }; ++ ++#if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) ++void nf_ct_proto_icmp_sysctl_cleanup(void) ++{ ++ if (!ve_is_super(get_exec_env())) { ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ free_sysctl_clone( ++ ve_nf_conntrack_l4proto_icmp->ctl_compat_table); ++ ve_nf_conntrack_l4proto_icmp->ctl_compat_table = NULL; ++#endif ++ free_sysctl_clone(ve_nf_conntrack_l4proto_icmp->ctl_table); ++ ve_nf_conntrack_l4proto_icmp->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l4proto_icmp); ++ ve_nf_conntrack_l4proto_icmp = NULL; ++ } ++} ++EXPORT_SYMBOL(nf_ct_proto_icmp_sysctl_cleanup); ++ ++int nf_ct_proto_icmp_sysctl_init(void) ++{ ++ struct nf_conntrack_l4proto *icmp; ++ ++ if (ve_is_super(get_exec_env())) { ++ icmp = &nf_conntrack_l4proto_icmp; ++ goto out; ++ } ++ ++ icmp = kmemdup(&nf_conntrack_l4proto_icmp, ++ sizeof(struct nf_conntrack_l4proto), GFP_KERNEL); ++ if (!icmp) ++ goto no_mem_ct; ++ ++ icmp->ctl_table_header = &ve_icmp_sysctl_header; ++ icmp->ctl_table = clone_sysctl_template(icmp_sysctl_table); ++ if (icmp->ctl_table == NULL) ++ goto no_mem_sys; ++ icmp->ctl_table[0].data = &ve_nf_ct_icmp_timeout; ++ ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ icmp->ctl_compat_table_header = ve_icmp_compat_sysctl_header; ++ icmp->ctl_compat_table = ++ clone_sysctl_template(icmp_compat_sysctl_table); ++ if (icmp->ctl_compat_table == NULL) ++ goto no_mem_compat; ++ icmp->ctl_compat_table[0].data = &ve_nf_ct_icmp_timeout; ++#endif ++out: ++ ve_nf_ct_icmp_timeout = nf_ct_icmp_timeout; ++ ++ ve_nf_conntrack_l4proto_icmp = icmp; ++ return 0; ++ ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++no_mem_compat: ++ free_sysctl_clone(icmp->ctl_table); ++#endif ++no_mem_sys: ++ kfree(icmp); ++no_mem_ct: ++ return -ENOMEM; ++} ++EXPORT_SYMBOL(nf_ct_proto_icmp_sysctl_init); ++#endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ +Index: kernel/net/ipv4/netfilter/nf_nat_core.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/nf_nat_core.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/nf_nat_core.c 2008-11-24 15:47:46.000000000 +0100 +@@ -19,6 +19,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -33,6 +35,9 @@ + + static DEFINE_RWLOCK(nf_nat_lock); + ++#define MAX_IP_NAT_PROTO 256 ++ ++static struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO]; + static struct nf_conntrack_l3proto *l3proto = NULL; + + /* Calculated at init based on memory size */ +@@ -41,13 +46,22 @@ + + static struct hlist_head *bysource; + +-#define MAX_IP_NAT_PROTO 256 +-static struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO]; ++#ifdef CONFIG_VE_IPTABLES ++#define ve_nf_nat_protos (get_exec_env()->_nf_conntrack->_nf_nat_protos) ++#define ve_nf_nat_l3proto (get_exec_env()->_nf_conntrack->_nf_nat_l3proto) ++#define ve_bysource (get_exec_env()->_nf_conntrack->_bysource) ++#define ve_nf_nat_vmalloced (get_exec_env()->_nf_conntrack->_nf_nat_vmalloced) ++#else ++#define ve_nf_nat_protos nf_nat_protos ++#define ve_nf_nat_l3proto l3proto ++#define ve_bysource bysource ++#define ve_nf_nat_vmalloced nf_nat_vmalloced ++#endif + + static inline struct nf_nat_protocol * + __nf_nat_proto_find(u_int8_t protonum) + { +- return rcu_dereference(nf_nat_protos[protonum]); ++ return rcu_dereference(ve_nf_nat_protos[protonum]); + } + + struct nf_nat_protocol * +@@ -151,7 +165,7 @@ + struct hlist_node *n; + + read_lock_bh(&nf_nat_lock); +- hlist_for_each_entry(nat, n, &bysource[h], bysource) { ++ hlist_for_each_entry(nat, n, &ve_bysource[h], bysource) { + ct = nat->ct; + if (same_src(ct, tuple)) { + /* Copy source part from reply tuple. */ +@@ -332,7 +346,7 @@ + /* nf_conntrack_alter_reply might re-allocate exntension aera */ + nat = nfct_nat(ct); + nat->ct = ct; +- hlist_add_head(&nat->bysource, &bysource[srchash]); ++ hlist_add_head(&nat->bysource, &ve_bysource[srchash]); + write_unlock_bh(&nf_nat_lock); + } + +@@ -424,7 +438,6 @@ + struct icmphdr icmp; + struct iphdr ip; + } *inside; +- struct nf_conntrack_l4proto *l4proto; + struct nf_conntrack_tuple inner, target; + int hdrlen = ip_hdrlen(skb); + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); +@@ -461,16 +474,14 @@ + "dir %s\n", skb, manip, + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); + +- /* rcu_read_lock()ed by nf_hook_slow */ +- l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol); +- + if (!nf_ct_get_tuple(skb, + ip_hdrlen(skb) + sizeof(struct icmphdr), + (ip_hdrlen(skb) + + sizeof(struct icmphdr) + inside->ip.ihl * 4), + (u_int16_t)AF_INET, + inside->ip.protocol, +- &inner, l3proto, l4proto)) ++ &inner, ve_nf_nat_l3proto, ++ __nf_ct_l4proto_find(PF_INET, inside->ip.protocol))) + return 0; + + /* Change inner back to look like incoming packet. We do the +@@ -520,11 +531,11 @@ + int ret = 0; + + write_lock_bh(&nf_nat_lock); +- if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) { ++ if (ve_nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) { + ret = -EBUSY; + goto out; + } +- rcu_assign_pointer(nf_nat_protos[proto->protonum], proto); ++ rcu_assign_pointer(ve_nf_nat_protos[proto->protonum], proto); + out: + write_unlock_bh(&nf_nat_lock); + return ret; +@@ -535,7 +546,7 @@ + void nf_nat_protocol_unregister(struct nf_nat_protocol *proto) + { + write_lock_bh(&nf_nat_lock); +- rcu_assign_pointer(nf_nat_protos[proto->protonum], ++ rcu_assign_pointer(ve_nf_nat_protos[proto->protonum], + &nf_nat_unknown_protocol); + write_unlock_bh(&nf_nat_lock); + synchronize_rcu(); +@@ -626,46 +637,58 @@ + .flags = NF_CT_EXT_F_PREALLOC, + }; + +-static int __init nf_nat_init(void) ++int nf_nat_init(void) + { + size_t i; + int ret; + +- ret = nf_ct_extend_register(&nat_extend); +- if (ret < 0) { +- printk(KERN_ERR "nf_nat_core: Unable to register extension\n"); +- return ret; ++ if (ve_is_super(get_exec_env())) { ++ ret = nf_ct_extend_register(&nat_extend); ++ if (ret < 0) { ++ printk(KERN_ERR "nf_nat_core: Unable to register extension\n"); ++ return ret; ++ } + } + + /* Leave them the same for the moment. */ + nf_nat_htable_size = nf_conntrack_htable_size; + +- bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, +- &nf_nat_vmalloced); +- if (!bysource) { ++ ve_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, ++ &ve_nf_nat_vmalloced); ++ if (!ve_bysource) { + ret = -ENOMEM; + goto cleanup_extend; + } + ++ ve_nf_nat_protos = kcalloc(MAX_IP_NAT_PROTO, sizeof(void *), GFP_KERNEL); ++ if (!ve_nf_nat_protos) { ++ ret = -ENOMEM; ++ goto cleanup_hash; ++ } ++ + /* Sew in builtin protocols. */ + write_lock_bh(&nf_nat_lock); + for (i = 0; i < MAX_IP_NAT_PROTO; i++) +- rcu_assign_pointer(nf_nat_protos[i], &nf_nat_unknown_protocol); +- rcu_assign_pointer(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp); +- rcu_assign_pointer(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp); +- rcu_assign_pointer(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp); ++ rcu_assign_pointer(ve_nf_nat_protos[i], &nf_nat_unknown_protocol); ++ rcu_assign_pointer(ve_nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp); ++ rcu_assign_pointer(ve_nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp); ++ rcu_assign_pointer(ve_nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp); + write_unlock_bh(&nf_nat_lock); + + for (i = 0; i < nf_nat_htable_size; i++) { +- INIT_HLIST_HEAD(&bysource[i]); ++ INIT_HLIST_HEAD(&ve_bysource[i]); + } + +- /* Initialize fake conntrack so that NAT will skip it */ +- nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; ++ if (ve_is_super(get_exec_env())) { ++ /* Initialize fake conntrack so that NAT will skip it */ ++ nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; ++ } + +- l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); ++ ve_nf_nat_l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); + return 0; + ++cleanup_hash: ++ nf_ct_free_hashtable(ve_bysource, ve_nf_nat_vmalloced, nf_nat_htable_size); + cleanup_extend: + nf_ct_extend_unregister(&nat_extend); + return ret; +@@ -683,16 +706,40 @@ + return 0; + } + +-static void __exit nf_nat_cleanup(void) ++void nf_nat_cleanup(void) + { + nf_ct_iterate_cleanup(&clean_nat, NULL); + synchronize_rcu(); +- nf_ct_free_hashtable(bysource, nf_nat_vmalloced, nf_nat_htable_size); +- nf_ct_l3proto_put(l3proto); +- nf_ct_extend_unregister(&nat_extend); ++ nf_ct_free_hashtable(ve_bysource, ve_nf_nat_vmalloced, nf_nat_htable_size); ++ nf_ct_l3proto_put(ve_nf_nat_l3proto); ++ if (ve_is_super(get_exec_env())) ++ nf_ct_extend_unregister(&nat_extend); ++} ++ ++static int __init init(void) ++{ ++ int rv; ++ ++ rv = nf_nat_init(); ++ if (rv < 0) ++ return rv; ++ ++ KSYMRESOLVE(nf_nat_init); ++ KSYMRESOLVE(nf_nat_cleanup); ++ KSYMMODRESOLVE(nf_nat); ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ KSYMMODUNRESOLVE(nf_nat); ++ KSYMUNRESOLVE(nf_nat_cleanup); ++ KSYMUNRESOLVE(nf_nat_init); ++ ++ nf_nat_cleanup(); + } + + MODULE_LICENSE("GPL"); + +-module_init(nf_nat_init); +-module_exit(nf_nat_cleanup); ++module_init(init); ++module_exit(fini); +Index: kernel/net/ipv4/netfilter/nf_nat_rule.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/nf_nat_rule.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/netfilter/nf_nat_rule.c 2008-11-24 15:47:46.000000000 +0100 +@@ -24,6 +24,13 @@ + #include + #include + ++#ifdef CONFIG_VE_IPTABLES ++#define ve_nf_nat_table \ ++ (get_exec_env()->_nf_conntrack->_nf_nat_table) ++#else ++#define ve_nf_nat_table &nat_table ++#endif ++ + #define NAT_VALID_HOOKS ((1< + #include + #include ++#include + + #include + #include +@@ -324,30 +325,64 @@ + }, + }; + +-static int __init nf_nat_standalone_init(void) ++int init_nftable_nat(void) + { +- int ret = 0; ++ int ret; + +- need_ipv4_conntrack(); ++ if (!ve_is_super(get_exec_env())) ++ __module_get(THIS_MODULE); + +-#ifdef CONFIG_XFRM +- BUG_ON(ip_nat_decode_session != NULL); +- ip_nat_decode_session = nat_decode_session; +-#endif + ret = nf_nat_rule_init(); + if (ret < 0) { + printk("nf_nat_init: can't setup rules.\n"); +- goto cleanup_decode_session; ++ goto out_modput; + } + ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); + if (ret < 0) { + printk("nf_nat_init: can't register hooks.\n"); + goto cleanup_rule_init; + } ++ return 0; ++ ++cleanup_rule_init: ++ nf_nat_rule_cleanup(); ++out_modput: ++ if (!ve_is_super(get_exec_env())) ++ module_put(THIS_MODULE); + return ret; ++} + +- cleanup_rule_init: ++void fini_nftable_nat(void) ++{ ++ nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); + nf_nat_rule_cleanup(); ++ if (!ve_is_super(get_exec_env())) ++ module_put(THIS_MODULE); ++} ++ ++static int __init nf_nat_standalone_init(void) ++{ ++ int ret = 0; ++ ++ need_ipv4_conntrack(); ++ ++#ifdef CONFIG_XFRM ++ BUG_ON(ip_nat_decode_session != NULL); ++ ip_nat_decode_session = nat_decode_session; ++#endif ++ ++ if (!ip_conntrack_disable_ve0) { ++ ret = init_nftable_nat(); ++ if (ret < 0) ++ goto cleanup_decode_session; ++ } ++ ++ KSYMRESOLVE(init_nftable_nat); ++ KSYMRESOLVE(fini_nftable_nat); ++ KSYMMODRESOLVE(iptable_nat); ++ ++ return ret; ++ + cleanup_decode_session: + #ifdef CONFIG_XFRM + ip_nat_decode_session = NULL; +@@ -358,8 +393,12 @@ + + static void __exit nf_nat_standalone_fini(void) + { +- nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); +- nf_nat_rule_cleanup(); ++ KSYMMODUNRESOLVE(iptable_nat); ++ KSYMUNRESOLVE(init_nftable_nat); ++ KSYMUNRESOLVE(fini_nftable_nat); ++ ++ if (!ip_conntrack_disable_ve0) ++ fini_nftable_nat(); + #ifdef CONFIG_XFRM + ip_nat_decode_session = NULL; + synchronize_net(); +Index: kernel/net/ipv4/proc.c +=================================================================== +--- kernel.orig/net/ipv4/proc.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/proc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -51,6 +51,9 @@ + */ + static int sockstat_seq_show(struct seq_file *seq, void *v) + { ++ if (!ve_is_super(get_exec_env())) ++ return 0; ++ + socket_seq_show(seq); + seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %d\n", + sock_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count), +@@ -240,7 +243,7 @@ + count = 0; + for (i = 0; i < ICMPMSG_MIB_MAX; i++) { + +- if (snmp_fold_field((void **) icmpmsg_statistics, i)) ++ if (snmp_fold_field((void **) ve_icmpmsg_statistics, i)) + out[count++] = i; + if (count < PERLINE) + continue; +@@ -252,7 +255,7 @@ + seq_printf(seq, "\nIcmpMsg: "); + for (j = 0; j < PERLINE; ++j) + seq_printf(seq, " %lu", +- snmp_fold_field((void **) icmpmsg_statistics, ++ snmp_fold_field((void **) ve_icmpmsg_statistics, + out[j])); + seq_putc(seq, '\n'); + } +@@ -264,7 +267,7 @@ + seq_printf(seq, "\nIcmpMsg:"); + for (j = 0; j < count; ++j) + seq_printf(seq, " %lu", snmp_fold_field((void **) +- icmpmsg_statistics, out[j])); ++ ve_icmpmsg_statistics, out[j])); + } + + #undef PERLINE +@@ -281,18 +284,18 @@ + for (i=0; icmpmibmap[i].name != NULL; i++) + seq_printf(seq, " Out%s", icmpmibmap[i].name); + seq_printf(seq, "\nIcmp: %lu %lu", +- snmp_fold_field((void **) icmp_statistics, ICMP_MIB_INMSGS), +- snmp_fold_field((void **) icmp_statistics, ICMP_MIB_INERRORS)); ++ snmp_fold_field((void **) ve_icmp_statistics, ICMP_MIB_INMSGS), ++ snmp_fold_field((void **) ve_icmp_statistics, ICMP_MIB_INERRORS)); + for (i=0; icmpmibmap[i].name != NULL; i++) + seq_printf(seq, " %lu", +- snmp_fold_field((void **) icmpmsg_statistics, ++ snmp_fold_field((void **) ve_icmpmsg_statistics, + icmpmibmap[i].index)); + seq_printf(seq, " %lu %lu", +- snmp_fold_field((void **) icmp_statistics, ICMP_MIB_OUTMSGS), +- snmp_fold_field((void **) icmp_statistics, ICMP_MIB_OUTERRORS)); ++ snmp_fold_field((void **) ve_icmp_statistics, ICMP_MIB_OUTMSGS), ++ snmp_fold_field((void **) ve_icmp_statistics, ICMP_MIB_OUTERRORS)); + for (i=0; icmpmibmap[i].name != NULL; i++) + seq_printf(seq, " %lu", +- snmp_fold_field((void **) icmpmsg_statistics, ++ snmp_fold_field((void **) ve_icmpmsg_statistics, + icmpmibmap[i].index | 0x100)); + } + +@@ -313,7 +316,7 @@ + + for (i = 0; snmp4_ipstats_list[i].name != NULL; i++) + seq_printf(seq, " %lu", +- snmp_fold_field((void **)ip_statistics, ++ snmp_fold_field((void **)ve_ip_statistics, + snmp4_ipstats_list[i].entry)); + + icmp_put(seq); /* RFC 2011 compatibility */ +@@ -328,11 +331,11 @@ + /* MaxConn field is signed, RFC 2012 */ + if (snmp4_tcp_list[i].entry == TCP_MIB_MAXCONN) + seq_printf(seq, " %ld", +- snmp_fold_field((void **)tcp_statistics, ++ snmp_fold_field((void **)ve_tcp_statistics, + snmp4_tcp_list[i].entry)); + else + seq_printf(seq, " %lu", +- snmp_fold_field((void **)tcp_statistics, ++ snmp_fold_field((void **)ve_tcp_statistics, + snmp4_tcp_list[i].entry)); + } + +@@ -343,7 +346,7 @@ + seq_puts(seq, "\nUdp:"); + for (i = 0; snmp4_udp_list[i].name != NULL; i++) + seq_printf(seq, " %lu", +- snmp_fold_field((void **)udp_statistics, ++ snmp_fold_field((void **)ve_udp_statistics, + snmp4_udp_list[i].entry)); + + /* the UDP and UDP-Lite MIBs are the same */ +@@ -354,7 +357,7 @@ + seq_puts(seq, "\nUdpLite:"); + for (i = 0; snmp4_udp_list[i].name != NULL; i++) + seq_printf(seq, " %lu", +- snmp_fold_field((void **)udplite_statistics, ++ snmp_fold_field((void **)ve_udplite_statistics, + snmp4_udp_list[i].entry)); + + seq_putc(seq, '\n'); +@@ -390,7 +393,7 @@ + seq_puts(seq, "\nTcpExt:"); + for (i = 0; snmp4_net_list[i].name != NULL; i++) + seq_printf(seq, " %lu", +- snmp_fold_field((void **)net_statistics, ++ snmp_fold_field((void **)ve_net_statistics, + snmp4_net_list[i].entry)); + + seq_puts(seq, "\nIpExt:"); +@@ -400,7 +403,7 @@ + seq_puts(seq, "\nIpExt:"); + for (i = 0; snmp4_ipextstats_list[i].name != NULL; i++) + seq_printf(seq, " %lu", +- snmp_fold_field((void **)ip_statistics, ++ snmp_fold_field((void **)ve_ip_statistics, + snmp4_ipextstats_list[i].entry)); + + seq_putc(seq, '\n'); +@@ -420,26 +423,38 @@ + .release = single_release, + }; + +-int __init ip_misc_proc_init(void) ++static int ipv4_proc_net_init(struct net *net) + { +- int rc = 0; +- +- if (!proc_net_fops_create(&init_net, "netstat", S_IRUGO, &netstat_seq_fops)) ++ if (!proc_net_fops_create(net, "netstat", S_IRUGO, &netstat_seq_fops)) + goto out_netstat; +- +- if (!proc_net_fops_create(&init_net, "snmp", S_IRUGO, &snmp_seq_fops)) ++ if (!proc_net_fops_create(net, "snmp", S_IRUGO, &snmp_seq_fops)) + goto out_snmp; +- +- if (!proc_net_fops_create(&init_net, "sockstat", S_IRUGO, &sockstat_seq_fops)) +- goto out_sockstat; +-out: +- return rc; +-out_sockstat: +- proc_net_remove(&init_net, "snmp"); ++ return 0; + out_snmp: +- proc_net_remove(&init_net, "netstat"); ++ proc_net_remove(net, "netstat"); + out_netstat: +- rc = -ENOMEM; +- goto out; ++ return -ENOMEM; + } + ++static void ipv4_proc_net_exit(struct net *net) ++{ ++ proc_net_remove(net, "snmp"); ++ proc_net_remove(net, "netstat"); ++} ++ ++static struct pernet_operations ipv4_proc_net_ops = { ++ .init = ipv4_proc_net_init, ++ .exit = ipv4_proc_net_exit, ++}; ++ ++int __init ip_misc_proc_init(void) ++{ ++ int rv; ++ ++ if (!proc_net_fops_create(&init_net, "sockstat", S_IRUGO, &sockstat_seq_fops)) ++ return -ENOMEM; ++ rv = register_pernet_subsys(&ipv4_proc_net_ops); ++ if (rv < 0) ++ proc_net_remove(&init_net, "sockstat"); ++ return rv; ++} +Index: kernel/net/ipv4/raw.c +=================================================================== +--- kernel.orig/net/ipv4/raw.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/raw.c 2008-11-24 15:47:46.000000000 +0100 +@@ -114,7 +114,8 @@ + if (inet->num == num && + !(inet->daddr && inet->daddr != raddr) && + !(inet->rcv_saddr && inet->rcv_saddr != laddr) && +- !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) ++ !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) && ++ ve_accessible_strict(sk->owner_env, get_exec_env())) + goto found; /* gotcha */ + } + sk = NULL; +@@ -804,8 +805,12 @@ + struct hlist_node *node; + + sk_for_each(sk, node, &raw_v4_htable[state->bucket]) +- if (sk->sk_family == PF_INET) ++ if (sk->sk_family == PF_INET) { ++ if (!ve_accessible(sk->owner_env, ++ get_exec_env())) ++ continue; + goto found; ++ } + } + sk = NULL; + found: +@@ -819,8 +824,13 @@ + do { + sk = sk_next(sk); + try_again: +- ; +- } while (sk && sk->sk_family != PF_INET); ++ if (!sk) ++ break; ++ if (sk->sk_family != PF_INET) ++ continue; ++ if (ve_accessible(sk->owner_env, get_exec_env())) ++ break; ++ } while (1); + + if (!sk && ++state->bucket < RAWV4_HTABLE_SIZE) { + sk = sk_head(&raw_v4_htable[state->bucket]); +@@ -919,13 +929,28 @@ + .release = seq_release_private, + }; + +-int __init raw_proc_init(void) ++static int raw_net_init(struct net *net) + { +- if (!proc_net_fops_create(&init_net, "raw", S_IRUGO, &raw_seq_fops)) ++ if (!proc_net_fops_create(net, "raw", S_IRUGO, &raw_seq_fops)) + return -ENOMEM; + return 0; + } + ++static void raw_net_exit(struct net *net) ++{ ++ proc_net_remove(net, "raw"); ++} ++ ++static struct pernet_operations raw_net_ops = { ++ .init = raw_net_init, ++ .exit = raw_net_exit, ++}; ++ ++int __init raw_proc_init(void) ++{ ++ return register_pernet_subsys(&raw_net_ops); ++} ++ + void __init raw_proc_exit(void) + { + proc_net_remove(&init_net, "raw"); +Index: kernel/net/ipv4/route.c +=================================================================== +--- kernel.orig/net/ipv4/route.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/route.c 2008-11-24 15:47:46.000000000 +0100 +@@ -71,6 +71,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -116,6 +117,8 @@ + + #define RT_GC_TIMEOUT (300*HZ) + ++int ip_rt_src_check = 1; ++ + static int ip_rt_min_delay = 2 * HZ; + static int ip_rt_max_delay = 10 * HZ; + static int ip_rt_max_size; +@@ -266,11 +269,28 @@ + rt_hash_code((__force u32)(__be32)(daddr),\ + (__force u32)(__be32)(saddr) ^ ((idx) << 5)) + ++void prepare_rt_cache(void) ++{ ++#ifdef CONFIG_VE ++ struct rtable *r; ++ int i; ++ ++ for (i = rt_hash_mask; i >= 0; i--) { ++ spin_lock_bh(rt_hash_lock_addr(i)); ++ for (r = rt_hash_table[i].chain; r; r = r->u.dst.rt_next) { ++ r->fl.owner_env = get_ve0(); ++ } ++ spin_unlock_bh(rt_hash_lock_addr(i)); ++ } ++#endif ++} ++ + #ifdef CONFIG_PROC_FS + struct rt_cache_iter_state { + int bucket; + }; + ++static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r); + static struct rtable *rt_cache_get_first(struct seq_file *seq) + { + struct rtable *r = NULL; +@@ -283,6 +303,8 @@ + break; + rcu_read_unlock_bh(); + } ++ if (r && !ve_accessible_strict(r->fl.owner_env, get_exec_env())) ++ return rt_cache_get_next(seq, r); + return rcu_dereference(r); + } + +@@ -290,6 +312,7 @@ + { + struct rt_cache_iter_state *st = seq->private; + ++loop: + r = r->u.dst.rt_next; + while (!r) { + rcu_read_unlock_bh(); +@@ -298,6 +321,8 @@ + rcu_read_lock_bh(); + r = rt_hash_table[st->bucket].chain; + } ++ if (r && !ve_accessible_strict(r->fl.owner_env, get_exec_env())) ++ goto loop; + return rcu_dereference(r); + } + +@@ -556,7 +581,8 @@ + (*(u16 *)&fl1->nl_u.ip4_u.tos ^ + *(u16 *)&fl2->nl_u.ip4_u.tos) | + (fl1->oif ^ fl2->oif) | +- (fl1->iif ^ fl2->iif)) == 0; ++ (fl1->iif ^ fl2->iif)) == 0 && ++ ve_accessible_strict(fl1->owner_env, fl2->owner_env); + } + + static void rt_check_expire(struct work_struct *work) +@@ -608,26 +634,105 @@ + schedule_delayed_work(&expires_work, ip_rt_gc_interval); + } + ++typedef unsigned long rt_flush_gen_t; ++ ++#ifdef CONFIG_VE ++ ++static rt_flush_gen_t rt_flush_gen; ++ ++/* called under rt_flush_lock */ ++static void set_rt_flush_required(struct ve_struct *env) ++{ ++ /* ++ * If the global generation rt_flush_gen is equal to G, then ++ * the pass considering entries labelled by G is yet to come. ++ */ ++ env->rt_flush_required = rt_flush_gen; ++} ++ ++static spinlock_t rt_flush_lock; ++static rt_flush_gen_t reset_rt_flush_required(void) ++{ ++ rt_flush_gen_t g; ++ ++ spin_lock_bh(&rt_flush_lock); ++ g = rt_flush_gen++; ++ spin_unlock_bh(&rt_flush_lock); ++ return g; ++} ++ ++static int check_rt_flush_required(struct ve_struct *env, rt_flush_gen_t gen) ++{ ++ /* can be checked without the lock */ ++ return env->rt_flush_required >= gen; ++} ++ ++#else ++ ++static void set_rt_flush_required(struct ve_struct *env) ++{ ++} ++ ++static rt_flush_gen_t reset_rt_flush_required(void) ++{ ++ return 0; ++} ++ ++#endif ++ + /* This can run from both BH and non-BH contexts, the latter + * in the case of a forced flush event. + */ + static void rt_run_flush(unsigned long dummy) + { + int i; +- struct rtable *rth, *next; ++ struct rtable * rth, * next; ++ struct rtable * tail; ++ rt_flush_gen_t gen; + + rt_deadline = 0; + + get_random_bytes(&rt_hash_rnd, 4); + ++ gen = reset_rt_flush_required(); ++ + for (i = rt_hash_mask; i >= 0; i--) { ++#ifdef CONFIG_VE ++ struct rtable ** prev, * p; ++ ++ spin_lock_bh(rt_hash_lock_addr(i)); ++ rth = rt_hash_table[i].chain; ++ ++ /* defer releasing the head of the list after spin_unlock */ ++ for (tail = rth; tail; tail = tail->u.dst.rt_next) ++ if (!check_rt_flush_required(tail->fl.owner_env, gen)) ++ break; ++ if (rth != tail) ++ rt_hash_table[i].chain = tail; ++ ++ /* call rt_free on entries after the tail requiring flush */ ++ prev = &rt_hash_table[i].chain; ++ for (p = *prev; p; p = next) { ++ next = p->u.dst.rt_next; ++ if (!check_rt_flush_required(p->fl.owner_env, gen)) { ++ prev = &p->u.dst.rt_next; ++ } else { ++ *prev = next; ++ rt_free(p); ++ } ++ } ++ ++#else + spin_lock_bh(rt_hash_lock_addr(i)); + rth = rt_hash_table[i].chain; + if (rth) + rt_hash_table[i].chain = NULL; ++ tail = NULL; ++ ++#endif + spin_unlock_bh(rt_hash_lock_addr(i)); + +- for (; rth; rth = next) { ++ for (; rth != tail; rth = next) { + next = rth->u.dst.rt_next; + rt_free(rth); + } +@@ -663,6 +768,8 @@ + delay = tmo; + } + ++ set_rt_flush_required(get_exec_env()); ++ + if (delay <= 0) { + spin_unlock_bh(&rt_flush_lock); + rt_run_flush(0); +@@ -678,9 +785,30 @@ + + static void rt_secret_rebuild(unsigned long dummy) + { ++ int i; ++ struct rtable *rth, *next; + unsigned long now = jiffies; + +- rt_cache_flush(0); ++ spin_lock_bh(&rt_flush_lock); ++ del_timer(&rt_flush_timer); ++ spin_unlock_bh(&rt_flush_lock); ++ ++ rt_deadline = 0; ++ get_random_bytes(&rt_hash_rnd, 4); ++ ++ for (i = rt_hash_mask; i >= 0; i--) { ++ spin_lock_bh(rt_hash_lock_addr(i)); ++ rth = rt_hash_table[i].chain; ++ if (rth) ++ rt_hash_table[i].chain = NULL; ++ spin_unlock_bh(rt_hash_lock_addr(i)); ++ ++ for (; rth; rth = next) { ++ next = rth->u.dst.rt_next; ++ rt_free(rth); ++ } ++ } ++ + mod_timer(&rt_secret_timer, now + ip_rt_secret_interval); + } + +@@ -1026,6 +1154,9 @@ + __be32 skeys[2] = { saddr, 0 }; + int ikeys[2] = { dev->ifindex, 0 }; + struct netevent_redirect netevent; ++ struct ve_struct *ve; ++ ++ ve = get_exec_env(); + + if (!in_dev) + return; +@@ -1057,6 +1188,10 @@ + if (rth->fl.fl4_dst != daddr || + rth->fl.fl4_src != skeys[i] || + rth->fl.oif != ikeys[k] || ++#ifdef CONFIG_VE ++ !ve_accessible_strict(rth->fl.owner_env, ++ ve) || ++#endif + rth->fl.iif != 0) { + rthp = &rth->u.dst.rt_next; + continue; +@@ -1095,6 +1230,9 @@ + rt->u.dst.neighbour = NULL; + rt->u.dst.hh = NULL; + rt->u.dst.xfrm = NULL; ++#ifdef CONFIG_VE ++ rt->fl.owner_env = ve; ++#endif + + rt->rt_flags |= RTCF_REDIRECTED; + +@@ -1389,8 +1527,9 @@ + { + struct rtable *rt = (struct rtable *) dst; + struct in_device *idev = rt->idev; +- if (dev != init_net.loopback_dev && idev && idev->dev == dev) { +- struct in_device *loopback_idev = in_dev_get(init_net.loopback_dev); ++ if (dev != dev->nd_net->loopback_dev && idev && idev->dev == dev) { ++ struct in_device *loopback_idev = ++ in_dev_get(dev->nd_net->loopback_dev); + if (loopback_idev) { + rt->idev = loopback_idev; + in_dev_put(idev); +@@ -1540,9 +1679,12 @@ + #ifdef CONFIG_NET_CLS_ROUTE + rth->u.dst.tclassid = itag; + #endif ++#ifdef CONFIG_VE ++ rth->fl.owner_env = get_exec_env(); ++#endif + rth->rt_iif = + rth->fl.iif = dev->ifindex; +- rth->u.dst.dev = init_net.loopback_dev; ++ rth->u.dst.dev = get_exec_env()->ve_ns->net_ns->loopback_dev; + dev_hold(rth->u.dst.dev); + rth->idev = in_dev_get(rth->u.dst.dev); + rth->fl.oif = 0; +@@ -1678,6 +1820,9 @@ + rth->fl.fl4_src = saddr; + rth->rt_src = saddr; + rth->rt_gateway = daddr; ++#ifdef CONFIG_VE ++ rth->fl.owner_env = get_exec_env(); ++#endif + rth->rt_iif = + rth->fl.iif = in_dev->dev->ifindex; + rth->u.dst.dev = (out_dev)->dev; +@@ -1799,7 +1944,7 @@ + if (res.type == RTN_LOCAL) { + int result; + result = fib_validate_source(saddr, daddr, tos, +- init_net.loopback_dev->ifindex, ++ get_exec_env()->ve_ns->net_ns->loopback_dev->ifindex, + dev, &spec_dst, &itag); + if (result < 0) + goto martian_source; +@@ -1861,11 +2006,14 @@ + #endif + rth->rt_iif = + rth->fl.iif = dev->ifindex; +- rth->u.dst.dev = init_net.loopback_dev; ++ rth->u.dst.dev = get_exec_env()->ve_ns->net_ns->loopback_dev; + dev_hold(rth->u.dst.dev); + rth->idev = in_dev_get(rth->u.dst.dev); + rth->rt_gateway = daddr; + rth->rt_spec_dst= spec_dst; ++#ifdef CONFIG_VE ++ rth->fl.owner_env = get_exec_env(); ++#endif + rth->u.dst.input= ip_local_deliver; + rth->rt_flags = flags|RTCF_LOCAL; + if (res.type == RTN_UNREACHABLE) { +@@ -1933,6 +2081,9 @@ + rth->fl.iif == iif && + rth->fl.oif == 0 && + rth->fl.mark == skb->mark && ++#ifdef CONFIG_VE ++ rth->fl.owner_env == get_exec_env() && ++#endif + rth->fl.fl4_tos == tos) { + dst_use(&rth->u.dst, jiffies); + RT_CACHE_STAT_INC(in_hit); +@@ -2050,6 +2201,9 @@ + rth->fl.mark = oldflp->mark; + rth->rt_dst = fl->fl4_dst; + rth->rt_src = fl->fl4_src; ++#ifdef CONFIG_VE ++ rth->fl.owner_env = get_exec_env(); ++#endif + rth->rt_iif = oldflp->oif ? : dev_out->ifindex; + /* get references to the devices that are to be hold by the routing + cache entry */ +@@ -2121,6 +2275,8 @@ + + static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net_device * loopback_dev = net->loopback_dev; + u32 tos = RT_FL_TOS(oldflp); + struct flowi fl = { .nl_u = { .ip4_u = + { .daddr = oldflp->fl4_dst, +@@ -2131,7 +2287,7 @@ + RT_SCOPE_UNIVERSE), + } }, + .mark = oldflp->mark, +- .iif = init_net.loopback_dev->ifindex, ++ .iif = loopback_dev->ifindex, + .oif = oldflp->oif }; + struct fib_result res; + unsigned flags = 0; +@@ -2152,10 +2308,13 @@ + ZERONET(oldflp->fl4_src)) + goto out; + +- /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ +- dev_out = ip_dev_find(oldflp->fl4_src); +- if (dev_out == NULL) +- goto out; ++ if (ip_rt_src_check) { ++ /* It is equivalent to ++ inet_addr_type(saddr) == RTN_LOCAL */ ++ dev_out = ip_dev_find(oldflp->fl4_src); ++ if (dev_out == NULL) ++ goto out; ++ } + + /* I removed check for oif == dev_out->oif here. + It was wrong for two reasons: +@@ -2182,6 +2341,12 @@ + Luckily, this hack is good workaround. + */ + ++ if (dev_out == NULL) { ++ dev_out = ip_dev_find(oldflp->fl4_src); ++ if (dev_out == NULL) ++ goto out; ++ } ++ + fl.oif = dev_out->ifindex; + goto make_route; + } +@@ -2192,7 +2357,7 @@ + + + if (oldflp->oif) { +- dev_out = dev_get_by_index(&init_net, oldflp->oif); ++ dev_out = dev_get_by_index(net, oldflp->oif); + err = -ENODEV; + if (dev_out == NULL) + goto out; +@@ -2225,9 +2390,9 @@ + fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK); + if (dev_out) + dev_put(dev_out); +- dev_out = init_net.loopback_dev; ++ dev_out = loopback_dev; + dev_hold(dev_out); +- fl.oif = init_net.loopback_dev->ifindex; ++ fl.oif = loopback_dev->ifindex; + res.type = RTN_LOCAL; + flags |= RTCF_LOCAL; + goto make_route; +@@ -2272,7 +2437,7 @@ + fl.fl4_src = fl.fl4_dst; + if (dev_out) + dev_put(dev_out); +- dev_out = init_net.loopback_dev; ++ dev_out = loopback_dev; + dev_hold(dev_out); + fl.oif = dev_out->ifindex; + if (res.fi) +@@ -2326,6 +2491,7 @@ + rth->fl.iif == 0 && + rth->fl.oif == flp->oif && + rth->fl.mark == flp->mark && ++ ve_accessible_strict(rth->fl.owner_env, get_exec_env()) && + !((rth->fl.fl4_tos ^ flp->fl4_tos) & + (IPTOS_RT_MASK | RTO_ONLINK))) { + dst_use(&rth->u.dst, jiffies); +@@ -2569,7 +2735,7 @@ + if (iif) { + struct net_device *dev; + +- dev = __dev_get_by_index(&init_net, iif); ++ dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, iif); + if (dev == NULL) { + err = -ENODEV; + goto errout_free; +@@ -2661,22 +2827,22 @@ + } + + #ifdef CONFIG_SYSCTL +-static int flush_delay; ++int ipv4_flush_delay; + +-static int ipv4_sysctl_rtcache_flush(ctl_table *ctl, int write, ++int ipv4_sysctl_rtcache_flush(ctl_table *ctl, int write, + struct file *filp, void __user *buffer, + size_t *lenp, loff_t *ppos) + { + if (write) { + proc_dointvec(ctl, write, filp, buffer, lenp, ppos); +- rt_cache_flush(flush_delay); ++ rt_cache_flush(ipv4_flush_delay); + return 0; + } + + return -EINVAL; + } + +-static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, ++int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, + int __user *name, + int nlen, + void __user *oldval, +@@ -2697,7 +2863,7 @@ + { + .ctl_name = NET_IPV4_ROUTE_FLUSH, + .procname = "flush", +- .data = &flush_delay, ++ .data = &ipv4_flush_delay, + .maxlen = sizeof(int), + .mode = 0200, + .proc_handler = &ipv4_sysctl_rtcache_flush, +@@ -2984,7 +3150,7 @@ + struct proc_dir_entry *rtstat_pde = NULL; /* keep gcc happy */ + if (!proc_net_fops_create(&init_net, "rt_cache", S_IRUGO, &rt_cache_seq_fops) || + !(rtstat_pde = create_proc_entry("rt_cache", S_IRUGO, +- init_net.proc_net_stat))) { ++ init_net.proc_net_stat))) { + return -ENOMEM; + } + rtstat_pde->proc_fops = &rt_cpu_seq_fops; +Index: kernel/net/ipv4/sysctl_net_ipv4.c +=================================================================== +--- kernel.orig/net/ipv4/sysctl_net_ipv4.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/sysctl_net_ipv4.c 2008-11-24 15:47:46.000000000 +0100 +@@ -24,6 +24,9 @@ + /* From af_inet.c */ + extern int sysctl_ip_nonlocal_bind; + ++int sysctl_tcp_use_sg = 1; ++EXPORT_SYMBOL(sysctl_tcp_use_sg); ++ + #ifdef CONFIG_SYSCTL + static int zero; + static int tcp_retr1_max = 255; +@@ -35,7 +38,6 @@ + + #ifdef CONFIG_SYSCTL + +-static + int ipv4_sysctl_forward(ctl_table *ctl, int write, struct file * filp, + void __user *buffer, size_t *lenp, loff_t *ppos) + { +@@ -50,7 +52,7 @@ + return ret; + } + +-static int ipv4_sysctl_forward_strategy(ctl_table *table, ++int ipv4_sysctl_forward_strategy(ctl_table *table, + int __user *name, int nlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen) +@@ -292,7 +294,7 @@ + { + .ctl_name = NET_IPV4_FORWARD, + .procname = "ip_forward", +- .data = &IPV4_DEVCONF_ALL(FORWARDING), ++ .data = &IPV4_DEVCONF(ipv4_devconf, FORWARDING), + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &ipv4_sysctl_forward, +@@ -548,6 +550,13 @@ + .mode = 0644, + .proc_handler = &proc_dointvec + }, ++ { ++ .procname = "tcp_use_sg", ++ .data = &sysctl_tcp_use_sg, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, + + #endif + { +@@ -748,6 +757,20 @@ + .extra1 = &zero + }, + { ++ .procname = "tcp_max_tw_kmem_fraction", ++ .data = &sysctl_tcp_max_tw_kmem_fraction, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, ++ { ++ .procname = "tcp_max_tw_buckets_ub", ++ .data = &sysctl_tcp_max_tw_buckets_ub, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, ++ { + .ctl_name = NET_TCP_NO_METRICS_SAVE, + .procname = "tcp_no_metrics_save", + .data = &sysctl_tcp_nometrics_save, +Index: kernel/net/ipv4/tcp.c +=================================================================== +--- kernel.orig/net/ipv4/tcp.c 2008-11-24 14:17:57.000000000 +0100 ++++ kernel/net/ipv4/tcp.c 2008-11-24 15:47:46.000000000 +0100 +@@ -266,6 +266,10 @@ + #include + #include + ++#include ++#include ++#include ++ + #include + #include + +@@ -323,6 +327,7 @@ + unsigned int mask; + struct sock *sk = sock->sk; + struct tcp_sock *tp = tcp_sk(sk); ++ int check_send_space; + + poll_wait(file, sk->sk_sleep, wait); + if (sk->sk_state == TCP_LISTEN) +@@ -337,6 +342,21 @@ + if (sk->sk_err) + mask = POLLERR; + ++ check_send_space = 1; ++#ifdef CONFIG_BEANCOUNTERS ++ if (!(sk->sk_shutdown & SEND_SHUTDOWN) && sock_has_ubc(sk)) { ++ unsigned long size; ++ size = MAX_TCP_HEADER + tp->mss_cache; ++ if (size > SOCK_MIN_UBCSPACE) ++ size = SOCK_MIN_UBCSPACE; ++ size = skb_charge_size(size); ++ if (ub_sock_makewres_tcp(sk, size)) { ++ check_send_space = 0; ++ ub_sock_sndqueueadd_tcp(sk, size); ++ } ++ } ++#endif ++ + /* + * POLLHUP is certainly not done right. But poll() doesn't + * have a notion of HUP in just one direction, and for a +@@ -380,7 +400,7 @@ + sock_flag(sk, SOCK_URGINLINE) || !tp->urg_data)) + mask |= POLLIN | POLLRDNORM; + +- if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { ++ if (check_send_space && !(sk->sk_shutdown & SEND_SHUTDOWN)) { + if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) { + mask |= POLLOUT | POLLWRNORM; + } else { /* send SIGIO later */ +@@ -531,16 +551,23 @@ + int copy, i, can_coalesce; + int offset = poffset % PAGE_SIZE; + int size = min_t(size_t, psize, PAGE_SIZE - offset); ++ unsigned long chargesize = 0; + + if (!tcp_send_head(sk) || (copy = size_goal - skb->len) <= 0) { + new_segment: ++ chargesize = 0; + if (!sk_stream_memory_free(sk)) + goto wait_for_sndbuf; + ++ chargesize = skb_charge_size(MAX_TCP_HEADER + ++ tp->mss_cache); ++ if (ub_sock_getwres_tcp(sk, chargesize) < 0) ++ goto wait_for_ubspace; + skb = sk_stream_alloc_pskb(sk, 0, 0, + sk->sk_allocation); + if (!skb) + goto wait_for_memory; ++ ub_skb_set_charge(skb, sk, chargesize, UB_TCPSNDBUF); + + skb_entail(sk, skb); + copy = size_goal; +@@ -596,10 +623,15 @@ + wait_for_sndbuf: + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + wait_for_memory: ++ ub_sock_retwres_tcp(sk, chargesize, ++ skb_charge_size(MAX_TCP_HEADER + tp->mss_cache)); ++ chargesize = 0; ++wait_for_ubspace: + if (copied) + tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); + +- if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) ++ err = __sk_stream_wait_memory(sk, &timeo, chargesize); ++ if (err != 0) + goto do_error; + + mss_now = tcp_current_mss(sk, !(flags&MSG_OOB)); +@@ -636,12 +668,8 @@ + return res; + } + +-#define TCP_PAGE(sk) (sk->sk_sndmsg_page) +-#define TCP_OFF(sk) (sk->sk_sndmsg_off) +- +-static inline int select_size(struct sock *sk) ++static inline int select_size(struct sock *sk, struct tcp_sock *tp) + { +- struct tcp_sock *tp = tcp_sk(sk); + int tmp = tp->mss_cache; + + if (sk->sk_route_caps & NETIF_F_SG) { +@@ -700,6 +728,7 @@ + while (--iovlen >= 0) { + int seglen = iov->iov_len; + unsigned char __user *from = iov->iov_base; ++ unsigned long chargesize = 0; + + iov++; + +@@ -710,18 +739,27 @@ + + if (!tcp_send_head(sk) || + (copy = size_goal - skb->len) <= 0) { ++ unsigned long size; + + new_segment: + /* Allocate new segment. If the interface is SG, + * allocate skb fitting to single page. + */ ++ chargesize = 0; + if (!sk_stream_memory_free(sk)) + goto wait_for_sndbuf; + +- skb = sk_stream_alloc_pskb(sk, select_size(sk), +- 0, sk->sk_allocation); ++ size = select_size(sk, tp); ++ chargesize = skb_charge_size(MAX_TCP_HEADER + ++ size); ++ if (ub_sock_getwres_tcp(sk, chargesize) < 0) ++ goto wait_for_ubspace; ++ skb = sk_stream_alloc_pskb(sk, size, 0, ++ sk->sk_allocation); + if (!skb) + goto wait_for_memory; ++ ub_skb_set_charge(skb, sk, chargesize, ++ UB_TCPSNDBUF); + + /* + * Check whether we can use HW checksum. +@@ -767,6 +805,7 @@ + } else if (page) { + if (off == PAGE_SIZE) { + put_page(page); ++ ub_sock_tcp_detachpage(sk); + TCP_PAGE(sk) = page = NULL; + off = 0; + } +@@ -780,6 +819,9 @@ + goto wait_for_memory; + + if (!page) { ++ chargesize = PAGE_SIZE; ++ if (ub_sock_tcp_chargepage(sk) < 0) ++ goto wait_for_ubspace; + /* Allocate new cache page. */ + if (!(page = sk_stream_alloc_page(sk))) + goto wait_for_memory; +@@ -811,7 +853,8 @@ + } else if (off + copy < PAGE_SIZE) { + get_page(page); + TCP_PAGE(sk) = page; +- } ++ } else ++ ub_sock_tcp_detachpage(sk); + } + + TCP_OFF(sk) = off + copy; +@@ -842,10 +885,15 @@ + wait_for_sndbuf: + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + wait_for_memory: ++ ub_sock_retwres_tcp(sk, chargesize, ++ skb_charge_size(MAX_TCP_HEADER+tp->mss_cache)); ++ chargesize = 0; ++wait_for_ubspace: + if (copied) + tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); + +- if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) ++ err = __sk_stream_wait_memory(sk, &timeo, chargesize); ++ if (err != 0) + goto do_error; + + mss_now = tcp_current_mss(sk, !(flags&MSG_OOB)); +@@ -945,7 +993,18 @@ + #if TCP_DEBUG + struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); + +- BUG_TRAP(!skb || before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)); ++ if (!(skb==NULL || before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq))) { ++ printk("KERNEL: assertion: skb==NULL || " ++ "before(tp->copied_seq, skb->end_seq)\n"); ++ printk("VE%u pid %d comm %.16s\n", ++ (get_exec_env() ? VEID(get_exec_env()) : 0), ++ current->pid, current->comm); ++ printk("copied=%d, copied_seq=%d, rcv_nxt=%d\n", copied, ++ tp->copied_seq, tp->rcv_nxt); ++ printk("skb->len=%d, skb->seq=%d, skb->end_seq=%d\n", ++ skb->len, TCP_SKB_CB(skb)->seq, ++ TCP_SKB_CB(skb)->end_seq); ++ } + #endif + + if (inet_csk_ack_scheduled(sk)) { +@@ -1199,7 +1258,23 @@ + goto found_ok_skb; + if (tcp_hdr(skb)->fin) + goto found_fin_ok; +- BUG_TRAP(flags & MSG_PEEK); ++ if (!(flags & MSG_PEEK)) { ++ printk("KERNEL: assertion: flags&MSG_PEEK\n"); ++ printk("VE%u pid %d comm %.16s\n", ++ (get_exec_env() ? ++ VEID(get_exec_env()) : 0), ++ current->pid, current->comm); ++ printk("flags=0x%x, len=%d, copied_seq=%d, " ++ "rcv_nxt=%d\n", flags, ++ (int)len, tp->copied_seq, ++ tp->rcv_nxt); ++ printk("skb->len=%d, *seq=%d, skb->seq=%d, " ++ "skb->end_seq=%d, offset=%d\n", ++ skb->len, *seq, ++ TCP_SKB_CB(skb)->seq, ++ TCP_SKB_CB(skb)->end_seq, ++ offset); ++ } + skb = skb->next; + } while (skb != (struct sk_buff *)&sk->sk_receive_queue); + +@@ -1262,8 +1337,19 @@ + + tp->ucopy.len = len; + +- BUG_TRAP(tp->copied_seq == tp->rcv_nxt || +- (flags & (MSG_PEEK | MSG_TRUNC))); ++ if (!(tp->copied_seq == tp->rcv_nxt || ++ (flags&(MSG_PEEK|MSG_TRUNC)))) { ++ printk("KERNEL: assertion: tp->copied_seq == " ++ "tp->rcv_nxt || ...\n"); ++ printk("VE%u pid %d comm %.16s\n", ++ (get_exec_env() ? ++ VEID(get_exec_env()) : 0), ++ current->pid, current->comm); ++ printk("flags=0x%x, len=%d, copied_seq=%d, " ++ "rcv_nxt=%d\n", flags, ++ (int)len, tp->copied_seq, ++ tp->rcv_nxt); ++ } + + /* Ugly... If prequeue is not empty, we have to + * process it before releasing socket, otherwise +@@ -1639,7 +1725,7 @@ + state = sk->sk_state; + sock_hold(sk); + sock_orphan(sk); +- atomic_inc(sk->sk_prot->orphan_count); ++ ub_inc_orphan_count(sk); + + /* It is the last release_sock in its life. It will remove backlog. */ + release_sock(sk); +@@ -1689,12 +1775,19 @@ + } + } + if (sk->sk_state != TCP_CLOSE) { ++ int orphans = ub_get_orphan_count(sk); ++ + sk_stream_mem_reclaim(sk); +- if (tcp_too_many_orphans(sk, +- atomic_read(sk->sk_prot->orphan_count))) { +- if (net_ratelimit()) ++ if (ub_too_many_orphans(sk, orphans)) { ++ if (net_ratelimit()) { ++ int ubid = 0; ++#ifdef CONFIG_USER_RESOURCE ++ ubid = sock_has_ubc(sk) ? ++ top_beancounter(sock_bc(sk)->ub)->ub_uid : 0; ++#endif + printk(KERN_INFO "TCP: too many of orphaned " +- "sockets\n"); ++ "sockets (%d in CT%d)\n", orphans, ubid); ++ } + tcp_set_state(sk, TCP_CLOSE); + tcp_send_active_reset(sk, GFP_ATOMIC); + NET_INC_STATS_BH(LINUX_MIB_TCPABORTONMEMORY); +@@ -1770,6 +1863,7 @@ + tp->snd_ssthresh = 0x7fffffff; + tp->snd_cwnd_cnt = 0; + tp->bytes_acked = 0; ++ tp->advmss = 65535; + tcp_set_ca_state(sk, TCP_CA_Open); + tcp_clear_retrans(tp); + inet_csk_delack_init(sk); +@@ -2412,6 +2506,7 @@ + EXPORT_SYMBOL_GPL(tcp_done); + + extern void __skb_cb_too_small_for_tcp(int, int); ++extern unsigned int nr_free_lowpages(void); + extern struct tcp_congestion_ops tcp_reno; + + static __initdata unsigned long thash_entries; +@@ -2437,7 +2532,7 @@ + tcp_hashinfo.bind_bucket_cachep = + kmem_cache_create("tcp_bind_bucket", + sizeof(struct inet_bind_bucket), 0, +- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); ++ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_UBC, NULL); + + /* Size and allocate the main established and bind bucket + * hash tables. +@@ -2505,6 +2600,11 @@ + sysctl_tcp_mem[1] = limit; + sysctl_tcp_mem[2] = sysctl_tcp_mem[0] * 2; + ++ if (sysctl_tcp_mem[2] - sysctl_tcp_mem[1] > 4096) ++ sysctl_tcp_mem[1] = sysctl_tcp_mem[2] - 4096; ++ if (sysctl_tcp_mem[1] - sysctl_tcp_mem[0] > 4096) ++ sysctl_tcp_mem[0] = sysctl_tcp_mem[1] - 4096; ++ + /* Set per-socket limits to no more than 1/128 the pressure threshold */ + limit = ((unsigned long)sysctl_tcp_mem[1]) << (PAGE_SHIFT - 7); + max_share = min(4UL*1024*1024, limit); +Index: kernel/net/ipv4/tcp_input.c +=================================================================== +--- kernel.orig/net/ipv4/tcp_input.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/tcp_input.c 2008-11-24 15:47:46.000000000 +0100 +@@ -72,6 +72,8 @@ + #include + #include + ++#include ++ + int sysctl_tcp_timestamps __read_mostly = 1; + int sysctl_tcp_window_scaling __read_mostly = 1; + int sysctl_tcp_sack __read_mostly = 1; +@@ -310,7 +312,7 @@ + /* Check #1 */ + if (tp->rcv_ssthresh < tp->window_clamp && + (int)tp->rcv_ssthresh < tcp_space(sk) && +- !tcp_memory_pressure) { ++ ub_tcp_rmem_allows_expand(sk)) { + int incr; + + /* Check #2. Increase window, if skb with such overhead +@@ -379,6 +381,8 @@ + + tp->rcv_ssthresh = min(tp->rcv_ssthresh, tp->window_clamp); + tp->snd_cwnd_stamp = tcp_time_stamp; ++ ++ ub_tcp_update_maxadvmss(sk); + } + + /* 5. Recalculate window clamp after socket hit its memory bounds. */ +@@ -391,7 +395,7 @@ + + if (sk->sk_rcvbuf < sysctl_tcp_rmem[2] && + !(sk->sk_userlocks & SOCK_RCVBUF_LOCK) && +- !tcp_memory_pressure && ++ !ub_tcp_memory_pressure(sk) && + atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) { + sk->sk_rcvbuf = min(atomic_read(&sk->sk_rmem_alloc), + sysctl_tcp_rmem[2]); +@@ -3747,7 +3751,7 @@ + !sk_stream_rmem_schedule(sk, skb))) { + if (tcp_prune_queue(sk) < 0 || + !sk_stream_rmem_schedule(sk, skb)) +- goto drop; ++ goto drop_part; + } + sk_stream_set_owner_r(skb, sk); + __skb_queue_tail(&sk->sk_receive_queue, skb); +@@ -3791,6 +3795,12 @@ + drop: + __kfree_skb(skb); + return; ++ ++drop_part: ++ if (after(tp->copied_seq, tp->rcv_nxt)) ++ tp->rcv_nxt = tp->copied_seq; ++ __kfree_skb(skb); ++ return; + } + + /* Out of window. F.e. zero window probe. */ +@@ -3962,6 +3972,10 @@ + nskb = alloc_skb(copy+header, GFP_ATOMIC); + if (!nskb) + return; ++ if (ub_tcprcvbuf_charge_forced(skb->sk, nskb) < 0) { ++ kfree_skb(nskb); ++ return; ++ } + + skb_set_mac_header(nskb, skb_mac_header(skb) - skb->head); + skb_set_network_header(nskb, (skb_network_header(skb) - +@@ -4063,7 +4077,7 @@ + + if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) + tcp_clamp_window(sk); +- else if (tcp_memory_pressure) ++ else if (ub_tcp_memory_pressure(sk)) + tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); + + tcp_collapse_ofo_queue(sk); +@@ -4142,7 +4156,7 @@ + return 0; + + /* If we are under global TCP memory pressure, do not expand. */ +- if (tcp_memory_pressure) ++ if (ub_tcp_memory_pressure(sk)) + return 0; + + /* If we are under soft global TCP memory pressure, do not expand. */ +@@ -4587,6 +4601,10 @@ + + if ((int)skb->truesize > sk->sk_forward_alloc) + goto step5; ++ /* This is OK not to try to free memory here. ++ * Do this below on slow path. Den */ ++ if (ub_tcprcvbuf_charge(sk, skb) < 0) ++ goto step5; + + NET_INC_STATS_BH(LINUX_MIB_TCPHPHITS); + +Index: kernel/net/ipv4/tcp_ipv4.c +=================================================================== +--- kernel.orig/net/ipv4/tcp_ipv4.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/tcp_ipv4.c 2008-11-24 15:47:46.000000000 +0100 +@@ -56,6 +56,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -73,6 +74,8 @@ + #include + #include + ++#include ++ + #include + #include + #include +@@ -720,7 +723,8 @@ + struct tcp_timewait_sock *tcptw = tcp_twsk(sk); + + tcp_v4_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, +- tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, ++ tcptw->tw_rcv_wnd >> ++ (tw->tw_rcv_wscale & TW_WSCALE_MASK), + tcptw->tw_ts_recent); + + inet_twsk_put(tw); +@@ -1245,6 +1249,7 @@ + .destructor = tcp_v4_reqsk_destructor, + .send_reset = tcp_v4_send_reset, + }; ++EXPORT_SYMBOL_GPL(tcp_request_sock_ops); + + #ifdef CONFIG_TCP_MD5SIG + static struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { +@@ -1555,6 +1560,10 @@ + int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) + { + struct sock *rsk; ++ struct user_beancounter *ub; ++ ++ ub = set_exec_ub(sock_bc(sk)->ub); ++ + #ifdef CONFIG_TCP_MD5SIG + /* + * We really want to reject the packet as early as possible +@@ -1573,7 +1582,7 @@ + goto reset; + } + TCP_CHECK_TIMER(sk); +- return 0; ++ goto restore_context; + } + + if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb)) +@@ -1589,7 +1598,7 @@ + rsk = nsk; + goto reset; + } +- return 0; ++ goto restore_context; + } + } + +@@ -1599,6 +1608,9 @@ + goto reset; + } + TCP_CHECK_TIMER(sk); ++ ++restore_context: ++ (void)set_exec_ub(ub); + return 0; + + reset: +@@ -1610,7 +1622,7 @@ + * might be destroyed here. This current version compiles correctly, + * but you have been warned. + */ +- return 0; ++ goto restore_context; + + csum_err: + TCP_INC_STATS_BH(TCP_MIB_INERRS); +@@ -1870,6 +1882,8 @@ + tp->snd_cwnd_clamp = ~0; + tp->mss_cache = 536; + ++ tp->advmss = 65535; /* max value */ ++ + tp->reordering = sysctl_tcp_reordering; + icsk->icsk_ca_ops = &tcp_init_congestion_ops; + +@@ -1931,6 +1945,8 @@ + * If sendmsg cached page exists, toss it. + */ + if (sk->sk_sndmsg_page) { ++ /* queue is empty, uncharge */ ++ ub_sock_tcp_detachpage(sk); + __free_page(sk->sk_sndmsg_page); + sk->sk_sndmsg_page = NULL; + } +@@ -1945,16 +1961,34 @@ + #ifdef CONFIG_PROC_FS + /* Proc filesystem TCP sock list dumping. */ + +-static inline struct inet_timewait_sock *tw_head(struct hlist_head *head) ++static inline struct inet_timewait_sock *tw_head(struct hlist_head *head, ++ envid_t veid) + { +- return hlist_empty(head) ? NULL : +- list_entry(head->first, struct inet_timewait_sock, tw_node); ++ struct inet_timewait_sock *tw; ++ struct hlist_node *pos; ++ ++ if (hlist_empty(head)) ++ return NULL; ++ hlist_for_each_entry(tw, pos, head, tw_node) { ++ if (!ve_accessible_veid(tw->tw_owner_env, veid)) ++ continue; ++ return tw; ++ } ++ return NULL; + } + +-static inline struct inet_timewait_sock *tw_next(struct inet_timewait_sock *tw) ++static inline struct inet_timewait_sock * ++ tw_next(struct inet_timewait_sock *tw, envid_t veid) + { +- return tw->tw_node.next ? +- hlist_entry(tw->tw_node.next, typeof(*tw), tw_node) : NULL; ++ while (1) { ++ if (tw->tw_node.next == NULL) ++ return NULL; ++ tw = hlist_entry(tw->tw_node.next, typeof(*tw), tw_node); ++ if (!ve_accessible_veid(tw->tw_owner_env, veid)) ++ continue; ++ return tw; ++ } ++ return NULL; /* make compiler happy */ + } + + static void *listening_get_next(struct seq_file *seq, void *cur) +@@ -1963,7 +1997,9 @@ + struct hlist_node *node; + struct sock *sk = cur; + struct tcp_iter_state* st = seq->private; ++ struct ve_struct *ve; + ++ ve = get_exec_env(); + if (!sk) { + st->bucket = 0; + sk = sk_head(&tcp_hashinfo.listening_hash[0]); +@@ -2003,6 +2039,8 @@ + } + get_sk: + sk_for_each_from(sk, node) { ++ if (!ve_accessible(sk->owner_env, ve)) ++ continue; + if (sk->sk_family == st->family) { + cur = sk; + goto out; +@@ -2043,7 +2081,9 @@ + { + struct tcp_iter_state* st = seq->private; + void *rc = NULL; ++ struct ve_struct *ve; + ++ ve = get_exec_env(); + for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) { + struct sock *sk; + struct hlist_node *node; +@@ -2052,6 +2092,8 @@ + + read_lock_bh(lock); + sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) { ++ if (!ve_accessible(sk->owner_env, ve)) ++ continue; + if (sk->sk_family != st->family) { + continue; + } +@@ -2061,6 +2103,8 @@ + st->state = TCP_SEQ_STATE_TIME_WAIT; + inet_twsk_for_each(tw, node, + &tcp_hashinfo.ehash[st->bucket].twchain) { ++ if (!ve_accessible_veid(tw->tw_owner_env, VEID(ve))) ++ continue; + if (tw->tw_family != st->family) { + continue; + } +@@ -2080,16 +2124,17 @@ + struct inet_timewait_sock *tw; + struct hlist_node *node; + struct tcp_iter_state* st = seq->private; ++ struct ve_struct *ve; + ++ ve = get_exec_env(); + ++st->num; + + if (st->state == TCP_SEQ_STATE_TIME_WAIT) { + tw = cur; +- tw = tw_next(tw); ++ tw = tw_next(tw, VEID(ve)); + get_tw: +- while (tw && tw->tw_family != st->family) { +- tw = tw_next(tw); +- } ++ while (tw && tw->tw_family != st->family) ++ tw = tw_next(tw, VEID(ve)); + if (tw) { + cur = tw; + goto out; +@@ -2108,12 +2153,14 @@ + sk = sk_next(sk); + + sk_for_each_from(sk, node) { ++ if (!ve_accessible(sk->owner_env, ve)) ++ continue; + if (sk->sk_family == st->family) + goto found; + } + + st->state = TCP_SEQ_STATE_TIME_WAIT; +- tw = tw_head(&tcp_hashinfo.ehash[st->bucket].twchain); ++ tw = tw_head(&tcp_hashinfo.ehash[st->bucket].twchain, VEID(ve)); + goto get_tw; + found: + cur = sk; +@@ -2255,7 +2302,7 @@ + afinfo->seq_fops->llseek = seq_lseek; + afinfo->seq_fops->release = seq_release_private; + +- p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops); ++ p = proc_net_fops_create(current->nsproxy->net_ns, afinfo->name, S_IRUGO, afinfo->seq_fops); + if (p) + p->data = afinfo; + else +@@ -2267,7 +2314,8 @@ + { + if (!afinfo) + return; +- proc_net_remove(&init_net, afinfo->name); ++ ++ proc_net_remove(current->nsproxy->net_ns, afinfo->name); + memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); + } + +@@ -2406,15 +2454,30 @@ + .seq_fops = &tcp4_seq_fops, + }; + +-int __init tcp4_proc_init(void) ++static int tcp4_proc_net_init(struct net *net) + { + return tcp_proc_register(&tcp4_seq_afinfo); + } + +-void tcp4_proc_exit(void) ++static void tcp4_proc_net_exit(struct net *net) + { + tcp_proc_unregister(&tcp4_seq_afinfo); + } ++ ++static struct pernet_operations tcp4_proc_net_ops = { ++ .init = tcp4_proc_net_init, ++ .exit = tcp4_proc_net_exit, ++}; ++ ++int __init tcp4_proc_init(void) ++{ ++ return register_pernet_subsys(&tcp4_proc_net_ops); ++} ++ ++void tcp4_proc_exit(void) ++{ ++ unregister_pernet_subsys(&tcp4_proc_net_ops); ++} + #endif /* CONFIG_PROC_FS */ + + DEFINE_PROTO_INUSE(tcp) +@@ -2463,6 +2526,87 @@ + panic("Failed to create the TCP control socket.\n"); + } + ++#ifdef CONFIG_VE ++static void tcp_kill_ve_onesk(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ /* Check the assumed state of the socket. */ ++ if (!sock_flag(sk, SOCK_DEAD)) { ++ static int printed; ++invalid: ++ if (!printed) ++ printk(KERN_DEBUG "Killing sk: dead %d, state %d, " ++ "wrseq %u unseq %u, wrqu %d.\n", ++ sock_flag(sk, SOCK_DEAD), sk->sk_state, ++ tp->write_seq, tp->snd_una, ++ !skb_queue_empty(&sk->sk_write_queue)); ++ printed = 1; ++ return; ++ } ++ ++ tcp_send_active_reset(sk, GFP_ATOMIC); ++ switch (sk->sk_state) { ++ case TCP_FIN_WAIT1: ++ case TCP_CLOSING: ++ /* In these 2 states the peer may want us to retransmit ++ * some data and/or FIN. Entering "resetting mode" ++ * instead. ++ */ ++ tcp_time_wait(sk, TCP_CLOSE, 0); ++ break; ++ case TCP_FIN_WAIT2: ++ /* By some reason the socket may stay in this state ++ * without turning into a TW bucket. Fix it. ++ */ ++ tcp_time_wait(sk, TCP_FIN_WAIT2, 0); ++ break; ++ case TCP_LAST_ACK: ++ /* Just jump into CLOSED state. */ ++ tcp_done(sk); ++ break; ++ default: ++ /* The socket must be already close()d. */ ++ goto invalid; ++ } ++} ++ ++void tcp_v4_kill_ve_sockets(struct ve_struct *envid) ++{ ++ struct inet_ehash_bucket *head; ++ int i; ++ ++ /* alive */ ++ local_bh_disable(); ++ head = tcp_hashinfo.ehash; ++ for (i = 0; i < tcp_hashinfo.ehash_size; i++) { ++ struct sock *sk; ++ struct hlist_node *node; ++ rwlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, i); ++more_work: ++ write_lock(lock); ++ sk_for_each(sk, node, &head[i].chain) { ++ if (ve_accessible_strict(sk->owner_env, envid)) { ++ sock_hold(sk); ++ write_unlock(lock); ++ ++ bh_lock_sock(sk); ++ /* sk might have disappeared from the hash before ++ * we got the lock */ ++ if (sk->sk_state != TCP_CLOSE) ++ tcp_kill_ve_onesk(sk); ++ bh_unlock_sock(sk); ++ sock_put(sk); ++ goto more_work; ++ } ++ } ++ write_unlock(lock); ++ } ++ local_bh_enable(); ++} ++EXPORT_SYMBOL(tcp_v4_kill_ve_sockets); ++#endif ++ + EXPORT_SYMBOL(ipv4_specific); + EXPORT_SYMBOL(tcp_hashinfo); + EXPORT_SYMBOL(tcp_prot); +Index: kernel/net/ipv4/tcp_minisocks.c +=================================================================== +--- kernel.orig/net/ipv4/tcp_minisocks.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/tcp_minisocks.c 2008-11-24 15:47:46.000000000 +0100 +@@ -28,6 +28,9 @@ + #include + #include + ++#include ++#include ++ + #ifdef CONFIG_SYSCTL + #define SYNC_INIT 0 /* let the user enable it */ + #else +@@ -36,6 +39,11 @@ + + int sysctl_tcp_syncookies __read_mostly = SYNC_INIT; + int sysctl_tcp_abort_on_overflow __read_mostly; ++int sysctl_tcp_max_tw_kmem_fraction __read_mostly = 384; ++int sysctl_tcp_max_tw_buckets_ub __read_mostly = 16536; ++ ++EXPORT_SYMBOL(sysctl_tcp_max_tw_kmem_fraction); ++EXPORT_SYMBOL(sysctl_tcp_max_tw_buckets_ub); + + struct inet_timewait_death_row tcp_death_row = { + .sysctl_max_tw_buckets = NR_FILE * 2, +@@ -51,6 +59,7 @@ + .twcal_hand = -1, + .twcal_timer = TIMER_INITIALIZER(inet_twdr_twcal_tick, 0, + (unsigned long)&tcp_death_row), ++ .ub_managed = 1, + }; + + EXPORT_SYMBOL_GPL(tcp_death_row); +@@ -279,7 +288,8 @@ + if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp) + recycle_ok = icsk->icsk_af_ops->remember_stamp(sk); + +- if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets) ++ if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets && ++ ub_timewait_check(sk, &tcp_death_row)) + tw = inet_twsk_alloc(sk, state); + + if (tw != NULL) { +@@ -292,6 +302,8 @@ + tcptw->tw_rcv_wnd = tcp_receive_window(tp); + tcptw->tw_ts_recent = tp->rx_opt.ts_recent; + tcptw->tw_ts_recent_stamp = tp->rx_opt.ts_recent_stamp; ++ if (sk->sk_user_data != NULL) ++ tw->tw_rcv_wscale |= TW_WSCALE_SPEC; + + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (tw->tw_family == PF_INET6) { +@@ -326,6 +338,7 @@ + } + } while (0); + #endif ++ tw->tw_owner_env = VEID(sk->owner_env); + + /* Linkage updates. */ + __inet_twsk_hashdance(tw, sk, &tcp_hashinfo); +@@ -346,11 +359,16 @@ + TCP_TIMEWAIT_LEN); + inet_twsk_put(tw); + } else { ++ int ubid = 0; + /* Sorry, if we're out of memory, just CLOSE this + * socket up. We've got bigger problems than + * non-graceful socket closings. + */ +- LIMIT_NETDEBUG(KERN_INFO "TCP: time wait bucket table overflow\n"); ++#ifdef CONFIG_BEANCOUNTERS ++ if (sock_has_ubc(sk)) ++ ubid = top_beancounter(sock_bc(sk)->ub)->ub_uid; ++#endif ++ LIMIT_NETDEBUG(KERN_INFO "TCP: time wait bucket table overflow (CT%d)\n", ubid); + } + + tcp_update_metrics(sk); +@@ -391,6 +409,8 @@ + struct tcp_sock *newtp; + + /* Now setup tcp_sock */ ++ newsk->owner_env = sk->owner_env; ++ + newtp = tcp_sk(newsk); + newtp->pred_flags = 0; + newtp->rcv_wup = newtp->copied_seq = newtp->rcv_nxt = treq->rcv_isn + 1; +Index: kernel/net/ipv4/tcp_output.c +=================================================================== +--- kernel.orig/net/ipv4/tcp_output.c 2008-11-24 14:17:56.000000000 +0100 ++++ kernel/net/ipv4/tcp_output.c 2008-11-24 15:47:46.000000000 +0100 +@@ -41,6 +41,9 @@ + #include + #include + ++#include ++#include ++ + /* People can turn this off for buggy TCP's found in printers etc. */ + int sysctl_tcp_retrans_collapse __read_mostly = 1; + +@@ -439,6 +442,13 @@ + #endif + } + ++static int skb_header_size(struct sock *sk, int tcp_hlen) ++{ ++ struct ip_options *opt = inet_sk(sk)->opt; ++ return tcp_hlen + sizeof(struct iphdr) + ++ (opt ? opt->optlen : 0) + ETH_HLEN /* For hard header */; ++} ++ + /* This routine actually transmits TCP packets queued in by + * tcp_do_sendmsg(). This is used by both the initial + * transmission and possible later retransmissions. +@@ -457,6 +467,7 @@ + struct tcp_sock *tp; + struct tcp_skb_cb *tcb; + int tcp_header_size; ++ int header_size; + #ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *md5; + __u8 *md5_hash_location; +@@ -516,6 +527,20 @@ + TCPOLEN_SACK_PERBLOCK)); + } + ++ /* Unfortunately, we can have skb from outside world here ++ * with size insufficient for header. It is impossible to make ++ * guess when we queue skb, so the decision should be made ++ * here. Den ++ */ ++ header_size = skb_header_size(sk, tcp_header_size); ++ if (skb->data - header_size < skb->head) { ++ int delta = header_size - skb_headroom(skb); ++ err = pskb_expand_head(skb, SKB_DATA_ALIGN(delta), ++ 0, GFP_ATOMIC); ++ if (err) ++ return err; ++ } ++ + if (tcp_packets_in_flight(tp) == 0) + tcp_ca_event(sk, CA_EVENT_TX_START); + +@@ -692,15 +717,23 @@ + if (nsize < 0) + nsize = 0; + +- if (skb_cloned(skb) && +- skb_is_nonlinear(skb) && +- pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) +- return -ENOMEM; ++ if (skb_cloned(skb) && skb_is_nonlinear(skb)) { ++ unsigned long chargesize; ++ chargesize = skb_bc(skb)->charged; ++ if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) ++ return -ENOMEM; ++ ub_sock_tcp_unchargesend(sk, chargesize); ++ ub_tcpsndbuf_charge_forced(sk, skb); ++ } + + /* Get a new skb... force flag on. */ + buff = sk_stream_alloc_skb(sk, nsize, GFP_ATOMIC); + if (buff == NULL) + return -ENOMEM; /* We'll just try again later. */ ++ if (ub_tcpsndbuf_charge(sk, buff) < 0) { ++ kfree_skb(buff); ++ return -ENOMEM; ++ } + + sk_charge_skb(sk, buff); + nlen = skb->len - len - nsize; +@@ -1000,6 +1033,8 @@ + return mss_now; + } + ++EXPORT_SYMBOL(tcp_current_mss); ++ + /* Congestion window validation. (RFC2861) */ + + static void tcp_cwnd_validate(struct sock *sk) +@@ -1186,6 +1221,11 @@ + if (unlikely(buff == NULL)) + return -ENOMEM; + ++ if (ub_tcpsndbuf_charge(sk, buff) < 0) { ++ kfree_skb(buff); ++ return -ENOMEM; ++ } ++ + sk_charge_skb(sk, buff); + buff->truesize += nlen; + skb->truesize -= nlen; +@@ -1516,6 +1556,8 @@ + } + } + ++EXPORT_SYMBOL(__tcp_push_pending_frames); ++ + /* Send _single_ skb sitting at the send head. This function requires + * true push pending frames to setup probe timer etc. + */ +@@ -1636,7 +1678,7 @@ + if (free_space < full_space/2) { + icsk->icsk_ack.quick = 0; + +- if (tcp_memory_pressure) ++ if (ub_tcp_shrink_rcvbuf(sk)) + tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U*tp->advmss); + + if (free_space < mss) +@@ -2080,6 +2122,7 @@ + break; + yield(); + } ++ ub_tcpsndbuf_charge_forced(sk, skb); + + /* Reserve space for headers and prepare control bits. */ + skb_reserve(skb, MAX_TCP_HEADER); +@@ -2150,6 +2193,10 @@ + struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); + if (nskb == NULL) + return -ENOMEM; ++ if (ub_tcpsndbuf_charge(sk, skb) < 0) { ++ kfree_skb(nskb); ++ return -ENOMEM; ++ } + tcp_unlink_write_queue(skb, sk); + skb_header_release(nskb); + __tcp_add_write_queue_head(sk, nskb); +@@ -2275,6 +2322,7 @@ + struct dst_entry *dst = __sk_dst_get(sk); + struct tcp_sock *tp = tcp_sk(sk); + __u8 rcv_wscale; ++ static int once = 0; + + /* We'll fix this up when we get a response from the other end. + * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT. +@@ -2294,9 +2342,23 @@ + tcp_mtup_init(sk); + tcp_sync_mss(sk, dst_mtu(dst)); + ++ if (!once && dst_metric(dst, RTAX_ADVMSS) == 0) { ++ once = 1; ++ ++ printk("Oops in connect_init! dst->advmss=%d\n", ++ dst_metric(dst, RTAX_ADVMSS)); ++ printk("dst: pmtu=%u\n", dst_metric(dst, RTAX_MTU)); ++ printk("sk->state=%d, tp: ack.rcv_mss=%d, mss_cache=%d, " ++ "advmss=%d, user_mss=%d\n", ++ sk->sk_state, inet_csk(sk)->icsk_ack.rcv_mss, ++ tp->mss_cache, tp->advmss, tp->rx_opt.user_mss); ++ } ++ + if (!tp->window_clamp) + tp->window_clamp = dst_metric(dst, RTAX_WINDOW); + tp->advmss = dst_metric(dst, RTAX_ADVMSS); ++ if (tp->advmss == 0) ++ tp->advmss = 1460; + tcp_initialize_rcv_mss(sk); + + tcp_select_initial_window(tcp_full_space(sk), +@@ -2337,6 +2399,10 @@ + buff = alloc_skb_fclone(MAX_TCP_HEADER + 15, sk->sk_allocation); + if (unlikely(buff == NULL)) + return -ENOBUFS; ++ if (ub_tcpsndbuf_charge(sk, buff) < 0) { ++ kfree_skb(buff); ++ return -ENOBUFS; ++ } + + /* Reserve space for headers. */ + skb_reserve(buff, MAX_TCP_HEADER); +Index: kernel/net/ipv4/tcp_timer.c +=================================================================== +--- kernel.orig/net/ipv4/tcp_timer.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/tcp_timer.c 2008-11-24 15:47:46.000000000 +0100 +@@ -22,6 +22,8 @@ + + #include + #include ++#include ++#include + + int sysctl_tcp_syn_retries __read_mostly = TCP_SYN_RETRIES; + int sysctl_tcp_synack_retries __read_mostly = TCP_SYNACK_RETRIES; +@@ -67,7 +69,8 @@ + static int tcp_out_of_resources(struct sock *sk, int do_reset) + { + struct tcp_sock *tp = tcp_sk(sk); +- int orphans = atomic_read(&tcp_orphan_count); ++ int orphans = ub_get_orphan_count(sk); ++ int orph = orphans; + + /* If peer does not open window for long time, or did not transmit + * anything for long time, penalize it. */ +@@ -78,10 +81,16 @@ + if (sk->sk_err_soft) + orphans <<= 1; + +- if (tcp_too_many_orphans(sk, orphans)) { +- if (net_ratelimit()) +- printk(KERN_INFO "Out of socket memory\n"); +- ++ if (ub_too_many_orphans(sk, orphans)) { ++ if (net_ratelimit()) { ++ int ubid = 0; ++#ifdef CONFIG_USER_RESOURCE ++ ubid = sock_has_ubc(sk) ? ++ top_beancounter(sock_bc(sk)->ub)->ub_uid : 0; ++#endif ++ printk(KERN_INFO "Orphaned socket dropped " ++ "(%d,%d in CT%d)\n", orph, orphans, ubid); ++ } + /* Catch exceptional cases, when connection requires reset. + * 1. Last segment was sent recently. */ + if ((s32)(tcp_time_stamp - tp->lsndtime) <= TCP_TIMEWAIT_LEN || +@@ -167,9 +176,12 @@ + static void tcp_delack_timer(unsigned long data) + { + struct sock *sk = (struct sock*)data; ++ struct ve_struct *env; + struct tcp_sock *tp = tcp_sk(sk); + struct inet_connection_sock *icsk = inet_csk(sk); + ++ env = set_exec_env(sk->owner_env); ++ + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ +@@ -218,11 +230,12 @@ + TCP_CHECK_TIMER(sk); + + out: +- if (tcp_memory_pressure) ++ if (ub_tcp_memory_pressure(sk)) + sk_stream_mem_reclaim(sk); + out_unlock: + bh_unlock_sock(sk); + sock_put(sk); ++ (void)set_exec_env(env); + } + + static void tcp_probe_timer(struct sock *sk) +@@ -277,8 +290,11 @@ + static void tcp_retransmit_timer(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); ++ struct ve_struct *env; + struct inet_connection_sock *icsk = inet_csk(sk); + ++ env = set_exec_env(sk->owner_env); ++ + if (!tp->packets_out) + goto out; + +@@ -375,15 +391,19 @@ + if (icsk->icsk_retransmits > sysctl_tcp_retries1) + __sk_dst_reset(sk); + +-out:; ++out: ++ (void)set_exec_env(env); + } + + static void tcp_write_timer(unsigned long data) + { + struct sock *sk = (struct sock*)data; ++ struct ve_struct *env; + struct inet_connection_sock *icsk = inet_csk(sk); + int event; + ++ env = set_exec_env(sk->owner_env); ++ + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later */ +@@ -417,6 +437,7 @@ + out_unlock: + bh_unlock_sock(sk); + sock_put(sk); ++ (void)set_exec_env(env); + } + + /* +@@ -444,10 +465,13 @@ + static void tcp_keepalive_timer (unsigned long data) + { + struct sock *sk = (struct sock *) data; ++ struct ve_struct *env; + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); + __u32 elapsed; + ++ env = set_exec_env(sk->owner_env); ++ + /* Only process if socket is not in use. */ + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { +@@ -519,4 +543,5 @@ + out: + bh_unlock_sock(sk); + sock_put(sk); ++ (void)set_exec_env(env); + } +Index: kernel/net/ipv4/udp.c +=================================================================== +--- kernel.orig/net/ipv4/udp.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/udp.c 2008-11-24 15:47:46.000000000 +0100 +@@ -115,13 +115,15 @@ + DEFINE_RWLOCK(udp_hash_lock); + + static inline int __udp_lib_lport_inuse(__u16 num, +- const struct hlist_head udptable[]) ++ const struct hlist_head udptable[], ++ struct ve_struct *ve) + { + struct sock *sk; + struct hlist_node *node; + +- sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)]) +- if (sk->sk_hash == num) ++ sk_for_each(sk, node, &udptable[udp_hashfn(num, VEID(ve))]) ++ if (sk->sk_hash == num && ++ ve_accessible_strict(sk->owner_env, ve)) + return 1; + return 0; + } +@@ -143,7 +145,9 @@ + struct hlist_head *head; + struct sock *sk2; + int error = 1; ++ struct ve_struct *ve; + ++ ve = get_exec_env(); + write_lock_bh(&udp_hash_lock); + + if (!snum) { +@@ -160,7 +164,7 @@ + for (i = 0; i < UDP_HTABLE_SIZE; i++) { + int size = 0; + +- head = &udptable[rover & (UDP_HTABLE_SIZE - 1)]; ++ head = &udptable[udp_hashfn(rover, VEID(ve))]; + if (hlist_empty(head)) + goto gotit; + +@@ -182,7 +186,7 @@ + /* 2nd pass: find hole in shortest hash chain */ + rover = best; + for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) { +- if (! __udp_lib_lport_inuse(rover, udptable)) ++ if (! __udp_lib_lport_inuse(rover, udptable, ve)) + goto gotit; + rover += UDP_HTABLE_SIZE; + if (rover > high) +@@ -197,12 +201,13 @@ + gotit: + snum = rover; + } else { +- head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; ++ head = &udptable[udp_hashfn(snum, VEID(ve))]; + + sk_for_each(sk2, node, head) + if (sk2->sk_hash == snum && + sk2 != sk && + (!sk2->sk_reuse || !sk->sk_reuse) && ++ ve_accessible_strict(sk2->owner_env, ve) && + (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if + || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && + (*saddr_comp)(sk, sk2) ) +@@ -212,7 +217,7 @@ + inet_sk(sk)->num = snum; + sk->sk_hash = snum; + if (sk_unhashed(sk)) { +- head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; ++ head = &udptable[udp_hashfn(snum, VEID(ve))]; + sk_add_node(sk, head); + sock_prot_inc_use(sk->sk_prot); + } +@@ -253,12 +258,15 @@ + struct hlist_node *node; + unsigned short hnum = ntohs(dport); + int badness = -1; ++ struct ve_struct *ve; + ++ ve = get_exec_env(); + read_lock(&udp_hash_lock); +- sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { ++ sk_for_each(sk, node, &udptable[udp_hashfn(hnum, VEID(ve))]) { + struct inet_sock *inet = inet_sk(sk); + +- if (sk->sk_hash == hnum && !ipv6_only_sock(sk)) { ++ if (sk->sk_hash == hnum && !ipv6_only_sock(sk) && ++ ve_accessible_strict(sk->owner_env, ve)) { + int score = (sk->sk_family == PF_INET ? 1 : 0); + if (inet->rcv_saddr) { + if (inet->rcv_saddr != daddr) +@@ -1047,7 +1055,8 @@ + int dif; + + read_lock(&udp_hash_lock); +- sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); ++ sk = sk_head(&udptable[udp_hashfn(ntohs(uh->dest), ++ VEID(skb->owner_env))]); + dif = skb->dev->ifindex; + sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); + if (sk) { +@@ -1464,10 +1473,14 @@ + { + struct sock *sk; + struct udp_iter_state *state = seq->private; ++ struct ve_struct *env; + ++ env = get_exec_env(); + for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { + struct hlist_node *node; + sk_for_each(sk, node, state->hashtable + state->bucket) { ++ if (!ve_accessible(sk->owner_env, env)) ++ continue; + if (sk->sk_family == state->family) + goto found; + } +@@ -1484,8 +1497,13 @@ + do { + sk = sk_next(sk); + try_again: +- ; +- } while (sk && sk->sk_family != state->family); ++ if (!sk) ++ break; ++ if (sk->sk_family != state->family) ++ continue; ++ if (ve_accessible(sk->owner_env, get_exec_env())) ++ break; ++ } while (1); + + if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { + sk = sk_head(state->hashtable + state->bucket); +Index: kernel/net/ipv4/xfrm4_policy.c +=================================================================== +--- kernel.orig/net/ipv4/xfrm4_policy.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv4/xfrm4_policy.c 2008-11-24 15:47:46.000000000 +0100 +@@ -295,7 +295,8 @@ + + xdst = (struct xfrm_dst *)dst; + if (xdst->u.rt.idev->dev == dev) { +- struct in_device *loopback_idev = in_dev_get(init_net.loopback_dev); ++ struct in_device *loopback_idev = ++ in_dev_get(dev->nd_net->loopback_dev); + BUG_ON(!loopback_idev); + + do { +Index: kernel/net/ipv6/addrconf.c +=================================================================== +--- kernel.orig/net/ipv6/addrconf.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/addrconf.c 2008-11-24 15:47:46.000000000 +0100 +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -101,6 +102,7 @@ + #define TIME_DELTA(a,b) ((unsigned long)((long)(a) - (long)(b))) + + #ifdef CONFIG_SYSCTL ++static struct addrconf_sysctl_table * __addrconf_sysctl_register(struct inet6_dev *idev, char *devname, int ifindex, struct ipv6_devconf *p); + static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf *p); + static void addrconf_sysctl_unregister(struct ipv6_devconf *p); + #endif +@@ -129,8 +131,6 @@ + static void addrconf_join_anycast(struct inet6_ifaddr *ifp); + static void addrconf_leave_anycast(struct inet6_ifaddr *ifp); + +-static int addrconf_ifdown(struct net_device *dev, int how); +- + static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); + static void addrconf_dad_timer(unsigned long data); + static void addrconf_dad_completed(struct inet6_ifaddr *ifp); +@@ -145,7 +145,7 @@ + + static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); + +-struct ipv6_devconf ipv6_devconf __read_mostly = { ++struct ipv6_devconf global_ipv6_devconf __read_mostly = { + .forwarding = 0, + .hop_limit = IPV6_DEFAULT_HOPLIMIT, + .mtu6 = IPV6_MIN_MTU, +@@ -178,7 +178,7 @@ + .accept_source_route = 0, /* we do not accept RH0 by default. */ + }; + +-static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { ++struct ipv6_devconf global_ipv6_devconf_dflt __read_mostly = { + .forwarding = 0, + .hop_limit = IPV6_DEFAULT_HOPLIMIT, + .mtu6 = IPV6_MIN_MTU, +@@ -210,6 +210,12 @@ + .accept_source_route = 0, /* we do not accept RH0 by default. */ + }; + ++#ifdef CONFIG_VE ++#define ipv6_devconf_dflt (*(get_exec_env()->_ipv6_devconf_dflt)) ++#else ++#define ipv6_devconf_dflt global_ipv6_devconf_dflt ++#endif ++ + /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ + const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; + const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; +@@ -375,9 +381,8 @@ + dev->type == ARPHRD_SIT || + #endif + dev->type == ARPHRD_NONE) { +- printk(KERN_INFO +- "%s: Disabled Privacy Extensions\n", +- dev->name); ++ ADBG((KERN_INFO "%s: Disabled Privacy Extensions\n", ++ dev->name)); + ndev->cnf.use_tempaddr = -1; + } else { + in6_dev_hold(ndev); +@@ -458,12 +463,12 @@ + struct inet6_dev *idev; + + read_lock(&dev_base_lock); +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { + rcu_read_lock(); + idev = __in6_dev_get(dev); + if (idev) { +- int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding); +- idev->cnf.forwarding = ipv6_devconf.forwarding; ++ int changed = (!idev->cnf.forwarding) ^ (!ve_ipv6_devconf.forwarding); ++ idev->cnf.forwarding = ve_ipv6_devconf.forwarding; + if (changed) + dev_forward_change(idev); + } +@@ -543,7 +548,7 @@ + goto out; + } + +- ifa = kzalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC); ++ ifa = kzalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC_UBC); + + if (ifa == NULL) { + ADBG(("ipv6_add_addr: malloc failed\n")); +@@ -936,7 +941,7 @@ + read_lock(&dev_base_lock); + rcu_read_lock(); + +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { + struct inet6_dev *idev; + struct inet6_ifaddr *ifa; + +@@ -1231,9 +1236,10 @@ + read_lock_bh(&addrconf_hash_lock); + for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { + if (ipv6_addr_equal(&ifp->addr, addr) && +- !(ifp->flags&IFA_F_TENTATIVE)) { ++ !(ifp->flags&IFA_F_TENTATIVE) && ++ ve_accessible_strict(ifp->idev->dev->owner_env, get_exec_env())) { + if (dev == NULL || ifp->idev->dev == dev || +- !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) ++ !((ifp->scope&(IFA_LINK|IFA_HOST)) || strict)) + break; + } + } +@@ -1251,7 +1257,9 @@ + + for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { + if (ipv6_addr_equal(&ifp->addr, addr)) { +- if (dev == NULL || ifp->idev->dev == dev) ++ if ((dev == NULL && ++ ve_accessible_strict(ifp->idev->dev->owner_env, get_exec_env())) ++ || ifp->idev->dev == dev) + break; + } + } +@@ -1265,9 +1273,10 @@ + + read_lock_bh(&addrconf_hash_lock); + for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { +- if (ipv6_addr_equal(&ifp->addr, addr)) { ++ if (ipv6_addr_equal(&ifp->addr, addr) && ++ ve_accessible_strict(ifp->idev->dev->owner_env, get_exec_env())) { + if (dev == NULL || ifp->idev->dev == dev || +- !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) { ++ !((ifp->scope&(IFA_LINK|IFA_HOST)) || strict)) { + in6_ifa_hold(ifp); + break; + } +@@ -1755,7 +1764,7 @@ + + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD + if (in6_dev->cnf.optimistic_dad && +- !ipv6_devconf.forwarding) ++ !ve_ipv6_devconf.forwarding) + addr_flags = IFA_F_OPTIMISTIC; + #endif + +@@ -1875,6 +1884,7 @@ + */ + int addrconf_set_dstaddr(void __user *arg) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + struct in6_ifreq ireq; + struct net_device *dev; + int err = -EINVAL; +@@ -1885,7 +1895,7 @@ + if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) + goto err_exit; + +- dev = __dev_get_by_index(&init_net, ireq.ifr6_ifindex); ++ dev = __dev_get_by_index(net, ireq.ifr6_ifindex); + + err = -ENODEV; + if (dev == NULL) +@@ -1916,7 +1926,7 @@ + + if (err == 0) { + err = -ENOBUFS; +- if ((dev = __dev_get_by_name(&init_net, p.name)) == NULL) ++ if ((dev = __dev_get_by_name(net, p.name)) == NULL) + goto err_exit; + err = dev_open(dev); + } +@@ -1931,7 +1941,7 @@ + /* + * Manual configuration of address on an interface + */ +-static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, ++int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, + __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft) + { + struct inet6_ifaddr *ifp; +@@ -1946,7 +1956,7 @@ + if (!valid_lft || prefered_lft > valid_lft) + return -EINVAL; + +- if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL) ++ if ((dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifindex)) == NULL) + return -ENODEV; + + if ((idev = addrconf_add_dev(dev)) == NULL) +@@ -1990,6 +2000,7 @@ + + return PTR_ERR(ifp); + } ++EXPORT_SYMBOL_GPL(inet6_addr_add); + + static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen) + { +@@ -1997,7 +2008,7 @@ + struct inet6_dev *idev; + struct net_device *dev; + +- if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL) ++ if ((dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifindex)) == NULL) + return -ENODEV; + + if ((idev = __in6_dev_get(dev)) == NULL) +@@ -2030,7 +2041,7 @@ + struct in6_ifreq ireq; + int err; + +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_VE_NET_ADMIN)) + return -EPERM; + + if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) +@@ -2048,7 +2059,7 @@ + struct in6_ifreq ireq; + int err; + +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_VE_NET_ADMIN)) + return -EPERM; + + if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) +@@ -2092,7 +2103,7 @@ + return; + } + +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { + struct in_device * in_dev = __in_dev_get_rtnl(dev); + if (in_dev && (dev->flags & IFF_UP)) { + struct in_ifaddr * ifa; +@@ -2162,7 +2173,7 @@ + + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD + if (idev->cnf.optimistic_dad && +- !ipv6_devconf.forwarding) ++ !ve_ipv6_devconf.forwarding) + addr_flags |= IFA_F_OPTIMISTIC; + #endif + +@@ -2244,16 +2255,17 @@ + + static void ip6_tnl_add_linklocal(struct inet6_dev *idev) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + struct net_device *link_dev; + + /* first try to inherit the link-local address from the link device */ + if (idev->dev->iflink && +- (link_dev = __dev_get_by_index(&init_net, idev->dev->iflink))) { ++ (link_dev = __dev_get_by_index(net, idev->dev->iflink))) { + if (!ipv6_inherit_linklocal(idev, link_dev)) + return; + } + /* then try to inherit it from any device */ +- for_each_netdev(&init_net, link_dev) { ++ for_each_netdev(net, link_dev) { + if (!ipv6_inherit_linklocal(idev, link_dev)) + return; + } +@@ -2286,9 +2298,6 @@ + int run_pending = 0; + int err; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + switch(event) { + case NETDEV_REGISTER: + if (!idev && dev->mtu >= IPV6_MIN_MTU) { +@@ -2431,7 +2440,7 @@ + .priority = 0 + }; + +-static int addrconf_ifdown(struct net_device *dev, int how) ++int addrconf_ifdown(struct net_device *dev, int how) + { + struct inet6_dev *idev; + struct inet6_ifaddr *ifa, **bifa; +@@ -2546,10 +2555,14 @@ + } + return 0; + } ++EXPORT_SYMBOL_GPL(addrconf_ifdown); + + static void addrconf_rs_timer(unsigned long data) + { + struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; ++ struct ve_struct *old_env; ++ ++ old_env = set_exec_env(ifp->idev->dev->owner_env); + + if (ifp->idev->cnf.forwarding) + goto out; +@@ -2588,6 +2601,7 @@ + + out: + in6_ifa_put(ifp); ++ (void)set_exec_env(old_env); + } + + /* +@@ -2664,6 +2678,9 @@ + struct inet6_dev *idev = ifp->idev; + struct in6_addr unspec; + struct in6_addr mcaddr; ++ struct ve_struct *old_env; ++ ++ old_env = set_exec_env(ifp->idev->dev->owner_env); + + read_lock_bh(&idev->lock); + if (idev->dead) { +@@ -2696,6 +2713,7 @@ + ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec); + out: + in6_ifa_put(ifp); ++ (void)set_exec_env(old_env); + } + + static void addrconf_dad_completed(struct inet6_ifaddr *ifp) +@@ -2763,8 +2781,11 @@ + + for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { + ifa = inet6_addr_lst[state->bucket]; +- if (ifa) +- break; ++ while (ifa) { ++ if (ve_accessible_strict(ifa->idev->dev->owner_env, get_exec_env())) ++ return ifa; ++ ifa = ifa->lst_next; ++ } + } + return ifa; + } +@@ -2775,6 +2796,11 @@ + + ifa = ifa->lst_next; + try_again: ++ while (ifa) { ++ if (ve_accessible_strict(ifa->idev->dev->owner_env, get_exec_env())) ++ break; ++ ifa = ifa->lst_next; ++ } + if (!ifa && ++state->bucket < IN6_ADDR_HSIZE) { + ifa = inet6_addr_lst[state->bucket]; + goto try_again; +@@ -2889,6 +2915,7 @@ + struct inet6_ifaddr *ifp; + unsigned long now, next; + int i; ++ struct ve_struct *old_env; + + spin_lock_bh(&addrconf_verify_lock); + now = jiffies; +@@ -2909,6 +2936,8 @@ + if (ifp->flags & IFA_F_PERMANENT) + continue; + ++ old_env = set_exec_env(ifp->idev->dev->owner_env); ++ + spin_lock(&ifp->lock); + age = (now - ifp->tstamp) / HZ; + +@@ -2924,9 +2953,11 @@ + in6_ifa_hold(ifp); + read_unlock(&addrconf_hash_lock); + ipv6_del_addr(ifp); ++ (void)set_exec_env(old_env); + goto restart; + } else if (ifp->prefered_lft == INFINITY_LIFE_TIME) { + spin_unlock(&ifp->lock); ++ set_exec_env(old_env); + continue; + } else if (age >= ifp->prefered_lft) { + /* jiffies - ifp->tsamp > age >= ifp->prefered_lft */ +@@ -2948,6 +2979,7 @@ + + ipv6_ifa_notify(0, ifp); + in6_ifa_put(ifp); ++ (void)set_exec_env(old_env); + goto restart; + } + #ifdef CONFIG_IPV6_PRIVACY +@@ -2969,6 +3001,7 @@ + ipv6_create_tempaddr(ifpub, ifp); + in6_ifa_put(ifpub); + in6_ifa_put(ifp); ++ (void)set_exec_env(old_env); + goto restart; + } + } else if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next)) +@@ -2981,6 +3014,7 @@ + next = ifp->tstamp + ifp->prefered_lft * HZ; + spin_unlock(&ifp->lock); + } ++ (void)set_exec_env(old_env); + } + read_unlock(&addrconf_hash_lock); + } +@@ -3102,7 +3136,7 @@ + valid_lft = INFINITY_LIFE_TIME; + } + +- dev = __dev_get_by_index(&init_net, ifm->ifa_index); ++ dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifm->ifa_index); + if (dev == NULL) + return -ENODEV; + +@@ -3286,7 +3320,7 @@ + s_ip_idx = ip_idx = cb->args[1]; + + idx = 0; +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { + if (idx < s_idx) + goto cont; + if (idx > s_idx) +@@ -3395,7 +3429,7 @@ + + ifm = nlmsg_data(nlh); + if (ifm->ifa_index) +- dev = __dev_get_by_index(&init_net, ifm->ifa_index); ++ dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifm->ifa_index); + + if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) { + err = -EADDRNOTAVAIL; +@@ -3607,7 +3641,7 @@ + + read_lock(&dev_base_lock); + idx = 0; +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { + if (idx < s_idx) + goto cont; + if ((idev = in6_dev_get(dev)) == NULL) +@@ -3766,7 +3800,7 @@ + ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + + if (write && valp != &ipv6_devconf_dflt.forwarding) { +- if (valp != &ipv6_devconf.forwarding) { ++ if (valp != &ve_ipv6_devconf.forwarding) { + if ((!*valp) ^ (!val)) { + struct inet6_dev *idev = (struct inet6_dev *)ctl->extra1; + if (idev == NULL) +@@ -3774,7 +3808,7 @@ + dev_forward_change(idev); + } + } else { +- ipv6_devconf_dflt.forwarding = ipv6_devconf.forwarding; ++ ipv6_devconf_dflt.forwarding = ve_ipv6_devconf.forwarding; + addrconf_forward_change(); + } + if (*valp) +@@ -3816,7 +3850,7 @@ + } + + if (valp != &ipv6_devconf_dflt.forwarding) { +- if (valp != &ipv6_devconf.forwarding) { ++ if (valp != &ve_ipv6_devconf.forwarding) { + struct inet6_dev *idev = (struct inet6_dev *)table->extra1; + int changed; + if (unlikely(idev == NULL)) +@@ -3852,7 +3886,7 @@ + { + .ctl_name = NET_IPV6_FORWARDING, + .procname = "forwarding", +- .data = &ipv6_devconf.forwarding, ++ .data = &global_ipv6_devconf.forwarding, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &addrconf_sysctl_forward, +@@ -3861,7 +3895,7 @@ + { + .ctl_name = NET_IPV6_HOP_LIMIT, + .procname = "hop_limit", +- .data = &ipv6_devconf.hop_limit, ++ .data = &global_ipv6_devconf.hop_limit, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, +@@ -3869,7 +3903,7 @@ + { + .ctl_name = NET_IPV6_MTU, + .procname = "mtu", +- .data = &ipv6_devconf.mtu6, ++ .data = &global_ipv6_devconf.mtu6, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3877,7 +3911,7 @@ + { + .ctl_name = NET_IPV6_ACCEPT_RA, + .procname = "accept_ra", +- .data = &ipv6_devconf.accept_ra, ++ .data = &global_ipv6_devconf.accept_ra, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3885,7 +3919,7 @@ + { + .ctl_name = NET_IPV6_ACCEPT_REDIRECTS, + .procname = "accept_redirects", +- .data = &ipv6_devconf.accept_redirects, ++ .data = &global_ipv6_devconf.accept_redirects, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3893,7 +3927,7 @@ + { + .ctl_name = NET_IPV6_AUTOCONF, + .procname = "autoconf", +- .data = &ipv6_devconf.autoconf, ++ .data = &global_ipv6_devconf.autoconf, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3901,7 +3935,7 @@ + { + .ctl_name = NET_IPV6_DAD_TRANSMITS, + .procname = "dad_transmits", +- .data = &ipv6_devconf.dad_transmits, ++ .data = &global_ipv6_devconf.dad_transmits, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3909,7 +3943,7 @@ + { + .ctl_name = NET_IPV6_RTR_SOLICITS, + .procname = "router_solicitations", +- .data = &ipv6_devconf.rtr_solicits, ++ .data = &global_ipv6_devconf.rtr_solicits, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3917,7 +3951,7 @@ + { + .ctl_name = NET_IPV6_RTR_SOLICIT_INTERVAL, + .procname = "router_solicitation_interval", +- .data = &ipv6_devconf.rtr_solicit_interval, ++ .data = &global_ipv6_devconf.rtr_solicit_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_jiffies, +@@ -3926,7 +3960,7 @@ + { + .ctl_name = NET_IPV6_RTR_SOLICIT_DELAY, + .procname = "router_solicitation_delay", +- .data = &ipv6_devconf.rtr_solicit_delay, ++ .data = &global_ipv6_devconf.rtr_solicit_delay, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_jiffies, +@@ -3935,7 +3969,7 @@ + { + .ctl_name = NET_IPV6_FORCE_MLD_VERSION, + .procname = "force_mld_version", +- .data = &ipv6_devconf.force_mld_version, ++ .data = &global_ipv6_devconf.force_mld_version, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3944,7 +3978,7 @@ + { + .ctl_name = NET_IPV6_USE_TEMPADDR, + .procname = "use_tempaddr", +- .data = &ipv6_devconf.use_tempaddr, ++ .data = &global_ipv6_devconf.use_tempaddr, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3952,7 +3986,7 @@ + { + .ctl_name = NET_IPV6_TEMP_VALID_LFT, + .procname = "temp_valid_lft", +- .data = &ipv6_devconf.temp_valid_lft, ++ .data = &global_ipv6_devconf.temp_valid_lft, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3960,7 +3994,7 @@ + { + .ctl_name = NET_IPV6_TEMP_PREFERED_LFT, + .procname = "temp_prefered_lft", +- .data = &ipv6_devconf.temp_prefered_lft, ++ .data = &global_ipv6_devconf.temp_prefered_lft, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3968,7 +4002,7 @@ + { + .ctl_name = NET_IPV6_REGEN_MAX_RETRY, + .procname = "regen_max_retry", +- .data = &ipv6_devconf.regen_max_retry, ++ .data = &global_ipv6_devconf.regen_max_retry, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3976,7 +4010,7 @@ + { + .ctl_name = NET_IPV6_MAX_DESYNC_FACTOR, + .procname = "max_desync_factor", +- .data = &ipv6_devconf.max_desync_factor, ++ .data = &global_ipv6_devconf.max_desync_factor, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3985,7 +4019,7 @@ + { + .ctl_name = NET_IPV6_MAX_ADDRESSES, + .procname = "max_addresses", +- .data = &ipv6_devconf.max_addresses, ++ .data = &global_ipv6_devconf.max_addresses, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -3993,7 +4027,7 @@ + { + .ctl_name = NET_IPV6_ACCEPT_RA_DEFRTR, + .procname = "accept_ra_defrtr", +- .data = &ipv6_devconf.accept_ra_defrtr, ++ .data = &global_ipv6_devconf.accept_ra_defrtr, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -4001,7 +4035,7 @@ + { + .ctl_name = NET_IPV6_ACCEPT_RA_PINFO, + .procname = "accept_ra_pinfo", +- .data = &ipv6_devconf.accept_ra_pinfo, ++ .data = &global_ipv6_devconf.accept_ra_pinfo, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -4010,7 +4044,7 @@ + { + .ctl_name = NET_IPV6_ACCEPT_RA_RTR_PREF, + .procname = "accept_ra_rtr_pref", +- .data = &ipv6_devconf.accept_ra_rtr_pref, ++ .data = &global_ipv6_devconf.accept_ra_rtr_pref, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -4018,7 +4052,7 @@ + { + .ctl_name = NET_IPV6_RTR_PROBE_INTERVAL, + .procname = "router_probe_interval", +- .data = &ipv6_devconf.rtr_probe_interval, ++ .data = &global_ipv6_devconf.rtr_probe_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_jiffies, +@@ -4028,7 +4062,7 @@ + { + .ctl_name = NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN, + .procname = "accept_ra_rt_info_max_plen", +- .data = &ipv6_devconf.accept_ra_rt_info_max_plen, ++ .data = &global_ipv6_devconf.accept_ra_rt_info_max_plen, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -4038,7 +4072,7 @@ + { + .ctl_name = NET_IPV6_PROXY_NDP, + .procname = "proxy_ndp", +- .data = &ipv6_devconf.proxy_ndp, ++ .data = &global_ipv6_devconf.proxy_ndp, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -4046,7 +4080,7 @@ + { + .ctl_name = NET_IPV6_ACCEPT_SOURCE_ROUTE, + .procname = "accept_source_route", +- .data = &ipv6_devconf.accept_source_route, ++ .data = &global_ipv6_devconf.accept_source_route, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -4055,7 +4089,7 @@ + { + .ctl_name = CTL_UNNUMBERED, + .procname = "optimistic_dad", +- .data = &ipv6_devconf.optimistic_dad, ++ .data = &global_ipv6_devconf.optimistic_dad, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, +@@ -4112,27 +4146,21 @@ + }, + }; + +-static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf *p) ++static struct addrconf_sysctl_table *__addrconf_sysctl_register( ++ struct inet6_dev *idev, char *dev_name, ++ int ifindex, struct ipv6_devconf *p) + { + int i; +- struct net_device *dev = idev ? idev->dev : NULL; + struct addrconf_sysctl_table *t; +- char *dev_name = NULL; + + t = kmemdup(&addrconf_sysctl, sizeof(*t), GFP_KERNEL); + if (t == NULL) +- return; ++ return NULL; ++ + for (i=0; t->addrconf_vars[i].data; i++) { +- t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf; ++ t->addrconf_vars[i].data += (char*)p - (char*)&global_ipv6_devconf; + t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */ + } +- if (dev) { +- dev_name = dev->name; +- t->addrconf_dev[0].ctl_name = dev->ifindex; +- } else { +- dev_name = "default"; +- t->addrconf_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT; +- } + + /* + * Make a copy of dev_name, because '.procname' is regarded as const +@@ -4143,6 +4171,7 @@ + if (!dev_name) + goto free; + ++ t->addrconf_dev[0].ctl_name = ifindex; + t->addrconf_dev[0].procname = dev_name; + + t->addrconf_dev[0].child = t->addrconf_vars; +@@ -4153,9 +4182,7 @@ + t->sysctl_header = register_sysctl_table(t->addrconf_root_dir); + if (t->sysctl_header == NULL) + goto free_procname; +- else +- p->sysctl = t; +- return; ++ return t; + + /* error path */ + free_procname: +@@ -4163,7 +4190,26 @@ + free: + kfree(t); + +- return; ++ return NULL; ++} ++ ++static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf *p) ++{ ++ struct net_device *dev; ++ char *dev_name; ++ int ifindex; ++ ++ dev = idev ? idev->dev : NULL; ++ ++ if (dev) { ++ dev_name = dev->name; ++ ifindex = dev->ifindex; ++ } else { ++ dev_name = "default"; ++ ifindex = NET_PROTO_CONF_DEFAULT; ++ } ++ ++ p->sysctl = __addrconf_sysctl_register(idev, dev_name, ifindex, p); + } + + static void addrconf_sysctl_unregister(struct ipv6_devconf *p) +@@ -4177,9 +4223,64 @@ + } + } + ++#ifdef CONFIG_VE ++int addrconf_sysctl_init(struct ve_struct *ve) ++{ ++ int err = 0; ++ struct ipv6_devconf *conf, *conf_def; ++ ++ err = -ENOMEM; + +-#endif ++ conf = kmalloc(sizeof(*conf), GFP_KERNEL); ++ if (!conf) ++ goto err1; ++ ++ memcpy(conf, &global_ipv6_devconf, sizeof(*conf)); ++ conf->sysctl = __addrconf_sysctl_register(NULL, "all", ++ NET_PROTO_CONF_ALL, conf); ++ if (!conf->sysctl) ++ goto err2; ++ ++ conf_def = kmalloc(sizeof(*conf_def), GFP_KERNEL); ++ if (!conf_def) ++ goto err3; ++ ++ memcpy(conf_def, &global_ipv6_devconf_dflt, sizeof(*conf_def)); ++ conf_def->sysctl = __addrconf_sysctl_register(NULL, "default", ++ NET_PROTO_CONF_DEFAULT, conf_def); ++ if (!conf_def->sysctl) ++ goto err4; ++ ++ ve->_ipv6_devconf = conf; ++ ve->_ipv6_devconf_dflt = conf_def; ++ return 0; ++ ++err4: ++ kfree(conf_def); ++err3: ++ addrconf_sysctl_unregister(conf); ++err2: ++ kfree(conf); ++err1: ++ return err; ++} ++EXPORT_SYMBOL(addrconf_sysctl_init); + ++void addrconf_sysctl_fini(struct ve_struct *ve) ++{ ++ addrconf_sysctl_unregister(ve->_ipv6_devconf); ++ addrconf_sysctl_unregister(ve->_ipv6_devconf_dflt); ++} ++EXPORT_SYMBOL(addrconf_sysctl_fini); ++ ++void addrconf_sysctl_free(struct ve_struct *ve) ++{ ++ kfree(ve->_ipv6_devconf); ++ kfree(ve->_ipv6_devconf_dflt); ++} ++EXPORT_SYMBOL(addrconf_sysctl_free); ++#endif /* CONFIG_VE */ ++#endif /* CONFIG_SYSCTL */ + /* + * Device notifier + */ +@@ -4206,6 +4307,11 @@ + { + int err = 0; + ++#ifdef CONFIG_VE ++ get_ve0()->_ipv6_devconf = &global_ipv6_devconf; ++ get_ve0()->_ipv6_devconf_dflt = &global_ipv6_devconf_dflt; ++#endif ++ + /* The addrconf netdev notifier requires that loopback_dev + * has it's ipv6 private information allocated and setup + * before it can bring up and give link-local addresses +@@ -4258,7 +4364,7 @@ + #ifdef CONFIG_SYSCTL + addrconf_sysctl.sysctl_header = + register_sysctl_table(addrconf_sysctl.addrconf_root_dir); +- addrconf_sysctl_register(NULL, &ipv6_devconf_dflt); ++ addrconf_sysctl_register(NULL, &global_ipv6_devconf_dflt); + #endif + + return 0; +@@ -4277,8 +4383,8 @@ + unregister_netdevice_notifier(&ipv6_dev_notf); + + #ifdef CONFIG_SYSCTL +- addrconf_sysctl_unregister(&ipv6_devconf_dflt); +- addrconf_sysctl_unregister(&ipv6_devconf); ++ addrconf_sysctl_unregister(&global_ipv6_devconf_dflt); ++ addrconf_sysctl_unregister(&global_ipv6_devconf); + #endif + + rtnl_lock(); +Index: kernel/net/ipv6/af_inet6.c +=================================================================== +--- kernel.orig/net/ipv6/af_inet6.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/af_inet6.c 2008-11-24 15:47:46.000000000 +0100 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -58,6 +59,10 @@ + #ifdef CONFIG_IPV6_TUNNEL + #include + #endif ++#ifdef CONFIG_IPV6_MIP6 ++#include ++#endif ++#include + + #include + #include +@@ -94,9 +99,6 @@ + int try_loading_module = 0; + int err; + +- if (net != &init_net) +- return -EAFNOSUPPORT; +- + if (sock->type != SOCK_RAW && + sock->type != SOCK_DGRAM && + !inet_ehash_secret) +@@ -149,6 +151,10 @@ + goto out_rcu_unlock; + } + ++ err = vz_security_protocol_check(answer->protocol); ++ if (err < 0) ++ goto out_rcu_unlock; ++ + err = -EPERM; + if (answer->capability > 0 && !capable(answer->capability)) + goto out_rcu_unlock; +@@ -166,6 +172,13 @@ + if (sk == NULL) + goto out; + ++ err = -ENOBUFS; ++ if (ub_sock_charge(sk, PF_INET6, sock->type)) ++ goto out_sk_free; ++ /* if charge was successful, sock_init_data() MUST be called to ++ * set sk->sk_type. otherwise sk will be uncharged to wrong resource ++ */ ++ + sock_init_data(sock, sk); + + err = 0; +@@ -240,6 +253,9 @@ + out_rcu_unlock: + rcu_read_unlock(); + goto out; ++out_sk_free: ++ sk_free(sk); ++ return err; + } + + +@@ -302,7 +318,7 @@ + err = -EINVAL; + goto out; + } +- dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); ++ dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, sk->sk_bound_dev_if); + if (!dev) { + err = -ENODEV; + goto out; +@@ -713,31 +729,31 @@ + + static int __init init_ipv6_mibs(void) + { +- if (snmp_mib_init((void **)ipv6_statistics, sizeof (struct ipstats_mib), ++ if (snmp_mib_init((void **)ve_ipv6_statistics, sizeof (struct ipstats_mib), + __alignof__(struct ipstats_mib)) < 0) + goto err_ip_mib; +- if (snmp_mib_init((void **)icmpv6_statistics, sizeof (struct icmpv6_mib), ++ if (snmp_mib_init((void **)ve_icmpv6_statistics, sizeof (struct icmpv6_mib), + __alignof__(struct icmpv6_mib)) < 0) + goto err_icmp_mib; +- if (snmp_mib_init((void **)icmpv6msg_statistics, ++ if (snmp_mib_init((void **)ve_icmpv6msg_statistics, + sizeof (struct icmpv6msg_mib), __alignof__(struct icmpv6_mib)) < 0) + goto err_icmpmsg_mib; +- if (snmp_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib), ++ if (snmp_mib_init((void **)ve_udp_stats_in6, sizeof (struct udp_mib), + __alignof__(struct udp_mib)) < 0) + goto err_udp_mib; +- if (snmp_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib), ++ if (snmp_mib_init((void **)ve_udplite_stats_in6, sizeof (struct udp_mib), + __alignof__(struct udp_mib)) < 0) + goto err_udplite_mib; + return 0; + + err_udplite_mib: +- snmp_mib_free((void **)udp_stats_in6); ++ snmp_mib_free((void **)ve_udp_stats_in6); + err_udp_mib: +- snmp_mib_free((void **)icmpv6msg_statistics); ++ snmp_mib_free((void **)ve_icmpv6msg_statistics); + err_icmpmsg_mib: +- snmp_mib_free((void **)icmpv6_statistics); ++ snmp_mib_free((void **)ve_icmpv6_statistics); + err_icmp_mib: +- snmp_mib_free((void **)ipv6_statistics); ++ snmp_mib_free((void **)ve_ipv6_statistics); + err_ip_mib: + return -ENOMEM; + +@@ -745,11 +761,11 @@ + + static void cleanup_ipv6_mibs(void) + { +- snmp_mib_free((void **)ipv6_statistics); +- snmp_mib_free((void **)icmpv6_statistics); +- snmp_mib_free((void **)icmpv6msg_statistics); +- snmp_mib_free((void **)udp_stats_in6); +- snmp_mib_free((void **)udplite_stats_in6); ++ snmp_mib_free((void **)ve_ipv6_statistics); ++ snmp_mib_free((void **)ve_icmpv6_statistics); ++ snmp_mib_free((void **)ve_icmpv6msg_statistics); ++ snmp_mib_free((void **)ve_udp_stats_in6); ++ snmp_mib_free((void **)ve_udplite_stats_in6); + } + + static int __init inet6_init(void) +Index: kernel/net/ipv6/anycast.c +=================================================================== +--- kernel.orig/net/ipv6/anycast.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/anycast.c 2008-11-24 15:47:46.000000000 +0100 +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -83,7 +84,7 @@ + struct net_device *dev = NULL; + struct inet6_dev *idev; + struct ipv6_ac_socklist *pac; +- int ishost = !ipv6_devconf.forwarding; ++ int ishost = !ve_ipv6_devconf.forwarding; + int err = 0; + + if (!capable(CAP_NET_ADMIN)) +@@ -113,10 +114,10 @@ + } else { + /* router, no matching interface: just pick one */ + +- dev = dev_get_by_flags(&init_net, IFF_UP, IFF_UP|IFF_LOOPBACK); ++ dev = dev_get_by_flags(get_exec_env()->ve_ns->net_ns, IFF_UP, IFF_UP|IFF_LOOPBACK); + } + } else +- dev = dev_get_by_index(&init_net, ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifindex); + + if (dev == NULL) { + err = -ENODEV; +@@ -197,7 +198,7 @@ + + write_unlock_bh(&ipv6_sk_ac_lock); + +- dev = dev_get_by_index(&init_net, pac->acl_ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, pac->acl_ifindex); + if (dev) { + ipv6_dev_ac_dec(dev, &pac->acl_addr); + dev_put(dev); +@@ -225,7 +226,7 @@ + if (pac->acl_ifindex != prev_index) { + if (dev) + dev_put(dev); +- dev = dev_get_by_index(&init_net, pac->acl_ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, pac->acl_ifindex); + prev_index = pac->acl_ifindex; + } + if (dev) +@@ -430,7 +431,7 @@ + if (dev) + return ipv6_chk_acast_dev(dev, addr); + read_lock(&dev_base_lock); +- for_each_netdev(&init_net, dev) ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) + if (ipv6_chk_acast_dev(dev, addr)) { + found = 1; + break; +@@ -454,8 +455,9 @@ + struct ac6_iter_state *state = ac6_seq_private(seq); + + state->idev = NULL; +- for_each_netdev(&init_net, state->dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, state->dev) { + struct inet6_dev *idev; ++ + idev = in6_dev_get(state->dev); + if (!idev) + continue; +@@ -486,6 +488,8 @@ + state->idev = NULL; + break; + } ++ if (unlikely(!ve_accessible_strict(state->dev->owner_env, get_exec_env()))) ++ continue; + state->idev = in6_dev_get(state->dev); + if (!state->idev) + continue; +Index: kernel/net/ipv6/datagram.c +=================================================================== +--- kernel.orig/net/ipv6/datagram.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/datagram.c 2008-11-24 15:47:46.000000000 +0100 +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -544,7 +545,7 @@ + if (!src_info->ipi6_ifindex) + return -EINVAL; + else { +- dev = dev_get_by_index(&init_net, src_info->ipi6_ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, src_info->ipi6_ifindex); + if (!dev) + return -ENODEV; + } +Index: kernel/net/ipv6/exthdrs.c +=================================================================== +--- kernel.orig/net/ipv6/exthdrs.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/exthdrs.c 2008-11-24 15:47:46.000000000 +0100 +@@ -352,7 +352,7 @@ + int n, i; + struct ipv6_rt_hdr *hdr; + struct rt0_hdr *rthdr; +- int accept_source_route = ipv6_devconf.accept_source_route; ++ int accept_source_route = ve_ipv6_devconf.accept_source_route; + + idev = in6_dev_get(skb->dev); + if (idev) { +Index: kernel/net/ipv6/inet6_connection_sock.c +=================================================================== +--- kernel.orig/net/ipv6/inet6_connection_sock.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/inet6_connection_sock.c 2008-11-24 15:47:46.000000000 +0100 +@@ -25,6 +25,8 @@ + #include + #include + #include ++#include ++#include + + int inet6_csk_bind_conflict(const struct sock *sk, + const struct inet_bind_bucket *tb) +@@ -35,6 +37,7 @@ + /* We must walk the whole port owner list in this case. -DaveM */ + sk_for_each_bound(sk2, node, &tb->owners) { + if (sk != sk2 && ++ ve_accessible_strict(sk->owner_env, sk2->owner_env) && + (!sk->sk_bound_dev_if || + !sk2->sk_bound_dev_if || + sk->sk_bound_dev_if == sk2->sk_bound_dev_if) && +Index: kernel/net/ipv6/inet6_hashtables.c +=================================================================== +--- kernel.orig/net/ipv6/inet6_hashtables.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/inet6_hashtables.c 2008-11-24 15:47:46.000000000 +0100 +@@ -67,7 +67,8 @@ + /* Optimize here for direct hit, only listening connections can + * have wildcards anyways. + */ +- unsigned int hash = inet6_ehashfn(daddr, hnum, saddr, sport); ++ struct ve_struct *env = get_exec_env(); ++ unsigned int hash = inet6_ehashfn(daddr, hnum, saddr, sport, VEID(env)); + struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); + rwlock_t *lock = inet_ehash_lockp(hashinfo, hash); + +@@ -75,7 +76,7 @@ + read_lock(lock); + sk_for_each(sk, node, &head->chain) { + /* For IPV6 do the cheaper port and family tests first. */ +- if (INET6_MATCH(sk, hash, saddr, daddr, ports, dif)) ++ if (INET6_MATCH(sk, hash, saddr, daddr, ports, dif, env)) + goto hit; /* You sunk my battleship! */ + } + /* Must check for a TIME_WAIT'er before going to listener hash. */ +@@ -88,6 +89,7 @@ + + if (ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && + ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && ++ ve_accessible_strict(tw->tw_owner_env, VEID(env)) && + (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif)) + goto hit; + } +@@ -110,9 +112,15 @@ + const struct hlist_node *node; + struct sock *result = NULL; + int score, hiscore = 0; ++ struct ve_struct *env; ++ ++ env = get_exec_env(); + + read_lock(&hashinfo->lhash_lock); +- sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) { ++ sk_for_each(sk, node, &hashinfo->listening_hash[ ++ inet_lhashfn(hnum, VEID(env))]) { ++ if (!ve_accessible_strict(sk->owner_env, env)) ++ continue; + if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) { + const struct ipv6_pinfo *np = inet6_sk(sk); + +@@ -163,7 +171,8 @@ + + static int __inet6_check_established(struct inet_timewait_death_row *death_row, + struct sock *sk, const __u16 lport, +- struct inet_timewait_sock **twp) ++ struct inet_timewait_sock **twp, ++ struct ve_struct *ve) + { + struct inet_hashinfo *hinfo = death_row->hashinfo; + struct inet_sock *inet = inet_sk(sk); +@@ -173,7 +182,7 @@ + const int dif = sk->sk_bound_dev_if; + const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport); + const unsigned int hash = inet6_ehashfn(daddr, lport, saddr, +- inet->dport); ++ inet->dport, VEID(ve)); + struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); + rwlock_t *lock = inet_ehash_lockp(hinfo, hash); + struct sock *sk2; +@@ -193,7 +202,8 @@ + sk2->sk_family == PF_INET6 && + ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && + ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && +- (!sk2->sk_bound_dev_if || sk2->sk_bound_dev_if == dif)) { ++ (!sk2->sk_bound_dev_if || sk2->sk_bound_dev_if == dif) && ++ ve_accessible_strict(tw->tw_owner_env, VEID(ve))) { + if (twsk_unique(sk, sk2, twp)) + goto unique; + else +@@ -204,7 +214,7 @@ + + /* And established part... */ + sk_for_each(sk2, node, &head->chain) { +- if (INET6_MATCH(sk2, hash, saddr, daddr, ports, dif)) ++ if (INET6_MATCH(sk2, hash, saddr, daddr, ports, dif, ve)) + goto not_unique; + } + +@@ -253,7 +263,9 @@ + struct inet_bind_hashbucket *head; + struct inet_bind_bucket *tb; + int ret; ++ struct ve_struct *ve; + ++ ve = sk->owner_env; + if (snum == 0) { + int i, port, low, high, remaining; + static u32 hint; +@@ -267,7 +279,7 @@ + local_bh_disable(); + for (i = 1; i <= remaining; i++) { + port = low + (i + offset) % remaining; +- head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)]; ++ head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size, VEID(ve))]; + spin_lock(&head->lock); + + /* Does not bother with rcv_saddr checks, +@@ -275,20 +287,21 @@ + * unique enough. + */ + inet_bind_bucket_for_each(tb, node, &head->chain) { +- if (tb->port == port) { ++ if (tb->port == port && ++ ve_accessible_strict(tb->owner_env, ve)) { + BUG_TRAP(!hlist_empty(&tb->owners)); + if (tb->fastreuse >= 0) + goto next_port; + if (!__inet6_check_established(death_row, + sk, port, +- &tw)) ++ &tw, ve)) + goto ok; + goto next_port; + } + } + + tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, +- head, port); ++ head, port, ve); + if (!tb) { + spin_unlock(&head->lock); + break; +@@ -323,7 +336,7 @@ + goto out; + } + +- head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size)]; ++ head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size, VEID(ve))]; + tb = inet_csk(sk)->icsk_bind_hash; + spin_lock_bh(&head->lock); + +@@ -334,7 +347,7 @@ + } else { + spin_unlock(&head->lock); + /* No definite answer... Walk to established hash table */ +- ret = __inet6_check_established(death_row, sk, snum, NULL); ++ ret = __inet6_check_established(death_row, sk, snum, NULL, ve); + out: + local_bh_enable(); + return ret; +Index: kernel/net/ipv6/ip6_fib.c +=================================================================== +--- kernel.orig/net/ipv6/ip6_fib.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/ip6_fib.c 2008-11-24 15:47:46.000000000 +0100 +@@ -174,12 +174,28 @@ + }, + }; + ++#ifdef CONFIG_VE ++static inline void prepare_fib6_table(void) ++{ ++ get_ve0()->_fib6_table = &fib6_main_tbl; ++} ++ ++#define fib6_main_tbl (*(get_exec_env()->_fib6_table)) ++#else ++#define prepare_fib6_table() do { } while (0) ++#endif ++ + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + #define FIB_TABLE_HASHSZ 256 + #else + #define FIB_TABLE_HASHSZ 1 + #endif ++ ++#ifdef CONFIG_VE ++#define fib_table_hash (get_exec_env()->_fib6_table_hash) ++#else + static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; ++#endif + + static void fib6_link_table(struct fib6_table *tb) + { +@@ -193,11 +209,16 @@ + + h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1); + +- /* +- * No protection necessary, this is the only list mutatation +- * operation, tables never disappear once they exist. +- */ ++ write_lock_bh(&tb->tb6_lock); + hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]); ++ write_unlock_bh(&tb->tb6_lock); ++} ++ ++static void fib6_unlink_table(struct fib6_table *tb) ++{ ++ write_lock_bh(&tb->tb6_lock); ++ hlist_del_rcu(&tb->tb6_hlist); ++ write_unlock_bh(&tb->tb6_lock); + } + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES +@@ -209,6 +230,16 @@ + }, + }; + ++#ifdef CONFIG_VE ++static inline void prepare_fib6_local_table(void) ++{ ++ get_ve0()->_fib6_local_table = &fib6_local_tbl; ++} ++#define fib6_local_tbl (*(get_exec_env())->_fib6_local_table) ++#else ++#define prepare_fib6_local_table() do { } while (0) ++#endif ++ + static struct fib6_table *fib6_alloc_table(u32 id) + { + struct fib6_table *table; +@@ -261,12 +292,18 @@ + return NULL; + } + +-static void __init fib6_tables_init(void) ++void fib6_tables_init(void) + { + fib6_link_table(&fib6_main_tbl); + fib6_link_table(&fib6_local_tbl); + } + ++void fib6_tables_cleanup(void) ++{ ++ fib6_unlink_table(&fib6_main_tbl); ++ fib6_unlink_table(&fib6_local_tbl); ++} ++ + #else + + struct fib6_table *fib6_new_table(u32 id) +@@ -285,11 +322,16 @@ + return (struct dst_entry *) lookup(&fib6_main_tbl, fl, flags); + } + +-static void __init fib6_tables_init(void) ++void fib6_tables_init(void) + { + fib6_link_table(&fib6_main_tbl); + } + ++void fib6_tables_cleanup(void) ++{ ++ fib6_unlink_table(&fib6_main_tbl); ++} ++ + #endif + + static int fib6_dump_node(struct fib6_walker_t *w) +@@ -1371,9 +1413,13 @@ + for (h = 0; h < FIB_TABLE_HASHSZ; h++) { + hlist_for_each_entry_rcu(table, node, &fib_table_hash[h], + tb6_hlist) { ++ struct ve_struct *old_env; ++ ++ old_env = set_exec_env(table->owner_env); + write_lock_bh(&table->tb6_lock); + fib6_clean_tree(&table->tb6_root, func, prune, arg); + write_unlock_bh(&table->tb6_lock); ++ (void)set_exec_env(old_env); + } + } + rcu_read_unlock(); +@@ -1441,6 +1487,8 @@ + + static DEFINE_SPINLOCK(fib6_gc_lock); + ++LIST_HEAD(fib6_table_list); ++ + void fib6_run_gc(unsigned long dummy) + { + if (dummy != ~0UL) { +@@ -1473,9 +1521,13 @@ + { + fib6_node_kmem = kmem_cache_create("fib6_nodes", + sizeof(struct fib6_node), +- 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, ++ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_UBC, + NULL); + ++ prepare_fib6_table(); ++#ifdef CONFIG_IPV6_MULTIPLE_TABLES ++ prepare_fib6_local_table(); ++#endif + fib6_tables_init(); + + __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); +Index: kernel/net/ipv6/ip6_flowlabel.c +=================================================================== +--- kernel.orig/net/ipv6/ip6_flowlabel.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/ip6_flowlabel.c 2008-11-24 15:47:46.000000000 +0100 +@@ -448,6 +448,9 @@ + struct ip6_flowlabel *fl, *fl1 = NULL; + + ++ if (!ve_is_super(get_exec_env())) ++ return -EPERM; ++ + if (optlen < sizeof(freq)) + return -EINVAL; + +Index: kernel/net/ipv6/ip6_input.c +=================================================================== +--- kernel.orig/net/ipv6/ip6_input.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/ip6_input.c 2008-11-24 15:47:46.000000000 +0100 +@@ -61,11 +61,6 @@ + u32 pkt_len; + struct inet6_dev *idev; + +- if (dev->nd_net != &init_net) { +- kfree_skb(skb); +- return 0; +- } +- + if (skb->pkt_type == PACKET_OTHERHOST) { + kfree_skb(skb); + return 0; +Index: kernel/net/ipv6/ip6_output.c +=================================================================== +--- kernel.orig/net/ipv6/ip6_output.c 2008-11-24 14:14:31.000000000 +0100 ++++ kernel/net/ipv6/ip6_output.c 2008-11-24 15:47:46.000000000 +0100 +@@ -378,7 +378,7 @@ + struct ipv6hdr *hdr = ipv6_hdr(skb); + struct inet6_skb_parm *opt = IP6CB(skb); + +- if (ipv6_devconf.forwarding == 0) ++ if (ve_ipv6_devconf.forwarding == 0) + goto error; + + if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { +@@ -422,7 +422,7 @@ + } + + /* XXX: idev->cnf.proxy_ndp? */ +- if (ipv6_devconf.proxy_ndp && ++ if (ve_ipv6_devconf.proxy_ndp && + pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) { + int proxied = ip6_forward_proxy_check(skb); + if (proxied > 0) +@@ -488,6 +488,20 @@ + return -EMSGSIZE; + } + ++ /* ++ * We try to optimize forwarding of VE packets: ++ * do not decrement TTL (and so save skb_cow) ++ * during forwarding of outgoing pkts from VE. ++ * For incoming pkts we still do ttl decr, ++ * since such skb is not cloned and does not require ++ * actual cow. So, there is at least one place ++ * in pkts path with mandatory ttl decr, that is ++ * sufficient to prevent routing loops. ++ */ ++ hdr = ipv6_hdr(skb); ++ if (skb->dev->features & NETIF_F_VENET) /* src is VENET device */ ++ goto no_ttl_decr; ++ + if (skb_cow(skb, dst->dev->hard_header_len)) { + IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS); + goto drop; +@@ -499,6 +513,7 @@ + + hdr->hop_limit--; + ++no_ttl_decr: + IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); + return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish); + +Index: kernel/net/ipv6/ipv6_sockglue.c +=================================================================== +--- kernel.orig/net/ipv6/ipv6_sockglue.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/ipv6_sockglue.c 2008-11-24 15:47:46.000000000 +0100 +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -544,7 +545,7 @@ + if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) + goto e_inval; + +- if (__dev_get_by_index(&init_net, val) == NULL) { ++ if (__dev_get_by_index(get_exec_env()->ve_ns->net_ns, val) == NULL) { + retv = -ENODEV; + break; + } +@@ -1021,7 +1022,7 @@ + dst_release(dst); + } + if (val < 0) +- val = ipv6_devconf.hop_limit; ++ val = ve_ipv6_devconf.hop_limit; + break; + } + +Index: kernel/net/ipv6/mcast.c +=================================================================== +--- kernel.orig/net/ipv6/mcast.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/mcast.c 2008-11-24 15:47:46.000000000 +0100 +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -156,7 +157,7 @@ + #define IGMP6_UNSOLICITED_IVAL (10*HZ) + #define MLD_QRV_DEFAULT 2 + +-#define MLD_V1_SEEN(idev) (ipv6_devconf.force_mld_version == 1 || \ ++#define MLD_V1_SEEN(idev) (ve_ipv6_devconf.force_mld_version == 1 || \ + (idev)->cnf.force_mld_version == 1 || \ + ((idev)->mc_v1_seen && \ + time_before(jiffies, (idev)->mc_v1_seen))) +@@ -215,7 +216,7 @@ + dst_release(&rt->u.dst); + } + } else +- dev = dev_get_by_index(&init_net, ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifindex); + + if (dev == NULL) { + sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); +@@ -248,6 +249,7 @@ + + return 0; + } ++EXPORT_SYMBOL_GPL(ipv6_sock_mc_join); + + /* + * socket leave on multicast group +@@ -266,7 +268,7 @@ + *lnk = mc_lst->next; + write_unlock_bh(&ipv6_sk_mc_lock); + +- if ((dev = dev_get_by_index(&init_net, mc_lst->ifindex)) != NULL) { ++ if ((dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, mc_lst->ifindex)) != NULL) { + struct inet6_dev *idev = in6_dev_get(dev); + + (void) ip6_mc_leave_src(sk, mc_lst, idev); +@@ -301,7 +303,7 @@ + dst_release(&rt->u.dst); + } + } else +- dev = dev_get_by_index(&init_net, ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifindex); + + if (!dev) + return NULL; +@@ -332,7 +334,7 @@ + np->ipv6_mc_list = mc_lst->next; + write_unlock_bh(&ipv6_sk_mc_lock); + +- dev = dev_get_by_index(&init_net, mc_lst->ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, mc_lst->ifindex); + if (dev) { + struct inet6_dev *idev = in6_dev_get(dev); + +@@ -2170,15 +2172,18 @@ + static void mld_gq_timer_expire(unsigned long data) + { + struct inet6_dev *idev = (struct inet6_dev *)data; ++ struct ve_struct *old_env = set_exec_env(idev->dev->owner_env); + + idev->mc_gq_running = 0; + mld_send_report(idev, NULL); + __in6_dev_put(idev); ++ set_exec_env(old_env); + } + + static void mld_ifc_timer_expire(unsigned long data) + { + struct inet6_dev *idev = (struct inet6_dev *)data; ++ struct ve_struct *old_env = set_exec_env(idev->dev->owner_env); + + mld_send_cr(idev); + if (idev->mc_ifc_count) { +@@ -2187,6 +2192,7 @@ + mld_ifc_start_timer(idev, idev->mc_maxdelay); + } + __in6_dev_put(idev); ++ set_exec_env(old_env); + } + + static void mld_ifc_event(struct inet6_dev *idev) +@@ -2201,6 +2207,7 @@ + static void igmp6_timer_handler(unsigned long data) + { + struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data; ++ struct ve_struct *old_env = set_exec_env(ma->idev->dev->owner_env); + + if (MLD_V1_SEEN(ma->idev)) + igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT); +@@ -2212,6 +2219,7 @@ + ma->mca_flags &= ~MAF_TIMER_RUNNING; + spin_unlock(&ma->mca_lock); + ma_put(ma); ++ set_exec_env(old_env); + } + + /* Device going down */ +@@ -2326,8 +2334,9 @@ + struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); + + state->idev = NULL; +- for_each_netdev(&init_net, state->dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, state->dev) { + struct inet6_dev *idev; ++ + idev = in6_dev_get(state->dev); + if (!idev) + continue; +@@ -2454,8 +2463,9 @@ + + state->idev = NULL; + state->im = NULL; +- for_each_netdev(&init_net, state->dev) { ++ for_each_netdev(get_exec_env()->ve_ns->net_ns, state->dev) { + struct inet6_dev *idev; ++ + idev = in6_dev_get(state->dev); + if (unlikely(idev == NULL)) + continue; +Index: kernel/net/ipv6/ndisc.c +=================================================================== +--- kernel.orig/net/ipv6/ndisc.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/ndisc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -128,7 +128,7 @@ + .queue_xmit = dev_queue_xmit, + }; + +-struct neigh_table nd_tbl = { ++struct neigh_table global_nd_tbl = { + .family = AF_INET6, + .entry_size = sizeof(struct neighbour) + sizeof(struct in6_addr), + .key_len = sizeof(struct in6_addr), +@@ -139,7 +139,7 @@ + .proxy_redo = pndisc_redo, + .id = "ndisc_cache", + .parms = { +- .tbl = &nd_tbl, ++ .tbl = &global_nd_tbl, + .base_reachable_time = 30 * HZ, + .retrans_time = 1 * HZ, + .gc_staletime = 60 * HZ, +@@ -787,7 +787,7 @@ + + if (ipv6_chk_acast_addr(dev, &msg->target) || + (idev->cnf.forwarding && +- (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && ++ (ve_ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && + (pneigh = pneigh_lookup(&nd_tbl, + &msg->target, dev, 0)) != NULL)) { + if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && +@@ -928,7 +928,7 @@ + * has already sent a NA to us. + */ + if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && +- ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && ++ ve_ipv6_devconf.forwarding && ve_ipv6_devconf.proxy_ndp && + pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) { + /* XXX: idev->cnf.prixy_ndp */ + goto out; +@@ -1610,9 +1610,6 @@ + { + struct net_device *dev = ptr; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + switch (event) { + case NETDEV_CHANGEADDR: + neigh_changeaddr(&nd_tbl, dev); +@@ -1729,6 +1726,55 @@ + + #endif + ++static int ndisc_net_init(struct net *net) ++{ ++ struct ve_struct *ve = get_exec_env(); ++ int err; ++ ++ ve->ve_nd_tbl = kmemdup(ve0.ve_nd_tbl, sizeof(struct neigh_table), ++ GFP_KERNEL); ++ if (ve->ve_nd_tbl == NULL) ++ return -ENOMEM; ++ ve->ve_nd_tbl->parms.tbl = ve->ve_nd_tbl; ++ ++ err = neigh_table_init(ve->ve_nd_tbl); ++ if (err) ++ goto out_free; ++#ifdef CONFIG_SYSCTL ++ neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, ++ "ipv6", ++ &ndisc_ifinfo_sysctl_change, ++ &ndisc_ifinfo_sysctl_strategy); ++#endif ++ err = 0; ++out: ++ return err; ++ ++out_free: ++ kfree(ve->ve_nd_tbl); ++ ve->ve_nd_tbl = NULL; ++ goto out; ++} ++ ++static void ndisc_net_exit(struct net *net) ++{ ++ struct ve_struct *ve = get_exec_env(); ++ ++ if (ve->ve_nd_tbl) { ++#ifdef CONFIG_SYSCTL ++ neigh_sysctl_unregister(&ve->ve_nd_tbl->parms); ++#endif ++ neigh_table_clear(ve->ve_nd_tbl); ++ kfree(ve->ve_nd_tbl); ++ ve->ve_nd_tbl = NULL; ++ } ++} ++ ++static struct pernet_operations ndisc_net_ops = { ++ .init = ndisc_net_init, ++ .exit = ndisc_net_exit, ++}; ++ + int __init ndisc_init(struct net_proto_family *ops) + { + struct ipv6_pinfo *np; +@@ -1755,15 +1801,8 @@ + /* + * Initialize the neighbour table + */ +- +- neigh_table_init(&nd_tbl); +- +-#ifdef CONFIG_SYSCTL +- neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, +- "ipv6", +- &ndisc_ifinfo_sysctl_change, +- &ndisc_ifinfo_sysctl_strategy); +-#endif ++ get_ve0()->ve_nd_tbl = &global_nd_tbl; ++ register_pernet_subsys(&ndisc_net_ops); + + register_netdevice_notifier(&ndisc_netdev_notifier); + return 0; +@@ -1772,10 +1811,7 @@ + void ndisc_cleanup(void) + { + unregister_netdevice_notifier(&ndisc_netdev_notifier); +-#ifdef CONFIG_SYSCTL +- neigh_sysctl_unregister(&nd_tbl.parms); +-#endif +- neigh_table_clear(&nd_tbl); ++ unregister_pernet_subsys(&ndisc_net_ops); + sock_release(ndisc_socket); + ndisc_socket = NULL; /* For safety. */ + } +Index: kernel/net/ipv6/netfilter/ip6_queue.c +=================================================================== +--- kernel.orig/net/ipv6/netfilter/ip6_queue.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/netfilter/ip6_queue.c 2008-11-24 15:47:46.000000000 +0100 +@@ -491,7 +491,7 @@ + if (type <= IPQM_BASE) + return; + +- if (security_netlink_recv(skb, CAP_NET_ADMIN)) ++ if (security_netlink_recv(skb, CAP_VE_NET_ADMIN)) + RCV_SKB_FAIL(-EPERM); + + write_lock_bh(&queue_lock); +@@ -521,8 +521,12 @@ + static void + ipq_rcv_skb(struct sk_buff *skb) + { ++ struct ve_struct *old_ve; ++ + mutex_lock(&ipqnl_mutex); ++ old_ve = set_exec_env(skb->owner_env); + __ipq_rcv_skb(skb); ++ (void)set_exec_env(old_ve); + mutex_unlock(&ipqnl_mutex); + } + +@@ -532,9 +536,6 @@ + { + struct net_device *dev = ptr; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + /* Drop any packets associated with the downed device */ + if (event == NETDEV_DOWN) + ipq_dev_drop(dev->ifindex); +@@ -554,7 +555,7 @@ + if (event == NETLINK_URELEASE && + n->protocol == NETLINK_IP6_FW && n->pid) { + write_lock_bh(&queue_lock); +- if ((n->net == &init_net) && (n->pid == peer_pid)) ++ if (n->pid == peer_pid) + __ipq_reset(); + write_unlock_bh(&queue_lock); + } +Index: kernel/net/ipv6/netfilter/ip6_tables.c +=================================================================== +--- kernel.orig/net/ipv6/netfilter/ip6_tables.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/netfilter/ip6_tables.c 2008-11-24 15:47:46.000000000 +0100 +@@ -26,6 +26,7 @@ + + #include + #include ++#include + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Netfilter Core Team "); +@@ -1211,9 +1212,14 @@ + { + int ret; + +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_VE_NET_ADMIN)) + return -EPERM; + ++#ifdef CONFIG_VE_IPTABLES ++ if (!get_exec_env()->_xt_tables[AF_INET6].next) ++ return -ENOENT; ++#endif ++ + switch (cmd) { + case IP6T_SO_SET_REPLACE: + ret = do_replace(user, len); +@@ -1236,9 +1242,14 @@ + { + int ret; + +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_VE_NET_ADMIN)) + return -EPERM; + ++#ifdef CONFIG_VE_IPTABLES ++ if (!get_exec_env()->_xt_tables[AF_INET6].next) ++ return -ENOENT; ++#endif ++ + switch (cmd) { + case IP6T_SO_GET_INFO: { + char name[IP6T_TABLE_MAXNAMELEN]; +@@ -1334,18 +1345,18 @@ + return ret; + } + +-int ip6t_register_table(struct xt_table *table, ++struct ip6t_table *ip6t_register_table(struct xt_table *table, + const struct ip6t_replace *repl) + { + int ret; + struct xt_table_info *newinfo; + static struct xt_table_info bootstrap +- = { 0, 0, 0, { 0 }, { 0 }, { } }; ++ = { 0, 0, 0, 0, { 0 }, { 0 }, { } }; + void *loc_cpu_entry; + + newinfo = xt_alloc_table_info(repl->size); + if (!newinfo) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); + + /* choose the copy on our node/cpu */ + loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; +@@ -1358,28 +1369,29 @@ + repl->underflow); + if (ret != 0) { + xt_free_table_info(newinfo); +- return ret; ++ return ERR_PTR(ret); + } + +- ret = xt_register_table(table, &bootstrap, newinfo); +- if (ret != 0) { ++ table = virt_xt_register_table(table, &bootstrap, newinfo); ++ if (IS_ERR(table)) + xt_free_table_info(newinfo); +- return ret; +- } +- +- return 0; ++ return table; + } + + void ip6t_unregister_table(struct xt_table *table) + { + struct xt_table_info *private; + void *loc_cpu_entry; ++ struct module *me; + +- private = xt_unregister_table(table); ++ me = table->me; ++ private = virt_xt_unregister_table(table); + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries[raw_smp_processor_id()]; + IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL); ++ if (private->number > private->initial_entries) ++ module_put(me); + xt_free_table_info(private); + } + +@@ -1474,12 +1486,30 @@ + .family = AF_INET6, + }; + ++static int init_ip6tables(void) ++{ ++#ifdef CONFIG_VE_IPTABLES ++ if (get_exec_env()->_xt_tables[AF_INET6].next != NULL) ++ return -EEXIST; ++#endif ++ ++ return xt_proto_init(AF_INET6); ++} ++ ++static void fini_ip6tables(void) ++{ ++#ifdef CONFIG_VE_IPTABLES ++ get_exec_env()->_xt_tables[AF_INET6].next = NULL; ++#endif ++ xt_proto_fini(AF_INET6); ++} ++ + static int __init ip6_tables_init(void) + { + int ret; + +- ret = xt_proto_init(AF_INET6); +- if (ret < 0) ++ ret = init_ip6tables(); ++ if (ret) + goto err1; + + /* Noone else will be downing sem now, so we won't sleep */ +@@ -1498,6 +1528,10 @@ + if (ret < 0) + goto err5; + ++ KSYMRESOLVE(init_ip6tables); ++ KSYMRESOLVE(fini_ip6tables); ++ KSYMMODRESOLVE(ip6_tables); ++ + printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n"); + return 0; + +@@ -1508,18 +1542,21 @@ + err3: + xt_unregister_target(&ip6t_standard_target); + err2: +- xt_proto_fini(AF_INET6); ++ fini_ip6tables(); + err1: + return ret; + } + + static void __exit ip6_tables_fini(void) + { ++ KSYMMODUNRESOLVE(ip6_tables); ++ KSYMUNRESOLVE(init_ip6tables); ++ KSYMUNRESOLVE(fini_ip6tables); + nf_unregister_sockopt(&ip6t_sockopts); + xt_unregister_match(&icmp6_matchstruct); + xt_unregister_target(&ip6t_error_target); + xt_unregister_target(&ip6t_standard_target); +- xt_proto_fini(AF_INET6); ++ fini_ip6tables(); + } + + /* +@@ -1605,5 +1642,5 @@ + EXPORT_SYMBOL(ip6t_ext_hdr); + EXPORT_SYMBOL(ipv6_find_hdr); + +-module_init(ip6_tables_init); ++subsys_initcall(ip6_tables_init); + module_exit(ip6_tables_fini); +Index: kernel/net/ipv6/netfilter/ip6table_filter.c +=================================================================== +--- kernel.orig/net/ipv6/netfilter/ip6table_filter.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/netfilter/ip6table_filter.c 2008-11-24 15:47:46.000000000 +0100 +@@ -11,12 +11,20 @@ + + #include + #include ++#include + #include + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Netfilter Core Team "); + MODULE_DESCRIPTION("ip6tables filter table"); + ++#ifdef CONFIG_VE_IPTABLES ++#include ++#define ve_packet_filter (get_exec_env()->_ve_ip6t_filter_pf) ++#else ++#define ve_packet_filter &packet_filter ++#endif ++ + #define FILTER_VALID_HOOKS ((1 << NF_IP6_LOCAL_IN) | (1 << NF_IP6_FORWARD) | (1 << NF_IP6_LOCAL_OUT)) + + static struct +@@ -24,7 +32,7 @@ + struct ip6t_replace repl; + struct ip6t_standard entries[3]; + struct ip6t_error term; +-} initial_table __initdata = { ++} initial_table = { + .repl = { + .name = "filter", + .valid_hooks = FILTER_VALID_HOOKS, +@@ -65,7 +73,7 @@ + const struct net_device *out, + int (*okfn)(struct sk_buff *)) + { +- return ip6t_do_table(skb, hook, in, out, &packet_filter); ++ return ip6t_do_table(skb, hook, in, out, ve_packet_filter); + } + + static unsigned int +@@ -85,7 +93,7 @@ + } + #endif + +- return ip6t_do_table(skb, hook, in, out, &packet_filter); ++ return ip6t_do_table(skb, hook, in, out, ve_packet_filter); + } + + static struct nf_hook_ops ip6t_ops[] = { +@@ -116,22 +124,19 @@ + static int forward = NF_ACCEPT; + module_param(forward, bool, 0000); + +-static int __init ip6table_filter_init(void) ++int init_ip6table_filter(void) + { + int ret; +- +- if (forward < 0 || forward > NF_MAX_VERDICT) { +- printk("iptables forward must be 0 or 1\n"); +- return -EINVAL; +- } +- +- /* Entry 1 is the FORWARD hook */ +- initial_table.entries[1].target.verdict = -forward - 1; ++ struct ip6t_table *tmp_filter; + + /* Register table */ +- ret = ip6t_register_table(&packet_filter, &initial_table.repl); +- if (ret < 0) +- return ret; ++ tmp_filter = ip6t_register_table(&packet_filter, ++ &initial_table.repl); ++ if (IS_ERR(tmp_filter)) ++ return PTR_ERR(tmp_filter); ++#ifdef CONFIG_VE_IPTABLES ++ ve_packet_filter = tmp_filter; ++#endif + + /* Register hooks */ + ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); +@@ -141,14 +146,50 @@ + return ret; + + cleanup_table: +- ip6t_unregister_table(&packet_filter); ++ ip6t_unregister_table(ve_packet_filter); ++#ifdef CONFIG_VE_IPTABLES ++ ve_packet_filter = NULL; ++#endif + return ret; + } + +-static void __exit ip6table_filter_fini(void) ++void fini_ip6table_filter(void) + { + nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); +- ip6t_unregister_table(&packet_filter); ++ ip6t_unregister_table(ve_packet_filter); ++#ifdef CONFIG_VE_IPTABLES ++ ve_packet_filter = NULL; ++#endif ++} ++ ++static int __init ip6table_filter_init(void) ++{ ++ int err; ++ ++ if (forward < 0 || forward > NF_MAX_VERDICT) { ++ printk("iptables forward must be 0 or 1\n"); ++ return -EINVAL; ++ } ++ ++ /* Entry 1 is the FORWARD hook */ ++ initial_table.entries[1].target.verdict = -forward - 1; ++ ++ err = init_ip6table_filter(); ++ if (err < 0) ++ return err; ++ ++ KSYMRESOLVE(init_ip6table_filter); ++ KSYMRESOLVE(fini_ip6table_filter); ++ KSYMMODRESOLVE(ip6table_filter); ++ return 0; ++} ++ ++static void __exit ip6table_filter_fini(void) ++{ ++ KSYMMODUNRESOLVE(ip6table_filter); ++ KSYMUNRESOLVE(init_ip6table_filter); ++ KSYMUNRESOLVE(fini_ip6table_filter); ++ fini_ip6table_filter(); + } + + module_init(ip6table_filter_init); +Index: kernel/net/ipv6/netfilter/ip6table_mangle.c +=================================================================== +--- kernel.orig/net/ipv6/netfilter/ip6table_mangle.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/netfilter/ip6table_mangle.c 2008-11-24 15:47:46.000000000 +0100 +@@ -10,6 +10,7 @@ + */ + #include + #include ++#include + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Netfilter Core Team "); +@@ -26,7 +27,7 @@ + struct ip6t_replace repl; + struct ip6t_standard entries[5]; + struct ip6t_error term; +-} initial_table __initdata = { ++} initial_table = { + .repl = { + .name = "mangle", + .valid_hooks = MANGLE_VALID_HOOKS, +@@ -65,6 +66,13 @@ + .af = AF_INET6, + }; + ++#ifdef CONFIG_VE_IPTABLES ++#include ++#define ve_packet_mangler (get_exec_env()->_ip6t_mangle_table) ++#else ++#define ve_packet_mangler &packet_mangler ++#endif ++ + /* The work comes in here from netfilter.c. */ + static unsigned int + ip6t_route_hook(unsigned int hook, +@@ -73,7 +81,7 @@ + const struct net_device *out, + int (*okfn)(struct sk_buff *)) + { +- return ip6t_do_table(skb, hook, in, out, &packet_mangler); ++ return ip6t_do_table(skb, hook, in, out, ve_packet_mangler); + } + + static unsigned int +@@ -108,7 +116,7 @@ + /* flowlabel and prio (includes version, which shouldn't change either */ + flowlabel = *((u_int32_t *)ipv6_hdr(skb)); + +- ret = ip6t_do_table(skb, hook, in, out, &packet_mangler); ++ ret = ip6t_do_table(skb, hook, in, out, ve_packet_mangler); + + if (ret != NF_DROP && ret != NF_STOLEN + && (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) +@@ -158,14 +166,19 @@ + }, + }; + +-static int __init ip6table_mangle_init(void) ++int init_ip6table_mangle(void) + { + int ret; ++ struct ip6t_table *tmp_mangler; + + /* Register table */ +- ret = ip6t_register_table(&packet_mangler, &initial_table.repl); +- if (ret < 0) +- return ret; ++ tmp_mangler = ip6t_register_table(&packet_mangler, ++ &initial_table.repl); ++ if (IS_ERR(tmp_mangler)) ++ return PTR_ERR(tmp_mangler); ++#ifdef CONFIG_VE_IPTABLES ++ ve_packet_mangler = tmp_mangler; ++#endif + + /* Register hooks */ + ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); +@@ -175,14 +188,42 @@ + return ret; + + cleanup_table: +- ip6t_unregister_table(&packet_mangler); ++ ip6t_unregister_table(ve_packet_mangler); ++#ifdef CONFIG_VE_IPTABLES ++ ve_packet_mangler = NULL; ++#endif + return ret; + } + +-static void __exit ip6table_mangle_fini(void) ++void fini_ip6table_mangle(void) + { + nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); +- ip6t_unregister_table(&packet_mangler); ++ ip6t_unregister_table(ve_packet_mangler); ++#ifdef CONFIG_VE_IPTABLES ++ ve_packet_mangler = NULL; ++#endif ++} ++ ++static int __init ip6table_mangle_init(void) ++{ ++ int err; ++ ++ err = init_ip6table_mangle(); ++ if (err < 0) ++ return err; ++ ++ KSYMRESOLVE(init_ip6table_mangle); ++ KSYMRESOLVE(fini_ip6table_mangle); ++ KSYMMODRESOLVE(ip6table_mangle); ++ return 0; ++} ++ ++static void __exit ip6table_mangle_fini(void) ++{ ++ KSYMMODUNRESOLVE(ip6table_mangle); ++ KSYMUNRESOLVE(init_ip6table_mangle); ++ KSYMUNRESOLVE(fini_ip6table_mangle); ++ fini_ip6table_mangle(); + } + + module_init(ip6table_mangle_init); +Index: kernel/net/ipv6/netfilter/ip6table_raw.c +=================================================================== +--- kernel.orig/net/ipv6/netfilter/ip6table_raw.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/netfilter/ip6table_raw.c 2008-11-24 15:47:46.000000000 +0100 +@@ -74,11 +74,12 @@ + static int __init ip6table_raw_init(void) + { + int ret; ++ struct ip6t_table *tmp; + + /* Register table */ +- ret = ip6t_register_table(&packet_raw, &initial_table.repl); +- if (ret < 0) +- return ret; ++ tmp = ip6t_register_table(&packet_raw, &initial_table.repl); ++ if (IS_ERR(tmp)) ++ return PTR_ERR(tmp); + + /* Register hooks */ + ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); +Index: kernel/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +=================================================================== +--- kernel.orig/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c 2008-11-24 15:47:46.000000000 +0100 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -394,39 +395,103 @@ + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI "); + +-static int __init nf_conntrack_l3proto_ipv6_init(void) ++#if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) ++static void nf_ct_proto_ipv6_sysctl_cleanup(void) + { +- int ret = 0; ++ if (!ve_is_super(get_exec_env())) { ++ free_sysctl_clone(ve_nf_conntrack_l3proto_ipv6->ctl_table); ++ ve_nf_conntrack_l3proto_ipv6->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l3proto_ipv6); ++ ve_nf_conntrack_l3proto_ipv6 = NULL; ++ } ++} + +- need_conntrack(); ++static int nf_ct_proto_ipv6_sysctl_init(void) ++{ ++ struct nf_conntrack_l3proto *ipv6; + ++ if (ve_is_super(get_exec_env())) { ++ ipv6 = &nf_conntrack_l3proto_ipv6; ++ goto out; ++ } ++ ++ ipv6 = kmemdup(&nf_conntrack_l3proto_ipv6, ++ sizeof(struct nf_conntrack_l3proto), GFP_KERNEL); ++ if (!ipv6) ++ goto no_mem_ct; ++ ++ ipv6->ctl_table_path = nf_net_netfilter_sysctl_path; ++ ipv6->ctl_table = clone_sysctl_template(nf_ct_ipv6_sysctl_table); ++ if (!ipv6->ctl_table) ++ goto no_mem_sys; ++ ++ ipv6->ctl_table[0].data = &ve_nf_ct_frag6_timeout; ++ ipv6->ctl_table[1].data = &ve_nf_ct_frag6_low_thresh; ++ ipv6->ctl_table[2].data = &ve_nf_ct_frag6_high_thresh; ++out: ++ ve_nf_ct_frag6_timeout = nf_frags_ctl.timeout; ++ ve_nf_ct_frag6_low_thresh = nf_frags_ctl.low_thresh; ++ ve_nf_ct_frag6_high_thresh = nf_frags_ctl.high_thresh; ++ ++ ve_nf_conntrack_l3proto_ipv6 = ipv6; ++ return 0; ++ ++no_mem_sys: ++ kfree(ipv6); ++no_mem_ct: ++ return -ENOMEM; ++} ++#endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ ++ ++int init_nf_ct_l3proto_ipv6(void) ++{ ++ int ret = -ENOMEM; ++ ++#ifdef CONFIG_VE_IPTABLES ++ if (!ve_is_super(get_exec_env())) ++ __module_get(THIS_MODULE); ++ ++ ret = nf_ct_proto_ipv6_sysctl_init(); ++ if (ret < 0) ++ goto no_mem_ipv6; ++ ret = nf_ct_proto_tcp_sysctl_init(); ++ if (ret < 0) ++ goto no_mem_tcp; ++ ret = nf_ct_proto_udp_sysctl_init(); ++ if (ret < 0) ++ goto no_mem_udp; ++ ret = nf_ct_proto_icmpv6_sysctl_init(); ++ if (ret < 0) ++ goto no_mem_icmp; ++#endif /* CONFIG_VE_IPTABLES */ + ret = nf_ct_frag6_init(); + if (ret < 0) { + printk("nf_conntrack_ipv6: can't initialize frag6.\n"); +- return ret; ++ goto cleanup_sys; + } +- ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6); ++ ++ ret = nf_conntrack_l4proto_register(ve_nf_conntrack_l4proto_tcp6); + if (ret < 0) { + printk("nf_conntrack_ipv6: can't register tcp.\n"); + goto cleanup_frag6; + } + +- ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6); ++ ret = nf_conntrack_l4proto_register(ve_nf_conntrack_l4proto_udp6); + if (ret < 0) { + printk("nf_conntrack_ipv6: can't register udp.\n"); +- goto cleanup_tcp; ++ goto unreg_tcp; + } + +- ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmpv6); ++ ret = nf_conntrack_l4proto_register(ve_nf_conntrack_l4proto_icmpv6); + if (ret < 0) { + printk("nf_conntrack_ipv6: can't register icmpv6.\n"); +- goto cleanup_udp; ++ goto unreg_udp; + } + +- ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6); ++ ret = nf_conntrack_l3proto_register(ve_nf_conntrack_l3proto_ipv6); + if (ret < 0) { + printk("nf_conntrack_ipv6: can't register ipv6\n"); +- goto cleanup_icmpv6; ++ goto unreg_icmpv6; + } + + ret = nf_register_hooks(ipv6_conntrack_ops, +@@ -434,32 +499,80 @@ + if (ret < 0) { + printk("nf_conntrack_ipv6: can't register pre-routing defrag " + "hook.\n"); +- goto cleanup_ipv6; ++ goto unreg_ipv6; + } +- return ret; ++ return 0; + +- cleanup_ipv6: +- nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6); +- cleanup_icmpv6: +- nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); +- cleanup_udp: +- nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6); +- cleanup_tcp: +- nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6); +- cleanup_frag6: ++unreg_ipv6: ++ nf_conntrack_l3proto_unregister(ve_nf_conntrack_l3proto_ipv6); ++unreg_icmpv6: ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_icmpv6); ++unreg_udp: ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_udp6); ++unreg_tcp: ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_tcp6); ++cleanup_frag6: + nf_ct_frag6_cleanup(); ++cleanup_sys: ++#ifdef CONFIG_VE_IPTABLES ++no_mem_icmp: ++ nf_ct_proto_udp_sysctl_cleanup(); ++no_mem_udp: ++ nf_ct_proto_tcp_sysctl_cleanup(); ++no_mem_tcp: ++ nf_ct_proto_ipv6_sysctl_cleanup(); ++no_mem_ipv6: ++ if (!ve_is_super(get_exec_env())) ++ module_put(THIS_MODULE); ++#endif /* CONFIG_VE_IPTABLES */ + return ret; + } ++EXPORT_SYMBOL(init_nf_ct_l3proto_ipv6); + +-static void __exit nf_conntrack_l3proto_ipv6_fini(void) ++void fini_nf_ct_l3proto_ipv6(void) + { +- synchronize_net(); + nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); +- nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6); +- nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); +- nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6); +- nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6); ++ nf_conntrack_l3proto_unregister(ve_nf_conntrack_l3proto_ipv6); ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_icmpv6); ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_udp6); ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_tcp6); + nf_ct_frag6_cleanup(); ++ ++#ifdef CONFIG_VE_IPTABLES ++ nf_ct_proto_icmpv6_sysctl_cleanup(); ++ nf_ct_proto_udp_sysctl_cleanup(); ++ nf_ct_proto_tcp_sysctl_cleanup(); ++ nf_ct_proto_ipv6_sysctl_cleanup(); ++ if (!ve_is_super(get_exec_env())) ++ module_put(THIS_MODULE); ++#endif /* CONFIG_VE_IPTABLES */ ++} ++EXPORT_SYMBOL(fini_nf_ct_l3proto_ipv6); ++ ++static int __init nf_conntrack_l3proto_ipv6_init(void) ++{ ++ int ret = 0; ++ ++ need_conntrack(); ++ ++ ret = init_nf_ct_l3proto_ipv6(); ++ if (ret < 0) { ++ printk(KERN_ERR "Unable to initialize netfilter protocols\n"); ++ return ret; ++ } ++ KSYMRESOLVE(init_nf_ct_l3proto_ipv6); ++ KSYMRESOLVE(fini_nf_ct_l3proto_ipv6); ++ KSYMMODRESOLVE(nf_conntrack_ipv6); ++ return 0; ++} ++ ++static void __exit nf_conntrack_l3proto_ipv6_fini(void) ++{ ++ synchronize_net(); ++ KSYMMODUNRESOLVE(nf_conntrack_ipv6); ++ KSYMUNRESOLVE(init_nf_ct_l3proto_ipv6); ++ KSYMUNRESOLVE(fini_nf_ct_l3proto_ipv6); ++ fini_nf_ct_l3proto_ipv6(); + } + + module_init(nf_conntrack_l3proto_ipv6_init); +Index: kernel/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +=================================================================== +--- kernel.orig/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c 2008-11-24 15:47:46.000000000 +0100 +@@ -10,6 +10,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -100,7 +101,7 @@ + } else { + atomic_inc(&ct->proto.icmp.count); + nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb); +- nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout); ++ nf_ct_refresh_acct(ct, ctinfo, skb, ve_nf_ct_icmpv6_timeout); + } + + return NF_ACCEPT; +@@ -156,7 +157,7 @@ + /* Ordinarily, we'd expect the inverted tupleproto, but it's + been preserved inside the ICMP. */ + if (!nf_ct_invert_tuple(&intuple, &origtuple, +- &nf_conntrack_l3proto_ipv6, inproto)) { ++ ve_nf_conntrack_l3proto_ipv6, inproto)) { + pr_debug("icmpv6_error: Can't invert tuple\n"); + return -NF_ACCEPT; + } +@@ -294,3 +295,49 @@ + .ctl_table = icmpv6_sysctl_table, + #endif + }; ++ ++#if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) ++void nf_ct_proto_icmpv6_sysctl_cleanup(void) ++{ ++ if (!ve_is_super(get_exec_env())) { ++ free_sysctl_clone(ve_nf_conntrack_l4proto_icmpv6->ctl_table); ++ ve_nf_conntrack_l4proto_icmpv6->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l4proto_icmpv6); ++ ve_nf_conntrack_l4proto_icmpv6 = NULL; ++ } ++} ++EXPORT_SYMBOL(nf_ct_proto_icmpv6_sysctl_cleanup); ++ ++int nf_ct_proto_icmpv6_sysctl_init(void) ++{ ++ struct nf_conntrack_l4proto *icmp6; ++ ++ if (ve_is_super(get_exec_env())) { ++ icmp6 = &nf_conntrack_l4proto_icmpv6; ++ goto out; ++ } ++ ++ icmp6 = kmemdup(&nf_conntrack_l4proto_icmpv6, ++ sizeof(struct nf_conntrack_l4proto), GFP_KERNEL); ++ if (!icmp6) ++ goto no_mem_ct; ++ ++ icmp6->ctl_table_header = &ve_icmpv6_sysctl_header; ++ icmp6->ctl_table = clone_sysctl_template(icmpv6_sysctl_table); ++ if (!icmp6->ctl_table) ++ goto no_mem_sys; ++ ++ icmp6->ctl_table[0].data = &ve_nf_ct_icmpv6_timeout; ++out: ++ ve_nf_ct_icmpv6_timeout = nf_ct_icmpv6_timeout; ++ ++ ve_nf_conntrack_l4proto_icmpv6 = icmp6; ++ return 0; ++ ++no_mem_sys: ++ kfree(icmp6); ++no_mem_ct: ++ return -ENOMEM; ++} ++EXPORT_SYMBOL(nf_ct_proto_icmpv6_sysctl_init); ++#endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ +Index: kernel/net/ipv6/netfilter/nf_conntrack_reasm.c +=================================================================== +--- kernel.orig/net/ipv6/netfilter/nf_conntrack_reasm.c 2008-11-24 14:17:53.000000000 +0100 ++++ kernel/net/ipv6/netfilter/nf_conntrack_reasm.c 2008-11-24 15:54:54.000000000 +0100 +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + + #define NF_CT_FRAG6_HIGH_THRESH 262144 /* == 256*1024 */ + #define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */ +@@ -76,9 +77,16 @@ + .timeout = IPV6_FRAG_TIMEOUT, + .secret_interval = 10 * 60 * HZ, + }; +- + static struct inet_frags nf_frags; + ++#ifdef CONFIG_VE_IPTABLES ++#define ve_nf_frags (get_exec_env()->_nf_conntrack->_nf_frags6) ++#define ve_nf_frags_ctl (get_exec_env()->_nf_conntrack->_nf_frags6_ctl) ++#else ++#define ve_nf_frags nf_frags ++#define ve_nf_frags_ctl nf_frags_ctl ++#endif ++ + static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr, + struct in6_addr *daddr) + { +@@ -90,7 +98,7 @@ + + a += JHASH_GOLDEN_RATIO; + b += JHASH_GOLDEN_RATIO; +- c += nf_frags.rnd; ++ c += ve_nf_frags.rnd; + __jhash_mix(a, b, c); + + a += (__force u32)saddr->s6_addr32[3]; +@@ -125,7 +133,7 @@ + { + if (work) + *work -= skb->truesize; +- atomic_sub(skb->truesize, &nf_frags.mem); ++ atomic_sub(skb->truesize, &ve_nf_frags.mem); + nf_skb_free(skb); + kfree_skb(skb); + } +@@ -134,7 +142,7 @@ + + static __inline__ void fq_put(struct nf_ct_frag6_queue *fq) + { +- inet_frag_put(&fq->q, &nf_frags); ++ inet_frag_put(&fq->q, &ve_nf_frags); + } + + /* Kill fq entry. It is not destroyed immediately, +@@ -142,13 +150,13 @@ + */ + static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq) + { +- inet_frag_kill(&fq->q, &nf_frags); ++ inet_frag_kill(&fq->q, &ve_nf_frags); + } + + static void nf_ct_frag6_evictor(void) + { + local_bh_disable(); +- inet_frag_evictor(&nf_frags); ++ inet_frag_evictor(&ve_nf_frags); + local_bh_enable(); + } + +@@ -185,7 +193,7 @@ + arg.dst = dst; + hash = ip6qhashfn(id, src, dst); + +- q = inet_frag_find(&nf_frags, &arg, hash); ++ q = inet_frag_find(&ve_nf_frags, &arg, hash); + if (q == NULL) + goto oom; + +@@ -354,7 +362,7 @@ + skb->dev = NULL; + fq->q.stamp = skb->tstamp; + fq->q.meat += skb->len; +- atomic_add(skb->truesize, &nf_frags.mem); ++ atomic_add(skb->truesize, &ve_nf_frags.mem); + + /* The first fragment. + * nhoffset is obtained from the first fragment, of course. +@@ -363,9 +371,9 @@ + fq->nhoffset = nhoff; + fq->q.last_in |= FIRST_IN; + } +- write_lock(&nf_frags.lock); +- list_move_tail(&fq->q.lru_list, &nf_frags.lru_list); +- write_unlock(&nf_frags.lock); ++ write_lock(&ve_nf_frags.lock); ++ list_move_tail(&fq->q.lru_list, &ve_nf_frags.lru_list); ++ write_unlock(&ve_nf_frags.lock); + return 0; + + err: +@@ -431,7 +439,7 @@ + clone->ip_summed = head->ip_summed; + + NFCT_FRAG6_CB(clone)->orig = NULL; +- atomic_add(clone->truesize, &nf_frags.mem); ++ atomic_add(clone->truesize, &ve_nf_frags.mem); + } + + /* We have to remove fragment header from datagram and to relocate +@@ -445,7 +453,7 @@ + skb_shinfo(head)->frag_list = head->next; + skb_reset_transport_header(head); + skb_push(head, head->data - skb_network_header(head)); +- atomic_sub(head->truesize, &nf_frags.mem); ++ atomic_sub(head->truesize, &ve_nf_frags.mem); + + for (fp=head->next; fp; fp = fp->next) { + head->data_len += fp->len; +@@ -455,7 +463,7 @@ + else if (head->ip_summed == CHECKSUM_COMPLETE) + head->csum = csum_add(head->csum, fp->csum); + head->truesize += fp->truesize; +- atomic_sub(fp->truesize, &nf_frags.mem); ++ atomic_sub(fp->truesize, &ve_nf_frags.mem); + } + + head->next = NULL; +@@ -605,7 +613,7 @@ + goto ret_orig; + } + +- if (atomic_read(&nf_frags.mem) > nf_frags_ctl.high_thresh) ++ if (atomic_read(&ve_nf_frags.mem) > ve_nf_frags_ctl.high_thresh) + nf_ct_frag6_evictor(); + + fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr); +@@ -676,23 +684,24 @@ + + int nf_ct_frag6_init(void) + { +- nf_frags.ctl = &nf_frags_ctl; +- nf_frags.hashfn = nf_hashfn; +- nf_frags.constructor = ip6_frag_init; +- nf_frags.destructor = NULL; +- nf_frags.skb_free = nf_skb_free; +- nf_frags.qsize = sizeof(struct nf_ct_frag6_queue); +- nf_frags.match = ip6_frag_match; +- nf_frags.frag_expire = nf_ct_frag6_expire; +- inet_frags_init(&nf_frags); ++ memcpy(&ve_nf_frags_ctl, &nf_frags_ctl, sizeof(struct inet_frags_ctl)); ++ ve_nf_frags.ctl = &ve_nf_frags_ctl; ++ ve_nf_frags.hashfn = nf_hashfn; ++ ve_nf_frags.constructor = ip6_frag_init; ++ ve_nf_frags.destructor = NULL; ++ ve_nf_frags.skb_free = nf_skb_free; ++ ve_nf_frags.qsize = sizeof(struct nf_ct_frag6_queue); ++ ve_nf_frags.match = ip6_frag_match; ++ ve_nf_frags.frag_expire = nf_ct_frag6_expire; ++ inet_frags_init(&ve_nf_frags); + + return 0; + } + + void nf_ct_frag6_cleanup(void) + { +- inet_frags_fini(&nf_frags); ++ inet_frags_fini(&ve_nf_frags); + +- nf_frags_ctl.low_thresh = 0; ++ ve_nf_frags_ctl.low_thresh = 0; + nf_ct_frag6_evictor(); + } +Index: kernel/net/ipv6/proc.c +=================================================================== +--- kernel.orig/net/ipv6/proc.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/proc.c 2008-11-24 15:47:46.000000000 +0100 +@@ -22,15 +22,21 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include + #include + #include + #include + #include + ++#ifdef CONFIG_VE ++#define proc_net_devsnmp6 (get_exec_env()->_proc_net_devsnmp6) ++#else + static struct proc_dir_entry *proc_net_devsnmp6; ++#endif + + static int sockstat6_seq_show(struct seq_file *seq, void *v) + { +@@ -171,11 +177,11 @@ + snmp6_seq_show_item(seq, (void **)idev->stats.icmpv6, snmp6_icmp6_list); + snmp6_seq_show_icmpv6msg(seq, (void **)idev->stats.icmpv6msg); + } else { +- snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipstats_list); +- snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list); +- snmp6_seq_show_icmpv6msg(seq, (void **)icmpv6msg_statistics); +- snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list); +- snmp6_seq_show_item(seq, (void **)udplite_stats_in6, snmp6_udplite6_list); ++ snmp6_seq_show_item(seq, (void **)ve_ipv6_statistics, snmp6_ipstats_list); ++ snmp6_seq_show_item(seq, (void **)ve_icmpv6_statistics, snmp6_icmp6_list); ++ snmp6_seq_show_icmpv6msg(seq, (void **)ve_icmpv6msg_statistics); ++ snmp6_seq_show_item(seq, (void **)ve_udp_stats_in6, snmp6_udp6_list); ++ snmp6_seq_show_item(seq, (void **)ve_udplite_stats_in6, snmp6_udplite6_list); + } + return 0; + } +@@ -233,12 +239,27 @@ + return -ENOENT; + if (!idev || !idev->stats.proc_dir_entry) + return -EINVAL; +- remove_proc_entry(idev->stats.proc_dir_entry->name, ++ remove_proc_glob_entry(idev->stats.proc_dir_entry->name, + proc_net_devsnmp6); + idev->stats.proc_dir_entry = NULL; + return 0; + } + ++int ve_snmp_proc_init(struct ve_struct *ve) ++{ ++ ve->_proc_net_devsnmp6 = proc_mkdir("dev_snmp6", ve->_proc_net); ++ if (!ve->_proc_net_devsnmp6) ++ return -ENOMEM; ++ return 0; ++} ++EXPORT_SYMBOL(ve_snmp_proc_init); ++ ++void ve_snmp_proc_fini(struct ve_struct *ve) ++{ ++ remove_proc_entry("dev_snmp6", ve->_proc_net); ++} ++EXPORT_SYMBOL(ve_snmp_proc_fini); ++ + int __init ipv6_misc_proc_init(void) + { + int rc = 0; +@@ -246,8 +267,7 @@ + if (!proc_net_fops_create(&init_net, "snmp6", S_IRUGO, &snmp6_seq_fops)) + goto proc_snmp6_fail; + +- proc_net_devsnmp6 = proc_mkdir("dev_snmp6", init_net.proc_net); +- if (!proc_net_devsnmp6) ++ if (ve_snmp_proc_init(get_exec_env())) + goto proc_dev_snmp6_fail; + + if (!proc_net_fops_create(&init_net, "sockstat6", S_IRUGO, &sockstat6_seq_fops)) +@@ -256,7 +276,7 @@ + return rc; + + proc_sockstat6_fail: +- proc_net_remove(&init_net, "dev_snmp6"); ++ ve_snmp_proc_fini(get_exec_env()); + proc_dev_snmp6_fail: + proc_net_remove(&init_net, "snmp6"); + proc_snmp6_fail: +@@ -267,7 +287,7 @@ + void ipv6_misc_proc_exit(void) + { + proc_net_remove(&init_net, "sockstat6"); +- proc_net_remove(&init_net, "dev_snmp6"); ++ ve_snmp_proc_fini(get_exec_env()); + proc_net_remove(&init_net, "snmp6"); + } + +Index: kernel/net/ipv6/raw.c +=================================================================== +--- kernel.orig/net/ipv6/raw.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/raw.c 2008-11-24 15:47:46.000000000 +0100 +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -102,6 +103,10 @@ + if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) + continue; + ++ if (!ve_accessible_strict(sk->owner_env, ++ get_exec_env())) ++ continue; ++ + if (!ipv6_addr_any(&np->rcv_saddr)) { + if (ipv6_addr_equal(&np->rcv_saddr, loc_addr)) + goto found; +@@ -283,7 +288,7 @@ + if (!sk->sk_bound_dev_if) + goto out; + +- dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); ++ dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, sk->sk_bound_dev_if); + if (!dev) { + err = -ENODEV; + goto out; +@@ -1200,8 +1205,13 @@ + do { + sk = sk_next(sk); + try_again: +- ; +- } while (sk && sk->sk_family != PF_INET6); ++ if (!sk) ++ break; ++ if (sk->sk_family != PF_INET6) ++ continue; ++ if (ve_accessible(sk->owner_env, get_exec_env())) ++ break; ++ } while (1); + + if (!sk && ++state->bucket < RAWV6_HTABLE_SIZE) { + sk = sk_head(&raw_v6_htable[state->bucket]); +Index: kernel/net/ipv6/reassembly.c +=================================================================== +--- kernel.orig/net/ipv6/reassembly.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/reassembly.c 2008-11-24 15:47:46.000000000 +0100 +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -80,6 +81,7 @@ + int iif; + unsigned int csum; + __u16 nhoffset; ++ struct ve_struct *owner_ve; + }; + + struct inet_frags_ctl ip6_frags_ctl __read_mostly = { +@@ -151,7 +153,8 @@ + fq = container_of(q, struct frag_queue, q); + return (fq->id == arg->id && + ipv6_addr_equal(&fq->saddr, arg->src) && +- ipv6_addr_equal(&fq->daddr, arg->dst)); ++ ipv6_addr_equal(&fq->daddr, arg->dst) && ++ fq->owner_ve == get_exec_env()); + } + EXPORT_SYMBOL(ip6_frag_match); + +@@ -203,8 +206,10 @@ + { + struct frag_queue *fq; + struct net_device *dev = NULL; ++ struct ve_struct *old_ve; + + fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q); ++ old_ve = set_exec_env(fq->owner_ve); + + spin_lock(&fq->q.lock); + +@@ -213,7 +218,7 @@ + + fq_kill(fq); + +- dev = dev_get_by_index(&init_net, fq->iif); ++ dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, fq->iif); + if (!dev) + goto out; + +@@ -238,6 +243,8 @@ + dev_put(dev); + spin_unlock(&fq->q.lock); + fq_put(fq); ++ ++ (void)set_exec_env(old_ve); + } + + static __inline__ struct frag_queue * +@@ -511,6 +518,7 @@ + clone->csum = 0; + clone->ip_summed = head->ip_summed; + atomic_add(clone->truesize, &ip6_frags.mem); ++ clone->owner_env = head->owner_env; + } + + /* We have to remove fragment header from datagram and to relocate +Index: kernel/net/ipv6/route.c +=================================================================== +--- kernel.orig/net/ipv6/route.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/route.c 2008-11-24 15:47:46.000000000 +0100 +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -49,7 +50,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -216,9 +216,10 @@ + { + struct rt6_info *rt = (struct rt6_info *)dst; + struct inet6_dev *idev = rt->rt6i_idev; ++ struct net_device *loopback_dev = dev->nd_net->loopback_dev; + +- if (dev != init_net.loopback_dev && idev != NULL && idev->dev == dev) { +- struct inet6_dev *loopback_idev = in6_dev_get(init_net.loopback_dev); ++ if (dev != loopback_dev && idev != NULL && idev->dev == dev) { ++ struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev); + if (loopback_idev != NULL) { + rt->rt6i_idev = loopback_idev; + in6_dev_put(idev); +@@ -668,8 +669,9 @@ + int strict = 0; + int attempts = 3; + int err; +- int reachable = ipv6_devconf.forwarding ? 0 : RT6_LOOKUP_F_REACHABLE; +- ++ int reachable; ++ ++ reachable = ve_ipv6_devconf.forwarding ? 0 : RT6_LOOKUP_F_REACHABLE; + strict |= flags & RT6_LOOKUP_F_IFACE; + + relookup: +@@ -1033,7 +1035,7 @@ + + int ipv6_get_hoplimit(struct net_device *dev) + { +- int hoplimit = ipv6_devconf.hop_limit; ++ int hoplimit = ve_ipv6_devconf.hop_limit; + struct inet6_dev *idev; + + idev = in6_dev_get(dev); +@@ -1050,6 +1052,7 @@ + + int ip6_route_add(struct fib6_config *cfg) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + int err; + struct rt6_info *rt = NULL; + struct net_device *dev = NULL; +@@ -1065,7 +1068,7 @@ + #endif + if (cfg->fc_ifindex) { + err = -ENODEV; +- dev = dev_get_by_index(&init_net, cfg->fc_ifindex); ++ dev = dev_get_by_index(net, cfg->fc_ifindex); + if (!dev) + goto out; + idev = in6_dev_get(dev); +@@ -1122,13 +1125,15 @@ + */ + if ((cfg->fc_flags & RTF_REJECT) || + (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { ++ struct net *net = get_exec_env()->ve_ns->net_ns; ++ + /* hold loopback dev/idev if we haven't done so. */ +- if (dev != init_net.loopback_dev) { ++ if (dev != net->loopback_dev) { + if (dev) { + dev_put(dev); + in6_dev_put(idev); + } +- dev = init_net.loopback_dev; ++ dev = net->loopback_dev; + dev_hold(dev); + idev = in6_dev_get(dev); + if (!idev) { +@@ -1827,18 +1832,19 @@ + const struct in6_addr *addr, + int anycast) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + struct rt6_info *rt = ip6_dst_alloc(); + + if (rt == NULL) + return ERR_PTR(-ENOMEM); + +- dev_hold(init_net.loopback_dev); ++ dev_hold(net->loopback_dev); + in6_dev_hold(idev); + + rt->u.dst.flags = DST_HOST; + rt->u.dst.input = ip6_input; + rt->u.dst.output = ip6_output; +- rt->rt6i_dev = init_net.loopback_dev; ++ rt->rt6i_dev = net->loopback_dev; + rt->rt6i_idev = idev; + rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); + rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); +@@ -1850,10 +1856,12 @@ + rt->rt6i_flags |= RTF_ANYCAST; + else + rt->rt6i_flags |= RTF_LOCAL; +- rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); +- if (rt->rt6i_nexthop == NULL) { +- dst_free(&rt->u.dst); +- return ERR_PTR(-ENOMEM); ++ rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, rt->rt6i_dev); ++ if (IS_ERR(rt->rt6i_nexthop)) { ++ void *err = rt->rt6i_nexthop; ++ rt->rt6i_nexthop = NULL; ++ dst_free((struct dst_entry *) rt); ++ return err; + } + + ipv6_addr_copy(&rt->rt6i_dst.addr, addr); +@@ -2129,8 +2137,12 @@ + if (rt->u.dst.neighbour) + NLA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key); + +- if (rt->u.dst.dev) +- NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); ++ if (rt->u.dst.dev) { ++ struct net_device *odev = rt->rt6i_dev; ++ if (rt == &ip6_null_entry) ++ odev = get_exec_env()->ve_ns->net_ns->loopback_dev; ++ NLA_PUT_U32(skb, RTA_OIF, odev->ifindex); ++ } + + NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric); + +@@ -2164,6 +2176,7 @@ + + static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + struct nlattr *tb[RTA_MAX+1]; + struct rt6_info *rt; + struct sk_buff *skb; +@@ -2200,7 +2213,7 @@ + + if (iif) { + struct net_device *dev; +- dev = __dev_get_by_index(&init_net, iif); ++ dev = __dev_get_by_index(net, iif); + if (!dev) { + err = -ENODEV; + goto errout; +@@ -2501,3 +2514,54 @@ + fib6_gc_cleanup(); + kmem_cache_destroy(ip6_dst_ops.kmem_cachep); + } ++ ++#ifdef CONFIG_VE ++int init_ve_route6(struct ve_struct *ve) ++{ ++ struct ve_struct *old_env = set_exec_env(ve); ++ ve->_fib6_table = kzalloc(sizeof(struct fib6_table), GFP_KERNEL_UBC); ++ if (!ve->_fib6_table) { ++ set_exec_env(old_env); ++ return -ENOMEM; ++ } ++ ve->_fib6_table->owner_env = ve; ++ ve->_fib6_table->tb6_id = RT6_TABLE_MAIN; ++ ve->_fib6_table->tb6_root.leaf = &ip6_null_entry; ++ ve->_fib6_table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | ++ RTN_RTINFO; ++#ifdef CONFIG_IPV6_MULTIPLE_TABLES ++ ve->_fib6_local_table = kzalloc(sizeof(struct fib6_table), ++ GFP_KERNEL_UBC); ++ if (!ve->_fib6_local_table) { ++ kfree(ve->_fib6_table); ++ set_exec_env(old_env); ++ return -ENOMEM; ++ } ++ ve->_fib6_local_table->owner_env = ve; ++ ve->_fib6_local_table->tb6_id = RT6_TABLE_LOCAL; ++ ve->_fib6_local_table->tb6_root.leaf = &ip6_null_entry; ++ ve->_fib6_local_table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | ++ RTN_RTINFO; ++#endif ++ fib6_tables_init(); ++ set_exec_env(old_env); ++ return 0; ++} ++EXPORT_SYMBOL(init_ve_route6); ++ ++void fini_ve_route6(struct ve_struct *ve) ++{ ++ struct ve_struct *old_env = set_exec_env(ve); ++ ++ if (ve->_fib6_table) { ++ rt6_ifdown(NULL); ++ fib6_tables_cleanup(); ++ kfree(ve->_fib6_table); ++#ifdef CONFIG_IPV6_MULTIPLE_TABLES ++ kfree(ve->_fib6_local_table); ++#endif ++ } ++ set_exec_env(old_env); ++} ++EXPORT_SYMBOL(fini_ve_route6); ++#endif +Index: kernel/net/ipv6/sit.c +=================================================================== +--- kernel.orig/net/ipv6/sit.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/sit.c 2008-11-24 15:47:46.000000000 +0100 +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -52,6 +53,8 @@ + #include + #include + ++#include ++ + /* + This version of net/ipv6/sit.c is cloned of net/ipv4/ip_gre.c + +@@ -65,6 +68,26 @@ + static int ipip6_tunnel_init(struct net_device *dev); + static void ipip6_tunnel_setup(struct net_device *dev); + ++#ifdef CONFIG_VE ++struct ve_sit_tunnels { ++ struct net_device *_ipip6_fb_tunnel_dev; ++ struct ip_tunnel *_tunnels_r_l[HASH_SIZE]; ++ struct ip_tunnel *_tunnels_r[HASH_SIZE]; ++ struct ip_tunnel *_tunnels_l[HASH_SIZE]; ++ struct ip_tunnel *_tunnels_wc[1]; ++ struct ip_tunnel **_tunnels[4]; ++ rwlock_t _ipip6_lock; ++}; ++ ++#define ipip6_fb_tunnel_dev \ ++ (get_exec_env()->_sit_tunnels->_ipip6_fb_tunnel_dev) ++#define tunnels_r_l (get_exec_env()->_sit_tunnels->_tunnels_r_l) ++#define tunnels_r (get_exec_env()->_sit_tunnels->_tunnels_r) ++#define tunnels_l (get_exec_env()->_sit_tunnels->_tunnels_l) ++#define tunnels_wc (get_exec_env()->_sit_tunnels->_tunnels_wc) ++#define tunnels (get_exec_env()->_sit_tunnels->_tunnels) ++#define ipip6_lock (get_exec_env()->_sit_tunnels->_ipip6_lock) ++#else + static struct net_device *ipip6_fb_tunnel_dev; + + static struct ip_tunnel *tunnels_r_l[HASH_SIZE]; +@@ -74,6 +97,7 @@ + static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l }; + + static DEFINE_RWLOCK(ipip6_lock); ++#endif + + static struct ip_tunnel * ipip6_tunnel_lookup(__be32 remote, __be32 local) + { +@@ -167,7 +191,7 @@ + int i; + for (i=1; i<100; i++) { + sprintf(name, "sit%d", i); +- if (__dev_get_by_name(&init_net, name) == NULL) ++ if (__dev_get_by_name(get_exec_env()->ve_ns->net_ns, name) == NULL) + break; + } + if (i==100) +@@ -619,9 +643,12 @@ + case SIOCADDTUNNEL: + case SIOCCHGTUNNEL: + err = -EPERM; +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_NET_ADMIN) ++#ifdef CONFIG_VE ++ && !capable(CAP_VE_NET_ADMIN) ++#endif ++ ) + goto done; +- + err = -EFAULT; + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) + goto done; +@@ -672,7 +699,11 @@ + + case SIOCDELTUNNEL: + err = -EPERM; +- if (!capable(CAP_NET_ADMIN)) ++ if (!capable(CAP_NET_ADMIN) ++#ifdef CONFIG_VE ++ && !capable(CAP_VE_NET_ADMIN) ++#endif ++ ) + goto done; + + if (dev == ipip6_fb_tunnel_dev) { +@@ -727,6 +758,9 @@ + dev->flags = IFF_NOARP; + dev->iflink = 0; + dev->addr_len = 4; ++#ifdef CONFIG_VE ++ dev->features |= NETIF_F_VIRTUAL; ++#endif + } + + static int ipip6_tunnel_init(struct net_device *dev) +@@ -760,7 +794,7 @@ + } + + if (!tdev && tunnel->parms.link) +- tdev = __dev_get_by_index(&init_net, tunnel->parms.link); ++ tdev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, tunnel->parms.link); + + if (tdev) { + dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); +@@ -773,7 +807,7 @@ + return 0; + } + +-static int __init ipip6_fb_tunnel_init(struct net_device *dev) ++static int ipip6_fb_tunnel_init(struct net_device *dev) + { + struct ip_tunnel *tunnel = netdev_priv(dev); + struct iphdr *iph = &tunnel->parms.iph; +@@ -797,7 +831,7 @@ + .priority = 1, + }; + +-static void __exit sit_destroy_tunnels(void) ++static void sit_destroy_tunnels(void) + { + int prio; + +@@ -811,14 +845,92 @@ + } + } + ++#ifdef CONFIG_VE ++static int sit_ve_start(void *data) ++{ ++ struct ve_struct *ve = data; ++ struct ve_sit_tunnels *st; ++ int err; ++ ++ if (!ve_is_super(ve)) ++ __module_get(THIS_MODULE); ++ ++ st = kzalloc(sizeof(struct ve_sit_tunnels), GFP_KERNEL_UBC); ++ if (!st) { ++ err = -ENOMEM; ++ goto out; ++ } ++ st->_tunnels[0] = st->_tunnels_wc; ++ st->_tunnels[1] = st->_tunnels_l; ++ st->_tunnels[2] = st->_tunnels_r; ++ st->_tunnels[3] = st->_tunnels_r_l; ++ rwlock_init(&st->_ipip6_lock); ++ ++ ve->_sit_tunnels = st; ++ if (ve_is_super(ve)) ++ goto out_ok; ++ ++ st->_ipip6_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), ++ "sit0", ipip6_tunnel_setup); ++ if (!st->_ipip6_fb_tunnel_dev) { ++ err = -ENOMEM; ++ goto free_tunnel; ++ } ++ st->_ipip6_fb_tunnel_dev->init = ipip6_fb_tunnel_init; ++ err = register_netdev(st->_ipip6_fb_tunnel_dev); ++ if (err < 0) ++ goto free_netdev; ++out_ok: ++ return 0; ++ ++free_netdev: ++ free_netdev(st->_ipip6_fb_tunnel_dev); ++free_tunnel: ++ kfree(st); ++ if (!ve_is_super(ve)) ++ module_put(THIS_MODULE); ++out: ++ return err; ++} ++ ++static void sit_ve_stop(void *data) ++{ ++ struct ve_struct *ve = data; ++ ++ if (ve->_sit_tunnels == NULL) ++ return; ++ if (!ve_is_super(ve)) { ++ rtnl_lock(); ++ sit_destroy_tunnels(); ++ unregister_netdevice(ipip6_fb_tunnel_dev); ++ rtnl_unlock(); ++ } ++ kfree(ve->_sit_tunnels); ++ ve->_sit_tunnels = NULL; ++ if (!ve_is_super(ve)) ++ module_put(THIS_MODULE); ++} ++ ++static struct ve_hook sit_ve_hook = { ++ .init = sit_ve_start, ++ .fini = sit_ve_stop, ++ .owner = THIS_MODULE, ++ .priority = HOOK_PRIO_NET_POST, ++}; ++#endif ++ + static void __exit sit_cleanup(void) + { ++ ve_hook_unregister(&sit_ve_hook); + xfrm4_tunnel_deregister(&sit_handler, AF_INET6); + + rtnl_lock(); + sit_destroy_tunnels(); + unregister_netdevice(ipip6_fb_tunnel_dev); + rtnl_unlock(); ++#ifdef CONFIG_VE ++ sit_ve_stop(get_exec_env()); ++#endif + } + + static int __init sit_init(void) +@@ -832,23 +944,35 @@ + return -EAGAIN; + } + ++#ifdef CONFIG_VE ++ err = sit_ve_start(get_exec_env()); ++ if (err) ++ goto err1; ++#endif ++ + ipip6_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0", + ipip6_tunnel_setup); + if (!ipip6_fb_tunnel_dev) { + err = -ENOMEM; +- goto err1; ++ goto err2; + } + + ipip6_fb_tunnel_dev->init = ipip6_fb_tunnel_init; + + if ((err = register_netdev(ipip6_fb_tunnel_dev))) +- goto err2; ++ goto err3; ++ ++ ve_hook_register(VE_SS_CHAIN, &sit_ve_hook); + + out: + return err; +- err2: ++ err3: + free_netdev(ipip6_fb_tunnel_dev); +- err1: ++ err2: ++#ifdef CONFIG_VE ++ sit_ve_stop(get_exec_env()); ++err1: ++#endif + xfrm4_tunnel_deregister(&sit_handler, AF_INET6); + goto out; + } +Index: kernel/net/ipv6/tcp_ipv6.c +=================================================================== +--- kernel.orig/net/ipv6/tcp_ipv6.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/tcp_ipv6.c 2008-11-24 15:47:46.000000000 +0100 +@@ -61,6 +61,8 @@ + #include + #include + ++#include ++ + #include + + #include +@@ -79,7 +81,7 @@ + + static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); + +-static struct inet_connection_sock_af_ops ipv6_mapped; ++struct inet_connection_sock_af_ops ipv6_mapped; + static struct inet_connection_sock_af_ops ipv6_specific; + #ifdef CONFIG_TCP_MD5SIG + static struct tcp_sock_af_ops tcp_sock_ipv6_specific; +@@ -1552,6 +1554,7 @@ + struct ipv6_pinfo *np = inet6_sk(sk); + struct tcp_sock *tp; + struct sk_buff *opt_skb = NULL; ++ struct user_beancounter *ub; + + /* Imagine: socket is IPv6. IPv4 packet arrives, + goes to IPv4 receive handler and backlogged. +@@ -1564,6 +1567,8 @@ + if (skb->protocol == htons(ETH_P_IP)) + return tcp_v4_do_rcv(sk, skb); + ++ ub = set_exec_ub(sock_bc(sk)->ub); ++ + #ifdef CONFIG_TCP_MD5SIG + if (tcp_v6_inbound_md5_hash (sk, skb)) + goto discard; +@@ -1600,7 +1605,7 @@ + TCP_CHECK_TIMER(sk); + if (opt_skb) + goto ipv6_pktoptions; +- return 0; ++ goto restore_context; + } + + if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb)) +@@ -1621,7 +1626,7 @@ + goto reset; + if (opt_skb) + __kfree_skb(opt_skb); +- return 0; ++ goto restore_context; + } + } + +@@ -1631,6 +1636,9 @@ + TCP_CHECK_TIMER(sk); + if (opt_skb) + goto ipv6_pktoptions; ++ ++restore_context: ++ (void)set_exec_ub(ub); + return 0; + + reset: +@@ -1639,7 +1647,7 @@ + if (opt_skb) + __kfree_skb(opt_skb); + kfree_skb(skb); +- return 0; ++ goto restore_context; + csum_err: + TCP_INC_STATS_BH(TCP_MIB_INERRS); + goto discard; +@@ -1671,7 +1679,7 @@ + + if (opt_skb) + kfree_skb(opt_skb); +- return 0; ++ goto restore_context; + } + + static int tcp_v6_rcv(struct sk_buff *skb) +@@ -1851,7 +1859,7 @@ + * TCP over IPv4 via INET6 API + */ + +-static struct inet_connection_sock_af_ops ipv6_mapped = { ++struct inet_connection_sock_af_ops ipv6_mapped = { + .queue_xmit = ip_queue_xmit, + .send_check = tcp_v4_send_check, + .rebuild_header = inet_sk_rebuild_header, +@@ -1869,6 +1877,8 @@ + #endif + }; + ++EXPORT_SYMBOL_GPL(ipv6_mapped); ++ + #ifdef CONFIG_TCP_MD5SIG + static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { + .md5_lookup = tcp_v4_md5_lookup, +Index: kernel/net/ipv6/udp.c +=================================================================== +--- kernel.orig/net/ipv6/udp.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/udp.c 2008-11-24 15:47:46.000000000 +0100 +@@ -65,12 +65,15 @@ + struct hlist_node *node; + unsigned short hnum = ntohs(dport); + int badness = -1; ++ struct ve_struct *ve; + ++ ve = get_exec_env(); + read_lock(&udp_hash_lock); +- sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { ++ sk_for_each(sk, node, &udptable[udp_hashfn(hnum, VEID(ve))]) { + struct inet_sock *inet = inet_sk(sk); + +- if (sk->sk_hash == hnum && sk->sk_family == PF_INET6) { ++ if (inet->num == hnum && sk->sk_family == PF_INET6 && ++ ve_accessible_strict(sk->owner_env, ve)) { + struct ipv6_pinfo *np = inet6_sk(sk); + int score = 0; + if (inet->dport) { +@@ -349,7 +352,7 @@ + int dif; + + read_lock(&udp_hash_lock); +- sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); ++ sk = sk_head(&udptable[udp_hashfn(ntohs(uh->dest), VEID(skb->owner_env))]); + dif = inet6_iif(skb); + sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); + if (!sk) { +Index: kernel/net/ipv6/xfrm6_policy.c +=================================================================== +--- kernel.orig/net/ipv6/xfrm6_policy.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/ipv6/xfrm6_policy.c 2008-11-24 15:47:46.000000000 +0100 +@@ -362,7 +362,8 @@ + + xdst = (struct xfrm_dst *)dst; + if (xdst->u.rt6.rt6i_idev->dev == dev) { +- struct inet6_dev *loopback_idev = in6_dev_get(init_net.loopback_dev); ++ struct inet6_dev *loopback_idev = ++ in6_dev_get(dev->nd_net->loopback_dev); + BUG_ON(!loopback_idev); + + do { +Index: kernel/net/netfilter/core.c +=================================================================== +--- kernel.orig/net/netfilter/core.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/core.c 2008-11-24 15:47:46.000000000 +0100 +@@ -59,16 +59,34 @@ + struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS] __read_mostly; + EXPORT_SYMBOL(nf_hooks); + static DEFINE_MUTEX(nf_hook_mutex); ++#ifdef CONFIG_VE_IPTABLES ++#define VE_NF_HOOKS(env, x, y) \ ++ ((struct list_head (*)[NF_MAX_HOOKS])(env->_nf_hooks))[x][y] ++#else ++#define VE_NF_HOOKS(env, x, y) nf_hooks[x][y] ++#endif + + int nf_register_hook(struct nf_hook_ops *reg) + { + struct list_head *i; ++ struct ve_struct *env; + int err; + ++ env = get_exec_env(); ++ if (!ve_is_super(env)) { ++ struct nf_hook_ops *tmp; ++ tmp = kmemdup(reg, sizeof(struct nf_hook_ops), GFP_KERNEL); ++ if (!tmp) ++ return -ENOMEM; ++ reg = tmp; ++ } ++ + err = mutex_lock_interruptible(&nf_hook_mutex); +- if (err < 0) ++ if (err < 0) { ++ kfree(reg); + return err; +- list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) { ++ } ++ list_for_each(i, &VE_NF_HOOKS(env, reg->pf, reg->hooknum)) { + if (reg->priority < ((struct nf_hook_ops *)i)->priority) + break; + } +@@ -80,11 +98,29 @@ + + void nf_unregister_hook(struct nf_hook_ops *reg) + { ++ struct nf_hook_ops *i; ++ struct ve_struct *env; ++ ++ env = get_exec_env(); ++ if (!ve_is_super(env)) { ++ list_for_each_entry_rcu(i, ++ &VE_NF_HOOKS(env, reg->pf, reg->hooknum), list) { ++ if (reg->hook == i->hook) { ++ reg = i; ++ break; ++ } ++ } ++ if (reg != i) ++ return; ++ } ++ + mutex_lock(&nf_hook_mutex); + list_del_rcu(®->list); + mutex_unlock(&nf_hook_mutex); + + synchronize_net(); ++ if (!ve_is_super(env)) ++ kfree(reg); + } + EXPORT_SYMBOL(nf_unregister_hook); + +@@ -169,13 +205,15 @@ + struct list_head *elem; + unsigned int verdict; + int ret = 0; ++ struct ve_struct *ve; + + /* We may already have this, but read-locks nest anyway */ + rcu_read_lock(); + +- elem = &nf_hooks[pf][hook]; ++ ve = get_exec_env(); ++ elem = &VE_NF_HOOKS(ve, pf, hook); + next_hook: +- verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev, ++ verdict = nf_iterate(&VE_NF_HOOKS(ve, pf, hook), skb, hook, indev, + outdev, &elem, okfn, hook_thresh); + if (verdict == NF_ACCEPT || verdict == NF_STOP) { + ret = 1; +@@ -275,13 +313,54 @@ + EXPORT_SYMBOL(proc_net_netfilter); + #endif + +-void __init netfilter_init(void) ++void init_nf_hooks(struct list_head (*nh)[NF_MAX_HOOKS]) + { + int i, h; + for (i = 0; i < NPROTO; i++) { + for (h = 0; h < NF_MAX_HOOKS; h++) +- INIT_LIST_HEAD(&nf_hooks[i][h]); ++ INIT_LIST_HEAD(&nh[i][h]); + } ++} ++ ++int init_netfilter(void) ++{ ++#ifdef CONFIG_VE_IPTABLES ++ struct ve_struct *envid; ++ ++ envid = get_exec_env(); ++ envid->_nf_hooks = kmalloc(sizeof(nf_hooks), GFP_KERNEL); ++ if (envid->_nf_hooks == NULL) ++ return -ENOMEM; ++ ++ /* FIXME: charge ubc */ ++ ++ init_nf_hooks(envid->_nf_hooks); ++ return 0; ++#else ++ init_nf_hooks(nf_hooks); ++ return 0; ++#endif ++} ++EXPORT_SYMBOL(init_netfilter); ++ ++#ifdef CONFIG_VE_IPTABLES ++void fini_netfilter(void) ++{ ++ struct ve_struct *envid; ++ ++ envid = get_exec_env(); ++ if (envid->_nf_hooks != NULL) ++ kfree(envid->_nf_hooks); ++ envid->_nf_hooks = NULL; ++ ++ /* FIXME: uncharge ubc */ ++} ++EXPORT_SYMBOL(fini_netfilter); ++#endif ++ ++void __init netfilter_init(void) ++{ ++ init_netfilter(); + + #ifdef CONFIG_PROC_FS + proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net); +Index: kernel/net/netfilter/nf_conntrack_core.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_core.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_core.c 2008-11-24 15:47:46.000000000 +0100 +@@ -38,6 +38,9 @@ + #include + #include + ++#include ++#include ++ + #define NF_CONNTRACK_VERSION "0.5.0" + + DEFINE_RWLOCK(nf_conntrack_lock); +@@ -177,7 +180,14 @@ + destroy_conntrack(struct nf_conntrack *nfct) + { + struct nf_conn *ct = (struct nf_conn *)nfct; ++ struct nf_conn_help *help = nfct_help(ct); ++ struct nf_conntrack_l3proto *l3proto; + struct nf_conntrack_l4proto *l4proto; ++#ifdef CONFIG_VE_IPTABLES ++ struct ve_struct *old_ve; ++ ++ old_ve = set_exec_env(ct->ct_owner_env); ++#endif + + pr_debug("destroy_conntrack(%p)\n", ct); + NF_CT_ASSERT(atomic_read(&nfct->use) == 0); +@@ -186,10 +196,17 @@ + nf_conntrack_event(IPCT_DESTROY, ct); + set_bit(IPS_DYING_BIT, &ct->status); + ++ if (help && help->helper && help->helper->destroy) ++ help->helper->destroy(ct); ++ + /* To make sure we don't get any weird locking issues here: + * destroy_conntrack() MUST NOT be called with a write lock + * to nf_conntrack_lock!!! -HW */ + rcu_read_lock(); ++ l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num); ++ if (l3proto && l3proto->destroy) ++ l3proto->destroy(ct); ++ + l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num, + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); + if (l4proto && l4proto->destroy) +@@ -220,6 +237,9 @@ + + pr_debug("destroy_conntrack: returning ct=%p to slab\n", ct); + nf_conntrack_free(ct); ++#ifdef CONFIG_VE_IPTABLES ++ (void)set_exec_env(old); ++#endif + } + + static void death_by_timeout(unsigned long ul_conntrack) +@@ -253,7 +273,7 @@ + struct hlist_node *n; + unsigned int hash = hash_conntrack(tuple); + +- hlist_for_each_entry(h, n, &nf_conntrack_hash[hash], hnode) { ++ hlist_for_each_entry(h, n, &ve_nf_conntrack_hash[hash], hnode) { + if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack && + nf_ct_tuple_equal(tuple, &h->tuple)) { + NF_CT_STAT_INC(found); +@@ -287,9 +307,9 @@ + unsigned int repl_hash) + { + hlist_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode, +- &nf_conntrack_hash[hash]); ++ &ve_nf_conntrack_hash[hash]); + hlist_add_head(&ct->tuplehash[IP_CT_DIR_REPLY].hnode, +- &nf_conntrack_hash[repl_hash]); ++ &ve_nf_conntrack_hash[repl_hash]); + } + + void nf_conntrack_hash_insert(struct nf_conn *ct) +@@ -343,11 +363,11 @@ + /* See if there's one in the list already, including reverse: + NAT could have grabbed it without realizing, since we're + not in the hash. If there is, we lost race. */ +- hlist_for_each_entry(h, n, &nf_conntrack_hash[hash], hnode) ++ hlist_for_each_entry(h, n, &ve_nf_conntrack_hash[hash], hnode) + if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, + &h->tuple)) + goto out; +- hlist_for_each_entry(h, n, &nf_conntrack_hash[repl_hash], hnode) ++ hlist_for_each_entry(h, n, &ve_nf_conntrack_hash[repl_hash], hnode) + if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, + &h->tuple)) + goto out; +@@ -415,7 +435,7 @@ + + read_lock_bh(&nf_conntrack_lock); + for (i = 0; i < nf_conntrack_htable_size; i++) { +- hlist_for_each_entry(h, n, &nf_conntrack_hash[hash], hnode) { ++ hlist_for_each_entry(h, n, &ve_nf_conntrack_hash[hash], hnode) { + tmp = nf_ct_tuplehash_to_ctrack(h); + if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) + ct = tmp; +@@ -442,9 +462,11 @@ + } + + struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, +- const struct nf_conntrack_tuple *repl) ++ const struct nf_conntrack_tuple *repl, ++ struct user_beancounter *ub) + { + struct nf_conn *conntrack = NULL; ++ struct user_beancounter *old_ub; + + if (unlikely(!nf_conntrack_hash_rnd_initted)) { + get_random_bytes(&nf_conntrack_hash_rnd, 4); +@@ -452,25 +474,27 @@ + } + + /* We don't want any race condition at early drop stage */ +- atomic_inc(&nf_conntrack_count); ++ atomic_inc(&ve_nf_conntrack_count); + +- if (nf_conntrack_max +- && atomic_read(&nf_conntrack_count) > nf_conntrack_max) { ++ if (ve_nf_conntrack_max ++ && atomic_read(&ve_nf_conntrack_count) > ve_nf_conntrack_max) { + unsigned int hash = hash_conntrack(orig); + if (!early_drop(hash)) { +- atomic_dec(&nf_conntrack_count); ++ atomic_dec(&ve_nf_conntrack_count); + if (net_ratelimit()) +- printk(KERN_WARNING +- "nf_conntrack: table full, dropping" +- " packet.\n"); ++ ve_printk(VE_LOG_BOTH, KERN_WARNING ++ "nf_conntrack: CT %d: table full, dropping" ++ " packet.\n", VEID(get_exec_env())); + return ERR_PTR(-ENOMEM); + } + } + ++ old_ub = set_exec_ub(ub); + conntrack = kmem_cache_zalloc(nf_conntrack_cachep, GFP_ATOMIC); ++ (void)set_exec_ub(old_ub); + if (conntrack == NULL) { + pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n"); +- atomic_dec(&nf_conntrack_count); ++ atomic_dec(&ve_nf_conntrack_count); + return ERR_PTR(-ENOMEM); + } + +@@ -480,6 +504,9 @@ + /* Don't set timer yet: wait for confirmation */ + setup_timer(&conntrack->timeout, death_by_timeout, + (unsigned long)conntrack); ++#ifdef CONFIG_VE_IPTABLES ++ conntrack->ct_owner_env = get_exec_env(); ++#endif + + return conntrack; + } +@@ -489,7 +516,7 @@ + { + nf_ct_ext_free(conntrack); + kmem_cache_free(nf_conntrack_cachep, conntrack); +- atomic_dec(&nf_conntrack_count); ++ atomic_dec(&ve_nf_conntrack_count); + } + EXPORT_SYMBOL_GPL(nf_conntrack_free); + +@@ -506,13 +533,20 @@ + struct nf_conn_help *help; + struct nf_conntrack_tuple repl_tuple; + struct nf_conntrack_expect *exp; ++ struct user_beancounter *ub = NULL; + + if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) { + pr_debug("Can't invert tuple.\n"); + return NULL; + } + +- conntrack = nf_conntrack_alloc(tuple, &repl_tuple); ++#ifdef CONFIG_BEANCOUNTERS ++ if (skb->dev != NULL) /* received skb */ ++ ub = netdev_bc(skb->dev)->exec_ub; ++ else if (skb->sk != NULL) /* sent skb */ ++ ub = sock_bc(skb->sk)->ub; ++#endif ++ conntrack = nf_conntrack_alloc(tuple, &repl_tuple, ub); + if (conntrack == NULL || IS_ERR(conntrack)) { + pr_debug("Can't allocate conntrack.\n"); + return (struct nf_conntrack_tuple_hash *)conntrack; +@@ -560,7 +594,7 @@ + + /* Overload tuple linked list to put us in unconfirmed list. */ + hlist_add_head(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].hnode, +- &unconfirmed); ++ &ve_unconfirmed); + + write_unlock_bh(&nf_conntrack_lock); + +@@ -901,13 +935,13 @@ + + write_lock_bh(&nf_conntrack_lock); + for (; *bucket < nf_conntrack_htable_size; (*bucket)++) { +- hlist_for_each_entry(h, n, &nf_conntrack_hash[*bucket], hnode) { ++ hlist_for_each_entry(h, n, &ve_nf_conntrack_hash[*bucket], hnode) { + ct = nf_ct_tuplehash_to_ctrack(h); + if (iter(ct, data)) + goto found; + } + } +- hlist_for_each_entry(h, n, &unconfirmed, hnode) { ++ hlist_for_each_entry(h, n, &ve_unconfirmed, hnode) { + ct = nf_ct_tuplehash_to_ctrack(h); + if (iter(ct, data)) + set_bit(IPS_DYING_BIT, &ct->status); +@@ -962,7 +996,13 @@ + supposed to kill the mall. */ + void nf_conntrack_cleanup(void) + { +- rcu_assign_pointer(ip_ct_attach, NULL); ++ struct ve_struct *ve = get_exec_env(); ++ ++#ifdef CONFIG_VE_IPTABLES ++ BUG_ON(!ve->_nf_conntrack); ++#endif ++ if (ve_is_super(ve)) ++ rcu_assign_pointer(ip_ct_attach, NULL); + + /* This makes sure all current packets have passed through + netfilter framework. Roll on, two-stage module +@@ -972,10 +1012,12 @@ + nf_ct_event_cache_flush(); + i_see_dead_people: + nf_conntrack_flush(); +- if (atomic_read(&nf_conntrack_count) != 0) { ++ if (atomic_read(&ve_nf_conntrack_count) != 0) { + schedule(); + goto i_see_dead_people; + } ++ if (!ve_is_super(ve)) ++ goto skip_ct_cache; + /* wait until all references to nf_conntrack_untracked are dropped */ + while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1) + schedule(); +@@ -983,12 +1025,25 @@ + rcu_assign_pointer(nf_ct_destroy, NULL); + + kmem_cache_destroy(nf_conntrack_cachep); +- nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_vmalloc, +- nf_conntrack_htable_size); +- +- nf_conntrack_proto_fini(); ++skip_ct_cache: + nf_conntrack_helper_fini(); + nf_conntrack_expect_fini(); ++ ++ nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_generic); ++ nf_ct_proto_generic_sysctl_cleanup(); ++ nf_ct_free_hashtable(ve_nf_conntrack_hash, ve_nf_conntrack_vmalloc, ++ nf_conntrack_htable_size); ++ ve_nf_conntrack_hash = NULL; ++ INIT_HLIST_HEAD(&ve_unconfirmed); ++ ve_nf_ct_expect_hash = NULL; ++ atomic_set(&ve_nf_conntrack_count, 0); ++ ve_nf_conntrack_max = 0; ++// nf_conntrack_proto_fini(); ++#ifdef CONFIG_VE_IPTABLES ++ ve_nf_conntrack_l4proto_generic = NULL; ++ kfree(ve->_nf_conntrack); ++ ve->_nf_conntrack = NULL; ++#endif + } + + struct hlist_head *nf_ct_alloc_hashtable(int *sizep, int *vmalloced) +@@ -999,13 +1054,13 @@ + *vmalloced = 0; + + size = *sizep = roundup(*sizep, PAGE_SIZE / sizeof(struct hlist_head)); +- hash = (void*)__get_free_pages(GFP_KERNEL|__GFP_NOWARN, ++ hash = (void*)__get_free_pages(GFP_KERNEL_UBC|__GFP_NOWARN, + get_order(sizeof(struct hlist_head) + * size)); + if (!hash) { + *vmalloced = 1; + printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n"); +- hash = vmalloc(sizeof(struct hlist_head) * size); ++ hash = ub_vmalloc(sizeof(struct hlist_head) * size); + } + + if (hash) +@@ -1042,8 +1097,8 @@ + + write_lock_bh(&nf_conntrack_lock); + for (i = 0; i < nf_conntrack_htable_size; i++) { +- while (!hlist_empty(&nf_conntrack_hash[i])) { +- h = hlist_entry(nf_conntrack_hash[i].first, ++ while (!hlist_empty(&ve_nf_conntrack_hash[i])) { ++ h = hlist_entry(ve_nf_conntrack_hash[i].first, + struct nf_conntrack_tuple_hash, hnode); + hlist_del(&h->hnode); + bucket = __hash_conntrack(&h->tuple, hashsize, rnd); +@@ -1051,12 +1106,12 @@ + } + } + old_size = nf_conntrack_htable_size; +- old_vmalloced = nf_conntrack_vmalloc; +- old_hash = nf_conntrack_hash; ++ old_vmalloced = ve_nf_conntrack_vmalloc; ++ old_hash = ve_nf_conntrack_hash; + + nf_conntrack_htable_size = hashsize; +- nf_conntrack_vmalloc = vmalloced; +- nf_conntrack_hash = hash; ++ ve_nf_conntrack_vmalloc = vmalloced; ++ ve_nf_conntrack_hash = hash; + nf_conntrack_hash_rnd = rnd; + write_unlock_bh(&nf_conntrack_lock); + +@@ -1068,52 +1123,81 @@ + module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, + &nf_conntrack_htable_size, 0600); + +-int __init nf_conntrack_init(void) ++int nf_conntrack_init(void) + { ++ struct ve_struct *ve = get_exec_env(); + int max_factor = 8; +- int ret; ++ int ret = 0, i; + +- /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB +- * machine has 512 buckets. >= 1GB machines have 16384 buckets. */ +- if (!nf_conntrack_htable_size) { +- nf_conntrack_htable_size +- = (((num_physpages << PAGE_SHIFT) / 16384) +- / sizeof(struct hlist_head)); +- if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) +- nf_conntrack_htable_size = 16384; +- if (nf_conntrack_htable_size < 32) +- nf_conntrack_htable_size = 32; +- +- /* Use a max. factor of four by default to get the same max as +- * with the old struct list_heads. When a table size is given +- * we use the old value of 8 to avoid reducing the max. +- * entries. */ +- max_factor = 4; +- } +- nf_conntrack_hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, +- &nf_conntrack_vmalloc); +- if (!nf_conntrack_hash) { +- printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); +- goto err_out; ++#ifdef CONFIG_VE_IPTABLES ++ if (ve->_nf_conntrack) ++ return 0; ++#endif ++ if (ve_is_super(ve)) { ++ ++ /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB ++ * machine has 512 buckets. >= 1GB machines have 16384 buckets. */ ++ if (!nf_conntrack_htable_size) { ++ nf_conntrack_htable_size ++ = (((num_physpages << PAGE_SHIFT) / 16384) ++ / sizeof(struct hlist_head)); ++ if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) ++ nf_conntrack_htable_size = 16384; ++ if (nf_conntrack_htable_size < 32) ++ nf_conntrack_htable_size = 32; ++ ++ /* Use a max. factor of four by default to get the same ++ * max as with the old struct list_heads. When a table ++ * size is given we use the old value of 8 to avoid ++ * reducing the max. entries. */ ++ max_factor = 4; ++ } ++ nf_conntrack_max = max_factor * nf_conntrack_htable_size; ++ ++ printk("nf_conntrack version %s (%u buckets, %d max)\n", ++ NF_CONNTRACK_VERSION, nf_conntrack_htable_size, ++ nf_conntrack_max); + } + +- nf_conntrack_max = max_factor * nf_conntrack_htable_size; ++#ifdef CONFIG_VE_IPTABLES ++ ve->_nf_conntrack = kzalloc(sizeof(struct ve_nf_conntrack), GFP_KERNEL); ++ if (!ve->_nf_conntrack) { ++ ret = -ENOMEM; ++ goto out; ++ } + +- printk("nf_conntrack version %s (%u buckets, %d max)\n", +- NF_CONNTRACK_VERSION, nf_conntrack_htable_size, +- nf_conntrack_max); ++ ve_nf_conntrack_max = nf_conntrack_max; ++ atomic_set(&ve_nf_conntrack_count, 0); ++ INIT_HLIST_HEAD(&ve_unconfirmed); ++#endif ++ ve_nf_conntrack_hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, ++ &ve_nf_conntrack_vmalloc); ++ if (!ve_nf_conntrack_hash) { ++ printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); ++ goto err_out; ++ } + +- nf_conntrack_cachep = kmem_cache_create("nf_conntrack", ++ if (ve_is_super(ve)) { ++ nf_conntrack_cachep = kmem_cache_create("nf_conntrack", + sizeof(struct nf_conn), +- 0, 0, NULL); +- if (!nf_conntrack_cachep) { +- printk(KERN_ERR "Unable to create nf_conn slab cache\n"); +- goto err_free_hash; ++ 0, SLAB_UBC, NULL); ++ if (!nf_conntrack_cachep) { ++ printk(KERN_ERR "Unable to create nf_conn slab cache\n"); ++ goto err_free_hash; ++ } + } + +- ret = nf_conntrack_proto_init(); ++ ret = nf_ct_proto_generic_sysctl_init(); + if (ret < 0) + goto err_free_conntrack_slab; ++ ret = nf_conntrack_l4proto_register(ve_nf_conntrack_l4proto_generic); ++ if (ret < 0) ++ goto free_sys; ++ /* Don't NEED lock here, but good form anyway. */ ++ write_lock_bh(&nf_conntrack_lock); ++ for (i = 0; i < AF_MAX; i++) ++ ve_nf_ct_l3protos[i] = &nf_conntrack_l3proto_generic; ++ write_unlock_bh(&nf_conntrack_lock); + + ret = nf_conntrack_expect_init(); + if (ret < 0) +@@ -1123,27 +1207,41 @@ + if (ret < 0) + goto out_fini_expect; + +- /* For use by REJECT target */ +- rcu_assign_pointer(ip_ct_attach, __nf_conntrack_attach); +- rcu_assign_pointer(nf_ct_destroy, destroy_conntrack); +- +- /* Set up fake conntrack: +- - to never be deleted, not in any hashes */ +- atomic_set(&nf_conntrack_untracked.ct_general.use, 1); +- /* - and look it like as a confirmed connection */ +- set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status); ++ if (ve_is_super(ve)) { ++ /* For use by REJECT target */ ++ rcu_assign_pointer(ip_ct_attach, __nf_conntrack_attach); ++ rcu_assign_pointer(nf_ct_destroy, destroy_conntrack); ++ ++ /* Set up fake conntrack: ++ - to never be deleted, not in any hashes */ ++ atomic_set(&nf_conntrack_untracked.ct_general.use, 1); ++ /* - and look it like as a confirmed connection */ ++ set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status); ++ } + +- return ret; ++ return 0; + ++free_sys: ++#if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) ++ nf_ct_proto_generic_sysctl_cleanup(); ++ ve_nf_conntrack_l4proto_generic = NULL; ++#endif + out_fini_expect: + nf_conntrack_expect_fini(); + out_fini_proto: + nf_conntrack_proto_fini(); + err_free_conntrack_slab: +- kmem_cache_destroy(nf_conntrack_cachep); ++ if (ve_is_super(ve)) ++ kmem_cache_destroy(nf_conntrack_cachep); + err_free_hash: +- nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_vmalloc, ++ nf_ct_free_hashtable(ve_nf_conntrack_hash, nf_conntrack_vmalloc, + nf_conntrack_htable_size); ++ ve_nf_conntrack_hash = NULL; + err_out: +- return -ENOMEM; ++#ifdef CONFIG_VE_IPTABLES ++ kfree(ve->_nf_conntrack); ++ ve->_nf_conntrack = NULL; ++out: ++#endif ++ return ret; + } +Index: kernel/net/netfilter/nf_conntrack_ecache.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_ecache.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_ecache.c 2008-11-24 15:47:46.000000000 +0100 +@@ -53,6 +53,9 @@ + { + struct nf_conntrack_ecache *ecache; + ++ if (!ve_is_super(get_exec_env())) ++ return; ++ + local_bh_disable(); + ecache = &__get_cpu_var(nf_conntrack_ecache); + if (ecache->ct == ct) +@@ -66,6 +69,9 @@ + { + struct nf_conntrack_ecache *ecache; + ++ if (!ve_is_super(get_exec_env())) ++ return; ++ + /* take care of delivering potentially old events */ + ecache = &__get_cpu_var(nf_conntrack_ecache); + BUG_ON(ecache->ct == ct); +@@ -84,6 +90,9 @@ + struct nf_conntrack_ecache *ecache; + int cpu; + ++ if (!ve_is_super(get_exec_env())) ++ return; ++ + for_each_possible_cpu(cpu) { + ecache = &per_cpu(nf_conntrack_ecache, cpu); + if (ecache->ct) +Index: kernel/net/netfilter/nf_conntrack_expect.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_expect.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_expect.c 2008-11-24 15:47:46.000000000 +0100 +@@ -39,6 +39,11 @@ + unsigned int nf_ct_expect_max __read_mostly; + static int nf_ct_expect_hash_rnd_initted __read_mostly; + static int nf_ct_expect_vmalloc; ++#ifdef CONFIG_VE_IPTABLES ++#define ve_nf_ct_expect_vmalloc (get_exec_env()->_nf_conntrack->_nf_ct_expect_vmalloc) ++#else ++#define ve_nf_ct_expect_vmalloc nf_ct_expect_vmalloc ++#endif + + static struct kmem_cache *nf_ct_expect_cachep __read_mostly; + +@@ -95,7 +100,7 @@ + return NULL; + + h = nf_ct_expect_dst_hash(tuple); +- hlist_for_each_entry(i, n, &nf_ct_expect_hash[h], hnode) { ++ hlist_for_each_entry(i, n, &ve_nf_ct_expect_hash[h], hnode) { + if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) + return i; + } +@@ -293,7 +298,7 @@ + hlist_add_head(&exp->lnode, &master_help->expectations); + master_help->expecting++; + +- hlist_add_head(&exp->hnode, &nf_ct_expect_hash[h]); ++ hlist_add_head(&exp->hnode, &ve_nf_ct_expect_hash[h]); + nf_ct_expect_count++; + + setup_timer(&exp->timeout, nf_ct_expectation_timed_out, +@@ -350,7 +355,7 @@ + goto out; + } + h = nf_ct_expect_dst_hash(&expect->tuple); +- hlist_for_each_entry(i, n, &nf_ct_expect_hash[h], hnode) { ++ hlist_for_each_entry(i, n, &ve_nf_ct_expect_hash[h], hnode) { + if (expect_matches(i, expect)) { + /* Refresh timer: if it's dying, ignore.. */ + if (refresh_timer(i)) { +@@ -367,7 +372,7 @@ + master_help->expecting >= master_help->helper->max_expected) + evict_oldest_expect(master); + +- if (nf_ct_expect_count >= nf_ct_expect_max) { ++ if (nf_ct_expect_count >= ve_nf_ct_expect_max) { + if (net_ratelimit()) + printk(KERN_WARNING + "nf_conntrack: expectation table full"); +@@ -394,8 +399,8 @@ + struct ct_expect_iter_state *st = seq->private; + + for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) { +- if (!hlist_empty(&nf_ct_expect_hash[st->bucket])) +- return nf_ct_expect_hash[st->bucket].first; ++ if (!hlist_empty(&ve_nf_ct_expect_hash[st->bucket])) ++ return ve_nf_ct_expect_hash[st->bucket].first; + } + return NULL; + } +@@ -409,7 +414,7 @@ + while (head == NULL) { + if (++st->bucket >= nf_ct_expect_hsize) + return NULL; +- head = nf_ct_expect_hash[st->bucket].first; ++ head = ve_nf_ct_expect_hash[st->bucket].first; + } + return head; + } +@@ -506,7 +511,7 @@ + + module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0600); + +-int __init nf_conntrack_expect_init(void) ++int nf_conntrack_expect_init(void) + { + int err = -ENOMEM; + +@@ -517,16 +522,18 @@ + } + nf_ct_expect_max = nf_ct_expect_hsize * 4; + +- nf_ct_expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, +- &nf_ct_expect_vmalloc); +- if (nf_ct_expect_hash == NULL) ++ ve_nf_ct_expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, ++ &ve_nf_ct_expect_vmalloc); ++ if (ve_nf_ct_expect_hash == NULL) + goto err1; + +- nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect", ++ if (ve_is_super(get_exec_env())) { ++ nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect", + sizeof(struct nf_conntrack_expect), +- 0, 0, NULL); +- if (!nf_ct_expect_cachep) +- goto err2; ++ 0, SLAB_UBC, NULL); ++ if (!nf_ct_expect_cachep) ++ goto err2; ++ } + + err = exp_proc_init(); + if (err < 0) +@@ -535,10 +542,11 @@ + return 0; + + err3: +- nf_ct_free_hashtable(nf_ct_expect_hash, nf_ct_expect_vmalloc, ++ nf_ct_free_hashtable(ve_nf_ct_expect_hash, ve_nf_ct_expect_vmalloc, + nf_ct_expect_hsize); + err2: +- kmem_cache_destroy(nf_ct_expect_cachep); ++ if (ve_is_super(get_exec_env())) ++ kmem_cache_destroy(nf_ct_expect_cachep); + err1: + return err; + } +@@ -546,7 +554,8 @@ + void nf_conntrack_expect_fini(void) + { + exp_proc_remove(); +- kmem_cache_destroy(nf_ct_expect_cachep); +- nf_ct_free_hashtable(nf_ct_expect_hash, nf_ct_expect_vmalloc, ++ if (ve_is_super(get_exec_env())) ++ kmem_cache_destroy(nf_ct_expect_cachep); ++ nf_ct_free_hashtable(ve_nf_ct_expect_hash, ve_nf_ct_expect_vmalloc, + nf_ct_expect_hsize); + } +Index: kernel/net/netfilter/nf_conntrack_helper.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_helper.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_helper.c 2008-11-24 15:47:46.000000000 +0100 +@@ -32,6 +32,13 @@ + static unsigned int nf_ct_helper_hsize __read_mostly; + static unsigned int nf_ct_helper_count __read_mostly; + static int nf_ct_helper_vmalloc; ++#ifdef CONFIG_VE_IPTABLES ++#define ve_nf_ct_helper_hash (get_exec_env()->_nf_conntrack->_nf_ct_helper_hash) ++#define ve_nf_ct_helper_vmalloc (get_exec_env()->_nf_conntrack->_nf_ct_helper_vmalloc) ++#else ++#define ve_nf_ct_helper_hash nf_ct_helper_hash ++#define ve_nf_ct_helper_vmalloc nf_ct_helper_vmalloc ++#endif + + + /* Stupid hash, but collision free for the default registrations of the +@@ -54,7 +61,7 @@ + return NULL; + + h = helper_hash(tuple); +- hlist_for_each_entry(helper, n, &nf_ct_helper_hash[h], hnode) { ++ hlist_for_each_entry(helper, n, &ve_nf_ct_helper_hash[h], hnode) { + if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask)) + return helper; + } +@@ -99,7 +106,7 @@ + unsigned int i; + + for (i = 0; i < nf_ct_helper_hsize; i++) { +- hlist_for_each_entry(h, n, &nf_ct_helper_hash[i], hnode) { ++ hlist_for_each_entry(h, n, &ve_nf_ct_helper_hash[i], hnode) { + if (!strcmp(h->name, name)) + return h; + } +@@ -141,7 +148,7 @@ + BUG_ON(me->timeout == 0); + + write_lock_bh(&nf_conntrack_lock); +- hlist_add_head(&me->hnode, &nf_ct_helper_hash[h]); ++ hlist_add_head(&me->hnode, &ve_nf_ct_helper_hash[h]); + nf_ct_helper_count++; + write_unlock_bh(&nf_conntrack_lock); + +@@ -164,7 +171,7 @@ + /* Get rid of expectations */ + for (i = 0; i < nf_ct_expect_hsize; i++) { + hlist_for_each_entry_safe(exp, n, next, +- &nf_ct_expect_hash[i], hnode) { ++ &ve_nf_ct_expect_hash[i], hnode) { + struct nf_conn_help *help = nfct_help(exp->master); + if ((help->helper == me || exp->helper == me) && + del_timer(&exp->timeout)) { +@@ -175,10 +182,10 @@ + } + + /* Get rid of expecteds, set helpers to NULL. */ +- hlist_for_each_entry(h, n, &unconfirmed, hnode) ++ hlist_for_each_entry(h, n, &ve_unconfirmed, hnode) + unhelp(h, me); + for (i = 0; i < nf_conntrack_htable_size; i++) { +- hlist_for_each_entry(h, n, &nf_conntrack_hash[i], hnode) ++ hlist_for_each_entry(h, n, &ve_nf_conntrack_hash[i], hnode) + unhelp(h, me); + } + write_unlock_bh(&nf_conntrack_lock); +@@ -199,26 +206,29 @@ + int err; + + nf_ct_helper_hsize = 1; /* gets rounded up to use one page */ +- nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize, +- &nf_ct_helper_vmalloc); +- if (!nf_ct_helper_hash) ++ ve_nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize, ++ &ve_nf_ct_helper_vmalloc); ++ if (!ve_nf_ct_helper_hash) + return -ENOMEM; + +- err = nf_ct_extend_register(&helper_extend); +- if (err < 0) +- goto err1; ++ if (ve_is_super(get_exec_env())) { ++ err = nf_ct_extend_register(&helper_extend); ++ if (err < 0) ++ goto err1; ++ } + + return 0; + + err1: +- nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc, ++ nf_ct_free_hashtable(ve_nf_ct_helper_hash, ve_nf_ct_helper_vmalloc, + nf_ct_helper_hsize); + return err; + } + + void nf_conntrack_helper_fini(void) + { +- nf_ct_extend_unregister(&helper_extend); +- nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc, ++ if (ve_is_super(get_exec_env())) ++ nf_ct_extend_unregister(&helper_extend); ++ nf_ct_free_hashtable(ve_nf_ct_helper_hash, ve_nf_ct_helper_vmalloc, + nf_ct_helper_hsize); + } +Index: kernel/net/netfilter/nf_conntrack_netlink.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_netlink.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_netlink.c 2008-11-24 15:47:46.000000000 +0100 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -43,6 +44,8 @@ + + #include + #include ++#include ++#include + + MODULE_LICENSE("GPL"); + +@@ -459,7 +462,7 @@ + last = (struct nf_conn *)cb->args[1]; + for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { + restart: +- hlist_for_each_entry(h, n, &nf_conntrack_hash[cb->args[0]], ++ hlist_for_each_entry(h, n, &ve_nf_conntrack_hash[cb->args[0]], + hnode) { + if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) + continue; +@@ -976,14 +979,15 @@ + ctnetlink_create_conntrack(struct nlattr *cda[], + struct nf_conntrack_tuple *otuple, + struct nf_conntrack_tuple *rtuple, +- struct nf_conn *master_ct) ++ struct nf_conn *master_ct, ++ struct user_beancounter *ub) + { + struct nf_conn *ct; + int err = -EINVAL; + struct nf_conn_help *help; + struct nf_conntrack_helper *helper; + +- ct = nf_conntrack_alloc(otuple, rtuple); ++ ct = nf_conntrack_alloc(otuple, rtuple, ub); + if (ct == NULL || IS_ERR(ct)) + return -ENOMEM; + +@@ -1094,11 +1098,19 @@ + + write_unlock_bh(&nf_conntrack_lock); + err = -ENOENT; +- if (nlh->nlmsg_flags & NLM_F_CREATE) ++ if (nlh->nlmsg_flags & NLM_F_CREATE) { ++ struct user_beancounter *ub = NULL; ++ ++#ifdef CONFIG_BEANCOUNTERS ++ if (skb->sk) ++ ub = sock_bc(skb->sk)->ub; ++#endif + err = ctnetlink_create_conntrack(cda, + &otuple, + &rtuple, +- master_ct); ++ master_ct, ++ ub); ++ } + if (err < 0 && master_ct) + nf_ct_put(master_ct); + +@@ -1318,7 +1330,7 @@ + last = (struct nf_conntrack_expect *)cb->args[1]; + for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) { + restart: +- hlist_for_each_entry(exp, n, &nf_ct_expect_hash[cb->args[0]], ++ hlist_for_each_entry(exp, n, &ve_nf_ct_expect_hash[cb->args[0]], + hnode) { + if (l3proto && exp->tuple.src.l3num != l3proto) + continue; +@@ -1463,7 +1475,7 @@ + } + for (i = 0; i < nf_ct_expect_hsize; i++) { + hlist_for_each_entry_safe(exp, n, next, +- &nf_ct_expect_hash[i], ++ &ve_nf_ct_expect_hash[i], + hnode) { + m_help = nfct_help(exp->master); + if (m_help->helper == h +@@ -1479,7 +1491,7 @@ + write_lock_bh(&nf_conntrack_lock); + for (i = 0; i < nf_ct_expect_hsize; i++) { + hlist_for_each_entry_safe(exp, n, next, +- &nf_ct_expect_hash[i], ++ &ve_nf_ct_expect_hash[i], + hnode) { + if (del_timer(&exp->timeout)) { + nf_ct_unlink_expect(exp); +Index: kernel/net/netfilter/nf_conntrack_proto.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_proto.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_proto.c 2008-11-24 15:47:46.000000000 +0100 +@@ -28,7 +28,7 @@ + #include + #include + +-static struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly; ++struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly; + struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly; + EXPORT_SYMBOL_GPL(nf_ct_l3protos); + +@@ -63,10 +63,10 @@ + struct nf_conntrack_l4proto * + __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) + { +- if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL)) +- return &nf_conntrack_l4proto_generic; ++ if (unlikely(l3proto >= AF_MAX || ve_nf_ct_protos[l3proto] == NULL)) ++ return ve_nf_conntrack_l4proto_generic; + +- return rcu_dereference(nf_ct_protos[l3proto][l4proto]); ++ return rcu_dereference(ve_nf_ct_protos[l3proto][l4proto]); + } + EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find); + +@@ -80,7 +80,7 @@ + rcu_read_lock(); + p = __nf_ct_l4proto_find(l3proto, l4proto); + if (!try_module_get(p->me)) +- p = &nf_conntrack_l4proto_generic; ++ p = ve_nf_conntrack_l4proto_generic; + rcu_read_unlock(); + + return p; +@@ -190,7 +190,8 @@ + return -EBUSY; + + mutex_lock(&nf_ct_proto_mutex); +- if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) { ++ if (ve_nf_ct_l3protos[proto->l3proto] != ++ &nf_conntrack_l3proto_generic) { + ret = -EBUSY; + goto out_unlock; + } +@@ -199,7 +200,7 @@ + if (ret < 0) + goto out_unlock; + +- rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); ++ rcu_assign_pointer(ve_nf_ct_l3protos[proto->l3proto], proto); + + out_unlock: + mutex_unlock(&nf_ct_proto_mutex); +@@ -212,8 +213,8 @@ + BUG_ON(proto->l3proto >= AF_MAX); + + mutex_lock(&nf_ct_proto_mutex); +- BUG_ON(nf_ct_l3protos[proto->l3proto] != proto); +- rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], ++ BUG_ON(ve_nf_ct_l3protos[proto->l3proto] != proto); ++ rcu_assign_pointer(ve_nf_ct_l3protos[proto->l3proto], + &nf_conntrack_l3proto_generic); + nf_ct_l3proto_unregister_sysctl(proto); + mutex_unlock(&nf_ct_proto_mutex); +@@ -281,7 +282,7 @@ + return -EBUSY; + + mutex_lock(&nf_ct_proto_mutex); +- if (!nf_ct_protos[l4proto->l3proto]) { ++ if (!ve_nf_ct_protos[l4proto->l3proto]) { + /* l3proto may be loaded latter. */ + struct nf_conntrack_l4proto **proto_array; + int i; +@@ -295,10 +296,10 @@ + } + + for (i = 0; i < MAX_NF_CT_PROTO; i++) +- proto_array[i] = &nf_conntrack_l4proto_generic; +- nf_ct_protos[l4proto->l3proto] = proto_array; +- } else if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != +- &nf_conntrack_l4proto_generic) { ++ proto_array[i] = ve_nf_conntrack_l4proto_generic; ++ ve_nf_ct_protos[l4proto->l3proto] = proto_array; ++ } else if (ve_nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != ++ ve_nf_conntrack_l4proto_generic) { + ret = -EBUSY; + goto out_unlock; + } +@@ -307,7 +308,7 @@ + if (ret < 0) + goto out_unlock; + +- rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], ++ rcu_assign_pointer(ve_nf_ct_protos[l4proto->l3proto][l4proto->l4proto], + l4proto); + + out_unlock: +@@ -321,9 +322,9 @@ + BUG_ON(l4proto->l3proto >= PF_MAX); + + mutex_lock(&nf_ct_proto_mutex); +- BUG_ON(nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != l4proto); +- rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], +- &nf_conntrack_l4proto_generic); ++ BUG_ON(ve_nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != l4proto); ++ rcu_assign_pointer(ve_nf_ct_protos[l4proto->l3proto][l4proto->l4proto], ++ ve_nf_conntrack_l4proto_generic); + nf_ct_l4proto_unregister_sysctl(l4proto); + mutex_unlock(&nf_ct_proto_mutex); + +@@ -339,12 +340,12 @@ + unsigned int i; + int err; + +- err = nf_ct_l4proto_register_sysctl(&nf_conntrack_l4proto_generic); ++ err = nf_ct_l4proto_register_sysctl(ve_nf_conntrack_l4proto_generic); + if (err < 0) + return err; + + for (i = 0; i < AF_MAX; i++) +- rcu_assign_pointer(nf_ct_l3protos[i], ++ rcu_assign_pointer(ve_nf_ct_l3protos[i], + &nf_conntrack_l3proto_generic); + return 0; + } +@@ -353,9 +354,11 @@ + { + unsigned int i; + +- nf_ct_l4proto_unregister_sysctl(&nf_conntrack_l4proto_generic); ++ nf_ct_l4proto_unregister_sysctl(ve_nf_conntrack_l4proto_generic); + + /* free l3proto protocol tables */ +- for (i = 0; i < PF_MAX; i++) +- kfree(nf_ct_protos[i]); ++ for (i = 0; i < PF_MAX; i++) { ++ kfree(ve_nf_ct_protos[i]); ++ ve_nf_ct_protos[i] = NULL; ++ } + } +Index: kernel/net/netfilter/nf_conntrack_proto_generic.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_proto_generic.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_proto_generic.c 2008-11-24 15:47:46.000000000 +0100 +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -55,7 +56,7 @@ + int pf, + unsigned int hooknum) + { +- nf_ct_refresh_acct(conntrack, ctinfo, skb, nf_ct_generic_timeout); ++ nf_ct_refresh_acct(conntrack, ctinfo, skb, ve_nf_ct_generic_timeout); + return NF_ACCEPT; + } + +@@ -115,3 +116,65 @@ + #endif + #endif + }; ++ ++#if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) ++void nf_ct_proto_generic_sysctl_cleanup(void) ++{ ++ if (!ve_is_super(get_exec_env())) { ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ free_sysctl_clone( ++ ve_nf_conntrack_l4proto_generic->ctl_compat_table); ++ ve_nf_conntrack_l4proto_generic->ctl_compat_table = NULL; ++#endif ++ free_sysctl_clone(ve_nf_conntrack_l4proto_generic->ctl_table); ++ ve_nf_conntrack_l4proto_generic->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l4proto_generic); ++ ve_nf_conntrack_l4proto_generic = NULL; ++ } ++} ++EXPORT_SYMBOL(nf_ct_proto_generic_sysctl_cleanup); ++ ++int nf_ct_proto_generic_sysctl_init(void) ++{ ++ struct nf_conntrack_l4proto *generic; ++ ++ if (ve_is_super(get_exec_env())) { ++ generic = &nf_conntrack_l4proto_generic; ++ goto out; ++ } ++ ++ generic = kmemdup(&nf_conntrack_l4proto_generic, ++ sizeof(struct nf_conntrack_l4proto), GFP_KERNEL); ++ if (generic == NULL) ++ goto no_mem_ct; ++ ++ generic->ctl_table_header = &ve_generic_sysctl_header; ++ generic->ctl_table = clone_sysctl_template(generic_sysctl_table); ++ if (generic->ctl_table == NULL) ++ goto no_mem_sys; ++ ++ generic->ctl_table[0].data = &ve_nf_ct_generic_timeout; ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ generic->ctl_compat_table_header = ve_generic_compat_sysctl_header; ++ generic->ctl_compat_table = clone_sysctl_template(generic_compat_sysctl_table); ++ if (generic->ctl_compat_table == NULL) ++ goto no_mem_compat; ++ generic->ctl_compat_table[0].data = &ve_nf_ct_generic_timeout; ++#endif ++out: ++ ve_nf_ct_generic_timeout = nf_ct_generic_timeout; ++ ++ ve_nf_conntrack_l4proto_generic = generic; ++ return 0; ++ ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++no_mem_compat: ++ free_sysctl_clone(generic->ctl_table); ++#endif ++no_mem_sys: ++ kfree(generic); ++no_mem_ct: ++ return -ENOMEM; ++} ++EXPORT_SYMBOL(nf_ct_proto_generic_sysctl_init); ++#endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ +Index: kernel/net/netfilter/nf_conntrack_proto_tcp.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_proto_tcp.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_proto_tcp.c 2008-11-24 15:47:46.000000000 +0100 +@@ -7,6 +7,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -31,16 +32,16 @@ + /* "Be conservative in what you do, + be liberal in what you accept from others." + If it's non-zero, we mark only out of window RST segments as INVALID. */ +-static int nf_ct_tcp_be_liberal __read_mostly = 0; ++int nf_ct_tcp_be_liberal __read_mostly = 0; + + /* If it is set to zero, we disable picking up already established + connections. */ +-static int nf_ct_tcp_loose __read_mostly = 1; ++int nf_ct_tcp_loose __read_mostly = 1; + + /* Max number of the retransmitted packets without receiving an (acceptable) + ACK from the destination. If this number is reached, a shorter timer + will be started. */ +-static int nf_ct_tcp_max_retrans __read_mostly = 3; ++int nf_ct_tcp_max_retrans __read_mostly = 3; + + /* FIXME: Examine ipfilter's timeouts and conntrack transitions more + closely. They're more complex. --RR */ +@@ -63,21 +64,21 @@ + #define HOURS * 60 MINS + #define DAYS * 24 HOURS + +-static unsigned int nf_ct_tcp_timeout_syn_sent __read_mostly = 2 MINS; +-static unsigned int nf_ct_tcp_timeout_syn_recv __read_mostly = 60 SECS; +-static unsigned int nf_ct_tcp_timeout_established __read_mostly = 5 DAYS; +-static unsigned int nf_ct_tcp_timeout_fin_wait __read_mostly = 2 MINS; +-static unsigned int nf_ct_tcp_timeout_close_wait __read_mostly = 60 SECS; +-static unsigned int nf_ct_tcp_timeout_last_ack __read_mostly = 30 SECS; +-static unsigned int nf_ct_tcp_timeout_time_wait __read_mostly = 2 MINS; +-static unsigned int nf_ct_tcp_timeout_close __read_mostly = 10 SECS; ++unsigned int nf_ct_tcp_timeout_syn_sent __read_mostly = 2 MINS; ++unsigned int nf_ct_tcp_timeout_syn_recv __read_mostly = 60 SECS; ++unsigned int nf_ct_tcp_timeout_established __read_mostly = 5 DAYS; ++unsigned int nf_ct_tcp_timeout_fin_wait __read_mostly = 2 MINS; ++unsigned int nf_ct_tcp_timeout_close_wait __read_mostly = 60 SECS; ++unsigned int nf_ct_tcp_timeout_last_ack __read_mostly = 30 SECS; ++unsigned int nf_ct_tcp_timeout_time_wait __read_mostly = 2 MINS; ++unsigned int nf_ct_tcp_timeout_close __read_mostly = 10 SECS; + + /* RFC1122 says the R2 limit should be at least 100 seconds. + Linux uses 15 packets as limit, which corresponds + to ~13-30min depending on RTO. */ +-static unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS; ++unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS; + +-static unsigned int * tcp_timeouts[] = { ++unsigned int * tcp_timeouts[] = { + NULL, /* TCP_CONNTRACK_NONE */ + &nf_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */ + &nf_ct_tcp_timeout_syn_recv, /* TCP_CONNTRACK_SYN_RECV, */ +@@ -671,7 +672,7 @@ + } else { + res = 0; + if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL || +- nf_ct_tcp_be_liberal) ++ ve_nf_ct_tcp_be_liberal) + res = 1; + if (!res && LOG_INVALID(IPPROTO_TCP)) + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, +@@ -960,9 +961,9 @@ + if (old_state != new_state + && new_state == TCP_CONNTRACK_FIN_WAIT) + conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; +- timeout = conntrack->proto.tcp.retrans >= nf_ct_tcp_max_retrans +- && *tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans +- ? nf_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state]; ++ timeout = conntrack->proto.tcp.retrans >= ve_nf_ct_tcp_max_retrans ++ && ve_nf_ct_tcp_timeouts[new_state] > ve_nf_ct_tcp_timeout_max_retrans ++ ? ve_nf_ct_tcp_timeout_max_retrans : ve_nf_ct_tcp_timeouts[new_state]; + write_unlock_bh(&tcp_lock); + + nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb); +@@ -1032,7 +1033,7 @@ + + tcp_options(skb, dataoff, th, &conntrack->proto.tcp.seen[0]); + conntrack->proto.tcp.seen[1].flags = 0; +- } else if (nf_ct_tcp_loose == 0) { ++ } else if (ve_nf_ct_tcp_loose == 0) { + /* Don't try to pick up connections. */ + return 0; + } else { +@@ -1427,3 +1428,118 @@ + #endif + }; + EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp6); ++ ++#if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) ++void nf_ct_proto_tcp_sysctl_cleanup(void) ++{ ++ if (!ve_is_super(get_exec_env())) { ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ free_sysctl_clone( ++ ve_nf_conntrack_l4proto_tcp4->ctl_compat_table); ++ ve_nf_conntrack_l4proto_tcp4->ctl_compat_table = NULL; ++#endif ++ free_sysctl_clone(ve_nf_conntrack_l4proto_tcp4->ctl_table); ++ ve_nf_conntrack_l4proto_tcp4->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l4proto_tcp4); ++ ve_nf_conntrack_l4proto_tcp4 = NULL; ++ ++ kfree(ve_nf_conntrack_l4proto_tcp6); ++ ve_nf_conntrack_l4proto_tcp6 = NULL; ++ } ++} ++EXPORT_SYMBOL(nf_ct_proto_tcp_sysctl_cleanup); ++ ++int nf_ct_proto_tcp_sysctl_init(void) ++{ ++ struct nf_conntrack_l4proto *tcp4, *tcp6; ++ ++ if (ve_is_super(get_exec_env())) { ++ tcp4 = &nf_conntrack_l4proto_tcp4; ++ tcp6 = &nf_conntrack_l4proto_tcp6; ++ goto out; ++ } ++ ++ tcp4 = kmemdup(&nf_conntrack_l4proto_tcp4, ++ sizeof(struct nf_conntrack_l4proto), GFP_KERNEL); ++ if (tcp4 == NULL) ++ goto no_mem_ct4; ++ ++ tcp4->ctl_table_users = &ve_tcp_sysctl_table_users; ++ tcp4->ctl_table_header = &ve_tcp_sysctl_header; ++ tcp4->ctl_table = clone_sysctl_template(tcp_sysctl_table); ++ if (tcp4->ctl_table == NULL) ++ goto no_mem_sys; ++ ++ tcp4->ctl_table[0].data = &ve_nf_ct_tcp_timeouts[1]; ++ tcp4->ctl_table[1].data = &ve_nf_ct_tcp_timeouts[2]; ++ tcp4->ctl_table[2].data = &ve_nf_ct_tcp_timeouts[3]; ++ tcp4->ctl_table[3].data = &ve_nf_ct_tcp_timeouts[4]; ++ tcp4->ctl_table[4].data = &ve_nf_ct_tcp_timeouts[5]; ++ tcp4->ctl_table[5].data = &ve_nf_ct_tcp_timeouts[6]; ++ tcp4->ctl_table[6].data = &ve_nf_ct_tcp_timeouts[7]; ++ tcp4->ctl_table[7].data = &ve_nf_ct_tcp_timeouts[8]; ++ tcp4->ctl_table[8].data = &ve_nf_ct_tcp_timeout_max_retrans; ++ tcp4->ctl_table[9].data = &ve_nf_ct_tcp_loose; ++ tcp4->ctl_table[10].data = &ve_nf_ct_tcp_be_liberal; ++ tcp4->ctl_table[11].data = &ve_nf_ct_tcp_max_retrans; ++ ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ tcp4->ctl_compat_table_header = ve_tcp_compat_sysctl_header; ++ tcp4->ctl_compat_table = clone_sysctl_template(tcp_compat_sysctl_table); ++ if (tcp4->ctl_compat_table == NULL) ++ goto no_mem_compat; ++ ++ tcp4->ctl_compat_table[0].data = &ve_nf_ct_tcp_timeouts[1]; ++ tcp4->ctl_compat_table[1].data = &ve_nf_ct_tcp_timeouts[2]; ++ tcp4->ctl_compat_table[2].data = &ve_nf_ct_tcp_timeouts[3]; ++ tcp4->ctl_compat_table[3].data = &ve_nf_ct_tcp_timeouts[4]; ++ tcp4->ctl_compat_table[4].data = &ve_nf_ct_tcp_timeouts[5]; ++ tcp4->ctl_compat_table[5].data = &ve_nf_ct_tcp_timeouts[6]; ++ tcp4->ctl_compat_table[6].data = &ve_nf_ct_tcp_timeouts[7]; ++ tcp4->ctl_compat_table[7].data = &ve_nf_ct_tcp_timeouts[8]; ++ tcp4->ctl_compat_table[8].data = &ve_nf_ct_tcp_timeout_max_retrans; ++ tcp4->ctl_compat_table[9].data = &ve_nf_ct_tcp_loose; ++ tcp4->ctl_compat_table[10].data = &ve_nf_ct_tcp_be_liberal; ++ tcp4->ctl_compat_table[11].data = &ve_nf_ct_tcp_max_retrans; ++#endif ++ ++ tcp6 = kmemdup(&nf_conntrack_l4proto_tcp6, ++ sizeof(struct nf_conntrack_l4proto), GFP_KERNEL); ++ if (!tcp6) ++ goto no_mem_ct6; ++ ++ tcp6->ctl_table_users = &ve_tcp_sysctl_table_users; ++ tcp6->ctl_table_header = &ve_tcp_sysctl_header; ++ tcp6->ctl_table = tcp4->ctl_table; ++out: ++ ve_nf_ct_tcp_timeouts[1] = nf_ct_tcp_timeout_syn_sent; ++ ve_nf_ct_tcp_timeouts[2] = nf_ct_tcp_timeout_syn_recv; ++ ve_nf_ct_tcp_timeouts[3] = nf_ct_tcp_timeout_established; ++ ve_nf_ct_tcp_timeouts[4] = nf_ct_tcp_timeout_fin_wait; ++ ve_nf_ct_tcp_timeouts[5] = nf_ct_tcp_timeout_close_wait; ++ ve_nf_ct_tcp_timeouts[6] = nf_ct_tcp_timeout_last_ack; ++ ve_nf_ct_tcp_timeouts[7] = nf_ct_tcp_timeout_time_wait; ++ ve_nf_ct_tcp_timeouts[8] = nf_ct_tcp_timeout_close; ++ ve_nf_ct_tcp_timeout_max_retrans = nf_ct_tcp_timeout_max_retrans; ++ ve_nf_ct_tcp_loose = nf_ct_tcp_loose; ++ ve_nf_ct_tcp_be_liberal = nf_ct_tcp_be_liberal; ++ ve_nf_ct_tcp_max_retrans = nf_ct_tcp_max_retrans; ++ ++ ve_nf_conntrack_l4proto_tcp4 = tcp4; ++ ve_nf_conntrack_l4proto_tcp6 = tcp6; ++ return 0; ++ ++no_mem_ct6: ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ free_sysctl_clone(tcp4->ctl_compat_table); ++no_mem_compat: ++#endif ++ free_sysctl_clone(tcp4->ctl_table); ++no_mem_sys: ++ kfree(tcp4); ++no_mem_ct4: ++ return -ENOMEM; ++} ++EXPORT_SYMBOL(nf_ct_proto_tcp_sysctl_init); ++#endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ ++ +Index: kernel/net/netfilter/nf_conntrack_proto_udp.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_proto_udp.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_proto_udp.c 2008-11-24 15:47:46.000000000 +0100 +@@ -7,6 +7,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -78,12 +79,12 @@ + stream. Extend timeout. */ + if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { + nf_ct_refresh_acct(conntrack, ctinfo, skb, +- nf_ct_udp_timeout_stream); ++ ve_nf_ct_udp_timeout_stream); + /* Also, more likely to be important, and not a probe */ + if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status)) + nf_conntrack_event_cache(IPCT_STATUS, skb); + } else +- nf_ct_refresh_acct(conntrack, ctinfo, skb, nf_ct_udp_timeout); ++ nf_ct_refresh_acct(conntrack, ctinfo, skb, ve_nf_ct_udp_timeout); + + return NF_ACCEPT; + } +@@ -238,3 +239,88 @@ + #endif + }; + EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6); ++ ++#if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) ++void nf_ct_proto_udp_sysctl_cleanup(void) ++{ ++ if (!ve_is_super(get_exec_env())) { ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ free_sysctl_clone( ++ ve_nf_conntrack_l4proto_udp4->ctl_compat_table); ++ ve_nf_conntrack_l4proto_udp4->ctl_compat_table = NULL; ++#endif ++ free_sysctl_clone(ve_nf_conntrack_l4proto_udp4->ctl_table); ++ ve_nf_conntrack_l4proto_udp4->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l4proto_udp4); ++ ve_nf_conntrack_l4proto_udp4 = NULL; ++ ++ kfree(ve_nf_conntrack_l4proto_udp6); ++ ve_nf_conntrack_l4proto_udp6 = NULL; ++ } ++} ++EXPORT_SYMBOL(nf_ct_proto_udp_sysctl_cleanup); ++ ++int nf_ct_proto_udp_sysctl_init(void) ++{ ++ struct nf_conntrack_l4proto *udp4, *udp6; ++ ++ if (ve_is_super(get_exec_env())) { ++ udp4 = &nf_conntrack_l4proto_udp4; ++ udp6 = &nf_conntrack_l4proto_udp6; ++ goto out; ++ } ++ ++ udp4 = kmemdup(&nf_conntrack_l4proto_udp4, ++ sizeof(struct nf_conntrack_l4proto), GFP_KERNEL); ++ if (udp4 == NULL) ++ goto no_mem_ct4; ++ ++ udp4->ctl_table_users = &ve_udp_sysctl_table_users; ++ udp4->ctl_table_header = &ve_udp_sysctl_header; ++ udp4->ctl_table = clone_sysctl_template(udp_sysctl_table); ++ if (udp4->ctl_table == NULL) ++ goto no_mem_sys; ++ udp4->ctl_table[0].data = &ve_nf_ct_udp_timeout; ++ udp4->ctl_table[1].data = &ve_nf_ct_udp_timeout_stream; ++ ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ udp4->ctl_compat_table_header = ve_udp_compat_sysctl_header; ++ udp4->ctl_compat_table = clone_sysctl_template(udp_compat_sysctl_table); ++ if (udp4->ctl_compat_table == NULL) ++ goto no_mem_compat; ++ udp4->ctl_compat_table[0].data = &ve_nf_ct_udp_timeout; ++ udp4->ctl_compat_table[1].data = &ve_nf_ct_udp_timeout_stream; ++#endif ++ ++ udp6 = kmemdup(&nf_conntrack_l4proto_udp6, ++ sizeof(struct nf_conntrack_l4proto), GFP_KERNEL); ++ if (!udp6) ++ goto no_mem_ct6; ++ ++ udp6->ctl_table_users = &ve_udp_sysctl_table_users; ++ udp6->ctl_table_header = &ve_udp_sysctl_header; ++ udp6->ctl_table = udp4->ctl_table; ++ ++ udp6->ctl_table[0].data = &ve_nf_ct_udp_timeout; ++ udp6->ctl_table[1].data = &ve_nf_ct_udp_timeout_stream; ++out: ++ ve_nf_ct_udp_timeout = nf_ct_udp_timeout; ++ ve_nf_ct_udp_timeout_stream = nf_ct_udp_timeout_stream; ++ ++ ve_nf_conntrack_l4proto_udp4 = udp4; ++ ve_nf_conntrack_l4proto_udp6 = udp6; ++ return 0; ++ ++no_mem_ct6: ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ free_sysctl_clone(udp4->ctl_compat_table); ++no_mem_compat: ++#endif ++ free_sysctl_clone(udp4->ctl_table); ++no_mem_sys: ++ kfree(udp4); ++no_mem_ct4: ++ return -ENOMEM; ++} ++EXPORT_SYMBOL(nf_ct_proto_udp_sysctl_init); ++#endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ +Index: kernel/net/netfilter/nf_conntrack_standalone.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_standalone.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_standalone.c 2008-11-24 15:47:46.000000000 +0100 +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -18,6 +19,7 @@ + #ifdef CONFIG_SYSCTL + #include + #endif ++#include + + #include + #include +@@ -28,6 +30,10 @@ + + MODULE_LICENSE("GPL"); + ++int ip_conntrack_disable_ve0 = 0; ++module_param(ip_conntrack_disable_ve0, int, 0440); ++EXPORT_SYMBOL(ip_conntrack_disable_ve0); ++ + #ifdef CONFIG_PROC_FS + int + print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple, +@@ -62,8 +68,8 @@ + for (st->bucket = 0; + st->bucket < nf_conntrack_htable_size; + st->bucket++) { +- if (!hlist_empty(&nf_conntrack_hash[st->bucket])) +- return nf_conntrack_hash[st->bucket].first; ++ if (!hlist_empty(&ve_nf_conntrack_hash[st->bucket])) ++ return ve_nf_conntrack_hash[st->bucket].first; + } + return NULL; + } +@@ -77,7 +83,7 @@ + while (head == NULL) { + if (++st->bucket >= nf_conntrack_htable_size) + return NULL; +- head = nf_conntrack_hash[st->bucket].first; ++ head = ve_nf_conntrack_hash[st->bucket].first; + } + return head; + } +@@ -244,7 +250,7 @@ + + static int ct_cpu_seq_show(struct seq_file *seq, void *v) + { +- unsigned int nr_conntracks = atomic_read(&nf_conntrack_count); ++ unsigned int nr_conntracks = atomic_read(&ve_nf_conntrack_count); + struct ip_conntrack_stat *st = v; + + if (v == SEQ_START_TOKEN) { +@@ -294,6 +300,55 @@ + .llseek = seq_lseek, + .release = seq_release_private, + }; ++ ++static int nf_conntrack_init_ve_proc(struct ve_struct *ve) ++{ ++ struct net *net = ve->ve_ns->net_ns; ++ struct proc_dir_entry *proc, *proc_stat; ++ int create_proc_net_stat_nf_conntrack = 1; ++ ++ proc = proc_net_fops_create(net, "nf_conntrack", 0440, &ct_file_ops); ++ if (!proc) ++ goto out; ++#ifdef CONFIG_VE_IPTABLES ++ create_proc_net_stat_nf_conntrack = ve_is_super(get_exec_env()); ++#endif ++ if (create_proc_net_stat_nf_conntrack) { ++ proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, ++ net->proc_net_stat); ++ if (!proc_stat) ++ goto out_rm_nf_conntrack_expect; ++ proc_stat->proc_fops = &ct_cpu_seq_fops; ++ proc_stat->owner = THIS_MODULE; ++ } ++ return 0; ++out_rm_nf_conntrack_expect: ++ proc_net_remove(net, "nf_conntrack"); ++out: ++ return -ENOMEM; ++} ++ ++static void nf_conntrack_fini_ve_proc(struct ve_struct *ve) ++{ ++ struct net *net = ve->ve_ns->net_ns; ++ int remove_proc_net_stat_nf_conntrack = 1; ++ ++#ifdef CONFIG_VE_IPTABLES ++ remove_proc_net_stat_nf_conntrack = ve_is_super(get_exec_env()); ++#endif ++ if (remove_proc_net_stat_nf_conntrack) ++ remove_proc_entry("nf_conntrack", net->proc_net_stat); ++ proc_net_remove(net, "nf_conntrack"); ++} ++#else ++static inline int nf_conntrack_init_ve_proc(struct ve_struct *ve) ++{ ++ return 0; ++} ++ ++static inline void nf_conntrack_fini_ve_proc(struct ve_struct *ve) ++{ ++} + #endif /* CONFIG_PROC_FS */ + + /* Sysctl support */ +@@ -395,61 +450,117 @@ + EXPORT_SYMBOL_GPL(nf_ct_log_invalid); + #endif /* CONFIG_SYSCTL */ + +-static int __init nf_conntrack_standalone_init(void) ++#if defined(CONFIG_SYSCTL) && defined(CONFIG_VE_IPTABLES) ++static int nf_conntrack_init_ve_sysctl(struct ve_struct *ve) + { +-#ifdef CONFIG_PROC_FS +- struct proc_dir_entry *proc, *proc_stat; +-#endif +- int ret = 0; ++ if (ve_is_super(ve)) { ++ ve_nf_ct_net_table = nf_ct_net_table; ++ ve_nf_ct_netfilter_table = nf_ct_netfilter_table; ++ ve_nf_ct_sysctl_table = nf_ct_sysctl_table; ++ return 0; ++ } + +- ret = nf_conntrack_init(); +- if (ret < 0) +- return ret; ++ ve_nf_ct_net_table = clone_sysctl_template(nf_ct_net_table); ++ if (ve_nf_ct_net_table == NULL) ++ goto out; ++ ++ ve_nf_ct_netfilter_table = ve_nf_ct_net_table[0].child; ++ ve_nf_ct_netfilter_table[1].data = &ve_nf_conntrack_max; ++ ve_nf_ct_sysctl_table = ve_nf_ct_netfilter_table[0].child; ++ ve_nf_ct_sysctl_table[0].data = &ve_nf_conntrack_max; ++ ve_nf_ct_sysctl_table[1].data = &ve_nf_conntrack_count; ++ ve_nf_ct_sysctl_table[3].data = &ve_nf_conntrack_checksum; ++ ve_nf_ct_sysctl_table[4].data = &ve_nf_ct_log_invalid; ++ ve_nf_ct_sysctl_table[5].data = &ve_nf_ct_expect_max; ++ ++ ve_nf_ct_sysctl_header = register_sysctl_table(ve_nf_ct_net_table); ++ if (!ve_nf_ct_sysctl_header) ++ goto out_unclone; + +-#ifdef CONFIG_PROC_FS +- proc = proc_net_fops_create(&init_net, "nf_conntrack", 0440, &ct_file_ops); +- if (!proc) goto cleanup_init; ++ return 0; + +- proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, init_net.proc_net_stat); +- if (!proc_stat) +- goto cleanup_proc; ++out_unclone: ++ free_sysctl_clone(ve_nf_ct_net_table); ++out: ++ return -ENOMEM; ++} + +- proc_stat->proc_fops = &ct_cpu_seq_fops; +- proc_stat->owner = THIS_MODULE; +-#endif +-#ifdef CONFIG_SYSCTL +- nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table); +- if (nf_ct_sysctl_header == NULL) { +- printk("nf_conntrack: can't register to sysctl.\n"); +- ret = -ENOMEM; +- goto cleanup_proc_stat; ++static void nf_conntrack_fini_ve_sysctl(struct ve_struct *ve) ++{ ++ if (!ve_is_super(ve)) { ++ unregister_sysctl_table(ve_nf_ct_sysctl_header); ++ free_sysctl_clone(ve_nf_ct_net_table); ++ ve_nf_ct_net_table = NULL; ++ ve_nf_ct_sysctl_table = NULL; ++ ve_nf_ct_netfilter_table = NULL; + } +-#endif +- return ret; ++} ++#else ++static inline int nf_conntrack_init_ve_sysctl(struct ve_struct *ve) ++{ ++ return 0; ++} + +-#ifdef CONFIG_SYSCTL +- cleanup_proc_stat: ++static inline void nf_conntrack_fini_ve_sysctl(struct ve_struct *ve) ++{ ++} + #endif +-#ifdef CONFIG_PROC_FS +- remove_proc_entry("nf_conntrack", init_net. proc_net_stat); +- cleanup_proc: +- proc_net_remove(&init_net, "nf_conntrack"); +- cleanup_init: +-#endif /* CNFIG_PROC_FS */ ++ ++int nf_conntrack_init_ve(void) ++{ ++ struct ve_struct *ve = get_exec_env(); ++ int err; ++ ++ err = nf_conntrack_init(); ++ if (err) ++ goto out; ++ ++ ve_nf_conntrack_checksum = nf_conntrack_checksum; ++ ++ err = nf_conntrack_init_ve_sysctl(ve); ++ if (err < 0) ++ goto out_generic; ++ ++ err = nf_conntrack_init_ve_proc(ve); ++ if (err < 0) ++ goto out_sysctl; ++ ++ return 0; ++ ++out_sysctl: ++ nf_conntrack_fini_ve_proc(ve); ++out_generic: ++ nf_conntrack_cleanup(); ++out: ++ return err; ++} ++ ++void nf_conntrack_cleanup_ve(void) ++{ ++ nf_conntrack_fini_ve_proc(get_exec_env()); ++ nf_conntrack_fini_ve_sysctl(get_exec_env()); + nf_conntrack_cleanup(); +- return ret; ++} ++EXPORT_SYMBOL(nf_conntrack_cleanup_ve); ++ ++static int __init nf_conntrack_standalone_init(void) ++{ ++#ifdef CONFIG_VE_IPTABLES ++ KSYMRESOLVE(nf_conntrack_init_ve); ++ KSYMRESOLVE(nf_conntrack_cleanup_ve); ++ KSYMMODRESOLVE(nf_conntrack); ++#endif ++ return nf_conntrack_init_ve(); + } + + static void __exit nf_conntrack_standalone_fini(void) + { +-#ifdef CONFIG_SYSCTL +- unregister_sysctl_table(nf_ct_sysctl_header); ++#ifdef CONFIG_VE_IPTABLES ++ KSYMMODUNRESOLVE(nf_conntrack); ++ KSYMUNRESOLVE(nf_conntrack_init_ve); ++ KSYMUNRESOLVE(nf_conntrack_cleanup_ve); + #endif +-#ifdef CONFIG_PROC_FS +- remove_proc_entry("nf_conntrack", init_net.proc_net_stat); +- proc_net_remove(&init_net, "nf_conntrack"); +-#endif /* CNFIG_PROC_FS */ +- nf_conntrack_cleanup(); ++ nf_conntrack_cleanup_ve(); + } + + module_init(nf_conntrack_standalone_init); +Index: kernel/net/netfilter/nf_queue.c +=================================================================== +--- kernel.orig/net/netfilter/nf_queue.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nf_queue.c 2008-11-24 15:47:46.000000000 +0100 +@@ -236,12 +236,12 @@ + /* Drop reference to owner of hook which queued us. */ + module_put(info->elem->owner); + +- list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) { ++ list_for_each_rcu(i, &ve_nf_hooks[info->pf][info->hook]) { + if (i == elem) + break; + } + +- if (i == &nf_hooks[info->pf][info->hook]) { ++ if (i == &ve_nf_hooks[info->pf][info->hook]) { + /* The module which sent it to userspace is gone. */ + NFDEBUG("%s: module disappeared, dropping packet.\n", + __FUNCTION__); +@@ -262,7 +262,7 @@ + + if (verdict == NF_ACCEPT) { + next_hook: +- verdict = nf_iterate(&nf_hooks[info->pf][info->hook], ++ verdict = nf_iterate(&ve_nf_hooks[info->pf][info->hook], + skb, info->hook, + info->indev, info->outdev, &elem, + info->okfn, INT_MIN); +Index: kernel/net/netfilter/nf_sockopt.c +=================================================================== +--- kernel.orig/net/netfilter/nf_sockopt.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nf_sockopt.c 2008-11-24 15:47:46.000000000 +0100 +@@ -65,8 +65,10 @@ + { + struct nf_sockopt_ops *ops; + +- if (sk->sk_net != &init_net) ++#ifdef CONFIG_VE_IPTABLES ++ if (!get_exec_env()->_nf_hooks) + return ERR_PTR(-ENOPROTOOPT); ++#endif + + if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) + return ERR_PTR(-EINTR); +Index: kernel/net/netfilter/nfnetlink.c +=================================================================== +--- kernel.orig/net/netfilter/nfnetlink.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/nfnetlink.c 2008-11-24 15:47:46.000000000 +0100 +@@ -124,7 +124,7 @@ + const struct nfnetlink_subsystem *ss; + int type, err; + +- if (security_netlink_recv(skb, CAP_NET_ADMIN)) ++ if (security_netlink_recv(skb, CAP_VE_NET_ADMIN)) + return -EPERM; + + /* All the messages must at least contain nfgenmsg */ +Index: kernel/net/netfilter/nfnetlink_queue.c +=================================================================== +--- kernel.orig/net/netfilter/nfnetlink_queue.c 2008-11-24 14:14:50.000000000 +0100 ++++ kernel/net/netfilter/nfnetlink_queue.c 2008-11-24 15:47:46.000000000 +0100 +@@ -728,9 +728,6 @@ + { + struct net_device *dev = ptr; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + /* Drop any packets associated with the downed device */ + if (event == NETDEV_DOWN) + nfqnl_dev_drop(dev->ifindex); +@@ -759,8 +756,7 @@ + struct hlist_head *head = &instance_table[i]; + + hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { +- if ((n->net == &init_net) && +- (n->pid == inst->peer_pid)) ++ if (n->pid == inst->peer_pid) + __instance_destroy(inst); + } + } +Index: kernel/net/netfilter/x_tables.c +=================================================================== +--- kernel.orig/net/netfilter/x_tables.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/x_tables.c 2008-11-24 15:47:46.000000000 +0100 +@@ -26,6 +26,10 @@ + + #include + #include ++#include ++ ++#include ++#include + + + MODULE_LICENSE("GPL"); +@@ -44,6 +48,14 @@ + + static struct xt_af *xt; + ++#ifdef CONFIG_VE_IPTABLES ++/* include ve.h and define get_exec_env */ ++#include ++#define xt_tables(af) (get_exec_env()->_xt_tables[af]) ++#else ++#define xt_tables(af) xt[af].tables ++#endif ++ + #ifdef DEBUG_IP_FIREWALL_USER + #define duprintf(format, args...) printk(format , ## args) + #else +@@ -62,6 +74,46 @@ + [NF_ARP] = "arp", + }; + ++#ifdef CONFIG_BEANCOUNTERS ++static inline struct user_beancounter *xt_table_ub(struct xt_table_info *info) ++{ ++ struct user_beancounter *ub; ++ ++ for (ub = mem_ub(info); ub->parent != NULL; ub = ub->parent); ++ return ub; ++} ++ ++static void uncharge_xtables(struct xt_table_info *info, unsigned long size) ++{ ++ struct user_beancounter *ub; ++ ++ ub = xt_table_ub(info); ++ uncharge_beancounter(ub, UB_NUMXTENT, size); ++} ++ ++static int recharge_xtables(int check_ub, ++ struct xt_table_info *new, struct xt_table_info *old) ++{ ++ struct user_beancounter *ub; ++ long change; ++ ++ ub = xt_table_ub(new); ++ BUG_ON(check_ub && ub != xt_table_ub(old)); ++ ++ change = (long)new->number - (long)old->number; ++ if (change > 0) { ++ if (charge_beancounter(ub, UB_NUMXTENT, change, UB_SOFT)) ++ return -ENOMEM; ++ } else if (change < 0) ++ uncharge_beancounter(ub, UB_NUMXTENT, -change); ++ ++ return 0; ++} ++#else ++#define recharge_xtables(c, new, old) (0) ++#define uncharge_xtables(info, s) do { } while (0) ++#endif /* CONFIG_BEANCOUNTERS */ ++ + /* Registration hooks for targets. */ + int + xt_register_target(struct xt_target *target) +@@ -73,7 +125,7 @@ + return ret; + list_add(&target->list, &xt[af].target); + mutex_unlock(&xt[af].mutex); +- return ret; ++ return 0; + } + EXPORT_SYMBOL(xt_register_target); + +@@ -130,7 +182,7 @@ + list_add(&match->list, &xt[af].match); + mutex_unlock(&xt[af].mutex); + +- return ret; ++ return 0; + } + EXPORT_SYMBOL(xt_register_match); + +@@ -310,23 +362,23 @@ + unsigned short proto, int inv_proto) + { + if (XT_ALIGN(match->matchsize) != size) { +- printk("%s_tables: %s match: invalid size %Zu != %u\n", ++ ve_printk(VE_LOG, "%s_tables: %s match: invalid size %Zu != %u\n", + xt_prefix[family], match->name, + XT_ALIGN(match->matchsize), size); + return -EINVAL; + } + if (match->table && strcmp(match->table, table)) { +- printk("%s_tables: %s match: only valid in %s table, not %s\n", ++ ve_printk(VE_LOG, "%s_tables: %s match: only valid in %s table, not %s\n", + xt_prefix[family], match->name, match->table, table); + return -EINVAL; + } + if (match->hooks && (hook_mask & ~match->hooks) != 0) { +- printk("%s_tables: %s match: bad hook_mask %u/%u\n", ++ ve_printk(VE_LOG, "%s_tables: %s match: bad hook_mask %u/%u\n", + xt_prefix[family], match->name, hook_mask, match->hooks); + return -EINVAL; + } + if (match->proto && (match->proto != proto || inv_proto)) { +- printk("%s_tables: %s match: only valid for protocol %u\n", ++ ve_printk(VE_LOG, "%s_tables: %s match: only valid for protocol %u\n", + xt_prefix[family], match->name, match->proto); + return -EINVAL; + } +@@ -402,24 +454,24 @@ + unsigned short proto, int inv_proto) + { + if (XT_ALIGN(target->targetsize) != size) { +- printk("%s_tables: %s target: invalid size %Zu != %u\n", ++ ve_printk(VE_LOG, "%s_tables: %s target: invalid size %Zu != %u\n", + xt_prefix[family], target->name, + XT_ALIGN(target->targetsize), size); + return -EINVAL; + } + if (target->table && strcmp(target->table, table)) { +- printk("%s_tables: %s target: only valid in %s table, not %s\n", ++ ve_printk(VE_LOG, "%s_tables: %s target: only valid in %s table, not %s\n", + xt_prefix[family], target->name, target->table, table); + return -EINVAL; + } + if (target->hooks && (hook_mask & ~target->hooks) != 0) { +- printk("%s_tables: %s target: bad hook_mask %u/%u\n", ++ ve_printk(VE_LOG, "%s_tables: %s target: bad hook_mask %u/%u\n", + xt_prefix[family], target->name, hook_mask, + target->hooks); + return -EINVAL; + } + if (target->proto && (target->proto != proto || inv_proto)) { +- printk("%s_tables: %s target: only valid for protocol %u\n", ++ ve_printk(VE_LOG, "%s_tables: %s target: only valid for protocol %u\n", + xt_prefix[family], target->name, target->proto); + return -EINVAL; + } +@@ -499,19 +551,19 @@ + if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages) + return NULL; + +- newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL); ++ newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL_UBC); + if (!newinfo) + return NULL; + +- newinfo->size = size; ++ newinfo->alloc_size = newinfo->size = size; + + for_each_possible_cpu(cpu) { + if (size <= PAGE_SIZE) + newinfo->entries[cpu] = kmalloc_node(size, +- GFP_KERNEL, ++ GFP_KERNEL_UBC, + cpu_to_node(cpu)); + else +- newinfo->entries[cpu] = vmalloc_node(size, ++ newinfo->entries[cpu] = ub_vmalloc_node(size, + cpu_to_node(cpu)); + + if (newinfo->entries[cpu] == NULL) { +@@ -529,7 +581,7 @@ + int cpu; + + for_each_possible_cpu(cpu) { +- if (info->size <= PAGE_SIZE) ++ if (info->alloc_size <= PAGE_SIZE) + kfree(info->entries[cpu]); + else + vfree(info->entries[cpu]); +@@ -546,7 +598,7 @@ + if (mutex_lock_interruptible(&xt[af].mutex) != 0) + return ERR_PTR(-EINTR); + +- list_for_each_entry(t, &xt[af].tables, list) ++ list_for_each_entry(t, &xt_tables(af), list) + if (strcmp(t->name, name) == 0 && try_module_get(t->me)) + return t; + mutex_unlock(&xt[af].mutex); +@@ -594,6 +646,13 @@ + return NULL; + } + oldinfo = private; ++ ++ if (recharge_xtables(num_counters != 0, newinfo, oldinfo)) { ++ write_unlock_bh(&table->lock); ++ *error = -ENOMEM; ++ return NULL; ++ } ++ + table->private = newinfo; + newinfo->initial_entries = oldinfo->initial_entries; + write_unlock_bh(&table->lock); +@@ -615,7 +674,7 @@ + return ret; + + /* Don't autoload: we'd eat our tail... */ +- list_for_each_entry(t, &xt[table->af].tables, list) { ++ list_for_each_entry(t, &xt_tables(table->af), list) { + if (strcmp(t->name, table->name) == 0) { + ret = -EEXIST; + goto unlock; +@@ -634,7 +693,7 @@ + /* save number of initial entries */ + private->initial_entries = private->number; + +- list_add(&table->list, &xt[table->af].tables); ++ list_add(&table->list, &xt_tables(table->af)); + + ret = 0; + unlock: +@@ -643,6 +702,39 @@ + } + EXPORT_SYMBOL_GPL(xt_register_table); + ++struct xt_table * virt_xt_register_table(struct xt_table *table, ++ struct xt_table_info *bootstrap, ++ struct xt_table_info *newinfo) ++{ ++ int ret; ++ struct module *mod = table->me; ++ ++ if (!ve_is_super(get_exec_env())) { ++ struct xt_table *tmp; ++ __module_get(mod); ++ ret = -ENOMEM; ++ tmp = kmalloc(sizeof(struct xt_table), GFP_KERNEL_UBC); ++ if (!tmp) ++ goto nomem; ++ memcpy(tmp, table, sizeof(struct xt_table)); ++ table = tmp; ++ } ++ ++ ret = xt_register_table(table, bootstrap, newinfo); ++ if (ret) ++ goto out; ++ ++ return table; ++out: ++ if (!ve_is_super(get_exec_env())) { ++ kfree(table); ++nomem: ++ module_put(mod); ++ } ++ return ERR_PTR(ret); ++} ++EXPORT_SYMBOL_GPL(virt_xt_register_table); ++ + void *xt_unregister_table(struct xt_table *table) + { + struct xt_table_info *private; +@@ -652,10 +744,25 @@ + list_del(&table->list); + mutex_unlock(&xt[table->af].mutex); + ++ uncharge_xtables(private, private->number); ++ + return private; + } + EXPORT_SYMBOL_GPL(xt_unregister_table); + ++void *virt_xt_unregister_table(struct xt_table *table) ++{ ++ void *ret; ++ ++ ret = xt_unregister_table(table); ++ if (!ve_is_super(get_exec_env())) { ++ module_put(table->me); ++ kfree(table); ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(virt_xt_unregister_table); ++ + #ifdef CONFIG_PROC_FS + static struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos) + { +@@ -684,7 +791,7 @@ + list = &xt[af].match; + break; + case TABLE: +- list = &xt[af].tables; ++ list = &xt_tables(af); + break; + default: + list = NULL; +@@ -797,6 +904,7 @@ + return -EINVAL; + + ++ INIT_LIST_HEAD(&xt_tables(af)); + #ifdef CONFIG_PROC_FS + strlcpy(buf, xt_prefix[af], sizeof(buf)); + strlcat(buf, FORMAT_TABLES, sizeof(buf)); +@@ -885,6 +993,6 @@ + kfree(xt); + } + +-module_init(xt_init); ++subsys_initcall(xt_init); + module_exit(xt_fini); + +Index: kernel/net/netfilter/xt_MARK.c +=================================================================== +--- kernel.orig/net/netfilter/xt_MARK.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/xt_MARK.c 2008-11-24 15:47:46.000000000 +0100 +@@ -75,7 +75,7 @@ + const struct xt_mark_target_info *markinfo = targinfo; + + if (markinfo->mark > 0xffffffff) { +- printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n"); ++ ve_printk(VE_LOG, KERN_WARNING "MARK: Only supports 32bit wide mark\n"); + return false; + } + return true; +@@ -93,12 +93,12 @@ + if (markinfo->mode != XT_MARK_SET + && markinfo->mode != XT_MARK_AND + && markinfo->mode != XT_MARK_OR) { +- printk(KERN_WARNING "MARK: unknown mode %u\n", ++ ve_printk(VE_LOG, KERN_WARNING "MARK: unknown mode %u\n", + markinfo->mode); + return false; + } + if (markinfo->mark > 0xffffffff) { +- printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n"); ++ ve_printk(VE_LOG, KERN_WARNING "MARK: Only supports 32bit wide mark\n"); + return false; + } + return true; +Index: kernel/net/netfilter/xt_TCPMSS.c +=================================================================== +--- kernel.orig/net/netfilter/xt_TCPMSS.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/xt_TCPMSS.c 2008-11-24 15:47:46.000000000 +0100 +@@ -63,7 +63,7 @@ + badly. --RR */ + if (tcplen != tcph->doff*4) { + if (net_ratelimit()) +- printk(KERN_ERR "xt_TCPMSS: bad length (%u bytes)\n", ++ ve_printk(VE_LOG, KERN_ERR "xt_TCPMSS: bad length (%u bytes)\n", + skb->len); + return -1; + } +@@ -71,7 +71,7 @@ + if (info->mss == XT_TCPMSS_CLAMP_PMTU) { + if (dst_mtu(skb->dst) <= minlen) { + if (net_ratelimit()) +- printk(KERN_ERR "xt_TCPMSS: " ++ ve_printk(VE_LOG, KERN_ERR "xt_TCPMSS: " + "unknown or invalid path-MTU (%u)\n", + dst_mtu(skb->dst)); + return -1; +@@ -217,13 +217,13 @@ + (hook_mask & ~((1 << NF_IP_FORWARD) | + (1 << NF_IP_LOCAL_OUT) | + (1 << NF_IP_POST_ROUTING))) != 0) { +- printk("xt_TCPMSS: path-MTU clamping only supported in " ++ ve_printk(VE_LOG, "xt_TCPMSS: path-MTU clamping only supported in " + "FORWARD, OUTPUT and POSTROUTING hooks\n"); + return false; + } + if (IPT_MATCH_ITERATE(e, find_syn_match)) + return true; +- printk("xt_TCPMSS: Only works on TCP SYN packets\n"); ++ ve_printk(VE_LOG, "xt_TCPMSS: Only works on TCP SYN packets\n"); + return false; + } + +@@ -242,13 +242,13 @@ + (hook_mask & ~((1 << NF_IP6_FORWARD) | + (1 << NF_IP6_LOCAL_OUT) | + (1 << NF_IP6_POST_ROUTING))) != 0) { +- printk("xt_TCPMSS: path-MTU clamping only supported in " ++ ve_printk(VE_LOG, "xt_TCPMSS: path-MTU clamping only supported in " + "FORWARD, OUTPUT and POSTROUTING hooks\n"); + return false; + } + if (IP6T_MATCH_ITERATE(e, find_syn_match)) + return true; +- printk("xt_TCPMSS: Only works on TCP SYN packets\n"); ++ ve_printk(VE_LOG, "xt_TCPMSS: Only works on TCP SYN packets\n"); + return false; + } + #endif +Index: kernel/net/netfilter/xt_hashlimit.c +=================================================================== +--- kernel.orig/net/netfilter/xt_hashlimit.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/xt_hashlimit.c 2008-11-24 15:47:46.000000000 +0100 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -36,8 +37,13 @@ + MODULE_ALIAS("ip6t_hashlimit"); + + /* need to declare this at the top */ ++#ifdef CONFIG_VE_IPTABLES ++#define hashlimit_procdir4 (get_exec_env()->_xt_hashlimit->hashlimit_procdir4) ++#define hashlimit_procdir6 (get_exec_env()->_xt_hashlimit->hashlimit_procdir6) ++#else + static struct proc_dir_entry *hashlimit_procdir4; + static struct proc_dir_entry *hashlimit_procdir6; ++#endif + static const struct file_operations dl_file_ops; + + /* hash table crap */ +@@ -92,7 +98,11 @@ + + static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */ + static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */ ++#ifdef CONFIG_VE_IPTABLES ++#define hashlimit_htables (get_exec_env()->_xt_hashlimit->hashlimit_htables) ++#else + static HLIST_HEAD(hashlimit_htables); ++#endif + static struct kmem_cache *hashlimit_cachep __read_mostly; + + static inline bool dst_cmp(const struct dsthash_ent *ent, +@@ -440,6 +450,9 @@ + return 0; + } + ++static int init_xt_hashlimit(struct ve_struct *ve); ++static void fini_xt_hashlimit(struct ve_struct *ve); ++ + static bool + hashlimit_match(const struct sk_buff *skb, + const struct net_device *in, +@@ -528,6 +541,9 @@ + if (r->name[sizeof(r->name) - 1] != '\0') + return false; + ++ if (init_xt_hashlimit(get_exec_env())) ++ return 0; ++ + /* This is the best we've got: We cannot release and re-grab lock, + * since checkentry() is called before x_tables.c grabs xt_mutex. + * We also cannot grab the hashtable spinlock, since htable_create will +@@ -553,6 +569,8 @@ + const struct xt_hashlimit_info *r = matchinfo; + + htable_put(r->hinfo); ++ if (!ve_is_super(get_exec_env()) && hlist_empty(&hashlimit_htables)) ++ fini_xt_hashlimit(get_exec_env()); + } + + #ifdef CONFIG_COMPAT +@@ -728,6 +746,59 @@ + .release = seq_release + }; + ++static int init_xt_hashlimit(struct ve_struct *ve) ++{ ++ struct proc_dir_entry *proc_net = ve->ve_ns->net_ns->proc_net; ++ ++#if defined(CONFIG_VE_IPTABLES) ++ if (ve->_xt_hashlimit) ++ return 0; ++ ++ ve->_xt_hashlimit = kzalloc(sizeof(struct ve_xt_hashlimit), GFP_KERNEL); ++ if (!ve->_xt_hashlimit) ++ goto err1; ++#endif ++ INIT_HLIST_HEAD(&hashlimit_htables); ++ ++ hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", proc_net); ++ if (!hashlimit_procdir4) { ++ printk(KERN_ERR "xt_hashlimit: unable to create proc dir " ++ "entry\n"); ++ goto err2; ++ } ++ hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", proc_net); ++ if (!hashlimit_procdir6) { ++ printk(KERN_ERR "xt_hashlimit: unable to create proc dir " ++ "entry\n"); ++ goto err3; ++ } ++ ++ return 0; ++ ++err3: ++ remove_proc_entry("ipt_hashlimit", proc_net); ++err2: ++#if defined(CONFIG_VE_IPTABLES) ++ kfree(ve->_xt_hashlimit); ++ ve->_xt_hashlimit = NULL; ++#endif ++err1: ++ return -ENOMEM; ++} ++ ++static void fini_xt_hashlimit(struct ve_struct *ve) ++{ ++ struct proc_dir_entry *proc_net = ve->ve_ns->net_ns->proc_net; ++ ++ remove_proc_entry("ip6t_hashlimit", proc_net); ++ remove_proc_entry("ipt_hashlimit", proc_net); ++ ++#if defined(CONFIG_VE_IPTABLES) ++ kfree(ve->_xt_hashlimit); ++ ve->_xt_hashlimit = NULL; ++#endif ++} ++ + static int __init xt_hashlimit_init(void) + { + int err; +@@ -744,21 +815,10 @@ + printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n"); + goto err2; + } +- hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", init_net.proc_net); +- if (!hashlimit_procdir4) { +- printk(KERN_ERR "xt_hashlimit: unable to create proc dir " +- "entry\n"); ++ err = init_xt_hashlimit(get_exec_env()); ++ if (err) + goto err3; +- } +- hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", init_net.proc_net); +- if (!hashlimit_procdir6) { +- printk(KERN_ERR "xt_hashlimit: unable to create proc dir " +- "entry\n"); +- goto err4; +- } + return 0; +-err4: +- remove_proc_entry("ipt_hashlimit", init_net.proc_net); + err3: + kmem_cache_destroy(hashlimit_cachep); + err2: +@@ -770,8 +830,7 @@ + + static void __exit xt_hashlimit_fini(void) + { +- remove_proc_entry("ipt_hashlimit", init_net.proc_net); +- remove_proc_entry("ip6t_hashlimit", init_net.proc_net); ++ fini_xt_hashlimit(get_exec_env()); + kmem_cache_destroy(hashlimit_cachep); + xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit)); + } +Index: kernel/net/netfilter/xt_limit.c +=================================================================== +--- kernel.orig/net/netfilter/xt_limit.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netfilter/xt_limit.c 2008-11-24 15:47:46.000000000 +0100 +@@ -111,7 +111,7 @@ + /* Check for overflow. */ + if (r->burst == 0 + || user2credits(r->avg * r->burst) < user2credits(r->avg)) { +- printk("Overflow in xt_limit, try lower: %u/%u\n", ++ ve_printk(VE_LOG, "Overflow in xt_limit, try lower: %u/%u\n", + r->avg, r->burst); + return false; + } +Index: kernel/net/netlink/af_netlink.c +=================================================================== +--- kernel.orig/net/netlink/af_netlink.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netlink/af_netlink.c 2008-11-24 15:47:46.000000000 +0100 +@@ -61,29 +61,14 @@ + #include + #include + #include ++#include ++ ++#include ++#include + + #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) + #define NLGRPLONGS(x) (NLGRPSZ(x)/sizeof(unsigned long)) + +-struct netlink_sock { +- /* struct sock has to be the first member of netlink_sock */ +- struct sock sk; +- u32 pid; +- u32 dst_pid; +- u32 dst_group; +- u32 flags; +- u32 subscriptions; +- u32 ngroups; +- unsigned long *groups; +- unsigned long state; +- wait_queue_head_t wait; +- struct netlink_callback *cb; +- struct mutex *cb_mutex; +- struct mutex cb_def_mutex; +- void (*netlink_rcv)(struct sk_buff *skb); +- struct module *module; +-}; +- + #define NETLINK_KERNEL_SOCKET 0x1 + #define NETLINK_RECV_PKTINFO 0x2 + +@@ -225,7 +210,9 @@ + read_lock(&nl_table_lock); + head = nl_pid_hashfn(hash, pid); + sk_for_each(sk, node, head) { +- if ((sk->sk_net == net) && (nlk_sk(sk)->pid == pid)) { ++ /* VEs should find sockets, created by kernel */ ++ if (nlk_sk(sk)->pid == pid && (netlink_is_kernel(sk) || ++ ve_accessible_strict(sk->owner_env, get_exec_env()))) { + sock_hold(sk); + goto found; + } +@@ -345,7 +332,8 @@ + head = nl_pid_hashfn(hash, pid); + len = 0; + sk_for_each(osk, node, head) { +- if ((osk->sk_net == net) && (nlk_sk(osk)->pid == pid)) ++ if ((osk->sk_net == net) && (nlk_sk(osk)->pid == pid) && ++ ve_accessible_strict(osk->owner_env, get_exec_env())) + break; + len++; + } +@@ -399,6 +387,8 @@ + sk = sk_alloc(net, PF_NETLINK, GFP_KERNEL, &netlink_proto); + if (!sk) + return -ENOMEM; ++ if (ub_other_sock_charge(sk)) ++ goto out_free; + + sock_init_data(sock, sk); + +@@ -414,6 +404,10 @@ + sk->sk_destruct = netlink_sock_destruct; + sk->sk_protocol = protocol; + return 0; ++ ++out_free: ++ sk_free(sk); ++ return -ENOMEM; + } + + static int netlink_create(struct net *net, struct socket *sock, int protocol) +@@ -516,7 +510,7 @@ + struct hlist_head *head; + struct sock *osk; + struct hlist_node *node; +- s32 pid = current->tgid; ++ s32 pid = task_tgid_vnr(current); + int err; + static s32 rover = -4097; + +@@ -527,6 +521,8 @@ + sk_for_each(osk, node, head) { + if ((osk->sk_net != net)) + continue; ++ if (!ve_accessible_strict(osk->owner_env, get_exec_env())) ++ continue; + if (nlk_sk(osk)->pid == pid) { + /* Bind collision, search negative pid values. */ + pid = rover--; +@@ -552,7 +548,7 @@ + static inline int netlink_capable(struct socket *sock, unsigned int flag) + { + return (nl_table[sock->sk->sk_protocol].nl_nonroot & flag) || +- capable(CAP_NET_ADMIN); ++ capable(CAP_VE_NET_ADMIN); + } + + static void +@@ -755,12 +751,20 @@ + long *timeo, struct sock *ssk) + { + struct netlink_sock *nlk; ++ unsigned long chargesize; ++ int no_ubc; + + nlk = nlk_sk(sk); + +- if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || ++ chargesize = skb_charge_fullsize(skb); ++ no_ubc = ub_sock_getwres_other(sk, chargesize); ++ if (no_ubc || atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || + test_bit(0, &nlk->state)) { + DECLARE_WAITQUEUE(wait, current); ++ ++ if (!no_ubc) ++ ub_sock_retwres_other(sk, chargesize, ++ SOCK_MIN_UBCSPACE_CH); + if (!*timeo) { + if (!ssk || netlink_is_kernel(ssk)) + netlink_overrun(sk); +@@ -772,13 +776,20 @@ + __set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&nlk->wait, &wait); + ++ /* this if can't be moved upper because ub_sock_snd_queue_add() ++ * may change task state to TASK_RUNNING */ ++ if (no_ubc) ++ ub_sock_sndqueueadd_other(sk, chargesize); ++ + if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || +- test_bit(0, &nlk->state)) && ++ test_bit(0, &nlk->state) || no_ubc) && + !sock_flag(sk, SOCK_DEAD)) + *timeo = schedule_timeout(*timeo); + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&nlk->wait, &wait); ++ if (no_ubc) ++ ub_sock_sndqueuedel(sk); + sock_put(sk); + + if (signal_pending(current)) { +@@ -788,6 +799,7 @@ + return 1; + } + skb_set_owner_r(skb, sk); ++ ub_skb_set_charge(skb, sk, chargesize, UB_OTHERSOCKBUF); + return 0; + } + +@@ -947,6 +959,9 @@ + if ((sk->sk_net != p->net)) + goto out; + ++ if (!ve_accessible_strict(get_exec_env(), sk->owner_env)) ++ goto out; ++ + if (p->failure) { + netlink_overrun(sk); + goto out; +@@ -1049,6 +1064,9 @@ + !test_bit(p->group - 1, nlk->groups)) + goto out; + ++ if (!ve_accessible_strict(get_exec_env(), sk->owner_env)) ++ goto out; ++ + sk->sk_err = p->code; + sk->sk_error_report(sk); + out: +@@ -1485,6 +1503,10 @@ + skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL); + if (!skb) + goto errout; ++ if (ub_nlrcvbuf_charge(skb, sk) < 0) { ++ kfree_skb(skb); ++ return -EACCES; ++ } + + mutex_lock(nlk->cb_mutex); + +Index: kernel/net/netlink/attr.c +=================================================================== +--- kernel.orig/net/netlink/attr.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netlink/attr.c 2008-11-24 15:47:46.000000000 +0100 +@@ -163,7 +163,7 @@ + } + + if (unlikely(rem > 0)) +- printk(KERN_WARNING "netlink: %d bytes leftover after parsing " ++ ve_printk(VE_LOG, KERN_WARNING "netlink: %d bytes leftover after parsing " + "attributes.\n", rem); + + err = 0; +Index: kernel/net/netlink/genetlink.c +=================================================================== +--- kernel.orig/net/netlink/genetlink.c 2008-11-18 01:19:47.000000000 +0100 ++++ kernel/net/netlink/genetlink.c 2008-11-24 15:47:46.000000000 +0100 +@@ -439,7 +439,7 @@ + return -EOPNOTSUPP; + + if ((ops->flags & GENL_ADMIN_PERM) && +- security_netlink_recv(skb, CAP_NET_ADMIN)) ++ security_netlink_recv(skb, CAP_VE_NET_ADMIN)) + return -EPERM; + + if (nlh->nlmsg_flags & NLM_F_DUMP) { +Index: kernel/net/packet/af_packet.c +=================================================================== +--- kernel.orig/net/packet/af_packet.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/packet/af_packet.c 2008-11-24 15:47:46.000000000 +0100 +@@ -51,6 +51,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -80,6 +81,8 @@ + #include + #include + ++#include ++ + #ifdef CONFIG_INET + #include + #endif +@@ -246,9 +249,6 @@ + struct sock *sk; + struct sockaddr_pkt *spkt; + +- if (dev->nd_net != &init_net) +- goto out; +- + /* + * When we registered the protocol we saved the socket in the data + * field for just this event. +@@ -267,7 +267,8 @@ + * so that this procedure is noop. + */ + +- if (skb->pkt_type == PACKET_LOOPBACK) ++ if (skb->pkt_type == PACKET_LOOPBACK || ++ !ve_accessible(skb->owner_env, sk->owner_env)) + goto out; + + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) +@@ -341,7 +342,7 @@ + */ + + saddr->spkt_device[13] = 0; +- dev = dev_get_by_name(&init_net, saddr->spkt_device); ++ dev = dev_get_by_name(current->nsproxy->net_ns, saddr->spkt_device); + err = -ENODEV; + if (dev == NULL) + goto out_unlock; +@@ -449,15 +450,17 @@ + int skb_len = skb->len; + unsigned int snaplen, res; + +- if (dev->nd_net != &init_net) +- goto drop; +- + if (skb->pkt_type == PACKET_LOOPBACK) + goto drop; + + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!ve_accessible(skb->owner_env, sk->owner_env)) ++ goto drop; ++ ++ skb_orphan(skb); ++ + skb->dev = dev; + + if (dev->header_ops) { +@@ -521,6 +524,9 @@ + if (pskb_trim(skb, snaplen)) + goto drop_n_acct; + ++ if (ub_sockrcvbuf_charge(sk, skb)) ++ goto drop_n_acct; ++ + skb_set_owner_r(skb, sk); + skb->dev = NULL; + dst_release(skb->dst); +@@ -566,15 +572,17 @@ + struct sk_buff *copy_skb = NULL; + struct timeval tv; + +- if (dev->nd_net != &init_net) +- goto drop; +- + if (skb->pkt_type == PACKET_LOOPBACK) + goto drop; + + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!ve_accessible(skb->owner_env, sk->owner_env)) ++ goto drop; ++ ++ skb_orphan(skb); ++ + if (dev->header_ops) { + if (sk->sk_type != SOCK_DGRAM) + skb_push(skb, skb->data - skb_mac_header(skb)); +@@ -621,6 +629,12 @@ + snaplen = 0; + } + ++ if (copy_skb && ++ ub_sockrcvbuf_charge(sk, copy_skb)) { ++ spin_lock(&sk->sk_receive_queue.lock); ++ goto ring_is_full; ++ } ++ + spin_lock(&sk->sk_receive_queue.lock); + h = packet_lookup_frame(po, po->head); + +@@ -732,7 +746,7 @@ + } + + +- dev = dev_get_by_index(&init_net, ifindex); ++ dev = dev_get_by_index(current->nsproxy->net_ns, ifindex); + err = -ENXIO; + if (dev == NULL) + goto out_unlock; +@@ -916,7 +930,7 @@ + return -EINVAL; + strlcpy(name,uaddr->sa_data,sizeof(name)); + +- dev = dev_get_by_name(&init_net, name); ++ dev = dev_get_by_name(current->nsproxy->net_ns, name); + if (dev) { + err = packet_do_bind(sk, dev, pkt_sk(sk)->num); + dev_put(dev); +@@ -943,7 +957,7 @@ + + if (sll->sll_ifindex) { + err = -ENODEV; +- dev = dev_get_by_index(&init_net, sll->sll_ifindex); ++ dev = dev_get_by_index(current->nsproxy->net_ns, sll->sll_ifindex); + if (dev == NULL) + goto out; + } +@@ -972,9 +986,6 @@ + __be16 proto = (__force __be16)protocol; /* weird, but documented */ + int err; + +- if (net != &init_net) +- return -EAFNOSUPPORT; +- + if (!capable(CAP_NET_RAW)) + return -EPERM; + if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW && +@@ -987,6 +998,8 @@ + sk = sk_alloc(net, PF_PACKET, GFP_KERNEL, &packet_proto); + if (sk == NULL) + goto out; ++ if (ub_other_sock_charge(sk)) ++ goto out_free; + + sock->ops = &packet_ops; + if (sock->type == SOCK_PACKET) +@@ -1024,6 +1037,9 @@ + sk_add_node(sk, &packet_sklist); + write_unlock_bh(&packet_sklist_lock); + return(0); ++ ++out_free: ++ sk_free(sk); + out: + return err; + } +@@ -1140,7 +1156,7 @@ + return -EOPNOTSUPP; + + uaddr->sa_family = AF_PACKET; +- dev = dev_get_by_index(&init_net, pkt_sk(sk)->ifindex); ++ dev = dev_get_by_index(current->nsproxy->net_ns, pkt_sk(sk)->ifindex); + if (dev) { + strlcpy(uaddr->sa_data, dev->name, 15); + dev_put(dev); +@@ -1165,7 +1181,7 @@ + sll->sll_family = AF_PACKET; + sll->sll_ifindex = po->ifindex; + sll->sll_protocol = po->num; +- dev = dev_get_by_index(&init_net, po->ifindex); ++ dev = dev_get_by_index(current->nsproxy->net_ns, po->ifindex); + if (dev) { + sll->sll_hatype = dev->type; + sll->sll_halen = dev->addr_len; +@@ -1217,7 +1233,7 @@ + rtnl_lock(); + + err = -ENODEV; +- dev = __dev_get_by_index(&init_net, mreq->mr_ifindex); ++ dev = __dev_get_by_index(current->nsproxy->net_ns, mreq->mr_ifindex); + if (!dev) + goto done; + +@@ -1271,7 +1287,7 @@ + if (--ml->count == 0) { + struct net_device *dev; + *mlp = ml->next; +- dev = dev_get_by_index(&init_net, ml->ifindex); ++ dev = dev_get_by_index(current->nsproxy->net_ns, ml->ifindex); + if (dev) { + packet_dev_mc(dev, ml, -1); + dev_put(dev); +@@ -1299,7 +1315,7 @@ + struct net_device *dev; + + po->mclist = ml->next; +- if ((dev = dev_get_by_index(&init_net, ml->ifindex)) != NULL) { ++ if ((dev = dev_get_by_index(current->nsproxy->net_ns, ml->ifindex)) != NULL) { + packet_dev_mc(dev, ml, -1); + dev_put(dev); + } +@@ -1455,14 +1471,16 @@ + struct sock *sk; + struct hlist_node *node; + struct net_device *dev = data; ++ struct ve_struct *ve; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- ++ ve = get_exec_env(); + read_lock(&packet_sklist_lock); + sk_for_each(sk, node, &packet_sklist) { + struct packet_sock *po = pkt_sk(sk); + ++ if (!ve_accessible_strict(sk->owner_env, ve)) ++ continue; ++ + switch (msg) { + case NETDEV_UNREGISTER: + if (po->mclist) +@@ -1868,6 +1886,8 @@ + struct hlist_node *node; + + sk_for_each(s, node, &packet_sklist) { ++ if (!ve_accessible(s->owner_env, get_exec_env())) ++ continue; + if (!off--) + return s; + } +@@ -1883,9 +1903,14 @@ + static void *packet_seq_next(struct seq_file *seq, void *v, loff_t *pos) + { + ++*pos; +- return (v == SEQ_START_TOKEN) +- ? sk_head(&packet_sklist) +- : sk_next((struct sock*)v) ; ++ do { ++ v = (v == SEQ_START_TOKEN) ++ ? sk_head(&packet_sklist) ++ : sk_next((struct sock*)v); ++ } while (v != NULL && ++ !ve_accessible(((struct sock*)v)->owner_env, ++ get_exec_env())); ++ return v; + } + + static void packet_seq_stop(struct seq_file *seq, void *v) +Index: kernel/net/sched/sch_cbq.c +=================================================================== +--- kernel.orig/net/sched/sch_cbq.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/sched/sch_cbq.c 2008-11-24 15:47:46.000000000 +0100 +@@ -905,8 +905,8 @@ + + if (cl->deficit <= 0) { + q->active[prio] = cl; +- cl = cl->next_alive; + cl->deficit += cl->quantum; ++ cl = cl->next_alive; + } + return skb; + +@@ -1078,17 +1078,19 @@ + + for (h=0; h<16; h++) { + for (cl = q->classes[h]; cl; cl = cl->next) { ++ long mtu; + /* BUGGGG... Beware! This expression suffer of + arithmetic overflows! + */ + if (cl->priority == prio) { +- cl->quantum = (cl->weight*cl->allot*q->nclasses[prio])/ +- q->quanta[prio]; +- } +- if (cl->quantum <= 0 || cl->quantum>32*cl->qdisc->dev->mtu) { +- printk(KERN_WARNING "CBQ: class %08x has bad quantum==%ld, repaired.\n", cl->classid, cl->quantum); +- cl->quantum = cl->qdisc->dev->mtu/2 + 1; ++ cl->quantum = (cl->weight * cl->allot) / ++ (q->quanta[prio] / q->nclasses[prio]); + } ++ mtu = cl->qdisc->dev->mtu; ++ if (cl->quantum <= mtu/2) ++ cl->quantum = mtu/2 + 1; ++ else if (cl->quantum > 32*mtu) ++ cl->quantum = 32*mtu; + } + } + } +Index: kernel/net/sched/sch_generic.c +=================================================================== +--- kernel.orig/net/sched/sch_generic.c 2008-11-24 14:17:55.000000000 +0100 ++++ kernel/net/sched/sch_generic.c 2008-11-24 15:47:46.000000000 +0100 +@@ -135,11 +135,13 @@ + struct Qdisc *q = dev->qdisc; + struct sk_buff *skb; + int ret = NETDEV_TX_BUSY; ++ struct ve_struct *old_ve; + + /* Dequeue packet */ + if (unlikely((skb = dev_dequeue_skb(dev, q)) == NULL)) + return 0; + ++ old_ve = set_exec_env(skb->owner_env); + + /* And release queue */ + spin_unlock(&dev->queue_lock); +@@ -173,6 +175,8 @@ + break; + } + ++ (void)set_exec_env(old_ve); ++ + return ret; + } + +Index: kernel/net/sched/sch_teql.c +=================================================================== +--- kernel.orig/net/sched/sch_teql.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/sched/sch_teql.c 2008-11-24 15:47:46.000000000 +0100 +@@ -174,6 +174,9 @@ + struct teql_master *m = (struct teql_master*)sch->ops; + struct teql_sched_data *q = qdisc_priv(sch); + ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ + if (dev->hard_header_len > m->dev->hard_header_len) + return -EINVAL; + +Index: kernel/net/socket.c +=================================================================== +--- kernel.orig/net/socket.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/socket.c 2008-11-24 15:47:46.000000000 +0100 +@@ -84,6 +84,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -155,15 +156,6 @@ + * divide and look after the messy bits. + */ + +-#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - +- 16 for IP, 16 for IPX, +- 24 for IPv6, +- about 80 for AX.25 +- must be at least one bigger than +- the AF_UNIX size (see net/unix/af_unix.c +- :unix_mkname()). +- */ +- + /** + * move_addr_to_kernel - copy a socket address into kernel space + * @uaddr: Address in user space +@@ -492,6 +484,8 @@ + return sock; + } + ++EXPORT_SYMBOL(sock_alloc); ++ + /* + * In theory you can't get an open on this inode, but /proc provides + * a back door. Remember to keep it shut otherwise you'll let the +@@ -739,7 +733,6 @@ + if (iocb->ki_left == 0) /* Match SYS5 behaviour */ + return 0; + +- + x = alloc_sock_iocb(iocb, &siocb); + if (!x) + return -ENOMEM; +@@ -1076,6 +1069,48 @@ + return 0; + } + ++int vz_security_family_check(int family) ++{ ++#ifdef CONFIG_VE ++ if (ve_is_super(get_exec_env())) ++ return 0; ++ ++ switch (family) { ++ case PF_UNSPEC: ++ case PF_PACKET: ++ case PF_NETLINK: ++ case PF_UNIX: ++ case PF_INET: ++ case PF_INET6: ++ break; ++ default: ++ return -EAFNOSUPPORT; ++ } ++#endif ++ return 0; ++} ++EXPORT_SYMBOL_GPL(vz_security_family_check); ++ ++int vz_security_protocol_check(int protocol) ++{ ++#ifdef CONFIG_VE ++ if (ve_is_super(get_exec_env())) ++ return 0; ++ ++ switch (protocol) { ++ case IPPROTO_IP: ++ case IPPROTO_TCP: ++ case IPPROTO_UDP: ++ case IPPROTO_RAW: ++ break; ++ default: ++ return -EAFNOSUPPORT; ++ } ++#endif ++ return 0; ++} ++EXPORT_SYMBOL_GPL(vz_security_protocol_check); ++ + static int __sock_create(struct net *net, int family, int type, int protocol, + struct socket **res, int kern) + { +@@ -1106,6 +1141,11 @@ + family = PF_PACKET; + } + ++ /* VZ compatibility layer */ ++ err = vz_security_family_check(family); ++ if (err < 0) ++ return err; ++ + err = security_socket_create(family, type, protocol, kern); + if (err) + return err; +@@ -2311,9 +2351,12 @@ + { + mm_segment_t oldfs = get_fs(); + int err; ++ struct ve_struct *old_env; + + set_fs(KERNEL_DS); ++ old_env = set_exec_env(sock->sk->owner_env); + err = sock->ops->ioctl(sock, cmd, arg); ++ (void)set_exec_env(old_env); + set_fs(oldfs); + + return err; +Index: kernel/net/sunrpc/clnt.c +=================================================================== +--- kernel.orig/net/sunrpc/clnt.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/sunrpc/clnt.c 2008-11-24 15:47:46.000000000 +0100 +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -88,6 +89,35 @@ + spin_unlock(&rpc_client_lock); + } + ++/* ++ * Grand abort timeout (stop the client if occures) ++ */ ++int xprt_abort_timeout = RPC_MAX_ABORT_TIMEOUT; ++ ++static int rpc_abort_hard(struct rpc_task *task) ++{ ++ struct rpc_clnt *clnt; ++ clnt = task->tk_client; ++ ++ if (clnt->cl_pr_time == 0) { ++ clnt->cl_pr_time = jiffies; ++ return 0; ++ } ++ if (xprt_abort_timeout == RPC_MAX_ABORT_TIMEOUT) ++ return 0; ++ if (time_before(jiffies, clnt->cl_pr_time + xprt_abort_timeout * HZ)) ++ return 0; ++ ++ clnt->cl_broken = 1; ++ rpc_killall_tasks(clnt); ++ return -ETIMEDOUT; ++} ++ ++static void rpc_abort_clear(struct rpc_task *task) ++{ ++ task->tk_client->cl_pr_time = 0; ++} ++ + static int + rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) + { +@@ -253,6 +283,7 @@ + if (IS_ERR(xprt)) + return (struct rpc_clnt *)xprt; + ++ xprt->owner_env = get_ve(get_exec_env()); + /* + * If the caller chooses not to specify a hostname, whip + * up a string representation of the passed-in address. +@@ -277,13 +308,16 @@ + + clnt = rpc_new_client(xprt, args->servername, args->program, + args->version, args->authflavor); +- if (IS_ERR(clnt)) ++ if (IS_ERR(clnt)) { ++ put_ve(xprt->owner_env); + return clnt; ++ } + + if (!(args->flags & RPC_CLNT_CREATE_NOPING)) { + int err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR); + if (err != 0) { + rpc_shutdown_client(clnt); ++ put_ve(xprt->owner_env); + return ERR_PTR(err); + } + } +@@ -322,6 +356,7 @@ + new->cl_autobind = 0; + INIT_LIST_HEAD(&new->cl_tasks); + spin_lock_init(&new->cl_lock); ++ new->cl_broken = 0; + rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); + new->cl_metrics = rpc_alloc_iostats(clnt); + if (new->cl_metrics == NULL) +@@ -528,6 +563,9 @@ + struct rpc_task *task, *ret; + sigset_t oldset; + ++ if (clnt->cl_broken) ++ return ERR_PTR(-EIO); ++ + task = rpc_new_task(clnt, flags, ops, data); + if (task == NULL) { + rpc_release_calldata(ops, data); +@@ -944,6 +982,7 @@ + + if (task->tk_status >= 0) { + dprint_status(task); ++ rpc_abort_clear(task); + task->tk_status = 0; + task->tk_action = call_connect; + return; +@@ -969,6 +1008,10 @@ + case -ETIMEDOUT: + dprintk("RPC: %5u rpcbind request timed out\n", + task->tk_pid); ++ if (rpc_abort_hard(task)) { ++ status = -EIO; ++ break; ++ } + goto retry_timeout; + case -EPFNOSUPPORT: + /* server doesn't support any rpcbind version we know of */ +@@ -1034,6 +1077,8 @@ + + /* Something failed: remote service port may have changed */ + rpc_force_rebind(clnt); ++ if (rpc_abort_hard(task)) ++ goto exit; + + switch (status) { + case -ENOTCONN: +@@ -1046,6 +1091,7 @@ + task->tk_action = call_timeout; + return; + } ++exit: + rpc_exit(task, -EIO); + } + +@@ -1176,7 +1222,7 @@ + dprintk("RPC: %5u call_timeout (major)\n", task->tk_pid); + task->tk_timeouts++; + +- if (RPC_IS_SOFT(task)) { ++ if (RPC_IS_SOFT(task) || rpc_abort_hard(task)) { + printk(KERN_NOTICE "%s: server %s not responding, timed out\n", + clnt->cl_protname, clnt->cl_server); + rpc_exit(task, -EIO); +@@ -1217,7 +1263,7 @@ + } + + if (task->tk_status < 12) { +- if (!RPC_IS_SOFT(task)) { ++ if (!RPC_IS_SOFT(task) && !rpc_abort_hard(task)) { + task->tk_action = call_bind; + clnt->cl_stats->rpcretrans++; + goto out_retry; +@@ -1228,6 +1274,7 @@ + goto out_retry; + } + ++ rpc_abort_clear(task); + /* + * Ensure that we see all writes made by xprt_complete_rqst() + * before it changed req->rq_received. +@@ -1563,3 +1610,67 @@ + spin_unlock(&rpc_client_lock); + } + #endif ++ ++#ifdef CONFIG_VE ++static int ve_sunrpc_start(void *data) ++{ ++ return 0; ++} ++ ++void ve_sunrpc_stop(void *data) ++{ ++ struct ve_struct *ve = (struct ve_struct *)data; ++ struct rpc_clnt *clnt; ++ struct rpc_task *rovr; ++ ++ dprintk("RPC: killing all tasks for VE %d\n", ve->veid); ++ ++ spin_lock(&rpc_client_lock); ++ list_for_each_entry(clnt, &all_clients, cl_clients) { ++ if (clnt->cl_xprt->owner_env != ve) ++ continue; ++ ++ spin_lock(&clnt->cl_lock); ++ list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) { ++ if (!RPC_IS_ACTIVATED(rovr)) ++ continue; ++ printk(KERN_WARNING "RPC: Killing task %d client %p\n", ++ rovr->tk_pid, clnt); ++ ++ rovr->tk_flags |= RPC_TASK_KILLED; ++ rpc_exit(rovr, -EIO); ++ rpc_wake_up_task(rovr); ++ } ++ schedule_work(&clnt->cl_xprt->task_cleanup); ++ spin_unlock(&clnt->cl_lock); ++ } ++ spin_unlock(&rpc_client_lock); ++ ++ flush_scheduled_work(); ++} ++ ++static struct ve_hook sunrpc_hook = { ++ .init = ve_sunrpc_start, ++ .fini = ve_sunrpc_stop, ++ .owner = THIS_MODULE, ++ .priority = HOOK_PRIO_NET_PRE, ++}; ++ ++void ve_sunrpc_hook_register(void) ++{ ++ ve_hook_register(VE_SS_CHAIN, &sunrpc_hook); ++} ++ ++void ve_sunrpc_hook_unregister(void) ++{ ++ ve_hook_unregister(&sunrpc_hook); ++} ++#else ++void ve_sunrpc_hook_register(void) ++{ ++} ++ ++void ve_sunrpc_hook_unregister(void) ++{ ++} ++#endif +Index: kernel/net/sunrpc/rpc_pipe.c +=================================================================== +--- kernel.orig/net/sunrpc/rpc_pipe.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/sunrpc/rpc_pipe.c 2008-11-24 15:47:46.000000000 +0100 +@@ -839,6 +839,7 @@ + .name = "rpc_pipefs", + .get_sb = rpc_get_sb, + .kill_sb = kill_litter_super, ++ .fs_flags = FS_VIRTUALIZED, + }; + + static void +Index: kernel/net/sunrpc/sched.c +=================================================================== +--- kernel.orig/net/sunrpc/sched.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/sunrpc/sched.c 2008-11-24 15:47:46.000000000 +0100 +@@ -631,7 +631,9 @@ + static void __rpc_execute(struct rpc_task *task) + { + int status = 0; ++ struct ve_struct *env; + ++ env = set_exec_env(task->tk_client->cl_xprt->owner_env); + dprintk("RPC: %5u __rpc_execute flags=0x%x\n", + task->tk_pid, task->tk_flags); + +@@ -681,10 +683,14 @@ + rpc_clear_running(task); + if (RPC_IS_ASYNC(task)) { + /* Careful! we may have raced... */ +- if (RPC_IS_QUEUED(task)) ++ if (RPC_IS_QUEUED(task)) { ++ (void)set_exec_env(env); + return; +- if (rpc_test_and_set_running(task)) ++ } ++ if (rpc_test_and_set_running(task)) { ++ (void)set_exec_env(env); + return; ++ } + continue; + } + +@@ -714,6 +720,7 @@ + task->tk_status); + /* Release all resources associated with the task */ + rpc_release_task(task); ++ (void)set_exec_env(env); + } + + /* +Index: kernel/net/sunrpc/sunrpc_syms.c +=================================================================== +--- kernel.orig/net/sunrpc/sunrpc_syms.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/sunrpc/sunrpc_syms.c 2008-11-24 15:47:46.000000000 +0100 +@@ -132,6 +132,9 @@ + + extern struct cache_detail ip_map_cache, unix_gid_cache; + ++extern void ve_sunrpc_hook_register(void); ++extern void ve_sunrpc_hook_unregister(void); ++ + static int __init + init_sunrpc(void) + { +@@ -153,6 +156,7 @@ + cache_register(&unix_gid_cache); + init_socket_xprt(); + rpcauth_init_module(); ++ ve_sunrpc_hook_register(); + out: + return err; + } +@@ -160,6 +164,7 @@ + static void __exit + cleanup_sunrpc(void) + { ++ ve_sunrpc_hook_unregister(); + rpcauth_remove_module(); + cleanup_socket_xprt(); + unregister_rpc_pipefs(); +Index: kernel/net/sunrpc/svcsock.c +=================================================================== +--- kernel.orig/net/sunrpc/svcsock.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/sunrpc/svcsock.c 2008-11-24 15:47:46.000000000 +0100 +@@ -508,6 +508,9 @@ + unsigned int pglen = xdr->page_len; + unsigned int flags = MSG_MORE; + char buf[RPC_MAX_ADDRBUFLEN]; ++ struct ve_struct *old_env; ++ ++ old_env = set_exec_env(sock->sk->owner_env); + + slen = xdr->len; + +@@ -568,6 +571,8 @@ + rqstp->rq_sock, xdr->head[0].iov_base, xdr->head[0].iov_len, + xdr->len, len, svc_print_addr(rqstp, buf, sizeof(buf))); + ++ (void)set_exec_env(old_env); ++ + return len; + } + +@@ -642,14 +647,18 @@ + svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr, int buflen) + { + struct svc_sock *svsk = rqstp->rq_sock; ++ struct socket *sock = svsk->sk_sock; + struct msghdr msg = { + .msg_flags = MSG_DONTWAIT, + }; + struct sockaddr *sin; + int len; ++ struct ve_struct *old_env; + ++ old_env = set_exec_env(sock->sk->owner_env); + len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen, + msg.msg_flags); ++ (void)set_exec_env(old_env); + + /* sock_recvmsg doesn't fill in the name/namelen, so we must.. + */ +@@ -1795,6 +1804,8 @@ + serv = svsk->sk_server; + sk = svsk->sk_sk; + ++ /* XXX: serialization? */ ++ sk->sk_user_data = NULL; + sk->sk_state_change = svsk->sk_ostate; + sk->sk_data_ready = svsk->sk_odata; + sk->sk_write_space = svsk->sk_owspace; +Index: kernel/net/sunrpc/xprt.c +=================================================================== +--- kernel.orig/net/sunrpc/xprt.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/sunrpc/xprt.c 2008-11-24 15:47:46.000000000 +0100 +@@ -567,10 +567,13 @@ + { + struct rpc_xprt *xprt = + container_of(work, struct rpc_xprt, task_cleanup); ++ struct ve_struct *ve; + ++ ve = set_exec_env(xprt->owner_env); + xprt_disconnect(xprt); + xprt->ops->close(xprt); + xprt_release_write(xprt, NULL); ++ (void)set_exec_env(ve); + } + + /** +@@ -1017,6 +1020,7 @@ + xprt->last_used = jiffies; + xprt->cwnd = RPC_INITCWND; + xprt->bind_index = 0; ++ xprt->owner_env = get_exec_env(); + + rpc_init_wait_queue(&xprt->binding, "xprt_binding"); + rpc_init_wait_queue(&xprt->pending, "xprt_pending"); +Index: kernel/net/sunrpc/xprtsock.c +=================================================================== +--- kernel.orig/net/sunrpc/xprtsock.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/sunrpc/xprtsock.c 2008-11-24 15:47:46.000000000 +0100 +@@ -64,6 +64,8 @@ + static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE; + static unsigned int xprt_min_resvport_limit = RPC_MIN_RESVPORT; + static unsigned int xprt_max_resvport_limit = RPC_MAX_RESVPORT; ++static int xprt_min_abort_timeout = RPC_MIN_ABORT_TIMEOUT; ++static int xprt_max_abort_timeout = RPC_MAX_ABORT_TIMEOUT; + + static struct ctl_table_header *sunrpc_table_header; + +@@ -117,6 +119,16 @@ + .extra2 = &xprt_max_resvport_limit + }, + { ++ .procname = "abort_timeout", ++ .data = &xprt_abort_timeout, ++ .maxlen = sizeof(unsigned int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec_minmax, ++ .strategy = &sysctl_intvec, ++ .extra1 = &xprt_min_abort_timeout, ++ .extra2 = &xprt_max_abort_timeout ++ }, ++ { + .ctl_name = 0, + }, + }; +@@ -735,18 +747,23 @@ + static void xs_close(struct rpc_xprt *xprt) + { + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); +- struct socket *sock = transport->sock; +- struct sock *sk = transport->inet; +- +- if (!sk) +- goto clear_close_wait; ++ struct socket *sock; ++ struct sock *sk; + + dprintk("RPC: xs_close xprt %p\n", xprt); + +- write_lock_bh(&sk->sk_callback_lock); ++ spin_lock_bh(&xprt->transport_lock); ++ if (transport->sock == NULL) { ++ spin_unlock_bh(&xprt->transport_lock); ++ goto clear_close_wait; ++ } ++ sock = transport->sock; ++ sk = transport->inet; + transport->inet = NULL; + transport->sock = NULL; ++ spin_unlock_bh(&xprt->transport_lock); + ++ write_lock_bh(&sk->sk_callback_lock); + sk->sk_user_data = NULL; + sk->sk_data_ready = transport->old_data_ready; + sk->sk_state_change = transport->old_state_change; +@@ -1415,7 +1432,12 @@ + struct rpc_xprt *xprt = &transport->xprt; + struct socket *sock = transport->sock; + int err, status = -EIO; ++ struct ve_struct *ve; + ++ ve = set_exec_env(xprt->owner_env); ++ down_read(&xprt->owner_env->op_sem); ++ if (!xprt->owner_env->is_running) ++ goto out; + if (xprt->shutdown || !xprt_bound(xprt)) + goto out; + +@@ -1441,6 +1463,8 @@ + out: + xprt_wake_pending_tasks(xprt, status); + xprt_clear_connecting(xprt); ++ up_read(&xprt->owner_env->op_sem); ++ (void)set_exec_env(ve); + } + + /** +@@ -1456,7 +1480,12 @@ + struct rpc_xprt *xprt = &transport->xprt; + struct socket *sock = transport->sock; + int err, status = -EIO; ++ struct ve_struct *ve; + ++ ve = set_exec_env(xprt->owner_env); ++ down_read(&xprt->owner_env->op_sem); ++ if (!xprt->owner_env->is_running) ++ goto out; + if (xprt->shutdown || !xprt_bound(xprt)) + goto out; + +@@ -1482,6 +1511,8 @@ + out: + xprt_wake_pending_tasks(xprt, status); + xprt_clear_connecting(xprt); ++ up_read(&xprt->owner_env->op_sem); ++ (void)set_exec_env(ve); + } + + /* +@@ -1560,7 +1591,12 @@ + struct rpc_xprt *xprt = &transport->xprt; + struct socket *sock = transport->sock; + int err, status = -EIO; ++ struct ve_struct *ve; + ++ ve = set_exec_env(xprt->owner_env); ++ down_read(&xprt->owner_env->op_sem); ++ if (!xprt->owner_env->is_running) ++ goto out; + if (xprt->shutdown || !xprt_bound(xprt)) + goto out; + +@@ -1621,7 +1657,12 @@ + struct rpc_xprt *xprt = &transport->xprt; + struct socket *sock = transport->sock; + int err, status = -EIO; ++ struct ve_struct *ve; + ++ ve = set_exec_env(xprt->owner_env); ++ down_read(&xprt->owner_env->op_sem); ++ if (!xprt->owner_env->is_running) ++ goto out; + if (xprt->shutdown || !xprt_bound(xprt)) + goto out; + +@@ -1666,6 +1707,8 @@ + xprt_wake_pending_tasks(xprt, status); + out_clear: + xprt_clear_connecting(xprt); ++ up_read(&xprt->owner_env->op_sem); ++ (void)set_exec_env(ve); + } + + /** +Index: kernel/net/unix/af_unix.c +=================================================================== +--- kernel.orig/net/unix/af_unix.c 2008-11-24 14:08:46.000000000 +0100 ++++ kernel/net/unix/af_unix.c 2008-11-24 15:47:46.000000000 +0100 +@@ -117,6 +117,9 @@ + #include + #include + ++#include ++#include ++ + int sysctl_unix_max_dgram_qlen __read_mostly = 10; + + static struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1]; +@@ -270,7 +273,8 @@ + spin_unlock(&unix_table_lock); + } + +-static struct sock *__unix_find_socket_byname(struct sockaddr_un *sunname, ++static struct sock *__unix_find_socket_byname(struct net *net, ++ struct sockaddr_un *sunname, + int len, int type, unsigned hash) + { + struct sock *s; +@@ -279,6 +283,9 @@ + sk_for_each(s, node, &unix_socket_table[hash ^ type]) { + struct unix_sock *u = unix_sk(s); + ++ if (s->sk_net != net) ++ continue; ++ + if (u->addr->len == len && + !memcmp(u->addr->name, sunname, len)) + goto found; +@@ -288,21 +295,22 @@ + return s; + } + +-static inline struct sock *unix_find_socket_byname(struct sockaddr_un *sunname, ++static inline struct sock *unix_find_socket_byname(struct net *net, ++ struct sockaddr_un *sunname, + int len, int type, + unsigned hash) + { + struct sock *s; + + spin_lock(&unix_table_lock); +- s = __unix_find_socket_byname(sunname, len, type, hash); ++ s = __unix_find_socket_byname(net, sunname, len, type, hash); + if (s) + sock_hold(s); + spin_unlock(&unix_table_lock); + return s; + } + +-static struct sock *unix_find_socket_byinode(struct inode *i) ++static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i) + { + struct sock *s; + struct hlist_node *node; +@@ -312,6 +320,9 @@ + &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) { + struct dentry *dentry = unix_sk(s)->dentry; + ++ if (s->sk_net != net) ++ continue; ++ + if(dentry && dentry->d_inode == i) + { + sock_hold(s); +@@ -606,6 +617,8 @@ + sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_proto); + if (!sk) + goto out; ++ if (ub_other_sock_charge(sk)) ++ goto out_sk_free; + + sock_init_data(sock,sk); + lockdep_set_class(&sk->sk_receive_queue.lock, +@@ -627,13 +640,13 @@ + if (sk == NULL) + atomic_dec(&unix_nr_socks); + return sk; ++out_sk_free: ++ sk_free(sk); ++ return NULL; + } + + static int unix_create(struct net *net, struct socket *sock, int protocol) + { +- if (net != &init_net) +- return -EAFNOSUPPORT; +- + if (protocol && protocol != PF_UNIX) + return -EPROTONOSUPPORT; + +@@ -677,6 +690,7 @@ + static int unix_autobind(struct socket *sock) + { + struct sock *sk = sock->sk; ++ struct net *net = sk->sk_net; + struct unix_sock *u = unix_sk(sk); + static u32 ordernum = 1; + struct unix_address * addr; +@@ -703,7 +717,7 @@ + spin_lock(&unix_table_lock); + ordernum = (ordernum+1)&0xFFFFF; + +- if (__unix_find_socket_byname(addr->name, addr->len, sock->type, ++ if (__unix_find_socket_byname(net, addr->name, addr->len, sock->type, + addr->hash)) { + spin_unlock(&unix_table_lock); + /* Sanity yield. It is unusual case, but yet... */ +@@ -723,7 +737,8 @@ + return err; + } + +-static struct sock *unix_find_other(struct sockaddr_un *sunname, int len, ++static struct sock *unix_find_other(struct net *net, ++ struct sockaddr_un *sunname, int len, + int type, unsigned hash, int *error) + { + struct sock *u; +@@ -741,7 +756,7 @@ + err = -ECONNREFUSED; + if (!S_ISSOCK(nd.dentry->d_inode->i_mode)) + goto put_fail; +- u=unix_find_socket_byinode(nd.dentry->d_inode); ++ u=unix_find_socket_byinode(net, nd.dentry->d_inode); + if (!u) + goto put_fail; + +@@ -757,7 +772,7 @@ + } + } else { + err = -ECONNREFUSED; +- u=unix_find_socket_byname(sunname, len, type, hash); ++ u=unix_find_socket_byname(net, sunname, len, type, hash); + if (u) { + struct dentry *dentry; + dentry = unix_sk(u)->dentry; +@@ -779,6 +794,7 @@ + static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + { + struct sock *sk = sock->sk; ++ struct net *net = sk->sk_net; + struct unix_sock *u = unix_sk(sk); + struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; + struct dentry * dentry = NULL; +@@ -853,7 +869,7 @@ + + if (!sunaddr->sun_path[0]) { + err = -EADDRINUSE; +- if (__unix_find_socket_byname(sunaddr, addr_len, ++ if (__unix_find_socket_byname(net, sunaddr, addr_len, + sk->sk_type, hash)) { + unix_release_addr(addr); + goto out_unlock; +@@ -919,6 +935,7 @@ + int alen, int flags) + { + struct sock *sk = sock->sk; ++ struct net *net = sk->sk_net; + struct sockaddr_un *sunaddr=(struct sockaddr_un*)addr; + struct sock *other; + unsigned hash; +@@ -935,7 +952,7 @@ + goto out; + + restart: +- other=unix_find_other(sunaddr, alen, sock->type, hash, &err); ++ other=unix_find_other(net, sunaddr, alen, sock->type, hash, &err); + if (!other) + goto out; + +@@ -1015,6 +1032,7 @@ + { + struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; + struct sock *sk = sock->sk; ++ struct net *net = sk->sk_net; + struct unix_sock *u = unix_sk(sk), *newu, *otheru; + struct sock *newsk = NULL; + struct sock *other = NULL; +@@ -1023,6 +1041,7 @@ + int st; + int err; + long timeo; ++ unsigned long chargesize; + + err = unix_mkname(sunaddr, addr_len, &hash); + if (err < 0) +@@ -1051,10 +1070,14 @@ + skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL); + if (skb == NULL) + goto out; ++ chargesize = skb_charge_fullsize(skb); ++ if (ub_sock_getwres_other(newsk, chargesize) < 0) ++ goto out; ++ ub_skb_set_charge(skb, newsk, chargesize, UB_OTHERSOCKBUF); + + restart: + /* Find listening sock. */ +- other = unix_find_other(sunaddr, addr_len, sk->sk_type, hash, &err); ++ other = unix_find_other(net, sunaddr, addr_len, sk->sk_type, hash, &err); + if (!other) + goto out; + +@@ -1299,7 +1322,7 @@ + unix_notinflight(scm->fp->fp[i]); + } + +-static void unix_destruct_fds(struct sk_buff *skb) ++void unix_destruct_fds(struct sk_buff *skb) + { + struct scm_cookie scm; + memset(&scm, 0, sizeof(scm)); +@@ -1310,6 +1333,7 @@ + scm_destroy(&scm); + sock_wfree(skb); + } ++EXPORT_SYMBOL_GPL(unix_destruct_fds); + + static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) + { +@@ -1339,6 +1363,7 @@ + { + struct sock_iocb *siocb = kiocb_to_siocb(kiocb); + struct sock *sk = sock->sk; ++ struct net *net = sk->sk_net; + struct unix_sock *u = unix_sk(sk); + struct sockaddr_un *sunaddr=msg->msg_name; + struct sock *other = NULL; +@@ -1405,7 +1430,7 @@ + if (sunaddr == NULL) + goto out_free; + +- other = unix_find_other(sunaddr, namelen, sk->sk_type, ++ other = unix_find_other(net, sunaddr, namelen, sk->sk_type, + hash, &err); + if (other==NULL) + goto out_free; +@@ -1534,6 +1559,16 @@ + + size = len-sent; + ++ if (msg->msg_flags & MSG_DONTWAIT) ++ ub_sock_makewres_other(sk, skb_charge_size(size)); ++ if (sock_bc(sk) != NULL && ++ sock_bc(sk)->poll_reserv >= ++ SOCK_MIN_UBCSPACE && ++ skb_charge_size(size) > ++ sock_bc(sk)->poll_reserv) ++ size = skb_charge_datalen(sock_bc(sk)->poll_reserv); ++ ++ + /* Keep two messages in the pipe so it schedules better */ + if (size > ((sk->sk_sndbuf >> 1) - 64)) + size = (sk->sk_sndbuf >> 1) - 64; +@@ -1545,7 +1580,9 @@ + * Grab a buffer + */ + +- skb=sock_alloc_send_skb(sk,size,msg->msg_flags&MSG_DONTWAIT, &err); ++ ++ skb = sock_alloc_send_skb2(sk, size, SOCK_MIN_UBCSPACE, ++ msg->msg_flags&MSG_DONTWAIT, &err); + + if (skb==NULL) + goto out_err; +@@ -1990,6 +2027,7 @@ + { + struct sock *sk = sock->sk; + unsigned int mask; ++ int no_ub_res; + + poll_wait(file, sk->sk_sleep, wait); + mask = 0; +@@ -2002,6 +2040,10 @@ + if (sk->sk_shutdown & RCV_SHUTDOWN) + mask |= POLLRDHUP; + ++ no_ub_res = ub_sock_makewres_other(sk, SOCK_MIN_UBCSPACE_CH); ++ if (no_ub_res) ++ ub_sock_sndqueueadd_other(sk, SOCK_MIN_UBCSPACE_CH); ++ + /* readable? */ + if (!skb_queue_empty(&sk->sk_receive_queue) || + (sk->sk_shutdown & RCV_SHUTDOWN)) +@@ -2015,7 +2057,7 @@ + * we set writable also when the other side has shut down the + * connection. This prevents stuck sockets. + */ +- if (unix_writable(sk)) ++ if (!no_ub_res && unix_writable(sk)) + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + + return mask; +@@ -2023,12 +2065,18 @@ + + + #ifdef CONFIG_PROC_FS +-static struct sock *unix_seq_idx(int *iter, loff_t pos) ++struct unix_iter_state { ++ struct net *net; ++ int i; ++}; ++static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos) + { + loff_t off = 0; + struct sock *s; + +- for (s = first_unix_socket(iter); s; s = next_unix_socket(iter, s)) { ++ for (s = first_unix_socket(&iter->i); s; s = next_unix_socket(&iter->i, s)) { ++ if (s->sk_net != iter->net) ++ continue; + if (off == pos) + return s; + ++off; +@@ -2039,17 +2087,24 @@ + + static void *unix_seq_start(struct seq_file *seq, loff_t *pos) + { ++ struct unix_iter_state *iter = seq->private; + spin_lock(&unix_table_lock); +- return *pos ? unix_seq_idx(seq->private, *pos - 1) : ((void *) 1); ++ return *pos ? unix_seq_idx(iter, *pos - 1) : ((void *) 1); + } + + static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) + { ++ struct unix_iter_state *iter = seq->private; ++ struct sock *sk = v; + ++*pos; + + if (v == (void *)1) +- return first_unix_socket(seq->private); +- return next_unix_socket(seq->private, v); ++ sk = first_unix_socket(&iter->i); ++ else ++ sk = next_unix_socket(&iter->i, sk); ++ while (sk && (sk->sk_net != iter->net)) ++ sk = next_unix_socket(&iter->i, sk); ++ return sk; + } + + static void unix_seq_stop(struct seq_file *seq, void *v) +@@ -2111,7 +2166,27 @@ + + static int unix_seq_open(struct inode *inode, struct file *file) + { +- return seq_open_private(file, &unix_seq_ops, sizeof(int)); ++ struct unix_iter_state *it; ++ ++ it = __seq_open_private(file, &unix_seq_ops, ++ sizeof(struct unix_iter_state)); ++ if (it == NULL) ++ return -ENOMEM; ++ ++ it->net = get_proc_net(inode); ++ if (it->net == NULL) { ++ seq_release_private(inode, file); ++ return -ENXIO; ++ } ++ return 0; ++} ++ ++static int unix_seq_release(struct inode *inode, struct file *file) ++{ ++ struct seq_file *seq = file->private_data; ++ struct unix_iter_state *iter = seq->private; ++ put_net(iter->net); ++ return seq_release_private(inode, file); + } + + static const struct file_operations unix_seq_fops = { +@@ -2119,7 +2194,7 @@ + .open = unix_seq_open, + .read = seq_read, + .llseek = seq_lseek, +- .release = seq_release_private, ++ .release = unix_seq_release, + }; + + #endif +@@ -2130,6 +2205,30 @@ + .owner = THIS_MODULE, + }; + ++ ++static int unix_net_init(struct net *net) ++{ ++ int error = -ENOMEM; ++ ++#ifdef CONFIG_PROC_FS ++ if (!proc_net_fops_create(net, "unix", 0, &unix_seq_fops)) ++ goto out; ++#endif ++ error = 0; ++out: ++ return 0; ++} ++ ++static void unix_net_exit(struct net *net) ++{ ++ proc_net_remove(net, "unix"); ++} ++ ++static struct pernet_operations unix_net_ops = { ++ .init = unix_net_init, ++ .exit = unix_net_exit, ++}; ++ + static int __init af_unix_init(void) + { + int rc = -1; +@@ -2145,9 +2244,7 @@ + } + + sock_register(&unix_family_ops); +-#ifdef CONFIG_PROC_FS +- proc_net_fops_create(&init_net, "unix", 0, &unix_seq_fops); +-#endif ++ register_pernet_subsys(&unix_net_ops); + unix_sysctl_register(); + out: + return rc; +@@ -2157,8 +2254,8 @@ + { + sock_unregister(PF_UNIX); + unix_sysctl_unregister(); +- proc_net_remove(&init_net, "unix"); + proto_unregister(&unix_proto); ++ unregister_pernet_subsys(&unix_net_ops); + } + + module_init(af_unix_init); +Index: kernel/net/unix/garbage.c +=================================================================== +--- kernel.orig/net/unix/garbage.c 2008-11-24 14:08:46.000000000 +0100 ++++ kernel/net/unix/garbage.c 2008-11-24 15:47:46.000000000 +0100 +@@ -81,6 +81,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -151,6 +152,7 @@ + spin_unlock(&unix_gc_lock); + } + } ++EXPORT_SYMBOL_GPL(unix_notinflight); + + static inline struct sk_buff *sock_queue_head(struct sock *sk) + { +Index: kernel/net/xfrm/xfrm_policy.c +=================================================================== +--- kernel.orig/net/xfrm/xfrm_policy.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/xfrm/xfrm_policy.c 2008-11-24 15:47:46.000000000 +0100 +@@ -1793,7 +1793,7 @@ + void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) + { + while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { +- dst->dev = init_net.loopback_dev; ++ dst->dev = dev->nd_net->loopback_dev; + dev_hold(dst->dev); + dev_put(dev); + } +@@ -2066,9 +2066,6 @@ + { + struct net_device *dev = ptr; + +- if (dev->nd_net != &init_net) +- return NOTIFY_DONE; +- + switch (event) { + case NETDEV_DOWN: + xfrm_flush_bundles(); +Index: kernel/net/xfrm/xfrm_user.c +=================================================================== +--- kernel.orig/net/xfrm/xfrm_user.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/net/xfrm/xfrm_user.c 2008-11-24 15:47:46.000000000 +0100 +@@ -1865,7 +1865,7 @@ + link = &xfrm_dispatch[type]; + + /* All operations require privileges, even GET */ +- if (security_netlink_recv(skb, CAP_NET_ADMIN)) ++ if (security_netlink_recv(skb, CAP_VE_NET_ADMIN)) + return -EPERM; + + if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || +Index: kernel/security/Kconfig +=================================================================== +--- kernel.orig/security/Kconfig 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/security/Kconfig 2008-11-24 15:47:46.000000000 +0100 +@@ -4,6 +4,8 @@ + + menu "Security options" + ++source grsecurity/Kconfig ++ + config KEYS + bool "Enable access key retention support" + help +@@ -41,7 +43,7 @@ + + config SECURITY + bool "Enable different security models" +- depends on SYSFS ++ depends on SYSFS && !VE + help + This allows you to choose different security modules to be + configured into your kernel. +Index: kernel/security/commoncap.c +=================================================================== +--- kernel.orig/security/commoncap.c 2008-11-24 14:18:05.000000000 +0100 ++++ kernel/security/commoncap.c 2008-11-24 15:47:46.000000000 +0100 +@@ -36,8 +36,10 @@ + # define CAP_INIT_BSET CAP_INIT_EFF_SET + #endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ + ++#ifndef CONFIG_VE + kernel_cap_t cap_bset = CAP_INIT_BSET; /* systemwide capability bound */ + EXPORT_SYMBOL(cap_bset); ++#endif + + /* Global security state */ + +@@ -52,6 +54,10 @@ + + int cap_netlink_recv(struct sk_buff *skb, int cap) + { ++ if (likely(cap == CAP_VE_NET_ADMIN) && ++ cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) ++ return 0; ++ + if (!cap_raised(NETLINK_CB(skb).eff_cap, cap)) + return -EPERM; + return 0; +@@ -384,7 +390,7 @@ + return 0; + } else if (!strncmp(name, XATTR_SECURITY_PREFIX, + sizeof(XATTR_SECURITY_PREFIX) - 1) && +- !capable(CAP_SYS_ADMIN)) ++ !capable(CAP_SYS_ADMIN) && !capable(CAP_VE_ADMIN)) + return -EPERM; + return 0; + } +@@ -398,7 +404,7 @@ + return 0; + } else if (!strncmp(name, XATTR_SECURITY_PREFIX, + sizeof(XATTR_SECURITY_PREFIX) - 1) && +- !capable(CAP_SYS_ADMIN)) ++ !capable(CAP_SYS_ADMIN) && !capable(CAP_VE_ADMIN)) + return -EPERM; + return 0; + } +@@ -555,7 +561,7 @@ + + int cap_syslog (int type) + { +- if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN)) ++ if ((type != 3 && type != 10) && !capable(CAP_VE_SYS_ADMIN)) + return -EPERM; + return 0; + } +Index: kernel/security/selinux/Kconfig +=================================================================== +--- kernel.orig/security/selinux/Kconfig 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/security/selinux/Kconfig 2008-11-24 15:47:46.000000000 +0100 +@@ -1,6 +1,6 @@ + config SECURITY_SELINUX + bool "NSA SELinux Support" +- depends on SECURITY_NETWORK && AUDIT && NET && INET ++ depends on SECURITY_NETWORK && AUDIT && NET && INET && !VE + select NETWORK_SECMARK + default n + help +Index: kernel/security/selinux/hooks.c +=================================================================== +--- kernel.orig/security/selinux/hooks.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/security/selinux/hooks.c 2008-11-24 15:47:46.000000000 +0100 +@@ -4664,12 +4664,12 @@ + struct task_struct *g, *t; + struct mm_struct *mm = p->mm; + read_lock(&tasklist_lock); +- do_each_thread(g, t) ++ do_each_thread_ve(g, t) + if (t->mm == mm && t != p) { + read_unlock(&tasklist_lock); + return -EPERM; + } +- while_each_thread(g, t); ++ while_each_thread_ve(g, t); + read_unlock(&tasklist_lock); + } + +Index: kernel/sound/core/info.c +=================================================================== +--- kernel.orig/sound/core/info.c 2008-11-18 01:19:48.000000000 +0100 ++++ kernel/sound/core/info.c 2008-11-24 15:47:46.000000000 +0100 +@@ -545,7 +545,7 @@ + { + struct proc_dir_entry *p; + +- p = snd_create_proc_entry("asound", S_IFDIR | S_IRUGO | S_IXUGO, &proc_root); ++ p = snd_create_proc_entry("asound", S_IFDIR | S_IRUGO | S_IXUGO, NULL); + if (p == NULL) + return -ENOMEM; + snd_proc_root = p; +@@ -595,7 +595,7 @@ + #ifdef CONFIG_SND_OSSEMUL + snd_info_free_entry(snd_oss_root); + #endif +- snd_remove_proc_entry(&proc_root, snd_proc_root); ++ snd_remove_proc_entry(NULL, snd_proc_root); + } + return 0; + } --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0056-IPv6-make-proc-net-ipv6_route-visible-in-VE.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0056-IPv6-make-proc-net-ipv6_route-visible-in-VE.patch @@ -0,0 +1,70 @@ +From 0f8928ff450f8255a36a08ed6f59468f982fa086 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Tue, 1 Apr 2008 17:41:43 +0400 +Subject: [PATCH 55/67] IPv6: make /proc/net/ipv6_route visible in VE + +Show only rules of current VE (this logic already exists and works, entries +enumerated in private ve hash). + +http://bugzilla.openvz.org/show_bug.cgi?id=857 +--- + net/ipv6/route.c | 21 +++++++++++++++++++-- + 1 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 226ae36..74c434b 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -2476,6 +2476,23 @@ ctl_table ipv6_route_table[] = { + + #endif + ++static int ip6_route_net_init(struct net *net) ++{ ++ if (!proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops)) ++ return -ENOMEM; ++ return 0; ++} ++ ++static void ip6_route_net_exit(struct net *net) ++{ ++ proc_net_remove(net, "ipv6_route"); ++} ++ ++static struct pernet_operations ip6_route_net_ops = { ++ .init = ip6_route_net_init, ++ .exit = ip6_route_net_exit, ++}; ++ + void __init ip6_route_init(void) + { + ip6_dst_ops.kmem_cachep = +@@ -2484,7 +2501,6 @@ void __init ip6_route_init(void) + ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; + + fib6_init(); +- proc_net_fops_create(&init_net, "ipv6_route", 0, &ipv6_route_proc_fops); + proc_net_fops_create(&init_net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); + #ifdef CONFIG_XFRM + xfrm6_init(); +@@ -2496,15 +2512,16 @@ void __init ip6_route_init(void) + __rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL); + __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL); + __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL); ++ register_pernet_subsys(&ip6_route_net_ops); + } + + void ip6_route_cleanup(void) + { ++ unregister_pernet_subsys(&ip6_route_net_ops); + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + fib6_rules_cleanup(); + #endif + #ifdef CONFIG_PROC_FS +- proc_net_remove(&init_net, "ipv6_route"); + proc_net_remove(&init_net, "rt6_stats"); + #endif + #ifdef CONFIG_XFRM +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0153-MS-NETNS-Make-netlink_kernel_release-publically-avai.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0153-MS-NETNS-Make-netlink_kernel_release-publically-avai.patch @@ -0,0 +1,118 @@ +From 7ce3d10885bf6c04d225d274bcf4458e56198c23 Mon Sep 17 00:00:00 2001 +From: Denis V. Lunev +Date: Fri, 29 Feb 2008 11:18:32 -0800 +Subject: [PATCH] MS NETNS Make netlink_kernel_release publically available as sk_release_kernel + +mainstream commit edf0208702007ec1f6a36756fdd005f771a4cf17 + +This staff will be needed for non-netlink kernel sockets, which should +also not pin a namespace like tcp_socket and icmp_socket. + +Signed-off-by: Denis V. Lunev +Acked-by: Daniel Lezcano +Signed-off-by: David S. Miller +--- + include/net/sock.h | 13 +++++++++++++ + net/core/sock.c | 18 ++++++++++++++++++ + net/netlink/af_netlink.c | 18 ++---------------- + 3 files changed, 33 insertions(+), 16 deletions(-) + +diff --git a/include/net/sock.h b/include/net/sock.h +index 6e1fb98..fc616d0 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -841,6 +841,7 @@ extern struct sock *sk_alloc(struct net *net, int family, + gfp_t priority, + struct proto *prot); + extern void sk_free(struct sock *sk); ++extern void sk_release_kernel(struct sock *sk); + extern struct sock *sk_clone(const struct sock *sk, + const gfp_t priority); + +@@ -1369,6 +1370,18 @@ static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_e + } + #endif + ++/* ++ * Kernel sockets, f.e. rtnl or icmp_socket, are a part of a namespace. ++ * They should not hold a referrence to a namespace in order to allow ++ * to stop it. ++ * Sockets after sk_change_net should be released using sk_release_kernel ++ */ ++static inline void sk_change_net(struct sock *sk, struct net *net) ++{ ++ put_net(sk->sk_net); ++ sk->sk_net = net; ++} ++ + extern void sock_enable_timestamp(struct sock *sk); + extern int sock_get_timestamp(struct sock *, struct timeval __user *); + extern int sock_get_timestampns(struct sock *, struct timespec __user *); +diff --git a/net/core/sock.c b/net/core/sock.c +index 83933fd..df11bc7 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -978,6 +978,24 @@ void sk_free(struct sock *sk) + sk_prot_free(sk->sk_prot_creator, sk); + } + ++/* ++ * Last sock_put should drop referrence to sk->sk_net. It has already ++ * been dropped in sk_change_net. Taking referrence to stopping namespace ++ * is not an option. ++ * Take referrence to a socket to remove it from hash _alive_ and after that ++ * destroy it in the context of init_net. ++ */ ++void sk_release_kernel(struct sock *sk) ++{ ++ if (sk == NULL || sk->sk_socket == NULL) ++ return; ++ ++ sock_hold(sk); ++ sock_release(sk->sk_socket); ++ sk->sk_net = get_net(&init_net); ++ sock_put(sk); ++} ++ + struct sock *sk_clone(const struct sock *sk, const gfp_t priority) + { + struct sock *newsk; +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 71e31e3..9533610 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1376,8 +1376,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, + goto out_sock_release_nosk; + + sk = sock->sk; +- put_net(sk->sk_net); +- sk->sk_net = net; ++ sk_change_net(sk, net); + + if (groups < 32) + groups = 32; +@@ -1424,20 +1423,7 @@ out_sock_release_nosk: + void + netlink_kernel_release(struct sock *sk) + { +- /* +- * Last sock_put should drop referrence to sk->sk_net. It has already +- * been dropped in netlink_kernel_create. Taking referrence to stopping +- * namespace is not an option. +- * Take referrence to a socket to remove it from netlink lookup table +- * _alive_ and after that destroy it in the context of init_net. +- */ +- if (sk == NULL || sk->sk_socket == NULL) +- return; +- +- sock_hold(sk); +- sock_release(sk->sk_socket); +- sk->sk_net = get_net(&init_net); +- sock_put(sk); ++ sk_release_kernel(sk); + } + EXPORT_SYMBOL(netlink_kernel_release); + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0031-NETFILTER-don-t-free-nf_conntrack_l4proto_generic-i.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0031-NETFILTER-don-t-free-nf_conntrack_l4proto_generic-i.patch @@ -0,0 +1,26 @@ +From d211c0017393748f68f515fd09dcd4786660f5b0 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 14 Mar 2008 18:08:41 +0300 +Subject: [PATCH 31/48] NETFILTER: don't free nf_conntrack_l4proto_generic if VE_IPTABLES=n + +ve_nf_conntrack_l4proto_generic is stubbed to nf_conntrack_l4proto_generic +which is statically allocated array and thus shouldn't be freed. +--- + net/netfilter/nf_conntrack_proto.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c +index 1384c03..bde6914 100644 +--- a/net/netfilter/nf_conntrack_proto.c ++++ b/net/netfilter/nf_conntrack_proto.c +@@ -361,5 +361,7 @@ void nf_conntrack_proto_fini(void) + kfree(ve_nf_ct_protos[i]); + ve_nf_ct_protos[i] = NULL; + } ++#ifdef CONFIG_VE_IPTABLES + kfree(ve_nf_conntrack_l4proto_generic); ++#endif + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0079-remove-spurious-kernel-time-c-warnings.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0079-remove-spurious-kernel-time-c-warnings.patch @@ -0,0 +1,47 @@ +commit 24e7cd454bb9f95fbda41bb4e8f9537747803859 +Author: Alexey Dobriyan +Date: Wed May 28 19:51:14 2008 +0400 + + Remove spurious warnings in kernel/time.c + + E.g. code in clock_t_to_jiffies() divides ~0UL thus assuming that all + "unsigned long" range is valid. Ditto for other functions. Alexey said + these warnings are old debugging stuff. + + http://bugzilla.openvz.org/show_bug.cgi?id=898 + +diff --git a/kernel/time.c b/kernel/time.c +index cb4894a..09d3c45 100644 +--- a/kernel/time.c ++++ b/kernel/time.c +@@ -577,14 +577,12 @@ EXPORT_SYMBOL(jiffies_to_clock_t); + unsigned long clock_t_to_jiffies(unsigned long x) + { + #if (HZ % USER_HZ)==0 +- WARN_ON((long)x < 0); + if (x >= ~0UL / (HZ / USER_HZ)) + return ~0UL; + return x * (HZ / USER_HZ); + #else + u64 jif; + +- WARN_ON((long)x < 0); + /* Don't worry about loss of precision here .. */ + if (x >= ~0UL / HZ * USER_HZ) + return ~0UL; +@@ -599,7 +597,6 @@ EXPORT_SYMBOL(clock_t_to_jiffies); + + u64 jiffies_64_to_clock_t(u64 x) + { +- WARN_ON((s64)x < 0); + #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 + do_div(x, HZ / USER_HZ); + #else +@@ -618,7 +615,6 @@ EXPORT_SYMBOL(jiffies_64_to_clock_t); + + u64 nsec_to_clock_t(u64 x) + { +- WARN_ON((s64)x < 0); + #if (NSEC_PER_SEC % USER_HZ) == 0 + do_div(x, (NSEC_PER_SEC / USER_HZ)); + #elif (USER_HZ % 512) == 0 --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0120-VE-virtualize-binfmt_misc.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0120-VE-virtualize-binfmt_misc.patch @@ -0,0 +1,282 @@ +From 0b522a5e097eb7c46d2c3a47f9ca8f0f70129980 Mon Sep 17 00:00:00 2001 +From: Pavel Emelianov +Date: Fri, 18 Jul 2008 15:25:50 +0400 +Subject: [PATCH 120/131] VE virtualize binfmt_misc + +Nothing special. SUN jdk complains since can't use binfmt. +Not serious and java surely works fine w/o it, but just to +make it and its users happy let's virtualize binfmt_misc. + +1. register ve start-stop hook +2. register per-ve filesystem +3. make status variable per-ve +4. make list of entries per-ve +5. make vfsmnt per-ve (for simple_pin/release_fs) +6. don't forget to genocide the entries on VE stop + +Bug #99599 +--- + fs/binfmt_misc.c | 104 ++++++++++++++++++++++++++++++++++++++++++++-------- + include/linux/ve.h | 8 ++++ + 2 files changed, 96 insertions(+), 16 deletions(-) + +diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c +index b53c7e5..b91aaab 100644 +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include + +@@ -34,8 +35,15 @@ enum { + VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */ + }; + ++#ifdef CONFIG_VE ++#define bm_entries(ve) ((ve)->bm_entries) ++#define bm_enabled(ve) ((ve)->bm_enabled) ++#else + static LIST_HEAD(entries); + static int enabled = 1; ++#define bm_entries(ve) (entries) ++#define bm_enabled(ve) (enabled) ++#endif + + enum {Enabled, Magic}; + #define MISC_FMT_PRESERVE_ARGV0 (1<<31) +@@ -55,21 +63,30 @@ typedef struct { + } Node; + + static DEFINE_RWLOCK(entries_lock); ++#ifdef CONFIG_VE ++#define bm_fs_type(ve) (*(ve)->bm_fs_type) ++#define bm_mnt(ve) ((ve)->bm_mnt) ++#define bm_entry_count(ve) ((ve)->bm_entry_count) ++#else + static struct file_system_type bm_fs_type; + static struct vfsmount *bm_mnt; + static int entry_count; ++#define bm_fs_type(ve) (bm_fs_type) ++#define bm_mnt(ve) (bm_mnt) ++#define bm_entry_count(ve) (bm_entry_count) ++#endif + + /* + * Check if we support the binfmt + * if we do, return the node, else NULL + * locking is done in load_misc_binary + */ +-static Node *check_file(struct linux_binprm *bprm) ++static Node *check_file(struct ve_struct *ve, struct linux_binprm *bprm) + { + char *p = strrchr(bprm->interp, '.'); + struct list_head *l; + +- list_for_each(l, &entries) { ++ list_for_each(l, &bm_entries(ve)) { + Node *e = list_entry(l, Node, list); + char *s; + int j; +@@ -111,14 +128,15 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) + int retval; + int fd_binary = -1; + struct files_struct *files = NULL; ++ struct ve_struct *ve = get_exec_env(); + + retval = -ENOEXEC; +- if (!enabled) ++ if (!bm_enabled(ve)) + goto _ret; + + /* to keep locking time low, we copy the interpreter string */ + read_lock(&entries_lock); +- fmt = check_file(bprm); ++ fmt = check_file(ve, bprm); + if (fmt) + strlcpy(iname, fmt->interpreter, BINPRM_BUF_SIZE); + read_unlock(&entries_lock); +@@ -519,7 +537,7 @@ static void bm_clear_inode(struct inode *inode) + kfree(inode->i_private); + } + +-static void kill_node(Node *e) ++static void kill_node(struct ve_struct *ve, Node *e) + { + struct dentry *dentry; + +@@ -535,7 +553,7 @@ static void kill_node(Node *e) + dentry->d_inode->i_nlink--; + d_drop(dentry); + dput(dentry); +- simple_release_fs(&bm_mnt, &entry_count); ++ simple_release_fs(&bm_mnt(ve), &bm_entry_count(ve)); + } + } + +@@ -589,7 +607,7 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer, + case 3: root = dget(file->f_path.mnt->mnt_sb->s_root); + mutex_lock(&root->d_inode->i_mutex); + +- kill_node(e); ++ kill_node(get_exec_env(), e); + + mutex_unlock(&root->d_inode->i_mutex); + dput(root); +@@ -614,6 +632,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer, + struct dentry *root, *dentry; + struct super_block *sb = file->f_path.mnt->mnt_sb; + int err = 0; ++ struct ve_struct *ve = get_exec_env(); + + e = create_entry(buffer, count); + +@@ -637,7 +656,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer, + if (!inode) + goto out2; + +- err = simple_pin_fs(&bm_fs_type, &bm_mnt, &entry_count); ++ err = simple_pin_fs(&bm_fs_type(ve), &bm_mnt(ve), &bm_entry_count(ve)); + if (err) { + iput(inode); + inode = NULL; +@@ -650,7 +669,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer, + + d_instantiate(dentry, inode); + write_lock(&entries_lock); +- list_add(&e->list, &entries); ++ list_add(&e->list, &bm_entries(ve)); + write_unlock(&entries_lock); + + err = 0; +@@ -676,26 +695,30 @@ static const struct file_operations bm_register_operations = { + static ssize_t + bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) + { +- char *s = enabled ? "enabled" : "disabled"; ++ char *s = bm_enabled(get_exec_env()) ? "enabled" : "disabled"; + + return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s)); + } + ++static void dm_genocide(struct ve_struct *ve) ++{ ++ while (!list_empty(&bm_entries(ve))) ++ kill_node(ve, list_entry(bm_entries(ve).next, Node, list)); ++} ++ + static ssize_t bm_status_write(struct file * file, const char __user * buffer, + size_t count, loff_t *ppos) + { ++ struct ve_struct *ve = get_exec_env(); + int res = parse_command(buffer, count); + struct dentry *root; + + switch (res) { +- case 1: enabled = 0; break; +- case 2: enabled = 1; break; ++ case 1: bm_enabled(ve) = 0; break; ++ case 2: bm_enabled(ve) = 1; break; + case 3: root = dget(file->f_path.mnt->mnt_sb->s_root); + mutex_lock(&root->d_inode->i_mutex); +- +- while (!list_empty(&entries)) +- kill_node(list_entry(entries.next, Node, list)); +- ++ dm_genocide(ve); + mutex_unlock(&root->d_inode->i_mutex); + dput(root); + default: return res; +@@ -746,6 +769,49 @@ static struct file_system_type bm_fs_type = { + .kill_sb = kill_litter_super, + }; + ++#ifdef CONFIG_VE ++static void __ve_binfmt_init(struct ve_struct *ve, struct file_system_type *fs) ++{ ++ ve->bm_fs_type = fs; ++ INIT_LIST_HEAD(&ve->bm_entries); ++ ve->bm_enabled = 1; ++ ve->bm_mnt = NULL; ++ ve->bm_entry_count = 0; ++} ++ ++static int ve_binfmt_init(void *x) ++{ ++ struct ve_struct *ve = x; ++ struct file_system_type *fs_type; ++ int err; ++ ++ err = register_ve_fs_type(ve, &bm_fs_type, &fs_type, NULL); ++ if (err == 0) ++ __ve_binfmt_init(ve, fs_type); ++ ++ return err; ++} ++ ++static void ve_binfmt_fini(void *x) ++{ ++ struct ve_struct *ve = x; ++ ++ /* ++ * no locks since exec_ve is dead and noone will ++ * mess with bm_xxx fields any longer ++ */ ++ dm_genocide(ve); ++ unregister_ve_fs_type(ve->bm_fs_type, NULL); ++} ++ ++static struct ve_hook ve_binfmt_hook = { ++ .init = ve_binfmt_init, ++ .fini = ve_binfmt_fini, ++ .priority = HOOK_PRIO_FS, ++ .owner = THIS_MODULE, ++}; ++#endif ++ + static int __init init_misc_binfmt(void) + { + int err = register_filesystem(&bm_fs_type); +@@ -754,11 +820,17 @@ static int __init init_misc_binfmt(void) + if (err) + unregister_filesystem(&bm_fs_type); + } ++ ++ if (!err) { ++ __ve_binfmt_init(get_ve0(), &bm_fs_type); ++ ve_hook_register(VE_SS_CHAIN, &ve_binfmt_hook); ++ } + return err; + } + + static void __exit exit_misc_binfmt(void) + { ++ ve_hook_unregister(&ve_binfmt_hook); + unregister_binfmt(&misc_format); + unregister_filesystem(&bm_fs_type); + } +diff --git a/include/linux/ve.h b/include/linux/ve.h +index f9cc6aa..88ecd3b 100644 +--- a/include/linux/ve.h ++++ b/include/linux/ve.h +@@ -333,6 +333,14 @@ struct ve_struct { + unsigned long _nlmsvc_timeout; + #endif + ++#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) ++ struct file_system_type *bm_fs_type; ++ struct vfsmount *bm_mnt; ++ int bm_enabled; ++ int bm_entry_count; ++ struct list_head bm_entries; ++#endif ++ + struct nsproxy *ve_ns; + #ifdef CONFIG_GRKERNSEC + struct { +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0021-FAIRSCHED-fix-config-option-name-in-VE-s-code.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0021-FAIRSCHED-fix-config-option-name-in-VE-s-code.patch @@ -0,0 +1,56 @@ +From 68e9756e1255488faedc3f31bf826c423ba37ead Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Wed, 12 Mar 2008 18:14:09 +0300 +Subject: [PATCH 21/48] FAIRSCHED: fix config option name in VE's code + +--- + kernel/ve/vecalls.c | 12 ++++++------ + 1 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/kernel/ve/vecalls.c b/kernel/ve/vecalls.c +index 3f4d3cd..ca4f1e5 100644 +--- a/kernel/ve/vecalls.c ++++ b/kernel/ve/vecalls.c +@@ -64,7 +64,7 @@ + #include + #include + #include +-#ifdef CONFIG_FAIRSCHED ++#ifdef CONFIG_VZ_FAIRSCHED + #include + #endif + +@@ -835,7 +835,7 @@ static void fini_venet(struct ve_struct *ve) + + static int init_ve_sched(struct ve_struct *ve) + { +-#ifdef CONFIG_FAIRSCHED ++#ifdef CONFIG_VZ_FAIRSCHED + int err; + + /* +@@ -864,9 +864,9 @@ static int init_ve_sched(struct ve_struct *ve) + + static void fini_ve_sched(struct ve_struct *ve) + { +-#ifdef CONFIG_FAIRSCHED +- if (task_vsched_id(current) == ve->veid) +- if (sys_fairsched_mvpr(current->pid, fairsched_init_node.id)) ++#ifdef CONFIG_VZ_FAIRSCHED ++ if (task_fairsched_node_id(current) == ve->veid) ++ if (sys_fairsched_mvpr(current->pid, FAIRSCHED_INIT_NODE_ID)) + printk(KERN_WARNING "Can't leave fairsched node %d\n", + ve->veid); + if (sys_fairsched_rmnod(ve->veid)) +@@ -1662,7 +1662,7 @@ static int do_env_enter(struct ve_struct *ve, unsigned int flags) + if (!thread_group_leader(tsk) || !thread_group_empty(tsk)) + goto out_up; + +-#ifdef CONFIG_FAIRSCHED ++#ifdef CONFIG_VZ_FAIRSCHED + err = sys_fairsched_mvpr(current->pid, ve->veid); + if (err) + goto out_up; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0048-Linux-2.6.24-ovz004.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0048-Linux-2.6.24-ovz004.patch @@ -0,0 +1,22 @@ +From 52bfa3b7c6b2eeac15d1b77ab80f350d7c66b5b5 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Tue, 25 Mar 2008 13:09:21 +0300 +Subject: [PATCH 48/48] Linux 2.6.24-ovz004 + +--- + Makefile | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: kernel/Makefile +=================================================================== +--- kernel.orig/Makefile 2008-11-24 15:59:06.000000000 +0100 ++++ kernel/Makefile 2008-11-24 15:59:19.000000000 +0100 +@@ -3,7 +3,7 @@ + SUBLEVEL = 24 + EXTRAVERSION = .6 + NAME = Err Metey! A Heury Beelge-a Ret! +-VZVERSION = ovz003 ++VZVERSION = ovz004 + + # *DOCUMENTATION* + # To see a list of typical targets execute "make help" --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0126-VE-simfs-statfs-on-root.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0126-VE-simfs-statfs-on-root.patch @@ -0,0 +1,32 @@ +From 44e3cef221021d6ad1834575abbb89e7609489f9 Mon Sep 17 00:00:00 2001 +From: Denis V. Lunev +Date: Fri, 18 Jul 2008 15:25:56 +0400 +Subject: [PATCH 126/131] VE simfs statfs on root + simfs: do not use s_root dentry of underlying for statfs + +The real problem is that s_root on the NFS super block is a crap. +Unfortunately, the original dentry (which is asked to be statfs-ed) +is not available at this point. The only visible solution for this +is to use the dentry to which simfs is point to. + +Bug #115232 +--- + fs/simfs.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/fs/simfs.c b/fs/simfs.c +index e5d6bae..b89320c 100644 +--- a/fs/simfs.c ++++ b/fs/simfs.c +@@ -131,7 +131,7 @@ static int sim_statfs(struct super_block *sb, struct kstatfs *buf) + + err = -ENOSYS; + if (lsb && lsb->s_op && lsb->s_op->statfs) +- err = lsb->s_op->statfs(lsb->s_root, &statbuf); ++ err = lsb->s_op->statfs(sb->s_root, &statbuf); + if (err) + return err; + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0134-BRIDGE-correct-checking-for-input-packets.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0134-BRIDGE-correct-checking-for-input-packets.patch @@ -0,0 +1,41 @@ +From 7c163a9667783ebd9ae87941723e31810edf3121 Mon Sep 17 00:00:00 2001 +From: Vitaliy Gusev +Date: Thu, 15 May 2008 18:45:50 +0400 +Subject: [PATCH] BRIDGE correct checking for input packets + +When via_phys_dev flag is set then bridge doesn't have any ip address. +Therefore ip-traffic HW->VE passes only if brigge has the same MAC-address as +real ethernet interface. + +Bug #92737 +--- + net/bridge/br_input.c | 6 +++++- + 1 files changed, 5 insertions(+), 1 deletions(-) + +diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c +index 3377788..ac27655 100644 +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -154,6 +154,8 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb) + } + + switch (p->state) { ++ struct net_device *out; ++ + case BR_STATE_FORWARDING: + rhook = rcu_dereference(br_should_route_hook); + if (rhook != NULL) { +@@ -166,7 +168,9 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb) + if (skb->brmark == BR_ALREADY_SEEN) + return 0; + +- if (!compare_ether_addr(p->br->dev->dev_addr, dest)) ++ out = p->br->via_phys_dev ? p->br->master_dev : p->br->dev; ++ ++ if (out && !compare_ether_addr(p->br->dev->dev_addr, dest)) + skb->pkt_type = PACKET_HOST; + + NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0051-CPT-Add-support-for-netdevice-hardware-addresses.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0051-CPT-Add-support-for-netdevice-hardware-addresses.patch @@ -0,0 +1,223 @@ +From bbd642a14f3281af16b0280afcf23c583531bd8b Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Tue, 25 Mar 2008 18:50:22 +0300 +Subject: [PATCH 50/67] CPT: Add support for netdevice hardware addresses + +In current implementation netdevice hardware (MAC) address is not saved, so +devices like tap will have different MAC address after restore. This will +lead to creation of new local IPv6 address based on MAC address. + +This patch allows to save/restore hardware addresses on all netdevices. + +Also this patch changes cpt image version. +This is done because of following code we have now: + + err = rst_get_object(CPT_OBJ_NET_DEVICE, sec, &di, ctx); + if (err) + return err; + + if (di.cpt_next > sizeof(di)) { + err = rst_restore_tuntap(sec, &di, ctx); + if (err) + return err; + } + +It was supposed that we will have only netdevice image or netdevice image and +tuntap image. + +With new code it will be possible to have netdevice and hwaddr image, so old +kernel will consider hwaddr image as tuntap image. And will return -EINVAL +while reading this image. +So, migration to old kernel is prohibited, just to be sure that sensible error +will be returned in this case. + +Bug #96040 +--- + include/linux/cpt_image.h | 12 +++++++++++ + kernel/cpt/cpt_net.c | 14 ++++++++++++ + kernel/cpt/rst_net.c | 49 +++++++++++++++++++++++++++++++++++++++++--- + 3 files changed, 71 insertions(+), 4 deletions(-) + +diff --git a/include/linux/cpt_image.h b/include/linux/cpt_image.h +index 731346c..20f23b4 100644 +--- a/include/linux/cpt_image.h ++++ b/include/linux/cpt_image.h +@@ -96,6 +96,7 @@ enum _cpt_object_type + CPT_OBJ_INOTIFY_EVENT, + CPT_OBJ_TASK_AUX, + CPT_OBJ_NET_TUNTAP, ++ CPT_OBJ_NET_HWADDR, + }; + + #define CPT_ALIGN(n) (((n)+7)&~7) +@@ -109,8 +110,10 @@ struct cpt_major_hdr + #define CPT_VERSION_8 0 + #define CPT_VERSION_9 0x100 + #define CPT_VERSION_9_1 0x101 ++#define CPT_VERSION_9_2 0x102 + #define CPT_VERSION_16 0x200 + #define CPT_VERSION_18 0x300 ++#define CPT_VERSION_18_1 0x301 + #define CPT_VERSION_20 0x400 + #define CPT_VERSION_24 0x500 + __u16 cpt_os_arch; /* Architecture */ +@@ -1501,6 +1504,15 @@ struct cpt_tuntap_image { + __u32 cpt_net_filter[2]; + } __attribute__ ((aligned (8))); + ++struct cpt_hwaddr_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u8 cpt_dev_addr[32]; ++} __attribute__ ((aligned (8))); ++ + struct cpt_ifaddr_image { + __u64 cpt_next; + __u32 cpt_object; +diff --git a/kernel/cpt/cpt_net.c b/kernel/cpt/cpt_net.c +index e3a73f4..4e3dcec 100644 +--- a/kernel/cpt/cpt_net.c ++++ b/kernel/cpt/cpt_net.c +@@ -86,6 +86,7 @@ int cpt_dump_link(struct cpt_context * ctx) + cpt_open_section(ctx, CPT_SECT_NET_DEVICE); + for_each_netdev(net, dev) { + struct cpt_netdev_image v; ++ struct cpt_hwaddr_image hw; + loff_t saved_obj; + + cpt_open_object(NULL, ctx); +@@ -101,7 +102,20 @@ int cpt_dump_link(struct cpt_context * ctx) + ctx->write(&v, sizeof(v), ctx); + + cpt_push_object(&saved_obj, ctx); ++ + cpt_dump_tuntap(dev, ctx); ++ ++ /* Dump hardware address */ ++ cpt_open_object(NULL, ctx); ++ hw.cpt_next = CPT_NULL; ++ hw.cpt_object = CPT_OBJ_NET_HWADDR; ++ hw.cpt_hdrlen = sizeof(hw); ++ hw.cpt_content = CPT_CONTENT_VOID; ++ BUG_ON(sizeof(hw.cpt_dev_addr) != sizeof(dev->dev_addr)); ++ memcpy(hw.cpt_dev_addr, dev->dev_addr, sizeof(hw.cpt_dev_addr)); ++ ctx->write(&hw, sizeof(hw), ctx); ++ cpt_close_object(ctx); ++ + cpt_pop_object(&saved_obj, ctx); + + cpt_close_object(ctx); +diff --git a/kernel/cpt/rst_net.c b/kernel/cpt/rst_net.c +index 934da78..2703800 100644 +--- a/kernel/cpt/rst_net.c ++++ b/kernel/cpt/rst_net.c +@@ -301,7 +301,7 @@ int rst_resume_network(struct cpt_context *ctx) + } + + /* We do not restore skb queue, just reinit it */ +-static int rst_restore_tuntap(loff_t pos, struct cpt_netdev_image *di, ++static int rst_restore_tuntap(loff_t start, struct cpt_netdev_image *di, + struct cpt_context *ctx) + { + int err = -ENODEV; +@@ -310,12 +310,14 @@ static int rst_restore_tuntap(loff_t pos, struct cpt_netdev_image *di, + struct net_device *dev; + struct file *bind_file = NULL; + struct tun_struct *tun; ++ loff_t pos; + +- pos += di->cpt_hdrlen; ++ pos = start + di->cpt_hdrlen; + err = rst_get_object(CPT_OBJ_NET_TUNTAP, pos, &ti, ctx); + if (err) + return err; + ++ pos += ti.cpt_next; + if (ti.cpt_bindfile) { + bind_file = rst_file(ti.cpt_bindfile, -1, ctx); + if (IS_ERR(bind_file)) { +@@ -353,6 +355,17 @@ static int rst_restore_tuntap(loff_t pos, struct cpt_netdev_image *di, + eprintk_ctx("failed to register tun/tap net device\n"); + goto out; + } ++ if (pos < start + di->cpt_next) { ++ struct cpt_hwaddr_image hw; ++ /* Restore hardware address */ ++ err = rst_get_object(CPT_OBJ_NET_HWADDR, pos, ++ &hw, ctx); ++ if (err) ++ goto out; ++ BUG_ON(sizeof(hw.cpt_dev_addr) != sizeof(dev->dev_addr)); ++ memcpy(dev->dev_addr, hw.cpt_dev_addr, ++ sizeof(hw.cpt_dev_addr)); ++ } + list_add(&tun->list, &tun_dev_list); + + bind_file->private_data = tun; +@@ -389,16 +402,28 @@ int rst_restore_netdev(struct cpt_context *ctx) + endsec = sec + h.cpt_next; + sec += h.cpt_hdrlen; + while (sec < endsec) { +- int err; ++ loff_t pos; + struct net_device *dev_new; + err = rst_get_object(CPT_OBJ_NET_DEVICE, sec, &di, ctx); + if (err) + return err; + ++ pos = sec + di.cpt_hdrlen; + if (di.cpt_next > sizeof(di)) { +- err = rst_restore_tuntap(sec, &di, ctx); ++ struct cpt_object_hdr hdr; ++ err = ctx->pread(&hdr, sizeof(struct cpt_object_hdr), ++ ctx, sec + di.cpt_hdrlen); + if (err) + return err; ++ if (hdr.cpt_object == CPT_OBJ_NET_TUNTAP) { ++ err = rst_restore_tuntap(sec, &di, ctx); ++ if (err) { ++ eprintk_ctx("restore tuntap %s: %d\n", ++ di.cpt_name, err); ++ return err; ++ } ++ pos += hdr.cpt_next; ++ } + } + + rtnl_lock(); +@@ -437,6 +462,19 @@ int rst_restore_netdev(struct cpt_context *ctx) + if (err) + eprintk_ctx("dev_change_flags err: %d\n", err); + } ++ if (pos < sec + di.cpt_next) { ++ struct cpt_hwaddr_image hw; ++ /* Restore hardware address */ ++ err = rst_get_object(CPT_OBJ_NET_HWADDR, pos, ++ &hw, ctx); ++ if (err) ++ goto out; ++ BUG_ON(sizeof(hw.cpt_dev_addr) != ++ sizeof(dev->dev_addr)); ++ memcpy(dev->dev_addr, hw.cpt_dev_addr, ++ sizeof(hw.cpt_dev_addr)); ++ pos += hw.cpt_next; ++ } + } else { + eprintk_ctx("unknown interface 2 %s\n", di.cpt_name); + } +@@ -444,6 +482,9 @@ int rst_restore_netdev(struct cpt_context *ctx) + sec += di.cpt_next; + } + return 0; ++out: ++ rtnl_unlock(); ++ return err; + } + + static int dumpfn(void *arg) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0095-UBC-tcpsndbuf-endless-loop.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0095-UBC-tcpsndbuf-endless-loop.patch @@ -0,0 +1,108 @@ +From 482427ea920bb8fbce111ce419f44e9182d048e6 Mon Sep 17 00:00:00 2001 +From: Denis Lunev +Date: Mon, 30 Jun 2008 13:48:49 +0400 +Subject: [PATCH 095/103] UBC tcpsndbuf endless loop + +The loop in __sk_stream_wait_memory when tcp_sendmsg asks to wait for +TCPSNDBUF space is endless when the timeout is not specified. The only way +out is to queue a signal for that process. + +Lets return a status flag from ub_sock_snd_queue_add that UB space is +available. This is enough to make a correct decision to leave the cycle. + +Bug #112103 +--- + include/bc/net.h | 10 +++++----- + kernel/bc/net.c | 7 ++++--- + net/core/stream.c | 4 ++-- + 3 files changed, 11 insertions(+), 10 deletions(-) + +diff --git a/include/bc/net.h b/include/bc/net.h +index 5330a88..5f82aff 100644 +--- a/include/bc/net.h ++++ b/include/bc/net.h +@@ -50,7 +50,7 @@ UB_DECLARE_VOID_FUNC(ub_sock_uncharge(struct sock *sk)) + /* management of queue for send space */ + UB_DECLARE_FUNC(long, ub_sock_wait_for_space(struct sock *sk, long timeo, + unsigned long size)) +-UB_DECLARE_VOID_FUNC(ub_sock_snd_queue_add(struct sock *sk, int resource, ++UB_DECLARE_FUNC(int, ub_sock_snd_queue_add(struct sock *sk, int resource, + unsigned long size)) + UB_DECLARE_VOID_FUNC(ub_sock_sndqueuedel(struct sock *sk)) + +@@ -105,14 +105,14 @@ static inline void ub_sock_retwres_tcp(struct sock *sk, unsigned long size, + ub_sock_ret_wreserv(sk, UB_TCPSNDBUF, size, ressize); + } + +-static inline void ub_sock_sndqueueadd_other(struct sock *sk, unsigned long sz) ++static inline int ub_sock_sndqueueadd_other(struct sock *sk, unsigned long sz) + { +- ub_sock_snd_queue_add(sk, UB_OTHERSOCKBUF, sz); ++ return ub_sock_snd_queue_add(sk, UB_OTHERSOCKBUF, sz); + } + +-static inline void ub_sock_sndqueueadd_tcp(struct sock *sk, unsigned long sz) ++static inline int ub_sock_sndqueueadd_tcp(struct sock *sk, unsigned long sz) + { +- ub_sock_snd_queue_add(sk, UB_TCPSNDBUF, sz); ++ return ub_sock_snd_queue_add(sk, UB_TCPSNDBUF, sz); + } + + static inline int ub_tcpsndbuf_charge(struct sock *sk, +diff --git a/kernel/bc/net.c b/kernel/bc/net.c +index 4db1f9b..ad88b86 100644 +--- a/kernel/bc/net.c ++++ b/kernel/bc/net.c +@@ -226,7 +226,7 @@ static void ub_tcp_snd_wakeup(struct user_beancounter *ub) + } + } + +-void ub_sock_snd_queue_add(struct sock *sk, int res, unsigned long size) ++int ub_sock_snd_queue_add(struct sock *sk, int res, unsigned long size) + { + unsigned long flags; + struct sock_beancounter *skbc; +@@ -234,7 +234,7 @@ void ub_sock_snd_queue_add(struct sock *sk, int res, unsigned long size) + unsigned long added_reserv; + + if (!sock_has_ubc(sk)) +- return; ++ return 0; + + skbc = sock_bc(sk); + ub = top_beancounter(skbc->ub); +@@ -253,7 +253,7 @@ void ub_sock_snd_queue_add(struct sock *sk, int res, unsigned long size) + spin_unlock_irqrestore(&ub->ub_lock, flags); + if (added_reserv) + charge_beancounter_notop(skbc->ub, res, added_reserv); +- return; ++ return 0; + } + + ub_debug(UBD_NET_SLEEP, "Adding sk to queue\n"); +@@ -278,6 +278,7 @@ void ub_sock_snd_queue_add(struct sock *sk, int res, unsigned long size) + } + out: + spin_unlock_irqrestore(&ub->ub_lock, flags); ++ return -ENOMEM; + } + + EXPORT_SYMBOL(ub_sock_snd_queue_add); +diff --git a/net/core/stream.c b/net/core/stream.c +index 08a185d..bd35f57 100644 +--- a/net/core/stream.c ++++ b/net/core/stream.c +@@ -139,8 +139,8 @@ int __sk_stream_wait_memory(struct sock *sk, long *timeo_p, + if (amount == 0) { + if (sk_stream_memory_free(sk) && !vm_wait) + break; +- } else +- ub_sock_sndqueueadd_tcp(sk, amount); ++ } else if (!ub_sock_sndqueueadd_tcp(sk, amount)) ++ break; + + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + sk->sk_write_pending++; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0145-VE-add-missed-semaphore-up-and-set-exec-env.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0145-VE-add-missed-semaphore-up-and-set-exec-env.patch @@ -0,0 +1,26 @@ +From 2e272c2b5966c134d7b70cfb555867c6d8623a5f Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Tue, 9 Sep 2008 13:42:31 +0400 +Subject: [PATCH] VE add missed semaphore up and set exec env + +NFS connect over TCP-IPv4 block VE stop process. +--- + net/sunrpc/xprtsock.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c +index f58f1ac..f6f3db8 100644 +--- a/net/sunrpc/xprtsock.c ++++ b/net/sunrpc/xprtsock.c +@@ -1642,6 +1642,8 @@ out: + xprt_wake_pending_tasks(xprt, status); + out_clear: + xprt_clear_connecting(xprt); ++ up_read(&xprt->owner_env->op_sem); ++ (void)set_exec_env(ve); + } + + /** +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0147-MS-NETNS-memory-leak-on-network-namespace-stop.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0147-MS-NETNS-memory-leak-on-network-namespace-stop.patch @@ -0,0 +1,34 @@ +From 36b7ca98361288413004d525891f9a821a2b8709 Mon Sep 17 00:00:00 2001 +From: Denis V. Lunev +Date: Fri, 6 Jun 2008 21:10:14 +0400 +Subject: [PATCH] MS NETNS memory leak on network namespace stop + +mainline commit 4f84d82f7a623f8641af2574425c329431ff158f + +Network namespace allocates 2 kernel netlink sockets, fibnl & +rtnl. These sockets should be disposed properly, i.e. by +sock_release. Plain sock_put is not enough. + +Signed-off-by: Denis V. Lunev +Tested-by: Alexey Dobriyan +Signed-off-by: David S. Miller +--- + net/core/rtnetlink.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c +index 9cb91f5..e025b0c 100644 +--- a/net/core/rtnetlink.c ++++ b/net/core/rtnetlink.c +@@ -1386,7 +1386,7 @@ static void rtnetlink_net_exit(struct net *net) + * free. + */ + sk->sk_net = get_net(&init_net); +- sock_put(sk); ++ sock_release(net->rtnl->sk_socket); + net->rtnl = NULL; + } + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0122-VE-NFS-compare-super.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0122-VE-NFS-compare-super.patch @@ -0,0 +1,28 @@ +From 3f71b17bd0dcd9ed2fb3472beef576f8e3c26224 Mon Sep 17 00:00:00 2001 +From: Denis Lunev +Date: Fri, 18 Jul 2008 15:25:51 +0400 +Subject: [PATCH 122/131] VE NFS compare super + +NFS super blocks in different VEs should be different +Teach nfs_compare_super to this. +--- + fs/nfs/super.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/fs/nfs/super.c b/fs/nfs/super.c +index 290bb86..fcab4a3 100644 +--- a/fs/nfs/super.c ++++ b/fs/nfs/super.c +@@ -1387,6 +1387,9 @@ static int nfs_compare_super(struct super_block *sb, void *data) + struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); + int mntflags = sb_mntdata->mntflags; + ++ if (!ve_accessible_strict(old->client->cl_xprt->owner_env, ++ get_exec_env())) ++ return 0; + if (memcmp(&old->nfs_client->cl_addr, + &server->nfs_client->cl_addr, + sizeof(old->nfs_client->cl_addr)) != 0) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0037-Add-pid-hide-logic-on-VE-creation.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0037-Add-pid-hide-logic-on-VE-creation.patch @@ -0,0 +1,29 @@ +From 5f6872e2893945c53efed0413e1948f8f895f0c9 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Mon, 17 Mar 2008 15:41:27 +0300 +Subject: [PATCH 37/48] Add pid hide logic on VE creation + +Dup the logic from CLONE_NEWPID codepath. init and entered processes remain +visible in all pidns's. +--- + kernel/ve/vecalls.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/kernel/ve/vecalls.c b/kernel/ve/vecalls.c +index ca4f1e5..4bb5d48 100644 +--- a/kernel/ve/vecalls.c ++++ b/kernel/ve/vecalls.c +@@ -896,6 +896,10 @@ static inline int init_ve_namespaces(struct ve_struct *ve, + ve->ve_ns = get_nsproxy(tsk->nsproxy); + memcpy(ve->ve_ns->uts_ns->name.release, virt_utsname.release, + sizeof(virt_utsname.release)); ++ ++ if (cur->pid_ns->flags & PID_NS_HIDE_CHILD) ++ ve->ve_ns->pid_ns->flags |= PID_NS_HIDDEN; ++ + *old = cur; + return 0; + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0121-VE-nf-netlink-dont-oops.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0121-VE-nf-netlink-dont-oops.patch @@ -0,0 +1,102 @@ +From 561bc6b6de71418dd0be8d872b1272c031cba6cc Mon Sep 17 00:00:00 2001 +From: Pavel Emelianov +Date: Fri, 18 Jul 2008 15:25:51 +0400 +Subject: [PATCH 121/131] VE nf netlink dont oops + +Fix oops in netlink conntrack module +If we load conntrack modules after ve start one pointer on +ve_struct is NULL and accessing it causes an oops. + +This is handled in most of the places, but the netlink +interface. Fix this one as well. + +http://bugzilla.openvz.org/show_bug.cgi?id=788 +--- + include/net/netfilter/nf_conntrack_core.h | 2 ++ + net/netfilter/nf_conntrack_netlink.c | 18 ++++++++++++++++++ + 2 files changed, 20 insertions(+), 0 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h +index cab835c..3e4ce33 100644 +--- a/include/net/netfilter/nf_conntrack_core.h ++++ b/include/net/netfilter/nf_conntrack_core.h +@@ -64,10 +64,12 @@ extern int __nf_conntrack_confirm(struct sk_buff *skb); + + #if defined(CONFIG_VE_IPTABLES) + #include ++#define ve_nf_conntrack_initialized() (get_exec_env()->_nf_conntrack != NULL) + #define ve_nf_conntrack_hash (get_exec_env()->_nf_conntrack->_nf_conntrack_hash) + #define ve_nf_conntrack_vmalloc (get_exec_env()->_nf_conntrack->_nf_conntrack_vmalloc) + #define ve_unconfirmed (get_exec_env()->_nf_conntrack->_unconfirmed) + #else ++#define ve_nf_conntrack_initialized() 1 + #define ve_nf_conntrack_hash nf_conntrack_hash + #define ve_nf_conntrack_vmalloc nf_conntrack_vmalloc + #define ve_unconfirmed unconfirmed +diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c +index 41b16c6..044f838 100644 +--- a/net/netfilter/nf_conntrack_netlink.c ++++ b/net/netfilter/nf_conntrack_netlink.c +@@ -705,6 +705,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, + u_int8_t u3 = nfmsg->nfgen_family; + int err = 0; + ++ if (!ve_nf_conntrack_initialized()) ++ return -ENOPROTOOPT; ++ + if (cda[CTA_TUPLE_ORIG]) + err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); + else if (cda[CTA_TUPLE_REPLY]) +@@ -751,6 +754,9 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, + u_int8_t u3 = nfmsg->nfgen_family; + int err = 0; + ++ if (!ve_nf_conntrack_initialized()) ++ return -ENOPROTOOPT; ++ + if (nlh->nlmsg_flags & NLM_F_DUMP) { + #ifndef CONFIG_NF_CT_ACCT + if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) +@@ -1056,6 +1062,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, + u_int8_t u3 = nfmsg->nfgen_family; + int err = 0; + ++ if (!ve_nf_conntrack_initialized()) ++ return -ENOPROTOOPT; ++ + if (cda[CTA_TUPLE_ORIG]) { + err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG, u3); + if (err < 0) +@@ -1377,6 +1386,9 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, + u_int8_t u3 = nfmsg->nfgen_family; + int err = 0; + ++ if (!ve_nf_conntrack_initialized()) ++ return -ENOPROTOOPT; ++ + if (nlh->nlmsg_flags & NLM_F_DUMP) { + return netlink_dump_start(ctnl, skb, nlh, + ctnetlink_exp_dump_table, +@@ -1438,6 +1450,9 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, + unsigned int i; + int err; + ++ if (!ve_nf_conntrack_initialized()) ++ return -ENOPROTOOPT; ++ + if (cda[CTA_EXPECT_TUPLE]) { + /* delete a single expect by tuple */ + err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); +@@ -1576,6 +1591,9 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, + u_int8_t u3 = nfmsg->nfgen_family; + int err = 0; + ++ if (!ve_nf_conntrack_initialized()) ++ return -ENOPROTOOPT; ++ + if (!cda[CTA_EXPECT_TUPLE] + || !cda[CTA_EXPECT_MASK] + || !cda[CTA_EXPECT_MASTER]) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0060-UBC-fix-preempt_enable-placement-in-dcache-accoun.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0060-UBC-fix-preempt_enable-placement-in-dcache-accoun.patch @@ -0,0 +1,34 @@ +From c77d67e020b658888c69f9133850e298b7c3d02e Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 4 Apr 2008 12:39:42 +0400 +Subject: [PATCH 59/67] UBC: fix preempt_enable() placement in dcache accounting + +--- + fs/dcache.c | 6 +++--- + 1 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/dcache.c b/fs/dcache.c +index b69a57e..f32cef2 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -231,14 +231,14 @@ kill_it: + ub = dentry->dentry_bc.d_ub; + d_ubsize = dentry->dentry_bc.d_ubsize; + dentry = d_kill(dentry); ++ preempt_disable(); + if (ub_dentry_on) { + uncharge_dcache(ub, d_ubsize); + put_beancounter(ub); + } +- if (dentry) { +- preempt_disable(); ++ if (dentry) + goto repeat; +- } ++ preempt_enable(); + } + + void dput(struct dentry *dentry) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0128-VE-veinfo-to-vzmon.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0128-VE-veinfo-to-vzmon.patch @@ -0,0 +1,164 @@ +From 21745854d0113d1ecec3a939015366c2bd5cb9a4 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 18 Jul 2008 15:25:57 +0400 +Subject: [PATCH 128/131] VE veinfo to vzmon + +Since some people wish to run openvz w/o venet device, but +vzlist tool relies on /proc/vz/veinfo file presence, vzmon +module is a better place for this file. + +http://bugzilla.openvz.org/show_bug.cgi?id=394 +--- + include/linux/ve_proto.h | 5 ++ + kernel/ve/vecalls.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 110 insertions(+), 0 deletions(-) + +diff --git a/include/linux/ve_proto.h b/include/linux/ve_proto.h +index 6093fbb..630263c 100644 +--- a/include/linux/ve_proto.h ++++ b/include/linux/ve_proto.h +@@ -14,6 +14,11 @@ + #ifdef CONFIG_VE + + struct ve_struct; ++struct seq_file; ++ ++typedef void (*ve_seq_print_t)(struct seq_file *, struct ve_struct *); ++void vzmon_register_veaddr_print_cb(ve_seq_print_t); ++void vzmon_unregister_veaddr_print_cb(ve_seq_print_t); + + #ifdef CONFIG_INET + void ip_fragment_cleanup(struct ve_struct *envid); +diff --git a/kernel/ve/vecalls.c b/kernel/ve/vecalls.c +index 616cf0b..c05685a 100644 +--- a/kernel/ve/vecalls.c ++++ b/kernel/ve/vecalls.c +@@ -2441,6 +2441,103 @@ static struct vnotifier_block meminfo_notifier_block = { + .notifier_call = meminfo_call + }; + ++/* /proc/vz/veinfo */ ++ ++static ve_seq_print_t veaddr_seq_print_cb; ++ ++void vzmon_register_veaddr_print_cb(ve_seq_print_t cb) ++{ ++ rcu_assign_pointer(veaddr_seq_print_cb, cb); ++} ++EXPORT_SYMBOL(vzmon_register_veaddr_print_cb); ++ ++void vzmon_unregister_veaddr_print_cb(ve_seq_print_t cb) ++{ ++ rcu_assign_pointer(veaddr_seq_print_cb, NULL); ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL(vzmon_unregister_veaddr_print_cb); ++ ++static int veinfo_seq_show(struct seq_file *m, void *v) ++{ ++ struct ve_struct *ve; ++ ve_seq_print_t veaddr_seq_print; ++ ++ ve = list_entry((struct list_head *)v, struct ve_struct, ve_list); ++ ++ seq_printf(m, "%10u %5u %5u", ve->veid, ++ ve->class_id, atomic_read(&ve->pcounter)); ++ ++ veaddr_seq_print = m->private; ++ if (veaddr_seq_print) ++ veaddr_seq_print(m, ve); ++ ++ seq_putc(m, '\n'); ++ return 0; ++} ++ ++static void *veinfo_seq_start(struct seq_file *m, loff_t *pos) ++{ ++ struct ve_struct *curve; ++ struct list_head *entry; ++ loff_t l; ++ ++ rcu_read_lock(); ++ m->private = rcu_dereference(veaddr_seq_print_cb); ++ curve = get_exec_env(); ++ read_lock(&ve_list_lock); ++ if (!ve_is_super(curve)) { ++ if (*pos != 0) ++ return NULL; ++ return curve; ++ } ++ ++ l = *pos; ++ list_for_each(entry, &ve_list_head) { ++ if (l == 0) ++ return entry; ++ l--; ++ } ++ return NULL; ++} ++ ++static void *veinfo_seq_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ struct list_head *entry; ++ ++ entry = (struct list_head *)v; ++ if (!ve_is_super(get_exec_env())) ++ return NULL; ++ (*pos)++; ++ return entry->next == &ve_list_head ? NULL : entry->next; ++} ++ ++static void veinfo_seq_stop(struct seq_file *m, void *v) ++{ ++ read_unlock(&ve_list_lock); ++ rcu_read_unlock(); ++} ++ ++ ++static struct seq_operations veinfo_seq_op = { ++ .start = veinfo_seq_start, ++ .next = veinfo_seq_next, ++ .stop = veinfo_seq_stop, ++ .show = veinfo_seq_show, ++}; ++ ++static int veinfo_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &veinfo_seq_op); ++} ++ ++static struct file_operations proc_veinfo_operations = { ++ .open = veinfo_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ + static int __init init_vecalls_proc(void) + { + struct proc_dir_entry *de; +@@ -2477,6 +2574,13 @@ static int __init init_vecalls_proc(void) + printk(KERN_WARNING + "VZMON: can't make version proc entry\n"); + ++ de = create_proc_glob_entry_mod("vz/veinfo", S_IFREG | S_IRUSR, NULL, ++ THIS_MODULE); ++ if (de) ++ de->proc_fops = &proc_veinfo_operations; ++ else ++ printk(KERN_WARNING "VZMON: can't make veinfo proc entry\n"); ++ + virtinfo_notifier_register(VITYPE_GENERAL, &meminfo_notifier_block); + + return 0; +@@ -2487,6 +2591,7 @@ static void fini_vecalls_proc(void) + remove_proc_entry("vz/version", NULL); + remove_proc_entry("vz/devperms", NULL); + remove_proc_entry("vz/vestat", NULL); ++ remove_proc_entry("vz/veinfo", NULL); + virtinfo_notifier_unregister(VITYPE_GENERAL, &meminfo_notifier_block); + } + #else +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0071-NETFILTER-remove-mismerge-in-mark_source_chains.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0071-NETFILTER-remove-mismerge-in-mark_source_chains.patch @@ -0,0 +1,30 @@ +From c9d0e80b84a8327381ba9f8a09e5248d7b52b851 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Wed, 30 Apr 2008 13:55:27 +0400 +Subject: [PATCH 70/72] NETFILTER: remove mismerge in mark_source_chains() + +--- + net/ipv4/netfilter/ip_tables.c | 7 ------- + 1 files changed, 0 insertions(+), 7 deletions(-) + +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index ca47b8a..c36e32c 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -506,13 +506,6 @@ mark_source_chains(struct xt_table_info *newinfo, + return 0; + } + +- if (t->verdict < -NF_MAX_VERDICT - 1) { +- duprintf("mark_source_chains: bad " +- "negative verdict (%i)\n", +- t->verdict); +- return 0; +- } +- + /* Return: backtrack through the last + big jump. */ + do { +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0064-CPT-get-lo-stats-from-correct-place-during-restore.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0064-CPT-get-lo-stats-from-correct-place-during-restore.patch @@ -0,0 +1,26 @@ +From 222a18fcb23b6a7a9c7375f07283fd0789b0ae59 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Wed, 9 Apr 2008 20:13:14 +0400 +Subject: [PATCH 62/67] CPT: get lo stats from correct place during restore + +struct pcpu_lstats and struct net_device_stats aren't the same. +--- + kernel/cpt/rst_net.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/kernel/cpt/rst_net.c b/kernel/cpt/rst_net.c +index 2cb47a4..4a0070e 100644 +--- a/kernel/cpt/rst_net.c ++++ b/kernel/cpt/rst_net.c +@@ -421,7 +421,7 @@ static int rst_restore_netstats(loff_t pos, struct net_device *dev, + BUG_ON(sizeof(struct cpt_netstats_image) != n->cpt_hdrlen); + preempt_disable(); + if (dev == lo) +- stats = netdev_priv(lo); ++ stats = &lo->stats; + #if defined(CONFIG_VE_ETHDEV) || defined(CONFIG_VE_ETHDEV_MODULE) + else if (KSYMREF(veth_open) && dev->open == KSYMREF(veth_open)) + stats = veth_stats(dev, smp_processor_id()); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0050-ubuntu-make-mmap-POSIX-conform.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0050-ubuntu-make-mmap-POSIX-conform.patch @@ -0,0 +1,15 @@ +X-Git-Url: http://git.openvz.org/?p=linux-2.6.24-openvz;a=blobdiff_plain;f=mm%2Fmmap.c;fp=mm%2Fmmap.c;h=89731b3901454e0abfb9544d7ee0be8b13e310aa;hp=15678aa6ec73a4389d1c523fe542144cd3050836;hb=8d7a5ca70e9913a71ec0ac9dccdb6ce85c23ac4b;hpb=148ba276d7db5fd498d17e2769291e7f17446233 + +Index: kernel/mm/mmap.c +=================================================================== +--- kernel.orig/mm/mmap.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/mm/mmap.c 2008-11-24 15:59:24.000000000 +0100 +@@ -930,7 +930,7 @@ + prot |= PROT_EXEC; + + if (!len) +- return addr; ++ return -EINVAL; + + if (!(flags & MAP_FIXED)) + addr = round_hint_to_min(addr); --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0152-MS-NETNS-No-need-for-a-separate-__netlink_release-ca.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0152-MS-NETNS-No-need-for-a-separate-__netlink_release-ca.patch @@ -0,0 +1,77 @@ +From 085010126cff45137d3a7bc74aa316007429ed97 Mon Sep 17 00:00:00 2001 +From: Denis V. Lunev +Date: Fri, 29 Feb 2008 11:17:56 -0800 +Subject: [PATCH] MS NETNS No need for a separate __netlink_release call + +mainstream commit 9dfbec1fb2bedff6b118504055cd9f0485edba45 + +Merge it to netlink_kernel_release. + +Signed-off-by: Denis V. Lunev +Acked-by: Daniel Lezcano +Signed-off-by: David S. Miller +--- + net/netlink/af_netlink.c | 30 ++++++++++++------------------ + 1 files changed, 12 insertions(+), 18 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index b548ab4..71e31e3 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1348,22 +1348,6 @@ static void netlink_data_ready(struct sock *sk, int len) + * queueing. + */ + +-static void __netlink_release(struct sock *sk) +-{ +- /* +- * Last sock_put should drop referrence to sk->sk_net. It has already +- * been dropped in netlink_kernel_create. Taking referrence to stopping +- * namespace is not an option. +- * Take referrence to a socket to remove it from netlink lookup table +- * _alive_ and after that destroy it in the context of init_net. +- */ +- +- sock_hold(sk); +- sock_release(sk->sk_socket); +- sk->sk_net = get_net(&init_net); +- sock_put(sk); +-} +- + struct sock * + netlink_kernel_create(struct net *net, int unit, unsigned int groups, + void (*input)(struct sk_buff *skb), +@@ -1428,7 +1412,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, + + out_sock_release: + kfree(listeners); +- __netlink_release(sk); ++ netlink_kernel_release(sk); + return NULL; + + out_sock_release_nosk: +@@ -1440,10 +1424,20 @@ out_sock_release_nosk: + void + netlink_kernel_release(struct sock *sk) + { ++ /* ++ * Last sock_put should drop referrence to sk->sk_net. It has already ++ * been dropped in netlink_kernel_create. Taking referrence to stopping ++ * namespace is not an option. ++ * Take referrence to a socket to remove it from netlink lookup table ++ * _alive_ and after that destroy it in the context of init_net. ++ */ + if (sk == NULL || sk->sk_socket == NULL) + return; + +- __netlink_release(sk); ++ sock_hold(sk); ++ sock_release(sk->sk_socket); ++ sk->sk_net = get_net(&init_net); ++ sock_put(sk); + } + EXPORT_SYMBOL(netlink_kernel_release); + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0090-UBC-bc-counter.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0090-UBC-bc-counter.patch @@ -0,0 +1,98 @@ +From 80f10d7cf91bc9aa477262f7fb3aeaf4ec8a9e1e Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Mon, 30 Jun 2008 13:48:49 +0400 +Subject: [PATCH 090/103] UBC bc counter + +Add ubc and sub-ubc account. +Changing all values protected with ub_hash_lock. +--- + include/bc/beancounter.h | 3 +++ + kernel/bc/beancounter.c | 23 +++++++++++++++++++++++ + 2 files changed, 26 insertions(+), 0 deletions(-) + +diff --git a/include/bc/beancounter.h b/include/bc/beancounter.h +index 7327bcb..89fcf20 100644 +--- a/include/bc/beancounter.h ++++ b/include/bc/beancounter.h +@@ -225,6 +225,7 @@ struct user_beancounter + struct ub_iopriv iopriv; + + struct user_beancounter *parent; ++ int ub_childs; + void *private_data; + unsigned long ub_aflags; + +@@ -250,6 +251,8 @@ struct user_beancounter + #endif + }; + ++extern int ub_count; ++ + enum ub_severity { UB_HARD, UB_SOFT, UB_FORCE }; + + #define UB_AFLAG_NOTIF_PAGEIN 0 +diff --git a/kernel/bc/beancounter.c b/kernel/bc/beancounter.c +index 48fa1cc..00b6469 100644 +--- a/kernel/bc/beancounter.c ++++ b/kernel/bc/beancounter.c +@@ -127,6 +127,25 @@ static inline struct user_beancounter *bc_lookup_hash(struct hlist_head *hash, + return NULL; + } + ++int ub_count; ++ ++/* next two must be called under ub_hash_lock */ ++static inline void ub_count_inc(struct user_beancounter *ub) ++{ ++ if (ub->parent) ++ ub->parent->ub_childs++; ++ else ++ ub_count++; ++} ++ ++static inline void ub_count_dec(struct user_beancounter *ub) ++{ ++ if (ub->parent) ++ ub->parent->ub_childs--; ++ else ++ ub_count--; ++} ++ + struct user_beancounter *get_beancounter_byuid(uid_t uid, int create) + { + struct user_beancounter *new_ub, *ub; +@@ -155,6 +174,7 @@ retry: + if (new_ub != NULL) { + list_add_rcu(&new_ub->ub_list, &ub_list_head); + hlist_add_head(&new_ub->ub_hash, hash); ++ ub_count_inc(new_ub); + spin_unlock_irqrestore(&ub_hash_lock, flags); + return new_ub; + } +@@ -212,6 +232,7 @@ retry: + if (new_ub != NULL) { + list_add_rcu(&new_ub->ub_list, &ub_list_head); + hlist_add_head(&new_ub->ub_hash, hash); ++ ub_count_inc(new_ub); + spin_unlock_irqrestore(&ub_hash_lock, flags); + return new_ub; + } +@@ -307,6 +328,7 @@ again: + + hlist_del(&ub->ub_hash); + list_del_rcu(&ub->ub_list); ++ ub_count_dec(ub); + spin_unlock_irqrestore(&ub_hash_lock, flags); + + bc_verify_held(ub); +@@ -657,6 +679,7 @@ void __init ub_init_early(void) + + hlist_add_head(&ub->ub_hash, &ub_hash[ub->ub_uid]); + list_add(&ub->ub_list, &ub_list_head); ++ ub_count_inc(ub); + } + + void __init ub_init_late(void) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0144-MISC-autofs-fix-default-pgrp-vnr.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0144-MISC-autofs-fix-default-pgrp-vnr.patch @@ -0,0 +1,27 @@ +From cf5f65e4441b3acb94f895cb65bbc948c9101384 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Mon, 8 Sep 2008 14:15:06 +0400 +Subject: [PATCH] MISC autofs fix default pgrp vnr + +Default pgrp should be virtual-nr, +because autofs lookup pid struct via find_get_pid. +--- + fs/autofs/inode.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c +index 45f5992..af82143 100644 +--- a/fs/autofs/inode.c ++++ b/fs/autofs/inode.c +@@ -80,7 +80,7 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, + + *uid = current->uid; + *gid = current->gid; +- *pgrp = task_pgrp_nr(current); ++ *pgrp = task_pgrp_vnr(current); + + *minproto = *maxproto = AUTOFS_PROTO_VERSION; + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0105-CPT-restore-conntrack-mark.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0105-CPT-restore-conntrack-mark.patch @@ -0,0 +1,30 @@ +From ebc6433b39e27052d66c0498b355e2bfee302ba9 Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Fri, 18 Jul 2008 15:25:38 +0400 +Subject: [PATCH 105/131] CPT restore conntrack mark + +Restore mark value in conntracks as it is needed for connmark module. + +Bug #114207 +--- + kernel/cpt/rst_conntrack.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/kernel/cpt/rst_conntrack.c b/kernel/cpt/rst_conntrack.c +index 4c31f32..1f48945 100644 +--- a/kernel/cpt/rst_conntrack.c ++++ b/kernel/cpt/rst_conntrack.c +@@ -188,6 +188,10 @@ static int undump_one_ct(struct cpt_ip_conntrack_image *ci, loff_t pos, + memcpy(&conntrack->proto, ci->cpt_proto_data, sizeof(conntrack->proto)); + memcpy(&conntrack->help, ci->cpt_help_data, sizeof(conntrack->help)); + ++#if defined(CONFIG_IP_NF_CONNTRACK_MARK) ++ conntrack->mark = ci->cpt_mark; ++#endif ++ + #ifdef CONFIG_IP_NF_NAT_NEEDED + #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ + defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0041-Linux-2.6.24-ovz003.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0041-Linux-2.6.24-ovz003.patch @@ -0,0 +1,22 @@ +From 54c5b7426aae1d374df4c7ab6adaeba4e40a51d3 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Tue, 18 Mar 2008 12:07:46 +0300 +Subject: [PATCH 41/48] Linux 2.6.24-ovz003 + +--- + Makefile | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: kernel/Makefile +=================================================================== +--- kernel.orig/Makefile 2008-11-24 15:47:45.000000000 +0100 ++++ kernel/Makefile 2008-11-24 15:59:06.000000000 +0100 +@@ -3,7 +3,7 @@ + SUBLEVEL = 24 + EXTRAVERSION = .6 + NAME = Err Metey! A Heury Beelge-a Ret! +-VZVERSION = ovz002 ++VZVERSION = ovz003 + + # *DOCUMENTATION* + # To see a list of typical targets execute "make help" --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0029-NETFILTER-fix-nf_conntrack_l4proto_generic-s-leak-o.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0029-NETFILTER-fix-nf_conntrack_l4proto_generic-s-leak-o.patch @@ -0,0 +1,64 @@ +From 73501b739013a19bc444de75a5db6f49c2ec9809 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 14 Mar 2008 16:35:50 +0300 +Subject: [PATCH 29/48] NETFILTER: fix nf_conntrack_l4proto_generic's leak on VE stop + +--- + net/netfilter/nf_conntrack_core.c | 7 ------- + net/netfilter/nf_conntrack_proto.c | 1 + + 2 files changed, 1 insertions(+), 7 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 5271220..030e14f 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1029,7 +1029,6 @@ skip_ct_cache: + nf_conntrack_helper_fini(); + nf_conntrack_expect_fini(); + +- nf_conntrack_l4proto_unregister(ve_nf_conntrack_l4proto_generic); + nf_ct_proto_generic_sysctl_cleanup(); + nf_ct_free_hashtable(ve_nf_conntrack_hash, ve_nf_conntrack_vmalloc, + nf_conntrack_htable_size); +@@ -1040,7 +1039,6 @@ skip_ct_cache: + ve_nf_conntrack_max = 0; + nf_conntrack_proto_fini(); + #ifdef CONFIG_VE_IPTABLES +- ve_nf_conntrack_l4proto_generic = NULL; + kfree(ve->_nf_conntrack); + ve->_nf_conntrack = NULL; + #endif +@@ -1190,9 +1188,6 @@ int nf_conntrack_init(void) + ret = nf_ct_proto_generic_sysctl_init(); + if (ret < 0) + goto err_free_conntrack_slab; +- ret = nf_conntrack_l4proto_register(ve_nf_conntrack_l4proto_generic); +- if (ret < 0) +- goto free_sys; + /* Don't NEED lock here, but good form anyway. */ + write_lock_bh(&nf_conntrack_lock); + for (i = 0; i < AF_MAX; i++) +@@ -1221,10 +1216,8 @@ int nf_conntrack_init(void) + + return 0; + +-free_sys: + #if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) + nf_ct_proto_generic_sysctl_cleanup(); +- ve_nf_conntrack_l4proto_generic = NULL; + #endif + out_fini_expect: + nf_conntrack_expect_fini(); +diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c +index d9a2b15..1384c03 100644 +--- a/net/netfilter/nf_conntrack_proto.c ++++ b/net/netfilter/nf_conntrack_proto.c +@@ -361,4 +361,5 @@ void nf_conntrack_proto_fini(void) + kfree(ve_nf_ct_protos[i]); + ve_nf_ct_protos[i] = NULL; + } ++ kfree(ve_nf_conntrack_l4proto_generic); + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0009-SIT-create-sit-devices-in-correct-netns.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0009-SIT-create-sit-devices-in-correct-netns.patch @@ -0,0 +1,34 @@ +From 1cfe443dac8890ab8e6e3eb8824b1aebb126f697 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Tue, 4 Mar 2008 13:48:08 +0300 +Subject: [PATCH 09/48] SIT: create sit devices in correct netns + +http://bugzilla.openvz.org/show_bug.cgi?id=825 +--- + net/ipv6/sit.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index 208b16e..f45f3ad 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -201,7 +201,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int + dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup); + if (dev == NULL) + return NULL; +- ++ dev->nd_net = get_exec_env()->ve_ns->net_ns; + nt = netdev_priv(dev); + dev->init = ipip6_tunnel_init; + nt->parms = *parms; +@@ -876,6 +876,7 @@ static int sit_ve_start(void *data) + err = -ENOMEM; + goto free_tunnel; + } ++ st->_ipip6_fb_tunnel_dev->nd_net = get_exec_env()->ve_ns->net_ns; + st->_ipip6_fb_tunnel_dev->init = ipip6_fb_tunnel_init; + err = register_netdev(st->_ipip6_fb_tunnel_dev); + if (err < 0) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0094-UBC-tcpsndbuf-uncharging-too-much.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0094-UBC-tcpsndbuf-uncharging-too-much.patch @@ -0,0 +1,34 @@ +From 3bd8ea9e606a6c35fbf1873060e67f9a71df6977 Mon Sep 17 00:00:00 2001 +From: Denis Lunev +Date: Mon, 30 Jun 2008 13:48:49 +0400 +Subject: [PATCH 094/103] UBC tcpsndbuf uncharging too much + +It is not allowed to go to the label wait_for_memory with chargesize != 0 +when this space is already placed to the skb. +--- + net/ipv4/tcp.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 2cdad17..c83979e 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -568,6 +568,7 @@ new_segment: + if (!skb) + goto wait_for_memory; + ub_skb_set_charge(skb, sk, chargesize, UB_TCPSNDBUF); ++ chargesize = 0; + + skb_entail(sk, skb); + copy = size_goal; +@@ -760,6 +761,7 @@ new_segment: + goto wait_for_memory; + ub_skb_set_charge(skb, sk, chargesize, + UB_TCPSNDBUF); ++ chargesize = 0; + + /* + * Check whether we can use HW checksum. +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0046-sysfs-add-missing-sysfs-allowed-checks.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0046-sysfs-add-missing-sysfs-allowed-checks.patch @@ -0,0 +1,42 @@ +From 5ac8d25b5e31e08af04f464e44c8214efea2e271 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 24 Mar 2008 17:15:49 +0300 +Subject: [PATCH 46/48] sysfs: add missing "sysfs allowed?" checks + +http://bugzilla.openvz.org/show_bug.cgi?id=852 +--- + fs/sysfs/bin.c | 3 +++ + fs/sysfs/dir.c | 3 +++ + 2 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c +index 3cc6838..9aec999 100644 +--- a/fs/sysfs/bin.c ++++ b/fs/sysfs/bin.c +@@ -241,6 +241,9 @@ const struct file_operations bin_fops = { + + int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) + { ++ if (!ve_sysfs_alowed()) ++ return 0; ++ + BUG_ON(!kobj || !kobj->sd || !attr); + + return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR); +diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c +index 5a17b68..c6cb983 100644 +--- a/fs/sysfs/dir.c ++++ b/fs/sysfs/dir.c +@@ -655,6 +655,9 @@ int sysfs_create_dir(struct kobject * kobj) + struct sysfs_dirent *parent_sd, *sd; + int error = 0; + ++ if (!ve_sysfs_alowed()) ++ return 0; ++ + BUG_ON(!kobj); + + if (kobj->parent) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0038-Add-kernel.pid_ns_hide_child-sysctl.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0038-Add-kernel.pid_ns_hide_child-sysctl.patch @@ -0,0 +1,76 @@ +From c8f0641ada56a05ab168d521205d78f5e8d0b80b Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Mon, 17 Mar 2008 15:45:36 +0300 +Subject: [PATCH 38/48] Add kernel.pid_ns_hide_child sysctl + +It's PID_NS_HIDE_CHILD flg manipulator for current pidns. + +If set to 1, all process except first (like init) in all created pid +namespaces after set will be invisible from current and upfollow pid +namespaces. sysctl itself visible only in VE0. +--- + kernel/sysctl.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 51 insertions(+), 0 deletions(-) + +Index: kernel/kernel/sysctl.c +=================================================================== +--- kernel.orig/kernel/sysctl.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/kernel/sysctl.c 2008-11-24 15:59:00.000000000 +0100 +@@ -2911,6 +2911,57 @@ + return 0; + } + ++#ifdef CONFIG_PID_NS ++#include ++ ++static int proc_pid_ns_hide_child(struct ctl_table *table, int write, ++ struct file *filp, void __user *buffer, ++ size_t *lenp, loff_t *ppos) ++{ ++ int tmp, res; ++ ++ tmp = (current->nsproxy->pid_ns->flags & PID_NS_HIDE_CHILD) ? 1 : 0; ++ ++ res = __do_proc_dointvec(&tmp, table, write, filp, buffer, ++ lenp, ppos, NULL, NULL); ++ if (res || !write) ++ return res; ++ ++ if (tmp) ++ current->nsproxy->pid_ns->flags |= PID_NS_HIDE_CHILD; ++ else ++ current->nsproxy->pid_ns->flags &= ~PID_NS_HIDE_CHILD; ++ return 0; ++} ++ ++static struct ctl_table pid_ns_kern_table[] = { ++ { ++ .procname = "pid_ns_hide_child", ++ .maxlen = sizeof(int), ++ .mode = 0600, ++ .proc_handler = proc_pid_ns_hide_child, ++ }, ++ {} ++}; ++ ++static struct ctl_table pid_ns_root_table[] = { ++ { ++ .ctl_name = CTL_KERN, ++ .procname = "kernel", ++ .mode = 0555, ++ .child = pid_ns_kern_table, ++ }, ++ {} ++}; ++ ++static __init int pid_ns_sysctl_init(void) ++{ ++ register_sysctl_table(pid_ns_root_table); ++ return 0; ++} ++postcore_initcall(pid_ns_sysctl_init); ++#endif /* CONFIG_PID_NS */ ++ + /* + * No sense putting this after each symbol definition, twice, + * exception granted :-) --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0023-FAIRSCHED-change-proc-interface-to-work-with-vz-gro.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0023-FAIRSCHED-change-proc-interface-to-work-with-vz-gro.patch @@ -0,0 +1,242 @@ +From b89e74dc201e5943b79051f7f0c61b2c39d4d244 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Wed, 12 Mar 2008 18:18:14 +0300 +Subject: [PATCH 23/48] FAIRSCHED: change proc interface to work with vz groups + +Show weight and rate limit from fairsched_node. +CFS internals are different, so show (start_tag, value, delay) fields as zeros. +--- + include/linux/fairsched.h | 2 + + init/main.c | 2 + + kernel/vzfairsched.c | 89 ++++++++++++++++++++------------------------- + 3 files changed, 44 insertions(+), 49 deletions(-) + +Index: kernel/include/linux/fairsched.h +=================================================================== +--- kernel.orig/include/linux/fairsched.h 2008-11-24 15:57:19.000000000 +0100 ++++ kernel/include/linux/fairsched.h 2008-11-24 15:57:27.000000000 +0100 +@@ -39,6 +39,7 @@ + extern struct fairsched_node fairsched_init_node; + + void fairsched_init_early(void); ++void fairsched_init_late(void); + + static inline int task_fairsched_node_id(struct task_struct *p) + { +@@ -72,6 +73,7 @@ + #else /* CONFIG_VZ_FAIRSCHED */ + + static inline void fairsched_init_early(void) { } ++static inline void fairsched_init_late(void) { } + static inline int task_fairsched_node_id(struct task_struct *p) { return 0; } + static inline void get_task_fairsched_node(struct task_struct *p) { } + static inline void put_task_fairsched_node(struct task_struct *p) { } +Index: kernel/init/main.c +=================================================================== +--- kernel.orig/init/main.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/init/main.c 2008-11-24 15:57:27.000000000 +0100 +@@ -57,6 +57,7 @@ + #include + #include + #include ++#include + + #include + +@@ -865,6 +866,7 @@ + do_pre_smp_initcalls(); + + smp_init(); ++ fairsched_init_late(); + sched_init_smp(); + + cpuset_init_smp(); +Index: kernel/kernel/vzfairsched.c +=================================================================== +--- kernel.orig/kernel/vzfairsched.c 2008-11-24 15:57:26.000000000 +0100 ++++ kernel/kernel/vzfairsched.c 2008-11-24 15:57:27.000000000 +0100 +@@ -337,37 +337,31 @@ + */ + /*********************************************************************/ + ++#include ++#include ++#include ++ + struct fairsched_node_dump { +-#ifdef CONFIG_VE +- envid_t veid; +-#endif + int id; + unsigned weight; + unsigned rate; +- unsigned rate_limited : 1, +- delayed : 1; +- fschtag_t start_tag; +- fschvalue_t value; +- cycles_t delay; +- int nr_ready; +- int nr_runnable; ++ int rate_limited; + int nr_pcpu; + int nr_tasks, nr_runtasks; + }; + + struct fairsched_dump { +- int len, compat; ++ int len; + struct fairsched_node_dump nodes[0]; + }; + + static struct fairsched_dump *fairsched_do_dump(int compat) + { + int nr_nodes; +- int len, i; ++ int len; + struct fairsched_dump *dump; + struct fairsched_node *node; + struct fairsched_node_dump *p; +- unsigned long flags; + + start: + nr_nodes = (ve_is_super(get_exec_env()) ? fairsched_nr_nodes + 16 : 1); +@@ -376,7 +370,7 @@ + if (dump == NULL) + goto out; + +- spin_lock_irqsave(&fairsched_lock, flags); ++ mutex_lock(&fairsched_mutex); + if (ve_is_super(get_exec_env()) && nr_nodes < fairsched_nr_nodes) + goto repeat; + p = dump->nodes; +@@ -388,39 +382,24 @@ + #ifdef CONFIG_VE + if (!ve_accessible(node->owner_env, get_exec_env())) + continue; +- p->veid = node->owner_env->veid; +- if (compat) { +- p->nr_tasks = atomic_read(&node->owner_env->pcounter); +- for_each_online_cpu(i) +- p->nr_runtasks += +- VE_CPU_STATS(node->owner_env, i) +- ->nr_running; +- if (p->nr_runtasks < 0) +- p->nr_runtasks = 0; +- } ++ p->nr_tasks = atomic_read(&node->owner_env->pcounter); ++ p->nr_runtasks = nr_running_ve(node->owner_env); + #endif + p->id = node->id; + p->weight = node->weight; + p->rate = node->rate; + p->rate_limited = node->rate_limited; +- p->delayed = node->delayed; +- p->start_tag = node->start_tag; +- p->value = node->value; +- p->delay = node->delay; +- p->nr_ready = node->nr_ready; +- p->nr_runnable = node->nr_runnable; +- p->nr_pcpu = node->nr_pcpu; ++ p->nr_pcpu = num_online_cpus(); + p++; + } + dump->len = p - dump->nodes; +- dump->compat = compat; +- spin_unlock_irqrestore(&fairsched_lock, flags); ++ mutex_unlock(&fairsched_mutex); + + out: + return dump; + + repeat: +- spin_unlock_irqrestore(&fairsched_lock, flags); ++ mutex_unlock(&fairsched_mutex); + vfree(dump); + goto start; + } +@@ -429,7 +408,7 @@ + + #define FAIRSHED_DEBUG " debug" + +-#if defined(CONFIG_VE) ++#ifdef CONFIG_VE + /* + * File format is dictated by compatibility reasons. + */ +@@ -451,7 +430,7 @@ + " parent " + "weight " + " rate " +- "tasks " ++ "tasks " + " run " + "cpus" + " " +@@ -491,12 +470,9 @@ + p->nr_runtasks, + p->nr_pcpu, + p->rate_limited ? 'L' : '.', +- p->delayed ? 'D' : '.', +- p->nr_ready, +- (unsigned long long)p->start_tag.t, +- (unsigned long long)p->value.v, +- (unsigned long long)p->delay +- ); ++ '.', ++ p->nr_runtasks, ++ 0ll, 0ll, 0ll); + } + + return 0; +@@ -523,7 +499,7 @@ + ++*pos; + return fairsched_seq_start(m, pos); + } +-#endif ++#endif /* CONFIG_VE */ + + static int fairsched2_seq_show(struct seq_file *m, void *v) + { +@@ -563,16 +539,14 @@ + p->id, + p->weight, + p->rate, +- p->nr_runnable, ++ p->nr_runtasks, + p->nr_pcpu + #ifdef FAIRSHED_DEBUG + , + p->rate_limited ? 'L' : '.', +- p->delayed ? 'D' : '.', +- p->nr_ready, +- (unsigned long long)p->start_tag.t, +- (unsigned long long)p->value.v, +- (unsigned long long)p->delay ++ '.', ++ p->nr_runtasks, ++ 0ll, 0ll, 0ll + #endif + ); + } +@@ -654,4 +628,21 @@ + .release = fairsched_seq_release + }; + ++void __init fairsched_init_late(void) ++{ ++ struct proc_dir_entry *entry; ++#ifdef CONFIG_VE ++ entry = create_proc_glob_entry("fairsched", S_IRUGO, NULL); ++ if (entry) ++ entry->proc_fops = &proc_fairsched_operations; ++#endif ++ entry = create_proc_glob_entry("fairsched2", S_IRUGO, NULL); ++ if (entry) ++ entry->proc_fops = &proc_fairsched_operations; ++} ++ ++#else ++ ++void __init fairsched_init_late(void) { } ++ + #endif /* CONFIG_PROC_FS */ --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0151-MS-NETNS-Fix-race-between-put_net-and-netlink_kern.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0151-MS-NETNS-Fix-race-between-put_net-and-netlink_kern.patch @@ -0,0 +1,170 @@ +From 1f244a7b4f67fed7ca58f70ba73757af770757bf Mon Sep 17 00:00:00 2001 +From: Pavel Emelyanov +Date: Wed, 30 Jan 2008 19:31:06 -0800 +Subject: [PATCH] MS NETNS Fix race between put_net() and netlink_kernel_create() + +mainstream commit 23fe18669e7fdaf5b229747858d943a723124e2e + +The comment about "race free view of the set of network +namespaces" was a bit hasty. Look (there even can be only +one CPU, as discovered by Alexey Dobriyan and Denis Lunev): + +put_net() + if (atomic_dec_and_test(&net->refcnt)) + /* true */ + __put_net(net); + queue_work(...); + +/* + * note: the net now has refcnt 0, but still in + * the global list of net namespaces + */ + +== re-schedule == + +register_pernet_subsys(&some_ops); + register_pernet_operations(&some_ops); + (*some_ops)->init(net); + /* + * we call netlink_kernel_create() here + * in some places + */ + netlink_kernel_create(); + sk_alloc(); + get_net(net); /* refcnt = 1 */ + /* + * now we drop the net refcount not to + * block the net namespace exit in the + * future (or this can be done on the + * error path) + */ + put_net(sk->sk_net); + if (atomic_dec_and_test(&...)) + /* + * true. BOOOM! The net is + * scheduled for release twice + */ + +When thinking on this problem, I decided, that getting and +putting the net in init callback is wrong. If some init +callback needs to have a refcount-less reference on the struct +net, _it_ has to be careful himself, rather than relying on +the infrastructure to handle this correctly. + +In case of netlink_kernel_create(), the problem is that the +sk_alloc() gets the given namespace, but passing the info +that we don't want to get it inside this call is too heavy. + +Instead, I propose to crate the socket inside an init_net +namespace and then re-attach it to the desired one right +after the socket is created. + +After doing this, we also have to be careful on error paths +not to drop the reference on the namespace, we didn't get +the one on. + +Signed-off-by: Pavel Emelyanov +Acked-by: Denis Lunev +Signed-off-by: David S. Miller +--- + net/netlink/af_netlink.c | 52 +++++++++++++++++++++++++++++---------------- + 1 files changed, 33 insertions(+), 19 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 716c31d..b548ab4 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1348,6 +1348,22 @@ static void netlink_data_ready(struct sock *sk, int len) + * queueing. + */ + ++static void __netlink_release(struct sock *sk) ++{ ++ /* ++ * Last sock_put should drop referrence to sk->sk_net. It has already ++ * been dropped in netlink_kernel_create. Taking referrence to stopping ++ * namespace is not an option. ++ * Take referrence to a socket to remove it from netlink lookup table ++ * _alive_ and after that destroy it in the context of init_net. ++ */ ++ ++ sock_hold(sk); ++ sock_release(sk->sk_socket); ++ sk->sk_net = get_net(&init_net); ++ sock_put(sk); ++} ++ + struct sock * + netlink_kernel_create(struct net *net, int unit, unsigned int groups, + void (*input)(struct sk_buff *skb), +@@ -1366,8 +1382,18 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, + if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) + return NULL; + +- if (__netlink_create(net, sock, cb_mutex, unit) < 0) +- goto out_sock_release; ++ /* ++ * We have to just have a reference on the net from sk, but don't ++ * get_net it. Besides, we cannot get and then put the net here. ++ * So we create one inside init_net and the move it to net. ++ */ ++ ++ if (__netlink_create(&init_net, sock, cb_mutex, unit) < 0) ++ goto out_sock_release_nosk; ++ ++ sk = sock->sk; ++ put_net(sk->sk_net); ++ sk->sk_net = net; + + if (groups < 32) + groups = 32; +@@ -1376,7 +1402,6 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, + if (!listeners) + goto out_sock_release; + +- sk = sock->sk; + sk->sk_data_ready = netlink_data_ready; + if (input) + nlk_sk(sk)->netlink_rcv = input; +@@ -1399,14 +1424,14 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, + nl_table[unit].registered++; + } + netlink_table_ungrab(); +- +- /* Do not hold an extra referrence to a namespace as this socket is +- * internal to a namespace and does not prevent it to stop. */ +- put_net(net); + return sk; + + out_sock_release: + kfree(listeners); ++ __netlink_release(sk); ++ return NULL; ++ ++out_sock_release_nosk: + sock_release(sock); + return NULL; + } +@@ -1418,18 +1443,7 @@ netlink_kernel_release(struct sock *sk) + if (sk == NULL || sk->sk_socket == NULL) + return; + +- /* +- * Last sock_put should drop referrence to sk->sk_net. It has already +- * been dropped in netlink_kernel_create. Taking referrence to stopping +- * namespace is not an option. +- * Take referrence to a socket to remove it from netlink lookup table +- * _alive_ and after that destroy it in the context of init_net. +- */ +- sock_hold(sk); +- sock_release(sk->sk_socket); +- +- sk->sk_net = get_net(&init_net); +- sock_put(sk); ++ __netlink_release(sk); + } + EXPORT_SYMBOL(netlink_kernel_release); + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0097-VE-ipv6-ifdown.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0097-VE-ipv6-ifdown.patch @@ -0,0 +1,78 @@ +From 5fda95f2ce999c33d1e552b9a258874b5e2a61f6 Mon Sep 17 00:00:00 2001 +From: Denis Lunev +Date: Mon, 30 Jun 2008 13:48:49 +0400 +Subject: [PATCH 097/103] VE ipv6 ifdown + +Fix refcounting for anycast dst entries. + +The problem occures when we stop IPv6 device without dropping all addresses +on it. For such a device addrconf_ifdown marks all entries as obsolete and +ip6_del_rt called from __ipv6_dev_ac_dec return ENOENT. +The referrence is not dropped. + +The fix is simple. DST entry should not keep referrence when stored in the +FIB6 tree. + +Bug #98611 +--- + net/ipv6/addrconf.c | 12 ++++++------ + 1 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index 85ec6c6..c0ef49f 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -2448,7 +2448,7 @@ int addrconf_ifdown(struct net_device *dev, int how) + + ASSERT_RTNL(); + +- if (dev == init_net.loopback_dev && how == 1) ++ if ((dev->flags & IFF_LOOPBACK) && how == 1) + how = 0; + + rt6_ifdown(dev); +@@ -2461,7 +2461,7 @@ int addrconf_ifdown(struct net_device *dev, int how) + /* Step 1: remove reference to ipv6 device from parent device. + Do not dev_put! + */ +- if (how == 1) { ++ if (how) { + idev->dead = 1; + + /* protected by rtnl_lock */ +@@ -2493,12 +2493,12 @@ int addrconf_ifdown(struct net_device *dev, int how) + write_lock_bh(&idev->lock); + + /* Step 3: clear flags for stateless addrconf */ +- if (how != 1) ++ if (!how) + idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); + + /* Step 4: clear address list */ + #ifdef CONFIG_IPV6_PRIVACY +- if (how == 1 && del_timer(&idev->regen_timer)) ++ if (how && del_timer(&idev->regen_timer)) + in6_dev_put(idev); + + /* clear tempaddr list */ +@@ -2535,7 +2535,7 @@ int addrconf_ifdown(struct net_device *dev, int how) + + /* Step 5: Discard multicast list */ + +- if (how == 1) ++ if (how) + ipv6_mc_destroy_dev(idev); + else + ipv6_mc_down(idev); +@@ -2544,7 +2544,7 @@ int addrconf_ifdown(struct net_device *dev, int how) + + /* Shot the device (if unregistered) */ + +- if (how == 1) { ++ if (how) { + #ifdef CONFIG_SYSCTL + addrconf_sysctl_unregister(&idev->cnf); + neigh_sysctl_unregister(idev->nd_parms); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0087-CPT-restore-infinity-rlimits.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0087-CPT-restore-infinity-rlimits.patch @@ -0,0 +1,82 @@ +From 9c66d6c6e0fce81d77bcff3844cfbc7f7f591881 Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Mon, 30 Jun 2008 13:48:49 +0400 +Subject: [PATCH 087/103] CPT restore infinity rlimits + +During 32bit to 64bit migration rlimits were restored incorrectly due to +different size of long on 32bit and 64bit archs. Now simple conversion is +introduced in case of 32bit-64bit migration. Infinity values are restored as +infinity values. Error is returned if value greater than RLIM_INFINITY32 is +found in dump during restore on 32bit arch. + +Bug #111965 +--- + kernel/cpt/rst_process.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- + 1 files changed, 43 insertions(+), 2 deletions(-) + +diff --git a/kernel/cpt/rst_process.c b/kernel/cpt/rst_process.c +index c54f04e..2630538 100644 +--- a/kernel/cpt/rst_process.c ++++ b/kernel/cpt/rst_process.c +@@ -1193,6 +1193,32 @@ static void rst_apply_mxcsr_mask(struct task_struct *tsk) + #endif + } + ++#define RLIM_INFINITY32 0xffffffff ++#define RLIM_INFINITY64 (~0ULL) ++ ++#ifdef CONFIG_X86_64 ++#define rst_rlim_32_to_64(a, i, t, im) \ ++do { \ ++ if (im->cpt_rlim_##a[i] == RLIM_INFINITY32) \ ++ t->signal->rlim[i].rlim_##a = RLIM_INFINITY64; \ ++ else \ ++ t->signal->rlim[i].rlim_##a = im->cpt_rlim_##a[i]; \ ++} while (0) ++#elif defined(CONFIG_X86_32) ++#define rst_rlim_64_to_32(a, i, t, im) \ ++do { \ ++ if (im->cpt_rlim_##a[i] == RLIM_INFINITY64) \ ++ t->signal->rlim[i].rlim_##a = RLIM_INFINITY32; \ ++ else if (im->cpt_rlim_##a[i] > RLIM_INFINITY32) { \ ++ eprintk_ctx("rlimit %Lu is too high for 32-bit task, " \ ++ "dump file is corrupted\n", \ ++ im->cpt_rlim_##a[i]); \ ++ return -EINVAL; \ ++ } else \ ++ t->signal->rlim[i].rlim_##a = im->cpt_rlim_##a[i]; \ ++} while (0) ++#endif ++ + int rst_restore_process(struct cpt_context *ctx) + { + cpt_object_t *obj; +@@ -1328,8 +1354,23 @@ int rst_restore_process(struct cpt_context *ctx) + tsk->signal->cmaj_flt = ti->cpt_cmaj_flt; + + for (i=0; isignal->rlim[i].rlim_cur = ti->cpt_rlim_cur[i]; +- tsk->signal->rlim[i].rlim_max = ti->cpt_rlim_max[i]; ++#ifdef CONFIG_X86_64 ++ if (ctx->image_arch == CPT_OS_ARCH_I386) { ++ rst_rlim_32_to_64(cur, i, tsk, ti); ++ rst_rlim_32_to_64(max, i, tsk, ti); ++ } else ++#elif defined(CONFIG_X86_32) ++ if (ctx->image_arch == CPT_OS_ARCH_EMT64) { ++ rst_rlim_64_to_32(cur, i, tsk, ti); ++ rst_rlim_64_to_32(max, i, tsk, ti); ++ } else ++#endif ++ { ++ tsk->signal->rlim[i].rlim_cur = ++ ti->cpt_rlim_cur[i]; ++ tsk->signal->rlim[i].rlim_max = ++ ti->cpt_rlim_max[i]; ++ } + } + } + #endif +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0136-VE-NETLINK-fix-lookup-check.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0136-VE-NETLINK-fix-lookup-check.patch @@ -0,0 +1,36 @@ +From b0ae571e4859bd84e292e957d5e91762c918a647 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 6 Jun 2008 19:01:31 +0400 +Subject: [PATCH] VE NETLINK fix lookup check + +netlink_unicast() is done in init_net context because +a) rtnl socket is bound to init_net, +b) kernel-space socket is successfully looked up by any VE, +c) rtnl is kernel-spase socket. +which is b-r-o-k-e-n, because e.g. just about any manipulation with +netdevices via netlink will be projected onto VE0. + +Fix (after per-netns rtnl socket patches) +http://bugzilla.openvz.org/show_bug.cgi?id=905 +--- + net/netlink/af_netlink.c | 4 +--- + 1 files changed, 1 insertions(+), 3 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index ad02fab..4cb562d 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -210,9 +210,7 @@ static __inline__ struct sock *netlink_lookup(struct net *net, int protocol, u32 + read_lock(&nl_table_lock); + head = nl_pid_hashfn(hash, pid); + sk_for_each(sk, node, head) { +- /* VEs should find sockets, created by kernel */ +- if (nlk_sk(sk)->pid == pid && (netlink_is_kernel(sk) || +- ve_accessible_strict(sk->owner_env, get_exec_env()))) { ++ if (nlk_sk(sk)->pid == pid && sk->sk_net == net) { + sock_hold(sk); + goto found; + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0103-VE-proc-root-nlink.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0103-VE-proc-root-nlink.patch @@ -0,0 +1,42 @@ +From 0b3117a59bc498ad0c58d5bd2a717350c7ff8ada Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Wed, 2 Jul 2008 19:55:20 +0400 +Subject: [PATCH 103/103] VE proc root nlink + +Correct nlink counter at proc root entry +* add entries from local tree, similar as in proc_getattr. +* inside ve add threads count instead of node total processes count. + it not fully correct, but that's good upper estimate + and ve threads counter already exists. +--- + fs/proc/root.c | 13 ++++++++++++- + 1 files changed, 12 insertions(+), 1 deletions(-) + +diff --git a/fs/proc/root.c b/fs/proc/root.c +index e73fca0..7fc4ba5 100644 +--- a/fs/proc/root.c ++++ b/fs/proc/root.c +@@ -148,8 +148,19 @@ void __init proc_root_init(void) + static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat + ) + { ++ struct ve_struct *ve = get_exec_env(); ++ + generic_fillattr(dentry->d_inode, stat); +- stat->nlink = proc_root.nlink + nr_processes(); ++ stat->nlink = proc_root.nlink; ++ if (ve_is_super(ve)) ++ stat->nlink += nr_processes(); ++#ifdef CONFIG_VE ++ else ++ /* not really processes count, it's not right, but it's ok */ ++ stat->nlink += atomic_read(&ve->pcounter); ++ /* the same logic as in the proc_getattr */ ++ stat->nlink += ve->proc_root->nlink - 2; ++#endif + return 0; + } + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0100-VE-proc-boot-time.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0100-VE-proc-boot-time.patch @@ -0,0 +1,29 @@ +From f0a9304509c8acf12d5ff8b3a9233a09911c376a Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Wed, 2 Jul 2008 19:55:20 +0400 +Subject: [PATCH 100/103] VE proc boot time + +Make boot time relative to VE start time. +Some proc process tools use it to calculate process times, +but /proc/*/stat already related to VE start time. + +http://bugzilla.openvz.org/show_bug.cgi?id=828 +--- + fs/proc/proc_misc.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c +index 2bb8529..27bfda9 100644 +--- a/fs/proc/proc_misc.c ++++ b/fs/proc/proc_misc.c +@@ -649,6 +649,7 @@ int show_stat(struct seq_file *p, void *v) + show_stat_ve(p, env); + __nr_running = nr_running_ve(env); + __nr_iowait = nr_iowait_ve(env); ++ jif += env->start_timespec.tv_sec; + } + #endif + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0012-NETFILTER-create-net.netfilter.-hierarchy-in-VE0-t.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0012-NETFILTER-create-net.netfilter.-hierarchy-in-VE0-t.patch @@ -0,0 +1,36 @@ +From fc59e9f2e9a0769009d2e87d8570bbc7a2d063d1 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 7 Mar 2008 15:37:12 +0300 +Subject: [PATCH 12/48] NETFILTER: create net.netfilter.* hierarchy in VE0 too + +--- + net/netfilter/nf_conntrack_standalone.c | 5 ++++- + 1 files changed, 4 insertions(+), 1 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c +index 78cfaf0..fb5e4c9 100644 +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -457,6 +457,9 @@ static int nf_conntrack_init_ve_sysctl(struct ve_struct *ve) + ve_nf_ct_net_table = nf_ct_net_table; + ve_nf_ct_netfilter_table = nf_ct_netfilter_table; + ve_nf_ct_sysctl_table = nf_ct_sysctl_table; ++ ve_nf_ct_sysctl_header = register_sysctl_table(ve_nf_ct_net_table); ++ if (!ve_nf_ct_sysctl_header) ++ return -ENOMEM; + return 0; + } + +@@ -487,8 +490,8 @@ out: + + static void nf_conntrack_fini_ve_sysctl(struct ve_struct *ve) + { ++ unregister_sysctl_table(ve_nf_ct_sysctl_header); + if (!ve_is_super(ve)) { +- unregister_sysctl_table(ve_nf_ct_sysctl_header); + free_sysctl_clone(ve_nf_ct_net_table); + ve_nf_ct_net_table = NULL; + ve_nf_ct_sysctl_table = NULL; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0004-CONNTRACK-move-exp_proc_init-to-text-section.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0004-CONNTRACK-move-exp_proc_init-to-text-section.patch @@ -0,0 +1,27 @@ +From 9c10803877cbf58bebe511eafa67fee2c615f6f6 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Thu, 28 Feb 2008 20:18:49 +0300 +Subject: [PATCH 04/48] CONNTRACK: move exp_proc_init() to text section + +nf_conntrack_expect_init() is calling exp_proc_init() which +was can't be in .init.text for that reason. +--- + net/netfilter/nf_conntrack_expect.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c +index 5f8d9dd..ccf3d50 100644 +--- a/net/netfilter/nf_conntrack_expect.c ++++ b/net/netfilter/nf_conntrack_expect.c +@@ -490,7 +490,7 @@ static const struct file_operations exp_file_ops = { + }; + #endif /* CONFIG_PROC_FS */ + +-static int __init exp_proc_init(void) ++static int exp_proc_init(void) + { + #ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0007-SLUBC-change-SLAB_UBC-SLAB_NO_CHARGE-flags.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0007-SLUBC-change-SLAB_UBC-SLAB_NO_CHARGE-flags.patch @@ -0,0 +1,30 @@ +From 73980b5b87e7619ba49364d2618b25d4f4bd8450 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 3 Mar 2008 15:02:38 +0300 +Subject: [PATCH 07/48] SLUBC: change SLAB_UBC, SLAB_NO_CHARGE flags + +SLAB_NO_CHARGE conflicted with __SYSFS_ADD_DEFERRED internal flag +which resulted in double and broken additional directories created +in /sys/slab/ . +--- + include/linux/slab.h | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/slab.h b/include/linux/slab.h +index 2ff029a..793613f 100644 +--- a/include/linux/slab.h ++++ b/include/linux/slab.h +@@ -62,8 +62,8 @@ + * poll, fdsets, ...) non-ub allocs) + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +-#define SLAB_UBC 0x20000000UL /* alloc space for ubs ... */ +-#define SLAB_NO_CHARGE 0x40000000UL /* ... but don't charge */ ++#define SLAB_UBC 0x10000000UL /* alloc space for ubs ... */ ++#define SLAB_NO_CHARGE 0x20000000UL /* ... but don't charge */ + + /* + * struct kmem_cache related prototypes +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0045-VE-fix-uevent-generation-in-VE.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0045-VE-fix-uevent-generation-in-VE.patch @@ -0,0 +1,33 @@ +From 0474535acfde6adec1628cf02c67a296f4f38c5e Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 24 Mar 2008 14:11:16 +0300 +Subject: [PATCH 45/48] VE: fix uevent generation in VE + +There is only one uevent netlink socket with ->net being init_net. +There are multiple listeners (->mc_list) both from VE0 and VE. + +So, when, e. g., init scripts inside VE do echo 1 >/sys/.../uevent +uevent is discarded due to "->net doesn't match" check! + +http://bugzilla.openvz.org/show_bug.cgi?id=840 +--- + net/netlink/af_netlink.c | 3 --- + 1 files changed, 0 insertions(+), 3 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 2bd6026..ad02fab 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -956,9 +956,6 @@ static inline int do_one_broadcast(struct sock *sk, + !test_bit(p->group - 1, nlk->groups)) + goto out; + +- if ((sk->sk_net != p->net)) +- goto out; +- + if (!ve_accessible_strict(get_exec_env(), sk->owner_env)) + goto out; + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0107-CPT-rst-iptables-diagnostics.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0107-CPT-rst-iptables-diagnostics.patch @@ -0,0 +1,29 @@ +From 92cc26fffdab5dc6cc3ac8a0784f029391b4714d Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Fri, 18 Jul 2008 15:25:40 +0400 +Subject: [PATCH 107/131] CPT rst iptables diagnostics + +Add diagnostics in case of iptables-restore fail. +It is not clear right now what is wrong if iptables-restore fails. +Add some diagnostics in case of error. + +Bug #95952 +--- + kernel/cpt/rst_net.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/kernel/cpt/rst_net.c b/kernel/cpt/rst_net.c +index 4a0070e..aa79c8b 100644 +--- a/kernel/cpt/rst_net.c ++++ b/kernel/cpt/rst_net.c +@@ -697,6 +697,7 @@ static int rst_restore_iptables(struct cpt_context * ctx) + err = (status & 0xff00) >> 8; + if (err != 0) { + eprintk_ctx("iptables-restore exited with %d\n", err); ++ eprintk_ctx("Most probably some iptables modules are not loaded\n"); + err = -EINVAL; + } + } else { +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0019-FAIRSCHED-add-sys_fairsched_-system-calls.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0019-FAIRSCHED-add-sys_fairsched_-system-calls.patch @@ -0,0 +1,397 @@ +From f14a05b0c80e9f858666f5574c97720f4a1fae21 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Wed, 12 Mar 2008 18:11:42 +0300 +Subject: [PATCH 19/48] FAIRSCHED: add sys_fairsched_* system calls + +--- + include/linux/fairsched.h | 23 ++++ + kernel/sys_ni.c | 8 ++ + kernel/vzfairsched.c | 300 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 331 insertions(+), 0 deletions(-) + +diff --git a/include/linux/fairsched.h b/include/linux/fairsched.h +index e5bb3a2..cdba9a4 100644 +--- a/include/linux/fairsched.h ++++ b/include/linux/fairsched.h +@@ -11,6 +11,10 @@ + #ifndef __LINUX_FAIRSCHED_H__ + #define __LINUX_FAIRSCHED_H__ + ++#define FAIRSCHED_SET_RATE 0 ++#define FAIRSCHED_DROP_RATE 1 ++#define FAIRSCHED_GET_RATE 2 ++ + #ifdef __KERNEL__ + + /* refcnt change protected with tasklist write lock */ +@@ -19,6 +23,13 @@ struct fairsched_node { + int refcnt; + unsigned id; + struct list_head nodelist; ++ ++ unsigned weight; ++ unsigned char rate_limited; ++ unsigned rate; ++#ifdef CONFIG_VE ++ struct ve_struct *owner_env; ++#endif + }; + + #ifdef CONFIG_VZ_FAIRSCHED +@@ -46,6 +57,18 @@ static inline void put_task_fairsched_node(struct task_struct *p) + + #define INIT_VZ_FAIRSCHED .fsched_node = &fairsched_init_node, + ++#define FSCHWEIGHT_MAX ((1 << 16) - 1) ++#define FSCHRATE_SHIFT 10 ++#define FSCH_TIMESLICE 16 ++ ++asmlinkage int sys_fairsched_mknod(unsigned int parent, unsigned int weight, ++ unsigned int newid); ++asmlinkage int sys_fairsched_rmnod(unsigned int id); ++asmlinkage int sys_fairsched_mvpr(pid_t pid, unsigned int nodeid); ++asmlinkage int sys_fairsched_vcpus(unsigned int id, unsigned int vcpus); ++asmlinkage int sys_fairsched_chwt(unsigned int id, unsigned int weight); ++asmlinkage int sys_fairsched_rate(unsigned int id, int op, unsigned rate); ++ + #else /* CONFIG_VZ_FAIRSCHED */ + + static inline void fairsched_init_early(void) { } +diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c +index f801b56..74137d8 100644 +--- a/kernel/sys_ni.c ++++ b/kernel/sys_ni.c +@@ -161,3 +161,11 @@ cond_syscall(sys_getluid); + cond_syscall(sys_setluid); + cond_syscall(sys_setublimit); + cond_syscall(sys_ubstat); ++ ++/* fairsched compat */ ++cond_syscall(sys_fairsched_mknod); ++cond_syscall(sys_fairsched_rmnod); ++cond_syscall(sys_fairsched_mvpr); ++cond_syscall(sys_fairsched_vcpus); ++cond_syscall(sys_fairsched_chwt); ++cond_syscall(sys_fairsched_rate); +diff --git a/kernel/vzfairsched.c b/kernel/vzfairsched.c +index 43c743a..c2eae4d 100644 +--- a/kernel/vzfairsched.c ++++ b/kernel/vzfairsched.c +@@ -10,10 +10,16 @@ + + #include + #include ++#include ++#include + + struct fairsched_node fairsched_init_node = { + .id = FAIRSCHED_INIT_NODE_ID, + .tg = &init_task_group, ++#ifdef CONFIG_VE ++ .owner_env = get_ve0(), ++#endif ++ .weight = 1, + }; + + static DEFINE_MUTEX(fairsched_mutex); +@@ -28,3 +34,297 @@ void __init fairsched_init_early(void) + fairsched_nr_nodes++; + } + ++#define FSCHWEIGHT_BASE 512000 ++ ++/****************************************************************************** ++ * cfs group shares = FSCHWEIGHT_BASE / fairsched weight ++ * ++ * vzctl cpuunits default 1000 ++ * cfs shares default value is 1024 (see init_task_group_load in sched.c) ++ * cpuunits = 1000 --> weight = 500000 / cpuunits = 500 --> shares = 1024 ++ * ^--- from vzctl ++ * weight in 1..65535 --> shares in 7..512000 ++ * shares should be >1 (see comment in sched_group_set_shares function) ++ *****************************************************************************/ ++ ++static struct fairsched_node *fairsched_find(unsigned int id) ++{ ++ struct fairsched_node *p; ++ list_for_each_entry(p, &fairsched_node_head, nodelist) { ++ if (p->id == id) ++ return p; ++ } ++ return NULL; ++} ++ ++/****************************************************************************** ++ * System calls ++ * ++ * All do_xxx functions are called under fairsched mutex and after ++ * capability check. ++ * ++ * The binary interfaces follow some other Fair Scheduler implementations ++ * (although some system call arguments are not needed for our implementation). ++ *****************************************************************************/ ++ ++static int do_fairsched_mknod(unsigned int parent, unsigned int weight, ++ unsigned int newid) ++{ ++ struct fairsched_node *node; ++ int retval; ++ ++ retval = -EINVAL; ++ if (weight < 1 || weight > FSCHWEIGHT_MAX) ++ goto out; ++ if (newid < 0 || newid > INT_MAX) ++ goto out; ++ ++ retval = -EBUSY; ++ if (fairsched_find(newid) != NULL) ++ goto out; ++ ++ retval = -ENOMEM; ++ node = kzalloc(sizeof(*node), GFP_KERNEL); ++ if (node == NULL) ++ goto out; ++ ++ node->tg = sched_create_group(); ++ if (IS_ERR(node->tg)) ++ goto out_free; ++ ++ node->id = newid; ++ node->weight = weight; ++ sched_group_set_shares(node->tg, FSCHWEIGHT_BASE / weight); ++#ifdef CONFIG_VE ++ node->owner_env = get_exec_env(); ++#endif ++ list_add(&node->nodelist, &fairsched_node_head); ++ fairsched_nr_nodes++; ++ ++ retval = newid; ++out: ++ return retval; ++ ++out_free: ++ kfree(node); ++ return retval; ++} ++ ++asmlinkage int sys_fairsched_mknod(unsigned int parent, unsigned int weight, ++ unsigned int newid) ++{ ++ int retval; ++ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ ++ mutex_lock(&fairsched_mutex); ++ retval = do_fairsched_mknod(parent, weight, newid); ++ mutex_unlock(&fairsched_mutex); ++ ++ return retval; ++} ++EXPORT_SYMBOL(sys_fairsched_mknod); ++ ++static int do_fairsched_rmnod(unsigned int id) ++{ ++ struct fairsched_node *node; ++ int retval; ++ ++ retval = -EINVAL; ++ node = fairsched_find(id); ++ if (node == NULL) ++ goto out; ++ if (node == &fairsched_init_node) ++ goto out; ++ ++ retval = -EBUSY; ++ if (node->refcnt) ++ goto out; ++ ++ list_del(&node->nodelist); ++ fairsched_nr_nodes--; ++ ++ sched_destroy_group(node->tg); ++ kfree(node); ++ retval = 0; ++out: ++ return retval; ++} ++ ++asmlinkage int sys_fairsched_rmnod(unsigned int id) ++{ ++ int retval; ++ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ ++ mutex_lock(&fairsched_mutex); ++ retval = do_fairsched_rmnod(id); ++ mutex_unlock(&fairsched_mutex); ++ ++ return retval; ++} ++EXPORT_SYMBOL(sys_fairsched_rmnod); ++ ++static int do_fairsched_chwt(unsigned int id, unsigned weight) ++{ ++ struct fairsched_node *node; ++ ++ if (id == 0) ++ return -EINVAL; ++ if (weight < 1 || weight > FSCHWEIGHT_MAX) ++ return -EINVAL; ++ ++ node = fairsched_find(id); ++ if (node == NULL) ++ return -ENOENT; ++ ++ node->weight = weight; ++ sched_group_set_shares(node->tg, FSCHWEIGHT_BASE / weight); ++ ++ return 0; ++} ++ ++asmlinkage int sys_fairsched_chwt(unsigned int id, unsigned weight) ++{ ++ int retval; ++ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ ++ mutex_lock(&fairsched_mutex); ++ retval = do_fairsched_chwt(id, weight); ++ mutex_unlock(&fairsched_mutex); ++ ++ return retval; ++} ++ ++static int do_fairsched_vcpus(unsigned int id, unsigned int vcpus) ++{ ++ struct fairsched_node *node; ++ ++ if (id == 0) ++ return -EINVAL; ++ ++ node = fairsched_find(id); ++ if (node == NULL) ++ return -ENOENT; ++ ++ return 0; ++} ++ ++asmlinkage int sys_fairsched_vcpus(unsigned int id, unsigned int vcpus) ++{ ++ int retval; ++ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ ++ mutex_lock(&fairsched_mutex); ++ retval = do_fairsched_vcpus(id, vcpus); ++ mutex_unlock(&fairsched_mutex); ++ ++ return retval; ++} ++EXPORT_SYMBOL(sys_fairsched_vcpus); ++ ++static int do_fairsched_rate(unsigned int id, int op, unsigned rate) ++{ ++ struct fairsched_node *node; ++ int retval; ++ ++ if (id == 0) ++ return -EINVAL; ++ if (op == FAIRSCHED_SET_RATE && (rate < 1 || rate >= (1UL << 31))) ++ return -EINVAL; ++ ++ node = fairsched_find(id); ++ if (node == NULL) ++ return -ENOENT; ++ ++ retval = -EINVAL; ++ switch (op) { ++ case FAIRSCHED_SET_RATE: ++ node->rate = rate; ++ node->rate_limited = 1; ++ retval = rate; ++ break; ++ case FAIRSCHED_DROP_RATE: ++ node->rate = 0; ++ node->rate_limited = 0; ++ retval = 0; ++ break; ++ case FAIRSCHED_GET_RATE: ++ if (node->rate_limited) ++ retval = node->rate; ++ else ++ retval = -ENODATA; ++ break; ++ } ++ return retval; ++} ++ ++asmlinkage int sys_fairsched_rate(unsigned int id, int op, unsigned rate) ++{ ++ int retval; ++ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ ++ mutex_lock(&fairsched_mutex); ++ retval = do_fairsched_rate(id, op, rate); ++ mutex_unlock(&fairsched_mutex); ++ ++ return retval; ++} ++ ++static int do_fairsched_mvpr(pid_t pid, unsigned int nodeid) ++{ ++ struct task_struct *p; ++ struct fairsched_node *node; ++ int retval; ++ unsigned flags; ++ ++ retval = -ENOENT; ++ node = fairsched_find(nodeid); ++ if (node == NULL) ++ goto out; ++ ++ write_lock_irqsave(&tasklist_lock, flags); ++ retval = -ESRCH; ++ p = find_task_by_pid(pid); ++ if (p == NULL) ++ goto out_unlock; ++ ++ get_task_struct(p); ++ put_task_fairsched_node(p); ++ p->fsched_node = node; ++ get_task_fairsched_node(p); ++ write_unlock_irqrestore(&tasklist_lock, flags); ++ ++ smp_wmb(); ++ sched_move_task(p); ++ put_task_struct(p); ++ return 0; ++ ++out_unlock: ++ write_unlock_irqrestore(&tasklist_lock, flags); ++out: ++ return retval; ++} ++ ++asmlinkage int sys_fairsched_mvpr(pid_t pid, unsigned int nodeid) ++{ ++ int retval; ++ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ ++ mutex_lock(&fairsched_mutex); ++ retval = do_fairsched_mvpr(pid, nodeid); ++ mutex_unlock(&fairsched_mutex); ++ ++ return retval; ++} ++EXPORT_SYMBOL(sys_fairsched_mvpr); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0010-CPT-select-PM-as-well.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0010-CPT-select-PM-as-well.patch @@ -0,0 +1,27 @@ +From 15938557b7ee1cebc893c676e0574a990fb79947 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Tue, 4 Mar 2008 15:33:53 +0300 +Subject: [PATCH 10/48] CPT: select PM as well + +Just PM_SLEEP is not enough, because selecting logic doesn't select second and +all other levels of dependencies (which is probably a bug in build system +depending on how to look at it). +--- + kernel/Kconfig.openvz | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/kernel/Kconfig.openvz b/kernel/Kconfig.openvz +index 5cdcdd3..5d5d6f0 100644 +--- a/kernel/Kconfig.openvz ++++ b/kernel/Kconfig.openvz +@@ -70,6 +70,7 @@ config VZ_WDOG + config VZ_CHECKPOINT + tristate "Checkpointing & restoring Virtual Environments" + depends on VE_CALLS && INET ++ select PM + select PM_SLEEP + select TUN + select VE_ETHDEV +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0115-UBC-cfq-bc-wait-statistics.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0115-UBC-cfq-bc-wait-statistics.patch @@ -0,0 +1,127 @@ +From b9784922c8bcc65457ce5c5dc0ced4f6d5654f39 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 18 Jul 2008 15:25:47 +0400 +Subject: [PATCH 115/131] UBC cfq bc wait statistics + Summarize per (bc, device) pair delays between bc enqueue and activation. + show in /proc/bc//ioprio_queues total wait time in milliseconds. + +--- + include/linux/cfq-iosched.h | 6 ++++++ + kernel/bc/io_prio.c | 42 ++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 46 insertions(+), 2 deletions(-) + +diff --git a/include/linux/cfq-iosched.h b/include/linux/cfq-iosched.h +index 69c8943..f43f5eb 100644 +--- a/include/linux/cfq-iosched.h ++++ b/include/linux/cfq-iosched.h +@@ -50,6 +50,12 @@ struct cfq_bc_data { + */ + struct cfq_queue *async_cfqq[2][CFQ_PRIO_LISTS]; + struct cfq_queue *async_idle_cfqq; ++ ++ /* write under cfqd->queue->request_queue_lock */ ++ seqcount_t stat_lock; ++ /* summarize delays between enqueue and activation. */ ++ unsigned long wait_time; ++ unsigned long wait_start; + }; + + /* +diff --git a/kernel/bc/io_prio.c b/kernel/bc/io_prio.c +index 74202fa..8c06a0d 100644 +--- a/kernel/bc/io_prio.c ++++ b/kernel/bc/io_prio.c +@@ -183,6 +183,34 @@ static inline int bc_empty(struct cfq_bc_data *cfq_bc) + return 0; + } + ++static void bc_wait_start(struct cfq_bc_data *cfq_bc, unsigned long now) ++{ ++ write_seqcount_begin(&cfq_bc->stat_lock); ++ cfq_bc->wait_start = now; ++ write_seqcount_end(&cfq_bc->stat_lock); ++} ++ ++static void bc_wait_stop(struct cfq_bc_data *cfq_bc, unsigned long now) ++{ ++ write_seqcount_begin(&cfq_bc->stat_lock); ++ cfq_bc->wait_time += now - cfq_bc->wait_start; ++ cfq_bc->wait_start = 0; ++ write_seqcount_end(&cfq_bc->stat_lock); ++} ++ ++static unsigned int bc_wait_time(struct cfq_bc_data *cfq_bc, unsigned long now) ++{ ++ unsigned long res; ++ unsigned seq; ++ ++ do { ++ seq = read_seqcount_begin(&cfq_bc->stat_lock); ++ res = cfq_bc->wait_time + now - (cfq_bc->wait_start ?: now); ++ } while (read_seqcount_retry(&cfq_bc->stat_lock, seq)); ++ ++ return jiffies_to_msecs(res); ++} ++ + /* return true if a iotime after b, like time_after */ + static int bc_iotime_after(unsigned long a, unsigned long b) + { +@@ -229,6 +257,9 @@ static void bc_enqueue(struct cfq_data *cfqd, struct cfq_bc_data *cfq_bc) + cfq_bc->cfq_bc_iotime = position; + + bc_insert(cfqd, cfq_bc); ++ ++ if (cfq_bc != cfqd->active_cfq_bc) ++ bc_wait_start(cfq_bc, jiffies); + } + + static void bc_dequeue(struct cfq_data *cfqd, struct cfq_bc_data *cfq_bc) +@@ -269,6 +300,9 @@ static inline void bc_set_active(struct cfq_data *cfqd) + return; + } + ++ if (cfq_bc && cfq_bc->rqnum) ++ bc_wait_start(cfq_bc, now); ++ + /* peek first bc from queue */ + cfq_bc = rb_entry(rb_first(&cfqd->cfq_bc_queue), + struct cfq_bc_data, cfq_bc_node); +@@ -280,6 +314,8 @@ static inline void bc_set_active(struct cfq_data *cfqd) + cfqd->active_cfq_bc = cfq_bc; + cfqd->slice_begin = now; + cfqd->slice_end = now + cfqd->cfq_ub_slice; ++ ++ bc_wait_stop(cfq_bc, now); + } + + void bc_schedule_active(struct cfq_data *cfqd) +@@ -375,6 +411,7 @@ static int bc_ioprio_queue_show(struct seq_file *f, void *v) + { + struct user_beancounter *bc; + struct cfq_bc_data *cfq_bc; ++ unsigned long now = jiffies; + + bc = seq_beancounter(f); + +@@ -383,7 +420,7 @@ static int bc_ioprio_queue_show(struct seq_file *f, void *v) + struct cfq_data *cfqd; + + cfqd = cfq_bc->cfqd; +- seq_printf(f, "\t%-10s%6lu %c%c\n", ++ seq_printf(f, "\t%-10s%6lu %c%c %10u\n", + /* + * this per-bc -> queue-data -> queue -> device + * access is safe w/o additional locks, since +@@ -393,7 +430,8 @@ static int bc_ioprio_queue_show(struct seq_file *f, void *v) + kobject_name(cfqd->queue->kobj.parent), + cfq_bc->rqnum, + cfq_bc->on_dispatch ? 'D' : ' ', +- cfqd->active_cfq_bc == cfq_bc ? 'A' : ' '); ++ cfqd->active_cfq_bc == cfq_bc ? 'A' : ' ', ++ bc_wait_time(cfq_bc, now)); + } + read_unlock_irq(&bc->iopriv.cfq_bc_list_lock); + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0044-VE-fix-compilation-without-SYSFS.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0044-VE-fix-compilation-without-SYSFS.patch @@ -0,0 +1,44 @@ +From 0a43b2ec540c364cc10ac851ddd5da2ec38f3d4b Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 24 Mar 2008 14:09:45 +0300 +Subject: [PATCH 44/48] VE: fix compilation without SYSFS + +--- + kernel/ve/vecalls.c | 6 +++++- + 1 files changed, 5 insertions(+), 1 deletions(-) + +diff --git a/kernel/ve/vecalls.c b/kernel/ve/vecalls.c +index 4bb5d48..49ecfb8 100644 +--- a/kernel/ve/vecalls.c ++++ b/kernel/ve/vecalls.c +@@ -588,7 +588,8 @@ static void fini_ve_shmem(struct ve_struct *ve) + ve->shmem_mnt = NULL; + } + +-static inline int init_ve_sysfs_root(struct ve_struct *ve) ++#ifdef CONFIG_SYSFS ++static int init_ve_sysfs_root(struct ve_struct *ve) + { + struct sysfs_dirent *sysfs_root; + +@@ -604,6 +605,7 @@ static inline int init_ve_sysfs_root(struct ve_struct *ve) + ve->_sysfs_root = sysfs_root; + return 0; + } ++#endif + + #if defined(CONFIG_NET) && defined(CONFIG_SYSFS) + extern struct device_attribute ve_net_class_attributes[]; +@@ -749,7 +751,9 @@ out_fs_type: + #endif + ve->class_subsys = NULL; + ve->class_obj_subsys = NULL; ++#ifdef CONFIG_SYSFS + out: ++#endif + return err; + } + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0156-VE-let-ve_netns-live-a-bit-more.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0156-VE-let-ve_netns-live-a-bit-more.patch @@ -0,0 +1,69 @@ +From e4645288a01f65d02382bcf0d10148965c2038ac Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 9 Jun 2008 15:53:08 +0400 +Subject: [PATCH] VE let ->ve_netns live a bit more + +1. netns shutdown is done asynchronously +2. nsproxy free is done synchronously +which means we can't use "get_exec_env()->ve_ns->net_ns" construct +anywhere in netns teardown codepath. ->ve_ns will be NULL (fixable) or +will point to freed memory (hardly fixable). + +The solution it to pin netns one more time, and use get_exec_env()->ve_netns . +get_exec_env() is always valid. It's ->ve_netns will also be valid during +shutdown. As for ->ve_ns, we don't care from now. +--- + kernel/ve/vecalls.c | 12 ++++++------ + 1 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/kernel/ve/vecalls.c b/kernel/ve/vecalls.c +index ee5d600..96e856f 100644 +--- a/kernel/ve/vecalls.c ++++ b/kernel/ve/vecalls.c +@@ -970,10 +970,8 @@ static inline void fini_ve_namespaces(struct ve_struct *ve, + tmp = ve->ve_ns; + ve->ve_ns = get_nsproxy(old); + put_nsproxy(tmp); +- } else { ++ } else + put_nsproxy(ve->ve_ns); +- ve->ve_ns = NULL; +- } + } + + static int init_ve_netns(struct ve_struct *ve, struct nsproxy **old) +@@ -991,7 +989,7 @@ static int init_ve_netns(struct ve_struct *ve, struct nsproxy **old) + + put_nsproxy(ve->ve_ns); + ve->ve_ns = get_nsproxy(tsk->nsproxy); +- ve->ve_netns = ve->ve_ns->net_ns; ++ ve->ve_netns = get_net(ve->ve_ns->net_ns); + *old = cur; + return 0; + } +@@ -1580,9 +1578,10 @@ err_devpts: + err_shmem: + fini_ve_tty_drivers(ve); + err_tty: +- ve->ve_ns->net_ns->sysfs_completion = &sysfs_completion; + fini_ve_namespaces(ve, old_ns_net); + put_nsproxy(old_ns_net); ++ ve->ve_netns->sysfs_completion = &sysfs_completion; ++ put_net(ve->ve_netns); + wait_for_completion(&sysfs_completion); + err_netns: + fini_ve_route6(ve); +@@ -1792,8 +1791,9 @@ static void env_cleanup(struct ve_struct *ve) + unregister_ve_tty_drivers(ve); + fini_ve_meminfo(ve); + +- ve->ve_ns->net_ns->sysfs_completion = &sysfs_completion; + fini_ve_namespaces(ve, NULL); ++ ve->ve_netns->sysfs_completion = &sysfs_completion; ++ put_net(ve->ve_netns); + wait_for_completion(&sysfs_completion); + fini_ve_route(ve); + fini_ve_route6(ve); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0127-VE-sysctl-add-dymmy-to-pin-kernel.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0127-VE-sysctl-add-dymmy-to-pin-kernel.patch @@ -0,0 +1,72 @@ +From 84612b3e5dc1e92cb0ae275d5cf36689b416a54d Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 18 Jul 2008 15:25:56 +0400 +Subject: [PATCH 127/131] VE sysctl add dymmy to pin kernel + +Add kernel.dummy-pde to prevent invisible /proc/sys/kernel + +This is a mess. + +There are global and VE0-local sysctl trees. + +They are populated on-demand: creating creates necessary directories +if needed, removing removes directories if they become empty. + +It can very well happen that VE0-local tree is empty before first module +registers sysctl. + +Now, if someone instantiates /proc/sys/kernel inode while VE0-local sysctl tree +doesn't contain /proc/sys/kernel, its LPDE will be NULL. + +Now module registers sysctl, proc entry is created in local list, but nobody +cares. Inode is in memory, and lookup and readdir won't find new shiny sysctl, +because they both see LPDE=NULL and thus won't iterate over local list. + +Net effect -- sysctl registered but invisible in /proc + +In case of BUG112482 they're kernel.vzprivrange and kernel.ve_allow_kthreads . + +One solution is to make sure that /proc/sys/kernel exists in both trees before +first register. But we can't just add directory -- first "service vz stop" can +remove it due to garbage-collecting nature of sysctl removal and situation will +reappear. + +So, add dummy kernel/.dummy-pde which nobody removes. + +Bug #112482 +--- + kernel/ve/veowner.c | 13 +++++++++++++ + 1 files changed, 13 insertions(+), 0 deletions(-) + +diff --git a/kernel/ve/veowner.c b/kernel/ve/veowner.c +index cee5765..172c9e5 100644 +--- a/kernel/ve/veowner.c ++++ b/kernel/ve/veowner.c +@@ -186,11 +186,24 @@ static ctl_table vz_fs_table[] = { + }, + { 0 } + }; ++static int dummy_pde_data = 0; ++static ctl_table dummy_kern_table[] = { ++ { ++ .ctl_name = 23571113, ++ .procname = ".dummy-pde", ++ .data = &dummy_pde_data, ++ .maxlen = sizeof(int), ++ .mode = 0400, ++ .proc_handler = proc_dointvec, ++ }, ++ {} ++}; + static ctl_table root_table2[] = { + #ifdef CONFIG_INET + {CTL_NET, "net", NULL, 0, 0555, vz_net_table}, + #endif + {CTL_FS, "fs", NULL, 0, 0555, vz_fs_table}, ++ {CTL_KERN, "kernel", NULL, 0, 0555, dummy_kern_table}, + { 0 } + }; + int prepare_sysctl(void) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0034-NETFILTER-remove-many-useless-NULL-assignments.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0034-NETFILTER-remove-many-useless-NULL-assignments.patch @@ -0,0 +1,223 @@ +From 06927aa0b67994378a98faa8f2322a204488a4b1 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 17 Mar 2008 14:41:40 +0300 +Subject: [PATCH 34/48] NETFILTER: remove many useless NULL assignments + +VE is going to disappear in a second and memory will be freed, so +all those clears are indeedd useless. +--- + net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 4 +--- + net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 3 --- + net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 2 -- + net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 2 -- + net/netfilter/nf_conntrack_core.c | 15 --------------- + net/netfilter/nf_conntrack_proto.c | 4 +--- + net/netfilter/nf_conntrack_proto_generic.c | 2 -- + net/netfilter/nf_conntrack_proto_tcp.c | 4 ---- + net/netfilter/nf_conntrack_proto_udp.c | 4 ---- + net/netfilter/nf_conntrack_standalone.c | 6 +----- + 10 files changed, 3 insertions(+), 43 deletions(-) + +Index: kernel/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 2008-11-24 15:58:42.000000000 +0100 ++++ kernel/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 2008-11-24 15:58:43.000000000 +0100 +@@ -449,10 +449,8 @@ + + static void nf_ct_proto_ipv4_sysctl_cleanup(void) + { +- if (!ve_is_super(get_exec_env())) { ++ if (!ve_is_super(get_exec_env())) + free_sysctl_clone(ve_nf_conntrack_l3proto_ipv4->ctl_table); +- ve_nf_conntrack_l3proto_ipv4->ctl_table = NULL; +- } + } + #else + static inline int nf_ct_proto_ipv4_sysctl_init(void) +Index: kernel/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/nf_conntrack_proto_icmp.c 2008-11-24 15:57:35.000000000 +0100 ++++ kernel/net/ipv4/netfilter/nf_conntrack_proto_icmp.c 2008-11-24 15:58:43.000000000 +0100 +@@ -388,12 +388,9 @@ + #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT + free_sysctl_clone( + ve_nf_conntrack_l4proto_icmp->ctl_compat_table); +- ve_nf_conntrack_l4proto_icmp->ctl_compat_table = NULL; + #endif + free_sysctl_clone(ve_nf_conntrack_l4proto_icmp->ctl_table); +- ve_nf_conntrack_l4proto_icmp->ctl_table = NULL; + kfree(ve_nf_conntrack_l4proto_icmp); +- ve_nf_conntrack_l4proto_icmp = NULL; + } + } + EXPORT_SYMBOL(nf_ct_proto_icmp_sysctl_cleanup); +Index: kernel/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +=================================================================== +--- kernel.orig/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c 2008-11-24 15:57:35.000000000 +0100 ++++ kernel/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c 2008-11-24 15:58:43.000000000 +0100 +@@ -436,9 +436,7 @@ + { + if (!ve_is_super(get_exec_env())) { + free_sysctl_clone(ve_nf_conntrack_l3proto_ipv6->ctl_table); +- ve_nf_conntrack_l3proto_ipv6->ctl_table = NULL; + kfree(ve_nf_conntrack_l3proto_ipv6); +- ve_nf_conntrack_l3proto_ipv6 = NULL; + } + } + #endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ +Index: kernel/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +=================================================================== +--- kernel.orig/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c 2008-11-24 15:57:35.000000000 +0100 ++++ kernel/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c 2008-11-24 15:58:43.000000000 +0100 +@@ -334,9 +334,7 @@ + { + if (!ve_is_super(get_exec_env())) { + free_sysctl_clone(ve_nf_conntrack_l4proto_icmpv6->ctl_table); +- ve_nf_conntrack_l4proto_icmpv6->ctl_table = NULL; + kfree(ve_nf_conntrack_l4proto_icmpv6); +- ve_nf_conntrack_l4proto_icmpv6 = NULL; + } + } + EXPORT_SYMBOL(nf_ct_proto_icmpv6_sysctl_cleanup); +Index: kernel/net/netfilter/nf_conntrack_core.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_core.c 2008-11-24 15:57:41.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_core.c 2008-11-24 15:58:43.000000000 +0100 +@@ -998,9 +998,6 @@ + { + struct ve_struct *ve = get_exec_env(); + +-#ifdef CONFIG_VE_IPTABLES +- BUG_ON(!ve->_nf_conntrack); +-#endif + if (ve_is_super(ve)) + rcu_assign_pointer(ip_ct_attach, NULL); + +@@ -1032,15 +1029,9 @@ + nf_ct_proto_generic_sysctl_cleanup(); + nf_ct_free_hashtable(ve_nf_conntrack_hash, ve_nf_conntrack_vmalloc, + nf_conntrack_htable_size); +- ve_nf_conntrack_hash = NULL; +- INIT_HLIST_HEAD(&ve_unconfirmed); +- ve_nf_ct_expect_hash = NULL; +- atomic_set(&ve_nf_conntrack_count, 0); +- ve_nf_conntrack_max = 0; + nf_conntrack_proto_fini(); + #ifdef CONFIG_VE_IPTABLES + kfree(ve->_nf_conntrack); +- ve->_nf_conntrack = NULL; + #endif + } + +@@ -1127,10 +1118,6 @@ + int max_factor = 8; + int ret = 0, i; + +-#ifdef CONFIG_VE_IPTABLES +- if (ve->_nf_conntrack) +- return 0; +-#endif + if (ve_is_super(ve)) { + + /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB +@@ -1229,11 +1216,9 @@ + err_free_hash: + nf_ct_free_hashtable(ve_nf_conntrack_hash, nf_conntrack_vmalloc, + nf_conntrack_htable_size); +- ve_nf_conntrack_hash = NULL; + err_out: + #ifdef CONFIG_VE_IPTABLES + kfree(ve->_nf_conntrack); +- ve->_nf_conntrack = NULL; + out: + #endif + return ret; +Index: kernel/net/netfilter/nf_conntrack_proto.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_proto.c 2008-11-24 15:58:41.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_proto.c 2008-11-24 15:58:43.000000000 +0100 +@@ -357,10 +357,8 @@ + nf_ct_l4proto_unregister_sysctl(ve_nf_conntrack_l4proto_generic); + + /* free l3proto protocol tables */ +- for (i = 0; i < PF_MAX; i++) { ++ for (i = 0; i < PF_MAX; i++) + kfree(ve_nf_ct_protos[i]); +- ve_nf_ct_protos[i] = NULL; +- } + #ifdef CONFIG_VE_IPTABLES + if (!ve_is_super(get_exec_env())) + kfree(ve_nf_conntrack_l4proto_generic); +Index: kernel/net/netfilter/nf_conntrack_proto_generic.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_proto_generic.c 2008-11-24 15:57:35.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_proto_generic.c 2008-11-24 15:58:43.000000000 +0100 +@@ -168,10 +168,8 @@ + #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT + free_sysctl_clone( + ve_nf_conntrack_l4proto_generic->ctl_compat_table); +- ve_nf_conntrack_l4proto_generic->ctl_compat_table = NULL; + #endif + free_sysctl_clone(ve_nf_conntrack_l4proto_generic->ctl_table); +- ve_nf_conntrack_l4proto_generic->ctl_table = NULL; + } + } + EXPORT_SYMBOL(nf_ct_proto_generic_sysctl_cleanup); +Index: kernel/net/netfilter/nf_conntrack_proto_tcp.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_proto_tcp.c 2008-11-24 15:57:35.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_proto_tcp.c 2008-11-24 15:58:43.000000000 +0100 +@@ -1529,15 +1529,11 @@ + #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT + free_sysctl_clone( + ve_nf_conntrack_l4proto_tcp4->ctl_compat_table); +- ve_nf_conntrack_l4proto_tcp4->ctl_compat_table = NULL; + #endif + free_sysctl_clone(ve_nf_conntrack_l4proto_tcp4->ctl_table); +- ve_nf_conntrack_l4proto_tcp4->ctl_table = NULL; + kfree(ve_nf_conntrack_l4proto_tcp4); +- ve_nf_conntrack_l4proto_tcp4 = NULL; + + kfree(ve_nf_conntrack_l4proto_tcp6); +- ve_nf_conntrack_l4proto_tcp6 = NULL; + } + } + EXPORT_SYMBOL(nf_ct_proto_tcp_sysctl_cleanup); +Index: kernel/net/netfilter/nf_conntrack_proto_udp.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_proto_udp.c 2008-11-24 15:57:35.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_proto_udp.c 2008-11-24 15:58:43.000000000 +0100 +@@ -311,15 +311,11 @@ + #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT + free_sysctl_clone( + ve_nf_conntrack_l4proto_udp4->ctl_compat_table); +- ve_nf_conntrack_l4proto_udp4->ctl_compat_table = NULL; + #endif + free_sysctl_clone(ve_nf_conntrack_l4proto_udp4->ctl_table); +- ve_nf_conntrack_l4proto_udp4->ctl_table = NULL; + kfree(ve_nf_conntrack_l4proto_udp4); +- ve_nf_conntrack_l4proto_udp4 = NULL; + + kfree(ve_nf_conntrack_l4proto_udp6); +- ve_nf_conntrack_l4proto_udp6 = NULL; + } + } + EXPORT_SYMBOL(nf_ct_proto_udp_sysctl_cleanup); +Index: kernel/net/netfilter/nf_conntrack_standalone.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_standalone.c 2008-11-24 15:57:02.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_standalone.c 2008-11-24 15:58:43.000000000 +0100 +@@ -488,12 +488,8 @@ + static void nf_conntrack_fini_ve_sysctl(struct ve_struct *ve) + { + unregister_sysctl_table(ve_nf_ct_sysctl_header); +- if (!ve_is_super(ve)) { ++ if (!ve_is_super(ve)) + free_sysctl_clone(ve_nf_ct_net_table); +- ve_nf_ct_net_table = NULL; +- ve_nf_ct_sysctl_table = NULL; +- ve_nf_ct_netfilter_table = NULL; +- } + } + #else + static inline int nf_conntrack_init_ve_sysctl(struct ve_struct *ve) --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0003-SLUB-drop-inline-from-__flush_cpu_slab-prototyp.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0003-SLUB-drop-inline-from-__flush_cpu_slab-prototyp.patch @@ -0,0 +1,35 @@ +From 5e5b46ec81534f34dffcca9795c528c4074a563f Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Thu, 28 Feb 2008 19:24:52 +0300 +Subject: [PATCH 03/48] SLUB: drop "inline" from __flush_cpu_slab() prototype + +3.4 gcc sometimes treats as error the following sequence: + + static inline foo(); + + foo(); + + static inline foo() + { + ... + } +--- + mm/slub.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/mm/slub.c b/mm/slub.c +index 3317f93..b251d42 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -346,7 +346,7 @@ unsigned long ub_cache_growth(struct kmem_cache *cachep) + return atomic_read(&cachep->grown) << cachep->order; + } + +-static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu); ++static void __flush_cpu_slab(struct kmem_cache *s, int cpu); + + static int kmem_cache_walk_page(struct page *pg, struct kmem_cache *s, + int (*fun)(void *)) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0049-ubuntu-specific-fgetstat-virtinfo-notifier.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0049-ubuntu-specific-fgetstat-virtinfo-notifier.patch @@ -0,0 +1,30 @@ +From: Konstantin Khlebnikov + +In Ubuntu kernel, sys_fstat implemented via new function vfs_fgetattr, +where virtinfo_notifier_call is not presented. As result syscalls stat +and fstat give different device id and inode numbers inside VE. + +http://forum.openvz.org/index.php?t=msg&th=5912 + +--- a/fs/stat.c ++++ b/fs/stat.c +@@ -76,11 +76,19 @@ static int vfs_fgetattr(struct file *fil + struct dentry *dentry = file->f_path.dentry; + struct inode *inode = dentry->d_inode; + int retval; ++ struct faudit_stat_arg arg; + + retval = security_inode_getattr(mnt, dentry); + if (retval) + return retval; + ++ arg.mnt = mnt; ++ arg.dentry = dentry; ++ arg.stat = stat; ++ if (virtinfo_notifier_call(VITYPE_FAUDIT, VIRTINFO_FAUDIT_STAT, &arg) ++ != NOTIFY_DONE) ++ return arg.err; ++ + if (file->f_op && file->f_op->fgetattr) { + return file->f_op->fgetattr(file, stat); + } else if (inode->i_op->getattr) { --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0119-UBC-dcache-sleep-in-dput.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0119-UBC-dcache-sleep-in-dput.patch @@ -0,0 +1,59 @@ +From a859cfd55614c65d7c8bcc92bbba45ac0935a3ff Mon Sep 17 00:00:00 2001 +From: Denis V. Lunev +Date: Fri, 18 Jul 2008 15:25:50 +0400 +Subject: [PATCH 119/131] UBC dcache sleep in dput + +dentry->dentry_bc.d_ub is unreliable after the sleep. + +d_kill can sleep inside. In this case dentry->dentry_bc.d_ub saved before +is unreliable as we can have dcache accounting on event during sleep. In this +case we'll have saved ub == NULL and OOPS/leak inside dcache_uncharge. + +Another problem here is that we should decrement inuse count on the +dentry appropriately. + +Bug #116095 +--- + fs/dcache.c | 16 +++++++--------- + 1 files changed, 7 insertions(+), 9 deletions(-) + +diff --git a/fs/dcache.c b/fs/dcache.c +index 09fdd5e..17efdbb 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -181,9 +181,6 @@ static struct dentry *d_kill(struct dentry *dentry) + + static void dput_recursive(struct dentry *dentry) + { +- struct user_beancounter *ub; +- unsigned long d_ubsize; +- + repeat: + if (unlikely(ub_dentry_on)) { + spin_lock(&dcache_lock); +@@ -234,15 +231,16 @@ kill_it: + list_del(&dentry->d_lru); + dentry_stat.nr_unused--; + } +- +- ub = dentry->dentry_bc.d_ub; +- d_ubsize = dentry->dentry_bc.d_ubsize; +- dentry = d_kill(dentry); +- preempt_disable(); + if (unlikely(ub_dentry_on)) { +- uncharge_dcache(ub, d_ubsize); ++ struct user_beancounter *ub; ++ ++ ub = dentry->dentry_bc.d_ub; ++ BUG_ON(!ub_dput_testzero(dentry)); ++ uncharge_dcache(ub, dentry->dentry_bc.d_ubsize); + put_beancounter(ub); + } ++ dentry = d_kill(dentry); ++ preempt_disable(); + if (dentry) + goto repeat; + preempt_enable(); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0089-UBC-check-net-skb-on-repeated-charging.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0089-UBC-check-net-skb-on-repeated-charging.patch @@ -0,0 +1,26 @@ +From d3c692ac7aede5577fd951ef95a35449330d4001 Mon Sep 17 00:00:00 2001 +From: Vitaliy Gusev +Date: Mon, 30 Jun 2008 13:48:49 +0400 +Subject: [PATCH 089/103] UBC check net skb on repeated charging + +This is a (useful) debug patch to find charge memory leak. +--- + kernel/bc/net.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/kernel/bc/net.c b/kernel/bc/net.c +index 422d687..4db1f9b 100644 +--- a/kernel/bc/net.c ++++ b/kernel/bc/net.c +@@ -330,6 +330,8 @@ void ub_sock_sndqueuedel(struct sock *sk) + static inline void __ub_skb_set_charge(struct sk_buff *skb, struct sock *sk, + unsigned long size, int resource) + { ++ WARN_ON_ONCE(skb_bc(skb)->ub != NULL); ++ + skb_bc(skb)->ub = sock_bc(sk)->ub; + skb_bc(skb)->charged = size; + skb_bc(skb)->resource = resource; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0137-VE-SYSCTL-cleanup-cap-bset.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0137-VE-SYSCTL-cleanup-cap-bset.patch @@ -0,0 +1,36 @@ +From 7bec95432b9a8d45de49033a246913bddea45c55 Mon Sep 17 00:00:00 2001 +From: Vasily Averin +Date: Fri, 16 May 2008 14:07:37 +0400 +Subject: [PATCH] VE SYSCTL cleanup cap bset + kernel.cap-bound sysctl cleanup + - proc entry is global and therefore it is ReadOnly-accessible from inside VE + +http://bugzilla.openvz.org/show_bug.cgi?id=524 +--- + kernel/sysctl.c | 9 +-------- + 1 files changed, 1 insertions(+), 8 deletions(-) + +diff --git a/kernel/sysctl.c b/kernel/sysctl.c +index d5c7b1d..88c5f76 100644 +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -2155,15 +2155,8 @@ int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp, + { + int op; + +- struct ve_struct *ve; +- +- ve = get_exec_env(); +- +- /* For VE's root writing to VE's cap-bound is prohibited */ +- if ((ve_is_super(ve) && write && !capable(CAP_SYS_MODULE)) || +- (!ve_is_super(ve) && (!capable(CAP_VE_ADMIN) || write))) { ++ if (write && !capable(CAP_SYS_MODULE)) + return -EPERM; +- } + + op = is_global_init(current) ? OP_SET : OP_AND; + return __do_proc_dointvec(&cap_bset, table, write, filp, +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0155-VE-introduce-ve_netns.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0155-VE-introduce-ve_netns.patch @@ -0,0 +1,1120 @@ +From dbf8e04245347b6f4c984aefdc99cd57c0abf065 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 9 Jun 2008 15:46:39 +0400 +Subject: [PATCH] VE introduce ->ve_netns + +Preparations for fixing "NULL ->ve_ns" oops in inet6_rt_notify(). +--- + drivers/net/tun.c | 2 +- + drivers/net/venet_core.c | 4 +- + drivers/net/vzethdev.c | 2 +- + include/linux/ve.h | 1 + + kernel/cpt/cpt_dump.c | 2 +- + kernel/cpt/cpt_net.c | 4 +- + kernel/cpt/rst_net.c | 6 ++-- + kernel/ve/ve.c | 1 + + kernel/ve/vecalls.c | 7 +++-- + net/8021q/vlan.c | 2 +- + net/8021q/vlanproc.c | 4 +- + net/bridge/br_netlink.c | 2 +- + net/core/fib_rules.c | 2 +- + net/ipv4/arp.c | 4 +- + net/ipv4/devinet.c | 16 +++++++------- + net/ipv4/fib_frontend.c | 2 +- + net/ipv4/fib_semantics.c | 6 ++-- + net/ipv4/icmp.c | 2 +- + net/ipv4/igmp.c | 4 +- + net/ipv4/ip_fragment.c | 2 +- + net/ipv4/ip_gre.c | 4 +- + net/ipv4/ip_sockglue.c | 2 +- + net/ipv4/ipconfig.c | 2 +- + net/ipv4/ipip.c | 4 +- + net/ipv4/ipmr.c | 2 +- + net/ipv4/ipvs/ip_vs_sync.c | 8 +++--- + net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 +- + net/ipv4/netfilter/ipt_recent.c | 4 +- + .../netfilter/nf_conntrack_l3proto_ipv4_compat.c | 4 +- + net/ipv4/route.c | 10 ++++---- + net/ipv6/addrconf.c | 22 ++++++++++---------- + net/ipv6/af_inet6.c | 2 +- + net/ipv6/anycast.c | 12 +++++----- + net/ipv6/datagram.c | 2 +- + net/ipv6/ipv6_sockglue.c | 2 +- + net/ipv6/mcast.c | 12 +++++----- + net/ipv6/raw.c | 2 +- + net/ipv6/reassembly.c | 2 +- + net/ipv6/route.c | 10 ++++---- + net/ipv6/sit.c | 8 +++--- + net/netfilter/nf_conntrack_standalone.c | 4 +- + net/netfilter/xt_hashlimit.c | 4 +- + 42 files changed, 101 insertions(+), 98 deletions(-) + +Index: kernel/drivers/net/tun.c +=================================================================== +--- kernel.orig/drivers/net/tun.c 2008-11-24 15:59:11.000000000 +0100 ++++ kernel/drivers/net/tun.c 2008-11-24 16:08:08.000000000 +0100 +@@ -495,7 +495,7 @@ + + static int tun_set_iff(struct file *file, struct ifreq *ifr) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct tun_struct *tun; + struct net_device *dev; + int err; +Index: kernel/drivers/net/venet_core.c +=================================================================== +--- kernel.orig/drivers/net/venet_core.c 2008-11-24 16:01:57.000000000 +0100 ++++ kernel/drivers/net/venet_core.c 2008-11-24 16:08:08.000000000 +0100 +@@ -374,7 +374,7 @@ + + ve_old = set_exec_env(ve); + read_lock(&dev_base_lock); +- for_each_netdev(ve->ve_ns->net_ns, dev) { ++ for_each_netdev(ve->ve_netns, dev) { + if (dev->hard_start_xmit == venet_xmit) + ret = fop(dev, data); + } +@@ -630,7 +630,7 @@ + dev_venet = alloc_netdev(0, "venet%d", venet_setup); + if (!dev_venet) + return -ENOMEM; +- dev_venet->nd_net = ve->ve_ns->net_ns; ++ dev_venet->nd_net = ve->ve_netns; + err = dev_alloc_name(dev_venet, dev_venet->name); + if (err<0) + goto err; +Index: kernel/drivers/net/vzethdev.c +=================================================================== +--- kernel.orig/drivers/net/vzethdev.c 2008-11-24 15:59:31.000000000 +0100 ++++ kernel/drivers/net/vzethdev.c 2008-11-24 16:08:08.000000000 +0100 +@@ -609,7 +609,7 @@ + dev = alloc_netdev(sizeof(struct veth_struct), name, veth_setup); + if (!dev) + return ERR_PTR(-ENOMEM); +- dev->nd_net = get_exec_env()->ve_ns->net_ns; ++ dev->nd_net = get_exec_env()->ve_netns; + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) +Index: kernel/include/linux/ve.h +=================================================================== +--- kernel.orig/include/linux/ve.h 2008-11-24 16:01:25.000000000 +0100 ++++ kernel/include/linux/ve.h 2008-11-24 16:08:08.000000000 +0100 +@@ -342,6 +342,7 @@ + #endif + + struct nsproxy *ve_ns; ++ struct net *ve_netns; + #ifdef CONFIG_GRKERNSEC + struct { + int lock; +Index: kernel/kernel/cpt/cpt_dump.c +=================================================================== +--- kernel.orig/kernel/cpt/cpt_dump.c 2008-11-24 16:00:38.000000000 +0100 ++++ kernel/kernel/cpt/cpt_dump.c 2008-11-24 16:08:08.000000000 +0100 +@@ -1035,7 +1035,7 @@ + + static void check_unsupported_netdevices(struct cpt_context *ctx, __u32 *caps) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct net_device *dev; + + read_lock(&dev_base_lock); +Index: kernel/kernel/cpt/cpt_net.c +=================================================================== +--- kernel.orig/kernel/cpt/cpt_net.c 2008-11-24 16:00:36.000000000 +0100 ++++ kernel/kernel/cpt/cpt_net.c 2008-11-24 16:08:08.000000000 +0100 +@@ -153,7 +153,7 @@ + + int cpt_dump_link(struct cpt_context * ctx) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct net_device *dev; + + cpt_open_section(ctx, CPT_SECT_NET_DEVICE); +@@ -237,7 +237,7 @@ + + int cpt_dump_ifaddr(struct cpt_context * ctx) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct net_device *dev; + + cpt_open_section(ctx, CPT_SECT_NET_IFADDR); +Index: kernel/kernel/cpt/rst_net.c +=================================================================== +--- kernel.orig/kernel/cpt/rst_net.c 2008-11-24 16:01:08.000000000 +0100 ++++ kernel/kernel/cpt/rst_net.c 2008-11-24 16:08:08.000000000 +0100 +@@ -48,7 +48,7 @@ + + int rst_restore_ifaddr(struct cpt_context *ctx) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + int err; + loff_t sec = ctx->sections[CPT_SECT_NET_IFADDR]; + loff_t endsec; +@@ -408,7 +408,7 @@ + { + struct cpt_netstats_image *n; + struct net_device_stats *stats = NULL; +- struct net_device *lo = get_exec_env()->ve_ns->net_ns->loopback_dev; ++ struct net_device *lo = get_exec_env()->ve_netns->loopback_dev; + int err; + + if (!dev->get_stats) +@@ -472,7 +472,7 @@ + + int rst_restore_netdev(struct cpt_context *ctx) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + int err; + loff_t sec = ctx->sections[CPT_SECT_NET_DEVICE]; + loff_t endsec; +Index: kernel/kernel/ve/ve.c +=================================================================== +--- kernel.orig/kernel/ve/ve.c 2008-11-24 16:01:59.000000000 +0100 ++++ kernel/kernel/ve/ve.c 2008-11-24 16:08:08.000000000 +0100 +@@ -111,6 +111,7 @@ + .devpts_config = &devpts_config, + #endif + .ve_ns = &init_nsproxy, ++ .ve_netns = &init_net, + .is_running = 1, + .op_sem = __RWSEM_INITIALIZER(ve0.op_sem), + }; +Index: kernel/kernel/ve/vecalls.c +=================================================================== +--- kernel.orig/kernel/ve/vecalls.c 2008-11-24 16:01:59.000000000 +0100 ++++ kernel/kernel/ve/vecalls.c 2008-11-24 16:08:08.000000000 +0100 +@@ -991,6 +991,7 @@ + + put_nsproxy(ve->ve_ns); + ve->ve_ns = get_nsproxy(tsk->nsproxy); ++ ve->ve_netns = ve->ve_ns->net_ns; + *old = cur; + return 0; + } +@@ -2156,7 +2157,7 @@ + if (dst_ve == NULL) + goto out; + +- dst_net = dst_ve->ve_ns->net_ns; ++ dst_net = dst_ve->ve_netns; + + rtnl_lock(); + read_lock(&dev_base_lock); +@@ -2189,7 +2190,7 @@ + if (src_ve == NULL) + goto out; + +- src_net = src_ve->ve_ns->net_ns; ++ src_net = src_ve->ve_netns; + + rtnl_lock(); + +@@ -2228,7 +2229,7 @@ + + static void ve_mapped_devs_cleanup(struct ve_struct *ve) + { +- struct net *net = ve->ve_ns->net_ns; ++ struct net *net = ve->ve_netns; + struct net_device *dev, *next; + int rv; + +Index: kernel/net/8021q/vlan.c +=================================================================== +--- kernel.orig/net/8021q/vlan.c 2008-11-24 16:00:29.000000000 +0100 ++++ kernel/net/8021q/vlan.c 2008-11-24 16:08:08.000000000 +0100 +@@ -604,7 +604,7 @@ + if (new_dev == NULL) + return -ENOBUFS; + +- new_dev->nd_net = get_exec_env()->ve_ns->net_ns; ++ new_dev->nd_net = get_exec_env()->ve_netns; + /* need 4 bytes for extra VLAN header info, + * hope the underlying device can handle it. + */ +Index: kernel/net/8021q/vlanproc.c +=================================================================== +--- kernel.orig/net/8021q/vlanproc.c 2008-11-24 16:00:29.000000000 +0100 ++++ kernel/net/8021q/vlanproc.c 2008-11-24 16:08:08.000000000 +0100 +@@ -166,7 +166,7 @@ + + void vlan_proc_cleanup(void) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + + if (proc_vlan_conf) + remove_proc_entry(name_conf, proc_vlan_dir); +@@ -185,7 +185,7 @@ + + int vlan_proc_init(void) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + + proc_vlan_dir = proc_mkdir(name_root, net->proc_net); + if (proc_vlan_dir) { +Index: kernel/net/bridge/br_netlink.c +=================================================================== +--- kernel.orig/net/bridge/br_netlink.c 2008-11-24 16:02:40.000000000 +0100 ++++ kernel/net/bridge/br_netlink.c 2008-11-24 16:08:08.000000000 +0100 +@@ -82,7 +82,7 @@ + */ + void br_ifinfo_notify(int event, struct net_bridge_port *port) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct sk_buff *skb; + int err = -ENOBUFS; + +Index: kernel/net/core/fib_rules.c +=================================================================== +--- kernel.orig/net/core/fib_rules.c 2008-11-24 16:02:40.000000000 +0100 ++++ kernel/net/core/fib_rules.c 2008-11-24 16:08:08.000000000 +0100 +@@ -575,7 +575,7 @@ + struct fib_rules_ops *ops, struct nlmsghdr *nlh, + u32 pid) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct sk_buff *skb; + int err = -ENOBUFS; + +Index: kernel/net/ipv4/arp.c +=================================================================== +--- kernel.orig/net/ipv4/arp.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/arp.c 2008-11-24 16:08:08.000000000 +0100 +@@ -961,7 +961,7 @@ + if (mask && mask != htonl(0xFFFFFFFF)) + return -EINVAL; + if (!dev && (r->arp_flags & ATF_COM)) { +- dev = dev_getbyhwaddr(get_exec_env()->ve_ns->net_ns, r->arp_ha.sa_family, r->arp_ha.sa_data); ++ dev = dev_getbyhwaddr(get_exec_env()->ve_netns, r->arp_ha.sa_family, r->arp_ha.sa_data); + if (!dev) + return -ENODEV; + } +@@ -1150,7 +1150,7 @@ + rtnl_lock(); + if (r.arp_dev[0]) { + err = -ENODEV; +- if ((dev = __dev_get_by_name(get_exec_env()->ve_ns->net_ns, r.arp_dev)) == NULL) ++ if ((dev = __dev_get_by_name(get_exec_env()->ve_netns, r.arp_dev)) == NULL) + goto out; + + /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ +Index: kernel/net/ipv4/devinet.c +=================================================================== +--- kernel.orig/net/ipv4/devinet.c 2008-11-24 16:02:40.000000000 +0100 ++++ kernel/net/ipv4/devinet.c 2008-11-24 16:08:08.000000000 +0100 +@@ -427,7 +427,7 @@ + struct net_device *dev; + struct in_device *in_dev = NULL; + read_lock(&dev_base_lock); +- dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifindex); ++ dev = __dev_get_by_index(get_exec_env()->ve_netns, ifindex); + if (dev) + in_dev = in_dev_get(dev); + read_unlock(&dev_base_lock); +@@ -514,7 +514,7 @@ + goto errout; + } + +- dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifm->ifa_index); ++ dev = __dev_get_by_index(get_exec_env()->ve_netns, ifm->ifa_index); + if (dev == NULL) { + err = -ENODEV; + goto errout; +@@ -618,7 +618,7 @@ + char *colon; + int ret = -EFAULT; + int tryaddrmatch = 0; +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + + /* + * Fetch the caller's info block into kernel space +@@ -917,7 +917,7 @@ + */ + read_lock(&dev_base_lock); + rcu_read_lock(); +- for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { ++ for_each_netdev(get_exec_env()->ve_netns, dev) { + if ((in_dev = __in_dev_get_rcu(dev)) == NULL) + continue; + +@@ -996,7 +996,7 @@ + + read_lock(&dev_base_lock); + rcu_read_lock(); +- for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { ++ for_each_netdev(get_exec_env()->ve_netns, dev) { + if ((in_dev = __in_dev_get_rcu(dev))) { + addr = confirm_addr_indev(in_dev, dst, local, scope); + if (addr) +@@ -1190,7 +1190,7 @@ + + s_ip_idx = ip_idx = cb->args[1]; + idx = 0; +- for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { ++ for_each_netdev(get_exec_env()->ve_netns, dev) { + if (idx < s_idx) + goto cont; + if (idx > s_idx) +@@ -1250,7 +1250,7 @@ + struct net_device *dev; + + read_lock(&dev_base_lock); +- for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { ++ for_each_netdev(get_exec_env()->ve_netns, dev) { + struct in_device *in_dev; + rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); +@@ -1338,7 +1338,7 @@ + IPV4_DEVCONF_DFLT(FORWARDING) = on; + + read_lock(&dev_base_lock); +- for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { ++ for_each_netdev(get_exec_env()->ve_netns, dev) { + struct in_device *in_dev; + rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); +Index: kernel/net/ipv4/fib_frontend.c +=================================================================== +--- kernel.orig/net/ipv4/fib_frontend.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/fib_frontend.c 2008-11-24 16:08:08.000000000 +0100 +@@ -352,7 +352,7 @@ + colon = strchr(devname, ':'); + if (colon) + *colon = 0; +- dev = __dev_get_by_name(get_exec_env()->ve_ns->net_ns, devname); ++ dev = __dev_get_by_name(get_exec_env()->ve_netns, devname); + if (!dev) + return -ENODEV; + cfg->fc_oif = dev->ifindex; +Index: kernel/net/ipv4/fib_semantics.c +=================================================================== +--- kernel.orig/net/ipv4/fib_semantics.c 2008-11-24 16:02:40.000000000 +0100 ++++ kernel/net/ipv4/fib_semantics.c 2008-11-24 16:08:08.000000000 +0100 +@@ -325,7 +325,7 @@ + int dst_len, u32 tb_id, struct nl_info *info, + unsigned int nlm_flags) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct sk_buff *skb; + u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; + int err = -ENOBUFS; +@@ -556,7 +556,7 @@ + return -EINVAL; + if (inet_addr_type(nh->nh_gw) != RTN_UNICAST) + return -EINVAL; +- if ((dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, nh->nh_oif)) == NULL) ++ if ((dev = __dev_get_by_index(get_exec_env()->ve_netns, nh->nh_oif)) == NULL) + return -ENODEV; + if (!(dev->flags&IFF_UP)) + return -ENETDOWN; +@@ -822,7 +822,7 @@ + if (nhs != 1 || nh->nh_gw) + goto err_inval; + nh->nh_scope = RT_SCOPE_NOWHERE; +- nh->nh_dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, fi->fib_nh->nh_oif); ++ nh->nh_dev = dev_get_by_index(get_exec_env()->ve_netns, fi->fib_nh->nh_oif); + err = -ENODEV; + if (nh->nh_dev == NULL) + goto failure; +Index: kernel/net/ipv4/icmp.c +=================================================================== +--- kernel.orig/net/ipv4/icmp.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/icmp.c 2008-11-24 16:08:08.000000000 +0100 +@@ -514,7 +514,7 @@ + struct net_device *dev = NULL; + + if (rt->fl.iif && sysctl_icmp_errors_use_inbound_ifaddr) +- dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, rt->fl.iif); ++ dev = dev_get_by_index(get_exec_env()->ve_netns, rt->fl.iif); + + if (dev) { + saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK); +Index: kernel/net/ipv4/igmp.c +=================================================================== +--- kernel.orig/net/ipv4/igmp.c 2008-11-24 16:00:59.000000000 +0100 ++++ kernel/net/ipv4/igmp.c 2008-11-24 16:08:08.000000000 +0100 +@@ -2301,7 +2301,7 @@ + struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); + + state->in_dev = NULL; +- for_each_netdev(get_exec_env()->ve_ns->net_ns, state->dev) { ++ for_each_netdev(get_exec_env()->ve_netns, state->dev) { + struct in_device *in_dev; + + in_dev = in_dev_get(state->dev); +@@ -2449,7 +2449,7 @@ + + state->idev = NULL; + state->im = NULL; +- for_each_netdev(get_exec_env()->ve_ns->net_ns, state->dev) { ++ for_each_netdev(get_exec_env()->ve_netns, state->dev) { + struct in_device *idev; + + idev = in_dev_get(state->dev); +Index: kernel/net/ipv4/ip_fragment.c +=================================================================== +--- kernel.orig/net/ipv4/ip_fragment.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/ip_fragment.c 2008-11-24 16:08:08.000000000 +0100 +@@ -228,7 +228,7 @@ + if ((qp->q.last_in&FIRST_IN) && qp->q.fragments != NULL) { + struct sk_buff *head = qp->q.fragments; + /* Send an ICMP "Fragment Reassembly Timeout" message. */ +- if ((head->dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, qp->iif)) != NULL) { ++ if ((head->dev = dev_get_by_index(get_exec_env()->ve_netns, qp->iif)) != NULL) { + icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); + dev_put(head->dev); + } +Index: kernel/net/ipv4/ip_gre.c +=================================================================== +--- kernel.orig/net/ipv4/ip_gre.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/ip_gre.c 2008-11-24 16:08:08.000000000 +0100 +@@ -263,7 +263,7 @@ + int i; + for (i=1; i<100; i++) { + sprintf(name, "gre%d", i); +- if (__dev_get_by_name(get_exec_env()->ve_ns->net_ns, name) == NULL) ++ if (__dev_get_by_name(get_exec_env()->ve_netns, name) == NULL) + break; + } + if (i==100) +@@ -1211,7 +1211,7 @@ + } + + if (!tdev && tunnel->parms.link) +- tdev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, tunnel->parms.link); ++ tdev = __dev_get_by_index(get_exec_env()->ve_netns, tunnel->parms.link); + + if (tdev) { + hlen = tdev->hard_header_len; +Index: kernel/net/ipv4/ip_sockglue.c +=================================================================== +--- kernel.orig/net/ipv4/ip_sockglue.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/ip_sockglue.c 2008-11-24 16:08:08.000000000 +0100 +@@ -596,7 +596,7 @@ + dev_put(dev); + } + } else +- dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, mreq.imr_ifindex); ++ dev = __dev_get_by_index(get_exec_env()->ve_netns, mreq.imr_ifindex); + + + err = -EADDRNOTAVAIL; +Index: kernel/net/ipv4/ipconfig.c +=================================================================== +--- kernel.orig/net/ipv4/ipconfig.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/ipconfig.c 2008-11-24 16:08:08.000000000 +0100 +@@ -185,7 +185,7 @@ + struct ic_device *d, **last; + struct net_device *dev; + unsigned short oflags; +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + + last = &ic_first_dev; + rtnl_lock(); +Index: kernel/net/ipv4/ipip.c +=================================================================== +--- kernel.orig/net/ipv4/ipip.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/ipip.c 2008-11-24 16:08:08.000000000 +0100 +@@ -226,7 +226,7 @@ + int i; + for (i=1; i<100; i++) { + sprintf(name, "tunl%d", i); +- if (__dev_get_by_name(get_exec_env()->ve_ns->net_ns, name) == NULL) ++ if (__dev_get_by_name(get_exec_env()->ve_netns, name) == NULL) + break; + } + if (i==100) +@@ -821,7 +821,7 @@ + } + + if (!tdev && tunnel->parms.link) +- tdev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, tunnel->parms.link); ++ tdev = __dev_get_by_index(get_exec_env()->ve_netns, tunnel->parms.link); + + if (tdev) { + dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); +Index: kernel/net/ipv4/ipmr.c +=================================================================== +--- kernel.orig/net/ipv4/ipmr.c 2008-11-24 16:02:40.000000000 +0100 ++++ kernel/net/ipv4/ipmr.c 2008-11-24 16:08:08.000000000 +0100 +@@ -124,7 +124,7 @@ + static + struct net_device *ipmr_new_tunnel(struct vifctl *v) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct net_device *dev; + + dev = __dev_get_by_name(net, "tunl0"); +Index: kernel/net/ipv4/ipvs/ip_vs_sync.c +=================================================================== +--- kernel.orig/net/ipv4/ipvs/ip_vs_sync.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/ipvs/ip_vs_sync.c 2008-11-24 16:08:08.000000000 +0100 +@@ -405,7 +405,7 @@ + struct net_device *dev; + struct inet_sock *inet = inet_sk(sk); + +- if ((dev = __dev_get_by_name(get_exec_env()->ve_ns->net_ns, ifname)) == NULL) ++ if ((dev = __dev_get_by_name(get_exec_env()->ve_netns, ifname)) == NULL) + return -ENODEV; + + if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) +@@ -426,7 +426,7 @@ + */ + static int set_sync_mesg_maxlen(int sync_state) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct net_device *dev; + int num; + +@@ -470,7 +470,7 @@ + memset(&mreq, 0, sizeof(mreq)); + memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr)); + +- if ((dev = __dev_get_by_name(get_exec_env()->ve_ns->net_ns, ifname)) == NULL) ++ if ((dev = __dev_get_by_name(get_exec_env()->ve_netns, ifname)) == NULL) + return -ENODEV; + if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) + return -EINVAL; +@@ -491,7 +491,7 @@ + __be32 addr; + struct sockaddr_in sin; + +- if ((dev = __dev_get_by_name(get_exec_env()->ve_ns->net_ns, ifname)) == NULL) ++ if ((dev = __dev_get_by_name(get_exec_env()->ve_netns, ifname)) == NULL) + return -ENODEV; + + addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); +Index: kernel/net/ipv4/netfilter/ipt_CLUSTERIP.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/ipt_CLUSTERIP.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/netfilter/ipt_CLUSTERIP.c 2008-11-24 16:08:08.000000000 +0100 +@@ -402,7 +402,7 @@ + return false; + } + +- dev = dev_get_by_name(get_exec_env()->ve_ns->net_ns, e->ip.iniface); ++ dev = dev_get_by_name(get_exec_env()->ve_netns, e->ip.iniface); + if (!dev) { + printk(KERN_WARNING "CLUSTERIP: no such interface %s\n", e->ip.iniface); + return false; +Index: kernel/net/ipv4/netfilter/ipt_recent.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/ipt_recent.c 2008-11-24 15:57:31.000000000 +0100 ++++ kernel/net/ipv4/netfilter/ipt_recent.c 2008-11-24 16:08:08.000000000 +0100 +@@ -508,7 +508,7 @@ + #ifdef CONFIG_PROC_FS + if (err) + return err; +- proc_dir = proc_mkdir("ipt_recent", ve->ve_ns->net_ns->proc_net); ++ proc_dir = proc_mkdir("ipt_recent", ve->ve_netns->proc_net); + if (proc_dir == NULL) { + err = -ENOMEM; + goto out_mem; +@@ -525,7 +525,7 @@ + + static void fini_ipt_recent(struct ve_struct *ve) + { +- remove_proc_entry("ipt_recent", ve->ve_ns->net_ns->proc_net); ++ remove_proc_entry("ipt_recent", ve->ve_netns->proc_net); + #ifdef CONFIG_VE_IPTABLES + kfree(ve->_ipt_recent); + ve->_ipt_recent = NULL; +Index: kernel/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c 2008-11-24 16:08:08.000000000 +0100 +@@ -422,7 +422,7 @@ + + int nf_conntrack_ipv4_compat_init(void) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct proc_dir_entry *proc, *proc_exp, *proc_stat; + + proc = proc_net_fops_create(net, "ip_conntrack", 0440, &ct_file_ops); +@@ -471,7 +471,7 @@ + + void nf_conntrack_ipv4_compat_fini(void) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + + unregister_sysctl_table(ve_ip_ct_sysctl_header); + if (!ve_is_super(get_exec_env())) +Index: kernel/net/ipv4/route.c +=================================================================== +--- kernel.orig/net/ipv4/route.c 2008-11-24 16:02:40.000000000 +0100 ++++ kernel/net/ipv4/route.c 2008-11-24 16:08:08.000000000 +0100 +@@ -1684,7 +1684,7 @@ + #endif + rth->rt_iif = + rth->fl.iif = dev->ifindex; +- rth->u.dst.dev = get_exec_env()->ve_ns->net_ns->loopback_dev; ++ rth->u.dst.dev = get_exec_env()->ve_netns->loopback_dev; + dev_hold(rth->u.dst.dev); + rth->idev = in_dev_get(rth->u.dst.dev); + rth->fl.oif = 0; +@@ -1944,7 +1944,7 @@ + if (res.type == RTN_LOCAL) { + int result; + result = fib_validate_source(saddr, daddr, tos, +- get_exec_env()->ve_ns->net_ns->loopback_dev->ifindex, ++ get_exec_env()->ve_netns->loopback_dev->ifindex, + dev, &spec_dst, &itag); + if (result < 0) + goto martian_source; +@@ -2006,7 +2006,7 @@ + #endif + rth->rt_iif = + rth->fl.iif = dev->ifindex; +- rth->u.dst.dev = get_exec_env()->ve_ns->net_ns->loopback_dev; ++ rth->u.dst.dev = get_exec_env()->ve_netns->loopback_dev; + dev_hold(rth->u.dst.dev); + rth->idev = in_dev_get(rth->u.dst.dev); + rth->rt_gateway = daddr; +@@ -2275,7 +2275,7 @@ + + static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct net_device * loopback_dev = net->loopback_dev; + u32 tos = RT_FL_TOS(oldflp); + struct flowi fl = { .nl_u = { .ip4_u = +@@ -2736,7 +2736,7 @@ + if (iif) { + struct net_device *dev; + +- dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, iif); ++ dev = __dev_get_by_index(get_exec_env()->ve_netns, iif); + if (dev == NULL) { + err = -ENODEV; + goto errout_free; +Index: kernel/net/ipv6/addrconf.c +=================================================================== +--- kernel.orig/net/ipv6/addrconf.c 2008-11-24 16:02:40.000000000 +0100 ++++ kernel/net/ipv6/addrconf.c 2008-11-24 16:08:08.000000000 +0100 +@@ -463,7 +463,7 @@ + struct inet6_dev *idev; + + read_lock(&dev_base_lock); +- for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { ++ for_each_netdev(get_exec_env()->ve_netns, dev) { + rcu_read_lock(); + idev = __in6_dev_get(dev); + if (idev) { +@@ -941,7 +941,7 @@ + read_lock(&dev_base_lock); + rcu_read_lock(); + +- for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { ++ for_each_netdev(get_exec_env()->ve_netns, dev) { + struct inet6_dev *idev; + struct inet6_ifaddr *ifa; + +@@ -1884,7 +1884,7 @@ + */ + int addrconf_set_dstaddr(void __user *arg) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct in6_ifreq ireq; + struct net_device *dev; + int err = -EINVAL; +@@ -1956,7 +1956,7 @@ + if (!valid_lft || prefered_lft > valid_lft) + return -EINVAL; + +- if ((dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifindex)) == NULL) ++ if ((dev = __dev_get_by_index(get_exec_env()->ve_netns, ifindex)) == NULL) + return -ENODEV; + + if ((idev = addrconf_add_dev(dev)) == NULL) +@@ -2008,7 +2008,7 @@ + struct inet6_dev *idev; + struct net_device *dev; + +- if ((dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifindex)) == NULL) ++ if ((dev = __dev_get_by_index(get_exec_env()->ve_netns, ifindex)) == NULL) + return -ENODEV; + + if ((idev = __in6_dev_get(dev)) == NULL) +@@ -2103,7 +2103,7 @@ + return; + } + +- for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { ++ for_each_netdev(get_exec_env()->ve_netns, dev) { + struct in_device * in_dev = __in_dev_get_rtnl(dev); + if (in_dev && (dev->flags & IFF_UP)) { + struct in_ifaddr * ifa; +@@ -2255,7 +2255,7 @@ + + static void ip6_tnl_add_linklocal(struct inet6_dev *idev) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct net_device *link_dev; + + /* first try to inherit the link-local address from the link device */ +@@ -3152,7 +3152,7 @@ + valid_lft = INFINITY_LIFE_TIME; + } + +- dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifm->ifa_index); ++ dev = __dev_get_by_index(get_exec_env()->ve_netns, ifm->ifa_index); + if (dev == NULL) + return -ENODEV; + +@@ -3336,7 +3336,7 @@ + s_ip_idx = ip_idx = cb->args[1]; + + idx = 0; +- for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { ++ for_each_netdev(get_exec_env()->ve_netns, dev) { + if (idx < s_idx) + goto cont; + if (idx > s_idx) +@@ -3446,7 +3446,7 @@ + + ifm = nlmsg_data(nlh); + if (ifm->ifa_index) +- dev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifm->ifa_index); ++ dev = __dev_get_by_index(get_exec_env()->ve_netns, ifm->ifa_index); + + if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) { + err = -EADDRNOTAVAIL; +@@ -3659,7 +3659,7 @@ + + read_lock(&dev_base_lock); + idx = 0; +- for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) { ++ for_each_netdev(get_exec_env()->ve_netns, dev) { + if (idx < s_idx) + goto cont; + if ((idev = in6_dev_get(dev)) == NULL) +Index: kernel/net/ipv6/af_inet6.c +=================================================================== +--- kernel.orig/net/ipv6/af_inet6.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv6/af_inet6.c 2008-11-24 16:08:08.000000000 +0100 +@@ -318,7 +318,7 @@ + err = -EINVAL; + goto out; + } +- dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, sk->sk_bound_dev_if); ++ dev = dev_get_by_index(get_exec_env()->ve_netns, sk->sk_bound_dev_if); + if (!dev) { + err = -ENODEV; + goto out; +Index: kernel/net/ipv6/anycast.c +=================================================================== +--- kernel.orig/net/ipv6/anycast.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv6/anycast.c 2008-11-24 16:08:08.000000000 +0100 +@@ -114,10 +114,10 @@ + } else { + /* router, no matching interface: just pick one */ + +- dev = dev_get_by_flags(get_exec_env()->ve_ns->net_ns, IFF_UP, IFF_UP|IFF_LOOPBACK); ++ dev = dev_get_by_flags(get_exec_env()->ve_netns, IFF_UP, IFF_UP|IFF_LOOPBACK); + } + } else +- dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_netns, ifindex); + + if (dev == NULL) { + err = -ENODEV; +@@ -198,7 +198,7 @@ + + write_unlock_bh(&ipv6_sk_ac_lock); + +- dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, pac->acl_ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_netns, pac->acl_ifindex); + if (dev) { + ipv6_dev_ac_dec(dev, &pac->acl_addr); + dev_put(dev); +@@ -226,7 +226,7 @@ + if (pac->acl_ifindex != prev_index) { + if (dev) + dev_put(dev); +- dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, pac->acl_ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_netns, pac->acl_ifindex); + prev_index = pac->acl_ifindex; + } + if (dev) +@@ -431,7 +431,7 @@ + if (dev) + return ipv6_chk_acast_dev(dev, addr); + read_lock(&dev_base_lock); +- for_each_netdev(get_exec_env()->ve_ns->net_ns, dev) ++ for_each_netdev(get_exec_env()->ve_netns, dev) + if (ipv6_chk_acast_dev(dev, addr)) { + found = 1; + break; +@@ -455,7 +455,7 @@ + struct ac6_iter_state *state = ac6_seq_private(seq); + + state->idev = NULL; +- for_each_netdev(get_exec_env()->ve_ns->net_ns, state->dev) { ++ for_each_netdev(get_exec_env()->ve_netns, state->dev) { + struct inet6_dev *idev; + + idev = in6_dev_get(state->dev); +Index: kernel/net/ipv6/datagram.c +=================================================================== +--- kernel.orig/net/ipv6/datagram.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv6/datagram.c 2008-11-24 16:08:08.000000000 +0100 +@@ -545,7 +545,7 @@ + if (!src_info->ipi6_ifindex) + return -EINVAL; + else { +- dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, src_info->ipi6_ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_netns, src_info->ipi6_ifindex); + if (!dev) + return -ENODEV; + } +Index: kernel/net/ipv6/ipv6_sockglue.c +=================================================================== +--- kernel.orig/net/ipv6/ipv6_sockglue.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv6/ipv6_sockglue.c 2008-11-24 16:08:08.000000000 +0100 +@@ -545,7 +545,7 @@ + if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) + goto e_inval; + +- if (__dev_get_by_index(get_exec_env()->ve_ns->net_ns, val) == NULL) { ++ if (__dev_get_by_index(get_exec_env()->ve_netns, val) == NULL) { + retv = -ENODEV; + break; + } +Index: kernel/net/ipv6/mcast.c +=================================================================== +--- kernel.orig/net/ipv6/mcast.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv6/mcast.c 2008-11-24 16:08:08.000000000 +0100 +@@ -216,7 +216,7 @@ + dst_release(&rt->u.dst); + } + } else +- dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_netns, ifindex); + + if (dev == NULL) { + sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); +@@ -268,7 +268,7 @@ + *lnk = mc_lst->next; + write_unlock_bh(&ipv6_sk_mc_lock); + +- if ((dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, mc_lst->ifindex)) != NULL) { ++ if ((dev = dev_get_by_index(get_exec_env()->ve_netns, mc_lst->ifindex)) != NULL) { + struct inet6_dev *idev = in6_dev_get(dev); + + (void) ip6_mc_leave_src(sk, mc_lst, idev); +@@ -303,7 +303,7 @@ + dst_release(&rt->u.dst); + } + } else +- dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_netns, ifindex); + + if (!dev) + return NULL; +@@ -334,7 +334,7 @@ + np->ipv6_mc_list = mc_lst->next; + write_unlock_bh(&ipv6_sk_mc_lock); + +- dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, mc_lst->ifindex); ++ dev = dev_get_by_index(get_exec_env()->ve_netns, mc_lst->ifindex); + if (dev) { + struct inet6_dev *idev = in6_dev_get(dev); + +@@ -2334,7 +2334,7 @@ + struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); + + state->idev = NULL; +- for_each_netdev(get_exec_env()->ve_ns->net_ns, state->dev) { ++ for_each_netdev(get_exec_env()->ve_netns, state->dev) { + struct inet6_dev *idev; + + idev = in6_dev_get(state->dev); +@@ -2463,7 +2463,7 @@ + + state->idev = NULL; + state->im = NULL; +- for_each_netdev(get_exec_env()->ve_ns->net_ns, state->dev) { ++ for_each_netdev(get_exec_env()->ve_netns, state->dev) { + struct inet6_dev *idev; + + idev = in6_dev_get(state->dev); +Index: kernel/net/ipv6/raw.c +=================================================================== +--- kernel.orig/net/ipv6/raw.c 2008-11-24 15:59:49.000000000 +0100 ++++ kernel/net/ipv6/raw.c 2008-11-24 16:08:08.000000000 +0100 +@@ -288,7 +288,7 @@ + if (!sk->sk_bound_dev_if) + goto out; + +- dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, sk->sk_bound_dev_if); ++ dev = dev_get_by_index(get_exec_env()->ve_netns, sk->sk_bound_dev_if); + if (!dev) { + err = -ENODEV; + goto out; +Index: kernel/net/ipv6/reassembly.c +=================================================================== +--- kernel.orig/net/ipv6/reassembly.c 2008-11-24 16:00:27.000000000 +0100 ++++ kernel/net/ipv6/reassembly.c 2008-11-24 16:08:08.000000000 +0100 +@@ -217,7 +217,7 @@ + + fq_kill(fq); + +- dev = dev_get_by_index(get_exec_env()->ve_ns->net_ns, fq->iif); ++ dev = dev_get_by_index(get_exec_env()->ve_netns, fq->iif); + if (!dev) + goto out; + +Index: kernel/net/ipv6/route.c +=================================================================== +--- kernel.orig/net/ipv6/route.c 2008-11-24 16:02:40.000000000 +0100 ++++ kernel/net/ipv6/route.c 2008-11-24 16:08:08.000000000 +0100 +@@ -1052,7 +1052,7 @@ + + int ip6_route_add(struct fib6_config *cfg) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + int err; + struct rt6_info *rt = NULL; + struct net_device *dev = NULL; +@@ -1125,7 +1125,7 @@ + */ + if ((cfg->fc_flags & RTF_REJECT) || + (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + + /* hold loopback dev/idev if we haven't done so. */ + if (dev != net->loopback_dev) { +@@ -1832,7 +1832,7 @@ + const struct in6_addr *addr, + int anycast) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct rt6_info *rt = ip6_dst_alloc(); + + if (rt == NULL) +@@ -2140,7 +2140,7 @@ + if (rt->u.dst.dev) { + struct net_device *odev = rt->rt6i_dev; + if (rt == &ip6_null_entry) +- odev = get_exec_env()->ve_ns->net_ns->loopback_dev; ++ odev = get_exec_env()->ve_netns->loopback_dev; + NLA_PUT_U32(skb, RTA_OIF, odev->ifindex); + } + +@@ -2250,7 +2250,7 @@ + + void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = get_exec_env()->ve_netns; + struct sk_buff *skb; + u32 pid = 0, seq = 0; + struct nlmsghdr *nlh = NULL; +Index: kernel/net/ipv6/sit.c +=================================================================== +--- kernel.orig/net/ipv6/sit.c 2008-11-24 15:56:52.000000000 +0100 ++++ kernel/net/ipv6/sit.c 2008-11-24 16:08:08.000000000 +0100 +@@ -191,7 +191,7 @@ + int i; + for (i=1; i<100; i++) { + sprintf(name, "sit%d", i); +- if (__dev_get_by_name(get_exec_env()->ve_ns->net_ns, name) == NULL) ++ if (__dev_get_by_name(get_exec_env()->ve_netns, name) == NULL) + break; + } + if (i==100) +@@ -201,7 +201,7 @@ + dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup); + if (dev == NULL) + return NULL; +- dev->nd_net = get_exec_env()->ve_ns->net_ns; ++ dev->nd_net = get_exec_env()->ve_netns; + nt = netdev_priv(dev); + dev->init = ipip6_tunnel_init; + nt->parms = *parms; +@@ -794,7 +794,7 @@ + } + + if (!tdev && tunnel->parms.link) +- tdev = __dev_get_by_index(get_exec_env()->ve_ns->net_ns, tunnel->parms.link); ++ tdev = __dev_get_by_index(get_exec_env()->ve_netns, tunnel->parms.link); + + if (tdev) { + dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); +@@ -876,7 +876,7 @@ + err = -ENOMEM; + goto free_tunnel; + } +- st->_ipip6_fb_tunnel_dev->nd_net = get_exec_env()->ve_ns->net_ns; ++ st->_ipip6_fb_tunnel_dev->nd_net = get_exec_env()->ve_netns; + st->_ipip6_fb_tunnel_dev->init = ipip6_fb_tunnel_init; + err = register_netdev(st->_ipip6_fb_tunnel_dev); + if (err < 0) +Index: kernel/net/netfilter/nf_conntrack_standalone.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_standalone.c 2008-11-24 16:02:16.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_standalone.c 2008-11-24 16:08:08.000000000 +0100 +@@ -303,7 +303,7 @@ + + static int nf_conntrack_init_ve_proc(struct ve_struct *ve) + { +- struct net *net = ve->ve_ns->net_ns; ++ struct net *net = ve->ve_netns; + struct proc_dir_entry *proc, *proc_stat; + int create_proc_net_stat_nf_conntrack = 1; + +@@ -330,7 +330,7 @@ + + static void nf_conntrack_fini_ve_proc(struct ve_struct *ve) + { +- struct net *net = ve->ve_ns->net_ns; ++ struct net *net = ve->ve_netns; + int remove_proc_net_stat_nf_conntrack = 1; + + #ifdef CONFIG_VE_IPTABLES +Index: kernel/net/netfilter/xt_hashlimit.c +=================================================================== +--- kernel.orig/net/netfilter/xt_hashlimit.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/netfilter/xt_hashlimit.c 2008-11-24 16:08:08.000000000 +0100 +@@ -748,7 +748,7 @@ + + static int init_xt_hashlimit(struct ve_struct *ve) + { +- struct proc_dir_entry *proc_net = ve->ve_ns->net_ns->proc_net; ++ struct proc_dir_entry *proc_net = ve->ve_netns->proc_net; + + #if defined(CONFIG_VE_IPTABLES) + if (ve->_xt_hashlimit) +@@ -788,7 +788,7 @@ + + static void fini_xt_hashlimit(struct ve_struct *ve) + { +- struct proc_dir_entry *proc_net = ve->ve_ns->net_ns->proc_net; ++ struct proc_dir_entry *proc_net = ve->ve_netns->proc_net; + + remove_proc_entry("ip6t_hashlimit", proc_net); + remove_proc_entry("ipt_hashlimit", proc_net); --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0011-CONNTACK-add-n-to-error-message.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0011-CONNTACK-add-n-to-error-message.patch @@ -0,0 +1,25 @@ +From 8544df2e3e8ebc6d028b8d2b12a2d296c3536fba Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 7 Mar 2008 12:23:39 +0300 +Subject: [PATCH 11/48] CONNTACK: add \n to error message + +--- + net/netfilter/nf_conntrack_expect.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c +index ccf3d50..c90024c 100644 +--- a/net/netfilter/nf_conntrack_expect.c ++++ b/net/netfilter/nf_conntrack_expect.c +@@ -375,7 +375,7 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect) + if (nf_ct_expect_count >= ve_nf_ct_expect_max) { + if (net_ratelimit()) + printk(KERN_WARNING +- "nf_conntrack: expectation table full"); ++ "nf_conntrack: expectation table full\n"); + ret = -EMFILE; + goto out; + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0124-VE-proc-devices.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0124-VE-proc-devices.patch @@ -0,0 +1,45 @@ +From dd0b4ed3b3484f5185b0b16ff3fbe4009362e178 Mon Sep 17 00:00:00 2001 +From: Vitaliy Gusev +Date: Fri, 18 Jul 2008 15:25:53 +0400 +Subject: [PATCH 124/131] VE proc devices + +Add empty /proc/devices to CT + +Some fancy tools are disappointed by its absence on the one hand, +but do not care for its content on the other. + +Bug #114847 +--- + fs/proc/proc_misc.c | 3 +++ + kernel/ve/veowner.c | 1 + + 2 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c +index 27bfda9..c69b817 100644 +--- a/fs/proc/proc_misc.c ++++ b/fs/proc/proc_misc.c +@@ -349,6 +349,9 @@ static int devinfo_show(struct seq_file *f, void *v) + + static void *devinfo_start(struct seq_file *f, loff_t *pos) + { ++ if (!ve_is_super(get_exec_env())) ++ return NULL; ++ + if (*pos < (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) + return pos; + return NULL; +diff --git a/kernel/ve/veowner.c b/kernel/ve/veowner.c +index b07bfb9..cee5765 100644 +--- a/kernel/ve/veowner.c ++++ b/kernel/ve/veowner.c +@@ -94,6 +94,7 @@ static void prepare_proc_misc(void) + "cmdline", + "vmstat", + "modules", ++ "devices", + NULL, + }; + char **p; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0158-Fix-wrong-size-of-ub0_percpu.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0158-Fix-wrong-size-of-ub0_percpu.patch @@ -0,0 +1,147 @@ +From a5a69260c66a4decfcb3d678821267a18addef67 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Tue, 7 Oct 2008 18:22:54 +0400 +Subject: [PATCH 158/158] Fix wrong size of ub0_percpu + +The struct percpu_data dynamically allocated and have array only for +1 cpu, so static usage of it does not work. + +Plus rework macros for static percpu variables declaration and +initialization. + +http://bugzilla.openvz.org/show_bug.cgi?id=1039 + +Singed-off-by: Konstantin Khlebnikov +Signed-off-by: Pavel Emelyanov +--- + include/linux/percpu.h | 21 +++++++++++++++++---- + kernel/bc/beancounter.c | 7 ++----- + kernel/sched.c | 8 ++------ + kernel/ve/ve.c | 15 ++++----------- + 4 files changed, 25 insertions(+), 26 deletions(-) + +Index: kernel/include/linux/percpu.h +=================================================================== +--- kernel.orig/include/linux/percpu.h 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/include/linux/percpu.h 2008-11-24 16:08:17.000000000 +0100 +@@ -49,11 +49,20 @@ + (__typeof__(ptr))__p->ptrs[(cpu)]; \ + }) + +-#define static_percpu_ptr(sptr, sptrs) ({ \ ++struct percpu_data_static { ++ void *ptrs[NR_CPUS]; ++}; ++ ++#define DEFINE_PER_CPU_STATIC(type, name) \ ++ static struct percpu_data_static per_cpu_data__##name; \ ++ static __typeof__(type) per_cpu__##name[NR_CPUS] ++ ++#define percpu_static_init(name) ({ \ + int i; \ + for (i = 0; i < NR_CPUS; i++) \ +- (sptr)->ptrs[i] = &(sptrs)[i]; \ +- (void *)__percpu_disguise(sptr); \ ++ (per_cpu_data__##name).ptrs[i] = &(per_cpu__##name)[i];\ ++ (__typeof__(&(per_cpu__##name)[0])) \ ++ __percpu_disguise(&(per_cpu_data__##name));\ + }) + + extern void *percpu_populate(void *__pdata, size_t size, gfp_t gfp, int cpu); +@@ -67,7 +76,11 @@ + #else /* CONFIG_SMP */ + + #define percpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); }) +-#define static_percpu_ptr(sptr, sptrs) (&sptrs[0]) ++ ++#define DEFINE_PER_CPU_STATIC(type, name) \ ++ static __typeof__(type) per_cpu__##name[NR_CPUS] ++ ++#define percpu_static_init(name) (&(per_cpu__##name)[0]) + + static inline void percpu_depopulate(void *__pdata, int cpu) + { +Index: kernel/kernel/bc/beancounter.c +=================================================================== +--- kernel.orig/kernel/bc/beancounter.c 2008-11-24 16:00:49.000000000 +0100 ++++ kernel/kernel/bc/beancounter.c 2008-11-24 16:08:17.000000000 +0100 +@@ -651,10 +651,7 @@ + ub->ub_limit_rl.interval = 300*HZ; + } + +-#ifdef CONFIG_SMP +-static struct percpu_data ub0_percpu; +-#endif +-static struct ub_percpu_struct ub0_percpu_data[NR_CPUS]; ++DEFINE_PER_CPU_STATIC(struct ub_percpu_struct, ub0_percpu); + + void __init ub_init_early(void) + { +@@ -667,7 +664,7 @@ + init_beancounter_nolimits(ub); + init_beancounter_store(ub); + init_beancounter_struct(ub); +- ub->ub_percpu = static_percpu_ptr(&ub0_percpu, ub0_percpu_data); ++ ub->ub_percpu = percpu_static_init(ub0_percpu); + + memset(¤t->task_bc, 0, sizeof(struct task_beancounter)); + (void)set_exec_ub(ub); +Index: kernel/kernel/sched.c +=================================================================== +--- kernel.orig/kernel/sched.c 2008-11-24 16:01:59.000000000 +0100 ++++ kernel/kernel/sched.c 2008-11-24 16:08:17.000000000 +0100 +@@ -385,10 +385,7 @@ + #endif + } + +-#ifdef CONFIG_SMP +-static struct percpu_data kstat_lat_pcpu_stats; +-#endif +-static struct kstat_lat_pcpu_snap_struct kstat_lat_pcpu_stats_data[NR_CPUS]; ++DEFINE_PER_CPU_STATIC(struct kstat_lat_pcpu_snap_struct, kstat_lat); + struct kernel_stat_glob kstat_glob; + + DEFINE_SPINLOCK(kstat_glb_lock); +@@ -7172,8 +7169,7 @@ + int highest_cpu = 0; + int i, j; + +- kstat_glob.sched_lat.cur = static_percpu_ptr(&kstat_lat_pcpu_stats, +- kstat_lat_pcpu_stats_data); ++ kstat_glob.sched_lat.cur = percpu_static_init(kstat_lat); + for_each_possible_cpu(i) { + struct rt_prio_array *array; + struct rq *rq; +Index: kernel/kernel/ve/ve.c +=================================================================== +--- kernel.orig/kernel/ve/ve.c 2008-11-24 16:08:08.000000000 +0100 ++++ kernel/kernel/ve/ve.c 2008-11-24 16:08:17.000000000 +0100 +@@ -118,13 +118,8 @@ + + EXPORT_SYMBOL(ve0); + +-#ifdef CONFIG_SMP +-static struct { +- void *ptrs[NR_CPUS]; +-} ve0_cpu_stats, ve0_lat_pcpu_stats; +-#endif +-static struct ve_cpu_stats ve0_cpu_stats_data[NR_CPUS]; +-static struct kstat_lat_pcpu_snap_struct ve0_lat_pcpu_stats_data[NR_CPUS]; ++DEFINE_PER_CPU_STATIC(struct ve_cpu_stats, ve0_cpu_stats); ++DEFINE_PER_CPU_STATIC(struct kstat_lat_pcpu_snap_struct, ve0_lat_stats); + + LIST_HEAD(ve_list_head); + rwlock_t ve_list_lock = RW_LOCK_UNLOCKED; +@@ -147,10 +142,8 @@ + (void)get_ve(ve); + atomic_set(&ve->pcounter, 1); + +- ve->cpu_stats = static_percpu_ptr(&ve0_cpu_stats, +- ve0_cpu_stats_data); +- ve->sched_lat_ve.cur = static_percpu_ptr(&ve0_lat_pcpu_stats, +- ve0_lat_pcpu_stats_data); ++ ve->cpu_stats = percpu_static_init(ve0_cpu_stats); ++ ve->sched_lat_ve.cur = percpu_static_init(ve0_lat_stats); + + list_add(&ve->ve_list, &ve_list_head); + } --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0112-UBC-cfq-data-queue-position.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0112-UBC-cfq-data-queue-position.patch @@ -0,0 +1,67 @@ +From d888beb1029e24f62c33424f8192bb0be3fde442 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 18 Jul 2008 15:25:45 +0400 +Subject: [PATCH 112/131] UBC cfq data queue position + +This patch eliminate BC IO overdose/underdose +after bc start, wakeup or iotime overlap. + +Queue position (cfq_bc_position) is a upper edge of previous active BC iotime. +Position updated at BC switch if it before new active BC iotime. + +BC enqueued according it's current iotime, +if it hit in interval position -/+ maximum slice, +otherwise iotime changed to queue position. +--- + include/linux/cfq-iosched.h | 1 + + kernel/bc/io_prio.c | 15 +++++++++++++++ + 2 files changed, 16 insertions(+), 0 deletions(-) + +diff --git a/include/linux/cfq-iosched.h b/include/linux/cfq-iosched.h +index 7f773a2..69c8943 100644 +--- a/include/linux/cfq-iosched.h ++++ b/include/linux/cfq-iosched.h +@@ -101,6 +101,7 @@ struct cfq_data { + unsigned int cfq_ub_slice; + unsigned long slice_begin; + unsigned long slice_end; ++ unsigned long cfq_bc_position; + int virt_mode; + int write_virt_mode; + }; +diff --git a/kernel/bc/io_prio.c b/kernel/bc/io_prio.c +index 9813a18..ef6982d 100644 +--- a/kernel/bc/io_prio.c ++++ b/kernel/bc/io_prio.c +@@ -220,6 +220,17 @@ static void bc_remove(struct cfq_data *cfqd, struct cfq_bc_data *cfq_bc) + + static void bc_enqueue(struct cfq_data *cfqd, struct cfq_bc_data *cfq_bc) + { ++ unsigned long iotime, slice, position; ++ ++ iotime = cfq_bc->cfq_bc_iotime; ++ slice = cfqd->cfq_ub_slice * 2; ++ position = cfqd->cfq_bc_position; ++ ++ /* adjust iotime to hit in interval position +/- maximum slice */ ++ if (bc_iotime_after(position, iotime + slice) ++ || bc_iotime_after(iotime, position + slice)) ++ cfq_bc->cfq_bc_iotime = position; ++ + bc_insert(cfqd, cfq_bc); + } + +@@ -261,6 +272,10 @@ static inline void bc_set_active(struct cfq_data *cfqd) + cfq_bc = rb_entry(rb_first(&cfqd->cfq_bc_queue), + struct cfq_bc_data, cfq_bc_node); + ++ /* adjust queue active position */ ++ if (bc_iotime_after(cfq_bc->cfq_bc_iotime, cfqd->cfq_bc_position)) ++ cfqd->cfq_bc_position = cfq_bc->cfq_bc_iotime; ++ + cfqd->active_cfq_bc = cfq_bc; + cfqd->slice_begin = now; + cfqd->slice_end = now + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0024-NETFILTER-fix-compilation-with-VE_IPTABLES-n.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0024-NETFILTER-fix-compilation-with-VE_IPTABLES-n.patch @@ -0,0 +1,57 @@ +From 191b730b9dd8ea3e55f8fe41baf22e9b549cc7ea Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Thu, 13 Mar 2008 20:05:08 +0300 +Subject: [PATCH 24/48] NETFILTER: fix compilation with VE_IPTABLES=n + +--- + net/ipv4/netfilter/ipt_recent.c | 2 ++ + net/ipv4/netfilter/nf_nat_core.c | 6 ++++-- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c +index cd85bf4..a6e4080 100644 +--- a/net/ipv4/netfilter/ipt_recent.c ++++ b/net/ipv4/netfilter/ipt_recent.c +@@ -517,7 +517,9 @@ static int init_ipt_recent(struct ve_struct *ve) + out: + return err; + out_mem: ++#ifdef CONFIG_VE_IPTABLES + kfree(ve->_ipt_recent); ++#endif + goto out; + } + +diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c +index c25715e..10b2f64 100644 +--- a/net/ipv4/netfilter/nf_nat_core.c ++++ b/net/ipv4/netfilter/nf_nat_core.c +@@ -659,13 +659,13 @@ int nf_nat_init(void) + ret = -ENOMEM; + goto cleanup_extend; + } +- ++#ifdef CONFIG_VE_IPTABLES + ve_nf_nat_protos = kcalloc(MAX_IP_NAT_PROTO, sizeof(void *), GFP_KERNEL); + if (!ve_nf_nat_protos) { + ret = -ENOMEM; + goto cleanup_hash; + } +- ++#endif + /* Sew in builtin protocols. */ + write_lock_bh(&nf_nat_lock); + for (i = 0; i < MAX_IP_NAT_PROTO; i++) +@@ -687,7 +687,9 @@ int nf_nat_init(void) + ve_nf_nat_l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); + return 0; + ++#ifdef CONFIG_VE_IPTABLES + cleanup_hash: ++#endif + nf_ct_free_hashtable(ve_bysource, ve_nf_nat_vmalloced, nf_nat_htable_size); + cleanup_extend: + nf_ct_extend_unregister(&nat_extend); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0062-ms-don-t-clear-afinfo-seq_fops-during-netns-stop.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0062-ms-don-t-clear-afinfo-seq_fops-during-netns-stop.patch @@ -0,0 +1,40 @@ +From ddaf8cd72814753b729bf7c6df1b9eaf07e4bafe Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Wed, 9 Apr 2008 18:23:02 +0400 +Subject: [PATCH 61/67] ms: don't clear afinfo->seq_fops during netns stop + +afinfo structures are shared, so netns shouldn't clear it for everyone. +This can result in situation when ->open won't be run, because it was +cleared, but ->read will be. +--- + net/ipv4/tcp_ipv4.c | 1 - + net/ipv4/udp.c | 1 - + 2 files changed, 0 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c +index 1a83482..2d132db 100644 +--- a/net/ipv4/tcp_ipv4.c ++++ b/net/ipv4/tcp_ipv4.c +@@ -2316,7 +2316,6 @@ void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo) + return; + + proc_net_remove(net, afinfo->name); +- memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); + } + + static void get_openreq4(struct sock *sk, struct request_sock *req, +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index a27ed8a..959ea53 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -1602,7 +1602,6 @@ void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo) + if (!afinfo) + return; + proc_net_remove(net, afinfo->name); +- memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); + } + + /* ------------------------------------------------------------------------ */ +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0133-CPT-SMP-race-in-detecting-state-of-ptraced-processes.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0133-CPT-SMP-race-in-detecting-state-of-ptraced-processes.patch @@ -0,0 +1,33 @@ +From 87490ee50be2cae1d07bc5e8d2c15cbff58a0d3f Mon Sep 17 00:00:00 2001 +From: Alexey Kuznetsov +Date: Thu, 15 May 2008 18:54:23 +0400 +Subject: [PATCH] CPT SMP race in detecting state of ptraced processes + +When suspending VE, we test state of processes while they are +still running. It is not a bug: we have to verify for invalid state +before checkpointing, real state is saved after processes are scheduled +out. + +The impact is that we can see process in a bad state, f.e. stopped +without any reasons. It is also not a bug, but this rersults in random +failures of checkpointing. The only way to fix this is to order updates +of state variables. The order is correct almost everywhere. +--- + kernel/signal.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/kernel/signal.c b/kernel/signal.c +index 10d8886..a2ea3a7 100644 +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -1822,6 +1822,7 @@ static int handle_group_stop(void) + */ + return 0; + ++ clear_pn_state(current); + /* + * There is a group stop in progress. We stop + * without any associated signal being in our queue. +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0030-NETFILTER-free-nat_protos-on-VE-stop.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0030-NETFILTER-free-nat_protos-on-VE-stop.patch @@ -0,0 +1,26 @@ +From 92d6607dfe0806f9eee3733e0bbf253d5ba2e1db Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 14 Mar 2008 17:12:10 +0300 +Subject: [PATCH 30/48] NETFILTER: free nat_protos on VE stop + +--- + net/ipv4/netfilter/nf_nat_core.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c +index 10b2f64..034ae79 100644 +--- a/net/ipv4/netfilter/nf_nat_core.c ++++ b/net/ipv4/netfilter/nf_nat_core.c +@@ -714,6 +714,9 @@ void nf_nat_cleanup(void) + synchronize_rcu(); + nf_ct_free_hashtable(ve_bysource, ve_nf_nat_vmalloced, nf_nat_htable_size); + nf_ct_l3proto_put(ve_nf_nat_l3proto); ++#ifdef CONFIG_VE_IPTABLES ++ kfree(ve_nf_nat_protos); ++#endif + if (ve_is_super(get_exec_env())) + nf_ct_extend_unregister(&nat_extend); + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0084-CPT-net-open-requests.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0084-CPT-net-open-requests.patch @@ -0,0 +1,128 @@ +From 67bf484b3dade2a0301e33a91d4469cd17979700 Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Mon, 30 Jun 2008 13:48:48 +0400 +Subject: [PATCH 084/103] CPT net open requests + +Open requests were saved and restored sometimes incorrectly: + +1. Family of open request was not saved (commented out) +2. Restore was broken, would crash because rsk_ops was cleared by memset. +3. And finally, all the coded restoring open requests was skipped. + +Tested with http_load. + +Bug #95113 +http://bugzilla.openvz.org/show_bug.cgi?id=784 +--- + include/net/tcp.h | 1 + + kernel/cpt/cpt_socket_in.c | 2 +- + kernel/cpt/rst_socket_in.c | 21 ++++++++++++++++++--- + net/ipv6/tcp_ipv6.c | 3 ++- + 4 files changed, 22 insertions(+), 5 deletions(-) + +Index: kernel/include/net/tcp.h +=================================================================== +--- kernel.orig/include/net/tcp.h 2008-11-24 15:59:46.000000000 +0100 ++++ kernel/include/net/tcp.h 2008-11-24 16:00:40.000000000 +0100 +@@ -1362,6 +1362,7 @@ + extern void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo); + + extern struct request_sock_ops tcp_request_sock_ops; ++extern struct request_sock_ops tcp6_request_sock_ops; + + extern int tcp_v4_destroy_sock(struct sock *sk); + +Index: kernel/kernel/cpt/cpt_socket_in.c +=================================================================== +--- kernel.orig/kernel/cpt/cpt_socket_in.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/kernel/cpt/cpt_socket_in.c 2008-11-24 16:00:40.000000000 +0100 +@@ -313,7 +313,7 @@ + v->cpt_snt_isn = tcp_rsk(req)->snt_isn; + v->cpt_rmt_port = inet_rsk(req)->rmt_port; + v->cpt_mss = req->mss; +- // // v->cpt_family = (req->class == &or_ipv4 ? AF_INET : AF_INET6); ++ v->cpt_family = req->rsk_ops->family; + v->cpt_retrans = req->retrans; + v->cpt_snd_wscale = inet_rsk(req)->snd_wscale; + v->cpt_rcv_wscale = inet_rsk(req)->rcv_wscale; +Index: kernel/kernel/cpt/rst_socket_in.c +=================================================================== +--- kernel.orig/kernel/cpt/rst_socket_in.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/kernel/cpt/rst_socket_in.c 2008-11-24 16:00:40.000000000 +0100 +@@ -400,7 +400,7 @@ + loff_t pos, struct cpt_context *ctx) + { + int err; +- loff_t end = si->cpt_next; ++ loff_t end = pos + si->cpt_next; + + pos += si->cpt_hdrlen; + while (pos < end) { +@@ -415,11 +415,21 @@ + } + + if (oi.cpt_object == CPT_OBJ_OPENREQ) { +- struct request_sock *req = reqsk_alloc(&tcp_request_sock_ops); ++ struct request_sock *req; ++ ++ if (oi.cpt_family == AF_INET6) { ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ req = reqsk_alloc(&tcp6_request_sock_ops); ++#else ++ return -EINVAL; ++#endif ++ } else { ++ req = reqsk_alloc(&tcp_request_sock_ops); ++ } ++ + if (req == NULL) + return -ENOMEM; + +- memset(req, 0, sizeof(*req)); + tcp_rsk(req)->rcv_isn = oi.cpt_rcv_isn; + tcp_rsk(req)->snt_isn = oi.cpt_snt_isn; + inet_rsk(req)->rmt_port = oi.cpt_rmt_port; +@@ -432,10 +442,14 @@ + inet_rsk(req)->wscale_ok = oi.cpt_wscale_ok; + inet_rsk(req)->ecn_ok = oi.cpt_ecn_ok; + inet_rsk(req)->acked = oi.cpt_acked; ++ inet_rsk(req)->opt = NULL; + req->window_clamp = oi.cpt_window_clamp; + req->rcv_wnd = oi.cpt_rcv_wnd; + req->ts_recent = oi.cpt_ts_recent; + req->expires = jiffies_import(oi.cpt_expires); ++ req->sk = NULL; ++ req->secid = 0; ++ req->peer_secid = 0; + + if (oi.cpt_family == AF_INET) { + memcpy(&inet_rsk(req)->loc_addr, oi.cpt_loc_addr, 4); +@@ -443,6 +457,7 @@ + inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); + } else { + #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ inet6_rsk(req)->pktopts = NULL; + memcpy(&inet6_rsk(req)->loc_addr, oi.cpt_loc_addr, 16); + memcpy(&inet6_rsk(req)->rmt_addr, oi.cpt_rmt_addr, 16); + inet6_rsk(req)->iif = oi.cpt_iif; +Index: kernel/net/ipv6/tcp_ipv6.c +=================================================================== +--- kernel.orig/net/ipv6/tcp_ipv6.c 2008-11-24 15:59:46.000000000 +0100 ++++ kernel/net/ipv6/tcp_ipv6.c 2008-11-24 16:00:40.000000000 +0100 +@@ -925,7 +925,7 @@ + } + #endif + +-static struct request_sock_ops tcp6_request_sock_ops __read_mostly = { ++struct request_sock_ops tcp6_request_sock_ops __read_mostly = { + .family = AF_INET6, + .obj_size = sizeof(struct tcp6_request_sock), + .rtx_syn_ack = tcp_v6_send_synack, +@@ -933,6 +933,7 @@ + .destructor = tcp_v6_reqsk_destructor, + .send_reset = tcp_v6_send_reset + }; ++EXPORT_SYMBOL(tcp6_request_sock_ops); + + #ifdef CONFIG_TCP_MD5SIG + static struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0125-VE-proc-task-state.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0125-VE-proc-task-state.patch @@ -0,0 +1,46 @@ +From 56f88e0d542d62ae5892a9a0e5538ac3e8304932 Mon Sep 17 00:00:00 2001 +From: Vitaliy Gusev +Date: Fri, 18 Jul 2008 15:25:54 +0400 +Subject: [PATCH 125/131] VE proc task state + +Show envID fields in /proc/self/status in VE. +Also show VPid, PNState, StopState, etc. + +http://bugzilla.openvz.org/show_bug.cgi?id=936 +--- + fs/proc/array.c | 19 +++++++++---------- + 1 files changed, 9 insertions(+), 10 deletions(-) + +diff --git a/fs/proc/array.c b/fs/proc/array.c +index 871badb..25f2d73 100644 +--- a/fs/proc/array.c ++++ b/fs/proc/array.c +@@ -208,16 +208,15 @@ static inline char *task_state(struct task_struct *p, char *buffer) + buffer += sprintf(buffer, "\n"); + + #ifdef CONFIG_VE +- if (ve_is_super(get_exec_env())) +- buffer += sprintf(buffer, +- "envID:\t%d\n" +- "VPid:\t%d\n" +- "PNState:\t%u\n" +- "StopState:\t%u\n", +- p->ve_task_info.owner_env->veid, +- task_pid_vnr(p), +- p->pn_state, +- p->stopped_state); ++ buffer += sprintf(buffer, ++ "envID:\t%d\n" ++ "VPid:\t%d\n" ++ "PNState:\t%u\n" ++ "StopState:\t%u\n", ++ p->ve_task_info.owner_env->veid, ++ task_pid_vnr(p), ++ p->pn_state, ++ p->stopped_state); + #endif + return buffer; + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0140-VZDQ-correct-size-on-proc-vz-aquota-aquota.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0140-VZDQ-correct-size-on-proc-vz-aquota-aquota.patch @@ -0,0 +1,50 @@ +From bcba535278b993cc23e1abb7ecd4ef9d1a611967 Mon Sep 17 00:00:00 2001 +From: Vasily Tarasov +Date: Thu, 15 May 2008 18:52:00 +0400 +Subject: [PATCH] VZDQ correct size on /proc/vz/aquota/*/aquota.* + +Bug #59920 + +Signed-off-by: Vasily Tarasov +Signed-off-by: Denis Lunev +--- + fs/vzdq_file.c | 16 +++++++++++++++- + 1 files changed, 15 insertions(+), 1 deletions(-) + +diff --git a/fs/vzdq_file.c b/fs/vzdq_file.c +index f63689a..ac3aeb0 100644 +--- a/fs/vzdq_file.c ++++ b/fs/vzdq_file.c +@@ -520,6 +520,8 @@ static int vzdq_aquotq_looktest(struct inode *inode, void *data) + static int vzdq_aquotq_lookset(struct inode *inode, void *data) + { + struct vzdq_aquotq_lookdata *d; ++ struct super_block *sb; ++ struct quotatree_data qtd; + struct quotatree_tree *tree; + + d = data; +@@ -535,7 +537,19 @@ static int vzdq_aquotq_lookset(struct inode *inode, void *data) + vzdq_aquot_setidev(inode, d->dev); + + /* Setting size */ +- tree = QUGID_TREE(d->qmblk, PROC_I(inode)->fd - 1); ++ sb = user_get_super(d->dev); ++ if (sb == NULL) ++ return -ENODEV; ++ qtd.qmblk = vzquota_find_qmblk(sb); ++ drop_super(sb); ++ ++ if (qtd.qmblk == NULL) ++ return -ESRCH; ++ if (qtd.qmblk == VZ_QUOTA_BAD) ++ return -EIO; ++ ++ qtd.type = PROC_I(inode)->fd - 1; ++ tree = QUGID_TREE(qtd.qmblk, qtd.type); + inode->i_size = get_block_num(tree) * 1024; + return 0; + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0154-MS-NETNS-sk_release_kernel-needs-to-be-exported-to-m.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0154-MS-NETNS-sk_release_kernel-needs-to-be-exported-to-m.patch @@ -0,0 +1,31 @@ +From 9f911a8444d69b0fe3d2927b66c4aaf1c1c6f5bb Mon Sep 17 00:00:00 2001 +From: David S. Miller +Date: Fri, 29 Feb 2008 11:33:19 -0800 +Subject: [PATCH] MS NETNS sk_release_kernel needs to be exported to modules + +mainsteam commit 45af1754bc09926b5e062bda24f789d7b320939f + +Fixes: + +ERROR: "sk_release_kernel" [net/ipv6/ipv6.ko] undefined! + +Signed-off-by: David S. Miller +--- + net/core/sock.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/net/core/sock.c b/net/core/sock.c +index df11bc7..01e6d56 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -995,6 +995,7 @@ void sk_release_kernel(struct sock *sk) + sk->sk_net = get_net(&init_net); + sock_put(sk); + } ++EXPORT_SYMBOL(sk_release_kernel); + + struct sock *sk_clone(const struct sock *sk, const gfp_t priority) + { +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0020-FAIRSCHED-wire-up-sys_fairsched_-system-calls.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0020-FAIRSCHED-wire-up-sys_fairsched_-system-calls.patch @@ -0,0 +1,207 @@ +From 4f2c64dd3f5f39789adb85ab01c544f523bce66c Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Wed, 12 Mar 2008 18:13:20 +0300 +Subject: [PATCH 20/48] FAIRSCHED: wire up sys_fairsched_* system calls + +--- + arch/ia64/kernel/entry.S | 8 +++++++- + arch/sparc64/kernel/systbls.S | 24 ++++++++++++++++++++++-- + arch/x86/kernel/syscall_table_32.S | 12 +++++++++++- + include/asm-ia64/unistd.h | 6 ++++++ + include/asm-powerpc/systbl.h | 15 +++++++++++++-- + include/asm-x86/unistd_32.h | 6 ++++++ + include/asm-x86/unistd_64.h | 12 ++++++++++++ + 7 files changed, 77 insertions(+), 6 deletions(-) + +diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S +index f5008ef..1a76acf 100644 +--- a/arch/ia64/kernel/entry.S ++++ b/arch/ia64/kernel/entry.S +@@ -1684,9 +1684,15 @@ sys_call_table: + data8 sys_signalfd + data8 sys_timerfd + data8 sys_eventfd +-.rept 1505-1310 ++.rept 1499-1310 + data8 sys_ni_syscall + .endr ++ data8 sys_fairsched_vcpus ++ data8 sys_fairsched_mknod // 1500 ++ data8 sys_fairsched_rmnod ++ data8 sys_fairsched_chwt ++ data8 sys_fairsched_mvpr ++ data8 sys_fairsched_rate + data8 sys_getluid // 1505 + data8 sys_setluid + data8 sys_setublimit +diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S +index d404e20..4155962 100644 +--- a/arch/sparc64/kernel/systbls.S ++++ b/arch/sparc64/kernel/systbls.S +@@ -82,9 +82,19 @@ sys_call_table32: + .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait + /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd, compat_sys_fallocate + +- .rept 510-303 ++ .rept 500-315 + .word sys_nis_syscall + .endr ++ .word sys_fairsched_mknod /* 500 */ ++ .word sys_fairsched_rmnod ++ .word sys_fairsched_chwt ++ .word sys_fairsched_mvpr ++ .word sys_fairsched_rate ++ .word sys_nis_syscall /* 505 */ ++ .word sys_nis_syscall ++ .word sys_nis_syscall ++ .word sys_nis_syscall ++ .word sys_nis_syscall + .word sys_getluid /* 510 */ + .word sys_setluid + .word compat_sys_setublimit +@@ -162,9 +172,19 @@ sys_call_table: + .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait + /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate + +- .rept 510-303 ++ .rept 500-315 + .word sys_nis_syscall + .endr ++ .word sys_fairsched_mknod /* 500 */ ++ .word sys_fairsched_rmnod ++ .word sys_fairsched_chwt ++ .word sys_fairsched_mvpr ++ .word sys_fairsched_rate ++ .word sys_nis_syscall /* 505 */ ++ .word sys_nis_syscall ++ .word sys_nis_syscall ++ .word sys_nis_syscall ++ .word sys_nis_syscall + .word sys_getluid /* 510 */ + .word sys_setluid + .word sys_setublimit +diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S +index 13d6963..13c932d 100644 +--- a/arch/x86/kernel/syscall_table_32.S ++++ b/arch/x86/kernel/syscall_table_32.S +@@ -324,9 +324,19 @@ ENTRY(sys_call_table) + .long sys_timerfd + .long sys_eventfd + .long sys_fallocate +- .rept 510-(.-sys_call_table)/4 ++ .rept 500-(.-sys_call_table)/4 + .long sys_ni_syscall + .endr ++ .long sys_fairsched_mknod /* 500 */ ++ .long sys_fairsched_rmnod ++ .long sys_fairsched_chwt ++ .long sys_fairsched_mvpr ++ .long sys_fairsched_rate ++ .long sys_fairsched_vcpus /* 505 */ ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_ni_syscall + .long sys_getluid /* 510 */ + .long sys_setluid + .long sys_setublimit +diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h +index 0097a22..4deeaf5 100644 +--- a/include/asm-ia64/unistd.h ++++ b/include/asm-ia64/unistd.h +@@ -299,6 +299,12 @@ + #define __NR_signalfd 1307 + #define __NR_timerfd 1308 + #define __NR_eventfd 1309 ++#define __NR_fairsched_vcpus 1499 ++#define __NR_fairsched_mknod 1500 ++#define __NR_fairsched_rmnod 1501 ++#define __NR_fairsched_chwt 1502 ++#define __NR_fairsched_mvpr 1503 ++#define __NR_fairsched_rate 1504 + #define __NR_getluid 1505 + #define __NR_setluid 1506 + #define __NR_setublimit 1507 +diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h +index 18b575d..6d1a440 100644 +--- a/include/asm-powerpc/systbl.h ++++ b/include/asm-powerpc/systbl.h +@@ -303,7 +303,7 @@ SYSCALL_SPU(readlinkat) + SYSCALL_SPU(fchmodat) + SYSCALL_SPU(faccessat) + COMPAT_SYS_SPU(get_robust_list) +-COMPAT_SYS_SPU(set_robust_list) ++COMPAT_SYS_SPU(set_robust_list) /* 300 */ + COMPAT_SYS_SPU(move_pages) + SYSCALL_SPU(getcpu) + COMPAT_SYS(epoll_pwait) +@@ -313,7 +313,18 @@ COMPAT_SYS_SPU(timerfd) + SYSCALL_SPU(eventfd) + COMPAT_SYS_SPU(sync_file_range2) + COMPAT_SYS(fallocate) +-SYS_SKIP(302, 409) ++SYS_SKIP(310, 400) ++SYSCALL(ni_syscall) ++SYS_SKIP_END() ++SYSCALL(fairsched_mknod) /* 400 */ ++SYSCALL(fairsched_rmnod) ++SYSCALL(fairsched_chwt) ++SYSCALL(fairsched_mvpr) ++SYSCALL(fairsched_rate) ++SYSCALL(fairsched_vcpus) ++SYS_SKIP(406, 410) ++SYSCALL(ni_syscall) ++SYS_SKIP_END() + SYSCALL(getluid) /* 410 */ + SYSCALL(setluid) + SYSCALL(setublimit) +diff --git a/include/asm-x86/unistd_32.h b/include/asm-x86/unistd_32.h +index 1288555..5346ad6 100644 +--- a/include/asm-x86/unistd_32.h ++++ b/include/asm-x86/unistd_32.h +@@ -330,6 +330,12 @@ + #define __NR_timerfd 322 + #define __NR_eventfd 323 + #define __NR_fallocate 324 ++#define __NR_fairsched_mknod 500 /* FairScheduler syscalls */ ++#define __NR_fairsched_rmnod 501 ++#define __NR_fairsched_chwt 502 ++#define __NR_fairsched_mvpr 503 ++#define __NR_fairsched_rate 504 ++#define __NR_fairsched_vcpus 505 + #define __NR_getluid 510 + #define __NR_setluid 511 + #define __NR_setublimit 512 +diff --git a/include/asm-x86/unistd_64.h b/include/asm-x86/unistd_64.h +index 747becb..933cd81 100644 +--- a/include/asm-x86/unistd_64.h ++++ b/include/asm-x86/unistd_64.h +@@ -635,6 +635,8 @@ __SYSCALL(__NR_timerfd, sys_timerfd) + __SYSCALL(__NR_eventfd, sys_eventfd) + #define __NR_fallocate 285 + __SYSCALL(__NR_fallocate, sys_fallocate) ++#define __NR_fairsched_vcpus 499 ++__SYSCALL(__NR_fairsched_vcpus, sys_fairsched_vcpus) + #define __NR_getluid 500 + __SYSCALL(__NR_getluid, sys_getluid) + #define __NR_setluid 501 +@@ -643,6 +645,16 @@ __SYSCALL(__NR_setluid, sys_setluid) + __SYSCALL(__NR_setublimit, sys_setublimit) + #define __NR_ubstat 503 + __SYSCALL(__NR_ubstat, sys_ubstat) ++#define __NR_fairsched_mknod 504 /* FairScheduler syscalls */ ++__SYSCALL(__NR_fairsched_mknod, sys_fairsched_mknod) ++#define __NR_fairsched_rmnod 505 ++__SYSCALL(__NR_fairsched_rmnod, sys_fairsched_rmnod) ++#define __NR_fairsched_chwt 506 ++__SYSCALL(__NR_fairsched_chwt, sys_fairsched_chwt) ++#define __NR_fairsched_mvpr 507 ++__SYSCALL(__NR_fairsched_mvpr, sys_fairsched_mvpr) ++#define __NR_fairsched_rate 508 ++__SYSCALL(__NR_fairsched_rate, sys_fairsched_rate) + #define __NR_lchmod 509 + __SYSCALL(__NR_lchmod, sys_lchmod) + #define __NR_lutime 510 +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0033-NETFILTER-fix-ipv4-conntrack-structure-double-free.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0033-NETFILTER-fix-ipv4-conntrack-structure-double-free.patch @@ -0,0 +1,26 @@ +From 5dbe8ec3aebc0c282b41e45bdc93c9c00a2368d3 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 17 Mar 2008 14:38:48 +0300 +Subject: [PATCH 33/48] NETFILTER: fix ipv4 conntrack structure double free + +It's masked by it's NULLifying, but it's double free nonetheless. +--- + net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 2 -- + 1 files changed, 0 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +index bbbfee7..10e970b 100644 +--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c ++++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +@@ -452,8 +452,6 @@ static void nf_ct_proto_ipv4_sysctl_cleanup(void) + if (!ve_is_super(get_exec_env())) { + free_sysctl_clone(ve_nf_conntrack_l3proto_ipv4->ctl_table); + ve_nf_conntrack_l3proto_ipv4->ctl_table = NULL; +- kfree(ve_nf_conntrack_l3proto_ipv4); +- ve_nf_conntrack_l3proto_ipv4 = NULL; + } + } + #else +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0110-UBC-ioprio-queues-proc.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0110-UBC-ioprio-queues-proc.patch @@ -0,0 +1,77 @@ +From fef55b01df3e94fc42d42ebf5c93d50a1b9246fb Mon Sep 17 00:00:00 2001 +From: Pavel Emelianov +Date: Fri, 18 Jul 2008 15:25:43 +0400 +Subject: [PATCH 110/131] UBC ioprio queues proc + +Show BC IO scheduler activity in proc + +Things, that may be interested for a beancounter are: + + * the number of requests on the BC + * whether or not this BC is during a request dispatch + * whether or not this BC is active + +(all above is per-queue). + +Add the /proc/bc//ioprio_queues file with the information +described above. + + sda 1 DA + hda 0 + sda 2 +--- + kernel/bc/io_prio.c | 35 +++++++++++++++++++++++++++++++++++ + 1 files changed, 35 insertions(+), 0 deletions(-) + +diff --git a/kernel/bc/io_prio.c b/kernel/bc/io_prio.c +index 1a10af4..5dcb9bb 100644 +--- a/kernel/bc/io_prio.c ++++ b/kernel/bc/io_prio.c +@@ -292,9 +292,44 @@ static struct bc_proc_entry bc_ioprio_entry = { + .u.show = bc_ioprio_show, + }; + ++static int bc_ioprio_queue_show(struct seq_file *f, void *v) ++{ ++ struct user_beancounter *bc; ++ struct cfq_bc_data *cfq_bc; ++ ++ bc = seq_beancounter(f); ++ ++ read_lock_irq(&bc->iopriv.cfq_bc_list_lock); ++ list_for_each_entry(cfq_bc, &bc->iopriv.cfq_bc_head, cfq_bc_list) { ++ struct cfq_data *cfqd; ++ ++ cfqd = cfq_bc->cfqd; ++ seq_printf(f, "\t%-10s%6lu %c%c\n", ++ /* ++ * this per-bc -> queue-data -> queue -> device ++ * access is safe w/o additional locks, since ++ * all the stuff above dies in the order shown ++ * and we're holding the first element ++ */ ++ kobject_name(cfqd->queue->kobj.parent), ++ cfq_bc->rqnum, ++ cfq_bc->on_dispatch ? 'D' : ' ', ++ cfqd->active_cfq_bc == cfq_bc ? 'A' : ' '); ++ } ++ read_unlock_irq(&bc->iopriv.cfq_bc_list_lock); ++ ++ return 0; ++} ++ ++static struct bc_proc_entry bc_ioprio_queues_entry = { ++ .name = "ioprio_queues", ++ .u.show = bc_ioprio_queue_show, ++}; ++ + static int __init bc_ioprio_init(void) + { + bc_register_proc_entry(&bc_ioprio_entry); ++ bc_register_proc_entry(&bc_ioprio_queues_entry); + return 0; + } + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0008-CPT-reexport-sys_open.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0008-CPT-reexport-sys_open.patch @@ -0,0 +1,23 @@ +From 29ec264a595bb385ce4818a31a01987b3b31fd9c Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Tue, 4 Mar 2008 12:24:54 +0300 +Subject: [PATCH 08/48] CPT: reexport sys_open() + +http://bugzilla.openvz.org/show_bug.cgi?id=835 +--- + fs/open.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: kernel/fs/open.c +=================================================================== +--- kernel.orig/fs/open.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/fs/open.c 2008-11-24 15:56:46.000000000 +0100 +@@ -1102,7 +1102,7 @@ + prevent_tail_call(ret); + return ret; + } +-EXPORT_UNUSED_SYMBOL_GPL(sys_open); /* To be deleted for 2.6.25 */ ++EXPORT_SYMBOL_GPL(sys_open); + + asmlinkage long sys_openat(int dfd, const char __user *filename, int flags, + int mode) --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0146-MS-NETNS-make-rtnetlink-infrastructure-network-names.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0146-MS-NETNS-make-rtnetlink-infrastructure-network-names.patch @@ -0,0 +1,735 @@ +From b34c8029a35c63bb9a029482034f30358c0fdd56 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 6 Jun 2008 20:26:24 +0400 +Subject: [PATCH] MS NETNS make rtnetlink infrastructure network namespace aware + +mainline commit 97c53cacf00d1f5aa04adabfebcc806ca8b22b10 + tweaks to get +netns from either netdevice ot something else. + +http://bugzilla.openvz.org/show_bug.cgi?id=905 + +[NET]: Make rtnetlink infrastructure network namespace aware (v3) + +After this patch none of the netlink callback support anything +except the initial network namespace but the rtnetlink infrastructure +now handles multiple network namespaces. + +Changes from v2: +- IPv6 addrlabel processing + +Changes from v1: +- no need for special rtnl_unlock handling +- fixed IPv6 ndisc + +Signed-off-by: Denis V. Lunev +Signed-off-by: Eric W. Biederman +Signed-off-by: David S. Miller +--- + include/linux/rtnetlink.h | 8 +++--- + include/net/net_namespace.h | 3 ++ + net/bridge/br_netlink.c | 5 ++- + net/core/fib_rules.c | 6 +++- + net/core/neighbour.c | 5 ++- + net/core/rtnetlink.c | 64 +++++++++++++++++++++++++++++++++++------- + net/decnet/dn_dev.c | 4 +- + net/decnet/dn_route.c | 2 +- + net/decnet/dn_table.c | 4 +- + net/ipv4/devinet.c | 5 ++- + net/ipv4/fib_semantics.c | 5 ++- + net/ipv4/ipmr.c | 4 +- + net/ipv4/route.c | 3 +- + net/ipv6/addrconf.c | 18 +++++++----- + net/ipv6/ndisc.c | 6 +++- + net/ipv6/route.c | 9 +++--- + net/sched/act_api.c | 8 +++--- + net/sched/cls_api.c | 2 +- + net/sched/sch_api.c | 4 +- + net/wireless/wext.c | 5 +++- + 20 files changed, 116 insertions(+), 54 deletions(-) + +diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h +index 4e81836..ef94cff 100644 +--- a/include/linux/rtnetlink.h ++++ b/include/linux/rtnetlink.h +@@ -613,11 +613,11 @@ extern int __rtattr_parse_nested_compat(struct rtattr *tb[], int maxattr, + ({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ + __rtattr_parse_nested_compat(tb, max, rta, len); }) + +-extern int rtnetlink_send(struct sk_buff *skb, u32 pid, u32 group, int echo); +-extern int rtnl_unicast(struct sk_buff *skb, u32 pid); +-extern int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group, ++extern int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, u32 group, int echo); ++extern int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid); ++extern int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, + struct nlmsghdr *nlh, gfp_t flags); +-extern void rtnl_set_sk_err(u32 group, int error); ++extern void rtnl_set_sk_err(struct net *net, u32 group, int error); + extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics); + extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, + u32 id, u32 ts, u32 tsage, long expires, +diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h +index de8803e..78565bd 100644 +--- a/include/net/net_namespace.h ++++ b/include/net/net_namespace.h +@@ -10,6 +10,7 @@ + + struct proc_dir_entry; + struct net_device; ++struct sock; + struct net { + atomic_t count; /* To decided when the network + * namespace should be freed. +@@ -30,6 +31,8 @@ struct net { + struct hlist_head *dev_name_head; + struct hlist_head *dev_index_head; + ++ struct sock *rtnl; /* rtnetlink socket */ ++ + int ifindex; + + #ifdef CONFIG_VE +diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c +index da03338..af51000 100644 +--- a/net/bridge/br_netlink.c ++++ b/net/bridge/br_netlink.c +@@ -82,6 +82,7 @@ nla_put_failure: + */ + void br_ifinfo_notify(int event, struct net_bridge_port *port) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + struct sk_buff *skb; + int err = -ENOBUFS; + +@@ -97,10 +98,10 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port) + kfree_skb(skb); + goto errout; + } +- err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); ++ err = rtnl_notify(skb, net,0, RTNLGRP_LINK, NULL, GFP_ATOMIC); + errout: + if (err < 0) +- rtnl_set_sk_err(RTNLGRP_LINK, err); ++ rtnl_set_sk_err(net, RTNLGRP_LINK, err); + } + + /* +diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c +index 7167acd..39f8645 100644 +--- a/net/core/fib_rules.c ++++ b/net/core/fib_rules.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -574,6 +575,7 @@ static void notify_rule_change(int event, struct fib_rule *rule, + struct fib_rules_ops *ops, struct nlmsghdr *nlh, + u32 pid) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + struct sk_buff *skb; + int err = -ENOBUFS; + +@@ -588,10 +590,10 @@ static void notify_rule_change(int event, struct fib_rule *rule, + kfree_skb(skb); + goto errout; + } +- err = rtnl_notify(skb, pid, ops->nlgroup, nlh, GFP_KERNEL); ++ err = rtnl_notify(skb, net, pid, ops->nlgroup, nlh, GFP_KERNEL); + errout: + if (err < 0) +- rtnl_set_sk_err(ops->nlgroup, err); ++ rtnl_set_sk_err(net, ops->nlgroup, err); + } + + static void attach_rules(struct list_head *rules, struct net_device *dev) +diff --git a/net/core/neighbour.c b/net/core/neighbour.c +index 3900342..6e167a8 100644 +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -2521,6 +2521,7 @@ static inline size_t neigh_nlmsg_size(void) + + static void __neigh_notify(struct neighbour *n, int type, int flags) + { ++ struct net *net = n->dev->nd_net; + struct sk_buff *skb; + int err = -ENOBUFS; + +@@ -2535,10 +2536,10 @@ static void __neigh_notify(struct neighbour *n, int type, int flags) + kfree_skb(skb); + goto errout; + } +- err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); ++ err = rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); + errout: + if (err < 0) +- rtnl_set_sk_err(RTNLGRP_NEIGH, err); ++ rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); + } + + #ifdef CONFIG_ARPD +diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c +index 07740f4..9cb91f5 100644 +--- a/net/core/rtnetlink.c ++++ b/net/core/rtnetlink.c +@@ -60,7 +60,6 @@ struct rtnl_link + }; + + static DEFINE_MUTEX(rtnl_mutex); +-static struct sock *rtnl; + + void rtnl_lock(void) + { +@@ -458,8 +457,9 @@ size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size) + return ret; + } + +-int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) ++int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo) + { ++ struct sock *rtnl = net->rtnl; + int err = 0; + + NETLINK_CB(skb).dst_group = group; +@@ -471,14 +471,17 @@ int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) + return err; + } + +-int rtnl_unicast(struct sk_buff *skb, u32 pid) ++int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid) + { ++ struct sock *rtnl = net->rtnl; ++ + return nlmsg_unicast(rtnl, skb, pid); + } + +-int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group, ++int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, + struct nlmsghdr *nlh, gfp_t flags) + { ++ struct sock *rtnl = net->rtnl; + int report = 0; + + if (nlh) +@@ -487,8 +490,10 @@ int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group, + return nlmsg_notify(rtnl, skb, pid, group, report, flags); + } + +-void rtnl_set_sk_err(u32 group, int error) ++void rtnl_set_sk_err(struct net *net, u32 group, int error) + { ++ struct sock *rtnl = net->rtnl; ++ + netlink_set_err(rtnl, 0, group, error); + } + +@@ -1186,7 +1191,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) + kfree_skb(nskb); + goto errout; + } +- err = rtnl_unicast(nskb, NETLINK_CB(skb).pid); ++ err = rtnl_unicast(nskb, net, NETLINK_CB(skb).pid); + errout: + dev_put(dev); + +@@ -1221,6 +1226,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) + + void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) + { ++ struct net *net = dev->nd_net; + struct sk_buff *skb; + int err = -ENOBUFS; + +@@ -1235,10 +1241,10 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) + kfree_skb(skb); + goto errout; + } +- err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL); ++ err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL); + errout: + if (err < 0) +- rtnl_set_sk_err(RTNLGRP_LINK, err); ++ rtnl_set_sk_err(net, RTNLGRP_LINK, err); + } + + /* Protected by RTNL sempahore. */ +@@ -1249,6 +1255,7 @@ static int rtattr_max; + + static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) + { ++ struct net *net = skb->sk->sk_net; + rtnl_doit_func doit; + int sz_idx, kind; + int min_len; +@@ -1277,6 +1284,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) + return -EPERM; + + if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { ++ struct sock *rtnl; + rtnl_dumpit_func dumpit; + + dumpit = rtnl_get_dumpit(family, type); +@@ -1284,6 +1292,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) + return -EOPNOTSUPP; + + __rtnl_unlock(); ++ rtnl = net->rtnl; + err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); + rtnl_lock(); + return err; +@@ -1353,6 +1362,40 @@ static struct notifier_block rtnetlink_dev_notifier = { + .notifier_call = rtnetlink_event, + }; + ++ ++static int rtnetlink_net_init(struct net *net) ++{ ++ struct sock *sk; ++ sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX, ++ rtnetlink_rcv, &rtnl_mutex, THIS_MODULE); ++ if (!sk) ++ return -ENOMEM; ++ ++ /* Don't hold an extra reference on the namespace */ ++ put_net(sk->sk_net); ++ net->rtnl = sk; ++ return 0; ++} ++ ++static void rtnetlink_net_exit(struct net *net) ++{ ++ struct sock *sk = net->rtnl; ++ if (sk) { ++ /* At the last minute lie and say this is a socket for the ++ * initial network namespace. So the socket will be safe to ++ * free. ++ */ ++ sk->sk_net = get_net(&init_net); ++ sock_put(sk); ++ net->rtnl = NULL; ++ } ++} ++ ++static struct pernet_operations rtnetlink_net_ops = { ++ .init = rtnetlink_net_init, ++ .exit = rtnetlink_net_exit, ++}; ++ + void __init rtnetlink_init(void) + { + int i; +@@ -1365,10 +1408,9 @@ void __init rtnetlink_init(void) + if (!rta_buf) + panic("rtnetlink_init: cannot allocate rta_buf\n"); + +- rtnl = netlink_kernel_create(&init_net, NETLINK_ROUTE, RTNLGRP_MAX, +- rtnetlink_rcv, &rtnl_mutex, THIS_MODULE); +- if (rtnl == NULL) ++ if (register_pernet_subsys(&rtnetlink_net_ops)) + panic("rtnetlink_init: cannot initialize rtnetlink\n"); ++ + netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); + register_netdevice_notifier(&rtnetlink_dev_notifier); + +diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c +index 3bc82dc..00d5b85 100644 +--- a/net/decnet/dn_dev.c ++++ b/net/decnet/dn_dev.c +@@ -785,10 +785,10 @@ static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa) + kfree_skb(skb); + goto errout; + } +- err = rtnl_notify(skb, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL); ++ err = rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL); + errout: + if (err < 0) +- rtnl_set_sk_err(RTNLGRP_DECnet_IFADDR, err); ++ rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_IFADDR, err); + } + + static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) +diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c +index 0e10ff2..d3ab88d 100644 +--- a/net/decnet/dn_route.c ++++ b/net/decnet/dn_route.c +@@ -1594,7 +1594,7 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void + goto out_free; + } + +- return rtnl_unicast(skb, NETLINK_CB(in_skb).pid); ++ return rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid); + + out_free: + kfree_skb(skb); +diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c +index fda0772..8beab0d 100644 +--- a/net/decnet/dn_table.c ++++ b/net/decnet/dn_table.c +@@ -375,10 +375,10 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id, + kfree_skb(skb); + goto errout; + } +- err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL); ++ err = rtnl_notify(skb, &init_net, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL); + errout: + if (err < 0) +- rtnl_set_sk_err(RTNLGRP_DECnet_ROUTE, err); ++ rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_ROUTE, err); + } + + static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb, +diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c +index 8f1f229..d26e56c 100644 +--- a/net/ipv4/devinet.c ++++ b/net/ipv4/devinet.c +@@ -1221,6 +1221,7 @@ done: + static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, + u32 pid) + { ++ struct net *net = ifa->ifa_dev->dev->nd_net; + struct sk_buff *skb; + u32 seq = nlh ? nlh->nlmsg_seq : 0; + int err = -ENOBUFS; +@@ -1236,10 +1237,10 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, + kfree_skb(skb); + goto errout; + } +- err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL); ++ err = rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL); + errout: + if (err < 0) +- rtnl_set_sk_err(RTNLGRP_IPV4_IFADDR, err); ++ rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err); + } + + #ifdef CONFIG_SYSCTL +diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c +index bf95051..de7a06f 100644 +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -325,6 +325,7 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, + int dst_len, u32 tb_id, struct nl_info *info, + unsigned int nlm_flags) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + struct sk_buff *skb; + u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; + int err = -ENOBUFS; +@@ -342,11 +343,11 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, + kfree_skb(skb); + goto errout; + } +- err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE, ++ err = rtnl_notify(skb, net, info->pid, RTNLGRP_IPV4_ROUTE, + info->nlh, GFP_KERNEL); + errout: + if (err < 0) +- rtnl_set_sk_err(RTNLGRP_IPV4_ROUTE, err); ++ rtnl_set_sk_err(net, RTNLGRP_IPV4_ROUTE, err); + } + + /* Return the first fib alias matching TOS with +diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c +index 255e206..1cb6670 100644 +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -323,7 +323,7 @@ static void ipmr_destroy_unres(struct mfc_cache *c) + e->error = -ETIMEDOUT; + memset(&e->msg, 0, sizeof(e->msg)); + +- rtnl_unicast(skb, NETLINK_CB(skb).pid); ++ rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid); + } else + kfree_skb(skb); + } +@@ -535,7 +535,7 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c) + memset(&e->msg, 0, sizeof(e->msg)); + } + +- rtnl_unicast(skb, NETLINK_CB(skb).pid); ++ rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid); + } else + ip_mr_forward(skb, c, 0); + } +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index dfd7dd0..b924a30 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -2697,6 +2697,7 @@ nla_put_failure: + + static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) + { ++ struct net *net = in_skb->sk->sk_net; + struct rtmsg *rtm; + struct nlattr *tb[RTA_MAX+1]; + struct rtable *rt = NULL; +@@ -2776,7 +2777,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void + if (err <= 0) + goto errout_free; + +- err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); ++ err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid); + errout: + return err; + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index ba5b3e3..f2b65ec 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -3425,6 +3425,7 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb) + static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, + void *arg) + { ++ struct net *net = in_skb->sk->sk_net; + struct ifaddrmsg *ifm; + struct nlattr *tb[IFA_MAX+1]; + struct in6_addr *addr = NULL; +@@ -3465,7 +3466,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, + kfree_skb(skb); + goto errout_ifa; + } +- err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); ++ err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid); + errout_ifa: + in6_ifa_put(ifa); + errout: +@@ -3474,6 +3475,7 @@ errout: + + static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) + { ++ struct net *net = ifa->idev->dev->nd_net; + struct sk_buff *skb; + int err = -ENOBUFS; + +@@ -3488,10 +3490,10 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) + kfree_skb(skb); + goto errout; + } +- err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); ++ err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); + errout: + if (err < 0) +- rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); ++ rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); + } + + static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, +@@ -3678,6 +3680,7 @@ cont: + + void inet6_ifinfo_notify(int event, struct inet6_dev *idev) + { ++ struct net *net = idev->dev->nd_net; + struct sk_buff *skb; + int err = -ENOBUFS; + +@@ -3692,10 +3695,10 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev) + kfree_skb(skb); + goto errout; + } +- err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); ++ err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); + errout: + if (err < 0) +- rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); ++ rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); + } + + static inline size_t inet6_prefix_nlmsg_size(void) +@@ -3747,6 +3750,7 @@ nla_put_failure: + static void inet6_prefix_notify(int event, struct inet6_dev *idev, + struct prefix_info *pinfo) + { ++ struct net *net = idev->dev->nd_net; + struct sk_buff *skb; + int err = -ENOBUFS; + +@@ -3761,10 +3765,10 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, + kfree_skb(skb); + goto errout; + } +- err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); ++ err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); + errout: + if (err < 0) +- rtnl_set_sk_err(RTNLGRP_IPV6_PREFIX, err); ++ rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err); + } + + static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) +diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c +index ce3bbc5..20f3b99 100644 +--- a/net/ipv6/ndisc.c ++++ b/net/ipv6/ndisc.c +@@ -1015,6 +1015,7 @@ out: + + static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) + { ++ struct net *net = ra->dev->nd_net; + struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra); + struct sk_buff *skb; + struct nlmsghdr *nlh; +@@ -1048,7 +1049,8 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) + &ipv6_hdr(ra)->saddr); + nlmsg_end(skb, nlh); + +- err = rtnl_notify(skb, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC); ++ err = rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, ++ GFP_ATOMIC); + if (err < 0) + goto errout; + +@@ -1058,7 +1060,7 @@ nla_put_failure: + nlmsg_free(skb); + err = -EMSGSIZE; + errout: +- rtnl_set_sk_err(RTNLGRP_ND_USEROPT, err); ++ rtnl_set_sk_err(&init_net, RTNLGRP_ND_USEROPT, err); + } + + static void ndisc_router_discovery(struct sk_buff *skb) +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 74c434b..ada957e 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -2176,7 +2176,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) + + static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) + { +- struct net *net = get_exec_env()->ve_ns->net_ns; ++ struct net *net = in_skb->sk->sk_net; + struct nlattr *tb[RTA_MAX+1]; + struct rt6_info *rt; + struct sk_buff *skb; +@@ -2243,13 +2243,14 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void + goto errout; + } + +- err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); ++ err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid); + errout: + return err; + } + + void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + struct sk_buff *skb; + u32 pid = 0, seq = 0; + struct nlmsghdr *nlh = NULL; +@@ -2273,10 +2274,10 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) + kfree_skb(skb); + goto errout; + } +- err = rtnl_notify(skb, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any()); ++ err = rtnl_notify(skb, net, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any()); + errout: + if (err < 0) +- rtnl_set_sk_err(RTNLGRP_IPV6_ROUTE, err); ++ rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err); + } + + /* +diff --git a/net/sched/act_api.c b/net/sched/act_api.c +index 72cdb0f..9b6ed89 100644 +--- a/net/sched/act_api.c ++++ b/net/sched/act_api.c +@@ -658,7 +658,7 @@ act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event) + return -EINVAL; + } + +- return rtnl_unicast(skb, pid); ++ return rtnl_unicast(skb, &init_net, pid); + } + + static struct tc_action * +@@ -779,7 +779,7 @@ static int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid) + nlh->nlmsg_flags |= NLM_F_ROOT; + module_put(a->ops->owner); + kfree(a); +- err = rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); ++ err = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + if (err > 0) + return 0; + +@@ -842,7 +842,7 @@ tca_action_gd(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int event) + + /* now do the delete */ + tcf_action_destroy(head, 0); +- ret = rtnetlink_send(skb, pid, RTNLGRP_TC, ++ ret = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, + n->nlmsg_flags&NLM_F_ECHO); + if (ret > 0) + return 0; +@@ -886,7 +886,7 @@ static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event, + nlh->nlmsg_len = skb_tail_pointer(skb) - b; + NETLINK_CB(skb).dst_group = RTNLGRP_TC; + +- err = rtnetlink_send(skb, pid, RTNLGRP_TC, flags&NLM_F_ECHO); ++ err = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, flags&NLM_F_ECHO); + if (err > 0) + err = 0; + return err; +diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c +index 0365797..7342edf 100644 +--- a/net/sched/cls_api.c ++++ b/net/sched/cls_api.c +@@ -355,7 +355,7 @@ static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n, + return -EINVAL; + } + +- return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); ++ return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + } + + struct tcf_dump_args +diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c +index 8ae137e..8f54bbb 100644 +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -863,7 +863,7 @@ static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, + } + + if (skb->len) +- return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); ++ return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + + err_out: + kfree_skb(skb); +@@ -1086,7 +1086,7 @@ static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, + return -EINVAL; + } + +- return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); ++ return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + } + + struct qdisc_dump_args +diff --git a/net/wireless/wext.c b/net/wireless/wext.c +index 47e80cc..db03ed5 100644 +--- a/net/wireless/wext.c ++++ b/net/wireless/wext.c +@@ -1137,7 +1137,7 @@ static void wireless_nlevent_process(unsigned long data) + struct sk_buff *skb; + + while ((skb = skb_dequeue(&wireless_nlevent_queue))) +- rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); ++ rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); + } + + static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); +@@ -1189,6 +1189,9 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) + struct sk_buff *skb; + int err; + ++ if (dev->nd_net != &init_net) ++ return; ++ + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!skb) + return; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0091-UBC-proc-nlink.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0091-UBC-proc-nlink.patch @@ -0,0 +1,66 @@ +From 7d73bf886255be04c87db19c31076dd282a849e0 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Mon, 30 Jun 2008 13:48:49 +0400 +Subject: [PATCH 091/103] UBC proc nlink + Override getattr callback on /proc/bc and ubc entries to get correct nlink. + +--- + kernel/bc/proc.c | 21 +++++++++++++++++++++ + 1 files changed, 21 insertions(+), 0 deletions(-) + +diff --git a/kernel/bc/proc.c b/kernel/bc/proc.c +index 433095f..caf4b1b 100644 +--- a/kernel/bc/proc.c ++++ b/kernel/bc/proc.c +@@ -601,6 +601,17 @@ static struct dentry *bc_entry_lookup(struct inode *dir, struct dentry *dentry, + return bc_lookup(ub, dir, dentry); + } + ++static int bc_entry_getattr(struct vfsmount *mnt, struct dentry *dentry, ++ struct kstat *stat) ++{ ++ struct user_beancounter *ub; ++ ++ generic_fillattr(dentry->d_inode, stat); ++ ub = (struct user_beancounter *)dentry->d_fsdata; ++ stat->nlink = ub->ub_childs + 2; ++ return 0; ++} ++ + static struct file_operations bc_entry_fops = { + .read = generic_read_dir, + .readdir = bc_entry_readdir, +@@ -608,6 +619,7 @@ static struct file_operations bc_entry_fops = { + + static struct inode_operations bc_entry_iops = { + .lookup = bc_entry_lookup, ++ .getattr = bc_entry_getattr, + }; + + /* +@@ -645,6 +657,14 @@ static struct dentry *bc_root_lookup(struct inode *dir, struct dentry *dentry, + return bc_lookup(ub, dir, dentry); + } + ++static int bc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, ++ struct kstat *stat) ++{ ++ generic_fillattr(dentry->d_inode, stat); ++ stat->nlink = ub_count + 2; ++ return 0; ++} ++ + static struct file_operations bc_root_fops = { + .read = generic_read_dir, + .readdir = bc_root_readdir, +@@ -652,6 +672,7 @@ static struct file_operations bc_root_fops = { + + static struct inode_operations bc_root_iops = { + .lookup = bc_root_lookup, ++ .getattr = bc_root_getattr, + }; + + static int __init ub_init_proc(void) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0104-VE-ipv6-ifdown-fix.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0104-VE-ipv6-ifdown-fix.patch @@ -0,0 +1,62 @@ +From 12a4a44de439ee8a91806c8aefef61059b26eb31 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 18 Jul 2008 14:46:33 +0400 +Subject: [PATCH 104/131] VE ipv6 ifdown fix + +Correct ipv6 ifdown at network namespace destroy. +--- + net/ipv6/addrconf.c | 24 ++++++++++++++++++++++++ + 1 files changed, 24 insertions(+), 0 deletions(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index c0ef49f..ba5b3e3 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -4315,6 +4315,25 @@ int unregister_inet6addr_notifier(struct notifier_block *nb) + + EXPORT_SYMBOL(unregister_inet6addr_notifier); + ++static void addrconf_net_exit(struct net *net) ++{ ++ struct net_device *dev; ++ ++ rtnl_lock(); ++ /* clean dev list */ ++ for_each_netdev(net, dev) { ++ if (__in6_dev_get(dev) == NULL) ++ continue; ++ addrconf_ifdown(dev, 1); ++ } ++ addrconf_ifdown(net->loopback_dev, 2); ++ rtnl_unlock(); ++} ++ ++static struct pernet_operations addrconf_net_ops = { ++ .exit = addrconf_net_exit, ++}; ++ + /* + * Init / cleanup code + */ +@@ -4362,6 +4381,10 @@ int __init addrconf_init(void) + ip6_blk_hole_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev); + #endif + ++ err = register_pernet_device(&addrconf_net_ops); ++ if (err) ++ return err; ++ + register_netdevice_notifier(&ipv6_dev_notf); + + addrconf_verify(0); +@@ -4397,6 +4420,7 @@ void __exit addrconf_cleanup(void) + int i; + + unregister_netdevice_notifier(&ipv6_dev_notf); ++ unregister_pernet_device(&addrconf_net_ops); + + #ifdef CONFIG_SYSCTL + addrconf_sysctl_unregister(&global_ipv6_devconf_dflt); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0075-ubc-drop-cpuset-lock-from-oom.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0075-ubc-drop-cpuset-lock-from-oom.patch @@ -0,0 +1,82 @@ +commit 5f318dd06be87f85073fb9d8a4c73c5554f08c31 +Author: Alexey Dobriyan +Date: Mon May 26 14:36:30 2008 +0400 + + UBC: drop cpuset lock from OOM handling + + cpuset_lock dances around OOM killing are gone in main code, so + no need to account for them. + + Mainline commit 3ff566963ce804809af9e32331b287eedeeff501 + Bug 112959 + + ===================================== + [ BUG: bad unlock balance detected! ] + ------------------------------------- + tstspoof/29391 is trying to release lock (callback_mutex) at: [] ub_oom_lock+0x9a/0xd6 + but there are no more locks to release! + other info that might help us debug this: + 1 lock held by tstspoof/29391: + #0: (&mm->mmap_sem){----}, at: [] do_page_fault+0x1d9/0x5fb + stack backtrace: + Pid: 29391, comm: tstspoof Not tainted 2.6.24-openvz #4 + [] print_unlock_inbalance_bug+0xe7/0xf3 + [] ub_oom_lock+0x9a/0xd6 + [] ktime_get_ts+0x16/0x44 + [] tick_program_event+0x33/0x52 + [] mark_held_locks+0x39/0x53 + [] restore_nocheck+0x12/0x15 + [] trace_hardirqs_on+0x122/0x145 + [] ub_oom_lock+0x9a/0xd6 + [] lock_release+0x148/0x16e + [] __mutex_unlock_slowpath+0xd3/0x140 + [] ub_oom_lock+0x9a/0xd6 + [] autoremove_wake_function+0x0/0x35 + [] out_of_memory+0x5d/0x177 + [] __alloc_pages+0xc3/0x38b + [] handle_mm_fault+0x226/0x87e + [] do_page_fault+0x1d9/0x5fb + [] do_page_fault+0x281/0x5fb + [] restore_nocheck+0x12/0x15 + [] do_page_fault+0x0/0x5fb + [] error_code+0x72/0x78 + +diff --git a/kernel/bc/oom_kill.c b/kernel/bc/oom_kill.c +index 6787750..f8a75c7 100644 +--- a/kernel/bc/oom_kill.c ++++ b/kernel/bc/oom_kill.c +@@ -37,7 +37,6 @@ static void ub_clear_oom(void) + rcu_read_unlock(); + } + +-/* Called with cpuset_lock held */ + int ub_oom_lock(void) + { + int timeout; +@@ -63,11 +62,9 @@ int ub_oom_lock(void) + __set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&oom_wq, &oom_w); + spin_unlock(&oom_lock); +- cpuset_unlock(); + + timeout = schedule_timeout(timeout); + +- cpuset_lock(); + spin_lock(&oom_lock); + remove_wait_queue(&oom_wq, &oom_w); + } +@@ -176,7 +173,6 @@ void ub_out_of_memory(struct user_beancounter *scope) + struct user_beancounter *ub; + struct task_struct *p; + +- cpuset_lock(); + spin_lock(&oom_lock); + ub_clear_oom(); + ub = get_beancounter(scope); +@@ -195,6 +191,5 @@ retry: + unlock: + read_unlock(&tasklist_lock); + spin_unlock(&oom_lock); +- cpuset_unlock(); + } + EXPORT_SYMBOL(ub_out_of_memory); --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0132-CPT-fix-EXIT_DEAD-TASK_DEAD-checks.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0132-CPT-fix-EXIT_DEAD-TASK_DEAD-checks.patch @@ -0,0 +1,41 @@ +From cdd141cddb559d5d7c235a0336da62194a5f429c Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 9 Jun 2008 20:06:27 +0400 +Subject: [PATCH] CPT fix EXIT_DEAD TASK_DEAD checks + +For one thing EXIT_DEAD was moved to ->exit_state only. +For another, this task state is called TASK_DEAD now and lives in ->state; +--- + kernel/cpt/cpt_process.c | 2 +- + kernel/cpt/rst_process.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kernel/cpt/cpt_process.c b/kernel/cpt/cpt_process.c +index 12e9bf1..0837fdf 100644 +--- a/kernel/cpt/cpt_process.c ++++ b/kernel/cpt/cpt_process.c +@@ -777,7 +777,7 @@ static int dump_one_process(cpt_object_t *obj, struct cpt_context *ctx) + } + if (tsk->exit_state) { + v->cpt_state = tsk->exit_state; +- if (tsk->state != EXIT_DEAD) { ++ if (tsk->state != TASK_DEAD) { + eprintk_ctx("invalid tsk->state %ld/%d on" CPT_FID "\n", + tsk->state, tsk->exit_state, CPT_TID(tsk)); + cpt_release_buf(ctx); +diff --git a/kernel/cpt/rst_process.c b/kernel/cpt/rst_process.c +index 2630538..5a893f5 100644 +--- a/kernel/cpt/rst_process.c ++++ b/kernel/cpt/rst_process.c +@@ -1630,7 +1630,7 @@ int rst_restore_process(struct cpt_context *ctx) + else if (ti->cpt_state & (EXIT_ZOMBIE|EXIT_DEAD)) { + tsk->signal->it_virt_expires = 0; + tsk->signal->it_prof_expires = 0; +- if (tsk->state != EXIT_DEAD) ++ if (tsk->state != TASK_DEAD) + eprintk_ctx("oops, schedule() did not make us dead\n"); + } + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0148-MS-NETNS-Double-free-in-netlink_release.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0148-MS-NETNS-Double-free-in-netlink_release.patch @@ -0,0 +1,51 @@ +From 00040a3ad6402c8493ad8a7c35d911da3e4204f3 Mon Sep 17 00:00:00 2001 +From: Denis V. Lunev +Date: Fri, 18 Jan 2008 23:53:31 -0800 +Subject: [PATCH] MS NETNS Double free in netlink_release + +mainstream commit 869e58f87094b1e8a0df49232e4a5172678d46c9 + +Netlink protocol table is global for all namespaces. Some netlink +protocols have been virtualized, i.e. they have per/namespace netlink +socket. This difference can easily lead to double free if more than 1 +namespace is started. Count the number of kernel netlink sockets to +track that this table is not used any more. + +Signed-off-by: Denis V. Lunev +Tested-by: Alexey Dobriyan +Signed-off-by: David S. Miller +--- + net/netlink/af_netlink.c | 10 +++++++--- + 1 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 4cb562d..fcdd345 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -486,9 +486,12 @@ static int netlink_release(struct socket *sock) + + netlink_table_grab(); + if (netlink_is_kernel(sk)) { +- kfree(nl_table[sk->sk_protocol].listeners); +- nl_table[sk->sk_protocol].module = NULL; +- nl_table[sk->sk_protocol].registered = 0; ++ BUG_ON(nl_table[sk->sk_protocol].registered == 0); ++ if (--nl_table[sk->sk_protocol].registered == 0) { ++ kfree(nl_table[sk->sk_protocol].listeners); ++ nl_table[sk->sk_protocol].module = NULL; ++ nl_table[sk->sk_protocol].registered = 0; ++ } + } else if (nlk->subscriptions) + netlink_update_listeners(sk); + netlink_table_ungrab(); +@@ -1393,6 +1396,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, + nl_table[unit].registered = 1; + } else { + kfree(listeners); ++ nl_table[unit].registered++; + } + netlink_table_ungrab(); + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0101-VE-proc-tossing-nlink-init.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0101-VE-proc-tossing-nlink-init.patch @@ -0,0 +1,45 @@ +From 8433ff061604f8d7d47d46882f6da59fe913737c Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Wed, 2 Jul 2008 19:55:20 +0400 +Subject: [PATCH 101/103] VE proc tossing nlink init + +Correct nlink counters at initial moving proc entries +between local and global trees. +--- + kernel/ve/veowner.c | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/kernel/ve/veowner.c b/kernel/ve/veowner.c +index abeb21d..b07bfb9 100644 +--- a/kernel/ve/veowner.c ++++ b/kernel/ve/veowner.c +@@ -68,6 +68,10 @@ static void proc_move(struct proc_dir_entry *ddir, + q->parent = ddir; + q->next = ddir->subdir; + ddir->subdir = q; ++ if (S_ISDIR(q->mode)) { ++ sdir->nlink--; ++ ddir->nlink++; ++ } + } + static void prepare_proc_misc(void) + { +@@ -107,6 +111,7 @@ int prepare_proc(void) + ve_root = ve0.proc_root->subdir; + /* move the whole tree to be visible in VE0 only */ + ve0.proc_root->subdir = proc_root.subdir; ++ ve0.proc_root->nlink += proc_root.nlink - 2; + for (de = ve0.proc_root->subdir; de->next != NULL; de = de->next) + de->parent = ve0.proc_root; + de->parent = ve0.proc_root; +@@ -114,6 +119,7 @@ int prepare_proc(void) + + /* move back into the global scope some specific entries */ + proc_root.subdir = NULL; ++ proc_root.nlink = 2; + prepare_proc_misc(); + proc_mkdir("vz", NULL); + #ifdef CONFIG_SYSVIPC +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0099-VE-ipv4-devconf-default.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0099-VE-ipv4-devconf-default.patch @@ -0,0 +1,30 @@ +From 24ee0c8feb02c4a53309a1ee30acddd7b10688bc Mon Sep 17 00:00:00 2001 +From: Pavel Emelianov +Date: Wed, 2 Jul 2008 19:55:20 +0400 +Subject: [PATCH 099/103] VE ipv4 devconf default + +Use per-VE ipv4_devconf_dflt for new devices +Otherwise, setting sys.ipv4.conf.default inside VE won't have +any effect and will confuse userspace. + +http://bugzilla.openvz.org/show_bug.cgi?id=826 +--- + net/ipv4/devinet.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c +index cbf3bee..8f1f229 100644 +--- a/net/ipv4/devinet.c ++++ b/net/ipv4/devinet.c +@@ -165,7 +165,7 @@ struct in_device *inetdev_init(struct net_device *dev) + if (!in_dev) + goto out; + INIT_RCU_HEAD(&in_dev->rcu_head); +- memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf)); ++ memcpy(&in_dev->cnf, &ve_ipv4_devconf_dflt, sizeof(in_dev->cnf)); + in_dev->cnf.sysctl = NULL; + in_dev->dev = dev; + if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0135-VE-IPv6-give-owner_ve-to-fib_table-and-fib6_local_ta.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0135-VE-IPv6-give-owner_ve-to-fib_table-and-fib6_local_ta.patch @@ -0,0 +1,34 @@ +From 115ea893b03ae5eab8a9186f83cbc06ae9e74efe Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 6 Jun 2008 20:20:58 +0400 +Subject: [PATCH] VE IPv6 give owner_ve to fib_table and fib6_local_table + +otherwise eventually fib6_clean_all will execute code in NULL context +which is no-no. +--- + net/ipv6/ip6_fib.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c +index b367550..0f9e611 100644 +--- a/net/ipv6/ip6_fib.c ++++ b/net/ipv6/ip6_fib.c +@@ -177,6 +177,7 @@ static struct fib6_table fib6_main_tbl = { + #ifdef CONFIG_VE + static inline void prepare_fib6_table(void) + { ++ fib6_main_tbl.owner_env = get_ve0(); + get_ve0()->_fib6_table = &fib6_main_tbl; + } + +@@ -233,6 +234,7 @@ static struct fib6_table fib6_local_tbl = { + #ifdef CONFIG_VE + static inline void prepare_fib6_local_table(void) + { ++ fib6_local_tbl.owner_env = get_ve0(); + get_ve0()->_fib6_local_table = &fib6_local_tbl; + } + #define fib6_local_tbl (*(get_exec_env())->_fib6_local_table) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0159-Fix-OOPS-while-stopping-VE-after-binfmt_misc.ko-load.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0159-Fix-OOPS-while-stopping-VE-after-binfmt_misc.ko-load.patch @@ -0,0 +1,32 @@ +From dd7d8b358930b07ab4047325fb27ce1da5510486 Mon Sep 17 00:00:00 2001 +From: Konstantin Ozerkov +Date: Thu, 13 Nov 2008 14:33:09 +0300 +Subject: [PATCH 159/159] Fix OOPS while stopping VE after binfmt_misc.ko loaded + +ve_binfmt_fini() should check if current VE have registered binfmt_misc fs. +(Properly handling situation while stopping VE which started before + binfmt_misc.ko loaded) + +http://bugzilla.openvz.org/show_bug.cgi?id=1028 + +Singed-off-by: Konstantin Khlebnikov +--- + fs/binfmt_misc.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c +index b91aaab..5bc2154 100644 +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -800,6 +800,8 @@ static void ve_binfmt_fini(void *x) + * no locks since exec_ve is dead and noone will + * mess with bm_xxx fields any longer + */ ++ if (!ve->bm_fs_type) ++ return; + dm_genocide(ve); + unregister_ve_fs_type(ve->bm_fs_type, NULL); + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0066-NETFILTER-fix-iptables-build-against-openvz-kernel.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0066-NETFILTER-fix-iptables-build-against-openvz-kernel.patch @@ -0,0 +1,48 @@ +From 12242e1c13001ab1345f4fa5cd2d074e07055819 Mon Sep 17 00:00:00 2001 +From: Peter Volkov +Date: Fri, 18 Apr 2008 19:54:54 +0400 +Subject: [PATCH 65/67] NETFILTER: fix iptables build against -openvz kernel headers + +http://bugzilla.openvz.org/show_bug.cgi?id=875 +--- + include/linux/netfilter/xt_hashlimit.h | 2 ++ + include/linux/netfilter_ipv4/ipt_recent.h | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/include/linux/netfilter/xt_hashlimit.h b/include/linux/netfilter/xt_hashlimit.h +index 934930b..9ef74c4 100644 +--- a/include/linux/netfilter/xt_hashlimit.h ++++ b/include/linux/netfilter/xt_hashlimit.h +@@ -38,9 +38,11 @@ struct xt_hashlimit_info { + } u; + }; + ++#ifdef __KERNEL__ + struct ve_xt_hashlimit { + struct hlist_head hashlimit_htables; + struct proc_dir_entry *hashlimit_procdir4; + struct proc_dir_entry *hashlimit_procdir6; + }; ++#endif + #endif /*_XT_HASHLIMIT_H*/ +diff --git a/include/linux/netfilter_ipv4/ipt_recent.h b/include/linux/netfilter_ipv4/ipt_recent.h +index 2ad01d9..4cc62b2 100644 +--- a/include/linux/netfilter_ipv4/ipt_recent.h ++++ b/include/linux/netfilter_ipv4/ipt_recent.h +@@ -24,10 +24,13 @@ struct ipt_recent_info { + u_int8_t side; + }; + ++#ifdef __KERNEL__ + struct ve_ipt_recent { + struct list_head tables; + #ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc_dir; + #endif + }; ++#endif ++ + #endif /*_IPT_RECENT_H*/ +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0043-ioprio-correct-emptyness-of-cfq_bc.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0043-ioprio-correct-emptyness-of-cfq_bc.patch @@ -0,0 +1,29 @@ +From 0dbdc45e3c9f940f8e360fae502a538d659f6a23 Mon Sep 17 00:00:00 2001 +From: Vasily Tarasov +Date: Thu, 20 Mar 2008 11:48:38 +0300 +Subject: [PATCH 43/48] ioprio: correct emptyness of cfq_bc + +While porting User Beancounters to 2.6.24 kernel, bc_empty() call was +forgotten, so in some cases I/O prioritization could not work properly. + +Signed-off-by: Vasily Tarasov +--- + kernel/bc/io_prio.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/kernel/bc/io_prio.c b/kernel/bc/io_prio.c +index 9407b38..20aa133 100644 +--- a/kernel/bc/io_prio.c ++++ b/kernel/bc/io_prio.c +@@ -204,7 +204,7 @@ static inline void bc_set_active(struct cfq_data *cfqd) + void bc_schedule_active(struct cfq_data *cfqd) + { + if (bc_expired(cfqd) || !cfqd->active_cfq_bc || +- !cfqd->active_cfq_bc->rqnum) ++ bc_empty(cfqd->active_cfq_bc)) + bc_set_active(cfqd); + } + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0072-FAIRSCHED-move-to-kernel-fairsched.c.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0072-FAIRSCHED-move-to-kernel-fairsched.c.patch @@ -0,0 +1,1333 @@ +From 0fb90a706d7b776e899e530a30c734fbcf427a26 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Wed, 30 Apr 2008 18:40:47 +0400 +Subject: [PATCH 71/72] FAIRSCHED: move to kernel/fairsched.c + +It was there before, so make patch application slightly easier. +--- + kernel/Makefile | 2 +- + kernel/fairsched.c | 648 ++++++++++++++++++++++++++++++++++++++++++++++++++ + kernel/vzfairsched.c | 648 -------------------------------------------------- + 3 files changed, 649 insertions(+), 649 deletions(-) + create mode 100644 kernel/fairsched.c + delete mode 100644 kernel/vzfairsched.c + +Index: kernel/kernel/Makefile +=================================================================== +--- kernel.orig/kernel/Makefile 2008-11-24 15:57:08.000000000 +0100 ++++ kernel/kernel/Makefile 2008-11-24 16:00:10.000000000 +0100 +@@ -62,7 +62,7 @@ + obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o + obj-$(CONFIG_MARKERS) += marker.o + obj-$(CONFIG_LATENCYTOP) += latencytop.o +-obj-$(CONFIG_VZ_FAIRSCHED) += vzfairsched.o ++obj-$(CONFIG_VZ_FAIRSCHED) += fairsched.o + + ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) + # According to Alan Modra , the -fno-omit-frame-pointer is +Index: kernel/kernel/fairsched.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/fairsched.c 2008-11-24 16:00:10.000000000 +0100 +@@ -0,0 +1,648 @@ ++/* ++ * Fair Scheduler ++ * ++ * Copyright (C) 2000-2008 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++struct fairsched_node fairsched_init_node = { ++ .id = FAIRSCHED_INIT_NODE_ID, ++ .tg = &init_task_group, ++#ifdef CONFIG_VE ++ .owner_env = get_ve0(), ++#endif ++ .weight = 1, ++}; ++ ++static DEFINE_MUTEX(fairsched_mutex); ++ ++/* list protected with fairsched_mutex */ ++static LIST_HEAD(fairsched_node_head); ++static int fairsched_nr_nodes; ++ ++void __init fairsched_init_early(void) ++{ ++ list_add(&fairsched_init_node.nodelist, &fairsched_node_head); ++ fairsched_nr_nodes++; ++} ++ ++#define FSCHWEIGHT_BASE 512000 ++ ++/****************************************************************************** ++ * cfs group shares = FSCHWEIGHT_BASE / fairsched weight ++ * ++ * vzctl cpuunits default 1000 ++ * cfs shares default value is 1024 (see init_task_group_load in sched.c) ++ * cpuunits = 1000 --> weight = 500000 / cpuunits = 500 --> shares = 1024 ++ * ^--- from vzctl ++ * weight in 1..65535 --> shares in 7..512000 ++ * shares should be >1 (see comment in sched_group_set_shares function) ++ *****************************************************************************/ ++ ++static struct fairsched_node *fairsched_find(unsigned int id) ++{ ++ struct fairsched_node *p; ++ list_for_each_entry(p, &fairsched_node_head, nodelist) { ++ if (p->id == id) ++ return p; ++ } ++ return NULL; ++} ++ ++/****************************************************************************** ++ * System calls ++ * ++ * All do_xxx functions are called under fairsched mutex and after ++ * capability check. ++ * ++ * The binary interfaces follow some other Fair Scheduler implementations ++ * (although some system call arguments are not needed for our implementation). ++ *****************************************************************************/ ++ ++static int do_fairsched_mknod(unsigned int parent, unsigned int weight, ++ unsigned int newid) ++{ ++ struct fairsched_node *node; ++ int retval; ++ ++ retval = -EINVAL; ++ if (weight < 1 || weight > FSCHWEIGHT_MAX) ++ goto out; ++ if (newid < 0 || newid > INT_MAX) ++ goto out; ++ ++ retval = -EBUSY; ++ if (fairsched_find(newid) != NULL) ++ goto out; ++ ++ retval = -ENOMEM; ++ node = kzalloc(sizeof(*node), GFP_KERNEL); ++ if (node == NULL) ++ goto out; ++ ++ node->tg = sched_create_group(); ++ if (IS_ERR(node->tg)) ++ goto out_free; ++ ++ node->id = newid; ++ node->weight = weight; ++ sched_group_set_shares(node->tg, FSCHWEIGHT_BASE / weight); ++#ifdef CONFIG_VE ++ node->owner_env = get_exec_env(); ++#endif ++ list_add(&node->nodelist, &fairsched_node_head); ++ fairsched_nr_nodes++; ++ ++ retval = newid; ++out: ++ return retval; ++ ++out_free: ++ kfree(node); ++ return retval; ++} ++ ++asmlinkage int sys_fairsched_mknod(unsigned int parent, unsigned int weight, ++ unsigned int newid) ++{ ++ int retval; ++ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ ++ mutex_lock(&fairsched_mutex); ++ retval = do_fairsched_mknod(parent, weight, newid); ++ mutex_unlock(&fairsched_mutex); ++ ++ return retval; ++} ++EXPORT_SYMBOL(sys_fairsched_mknod); ++ ++static int do_fairsched_rmnod(unsigned int id) ++{ ++ struct fairsched_node *node; ++ int retval; ++ ++ retval = -EINVAL; ++ node = fairsched_find(id); ++ if (node == NULL) ++ goto out; ++ if (node == &fairsched_init_node) ++ goto out; ++ ++ retval = -EBUSY; ++ if (node->refcnt) ++ goto out; ++ ++ list_del(&node->nodelist); ++ fairsched_nr_nodes--; ++ ++ sched_destroy_group(node->tg); ++ kfree(node); ++ retval = 0; ++out: ++ return retval; ++} ++ ++asmlinkage int sys_fairsched_rmnod(unsigned int id) ++{ ++ int retval; ++ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ ++ mutex_lock(&fairsched_mutex); ++ retval = do_fairsched_rmnod(id); ++ mutex_unlock(&fairsched_mutex); ++ ++ return retval; ++} ++EXPORT_SYMBOL(sys_fairsched_rmnod); ++ ++static int do_fairsched_chwt(unsigned int id, unsigned weight) ++{ ++ struct fairsched_node *node; ++ ++ if (id == 0) ++ return -EINVAL; ++ if (weight < 1 || weight > FSCHWEIGHT_MAX) ++ return -EINVAL; ++ ++ node = fairsched_find(id); ++ if (node == NULL) ++ return -ENOENT; ++ ++ node->weight = weight; ++ sched_group_set_shares(node->tg, FSCHWEIGHT_BASE / weight); ++ ++ return 0; ++} ++ ++asmlinkage int sys_fairsched_chwt(unsigned int id, unsigned weight) ++{ ++ int retval; ++ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ ++ mutex_lock(&fairsched_mutex); ++ retval = do_fairsched_chwt(id, weight); ++ mutex_unlock(&fairsched_mutex); ++ ++ return retval; ++} ++ ++static int do_fairsched_vcpus(unsigned int id, unsigned int vcpus) ++{ ++ struct fairsched_node *node; ++ ++ if (id == 0) ++ return -EINVAL; ++ ++ node = fairsched_find(id); ++ if (node == NULL) ++ return -ENOENT; ++ ++ return 0; ++} ++ ++asmlinkage int sys_fairsched_vcpus(unsigned int id, unsigned int vcpus) ++{ ++ int retval; ++ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ ++ mutex_lock(&fairsched_mutex); ++ retval = do_fairsched_vcpus(id, vcpus); ++ mutex_unlock(&fairsched_mutex); ++ ++ return retval; ++} ++EXPORT_SYMBOL(sys_fairsched_vcpus); ++ ++static int do_fairsched_rate(unsigned int id, int op, unsigned rate) ++{ ++ struct fairsched_node *node; ++ int retval; ++ ++ if (id == 0) ++ return -EINVAL; ++ if (op == FAIRSCHED_SET_RATE && (rate < 1 || rate >= (1UL << 31))) ++ return -EINVAL; ++ ++ node = fairsched_find(id); ++ if (node == NULL) ++ return -ENOENT; ++ ++ retval = -EINVAL; ++ switch (op) { ++ case FAIRSCHED_SET_RATE: ++ node->rate = rate; ++ node->rate_limited = 1; ++ retval = rate; ++ break; ++ case FAIRSCHED_DROP_RATE: ++ node->rate = 0; ++ node->rate_limited = 0; ++ retval = 0; ++ break; ++ case FAIRSCHED_GET_RATE: ++ if (node->rate_limited) ++ retval = node->rate; ++ else ++ retval = -ENODATA; ++ break; ++ } ++ return retval; ++} ++ ++asmlinkage int sys_fairsched_rate(unsigned int id, int op, unsigned rate) ++{ ++ int retval; ++ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ ++ mutex_lock(&fairsched_mutex); ++ retval = do_fairsched_rate(id, op, rate); ++ mutex_unlock(&fairsched_mutex); ++ ++ return retval; ++} ++ ++static int do_fairsched_mvpr(pid_t pid, unsigned int nodeid) ++{ ++ struct task_struct *p; ++ struct fairsched_node *node; ++ int retval; ++ unsigned flags; ++ ++ retval = -ENOENT; ++ node = fairsched_find(nodeid); ++ if (node == NULL) ++ goto out; ++ ++ write_lock_irqsave(&tasklist_lock, flags); ++ retval = -ESRCH; ++ p = find_task_by_pid(pid); ++ if (p == NULL) ++ goto out_unlock; ++ ++ get_task_struct(p); ++ put_task_fairsched_node(p); ++ p->fsched_node = node; ++ get_task_fairsched_node(p); ++ write_unlock_irqrestore(&tasklist_lock, flags); ++ ++ smp_wmb(); ++ sched_move_task(p); ++ put_task_struct(p); ++ return 0; ++ ++out_unlock: ++ write_unlock_irqrestore(&tasklist_lock, flags); ++out: ++ return retval; ++} ++ ++asmlinkage int sys_fairsched_mvpr(pid_t pid, unsigned int nodeid) ++{ ++ int retval; ++ ++ if (!capable(CAP_SETVEID)) ++ return -EPERM; ++ ++ mutex_lock(&fairsched_mutex); ++ retval = do_fairsched_mvpr(pid, nodeid); ++ mutex_unlock(&fairsched_mutex); ++ ++ return retval; ++} ++EXPORT_SYMBOL(sys_fairsched_mvpr); ++ ++#ifdef CONFIG_PROC_FS ++ ++/*********************************************************************/ ++/* ++ * proc interface ++ */ ++/*********************************************************************/ ++ ++#include ++#include ++#include ++ ++struct fairsched_node_dump { ++ int id; ++ unsigned weight; ++ unsigned rate; ++ int rate_limited; ++ int nr_pcpu; ++ int nr_tasks, nr_runtasks; ++}; ++ ++struct fairsched_dump { ++ int len; ++ struct fairsched_node_dump nodes[0]; ++}; ++ ++static struct fairsched_dump *fairsched_do_dump(int compat) ++{ ++ int nr_nodes; ++ int len; ++ struct fairsched_dump *dump; ++ struct fairsched_node *node; ++ struct fairsched_node_dump *p; ++ ++start: ++ nr_nodes = (ve_is_super(get_exec_env()) ? fairsched_nr_nodes + 16 : 1); ++ len = sizeof(*dump) + nr_nodes * sizeof(dump->nodes[0]); ++ dump = ub_vmalloc(len); ++ if (dump == NULL) ++ goto out; ++ ++ mutex_lock(&fairsched_mutex); ++ if (ve_is_super(get_exec_env()) && nr_nodes < fairsched_nr_nodes) ++ goto repeat; ++ p = dump->nodes; ++ list_for_each_entry_reverse(node, &fairsched_node_head, nodelist) { ++ if ((char *)p - (char *)dump >= len) ++ break; ++ p->nr_tasks = 0; ++ p->nr_runtasks = 0; ++#ifdef CONFIG_VE ++ if (!ve_accessible(node->owner_env, get_exec_env())) ++ continue; ++ p->nr_tasks = atomic_read(&node->owner_env->pcounter); ++ p->nr_runtasks = nr_running_ve(node->owner_env); ++#endif ++ p->id = node->id; ++ p->weight = node->weight; ++ p->rate = node->rate; ++ p->rate_limited = node->rate_limited; ++ p->nr_pcpu = num_online_cpus(); ++ p++; ++ } ++ dump->len = p - dump->nodes; ++ mutex_unlock(&fairsched_mutex); ++ ++out: ++ return dump; ++ ++repeat: ++ mutex_unlock(&fairsched_mutex); ++ vfree(dump); ++ goto start; ++} ++ ++#define FAIRSCHED_PROC_HEADLINES 2 ++ ++#define FAIRSHED_DEBUG " debug" ++ ++#ifdef CONFIG_VE ++/* ++ * File format is dictated by compatibility reasons. ++ */ ++static int fairsched_seq_show(struct seq_file *m, void *v) ++{ ++ struct fairsched_dump *dump; ++ struct fairsched_node_dump *p; ++ unsigned vid, nid, pid, r; ++ ++ dump = m->private; ++ p = (struct fairsched_node_dump *)((unsigned long)v & ~3UL); ++ if (p - dump->nodes < FAIRSCHED_PROC_HEADLINES) { ++ if (p == dump->nodes) ++ seq_printf(m, "Version: 2.6 debug\n"); ++ else if (p == dump->nodes + 1) ++ seq_printf(m, ++ " veid " ++ " id " ++ " parent " ++ "weight " ++ " rate " ++ "tasks " ++ " run " ++ "cpus" ++ " " ++ "flg " ++ "ready " ++ " start_tag " ++ " value " ++ " delay" ++ "\n"); ++ } else { ++ p -= FAIRSCHED_PROC_HEADLINES; ++ vid = nid = pid = 0; ++ r = (unsigned long)v & 3; ++ if (p == dump->nodes) { ++ if (r == 2) ++ nid = p->id; ++ } else { ++ if (!r) ++ nid = p->id; ++ else if (r == 1) ++ vid = pid = p->id; ++ else ++ vid = p->id, nid = 1; ++ } ++ seq_printf(m, ++ "%10u " ++ "%10u %10u %6u %5u %5u %5u %4u" ++ " " ++ " %c%c %5u %20Lu %20Lu %20Lu" ++ "\n", ++ vid, ++ nid, ++ pid, ++ p->weight, ++ p->rate, ++ p->nr_tasks, ++ p->nr_runtasks, ++ p->nr_pcpu, ++ p->rate_limited ? 'L' : '.', ++ '.', ++ p->nr_runtasks, ++ 0ll, 0ll, 0ll); ++ } ++ ++ return 0; ++} ++ ++static void *fairsched_seq_start(struct seq_file *m, loff_t *pos) ++{ ++ struct fairsched_dump *dump; ++ unsigned long l; ++ ++ dump = m->private; ++ if (*pos >= dump->len * 3 - 1 + FAIRSCHED_PROC_HEADLINES) ++ return NULL; ++ if (*pos < FAIRSCHED_PROC_HEADLINES) ++ return dump->nodes + *pos; ++ /* guess why... */ ++ l = (unsigned long)(dump->nodes + ++ ((unsigned long)*pos + FAIRSCHED_PROC_HEADLINES * 2 + 1) / 3); ++ l |= ((unsigned long)*pos + FAIRSCHED_PROC_HEADLINES * 2 + 1) % 3; ++ return (void *)l; ++} ++static void *fairsched_seq_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ ++*pos; ++ return fairsched_seq_start(m, pos); ++} ++#endif /* CONFIG_VE */ ++ ++static int fairsched2_seq_show(struct seq_file *m, void *v) ++{ ++ struct fairsched_dump *dump; ++ struct fairsched_node_dump *p; ++ ++ dump = m->private; ++ p = v; ++ if (p - dump->nodes < FAIRSCHED_PROC_HEADLINES) { ++ if (p == dump->nodes) ++ seq_printf(m, "Version: 2.7" FAIRSHED_DEBUG "\n"); ++ else if (p == dump->nodes + 1) ++ seq_printf(m, ++ " id " ++ "weight " ++ " rate " ++ " run " ++ "cpus" ++#ifdef FAIRSHED_DEBUG ++ " " ++ "flg " ++ "ready " ++ " start_tag " ++ " value " ++ " delay" ++#endif ++ "\n"); ++ } else { ++ p -= FAIRSCHED_PROC_HEADLINES; ++ seq_printf(m, ++ "%10u %6u %5u %5u %4u" ++#ifdef FAIRSHED_DEBUG ++ " " ++ " %c%c %5u %20Lu %20Lu %20Lu" ++#endif ++ "\n", ++ p->id, ++ p->weight, ++ p->rate, ++ p->nr_runtasks, ++ p->nr_pcpu ++#ifdef FAIRSHED_DEBUG ++ , ++ p->rate_limited ? 'L' : '.', ++ '.', ++ p->nr_runtasks, ++ 0ll, 0ll, 0ll ++#endif ++ ); ++ } ++ ++ return 0; ++} ++ ++static void *fairsched2_seq_start(struct seq_file *m, loff_t *pos) ++{ ++ struct fairsched_dump *dump; ++ ++ dump = m->private; ++ if (*pos >= dump->len + FAIRSCHED_PROC_HEADLINES) ++ return NULL; ++ return dump->nodes + *pos; ++} ++static void *fairsched2_seq_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ ++*pos; ++ return fairsched2_seq_start(m, pos); ++} ++static void fairsched2_seq_stop(struct seq_file *m, void *v) ++{ ++} ++ ++#ifdef CONFIG_VE ++static struct seq_operations fairsched_seq_op = { ++ .start = fairsched_seq_start, ++ .next = fairsched_seq_next, ++ .stop = fairsched2_seq_stop, ++ .show = fairsched_seq_show ++}; ++#endif ++static struct seq_operations fairsched2_seq_op = { ++ .start = fairsched2_seq_start, ++ .next = fairsched2_seq_next, ++ .stop = fairsched2_seq_stop, ++ .show = fairsched2_seq_show ++}; ++static int fairsched_seq_open(struct inode *inode, struct file *file) ++{ ++ int ret; ++ struct seq_file *m; ++ int compat; ++ ++#ifdef CONFIG_VE ++ compat = (file->f_dentry->d_name.len == sizeof("fairsched") - 1); ++ ret = seq_open(file, compat ? &fairsched_seq_op : &fairsched2_seq_op); ++#else ++ compat = 0; ++ ret = seq_open(file, &fairsched2_seq_op); ++#endif ++ if (ret) ++ return ret; ++ m = file->private_data; ++ m->private = fairsched_do_dump(compat); ++ if (m->private == NULL) { ++ seq_release(inode, file); ++ ret = -ENOMEM; ++ } ++ return ret; ++} ++static int fairsched_seq_release(struct inode *inode, struct file *file) ++{ ++ struct seq_file *m; ++ struct fairsched_dump *dump; ++ ++ m = file->private_data; ++ dump = m->private; ++ m->private = NULL; ++ vfree(dump); ++ seq_release(inode, file); ++ return 0; ++} ++static struct file_operations proc_fairsched_operations = { ++ .open = fairsched_seq_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = fairsched_seq_release ++}; ++ ++void __init fairsched_init_late(void) ++{ ++ struct proc_dir_entry *entry; ++#ifdef CONFIG_VE ++ entry = create_proc_glob_entry("fairsched", S_IRUGO, NULL); ++ if (entry) ++ entry->proc_fops = &proc_fairsched_operations; ++#endif ++ entry = create_proc_glob_entry("fairsched2", S_IRUGO, NULL); ++ if (entry) ++ entry->proc_fops = &proc_fairsched_operations; ++} ++ ++#else ++ ++void __init fairsched_init_late(void) { } ++ ++#endif /* CONFIG_PROC_FS */ +Index: kernel/kernel/vzfairsched.c +=================================================================== +--- kernel.orig/kernel/vzfairsched.c 2008-11-24 15:57:27.000000000 +0100 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,648 +0,0 @@ +-/* +- * Fair Scheduler +- * +- * Copyright (C) 2000-2008 SWsoft +- * All rights reserved. +- * +- * Licensing governed by "linux/COPYING.SWsoft" file. +- * +- */ +- +-#include +-#include +-#include +-#include +- +-struct fairsched_node fairsched_init_node = { +- .id = FAIRSCHED_INIT_NODE_ID, +- .tg = &init_task_group, +-#ifdef CONFIG_VE +- .owner_env = get_ve0(), +-#endif +- .weight = 1, +-}; +- +-static DEFINE_MUTEX(fairsched_mutex); +- +-/* list protected with fairsched_mutex */ +-static LIST_HEAD(fairsched_node_head); +-static int fairsched_nr_nodes; +- +-void __init fairsched_init_early(void) +-{ +- list_add(&fairsched_init_node.nodelist, &fairsched_node_head); +- fairsched_nr_nodes++; +-} +- +-#define FSCHWEIGHT_BASE 512000 +- +-/****************************************************************************** +- * cfs group shares = FSCHWEIGHT_BASE / fairsched weight +- * +- * vzctl cpuunits default 1000 +- * cfs shares default value is 1024 (see init_task_group_load in sched.c) +- * cpuunits = 1000 --> weight = 500000 / cpuunits = 500 --> shares = 1024 +- * ^--- from vzctl +- * weight in 1..65535 --> shares in 7..512000 +- * shares should be >1 (see comment in sched_group_set_shares function) +- *****************************************************************************/ +- +-static struct fairsched_node *fairsched_find(unsigned int id) +-{ +- struct fairsched_node *p; +- list_for_each_entry(p, &fairsched_node_head, nodelist) { +- if (p->id == id) +- return p; +- } +- return NULL; +-} +- +-/****************************************************************************** +- * System calls +- * +- * All do_xxx functions are called under fairsched mutex and after +- * capability check. +- * +- * The binary interfaces follow some other Fair Scheduler implementations +- * (although some system call arguments are not needed for our implementation). +- *****************************************************************************/ +- +-static int do_fairsched_mknod(unsigned int parent, unsigned int weight, +- unsigned int newid) +-{ +- struct fairsched_node *node; +- int retval; +- +- retval = -EINVAL; +- if (weight < 1 || weight > FSCHWEIGHT_MAX) +- goto out; +- if (newid < 0 || newid > INT_MAX) +- goto out; +- +- retval = -EBUSY; +- if (fairsched_find(newid) != NULL) +- goto out; +- +- retval = -ENOMEM; +- node = kzalloc(sizeof(*node), GFP_KERNEL); +- if (node == NULL) +- goto out; +- +- node->tg = sched_create_group(); +- if (IS_ERR(node->tg)) +- goto out_free; +- +- node->id = newid; +- node->weight = weight; +- sched_group_set_shares(node->tg, FSCHWEIGHT_BASE / weight); +-#ifdef CONFIG_VE +- node->owner_env = get_exec_env(); +-#endif +- list_add(&node->nodelist, &fairsched_node_head); +- fairsched_nr_nodes++; +- +- retval = newid; +-out: +- return retval; +- +-out_free: +- kfree(node); +- return retval; +-} +- +-asmlinkage int sys_fairsched_mknod(unsigned int parent, unsigned int weight, +- unsigned int newid) +-{ +- int retval; +- +- if (!capable(CAP_SETVEID)) +- return -EPERM; +- +- mutex_lock(&fairsched_mutex); +- retval = do_fairsched_mknod(parent, weight, newid); +- mutex_unlock(&fairsched_mutex); +- +- return retval; +-} +-EXPORT_SYMBOL(sys_fairsched_mknod); +- +-static int do_fairsched_rmnod(unsigned int id) +-{ +- struct fairsched_node *node; +- int retval; +- +- retval = -EINVAL; +- node = fairsched_find(id); +- if (node == NULL) +- goto out; +- if (node == &fairsched_init_node) +- goto out; +- +- retval = -EBUSY; +- if (node->refcnt) +- goto out; +- +- list_del(&node->nodelist); +- fairsched_nr_nodes--; +- +- sched_destroy_group(node->tg); +- kfree(node); +- retval = 0; +-out: +- return retval; +-} +- +-asmlinkage int sys_fairsched_rmnod(unsigned int id) +-{ +- int retval; +- +- if (!capable(CAP_SETVEID)) +- return -EPERM; +- +- mutex_lock(&fairsched_mutex); +- retval = do_fairsched_rmnod(id); +- mutex_unlock(&fairsched_mutex); +- +- return retval; +-} +-EXPORT_SYMBOL(sys_fairsched_rmnod); +- +-static int do_fairsched_chwt(unsigned int id, unsigned weight) +-{ +- struct fairsched_node *node; +- +- if (id == 0) +- return -EINVAL; +- if (weight < 1 || weight > FSCHWEIGHT_MAX) +- return -EINVAL; +- +- node = fairsched_find(id); +- if (node == NULL) +- return -ENOENT; +- +- node->weight = weight; +- sched_group_set_shares(node->tg, FSCHWEIGHT_BASE / weight); +- +- return 0; +-} +- +-asmlinkage int sys_fairsched_chwt(unsigned int id, unsigned weight) +-{ +- int retval; +- +- if (!capable(CAP_SETVEID)) +- return -EPERM; +- +- mutex_lock(&fairsched_mutex); +- retval = do_fairsched_chwt(id, weight); +- mutex_unlock(&fairsched_mutex); +- +- return retval; +-} +- +-static int do_fairsched_vcpus(unsigned int id, unsigned int vcpus) +-{ +- struct fairsched_node *node; +- +- if (id == 0) +- return -EINVAL; +- +- node = fairsched_find(id); +- if (node == NULL) +- return -ENOENT; +- +- return 0; +-} +- +-asmlinkage int sys_fairsched_vcpus(unsigned int id, unsigned int vcpus) +-{ +- int retval; +- +- if (!capable(CAP_SETVEID)) +- return -EPERM; +- +- mutex_lock(&fairsched_mutex); +- retval = do_fairsched_vcpus(id, vcpus); +- mutex_unlock(&fairsched_mutex); +- +- return retval; +-} +-EXPORT_SYMBOL(sys_fairsched_vcpus); +- +-static int do_fairsched_rate(unsigned int id, int op, unsigned rate) +-{ +- struct fairsched_node *node; +- int retval; +- +- if (id == 0) +- return -EINVAL; +- if (op == FAIRSCHED_SET_RATE && (rate < 1 || rate >= (1UL << 31))) +- return -EINVAL; +- +- node = fairsched_find(id); +- if (node == NULL) +- return -ENOENT; +- +- retval = -EINVAL; +- switch (op) { +- case FAIRSCHED_SET_RATE: +- node->rate = rate; +- node->rate_limited = 1; +- retval = rate; +- break; +- case FAIRSCHED_DROP_RATE: +- node->rate = 0; +- node->rate_limited = 0; +- retval = 0; +- break; +- case FAIRSCHED_GET_RATE: +- if (node->rate_limited) +- retval = node->rate; +- else +- retval = -ENODATA; +- break; +- } +- return retval; +-} +- +-asmlinkage int sys_fairsched_rate(unsigned int id, int op, unsigned rate) +-{ +- int retval; +- +- if (!capable(CAP_SETVEID)) +- return -EPERM; +- +- mutex_lock(&fairsched_mutex); +- retval = do_fairsched_rate(id, op, rate); +- mutex_unlock(&fairsched_mutex); +- +- return retval; +-} +- +-static int do_fairsched_mvpr(pid_t pid, unsigned int nodeid) +-{ +- struct task_struct *p; +- struct fairsched_node *node; +- int retval; +- unsigned flags; +- +- retval = -ENOENT; +- node = fairsched_find(nodeid); +- if (node == NULL) +- goto out; +- +- write_lock_irqsave(&tasklist_lock, flags); +- retval = -ESRCH; +- p = find_task_by_pid(pid); +- if (p == NULL) +- goto out_unlock; +- +- get_task_struct(p); +- put_task_fairsched_node(p); +- p->fsched_node = node; +- get_task_fairsched_node(p); +- write_unlock_irqrestore(&tasklist_lock, flags); +- +- smp_wmb(); +- sched_move_task(p); +- put_task_struct(p); +- return 0; +- +-out_unlock: +- write_unlock_irqrestore(&tasklist_lock, flags); +-out: +- return retval; +-} +- +-asmlinkage int sys_fairsched_mvpr(pid_t pid, unsigned int nodeid) +-{ +- int retval; +- +- if (!capable(CAP_SETVEID)) +- return -EPERM; +- +- mutex_lock(&fairsched_mutex); +- retval = do_fairsched_mvpr(pid, nodeid); +- mutex_unlock(&fairsched_mutex); +- +- return retval; +-} +-EXPORT_SYMBOL(sys_fairsched_mvpr); +- +-#ifdef CONFIG_PROC_FS +- +-/*********************************************************************/ +-/* +- * proc interface +- */ +-/*********************************************************************/ +- +-#include +-#include +-#include +- +-struct fairsched_node_dump { +- int id; +- unsigned weight; +- unsigned rate; +- int rate_limited; +- int nr_pcpu; +- int nr_tasks, nr_runtasks; +-}; +- +-struct fairsched_dump { +- int len; +- struct fairsched_node_dump nodes[0]; +-}; +- +-static struct fairsched_dump *fairsched_do_dump(int compat) +-{ +- int nr_nodes; +- int len; +- struct fairsched_dump *dump; +- struct fairsched_node *node; +- struct fairsched_node_dump *p; +- +-start: +- nr_nodes = (ve_is_super(get_exec_env()) ? fairsched_nr_nodes + 16 : 1); +- len = sizeof(*dump) + nr_nodes * sizeof(dump->nodes[0]); +- dump = ub_vmalloc(len); +- if (dump == NULL) +- goto out; +- +- mutex_lock(&fairsched_mutex); +- if (ve_is_super(get_exec_env()) && nr_nodes < fairsched_nr_nodes) +- goto repeat; +- p = dump->nodes; +- list_for_each_entry_reverse(node, &fairsched_node_head, nodelist) { +- if ((char *)p - (char *)dump >= len) +- break; +- p->nr_tasks = 0; +- p->nr_runtasks = 0; +-#ifdef CONFIG_VE +- if (!ve_accessible(node->owner_env, get_exec_env())) +- continue; +- p->nr_tasks = atomic_read(&node->owner_env->pcounter); +- p->nr_runtasks = nr_running_ve(node->owner_env); +-#endif +- p->id = node->id; +- p->weight = node->weight; +- p->rate = node->rate; +- p->rate_limited = node->rate_limited; +- p->nr_pcpu = num_online_cpus(); +- p++; +- } +- dump->len = p - dump->nodes; +- mutex_unlock(&fairsched_mutex); +- +-out: +- return dump; +- +-repeat: +- mutex_unlock(&fairsched_mutex); +- vfree(dump); +- goto start; +-} +- +-#define FAIRSCHED_PROC_HEADLINES 2 +- +-#define FAIRSHED_DEBUG " debug" +- +-#ifdef CONFIG_VE +-/* +- * File format is dictated by compatibility reasons. +- */ +-static int fairsched_seq_show(struct seq_file *m, void *v) +-{ +- struct fairsched_dump *dump; +- struct fairsched_node_dump *p; +- unsigned vid, nid, pid, r; +- +- dump = m->private; +- p = (struct fairsched_node_dump *)((unsigned long)v & ~3UL); +- if (p - dump->nodes < FAIRSCHED_PROC_HEADLINES) { +- if (p == dump->nodes) +- seq_printf(m, "Version: 2.6 debug\n"); +- else if (p == dump->nodes + 1) +- seq_printf(m, +- " veid " +- " id " +- " parent " +- "weight " +- " rate " +- "tasks " +- " run " +- "cpus" +- " " +- "flg " +- "ready " +- " start_tag " +- " value " +- " delay" +- "\n"); +- } else { +- p -= FAIRSCHED_PROC_HEADLINES; +- vid = nid = pid = 0; +- r = (unsigned long)v & 3; +- if (p == dump->nodes) { +- if (r == 2) +- nid = p->id; +- } else { +- if (!r) +- nid = p->id; +- else if (r == 1) +- vid = pid = p->id; +- else +- vid = p->id, nid = 1; +- } +- seq_printf(m, +- "%10u " +- "%10u %10u %6u %5u %5u %5u %4u" +- " " +- " %c%c %5u %20Lu %20Lu %20Lu" +- "\n", +- vid, +- nid, +- pid, +- p->weight, +- p->rate, +- p->nr_tasks, +- p->nr_runtasks, +- p->nr_pcpu, +- p->rate_limited ? 'L' : '.', +- '.', +- p->nr_runtasks, +- 0ll, 0ll, 0ll); +- } +- +- return 0; +-} +- +-static void *fairsched_seq_start(struct seq_file *m, loff_t *pos) +-{ +- struct fairsched_dump *dump; +- unsigned long l; +- +- dump = m->private; +- if (*pos >= dump->len * 3 - 1 + FAIRSCHED_PROC_HEADLINES) +- return NULL; +- if (*pos < FAIRSCHED_PROC_HEADLINES) +- return dump->nodes + *pos; +- /* guess why... */ +- l = (unsigned long)(dump->nodes + +- ((unsigned long)*pos + FAIRSCHED_PROC_HEADLINES * 2 + 1) / 3); +- l |= ((unsigned long)*pos + FAIRSCHED_PROC_HEADLINES * 2 + 1) % 3; +- return (void *)l; +-} +-static void *fairsched_seq_next(struct seq_file *m, void *v, loff_t *pos) +-{ +- ++*pos; +- return fairsched_seq_start(m, pos); +-} +-#endif /* CONFIG_VE */ +- +-static int fairsched2_seq_show(struct seq_file *m, void *v) +-{ +- struct fairsched_dump *dump; +- struct fairsched_node_dump *p; +- +- dump = m->private; +- p = v; +- if (p - dump->nodes < FAIRSCHED_PROC_HEADLINES) { +- if (p == dump->nodes) +- seq_printf(m, "Version: 2.7" FAIRSHED_DEBUG "\n"); +- else if (p == dump->nodes + 1) +- seq_printf(m, +- " id " +- "weight " +- " rate " +- " run " +- "cpus" +-#ifdef FAIRSHED_DEBUG +- " " +- "flg " +- "ready " +- " start_tag " +- " value " +- " delay" +-#endif +- "\n"); +- } else { +- p -= FAIRSCHED_PROC_HEADLINES; +- seq_printf(m, +- "%10u %6u %5u %5u %4u" +-#ifdef FAIRSHED_DEBUG +- " " +- " %c%c %5u %20Lu %20Lu %20Lu" +-#endif +- "\n", +- p->id, +- p->weight, +- p->rate, +- p->nr_runtasks, +- p->nr_pcpu +-#ifdef FAIRSHED_DEBUG +- , +- p->rate_limited ? 'L' : '.', +- '.', +- p->nr_runtasks, +- 0ll, 0ll, 0ll +-#endif +- ); +- } +- +- return 0; +-} +- +-static void *fairsched2_seq_start(struct seq_file *m, loff_t *pos) +-{ +- struct fairsched_dump *dump; +- +- dump = m->private; +- if (*pos >= dump->len + FAIRSCHED_PROC_HEADLINES) +- return NULL; +- return dump->nodes + *pos; +-} +-static void *fairsched2_seq_next(struct seq_file *m, void *v, loff_t *pos) +-{ +- ++*pos; +- return fairsched2_seq_start(m, pos); +-} +-static void fairsched2_seq_stop(struct seq_file *m, void *v) +-{ +-} +- +-#ifdef CONFIG_VE +-static struct seq_operations fairsched_seq_op = { +- .start = fairsched_seq_start, +- .next = fairsched_seq_next, +- .stop = fairsched2_seq_stop, +- .show = fairsched_seq_show +-}; +-#endif +-static struct seq_operations fairsched2_seq_op = { +- .start = fairsched2_seq_start, +- .next = fairsched2_seq_next, +- .stop = fairsched2_seq_stop, +- .show = fairsched2_seq_show +-}; +-static int fairsched_seq_open(struct inode *inode, struct file *file) +-{ +- int ret; +- struct seq_file *m; +- int compat; +- +-#ifdef CONFIG_VE +- compat = (file->f_dentry->d_name.len == sizeof("fairsched") - 1); +- ret = seq_open(file, compat ? &fairsched_seq_op : &fairsched2_seq_op); +-#else +- compat = 0; +- ret = seq_open(file, &fairsched2_seq_op); +-#endif +- if (ret) +- return ret; +- m = file->private_data; +- m->private = fairsched_do_dump(compat); +- if (m->private == NULL) { +- seq_release(inode, file); +- ret = -ENOMEM; +- } +- return ret; +-} +-static int fairsched_seq_release(struct inode *inode, struct file *file) +-{ +- struct seq_file *m; +- struct fairsched_dump *dump; +- +- m = file->private_data; +- dump = m->private; +- m->private = NULL; +- vfree(dump); +- seq_release(inode, file); +- return 0; +-} +-static struct file_operations proc_fairsched_operations = { +- .open = fairsched_seq_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = fairsched_seq_release +-}; +- +-void __init fairsched_init_late(void) +-{ +- struct proc_dir_entry *entry; +-#ifdef CONFIG_VE +- entry = create_proc_glob_entry("fairsched", S_IRUGO, NULL); +- if (entry) +- entry->proc_fops = &proc_fairsched_operations; +-#endif +- entry = create_proc_glob_entry("fairsched2", S_IRUGO, NULL); +- if (entry) +- entry->proc_fops = &proc_fairsched_operations; +-} +- +-#else +- +-void __init fairsched_init_late(void) { } +- +-#endif /* CONFIG_PROC_FS */ --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0057-Add-per-VE-proc-net-udp-udp6-udplite-udplite6.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0057-Add-per-VE-proc-net-udp-udp6-udplite-udplite6.patch @@ -0,0 +1,208 @@ +From 452bdf6ea996f2e9e030822d87d9106bf33e0677 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Tue, 1 Apr 2008 17:55:52 +0400 +Subject: [PATCH 56/67] Add per-VE /proc/net/{udp,udp6,udplite,udplite6} + +Show only connections of current VE (already implemented). +Required for netstat. + +http://bugzilla.openvz.org/show_bug.cgi?id=860 +--- + include/net/udp.h | 4 ++-- + net/ipv4/udp.c | 27 +++++++++++++++++++++------ + net/ipv4/udplite.c | 17 ++++++++++++++++- + net/ipv6/udp.c | 19 +++++++++++++++++-- + net/ipv6/udplite.c | 19 +++++++++++++++++-- + 5 files changed, 73 insertions(+), 13 deletions(-) + +diff --git a/include/net/udp.h b/include/net/udp.h +index 71967e3..20bc0ab 100644 +--- a/include/net/udp.h ++++ b/include/net/udp.h +@@ -180,8 +180,8 @@ struct udp_iter_state { + }; + + #ifdef CONFIG_PROC_FS +-extern int udp_proc_register(struct udp_seq_afinfo *afinfo); +-extern void udp_proc_unregister(struct udp_seq_afinfo *afinfo); ++extern int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo); ++extern void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo); + + extern int udp4_proc_init(void); + extern void udp4_proc_exit(void); +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index 32fddac..a27ed8a 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -1576,7 +1576,7 @@ out_kfree: + } + + /* ------------------------------------------------------------------------ */ +-int udp_proc_register(struct udp_seq_afinfo *afinfo) ++int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) + { + struct proc_dir_entry *p; + int rc = 0; +@@ -1589,7 +1589,7 @@ int udp_proc_register(struct udp_seq_afinfo *afinfo) + afinfo->seq_fops->llseek = seq_lseek; + afinfo->seq_fops->release = seq_release_private; + +- p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops); ++ p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops); + if (p) + p->data = afinfo; + else +@@ -1597,11 +1597,11 @@ int udp_proc_register(struct udp_seq_afinfo *afinfo) + return rc; + } + +-void udp_proc_unregister(struct udp_seq_afinfo *afinfo) ++void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo) + { + if (!afinfo) + return; +- proc_net_remove(&init_net, afinfo->name); ++ proc_net_remove(net, afinfo->name); + memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); + } + +@@ -1651,14 +1651,29 @@ static struct udp_seq_afinfo udp4_seq_afinfo = { + .seq_fops = &udp4_seq_fops, + }; + ++static int udp4_proc_net_init(struct net *net) ++{ ++ return udp_proc_register(net, &udp4_seq_afinfo); ++} ++ ++static void udp4_proc_net_exit(struct net *net) ++{ ++ udp_proc_unregister(net, &udp4_seq_afinfo); ++} ++ ++static struct pernet_operations udp4_proc_net_ops = { ++ .init = udp4_proc_net_init, ++ .exit = udp4_proc_net_exit, ++}; ++ + int __init udp4_proc_init(void) + { +- return udp_proc_register(&udp4_seq_afinfo); ++ return register_pernet_subsys(&udp4_proc_net_ops); + } + + void udp4_proc_exit(void) + { +- udp_proc_unregister(&udp4_seq_afinfo); ++ unregister_pernet_subsys(&udp4_proc_net_ops); + } + #endif /* CONFIG_PROC_FS */ + +diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c +index f5baeb3..c66933b 100644 +--- a/net/ipv4/udplite.c ++++ b/net/ipv4/udplite.c +@@ -92,6 +92,21 @@ static struct udp_seq_afinfo udplite4_seq_afinfo = { + .seq_show = udp4_seq_show, + .seq_fops = &udplite4_seq_fops, + }; ++ ++static int udplite4_proc_net_init(struct net *net) ++{ ++ return udp_proc_register(net, &udplite4_seq_afinfo); ++} ++ ++static void udplite4_proc_net_exit(struct net *net) ++{ ++ udp_proc_unregister(net, &udplite4_seq_afinfo); ++} ++ ++static struct pernet_operations udplite4_proc_net_ops = { ++ .init = udplite4_proc_net_init, ++ .exit = udplite4_proc_net_exit, ++}; + #endif + + void __init udplite4_register(void) +@@ -105,7 +120,7 @@ void __init udplite4_register(void) + inet_register_protosw(&udplite4_protosw); + + #ifdef CONFIG_PROC_FS +- if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ ++ if (register_pernet_subsys(&udplite4_proc_net_ops)) /* udplite4_proc_init() */ + printk(KERN_ERR "%s: Cannot register /proc!\n", __FUNCTION__); + #endif + return; +diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c +index a28f405..bf170a8 100644 +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -961,13 +961,28 @@ static struct udp_seq_afinfo udp6_seq_afinfo = { + .seq_fops = &udp6_seq_fops, + }; + ++static int udp6_proc_net_init(struct net *net) ++{ ++ return udp_proc_register(net, &udp6_seq_afinfo); ++} ++ ++static void udp6_proc_net_exit(struct net *net) ++{ ++ udp_proc_unregister(net, &udp6_seq_afinfo); ++} ++ ++static struct pernet_operations udp6_proc_net_ops = { ++ .init = udp6_proc_net_init, ++ .exit = udp6_proc_net_exit, ++}; ++ + int __init udp6_proc_init(void) + { +- return udp_proc_register(&udp6_seq_afinfo); ++ return register_pernet_subsys(&udp6_proc_net_ops); + } + + void udp6_proc_exit(void) { +- udp_proc_unregister(&udp6_seq_afinfo); ++ unregister_pernet_subsys(&udp6_proc_net_ops); + } + #endif /* CONFIG_PROC_FS */ + +diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c +index 5a0379f..992e677 100644 +--- a/net/ipv6/udplite.c ++++ b/net/ipv6/udplite.c +@@ -96,13 +96,28 @@ static struct udp_seq_afinfo udplite6_seq_afinfo = { + .seq_fops = &udplite6_seq_fops, + }; + ++static int udplite6_proc_net_init(struct net *net) ++{ ++ return udp_proc_register(net, &udplite6_seq_afinfo); ++} ++ ++static void udplite6_proc_net_exit(struct net *net) ++{ ++ udp_proc_unregister(net, &udplite6_seq_afinfo); ++} ++ ++static struct pernet_operations udplite6_proc_net_ops = { ++ .init = udplite6_proc_net_init, ++ .exit = udplite6_proc_net_exit, ++}; ++ + int __init udplite6_proc_init(void) + { +- return udp_proc_register(&udplite6_seq_afinfo); ++ return register_pernet_subsys(&udplite6_proc_net_ops); + } + + void udplite6_proc_exit(void) + { +- udp_proc_unregister(&udplite6_seq_afinfo); ++ unregister_pernet_subsys(&udplite6_proc_net_ops); + } + #endif +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0109-UBC-ioprio-proc.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0109-UBC-ioprio-proc.patch @@ -0,0 +1,64 @@ +From 8fe6eaaa2a02ceeb2ddd84f6f1f7867f98ff1ad3 Mon Sep 17 00:00:00 2001 +From: Pavel Emelianov +Date: Fri, 18 Jul 2008 15:25:43 +0400 +Subject: [PATCH 109/131] UBC ioprio proc + +Show BC current IO priority +Surprisingly, but currently on the running system, there's no +way to find out what IO priority a VE... sorry - CT has. + +Add the /proc/bc//ioprio file with (currently only) this +information. + +prio: 4 +--- + kernel/bc/io_prio.c | 26 ++++++++++++++++++++++++++ + 1 files changed, 26 insertions(+), 0 deletions(-) + +diff --git a/kernel/bc/io_prio.c b/kernel/bc/io_prio.c +index 20aa133..1a10af4 100644 +--- a/kernel/bc/io_prio.c ++++ b/kernel/bc/io_prio.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + + struct cfq_bc_data *__find_cfq_bc(struct ub_iopriv *iopriv, +@@ -275,6 +276,31 @@ void bc_io_restore_context(struct user_beancounter *ub) + } + } + ++#ifdef CONFIG_PROC_FS ++static int bc_ioprio_show(struct seq_file *f, void *v) ++{ ++ struct user_beancounter *bc; ++ ++ bc = seq_beancounter(f); ++ seq_printf(f, "prio: %u\n", bc->iopriv.ioprio); ++ ++ return 0; ++} ++ ++static struct bc_proc_entry bc_ioprio_entry = { ++ .name = "ioprio", ++ .u.show = bc_ioprio_show, ++}; ++ ++static int __init bc_ioprio_init(void) ++{ ++ bc_register_proc_entry(&bc_ioprio_entry); ++ return 0; ++} ++ ++late_initcall(bc_ioprio_init); ++#endif ++ + EXPORT_SYMBOL(bc_io_switch_context); + EXPORT_SYMBOL(bc_io_restore_context); + EXPORT_SYMBOL(__find_cfq_bc); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0129-VE-veinfo-from-venet.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0129-VE-veinfo-from-venet.patch @@ -0,0 +1,138 @@ +From d4abc6686ac67aa51ff8a78ac3097667affa0c8f Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 18 Jul 2008 15:25:57 +0400 +Subject: [PATCH 129/131] VE veinfo from venet + venet part of VE-veinfo-to-vzmon patch + +--- + drivers/net/venet_core.c | 78 ++-------------------------------------------- + 1 files changed, 3 insertions(+), 75 deletions(-) + +diff --git a/drivers/net/venet_core.c b/drivers/net/venet_core.c +index 8355627..7c718d8 100644 +--- a/drivers/net/venet_core.c ++++ b/drivers/net/venet_core.c +@@ -444,15 +444,10 @@ static void venet_setup(struct net_device *dev) + } + + #ifdef CONFIG_PROC_FS +-static int veinfo_seq_show(struct seq_file *m, void *v) ++static void veaddr_seq_print(struct seq_file *m, struct ve_struct *ve) + { +- struct ve_struct *ve; + struct ip_entry_struct *entry; + +- ve = list_entry((struct list_head *)v, struct ve_struct, ve_list); +- +- seq_printf(m, "%10u %5u %5u", ve->veid, +- ve->class_id, atomic_read(&ve->pcounter)); + read_lock(&veip_hash_lock); + if (ve->veip == NULL) + goto unlock; +@@ -470,69 +465,8 @@ static int veinfo_seq_show(struct seq_file *m, void *v) + } + unlock: + read_unlock(&veip_hash_lock); +- seq_putc(m, '\n'); +- return 0; + } + +-static void *ve_seq_start(struct seq_file *m, loff_t *pos) +-{ +- struct ve_struct *curve; +- struct list_head *entry; +- loff_t l; +- +- curve = get_exec_env(); +- read_lock(&ve_list_lock); +- if (!ve_is_super(curve)) { +- if (*pos != 0) +- return NULL; +- return curve; +- } +- +- l = *pos; +- list_for_each(entry, &ve_list_head) { +- if (l == 0) +- return entry; +- l--; +- } +- return NULL; +-} +- +-static void *ve_seq_next(struct seq_file *m, void *v, loff_t *pos) +-{ +- struct list_head *entry; +- +- entry = (struct list_head *)v; +- if (!ve_is_super(get_exec_env())) +- return NULL; +- (*pos)++; +- return entry->next == &ve_list_head ? NULL : entry->next; +-} +- +-static void ve_seq_stop(struct seq_file *m, void *v) +-{ +- read_unlock(&ve_list_lock); +-} +- +- +-static struct seq_operations veinfo_seq_op = { +- .start = ve_seq_start, +- .next = ve_seq_next, +- .stop = ve_seq_stop, +- .show = veinfo_seq_show, +-}; +- +-static int veinfo_open(struct inode *inode, struct file *file) +-{ +- return seq_open(file, &veinfo_seq_op); +-} +- +-static struct file_operations proc_veinfo_operations = { +- .open = veinfo_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = seq_release, +-}; +- + static void *veip_seq_start(struct seq_file *m, loff_t *pos) + { + loff_t l; +@@ -775,13 +709,6 @@ __init int venet_init(void) + return err; + + #ifdef CONFIG_PROC_FS +- de = create_proc_glob_entry_mod("vz/veinfo", +- S_IFREG|S_IRUSR, NULL, THIS_MODULE); +- if (de) +- de->proc_fops = &proc_veinfo_operations; +- else +- printk(KERN_WARNING "venet: can't make veinfo proc entry\n"); +- + de = create_proc_entry_mod("vz/veip", + S_IFREG|S_IRUSR, NULL, THIS_MODULE); + if (de) +@@ -792,17 +719,18 @@ __init int venet_init(void) + + ve_hook_register(VE_SS_CHAIN, &venet_ve_hook); + vzioctl_register(&venetcalls); ++ vzmon_register_veaddr_print_cb(veaddr_seq_print); + return 0; + } + + __exit void venet_exit(void) + { ++ vzmon_unregister_veaddr_print_cb(veaddr_seq_print); + vzioctl_unregister(&venetcalls); + ve_hook_unregister(&venet_ve_hook); + + #ifdef CONFIG_PROC_FS + remove_proc_entry("vz/veip", NULL); +- remove_proc_entry("vz/veinfo", NULL); + #endif + venet_stop(get_ve0()); + veip_cleanup(); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0076-ipv6-fix-frags-owner-ve.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0076-ipv6-fix-frags-owner-ve.patch @@ -0,0 +1,49 @@ +commit a628e361137fa399f047747e1df2ed914655e560 +Author: Alexey Dobriyan +Date: Thu May 29 15:18:19 2008 +0400 + + IPv6: get frag's owner VE from inet_frag_queue + + IPv6 specific frag queue doesn't need owner_ve, because it's already in core + data structure (struct inet_frag_queue). + + And it's in fact NULL, which is the cause of + http://bugzilla.openvz.org/show_bug.cgi?id=899 + +diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c +index 846c622..2cc9769 100644 +--- a/net/ipv6/reassembly.c ++++ b/net/ipv6/reassembly.c +@@ -81,7 +81,6 @@ struct frag_queue + int iif; + unsigned int csum; + __u16 nhoffset; +- struct ve_struct *owner_ve; + }; + + struct inet_frags_ctl ip6_frags_ctl __read_mostly = { +@@ -154,7 +153,7 @@ int ip6_frag_match(struct inet_frag_queue *q, void *a) + return (fq->id == arg->id && + ipv6_addr_equal(&fq->saddr, arg->src) && + ipv6_addr_equal(&fq->daddr, arg->dst) && +- fq->owner_ve == get_exec_env()); ++ q->owner_ve == get_exec_env()); + } + EXPORT_SYMBOL(ip6_frag_match); + +@@ -204,12 +203,12 @@ static void ip6_evictor(struct inet6_dev *idev) + + static void ip6_frag_expire(unsigned long data) + { +- struct frag_queue *fq; ++ struct inet_frag_queue *q = (struct inet_frag_queue *)data; ++ struct frag_queue *fq = container_of(q, struct frag_queue, q); + struct net_device *dev = NULL; + struct ve_struct *old_ve; + +- fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q); +- old_ve = set_exec_env(fq->owner_ve); ++ old_ve = set_exec_env(q->owner_ve); + + spin_lock(&fq->q.lock); + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0142-MISC-autofs4-ia32-compat.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0142-MISC-autofs4-ia32-compat.patch @@ -0,0 +1,41 @@ +From 62cb46b6c2eb619bc66ab670dfaa4eb36ecd24e4 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Mon, 8 Sep 2008 14:15:06 +0400 +Subject: [PATCH] MISC autofs4 ia32 compat + +The struct autofs_v5_packet has only one difference between +32-bit and 64-bit versions - on 64-bit gcc aligns its size and +it is 4 bytes larger that it is on 32-bit kernel. This confuses +32-bit user-space daemon, when talking to 64-bit kernel. + +This is very critical for containerized setups, when containers +with -bit tolls are used. + +Signed-off-by: Konstantin Khlebnikov +Acked-by: Pavel Emelyanov +--- + fs/autofs4/waitq.c | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c +index 1fe28e4..788ca05 100644 +--- a/fs/autofs4/waitq.c ++++ b/fs/autofs4/waitq.c +@@ -136,6 +136,14 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, + struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet; + + pktsz = sizeof(*packet); ++#if defined(CONFIG_X86_64) && defined(CONFIG_IA32_EMULATION) ++ /* ++ * On x86_64 autofs_v5_packet struct is padded with 4 bytes ++ * which breaks 32-bit autofs daemon. ++ */ ++ if (test_thread_flag(TIF_IA32)) ++ pktsz -= 4; ++#endif + + packet->wait_queue_token = wq->wait_queue_token; + packet->len = wq->len; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0118-UBC-pid-charge-size.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0118-UBC-pid-charge-size.patch @@ -0,0 +1,36 @@ +From ee08765df7bc7994142c133a78e1cb817d53be86 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 18 Jul 2008 15:25:49 +0400 +Subject: [PATCH 118/131] UBC pid charge size + add missign CHARGE_SIZE macro + +--- + kernel/pid.c | 5 +++-- + 1 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/kernel/pid.c b/kernel/pid.c +index e26509f..56dd048 100644 +--- a/kernel/pid.c ++++ b/kernel/pid.c +@@ -269,7 +269,8 @@ fastcall void free_pid(struct pid *pid) + hlist_del_rcu(&upid->pid_chain); + } + spin_unlock(&pidmap_lock); +- ub_kmemsize_uncharge(pid->ub, pid->numbers[pid->level].ns->pid_cachep->objuse); ++ ub_kmemsize_uncharge(pid->ub, CHARGE_SIZE(pid->numbers[pid->level].ns-> ++ pid_cachep->objuse)); + local_irq_restore(flags); + + for (i = 0; i <= pid->level; i++) +@@ -315,7 +316,7 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t vpid) + local_irq_disable(); + #ifdef CONFIG_BEANCOUNTERS + ub = get_exec_ub(); +- if (ub_kmemsize_charge(ub, ns->pid_cachep->objuse, UB_HARD)) ++ if (ub_kmemsize_charge(ub, CHARGE_SIZE(ns->pid_cachep->objuse), UB_HARD)) + goto out_enable; + pid->ub = get_beancounter(ub); + spin_lock(&pidmap_lock); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0014-NETFILTER-move-VE-s-expect_max-value-initialization.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0014-NETFILTER-move-VE-s-expect_max-value-initialization.patch @@ -0,0 +1,40 @@ +From 3ac4bfd9c19541c576d0804fde799eb4d50facdf Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 7 Mar 2008 16:45:12 +0300 +Subject: [PATCH 14/48] NETFILTER: move VE's expect_max value initialization into correct place + +Copying from nf_ct_expect_max is pointless for VE0 because it's 0 at this place +Move initialization to nf_conntrack_expect_init() for correct behaviour. +--- + net/netfilter/nf_conntrack_core.c | 1 - + net/netfilter/nf_conntrack_expect.c | 2 +- + 2 files changed, 1 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 46e0c5b..879dc9e 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1167,7 +1167,6 @@ int nf_conntrack_init(void) + } + + ve_nf_conntrack_max = nf_conntrack_max; +- ve_nf_ct_expect_max = nf_ct_expect_max; + atomic_set(&ve_nf_conntrack_count, 0); + INIT_HLIST_HEAD(&ve_unconfirmed); + #endif +diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c +index c90024c..39dde85 100644 +--- a/net/netfilter/nf_conntrack_expect.c ++++ b/net/netfilter/nf_conntrack_expect.c +@@ -521,7 +521,7 @@ int nf_conntrack_expect_init(void) + nf_ct_expect_hsize = 1; + } + nf_ct_expect_max = nf_ct_expect_hsize * 4; +- ++ ve_nf_ct_expect_max = nf_ct_expect_max; + ve_nf_ct_expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, + &ve_nf_ct_expect_vmalloc); + if (ve_nf_ct_expect_hash == NULL) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0016-NETFILTER-per-VE-expect-count.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0016-NETFILTER-per-VE-expect-count.patch @@ -0,0 +1,87 @@ +From 455602f53647d6d947dd966c0f663424a23d1fa4 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 7 Mar 2008 20:10:17 +0300 +Subject: [PATCH 16/48] NETFILTER: per-VE expect count + +Expectation count were left global which defeats the point of per-VE +expectation limits. :-) +--- + include/linux/ve.h | 1 + + net/netfilter/nf_conntrack_expect.c | 12 ++++++++---- + 2 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/include/linux/ve.h b/include/linux/ve.h +index e60159b..1a5b357 100644 +--- a/include/linux/ve.h ++++ b/include/linux/ve.h +@@ -67,6 +67,7 @@ struct ve_nf_conntrack { + struct hlist_head _unconfirmed; + struct hlist_head *_nf_ct_expect_hash; + unsigned int _nf_ct_expect_vmalloc; ++ unsigned int _nf_ct_expect_count; + unsigned int _nf_ct_expect_max; + struct hlist_head *_nf_ct_helper_hash; + unsigned int _nf_ct_helper_vmalloc; +diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c +index 39dde85..7f85c87 100644 +--- a/net/netfilter/nf_conntrack_expect.c ++++ b/net/netfilter/nf_conntrack_expect.c +@@ -40,8 +40,10 @@ unsigned int nf_ct_expect_max __read_mostly; + static int nf_ct_expect_hash_rnd_initted __read_mostly; + static int nf_ct_expect_vmalloc; + #ifdef CONFIG_VE_IPTABLES ++#define ve_nf_ct_expect_count (get_exec_env()->_nf_conntrack->_nf_ct_expect_count) + #define ve_nf_ct_expect_vmalloc (get_exec_env()->_nf_conntrack->_nf_ct_expect_vmalloc) + #else ++#define ve_nf_ct_expect_count nf_ct_expect_count + #define ve_nf_ct_expect_vmalloc nf_ct_expect_vmalloc + #endif + +@@ -56,7 +58,7 @@ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) + NF_CT_ASSERT(!timer_pending(&exp->timeout)); + + hlist_del(&exp->hnode); +- nf_ct_expect_count--; ++ ve_nf_ct_expect_count--; + + hlist_del(&exp->lnode); + master_help->expecting--; +@@ -96,7 +98,7 @@ __nf_ct_expect_find(const struct nf_conntrack_tuple *tuple) + struct hlist_node *n; + unsigned int h; + +- if (!nf_ct_expect_count) ++ if (!ve_nf_ct_expect_count) + return NULL; + + h = nf_ct_expect_dst_hash(tuple); +@@ -299,7 +301,7 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) + master_help->expecting++; + + hlist_add_head(&exp->hnode, &ve_nf_ct_expect_hash[h]); +- nf_ct_expect_count++; ++ ve_nf_ct_expect_count++; + + setup_timer(&exp->timeout, nf_ct_expectation_timed_out, + (unsigned long)exp); +@@ -372,7 +374,7 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect) + master_help->expecting >= master_help->helper->max_expected) + evict_oldest_expect(master); + +- if (nf_ct_expect_count >= ve_nf_ct_expect_max) { ++ if (ve_nf_ct_expect_count >= ve_nf_ct_expect_max) { + if (net_ratelimit()) + printk(KERN_WARNING + "nf_conntrack: expectation table full\n"); +@@ -521,6 +523,8 @@ int nf_conntrack_expect_init(void) + nf_ct_expect_hsize = 1; + } + nf_ct_expect_max = nf_ct_expect_hsize * 4; ++ ++ ve_nf_ct_expect_count = 0; + ve_nf_ct_expect_max = nf_ct_expect_max; + ve_nf_ct_expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, + &ve_nf_ct_expect_vmalloc); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0025-NETFILTER-fix-memory-leak-if-nf_conntrack_ipv4-was.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0025-NETFILTER-fix-memory-leak-if-nf_conntrack_ipv4-was.patch @@ -0,0 +1,45 @@ +From 85e6bc2ba4997464c6ff0f92e7f56b503c6ff792 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 14 Mar 2008 12:51:36 +0300 +Subject: [PATCH 25/48] NETFILTER: fix memory leak if nf_conntrack_ipv4 was used by VE + +--- + net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +index aa23976..9ac2567 100644 +--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c ++++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +@@ -490,6 +490,12 @@ out: + ve_nf_conntrack_l3proto_ipv4 = ipv4; + return 0; + } ++ ++static void nf_ct_proto_ipv4_fini(void) ++{ ++ if (!ve_is_super(get_exec_env())) ++ kfree(ve_nf_conntrack_l3proto_ipv4); ++} + #endif + + int init_nf_ct_l3proto_ipv4(void) +@@ -571,6 +577,7 @@ no_mem_udp: + no_mem_tcp: + nf_ct_proto_ipv4_sysctl_cleanup(); + no_mem_ipv4: ++ nf_ct_proto_ipv4_fini(); + err_out: + if (!ve_is_super(get_exec_env())) + module_put(THIS_MODULE); +@@ -593,6 +600,7 @@ void fini_nf_ct_l3proto_ipv4(void) + nf_ct_proto_udp_sysctl_cleanup(); + nf_ct_proto_tcp_sysctl_cleanup(); + nf_ct_proto_ipv4_sysctl_cleanup(); ++ nf_ct_proto_ipv4_fini(); + if (!ve_is_super(get_exec_env())) + module_put(THIS_MODULE); + #endif /* CONFIG_VE_IPTABLES */ +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0073-CPT-fix-shmat-2-ted-segments.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0073-CPT-fix-shmat-2-ted-segments.patch @@ -0,0 +1,462 @@ +From f28668f8d342c3797cb5cc468675e5ed1012aac3 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Sun, 4 May 2008 17:45:04 +0400 +Subject: [PATCH 72/72] CPT: fix shmat(2)'ted segments + +Commit bc56bba8f31bd99f350a5ebfd43d50f411b620c7 aka +"[PATCH] shm: make sysv ipc shared memory use stacked files"... + +It changed number and relationship of "struct file"s associated +with SysV shmem: + +Before: one struct file for each shmem segment + After: one struct file for each shmem segment + + one struct file (different) for each shmat(2) call. + +Obviously checkpointing broke horribly. There aren't any files of second sort +in image and they have to be recreated by hand. + +What code will do: +a) if CPT_OBJ_SYSV_SHM object restored first -- fine, restore as previous kernels did +b) if CPT_VMA_TYPE_SHM restored first -- restore corresponding segment, then do more + or less similar to what do_shmat() does. +c) if shmem segment already was restored, correct refcounting and just do shmat() part + +http://bugzilla.openvz.org/show_bug.cgi?id=850 +--- + include/linux/ipc.h | 20 +++++++++++ + include/linux/shm.h | 25 +++++++++++++ + ipc/shm.c | 28 +-------------- + ipc/util.c | 3 +- + ipc/util.h | 19 ---------- + kernel/cpt/cpt_files.c | 7 ++++ + kernel/cpt/cpt_files.h | 5 +-- + kernel/cpt/cpt_mm.c | 8 +++-- + kernel/cpt/rst_files.c | 2 +- + kernel/cpt/rst_mm.c | 2 +- + kernel/cpt/rst_sysvipc.c | 86 ++++++++++++++++++++++++++++++++++++++++++++- + 11 files changed, 149 insertions(+), 56 deletions(-) + +diff --git a/include/linux/ipc.h b/include/linux/ipc.h +index 408696e..b7ac734 100644 +--- a/include/linux/ipc.h ++++ b/include/linux/ipc.h +@@ -80,8 +80,21 @@ struct ipc_kludge { + #ifdef __KERNEL__ + + #include ++#include ++#include + #include + ++#define IPC_SEM_IDS 0 ++#define IPC_MSG_IDS 1 ++#define IPC_SHM_IDS 2 ++ ++struct ipc_ids { ++ int in_use; ++ unsigned short seq; ++ unsigned short seq_max; ++ struct rw_semaphore rw_mutex; ++ struct idr ipcs_idr; ++}; + #define IPCMNI 32768 /* <= MAX_INT limit for ipc arrays (including sysctl changes) */ + + /* used by in-kernel data structures */ +@@ -100,6 +113,13 @@ struct kern_ipc_perm + void *security; + }; + ++struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int); ++static inline void ipc_unlock(struct kern_ipc_perm *perm) ++{ ++ spin_unlock(&perm->lock); ++ rcu_read_unlock(); ++} ++ + struct ipc_ids; + struct ipc_namespace { + struct kref kref; +diff --git a/include/linux/shm.h b/include/linux/shm.h +index 19fd699..b2c48c4 100644 +--- a/include/linux/shm.h ++++ b/include/linux/shm.h +@@ -75,6 +75,15 @@ struct shm_info { + }; + + #ifdef __KERNEL__ ++struct shm_file_data { ++ int id; ++ struct ipc_namespace *ns; ++ struct file *file; ++ const struct vm_operations_struct *vm_ops; ++}; ++#define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data)) ++#define shm_ids(ns) (*((ns)->ids[IPC_SHM_IDS])) ++ + struct shmid_kernel /* private to the kernel */ + { + struct kern_ipc_perm shm_perm; +@@ -89,6 +98,20 @@ struct shmid_kernel /* private to the kernel */ + struct user_struct *mlock_user; + }; + ++/* ++ * shm_lock_(check_) routines are called in the paths where the rw_mutex ++ * is not held. ++ */ ++static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id) ++{ ++ struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id); ++ ++ return container_of(ipcp, struct shmid_kernel, shm_perm); ++} ++ ++#define shm_unlock(shp) \ ++ ipc_unlock(&(shp)->shm_perm) ++ + /* shm_mode upper byte flags */ + #define SHM_DEST 01000 /* segment will be destroyed on last detach */ + #define SHM_LOCKED 02000 /* segment will not be swapped */ +@@ -112,6 +135,8 @@ static inline int is_file_shm_hugepages(struct file *file) + + int sysvipc_walk_shm(int (*func)(struct shmid_kernel*, void *), void *arg); + struct file * sysvipc_setup_shm(key_t key, int shmid, size_t size, int shmflg); ++extern const struct file_operations shmem_file_operations; ++extern const struct file_operations shm_file_operations; + + #endif /* __KERNEL__ */ + +diff --git a/ipc/shm.c b/ipc/shm.c +index 14f0cc2..03cf380 100644 +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -43,24 +43,10 @@ + + #include "util.h" + +-struct shm_file_data { +- int id; +- struct ipc_namespace *ns; +- struct file *file; +- const struct vm_operations_struct *vm_ops; +-}; +- +-#define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data)) +- +-static const struct file_operations shm_file_operations; + static struct vm_operations_struct shm_vm_ops; + + static struct ipc_ids init_shm_ids; + +-#define shm_ids(ns) (*((ns)->ids[IPC_SHM_IDS])) +- +-#define shm_unlock(shp) \ +- ipc_unlock(&(shp)->shm_perm) + #define shm_buildid(id, seq) ipc_buildid(id, seq) + + static int newseg(struct ipc_namespace *, struct ipc_params *); +@@ -161,17 +147,6 @@ static inline struct shmid_kernel *shm_lock_check_down( + return container_of(ipcp, struct shmid_kernel, shm_perm); + } + +-/* +- * shm_lock_(check_) routines are called in the paths where the rw_mutex +- * is not held. +- */ +-static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id) +-{ +- struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id); +- +- return container_of(ipcp, struct shmid_kernel, shm_perm); +-} +- + static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns, + int id) + { +@@ -344,11 +319,12 @@ static unsigned long shm_get_unmapped_area(struct file *file, + pgoff, flags); + } + +-static const struct file_operations shm_file_operations = { ++const struct file_operations shm_file_operations = { + .mmap = shm_mmap, + .fsync = shm_fsync, + .release = shm_release, + }; ++EXPORT_SYMBOL_GPL(shm_file_operations); + + static const struct file_operations shm_file_operations_huge = { + .mmap = shm_mmap, +diff --git a/ipc/util.c b/ipc/util.c +index 50d9838..8e0a7db 100644 +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -278,7 +278,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size, int reqi + id = reqid % SEQ_MULTIPLIER; + err = idr_get_new_above(&ids->ipcs_idr, new, id, &id); + if (err || id != (reqid % SEQ_MULTIPLIER)) +- return -1; ++ return -EEXIST; + goto found; + } + +@@ -749,6 +749,7 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id) + + return out; + } ++EXPORT_SYMBOL_GPL(ipc_lock); + + /** + * ipc_lock_down - Lock an ipc structure with rw_sem held +diff --git a/ipc/util.h b/ipc/util.h +index 711740c..7ddaf0f 100644 +--- a/ipc/util.h ++++ b/ipc/util.h +@@ -28,14 +28,6 @@ void sem_exit_ns(struct ipc_namespace *ns); + void msg_exit_ns(struct ipc_namespace *ns); + void shm_exit_ns(struct ipc_namespace *ns); + +-struct ipc_ids { +- int in_use; +- unsigned short seq; +- unsigned short seq_max; +- struct rw_semaphore rw_mutex; +- struct idr ipcs_idr; +-}; +- + /* + * Structure that holds the parameters needed by the ipc operations + * (see after) +@@ -76,10 +68,6 @@ void __init ipc_init_proc_interface(const char *path, const char *header, + #define ipc_init_proc_interface(path, header, ids, show) do {} while (0) + #endif + +-#define IPC_SEM_IDS 0 +-#define IPC_MSG_IDS 1 +-#define IPC_SHM_IDS 2 +- + #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER) + + /* must be called with ids->rw_mutex acquired for writing */ +@@ -115,7 +103,6 @@ void ipc_rcu_putref(void *ptr); + * ipc_lock: called without that lock held + */ + struct kern_ipc_perm *ipc_lock_down(struct ipc_ids *, int); +-struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int); + + void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); + void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); +@@ -156,12 +143,6 @@ static inline void ipc_lock_by_ptr(struct kern_ipc_perm *perm) + spin_lock(&perm->lock); + } + +-static inline void ipc_unlock(struct kern_ipc_perm *perm) +-{ +- spin_unlock(&perm->lock); +- rcu_read_unlock(); +-} +- + static inline struct kern_ipc_perm *ipc_lock_check_down(struct ipc_ids *ids, + int id) + { +diff --git a/kernel/cpt/cpt_files.c b/kernel/cpt/cpt_files.c +index 6b3885e..fbba10b 100644 +--- a/kernel/cpt/cpt_files.c ++++ b/kernel/cpt/cpt_files.c +@@ -609,6 +609,13 @@ static int dump_content_regular(struct file *file, struct cpt_context *ctx) + return -EINVAL; + + do_read = file->f_op->read; ++ if (file->f_op == &shm_file_operations) { ++ struct shm_file_data *sfd = file->private_data; ++ ++ cpt_dump_content_sysvshm(sfd->file, ctx); ++ ++ return 0; ++ } + if (file->f_op == &shmem_file_operations) { + do_read = file->f_dentry->d_inode->i_fop->read; + cpt_dump_content_sysvshm(file, ctx); +diff --git a/kernel/cpt/cpt_files.h b/kernel/cpt/cpt_files.h +index b08afea..7770ab2 100644 +--- a/kernel/cpt/cpt_files.h ++++ b/kernel/cpt/cpt_files.h +@@ -9,7 +9,8 @@ int cpt_dump_fs_struct(struct cpt_context *ctx); + int cpt_dump_content_sysvshm(struct file *file, struct cpt_context *ctx); + int cpt_dump_content_tty(struct file *file, struct cpt_context *ctx); + int cpt_dump_tty(cpt_object_t *, struct cpt_context *ctx); +-struct file * rst_sysv_shm(loff_t pos, struct cpt_context *ctx); ++struct file * rst_sysv_shm_vma(struct cpt_vma_image *vmai, struct cpt_context *ctx); ++struct file * rst_sysv_shm_itself(loff_t pos, struct cpt_context *ctx); + struct file * rst_open_tty(struct cpt_file_image *fi, struct cpt_inode_image *ii, unsigned flags, struct cpt_context *ctx); + __u32 cpt_tty_fasync(struct file *file, struct cpt_context *ctx); + +@@ -68,5 +69,3 @@ int cpt_verify_overmount(char *path, struct dentry *d, struct vfsmount *mnt, + strcmp(mnt->mnt_sb->s_type->name, "devpts") != 0 && \ + strcmp(mnt->mnt_sb->s_type->name, "proc") != 0 && \ + strcmp(mnt->mnt_sb->s_type->name, "sysfs") != 0) +- +-extern const struct file_operations shmem_file_operations; +diff --git a/kernel/cpt/cpt_mm.c b/kernel/cpt/cpt_mm.c +index 3c462b8..08aefe2 100644 +--- a/kernel/cpt/cpt_mm.c ++++ b/kernel/cpt/cpt_mm.c +@@ -653,10 +653,12 @@ static int dump_one_vma(cpt_object_t *mmobj, + cpt_object_t *obj = lookup_cpt_object(CPT_OBJ_FILE, vma->vm_file, ctx); + if (obj == NULL) BUG(); + filp = obj->o_obj; +- if (filp->f_op && +- filp->f_op->read == NULL && +- filp->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_TMPFS) ++ if (filp->f_op == &shm_file_operations) { ++ struct shm_file_data *sfd = filp->private_data; ++ + v->cpt_type = CPT_VMA_TYPE_SHM; ++ obj = lookup_cpt_object(CPT_OBJ_FILE, sfd->file, ctx); ++ } + v->cpt_file = obj->o_pos; + } + +diff --git a/kernel/cpt/rst_files.c b/kernel/cpt/rst_files.c +index 4b4079c..2b6b767 100644 +--- a/kernel/cpt/rst_files.c ++++ b/kernel/cpt/rst_files.c +@@ -1640,7 +1640,7 @@ int rst_stray_files(struct cpt_context *ctx) + + dprintk_ctx("stray file %Ld\n", sec); + +- file = rst_sysv_shm(sec, ctx); ++ file = rst_sysv_shm_itself(sec, ctx); + + if (IS_ERR(file)) { + eprintk_ctx("rst_stray_files: %ld\n", PTR_ERR(file)); +diff --git a/kernel/cpt/rst_mm.c b/kernel/cpt/rst_mm.c +index 1f1e472..9b9808d 100644 +--- a/kernel/cpt/rst_mm.c ++++ b/kernel/cpt/rst_mm.c +@@ -511,7 +511,7 @@ static int do_rst_vma(struct cpt_vma_image *vmai, loff_t vmapos, loff_t mmpos, s + return PTR_ERR(file); + } + } else if (vmai->cpt_type == CPT_VMA_TYPE_SHM) { +- file = rst_sysv_shm(vmai->cpt_file, ctx); ++ file = rst_sysv_shm_vma(vmai, ctx); + if (IS_ERR(file)) + return PTR_ERR(file); + } +diff --git a/kernel/cpt/rst_sysvipc.c b/kernel/cpt/rst_sysvipc.c +index f3c9afe..8803de5 100644 +--- a/kernel/cpt/rst_sysvipc.c ++++ b/kernel/cpt/rst_sysvipc.c +@@ -131,7 +131,7 @@ static int fixup_shm_data(struct file *file, loff_t pos, loff_t end, + return 0; + } + +-struct file * rst_sysv_shm(loff_t pos, struct cpt_context *ctx) ++struct file * rst_sysv_shm_itself(loff_t pos, struct cpt_context *ctx) + { + struct file *file; + int err; +@@ -156,16 +156,98 @@ struct file * rst_sysv_shm(loff_t pos, struct cpt_context *ctx) + goto err_out; + dpos += u.shmi.cpt_next; + +- file = sysvipc_setup_shm(u.shmi.cpt_key, u.shmi.cpt_id, ++ file = sysvipc_setup_shm(u.shmi.cpt_key, u.shmi.cpt_id, + u.shmi.cpt_segsz, u.shmi.cpt_mode); + if (!IS_ERR(file)) { + err = fixup_shm(file, &u.shmi); + if (err != -EEXIST && dpos < epos) + err = fixup_shm_data(file, dpos, epos, ctx); ++ } else if (IS_ERR(file) && PTR_ERR(file) == -EEXIST) { ++ struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; ++ struct shmid_kernel *shp; ++ ++ shp = shm_lock(ipc_ns, u.shmi.cpt_id); ++ BUG_ON(IS_ERR(shp)); ++ get_file(shp->shm_file); ++ file = shp->shm_file; ++ shm_unlock(shp); + } ++ return file; ++ ++err_out: ++ return ERR_PTR(err); ++} ++ ++struct file * rst_sysv_shm_vma(struct cpt_vma_image *vmai, struct cpt_context *ctx) ++{ ++ struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; ++ struct file *file; ++ union { ++ struct cpt_file_image fi; ++ struct cpt_inode_image ii; ++ struct cpt_sysvshm_image shmi; ++ } u; ++ struct shmid_kernel *shp; ++ struct shm_file_data *sfd; ++ struct path path; ++ mode_t f_mode; ++ loff_t pos; ++ int err; ++ ++ pos = vmai->cpt_file; ++ file = rst_sysv_shm_itself(pos, ctx); ++ if (IS_ERR(file) && PTR_ERR(file) != -EEXIST) ++ return file; ++ fput(file); ++ ++ err = rst_get_object(CPT_OBJ_FILE, pos, &u.fi, ctx); ++ if (err < 0) ++ goto err_out; ++ pos = u.fi.cpt_inode; ++ err = rst_get_object(CPT_OBJ_INODE, pos, &u.ii, ctx); ++ if (err < 0) ++ goto err_out; ++ err = rst_get_object(CPT_OBJ_SYSV_SHM, pos + u.ii.cpt_hdrlen, &u.shmi, ctx); ++ if (err < 0) ++ goto err_out; ++ ++ shp = shm_lock(ipc_ns, u.shmi.cpt_id); ++ BUG_ON(IS_ERR(shp)); ++ path.dentry = dget(shp->shm_file->f_path.dentry); ++ path.mnt = shp->shm_file->f_path.mnt; ++ shm_unlock(shp); ++ ++ err = -ENOMEM; ++ sfd = kzalloc(sizeof(*sfd), GFP_KERNEL); ++ if (!sfd) ++ goto out_put_dentry; ++ ++ f_mode = 0; ++ if (vmai->cpt_flags & VM_READ) ++ f_mode |= FMODE_READ; ++ if (vmai->cpt_flags & VM_WRITE) ++ f_mode |= FMODE_WRITE; ++ if (vmai->cpt_flags & VM_EXEC) ++ f_mode |= FMODE_EXEC; ++ ++ err = -ENOMEM; ++ file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations); ++ if (!file) ++ goto out_free; ++ ++ file->private_data = sfd; ++ file->f_mapping = shp->shm_file->f_mapping; ++ sfd->id = shp->shm_perm.id; ++ sfd->ns = get_ipc_ns(ipc_ns); ++ sfd->file = shp->shm_file; ++ sfd->vm_ops = NULL; + + return file; + ++out_free: ++ kfree(sfd); ++out_put_dentry: ++ dput(path.dentry); + err_out: + return ERR_PTR(err); + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0098-VE-igmp-owner-ve.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0098-VE-igmp-owner-ve.patch @@ -0,0 +1,74 @@ +From c9d58c128b1abebc32e9a6d4fbd9209830c3fef6 Mon Sep 17 00:00:00 2001 +From: Denis Lunev +Date: Wed, 2 Jul 2008 19:55:19 +0400 +Subject: [PATCH 098/103] VE igmp owner ve + +IGMP packets should be sent in the context of correct VE. + +Timers by default are processed in the context of VE0. +Obtain the context from device and send the packet inside it. +(Add 2 more timers after tangaldi's patch). +--- + net/ipv4/igmp.c | 9 +++++++++ + 1 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c +index c81ec13..5bfd510 100644 +--- a/net/ipv4/igmp.c ++++ b/net/ipv4/igmp.c +@@ -703,22 +703,28 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, + static void igmp_gq_timer_expire(unsigned long data) + { + struct in_device *in_dev = (struct in_device *)data; ++ struct ve_struct *old_env; + ++ old_env = set_exec_env(in_dev->dev->owner_env); + in_dev->mr_gq_running = 0; + igmpv3_send_report(in_dev, NULL); + __in_dev_put(in_dev); ++ (void)set_exec_env(old_env); + } + + static void igmp_ifc_timer_expire(unsigned long data) + { + struct in_device *in_dev = (struct in_device *)data; ++ struct ve_struct *old_env; + ++ old_env = set_exec_env(in_dev->dev->owner_env); + igmpv3_send_cr(in_dev); + if (in_dev->mr_ifc_count) { + in_dev->mr_ifc_count--; + igmp_ifc_start_timer(in_dev, IGMP_Unsolicited_Report_Interval); + } + __in_dev_put(in_dev); ++ (void)set_exec_env(old_env); + } + + static void igmp_ifc_event(struct in_device *in_dev) +@@ -735,6 +741,7 @@ static void igmp_timer_expire(unsigned long data) + { + struct ip_mc_list *im=(struct ip_mc_list *)data; + struct in_device *in_dev = im->interface; ++ struct ve_struct *old_env; + + spin_lock(&im->lock); + im->tm_running=0; +@@ -746,6 +753,7 @@ static void igmp_timer_expire(unsigned long data) + im->reporter = 1; + spin_unlock(&im->lock); + ++ old_env = set_exec_env(in_dev->dev->owner_env); + if (IGMP_V1_SEEN(in_dev)) + igmp_send_report(in_dev, im, IGMP_HOST_MEMBERSHIP_REPORT); + else if (IGMP_V2_SEEN(in_dev)) +@@ -754,6 +762,7 @@ static void igmp_timer_expire(unsigned long data) + igmp_send_report(in_dev, im, IGMPV3_HOST_MEMBERSHIP_REPORT); + + ip_ma_put(im); ++ (void)set_exec_env(old_env); + } + + /* mark EXCLUDE-mode sources */ +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0086-CPT-reopen-dentries.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0086-CPT-reopen-dentries.patch @@ -0,0 +1,83 @@ +From 3a7f9103e864afaf9ee091a792fee72e2918bfd8 Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Mon, 30 Jun 2008 13:48:48 +0400 +Subject: [PATCH 086/103] CPT reopen dentries + +Dentries were not reopened correctly during checkpointing and restore. + +Two bugs fixed: +1. In case of huge files (more then 2Gb) dentry_open() returns -EFBIG if + O_LARGEFILE flag is not set. This flag should be used for temporary files + used during checkpointing and restore process. + Bug #99544 + +2. In dump_content_regular() we have following code: + file = dentry_open(dget(file->f_dentry), + mntget(file->f_vfsmnt), O_RDONLY); + if (IS_ERR(file)) { + cpt_printk_dentry(file->f_dentry, file->f_vfsmnt); + eprintk_ctx("cannot reopen file for read %ld\n", PTR_ERR(file)); + return PTR_ERR(file); + } + + Which results in kernel oops if dentry_open() returns error + (e.g. -EFBIG because of bug #99544) + + Bug #99542 +--- + kernel/cpt/cpt_files.c | 15 +++++++++------ + kernel/cpt/rst_files.c | 3 ++- + 2 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/kernel/cpt/cpt_files.c b/kernel/cpt/cpt_files.c +index e728b64..ec24ba7 100644 +--- a/kernel/cpt/cpt_files.c ++++ b/kernel/cpt/cpt_files.c +@@ -627,13 +627,16 @@ static int dump_content_regular(struct file *file, struct cpt_context *ctx) + + if (!(file->f_mode & FMODE_READ) || + (file->f_flags & O_DIRECT)) { +- file = dentry_open(dget(file->f_dentry), +- mntget(file->f_vfsmnt), O_RDONLY); +- if (IS_ERR(file)) { ++ struct file *filp; ++ filp = dentry_open(dget(file->f_dentry), ++ mntget(file->f_vfsmnt), ++ O_RDONLY | O_LARGEFILE); ++ if (IS_ERR(filp)) { + cpt_printk_dentry(file->f_dentry, file->f_vfsmnt); +- eprintk_ctx("cannot reopen file for read %ld\n", PTR_ERR(file)); +- return PTR_ERR(file); ++ eprintk_ctx("cannot reopen file for read %ld\n", PTR_ERR(filp)); ++ return PTR_ERR(filp); + } ++ file = filp; + } else { + atomic_inc(&file->f_count); + } +@@ -895,7 +898,7 @@ static int find_linked_dentry(struct dentry *d, struct vfsmount *mnt, + return -EINVAL; + + mntget(mnt); +- f = dentry_open(de, mnt, O_RDONLY); ++ f = dentry_open(de, mnt, O_RDONLY | O_LARGEFILE); + if (IS_ERR(f)) + return PTR_ERR(f); + +diff --git a/kernel/cpt/rst_files.c b/kernel/cpt/rst_files.c +index fd29b60..06dcc2c 100644 +--- a/kernel/cpt/rst_files.c ++++ b/kernel/cpt/rst_files.c +@@ -524,7 +524,8 @@ static int fixup_reg_data(struct file *file, loff_t pos, loff_t end, + (file->f_flags&O_DIRECT)) { + fput(file); + file = dentry_open(dget(file->f_dentry), +- mntget(file->f_vfsmnt), O_WRONLY); ++ mntget(file->f_vfsmnt), ++ O_WRONLY | O_LARGEFILE); + if (IS_ERR(file)) { + __cpt_release_buf(ctx); + return PTR_ERR(file); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0068-Leave-irq-state-alone-during-call_console_drivers.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0068-Leave-irq-state-alone-during-call_console_drivers.patch @@ -0,0 +1,31 @@ +From 551b0650d9b192116226b8f55bdeda4953a062d6 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Tue, 22 Apr 2008 15:20:19 +0400 +Subject: [PATCH 67/67] Leave irq state alone during call_console_drivers() + +Mainline does so at least. + +http://bugzilla.openvz.org/show_bug.cgi?id=812 +--- + kernel/printk.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kernel/printk.c b/kernel/printk.c +index bd62078..0c91174 100644 +--- a/kernel/printk.c ++++ b/kernel/printk.c +@@ -1105,9 +1105,9 @@ static unsigned long do_release_console_sem(unsigned long *flags) + _con_start = con_start; + _log_end = log_end; + con_start = log_end; /* Flush */ +- spin_unlock_irqrestore(&logbuf_lock, *flags); ++ spin_unlock(&logbuf_lock); + call_console_drivers(_con_start, _log_end); +- spin_lock_irqsave(&logbuf_lock, *flags); ++ spin_lock(&logbuf_lock); + } + out: + return wake_klogd; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0117-UBC-irq-sequence-fix.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0117-UBC-irq-sequence-fix.patch @@ -0,0 +1,29 @@ +From ed9efe4cf895f9bc6b66de37830383207bd90302 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 18 Jul 2008 15:25:49 +0400 +Subject: [PATCH 117/131] UBC irq sequence fix + +fix irq enable/disable sequence in case CONFIG_BEANCOUNTERS=n +http://bugzilla.openvz.org/show_bug.cgi?id=433 +--- + kernel/pid.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/kernel/pid.c b/kernel/pid.c +index 225d221..e26509f 100644 +--- a/kernel/pid.c ++++ b/kernel/pid.c +@@ -312,9 +312,9 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t vpid) + for (type = 0; type < PIDTYPE_MAX; ++type) + INIT_HLIST_HEAD(&pid->tasks[type]); + ++ local_irq_disable(); + #ifdef CONFIG_BEANCOUNTERS + ub = get_exec_ub(); +- local_irq_disable(); + if (ub_kmemsize_charge(ub, ns->pid_cachep->objuse, UB_HARD)) + goto out_enable; + pid->ub = get_beancounter(ub); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0028-NETFILTER-add-back-__init-__exit-markers-for-nf_con.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0028-NETFILTER-add-back-__init-__exit-markers-for-nf_con.patch @@ -0,0 +1,34 @@ +From 5b45e0d2b46b4a7293f61fa8f7bf4d48ddcdf267 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 14 Mar 2008 15:57:51 +0300 +Subject: [PATCH 28/48] NETFILTER: add back __init/__exit markers for nf_conntrack_ipv4 + +--- + net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +index fee3438..bbbfee7 100644 +--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c ++++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +@@ -607,7 +607,7 @@ void fini_nf_ct_l3proto_ipv4(void) + } + EXPORT_SYMBOL(fini_nf_ct_l3proto_ipv4); + +-static int nf_conntrack_l3proto_ipv4_init(void) ++static int __init nf_conntrack_l3proto_ipv4_init(void) + { + int ret = 0; + +@@ -634,7 +634,7 @@ static int nf_conntrack_l3proto_ipv4_init(void) + return ret; + } + +-static void nf_conntrack_l3proto_ipv4_fini(void) ++static void __exit nf_conntrack_l3proto_ipv4_fini(void) + { + synchronize_net(); + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0150-MS-NETNS-Namespace-stop-vs-ip-r-l-race.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0150-MS-NETNS-Namespace-stop-vs-ip-r-l-race.patch @@ -0,0 +1,98 @@ +From e8cde2114d19cad865298b0e5dbb4912a137cc30 Mon Sep 17 00:00:00 2001 +From: Denis V. Lunev +Date: Fri, 18 Jan 2008 23:55:19 -0800 +Subject: [PATCH] MS NETNS Namespace stop vs 'ip r l' race + +mainstream commit 775516bfa2bd7993620c9039191a0c30b8d8a496 + +During network namespace stop process kernel side netlink sockets +belonging to a namespace should be closed. They should not prevent +namespace to stop, so they do not increment namespace usage +counter. Though this counter will be put during last sock_put. + +The raplacement of the correct netns for init_ns solves the problem +only partial as socket to be stoped until proper stop is a valid +netlink kernel socket and can be looked up by the user processes. This +is not a problem until it resides in initial namespace (no processes +inside this net), but this is not true for init_net. + +So, hold the referrence for a socket, remove it from lookup tables and +only after that change namespace and perform a last put. + +Signed-off-by: Denis V. Lunev +Tested-by: Alexey Dobriyan +Signed-off-by: David S. Miller +--- + net/core/rtnetlink.c | 15 ++------------- + net/netlink/af_netlink.c | 15 +++++++++++++++ + 2 files changed, 17 insertions(+), 13 deletions(-) + +diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c +index 6ed7e74..68675f1 100644 +--- a/net/core/rtnetlink.c ++++ b/net/core/rtnetlink.c +@@ -1370,25 +1370,14 @@ static int rtnetlink_net_init(struct net *net) + rtnetlink_rcv, &rtnl_mutex, THIS_MODULE); + if (!sk) + return -ENOMEM; +- +- /* Don't hold an extra reference on the namespace */ +- put_net(sk->sk_net); + net->rtnl = sk; + return 0; + } + + static void rtnetlink_net_exit(struct net *net) + { +- struct sock *sk = net->rtnl; +- if (sk) { +- /* At the last minute lie and say this is a socket for the +- * initial network namespace. So the socket will be safe to +- * free. +- */ +- sk->sk_net = get_net(&init_net); +- netlink_kernel_release(net->rtnl); +- net->rtnl = NULL; +- } ++ netlink_kernel_release(net->rtnl); ++ net->rtnl = NULL; + } + + static struct pernet_operations rtnetlink_net_ops = { +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index cf31346..716c31d 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1400,6 +1400,9 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, + } + netlink_table_ungrab(); + ++ /* Do not hold an extra referrence to a namespace as this socket is ++ * internal to a namespace and does not prevent it to stop. */ ++ put_net(net); + return sk; + + out_sock_release: +@@ -1414,7 +1417,19 @@ netlink_kernel_release(struct sock *sk) + { + if (sk == NULL || sk->sk_socket == NULL) + return; ++ ++ /* ++ * Last sock_put should drop referrence to sk->sk_net. It has already ++ * been dropped in netlink_kernel_create. Taking referrence to stopping ++ * namespace is not an option. ++ * Take referrence to a socket to remove it from netlink lookup table ++ * _alive_ and after that destroy it in the context of init_net. ++ */ ++ sock_hold(sk); + sock_release(sk->sk_socket); ++ ++ sk->sk_net = get_net(&init_net); ++ sock_put(sk); + } + EXPORT_SYMBOL(netlink_kernel_release); + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0139-VE-NETFILTER-destroy-nf_conntrack_cache-correctly.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0139-VE-NETFILTER-destroy-nf_conntrack_cache-correctly.patch @@ -0,0 +1,26 @@ +From 144e92142adf7bf1ca8221ec1b951e65e4cdb63c Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Tue, 10 Jun 2008 16:55:18 +0400 +Subject: [PATCH] VE NETFILTER destroy nf_conntrack_cache correctly + +--- + net/netfilter/nf_conntrack_core.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 742b808..3fb2bf7 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1021,7 +1021,8 @@ void nf_conntrack_cleanup(void) + + rcu_assign_pointer(nf_ct_destroy, NULL); + +- kmem_cache_destroy(nf_conntrack_cachep); ++ if (ve_is_super(ve)) ++ kmem_cache_destroy(nf_conntrack_cachep); + skip_ct_cache: + nf_conntrack_helper_fini(); + nf_conntrack_expect_fini(); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0092-UBC-release-udp-once.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0092-UBC-release-udp-once.patch @@ -0,0 +1,31 @@ +From e01cb0998c6c084e1aa2a81e7837d434ba1ec9d8 Mon Sep 17 00:00:00 2001 +From: Denis Lunev +Date: Mon, 30 Jun 2008 13:48:49 +0400 +Subject: [PATCH 092/103] UBC release udp once + +The socket resided in UB space waiting queue could be released. In this +case ub_snd_wakeup running on the another CPU could hold/release that +socket effectively hitting 0 refcounter second time. + +Bug #112170 +--- + net/socket.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/net/socket.c b/net/socket.c +index 6625730..fbeafc6 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -513,6 +513,9 @@ const struct file_operations bad_sock_fops = { + + void sock_release(struct socket *sock) + { ++ if (sock->sk) ++ ub_sock_sndqueuedel(sock->sk); ++ + if (sock->ops) { + struct module *owner = sock->ops->owner; + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0149-MS-NETNS-Consolidate-kernel-netlink-socket-destructi.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0149-MS-NETNS-Consolidate-kernel-netlink-socket-destructi.patch @@ -0,0 +1,304 @@ +From b1a0175d49f9e1186c59c2b2c5a61c8d74d62c53 Mon Sep 17 00:00:00 2001 +From: Denis V. Lunev +Date: Mon, 28 Jan 2008 14:41:19 -0800 +Subject: [PATCH] MS NETNS Consolidate kernel netlink socket destruction + +mainstream commit b7c6ba6eb1234e35a74fb8ba8123232a7b1ba9e4 + +Create a specific helper for netlink kernel socket disposal. This just +let the code look better and provides a ground for proper disposal +inside a namespace. + +Signed-off-by: Denis V. Lunev +Tested-by: Alexey Dobriyan +Signed-off-by: David S. Miller +--- + drivers/connector/connector.c | 9 +++------ + drivers/scsi/scsi_netlink.c | 2 +- + drivers/scsi/scsi_transport_iscsi.c | 2 +- + fs/ecryptfs/netlink.c | 3 +-- + include/linux/netlink.h | 1 + + net/bridge/netfilter/ebt_ulog.c | 4 ++-- + net/core/rtnetlink.c | 2 +- + net/decnet/netfilter/dn_rtmsg.c | 4 ++-- + net/ipv4/inet_diag.c | 2 +- + net/ipv4/netfilter/ip_queue.c | 4 ++-- + net/ipv4/netfilter/ipt_ULOG.c | 4 ++-- + net/ipv6/netfilter/ip6_queue.c | 4 ++-- + net/netfilter/nfnetlink.c | 2 +- + net/netlink/af_netlink.c | 11 +++++++++++ + net/xfrm/xfrm_user.c | 2 +- + 15 files changed, 32 insertions(+), 24 deletions(-) + +diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c +index bf9716b..615bc09 100644 +--- a/drivers/connector/connector.c ++++ b/drivers/connector/connector.c +@@ -441,8 +441,7 @@ static int __devinit cn_init(void) + + dev->cbdev = cn_queue_alloc_dev("cqueue", dev->nls); + if (!dev->cbdev) { +- if (dev->nls->sk_socket) +- sock_release(dev->nls->sk_socket); ++ netlink_kernel_release(dev->nls); + return -EINVAL; + } + +@@ -452,8 +451,7 @@ static int __devinit cn_init(void) + if (err) { + cn_already_initialized = 0; + cn_queue_free_dev(dev->cbdev); +- if (dev->nls->sk_socket) +- sock_release(dev->nls->sk_socket); ++ netlink_kernel_release(dev->nls); + return -EINVAL; + } + +@@ -468,8 +466,7 @@ static void __devexit cn_fini(void) + + cn_del_callback(&dev->id); + cn_queue_free_dev(dev->cbdev); +- if (dev->nls->sk_socket) +- sock_release(dev->nls->sk_socket); ++ netlink_kernel_release(dev->nls); + } + + subsys_initcall(cn_init); +diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c +index 40579ed..fe48c24 100644 +--- a/drivers/scsi/scsi_netlink.c ++++ b/drivers/scsi/scsi_netlink.c +@@ -169,7 +169,7 @@ void + scsi_netlink_exit(void) + { + if (scsi_nl_sock) { +- sock_release(scsi_nl_sock->sk_socket); ++ netlink_kernel_release(scsi_nl_sock); + netlink_unregister_notifier(&scsi_netlink_notifier); + } + +diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c +index 5428d15..9e463a6 100644 +--- a/drivers/scsi/scsi_transport_iscsi.c ++++ b/drivers/scsi/scsi_transport_iscsi.c +@@ -1533,7 +1533,7 @@ unregister_transport_class: + + static void __exit iscsi_transport_exit(void) + { +- sock_release(nls->sk_socket); ++ netlink_kernel_release(nls); + transport_class_unregister(&iscsi_connection_class); + transport_class_unregister(&iscsi_session_class); + transport_class_unregister(&iscsi_host_class); +diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c +index 9aa3451..f638a69 100644 +--- a/fs/ecryptfs/netlink.c ++++ b/fs/ecryptfs/netlink.c +@@ -237,7 +237,6 @@ out: + */ + void ecryptfs_release_netlink(void) + { +- if (ecryptfs_nl_sock && ecryptfs_nl_sock->sk_socket) +- sock_release(ecryptfs_nl_sock->sk_socket); ++ netlink_kernel_release(ecryptfs_nl_sock); + ecryptfs_nl_sock = NULL; + } +diff --git a/include/linux/netlink.h b/include/linux/netlink.h +index d5bfaba..530b27c 100644 +--- a/include/linux/netlink.h ++++ b/include/linux/netlink.h +@@ -178,6 +178,7 @@ extern struct sock *netlink_kernel_create(struct net *net, + void (*input)(struct sk_buff *skb), + struct mutex *cb_mutex, + struct module *module); ++extern void netlink_kernel_release(struct sock *sk); + extern int netlink_change_ngroups(struct sock *sk, unsigned int groups); + extern void netlink_clear_multicast_users(struct sock *sk, unsigned int group); + extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); +diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c +index e7cfd30..d756bcf 100644 +--- a/net/bridge/netfilter/ebt_ulog.c ++++ b/net/bridge/netfilter/ebt_ulog.c +@@ -306,7 +306,7 @@ static int __init ebt_ulog_init(void) + if (!ebtulognl) + ret = -ENOMEM; + else if ((ret = ebt_register_watcher(&ulog))) +- sock_release(ebtulognl->sk_socket); ++ netlink_kernel_release(ebtulognl); + + if (ret == 0) + nf_log_register(PF_BRIDGE, &ebt_ulog_logger); +@@ -332,7 +332,7 @@ static void __exit ebt_ulog_fini(void) + } + spin_unlock_bh(&ub->lock); + } +- sock_release(ebtulognl->sk_socket); ++ netlink_kernel_release(ebtulognl); + } + + module_init(ebt_ulog_init); +diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c +index e025b0c..6ed7e74 100644 +--- a/net/core/rtnetlink.c ++++ b/net/core/rtnetlink.c +@@ -1386,7 +1386,7 @@ static void rtnetlink_net_exit(struct net *net) + * free. + */ + sk->sk_net = get_net(&init_net); +- sock_release(net->rtnl->sk_socket); ++ netlink_kernel_release(net->rtnl); + net->rtnl = NULL; + } + } +diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c +index eca4340..5ba99b3 100644 +--- a/net/decnet/netfilter/dn_rtmsg.c ++++ b/net/decnet/netfilter/dn_rtmsg.c +@@ -137,7 +137,7 @@ static int __init dn_rtmsg_init(void) + + rv = nf_register_hook(&dnrmg_ops); + if (rv) { +- sock_release(dnrmg->sk_socket); ++ netlink_kernel_release(dnrmg); + } + + return rv; +@@ -146,7 +146,7 @@ static int __init dn_rtmsg_init(void) + static void __exit dn_rtmsg_fini(void) + { + nf_unregister_hook(&dnrmg_ops); +- sock_release(dnrmg->sk_socket); ++ netlink_kernel_release(dnrmg); + } + + +diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c +index 2715ada..a859c34 100644 +--- a/net/ipv4/inet_diag.c ++++ b/net/ipv4/inet_diag.c +@@ -944,7 +944,7 @@ out_free_table: + + static void __exit inet_diag_exit(void) + { +- sock_release(idiagnl->sk_socket); ++ netlink_kernel_release(idiagnl); + kfree(inet_diag_table); + } + +diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c +index 1b5847d..d8ba67d 100644 +--- a/net/ipv4/netfilter/ip_queue.c ++++ b/net/ipv4/netfilter/ip_queue.c +@@ -690,7 +690,7 @@ cleanup_sysctl: + unregister_netdevice_notifier(&ipq_dev_notifier); + proc_net_remove(&init_net, IPQ_PROC_FS_NAME); + cleanup_ipqnl: +- sock_release(ipqnl->sk_socket); ++ netlink_kernel_release(ipqnl); + mutex_lock(&ipqnl_mutex); + mutex_unlock(&ipqnl_mutex); + +@@ -709,7 +709,7 @@ static void __exit ip_queue_fini(void) + unregister_netdevice_notifier(&ipq_dev_notifier); + proc_net_remove(&init_net, IPQ_PROC_FS_NAME); + +- sock_release(ipqnl->sk_socket); ++ netlink_kernel_release(ipqnl); + mutex_lock(&ipqnl_mutex); + mutex_unlock(&ipqnl_mutex); + +diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c +index 212b830..b02b928 100644 +--- a/net/ipv4/netfilter/ipt_ULOG.c ++++ b/net/ipv4/netfilter/ipt_ULOG.c +@@ -417,7 +417,7 @@ static int __init ipt_ulog_init(void) + + ret = xt_register_target(&ipt_ulog_reg); + if (ret < 0) { +- sock_release(nflognl->sk_socket); ++ netlink_kernel_release(nflognl); + return ret; + } + if (nflog) +@@ -436,7 +436,7 @@ static void __exit ipt_ulog_fini(void) + if (nflog) + nf_log_unregister(&ipt_ulog_logger); + xt_unregister_target(&ipt_ulog_reg); +- sock_release(nflognl->sk_socket); ++ netlink_kernel_release(nflognl); + + /* remove pending timers and free allocated skb's */ + for (i = 0; i < ULOG_MAXNLGROUPS; i++) { +diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c +index f1a3b2b..14ac71d 100644 +--- a/net/ipv6/netfilter/ip6_queue.c ++++ b/net/ipv6/netfilter/ip6_queue.c +@@ -680,7 +680,7 @@ cleanup_sysctl: + proc_net_remove(&init_net, IPQ_PROC_FS_NAME); + + cleanup_ipqnl: +- sock_release(ipqnl->sk_socket); ++ netlink_kernel_release(ipqnl); + mutex_lock(&ipqnl_mutex); + mutex_unlock(&ipqnl_mutex); + +@@ -699,7 +699,7 @@ static void __exit ip6_queue_fini(void) + unregister_netdevice_notifier(&ipq_dev_notifier); + proc_net_remove(&init_net, IPQ_PROC_FS_NAME); + +- sock_release(ipqnl->sk_socket); ++ netlink_kernel_release(ipqnl); + mutex_lock(&ipqnl_mutex); + mutex_unlock(&ipqnl_mutex); + +diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c +index 32007af..04491ab 100644 +--- a/net/netfilter/nfnetlink.c ++++ b/net/netfilter/nfnetlink.c +@@ -179,7 +179,7 @@ static void nfnetlink_rcv(struct sk_buff *skb) + static void __exit nfnetlink_exit(void) + { + printk("Removing netfilter NETLINK layer.\n"); +- sock_release(nfnl->sk_socket); ++ netlink_kernel_release(nfnl); + return; + } + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index fcdd345..cf31346 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1408,6 +1408,17 @@ out_sock_release: + return NULL; + } + ++ ++void ++netlink_kernel_release(struct sock *sk) ++{ ++ if (sk == NULL || sk->sk_socket == NULL) ++ return; ++ sock_release(sk->sk_socket); ++} ++EXPORT_SYMBOL(netlink_kernel_release); ++ ++ + /** + * netlink_change_ngroups - change number of multicast groups + * +diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c +index a128476..52c6535 100644 +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -2420,7 +2420,7 @@ static void __exit xfrm_user_exit(void) + xfrm_unregister_km(&netlink_mgr); + rcu_assign_pointer(xfrm_nl, NULL); + synchronize_rcu(); +- sock_release(nlsk->sk_socket); ++ netlink_kernel_release(nlsk); + } + + module_init(xfrm_user_init); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0006-CPT-select-tun-venet-veth-modules.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0006-CPT-select-tun-venet-veth-modules.patch @@ -0,0 +1,30 @@ +From b1a7063c226542f1f62972173056fa0971f9d9e8 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 3 Mar 2008 13:46:34 +0300 +Subject: [PATCH 06/48] CPT: select tun, venet, veth modules + +CONFIG_VZ_CHEKPOINT=y, CONFIG_TUN=m result in linking breakage +because CPT can't find tun_chr_open() et al. + +So, if you build CPT as standalone, tun/tap will be also standalone. +--- + kernel/Kconfig.openvz | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/kernel/Kconfig.openvz b/kernel/Kconfig.openvz +index 7371679..5cdcdd3 100644 +--- a/kernel/Kconfig.openvz ++++ b/kernel/Kconfig.openvz +@@ -71,6 +71,9 @@ config VZ_CHECKPOINT + tristate "Checkpointing & restoring Virtual Environments" + depends on VE_CALLS && INET + select PM_SLEEP ++ select TUN ++ select VE_ETHDEV ++ select VE_NETDEV + default m + help + This option adds two modules, "cpt" and "rst", which allow +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0130-VE-vzdq-vzaquota-proc-nlink.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0130-VE-vzdq-vzaquota-proc-nlink.patch @@ -0,0 +1,67 @@ +From abb3f592cc62d01f96ca4fdeb8fdd6affaf95633 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 18 Jul 2008 15:25:58 +0400 +Subject: [PATCH 130/131] VE vzdq vzaquota proc nlink + +Produce correct nlink count for /proc/vz/vzaquota + +Use count mounpoints accessible from VE as upper estimate for +count subdirectories inside /proc/vz/vzaquot. +Concept stolen from vzdq_aquotd_readdir. + +Disable enumation in VE0 for performance reason (like in _readdir and _lookup) + +Bug #115343 +--- + fs/vzdq_file.c | 28 ++++++++++++++++++++++++++++ + 1 files changed, 28 insertions(+), 0 deletions(-) + +diff --git a/fs/vzdq_file.c b/fs/vzdq_file.c +index 5b4133a..f63689a 100644 +--- a/fs/vzdq_file.c ++++ b/fs/vzdq_file.c +@@ -851,6 +851,33 @@ out: + return ERR_PTR(-ENOENT); + } + ++static int vzdq_aquotd_getattr(struct vfsmount *mnt, struct dentry *dentry, ++ struct kstat *stat) ++{ ++ struct ve_struct *ve, *old_ve; ++ struct list_head mntlist, *pos; ++ ++ generic_fillattr(dentry->d_inode, stat); ++ ve = dentry->d_sb->s_type->owner_env; ++#ifdef CONFIG_VE ++ /* ++ * The only reason of disabling getattr for the host system is that ++ * this getattr can be slow and CPU consuming with large number of VPSs ++ * (or just mount points). ++ */ ++ if (ve_is_super(ve)) ++ return 0; ++#endif ++ INIT_LIST_HEAD(&mntlist); ++ old_ve = set_exec_env(ve); ++ if (!vzdq_aquot_buildmntlist(ve, &mntlist)) ++ list_for_each(pos, &mntlist) ++ stat->nlink++; ++ vzdq_aquot_releasemntlist(ve, &mntlist); ++ (void)set_exec_env(old_ve); ++ return 0; ++} ++ + static struct file_operations vzdq_aquotd_file_operations = { + .read = &generic_read_dir, + .readdir = &vzdq_aquotd_readdir, +@@ -858,6 +885,7 @@ static struct file_operations vzdq_aquotd_file_operations = { + + static struct inode_operations vzdq_aquotd_inode_operations = { + .lookup = &vzdq_aquotd_lookup, ++ .getattr = &vzdq_aquotd_getattr, + }; + + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0070-Backport-SLUB-Do-not-upset-lockdep.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0070-Backport-SLUB-Do-not-upset-lockdep.patch @@ -0,0 +1,74 @@ +From 6b35cc2ae08825f32c9e5a763c14aa89905d2444 Mon Sep 17 00:00:00 2001 +From: Peter Zijlstra +Date: Fri, 25 Apr 2008 13:11:31 +0400 +Subject: [PATCH 69/72] Backport "SLUB: Do not upset lockdep" + +http://bugzilla.openvz.org/show_bug.cgi?id=873 + +commit ba84c73c7ae21fc891a3c2576fa3be42752fce53 +Author: root +Date: Mon Jan 7 23:20:28 2008 -0800 + + SLUB: Do not upset lockdep + + inconsistent {softirq-on-W} -> {in-softirq-W} usage. + swapper/0 [HC0[0]:SC1[1]:HE0:SE0] takes: + (&n->list_lock){-+..}, at: [] add_partial+0x31/0xa0 + {softirq-on-W} state was registered at: + [] __lock_acquire+0x3e8/0x1140 + [] debug_check_no_locks_freed+0x188/0x1a0 + [] lock_acquire+0x55/0x70 + [] add_partial+0x31/0xa0 + [] _spin_lock+0x1e/0x30 + [] add_partial+0x31/0xa0 + [] kmem_cache_open+0x1cc/0x330 + [] _spin_unlock_irq+0x24/0x30 + [] create_kmalloc_cache+0x64/0xf0 + [] init_alloc_cpu_cpu+0x70/0x90 + [] kmem_cache_init+0x65/0x1d0 + [] start_kernel+0x23e/0x350 + [] _sinittext+0x12d/0x140 + [] 0xffffffffffffffff + + This change isn't really necessary for correctness, but it prevents lockdep + from getting upset and then disabling itself. + + Signed-off-by: Peter Zijlstra + Cc: Christoph Lameter + Cc: Kamalesh Babulal + Signed-off-by: Andrew Morton + Signed-off-by: Christoph Lameter +--- + mm/slub.c | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/mm/slub.c b/mm/slub.c +index ad0717a..734b0ba 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -2127,6 +2127,7 @@ static struct kmem_cache_node *early_kmem_cache_node_alloc(gfp_t gfpflags, + { + struct page *page; + struct kmem_cache_node *n; ++ unsigned long flags; + + BUG_ON(kmalloc_caches->size < sizeof(struct kmem_cache_node)); + +@@ -2151,7 +2152,14 @@ static struct kmem_cache_node *early_kmem_cache_node_alloc(gfp_t gfpflags, + #endif + init_kmem_cache_node(n); + atomic_long_inc(&n->nr_slabs); ++ /* ++ * lockdep requires consistent irq usage for each lock ++ * so even though there cannot be a race this early in ++ * the boot sequence, we still disable irqs. ++ */ ++ local_irq_save(flags); + add_partial(n, page); ++ local_irq_restore(flags); + return n; + } + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0138-VE-NETFILTER-make-ip_conntrack_disable_ve0-option-do.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0138-VE-NETFILTER-make-ip_conntrack_disable_ve0-option-do.patch @@ -0,0 +1,42 @@ +From 7d7f1709db01ef933d1f711914f12998a7bdcc41 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 16 May 2008 17:39:02 +0400 +Subject: [PATCH] VE NETFILTER make ip_conntrack_disable_ve0 option do something + +--- + net/netfilter/nf_conntrack_standalone.c | 12 ++++++++++-- + 1 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c +index 55161c5..3b2df53 100644 +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -511,6 +511,9 @@ int nf_conntrack_init_ve(void) + if (err) + goto out; + ++ if (ve_is_super(ve) && ip_conntrack_disable_ve0) ++ return 0; ++ + ve_nf_conntrack_checksum = nf_conntrack_checksum; + + err = nf_conntrack_init_ve_sysctl(ve); +@@ -533,8 +536,13 @@ out: + + void nf_conntrack_cleanup_ve(void) + { +- nf_conntrack_fini_ve_proc(get_exec_env()); +- nf_conntrack_fini_ve_sysctl(get_exec_env()); ++ struct ve_struct *ve = get_exec_env(); ++ ++ if (ve_is_super(ve) && ip_conntrack_disable_ve0) ++ goto cleanup; ++ nf_conntrack_fini_ve_proc(ve); ++ nf_conntrack_fini_ve_sysctl(ve); ++cleanup: + nf_conntrack_cleanup(); + } + EXPORT_SYMBOL(nf_conntrack_cleanup_ve); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0059-Add-per-VE-proc-net-raw6.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0059-Add-per-VE-proc-net-raw6.patch @@ -0,0 +1,70 @@ +From 2670e872531c35866f12598970ee812456c0e9ee Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Tue, 1 Apr 2008 18:28:28 +0400 +Subject: [PATCH 58/67] Add per-VE /proc/net/raw6 + +Show only connections of current VE (already implemented) + +Required for netstat +http://bugzilla.openvz.org/show_bug.cgi?id=860 + +and fix small bug in v4 raw socket proc -- call unregister_pernet_subsys +instead of remove_proc_entry(). +--- + net/ipv4/raw.c | 2 +- + net/ipv6/raw.c | 21 ++++++++++++++++++--- + 2 files changed, 19 insertions(+), 4 deletions(-) + +diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c +index 8e0df71..abf5873 100644 +--- a/net/ipv4/raw.c ++++ b/net/ipv4/raw.c +@@ -953,6 +953,6 @@ int __init raw_proc_init(void) + + void __init raw_proc_exit(void) + { +- proc_net_remove(&init_net, "raw"); ++ unregister_pernet_subsys(&raw_net_ops); + } + #endif /* CONFIG_PROC_FS */ +diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c +index f6dcbe4..1cc3e0f 100644 +--- a/net/ipv6/raw.c ++++ b/net/ipv6/raw.c +@@ -1314,15 +1314,30 @@ static const struct file_operations raw6_seq_fops = { + .release = seq_release_private, + }; + +-int __init raw6_proc_init(void) ++static int raw6_net_init(struct net *net) + { +- if (!proc_net_fops_create(&init_net, "raw6", S_IRUGO, &raw6_seq_fops)) ++ if (!proc_net_fops_create(net, "raw6", S_IRUGO, &raw6_seq_fops)) + return -ENOMEM; + return 0; + } + ++static void raw6_net_exit(struct net *net) ++{ ++ proc_net_remove(net, "raw6"); ++} ++ ++static struct pernet_operations raw6_net_ops = { ++ .init = raw6_net_init, ++ .exit = raw6_net_exit, ++}; ++ ++int __init raw6_proc_init(void) ++{ ++ return register_pernet_subsys(&raw6_net_ops); ++} ++ + void raw6_proc_exit(void) + { +- proc_net_remove(&init_net, "raw6"); ++ unregister_pernet_subsys(&raw6_net_ops); + } + #endif /* CONFIG_PROC_FS */ +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0018-FAIRSCHED-add-scheduler-grouping-based-on-stock-gro.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0018-FAIRSCHED-add-scheduler-grouping-based-on-stock-gro.patch @@ -0,0 +1,244 @@ +From a02e3acb4a97ede13b34641754c27416338e1426 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Wed, 12 Mar 2008 18:07:48 +0300 +Subject: [PATCH 18/48] FAIRSCHED: add scheduler grouping based on stock grouping code + +--- + include/linux/fairsched.h | 61 +++++++++++++++++++++++++++++++++++++++++++++ + include/linux/init_task.h | 2 + + include/linux/sched.h | 3 ++ + init/Kconfig | 6 ++++ + kernel/Makefile | 1 + + kernel/exit.c | 2 + + kernel/fork.c | 1 + + kernel/sched.c | 4 +++ + kernel/vzfairsched.c | 30 ++++++++++++++++++++++ + 9 files changed, 110 insertions(+), 0 deletions(-) + create mode 100644 include/linux/fairsched.h + create mode 100644 kernel/vzfairsched.c + +Index: kernel/include/linux/fairsched.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/include/linux/fairsched.h 2008-11-24 15:57:08.000000000 +0100 +@@ -0,0 +1,61 @@ ++/* ++ * Fair Scheduler ++ * ++ * Copyright (C) 2000-2008 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#ifndef __LINUX_FAIRSCHED_H__ ++#define __LINUX_FAIRSCHED_H__ ++ ++#ifdef __KERNEL__ ++ ++/* refcnt change protected with tasklist write lock */ ++struct fairsched_node { ++ struct task_group *tg; ++ int refcnt; ++ unsigned id; ++ struct list_head nodelist; ++}; ++ ++#ifdef CONFIG_VZ_FAIRSCHED ++ ++#define FAIRSCHED_INIT_NODE_ID INT_MAX ++ ++extern struct fairsched_node fairsched_init_node; ++ ++void fairsched_init_early(void); ++ ++static inline int task_fairsched_node_id(struct task_struct *p) ++{ ++ return p->fsched_node->id; ++} ++ ++/* must called with tasklist write locked */ ++static inline void get_task_fairsched_node(struct task_struct *p) ++{ ++ p->fsched_node->refcnt++; ++} ++static inline void put_task_fairsched_node(struct task_struct *p) ++{ ++ p->fsched_node->refcnt--; ++} ++ ++#define INIT_VZ_FAIRSCHED .fsched_node = &fairsched_init_node, ++ ++#else /* CONFIG_VZ_FAIRSCHED */ ++ ++static inline void fairsched_init_early(void) { } ++static inline int task_fairsched_node_id(struct task_struct *p) { return 0; } ++static inline void get_task_fairsched_node(struct task_struct *p) { } ++static inline void put_task_fairsched_node(struct task_struct *p) { } ++ ++#define INIT_VZ_FAIRSCHED ++ ++#endif /* CONFIG_VZ_FAIRSCHED */ ++#endif /* __KERNEL__ */ ++ ++#endif /* __LINUX_FAIRSCHED_H__ */ +Index: kernel/include/linux/init_task.h +=================================================================== +--- kernel.orig/include/linux/init_task.h 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/include/linux/init_task.h 2008-11-24 15:57:08.000000000 +0100 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #define INIT_FDTABLE \ + { \ +@@ -180,6 +181,7 @@ + .dirties = INIT_PROP_LOCAL_SINGLE(dirties), \ + INIT_TRACE_IRQFLAGS \ + INIT_LOCKDEP \ ++ INIT_VZ_FAIRSCHED \ + } + + +Index: kernel/include/linux/sched.h +=================================================================== +--- kernel.orig/include/linux/sched.h 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/include/linux/sched.h 2008-11-24 15:57:08.000000000 +0100 +@@ -1239,6 +1239,9 @@ + unsigned long magic; + struct inode *ino; + #endif ++#ifdef CONFIG_VZ_FAIRSCHED ++ struct fairsched_node *fsched_node; ++#endif + }; + + /* +Index: kernel/init/Kconfig +=================================================================== +--- kernel.orig/init/Kconfig 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/init/Kconfig 2008-11-24 15:57:08.000000000 +0100 +@@ -362,6 +362,12 @@ + Refer to Documentation/cgroups.txt for more information + on "cgroup" pseudo filesystem. + ++config VZ_FAIRSCHED ++ bool "OpenVZ groups" ++ help ++ This option add customizable task groups with OpenVZ compatible ++ syscall and procfs interface. ++ + endchoice + + config CGROUP_CPUACCT +Index: kernel/kernel/Makefile +=================================================================== +--- kernel.orig/kernel/Makefile 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/kernel/Makefile 2008-11-24 15:57:08.000000000 +0100 +@@ -62,6 +62,7 @@ + obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o + obj-$(CONFIG_MARKERS) += marker.o + obj-$(CONFIG_LATENCYTOP) += latencytop.o ++obj-$(CONFIG_VZ_FAIRSCHED) += vzfairsched.o + + ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) + # According to Alan Modra , the -fno-omit-frame-pointer is +Index: kernel/kernel/exit.c +=================================================================== +--- kernel.orig/kernel/exit.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/kernel/exit.c 2008-11-24 15:57:08.000000000 +0100 +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -185,6 +186,7 @@ + */ + zap_leader = (leader->exit_signal == -1); + } ++ put_task_fairsched_node(p); + + write_unlock_irq(&tasklist_lock); + release_thread(p); +Index: kernel/kernel/fork.c +=================================================================== +--- kernel.orig/kernel/fork.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/kernel/fork.c 2008-11-24 15:57:08.000000000 +0100 +@@ -1364,6 +1364,7 @@ + #endif + total_forks++; + spin_unlock(¤t->sighand->siglock); ++ get_task_fairsched_node(p); + write_unlock_irq(&tasklist_lock); + proc_fork_connector(p); + cgroup_post_fork(p); +Index: kernel/kernel/sched.c +=================================================================== +--- kernel.orig/kernel/sched.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/kernel/sched.c 2008-11-24 15:57:08.000000000 +0100 +@@ -63,6 +63,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -208,6 +209,8 @@ + #elif defined(CONFIG_FAIR_CGROUP_SCHED) + tg = container_of(task_subsys_state(p, cpu_cgroup_subsys_id), + struct task_group, css); ++#elif defined(CONFIG_VZ_FAIRSCHED) ++ tg = p->fsched_node->tg; + #else + tg = &init_task_group; + #endif +@@ -7254,6 +7257,7 @@ + * During early bootup we pretend to be a normal task: + */ + current->sched_class = &fair_sched_class; ++ fairsched_init_early(); + } + + #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP +Index: kernel/kernel/vzfairsched.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kernel/kernel/vzfairsched.c 2008-11-24 15:57:08.000000000 +0100 +@@ -0,0 +1,30 @@ ++/* ++ * Fair Scheduler ++ * ++ * Copyright (C) 2000-2008 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ ++ ++#include ++#include ++ ++struct fairsched_node fairsched_init_node = { ++ .id = FAIRSCHED_INIT_NODE_ID, ++ .tg = &init_task_group, ++}; ++ ++static DEFINE_MUTEX(fairsched_mutex); ++ ++/* list protected with fairsched_mutex */ ++static LIST_HEAD(fairsched_node_head); ++static int fairsched_nr_nodes; ++ ++void __init fairsched_init_early(void) ++{ ++ list_add(&fairsched_init_node.nodelist, &fairsched_node_head); ++ fairsched_nr_nodes++; ++} ++ --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0036-Add-pid-ns-flags-PID_NS_HIDE_CHILD-and-PID_NS_HIDDEN.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0036-Add-pid-ns-flags-PID_NS_HIDE_CHILD-and-PID_NS_HIDDEN.patch @@ -0,0 +1,97 @@ +From f024f0d3b8cd8f6d4d66d2bacc352ad5cf0e62f9 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Mon, 17 Mar 2008 15:39:37 +0300 +Subject: [PATCH 36/48] Add pid ns flags PID_NS_HIDE_CHILD and PID_NS_HIDDEN + +If pid ns created in ns with PID_NS_HIDE_CHILD flag first process (like init) +will be added to parent ns, then flag PID_NS_HIDDEN set on new child ns +and all following process will be hidden. Hidden processes have their pids +allocated in all parent ns, but they aren't added to hash. +--- + include/linux/pid_namespace.h | 9 +++++++++ + kernel/fork.c | 2 ++ + kernel/pid.c | 12 ++++++++++-- + 3 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h +index 1689e28..49bea5f 100644 +--- a/include/linux/pid_namespace.h ++++ b/include/linux/pid_namespace.h +@@ -14,6 +14,14 @@ struct pidmap { + + #define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8) + ++/* pid namespace flags */ ++ ++/* if set newly created pid ns got PID_NS_HIDE_CHILD flag */ ++#define PID_NS_HIDE_CHILD 0x00000001 ++ ++/* if set newly created processes invisible from parent ns*/ ++#define PID_NS_HIDDEN 0x00000002 ++ + struct pid_namespace { + struct kref kref; + struct pidmap pidmap[PIDMAP_ENTRIES]; +@@ -22,6 +30,7 @@ struct pid_namespace { + struct kmem_cache *pid_cachep; + int level; + struct pid_namespace *parent; ++ unsigned flags; + #ifdef CONFIG_PROC_FS + struct vfsmount *proc_mnt; + #endif +diff --git a/kernel/fork.c b/kernel/fork.c +index 6e82c6f..15e0b0a 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -1205,6 +1205,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, + retval = pid_ns_prepare_proc(task_active_pid_ns(p)); + if (retval < 0) + goto bad_fork_free_pid; ++ if (task_active_pid_ns(current)->flags & PID_NS_HIDE_CHILD) ++ task_active_pid_ns(p)->flags |= PID_NS_HIDDEN; + } + } + +diff --git a/kernel/pid.c b/kernel/pid.c +index 7ab1c07..225d221 100644 +--- a/kernel/pid.c ++++ b/kernel/pid.c +@@ -260,10 +260,14 @@ fastcall void free_pid(struct pid *pid) + /* We can be called with write_lock_irq(&tasklist_lock) held */ + int i; + unsigned long flags; ++ struct upid *upid; + + spin_lock_irqsave(&pidmap_lock, flags); +- for (i = 0; i <= pid->level; i++) +- hlist_del_rcu(&pid->numbers[i].pid_chain); ++ for (i = 0; i <= pid->level; i++) { ++ upid = &pid->numbers[i]; ++ if (!hlist_unhashed(&upid->pid_chain)) ++ hlist_del_rcu(&upid->pid_chain); ++ } + spin_unlock(&pidmap_lock); + ub_kmemsize_uncharge(pid->ub, pid->numbers[pid->level].ns->pid_cachep->objuse); + local_irq_restore(flags); +@@ -322,6 +326,9 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t vpid) + upid = &pid->numbers[i]; + hlist_add_head_rcu(&upid->pid_chain, + &pid_hash[pid_hashfn(upid->nr, upid->ns)]); ++ if (upid->ns->flags & PID_NS_HIDDEN) ++ while (i--) ++ INIT_HLIST_NODE(&pid->numbers[i].pid_chain); + } + spin_unlock_irq(&pidmap_lock); + +@@ -616,6 +623,7 @@ static struct pid_namespace *create_pid_namespace(int level) + ns->last_pid = 0; + ns->child_reaper = NULL; + ns->level = level; ++ ns->flags = 0; + + set_bit(0, ns->pidmap[0].page); + atomic_set(&ns->pidmap[0].nr_free, BITS_PER_PAGE - 1); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0113-UBC-cfq-weighted-bandwidth.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0113-UBC-cfq-weighted-bandwidth.patch @@ -0,0 +1,59 @@ +From e7c95bcf3a2478d1f8b8e9021c7b5035f386f732 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 18 Jul 2008 15:25:46 +0400 +Subject: [PATCH 113/131] UBC cfq weighted bandwidth + +Implement bandwidth distribution control based +on per ioprio iotime ratio coefficient. + +It works like bc iotime flows with different speed, depends on ioprio. +BC with lower IO priority faster sink in queue and got less bandwidth. + +Ratio coefficients selected to conform with bandwidth distribution in +previous implementation: ratio = 100./(1+ioprio/7.) + +ioprio 0 -> ratio 100 -> weight 1 +ioprio 7 -> ratio 50 -> weight 2 +--- + kernel/bc/io_prio.c | 11 ++++++++++- + 1 files changed, 10 insertions(+), 1 deletions(-) + +diff --git a/kernel/bc/io_prio.c b/kernel/bc/io_prio.c +index ef6982d..d3a39e5 100644 +--- a/kernel/bc/io_prio.c ++++ b/kernel/bc/io_prio.c +@@ -19,6 +19,11 @@ + #include + #include + ++#define BC_MAX_RATIO 100 ++ ++/* bc bandwidth inversely proportional coefficient per ioprio */ ++static int bc_ioprio_ratio[CFQ_PRIO_LISTS] = {100, 87, 77, 70, 63, 58, 53, 50}; ++ + struct cfq_bc_data *__find_cfq_bc(struct ub_iopriv *iopriv, + struct cfq_data *cfqd) + { +@@ -223,7 +228,7 @@ static void bc_enqueue(struct cfq_data *cfqd, struct cfq_bc_data *cfq_bc) + unsigned long iotime, slice, position; + + iotime = cfq_bc->cfq_bc_iotime; +- slice = cfqd->cfq_ub_slice * 2; ++ slice = cfqd->cfq_ub_slice * BC_MAX_RATIO; + position = cfqd->cfq_bc_position; + + /* adjust iotime to hit in interval position +/- maximum slice */ +@@ -243,6 +248,10 @@ static void bc_dequeue(struct cfq_data *cfqd, struct cfq_bc_data *cfq_bc) + static void bc_update(struct cfq_data *cfqd, struct cfq_bc_data *cfq_bc, + unsigned long delta) + { ++ int ioprio; ++ ++ ioprio = cfq_bc->ub_iopriv->ioprio; ++ delta *= bc_ioprio_ratio[ioprio]; + cfq_bc->cfq_bc_iotime += delta; + + if (!cfq_bc->rqnum) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0102-VE-proc-getattr.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0102-VE-proc-getattr.patch @@ -0,0 +1,63 @@ +From 564a2db2f8d14dfff620ac89cc702b9c84742bbd Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Wed, 2 Jul 2008 19:55:20 +0400 +Subject: [PATCH 102/103] VE proc getattr + +Move nlink correction from proc_lookup to proc_getattr +and change it in stat result insted of inode nlink. + +Bug #114644 +--- + fs/proc/generic.c | 25 ++++++++++++++----------- + 1 files changed, 14 insertions(+), 11 deletions(-) + +diff --git a/fs/proc/generic.c b/fs/proc/generic.c +index 2260a20..a5a6f1f 100644 +--- a/fs/proc/generic.c ++++ b/fs/proc/generic.c +@@ -268,10 +268,21 @@ static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry, + { + struct inode *inode = dentry->d_inode; + struct proc_dir_entry *de = PROC_I(inode)->pde; +- if (de && de->nlink) +- inode->i_nlink = de->nlink; ++ struct proc_dir_entry *gde = GPDE(inode); + + generic_fillattr(inode, stat); ++ ++ if (de && de->nlink) ++ stat->nlink = de->nlink; ++ /* if dentry is found in both trees and it is a directory ++ * then inode's nlink count must be altered, because local ++ * and global subtrees may differ. ++ * on the other hand, they may intersect, so actual nlink ++ * value is difficult to calculate - upper estimate is used ++ * instead of it. ++ */ ++ if (de && gde && de != gde && gde->nlink > 1) ++ stat->nlink += gde->nlink - 2; + return 0; + } + +@@ -503,17 +514,9 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam + if (gde) + __module_get(gde->owner); + +- /* if dentry is found in both trees and it is a directory +- * then inode's nlink count must be altered, because local +- * and global subtrees may differ. +- * on the other hand, they may intersect, so actual nlink +- * value is difficult to calculate - upper estimate is used +- * instead of it. +- * dentry found in global tree only must not be writable ++ /* dentry found in global tree only must not be writable + * in non-super ve. + */ +- if (lde && gde && lde != gde && gde->nlink > 1) +- inode->i_nlink += gde->nlink - 2; + if (lde == NULL && !ve_is_super(dir->i_sb->s_type->owner_env)) + inode->i_mode &= ~S_IWUGO; + #endif +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0106-CPT-restore-conntrack-timer-fix.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0106-CPT-restore-conntrack-timer-fix.patch @@ -0,0 +1,57 @@ +From c8ae69f583b6939f86ca75dba8bfb67b518ab0e5 Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Fri, 18 Jul 2008 15:25:39 +0400 +Subject: [PATCH 106/131] CPT restore conntrack timer fix + +One more fix of restore conntrack procedure. +Following code: + + if (ct->helper->timeout && !del_timer(&exp->timeout)) { + ... + } + +can lead to oops, as exp->timeout is not initialized at this point. + +Actually this optimization is not needed at all. +If expectation is dying, then we will let it die by its own death. + +Also in ip_conntrack_expect_insert() there is an initialization of +exp->timeout. And we can't just do add_timer() after that (as in add_timer() +we have BUG_ON(timer_pending(timer))), we must do mod_timer() instead. + +Bug #114209 +--- + kernel/cpt/rst_conntrack.c | 10 +--------- + 1 files changed, 1 insertions(+), 9 deletions(-) + +diff --git a/kernel/cpt/rst_conntrack.c b/kernel/cpt/rst_conntrack.c +index 1f48945..bfa6ef2 100644 +--- a/kernel/cpt/rst_conntrack.c ++++ b/kernel/cpt/rst_conntrack.c +@@ -121,13 +121,6 @@ static int undump_expect_list(struct ip_conntrack *ct, + return -ENOMEM; + } + +- if (ct->helper->timeout && !del_timer(&exp->timeout)) { +- /* Dying already. We can do nothing. */ +- write_unlock_bh(&ip_conntrack_lock); +- dprintk_ctx("conntrack expectation is dying\n"); +- continue; +- } +- + decode_tuple(&v.cpt_tuple, &exp->tuple, 0); + decode_tuple(&v.cpt_mask, &exp->mask, 0); + +@@ -144,8 +137,7 @@ static int undump_expect_list(struct ip_conntrack *ct, + } else + #endif + if (ct->helper->timeout) { +- exp->timeout.expires = jiffies + v.cpt_timeout; +- add_timer(&exp->timeout); ++ mod_timer(&exp->timeout, jiffies + v.cpt_timeout); + } + write_unlock_bh(&ip_conntrack_lock); + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0039-CPT-disable-for-hidden-pid-namespaces.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0039-CPT-disable-for-hidden-pid-namespaces.patch @@ -0,0 +1,31 @@ +From bbbb51672f190dfeed6b8866ed2dd2e675af932e Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Mon, 17 Mar 2008 15:46:43 +0300 +Subject: [PATCH 39/48] CPT: disable for "hidden" pid namespaces + +CPT is currently broken if session id or process group id not presented in +global pid ns. +--- + kernel/cpt/cpt_dump.c | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/kernel/cpt/cpt_dump.c b/kernel/cpt/cpt_dump.c +index 4ff03f0..ea84dcb 100644 +--- a/kernel/cpt/cpt_dump.c ++++ b/kernel/cpt/cpt_dump.c +@@ -875,6 +875,12 @@ int cpt_dump(struct cpt_context *ctx) + goto out_noenv; + if (!env->is_locked) + goto out_noenv; ++ err = -EINVAL; ++ if (env->ve_ns->pid_ns->flags & PID_NS_HIDDEN) { ++ printk(KERN_WARNING "CT: checkpointing not supported yet" ++ " for hidden pid namespaces.\n"); ++ goto out_noenv; ++ } + + oldenv = set_exec_env(env); + old_ns = current->nsproxy; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0002-ubuntu-specific-revert-aa-d-path-changes.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0002-ubuntu-specific-revert-aa-d-path-changes.patch @@ -0,0 +1,124 @@ +Index: kernel/fs/dcache.c +=================================================================== +--- kernel.orig/fs/dcache.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/fs/dcache.c 2008-11-24 15:56:23.000000000 +0100 +@@ -1855,16 +1855,13 @@ + * @rootmnt: vfsmnt to which the root dentry belongs + * @buffer: buffer to return value in + * @buflen: buffer length +- * @fail_deleted: what to return for deleted files + * +- * Convert a dentry into an ASCII path name. If the entry has been deleted, +- * then if @fail_deleted is true, ERR_PTR(-ENOENT) is returned. Otherwise, ++ * Convert a dentry into an ASCII path name. If the entry has been deleted + * the string " (deleted)" is appended. Note that this is ambiguous. + * +- * If @dentry is not connected to @root, the path returned will be relative +- * (i.e., it will not start with a slash). ++ * Returns the buffer or an error code if the path was too long. + * +- * Returns the buffer or an error code. ++ * "buflen" should be positive. Caller holds the dcache_lock. + */ + char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, + struct dentry *root, struct vfsmount *rootmnt, +@@ -1892,6 +1889,8 @@ + for (;;) { + struct dentry * parent; + ++ if (dentry == root && vfsmnt == rootmnt) ++ break; + if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { + /* root of a tree? */ + spin_lock(&vfsmount_lock); +@@ -1901,6 +1900,7 @@ + } + dentry = vfsmnt->mnt_mountpoint; + vfsmnt = vfsmnt->mnt_parent; ++ spin_unlock(&vfsmount_lock); + continue; + } + parent = dentry->d_parent; +@@ -1953,23 +1953,12 @@ + Elong: + return ERR_PTR(-ENAMETOOLONG); + } +-EXPORT_SYMBOL(__d_path); + +-static char *__connect_d_path(char *path, char *buffer) +-{ +- if (!IS_ERR(path) && *path != '/') { +- /* Pretend that disconnected paths are hanging off the root. */ +- if (path == buffer) +- path = ERR_PTR(-ENAMETOOLONG); +- else +- *--path = '/'; +- } +- return path; +-} ++EXPORT_SYMBOL(__d_path); + + /* write full pathname into buffer and return start of pathname */ +-char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf, +- int buflen) ++char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, ++ char *buf, int buflen) + { + char *res; + struct vfsmount *rootmnt; +@@ -2264,10 +2253,10 @@ + */ + asmlinkage long sys_getcwd(char __user *buf, unsigned long size) + { +- int error, len; ++ int error; + struct vfsmount *pwdmnt, *rootmnt; + struct dentry *pwd, *root; +- char *page = (char *) __get_free_page(GFP_USER), *cwd; ++ char *page = (char *) __get_free_page(GFP_USER); + + if (!page) + return -ENOMEM; +@@ -2279,19 +2268,29 @@ + root = dget(current->fs->root); + read_unlock(¤t->fs->lock); + +- cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE); +- cwd = __connect_d_path(cwd, page); +- error = PTR_ERR(cwd); +- if (IS_ERR(cwd)) +- goto out; +- +- error = -ERANGE; +- len = PAGE_SIZE + page - cwd; +- if (len <= size) { +- error = len; +- if (copy_to_user(buf, cwd, len)) +- error = -EFAULT; +- } ++ error = -ENOENT; ++ /* Has the current directory has been unlinked? */ ++ spin_lock(&dcache_lock); ++ if (pwd->d_parent == pwd || !d_unhashed(pwd)) { ++ unsigned long len; ++ char * cwd; ++ ++ cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE); ++ spin_unlock(&dcache_lock); ++ ++ error = PTR_ERR(cwd); ++ if (IS_ERR(cwd)) ++ goto out; ++ ++ error = -ERANGE; ++ len = PAGE_SIZE + page - cwd; ++ if (len <= size) { ++ error = len; ++ if (copy_to_user(buf, cwd, len)) ++ error = -EFAULT; ++ } ++ } else ++ spin_unlock(&dcache_lock); + + out: + dput(pwd); --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0093-UBC-proc-permissions.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0093-UBC-proc-permissions.patch @@ -0,0 +1,53 @@ +From ec5cfa5fba2635c2561837d10233120917968972 Mon Sep 17 00:00:00 2001 +From: Pavel Emelianov +Date: Mon, 30 Jun 2008 13:48:49 +0400 +Subject: [PATCH 093/103] UBC proc permissions + +Set correct permissions on beancounters' proc files + +All these files allow to read from them only for root, +but the mode mask is r--r--r--, which sometimes confuses +the user. + +Set the r-------- mask for all the bc proc files and the +r-x------ for directories. + +http://bugzilla.openvz.org/show_bug.cgi?id=782 +--- + kernel/bc/proc.c | 6 +++--- + 1 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/kernel/bc/proc.c b/kernel/bc/proc.c +index caf4b1b..012bd48 100644 +--- a/kernel/bc/proc.c ++++ b/kernel/bc/proc.c +@@ -421,7 +421,7 @@ static int bc_lookset(struct inode *ino, void *data) + ino->i_ino = bc_make_ino(ub); + ino->i_fop = &bc_entry_fops; + ino->i_op = &bc_entry_iops; +- ino->i_mode = S_IFDIR | S_IRUSR | S_IXUGO; ++ ino->i_mode = S_IFDIR | S_IRUSR | S_IXUSR; + /* subbeancounters are not included, but who cares? */ + ino->i_nlink = num_entries + 2; + ino->i_gid = 0; +@@ -680,7 +680,7 @@ static int __init ub_init_proc(void) + struct proc_dir_entry *entry; + + bc_proc_root = create_proc_entry("bc", +- S_IFDIR | S_IRUGO | S_IXUGO, NULL); ++ S_IFDIR | S_IRUSR | S_IXUSR, NULL); + if (bc_proc_root == NULL) + panic("Can't create /proc/bc entry"); + +@@ -693,7 +693,7 @@ static int __init ub_init_proc(void) + #endif + bc_register_proc_root_entry(&bc_all_resources_entry); + +- entry = create_proc_glob_entry("user_beancounters", S_IRUGO, NULL); ++ entry = create_proc_glob_entry("user_beancounters", S_IRUSR, NULL); + entry->proc_fops = &ub_file_operations; + return 0; + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0083-CPT-inotify-on-symlink.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0083-CPT-inotify-on-symlink.patch @@ -0,0 +1,55 @@ +From a984380ffcba9d10f107d318158427f2eea50900 Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Mon, 30 Jun 2008 13:48:48 +0400 +Subject: [PATCH 083/103] CPT inotify on symlink + +Inside VE file /etc/mtab is a symlink to /proc/mounts. +FreeNX server with KDE creates inotify on /etc/mtab file. +To restore such inotify we need to obtain dentry with path_lookup() and +restore inotify on it. + +Bug #96464 +--- + kernel/cpt/rst_files.c | 25 ++++++++++++++++++++++++- + 1 files changed, 24 insertions(+), 1 deletions(-) + +diff --git a/kernel/cpt/rst_files.c b/kernel/cpt/rst_files.c +index 579f9b7..fd29b60 100644 +--- a/kernel/cpt/rst_files.c ++++ b/kernel/cpt/rst_files.c +@@ -1215,8 +1215,31 @@ int cpt_get_dentry(struct dentry **dp, struct vfsmount **mp, + return err; + + file = rst_file(*pos, -2, ctx); +- if (IS_ERR(file)) ++ if (IS_ERR(file)) { ++ if (PTR_ERR(file) == -EINVAL && S_ISLNK(fi.cpt_i_mode)) { ++ /* One special case: inotify on symlink */ ++ struct nameidata nd; ++ __u8 *name = NULL; ++ ++ if (fi.cpt_next > fi.cpt_hdrlen) ++ name = rst_get_name(*pos + sizeof(fi), ctx); ++ if (!name) { ++ eprintk_ctx("can't get name for file\n"); ++ return -EINVAL; ++ } ++ if ((err = path_lookup(name, 0, &nd)) != 0) { ++ eprintk_ctx("path_lookup %s: %d\n", name, err); ++ rst_put_name(name, ctx); ++ return -EINVAL; ++ } ++ *dp = nd.dentry; ++ *mp = nd.mnt; ++ *pos += fi.cpt_next; ++ rst_put_name(name, ctx); ++ return 0; ++ } + return PTR_ERR(file); ++ } + + *dp = dget(file->f_dentry); + *mp = mntget(file->f_vfsmnt); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0157-CPT-assign-net_ns-of-restored-tun-tap-device.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0157-CPT-assign-net_ns-of-restored-tun-tap-device.patch @@ -0,0 +1,25 @@ +From bce432d13a89bfed1d183084ef69a9e763e26262 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 9 Jun 2008 17:08:16 +0400 +Subject: [PATCH] CPT assign ->net_ns of restored tun/tap device + +otherwise init_net is used and device becomes invisible in CT. +--- + kernel/cpt/rst_net.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/kernel/cpt/rst_net.c b/kernel/cpt/rst_net.c +index 7575dd8..179655e 100644 +--- a/kernel/cpt/rst_net.c ++++ b/kernel/cpt/rst_net.c +@@ -336,6 +336,7 @@ static int rst_restore_tuntap(loff_t start, struct cpt_netdev_image *di, + dev = alloc_netdev(sizeof(struct tun_struct), di->cpt_name, tun_setup); + if (!dev) + goto out; ++ dev->nd_net = get_exec_env()->ve_netns; + + tun = netdev_priv(dev); + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0054-UBC-don-t-do-preventive-dentries-uncharge.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0054-UBC-don-t-do-preventive-dentries-uncharge.patch @@ -0,0 +1,100 @@ +From 95fcbf4bed2550fd173963493c217aefcc6a866a Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Tue, 1 Apr 2008 15:55:25 +0400 +Subject: [PATCH 53/67] UBC: don't do preventive dentries uncharge + +NFS in 2.6.23+ kernels started to dget parent dentry temporarily +during final dentry put. This doesn't work with current scheme, namely, "drop +all ->d_inuse counters, uncharge, do normal put later", because +ub_dget_testone() will oops on such dentries in filesystem. + +So, move actual uncharge code to later stage right after dentry free, so +that "->d_inuse" won't be -1 during filesystem dentry put method. + +Once we find parent dentry which won't be freed this time, drop ->d_inuse et +al counters as usually do. + +Steps to reproduce: + creat08 test from LTP on NFS mounted /vz with dentry accounting active. + +Mainline commit: e4eff1a622edd6ab7b73acd5d8763aa2fa3fee49 + aka "SUNRPC: Clean up the sillyrename code" +--- + fs/dcache.c | 16 ++++++++++++++-- + include/bc/dcache_op.h | 2 ++ + 2 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/fs/dcache.c b/fs/dcache.c +index 499f1ba..b69a57e 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -181,9 +181,14 @@ static struct dentry *d_kill(struct dentry *dentry) + + static void dput_recursive(struct dentry *dentry) + { ++ struct user_beancounter *ub; ++ unsigned long d_ubsize; ++ + repeat: +- if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock)) ++ if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock)) { ++ ub_dentry_uncharge(dentry); + goto out_preempt; ++ } + + spin_lock(&dentry->d_lock); + if (atomic_read(&dentry->d_count)) +@@ -206,6 +211,7 @@ repeat: + } + out_unlock: + spin_unlock(&dentry->d_lock); ++ ub_dentry_uncharge_locked(dentry); + spin_unlock(&dcache_lock); + out_preempt: + preempt_enable(); +@@ -221,7 +227,14 @@ kill_it: + list_del(&dentry->d_lru); + dentry_stat.nr_unused--; + } ++ ++ ub = dentry->dentry_bc.d_ub; ++ d_ubsize = dentry->dentry_bc.d_ubsize; + dentry = d_kill(dentry); ++ if (ub_dentry_on) { ++ uncharge_dcache(ub, d_ubsize); ++ put_beancounter(ub); ++ } + if (dentry) { + preempt_disable(); + goto repeat; +@@ -237,7 +250,6 @@ void dput(struct dentry *dentry) + might_sleep(); + + preempt_disable(); +- ub_dentry_uncharge(dentry); + dput_recursive(dentry); + } + +diff --git a/include/bc/dcache_op.h b/include/bc/dcache_op.h +index 6227195..23306e9 100644 +--- a/include/bc/dcache_op.h ++++ b/include/bc/dcache_op.h +@@ -85,6 +85,7 @@ static inline void ub_dentry_uncharge(struct dentry *d) + spin_unlock(&dcache_lock); + } + ++void uncharge_dcache(struct user_beancounter *ub, unsigned long size); + #else /* CONFIG_BEANCOUNTERS */ + + static inline int ub_dentry_alloc(struct dentry *d) { return 0; } +@@ -94,6 +95,7 @@ static inline int ub_dentry_charge(struct dentry *d) { return 0; } + static inline void ub_dentry_charge_nofail(struct dentry *d) { } + static inline void ub_dentry_uncharge_locked(struct dentry *d) { } + static inline void ub_dentry_uncharge(struct dentry *d) { } ++static inline void uncharge_dcache(struct user_beancounter *ub, unsigned long size) { } + + #endif /* CONFIG_BEANCOUNTERS */ + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0042-tun-fix-netdevice-creation-in-VE.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0042-tun-fix-netdevice-creation-in-VE.patch @@ -0,0 +1,49 @@ +From b0a6532da1157d370daa475f545ba18de04dee86 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Wed, 19 Mar 2008 18:15:44 +0300 +Subject: [PATCH 42/48] tun: fix netdevice creation in VE + +--- + drivers/net/tun.c | 5 ++++- + 1 files changed, 4 insertions(+), 1 deletions(-) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 98d1db9..2fcf253 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -53,6 +53,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -494,6 +495,7 @@ static struct tun_struct *tun_get_by_name(const char *name) + + static int tun_set_iff(struct file *file, struct ifreq *ifr) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; + struct tun_struct *tun; + struct net_device *dev; + int err; +@@ -512,7 +514,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr) + !capable(CAP_VE_NET_ADMIN)) + return -EPERM; + } +- else if (__dev_get_by_name(&init_net, ifr->ifr_name)) ++ else if (__dev_get_by_name(net, ifr->ifr_name)) + return -EINVAL; + else { + char *name; +@@ -542,6 +544,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr) + tun_setup); + if (!dev) + return -ENOMEM; ++ dev->nd_net = net; + + tun = netdev_priv(dev); + tun->dev = dev; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0052-CPT-enhance-support-of-veth-device.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0052-CPT-enhance-support-of-veth-device.patch @@ -0,0 +1,244 @@ +From ae528ceeeffe35582a2e81c5ce4adbd8f6e3facd Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Tue, 25 Mar 2008 19:03:58 +0300 +Subject: [PATCH 51/67] CPT: enhance support of veth device + +In current implementation veth devices are not dumped correctly and +we can lose private veth data. + +This patch allows to save/restore private veth data. +--- + drivers/net/vzethdev.c | 17 +---------------- + include/linux/cpt_image.h | 11 +++++++++++ + include/linux/veth.h | 27 +++++++++++++++++++++++++++ + kernel/cpt/cpt_net.c | 28 ++++++++++++++++++++++++++++ + kernel/cpt/rst_net.c | 38 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 105 insertions(+), 16 deletions(-) + +diff --git a/drivers/net/vzethdev.c b/drivers/net/vzethdev.c +index 05d2ec5..5fe9fae 100644 +--- a/drivers/net/vzethdev.c ++++ b/drivers/net/vzethdev.c +@@ -44,6 +44,7 @@ + #include /* For ARPHRD_ETHER */ + #include + #include ++#include + #include + #include + +@@ -52,26 +53,10 @@ + #include + #include + +-struct veth_struct +-{ +- struct net_device_stats stats; +- struct net_device *pair; +- struct list_head hwaddr_list; +- struct net_device_stats *real_stats; +- int allow_mac_change; +-}; +- + static LIST_HEAD(veth_hwaddr_list); + static DEFINE_RWLOCK(ve_hwaddr_lock); + static DECLARE_MUTEX(hwaddr_sem); + +-#define veth_from_netdev(dev) \ +- ((struct veth_struct *)(netdev_priv(dev))) +-static inline struct net_device * veth_to_netdev(struct veth_struct *veth) +-{ +- return (struct net_device *)((char *)veth - ((sizeof(struct net_device) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST)); +-} +- + static inline struct net_device_stats * + veth_stats(struct net_device *dev, int cpuid) + { +diff --git a/include/linux/cpt_image.h b/include/linux/cpt_image.h +index 20f23b4..045bc1f 100644 +--- a/include/linux/cpt_image.h ++++ b/include/linux/cpt_image.h +@@ -97,6 +97,7 @@ enum _cpt_object_type + CPT_OBJ_TASK_AUX, + CPT_OBJ_NET_TUNTAP, + CPT_OBJ_NET_HWADDR, ++ CPT_OBJ_NET_VETH, + }; + + #define CPT_ALIGN(n) (((n)+7)&~7) +@@ -1504,6 +1505,16 @@ struct cpt_tuntap_image { + __u32 cpt_net_filter[2]; + } __attribute__ ((aligned (8))); + ++struct cpt_veth_image { ++ __u64 cpt_next; ++ __u32 cpt_object; ++ __u16 cpt_hdrlen; ++ __u16 cpt_content; ++ ++ __u32 cpt_allow_mac_change; ++ __u32 __cpt_pad; ++} __attribute__ ((aligned (8))); ++ + struct cpt_hwaddr_image { + __u64 cpt_next; + __u32 cpt_object; +diff --git a/include/linux/veth.h b/include/linux/veth.h +index 3354c1e..9d0273f 100644 +--- a/include/linux/veth.h ++++ b/include/linux/veth.h +@@ -1,3 +1,12 @@ ++/* ++ * include/linux/veth.h ++ * ++ * Copyright (C) 2007 SWsoft ++ * All rights reserved. ++ * ++ * Licensing governed by "linux/COPYING.SWsoft" file. ++ * ++ */ + #ifndef __NET_VETH_H_ + #define __NET_VETH_H_ + +@@ -9,4 +18,22 @@ enum { + #define VETH_INFO_MAX (__VETH_INFO_MAX - 1) + }; + ++#ifdef __KERNEL__ ++struct veth_struct ++{ ++ struct net_device_stats stats; ++ struct net_device *pair; ++ struct list_head hwaddr_list; ++ struct net_device_stats *real_stats; ++ int allow_mac_change; ++}; ++ ++#define veth_from_netdev(dev) \ ++ ((struct veth_struct *)(netdev_priv(dev))) ++static inline struct net_device * veth_to_netdev(struct veth_struct *veth) ++{ ++ return (struct net_device *)((char *)veth - ((sizeof(struct net_device) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST)); ++} ++#endif ++ + #endif +diff --git a/kernel/cpt/cpt_net.c b/kernel/cpt/cpt_net.c +index 4e3dcec..4fe5ca7 100644 +--- a/kernel/cpt/cpt_net.c ++++ b/kernel/cpt/cpt_net.c +@@ -31,12 +31,38 @@ + #include + #include + #include ++#include + + #include "cpt_obj.h" + #include "cpt_context.h" + #include "cpt_kernel.h" + #include "cpt_syscalls.h" + ++static void cpt_dump_veth(struct net_device *dev, struct cpt_context * ctx) ++{ ++#if defined(CONFIG_VE_ETHDEV) || defined(CONFIG_VE_ETHDEV_MODULE) ++ struct cpt_veth_image v; ++ struct veth_struct *veth; ++ ++ if (!KSYMREF(veth_open) || dev->open != KSYMREF(veth_open)) ++ return; ++ ++ veth = veth_from_netdev(dev); ++ cpt_open_object(NULL, ctx); ++ ++ v.cpt_next = CPT_NULL; ++ v.cpt_object = CPT_OBJ_NET_VETH; ++ v.cpt_hdrlen = sizeof(v); ++ v.cpt_content = CPT_CONTENT_VOID; ++ ++ v.cpt_allow_mac_change = veth->allow_mac_change; ++ ++ ctx->write(&v, sizeof(v), ctx); ++ cpt_close_object(ctx); ++#endif ++ return; ++} ++ + static void cpt_dump_tuntap(struct net_device *dev, struct cpt_context * ctx) + { + #if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) +@@ -105,6 +131,8 @@ int cpt_dump_link(struct cpt_context * ctx) + + cpt_dump_tuntap(dev, ctx); + ++ cpt_dump_veth(dev, ctx); ++ + /* Dump hardware address */ + cpt_open_object(NULL, ctx); + hw.cpt_next = CPT_NULL; +diff --git a/kernel/cpt/rst_net.c b/kernel/cpt/rst_net.c +index 2703800..df6b659 100644 +--- a/kernel/cpt/rst_net.c ++++ b/kernel/cpt/rst_net.c +@@ -30,6 +30,8 @@ + #include + #include + #include ++#include ++#include + + #include "cpt_obj.h" + #include "cpt_context.h" +@@ -378,6 +380,28 @@ out: + return err; + } + ++static int rst_restore_veth(loff_t pos, struct net_device *dev, ++ struct cpt_context *ctx) ++{ ++ int err = -ENODEV; ++#if defined(CONFIG_VE_ETHDEV) || defined(CONFIG_VE_ETHDEV_MODULE) ++ struct cpt_veth_image vi; ++ struct veth_struct *veth; ++ ++ if (!KSYMREF(veth_open) || dev->open != KSYMREF(veth_open)) { ++ eprintk_ctx("Module vzethdev is not loaded, " ++ "or device %s is not a veth device\n", dev->name); ++ return -EINVAL; ++ } ++ err = rst_get_object(CPT_OBJ_NET_VETH, pos, &vi, ctx); ++ if (err) ++ return err; ++ veth = veth_from_netdev(dev); ++ veth->allow_mac_change = vi.cpt_allow_mac_change; ++#endif ++ return err; ++} ++ + int rst_restore_netdev(struct cpt_context *ctx) + { + struct net *net = get_exec_env()->ve_ns->net_ns; +@@ -463,7 +487,21 @@ int rst_restore_netdev(struct cpt_context *ctx) + eprintk_ctx("dev_change_flags err: %d\n", err); + } + if (pos < sec + di.cpt_next) { ++ struct cpt_object_hdr hdr; + struct cpt_hwaddr_image hw; ++ err = ctx->pread(&hdr, sizeof(struct cpt_object_hdr), ++ ctx, pos); ++ if (err) ++ goto out; ++ if (hdr.cpt_object == CPT_OBJ_NET_VETH) { ++ err = rst_restore_veth(pos, dev, ctx); ++ if (err) { ++ eprintk_ctx("restore veth %s: %d\n", ++ di.cpt_name, err); ++ goto out; ++ } ++ pos += hdr.cpt_next; ++ } + /* Restore hardware address */ + err = rst_get_object(CPT_OBJ_NET_HWADDR, pos, + &hw, ctx); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0085-CPT-relax-check-for-bind-mounts.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0085-CPT-relax-check-for-bind-mounts.patch @@ -0,0 +1,137 @@ +From 9bdf25b67ea0a67dc09960bf9ed917bff35a420e Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Mon, 30 Jun 2008 13:48:48 +0400 +Subject: [PATCH 085/103] CPT relax check for bind mounts + +Relax check for special bind mounts which mounted several times on the same +mount point. We need to check only dentry, mount check can be skipped in this +case. +We can't remove completely mount check as there are exist cases when we need +to check mnt too. E.g. /dev is mounted with NODEV over /dev and some file is +opened from underlying mount. If mount check is removed, then we will be able +to checkpoint such state, but we will not be able to restore it. + +Correct sollution will be to dump/restore whole mount tree with overmounts. +But we can't implement this right now for number of reasons. + +Bug #84310 +--- + kernel/cpt/cpt_files.c | 18 +++++++++--------- + kernel/cpt/cpt_files.h | 2 +- + kernel/cpt/cpt_socket.c | 2 +- + 3 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/kernel/cpt/cpt_files.c b/kernel/cpt/cpt_files.c +index adbd43b..e728b64 100644 +--- a/kernel/cpt/cpt_files.c ++++ b/kernel/cpt/cpt_files.c +@@ -58,7 +58,7 @@ void cpt_printk_dentry(struct dentry *d, struct vfsmount *mnt) + } + + int cpt_verify_overmount(char *path, struct dentry *d, struct vfsmount *mnt, +- cpt_context_t *ctx) ++ int verify, cpt_context_t *ctx) + { + if (path[0] == '/' && !(!IS_ROOT(d) && d_unhashed(d))) { + struct nameidata nd; +@@ -66,7 +66,7 @@ int cpt_verify_overmount(char *path, struct dentry *d, struct vfsmount *mnt, + eprintk_ctx("d_path cannot be looked up %s\n", path); + return -EINVAL; + } +- if (nd.dentry != d || nd.mnt != mnt) { ++ if (nd.dentry != d || (verify && nd.mnt != mnt)) { + eprintk_ctx("d_path is invisible %s\n", path); + path_release(&nd); + return -EINVAL; +@@ -125,7 +125,7 @@ cpt_replaced(struct dentry * de, struct vfsmount *mnt, cpt_context_t * ctx) + } + + static int cpt_dump_dentry(struct dentry *d, struct vfsmount *mnt, +- int replaced, cpt_context_t *ctx) ++ int replaced, int verify, cpt_context_t *ctx) + { + int len; + char *path; +@@ -187,7 +187,7 @@ static int cpt_dump_dentry(struct dentry *d, struct vfsmount *mnt, + o.cpt_content = CPT_CONTENT_NAME; + path[len] = 0; + +- if (cpt_verify_overmount(path, d, mnt, ctx)) { ++ if (cpt_verify_overmount(path, d, mnt, verify, ctx)) { + __cpt_release_buf(ctx); + return -EINVAL; + } +@@ -226,7 +226,7 @@ int cpt_dump_string(const char *s, struct cpt_context *ctx) + static int + cpt_dump_filename(struct file *file, int replaced, cpt_context_t *ctx) + { +- return cpt_dump_dentry(file->f_dentry, file->f_vfsmnt, replaced, ctx); ++ return cpt_dump_dentry(file->f_dentry, file->f_vfsmnt, replaced, 1, ctx); + } + + int cpt_dump_inode(struct dentry *d, struct vfsmount *mnt, struct cpt_context *ctx) +@@ -881,7 +881,7 @@ static int find_linked_dentry(struct dentry *d, struct vfsmount *mnt, + } + spin_unlock(&dcache_lock); + if (found) { +- err = cpt_dump_dentry(found, mnt, 0, ctx); ++ err = cpt_dump_dentry(found, mnt, 0, 1, ctx); + dput(found); + if (!err) { + dprintk_ctx("dentry found in aliases\n"); +@@ -920,7 +920,7 @@ static int find_linked_dentry(struct dentry *d, struct vfsmount *mnt, + + dprintk_ctx("dentry found in dir\n"); + __cpt_release_buf(ctx); +- err = cpt_dump_dentry(found, mnt, 0, ctx); ++ err = cpt_dump_dentry(found, mnt, 0, 1, ctx); + + err_lookup: + dput(found); +@@ -1484,7 +1484,7 @@ static int cpt_dump_bind_mnt(struct vfsmount * mnt, cpt_context_t * ctx) + + /* One special case: mount --bind /a /a */ + if (mnt->mnt_root == mnt->mnt_mountpoint) +- return cpt_dump_dentry(mnt->mnt_root, mnt, 0, ctx); ++ return cpt_dump_dentry(mnt->mnt_root, mnt, 0, 0, ctx); + + list_for_each_prev(p, &mnt->mnt_list) { + struct vfsmount * m; +@@ -1497,7 +1497,7 @@ static int cpt_dump_bind_mnt(struct vfsmount * mnt, cpt_context_t * ctx) + if (m->mnt_sb != mnt->mnt_sb) + continue; + +- err = cpt_dump_dentry(mnt->mnt_root, m, 0, ctx); ++ err = cpt_dump_dentry(mnt->mnt_root, m, 0, 1, ctx); + if (err == 0) + break; + } +diff --git a/kernel/cpt/cpt_files.h b/kernel/cpt/cpt_files.h +index 7770ab2..7f4afab 100644 +--- a/kernel/cpt/cpt_files.h ++++ b/kernel/cpt/cpt_files.h +@@ -57,7 +57,7 @@ struct file *rst_open_inotify(struct cpt_file_image *fi, + + + int cpt_verify_overmount(char *path, struct dentry *d, struct vfsmount *mnt, +- cpt_context_t *ctx); ++ int verify, cpt_context_t *ctx); + + #define check_one_vfsmount(mnt) \ + (strcmp(mnt->mnt_sb->s_type->name, "rootfs") != 0 && \ +diff --git a/kernel/cpt/cpt_socket.c b/kernel/cpt/cpt_socket.c +index 10fdd3f..9f7af89 100644 +--- a/kernel/cpt/cpt_socket.c ++++ b/kernel/cpt/cpt_socket.c +@@ -509,7 +509,7 @@ int cpt_dump_socket(cpt_object_t *obj, struct sock *sk, int index, int parent, s + } else { + wprintk_ctx("af_unix path is too long: %s (%s)\n", path, ((char*)v->cpt_laddr)+2); + } +- err = cpt_verify_overmount(path, d, unix_sk(sk)->mnt, ctx); ++ err = cpt_verify_overmount(path, d, unix_sk(sk)->mnt, 1, ctx); + } else { + eprintk_ctx("cannot get path of an af_unix socket\n"); + err = PTR_ERR(path); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0017-Remove-kmem_cache-walking-logic.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0017-Remove-kmem_cache-walking-logic.patch @@ -0,0 +1,418 @@ +From b7cb384df2e4564afb89fc9213fa0c0af27c26b9 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Wed, 12 Mar 2008 13:46:09 +0300 +Subject: [PATCH 17/48] Remove kmem_cache walking logic + +It can't work in case of SLUB because full pages aren't in any slab lists. +--- + include/bc/dcache.h | 2 - + include/linux/slab.h | 1 - + kernel/bc/dcache.c | 163 -------------------------------------------------- + mm/slab.c | 112 ---------------------------------- + mm/slub.c | 55 ----------------- + 5 files changed, 0 insertions(+), 333 deletions(-) + +Index: kernel/include/bc/dcache.h +=================================================================== +--- kernel.orig/include/bc/dcache.h 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/include/bc/dcache.h 2008-11-24 15:57:05.000000000 +0100 +@@ -40,10 +40,8 @@ + #define INUSE_INIT 0 + + extern int ub_dentry_on; +-extern void ub_dentry_checkup(void); + #else + #define ub_dget_testone(d) (0) + #define ub_dput_testzero(d) (0) +-#define ub_dentry_checkup() do { } while (0) + #endif + #endif +Index: kernel/include/linux/slab.h +=================================================================== +--- kernel.orig/include/linux/slab.h 2008-11-24 15:56:45.000000000 +0100 ++++ kernel/include/linux/slab.h 2008-11-24 15:57:05.000000000 +0100 +@@ -83,7 +83,6 @@ + extern void show_slab_info(void); + int kmem_cache_objuse(struct kmem_cache *cachep); + int kmem_obj_objuse(void *obj); +-int kmem_cache_walk_objects(struct kmem_cache *cachep, int (*fun)(void *obj)); + unsigned long ub_cache_growth(struct kmem_cache *cachep); + + #ifdef CONFIG_BEANCOUNTERS +Index: kernel/kernel/bc/dcache.c +=================================================================== +--- kernel.orig/kernel/bc/dcache.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/kernel/bc/dcache.c 2008-11-24 15:57:05.000000000 +0100 +@@ -322,7 +322,6 @@ + int ub_dentry_alloc_barrier; + EXPORT_SYMBOL(ub_dentry_on); + +-static DEFINE_PER_CPU(int, checkcnt); + static unsigned long checklowat = 0; + static unsigned long checkhiwat = ULONG_MAX; + +@@ -333,168 +332,6 @@ + /* 1024th of lowmem size */ + static unsigned int sysctl_ub_watermark[2] = {0, 100}; + +- +-static int ub_dentry_acctinit(struct dentry *dentry) +-{ +- struct dentry_beancounter *d_bc; +- +- d_bc = &dentry->dentry_bc; +- d_bc->d_ub = NULL; +- atomic_set(&d_bc->d_inuse, -1); +-#if 0 +- if (dname_external(dentry)) { +- struct page *page; +- page = virt_to_page(dentry->d_name.name); +- if (!PageSlab(page) || page_get_cache(page) == NULL) { +- printk("Problem with name, dentry %p, parent %p, " +- "name %p len %d\n", +- dentry, dentry->d_parent, +- dentry->d_name.name, +- dentry->d_name.len); +- printk(" de %p name %.10s\n", +- dentry, dentry->d_name.name); +- d_bc->d_ubsize = 0; +- return 0; +- } +- } +-#endif +- d_bc->d_ubsize = d_charge_size(dentry); +- return 0; +-} +- +-static int ub_dentry_acctcount(struct dentry *dentry) +-{ +- struct dentry_beancounter *d_bc; +- struct dentry *child; +- int count; +- +- count = 0; +- list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) +- count++; +- +- d_bc = &dentry->dentry_bc; +- count = atomic_read(&dentry->d_count) - count; +- if (count) { +- __ub_dentry_charge_nofail(dentry); +- if (count > 1) +- atomic_add(count - 1, &d_bc->d_inuse); +- } +- +- return 0; +-} +- +-static int ub_dentry_acctdrop(struct dentry *dentry) +-{ +- struct dentry_beancounter *d_bc; +- +- d_bc = &dentry->dentry_bc; +- if (atomic_read(&d_bc->d_inuse) < 0) +- return 0; +- atomic_set(&d_bc->d_inuse, -1); +- uncharge_dcache(d_bc->d_ub, d_bc->d_ubsize); +- put_beancounter(d_bc->d_ub); +- return 0; +-} +- +-static inline int ub_dentry_walk(int (*fun)(struct dentry *d)) +-{ +- return kmem_cache_walk_objects(dentry_cache, +- (int (*)(void *))fun); +-} +- +-static int ub_dentry_accton(void *data) +-{ +- struct user_beancounter *ub; +- int err; +- +- ub = get_exec_ub(); +- set_exec_ub(get_ub0()); +- err = ub_dentry_walk(&ub_dentry_acctinit); +- if (!err) +- err = ub_dentry_walk(&ub_dentry_acctcount); +- set_exec_ub(ub); +- if (err == 0) +- ub_dentry_on = 1; +- return err; +-} +- +-static int ub_dentry_acctoff(void *data) +-{ +- int ret; +- ret = ub_dentry_walk(&ub_dentry_acctdrop); +- if (ret == 0) +- ub_dentry_on = 0; +- return ret; +-} +- +-/* +- * Main function turning dcache accounting on and off. +- * Called with preemption disabled (for caller's convenience). +- */ +-static void ub_dentry_switch(int onoff, unsigned long pages, int (*fun)(void *)) +-{ +- static char *s[] = { "off", "on" }; +- unsigned long start_jiffies; +- int err, tm; +- +- start_jiffies = jiffies; +- preempt_enable(); +- ub_dentry_alloc_barrier = 1; +- /* ensure ub_dentry_alloc_barrier is visible on all CPUs */ +- mb(); +- synchronize_rcu(); +- down_write(&ub_dentry_alloc_sem); +- if (ub_dentry_on == onoff) +- goto done; +- +- printk("UBC: preparing to turn dcache accounting %s, " +- "size %lu pages, watermarks %lu %lu\n", +- s[onoff], pages, checklowat, checkhiwat); +- err = stop_machine_run(fun, NULL, NR_CPUS); +- if (err) { +- printk(KERN_ERR "UBC: ERROR: dcache accounting switch %d\n", +- err); +- preempt_disable(); +- checklowat = 0; +- checkhiwat = ULONG_MAX; +- sysctl_ub_dentry_chk = INT_MAX; +- preempt_enable(); +- } else { +- tm = jiffies_to_msecs(jiffies - start_jiffies); +- printk("UBC: turning dcache accounting %s succeeded, " +- "usage %lu, time %u.%03u\n", +- s[onoff], +- get_ub0()->ub_parms[UB_DCACHESIZE].held, +- tm / 1000, tm % 1000); +- } +- +-done: +- ub_dentry_alloc_barrier = 0; +- up_write(&ub_dentry_alloc_sem); +- preempt_disable(); +-} +- +-void ub_dentry_checkup(void) +-{ +- int *p; +- unsigned long pages; +- +- preempt_disable(); +- p = &__get_cpu_var(checkcnt); +- if (++*p > sysctl_ub_dentry_chk) { +- *p = 0; +- pages = ub_cache_growth(dentry_cache); +- if (ub_dentry_on) { +- if (pages < checklowat) +- ub_dentry_switch(0, pages, &ub_dentry_acctoff); +- } else { +- if (pages >= checkhiwat) +- ub_dentry_switch(1, pages, &ub_dentry_accton); +- } +- } +- preempt_enable(); +-} +- + static void ub_dentry_set_limits(unsigned long pages, unsigned long cap) + { + down_write(&ub_dentry_alloc_sem); +Index: kernel/mm/slab.c +=================================================================== +--- kernel.orig/mm/slab.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/mm/slab.c 2008-11-24 15:57:05.000000000 +0100 +@@ -755,105 +755,6 @@ + return virt_to_cache(obj)->objuse; + } + +-static void kmem_cache_free_block(struct kmem_cache *cachep, +- struct kmem_list3 *l3, void **objpp, +- int nr_objects, int node); +- +-static int kmem_cache_walk_node(struct kmem_cache *cachep, int node, +- int (*fun)(void *)) +-{ +- struct array_cache *ac; +- struct slab *slabp; +- char *objp; +- int cpu, i, sz, r, n; +- struct kmem_list3 *l3; +- unsigned long map[PAGE_SIZE / sizeof(struct dentry) +- / BITS_PER_LONG + 1]; +- +- if (cachep->num >= sizeof(map) * 8) +- return -E2BIG; +- +- l3 = cachep->nodelists[node]; +- /* drain all CPU caches to have up-to-date free map */ +- +-#ifdef CONFIG_NUMA +- /* walk through all nodes and drain alien caches */ +- for_each_online_node (n) { +- if (!cachep->nodelists[n]->alien) +- continue; +- ac = cachep->nodelists[n]->alien[node]; +- if (!ac) +- continue; +- kmem_cache_free_block(cachep, cachep->nodelists[node], +- ac->entry, ac->avail, node); +- ac->avail = 0; +- } +-#endif +- +- ac = l3->shared; +- kmem_cache_free_block(cachep, l3, ac->entry, ac->avail, node); +- ac->avail = 0; +- for_each_online_cpu(cpu) { +- ac = cachep->array[cpu]; +- n = cpu_to_node(cpu); +- kmem_cache_free_block(cachep, cachep->nodelists[n], +- ac->entry, ac->avail, n); +- ac->avail = 0; +- } +- +- list_for_each_entry(slabp, &l3->slabs_full, list) { +- touch_nmi_watchdog(); +- for (i = 0, objp = slabp->s_mem; +- i < cachep->num; +- i++, objp += cachep->buffer_size) { +-#if SLAB_DEBUG +- objp += cachep->obj_offset; +-#endif +- r = (*fun)(objp); +- if (r) +- return r; +- } +- } +- +- list_for_each_entry(slabp, &l3->slabs_partial, list) { +- touch_nmi_watchdog(); +- memset(map, 0xff, sizeof(map)); +- for (i = slabp->free, r = 0; +- i != BUFCTL_END; +- i = slab_bufctl(slabp)[i], r++) { +- if (r > cachep->num) +- return -1; +- __clear_bit(i, map); +- } +- sz = sizeof(map) * BITS_PER_LONG; +- for (i = find_first_bit(map, sz); +- i < cachep->num; +- i = find_next_bit(map, sz, i + 1)) { +- objp = slabp->s_mem + i * cachep->buffer_size; +-#if SLAB_DEBUG +- objp += cachep->obj_offset; +-#endif +- r = (*fun)(objp); +- if (r) +- return r; +- } +- } +- +- return 0; +-} +- +-int kmem_cache_walk_objects(struct kmem_cache *cachep, int (*fun)(void *)) +-{ +- int node; +- int err; +- +- for_each_online_node (node) +- if ((err = kmem_cache_walk_node(cachep, node, fun)) != 0) +- return err; +- +- return 0; +-} +- + unsigned long ub_cache_growth(struct kmem_cache *cachep) + { + return (cachep->grown - cachep->reaped - cachep->shrunk) +@@ -3643,19 +3544,6 @@ + } + } + +-static void kmem_cache_free_block(struct kmem_cache *cachep, struct kmem_list3 *l3, +- void **objpp, int nr_objects, int node) +-{ +- unsigned long flags; +- +- if (!nr_objects) +- return; +- +- spin_lock_irqsave(&l3->list_lock, flags); +- free_block(cachep, objpp, nr_objects, node); +- spin_unlock_irqrestore(&l3->list_lock, flags); +-} +- + static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac) + { + int batchcount; +Index: kernel/mm/slub.c +=================================================================== +--- kernel.orig/mm/slub.c 2008-11-24 15:56:35.000000000 +0100 ++++ kernel/mm/slub.c 2008-11-24 15:57:05.000000000 +0100 +@@ -348,61 +348,6 @@ + + static void __flush_cpu_slab(struct kmem_cache *s, int cpu); + +-static int kmem_cache_walk_page(struct page *pg, struct kmem_cache *s, +- int (*fun)(void *)) +-{ +- int r; +- void *p, *start; +- DECLARE_BITMAP(map, s->objects); +- +- start = page_address(pg); +- +- bitmap_zero(map, s->objects); +- for_each_free_object(p, s, pg->freelist) +- set_bit(slab_index(p, s, start), map); +- +- for_each_object(p, s, start) +- if (!test_bit(slab_index(p, s, start), map)) { +- r = fun(p); +- if (r) +- return r; +- } +- +- return 0; +-} +- +-int kmem_cache_walk_objects(struct kmem_cache *s, int (*fun)(void *)) +-{ +- int i; +- +- /* run under stopachine only, so no locks at all */ +- +- for_each_online_cpu(i) +- __flush_cpu_slab(s, i); +- +- for_each_online_node(i) { +- int r; +- struct page *page; +- struct kmem_cache_node *n; +- +- n = get_node(s, i); +- +- list_for_each_entry(page, &n->partial, lru) { +- r = kmem_cache_walk_page(page, s, fun); +- if (r) +- return r; +- } +- +- list_for_each_entry(page, &n->full, lru) { +- r = kmem_cache_walk_page(page, s, fun); +- if (r) +- return r; +- } +- } +- +- return 0; +-} +- + int kmem_cache_objuse(struct kmem_cache *cachep) + { + return cachep->objuse; --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0013-NETFILTER-copy-max-expect-value-from-VE0-s-during-V.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0013-NETFILTER-copy-max-expect-value-from-VE0-s-during-V.patch @@ -0,0 +1,25 @@ +From b20f7531a00d4433d2791655e1899e015a0dfd04 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 7 Mar 2008 16:03:55 +0300 +Subject: [PATCH 13/48] NETFILTER: copy max expect value from VE0's during VE start + +Otherwise it's set to 0, which effectively means no FTP conntrack by default. +--- + net/netfilter/nf_conntrack_core.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 879dc9e..46e0c5b 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1167,6 +1167,7 @@ int nf_conntrack_init(void) + } + + ve_nf_conntrack_max = nf_conntrack_max; ++ ve_nf_ct_expect_max = nf_ct_expect_max; + atomic_set(&ve_nf_conntrack_count, 0); + INIT_HLIST_HEAD(&ve_unconfirmed); + #endif +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0047-VE-add-ve-mem-class-to-sysfs.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0047-VE-add-ve-mem-class-to-sysfs.patch @@ -0,0 +1,115 @@ +From c6504c8d5283ade41cd3b3c6e1be9a9deafbdaab Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Tue, 25 Mar 2008 11:34:36 +0300 +Subject: [PATCH 47/48] [PATCH] VE: add ve mem class to sysfs + +Create in VE sysfs mem class and some its devices: +null, zero, full, random, urandom. + +Required for Ubuntu 8.04 and maybe some other new distro udev package. + +Bug #99897 +http://bugzilla.openvz.org/show_bug.cgi?id=840 +--- + include/linux/ve.h | 1 + + kernel/ve/vecalls.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 50 insertions(+), 0 deletions(-) + +diff --git a/include/linux/ve.h b/include/linux/ve.h +index 1a5b357..f9cc6aa 100644 +--- a/include/linux/ve.h ++++ b/include/linux/ve.h +@@ -211,6 +211,7 @@ struct ve_struct { + struct kset *class_obj_subsys; + struct kset *devices_subsys; + struct class *tty_class; ++ struct class *mem_class; + + #ifdef CONFIG_NET + struct class *net_class; +diff --git a/kernel/ve/vecalls.c b/kernel/ve/vecalls.c +index 49ecfb8..616cf0b 100644 +--- a/kernel/ve/vecalls.c ++++ b/kernel/ve/vecalls.c +@@ -71,6 +71,7 @@ + #include + #include + #include ++#include + + int nr_ve = 1; /* One VE always exists. Compatibility with vestat */ + EXPORT_SYMBOL(nr_ve); +@@ -645,6 +646,44 @@ static inline void fini_ve_netclass(struct ve_struct *ve) { ; } + + extern struct kset devices_subsys; + ++static const struct { ++ unsigned minor; ++ char *name; ++} mem_class_devices [] = { ++ {3, "null"}, ++ {5, "zero"}, ++ {7, "full"}, ++ {8, "random"}, ++ {9, "urandom"}, ++ {0, NULL}, ++}; ++ ++static struct class *init_ve_mem_class(void) ++{ ++ int i; ++ struct class *ve_mem_class; ++ ++ ve_mem_class = class_create(THIS_MODULE, "mem"); ++ if (IS_ERR(ve_mem_class)) ++ return ve_mem_class; ++ for (i = 0; mem_class_devices[i].name; i++) ++ class_device_create(ve_mem_class, NULL, ++ MKDEV(MEM_MAJOR, mem_class_devices[i].minor), ++ NULL, mem_class_devices[i].name); ++ return ve_mem_class; ++} ++ ++ ++void fini_ve_mem_class(struct class *ve_mem_class) ++{ ++ int i; ++ ++ for (i = 0; mem_class_devices[i].name; i++) ++ class_device_destroy(ve_mem_class, ++ MKDEV(MEM_MAJOR, mem_class_devices[i].minor)); ++ class_destroy(ve_mem_class); ++} ++ + static int init_ve_sysfs(struct ve_struct *ve) + { + struct kset *subsys; +@@ -721,8 +760,17 @@ static int init_ve_sysfs(struct ve_struct *ve) + goto out_tty_class_register; + } + ++ ve->mem_class = init_ve_mem_class(); ++ if (IS_ERR(ve->mem_class)) { ++ err = PTR_ERR(ve->mem_class); ++ ve->mem_class = NULL; ++ goto out_mem_class_register; ++ } ++ + return err; + ++out_mem_class_register: ++ fini_ve_tty_class(ve->tty_class); + out_tty_class_register: + fini_ve_netclass(ve); + out_nc: +@@ -759,6 +807,7 @@ out: + + static void fini_ve_sysfs(struct ve_struct *ve) + { ++ fini_ve_mem_class(ve->mem_class); + fini_ve_tty_class(ve->tty_class); + fini_ve_netclass(ve); + subsystem_unregister(ve->devices_subsys); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0123-VE-NFS-lockd-without-ve.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0123-VE-NFS-lockd-without-ve.patch @@ -0,0 +1,28 @@ +From f0601527973500793e52950c3091a542adafd9a5 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 18 Jul 2008 15:25:52 +0400 +Subject: [PATCH 123/131] VE NFS lockd without ve + +fix macro in ve_nfs.h when CONFIG_VE=n +--- + include/linux/ve_nfs.h | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/ve_nfs.h b/include/linux/ve_nfs.h +index 9f2b4f1..74ba0cd 100644 +--- a/include/linux/ve_nfs.h ++++ b/include/linux/ve_nfs.h +@@ -20,8 +20,8 @@ + #define nlmsvc_users NFS_CTX_FIELD(nlmsvc_users) + #define nlmsvc_pid NFS_CTX_FIELD(nlmsvc_pid) + #else +-#define nlmsvc_grace_period _nlmsvc_timeout +-#define nlmsvc_timeout _nlmsvc_grace_period ++#define nlmsvc_grace_period _nlmsvc_grace_period ++#define nlmsvc_users _nlmsvc_users + #define nlmsvc_pid _nlmsvc_pid + #define nlmsvc_timeout _nlmsvc_timeout + #endif +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0108-UBC-account-for-rss-pages.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0108-UBC-account-for-rss-pages.patch @@ -0,0 +1,118 @@ +From 9de272e0bbf4a41408db8a7ef54acf5e5ff7be51 Mon Sep 17 00:00:00 2001 +From: Pavel Emelianov +Date: Fri, 18 Jul 2008 15:25:42 +0400 +Subject: [PATCH 108/131] UBC account for rss pages + +UBC: show how much page beancounters each UB has + +Essentially, this is the per-UB rss value calculated +(unline physpages and privvmpages) w/o taking sharing +into account. + +With this statistics (shown via /proc/bc/XXX/vmaux:rss) +we can evaluate the portion of pages, that are shared +accross beancounters (i.e. CTs) like this: + +(\sum (bc.rss + bc.tmpfs_respages) - \sum (bc.physpages)) / + (\sum (bc.rss + bc.tmpfs_respages)) + +Bug #114660 +--- + include/bc/beancounter.h | 3 ++- + include/bc/debug.h | 6 ------ + kernel/bc/rss_pages.c | 16 ++++++++++++++++ + kernel/bc/vm_pages.c | 1 + + 4 files changed, 19 insertions(+), 7 deletions(-) + +diff --git a/include/bc/beancounter.h b/include/bc/beancounter.h +index 89fcf20..0b621dc 100644 +--- a/include/bc/beancounter.h ++++ b/include/bc/beancounter.h +@@ -142,6 +142,7 @@ struct page_private { + unsigned long ubp_unused_privvmpages; + unsigned long ubp_tmpfs_respages; + unsigned long ubp_swap_pages; ++ unsigned long ubp_pbcs; + unsigned long long ubp_held_pages; + }; + +@@ -170,7 +171,6 @@ struct ub_percpu_struct { + #ifdef CONFIG_BC_DEBUG_KMEM + long pages_charged; + long vmalloc_charged; +- long pbcs; + #endif + unsigned long sync; + unsigned long sync_done; +@@ -213,6 +213,7 @@ struct user_beancounter + #define ub_tmpfs_respages ppriv.ubp_tmpfs_respages + #define ub_swap_pages ppriv.ubp_swap_pages + #define ub_held_pages ppriv.ubp_held_pages ++#define ub_pbcs ppriv.ubp_pbcs + struct sock_private spriv; + #define ub_rmem_thres spriv.ubp_rmem_thres + #define ub_maxadvmss spriv.ubp_maxadvmss +diff --git a/include/bc/debug.h b/include/bc/debug.h +index 7b1feb6..58c64f3 100644 +--- a/include/bc/debug.h ++++ b/include/bc/debug.h +@@ -91,17 +91,11 @@ struct vm_struct; + ub_percpu_sub(ub, vmalloc_charged, \ + vm->nr_pages); \ + } while (0) +- +-#define inc_pbc_count(ub) ub_percpu_inc(ub, pbcs) +-#define dec_pbc_count(ub) ub_percpu_dec(ub, pbcs) + #else + #define init_cache_counters() do { } while (0) + #define inc_vmalloc_charged(vm, f) do { } while (0) + #define dec_vmalloc_charged(vm) do { } while (0) + +-#define inc_pbc_count(ub) do { } while (0) +-#define dec_pbc_count(ub) do { } while (0) +- + #define ub_free_counters(ub) do { } while (0) + #define ub_kmemcache_free(cachep) do { } while (0) + #endif +diff --git a/kernel/bc/rss_pages.c b/kernel/bc/rss_pages.c +index 391585e..84c4c6d 100644 +--- a/kernel/bc/rss_pages.c ++++ b/kernel/bc/rss_pages.c +@@ -85,6 +85,22 @@ static void inc_held_pages(struct user_beancounter *ub, int value) + } + + /* ++ * ++ and -- beyond are protected with pb_lock ++ */ ++ ++static inline void inc_pbc_count(struct user_beancounter *ub) ++{ ++ for (; ub != NULL; ub = ub->parent) ++ ub->ub_pbcs++; ++} ++ ++static inline void dec_pbc_count(struct user_beancounter *ub) ++{ ++ for (; ub != NULL; ub = ub->parent) ++ ub->ub_pbcs--; ++} ++ ++/* + * Alloc - free + */ + +diff --git a/kernel/bc/vm_pages.c b/kernel/bc/vm_pages.c +index d48f327..124ebf7 100644 +--- a/kernel/bc/vm_pages.c ++++ b/kernel/bc/vm_pages.c +@@ -529,6 +529,7 @@ static int bc_vmaux_show(struct seq_file *f, void *v) + ub->ub_tmpfs_respages); + seq_printf(f, bc_proc_lu_fmt, ub_rnames[UB_SWAPPAGES], + ub->ub_swap_pages); ++ seq_printf(f, bc_proc_lu_fmt, "rss", ub->ub_pbcs); + + seq_printf(f, bc_proc_lu_fmt, "swapin", swap); + seq_printf(f, bc_proc_lu_fmt, "unmap", unmap); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0116-UBC-net-setcharge-warning-fix.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0116-UBC-net-setcharge-warning-fix.patch @@ -0,0 +1,100 @@ +From a96cbb24e5e820a4457b6520e2590951348028e1 Mon Sep 17 00:00:00 2001 +From: Denis Lunev +Date: Fri, 18 Jul 2008 15:25:48 +0400 +Subject: [PATCH 116/131] UBC net setcharge warning fix + +ub: ub_sock_tcp_chargesend warning if called via tcp_fragment + +BUG: warning at kernel/ub/ub_net.c:335/__ub_skb_set_charge() (Tainted: P ) + [] ub_sock_tcp_chargesend+0x86/0x171 + [] tcp_fragment+0xaf/0x452 + [] tcp_sacktag_write_queue+0x30f/0x71e + [] tcp_ack+0x206/0x184c + [] __tcp_push_pending_frames+0x4ab/0x79e + [] tcp_rcv_established+0x76b/0x884 + [] tcp_v4_do_rcv+0x40/0x329 + [] ipt_hook+0x28/0x30 [iptable_filter] + [] nf_iterate+0x30/0x61 + [] tcp_v4_rcv+0x981/0x9d5 + [] ip_local_deliver+0x1a6/0x26f + [] ip_rcv+0x4fb/0x53e + [] netif_receive_skb+0x306/0x3ac + [] e1000_clean_rx_irq+0x34a/0x41f [e1000] + [] e1000_clean+0x6b/0x222 [e1000] + [] net_rx_action+0x92/0x175 + [] __do_softirq+0x84/0x109 + [] do_softirq+0x36/0x3a + [] do_IRQ+0xad/0xb6 + [] common_interrupt+0x1a/0x20 + [] mwait_idle+0x25/0x38 + [] cpu_idle+0x5e/0x74 + ======================= + +The warning occures when we try to charge skb that is already charged. +This is correct for the case. The size of underlying skb is changed and +we uncharge/charge to keep situation sane. + +ub_skb_uncharge is equivalent to + ub_sock_ret_wreserv + ub_skb_set_uncharge +which is just correct for the case. + +Bug #115332 +--- + include/bc/net.h | 2 -- + kernel/bc/net.c | 8 -------- + net/ipv4/tcp_output.c | 4 +--- + 3 files changed, 1 insertions(+), 13 deletions(-) + +diff --git a/include/bc/net.h b/include/bc/net.h +index 5f82aff..32f33b9 100644 +--- a/include/bc/net.h ++++ b/include/bc/net.h +@@ -63,8 +63,6 @@ UB_DECLARE_VOID_FUNC(ub_sock_ret_wreserv(struct sock *sk, int bufid, + unsigned long size, unsigned long ressize)) + UB_DECLARE_FUNC(int, ub_sock_tcp_chargesend(struct sock *sk, + struct sk_buff *skb, enum ub_severity strict)) +-UB_DECLARE_VOID_FUNC(ub_sock_tcp_unchargesend(struct sock *sk, +- unsigned long size)) + UB_DECLARE_FUNC(int, ub_sock_tcp_chargepage(struct sock *sk)) + UB_DECLARE_VOID_FUNC(ub_sock_tcp_detachpage(struct sock *sk)) + +diff --git a/kernel/bc/net.c b/kernel/bc/net.c +index ad88b86..8f7512f 100644 +--- a/kernel/bc/net.c ++++ b/kernel/bc/net.c +@@ -1135,14 +1135,6 @@ int ub_sock_tcp_chargesend(struct sock *sk, struct sk_buff *skb, + } + EXPORT_SYMBOL(ub_sock_tcp_chargesend); + +-void ub_sock_tcp_unchargesend(struct sock *sk, unsigned long size) +-{ +- if (unlikely(!sock_has_ubc(sk))) +- return; +- /* see ub_tcpsndbuf_uncharge */ +- ub_sock_ret_wreserv(sk, UB_TCPSNDBUF, size, sock_bc(sk)->poll_reserv); +-} +- + /* + * Initialization + */ +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 3e0a33a..f414220 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -718,11 +718,9 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss + nsize = 0; + + if (skb_cloned(skb) && skb_is_nonlinear(skb)) { +- unsigned long chargesize; +- chargesize = skb_bc(skb)->charged; + if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + return -ENOMEM; +- ub_sock_tcp_unchargesend(sk, chargesize); ++ ub_skb_uncharge(skb); + ub_tcpsndbuf_charge_forced(sk, skb); + } + +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0114-UBC-cfq-remove-variable-slice.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0114-UBC-cfq-remove-variable-slice.patch @@ -0,0 +1,49 @@ +From 8f7aa861d70b16db33db541070a87ed03884e790 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 18 Jul 2008 15:25:46 +0400 +Subject: [PATCH 114/131] UBC cfq remove variable slice + +Remove variable bc timeslice -- with fair queue it useless. +BC got bigger timeslice, but bandwidth unchanged, +because bc queued according it iotime. + +Bandwidth distribution now fully controlled by iotime ratio coefficients. +--- + kernel/bc/io_prio.c | 14 ++------------ + 1 files changed, 2 insertions(+), 12 deletions(-) + +diff --git a/kernel/bc/io_prio.c b/kernel/bc/io_prio.c +index d3a39e5..74202fa 100644 +--- a/kernel/bc/io_prio.c ++++ b/kernel/bc/io_prio.c +@@ -182,15 +182,7 @@ static inline int bc_empty(struct cfq_bc_data *cfq_bc) + + return 0; + } +- +-static inline unsigned long bc_time_slice_by_ioprio(unsigned int ioprio, +- unsigned int base_slice) +-{ +- return base_slice + +- (base_slice * (ioprio - UB_IOPRIO_MIN)) +- / (UB_IOPRIO_MAX - UB_IOPRIO_MIN - 1); +-} +- ++ + /* return true if a iotime after b, like time_after */ + static int bc_iotime_after(unsigned long a, unsigned long b) + { +@@ -287,9 +279,7 @@ static inline void bc_set_active(struct cfq_data *cfqd) + + cfqd->active_cfq_bc = cfq_bc; + cfqd->slice_begin = now; +- cfqd->slice_end = now + +- bc_time_slice_by_ioprio(cfqd->active_cfq_bc->ub_iopriv->ioprio, +- cfqd->cfq_ub_slice); ++ cfqd->slice_end = now + cfqd->cfq_ub_slice; + } + + void bc_schedule_active(struct cfq_data *cfqd) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0081-CPT-kernel-thread-owner-ve.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0081-CPT-kernel-thread-owner-ve.patch @@ -0,0 +1,128 @@ +From 4d7043260ff770c44716d035d1f220211e5a3694 Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Mon, 30 Jun 2008 13:48:48 +0400 +Subject: [PATCH 081/103] CPT kernel thread owner ve + +In current implementation master process which performs checkpointing has +owner_env set to VE0 and exec_env set to VE. All auxiliary kernel threads +are created with exec_env set to VE and owner_env set to VE0, so after the +do_fork_pid() we have the follwing: + + * new thread has owner_env == ve0, exec env == ve + * its pid belongs to ve (pid->veid != 0) + +That is why if ve_enter() in thread fails, then we hit BUG_ON in + release_task -> detach_pid -> free_pid +sequence, since task owner env != pid's veid. + +When enter succeeds the task's owner env becomes ve and this BUG_ON +is not triggered. + +To solve this problem exec_env is switched to VE before kernel thread +creation and switched back after. Veid is passed to kernel via args. All +kernel threads are created with CLONE_VFORK to be sure that parent +process will not exit before doing exec() in thread. + +Bug #97124 +--- + kernel/cpt/cpt_files.c | 7 ++++++- + kernel/cpt/cpt_net.c | 20 +++++++++++++++++--- + 2 files changed, 23 insertions(+), 4 deletions(-) + +diff --git a/kernel/cpt/cpt_files.c b/kernel/cpt/cpt_files.c +index fbba10b..adbd43b 100644 +--- a/kernel/cpt/cpt_files.c ++++ b/kernel/cpt/cpt_files.c +@@ -1330,6 +1330,7 @@ struct args_t + { + int* pfd; + char* path; ++ envid_t veid; + }; + + static int dumptmpfs(void *arg) +@@ -1341,7 +1342,7 @@ static int dumptmpfs(void *arg) + char *path = args->path; + char *argv[] = { "tar", "-c", "-S", "--numeric-owner", path, NULL }; + +- i = real_env_create(VEID(get_exec_env()), VE_ENTER|VE_SKIPLOCK, 2, NULL, 0); ++ i = real_env_create(args->veid, VE_ENTER|VE_SKIPLOCK, 2, NULL, 0); + if (i < 0) { + eprintk("cannot enter ve to dump tmpfs\n"); + module_put(THIS_MODULE); +@@ -1388,16 +1389,20 @@ static int cpt_dump_tmpfs(char *path, struct cpt_context *ctx) + int status; + mm_segment_t oldfs; + sigset_t ignore, blocked; ++ struct ve_struct *oldenv; + + err = sc_pipe(pfd); + if (err < 0) + return err; + args.pfd = pfd; + args.path = path; ++ args.veid = VEID(get_exec_env()); + ignore.sig[0] = CPT_SIG_IGNORE_MASK; + sigprocmask(SIG_BLOCK, &ignore, &blocked); ++ oldenv = set_exec_env(get_ve0()); + err = pid = local_kernel_thread(dumptmpfs, (void*)&args, + SIGCHLD | CLONE_VFORK, 0); ++ set_exec_env(oldenv); + if (err < 0) { + eprintk_ctx("tmpfs local_kernel_thread: %d\n", err); + goto out; +diff --git a/kernel/cpt/cpt_net.c b/kernel/cpt/cpt_net.c +index 2926d24..1944654 100644 +--- a/kernel/cpt/cpt_net.c ++++ b/kernel/cpt/cpt_net.c +@@ -460,13 +460,20 @@ out_sock: + return err; + } + ++struct args_t ++{ ++ int* pfd; ++ envid_t veid; ++}; ++ + static int dumpfn(void *arg) + { + int i; +- int *pfd = arg; ++ struct args_t *args = arg; ++ int *pfd = args->pfd; + char *argv[] = { "iptables-save", "-c", NULL }; + +- i = real_env_create(VEID(get_exec_env()), VE_ENTER|VE_SKIPLOCK, 2, NULL, 0); ++ i = real_env_create(args->veid, VE_ENTER|VE_SKIPLOCK, 2, NULL, 0); + if (i < 0) { + eprintk("cannot enter ve to dump iptables\n"); + module_put(THIS_MODULE); +@@ -506,6 +513,8 @@ static int cpt_dump_iptables(struct cpt_context * ctx) + int status; + mm_segment_t oldfs; + sigset_t ignore, blocked; ++ struct args_t args; ++ struct ve_struct *oldenv; + + if (!(get_exec_env()->_iptables_modules & VE_IP_IPTABLES_MOD)) + return 0; +@@ -515,9 +524,14 @@ static int cpt_dump_iptables(struct cpt_context * ctx) + eprintk_ctx("sc_pipe: %d\n", err); + return err; + } ++ args.pfd = pfd; ++ args.veid = VEID(get_exec_env()); + ignore.sig[0] = CPT_SIG_IGNORE_MASK; + sigprocmask(SIG_BLOCK, &ignore, &blocked); +- err = pid = local_kernel_thread(dumpfn, (void*)pfd, SIGCHLD, 0); ++ oldenv = set_exec_env(get_ve0()); ++ err = pid = local_kernel_thread(dumpfn, (void*)&args, ++ SIGCHLD | CLONE_VFORK, 0); ++ set_exec_env(oldenv); + if (err < 0) { + eprintk_ctx("local_kernel_thread: %d\n", err); + goto out; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0082-CPT-dcache-lock.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0082-CPT-dcache-lock.patch @@ -0,0 +1,61 @@ +From df46b61362d3c5b1f0454a7a093da85f02c9a778 Mon Sep 17 00:00:00 2001 +From: Andrey Mirkin +Date: Mon, 30 Jun 2008 13:48:48 +0400 +Subject: [PATCH 082/103] CPT dcache lock + +Protect __d_path() call with dcache_lock spinlock. +Protect other checks with env->op_sem semaphore. + +Bug #98833 +--- + kernel/cpt/cpt_dump.c | 17 +++++++++++++++++ + 1 files changed, 17 insertions(+), 0 deletions(-) + +diff --git a/kernel/cpt/cpt_dump.c b/kernel/cpt/cpt_dump.c +index ea84dcb..72b7712 100644 +--- a/kernel/cpt/cpt_dump.c ++++ b/kernel/cpt/cpt_dump.c +@@ -1154,9 +1154,11 @@ static void check_unsupported_mounts(struct cpt_context *ctx, __u32 *caps, + list_for_each(p, &n->list) { + struct vfsmount *mnt = list_entry(p, struct vfsmount, mnt_list); + ++ spin_lock(&dcache_lock); + path = __d_path(mnt->mnt_root, mnt, + env->fs_root, env->fs_rootmnt, + path_buf, PAGE_SIZE); ++ spin_unlock(&dcache_lock); + if (IS_ERR(path)) + continue; + +@@ -1186,6 +1188,19 @@ int cpt_vps_caps(struct cpt_context *ctx, __u32 *caps) + if (env == NULL) + return -ESRCH; + ++ down_read(&env->op_sem); ++ err = -ESRCH; ++ if (!env->is_running) { ++ eprintk_ctx("CT is not running\n"); ++ goto out_noenv; ++ } ++ ++ err = -EBUSY; ++ if (env->is_locked) { ++ eprintk_ctx("CT is locked\n"); ++ goto out_noenv; ++ } ++ + *caps = flags & (1<nsproxy = old_ns; + set_exec_env(old_env); ++out_noenv: ++ up_read(&env->op_sem); + put_ve(env); + + return err; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0055-IPV6-make-proc-net-if_inet6-visible-in-VE.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0055-IPV6-make-proc-net-if_inet6-visible-in-VE.patch @@ -0,0 +1,51 @@ +From 55f446a3291f66d97b068470e7ae88bd18b8fd59 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Tue, 1 Apr 2008 16:49:17 +0400 +Subject: [PATCH 54/67] IPV6: make /proc/net/if_inet6 visible in VE + +Logic for showing per-VE IPv6 addresses is already in place. + +http://bugzilla.openvz.org/show_bug.cgi?id=857 +--- + net/ipv6/addrconf.c | 21 ++++++++++++++++++--- + 1 files changed, 18 insertions(+), 3 deletions(-) + +Index: kernel/net/ipv6/addrconf.c +=================================================================== +--- kernel.orig/net/ipv6/addrconf.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv6/addrconf.c 2008-11-24 15:59:35.000000000 +0100 +@@ -2873,16 +2873,31 @@ + .release = seq_release_private, + }; + +-int __init if6_proc_init(void) ++static int ipv6_proc_net_init(struct net *net) + { +- if (!proc_net_fops_create(&init_net, "if_inet6", S_IRUGO, &if6_fops)) ++ if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) + return -ENOMEM; + return 0; + } + ++static void ipv6_proc_net_exit(struct net *net) ++{ ++ proc_net_remove(net, "if_inet6"); ++} ++ ++static struct pernet_operations ipv6_proc_net_ops = { ++ .init = ipv6_proc_net_init, ++ .exit = ipv6_proc_net_exit, ++}; ++ ++int __init if6_proc_init(void) ++{ ++ return register_pernet_subsys(&ipv6_proc_net_ops); ++} ++ + void if6_proc_exit(void) + { +- proc_net_remove(&init_net, "if_inet6"); ++ unregister_pernet_subsys(&ipv6_proc_net_ops); + } + #endif /* CONFIG_PROC_FS */ + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0077-fix-proc-cwd-link.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0077-fix-proc-cwd-link.patch @@ -0,0 +1,23 @@ +commit 72746db0ffbf3715516991a14903b6d30d8d96ed +Author: Alexey Dobriyan +Date: Mon Jun 2 17:53:28 2008 +0400 + + proc: fix proc_cwd_link + + If d_root_check() in there fails, we shouldn't pretend everything is OK + and leave mnt unitialized or NULL (in case /proc/*/cwd). + + http://bugzilla.openvz.org/show_bug.cgi?id=900 + +diff --git a/fs/proc/base.c b/fs/proc/base.c +index da0be8b..8579ee6 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -171,7 +171,6 @@ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfs + *dentry = dget(fs->pwd); + } + read_unlock(&fs->lock); +- result = 0; + put_fs_struct(fs); + } + return result; --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0111-UBC-cfq-fair-queue.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0111-UBC-cfq-fair-queue.patch @@ -0,0 +1,215 @@ +From 79c9f8358982d12f1c3b22947aa368c6a21d758f Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Fri, 18 Jul 2008 15:25:44 +0400 +Subject: [PATCH 111/131] UBC cfq fair queue + +replace round-robin scheduling in CFQ BC level with +fair queuing scheme based on used io time accounting. + +replace list per cfq bc data storage with rb-tree based priority queue +ordered by total used io time (cfq_bc_iotime). + +iotime is a monotonic rising counter of bc total used io time. + +on bc switch queue update iotime of previous active bc according it used time +and activate bc with smallest iotime. +--- + block/cfq-iosched.c | 14 ++++--- + include/linux/cfq-iosched.h | 10 +++-- + kernel/bc/io_prio.c | 85 ++++++++++++++++++++++++++++++++++++++----- + 3 files changed, 89 insertions(+), 20 deletions(-) + +diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c +index 223dd18..8999df2 100644 +--- a/block/cfq-iosched.c ++++ b/block/cfq-iosched.c +@@ -1093,17 +1093,19 @@ static int __cfq_forced_dispatch(struct cfq_bc_data *cfq_bc) + + static int cfq_forced_dispatch(struct cfq_data *cfqd) + { ++ struct rb_node *node; + struct cfq_bc_data *cfq_bc; +- struct cfq_bc_data *cfq_bc_tmp; + int dispatched; + + dispatched = 0; + /* + * We use here _safe iterating, because +- * __cfq_forced_dispatch() produces list_del() implicitly +- */ +- list_for_each_entry_safe(cfq_bc, cfq_bc_tmp, +- &cfqd->act_cfq_bc_head, act_cfq_bc_list) { ++ * __cfq_forced_dispatch() remove bc from tree implicitly ++ */ ++ node = rb_first(&cfqd->cfq_bc_queue); ++ while (node) { ++ cfq_bc = rb_entry(node, struct cfq_bc_data, cfq_bc_node); ++ node = rb_next(node); + dispatched += __cfq_forced_dispatch(cfq_bc); + } + +@@ -2154,7 +2156,7 @@ static void *cfq_init_queue(struct request_queue *q) + if (!cfqd) + return NULL; + +- INIT_LIST_HEAD(&cfqd->act_cfq_bc_head); ++ cfqd->cfq_bc_queue = RB_ROOT; + #ifndef CONFIG_BC_IO_SCHED + cfq_init_cfq_bc(&cfqd->cfq_bc); + /* +diff --git a/include/linux/cfq-iosched.h b/include/linux/cfq-iosched.h +index 62a5697..7f773a2 100644 +--- a/include/linux/cfq-iosched.h ++++ b/include/linux/cfq-iosched.h +@@ -27,8 +27,8 @@ struct cfq_rb_root { + struct cfq_bc_data { + /* for ub.iopriv->cfq_bc_head */ + struct list_head cfq_bc_list; +- /* for cfqd->act_cfq_bc_head */ +- struct list_head act_cfq_bc_list; ++ /* for cfqd->cfq_bc_queue */ ++ struct rb_node cfq_bc_node; + + struct cfq_data *cfqd; + struct ub_iopriv *ub_iopriv; +@@ -43,6 +43,7 @@ struct cfq_bc_data { + + unsigned long rqnum; + unsigned long on_dispatch; ++ unsigned long cfq_bc_iotime; + + /* + * async queue for each priority case +@@ -93,11 +94,12 @@ struct cfq_data { + + struct list_head cic_list; + +- /* list of ub that have requests */ +- struct list_head act_cfq_bc_head; ++ /* bc priority queue */ ++ struct rb_root cfq_bc_queue; + /* ub that owns a timeslice at the moment */ + struct cfq_bc_data *active_cfq_bc; + unsigned int cfq_ub_slice; ++ unsigned long slice_begin; + unsigned long slice_end; + int virt_mode; + int write_virt_mode; +diff --git a/kernel/bc/io_prio.c b/kernel/bc/io_prio.c +index 5dcb9bb..9813a18 100644 +--- a/kernel/bc/io_prio.c ++++ b/kernel/bc/io_prio.c +@@ -186,18 +186,84 @@ static inline unsigned long bc_time_slice_by_ioprio(unsigned int ioprio, + / (UB_IOPRIO_MAX - UB_IOPRIO_MIN - 1); + } + ++/* return true if a iotime after b, like time_after */ ++static int bc_iotime_after(unsigned long a, unsigned long b) ++{ ++ return (long)a - (long)b > 0; ++} ++ ++/* cfq bc queue rb_tree helper function */ ++static void bc_insert(struct cfq_data *cfqd, struct cfq_bc_data *cfq_bc) ++{ ++ struct rb_node **p = &cfqd->cfq_bc_queue.rb_node; ++ struct rb_node *parent = NULL; ++ struct cfq_bc_data *__cfq_bc; ++ ++ while (*p) { ++ parent = *p; ++ __cfq_bc = rb_entry(parent, struct cfq_bc_data, cfq_bc_node); ++ /* important: if equal push right */ ++ if (bc_iotime_after(__cfq_bc->cfq_bc_iotime, ++ cfq_bc->cfq_bc_iotime)) ++ p = &(*p)->rb_left; ++ else ++ p = &(*p)->rb_right; ++ } ++ rb_link_node(&cfq_bc->cfq_bc_node, parent, p); ++ rb_insert_color(&cfq_bc->cfq_bc_node, &cfqd->cfq_bc_queue); ++} ++ ++static void bc_remove(struct cfq_data *cfqd, struct cfq_bc_data *cfq_bc) ++{ ++ rb_erase(&cfq_bc->cfq_bc_node, &cfqd->cfq_bc_queue); ++} ++ ++static void bc_enqueue(struct cfq_data *cfqd, struct cfq_bc_data *cfq_bc) ++{ ++ bc_insert(cfqd, cfq_bc); ++} ++ ++static void bc_dequeue(struct cfq_data *cfqd, struct cfq_bc_data *cfq_bc) ++{ ++ bc_remove(cfqd, cfq_bc); ++} ++ ++/* update bc iotime */ ++static void bc_update(struct cfq_data *cfqd, struct cfq_bc_data *cfq_bc, ++ unsigned long delta) ++{ ++ cfq_bc->cfq_bc_iotime += delta; ++ ++ if (!cfq_bc->rqnum) ++ return; ++ ++ bc_remove(cfqd, cfq_bc); ++ bc_insert(cfqd, cfq_bc); ++} ++ + static inline void bc_set_active(struct cfq_data *cfqd) + { +- if (list_empty(&cfqd->act_cfq_bc_head)) { +- cfqd->active_cfq_bc = NULL; ++ struct cfq_bc_data *cfq_bc; ++ unsigned long now = jiffies; ++ ++ /* update iotime of last active bc according to used time */ ++ cfq_bc = cfqd->active_cfq_bc; ++ if (cfq_bc && cfqd->slice_begin) ++ bc_update(cfqd, cfq_bc, now - cfqd->slice_begin); ++ ++ /* if no active BCs then keep this as an active one */ ++ if (RB_EMPTY_ROOT(&cfqd->cfq_bc_queue)) { ++ cfqd->slice_begin = 0; + return; + } + +- cfqd->active_cfq_bc = list_first_entry(&cfqd->act_cfq_bc_head, +- struct cfq_bc_data, act_cfq_bc_list); +- list_move_tail(&cfqd->active_cfq_bc->act_cfq_bc_list, +- &cfqd->act_cfq_bc_head); +- cfqd->slice_end = jiffies + ++ /* peek first bc from queue */ ++ cfq_bc = rb_entry(rb_first(&cfqd->cfq_bc_queue), ++ struct cfq_bc_data, cfq_bc_node); ++ ++ cfqd->active_cfq_bc = cfq_bc; ++ cfqd->slice_begin = now; ++ cfqd->slice_end = now + + bc_time_slice_by_ioprio(cfqd->active_cfq_bc->ub_iopriv->ioprio, + cfqd->cfq_ub_slice); + } +@@ -216,8 +282,7 @@ void bc_inc_rqnum(struct cfq_queue *cfqq) + cfq_bc = cfqq->cfq_bc; + + if (!cfq_bc->rqnum) +- list_add_tail(&cfq_bc->act_cfq_bc_list, +- &cfqq->cfqd->act_cfq_bc_head); ++ bc_enqueue(cfq_bc->cfqd, cfq_bc); + + cfq_bc->rqnum++; + } +@@ -231,7 +296,7 @@ void bc_dec_rqnum(struct cfq_queue *cfqq) + cfq_bc->rqnum--; + + if (!cfq_bc->rqnum) +- list_del(&cfq_bc->act_cfq_bc_list); ++ bc_dequeue(cfq_bc->cfqd, cfq_bc); + } + + unsigned long bc_set_ioprio(int ubid, int ioprio) +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0035-Change-sys_setsid-and-set_special_pids-to-work-w.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0035-Change-sys_setsid-and-set_special_pids-to-work-w.patch @@ -0,0 +1,145 @@ +From 5185276590e2099c55292fec2906e8d0f8a5bc16 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Mon, 17 Mar 2008 15:36:28 +0300 +Subject: [PATCH 35/48] Change sys_setsid() and set_special_pids() to work with struct pid. + +Backport mainstream patch from Oleg Nesterov . +--- + include/linux/sched.h | 6 ++---- + init/main.c | 2 +- + kernel/exit.c | 21 +++++++++++---------- + kernel/sys.c | 11 ++++++----- + 4 files changed, 20 insertions(+), 20 deletions(-) + +Index: kernel/include/linux/sched.h +=================================================================== +--- kernel.orig/include/linux/sched.h 2008-11-24 15:57:08.000000000 +0100 ++++ kernel/include/linux/sched.h 2008-11-24 15:58:47.000000000 +0100 +@@ -1665,8 +1665,6 @@ + extern struct task_struct *find_task_by_pid_ns(pid_t nr, + struct pid_namespace *ns); + +-extern void __set_special_pids(pid_t session, pid_t pgrp); +- + /* per-UID process charging. */ + extern struct user_struct * alloc_uid(struct user_namespace *, uid_t); + static inline struct user_struct *get_uid(struct user_struct *u) +@@ -1678,8 +1676,8 @@ + extern void switch_uid(struct user_struct *); + extern void release_uids(struct user_namespace *ns); + extern int set_user(uid_t uid, int dumpclear); +-extern void set_special_pids(pid_t session, pid_t pgrp); +-extern void __set_special_pids(pid_t session, pid_t pgrp); ++extern void set_special_pids(struct pid *pid); ++extern void __set_special_pids(struct pid *pid); + + #include + +Index: kernel/init/main.c +=================================================================== +--- kernel.orig/init/main.c 2008-11-24 15:57:27.000000000 +0100 ++++ kernel/init/main.c 2008-11-24 15:58:47.000000000 +0100 +@@ -858,7 +858,7 @@ + */ + init_pid_ns.child_reaper = current; + +- __set_special_pids(1, 1); ++ __set_special_pids(&init_struct_pid); + cad_pid = task_pid(current); + + smp_prepare_cpus(max_cpus); +Index: kernel/kernel/exit.c +=================================================================== +--- kernel.orig/kernel/exit.c 2008-11-24 15:57:08.000000000 +0100 ++++ kernel/kernel/exit.c 2008-11-24 15:58:47.000000000 +0100 +@@ -310,26 +310,27 @@ + switch_uid(INIT_USER); + } + +-void __set_special_pids(pid_t session, pid_t pgrp) ++void __set_special_pids(struct pid *pid) + { + struct task_struct *curr = current->group_leader; ++ pid_t nr = pid_nr(pid); + +- if (task_session_nr(curr) != session) { ++ if (task_session(curr) != pid) { + detach_pid(curr, PIDTYPE_SID); +- set_task_session(curr, session); +- attach_pid(curr, PIDTYPE_SID, find_pid(session)); ++ attach_pid(curr, PIDTYPE_SID, pid); ++ set_task_session(curr, nr); + } +- if (task_pgrp_nr(curr) != pgrp) { ++ if (task_pgrp(curr) != pid) { + detach_pid(curr, PIDTYPE_PGID); +- set_task_pgrp(curr, pgrp); +- attach_pid(curr, PIDTYPE_PGID, find_pid_ns(pgrp, &init_pid_ns)); ++ attach_pid(curr, PIDTYPE_PGID, pid); ++ set_task_pgrp(curr, nr); + } + } + +-void set_special_pids(pid_t session, pid_t pgrp) ++void set_special_pids(struct pid *pid) + { + write_lock_irq(&tasklist_lock); +- __set_special_pids(session, pgrp); ++ __set_special_pids(pid); + write_unlock_irq(&tasklist_lock); + } + EXPORT_SYMBOL(set_special_pids); +@@ -401,7 +402,7 @@ + */ + current->flags |= PF_NOFREEZE; + +- set_special_pids(1, 1); ++ set_special_pids(&init_struct_pid); + proc_clear_tty(current); + + /* Block and flush all signals */ +Index: kernel/kernel/sys.c +=================================================================== +--- kernel.orig/kernel/sys.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/kernel/sys.c 2008-11-24 15:58:47.000000000 +0100 +@@ -1192,6 +1192,7 @@ + { + struct task_struct *group_leader = current->group_leader; + pid_t session; ++ struct pid *sid; + int err = -EPERM; + + write_lock_irq(&tasklist_lock); +@@ -1200,7 +1201,8 @@ + if (group_leader->signal->leader) + goto out; + +- session = group_leader->pid; ++ sid = task_pid(group_leader); ++ session = pid_vnr(sid); + /* Fail if a process group id already exists that equals the + * proposed session id. + * +@@ -1208,19 +1210,18 @@ + * session id and so the check will always fail and make it so + * init cannot successfully call setsid. + */ +- if (session > 1 && find_task_by_pid_type_ns(PIDTYPE_PGID, +- session, &init_pid_ns)) ++ if (session > 1 && pid_task(sid, PIDTYPE_PGID)) + goto out; + + group_leader->signal->leader = 1; +- __set_special_pids(session, session); ++ __set_special_pids(sid); + + spin_lock(&group_leader->sighand->siglock); + group_leader->signal->tty = NULL; + group_leader->signal->tty_old_pgrp = 0; + spin_unlock(&group_leader->sighand->siglock); + +- err = task_pgrp_vnr(group_leader); ++ err = session; + out: + write_unlock_irq(&tasklist_lock); + return err; --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0141-MISC-autofs4-revert-ia32-compat-hack.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0141-MISC-autofs4-revert-ia32-compat-hack.patch @@ -0,0 +1,286 @@ +From 6e9bc37f6990e4c5fd8f9afc491f2ecc717eda16 Mon Sep 17 00:00:00 2001 +From: Konstantin Khlebnikov +Date: Mon, 8 Sep 2008 14:15:06 +0400 +Subject: [PATCH] MISC autofs4 revert ia32 compat hack + +Next patch fix it in a less-intrusive manner. +--- + fs/autofs4/autofs_i.h | 5 -- + fs/autofs4/inode.c | 7 --- + fs/autofs4/waitq.c | 107 ++++++++++++++------------------------------- + include/linux/auto_fs.h | 16 ------- + include/linux/auto_fs4.h | 26 ----------- + 5 files changed, 33 insertions(+), 128 deletions(-) + +diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h +index 32d1ddb..2d4ae40 100644 +--- a/fs/autofs4/autofs_i.h ++++ b/fs/autofs4/autofs_i.h +@@ -94,10 +94,6 @@ struct autofs_wait_queue { + #define AUTOFS_TYPE_DIRECT 0x0002 + #define AUTOFS_TYPE_OFFSET 0x0004 + +-/* flags for userspace automount daemon */ +-#define AUTOFS_DEAMON_32BIT 0 /* automount is a 32bit process */ +-#define _AUTOFS_DEAMON_32BIT (1 << AUTOFS_DEAMON_32BIT) +- + struct autofs_sb_info { + u32 magic; + int pipefd; +@@ -118,7 +114,6 @@ struct autofs_sb_info { + struct autofs_wait_queue *queues; /* Wait queue pointer */ + spinlock_t rehash_lock; + struct list_head rehash_list; +- u32 flags; /* flags for userspace automount daemon */ + }; + + static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb) +diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c +index 2737f29..7f05d6c 100644 +--- a/fs/autofs4/inode.c ++++ b/fs/autofs4/inode.c +@@ -311,7 +311,6 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) + int pipefd; + struct autofs_sb_info *sbi; + struct autofs_info *ino; +- struct task_struct *tsk = current; + + sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); + if (!sbi) +@@ -331,12 +330,6 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) + sbi->type = 0; + sbi->min_proto = 0; + sbi->max_proto = 0; +-#ifdef __x86_64__ +- if (task_thread_info(tsk)->flags & _TIF_IA32) { +- /* mark that automount daemon is 32 bit */ +- sbi->flags |= _AUTOFS_DEAMON_32BIT; +- } +-#endif + mutex_init(&sbi->wq_mutex); + spin_lock_init(&sbi->fs_lock); + sbi->queues = NULL; +diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c +index 98552fd..1fe28e4 100644 +--- a/fs/autofs4/waitq.c ++++ b/fs/autofs4/waitq.c +@@ -102,50 +102,27 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, + /* Kernel protocol v4 missing and expire packets */ + case autofs_ptype_missing: + { +- if (sbi->flags & _AUTOFS_DEAMON_32BIT) { +- struct autofs_packet_missing_32bit *mp = &pkt.v4_pkt.missing_32bit; +- +- pktsz = sizeof(*mp); +- mp->wait_queue_token = wq->wait_queue_token; +- mp->len = wq->len; +- memcpy(mp->name, wq->name, wq->len); +- mp->name[wq->len] = '\0'; +- break; +- } else { +- struct autofs_packet_missing *mp = &pkt.v4_pkt.missing; ++ struct autofs_packet_missing *mp = &pkt.v4_pkt.missing; + +- pktsz = sizeof(*mp); ++ pktsz = sizeof(*mp); + +- mp->wait_queue_token = wq->wait_queue_token; +- mp->len = wq->len; +- memcpy(mp->name, wq->name, wq->len); +- mp->name[wq->len] = '\0'; +- break; +- } ++ mp->wait_queue_token = wq->wait_queue_token; ++ mp->len = wq->len; ++ memcpy(mp->name, wq->name, wq->len); ++ mp->name[wq->len] = '\0'; ++ break; + } + case autofs_ptype_expire_multi: + { +- if (sbi->flags & _AUTOFS_DEAMON_32BIT) { +- struct autofs_packet_expire_multi_32bit *ep = &pkt.v4_pkt.expire_multi_32bit; +- +- pktsz = sizeof(*ep); +- +- ep->wait_queue_token = wq->wait_queue_token; +- ep->len = wq->len; +- memcpy(ep->name, wq->name, wq->len); +- ep->name[wq->len] = '\0'; +- break; +- } else { +- struct autofs_packet_expire_multi *ep = &pkt.v4_pkt.expire_multi; ++ struct autofs_packet_expire_multi *ep = &pkt.v4_pkt.expire_multi; + +- pktsz = sizeof(*ep); ++ pktsz = sizeof(*ep); + +- ep->wait_queue_token = wq->wait_queue_token; +- ep->len = wq->len; +- memcpy(ep->name, wq->name, wq->len); +- ep->name[wq->len] = '\0'; +- break; +- } ++ ep->wait_queue_token = wq->wait_queue_token; ++ ep->len = wq->len; ++ memcpy(ep->name, wq->name, wq->len); ++ ep->name[wq->len] = '\0'; ++ break; + } + /* + * Kernel protocol v5 packet for handling indirect and direct +@@ -156,39 +133,21 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, + case autofs_ptype_missing_direct: + case autofs_ptype_expire_direct: + { +- if (sbi->flags & _AUTOFS_DEAMON_32BIT) { +- struct autofs_v5_packet_32bit *packet = &pkt.v5_pkt.v5_packet_32bit; +- +- pktsz = sizeof(*packet); +- +- packet->wait_queue_token = wq->wait_queue_token; +- packet->len = wq->len; +- memcpy(packet->name, wq->name, wq->len); +- packet->name[wq->len] = '\0'; +- packet->dev = wq->dev; +- packet->ino = wq->ino; +- packet->uid = wq->uid; +- packet->gid = wq->gid; +- packet->pid = wq->pid; +- packet->tgid = wq->tgid; +- break; +- } else { +- struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet; +- +- pktsz = sizeof(*packet); +- +- packet->wait_queue_token = wq->wait_queue_token; +- packet->len = wq->len; +- memcpy(packet->name, wq->name, wq->len); +- packet->name[wq->len] = '\0'; +- packet->dev = wq->dev; +- packet->ino = wq->ino; +- packet->uid = wq->uid; +- packet->gid = wq->gid; +- packet->pid = wq->pid; +- packet->tgid = wq->tgid; +- break; +- } ++ struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet; ++ ++ pktsz = sizeof(*packet); ++ ++ packet->wait_queue_token = wq->wait_queue_token; ++ packet->len = wq->len; ++ memcpy(packet->name, wq->name, wq->len); ++ packet->name[wq->len] = '\0'; ++ packet->dev = wq->dev; ++ packet->ino = wq->ino; ++ packet->uid = wq->uid; ++ packet->gid = wq->gid; ++ packet->pid = wq->pid; ++ packet->tgid = wq->tgid; ++ break; + } + default: + printk("autofs4_notify_daemon: bad type %d!\n", type); +diff --git a/include/linux/auto_fs.h b/include/linux/auto_fs.h +index 559a0af..c21e597 100644 +--- a/include/linux/auto_fs.h ++++ b/include/linux/auto_fs.h +@@ -51,8 +51,6 @@ typedef unsigned int autofs_wqt_t; + typedef unsigned long autofs_wqt_t; + #endif + +-typedef __u32 autofs_wqt_t_32bit; +- + /* Packet types */ + #define autofs_ptype_missing 0 /* Missing entry (mount request) */ + #define autofs_ptype_expire 1 /* Expire entry (umount request) */ +@@ -69,13 +67,6 @@ struct autofs_packet_missing { + char name[NAME_MAX+1]; + }; + +-struct autofs_packet_missing_32bit { +- struct autofs_packet_hdr hdr; +- autofs_wqt_t_32bit wait_queue_token; +- int len; +- char name[NAME_MAX+1]; +-} __attribute__ ((__packed__)); +- + /* v3 expire (via ioctl) */ + struct autofs_packet_expire { + struct autofs_packet_hdr hdr; +@@ -83,13 +74,6 @@ struct autofs_packet_expire { + char name[NAME_MAX+1]; + }; + +-/* v3 expire (via ioctl) for 32 bit userspace daemon and x68_64 kernel */ +-struct autofs_packet_expire_32bit { +- struct autofs_packet_hdr hdr; +- int len; +- char name[NAME_MAX+1]; +-} __attribute__ ((__packed__)); +- + #define AUTOFS_IOC_READY _IO(0x93,0x60) + #define AUTOFS_IOC_FAIL _IO(0x93,0x61) + #define AUTOFS_IOC_CATATONIC _IO(0x93,0x62) +diff --git a/include/linux/auto_fs4.h b/include/linux/auto_fs4.h +index 16a80d3..31a2954 100644 +--- a/include/linux/auto_fs4.h ++++ b/include/linux/auto_fs4.h +@@ -59,22 +59,11 @@ struct autofs_packet_expire_multi { + char name[NAME_MAX+1]; + }; + +-/* v4 multi expire (via pipe) for 32 bit userspace daemon and x68_64 kernel */ +-struct autofs_packet_expire_multi_32bit { +- struct autofs_packet_hdr hdr; +- autofs_wqt_t_32bit wait_queue_token; +- int len; +- char name[NAME_MAX+1]; +-} __attribute__ ((__packed__)); +- + union autofs_packet_union { + struct autofs_packet_hdr hdr; + struct autofs_packet_missing missing; +- struct autofs_packet_missing_32bit missing_32bit; + struct autofs_packet_expire expire; +- struct autofs_packet_expire_32bit expire_32bit; + struct autofs_packet_expire_multi expire_multi; +- struct autofs_packet_expire_multi_32bit expire_multi_32bit; + }; + + /* autofs v5 common packet struct */ +@@ -91,20 +80,6 @@ struct autofs_v5_packet { + char name[NAME_MAX+1]; + }; + +-/* autofs v5 packet struct for 32 bit userspace daemon and x68_64 kernel*/ +-struct autofs_v5_packet_32bit { +- struct autofs_packet_hdr hdr; +- autofs_wqt_t_32bit wait_queue_token; +- __u32 dev; +- __u64 ino; +- __u32 uid; +- __u32 gid; +- __u32 pid; +- __u32 tgid; +- __u32 len; +- char name[NAME_MAX+1]; +-} __attribute__ ((__packed__)); +- + typedef struct autofs_v5_packet autofs_packet_missing_indirect_t; + typedef struct autofs_v5_packet autofs_packet_expire_indirect_t; + typedef struct autofs_v5_packet autofs_packet_missing_direct_t; +@@ -113,7 +88,6 @@ typedef struct autofs_v5_packet autofs_packet_expire_direct_t; + union autofs_v5_packet_union { + struct autofs_packet_hdr hdr; + struct autofs_v5_packet v5_packet; +- struct autofs_v5_packet_32bit v5_packet_32bit; + autofs_packet_missing_indirect_t missing_indirect; + autofs_packet_expire_indirect_t expire_indirect; + autofs_packet_missing_direct_t missing_direct; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0080-CPT-checkrunning.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0080-CPT-checkrunning.patch @@ -0,0 +1,27 @@ +From fdf061b9895ab15cfd55f6fdcd5375bd31c3f350 Mon Sep 17 00:00:00 2001 +From: Denis Lunev +Date: Mon, 30 Jun 2008 12:41:16 +0400 +Subject: [PATCH 080/103] CPT checkrunning + Check that VE is not running on restore. + +#99679 +--- + kernel/cpt/rst_undump.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/kernel/cpt/rst_undump.c b/kernel/cpt/rst_undump.c +index 13aa020..26eb211 100644 +--- a/kernel/cpt/rst_undump.c ++++ b/kernel/cpt/rst_undump.c +@@ -144,7 +144,7 @@ static int vps_rst_reparent_root(cpt_object_t *obj, struct cpt_context *ctx) + param.known_features = (ctx->image_version < CPT_VERSION_18) ? + VE_FEATURES_OLD : ~(__u64)0; + +- err = real_env_create(ctx->ve_id, VE_CREATE|VE_LOCK, 2, ++ err = real_env_create(ctx->ve_id, VE_CREATE|VE_LOCK|VE_EXCLUSIVE, 2, + ¶m, sizeof(param)); + if (err < 0) + eprintk_ctx("real_env_create: %d\n", err); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0065-CPT-fix-non-existent-RCU-locking-during-resume.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0065-CPT-fix-non-existent-RCU-locking-during-resume.patch @@ -0,0 +1,170 @@ +From 2898400a6c100c60930ac3f0ae54f19e3199a4ab Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 18 Apr 2008 19:41:05 +0400 +Subject: [PATCH 64/67] CPT: fix non-existent RCU locking during resume + +The rules are that manipulations with pid's found by find_vpid() +should be done under RCU lock. +--- + kernel/cpt/rst_process.c | 32 ++++++++++++++++++-------------- + kernel/cpt/rst_tty.c | 9 +++++++-- + 2 files changed, 25 insertions(+), 16 deletions(-) + +diff --git a/kernel/cpt/rst_process.c b/kernel/cpt/rst_process.c +index 8388f32..c54f04e 100644 +--- a/kernel/cpt/rst_process.c ++++ b/kernel/cpt/rst_process.c +@@ -230,7 +230,8 @@ int rst_process_linkage(cpt_context_t *ctx) + if (task_pgrp_vnr(tsk) != ti->cpt_pgrp) { + struct pid *pid; + +- pid = get_pid(find_vpid(ti->cpt_pgrp)); ++ rcu_read_lock(); ++ pid = find_vpid(ti->cpt_pgrp); + if (!pid) { + eprintk_ctx("illegal PGRP " CPT_FID "\n", CPT_TID(tsk)); + return -EINVAL; +@@ -240,23 +241,21 @@ int rst_process_linkage(cpt_context_t *ctx) + if (task_pgrp_nr(tsk) != pid_nr(pid)) { + detach_pid(tsk, PIDTYPE_PGID); + set_task_pgrp(tsk, pid_nr(pid)); +- if (thread_group_leader(tsk)) { +- get_pid(pid); ++ if (thread_group_leader(tsk)) + attach_pid(tsk, PIDTYPE_PGID, pid); +- } + } + write_unlock_irq(&tasklist_lock); + if (task_pgrp_nr(tsk) != pid_nr(pid)) { +- put_pid(pid); + eprintk_ctx("cannot set PGRP " CPT_FID "\n", CPT_TID(tsk)); + return -EINVAL; + } +- put_pid(pid); ++ rcu_read_unlock(); + } + if (task_session_vnr(tsk) != ti->cpt_session) { + struct pid *pid; + +- pid = get_pid(find_vpid(ti->cpt_session)); ++ rcu_read_lock(); ++ pid = find_vpid(ti->cpt_session); + if (!pid) { + eprintk_ctx("illegal SID " CPT_FID "\n", CPT_TID(tsk)); + return -EINVAL; +@@ -266,28 +265,27 @@ int rst_process_linkage(cpt_context_t *ctx) + if (task_session_nr(tsk) != pid_nr(pid)) { + detach_pid(tsk, PIDTYPE_SID); + set_task_session(tsk, pid_nr(pid)); +- if (thread_group_leader(tsk)) { +- get_pid(pid); ++ if (thread_group_leader(tsk)) + attach_pid(tsk, PIDTYPE_SID, pid); +- } + } + write_unlock_irq(&tasklist_lock); + if (task_session_nr(tsk) != pid_nr(pid)) { +- put_pid(pid); + eprintk_ctx("cannot set SID " CPT_FID "\n", CPT_TID(tsk)); + return -EINVAL; + } +- put_pid(pid); ++ rcu_read_unlock(); + } + if (ti->cpt_old_pgrp > 0 && !tsk->signal->tty_old_pgrp) { + struct pid *pid; + ++ rcu_read_lock(); + pid = get_pid(find_vpid(ti->cpt_old_pgrp)); + if (!pid) { + eprintk_ctx("illegal OLD_PGRP " CPT_FID "\n", CPT_TID(tsk)); + return -EINVAL; + } + tsk->signal->tty_old_pgrp = pid; ++ rcu_read_unlock(); + } + } + +@@ -300,7 +298,7 @@ struct pid *alloc_vpid_safe(pid_t vnr) + + pid = alloc_pid(current->nsproxy->pid_ns, vnr); + if (!pid) +- pid = get_pid(find_vpid(vnr)); ++ pid = find_vpid(vnr); + return pid; + } + +@@ -321,6 +319,7 @@ restore_one_signal_struct(struct cpt_task_image *ti, int *exiting, cpt_context_t + if (task_pgrp_vnr(current) != si->cpt_pgrp) { + struct pid * pid = NULL, *free = NULL; + ++ rcu_read_lock(); + if (si->cpt_pgrp_type == CPT_PGRP_ORPHAN) { + #if 0 + if (!is_virtual_pid(si->cpt_pgrp)) { +@@ -346,6 +345,7 @@ restore_one_signal_struct(struct cpt_task_image *ti, int *exiting, cpt_context_t + write_unlock_irq(&tasklist_lock); + if (free != NULL) + free_pid(free); ++ rcu_read_unlock(); + } + + current->signal->tty_old_pgrp = NULL; +@@ -359,8 +359,10 @@ restore_one_signal_struct(struct cpt_task_image *ti, int *exiting, cpt_context_t + return -EINVAL; + } + } else { ++ rcu_read_lock(); + current->signal->tty_old_pgrp = +- alloc_vpid_safe(si->cpt_old_pgrp); ++ get_pid(alloc_vpid_safe(si->cpt_old_pgrp)); ++ rcu_read_unlock(); + if (!current->signal->tty_old_pgrp) { + dprintk_ctx("forward old tty PGID\n"); + current->signal->tty_old_pgrp = NULL; +@@ -371,6 +373,7 @@ restore_one_signal_struct(struct cpt_task_image *ti, int *exiting, cpt_context_t + if (task_session_vnr(current) != si->cpt_session) { + struct pid * pid = NULL, *free = NULL; + ++ rcu_read_lock(); + if (si->cpt_session_type == CPT_PGRP_ORPHAN) { + #if 0 + if (!is_virtual_pid(si->cpt_session)) { +@@ -398,6 +401,7 @@ restore_one_signal_struct(struct cpt_task_image *ti, int *exiting, cpt_context_t + write_unlock_irq(&tasklist_lock); + if (free != NULL) + free_pid(free); ++ rcu_read_unlock(); + } + + cpt_sigset_import(¤t->signal->shared_pending.signal, si->cpt_sigpending); +diff --git a/kernel/cpt/rst_tty.c b/kernel/cpt/rst_tty.c +index f6d90aa..48bc4ce 100644 +--- a/kernel/cpt/rst_tty.c ++++ b/kernel/cpt/rst_tty.c +@@ -350,7 +350,9 @@ int rst_tty_jobcontrol(struct cpt_context *ctx) + if (obj) { + struct tty_struct *stty = obj->o_obj; + if ((int)pibuf->cpt_pgrp > 0) { +- stty->pgrp = alloc_vpid_safe(pibuf->cpt_pgrp); ++ rcu_read_lock(); ++ stty->pgrp = get_pid(alloc_vpid_safe(pibuf->cpt_pgrp)); ++ rcu_read_unlock(); + if (!stty->pgrp) + dprintk_ctx("unknown tty pgrp %d\n", pibuf->cpt_pgrp); + } else if (pibuf->cpt_pgrp) { +@@ -364,7 +366,10 @@ int rst_tty_jobcontrol(struct cpt_context *ctx) + } + if ((int)pibuf->cpt_session > 0) { + struct pid *sess; +- sess = alloc_vpid_safe(pibuf->cpt_session); ++ ++ rcu_read_lock(); ++ sess = get_pid(alloc_vpid_safe(pibuf->cpt_session)); ++ rcu_read_unlock(); + if (!sess) { + dprintk_ctx("unknown tty session %d\n", pibuf->cpt_session); + } else if (!stty->session) { +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0078-vlan-fix-after-netns.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0078-vlan-fix-after-netns.patch @@ -0,0 +1,203 @@ +commit beee05115ef107e73bb6e7eef7dce9532caf0687 +Author: Alexey Dobriyan +Date: Tue May 20 16:42:16 2008 +0400 + + VLAN: fix rmmod 8021q with vlan interface setup + +diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c +index b4c8a23..c356a24 100644 +--- a/net/8021q/vlan.c ++++ b/net/8021q/vlan.c +@@ -21,6 +21,7 @@ + #include /* for copy_from_user */ + #include + #include ++#include + #include + #include + #include +@@ -231,8 +232,9 @@ static void vlan_group_free(struct vlan_group *grp) + kfree(grp); + } + +-static struct vlan_group *vlan_group_alloc(int ifindex) ++static struct vlan_group *vlan_group_alloc(struct net_device *real_dev) + { ++ int ifindex = real_dev->ifindex; + struct vlan_group *grp; + unsigned int size; + unsigned int i; +@@ -250,6 +252,7 @@ static struct vlan_group *vlan_group_alloc(int ifindex) + } + + grp->real_dev_ifindex = ifindex; ++ grp->owner = get_ve(real_dev->owner_env); + hlist_add_head_rcu(&grp->hlist, + &vlan_group_hash[vlan_grp_hashfn(ifindex)]); + return grp; +@@ -508,7 +511,7 @@ int register_vlan_dev(struct net_device *dev) + + grp = __vlan_find_group(real_dev->ifindex, real_dev->owner_env); + if (!grp) { +- ngrp = grp = vlan_group_alloc(real_dev->ifindex); ++ ngrp = grp = vlan_group_alloc(real_dev); + if (!grp) + return -ENOBUFS; + } +@@ -601,6 +604,7 @@ static int register_vlan_device(struct net_device *real_dev, + if (new_dev == NULL) + return -ENOBUFS; + ++ new_dev->nd_net = get_exec_env()->ve_ns->net_ns; + /* need 4 bytes for extra VLAN header info, + * hope the underlying device can handle it. + */ +@@ -802,7 +806,7 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg) + case GET_VLAN_REALDEV_NAME_CMD: + case GET_VLAN_VID_CMD: + err = -ENODEV; +- dev = __dev_get_by_name(&init_net, args.device1); ++ dev = __dev_get_by_name(net, args.device1); + if (!dev) + goto out; + +diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c +index 1493b9e..800da47 100644 +--- a/net/8021q/vlan_dev.c ++++ b/net/8021q/vlan_dev.c +@@ -122,11 +122,6 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, + unsigned short vlan_TCI; + __be16 proto; + +- if (dev->nd_net != &init_net) { +- kfree_skb(skb); +- return -1; +- } +- + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) + return -1; + +diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c +index 0996185..cb74c5f 100644 +--- a/net/8021q/vlan_netlink.c ++++ b/net/8021q/vlan_netlink.c +@@ -113,7 +113,7 @@ static int vlan_newlink(struct net_device *dev, + + if (!tb[IFLA_LINK]) + return -EINVAL; +- real_dev = __dev_get_by_index(&init_net, nla_get_u32(tb[IFLA_LINK])); ++ real_dev = __dev_get_by_index(dev->nd_net, nla_get_u32(tb[IFLA_LINK])); + if (!real_dev) + return -ENODEV; + +diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c +index af38076..1207c21 100644 +--- a/net/8021q/vlanproc.c ++++ b/net/8021q/vlanproc.c +@@ -23,6 +23,7 @@ + #include + #include /* kmalloc(), kfree() */ + #include ++#include + #include /* inline mem*, str* functions */ + #include /* __initfunc et al. */ + #include /* htons(), etc. */ +@@ -79,7 +80,24 @@ static const struct seq_operations vlan_seq_ops = { + + static int vlan_seq_open(struct inode *inode, struct file *file) + { +- return seq_open(file, &vlan_seq_ops); ++ struct seq_file *m; ++ int rv; ++ ++ rv = seq_open(file, &vlan_seq_ops); ++ if (rv < 0) ++ return rv; ++ m = file->private_data; ++ m->private = get_proc_net(inode); ++ return 0; ++} ++ ++static int vlan_seq_release(struct inode *inode, struct file *file) ++{ ++ struct seq_file *m = file->private_data; ++ struct net *net = m->private; ++ ++ put_net(net); ++ return seq_release(inode, file); + } + + static const struct file_operations vlan_fops = { +@@ -87,7 +105,7 @@ static const struct file_operations vlan_fops = { + .open = vlan_seq_open, + .read = seq_read, + .llseek = seq_lseek, +- .release = seq_release, ++ .release = vlan_seq_release, + }; + + /* +@@ -148,11 +166,13 @@ static const char *vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = { + + void vlan_proc_cleanup(void) + { ++ struct net *net = get_exec_env()->ve_ns->net_ns; ++ + if (proc_vlan_conf) + remove_proc_entry(name_conf, proc_vlan_dir); + + if (proc_vlan_dir) +- proc_net_remove(&init_net, name_root); ++ proc_net_remove(net, name_root); + + /* Dynamically added entries should be cleaned up as their vlan_device + * is removed, so we should not have to take care of it here... +@@ -165,8 +185,11 @@ void vlan_proc_cleanup(void) + + int vlan_proc_init(void) + { +- proc_vlan_dir = proc_mkdir(name_root, init_net.proc_net); ++ struct net *net = get_exec_env()->ve_ns->net_ns; ++ ++ proc_vlan_dir = proc_mkdir(name_root, net->proc_net); + if (proc_vlan_dir) { ++ proc_vlan_dir->data = net; + proc_vlan_conf = create_proc_entry(name_conf, + S_IFREG|S_IRUSR|S_IWUSR, + proc_vlan_dir); +@@ -254,6 +277,7 @@ static inline int is_vlan_dev(struct net_device *dev) + /* start read of /proc/net/vlan/config */ + static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) + { ++ struct net *net = seq->private; + struct net_device *dev; + loff_t i = 1; + +@@ -262,7 +286,7 @@ static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) + if (*pos == 0) + return SEQ_START_TOKEN; + +- for_each_netdev(&init_net, dev) { ++ for_each_netdev(net, dev) { + if (!is_vlan_dev(dev)) + continue; + +@@ -275,15 +299,16 @@ static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) + + static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) + { ++ struct net *net = seq->private; + struct net_device *dev; + + ++*pos; + + dev = (struct net_device *)v; + if (v == SEQ_START_TOKEN) +- dev = net_device_entry(&init_net.dev_base_head); ++ dev = net_device_entry(&net->dev_base_head); + +- for_each_netdev_continue(&init_net, dev) { ++ for_each_netdev_continue(net, dev) { + if (!is_vlan_dev(dev)) + continue; + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0061-UBC-fix-use-after-free-in-dcache-accounting.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0061-UBC-fix-use-after-free-in-dcache-accounting.patch @@ -0,0 +1,47 @@ +From e6c66d4324baffd63b43c39f9100453ae3889562 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 7 Apr 2008 15:20:16 +0400 +Subject: [PATCH 60/67] UBC: fix use-after-free in dcache accounting + +After ->d_count is decremented and dcache_lock is dropped dentry can +dissapear at any moment, so we can't start uncharging from it to root. +--- + fs/dcache.c | 15 +++++++++++---- + 1 files changed, 11 insertions(+), 4 deletions(-) + +diff --git a/fs/dcache.c b/fs/dcache.c +index f32cef2..09fdd5e 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -185,9 +185,16 @@ static void dput_recursive(struct dentry *dentry) + unsigned long d_ubsize; + + repeat: +- if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock)) { +- ub_dentry_uncharge(dentry); +- goto out_preempt; ++ if (unlikely(ub_dentry_on)) { ++ spin_lock(&dcache_lock); ++ if (!atomic_dec_and_test(&dentry->d_count)) { ++ ub_dentry_uncharge_locked(dentry); ++ spin_unlock(&dcache_lock); ++ goto out_preempt; ++ } ++ } else { ++ if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock)) ++ goto out_preempt; + } + + spin_lock(&dentry->d_lock); +@@ -232,7 +239,7 @@ kill_it: + d_ubsize = dentry->dentry_bc.d_ubsize; + dentry = d_kill(dentry); + preempt_disable(); +- if (ub_dentry_on) { ++ if (unlikely(ub_dentry_on)) { + uncharge_dcache(ub, d_ubsize); + put_beancounter(ub); + } +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0040-Backport-modules-warn-about-suspicious-return-valu.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0040-Backport-modules-warn-about-suspicious-return-valu.patch @@ -0,0 +1,64 @@ +From 0812a8a04f802de46e47f2623cf3114116174283 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Mon, 17 Mar 2008 17:08:19 +0300 +Subject: [PATCH 40/48] Backport "modules: warn about suspicious return values from module's ->init() hook" + +commit e24e2e64c468c8060bb7173abecdf11d00ed5751 +Author: Alexey Dobriyan +Date: Mon Mar 10 11:43:53 2008 -0700 + + modules: warn about suspicious return values from module's ->init() hook + + Return value convention of module's init functions is 0/-E. Sometimes, + e.g. during forward-porting mistakes happen and buggy module created, + where result of comparison "workqueue != NULL" is propagated all the way up + to sys_init_module. What happens is that some other module created + workqueue in question, our module created it again and module was + successfully loaded. + + Or it could be some other bug. + + Let's make such mistakes much more visible. In retrospective, such + messages would noticeably shorten some of my head-scratching sessions. + + Note, that dump_stack() is just a way to get attention from user. Sample + message: + + sys_init_module: 'foo'->init suspiciously returned 1, it should follow 0/-E convention + sys_init_module: loading module anyway... + Pid: 4223, comm: modprobe Not tainted 2.6.24-25f666300625d894ebe04bac2b4b3aadb907c861 #5 + + Call Trace: + [] sys_init_module+0xe5/0x1d0 + [] system_call_after_swapgs+0x7b/0x80 + + Signed-off-by: Alexey Dobriyan + Cc: Rusty Russell + Signed-off-by: Andrew Morton + Signed-off-by: Linus Torvalds +--- + kernel/module.c | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/kernel/module.c b/kernel/module.c +index ebc0e03..d5bf278 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2135,6 +2135,14 @@ sys_init_module(void __user *umod, + mutex_unlock(&module_mutex); + return ret; + } ++ if (ret > 0) { ++ printk(KERN_WARNING "%s: '%s'->init suspiciously returned %d, " ++ "it should follow 0/-E convention\n" ++ KERN_WARNING "%s: loading module anyway...\n", ++ __func__, mod->name, ret, ++ __func__); ++ dump_stack(); ++ } + + /* Now it's a first class citizen! */ + mutex_lock(&module_mutex); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0096-VE-do-open-check-perm.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0096-VE-do-open-check-perm.patch @@ -0,0 +1,42 @@ +From 91657bd52f0b6e9d1b655bc43c125da3b9f36fe7 Mon Sep 17 00:00:00 2001 +From: Marat Stanichenko +Date: Mon, 30 Jun 2008 13:48:49 +0400 +Subject: [PATCH 096/103] VE do open check perm + +Don't check permissions in do_open if we already have checked them. +We might come into do_open from __blkdev_get which is called from do_open. +This means that we have already passed the previous test get_device_perms_ve() +and allowed an access to device. +So we don't call get_device_perms_ve() twice because we mightn't pass the test. +--- + fs/block_dev.c | 14 ++++++++++---- + 1 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/fs/block_dev.c b/fs/block_dev.c +index 1ed4a29..f1947df 100644 +--- a/fs/block_dev.c ++++ b/fs/block_dev.c +@@ -1128,10 +1128,16 @@ static int do_open(struct block_device *bdev, struct file *file, int for_part) + int ret; + int part; + +- ret = get_device_perms_ve(S_IFBLK, bdev->bd_dev, +- file->f_mode & (FMODE_READ | FMODE_WRITE)); +- if (ret) +- return ret; ++ /* ++ * We don't check permissions if we already have checked them ++ * and come here from __blkdev_get which is called below ++ */ ++ if (!for_part) { ++ ret = get_device_perms_ve(S_IFBLK, bdev->bd_dev, ++ file->f_mode & (FMODE_READ | FMODE_WRITE)); ++ if (ret) ++ return ret; ++ } + + ret = -ENXIO; + file->f_mapping = bdev->bd_inode->i_mapping; +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0063-CPT-fix-epoll-checkpointing.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0063-CPT-fix-epoll-checkpointing.patch @@ -0,0 +1,112 @@ +From b9f72ff552da04eb5f741f0a7d81c24affa5ce55 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Thu, 10 Apr 2008 18:35:29 +0400 +Subject: [PATCH 63/67] CPT: fix epoll checkpointing + +eventpoll inodes are created via anon_inodes infrastructure which means they +all have the same magic in superblock: ANON_INODE_FS_MAGIC. Filtering epoll +inodes by magic can't work. So, do it by looking at file->f_op. +--- + kernel/cpt/cpt_epoll.c | 2 -- + kernel/cpt/cpt_files.c | 12 ++++-------- + kernel/cpt/cpt_files.h | 1 + + kernel/cpt/cpt_fsmagic.h | 1 - + kernel/cpt/rst_epoll.c | 1 - + 5 files changed, 5 insertions(+), 12 deletions(-) + +diff --git a/kernel/cpt/cpt_epoll.c b/kernel/cpt/cpt_epoll.c +index 68387e2..81d2b98 100644 +--- a/kernel/cpt/cpt_epoll.c ++++ b/kernel/cpt/cpt_epoll.c +@@ -38,8 +38,6 @@ + #include "cpt_fsmagic.h" + #include "cpt_syscalls.h" + +-extern struct file_operations eventpoll_fops; +- + int cpt_dump_epolldev(cpt_object_t *obj, cpt_context_t *ctx) + { + int err = 0; +diff --git a/kernel/cpt/cpt_files.c b/kernel/cpt/cpt_files.c +index 582bda4..6b3885e 100644 +--- a/kernel/cpt/cpt_files.c ++++ b/kernel/cpt/cpt_files.c +@@ -511,7 +511,7 @@ static int dump_one_file(cpt_object_t *obj, struct file *file, cpt_context_t *ct + if (file->f_flags&FASYNC) + v->cpt_fown_fd = cpt_socket_fasync(file, ctx); + } +- if (file->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_EPOLL) { ++ if (file->f_op == &eventpoll_fops) { + v->cpt_priv = file->f_dentry->d_inode->i_ino; + v->cpt_lflags |= CPT_DENTRY_EPOLL; + } +@@ -942,11 +942,7 @@ static int dump_one_inode(struct file *file, struct dentry *d, + !cpt_replaced(d, mnt, ctx)) + dump_it = 1; + if (!S_ISREG(ino->i_mode) && !S_ISDIR(ino->i_mode)) { +- /* One more bug in epoll: invalid inode mode. +- * What a load of crap... +- */ +- if (ino->i_sb->s_magic == FSMAGIC_EPOLL && +- (ino->i_mode & S_IFMT) == 0) ++ if (file->f_op == &eventpoll_fops) + return 0; + dump_it = 1; + } +@@ -1059,7 +1055,7 @@ int cpt_dump_files(struct cpt_context *ctx) + + if ((err = dump_one_file(obj, file, ctx)) != 0) + return err; +- if (file->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_EPOLL) ++ if (file->f_op == &eventpoll_fops) + epoll_nr++; + if (file->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_INOTIFY) + inotify_nr++; +@@ -1070,7 +1066,7 @@ int cpt_dump_files(struct cpt_context *ctx) + cpt_open_section(ctx, CPT_SECT_EPOLL); + for_each_object(obj, CPT_OBJ_FILE) { + struct file *file = obj->o_obj; +- if (file->f_dentry->d_inode->i_sb->s_magic == FSMAGIC_EPOLL) { ++ if (file->f_op == &eventpoll_fops) { + int err; + if ((err = cpt_dump_epolldev(obj, ctx)) != 0) + return err; +diff --git a/kernel/cpt/cpt_files.h b/kernel/cpt/cpt_files.h +index a4cb0fd..b08afea 100644 +--- a/kernel/cpt/cpt_files.h ++++ b/kernel/cpt/cpt_files.h +@@ -37,6 +37,7 @@ int rst_tty_jobcontrol(struct cpt_context *ctx); + void rst_flush_filejobs(struct cpt_context *); + int rst_do_filejobs(struct cpt_context *); + ++extern struct file_operations eventpoll_fops; + int rst_eventpoll(struct cpt_context *); + struct file *cpt_open_epolldev(struct cpt_file_image *fi, + unsigned flags, +diff --git a/kernel/cpt/cpt_fsmagic.h b/kernel/cpt/cpt_fsmagic.h +index 45c4fb8..142e539 100644 +--- a/kernel/cpt/cpt_fsmagic.h ++++ b/kernel/cpt/cpt_fsmagic.h +@@ -5,7 +5,6 @@ + #define FSMAGIC_SOCKFS 0x534F434B + #define FSMAGIC_PFMFS 0xa0b4d889 + #define FSMAGIC_BDEV 0x62646576 +-#define FSMAGIC_EPOLL 0x03111965 + #define FSMAGIC_FUTEX 0x0BAD1DEA + #define FSMAGIC_INOTIFY 0x2BAD1DEA + #define FSMAGIC_MQUEUE 0x19800202 +diff --git a/kernel/cpt/rst_epoll.c b/kernel/cpt/rst_epoll.c +index 913ceab..0ac4cae 100644 +--- a/kernel/cpt/rst_epoll.c ++++ b/kernel/cpt/rst_epoll.c +@@ -39,7 +39,6 @@ + #include "cpt_syscalls.h" + + /* Those funcations are static in fs/eventpoll.c */ +-extern struct file_operations eventpoll_fops; + extern int ep_insert(struct eventpoll *ep, struct epoll_event *event, + struct file *tfile, int fd); + extern struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd); +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0027-NETFILTER-move-init-functions-after-fini-functions.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0027-NETFILTER-move-init-functions-after-fini-functions.patch @@ -0,0 +1,331 @@ +From 69e391057ffeb889138078c85666c2db4bd9c182 Mon Sep 17 00:00:00 2001 +From: Alexey Dobriyan +Date: Fri, 14 Mar 2008 15:54:13 +0300 +Subject: [PATCH 27/48] NETFILTER: move init functions after fini functions + +This is getting incosistent across netfilter changes, so make it consistent. +--- + net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 20 ++++++------ + net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 32 ++++++++++---------- + net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 20 ++++++------ + net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 22 +++++++------- + net/netfilter/nf_conntrack_proto_generic.c | 28 +++++++++--------- + net/netfilter/nf_conntrack_proto_tcp.c | 38 ++++++++++++------------ + net/netfilter/nf_conntrack_proto_udp.c | 38 ++++++++++++------------ + 7 files changed, 99 insertions(+), 99 deletions(-) + +Index: kernel/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 2008-11-24 15:57:32.000000000 +0100 ++++ kernel/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 2008-11-24 15:57:35.000000000 +0100 +@@ -429,16 +429,6 @@ + + #ifdef CONFIG_VE_IPTABLES + #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) +-static void nf_ct_proto_ipv4_sysctl_cleanup(void) +-{ +- if (!ve_is_super(get_exec_env())) { +- free_sysctl_clone(ve_nf_conntrack_l3proto_ipv4->ctl_table); +- ve_nf_conntrack_l3proto_ipv4->ctl_table = NULL; +- kfree(ve_nf_conntrack_l3proto_ipv4); +- ve_nf_conntrack_l3proto_ipv4 = NULL; +- } +-} +- + static int nf_ct_proto_ipv4_sysctl_init(void) + { + struct nf_conntrack_l3proto *ipv4 = ve_nf_conntrack_l3proto_ipv4; +@@ -456,6 +446,16 @@ + + return 0; + } ++ ++static void nf_ct_proto_ipv4_sysctl_cleanup(void) ++{ ++ if (!ve_is_super(get_exec_env())) { ++ free_sysctl_clone(ve_nf_conntrack_l3proto_ipv4->ctl_table); ++ ve_nf_conntrack_l3proto_ipv4->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l3proto_ipv4); ++ ve_nf_conntrack_l3proto_ipv4 = NULL; ++ } ++} + #else + static inline int nf_ct_proto_ipv4_sysctl_init(void) + { +Index: kernel/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +=================================================================== +--- kernel.orig/net/ipv4/netfilter/nf_conntrack_proto_icmp.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv4/netfilter/nf_conntrack_proto_icmp.c 2008-11-24 15:57:35.000000000 +0100 +@@ -337,22 +337,6 @@ + }; + + #if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) +-void nf_ct_proto_icmp_sysctl_cleanup(void) +-{ +- if (!ve_is_super(get_exec_env())) { +-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT +- free_sysctl_clone( +- ve_nf_conntrack_l4proto_icmp->ctl_compat_table); +- ve_nf_conntrack_l4proto_icmp->ctl_compat_table = NULL; +-#endif +- free_sysctl_clone(ve_nf_conntrack_l4proto_icmp->ctl_table); +- ve_nf_conntrack_l4proto_icmp->ctl_table = NULL; +- kfree(ve_nf_conntrack_l4proto_icmp); +- ve_nf_conntrack_l4proto_icmp = NULL; +- } +-} +-EXPORT_SYMBOL(nf_ct_proto_icmp_sysctl_cleanup); +- + int nf_ct_proto_icmp_sysctl_init(void) + { + struct nf_conntrack_l4proto *icmp; +@@ -397,4 +381,20 @@ + return -ENOMEM; + } + EXPORT_SYMBOL(nf_ct_proto_icmp_sysctl_init); ++ ++void nf_ct_proto_icmp_sysctl_cleanup(void) ++{ ++ if (!ve_is_super(get_exec_env())) { ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ free_sysctl_clone( ++ ve_nf_conntrack_l4proto_icmp->ctl_compat_table); ++ ve_nf_conntrack_l4proto_icmp->ctl_compat_table = NULL; ++#endif ++ free_sysctl_clone(ve_nf_conntrack_l4proto_icmp->ctl_table); ++ ve_nf_conntrack_l4proto_icmp->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l4proto_icmp); ++ ve_nf_conntrack_l4proto_icmp = NULL; ++ } ++} ++EXPORT_SYMBOL(nf_ct_proto_icmp_sysctl_cleanup); + #endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ +Index: kernel/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +=================================================================== +--- kernel.orig/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c 2008-11-24 15:57:35.000000000 +0100 +@@ -396,16 +396,6 @@ + MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI "); + + #if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) +-static void nf_ct_proto_ipv6_sysctl_cleanup(void) +-{ +- if (!ve_is_super(get_exec_env())) { +- free_sysctl_clone(ve_nf_conntrack_l3proto_ipv6->ctl_table); +- ve_nf_conntrack_l3proto_ipv6->ctl_table = NULL; +- kfree(ve_nf_conntrack_l3proto_ipv6); +- ve_nf_conntrack_l3proto_ipv6 = NULL; +- } +-} +- + static int nf_ct_proto_ipv6_sysctl_init(void) + { + struct nf_conntrack_l3proto *ipv6; +@@ -441,6 +431,16 @@ + no_mem_ct: + return -ENOMEM; + } ++ ++static void nf_ct_proto_ipv6_sysctl_cleanup(void) ++{ ++ if (!ve_is_super(get_exec_env())) { ++ free_sysctl_clone(ve_nf_conntrack_l3proto_ipv6->ctl_table); ++ ve_nf_conntrack_l3proto_ipv6->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l3proto_ipv6); ++ ve_nf_conntrack_l3proto_ipv6 = NULL; ++ } ++} + #endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ + + int init_nf_ct_l3proto_ipv6(void) +Index: kernel/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +=================================================================== +--- kernel.orig/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c 2008-11-24 15:57:35.000000000 +0100 +@@ -297,17 +297,6 @@ + }; + + #if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) +-void nf_ct_proto_icmpv6_sysctl_cleanup(void) +-{ +- if (!ve_is_super(get_exec_env())) { +- free_sysctl_clone(ve_nf_conntrack_l4proto_icmpv6->ctl_table); +- ve_nf_conntrack_l4proto_icmpv6->ctl_table = NULL; +- kfree(ve_nf_conntrack_l4proto_icmpv6); +- ve_nf_conntrack_l4proto_icmpv6 = NULL; +- } +-} +-EXPORT_SYMBOL(nf_ct_proto_icmpv6_sysctl_cleanup); +- + int nf_ct_proto_icmpv6_sysctl_init(void) + { + struct nf_conntrack_l4proto *icmp6; +@@ -340,4 +329,15 @@ + return -ENOMEM; + } + EXPORT_SYMBOL(nf_ct_proto_icmpv6_sysctl_init); ++ ++void nf_ct_proto_icmpv6_sysctl_cleanup(void) ++{ ++ if (!ve_is_super(get_exec_env())) { ++ free_sysctl_clone(ve_nf_conntrack_l4proto_icmpv6->ctl_table); ++ ve_nf_conntrack_l4proto_icmpv6->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l4proto_icmpv6); ++ ve_nf_conntrack_l4proto_icmpv6 = NULL; ++ } ++} ++EXPORT_SYMBOL(nf_ct_proto_icmpv6_sysctl_cleanup); + #endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ +Index: kernel/net/netfilter/nf_conntrack_proto_generic.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_proto_generic.c 2008-11-24 15:57:33.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_proto_generic.c 2008-11-24 15:57:35.000000000 +0100 +@@ -118,20 +118,6 @@ + }; + + #if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) +-void nf_ct_proto_generic_sysctl_cleanup(void) +-{ +- if (!ve_is_super(get_exec_env())) { +-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT +- free_sysctl_clone( +- ve_nf_conntrack_l4proto_generic->ctl_compat_table); +- ve_nf_conntrack_l4proto_generic->ctl_compat_table = NULL; +-#endif +- free_sysctl_clone(ve_nf_conntrack_l4proto_generic->ctl_table); +- ve_nf_conntrack_l4proto_generic->ctl_table = NULL; +- } +-} +-EXPORT_SYMBOL(nf_ct_proto_generic_sysctl_cleanup); +- + int nf_ct_proto_generic_sysctl_init(void) + { + struct nf_conntrack_l4proto *generic; +@@ -175,4 +161,18 @@ + return -ENOMEM; + } + EXPORT_SYMBOL(nf_ct_proto_generic_sysctl_init); ++ ++void nf_ct_proto_generic_sysctl_cleanup(void) ++{ ++ if (!ve_is_super(get_exec_env())) { ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ free_sysctl_clone( ++ ve_nf_conntrack_l4proto_generic->ctl_compat_table); ++ ve_nf_conntrack_l4proto_generic->ctl_compat_table = NULL; ++#endif ++ free_sysctl_clone(ve_nf_conntrack_l4proto_generic->ctl_table); ++ ve_nf_conntrack_l4proto_generic->ctl_table = NULL; ++ } ++} ++EXPORT_SYMBOL(nf_ct_proto_generic_sysctl_cleanup); + #endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ +Index: kernel/net/netfilter/nf_conntrack_proto_tcp.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_proto_tcp.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_proto_tcp.c 2008-11-24 15:57:35.000000000 +0100 +@@ -1430,25 +1430,6 @@ + EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp6); + + #if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) +-void nf_ct_proto_tcp_sysctl_cleanup(void) +-{ +- if (!ve_is_super(get_exec_env())) { +-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT +- free_sysctl_clone( +- ve_nf_conntrack_l4proto_tcp4->ctl_compat_table); +- ve_nf_conntrack_l4proto_tcp4->ctl_compat_table = NULL; +-#endif +- free_sysctl_clone(ve_nf_conntrack_l4proto_tcp4->ctl_table); +- ve_nf_conntrack_l4proto_tcp4->ctl_table = NULL; +- kfree(ve_nf_conntrack_l4proto_tcp4); +- ve_nf_conntrack_l4proto_tcp4 = NULL; +- +- kfree(ve_nf_conntrack_l4proto_tcp6); +- ve_nf_conntrack_l4proto_tcp6 = NULL; +- } +-} +-EXPORT_SYMBOL(nf_ct_proto_tcp_sysctl_cleanup); +- + int nf_ct_proto_tcp_sysctl_init(void) + { + struct nf_conntrack_l4proto *tcp4, *tcp6; +@@ -1541,5 +1522,24 @@ + return -ENOMEM; + } + EXPORT_SYMBOL(nf_ct_proto_tcp_sysctl_init); ++ ++void nf_ct_proto_tcp_sysctl_cleanup(void) ++{ ++ if (!ve_is_super(get_exec_env())) { ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ free_sysctl_clone( ++ ve_nf_conntrack_l4proto_tcp4->ctl_compat_table); ++ ve_nf_conntrack_l4proto_tcp4->ctl_compat_table = NULL; ++#endif ++ free_sysctl_clone(ve_nf_conntrack_l4proto_tcp4->ctl_table); ++ ve_nf_conntrack_l4proto_tcp4->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l4proto_tcp4); ++ ve_nf_conntrack_l4proto_tcp4 = NULL; ++ ++ kfree(ve_nf_conntrack_l4proto_tcp6); ++ ve_nf_conntrack_l4proto_tcp6 = NULL; ++ } ++} ++EXPORT_SYMBOL(nf_ct_proto_tcp_sysctl_cleanup); + #endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ + +Index: kernel/net/netfilter/nf_conntrack_proto_udp.c +=================================================================== +--- kernel.orig/net/netfilter/nf_conntrack_proto_udp.c 2008-11-24 15:47:46.000000000 +0100 ++++ kernel/net/netfilter/nf_conntrack_proto_udp.c 2008-11-24 15:57:35.000000000 +0100 +@@ -241,25 +241,6 @@ + EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6); + + #if defined(CONFIG_VE_IPTABLES) && defined(CONFIG_SYSCTL) +-void nf_ct_proto_udp_sysctl_cleanup(void) +-{ +- if (!ve_is_super(get_exec_env())) { +-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT +- free_sysctl_clone( +- ve_nf_conntrack_l4proto_udp4->ctl_compat_table); +- ve_nf_conntrack_l4proto_udp4->ctl_compat_table = NULL; +-#endif +- free_sysctl_clone(ve_nf_conntrack_l4proto_udp4->ctl_table); +- ve_nf_conntrack_l4proto_udp4->ctl_table = NULL; +- kfree(ve_nf_conntrack_l4proto_udp4); +- ve_nf_conntrack_l4proto_udp4 = NULL; +- +- kfree(ve_nf_conntrack_l4proto_udp6); +- ve_nf_conntrack_l4proto_udp6 = NULL; +- } +-} +-EXPORT_SYMBOL(nf_ct_proto_udp_sysctl_cleanup); +- + int nf_ct_proto_udp_sysctl_init(void) + { + struct nf_conntrack_l4proto *udp4, *udp6; +@@ -323,4 +304,23 @@ + return -ENOMEM; + } + EXPORT_SYMBOL(nf_ct_proto_udp_sysctl_init); ++ ++void nf_ct_proto_udp_sysctl_cleanup(void) ++{ ++ if (!ve_is_super(get_exec_env())) { ++#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT ++ free_sysctl_clone( ++ ve_nf_conntrack_l4proto_udp4->ctl_compat_table); ++ ve_nf_conntrack_l4proto_udp4->ctl_compat_table = NULL; ++#endif ++ free_sysctl_clone(ve_nf_conntrack_l4proto_udp4->ctl_table); ++ ve_nf_conntrack_l4proto_udp4->ctl_table = NULL; ++ kfree(ve_nf_conntrack_l4proto_udp4); ++ ve_nf_conntrack_l4proto_udp4 = NULL; ++ ++ kfree(ve_nf_conntrack_l4proto_udp6); ++ ve_nf_conntrack_l4proto_udp6 = NULL; ++ } ++} ++EXPORT_SYMBOL(nf_ct_proto_udp_sysctl_cleanup); + #endif /* CONFIG_VE_IPTABLES && CONFIG_SYSCTL */ --- linux-2.6.24.orig/debian/binary-custom.d/openvz/patchset/0005-Fix-proc-compilation.patch +++ linux-2.6.24/debian/binary-custom.d/openvz/patchset/0005-Fix-proc-compilation.patch @@ -0,0 +1,42 @@ +From da23c1831f33ce142b38534f8e54f985f651707c Mon Sep 17 00:00:00 2001 +From: Peter Volkov +Date: Mon, 3 Mar 2008 12:52:27 +0300 +Subject: [PATCH 05/48] Fix proc compilation + +fs/proc/generic.c: In function 'xlate_proc_loc_name': +fs/proc/generic.c:330: error: implicit declaration of function 'get_exec_env' +fs/proc/generic.c:330: error: invalid type argument of '->' +fs/proc/generic.c: In function 'proc_lookup': +fs/proc/generic.c:516: error: implicit declaration of function 've_is_super' +--- + fs/proc/generic.c | 1 + + fs/proc/proc_tty.c | 1 + + 2 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/fs/proc/generic.c b/fs/proc/generic.c +index ff8484e..2260a20 100644 +--- a/fs/proc/generic.c ++++ b/fs/proc/generic.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + + #include "internal.h" +diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c +index a5e8cd9..a3da5a0 100644 +--- a/fs/proc/proc_tty.c ++++ b/fs/proc/proc_tty.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + static int tty_ldiscs_read_proc(char *page, char **start, off_t off, +-- +1.5.4.3 + --- linux-2.6.24.orig/debian/binary-custom.d/rt/rules +++ linux-2.6.24/debian/binary-custom.d/rt/rules @@ -0,0 +1 @@ +# Nothing special here --- linux-2.6.24.orig/debian/binary-custom.d/rt/vars +++ linux-2.6.24/debian/binary-custom.d/rt/vars @@ -0,0 +1,7 @@ +arch="i386 amd64" +supported="Generic" +target="RT kernel" +desc="Ingo Molnar's full real time preemption patch (2.6.24.7-rt27)" +bootloader="lilo (>= 19.1) | grub" +provides="kvm-api-4, redhat-cluster-modules" +section_image="universe/base" --- linux-2.6.24.orig/debian/binary-custom.d/rt/config.amd64 +++ linux-2.6.24/debian/binary-custom.d/rt/config.amd64 @@ -0,0 +1,3680 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.24.6 +# Mon Feb 23 16:04:01 2009 +# +CONFIG_64BIT=y +# CONFIG_X86_32 is not set +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_SEMAPHORE_SLEEPERS=y +CONFIG_MMU=y +CONFIG_ZONE_DMA=y +# CONFIG_QUICKLIST is not set +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_DMI=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ASM_SEMAPHORES=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_ARCH_SUPPORTS_OPROFILE=y +CONFIG_ZONE_DMA32=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_X86_HT=y +# CONFIG_KTIME_SCALAR is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-4.6-generic" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_TREE=y +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_NS=y +CONFIG_CPUSETS=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_FAIR_USER_SCHED is not set +CONFIG_FAIR_CGROUP_SCHED=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_PROC_PID_CPUSET=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_RADIX_TREE_CONCURRENT=y +CONFIG_RADIX_TREE_OPTIMISTIC=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_BLOCK_COMPAT=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_LSM_MMAP_MIN_ADDR=0 + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_PREEMPT_NOTIFIERS=y + +# +# Processor type and features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_SMP=y +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_X86_VSMP is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MEFFICEON is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_L1_CACHE_BYTES=128 +CONFIG_X86_INTERNODE_CACHE_BYTES=128 +CONFIG_X86_CMPXCHG=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_GOOD_APIC=y +CONFIG_X86_TSC=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_GART_IOMMU=y +CONFIG_CALGARY_IOMMU=y +CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y +CONFIG_SWIOTLB=y +CONFIG_NR_CPUS=8 +# CONFIG_SCHED_SMT is not set +CONFIG_SCHED_MC=y +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT_DESKTOP is not set +CONFIG_PREEMPT_RT=y +CONFIG_PREEMPT=y +CONFIG_PREEMPT_SOFTIRQS=y +CONFIG_PREEMPT_HARDIRQS=y +CONFIG_PREEMPT_BKL=y +# CONFIG_CLASSIC_RCU is not set +CONFIG_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU_BOOST=y +CONFIG_RCU_TRACE=m +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_MCE=y +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_MICROCODE=m +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m +CONFIG_NUMA=y +CONFIG_K8_NUMA=y +CONFIG_X86_64_ACPI_NUMA=y +# CONFIG_NUMA_EMU is not set +CONFIG_NODES_SHIFT=6 +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MIGRATION=y +CONFIG_RESOURCES_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_MTRR=y +CONFIG_SECCOMP=y +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR_ALL is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RELOCATABLE=y +CONFIG_PHYSICAL_ALIGN=0x200000 +CONFIG_HOTPLUG_CPU=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y +CONFIG_OUT_OF_LINE_PFN_TO_PAGE=y +CONFIG_HARDIRQS_SW_RESEND=y + +# +# Power management options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +CONFIG_PM=y +CONFIG_PM_LEGACY=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_VERBOSE is not set +CONFIG_PM_TRACE=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SUSPEND=y +CONFIG_PM_DISABLE_CONSOLE=y +CONFIG_HIBERNATION_SMP_POSSIBLE=y +CONFIG_HIBERNATION=y +CONFIG_PM_STD_PARTITION="" +CONFIG_ACPI=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_PROCFS=y +CONFIG_ACPI_PROCFS_POWER=y +CONFIG_ACPI_SYSFS_POWER=y +CONFIG_ACPI_PROC_EVENT=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_VIDEO=m +CONFIG_ACPI_FAN=m +CONFIG_ACPI_DOCK=m +CONFIG_ACPI_BAY=m +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_NUMA=y +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_ACPI_CUSTOM_DSDT_INITRD=y +CONFIG_ACPI_BLACKLIST_YEAR=0 +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y +CONFIG_ACPI_CONTAINER=m +CONFIG_ACPI_SBS=m + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=m +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_POWERNOW_K8=m +CONFIG_X86_POWERNOW_K8_ACPI=y +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +# CONFIG_X86_SPEEDSTEP_LIB is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y + +# +# Bus options (PCI etc.) +# +CONFIG_PCI=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_DOMAINS=y +# CONFIG_DMAR is not set +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_PCIEAER=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_LEGACY=y +# CONFIG_PCI_DEBUG is not set +CONFIG_HT_IRQ=y +CONFIG_ISA_DMA_API=y +CONFIG_K8_NB=y +CONFIG_PCCARD=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA=m +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y +CONFIG_CARDBUS=y + +# +# PC-card bridges +# +CONFIG_YENTA=m +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_PD6729=m +CONFIG_I82092=m +CONFIG_PCCARD_NONSTATIC=m +CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI_FAKE=m +CONFIG_HOTPLUG_PCI_ACPI=m +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m +CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +CONFIG_HOTPLUG_PCI_SHPC=m + +# +# Executable file formats / Emulations +# +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_IA32_EMULATION=y +# CONFIG_IA32_AOUT is not set +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_LRO=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +# CONFIG_DEFAULT_BIC is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_HTCP is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFAULT_RENO=y +CONFIG_DEFAULT_TCP_CONG="reno" +CONFIG_TCP_MD5SIG=y +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_NETLABEL is not set +CONFIG_NETWORK_SECMARK=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m + +# +# IP: Netfilter Configuration +# +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_SIP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_RAW=m + +# +# DECnet: Netfilter Configuration +# +CONFIG_DECNET_NF_GRABULATOR=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_IP_DCCP_ACKVEC=y + +# +# DCCP CCIDs Configuration (EXPERIMENTAL) +# +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +CONFIG_IP_DCCP_TFRC_LIB=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 + +# +# DCCP Kernel Hacking +# +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_NET_DCCPPROBE=m +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +CONFIG_ATM=y +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_DECNET=m +# CONFIG_DECNET_ROUTER is not set +CONFIG_LLC=y +CONFIG_LLC2=m +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RR=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +# CONFIG_NET_CLS_POLICE is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +CONFIG_NET_TCPPROBE=m +CONFIG_HAMRADIO=y + +# +# Packet Radio protocols +# +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_NETROM=m +CONFIG_ROSE=m + +# +# AX.25 network device drivers +# +CONFIG_MKISS=m +CONFIG_6PACK=m +CONFIG_BPQETHER=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BAYCOM_PAR=m +CONFIG_YAM=m +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m +CONFIG_KINGSUN_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KS959_DONGLE=m + +# +# Old SIR device drivers +# + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +CONFIG_WINBOND_FIR=m +CONFIG_SMC_IRCC_FIR=m +CONFIG_ALI_FIR=m +CONFIG_VLSI_FIR=m +CONFIG_VIA_FIR=m +CONFIG_MCS_FIR=m +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_RXKAD=m +CONFIG_FIB_RULES=y + +# +# Wireless +# +CONFIG_CFG80211=m +CONFIG_NL80211=y +CONFIG_WIRELESS_EXT=y +CONFIG_MAC80211=m +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_DEBUGFS=y +# CONFIG_MAC80211_DEBUG is not set +CONFIG_IEEE80211=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_CRYPT_WEP=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +CONFIG_NET_9P=m +CONFIG_NET_9P_FD=m +CONFIG_NET_9P_VIRTIO=m +# CONFIG_NET_9P_DEBUG is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=m +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m +CONFIG_RFD_FTL=m +CONFIG_SSFDC=m +CONFIG_MTD_OOPS=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PNC2000=m +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_TS5500=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_DILNETPC=m +CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000 +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_PLATRAM=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_DATAFLASH=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTD_BLOCK2MTD=m + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCECC=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_IDS=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_2X_PROGRAM=y +CONFIG_MTD_ONENAND_SIM=m + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +CONFIG_MTD_UBI_GLUEBI=y + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_AX88796=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_NOT_PC=y +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_FD=m +CONFIG_PARIDE=m + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_SX8=m +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_VIRTIO_BLK=m +CONFIG_MISC_DEVICES=y +CONFIG_IBM_ASM=m +CONFIG_PHANTOM=m +CONFIG_EEPROM_93CX6=m +CONFIG_SGI_IOC4=m +CONFIG_TIFM_CORE=m +CONFIG_TIFM_7XX1=m +CONFIG_ASUS_LAPTOP=m +CONFIG_FUJITSU_LAPTOP=m +CONFIG_MSI_LAPTOP=m +CONFIG_SONY_LAPTOP=m +CONFIG_SONYPI_COMPAT=y +CONFIG_THINKPAD_ACPI=m +# CONFIG_THINKPAD_ACPI_DEBUG is not set +CONFIG_THINKPAD_ACPI_BAY=y +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_BLK_DEV_IDEACPI=y +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +CONFIG_BLK_DEV_PLATFORM=m +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +CONFIG_BLK_DEV_IDEPNP=y + +# +# PCI IDE chipsets support +# +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_GENERIC is not set +CONFIG_BLK_DEV_OPTI621=m +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI15X3=m +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +CONFIG_BLK_DEV_ATIIXP=m +CONFIG_BLK_DEV_CMD64X=m +# CONFIG_BLK_DEV_TRIFLEX is not set +CONFIG_BLK_DEV_CY82C693=m +# CONFIG_BLK_DEV_CS5520 is not set +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_HPT34X=m +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=m +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_SC1200=m +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +CONFIG_BLK_DEV_NS87415=m +CONFIG_BLK_DEV_PDC202XX_OLD=m +CONFIG_PDC202XX_BURST=y +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +CONFIG_BLK_DEV_TRM290=m +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLK_DEV_TC86C001=m +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=m +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=m +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SAS_ATA=y +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_SCSI_AIC94XX=m +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPR_DUMP is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_ATA=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_ACPI=y +CONFIG_SATA_AHCI=m +CONFIG_SATA_SVW=m +CONFIG_ATA_PIIX=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_PDC_ADMA=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_SX4=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SATA_INIC162X=m +CONFIG_PATA_ACPI=m +# CONFIG_PATA_ALI is not set +CONFIG_PATA_AMD=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +# CONFIG_PATA_CMD640_PCI is not set +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CS5520=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +CONFIG_ATA_GENERIC=m +CONFIG_PATA_HPT366=m +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +CONFIG_PATA_HPT3X3=m +# CONFIG_PATA_HPT3X3_DMA is not set +CONFIG_PATA_IT821X=m +CONFIG_PATA_IT8213=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_NETCELL=m +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PCMCIA=m +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +CONFIG_PATA_PLATFORM=m +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m +CONFIG_DM_MULTIPATH_RDAC=m +CONFIG_DM_MULTIPATH_HP=m +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_SAS=m +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# Controllers +# +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocols +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_I2O=m +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_EXT_ADAPTEC_DMA64=y +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_BUS=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_NETDEVICES=y +CONFIG_NETDEVICES_MULTIQUEUE=y +CONFIG_IFB=m +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_MACVLAN=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_NET_SB1000=m +CONFIG_ARCNET=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_PHYLIB=m + +# +# MII PHY device drivers +# +CONFIG_MARVELL_PHY=m +CONFIG_DAVICOM_PHY=m +CONFIG_QSEMI_PHY=m +CONFIG_LXT_PHY=m +CONFIG_CICADA_PHY=m +CONFIG_VITESSE_PHY=m +CONFIG_SMSC_PHY=m +CONFIG_BROADCOM_PHY=m +CONFIG_ICPLUS_PHY=m +CONFIG_FIXED_PHY=m +# CONFIG_FIXED_MII_10_FDX is not set +# CONFIG_FIXED_MII_100_FDX is not set +CONFIG_FIXED_MII_1000_FDX=y +CONFIG_FIXED_MII_AMNT=1 +CONFIG_MDIO_BITBANG=m +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_ULI526X=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_HP100=m +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_AMD8111_ETH=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_B44=m +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI=y +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +CONFIG_EEPRO100=m +CONFIG_E100=m +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_RHINE_NAPI=y +CONFIG_SC92031=m +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_NETDEV_1000=y +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E1000E=m +CONFIG_IP1000=m +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_SIS190=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SK98LIN is not set +CONFIG_VIA_VELOCITY=m +CONFIG_TIGON3=m +CONFIG_BNX2=m +CONFIG_QLA3XXX=m +CONFIG_ATL1=m +CONFIG_NETDEV_10000=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_IXGBE=m +CONFIG_IXGB=m +# CONFIG_IXGB_NAPI is not set +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +CONFIG_MYRI10GE=m +CONFIG_NETXEN_NIC=m +CONFIG_NIU=m +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_TEHUTI=m +CONFIG_TR=y +CONFIG_IBMOL=m +CONFIG_3C359=m +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +CONFIG_ABYSS=m + +# +# Wireless LAN +# +CONFIG_WLAN_PRE80211=y +CONFIG_STRIP=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_WLAN_80211=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_IPW2100=m +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2200=m +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +# CONFIG_IPW2200_DEBUG is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_CS=m +CONFIG_LIBERTAS_SDIO=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_AIRO=m +CONFIG_HERMES=m +# CONFIG_PLX_HERMES is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_PCI_HERMES is not set +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PRISM54=m +CONFIG_USB_ZD1201=m +CONFIG_RTL8187=m +CONFIG_ADM8211=m +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +CONFIG_P54_PCI=m +# CONFIG_IWLWIFI is not set +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_CS=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_PIO=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +# CONFIG_BCM43XX_PIO_MODE is not set +CONFIG_B43=m +CONFIG_B43_PCI_AUTOSELECT=y +CONFIG_B43_PCICORE_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_LEDS=y +CONFIG_B43_RFKILL=y +CONFIG_B43_DEBUG=y +CONFIG_B43_DMA=y +CONFIG_B43_PIO=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +# CONFIG_B43_PIO_MODE is not set +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_PIO=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_RT2X00=m +CONFIG_RT2X00_LIB=m +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +# CONFIG_RT2X00_DEBUG is not set + +# +# USB Network Adapters +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_WAN=y +CONFIG_LANMEDIA=m +CONFIG_HDLC=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_X25=m +CONFIG_PCI200SYN=m +CONFIG_WANXL=m +CONFIG_PC300=m +CONFIG_PC300_MLPPP=y + +# +# Cyclades-PC300 MLPPP support is disabled. +# + +# +# Refer to the file README.mlppp, provided by PC300 package. +# +# CONFIG_PC300TOO is not set +CONFIG_FARSYNC=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +CONFIG_LAPBETHER=m +CONFIG_X25_ASY=m +CONFIG_SBNI=m +# CONFIG_SBNI_MULTILINE is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_TCP=m +CONFIG_ATM_LANAI=m +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_FORE200E_MAYBE=m +CONFIG_ATM_FORE200E_PCA=y +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_FORE200E_TX_RETRY=16 +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E=m +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_FDDI=y +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_SKFP=m +CONFIG_HIPPI=y +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +CONFIG_PPPOE=m +CONFIG_PPPOATM=m +CONFIG_PPPOL2TP=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLHC=m +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_NET_FC=y +CONFIG_SHAPER=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_VIRTIO_NET=m +CONFIG_ISDN=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y +CONFIG_ISDN_X25=y + +# +# ISDN feature submodules +# +CONFIG_ISDN_DIVERSION=m + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_KEYPAD is not set +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_GIGASET_BASE=m +CONFIG_GIGASET_M105=m +CONFIG_GIGASET_M101=m +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_UNDOCREQ is not set +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_CAPI_TRACE=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# +CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_POLLDEV=m + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_EVBUG=m + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_YEALINK=m +CONFIG_INPUT_UINPUT=m + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_DEV_KMEM is not set +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_COMPUTONE=m +CONFIG_ROCKETPORT=m +CONFIG_CYCLADES=m +# CONFIG_CYZ_INTR is not set +CONFIG_DIGIEPCA=m +CONFIG_MOXA_INTELLIO=m +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +# CONFIG_ISI is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_GT=m +CONFIG_N_HDLC=m +CONFIG_SPECIALIX=m +# CONFIG_SPECIALIX_RTSCTS is not set +CONFIG_SX=m +CONFIG_RIO=m +# CONFIG_RIO_OLDPCI is not set +CONFIG_STALDRV=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_CS=m +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +CONFIG_PPDEV=m +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPMI_POWEROFF=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_INTEL=m +CONFIG_HW_RANDOM_AMD=m +CONFIG_NVRAM=m +CONFIG_RTC=y +# CONFIG_RTC_HISTOGRAM is not set +CONFIG_BLOCKER=m +CONFIG_LPPTEST=m +CONFIG_R3964=m +CONFIG_APPLICOM=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_MWAVE=m +CONFIG_PC8736x_GPIO=m +CONFIG_NSC_GPIO=m +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +CONFIG_HPET=y +# CONFIG_HPET_RTC_IRQ is not set +CONFIG_HPET_MMAP=y +CONFIG_HANGCHECK_TIMER=m +CONFIG_TCG_TPM=m +CONFIG_TCG_TIS=m +CONFIG_TCG_NSC=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TELCLOCK=m +CONFIG_RMEM=m +CONFIG_ALLOC_RTSJ_MEM=m +CONFIG_DEVPORT=y +CONFIG_I2C=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Miscellaneous I2C Chip support +# +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_DS1682=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_TSL2550=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +CONFIG_SPI_LM70_LLP=m + +# +# SPI Protocol Masters +# +CONFIG_SPI_AT25=m +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_W1=m +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PDA_POWER=m +CONFIG_BATTERY_DS2760=m +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_HDAPS=m +CONFIG_SENSORS_APPLESMC=m +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_WAFER_WDT=m +CONFIG_I6300ESB_WDT=m +CONFIG_ITCO_WDT=m +CONFIG_ITCO_VENDOR_SUPPORT=y +CONFIG_IT8712F_WDT=m +CONFIG_SC1200_WDT=m +CONFIG_PC87413_WDT=m +CONFIG_60XX_WDT=m +CONFIG_SBC8360_WDT=m +CONFIG_CPU5_WDT=m +CONFIG_SMSC37B787_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83697HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_MACHZ_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +# CONFIG_SSB_PCMCIAHOST is not set +# CONFIG_SSB_SILENT is not set +CONFIG_SSB_DEBUG=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_DRIVER_PCICORE=y + +# +# Multifunction device drivers +# +CONFIG_MFD_SM501=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders/decoders and other helper chips +# + +# +# Audio decoders +# +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_VP27SMPX=m + +# +# Video decoders +# +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_TCM825X=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7191=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_VPX3220=m + +# +# Video and audio decoders +# +CONFIG_VIDEO_CX25840=m + +# +# MPEG video encoders +# +CONFIG_VIDEO_CX2341X=m + +# +# Video encoders +# +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m + +# +# Video improvement chips +# +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_DVB=m +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_DPC is not set +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_29XXX=y +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_SYSFS=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_USB_VICAM=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_ET61X251=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_USB_W9968CF=m +# CONFIG_USB_OV511 is not set +CONFIG_USB_SE401=m +CONFIG_USB_SN9C102=m +CONFIG_USB_STV680=m +CONFIG_USB_ZC0301=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_ZR364XX=m +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_USB_DSBR=m +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CAPTURE_DRIVERS=y + +# +# Supported SAA7146 based PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +# +# Supported USB Adapters +# +CONFIG_DVB_USB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 + +# +# Supported FlexCopII (B2C2) Adapters +# +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m + +# +# Supported Pluto2 Adapters +# +CONFIG_DVB_PLUTO2=m + +# +# Supported DVB Frontends +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_FE_CUSTOMISE is not set + +# +# DVB-S (satellite) frontends +# +CONFIG_DVB_STV0299=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_TDA10086=m + +# +# DVB-T (terrestrial) frontends +# +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_L64781=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_ZL10353=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m + +# +# DVB-C (cable) frontends +# +CONFIG_DVB_VES1820=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_STV0297=m + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +CONFIG_DVB_NXT200X=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_S5H1409=m + +# +# Tuners/PLL support +# +CONFIG_DVB_PLL=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +CONFIG_DVB_TUNER_QT1010=m +CONFIG_DVB_TUNER_MT2060=m +CONFIG_DVB_TUNER_MT2266=m +CONFIG_DVB_TUNER_MT2131=m +CONFIG_DVB_TUNER_DIB0070=m + +# +# Miscellaneous devices +# +CONFIG_DVB_LNBP21=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_TUA6100=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TUNER_SIMPLE=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_DAB=y +CONFIG_USB_DABUSB=m + +# +# Graphics support +# +CONFIG_AGP=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=m +CONFIG_AGP_SIS=m +CONFIG_AGP_VIA=m +CONFIG_DRM=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_I915=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m +CONFIG_DRM_VIA=m +CONFIG_DRM_VIA_CHROME9=m +CONFIG_DRM_SAVAGE=m +CONFIG_VGASTATE=m +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_DDC=m +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_IMAGEBLIT=m +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_SVGALIB=m +# CONFIG_FB_MACMODES is not set +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +CONFIG_FB_CIRRUS=m +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_CYBER2000=m +CONFIG_FB_ARC=m +CONFIG_FB_ASILIANT=y +CONFIG_FB_IMSTT=y +CONFIG_FB_VGA16=m +CONFIG_FB_UVESA=m +CONFIG_FB_VESA=m +CONFIG_FB_EFI=y +CONFIG_FB_HECUBA=m +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_S1D13XXX=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_I2C=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_BACKLIGHT=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_I2C=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_BACKLIGHT=y +CONFIG_FB_LE80578=m +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_ARK=m +CONFIG_FB_PM3=m +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_LX=m +CONFIG_FB_GEODE_GX=m +# CONFIG_FB_GEODE_GX_SET_FBSIZE is not set +CONFIG_FB_GEODE_GX1=m +CONFIG_FB_SM501=m +# CONFIG_FB_VIRTUAL is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_PROGEAR=m +CONFIG_BACKLIGHT_CARILLO_RANCH=m + +# +# Display device support +# +CONFIG_DISPLAY_SUPPORT=m + +# +# Display hardware drivers +# + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VIDEO_SELECT=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=m +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_LOGO is not set + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +# CONFIG_SND is not set + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set +CONFIG_AC97_BUS=m +CONFIG_HID_SUPPORT=y +CONFIG_HID=m +# CONFIG_HID_DEBUG is not set +CONFIG_HIDRAW=y + +# +# USB Input Devices +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT_POWERBOOK=y +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +CONFIG_USB_PERSIST=y +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_ISP116X_HCD=m +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_HCD_SSB is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SL811_CS=m +CONFIG_USB_R8A66597_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_MON=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +# CONFIG_USB_SERIAL_IR is not set +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_LED=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_IOWARRIOR=m +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# +CONFIG_USB_ATM=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_CXACRU=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=m +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_GADGET_AMD5536UDC=y +CONFIG_USB_AMD5536UDC=m +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_GADGETFS=m +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_G_SERIAL=m +# CONFIG_USB_MIDI_GADGET is not set + +# +# MMC/SD/SDIO support, can only select one arch from MMC and MSS +# +CONFIG_MMC=m +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_SDIO_UART=m + +# +# MMC/SD Host Controller Drivers +# +CONFIG_MMC_SDHCI=m +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_WBSD=m +CONFIG_MMC_TIFM_SD=m +CONFIG_MMC_SPI=m +# CONFIG_MSS is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=m + +# +# LED drivers +# + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_IPATH=m +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_MLX4_INFINIBAND=m +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_ISER=m +CONFIG_EDAC=y + +# +# Reporting subsystems +# +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_MM_EDAC=m +CONFIG_EDAC_E752X=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_I5000=m +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_DRV_TEST=m + +# +# I2C RTC drivers +# +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y + +# +# SPI RTC drivers +# +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_MAX6902=m + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_V3020=m + +# +# on-CPU RTC drivers +# +CONFIG_DMADEVICES=y + +# +# DMA Devices +# +CONFIG_INTEL_IOATDMA=m +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +CONFIG_NET_DMA=y +CONFIG_DCA=m +CONFIG_AUXDISPLAY=y +CONFIG_KS0108=m +CONFIG_KS0108_PORT=0x378 +CONFIG_KS0108_DELAY=2 +CONFIG_CFAG12864B=m +CONFIG_CFAG12864B_RATE=20 + +# +# Userspace I/O +# +CONFIG_UIO=m +CONFIG_UIO_CIF=m + +# +# Firmware Drivers +# +CONFIG_EDD=y +CONFIG_EDD_OFF=y +CONFIG_DELL_RBU=m +CONFIG_DCDBAS=m +CONFIG_DMIID=y + +# +# File systems +# +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=m +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_STATISTICS=y +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_NOLOCK=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_OCFS2_FS=m +CONFIG_OCFS2_DEBUG_MASKLOG=y +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_QUOTACTL=y +CONFIG_DNOTIFY=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=m +CONFIG_GENERIC_ACL=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m + +# +# Miscellaneous filesystems +# +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +CONFIG_CRAMFS=y +CONFIG_VXFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_UFS_DEBUG is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_XPRT_RDMA=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_WEAK_PW_HASH=y +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +CONFIG_CIFS_EXPERIMENTAL=y +CONFIG_CIFS_UPCALL=y +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +CONFIG_CODA_FS=m +# CONFIG_CODA_FS_OLD_API is not set +CONFIG_AFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_9P_FS=m +CONFIG_DEFAULT_RELATIME=y +CONFIG_DEFAULT_RELATIME_VAL=1 + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_CUMANA is not set +# CONFIG_ACORN_PARTITION_EESOX is not set +CONFIG_ACORN_PARTITION_ICS=y +# CONFIG_ACORN_PARTITION_ADFS is not set +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_ATARI_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +CONFIG_SGI_PARTITION=y +CONFIG_ULTRIX_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_SYSV68_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_INSTRUMENTATION=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=m +CONFIG_PROFILE_NMI=y +CONFIG_KPROBES=y +# CONFIG_MARKERS is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_PRINTK_TIME=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RTMUTEX_CHECK is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_RWLOCK_TORTURE_TEST is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_FORCED_INLINING is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_LKDTM is not set +# CONFIG_FAULT_INJECTION is not set +CONFIG_HAVE_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +# CONFIG_FTRACE is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_WAKEUP_LATENCY_HIST is not set +# CONFIG_PREEMPT_TRACE is not set +# CONFIG_SAMPLES is not set +CONFIG_NONPROMISC_DEVMEM=y +CONFIG_EARLY_PRINTK=y +# CONFIG_WRAPPER_PRINT is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +CONFIG_DEBUG_RODATA=y +# CONFIG_IOMMU_DEBUG is not set +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +CONFIG_IO_DELAY_TYPE_NONE=3 +# CONFIG_IO_DELAY_0X80 is not set +CONFIG_IO_DELAY_0XED=y +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_DEFAULT_IO_DELAY_TYPE=1 + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +# CONFIG_SECURITY_APPARMOR_DISABLE is not set +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_TWOFISH_X86_64=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_AES_X86_64=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_HW=y +CONFIG_HAVE_KVM=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_INTEL=m +CONFIG_KVM_AMD=m +CONFIG_VIRTIO=m +CONFIG_VIRTIO_RING=m +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_BALLOON=m + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CHECK_SIGNATURE=y --- linux-2.6.24.orig/debian/binary-custom.d/rt/config.i386 +++ linux-2.6.24/debian/binary-custom.d/rt/config.i386 @@ -0,0 +1,3957 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.24.6 +# Mon Feb 23 16:02:25 2009 +# +# CONFIG_64BIT is not set +CONFIG_X86_32=y +# CONFIG_X86_64 is not set +CONFIG_X86=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_SEMAPHORE_SLEEPERS=y +CONFIG_MMU=y +CONFIG_ZONE_DMA=y +CONFIG_QUICKLIST=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_DMI=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ASM_SEMAPHORES=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME_VSYSCALL is not set +CONFIG_ARCH_SUPPORTS_OPROFILE=y +# CONFIG_ZONE_DMA32 is not set +CONFIG_ARCH_POPULATES_NODE_MAP=y +# CONFIG_AUDIT_ARCH is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_X86_SMP=y +CONFIG_X86_HT=y +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_TRAMPOLINE=y +CONFIG_KTIME_SCALAR=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_VERSION_SIGNATURE="Ubuntu 2.6.24-4.6-generic" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_TREE=y +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_NS=y +CONFIG_CPUSETS=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_FAIR_USER_SCHED is not set +CONFIG_FAIR_CGROUP_SCHED=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_PROC_PID_CPUSET=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_RADIX_TREE_CONCURRENT=y +CONFIG_RADIX_TREE_OPTIMISTIC=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBD=y +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_LSM_MMAP_MIN_ADDR=0 + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_PREEMPT_NOTIFIERS=y + +# +# Processor type and features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_SMP=y +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_X86_VSMP is not set +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_GUEST=y +CONFIG_VMI=y +# CONFIG_LGUEST_GUEST is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +CONFIG_M586=y +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MEFFICEON is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_GENERIC_CPU is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_XADD=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_F00F_BUG=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_MINIMUM_CPU_FAMILY=4 +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_NR_CPUS=8 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT_DESKTOP is not set +CONFIG_PREEMPT_RT=y +CONFIG_PREEMPT=y +CONFIG_PREEMPT_SOFTIRQS=y +CONFIG_PREEMPT_HARDIRQS=y +CONFIG_PREEMPT_BKL=y +# CONFIG_CLASSIC_RCU is not set +CONFIG_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU_BOOST=y +CONFIG_RCU_TRACE=m +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_MCE is not set +CONFIG_VM86=y +CONFIG_TOSHIBA=m +CONFIG_I8K=m +CONFIG_X86_REBOOTFIXUPS=y +CONFIG_MICROCODE=m +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_HIGHMEM=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_SPARSEMEM_STATIC=y +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_NR_QUICK=1 +CONFIG_VIRT_TO_BUS=y +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +CONFIG_EFI=y +# CONFIG_IRQBALANCE is not set +CONFIG_BOOT_IOREMAP=y +CONFIG_SECCOMP=y +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +CONFIG_PHYSICAL_START=0x100000 +CONFIG_RELOCATABLE=y +CONFIG_PHYSICAL_ALIGN=0x100000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_COMPAT_VDSO is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_HARDIRQS_SW_RESEND=y + +# +# Power management options +# +CONFIG_PM=y +CONFIG_PM_LEGACY=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_VERBOSE is not set +CONFIG_PM_TRACE=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SUSPEND=y +CONFIG_PM_DISABLE_CONSOLE=y +CONFIG_HIBERNATION_SMP_POSSIBLE=y +CONFIG_HIBERNATION=y +CONFIG_PM_STD_PARTITION="" +CONFIG_ACPI=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_PROCFS=y +CONFIG_ACPI_PROCFS_POWER=y +CONFIG_ACPI_SYSFS_POWER=y +CONFIG_ACPI_PROC_EVENT=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_VIDEO=m +CONFIG_ACPI_FAN=m +CONFIG_ACPI_DOCK=m +CONFIG_ACPI_BAY=m +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_ACPI_CUSTOM_DSDT_INITRD=y +CONFIG_ACPI_BLACKLIST_YEAR=2000 +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y +CONFIG_ACPI_CONTAINER=m +CONFIG_ACPI_SBS=m +CONFIG_APM=m +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +# CONFIG_APM_CPU_IDLE is not set +# CONFIG_APM_DISPLAY_BLANK is not set +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=m +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=m +CONFIG_X86_POWERNOW_K7_ACPI=y +CONFIG_X86_POWERNOW_K8=m +CONFIG_X86_POWERNOW_K8_ACPI=y +CONFIG_X86_GX_SUSPMOD=m +CONFIG_X86_SPEEDSTEP_CENTRINO=m +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_ICH=m +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_CPUFREQ_NFORCE2=m +CONFIG_X86_LONGRUN=m +CONFIG_X86_LONGHAUL=m +# CONFIG_X86_E_POWERSAVER is not set + +# +# shared options +# +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_SPEEDSTEP_LIB=m +CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y + +# +# Bus options (PCI etc.) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_PCIEAER=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_LEGACY=y +# CONFIG_PCI_DEBUG is not set +CONFIG_HT_IRQ=y +CONFIG_ISA_DMA_API=y +CONFIG_ISA=y +CONFIG_EISA=y +CONFIG_EISA_VLB_PRIMING=y +CONFIG_EISA_PCI_EISA=y +CONFIG_EISA_VIRTUAL_ROOT=y +CONFIG_EISA_NAMES=y +CONFIG_MCA=y +CONFIG_MCA_LEGACY=y +# CONFIG_MCA_PROC_FS is not set +CONFIG_SCx200=m +CONFIG_SCx200HR_TIMER=m +CONFIG_K8_NB=y +CONFIG_PCCARD=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA=m +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y +CONFIG_CARDBUS=y + +# +# PC-card bridges +# +CONFIG_YENTA=m +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_PD6729=m +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_TCIC=m +CONFIG_PCMCIA_PROBE=y +CONFIG_PCCARD_NONSTATIC=m +CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI_FAKE=m +CONFIG_HOTPLUG_PCI_COMPAQ=m +CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM=y +CONFIG_HOTPLUG_PCI_IBM=m +CONFIG_HOTPLUG_PCI_ACPI=m +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m +CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +CONFIG_HOTPLUG_PCI_SHPC=m + +# +# Executable file formats / Emulations +# +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=m +CONFIG_BINFMT_MISC=m + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_LRO=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +# CONFIG_DEFAULT_BIC is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_HTCP is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFAULT_RENO=y +CONFIG_DEFAULT_TCP_CONG="reno" +CONFIG_TCP_MD5SIG=y +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_NETLABEL is not set +CONFIG_NETWORK_SECMARK=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m + +# +# IP: Netfilter Configuration +# +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_SIP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_RAW=m + +# +# DECnet: Netfilter Configuration +# +CONFIG_DECNET_NF_GRABULATOR=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_IP_DCCP_ACKVEC=y + +# +# DCCP CCIDs Configuration (EXPERIMENTAL) +# +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +CONFIG_IP_DCCP_TFRC_LIB=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 + +# +# DCCP Kernel Hacking +# +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_NET_DCCPPROBE=m +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +CONFIG_ATM=y +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_DECNET=m +# CONFIG_DECNET_ROUTER is not set +CONFIG_LLC=y +CONFIG_LLC2=m +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_LTPC=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RR=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +# CONFIG_NET_CLS_POLICE is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +CONFIG_NET_TCPPROBE=m +CONFIG_HAMRADIO=y + +# +# Packet Radio protocols +# +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_NETROM=m +CONFIG_ROSE=m + +# +# AX.25 network device drivers +# +CONFIG_MKISS=m +CONFIG_6PACK=m +CONFIG_BPQETHER=m +CONFIG_SCC=m +# CONFIG_SCC_DELAY is not set +# CONFIG_SCC_TRXECHO is not set +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_EPP=m +CONFIG_YAM=m +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m +CONFIG_KINGSUN_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KS959_DONGLE=m + +# +# Old SIR device drivers +# + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +CONFIG_WINBOND_FIR=m +CONFIG_TOSHIBA_FIR=m +CONFIG_SMC_IRCC_FIR=m +CONFIG_ALI_FIR=m +CONFIG_VLSI_FIR=m +CONFIG_VIA_FIR=m +CONFIG_MCS_FIR=m +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_RXKAD=m +CONFIG_FIB_RULES=y + +# +# Wireless +# +CONFIG_CFG80211=m +CONFIG_NL80211=y +CONFIG_WIRELESS_EXT=y +CONFIG_MAC80211=m +CONFIG_MAC80211_RCSIMPLE=y +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_DEBUGFS=y +# CONFIG_MAC80211_DEBUG is not set +CONFIG_IEEE80211=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_CRYPT_WEP=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +CONFIG_NET_9P=m +CONFIG_NET_9P_FD=m +CONFIG_NET_9P_VIRTIO=m +# CONFIG_NET_9P_DEBUG is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=m +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m +CONFIG_RFD_FTL=m +CONFIG_SSFDC=m +CONFIG_MTD_OOPS=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PNC2000=m +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_TS5500=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_DILNETPC=m +CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000 +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_PLATRAM=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_DATAFLASH=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTD_BLOCK2MTD=m + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCECC=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_IDS=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_CS553X=m +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_2X_PROGRAM=y +CONFIG_MTD_ONENAND_SIM=m + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +CONFIG_MTD_UBI_GLUEBI=y + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_AX88796=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_NOT_PC=y +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y +CONFIG_PNPBIOS=y +CONFIG_PNPBIOS_PROC_FS=y +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_FD=m +CONFIG_BLK_DEV_XD=m +CONFIG_PARIDE=m + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_BPCK6=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_SX8=m +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_VIRTIO_BLK=m +CONFIG_MISC_DEVICES=y +CONFIG_IBM_ASM=m +CONFIG_PHANTOM=m +CONFIG_EEPROM_93CX6=m +CONFIG_SGI_IOC4=m +CONFIG_TIFM_CORE=m +CONFIG_TIFM_7XX1=m +CONFIG_ASUS_LAPTOP=m +CONFIG_FUJITSU_LAPTOP=m +CONFIG_MSI_LAPTOP=m +CONFIG_SONY_LAPTOP=m +CONFIG_SONYPI_COMPAT=y +CONFIG_THINKPAD_ACPI=m +# CONFIG_THINKPAD_ACPI_DEBUG is not set +CONFIG_THINKPAD_ACPI_BAY=y +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_BLK_DEV_IDEACPI=y +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +CONFIG_BLK_DEV_PLATFORM=m +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +CONFIG_BLK_DEV_IDEPNP=y + +# +# PCI IDE chipsets support +# +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_GENERIC is not set +CONFIG_BLK_DEV_OPTI621=m +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI15X3=m +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +CONFIG_BLK_DEV_ATIIXP=m +CONFIG_BLK_DEV_CMD64X=m +# CONFIG_BLK_DEV_TRIFLEX is not set +CONFIG_BLK_DEV_CY82C693=m +# CONFIG_BLK_DEV_CS5520 is not set +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_CS5535=m +CONFIG_BLK_DEV_HPT34X=m +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=m +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_SC1200=m +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +CONFIG_BLK_DEV_NS87415=m +CONFIG_BLK_DEV_PDC202XX_OLD=m +CONFIG_PDC202XX_BURST=y +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +CONFIG_BLK_DEV_TRM290=m +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLK_DEV_TC86C001=m +# CONFIG_IDE_ARM is not set + +# +# Other IDE chipsets support +# + +# +# Note: most of these also require special kernel boot parameters +# +CONFIG_BLK_DEV_4DRIVES=y +CONFIG_BLK_DEV_ALI14XX=m +CONFIG_BLK_DEV_DTC2278=m +CONFIG_BLK_DEV_HT6560B=m +CONFIG_BLK_DEV_QD65XX=m +CONFIG_BLK_DEV_UMC8672=m +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=m +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=m +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SAS_ATA=y +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_7000FASST=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AHA1740=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_SCSI_AIC94XX=m +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_DTC3280=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_FD_MCS=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_GENERIC_NCR5380=m +CONFIG_SCSI_GENERIC_NCR5380_MMIO=m +CONFIG_SCSI_GENERIC_NCR53C400=y +CONFIG_SCSI_IBMMCA=m +CONFIG_IBMMCA_SCSI_ORDER_STANDARD=y +# CONFIG_IBMMCA_SCSI_DEV_RESET is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_NCR53C406A=m +CONFIG_SCSI_NCR_D700=m +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPR_DUMP is not set +CONFIG_SCSI_NCR_Q720=m +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 +CONFIG_SCSI_NCR53C8XX_SYNC=5 +CONFIG_SCSI_PAS16=m +CONFIG_SCSI_PSI240I=m +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_SEAGATE=m +CONFIG_SCSI_SIM710=m +CONFIG_SCSI_SYM53C416=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_T128=m +CONFIG_SCSI_U14_34F=m +CONFIG_SCSI_U14_34F_TAGGED_QUEUE=y +CONFIG_SCSI_U14_34F_LINKED_COMMANDS=y +CONFIG_SCSI_U14_34F_MAX_TAGS=8 +CONFIG_SCSI_ULTRASTOR=m +CONFIG_SCSI_NSP32=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_ATA=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_ACPI=y +CONFIG_SATA_AHCI=m +CONFIG_SATA_SVW=m +CONFIG_ATA_PIIX=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_PDC_ADMA=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_SX4=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SATA_INIC162X=m +CONFIG_PATA_ACPI=m +# CONFIG_PATA_ALI is not set +CONFIG_PATA_AMD=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +# CONFIG_PATA_CMD640_PCI is not set +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CS5520=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +CONFIG_PATA_CS5536=m +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +CONFIG_ATA_GENERIC=m +CONFIG_PATA_HPT366=m +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +CONFIG_PATA_HPT3X3=m +# CONFIG_PATA_HPT3X3_DMA is not set +# CONFIG_PATA_ISAPNP is not set +CONFIG_PATA_IT821X=m +CONFIG_PATA_IT8213=m +CONFIG_PATA_JMICRON=m +# CONFIG_PATA_LEGACY is not set +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_NETCELL=m +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PCMCIA=m +# CONFIG_PATA_PDC_OLD is not set +CONFIG_PATA_QDI=m +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +# CONFIG_PATA_WINBOND_VLB is not set +CONFIG_PATA_PLATFORM=m +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m +CONFIG_DM_MULTIPATH_RDAC=m +CONFIG_DM_MULTIPATH_HP=m +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_SAS=m +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# Controllers +# +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocols +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_I2O=m +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_BUS=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_NETDEVICES=y +CONFIG_NETDEVICES_MULTIQUEUE=y +CONFIG_IFB=m +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_MACVLAN=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_NET_SB1000=m +CONFIG_ARCNET=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_ISA=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_PHYLIB=m + +# +# MII PHY device drivers +# +CONFIG_MARVELL_PHY=m +CONFIG_DAVICOM_PHY=m +CONFIG_QSEMI_PHY=m +CONFIG_LXT_PHY=m +CONFIG_CICADA_PHY=m +CONFIG_VITESSE_PHY=m +CONFIG_SMSC_PHY=m +CONFIG_BROADCOM_PHY=m +CONFIG_ICPLUS_PHY=m +CONFIG_FIXED_PHY=m +# CONFIG_FIXED_MII_10_FDX is not set +# CONFIG_FIXED_MII_100_FDX is not set +CONFIG_FIXED_MII_1000_FDX=y +CONFIG_FIXED_MII_AMNT=1 +CONFIG_MDIO_BITBANG=m +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_ELMC=m +CONFIG_ELMC_II=m +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRAMCA=m +CONFIG_ULTRA=m +CONFIG_ULTRA32=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +CONFIG_NI52=m +CONFIG_NI65=m +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_ULI526X=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_AT1700=m +CONFIG_DEPCA=m +CONFIG_HP100=m +CONFIG_NET_ISA=y +CONFIG_E2100=m +CONFIG_EWRK3=m +CONFIG_EEXPRESS=m +CONFIG_EEXPRESS_PRO=m +CONFIG_HPLAN_PLUS=m +CONFIG_HPLAN=m +CONFIG_LP486E=m +CONFIG_ETH16I=m +CONFIG_NE2000=m +CONFIG_ZNET=m +CONFIG_SEEQ8005=m +CONFIG_NE2_MCA=m +CONFIG_IBMLANA=m +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_AMD8111_ETH=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI=y +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +CONFIG_CS89x0=m +CONFIG_EEPRO100=m +CONFIG_E100=m +CONFIG_LNE390=m +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_NE3210=m +CONFIG_ES3210=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_RHINE_NAPI=y +CONFIG_SC92031=m +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_NETDEV_1000=y +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E1000E=m +CONFIG_IP1000=m +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_SIS190=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SK98LIN is not set +CONFIG_VIA_VELOCITY=m +CONFIG_TIGON3=m +CONFIG_BNX2=m +CONFIG_QLA3XXX=m +CONFIG_ATL1=m +CONFIG_NETDEV_10000=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T1_NAPI=y +CONFIG_CHELSIO_T3=m +CONFIG_IXGBE=m +CONFIG_IXGB=m +# CONFIG_IXGB_NAPI is not set +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +CONFIG_MYRI10GE=m +CONFIG_NETXEN_NIC=m +CONFIG_NIU=m +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_TEHUTI=m +CONFIG_TR=y +CONFIG_IBMTR=m +CONFIG_IBMOL=m +CONFIG_IBMLS=m +CONFIG_3C359=m +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +CONFIG_SKISA=m +CONFIG_PROTEON=m +CONFIG_ABYSS=m +CONFIG_MADGEMC=m +CONFIG_SMCTR=m + +# +# Wireless LAN +# +CONFIG_WLAN_PRE80211=y +CONFIG_STRIP=m +CONFIG_ARLAN=m +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_WLAN_80211=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_IPW2100=m +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2200=m +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +# CONFIG_IPW2200_DEBUG is not set +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_CS=m +CONFIG_LIBERTAS_SDIO=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_AIRO=m +CONFIG_HERMES=m +# CONFIG_PLX_HERMES is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_PCI_HERMES is not set +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PRISM54=m +CONFIG_USB_ZD1201=m +CONFIG_RTL8187=m +CONFIG_ADM8211=m +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +CONFIG_P54_PCI=m +# CONFIG_IWLWIFI is not set +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_CS=m +CONFIG_BCM43XX=m +# CONFIG_BCM43XX_DEBUG is not set +CONFIG_BCM43XX_DMA=y +CONFIG_BCM43XX_PIO=y +CONFIG_BCM43XX_DMA_AND_PIO_MODE=y +# CONFIG_BCM43XX_DMA_MODE is not set +# CONFIG_BCM43XX_PIO_MODE is not set +CONFIG_B43=m +CONFIG_B43_PCI_AUTOSELECT=y +CONFIG_B43_PCICORE_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_LEDS=y +CONFIG_B43_RFKILL=y +CONFIG_B43_DEBUG=y +CONFIG_B43_DMA=y +CONFIG_B43_PIO=y +CONFIG_B43_DMA_AND_PIO_MODE=y +# CONFIG_B43_DMA_MODE is not set +# CONFIG_B43_PIO_MODE is not set +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_PIO=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_RT2X00=m +CONFIG_RT2X00_LIB=m +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT61PCI=m +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +# CONFIG_RT2X00_DEBUG is not set + +# +# USB Network Adapters +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_PCMCIA_IBMTR=m +CONFIG_WAN=y +CONFIG_HOSTESS_SV11=m +CONFIG_COSA=m +CONFIG_LANMEDIA=m +CONFIG_SEALEVEL_4021=m +CONFIG_HDLC=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_X25=m +CONFIG_PCI200SYN=m +CONFIG_WANXL=m +CONFIG_PC300=m +CONFIG_PC300_MLPPP=y + +# +# Cyclades-PC300 MLPPP support is disabled. +# + +# +# Refer to the file README.mlppp, provided by PC300 package. +# +# CONFIG_PC300TOO is not set +CONFIG_N2=m +CONFIG_C101=m +CONFIG_FARSYNC=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_SDLA=m +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +CONFIG_LAPBETHER=m +CONFIG_X25_ASY=m +CONFIG_SBNI=m +# CONFIG_SBNI_MULTILINE is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_TCP=m +CONFIG_ATM_LANAI=m +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_ATM_NICSTAR=m +# CONFIG_ATM_NICSTAR_USE_SUNI is not set +# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_FORE200E_MAYBE=m +CONFIG_ATM_FORE200E_PCA=y +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_FORE200E_TX_RETRY=16 +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E=m +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_FDDI=y +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_SKFP=m +CONFIG_HIPPI=y +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +CONFIG_PPPOE=m +CONFIG_PPPOATM=m +CONFIG_PPPOL2TP=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLHC=m +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_NET_FC=y +CONFIG_SHAPER=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_VIRTIO_NET=m +CONFIG_ISDN=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y +CONFIG_ISDN_X25=y + +# +# ISDN feature submodules +# +CONFIG_ISDN_DIVERSION=m + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_KEYPAD is not set +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_GIGASET_BASE=m +CONFIG_GIGASET_M105=m +CONFIG_GIGASET_M101=m +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_UNDOCREQ is not set +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_CAPI_TRACE=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# +CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_T1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_POLLDEV=m + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_EVBUG=m + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_INPORT=m +# CONFIG_MOUSE_ATIXL is not set +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +CONFIG_INPUT_WISTRON_BTNS=m +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_YEALINK=m +CONFIG_INPUT_UINPUT=m + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_DEV_KMEM is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +CONFIG_ROCKETPORT=m +CONFIG_CYCLADES=m +# CONFIG_CYZ_INTR is not set +CONFIG_DIGIEPCA=m +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +# CONFIG_ISI is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_GT=m +CONFIG_N_HDLC=m +CONFIG_SPECIALIX=m +# CONFIG_SPECIALIX_RTSCTS is not set +CONFIG_SX=m +# CONFIG_RIO is not set +CONFIG_STALDRV=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_CS=m +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_FOURPORT=m +CONFIG_SERIAL_8250_ACCENT=m +CONFIG_SERIAL_8250_BOCA=m +CONFIG_SERIAL_8250_EXAR_ST16C554=m +CONFIG_SERIAL_8250_HUB6=m +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_MCA=m + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +CONFIG_PPDEV=m +CONFIG_HVC_DRIVER=y +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPMI_POWEROFF=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_INTEL=m +CONFIG_HW_RANDOM_AMD=m +CONFIG_HW_RANDOM_GEODE=m +CONFIG_HW_RANDOM_VIA=m +CONFIG_NVRAM=m +CONFIG_RTC=y +# CONFIG_RTC_HISTOGRAM is not set +CONFIG_BLOCKER=m +CONFIG_LPPTEST=m +CONFIG_DTLK=m +CONFIG_R3964=m +CONFIG_APPLICOM=m +CONFIG_SONYPI=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_MWAVE=m +CONFIG_SCx200_GPIO=m +CONFIG_PC8736x_GPIO=m +CONFIG_NSC_GPIO=m +CONFIG_CS5535_GPIO=m +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +CONFIG_HPET=y +# CONFIG_HPET_RTC_IRQ is not set +CONFIG_HPET_MMAP=y +CONFIG_HANGCHECK_TIMER=m +CONFIG_TCG_TPM=m +CONFIG_TCG_TIS=m +CONFIG_TCG_NSC=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TELCLOCK=m +CONFIG_RMEM=m +CONFIG_ALLOC_RTSJ_MEM=m +CONFIG_DEVPORT=y +CONFIG_I2C=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +CONFIG_I2C_SIMTEC=m +CONFIG_SCx200_I2C=m +CONFIG_SCx200_I2C_SCL=12 +CONFIG_SCx200_I2C_SDA=13 +CONFIG_SCx200_ACB=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m +CONFIG_I2C_PCA_ISA=m + +# +# Miscellaneous I2C Chip support +# +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_DS1682=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_TSL2550=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +CONFIG_SPI_LM70_LLP=m + +# +# SPI Protocol Masters +# +CONFIG_SPI_AT25=m +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_W1=m +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PDA_POWER=m +CONFIG_BATTERY_DS2760=m +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_HDAPS=m +CONFIG_SENSORS_APPLESMC=m +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_WAFER_WDT=m +CONFIG_I6300ESB_WDT=m +CONFIG_ITCO_WDT=m +CONFIG_ITCO_VENDOR_SUPPORT=y +CONFIG_IT8712F_WDT=m +CONFIG_SC1200_WDT=m +CONFIG_SCx200_WDT=m +CONFIG_PC87413_WDT=m +CONFIG_60XX_WDT=m +CONFIG_SBC8360_WDT=m +CONFIG_SBC7240_WDT=m +CONFIG_CPU5_WDT=m +CONFIG_SMSC37B787_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83697HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_MACHZ_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m + +# +# ISA-based Watchdog Cards +# +CONFIG_PCWATCHDOG=m +CONFIG_MIXCOMWD=m +CONFIG_WDT=m +CONFIG_WDT_501=y + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +# CONFIG_SSB_PCMCIAHOST is not set +# CONFIG_SSB_SILENT is not set +CONFIG_SSB_DEBUG=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_DRIVER_PCICORE=y + +# +# Multifunction device drivers +# +CONFIG_MFD_SM501=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders/decoders and other helper chips +# + +# +# Audio decoders +# +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_VP27SMPX=m + +# +# Video decoders +# +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_TCM825X=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7191=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_VPX3220=m + +# +# Video and audio decoders +# +CONFIG_VIDEO_CX25840=m + +# +# MPEG video encoders +# +CONFIG_VIDEO_CX2341X=m + +# +# Video encoders +# +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m + +# +# Video improvement chips +# +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_DVB=m +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_DPC is not set +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_29XXX=y +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_SYSFS=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_USB_VICAM=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_ET61X251=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_USB_W9968CF=m +# CONFIG_USB_OV511 is not set +CONFIG_USB_SE401=m +CONFIG_USB_SN9C102=m +CONFIG_USB_STV680=m +CONFIG_USB_ZC0301=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_ZR364XX=m +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +# CONFIG_RADIO_TYPHOON_PROC_FS is not set +CONFIG_RADIO_ZOLTRIX=m +CONFIG_USB_DSBR=m +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CAPTURE_DRIVERS=y + +# +# Supported SAA7146 based PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +# +# Supported USB Adapters +# +CONFIG_DVB_USB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 + +# +# Supported FlexCopII (B2C2) Adapters +# +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m + +# +# Supported Pluto2 Adapters +# +CONFIG_DVB_PLUTO2=m + +# +# Supported DVB Frontends +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_FE_CUSTOMISE is not set + +# +# DVB-S (satellite) frontends +# +CONFIG_DVB_STV0299=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_TDA10086=m + +# +# DVB-T (terrestrial) frontends +# +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_L64781=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_ZL10353=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m + +# +# DVB-C (cable) frontends +# +CONFIG_DVB_VES1820=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_STV0297=m + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +CONFIG_DVB_NXT200X=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_S5H1409=m + +# +# Tuners/PLL support +# +CONFIG_DVB_PLL=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +CONFIG_DVB_TUNER_QT1010=m +CONFIG_DVB_TUNER_MT2060=m +CONFIG_DVB_TUNER_MT2266=m +CONFIG_DVB_TUNER_MT2131=m +CONFIG_DVB_TUNER_DIB0070=m + +# +# Miscellaneous devices +# +CONFIG_DVB_LNBP21=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_TUA6100=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_TUNER=m +# CONFIG_VIDEO_TUNER_CUSTOMIZE is not set +CONFIG_TUNER_MT20XX=m +CONFIG_TUNER_TDA8290=m +CONFIG_TUNER_TEA5761=m +CONFIG_TUNER_TEA5767=m +CONFIG_TUNER_SIMPLE=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_DAB=y +CONFIG_USB_DABUSB=m + +# +# Graphics support +# +CONFIG_AGP=m +CONFIG_AGP_ALI=m +CONFIG_AGP_ATI=m +CONFIG_AGP_AMD=m +CONFIG_AGP_AMD64=m +CONFIG_AGP_INTEL=m +CONFIG_AGP_NVIDIA=m +CONFIG_AGP_SIS=m +CONFIG_AGP_SWORKS=m +CONFIG_AGP_VIA=m +CONFIG_AGP_EFFICEON=m +CONFIG_DRM=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_I915=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m +CONFIG_DRM_VIA=m +CONFIG_DRM_VIA_CHROME9=m +CONFIG_DRM_SAVAGE=m +CONFIG_VGASTATE=m +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_DDC=m +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_IMAGEBLIT=m +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_SVGALIB=m +# CONFIG_FB_MACMODES is not set +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +CONFIG_FB_CIRRUS=m +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_CYBER2000=m +CONFIG_FB_ARC=m +CONFIG_FB_ASILIANT=y +CONFIG_FB_IMSTT=y +CONFIG_FB_VGA16=m +CONFIG_FB_UVESA=m +CONFIG_FB_VESA=m +CONFIG_FB_EFI=y +CONFIG_FB_IMAC=y +CONFIG_FB_HECUBA=m +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_S1D13XXX=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_I2C=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_BACKLIGHT=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_I2C=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_BACKLIGHT=y +CONFIG_FB_I810=m +# CONFIG_FB_I810_GTF is not set +CONFIG_FB_LE80578=m +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FB_CYBLA=m +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_ARK=m +CONFIG_FB_PM3=m +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_LX=m +CONFIG_FB_GEODE_GX=m +# CONFIG_FB_GEODE_GX_SET_FBSIZE is not set +CONFIG_FB_GEODE_GX1=m +CONFIG_FB_SM501=m +# CONFIG_FB_VIRTUAL is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_LTV350QV=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_PROGEAR=m +CONFIG_BACKLIGHT_CARILLO_RANCH=m + +# +# Display device support +# +CONFIG_DISPLAY_SUPPORT=m + +# +# Display hardware drivers +# + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VIDEO_SELECT=y +CONFIG_MDA_CONSOLE=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=m +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_LOGO is not set + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +# CONFIG_SND is not set + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set +CONFIG_AC97_BUS=m +CONFIG_HID_SUPPORT=y +CONFIG_HID=m +# CONFIG_HID_DEBUG is not set +CONFIG_HIDRAW=y + +# +# USB Input Devices +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT_POWERBOOK=y +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +CONFIG_USB_PERSIST=y +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_ISP116X_HCD=m +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_HCD_SSB is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SL811_CS=m +CONFIG_USB_R8A66597_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_MON=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +# CONFIG_USB_SERIAL_IR is not set +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_LED=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_IOWARRIOR=m +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# +CONFIG_USB_ATM=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_CXACRU=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=m +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +CONFIG_USB_GADGET_NET2280=y +CONFIG_USB_NET2280=m +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_GADGETFS=m +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_G_SERIAL=m +# CONFIG_USB_MIDI_GADGET is not set + +# +# MMC/SD/SDIO support, can only select one arch from MMC and MSS +# +CONFIG_MMC=m +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_SDIO_UART=m + +# +# MMC/SD Host Controller Drivers +# +CONFIG_MMC_SDHCI=m +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_WBSD=m +CONFIG_MMC_TIFM_SD=m +# CONFIG_MSS is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=m + +# +# LED drivers +# +CONFIG_LEDS_NET48XX=m +CONFIG_LEDS_WRAP=m + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_MLX4_INFINIBAND=m +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_ISER=m +CONFIG_EDAC=y + +# +# Reporting subsystems +# +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_MM_EDAC=m +# CONFIG_EDAC_AMD76X is not set +CONFIG_EDAC_E7XXX=m +CONFIG_EDAC_E752X=m +CONFIG_EDAC_I82875P=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_I3000=m +CONFIG_EDAC_I82860=m +CONFIG_EDAC_R82600=m +CONFIG_EDAC_I5000=m +CONFIG_RTC_LIB=m +CONFIG_RTC_CLASS=m + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_DRV_TEST=m + +# +# I2C RTC drivers +# +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y + +# +# SPI RTC drivers +# +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_MAX6902=m + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_V3020=m + +# +# on-CPU RTC drivers +# +CONFIG_DMADEVICES=y + +# +# DMA Devices +# +CONFIG_INTEL_IOATDMA=m +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +CONFIG_NET_DMA=y +CONFIG_DCA=m +CONFIG_AUXDISPLAY=y +CONFIG_KS0108=m +CONFIG_KS0108_PORT=0x378 +CONFIG_KS0108_DELAY=2 +CONFIG_CFAG12864B=m +CONFIG_CFAG12864B_RATE=20 + +# +# Userspace I/O +# +CONFIG_UIO=m +CONFIG_UIO_CIF=m + +# +# Firmware Drivers +# +CONFIG_EDD=y +CONFIG_EDD_OFF=y +CONFIG_EFI_VARS=y +CONFIG_DELL_RBU=m +CONFIG_DCDBAS=m +CONFIG_DMIID=y + +# +# File systems +# +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=m +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_STATISTICS=y +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_NOLOCK=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_OCFS2_FS=m +CONFIG_OCFS2_DEBUG_MASKLOG=y +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_QUOTACTL=y +CONFIG_DNOTIFY=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=m +CONFIG_GENERIC_ACL=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m + +# +# Miscellaneous filesystems +# +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +CONFIG_CRAMFS=y +CONFIG_VXFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_UFS_DEBUG is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_XPRT_RDMA=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_WEAK_PW_HASH=y +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +CONFIG_CIFS_EXPERIMENTAL=y +CONFIG_CIFS_UPCALL=y +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +CONFIG_CODA_FS=m +# CONFIG_CODA_FS_OLD_API is not set +CONFIG_AFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_9P_FS=m +CONFIG_DEFAULT_RELATIME=y +CONFIG_DEFAULT_RELATIME_VAL=1 + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_CUMANA is not set +# CONFIG_ACORN_PARTITION_EESOX is not set +CONFIG_ACORN_PARTITION_ICS=y +# CONFIG_ACORN_PARTITION_ADFS is not set +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_ATARI_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +CONFIG_SGI_PARTITION=y +CONFIG_ULTRIX_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_SYSV68_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_INSTRUMENTATION=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=m +CONFIG_PROFILE_NMI=y +CONFIG_KPROBES=y +# CONFIG_MARKERS is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_PRINTK_TIME=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RTMUTEX_CHECK is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_RWLOCK_TORTURE_TEST is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_FORCED_INLINING is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_LKDTM is not set +# CONFIG_FAULT_INJECTION is not set +CONFIG_HAVE_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +# CONFIG_FTRACE is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_WAKEUP_LATENCY_HIST is not set +# CONFIG_PREEMPT_TRACE is not set +# CONFIG_SAMPLES is not set +CONFIG_NONPROMISC_DEVMEM=y +CONFIG_EARLY_PRINTK=y +# CONFIG_WRAPPER_PRINT is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set + +# +# Page alloc debug is incompatible with Software Suspend on i386 +# +CONFIG_DEBUG_RODATA=y +# CONFIG_4KSTACKS is not set +CONFIG_X86_FIND_SMP_CONFIG=y +CONFIG_X86_MPPARSE=y +CONFIG_DOUBLEFAULT=y +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +CONFIG_IO_DELAY_TYPE_NONE=3 +# CONFIG_IO_DELAY_0X80 is not set +CONFIG_IO_DELAY_0XED=y +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_DEFAULT_IO_DELAY_TYPE=1 + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +# CONFIG_SECURITY_APPARMOR_DISABLE is not set +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ABLKCIPHER=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_TWOFISH_586=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_AES_586=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_PADLOCK=y +CONFIG_CRYPTO_DEV_PADLOCK_AES=m +CONFIG_CRYPTO_DEV_PADLOCK_SHA=m +CONFIG_CRYPTO_DEV_GEODE=m +CONFIG_HAVE_KVM=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_INTEL=m +CONFIG_KVM_AMD=m +CONFIG_LGUEST=m +CONFIG_VIRTIO=m +CONFIG_VIRTIO_RING=m +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_BALLOON=m + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=m +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CHECK_SIGNATURE=y --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0209-preempt-realtime-arm-footbridge.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0209-preempt-realtime-arm-footbridge.patch @@ -0,0 +1,31 @@ +--- + arch/arm/mach-footbridge/netwinder-hw.c | 2 +- + arch/arm/mach-footbridge/netwinder-leds.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/arm/mach-footbridge/netwinder-hw.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mach-footbridge/netwinder-hw.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mach-footbridge/netwinder-hw.c 2009-02-08 00:02:21.000000000 -0500 +@@ -67,7 +67,7 @@ static inline void wb977_ww(int reg, int + /* + * This is a lock for accessing ports GP1_IO_BASE and GP2_IO_BASE + */ +-DEFINE_SPINLOCK(gpio_lock); ++DEFINE_RAW_SPINLOCK(gpio_lock); + + static unsigned int current_gpio_op; + static unsigned int current_gpio_io; +Index: linux-2.6.24.7-rt27/arch/arm/mach-footbridge/netwinder-leds.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mach-footbridge/netwinder-leds.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mach-footbridge/netwinder-leds.c 2009-02-08 00:02:21.000000000 -0500 +@@ -32,7 +32,7 @@ static char led_state; + static char hw_led_state; + + static DEFINE_SPINLOCK(leds_lock); +-extern spinlock_t gpio_lock; ++extern raw_spinlock_t gpio_lock; + + static void netwinder_leds_event(led_event_t evt) + { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0303-kmap-atomic-i386-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0303-kmap-atomic-i386-fix.patch @@ -0,0 +1,38 @@ +--- + arch/x86/mm/highmem_32.c | 2 +- + include/asm-x86/highmem.h | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/mm/highmem_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/mm/highmem_32.c 2009-02-08 00:03:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/mm/highmem_32.c 2009-02-08 00:03:14.000000000 -0500 +@@ -3,9 +3,9 @@ + + void *kmap(struct page *page) + { +- might_sleep(); + if (!PageHighMem(page)) + return page_address(page); ++ might_sleep(); + return kmap_high(page); + } + +Index: linux-2.6.24.7-rt27/include/asm-x86/highmem.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/highmem.h 2009-02-08 00:02:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/highmem.h 2009-02-08 00:03:14.000000000 -0500 +@@ -94,10 +94,10 @@ struct page *kmap_atomic_to_page(void *p + * on PREEMPT_RT kmap_atomic() is a wrapper that uses kmap(): + */ + #ifdef CONFIG_PREEMPT_RT +-# define kmap_atomic_prot(page, type, prot) kmap(page) +-# define kmap_atomic(page, type) kmap(page) ++# define kmap_atomic_prot(page, type, prot) ({ pagefault_disable(); kmap(page); }) ++# define kmap_atomic(page, type) ({ pagefault_disable(); kmap(page); }) + # define kmap_atomic_pfn(pfn, type) kmap(pfn_to_page(pfn)) +-# define kunmap_atomic(kvaddr, type) kunmap_virt(kvaddr) ++# define kunmap_atomic(kvaddr, type) do { pagefault_enable(); kunmap_virt(kvaddr); } while(0) + # define kmap_atomic_to_page(kvaddr) kmap_to_page(kvaddr) + #else + # define kmap_atomic_prot(page, type, prot) __kmap_atomic_prot(page, type, prot) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0079-ftrace-m68knommu-generic-stacktrace-function.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0079-ftrace-m68knommu-generic-stacktrace-function.patch @@ -0,0 +1,105 @@ +From 616acbc45cdc24f145edd2960f6f6a0a5c2579b6 Mon Sep 17 00:00:00 2001 +From: Sebastian Siewior +Date: Wed, 9 Jul 2008 13:36:37 +0200 +Subject: [PATCH] m68knommu: generic stacktrace function + +This provides the generic stack trace interface which is based +on x86 and required by ftrace. +A proper sollution will come once I unify this and the current +m68knommu stack trace algo. + +Signed-off-by: Sebastian Siewior +Signed-off-by: Thomas Gleixner +--- + arch/m68knommu/kernel/Makefile | 5 +- + arch/m68knommu/kernel/stacktrace.c | 69 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 72 insertions(+), 2 deletions(-) + create mode 100644 arch/m68knommu/kernel/stacktrace.c + +Index: linux-2.6.24.7-rt27/arch/m68knommu/kernel/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/kernel/Makefile 2009-02-08 00:00:24.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/kernel/Makefile 2009-02-08 00:01:20.000000000 -0500 +@@ -7,5 +7,6 @@ extra-y := vmlinux.lds + obj-y += dma.o entry.o init_task.o irq.o m68k_ksyms.o process.o ptrace.o \ + semaphore.o setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o + +-obj-$(CONFIG_MODULES) += module.o +-obj-$(CONFIG_COMEMPCI) += comempci.o ++obj-$(CONFIG_MODULES) += module.o ++obj-$(CONFIG_COMEMPCI) += comempci.o ++obj-$(CONFIG_STACKTRACE) += stacktrace.o +Index: linux-2.6.24.7-rt27/arch/m68knommu/kernel/stacktrace.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/m68knommu/kernel/stacktrace.c 2009-02-08 00:01:20.000000000 -0500 +@@ -0,0 +1,69 @@ ++/* ++ * Quick & dirty stacktrace implementation. ++ */ ++#include ++#include ++ ++typedef void (save_stack_addr_t)(void *data, unsigned long addr, int reliable); ++ ++static void save_stack_address(void *data, unsigned long addr, int reliable) ++{ ++ struct stack_trace *trace = data; ++ if (!reliable) ++ return; ++ if (trace->skip > 0) { ++ trace->skip--; ++ return; ++ } ++ if (trace->nr_entries < trace->max_entries) ++ trace->entries[trace->nr_entries++] = addr; ++} ++ ++static void print_context_stack(unsigned long *stack, ++ save_stack_addr_t *sstack_func, struct stack_trace *trace) ++{ ++ unsigned long *last_stack; ++ unsigned long *endstack; ++ unsigned long addr; ++ ++ addr = (unsigned long) stack; ++ endstack = (unsigned long *) PAGE_ALIGN(addr); ++ ++ last_stack = stack - 1; ++ while (stack <= endstack && stack > last_stack) { ++ ++ addr = *(stack + 1); ++ sstack_func(trace, addr, 1); ++ ++ last_stack = stack; ++ stack = (unsigned long *)*stack; ++ } ++} ++ ++static noinline long *get_current_stack(void) ++{ ++ unsigned long *stack; ++ ++ stack = (unsigned long *)&stack; ++ stack++; ++ return stack; ++} ++ ++static void save_current_stack(save_stack_addr_t *sstack_func, ++ struct stack_trace *trace) ++{ ++ unsigned long *stack; ++ ++ stack = get_current_stack(); ++ print_context_stack(stack, save_stack_address, trace); ++} ++ ++/* ++ * Save stack-backtrace addresses into a stack_trace buffer. ++ */ ++void save_stack_trace(struct stack_trace *trace) ++{ ++ save_current_stack(save_stack_address, trace); ++ if (trace->nr_entries < trace->max_entries) ++ trace->entries[trace->nr_entries++] = ULONG_MAX; ++} --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0566-tglx-01-ftrace-fix-task-state-print.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0566-tglx-01-ftrace-fix-task-state-print.patch @@ -0,0 +1,109 @@ +From tglx@linutronix.de Fri Dec 19 16:40:02 2008 +Date: Fri, 19 Dec 2008 21:22:44 -0000 +From: Thomas Gleixner +To: LKML +Cc: Ingo Molnar , Steven Rostedt , Peter Zijlstra , Clark Williams , Gregory Haskins , Linux-rt +Subject: [patch 1/7] ftrace: fix task state printout + +Impact: tracer task state decoding is wrong, size check is buggy + +The tracing code has interesting varieties of printing out task state. +Unfortunalely only one of the instances is correct as it copies the +code from sched.c:sched_show_task(). The others are plain wrong as +they treatthe bitfield as an integer offset into the character +array. Also the size check of the character array is wrong as it +includes the trailing \0. + +Use a common state decoder inline which does the Right Thing. + +Signed-off-by: Thomas Gleixner +--- + kernel/trace/trace.c | 40 ++++++++++++++++++---------------------- + 1 file changed, 18 insertions(+), 22 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/trace/trace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace.c 2009-02-08 00:05:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace.c 2009-02-08 00:05:21.000000000 -0500 +@@ -1626,6 +1626,13 @@ lat_print_timestamp(struct trace_seq *s, + + static const char state_to_char[] = TASK_STATE_TO_CHAR_STR; + ++static int task_state_char(unsigned long state) ++{ ++ int bit = state ? __ffs(state) + 1 : 0; ++ ++ return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?'; ++} ++ + extern unsigned long sys_call_table[NR_syscalls]; + + #if defined(CONFIG_COMPAT) && defined(CONFIG_X86) +@@ -1654,7 +1661,6 @@ print_lat_fmt(struct trace_iterator *ite + char *comm; + int S, T; + int i; +- unsigned state; + + if (!next_entry) + next_entry = entry; +@@ -1685,11 +1691,8 @@ print_lat_fmt(struct trace_iterator *ite + break; + case TRACE_CTX: + case TRACE_WAKE: +- T = entry->ctx.next_state < sizeof(state_to_char) ? +- state_to_char[entry->ctx.next_state] : 'X'; +- +- state = entry->ctx.prev_state ? __ffs(entry->ctx.prev_state) + 1 : 0; +- S = state < sizeof(state_to_char) - 1 ? state_to_char[state] : 'X'; ++ T = task_state_char(entry->ctx.next_state); ++ S = task_state_char(entry->ctx.prev_state); + comm = trace_find_cmdline(entry->ctx.next_pid); + trace_seq_printf(s, " %5d:%3d:%c %s %5d:%3d:%c %s\n", + entry->ctx.prev_pid, +@@ -1862,10 +1865,8 @@ static int print_trace_fmt(struct trace_ + break; + case TRACE_CTX: + case TRACE_WAKE: +- S = entry->ctx.prev_state < sizeof(state_to_char) ? +- state_to_char[entry->ctx.prev_state] : 'X'; +- T = entry->ctx.next_state < sizeof(state_to_char) ? +- state_to_char[entry->ctx.next_state] : 'X'; ++ T = task_state_char(entry->ctx.next_state); ++ S = task_state_char(entry->ctx.prev_state); + ret = trace_seq_printf(s, " %5d:%3d:%c %s %5d:%3d:%c\n", + entry->ctx.prev_pid, + entry->ctx.prev_prio, +@@ -2012,12 +2013,10 @@ static int print_raw_fmt(struct trace_it + break; + case TRACE_CTX: + case TRACE_WAKE: +- S = entry->ctx.prev_state < sizeof(state_to_char) ? +- state_to_char[entry->ctx.prev_state] : 'X'; +- T = entry->ctx.next_state < sizeof(state_to_char) ? +- state_to_char[entry->ctx.next_state] : 'X'; +- if (entry->type == TRACE_WAKE) +- S = '+'; ++ T = task_state_char(entry->ctx.next_state); ++ S = entry->type == TRACE_WAKE ? '+' : ++ task_state_char(entry->ctx.prev_state); ++ + ret = trace_seq_printf(s, "%d %d %c %d %d %c\n", + entry->ctx.prev_pid, + entry->ctx.prev_prio, +@@ -2073,12 +2072,9 @@ static int print_hex_fmt(struct trace_it + break; + case TRACE_CTX: + case TRACE_WAKE: +- S = entry->ctx.prev_state < sizeof(state_to_char) ? +- state_to_char[entry->ctx.prev_state] : 'X'; +- T = entry->ctx.next_state < sizeof(state_to_char) ? +- state_to_char[entry->ctx.next_state] : 'X'; +- if (entry->type == TRACE_WAKE) +- S = '+'; ++ T = task_state_char(entry->ctx.next_state); ++ S = entry->type == TRACE_WAKE ? '+' : ++ task_state_char(entry->ctx.prev_state); + SEQ_PUT_HEX_FIELD_RET(s, entry->ctx.prev_pid); + SEQ_PUT_HEX_FIELD_RET(s, entry->ctx.prev_prio); + SEQ_PUT_HEX_FIELD_RET(s, S); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0275-gtod-optimize.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0275-gtod-optimize.patch @@ -0,0 +1,22 @@ +--- + kernel/timer.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/timer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/timer.c 2009-02-08 00:02:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/timer.c 2009-02-08 00:02:58.000000000 -0500 +@@ -1012,6 +1012,13 @@ static inline void update_times(void) + static unsigned long last_tick = INITIAL_JIFFIES; + unsigned long ticks, flags; + ++ /* ++ * Dont take the xtime_lock from every CPU in ++ * every tick - only when needed: ++ */ ++ if (jiffies == last_tick) ++ return; ++ + write_seqlock_irqsave(&xtime_lock, flags); + ticks = jiffies - last_tick; + if (ticks) { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0300-kmap-atomic-prepare.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0300-kmap-atomic-prepare.patch @@ -0,0 +1,162 @@ + +With the separation of pagefault_{disable,enable}() from the preempt_count +a previously overlooked dependancy became painfully clear. + +kmap_atomic() is per cpu and relies not only on disabling the pagefault +handler, but really needs preemption disabled too. + +make this explicit now - so that we can change pagefault_disable(). + +Signed-off-by: Peter Zijlstra +--- + arch/mips/mm/highmem.c | 5 ++++- + arch/sparc/mm/highmem.c | 4 +++- + arch/x86/mm/highmem_32.c | 4 +++- + include/asm-frv/highmem.h | 2 ++ + include/asm-ppc/highmem.h | 4 +++- + 5 files changed, 15 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/mips/mm/highmem.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/mm/highmem.c 2009-02-07 23:59:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/mm/highmem.c 2009-02-08 00:03:13.000000000 -0500 +@@ -38,7 +38,7 @@ void *__kmap_atomic(struct page *page, e + enum fixed_addresses idx; + unsigned long vaddr; + +- /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ ++ preempt_disable(); + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); +@@ -63,6 +63,7 @@ void __kunmap_atomic(void *kvaddr, enum + + if (vaddr < FIXADDR_START) { // FIXME + pagefault_enable(); ++ preempt_enable(); + return; + } + +@@ -78,6 +79,7 @@ void __kunmap_atomic(void *kvaddr, enum + #endif + + pagefault_enable(); ++ preempt_enable(); + } + + /* +@@ -89,6 +91,7 @@ void *kmap_atomic_pfn(unsigned long pfn, + enum fixed_addresses idx; + unsigned long vaddr; + ++ preempt_disable(); + pagefault_disable(); + + idx = type + KM_TYPE_NR*smp_processor_id(); +Index: linux-2.6.24.7-rt27/arch/sparc/mm/highmem.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sparc/mm/highmem.c 2009-02-07 23:59:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sparc/mm/highmem.c 2009-02-08 00:03:13.000000000 -0500 +@@ -34,7 +34,7 @@ void *kmap_atomic(struct page *page, enu + unsigned long idx; + unsigned long vaddr; + +- /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ ++ preempt_disable(); + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); +@@ -71,6 +71,7 @@ void kunmap_atomic(void *kvaddr, enum km + + if (vaddr < FIXADDR_START) { // FIXME + pagefault_enable(); ++ preempt_enable(); + return; + } + +@@ -97,6 +98,7 @@ void kunmap_atomic(void *kvaddr, enum km + #endif + + pagefault_enable(); ++ preempt_enable(); + } + + /* We may be fed a pagetable here by ptep_to_xxx and others. */ +Index: linux-2.6.24.7-rt27/arch/x86/mm/highmem_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/mm/highmem_32.c 2009-02-08 00:02:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/mm/highmem_32.c 2009-02-08 00:03:13.000000000 -0500 +@@ -51,7 +51,7 @@ void *__kmap_atomic_prot(struct page *pa + enum fixed_addresses idx; + unsigned long vaddr; + +- /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ ++ preempt_disable(); + pagefault_disable(); + + if (!PageHighMem(page)) +@@ -93,6 +93,7 @@ void __kunmap_atomic(void *kvaddr, enum + + arch_flush_lazy_mmu_mode(); + pagefault_enable(); ++ preempt_enable(); + } + + /* This is the same as kmap_atomic() but can map memory that doesn't +@@ -103,6 +104,7 @@ void *__kmap_atomic_pfn(unsigned long pf + enum fixed_addresses idx; + unsigned long vaddr; + ++ preempt_disable(); + pagefault_disable(); + + idx = type + KM_TYPE_NR*smp_processor_id(); +Index: linux-2.6.24.7-rt27/include/asm-frv/highmem.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-frv/highmem.h 2009-02-07 23:59:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-frv/highmem.h 2009-02-08 00:03:13.000000000 -0500 +@@ -115,6 +115,7 @@ static inline void *kmap_atomic(struct p + { + unsigned long paddr; + ++ preempt_disable(); + pagefault_disable(); + paddr = page_to_phys(page); + +@@ -171,6 +172,7 @@ static inline void kunmap_atomic(void *k + BUG(); + } + pagefault_enable(); ++ preempt_enable(); + } + + #endif /* !__ASSEMBLY__ */ +Index: linux-2.6.24.7-rt27/include/asm-ppc/highmem.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-ppc/highmem.h 2009-02-07 23:59:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-ppc/highmem.h 2009-02-08 00:03:13.000000000 -0500 +@@ -78,7 +78,7 @@ static inline void *kmap_atomic(struct p + unsigned int idx; + unsigned long vaddr; + +- /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ ++ preempt_disable(); + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); +@@ -102,6 +102,7 @@ static inline void kunmap_atomic(void *k + + if (vaddr < KMAP_FIX_BEGIN) { // FIXME + pagefault_enable(); ++ preempt_enable(); + return; + } + +@@ -115,6 +116,7 @@ static inline void kunmap_atomic(void *k + flush_tlb_page(NULL, vaddr); + #endif + pagefault_enable(); ++ preempt_enable(); + } + + static inline struct page *kmap_atomic_to_page(void *ptr) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0549-1fb9b7d29d8e85ba3196eaa7ab871bf76fc98d36.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0549-1fb9b7d29d8e85ba3196eaa7ab871bf76fc98d36.patch @@ -0,0 +1,131 @@ +commit 1fb9b7d29d8e85ba3196eaa7ab871bf76fc98d36 +Author: Thomas Gleixner +Date: Wed Sep 3 21:37:14 2008 +0000 + + clockevents: prevent endless loop lockup + + The C1E/HPET bug reports on AMDX2/RS690 systems where tracked down to a + too small value of the HPET minumum delta for programming an event. + + The clockevents code needs to enforce an interrupt event on the clock event + device in some cases. The enforcement code was stupid and naive, as it just + added the minimum delta to the current time and tried to reprogram the device. + When the minimum delta is too small, then this loops forever. + + Add a sanity check. Allow reprogramming to fail 3 times, then print a warning + and double the minimum delta value to make sure, that this does not happen again. + Use the same function for both tick-oneshot and tick-broadcast code. + + Signed-off-by: Thomas Gleixner + Signed-off-by: Ingo Molnar + +--- + kernel/time/tick-broadcast.c | 10 +--------- + kernel/time/tick-internal.h | 2 ++ + kernel/time/tick-oneshot.c | 36 ++++++++++++++++++++++++++++++------ + 3 files changed, 33 insertions(+), 15 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/time/tick-broadcast.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-broadcast.c 2009-02-08 00:05:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-broadcast.c 2009-02-08 00:05:11.000000000 -0500 +@@ -373,16 +373,8 @@ cpumask_t *tick_get_broadcast_oneshot_ma + static int tick_broadcast_set_event(ktime_t expires, int force) + { + struct clock_event_device *bc = tick_broadcast_device.evtdev; +- ktime_t now = ktime_get(); +- int res; + +- for(;;) { +- res = clockevents_program_event(bc, expires, now); +- if (!res || !force) +- return res; +- now = ktime_get(); +- expires = ktime_add(now, ktime_set(0, bc->min_delta_ns)); +- } ++ return tick_dev_program_event(bc, expires, force); + } + + int tick_resume_broadcast_oneshot(struct clock_event_device *bc) +Index: linux-2.6.24.7-rt27/kernel/time/tick-internal.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-internal.h 2009-02-08 00:02:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-internal.h 2009-02-08 00:05:11.000000000 -0500 +@@ -17,6 +17,8 @@ extern void tick_handle_periodic(struct + extern void tick_setup_oneshot(struct clock_event_device *newdev, + void (*handler)(struct clock_event_device *), + ktime_t nextevt); ++extern int tick_dev_program_event(struct clock_event_device *dev, ++ ktime_t expires, int force); + extern int tick_program_event(ktime_t expires, int force); + extern void tick_oneshot_notify(void); + extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)); +Index: linux-2.6.24.7-rt27/kernel/time/tick-oneshot.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-oneshot.c 2009-02-08 00:05:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-oneshot.c 2009-02-08 00:05:11.000000000 -0500 +@@ -25,18 +25,42 @@ + /** + * tick_program_event internal worker function + */ +-static int __tick_program_event(struct clock_event_device *dev, +- ktime_t expires, int force) ++int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires, ++ int force) + { + ktime_t now = ktime_get(); ++ int i; + +- while (1) { ++ for (i = 0;;) { + int ret = clockevents_program_event(dev, expires, now); + + if (!ret || !force) + return ret; ++ ++ /* ++ * We tried 2 times to program the device with the given ++ * min_delta_ns. If that's not working then we double it ++ * and emit a warning. ++ */ ++ if (++i > 2) { ++ printk(KERN_WARNING "CE: __tick_program_event of %s is " ++ "stuck %llx %llx\n", dev->name ? dev->name : "?", ++ now.tv64, expires.tv64); ++ printk(KERN_WARNING ++ "CE: increasing min_delta_ns %ld to %ld nsec\n", ++ dev->min_delta_ns, dev->min_delta_ns << 1); ++ WARN_ON(1); ++ ++ /* Double the min. delta and try again */ ++ if (!dev->min_delta_ns) ++ dev->min_delta_ns = 5000; ++ else ++ dev->min_delta_ns <<= 1; ++ i = 0; ++ } ++ + now = ktime_get(); +- expires = ktime_add(now, ktime_set(0, dev->min_delta_ns)); ++ expires = ktime_add_ns(now, dev->min_delta_ns); + } + } + +@@ -47,7 +71,7 @@ int tick_program_event(ktime_t expires, + { + struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; + +- return __tick_program_event(dev, expires, force); ++ return tick_dev_program_event(dev, expires, force); + } + + /** +@@ -71,7 +95,7 @@ void tick_setup_oneshot(struct clock_eve + { + newdev->event_handler = handler; + clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); +- __tick_program_event(newdev, next_event, 1); ++ tick_dev_program_event(newdev, next_event, 1); + } + + /** --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0198-cputimer-thread-rt_A0.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0198-cputimer-thread-rt_A0.patch @@ -0,0 +1,306 @@ +Ingo, + This patch re-adds the posix-cpu-timer functionality by running it from +a per-cpu RT thread. This allows cpu rlimits to be enforced against RT +processes that would otherwise starve the system. + +thanks +-john + +Signed-off-by: John Stultz + + include/linux/init_task.h | 1 + include/linux/posix-timers.h | 2 + include/linux/sched.h | 2 + init/main.c | 2 + kernel/fork.c | 2 + kernel/posix-cpu-timers.c | 176 ++++++++++++++++++++++++++++++++++++++++++- + 6 files changed, 180 insertions(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/init_task.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/init_task.h 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/init_task.h 2009-02-08 00:02:16.000000000 -0500 +@@ -166,6 +166,7 @@ extern struct group_info init_groups; + .journal_info = NULL, \ + .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \ + .fs_excl = ATOMIC_INIT(0), \ ++ .posix_timer_list = NULL, \ + .pi_lock = RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock), \ + .pids = { \ + [PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID), \ +Index: linux-2.6.24.7-rt27/include/linux/posix-timers.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/posix-timers.h 2009-02-08 00:00:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/posix-timers.h 2009-02-08 00:02:16.000000000 -0500 +@@ -115,4 +115,6 @@ void set_process_cpu_timer(struct task_s + + long clock_nanosleep_restart(struct restart_block *restart_block); + ++int posix_cpu_thread_init(void); ++ + #endif +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:02:16.000000000 -0500 +@@ -1070,6 +1070,8 @@ struct task_struct { + unsigned long long it_sched_expires; + struct list_head cpu_timers[3]; + ++ struct task_struct* posix_timer_list; ++ + /* process credentials */ + uid_t uid,euid,suid,fsuid; + gid_t gid,egid,sgid,fsgid; +Index: linux-2.6.24.7-rt27/init/main.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/init/main.c 2009-02-08 00:01:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/init/main.c 2009-02-08 00:02:16.000000000 -0500 +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -753,6 +754,7 @@ static void __init do_pre_smp_initcalls( + extern int spawn_ksoftirqd(void); + + migration_init(); ++ posix_cpu_thread_init(); + spawn_ksoftirqd(); + if (!nosoftlockup) + spawn_softlockup_task(); +Index: linux-2.6.24.7-rt27/kernel/fork.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/fork.c 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/fork.c 2009-02-08 00:02:16.000000000 -0500 +@@ -1081,7 +1081,7 @@ static struct task_struct *copy_process( + INIT_LIST_HEAD(&p->cpu_timers[0]); + INIT_LIST_HEAD(&p->cpu_timers[1]); + INIT_LIST_HEAD(&p->cpu_timers[2]); +- ++ p->posix_timer_list = NULL; + p->lock_depth = -1; /* -1 = no lock */ + do_posix_clock_monotonic_gettime(&p->start_time); + p->real_start_time = p->start_time; +Index: linux-2.6.24.7-rt27/kernel/posix-cpu-timers.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/posix-cpu-timers.c 2009-02-08 00:00:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/posix-cpu-timers.c 2009-02-08 00:02:16.000000000 -0500 +@@ -578,7 +578,7 @@ static void arm_timer(struct k_itimer *t + p->cpu_timers : p->signal->cpu_timers); + head += CPUCLOCK_WHICH(timer->it_clock); + +- BUG_ON(!irqs_disabled()); ++ BUG_ON_NONRT(!irqs_disabled()); + spin_lock(&p->sighand->siglock); + + listpos = head; +@@ -735,7 +735,7 @@ int posix_cpu_timer_set(struct k_itimer + /* + * Disarm any old timer after extracting its expiry time. + */ +- BUG_ON(!irqs_disabled()); ++ BUG_ON_NONRT(!irqs_disabled()); + + ret = 0; + spin_lock(&p->sighand->siglock); +@@ -1287,12 +1287,11 @@ out: + * already updated our counts. We need to check if any timers fire now. + * Interrupts are disabled. + */ +-void run_posix_cpu_timers(struct task_struct *tsk) ++void __run_posix_cpu_timers(struct task_struct *tsk) + { + LIST_HEAD(firing); + struct k_itimer *timer, *next; + +- BUG_ON(!irqs_disabled()); + + #define UNEXPIRED(clock) \ + (cputime_eq(tsk->it_##clock##_expires, cputime_zero) || \ +@@ -1355,6 +1354,169 @@ void run_posix_cpu_timers(struct task_st + } + } + ++#include ++#include ++DEFINE_PER_CPU(struct task_struct *, posix_timer_task); ++DEFINE_PER_CPU(struct task_struct *, posix_timer_tasklist); ++ ++static int posix_cpu_timers_thread(void *data) ++{ ++ int cpu = (long)data; ++ ++ BUG_ON(per_cpu(posix_timer_task,cpu) != current); ++ ++ ++ while (!kthread_should_stop()) { ++ struct task_struct *tsk = NULL; ++ struct task_struct *next = NULL; ++ ++ if (cpu_is_offline(cpu)) { ++ goto wait_to_die; ++ } ++ ++ /* grab task list */ ++ raw_local_irq_disable(); ++ tsk = per_cpu(posix_timer_tasklist, cpu); ++ per_cpu(posix_timer_tasklist, cpu) = NULL; ++ raw_local_irq_enable(); ++ ++ ++ /* its possible the list is empty, just return */ ++ if (!tsk) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule(); ++ __set_current_state(TASK_RUNNING); ++ continue; ++ } ++ ++ /* Process task list */ ++ while (1) { ++ /* save next */ ++ next = tsk->posix_timer_list; ++ ++ /* run the task timers, clear its ptr and ++ * unreference it ++ */ ++ __run_posix_cpu_timers(tsk); ++ tsk->posix_timer_list = NULL; ++ put_task_struct(tsk); ++ ++ /* check if this is the last on the list */ ++ if (next == tsk) ++ break; ++ tsk = next; ++ } ++ } ++ return 0; ++ ++wait_to_die: ++ /* Wait for kthread_stop */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ while (!kthread_should_stop()) { ++ schedule(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ } ++ __set_current_state(TASK_RUNNING); ++ return 0; ++} ++ ++void run_posix_cpu_timers(struct task_struct *tsk) ++{ ++ unsigned long cpu = smp_processor_id(); ++ struct task_struct *tasklist; ++ ++ BUG_ON(!irqs_disabled()); ++ if(!per_cpu(posix_timer_task, cpu)) ++ return; ++ /* get per-cpu references */ ++ tasklist = per_cpu(posix_timer_tasklist, cpu); ++ ++ /* check to see if we're already queued */ ++ if (!tsk->posix_timer_list) { ++ get_task_struct(tsk); ++ if (tasklist) { ++ tsk->posix_timer_list = tasklist; ++ } else { ++ /* ++ * The list is terminated by a self-pointing ++ * task_struct ++ */ ++ tsk->posix_timer_list = tsk; ++ } ++ per_cpu(posix_timer_tasklist, cpu) = tsk; ++ } ++ /* XXX signal the thread somehow */ ++ wake_up_process(per_cpu(posix_timer_task,cpu)); ++} ++ ++ ++ ++ ++/* ++ * posix_cpu_thread_call - callback that gets triggered when a CPU is added. ++ * Here we can start up the necessary migration thread for the new CPU. ++ */ ++static int posix_cpu_thread_call(struct notifier_block *nfb, unsigned long action, ++ void *hcpu) ++{ ++ int cpu = (long)hcpu; ++ struct task_struct *p; ++ struct sched_param param; ++ ++ switch (action) { ++ case CPU_UP_PREPARE: ++ p = kthread_create(posix_cpu_timers_thread, hcpu, ++ "posix_cpu_timers/%d",cpu); ++ if (IS_ERR(p)) ++ return NOTIFY_BAD; ++ p->flags |= PF_NOFREEZE; ++ kthread_bind(p, cpu); ++ /* Must be high prio to avoid getting starved */ ++ param.sched_priority = MAX_RT_PRIO-1; ++ sched_setscheduler(p, SCHED_FIFO, ¶m); ++ per_cpu(posix_timer_task,cpu) = p; ++ break; ++ case CPU_ONLINE: ++ /* Strictly unneccessary, as first user will wake it. */ ++ wake_up_process(per_cpu(posix_timer_task,cpu)); ++ break; ++#ifdef CONFIG_HOTPLUG_CPU ++ case CPU_UP_CANCELED: ++ /* Unbind it from offline cpu so it can run. Fall thru. */ ++ kthread_bind(per_cpu(posix_timer_task,cpu), ++ any_online_cpu(cpu_online_map)); ++ kthread_stop(per_cpu(posix_timer_task,cpu)); ++ per_cpu(posix_timer_task,cpu) = NULL; ++ break; ++ case CPU_DEAD: ++ kthread_stop(per_cpu(posix_timer_task,cpu)); ++ per_cpu(posix_timer_task,cpu) = NULL; ++ break; ++#endif ++ } ++ return NOTIFY_OK; ++} ++ ++/* Register at highest priority so that task migration (migrate_all_tasks) ++ * happens before everything else. ++ */ ++static struct notifier_block __devinitdata posix_cpu_thread_notifier = { ++ .notifier_call = posix_cpu_thread_call, ++ .priority = 10 ++}; ++ ++int __init posix_cpu_thread_init(void) ++{ ++ void *cpu = (void *)(long)smp_processor_id(); ++ /* Start one for boot CPU. */ ++ posix_cpu_thread_call(&posix_cpu_thread_notifier, CPU_UP_PREPARE, cpu); ++ posix_cpu_thread_call(&posix_cpu_thread_notifier, CPU_ONLINE, cpu); ++ register_cpu_notifier(&posix_cpu_thread_notifier); ++ return 0; ++} ++ ++ ++ + /* + * Set one of the process-wide special case CPU timers. + * The tasklist_lock and tsk->sighand->siglock must be held by the caller. +@@ -1620,6 +1782,12 @@ static __init int init_posix_cpu_timers( + .nsleep = thread_cpu_nsleep, + .nsleep_restart = thread_cpu_nsleep_restart, + }; ++ unsigned long cpu; ++ ++ /* init the per-cpu posix_timer_tasklets */ ++ for_each_cpu_mask(cpu, cpu_possible_map) { ++ per_cpu(posix_timer_tasklist, cpu) = NULL; ++ } + + register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process); + register_posix_clock(CLOCK_THREAD_CPUTIME_ID, &thread); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0012-x86_64-ptrace_sign_extend_orig_rax_to_64bits.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0012-x86_64-ptrace_sign_extend_orig_rax_to_64bits.patch @@ -0,0 +1,54 @@ +Bugzilla: + +From: Clark Williams + +https://bugzilla.redhat.com/show_bug.cgi?id=437882 + +Description: +GDB testsuite failure for x86_64 debugger running i386 debuggee. +GDB sets orig_rax to 0x00000000ffffffff which is not recognized by +kernel as -1. +That bug is revealed by the fix of 434998. It could not happen +before. + +Solution: +Make ptrace always sign-extend orig_rax to 64 bits + +Upstream status: +commit 84c6f6046c5a2189160a8f0dca8b90427bf690ea + +Test status: +Built on all arch, tested on x86_64 using the reproducer provided on +bugzilla. + +Brew build (also includes patch for bz434998): +http://brewweb.devel.redhat.com/brew/taskinfo?taskID=1365281 + +Regards, +Jerome +--- + + arch/x86/kernel/ptrace_64.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/ptrace_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/ptrace_64.c 2009-02-08 00:00:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/ptrace_64.c 2009-02-08 00:00:47.000000000 -0500 +@@ -267,6 +267,16 @@ static int putreg(struct task_struct *ch + return -EIO; + child->thread.gs = value; + return 0; ++ case offsetof(struct user_regs_struct, orig_rax): ++ /* ++ * Orig_rax is really just a flag with small positive ++ * and negative values, so make sure to always ++ * sign-extend it from 32 bits so that it works ++ * correctly regardless of whether we come from a ++ * 32-bit environment or not. ++ */ ++ value = (long) (s32) value; ++ break; + case offsetof(struct user_regs_struct, eflags): + value &= FLAG_MASK; + tmp = get_stack_long(child, EFL_OFFSET); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0529-powerpc-make-the-irq-reverse-mapping-radix-tree-lockless.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0529-powerpc-make-the-irq-reverse-mapping-radix-tree-lockless.patch @@ -0,0 +1,207 @@ +Subject: powerpc - Make the irq reverse mapping radix tree + lockless +From: Sebastien Dugue +Date: Wed, 23 Jul 2008 17:01:02 +0200 +From: Sebastien Dugue +Date: Tue, 22 Jul 2008 11:56:41 +0200 +Subject: [PATCH][RT] powerpc - Make the irq reverse mapping radix tree lockless + + The radix tree used by interrupt controllers for their irq reverse mapping +(currently only the XICS found on pSeries) have a complex locking scheme +dating back to before the advent of the concurrent radix tree on preempt-rt. + + Take advantage of this and of the fact that the items of the tree are +pointers to a static array (irq_map) elements which can never go under us +to simplify the locking. + + Concurrency between readers and writers are handled by the intrinsic +properties of the concurrent radix tree. Concurrency between the tree +initialization which is done asynchronously with readers and writers access is +handled via an atomic variable (revmap_trees_allocated) set when the tree +has been initialized and checked before any reader or writer access just +like we used to check for tree.gfp_mask != 0 before. + +Signed-off-by: Sebastien Dugue +Cc: Tim Chavez +Cc: Jean Pierre Dion +Cc: linuxppc-dev@ozlabs.org +Cc: paulus@samba.org +Cc: Gilles Carry +Signed-off-by: Thomas Gleixner +Cc: Benjamin Herrenschmidt +Cc: Paul Mackerras + +--- + arch/powerpc/kernel/irq.c | 102 ++++++++++++---------------------------------- + 1 file changed, 27 insertions(+), 75 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/irq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/irq.c 2009-02-08 00:02:30.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/irq.c 2009-02-08 00:05:03.000000000 -0500 +@@ -404,8 +404,7 @@ void do_softirq(void) + + static LIST_HEAD(irq_hosts); + static DEFINE_RAW_SPINLOCK(irq_big_lock); +-static DEFINE_PER_CPU(unsigned int, irq_radix_reader); +-static unsigned int irq_radix_writer; ++static atomic_t revmap_trees_allocated = ATOMIC_INIT(0); + struct irq_map_entry irq_map[NR_IRQS]; + static unsigned int irq_virq_count = NR_IRQS; + static struct irq_host *irq_default_host; +@@ -548,57 +547,6 @@ void irq_set_virq_count(unsigned int cou + irq_virq_count = count; + } + +-/* radix tree not lockless safe ! we use a brlock-type mecanism +- * for now, until we can use a lockless radix tree +- */ +-static void irq_radix_wrlock(unsigned long *flags) +-{ +- unsigned int cpu, ok; +- +- spin_lock_irqsave(&irq_big_lock, *flags); +- irq_radix_writer = 1; +- smp_mb(); +- do { +- barrier(); +- ok = 1; +- for_each_possible_cpu(cpu) { +- if (per_cpu(irq_radix_reader, cpu)) { +- ok = 0; +- break; +- } +- } +- if (!ok) +- cpu_relax(); +- } while(!ok); +-} +- +-static void irq_radix_wrunlock(unsigned long flags) +-{ +- smp_wmb(); +- irq_radix_writer = 0; +- spin_unlock_irqrestore(&irq_big_lock, flags); +-} +- +-static void irq_radix_rdlock(unsigned long *flags) +-{ +- local_irq_save(*flags); +- __get_cpu_var(irq_radix_reader) = 1; +- smp_mb(); +- if (likely(irq_radix_writer == 0)) +- return; +- __get_cpu_var(irq_radix_reader) = 0; +- smp_wmb(); +- spin_lock(&irq_big_lock); +- __get_cpu_var(irq_radix_reader) = 1; +- spin_unlock(&irq_big_lock); +-} +- +-static void irq_radix_rdunlock(unsigned long flags) +-{ +- __get_cpu_var(irq_radix_reader) = 0; +- local_irq_restore(flags); +-} +- + static int irq_setup_virq(struct irq_host *host, unsigned int virq, + irq_hw_number_t hwirq) + { +@@ -753,7 +701,6 @@ void irq_dispose_mapping(unsigned int vi + { + struct irq_host *host; + irq_hw_number_t hwirq; +- unsigned long flags; + + if (virq == NO_IRQ) + return; +@@ -785,15 +732,20 @@ void irq_dispose_mapping(unsigned int vi + if (hwirq < host->revmap_data.linear.size) + host->revmap_data.linear.revmap[hwirq] = NO_IRQ; + break; +- case IRQ_HOST_MAP_TREE: ++ case IRQ_HOST_MAP_TREE: { ++ DEFINE_RADIX_TREE_CONTEXT(ctx, &host->revmap_data.tree); ++ + /* Check if radix tree allocated yet */ +- if (host->revmap_data.tree.gfp_mask == 0) ++ if (atomic_read(&revmap_trees_allocated) == 0) + break; +- irq_radix_wrlock(&flags); +- radix_tree_delete(&host->revmap_data.tree, hwirq); +- irq_radix_wrunlock(flags); ++ ++ radix_tree_lock(&ctx); ++ radix_tree_delete(ctx.tree, hwirq); ++ radix_tree_unlock(&ctx); ++ + break; + } ++ } + + /* Destroy map */ + smp_mb(); +@@ -846,22 +798,20 @@ unsigned int irq_radix_revmap(struct irq + struct radix_tree_root *tree; + struct irq_map_entry *ptr; + unsigned int virq; +- unsigned long flags; + + WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE); + +- /* Check if the radix tree exist yet. We test the value of +- * the gfp_mask for that. Sneaky but saves another int in the +- * structure. If not, we fallback to slow mode +- */ +- tree = &host->revmap_data.tree; +- if (tree->gfp_mask == 0) ++ /* Check if the radix tree exist yet. */ ++ if (atomic_read(&revmap_trees_allocated) == 0) + return irq_find_mapping(host, hwirq); + +- /* Now try to resolve */ +- irq_radix_rdlock(&flags); ++ /* ++ * Now try to resolve ++ * No rcu_read_lock(ing) needed, the ptr returned can't go under us ++ * as it's referencing an entry in the static irq_map table. ++ */ ++ tree = &host->revmap_data.tree; + ptr = radix_tree_lookup(tree, hwirq); +- irq_radix_rdunlock(flags); + + /* Found it, return */ + if (ptr) { +@@ -872,9 +822,10 @@ unsigned int irq_radix_revmap(struct irq + /* If not there, try to insert it */ + virq = irq_find_mapping(host, hwirq); + if (virq != NO_IRQ) { +- irq_radix_wrlock(&flags); +- radix_tree_insert(tree, hwirq, &irq_map[virq]); +- irq_radix_wrunlock(flags); ++ DEFINE_RADIX_TREE_CONTEXT(ctx, tree); ++ radix_tree_lock(&ctx); ++ radix_tree_insert(ctx.tree, hwirq, &irq_map[virq]); ++ radix_tree_unlock(&ctx); + } + return virq; + } +@@ -985,14 +936,15 @@ void irq_early_init(void) + static int irq_late_init(void) + { + struct irq_host *h; +- unsigned long flags; + +- irq_radix_wrlock(&flags); + list_for_each_entry(h, &irq_hosts, link) { + if (h->revmap_type == IRQ_HOST_MAP_TREE) + INIT_RADIX_TREE(&h->revmap_data.tree, GFP_ATOMIC); + } +- irq_radix_wrunlock(flags); ++ ++ /* Make sure the radix trees inits are visible before setting the flag */ ++ smp_mb(); ++ atomic_set(&revmap_trees_allocated, 1); + + return 0; + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0244-preempt-realtime-ipc.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0244-preempt-realtime-ipc.patch @@ -0,0 +1,111 @@ +--- + ipc/mqueue.c | 5 +++++ + ipc/msg.c | 25 +++++++++++++++++++------ + ipc/sem.c | 6 ++++++ + 3 files changed, 30 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/ipc/mqueue.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/ipc/mqueue.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/ipc/mqueue.c 2009-02-08 00:02:41.000000000 -0500 +@@ -779,12 +779,17 @@ static inline void pipelined_send(struct + struct msg_msg *message, + struct ext_wait_queue *receiver) + { ++ /* ++ * Keep them in one critical section for PREEMPT_RT: ++ */ ++ preempt_disable(); + receiver->msg = message; + list_del(&receiver->list); + receiver->state = STATE_PENDING; + wake_up_process(receiver->task); + smp_wmb(); + receiver->state = STATE_READY; ++ preempt_enable(); + } + + /* pipelined_receive() - if there is task waiting in sys_mq_timedsend() +Index: linux-2.6.24.7-rt27/ipc/msg.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/ipc/msg.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/ipc/msg.c 2009-02-08 00:02:41.000000000 -0500 +@@ -261,12 +261,19 @@ static void expunge_all(struct msg_queue + while (tmp != &msq->q_receivers) { + struct msg_receiver *msr; + ++ /* ++ * Make sure that the wakeup doesnt preempt ++ * this CPU prematurely. (on PREEMPT_RT) ++ */ ++ preempt_disable(); ++ + msr = list_entry(tmp, struct msg_receiver, r_list); + tmp = tmp->next; + msr->r_msg = NULL; +- wake_up_process(msr->r_tsk); +- smp_mb(); ++ wake_up_process(msr->r_tsk); /* serializes */ + msr->r_msg = ERR_PTR(res); ++ ++ preempt_enable(); + } + } + +@@ -637,22 +644,28 @@ static inline int pipelined_send(struct + !security_msg_queue_msgrcv(msq, msg, msr->r_tsk, + msr->r_msgtype, msr->r_mode)) { + ++ /* ++ * Make sure that the wakeup doesnt preempt ++ * this CPU prematurely. (on PREEMPT_RT) ++ */ ++ preempt_disable(); ++ + list_del(&msr->r_list); + if (msr->r_maxsize < msg->m_ts) { + msr->r_msg = NULL; +- wake_up_process(msr->r_tsk); +- smp_mb(); ++ wake_up_process(msr->r_tsk); /* serializes */ + msr->r_msg = ERR_PTR(-E2BIG); + } else { + msr->r_msg = NULL; + msq->q_lrpid = task_pid_vnr(msr->r_tsk); + msq->q_rtime = get_seconds(); +- wake_up_process(msr->r_tsk); +- smp_mb(); ++ wake_up_process(msr->r_tsk); /* serializes */ + msr->r_msg = msg; ++ preempt_enable(); + + return 1; + } ++ preempt_enable(); + } + } + return 0; +Index: linux-2.6.24.7-rt27/ipc/sem.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/ipc/sem.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/ipc/sem.c 2009-02-08 00:02:41.000000000 -0500 +@@ -467,6 +467,11 @@ static void update_queue (struct sem_arr + if (error <= 0) { + struct sem_queue *n; + remove_from_queue(sma,q); ++ /* ++ * make sure that the wakeup doesnt preempt ++ * _this_ cpu prematurely. (on preempt_rt) ++ */ ++ preempt_disable(); + q->status = IN_WAKEUP; + /* + * Continue scanning. The next operation +@@ -489,6 +494,7 @@ static void update_queue (struct sem_arr + */ + smp_wmb(); + q->status = error; ++ preempt_enable(); + q = n; + } else { + q = q->next; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0287-2.6.21-rc6-lockless3-radix-tree-gang-slot-lookups.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0287-2.6.21-rc6-lockless3-radix-tree-gang-slot-lookups.patch @@ -0,0 +1,319 @@ +From: Nick Piggin +Subject: [patch 3/9] radix-tree: gang slot lookups + +Introduce gang_lookup_slot and gang_lookup_slot_tag functions, which are used +by lockless pagecache. + +Signed-off-by: Nick Piggin + +--- + include/linux/radix-tree.h | 12 ++- + lib/radix-tree.c | 176 +++++++++++++++++++++++++++++++++++++++------ + 2 files changed, 166 insertions(+), 22 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/radix-tree.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/radix-tree.h 2009-02-08 00:02:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/radix-tree.h 2009-02-08 00:03:04.000000000 -0500 +@@ -99,12 +99,15 @@ do { \ + * + * The notable exceptions to this rule are the following functions: + * radix_tree_lookup ++ * radix_tree_lookup_slot + * radix_tree_tag_get + * radix_tree_gang_lookup ++ * radix_tree_gang_lookup_slot + * radix_tree_gang_lookup_tag ++ * radix_tree_gang_lookup_tag_slot + * radix_tree_tagged + * +- * The first 4 functions are able to be called locklessly, using RCU. The ++ * The first 7 functions are able to be called locklessly, using RCU. The + * caller must ensure calls to these functions are made within rcu_read_lock() + * regions. Other readers (lock-free or otherwise) and modifications may be + * running concurrently. +@@ -159,6 +162,9 @@ void *radix_tree_delete(struct radix_tre + unsigned int + radix_tree_gang_lookup(struct radix_tree_root *root, void **results, + unsigned long first_index, unsigned int max_items); ++unsigned int ++radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results, ++ unsigned long first_index, unsigned int max_items); + unsigned long radix_tree_next_hole(struct radix_tree_root *root, + unsigned long index, unsigned long max_scan); + /* +@@ -184,6 +190,10 @@ unsigned int + radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, + unsigned long first_index, unsigned int max_items, + unsigned int tag); ++unsigned int ++radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results, ++ unsigned long first_index, unsigned int max_items, ++ unsigned int tag); + int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag); + + static inline void radix_tree_preload_end(void) +Index: linux-2.6.24.7-rt27/lib/radix-tree.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/radix-tree.c 2009-02-08 00:02:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/radix-tree.c 2009-02-08 00:03:04.000000000 -0500 +@@ -350,18 +350,17 @@ EXPORT_SYMBOL(radix_tree_insert); + * Returns: the slot corresponding to the position @index in the + * radix tree @root. This is useful for update-if-exists operations. + * +- * This function cannot be called under rcu_read_lock, it must be +- * excluded from writers, as must the returned slot for subsequent +- * use by radix_tree_deref_slot() and radix_tree_replace slot. +- * Caller must hold tree write locked across slot lookup and +- * replace. ++ * This function can be called under rcu_read_lock iff the slot is not ++ * modified by radix_tree_replace_slot, otherwise it must be called ++ * exclusive from other writers. Any dereference of the slot must be done ++ * using radix_tree_deref_slot. + */ + void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) + { + unsigned int height, shift; + struct radix_tree_node *node, **slot; + +- node = root->rnode; ++ node = rcu_dereference(root->rnode); + if (node == NULL) + return NULL; + +@@ -381,7 +380,7 @@ void **radix_tree_lookup_slot(struct rad + do { + slot = (struct radix_tree_node **) + (node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK)); +- node = *slot; ++ node = rcu_dereference(*slot); + if (node == NULL) + return NULL; + +@@ -658,7 +657,7 @@ unsigned long radix_tree_next_hole(struc + EXPORT_SYMBOL(radix_tree_next_hole); + + static unsigned int +-__lookup(struct radix_tree_node *slot, void **results, unsigned long index, ++__lookup(struct radix_tree_node *slot, void ***results, unsigned long index, + unsigned int max_items, unsigned long *next_index) + { + unsigned int nr_found = 0; +@@ -692,11 +691,9 @@ __lookup(struct radix_tree_node *slot, v + + /* Bottom level: grab some items */ + for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) { +- struct radix_tree_node *node; + index++; +- node = slot->slots[i]; +- if (node) { +- results[nr_found++] = rcu_dereference(node); ++ if (slot->slots[i]) { ++ results[nr_found++] = &(slot->slots[i]); + if (nr_found == max_items) + goto out; + } +@@ -750,13 +747,22 @@ radix_tree_gang_lookup(struct radix_tree + + ret = 0; + while (ret < max_items) { +- unsigned int nr_found; ++ unsigned int nr_found, slots_found, i; + unsigned long next_index; /* Index of next search */ + + if (cur_index > max_index) + break; +- nr_found = __lookup(node, results + ret, cur_index, ++ slots_found = __lookup(node, (void ***)results + ret, cur_index, + max_items - ret, &next_index); ++ nr_found = 0; ++ for (i = 0; i < slots_found; i++) { ++ struct radix_tree_node *slot; ++ slot = *(((void ***)results)[ret + i]); ++ if (!slot) ++ continue; ++ results[ret + nr_found] = rcu_dereference(slot); ++ nr_found++; ++ } + ret += nr_found; + if (next_index == 0) + break; +@@ -767,12 +773,71 @@ radix_tree_gang_lookup(struct radix_tree + } + EXPORT_SYMBOL(radix_tree_gang_lookup); + ++/** ++ * radix_tree_gang_lookup_slot - perform multiple slot lookup on radix tree ++ * @root: radix tree root ++ * @results: where the results of the lookup are placed ++ * @first_index: start the lookup from this key ++ * @max_items: place up to this many items at *results ++ * ++ * Performs an index-ascending scan of the tree for present items. Places ++ * their slots at *@results and returns the number of items which were ++ * placed at *@results. ++ * ++ * The implementation is naive. ++ * ++ * Like radix_tree_gang_lookup as far as RCU and locking goes. Slots must ++ * be dereferenced with radix_tree_deref_slot, and if using only RCU ++ * protection, radix_tree_deref_slot may fail requiring a retry. ++ */ ++unsigned int ++radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results, ++ unsigned long first_index, unsigned int max_items) ++{ ++ unsigned long max_index; ++ struct radix_tree_node *node; ++ unsigned long cur_index = first_index; ++ unsigned int ret; ++ ++ node = rcu_dereference(root->rnode); ++ if (!node) ++ return 0; ++ ++ if (!radix_tree_is_indirect_ptr(node)) { ++ if (first_index > 0) ++ return 0; ++ results[0] = (void **)&root->rnode; ++ return 1; ++ } ++ node = radix_tree_indirect_to_ptr(node); ++ ++ max_index = radix_tree_maxindex(node->height); ++ ++ ret = 0; ++ while (ret < max_items) { ++ unsigned int slots_found; ++ unsigned long next_index; /* Index of next search */ ++ ++ if (cur_index > max_index) ++ break; ++ slots_found = __lookup(node, results + ret, cur_index, ++ max_items - ret, &next_index); ++ ret += slots_found; ++ if (next_index == 0) ++ break; ++ cur_index = next_index; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(radix_tree_gang_lookup_slot); ++ + /* + * FIXME: the two tag_get()s here should use find_next_bit() instead of + * open-coding the search. + */ + static unsigned int +-__lookup_tag(struct radix_tree_node *slot, void **results, unsigned long index, ++__lookup_tag(struct radix_tree_node *slot, void ***results, unsigned long index, + unsigned int max_items, unsigned long *next_index, unsigned int tag) + { + unsigned int nr_found = 0; +@@ -817,9 +882,8 @@ __lookup_tag(struct radix_tree_node *slo + * lookup ->slots[x] without a lock (ie. can't + * rely on its value remaining the same). + */ +- if (node) { +- node = rcu_dereference(node); +- results[nr_found++] = node; ++ if (slot->slots[j]) { ++ results[nr_found++] = &slot->slots[j]; + if (nr_found == max_items) + goto out; + } +@@ -878,13 +942,22 @@ radix_tree_gang_lookup_tag(struct radix_ + + ret = 0; + while (ret < max_items) { +- unsigned int nr_found; ++ unsigned int slots_found, nr_found, i; + unsigned long next_index; /* Index of next search */ + + if (cur_index > max_index) + break; +- nr_found = __lookup_tag(node, results + ret, cur_index, +- max_items - ret, &next_index, tag); ++ slots_found = __lookup_tag(node, (void ***)results + ret, ++ cur_index, max_items - ret, &next_index, tag); ++ nr_found = 0; ++ for (i = 0; i < slots_found; i++) { ++ struct radix_tree_node *slot; ++ slot = *((void ***)results)[ret + i]; ++ if (!slot) ++ continue; ++ results[ret + nr_found] = rcu_dereference(slot); ++ nr_found++; ++ } + ret += nr_found; + if (next_index == 0) + break; +@@ -896,6 +969,67 @@ radix_tree_gang_lookup_tag(struct radix_ + EXPORT_SYMBOL(radix_tree_gang_lookup_tag); + + /** ++ * radix_tree_gang_lookup_tag_slot - perform multiple slot lookup on a ++ * radix tree based on a tag ++ * @root: radix tree root ++ * @results: where the results of the lookup are placed ++ * @first_index: start the lookup from this key ++ * @max_items: place up to this many items at *results ++ * @tag: the tag index (< RADIX_TREE_MAX_TAGS) ++ * ++ * Performs an index-ascending scan of the tree for present items which ++ * have the tag indexed by @tag set. Places the slots at *@results and ++ * returns the number of slots which were placed at *@results. ++ */ ++unsigned int ++radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results, ++ unsigned long first_index, unsigned int max_items, ++ unsigned int tag) ++{ ++ struct radix_tree_node *node; ++ unsigned long max_index; ++ unsigned long cur_index = first_index; ++ unsigned int ret; ++ ++ /* check the root's tag bit */ ++ if (!root_tag_get(root, tag)) ++ return 0; ++ ++ node = rcu_dereference(root->rnode); ++ if (!node) ++ return 0; ++ ++ if (!radix_tree_is_indirect_ptr(node)) { ++ if (first_index > 0) ++ return 0; ++ results[0] = (void **)&root->rnode; ++ return 1; ++ } ++ node = radix_tree_indirect_to_ptr(node); ++ ++ max_index = radix_tree_maxindex(node->height); ++ ++ ret = 0; ++ while (ret < max_items) { ++ unsigned int slots_found; ++ unsigned long next_index; /* Index of next search */ ++ ++ if (cur_index > max_index) ++ break; ++ slots_found = __lookup_tag(node, results + ret, ++ cur_index, max_items - ret, &next_index, tag); ++ ret += slots_found; ++ if (next_index == 0) ++ break; ++ cur_index = next_index; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(radix_tree_gang_lookup_tag_slot); ++ ++ ++/** + * radix_tree_shrink - shrink height of a radix tree to minimal + * @root radix tree root + */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0236-preempt-realtime-mmdrop-delayed.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0236-preempt-realtime-mmdrop-delayed.patch @@ -0,0 +1,261 @@ +--- + include/linux/mm_types.h | 3 + + include/linux/sched.h | 8 ++ + kernel/fork.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++ + kernel/sched.c | 6 +- + 4 files changed, 155 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/include/linux/mm_types.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/mm_types.h 2009-02-07 23:59:58.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/mm_types.h 2009-02-08 00:02:37.000000000 -0500 +@@ -199,6 +199,9 @@ struct mm_struct { + /* Architecture-specific MM context */ + mm_context_t context; + ++ /* realtime bits */ ++ struct list_head delayed_drop; ++ + /* Swap token stuff */ + /* + * Last value of global fault stamp as seen by this process. +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:02:37.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:02:37.000000000 -0500 +@@ -1789,12 +1789,20 @@ extern struct mm_struct * mm_alloc(void) + + /* mmdrop drops the mm and the page tables */ + extern void FASTCALL(__mmdrop(struct mm_struct *)); ++extern void FASTCALL(__mmdrop_delayed(struct mm_struct *)); ++ + static inline void mmdrop(struct mm_struct * mm) + { + if (unlikely(atomic_dec_and_test(&mm->mm_count))) + __mmdrop(mm); + } + ++static inline void mmdrop_delayed(struct mm_struct * mm) ++{ ++ if (atomic_dec_and_test(&mm->mm_count)) ++ __mmdrop_delayed(mm); ++} ++ + /* mmput gets rid of the mappings and all user-space */ + extern void mmput(struct mm_struct *); + /* Grab a reference to a task's mm, if it is not already going away */ +Index: linux-2.6.24.7-rt27/kernel/fork.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/fork.c 2009-02-08 00:02:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/fork.c 2009-02-08 00:02:37.000000000 -0500 +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -41,6 +42,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -71,6 +74,15 @@ DEFINE_PER_CPU(unsigned long, process_co + + __cacheline_aligned DEFINE_RWLOCK(tasklist_lock); /* outer */ + ++/* ++ * Delayed mmdrop. In the PREEMPT_RT case we ++ * dont want to do this from the scheduling ++ * context. ++ */ ++static DEFINE_PER_CPU(struct task_struct *, desched_task); ++ ++static DEFINE_PER_CPU(struct list_head, delayed_drop_list); ++ + int nr_processes(void) + { + int cpu; +@@ -132,6 +144,8 @@ void __put_task_struct(struct task_struc + + void __init fork_init(unsigned long mempages) + { ++ int i; ++ + #ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR + #ifndef ARCH_MIN_TASKALIGN + #define ARCH_MIN_TASKALIGN L1_CACHE_BYTES +@@ -159,6 +173,9 @@ void __init fork_init(unsigned long memp + init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2; + init_task.signal->rlim[RLIMIT_SIGPENDING] = + init_task.signal->rlim[RLIMIT_NPROC]; ++ ++ for (i = 0; i < NR_CPUS; i++) ++ INIT_LIST_HEAD(&per_cpu(delayed_drop_list, i)); + } + + static struct task_struct *dup_task_struct(struct task_struct *orig) +@@ -354,6 +371,7 @@ static struct mm_struct * mm_init(struct + spin_lock_init(&mm->page_table_lock); + rwlock_init(&mm->ioctx_list_lock); + mm->ioctx_list = NULL; ++ INIT_LIST_HEAD(&mm->delayed_drop); + mm->free_area_cache = TASK_UNMAPPED_BASE; + mm->cached_hole_size = ~0UL; + +@@ -1312,7 +1330,9 @@ static struct task_struct *copy_process( + attach_pid(p, PIDTYPE_PGID, task_pgrp(current)); + attach_pid(p, PIDTYPE_SID, task_session(current)); + list_add_tail_rcu(&p->tasks, &init_task.tasks); ++ preempt_disable(); + __get_cpu_var(process_counts)++; ++ preempt_enable(); + } + attach_pid(p, PIDTYPE_PID, pid); + nr_threads++; +@@ -1743,3 +1763,122 @@ bad_unshare_cleanup_thread: + bad_unshare_out: + return err; + } ++ ++static int mmdrop_complete(void) ++{ ++ struct list_head *head; ++ int ret = 0; ++ ++ head = &get_cpu_var(delayed_drop_list); ++ while (!list_empty(head)) { ++ struct mm_struct *mm = list_entry(head->next, ++ struct mm_struct, delayed_drop); ++ list_del(&mm->delayed_drop); ++ put_cpu_var(delayed_drop_list); ++ ++ __mmdrop(mm); ++ ret = 1; ++ ++ head = &get_cpu_var(delayed_drop_list); ++ } ++ put_cpu_var(delayed_drop_list); ++ ++ return ret; ++} ++ ++/* ++ * We dont want to do complex work from the scheduler, thus ++ * we delay the work to a per-CPU worker thread: ++ */ ++void fastcall __mmdrop_delayed(struct mm_struct *mm) ++{ ++ struct task_struct *desched_task; ++ struct list_head *head; ++ ++ head = &get_cpu_var(delayed_drop_list); ++ list_add_tail(&mm->delayed_drop, head); ++ desched_task = __get_cpu_var(desched_task); ++ if (desched_task) ++ wake_up_process(desched_task); ++ put_cpu_var(delayed_drop_list); ++} ++ ++static int desched_thread(void * __bind_cpu) ++{ ++ set_user_nice(current, -10); ++ current->flags |= PF_NOFREEZE | PF_SOFTIRQ; ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ while (!kthread_should_stop()) { ++ ++ if (mmdrop_complete()) ++ continue; ++ schedule(); ++ ++ /* This must be called from time to time on ia64, and is a no-op on other archs. ++ * Used to be in cpu_idle(), but with the new -rt semantics it can't stay there. ++ */ ++ check_pgt_cache(); ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ } ++ __set_current_state(TASK_RUNNING); ++ return 0; ++} ++ ++static int __devinit cpu_callback(struct notifier_block *nfb, ++ unsigned long action, ++ void *hcpu) ++{ ++ int hotcpu = (unsigned long)hcpu; ++ struct task_struct *p; ++ ++ switch (action) { ++ case CPU_UP_PREPARE: ++ ++ BUG_ON(per_cpu(desched_task, hotcpu)); ++ INIT_LIST_HEAD(&per_cpu(delayed_drop_list, hotcpu)); ++ p = kthread_create(desched_thread, hcpu, "desched/%d", hotcpu); ++ if (IS_ERR(p)) { ++ printk("desched_thread for %i failed\n", hotcpu); ++ return NOTIFY_BAD; ++ } ++ per_cpu(desched_task, hotcpu) = p; ++ kthread_bind(p, hotcpu); ++ break; ++ case CPU_ONLINE: ++ ++ wake_up_process(per_cpu(desched_task, hotcpu)); ++ break; ++#ifdef CONFIG_HOTPLUG_CPU ++ case CPU_UP_CANCELED: ++ ++ /* Unbind so it can run. Fall thru. */ ++ kthread_bind(per_cpu(desched_task, hotcpu), smp_processor_id()); ++ case CPU_DEAD: ++ ++ p = per_cpu(desched_task, hotcpu); ++ per_cpu(desched_task, hotcpu) = NULL; ++ kthread_stop(p); ++ takeover_tasklets(hotcpu); ++ break; ++#endif /* CONFIG_HOTPLUG_CPU */ ++ } ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block __devinitdata cpu_nfb = { ++ .notifier_call = cpu_callback ++}; ++ ++__init int spawn_desched_task(void) ++{ ++ void *cpu = (void *)(long)smp_processor_id(); ++ ++ cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu); ++ cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); ++ register_cpu_notifier(&cpu_nfb); ++ return 0; ++} ++ +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:02:37.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:02:37.000000000 -0500 +@@ -2047,8 +2047,12 @@ static void finish_task_switch(struct rq + #endif + + fire_sched_in_preempt_notifiers(current); ++ /* ++ * Delay the final freeing of the mm or task, so that we dont have ++ * to do complex work from within the scheduler: ++ */ + if (mm) +- mmdrop(mm); ++ mmdrop_delayed(mm); + if (unlikely(prev_state == TASK_DEAD)) { + /* + * Remove function-return probe instances associated with this --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0537-nfs-stats-miss-preemption.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0537-nfs-stats-miss-preemption.patch @@ -0,0 +1,36 @@ +Subject: nfs: fix missing preemption check +From: Thomas Gleixner +Date: Sun, 27 Jul 2008 00:54:19 +0200 + +NFS iostats use get_cpu()/put_cpu_no_preempt(). That misses a +preemption check for no good reason and introduces long latencies when +a wakeup of a higher priority task happens in the preempt disabled +region. + +Signed-off-by: Thomas Gleixner +--- + fs/nfs/iostat.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/fs/nfs/iostat.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/nfs/iostat.h 2009-02-07 23:59:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/nfs/iostat.h 2009-02-08 00:05:06.000000000 -0500 +@@ -125,7 +125,7 @@ static inline void nfs_inc_server_stats( + cpu = get_cpu(); + iostats = per_cpu_ptr(server->io_stats, cpu); + iostats->events[stat] ++; +- put_cpu_no_resched(); ++ put_cpu(); + } + + static inline void nfs_inc_stats(struct inode *inode, enum nfs_stat_eventcounters stat) +@@ -141,7 +141,7 @@ static inline void nfs_add_server_stats( + cpu = get_cpu(); + iostats = per_cpu_ptr(server->io_stats, cpu); + iostats->bytes[stat] += addend; +- put_cpu_no_resched(); ++ put_cpu(); + } + + static inline void nfs_add_stats(struct inode *inode, enum nfs_stat_bytecounters stat, unsigned long addend) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0299-mm-concurrent-pagecache-rt.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0299-mm-concurrent-pagecache-rt.patch @@ -0,0 +1,151 @@ +Subject: mm: -rt bits for concurrent pagecache + + +Signed-off-by: Peter Zijlstra +--- + include/linux/pagemap.h | 62 ++++++++++++++++++++++++++++++++++++++++++++---- + mm/filemap.c | 17 ++----------- + 2 files changed, 60 insertions(+), 19 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/pagemap.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/pagemap.h 2009-02-08 00:03:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/pagemap.h 2009-02-08 00:03:12.000000000 -0500 +@@ -15,6 +15,9 @@ + #include + #include /* for in_interrupt() */ + #include ++#include ++#include ++#include + + /* + * Bits in mapping->flags. The lower __GFP_BITS_SHIFT bits are the page +@@ -65,6 +68,26 @@ static inline void mapping_set_gfp_mask( + #define page_cache_release(page) put_page(page) + void release_pages(struct page **pages, int nr, int cold); + ++/* ++ * In order to wait for pages to become available there must be ++ * waitqueues associated with pages. By using a hash table of ++ * waitqueues where the bucket discipline is to maintain all ++ * waiters on the same queue and wake all when any of the pages ++ * become available, and for the woken contexts to check to be ++ * sure the appropriate page became available, this saves space ++ * at a cost of "thundering herd" phenomena during rare hash ++ * collisions. ++ */ ++static inline wait_queue_head_t *page_waitqueue(struct page *page) ++{ ++ const struct zone *zone = page_zone(page); ++ ++ return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)]; ++} ++ ++extern int __sleep_on_page(void *); ++ ++#ifndef CONFIG_PREEMPT_RT + static inline void lock_page_ref(struct page *page) + { + bit_spin_lock(PG_nonewrefs, &page->flags); +@@ -81,29 +104,58 @@ static inline void wait_on_page_ref(stru + while (unlikely(test_bit(PG_nonewrefs, &page->flags))) + cpu_relax(); + } ++#else // CONFIG_PREEMPT_RT ++static inline void wait_on_page_ref(struct page *page) ++{ ++ might_sleep(); ++ if (unlikely(PageNoNewRefs(page))) { ++ DEFINE_WAIT_BIT(wait, &page->flags, PG_nonewrefs); ++ __wait_on_bit(page_waitqueue(page), &wait, __sleep_on_page, ++ TASK_UNINTERRUPTIBLE); ++ } ++} ++ ++static inline void lock_page_ref(struct page *page) ++{ ++ while (test_and_set_bit(PG_nonewrefs, &page->flags)) ++ wait_on_page_ref(page); ++ __acquire(bitlock); ++ smp_wmb(); ++} ++ ++static inline void unlock_page_ref(struct page *page) ++{ ++ VM_BUG_ON(!PageNoNewRefs(page)); ++ smp_mb__before_clear_bit(); ++ ClearPageNoNewRefs(page); ++ smp_mb__after_clear_bit(); ++ __wake_up_bit(page_waitqueue(page), &page->flags, PG_nonewrefs); ++ __release(bitlock); ++} ++#endif // CONFIG_PREEMPT_RT + + #define lock_page_ref_irq(page) \ + do { \ +- local_irq_disable(); \ ++ local_irq_disable_nort(); \ + lock_page_ref(page); \ + } while (0) + + #define unlock_page_ref_irq(page) \ + do { \ + unlock_page_ref(page); \ +- local_irq_enable(); \ ++ local_irq_enable_nort(); \ + } while (0) + + #define lock_page_ref_irqsave(page, flags) \ + do { \ +- local_irq_save(flags); \ ++ local_irq_save_nort(flags); \ + lock_page_ref(page); \ + } while (0) + + #define unlock_page_ref_irqrestore(page, flags) \ + do { \ + unlock_page_ref(page); \ +- local_irq_restore(flags); \ ++ local_irq_restore_nort(flags); \ + } while (0) + + /* +@@ -155,7 +207,7 @@ static inline int page_cache_get_specula + { + VM_BUG_ON(in_interrupt()); + +-#ifndef CONFIG_SMP ++#if !defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_RT) + # ifdef CONFIG_PREEMPT + VM_BUG_ON(!in_atomic()); + # endif +Index: linux-2.6.24.7-rt27/mm/filemap.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/filemap.c 2009-02-08 00:03:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/filemap.c 2009-02-08 00:03:12.000000000 -0500 +@@ -505,21 +505,10 @@ static int __sleep_on_page_lock(void *wo + return 0; + } + +-/* +- * In order to wait for pages to become available there must be +- * waitqueues associated with pages. By using a hash table of +- * waitqueues where the bucket discipline is to maintain all +- * waiters on the same queue and wake all when any of the pages +- * become available, and for the woken contexts to check to be +- * sure the appropriate page became available, this saves space +- * at a cost of "thundering herd" phenomena during rare hash +- * collisions. +- */ +-static wait_queue_head_t *page_waitqueue(struct page *page) ++int __sleep_on_page(void *word) + { +- const struct zone *zone = page_zone(page); +- +- return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)]; ++ schedule(); ++ return 0; + } + + static inline void wake_up_page(struct page *page, int bit) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0278-futex-performance-hack-sysctl-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0278-futex-performance-hack-sysctl-fix.patch @@ -0,0 +1,72 @@ +From lethal@linux-sh.org Fri May 18 06:46:43 2007 +Return-Path: +Received: from smtp.ocgnet.org (smtp.ocgnet.org [64.20.243.3]) by + mail.tglx.de (Postfix) with ESMTP id 0FCC865C065 for ; + Fri, 18 May 2007 06:46:43 +0200 (CEST) +Received: from smtp.ocgnet.org (localhost [127.0.0.1]) by smtp.ocgnet.org + (Postfix) with ESMTP id 616355203FB; Thu, 17 May 2007 23:46:39 -0500 (CDT) +X-Spam-Checker-Version: SpamAssassin 3.1.3-gr0 (2006-06-01) on + smtp.ocgnet.org +X-Spam-Level: +X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=no + version=3.1.3-gr0 +Received: from master.linux-sh.org (124x34x33x190.ap124.ftth.ucom.ne.jp + [124.34.33.190]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 + bits)) (No client certificate requested) by smtp.ocgnet.org (Postfix) with + ESMTP id E1F585203E0; Thu, 17 May 2007 23:46:38 -0500 (CDT) +Received: from localhost (unknown [127.0.0.1]) by master.linux-sh.org + (Postfix) with ESMTP id 4984664C7C; Fri, 18 May 2007 04:46:00 +0000 (UTC) +X-Virus-Scanned: amavisd-new at linux-sh.org +Received: from master.linux-sh.org ([127.0.0.1]) by localhost + (master.linux-sh.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id + BE+H5LV2TYuQ; Fri, 18 May 2007 13:46:00 +0900 (JST) +Received: by master.linux-sh.org (Postfix, from userid 500) id 08A5664C7D; + Fri, 18 May 2007 13:46:00 +0900 (JST) +Date: Fri, 18 May 2007 13:45:59 +0900 +From: Paul Mundt +To: Ingo Molnar , Thomas Gleixner +Cc: linux-kernel@vger.kernel.org +Subject: [PATCH -rt] futex_performance_hack sysctl build fix +Message-ID: <20070518044559.GB22660@linux-sh.org> +Mail-Followup-To: Paul Mundt , Ingo Molnar + , Thomas Gleixner , + linux-kernel@vger.kernel.org +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline +User-Agent: Mutt/1.5.13 (2006-08-11) +X-Virus-Scanned: ClamAV using ClamSMTP +X-Evolution-Source: imap://tglx%40linutronix.de@localhost:8993/ +Content-Transfer-Encoding: 8bit + +-rt adds a futex_performance_hack sysctl, which is only defined if +kernel/futex.c is built in. This fixes the build in the CONFIG_FUTEX=n +case. + +Signed-off-by: Paul Mundt + +-- + + kernel/sysctl.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/sysctl.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sysctl.c 2009-02-08 00:02:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sysctl.c 2009-02-08 00:02:59.000000000 -0500 +@@ -340,6 +340,7 @@ static struct ctl_table kern_table[] = { + .proc_handler = &proc_dointvec, + }, + #endif ++#ifdef CONFIG_FUTEX + { + .ctl_name = CTL_UNNUMBERED, + .procname = "futex_performance_hack", +@@ -348,6 +349,7 @@ static struct ctl_table kern_table[] = { + .mode = 0644, + .proc_handler = &proc_dointvec, + }, ++#endif + { + .ctl_name = CTL_UNNUMBERED, + .procname = "prof_pid", --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0181-rt-mutex-compat-semaphores.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0181-rt-mutex-compat-semaphores.patch @@ -0,0 +1,296 @@ + drivers/acpi/osl.c | 12 ++++++------ + drivers/media/dvb/dvb-core/dvb_frontend.c | 2 +- + drivers/net/3c527.c | 2 +- + drivers/net/hamradio/6pack.c | 2 +- + drivers/net/hamradio/mkiss.c | 2 +- + drivers/net/plip.c | 5 ++++- + drivers/net/ppp_async.c | 2 +- + drivers/net/ppp_synctty.c | 2 +- + drivers/pci/hotplug/ibmphp_hpc.c | 2 +- + drivers/scsi/aacraid/aacraid.h | 4 ++-- + drivers/scsi/qla2xxx/qla_def.h | 2 +- + drivers/usb/storage/usb.h | 2 +- + fs/jffs2/jffs2_fs_i.h | 2 +- + fs/xfs/linux-2.6/sema.h | 9 +++++++-- + fs/xfs/linux-2.6/xfs_buf.h | 4 ++-- + include/linux/parport.h | 2 +- + 16 files changed, 32 insertions(+), 24 deletions(-) + +Index: linux-2.6.24.7-rt27/drivers/acpi/osl.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/acpi/osl.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/acpi/osl.c 2009-02-08 00:02:09.000000000 -0500 +@@ -775,13 +775,13 @@ void acpi_os_delete_lock(acpi_spinlock h + acpi_status + acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) + { +- struct semaphore *sem = NULL; ++ struct compat_semaphore *sem = NULL; + + +- sem = acpi_os_allocate(sizeof(struct semaphore)); ++ sem = acpi_os_allocate(sizeof(struct compat_semaphore)); + if (!sem) + return AE_NO_MEMORY; +- memset(sem, 0, sizeof(struct semaphore)); ++ memset(sem, 0, sizeof(struct compat_semaphore)); + + sema_init(sem, initial_units); + +@@ -804,7 +804,7 @@ EXPORT_SYMBOL(acpi_os_create_semaphore); + + acpi_status acpi_os_delete_semaphore(acpi_handle handle) + { +- struct semaphore *sem = (struct semaphore *)handle; ++ struct compat_semaphore *sem = (struct compat_semaphore *)handle; + + + if (!sem) +@@ -832,7 +832,7 @@ EXPORT_SYMBOL(acpi_os_delete_semaphore); + acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) + { + acpi_status status = AE_OK; +- struct semaphore *sem = (struct semaphore *)handle; ++ struct compat_semaphore *sem = (struct compat_semaphore *)handle; + int ret = 0; + + +@@ -919,7 +919,7 @@ EXPORT_SYMBOL(acpi_os_wait_semaphore); + */ + acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units) + { +- struct semaphore *sem = (struct semaphore *)handle; ++ struct compat_semaphore *sem = (struct compat_semaphore *)handle; + + + if (!sem || (units < 1)) +Index: linux-2.6.24.7-rt27/drivers/media/dvb/dvb-core/dvb_frontend.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/media/dvb/dvb-core/dvb_frontend.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/media/dvb/dvb-core/dvb_frontend.c 2009-02-08 00:02:09.000000000 -0500 +@@ -97,7 +97,7 @@ struct dvb_frontend_private { + struct dvb_device *dvbdev; + struct dvb_frontend_parameters parameters; + struct dvb_fe_events events; +- struct semaphore sem; ++ struct compat_semaphore sem; + struct list_head list_head; + wait_queue_head_t wait_queue; + struct task_struct *thread; +Index: linux-2.6.24.7-rt27/drivers/net/3c527.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/net/3c527.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/net/3c527.c 2009-02-08 00:02:09.000000000 -0500 +@@ -182,7 +182,7 @@ struct mc32_local + + u16 rx_ring_tail; /* index to rx de-queue end */ + +- struct semaphore cmd_mutex; /* Serialises issuing of execute commands */ ++ struct compat_semaphore cmd_mutex; /* Serialises issuing of execute commands */ + struct completion execution_cmd; /* Card has completed an execute command */ + struct completion xceiver_cmd; /* Card has completed a tx or rx command */ + }; +Index: linux-2.6.24.7-rt27/drivers/net/hamradio/6pack.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/net/hamradio/6pack.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/net/hamradio/6pack.c 2009-02-08 00:02:09.000000000 -0500 +@@ -123,7 +123,7 @@ struct sixpack { + struct timer_list tx_t; + struct timer_list resync_t; + atomic_t refcnt; +- struct semaphore dead_sem; ++ struct compat_semaphore dead_sem; + spinlock_t lock; + }; + +Index: linux-2.6.24.7-rt27/drivers/net/hamradio/mkiss.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/net/hamradio/mkiss.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/net/hamradio/mkiss.c 2009-02-08 00:02:09.000000000 -0500 +@@ -84,7 +84,7 @@ struct mkiss { + #define CRC_MODE_SMACK_TEST 4 + + atomic_t refcnt; +- struct semaphore dead_sem; ++ struct compat_semaphore dead_sem; + }; + + /*---------------------------------------------------------------------------*/ +Index: linux-2.6.24.7-rt27/drivers/net/plip.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/net/plip.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/net/plip.c 2009-02-08 00:02:09.000000000 -0500 +@@ -221,7 +221,10 @@ struct net_local { + int should_relinquish; + spinlock_t lock; + atomic_t kill_timer; +- struct semaphore killed_timer_sem; ++ /* ++ * PREEMPT_RT: this isnt a mutex, it should be struct completion. ++ */ ++ struct compat_semaphore killed_timer_sem; + }; + + static inline void enable_parport_interrupts (struct net_device *dev) +Index: linux-2.6.24.7-rt27/drivers/net/ppp_async.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/net/ppp_async.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/net/ppp_async.c 2009-02-08 00:02:09.000000000 -0500 +@@ -67,7 +67,7 @@ struct asyncppp { + struct tasklet_struct tsk; + + atomic_t refcnt; +- struct semaphore dead_sem; ++ struct compat_semaphore dead_sem; + struct ppp_channel chan; /* interface to generic ppp layer */ + unsigned char obuf[OBUFSIZE]; + }; +Index: linux-2.6.24.7-rt27/drivers/net/ppp_synctty.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/net/ppp_synctty.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/net/ppp_synctty.c 2009-02-08 00:02:09.000000000 -0500 +@@ -70,7 +70,7 @@ struct syncppp { + struct tasklet_struct tsk; + + atomic_t refcnt; +- struct semaphore dead_sem; ++ struct compat_semaphore dead_sem; + struct ppp_channel chan; /* interface to generic ppp layer */ + }; + +Index: linux-2.6.24.7-rt27/drivers/pci/hotplug/ibmphp_hpc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/pci/hotplug/ibmphp_hpc.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/pci/hotplug/ibmphp_hpc.c 2009-02-08 00:02:09.000000000 -0500 +@@ -104,7 +104,7 @@ static int to_debug = 0; + static struct mutex sem_hpcaccess; // lock access to HPC + static struct semaphore semOperations; // lock all operations and + // access to data structures +-static struct semaphore sem_exit; // make sure polling thread goes away ++static struct compat_semaphore sem_exit; // make sure polling thread goes away + static struct task_struct *ibmphp_poll_thread; + //---------------------------------------------------------------------------- + // local function prototypes +Index: linux-2.6.24.7-rt27/drivers/scsi/aacraid/aacraid.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/scsi/aacraid/aacraid.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/scsi/aacraid/aacraid.h 2009-02-08 00:02:09.000000000 -0500 +@@ -715,7 +715,7 @@ struct aac_fib_context { + u32 unique; // unique value representing this context + ulong jiffies; // used for cleanup - dmb changed to ulong + struct list_head next; // used to link context's into a linked list +- struct semaphore wait_sem; // this is used to wait for the next fib to arrive. ++ struct compat_semaphore wait_sem; // this is used to wait for the next fib to arrive. + int wait; // Set to true when thread is in WaitForSingleObject + unsigned long count; // total number of FIBs on FibList + struct list_head fib_list; // this holds fibs and their attachd hw_fibs +@@ -785,7 +785,7 @@ struct fib { + * This is the event the sendfib routine will wait on if the + * caller did not pass one and this is synch io. + */ +- struct semaphore event_wait; ++ struct compat_semaphore event_wait; + spinlock_t event_lock; + + u32 done; /* gets set to 1 when fib is complete */ +Index: linux-2.6.24.7-rt27/drivers/scsi/qla2xxx/qla_def.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/scsi/qla2xxx/qla_def.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/scsi/qla2xxx/qla_def.h 2009-02-08 00:02:09.000000000 -0500 +@@ -2418,7 +2418,7 @@ typedef struct scsi_qla_host { + + struct semaphore mbx_cmd_sem; /* Serialialize mbx access */ + struct semaphore vport_sem; /* Virtual port synchronization */ +- struct semaphore mbx_intr_sem; /* Used for completion notification */ ++ struct compat_semaphore mbx_intr_sem; /* Used for completion notification */ + + uint32_t mbx_flags; + #define MBX_IN_PROGRESS BIT_0 +Index: linux-2.6.24.7-rt27/drivers/usb/storage/usb.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/usb/storage/usb.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/usb/storage/usb.h 2009-02-08 00:02:09.000000000 -0500 +@@ -147,7 +147,7 @@ struct us_data { + struct task_struct *ctl_thread; /* the control thread */ + + /* mutual exclusion and synchronization structures */ +- struct semaphore sema; /* to sleep thread on */ ++ struct compat_semaphore sema; /* to sleep thread on */ + struct completion notify; /* thread begin/end */ + wait_queue_head_t delay_wait; /* wait during scan, reset */ + struct completion scanning_done; /* wait for scan thread */ +Index: linux-2.6.24.7-rt27/fs/jffs2/jffs2_fs_i.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/jffs2/jffs2_fs_i.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/jffs2/jffs2_fs_i.h 2009-02-08 00:02:09.000000000 -0500 +@@ -24,7 +24,7 @@ struct jffs2_inode_info { + before letting GC proceed. Or we'd have to put ugliness + into the GC code so it didn't attempt to obtain the i_mutex + for the inode(s) which are already locked */ +- struct semaphore sem; ++ struct compat_semaphore sem; + + /* The highest (datanode) version number used for this ino */ + uint32_t highest_version; +Index: linux-2.6.24.7-rt27/fs/xfs/linux-2.6/sema.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/xfs/linux-2.6/sema.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/xfs/linux-2.6/sema.h 2009-02-08 00:02:09.000000000 -0500 +@@ -27,7 +27,7 @@ + * sema_t structure just maps to struct semaphore in Linux kernel. + */ + +-typedef struct semaphore sema_t; ++typedef struct compat_semaphore sema_t; + + #define initnsema(sp, val, name) sema_init(sp, val) + #define psema(sp, b) down(sp) +@@ -36,7 +36,12 @@ typedef struct semaphore sema_t; + + static inline int issemalocked(sema_t *sp) + { +- return down_trylock(sp) || (up(sp), 0); ++ int rv; ++ ++ if ((rv = down_trylock(sp))) ++ return (rv); ++ up(sp); ++ return (0); + } + + /* +Index: linux-2.6.24.7-rt27/fs/xfs/linux-2.6/xfs_buf.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/xfs/linux-2.6/xfs_buf.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/xfs/linux-2.6/xfs_buf.h 2009-02-08 00:02:09.000000000 -0500 +@@ -118,7 +118,7 @@ typedef int (*xfs_buf_bdstrat_t)(struct + #define XB_PAGES 2 + + typedef struct xfs_buf { +- struct semaphore b_sema; /* semaphore for lockables */ ++ struct compat_semaphore b_sema; /* semaphore for lockables */ + unsigned long b_queuetime; /* time buffer was queued */ + atomic_t b_pin_count; /* pin count */ + wait_queue_head_t b_waiters; /* unpin waiters */ +@@ -138,7 +138,7 @@ typedef struct xfs_buf { + xfs_buf_iodone_t b_iodone; /* I/O completion function */ + xfs_buf_relse_t b_relse; /* releasing function */ + xfs_buf_bdstrat_t b_strat; /* pre-write function */ +- struct semaphore b_iodonesema; /* Semaphore for I/O waiters */ ++ struct compat_semaphore b_iodonesema; /* Semaphore for I/O waiters */ + void *b_fspriv; + void *b_fspriv2; + void *b_fspriv3; +Index: linux-2.6.24.7-rt27/include/linux/parport.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/parport.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/parport.h 2009-02-08 00:02:09.000000000 -0500 +@@ -266,7 +266,7 @@ enum ieee1284_phase { + struct ieee1284_info { + int mode; + volatile enum ieee1284_phase phase; +- struct semaphore irq; ++ struct compat_semaphore irq; + }; + + /* A parallel port */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0366-rcu-trace-fix-free.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0366-rcu-trace-fix-free.patch @@ -0,0 +1,26 @@ +--- + kernel/rcupreempt_trace.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/rcupreempt_trace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt_trace.c 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt_trace.c 2009-02-08 00:03:44.000000000 -0500 +@@ -309,11 +309,16 @@ out: + + static int __init rcupreempt_trace_init(void) + { ++ int ret; ++ + mutex_init(&rcupreempt_trace_mutex); + rcupreempt_trace_buf = kmalloc(RCUPREEMPT_TRACE_BUF_SIZE, GFP_KERNEL); + if (!rcupreempt_trace_buf) + return 1; +- return rcupreempt_debugfs_init(); ++ ret = rcupreempt_debugfs_init(); ++ if (ret) ++ kfree(rcupreempt_trace_buf); ++ return ret; + } + + static void __exit rcupreempt_trace_cleanup(void) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0217-preempt-realtime-ppc-need-resched-delayed.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0217-preempt-realtime-ppc-need-resched-delayed.patch @@ -0,0 +1,34 @@ +From tsutomu.owa@toshiba.co.jp Mon May 14 15:29:17 2007 +Date: Mon, 14 May 2007 15:29:17 +0900 +From: Tsutomu OWA +To: linuxppc-dev@ozlabs.org, linux-kernel@vger.kernel.org +Cc: mingo@elte.hu, tglx@linutronix.de +Subject: Re: [patch 3/4] powerpc 2.6.21-rt1: add a need_resched_delayed() check + + +Add a need_resched_delayed() check. +This was pointed by Sergei Shtylyov; + http://ozlabs.org/pipermail/linuxppc-dev/2007-March/033148.html + +Signed-off-by: Tsutomu Owa +-- owa + +--- + arch/powerpc/kernel/idle.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/idle.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/idle.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/idle.c 2009-02-08 00:02:27.000000000 -0500 +@@ -74,7 +74,9 @@ void cpu_idle(void) + local_irq_disable(); + + /* check again after disabling irqs */ +- if (!need_resched() && !cpu_should_die()) ++ if (!need_resched() && ++ !need_resched_delayed() && ++ !cpu_should_die()) + ppc_md.power_save(); + + local_irq_enable(); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0359-call_rcu_bh-rename-of-call_rcu.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0359-call_rcu_bh-rename-of-call_rcu.patch @@ -0,0 +1,49 @@ +Subject: [PATCH] just rename call_rcu_bh instead of making it a macro + +Seems that I found a box that has a config that passes call_rcu_bh as a +function pointer (see net/sctp/sm_make_chunk.c), so declaring the +call_rcu_bh has a macro function isn't good enough. + +This patch makes it just another name of call_rcu for rcupreempt. + +Signed-off-by: Steven Rostedt + +--- + include/linux/rcupdate.h | 4 ++-- + include/linux/rcupreempt.h | 7 ++++++- + 2 files changed, 8 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/rcupdate.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupdate.h 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupdate.h 2009-02-08 00:03:41.000000000 -0500 +@@ -221,9 +221,9 @@ extern struct lockdep_map rcu_lock_map; + * and may be nested. + */ + #ifdef CONFIG_CLASSIC_RCU +-#define call_rcu(head, func) call_rcu_classic(head, func) ++#define call_rcu call_rcu_classic + #else /* #ifdef CONFIG_CLASSIC_RCU */ +-#define call_rcu(head, func) call_rcu_preempt(head, func) ++#define call_rcu call_rcu_preempt + #endif /* #else #ifdef CONFIG_CLASSIC_RCU */ + + /** +Index: linux-2.6.24.7-rt27/include/linux/rcupreempt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupreempt.h 2009-02-08 00:01:43.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupreempt.h 2009-02-08 00:03:41.000000000 -0500 +@@ -42,7 +42,12 @@ + #include + #include + +-#define call_rcu_bh(head, rcu) call_rcu(head, rcu) ++/* ++ * Someone might want to pass call_rcu_bh as a function pointer. ++ * So this needs to just be a rename and not a macro function. ++ * (no parentheses) ++ */ ++#define call_rcu_bh call_rcu_preempt + #define rcu_bh_qsctr_inc(cpu) do { } while (0) + #define __rcu_read_lock_bh() { rcu_read_lock(); local_bh_disable(); } + #define __rcu_read_unlock_bh() { local_bh_enable(); rcu_read_unlock(); } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0355-rt-s_files-kill-a-union.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0355-rt-s_files-kill-a-union.patch @@ -0,0 +1,25 @@ + +Remove a dependancy on the size of rcu_head. + +Signed-off-by: Peter Zijlstra +--- + include/linux/fs.h | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/fs.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/fs.h 2009-02-08 00:03:38.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/fs.h 2009-02-08 00:03:39.000000000 -0500 +@@ -797,11 +797,7 @@ static inline int ra_has_index(struct fi + } + + struct file { +- /* +- * fu_llist becomes invalid after file_free is called and queued via +- * fu_rcuhead for RCU freeing +- */ +- union { ++ struct { + struct lock_list_head fu_llist; + struct rcu_head fu_rcuhead; + } f_u; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0472-rwlocks-fix-no-preempt-rt.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0472-rwlocks-fix-no-preempt-rt.patch @@ -0,0 +1,73 @@ +From: Steven Rostedt +Subject: rwlock: fix non PREEMPT_RT case + +Seems that the addition of RT_RW_READER broke the non PREEMPT_RT case. +This patch fixes it. + +Signed-off-by: Steven Rostedt +--- + kernel/rtmutex.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:27.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:34.000000000 -0500 +@@ -123,6 +123,12 @@ static inline void mark_rt_rwlock_check( + #endif /* CONFIG_PREEMPT_RT */ + #endif + ++#ifdef CONFIG_PREEMPT_RT ++#define task_is_reader(task) ((task) == RT_RW_READER) ++#else ++#define task_is_reader(task) (0) ++#endif ++ + int pi_initialized; + + /* +@@ -315,7 +321,7 @@ static int rt_mutex_adjust_prio_chain(st + /* + * Readers are special. We may need to boost more than one owner. + */ +- if (task == RT_RW_READER) { ++ if (task_is_reader(task)) { + ret = rt_mutex_adjust_readers(orig_lock, orig_waiter, + top_task, lock, + recursion_depth); +@@ -376,7 +382,7 @@ static inline int try_to_steal_lock(stru + if (pendowner == current) + return 1; + +- WARN_ON(rt_mutex_owner(lock) == RT_RW_READER); ++ WARN_ON(task_is_reader(rt_mutex_owner(lock))); + + spin_lock(&pendowner->pi_lock); + if (!lock_is_stealable(pendowner, mode)) { +@@ -506,7 +512,7 @@ static int task_blocks_on_rt_mutex(struc + + if (waiter == rt_mutex_top_waiter(lock)) { + /* readers are handled differently */ +- if (owner == RT_RW_READER) { ++ if (task_is_reader(owner)) { + res = rt_mutex_adjust_readers(lock, waiter, + current, lock, 0); + return res; +@@ -524,7 +530,7 @@ static int task_blocks_on_rt_mutex(struc + else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) + chain_walk = 1; + +- if (!chain_walk || owner == RT_RW_READER) ++ if (!chain_walk || task_is_reader(owner)) + return 0; + + /* +@@ -624,7 +630,7 @@ static void remove_waiter(struct rt_mute + current->pi_blocked_on = NULL; + spin_unlock(¤t->pi_lock); + +- if (first && owner != current && owner != RT_RW_READER) { ++ if (first && owner != current && !task_is_reader(owner)) { + + spin_lock(&owner->pi_lock); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0246-preempt-realtime-mm.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0246-preempt-realtime-mm.patch @@ -0,0 +1,261 @@ +--- + include/linux/pagevec.h | 2 +- + include/linux/vmstat.h | 10 ++++++++++ + mm/bounce.c | 4 ++-- + mm/memory.c | 11 +++++++++-- + mm/mmap.c | 10 ++++++++-- + mm/vmscan.c | 10 ++++++++-- + mm/vmstat.c | 38 ++++++++++++++++++++++++++++++++------ + 7 files changed, 70 insertions(+), 15 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/pagevec.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/pagevec.h 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/pagevec.h 2009-02-08 00:02:42.000000000 -0500 +@@ -9,7 +9,7 @@ + #define _LINUX_PAGEVEC_H + + /* 14 pointers + two long's align the pagevec structure to a power of two */ +-#define PAGEVEC_SIZE 14 ++#define PAGEVEC_SIZE 8 + + struct page; + struct address_space; +Index: linux-2.6.24.7-rt27/include/linux/vmstat.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/vmstat.h 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/vmstat.h 2009-02-08 00:02:42.000000000 -0500 +@@ -59,7 +59,12 @@ DECLARE_PER_CPU(struct vm_event_state, v + + static inline void __count_vm_event(enum vm_event_item item) + { ++#ifdef CONFIG_PREEMPT_RT ++ get_cpu_var(vm_event_states).event[item]++; ++ put_cpu(); ++#else + __get_cpu_var(vm_event_states).event[item]++; ++#endif + } + + static inline void count_vm_event(enum vm_event_item item) +@@ -70,7 +75,12 @@ static inline void count_vm_event(enum v + + static inline void __count_vm_events(enum vm_event_item item, long delta) + { ++#ifdef CONFIG_PREEMPT_RT ++ get_cpu_var(vm_event_states).event[item] += delta; ++ put_cpu(); ++#else + __get_cpu_var(vm_event_states).event[item] += delta; ++#endif + } + + static inline void count_vm_events(enum vm_event_item item, long delta) +Index: linux-2.6.24.7-rt27/mm/bounce.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/bounce.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/bounce.c 2009-02-08 00:02:42.000000000 -0500 +@@ -48,11 +48,11 @@ static void bounce_copy_vec(struct bio_v + unsigned long flags; + unsigned char *vto; + +- local_irq_save(flags); ++ local_irq_save_nort(flags); + vto = kmap_atomic(to->bv_page, KM_BOUNCE_READ); + memcpy(vto + to->bv_offset, vfrom, to->bv_len); + kunmap_atomic(vto, KM_BOUNCE_READ); +- local_irq_restore(flags); ++ local_irq_restore_nort(flags); + } + + #else /* CONFIG_HIGHMEM */ +Index: linux-2.6.24.7-rt27/mm/memory.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/memory.c 2009-02-08 00:01:27.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/memory.c 2009-02-08 00:02:42.000000000 -0500 +@@ -278,7 +278,9 @@ void free_pgtables(struct mmu_gather **t + + if (!vma) /* Sometimes when exiting after an oops */ + return; ++#ifndef CONFIG_PREEMPT_RT + if (vma->vm_next) ++#endif + tlb_finish_mmu(*tlb, tlb_start_addr(*tlb), tlb_end_addr(*tlb)); + /* + * Hide vma from rmap and vmtruncate before freeeing pgtables, +@@ -289,7 +291,9 @@ void free_pgtables(struct mmu_gather **t + unlink_file_vma(unlink); + unlink = unlink->vm_next; + } ++#ifndef CONFIG_PREEMPT_RT + if (vma->vm_next) ++#endif + *tlb = tlb_gather_mmu(vma->vm_mm, fullmm); + #endif + while (vma) { +@@ -804,10 +808,13 @@ static unsigned long unmap_page_range(st + return addr; + } + +-#ifdef CONFIG_PREEMPT ++#if defined(CONFIG_PREEMPT) && !defined(CONFIG_PREEMPT_RT) + # define ZAP_BLOCK_SIZE (8 * PAGE_SIZE) + #else +-/* No preempt: go for improved straight-line efficiency */ ++/* ++ * No preempt: go for improved straight-line efficiency ++ * on PREEMPT_RT this is not a critical latency-path. ++ */ + # define ZAP_BLOCK_SIZE (1024 * PAGE_SIZE) + #endif + +Index: linux-2.6.24.7-rt27/mm/mmap.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/mmap.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/mmap.c 2009-02-08 00:02:42.000000000 -0500 +@@ -1910,10 +1910,16 @@ asmlinkage long sys_munmap(unsigned long + static inline void verify_mm_writelocked(struct mm_struct *mm) + { + #ifdef CONFIG_DEBUG_VM +- if (unlikely(down_read_trylock(&mm->mmap_sem))) { ++# ifdef CONFIG_PREEMPT_RT ++ if (unlikely(!rt_rwsem_is_locked(&mm->mmap_sem))) { + WARN_ON(1); +- up_read(&mm->mmap_sem); + } ++# else ++ if (unlikely(down_read_trylock(&mm->mmap_sem))) { ++ WARN_ON(1); ++ up_read(&mm->mmap_sem); ++ } ++# endif + #endif + } + +Index: linux-2.6.24.7-rt27/mm/vmscan.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/vmscan.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/vmscan.c 2009-02-08 00:02:42.000000000 -0500 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include /* for try_to_release_page(), + buffer_heads_over_limit */ + #include +@@ -840,7 +841,7 @@ static unsigned long shrink_inactive_lis + } + + nr_reclaimed += nr_freed; +- local_irq_disable(); ++ local_irq_disable_nort(); + if (current_is_kswapd()) { + __count_zone_vm_events(PGSCAN_KSWAPD, zone, nr_scan); + __count_vm_events(KSWAPD_STEAL, nr_freed); +@@ -871,9 +872,14 @@ static unsigned long shrink_inactive_lis + } + } + } while (nr_scanned < max_scan); ++ /* ++ * Non-PREEMPT_RT relies on IRQs-off protecting the page_states ++ * per-CPU data. PREEMPT_RT has that data protected even in ++ * __mod_page_state(), so no need to keep IRQs disabled. ++ */ + spin_unlock(&zone->lru_lock); + done: +- local_irq_enable(); ++ local_irq_enable_nort(); + pagevec_release(&pvec); + return nr_reclaimed; + } +Index: linux-2.6.24.7-rt27/mm/vmstat.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/vmstat.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/vmstat.c 2009-02-08 00:02:42.000000000 -0500 +@@ -157,10 +157,14 @@ static void refresh_zone_stat_thresholds + void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item, + int delta) + { +- struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id()); +- s8 *p = pcp->vm_stat_diff + item; ++ struct per_cpu_pageset *pcp; ++ int cpu; + long x; ++ s8 *p; + ++ cpu = get_cpu(); ++ pcp = zone_pcp(zone, cpu); ++ p = pcp->vm_stat_diff + item; + x = delta + *p; + + if (unlikely(x > pcp->stat_threshold || x < -pcp->stat_threshold)) { +@@ -168,6 +172,7 @@ void __mod_zone_page_state(struct zone * + x = 0; + } + *p = x; ++ put_cpu(); + } + EXPORT_SYMBOL(__mod_zone_page_state); + +@@ -210,9 +215,13 @@ EXPORT_SYMBOL(mod_zone_page_state); + */ + void __inc_zone_state(struct zone *zone, enum zone_stat_item item) + { +- struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id()); +- s8 *p = pcp->vm_stat_diff + item; ++ struct per_cpu_pageset *pcp; ++ int cpu; ++ s8 *p; + ++ cpu = get_cpu(); ++ pcp = zone_pcp(zone, cpu); ++ p = pcp->vm_stat_diff + item; + (*p)++; + + if (unlikely(*p > pcp->stat_threshold)) { +@@ -221,18 +230,34 @@ void __inc_zone_state(struct zone *zone, + zone_page_state_add(*p + overstep, zone, item); + *p = -overstep; + } ++ put_cpu(); + } + + void __inc_zone_page_state(struct page *page, enum zone_stat_item item) + { ++#ifdef CONFIG_PREEMPT_RT ++ unsigned long flags; ++ struct zone *zone; ++ ++ zone = page_zone(page); ++ local_irq_save(flags); ++ __inc_zone_state(zone, item); ++ local_irq_restore(flags); ++#else + __inc_zone_state(page_zone(page), item); ++#endif + } + EXPORT_SYMBOL(__inc_zone_page_state); + + void __dec_zone_state(struct zone *zone, enum zone_stat_item item) + { +- struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id()); +- s8 *p = pcp->vm_stat_diff + item; ++ struct per_cpu_pageset *pcp; ++ int cpu; ++ s8 *p; ++ ++ cpu = get_cpu(); ++ pcp = zone_pcp(zone, cpu); ++ p = pcp->vm_stat_diff + item; + + (*p)--; + +@@ -242,6 +267,7 @@ void __dec_zone_state(struct zone *zone, + zone_page_state_add(*p - overstep, zone, item); + *p = overstep; + } ++ put_cpu(); + } + + void __dec_zone_page_state(struct page *page, enum zone_stat_item item) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0436-rt-avoid-deadlock-in-swap.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0436-rt-avoid-deadlock-in-swap.patch @@ -0,0 +1,62 @@ +From h-shimamoto@ct.jp.nec.com Thu May 15 09:57:50 2008 +Date: Thu, 17 Apr 2008 16:57:20 +0200 +From: Hiroshi Shimamoto +To: Peter Zijlstra +Cc: Steven Rostedt , + linux-rt-users , + Ingo Molnar , Thomas Gleixner , + LKML +Subject: [PATCH -rt] avoid deadlock related with PG_nonewrefs and swap_lock +Resent-Date: Thu, 17 Apr 2008 14:57:28 +0000 (UTC) +Resent-From: Peter Zijlstra +Resent-To: Steven Rostedt + +Hi Peter, + +I've updated the patch. Could you please review it? + +I'm also thinking that it can be in the mainline because it makes +the lock period shorter, correct? + +--- +From: Hiroshi Shimamoto + +There is a deadlock scenario; remove_mapping() vs free_swap_and_cache(). +remove_mapping() turns PG_nonewrefs bit on, then locks swap_lock. +free_swap_and_cache() locks swap_lock, then wait to turn PG_nonewrefs bit +off in find_get_page(). + +swap_lock can be unlocked before calling find_get_page(). + +In remove_exclusive_swap_page(), there is similar lock sequence; +swap_lock, then PG_nonewrefs bit. swap_lock can be unlocked before +turning PG_nonewrefs bit on. + +Signed-off-by: Hiroshi Shimamoto +--- + mm/swapfile.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/mm/swapfile.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/swapfile.c 2009-02-08 00:04:15.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/swapfile.c 2009-02-08 00:04:18.000000000 -0500 +@@ -366,6 +366,7 @@ int remove_exclusive_swap_page(struct pa + /* Is the only swap cache user the cache itself? */ + retval = 0; + if (p->swap_map[swp_offset(entry)] == 1) { ++ spin_unlock(&swap_lock); + /* Recheck the page count with the swapcache lock held.. */ + lock_page_ref_irq(page); + if ((page_count(page) == 2) && !PageWriteback(page)) { +@@ -374,8 +375,8 @@ int remove_exclusive_swap_page(struct pa + retval = 1; + } + unlock_page_ref_irq(page); +- } +- spin_unlock(&swap_lock); ++ } else ++ spin_unlock(&swap_lock); + + if (retval) { + swap_free(entry); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0017-0003-sched-add-RT-task-pushing.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0017-0003-sched-add-RT-task-pushing.patch @@ -0,0 +1,321 @@ +From 6d3e7dfa47b1d3ae3abd608e5d89b56cad72cccb Mon Sep 17 00:00:00 2001 +From: Steven Rostedt +Date: Tue, 11 Dec 2007 10:02:37 +0100 +Subject: [PATCH] sched: add RT task pushing + +This patch adds an algorithm to push extra RT tasks off a run queue to +other CPU runqueues. + +When more than one RT task is added to a run queue, this algorithm takes +an assertive approach to push the RT tasks that are not running onto other +run queues that have lower priority. The way this works is that the highest +RT task that is not running is looked at and we examine the runqueues on +the CPUS for that tasks affinity mask. We find the runqueue with the lowest +prio in the CPU affinity of the picked task, and if it is lower in prio than +the picked task, we push the task onto that CPU runqueue. + +We continue pushing RT tasks off the current runqueue until we don't push any +more. The algorithm stops when the next highest RT task can't preempt any +other processes on other CPUS. + +TODO: The algorithm may stop when there are still RT tasks that can be + migrated. Specifically, if the highest non running RT task CPU affinity + is restricted to CPUs that are running higher priority tasks, there may + be a lower priority task queued that has an affinity with a CPU that is + running a lower priority task that it could be migrated to. This + patch set does not address this issue. + +Note: checkpatch reveals two over 80 character instances. I'm not sure + that breaking them up will help visually, so I left them as is. + +Signed-off-by: Steven Rostedt +Signed-off-by: Ingo Molnar + +--- + kernel/sched.c | 8 + + kernel/sched_rt.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 231 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:00:51.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:00:51.000000000 -0500 +@@ -1937,6 +1937,8 @@ static void finish_task_switch(struct rq + prev_state = prev->state; + finish_arch_switch(prev); + finish_lock_switch(rq, prev); ++ schedule_tail_balance_rt(rq); ++ + fire_sched_in_preempt_notifiers(current); + if (mm) + mmdrop(mm); +@@ -2170,11 +2172,13 @@ static void double_rq_unlock(struct rq * + /* + * double_lock_balance - lock the busiest runqueue, this_rq is locked already. + */ +-static void double_lock_balance(struct rq *this_rq, struct rq *busiest) ++static int double_lock_balance(struct rq *this_rq, struct rq *busiest) + __releases(this_rq->lock) + __acquires(busiest->lock) + __acquires(this_rq->lock) + { ++ int ret = 0; ++ + if (unlikely(!irqs_disabled())) { + /* printk() doesn't work good under rq->lock */ + spin_unlock(&this_rq->lock); +@@ -2185,9 +2189,11 @@ static void double_lock_balance(struct r + spin_unlock(&this_rq->lock); + spin_lock(&busiest->lock); + spin_lock(&this_rq->lock); ++ ret = 1; + } else + spin_lock(&busiest->lock); + } ++ return ret; + } + + /* +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:00:51.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:00:51.000000000 -0500 +@@ -133,6 +133,227 @@ static void put_prev_task_rt(struct rq * + } + + #ifdef CONFIG_SMP ++/* Only try algorithms three times */ ++#define RT_MAX_TRIES 3 ++ ++static int double_lock_balance(struct rq *this_rq, struct rq *busiest); ++static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep); ++ ++/* Return the second highest RT task, NULL otherwise */ ++static struct task_struct *pick_next_highest_task_rt(struct rq *rq) ++{ ++ struct rt_prio_array *array = &rq->rt.active; ++ struct task_struct *next; ++ struct list_head *queue; ++ int idx; ++ ++ assert_spin_locked(&rq->lock); ++ ++ if (likely(rq->rt.rt_nr_running < 2)) ++ return NULL; ++ ++ idx = sched_find_first_bit(array->bitmap); ++ if (unlikely(idx >= MAX_RT_PRIO)) { ++ WARN_ON(1); /* rt_nr_running is bad */ ++ return NULL; ++ } ++ ++ queue = array->queue + idx; ++ next = list_entry(queue->next, struct task_struct, run_list); ++ if (unlikely(next != rq->curr)) ++ return next; ++ ++ if (queue->next->next != queue) { ++ /* same prio task */ ++ next = list_entry(queue->next->next, struct task_struct, run_list); ++ return next; ++ } ++ ++ /* slower, but more flexible */ ++ idx = find_next_bit(array->bitmap, MAX_RT_PRIO, idx+1); ++ if (unlikely(idx >= MAX_RT_PRIO)) { ++ WARN_ON(1); /* rt_nr_running was 2 and above! */ ++ return NULL; ++ } ++ ++ queue = array->queue + idx; ++ next = list_entry(queue->next, struct task_struct, run_list); ++ ++ return next; ++} ++ ++static DEFINE_PER_CPU(cpumask_t, local_cpu_mask); ++ ++/* Will lock the rq it finds */ ++static struct rq *find_lock_lowest_rq(struct task_struct *task, ++ struct rq *this_rq) ++{ ++ struct rq *lowest_rq = NULL; ++ int cpu; ++ int tries; ++ cpumask_t *cpu_mask = &__get_cpu_var(local_cpu_mask); ++ ++ cpus_and(*cpu_mask, cpu_online_map, task->cpus_allowed); ++ ++ for (tries = 0; tries < RT_MAX_TRIES; tries++) { ++ /* ++ * Scan each rq for the lowest prio. ++ */ ++ for_each_cpu_mask(cpu, *cpu_mask) { ++ struct rq *rq = &per_cpu(runqueues, cpu); ++ ++ if (cpu == this_rq->cpu) ++ continue; ++ ++ /* We look for lowest RT prio or non-rt CPU */ ++ if (rq->rt.highest_prio >= MAX_RT_PRIO) { ++ lowest_rq = rq; ++ break; ++ } ++ ++ /* no locking for now */ ++ if (rq->rt.highest_prio > task->prio && ++ (!lowest_rq || rq->rt.highest_prio > lowest_rq->rt.highest_prio)) { ++ lowest_rq = rq; ++ } ++ } ++ ++ if (!lowest_rq) ++ break; ++ ++ /* if the prio of this runqueue changed, try again */ ++ if (double_lock_balance(this_rq, lowest_rq)) { ++ /* ++ * We had to unlock the run queue. In ++ * the mean time, task could have ++ * migrated already or had its affinity changed. ++ * Also make sure that it wasn't scheduled on its rq. ++ */ ++ if (unlikely(task_rq(task) != this_rq || ++ !cpu_isset(lowest_rq->cpu, task->cpus_allowed) || ++ task_running(this_rq, task) || ++ !task->se.on_rq)) { ++ spin_unlock(&lowest_rq->lock); ++ lowest_rq = NULL; ++ break; ++ } ++ } ++ ++ /* If this rq is still suitable use it. */ ++ if (lowest_rq->rt.highest_prio > task->prio) ++ break; ++ ++ /* try again */ ++ spin_unlock(&lowest_rq->lock); ++ lowest_rq = NULL; ++ } ++ ++ return lowest_rq; ++} ++ ++/* ++ * If the current CPU has more than one RT task, see if the non ++ * running task can migrate over to a CPU that is running a task ++ * of lesser priority. ++ */ ++static int push_rt_task(struct rq *this_rq) ++{ ++ struct task_struct *next_task; ++ struct rq *lowest_rq; ++ int ret = 0; ++ int paranoid = RT_MAX_TRIES; ++ ++ assert_spin_locked(&this_rq->lock); ++ ++ next_task = pick_next_highest_task_rt(this_rq); ++ if (!next_task) ++ return 0; ++ ++ retry: ++ if (unlikely(next_task == this_rq->curr)) ++ return 0; ++ ++ /* ++ * It's possible that the next_task slipped in of ++ * higher priority than current. If that's the case ++ * just reschedule current. ++ */ ++ if (unlikely(next_task->prio < this_rq->curr->prio)) { ++ resched_task(this_rq->curr); ++ return 0; ++ } ++ ++ /* We might release this_rq lock */ ++ get_task_struct(next_task); ++ ++ /* find_lock_lowest_rq locks the rq if found */ ++ lowest_rq = find_lock_lowest_rq(next_task, this_rq); ++ if (!lowest_rq) { ++ struct task_struct *task; ++ /* ++ * find lock_lowest_rq releases this_rq->lock ++ * so it is possible that next_task has changed. ++ * If it has, then try again. ++ */ ++ task = pick_next_highest_task_rt(this_rq); ++ if (unlikely(task != next_task) && task && paranoid--) { ++ put_task_struct(next_task); ++ next_task = task; ++ goto retry; ++ } ++ goto out; ++ } ++ ++ assert_spin_locked(&lowest_rq->lock); ++ ++ deactivate_task(this_rq, next_task, 0); ++ set_task_cpu(next_task, lowest_rq->cpu); ++ activate_task(lowest_rq, next_task, 0); ++ ++ resched_task(lowest_rq->curr); ++ ++ spin_unlock(&lowest_rq->lock); ++ ++ ret = 1; ++out: ++ put_task_struct(next_task); ++ ++ return ret; ++} ++ ++/* ++ * TODO: Currently we just use the second highest prio task on ++ * the queue, and stop when it can't migrate (or there's ++ * no more RT tasks). There may be a case where a lower ++ * priority RT task has a different affinity than the ++ * higher RT task. In this case the lower RT task could ++ * possibly be able to migrate where as the higher priority ++ * RT task could not. We currently ignore this issue. ++ * Enhancements are welcome! ++ */ ++static void push_rt_tasks(struct rq *rq) ++{ ++ /* push_rt_task will return true if it moved an RT */ ++ while (push_rt_task(rq)) ++ ; ++} ++ ++static void schedule_tail_balance_rt(struct rq *rq) ++{ ++ /* ++ * If we have more than one rt_task queued, then ++ * see if we can push the other rt_tasks off to other CPUS. ++ * Note we may release the rq lock, and since ++ * the lock was owned by prev, we need to release it ++ * first via finish_lock_switch and then reaquire it here. ++ */ ++ if (unlikely(rq->rt.rt_nr_running > 1)) { ++ spin_lock_irq(&rq->lock); ++ push_rt_tasks(rq); ++ spin_unlock_irq(&rq->lock); ++ } ++} ++ + /* + * Load-balancing iterator. Note: while the runqueue stays locked + * during the whole iteration, the current task might be +@@ -237,7 +458,9 @@ move_one_task_rt(struct rq *this_rq, int + return iter_move_one_task(this_rq, this_cpu, busiest, sd, idle, + &rt_rq_iterator); + } +-#endif ++#else /* CONFIG_SMP */ ++# define schedule_tail_balance_rt(rq) do { } while (0) ++#endif /* CONFIG_SMP */ + + static void task_tick_rt(struct rq *rq, struct task_struct *p) + { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0230-preempt-realtime-i386.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0230-preempt-realtime-i386.patch @@ -0,0 +1,828 @@ +--- + arch/x86/Kconfig.debug | 2 + + arch/x86/kernel/cpu/mtrr/generic.c | 2 - + arch/x86/kernel/head_32.S | 1 + arch/x86/kernel/i8253.c | 2 - + arch/x86/kernel/i8259_32.c | 2 - + arch/x86/kernel/io_apic_32.c | 4 +-- + arch/x86/kernel/irq_32.c | 4 ++- + arch/x86/kernel/microcode.c | 2 - + arch/x86/kernel/nmi_32.c | 5 +++ + arch/x86/kernel/process_32.c | 19 ++++++++++---- + arch/x86/kernel/signal_32.c | 14 ++++++++++ + arch/x86/kernel/smp_32.c | 19 ++++++++++---- + arch/x86/kernel/traps_32.c | 18 +++++++++++--- + arch/x86/kernel/vm86_32.c | 1 + arch/x86/mm/fault_32.c | 1 + arch/x86/mm/highmem_32.c | 37 ++++++++++++++++++++++------- + arch/x86/mm/pgtable_32.c | 2 - + arch/x86/pci/common.c | 2 - + arch/x86/pci/direct.c | 29 ++++++++++++++-------- + arch/x86/pci/pci.h | 2 - + include/asm-x86/acpi_32.h | 4 +-- + include/asm-x86/dma_32.h | 2 - + include/asm-x86/highmem.h | 27 +++++++++++++++++++++ + include/asm-x86/i8253.h | 2 - + include/asm-x86/i8259.h | 2 - + include/asm-x86/mach-default/irq_vectors.h | 2 - + include/asm-x86/mc146818rtc_32.h | 2 - + include/asm-x86/pgtable_32.h | 2 - + include/asm-x86/tlbflush_32.h | 26 ++++++++++++++++++++ + include/asm-x86/xor_32.h | 21 ++++++++++++++-- + kernel/Kconfig.instrumentation | 5 +++ + 31 files changed, 211 insertions(+), 52 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/Kconfig.debug +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/Kconfig.debug 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/Kconfig.debug 2009-02-08 00:02:34.000000000 -0500 +@@ -50,6 +50,7 @@ config DEBUG_PAGEALLOC + config DEBUG_RODATA + bool "Write protect kernel read-only data structures" + depends on DEBUG_KERNEL ++ default y + help + Mark the kernel read-only data as write-protected in the pagetables, + in order to catch accidental (and incorrect) writes to such const +@@ -61,6 +62,7 @@ config 4KSTACKS + bool "Use 4Kb for kernel stacks instead of 8Kb" + depends on DEBUG_KERNEL + depends on X86_32 ++ default y + help + If you say Y here the kernel will use a 4Kb stacksize for the + kernel stack attached to each process/thread. This facilitates +Index: linux-2.6.24.7-rt27/arch/x86/kernel/cpu/mtrr/generic.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/cpu/mtrr/generic.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/cpu/mtrr/generic.c 2009-02-08 00:02:34.000000000 -0500 +@@ -330,7 +330,7 @@ static unsigned long set_mtrr_state(void + + + static unsigned long cr4 = 0; +-static DEFINE_SPINLOCK(set_atomicity_lock); ++static DEFINE_RAW_SPINLOCK(set_atomicity_lock); + + /* + * Since we are disabling the cache don't allow any interrupts - they +Index: linux-2.6.24.7-rt27/arch/x86/kernel/head_32.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/head_32.S 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/head_32.S 2009-02-08 00:02:34.000000000 -0500 +@@ -533,6 +533,7 @@ ignore_int: + call printk + #endif + addl $(5*4),%esp ++ call dump_stack + popl %ds + popl %es + popl %edx +Index: linux-2.6.24.7-rt27/arch/x86/kernel/i8253.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/i8253.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/i8253.c 2009-02-08 00:02:34.000000000 -0500 +@@ -14,7 +14,7 @@ + #include + #include + +-DEFINE_SPINLOCK(i8253_lock); ++DEFINE_RAW_SPINLOCK(i8253_lock); + EXPORT_SYMBOL(i8253_lock); + + /* +Index: linux-2.6.24.7-rt27/arch/x86/kernel/i8259_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/i8259_32.c 2009-02-08 00:01:51.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/i8259_32.c 2009-02-08 00:02:34.000000000 -0500 +@@ -33,7 +33,7 @@ + */ + + static int i8259A_auto_eoi; +-DEFINE_SPINLOCK(i8259A_lock); ++DEFINE_RAW_SPINLOCK(i8259A_lock); + static void mask_and_ack_8259A(unsigned int); + + static struct irq_chip i8259A_chip = { +Index: linux-2.6.24.7-rt27/arch/x86/kernel/io_apic_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/io_apic_32.c 2009-02-08 00:01:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/io_apic_32.c 2009-02-08 00:02:34.000000000 -0500 +@@ -56,8 +56,8 @@ atomic_t irq_mis_count; + /* Where if anywhere is the i8259 connect in external int mode */ + static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; + +-static DEFINE_SPINLOCK(ioapic_lock); +-static DEFINE_SPINLOCK(vector_lock); ++static DEFINE_RAW_SPINLOCK(ioapic_lock); ++static DEFINE_RAW_SPINLOCK(vector_lock); + + int timer_over_8254 __initdata = 1; + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/irq_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/irq_32.c 2009-02-08 00:01:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/irq_32.c 2009-02-08 00:02:34.000000000 -0500 +@@ -79,6 +79,8 @@ fastcall unsigned int do_IRQ(struct pt_r + u32 *isp; + #endif + ++ irq_show_regs_callback(smp_processor_id(), regs); ++ + if (unlikely((unsigned)irq >= NR_IRQS)) { + printk(KERN_EMERG "%s: cannot handle IRQ %d\n", + __FUNCTION__, irq); +@@ -96,7 +98,7 @@ fastcall unsigned int do_IRQ(struct pt_r + __asm__ __volatile__("andl %%esp,%0" : + "=r" (esp) : "0" (THREAD_SIZE - 1)); + if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) { +- printk("do_IRQ: stack overflow: %ld\n", ++ printk("BUG: do_IRQ: stack overflow: %ld\n", + esp - sizeof(struct thread_info)); + dump_stack(); + } +Index: linux-2.6.24.7-rt27/arch/x86/kernel/microcode.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/microcode.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/microcode.c 2009-02-08 00:02:34.000000000 -0500 +@@ -117,7 +117,7 @@ MODULE_LICENSE("GPL"); + #define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE) + + /* serialize access to the physical write to MSR 0x79 */ +-static DEFINE_SPINLOCK(microcode_update_lock); ++static DEFINE_RAW_SPINLOCK(microcode_update_lock); + + /* no concurrent ->write()s are allowed on /dev/cpu/microcode */ + static DEFINE_MUTEX(microcode_mutex); +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_32.c 2009-02-08 00:01:32.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c 2009-02-08 00:02:34.000000000 -0500 +@@ -59,7 +59,12 @@ static int endflag __initdata = 0; + static __init void nmi_cpu_busy(void *data) + { + #ifdef CONFIG_SMP ++ /* ++ * avoid a warning, on PREEMPT_RT this wont run in hardirq context: ++ */ ++#ifndef CONFIG_PREEMPT_RT + local_irq_enable_in_hardirq(); ++#endif + /* Intentionally don't use cpu_relax here. This is + to make sure that the performance counter really ticks, + even if there is a simulator or similar that catches the +Index: linux-2.6.24.7-rt27/arch/x86/kernel/process_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/process_32.c 2009-02-08 00:02:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/process_32.c 2009-02-08 00:02:34.000000000 -0500 +@@ -342,9 +342,10 @@ void __show_registers(struct pt_regs *re + regs->eax, regs->ebx, regs->ecx, regs->edx); + printk("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", + regs->esi, regs->edi, regs->ebp, esp); +- printk(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", ++ printk(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x" ++ " preempt:%08x\n", + regs->xds & 0xffff, regs->xes & 0xffff, +- regs->xfs & 0xffff, gs, ss); ++ regs->xfs & 0xffff, gs, ss, preempt_count()); + + if (!all) + return; +@@ -416,15 +417,23 @@ void exit_thread(void) + if (unlikely(test_thread_flag(TIF_IO_BITMAP))) { + struct task_struct *tsk = current; + struct thread_struct *t = &tsk->thread; +- int cpu = get_cpu(); +- struct tss_struct *tss = &per_cpu(init_tss, cpu); ++ void *io_bitmap_ptr = t->io_bitmap_ptr; ++ int cpu; ++ struct tss_struct *tss; + +- kfree(t->io_bitmap_ptr); ++ /* ++ * On PREEMPT_RT we must not call kfree() with ++ * preemption disabled, so we first zap the pointer: ++ */ + t->io_bitmap_ptr = NULL; ++ kfree(io_bitmap_ptr); ++ + clear_thread_flag(TIF_IO_BITMAP); + /* + * Careful, clear this in the TSS too: + */ ++ cpu = get_cpu(); ++ tss = &per_cpu(init_tss, cpu); + memset(tss->io_bitmap, 0xff, tss->io_bitmap_max); + t->io_bitmap_max = 0; + tss->io_bitmap_owner = NULL; +Index: linux-2.6.24.7-rt27/arch/x86/kernel/signal_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/signal_32.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/signal_32.c 2009-02-08 00:02:34.000000000 -0500 +@@ -536,6 +536,13 @@ handle_signal(unsigned long sig, siginfo + } + } + ++#ifdef CONFIG_PREEMPT_RT ++ /* ++ * Fully-preemptible kernel does not need interrupts disabled: ++ */ ++ local_irq_enable(); ++ preempt_check_resched(); ++#endif + /* + * If TF is set due to a debugger (PT_DTRACE), clear the TF flag so + * that register information in the sigcontext is correct. +@@ -576,6 +583,13 @@ static void fastcall do_signal(struct pt + struct k_sigaction ka; + sigset_t *oldset; + ++#ifdef CONFIG_PREEMPT_RT ++ /* ++ * Fully-preemptible kernel does not need interrupts disabled: ++ */ ++ local_irq_enable(); ++ preempt_check_resched(); ++#endif + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from +Index: linux-2.6.24.7-rt27/arch/x86/kernel/smp_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/smp_32.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/smp_32.c 2009-02-08 00:02:34.000000000 -0500 +@@ -247,7 +247,7 @@ void send_IPI_mask_sequence(cpumask_t ma + static cpumask_t flush_cpumask; + static struct mm_struct * flush_mm; + static unsigned long flush_va; +-static DEFINE_SPINLOCK(tlbstate_lock); ++static DEFINE_RAW_SPINLOCK(tlbstate_lock); + + /* + * We cannot call mmdrop() because we are in interrupt context, +@@ -476,10 +476,20 @@ static void native_smp_send_reschedule(i + } + + /* ++ * this function sends a 'reschedule' IPI to all other CPUs. ++ * This is used when RT tasks are starving and other CPUs ++ * might be able to run them: ++ */ ++void smp_send_reschedule_allbutself(void) ++{ ++ send_IPI_allbutself(RESCHEDULE_VECTOR); ++} ++ ++/* + * Structure and data for smp_call_function(). This is designed to minimise + * static memory requirements. It also looks cleaner. + */ +-static DEFINE_SPINLOCK(call_lock); ++static DEFINE_RAW_SPINLOCK(call_lock); + + struct call_data_struct { + void (*func) (void *info); +@@ -634,9 +644,8 @@ static void native_smp_send_stop(void) + } + + /* +- * Reschedule call back. Nothing to do, +- * all the work is done automatically when +- * we return from the interrupt. ++ * Reschedule call back. Trigger a reschedule pass so that ++ * RT-overload balancing can pass tasks around. + */ + fastcall void smp_reschedule_interrupt(struct pt_regs *regs) + { +Index: linux-2.6.24.7-rt27/arch/x86/kernel/traps_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/traps_32.c 2009-02-08 00:01:36.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/traps_32.c 2009-02-08 00:02:34.000000000 -0500 +@@ -297,6 +297,12 @@ void dump_stack(void) + + EXPORT_SYMBOL(dump_stack); + ++#if defined(CONFIG_DEBUG_STACKOVERFLOW) && defined(CONFIG_EVENT_TRACE) ++extern unsigned long worst_stack_left; ++#else ++# define worst_stack_left -1L ++#endif ++ + void show_registers(struct pt_regs *regs) + { + int i; +@@ -366,7 +372,7 @@ void die(const char * str, struct pt_reg + u32 lock_owner; + int lock_owner_depth; + } die = { +- .lock = __RAW_SPIN_LOCK_UNLOCKED, ++ .lock = RAW_SPIN_LOCK_UNLOCKED(die.lock), + .lock_owner = -1, + .lock_owner_depth = 0 + }; +@@ -378,7 +384,7 @@ void die(const char * str, struct pt_reg + if (die.lock_owner != raw_smp_processor_id()) { + console_verbose(); + raw_local_irq_save(flags); +- __raw_spin_lock(&die.lock); ++ spin_lock(&die.lock); + die.lock_owner = smp_processor_id(); + die.lock_owner_depth = 0; + bust_spinlocks(1); +@@ -427,7 +433,7 @@ void die(const char * str, struct pt_reg + bust_spinlocks(0); + die.lock_owner = -1; + add_taint(TAINT_DIE); +- __raw_spin_unlock(&die.lock); ++ spin_unlock(&die.lock); + raw_local_irq_restore(flags); + + if (!regs) +@@ -467,6 +473,11 @@ static void __kprobes do_trap(int trapnr + if (!user_mode(regs)) + goto kernel_trap; + ++#ifdef CONFIG_PREEMPT_RT ++ local_irq_enable(); ++ preempt_check_resched(); ++#endif ++ + trap_signal: { + /* + * We want error_code and trap_no set for userspace faults and +@@ -724,6 +735,7 @@ void __kprobes die_nmi(struct pt_regs *r + crash_kexec(regs); + } + ++ nmi_exit(); + do_exit(SIGSEGV); + } + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/vm86_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/vm86_32.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/vm86_32.c 2009-02-08 00:02:34.000000000 -0500 +@@ -135,6 +135,7 @@ struct pt_regs * fastcall save_v86_state + local_irq_enable(); + + if (!current->thread.vm86_info) { ++ local_irq_disable(); + printk("no vm86_info: BAD\n"); + do_exit(SIGSEGV); + } +Index: linux-2.6.24.7-rt27/arch/x86/mm/fault_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/mm/fault_32.c 2009-02-08 00:01:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/mm/fault_32.c 2009-02-08 00:02:34.000000000 -0500 +@@ -502,6 +502,7 @@ bad_area_nosemaphore: + nr = (address - idt_descr.address) >> 3; + + if (nr == 6) { ++ zap_rt_locks(); + do_invalid_op(regs, 0); + return; + } +Index: linux-2.6.24.7-rt27/arch/x86/mm/highmem_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/mm/highmem_32.c 2009-02-08 00:01:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/mm/highmem_32.c 2009-02-08 00:02:34.000000000 -0500 +@@ -18,6 +18,26 @@ void kunmap(struct page *page) + kunmap_high(page); + } + ++void kunmap_virt(void *ptr) ++{ ++ struct page *page; ++ ++ if ((unsigned long)ptr < PKMAP_ADDR(0)) ++ return; ++ page = pte_page(pkmap_page_table[PKMAP_NR((unsigned long)ptr)]); ++ kunmap(page); ++} ++ ++struct page *kmap_to_page(void *ptr) ++{ ++ struct page *page; ++ ++ if ((unsigned long)ptr < PKMAP_ADDR(0)) ++ return virt_to_page(ptr); ++ page = pte_page(pkmap_page_table[PKMAP_NR((unsigned long)ptr)]); ++ return page; ++} ++ + /* + * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because + * no global lock is needed and because the kmap code must perform a global TLB +@@ -26,7 +46,7 @@ void kunmap(struct page *page) + * However when holding an atomic kmap is is not legal to sleep, so atomic + * kmaps are appropriate for short, tight code paths only. + */ +-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot) ++void *__kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot) + { + enum fixed_addresses idx; + unsigned long vaddr; +@@ -46,12 +66,12 @@ void *kmap_atomic_prot(struct page *page + return (void *)vaddr; + } + +-void *kmap_atomic(struct page *page, enum km_type type) ++void *__kmap_atomic(struct page *page, enum km_type type) + { + return kmap_atomic_prot(page, type, kmap_prot); + } + +-void kunmap_atomic(void *kvaddr, enum km_type type) ++void __kunmap_atomic(void *kvaddr, enum km_type type) + { + unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; + enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); +@@ -78,7 +98,7 @@ void kunmap_atomic(void *kvaddr, enum km + /* This is the same as kmap_atomic() but can map memory that doesn't + * have a struct page associated with it. + */ +-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type) ++void *__kmap_atomic_pfn(unsigned long pfn, enum km_type type) + { + enum fixed_addresses idx; + unsigned long vaddr; +@@ -93,7 +113,7 @@ void *kmap_atomic_pfn(unsigned long pfn, + return (void*) vaddr; + } + +-struct page *kmap_atomic_to_page(void *ptr) ++struct page *__kmap_atomic_to_page(void *ptr) + { + unsigned long idx, vaddr = (unsigned long)ptr; + pte_t *pte; +@@ -108,6 +128,7 @@ struct page *kmap_atomic_to_page(void *p + + EXPORT_SYMBOL(kmap); + EXPORT_SYMBOL(kunmap); +-EXPORT_SYMBOL(kmap_atomic); +-EXPORT_SYMBOL(kunmap_atomic); +-EXPORT_SYMBOL(kmap_atomic_to_page); ++EXPORT_SYMBOL(kunmap_virt); ++EXPORT_SYMBOL(__kmap_atomic); ++EXPORT_SYMBOL(__kunmap_atomic); ++EXPORT_SYMBOL(__kmap_atomic_to_page); +Index: linux-2.6.24.7-rt27/arch/x86/mm/pgtable_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/mm/pgtable_32.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/mm/pgtable_32.c 2009-02-08 00:02:34.000000000 -0500 +@@ -210,7 +210,7 @@ void pmd_ctor(struct kmem_cache *cache, + * vmalloc faults work because attached pagetables are never freed. + * -- wli + */ +-DEFINE_SPINLOCK(pgd_lock); ++DEFINE_RAW_SPINLOCK(pgd_lock); + struct page *pgd_list; + + static inline void pgd_list_add(pgd_t *pgd) +Index: linux-2.6.24.7-rt27/arch/x86/pci/common.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/pci/common.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/pci/common.c 2009-02-08 00:02:34.000000000 -0500 +@@ -54,7 +54,7 @@ int pcibios_scanned; + * This interrupt-safe spinlock protects all accesses to PCI + * configuration space. + */ +-DEFINE_SPINLOCK(pci_config_lock); ++DEFINE_RAW_SPINLOCK(pci_config_lock); + + /* + * Several buggy motherboards address only 16 devices and mirror +Index: linux-2.6.24.7-rt27/arch/x86/pci/direct.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/pci/direct.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/pci/direct.c 2009-02-08 00:02:34.000000000 -0500 +@@ -220,16 +220,23 @@ static int __init pci_check_type1(void) + unsigned int tmp; + int works = 0; + +- local_irq_save(flags); ++ spin_lock_irqsave(&pci_config_lock, flags); + + outb(0x01, 0xCFB); + tmp = inl(0xCF8); + outl(0x80000000, 0xCF8); +- if (inl(0xCF8) == 0x80000000 && pci_sanity_check(&pci_direct_conf1)) { +- works = 1; ++ ++ if (inl(0xCF8) == 0x80000000) { ++ spin_unlock_irqrestore(&pci_config_lock, flags); ++ ++ if (pci_sanity_check(&pci_direct_conf1)) ++ works = 1; ++ ++ spin_lock_irqsave(&pci_config_lock, flags); + } + outl(tmp, 0xCF8); +- local_irq_restore(flags); ++ ++ spin_unlock_irqrestore(&pci_config_lock, flags); + + return works; + } +@@ -239,17 +246,19 @@ static int __init pci_check_type2(void) + unsigned long flags; + int works = 0; + +- local_irq_save(flags); ++ spin_lock_irqsave(&pci_config_lock, flags); + + outb(0x00, 0xCFB); + outb(0x00, 0xCF8); + outb(0x00, 0xCFA); +- if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 && +- pci_sanity_check(&pci_direct_conf2)) { +- works = 1; +- } + +- local_irq_restore(flags); ++ if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00) { ++ spin_unlock_irqrestore(&pci_config_lock, flags); ++ ++ if (pci_sanity_check(&pci_direct_conf2)) ++ works = 1; ++ } else ++ spin_unlock_irqrestore(&pci_config_lock, flags); + + return works; + } +Index: linux-2.6.24.7-rt27/arch/x86/pci/pci.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/pci/pci.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/pci/pci.h 2009-02-08 00:02:34.000000000 -0500 +@@ -80,7 +80,7 @@ struct irq_routing_table { + extern unsigned int pcibios_irq_mask; + + extern int pcibios_scanned; +-extern spinlock_t pci_config_lock; ++extern raw_spinlock_t pci_config_lock; + + extern int (*pcibios_enable_irq)(struct pci_dev *dev); + extern void (*pcibios_disable_irq)(struct pci_dev *dev); +Index: linux-2.6.24.7-rt27/include/asm-x86/acpi_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/acpi_32.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/acpi_32.h 2009-02-08 00:02:34.000000000 -0500 +@@ -52,8 +52,8 @@ + + #define ACPI_ASM_MACROS + #define BREAKPOINT3 +-#define ACPI_DISABLE_IRQS() local_irq_disable() +-#define ACPI_ENABLE_IRQS() local_irq_enable() ++#define ACPI_DISABLE_IRQS() local_irq_disable_nort() ++#define ACPI_ENABLE_IRQS() local_irq_enable_nort() + #define ACPI_FLUSH_CPU_CACHE() wbinvd() + + int __acpi_acquire_global_lock(unsigned int *lock); +Index: linux-2.6.24.7-rt27/include/asm-x86/dma_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/dma_32.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/dma_32.h 2009-02-08 00:02:34.000000000 -0500 +@@ -134,7 +134,7 @@ + #define DMA_AUTOINIT 0x10 + + +-extern spinlock_t dma_spin_lock; ++extern spinlock_t dma_spin_lock; + + static __inline__ unsigned long claim_dma_lock(void) + { +Index: linux-2.6.24.7-rt27/include/asm-x86/highmem.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/highmem.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/highmem.h 2009-02-08 00:02:34.000000000 -0500 +@@ -67,6 +67,16 @@ extern void * FASTCALL(kmap_high(struct + extern void FASTCALL(kunmap_high(struct page *page)); + + void *kmap(struct page *page); ++extern void kunmap_virt(void *ptr); ++extern struct page *kmap_to_page(void *ptr); ++void kunmap(struct page *page); ++ ++void *__kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot); ++void *__kmap_atomic(struct page *page, enum km_type type); ++void __kunmap_atomic(void *kvaddr, enum km_type type); ++void *__kmap_atomic_pfn(unsigned long pfn, enum km_type type); ++struct page *__kmap_atomic_to_page(void *ptr); ++ + void kunmap(struct page *page); + void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot); + void *kmap_atomic(struct page *page, enum km_type type); +@@ -80,6 +90,23 @@ struct page *kmap_atomic_to_page(void *p + + #define flush_cache_kmaps() do { } while (0) + ++/* ++ * on PREEMPT_RT kmap_atomic() is a wrapper that uses kmap(): ++ */ ++#ifdef CONFIG_PREEMPT_RT ++# define kmap_atomic_prot(page, type, prot) kmap(page) ++# define kmap_atomic(page, type) kmap(page) ++# define kmap_atomic_pfn(pfn, type) kmap(pfn_to_page(pfn)) ++# define kunmap_atomic(kvaddr, type) kunmap_virt(kvaddr) ++# define kmap_atomic_to_page(kvaddr) kmap_to_page(kvaddr) ++#else ++# define kmap_atomic_prot(page, type, prot) __kmap_atomic_prot(page, type, prot) ++# define kmap_atomic(page, type) __kmap_atomic(page, type) ++# define kmap_atomic_pfn(pfn, type) __kmap_atomic_pfn(pfn, type) ++# define kunmap_atomic(kvaddr, type) __kunmap_atomic(kvaddr, type) ++# define kmap_atomic_to_page(kvaddr) __kmap_atomic_to_page(kvaddr) ++#endif ++ + #endif /* __KERNEL__ */ + + #endif /* _ASM_HIGHMEM_H */ +Index: linux-2.6.24.7-rt27/include/asm-x86/i8253.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/i8253.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/i8253.h 2009-02-08 00:02:34.000000000 -0500 +@@ -6,7 +6,7 @@ + #define PIT_CH0 0x40 + #define PIT_CH2 0x42 + +-extern spinlock_t i8253_lock; ++extern raw_spinlock_t i8253_lock; + + extern struct clock_event_device *global_clock_event; + +Index: linux-2.6.24.7-rt27/include/asm-x86/i8259.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/i8259.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/i8259.h 2009-02-08 00:02:34.000000000 -0500 +@@ -7,7 +7,7 @@ extern unsigned int cached_irq_mask; + #define cached_master_mask (__byte(0, cached_irq_mask)) + #define cached_slave_mask (__byte(1, cached_irq_mask)) + +-extern spinlock_t i8259A_lock; ++extern raw_spinlock_t i8259A_lock; + + extern void init_8259A(int auto_eoi); + extern void enable_8259A_irq(unsigned int irq); +Index: linux-2.6.24.7-rt27/include/asm-x86/mach-default/irq_vectors.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/mach-default/irq_vectors.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/mach-default/irq_vectors.h 2009-02-08 00:02:34.000000000 -0500 +@@ -63,7 +63,7 @@ + * levels. (0x80 is the syscall vector) + */ + #define FIRST_DEVICE_VECTOR 0x31 +-#define FIRST_SYSTEM_VECTOR 0xef ++#define FIRST_SYSTEM_VECTOR 0xee + + #define TIMER_IRQ 0 + +Index: linux-2.6.24.7-rt27/include/asm-x86/mc146818rtc_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/mc146818rtc_32.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/mc146818rtc_32.h 2009-02-08 00:02:34.000000000 -0500 +@@ -72,7 +72,7 @@ static inline unsigned char current_lock + lock_cmos(reg) + #define lock_cmos_suffix(reg) \ + unlock_cmos(); \ +- local_irq_restore(cmos_flags); \ ++ local_irq_restore(cmos_flags); \ + } while (0) + #else + #define lock_cmos_prefix(reg) do {} while (0) +Index: linux-2.6.24.7-rt27/include/asm-x86/pgtable_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/pgtable_32.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/pgtable_32.h 2009-02-08 00:02:34.000000000 -0500 +@@ -33,7 +33,7 @@ struct vm_area_struct; + extern unsigned long empty_zero_page[1024]; + extern pgd_t swapper_pg_dir[1024]; + extern struct kmem_cache *pmd_cache; +-extern spinlock_t pgd_lock; ++extern raw_spinlock_t pgd_lock; + extern struct page *pgd_list; + void check_pgt_cache(void); + +Index: linux-2.6.24.7-rt27/include/asm-x86/tlbflush_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/tlbflush_32.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/tlbflush_32.h 2009-02-08 00:02:34.000000000 -0500 +@@ -4,6 +4,21 @@ + #include + #include + ++/* ++ * TLB-flush needs to be nonpreemptible on PREEMPT_RT due to the ++ * following complex race scenario: ++ * ++ * if the current task is lazy-TLB and does a TLB flush and ++ * gets preempted after the movl %%r3, %0 but before the ++ * movl %0, %%cr3 then its ->active_mm might change and it will ++ * install the wrong cr3 when it switches back. This is not a ++ * problem for the lazy-TLB task itself, but if the next task it ++ * switches to has an ->mm that is also the lazy-TLB task's ++ * new ->active_mm, then the scheduler will assume that cr3 is ++ * the new one, while we overwrote it with the old one. The result ++ * is the wrong cr3 in the new (non-lazy-TLB) task, which typically ++ * causes an infinite pagefault upon the next userspace access. ++ */ + #ifdef CONFIG_PARAVIRT + #include + #else +@@ -16,11 +31,13 @@ + do { \ + unsigned int tmpreg; \ + \ ++ preempt_disable(); \ + __asm__ __volatile__( \ + "movl %%cr3, %0; \n" \ + "movl %0, %%cr3; # flush TLB \n" \ + : "=r" (tmpreg) \ + :: "memory"); \ ++ preempt_enable(); \ + } while (0) + + /* +@@ -31,6 +48,7 @@ + do { \ + unsigned int tmpreg, cr4, cr4_orig; \ + \ ++ preempt_disable(); \ + __asm__ __volatile__( \ + "movl %%cr4, %2; # turn off PGE \n" \ + "movl %2, %1; \n" \ +@@ -42,6 +60,7 @@ + : "=&r" (tmpreg), "=&r" (cr4), "=&r" (cr4_orig) \ + : "i" (~X86_CR4_PGE) \ + : "memory"); \ ++ preempt_enable(); \ + } while (0) + + #define __native_flush_tlb_single(addr) \ +@@ -97,6 +116,13 @@ + + static inline void flush_tlb_mm(struct mm_struct *mm) + { ++ /* ++ * This is safe on PREEMPT_RT because if we preempt ++ * right after the check but before the __flush_tlb(), ++ * and if ->active_mm changes, then we might miss a ++ * TLB flush, but that TLB flush happened already when ++ * ->active_mm was changed: ++ */ + if (mm == current->active_mm) + __flush_tlb(); + } +Index: linux-2.6.24.7-rt27/include/asm-x86/xor_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/xor_32.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/xor_32.h 2009-02-08 00:02:34.000000000 -0500 +@@ -862,7 +862,21 @@ static struct xor_block_template xor_blo + #include + + #undef XOR_TRY_TEMPLATES +-#define XOR_TRY_TEMPLATES \ ++/* ++ * MMX/SSE ops disable preemption for long periods of time, ++ * so on PREEMPT_RT use the register-based ops only: ++ */ ++#ifdef CONFIG_PREEMPT_RT ++# define XOR_TRY_TEMPLATES \ ++ do { \ ++ xor_speed(&xor_block_8regs); \ ++ xor_speed(&xor_block_8regs_p); \ ++ xor_speed(&xor_block_32regs); \ ++ xor_speed(&xor_block_32regs_p); \ ++ } while (0) ++# define XOR_SELECT_TEMPLATE(FASTEST) (FASTEST) ++#else ++# define XOR_TRY_TEMPLATES \ + do { \ + xor_speed(&xor_block_8regs); \ + xor_speed(&xor_block_8regs_p); \ +@@ -875,9 +889,10 @@ static struct xor_block_template xor_blo + xor_speed(&xor_block_p5_mmx); \ + } \ + } while (0) +- + /* We force the use of the SSE xor block because it can write around L2. + We may also be able to load into the L1 only depending on how the cpu + deals with a load to a line that is being prefetched. */ +-#define XOR_SELECT_TEMPLATE(FASTEST) \ ++# define XOR_SELECT_TEMPLATE(FASTEST) \ + (cpu_has_xmm ? &xor_block_pIII_sse : FASTEST) ++#endif ++ +Index: linux-2.6.24.7-rt27/kernel/Kconfig.instrumentation +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/Kconfig.instrumentation 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/Kconfig.instrumentation 2009-02-08 00:02:34.000000000 -0500 +@@ -29,6 +29,11 @@ config OPROFILE + + If unsure, say N. + ++config PROFILE_NMI ++ bool ++ depends on OPROFILE ++ default y ++ + config KPROBES + bool "Kprobes" + depends on KALLSYMS && MODULES && !UML --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0250-preempt-realtime-debug-sysctl.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0250-preempt-realtime-debug-sysctl.patch @@ -0,0 +1,143 @@ +--- + drivers/char/sysrq.c | 18 ++++++++++++++- + drivers/char/tty_io.c | 1 + kernel/panic.c | 1 + kernel/sysctl.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 77 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/drivers/char/sysrq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/char/sysrq.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/char/sysrq.c 2009-02-08 00:02:44.000000000 -0500 +@@ -209,6 +209,22 @@ static struct sysrq_key_op sysrq_showreg + .enable_mask = SYSRQ_ENABLE_DUMP, + }; + ++#if defined(__i386__) ++ ++static void sysrq_handle_showallregs(int key, struct tty_struct *tty) ++{ ++ nmi_show_all_regs(); ++} ++ ++static struct sysrq_key_op sysrq_showallregs_op = { ++ .handler = sysrq_handle_showallregs, ++ .help_msg = "showalLcpupc", ++ .action_msg = "Show Regs On All CPUs", ++}; ++#else ++#define sysrq_showallregs_op (*(struct sysrq_key_op *)0) ++#endif ++ + static void sysrq_handle_showstate(int key, struct tty_struct *tty) + { + show_state(); +@@ -341,7 +357,7 @@ static struct sysrq_key_op *sysrq_key_ta + &sysrq_kill_op, /* i */ + NULL, /* j */ + &sysrq_SAK_op, /* k */ +- NULL, /* l */ ++ &sysrq_showallregs_op, /* l */ + &sysrq_showmem_op, /* m */ + &sysrq_unrt_op, /* n */ + /* o: This will often be registered as 'Off' at init time */ +Index: linux-2.6.24.7-rt27/drivers/char/tty_io.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/char/tty_io.c 2009-02-08 00:02:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/char/tty_io.c 2009-02-08 00:02:44.000000000 -0500 +@@ -258,6 +258,7 @@ static int check_tty_count(struct tty_st + printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) " + "!= #fd's(%d) in %s\n", + tty->name, tty->count, count, routine); ++ dump_stack(); + return count; + } + #endif +Index: linux-2.6.24.7-rt27/kernel/panic.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/panic.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/panic.c 2009-02-08 00:02:44.000000000 -0500 +@@ -79,6 +79,7 @@ NORET_TYPE void panic(const char * fmt, + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf); ++ dump_stack(); + bust_spinlocks(0); + + /* +Index: linux-2.6.24.7-rt27/kernel/sysctl.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sysctl.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sysctl.c 2009-02-08 00:02:44.000000000 -0500 +@@ -340,6 +340,54 @@ static struct ctl_table kern_table[] = { + }, + #endif + { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "prof_pid", ++ .data = &prof_pid, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++#ifdef CONFIG_PREEMPT ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "kernel_preemption", ++ .data = &kernel_preemption, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++#endif ++#ifdef CONFIG_PREEMPT_VOLUNTARY ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "voluntary_preemption", ++ .data = &voluntary_preemption, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++#endif ++#if defined(CONFIG_PREEMPT_SOFTIRQS) && !defined(CONFIG_PREEMPT_RT) ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "softirq_preemption", ++ .data = &softirq_preemption, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++#endif ++#if defined(CONFIG_PREEMPT_HARDIRQS) && !defined(CONFIG_PREEMPT_RT) ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "hardirq_preemption", ++ .data = &hardirq_preemption, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++#endif ++ { + .ctl_name = KERN_PANIC, + .procname = "panic", + .data = &panic_timeout, +@@ -347,6 +395,16 @@ static struct ctl_table kern_table[] = { + .mode = 0644, + .proc_handler = &proc_dointvec, + }, ++#ifdef CONFIG_GENERIC_HARDIRQS ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "debug_direct_keyboard", ++ .data = &debug_direct_keyboard, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++#endif + { + .ctl_name = KERN_CORE_USES_PID, + .procname = "core_uses_pid", --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0539-seqlocks-handle-rwlock-and-spin.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0539-seqlocks-handle-rwlock-and-spin.patch @@ -0,0 +1,55 @@ +From: Steven Rostedt +Subject: seqlock - fix for both PREEMPT_RT and non PREEMPT_RT + +The change to have two different types of locks (spinlocks for raw seqlocks +and rwlocks for preempt seqlocks), caused the non PREEMPT_RT build to fail. + +This patch cleans up the code a bit to allow for both types of locks. + +Signed-off-by: Steven Rostedt +--- + include/linux/seqlock.h | 23 +++++++++++++++++++---- + 1 file changed, 19 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/seqlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/seqlock.h 2009-02-08 00:05:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/seqlock.h 2009-02-08 00:05:07.000000000 -0500 +@@ -30,6 +30,7 @@ + * Priority inheritance and live-lock avoidance by Gregory Haskins + */ + ++#include + #include + #include + +@@ -69,11 +70,25 @@ typedef __raw_seqlock_t raw_seqlock_t; + #define SEQLOCK_UNLOCKED \ + __SEQLOCK_UNLOCKED(old_style_seqlock_init) + +-#define raw_seqlock_init(x) \ +- do { *(x) = (raw_seqlock_t) __RAW_SEQLOCK_UNLOCKED(x); spin_lock_init(&(x)->lock); } while (0) ++static inline void __raw_seqlock_init(raw_seqlock_t *seqlock) ++{ ++ *seqlock = (raw_seqlock_t) __RAW_SEQLOCK_UNLOCKED(x); ++ spin_lock_init(&seqlock->lock); ++} ++ ++#ifdef CONFIG_PREEMPT_RT ++static inline void __seqlock_init(seqlock_t *seqlock) ++{ ++ *seqlock = (seqlock_t) __SEQLOCK_UNLOCKED(seqlock); ++ rwlock_init(&seqlock->lock); ++} ++#else ++extern void __seqlock_init(seqlock_t *seqlock); ++#endif + +-#define seqlock_init(x) \ +- do { *(x) = (seqlock_t) __SEQLOCK_UNLOCKED(x); rwlock_init(&(x)->lock); } while (0) ++#define seqlock_init(seq) \ ++ PICK_FUNCTION(raw_seqlock_t *, seqlock_t *, \ ++ __raw_seqlock_init, __seqlock_init, seq); + + #define DEFINE_SEQLOCK(x) \ + seqlock_t x = __SEQLOCK_UNLOCKED(x) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0315-Add-dev-rmem-device-driver-for-real-time-JVM-testing.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0315-Add-dev-rmem-device-driver-for-real-time-JVM-testing.patch @@ -0,0 +1,193 @@ +Add /dev/rmem device driver for real-time JVM testing + +From: Theodore Ts'o + +This kernel modules is needed for use by the TCK conformance test +which tests the JVM's RTSJ implementation. Unfortunately, RTSJ +requires that Java programs have direct access to physical memory, and +/dev/mem does not allow mmap to work to anything beyond I/O mapped +memory regions on the x86 platform. Since this is a spectacularly bad +idea (so much for write once, debug everywehere) and could potentially +destablize the kernel, set the TAINT_USER flag if available. + +Signed-off-by: "Theodore Ts'o" +--- + + drivers/char/Kconfig | 11 ++++ + drivers/char/Makefile | 1 + drivers/char/rmem.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 146 insertions(+) + +Index: linux-2.6.24.7-rt27/drivers/char/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/char/Kconfig 2009-02-08 00:01:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/char/Kconfig 2009-02-08 00:03:19.000000000 -0500 +@@ -1072,6 +1072,17 @@ config TELCLOCK + /sys/devices/platform/telco_clock, with a number of files for + controlling the behavior of this hardware. + ++config RMEM ++ tristate "Access to physical memory via /dev/rmem" ++ default m ++ help ++ The /dev/mem device only allows mmap() memory available to ++ I/O mapped memory; it does not allow access to "real" ++ physical memory. The /dev/rmem device is a hack which does ++ allow access to physical memory. We use this instead of ++ patching /dev/mem because we don't expect this functionality ++ to ever be accepted into mainline. ++ + config DEVPORT + bool + depends on !M68K +Index: linux-2.6.24.7-rt27/drivers/char/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/char/Makefile 2009-02-08 00:01:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/char/Makefile 2009-02-08 00:03:19.000000000 -0500 +@@ -98,6 +98,7 @@ obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio + obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o + obj-$(CONFIG_GPIO_TB0219) += tb0219.o + obj-$(CONFIG_TELCLOCK) += tlclk.o ++obj-$(CONFIG_RMEM) += rmem.o + + obj-$(CONFIG_MWAVE) += mwave/ + obj-$(CONFIG_AGP) += agp/ +Index: linux-2.6.24.7-rt27/drivers/char/rmem.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/drivers/char/rmem.c 2009-02-08 00:03:19.000000000 -0500 +@@ -0,0 +1,134 @@ ++/* ++ * Rmem - REALLY simple memory mapping demonstration. ++ * ++ * Copyright (C) 2005 by Theodore Ts'o ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int rmem_major = 0; ++module_param(rmem_major, int, 0444); ++ ++static struct class *rmem_class; ++ ++MODULE_AUTHOR("Theodore Ts'o"); ++MODULE_LICENSE("GPL"); ++ ++struct page *rmem_vma_nopage(struct vm_area_struct *vma, ++ unsigned long address, int *type) ++{ ++ struct page *pageptr; ++ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; ++ unsigned long physaddr = address - vma->vm_start + offset; ++ unsigned long pageframe = physaddr >> PAGE_SHIFT; ++ ++ if (!pfn_valid(pageframe)) ++ return NOPAGE_SIGBUS; ++ pageptr = pfn_to_page(pageframe); ++ get_page(pageptr); ++ if (type) ++ *type = VM_FAULT_MINOR; ++ return pageptr; ++} ++ ++static struct vm_operations_struct rmem_nopage_vm_ops = { ++ .nopage = rmem_vma_nopage, ++}; ++ ++static int rmem_nopage_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; ++ ++ if (offset >= __pa(high_memory) || (filp->f_flags & O_SYNC)) ++ vma->vm_flags |= VM_IO; ++ vma->vm_flags |= VM_RESERVED; ++ vma->vm_ops = &rmem_nopage_vm_ops; ++#ifdef TAINT_USER ++ add_taint(TAINT_USER); ++#endif ++ return 0; ++} ++ ++static struct file_operations rmem_nopage_ops = { ++ .owner = THIS_MODULE, ++ .mmap = rmem_nopage_mmap, ++}; ++ ++static struct cdev rmem_cdev = { ++ .kobj = {.k_name = "rmem", }, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init rmem_init(void) ++{ ++ int result; ++ dev_t dev = MKDEV(rmem_major, 0); ++ ++ /* Figure out our device number. */ ++ if (rmem_major) ++ result = register_chrdev_region(dev, 1, "rmem"); ++ else { ++ result = alloc_chrdev_region(&dev, 0, 1, "rmem"); ++ rmem_major = MAJOR(dev); ++ } ++ if (result < 0) { ++ printk(KERN_WARNING "rmem: unable to get major %d\n", rmem_major); ++ return result; ++ } ++ if (rmem_major == 0) ++ rmem_major = result; ++ ++ cdev_init(&rmem_cdev, &rmem_nopage_ops); ++ result = cdev_add(&rmem_cdev, dev, 1); ++ if (result) { ++ printk (KERN_NOTICE "Error %d adding /dev/rmem", result); ++ kobject_put(&rmem_cdev.kobj); ++ unregister_chrdev_region(dev, 1); ++ return 1; ++ } ++ ++ rmem_class = class_create(THIS_MODULE, "rmem"); ++ class_device_create(rmem_class, NULL, dev, NULL, "rmem"); ++ ++ return 0; ++} ++ ++ ++static void __exit rmem_cleanup(void) ++{ ++ cdev_del(&rmem_cdev); ++ unregister_chrdev_region(MKDEV(rmem_major, 0), 1); ++ class_destroy(rmem_class); ++} ++ ++ ++module_init(rmem_init); ++module_exit(rmem_cleanup); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0004-hrtimer-20080427.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0004-hrtimer-20080427.patch @@ -0,0 +1,46 @@ +Subject: [GTI pull] hrtimer fixes + +From: Thomas Gleixner + +Linus, + + +please pull hrtimer fixes from: + + ssh://master.kernel.org/pub/scm/linux/kernel/git/tglx/linux-2.6-hrt.git master + +This fixes a long standing hrtimer reprogramming bug. + +Thanks, + tglx +--- + + kernel/hrtimer.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/hrtimer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/hrtimer.c 2009-02-08 00:00:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/hrtimer.c 2009-02-08 00:00:41.000000000 -0500 +@@ -1172,8 +1172,19 @@ static void run_hrtimer_softirq(struct s + * If the timer was rearmed on another CPU, reprogram + * the event device. + */ +- if (timer->base->first == &timer->node) +- hrtimer_reprogram(timer, timer->base); ++ struct hrtimer_clock_base *base = timer->base; ++ ++ if (base->first == &timer->node && ++ hrtimer_reprogram(timer, base)) { ++ /* ++ * Timer is expired. Thus move it from tree to ++ * pending list again. ++ */ ++ __remove_hrtimer(timer, base, ++ HRTIMER_STATE_PENDING, 0); ++ list_add_tail(&timer->cb_entry, ++ &base->cpu_base->cb_pending); ++ } + } + } + spin_unlock_irq(&cpu_base->lock); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0308-highmem_rewrite.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0308-highmem_rewrite.patch @@ -0,0 +1,626 @@ +Subject: mm: remove kmap_lock + +Eradicate global locks. + + - kmap_lock is removed by extensive use of atomic_t and a new flush scheme. + + - pool_lock is removed by using the pkmap index for the page_address_maps and +modifying set_page_address to only allow NULL<->virt transitions. + +Signed-off-by: Peter Zijlstra +--- + include/linux/mm.h | 32 ++- + mm/highmem.c | 433 ++++++++++++++++++++++++++++++----------------------- + 2 files changed, 276 insertions(+), 189 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/mm.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/mm.h 2009-02-07 23:59:51.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/mm.h 2009-02-08 00:03:16.000000000 -0500 +@@ -543,23 +543,39 @@ static __always_inline void *lowmem_page + #endif + + #if defined(WANT_PAGE_VIRTUAL) +-#define page_address(page) ((page)->virtual) +-#define set_page_address(page, address) \ +- do { \ +- (page)->virtual = (address); \ +- } while(0) +-#define page_address_init() do { } while(0) ++/* ++ * wrap page->virtual so it is safe to set/read locklessly ++ */ ++#define page_address(page) \ ++ ({ typeof((page)->virtual) v = (page)->virtual; \ ++ smp_read_barrier_depends(); \ ++ v; }) ++ ++static inline int set_page_address(struct page *page, void *address) ++{ ++ if (address) ++ return cmpxchg(&page->virtual, NULL, address) == NULL; ++ else { ++ /* ++ * cmpxchg is a bit abused because it is not guaranteed ++ * safe wrt direct assignment on all platforms. ++ */ ++ void *virt = page->virtual; ++ return cmpxchg(&page->vitrual, virt, NULL) == virt; ++ } ++} ++void page_address_init(void); + #endif + + #if defined(HASHED_PAGE_VIRTUAL) + void *page_address(struct page *page); +-void set_page_address(struct page *page, void *virtual); ++int set_page_address(struct page *page, void *virtual); + void page_address_init(void); + #endif + + #if !defined(HASHED_PAGE_VIRTUAL) && !defined(WANT_PAGE_VIRTUAL) + #define page_address(page) lowmem_page_address(page) +-#define set_page_address(page, address) do { } while(0) ++#define set_page_address(page, address) (0) + #define page_address_init() do { } while(0) + #endif + +Index: linux-2.6.24.7-rt27/mm/highmem.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/highmem.c 2009-02-08 00:03:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/highmem.c 2009-02-08 00:03:16.000000000 -0500 +@@ -14,6 +14,11 @@ + * based on Linus' idea. + * + * Copyright (C) 1999 Ingo Molnar ++ * ++ * Largely rewritten to get rid of all global locks ++ * ++ * Copyright (C) 2006 Red Hat, Inc., Peter Zijlstra ++ * + */ + + #include +@@ -27,18 +32,14 @@ + #include + #include + #include ++ + #include ++#include + +-/* +- * Virtual_count is not a pure "count". +- * 0 means that it is not mapped, and has not been mapped +- * since a TLB flush - it is usable. +- * 1 means that there are no users, but it has been mapped +- * since the last TLB flush - so we can't use it. +- * n means that there are (n-1) current users of it. +- */ + #ifdef CONFIG_HIGHMEM + ++static int __set_page_address(struct page *page, void *virtual, int pos); ++ + unsigned long totalhigh_pages __read_mostly; + + unsigned int nr_free_highpages (void) +@@ -58,164 +59,208 @@ unsigned int nr_free_highpages (void) + return pages; + } + +-static int pkmap_count[LAST_PKMAP]; +-static unsigned int last_pkmap_nr; +-static __cacheline_aligned_in_smp DEFINE_SPINLOCK(kmap_lock); ++/* ++ * count is not a pure "count". ++ * 0 means its owned exclusively by someone ++ * 1 means its free for use - either mapped or not. ++ * n means that there are (n-1) current users of it. ++ */ ++static atomic_t pkmap_count[LAST_PKMAP]; ++static atomic_t pkmap_hand; + + pte_t * pkmap_page_table; + + static DECLARE_WAIT_QUEUE_HEAD(pkmap_map_wait); + +-static void flush_all_zero_pkmaps(void) ++/* ++ * Try to free a given kmap slot. ++ * ++ * Returns: ++ * -1 - in use ++ * 0 - free, no TLB flush needed ++ * 1 - free, needs TLB flush ++ */ ++static int pkmap_try_free(int pos) + { +- int i; +- +- flush_cache_kmaps(); ++ if (atomic_cmpxchg(&pkmap_count[pos], 1, 0) != 1) ++ return -1; + +- for (i = 0; i < LAST_PKMAP; i++) { +- struct page *page; ++ /* ++ * TODO: add a young bit to make it CLOCK ++ */ ++ if (!pte_none(pkmap_page_table[pos])) { ++ struct page *page = pte_page(pkmap_page_table[pos]); ++ unsigned long addr = PKMAP_ADDR(pos); ++ pte_t *ptep = &pkmap_page_table[pos]; ++ ++ VM_BUG_ON(addr != (unsigned long)page_address(page)); ++ ++ if (!__set_page_address(page, NULL, pos)) ++ BUG(); ++ flush_kernel_dcache_page(page); ++ pte_clear(&init_mm, addr, ptep); + +- /* +- * zero means we don't have anything to do, +- * >1 means that it is still in use. Only +- * a count of 1 means that it is free but +- * needs to be unmapped +- */ +- if (pkmap_count[i] != 1) +- continue; +- pkmap_count[i] = 0; ++ return 1; ++ } + +- /* sanity check */ +- BUG_ON(pte_none(pkmap_page_table[i])); ++ return 0; ++} + +- /* +- * Don't need an atomic fetch-and-clear op here; +- * no-one has the page mapped, and cannot get at +- * its virtual address (and hence PTE) without first +- * getting the kmap_lock (which is held here). +- * So no dangers, even with speculative execution. +- */ +- page = pte_page(pkmap_page_table[i]); +- pte_clear(&init_mm, (unsigned long)page_address(page), +- &pkmap_page_table[i]); ++static inline void pkmap_put(atomic_t *counter) ++{ ++ switch (atomic_dec_return(counter)) { ++ case 0: ++ BUG(); + +- set_page_address(page, NULL); ++ case 1: ++ wake_up(&pkmap_map_wait); + } +- flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP)); + } + +-static inline unsigned long map_new_virtual(struct page *page) ++#define TLB_BATCH 32 ++ ++static int pkmap_get_free(void) + { +- unsigned long vaddr; +- int count; ++ int i, pos, flush; ++ DECLARE_WAITQUEUE(wait, current); + +-start: +- count = LAST_PKMAP; +- /* Find an empty entry */ +- for (;;) { +- last_pkmap_nr = (last_pkmap_nr + 1) & LAST_PKMAP_MASK; +- if (!last_pkmap_nr) { +- flush_all_zero_pkmaps(); +- count = LAST_PKMAP; +- } +- if (!pkmap_count[last_pkmap_nr]) +- break; /* Found a usable entry */ +- if (--count) +- continue; ++restart: ++ for (i = 0; i < LAST_PKMAP; i++) { ++ pos = atomic_inc_return(&pkmap_hand) % LAST_PKMAP; ++ flush = pkmap_try_free(pos); ++ if (flush >= 0) ++ goto got_one; ++ } ++ ++ /* ++ * wait for somebody else to unmap their entries ++ */ ++ __set_current_state(TASK_UNINTERRUPTIBLE); ++ add_wait_queue(&pkmap_map_wait, &wait); ++ schedule(); ++ remove_wait_queue(&pkmap_map_wait, &wait); ++ ++ goto restart; ++ ++got_one: ++ if (flush) { ++#if 0 ++ flush_tlb_kernel_range(PKMAP_ADDR(pos), PKMAP_ADDR(pos+1)); ++#else ++ int pos2 = (pos + 1) % LAST_PKMAP; ++ int nr; ++ int entries[TLB_BATCH]; + + /* +- * Sleep for somebody else to unmap their entries ++ * For those architectures that cannot help but flush the ++ * whole TLB, flush some more entries to make it worthwhile. ++ * Scan ahead of the hand to minimise search distances. + */ +- { +- DECLARE_WAITQUEUE(wait, current); ++ for (i = 0, nr = 0; i < LAST_PKMAP && nr < TLB_BATCH; ++ i++, pos2 = (pos2 + 1) % LAST_PKMAP) { + +- __set_current_state(TASK_UNINTERRUPTIBLE); +- add_wait_queue(&pkmap_map_wait, &wait); +- spin_unlock(&kmap_lock); +- schedule(); +- remove_wait_queue(&pkmap_map_wait, &wait); +- spin_lock(&kmap_lock); +- +- /* Somebody else might have mapped it while we slept */ +- if (page_address(page)) +- return (unsigned long)page_address(page); ++ flush = pkmap_try_free(pos2); ++ if (flush < 0) ++ continue; ++ ++ if (!flush) { ++ atomic_t *counter = &pkmap_count[pos2]; ++ VM_BUG_ON(atomic_read(counter) != 0); ++ atomic_set(counter, 2); ++ pkmap_put(counter); ++ } else ++ entries[nr++] = pos2; ++ } ++ flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP)); + +- /* Re-start */ +- goto start; ++ for (i = 0; i < nr; i++) { ++ atomic_t *counter = &pkmap_count[entries[i]]; ++ VM_BUG_ON(atomic_read(counter) != 0); ++ atomic_set(counter, 2); ++ pkmap_put(counter); + } ++#endif + } +- vaddr = PKMAP_ADDR(last_pkmap_nr); +- set_pte_at(&init_mm, vaddr, +- &(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot)); ++ return pos; ++} ++ ++static unsigned long pkmap_insert(struct page *page) ++{ ++ int pos = pkmap_get_free(); ++ unsigned long vaddr = PKMAP_ADDR(pos); ++ pte_t *ptep = &pkmap_page_table[pos]; ++ pte_t entry = mk_pte(page, kmap_prot); ++ atomic_t *counter = &pkmap_count[pos]; ++ ++ VM_BUG_ON(atomic_read(counter) != 0); + +- pkmap_count[last_pkmap_nr] = 1; +- set_page_address(page, (void *)vaddr); ++ set_pte_at(&init_mm, vaddr, ptep, entry); ++ if (unlikely(!__set_page_address(page, (void *)vaddr, pos))) { ++ /* ++ * concurrent pkmap_inserts for this page - ++ * the other won the race, release this entry. ++ * ++ * we can still clear the pte without a tlb flush since ++ * it couldn't have been used yet. ++ */ ++ pte_clear(&init_mm, vaddr, ptep); ++ VM_BUG_ON(atomic_read(counter) != 0); ++ atomic_set(counter, 2); ++ pkmap_put(counter); ++ vaddr = 0; ++ } else ++ atomic_set(counter, 2); + + return vaddr; + } + +-void fastcall *kmap_high(struct page *page) ++fastcall void *kmap_high(struct page *page) + { + unsigned long vaddr; +- +- /* +- * For highmem pages, we can't trust "virtual" until +- * after we have the lock. +- * +- * We cannot call this from interrupts, as it may block +- */ +- spin_lock(&kmap_lock); ++again: + vaddr = (unsigned long)page_address(page); ++ if (vaddr) { ++ atomic_t *counter = &pkmap_count[PKMAP_NR(vaddr)]; ++ if (atomic_inc_not_zero(counter)) { ++ /* ++ * atomic_inc_not_zero implies a (memory) barrier on success ++ * so page address will be reloaded. ++ */ ++ unsigned long vaddr2 = (unsigned long)page_address(page); ++ if (likely(vaddr == vaddr2)) ++ return (void *)vaddr; ++ ++ /* ++ * Oops, we got someone else. ++ * ++ * This can happen if we get preempted after ++ * page_address() and before atomic_inc_not_zero() ++ * and during that preemption this slot is freed and ++ * reused. ++ */ ++ pkmap_put(counter); ++ goto again; ++ } ++ } ++ ++ vaddr = pkmap_insert(page); + if (!vaddr) +- vaddr = map_new_virtual(page); +- pkmap_count[PKMAP_NR(vaddr)]++; +- BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 2); +- spin_unlock(&kmap_lock); +- return (void*) vaddr; ++ goto again; ++ ++ return (void *)vaddr; + } + + EXPORT_SYMBOL(kmap_high); + +-void fastcall kunmap_high(struct page *page) ++fastcall void kunmap_high(struct page *page) + { +- unsigned long vaddr; +- unsigned long nr; +- int need_wakeup; +- +- spin_lock(&kmap_lock); +- vaddr = (unsigned long)page_address(page); ++ unsigned long vaddr = (unsigned long)page_address(page); + BUG_ON(!vaddr); +- nr = PKMAP_NR(vaddr); +- +- /* +- * A count must never go down to zero +- * without a TLB flush! +- */ +- need_wakeup = 0; +- switch (--pkmap_count[nr]) { +- case 0: +- BUG(); +- case 1: +- /* +- * Avoid an unnecessary wake_up() function call. +- * The common case is pkmap_count[] == 1, but +- * no waiters. +- * The tasks queued in the wait-queue are guarded +- * by both the lock in the wait-queue-head and by +- * the kmap_lock. As the kmap_lock is held here, +- * no need for the wait-queue-head's lock. Simply +- * test if the queue is empty. +- */ +- need_wakeup = waitqueue_active(&pkmap_map_wait); +- } +- spin_unlock(&kmap_lock); +- +- /* do wake-up, if needed, race-free outside of the spin lock */ +- if (need_wakeup) +- wake_up(&pkmap_map_wait); ++ pkmap_put(&pkmap_count[PKMAP_NR(vaddr)]); + } + + EXPORT_SYMBOL(kunmap_high); ++ + #endif + + #if defined(HASHED_PAGE_VIRTUAL) +@@ -223,19 +268,13 @@ EXPORT_SYMBOL(kunmap_high); + #define PA_HASH_ORDER 7 + + /* +- * Describes one page->virtual association ++ * Describes one page->virtual address association. + */ +-struct page_address_map { ++static struct page_address_map { + struct page *page; + void *virtual; + struct list_head list; +-}; +- +-/* +- * page_address_map freelist, allocated from page_address_maps. +- */ +-static struct list_head page_address_pool; /* freelist */ +-static spinlock_t pool_lock; /* protects page_address_pool */ ++} page_address_maps[LAST_PKMAP]; + + /* + * Hash table bucket +@@ -250,91 +289,123 @@ static struct page_address_slot *page_sl + return &page_address_htable[hash_ptr(page, PA_HASH_ORDER)]; + } + +-void *page_address(struct page *page) ++static void *__page_address(struct page_address_slot *pas, struct page *page) + { +- unsigned long flags; +- void *ret; +- struct page_address_slot *pas; +- +- if (!PageHighMem(page)) +- return lowmem_page_address(page); ++ void *ret = NULL; + +- pas = page_slot(page); +- ret = NULL; +- spin_lock_irqsave(&pas->lock, flags); + if (!list_empty(&pas->lh)) { + struct page_address_map *pam; + + list_for_each_entry(pam, &pas->lh, list) { + if (pam->page == page) { + ret = pam->virtual; +- goto done; ++ break; + } + } + } +-done: ++ ++ return ret; ++} ++ ++void *page_address(struct page *page) ++{ ++ unsigned long flags; ++ void *ret; ++ struct page_address_slot *pas; ++ ++ if (!PageHighMem(page)) ++ return lowmem_page_address(page); ++ ++ pas = page_slot(page); ++ spin_lock_irqsave(&pas->lock, flags); ++ ret = __page_address(pas, page); + spin_unlock_irqrestore(&pas->lock, flags); + return ret; + } + + EXPORT_SYMBOL(page_address); + +-void set_page_address(struct page *page, void *virtual) ++static int __set_page_address(struct page *page, void *virtual, int pos) + { ++ int ret = 0; + unsigned long flags; + struct page_address_slot *pas; + struct page_address_map *pam; + +- BUG_ON(!PageHighMem(page)); ++ VM_BUG_ON(!PageHighMem(page)); ++ VM_BUG_ON(atomic_read(&pkmap_count[pos]) != 0); ++ VM_BUG_ON(pos < 0 || pos >= LAST_PKMAP); + + pas = page_slot(page); +- if (virtual) { /* Add */ +- BUG_ON(list_empty(&page_address_pool)); ++ pam = &page_address_maps[pos]; + +- spin_lock_irqsave(&pool_lock, flags); +- pam = list_entry(page_address_pool.next, +- struct page_address_map, list); +- list_del(&pam->list); +- spin_unlock_irqrestore(&pool_lock, flags); +- +- pam->page = page; +- pam->virtual = virtual; +- +- spin_lock_irqsave(&pas->lock, flags); +- list_add_tail(&pam->list, &pas->lh); +- spin_unlock_irqrestore(&pas->lock, flags); +- } else { /* Remove */ +- spin_lock_irqsave(&pas->lock, flags); +- list_for_each_entry(pam, &pas->lh, list) { +- if (pam->page == page) { +- list_del(&pam->list); +- spin_unlock_irqrestore(&pas->lock, flags); +- spin_lock_irqsave(&pool_lock, flags); +- list_add_tail(&pam->list, &page_address_pool); +- spin_unlock_irqrestore(&pool_lock, flags); +- goto done; +- } ++ spin_lock_irqsave(&pas->lock, flags); ++ if (virtual) { /* add */ ++ VM_BUG_ON(!list_empty(&pam->list)); ++ ++ if (!__page_address(pas, page)) { ++ pam->page = page; ++ pam->virtual = virtual; ++ list_add_tail(&pam->list, &pas->lh); ++ ret = 1; ++ } ++ } else { /* remove */ ++ if (!list_empty(&pam->list)) { ++ list_del_init(&pam->list); ++ ret = 1; + } +- spin_unlock_irqrestore(&pas->lock, flags); + } +-done: +- return; ++ spin_unlock_irqrestore(&pas->lock, flags); ++ ++ return ret; + } + +-static struct page_address_map page_address_maps[LAST_PKMAP]; ++int set_page_address(struct page *page, void *virtual) ++{ ++ /* ++ * set_page_address is not supposed to be called when using ++ * hashed virtual addresses. ++ */ ++ BUG(); ++ return 0; ++} + +-void __init page_address_init(void) ++void __init __page_address_init(void) + { + int i; + +- INIT_LIST_HEAD(&page_address_pool); + for (i = 0; i < ARRAY_SIZE(page_address_maps); i++) +- list_add(&page_address_maps[i].list, &page_address_pool); ++ INIT_LIST_HEAD(&page_address_maps[i].list); ++ + for (i = 0; i < ARRAY_SIZE(page_address_htable); i++) { + INIT_LIST_HEAD(&page_address_htable[i].lh); + spin_lock_init(&page_address_htable[i].lock); + } +- spin_lock_init(&pool_lock); ++} ++ ++#elif defined (CONFIG_HIGHMEM) /* HASHED_PAGE_VIRTUAL */ ++ ++static int __set_page_address(struct page *page, void *virtual, int pos) ++{ ++ return set_page_address(page, virtual); + } + + #endif /* defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL) */ ++ ++#if defined(CONFIG_HIGHMEM) || defined(HASHED_PAGE_VIRTUAL) ++ ++void __init page_address_init(void) ++{ ++#ifdef CONFIG_HIGHMEM ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(pkmap_count); i++) ++ atomic_set(&pkmap_count[i], 1); ++#endif ++ ++#ifdef HASHED_PAGE_VIRTUAL ++ __page_address_init(); ++#endif ++} ++ ++#endif --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0221-preempt-realtime-powerpc-a7.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0221-preempt-realtime-powerpc-a7.patch @@ -0,0 +1,124 @@ + + To fix the following compile error by changing local_irq_restore() +to raw_local_irq_restore(). + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +include/asm-powerpc/hw_irq.h +In file included from include/asm/system.h:9, + from include/linux/list.h:9, + from include/linux/signal.h:8, + from arch/powerpc/kernel/asm-offsets.c:16: +include/asm/hw_irq.h: In function 'local_get_flags': +include/asm/hw_irq.h:23: error: expected expression before '<<' token +include/asm/hw_irq.h:24: error: expected expression before '<<' token +include/asm/hw_irq.h:25: error: expected expression before ':' token +include/asm/hw_irq.h:25: error: expected statement before ')' token +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +Signed-off-by: Tsutomu Owa +-- owa + +--- + arch/powerpc/kernel/head_64.S | 2 +- + arch/powerpc/kernel/irq.c | 2 +- + arch/powerpc/kernel/ppc_ksyms.c | 2 +- + include/asm-powerpc/hw_irq.h | 18 ++++++++---------- + 4 files changed, 11 insertions(+), 13 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/head_64.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/head_64.S 2009-02-08 00:00:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/head_64.S 2009-02-08 00:02:30.000000000 -0500 +@@ -878,7 +878,7 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISER + * handles any interrupts pending at this point. + */ + ld r3,SOFTE(r1) +- bl .local_irq_restore ++ bl .raw_local_irq_restore + b 11f + + /* Here we have a page fault that hash_page can't handle. */ +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/irq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/irq.c 2009-02-08 00:01:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/irq.c 2009-02-08 00:02:30.000000000 -0500 +@@ -112,7 +112,7 @@ static inline notrace void set_soft_enab + : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); + } + +-notrace void local_irq_restore(unsigned long en) ++notrace void raw_local_irq_restore(unsigned long en) + { + /* + * get_paca()->soft_enabled = en; +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/ppc_ksyms.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/ppc_ksyms.c 2009-02-08 00:02:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/ppc_ksyms.c 2009-02-08 00:02:30.000000000 -0500 +@@ -46,7 +46,7 @@ + #include + + #ifdef CONFIG_PPC64 +-EXPORT_SYMBOL(local_irq_restore); ++EXPORT_SYMBOL(raw_local_irq_restore); + #endif + + #ifdef CONFIG_PPC32 +Index: linux-2.6.24.7-rt27/include/asm-powerpc/hw_irq.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-powerpc/hw_irq.h 2009-02-08 00:02:29.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-powerpc/hw_irq.h 2009-02-08 00:02:30.000000000 -0500 +@@ -16,18 +16,18 @@ extern void timer_interrupt(struct pt_re + #ifdef CONFIG_PPC64 + #include + +-static inline unsigned long local_get_flags(void) ++static inline unsigned long raw_local_get_flags(void) + { + unsigned long flags; + +-<<<<<<< delete extern unsigned long local_get_flags(void); +-<<<<<<< delete extern unsigned long local_irq_disable(void); ++ __asm__ __volatile__("lbz %0,%1(13)" ++ : "=r" (flags) + : "i" (offsetof(struct paca_struct, soft_enabled))); + + return flags; + } + +-static inline unsigned long local_irq_disable(void) ++static inline unsigned long raw_local_irq_disable(void) + { + unsigned long flags, zero; + +@@ -53,8 +53,8 @@ extern void raw_local_irq_restore(unsign + #define raw_irqs_disabled_flags(flags) ((flags) == 0) + + +-#define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) +-#define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) ++#define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) ++#define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) + + #define hard_irq_disable() \ + do { \ +@@ -63,17 +63,15 @@ extern void raw_local_irq_restore(unsign + get_paca()->hard_enabled = 0; \ + } while(0) + +-#else ++#else /* CONFIG_PPC64 */ + + #if defined(CONFIG_BOOKE) + #define SET_MSR_EE(x) mtmsr(x) + #define raw_local_irq_restore(flags) __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory") +-<<<<<<< delete #define local_irq_restore(flags) do { \ +-#define raw_local_irq_restore(flags) do { \ + #else + #define SET_MSR_EE(x) mtmsr(x) + #define raw_local_irq_restore(flags) mtmsr(flags) +-#endif ++#endif /* CONFIG_BOOKE */ + + static inline void raw_local_irq_disable(void) + { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0124-rcu-new-7.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0124-rcu-new-7.patch @@ -0,0 +1,253 @@ +From paulmck@linux.vnet.ibm.com Thu Sep 27 15:32:09 2007 +Date: Mon, 10 Sep 2007 11:39:46 -0700 +From: Paul E. McKenney +To: linux-kernel@vger.kernel.org +Cc: linux-rt-users@vger.kernel.org, mingo@elte.hu, akpm@linux-foundation.org, + dipankar@in.ibm.com, josht@linux.vnet.ibm.com, tytso@us.ibm.com, + dvhltc@us.ibm.com, tglx@linutronix.de, a.p.zijlstra@chello.nl, + bunk@kernel.org, ego@in.ibm.com, oleg@tv-sign.ru, srostedt@redhat.com +Subject: [PATCH RFC 7/9] RCU: rcutorture testing for RCU priority boosting + +Work in progress, not for inclusion. Still uses xtime because this +patch is still against 2.6.22. + +This patch modifies rcutorture to also torture RCU priority boosting. +The torturing involves forcing RCU read-side critical sections (already +performed as part of the torturing of RCU) to run for extremely long +time periods, increasing the probability of their being preempted and +thus needing priority boosting. The fact that rcutorture's "nreaders" +module parameter defaults to twice the number of CPUs helps ensure lots +of the needed preemption. + +To cause the torturing to be fully effective in -mm, run in presence +of CPU-hotplug operations. + +Signed-off-by: Paul E. McKenney +--- + + kernel/rcutorture.c | 91 ++++++++++++++++++++++++++++++++++++++-------- + kernel/time/timekeeping.c | 2 + + 2 files changed, 79 insertions(+), 14 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rcutorture.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcutorture.c 2009-02-08 00:00:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcutorture.c 2009-02-08 00:01:42.000000000 -0500 +@@ -57,6 +57,7 @@ static int stat_interval; /* Interval be + static int verbose; /* Print more debug info. */ + static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ + static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/ ++static int preempt_torture; /* Realtime task preempts torture readers. */ + static char *torture_type = "rcu"; /* What RCU implementation to torture. */ + + module_param(nreaders, int, 0444); +@@ -71,6 +72,8 @@ module_param(test_no_idle_hz, bool, 0444 + MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs"); + module_param(shuffle_interval, int, 0444); + MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); ++module_param(preempt_torture, bool, 0444); ++MODULE_PARM_DESC(preempt_torture, "Enable realtime preemption torture"); + module_param(torture_type, charp, 0444); + MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)"); + +@@ -191,6 +194,8 @@ struct rcu_torture_ops { + int (*completed)(void); + void (*deferredfree)(struct rcu_torture *p); + void (*sync)(void); ++ long (*preemptstart)(void); ++ void (*preemptend)(void); + int (*stats)(char *page); + char *name; + }; +@@ -255,16 +260,75 @@ static void rcu_torture_deferred_free(st + call_rcu(&p->rtort_rcu, rcu_torture_cb); + } + ++static struct task_struct *rcu_preeempt_task; ++static unsigned long rcu_torture_preempt_errors; ++ ++static int rcu_torture_preempt(void *arg) ++{ ++ int completedstart; ++ int err; ++ time_t gcstart; ++ struct sched_param sp; ++ ++ sp.sched_priority = MAX_RT_PRIO - 1; ++ err = sched_setscheduler(current, SCHED_RR, &sp); ++ if (err != 0) ++ printk(KERN_ALERT "rcu_torture_preempt() priority err: %d\n", ++ err); ++ current->flags |= PF_NOFREEZE; ++ ++ do { ++ completedstart = rcu_torture_completed(); ++ gcstart = xtime.tv_sec; ++ while ((xtime.tv_sec - gcstart < 10) && ++ (rcu_torture_completed() == completedstart)) ++ cond_resched(); ++ if (rcu_torture_completed() == completedstart) ++ rcu_torture_preempt_errors++; ++ schedule_timeout_interruptible(1); ++ } while (!kthread_should_stop()); ++ return 0; ++} ++ ++static long rcu_preempt_start(void) ++{ ++ long retval = 0; ++ ++ rcu_preeempt_task = kthread_run(rcu_torture_preempt, NULL, ++ "rcu_torture_preempt"); ++ if (IS_ERR(rcu_preeempt_task)) { ++ VERBOSE_PRINTK_ERRSTRING("Failed to create preempter"); ++ retval = PTR_ERR(rcu_preeempt_task); ++ rcu_preeempt_task = NULL; ++ } ++ return retval; ++} ++ ++static void rcu_preempt_end(void) ++{ ++ if (rcu_preeempt_task != NULL) { ++ VERBOSE_PRINTK_STRING("Stopping rcu_preempt task"); ++ kthread_stop(rcu_preeempt_task); ++ } ++ rcu_preeempt_task = NULL; ++} ++ ++static int rcu_preempt_stats(char *page) ++{ ++ return sprintf(page, ++ "Preemption stalls: %lu\n", rcu_torture_preempt_errors); ++} ++ + static struct rcu_torture_ops rcu_ops = { +- .init = NULL, +- .cleanup = NULL, + .readlock = rcu_torture_read_lock, + .readdelay = rcu_read_delay, + .readunlock = rcu_torture_read_unlock, + .completed = rcu_torture_completed, + .deferredfree = rcu_torture_deferred_free, + .sync = synchronize_rcu, +- .stats = NULL, ++ .preemptstart = rcu_preempt_start, ++ .preemptend = rcu_preempt_end, ++ .stats = rcu_preempt_stats, + .name = "rcu" + }; + +@@ -296,14 +360,12 @@ static void rcu_sync_torture_init(void) + + static struct rcu_torture_ops rcu_sync_ops = { + .init = rcu_sync_torture_init, +- .cleanup = NULL, + .readlock = rcu_torture_read_lock, + .readdelay = rcu_read_delay, + .readunlock = rcu_torture_read_unlock, + .completed = rcu_torture_completed, + .deferredfree = rcu_sync_torture_deferred_free, + .sync = synchronize_rcu, +- .stats = NULL, + .name = "rcu_sync" + }; + +@@ -355,28 +417,23 @@ static void rcu_bh_torture_synchronize(v + } + + static struct rcu_torture_ops rcu_bh_ops = { +- .init = NULL, +- .cleanup = NULL, + .readlock = rcu_bh_torture_read_lock, + .readdelay = rcu_read_delay, /* just reuse rcu's version. */ + .readunlock = rcu_bh_torture_read_unlock, + .completed = rcu_bh_torture_completed, + .deferredfree = rcu_bh_torture_deferred_free, + .sync = rcu_bh_torture_synchronize, +- .stats = NULL, + .name = "rcu_bh" + }; + + static struct rcu_torture_ops rcu_bh_sync_ops = { + .init = rcu_sync_torture_init, +- .cleanup = NULL, + .readlock = rcu_bh_torture_read_lock, + .readdelay = rcu_read_delay, /* just reuse rcu's version. */ + .readunlock = rcu_bh_torture_read_unlock, + .completed = rcu_bh_torture_completed, + .deferredfree = rcu_sync_torture_deferred_free, + .sync = rcu_bh_torture_synchronize, +- .stats = NULL, + .name = "rcu_bh_sync" + }; + +@@ -488,14 +545,12 @@ static void sched_torture_synchronize(vo + + static struct rcu_torture_ops sched_ops = { + .init = rcu_sync_torture_init, +- .cleanup = NULL, + .readlock = sched_torture_read_lock, + .readdelay = rcu_read_delay, /* just reuse rcu's version. */ + .readunlock = sched_torture_read_unlock, + .completed = sched_torture_completed, + .deferredfree = rcu_sync_torture_deferred_free, + .sync = sched_torture_synchronize, +- .stats = NULL, + .name = "sched" + }; + +@@ -787,9 +842,10 @@ rcu_torture_print_module_parms(char *tag + printk(KERN_ALERT "%s" TORTURE_FLAG + "--- %s: nreaders=%d nfakewriters=%d " + "stat_interval=%d verbose=%d test_no_idle_hz=%d " +- "shuffle_interval = %d\n", ++ "shuffle_interval=%d preempt_torture=%d\n", + torture_type, tag, nrealreaders, nfakewriters, +- stat_interval, verbose, test_no_idle_hz, shuffle_interval); ++ stat_interval, verbose, test_no_idle_hz, shuffle_interval, ++ preempt_torture); + } + + static void +@@ -842,6 +898,8 @@ rcu_torture_cleanup(void) + kthread_stop(stats_task); + } + stats_task = NULL; ++ if (preempt_torture && (cur_ops->preemptend != NULL)) ++ cur_ops->preemptend(); + + /* Wait for all RCU callbacks to fire. */ + rcu_barrier(); +@@ -984,6 +1042,11 @@ rcu_torture_init(void) + goto unwind; + } + } ++ if (preempt_torture && (cur_ops->preemptstart != NULL)) { ++ firsterr = cur_ops->preemptstart(); ++ if (firsterr != 0) ++ goto unwind; ++ } + return 0; + + unwind: +Index: linux-2.6.24.7-rt27/kernel/time/timekeeping.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/timekeeping.c 2009-02-08 00:00:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/timekeeping.c 2009-02-08 00:01:42.000000000 -0500 +@@ -26,6 +26,7 @@ + */ + __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock); + ++EXPORT_SYMBOL_GPL(xtime_lock); + + /* + * The current time +@@ -45,6 +46,7 @@ __cacheline_aligned_in_smp DEFINE_SEQLOC + struct timespec xtime __attribute__ ((aligned (16))); + struct timespec wall_to_monotonic __attribute__ ((aligned (16))); + static unsigned long total_sleep_time; /* seconds */ ++EXPORT_SYMBOL_GPL(xtime); + + static struct timespec xtime_cache __attribute__ ((aligned (16))); + static inline void update_xtime_cache(u64 nsec) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0295-mm-concurrent-pagecache.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0295-mm-concurrent-pagecache.patch @@ -0,0 +1,471 @@ +Subject: mm: concurrent pagecache write side + +Remove the tree_lock, change address_space::nrpages to atomic_long_t +because its not protected any longer and use the concurrent radix tree API to +protect the modifying radix tree operations. + +The tree_lock is actually renamed to priv_lock and its only remaining user will +be the __flush_dcache_page logic on arm an parisc. Another potential user would +be the per address_space node mask allocation Christoph is working on. + + [ BUG: the NFS client code seems to rely on mapping->tree_lock in some hidden + way, which makes it crash... ] + +Signed-off-by: Peter Zijlstra +--- + fs/buffer.c | 7 ++++--- + fs/inode.c | 2 +- + include/asm-arm/cacheflush.h | 4 ++-- + include/asm-parisc/cacheflush.h | 4 ++-- + include/linux/fs.h | 12 ++++++------ + mm/filemap.c | 17 +++++++++-------- + mm/migrate.c | 12 ++++++------ + mm/page-writeback.c | 33 +++++++++++++++++++-------------- + mm/swap_state.c | 18 ++++++++++-------- + mm/swapfile.c | 2 -- + mm/truncate.c | 3 --- + mm/vmscan.c | 4 ---- + 12 files changed, 59 insertions(+), 59 deletions(-) + +Index: linux-2.6.24.7-rt27/fs/buffer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/buffer.c 2009-02-08 00:03:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/buffer.c 2009-02-08 00:03:09.000000000 -0500 +@@ -698,8 +698,8 @@ static int __set_page_dirty(struct page + return 0; + + lock_page_ref_irq(page); +- spin_lock(&mapping->tree_lock); + if (page->mapping) { /* Race with truncate? */ ++ DEFINE_RADIX_TREE_CONTEXT(ctx, &mapping->page_tree); + WARN_ON_ONCE(warn && !PageUptodate(page)); + + if (mapping_cap_account_dirty(mapping)) { +@@ -708,10 +708,11 @@ static int __set_page_dirty(struct page + BDI_RECLAIMABLE); + task_io_account_write(PAGE_CACHE_SIZE); + } +- radix_tree_tag_set(&mapping->page_tree, ++ radix_tree_lock(&ctx); ++ radix_tree_tag_set(ctx.tree, + page_index(page), PAGECACHE_TAG_DIRTY); ++ radix_tree_unlock(&ctx); + } +- spin_unlock(&mapping->tree_lock); + unlock_page_ref_irq(page); + __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); + +Index: linux-2.6.24.7-rt27/fs/inode.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/inode.c 2009-02-08 00:03:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/inode.c 2009-02-08 00:03:09.000000000 -0500 +@@ -209,7 +209,7 @@ void inode_init_once(struct inode *inode + INIT_LIST_HEAD(&inode->i_dentry); + INIT_LIST_HEAD(&inode->i_devices); + INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC); +- spin_lock_init(&inode->i_data.tree_lock); ++ spin_lock_init(&inode->i_data.priv_lock); + spin_lock_init(&inode->i_data.i_mmap_lock); + INIT_LIST_HEAD(&inode->i_data.private_list); + spin_lock_init(&inode->i_data.private_lock); +Index: linux-2.6.24.7-rt27/include/asm-arm/cacheflush.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/cacheflush.h 2009-02-08 00:03:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/cacheflush.h 2009-02-08 00:03:09.000000000 -0500 +@@ -413,9 +413,9 @@ static inline void flush_anon_page(struc + } + + #define flush_dcache_mmap_lock(mapping) \ +- spin_lock_irq(&(mapping)->tree_lock) ++ spin_lock_irq(&(mapping)->priv_lock) + #define flush_dcache_mmap_unlock(mapping) \ +- spin_unlock_irq(&(mapping)->tree_lock) ++ spin_unlock_irq(&(mapping)->priv_lock) + + #define flush_icache_user_range(vma,page,addr,len) \ + flush_dcache_page(page) +Index: linux-2.6.24.7-rt27/include/asm-parisc/cacheflush.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-parisc/cacheflush.h 2009-02-08 00:03:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-parisc/cacheflush.h 2009-02-08 00:03:09.000000000 -0500 +@@ -45,9 +45,9 @@ void flush_cache_mm(struct mm_struct *mm + extern void flush_dcache_page(struct page *page); + + #define flush_dcache_mmap_lock(mapping) \ +- spin_lock_irq(&(mapping)->tree_lock) ++ spin_lock_irq(&(mapping)->priv_lock) + #define flush_dcache_mmap_unlock(mapping) \ +- spin_unlock_irq(&(mapping)->tree_lock) ++ spin_unlock_irq(&(mapping)->priv_lock) + + #define flush_icache_page(vma,page) do { \ + flush_kernel_dcache_page(page); \ +Index: linux-2.6.24.7-rt27/include/linux/fs.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/fs.h 2009-02-08 00:03:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/fs.h 2009-02-08 00:03:09.000000000 -0500 +@@ -499,13 +499,13 @@ struct backing_dev_info; + struct address_space { + struct inode *host; /* owner: inode, block_device */ + struct radix_tree_root page_tree; /* radix tree of all pages */ +- spinlock_t tree_lock; /* and lock protecting it */ ++ spinlock_t priv_lock; /* spinlock protecting various stuffs */ + unsigned int i_mmap_writable;/* count VM_SHARED mappings */ + struct prio_tree_root i_mmap; /* tree of private and shared mappings */ + struct list_head i_mmap_nonlinear;/*list VM_NONLINEAR mappings */ + spinlock_t i_mmap_lock; /* protect tree, count, list */ + unsigned int truncate_count; /* Cover race condition with truncate */ +- unsigned long __nrpages; /* number of total pages */ ++ atomic_long_t __nrpages; /* number of total pages */ + pgoff_t writeback_index;/* writeback starts here */ + const struct address_space_operations *a_ops; /* methods */ + unsigned long flags; /* error bits/gfp mask */ +@@ -522,22 +522,22 @@ struct address_space { + + static inline void mapping_nrpages_init(struct address_space *mapping) + { +- mapping->__nrpages = 0; ++ mapping->__nrpages = (atomic_long_t)ATOMIC_LONG_INIT(0); + } + + static inline unsigned long mapping_nrpages(struct address_space *mapping) + { +- return mapping->__nrpages; ++ return (unsigned long)atomic_long_read(&mapping->__nrpages); + } + + static inline void mapping_nrpages_inc(struct address_space *mapping) + { +- mapping->__nrpages++; ++ atomic_long_inc(&mapping->__nrpages); + } + + static inline void mapping_nrpages_dec(struct address_space *mapping) + { +- mapping->__nrpages--; ++ atomic_long_dec(&mapping->__nrpages); + } + + struct block_device { +Index: linux-2.6.24.7-rt27/mm/filemap.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/filemap.c 2009-02-08 00:03:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/filemap.c 2009-02-08 00:03:09.000000000 -0500 +@@ -118,8 +118,11 @@ generic_file_direct_IO(int rw, struct ki + void __remove_from_page_cache(struct page *page) + { + struct address_space *mapping = page->mapping; ++ DEFINE_RADIX_TREE_CONTEXT(ctx, &mapping->page_tree); + +- radix_tree_delete(&mapping->page_tree, page->index); ++ radix_tree_lock(&ctx); ++ radix_tree_delete(ctx.tree, page->index); ++ radix_tree_unlock(&ctx); + page->mapping = NULL; + mapping_nrpages_dec(mapping); + __dec_zone_page_state(page, NR_FILE_PAGES); +@@ -140,14 +143,10 @@ void __remove_from_page_cache(struct pag + + void remove_from_page_cache(struct page *page) + { +- struct address_space *mapping = page->mapping; +- + BUG_ON(!PageLocked(page)); + + lock_page_ref_irq(page); +- spin_lock(&mapping->tree_lock); + __remove_from_page_cache(page); +- spin_unlock(&mapping->tree_lock); + unlock_page_ref_irq(page); + } + +@@ -458,9 +457,12 @@ int add_to_page_cache(struct page *page, + int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); + + if (error == 0) { ++ DEFINE_RADIX_TREE_CONTEXT(ctx, &mapping->page_tree); ++ + lock_page_ref_irq(page); +- spin_lock(&mapping->tree_lock); +- error = radix_tree_insert(&mapping->page_tree, offset, page); ++ radix_tree_lock(&ctx); ++ error = radix_tree_insert(ctx.tree, offset, page); ++ radix_tree_unlock(&ctx); + if (!error) { + page_cache_get(page); + SetPageLocked(page); +@@ -469,7 +471,6 @@ int add_to_page_cache(struct page *page, + mapping_nrpages_inc(mapping); + __inc_zone_page_state(page, NR_FILE_PAGES); + } +- spin_unlock(&mapping->tree_lock); + unlock_page_ref_irq(page); + radix_tree_preload_end(); + } +Index: linux-2.6.24.7-rt27/mm/migrate.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/migrate.c 2009-02-08 00:03:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/migrate.c 2009-02-08 00:03:09.000000000 -0500 +@@ -295,6 +295,7 @@ static int migrate_page_move_mapping(str + struct page *newpage, struct page *page) + { + void **pslot; ++ struct radix_tree_context ctx; + + if (!mapping) { + /* Anonymous page without mapping */ +@@ -303,15 +304,14 @@ static int migrate_page_move_mapping(str + return 0; + } + ++ init_radix_tree_context(&ctx, &mapping->page_tree); + lock_page_ref_irq(page); +- spin_lock(&mapping->tree_lock); +- +- pslot = radix_tree_lookup_slot(&mapping->page_tree, +- page_index(page)); ++ radix_tree_lock(&ctx); ++ pslot = radix_tree_lookup_slot(ctx.tree, page_index(page)); + + if (page_count(page) != 2 + !!PagePrivate(page) || + (struct page *)radix_tree_deref_slot(pslot) != page) { +- spin_unlock(&mapping->tree_lock); ++ radix_tree_unlock(&ctx); + unlock_page_ref_irq(page); + return -EAGAIN; + } +@@ -329,7 +329,7 @@ static int migrate_page_move_mapping(str + + radix_tree_replace_slot(pslot, newpage); + page->mapping = NULL; +- spin_unlock(&mapping->tree_lock); ++ radix_tree_unlock(&ctx); + + /* + * If moved to a different zone then also account +Index: linux-2.6.24.7-rt27/mm/page-writeback.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/page-writeback.c 2009-02-08 00:03:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/page-writeback.c 2009-02-08 00:03:09.000000000 -0500 +@@ -1009,9 +1009,10 @@ int __set_page_dirty_nobuffers(struct pa + return 1; + + lock_page_ref_irq(page); +- spin_lock(&mapping->tree_lock); + mapping2 = page_mapping(page); + if (mapping2) { /* Race with truncate? */ ++ DEFINE_RADIX_TREE_CONTEXT(ctx, &mapping->page_tree); ++ + BUG_ON(mapping2 != mapping); + WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page)); + if (mapping_cap_account_dirty(mapping)) { +@@ -1020,10 +1021,11 @@ int __set_page_dirty_nobuffers(struct pa + BDI_RECLAIMABLE); + task_io_account_write(PAGE_CACHE_SIZE); + } +- radix_tree_tag_set(&mapping->page_tree, ++ radix_tree_lock(&ctx); ++ radix_tree_tag_set(ctx.tree, + page_index(page), PAGECACHE_TAG_DIRTY); ++ radix_tree_unlock(&ctx); + } +- spin_unlock(&mapping->tree_lock); + unlock_page_ref_irq(page); + if (mapping->host) { + /* !PageAnon && !swapper_space */ +@@ -1181,18 +1183,19 @@ int test_clear_page_writeback(struct pag + unsigned long flags; + + lock_page_ref_irqsave(page, flags); +- spin_lock(&mapping->tree_lock); + ret = TestClearPageWriteback(page); + if (ret) { +- radix_tree_tag_clear(&mapping->page_tree, +- page_index(page), ++ DEFINE_RADIX_TREE_CONTEXT(ctx, &mapping->page_tree); ++ ++ radix_tree_lock(&ctx); ++ radix_tree_tag_clear(ctx.tree, page_index(page), + PAGECACHE_TAG_WRITEBACK); ++ radix_tree_unlock(&ctx); + if (bdi_cap_writeback_dirty(bdi)) { + __dec_bdi_stat(bdi, BDI_WRITEBACK); + __bdi_writeout_inc(bdi); + } + } +- spin_unlock(&mapping->tree_lock); + unlock_page_ref_irqrestore(page, flags); + } else { + ret = TestClearPageWriteback(page); +@@ -1210,22 +1213,24 @@ int test_set_page_writeback(struct page + if (mapping) { + struct backing_dev_info *bdi = mapping->backing_dev_info; + unsigned long flags; ++ DEFINE_RADIX_TREE_CONTEXT(ctx, &mapping->page_tree); + + lock_page_ref_irqsave(page, flags); +- spin_lock(&mapping->tree_lock); + ret = TestSetPageWriteback(page); + if (!ret) { +- radix_tree_tag_set(&mapping->page_tree, +- page_index(page), ++ radix_tree_lock(&ctx); ++ radix_tree_tag_set(ctx.tree, page_index(page), + PAGECACHE_TAG_WRITEBACK); ++ radix_tree_unlock(&ctx); + if (bdi_cap_writeback_dirty(bdi)) + __inc_bdi_stat(bdi, BDI_WRITEBACK); + } +- if (!PageDirty(page)) +- radix_tree_tag_clear(&mapping->page_tree, +- page_index(page), ++ if (!PageDirty(page)) { ++ radix_tree_lock(&ctx); ++ radix_tree_tag_clear(ctx.tree, page_index(page), + PAGECACHE_TAG_DIRTY); +- spin_unlock(&mapping->tree_lock); ++ radix_tree_unlock(&ctx); ++ } + unlock_page_ref_irqrestore(page, flags); + } else { + ret = TestSetPageWriteback(page); +Index: linux-2.6.24.7-rt27/mm/swap_state.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/swap_state.c 2009-02-08 00:03:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/swap_state.c 2009-02-08 00:03:09.000000000 -0500 +@@ -38,7 +38,6 @@ static struct backing_dev_info swap_back + + struct address_space swapper_space = { + .page_tree = RADIX_TREE_INIT(GFP_ATOMIC|__GFP_NOWARN), +- .tree_lock = __SPIN_LOCK_UNLOCKED(swapper_space.tree_lock), + .a_ops = &swap_aops, + .i_mmap_nonlinear = LIST_HEAD_INIT(swapper_space.i_mmap_nonlinear), + .backing_dev_info = &swap_backing_dev_info, +@@ -79,10 +78,12 @@ static int __add_to_swap_cache(struct pa + BUG_ON(PagePrivate(page)); + error = radix_tree_preload(gfp_mask); + if (!error) { ++ DEFINE_RADIX_TREE_CONTEXT(ctx, &swapper_space.page_tree); ++ + lock_page_ref_irq(page); +- spin_lock(&swapper_space.tree_lock); +- error = radix_tree_insert(&swapper_space.page_tree, +- entry.val, page); ++ radix_tree_lock(&ctx); ++ error = radix_tree_insert(ctx.tree, entry.val, page); ++ radix_tree_unlock(&ctx); + if (!error) { + page_cache_get(page); + SetPageSwapCache(page); +@@ -90,7 +91,6 @@ static int __add_to_swap_cache(struct pa + mapping_nrpages_inc(&swapper_space); + __inc_zone_page_state(page, NR_FILE_PAGES); + } +- spin_unlock(&swapper_space.tree_lock); + unlock_page_ref_irq(page); + radix_tree_preload_end(); + } +@@ -128,12 +128,16 @@ static int add_to_swap_cache(struct page + */ + void __delete_from_swap_cache(struct page *page) + { ++ DEFINE_RADIX_TREE_CONTEXT(ctx, &swapper_space.page_tree); ++ + BUG_ON(!PageLocked(page)); + BUG_ON(!PageSwapCache(page)); + BUG_ON(PageWriteback(page)); + BUG_ON(PagePrivate(page)); + +- radix_tree_delete(&swapper_space.page_tree, page_private(page)); ++ radix_tree_lock(&ctx); ++ radix_tree_delete(ctx.tree, page_private(page)); ++ radix_tree_unlock(&ctx); + set_page_private(page, 0); + ClearPageSwapCache(page); + mapping_nrpages_dec(&swapper_space); +@@ -206,9 +210,7 @@ void delete_from_swap_cache(struct page + entry.val = page_private(page); + + lock_page_ref_irq(page); +- spin_lock(&swapper_space.tree_lock); + __delete_from_swap_cache(page); +- spin_unlock(&swapper_space.tree_lock); + unlock_page_ref_irq(page); + + swap_free(entry); +Index: linux-2.6.24.7-rt27/mm/swapfile.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/swapfile.c 2009-02-08 00:03:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/swapfile.c 2009-02-08 00:03:09.000000000 -0500 +@@ -368,13 +368,11 @@ int remove_exclusive_swap_page(struct pa + if (p->swap_map[swp_offset(entry)] == 1) { + /* Recheck the page count with the swapcache lock held.. */ + lock_page_ref_irq(page); +- spin_lock(&swapper_space.tree_lock); + if ((page_count(page) == 2) && !PageWriteback(page)) { + __delete_from_swap_cache(page); + SetPageDirty(page); + retval = 1; + } +- spin_unlock(&swapper_space.tree_lock); + unlock_page_ref_irq(page); + } + spin_unlock(&swap_lock); +Index: linux-2.6.24.7-rt27/mm/truncate.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/truncate.c 2009-02-08 00:03:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/truncate.c 2009-02-08 00:03:09.000000000 -0500 +@@ -351,19 +351,16 @@ invalidate_complete_page2(struct address + return 0; + + lock_page_ref_irq(page); +- spin_lock(&mapping->tree_lock); + if (PageDirty(page)) + goto failed; + + BUG_ON(PagePrivate(page)); + __remove_from_page_cache(page); +- spin_unlock(&mapping->tree_lock); + unlock_page_ref_irq(page); + ClearPageUptodate(page); + page_cache_release(page); /* pagecache ref */ + return 1; + failed: +- spin_unlock(&mapping->tree_lock); + unlock_page_ref_irq(page); + return 0; + } +Index: linux-2.6.24.7-rt27/mm/vmscan.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/vmscan.c 2009-02-08 00:03:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/vmscan.c 2009-02-08 00:03:09.000000000 -0500 +@@ -386,7 +386,6 @@ int remove_mapping(struct address_space + BUG_ON(mapping != page_mapping(page)); + + lock_page_ref_irq(page); +- spin_lock(&mapping->tree_lock); + /* + * The non racy check for a busy page. + * +@@ -421,13 +420,11 @@ int remove_mapping(struct address_space + if (PageSwapCache(page)) { + swp_entry_t swap = { .val = page_private(page) }; + __delete_from_swap_cache(page); +- spin_unlock(&mapping->tree_lock); + swap_free(swap); + goto free_it; + } + + __remove_from_page_cache(page); +- spin_unlock(&mapping->tree_lock); + + free_it: + unlock_page_ref_irq(page); +@@ -435,7 +432,6 @@ free_it: + return 1; + + cannot_free: +- spin_unlock(&mapping->tree_lock); + unlock_page_ref_irq(page); + return 0; + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0419-apic-level-smp-affinity.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0419-apic-level-smp-affinity.patch @@ -0,0 +1,24 @@ +--- + arch/x86/kernel/io_apic_64.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/io_apic_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/io_apic_64.c 2009-02-08 00:02:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/io_apic_64.c 2009-02-08 00:04:11.000000000 -0500 +@@ -1509,6 +1509,15 @@ static void ack_apic_level(unsigned int + move_masked_irq(irq); + unmask_IO_APIC_irq(irq); + } ++#if (defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)) && \ ++ defined(CONFIG_PREEMPT_HARDIRQS) ++ /* ++ * With threaded interrupts, we always have IRQ_INPROGRESS ++ * when acking. ++ */ ++ else if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) ++ move_masked_irq(irq); ++#endif + } + + static struct irq_chip ioapic_chip __read_mostly = { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0489-trace_hist-latediv.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0489-trace_hist-latediv.patch @@ -0,0 +1,74 @@ +--- + kernel/trace/trace_hist.c | 22 +++++++++++++--------- + 1 file changed, 13 insertions(+), 9 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/trace/trace_hist.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace_hist.c 2009-02-08 00:02:36.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace_hist.c 2009-02-08 00:04:44.000000000 -0500 +@@ -37,7 +37,6 @@ enum { + struct hist_data { + atomic_t hist_mode; /* 0 log, 1 don't log */ + unsigned long min_lat; +- unsigned long avg_lat; + unsigned long max_lat; + unsigned long long beyond_hist_bound_samples; + unsigned long long accumulate_lat; +@@ -70,7 +69,6 @@ static char *wakeup_latency_hist_dir = " + void notrace latency_hist(int latency_type, int cpu, unsigned long latency) + { + struct hist_data *my_hist; +- unsigned long long total_samples; + + if ((cpu < 0) || (cpu >= NR_CPUS) || (latency_type < INTERRUPT_LATENCY) + || (latency_type > WAKEUP_LATENCY) || (latency < 0)) +@@ -117,11 +115,8 @@ void notrace latency_hist(int latency_ty + else if (latency > my_hist->max_lat) + my_hist->max_lat = latency; + +- total_samples = my_hist->total_samples++; ++ my_hist->total_samples++; + my_hist->accumulate_lat += latency; +- if (likely(total_samples)) +- my_hist->avg_lat = (unsigned long) +- div64_64(my_hist->accumulate_lat, total_samples); + return; + } + +@@ -135,16 +130,26 @@ static void *l_start(struct seq_file *m, + return NULL; + + if (index == 0) { ++ char avgstr[32]; ++ + atomic_dec(&my_hist->hist_mode); ++ if (likely(my_hist->total_samples)) { ++ unsigned long avg = (unsigned long) ++ div64_64(my_hist->accumulate_lat, ++ my_hist->total_samples); ++ sprintf(avgstr, "%lu", avg); ++ } else ++ strcpy(avgstr, ""); ++ + seq_printf(m, "#Minimum latency: %lu microseconds.\n" +- "#Average latency: %lu microseconds.\n" ++ "#Average latency: %s microseconds.\n" + "#Maximum latency: %lu microseconds.\n" + "#Total samples: %llu\n" + "#There are %llu samples greater or equal" + " than %d microseconds\n" + "#usecs\t%16s\n" + , my_hist->min_lat +- , my_hist->avg_lat ++ , avgstr + , my_hist->max_lat + , my_hist->total_samples + , my_hist->beyond_hist_bound_samples +@@ -220,7 +225,6 @@ static void hist_reset(struct hist_data + hist->max_lat = 0UL; + hist->total_samples = 0ULL; + hist->accumulate_lat = 0ULL; +- hist->avg_lat = 0UL; + + atomic_inc(&hist->hist_mode); + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0038-0025-sched-remove-rt_overload.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0038-0025-sched-remove-rt_overload.patch @@ -0,0 +1,48 @@ +From 03c269c753ca432cc33c3039c743bfceba10a3e9 Mon Sep 17 00:00:00 2001 +From: Ingo Molnar +Date: Tue, 11 Dec 2007 10:02:39 +0100 +Subject: [PATCH] sched: remove rt_overload() + +remove rt_overload() - it's an unnecessary indirection. + +Signed-off-by: Ingo Molnar + +--- + kernel/sched_rt.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:01:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:01:02.000000000 -0500 +@@ -17,11 +17,6 @@ static inline int rt_overloaded(void) + return atomic_read(&rto_count); + } + +-static inline cpumask_t *rt_overload(void) +-{ +- return &rt_overload_mask; +-} +- + static inline void rt_set_overload(struct rq *rq) + { + rq->rt.overloaded = 1; +@@ -586,7 +581,6 @@ static int pull_rt_task(struct rq *this_ + struct task_struct *next; + struct task_struct *p; + struct rq *src_rq; +- cpumask_t *rto_cpumask; + int this_cpu = this_rq->cpu; + int cpu; + int ret = 0; +@@ -604,9 +598,7 @@ static int pull_rt_task(struct rq *this_ + + next = pick_next_task_rt(this_rq); + +- rto_cpumask = rt_overload(); +- +- for_each_cpu_mask(cpu, *rto_cpumask) { ++ for_each_cpu_mask(cpu, rt_overload_mask) { + if (this_cpu == cpu) + continue; + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0258-preempt-realtime-rcu.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0258-preempt-realtime-rcu.patch @@ -0,0 +1,62 @@ +--- + kernel/rcuclassic.c | 6 +++--- + kernel/rcupreempt.c | 6 +++--- + 2 files changed, 6 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rcuclassic.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcuclassic.c 2009-02-08 00:01:43.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcuclassic.c 2009-02-08 00:02:48.000000000 -0500 +@@ -57,7 +57,7 @@ struct rcu_ctrlblk { + + int signaled; + +- spinlock_t lock ____cacheline_internodealigned_in_smp; ++ raw_spinlock_t lock ____cacheline_internodealigned_in_smp; + cpumask_t cpumask; /* CPUs that need to switch in order */ + /* for current batch to proceed. */ + } ____cacheline_internodealigned_in_smp; +@@ -96,13 +96,13 @@ struct rcu_data { + static struct rcu_ctrlblk rcu_ctrlblk = { + .cur = -300, + .completed = -300, +- .lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock), ++ .lock = RAW_SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock), + .cpumask = CPU_MASK_NONE, + }; + static struct rcu_ctrlblk rcu_bh_ctrlblk = { + .cur = -300, + .completed = -300, +- .lock = __SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock), ++ .lock = RAW_SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock), + .cpumask = CPU_MASK_NONE, + }; + +Index: linux-2.6.24.7-rt27/kernel/rcupreempt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt.c 2009-02-08 00:01:43.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt.c 2009-02-08 00:02:48.000000000 -0500 +@@ -62,7 +62,7 @@ + + #define GP_STAGES 2 + struct rcu_data { +- spinlock_t lock; /* Protect rcu_data fields. */ ++ raw_spinlock_t lock; /* Protect rcu_data fields. */ + long completed; /* Number of last completed batch. */ + int waitlistcount; + struct rcu_head *nextlist; +@@ -76,12 +76,12 @@ struct rcu_data { + #endif /* #ifdef CONFIG_RCU_TRACE */ + }; + struct rcu_ctrlblk { +- spinlock_t fliplock; /* Protect state-machine transitions. */ ++ raw_spinlock_t fliplock; /* Protect state-machine transitions. */ + long completed; /* Number of last completed batch. */ + }; + static DEFINE_PER_CPU(struct rcu_data, rcu_data); + static struct rcu_ctrlblk rcu_ctrlblk = { +- .fliplock = SPIN_LOCK_UNLOCKED, ++ .fliplock = RAW_SPIN_LOCK_UNLOCKED(rcu_ctrlblk.fliplock), + .completed = 0, + }; + static DEFINE_PER_CPU(int [2], rcu_flipctr) = { 0, 0 }; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0215-preempt-realtime-x86_64.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0215-preempt-realtime-x86_64.patch @@ -0,0 +1,403 @@ + arch/x86/kernel/early_printk.c | 2 +- + arch/x86/kernel/head64.c | 6 +++++- + arch/x86/kernel/i8259_64.c | 2 +- + arch/x86/kernel/io_apic_64.c | 13 +++++++------ + arch/x86/kernel/nmi_64.c | 2 ++ + arch/x86/kernel/process_64.c | 21 ++++++++++++--------- + arch/x86/kernel/signal_64.c | 7 +++++++ + arch/x86/kernel/smp_64.c | 14 ++++++++++++-- + arch/x86/kernel/traps_64.c | 13 ++++++------- + include/asm-x86/acpi_64.h | 4 ++-- + include/asm-x86/hw_irq_64.h | 2 +- + include/asm-x86/io_apic_64.h | 2 +- + include/asm-x86/spinlock_64.h | 6 +++--- + include/asm-x86/tlbflush_64.h | 8 +++++++- + include/asm-x86/vgtod.h | 2 +- + 15 files changed, 68 insertions(+), 36 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/early_printk.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/early_printk.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/early_printk.c 2009-02-08 00:02:25.000000000 -0500 +@@ -198,7 +198,7 @@ static int early_console_initialized = 0 + + void early_printk(const char *fmt, ...) + { +- char buf[512]; ++ static char buf[512]; + int n; + va_list ap; + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/head64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/head64.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/head64.c 2009-02-08 00:02:25.000000000 -0500 +@@ -24,7 +24,11 @@ static void __init zap_identity_mappings + { + pgd_t *pgd = pgd_offset_k(0UL); + pgd_clear(pgd); +- __flush_tlb(); ++ /* ++ * preempt_disable/enable does not work this early in the ++ * bootup yet: ++ */ ++ write_cr3(read_cr3()); + } + + /* Don't add a printk in there. printk relies on the PDA which is not initialized +Index: linux-2.6.24.7-rt27/arch/x86/kernel/i8259_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/i8259_64.c 2009-02-08 00:01:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/i8259_64.c 2009-02-08 00:02:25.000000000 -0500 +@@ -96,8 +96,8 @@ static void (*interrupt[NR_VECTORS - FIR + */ + + static int i8259A_auto_eoi; +-DEFINE_SPINLOCK(i8259A_lock); + static void mask_and_ack_8259A(unsigned int); ++DEFINE_RAW_SPINLOCK(i8259A_lock); + + static struct irq_chip i8259A_chip = { + .name = "XT-PIC", +Index: linux-2.6.24.7-rt27/arch/x86/kernel/io_apic_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/io_apic_64.c 2009-02-08 00:01:53.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/io_apic_64.c 2009-02-08 00:02:25.000000000 -0500 +@@ -91,8 +91,8 @@ int timer_over_8254 __initdata = 1; + /* Where if anywhere is the i8259 connect in external int mode */ + static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; + +-static DEFINE_SPINLOCK(ioapic_lock); +-DEFINE_SPINLOCK(vector_lock); ++static DEFINE_RAW_SPINLOCK(ioapic_lock); ++DEFINE_RAW_SPINLOCK(vector_lock); + + /* + * # of IRQ routing registers +@@ -205,6 +205,9 @@ static inline void io_apic_sync(unsigned + reg ACTION; \ + io_apic_modify(entry->apic, reg); \ + FINAL; \ ++ /* Force POST flush by reading: */ \ ++ reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ ++ \ + if (!entry->next) \ + break; \ + entry = irq_2_pin + entry->next; \ +@@ -349,10 +352,8 @@ static void add_pin_to_irq(unsigned int + static void name##_IO_APIC_irq (unsigned int irq) \ + __DO_ACTION(R, ACTION, FINAL) + +-DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic) ) +- /* mask = 1 */ +-DO_ACTION( __unmask, 0, &= 0xfffeffff, ) +- /* mask = 0 */ ++DO_ACTION( __mask, 0, |= 0x00010000, ) /* mask = 1 */ ++DO_ACTION( __unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ + + DO_ACTION( __pcix_mask, 0, &= 0xffff7fff, ) /* edge */ + DO_ACTION( __pcix_unmask, 0, = (reg & 0xfffeffff) | 0x00008000, ) /* level */ +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_64.c 2009-02-08 00:01:32.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c 2009-02-08 00:02:25.000000000 -0500 +@@ -68,7 +68,9 @@ static int endflag __initdata = 0; + */ + static __init void nmi_cpu_busy(void *data) + { ++#ifndef CONFIG_PREEMPT_RT + local_irq_enable_in_hardirq(); ++#endif + /* Intentionally don't use cpu_relax here. This is + to make sure that the performance counter really ticks, + even if there is a simulator or similar that catches the +Index: linux-2.6.24.7-rt27/arch/x86/kernel/process_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/process_64.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/process_64.c 2009-02-08 00:02:25.000000000 -0500 +@@ -115,7 +115,7 @@ static void default_idle(void) + */ + smp_mb(); + local_irq_disable(); +- if (!need_resched()) { ++ if (!need_resched() && !need_resched_delayed()) { + /* Enables interrupts one instruction before HLT. + x86 special cases this so there is no race. */ + safe_halt(); +@@ -213,7 +213,7 @@ void cpu_idle (void) + /* endless idle loop with no priority at all */ + while (1) { + tick_nohz_stop_sched_tick(); +- while (!need_resched()) { ++ while (!need_resched() && !need_resched_delayed()) { + void (*idle)(void); + + if (__get_cpu_var(cpu_idle_state)) +@@ -243,9 +243,11 @@ void cpu_idle (void) + } + + tick_nohz_restart_sched_tick(); +- preempt_enable_no_resched(); +- schedule(); ++ local_irq_disable(); ++ __preempt_enable_no_resched(); ++ __schedule(); + preempt_disable(); ++ local_irq_enable(); + } + } + +@@ -261,10 +263,10 @@ void cpu_idle (void) + */ + void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) + { +- if (!need_resched()) { ++ if (!need_resched() && !need_resched_delayed()) { + __monitor((void *)¤t_thread_info()->flags, 0, 0); + smp_mb(); +- if (!need_resched()) ++ if (!need_resched() && !need_resched_delayed()) + __mwait(eax, ecx); + } + } +@@ -272,10 +274,10 @@ void mwait_idle_with_hints(unsigned long + /* Default MONITOR/MWAIT with no hints, used for default C1 state */ + static void mwait_idle(void) + { +- if (!need_resched()) { ++ if (!need_resched() && !need_resched_delayed()) { + __monitor((void *)¤t_thread_info()->flags, 0, 0); + smp_mb(); +- if (!need_resched()) ++ if (!need_resched() && !need_resched_delayed()) + __sti_mwait(0, 0); + else + local_irq_enable(); +@@ -393,7 +395,7 @@ void exit_thread(void) + struct thread_struct *t = &me->thread; + + if (me->thread.io_bitmap_ptr) { +- struct tss_struct *tss = &per_cpu(init_tss, get_cpu()); ++ struct tss_struct *tss; + + kfree(t->io_bitmap_ptr); + t->io_bitmap_ptr = NULL; +@@ -401,6 +403,7 @@ void exit_thread(void) + /* + * Careful, clear this in the TSS too: + */ ++ tss = &per_cpu(init_tss, get_cpu()); + memset(tss->io_bitmap, 0xff, t->io_bitmap_max); + t->io_bitmap_max = 0; + put_cpu(); +Index: linux-2.6.24.7-rt27/arch/x86/kernel/signal_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/signal_64.c 2009-02-08 00:00:47.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/signal_64.c 2009-02-08 00:02:25.000000000 -0500 +@@ -423,6 +423,13 @@ static void do_signal(struct pt_regs *re + int signr; + sigset_t *oldset; + ++#ifdef CONFIG_PREEMPT_RT ++ /* ++ * Fully-preemptible kernel does not need interrupts disabled: ++ */ ++ local_irq_enable(); ++ preempt_check_resched(); ++#endif + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from +Index: linux-2.6.24.7-rt27/arch/x86/kernel/smp_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/smp_64.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/smp_64.c 2009-02-08 00:02:25.000000000 -0500 +@@ -56,7 +56,7 @@ union smp_flush_state { + struct mm_struct *flush_mm; + unsigned long flush_va; + #define FLUSH_ALL -1ULL +- spinlock_t tlbstate_lock; ++ raw_spinlock_t tlbstate_lock; + }; + char pad[SMP_CACHE_BYTES]; + } ____cacheline_aligned; +@@ -296,10 +296,20 @@ void smp_send_reschedule(int cpu) + } + + /* ++ * this function sends a 'reschedule' IPI to all other CPUs. ++ * This is used when RT tasks are starving and other CPUs ++ * might be able to run them: ++ */ ++void smp_send_reschedule_allbutself(void) ++{ ++ send_IPI_allbutself(RESCHEDULE_VECTOR); ++} ++ ++/* + * Structure and data for smp_call_function(). This is designed to minimise + * static memory requirements. It also looks cleaner. + */ +-static DEFINE_SPINLOCK(call_lock); ++static DEFINE_RAW_SPINLOCK(call_lock); + + struct call_data_struct { + void (*func) (void *info); +Index: linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/traps_64.c 2009-02-08 00:01:36.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c 2009-02-08 00:02:25.000000000 -0500 +@@ -220,7 +220,7 @@ void dump_trace(struct task_struct *tsk, + unsigned long *stack, + const struct stacktrace_ops *ops, void *data) + { +- const unsigned cpu = get_cpu(); ++ const unsigned cpu = raw_smp_processor_id(); + unsigned long *irqstack_end = (unsigned long*)cpu_pda(cpu)->irqstackptr; + unsigned used = 0; + struct thread_info *tinfo; +@@ -311,7 +311,6 @@ void dump_trace(struct task_struct *tsk, + tinfo = task_thread_info(tsk); + HANDLE_STACK (valid_stack_ptr(tinfo, stack)); + #undef HANDLE_STACK +- put_cpu(); + } + EXPORT_SYMBOL(dump_trace); + +@@ -361,7 +360,7 @@ _show_stack(struct task_struct *tsk, str + { + unsigned long *stack; + int i; +- const int cpu = smp_processor_id(); ++ const int cpu = raw_smp_processor_id(); + unsigned long *irqstack_end = (unsigned long *) (cpu_pda(cpu)->irqstackptr); + unsigned long *irqstack = (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE); + +@@ -473,7 +472,7 @@ void out_of_line_bug(void) + EXPORT_SYMBOL(out_of_line_bug); + #endif + +-static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; ++static raw_spinlock_t die_lock = RAW_SPIN_LOCK_UNLOCKED(die_lock); + static int die_owner = -1; + static unsigned int die_nest_count; + +@@ -487,11 +486,11 @@ unsigned __kprobes long oops_begin(void) + /* racy, but better than risking deadlock. */ + raw_local_irq_save(flags); + cpu = smp_processor_id(); +- if (!__raw_spin_trylock(&die_lock)) { ++ if (!spin_trylock(&die_lock)) { + if (cpu == die_owner) + /* nested oops. should stop eventually */; + else +- __raw_spin_lock(&die_lock); ++ spin_lock(&die_lock); + } + die_nest_count++; + die_owner = cpu; +@@ -507,7 +506,7 @@ void __kprobes oops_end(unsigned long fl + die_nest_count--; + if (!die_nest_count) + /* Nest count reaches zero, release the lock. */ +- __raw_spin_unlock(&die_lock); ++ spin_unlock(&die_lock); + raw_local_irq_restore(flags); + if (panic_on_oops) + panic("Fatal exception"); +Index: linux-2.6.24.7-rt27/include/asm-x86/acpi_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/acpi_64.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/acpi_64.h 2009-02-08 00:02:25.000000000 -0500 +@@ -51,8 +51,8 @@ + + #define ACPI_ASM_MACROS + #define BREAKPOINT3 +-#define ACPI_DISABLE_IRQS() local_irq_disable() +-#define ACPI_ENABLE_IRQS() local_irq_enable() ++#define ACPI_DISABLE_IRQS() local_irq_disable_nort() ++#define ACPI_ENABLE_IRQS() local_irq_enable_nort() + #define ACPI_FLUSH_CPU_CACHE() wbinvd() + + int __acpi_acquire_global_lock(unsigned int *lock); +Index: linux-2.6.24.7-rt27/include/asm-x86/hw_irq_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/hw_irq_64.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/hw_irq_64.h 2009-02-08 00:02:25.000000000 -0500 +@@ -118,7 +118,7 @@ void i8254_timer_resume(void); + typedef int vector_irq_t[NR_VECTORS]; + DECLARE_PER_CPU(vector_irq_t, vector_irq); + extern void __setup_vector_irq(int cpu); +-extern spinlock_t vector_lock; ++extern raw_spinlock_t vector_lock; + + /* + * Various low-level irq details needed by irq.c, process.c, +Index: linux-2.6.24.7-rt27/include/asm-x86/io_apic_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/io_apic_64.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/io_apic_64.h 2009-02-08 00:02:25.000000000 -0500 +@@ -131,7 +131,7 @@ extern int sis_apic_bug; /* dummy */ + + void enable_NMI_through_LVT0(void); + +-extern spinlock_t i8259A_lock; ++extern raw_spinlock_t i8259A_lock; + + extern int timer_over_8254; + +Index: linux-2.6.24.7-rt27/include/asm-x86/spinlock_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/spinlock_64.h 2009-02-08 00:02:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/spinlock_64.h 2009-02-08 00:02:25.000000000 -0500 +@@ -160,8 +160,8 @@ static inline void __raw_write_unlock(__ + : "=m" (rw->lock) : : "memory"); + } + +-#define _raw_spin_relax(lock) cpu_relax() +-#define _raw_read_relax(lock) cpu_relax() +-#define _raw_write_relax(lock) cpu_relax() ++#define __raw_spin_relax(lock) cpu_relax() ++#define __raw_read_relax(lock) cpu_relax() ++#define __raw_write_relax(lock) cpu_relax() + + #endif /* __ASM_SPINLOCK_H */ +Index: linux-2.6.24.7-rt27/include/asm-x86/tlbflush_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/tlbflush_64.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/tlbflush_64.h 2009-02-08 00:02:25.000000000 -0500 +@@ -8,14 +8,20 @@ + + static inline void __flush_tlb(void) + { ++ preempt_disable(); + write_cr3(read_cr3()); ++ preempt_enable(); + } + + static inline void __flush_tlb_all(void) + { +- unsigned long cr4 = read_cr4(); ++ unsigned long cr4; ++ ++ preempt_disable(); ++ cr4 = read_cr4(); + write_cr4(cr4 & ~X86_CR4_PGE); /* clear PGE */ + write_cr4(cr4); /* write old PGE again and flush TLBs */ ++ preempt_enable(); + } + + #define __flush_tlb_one(addr) \ +Index: linux-2.6.24.7-rt27/include/asm-x86/vgtod.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/vgtod.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/vgtod.h 2009-02-08 00:02:25.000000000 -0500 +@@ -5,7 +5,7 @@ + #include + + struct vsyscall_gtod_data { +- seqlock_t lock; ++ raw_seqlock_t lock; + + /* open coded 'struct timespec' */ + time_t wall_time_sec; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0194-tasklet-more-fixes.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0194-tasklet-more-fixes.patch @@ -0,0 +1,176 @@ +From linux-kernel-owner@vger.kernel.org Thu Jun 14 23:21:31 2007 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.1.7-deb (2006-10-05) on debian +X-Spam-Level: +X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable + version=3.1.7-deb +Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by + mail.tglx.de (Postfix) with ESMTP id F2D8065C3D9 for ; + Thu, 14 Jun 2007 23:21:31 +0200 (CEST) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id + S1756447AbXFNVVF (ORCPT ); Thu, 14 Jun 2007 + 17:21:05 -0400 +Received: (majordomo@vger.kernel.org) by vger.kernel.org id + S1753441AbXFNVUw (ORCPT ); Thu, 14 Jun 2007 + 17:20:52 -0400 +Received: from e33.co.us.ibm.com ([32.97.110.151]:53331 "EHLO + e33.co.us.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP + id S1752693AbXFNVUv (ORCPT ); Thu, 14 + Jun 2007 17:20:51 -0400 +Received: from d03relay02.boulder.ibm.com (d03relay02.boulder.ibm.com + [9.17.195.227]) by e33.co.us.ibm.com (8.13.8/8.13.8) with ESMTP id + l5ELKnM3030113 for ; Thu, 14 Jun 2007 + 17:20:49 -0400 +Received: from d03av01.boulder.ibm.com (d03av01.boulder.ibm.com + [9.17.195.167]) by d03relay02.boulder.ibm.com (8.13.8/8.13.8/NCO v8.3) with + ESMTP id l5ELKniv268710 for ; Thu, 14 Jun + 2007 15:20:49 -0600 +Received: from d03av01.boulder.ibm.com (loopback [127.0.0.1]) by + d03av01.boulder.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id + l5ELKm9A010919 for ; Thu, 14 Jun 2007 + 15:20:49 -0600 +Received: from [9.67.41.186] (wecm-9-67-41-186.wecm.ibm.com [9.67.41.186]) + by d03av01.boulder.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id + l5ELKl3X010835; Thu, 14 Jun 2007 15:20:47 -0600 +Subject: Re: [PATCH -rt] Fix TASKLET_STATE_SCHED WARN_ON() +From: john stultz +To: Ingo Molnar +Cc: Thomas Gleixner , Steven Rostedt , "Paul E. McKenney" , lkml +In-Reply-To: <1181096244.6018.20.camel@localhost> +References: <1181096244.6018.20.camel@localhost> +Content-Type: text/plain +Date: Thu, 14 Jun 2007 14:20:20 -0700 +Message-Id: <1181856020.6276.14.camel@localhost.localdomain> +Mime-Version: 1.0 +X-Mailer: Evolution 2.10.1 +Sender: linux-kernel-owner@vger.kernel.org +Precedence: bulk +X-Mailing-List: linux-kernel@vger.kernel.org +X-Filter-To: .Kernel.LKML +X-Evolution-Source: imap://tglx%40linutronix.de@localhost:8993/ +Content-Transfer-Encoding: 8bit + +On Tue, 2007-06-05 at 19:17 -0700, john stultz wrote: +> Hey Ingo, +> So we've been seeing the following trace fairly frequently on our SMP +> boxes when running kernbench: +> +> BUG: at kernel/softirq.c:639 __tasklet_action() +> +> Call Trace: +> [] dump_trace+0xaa/0x32a +> [] show_trace+0x41/0x5c +> [] dump_stack+0x15/0x17 +> [] __tasklet_action+0xdf/0x12e +> [] tasklet_action+0x27/0x29 +> [] ksoftirqd+0x16c/0x271 +> [] kthread+0xf5/0x128 +> [] child_rip+0xa/0x12 +> +> +> Paul also pointed this out awhile back: http://lkml.org/lkml/2007/2/25/1 +> +> +> Anyway, I think I finally found the issue. Its a bit hard to explain, +> but the idea is while __tasklet_action is running the tasklet function +> on CPU1, if a call to tasklet_schedule() on CPU2 is made, and if right +> after we mark the TASKLET_STATE_SCHED bit we are preempted, +> __tasklet_action on CPU1 might be able to re-run the function, clear the +> bit and unlock the tasklet before CPU2 enters __tasklet_common_schedule. +> Once __tasklet_common_schedule locks the tasklet, we will add the +> tasklet to the list with the TASKLET_STATE_SCHED *unset*. +> +> I've verified this race occurs w/ a WARN_ON in +> __tasklet_common_schedule(). +> +> +> This fix avoids this race by making sure *after* we've locked the +> tasklet that the STATE_SCHED bit is set before adding it to the list. +> +> Does it look ok to you? +> +> thanks +> -john +> +> Signed-off-by: John Stultz +> +> Index: 2.6-rt/kernel/softirq.c +> =================================================================== +> --- 2.6-rt.orig/kernel/softirq.c 2007-06-05 18:30:54.000000000 -0700 +> +++ 2.6-rt/kernel/softirq.c 2007-06-05 18:36:44.000000000 -0700 +> @@ -544,10 +544,17 @@ static void inline +> __tasklet_common_schedule(struct tasklet_struct *t, struct tasklet_head *head, unsigned int nr) +> { +> if (tasklet_trylock(t)) { +> - WARN_ON(t->next != NULL); +> - t->next = head->list; +> - head->list = t; +> - raise_softirq_irqoff(nr); +> + /* We may have been preempted before tasklet_trylock +> + * and __tasklet_action may have already run. +> + * So double check the sched bit while the takslet +> + * is locked before adding it to the list. +> + */ +> + if (test_bit(TASKLET_STATE_SCHED, &t->state)) { +> + WARN_ON(t->next != NULL); +> + t->next = head->list; +> + head->list = t; +> + raise_softirq_irqoff(nr); +> + } +> tasklet_unlock(t); +> } +> } + +So while digging on a strange OOM issue we were seeing (which actually +ended up being fixed by Steven's softirq patch), I noticed that the fix +above is incomplete. With only the patch above, we may no longer have +unscheduled tasklets added to the list, but we may end up with scheduled +tasklets that are not on the list (and will stay that way!). + +The following additional patch should correct this issue. Although since +we weren't actually hitting it, the issue is a bit theoretical, so I've +not been able to prove it really fixes anything. + +thanks +-john + +--- + kernel/softirq.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/softirq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/softirq.c 2009-02-08 00:02:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/softirq.c 2009-02-08 00:02:14.000000000 -0500 +@@ -459,6 +459,7 @@ static void inline + __tasklet_common_schedule(struct tasklet_struct *t, struct tasklet_head *head, unsigned int nr) + { + if (tasklet_trylock(t)) { ++again: + /* We may have been preempted before tasklet_trylock + * and __tasklet_action may have already run. + * So double check the sched bit while the takslet +@@ -469,8 +470,21 @@ __tasklet_common_schedule(struct tasklet + t->next = head->list; + head->list = t; + raise_softirq_irqoff(nr); ++ tasklet_unlock(t); ++ } else { ++ /* This is subtle. If we hit the corner case above ++ * It is possible that we get preempted right here, ++ * and another task has successfully called ++ * tasklet_schedule(), then this function, and ++ * failed on the trylock. Thus we must be sure ++ * before releasing the tasklet lock, that the ++ * SCHED_BIT is clear. Otherwise the tasklet ++ * may get its SCHED_BIT set, but not added to the ++ * list ++ */ ++ if (!tasklet_tryunlock(t)) ++ goto again; + } +- tasklet_unlock(t); + } + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0475-adaptive-adjust-pi-wakeup.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0475-adaptive-adjust-pi-wakeup.patch @@ -0,0 +1,67 @@ +From ghaskins@novell.com Fri May 23 23:34:24 2008 +Date: Tue, 20 May 2008 10:49:31 -0400 +From: Gregory Haskins +To: mingo@elte.hu, tglx@linutronix.de, rostedt@goodmis.org, + linux-rt-users@vger.kernel.org +Cc: linux-kernel@vger.kernel.org, sdietrich@novell.com, pmorreale@novell.com, + mkohari@novell.com, ghaskins@novell.com +Subject: [PATCH 4/5] adjust pi_lock usage in wakeup + + [ The following text is in the "utf-8" character set. ] + [ Your display is set for the "iso-8859-1" character set. ] + [ Some characters may be displayed incorrectly. ] + +From: Peter W.Morreale + +In wakeup_next_waiter(), we take the pi_lock, and then find out whether +we have another waiter to add to the pending owner. We can reduce +contention on the pi_lock for the pending owner if we first obtain the +pointer to the next waiter outside of the pi_lock. + +Signed-off-by: Peter W. Morreale +Signed-off-by: Gregory Haskins +--- + + kernel/rtmutex.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:36.000000000 -0500 +@@ -562,6 +562,7 @@ static void wakeup_next_waiter(struct rt + { + struct rt_mutex_waiter *waiter; + struct task_struct *pendowner; ++ struct rt_mutex_waiter *next; + + spin_lock(¤t->pi_lock); + +@@ -624,6 +625,12 @@ static void wakeup_next_waiter(struct rt + * waiter with higher priority than pending-owner->normal_prio + * is blocked on the unboosted (pending) owner. + */ ++ ++ if (rt_mutex_has_waiters(lock)) ++ next = rt_mutex_top_waiter(lock); ++ else ++ next = NULL; ++ + spin_lock(&pendowner->pi_lock); + + WARN_ON(!pendowner->pi_blocked_on); +@@ -632,12 +639,9 @@ static void wakeup_next_waiter(struct rt + + pendowner->pi_blocked_on = NULL; + +- if (rt_mutex_has_waiters(lock)) { +- struct rt_mutex_waiter *next; +- +- next = rt_mutex_top_waiter(lock); ++ if (next) + plist_add(&next->pi_list_entry, &pendowner->pi_waiters); +- } ++ + spin_unlock(&pendowner->pi_lock); + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0579-sched-fix-the-cpuprio-count-really.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0579-sched-fix-the-cpuprio-count-really.patch @@ -0,0 +1,31 @@ +commit e539d8fcd11af811db70707d47ea436d5621d0da +Author: Thomas Gleixner +Date: Thu Jun 5 10:28:00 2008 +0200 + + sched: fix the cpuprio count really + + Peter pointed out that the last version of the "fix" was still one off + under certain circumstances. Use BITS_TO_LONG instead to get an + accurate result. + + Signed-off-by: Thomas Gleixner + +--- + kernel/sched_cpupri.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_cpupri.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_cpupri.h 2009-02-08 00:04:47.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_cpupri.h 2009-02-08 00:05:26.000000000 -0500 +@@ -3,8 +3,8 @@ + + #include + +-#define CPUPRI_NR_PRIORITIES 2+MAX_RT_PRIO +-#define CPUPRI_NR_PRI_WORDS (CPUPRI_NR_PRIORITIES + BITS_PER_LONG/2)/BITS_PER_LONG ++#define CPUPRI_NR_PRIORITIES (MAX_RT_PRIO + 2) ++#define CPUPRI_NR_PRI_WORDS BITS_TO_LONGS(CPUPRI_NR_PRIORITIES) + + #define CPUPRI_INVALID -1 + #define CPUPRI_IDLE 0 --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0259-preempt-realtime-timer.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0259-preempt-realtime-timer.patch @@ -0,0 +1,256 @@ +--- + include/linux/hrtimer.h | 2 - + include/linux/time.h | 2 - + kernel/time/clockevents.c | 2 - + kernel/time/clocksource.c | 2 - + kernel/time/tick-broadcast.c | 2 - + kernel/time/tick-common.c | 2 - + kernel/time/tick-internal.h | 2 - + kernel/time/tick-sched.c | 2 - + kernel/time/timekeeping.c | 2 - + kernel/time/timer_stats.c | 6 ++--- + kernel/timer.c | 46 +++++++++++++++++++++++++++++++++++++++++-- + 11 files changed, 56 insertions(+), 14 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/hrtimer.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/hrtimer.h 2009-02-08 00:01:51.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/hrtimer.h 2009-02-08 00:02:49.000000000 -0500 +@@ -191,7 +191,7 @@ struct hrtimer_clock_base { + * @nr_events: Total number of timer interrupt events + */ + struct hrtimer_cpu_base { +- spinlock_t lock; ++ raw_spinlock_t lock; + struct lock_class_key lock_key; + struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; + #ifdef CONFIG_HIGH_RES_TIMERS +Index: linux-2.6.24.7-rt27/include/linux/time.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/time.h 2009-02-07 23:59:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/time.h 2009-02-08 00:02:49.000000000 -0500 +@@ -92,7 +92,7 @@ static inline struct timespec timespec_s + + extern struct timespec xtime; + extern struct timespec wall_to_monotonic; +-extern seqlock_t xtime_lock; ++extern raw_seqlock_t xtime_lock; + + extern unsigned long read_persistent_clock(void); + extern int update_persistent_clock(struct timespec now); +Index: linux-2.6.24.7-rt27/kernel/time/clockevents.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/clockevents.c 2009-02-07 23:59:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/clockevents.c 2009-02-08 00:02:49.000000000 -0500 +@@ -27,7 +27,7 @@ static LIST_HEAD(clockevents_released); + static RAW_NOTIFIER_HEAD(clockevents_chain); + + /* Protection for the above */ +-static DEFINE_SPINLOCK(clockevents_lock); ++static DEFINE_RAW_SPINLOCK(clockevents_lock); + + /** + * clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds +Index: linux-2.6.24.7-rt27/kernel/time/clocksource.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/clocksource.c 2009-02-07 23:59:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/clocksource.c 2009-02-08 00:02:49.000000000 -0500 +@@ -51,7 +51,7 @@ static struct clocksource *curr_clocksou + static struct clocksource *next_clocksource; + static struct clocksource *clocksource_override; + static LIST_HEAD(clocksource_list); +-static DEFINE_SPINLOCK(clocksource_lock); ++static DEFINE_RAW_SPINLOCK(clocksource_lock); + static char override_name[32]; + static int finished_booting; + +Index: linux-2.6.24.7-rt27/kernel/time/tick-broadcast.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-broadcast.c 2009-02-07 23:59:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-broadcast.c 2009-02-08 00:02:49.000000000 -0500 +@@ -29,7 +29,7 @@ + + struct tick_device tick_broadcast_device; + static cpumask_t tick_broadcast_mask; +-static DEFINE_SPINLOCK(tick_broadcast_lock); ++static DEFINE_RAW_SPINLOCK(tick_broadcast_lock); + + #ifdef CONFIG_TICK_ONESHOT + static void tick_broadcast_clear_oneshot(int cpu); +Index: linux-2.6.24.7-rt27/kernel/time/tick-common.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-common.c 2009-02-08 00:01:32.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-common.c 2009-02-08 00:02:49.000000000 -0500 +@@ -32,7 +32,7 @@ DEFINE_PER_CPU(struct tick_device, tick_ + ktime_t tick_next_period; + ktime_t tick_period; + int tick_do_timer_cpu __read_mostly = -1; +-DEFINE_SPINLOCK(tick_device_lock); ++DEFINE_RAW_SPINLOCK(tick_device_lock); + + /* + * Debugging: see timer_list.c +Index: linux-2.6.24.7-rt27/kernel/time/tick-internal.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-internal.h 2009-02-07 23:59:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-internal.h 2009-02-08 00:02:49.000000000 -0500 +@@ -2,7 +2,7 @@ + * tick internal variable and functions used by low/high res code + */ + DECLARE_PER_CPU(struct tick_device, tick_cpu_device); +-extern spinlock_t tick_device_lock; ++extern raw_spinlock_t tick_device_lock; + extern ktime_t tick_next_period; + extern ktime_t tick_period; + extern int tick_do_timer_cpu __read_mostly; +Index: linux-2.6.24.7-rt27/kernel/time/tick-sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-sched.c 2009-02-08 00:01:43.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-sched.c 2009-02-08 00:02:49.000000000 -0500 +@@ -178,7 +178,7 @@ void tick_nohz_stop_sched_tick(void) + if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) + goto end; + +- if (need_resched()) ++ if (need_resched() || need_resched_delayed()) + goto end; + + cpu = smp_processor_id(); +Index: linux-2.6.24.7-rt27/kernel/time/timekeeping.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/timekeeping.c 2009-02-08 00:01:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/timekeeping.c 2009-02-08 00:02:49.000000000 -0500 +@@ -24,7 +24,7 @@ + * This read-write spinlock protects us from races in SMP while + * playing with xtime and avenrun. + */ +-__cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock); ++__cacheline_aligned_in_smp DEFINE_RAW_SEQLOCK(xtime_lock); + + EXPORT_SYMBOL_GPL(xtime_lock); + +Index: linux-2.6.24.7-rt27/kernel/time/timer_stats.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/timer_stats.c 2009-02-07 23:59:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/timer_stats.c 2009-02-08 00:02:49.000000000 -0500 +@@ -81,12 +81,12 @@ struct entry { + /* + * Spinlock protecting the tables - not taken during lookup: + */ +-static DEFINE_SPINLOCK(table_lock); ++static DEFINE_RAW_SPINLOCK(table_lock); + + /* + * Per-CPU lookup locks for fast hash lookup: + */ +-static DEFINE_PER_CPU(spinlock_t, lookup_lock); ++static DEFINE_PER_CPU(raw_spinlock_t, lookup_lock); + + /* + * Mutex to serialize state changes with show-stats activities: +@@ -238,7 +238,7 @@ void timer_stats_update_stats(void *time + /* + * It doesnt matter which lock we take: + */ +- spinlock_t *lock; ++ raw_spinlock_t *lock = &per_cpu(lookup_lock, raw_smp_processor_id()); + struct entry *entry, input; + unsigned long flags; + +Index: linux-2.6.24.7-rt27/kernel/timer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/timer.c 2009-02-08 00:01:50.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/timer.c 2009-02-08 00:02:49.000000000 -0500 +@@ -860,9 +860,22 @@ unsigned long get_next_timer_interrupt(u + tvec_base_t *base = __get_cpu_var(tvec_bases); + unsigned long expires; + ++#ifdef CONFIG_PREEMPT_RT ++ /* ++ * On PREEMPT_RT we cannot sleep here. If the trylock does not ++ * succeed then we return the worst-case 'expires in 1 tick' ++ * value: ++ */ ++ if (spin_trylock(&base->lock)) { ++ expires = __next_timer_interrupt(base); ++ spin_unlock(&base->lock); ++ } else ++ expires = now + 1; ++#else + spin_lock(&base->lock); + expires = __next_timer_interrupt(base); + spin_unlock(&base->lock); ++#endif + + if (time_before_eq(expires, now)) + return now; +@@ -915,8 +928,29 @@ void update_process_times(int user_tick) + */ + static unsigned long count_active_tasks(void) + { ++ /* ++ * On PREEMPT_RT, we are running in the timer softirq thread, ++ * so consider 1 less running tasks: ++ */ ++#ifdef CONFIG_PREEMPT_RT ++ return (nr_active() - 1) * FIXED_1; ++#else + return nr_active() * FIXED_1; ++#endif ++} ++ ++#ifdef CONFIG_PREEMPT_RT ++/* ++ * Nr of active tasks - counted in fixed-point numbers ++ */ ++static unsigned long count_active_rt_tasks(void) ++{ ++ extern unsigned long rt_nr_running(void); ++ extern unsigned long rt_nr_uninterruptible(void); ++ ++ return (rt_nr_running() + rt_nr_uninterruptible()) * FIXED_1; + } ++#endif + + /* + * Hmm.. Changed this, as the GNU make sources (load.c) seems to +@@ -930,6 +964,8 @@ unsigned long avenrun[3]; + + EXPORT_SYMBOL(avenrun); + ++unsigned long avenrun_rt[3]; ++ + /* + * calc_load - given tick count, update the avenrun load estimates. + * This is called while holding a write_lock on xtime_lock. +@@ -948,6 +984,12 @@ static inline void calc_load(unsigned lo + CALC_LOAD(avenrun[2], EXP_15, active_tasks); + count += LOAD_FREQ; + } while (count < 0); ++#ifdef CONFIG_PREEMPT_RT ++ active_tasks = count_active_rt_tasks(); ++ CALC_LOAD(avenrun_rt[0], EXP_1, active_tasks); ++ CALC_LOAD(avenrun_rt[1], EXP_5, active_tasks); ++ CALC_LOAD(avenrun_rt[2], EXP_15, active_tasks); ++#endif + } + } + +@@ -1371,7 +1413,7 @@ static void __cpuinit migrate_timers(int + old_base = per_cpu(tvec_bases, cpu); + new_base = get_cpu_var(tvec_bases); + +- local_irq_disable(); ++ local_irq_disable_nort(); + double_spin_lock(&new_base->lock, &old_base->lock, + smp_processor_id() < cpu); + +@@ -1388,7 +1430,7 @@ static void __cpuinit migrate_timers(int + + double_spin_unlock(&new_base->lock, &old_base->lock, + smp_processor_id() < cpu); +- local_irq_enable(); ++ local_irq_enable_nort(); + put_cpu_var(tvec_bases); + } + #endif /* CONFIG_HOTPLUG_CPU */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0191-tasklet-redesign.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0191-tasklet-redesign.patch @@ -0,0 +1,297 @@ +From: Ingo Molnar + +tasklet redesign: make it saner and make it easier to thread. + +Signed-off-by: Ingo Molnar + +---- + include/linux/interrupt.h | 39 ++++++----- + kernel/softirq.c | 155 +++++++++++++++++++++++++++++++--------------- + 2 files changed, 128 insertions(+), 66 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/interrupt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/interrupt.h 2009-02-08 00:01:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/interrupt.h 2009-02-08 00:02:13.000000000 -0500 +@@ -310,8 +310,9 @@ extern void wait_for_softirq(int softirq + to be executed on some cpu at least once after this. + * If the tasklet is already scheduled, but its excecution is still not + started, it will be executed only once. +- * If this tasklet is already running on another CPU (or schedule is called +- from tasklet itself), it is rescheduled for later. ++ * If this tasklet is already running on another CPU, it is rescheduled ++ for later. ++ * Schedule must not be called from the tasklet itself (a lockup occurs) + * Tasklet is strictly serialized wrt itself, but not + wrt another tasklets. If client needs some intertask synchronization, + he makes it with spinlocks. +@@ -336,15 +337,25 @@ struct tasklet_struct name = { NULL, 0, + enum + { + TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */ +- TASKLET_STATE_RUN /* Tasklet is running (SMP only) */ ++ TASKLET_STATE_RUN, /* Tasklet is running (SMP only) */ ++ TASKLET_STATE_PENDING /* Tasklet is pending */ + }; + +-#ifdef CONFIG_SMP ++#define TASKLET_STATEF_SCHED (1 << TASKLET_STATE_SCHED) ++#define TASKLET_STATEF_RUN (1 << TASKLET_STATE_RUN) ++#define TASKLET_STATEF_PENDING (1 << TASKLET_STATE_PENDING) ++ ++#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT) + static inline int tasklet_trylock(struct tasklet_struct *t) + { + return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state); + } + ++static inline int tasklet_tryunlock(struct tasklet_struct *t) ++{ ++ return cmpxchg(&t->state, TASKLET_STATEF_RUN, 0) == TASKLET_STATEF_RUN; ++} ++ + static inline void tasklet_unlock(struct tasklet_struct *t) + { + smp_mb__before_clear_bit(); +@@ -356,9 +367,10 @@ static inline void tasklet_unlock_wait(s + while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); } + } + #else +-#define tasklet_trylock(t) 1 +-#define tasklet_unlock_wait(t) do { } while (0) +-#define tasklet_unlock(t) do { } while (0) ++# define tasklet_trylock(t) 1 ++# define tasklet_tryunlock(t) 1 ++# define tasklet_unlock_wait(t) do { } while (0) ++# define tasklet_unlock(t) do { } while (0) + #endif + + extern void FASTCALL(__tasklet_schedule(struct tasklet_struct *t)); +@@ -391,17 +403,8 @@ static inline void tasklet_disable(struc + smp_mb(); + } + +-static inline void tasklet_enable(struct tasklet_struct *t) +-{ +- smp_mb__before_atomic_dec(); +- atomic_dec(&t->count); +-} +- +-static inline void tasklet_hi_enable(struct tasklet_struct *t) +-{ +- smp_mb__before_atomic_dec(); +- atomic_dec(&t->count); +-} ++extern fastcall void tasklet_enable(struct tasklet_struct *t); ++extern fastcall void tasklet_hi_enable(struct tasklet_struct *t); + + extern void tasklet_kill(struct tasklet_struct *t); + extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu); +Index: linux-2.6.24.7-rt27/kernel/softirq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/softirq.c 2009-02-08 00:01:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/softirq.c 2009-02-08 00:02:13.000000000 -0500 +@@ -454,14 +454,24 @@ struct tasklet_head + static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec) = { NULL }; + static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec) = { NULL }; + ++static void inline ++__tasklet_common_schedule(struct tasklet_struct *t, struct tasklet_head *head, unsigned int nr) ++{ ++ if (tasklet_trylock(t)) { ++ WARN_ON(t->next != NULL); ++ t->next = head->list; ++ head->list = t; ++ raise_softirq_irqoff(nr); ++ tasklet_unlock(t); ++ } ++} ++ + void fastcall __tasklet_schedule(struct tasklet_struct *t) + { + unsigned long flags; + + local_irq_save(flags); +- t->next = __get_cpu_var(tasklet_vec).list; +- __get_cpu_var(tasklet_vec).list = t; +- raise_softirq_irqoff(TASKLET_SOFTIRQ); ++ __tasklet_common_schedule(t, &__get_cpu_var(tasklet_vec), TASKLET_SOFTIRQ); + local_irq_restore(flags); + } + +@@ -472,81 +482,130 @@ void fastcall __tasklet_hi_schedule(stru + unsigned long flags; + + local_irq_save(flags); +- t->next = __get_cpu_var(tasklet_hi_vec).list; +- __get_cpu_var(tasklet_hi_vec).list = t; +- raise_softirq_irqoff(HI_SOFTIRQ); ++ __tasklet_common_schedule(t, &__get_cpu_var(tasklet_hi_vec), HI_SOFTIRQ); + local_irq_restore(flags); + } + + EXPORT_SYMBOL(__tasklet_hi_schedule); + +-static void tasklet_action(struct softirq_action *a) ++void fastcall tasklet_enable(struct tasklet_struct *t) + { +- struct tasklet_struct *list; ++ if (!atomic_dec_and_test(&t->count)) ++ return; ++ if (test_and_clear_bit(TASKLET_STATE_PENDING, &t->state)) ++ tasklet_schedule(t); ++} + +- local_irq_disable(); +- list = __get_cpu_var(tasklet_vec).list; +- __get_cpu_var(tasklet_vec).list = NULL; +- local_irq_enable(); ++EXPORT_SYMBOL(tasklet_enable); ++ ++void fastcall tasklet_hi_enable(struct tasklet_struct *t) ++{ ++ if (!atomic_dec_and_test(&t->count)) ++ return; ++ if (test_and_clear_bit(TASKLET_STATE_PENDING, &t->state)) ++ tasklet_hi_schedule(t); ++} ++ ++EXPORT_SYMBOL(tasklet_hi_enable); ++ ++static void ++__tasklet_action(struct softirq_action *a, struct tasklet_struct *list) ++{ ++ int loops = 1000000; + + while (list) { + struct tasklet_struct *t = list; + + list = list->next; ++ /* ++ * Should always succeed - after a tasklist got on the ++ * list (after getting the SCHED bit set from 0 to 1), ++ * nothing but the tasklet softirq it got queued to can ++ * lock it: ++ */ ++ if (!tasklet_trylock(t)) { ++ WARN_ON(1); ++ continue; ++ } ++ ++ t->next = NULL; ++ ++ /* ++ * If we cannot handle the tasklet because it's disabled, ++ * mark it as pending. tasklet_enable() will later ++ * re-schedule the tasklet. ++ */ ++ if (unlikely(atomic_read(&t->count))) { ++out_disabled: ++ /* implicit unlock: */ ++ wmb(); ++ t->state = TASKLET_STATEF_PENDING; ++ continue; ++ } + +- if (tasklet_trylock(t)) { +- if (!atomic_read(&t->count)) { +- if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) +- BUG(); +- t->func(t->data); ++ /* ++ * After this point on the tasklet might be rescheduled ++ * on another CPU, but it can only be added to another ++ * CPU's tasklet list if we unlock the tasklet (which we ++ * dont do yet). ++ */ ++ if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) ++ WARN_ON(1); ++ ++again: ++ t->func(t->data); ++ ++ /* ++ * Try to unlock the tasklet. We must use cmpxchg, because ++ * another CPU might have scheduled or disabled the tasklet. ++ * We only allow the STATE_RUN -> 0 transition here. ++ */ ++ while (!tasklet_tryunlock(t)) { ++ /* ++ * If it got disabled meanwhile, bail out: ++ */ ++ if (atomic_read(&t->count)) ++ goto out_disabled; ++ /* ++ * If it got scheduled meanwhile, re-execute ++ * the tasklet function: ++ */ ++ if (test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) ++ goto again; ++ if (!--loops) { ++ printk("hm, tasklet state: %08lx\n", t->state); ++ WARN_ON(1); + tasklet_unlock(t); +- continue; ++ break; + } +- tasklet_unlock(t); + } +- +- local_irq_disable(); +- t->next = __get_cpu_var(tasklet_vec).list; +- __get_cpu_var(tasklet_vec).list = t; +- __do_raise_softirq_irqoff(TASKLET_SOFTIRQ); +- local_irq_enable(); + } + } + +-static void tasklet_hi_action(struct softirq_action *a) ++static void tasklet_action(struct softirq_action *a) + { + struct tasklet_struct *list; + + local_irq_disable(); +- list = __get_cpu_var(tasklet_hi_vec).list; +- __get_cpu_var(tasklet_hi_vec).list = NULL; ++ list = __get_cpu_var(tasklet_vec).list; ++ __get_cpu_var(tasklet_vec).list = NULL; + local_irq_enable(); + +- while (list) { +- struct tasklet_struct *t = list; ++ __tasklet_action(a, list); ++} + +- list = list->next; ++static void tasklet_hi_action(struct softirq_action *a) ++{ ++ struct tasklet_struct *list; + +- if (tasklet_trylock(t)) { +- if (!atomic_read(&t->count)) { +- if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) +- BUG(); +- t->func(t->data); +- tasklet_unlock(t); +- continue; +- } +- tasklet_unlock(t); +- } ++ local_irq_disable(); ++ list = __get_cpu_var(tasklet_hi_vec).list; ++ __get_cpu_var(tasklet_hi_vec).list = NULL; ++ local_irq_enable(); + +- local_irq_disable(); +- t->next = __get_cpu_var(tasklet_hi_vec).list; +- __get_cpu_var(tasklet_hi_vec).list = t; +- __do_raise_softirq_irqoff(HI_SOFTIRQ); +- local_irq_enable(); +- } ++ __tasklet_action(a, list); + } + +- + void tasklet_init(struct tasklet_struct *t, + void (*func)(unsigned long), unsigned long data) + { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0083-ep93xx-clockevents.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0083-ep93xx-clockevents.patch @@ -0,0 +1,213 @@ +clockevent support for the EP93xx platform + +clockevent support for the EP93xx platform (by tglx) +Only added a fix for clockevent_ep93xx.mult, which was using the wrong clock +tickrate) + +--- + arch/arm/mach-ep93xx/core.c | 125 ++++++++++++++++++++---------- + include/asm-arm/arch-ep93xx/ep93xx-regs.h | 6 + + 2 files changed, 91 insertions(+), 40 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/arm/mach-ep93xx/core.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mach-ep93xx/core.c 2009-02-08 00:01:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mach-ep93xx/core.c 2009-02-08 00:01:23.000000000 -0500 +@@ -32,6 +32,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -50,7 +52,6 @@ + + #include + +- + /************************************************************************* + * Static I/O mappings that are needed for all EP93xx platforms + *************************************************************************/ +@@ -93,39 +94,58 @@ void __init ep93xx_map_io(void) + * to use this timer for something else. We also use timer 4 for keeping + * track of lost jiffies. + */ +-static unsigned int last_jiffy_time; +-static unsigned int next_jiffy_time; +-static unsigned int accumulator; ++static struct clock_event_device clockevent_ep93xx; ++ ++static int ep93xx_timer_interrupt(int irq, void *dev_id) ++{ ++ __raw_writel(EP93XX_TC_CLEAR, EP93XX_TIMER1_CLEAR); + +-#define TIMER4_TICKS_PER_JIFFY (983040 / HZ) +-#define TIMER4_TICKS_MOD_JIFFY (983040 % HZ) ++ clockevent_ep93xx.event_handler(&clockevent_ep93xx); + +-static int after_eq(unsigned long a, unsigned long b) ++ return IRQ_HANDLED; ++} ++ ++static int ep93xx_set_next_event(unsigned long evt, ++ struct clock_event_device *unused) + { +- return ((signed long)(a - b)) >= 0; ++ __raw_writel(evt, EP93XX_TIMER1_LOAD); ++ return 0; + } + +-static int ep93xx_timer_interrupt(int irq, void *dev_id) ++static void ep93xx_set_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) + { +- write_seqlock(&xtime_lock); ++ u32 tmode = EP93XX_TC123_SEL_508KHZ; + +- __raw_writel(1, EP93XX_TIMER1_CLEAR); +- while (after_eq(__raw_readl(EP93XX_TIMER4_VALUE_LOW), next_jiffy_time)) { +- timer_tick(); +- +- last_jiffy_time = next_jiffy_time; +- next_jiffy_time += TIMER4_TICKS_PER_JIFFY; +- accumulator += TIMER4_TICKS_MOD_JIFFY; +- if (accumulator >= HZ) { +- next_jiffy_time++; +- accumulator -= HZ; +- } ++ /* Disable timer */ ++ __raw_writel(tmode, EP93XX_TIMER1_CONTROL); ++ ++ switch(mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ /* Set timer period */ ++ __raw_writel((508469 / HZ) - 1, EP93XX_TIMER1_LOAD); ++ tmode |= EP93XX_TC123_PERIODIC; ++ ++ case CLOCK_EVT_MODE_ONESHOT: ++ tmode |= EP93XX_TC123_ENABLE; ++ __raw_writel(tmode, EP93XX_TIMER1_CONTROL); ++ break; ++ ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ case CLOCK_EVT_MODE_UNUSED: ++ case CLOCK_EVT_MODE_RESUME: ++ return; + } ++} + +- write_sequnlock(&xtime_lock); ++static struct clock_event_device clockevent_ep93xx = { ++ .name = "ep93xx-timer1", ++ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, ++ .shift = 32, ++ .set_mode = ep93xx_set_mode, ++ .set_next_event = ep93xx_set_next_event, ++}; + +- return IRQ_HANDLED; +-} + + static struct irqaction ep93xx_timer_irq = { + .name = "ep93xx timer", +@@ -133,32 +153,58 @@ static struct irqaction ep93xx_timer_irq + .handler = ep93xx_timer_interrupt, + }; + +-static void __init ep93xx_timer_init(void) ++static void __init ep93xx_clockevent_init(void) + { +- /* Enable periodic HZ timer. */ +- __raw_writel(0x48, EP93XX_TIMER1_CONTROL); +- __raw_writel((508469 / HZ) - 1, EP93XX_TIMER1_LOAD); +- __raw_writel(0xc8, EP93XX_TIMER1_CONTROL); ++ setup_irq(IRQ_EP93XX_TIMER1, &ep93xx_timer_irq); + +- /* Enable lost jiffy timer. */ +- __raw_writel(0x100, EP93XX_TIMER4_VALUE_HIGH); ++ clockevent_ep93xx.mult = div_sc(508469, NSEC_PER_SEC, ++ clockevent_ep93xx.shift); ++ clockevent_ep93xx.max_delta_ns = ++ clockevent_delta2ns(0xfffffffe, &clockevent_ep93xx); ++ clockevent_ep93xx.min_delta_ns = ++ clockevent_delta2ns(0xf, &clockevent_ep93xx); ++ clockevent_ep93xx.cpumask = cpumask_of_cpu(0); ++ clockevents_register_device(&clockevent_ep93xx); ++} + +- setup_irq(IRQ_EP93XX_TIMER1, &ep93xx_timer_irq); ++/* ++ * timer4 is a 40 Bit timer, separated in a 32bit and a 8 bit ++ * register, EP93XX_TIMER4_VALUE_LOW stores 32 bit word. The ++ * controlregister is in EP93XX_TIMER4_VALUE_HIGH ++ */ ++ ++cycle_t ep93xx_get_cycles(void) ++{ ++ return __raw_readl(EP93XX_TIMER4_VALUE_LOW); + } + +-static unsigned long ep93xx_gettimeoffset(void) ++static struct clocksource clocksource_ep93xx = { ++ .name = "ep93xx_timer4", ++ .rating = 200, ++ .read = ep93xx_get_cycles, ++ .mask = 0xFFFFFFFF, ++ .shift = 20, ++ .flags = CLOCK_SOURCE_IS_CONTINUOUS, ++}; ++ ++static void __init ep93xx_clocksource_init(void) + { +- int offset; ++ /* Reset time-stamp counter */ ++ __raw_writel(0x100, EP93XX_TIMER4_VALUE_HIGH); + +- offset = __raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time; ++ clocksource_ep93xx.mult = ++ clocksource_hz2mult(983040, clocksource_ep93xx.shift); ++ clocksource_register(&clocksource_ep93xx); ++} + +- /* Calculate (1000000 / 983040) * offset. */ +- return offset + (53 * offset / 3072); ++static void __init ep93xx_timer_init(void) ++{ ++ ep93xx_clocksource_init(); ++ ep93xx_clockevent_init(); + } + + struct sys_timer ep93xx_timer = { +- .init = ep93xx_timer_init, +- .offset = ep93xx_gettimeoffset, ++ .init = ep93xx_timer_init, + }; + + +@@ -510,7 +556,6 @@ static struct platform_device ep93xx_ohc + .resource = ep93xx_ohci_resources, + }; + +- + void __init ep93xx_init_devices(void) + { + unsigned int v; +Index: linux-2.6.24.7-rt27/include/asm-arm/arch-ep93xx/ep93xx-regs.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/arch-ep93xx/ep93xx-regs.h 2009-02-08 00:00:23.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/arch-ep93xx/ep93xx-regs.h 2009-02-08 00:01:23.000000000 -0500 +@@ -67,6 +67,12 @@ + #define EP93XX_TIMER3_CONTROL EP93XX_TIMER_REG(0x88) + #define EP93XX_TIMER3_CLEAR EP93XX_TIMER_REG(0x8c) + ++#define EP93XX_TC_CLEAR 0x00000001 ++#define EP93XX_TC123_ENABLE 0x00000080 ++#define EP93XX_TC123_PERIODIC 0x00000040 ++#define EP93XX_TC123_SEL_508KHZ 0x00000008 ++#define EP93XX_TC4_ENABLE 0x00000100 ++ + #define EP93XX_I2S_BASE (EP93XX_APB_VIRT_BASE + 0x00020000) + + #define EP93XX_SECURITY_BASE (EP93XX_APB_VIRT_BASE + 0x00030000) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0318-softirq-per-cpu-assumptions-fixes.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0318-softirq-per-cpu-assumptions-fixes.patch @@ -0,0 +1,180 @@ +--- + kernel/hrtimer.c | 38 +++++++++++++++++++++----------------- + kernel/sched.c | 2 +- + kernel/softirq.c | 5 +++-- + kernel/timer.c | 2 +- + 4 files changed, 26 insertions(+), 21 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/hrtimer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/hrtimer.c 2009-02-08 00:02:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/hrtimer.c 2009-02-08 00:03:21.000000000 -0500 +@@ -380,9 +380,9 @@ static inline int hrtimer_is_hres_enable + /* + * Is the high resolution mode active ? + */ +-static inline int hrtimer_hres_active(void) ++static inline int hrtimer_hres_active(struct hrtimer_cpu_base *cpu_base) + { +- return __get_cpu_var(hrtimer_bases).hres_active; ++ return cpu_base->hres_active; + } + + /* +@@ -470,11 +470,12 @@ static int hrtimer_reprogram(struct hrti + */ + static void retrigger_next_event(void *arg) + { +- struct hrtimer_cpu_base *base; ++ struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases); ++ + struct timespec realtime_offset; + unsigned long seq; + +- if (!hrtimer_hres_active()) ++ if (!hrtimer_hres_active(base)) + return; + + do { +@@ -484,8 +485,6 @@ static void retrigger_next_event(void *a + -wall_to_monotonic.tv_nsec); + } while (read_seqretry(&xtime_lock, seq)); + +- base = &__get_cpu_var(hrtimer_bases); +- + /* Adjust CLOCK_REALTIME offset */ + spin_lock(&base->lock); + base->clock_base[CLOCK_REALTIME].offset = +@@ -606,10 +605,8 @@ static inline int hrtimer_enqueue_reprog + /* + * Switch to high resolution mode + */ +-static int hrtimer_switch_to_hres(void) ++static int hrtimer_switch_to_hres(struct hrtimer_cpu_base *base) + { +- int cpu = smp_processor_id(); +- struct hrtimer_cpu_base *base = &per_cpu(hrtimer_bases, cpu); + unsigned long flags; + + if (base->hres_active) +@@ -620,7 +617,7 @@ static int hrtimer_switch_to_hres(void) + if (tick_init_highres()) { + local_irq_restore(flags); + printk(KERN_WARNING "Could not switch to high resolution " +- "mode on CPU %d\n", cpu); ++ "mode on CPU %d\n", raw_smp_processor_id()); + return 0; + } + base->hres_active = 1; +@@ -642,9 +639,15 @@ static inline void hrtimer_raise_softirq + + #else + +-static inline int hrtimer_hres_active(void) { return 0; } ++static inline int hrtimer_hres_active(struct hrtimer_cpu_base *base) ++{ ++ return 0; ++} + static inline int hrtimer_is_hres_enabled(void) { return 0; } +-static inline int hrtimer_switch_to_hres(void) { return 0; } ++static inline int hrtimer_switch_to_hres(struct hrtimer_cpu_base *base) ++{ ++ return 0; ++} + static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { } + static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, + struct hrtimer_clock_base *base) +@@ -836,7 +839,7 @@ static void __remove_hrtimer(struct hrti + if (base->first == &timer->node) { + base->first = rb_next(&timer->node); + /* Reprogram the clock event device. if enabled */ +- if (reprogram && hrtimer_hres_active()) ++ if (reprogram && hrtimer_hres_active(base->cpu_base)) + hrtimer_force_reprogram(base->cpu_base); + } + rb_erase(&timer->node, &base->active); +@@ -1027,7 +1030,7 @@ ktime_t hrtimer_get_next_event(void) + + spin_lock_irqsave(&cpu_base->lock, flags); + +- if (!hrtimer_hres_active()) { ++ if (!hrtimer_hres_active(cpu_base)) { + for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++, base++) { + struct hrtimer *timer; + +@@ -1335,10 +1338,11 @@ static inline void run_hrtimer_queue(str + */ + void hrtimer_run_queues(void) + { +- struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); ++ struct hrtimer_cpu_base *cpu_base; + int i; + +- if (hrtimer_hres_active()) ++ cpu_base = &per_cpu(hrtimer_bases, raw_smp_processor_id()); ++ if (hrtimer_hres_active(cpu_base)) + return; + + /* +@@ -1350,7 +1354,7 @@ void hrtimer_run_queues(void) + * deadlock vs. xtime_lock. + */ + if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) +- if (hrtimer_switch_to_hres()) ++ if (hrtimer_switch_to_hres(cpu_base)) + return; + + hrtimer_get_softirq_time(cpu_base); +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:02:38.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:03:21.000000000 -0500 +@@ -3392,7 +3392,7 @@ out: + */ + static void run_rebalance_domains(struct softirq_action *h) + { +- int this_cpu = smp_processor_id(); ++ int this_cpu = raw_smp_processor_id(); + struct rq *this_rq = cpu_rq(this_cpu); + enum cpu_idle_type idle = this_rq->idle_at_tick ? + CPU_IDLE : CPU_NOT_IDLE; +Index: linux-2.6.24.7-rt27/kernel/softirq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/softirq.c 2009-02-08 00:03:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/softirq.c 2009-02-08 00:03:21.000000000 -0500 +@@ -411,12 +411,12 @@ void do_softirq_from_hardirq(void) + { + unsigned long p_flags; + +- if (!local_softirq_pending()) +- return; + /* + * 'immediate' softirq execution, from hardirq context: + */ + local_irq_disable(); ++ if (!local_softirq_pending()) ++ goto out; + __local_bh_disable((unsigned long)__builtin_return_address(0)); + #ifndef CONFIG_PREEMPT_SOFTIRQS + trace_softirq_enter(); +@@ -436,6 +436,7 @@ void do_softirq_from_hardirq(void) + current->flags &= ~PF_SOFTIRQ; + + _local_bh_enable(); ++out: + local_irq_enable(); + } + +Index: linux-2.6.24.7-rt27/kernel/timer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/timer.c 2009-02-08 00:02:58.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/timer.c 2009-02-08 00:03:21.000000000 -0500 +@@ -1035,7 +1035,7 @@ static inline void update_times(void) + */ + static void run_timer_softirq(struct softirq_action *h) + { +- tvec_base_t *base = __get_cpu_var(tvec_bases); ++ tvec_base_t *base = per_cpu(tvec_bases, raw_smp_processor_id()); + + update_times(); + hrtimer_run_queues(); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0286-fix-circular-locking-deadlock.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0286-fix-circular-locking-deadlock.patch @@ -0,0 +1,140 @@ +On Thu, 2007-08-16 at 09:39 +0200, Peter Zijlstra wrote: +> On Wed, 2007-08-15 at 18:39 -0700, john stultz wrote: +> > Hey Ingo, Thomas, +> > +> > I was playing with the latency tracer on 2.6.23-rc2-rt2 while a "make +> > -j8" was going on in the background and the box hung with this on the +> > console: +> +> Hmm, this would have been me :-/ +> +> I'll go play... + + +Could you give this a spin... + +(not sure on the added rmbs, but they can't hurt) + +--- +Fix a deadlock in the fine grain locked list primitives. + +Delete and splice use a double lock, which normally locks in the +prev->cur order. For delete this is deadlock free provided one will +never delete the list head - which is exactly what splice attempts. + +In order to solve this, use the reverse locking order for splice - which +then assumes that the list passes is indeed the list head (no fancy +dummy item headless lists here). + +Signed-off-by: Peter Zijlstra +--- + lib/lock_list.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 60 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/lib/lock_list.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/lock_list.c 2009-02-08 00:03:02.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/lock_list.c 2009-02-08 00:03:03.000000000 -0500 +@@ -11,7 +11,7 @@ + * + * Passed pointers are assumed to be stable by external means such as + * refcounts or RCU. The individual list entries are assumed to be RCU +- * freed (requirement of __lock_list_del). ++ * freed (requirement of __lock_list). + */ + + #include +@@ -19,12 +19,9 @@ + void lock_list_add(struct lock_list_head *new, + struct lock_list_head *list) + { +- struct lock_list_head *next; +- + spin_lock(&new->lock); + spin_lock_nested(&list->lock, LOCK_LIST_NESTING_PREV); +- next = list->next; +- __list_add(&new->head, &list->head, &next->head); ++ __list_add(&new->head, &list->head, &list->next->head); + spin_unlock(&list->lock); + spin_unlock(&new->lock); + } +@@ -35,6 +32,13 @@ static spinlock_t *__lock_list(struct lo + spinlock_t *lock = NULL; + + again: ++ /* ++ * all modifications are done under spinlocks ++ * but this read is not, the unlock acks as a wmb ++ * for modifications. ++ */ ++ smp_rmb(); ++ + prev = entry->prev; + if (prev == entry) + goto one; +@@ -52,6 +56,56 @@ one: + return lock; + } + ++/* ++ * deadlock galore... ++ * ++ * when using __lock_list to lock the list head we get this: ++ * ++ * lock H 2 1 ++ * lock 1 a b ++ * lock 2 A B ++ * ++ * list: ..-> [H] <-> [1] <-> [2] <-.. ++ * ++ * obvious dead-lock, to solve this we must use a reverse order ++ * when trying to acquire a double lock on the head: ++ * ++ * lock H r 1 2 ++ * lock 1 a b ++ * lock 2 A B ++ * ++ * list: ..-> [H] <-> [1] <-> [2] <-.. ++ */ ++static spinlock_t *__lock_list_reverse(struct lock_list_head *entry) ++{ ++ struct lock_list_head *prev; ++ spinlock_t *lock = NULL; ++ ++ spin_lock(&entry->lock); ++again: ++ /* ++ * all modifications are done under spinlocks ++ * but this read is not, the unlock acks as a wmb ++ * for modifications. ++ */ ++ smp_rmb(); ++ prev = entry->prev; ++ if (prev == entry) ++ goto done; ++ ++ spin_lock_nested(&prev->lock, LOCK_LIST_NESTING_PREV); ++ if (unlikely(entry->prev != prev)) { ++ /* ++ * we lost ++ */ ++ spin_unlock(&prev->lock); ++ goto again; ++ } ++ lock = &prev->lock; ++done: ++ return lock; ++} ++ + void lock_list_del_init(struct lock_list_head *entry) + { + spinlock_t *lock; +@@ -71,7 +125,7 @@ void lock_list_splice_init(struct lock_l + spinlock_t *lock; + + rcu_read_lock(); +- lock = __lock_list(list); ++ lock = __lock_list_reverse(list); + if (!list_empty(&list->head)) { + spin_lock_nested(&head->lock, LOCK_LIST_NESTING_NEXT); + __list_splice(&list->head, &head->head); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0172-rt-mutex-mips.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0172-rt-mutex-mips.patch @@ -0,0 +1,250 @@ +--- + arch/mips/Kconfig | 15 +++++++++++---- + arch/mips/kernel/Makefile | 4 +++- + include/asm-mips/atomic.h | 26 +++++++++++++++++++++----- + include/asm-mips/semaphore.h | 30 +++++++++++++++++++++--------- + 4 files changed, 56 insertions(+), 19 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/mips/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/Kconfig 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/Kconfig 2009-02-08 00:02:04.000000000 -0500 +@@ -52,6 +52,7 @@ config BCM47XX + select CEVT_R4K + select CSRC_R4K + select DMA_NONCOHERENT ++ select NO_SPINLOCK + select HW_HAS_PCI + select IRQ_CPU + select SYS_HAS_CPU_MIPS32_R1 +@@ -703,10 +704,17 @@ endmenu + + config RWSEM_GENERIC_SPINLOCK + bool ++ depends on !PREEMPT_RT + default y + + config RWSEM_XCHGADD_ALGORITHM + bool ++ depends on !PREEMPT_RT ++ ++config ASM_SEMAPHORES ++ bool ++# depends on !PREEMPT_RT ++ default y + + config ARCH_HAS_ILOG2_U32 + bool +@@ -808,6 +816,9 @@ config DMA_NONCOHERENT + config DMA_NEED_PCI_MAP_STATE + bool + ++config NO_SPINLOCK ++ bool ++ + config EARLY_PRINTK + bool "Early printk" if EMBEDDED && DEBUG_KERNEL + depends on SYS_HAS_EARLY_PRINTK +@@ -1889,10 +1900,6 @@ config SECCOMP + + endmenu + +-config RWSEM_GENERIC_SPINLOCK +- bool +- default y +- + config LOCKDEP_SUPPORT + bool + default y +Index: linux-2.6.24.7-rt27/arch/mips/kernel/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/Makefile 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/Makefile 2009-02-08 00:02:04.000000000 -0500 +@@ -5,7 +5,7 @@ + extra-y := head.o init_task.o vmlinux.lds + + obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ +- ptrace.o reset.o semaphore.o setup.o signal.o syscall.o \ ++ ptrace.o reset.o setup.o signal.o syscall.o \ + time.o topology.o traps.o unaligned.o + + obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o +@@ -26,6 +26,8 @@ obj-$(CONFIG_MODULES) += mips_ksyms.o m + obj-$(CONFIG_CPU_LOONGSON2) += r4k_fpu.o r4k_switch.o + obj-$(CONFIG_CPU_MIPS32) += r4k_fpu.o r4k_switch.o + obj-$(CONFIG_CPU_MIPS64) += r4k_fpu.o r4k_switch.o ++obj-$(CONFIG_ASM_SEMAPHORES) += semaphore.o ++ + obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o + obj-$(CONFIG_CPU_R4000) += r4k_fpu.o r4k_switch.o + obj-$(CONFIG_CPU_R4300) += r4k_fpu.o r4k_switch.o +Index: linux-2.6.24.7-rt27/include/asm-mips/atomic.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/atomic.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/atomic.h 2009-02-08 00:02:04.000000000 -0500 +@@ -171,7 +171,9 @@ static __inline__ int atomic_add_return( + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) + : "memory"); +- } else { ++ } ++#if !defined(CONFIG_NO_SPINLOCK) && !defined(CONFIG_PREEMPT_RT) ++ else { + unsigned long flags; + + raw_local_irq_save(flags); +@@ -180,6 +182,7 @@ static __inline__ int atomic_add_return( + v->counter = result; + raw_local_irq_restore(flags); + } ++#endif + + smp_llsc_mb(); + +@@ -223,7 +226,9 @@ static __inline__ int atomic_sub_return( + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) + : "memory"); +- } else { ++ } ++#if !defined(CONFIG_NO_SPINLOCK) && !defined(CONFIG_PREEMPT_RT) ++ else { + unsigned long flags; + + raw_local_irq_save(flags); +@@ -232,6 +237,7 @@ static __inline__ int atomic_sub_return( + v->counter = result; + raw_local_irq_restore(flags); + } ++#endif + + smp_llsc_mb(); + +@@ -291,7 +297,9 @@ static __inline__ int atomic_sub_if_posi + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) + : "memory"); +- } else { ++ } ++#if !defined(CONFIG_NO_SPINLOCK) && !defined(CONFIG_PREEMPT_RT) ++ else { + unsigned long flags; + + raw_local_irq_save(flags); +@@ -301,6 +309,7 @@ static __inline__ int atomic_sub_if_posi + v->counter = result; + raw_local_irq_restore(flags); + } ++#endif + + smp_llsc_mb(); + +@@ -552,7 +561,9 @@ static __inline__ long atomic64_add_retu + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) + : "memory"); +- } else { ++ } ++#if !defined(CONFIG_NO_SPINLOCK) && !defined(CONFIG_PREEMPT_RT) ++ else { + unsigned long flags; + + raw_local_irq_save(flags); +@@ -561,6 +572,8 @@ static __inline__ long atomic64_add_retu + v->counter = result; + raw_local_irq_restore(flags); + } ++#endif ++#endif + + smp_llsc_mb(); + +@@ -604,7 +617,9 @@ static __inline__ long atomic64_sub_retu + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) + : "memory"); +- } else { ++ } ++#if !defined(CONFIG_NO_SPINLOCK) && !defined(CONFIG_PREEMPT_RT) ++ else { + unsigned long flags; + + raw_local_irq_save(flags); +@@ -682,6 +697,7 @@ static __inline__ long atomic64_sub_if_p + v->counter = result; + raw_local_irq_restore(flags); + } ++#endif + + smp_llsc_mb(); + +Index: linux-2.6.24.7-rt27/include/asm-mips/semaphore.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/semaphore.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/semaphore.h 2009-02-08 00:02:04.000000000 -0500 +@@ -24,12 +24,20 @@ + + #ifdef __KERNEL__ + +-#include +-#include + #include + #include + +-struct semaphore { ++/* ++ * On !PREEMPT_RT all semaphores are compat: ++ */ ++#ifndef CONFIG_PREEMPT_RT ++# define compat_semaphore semaphore ++#endif ++ ++#include ++#include ++ ++struct compat_semaphore { + /* + * Note that any negative value of count is equivalent to 0, + * but additionally indicates that some process(es) might be +@@ -78,31 +86,35 @@ static inline void down(struct semaphore + * Try to get the semaphore, take the slow path if we fail. + */ + if (unlikely(atomic_dec_return(&sem->count) < 0)) +- __down(sem); ++ __compat_down(sem); + } + +-static inline int down_interruptible(struct semaphore * sem) ++static inline int compat_down_interruptible(struct compat_semaphore * sem) + { + int ret = 0; + + might_sleep(); + + if (unlikely(atomic_dec_return(&sem->count) < 0)) +- ret = __down_interruptible(sem); ++ ret = __compat_down_interruptible(sem); + return ret; + } + +-static inline int down_trylock(struct semaphore * sem) ++static inline int compat_down_trylock(struct compat_semaphore * sem) + { + return atomic_dec_if_positive(&sem->count) < 0; + } + +-static inline void up(struct semaphore * sem) ++static inline void compat_up(struct compat_semaphore * sem) + { + if (unlikely(atomic_inc_return(&sem->count) <= 0)) +- __up(sem); ++ __compat_up(sem); + } + ++#define compat_sema_count(sem) atomic_read(&(sem)->count) ++ ++#include ++ + #endif /* __KERNEL__ */ + + #endif /* __ASM_SEMAPHORE_H */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0238-preempt-realtime-prevent-idle-boosting.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0238-preempt-realtime-prevent-idle-boosting.patch @@ -0,0 +1,57 @@ +Subject: Premmpt-RT: Preevent boosting of idle task + +Idle task boosting is a nono in general. There is one +exception, when NOHZ is active: + +The idle task calls get_next_timer_interrupt() and holds +the timer wheel base->lock on the CPU and another CPU wants +to access the timer (probably to cancel it). We can safely +ignore the boosting request, as the idle CPU runs this code +with interrupts disabled and will complete the lock +protected section without being interrupted. So there is no +real need to boost. + +Signed-off-by: Thomas Gleixner + +--- + kernel/sched.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:02:37.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:02:38.000000000 -0500 +@@ -4343,6 +4343,25 @@ void rt_mutex_setprio(struct task_struct + BUG_ON(prio < 0 || prio > MAX_PRIO); + + rq = task_rq_lock(p, &flags); ++ ++ /* ++ * Idle task boosting is a nono in general. There is one ++ * exception, when NOHZ is active: ++ * ++ * The idle task calls get_next_timer_interrupt() and holds ++ * the timer wheel base->lock on the CPU and another CPU wants ++ * to access the timer (probably to cancel it). We can safely ++ * ignore the boosting request, as the idle CPU runs this code ++ * with interrupts disabled and will complete the lock ++ * protected section without being interrupted. So there is no ++ * real need to boost. ++ */ ++ if (unlikely(p == rq->idle)) { ++ WARN_ON(p != rq->curr); ++ WARN_ON(p->pi_blocked_on); ++ goto out_unlock; ++ } ++ + update_rq_clock(rq); + + oldprio = p->prio; +@@ -4371,6 +4390,7 @@ void rt_mutex_setprio(struct task_struct + } + // trace_special(prev_resched, _need_resched(), 0); + ++out_unlock: + task_rq_unlock(rq, &flags); + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0232-preempt-irqs-i386-idle-poll-loop-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0232-preempt-irqs-i386-idle-poll-loop-fix.patch @@ -0,0 +1,19 @@ +--- + arch/x86/kernel/process_32.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/process_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/process_32.c 2009-02-08 00:02:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/process_32.c 2009-02-08 00:02:35.000000000 -0500 +@@ -134,7 +134,9 @@ EXPORT_SYMBOL(default_idle); + */ + static void poll_idle (void) + { +- cpu_relax(); ++ do { ++ cpu_relax(); ++ } while (!need_resched() && !need_resched_delayed()); + } + + #ifdef CONFIG_HOTPLUG_CPU --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0575-ftrace-correctly-display-preempt-count-in-ftracer.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0575-ftrace-correctly-display-preempt-count-in-ftracer.patch @@ -0,0 +1,343 @@ +From: Carsten Emde +Subject: ftrace: display real preempt_count in ftracer +Date: Wed, 28 Jan 2009 14:39:51 +0100 + +Ftrace determined the preempt_count after preemption was disabled +instead of the original preemption count. + +Signed-off-by: Carsten Emde +Signed-off-by: Thomas Gleixner + +--- + kernel/trace/trace.c | 48 +++++++++++++++++++------------------- + kernel/trace/trace.h | 3 +- + kernel/trace/trace_hist.c | 2 - + kernel/trace/trace_irqsoff.c | 13 ++++++---- + kernel/trace/trace_sched_wakeup.c | 9 ++++--- + 5 files changed, 41 insertions(+), 34 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/trace/trace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace.c 2009-02-08 00:05:21.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace.c 2009-02-08 00:05:24.000000000 -0500 +@@ -808,12 +808,10 @@ tracing_get_trace_entry(struct trace_arr + } + + static inline void +-tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags) ++tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags, ++ unsigned long pc) + { + struct task_struct *tsk = current; +- unsigned long pc; +- +- pc = preempt_count(); + + entry->preempt_count = pc & 0xff; + entry->pid = (tsk) ? tsk->pid : 0; +@@ -826,7 +824,8 @@ tracing_generic_entry_update(struct trac + + void + trace_function(struct trace_array *tr, struct trace_array_cpu *data, +- unsigned long ip, unsigned long parent_ip, unsigned long flags) ++ unsigned long ip, unsigned long parent_ip, unsigned long flags, ++ unsigned long pc) + { + struct trace_entry *entry; + unsigned long irq_flags; +@@ -834,7 +833,7 @@ trace_function(struct trace_array *tr, s + raw_local_irq_save(irq_flags); + __raw_spin_lock(&data->lock); + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, pc); + entry->type = TRACE_FN; + entry->fn.ip = ip; + entry->fn.parent_ip = parent_ip; +@@ -847,7 +846,8 @@ ftrace(struct trace_array *tr, struct tr + unsigned long ip, unsigned long parent_ip, unsigned long flags) + { + if (likely(!atomic_read(&data->disabled))) +- trace_function(tr, data, ip, parent_ip, flags); ++ trace_function(tr, data, ip, parent_ip, flags, ++ preempt_count()); + } + + #ifdef CONFIG_MMIOTRACE +@@ -861,7 +861,7 @@ void __trace_mmiotrace_rw(struct trace_a + __raw_spin_lock(&data->lock); + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, 0); ++ tracing_generic_entry_update(entry, 0, preempt_count()); + entry->type = TRACE_MMIO_RW; + entry->mmiorw = *rw; + +@@ -881,7 +881,7 @@ void __trace_mmiotrace_map(struct trace_ + __raw_spin_lock(&data->lock); + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, 0); ++ tracing_generic_entry_update(entry, 0, preempt_count()); + entry->type = TRACE_MMIO_MAP; + entry->mmiomap = *map; + +@@ -904,7 +904,7 @@ void __trace_stack(struct trace_array *t + return; + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_STACK; + + memset(&entry->stack, 0, sizeof(entry->stack)); +@@ -929,7 +929,7 @@ __trace_special(void *__tr, void *__data + raw_local_irq_save(irq_flags); + __raw_spin_lock(&data->lock); + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, 0); ++ tracing_generic_entry_update(entry, 0, preempt_count()); + entry->type = TRACE_SPECIAL; + entry->special.arg1 = arg1; + entry->special.arg2 = arg2; +@@ -954,7 +954,7 @@ tracing_sched_switch_trace(struct trace_ + raw_local_irq_save(irq_flags); + __raw_spin_lock(&data->lock); + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_CTX; + entry->ctx.prev_pid = prev->pid; + entry->ctx.prev_prio = prev->prio; +@@ -980,7 +980,7 @@ tracing_sched_wakeup_trace(struct trace_ + raw_local_irq_save(irq_flags); + __raw_spin_lock(&data->lock); + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_WAKE; + entry->ctx.prev_pid = curr->pid; + entry->ctx.prev_prio = curr->prio; +@@ -1029,7 +1029,7 @@ void tracing_event_irq(struct trace_arra + struct trace_entry *entry; + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_IRQ; + entry->irq.ip = ip; + entry->irq.irq = irq; +@@ -1048,7 +1048,7 @@ void tracing_event_fault(struct trace_ar + struct trace_entry *entry; + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_FAULT; + entry->fault.ip = ip; + entry->fault.ret_ip = retip; +@@ -1065,7 +1065,7 @@ void tracing_event_timer_set(struct trac + struct trace_entry *entry; + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_TIMER_SET; + entry->timer.ip = ip; + entry->timer.expire = *expires; +@@ -1081,7 +1081,7 @@ void tracing_event_program_event(struct + struct trace_entry *entry; + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_PROGRAM_EVENT; + entry->program.ip = ip; + entry->program.expire = *expires; +@@ -1097,7 +1097,7 @@ void tracing_event_timer_triggered(struc + struct trace_entry *entry; + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_TIMER_TRIG; + entry->timer.ip = ip; + entry->timer.expire = *expired; +@@ -1113,7 +1113,7 @@ void tracing_event_timestamp(struct trac + struct trace_entry *entry; + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_TIMESTAMP; + entry->timestamp.ip = ip; + entry->timestamp.now = *now; +@@ -1129,7 +1129,7 @@ void tracing_event_task_activate(struct + struct trace_entry *entry; + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_TASK_ACT; + entry->task.ip = ip; + entry->task.pid = p->pid; +@@ -1147,7 +1147,7 @@ void tracing_event_task_deactivate(struc + struct trace_entry *entry; + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_TASK_DEACT; + entry->task.ip = ip; + entry->task.pid = p->pid; +@@ -1167,7 +1167,7 @@ void tracing_event_syscall(struct trace_ + struct trace_entry *entry; + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_SYSCALL; + entry->syscall.ip = ip; + entry->syscall.nr = nr; +@@ -1185,7 +1185,7 @@ void tracing_event_sysret(struct trace_a + struct trace_entry *entry; + + entry = tracing_get_trace_entry(tr, data); +- tracing_generic_entry_update(entry, flags); ++ tracing_generic_entry_update(entry, flags, preempt_count()); + entry->type = TRACE_SYSRET; + entry->sysret.ip = ip; + entry->sysret.ret = ret; +@@ -1210,7 +1210,7 @@ function_trace_call(unsigned long ip, un + disabled = atomic_inc_return(&data->disabled); + + if (likely(disabled == 1)) +- trace_function(tr, data, ip, parent_ip, flags); ++ trace_function(tr, data, ip, parent_ip, flags, preempt_count()); + + atomic_dec(&data->disabled); + local_irq_restore(flags); +Index: linux-2.6.24.7-rt27/kernel/trace/trace.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace.h 2009-02-08 00:05:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace.h 2009-02-08 00:05:24.000000000 -0500 +@@ -302,7 +302,8 @@ void trace_function(struct trace_array * + struct trace_array_cpu *data, + unsigned long ip, + unsigned long parent_ip, +- unsigned long flags); ++ unsigned long flags, ++ unsigned long pc); + void tracing_event_irq(struct trace_array *tr, + struct trace_array_cpu *data, + unsigned long flags, +Index: linux-2.6.24.7-rt27/kernel/trace/trace_hist.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace_hist.c 2009-02-08 00:05:23.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace_hist.c 2009-02-08 00:05:24.000000000 -0500 +@@ -354,7 +354,7 @@ notrace void tracing_hist_preempt_stop(i + cpu = raw_smp_processor_id(); + + #ifdef CONFIG_INTERRUPT_OFF_HIST +- if (irqs_on && ++ if (irqs_on && + per_cpu(hist_irqsoff_tracing, cpu)) { + stop = ftrace_now(cpu); + stop_set++; +Index: linux-2.6.24.7-rt27/kernel/trace/trace_irqsoff.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace_irqsoff.c 2009-02-08 00:05:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace_irqsoff.c 2009-02-08 00:05:24.000000000 -0500 +@@ -99,7 +99,8 @@ irqsoff_tracer_call(unsigned long ip, un + disabled = atomic_inc_return(&data->disabled); + + if (likely(disabled == 1)) +- trace_function(tr, data, ip, parent_ip, flags); ++ trace_function(tr, data, ip, parent_ip, flags, ++ preempt_count()); + + atomic_dec(&data->disabled); + } +@@ -154,7 +155,8 @@ check_critical_timing(struct trace_array + if (!report_latency(delta)) + goto out_unlock; + +- trace_function(tr, data, CALLER_ADDR0, parent_ip, flags); ++ trace_function(tr, data, CALLER_ADDR0, parent_ip, flags, ++ preempt_count()); + + latency = nsecs_to_usecs(delta); + +@@ -178,7 +180,8 @@ out: + data->critical_sequence = max_sequence; + data->preempt_timestamp = ftrace_now(cpu); + tracing_reset(data); +- trace_function(tr, data, CALLER_ADDR0, parent_ip, flags); ++ trace_function(tr, data, CALLER_ADDR0, parent_ip, flags, ++ preempt_count()); + } + + static inline void +@@ -211,7 +214,7 @@ start_critical_timing(unsigned long ip, + + local_save_flags(flags); + +- trace_function(tr, data, ip, parent_ip, flags); ++ trace_function(tr, data, ip, parent_ip, flags, preempt_count()); + + per_cpu(tracing_cpu, cpu) = 1; + +@@ -245,7 +248,7 @@ stop_critical_timing(unsigned long ip, u + atomic_inc(&data->disabled); + + local_save_flags(flags); +- trace_function(tr, data, ip, parent_ip, flags); ++ trace_function(tr, data, ip, parent_ip, flags, preempt_count()); + check_critical_timing(tr, data, parent_ip ? : ip, cpu); + data->critical_start = 0; + atomic_dec(&data->disabled); +Index: linux-2.6.24.7-rt27/kernel/trace/trace_sched_wakeup.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace_sched_wakeup.c 2009-02-08 00:04:48.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace_sched_wakeup.c 2009-02-08 00:05:24.000000000 -0500 +@@ -44,10 +44,12 @@ wakeup_tracer_call(unsigned long ip, uns + long disabled; + int resched; + int cpu; ++ unsigned long pc; + + if (likely(!wakeup_task) || !ftrace_enabled) + return; + ++ pc = preempt_count(); + resched = need_resched(); + preempt_disable_notrace(); + +@@ -70,7 +72,7 @@ wakeup_tracer_call(unsigned long ip, uns + if (task_cpu(wakeup_task) != cpu) + goto unlock; + +- trace_function(tr, data, ip, parent_ip, flags); ++ trace_function(tr, data, ip, parent_ip, flags, pc); + + unlock: + __raw_spin_unlock(&wakeup_lock); +@@ -155,7 +157,8 @@ wakeup_sched_switch(void *private, void + if (unlikely(!tracer_enabled || next != wakeup_task)) + goto out_unlock; + +- trace_function(tr, data, CALLER_ADDR1, CALLER_ADDR2, flags); ++ trace_function(tr, data, CALLER_ADDR1, CALLER_ADDR2, flags, ++ preempt_count()); + + /* + * usecs conversion is slow so we try to delay the conversion +@@ -276,7 +279,7 @@ wakeup_check_start(struct trace_array *t + + tr->data[wakeup_cpu]->preempt_timestamp = ftrace_now(cpu); + trace_function(tr, tr->data[wakeup_cpu], +- CALLER_ADDR1, CALLER_ADDR2, flags); ++ CALLER_ADDR1, CALLER_ADDR2, flags, preempt_count()); + + out_locked: + __raw_spin_unlock(&wakeup_lock); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0504-rt-mutex-namespace.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0504-rt-mutex-namespace.patch @@ -0,0 +1,138 @@ +Subject: rt-mutex-namespace.patch +From: Thomas Gleixner +Date: Fri, 20 Jun 2008 12:22:52 +0200 + +Signed-off-by: Thomas Gleixner +--- + kernel/rtmutex.c | 21 ++++++++++++--------- + kernel/rtmutex_common.h | 18 ++++++++++-------- + 2 files changed, 22 insertions(+), 17 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:50.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:50.000000000 -0500 +@@ -1291,7 +1291,7 @@ try_to_take_rw_write(struct rw_mutex *rw + } + + /* +- * RT_RW_PENDING means that the lock is free, but there are ++ * RT_RWLOCK_PENDING means that the lock is free, but there are + * pending owners on the mutex + */ + WARN_ON(own && !rt_mutex_owner_pending(mutex)); +@@ -1629,7 +1629,8 @@ rt_write_fastlock(struct rw_mutex *rwm, + void fastcall (*slowfn)(struct rw_mutex *rwm, int mtx), + int mtx) + { +- struct task_struct *val = (void *)((unsigned long)current | RT_RWLOCK_WRITER); ++ struct task_struct *val = (void *)((unsigned long)current | ++ RT_RWLOCK_WRITER); + + if (likely(rt_rwlock_cmpxchg(rwm, NULL, val))) + rt_mutex_deadlock_account_lock(&rwm->mutex, current); +@@ -1669,7 +1670,8 @@ static inline int + rt_write_fasttrylock(struct rw_mutex *rwm, + int fastcall (*slowfn)(struct rw_mutex *rwm, int mtx), int mtx) + { +- struct task_struct *val = (void *)((unsigned long)current | RT_RWLOCK_WRITER); ++ struct task_struct *val = (void *)((unsigned long)current | ++ RT_RWLOCK_WRITER); + + if (likely(rt_rwlock_cmpxchg(rwm, NULL, val))) { + rt_mutex_deadlock_account_lock(&rwm->mutex, current); +@@ -1762,7 +1764,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + /* We could still have a pending reader waiting */ + if (rt_mutex_owner_pending(mutex)) { + /* set the rwm back to pending */ +- rwm->owner = RT_RW_PENDING_READ; ++ rwm->owner = RT_RWLOCK_PENDING_READ; + } else { + rwm->owner = NULL; + mutex->owner = NULL; +@@ -1783,7 +1785,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + /* only wake up if there are no readers */ + if (reader_count) + goto out; +- rwm->owner = RT_RW_PENDING_WRITE; ++ rwm->owner = RT_RWLOCK_PENDING_WRITE; + } else { + /* + * It is also possible that the reader limit decreased. +@@ -1794,7 +1796,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + unlikely(atomic_read(&rwm->owners) >= rt_rwlock_limit)) + goto out; + if (!reader_count) +- rwm->owner = RT_RW_PENDING_READ; ++ rwm->owner = RT_RWLOCK_PENDING_READ; + } + + pendowner = waiter->task; +@@ -1919,11 +1921,11 @@ rt_write_slowunlock(struct rw_mutex *rwm + + /* another writer is next? */ + if (waiter->write_lock) { +- rwm->owner = RT_RW_PENDING_WRITE; ++ rwm->owner = RT_RWLOCK_PENDING_WRITE; + goto out; + } + +- rwm->owner = RT_RW_PENDING_READ; ++ rwm->owner = RT_RWLOCK_PENDING_READ; + + if (!rt_mutex_has_waiters(mutex)) + goto out; +@@ -1999,7 +2001,8 @@ rt_write_fastunlock(struct rw_mutex *rwm + int mtx), + int mtx) + { +- struct task_struct *val = (void *)((unsigned long)current | RT_RWLOCK_WRITER); ++ struct task_struct *val = (void *)((unsigned long)current | ++ RT_RWLOCK_WRITER); + + WARN_ON(rt_rwlock_owner(rwm) != current); + if (likely(rt_rwlock_cmpxchg(rwm, (struct task_struct *)val, NULL))) +Index: linux-2.6.24.7-rt27/kernel/rtmutex_common.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex_common.h 2009-02-08 00:04:27.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex_common.h 2009-02-08 00:04:50.000000000 -0500 +@@ -123,29 +123,31 @@ static inline unsigned long rt_mutex_own + #define RT_RWLOCK_WRITER 2UL + #define RT_RWLOCK_MASKALL 3UL + +-/* used as reader owner of the mutex */ +-#define RT_RW_READER (struct task_struct *)0x100 +- + /* used when a writer releases the lock with waiters */ + /* pending owner is a reader */ +-#define RT_RW_PENDING_READ (struct task_struct *)0x200 ++#define RT_RWLOCK_PENDING_READ ((struct task_struct *)0x200) + /* pending owner is a writer */ +-#define RT_RW_PENDING_WRITE (struct task_struct *)0x400 ++#define RT_RWLOCK_PENDING_WRITE ((struct task_struct *)0x400) + /* Either of the above is true */ +-#define RT_RW_PENDING_MASK (0x600 | RT_RWLOCK_MASKALL) ++#define RT_RWLOCK_PENDING_MASK \ ++ ((unsigned long) RT_RWLOCK_PENDING_READ | \ ++ (unsigned long) RT_RWLOCK_PENDING_WRITE | RT_RWLOCK_MASKALL) ++ ++/* used as reader owner of the rt_mutex inside of the rw_mutex */ ++#define RT_RW_READER (struct task_struct *)0x100 + + /* Return true if lock is not owned but has pending owners */ + static inline int rt_rwlock_pending(struct rw_mutex *rwm) + { + unsigned long owner = (unsigned long)rwm->owner; +- return (owner & RT_RW_PENDING_MASK) == owner; ++ return (owner & RT_RWLOCK_PENDING_MASK) == owner; + } + + static inline int rt_rwlock_pending_writer(struct rw_mutex *rwm) + { + unsigned long owner = (unsigned long)rwm->owner; + return rt_rwlock_pending(rwm) && +- (owner & (unsigned long)RT_RW_PENDING_WRITE); ++ (owner & (unsigned long)RT_RWLOCK_PENDING_WRITE); + } + + static inline struct task_struct *rt_rwlock_owner(struct rw_mutex *rwm) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0362-fix-PICK_FUNCTION-spin_trylock_irq.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0362-fix-PICK_FUNCTION-spin_trylock_irq.patch @@ -0,0 +1,42 @@ +From sebastien.dugue@bull.net Thu Oct 11 11:32:58 2007 +Date: Thu, 11 Oct 2007 14:24:17 +0200 +From: "[UTF-8] Sébastien Dugué" +To: Ingo Molnar , Thomas Gleixner , + Steven Rostedt +Cc: Linux RT Users , + linux-kernel +Subject: [PATCH] RT: fix spin_trylock_irq + + [ The following text is in the "UTF-8" character set. ] + [ Your display is set for the "iso-8859-1" character set. ] + [ Some characters may be displayed incorrectly. ] + + + This patch fixes a bug in spin_trylock_irq() where __spin_trylock_irq() is +picked for regular (non-raw) spinlocks instead of _spin_trylock_irq(). + + This results in systematic boot hangs and may have been going unnoticed +for quite some time as it only manifests (aside from a compile warning) when +booting with a NUMA config or when using the Chelsio T3 (cxgb3) driver as +these seems to be the sole users. + + +Signed-off-by: Sébastien Dugué + +--- + include/linux/spinlock.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/include/linux/spinlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/spinlock.h 2009-02-08 00:03:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/spinlock.h 2009-02-08 00:03:42.000000000 -0500 +@@ -501,7 +501,7 @@ do { \ + + #define spin_trylock_irq(lock) \ + __cond_lock(lock, PICK_SPIN_OP_RET(__spin_trylock_irq, \ +- __spin_trylock_irq, lock)) ++ _spin_trylock_irq, lock)) + + #define spin_trylock_irqsave(lock, flags) \ + __cond_lock(lock, PICK_SPIN_OP_RET(__spin_trylock_irqsave, \ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0464-ftrace-trace-sched.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0464-ftrace-trace-sched.patch @@ -0,0 +1,24 @@ +From: Steven Rostedt +Subject: ftrace: trace sched.c + +The clock code has been removed to its own file "sched_clock", and that +shouldn't be traced. But we still want to trace the scheduler code. + +Signed-off-by: Steven Rostedt +--- + kernel/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/Makefile 2009-02-08 00:03:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/Makefile 2009-02-08 00:04:31.000000000 -0500 +@@ -11,7 +11,7 @@ obj-y = sched.o fork.o exec_domain.o + hrtimer.o rwsem.o latency.o nsproxy.o srcu.o \ + utsname.o notifier.o + +-CFLAGS_REMOVE_sched.o = -pg -mno-spe ++CFLAGS_REMOVE_sched.o = -mno-spe + + ifdef CONFIG_FTRACE + # Do not trace debug files and internal ftrace files --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0154-preempt-irqs-ppc-fix-b6.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0154-preempt-irqs-ppc-fix-b6.patch @@ -0,0 +1,44 @@ + + To fix the following boot time warnings by setting soft_enabled and +hard_enabled. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Freeing unused kernel memory: 248k freed +BUG: scheduling with irqs disabled: rc.sysinit/0x00000000/373 +caller is user_work+0x14/0x2c +Call Trace: +[C00000001FEC3D10] [C00000000000FAA0] .show_stack+0x68/0x1b0 (unreliable) +[C00000001FEC3DB0] [C0000000003E78DC] .schedule+0x78/0x128 +[C00000001FEC3E30] [C000000000008C40] user_work+0x14/0x2c +BUG: scheduling with irqs disabled: sed/0x00000000/378 +caller is user_work+0x14/0x2c +Call Trace: +[C00000000FA33D10] [C00000000000FAA0] .show_stack+0x68/0x1b0 (unreliable) +[C00000000FA33DB0] [C0000000003E78DC] .schedule+0x78/0x128 +[C00000000FA33E30] [C000000000008C40] user_work+0x14/0x2c + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +Signed-off-by: Tsutomu Owa +-- owa + +--- + arch/powerpc/kernel/entry_64.S | 5 +++++ + 1 file changed, 5 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_64.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/entry_64.S 2009-02-08 00:01:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_64.S 2009-02-08 00:01:55.000000000 -0500 +@@ -599,6 +599,11 @@ do_work: + + user_work: + #endif ++ /* here we are preempting the current task */ ++ li r0,1 ++ stb r0,PACASOFTIRQEN(r13) ++ stb r0,PACAHARDIRQEN(r13) ++ + /* Enable interrupts */ + ori r10,r10,MSR_EE + mtmsrd r10,1 --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0187-net-core-preempt-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0187-net-core-preempt-fix.patch @@ -0,0 +1,18 @@ +--- + net/core/dev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/net/core/dev.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/net/core/dev.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/net/core/dev.c 2009-02-08 00:02:11.000000000 -0500 +@@ -1801,8 +1801,8 @@ int netif_rx_ni(struct sk_buff *skb) + { + int err; + +- preempt_disable(); + err = netif_rx(skb); ++ preempt_disable(); + if (local_softirq_pending()) + do_softirq(); + preempt_enable(); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0192-tasklet-busy-loop-hack.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0192-tasklet-busy-loop-hack.patch @@ -0,0 +1,60 @@ +--- + include/linux/interrupt.h | 6 ++---- + kernel/softirq.c | 20 ++++++++++++++++++++ + 2 files changed, 22 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/interrupt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/interrupt.h 2009-02-08 00:02:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/interrupt.h 2009-02-08 00:02:13.000000000 -0500 +@@ -362,10 +362,8 @@ static inline void tasklet_unlock(struct + clear_bit(TASKLET_STATE_RUN, &(t)->state); + } + +-static inline void tasklet_unlock_wait(struct tasklet_struct *t) +-{ +- while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); } +-} ++extern void tasklet_unlock_wait(struct tasklet_struct *t); ++ + #else + # define tasklet_trylock(t) 1 + # define tasklet_tryunlock(t) 1 +Index: linux-2.6.24.7-rt27/kernel/softirq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/softirq.c 2009-02-08 00:02:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/softirq.c 2009-02-08 00:02:13.000000000 -0500 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -640,6 +641,25 @@ void __init softirq_init(void) + open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL); + } + ++#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT) ++ ++void tasklet_unlock_wait(struct tasklet_struct *t) ++{ ++ while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { ++ /* ++ * Hack for now to avoid this busy-loop: ++ */ ++#ifdef CONFIG_PREEMPT_RT ++ msleep(1); ++#else ++ barrier(); ++#endif ++ } ++} ++EXPORT_SYMBOL(tasklet_unlock_wait); ++ ++#endif ++ + static int ksoftirqd(void * __data) + { + struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2 }; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0073-powerpc-add-ftrace.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0073-powerpc-add-ftrace.patch @@ -0,0 +1,552 @@ +--- + arch/powerpc/Kconfig | 1 + arch/powerpc/kernel/Makefile | 14 ++ + arch/powerpc/kernel/entry_32.S | 130 ++++++++++++++++++++++++ + arch/powerpc/kernel/entry_64.S | 62 +++++++++++ + arch/powerpc/kernel/ftrace.c | 165 +++++++++++++++++++++++++++++++ + arch/powerpc/kernel/io.c | 3 + arch/powerpc/kernel/irq.c | 6 - + arch/powerpc/kernel/setup_32.c | 11 +- + arch/powerpc/kernel/setup_64.c | 5 + arch/powerpc/platforms/powermac/Makefile | 5 + 10 files changed, 395 insertions(+), 7 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/Kconfig 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/Kconfig 2009-02-08 00:01:17.000000000 -0500 +@@ -79,6 +79,7 @@ config ARCH_NO_VIRT_TO_BUS + config PPC + bool + default y ++ select HAVE_FTRACE + + config EARLY_PRINTK + bool +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/Makefile 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/Makefile 2009-02-08 00:01:17.000000000 -0500 +@@ -10,6 +10,18 @@ CFLAGS_prom_init.o += -fPIC + CFLAGS_btext.o += -fPIC + endif + ++ifdef CONFIG_FTRACE ++# Do not trace early boot code ++CFLAGS_REMOVE_cputable.o = -pg ++CFLAGS_REMOVE_prom_init.o = -pg ++ ++ifdef CONFIG_DYNAMIC_FTRACE ++# dynamic ftrace setup. ++CFLAGS_REMOVE_ftrace.o = -pg ++endif ++ ++endif ++ + obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ + irq.o align.o signal_32.o pmc.o vdso.o \ + init_task.o process.o systbl.o idle.o \ +@@ -75,6 +87,8 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o + obj-$(CONFIG_AUDIT) += audit.o + obj64-$(CONFIG_AUDIT) += compat_audit.o + ++obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o ++ + obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o + + ifneq ($(CONFIG_PPC_INDIRECT_IO),y) +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_32.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/entry_32.S 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_32.S 2009-02-08 00:01:17.000000000 -0500 +@@ -1022,3 +1022,133 @@ machine_check_in_rtas: + /* XXX load up BATs and panic */ + + #endif /* CONFIG_PPC_RTAS */ ++ ++#ifdef CONFIG_FTRACE ++#ifdef CONFIG_DYNAMIC_FTRACE ++_GLOBAL(mcount) ++_GLOBAL(_mcount) ++ stwu r1,-48(r1) ++ stw r3, 12(r1) ++ stw r4, 16(r1) ++ stw r5, 20(r1) ++ stw r6, 24(r1) ++ mflr r3 ++ stw r7, 28(r1) ++ mfcr r5 ++ stw r8, 32(r1) ++ stw r9, 36(r1) ++ stw r10,40(r1) ++ stw r3, 44(r1) ++ stw r5, 8(r1) ++ .globl mcount_call ++mcount_call: ++ bl ftrace_stub ++ nop ++ lwz r6, 8(r1) ++ lwz r0, 44(r1) ++ lwz r3, 12(r1) ++ mtctr r0 ++ lwz r4, 16(r1) ++ mtcr r6 ++ lwz r5, 20(r1) ++ lwz r6, 24(r1) ++ lwz r0, 52(r1) ++ lwz r7, 28(r1) ++ lwz r8, 32(r1) ++ mtlr r0 ++ lwz r9, 36(r1) ++ lwz r10,40(r1) ++ addi r1, r1, 48 ++ bctr ++ ++_GLOBAL(ftrace_caller) ++ /* Based off of objdump optput from glibc */ ++ stwu r1,-48(r1) ++ stw r3, 12(r1) ++ stw r4, 16(r1) ++ stw r5, 20(r1) ++ stw r6, 24(r1) ++ mflr r3 ++ lwz r4, 52(r1) ++ mfcr r5 ++ stw r7, 28(r1) ++ stw r8, 32(r1) ++ stw r9, 36(r1) ++ stw r10,40(r1) ++ stw r3, 44(r1) ++ stw r5, 8(r1) ++.globl ftrace_call ++ftrace_call: ++ bl ftrace_stub ++ nop ++ lwz r6, 8(r1) ++ lwz r0, 44(r1) ++ lwz r3, 12(r1) ++ mtctr r0 ++ lwz r4, 16(r1) ++ mtcr r6 ++ lwz r5, 20(r1) ++ lwz r6, 24(r1) ++ lwz r0, 52(r1) ++ lwz r7, 28(r1) ++ lwz r8, 32(r1) ++ mtlr r0 ++ lwz r9, 36(r1) ++ lwz r10,40(r1) ++ addi r1, r1, 48 ++ bctr ++#else ++_GLOBAL(mcount) ++_GLOBAL(_mcount) ++ stwu r1,-48(r1) ++ stw r3, 12(r1) ++ stw r4, 16(r1) ++ stw r5, 20(r1) ++ stw r6, 24(r1) ++ mflr r3 ++ lwz r4, 52(r1) ++ mfcr r5 ++ stw r7, 28(r1) ++ stw r8, 32(r1) ++ stw r9, 36(r1) ++ stw r10,40(r1) ++ stw r3, 44(r1) ++ stw r5, 8(r1) ++ ++ LOAD_REG_ADDR(r5, ftrace_trace_function) ++#if 0 ++ mtctr r3 ++ mr r1, r5 ++ bctrl ++#endif ++ lwz r5,0(r5) ++#if 1 ++ mtctr r5 ++ bctrl ++#else ++ bl ftrace_stub ++#endif ++ nop ++ ++ lwz r6, 8(r1) ++ lwz r0, 44(r1) ++ lwz r3, 12(r1) ++ mtctr r0 ++ lwz r4, 16(r1) ++ mtcr r6 ++ lwz r5, 20(r1) ++ lwz r6, 24(r1) ++ lwz r0, 52(r1) ++ lwz r7, 28(r1) ++ lwz r8, 32(r1) ++ mtlr r0 ++ lwz r9, 36(r1) ++ lwz r10,40(r1) ++ addi r1, r1, 48 ++ bctr ++#endif ++ ++_GLOBAL(ftrace_stub) ++ blr ++ ++#endif /* CONFIG_MCOUNT */ +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_64.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/entry_64.S 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_64.S 2009-02-08 00:01:17.000000000 -0500 +@@ -846,3 +846,65 @@ _GLOBAL(enter_prom) + ld r0,16(r1) + mtlr r0 + blr ++ ++#ifdef CONFIG_FTRACE ++#ifdef CONFIG_DYNAMIC_FTRACE ++_GLOBAL(mcount) ++_GLOBAL(_mcount) ++ /* Taken from output of objdump from lib64/glibc */ ++ mflr r3 ++ stdu r1, -112(r1) ++ std r3, 128(r1) ++ .globl mcount_call ++mcount_call: ++ bl ftrace_stub ++ nop ++ ld r0, 128(r1) ++ mtlr r0 ++ addi r1, r1, 112 ++ blr ++ ++_GLOBAL(ftrace_caller) ++ /* Taken from output of objdump from lib64/glibc */ ++ mflr r3 ++ ld r11, 0(r1) ++ stdu r1, -112(r1) ++ std r3, 128(r1) ++ ld r4, 16(r11) ++.globl ftrace_call ++ftrace_call: ++ bl ftrace_stub ++ nop ++ ld r0, 128(r1) ++ mtlr r0 ++ addi r1, r1, 112 ++_GLOBAL(ftrace_stub) ++ blr ++#else ++_GLOBAL(mcount) ++ blr ++ ++_GLOBAL(_mcount) ++ /* Taken from output of objdump from lib64/glibc */ ++ mflr r3 ++ ld r11, 0(r1) ++ stdu r1, -112(r1) ++ std r3, 128(r1) ++ ld r4, 16(r11) ++ ++ ++ LOAD_REG_ADDR(r5,ftrace_trace_function) ++ ld r5,0(r5) ++ ld r5,0(r5) ++ mtctr r5 ++ bctrl ++ ++ nop ++ ld r0, 128(r1) ++ mtlr r0 ++ addi r1, r1, 112 ++_GLOBAL(ftrace_stub) ++ blr ++ ++#endif ++#endif +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/ftrace.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/ftrace.c 2009-02-08 00:01:17.000000000 -0500 +@@ -0,0 +1,165 @@ ++/* ++ * Code for replacing ftrace calls with jumps. ++ * ++ * Copyright (C) 2007-2008 Steven Rostedt ++ * ++ * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define CALL_BACK 4 ++ ++static unsigned int ftrace_nop = 0x60000000; ++ ++#ifdef CONFIG_PPC32 ++# define GET_ADDR(addr) addr ++#else ++/* PowerPC64's functions are data that points to the functions */ ++# define GET_ADDR(addr) *(unsigned long *)addr ++#endif ++ ++notrace int ftrace_ip_converted(unsigned long ip) ++{ ++ unsigned int save; ++ ++ ip -= CALL_BACK; ++ save = *(unsigned int *)ip; ++ ++ return save == ftrace_nop; ++} ++ ++static unsigned int notrace ftrace_calc_offset(long ip, long addr) ++{ ++ return (int)((addr + CALL_BACK) - ip); ++} ++ ++notrace unsigned char *ftrace_nop_replace(void) ++{ ++ return (char *)&ftrace_nop; ++} ++ ++notrace unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) ++{ ++ static unsigned int op; ++ ++ addr = GET_ADDR(addr); ++ ++ /* Set to "bl addr" */ ++ op = 0x48000001 | (ftrace_calc_offset(ip, addr) & 0x03fffffe); ++ ++ /* ++ * No locking needed, this must be called via kstop_machine ++ * which in essence is like running on a uniprocessor machine. ++ */ ++ return (unsigned char *)&op; ++} ++ ++#ifdef CONFIG_PPC64 ++# define _ASM_ALIGN " .align 3 " ++# define _ASM_PTR " .llong " ++#else ++# define _ASM_ALIGN " .align 2 " ++# define _ASM_PTR " .long " ++#endif ++ ++notrace int ++ftrace_modify_code(unsigned long ip, unsigned char *old_code, ++ unsigned char *new_code) ++{ ++ unsigned replaced; ++ unsigned old = *(unsigned *)old_code; ++ unsigned new = *(unsigned *)new_code; ++ int faulted = 0; ++ ++ /* move the IP back to the start of the call */ ++ ip -= CALL_BACK; ++ ++ /* ++ * Note: Due to modules and __init, code can ++ * disappear and change, we need to protect against faulting ++ * as well as code changing. ++ * ++ * No real locking needed, this code is run through ++ * kstop_machine. ++ */ ++ asm volatile ( ++ "1: lwz %1, 0(%2)\n" ++ " cmpw %1, %5\n" ++ " bne 2f\n" ++ " stwu %3, 0(%2)\n" ++ "2:\n" ++ ".section .fixup, \"ax\"\n" ++ "3: li %0, 1\n" ++ " b 2b\n" ++ ".previous\n" ++ ".section __ex_table,\"a\"\n" ++ _ASM_ALIGN "\n" ++ _ASM_PTR "1b, 3b\n" ++ ".previous" ++ : "=r"(faulted), "=r"(replaced) ++ : "r"(ip), "r"(new), ++ "0"(faulted), "r"(old) ++ : "memory"); ++ ++ if (replaced != old && replaced != new) ++ faulted = 2; ++ ++ if (!faulted) ++ flush_icache_range(ip, ip + 8); ++ ++ return faulted; ++} ++ ++notrace int ftrace_update_ftrace_func(ftrace_func_t func) ++{ ++ unsigned long ip = (unsigned long)(&ftrace_call); ++ unsigned char old[4], *new; ++ int ret; ++ ++ ip += CALL_BACK; ++ ++ memcpy(old, &ftrace_call, 4); ++ new = ftrace_call_replace(ip, (unsigned long)func); ++ ret = ftrace_modify_code(ip, old, new); ++ ++ return ret; ++} ++ ++notrace int ftrace_mcount_set(unsigned long *data) ++{ ++ unsigned long ip = (long)(&mcount_call); ++ unsigned long *addr = data; ++ unsigned char old[4], *new; ++ ++ /* ip is at the location, but modify code will subtact this */ ++ ip += CALL_BACK; ++ ++ /* ++ * Replace the mcount stub with a pointer to the ++ * ip recorder function. ++ */ ++ memcpy(old, &mcount_call, 4); ++ new = ftrace_call_replace(ip, *addr); ++ *addr = ftrace_modify_code(ip, old, new); ++ ++ return 0; ++} ++ ++int __init ftrace_dyn_arch_init(void *data) ++{ ++ /* This is running in kstop_machine */ ++ ++ ftrace_mcount_set(data); ++ ++ return 0; ++} ++ +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/io.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/io.c 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/io.c 2009-02-08 00:01:17.000000000 -0500 +@@ -120,7 +120,8 @@ EXPORT_SYMBOL(_outsl_ns); + + #define IO_CHECK_ALIGN(v,a) ((((unsigned long)(v)) & ((a) - 1)) == 0) + +-void _memset_io(volatile void __iomem *addr, int c, unsigned long n) ++notrace void ++_memset_io(volatile void __iomem *addr, int c, unsigned long n) + { + void *p = (void __force *)addr; + u32 lc = c; +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/irq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/irq.c 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/irq.c 2009-02-08 00:01:17.000000000 -0500 +@@ -98,7 +98,7 @@ EXPORT_SYMBOL(irq_desc); + + int distribute_irqs = 1; + +-static inline unsigned long get_hard_enabled(void) ++static inline notrace unsigned long get_hard_enabled(void) + { + unsigned long enabled; + +@@ -108,13 +108,13 @@ static inline unsigned long get_hard_ena + return enabled; + } + +-static inline void set_soft_enabled(unsigned long enable) ++static inline notrace void set_soft_enabled(unsigned long enable) + { + __asm__ __volatile__("stb %0,%1(13)" + : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); + } + +-void local_irq_restore(unsigned long en) ++notrace void local_irq_restore(unsigned long en) + { + /* + * get_paca()->soft_enabled = en; +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/setup_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/setup_32.c 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/setup_32.c 2009-02-08 00:01:17.000000000 -0500 +@@ -49,6 +49,11 @@ + #include + #endif + ++#ifdef CONFIG_FTRACE ++extern void _mcount(void); ++EXPORT_SYMBOL(_mcount); ++#endif ++ + extern void bootx_init(unsigned long r4, unsigned long phys); + + #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +@@ -88,7 +93,7 @@ int ucache_bsize; + * from the address that it was linked at, so we must use RELOC/PTRRELOC + * to access static data (including strings). -- paulus + */ +-unsigned long __init early_init(unsigned long dt_ptr) ++notrace unsigned long __init early_init(unsigned long dt_ptr) + { + unsigned long offset = reloc_offset(); + struct cpu_spec *spec; +@@ -118,7 +123,7 @@ unsigned long __init early_init(unsigned + * This is called very early on the boot process, after a minimal + * MMU environment has been set up but before MMU_init is called. + */ +-void __init machine_init(unsigned long dt_ptr, unsigned long phys) ++notrace void __init machine_init(unsigned long dt_ptr, unsigned long phys) + { + /* Enable early debugging if any specified (see udbg.h) */ + udbg_early_init(); +@@ -140,7 +145,7 @@ void __init machine_init(unsigned long d + + #ifdef CONFIG_BOOKE_WDT + /* Checks wdt=x and wdt_period=xx command-line option */ +-int __init early_parse_wdt(char *p) ++notrace int __init early_parse_wdt(char *p) + { + if (p && strncmp(p, "0", 1) != 0) + booke_wdt_enabled = 1; +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/setup_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/setup_64.c 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/setup_64.c 2009-02-08 00:01:17.000000000 -0500 +@@ -84,6 +84,11 @@ struct ppc64_caches ppc64_caches = { + }; + EXPORT_SYMBOL_GPL(ppc64_caches); + ++#ifdef CONFIG_FTRACE ++extern void _mcount(void); ++EXPORT_SYMBOL(_mcount); ++#endif ++ + /* + * These are used in binfmt_elf.c to put aux entries on the stack + * for each elf executable being started. +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/powermac/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/powermac/Makefile 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/powermac/Makefile 2009-02-08 00:01:17.000000000 -0500 +@@ -1,5 +1,10 @@ + CFLAGS_bootx_init.o += -fPIC + ++ifdef CONFIG_FTRACE ++# Do not trace early boot code ++CFLAGS_REMOVE_bootx_init.o = -pg ++endif ++ + obj-y += pic.o setup.o time.o feature.o pci.o \ + sleep.o low_i2c.o cache.o pfunc_core.o \ + pfunc_base.o --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0379-rt-workqeue-prio.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0379-rt-workqeue-prio.patch @@ -0,0 +1,212 @@ +Subject: rt: PI-workqueue support +From: Daniel Walker + +Add support for priority queueing and priority inheritance to the workqueue +infrastructure. This is done by replacing the linear linked worklist with a +priority sorted plist. + +The drawback is that this breaks the workqueue barrier, needed to support +flush_workqueue() and wait_on_work(). + +Signed-off-by: Daniel Walker +Signed-off-by: Peter Zijlstra +--- + include/linux/workqueue.h | 9 +++++---- + kernel/power/poweroff.c | 1 + + kernel/workqueue.c | 40 +++++++++++++++++++++++++--------------- + 3 files changed, 31 insertions(+), 19 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/workqueue.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/workqueue.h 2009-02-08 00:03:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/workqueue.h 2009-02-08 00:03:51.000000000 -0500 +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + + struct workqueue_struct; +@@ -27,7 +28,7 @@ struct work_struct { + #define WORK_STRUCT_PENDING 0 /* T if work item pending execution */ + #define WORK_STRUCT_FLAG_MASK (3UL) + #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK) +- struct list_head entry; ++ struct plist_node entry; + work_func_t func; + #ifdef CONFIG_LOCKDEP + struct lockdep_map lockdep_map; +@@ -59,7 +60,7 @@ struct execute_work { + + #define __WORK_INITIALIZER(n, f) { \ + .data = WORK_DATA_INIT(), \ +- .entry = { &(n).entry, &(n).entry }, \ ++ .entry = PLIST_NODE_INIT(n.entry, MAX_PRIO), \ + .func = (f), \ + __WORK_INIT_LOCKDEP_MAP(#n, &(n)) \ + } +@@ -100,14 +101,14 @@ struct execute_work { + \ + (_work)->data = (atomic_long_t) WORK_DATA_INIT(); \ + lockdep_init_map(&(_work)->lockdep_map, #_work, &__key, 0);\ +- INIT_LIST_HEAD(&(_work)->entry); \ ++ plist_node_init(&(_work)->entry, -1); \ + PREPARE_WORK((_work), (_func)); \ + } while (0) + #else + #define INIT_WORK(_work, _func) \ + do { \ + (_work)->data = (atomic_long_t) WORK_DATA_INIT(); \ +- INIT_LIST_HEAD(&(_work)->entry); \ ++ plist_node_init(&(_work)->entry, -1); \ + PREPARE_WORK((_work), (_func)); \ + } while (0) + #endif +Index: linux-2.6.24.7-rt27/kernel/power/poweroff.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/power/poweroff.c 2009-02-07 23:59:46.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/power/poweroff.c 2009-02-08 00:03:51.000000000 -0500 +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + +Index: linux-2.6.24.7-rt27/kernel/workqueue.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/workqueue.c 2009-02-08 00:03:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/workqueue.c 2009-02-08 00:03:51.000000000 -0500 +@@ -45,7 +45,7 @@ struct cpu_workqueue_struct { + + spinlock_t lock; + +- struct list_head worklist; ++ struct plist_head worklist; + wait_queue_head_t more_work; + struct work_struct *current_work; + +@@ -131,16 +131,19 @@ struct cpu_workqueue_struct *get_wq_data + static void insert_work(struct cpu_workqueue_struct *cwq, + struct work_struct *work, int tail) + { ++ int prio = current->normal_prio; ++ + set_wq_data(work, cwq); + /* + * Ensure that we get the right work->data if we see the + * result of list_add() below, see try_to_grab_pending(). + */ + smp_wmb(); +- if (tail) +- list_add_tail(&work->entry, &cwq->worklist); +- else +- list_add(&work->entry, &cwq->worklist); ++ plist_node_init(&work->entry, prio); ++ plist_add(&work->entry, &cwq->worklist); ++ ++ if (prio < cwq->thread->prio) ++ task_setprio(cwq->thread, prio); + wake_up(&cwq->more_work); + } + +@@ -172,7 +175,7 @@ int fastcall queue_work(struct workqueue + int ret = 0, cpu = raw_smp_processor_id(); + + if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) { +- BUG_ON(!list_empty(&work->entry)); ++ BUG_ON(!plist_node_empty(&work->entry)); + __queue_work(wq_per_cpu(wq, cpu), work); + ret = 1; + } +@@ -226,7 +229,7 @@ int queue_delayed_work_on(int cpu, struc + + if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) { + BUG_ON(timer_pending(timer)); +- BUG_ON(!list_empty(&work->entry)); ++ BUG_ON(!plist_node_empty(&work->entry)); + + /* This stores cwq for the moment, for the timer_fn */ + set_wq_data(work, wq_per_cpu(wq, raw_smp_processor_id())); +@@ -268,8 +271,8 @@ static void run_workqueue(struct cpu_wor + __FUNCTION__, cwq->run_depth); + dump_stack(); + } +- while (!list_empty(&cwq->worklist)) { +- struct work_struct *work = list_entry(cwq->worklist.next, ++ while (!plist_head_empty(&cwq->worklist)) { ++ struct work_struct *work = plist_first_entry(&cwq->worklist, + struct work_struct, entry); + work_func_t f = work->func; + #ifdef CONFIG_LOCKDEP +@@ -284,8 +287,12 @@ static void run_workqueue(struct cpu_wor + struct lockdep_map lockdep_map = work->lockdep_map; + #endif + ++ if (likely(cwq->thread->prio != work->entry.prio)) ++ task_setprio(cwq->thread, work->entry.prio); ++ + cwq->current_work = work; +- list_del_init(cwq->worklist.next); ++ plist_del(&work->entry, &cwq->worklist); ++ plist_node_init(&work->entry, MAX_PRIO); + spin_unlock_irq(&cwq->lock); + + BUG_ON(get_wq_data(work) != cwq); +@@ -301,6 +308,7 @@ static void run_workqueue(struct cpu_wor + spin_lock_irq(&cwq->lock); + cwq->current_work = NULL; + } ++ task_setprio(cwq->thread, current->normal_prio); + cwq->run_depth--; + spin_unlock_irq(&cwq->lock); + } +@@ -319,7 +327,7 @@ static int worker_thread(void *__cwq) + prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE); + if (!freezing(current) && + !kthread_should_stop() && +- list_empty(&cwq->worklist)) ++ plist_head_empty(&cwq->worklist)) + schedule(); + finish_wait(&cwq->more_work, &wait); + +@@ -372,7 +380,8 @@ static int flush_cpu_workqueue(struct cp + + active = 0; + spin_lock_irq(&cwq->lock); +- if (!list_empty(&cwq->worklist) || cwq->current_work != NULL) { ++ if (!plist_head_empty(&cwq->worklist) || ++ cwq->current_work != NULL) { + insert_wq_barrier(cwq, &barr, 1); + active = 1; + } +@@ -433,7 +442,7 @@ static int try_to_grab_pending(struct wo + return ret; + + spin_lock_irq(&cwq->lock); +- if (!list_empty(&work->entry)) { ++ if (!plist_node_empty(&work->entry)) { + /* + * This work is queued, but perhaps we locked the wrong cwq. + * In that case we must see the new value after rmb(), see +@@ -441,7 +450,8 @@ static int try_to_grab_pending(struct wo + */ + smp_rmb(); + if (cwq == get_wq_data(work)) { +- list_del_init(&work->entry); ++ plist_del(&work->entry, &cwq->worklist); ++ plist_node_init(&work->entry, MAX_PRIO); + ret = 1; + } + } +@@ -770,7 +780,7 @@ init_cpu_workqueue(struct workqueue_stru + + cwq->wq = wq; + spin_lock_init(&cwq->lock); +- INIT_LIST_HEAD(&cwq->worklist); ++ plist_head_init(&cwq->worklist, NULL); + init_waitqueue_head(&cwq->more_work); + + return cwq; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0326-REFRESHED-print-might-sleep-hack.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0326-REFRESHED-print-might-sleep-hack.patch @@ -0,0 +1,79 @@ +Temporary HACK!!!! + +PREEMPT_RT suffers from the on going problem of running +printk in atomic operations. It is very advantageous to do so +but with PREEMPT_RT making spin_locks sleep, it can also be +devastating. + +This patch does not solve the problem of printk sleeping in +an atomic operation. This patch just makes printk not report +that it is. Of course if printk does report that it's sleeping +in an atomic operation, then that printing of the report will +also print a report, and you go into recursive hell. + +We need to really sit down and solve the real issue here. + +--- + include/linux/sched.h | 13 +++++++++++++ + kernel/printk.c | 5 ++++- + kernel/rtmutex.c | 4 +++- + 3 files changed, 20 insertions(+), 2 deletions(-) + +Index: ubuntu-hardy/include/linux/sched.h +=================================================================== +--- ubuntu-hardy.orig/include/linux/sched.h 2009-02-23 15:20:06.000000000 +0100 ++++ ubuntu-hardy/include/linux/sched.h 2009-02-23 15:21:28.000000000 +0100 +@@ -1301,8 +1301,21 @@ + struct latency_record latency_record[LT_SAVECOUNT]; + #endif + struct list_head *scm_work_list; ++#ifdef CONFIG_PREEMPT_RT ++ /* ++ * Temporary hack, until we find a solution to ++ * handle printk in atomic operations. ++ */ ++ int in_printk; ++#endif + }; + ++#ifdef CONFIG_PREEMPT_RT ++# define set_printk_might_sleep(x) do { current->in_printk = x; } while(0) ++#else ++# define set_printk_might_sleep(x) do { } while(0) ++#endif ++ + /* + * Priority of a process goes from 0..MAX_PRIO-1, valid RT + * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH +Index: ubuntu-hardy/kernel/printk.c +=================================================================== +--- ubuntu-hardy.orig/kernel/printk.c 2009-02-23 15:20:04.000000000 +0100 ++++ ubuntu-hardy/kernel/printk.c 2009-02-23 15:20:12.000000000 +0100 +@@ -436,8 +436,11 @@ + for (con = console_drivers; con; con = con->next) { + if ((con->flags & CON_ENABLED) && con->write && + (cpu_online(raw_smp_processor_id()) || +- (con->flags & CON_ANYTIME))) ++ (con->flags & CON_ANYTIME))) { ++ set_printk_might_sleep(1); + con->write(con, &LOG_BUF(start), end - start); ++ set_printk_might_sleep(0); ++ } + } + } + +Index: ubuntu-hardy/kernel/rtmutex.c +=================================================================== +--- ubuntu-hardy.orig/kernel/rtmutex.c 2009-02-23 15:19:58.000000000 +0100 ++++ ubuntu-hardy/kernel/rtmutex.c 2009-02-23 15:20:12.000000000 +0100 +@@ -631,7 +631,9 @@ + rt_spin_lock_fastlock(struct rt_mutex *lock, + void fastcall (*slowfn)(struct rt_mutex *lock)) + { +- might_sleep(); ++ /* Temporary HACK! */ ++ if (!current->in_printk) ++ might_sleep(); + + if (likely(rt_mutex_cmpxchg(lock, NULL, current))) + rt_mutex_deadlock_account_lock(lock, current); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0074-powerpc-ftrace-cleanups.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0074-powerpc-ftrace-cleanups.patch @@ -0,0 +1,122 @@ +--- + arch/powerpc/kernel/entry_32.S | 11 ++--------- + arch/powerpc/kernel/ftrace.c | 8 +++++++- + arch/powerpc/kernel/ppc_ksyms.c | 5 +++++ + arch/powerpc/kernel/setup_32.c | 5 ----- + arch/powerpc/kernel/setup_64.c | 5 ----- + include/asm-powerpc/ftrace.h | 6 ++++++ + 6 files changed, 20 insertions(+), 20 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_32.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/entry_32.S 2009-02-08 00:01:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_32.S 2009-02-08 00:01:18.000000000 -0500 +@@ -1116,18 +1116,11 @@ _GLOBAL(_mcount) + stw r5, 8(r1) + + LOAD_REG_ADDR(r5, ftrace_trace_function) +-#if 0 +- mtctr r3 +- mr r1, r5 +- bctrl +-#endif + lwz r5,0(r5) +-#if 1 ++ + mtctr r5 + bctrl +-#else +- bl ftrace_stub +-#endif ++ + nop + + lwz r6, 8(r1) +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/ftrace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/ftrace.c 2009-02-08 00:01:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/ftrace.c 2009-02-08 00:01:18.000000000 -0500 +@@ -51,10 +51,16 @@ notrace unsigned char *ftrace_call_repla + { + static unsigned int op; + ++ /* ++ * It would be nice to just use create_function_call, but that will ++ * update the code itself. Here we need to just return the ++ * instruction that is going to be modified, without modifying the ++ * code. ++ */ + addr = GET_ADDR(addr); + + /* Set to "bl addr" */ +- op = 0x48000001 | (ftrace_calc_offset(ip, addr) & 0x03fffffe); ++ op = 0x48000001 | (ftrace_calc_offset(ip, addr) & 0x03fffffc); + + /* + * No locking needed, this must be called via kstop_machine +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/ppc_ksyms.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/ppc_ksyms.c 2009-02-08 00:00:24.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/ppc_ksyms.c 2009-02-08 00:01:18.000000000 -0500 +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_PPC64 + EXPORT_SYMBOL(local_irq_restore); +@@ -72,6 +73,10 @@ EXPORT_SYMBOL(single_step_exception); + EXPORT_SYMBOL(sys_sigreturn); + #endif + ++#ifdef CONFIG_FTRACE ++EXPORT_SYMBOL(_mcount); ++#endif ++ + EXPORT_SYMBOL(strcpy); + EXPORT_SYMBOL(strncpy); + EXPORT_SYMBOL(strcat); +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/setup_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/setup_32.c 2009-02-08 00:01:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/setup_32.c 2009-02-08 00:01:18.000000000 -0500 +@@ -49,11 +49,6 @@ + #include + #endif + +-#ifdef CONFIG_FTRACE +-extern void _mcount(void); +-EXPORT_SYMBOL(_mcount); +-#endif +- + extern void bootx_init(unsigned long r4, unsigned long phys); + + #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/setup_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/setup_64.c 2009-02-08 00:01:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/setup_64.c 2009-02-08 00:01:18.000000000 -0500 +@@ -84,11 +84,6 @@ struct ppc64_caches ppc64_caches = { + }; + EXPORT_SYMBOL_GPL(ppc64_caches); + +-#ifdef CONFIG_FTRACE +-extern void _mcount(void); +-EXPORT_SYMBOL(_mcount); +-#endif +- + /* + * These are used in binfmt_elf.c to put aux entries on the stack + * for each elf executable being started. +Index: linux-2.6.24.7-rt27/include/asm-powerpc/ftrace.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/include/asm-powerpc/ftrace.h 2009-02-08 00:01:18.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef _ASM_POWERPC_FTRACE ++#define _ASM_POWERPC_FTRACE ++ ++extern void _mcount(void); ++ ++#endif --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0128-rcu-dynticks-update.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0128-rcu-dynticks-update.patch @@ -0,0 +1,121 @@ +--- + include/linux/hardirq.h | 10 ++++++++++ + include/linux/rcuclassic.h | 2 ++ + include/linux/rcupreempt.h | 22 ++++++++++++++++++++++ + kernel/softirq.c | 1 + + kernel/time/tick-sched.c | 3 +++ + 5 files changed, 38 insertions(+) + +Index: linux-2.6.24.7-rt27/include/linux/hardirq.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/hardirq.h 2009-02-08 00:00:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/hardirq.h 2009-02-08 00:01:43.000000000 -0500 +@@ -113,6 +113,14 @@ static inline void account_system_vtime( + } + #endif + ++#if defined(CONFIG_PREEMPT_RCU) && defined(CONFIG_NO_HZ) ++extern void rcu_irq_enter(void); ++extern void rcu_irq_exit(void); ++#else ++# define rcu_irq_enter() do { } while (0) ++# define rcu_irq_exit() do { } while (0) ++#endif /* CONFIG_PREEMPT_RCU */ ++ + /* + * It is safe to do non-atomic ops on ->hardirq_context, + * because NMI handlers may not preempt and the ops are +@@ -121,6 +129,7 @@ static inline void account_system_vtime( + */ + #define __irq_enter() \ + do { \ ++ rcu_irq_enter(); \ + account_system_vtime(current); \ + add_preempt_count(HARDIRQ_OFFSET); \ + trace_hardirq_enter(); \ +@@ -139,6 +148,7 @@ extern void irq_enter(void); + trace_hardirq_exit(); \ + account_system_vtime(current); \ + sub_preempt_count(HARDIRQ_OFFSET); \ ++ rcu_irq_exit(); \ + } while (0) + + /* +Index: linux-2.6.24.7-rt27/include/linux/rcuclassic.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcuclassic.h 2009-02-08 00:01:41.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcuclassic.h 2009-02-08 00:01:43.000000000 -0500 +@@ -86,6 +86,8 @@ static inline void rcu_bh_qsctr_inc(int + #define rcu_online_cpu_rt(cpu) + #define rcu_pending_rt(cpu) 0 + #define rcu_process_callbacks_rt(unused) do { } while (0) ++#define rcu_enter_nohz() do { } while (0) ++#define rcu_exit_nohz() do { } while (0) + + extern void FASTCALL(call_rcu_classic(struct rcu_head *head, + void (*func)(struct rcu_head *head))); +Index: linux-2.6.24.7-rt27/include/linux/rcupreempt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupreempt.h 2009-02-08 00:01:41.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupreempt.h 2009-02-08 00:01:43.000000000 -0500 +@@ -77,5 +77,27 @@ extern struct rcupreempt_trace *rcupreem + + struct softirq_action; + ++#ifdef CONFIG_NO_HZ ++DECLARE_PER_CPU(long, dynticks_progress_counter); ++ ++static inline void rcu_enter_nohz(void) ++{ ++ __get_cpu_var(dynticks_progress_counter)++; ++ WARN_ON(__get_cpu_var(dynticks_progress_counter) & 0x1); ++ mb(); ++} ++ ++static inline void rcu_exit_nohz(void) ++{ ++ mb(); ++ __get_cpu_var(dynticks_progress_counter)++; ++ WARN_ON(!(__get_cpu_var(dynticks_progress_counter) & 0x1)); ++} ++ ++#else /* CONFIG_NO_HZ */ ++#define rcu_enter_nohz() do { } while (0) ++#define rcu_exit_nohz() do { } while (0) ++#endif /* CONFIG_NO_HZ */ ++ + #endif /* __KERNEL__ */ + #endif /* __LINUX_RCUPREEMPT_H */ +Index: linux-2.6.24.7-rt27/kernel/softirq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/softirq.c 2009-02-08 00:00:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/softirq.c 2009-02-08 00:01:43.000000000 -0500 +@@ -306,6 +306,7 @@ void irq_exit(void) + /* Make sure that timer wheel updates are propagated */ + if (!in_interrupt() && idle_cpu(smp_processor_id()) && !need_resched()) + tick_nohz_stop_sched_tick(); ++ rcu_irq_exit(); + #endif + preempt_enable_no_resched(); + } +Index: linux-2.6.24.7-rt27/kernel/time/tick-sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-sched.c 2009-02-08 00:01:32.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-sched.c 2009-02-08 00:01:43.000000000 -0500 +@@ -249,6 +249,7 @@ void tick_nohz_stop_sched_tick(void) + ts->idle_tick = ts->sched_timer.expires; + ts->tick_stopped = 1; + ts->idle_jiffies = last_jiffies; ++ rcu_enter_nohz(); + } + + /* +@@ -337,6 +338,8 @@ void tick_nohz_restart_sched_tick(void) + if (!ts->tick_stopped) + return; + ++ rcu_exit_nohz(); ++ + /* Update jiffies first */ + now = ktime_get(); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0149-preempt-irqs-arm.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0149-preempt-irqs-arm.patch @@ -0,0 +1,17 @@ +--- + arch/arm/common/time-acorn.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/arm/common/time-acorn.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/common/time-acorn.c 2009-02-08 00:00:14.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/common/time-acorn.c 2009-02-08 00:01:53.000000000 -0500 +@@ -77,7 +77,7 @@ ioc_timer_interrupt(int irq, void *dev_i + + static struct irqaction ioc_timer_irq = { + .name = "timer", +- .flags = IRQF_DISABLED, ++ .flags = IRQF_DISABLED | IRQF_NODELAY, + .handler = ioc_timer_interrupt + }; + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0565-rtmutex-tglx-is-a-moron.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0565-rtmutex-tglx-is-a-moron.patch @@ -0,0 +1,29 @@ +Subject: rtmutex-tglx-is-a-moron.patch +From: Thomas Gleixner +Date: Wed, 10 Dec 2008 12:36:37 +0100 + +Signed-off-by: Thomas Gleixner +--- + kernel/rtmutex.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:05:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:05:20.000000000 -0500 +@@ -2140,12 +2140,13 @@ static int rt_mutex_adjust_readers(struc + int chain_walk = 0; + + task = rls->task; +- get_task_struct(task); + + spin_lock(&task->pi_lock); + __rt_mutex_adjust_prio(task); +- if (task->pi_blocked_on) ++ if (task->pi_blocked_on) { + chain_walk = 1; ++ get_task_struct(task); ++ } + spin_unlock(&task->pi_lock); + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0164-rt-mutex-irq-flags-checking.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0164-rt-mutex-irq-flags-checking.patch @@ -0,0 +1,83 @@ +--- + include/linux/irqflags.h | 37 ++++++++++++++++++++++++++++++++----- + 1 file changed, 32 insertions(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/irqflags.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/irqflags.h 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/irqflags.h 2009-02-08 00:01:59.000000000 -0500 +@@ -11,6 +11,12 @@ + #ifndef _LINUX_TRACE_IRQFLAGS_H + #define _LINUX_TRACE_IRQFLAGS_H + ++#define BUILD_CHECK_IRQ_FLAGS(flags) \ ++ do { \ ++ BUILD_BUG_ON(sizeof(flags) != sizeof(unsigned long)); \ ++ typecheck(unsigned long, flags); \ ++ } while (0) ++ + #ifdef CONFIG_TRACE_IRQFLAGS + extern void trace_hardirqs_on(void); + extern void trace_hardirqs_off(void); +@@ -59,10 +65,15 @@ + #define local_irq_disable() \ + do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0) + #define local_irq_save(flags) \ +- do { raw_local_irq_save(flags); trace_hardirqs_off(); } while (0) ++ do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ raw_local_irq_save(flags); \ ++ trace_hardirqs_off(); \ ++ } while (0) + + #define local_irq_restore(flags) \ + do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ + if (raw_irqs_disabled_flags(flags)) { \ + raw_local_irq_restore(flags); \ + trace_hardirqs_off(); \ +@@ -78,8 +89,16 @@ + */ + # define raw_local_irq_disable() local_irq_disable() + # define raw_local_irq_enable() local_irq_enable() +-# define raw_local_irq_save(flags) local_irq_save(flags) +-# define raw_local_irq_restore(flags) local_irq_restore(flags) ++# define raw_local_irq_save(flags) \ ++ do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ local_irq_save(flags); \ ++ } while (0) ++# define raw_local_irq_restore(flags) \ ++ do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ local_irq_restore(flags); \ ++ } while (0) + #endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */ + + #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT +@@ -89,7 +108,11 @@ + raw_safe_halt(); \ + } while (0) + +-#define local_save_flags(flags) raw_local_save_flags(flags) ++#define local_save_flags(flags) \ ++ do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ raw_local_save_flags(flags); \ ++ } while (0) + + #define irqs_disabled() \ + ({ \ +@@ -99,7 +122,11 @@ + raw_irqs_disabled_flags(flags); \ + }) + +-#define irqs_disabled_flags(flags) raw_irqs_disabled_flags(flags) ++#define irqs_disabled_flags(flags) \ ++({ \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ raw_irqs_disabled_flags(flags); \ ++}) + #endif /* CONFIG_X86 */ + + #endif --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0165-rt-mutex-trivial-tcp-preempt-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0165-rt-mutex-trivial-tcp-preempt-fix.patch @@ -0,0 +1,22 @@ +--- + net/ipv4/tcp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/net/ipv4/tcp.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/net/ipv4/tcp.c 2009-02-08 00:00:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/net/ipv4/tcp.c 2009-02-08 00:01:59.000000000 -0500 +@@ -1155,11 +1155,11 @@ int tcp_recvmsg(struct kiocb *iocb, stru + (len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) && + !sysctl_tcp_low_latency && + __get_cpu_var(softnet_data).net_dma) { +- preempt_enable_no_resched(); ++ preempt_enable(); + tp->ucopy.pinned_list = + dma_pin_iovec_pages(msg->msg_iov, len); + } else { +- preempt_enable_no_resched(); ++ preempt_enable(); + } + } + #endif --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0211-preempt-realtime-arm-ixp4xx.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0211-preempt-realtime-arm-ixp4xx.patch @@ -0,0 +1,17 @@ +--- + arch/arm/mach-ixp4xx/common-pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/arm/mach-ixp4xx/common-pci.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mach-ixp4xx/common-pci.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mach-ixp4xx/common-pci.c 2009-02-08 00:02:22.000000000 -0500 +@@ -53,7 +53,7 @@ unsigned long ixp4xx_pci_reg_base = 0; + * these transactions are atomic or we will end up + * with corrupt data on the bus or in a driver. + */ +-static DEFINE_SPINLOCK(ixp4xx_pci_lock); ++static DEFINE_RAW_SPINLOCK(ixp4xx_pci_lock); + + /* + * Read from PCI config space --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0280-s_files-pipe-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0280-s_files-pipe-fix.patch @@ -0,0 +1,38 @@ +Subject: s_files: free_write_pipe() fix +From: Ingo Molnar + +file_kill() has to look at the file's inode (for the barrier logic), +hence make sure we free the inode before the file. + +Signed-off-by: Ingo Molnar +--- + fs/pipe.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/fs/pipe.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/pipe.c 2009-02-08 00:02:40.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/pipe.c 2009-02-08 00:03:00.000000000 -0500 +@@ -1011,12 +1011,17 @@ struct file *create_write_pipe(void) + return ERR_PTR(err); + } + +-void free_write_pipe(struct file *f) ++void free_write_pipe(struct file *file) + { +- free_pipe_info(f->f_dentry->d_inode); +- dput(f->f_path.dentry); +- mntput(f->f_path.mnt); +- put_filp(f); ++ struct dentry *dentry = file->f_path.dentry; ++ struct vfsmount *mnt = file->f_path.mnt; ++ ++ free_pipe_info(file->f_dentry->d_inode); ++ file->f_path.dentry = NULL; ++ file->f_path.mnt = NULL; ++ put_filp(file); ++ dput(dentry); ++ mntput(mnt); + } + + struct file *create_read_pipe(struct file *wrf) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0560-rwlock-update-torture-test.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0560-rwlock-update-torture-test.patch @@ -0,0 +1,289 @@ +From: Steven Rostedt +Subject: rwlock: update torture test for testing unnested locking + +Signed-off-by: Steven Rostedt +--- + kernel/rwlock_torture.c | 126 +++++++++++++++++++++++++++++++++++------------- + 1 file changed, 94 insertions(+), 32 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rwlock_torture.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rwlock_torture.c 2009-02-08 00:04:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rwlock_torture.c 2009-02-08 00:05:18.000000000 -0500 +@@ -13,7 +13,20 @@ + + #ifdef CONFIG_LOGDEV + #include ++#define LD_WARN_ON_ONCE(cond) \ ++ do { \ ++ static int once; \ ++ if (unlikely(cond) && !once++) { \ ++ lfcnprint("FAILED " #cond); \ ++ logdev_print_off(); \ ++ oops_in_progress++; \ ++ logdev_dump(); \ ++ WARN_ON(1); \ ++ oops_in_progress--; \ ++ } \ ++ } while (0) + #else ++#define LD_WARN_ON_ONCE(cond) WARN_ON_ONCE(cond) + #define lfcnprint(x...) do { } while (0) + #define lmark() do { } while(0) + #define logdev_dump() do { } while (0) +@@ -31,19 +44,30 @@ static DEFINE_MUTEX(mutex1); + static DEFINE_MUTEX(mutex2); + static DEFINE_MUTEX(mutex3); + ++static DEFINE_SPINLOCK(reverse_lock); ++ + struct locks { + union { + struct rw_semaphore *sem; + rwlock_t *lock; + struct mutex *mutex; + }; ++ + int type; + char *name; ++ ++ /* to test unnested locks */ ++ struct locks *reverse_lock; ++ int reverse_read; ++ struct task_struct *who; ++ ++ /* stats */ + int read_cnt; + int write_cnt; + int downgrade; + int taken; + int retaken; ++ int reversed; + }; + + enum { LOCK_TYPE_LOCK = 0, +@@ -306,6 +330,7 @@ pick_lock(struct locks *lock, struct loc + + static void do_lock(struct locks *lock, int read) + { ++ lfcnprint("reader_lock_count=%d", current->reader_lock_count); + switch (read) { + case LOCK_READ: + if (unlikely(lock->type != LOCK_TYPE_LOCK)) { +@@ -363,8 +388,29 @@ static void do_lock(struct locks *lock, + lfcnprint("taken %s %p", lock->name, lock); + } + +-static void do_unlock(struct locks *lock, int read) ++static void do_unlock(struct locks *lock, int read, struct locks *prev_lock) + { ++ if (prev_lock) { ++ spin_lock(&reverse_lock); ++ if (!prev_lock->reverse_lock) { ++ int x; ++ /* test reverse order unlocking */ ++ x = random32(); ++ if (x & 1) { ++ lfcnprint("reverse lock %s %p and %s %p", ++ lock->name, lock, ++ prev_lock->name, prev_lock); ++ prev_lock->reverse_lock = lock; ++ prev_lock->reverse_read = read; ++ prev_lock->who = current; ++ lock->reversed++; ++ spin_unlock(&reverse_lock); ++ return; ++ } ++ } ++ spin_unlock(&reverse_lock); ++ } ++ + switch (read) { + case LOCK_READ: + if (unlikely(lock->type != LOCK_TYPE_LOCK)) { +@@ -418,10 +464,18 @@ static void do_unlock(struct locks *lock + default: + printk("bad lock value %d!!!\n", read); + } +- lfcnprint("unlocked"); ++ lfcnprint("%s unlocked", lock->name); ++ ++ if (lock->reverse_lock && lock->who == current) { ++ lock->who = NULL; ++ lfcnprint("unlock reverse lock %s %p", ++ lock->reverse_lock->name, lock->reverse_lock); ++ do_unlock(lock->reverse_lock, lock->reverse_read, NULL); ++ lock->reverse_lock = NULL; ++ } + } + +-static void do_something(unsigned long time, int ignore) ++static void do_something(unsigned long time, int ignore, struct locks *prev_lock) + { + lmark(); + if (test_done) +@@ -450,7 +504,7 @@ static void do_downgrade(unsigned long t + lfcnprint("downgrade %p", sem); + lock->downgrade++; + downgrade_write(sem); +- do_something(time, 0); ++ do_something(time, 0, NULL); + /* need to do unlock read */ + *read = SEM_READ; + } +@@ -474,10 +528,11 @@ static void update_stats(int read, struc + + #define MAX_DEPTH 10 + +-static void run_lock(void (*func)(unsigned long time, int read), +- struct locks *lock, unsigned long time, int read, int depth); ++static void run_lock(void (*func)(unsigned long time, int read, struct locks *prev_lock), ++ struct locks *lock, unsigned long time, int read, int depth, ++ struct locks *prev_lock); + +-static void do_again(void (*func)(unsigned long time, int read), ++static void do_again(void (*func)(unsigned long time, int read, struct locks *prev_lock), + struct locks *lock, unsigned long time, int read, int depth) + { + unsigned long x; +@@ -485,19 +540,23 @@ static void do_again(void (*func)(unsign + if (test_done) + return; + +- /* If this was grabbed for read via rwlock, do again */ +- if (likely(read != LOCK_READ) || depth >= MAX_DEPTH) ++ /* ++ * If this was grabbed for read via rwlock, do again ++ * (but not if we did a reverse) ++ */ ++ if (likely(read != LOCK_READ) || depth >= MAX_DEPTH || lock->reverse_lock) + return; + + x = random32(); + if (x & 1) { + lfcnprint("read lock again"); +- run_lock(func, lock, time, read, depth+1); ++ run_lock(func, lock, time, read, depth+1, NULL); + } + } + +-static void run_lock(void (*func)(unsigned long time, int read), +- struct locks *lock, unsigned long time, int read, int depth) ++static void run_lock(void (*func)(unsigned long time, int read, struct locks *prev_lock), ++ struct locks *lock, unsigned long time, int read, int depth, ++ struct locks *prev_lock) + { + if (test_done) + return; +@@ -507,39 +566,39 @@ static void run_lock(void (*func)(unsign + lock->retaken++; + do_lock(lock, read); + if (!test_done) { +- func(time, do_read(read)); ++ func(time, do_read(read), lock); + do_again(func, lock, time, read, depth); + } + do_downgrade(time, lock, &read); +- do_unlock(lock, read); ++ do_unlock(lock, read, prev_lock); + + } + +-static void run_one_lock(unsigned long time, int read) ++static void run_one_lock(unsigned long time, int read, struct locks *prev_lock) + { + struct locks *lock; + + lmark(); + lock = pick_lock(&test_lock1, &test_sem1, &test_mutex1, read); +- run_lock(do_something, lock, time, read, 0); ++ run_lock(do_something, lock, time, read, 0, prev_lock); + } + +-static void run_two_locks(unsigned long time, int read) ++static void run_two_locks(unsigned long time, int read, struct locks *prev_lock) + { + struct locks *lock; + + lmark(); + lock = pick_lock(&test_lock2, &test_sem2, &test_mutex2, read); +- run_lock(run_one_lock, lock, time, read, 0); ++ run_lock(run_one_lock, lock, time, read, 0, prev_lock); + } + +-static void run_three_locks(unsigned long time, int read) ++static void run_three_locks(unsigned long time, int read, struct locks *prev_lock) + { + struct locks *lock; + + lmark(); + lock = pick_lock(&test_lock3, &test_sem3, &test_mutex3, read); +- run_lock(run_two_locks, lock, time, read, 0); ++ run_lock(run_two_locks, lock, time, read, 0, prev_lock); + } + + static int run_test(unsigned long time) +@@ -557,22 +616,20 @@ static int run_test(unsigned long time) + + switch (ret = (start & 3)) { + case 0: +- run_one_lock(time, read); ++ run_one_lock(time, read, NULL); + break; + case 1: +- run_two_locks(time, read); ++ run_two_locks(time, read, NULL); + break; + case 2: +- run_three_locks(time, read); ++ run_three_locks(time, read, NULL); + break; + default: + ret = 1; +- run_two_locks(time, read); ++ run_two_locks(time, read, NULL); + } + +-#ifdef CONFIG_PREEMPT_RT +- WARN_ON_ONCE(current->reader_lock_count); +-#endif ++ LD_WARN_ON_ONCE(current->reader_lock_count); + + return ret; + } +@@ -618,7 +675,8 @@ static void print_lock_stat(struct locks + lock->name, lock->downgrade); + } + } +- printk("%8s taken: %8d\n\n", lock->name, lock->taken); ++ printk("%8s taken: %8d\n", lock->name, lock->taken); ++ printk("%8s reversed: %8d\n\n", lock->name, lock->reversed); + } + + static int __init mutex_stress_init(void) +@@ -676,7 +734,12 @@ static int __init mutex_stress_init(void + if (tsks[i]) { + struct rt_mutex *mtx; + unsigned long own; +- struct rt_mutex_waiter *w; ++ struct rt_my_waiter { ++ struct plist_node list_entry; ++ struct plist_node pi_list_entry; ++ struct task_struct *task; ++ struct rt_mutex *lock; ++ } *w; + + spin_lock_irq(&tsks[i]->pi_lock); + +@@ -690,9 +753,8 @@ static int __init mutex_stress_init(void + spin_lock(&tsks[i]->pi_lock); + own = (unsigned long)mtx->owner & ~3UL; + oops_in_progress++; +- printk("%s:%d is blocked on ", +- tsks[i]->comm, tsks[i]->pid); +- __print_symbol("%s", (unsigned long)mtx); ++ printk("%s:%d is blocked on %p ", ++ tsks[i]->comm, tsks[i]->pid, mtx); + if (own == 0x100) + printk(" owner is READER\n"); + else if (!(own & ~300)) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0013-x86_fix_vsyscall_wreckage.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0013-x86_fix_vsyscall_wreckage.patch @@ -0,0 +1,134 @@ +# Commit: ce28b9864b853803320c3f1d8de1b81aa4120b14 + +From: Clark Williams + +# Parent: d4afe414189b098d56bcd24280c018aa2ac9a990 + # Author: Thomas Gleixner <[EMAIL PROTECTED]> + # AuthorDate: Wed Feb 20 23:57:30 2008 +0100 + # Committer: Ingo Molnar <[EMAIL PROTECTED]> + # CommitDate: Tue Feb 26 12:55:57 2008 +0100 + + x86: fix vsyscall wreckage + + based on a report from Arne Georg Gleditsch about user-space apps + misbehaving after toggling /proc/sys/kernel/vsyscall64, a review + of the code revealed that the "NOP patching" done there is + fundamentally unsafe for a number of reasons: + + 1) the patching code runs without synchronizing other CPUs + + 2) it inserts NOPs even if there is no clock source which provides vread + + 3) when the clock source changes to one without vread we run in + exactly the same problem as in #2 + + 4) if nobody toggles the proc entry from 1 to 0 and to 1 again, then + the syscall is not patched out + + as a result it is possible to break user-space via this patching. + The only safe thing for now is to remove the patching. + + This code was broken since v2.6.21. + + Reported-by: Arne Georg Gleditsch <[EMAIL PROTECTED]> + Signed-off-by: Thomas Gleixner <[EMAIL PROTECTED]> + Signed-off-by: Ingo Molnar <[EMAIL PROTECTED]> +--- + + arch/x86/kernel/vsyscall_64.c | 52 ++---------------------------------------- + 1 file changed, 3 insertions(+), 49 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/vsyscall_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/vsyscall_64.c 2009-02-08 00:00:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/vsyscall_64.c 2009-02-08 00:00:48.000000000 -0500 +@@ -44,11 +44,6 @@ + + #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) + #define __syscall_clobber "r11","rcx","memory" +-#define __pa_vsymbol(x) \ +- ({unsigned long v; \ +- extern char __vsyscall_0; \ +- asm("" : "=r" (v) : "0" (x)); \ +- ((v - VSYSCALL_START) + __pa_symbol(&__vsyscall_0)); }) + + /* + * vsyscall_gtod_data contains data that is : +@@ -102,7 +97,7 @@ static __always_inline void do_get_tz(st + static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz) + { + int ret; +- asm volatile("vsysc2: syscall" ++ asm volatile("syscall" + : "=a" (ret) + : "0" (__NR_gettimeofday),"D" (tv),"S" (tz) + : __syscall_clobber ); +@@ -112,7 +107,7 @@ static __always_inline int gettimeofday( + static __always_inline long time_syscall(long *t) + { + long secs; +- asm volatile("vsysc1: syscall" ++ asm volatile("syscall" + : "=a" (secs) + : "0" (__NR_time),"D" (t) : __syscall_clobber); + return secs; +@@ -227,50 +222,10 @@ long __vsyscall(3) venosys_1(void) + } + + #ifdef CONFIG_SYSCTL +- +-#define SYSCALL 0x050f +-#define NOP2 0x9090 +- +-/* +- * NOP out syscall in vsyscall page when not needed. +- */ +-static int vsyscall_sysctl_change(ctl_table *ctl, int write, struct file * filp, +- void __user *buffer, size_t *lenp, loff_t *ppos) +-{ +- extern u16 vsysc1, vsysc2; +- u16 __iomem *map1; +- u16 __iomem *map2; +- int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); +- if (!write) +- return ret; +- /* gcc has some trouble with __va(__pa()), so just do it this +- way. */ +- map1 = ioremap(__pa_vsymbol(&vsysc1), 2); +- if (!map1) +- return -ENOMEM; +- map2 = ioremap(__pa_vsymbol(&vsysc2), 2); +- if (!map2) { +- ret = -ENOMEM; +- goto out; +- } +- if (!vsyscall_gtod_data.sysctl_enabled) { +- writew(SYSCALL, map1); +- writew(SYSCALL, map2); +- } else { +- writew(NOP2, map1); +- writew(NOP2, map2); +- } +- iounmap(map2); +-out: +- iounmap(map1); +- return ret; +-} +- + static ctl_table kernel_table2[] = { + { .procname = "vsyscall64", + .data = &vsyscall_gtod_data.sysctl_enabled, .maxlen = sizeof(int), +- .mode = 0644, +- .proc_handler = vsyscall_sysctl_change }, ++ .mode = 0644 }, + {} + }; + +@@ -279,7 +234,6 @@ static ctl_table kernel_root_table2[] = + .child = kernel_table2 }, + {} + }; +- + #endif + + /* Assume __initcall executes before all user space. Hopefully kmod --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0228-preempt-realtime-powerpc-missing-raw-spinlocks.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0228-preempt-realtime-powerpc-missing-raw-spinlocks.patch @@ -0,0 +1,107 @@ +From sshtylyov@ru.mvista.com Thu Jun 21 22:24:22 2007 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.1.7-deb (2006-10-05) on debian +X-Spam-Level: +X-Spam-Status: No, score=0.0 required=5.0 tests=AWL autolearn=unavailable + version=3.1.7-deb +Received: from imap.sh.mvista.com (unknown [63.81.120.155]) by mail.tglx.de + (Postfix) with ESMTP id 2149065C065 for ; Thu, 21 Jun + 2007 22:24:22 +0200 (CEST) +Received: from wasted.dev.rtsoft.ru (unknown [10.150.0.9]) by + imap.sh.mvista.com (Postfix) with ESMTP id D27113EC9; Thu, 21 Jun 2007 + 13:24:15 -0700 (PDT) +From: Sergei Shtylyov +Organization: MontaVista Software Inc. +To: tglx@linutronix.de, bruce.ashfield@gmail.com, rostedt@goodmis.org +Subject: [PATCH] (2.6.20-rt3) PowerPC: convert spinlocks into raw +Date: Thu, 21 Jun 2007 23:25:58 +0300 +User-Agent: KMail/1.5 +MIME-Version: 1.0 +Content-Disposition: inline +Content-Type: text/plain; charset="iso-8859-1" +Message-Id: <200706220025.58799.sshtylyov@ru.mvista.com> +X-Evolution-Source: imap://tglx%40linutronix.de@localhost:8993/ +Content-Transfer-Encoding: 8bit + +Convert the spinlocks in the PowerPC interrupt related code into the raw ones, +also convert the PURR and PMC related spinlocks... + +Signed-off-by: Mark A. Greer +Signed-off-by: Sergei Shtylyov + +--- +Resending in hopes it still can apply -- if it doesn't, bug me again... :-) + +--- + arch/powerpc/kernel/pmc.c | 2 +- + arch/powerpc/sysdev/i8259.c | 2 +- + arch/powerpc/sysdev/ipic.c | 2 +- + arch/powerpc/sysdev/mpic.c | 2 +- + include/asm-powerpc/mpic.h | 2 +- + 5 files changed, 5 insertions(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/pmc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/pmc.c 2009-02-08 00:00:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/pmc.c 2009-02-08 00:02:32.000000000 -0500 +@@ -37,7 +37,7 @@ static void dummy_perf(struct pt_regs *r + } + + +-static DEFINE_SPINLOCK(pmc_owner_lock); ++static DEFINE_RAW_SPINLOCK(pmc_owner_lock); + static void *pmc_owner_caller; /* mostly for debugging */ + perf_irq_t perf_irq = dummy_perf; + +Index: linux-2.6.24.7-rt27/arch/powerpc/sysdev/i8259.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/sysdev/i8259.c 2009-02-08 00:00:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/sysdev/i8259.c 2009-02-08 00:02:32.000000000 -0500 +@@ -23,7 +23,7 @@ static unsigned char cached_8259[2] = { + #define cached_A1 (cached_8259[0]) + #define cached_21 (cached_8259[1]) + +-static DEFINE_SPINLOCK(i8259_lock); ++static DEFINE_RAW_SPINLOCK(i8259_lock); + + static struct irq_host *i8259_host; + +Index: linux-2.6.24.7-rt27/arch/powerpc/sysdev/ipic.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/sysdev/ipic.c 2009-02-08 00:00:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/sysdev/ipic.c 2009-02-08 00:02:32.000000000 -0500 +@@ -30,7 +30,7 @@ + #include "ipic.h" + + static struct ipic * primary_ipic; +-static DEFINE_SPINLOCK(ipic_lock); ++static DEFINE_RAW_SPINLOCK(ipic_lock); + + static struct ipic_info ipic_info[] = { + [9] = { +Index: linux-2.6.24.7-rt27/arch/powerpc/sysdev/mpic.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/sysdev/mpic.c 2009-02-08 00:01:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/sysdev/mpic.c 2009-02-08 00:02:32.000000000 -0500 +@@ -46,7 +46,7 @@ + + static struct mpic *mpics; + static struct mpic *mpic_primary; +-static DEFINE_SPINLOCK(mpic_lock); ++static DEFINE_RAW_SPINLOCK(mpic_lock); + + #ifdef CONFIG_PPC32 /* XXX for now */ + #ifdef CONFIG_IRQ_ALL_CPUS +Index: linux-2.6.24.7-rt27/include/asm-powerpc/mpic.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-powerpc/mpic.h 2009-02-08 00:00:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-powerpc/mpic.h 2009-02-08 00:02:32.000000000 -0500 +@@ -275,7 +275,7 @@ struct mpic + #ifdef CONFIG_MPIC_U3_HT_IRQS + /* The fixup table */ + struct mpic_irq_fixup *fixups; +- spinlock_t fixup_lock; ++ raw_spinlock_t fixup_lock; + #endif + + /* Register access method */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0469-lockstat-fix-contention-points.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0469-lockstat-fix-contention-points.patch @@ -0,0 +1,23 @@ +Subject: lockstat: fix contention points +From: Peter Zijlstra + +blatantly stupid bug.. + +Signed-off-by: Peter Zijlstra +--- + kernel/lockdep.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/lockdep.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/lockdep.c 2009-02-08 00:03:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/lockdep.c 2009-02-08 00:04:33.000000000 -0500 +@@ -2889,7 +2889,7 @@ found_it: + + stats = get_lock_stats(hlock->class); + if (point < ARRAY_SIZE(stats->contention_point)) +- stats->contention_point[i]++; ++ stats->contention_point[point]++; + if (lock->cpu != smp_processor_id()) + stats->bounces[bounce_contended + !!hlock->read]++; + put_lock_stats(stats); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0496-sched-cpupri-hotplug-support.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0496-sched-cpupri-hotplug-support.patch @@ -0,0 +1,271 @@ +From ghaskins@novell.com Thu Jun 5 09:51:42 2008 +Date: Wed, 04 Jun 2008 15:04:05 -0400 +From: Gregory Haskins +To: Ingo Molnar , Thomas Gleixner , + Steven Rostedt , + Arnaldo Carvalho de Melo +Cc: Gregory Haskins , linux-kernel@vger.kernel.org, + linux-rt-users@vger.kernel.org, Peter Zijlstra +Subject: [PATCH 1/2] sched: fix cpupri hotplug support + + [ The following text is in the "utf-8" character set. ] + [ Your display is set for the "iso-8859-1" character set. ] + [ Some characters may be displayed incorrectly. ] + + +The RT folks over at RedHat found an issue w.r.t. hotplug support which +was traced to problems with the cpupri infrastructure in the scheduler: + +https://bugzilla.redhat.com/show_bug.cgi?id=449676 + +This bug affects 23-rt12+, 24-rtX, 25-rtX, and sched-devel. This patch +applies to 25.4-rt4, though it should trivially apply to most cpupri enabled +kernels mentioned above. + +It turned out that the issue was that offline cpus could get inadvertently +registered with cpupri so that they were erroneously selected during +migration decisions. The end result would be an OOPS as the offline cpu +had tasks routed to it. + +This patch generalizes the old join/leave domain interface into an +online/offline interface, and adjusts the root-domain/hotplug code to +utilize it. + +I was able to easily reproduce the issue prior to this patch, and am no +longer able to reproduce it after this patch. I can offline cpus +indefinately and everything seems to be in working order. + +Thanks to Arnaldo (acme), Thomas, and Peter for doing the legwork to point +me in the right direction. Also thank you to Peter for reviewing the +early iterations of this patch. + +Signed-off-by: Gregory Haskins +CC: Ingo Molnar +CC: Thomas Gleixner +CC: Steven Rostedt +CC: Arnaldo Carvalho de Melo +CC: Peter Zijlstra +--- + + include/linux/sched.h | 4 +-- + kernel/sched.c | 54 +++++++++++++++++++++++++++++++++++++------------- + kernel/sched_rt.c | 26 +++++++++++++++++------- + 3 files changed, 61 insertions(+), 23 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:04:43.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:04:47.000000000 -0500 +@@ -931,8 +931,8 @@ struct sched_class { + void (*task_new) (struct rq *rq, struct task_struct *p); + void (*set_cpus_allowed)(struct task_struct *p, cpumask_t *newmask); + +- void (*join_domain)(struct rq *rq); +- void (*leave_domain)(struct rq *rq); ++ void (*rq_online)(struct rq *rq); ++ void (*rq_offline)(struct rq *rq); + + void (*switched_from) (struct rq *this_rq, struct task_struct *task, + int running); +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:04:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:04:47.000000000 -0500 +@@ -428,6 +428,7 @@ struct rq { + int push_cpu; + /* cpu of this runqueue: */ + int cpu; ++ int online; + + struct task_struct *migration_thread; + struct list_head migration_queue; +@@ -1093,6 +1094,8 @@ static int task_hot(struct task_struct * + #endif + + #define sched_class_highest (&rt_sched_class) ++#define for_each_class(class) \ ++ for (class = sched_class_highest; class; class = class->next) + + /* + * Update delta_exec, delta_fair fields for rq. +@@ -6109,6 +6112,36 @@ static void unregister_sched_domain_sysc + } + #endif + ++static void set_rq_online(struct rq *rq) ++{ ++ if (!rq->online) { ++ const struct sched_class *class; ++ ++ cpu_set(rq->cpu, rq->rd->online); ++ rq->online = 1; ++ ++ for_each_class(class) { ++ if (class->rq_online) ++ class->rq_online(rq); ++ } ++ } ++} ++ ++static void set_rq_offline(struct rq *rq) ++{ ++ if (rq->online) { ++ const struct sched_class *class; ++ ++ for_each_class(class) { ++ if (class->rq_offline) ++ class->rq_offline(rq); ++ } ++ ++ cpu_clear(rq->cpu, rq->rd->online); ++ rq->online = 0; ++ } ++} ++ + /* + * migration_call - callback that gets triggered when a CPU is added. + * Here we can start up the necessary migration thread for the new CPU. +@@ -6149,7 +6182,8 @@ migration_call(struct notifier_block *nf + spin_lock_irqsave(&rq->lock, flags); + if (rq->rd) { + BUG_ON(!cpu_isset(cpu, rq->rd->span)); +- cpu_set(cpu, rq->rd->online); ++ ++ set_rq_online(rq); + } + spin_unlock_irqrestore(&rq->lock, flags); + break; +@@ -6209,7 +6243,7 @@ migration_call(struct notifier_block *nf + spin_lock_irqsave(&rq->lock, flags); + if (rq->rd) { + BUG_ON(!cpu_isset(cpu, rq->rd->span)); +- cpu_clear(cpu, rq->rd->online); ++ set_rq_offline(rq); + } + spin_unlock_irqrestore(&rq->lock, flags); + break; +@@ -6407,7 +6441,6 @@ sd_parent_degenerate(struct sched_domain + static void rq_attach_root(struct rq *rq, struct root_domain *rd) + { + unsigned long flags; +- const struct sched_class *class; + struct root_domain *reap = NULL; + + spin_lock_irqsave(&rq->lock, flags); +@@ -6415,13 +6448,10 @@ static void rq_attach_root(struct rq *rq + if (rq->rd) { + struct root_domain *old_rd = rq->rd; + +- for (class = sched_class_highest; class; class = class->next) { +- if (class->leave_domain) +- class->leave_domain(rq); +- } ++ if (cpu_isset(rq->cpu, old_rd->online)) ++ set_rq_offline(rq); + + cpu_clear(rq->cpu, old_rd->span); +- cpu_clear(rq->cpu, old_rd->online); + + if (atomic_dec_and_test(&old_rd->refcount)) + reap = old_rd; +@@ -6432,12 +6462,7 @@ static void rq_attach_root(struct rq *rq + + cpu_set(rq->cpu, rd->span); + if (cpu_isset(rq->cpu, cpu_online_map)) +- cpu_set(rq->cpu, rd->online); +- +- for (class = sched_class_highest; class; class = class->next) { +- if (class->join_domain) +- class->join_domain(rq); +- } ++ set_rq_online(rq); + + spin_unlock_irqrestore(&rq->lock, flags); + +@@ -7452,6 +7477,7 @@ void __init sched_init(void) + rq->next_balance = jiffies; + rq->push_cpu = 0; + rq->cpu = i; ++ rq->online = 0; + rq->migration_thread = NULL; + INIT_LIST_HEAD(&rq->migration_queue); + rq->rt.highest_prio = MAX_RT_PRIO; +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:04:43.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:04:47.000000000 -0500 +@@ -12,6 +12,9 @@ static inline int rt_overloaded(struct r + + static inline void rt_set_overload(struct rq *rq) + { ++ if (!rq->online) ++ return; ++ + cpu_set(rq->cpu, rq->rd->rto_mask); + /* + * Make sure the mask is visible before we set +@@ -26,6 +29,9 @@ static inline void rt_set_overload(struc + + static inline void rt_clear_overload(struct rq *rq) + { ++ if (!rq->online) ++ return; ++ + /* the order here really doesn't matter */ + atomic_dec(&rq->rd->rto_count); + cpu_clear(rq->cpu, rq->rd->rto_mask); +@@ -78,7 +84,10 @@ static inline void inc_rt_tasks(struct t + #ifdef CONFIG_SMP + if (p->prio < rq->rt.highest_prio) { + rq->rt.highest_prio = p->prio; +- cpupri_set(&rq->rd->cpupri, rq->cpu, p->prio); ++ ++ if (rq->online) ++ cpupri_set(&rq->rd->cpupri, rq->cpu, ++ p->prio); + } + if (p->nr_cpus_allowed > 1) + rq->rt.rt_nr_migratory++; +@@ -113,8 +122,11 @@ static inline void dec_rt_tasks(struct t + rq->rt.rt_nr_migratory--; + } + +- if (rq->rt.highest_prio != highest_prio) +- cpupri_set(&rq->rd->cpupri, rq->cpu, rq->rt.highest_prio); ++ if (rq->rt.highest_prio != highest_prio) { ++ if (rq->online) ++ cpupri_set(&rq->rd->cpupri, rq->cpu, ++ rq->rt.highest_prio); ++ } + + update_rt_migration(rq); + #endif /* CONFIG_SMP */ +@@ -758,7 +770,7 @@ static void set_cpus_allowed_rt(struct t + p->nr_cpus_allowed = weight; + } + /* Assumes rq->lock is held */ +-static void join_domain_rt(struct rq *rq) ++static void rq_online_rt(struct rq *rq) + { + if (rq->rt.overloaded) + rt_set_overload(rq); +@@ -767,7 +779,7 @@ static void join_domain_rt(struct rq *rq + } + + /* Assumes rq->lock is held */ +-static void leave_domain_rt(struct rq *rq) ++static void rq_offline_rt(struct rq *rq) + { + if (rq->rt.overloaded) + rt_clear_overload(rq); +@@ -919,8 +931,8 @@ const struct sched_class rt_sched_class + .load_balance = load_balance_rt, + .move_one_task = move_one_task_rt, + .set_cpus_allowed = set_cpus_allowed_rt, +- .join_domain = join_domain_rt, +- .leave_domain = leave_domain_rt, ++ .rq_online = rq_online_rt, ++ .rq_offline = rq_offline_rt, + .pre_schedule = pre_schedule_rt, + .post_schedule = post_schedule_rt, + .task_wake_up = task_wake_up_rt, --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0285-s_files.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0285-s_files.patch @@ -0,0 +1,322 @@ +Subject: remove global files_lock + +remove the global files_lock by reworking super_block and tty file lists. +these are replaced by percpu_lists which are fine grain locked lists +(lock_list) with a per cpu list head. + +Signed-off-by: Peter Zijlstra +--- + drivers/char/tty_io.c | 23 ++++++++++------------- + fs/file_table.c | 34 ++++++++++++++++++---------------- + fs/proc/generic.c | 2 ++ + fs/super.c | 12 ++++++++---- + include/linux/fs.h | 14 +++++++------- + include/linux/tty.h | 2 +- + security/selinux/hooks.c | 9 ++++++--- + 7 files changed, 52 insertions(+), 44 deletions(-) + +Index: linux-2.6.24.7-rt27/drivers/char/tty_io.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/char/tty_io.c 2009-02-08 00:02:44.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/char/tty_io.c 2009-02-08 00:03:02.000000000 -0500 +@@ -242,14 +242,13 @@ int tty_paranoia_check(struct tty_struct + static int check_tty_count(struct tty_struct *tty, const char *routine) + { + #ifdef CHECK_TTY_COUNT +- struct list_head *p; ++ struct file *filp; + int count = 0; +- +- file_list_lock(); +- list_for_each(p, &tty->tty_files) { ++ ++ percpu_list_fold(&tty->tty_files); ++ lock_list_for_each_entry(filp, percpu_list_head(&tty->tty_files), f_u.fu_llist) + count++; +- } +- file_list_unlock(); ++ + if (tty->driver->type == TTY_DRIVER_TYPE_PTY && + tty->driver->subtype == PTY_TYPE_SLAVE && + tty->link && tty->link->count) +@@ -1376,9 +1375,8 @@ static void do_tty_hangup(struct work_st + spin_unlock(&redirect_lock); + + check_tty_count(tty, "do_tty_hangup"); +- file_list_lock(); + /* This breaks for file handles being sent over AF_UNIX sockets ? */ +- list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { ++ lock_list_for_each_entry(filp, percpu_list_head(&tty->tty_files), f_u.fu_llist) { + if (filp->f_op->write == redirected_tty_write) + cons_filp = filp; + if (filp->f_op->write != tty_write) +@@ -1387,7 +1385,6 @@ static void do_tty_hangup(struct work_st + tty_fasync(-1, filp, 0); /* can't block */ + filp->f_op = &hung_up_tty_fops; + } +- file_list_unlock(); + + /* FIXME! What are the locking issues here? This may me overdoing things.. + * this question is especially important now that we've removed the irqlock. */ +@@ -2268,9 +2265,9 @@ static void release_one_tty(struct tty_s + tty->magic = 0; + tty->driver->refcount--; + +- file_list_lock(); +- list_del_init(&tty->tty_files); +- file_list_unlock(); ++ percpu_list_fold(&tty->tty_files); ++ lock_list_del_init(percpu_list_head(&tty->tty_files)); ++ percpu_list_destroy(&tty->tty_files); + + free_tty_struct(tty); + } +@@ -3734,7 +3731,7 @@ static void initialize_tty_struct(struct + mutex_init(&tty->atomic_read_lock); + mutex_init(&tty->atomic_write_lock); + spin_lock_init(&tty->read_lock); +- INIT_LIST_HEAD(&tty->tty_files); ++ percpu_list_init(&tty->tty_files); + INIT_WORK(&tty->SAK_work, do_SAK_work); + } + +Index: linux-2.6.24.7-rt27/fs/file_table.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/file_table.c 2009-02-07 23:59:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/file_table.c 2009-02-08 00:03:02.000000000 -0500 +@@ -28,9 +28,6 @@ struct files_stat_struct files_stat = { + .max_files = NR_FILE + }; + +-/* public. Not pretty! */ +-__cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); +- + static struct percpu_counter nr_files __cacheline_aligned_in_smp; + + static inline void file_free_rcu(struct rcu_head *head) +@@ -111,7 +108,7 @@ struct file *get_empty_filp(void) + goto fail_sec; + + tsk = current; +- INIT_LIST_HEAD(&f->f_u.fu_list); ++ INIT_LOCK_LIST_HEAD(&f->f_u.fu_llist); + atomic_set(&f->f_count, 1); + rwlock_init(&f->f_owner.lock); + f->f_uid = tsk->fsuid; +@@ -303,31 +300,35 @@ void put_filp(struct file *file) + } + } + +-void file_move(struct file *file, struct list_head *list) ++void file_move(struct file *file, struct percpu_list *list) + { + if (!list) + return; +- file_list_lock(); +- list_move(&file->f_u.fu_list, list); +- file_list_unlock(); ++ ++ file_kill(file); ++ percpu_list_add(list, &file->f_u.fu_llist); + } + + void file_kill(struct file *file) + { +- if (!list_empty(&file->f_u.fu_list)) { +- file_list_lock(); +- list_del_init(&file->f_u.fu_list); +- file_list_unlock(); ++ if (file && file->f_mapping && file->f_mapping->host) { ++ struct super_block *sb = file->f_mapping->host->i_sb; ++ if (sb) ++ synchronize_qrcu(&sb->s_qrcu); + } ++ ++ lock_list_del_init(&file->f_u.fu_llist); + } + + int fs_may_remount_ro(struct super_block *sb) + { + struct file *file; ++ int idx; + + /* Check that no files are currently opened for writing. */ +- file_list_lock(); +- list_for_each_entry(file, &sb->s_files, f_u.fu_list) { ++ idx = qrcu_read_lock(&sb->s_qrcu); ++ percpu_list_fold(&sb->s_files); ++ lock_list_for_each_entry(file, percpu_list_head(&sb->s_files), f_u.fu_llist) { + struct inode *inode = file->f_path.dentry->d_inode; + + /* File with pending delete? */ +@@ -338,10 +339,11 @@ int fs_may_remount_ro(struct super_block + if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) + goto too_bad; + } +- file_list_unlock(); ++ qrcu_read_unlock(&sb->s_qrcu, idx); + return 1; /* Tis' cool bro. */ + too_bad: +- file_list_unlock(); ++ lock_list_for_each_entry_stop(file, f_u.fu_llist); ++ qrcu_read_unlock(&sb->s_qrcu, idx); + return 0; + } + +Index: linux-2.6.24.7-rt27/fs/proc/generic.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/proc/generic.c 2009-02-07 23:59:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/proc/generic.c 2009-02-08 00:03:02.000000000 -0500 +@@ -698,6 +698,8 @@ void remove_proc_entry(const char *name, + goto out; + len = strlen(fn); + ++ percpu_list_fold(&proc_mnt->mnt_sb->s_files); ++ + spin_lock(&proc_subdir_lock); + for (p = &parent->subdir; *p; p=&(*p)->next ) { + if (!proc_match(len, fn, *p)) +Index: linux-2.6.24.7-rt27/fs/super.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/super.c 2009-02-07 23:59:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/super.c 2009-02-08 00:03:02.000000000 -0500 +@@ -64,7 +64,8 @@ static struct super_block *alloc_super(s + INIT_LIST_HEAD(&s->s_dirty); + INIT_LIST_HEAD(&s->s_io); + INIT_LIST_HEAD(&s->s_more_io); +- INIT_LIST_HEAD(&s->s_files); ++ percpu_list_init(&s->s_files); ++ init_qrcu_struct(&s->s_qrcu); + INIT_LIST_HEAD(&s->s_instances); + INIT_HLIST_HEAD(&s->s_anon); + INIT_LIST_HEAD(&s->s_inodes); +@@ -103,6 +104,7 @@ out: + */ + static inline void destroy_super(struct super_block *s) + { ++ percpu_list_destroy(&s->s_files); + security_sb_free(s); + kfree(s->s_subtype); + kfree(s); +@@ -565,13 +567,15 @@ out: + static void mark_files_ro(struct super_block *sb) + { + struct file *f; ++ int idx; + +- file_list_lock(); +- list_for_each_entry(f, &sb->s_files, f_u.fu_list) { ++ idx = qrcu_read_lock(&sb->s_qrcu); ++ percpu_list_fold(&sb->s_files); ++ lock_list_for_each_entry(f, percpu_list_head(&sb->s_files), f_u.fu_llist) { + if (S_ISREG(f->f_path.dentry->d_inode->i_mode) && file_count(f)) + f->f_mode &= ~FMODE_WRITE; + } +- file_list_unlock(); ++ qrcu_read_unlock(&sb->s_qrcu, idx); + } + + /** +Index: linux-2.6.24.7-rt27/include/linux/fs.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/fs.h 2009-02-07 23:59:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/fs.h 2009-02-08 00:03:02.000000000 -0500 +@@ -279,12 +279,14 @@ extern int dir_notify_enable; + #include + #include + #include ++#include + #include + #include + #include + #include + #include + #include ++#include + + #include + #include +@@ -776,11 +778,11 @@ static inline int ra_has_index(struct fi + + struct file { + /* +- * fu_list becomes invalid after file_free is called and queued via ++ * fu_llist becomes invalid after file_free is called and queued via + * fu_rcuhead for RCU freeing + */ + union { +- struct list_head fu_list; ++ struct lock_list_head fu_llist; + struct rcu_head fu_rcuhead; + } f_u; + struct path f_path; +@@ -809,9 +811,6 @@ struct file { + #endif /* #ifdef CONFIG_EPOLL */ + struct address_space *f_mapping; + }; +-extern spinlock_t files_lock; +-#define file_list_lock() spin_lock(&files_lock); +-#define file_list_unlock() spin_unlock(&files_lock); + + #define get_file(x) atomic_inc(&(x)->f_count) + #define file_count(x) atomic_read(&(x)->f_count) +@@ -1007,7 +1006,8 @@ struct super_block { + struct list_head s_io; /* parked for writeback */ + struct list_head s_more_io; /* parked for more writeback */ + struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */ +- struct list_head s_files; ++ struct percpu_list s_files; ++ struct qrcu_struct s_qrcu; + + struct block_device *s_bdev; + struct mtd_info *s_mtd; +@@ -1777,7 +1777,7 @@ static inline void insert_inode_hash(str + } + + extern struct file * get_empty_filp(void); +-extern void file_move(struct file *f, struct list_head *list); ++extern void file_move(struct file *f, struct percpu_list *list); + extern void file_kill(struct file *f); + #ifdef CONFIG_BLOCK + struct bio; +Index: linux-2.6.24.7-rt27/include/linux/tty.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/tty.h 2009-02-07 23:59:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/tty.h 2009-02-08 00:03:02.000000000 -0500 +@@ -211,7 +211,7 @@ struct tty_struct { + struct work_struct hangup_work; + void *disc_data; + void *driver_data; +- struct list_head tty_files; ++ struct percpu_list tty_files; + + #define N_TTY_BUF_SIZE 4096 + +Index: linux-2.6.24.7-rt27/security/selinux/hooks.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/security/selinux/hooks.c 2009-02-07 23:59:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/security/selinux/hooks.c 2009-02-08 00:03:02.000000000 -0500 +@@ -1747,8 +1747,11 @@ static inline void flush_unauthorized_fi + mutex_lock(&tty_mutex); + tty = get_current_tty(); + if (tty) { +- file_list_lock(); +- file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list); ++ lock_list_for_each_entry(file, ++ percpu_list_head(&tty->tty_files), ++ f_u.fu_llist) ++ break; ++ + if (file) { + /* Revalidate access to controlling tty. + Use inode_has_perm on the tty inode directly rather +@@ -1760,8 +1763,8 @@ static inline void flush_unauthorized_fi + FILE__READ | FILE__WRITE, NULL)) { + drop_tty = 1; + } ++ lock_list_for_each_entry_stop(file, f_u.fu_llist); + } +- file_list_unlock(); + } + mutex_unlock(&tty_mutex); + /* Reset controlling tty. */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0283-lock_list.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0283-lock_list.patch @@ -0,0 +1,221 @@ +Subject: lock_list - a fine grain locked double linked list + +Provide a simple fine grain locked double link list. + +It build upon the regular double linked list primitives, spinlocks and RCU. + +In order to avoid deadlocks a prev -> next locking order is observed. This +prevents reverse iteration. + +Signed-off-by: Peter Zijlstra +Signed-off-by: Ingo Molnar +--- + include/linux/lock_list.h | 74 +++++++++++++++++++++++++++++++ + lib/Makefile | 2 + lib/lock_list.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 182 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/include/linux/lock_list.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/include/linux/lock_list.h 2009-02-08 00:03:02.000000000 -0500 +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (C) 2006, Red Hat, Inc., Peter Zijlstra ++ * Licenced under the GPLv2. ++ * ++ * Simple fine grain locked double linked list. ++ */ ++#ifndef _LINUX_LOCK_LIST_H ++#define _LINUX_LOCK_LIST_H ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++struct lock_list_head { ++ union { ++ struct list_head head; ++ struct { ++ struct lock_list_head *next, *prev; ++ }; ++ }; ++ spinlock_t lock; ++}; ++ ++enum { ++ LOCK_LIST_NESTING_PREV = 1, ++ LOCK_LIST_NESTING_CUR, ++ LOCK_LIST_NESTING_NEXT, ++}; ++ ++static inline void INIT_LOCK_LIST_HEAD(struct lock_list_head *list) ++{ ++ INIT_LIST_HEAD(&list->head); ++ spin_lock_init(&list->lock); ++} ++ ++/* ++ * Passed pointers are assumed stable by external means (refcount, rcu) ++ */ ++extern void lock_list_add(struct lock_list_head *new, ++ struct lock_list_head *list); ++extern void lock_list_del_init(struct lock_list_head *entry); ++extern void lock_list_splice_init(struct lock_list_head *list, ++ struct lock_list_head *head); ++ ++struct lock_list_head *lock_list_next_entry(struct lock_list_head *list, ++ struct lock_list_head *entry); ++struct lock_list_head *lock_list_first_entry(struct lock_list_head *list); ++ ++#define lock_list_for_each_entry(pos, list, member) \ ++ for (pos = list_entry(lock_list_first_entry(list), \ ++ typeof(*pos), member); \ ++ pos; \ ++ pos = list_entry(lock_list_next_entry(list, &pos->member), \ ++ typeof(*pos), member)) ++ ++/* ++ * to be used when iteration is terminated by breaking out of the ++ * lock_list_for_each_entry() loop. ++ * ++ * lock_list_for_each_entry(i, list, member) { ++ * if (cond) { ++ * lock_list_for_each_entry_stop(i, member); ++ * goto foo; ++ * } ++ * } ++ * ++ */ ++#define lock_list_for_each_entry_stop(pos, member) \ ++ spin_unlock(&(pos->member.lock)) ++ ++#endif /* __KERNEL__ */ ++#endif /* _LINUX_LOCK_LIST_H */ +Index: linux-2.6.24.7-rt27/lib/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/Makefile 2009-02-08 00:02:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/Makefile 2009-02-08 00:03:02.000000000 -0500 +@@ -3,7 +3,7 @@ + # + + lib-y := ctype.o string.o vsprintf.o cmdline.o \ +- rbtree.o radix-tree.o dump_stack.o \ ++ rbtree.o radix-tree.o dump_stack.o lock_list.o \ + idr.o int_sqrt.o extable.o prio_tree.o \ + sha1.o irq_regs.o reciprocal_div.o argv_split.o \ + proportions.o prio_heap.o +Index: linux-2.6.24.7-rt27/lib/lock_list.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/lib/lock_list.c 2009-02-08 00:03:02.000000000 -0500 +@@ -0,0 +1,107 @@ ++/* ++ * Copyright (C) 2006, Red Hat, Inc., Peter Zijlstra ++ * Licenced under the GPLv2. ++ * ++ * Simple fine grain locked double linked list. ++ * ++ * Locking order is from prev -> next. ++ * Edges are locked not nodes; that is, cur->lock protects: ++ * - cur->next, ++ * - cur->next->prev. ++ * ++ * Passed pointers are assumed to be stable by external means such as ++ * refcounts or RCU. The individual list entries are assumed to be RCU ++ * freed (requirement of __lock_list_del). ++ */ ++ ++#include ++ ++void lock_list_add(struct lock_list_head *new, ++ struct lock_list_head *list) ++{ ++ struct lock_list_head *next; ++ ++ spin_lock(&new->lock); ++ spin_lock_nested(&list->lock, LOCK_LIST_NESTING_PREV); ++ next = list->next; ++ __list_add(&new->head, &list->head, &next->head); ++ spin_unlock(&list->lock); ++ spin_unlock(&new->lock); ++} ++ ++static spinlock_t *__lock_list(struct lock_list_head *entry) ++{ ++ struct lock_list_head *prev; ++ spinlock_t *lock = NULL; ++ ++again: ++ prev = entry->prev; ++ if (prev == entry) ++ goto one; ++ spin_lock_nested(&prev->lock, LOCK_LIST_NESTING_PREV); ++ if (unlikely(entry->prev != prev)) { ++ /* ++ * we lost ++ */ ++ spin_unlock(&prev->lock); ++ goto again; ++ } ++ lock = &prev->lock; ++one: ++ spin_lock_nested(&entry->lock, LOCK_LIST_NESTING_CUR); ++ return lock; ++} ++ ++void lock_list_del_init(struct lock_list_head *entry) ++{ ++ spinlock_t *lock; ++ ++ rcu_read_lock(); ++ lock = __lock_list(entry); ++ list_del_init(&entry->head); ++ spin_unlock(&entry->lock); ++ if (lock) ++ spin_unlock(lock); ++ rcu_read_unlock(); ++} ++ ++void lock_list_splice_init(struct lock_list_head *list, ++ struct lock_list_head *head) ++{ ++ spinlock_t *lock; ++ ++ rcu_read_lock(); ++ lock = __lock_list(list); ++ if (!list_empty(&list->head)) { ++ spin_lock_nested(&head->lock, LOCK_LIST_NESTING_NEXT); ++ __list_splice(&list->head, &head->head); ++ INIT_LIST_HEAD(&list->head); ++ spin_unlock(&head->lock); ++ } ++ spin_unlock(&list->lock); ++ if (lock) ++ spin_unlock(lock); ++ rcu_read_unlock(); ++} ++ ++struct lock_list_head *lock_list_next_entry(struct lock_list_head *list, ++ struct lock_list_head *entry) ++{ ++ struct lock_list_head *next = entry->next; ++ if (likely(next != list)) { ++ lock_set_subclass(&entry->lock.dep_map, ++ LOCK_LIST_NESTING_CUR, _THIS_IP_); ++ spin_lock_nested(&next->lock, LOCK_LIST_NESTING_NEXT); ++ BUG_ON(entry->next != next); ++ } else ++ next = NULL; ++ spin_unlock(&entry->lock); ++ return next; ++} ++ ++struct lock_list_head *lock_list_first_entry(struct lock_list_head *list) ++{ ++ spin_lock(&list->lock); ++ return lock_list_next_entry(list, list); ++} ++ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0394-drain-all-local-pages-via-sched.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0394-drain-all-local-pages-via-sched.patch @@ -0,0 +1,55 @@ +--- + mm/page_alloc.c | 33 +++++++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +Index: linux-2.6.24.7-rt27/mm/page_alloc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/page_alloc.c 2009-02-08 00:01:58.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/page_alloc.c 2009-02-08 00:03:57.000000000 -0500 +@@ -1020,6 +1020,38 @@ void smp_drain_local_pages(void *arg) + */ + void drain_all_local_pages(void) + { ++#ifdef CONFIG_PREEMPT_RT ++ /* ++ * HACK!!!!! ++ * For RT we can't use IPIs to run drain_local_pages, since ++ * that code will call spin_locks that will now sleep. ++ * But, schedule_on_each_cpu will call kzalloc, which will ++ * call page_alloc which was what calls this. ++ * ++ * Luckily, there's a condition to get here, and that is if ++ * the order passed in to alloc_pages is greater than 0 ++ * (alloced more than a page size). The slabs only allocate ++ * what is needed, and the allocation made by schedule_on_each_cpu ++ * does an alloc of "sizeof(void *)*nr_cpu_ids". ++ * ++ * So we can safely call schedule_on_each_cpu if that number ++ * is less than a page. Otherwise don't bother. At least warn of ++ * this issue. ++ * ++ * And yes, this is one big hack. Please fix ;-) ++ */ ++ if (sizeof(void *)*nr_cpu_ids < PAGE_SIZE) ++ schedule_on_each_cpu(smp_drain_local_pages, NULL, 0, 1); ++ else { ++ static int once; ++ if (!once) { ++ printk(KERN_ERR "Can't drain all CPUS due to possible recursion\n"); ++ once = 1; ++ } ++ drain_local_pages(); ++ } ++ ++#else + unsigned long flags; + + local_irq_save(flags); +@@ -1027,6 +1059,7 @@ void drain_all_local_pages(void) + local_irq_restore(flags); + + smp_call_function(smp_drain_local_pages, NULL, 0, 1); ++#endif + } + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0260-kstat-fix-spurious-system-load-spikes-in-proc-loadavgrt.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0260-kstat-fix-spurious-system-load-spikes-in-proc-loadavgrt.patch @@ -0,0 +1,145 @@ +From lclaudio@uudg.org Fri Aug 17 21:40:37 2007 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.1.7-deb (2006-10-05) on debian +X-Spam-Level: +X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=ham + version=3.1.7-deb +Received: from sr02-01.mta.terra.com.br (sr02-01.mta.terra.com.br + [200.154.152.30]) by mail.tglx.de (Postfix) with ESMTP id 2E9BC65C3D9 for + ; Fri, 17 Aug 2007 21:40:37 +0200 (CEST) +Received: from tiaro.hst.terra.com.br (tiaro.hst.terra.com.br + [200.176.10.7]) by bundure.hst.terra.com.br (Postfix) with ESMTP id + 459344D7005C; Fri, 17 Aug 2007 16:40:34 -0300 (BRT) +X-Terra-Karma: -2% +X-Terra-Hash: 9bbc9fa12a67f4c16ad599245ee6a8fb +Received-SPF: none (tiaro.hst.terra.com.br: 200.176.10.7 is neither + permitted nor denied by domain of uudg.org) client-ip=200.176.10.7; + envelope-from=lclaudio@uudg.org; helo=lclaudio.dyndns.org; +Received: from lclaudio.dyndns.org (unknown [189.4.11.102]) (authenticated + user lc_poa) by tiaro.hst.terra.com.br (Postfix) with ESMTP id 97492214136; + Fri, 17 Aug 2007 16:40:32 -0300 (BRT) +Received: by lclaudio.dyndns.org (Postfix, from userid 500) id 7530B117DC8; + Fri, 17 Aug 2007 16:37:07 -0300 (BRT) +Date: Fri, 17 Aug 2007 16:37:06 -0300 +From: "Luis Claudio R. Goncalves" +To: Thomas Gleixner , Ingo Molnar +Subject: [PATCH] Fixes spurious system load spikes in /proc/loadavgrt +Message-ID: <20070817193706.GB18693@unix.sh> +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline +User-Agent: Mutt/1.5.14 (2007-02-12) +X-Evolution-Source: imap://tglx%40linutronix.de@localhost:8993/ +Content-Transfer-Encoding: 8bit + +Hi! + +The patch I sent to the list had a minor glitch in the path for the second +half of the diff. This is the fixed version. + +Sorry for any disturbance! + +Best regards, +Luis + + +Hello, + +The values in /proc/loadavgrt are sometimes the real load and sometimes +garbage. As you can see in th tests below, it occurs from in 2.6.21.5-rt20 +to 2.6.23-rc2-rt2. The code for calc_load(), in kernel/timer.c has not +changed much in -rt patches. + + [lclaudio@lab sandbox]$ ls /proc/loadavg* + /proc/loadavg /proc/loadavgrt + [lclaudio@lab sandbox]$ uname -a + Linux lab.casa 2.6.21-34.el5rt #1 SMP PREEMPT RT Thu Jul 12 15:26:48 EDT 2007 x86_64 x86_64 x86_64 GNU/Linux + [lclaudio@lab sandbox]$ cat /proc/loadavg* + 4.57 4.90 4.16 3/146 23499 + 0.44 0.98 1.78 0/146 23499 + ... + [lclaudio@lab sandbox]$ cat /proc/loadavg* + 4.65 4.80 4.75 5/144 20720 + 23896.04 -898421.23 383170.94 2/144 20720 + + [root@neverland ~]# uname -a + Linux neverland.casa 2.6.21.5-rt20 #2 SMP PREEMPT RT Fri Jul 1318:31:38 BRT 2007 i686 athlon i386 GNU/Linux + [root@neverland ~]# cat /proc/loadavg* + 0.16 0.16 0.15 1/184 11240 + 344.65 0.38 311.71 0/184 11240 + + [williams@torg ~]$ uname -a + Linux torg 2.6.23-rc2-rt2 #14 SMP PREEMPT RT Tue Aug 7 20:07:31 CDT 2007 x86_64 x86_64 x86_64 GNU/Linux + [williams@torg ~]$ cat /proc/loadavg* + 0.88 0.76 0.57 1/257 7267 + 122947.70 103790.53 -564712.87 0/257 7267 + +----------> + +Fixes spurious system load spikes observed in /proc/loadavgrt, as described in: + + Bug 253103: /proc/loadavgrt issues weird results + https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=253103 + +Signed-off-by: Luis Claudio R. Goncalves +--- + +--- + kernel/sched_rt.c | 7 +++++++ + kernel/timer.c | 14 ++++++++------ + 2 files changed, 15 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:02:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:02:49.000000000 -0500 +@@ -149,6 +149,13 @@ unsigned long rt_nr_uninterruptible(void + for_each_online_cpu(i) + sum += cpu_rq(i)->rt.rt_nr_uninterruptible; + ++ /* ++ * Since we read the counters lockless, it might be slightly ++ * inaccurate. Do not allow it to go below zero though: ++ */ ++ if (unlikely((long)sum < 0)) ++ sum = 0; ++ + return sum; + } + +Index: linux-2.6.24.7-rt27/kernel/timer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/timer.c 2009-02-08 00:02:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/timer.c 2009-02-08 00:02:49.000000000 -0500 +@@ -973,23 +973,25 @@ unsigned long avenrun_rt[3]; + static inline void calc_load(unsigned long ticks) + { + unsigned long active_tasks; /* fixed-point */ ++ unsigned long active_rt_tasks; /* fixed-point */ + static int count = LOAD_FREQ; + + count -= ticks; + if (unlikely(count < 0)) { + active_tasks = count_active_tasks(); ++ active_rt_tasks = count_active_rt_tasks(); + do { + CALC_LOAD(avenrun[0], EXP_1, active_tasks); + CALC_LOAD(avenrun[1], EXP_5, active_tasks); + CALC_LOAD(avenrun[2], EXP_15, active_tasks); +- count += LOAD_FREQ; +- } while (count < 0); + #ifdef CONFIG_PREEMPT_RT +- active_tasks = count_active_rt_tasks(); +- CALC_LOAD(avenrun_rt[0], EXP_1, active_tasks); +- CALC_LOAD(avenrun_rt[1], EXP_5, active_tasks); +- CALC_LOAD(avenrun_rt[2], EXP_15, active_tasks); ++ CALC_LOAD(avenrun_rt[0], EXP_1, active_tasks); ++ CALC_LOAD(avenrun_rt[1], EXP_5, active_tasks); ++ CALC_LOAD(avenrun_rt[2], EXP_15, active_tasks); + #endif ++ count += LOAD_FREQ; ++ ++ } while (count < 0); + } + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0133-arm-futex-atomic-cmpxchg.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0133-arm-futex-atomic-cmpxchg.patch @@ -0,0 +1,156 @@ +Implement futex macros for ARM + +Signed-off-by: Khem Raj +Signed-off-by: Nicolas Pitre +Signed-off-by: George Davis + + arch/arm/kernel/process.c | 2 + include/asm-arm/futex.h | 125 ++++++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 124 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/arm/kernel/process.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/process.c 2009-02-08 00:00:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/process.c 2009-02-08 00:01:45.000000000 -0500 +@@ -37,6 +37,8 @@ + #include + #include + ++DEFINE_SPINLOCK(futex_atomic_lock); ++ + static const char *processor_modes[] = { + "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , + "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26", +Index: linux-2.6.24.7-rt27/include/asm-arm/futex.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/futex.h 2009-02-08 00:00:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/futex.h 2009-02-08 00:01:45.000000000 -0500 +@@ -1,6 +1,125 @@ +-#ifndef _ASM_FUTEX_H +-#define _ASM_FUTEX_H ++#ifndef _ASM_ARM_FUTEX_H ++#define _ASM_ARM_FUTEX_H + +-#include ++#ifdef __KERNEL__ + ++#include ++#include ++#include ++ ++extern spinlock_t futex_atomic_lock; ++ ++#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ ++ __asm__ __volatile__ ( \ ++ "1: ldrt %1, [%2] \n" \ ++ insn \ ++ "2: strt %0, [%2] \n" \ ++ " mov %0, #0 \n" \ ++ "3: \n" \ ++ " .section __ex_table, \"a\" \n" \ ++ " .align 3 \n" \ ++ " .long 1b, 4f, 2b, 4f \n" \ ++ " .previous \n" \ ++ " .section .fixup,\"ax\" \n" \ ++ "4: mov %0, %4 \n" \ ++ " b 3b \n" \ ++ " .previous" \ ++ : "=&r" (ret), "=&r" (oldval) \ ++ : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ ++ : "cc", "memory") ++ ++static inline int ++futex_atomic_op_inuser (int encoded_op, int __user *uaddr) ++{ ++ int op = (encoded_op >> 28) & 7; ++ int cmp = (encoded_op >> 24) & 15; ++ int oparg = (encoded_op << 8) >> 20; ++ int cmparg = (encoded_op << 20) >> 20; ++ int oldval = 0, ret; ++ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) ++ oparg = 1 << oparg; ++ ++ if (!access_ok (VERIFY_WRITE, uaddr, sizeof(int))) ++ return -EFAULT; ++ ++ pagefault_disable(); ++ ++ spin_lock(&futex_atomic_lock); ++ ++ switch (op) { ++ case FUTEX_OP_SET: ++ __futex_atomic_op(" mov %0, %3\n", ++ ret, oldval, uaddr, oparg); ++ break; ++ case FUTEX_OP_ADD: ++ __futex_atomic_op(" add %0, %1, %3\n", ++ ret, oldval, uaddr, oparg); ++ break; ++ case FUTEX_OP_OR: ++ __futex_atomic_op(" orr %0, %1, %3\n", ++ ret, oldval, uaddr, oparg); ++ break; ++ case FUTEX_OP_ANDN: ++ __futex_atomic_op(" and %0, %1, %3\n", ++ ret, oldval, uaddr, oparg); ++ break; ++ case FUTEX_OP_XOR: ++ __futex_atomic_op(" eor %0, %1, %3\n", ++ ret, oldval, uaddr, oparg); ++ break; ++ default: ++ ret = -ENOSYS; ++ } ++ ++ spin_unlock(&futex_atomic_lock); ++ ++ pagefault_enable(); ++ ++ if (!ret) { ++ switch (cmp) { ++ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; ++ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; ++ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; ++ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; ++ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; ++ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; ++ default: ret = -ENOSYS; ++ } ++ } ++ return ret; ++} ++ ++static inline int ++futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) ++{ ++ int val; ++ ++ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) ++ return -EFAULT; ++ ++ spin_lock(&futex_atomic_lock); ++ ++ __asm__ __volatile__( "@futex_atomic_cmpxchg_inatomic \n" ++ "1: ldrt %0, [%3] \n" ++ " teq %0, %1 \n" ++ "2: streqt %2, [%3] \n" ++ "3: \n" ++ " .section __ex_table, \"a\" \n" ++ " .align 3 \n" ++ " .long 1b, 4f, 2b, 4f \n" ++ " .previous \n" ++ " .section .fixup,\"ax\" \n" ++ "4: mov %0, %4 \n" ++ " b 3b \n" ++ " .previous" ++ : "=&r" (val) ++ : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT) ++ : "cc"); ++ ++ spin_unlock(&futex_atomic_lock); ++ ++ return val; ++} ++ ++#endif + #endif --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0500-fix-adaptive-hack.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0500-fix-adaptive-hack.patch @@ -0,0 +1,84 @@ +Subject: fix-adaptive-hack.patch +From: Thomas Gleixner +Date: Tue, 17 Jun 2008 18:01:12 +0200 + +Signed-off-by: Thomas Gleixner +--- + kernel/rtmutex.c | 34 +++++++++------------------------- + 1 file changed, 9 insertions(+), 25 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:48.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:49.000000000 -0500 +@@ -774,41 +774,22 @@ update_current(unsigned long new_state, + static int adaptive_wait(struct rt_mutex_waiter *waiter, + struct task_struct *orig_owner) + { +- int sleep = 0; +- + for (;;) { + + /* we are the owner? */ + if (!waiter->task) +- break; ++ return 0; + +- /* +- * We need to read the owner of the lock and then check +- * its state. But we can't let the owner task be freed +- * while we read the state. We grab the rcu_lock and +- * this makes sure that the owner task wont disappear +- * between testing that it still has the lock, and checking +- * its state. +- */ +- rcu_read_lock(); + /* Owner changed? Then lets update the original */ +- if (orig_owner != rt_mutex_owner(waiter->lock)) { +- rcu_read_unlock(); +- break; +- } ++ if (orig_owner != rt_mutex_owner(waiter->lock)) ++ return 0; + + /* Owner went to bed, so should we */ +- if (!task_is_current(orig_owner)) { +- sleep = 1; +- rcu_read_unlock(); +- break; +- } +- rcu_read_unlock(); ++ if (!task_is_current(orig_owner)) ++ return 1; + + cpu_relax(); + } +- +- return sleep; + } + #else + static int adaptive_wait(struct rt_mutex_waiter *waiter, +@@ -889,11 +870,13 @@ rt_spin_lock_slowlock(struct rt_mutex *l + current->lock_depth = -1; + current->flags &= ~PF_NOSCHED; + orig_owner = rt_mutex_owner(lock); ++ get_task_struct(orig_owner); + spin_unlock_irqrestore(&lock->wait_lock, flags); + + debug_rt_mutex_print_deadlock(&waiter); + + if (adaptive_wait(&waiter, orig_owner)) { ++ put_task_struct(orig_owner); + update_current(TASK_UNINTERRUPTIBLE, &saved_state); + /* + * The xchg() in update_current() is an implicit +@@ -902,7 +885,8 @@ rt_spin_lock_slowlock(struct rt_mutex *l + */ + if (waiter.task) + schedule_rt_mutex(lock); +- } ++ } else ++ put_task_struct(orig_owner); + + spin_lock_irqsave(&lock->wait_lock, flags); + current->flags |= saved_flags; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0532-hotplug-smp-boot-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0532-hotplug-smp-boot-fix.patch @@ -0,0 +1,43 @@ +--- + arch/x86/kernel/head64.c | 1 + + arch/x86/kernel/smpboot_64.c | 2 +- + include/asm-x86/proto.h | 1 + + 3 files changed, 3 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/head64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/head64.c 2009-02-08 00:02:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/head64.c 2009-02-08 00:05:04.000000000 -0500 +@@ -70,6 +70,7 @@ void __init x86_64_start_kernel(char * r + cpu_pda(i) = &boot_cpu_pda[i]; + + pda_init(0); ++ allocate_stacks(0); + copy_bootdata(__va(real_mode_data)); + #ifdef CONFIG_SMP + cpu_set(0, cpu_online_map); +Index: linux-2.6.24.7-rt27/arch/x86/kernel/smpboot_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/smpboot_64.c 2009-02-08 00:04:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/smpboot_64.c 2009-02-08 00:05:04.000000000 -0500 +@@ -538,7 +538,7 @@ static void __cpuinit do_fork_idle(struc + static char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ] + __attribute__((section(".bss.page_aligned"))); + +-static int __cpuinit allocate_stacks(int cpu) ++int __cpuinit allocate_stacks(int cpu) + { + static const unsigned int order[N_EXCEPTION_STACKS] = { + [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, +Index: linux-2.6.24.7-rt27/include/asm-x86/proto.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/proto.h 2009-02-07 23:59:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/proto.h 2009-02-08 00:05:04.000000000 -0500 +@@ -10,6 +10,7 @@ struct pt_regs; + + extern void start_kernel(void); + extern void pda_init(int); ++extern int allocate_stacks(int cpu); + + extern void early_idt_handler(void); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0061-ftrace-update-cnt-stat-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0061-ftrace-update-cnt-stat-fix.patch @@ -0,0 +1,53 @@ +From sagar.abhishek@gmail.com Tue May 27 11:54:47 2008 +Date: Sun, 25 May 2008 00:10:04 +0530 +From: Abhishek Sagar +To: Ingo Molnar , rostedt@goodmis.org +Cc: LKML +Subject: [PATCH] ftrace: fix updating of ftrace_update_cnt + +Hi Ingo/Steven, + +Ftrace currently maintains an update count which includes false updates, i.e, updates which failed. If anything, such failures should be tracked by some separate variable, but this patch provides a minimal fix. + +Signed-off-by: Abhishek Sagar +--- +fix updating of ftrace_update_cnt + +--- + kernel/trace/ftrace.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/trace/ftrace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/ftrace.c 2009-02-08 00:01:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/ftrace.c 2009-02-08 00:01:12.000000000 -0500 +@@ -452,7 +452,7 @@ static void ftrace_shutdown_replenish(vo + ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL); + } + +-static void ++static int + ftrace_code_disable(struct dyn_ftrace *rec) + { + unsigned long ip; +@@ -468,7 +468,9 @@ ftrace_code_disable(struct dyn_ftrace *r + if (failed) { + rec->flags |= FTRACE_FL_FAILED; + ftrace_free_rec(rec); ++ return 0; + } ++ return 1; + } + + static int __ftrace_update_code(void *ignore); +@@ -643,8 +645,8 @@ static int __ftrace_update_code(void *ig + + /* all CPUS are stopped, we are safe to modify code */ + hlist_for_each_entry(p, t, &head, node) { +- ftrace_code_disable(p); +- ftrace_update_cnt++; ++ if (ftrace_code_disable(p)) ++ ftrace_update_cnt++; + } + + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0131-arm-fix-atomic-cmpxchg.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0131-arm-fix-atomic-cmpxchg.patch @@ -0,0 +1,21 @@ +--- + include/asm-arm/atomic.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/include/asm-arm/atomic.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/atomic.h 2009-02-08 00:01:44.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/atomic.h 2009-02-08 00:01:44.000000000 -0500 +@@ -189,10 +189,10 @@ static inline unsigned long __cmpxchg(vo + volatile unsigned long *p = ptr; + + if (size == 4) { +- local_irq_save(flags); ++ raw_local_irq_save(flags); + if ((prev = *p) == old) + *p = new; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + return(prev); + } else + return wrong_size_cmpxchg(ptr); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0089-rtmutex-debug.h-cleanup.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0089-rtmutex-debug.h-cleanup.patch @@ -0,0 +1,38 @@ +Subject: [patch] lock debugging: clean up rtmutex-debug.h +From: Ingo Molnar + +style cleanups. + +Signed-off-by: Ingo Molnar +--- + kernel/rtmutex-debug.h | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex-debug.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex-debug.h 2009-02-08 00:00:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex-debug.h 2009-02-08 00:01:25.000000000 -0500 +@@ -17,17 +17,17 @@ extern void debug_rt_mutex_free_waiter(s + extern void debug_rt_mutex_init(struct rt_mutex *lock, const char *name); + extern void debug_rt_mutex_lock(struct rt_mutex *lock); + extern void debug_rt_mutex_unlock(struct rt_mutex *lock); +-extern void debug_rt_mutex_proxy_lock(struct rt_mutex *lock, +- struct task_struct *powner); ++extern void ++debug_rt_mutex_proxy_lock(struct rt_mutex *lock, struct task_struct *powner); + extern void debug_rt_mutex_proxy_unlock(struct rt_mutex *lock); + extern void debug_rt_mutex_deadlock(int detect, struct rt_mutex_waiter *waiter, + struct rt_mutex *lock); + extern void debug_rt_mutex_print_deadlock(struct rt_mutex_waiter *waiter); +-# define debug_rt_mutex_reset_waiter(w) \ ++# define debug_rt_mutex_reset_waiter(w) \ + do { (w)->deadlock_lock = NULL; } while (0) + +-static inline int debug_rt_mutex_detect_deadlock(struct rt_mutex_waiter *waiter, +- int detect) ++static inline int ++debug_rt_mutex_detect_deadlock(struct rt_mutex_waiter *waiter, int detect) + { +- return (waiter != NULL); ++ return waiter != NULL; + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0095-floppy-resume-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0095-floppy-resume-fix.patch @@ -0,0 +1,77 @@ +Subject: [patch] floppy: suspend/resume fix +From: Ingo Molnar + +introduce a floppy platform-driver and suspend/resume ops to +stop/start the floppy driver. Bug reported by Mikael Pettersson. + +Signed-off-by: Ingo Molnar +--- + drivers/block/floppy.c | 31 ++++++++++++++++++++++++++++++- + 1 file changed, 30 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/drivers/block/floppy.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/block/floppy.c 2009-02-08 00:00:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/block/floppy.c 2009-02-08 00:01:27.000000000 -0500 +@@ -4149,6 +4149,28 @@ static void floppy_device_release(struct + complete(&device_release); + } + ++static int floppy_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ floppy_release_irq_and_dma(); ++ ++ return 0; ++} ++ ++static int floppy_resume(struct platform_device *dev) ++{ ++ floppy_grab_irq_and_dma(); ++ ++ return 0; ++} ++ ++static struct platform_driver floppy_driver = { ++ .suspend = floppy_suspend, ++ .resume = floppy_resume, ++ .driver = { ++ .name = "floppy", ++ }, ++}; ++ + static struct platform_device floppy_device[N_DRIVE]; + + static struct kobject *floppy_find(dev_t dev, int *part, void *data) +@@ -4197,10 +4219,14 @@ static int __init floppy_init(void) + if (err) + goto out_put_disk; + ++ err = platform_driver_register(&floppy_driver); ++ if (err) ++ goto out_unreg_blkdev; ++ + floppy_queue = blk_init_queue(do_fd_request, &floppy_lock); + if (!floppy_queue) { + err = -ENOMEM; +- goto out_unreg_blkdev; ++ goto out_unreg_driver; + } + blk_queue_max_sectors(floppy_queue, 64); + +@@ -4349,6 +4375,8 @@ out_flush_work: + out_unreg_region: + blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); + blk_cleanup_queue(floppy_queue); ++out_unreg_driver: ++ platform_driver_unregister(&floppy_driver); + out_unreg_blkdev: + unregister_blkdev(FLOPPY_MAJOR, "fd"); + out_put_disk: +@@ -4544,6 +4572,7 @@ void cleanup_module(void) + init_completion(&device_release); + blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); + unregister_blkdev(FLOPPY_MAJOR, "fd"); ++ platform_driver_unregister(&floppy_driver); + + for (drive = 0; drive < N_DRIVE; drive++) { + del_timer_sync(&motor_off_timer[drive]); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0046-0034-sched-style-cleanup-2.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0046-0034-sched-style-cleanup-2.patch @@ -0,0 +1,121 @@ +From 9a98470df9d0bd5860ea0c9a1c16d373c242e248 Mon Sep 17 00:00:00 2001 +From: Ingo Molnar +Date: Tue, 11 Dec 2007 10:02:43 +0100 +Subject: [PATCH] sched: style cleanup, #2 + +style cleanup of various changes that were done recently. + +no code changed: + + text data bss dec hex filename + 26399 2578 48 29025 7161 sched.o.before + 26399 2578 48 29025 7161 sched.o.after + +Signed-off-by: Ingo Molnar + +--- + kernel/sched.c | 28 +++++++++++++++------------- + 1 file changed, 15 insertions(+), 13 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:01:03.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:01:05.000000000 -0500 +@@ -186,12 +186,12 @@ static struct cfs_rq *init_cfs_rq_p[NR_C + * Every task in system belong to this group at bootup. + */ + struct task_group init_task_group = { +- .se = init_sched_entity_p, ++ .se = init_sched_entity_p, + .cfs_rq = init_cfs_rq_p, + }; + + #ifdef CONFIG_FAIR_USER_SCHED +-# define INIT_TASK_GRP_LOAD 2*NICE_0_LOAD ++# define INIT_TASK_GRP_LOAD (2*NICE_0_LOAD) + #else + # define INIT_TASK_GRP_LOAD NICE_0_LOAD + #endif +@@ -277,8 +277,8 @@ struct rt_rq { + + /* + * We add the notion of a root-domain which will be used to define per-domain +- * variables. Each exclusive cpuset essentially defines an island domain by +- * fully partitioning the member cpus from any other cpuset. Whenever a new ++ * variables. Each exclusive cpuset essentially defines an island domain by ++ * fully partitioning the member cpus from any other cpuset. Whenever a new + * exclusive cpuset is created, we also create and attach a new root-domain + * object. + * +@@ -290,12 +290,12 @@ struct root_domain { + cpumask_t span; + cpumask_t online; + +- /* ++ /* + * The "RT overload" flag: it gets set if a CPU has more than + * one runnable RT task. + */ + cpumask_t rto_mask; +- atomic_t rto_count; ++ atomic_t rto_count; + }; + + static struct root_domain def_root_domain; +@@ -359,7 +359,7 @@ struct rq { + atomic_t nr_iowait; + + #ifdef CONFIG_SMP +- struct root_domain *rd; ++ struct root_domain *rd; + struct sched_domain *sd; + + /* For active balancing */ +@@ -5053,7 +5053,7 @@ int set_cpus_allowed(struct task_struct + if (p->sched_class->set_cpus_allowed) + p->sched_class->set_cpus_allowed(p, &new_mask); + else { +- p->cpus_allowed = new_mask; ++ p->cpus_allowed = new_mask; + p->nr_cpus_allowed = cpus_weight(new_mask); + } + +@@ -5840,9 +5840,10 @@ static void rq_attach_root(struct rq *rq + if (rq->rd) { + struct root_domain *old_rd = rq->rd; + +- for (class = sched_class_highest; class; class = class->next) ++ for (class = sched_class_highest; class; class = class->next) { + if (class->leave_domain) + class->leave_domain(rq); ++ } + + cpu_clear(rq->cpu, old_rd->span); + cpu_clear(rq->cpu, old_rd->online); +@@ -5854,9 +5855,10 @@ static void rq_attach_root(struct rq *rq + atomic_inc(&rd->refcount); + rq->rd = rd; + +- for (class = sched_class_highest; class; class = class->next) ++ for (class = sched_class_highest; class; class = class->next) { + if (class->join_domain) + class->join_domain(rq); ++ } + + spin_unlock_irqrestore(&rq->lock, flags); + } +@@ -5891,11 +5893,11 @@ static struct root_domain *alloc_rootdom + } + + /* +- * Attach the domain 'sd' to 'cpu' as its base domain. Callers must ++ * Attach the domain 'sd' to 'cpu' as its base domain. Callers must + * hold the hotplug lock. + */ +-static void cpu_attach_domain(struct sched_domain *sd, +- struct root_domain *rd, int cpu) ++static void ++cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu) + { + struct rq *rq = cpu_rq(cpu); + struct sched_domain *tmp; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0032-0018-sched-RT-balance-optimize.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0032-0018-sched-RT-balance-optimize.patch @@ -0,0 +1,79 @@ +From 1dcf532e3660c064d4ff53deabcd6167ff854af8 Mon Sep 17 00:00:00 2001 +From: Gregory Haskins +Date: Tue, 11 Dec 2007 10:02:38 +0100 +Subject: [PATCH] sched: RT-balance, optimize + +We can cheaply track the number of bits set in the cpumask for the lowest +priority CPUs. Therefore, compute the mask's weight and use it to skip +the optimal domain search logic when there is only one CPU available. + +Signed-off-by: Gregory Haskins +Signed-off-by: Ingo Molnar + +--- + kernel/sched_rt.c | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:00:58.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:00:59.000000000 -0500 +@@ -299,7 +299,7 @@ static int find_lowest_cpus(struct task_ + int cpu; + cpumask_t *valid_mask = &__get_cpu_var(valid_cpu_mask); + int lowest_prio = -1; +- int ret = 0; ++ int count = 0; + + cpus_clear(*lowest_mask); + cpus_and(*valid_mask, cpu_online_map, task->cpus_allowed); +@@ -312,7 +312,7 @@ static int find_lowest_cpus(struct task_ + + /* We look for lowest RT prio or non-rt CPU */ + if (rq->rt.highest_prio >= MAX_RT_PRIO) { +- if (ret) ++ if (count) + cpus_clear(*lowest_mask); + cpu_set(rq->cpu, *lowest_mask); + return 1; +@@ -324,14 +324,17 @@ static int find_lowest_cpus(struct task_ + if (rq->rt.highest_prio > lowest_prio) { + /* new low - clear old data */ + lowest_prio = rq->rt.highest_prio; +- cpus_clear(*lowest_mask); ++ if (count) { ++ cpus_clear(*lowest_mask); ++ count = 0; ++ } + } + cpu_set(rq->cpu, *lowest_mask); +- ret = 1; ++ count++; + } + } + +- return ret; ++ return count; + } + + static inline int pick_optimal_cpu(int this_cpu, cpumask_t *mask) +@@ -355,9 +358,17 @@ static int find_lowest_rq(struct task_st + cpumask_t *lowest_mask = &__get_cpu_var(local_cpu_mask); + int this_cpu = smp_processor_id(); + int cpu = task_cpu(task); ++ int count = find_lowest_cpus(task, lowest_mask); + +- if (!find_lowest_cpus(task, lowest_mask)) +- return -1; ++ if (!count) ++ return -1; /* No targets found */ ++ ++ /* ++ * There is no sense in performing an optimal search if only one ++ * target is found. ++ */ ++ if (count == 1) ++ return first_cpu(*lowest_mask); + + /* + * At this point we have built a mask of cpus representing the --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0063-tracer-add-event-markers.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0063-tracer-add-event-markers.patch @@ -0,0 +1,306 @@ +Add markers to various events + +This patch adds markers to various events in the kernel. +(interrupts, task activation and hrtimers) + +Signed-off-by: Steven Rostedt +--- + arch/x86/kernel/apic_32.c | 3 ++ + arch/x86/kernel/irq_32.c | 3 ++ + arch/x86/kernel/irq_64.c | 4 +++ + arch/x86/kernel/traps_32.c | 4 +++ + arch/x86/kernel/traps_64.c | 4 +++ + arch/x86/mm/fault_32.c | 4 +++ + arch/x86/mm/fault_64.c | 4 +++ + include/linux/ftrace.h | 49 +++++++++++++++++++++++++++++++++++++++++++++ + kernel/hrtimer.c | 6 +++++ + kernel/sched.c | 7 ++++++ + 10 files changed, 88 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/apic_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/apic_32.c 2009-02-08 00:00:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/apic_32.c 2009-02-08 00:01:13.000000000 -0500 +@@ -45,6 +45,8 @@ + + #include "io_ports.h" + ++#include ++ + /* + * Sanity check + */ +@@ -581,6 +583,7 @@ void fastcall smp_apic_timer_interrupt(s + { + struct pt_regs *old_regs = set_irq_regs(regs); + ++ ftrace_event_irq(-1, user_mode(regs), regs->eip); + /* + * NOTE! We'd better ACK the irq immediately, + * because timer handling can be slow. +Index: linux-2.6.24.7-rt27/arch/x86/kernel/irq_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/irq_32.c 2009-02-08 00:00:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/irq_32.c 2009-02-08 00:01:13.000000000 -0500 +@@ -16,6 +16,8 @@ + #include + #include + ++#include ++ + #include + #include + +@@ -85,6 +87,7 @@ fastcall unsigned int do_IRQ(struct pt_r + + old_regs = set_irq_regs(regs); + irq_enter(); ++ ftrace_event_irq(irq, user_mode(regs), regs->eip); + #ifdef CONFIG_DEBUG_STACKOVERFLOW + /* Debugging check for stack overflow: is there less than 1KB free? */ + { +Index: linux-2.6.24.7-rt27/arch/x86/kernel/irq_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/irq_64.c 2009-02-08 00:00:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/irq_64.c 2009-02-08 00:01:13.000000000 -0500 +@@ -18,6 +18,8 @@ + #include + #include + ++#include ++ + atomic_t irq_err_count; + + #ifdef CONFIG_DEBUG_STACKOVERFLOW +@@ -149,6 +151,8 @@ asmlinkage unsigned int do_IRQ(struct pt + irq_enter(); + irq = __get_cpu_var(vector_irq)[vector]; + ++ ftrace_event_irq(irq, user_mode(regs), regs->rip); ++ + #ifdef CONFIG_DEBUG_STACKOVERFLOW + stack_overflow_check(regs); + #endif +Index: linux-2.6.24.7-rt27/arch/x86/kernel/traps_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/traps_32.c 2009-02-08 00:00:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/traps_32.c 2009-02-08 00:01:13.000000000 -0500 +@@ -30,6 +30,8 @@ + #include + #include + ++#include ++ + #ifdef CONFIG_EISA + #include + #include +@@ -769,6 +771,8 @@ fastcall __kprobes void do_nmi(struct pt + + nmi_enter(); + ++ ftrace_event_irq(-1, user_mode(regs), regs->eip); ++ + cpu = smp_processor_id(); + + ++nmi_count(cpu); +Index: linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/traps_64.c 2009-02-08 00:00:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c 2009-02-08 00:01:13.000000000 -0500 +@@ -33,6 +33,8 @@ + #include + #include + ++#include ++ + #if defined(CONFIG_EDAC) + #include + #endif +@@ -782,6 +784,8 @@ asmlinkage __kprobes void default_do_nmi + + cpu = smp_processor_id(); + ++ ftrace_event_irq(-1, user_mode(regs), regs->rip); ++ + /* Only the BSP gets external NMIs from the system. */ + if (!cpu) + reason = get_nmi_reason(); +Index: linux-2.6.24.7-rt27/arch/x86/mm/fault_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/mm/fault_32.c 2009-02-08 00:00:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/mm/fault_32.c 2009-02-08 00:01:13.000000000 -0500 +@@ -27,6 +27,8 @@ + #include + #include + ++#include ++ + #include + #include + #include +@@ -311,6 +313,8 @@ fastcall void __kprobes do_page_fault(st + /* get the address */ + address = read_cr2(); + ++ ftrace_event_fault(regs->eip, error_code, address); ++ + tsk = current; + + si_code = SEGV_MAPERR; +Index: linux-2.6.24.7-rt27/arch/x86/mm/fault_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/mm/fault_64.c 2009-02-08 00:00:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/mm/fault_64.c 2009-02-08 00:01:13.000000000 -0500 +@@ -27,6 +27,8 @@ + #include + #include + ++#include ++ + #include + #include + #include +@@ -316,6 +318,8 @@ asmlinkage void __kprobes do_page_fault( + /* get the address */ + address = read_cr2(); + ++ ftrace_event_fault(regs->rip, error_code, address); ++ + info.si_code = SEGV_MAPERR; + + +Index: linux-2.6.24.7-rt27/include/linux/ftrace.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/ftrace.h 2009-02-08 00:01:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/ftrace.h 2009-02-08 00:01:13.000000000 -0500 +@@ -4,6 +4,7 @@ + #ifdef CONFIG_FTRACE + + #include ++#include + #include + + extern int ftrace_enabled; +@@ -136,4 +137,52 @@ static inline void + ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) { } + #endif + ++#ifdef CONFIG_EVENT_TRACER ++#include ++ ++static inline void ftrace_event_irq(int irq, int user, unsigned long ip) ++{ ++ trace_mark(ftrace_event_irq, "%d %d %ld", irq, user, ip); ++} ++ ++static inline void ftrace_event_fault(unsigned long ip, unsigned long error, ++ unsigned long addr) ++{ ++ trace_mark(ftrace_event_fault, "%ld %ld %ld", ip, error, addr); ++} ++ ++static inline void ftrace_event_timer_set(void *p1, void *p2) ++{ ++ trace_mark(ftrace_event_timer_set, "%p %p", p1, p2); ++} ++ ++static inline void ftrace_event_timer_triggered(void *p1, void *p2) ++{ ++ trace_mark(ftrace_event_timer_triggered, "%p %p", p1, p2); ++} ++ ++static inline void ftrace_event_timestamp(ktime_t *time) ++{ ++ trace_mark(ftrace_event_hrtimer, "%p", time); ++} ++ ++static inline void ftrace_event_task_activate(struct task_struct *p, int cpu) ++{ ++ trace_mark(ftrace_event_task_activate, "%p %d", p, cpu); ++} ++ ++static inline void ftrace_event_task_deactivate(struct task_struct *p, int cpu) ++{ ++ trace_mark(ftrace_event_task_deactivate, "%p %d", p, cpu); ++} ++#else ++# define ftrace_event_irq(irq, user, ip) do { } while (0) ++# define ftrace_event_fault(ip, error, addr) do { } while (0) ++# define ftrace_event_timer_set(p1, p2) do { } while (0) ++# define ftrace_event_timer_triggered(p1, p2) do { } while (0) ++# define ftrace_event_timestamp(now) do { } while (0) ++# define ftrace_event_task_activate(p, cpu) do { } while (0) ++# define ftrace_event_task_deactivate(p, cpu) do { } while (0) ++#endif /* CONFIG_TRACE_EVENTS */ ++ + #endif /* _LINUX_FTRACE_H */ +Index: linux-2.6.24.7-rt27/kernel/hrtimer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/hrtimer.c 2009-02-08 00:00:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/hrtimer.c 2009-02-08 00:01:13.000000000 -0500 +@@ -44,6 +44,8 @@ + #include + #include + ++#include ++ + #include + + /** +@@ -742,6 +744,7 @@ static void enqueue_hrtimer(struct hrtim + struct hrtimer *entry; + int leftmost = 1; + ++ ftrace_event_timer_set(&timer->expires, timer); + /* + * Find the right place in the rbtree: + */ +@@ -1094,6 +1097,7 @@ void hrtimer_interrupt(struct clock_even + + retry: + now = ktime_get(); ++ ftrace_event_timestamp(&now); + + expires_next.tv64 = KTIME_MAX; + +@@ -1122,6 +1126,8 @@ void hrtimer_interrupt(struct clock_even + break; + } + ++ ftrace_event_timer_triggered(&timer->expires, timer); ++ + /* Move softirq callbacks to the pending list */ + if (timer->cb_mode == HRTIMER_CB_SOFTIRQ) { + __remove_hrtimer(timer, base, +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:01:13.000000000 -0500 +@@ -91,6 +91,11 @@ unsigned long long __attribute__((weak)) + #define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20) + #define TASK_NICE(p) PRIO_TO_NICE((p)->static_prio) + ++#define __PRIO(prio) \ ++ ((prio) <= 99 ? 199 - (prio) : (prio) - 120) ++ ++#define PRIO(p) __PRIO((p)->prio) ++ + /* + * 'User priority' is the nice value converted to something we + * can work with better when scaling various scheduler parameters, +@@ -1119,6 +1124,7 @@ static void activate_task(struct rq *rq, + if (p->state == TASK_UNINTERRUPTIBLE) + rq->nr_uninterruptible--; + ++ ftrace_event_task_activate(p, cpu_of(rq)); + enqueue_task(rq, p, wakeup); + inc_nr_running(p, rq); + } +@@ -1131,6 +1137,7 @@ static void deactivate_task(struct rq *r + if (p->state == TASK_UNINTERRUPTIBLE) + rq->nr_uninterruptible++; + ++ ftrace_event_task_deactivate(p, cpu_of(rq)); + dequeue_task(rq, p, sleep); + dec_nr_running(p, rq); + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0434-nmi-watchdog-fix-3.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0434-nmi-watchdog-fix-3.patch @@ -0,0 +1,61 @@ +From h-shimamoto@ct.jp.nec.com Thu May 15 10:15:00 2008 +Date: Mon, 28 Apr 2008 11:17:48 -0700 +From: Hiroshi Shimamoto +To: Ingo Molnar , Steven Rostedt , + Thomas Gleixner +Cc: linux-kernel@vger.kernel.org, linux-rt-users@vger.kernel.org +Subject: [PATCH -rt 3/4] x86: nmi_watchdog NMI needed for + irq_show_regs_callback() + +From: Hiroshi Shimamoto + +The -rt kernel doesn't panic immediately when NMI lockup detected. +Because the kernel waits show_regs on all cpus, but NMI is not come so +frequently. + +Signed-off-by: Hiroshi Shimamoto +--- + arch/x86/kernel/nmi_32.c | 7 +++++++ + arch/x86/kernel/nmi_64.c | 8 +++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_32.c 2009-02-08 00:04:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c 2009-02-08 00:04:17.000000000 -0500 +@@ -428,6 +428,13 @@ nmi_watchdog_tick(struct pt_regs * regs, + if (i == cpu) + continue; + nmi_show_regs[i] = 1; ++ } ++ ++ smp_send_nmi_allbutself(); ++ ++ for_each_online_cpu(i) { ++ if (i == cpu) ++ continue; + while (nmi_show_regs[i] == 1) + cpu_relax(); + } +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_64.c 2009-02-08 00:04:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c 2009-02-08 00:04:17.000000000 -0500 +@@ -413,10 +413,16 @@ nmi_watchdog_tick(struct pt_regs * regs, + if (i == cpu) + continue; + nmi_show_regs[i] = 1; ++ } ++ ++ smp_send_nmi_allbutself(); ++ ++ for_each_online_cpu(i) { ++ if (i == cpu) ++ continue; + while (nmi_show_regs[i] == 1) + cpu_relax(); + } +- + die_nmi("NMI Watchdog detected LOCKUP on CPU %d\n", regs, + panic_on_timeout); + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0114-lockdep-lock_set_subclass.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0114-lockdep-lock_set_subclass.patch @@ -0,0 +1,123 @@ +Subject: [patch] lockdep: lock_set_subclass - reset a held lock's subclass +From: Peter Zijlstra + +this can be used to reset a held lock's subclass, for arbitrary-depth +iterated data structures such as trees or lists which have per-node +locks. + +Signed-off-by: Peter Zijlstra +Signed-off-by: Ingo Molnar +--- + include/linux/lockdep.h | 4 ++ + kernel/lockdep.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 73 insertions(+) + +Index: linux-2.6.24.7-rt27/include/linux/lockdep.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/lockdep.h 2009-02-08 00:00:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/lockdep.h 2009-02-08 00:01:36.000000000 -0500 +@@ -304,6 +304,9 @@ extern void lock_acquire(struct lockdep_ + extern void lock_release(struct lockdep_map *lock, int nested, + unsigned long ip); + ++extern void lock_set_subclass(struct lockdep_map *lock, unsigned int subclass, ++ unsigned long ip); ++ + # define INIT_LOCKDEP .lockdep_recursion = 0, + + #define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) +@@ -320,6 +323,7 @@ static inline void lockdep_on(void) + + # define lock_acquire(l, s, t, r, c, i) do { } while (0) + # define lock_release(l, n, i) do { } while (0) ++# define lock_set_subclass(l, s, i) do { } while (0) + # define lockdep_init() do { } while (0) + # define lockdep_info() do { } while (0) + # define lockdep_init_map(lock, name, key, sub) do { (void)(key); } while (0) +Index: linux-2.6.24.7-rt27/kernel/lockdep.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/lockdep.c 2009-02-08 00:01:36.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/lockdep.c 2009-02-08 00:01:36.000000000 -0500 +@@ -2539,6 +2539,55 @@ static int check_unlock(struct task_stru + return 1; + } + ++static int ++__lock_set_subclass(struct lockdep_map *lock, ++ unsigned int subclass, unsigned long ip) ++{ ++ struct task_struct *curr = current; ++ struct held_lock *hlock, *prev_hlock; ++ struct lock_class *class; ++ unsigned int depth; ++ int i; ++ ++ depth = curr->lockdep_depth; ++ if (DEBUG_LOCKS_WARN_ON(!depth)) ++ return 0; ++ ++ prev_hlock = NULL; ++ for (i = depth-1; i >= 0; i--) { ++ hlock = curr->held_locks + i; ++ /* ++ * We must not cross into another context: ++ */ ++ if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) ++ break; ++ if (hlock->instance == lock) ++ goto found_it; ++ prev_hlock = hlock; ++ } ++ return print_unlock_inbalance_bug(curr, lock, ip); ++ ++found_it: ++ class = register_lock_class(lock, subclass, 0); ++ hlock->class = class; ++ ++ curr->lockdep_depth = i; ++ curr->curr_chain_key = hlock->prev_chain_key; ++ ++ for (; i < depth; i++) { ++ hlock = curr->held_locks + i; ++ if (!__lock_acquire(hlock->instance, ++ hlock->class->subclass, hlock->trylock, ++ hlock->read, hlock->check, hlock->hardirqs_off, ++ hlock->acquire_ip)) ++ return 0; ++ } ++ ++ if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth)) ++ return 0; ++ return 1; ++} ++ + /* + * Remove the lock to the list of currently held locks in a + * potentially non-nested (out of order) manner. This is a +@@ -2702,6 +2751,26 @@ static void check_flags(unsigned long fl + #endif + } + ++void ++lock_set_subclass(struct lockdep_map *lock, ++ unsigned int subclass, unsigned long ip) ++{ ++ unsigned long flags; ++ ++ if (unlikely(current->lockdep_recursion)) ++ return; ++ ++ raw_local_irq_save(flags); ++ current->lockdep_recursion = 1; ++ check_flags(flags); ++ if (__lock_set_subclass(lock, subclass, ip)) ++ check_chain_key(current); ++ current->lockdep_recursion = 0; ++ raw_local_irq_restore(flags); ++} ++ ++EXPORT_SYMBOL_GPL(lock_set_subclass); ++ + /* + * We are not always called with irqs disabled - do that here, + * and also avoid lockdep recursion: --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0581-linux-2.6-dynticks-off-by-default.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0581-linux-2.6-dynticks-off-by-default.patch @@ -0,0 +1,24 @@ +Default boot behavior to dynticks off. + +From: Jon Masters + + +--- + + kernel/time/tick-sched.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + + +diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c +index a70a98c..ae7f394 100644 +--- a/kernel/time/tick-sched.c ++++ b/kernel/time/tick-sched.c +@@ -95,7 +95,7 @@ static ktime_t tick_init_jiffy_update(void) + /* + * NO HZ enabled ? + */ +-static int tick_nohz_enabled __read_mostly = 1; ++static int tick_nohz_enabled __read_mostly = 0; + + /* + * Enable / Disable tickless mode --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0269-preempt-realtime-supress-rtc-printk.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0269-preempt-realtime-supress-rtc-printk.patch @@ -0,0 +1,19 @@ +--- + drivers/char/rtc.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: linux-2.6.24.7-rt27/drivers/char/rtc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/char/rtc.c 2009-02-08 00:01:36.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/char/rtc.c 2009-02-08 00:02:53.000000000 -0500 +@@ -1341,8 +1341,10 @@ static void rtc_dropped_irq(unsigned lon + + spin_unlock_irq(&rtc_lock); + ++#ifndef CONFIG_PREEMPT_RT + if (printk_ratelimit()) + printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq); ++#endif + + /* Now we have new data */ + wake_up_interruptible(&rtc_wait); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0085-arm-leds-timer.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0085-arm-leds-timer.patch @@ -0,0 +1,28 @@ +The clockevent layer now handles everything done by the ARM +timer_tick() call, except the LED stuff. Here we add an +arch_tick_leds() to handle LED toggling which is called by +do_timer(). + +Signed-off-by: Kevin Hilman +--- + arch/arm/kernel/time.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/arm/kernel/time.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/time.c 2009-02-08 00:00:23.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/time.c 2009-02-08 00:01:23.000000000 -0500 +@@ -236,6 +236,13 @@ static inline void do_leds(void) + #define do_leds() + #endif + ++void arch_tick_leds(void) ++{ ++#ifdef CONFIG_LEDS_TIMER ++ do_leds(); ++#endif ++} ++ + #ifndef CONFIG_GENERIC_TIME + void do_gettimeofday(struct timeval *tv) + { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0341-schedule_on_each_cpu-enhance.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0341-schedule_on_each_cpu-enhance.patch @@ -0,0 +1,143 @@ +It always bothered me a bit that on_each_cpu() and +schedule_on_each_cpu() had wildly different interfaces. + +Rectify this and convert the sole in-kernel user to the new interface. + +Signed-off-by: Peter Zijlstra +Acked-by: Ingo Molnar +--- + include/linux/workqueue.h | 2 - + kernel/workqueue.c | 63 ++++++++++++++++++++++++++++++++++++++-------- + mm/swap.c | 4 +- + 3 files changed, 56 insertions(+), 13 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/workqueue.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/workqueue.h 2009-02-08 00:03:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/workqueue.h 2009-02-08 00:03:33.000000000 -0500 +@@ -196,7 +196,7 @@ extern int FASTCALL(schedule_delayed_wor + extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, + unsigned long delay); + extern int schedule_on_each_cpu_wq(struct workqueue_struct *wq, work_func_t func); +-extern int schedule_on_each_cpu(work_func_t func); ++extern int schedule_on_each_cpu(void (*func)(void *info), void *info, int retry, int wait); + extern int current_is_keventd(void); + extern int keventd_up(void); + +Index: linux-2.6.24.7-rt27/kernel/workqueue.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/workqueue.c 2009-02-08 00:03:23.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/workqueue.c 2009-02-08 00:03:33.000000000 -0500 +@@ -594,9 +594,28 @@ int schedule_delayed_work_on(int cpu, + } + EXPORT_SYMBOL(schedule_delayed_work_on); + ++struct schedule_on_each_cpu_work { ++ struct work_struct work; ++ void (*func)(void *info); ++ void *info; ++}; ++ ++static void schedule_on_each_cpu_func(struct work_struct *work) ++{ ++ struct schedule_on_each_cpu_work *w; ++ ++ w = container_of(work, typeof(*w), work); ++ w->func(w->info); ++ ++ kfree(w); ++} ++ + /** + * schedule_on_each_cpu - call a function on each online CPU from keventd + * @func: the function to call ++ * @info: data to pass to function ++ * @retry: ignored ++ * @wait: wait for completion + * + * Returns zero on success. + * Returns -ve errno on failure. +@@ -605,27 +624,51 @@ EXPORT_SYMBOL(schedule_delayed_work_on); + * + * schedule_on_each_cpu() is very slow. + */ +-int schedule_on_each_cpu(work_func_t func) ++int schedule_on_each_cpu(void (*func)(void *info), void *info, int retry, int wait) + { + int cpu; +- struct work_struct *works; ++ struct schedule_on_each_cpu_work **works; ++ int err = 0; + +- works = alloc_percpu(struct work_struct); ++ works = kzalloc(sizeof(void *)*nr_cpu_ids, GFP_KERNEL); + if (!works) + return -ENOMEM; + ++ for_each_possible_cpu(cpu) { ++ works[cpu] = kmalloc_node(sizeof(struct schedule_on_each_cpu_work), ++ GFP_KERNEL, cpu_to_node(cpu)); ++ if (!works[cpu]) { ++ err = -ENOMEM; ++ goto out; ++ } ++ } ++ + preempt_disable(); /* CPU hotplug */ + for_each_online_cpu(cpu) { +- struct work_struct *work = per_cpu_ptr(works, cpu); ++ struct schedule_on_each_cpu_work *work; + +- INIT_WORK(work, func); +- set_bit(WORK_STRUCT_PENDING, work_data_bits(work)); +- __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), work); ++ work = works[cpu]; ++ works[cpu] = NULL; ++ ++ work->func = func; ++ work->info = info; ++ INIT_WORK(&work->work, schedule_on_each_cpu_func); ++ set_bit(WORK_STRUCT_PENDING, work_data_bits(&work->work)); ++ __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), &work->work); + } + preempt_enable(); +- flush_workqueue(keventd_wq); +- free_percpu(works); +- return 0; ++ ++out: ++ for_each_possible_cpu(cpu) { ++ if (works[cpu]) ++ kfree(works[cpu]); ++ } ++ kfree(works); ++ ++ if (!err && wait) ++ flush_workqueue(keventd_wq); ++ ++ return err; + } + + /** +Index: linux-2.6.24.7-rt27/mm/swap.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/swap.c 2009-02-08 00:02:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/swap.c 2009-02-08 00:03:33.000000000 -0500 +@@ -318,7 +318,7 @@ void lru_add_drain(void) + } + + #ifdef CONFIG_NUMA +-static void lru_add_drain_per_cpu(struct work_struct *dummy) ++static void lru_add_drain_per_cpu(void *info) + { + lru_add_drain(); + } +@@ -328,7 +328,7 @@ static void lru_add_drain_per_cpu(struct + */ + int lru_add_drain_all(void) + { +- return schedule_on_each_cpu(lru_add_drain_per_cpu); ++ return schedule_on_each_cpu(lru_add_drain_per_cpu, NULL, 0, 1); + } + + #else --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0045-0032-sched-fix-sched_rt.c-join-leave_domain.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0045-0032-sched-fix-sched_rt.c-join-leave_domain.patch @@ -0,0 +1,74 @@ +From d64bfbadc24903458938fed1704488eb4eef0487 Mon Sep 17 00:00:00 2001 +From: Ingo Molnar +Date: Tue, 11 Dec 2007 10:02:43 +0100 +Subject: [PATCH] sched: fix sched_rt.c:join/leave_domain + +fix build bug in sched_rt.c:join/leave_domain and make them only +be included on SMP builds. + +Signed-off-by: Ingo Molnar + +--- + kernel/sched_rt.c | 33 ++++++++++++++++----------------- + 1 file changed, 16 insertions(+), 17 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:01:03.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:01:04.000000000 -0500 +@@ -761,6 +761,20 @@ static void set_cpus_allowed_rt(struct t + p->cpus_allowed = *new_mask; + p->nr_cpus_allowed = weight; + } ++/* Assumes rq->lock is held */ ++static void join_domain_rt(struct rq *rq) ++{ ++ if (rq->rt.overloaded) ++ rt_set_overload(rq); ++} ++ ++/* Assumes rq->lock is held */ ++static void leave_domain_rt(struct rq *rq) ++{ ++ if (rq->rt.overloaded) ++ rt_clear_overload(rq); ++} ++ + #else /* CONFIG_SMP */ + # define schedule_tail_balance_rt(rq) do { } while (0) + # define schedule_balance_rt(rq, prev) do { } while (0) +@@ -793,20 +807,6 @@ static void task_tick_rt(struct rq *rq, + } + } + +-/* Assumes rq->lock is held */ +-static void join_domain_rt(struct rq *rq) +-{ +- if (rq->rt.overloaded) +- rt_set_overload(rq); +-} +- +-/* Assumes rq->lock is held */ +-static void leave_domain_rt(struct rq *rq) +-{ +- if (rq->rt.overloaded) +- rt_clear_overload(rq); +-} +- + static void set_curr_task_rt(struct rq *rq) + { + struct task_struct *p = rq->curr; +@@ -832,11 +832,10 @@ const struct sched_class rt_sched_class + .load_balance = load_balance_rt, + .move_one_task = move_one_task_rt, + .set_cpus_allowed = set_cpus_allowed_rt, ++ .join_domain = join_domain_rt, ++ .leave_domain = leave_domain_rt, + #endif + + .set_curr_task = set_curr_task_rt, + .task_tick = task_tick_rt, +- +- .join_domain = join_domain_rt, +- .leave_domain = leave_domain_rt, + }; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0167-rt-mutex-delayed-resched.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0167-rt-mutex-delayed-resched.patch @@ -0,0 +1,131 @@ +--- + drivers/acpi/processor_idle.c | 6 +++--- + include/linux/preempt.h | 16 ++++++++++++++++ + include/linux/sched.h | 22 +++++++++++++++++++++- + kernel/sched.c | 4 +++- + 4 files changed, 43 insertions(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/drivers/acpi/processor_idle.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/acpi/processor_idle.c 2009-02-08 00:00:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/acpi/processor_idle.c 2009-02-08 00:02:00.000000000 -0500 +@@ -209,7 +209,7 @@ static void acpi_safe_halt(void) + * test NEED_RESCHED: + */ + smp_mb(); +- if (!need_resched()) ++ if (!need_resched() || !need_resched_delayed()) + safe_halt(); + current_thread_info()->status |= TS_POLLING; + } +@@ -1417,7 +1417,7 @@ static int acpi_idle_enter_simple(struct + */ + smp_mb(); + +- if (unlikely(need_resched())) { ++ if (unlikely(need_resched() || need_resched_delayed())) { + current_thread_info()->status |= TS_POLLING; + local_irq_enable(); + return 0; +@@ -1503,7 +1503,7 @@ static int acpi_idle_enter_bm(struct cpu + */ + smp_mb(); + +- if (unlikely(need_resched())) { ++ if (unlikely(need_resched() || need_resched_delayed())) { + current_thread_info()->status |= TS_POLLING; + local_irq_enable(); + return 0; +Index: linux-2.6.24.7-rt27/include/linux/preempt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/preempt.h 2009-02-08 00:01:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/preempt.h 2009-02-08 00:02:00.000000000 -0500 +@@ -55,6 +55,21 @@ do { \ + preempt_schedule(); \ + } while (0) + ++ ++/* ++ * If the architecture doens't have TIF_NEED_RESCHED_DELAYED ++ * help it out and define it back to TIF_NEED_RESCHED ++ */ ++#ifndef TIF_NEED_RESCHED_DELAYED ++# define TIF_NEED_RESCHED_DELAYED TIF_NEED_RESCHED ++#endif ++ ++#define preempt_check_resched_delayed() \ ++do { \ ++ if (unlikely(test_thread_flag(TIF_NEED_RESCHED_DELAYED))) \ ++ preempt_schedule(); \ ++} while (0) ++ + #define preempt_enable() \ + do { \ + __preempt_enable_no_resched(); \ +@@ -97,6 +112,7 @@ do { \ + #define __preempt_enable_no_resched() do { } while (0) + #define preempt_enable() do { } while (0) + #define preempt_check_resched() do { } while (0) ++#define preempt_check_resched_delayed() do { } while (0) + + #define preempt_disable_notrace() do { } while (0) + #define preempt_enable_no_resched_notrace() do { } while (0) +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:01:50.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:02:00.000000000 -0500 +@@ -1893,11 +1893,31 @@ static inline int signal_pending(struct + return unlikely(test_tsk_thread_flag(p,TIF_SIGPENDING)); + } + +-static inline int need_resched(void) ++static inline int _need_resched(void) + { + return unlikely(test_thread_flag(TIF_NEED_RESCHED)); + } + ++static inline int need_resched(void) ++{ ++ return _need_resched(); ++} ++ ++static inline void set_tsk_need_resched_delayed(struct task_struct *tsk) ++{ ++ set_tsk_thread_flag(tsk,TIF_NEED_RESCHED_DELAYED); ++} ++ ++static inline void clear_tsk_need_resched_delayed(struct task_struct *tsk) ++{ ++ clear_tsk_thread_flag(tsk,TIF_NEED_RESCHED_DELAYED); ++} ++ ++static inline int need_resched_delayed(void) ++{ ++ return unlikely(test_thread_flag(TIF_NEED_RESCHED_DELAYED)); ++} ++ + /* + * cond_resched() and cond_resched_lock(): latency reduction via + * explicit rescheduling in places that are safe. The return +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:01:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:02:00.000000000 -0500 +@@ -3735,6 +3735,7 @@ need_resched_nonpreemptible: + __update_rq_clock(rq); + spin_lock(&rq->lock); + clear_tsk_need_resched(prev); ++ clear_tsk_need_resched_delayed(prev); + + if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { + if (unlikely((prev->state & TASK_INTERRUPTIBLE) && +@@ -3774,7 +3775,8 @@ need_resched_nonpreemptible: + goto need_resched_nonpreemptible; + } + __preempt_enable_no_resched(); +- if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) ++ if (unlikely(test_thread_flag(TIF_NEED_RESCHED) || ++ test_thread_flag(TIF_NEED_RESCHED_DELAYED))) + goto need_resched; + } + EXPORT_SYMBOL(schedule); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0387-irq-flags-unsigned-long.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0387-irq-flags-unsigned-long.patch @@ -0,0 +1,35 @@ +--- + drivers/media/video/zoran_driver.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/drivers/media/video/zoran_driver.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/media/video/zoran_driver.c 2009-02-07 23:59:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/media/video/zoran_driver.c 2009-02-08 00:03:54.000000000 -0500 +@@ -1174,7 +1174,7 @@ zoran_close_end_session (struct file *fi + + /* v4l capture */ + if (fh->v4l_buffers.active != ZORAN_FREE) { +- long flags; ++ unsigned long flags; + + spin_lock_irqsave(&zr->spinlock, flags); + zr36057_set_memgrab(zr, 0); +@@ -3447,7 +3447,7 @@ zoran_do_ioctl (struct inode *inode, + + /* unload capture */ + if (zr->v4l_memgrab_active) { +- long flags; ++ unsigned long flags; + + spin_lock_irqsave(&zr->spinlock, flags); + zr36057_set_memgrab(zr, 0); +@@ -4387,7 +4387,7 @@ zoran_vm_close (struct vm_area_struct *v + mutex_lock(&zr->resource_lock); + + if (fh->v4l_buffers.active != ZORAN_FREE) { +- long flags; ++ unsigned long flags; + + spin_lock_irqsave(&zr->spinlock, flags); + zr36057_set_memgrab(zr, 0); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0271-nmi-profiling.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0271-nmi-profiling.patch @@ -0,0 +1,101 @@ +--- + arch/x86/kernel/irq_32.c | 2 ++ + arch/x86/kernel/nmi_32.c | 5 ++--- + arch/x86/kernel/nmi_64.c | 4 ++-- + drivers/char/sysrq.c | 2 +- + include/asm-x86/apic_64.h | 2 ++ + include/linux/sched.h | 1 + + 6 files changed, 10 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/irq_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/irq_32.c 2009-02-08 00:02:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/irq_32.c 2009-02-08 00:02:55.000000000 -0500 +@@ -79,7 +79,9 @@ fastcall unsigned int do_IRQ(struct pt_r + u32 *isp; + #endif + ++#ifdef CONFIG_X86_LOCAL_APIC + irq_show_regs_callback(smp_processor_id(), regs); ++#endif + + if (unlikely((unsigned)irq >= NR_IRQS)) { + printk(KERN_EMERG "%s: cannot handle IRQ %d\n", +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_32.c 2009-02-08 00:02:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c 2009-02-08 00:02:55.000000000 -0500 +@@ -348,9 +348,9 @@ void nmi_show_all_regs(void) + } + } + +-static DEFINE_SPINLOCK(nmi_print_lock); ++static DEFINE_RAW_SPINLOCK(nmi_print_lock); + +-void irq_show_regs_callback(int cpu, struct pt_regs *regs) ++notrace void irq_show_regs_callback(int cpu, struct pt_regs *regs) + { + if (!nmi_show_regs[cpu]) + return; +@@ -435,7 +435,6 @@ nmi_watchdog_tick(struct pt_regs * regs, + for_each_online_cpu(i) + alert_counter[i] = 0; + +- + } + + } else { +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_64.c 2009-02-08 00:02:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c 2009-02-08 00:02:55.000000000 -0500 +@@ -338,9 +338,9 @@ void nmi_show_all_regs(void) + } + } + +-static DEFINE_SPINLOCK(nmi_print_lock); ++static DEFINE_RAW_SPINLOCK(nmi_print_lock); + +-void irq_show_regs_callback(int cpu, struct pt_regs *regs) ++notrace void irq_show_regs_callback(int cpu, struct pt_regs *regs) + { + if (!nmi_show_regs[cpu]) + return; +Index: linux-2.6.24.7-rt27/drivers/char/sysrq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/char/sysrq.c 2009-02-08 00:02:44.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/char/sysrq.c 2009-02-08 00:02:55.000000000 -0500 +@@ -209,7 +209,7 @@ static struct sysrq_key_op sysrq_showreg + .enable_mask = SYSRQ_ENABLE_DUMP, + }; + +-#if defined(__i386__) ++#if defined(__i386__) || defined(__x86_64__) + + static void sysrq_handle_showallregs(int key, struct tty_struct *tty) + { +Index: linux-2.6.24.7-rt27/include/asm-x86/apic_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/apic_64.h 2009-02-08 00:01:32.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/apic_64.h 2009-02-08 00:02:55.000000000 -0500 +@@ -96,6 +96,8 @@ extern void smp_send_nmi_allbutself(void + #define K8_APIC_EXT_INT_MSG_EXT 0x7 + #define K8_APIC_EXT_LVT_ENTRY_THRESHOLD 0 + ++extern void smp_send_nmi_allbutself(void); ++ + #define ARCH_APICTIMER_STOPS_ON_C3 1 + + extern unsigned boot_cpu_id; +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:02:37.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:02:55.000000000 -0500 +@@ -292,6 +292,7 @@ static inline void show_state(void) + } + + extern void show_regs(struct pt_regs *); ++extern void irq_show_regs_callback(int cpu, struct pt_regs *regs); + + /* + * TASK is a pointer to the task whose backtrace we want to see (or NULL for current --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0460-sched_load_balance_lockbreak.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0460-sched_load_balance_lockbreak.patch @@ -0,0 +1,172 @@ +Subject: sched: lock-break the load balance path +From: Peter Zijlstra + +move_tasks() can do a lot of work, and it holds two runqueue locks and has +IRQs disabled. We already introduced sysctl_sched_nr_migrate to limit +the number of task iterations it can do. + +This patch takes it one step further and drops the locks once we break out +of the iteration due to sysctl_sched_nr_migrate and re-enables IRQs. Then it +re-acquires everything and continues. + +Dropping the locks is safe because: + - load_balance() doesn't rely on it + - load_balance_newidle() uses double_lock_balance() which + can already drop the locks. + +Enabling IRQs should be safe since we already dropped all locks. + +We add the LB_COMPLETE state to detect the truncated iteration due to +sysctl_sched_nr_migrate. + +For now we must break out of the restart when load_moved is 0, because each +iteration will test the same tasks - hence we can live-lock here. + +Signed-off-by: Peter Zijlstra +--- + kernel/sched.c | 42 +++++++++++++++++++++++++++++++++++++----- + kernel/sched_debug.c | 28 ++++++++++++++++++++++------ + 2 files changed, 59 insertions(+), 11 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:04:28.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:04:29.000000000 -0500 +@@ -461,6 +461,8 @@ struct rq { + unsigned long rto_wakeup; + unsigned long rto_pulled; + unsigned long rto_pushed; ++ ++ unsigned long lb_breaks; + #endif + struct lock_class_key rq_lock_key; + }; +@@ -587,6 +589,7 @@ enum { + SCHED_FEAT_START_DEBIT = 4, + SCHED_FEAT_TREE_AVG = 8, + SCHED_FEAT_APPROX_AVG = 16, ++ SCHED_FEAT_LB_BREAK = 32, + }; + + const_debug unsigned int sysctl_sched_features = +@@ -594,7 +597,8 @@ const_debug unsigned int sysctl_sched_fe + SCHED_FEAT_WAKEUP_PREEMPT * 1 | + SCHED_FEAT_START_DEBIT * 1 | + SCHED_FEAT_TREE_AVG * 0 | +- SCHED_FEAT_APPROX_AVG * 0; ++ SCHED_FEAT_APPROX_AVG * 0 | ++ SCHED_FEAT_LB_BREAK * 1; + + #define sched_feat(x) (sysctl_sched_features & SCHED_FEAT_##x) + +@@ -2270,6 +2274,7 @@ static void update_cpu_load(struct rq *t + #ifdef CONFIG_SMP + + #define LB_ALL_PINNED 0x01 ++#define LB_COMPLETE 0x02 + + /* + * double_rq_lock - safely lock two runqueues +@@ -2476,8 +2481,13 @@ balance_tasks(struct rq *this_rq, int th + if (p) + pinned = 1; + next: +- if (!p || loops++ > sysctl_sched_nr_migrate) ++ if (!p) ++ goto out; ++ ++ if (loops++ > sysctl_sched_nr_migrate) { ++ *lb_flags &= ~LB_COMPLETE; + goto out; ++ } + /* + * To help distribute high priority tasks across CPUs we don't + * skip a task if it will be the highest priority task (i.e. smallest +@@ -2535,11 +2545,30 @@ static int move_tasks(struct rq *this_rq + int this_best_prio = this_rq->curr->prio; + + do { +- total_load_moved += +- class->load_balance(this_rq, this_cpu, busiest, ++ unsigned long load_moved; ++ ++ *lb_flags |= LB_COMPLETE; ++ ++ load_moved = class->load_balance(this_rq, this_cpu, busiest, + max_load_move - total_load_moved, + sd, idle, lb_flags, &this_best_prio); +- class = class->next; ++ ++ total_load_moved += load_moved; ++ ++ if (!load_moved || *lb_flags & LB_COMPLETE) { ++ class = class->next; ++ } else if (sched_feat(LB_BREAK)) { ++ schedstat_inc(this_rq, lb_breaks); ++ ++ double_rq_unlock(this_rq, busiest); ++ local_irq_enable(); ++ ++ if (!in_atomic()) ++ cond_resched(); ++ ++ local_irq_disable(); ++ double_rq_lock(this_rq, busiest); ++ } + } while (class && max_load_move > total_load_moved); + + return total_load_moved > 0; +@@ -2983,6 +3012,9 @@ redo: + + ld_moved = 0; + if (busiest->nr_running > 1) { ++ ++ WARN_ON(irqs_disabled()); ++ + /* + * Attempt to move tasks. If find_busiest_group has found + * an imbalance but busiest->nr_running <= 1, the group is +Index: linux-2.6.24.7-rt27/kernel/sched_debug.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_debug.c 2009-02-08 00:03:30.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_debug.c 2009-02-08 00:04:29.000000000 -0500 +@@ -186,17 +186,33 @@ static void print_cpu(struct seq_file *m + P(cpu_load[2]); + P(cpu_load[3]); + P(cpu_load[4]); +-#ifdef CONFIG_PREEMPT_RT +- /* Print rt related rq stats */ +- P(rt.rt_nr_running); +- P(rt.rt_nr_uninterruptible); +-# ifdef CONFIG_SCHEDSTATS ++#ifdef CONFIG_SCHEDSTATS ++ P(yld_exp_empty); ++ P(yld_act_empty); ++ P(yld_both_empty); ++ P(yld_count); ++ ++ P(sched_switch); ++ P(sched_count); ++ P(sched_goidle); ++ ++ P(ttwu_count); ++ P(ttwu_local); ++ ++ P(bkl_count); ++ + P(rto_schedule); + P(rto_schedule_tail); + P(rto_wakeup); + P(rto_pulled); + P(rto_pushed); +-# endif ++ ++ P(lb_breaks); ++#endif ++#ifdef CONFIG_PREEMPT_RT ++ /* Print rt related rq stats */ ++ P(rt.rt_nr_running); ++ P(rt.rt_nr_uninterruptible); + #endif + + #undef P --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0393-user-no-irq-disable.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0393-user-no-irq-disable.patch @@ -0,0 +1,25 @@ +--- + kernel/user.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/user.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/user.c 2009-02-08 00:02:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/user.c 2009-02-08 00:03:57.000000000 -0500 +@@ -225,14 +225,14 @@ static void remove_user_sysfs_dir(struct + */ + uids_mutex_lock(); + +- local_irq_save(flags); ++ local_irq_save_nort(flags); + + if (atomic_dec_and_lock(&up->__count, &uidhash_lock)) { + uid_hash_remove(up); + remove_user = 1; + spin_unlock_irqrestore(&uidhash_lock, flags); + } else { +- local_irq_restore(flags); ++ local_irq_restore_nort(flags); + } + + if (!remove_user) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0378-rt-plist-mods.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0378-rt-plist-mods.patch @@ -0,0 +1,113 @@ +Subject: rt: plist_head_splice + +merge-sort two plists together + +Signed-off-by: Peter Zijlstra +--- + include/linux/plist.h | 2 + + lib/plist.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 68 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/plist.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/plist.h 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/plist.h 2009-02-08 00:03:50.000000000 -0500 +@@ -148,6 +148,8 @@ static inline void plist_node_init(struc + extern void plist_add(struct plist_node *node, struct plist_head *head); + extern void plist_del(struct plist_node *node, struct plist_head *head); + ++extern void plist_head_splice(struct plist_head *src, struct plist_head *dst); ++ + /** + * plist_for_each - iterate over the plist + * @pos: the type * to use as a loop counter +Index: linux-2.6.24.7-rt27/lib/plist.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/plist.c 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/plist.c 2009-02-08 00:03:50.000000000 -0500 +@@ -66,6 +66,30 @@ static void plist_check_head(struct plis + # define plist_check_head(h) do { } while (0) + #endif + ++static inline struct plist_node *prev_node(struct plist_node *iter) ++{ ++ return list_entry(iter->plist.node_list.prev, struct plist_node, ++ plist.node_list); ++} ++ ++static inline struct plist_node *next_node(struct plist_node *iter) ++{ ++ return list_entry(iter->plist.node_list.next, struct plist_node, ++ plist.node_list); ++} ++ ++static inline struct plist_node *prev_prio(struct plist_node *iter) ++{ ++ return list_entry(iter->plist.prio_list.prev, struct plist_node, ++ plist.prio_list); ++} ++ ++static inline struct plist_node *next_prio(struct plist_node *iter) ++{ ++ return list_entry(iter->plist.prio_list.next, struct plist_node, ++ plist.prio_list); ++} ++ + /** + * plist_add - add @node to @head + * +@@ -83,8 +107,7 @@ void plist_add(struct plist_node *node, + if (node->prio < iter->prio) + goto lt_prio; + else if (node->prio == iter->prio) { +- iter = list_entry(iter->plist.prio_list.next, +- struct plist_node, plist.prio_list); ++ iter = next_prio(iter); + goto eq_prio; + } + } +@@ -118,3 +141,44 @@ void plist_del(struct plist_node *node, + + plist_check_head(head); + } ++ ++void plist_head_splice(struct plist_head *src, struct plist_head *dst) ++{ ++ struct plist_node *src_iter_first, *src_iter_last, *dst_iter; ++ struct plist_node *tail = container_of(dst, struct plist_node, plist); ++ ++ dst_iter = next_prio(tail); ++ ++ while (!plist_head_empty(src) && dst_iter != tail) { ++ src_iter_first = plist_first(src); ++ ++ src_iter_last = next_prio(src_iter_first); ++ src_iter_last = prev_node(src_iter_last); ++ ++ WARN_ON(src_iter_first->prio != src_iter_last->prio); ++ WARN_ON(list_empty(&src_iter_first->plist.prio_list)); ++ ++ while (src_iter_first->prio > dst_iter->prio) { ++ dst_iter = next_prio(dst_iter); ++ if (dst_iter == tail) ++ goto tail; ++ } ++ ++ list_del_init(&src_iter_first->plist.prio_list); ++ ++ if (src_iter_first->prio < dst_iter->prio) { ++ list_add_tail(&src_iter_first->plist.prio_list, ++ &dst_iter->plist.prio_list); ++ } else if (src_iter_first->prio == dst_iter->prio) { ++ dst_iter = next_prio(dst_iter); ++ } else BUG(); ++ ++ list_splice2_tail(&src_iter_first->plist.node_list, ++ &src_iter_last->plist.node_list, ++ &dst_iter->plist.node_list); ++ } ++ ++tail: ++ list_splice_tail_init(&src->prio_list, &dst->prio_list); ++ list_splice_tail_init(&src->node_list, &dst->node_list); ++} --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0334-quicklist-release-before-free-page-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0334-quicklist-release-before-free-page-fix.patch @@ -0,0 +1,82 @@ +--- + include/linux/quicklist.h | 18 ++++++++---------- + mm/quicklist.c | 8 ++------ + 2 files changed, 10 insertions(+), 16 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/quicklist.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/quicklist.h 2009-02-08 00:03:29.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/quicklist.h 2009-02-08 00:03:29.000000000 -0500 +@@ -30,13 +30,10 @@ DECLARE_PER_CPU_LOCKED(struct quicklist, + * The fast patch in quicklist_alloc touched only a per cpu cacheline and + * the first cacheline of the page itself. There is minmal overhead involved. + */ +-static inline void *__quicklist_alloc(int cpu, int nr, gfp_t flags, void (*ctor)(void *)) ++static inline void *__quicklist_alloc(struct quicklist *q) + { +- struct quicklist *q; +- void **p = NULL; ++ void **p = q->page; + +- q = &__get_cpu_var_locked(quicklist, cpu)[nr]; +- p = q->page; + if (likely(p)) { + q->page = p[0]; + p[0] = NULL; +@@ -48,11 +45,11 @@ static inline void *__quicklist_alloc(in + static inline void *quicklist_alloc(int nr, gfp_t flags, void (*ctor)(void *)) + { + struct quicklist *q; +- void **p = NULL; ++ void **p; + int cpu; + +- (void)get_cpu_var_locked(quicklist, &cpu)[nr]; +- p = __quicklist_alloc(cpu, nr, flags, ctor); ++ q = &get_cpu_var_locked(quicklist, &cpu)[nr]; ++ p = __quicklist_alloc(q); + put_cpu_var_locked(quicklist, cpu); + if (likely(p)) + return p; +@@ -67,12 +64,13 @@ static inline void __quicklist_free(int + struct page *page) + { + struct quicklist *q; ++ int cpu; + +- q = &get_cpu_var(quicklist)[nr]; ++ q = &get_cpu_var_locked(quicklist, &cpu)[nr]; + *(void **)p = q->page; + q->page = p; + q->nr_pages++; +- put_cpu_var(quicklist); ++ put_cpu_var_locked(quicklist, cpu); + } + + static inline void quicklist_free(int nr, void (*dtor)(void *), void *pp) +Index: linux-2.6.24.7-rt27/mm/quicklist.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/quicklist.c 2009-02-08 00:03:29.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/quicklist.c 2009-02-08 00:03:29.000000000 -0500 +@@ -66,11 +66,7 @@ void quicklist_trim(int nr, void (*dtor) + pages_to_free = min_pages_to_free(q, min_pages, max_free); + + while (pages_to_free > 0) { +- /* +- * We pass a gfp_t of 0 to quicklist_alloc here +- * because we will never call into the page allocator. +- */ +- void *p = __quicklist_alloc(cpu, nr, 0, NULL); ++ void *p = __quicklist_alloc(q); + + if (dtor) + dtor(p); +@@ -88,7 +84,7 @@ unsigned long quicklist_total_size(void) + struct quicklist *ql, *q; + + for_each_online_cpu(cpu) { +- ql = per_cpu(quicklist, cpu); ++ ql = per_cpu_var_locked(quicklist, cpu); + for (q = ql; q < ql + CONFIG_NR_QUICK; q++) + count += q->nr_pages; + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0492-event-trace-hrtimer-trace.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0492-event-trace-hrtimer-trace.patch @@ -0,0 +1,228 @@ +From: Steven Rostedt +Subject: event-tracer: add clockevent trace + +The old latency tracer recorded clockevent programming of the timer. +This patch adds that back in to the event tracer. + +Signed-off-by: Steven Rostedt +--- + include/linux/ftrace.h | 7 +++++++ + kernel/time/clockevents.c | 3 +++ + kernel/trace/trace.c | 26 ++++++++++++++++++++++++++ + kernel/trace/trace.h | 13 +++++++++++++ + kernel/trace/trace_events.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 93 insertions(+) + +Index: linux-2.6.24.7-rt27/include/linux/ftrace.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/ftrace.h 2009-02-08 00:04:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/ftrace.h 2009-02-08 00:04:45.000000000 -0500 +@@ -176,6 +176,12 @@ static inline void ftrace_event_task_dea + { + trace_mark(ftrace_event_task_deactivate, "%p %d", p, cpu); + } ++ ++static inline void ftrace_event_program_event(ktime_t *expires, int64_t *delta) ++{ ++ trace_mark(ftrace_event_timer, "%p %p", expires, delta); ++} ++ + #else + # define ftrace_event_irq(irq, user, ip) do { } while (0) + # define ftrace_event_fault(ip, error, addr) do { } while (0) +@@ -184,6 +190,7 @@ static inline void ftrace_event_task_dea + # define ftrace_event_timestamp(now) do { } while (0) + # define ftrace_event_task_activate(p, cpu) do { } while (0) + # define ftrace_event_task_deactivate(p, cpu) do { } while (0) ++# define ftrace_event_program_event(p, d) do { } while (0) + #endif /* CONFIG_TRACE_EVENTS */ + + #endif /* _LINUX_FTRACE_H */ +Index: linux-2.6.24.7-rt27/kernel/time/clockevents.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/clockevents.c 2009-02-08 00:02:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/clockevents.c 2009-02-08 00:04:45.000000000 -0500 +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + /* The registered clock event devices */ + static LIST_HEAD(clockevent_devices); +@@ -85,6 +86,8 @@ int clockevents_program_event(struct clo + + delta = ktime_to_ns(ktime_sub(expires, now)); + ++ ftrace_event_program_event(&expires, &delta); ++ + if (delta <= 0) + return -ETIME; + +Index: linux-2.6.24.7-rt27/kernel/trace/trace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace.c 2009-02-08 00:04:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace.c 2009-02-08 00:04:45.000000000 -0500 +@@ -1069,6 +1069,22 @@ void tracing_event_timer_set(struct trac + entry->timer.timer = timer; + } + ++void tracing_event_program_event(struct trace_array *tr, ++ struct trace_array_cpu *data, ++ unsigned long flags, ++ unsigned long ip, ++ ktime_t *expires, int64_t *delta) ++{ ++ struct trace_entry *entry; ++ ++ entry = tracing_get_trace_entry(tr, data); ++ tracing_generic_entry_update(entry, flags); ++ entry->type = TRACE_PROGRAM_EVENT; ++ entry->program.ip = ip; ++ entry->program.expire = *expires; ++ entry->program.delta = *delta; ++} ++ + void tracing_event_timer_triggered(struct trace_array *tr, + struct trace_array_cpu *data, + unsigned long flags, +@@ -1722,6 +1738,11 @@ print_lat_fmt(struct trace_iterator *ite + trace_seq_printf(s, " (%Ld)\n", + entry->timestamp.now.tv64); + break; ++ case TRACE_PROGRAM_EVENT: ++ seq_print_ip_sym(s, entry->program.ip, sym_flags); ++ trace_seq_printf(s, " (%Ld) (%Ld)\n", ++ entry->program.expire, entry->program.delta); ++ break; + case TRACE_TASK_ACT: + seq_print_ip_sym(s, entry->task.ip, sym_flags); + comm = trace_find_cmdline(entry->task.pid); +@@ -1897,6 +1918,11 @@ static int print_trace_fmt(struct trace_ + trace_seq_printf(s, " (%Ld)\n", + entry->timestamp.now.tv64); + break; ++ case TRACE_PROGRAM_EVENT: ++ seq_print_ip_sym(s, entry->program.ip, sym_flags); ++ trace_seq_printf(s, " (%Ld) (%Ld)\n", ++ entry->program.expire, entry->program.delta); ++ break; + case TRACE_TASK_ACT: + seq_print_ip_sym(s, entry->task.ip, sym_flags); + comm = trace_find_cmdline(entry->task.pid); +Index: linux-2.6.24.7-rt27/kernel/trace/trace.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace.h 2009-02-08 00:02:36.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace.h 2009-02-08 00:04:45.000000000 -0500 +@@ -22,6 +22,7 @@ enum trace_type { + TRACE_TIMER_SET, + TRACE_TIMER_TRIG, + TRACE_TIMESTAMP, ++ TRACE_PROGRAM_EVENT, + TRACE_TASK_ACT, + TRACE_TASK_DEACT, + TRACE_SYSCALL, +@@ -79,6 +80,12 @@ struct timer_entry { + void *timer; + }; + ++struct program_entry { ++ unsigned long ip; ++ ktime_t expire; ++ int64_t delta; ++}; ++ + struct timestamp_entry { + unsigned long ip; + ktime_t now; +@@ -145,6 +152,7 @@ struct trace_entry { + struct fault_entry fault; + struct timer_entry timer; + struct timestamp_entry timestamp; ++ struct program_entry program; + struct task_entry task; + struct wakeup_entry wakeup; + struct syscall_entry syscall; +@@ -331,6 +339,11 @@ void tracing_event_task_deactivate(struc + unsigned long ip, + struct task_struct *p, + int cpu); ++void tracing_event_program_event(struct trace_array *tr, ++ struct trace_array_cpu *data, ++ unsigned long flags, ++ unsigned long ip, ++ ktime_t *expires, int64_t *delta); + void tracing_event_wakeup(struct trace_array *tr, + struct trace_array_cpu *data, + unsigned long flags, +Index: linux-2.6.24.7-rt27/kernel/trace/trace_events.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace_events.c 2009-02-08 00:01:15.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace_events.c 2009-02-08 00:04:45.000000000 -0500 +@@ -291,6 +291,40 @@ event_hrtimer_callback(void *probe_data, + } + + static void ++event_program_event_callback(void *probe_data, void *call_data, ++ const char *format, va_list *args) ++{ ++ struct trace_array *tr = probe_data; ++ struct trace_array_cpu *data; ++ unsigned long flags; ++ ktime_t *expires; ++ int64_t *delta; ++ long disable; ++ int cpu; ++ ++ if (!tracer_enabled) ++ return; ++ ++ getarg(expires, *args); ++ getarg(delta, *args); ++ ++ /* interrupts should be off, we are in an interrupt */ ++ cpu = smp_processor_id(); ++ data = tr->data[cpu]; ++ ++ disable = atomic_inc_return(&data->disabled); ++ if (disable != 1) ++ goto out; ++ ++ local_save_flags(flags); ++ tracing_event_program_event(tr, data, flags, CALLER_ADDR1, expires, delta); ++ ++ out: ++ atomic_dec(&data->disabled); ++} ++ ++ ++static void + event_task_activate_callback(void *probe_data, void *call_data, + const char *format, va_list *args) + { +@@ -511,8 +545,16 @@ static void event_tracer_register(struct + if (ret) + goto out9; + ++ ret = event_register_marker("ftrace_event_timer", "%p %p", ++ event_program_event_callback, tr); ++ if (ret) ++ goto out10; ++ + return; + ++ out10: ++ marker_probe_unregister("kernel_sched_schedule", ++ event_ctx_callback, tr); + out9: + marker_probe_unregister("kernel_sched_wakeup_new", + event_wakeup_callback, tr); +@@ -544,6 +586,8 @@ static void event_tracer_register(struct + + static void event_tracer_unregister(struct trace_array *tr) + { ++ marker_probe_unregister("ftrace_event_timer", ++ event_program_event_callback, tr); + marker_probe_unregister("kernel_sched_schedule", + event_ctx_callback, tr); + marker_probe_unregister("kernel_sched_wakeup_new", --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0223-preempt-realtime-powerpc-b3.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0223-preempt-realtime-powerpc-b3.patch @@ -0,0 +1,47 @@ + + To fix the following runtime warning. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BUG: using smp_processor_id() in preemptible [00000000] code: init/371 +caller is .pgtable_free_tlb+0x2c/0x14c +Call Trace: +[C00000000FF6B770] [C00000000000FAAC] .show_stack+0x68/0x1b0 (unreliable) +[C00000000FF6B810] [C0000000001F7190] .debug_smp_processor_id+0xc8/0xf8 +[C00000000FF6B8A0] [C00000000002C52C] .pgtable_free_tlb+0x2c/0x14c +[C00000000FF6B940] [C0000000000B6528] .free_pgd_range+0x234/0x3bc +[C00000000FF6BA40] [C0000000000B6AB8] .free_pgtables+0x224/0x260 +[C00000000FF6BB00] [C0000000000B7FE8] .exit_mmap+0x100/0x208 +[C00000000FF6BBC0] [C000000000055FB0] .mmput+0x70/0x12c +[C00000000FF6BC50] [C00000000005B728] .exit_mm+0x150/0x170 +[C00000000FF6BCE0] [C00000000005D80C] .do_exit+0x28c/0x9bc +[C00000000FF6BDA0] [C00000000005DFF0] .sys_exit_group+0x0/0x8 +[C00000000FF6BE30] [C000000000008634] syscall_exit+0x0/0x40 +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Would it be better to just use raw_smp_processor_id() rather than tlb->cpu? + +Signed-off-by: Tsutomu Owa +-- owa + +--- + arch/powerpc/mm/tlb_64.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/mm/tlb_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/mm/tlb_64.c 2009-02-08 00:02:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/mm/tlb_64.c 2009-02-08 00:02:30.000000000 -0500 +@@ -91,8 +91,11 @@ static void pte_free_submit(struct pte_f + + void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf) + { +- /* This is safe since tlb_gather_mmu has disabled preemption */ +- cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id()); ++ /* ++ * This is safe since tlb_gather_mmu has disabled preemption. ++ * tlb->cpu is set by tlb_gather_mmu as well. ++ */ ++ cpumask_t local_cpumask = cpumask_of_cpu(tlb->cpu); + struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur); + + if (atomic_read(&tlb->mm->mm_users) < 2 || --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0255-preempt-realtime-printk.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0255-preempt-realtime-printk.patch @@ -0,0 +1,144 @@ +--- + kernel/printk.c | 54 +++++++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 45 insertions(+), 9 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/printk.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/printk.c 2009-02-07 23:59:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/printk.c 2009-02-08 00:02:46.000000000 -0500 +@@ -84,7 +84,7 @@ static int console_locked, console_suspe + * It is also used in interesting ways to provide interlocking in + * release_console_sem(). + */ +-static DEFINE_SPINLOCK(logbuf_lock); ++static DEFINE_RAW_SPINLOCK(logbuf_lock); + + #define LOG_BUF_MASK (log_buf_len-1) + #define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK]) +@@ -435,7 +435,7 @@ static void __call_console_drivers(unsig + + for (con = console_drivers; con; con = con->next) { + if ((con->flags & CON_ENABLED) && con->write && +- (cpu_online(smp_processor_id()) || ++ (cpu_online(raw_smp_processor_id()) || + (con->flags & CON_ANYTIME))) + con->write(con, &LOG_BUF(start), end - start); + } +@@ -551,6 +551,7 @@ static void zap_locks(void) + spin_lock_init(&logbuf_lock); + /* And make sure that we print immediately */ + init_MUTEX(&console_sem); ++ zap_rt_locks(); + } + + #if defined(CONFIG_PRINTK_TIME) +@@ -649,6 +650,7 @@ asmlinkage int vprintk(const char *fmt, + lockdep_off(); + spin_lock(&logbuf_lock); + printk_cpu = smp_processor_id(); ++ preempt_enable(); + + /* Emit the output into the temporary buffer */ + printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args); +@@ -718,6 +720,8 @@ asmlinkage int vprintk(const char *fmt, + console_locked = 1; + printk_cpu = UINT_MAX; + spin_unlock(&logbuf_lock); ++ lockdep_on(); ++ local_irq_restore(flags); + + /* + * Console drivers may assume that per-cpu resources have +@@ -725,7 +729,7 @@ asmlinkage int vprintk(const char *fmt, + * being able to cope (CON_ANYTIME) don't call them until + * this CPU is officially up. + */ +- if (cpu_online(smp_processor_id()) || have_callable_console()) { ++ if (cpu_online(raw_smp_processor_id()) || have_callable_console()) { + console_may_schedule = 0; + release_console_sem(); + } else { +@@ -733,8 +737,6 @@ asmlinkage int vprintk(const char *fmt, + console_locked = 0; + up(&console_sem); + } +- lockdep_on(); +- raw_local_irq_restore(flags); + } else { + /* + * Someone else owns the drivers. We drop the spinlock, which +@@ -747,7 +749,6 @@ asmlinkage int vprintk(const char *fmt, + raw_local_irq_restore(flags); + } + +- preempt_enable(); + return printed_len; + } + EXPORT_SYMBOL(printk); +@@ -971,13 +972,31 @@ void release_console_sem(void) + _con_start = con_start; + _log_end = log_end; + con_start = log_end; /* Flush */ ++ /* ++ * on PREEMPT_RT, call console drivers with ++ * interrupts enabled (if printk was called ++ * with interrupts disabled): ++ */ ++#ifdef CONFIG_PREEMPT_RT ++ spin_unlock_irqrestore(&logbuf_lock, flags); ++#else + spin_unlock(&logbuf_lock); ++#endif + call_console_drivers(_con_start, _log_end); +- local_irq_restore(flags); ++ local_irq_restore_nort(flags); + } + console_locked = 0; +- up(&console_sem); + spin_unlock_irqrestore(&logbuf_lock, flags); ++ up(&console_sem); ++ /* ++ * On PREEMPT_RT kernels __wake_up may sleep, so wake syslogd ++ * up only if we are in a preemptible section. We normally dont ++ * printk from non-preemptible sections so this is for the emergency ++ * case only. ++ */ ++#ifdef CONFIG_PREEMPT_RT ++ if (!in_atomic() && !irqs_disabled()) ++#endif + if (wake_klogd) + wake_up_klogd(); + } +@@ -1244,7 +1263,7 @@ void tty_write_message(struct tty_struct + */ + int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst) + { +- static DEFINE_SPINLOCK(ratelimit_lock); ++ static DEFINE_RAW_SPINLOCK(ratelimit_lock); + static unsigned long toks = 10 * 5 * HZ; + static unsigned long last_msg; + static int missed; +@@ -1285,6 +1304,23 @@ int printk_ratelimit(void) + } + EXPORT_SYMBOL(printk_ratelimit); + ++static DEFINE_RAW_SPINLOCK(warn_lock); ++ ++void __WARN_ON(const char *func, const char *file, const int line) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&warn_lock, flags); ++ printk("%s/%d[CPU#%d]: BUG in %s at %s:%d\n", ++ current->comm, current->pid, raw_smp_processor_id(), ++ func, file, line); ++ dump_stack(); ++ spin_unlock_irqrestore(&warn_lock, flags); ++} ++ ++EXPORT_SYMBOL(__WARN_ON); ++ ++ + /** + * printk_timed_ratelimit - caller-controlled printk ratelimiting + * @caller_jiffies: pointer to caller's state --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0361-replace-PICK_OP-with-PICK_FUNCTION.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0361-replace-PICK_OP-with-PICK_FUNCTION.patch @@ -0,0 +1,550 @@ +From dwalker@mvista.com Wed Sep 26 21:45:42 2007 +Date: Tue, 28 Aug 2007 14:37:50 -0700 +From: Daniel Walker +To: mingo@elte.hu +Cc: mingo@redhat.com, linux-kernel@vger.kernel.org, + linux-rt-users@vger.kernel.org +Subject: [PATCH -rt 2/8] spinlocks/rwlocks: use PICK_FUNCTION() + +Reaplace old PICK_OP style macros with the new PICK_FUNCTION macro. + +Signed-off-by: Daniel Walker + +--- + include/linux/sched.h | 13 - + include/linux/spinlock.h | 345 ++++++++++++++--------------------------------- + kernel/rtmutex.c | 2 + lib/dec_and_lock.c | 2 + 4 files changed, 111 insertions(+), 251 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:03:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:03:42.000000000 -0500 +@@ -2033,17 +2033,8 @@ extern int __cond_resched_raw_spinlock(r + extern int __cond_resched_spinlock(spinlock_t *spinlock); + + #define cond_resched_lock(lock) \ +-({ \ +- int __ret; \ +- \ +- if (TYPE_EQUAL((lock), raw_spinlock_t)) \ +- __ret = __cond_resched_raw_spinlock((raw_spinlock_t *)lock);\ +- else if (TYPE_EQUAL(lock, spinlock_t)) \ +- __ret = __cond_resched_spinlock((spinlock_t *)lock); \ +- else __ret = __bad_spinlock_type(); \ +- \ +- __ret; \ +-}) ++ PICK_SPIN_OP_RET(__cond_resched_raw_spinlock, __cond_resched_spinlock,\ ++ lock) + + extern int cond_resched_softirq(void); + extern int cond_resched_softirq_context(void); +Index: linux-2.6.24.7-rt27/include/linux/spinlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/spinlock.h 2009-02-08 00:02:03.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/spinlock.h 2009-02-08 00:03:42.000000000 -0500 +@@ -91,6 +91,7 @@ + #include + #include + #include ++#include + + #include + +@@ -162,7 +163,7 @@ extern void __lockfunc rt_spin_unlock_wa + extern int __lockfunc + rt_spin_trylock_irqsave(spinlock_t *lock, unsigned long *flags); + extern int __lockfunc rt_spin_trylock(spinlock_t *lock); +-extern int _atomic_dec_and_spin_lock(atomic_t *atomic, spinlock_t *lock); ++extern int _atomic_dec_and_spin_lock(spinlock_t *lock, atomic_t *atomic); + + /* + * lockdep-less calls, for derived types like rwlock: +@@ -243,54 +244,6 @@ do { \ + # define _spin_trylock_irqsave(l,f) TSNBCONRT(l) + #endif + +-#undef TYPE_EQUAL +-#define TYPE_EQUAL(lock, type) \ +- __builtin_types_compatible_p(typeof(lock), type *) +- +-#define PICK_OP(op, lock) \ +-do { \ +- if (TYPE_EQUAL((lock), raw_spinlock_t)) \ +- __spin##op((raw_spinlock_t *)(lock)); \ +- else if (TYPE_EQUAL(lock, spinlock_t)) \ +- _spin##op((spinlock_t *)(lock)); \ +- else __bad_spinlock_type(); \ +-} while (0) +- +-#define PICK_OP_RET(op, lock...) \ +-({ \ +- unsigned long __ret; \ +- \ +- if (TYPE_EQUAL((lock), raw_spinlock_t)) \ +- __ret = __spin##op((raw_spinlock_t *)(lock)); \ +- else if (TYPE_EQUAL(lock, spinlock_t)) \ +- __ret = _spin##op((spinlock_t *)(lock)); \ +- else __ret = __bad_spinlock_type(); \ +- \ +- __ret; \ +-}) +- +-#define PICK_OP2(op, lock, flags) \ +-do { \ +- if (TYPE_EQUAL((lock), raw_spinlock_t)) \ +- __spin##op((raw_spinlock_t *)(lock), flags); \ +- else if (TYPE_EQUAL(lock, spinlock_t)) \ +- _spin##op((spinlock_t *)(lock), flags); \ +- else __bad_spinlock_type(); \ +-} while (0) +- +-#define PICK_OP2_RET(op, lock, flags) \ +-({ \ +- unsigned long __ret; \ +- \ +- if (TYPE_EQUAL((lock), raw_spinlock_t)) \ +- __ret = __spin##op((raw_spinlock_t *)(lock), flags); \ +- else if (TYPE_EQUAL(lock, spinlock_t)) \ +- __ret = _spin##op((spinlock_t *)(lock), flags); \ +- else __bad_spinlock_type(); \ +- \ +- __ret; \ +-}) +- + extern void __lockfunc rt_write_lock(rwlock_t *rwlock); + extern void __lockfunc rt_read_lock(rwlock_t *rwlock); + extern int __lockfunc rt_write_trylock(rwlock_t *rwlock); +@@ -349,76 +302,10 @@ do { \ + # define _read_unlock_irqrestore(rwl, f) rt_read_unlock(rwl) + # define _write_unlock_irqrestore(rwl, f) rt_write_unlock(rwl) + +-#define __PICK_RW_OP(optype, op, lock) \ +-do { \ +- if (TYPE_EQUAL((lock), raw_rwlock_t)) \ +- __##optype##op((raw_rwlock_t *)(lock)); \ +- else if (TYPE_EQUAL(lock, rwlock_t)) \ +- ##op((rwlock_t *)(lock)); \ +- else __bad_rwlock_type(); \ +-} while (0) +- +-#define PICK_RW_OP(optype, op, lock) \ +-do { \ +- if (TYPE_EQUAL((lock), raw_rwlock_t)) \ +- __##optype##op((raw_rwlock_t *)(lock)); \ +- else if (TYPE_EQUAL(lock, rwlock_t)) \ +- _##optype##op((rwlock_t *)(lock)); \ +- else __bad_rwlock_type(); \ +-} while (0) +- +-#define __PICK_RW_OP_RET(optype, op, lock...) \ +-({ \ +- unsigned long __ret; \ +- \ +- if (TYPE_EQUAL((lock), raw_rwlock_t)) \ +- __ret = __##optype##op((raw_rwlock_t *)(lock)); \ +- else if (TYPE_EQUAL(lock, rwlock_t)) \ +- __ret = _##optype##op((rwlock_t *)(lock)); \ +- else __ret = __bad_rwlock_type(); \ +- \ +- __ret; \ +-}) +- +-#define PICK_RW_OP_RET(optype, op, lock...) \ +-({ \ +- unsigned long __ret; \ +- \ +- if (TYPE_EQUAL((lock), raw_rwlock_t)) \ +- __ret = __##optype##op((raw_rwlock_t *)(lock)); \ +- else if (TYPE_EQUAL(lock, rwlock_t)) \ +- __ret = _##optype##op((rwlock_t *)(lock)); \ +- else __ret = __bad_rwlock_type(); \ +- \ +- __ret; \ +-}) +- +-#define PICK_RW_OP2(optype, op, lock, flags) \ +-do { \ +- if (TYPE_EQUAL((lock), raw_rwlock_t)) \ +- __##optype##op((raw_rwlock_t *)(lock), flags); \ +- else if (TYPE_EQUAL(lock, rwlock_t)) \ +- _##optype##op((rwlock_t *)(lock), flags); \ +- else __bad_rwlock_type(); \ +-} while (0) +- +-#define PICK_RW_OP2_RET(optype, op, lock, flags) \ +-({ \ +- unsigned long __ret; \ +- \ +- if (TYPE_EQUAL((lock), raw_rwlock_t)) \ +- __ret = __##optype##op((raw_rwlock_t *)(lock), flags); \ +- else if (TYPE_EQUAL(lock, rwlock_t)) \ +- __ret = _##optype##op((rwlock_t *)(lock), flags); \ +- else __bad_rwlock_type(); \ +- \ +- __ret; \ +-}) +- + #ifdef CONFIG_DEBUG_SPINLOCK + extern void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name, + struct lock_class_key *key); +-# define _raw_spin_lock_init(lock) \ ++# define _raw_spin_lock_init(lock, name, file, line) \ + do { \ + static struct lock_class_key __key; \ + \ +@@ -428,25 +315,28 @@ do { \ + #else + #define __raw_spin_lock_init(lock) \ + do { *(lock) = RAW_SPIN_LOCK_UNLOCKED(lock); } while (0) +-# define _raw_spin_lock_init(lock) __raw_spin_lock_init(lock) ++# define _raw_spin_lock_init(lock, name, file, line) __raw_spin_lock_init(lock) + #endif + +-#define PICK_OP_INIT(op, lock) \ +-do { \ +- if (TYPE_EQUAL((lock), raw_spinlock_t)) \ +- _raw_spin##op((raw_spinlock_t *)(lock)); \ +- else if (TYPE_EQUAL(lock, spinlock_t)) \ +- _spin##op((spinlock_t *)(lock), #lock, __FILE__, __LINE__); \ +- else __bad_spinlock_type(); \ +-} while (0) +- ++/* ++ * PICK_SPIN_OP()/PICK_RW_OP() are simple redirectors for PICK_FUNCTION ++ */ ++#define PICK_SPIN_OP(...) \ ++ PICK_FUNCTION(raw_spinlock_t *, spinlock_t *, ##__VA_ARGS__) ++#define PICK_SPIN_OP_RET(...) \ ++ PICK_FUNCTION_RET(raw_spinlock_t *, spinlock_t *, ##__VA_ARGS__) ++#define PICK_RW_OP(...) PICK_FUNCTION(raw_rwlock_t *, rwlock_t *, ##__VA_ARGS__) ++#define PICK_RW_OP_RET(...) \ ++ PICK_FUNCTION_RET(raw_rwlock_t *, rwlock_t *, ##__VA_ARGS__) + +-#define spin_lock_init(lock) PICK_OP_INIT(_lock_init, lock) ++#define spin_lock_init(lock) \ ++ PICK_SPIN_OP(_raw_spin_lock_init, _spin_lock_init, lock, #lock, \ ++ __FILE__, __LINE__) + + #ifdef CONFIG_DEBUG_SPINLOCK + extern void __raw_rwlock_init(raw_rwlock_t *lock, const char *name, + struct lock_class_key *key); +-# define _raw_rwlock_init(lock) \ ++# define _raw_rwlock_init(lock, name, file, line) \ + do { \ + static struct lock_class_key __key; \ + \ +@@ -455,83 +345,82 @@ do { \ + #else + #define __raw_rwlock_init(lock) \ + do { *(lock) = RAW_RW_LOCK_UNLOCKED(lock); } while (0) +-# define _raw_rwlock_init(lock) __raw_rwlock_init(lock) ++# define _raw_rwlock_init(lock, name, file, line) __raw_rwlock_init(lock) + #endif + +-#define __PICK_RW_OP_INIT(optype, op, lock) \ +-do { \ +- if (TYPE_EQUAL((lock), raw_rwlock_t)) \ +- _raw_##optype##op((raw_rwlock_t *)(lock)); \ +- else if (TYPE_EQUAL(lock, rwlock_t)) \ +- _##optype##op((rwlock_t *)(lock), #lock, __FILE__, __LINE__);\ +- else __bad_spinlock_type(); \ +-} while (0) +- +-#define rwlock_init(lock) __PICK_RW_OP_INIT(rwlock, _init, lock) ++#define rwlock_init(lock) \ ++ PICK_RW_OP(_raw_rwlock_init, _rwlock_init, lock, #lock, \ ++ __FILE__, __LINE__) + + #define __spin_is_locked(lock) __raw_spin_is_locked(&(lock)->raw_lock) + +-#define spin_is_locked(lock) PICK_OP_RET(_is_locked, lock) ++#define spin_is_locked(lock) \ ++ PICK_SPIN_OP_RET(__spin_is_locked, _spin_is_locked, lock) + + #define __spin_unlock_wait(lock) __raw_spin_unlock_wait(&(lock)->raw_lock) + +-#define spin_unlock_wait(lock) PICK_OP(_unlock_wait, lock) ++#define spin_unlock_wait(lock) \ ++ PICK_SPIN_OP(__spin_unlock_wait, _spin_unlock_wait, lock) ++ + /* + * Define the various spin_lock and rw_lock methods. Note we define these + * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various + * methods are defined as nops in the case they are not required. + */ +-// #define spin_trylock(lock) _spin_trylock(lock) +-#define spin_trylock(lock) __cond_lock(lock, PICK_OP_RET(_trylock, lock)) ++#define spin_trylock(lock) \ ++ __cond_lock(lock, PICK_SPIN_OP_RET(__spin_trylock, _spin_trylock, lock)) + +-//#define read_trylock(lock) _read_trylock(lock) +-#define read_trylock(lock) __cond_lock(lock, PICK_RW_OP_RET(read, _trylock, lock)) ++#define read_trylock(lock) \ ++ __cond_lock(lock, PICK_RW_OP_RET(__read_trylock, _read_trylock, lock)) + +-//#define write_trylock(lock) _write_trylock(lock) +-#define write_trylock(lock) __cond_lock(lock, PICK_RW_OP_RET(write, _trylock, lock)) ++#define write_trylock(lock) \ ++ __cond_lock(lock, PICK_RW_OP_RET(__write_trylock, _write_trylock, lock)) + + #define write_trylock_irqsave(lock, flags) \ +- __cond_lock(lock, PICK_RW_OP2_RET(write, _trylock_irqsave, lock, &flags)) ++ __cond_lock(lock, PICK_RW_OP_RET(__write_trylock_irqsave, \ ++ _write_trylock_irqsave, lock, &flags)) + + #define __spin_can_lock(lock) __raw_spin_can_lock(&(lock)->raw_lock) + #define __read_can_lock(lock) __raw_read_can_lock(&(lock)->raw_lock) + #define __write_can_lock(lock) __raw_write_can_lock(&(lock)->raw_lock) + + #define spin_can_lock(lock) \ +- __cond_lock(lock, PICK_OP_RET(_can_lock, lock)) ++ __cond_lock(lock, PICK_SPIN_OP_RET(__spin_can_lock, _spin_can_lock,\ ++ lock)) + + #define read_can_lock(lock) \ +- __cond_lock(lock, PICK_RW_OP_RET(read, _can_lock, lock)) ++ __cond_lock(lock, PICK_RW_OP_RET(__read_can_lock, _read_can_lock, lock)) + + #define write_can_lock(lock) \ +- __cond_lock(lock, PICK_RW_OP_RET(write, _can_lock, lock)) ++ __cond_lock(lock, PICK_RW_OP_RET(__write_can_lock, _write_can_lock,\ ++ lock)) + +-// #define spin_lock(lock) _spin_lock(lock) +-#define spin_lock(lock) PICK_OP(_lock, lock) ++#define spin_lock(lock) PICK_SPIN_OP(__spin_lock, _spin_lock, lock) + + #ifdef CONFIG_DEBUG_LOCK_ALLOC +-# define spin_lock_nested(lock, subclass) PICK_OP2(_lock_nested, lock, subclass) ++# define spin_lock_nested(lock, subclass) \ ++ PICK_SPIN_OP(__spin_lock_nested, _spin_lock_nested, lock, subclass) + #else + # define spin_lock_nested(lock, subclass) spin_lock(lock) + #endif + +-//#define write_lock(lock) _write_lock(lock) +-#define write_lock(lock) PICK_RW_OP(write, _lock, lock) ++#define write_lock(lock) PICK_RW_OP(__write_lock, _write_lock, lock) + +-// #define read_lock(lock) _read_lock(lock) +-#define read_lock(lock) PICK_RW_OP(read, _lock, lock) ++#define read_lock(lock) PICK_RW_OP(__read_lock, _read_lock, lock) + + # define spin_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ +- flags = PICK_OP_RET(_lock_irqsave, lock); \ ++ flags = PICK_SPIN_OP_RET(__spin_lock_irqsave, _spin_lock_irqsave, \ ++ lock); \ + } while (0) + + #ifdef CONFIG_DEBUG_LOCK_ALLOC + # define spin_lock_irqsave_nested(lock, flags, subclass) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ +- flags = PICK_OP2_RET(_lock_irqsave_nested, lock, subclass); \ ++ flags = PICK_SPIN_OP_RET(__spin_lock_irqsave_nested, \ ++ _spin_lock_irqsave_nested, lock, subclass); \ + } while (0) + #else + # define spin_lock_irqsave_nested(lock, flags, subclass) \ +@@ -541,112 +430,92 @@ do { \ + # define read_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ +- flags = PICK_RW_OP_RET(read, _lock_irqsave, lock); \ ++ flags = PICK_RW_OP_RET(__read_lock_irqsave, _read_lock_irqsave, lock);\ + } while (0) + + # define write_lock_irqsave(lock, flags) \ + do { \ + BUILD_CHECK_IRQ_FLAGS(flags); \ +- flags = PICK_RW_OP_RET(write, _lock_irqsave, lock); \ ++ flags = PICK_RW_OP_RET(__write_lock_irqsave, _write_lock_irqsave,lock);\ + } while (0) + +-// #define spin_lock_irq(lock) _spin_lock_irq(lock) +-// #define spin_lock_bh(lock) _spin_lock_bh(lock) +-#define spin_lock_irq(lock) PICK_OP(_lock_irq, lock) +-#define spin_lock_bh(lock) PICK_OP(_lock_bh, lock) +- +-// #define read_lock_irq(lock) _read_lock_irq(lock) +-// #define read_lock_bh(lock) _read_lock_bh(lock) +-#define read_lock_irq(lock) PICK_RW_OP(read, _lock_irq, lock) +-#define read_lock_bh(lock) PICK_RW_OP(read, _lock_bh, lock) +- +-// #define write_lock_irq(lock) _write_lock_irq(lock) +-// #define write_lock_bh(lock) _write_lock_bh(lock) +-#define write_lock_irq(lock) PICK_RW_OP(write, _lock_irq, lock) +-#define write_lock_bh(lock) PICK_RW_OP(write, _lock_bh, lock) +- +-// #define spin_unlock(lock) _spin_unlock(lock) +-// #define write_unlock(lock) _write_unlock(lock) +-// #define read_unlock(lock) _read_unlock(lock) +-#define spin_unlock(lock) PICK_OP(_unlock, lock) +-#define read_unlock(lock) PICK_RW_OP(read, _unlock, lock) +-#define write_unlock(lock) PICK_RW_OP(write, _unlock, lock) ++#define spin_lock_irq(lock) PICK_SPIN_OP(__spin_lock_irq, _spin_lock_irq, lock) + +-// #define spin_unlock(lock) _spin_unlock_no_resched(lock) +-#define spin_unlock_no_resched(lock) \ +- PICK_OP(_unlock_no_resched, lock) ++#define spin_lock_bh(lock) PICK_SPIN_OP(__spin_lock_bh, _spin_lock_bh, lock) + +-//#define spin_unlock_irqrestore(lock, flags) +-// _spin_unlock_irqrestore(lock, flags) +-//#define spin_unlock_irq(lock) _spin_unlock_irq(lock) +-//#define spin_unlock_bh(lock) _spin_unlock_bh(lock) +-#define spin_unlock_irqrestore(lock, flags) \ +-do { \ +- BUILD_CHECK_IRQ_FLAGS(flags); \ +- PICK_OP2(_unlock_irqrestore, lock, flags); \ +-} while (0) ++#define read_lock_irq(lock) PICK_RW_OP(__read_lock_irq, _read_lock_irq, lock) + +-#define spin_unlock_irq(lock) PICK_OP(_unlock_irq, lock) +-#define spin_unlock_bh(lock) PICK_OP(_unlock_bh, lock) ++#define read_lock_bh(lock) PICK_RW_OP(__read_lock_bh, _read_lock_bh, lock) + +-// #define read_unlock_irqrestore(lock, flags) +-// _read_unlock_irqrestore(lock, flags) +-// #define read_unlock_irq(lock) _read_unlock_irq(lock) +-// #define read_unlock_bh(lock) _read_unlock_bh(lock) +-#define read_unlock_irqrestore(lock, flags) \ +-do { \ +- BUILD_CHECK_IRQ_FLAGS(flags); \ +- PICK_RW_OP2(read, _unlock_irqrestore, lock, flags); \ ++#define write_lock_irq(lock) PICK_RW_OP(__write_lock_irq, _write_lock_irq, lock) ++ ++#define write_lock_bh(lock) PICK_RW_OP(__write_lock_bh, _write_lock_bh, lock) ++ ++#define spin_unlock(lock) PICK_SPIN_OP(__spin_unlock, _spin_unlock, lock) ++ ++#define read_unlock(lock) PICK_RW_OP(__read_unlock, _read_unlock, lock) ++ ++#define write_unlock(lock) PICK_RW_OP(__write_unlock, _write_unlock, lock) ++ ++#define spin_unlock_no_resched(lock) \ ++ PICK_SPIN_OP(__spin_unlock_no_resched, _spin_unlock_no_resched, lock) ++ ++#define spin_unlock_irqrestore(lock, flags) \ ++do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ PICK_SPIN_OP(__spin_unlock_irqrestore, _spin_unlock_irqrestore, \ ++ lock, flags); \ + } while (0) + +-#define read_unlock_irq(lock) PICK_RW_OP(read, _unlock_irq, lock) +-#define read_unlock_bh(lock) PICK_RW_OP(read, _unlock_bh, lock) ++#define spin_unlock_irq(lock) \ ++ PICK_SPIN_OP(__spin_unlock_irq, _spin_unlock_irq, lock) ++#define spin_unlock_bh(lock) \ ++ PICK_SPIN_OP(__spin_unlock_bh, _spin_unlock_bh, lock) + +-// #define write_unlock_irqrestore(lock, flags) +-// _write_unlock_irqrestore(lock, flags) +-// #define write_unlock_irq(lock) _write_unlock_irq(lock) +-// #define write_unlock_bh(lock) _write_unlock_bh(lock) +-#define write_unlock_irqrestore(lock, flags) \ +-do { \ +- BUILD_CHECK_IRQ_FLAGS(flags); \ +- PICK_RW_OP2(write, _unlock_irqrestore, lock, flags); \ ++#define read_unlock_irqrestore(lock, flags) \ ++do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ PICK_RW_OP(__read_unlock_irqrestore, _read_unlock_irqrestore, \ ++ lock, flags); \ + } while (0) +-#define write_unlock_irq(lock) PICK_RW_OP(write, _unlock_irq, lock) +-#define write_unlock_bh(lock) PICK_RW_OP(write, _unlock_bh, lock) + +-// #define spin_trylock_bh(lock) _spin_trylock_bh(lock) +-#define spin_trylock_bh(lock) __cond_lock(lock, PICK_OP_RET(_trylock_bh, lock)) ++#define read_unlock_irq(lock) \ ++ PICK_RW_OP(__read_unlock_irq, _read_unlock_irq, lock) ++#define read_unlock_bh(lock) PICK_RW_OP(__read_unlock_bh, _read_unlock_bh, lock) + +-// #define spin_trylock_irq(lock) ++#define write_unlock_irqrestore(lock, flags) \ ++do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ PICK_RW_OP(__write_unlock_irqrestore, _write_unlock_irqrestore, \ ++ lock, flags); \ ++} while (0) ++#define write_unlock_irq(lock) \ ++ PICK_RW_OP(__write_unlock_irq, _write_unlock_irq, lock) + +-#define spin_trylock_irq(lock) __cond_lock(lock, PICK_OP_RET(_trylock_irq, lock)) ++#define write_unlock_bh(lock) \ ++ PICK_RW_OP(__write_unlock_bh, _write_unlock_bh, lock) + +-// #define spin_trylock_irqsave(lock, flags) ++#define spin_trylock_bh(lock) \ ++ __cond_lock(lock, PICK_SPIN_OP_RET(__spin_trylock_bh, _spin_trylock_bh,\ ++ lock)) ++ ++#define spin_trylock_irq(lock) \ ++ __cond_lock(lock, PICK_SPIN_OP_RET(__spin_trylock_irq, \ ++ __spin_trylock_irq, lock)) + + #define spin_trylock_irqsave(lock, flags) \ +- __cond_lock(lock, PICK_OP2_RET(_trylock_irqsave, lock, &flags)) ++ __cond_lock(lock, PICK_SPIN_OP_RET(__spin_trylock_irqsave, \ ++ _spin_trylock_irqsave, lock, &flags)) + + /* "lock on reference count zero" */ + #ifndef ATOMIC_DEC_AND_LOCK + # include +- extern int __atomic_dec_and_spin_lock(atomic_t *atomic, raw_spinlock_t *lock); ++ extern int __atomic_dec_and_spin_lock(raw_spinlock_t *lock, atomic_t *atomic); + #endif + + #define atomic_dec_and_lock(atomic, lock) \ +-__cond_lock(lock, ({ \ +- unsigned long __ret; \ +- \ +- if (TYPE_EQUAL(lock, raw_spinlock_t)) \ +- __ret = __atomic_dec_and_spin_lock(atomic, \ +- (raw_spinlock_t *)(lock)); \ +- else if (TYPE_EQUAL(lock, spinlock_t)) \ +- __ret = _atomic_dec_and_spin_lock(atomic, \ +- (spinlock_t *)(lock)); \ +- else __ret = __bad_spinlock_type(); \ +- \ +- __ret; \ +-})) +- ++ __cond_lock(lock, PICK_SPIN_OP_RET(__atomic_dec_and_spin_lock, \ ++ _atomic_dec_and_spin_lock, lock, atomic)) + + /* + * bit-based spin_lock() +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:03:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:03:42.000000000 -0500 +@@ -857,7 +857,7 @@ int __lockfunc rt_spin_trylock_irqsave(s + } + EXPORT_SYMBOL(rt_spin_trylock_irqsave); + +-int _atomic_dec_and_spin_lock(atomic_t *atomic, spinlock_t *lock) ++int _atomic_dec_and_spin_lock(spinlock_t *lock, atomic_t *atomic) + { + /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */ + if (atomic_add_unless(atomic, -1, 1)) +Index: linux-2.6.24.7-rt27/lib/dec_and_lock.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/dec_and_lock.c 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/dec_and_lock.c 2009-02-08 00:03:42.000000000 -0500 +@@ -17,7 +17,7 @@ + * because the spin-lock and the decrement must be + * "atomic". + */ +-int __atomic_dec_and_spin_lock(atomic_t *atomic, raw_spinlock_t *lock) ++int __atomic_dec_and_spin_lock(raw_spinlock_t *lock, atomic_t *atomic) + { + #ifdef CONFIG_SMP + /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0454-rwlock-typecast-cmpxchg.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0454-rwlock-typecast-cmpxchg.patch @@ -0,0 +1,35 @@ +--- + kernel/rtmutex.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:26.000000000 -0500 +@@ -1577,7 +1577,7 @@ rt_write_fastlock(struct rw_mutex *rwm, + void fastcall (*slowfn)(struct rw_mutex *rwm, int mtx), + int mtx) + { +- unsigned long val = (unsigned long)current | RT_RWLOCK_WRITER; ++ struct task_struct *val = (void *)((unsigned long)current | RT_RWLOCK_WRITER); + + if (likely(rt_rwlock_cmpxchg(rwm, NULL, val))) + rt_mutex_deadlock_account_lock(&rwm->mutex, current); +@@ -1617,7 +1617,7 @@ static inline int + rt_write_fasttrylock(struct rw_mutex *rwm, + int fastcall (*slowfn)(struct rw_mutex *rwm, int mtx), int mtx) + { +- unsigned long val = (unsigned long)current | RT_RWLOCK_WRITER; ++ struct task_struct *val = (void *)((unsigned long)current | RT_RWLOCK_WRITER); + + if (likely(rt_rwlock_cmpxchg(rwm, NULL, val))) { + rt_mutex_deadlock_account_lock(&rwm->mutex, current); +@@ -1902,7 +1902,7 @@ rt_write_fastunlock(struct rw_mutex *rwm + int mtx), + int mtx) + { +- unsigned long val = (unsigned long)current | RT_RWLOCK_WRITER; ++ struct task_struct *val = (void *)((unsigned long)current | RT_RWLOCK_WRITER); + + WARN_ON(rt_rwlock_owner(rwm) != current); + if (likely(rt_rwlock_cmpxchg(rwm, (struct task_struct *)val, NULL))) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0339-rcu-preempt-hotplug-hackaround.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0339-rcu-preempt-hotplug-hackaround.patch @@ -0,0 +1,16 @@ +--- + kernel/sched.c | 1 - + 1 file changed, 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:03:21.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:03:32.000000000 -0500 +@@ -7076,7 +7076,6 @@ static void detach_destroy_domains(const + + for_each_cpu_mask(i, *cpu_map) + cpu_attach_domain(NULL, &def_root_domain, i); +- synchronize_sched(); + arch_destroy_sched_domains(cpu_map); + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0008-linux-2.6.24-pollfix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0008-linux-2.6.24-pollfix.patch @@ -0,0 +1,26 @@ +Make sys_poll() wait at least timeout ms +From: Karsten Wiese + +schedule_timeout(jiffies) waits for at least jiffies - 1. +Add 1 jiffie to the timeout_jiffies calculated in sys_poll() to wait at least +timeout_msecs, like poll() manpage says. + +Signed-off-by: Karsten Wiese +--- + + fs/select.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/fs/select.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/select.c 2009-02-08 00:00:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/select.c 2009-02-08 00:00:42.000000000 -0500 +@@ -739,7 +739,7 @@ asmlinkage long sys_poll(struct pollfd _ + timeout_jiffies = -1; + else + #endif +- timeout_jiffies = msecs_to_jiffies(timeout_msecs); ++ timeout_jiffies = msecs_to_jiffies(timeout_msecs) + 1; + } else { + /* Infinite (< 0) or no (0) timeout */ + timeout_jiffies = timeout_msecs; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0279-s_files-schedule_on_each_cpu_wq.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0279-s_files-schedule_on_each_cpu_wq.patch @@ -0,0 +1,112 @@ +--- + include/linux/workqueue.h | 1 + kernel/workqueue.c | 65 ++++++++++++++++++++++++++++++++++++++-------- + 2 files changed, 55 insertions(+), 11 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/workqueue.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/workqueue.h 2009-02-08 00:02:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/workqueue.h 2009-02-08 00:03:00.000000000 -0500 +@@ -195,6 +195,7 @@ extern int FASTCALL(schedule_delayed_wor + unsigned long delay)); + extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, + unsigned long delay); ++extern int schedule_on_each_cpu_wq(struct workqueue_struct *wq, work_func_t func); + extern int schedule_on_each_cpu(work_func_t func); + extern int current_is_keventd(void); + extern int keventd_up(void); +Index: linux-2.6.24.7-rt27/kernel/workqueue.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/workqueue.c 2009-02-08 00:02:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/workqueue.c 2009-02-08 00:03:00.000000000 -0500 +@@ -244,6 +244,20 @@ int queue_delayed_work_on(int cpu, struc + } + EXPORT_SYMBOL_GPL(queue_delayed_work_on); + ++static void leak_check(void *func) ++{ ++ if (!in_atomic() && lockdep_depth(current) <= 0) ++ return; ++ printk(KERN_ERR "BUG: workqueue leaked lock or atomic: " ++ "%s/0x%08x/%d\n", ++ current->comm, preempt_count(), ++ current->pid); ++ printk(KERN_ERR " last function: "); ++ print_symbol("%s\n", (unsigned long)func); ++ debug_show_held_locks(current); ++ dump_stack(); ++} ++ + static void run_workqueue(struct cpu_workqueue_struct *cwq) + { + spin_lock_irq(&cwq->lock); +@@ -276,22 +290,13 @@ static void run_workqueue(struct cpu_wor + + BUG_ON(get_wq_data(work) != cwq); + work_clear_pending(work); ++ leak_check(NULL); + lock_acquire(&cwq->wq->lockdep_map, 0, 0, 0, 2, _THIS_IP_); + lock_acquire(&lockdep_map, 0, 0, 0, 2, _THIS_IP_); + f(work); + lock_release(&lockdep_map, 1, _THIS_IP_); + lock_release(&cwq->wq->lockdep_map, 1, _THIS_IP_); +- +- if (unlikely(in_atomic() || lockdep_depth(current) > 0)) { +- printk(KERN_ERR "BUG: workqueue leaked lock or atomic: " +- "%s/0x%08x/%d\n", +- current->comm, preempt_count(), +- task_pid_nr(current)); +- printk(KERN_ERR " last function: "); +- print_symbol("%s\n", (unsigned long)f); +- debug_show_held_locks(current); +- dump_stack(); +- } ++ leak_check(f); + + spin_lock_irq(&cwq->lock); + cwq->current_work = NULL; +@@ -623,6 +628,44 @@ int schedule_on_each_cpu(work_func_t fun + return 0; + } + ++/** ++ * schedule_on_each_cpu_wq - call a function on each online CPU on a per-CPU wq ++ * @func: the function to call ++ * ++ * Returns zero on success. ++ * Returns -ve errno on failure. ++ * ++ * Appears to be racy against CPU hotplug. ++ * ++ * schedule_on_each_cpu() is very slow. ++ */ ++int schedule_on_each_cpu_wq(struct workqueue_struct *wq, work_func_t func) ++{ ++ int cpu; ++ struct work_struct *works; ++ ++ if (is_single_threaded(wq)) { ++ WARN_ON(1); ++ return -EINVAL; ++ } ++ works = alloc_percpu(struct work_struct); ++ if (!works) ++ return -ENOMEM; ++ ++ for_each_online_cpu(cpu) { ++ struct work_struct *work = per_cpu_ptr(works, cpu); ++ ++ INIT_WORK(work, func); ++ set_bit(WORK_STRUCT_PENDING, work_data_bits(work)); ++ __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work); ++ } ++ flush_workqueue(wq); ++ free_percpu(works); ++ ++ return 0; ++} ++ ++ + void flush_scheduled_work(void) + { + flush_workqueue(keventd_wq); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0248-preempt-realtime-compile-fixes.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0248-preempt-realtime-compile-fixes.patch @@ -0,0 +1,17 @@ +--- + drivers/block/paride/pseudo.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/drivers/block/paride/pseudo.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/block/paride/pseudo.h 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/block/paride/pseudo.h 2009-02-08 00:02:44.000000000 -0500 +@@ -43,7 +43,7 @@ static unsigned long ps_timeout; + static int ps_tq_active = 0; + static int ps_nice = 0; + +-static DEFINE_SPINLOCK(ps_spinlock __attribute__((unused))); ++static __attribute__((unused)) DEFINE_SPINLOCK(ps_spinlock); + + static DECLARE_DELAYED_WORK(ps_tq, ps_tq_int); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0391-send-nmi-all-preempt-disable.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0391-send-nmi-all-preempt-disable.patch @@ -0,0 +1,35 @@ +--- + arch/x86/kernel/nmi_32.c | 2 ++ + arch/x86/kernel/nmi_64.c | 2 ++ + 2 files changed, 4 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_32.c 2009-02-08 00:03:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c 2009-02-08 00:03:56.000000000 -0500 +@@ -538,9 +538,11 @@ void smp_send_nmi_allbutself(void) + { + #ifdef CONFIG_SMP + cpumask_t mask = cpu_online_map; ++ preempt_disable(); + cpu_clear(safe_smp_processor_id(), mask); + if (!cpus_empty(mask)) + send_IPI_mask(mask, NMI_VECTOR); ++ preempt_enable(); + #endif + } + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_64.c 2009-02-08 00:03:40.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c 2009-02-08 00:03:56.000000000 -0500 +@@ -539,7 +539,9 @@ void __trigger_all_cpu_backtrace(void) + void smp_send_nmi_allbutself(void) + { + #ifdef CONFIG_SMP ++ preempt_disable(); + send_IPI_allbutself(NMI_VECTOR); ++ preempt_enable(); + #endif + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0082-ep93xx-timer-accuracy.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0082-ep93xx-timer-accuracy.patch @@ -0,0 +1,53 @@ + +The ep93xx has a weird timer tick base (983.04 kHz.) This experimental +patch tries to increase time of day accuracy by keeping the number of +ticks until the next jiffy in a fractional value representation. + +Signed-off-by: Lennert Buytenhek + +--- + arch/arm/mach-ep93xx/core.c | 23 ++++++++++++++++++----- + 1 file changed, 18 insertions(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/arm/mach-ep93xx/core.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mach-ep93xx/core.c 2009-02-08 00:00:23.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mach-ep93xx/core.c 2009-02-08 00:01:22.000000000 -0500 +@@ -94,19 +94,32 @@ void __init ep93xx_map_io(void) + * track of lost jiffies. + */ + static unsigned int last_jiffy_time; ++static unsigned int next_jiffy_time; ++static unsigned int accumulator; + +-#define TIMER4_TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ) ++#define TIMER4_TICKS_PER_JIFFY (983040 / HZ) ++#define TIMER4_TICKS_MOD_JIFFY (983040 % HZ) ++ ++static int after_eq(unsigned long a, unsigned long b) ++{ ++ return ((signed long)(a - b)) >= 0; ++} + + static int ep93xx_timer_interrupt(int irq, void *dev_id) + { + write_seqlock(&xtime_lock); + + __raw_writel(1, EP93XX_TIMER1_CLEAR); +- while ((signed long) +- (__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time) +- >= TIMER4_TICKS_PER_JIFFY) { +- last_jiffy_time += TIMER4_TICKS_PER_JIFFY; ++ while (after_eq(__raw_readl(EP93XX_TIMER4_VALUE_LOW), next_jiffy_time)) { + timer_tick(); ++ ++ last_jiffy_time = next_jiffy_time; ++ next_jiffy_time += TIMER4_TICKS_PER_JIFFY; ++ accumulator += TIMER4_TICKS_MOD_JIFFY; ++ if (accumulator >= HZ) { ++ next_jiffy_time++; ++ accumulator -= HZ; ++ } + } + + write_sequnlock(&xtime_lock); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0348-powerpc-count_active_rt_tasks-is-undefined-for-non-preempt-rt.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0348-powerpc-count_active_rt_tasks-is-undefined-for-non-preempt-rt.patch @@ -0,0 +1,50 @@ +From tony@bakeyournoodle.com Wed Sep 26 10:26:59 2007 +Date: Tue, 04 Sep 2007 17:09:02 +1000 +From: Tony Breeds +To: linux-rt-users@vger.kernel.org +Subject: [PATCH 2/5] count_active_rt_tasks() is undefined when + CONFIG_PREEMPT_RT is not set. + +Also, it looks to me that active_rt_tasks[] was never modified. + +Signed-off-by: Tony Breeds + +--- + + kernel/timer.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/timer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/timer.c 2009-02-08 00:03:21.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/timer.c 2009-02-08 00:03:36.000000000 -0500 +@@ -973,21 +973,25 @@ unsigned long avenrun_rt[3]; + static inline void calc_load(unsigned long ticks) + { + unsigned long active_tasks; /* fixed-point */ +- unsigned long active_rt_tasks; /* fixed-point */ + static int count = LOAD_FREQ; ++#ifdef CONFIG_PREEMPT_RT ++ unsigned long active_rt_tasks; /* fixed-point */ ++#endif + + count -= ticks; + if (unlikely(count < 0)) { + active_tasks = count_active_tasks(); ++#ifdef CONFIG_PREEMPT_RT + active_rt_tasks = count_active_rt_tasks(); ++#endif + do { + CALC_LOAD(avenrun[0], EXP_1, active_tasks); + CALC_LOAD(avenrun[1], EXP_5, active_tasks); + CALC_LOAD(avenrun[2], EXP_15, active_tasks); + #ifdef CONFIG_PREEMPT_RT +- CALC_LOAD(avenrun_rt[0], EXP_1, active_tasks); +- CALC_LOAD(avenrun_rt[1], EXP_5, active_tasks); +- CALC_LOAD(avenrun_rt[2], EXP_15, active_tasks); ++ CALC_LOAD(avenrun_rt[0], EXP_1, active_rt_tasks); ++ CALC_LOAD(avenrun_rt[1], EXP_5, active_rt_tasks); ++ CALC_LOAD(avenrun_rt[2], EXP_15, active_rt_tasks); + #endif + count += LOAD_FREQ; + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0267-preempt-realtime-loopback.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0267-preempt-realtime-loopback.patch @@ -0,0 +1,17 @@ +--- + drivers/net/loopback.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/drivers/net/loopback.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/net/loopback.c 2009-02-08 00:01:38.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/net/loopback.c 2009-02-08 00:02:53.000000000 -0500 +@@ -160,7 +160,7 @@ static int loopback_xmit(struct sk_buff + lb_stats->packets++; + put_cpu(); + +- netif_rx(skb); ++ netif_rx_ni(skb); + + return 0; + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0075-powerpc-remove-ip-converted.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0075-powerpc-remove-ip-converted.patch @@ -0,0 +1,25 @@ +--- + arch/powerpc/kernel/ftrace.c | 10 ---------- + 1 file changed, 10 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/ftrace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/ftrace.c 2009-02-08 00:01:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/ftrace.c 2009-02-08 00:01:18.000000000 -0500 +@@ -27,16 +27,6 @@ static unsigned int ftrace_nop = 0x60000 + # define GET_ADDR(addr) *(unsigned long *)addr + #endif + +-notrace int ftrace_ip_converted(unsigned long ip) +-{ +- unsigned int save; +- +- ip -= CALL_BACK; +- save = *(unsigned int *)ip; +- +- return save == ftrace_nop; +-} +- + static unsigned int notrace ftrace_calc_offset(long ip, long addr) + { + return (int)((addr + CALL_BACK) - ip); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0309-highmem-redo-mainline.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0309-highmem-redo-mainline.patch @@ -0,0 +1,23 @@ +--- + mm/highmem.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +Index: linux-2.6.24.7-rt27/mm/highmem.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/highmem.c 2009-02-08 00:03:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/highmem.c 2009-02-08 00:03:17.000000000 -0500 +@@ -214,6 +214,14 @@ static unsigned long pkmap_insert(struct + return vaddr; + } + ++/* ++ * Flush all unused kmap mappings in order to remove stray mappings. ++ */ ++void kmap_flush_unused(void) ++{ ++ WARN_ON_ONCE(1); ++} ++ + fastcall void *kmap_high(struct page *page) + { + unsigned long vaddr; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0067-event-tracer-syscall-x86_64.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0067-event-tracer-syscall-x86_64.patch @@ -0,0 +1,168 @@ +Add hooks to x86 to track syscalls for event trace. + +This code was taken from the work by Ingo Molnar. + +Signed-off-by: Steven Rostedt +--- + arch/x86/ia32/ia32entry.S | 9 +++++++ + arch/x86/kernel/entry_64.S | 8 ++++++- + include/asm-x86/calling.h | 50 ++++++++++++++++++++++++++++++++++++++++++++ + include/asm-x86/unistd_64.h | 2 + + 4 files changed, 67 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/ia32/ia32entry.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/ia32/ia32entry.S 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/ia32/ia32entry.S 2009-02-08 00:01:15.000000000 -0500 +@@ -132,7 +132,9 @@ sysenter_do_call: + cmpl $(IA32_NR_syscalls-1),%eax + ja ia32_badsys + IA32_ARG_FIXUP 1 ++ TRACE_SYS_IA32_CALL + call *ia32_sys_call_table(,%rax,8) ++ TRACE_SYS_RET + movq %rax,RAX-ARGOFFSET(%rsp) + GET_THREAD_INFO(%r10) + cli +@@ -237,7 +239,9 @@ cstar_do_call: + cmpl $IA32_NR_syscalls-1,%eax + ja ia32_badsys + IA32_ARG_FIXUP 1 ++ TRACE_SYS_IA32_CALL + call *ia32_sys_call_table(,%rax,8) ++ TRACE_SYS_RET + movq %rax,RAX-ARGOFFSET(%rsp) + GET_THREAD_INFO(%r10) + cli +@@ -328,8 +332,10 @@ ia32_do_syscall: + cmpl $(IA32_NR_syscalls-1),%eax + ja ia32_badsys + IA32_ARG_FIXUP ++ TRACE_SYS_IA32_CALL + call *ia32_sys_call_table(,%rax,8) # xxx: rip relative + ia32_sysret: ++ TRACE_SYS_RET + movq %rax,RAX-ARGOFFSET(%rsp) + jmp int_ret_from_sys_call + +@@ -400,7 +406,7 @@ END(ia32_ptregs_common) + + .section .rodata,"a" + .align 8 +-ia32_sys_call_table: ++ENTRY(ia32_sys_call_table) + .quad sys_restart_syscall + .quad sys_exit + .quad stub32_fork +@@ -726,4 +732,5 @@ ia32_sys_call_table: + .quad compat_sys_timerfd + .quad sys_eventfd + .quad sys32_fallocate ++.globl ia32_syscall_end + ia32_syscall_end: +Index: linux-2.6.24.7-rt27/arch/x86/kernel/entry_64.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/entry_64.S 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/entry_64.S 2009-02-08 00:01:15.000000000 -0500 +@@ -338,7 +338,10 @@ ENTRY(system_call) + cmpq $__NR_syscall_max,%rax + ja badsys + movq %r10,%rcx ++ TRACE_SYS_CALL + call *sys_call_table(,%rax,8) # XXX: rip relative ++system_call_ret: ++ TRACE_SYS_RET + movq %rax,RAX-ARGOFFSET(%rsp) + /* + * Syscall return path ending with SYSRET (fast path) +@@ -408,7 +411,7 @@ badsys: + jmp ret_from_sys_call + + /* Do syscall tracing */ +-tracesys: ++tracesys: + SAVE_REST + movq $-ENOSYS,RAX(%rsp) + FIXUP_TOP_OF_STACK %rdi +@@ -421,7 +424,10 @@ tracesys: + cmova %rcx,%rax + ja 1f + movq %r10,%rcx /* fixup for C */ ++ TRACE_SYS_CALL + call *sys_call_table(,%rax,8) ++traceret: ++ TRACE_SYS_RET + 1: movq %rax,RAX-ARGOFFSET(%rsp) + /* Use IRET because user could have changed frame */ + +Index: linux-2.6.24.7-rt27/include/asm-x86/calling.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/calling.h 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/calling.h 2009-02-08 00:01:15.000000000 -0500 +@@ -160,3 +160,53 @@ + .macro icebp + .byte 0xf1 + .endm ++ ++/* ++ * latency-tracing helpers: ++ */ ++ ++ .macro TRACE_SYS_CALL ++ ++#ifdef CONFIG_EVENT_TRACER ++ SAVE_ARGS ++ ++ mov %rdx, %rcx ++ mov %rsi, %rdx ++ mov %rdi, %rsi ++ mov %rax, %rdi ++ ++ call sys_call ++ ++ RESTORE_ARGS ++#endif ++ .endm ++ ++ ++ .macro TRACE_SYS_IA32_CALL ++ ++#ifdef CONFIG_EVENT_TRACER ++ SAVE_ARGS ++ ++ mov %rdx, %rcx ++ mov %rsi, %rdx ++ mov %rdi, %rsi ++ mov %rax, %rdi ++ ++ call sys_ia32_call ++ ++ RESTORE_ARGS ++#endif ++ .endm ++ ++ .macro TRACE_SYS_RET ++ ++#ifdef CONFIG_EVENT_TRACER ++ SAVE_ARGS ++ ++ mov %rax, %rdi ++ ++ call sys_ret ++ ++ RESTORE_ARGS ++#endif ++ .endm +Index: linux-2.6.24.7-rt27/include/asm-x86/unistd_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/unistd_64.h 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/unistd_64.h 2009-02-08 00:01:15.000000000 -0500 +@@ -11,6 +11,8 @@ + * Note: holes are not allowed. + */ + ++#define NR_syscalls (__NR_syscall_max+1) ++ + /* at least 8 syscall per cacheline */ + #define __NR_read 0 + __SYSCALL(__NR_read, sys_read) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0569-tglx-04-rtmutex-unify-state-manipulation.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0569-tglx-04-rtmutex-unify-state-manipulation.patch @@ -0,0 +1,216 @@ +From tglx@linutronix.de Fri Dec 19 17:09:44 2008 +Date: Fri, 19 Dec 2008 21:22:57 -0000 +From: Thomas Gleixner +To: LKML +Cc: Ingo Molnar , Steven Rostedt , Peter Zijlstra , Clark Williams , Gregory Haskins , Linux-rt +Subject: [patch 4/7] rtmutex: unify state manipulation + +The manipulation of the waiter task state is copied all over the place +with slightly different details. Use one set of functions to reduce +duplicated code and make the handling consistent for all instances. + +Signed-off-by: Thomas Gleixner +--- + kernel/rtmutex.c | 95 +++++++++++++++++++++++++++---------------------------- + 1 file changed, 48 insertions(+), 47 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:05:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:05:22.000000000 -0500 +@@ -765,13 +765,6 @@ rt_spin_lock_fastunlock(struct rt_mutex + slowfn(lock); + } + +-static inline void +-update_current(unsigned long new_state, unsigned long *saved_state) +-{ +- unsigned long state = xchg(¤t->state, new_state); +- if (unlikely(state == TASK_RUNNING)) +- *saved_state = TASK_RUNNING; +-} + + #ifdef CONFIG_SMP + static int adaptive_wait(struct rt_mutex_waiter *waiter, +@@ -803,6 +796,34 @@ static int adaptive_wait(struct rt_mutex + #endif + + /* ++ * The state setting needs to preserve the original state and needs to ++ * take care of non rtmutex wakeups. ++ */ ++static inline unsigned long ++rt_set_current_blocked_state(unsigned long saved_state) ++{ ++ unsigned long state; ++ ++ state = xchg(¤t->state, TASK_UNINTERRUPTIBLE); ++ /* ++ * Take care of non rtmutex wakeups. rtmutex wakeups ++ * set the state to TASK_RUNNING_MUTEX. ++ */ ++ if (state == TASK_RUNNING) ++ saved_state = TASK_RUNNING; ++ ++ return saved_state; ++} ++ ++static inline void rt_restore_current_state(unsigned long saved_state) ++{ ++ unsigned long state = xchg(¤t->state, saved_state); ++ ++ if (state == TASK_RUNNING) ++ current->state = TASK_RUNNING; ++} ++ ++/* + * Slow path lock function spin_lock style: this variant is very + * careful not to miss any non-lock wakeups. + * +@@ -816,7 +837,7 @@ static void fastcall noinline __sched + rt_spin_lock_slowlock(struct rt_mutex *lock) + { + struct rt_mutex_waiter waiter; +- unsigned long saved_state, state, flags; ++ unsigned long saved_state, flags; + struct task_struct *orig_owner; + int missed = 0; + +@@ -836,7 +857,9 @@ rt_spin_lock_slowlock(struct rt_mutex *l + * of the lock sleep/wakeup mechanism. When we get a real + * wakeup the task->state is TASK_RUNNING and we change + * saved_state accordingly. If we did not get a real wakeup +- * then we return with the saved state. ++ * then we return with the saved state. We need to be careful ++ * about original state TASK_INTERRUPTIBLE as well, as we ++ * could miss a wakeup_interruptible() + */ + saved_state = current->state; + +@@ -880,7 +903,8 @@ rt_spin_lock_slowlock(struct rt_mutex *l + + if (adaptive_wait(&waiter, orig_owner)) { + put_task_struct(orig_owner); +- update_current(TASK_UNINTERRUPTIBLE, &saved_state); ++ ++ saved_state = rt_set_current_blocked_state(saved_state); + /* + * The xchg() in update_current() is an implicit + * barrier which we rely upon to ensure current->state +@@ -896,9 +920,7 @@ rt_spin_lock_slowlock(struct rt_mutex *l + current->lock_depth = saved_lock_depth; + } + +- state = xchg(¤t->state, saved_state); +- if (unlikely(state == TASK_RUNNING)) +- current->state = TASK_RUNNING; ++ rt_restore_current_state(saved_state); + + /* + * Extremely rare case, if we got woken up by a non-mutex wakeup, +@@ -1333,7 +1355,7 @@ rt_read_slowlock(struct rw_mutex *rwm, i + struct rt_mutex_waiter waiter; + struct rt_mutex *mutex = &rwm->mutex; + int saved_lock_depth = -1; +- unsigned long saved_state = -1, state, flags; ++ unsigned long saved_state, flags; + + spin_lock_irqsave(&mutex->wait_lock, flags); + init_rw_lists(rwm); +@@ -1357,13 +1379,13 @@ rt_read_slowlock(struct rw_mutex *rwm, i + */ + if (unlikely(current->lock_depth >= 0)) + saved_lock_depth = rt_release_bkl(mutex, flags); +- set_current_state(TASK_UNINTERRUPTIBLE); + } else { + /* Spin lock must preserve BKL */ +- saved_state = xchg(¤t->state, TASK_UNINTERRUPTIBLE); + saved_lock_depth = current->lock_depth; + } + ++ saved_state = rt_set_current_blocked_state(current->state); ++ + for (;;) { + unsigned long saved_flags; + +@@ -1398,23 +1420,12 @@ rt_read_slowlock(struct rw_mutex *rwm, i + spin_lock_irqsave(&mutex->wait_lock, flags); + + current->flags |= saved_flags; +- if (mtx) +- set_current_state(TASK_UNINTERRUPTIBLE); +- else { ++ if (!mtx) + current->lock_depth = saved_lock_depth; +- state = xchg(¤t->state, TASK_UNINTERRUPTIBLE); +- if (unlikely(state == TASK_RUNNING)) +- saved_state = TASK_RUNNING; +- } ++ saved_state = rt_set_current_blocked_state(saved_state); + } + +- if (mtx) +- set_current_state(TASK_RUNNING); +- else { +- state = xchg(¤t->state, saved_state); +- if (unlikely(state == TASK_RUNNING)) +- current->state = TASK_RUNNING; +- } ++ rt_restore_current_state(!mtx ? saved_state : TASK_RUNNING); + + if (unlikely(waiter.task)) + remove_waiter(mutex, &waiter, flags); +@@ -1490,7 +1501,7 @@ rt_write_slowlock(struct rw_mutex *rwm, + struct rt_mutex *mutex = &rwm->mutex; + struct rt_mutex_waiter waiter; + int saved_lock_depth = -1; +- unsigned long flags, saved_state = -1, state; ++ unsigned long flags, saved_state; + + debug_rt_mutex_init_waiter(&waiter); + waiter.task = NULL; +@@ -1514,13 +1525,13 @@ rt_write_slowlock(struct rw_mutex *rwm, + */ + if (unlikely(current->lock_depth >= 0)) + saved_lock_depth = rt_release_bkl(mutex, flags); +- set_current_state(TASK_UNINTERRUPTIBLE); + } else { + /* Spin locks must preserve the BKL */ + saved_lock_depth = current->lock_depth; +- saved_state = xchg(¤t->state, TASK_UNINTERRUPTIBLE); + } + ++ saved_state = rt_set_current_blocked_state(current->state); ++ + for (;;) { + unsigned long saved_flags; + +@@ -1555,24 +1566,14 @@ rt_write_slowlock(struct rw_mutex *rwm, + spin_lock_irqsave(&mutex->wait_lock, flags); + + current->flags |= saved_flags; +- if (mtx) +- set_current_state(TASK_UNINTERRUPTIBLE); +- else { ++ if (!mtx) + current->lock_depth = saved_lock_depth; +- state = xchg(¤t->state, TASK_UNINTERRUPTIBLE); +- if (unlikely(state == TASK_RUNNING)) +- saved_state = TASK_RUNNING; +- } +- } + +- if (mtx) +- set_current_state(TASK_RUNNING); +- else { +- state = xchg(¤t->state, saved_state); +- if (unlikely(state == TASK_RUNNING)) +- current->state = TASK_RUNNING; ++ saved_state = rt_set_current_blocked_state(saved_state); + } + ++ rt_restore_current_state(!mtx ? saved_state : TASK_RUNNING); ++ + if (unlikely(waiter.task)) + remove_waiter(mutex, &waiter, flags); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0240-preempt-realtime-sched-cpupri.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0240-preempt-realtime-sched-cpupri.patch @@ -0,0 +1,17 @@ +--- + kernel/sched_cpupri.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_cpupri.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_cpupri.h 2009-02-08 00:01:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_cpupri.h 2009-02-08 00:02:39.000000000 -0500 +@@ -12,7 +12,7 @@ + /* values 2-101 are RT priorities 0-99 */ + + struct cpupri_vec { +- spinlock_t lock; ++ raw_spinlock_t lock; + int count; + cpumask_t mask; + }; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0323-irda-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0323-irda-fix.patch @@ -0,0 +1,25 @@ +This was found around the 2.6.10 timeframe when testing with the -rt patch +and I believe is still is an issue. irttp_dup() does a memcpy() of the tsap_cb +structure causing the spinlock protecting various fields in the structure to be +duped. This works OK in the non-RT case but in the RT case we end up with two +mutexes pointing to the same wait_list and leading to an OOPS. Fix is to simply +initialize the spinlock after the memcpy(). + +Signed-off-by: Deepak Saxena + +--- + net/irda/irttp.c | 1 + + 1 file changed, 1 insertion(+) + +Index: linux-2.6.24.7-rt27/net/irda/irttp.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/net/irda/irttp.c 2009-02-07 23:59:50.000000000 -0500 ++++ linux-2.6.24.7-rt27/net/irda/irttp.c 2009-02-08 00:03:24.000000000 -0500 +@@ -1453,6 +1453,7 @@ struct tsap_cb *irttp_dup(struct tsap_cb + } + /* Dup */ + memcpy(new, orig, sizeof(struct tsap_cb)); ++ spin_lock_init(&new->lock); + + /* We don't need the old instance any more */ + spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0055-REFRESHED-sched-use-a-2d-bitmap-search-prio-cpu.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0055-REFRESHED-sched-use-a-2d-bitmap-search-prio-cpu.patch @@ -0,0 +1,435 @@ +From ghaskins@novell.com Wed Dec 12 00:28:53 2007 +Date: Tue, 11 Dec 2007 17:34:03 -0500 +From: Gregory Haskins +To: rostedt@goodmis.org +Cc: ghaskins@novell.com +Subject: [PATCH] sched: Use a 2-d bitmap for searching lowest-pri CPU + + [ The following text is in the "utf-8" character set. ] + [ Your display is set for the "iso-8859-1" character set. ] + [ Some characters may be displayed incorrectly. ] + +The current code use a linear algorithm which causes scaling issues +on larger SMP machines. This patch replaces that algorithm with a +2-dimensional bitmap to reduce latencies in the wake-up path. + +Signed-off-by: Gregory Haskins +CC: Christoph Lameter +--- + + kernel/Makefile | 1 + kernel/sched.c | 8 ++ + kernel/sched_cpupri.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++ + kernel/sched_cpupri.h | 36 ++++++++++ + kernel/sched_rt.c | 85 ++++++------------------ + 5 files changed, 243 insertions(+), 61 deletions(-) + +Index: ubuntu-hardy/kernel/Makefile +=================================================================== +--- ubuntu-hardy.orig/kernel/Makefile 2009-02-23 14:36:37.000000000 +0100 ++++ ubuntu-hardy/kernel/Makefile 2009-02-23 15:07:34.000000000 +0100 +@@ -58,6 +58,7 @@ + obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o + obj-$(CONFIG_MARKERS) += marker.o + obj-$(CONFIG_LATENCYTOP) += latencytop.o ++obj-$(CONFIG_SMP) += sched_cpupri.o + + ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) + # According to Alan Modra , the -fno-omit-frame-pointer is +Index: ubuntu-hardy/kernel/sched.c +=================================================================== +--- ubuntu-hardy.orig/kernel/sched.c 2009-02-23 15:05:27.000000000 +0100 ++++ ubuntu-hardy/kernel/sched.c 2009-02-23 15:07:15.000000000 +0100 +@@ -69,6 +69,8 @@ + #include + #include + ++#include "sched_cpupri.h" ++ + /* + * Scheduler clock - returns current time in nanosec units. + * This is default implementation. +@@ -298,6 +300,9 @@ + */ + cpumask_t rto_mask; + atomic_t rto_count; ++#ifdef CONFIG_SMP ++ struct cpupri cpupri; ++#endif + }; + + static struct root_domain def_root_domain; +@@ -5872,6 +5877,9 @@ + + rd->span = *map; + cpus_and(rd->online, rd->span, cpu_online_map); ++ ++ cpupri_init(&rd->cpupri); ++ + } + + static void init_defrootdomain(void) +Index: ubuntu-hardy/kernel/sched_cpupri.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ ubuntu-hardy/kernel/sched_cpupri.c 2009-02-23 15:07:15.000000000 +0100 +@@ -0,0 +1,174 @@ ++/* ++ * kernel/sched_cpupri.c ++ * ++ * CPU priority management ++ * ++ * Copyright (C) 2007 Novell ++ * ++ * Author: Gregory Haskins ++ * ++ * This code tracks the priority of each CPU so that global migration ++ * decisions are easy to calculate. Each CPU can be in a state as follows: ++ * ++ * (INVALID), IDLE, NORMAL, RT1, ... RT99 ++ * ++ * going from the lowest priority to the highest. CPUs in the INVALID state ++ * are not eligible for routing. The system maintains this state with ++ * a 2 dimensional bitmap (the first for priority class, the second for cpus ++ * in that class). Therefore a typical application without affinity ++ * restrictions can find a suitable CPU with O(1) complexity (e.g. two bit ++ * searches). For tasks with affinity restrictions, the algorithm has a ++ * worst case complexity of O(min(102, nr_domcpus)), though the scenario that ++ * yields the worst case search is fairly contrived. ++ * ++ * 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; version 2 ++ * of the License. ++ */ ++ ++#include "sched_cpupri.h" ++ ++/* Convert between a 140 based task->prio, and our 102 based cpupri */ ++static int convert_prio(int prio) ++{ ++ int cpupri; ++ ++ if (prio == CPUPRI_INVALID) ++ cpupri = CPUPRI_INVALID; ++ else if (prio == MAX_PRIO) ++ cpupri = CPUPRI_IDLE; ++ else if (prio >= MAX_RT_PRIO) ++ cpupri = CPUPRI_NORMAL; ++ else ++ cpupri = MAX_RT_PRIO - prio + 1; ++ ++ return cpupri; ++} ++ ++#define for_each_cpupri_active(array, idx) \ ++ for (idx = find_first_bit(array, CPUPRI_NR_PRIORITIES); \ ++ idx < CPUPRI_NR_PRIORITIES; \ ++ idx = find_next_bit(array, CPUPRI_NR_PRIORITIES, idx+1)) ++ ++/** ++ * cpupri_find - find the best (lowest-pri) CPU in the system ++ * @cp: The cpupri context ++ * @p: The task ++ * @lowest_mask: A mask to fill in with selected CPUs ++ * ++ * Note: This function returns the recommended CPUs as calculated during the ++ * current invokation. By the time the call returns, the CPUs may have in ++ * fact changed priorities any number of times. While not ideal, it is not ++ * an issue of correctness since the normal rebalancer logic will correct ++ * any discrepancies created by racing against the uncertainty of the current ++ * priority configuration. ++ * ++ * Returns: (int)bool - CPUs were found ++ */ ++int cpupri_find(struct cpupri *cp, struct task_struct *p, ++ cpumask_t *lowest_mask) ++{ ++ int idx = 0; ++ int task_pri = convert_prio(p->prio); ++ ++ for_each_cpupri_active(cp->pri_active, idx) { ++ struct cpupri_vec *vec = &cp->pri_to_cpu[idx]; ++ cpumask_t mask; ++ ++ if (idx >= task_pri) ++ break; ++ ++ cpus_and(mask, p->cpus_allowed, vec->mask); ++ ++ if (cpus_empty(mask)) ++ continue; ++ ++ *lowest_mask = mask; ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/** ++ * cpupri_set - update the cpu priority setting ++ * @cp: The cpupri context ++ * @cpu: The target cpu ++ * @pri: The priority (INVALID-RT99) to assign to this CPU ++ * ++ * Note: Assumes cpu_rq(cpu)->lock is locked ++ * ++ * Returns: (void) ++ */ ++void cpupri_set(struct cpupri *cp, int cpu, int newpri) ++{ ++ int *currpri = &cp->cpu_to_pri[cpu]; ++ int oldpri = *currpri; ++ unsigned long flags; ++ ++ newpri = convert_prio(newpri); ++ ++ BUG_ON(newpri >= CPUPRI_NR_PRIORITIES); ++ ++ if (newpri == oldpri) ++ return; ++ ++ /* ++ * If the cpu was currently mapped to a different value, we ++ * first need to unmap the old value ++ */ ++ if (likely(oldpri != CPUPRI_INVALID)) { ++ struct cpupri_vec *vec = &cp->pri_to_cpu[oldpri]; ++ ++ spin_lock_irqsave(&vec->lock, flags); ++ ++ vec->count--; ++ if (!vec->count) ++ clear_bit(oldpri, cp->pri_active); ++ cpu_clear(cpu, vec->mask); ++ ++ spin_unlock_irqrestore(&vec->lock, flags); ++ } ++ ++ if (likely(newpri != CPUPRI_INVALID)) { ++ struct cpupri_vec *vec = &cp->pri_to_cpu[newpri]; ++ ++ spin_lock_irqsave(&vec->lock, flags); ++ ++ cpu_set(cpu, vec->mask); ++ vec->count++; ++ if (vec->count == 1) ++ set_bit(newpri, cp->pri_active); ++ ++ spin_unlock_irqrestore(&vec->lock, flags); ++ } ++ ++ *currpri = newpri; ++} ++ ++/** ++ * cpupri_init - initialize the cpupri structure ++ * @cp: The cpupri context ++ * ++ * Returns: (void) ++ */ ++void cpupri_init(struct cpupri *cp) ++{ ++ int i; ++ ++ memset(cp, 0, sizeof(*cp)); ++ ++ for (i = 0; i < CPUPRI_NR_PRIORITIES; i++) { ++ struct cpupri_vec *vec = &cp->pri_to_cpu[i]; ++ ++ spin_lock_init(&vec->lock); ++ vec->count = 0; ++ cpus_clear(vec->mask); ++ } ++ ++ for_each_possible_cpu(i) ++ cp->cpu_to_pri[i] = CPUPRI_INVALID; ++} ++ ++ +Index: ubuntu-hardy/kernel/sched_cpupri.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ ubuntu-hardy/kernel/sched_cpupri.h 2009-02-23 15:07:15.000000000 +0100 +@@ -0,0 +1,36 @@ ++#ifndef _LINUX_CPUPRI_H ++#define _LINUX_CPUPRI_H ++ ++#include ++ ++#define CPUPRI_NR_PRIORITIES 2+MAX_RT_PRIO ++#define CPUPRI_NR_PRI_WORDS CPUPRI_NR_PRIORITIES/BITS_PER_LONG ++ ++#define CPUPRI_INVALID -1 ++#define CPUPRI_IDLE 0 ++#define CPUPRI_NORMAL 1 ++/* values 2-101 are RT priorities 0-99 */ ++ ++struct cpupri_vec { ++ spinlock_t lock; ++ int count; ++ cpumask_t mask; ++}; ++ ++struct cpupri { ++ struct cpupri_vec pri_to_cpu[CPUPRI_NR_PRIORITIES]; ++ long pri_active[CPUPRI_NR_PRI_WORDS]; ++ int cpu_to_pri[NR_CPUS]; ++}; ++ ++#ifdef CONFIG_SMP ++int cpupri_find(struct cpupri *cp, ++ struct task_struct *p, cpumask_t *lowest_mask); ++void cpupri_set(struct cpupri *cp, int cpu, int pri); ++void cpupri_init(struct cpupri *cp); ++#else ++#define cpupri_set(cp, cpu, pri) do { } while (0) ++#define cpupri_init() do { } while (0) ++#endif ++ ++#endif /* _LINUX_CPUPRI_H */ +Index: ubuntu-hardy/kernel/sched_rt.c +=================================================================== +--- ubuntu-hardy.orig/kernel/sched_rt.c 2009-02-23 15:07:12.000000000 +0100 ++++ ubuntu-hardy/kernel/sched_rt.c 2009-02-23 15:07:15.000000000 +0100 +@@ -73,8 +73,10 @@ + WARN_ON(!rt_task(p)); + rq->rt.rt_nr_running++; + #ifdef CONFIG_SMP +- if (p->prio < rq->rt.highest_prio) ++ if (p->prio < rq->rt.highest_prio) { + rq->rt.highest_prio = p->prio; ++ cpupri_set(&rq->rd->cpupri, rq->cpu, p->prio); ++ } + if (p->nr_cpus_allowed > 1) + rq->rt.rt_nr_migratory++; + +@@ -84,6 +86,8 @@ + + static inline void dec_rt_tasks(struct task_struct *p, struct rq *rq) + { ++ int highest_prio = rq->rt.highest_prio; ++ + WARN_ON(!rt_task(p)); + WARN_ON(!rq->rt.rt_nr_running); + rq->rt.rt_nr_running--; +@@ -103,6 +107,9 @@ + if (p->nr_cpus_allowed > 1) + rq->rt.rt_nr_migratory--; + ++ if (rq->rt.highest_prio != highest_prio) ++ cpupri_set(&rq->rd->cpupri, rq->cpu, rq->rt.highest_prio); ++ + update_rt_migration(rq); + #endif /* CONFIG_SMP */ + } +@@ -293,69 +300,17 @@ + + static int find_lowest_cpus(struct task_struct *task, cpumask_t *lowest_mask) + { +- int lowest_prio = -1; +- int lowest_cpu = -1; +- int count = 0; +- int cpu; ++ int count; + +- cpus_and(*lowest_mask, task_rq(task)->rd->online, task->cpus_allowed); ++ count = cpupri_find(&task_rq(task)->rd->cpupri, task, lowest_mask); + + /* +- * Scan each rq for the lowest prio. ++ * cpupri cannot efficiently tell us how many bits are set, so it only ++ * returns a boolean. However, the caller of this function will ++ * special case the value "1", so we want to return a positive integer ++ * other than one if there are bits to look at + */ +- for_each_cpu_mask(cpu, *lowest_mask) { +- struct rq *rq = cpu_rq(cpu); +- +- /* We look for lowest RT prio or non-rt CPU */ +- if (rq->rt.highest_prio >= MAX_RT_PRIO) { +- /* +- * if we already found a low RT queue +- * and now we found this non-rt queue +- * clear the mask and set our bit. +- * Otherwise just return the queue as is +- * and the count==1 will cause the algorithm +- * to use the first bit found. +- */ +- if (lowest_cpu != -1) { +- cpus_clear(*lowest_mask); +- cpu_set(rq->cpu, *lowest_mask); +- } +- return 1; +- } +- +- /* no locking for now */ +- if ((rq->rt.highest_prio > task->prio) +- && (rq->rt.highest_prio >= lowest_prio)) { +- if (rq->rt.highest_prio > lowest_prio) { +- /* new low - clear old data */ +- lowest_prio = rq->rt.highest_prio; +- lowest_cpu = cpu; +- count = 0; +- } +- count++; +- } else +- cpu_clear(cpu, *lowest_mask); +- } +- +- /* +- * Clear out all the set bits that represent +- * runqueues that were of higher prio than +- * the lowest_prio. +- */ +- if (lowest_cpu > 0) { +- /* +- * Perhaps we could add another cpumask op to +- * zero out bits. Like cpu_zero_bits(cpumask, nrbits); +- * Then that could be optimized to use memset and such. +- */ +- for_each_cpu_mask(cpu, *lowest_mask) { +- if (cpu >= lowest_cpu) +- break; +- cpu_clear(cpu, *lowest_mask); +- } +- } +- +- return count; ++ return count ? 2 : 0; + } + + static inline int pick_optimal_cpu(int this_cpu, cpumask_t *mask) +@@ -379,8 +334,12 @@ + cpumask_t *lowest_mask = &__get_cpu_var(local_cpu_mask); + int this_cpu = smp_processor_id(); + int cpu = task_cpu(task); +- int count = find_lowest_cpus(task, lowest_mask); ++ int count; ++ ++ if (task->nr_cpus_allowed == 1) ++ return -1; /* No other targets possible */ + ++ count = find_lowest_cpus(task, lowest_mask); + if (!count) + return -1; /* No targets found */ + +@@ -734,6 +693,8 @@ + { + if (rq->rt.overloaded) + rt_set_overload(rq); ++ ++ cpupri_set(&rq->rd->cpupri, rq->cpu, rq->rt.highest_prio); + } + + /* Assumes rq->lock is held */ +@@ -741,6 +702,8 @@ + { + if (rq->rt.overloaded) + rt_clear_overload(rq); ++ ++ cpupri_set(&rq->rd->cpupri, rq->cpu, CPUPRI_INVALID); + } + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0572-tglx-07-rtmutex-prevent-missed-wakeups.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0572-tglx-07-rtmutex-prevent-missed-wakeups.patch @@ -0,0 +1,203 @@ +From tglx@linutronix.de Fri Dec 19 17:09:56 2008 +Date: Fri, 19 Dec 2008 21:23:10 -0000 +From: Thomas Gleixner +To: LKML +Cc: Ingo Molnar , Steven Rostedt , Peter Zijlstra , Clark Williams , Gregory Haskins , Linux-rt +Subject: [patch 7/7] rtmutex: prevent missed wakeups + +The sleeping locks implementation based on rtmutexes can miss wakeups +for two reasons: + +1) The unconditional usage TASK_UNINTERRUPTIBLE for the blocking state + + Results in missed wakeups from wake_up_interruptible*() + + state = TASK_INTERRUPTIBLE; + blocks_on_lock() + state = TASK_UNINTERRUPTIBLE; + schedule(); + .... + acquires_lock(); + restore_state(); + + Until the waiter has restored its state wake_up_interruptible*() will + fail. + +2) The rtmutex wakeup intermediate state TASK_RUNNING_MUTEX + + Results in missed wakeups from wake_up*() + + waiter is woken by mutex wakeup + waiter->state = TASK_RUNNING_MUTEX; + .... + acquires_lock(); + restore_state(); + + Until the waiter has restored its state wake_up*() will fail. + +Solution: + +Instead of setting the state to TASK_RUNNING_MUTEX in the mutex wakeup +case we logically OR TASK_RUNNING_MUTEX to the current waiter +state. This keeps the original bits (TASK_INTERRUPTIBLE / +TASK_UNINTERRUPTIBLE) intact and lets wakeups succeed. When a task +blocks on a lock in state TASK_INTERRUPTIBLE and is woken up by a real +wakeup, then we store the state = TASK_RUNNING for the restore and can +safely use TASK_UNINTERRUPTIBLE from that point to avoid further +wakeups which just let us loop in the lock code. + +This also removes the extra TASK_RUNNING_MUTEX flags from the +wakeup_process*() functions as they are not longer necessary. + +Signed-off-by: Thomas Gleixner +--- + kernel/rtmutex.c | 22 +++++++++++++++++++--- + kernel/sched.c | 40 +++++++++++++++++++++++----------------- + 2 files changed, 42 insertions(+), 20 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:05:23.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:05:23.000000000 -0500 +@@ -798,16 +798,32 @@ static int adaptive_wait(struct rt_mutex + /* + * The state setting needs to preserve the original state and needs to + * take care of non rtmutex wakeups. ++ * ++ * Called with rtmutex->wait_lock held to serialize against rtmutex ++ * wakeups(). + */ + static inline unsigned long + rt_set_current_blocked_state(unsigned long saved_state) + { +- unsigned long state; ++ unsigned long state, block_state; ++ ++ /* ++ * If state is TASK_INTERRUPTIBLE, then we set the state for ++ * blocking to TASK_INTERRUPTIBLE as well, otherwise we would ++ * miss real wakeups via wake_up_interruptible(). If such a ++ * wakeup happens we see the running state and preserve it in ++ * saved_state. Now we can ignore further wakeups as we will ++ * return in state running from our "spin" sleep. ++ */ ++ if (saved_state == TASK_INTERRUPTIBLE) ++ block_state = TASK_INTERRUPTIBLE; ++ else ++ block_state = TASK_UNINTERRUPTIBLE; + +- state = xchg(¤t->state, TASK_UNINTERRUPTIBLE); ++ state = xchg(¤t->state, block_state); + /* + * Take care of non rtmutex wakeups. rtmutex wakeups +- * set the state to TASK_RUNNING_MUTEX. ++ * or TASK_RUNNING_MUTEX to (UN)INTERRUPTIBLE. + */ + if (state == TASK_RUNNING) + saved_state = TASK_RUNNING; +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:05:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:05:23.000000000 -0500 +@@ -1765,10 +1765,20 @@ out_activate: + + out_running: + trace_kernel_sched_wakeup(rq, p); ++ ++ /* ++ * For a mutex wakeup we or TASK_RUNNING_MUTEX to the task ++ * state to preserve the original state, so a real wakeup ++ * still can see the (UN)INTERRUPTIBLE bits in the state check ++ * above. We dont have to worry about the | TASK_RUNNING_MUTEX ++ * here. The waiter is serialized by the mutex lock and nobody ++ * else can fiddle with p->state as we hold rq lock. ++ */ + if (mutex) +- p->state = TASK_RUNNING_MUTEX; ++ p->state |= TASK_RUNNING_MUTEX; + else + p->state = TASK_RUNNING; ++ + #ifdef CONFIG_SMP + if (p->sched_class->task_wake_up) + p->sched_class->task_wake_up(rq, p); +@@ -1782,38 +1792,34 @@ out: + int fastcall wake_up_process(struct task_struct *p) + { + return try_to_wake_up(p, TASK_STOPPED | TASK_TRACED | +- TASK_RUNNING_MUTEX | TASK_INTERRUPTIBLE | +- TASK_UNINTERRUPTIBLE, 0, 0); ++ TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0, 0); + } + EXPORT_SYMBOL(wake_up_process); + + int fastcall wake_up_process_sync(struct task_struct * p) + { + return try_to_wake_up(p, TASK_STOPPED | TASK_TRACED | +- TASK_RUNNING_MUTEX | TASK_INTERRUPTIBLE | +- TASK_UNINTERRUPTIBLE, 1, 0); ++ TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 1, 0); + } + EXPORT_SYMBOL(wake_up_process_sync); + + int fastcall wake_up_process_mutex(struct task_struct * p) + { + return try_to_wake_up(p, TASK_STOPPED | TASK_TRACED | +- TASK_RUNNING_MUTEX | TASK_INTERRUPTIBLE | +- TASK_UNINTERRUPTIBLE, 0, 1); ++ TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0, 1); + } + EXPORT_SYMBOL(wake_up_process_mutex); + + int fastcall wake_up_process_mutex_sync(struct task_struct * p) + { + return try_to_wake_up(p, TASK_STOPPED | TASK_TRACED | +- TASK_RUNNING_MUTEX | TASK_INTERRUPTIBLE | +- TASK_UNINTERRUPTIBLE, 1, 1); ++ TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 1, 1); + } + EXPORT_SYMBOL(wake_up_process_mutex_sync); + + int fastcall wake_up_state(struct task_struct *p, unsigned int state) + { +- return try_to_wake_up(p, state | TASK_RUNNING_MUTEX, 0, 0); ++ return try_to_wake_up(p, state, 0, 0); + } + + /* +@@ -3961,10 +3967,10 @@ asmlinkage void __sched __schedule(void) + clear_tsk_need_resched(prev); + clear_tsk_need_resched_delayed(prev); + +- if ((prev->state & ~TASK_RUNNING_MUTEX) && +- !(preempt_count() & PREEMPT_ACTIVE)) { ++ if (!(prev->state & TASK_RUNNING_MUTEX) && prev->state && ++ !(preempt_count() & PREEMPT_ACTIVE)) { + if (unlikely((prev->state & TASK_INTERRUPTIBLE) && +- unlikely(signal_pending(prev)))) { ++ unlikely(signal_pending(prev)))) { + prev->state = TASK_RUNNING; + } else { + touch_softlockup_watchdog(); +@@ -4184,8 +4190,7 @@ asmlinkage void __sched preempt_schedule + int default_wake_function(wait_queue_t *curr, unsigned mode, int sync, + void *key) + { +- return try_to_wake_up(curr->private, mode | TASK_RUNNING_MUTEX, +- sync, 0); ++ return try_to_wake_up(curr->private, mode, sync, 0); + } + EXPORT_SYMBOL(default_wake_function); + +@@ -5421,8 +5426,9 @@ static void show_task(struct task_struct + unsigned state; + + state = p->state ? __ffs(p->state) + 1 : 0; +- printk("%-13.13s %c [%p]", p->comm, +- state < sizeof(stat_nam) - 1 ? stat_nam[state] : '?', p); ++ printk("%-13.13s %c (%03lx) [%p]", p->comm, ++ state < sizeof(stat_nam) - 1 ? stat_nam[state] : '?', ++ (unsigned long) p->state, p); + #if BITS_PER_LONG == 32 + if (0 && (state == TASK_RUNNING)) + printk(KERN_CONT " running "); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0342-schedule_on_each_cpu-enhance-rt.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0342-schedule_on_each_cpu-enhance-rt.patch @@ -0,0 +1,26 @@ +--- + kernel/workqueue.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/workqueue.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/workqueue.c 2009-02-08 00:03:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/workqueue.c 2009-02-08 00:03:33.000000000 -0500 +@@ -643,7 +643,7 @@ int schedule_on_each_cpu(void (*func)(vo + } + } + +- preempt_disable(); /* CPU hotplug */ ++ lock_cpu_hotplug(); + for_each_online_cpu(cpu) { + struct schedule_on_each_cpu_work *work; + +@@ -656,7 +656,7 @@ int schedule_on_each_cpu(void (*func)(vo + set_bit(WORK_STRUCT_PENDING, work_data_bits(&work->work)); + __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), &work->work); + } +- preempt_enable(); ++ unlock_cpu_hotplug(); + + out: + for_each_possible_cpu(cpu) { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0395-local_irq_save_nort-in-swap.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0395-local_irq_save_nort-in-swap.patch @@ -0,0 +1,20 @@ +--- + mm/swap.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/mm/swap.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/swap.c 2009-02-08 00:03:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/swap.c 2009-02-08 00:03:58.000000000 -0500 +@@ -302,9 +302,9 @@ static void drain_cpu_pagevecs(int cpu) + unsigned long flags; + + /* No harm done if a racing interrupt already did this */ +- local_irq_save(flags); ++ local_irq_save_nort(flags); + pagevec_move_tail(pvec); +- local_irq_restore(flags); ++ local_irq_restore_nort(flags); + } + swap_per_cpu_unlock(lru_rotate_pvecs, cpu); + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0553-f7676254f179eac6b5244a80195ec8ae0e9d4606.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0553-f7676254f179eac6b5244a80195ec8ae0e9d4606.patch @@ -0,0 +1,52 @@ +commit f7676254f179eac6b5244a80195ec8ae0e9d4606 +Author: Thomas Gleixner +Date: Sat Sep 6 03:03:32 2008 +0200 + + x86: HPET fix moronic 32/64bit thinko + + We use the HPET only in 32bit mode because: + 1) some HPETs are 32bit only + 2) on i386 there is no way to read/write the HPET atomic 64bit wide + + The HPET code unification done by the "moron of the year" did + not take into account that unsigned long is different on 32 and + 64 bit. + + This thinko results in a possible endless loop in the clockevents + code, when the return comparison fails due to the 64bit/332bit + unawareness. + + unsigned long cnt = (u32) hpet_read() + delta can wrap over 32bit. + but the final compare will fail and return -ETIME causing endless + loops. + + Signed-off-by: Thomas Gleixner + +--- + arch/x86/kernel/hpet.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/hpet.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/hpet.c 2009-02-08 00:05:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/hpet.c 2009-02-08 00:05:13.000000000 -0500 +@@ -281,15 +281,15 @@ static void hpet_legacy_set_mode(enum cl + } + + static int hpet_legacy_next_event(unsigned long delta, +- struct clock_event_device *evt) ++ struct clock_event_device *evt) + { +- unsigned long cnt; ++ u32 cnt; + + cnt = hpet_readl(HPET_COUNTER); +- cnt += delta; ++ cnt += (u32) delta; + hpet_writel(cnt, HPET_T0_CMP); + +- return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0) ? -ETIME : 0; ++ return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; + } + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0245-preempt-realtime-sound.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0245-preempt-realtime-sound.patch @@ -0,0 +1,24 @@ +--- + sound/core/pcm_lib.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: linux-2.6.24.7-rt27/sound/core/pcm_lib.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/sound/core/pcm_lib.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/sound/core/pcm_lib.c 2009-02-08 00:02:41.000000000 -0500 +@@ -30,6 +30,7 @@ + #include + #include + ++#include + /* + * fill ring buffer with silence + * runtime->silence_start: starting pointer to silence area +@@ -130,6 +131,7 @@ static void xrun(struct snd_pcm_substrea + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + #ifdef CONFIG_SND_PCM_XRUN_DEBUG + if (substream->pstr->xrun_debug) { ++ user_trace_stop(); + snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n", + substream->pcm->card->number, + substream->pcm->device, --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0216-preempt-realtime-ia64.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0216-preempt-realtime-ia64.patch @@ -0,0 +1,1484 @@ + +Hi, + +This is a first version of my port of Ingo's -rt kernel to the IA64 arch. + +So far the kernel boots with PREEMPT_RT enabled (on a 4-cpu tiger), and +that's about it. I've not done extensive tests (only scripts/rt-tester), +nor any measurements of any kind. + +There's very probably many bugs I'm not aware of. + +But there is already one thing I know should be fixed : I've changed the +declaration of (struct zone).lock (in include/linux/mmzone.h) from +spinlock_t to raw_spinlock_t. + +I did this because on IA64, cpu_idle(), which is not allowed to call +schedule(), calls check_pgt_cache(). I guess this could be fixed by moving +this call to another kernel thread... ideas are welcome. + + + Simon. + + + + +Signed-off-by: Simon.Derr@bull.net + + arch/ia64/Kconfig | 64 +++++++++++++++++++++++++ + arch/ia64/kernel/asm-offsets.c | 2 + arch/ia64/kernel/entry.S | 25 +++++----- + arch/ia64/kernel/fsys.S | 21 ++++++++ + arch/ia64/kernel/iosapic.c | 33 ++++++++++++- + arch/ia64/kernel/mca.c | 2 + arch/ia64/kernel/perfmon.c | 6 +- + arch/ia64/kernel/process.c | 14 +++-- + arch/ia64/kernel/sal.c | 2 + arch/ia64/kernel/salinfo.c | 6 +- + arch/ia64/kernel/semaphore.c | 8 +-- + arch/ia64/kernel/signal.c | 8 +++ + arch/ia64/kernel/smp.c | 16 ++++++ + arch/ia64/kernel/smpboot.c | 3 + + arch/ia64/kernel/time.c | 74 +++++++++++++++++++---------- + arch/ia64/kernel/traps.c | 10 ++-- + arch/ia64/kernel/unwind.c | 4 - + arch/ia64/kernel/unwind_i.h | 2 + arch/ia64/mm/init.c | 2 + arch/ia64/mm/tlb.c | 2 + include/asm-ia64/irqflags.h | 95 ++++++++++++++++++++++++++++++++++++++ + include/asm-ia64/mmu_context.h | 2 + include/asm-ia64/percpu.h | 21 +++++++- + include/asm-ia64/processor.h | 6 +- + include/asm-ia64/rtc.h | 7 ++ + include/asm-ia64/rwsem.h | 32 ++++++------ + include/asm-ia64/sal.h | 2 + include/asm-ia64/semaphore.h | 51 ++++++++++++-------- + include/asm-ia64/spinlock.h | 26 ++++------ + include/asm-ia64/spinlock_types.h | 4 - + include/asm-ia64/system.h | 67 -------------------------- + include/asm-ia64/thread_info.h | 1 + include/asm-ia64/tlb.h | 10 ++-- + 33 files changed, 436 insertions(+), 192 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/ia64/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/Kconfig 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/Kconfig 2009-02-08 00:02:25.000000000 -0500 +@@ -44,6 +44,7 @@ config SWIOTLB + + config RWSEM_XCHGADD_ALGORITHM + bool ++ depends on !PREEMPT_RT + default y + + config ARCH_HAS_ILOG2_U32 +@@ -280,6 +281,69 @@ config SMP + + If you don't know what to do here, say N. + ++ ++config GENERIC_TIME ++ bool ++ default y ++ ++config HIGH_RES_TIMERS ++ bool "High-Resolution Timers" ++ help ++ ++ POSIX timers are available by default. This option enables ++ high-resolution POSIX timers. With this option the resolution ++ is at least 1 microsecond. High resolution is not free. If ++ enabled this option will add a small overhead each time a ++ timer expires that is not on a 1/HZ tick boundary. If no such ++ timers are used the overhead is nil. ++ ++ This option enables two additional POSIX CLOCKS, ++ CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR. Note that this ++ option does not change the resolution of CLOCK_REALTIME or ++ CLOCK_MONOTONIC which remain at 1/HZ resolution. ++ ++config HIGH_RES_RESOLUTION ++ int "High-Resolution-Timer resolution (nanoseconds)" ++ depends on HIGH_RES_TIMERS ++ default 1000 ++ help ++ ++ This sets the resolution of timers accessed with ++ CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR. Too ++ fine a resolution (small a number) will usually not ++ be observable due to normal system latencies. For an ++ 800 MHZ processor about 10,000 is the recommended maximum ++ (smallest number). If you don't need that sort of resolution, ++ higher numbers may generate less overhead. ++ ++choice ++ prompt "Clock source" ++ depends on HIGH_RES_TIMERS ++ default HIGH_RES_TIMER_ITC ++ help ++ This option allows you to choose the hardware source in charge ++ of generating high precision interruptions on your system. ++ On IA-64 these are: ++ ++ ++ ITC Interval Time Counter 1/CPU clock ++ HPET High Precision Event Timer ~ (XXX:have to check the spec) ++ ++ The ITC timer is available on all the ia64 computers because ++ it is integrated directly into the processor. However it may not ++ give correct results on MP machines with processors running ++ at different clock rates. In this case you may want to use ++ the HPET if available on your machine. ++ ++ ++config HIGH_RES_TIMER_ITC ++ bool "Interval Time Counter/ITC" ++ ++config HIGH_RES_TIMER_HPET ++ bool "High Precision Event Timer/HPET" ++ ++endchoice ++ + config NR_CPUS + int "Maximum number of CPUs (2-1024)" + range 2 1024 +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/asm-offsets.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/asm-offsets.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/asm-offsets.c 2009-02-08 00:02:25.000000000 -0500 +@@ -257,6 +257,7 @@ void foo(void) + offsetof (struct pal_min_state_area_s, pmsa_xip)); + BLANK(); + ++#ifdef CONFIG_TIME_INTERPOLATION + /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ + DEFINE(IA64_GTOD_LOCK_OFFSET, + offsetof (struct fsyscall_gtod_data_t, lock)); +@@ -278,4 +279,5 @@ void foo(void) + offsetof (struct itc_jitter_data_t, itc_jitter)); + DEFINE(IA64_ITC_LASTCYCLE_OFFSET, + offsetof (struct itc_jitter_data_t, itc_lastcycle)); ++#endif + } +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/entry.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/entry.S 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/entry.S 2009-02-08 00:02:25.000000000 -0500 +@@ -1098,23 +1098,24 @@ skip_rbs_switch: + st8 [r2]=r8 + st8 [r3]=r10 + .work_pending: +- tbit.z p6,p0=r31,TIF_NEED_RESCHED // current_thread_info()->need_resched==0? ++ tbit.nz p6,p0=r31,TIF_NEED_RESCHED // current_thread_info()->need_resched==0? ++(p6) br.cond.sptk.few .needresched ++ tbit.z p6,p0=r31,TIF_NEED_RESCHED_DELAYED // current_thread_info()->need_resched_delayed==0? + (p6) br.cond.sptk.few .notify +-#ifdef CONFIG_PREEMPT +-(pKStk) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1 ++ ++.needresched: ++ ++(pKStk) br.cond.sptk.many .fromkernel + ;; +-(pKStk) st4 [r20]=r21 + ssm psr.i // enable interrupts +-#endif + br.call.spnt.many rp=schedule +-.ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1 +- rsm psr.i // disable interrupts +- ;; +-#ifdef CONFIG_PREEMPT +-(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 ++.ret9a: rsm psr.i // disable interrupts + ;; +-(pKStk) st4 [r20]=r0 // preempt_count() <- 0 +-#endif ++ br.cond.sptk.many .endpreemptdep ++.fromkernel: ++ br.call.spnt.many rp=preempt_schedule_irq ++.ret9b: rsm psr.i // disable interrupts ++.endpreemptdep: + (pLvSys)br.cond.sptk.few .work_pending_syscall_end + br.cond.sptk.many .work_processed_kernel // re-check + +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/fsys.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/fsys.S 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/fsys.S 2009-02-08 00:02:25.000000000 -0500 +@@ -26,6 +26,7 @@ + + #include "entry.h" + ++#ifdef CONFIG_TIME_INTERPOLATION + /* + * See Documentation/ia64/fsys.txt for details on fsyscalls. + * +@@ -349,6 +350,26 @@ ENTRY(fsys_clock_gettime) + br.many .gettime + END(fsys_clock_gettime) + ++ ++#else // !CONFIG_TIME_INTERPOLATION ++ ++# define fsys_gettimeofday 0 ++# define fsys_clock_gettime 0 ++ ++.fail_einval: ++ mov r8 = EINVAL ++ mov r10 = -1 ++ FSYS_RETURN ++ ++.fail_efault: ++ mov r8 = EFAULT ++ mov r10 = -1 ++ FSYS_RETURN ++ ++#endif ++ ++ ++ + /* + * long fsys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize). + */ +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/iosapic.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/iosapic.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/iosapic.c 2009-02-08 00:02:25.000000000 -0500 +@@ -111,7 +111,7 @@ + (PAGE_SIZE / sizeof(struct iosapic_rte_info)) + #define RTE_PREALLOCATED (1) + +-static DEFINE_SPINLOCK(iosapic_lock); ++static DEFINE_RAW_SPINLOCK(iosapic_lock); + + /* + * These tables map IA-64 vectors to the IOSAPIC pin that generates this +@@ -390,6 +390,34 @@ iosapic_startup_level_irq (unsigned int + return 0; + } + ++/* ++ * In the preemptible case mask the IRQ first then handle it and ack it. ++ */ ++#ifdef CONFIG_PREEMPT_HARDIRQS ++ ++static void ++iosapic_ack_level_irq (unsigned int irq) ++{ ++ ia64_vector vec = irq_to_vector(irq); ++ struct iosapic_rte_info *rte; ++ ++ move_irq(irq); ++ mask_irq(irq); ++ list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) ++ iosapic_eoi(rte->addr, vec); ++} ++ ++static void ++iosapic_end_level_irq (unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & IRQ_INPROGRESS)) ++ unmask_irq(irq); ++} ++ ++#else /* !CONFIG_PREEMPT_HARDIRQS */ ++ ++#define iosapic_ack_level_irq nop ++ + static void + iosapic_end_level_irq (unsigned int irq) + { +@@ -411,10 +439,11 @@ iosapic_end_level_irq (unsigned int irq) + } + } + ++#endif ++ + #define iosapic_shutdown_level_irq mask_irq + #define iosapic_enable_level_irq unmask_irq + #define iosapic_disable_level_irq mask_irq +-#define iosapic_ack_level_irq nop + + static struct irq_chip irq_type_iosapic_level = { + .name = "IO-SAPIC-level", +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/mca.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/mca.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/mca.c 2009-02-08 00:02:25.000000000 -0500 +@@ -323,7 +323,7 @@ ia64_mca_spin(const char *func) + + typedef struct ia64_state_log_s + { +- spinlock_t isl_lock; ++ raw_spinlock_t isl_lock; + int isl_index; + unsigned long isl_count; + ia64_err_rec_t *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */ +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/perfmon.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/perfmon.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/perfmon.c 2009-02-08 00:02:25.000000000 -0500 +@@ -280,7 +280,7 @@ typedef struct { + */ + + typedef struct pfm_context { +- spinlock_t ctx_lock; /* context protection */ ++ raw_spinlock_t ctx_lock; /* context protection */ + + pfm_context_flags_t ctx_flags; /* bitmask of flags (block reason incl.) */ + unsigned int ctx_state; /* state: active/inactive (no bitfield) */ +@@ -369,7 +369,7 @@ typedef struct pfm_context { + * mostly used to synchronize between system wide and per-process + */ + typedef struct { +- spinlock_t pfs_lock; /* lock the structure */ ++ raw_spinlock_t pfs_lock; /* lock the structure */ + + unsigned int pfs_task_sessions; /* number of per task sessions */ + unsigned int pfs_sys_sessions; /* number of per system wide sessions */ +@@ -510,7 +510,7 @@ static pfm_intr_handler_desc_t *pfm_alt + static struct proc_dir_entry *perfmon_dir; + static pfm_uuid_t pfm_null_uuid = {0,}; + +-static spinlock_t pfm_buffer_fmt_lock; ++static raw_spinlock_t pfm_buffer_fmt_lock; + static LIST_HEAD(pfm_buffer_fmt_list); + + static pmu_config_t *pmu_conf; +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/process.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/process.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/process.c 2009-02-08 00:02:25.000000000 -0500 +@@ -95,6 +95,9 @@ show_stack (struct task_struct *task, un + void + dump_stack (void) + { ++ if (irqs_disabled()) { ++ printk("Uh oh.. entering dump_stack() with irqs disabled.\n"); ++ } + show_stack(NULL, NULL); + } + +@@ -200,7 +203,7 @@ void + default_idle (void) + { + local_irq_enable(); +- while (!need_resched()) { ++ while (!need_resched() && !need_resched_delayed()) { + if (can_do_pal_halt) { + local_irq_disable(); + if (!need_resched()) { +@@ -288,7 +291,7 @@ cpu_idle (void) + current_thread_info()->status |= TS_POLLING; + } + +- if (!need_resched()) { ++ if (!need_resched() && !need_resched_delayed()) { + void (*idle)(void); + #ifdef CONFIG_SMP + min_xtp(); +@@ -310,10 +313,11 @@ cpu_idle (void) + normal_xtp(); + #endif + } +- preempt_enable_no_resched(); +- schedule(); ++ __preempt_enable_no_resched(); ++ __schedule(); ++ + preempt_disable(); +- check_pgt_cache(); ++ + if (cpu_is_offline(cpu)) + play_dead(); + } +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/sal.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/sal.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/sal.c 2009-02-08 00:02:25.000000000 -0500 +@@ -18,7 +18,7 @@ + #include + #include + +- __cacheline_aligned DEFINE_SPINLOCK(sal_lock); ++ __cacheline_aligned DEFINE_RAW_SPINLOCK(sal_lock); + unsigned long sal_platform_features; + + unsigned short sal_revision; +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/salinfo.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/salinfo.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/salinfo.c 2009-02-08 00:02:25.000000000 -0500 +@@ -140,7 +140,7 @@ enum salinfo_state { + + struct salinfo_data { + cpumask_t cpu_event; /* which cpus have outstanding events */ +- struct semaphore mutex; ++ struct compat_semaphore mutex; + u8 *log_buffer; + u64 log_size; + u8 *oemdata; /* decoded oem data */ +@@ -156,8 +156,8 @@ struct salinfo_data { + + static struct salinfo_data salinfo_data[ARRAY_SIZE(salinfo_log_name)]; + +-static DEFINE_SPINLOCK(data_lock); +-static DEFINE_SPINLOCK(data_saved_lock); ++static DEFINE_RAW_SPINLOCK(data_lock); ++static DEFINE_RAW_SPINLOCK(data_saved_lock); + + /** salinfo_platform_oemdata - optional callback to decode oemdata from an error + * record. +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/semaphore.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/semaphore.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/semaphore.c 2009-02-08 00:02:25.000000000 -0500 +@@ -40,12 +40,12 @@ + */ + + void +-__up (struct semaphore *sem) ++__up (struct compat_semaphore *sem) + { + wake_up(&sem->wait); + } + +-void __sched __down (struct semaphore *sem) ++void __sched __down (struct compat_semaphore *sem) + { + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); +@@ -82,7 +82,7 @@ void __sched __down (struct semaphore *s + tsk->state = TASK_RUNNING; + } + +-int __sched __down_interruptible (struct semaphore * sem) ++int __sched __down_interruptible (struct compat_semaphore * sem) + { + int retval = 0; + struct task_struct *tsk = current; +@@ -142,7 +142,7 @@ int __sched __down_interruptible (struct + * count. + */ + int +-__down_trylock (struct semaphore *sem) ++__down_trylock (struct compat_semaphore *sem) + { + unsigned long flags; + int sleepers; +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/signal.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/signal.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/signal.c 2009-02-08 00:02:25.000000000 -0500 +@@ -438,6 +438,14 @@ ia64_do_signal (struct sigscratch *scr, + long errno = scr->pt.r8; + # define ERR_CODE(c) (IS_IA32_PROCESS(&scr->pt) ? -(c) : (c)) + ++#ifdef CONFIG_PREEMPT_RT ++ /* ++ * Fully-preemptible kernel does not need interrupts disabled: ++ */ ++ local_irq_enable(); ++ preempt_check_resched(); ++#endif ++ + /* + * In the ia64_leave_kernel code path, we want the common case to go fast, which + * is why we may in certain cases get here from kernel mode. Just return without +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/smp.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/smp.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/smp.c 2009-02-08 00:02:25.000000000 -0500 +@@ -261,6 +261,22 @@ smp_send_reschedule (int cpu) + } + + /* ++ * this function sends a 'reschedule' IPI to all other CPUs. ++ * This is used when RT tasks are starving and other CPUs ++ * might be able to run them: ++ */ ++void smp_send_reschedule_allbutself(void) ++{ ++ unsigned int cpu; ++ ++ for_each_online_cpu(cpu) { ++ if (cpu != smp_processor_id()) ++ platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, ++ IA64_IPI_DM_INT, 0); ++ } ++} ++ ++/* + * Called with preemption disabled. + */ + static void +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/smpboot.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/smpboot.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/smpboot.c 2009-02-08 00:02:25.000000000 -0500 +@@ -372,6 +372,8 @@ smp_setup_percpu_timer (void) + { + } + ++extern void register_itc_clockevent(void); ++ + static void __cpuinit + smp_callin (void) + { +@@ -450,6 +452,7 @@ smp_callin (void) + #ifdef CONFIG_IA32_SUPPORT + ia32_gdt_init(); + #endif ++ register_itc_clockevent(); + + /* + * Allow the master to continue. +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/time.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/time.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/time.c 2009-02-08 00:02:25.000000000 -0500 +@@ -70,6 +70,7 @@ timer_interrupt (int irq, void *dev_id) + + platform_timer_interrupt(irq, dev_id); + ++#if 0 + new_itm = local_cpu_data->itm_next; + + if (!time_after(ia64_get_itc(), new_itm)) +@@ -77,29 +78,48 @@ timer_interrupt (int irq, void *dev_id) + ia64_get_itc(), new_itm); + + profile_tick(CPU_PROFILING); ++#endif ++ ++ if (time_after(ia64_get_itc(), local_cpu_data->itm_tick_next)) { + +- while (1) { +- update_process_times(user_mode(get_irq_regs())); ++ unsigned long new_tick_itm; ++ new_tick_itm = local_cpu_data->itm_tick_next; + +- new_itm += local_cpu_data->itm_delta; ++ profile_tick(CPU_PROFILING, get_irq_regs()); + +- if (smp_processor_id() == time_keeper_id) { +- /* +- * Here we are in the timer irq handler. We have irqs locally +- * disabled, but we don't know if the timer_bh is running on +- * another CPU. We need to avoid to SMP race by acquiring the +- * xtime_lock. +- */ +- write_seqlock(&xtime_lock); +- do_timer(1); +- local_cpu_data->itm_next = new_itm; +- write_sequnlock(&xtime_lock); +- } else +- local_cpu_data->itm_next = new_itm; ++ while (1) { ++ update_process_times(user_mode(get_irq_regs())); ++ ++ new_tick_itm += local_cpu_data->itm_tick_delta; ++ ++ if (smp_processor_id() == time_keeper_id) { ++ /* ++ * Here we are in the timer irq handler. We have irqs locally ++ * disabled, but we don't know if the timer_bh is running on ++ * another CPU. We need to avoid to SMP race by acquiring the ++ * xtime_lock. ++ */ ++ write_seqlock(&xtime_lock); ++ do_timer(get_irq_regs()); ++ local_cpu_data->itm_tick_next = new_tick_itm; ++ write_sequnlock(&xtime_lock); ++ } else ++ local_cpu_data->itm_tick_next = new_tick_itm; ++ ++ if (time_after(new_tick_itm, ia64_get_itc())) ++ break; ++ } ++ } + +- if (time_after(new_itm, ia64_get_itc())) +- break; ++ if (time_after(ia64_get_itc(), local_cpu_data->itm_timer_next)) { ++ if (itc_clockevent.event_handler) ++ itc_clockevent.event_handler(get_irq_regs()); + ++ // FIXME, really, please ++ new_itm = local_cpu_data->itm_tick_next; ++ ++ if (time_after(new_itm, local_cpu_data->itm_timer_next)) ++ new_itm = local_cpu_data->itm_timer_next; + /* + * Allow IPIs to interrupt the timer loop. + */ +@@ -117,8 +137,8 @@ timer_interrupt (int irq, void *dev_id) + * too fast (with the potentially devastating effect + * of losing monotony of time). + */ +- while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2)) +- new_itm += local_cpu_data->itm_delta; ++ while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_tick_delta/2)) ++ new_itm += local_cpu_data->itm_tick_delta; + ia64_set_itm(new_itm); + /* double check, in case we got hit by a (slow) PMI: */ + } while (time_after_eq(ia64_get_itc(), new_itm)); +@@ -137,7 +157,7 @@ ia64_cpu_local_tick (void) + /* arrange for the cycle counter to generate a timer interrupt: */ + ia64_set_itv(IA64_TIMER_VECTOR); + +- delta = local_cpu_data->itm_delta; ++ delta = local_cpu_data->itm_tick_delta; + /* + * Stagger the timer tick for each CPU so they don't occur all at (almost) the + * same time: +@@ -146,8 +166,8 @@ ia64_cpu_local_tick (void) + unsigned long hi = 1UL << ia64_fls(cpu); + shift = (2*(cpu - hi) + 1) * delta/hi/2; + } +- local_cpu_data->itm_next = ia64_get_itc() + delta + shift; +- ia64_set_itm(local_cpu_data->itm_next); ++ local_cpu_data->itm_tick_next = ia64_get_itc() + delta + shift; ++ ia64_set_itm(local_cpu_data->itm_tick_next); + } + + static int nojitter; +@@ -205,7 +225,7 @@ ia64_init_itm (void) + + itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; + +- local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ; ++ local_cpu_data->itm_tick_delta = (itc_freq + HZ/2) / HZ; + printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%u/%u, " + "ITC freq=%lu.%03luMHz", smp_processor_id(), + platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, +@@ -225,6 +245,7 @@ ia64_init_itm (void) + local_cpu_data->nsec_per_cyc = ((NSEC_PER_SEC<mfh = 1; + } +- preempt_enable_no_resched(); ++ __preempt_enable_no_resched(); + } + + static inline int +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/unwind.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/unwind.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/unwind.c 2009-02-08 00:02:25.000000000 -0500 +@@ -82,7 +82,7 @@ typedef unsigned long unw_word; + typedef unsigned char unw_hash_index_t; + + static struct { +- spinlock_t lock; /* spinlock for unwind data */ ++ raw_spinlock_t lock; /* spinlock for unwind data */ + + /* list of unwind tables (one per load-module) */ + struct unw_table *tables; +@@ -146,7 +146,7 @@ static struct { + # endif + } unw = { + .tables = &unw.kernel_table, +- .lock = __SPIN_LOCK_UNLOCKED(unw.lock), ++ .lock = RAW_SPIN_LOCK_UNLOCKED(unw.lock), + .save_order = { + UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR, + UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR +Index: linux-2.6.24.7-rt27/arch/ia64/kernel/unwind_i.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/kernel/unwind_i.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/kernel/unwind_i.h 2009-02-08 00:02:25.000000000 -0500 +@@ -154,7 +154,7 @@ struct unw_script { + unsigned long ip; /* ip this script is for */ + unsigned long pr_mask; /* mask of predicates script depends on */ + unsigned long pr_val; /* predicate values this script is for */ +- rwlock_t lock; ++ raw_rwlock_t lock; + unsigned int flags; /* see UNW_FLAG_* in unwind.h */ + unsigned short lru_chain; /* used for least-recently-used chain */ + unsigned short coll_chain; /* used for hash collisions */ +Index: linux-2.6.24.7-rt27/arch/ia64/mm/init.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/mm/init.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/mm/init.c 2009-02-08 00:02:25.000000000 -0500 +@@ -37,7 +37,7 @@ + #include + #include + +-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); ++DEFINE_PER_CPU_LOCKED(struct mmu_gather, mmu_gathers); + + extern void ia64_tlb_init (void); + +Index: linux-2.6.24.7-rt27/arch/ia64/mm/tlb.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ia64/mm/tlb.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ia64/mm/tlb.c 2009-02-08 00:02:25.000000000 -0500 +@@ -33,7 +33,7 @@ static struct { + } purge; + + struct ia64_ctx ia64_ctx = { +- .lock = __SPIN_LOCK_UNLOCKED(ia64_ctx.lock), ++ .lock = RAW_SPIN_LOCK_UNLOCKED(ia64_ctx.lock), + .next = 1, + .max_ctx = ~0U + }; +Index: linux-2.6.24.7-rt27/include/asm-ia64/irqflags.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/include/asm-ia64/irqflags.h 2009-02-08 00:02:25.000000000 -0500 +@@ -0,0 +1,95 @@ ++ ++/* ++ * include/asm-i64/irqflags.h ++ * ++ * IRQ flags handling ++ * ++ * This file gets included from lowlevel asm headers too, to provide ++ * wrapped versions of the local_irq_*() APIs, based on the ++ * raw_local_irq_*() macros from the lowlevel headers. ++ */ ++#ifndef _ASM_IRQFLAGS_H ++#define _ASM_IRQFLAGS_H ++ ++/* For spinlocks etc */ ++ ++/* ++ * - clearing psr.i is implicitly serialized (visible by next insn) ++ * - setting psr.i requires data serialization ++ * - we need a stop-bit before reading PSR because we sometimes ++ * write a floating-point register right before reading the PSR ++ * and that writes to PSR.mfl ++ */ ++#define __local_irq_save(x) \ ++do { \ ++ ia64_stop(); \ ++ (x) = ia64_getreg(_IA64_REG_PSR); \ ++ ia64_stop(); \ ++ ia64_rsm(IA64_PSR_I); \ ++} while (0) ++ ++#define __local_irq_disable() \ ++do { \ ++ ia64_stop(); \ ++ ia64_rsm(IA64_PSR_I); \ ++} while (0) ++ ++#define __local_irq_restore(x) ia64_intrin_local_irq_restore((x) & IA64_PSR_I) ++ ++#ifdef CONFIG_IA64_DEBUG_IRQ ++ ++ extern unsigned long last_cli_ip; ++ ++# define __save_ip() last_cli_ip = ia64_getreg(_IA64_REG_IP) ++ ++# define raw_local_irq_save(x) \ ++do { \ ++ unsigned long psr; \ ++ \ ++ __local_irq_save(psr); \ ++ if (psr & IA64_PSR_I) \ ++ __save_ip(); \ ++ (x) = psr; \ ++} while (0) ++ ++# define raw_local_irq_disable() do { unsigned long x; local_irq_save(x); } while (0) ++ ++# define raw_local_irq_restore(x) \ ++do { \ ++ unsigned long old_psr, psr = (x); \ ++ \ ++ local_save_flags(old_psr); \ ++ __local_irq_restore(psr); \ ++ if ((old_psr & IA64_PSR_I) && !(psr & IA64_PSR_I)) \ ++ __save_ip(); \ ++} while (0) ++ ++#else /* !CONFIG_IA64_DEBUG_IRQ */ ++# define raw_local_irq_save(x) __local_irq_save(x) ++# define raw_local_irq_disable() __local_irq_disable() ++# define raw_local_irq_restore(x) __local_irq_restore(x) ++#endif /* !CONFIG_IA64_DEBUG_IRQ */ ++ ++#define raw_local_irq_enable() ({ ia64_stop(); ia64_ssm(IA64_PSR_I); ia64_srlz_d(); }) ++#define raw_local_save_flags(flags) ({ ia64_stop(); (flags) = ia64_getreg(_IA64_REG_PSR); }) ++ ++#define raw_irqs_disabled() \ ++({ \ ++ unsigned long __ia64_id_flags; \ ++ local_save_flags(__ia64_id_flags); \ ++ (__ia64_id_flags & IA64_PSR_I) == 0; \ ++}) ++ ++#define raw_irqs_disabled_flags(flags) ((flags & IA64_PSR_I) == 0) ++ ++ ++#define raw_safe_halt() ia64_pal_halt_light() /* PAL_HALT_LIGHT */ ++ ++/* TBD... */ ++# define TRACE_IRQS_ON ++# define TRACE_IRQS_OFF ++# define TRACE_IRQS_ON_STR ++# define TRACE_IRQS_OFF_STR ++ ++#endif ++ +Index: linux-2.6.24.7-rt27/include/asm-ia64/mmu_context.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-ia64/mmu_context.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-ia64/mmu_context.h 2009-02-08 00:02:25.000000000 -0500 +@@ -32,7 +32,7 @@ + #include + + struct ia64_ctx { +- spinlock_t lock; ++ raw_spinlock_t lock; + unsigned int next; /* next context number to use */ + unsigned int limit; /* available free range */ + unsigned int max_ctx; /* max. context value supported by all CPUs */ +Index: linux-2.6.24.7-rt27/include/asm-ia64/percpu.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-ia64/percpu.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-ia64/percpu.h 2009-02-08 00:02:25.000000000 -0500 +@@ -24,10 +24,17 @@ + #define DECLARE_PER_CPU(type, name) \ + extern __SMALL_ADDR_AREA __typeof__(type) per_cpu__##name + ++#define DECLARE_PER_CPU_LOCKED(type, name) \ ++ extern spinlock_t per_cpu_lock__##name##_locked; \ ++ extern __SMALL_ADDR_AREA __typeof__(type) per_cpu__##name##_locked ++ + /* Separate out the type, so (int[3], foo) works. */ + #define DEFINE_PER_CPU(type, name) \ +- __attribute__((__section__(".data.percpu"))) \ +- __SMALL_ADDR_AREA __typeof__(type) per_cpu__##name ++ __attribute__((__section__(".data.percpu"))) __SMALL_ADDR_AREA __typeof__(type) per_cpu__##name ++ ++#define DEFINE_PER_CPU_LOCKED(type, name) \ ++ __attribute__((__section__(".data.percpu"))) __SMALL_ADDR_AREA __DEFINE_SPINLOCK(per_cpu_lock__##name##_locked); \ ++ __attribute__((__section__(".data.percpu"))) __SMALL_ADDR_AREA __typeof__(type) per_cpu__##name##_locked + + #ifdef CONFIG_SMP + #define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \ +@@ -55,6 +62,16 @@ DECLARE_PER_CPU(unsigned long, local_per + #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __ia64_per_cpu_var(local_per_cpu_offset))) + #define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __ia64_per_cpu_var(local_per_cpu_offset))) + ++#define per_cpu_lock(var, cpu) \ ++ (*RELOC_HIDE(&per_cpu_lock__##var##_locked, __per_cpu_offset[cpu])) ++#define per_cpu_var_locked(var, cpu) \ ++ (*RELOC_HIDE(&per_cpu__##var##_locked, __per_cpu_offset[cpu])) ++#define __get_cpu_lock(var, cpu) \ ++ per_cpu_lock(var, cpu) ++#define __get_cpu_var_locked(var, cpu) \ ++ per_cpu_var_locked(var, cpu) ++ ++ + extern void percpu_modcopy(void *pcpudst, const void *src, unsigned long size); + extern void setup_per_cpu_areas (void); + extern void *per_cpu_init(void); +Index: linux-2.6.24.7-rt27/include/asm-ia64/processor.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-ia64/processor.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-ia64/processor.h 2009-02-08 00:02:25.000000000 -0500 +@@ -124,8 +124,10 @@ struct ia64_psr { + */ + struct cpuinfo_ia64 { + __u32 softirq_pending; +- __u64 itm_delta; /* # of clock cycles between clock ticks */ +- __u64 itm_next; /* interval timer mask value to use for next clock tick */ ++ __u64 itm_tick_delta; /* # of clock cycles between clock ticks */ ++ __u64 itm_tick_next; /* interval timer mask value to use for next clock tick */ ++ __u64 itm_timer_next; ++ __u64 __itm_next; + __u64 nsec_per_cyc; /* (1000000000<count = RWSEM_UNLOCKED_VALUE; + spin_lock_init(&sem->wait_lock); +@@ -70,7 +70,7 @@ init_rwsem (struct rw_semaphore *sem) + * lock for reading + */ + static inline void +-__down_read (struct rw_semaphore *sem) ++__down_read (struct compat_rw_semaphore *sem) + { + long result = ia64_fetchadd8_acq((unsigned long *)&sem->count, 1); + +@@ -82,7 +82,7 @@ __down_read (struct rw_semaphore *sem) + * lock for writing + */ + static inline void +-__down_write (struct rw_semaphore *sem) ++__down_write (struct compat_rw_semaphore *sem) + { + long old, new; + +@@ -99,7 +99,7 @@ __down_write (struct rw_semaphore *sem) + * unlock after reading + */ + static inline void +-__up_read (struct rw_semaphore *sem) ++__up_read (struct compat_rw_semaphore *sem) + { + long result = ia64_fetchadd8_rel((unsigned long *)&sem->count, -1); + +@@ -111,7 +111,7 @@ __up_read (struct rw_semaphore *sem) + * unlock after writing + */ + static inline void +-__up_write (struct rw_semaphore *sem) ++__up_write (struct compat_rw_semaphore *sem) + { + long old, new; + +@@ -128,7 +128,7 @@ __up_write (struct rw_semaphore *sem) + * trylock for reading -- returns 1 if successful, 0 if contention + */ + static inline int +-__down_read_trylock (struct rw_semaphore *sem) ++__down_read_trylock (struct compat_rw_semaphore *sem) + { + long tmp; + while ((tmp = sem->count) >= 0) { +@@ -143,7 +143,7 @@ __down_read_trylock (struct rw_semaphore + * trylock for writing -- returns 1 if successful, 0 if contention + */ + static inline int +-__down_write_trylock (struct rw_semaphore *sem) ++__down_write_trylock (struct compat_rw_semaphore *sem) + { + long tmp = cmpxchg_acq(&sem->count, RWSEM_UNLOCKED_VALUE, + RWSEM_ACTIVE_WRITE_BIAS); +@@ -154,7 +154,7 @@ __down_write_trylock (struct rw_semaphor + * downgrade write lock to read lock + */ + static inline void +-__downgrade_write (struct rw_semaphore *sem) ++__downgrade_write (struct compat_rw_semaphore *sem) + { + long old, new; + +@@ -174,7 +174,7 @@ __downgrade_write (struct rw_semaphore * + #define rwsem_atomic_add(delta, sem) atomic64_add(delta, (atomic64_t *)(&(sem)->count)) + #define rwsem_atomic_update(delta, sem) atomic64_add_return(delta, (atomic64_t *)(&(sem)->count)) + +-static inline int rwsem_is_locked(struct rw_semaphore *sem) ++static inline int compat_rwsem_is_locked(struct compat_rw_semaphore *sem) + { + return (sem->count != 0); + } +Index: linux-2.6.24.7-rt27/include/asm-ia64/sal.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-ia64/sal.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-ia64/sal.h 2009-02-08 00:02:25.000000000 -0500 +@@ -43,7 +43,7 @@ + #include + #include + +-extern spinlock_t sal_lock; ++extern raw_spinlock_t sal_lock; + + /* SAL spec _requires_ eight args for each call. */ + #define __IA64_FW_CALL(entry,result,a0,a1,a2,a3,a4,a5,a6,a7) \ +Index: linux-2.6.24.7-rt27/include/asm-ia64/semaphore.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-ia64/semaphore.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-ia64/semaphore.h 2009-02-08 00:02:25.000000000 -0500 +@@ -11,53 +11,64 @@ + + #include + +-struct semaphore { ++/* ++ * On !PREEMPT_RT all semaphores are compat: ++ */ ++#ifndef CONFIG_PREEMPT_RT ++# define compat_semaphore semaphore ++#endif ++ ++struct compat_semaphore { + atomic_t count; + int sleepers; + wait_queue_head_t wait; + }; + +-#define __SEMAPHORE_INITIALIZER(name, n) \ ++#define __COMPAT_SEMAPHORE_INITIALIZER(name, n) \ + { \ + .count = ATOMIC_INIT(n), \ + .sleepers = 0, \ + .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + } + +-#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ +- struct semaphore name = __SEMAPHORE_INITIALIZER(name, count) ++#define __COMPAT_DECLARE_SEMAPHORE_GENERIC(name,count) \ ++ struct compat_semaphore name = __COMPAT_SEMAPHORE_INITIALIZER(name, count) + +-#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1) ++#define COMPAT_DECLARE_MUTEX(name) __COMPAT_DECLARE_SEMAPHORE_GENERIC(name, 1) ++ ++#define compat_sema_count(sem) atomic_read(&(sem)->count) ++ ++asmlinkage int compat_sem_is_locked(struct compat_semaphore *sem); + + static inline void +-sema_init (struct semaphore *sem, int val) ++compat_sema_init (struct compat_semaphore *sem, int val) + { +- *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val); ++ *sem = (struct compat_semaphore) __COMPAT_SEMAPHORE_INITIALIZER(*sem, val); + } + + static inline void +-init_MUTEX (struct semaphore *sem) ++compat_init_MUTEX (struct compat_semaphore *sem) + { +- sema_init(sem, 1); ++ compat_sema_init(sem, 1); + } + + static inline void +-init_MUTEX_LOCKED (struct semaphore *sem) ++compat_init_MUTEX_LOCKED (struct compat_semaphore *sem) + { +- sema_init(sem, 0); ++ compat_sema_init(sem, 0); + } + +-extern void __down (struct semaphore * sem); +-extern int __down_interruptible (struct semaphore * sem); +-extern int __down_trylock (struct semaphore * sem); +-extern void __up (struct semaphore * sem); ++extern void __down (struct compat_semaphore * sem); ++extern int __down_interruptible (struct compat_semaphore * sem); ++extern int __down_trylock (struct compat_semaphore * sem); ++extern void __up (struct compat_semaphore * sem); + + /* + * Atomically decrement the semaphore's count. If it goes negative, + * block the calling thread in the TASK_UNINTERRUPTIBLE state. + */ + static inline void +-down (struct semaphore *sem) ++compat_down (struct compat_semaphore *sem) + { + might_sleep(); + if (ia64_fetchadd(-1, &sem->count.counter, acq) < 1) +@@ -69,7 +80,7 @@ down (struct semaphore *sem) + * block the calling thread in the TASK_INTERRUPTIBLE state. + */ + static inline int +-down_interruptible (struct semaphore * sem) ++compat_down_interruptible (struct compat_semaphore * sem) + { + int ret = 0; + +@@ -80,7 +91,7 @@ down_interruptible (struct semaphore * s + } + + static inline int +-down_trylock (struct semaphore *sem) ++compat_down_trylock (struct compat_semaphore *sem) + { + int ret = 0; + +@@ -90,10 +101,12 @@ down_trylock (struct semaphore *sem) + } + + static inline void +-up (struct semaphore * sem) ++compat_up (struct compat_semaphore * sem) + { + if (ia64_fetchadd(1, &sem->count.counter, rel) <= -1) + __up(sem); + } + ++#include ++ + #endif /* _ASM_IA64_SEMAPHORE_H */ +Index: linux-2.6.24.7-rt27/include/asm-ia64/spinlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-ia64/spinlock.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-ia64/spinlock.h 2009-02-08 00:02:25.000000000 -0500 +@@ -17,8 +17,6 @@ + #include + #include + +-#define __raw_spin_lock_init(x) ((x)->lock = 0) +- + #ifdef ASM_SUPPORTED + /* + * Try to get the lock. If we fail to get the lock, make a non-standard call to +@@ -30,7 +28,7 @@ + #define IA64_SPINLOCK_CLOBBERS "ar.ccv", "ar.pfs", "p14", "p15", "r27", "r28", "r29", "r30", "b6", "memory" + + static inline void +-__raw_spin_lock_flags (raw_spinlock_t *lock, unsigned long flags) ++__raw_spin_lock_flags (__raw_spinlock_t *lock, unsigned long flags) + { + register volatile unsigned int *ptr asm ("r31") = &lock->lock; + +@@ -89,7 +87,7 @@ __raw_spin_lock_flags (raw_spinlock_t *l + #define __raw_spin_lock(lock) __raw_spin_lock_flags(lock, 0) + + /* Unlock by doing an ordered store and releasing the cacheline with nta */ +-static inline void __raw_spin_unlock(raw_spinlock_t *x) { ++static inline void __raw_spin_unlock(__raw_spinlock_t *x) { + barrier(); + asm volatile ("st4.rel.nta [%0] = r0\n\t" :: "r"(x)); + } +@@ -109,7 +107,7 @@ do { \ + } while (ia64_spinlock_val); \ + } \ + } while (0) +-#define __raw_spin_unlock(x) do { barrier(); ((raw_spinlock_t *) x)->lock = 0; } while (0) ++#define __raw_spin_unlock(x) do { barrier(); ((__raw_spinlock_t *) x)->lock = 0; } while (0) + #endif /* !ASM_SUPPORTED */ + + #define __raw_spin_is_locked(x) ((x)->lock != 0) +@@ -122,7 +120,7 @@ do { \ + + #define __raw_read_lock(rw) \ + do { \ +- raw_rwlock_t *__read_lock_ptr = (rw); \ ++ __raw_rwlock_t *__read_lock_ptr = (rw); \ + \ + while (unlikely(ia64_fetchadd(1, (int *) __read_lock_ptr, acq) < 0)) { \ + ia64_fetchadd(-1, (int *) __read_lock_ptr, rel); \ +@@ -133,7 +131,7 @@ do { \ + + #define __raw_read_unlock(rw) \ + do { \ +- raw_rwlock_t *__read_lock_ptr = (rw); \ ++ __raw_rwlock_t *__read_lock_ptr = (rw); \ + ia64_fetchadd(-1, (int *) __read_lock_ptr, rel); \ + } while (0) + +@@ -165,7 +163,7 @@ do { \ + (result == 0); \ + }) + +-static inline void __raw_write_unlock(raw_rwlock_t *x) ++static inline void __raw_write_unlock(__raw_rwlock_t *x) + { + u8 *y = (u8 *)x; + barrier(); +@@ -193,7 +191,7 @@ static inline void __raw_write_unlock(ra + (ia64_val == 0); \ + }) + +-static inline void __raw_write_unlock(raw_rwlock_t *x) ++static inline void __raw_write_unlock(__raw_rwlock_t *x) + { + barrier(); + x->write_lock = 0; +@@ -201,10 +199,10 @@ static inline void __raw_write_unlock(ra + + #endif /* !ASM_SUPPORTED */ + +-static inline int __raw_read_trylock(raw_rwlock_t *x) ++static inline int __raw_read_trylock(__raw_rwlock_t *x) + { + union { +- raw_rwlock_t lock; ++ __raw_rwlock_t lock; + __u32 word; + } old, new; + old.lock = new.lock = *x; +@@ -213,8 +211,8 @@ static inline int __raw_read_trylock(raw + return (u32)ia64_cmpxchg4_acq((__u32 *)(x), new.word, old.word) == old.word; + } + +-#define _raw_spin_relax(lock) cpu_relax() +-#define _raw_read_relax(lock) cpu_relax() +-#define _raw_write_relax(lock) cpu_relax() ++#define __raw_spin_relax(lock) cpu_relax() ++#define __raw_read_relax(lock) cpu_relax() ++#define __raw_write_relax(lock) cpu_relax() + + #endif /* _ASM_IA64_SPINLOCK_H */ +Index: linux-2.6.24.7-rt27/include/asm-ia64/spinlock_types.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-ia64/spinlock_types.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-ia64/spinlock_types.h 2009-02-08 00:02:25.000000000 -0500 +@@ -7,14 +7,14 @@ + + typedef struct { + volatile unsigned int lock; +-} raw_spinlock_t; ++} __raw_spinlock_t; + + #define __RAW_SPIN_LOCK_UNLOCKED { 0 } + + typedef struct { + volatile unsigned int read_counter : 31; + volatile unsigned int write_lock : 1; +-} raw_rwlock_t; ++} __raw_rwlock_t; + + #define __RAW_RW_LOCK_UNLOCKED { 0, 0 } + +Index: linux-2.6.24.7-rt27/include/asm-ia64/system.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-ia64/system.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-ia64/system.h 2009-02-08 00:02:25.000000000 -0500 +@@ -106,81 +106,16 @@ extern struct ia64_boot_param { + */ + #define set_mb(var, value) do { (var) = (value); mb(); } while (0) + +-#define safe_halt() ia64_pal_halt_light() /* PAL_HALT_LIGHT */ + + /* + * The group barrier in front of the rsm & ssm are necessary to ensure + * that none of the previous instructions in the same group are + * affected by the rsm/ssm. + */ +-/* For spinlocks etc */ + +-/* +- * - clearing psr.i is implicitly serialized (visible by next insn) +- * - setting psr.i requires data serialization +- * - we need a stop-bit before reading PSR because we sometimes +- * write a floating-point register right before reading the PSR +- * and that writes to PSR.mfl +- */ +-#define __local_irq_save(x) \ +-do { \ +- ia64_stop(); \ +- (x) = ia64_getreg(_IA64_REG_PSR); \ +- ia64_stop(); \ +- ia64_rsm(IA64_PSR_I); \ +-} while (0) +- +-#define __local_irq_disable() \ +-do { \ +- ia64_stop(); \ +- ia64_rsm(IA64_PSR_I); \ +-} while (0) +- +-#define __local_irq_restore(x) ia64_intrin_local_irq_restore((x) & IA64_PSR_I) +- +-#ifdef CONFIG_IA64_DEBUG_IRQ + +- extern unsigned long last_cli_ip; +- +-# define __save_ip() last_cli_ip = ia64_getreg(_IA64_REG_IP) +- +-# define local_irq_save(x) \ +-do { \ +- unsigned long psr; \ +- \ +- __local_irq_save(psr); \ +- if (psr & IA64_PSR_I) \ +- __save_ip(); \ +- (x) = psr; \ +-} while (0) +- +-# define local_irq_disable() do { unsigned long x; local_irq_save(x); } while (0) +- +-# define local_irq_restore(x) \ +-do { \ +- unsigned long old_psr, psr = (x); \ +- \ +- local_save_flags(old_psr); \ +- __local_irq_restore(psr); \ +- if ((old_psr & IA64_PSR_I) && !(psr & IA64_PSR_I)) \ +- __save_ip(); \ +-} while (0) ++#include + +-#else /* !CONFIG_IA64_DEBUG_IRQ */ +-# define local_irq_save(x) __local_irq_save(x) +-# define local_irq_disable() __local_irq_disable() +-# define local_irq_restore(x) __local_irq_restore(x) +-#endif /* !CONFIG_IA64_DEBUG_IRQ */ +- +-#define local_irq_enable() ({ ia64_stop(); ia64_ssm(IA64_PSR_I); ia64_srlz_d(); }) +-#define local_save_flags(flags) ({ ia64_stop(); (flags) = ia64_getreg(_IA64_REG_PSR); }) +- +-#define irqs_disabled() \ +-({ \ +- unsigned long __ia64_id_flags; \ +- local_save_flags(__ia64_id_flags); \ +- (__ia64_id_flags & IA64_PSR_I) == 0; \ +-}) + + #ifdef __KERNEL__ + +Index: linux-2.6.24.7-rt27/include/asm-ia64/thread_info.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-ia64/thread_info.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-ia64/thread_info.h 2009-02-08 00:02:25.000000000 -0500 +@@ -91,6 +91,7 @@ struct thread_info { + #define TIF_MCA_INIT 18 /* this task is processing MCA or INIT */ + #define TIF_DB_DISABLED 19 /* debug trap disabled for fsyscall */ + #define TIF_FREEZE 20 /* is freezing for suspend */ ++#define TIF_NEED_RESCHED_DELAYED 20 /* reschedule on return to userspace */ + + #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) + #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) +Index: linux-2.6.24.7-rt27/include/asm-ia64/tlb.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-ia64/tlb.h 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-ia64/tlb.h 2009-02-08 00:02:25.000000000 -0500 +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -61,11 +62,12 @@ struct mmu_gather { + unsigned char need_flush; /* really unmapped some PTEs? */ + unsigned long start_addr; + unsigned long end_addr; ++ int cpu; + struct page *pages[FREE_PTE_NR]; + }; + + /* Users of the generic TLB shootdown code must declare this storage space. */ +-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); ++DECLARE_PER_CPU_LOCKED(struct mmu_gather, mmu_gathers); + + /* + * Flush the TLB for address range START to END and, if not in fast mode, release the +@@ -127,8 +129,10 @@ ia64_tlb_flush_mmu (struct mmu_gather *t + static inline struct mmu_gather * + tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush) + { +- struct mmu_gather *tlb = &get_cpu_var(mmu_gathers); ++ int cpu; ++ struct mmu_gather *tlb = &get_cpu_var_locked(mmu_gathers, &cpu); + ++ tlb->cpu = cpu; + tlb->mm = mm; + /* + * Use fast mode if only 1 CPU is online. +@@ -165,7 +169,7 @@ tlb_finish_mmu (struct mmu_gather *tlb, + /* keep the page table cache within bounds */ + check_pgt_cache(); + +- put_cpu_var(mmu_gathers); ++ put_cpu_var_locked(mmu_gathers, tlb->cpu); + } + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0193-tasklet-fix-preemption-race.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0193-tasklet-fix-preemption-race.patch @@ -0,0 +1,103 @@ +From johnstul@us.ibm.com Wed Jun 6 04:17:34 2007 +Return-Path: +Received: from e3.ny.us.ibm.com (e3.ny.us.ibm.com [32.97.182.143]) (using + TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate + requested) by mail.tglx.de (Postfix) with ESMTP id 1CCC065C065 for + ; Wed, 6 Jun 2007 04:17:34 +0200 (CEST) +Received: from d01relay04.pok.ibm.com (d01relay04.pok.ibm.com + [9.56.227.236]) by e3.ny.us.ibm.com (8.13.8/8.13.8) with ESMTP id + l561EvIT011411 for ; Tue, 5 Jun 2007 21:14:57 -0400 +Received: from d01av04.pok.ibm.com (d01av04.pok.ibm.com [9.56.224.64]) by + d01relay04.pok.ibm.com (8.13.8/8.13.8/NCO v8.3) with ESMTP id + l562HUG6545736 for ; Tue, 5 Jun 2007 22:17:30 -0400 +Received: from d01av04.pok.ibm.com (loopback [127.0.0.1]) by + d01av04.pok.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id l562HUu0027167 + for ; Tue, 5 Jun 2007 22:17:30 -0400 +Received: from [9.47.21.16] (cog.beaverton.ibm.com [9.47.21.16]) by + d01av04.pok.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id + l562HTkh027139; Tue, 5 Jun 2007 22:17:29 -0400 +Subject: [PATCH -rt] Fix TASKLET_STATE_SCHED WARN_ON() +From: john stultz +To: Ingo Molnar +Cc: Thomas Gleixner , Steven Rostedt , "Paul E. McKenney" , lkml +Content-Type: text/plain +Date: Tue, 05 Jun 2007 19:17:23 -0700 +Message-Id: <1181096244.6018.20.camel@localhost> +Mime-Version: 1.0 +X-Mailer: Evolution 2.10.1 +X-Evolution-Source: imap://tglx%40linutronix.de@localhost:8993/ +Content-Transfer-Encoding: 8bit + +Hey Ingo, + So we've been seeing the following trace fairly frequently on our SMP +boxes when running kernbench: + +BUG: at kernel/softirq.c:639 __tasklet_action() + +Call Trace: + [] dump_trace+0xaa/0x32a + [] show_trace+0x41/0x5c + [] dump_stack+0x15/0x17 + [] __tasklet_action+0xdf/0x12e + [] tasklet_action+0x27/0x29 + [] ksoftirqd+0x16c/0x271 + [] kthread+0xf5/0x128 + [] child_rip+0xa/0x12 + + +Paul also pointed this out awhile back: http://lkml.org/lkml/2007/2/25/1 + + +Anyway, I think I finally found the issue. Its a bit hard to explain, +but the idea is while __tasklet_action is running the tasklet function +on CPU1, if a call to tasklet_schedule() on CPU2 is made, and if right +after we mark the TASKLET_STATE_SCHED bit we are preempted, +__tasklet_action on CPU1 might be able to re-run the function, clear the +bit and unlock the tasklet before CPU2 enters __tasklet_common_schedule. +Once __tasklet_common_schedule locks the tasklet, we will add the +tasklet to the list with the TASKLET_STATE_SCHED *unset*. + +I've verified this race occurs w/ a WARN_ON in +__tasklet_common_schedule(). + + +This fix avoids this race by making sure *after* we've locked the +tasklet that the STATE_SCHED bit is set before adding it to the list. + +Does it look ok to you? + +thanks +-john + +Signed-off-by: John Stultz + +--- + kernel/softirq.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/softirq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/softirq.c 2009-02-08 00:02:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/softirq.c 2009-02-08 00:02:13.000000000 -0500 +@@ -459,10 +459,17 @@ static void inline + __tasklet_common_schedule(struct tasklet_struct *t, struct tasklet_head *head, unsigned int nr) + { + if (tasklet_trylock(t)) { +- WARN_ON(t->next != NULL); +- t->next = head->list; +- head->list = t; +- raise_softirq_irqoff(nr); ++ /* We may have been preempted before tasklet_trylock ++ * and __tasklet_action may have already run. ++ * So double check the sched bit while the takslet ++ * is locked before adding it to the list. ++ */ ++ if (test_bit(TASKLET_STATE_SCHED, &t->state)) { ++ WARN_ON(t->next != NULL); ++ t->next = head->list; ++ head->list = t; ++ raise_softirq_irqoff(nr); ++ } + tasklet_unlock(t); + } + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0108-latency-tracing-arm.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0108-latency-tracing-arm.patch @@ -0,0 +1,368 @@ + arch/arm/boot/compressed/head.S | 13 ++++ + arch/arm/kernel/entry-common.S | 109 ++++++++++++++++++++++++++++++++++++++++ + arch/arm/kernel/fiq.c | 4 - + arch/arm/kernel/irq.c | 2 + arch/arm/mm/copypage-v4mc.c | 4 - + arch/arm/mm/copypage-xscale.c | 4 - + arch/arm/mm/fault.c | 14 ++--- + include/asm-arm/pgalloc.h | 4 - + include/asm-arm/timex.h | 10 +++ + include/asm-arm/unistd.h | 4 + + 10 files changed, 151 insertions(+), 17 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/arm/boot/compressed/head.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/boot/compressed/head.S 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/boot/compressed/head.S 2009-02-08 00:01:34.000000000 -0500 +@@ -928,6 +928,19 @@ memdump: mov r12, r0 + #endif + + .ltorg ++#ifdef CONFIG_MCOUNT ++/* CONFIG_MCOUNT causes boot header to be built with -pg requiring this ++ * trampoline ++ */ ++ .text ++ .align 0 ++ .type mcount %function ++ .global mcount ++mcount: ++ mov pc, lr @ just return ++#endif ++ ++ + reloc_end: + + .align +Index: linux-2.6.24.7-rt27/arch/arm/kernel/entry-common.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/entry-common.S 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/entry-common.S 2009-02-08 00:01:34.000000000 -0500 +@@ -3,6 +3,8 @@ + * + * Copyright (C) 2000 Russell King + * ++ * FUNCTION_TRACE/mcount support (C) 2005 Timesys john.cooper@timesys.com ++ * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +@@ -395,5 +397,112 @@ ENTRY(sys_oabi_call_table) + #undef ABI + #undef OBSOLETE + ++#ifdef CONFIG_FRAME_POINTER ++ ++#ifdef CONFIG_MCOUNT ++/* ++ * At the point where we are in mcount() we maintain the ++ * frame of the prologue code and keep the call to mcount() ++ * out of the stack frame list: ++ ++ saved pc <---\ caller of instrumented routine ++ saved lr | ++ ip/prev_sp | ++ fp -----^ | ++ : | ++ | ++ -> saved pc | instrumented routine ++ | saved lr | ++ | ip/prev_sp | ++ | fp ---------/ ++ | : ++ | ++ | mcount ++ | saved pc ++ | saved lr ++ | ip/prev sp ++ -- fp ++ r3 ++ r2 ++ r1 ++ sp-> r0 ++ : ++ */ ++ ++ .text ++ .align 0 ++ .type mcount %function ++ .global mcount ++ ++/* gcc -pg generated FUNCTION_PROLOGUE references mcount() ++ * and has already created the stack frame invocation for ++ * the routine we have been called to instrument. We create ++ * a complete frame nevertheless, as we want to use the same ++ * call to mcount() from c code. ++ */ ++mcount: ++ ++ ldr ip, =mcount_enabled @ leave early, if disabled ++ ldr ip, [ip] ++ cmp ip, #0 ++ moveq pc,lr ++ ++ mov ip, sp ++ stmdb sp!, {r0 - r3, fp, ip, lr, pc} @ create stack frame ++ ++ ldr r1, [fp, #-4] @ get lr (the return address ++ @ of the caller of the ++ @ instrumented function) ++ mov r0, lr @ get lr - (the return address ++ @ of the instrumented function) ++ ++ sub fp, ip, #4 @ point fp at this frame ++ ++ bl __trace ++1: ++ ldmdb fp, {r0 - r3, fp, sp, pc} @ pop entry frame and return ++ ++#endif ++ ++/* ARM replacement for unsupported gcc __builtin_return_address(n) ++ * where 0 < n. n == 0 is supported here as well. ++ * ++ * Walk up the stack frame until the desired frame is found or a NULL ++ * fp is encountered, return NULL in the latter case. ++ * ++ * Note: it is possible under code optimization for the stack invocation ++ * of an ancestor function (level N) to be removed before calling a ++ * descendant function (level N+1). No easy means is available to deduce ++ * this scenario with the result being [for example] caller_addr(0) when ++ * called from level N+1 returning level N-1 rather than the expected ++ * level N. This optimization issue appears isolated to the case of ++ * a call to a level N+1 routine made at the tail end of a level N ++ * routine -- the level N frame is deleted and a simple branch is made ++ * to the level N+1 routine. ++ */ ++ ++ .text ++ .align 0 ++ .type arm_return_addr %function ++ .global arm_return_addr ++ ++arm_return_addr: ++ mov ip, r0 ++ mov r0, fp ++3: ++ cmp r0, #0 ++ beq 1f @ frame list hit end, bail ++ cmp ip, #0 ++ beq 2f @ reached desired frame ++ ldr r0, [r0, #-12] @ else continue, get next fp ++ sub ip, ip, #1 ++ b 3b ++2: ++ ldr r0, [r0, #-4] @ get target return address ++1: ++ mov pc, lr ++ ++#endif ++ + #endif + +Index: linux-2.6.24.7-rt27/arch/arm/kernel/fiq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/fiq.c 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/fiq.c 2009-02-08 00:01:34.000000000 -0500 +@@ -89,7 +89,7 @@ void set_fiq_handler(void *start, unsign + * disable irqs for the duration. Note - these functions are almost + * entirely coded in assembly. + */ +-void __attribute__((naked)) set_fiq_regs(struct pt_regs *regs) ++void notrace __attribute__((naked)) set_fiq_regs(struct pt_regs *regs) + { + register unsigned long tmp; + asm volatile ( +@@ -107,7 +107,7 @@ void __attribute__((naked)) set_fiq_regs + : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); + } + +-void __attribute__((naked)) get_fiq_regs(struct pt_regs *regs) ++void notrace __attribute__((naked)) get_fiq_regs(struct pt_regs *regs) + { + register unsigned long tmp; + asm volatile ( +Index: linux-2.6.24.7-rt27/arch/arm/kernel/irq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/irq.c 2009-02-08 00:01:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/irq.c 2009-02-08 00:01:34.000000000 -0500 +@@ -110,7 +110,7 @@ static struct irq_desc bad_irq_desc = { + * come via this function. Instead, they should provide their + * own 'handler' + */ +-asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs) ++asmlinkage void __exception notrace asm_do_IRQ(unsigned int irq, struct pt_regs *regs) + { + struct pt_regs *old_regs = set_irq_regs(regs); + struct irq_desc *desc = irq_desc + irq; +Index: linux-2.6.24.7-rt27/arch/arm/mm/copypage-v4mc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mm/copypage-v4mc.c 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mm/copypage-v4mc.c 2009-02-08 00:01:34.000000000 -0500 +@@ -44,7 +44,7 @@ static DEFINE_SPINLOCK(minicache_lock); + * instruction. If your processor does not supply this, you have to write your + * own copy_user_page that does the right thing. + */ +-static void __attribute__((naked)) ++static void notrace __attribute__((naked)) + mc_copy_user_page(void *from, void *to) + { + asm volatile( +@@ -88,7 +88,7 @@ void v4_mc_copy_user_page(void *kto, con + /* + * ARMv4 optimised clear_user_page + */ +-void __attribute__((naked)) ++void notrace __attribute__((naked)) + v4_mc_clear_user_page(void *kaddr, unsigned long vaddr) + { + asm volatile( +Index: linux-2.6.24.7-rt27/arch/arm/mm/copypage-xscale.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mm/copypage-xscale.c 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mm/copypage-xscale.c 2009-02-08 00:01:34.000000000 -0500 +@@ -42,7 +42,7 @@ static DEFINE_SPINLOCK(minicache_lock); + * Dcache aliasing issue. The writes will be forwarded to the write buffer, + * and merged as appropriate. + */ +-static void __attribute__((naked)) ++static void notrace __attribute__((naked)) + mc_copy_user_page(void *from, void *to) + { + /* +@@ -110,7 +110,7 @@ void xscale_mc_copy_user_page(void *kto, + /* + * XScale optimised clear_user_page + */ +-void __attribute__((naked)) ++void notrace __attribute__((naked)) + xscale_mc_clear_user_page(void *kaddr, unsigned long vaddr) + { + asm volatile( +Index: linux-2.6.24.7-rt27/arch/arm/mm/fault.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mm/fault.c 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mm/fault.c 2009-02-08 00:01:34.000000000 -0500 +@@ -215,7 +215,7 @@ out: + return fault; + } + +-static int ++static notrace int + do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) + { + struct task_struct *tsk; +@@ -311,7 +311,7 @@ no_context: + * interrupt or a critical region, and should only copy the information + * from the master page table, nothing more. + */ +-static int ++static notrace int + do_translation_fault(unsigned long addr, unsigned int fsr, + struct pt_regs *regs) + { +@@ -354,7 +354,7 @@ bad_area: + * Some section permission faults need to be handled gracefully. + * They can happen due to a __{get,put}_user during an oops. + */ +-static int ++static notrace int + do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) + { + do_bad_area(addr, fsr, regs); +@@ -364,7 +364,7 @@ do_sect_fault(unsigned long addr, unsign + /* + * This abort handler always returns "fault". + */ +-static int ++static notrace int + do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs) + { + return 1; +@@ -419,7 +419,7 @@ static struct fsr_info { + { do_bad, SIGBUS, 0, "unknown 31" } + }; + +-void __init ++void __init notrace + hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), + int sig, const char *name) + { +@@ -433,7 +433,7 @@ hook_fault_code(int nr, int (*fn)(unsign + /* + * Dispatch a data abort to the relevant handler. + */ +-asmlinkage void __exception ++asmlinkage void __exception notrace + do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) + { + const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6); +@@ -452,7 +452,7 @@ do_DataAbort(unsigned long addr, unsigne + arm_notify_die("", regs, &info, fsr, 0); + } + +-asmlinkage void __exception ++asmlinkage void __exception notrace + do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) + { + do_translation_fault(addr, 0, regs); +Index: linux-2.6.24.7-rt27/include/asm-arm/pgalloc.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/pgalloc.h 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/pgalloc.h 2009-02-08 00:01:34.000000000 -0500 +@@ -109,7 +109,7 @@ static inline void __pmd_populate(pmd_t + * + * Ensure that we always set both PMD entries. + */ +-static inline void ++static inline void notrace + pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) + { + unsigned long pte_ptr = (unsigned long)ptep; +@@ -122,7 +122,7 @@ pmd_populate_kernel(struct mm_struct *mm + __pmd_populate(pmdp, __pa(pte_ptr) | _PAGE_KERNEL_TABLE); + } + +-static inline void ++static inline void notrace + pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *ptep) + { + __pmd_populate(pmdp, page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE); +Index: linux-2.6.24.7-rt27/include/asm-arm/timex.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/timex.h 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/timex.h 2009-02-08 00:01:34.000000000 -0500 +@@ -16,9 +16,17 @@ + + typedef unsigned long cycles_t; + ++#ifndef mach_read_cycles ++ #define mach_read_cycles() (0) ++#ifdef CONFIG_LATENCY_TIMING ++ #define mach_cycles_to_usecs(d) (d) ++ #define mach_usecs_to_cycles(d) (d) ++#endif ++#endif ++ + static inline cycles_t get_cycles (void) + { +- return 0; ++ return mach_read_cycles(); + } + + #endif +Index: linux-2.6.24.7-rt27/include/asm-arm/unistd.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/unistd.h 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/unistd.h 2009-02-08 00:01:34.000000000 -0500 +@@ -380,6 +380,10 @@ + #define __NR_eventfd (__NR_SYSCALL_BASE+351) + #define __NR_fallocate (__NR_SYSCALL_BASE+352) + ++#ifndef __ASSEMBLY__ ++#define NR_syscalls (__NR_fallocate + 1 - __NR_SYSCALL_BASE) ++#endif ++ + /* + * The following SWIs are ARM private. + */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0403-dynamically-update-root-domain-span-online-maps.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0403-dynamically-update-root-domain-span-online-maps.patch @@ -0,0 +1,138 @@ +From ghaskins@novell.com Fri Jan 11 14:52:37 2008 +Date: Mon, 17 Dec 2007 21:40:32 -0500 +From: Gregory Haskins +To: srostedt@redhat.com +Cc: mingo@elte.hu, linux-rt-users@vger.kernel.org, linux-kernel@vger.kernel.org, + ghaskins@novell.com +Subject: [PATCH] sched: dynamically update the root-domain span/online maps + + [ The following text is in the "utf-8" character set. ] + [ Your display is set for the "iso-8859-1" character set. ] + [ Some characters may be displayed incorrectly. ] + +Hi Steven, + I posted a suspend-to-ram fix to sched-devel earlier today: + +http://lkml.org/lkml/2007/12/17/445 + +This fix should also be applied to -rt as I introduced the same regression +there. Here is a version of the fix for 23-rt13. I can submit a version for +24-rc5-rt1 at your request. + +Regards, +-Greg + +--------------------------------- + +The baseline code statically builds the span maps when the domain is formed. +Previous attempts at dynamically updating the maps caused a suspend-to-ram +regression, which should now be fixed. + +Signed-off-by: Gregory Haskins +CC: Gautham R Shenoy +--- + + kernel/sched.c | 28 ++++++++++++++++------------ + 1 file changed, 16 insertions(+), 12 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:03:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:04:01.000000000 -0500 +@@ -336,8 +336,6 @@ struct rt_rq { + * exclusive cpuset is created, we also create and attach a new root-domain + * object. + * +- * By default the system creates a single root-domain with all cpus as +- * members (mimicking the global state we have today). + */ + struct root_domain { + atomic_t refcount; +@@ -355,6 +353,10 @@ struct root_domain { + #endif + }; + ++/* ++ * By default the system creates a single root-domain with all cpus as ++ * members (mimicking the global state we have today). ++ */ + static struct root_domain def_root_domain; + + #endif +@@ -6344,6 +6346,10 @@ static void rq_attach_root(struct rq *rq + atomic_inc(&rd->refcount); + rq->rd = rd; + ++ cpu_set(rq->cpu, rd->span); ++ if (cpu_isset(rq->cpu, cpu_online_map)) ++ cpu_set(rq->cpu, rd->online); ++ + for (class = sched_class_highest; class; class = class->next) { + if (class->join_domain) + class->join_domain(rq); +@@ -6352,12 +6358,12 @@ static void rq_attach_root(struct rq *rq + spin_unlock_irqrestore(&rq->lock, flags); + } + +-static void init_rootdomain(struct root_domain *rd, const cpumask_t *map) ++static void init_rootdomain(struct root_domain *rd) + { + memset(rd, 0, sizeof(*rd)); + +- rd->span = *map; +- cpus_and(rd->online, rd->span, cpu_online_map); ++ cpus_clear(rd->span); ++ cpus_clear(rd->online); + + cpupri_init(&rd->cpupri); + +@@ -6365,13 +6371,11 @@ static void init_rootdomain(struct root_ + + static void init_defrootdomain(void) + { +- cpumask_t cpus = CPU_MASK_ALL; +- +- init_rootdomain(&def_root_domain, &cpus); ++ init_rootdomain(&def_root_domain); + atomic_set(&def_root_domain.refcount, 1); + } + +-static struct root_domain *alloc_rootdomain(const cpumask_t *map) ++static struct root_domain *alloc_rootdomain(void) + { + struct root_domain *rd; + +@@ -6379,7 +6383,7 @@ static struct root_domain *alloc_rootdom + if (!rd) + return NULL; + +- init_rootdomain(rd, map); ++ init_rootdomain(rd); + + return rd; + } +@@ -6800,7 +6804,7 @@ static int build_sched_domains(const cpu + sched_group_nodes_bycpu[first_cpu(*cpu_map)] = sched_group_nodes; + #endif + +- rd = alloc_rootdomain(cpu_map); ++ rd = alloc_rootdomain(); + if (!rd) { + printk(KERN_WARNING "Cannot alloc root domain\n"); + return -ENOMEM; +@@ -7356,7 +7360,6 @@ void __init sched_init(void) + #ifdef CONFIG_SMP + rq->sd = NULL; + rq->rd = NULL; +- rq_attach_root(rq, &def_root_domain); + rq->active_balance = 0; + rq->next_balance = jiffies; + rq->push_cpu = 0; +@@ -7365,6 +7368,7 @@ void __init sched_init(void) + INIT_LIST_HEAD(&rq->migration_queue); + rq->rt.highest_prio = MAX_RT_PRIO; + rq->rt.overloaded = 0; ++ rq_attach_root(rq, &def_root_domain); + #endif + atomic_set(&rq->nr_iowait, 0); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0106-nmi-profiling-base.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0106-nmi-profiling-base.patch @@ -0,0 +1,420 @@ +Subject: [patch] nmi-driven profiling for /proc/profile +From: Ingo Molnar + +nmi-driven profiling for /proc/profile + +Signed-off-by: Ingo Molnar +--- + arch/x86/kernel/crash.c | 8 ---- + arch/x86/kernel/irq_64.c | 2 + + arch/x86/kernel/nmi_32.c | 89 ++++++++++++++++++++++++++++++++++++++++++---- + arch/x86/kernel/nmi_64.c | 64 +++++++++++++++++++++++++++++++-- + include/asm-x86/apic_32.h | 2 + + include/asm-x86/apic_64.h | 2 + + include/linux/profile.h | 1 + kernel/profile.c | 9 +++- + kernel/time/tick-common.c | 1 + kernel/time/tick-sched.c | 2 - + 10 files changed, 156 insertions(+), 24 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/crash.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/crash.c 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/crash.c 2009-02-08 00:01:32.000000000 -0500 +@@ -78,14 +78,6 @@ static int crash_nmi_callback(struct not + return 1; + } + +-static void smp_send_nmi_allbutself(void) +-{ +- cpumask_t mask = cpu_online_map; +- cpu_clear(safe_smp_processor_id(), mask); +- if (!cpus_empty(mask)) +- send_IPI_mask(mask, NMI_VECTOR); +-} +- + static struct notifier_block crash_nmi_nb = { + .notifier_call = crash_nmi_callback, + }; +Index: linux-2.6.24.7-rt27/arch/x86/kernel/irq_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/irq_64.c 2009-02-08 00:01:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/irq_64.c 2009-02-08 00:01:32.000000000 -0500 +@@ -147,6 +147,8 @@ asmlinkage unsigned int do_IRQ(struct pt + unsigned vector = ~regs->orig_rax; + unsigned irq; + ++ irq_show_regs_callback(smp_processor_id(), regs); ++ + exit_idle(); + irq_enter(); + irq = __get_cpu_var(vector_irq)[vector]; +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_32.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c 2009-02-08 00:01:32.000000000 -0500 +@@ -25,6 +25,7 @@ + + #include + #include ++#include + + #include "mach_traps.h" + +@@ -42,7 +43,7 @@ static cpumask_t backtrace_mask = CPU_MA + atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */ + + unsigned int nmi_watchdog = NMI_DEFAULT; +-static unsigned int nmi_hz = HZ; ++static unsigned int nmi_hz = 1000; + + static DEFINE_PER_CPU(short, wd_enabled); + +@@ -93,7 +94,7 @@ static int __init check_nmi_watchdog(voi + for_each_possible_cpu(cpu) + prev_nmi_count[cpu] = per_cpu(irq_stat, cpu).__nmi_count; + local_irq_enable(); +- mdelay((20*1000)/nmi_hz); // wait 20 ticks ++ mdelay((100*1000)/nmi_hz); /* wait 100 ticks */ + + for_each_possible_cpu(cpu) { + #ifdef CONFIG_SMP +@@ -318,6 +319,46 @@ EXPORT_SYMBOL(touch_nmi_watchdog); + + extern void die_nmi(struct pt_regs *, const char *msg); + ++int nmi_show_regs[NR_CPUS]; ++ ++void nmi_show_all_regs(void) ++{ ++ int i; ++ ++ if (system_state == SYSTEM_BOOTING) ++ return; ++ ++ printk(KERN_WARNING "nmi_show_all_regs(): start on CPU#%d.\n", ++ raw_smp_processor_id()); ++ dump_stack(); ++ ++ for_each_online_cpu(i) ++ nmi_show_regs[i] = 1; ++ ++ smp_send_nmi_allbutself(); ++ ++ for_each_online_cpu(i) { ++ while (nmi_show_regs[i] == 1) ++ barrier(); ++ } ++} ++ ++static DEFINE_SPINLOCK(nmi_print_lock); ++ ++void irq_show_regs_callback(int cpu, struct pt_regs *regs) ++{ ++ if (!nmi_show_regs[cpu]) ++ return; ++ ++ nmi_show_regs[cpu] = 0; ++ spin_lock(&nmi_print_lock); ++ printk(KERN_WARNING "NMI show regs on CPU#%d:\n", cpu); ++ printk(KERN_WARNING "apic_timer_irqs: %d\n", ++ per_cpu(irq_stat, cpu).apic_timer_irqs); ++ show_regs(regs); ++ spin_unlock(&nmi_print_lock); ++} ++ + notrace __kprobes int + nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) + { +@@ -332,6 +373,8 @@ nmi_watchdog_tick(struct pt_regs * regs, + int cpu = smp_processor_id(); + int rc=0; + ++ __profile_tick(CPU_PROFILING, regs); ++ + /* check for other users first */ + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) + == NOTIFY_STOP) { +@@ -356,6 +399,9 @@ nmi_watchdog_tick(struct pt_regs * regs, + sum = per_cpu(irq_stat, cpu).apic_timer_irqs + + per_cpu(irq_stat, cpu).irq0_irqs; + ++ irq_show_regs_callback(cpu, regs); ++ ++ /* if the apic timer isn't firing, this cpu isn't doing much */ + /* if the none of the timers isn't firing, this cpu isn't doing much */ + if (!touched && last_irq_sums[cpu] == sum) { + /* +@@ -363,11 +409,30 @@ nmi_watchdog_tick(struct pt_regs * regs, + * wait a few IRQs (5 seconds) before doing the oops ... + */ + alert_counter[cpu]++; +- if (alert_counter[cpu] == 5*nmi_hz) +- /* +- * die_nmi will return ONLY if NOTIFY_STOP happens.. +- */ +- die_nmi(regs, "BUG: NMI Watchdog detected LOCKUP"); ++ if (alert_counter[cpu] && !(alert_counter[cpu] % (5*nmi_hz))) { ++ int i; ++ ++ spin_lock(&nmi_print_lock); ++ printk(KERN_WARNING "NMI watchdog detected lockup on " ++ "CPU#%d (%d/%d)\n", cpu, alert_counter[cpu], ++ 5*nmi_hz); ++ show_regs(regs); ++ spin_unlock(&nmi_print_lock); ++ ++ for_each_online_cpu(i) { ++ if (i == cpu) ++ continue; ++ nmi_show_regs[i] = 1; ++ while (nmi_show_regs[i] == 1) ++ cpu_relax(); ++ } ++ printk(KERN_WARNING "NMI watchdog running again ...\n"); ++ for_each_online_cpu(i) ++ alert_counter[i] = 0; ++ ++ ++ } ++ + } else { + last_irq_sums[cpu] = sum; + alert_counter[cpu] = 0; +@@ -465,5 +530,15 @@ void __trigger_all_cpu_backtrace(void) + } + } + ++void smp_send_nmi_allbutself(void) ++{ ++#ifdef CONFIG_SMP ++ cpumask_t mask = cpu_online_map; ++ cpu_clear(safe_smp_processor_id(), mask); ++ if (!cpus_empty(mask)) ++ send_IPI_mask(mask, NMI_VECTOR); ++#endif ++} ++ + EXPORT_SYMBOL(nmi_active); + EXPORT_SYMBOL(nmi_watchdog); +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_64.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c 2009-02-08 00:01:32.000000000 -0500 +@@ -20,11 +20,13 @@ + #include + #include + #include ++#include + + #include + #include + #include + #include ++#include + + int unknown_nmi_panic; + int nmi_watchdog_enabled; +@@ -42,7 +44,7 @@ atomic_t nmi_active = ATOMIC_INIT(0); / + int panic_on_timeout; + + unsigned int nmi_watchdog = NMI_DEFAULT; +-static unsigned int nmi_hz = HZ; ++static unsigned int nmi_hz = 1000; + + static DEFINE_PER_CPU(short, wd_enabled); + +@@ -301,7 +303,7 @@ void touch_nmi_watchdog(void) + unsigned cpu; + + /* +- * Tell other CPUs to reset their alert counters. We cannot ++ * Tell other CPUs to reset their alert counters. We cannot + * do it ourselves because the alert count increase is not + * atomic. + */ +@@ -314,6 +316,41 @@ void touch_nmi_watchdog(void) + touch_softlockup_watchdog(); + } + ++int nmi_show_regs[NR_CPUS]; ++ ++void nmi_show_all_regs(void) ++{ ++ int i; ++ ++ if (system_state == SYSTEM_BOOTING) ++ return; ++ ++ smp_send_nmi_allbutself(); ++ ++ for_each_online_cpu(i) ++ nmi_show_regs[i] = 1; ++ ++ for_each_online_cpu(i) { ++ while (nmi_show_regs[i] == 1) ++ barrier(); ++ } ++} ++ ++static DEFINE_SPINLOCK(nmi_print_lock); ++ ++void irq_show_regs_callback(int cpu, struct pt_regs *regs) ++{ ++ if (!nmi_show_regs[cpu]) ++ return; ++ ++ nmi_show_regs[cpu] = 0; ++ spin_lock(&nmi_print_lock); ++ printk(KERN_WARNING "NMI show regs on CPU#%d:\n", cpu); ++ printk(KERN_WARNING "apic_timer_irqs: %d\n", read_pda(apic_timer_irqs)); ++ show_regs(regs); ++ spin_unlock(&nmi_print_lock); ++} ++ + notrace int __kprobes + nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) + { +@@ -322,6 +359,9 @@ nmi_watchdog_tick(struct pt_regs * regs, + int cpu = smp_processor_id(); + int rc = 0; + ++ irq_show_regs_callback(cpu, regs); ++ __profile_tick(CPU_PROFILING, regs); ++ + /* check for other users first */ + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) + == NOTIFY_STOP) { +@@ -358,9 +398,20 @@ nmi_watchdog_tick(struct pt_regs * regs, + * wait a few IRQs (5 seconds) before doing the oops ... + */ + local_inc(&__get_cpu_var(alert_counter)); +- if (local_read(&__get_cpu_var(alert_counter)) == 5*nmi_hz) ++ if (local_read(&__get_cpu_var(alert_counter)) == 5*nmi_hz) { ++ int i; ++ ++ for_each_online_cpu(i) { ++ if (i == cpu) ++ continue; ++ nmi_show_regs[i] = 1; ++ while (nmi_show_regs[i] == 1) ++ cpu_relax(); ++ } ++ + die_nmi("NMI Watchdog detected LOCKUP on CPU %d\n", regs, + panic_on_timeout); ++ } + } else { + __get_cpu_var(last_irq_sum) = sum; + local_set(&__get_cpu_var(alert_counter), 0); +@@ -478,6 +529,13 @@ void __trigger_all_cpu_backtrace(void) + } + } + ++void smp_send_nmi_allbutself(void) ++{ ++#ifdef CONFIG_SMP ++ send_IPI_allbutself(NMI_VECTOR); ++#endif ++} ++ + EXPORT_SYMBOL(nmi_active); + EXPORT_SYMBOL(nmi_watchdog); + EXPORT_SYMBOL(touch_nmi_watchdog); +Index: linux-2.6.24.7-rt27/include/asm-x86/apic_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/apic_32.h 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/apic_32.h 2009-02-08 00:01:32.000000000 -0500 +@@ -118,6 +118,8 @@ extern int local_apic_timer_c2_ok; + + extern int local_apic_timer_disabled; + ++extern void smp_send_nmi_allbutself(void); ++ + #else /* !CONFIG_X86_LOCAL_APIC */ + static inline void lapic_shutdown(void) { } + #define local_apic_timer_c2_ok 1 +Index: linux-2.6.24.7-rt27/include/asm-x86/apic_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/apic_64.h 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/apic_64.h 2009-02-08 00:01:32.000000000 -0500 +@@ -87,6 +87,8 @@ extern void setup_APIC_extended_lvt(unsi + + extern int apic_is_clustered_box(void); + ++extern void smp_send_nmi_allbutself(void); ++ + #define K8_APIC_EXT_LVT_BASE 0x500 + #define K8_APIC_EXT_INT_MSG_FIX 0x0 + #define K8_APIC_EXT_INT_MSG_SMI 0x2 +Index: linux-2.6.24.7-rt27/include/linux/profile.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/profile.h 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/profile.h 2009-02-08 00:01:32.000000000 -0500 +@@ -23,6 +23,7 @@ struct notifier_block; + + /* init basic kernel profiler */ + void __init profile_init(void); ++void __profile_tick(int type, struct pt_regs *regs); + void profile_tick(int); + + /* +Index: linux-2.6.24.7-rt27/kernel/profile.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/profile.c 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/profile.c 2009-02-08 00:01:32.000000000 -0500 +@@ -412,16 +412,19 @@ void profile_hits(int type, void *__pc, + + EXPORT_SYMBOL_GPL(profile_hits); + +-void profile_tick(int type) ++void __profile_tick(int type, struct pt_regs *regs) + { +- struct pt_regs *regs = get_irq_regs(); +- + if (type == CPU_PROFILING && timer_hook) + timer_hook(regs); + if (!user_mode(regs) && cpu_isset(smp_processor_id(), prof_cpu_mask)) + profile_hit(type, (void *)profile_pc(regs)); + } + ++void profile_tick(int type) ++{ ++ return __profile_tick(type, get_irq_regs()); ++} ++ + #ifdef CONFIG_PROC_FS + #include + #include +Index: linux-2.6.24.7-rt27/kernel/time/tick-common.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-common.c 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-common.c 2009-02-08 00:01:32.000000000 -0500 +@@ -68,7 +68,6 @@ static void tick_periodic(int cpu) + } + + update_process_times(user_mode(get_irq_regs())); +- profile_tick(CPU_PROFILING); + } + + /* +Index: linux-2.6.24.7-rt27/kernel/time/tick-sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-sched.c 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-sched.c 2009-02-08 00:01:32.000000000 -0500 +@@ -440,7 +440,6 @@ static void tick_nohz_handler(struct clo + } + + update_process_times(user_mode(regs)); +- profile_tick(CPU_PROFILING); + + /* Do not restart, when we are in the idle loop */ + if (ts->tick_stopped) +@@ -554,7 +553,6 @@ static enum hrtimer_restart tick_sched_t + */ + spin_unlock(&base->lock); + update_process_times(user_mode(regs)); +- profile_tick(CPU_PROFILING); + spin_lock(&base->lock); + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0410-ppc-chpr-set-rtc-lock.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0410-ppc-chpr-set-rtc-lock.patch @@ -0,0 +1,30 @@ +--- + arch/powerpc/platforms/chrp/time.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/chrp/time.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/chrp/time.c 2009-02-08 00:02:28.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/chrp/time.c 2009-02-08 00:04:04.000000000 -0500 +@@ -27,7 +27,7 @@ + #include + #include + +-extern raw_spinlock_t rtc_lock; ++extern spinlock_t rtc_lock; + + static int nvram_as1 = NVRAM_AS1; + static int nvram_as0 = NVRAM_AS0; +@@ -83,7 +83,12 @@ int chrp_set_rtc_time(struct rtc_time *t + unsigned char save_control, save_freq_select; + struct rtc_time tm = *tmarg; + ++#if CONFIG_PREEMPT_RT ++ if (!spin_trylock(&rtc_lock)) ++ return -1; ++#else + spin_lock(&rtc_lock); ++#endif + + save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */ + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0203-fix-emac-locking-2.6.16.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0203-fix-emac-locking-2.6.16.patch @@ -0,0 +1,95 @@ + drivers/net/ibm_emac/ibm_emac_core.c | 11 +++++++++++ + drivers/net/ibm_emac/ibm_emac_core.h | 2 ++ + 2 files changed, 13 insertions(+) + +Index: linux-2.6.24.7-rt27/drivers/net/ibm_emac/ibm_emac_core.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/net/ibm_emac/ibm_emac_core.c 2009-02-08 00:00:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/net/ibm_emac/ibm_emac_core.c 2009-02-08 00:02:18.000000000 -0500 +@@ -1058,6 +1058,8 @@ static inline int emac_xmit_finish(struc + ++dev->stats.tx_packets; + dev->stats.tx_bytes += len; + ++ spin_unlock(&dev->tx_lock); ++ + return 0; + } + +@@ -1071,6 +1073,7 @@ static int emac_start_xmit(struct sk_buf + u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | + MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb); + ++ spin_lock(&dev->tx_lock); + slot = dev->tx_slot++; + if (dev->tx_slot == NUM_TX_BUFF) { + dev->tx_slot = 0; +@@ -1133,6 +1136,8 @@ static int emac_start_xmit_sg(struct sk_ + if (likely(!nr_frags && len <= MAL_MAX_TX_SIZE)) + return emac_start_xmit(skb, ndev); + ++ spin_lock(&dev->tx_lock); ++ + len -= skb->data_len; + + /* Note, this is only an *estimation*, we can still run out of empty +@@ -1201,6 +1206,7 @@ static int emac_start_xmit_sg(struct sk_ + stop_queue: + netif_stop_queue(ndev); + DBG2("%d: stopped TX queue" NL, dev->def->index); ++ spin_unlock(&dev->tx_lock); + return 1; + } + #else +@@ -1240,6 +1246,7 @@ static void emac_poll_tx(void *param) + DBG2("%d: poll_tx, %d %d" NL, dev->def->index, dev->tx_cnt, + dev->ack_slot); + ++ spin_lock(&dev->tx_lock); + if (dev->tx_cnt) { + u16 ctrl; + int slot = dev->ack_slot, n = 0; +@@ -1249,6 +1256,7 @@ static void emac_poll_tx(void *param) + struct sk_buff *skb = dev->tx_skb[slot]; + ++n; + ++ spin_unlock(&dev->tx_lock); + if (skb) { + dev_kfree_skb(skb); + dev->tx_skb[slot] = NULL; +@@ -1258,6 +1266,7 @@ static void emac_poll_tx(void *param) + if (unlikely(EMAC_IS_BAD_TX(ctrl))) + emac_parse_tx_error(dev, ctrl); + ++ spin_lock(&dev->tx_lock); + if (--dev->tx_cnt) + goto again; + } +@@ -1270,6 +1279,7 @@ static void emac_poll_tx(void *param) + DBG2("%d: tx %d pkts" NL, dev->def->index, n); + } + } ++ spin_unlock(&dev->tx_lock); + } + + static inline void emac_recycle_rx_skb(struct ocp_enet_private *dev, int slot, +@@ -1964,6 +1974,7 @@ static int __init emac_probe(struct ocp_ + dev->ndev = ndev; + dev->ldev = &ocpdev->dev; + dev->def = ocpdev->def; ++ spin_lock_init(&dev->tx_lock); + + /* Find MAL device we are connected to */ + maldev = +Index: linux-2.6.24.7-rt27/drivers/net/ibm_emac/ibm_emac_core.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/net/ibm_emac/ibm_emac_core.h 2009-02-08 00:00:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/net/ibm_emac/ibm_emac_core.h 2009-02-08 00:02:18.000000000 -0500 +@@ -193,6 +193,8 @@ struct ocp_enet_private { + struct ibm_emac_error_stats estats; + struct net_device_stats nstats; + ++ spinlock_t tx_lock; ++ + struct device* ldev; + }; + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0423-rt-balance-check-rq.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0423-rt-balance-check-rq.patch @@ -0,0 +1,22 @@ +--- + kernel/sched_rt.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:04:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:04:12.000000000 -0500 +@@ -840,9 +840,11 @@ static void prio_changed_rt(struct rq *r + pull_rt_task(rq); + /* + * If there's a higher priority task waiting to run +- * then reschedule. ++ * then reschedule. Note, the above pull_rt_task ++ * can release the rq lock and p could migrate. ++ * Only reschedule if p is still on the same runqueue. + */ +- if (p->prio > rq->rt.highest_prio) ++ if (p->prio > rq->rt.highest_prio && task_rq(p) == rq) + resched_task(p); + #else + /* For UP simply resched on drop of prio */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0290-2.6.21-rc6-lockless7-lockless-pagecache-lookups.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0290-2.6.21-rc6-lockless7-lockless-pagecache-lookups.patch @@ -0,0 +1,246 @@ +From: Nick Piggin +Subject: [patch 7/9] mm: lockless pagecache lookups + +Combine page_cache_get_speculative with lockless radix tree lookups to +introduce lockless page cache lookups (ie. no mapping->tree_lock on +the read-side). + +The only atomicity changes this introduces is that the gang pagecache +lookup functions now behave as if they are implemented with multiple +find_get_page calls, rather than operating on a snapshot of the pages. +In practice, this atomicity guarantee is not used anyway, and it is +difficult to see how it could be. Gang pagecache lookups are designed +to replace individual lookups, so these semantics are natural. + +Signed-off-by: Nick Piggin + +--- + mm/filemap.c | 173 ++++++++++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 131 insertions(+), 42 deletions(-) + +Index: linux-2.6.24.7-rt27/mm/filemap.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/filemap.c 2009-02-08 00:03:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/filemap.c 2009-02-08 00:03:05.000000000 -0500 +@@ -612,13 +612,33 @@ void fastcall __lock_page_nosync(struct + */ + struct page * find_get_page(struct address_space *mapping, pgoff_t offset) + { ++ void **pagep; + struct page *page; + +- read_lock_irq(&mapping->tree_lock); +- page = radix_tree_lookup(&mapping->page_tree, offset); +- if (page) +- page_cache_get(page); +- read_unlock_irq(&mapping->tree_lock); ++ rcu_read_lock(); ++repeat: ++ page = NULL; ++ pagep = radix_tree_lookup_slot(&mapping->page_tree, offset); ++ if (pagep) { ++ page = radix_tree_deref_slot(pagep); ++ if (unlikely(!page || page == RADIX_TREE_RETRY)) ++ goto repeat; ++ ++ if (!page_cache_get_speculative(page)) ++ goto repeat; ++ ++ /* ++ * Has the page moved? ++ * This is part of the lockless pagecache protocol. See ++ * include/linux/pagemap.h for details. ++ */ ++ if (unlikely(page != *pagep)) { ++ page_cache_release(page); ++ goto repeat; ++ } ++ } ++ rcu_read_unlock(); ++ + return page; + } + EXPORT_SYMBOL(find_get_page); +@@ -639,26 +659,16 @@ struct page *find_lock_page(struct addre + struct page *page; + + repeat: +- read_lock_irq(&mapping->tree_lock); +- page = radix_tree_lookup(&mapping->page_tree, offset); ++ page = find_get_page(mapping, offset); + if (page) { +- page_cache_get(page); +- if (TestSetPageLocked(page)) { +- read_unlock_irq(&mapping->tree_lock); +- __lock_page(page); +- +- /* Has the page been truncated while we slept? */ +- if (unlikely(page->mapping != mapping)) { +- unlock_page(page); +- page_cache_release(page); +- goto repeat; +- } +- VM_BUG_ON(page->index != offset); +- goto out; ++ lock_page(page); ++ /* Has the page been truncated? */ ++ if (unlikely(page->mapping != mapping)) { ++ unlock_page(page); ++ page_cache_release(page); ++ goto repeat; + } + } +- read_unlock_irq(&mapping->tree_lock); +-out: + return page; + } + EXPORT_SYMBOL(find_lock_page); +@@ -724,13 +734,39 @@ unsigned find_get_pages(struct address_s + { + unsigned int i; + unsigned int ret; ++ unsigned int nr_found; ++ ++ rcu_read_lock(); ++restart: ++ nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree, ++ (void ***)pages, start, nr_pages); ++ ret = 0; ++ for (i = 0; i < nr_found; i++) { ++ struct page *page; ++repeat: ++ page = radix_tree_deref_slot((void **)pages[i]); ++ if (unlikely(!page)) ++ continue; ++ /* ++ * this can only trigger if nr_found == 1, making livelock ++ * a non issue. ++ */ ++ if (unlikely(page == RADIX_TREE_RETRY)) ++ goto restart; ++ ++ if (!page_cache_get_speculative(page)) ++ goto repeat; ++ ++ /* Has the page moved? */ ++ if (unlikely(page != *((void **)pages[i]))) { ++ page_cache_release(page); ++ goto repeat; ++ } + +- read_lock_irq(&mapping->tree_lock); +- ret = radix_tree_gang_lookup(&mapping->page_tree, +- (void **)pages, start, nr_pages); +- for (i = 0; i < ret; i++) +- page_cache_get(pages[i]); +- read_unlock_irq(&mapping->tree_lock); ++ pages[ret] = page; ++ ret++; ++ } ++ rcu_read_unlock(); + return ret; + } + +@@ -751,19 +787,44 @@ unsigned find_get_pages_contig(struct ad + { + unsigned int i; + unsigned int ret; ++ unsigned int nr_found; ++ ++ rcu_read_lock(); ++restart: ++ nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree, ++ (void ***)pages, index, nr_pages); ++ ret = 0; ++ for (i = 0; i < nr_found; i++) { ++ struct page *page; ++repeat: ++ page = radix_tree_deref_slot((void **)pages[i]); ++ if (unlikely(!page)) ++ continue; ++ /* ++ * this can only trigger if nr_found == 1, making livelock ++ * a non issue. ++ */ ++ if (unlikely(page == RADIX_TREE_RETRY)) ++ goto restart; + +- read_lock_irq(&mapping->tree_lock); +- ret = radix_tree_gang_lookup(&mapping->page_tree, +- (void **)pages, index, nr_pages); +- for (i = 0; i < ret; i++) { +- if (pages[i]->mapping == NULL || pages[i]->index != index) ++ if (page->mapping == NULL || page->index != index) + break; + +- page_cache_get(pages[i]); ++ if (!page_cache_get_speculative(page)) ++ goto repeat; ++ ++ /* Has the page moved? */ ++ if (unlikely(page != *((void **)pages[i]))) { ++ page_cache_release(page); ++ goto repeat; ++ } ++ ++ pages[ret] = page; ++ ret++; + index++; + } +- read_unlock_irq(&mapping->tree_lock); +- return i; ++ rcu_read_unlock(); ++ return ret; + } + EXPORT_SYMBOL(find_get_pages_contig); + +@@ -783,15 +844,43 @@ unsigned find_get_pages_tag(struct addre + { + unsigned int i; + unsigned int ret; ++ unsigned int nr_found; ++ ++ rcu_read_lock(); ++restart: ++ nr_found = radix_tree_gang_lookup_tag_slot(&mapping->page_tree, ++ (void ***)pages, *index, nr_pages, tag); ++ ret = 0; ++ for (i = 0; i < nr_found; i++) { ++ struct page *page; ++repeat: ++ page = radix_tree_deref_slot((void **)pages[i]); ++ if (unlikely(!page)) ++ continue; ++ /* ++ * this can only trigger if nr_found == 1, making livelock ++ * a non issue. ++ */ ++ if (unlikely(page == RADIX_TREE_RETRY)) ++ goto restart; ++ ++ if (!page_cache_get_speculative(page)) ++ goto repeat; ++ ++ /* Has the page moved? */ ++ if (unlikely(page != *((void **)pages[i]))) { ++ page_cache_release(page); ++ goto repeat; ++ } ++ ++ pages[ret] = page; ++ ret++; ++ } ++ rcu_read_unlock(); + +- read_lock_irq(&mapping->tree_lock); +- ret = radix_tree_gang_lookup_tag(&mapping->page_tree, +- (void **)pages, *index, nr_pages, tag); +- for (i = 0; i < ret; i++) +- page_cache_get(pages[i]); + if (ret) + *index = pages[ret - 1]->index + 1; +- read_unlock_irq(&mapping->tree_lock); ++ + return ret; + } + EXPORT_SYMBOL(find_get_pages_tag); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0554-72d43d9bc9210d24d09202eaf219eac09e17b339.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0554-72d43d9bc9210d24d09202eaf219eac09e17b339.patch @@ -0,0 +1,36 @@ +commit 72d43d9bc9210d24d09202eaf219eac09e17b339 +Author: Thomas Gleixner +Date: Sat Sep 6 03:06:08 2008 +0200 + + x86: HPET: read back compare register before reading counter + + After fixing the u32 thinko I sill had occasional hickups on ATI chipsets + with small deltas. There seems to be a delay between writing the compare + register and the transffer to the internal register which triggers the + interrupt. Reading back the value makes sure, that it hit the internal + match register befor we compare against the counter value. + + Signed-off-by: Thomas Gleixner + +--- + arch/x86/kernel/hpet.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/hpet.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/hpet.c 2009-02-08 00:05:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/hpet.c 2009-02-08 00:05:13.000000000 -0500 +@@ -289,6 +289,13 @@ static int hpet_legacy_next_event(unsign + cnt += (u32) delta; + hpet_writel(cnt, HPET_T0_CMP); + ++ /* ++ * We need to read back the CMP register to make sure that ++ * what we wrote hit the chip before we compare it to the ++ * counter. ++ */ ++ WARN_ON((u32)hpet_readl(HPET_T0_CMP) != cnt); ++ + return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0365-disable-ist-x86_64.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0365-disable-ist-x86_64.patch @@ -0,0 +1,106 @@ +From ak@suse.de Thu Oct 4 11:22:57 2007 +Date: Tue, 2 Oct 2007 10:24:27 +0200 +From: Andi Kleen +To: linux-rt-users@vger.kernel.org +Cc: mingo@elte.hu, Thomas Gleixner +Subject: [PATCH] Disable IST stacks for debug/int 3/stack fault for + PREEMPT_RT + + +Normally the x86-64 trap handlers for debug/int 3/stack fault run +on a special interrupt stack to make them more robust +when dealing with kernel code. + +The PREEMPT_RT kernel can sleep in locks even while allocating +GFP_ATOMIC memory. When one of these trap handlers needs to send +real time signals for ptrace it allocates memory and could then +try to to schedule. But it is not allowed to schedule on a +IST stack. This can cause warnings and hangs. + +This patch disables the IST stacks for these handlers for PREEMPT_RT +kernel. Instead let them run on the normal process stack. + +The kernel only really needs the ISTs here to make kernel debuggers more +robust in case someone sets a break point somewhere where the stack is +invalid. But there are no kernel debuggers in the standard kernel +that do this. + +It also means kprobes cannot be set in situations with invalid stack; +but that sounds like a reasonable restriction. + +The stack fault change could minimally impact oops quality, but not very +much because stack faults are fairly rare. + +A better solution would be to use similar logic as the NMI "paranoid" +path: check if signal is for user space, if yes go back to entry.S, switch stack, +call sync_regs, then do the signal sending etc. + +But this patch is much simpler and should work too with minimal impact. + +Signed-off-by: Andi Kleen + +--- + arch/x86/kernel/setup64.c | 2 ++ + arch/x86/kernel/traps_64.c | 4 ++++ + include/asm-x86/page_64.h | 9 +++++++++ + 3 files changed, 15 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/setup64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/setup64.c 2009-02-07 23:59:47.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/setup64.c 2009-02-08 00:03:44.000000000 -0500 +@@ -248,7 +248,9 @@ void __cpuinit cpu_init (void) + for (v = 0; v < N_EXCEPTION_STACKS; v++) { + static const unsigned int order[N_EXCEPTION_STACKS] = { + [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, ++#if DEBUG_STACK > 0 + [DEBUG_STACK - 1] = DEBUG_STACK_ORDER ++#endif + }; + if (cpu) { + estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]); +Index: linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/traps_64.c 2009-02-08 00:03:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c 2009-02-08 00:03:44.000000000 -0500 +@@ -131,10 +131,14 @@ static unsigned long *in_exception_stack + unsigned *usedp, char **idp) + { + static char ids[][8] = { ++#if DEBUG_STACK > 0 + [DEBUG_STACK - 1] = "#DB", ++#endif + [NMI_STACK - 1] = "NMI", + [DOUBLEFAULT_STACK - 1] = "#DF", ++#if STACKFAULT_STACK > 0 + [STACKFAULT_STACK - 1] = "#SS", ++#endif + [MCE_STACK - 1] = "#MC", + #if DEBUG_STKSZ > EXCEPTION_STKSZ + [N_EXCEPTION_STACKS ... N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]" +Index: linux-2.6.24.7-rt27/include/asm-x86/page_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/page_64.h 2009-02-07 23:59:47.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/page_64.h 2009-02-08 00:03:44.000000000 -0500 +@@ -22,12 +22,21 @@ + #define IRQSTACK_ORDER 2 + #define IRQSTACKSIZE (PAGE_SIZE << IRQSTACK_ORDER) + ++#ifdef CONFIG_PREEMPT_RT ++#define STACKFAULT_STACK 0 ++#define DOUBLEFAULT_STACK 1 ++#define NMI_STACK 2 ++#define DEBUG_STACK 0 ++#define MCE_STACK 3 ++#define N_EXCEPTION_STACKS 3 /* hw limit: 7 */ ++#else + #define STACKFAULT_STACK 1 + #define DOUBLEFAULT_STACK 2 + #define NMI_STACK 3 + #define DEBUG_STACK 4 + #define MCE_STACK 5 + #define N_EXCEPTION_STACKS 5 /* hw limit: 7 */ ++#endif + + #define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1)) + #define LARGE_PAGE_SIZE (_AC(1,UL) << PMD_SHIFT) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0147-preempt-irqs-x86-64.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0147-preempt-irqs-x86-64.patch @@ -0,0 +1,31 @@ +--- + arch/x86/kernel/i8259_64.c | 1 + + arch/x86/kernel/time_64.c | 3 ++- + 2 files changed, 3 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/i8259_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/i8259_64.c 2009-02-08 00:00:14.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/i8259_64.c 2009-02-08 00:01:52.000000000 -0500 +@@ -397,6 +397,7 @@ device_initcall(i8259A_init_sysfs); + + static struct irqaction irq2 = { + .handler = no_action, ++ .flags = IRQF_NODELAY, + .mask = CPU_MASK_NONE, + .name = "cascade", + }; +Index: linux-2.6.24.7-rt27/arch/x86/kernel/time_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/time_64.c 2009-02-08 00:00:14.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/time_64.c 2009-02-08 00:01:52.000000000 -0500 +@@ -259,7 +259,8 @@ static unsigned int __init tsc_calibrate + + static struct irqaction irq0 = { + .handler = timer_event_interrupt, +- .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING, ++ .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING | ++ IRQF_NODELAY, + .mask = CPU_MASK_NONE, + .name = "timer" + }; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0416-ppc32-latency-compile-hack-fixes.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0416-ppc32-latency-compile-hack-fixes.patch @@ -0,0 +1,31 @@ +--- + arch/powerpc/kernel/setup_32.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/setup_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/setup_32.c 2009-02-08 00:01:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/setup_32.c 2009-02-08 00:04:08.000000000 -0500 +@@ -296,3 +296,22 @@ void __init setup_arch(char **cmdline_p) + + paging_init(); + } ++ ++#ifdef CONFIG_STACKTRACE ++#include ++void notrace save_stack_trace(struct stack_trace *trace) ++{ ++} ++#endif /* CONFIG_STACKTRACE */ ++ ++#ifdef CONFIG_EARLY_PRINTK ++void notrace early_printk(const char *fmt, ...) ++{ ++ BUG(); ++} ++#endif /* CONFIG_EARLY_PRINTK */ ++ ++#ifdef CONFIG_MCOUNT ++extern void _mcount(void); ++EXPORT_SYMBOL(_mcount); ++#endif /* CONFIG_MCOUNT */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0571-tglx-06-rtmutex-remove-useless-schedule-enforcement.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0571-tglx-06-rtmutex-remove-useless-schedule-enforcement.patch @@ -0,0 +1,39 @@ +From tglx@linutronix.de Fri Dec 19 16:40:02 2008 +Date: Fri, 19 Dec 2008 21:23:06 -0000 +From: Thomas Gleixner +To: LKML +Cc: Ingo Molnar , Steven Rostedt , Peter Zijlstra , Clark Williams , Gregory Haskins , Linux-rt +Subject: [patch 6/7] rtmutex: remove useless schedule enforcement + +For !mtx the call to schedule() is forced even if the waiter is +already woken (waiter.task == NULL). + +This makes no sense at all and is just waste. + +Signed-off-by: Thomas Gleixner +--- + kernel/rtmutex.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:05:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:05:23.000000000 -0500 +@@ -1402,7 +1402,7 @@ rt_read_slowlock(struct rw_mutex *rwm, i + + debug_rt_mutex_print_deadlock(&waiter); + +- if (!mtx || waiter.task) ++ if (waiter.task) + schedule_rt_mutex(mutex); + + spin_lock_irqsave(&mutex->wait_lock, flags); +@@ -1548,7 +1548,7 @@ rt_write_slowlock(struct rw_mutex *rwm, + + debug_rt_mutex_print_deadlock(&waiter); + +- if (!mtx || waiter.task) ++ if (waiter.task) + schedule_rt_mutex(mutex); + + spin_lock_irqsave(&mutex->wait_lock, flags); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0151-preempt-irqs-ppc.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0151-preempt-irqs-ppc.patch @@ -0,0 +1,133 @@ +--- + arch/powerpc/kernel/entry_32.S | 6 +++--- + arch/powerpc/kernel/irq.c | 2 -- + arch/powerpc/kernel/ppc_ksyms.c | 1 - + arch/powerpc/platforms/iseries/setup.c | 6 ++++-- + arch/powerpc/platforms/pseries/setup.c | 6 ++++-- + include/asm-powerpc/thread_info.h | 5 +++++ + 6 files changed, 16 insertions(+), 10 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_32.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/entry_32.S 2009-02-08 00:01:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_32.S 2009-02-08 00:01:54.000000000 -0500 +@@ -662,7 +662,7 @@ user_exc_return: /* r10 contains MSR_KE + /* Check current_thread_info()->flags */ + rlwinm r9,r1,0,0,(31-THREAD_SHIFT) + lwz r9,TI_FLAGS(r9) +- andi. r0,r9,(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NEED_RESCHED) ++ andi. r0,r9,(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED) + bne do_work + + restore_user: +@@ -897,7 +897,7 @@ global_dbcr0: + #endif /* !(CONFIG_4xx || CONFIG_BOOKE) */ + + do_work: /* r10 contains MSR_KERNEL here */ +- andi. r0,r9,_TIF_NEED_RESCHED ++ andi. r0,r9,(_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED) + beq do_user_signal + + do_resched: /* r10 contains MSR_KERNEL here */ +@@ -911,7 +911,7 @@ recheck: + MTMSRD(r10) /* disable interrupts */ + rlwinm r9,r1,0,0,(31-THREAD_SHIFT) + lwz r9,TI_FLAGS(r9) +- andi. r0,r9,_TIF_NEED_RESCHED ++ andi. r0,r9,(_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED) + bne- do_resched + andi. r0,r9,_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK + beq restore_user +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/irq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/irq.c 2009-02-08 00:01:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/irq.c 2009-02-08 00:01:54.000000000 -0500 +@@ -94,8 +94,6 @@ extern atomic_t ipi_sent; + #endif + + #ifdef CONFIG_PPC64 +-EXPORT_SYMBOL(irq_desc); +- + int distribute_irqs = 1; + + static inline notrace unsigned long get_hard_enabled(void) +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/ppc_ksyms.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/ppc_ksyms.c 2009-02-08 00:01:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/ppc_ksyms.c 2009-02-08 00:01:54.000000000 -0500 +@@ -167,7 +167,6 @@ EXPORT_SYMBOL(screen_info); + + #ifdef CONFIG_PPC32 + EXPORT_SYMBOL(timer_interrupt); +-EXPORT_SYMBOL(irq_desc); + EXPORT_SYMBOL(tb_ticks_per_jiffy); + EXPORT_SYMBOL(console_drivers); + EXPORT_SYMBOL(cacheable_memcpy); +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/iseries/setup.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/iseries/setup.c 2009-02-08 00:00:14.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/iseries/setup.c 2009-02-08 00:01:54.000000000 -0500 +@@ -564,12 +564,14 @@ static void iseries_shared_idle(void) + { + while (1) { + tick_nohz_stop_sched_tick(); +- while (!need_resched() && !hvlpevent_is_pending()) { ++ while (!need_resched() && !need_resched_delayed() ++ && !hvlpevent_is_pending()) { + local_irq_disable(); + ppc64_runlatch_off(); + + /* Recheck with irqs off */ +- if (!need_resched() && !hvlpevent_is_pending()) ++ if (!need_resched() && !need_resched_delayed() ++ && !hvlpevent_is_pending()) + yield_shared_processor(); + + HMT_medium(); +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/pseries/setup.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/pseries/setup.c 2009-02-08 00:00:14.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/pseries/setup.c 2009-02-08 00:01:54.000000000 -0500 +@@ -413,7 +413,8 @@ static void pseries_dedicated_idle_sleep + set_thread_flag(TIF_POLLING_NRFLAG); + + while (get_tb() < start_snooze) { +- if (need_resched() || cpu_is_offline(cpu)) ++ if (need_resched() || need_resched_delayed() || ++ cpu_is_offline(cpu)) + goto out; + ppc64_runlatch_off(); + HMT_low(); +@@ -424,7 +425,8 @@ static void pseries_dedicated_idle_sleep + clear_thread_flag(TIF_POLLING_NRFLAG); + smp_mb(); + local_irq_disable(); +- if (need_resched() || cpu_is_offline(cpu)) ++ if (need_resched() || need_resched_delayed() || ++ cpu_is_offline(cpu)) + goto out; + } + +Index: linux-2.6.24.7-rt27/include/asm-powerpc/thread_info.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-powerpc/thread_info.h 2009-02-08 00:00:14.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-powerpc/thread_info.h 2009-02-08 00:01:54.000000000 -0500 +@@ -124,6 +124,9 @@ static inline struct thread_info *curren + #define TIF_FREEZE 14 /* Freezing for suspend */ + #define TIF_RUNLATCH 15 /* Is the runlatch enabled? */ + #define TIF_ABI_PENDING 16 /* 32/64 bit switch needed */ ++#define TIF_NEED_RESCHED_DELAYED \ ++ 17 /* reschedule on return to userspace */ ++ + + /* as above, but as bit values */ + #define _TIF_SYSCALL_TRACE (1< +Date: Tue, 11 Dec 2007 10:02:38 +0100 +Subject: [PATCH] sched: optimize RT affinity + +The current code base assumes a relatively flat CPU/core topology and will +route RT tasks to any CPU fairly equally. In the real world, there are +various toplogies and affinities that govern where a task is best suited to +run with the smallest amount of overhead. NUMA and multi-core CPUs are +prime examples of topologies that can impact cache performance. + +Fortunately, linux is already structured to represent these topologies via +the sched_domains interface. So we change our RT router to consult a +combination of topology and affinity policy to best place tasks during +migration. + +Signed-off-by: Gregory Haskins +Signed-off-by: Steven Rostedt +Signed-off-by: Ingo Molnar + +--- + kernel/sched_rt.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 88 insertions(+), 12 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:00:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:00:57.000000000 -0500 +@@ -277,35 +277,111 @@ static struct task_struct *pick_next_hig + } + + static DEFINE_PER_CPU(cpumask_t, local_cpu_mask); ++static DEFINE_PER_CPU(cpumask_t, valid_cpu_mask); + +-static int find_lowest_rq(struct task_struct *task) ++static int find_lowest_cpus(struct task_struct *task, cpumask_t *lowest_mask) + { +- int cpu; +- cpumask_t *cpu_mask = &__get_cpu_var(local_cpu_mask); +- struct rq *lowest_rq = NULL; ++ int cpu; ++ cpumask_t *valid_mask = &__get_cpu_var(valid_cpu_mask); ++ int lowest_prio = -1; ++ int ret = 0; + +- cpus_and(*cpu_mask, cpu_online_map, task->cpus_allowed); ++ cpus_clear(*lowest_mask); ++ cpus_and(*valid_mask, cpu_online_map, task->cpus_allowed); + + /* + * Scan each rq for the lowest prio. + */ +- for_each_cpu_mask(cpu, *cpu_mask) { ++ for_each_cpu_mask(cpu, *valid_mask) { + struct rq *rq = cpu_rq(cpu); + + /* We look for lowest RT prio or non-rt CPU */ + if (rq->rt.highest_prio >= MAX_RT_PRIO) { +- lowest_rq = rq; +- break; ++ if (ret) ++ cpus_clear(*lowest_mask); ++ cpu_set(rq->cpu, *lowest_mask); ++ return 1; + } + + /* no locking for now */ +- if (rq->rt.highest_prio > task->prio && +- (!lowest_rq || rq->rt.highest_prio > lowest_rq->rt.highest_prio)) { +- lowest_rq = rq; ++ if ((rq->rt.highest_prio > task->prio) ++ && (rq->rt.highest_prio >= lowest_prio)) { ++ if (rq->rt.highest_prio > lowest_prio) { ++ /* new low - clear old data */ ++ lowest_prio = rq->rt.highest_prio; ++ cpus_clear(*lowest_mask); ++ } ++ cpu_set(rq->cpu, *lowest_mask); ++ ret = 1; ++ } ++ } ++ ++ return ret; ++} ++ ++static inline int pick_optimal_cpu(int this_cpu, cpumask_t *mask) ++{ ++ int first; ++ ++ /* "this_cpu" is cheaper to preempt than a remote processor */ ++ if ((this_cpu != -1) && cpu_isset(this_cpu, *mask)) ++ return this_cpu; ++ ++ first = first_cpu(*mask); ++ if (first != NR_CPUS) ++ return first; ++ ++ return -1; ++} ++ ++static int find_lowest_rq(struct task_struct *task) ++{ ++ struct sched_domain *sd; ++ cpumask_t *lowest_mask = &__get_cpu_var(local_cpu_mask); ++ int this_cpu = smp_processor_id(); ++ int cpu = task_cpu(task); ++ ++ if (!find_lowest_cpus(task, lowest_mask)) ++ return -1; ++ ++ /* ++ * At this point we have built a mask of cpus representing the ++ * lowest priority tasks in the system. Now we want to elect ++ * the best one based on our affinity and topology. ++ * ++ * We prioritize the last cpu that the task executed on since ++ * it is most likely cache-hot in that location. ++ */ ++ if (cpu_isset(cpu, *lowest_mask)) ++ return cpu; ++ ++ /* ++ * Otherwise, we consult the sched_domains span maps to figure ++ * out which cpu is logically closest to our hot cache data. ++ */ ++ if (this_cpu == cpu) ++ this_cpu = -1; /* Skip this_cpu opt if the same */ ++ ++ for_each_domain(cpu, sd) { ++ if (sd->flags & SD_WAKE_AFFINE) { ++ cpumask_t domain_mask; ++ int best_cpu; ++ ++ cpus_and(domain_mask, sd->span, *lowest_mask); ++ ++ best_cpu = pick_optimal_cpu(this_cpu, ++ &domain_mask); ++ if (best_cpu != -1) ++ return best_cpu; + } + } + +- return lowest_rq ? lowest_rq->cpu : -1; ++ /* ++ * And finally, if there were no matches within the domains ++ * just give the caller *something* to work with from the compatible ++ * locations. ++ */ ++ return pick_optimal_cpu(this_cpu, lowest_mask); + } + + /* Will lock the rq it finds */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0335-disable-lpptest-on-nonlinux.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0335-disable-lpptest-on-nonlinux.patch @@ -0,0 +1,40 @@ + +Sadly people keep wanting to build kernels on non-Linux hosts +(cygwin & solaris) and testlpp really doesn't like to build on +those. I have a separate patch to testlpp.c that fixes this, +but it really makes no sense to build the tool to run on your +cygwin host as it's meant to be run on Linux with the testlpp +module loaded. + +Even this patch isn't really the right solution b/c you really want +to cross-build the may be cross-building for another architecture from +Linux you want cross-compile, not host compile but there's no really easy +way to cross-compile a userland binary from the kernel build w/o some +makefile uglyiness AFAICT. + +Is there some sort of -rt userland package this could move to instead +of being in the kernel itself...? + +Signed-off-by: Deepak Saxena + +--- + scripts/Makefile | 3 +++ + 1 file changed, 3 insertions(+) + +Index: linux-2.6.24.7-rt27/scripts/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/scripts/Makefile 2009-02-08 00:01:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/scripts/Makefile 2009-02-08 00:03:29.000000000 -0500 +@@ -12,9 +12,12 @@ hostprogs-$(CONFIG_LOGO) += pnmt + hostprogs-$(CONFIG_VT) += conmakehash + hostprogs-$(CONFIG_PROM_CONSOLE) += conmakehash + hostprogs-$(CONFIG_IKCONFIG) += bin2c ++HOST_OS := $(shell uname) ++ifeq ($(HOST_OS),Linux) + ifdef CONFIG_LPPTEST + hostprogs-y += testlpp + endif ++endif + + always := $(hostprogs-y) $(hostprogs-m) + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0153-preempt-irqs-ppc-fix-b5.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0153-preempt-irqs-ppc-fix-b5.patch @@ -0,0 +1,42 @@ + + To fix the following boot time error by removing ack member added by +the rt patch. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Processor 1 found. +Brought up 2 CPUs +------------[ cut here ]------------ +kernel BUG at arch/powerpc/platforms/cell/interrupt.c:86! +pu 0x1: Vector: 700 (Program Check) at [c00000000fff3c80] + pc: c000000000033f9c: .iic_eoi+0x58/0x64 + lr: c00000000009add8: .handle_percpu_irq+0xd4/0xf4 + sp: c00000000fff3f00 + msr: 9000000000021032 + current = 0xc000000000fee040 + paca = 0xc000000000509e80 + pid = 0, comm = swapper +kernel BUG at arch/powerpc/platforms/cell/interrupt.c:86! +enter ? for help +[link register ] c00000000009add8 .handle_percpu_irq+0xd4/0xf4 +[c00000000fff3f00] c00000000009ada8 .handle_percpu_irq+0xa4/0xf4 (unreliable) +[c00000000fff3f90] c000000000023bb8 .call_handle_irq+0x1c/0x2c +[c000000000ff7950] c00000000000c910 .do_IRQ+0xf8/0x1b8 +[c000000000ff79f0] c000000000034f34 .cbe_system_reset_exception+0x74/0xb4 +[c000000000ff7a70] c000000000022610 .system_reset_exception+0x40/0xe0 +[c000000000ff7af0] c000000000003378 system_reset_common+0xf8/0x100 +--- + arch/powerpc/platforms/cell/interrupt.c | 1 - + 1 file changed, 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/cell/interrupt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/cell/interrupt.c 2009-02-08 00:01:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/cell/interrupt.c 2009-02-08 00:01:55.000000000 -0500 +@@ -90,7 +90,6 @@ static struct irq_chip iic_chip = { + .typename = " CELL-IIC ", + .mask = iic_mask, + .unmask = iic_unmask, +- .ack = iic_eoi, + .eoi = iic_eoi, + }; + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0127-rcu-fix-rcu-preempt.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0127-rcu-fix-rcu-preempt.patch @@ -0,0 +1,335 @@ +--- + kernel/rcupreempt.c | 271 ++++++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 203 insertions(+), 68 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rcupreempt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt.c 2009-02-08 00:01:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt.c 2009-02-08 00:01:43.000000000 -0500 +@@ -23,6 +23,10 @@ + * to Suparna Bhattacharya for pushing me completely away + * from atomic instructions on the read side. + * ++ * - Added handling of Dynamic Ticks ++ * Copyright 2007 - Paul E. Mckenney ++ * - Steven Rostedt ++ * + * Papers: http://www.rdrop.com/users/paulmck/RCU + * + * For detailed explanation of Read-Copy Update mechanism see - +@@ -368,51 +372,131 @@ static void __rcu_advance_callbacks(stru + } + } + +-/* +- * Get here when RCU is idle. Decide whether we need to +- * move out of idle state, and return non-zero if so. +- * "Straightforward" approach for the moment, might later +- * use callback-list lengths, grace-period duration, or +- * some such to determine when to exit idle state. +- * Might also need a pre-idle test that does not acquire +- * the lock, but let's get the simple case working first... +- */ ++#ifdef CONFIG_NO_HZ + +-static int +-rcu_try_flip_idle(void) ++DEFINE_PER_CPU(long, dynticks_progress_counter) = 1; ++static DEFINE_PER_CPU(long, rcu_dyntick_snapshot); ++static DEFINE_PER_CPU(int, rcu_update_flag); ++ ++/** ++ * rcu_irq_enter - Called from Hard irq handlers and NMI/SMI. ++ * ++ * If the CPU was idle with dynamic ticks active, this updates the ++ * dynticks_progress_counter to let the RCU handling know that the ++ * CPU is active. ++ */ ++void rcu_irq_enter(void) + { +- int cpu; ++ int cpu = smp_processor_id(); + +- RCU_TRACE_ME(rcupreempt_trace_try_flip_i1); +- if (!rcu_pending(smp_processor_id())) { +- RCU_TRACE_ME(rcupreempt_trace_try_flip_ie1); +- return 0; +- } ++ if (per_cpu(rcu_update_flag, cpu)) ++ per_cpu(rcu_update_flag, cpu)++; + + /* +- * Do the flip. ++ * Only update if we are coming from a stopped ticks mode ++ * (dynticks_progress_counter is even). + */ ++ if (!in_interrupt() && (per_cpu(dynticks_progress_counter, cpu) & 0x1) == 0) { ++ /* ++ * The following might seem like we could have a race ++ * with NMI/SMIs. But this really isn't a problem. ++ * Here we do a read/modify/write, and the race happens ++ * when an NMI/SMI comes in after the read and before ++ * the write. But NMI/SMIs will increment this counter ++ * twice before returning, so the zero bit will not ++ * be corrupted by the NMI/SMI which is the most important ++ * part. ++ * ++ * The only thing is that we would bring back the counter ++ * to a postion that it was in during the NMI/SMI. ++ * But the zero bit would be set, so the rest of the ++ * counter would again be ignored. ++ * ++ * On return from the IRQ, the counter may have the zero ++ * bit be 0 and the counter the same as the return from ++ * the NMI/SMI. If the state machine was so unlucky to ++ * see that, it still doesn't matter, since all ++ * RCU read-side critical sections on this CPU would ++ * have already completed. ++ */ ++ per_cpu(dynticks_progress_counter, cpu)++; ++ /* ++ * The following memory barrier ensures that any ++ * rcu_read_lock() primitives in the irq handler ++ * are seen by other CPUs to follow the above ++ * increment to dynticks_progress_counter. This is ++ * required in order for other CPUs to correctly ++ * determine when it is safe to advance the RCU ++ * grace-period state machine. ++ */ ++ smp_mb(); /* see above block comment. */ ++ /* ++ * Since we can't determine the dynamic tick mode from ++ * the dynticks_progress_counter after this routine, ++ * we use a second flag to acknowledge that we came ++ * from an idle state with ticks stopped. ++ */ ++ per_cpu(rcu_update_flag, cpu)++; ++ /* ++ * If we take an NMI/SMI now, they will also increment ++ * the rcu_update_flag, and will not update the ++ * dynticks_progress_counter on exit. That is for ++ * this IRQ to do. ++ */ ++ } ++} + +- RCU_TRACE_ME(rcupreempt_trace_try_flip_g1); +- rcu_ctrlblk.completed++; /* stands in for rcu_try_flip_g2 */ ++/** ++ * rcu_irq_exit - Called from exiting Hard irq context. ++ * ++ * If the CPU was idle with dynamic ticks active, update the ++ * dynticks_progress_counter to put let the RCU handling be ++ * aware that the CPU is going back to idle with no ticks. ++ */ ++void rcu_irq_exit(void) ++{ ++ int cpu = smp_processor_id(); + + /* +- * Need a memory barrier so that other CPUs see the new +- * counter value before they see the subsequent change of all +- * the rcu_flip_flag instances to rcu_flipped. ++ * rcu_update_flag is set if we interrupted the CPU ++ * when it was idle with ticks stopped. ++ * Once this occurs, we keep track of interrupt nesting ++ * because a NMI/SMI could also come in, and we still ++ * only want the IRQ that started the increment of the ++ * dynticks_progress_counter to be the one that modifies ++ * it on exit. + */ ++ if (per_cpu(rcu_update_flag, cpu)) { ++ if (--per_cpu(rcu_update_flag, cpu)) ++ return; + +- smp_mb(); /* see above block comment. */ ++ /* This must match the interrupt nesting */ ++ WARN_ON(in_interrupt()); + +- /* Now ask each CPU for acknowledgement of the flip. */ ++ /* ++ * If an NMI/SMI happens now we are still ++ * protected by the dynticks_progress_counter being odd. ++ */ + +- for_each_cpu_mask(cpu, rcu_cpu_online_map) { +- per_cpu(rcu_flip_flag, cpu) = rcu_flipped; +- per_cpu(rcu_dyntick_snapshot, cpu) = +- per_cpu(dynticks_progress_counter, cpu); ++ /* ++ * The following memory barrier ensures that any ++ * rcu_read_unlock() primitives in the irq handler ++ * are seen by other CPUs to preceed the following ++ * increment to dynticks_progress_counter. This ++ * is required in order for other CPUs to determine ++ * when it is safe to advance the RCU grace-period ++ * state machine. ++ */ ++ smp_mb(); /* see above block comment. */ ++ per_cpu(dynticks_progress_counter, cpu)++; ++ WARN_ON(per_cpu(dynticks_progress_counter, cpu) & 0x1); + } ++} + +- return 1; ++static void dyntick_save_progress_counter(int cpu) ++{ ++ per_cpu(rcu_dyntick_snapshot, cpu) = ++ per_cpu(dynticks_progress_counter, cpu); + } + + static inline int +@@ -451,6 +535,94 @@ rcu_try_flip_waitack_needed(int cpu) + return 1; + } + ++static inline int ++rcu_try_flip_waitmb_needed(int cpu) ++{ ++ long curr; ++ long snap; ++ ++ curr = per_cpu(dynticks_progress_counter, cpu); ++ snap = per_cpu(rcu_dyntick_snapshot, cpu); ++ smp_mb(); /* force ordering with cpu entering/leaving dynticks. */ ++ ++ /* ++ * If the CPU remained in dynticks mode for the entire time ++ * and didn't take any interrupts, NMIs, SMIs, or whatever, ++ * then it cannot have executed an RCU read-side critical section ++ * during that time, so there is no need for it to execute a ++ * memory barrier. ++ */ ++ ++ if ((curr == snap) && ((curr & 0x1) == 0)) ++ return 0; ++ ++ /* ++ * If the CPU either entered or exited an outermost interrupt, ++ * SMI, NMI, or whatever handler, then we know that it executed ++ * a memory barrier when doing so. So we don't need another one. ++ */ ++ if (curr != snap) ++ return 0; ++ ++ /* We need the CPU to execute a memory barrier. */ ++ ++ return 1; ++} ++ ++#else /* !CONFIG_NO_HZ */ ++ ++# define dyntick_save_progress_counter(cpu) do { } while (0) ++# define rcu_try_flip_waitack_needed(cpu) (1) ++# define rcu_try_flip_waitmb_needed(cpu) (1) ++ ++#endif /* CONFIG_NO_HZ */ ++ ++/* ++ * Get here when RCU is idle. Decide whether we need to ++ * move out of idle state, and return non-zero if so. ++ * "Straightforward" approach for the moment, might later ++ * use callback-list lengths, grace-period duration, or ++ * some such to determine when to exit idle state. ++ * Might also need a pre-idle test that does not acquire ++ * the lock, but let's get the simple case working first... ++ */ ++ ++static int ++rcu_try_flip_idle(void) ++{ ++ int cpu; ++ ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_i1); ++ if (!rcu_pending(smp_processor_id())) { ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_ie1); ++ return 0; ++ } ++ ++ /* ++ * Do the flip. ++ */ ++ ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_g1); ++ rcu_ctrlblk.completed++; /* stands in for rcu_try_flip_g2 */ ++ ++ /* ++ * Need a memory barrier so that other CPUs see the new ++ * counter value before they see the subsequent change of all ++ * the rcu_flip_flag instances to rcu_flipped. ++ */ ++ ++ smp_mb(); /* see above block comment. */ ++ ++ /* Now ask each CPU for acknowledgement of the flip. */ ++ ++ for_each_cpu_mask(cpu, rcu_cpu_online_map) { ++ per_cpu(rcu_flip_flag, cpu) = rcu_flipped; ++ dyntick_save_progress_counter(cpu); ++ } ++ ++ return 1; ++} ++ + /* + * Wait for CPUs to acknowledge the flip. + */ +@@ -506,48 +678,13 @@ rcu_try_flip_waitzero(void) + + for_each_cpu_mask(cpu, rcu_cpu_online_map) { + per_cpu(rcu_mb_flag, cpu) = rcu_mb_needed; +- per_cpu(rcu_dyntick_snapshot, cpu) = +- per_cpu(dynticks_progress_counter, cpu); ++ dyntick_save_progress_counter(cpu); + } + + RCU_TRACE_ME(rcupreempt_trace_try_flip_z2); + return 1; + } + +-static inline int +-rcu_try_flip_waitmb_needed(int cpu) +-{ +- long curr; +- long snap; +- +- curr = per_cpu(dynticks_progress_counter, cpu); +- snap = per_cpu(rcu_dyntick_snapshot, cpu); +- smp_mb(); /* force ordering with cpu entering/leaving dynticks. */ +- +- /* +- * If the CPU remained in dynticks mode for the entire time +- * and didn't take any interrupts, NMIs, SMIs, or whatever, +- * then it cannot have executed an RCU read-side critical section +- * during that time, so there is no need for it to execute a +- * memory barrier. +- */ +- +- if ((curr == snap) && ((curr & 0x1) == 0)) +- return 0; +- +- /* +- * If the CPU either entered or exited an outermost interrupt, +- * SMI, NMI, or whatever handler, then we know that it executed +- * a memory barrier when doing so. So we don't need another one. +- */ +- if (curr != snap) +- return 0; +- +- /* We need the CPU to execute a memory barrier. */ +- +- return 1; +-} +- + /* + * Wait for all CPUs to do their end-of-grace-period memory barrier. + * Return 0 once all CPUs have done so. +@@ -857,8 +994,6 @@ void __init rcu_init_rt(void) + } + } + +-static DEFINE_PER_CPU(long, rcu_dyntick_snapshot); +- + /* + * Deprecated, use synchronize_rcu() or synchronize_sched() instead. + */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0371-rcu-torture-preempt-update.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0371-rcu-torture-preempt-update.patch @@ -0,0 +1,164 @@ +--- + kernel/rcutorture.c | 69 ++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 54 insertions(+), 15 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rcutorture.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcutorture.c 2009-02-08 00:03:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcutorture.c 2009-02-08 00:03:47.000000000 -0500 +@@ -52,6 +52,7 @@ MODULE_AUTHOR("Paul E. McKenney rtort_rcu, rcu_torture_cb); + } + +-static struct task_struct *rcu_preeempt_task; + static unsigned long rcu_torture_preempt_errors; + + static int rcu_torture_preempt(void *arg) +@@ -270,7 +272,7 @@ static int rcu_torture_preempt(void *arg + time_t gcstart; + struct sched_param sp; + +- sp.sched_priority = MAX_RT_PRIO - 1; ++ sp.sched_priority = 1; + err = sched_setscheduler(current, SCHED_RR, &sp); + if (err != 0) + printk(KERN_ALERT "rcu_torture_preempt() priority err: %d\n", +@@ -293,24 +295,43 @@ static int rcu_torture_preempt(void *arg + static long rcu_preempt_start(void) + { + long retval = 0; ++ int i; + +- rcu_preeempt_task = kthread_run(rcu_torture_preempt, NULL, +- "rcu_torture_preempt"); +- if (IS_ERR(rcu_preeempt_task)) { +- VERBOSE_PRINTK_ERRSTRING("Failed to create preempter"); +- retval = PTR_ERR(rcu_preeempt_task); +- rcu_preeempt_task = NULL; ++ rcu_preempt_tasks = kzalloc(nrealpreempthogs * sizeof(rcu_preempt_tasks[0]), ++ GFP_KERNEL); ++ if (rcu_preempt_tasks == NULL) { ++ VERBOSE_PRINTK_ERRSTRING("out of memory"); ++ retval = -ENOMEM; ++ goto out; + } ++ ++ for (i=0; i < nrealpreempthogs; i++) { ++ rcu_preempt_tasks[i] = kthread_run(rcu_torture_preempt, NULL, ++ "rcu_torture_preempt"); ++ if (IS_ERR(rcu_preempt_tasks[i])) { ++ VERBOSE_PRINTK_ERRSTRING("Failed to create preempter"); ++ retval = PTR_ERR(rcu_preempt_tasks[i]); ++ rcu_preempt_tasks[i] = NULL; ++ break; ++ } ++ } ++ out: + return retval; + } + + static void rcu_preempt_end(void) + { +- if (rcu_preeempt_task != NULL) { +- VERBOSE_PRINTK_STRING("Stopping rcu_preempt task"); +- kthread_stop(rcu_preeempt_task); ++ int i; ++ if (rcu_preempt_tasks) { ++ for (i=0; i < nrealpreempthogs; i++) { ++ if (rcu_preempt_tasks[i] != NULL) { ++ VERBOSE_PRINTK_STRING("Stopping rcu_preempt task"); ++ kthread_stop(rcu_preempt_tasks[i]); ++ } ++ rcu_preempt_tasks[i] = NULL; ++ } ++ kfree(rcu_preempt_tasks); + } +- rcu_preeempt_task = NULL; + } + + static int rcu_preempt_stats(char *page) +@@ -605,10 +626,20 @@ rcu_torture_writer(void *arg) + static int + rcu_torture_fakewriter(void *arg) + { ++ struct sched_param sp; ++ long id = (long) arg; ++ int err; + DEFINE_RCU_RANDOM(rand); + + VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started"); +- set_user_nice(current, 19); ++ /* ++ * Set up at a higher prio than the readers. ++ */ ++ sp.sched_priority = 1 + id; ++ err = sched_setscheduler(current, SCHED_RR, &sp); ++ if (err != 0) ++ printk(KERN_ALERT "rcu_torture_writer() priority err: %d\n", ++ err); + + do { + schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); +@@ -841,9 +872,11 @@ rcu_torture_print_module_parms(char *tag + { + printk(KERN_ALERT "%s" TORTURE_FLAG + "--- %s: nreaders=%d nfakewriters=%d " ++ "npreempthogs=%d " + "stat_interval=%d verbose=%d test_no_idle_hz=%d " + "shuffle_interval=%d preempt_torture=%d\n", + torture_type, tag, nrealreaders, nfakewriters, ++ nrealpreempthogs, + stat_interval, verbose, test_no_idle_hz, shuffle_interval, + preempt_torture); + } +@@ -917,7 +950,7 @@ rcu_torture_cleanup(void) + static int __init + rcu_torture_init(void) + { +- int i; ++ long i; + int cpu; + int firsterr = 0; + static struct rcu_torture_ops *torture_ops[] = +@@ -945,6 +978,12 @@ rcu_torture_init(void) + rcu_torture_print_module_parms("Start of test"); + fullstop = 0; + ++ if (npreempthogs >= 0) ++ nrealpreempthogs = npreempthogs; ++ else ++ nrealpreempthogs = num_online_cpus() == 1 ? 1 : ++ num_online_cpus() - 1; ++ + /* Set up the freelist. */ + + INIT_LIST_HEAD(&rcu_torture_freelist); +@@ -992,7 +1031,7 @@ rcu_torture_init(void) + } + for (i = 0; i < nfakewriters; i++) { + VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task"); +- fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL, ++ fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, (void*)i, + "rcu_torture_fakewriter"); + if (IS_ERR(fakewriter_tasks[i])) { + firsterr = PTR_ERR(fakewriter_tasks[i]); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0562-rwlock-fix-owners-race.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0562-rwlock-fix-owners-race.patch @@ -0,0 +1,62 @@ +From: Steven Rostedt +Subject: rwlock: fix modification of owners race + +Thomas Gleixner has been hitting a bug where everything would freeze. +It was caused by the race between the owner of a reader lock releasing +it and before it updates its owner count. The pending owner tries to +take the lock, but sees the owners count is too high and fails. This causes +the lock to be unowned, with the owner sleeping. + +The fix is to only check the owners count if the lock happens to be held. +Do not check it if the lock is pending. + +Signed-off-by: Steven Rostedt +--- + kernel/rtmutex.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:05:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:05:19.000000000 -0500 +@@ -1175,7 +1175,6 @@ static int try_to_take_rw_read(struct rw + struct rt_mutex_waiter *waiter; + struct reader_lock_struct *rls; + struct task_struct *mtxowner; +- int owners; + int reader_count, i; + int incr = 1; + +@@ -1215,13 +1214,6 @@ static int try_to_take_rw_read(struct rw + goto taken; + } + +- owners = atomic_read(&rwm->owners); +- rt_rwlock_update_owner(rwm, rt_rwlock_owner(rwm)); +- +- /* Check for rwlock limits */ +- if (rt_rwlock_limit && owners >= rt_rwlock_limit) +- return 0; +- + if (mtxowner && mtxowner != RT_RW_READER) { + int mode = mtx ? STEAL_NORMAL : STEAL_LATERAL; + +@@ -1261,6 +1253,18 @@ static int try_to_take_rw_read(struct rw + } + /* Readers never own the mutex */ + rt_mutex_set_owner(mutex, RT_RW_READER, 0); ++ } else { ++ int owners; ++ /* ++ * Only check the owner condition when the lock is ++ * held for readers. ++ */ ++ owners = atomic_read(&rwm->owners); ++ rt_rwlock_update_owner(rwm, rt_rwlock_owner(rwm)); ++ ++ /* Check for rwlock limits */ ++ if (rt_rwlock_limit && owners >= rt_rwlock_limit) ++ return 0; + } + + /* RT_RW_READER forces slow paths */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0368-rcu-preempt-boost-sdr.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0368-rcu-preempt-boost-sdr.patch @@ -0,0 +1,884 @@ +--- + include/linux/init_task.h | 13 + + include/linux/rcupdate.h | 44 +++ + include/linux/rcupreempt.h | 20 + + include/linux/sched.h | 22 + + kernel/Kconfig.preempt | 13 + + kernel/Makefile | 1 + kernel/fork.c | 8 + kernel/rcupdate.c | 3 + kernel/rcupreempt-boost.c | 549 +++++++++++++++++++++++++++++++++++++++++++++ + kernel/rcupreempt.c | 2 + kernel/rcupreempt_trace.c | 7 + kernel/rtmutex.c | 7 + kernel/sched.c | 2 + 13 files changed, 687 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/init_task.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/init_task.h 2009-02-08 00:02:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/init_task.h 2009-02-08 00:03:45.000000000 -0500 +@@ -88,6 +88,17 @@ extern struct nsproxy init_nsproxy; + .signalfd_wqh = __WAIT_QUEUE_HEAD_INITIALIZER(sighand.signalfd_wqh), \ + } + ++#ifdef CONFIG_PREEMPT_RCU_BOOST ++#define INIT_RCU_BOOST_PRIO .rcu_prio = MAX_PRIO, ++#define INIT_PREEMPT_RCU_BOOST(tsk) \ ++ .rcub_rbdp = NULL, \ ++ .rcub_state = RCU_BOOST_IDLE, \ ++ .rcub_entry = LIST_HEAD_INIT(tsk.rcub_entry), ++#else /* #ifdef CONFIG_PREEMPT_RCU_BOOST */ ++#define INIT_RCU_BOOST_PRIO ++#define INIT_PREEMPT_RCU_BOOST(tsk) ++#endif /* #else #ifdef CONFIG_PREEMPT_RCU_BOOST */ ++ + extern struct group_info init_groups; + + #define INIT_STRUCT_PID { \ +@@ -130,6 +141,7 @@ extern struct group_info init_groups; + .static_prio = MAX_PRIO-20, \ + .normal_prio = MAX_PRIO-20, \ + .policy = SCHED_NORMAL, \ ++ INIT_RCU_BOOST_PRIO \ + .cpus_allowed = CPU_MASK_ALL, \ + .nr_cpus_allowed = NR_CPUS, \ + .mm = NULL, \ +@@ -176,6 +188,7 @@ extern struct group_info init_groups; + .dirties = INIT_PROP_LOCAL_SINGLE(dirties), \ + INIT_TRACE_IRQFLAGS \ + INIT_LOCKDEP \ ++ INIT_PREEMPT_RCU_BOOST(tsk) \ + } + + +Index: linux-2.6.24.7-rt27/include/linux/rcupdate.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupdate.h 2009-02-08 00:03:41.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupdate.h 2009-02-08 00:03:45.000000000 -0500 +@@ -275,5 +275,49 @@ static inline void rcu_qsctr_inc(int cpu + per_cpu(rcu_data_passed_quiesc, cpu) = 1; + } + ++struct dentry; ++ ++#ifdef CONFIG_PREEMPT_RCU_BOOST ++extern void init_rcu_boost_late(void); ++extern void rcu_boost_readers(void); ++extern void rcu_unboost_readers(void); ++extern void __rcu_preempt_boost(void); ++#ifdef CONFIG_RCU_TRACE ++extern int rcu_trace_boost_create(struct dentry *rcudir); ++extern void rcu_trace_boost_destroy(void); ++#endif /* CONFIG_RCU_TRACE */ ++#define rcu_preempt_boost() /* cpp to avoid #include hell. */ \ ++ do { \ ++ if (unlikely(current->rcu_read_lock_nesting > 0)) \ ++ __rcu_preempt_boost(); \ ++ } while (0) ++extern void __rcu_preempt_unboost(void); ++#else /* #ifdef CONFIG_PREEMPT_RCU_BOOST */ ++static inline void init_rcu_boost_late(void) ++{ ++} ++static inline void rcu_preempt_boost(void) ++{ ++} ++static inline void __rcu_preempt_unboost(void) ++{ ++} ++static inline void rcu_boost_readers(void) ++{ ++} ++static inline void rcu_unboost_readers(void) ++{ ++} ++#ifdef CONFIG_RCU_TRACE ++static inline int rcu_trace_boost_create(struct dentry *rcudir) ++{ ++ return 0; ++} ++static inline void rcu_trace_boost_destroy(void) ++{ ++} ++#endif /* CONFIG_RCU_TRACE */ ++#endif /* #else #ifdef CONFIG_PREEMPT_RCU_BOOST */ ++ + #endif /* __KERNEL__ */ + #endif /* __LINUX_RCUPDATE_H */ +Index: linux-2.6.24.7-rt27/include/linux/rcupreempt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupreempt.h 2009-02-08 00:03:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupreempt.h 2009-02-08 00:03:45.000000000 -0500 +@@ -42,6 +42,26 @@ + #include + #include + ++#ifdef CONFIG_PREEMPT_RCU_BOOST ++/* ++ * Task state with respect to being RCU-boosted. This state is changed ++ * by the task itself in response to the following three events: ++ * 1. Preemption (or block on lock) while in RCU read-side critical section. ++ * 2. Outermost rcu_read_unlock() for blocked RCU read-side critical section. ++ * ++ * The RCU-boost task also updates the state when boosting priority. ++ */ ++enum rcu_boost_state { ++ RCU_BOOST_IDLE = 0, /* Not yet blocked if in RCU read-side. */ ++ RCU_BOOST_BLOCKED = 1, /* Blocked from RCU read-side. */ ++ RCU_BOOSTED = 2, /* Boosting complete. */ ++ RCU_BOOST_INVALID = 3, /* For bogus state sightings. */ ++}; ++ ++#define N_RCU_BOOST_STATE (RCU_BOOST_INVALID + 1) ++ ++#endif /* #ifdef CONFIG_PREEMPT_RCU_BOOST */ ++ + /* + * Someone might want to pass call_rcu_bh as a function pointer. + * So this needs to just be a rename and not a macro function. +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:03:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:03:45.000000000 -0500 +@@ -585,6 +585,19 @@ struct signal_struct { + #define SIGNAL_STOP_CONTINUED 0x00000004 /* SIGCONT since WCONTINUED reap */ + #define SIGNAL_GROUP_EXIT 0x00000008 /* group exit in progress */ + ++#ifdef CONFIG_PREEMPT_RCU_BOOST ++#define set_rcu_prio(p, prio) /* cpp to avoid #include hell */ \ ++ do { \ ++ (p)->rcu_prio = (prio); \ ++ } while (0) ++#define get_rcu_prio(p) (p)->rcu_prio /* cpp to avoid #include hell */ ++#else /* #ifdef CONFIG_PREEMPT_RCU_BOOST */ ++static inline void set_rcu_prio(struct task_struct *p, int prio) ++{ ++} ++#define get_rcu_prio(p) (MAX_PRIO) /* cpp to use MAX_PRIO before it's defined */ ++#endif /* #else #ifdef CONFIG_PREEMPT_RCU_BOOST */ ++ + /* + * Some day this will be a full-fledged user tracking system.. + */ +@@ -1008,6 +1021,9 @@ struct task_struct { + #endif + + int prio, static_prio, normal_prio; ++#ifdef CONFIG_PREEMPT_RCU_BOOST ++ int rcu_prio; ++#endif + struct list_head run_list; + const struct sched_class *sched_class; + struct sched_entity se; +@@ -1045,6 +1061,12 @@ struct task_struct { + #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) + struct sched_info sched_info; + #endif ++#ifdef CONFIG_PREEMPT_RCU_BOOST ++ struct rcu_boost_dat *rcub_rbdp; ++ enum rcu_boost_state rcub_state; ++ struct list_head rcub_entry; ++ unsigned long rcu_preempt_counter; ++#endif + + struct list_head tasks; + /* +Index: linux-2.6.24.7-rt27/kernel/Kconfig.preempt +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/Kconfig.preempt 2009-02-08 00:02:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/Kconfig.preempt 2009-02-08 00:03:45.000000000 -0500 +@@ -157,6 +157,19 @@ config PREEMPT_RCU + + endchoice + ++config PREEMPT_RCU_BOOST ++ bool "Enable priority boosting of RCU read-side critical sections" ++ depends on PREEMPT_RCU ++ help ++ This option permits priority boosting of RCU read-side critical ++ sections tat have been preempted and a RT process is waiting ++ on a synchronize_rcu. ++ ++ An RCU thread is also created that periodically wakes up and ++ performs a synchronize_rcu to make sure that all readers eventually ++ do complete to prevent an indefinite delay of grace periods and ++ possible OOM problems. ++ + config RCU_TRACE + bool "Enable tracing for RCU - currently stats in debugfs" + select DEBUG_FS +Index: linux-2.6.24.7-rt27/kernel/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/Makefile 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/Makefile 2009-02-08 00:03:45.000000000 -0500 +@@ -70,6 +70,7 @@ obj-$(CONFIG_SECCOMP) += seccomp.o + obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o + obj-$(CONFIG_CLASSIC_RCU) += rcuclassic.o + obj-$(CONFIG_PREEMPT_RCU) += rcuclassic.o rcupreempt.o ++obj-$(CONFIG_PREEMPT_RCU_BOOST) += rcupreempt-boost.o + ifeq ($(CONFIG_PREEMPT_RCU),y) + obj-$(CONFIG_RCU_TRACE) += rcupreempt_trace.o + endif +Index: linux-2.6.24.7-rt27/kernel/fork.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/fork.c 2009-02-08 00:03:43.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/fork.c 2009-02-08 00:03:45.000000000 -0500 +@@ -1089,7 +1089,13 @@ static struct task_struct *copy_process( + #ifdef CONFIG_PREEMPT_RCU + p->rcu_read_lock_nesting = 0; + p->rcu_flipctr_idx = 0; +-#endif /* #ifdef CONFIG_PREEMPT_RCU */ ++#ifdef CONFIG_PREEMPT_RCU_BOOST ++ p->rcu_prio = MAX_PRIO; ++ p->rcub_rbdp = NULL; ++ p->rcub_state = RCU_BOOST_IDLE; ++ INIT_LIST_HEAD(&p->rcub_entry); ++#endif ++#endif /* CONFIG_PREEMPT_RCU */ + p->vfork_done = NULL; + spin_lock_init(&p->alloc_lock); + +Index: linux-2.6.24.7-rt27/kernel/rcupdate.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupdate.c 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupdate.c 2009-02-08 00:03:45.000000000 -0500 +@@ -91,8 +91,11 @@ void synchronize_rcu(void) + /* Will wake me after RCU finished */ + call_rcu(&rcu.head, wakeme_after_rcu); + ++ rcu_boost_readers(); ++ + /* Wait for it */ + wait_for_completion(&rcu.completion); ++ rcu_unboost_readers(); + } + EXPORT_SYMBOL_GPL(synchronize_rcu); + +Index: linux-2.6.24.7-rt27/kernel/rcupreempt-boost.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt-boost.c 2009-02-08 00:03:45.000000000 -0500 +@@ -0,0 +1,549 @@ ++/* ++ * Read-Copy Update preempt priority boosting ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright Red Hat Inc, 2007 ++ * ++ * Authors: Steven Rostedt ++ * ++ * Based on the original work by Paul McKenney . ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++DEFINE_RAW_SPINLOCK(rcu_boost_wake_lock); ++static int rcu_boost_prio = MAX_PRIO; /* Prio to set preempted RCU readers */ ++static long rcu_boost_counter; /* used to keep track of who boosted */ ++static int rcu_preempt_thread_secs = 3; /* Seconds between waking rcupreemptd thread */ ++ ++struct rcu_boost_dat { ++ raw_spinlock_t rbs_lock; /* Sync changes to this struct */ ++ int rbs_prio; /* CPU copy of rcu_boost_prio */ ++ struct list_head rbs_toboost; /* Preempted RCU readers */ ++ struct list_head rbs_boosted; /* RCU readers that have been boosted */ ++#ifdef CONFIG_RCU_TRACE ++ /* The rest are for statistics */ ++ unsigned long rbs_stat_task_boost_called; ++ unsigned long rbs_stat_task_boosted; ++ unsigned long rbs_stat_boost_called; ++ unsigned long rbs_stat_try_boost; ++ unsigned long rbs_stat_boosted; ++ unsigned long rbs_stat_unboost_called; ++ unsigned long rbs_stat_unboosted; ++ unsigned long rbs_stat_try_boost_readers; ++ unsigned long rbs_stat_boost_readers; ++ unsigned long rbs_stat_try_unboost_readers; ++ unsigned long rbs_stat_unboost_readers; ++ unsigned long rbs_stat_over_taken; ++#endif /* CONFIG_RCU_TRACE */ ++}; ++ ++static DEFINE_PER_CPU(struct rcu_boost_dat, rcu_boost_data); ++#define RCU_BOOST_ME &__get_cpu_var(rcu_boost_data) ++ ++#ifdef CONFIG_RCU_TRACE ++ ++#define RCUPREEMPT_BOOST_TRACE_BUF_SIZE 4096 ++static char rcupreempt_boost_trace_buf[RCUPREEMPT_BOOST_TRACE_BUF_SIZE]; ++ ++static ssize_t rcuboost_read(struct file *filp, char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ static DEFINE_MUTEX(mutex); ++ int cnt = 0; ++ int cpu; ++ struct rcu_boost_dat *rbd; ++ ssize_t bcount; ++ unsigned long task_boost_called = 0; ++ unsigned long task_boosted = 0; ++ unsigned long boost_called = 0; ++ unsigned long try_boost = 0; ++ unsigned long boosted = 0; ++ unsigned long unboost_called = 0; ++ unsigned long unboosted = 0; ++ unsigned long try_boost_readers = 0; ++ unsigned long boost_readers = 0; ++ unsigned long try_unboost_readers = 0; ++ unsigned long unboost_readers = 0; ++ unsigned long over_taken = 0; ++ ++ mutex_lock(&mutex); ++ ++ for_each_online_cpu(cpu) { ++ rbd = &per_cpu(rcu_boost_data, cpu); ++ ++ task_boost_called += rbd->rbs_stat_task_boost_called; ++ task_boosted += rbd->rbs_stat_task_boosted; ++ boost_called += rbd->rbs_stat_boost_called; ++ try_boost += rbd->rbs_stat_try_boost; ++ boosted += rbd->rbs_stat_boosted; ++ unboost_called += rbd->rbs_stat_unboost_called; ++ unboosted += rbd->rbs_stat_unboosted; ++ try_boost_readers += rbd->rbs_stat_try_boost_readers; ++ boost_readers += rbd->rbs_stat_boost_readers; ++ try_unboost_readers += rbd->rbs_stat_try_boost_readers; ++ unboost_readers += rbd->rbs_stat_boost_readers; ++ over_taken += rbd->rbs_stat_over_taken; ++ } ++ ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "task_boost_called = %ld\n", ++ task_boost_called); ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "task_boosted = %ld\n", ++ task_boosted); ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "boost_called = %ld\n", ++ boost_called); ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "try_boost = %ld\n", ++ try_boost); ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "boosted = %ld\n", ++ boosted); ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "unboost_called = %ld\n", ++ unboost_called); ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "unboosted = %ld\n", ++ unboosted); ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "try_boost_readers = %ld\n", ++ try_boost_readers); ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "boost_readers = %ld\n", ++ boost_readers); ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "try_unboost_readers = %ld\n", ++ try_unboost_readers); ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "unboost_readers = %ld\n", ++ unboost_readers); ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "over_taken = %ld\n", ++ over_taken); ++ cnt += snprintf(&rcupreempt_boost_trace_buf[cnt], ++ RCUPREEMPT_BOOST_TRACE_BUF_SIZE - cnt, ++ "rcu_boost_prio = %d\n", ++ rcu_boost_prio); ++ bcount = simple_read_from_buffer(buffer, count, ppos, ++ rcupreempt_boost_trace_buf, strlen(rcupreempt_boost_trace_buf)); ++ mutex_unlock(&mutex); ++ ++ return bcount; ++} ++ ++static struct file_operations rcuboost_fops = { ++ .read = rcuboost_read, ++}; ++ ++static struct dentry *rcuboostdir; ++int rcu_trace_boost_create(struct dentry *rcudir) ++{ ++ rcuboostdir = debugfs_create_file("rcuboost", 0444, rcudir, ++ NULL, &rcuboost_fops); ++ if (!rcuboostdir) ++ return 1; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(rcu_trace_boost_create); ++ ++void rcu_trace_boost_destroy(void) ++{ ++ if (rcuboostdir) ++ debugfs_remove(rcuboostdir); ++ rcuboostdir = NULL; ++} ++EXPORT_SYMBOL_GPL(rcu_trace_boost_destroy); ++ ++#define RCU_BOOST_TRACE_FUNC_DECL(type) \ ++ static void rcu_trace_boost_##type(struct rcu_boost_dat *rbd) \ ++ { \ ++ rbd->rbs_stat_##type++; \ ++ } ++RCU_BOOST_TRACE_FUNC_DECL(task_boost_called) ++RCU_BOOST_TRACE_FUNC_DECL(task_boosted) ++RCU_BOOST_TRACE_FUNC_DECL(boost_called) ++RCU_BOOST_TRACE_FUNC_DECL(try_boost) ++RCU_BOOST_TRACE_FUNC_DECL(boosted) ++RCU_BOOST_TRACE_FUNC_DECL(unboost_called) ++RCU_BOOST_TRACE_FUNC_DECL(unboosted) ++RCU_BOOST_TRACE_FUNC_DECL(try_boost_readers) ++RCU_BOOST_TRACE_FUNC_DECL(boost_readers) ++RCU_BOOST_TRACE_FUNC_DECL(try_unboost_readers) ++RCU_BOOST_TRACE_FUNC_DECL(unboost_readers) ++RCU_BOOST_TRACE_FUNC_DECL(over_taken) ++#else /* CONFIG_RCU_TRACE */ ++/* These were created by the above macro "RCU_BOOST_TRACE_FUNC_DECL" */ ++# define rcu_trace_boost_task_boost_called(rbd) do { } while (0) ++# define rcu_trace_boost_task_boosted(rbd) do { } while (0) ++# define rcu_trace_boost_boost_called(rbd) do { } while (0) ++# define rcu_trace_boost_try_boost(rbd) do { } while (0) ++# define rcu_trace_boost_boosted(rbd) do { } while (0) ++# define rcu_trace_boost_unboost_called(rbd) do { } while (0) ++# define rcu_trace_boost_unboosted(rbd) do { } while (0) ++# define rcu_trace_boost_try_boost_readers(rbd) do { } while (0) ++# define rcu_trace_boost_boost_readers(rbd) do { } while (0) ++# define rcu_trace_boost_try_unboost_readers(rbd) do { } while (0) ++# define rcu_trace_boost_unboost_readers(rbd) do { } while (0) ++# define rcu_trace_boost_over_taken(rbd) do { } while (0) ++#endif /* CONFIG_RCU_TRACE */ ++ ++/* ++ * Helper function to boost a task's prio. ++ */ ++static void rcu_boost_task(struct task_struct *task) ++{ ++ WARN_ON(!irqs_disabled()); ++ WARN_ON_SMP(!spin_is_locked(&task->pi_lock)); ++ ++ rcu_trace_boost_task_boost_called(RCU_BOOST_ME); ++ ++ if (task->rcu_prio < task->prio) { ++ rcu_trace_boost_task_boosted(RCU_BOOST_ME); ++ rt_mutex_setprio(task, task->rcu_prio); ++ } ++} ++ ++/** ++ * __rcu_preepmt_boost - Called by sleeping RCU readers. ++ * ++ * When the RCU read-side critical section is preempted ++ * (or schedules out due to RT mutex) ++ * it places itself onto a list to notify that it is sleeping ++ * while holding a RCU read lock. If there is already a ++ * synchronize_rcu happening, then it will increase its ++ * priority (if necessary). ++ */ ++void __rcu_preempt_boost(void) ++{ ++ struct task_struct *curr = current; ++ struct rcu_boost_dat *rbd; ++ int prio; ++ unsigned long flags; ++ ++ WARN_ON(!current->rcu_read_lock_nesting); ++ ++ rcu_trace_boost_boost_called(RCU_BOOST_ME); ++ ++ /* check to see if we are already boosted */ ++ if (unlikely(curr->rcub_rbdp)) ++ return; ++ ++ /* ++ * To keep us from preempting between grabing ++ * the rbd and locking it, we use local_irq_save ++ */ ++ local_irq_save(flags); ++ rbd = &__get_cpu_var(rcu_boost_data); ++ spin_lock(&rbd->rbs_lock); ++ ++ spin_lock(&curr->pi_lock); ++ ++ curr->rcub_rbdp = rbd; ++ ++ rcu_trace_boost_try_boost(rbd); ++ ++ prio = rt_mutex_getprio(curr); ++ ++ if (list_empty(&curr->rcub_entry)) ++ list_add_tail(&curr->rcub_entry, &rbd->rbs_toboost); ++ if (prio <= rbd->rbs_prio) ++ goto out; ++ ++ rcu_trace_boost_boosted(curr->rcub_rbdp); ++ ++ curr->rcu_prio = rbd->rbs_prio; ++ rcu_boost_task(curr); ++ ++ out: ++ spin_unlock(&curr->pi_lock); ++ spin_unlock_irqrestore(&rbd->rbs_lock, flags); ++} ++ ++/** ++ * __rcu_preempt_unboost - called when releasing the RCU read lock ++ * ++ * When releasing the RCU read lock, a check is made to see if ++ * the task was preempted. If it was, it removes itself from the ++ * RCU data lists and if necessary, sets its priority back to ++ * normal. ++ */ ++void __rcu_preempt_unboost(void) ++{ ++ struct task_struct *curr = current; ++ struct rcu_boost_dat *rbd; ++ int prio; ++ unsigned long flags; ++ ++ rcu_trace_boost_unboost_called(RCU_BOOST_ME); ++ ++ /* if not boosted, then ignore */ ++ if (likely(!curr->rcub_rbdp)) ++ return; ++ ++ rbd = curr->rcub_rbdp; ++ ++ spin_lock_irqsave(&rbd->rbs_lock, flags); ++ list_del_init(&curr->rcub_entry); ++ ++ rcu_trace_boost_unboosted(curr->rcub_rbdp); ++ ++ curr->rcu_prio = MAX_PRIO; ++ ++ spin_lock(&curr->pi_lock); ++ prio = rt_mutex_getprio(curr); ++ rt_mutex_setprio(curr, prio); ++ ++ curr->rcub_rbdp = NULL; ++ ++ spin_unlock(&curr->pi_lock); ++ spin_unlock_irqrestore(&rbd->rbs_lock, flags); ++} ++ ++/* ++ * For each rcu_boost_dat structure, update all the tasks that ++ * are on the lists to the priority of the caller of ++ * synchronize_rcu. ++ */ ++static int __rcu_boost_readers(struct rcu_boost_dat *rbd, int prio, unsigned long flags) ++{ ++ struct task_struct *curr = current; ++ struct task_struct *p; ++ ++ spin_lock(&rbd->rbs_lock); ++ ++ rbd->rbs_prio = prio; ++ ++ /* ++ * Move the already boosted readers onto the list and reboost ++ * them. ++ */ ++ list_splice_init(&rbd->rbs_boosted, ++ &rbd->rbs_toboost); ++ ++ while (!list_empty(&rbd->rbs_toboost)) { ++ p = list_entry(rbd->rbs_toboost.next, ++ struct task_struct, rcub_entry); ++ list_move_tail(&p->rcub_entry, ++ &rbd->rbs_boosted); ++ p->rcu_prio = prio; ++ spin_lock(&p->pi_lock); ++ rcu_boost_task(p); ++ spin_unlock(&p->pi_lock); ++ ++ /* ++ * Now we release the lock to allow for a higher ++ * priority task to come in and boost the readers ++ * even higher. Or simply to let a higher priority ++ * task to run now. ++ */ ++ spin_unlock(&rbd->rbs_lock); ++ spin_unlock_irqrestore(&rcu_boost_wake_lock, flags); ++ ++ cpu_relax(); ++ spin_lock_irqsave(&rcu_boost_wake_lock, flags); ++ /* ++ * Another task may have taken over. ++ */ ++ if (curr->rcu_preempt_counter != rcu_boost_counter) { ++ rcu_trace_boost_over_taken(rbd); ++ return 1; ++ } ++ ++ spin_lock(&rbd->rbs_lock); ++ } ++ ++ spin_unlock(&rbd->rbs_lock); ++ ++ return 0; ++} ++ ++/** ++ * rcu_boost_readers - called by synchronize_rcu to boost sleeping RCU readers. ++ * ++ * This function iterates over all the per_cpu rcu_boost_data descriptors ++ * and boosts any sleeping (or slept) RCU readers. ++ */ ++void rcu_boost_readers(void) ++{ ++ struct task_struct *curr = current; ++ struct rcu_boost_dat *rbd; ++ unsigned long flags; ++ int prio; ++ int cpu; ++ int ret; ++ ++ spin_lock_irqsave(&rcu_boost_wake_lock, flags); ++ ++ prio = rt_mutex_getprio(curr); ++ ++ rcu_trace_boost_try_boost_readers(RCU_BOOST_ME); ++ ++ if (prio >= rcu_boost_prio) { ++ /* already boosted */ ++ spin_unlock_irqrestore(&rcu_boost_wake_lock, flags); ++ return; ++ } ++ ++ rcu_boost_prio = prio; ++ ++ rcu_trace_boost_boost_readers(RCU_BOOST_ME); ++ ++ /* Flag that we are the one to unboost */ ++ curr->rcu_preempt_counter = ++rcu_boost_counter; ++ ++ for_each_online_cpu(cpu) { ++ rbd = &per_cpu(rcu_boost_data, cpu); ++ ret = __rcu_boost_readers(rbd, prio, flags); ++ if (ret) ++ break; ++ } ++ ++ spin_unlock_irqrestore(&rcu_boost_wake_lock, flags); ++ ++} ++ ++/** ++ * rcu_unboost_readers - set the boost level back to normal. ++ * ++ * This function DOES NOT change the priority of any RCU reader ++ * that was boosted. The RCU readers do that when they release ++ * the RCU lock. This function only sets the global ++ * rcu_boost_prio to MAX_PRIO so that new RCU readers that sleep ++ * do not increase their priority. ++ */ ++void rcu_unboost_readers(void) ++{ ++ struct rcu_boost_dat *rbd; ++ unsigned long flags; ++ int cpu; ++ ++ spin_lock_irqsave(&rcu_boost_wake_lock, flags); ++ ++ rcu_trace_boost_try_unboost_readers(RCU_BOOST_ME); ++ ++ if (current->rcu_preempt_counter != rcu_boost_counter) ++ goto out; ++ ++ rcu_trace_boost_unboost_readers(RCU_BOOST_ME); ++ ++ /* ++ * We could also put in something that ++ * would allow other synchronize_rcu callers ++ * of lower priority that are still waiting ++ * to boost the prio. ++ */ ++ rcu_boost_prio = MAX_PRIO; ++ ++ for_each_online_cpu(cpu) { ++ rbd = &per_cpu(rcu_boost_data, cpu); ++ ++ spin_lock(&rbd->rbs_lock); ++ rbd->rbs_prio = rcu_boost_prio; ++ spin_unlock(&rbd->rbs_lock); ++ } ++ ++ out: ++ spin_unlock_irqrestore(&rcu_boost_wake_lock, flags); ++} ++ ++/* ++ * The krcupreemptd wakes up every "rcu_preempt_thread_secs" ++ * seconds at the minimum priority of 1 to do a ++ * synchronize_rcu. This ensures that grace periods finish ++ * and that we do not starve the system. If there are RT ++ * tasks above priority 1 that are hogging the system and ++ * preventing release of memory, then its the fault of the ++ * system designer running RT tasks too aggressively and the ++ * system is flawed regardless. ++ */ ++static int krcupreemptd(void *data) ++{ ++ struct sched_param param = { .sched_priority = 1 }; ++ int ret; ++ int prio; ++ ++ ret = sched_setscheduler(current, SCHED_FIFO, ¶m); ++ printk("krcupreemptd setsched %d\n", ret); ++ prio = current->prio; ++ printk(" prio = %d\n", prio); ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ while (!kthread_should_stop()) { ++ schedule_timeout(rcu_preempt_thread_secs * HZ); ++ ++ __set_current_state(TASK_RUNNING); ++ if (prio != current->prio) { ++ prio = current->prio; ++ printk("krcupreemptd new prio is %d??\n",prio); ++ } ++ ++ synchronize_rcu(); ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ } ++ __set_current_state(TASK_RUNNING); ++ return 0; ++} ++ ++static int __init rcu_preempt_boost_init(void) ++{ ++ struct rcu_boost_dat *rbd; ++ struct task_struct *p; ++ int cpu; ++ ++ for_each_possible_cpu(cpu) { ++ rbd = &per_cpu(rcu_boost_data, cpu); ++ ++ spin_lock_init(&rbd->rbs_lock); ++ rbd->rbs_prio = MAX_PRIO; ++ INIT_LIST_HEAD(&rbd->rbs_toboost); ++ INIT_LIST_HEAD(&rbd->rbs_boosted); ++ } ++ ++ p = kthread_create(krcupreemptd, NULL, ++ "krcupreemptd"); ++ ++ if (IS_ERR(p)) { ++ printk("krcupreemptd failed\n"); ++ return NOTIFY_BAD; ++ } ++ wake_up_process(p); ++ ++ return 0; ++} ++ ++core_initcall(rcu_preempt_boost_init); +Index: linux-2.6.24.7-rt27/kernel/rcupreempt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt.c 2009-02-08 00:02:48.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt.c 2009-02-08 00:03:45.000000000 -0500 +@@ -310,6 +310,8 @@ void __rcu_read_unlock(void) + + ACCESS_ONCE(__get_cpu_var(rcu_flipctr)[idx])--; + local_irq_restore(oldirq); ++ ++ __rcu_preempt_unboost(); + } + } + EXPORT_SYMBOL_GPL(__rcu_read_unlock); +Index: linux-2.6.24.7-rt27/kernel/rcupreempt_trace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt_trace.c 2009-02-08 00:03:44.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt_trace.c 2009-02-08 00:03:45.000000000 -0500 +@@ -296,8 +296,14 @@ static int rcupreempt_debugfs_init(void) + NULL, &rcuctrs_fops); + if (!ctrsdir) + goto free_out; ++ ++ if (!rcu_trace_boost_create(rcudir)) ++ goto free_out; ++ + return 0; + free_out: ++ if (ctrsdir) ++ debugfs_remove(ctrsdir); + if (statdir) + debugfs_remove(statdir); + if (gpdir) +@@ -323,6 +329,7 @@ static int __init rcupreempt_trace_init( + + static void __exit rcupreempt_trace_cleanup(void) + { ++ rcu_trace_boost_destroy(); + debugfs_remove(statdir); + debugfs_remove(gpdir); + debugfs_remove(ctrsdir); +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:03:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:03:45.000000000 -0500 +@@ -121,11 +121,12 @@ static inline void init_lists(struct rt_ + */ + int rt_mutex_getprio(struct task_struct *task) + { ++ int prio = min(task->normal_prio, get_rcu_prio(task)); ++ + if (likely(!task_has_pi_waiters(task))) +- return task->normal_prio; ++ return prio; + +- return min(task_top_pi_waiter(task)->pi_list_entry.prio, +- task->normal_prio); ++ return min(task_top_pi_waiter(task)->pi_list_entry.prio, prio); + } + + /* +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:03:40.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:03:45.000000000 -0500 +@@ -3850,6 +3850,8 @@ asmlinkage void __sched __schedule(void) + struct rq *rq; + int cpu; + ++ rcu_preempt_boost(); ++ + preempt_disable(); + cpu = smp_processor_id(); + rq = cpu_rq(cpu); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0001-futex-fix-fault-damage.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0001-futex-fix-fault-damage.patch @@ -0,0 +1,151 @@ +Subject: futex-fix-fault-damage.patch +From: Thomas Gleixner +Date: Sat, 21 Jun 2008 09:09:44 +0200 + +Signed-off-by: Thomas Gleixner +--- + kernel/futex.c | 93 ++++++++++++++++++++++++++++++++++++++++++++------------- + 1 file changed, 73 insertions(+), 20 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/futex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/futex.c 2009-02-08 00:00:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/futex.c 2009-02-08 00:00:39.000000000 -0500 +@@ -1107,21 +1107,64 @@ static void unqueue_me_pi(struct futex_q + * private futexes. + */ + static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, +- struct task_struct *newowner) ++ struct task_struct *newowner, ++ struct rw_semaphore *fshared) + { + u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS; + struct futex_pi_state *pi_state = q->pi_state; ++ struct task_struct *oldowner = pi_state->owner; + u32 uval, curval, newval; +- int ret; ++ int ret, attempt = 0; + + /* Owner died? */ ++ if (!pi_state->owner) ++ newtid |= FUTEX_OWNER_DIED; ++ ++ /* ++ * We are here either because we stole the rtmutex from the ++ * pending owner or we are the pending owner which failed to ++ * get the rtmutex. We have to replace the pending owner TID ++ * in the user space variable. This must be atomic as we have ++ * preserve the owner died bit here. ++ * ++ * Note: We write the user space value _before_ changing the ++ * pi_state because we can fault here. Imagine swapped out ++ * pages or a fork, which was running right before we acquired ++ * mmap_sem, that marked all the anonymous memory readonly for ++ * cow. ++ * ++ * Modifying pi_state _before_ the user space value would ++ * leave the pi_state in an inconsistent state when we fault ++ * here, because we need to drop the hash bucket lock to ++ * handle the fault. This might be observed in the PID check ++ * in lookup_pi_state. ++ */ ++retry: ++ if (get_futex_value_locked(&uval, uaddr)) ++ goto handle_fault; ++ ++ while (1) { ++ newval = (uval & FUTEX_OWNER_DIED) | newtid; ++ ++ curval = cmpxchg_futex_value_locked(uaddr, uval, newval); ++ ++ if (curval == -EFAULT) ++ goto handle_fault; ++ if (curval == uval) ++ break; ++ uval = curval; ++ } ++ ++ /* ++ * We fixed up user space. Now we need to fix the pi_state ++ * itself. ++ */ + if (pi_state->owner != NULL) { + spin_lock_irq(&pi_state->owner->pi_lock); + WARN_ON(list_empty(&pi_state->list)); + list_del_init(&pi_state->list); + spin_unlock_irq(&pi_state->owner->pi_lock); +- } else +- newtid |= FUTEX_OWNER_DIED; ++ } + + pi_state->owner = newowner; + +@@ -1129,26 +1172,35 @@ static int fixup_pi_state_owner(u32 __us + WARN_ON(!list_empty(&pi_state->list)); + list_add(&pi_state->list, &newowner->pi_state_list); + spin_unlock_irq(&newowner->pi_lock); ++ return 0; + + /* +- * We own it, so we have to replace the pending owner +- * TID. This must be atomic as we have preserve the +- * owner died bit here. ++ * To handle the page fault we need to drop the hash bucket ++ * lock here. That gives the other task (either the pending ++ * owner itself or the task which stole the rtmutex) the ++ * chance to try the fixup of the pi_state. So once we are ++ * back from handling the fault we need to check the pi_state ++ * after reacquiring the hash bucket lock and before trying to ++ * do another fixup. When the fixup has been done already we ++ * simply return. + */ +- ret = get_futex_value_locked(&uval, uaddr); ++handle_fault: ++ spin_unlock(q->lock_ptr); + +- while (!ret) { +- newval = (uval & FUTEX_OWNER_DIED) | newtid; ++ ret = futex_handle_fault((unsigned long)uaddr, fshared, attempt++); + +- curval = cmpxchg_futex_value_locked(uaddr, uval, newval); ++ spin_lock(q->lock_ptr); + +- if (curval == -EFAULT) +- ret = -EFAULT; +- if (curval == uval) +- break; +- uval = curval; +- } +- return ret; ++ /* ++ * Check if someone else fixed it for us: ++ */ ++ if (pi_state->owner != oldowner) ++ return 0; ++ ++ if (ret) ++ return ret; ++ ++ goto retry; + } + + /* +@@ -1505,7 +1557,7 @@ static int futex_lock_pi(u32 __user *uad + * that case: + */ + if (q.pi_state->owner != curr) +- ret = fixup_pi_state_owner(uaddr, &q, curr); ++ ret = fixup_pi_state_owner(uaddr, &q, curr, fshared); + } else { + /* + * Catch the rare case, where the lock was released +@@ -1537,7 +1589,8 @@ static int futex_lock_pi(u32 __user *uad + int res; + + owner = rt_mutex_owner(&q.pi_state->pi_mutex); +- res = fixup_pi_state_owner(uaddr, &q, owner); ++ res = fixup_pi_state_owner(uaddr, &q, owner, ++ fshared); + + WARN_ON(rt_mutex_owner(&q.pi_state->pi_mutex) != + owner); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0555-4ff4b9e19a80b73959ebeb28d1df40176686f0a8.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0555-4ff4b9e19a80b73959ebeb28d1df40176686f0a8.patch @@ -0,0 +1,55 @@ +commit 4ff4b9e19a80b73959ebeb28d1df40176686f0a8 +Author: Maciej W. Rozycki +Date: Fri Sep 5 14:05:31 2008 -0700 + + ntp: fix calculation of the next jiffie to trigger RTC sync + + We have a bug in the calculation of the next jiffie to trigger the RTC + synchronisation. The aim here is to run sync_cmos_clock() as close as + possible to the middle of a second. Which means we want this function to + be called less than or equal to half a jiffie away from when now.tv_nsec + equals 5e8 (500000000). + + If this is not the case for a given call to the function, for this purpose + instead of updating the RTC we calculate the offset in nanoseconds to the + next point in time where now.tv_nsec will be equal 5e8. The calculated + offset is then converted to jiffies as these are the unit used by the + timer. + + Hovewer timespec_to_jiffies() used here uses a ceil()-type rounding mode, + where the resulting value is rounded up. As a result the range of + now.tv_nsec when the timer will trigger is from 5e8 to 5e8 + TICK_NSEC + rather than the desired 5e8 - TICK_NSEC / 2 to 5e8 + TICK_NSEC / 2. + + As a result if for example sync_cmos_clock() happens to be called at the + time when now.tv_nsec is between 5e8 + TICK_NSEC / 2 and 5e8 to 5e8 + + TICK_NSEC, it will simply be rescheduled HZ jiffies later, falling in the + same range of now.tv_nsec again. Similarly for cases offsetted by an + integer multiple of TICK_NSEC. + + This change addresses the problem by subtracting TICK_NSEC / 2 from the + nanosecond offset to the next point in time where now.tv_nsec will be + equal 5e8, effectively shifting the following rounding in + timespec_to_jiffies() so that it produces a rounded-to-nearest result. + + Signed-off-by: Maciej W. Rozycki + Signed-off-by: Andrew Morton + Signed-off-by: Ingo Molnar + +--- + kernel/time/ntp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/time/ntp.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/ntp.c 2009-02-07 23:59:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/ntp.c 2009-02-08 00:05:14.000000000 -0500 +@@ -208,7 +208,7 @@ static void sync_cmos_clock(unsigned lon + if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) + fail = update_persistent_clock(now); + +- next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec; ++ next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2); + if (next.tv_nsec <= 0) + next.tv_nsec += NSEC_PER_SEC; + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0514-cpu-hotplug-cpu-down-vs-preempt-rt.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0514-cpu-hotplug-cpu-down-vs-preempt-rt.patch @@ -0,0 +1,140 @@ +Subject: cpu-hotplug: cpu_down vs preempt-rt +From: Peter Zijlstra +Date: Tue, 10 Jun 2008 13:13:04 +0200 + +idle_task_exit() calls mmdrop() from the idle thread, but in PREEMPT_RT all the +allocator locks are sleeping locks - for obvious reasons scheduling away the +idle thread gives some curious problems. + +Solve this by pushing the mmdrop() into an RCU callback, however we can't use +RCU because the CPU is already down and all the local RCU state has been +destroyed. + +Therefore create a new call_rcu() variant that enqueues the callback on an +online cpu. + +Signed-off-by: Peter Zijlstra +Cc: Steven Rostedt +Cc: Clark Williams +Cc: Gregory Haskins +Cc: "Paul E. McKenney" +Cc: Gautham R Shenoy +Cc: Pekka Enberg +Cc: Arnaldo Carvalho de Melo +Cc: Peter Zijlstra +Signed-off-by: Thomas Gleixner +--- + include/linux/mm_types.h | 5 +++++ + include/linux/rcupreempt.h | 2 ++ + kernel/rcupreempt.c | 29 +++++++++++++++++++++++++++++ + kernel/sched.c | 13 +++++++++++++ + 4 files changed, 49 insertions(+) + +Index: linux-2.6.24.7-rt27/include/linux/mm_types.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/mm_types.h 2009-02-08 00:02:37.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/mm_types.h 2009-02-08 00:04:55.000000000 -0500 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -222,6 +223,10 @@ struct mm_struct { + /* aio bits */ + rwlock_t ioctx_list_lock; + struct kioctx *ioctx_list; ++ ++#ifdef CONFIG_PREEMPT_RT ++ struct rcu_head rcu_head; ++#endif + }; + + #endif /* _LINUX_MM_TYPES_H */ +Index: linux-2.6.24.7-rt27/include/linux/rcupreempt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupreempt.h 2009-02-08 00:04:02.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupreempt.h 2009-02-08 00:04:55.000000000 -0500 +@@ -83,6 +83,8 @@ extern void FASTCALL(call_rcu_classic(st + void (*func)(struct rcu_head *head))); + extern void FASTCALL(call_rcu_preempt(struct rcu_head *head, + void (*func)(struct rcu_head *head))); ++extern void FASTCALL(call_rcu_preempt_online(struct rcu_head *head, ++ void (*func)(struct rcu_head *head))); + extern void __rcu_read_lock(void); + extern void __rcu_read_unlock(void); + extern void __synchronize_sched(void); +Index: linux-2.6.24.7-rt27/kernel/rcupreempt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt.c 2009-02-08 00:04:55.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt.c 2009-02-08 00:04:55.000000000 -0500 +@@ -916,6 +916,35 @@ void fastcall call_rcu_preempt(struct rc + } + EXPORT_SYMBOL_GPL(call_rcu_preempt); + ++void fastcall call_rcu_preempt_online(struct rcu_head *head, ++ void (*func)(struct rcu_head *rcu)) ++{ ++ struct rcu_data *rdp; ++ unsigned long flags; ++ int cpu; ++ ++ head->func = func; ++ head->next = NULL; ++again: ++ cpu = first_cpu(cpu_online_map); ++ rdp = RCU_DATA_CPU(cpu); ++ ++ spin_lock_irqsave(&rdp->lock, flags); ++ if (unlikely(!cpu_online(cpu))) { ++ /* ++ * cpu is removed from the online map before rcu_offline_cpu ++ * is called. ++ */ ++ spin_unlock_irqrestore(&rdp->lock, flags); ++ goto again; ++ } ++ ++ *rdp->nexttail = head; ++ rdp->nexttail = &head->next; ++ spin_unlock_irqrestore(&rdp->lock, flags); ++ ++} ++ + /* + * Check to see if any future RCU-related work will need to be done + * by the current CPU, even if none need be done immediately, returning +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:04:47.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:04:55.000000000 -0500 +@@ -5888,6 +5888,15 @@ void sched_idle_next(void) + spin_unlock_irqrestore(&rq->lock, flags); + } + ++#ifdef CONFIG_PREEMPT_RT ++void mmdrop_rcu(struct rcu_head *head) ++{ ++ struct mm_struct *mm = container_of(head, struct mm_struct, rcu_head); ++ ++ mmdrop(mm); ++} ++#endif ++ + /* + * Ensures that the idle task is using init_mm right before its cpu goes + * offline. +@@ -5900,7 +5909,11 @@ void idle_task_exit(void) + + if (mm != &init_mm) + switch_mm(mm, &init_mm, current); ++#ifdef CONFIG_PREEMPT_RT ++ call_rcu_preempt_online(&mm->rcu_head, mmdrop_rcu); ++#else + mmdrop(mm); ++#endif + } + + /* called under rq->lock with disabled interrupts */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0306-timer-freq-tweaks.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0306-timer-freq-tweaks.patch @@ -0,0 +1,119 @@ +--- + kernel/rcutorture.c | 2 +- + mm/slab.c | 25 +++++++++++++++---------- + 2 files changed, 16 insertions(+), 11 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rcutorture.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcutorture.c 2009-02-08 00:01:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcutorture.c 2009-02-08 00:03:16.000000000 -0500 +@@ -647,7 +647,7 @@ rcu_torture_reader(void *arg) + if (p == NULL) { + /* Wait for rcu_torture_writer to get underway */ + cur_ops->readunlock(idx); +- schedule_timeout_interruptible(HZ); ++ schedule_timeout_interruptible(round_jiffies_relative(HZ)); + continue; + } + if (p->rtort_mbtest == 0) +Index: linux-2.6.24.7-rt27/mm/slab.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/slab.c 2009-02-08 00:01:58.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/slab.c 2009-02-08 00:03:16.000000000 -0500 +@@ -1051,7 +1051,7 @@ static int transfer_objects(struct array + #ifndef CONFIG_NUMA + + #define drain_alien_cache(cachep, alien) do { } while (0) +-#define reap_alien(cachep, l3, this_cpu) do { } while (0) ++#define reap_alien(cachep, l3, this_cpu) 0 + + static inline struct array_cache **alloc_alien_cache(int node, int limit) + { +@@ -1149,7 +1149,7 @@ static void __drain_alien_cache(struct k + /* + * Called from cache_reap() to regularly drain alien caches round robin. + */ +-static void ++static int + reap_alien(struct kmem_cache *cachep, struct kmem_list3 *l3, int *this_cpu) + { + int node = per_cpu(reap_node, *this_cpu); +@@ -1160,8 +1160,10 @@ reap_alien(struct kmem_cache *cachep, st + if (ac && ac->avail && spin_trylock_irq(&ac->lock)) { + __drain_alien_cache(cachep, ac, node, this_cpu); + spin_unlock_irq(&ac->lock); ++ return 1; + } + } ++ return 0; + } + + static void drain_alien_cache(struct kmem_cache *cachep, +@@ -2514,7 +2516,7 @@ static void check_spinlock_acquired_node + #define check_spinlock_acquired_node(x, y) do { } while(0) + #endif + +-static void drain_array(struct kmem_cache *cachep, struct kmem_list3 *l3, ++static int drain_array(struct kmem_cache *cachep, struct kmem_list3 *l3, + struct array_cache *ac, + int force, int node); + +@@ -4148,14 +4150,15 @@ static int enable_cpucache(struct kmem_c + * Drain an array if it contains any elements taking the l3 lock only if + * necessary. Note that the l3 listlock also protects the array_cache + * if drain_array() is used on the shared array. ++ * returns non-zero if some work is done + */ +-void drain_array(struct kmem_cache *cachep, struct kmem_list3 *l3, ++int drain_array(struct kmem_cache *cachep, struct kmem_list3 *l3, + struct array_cache *ac, int force, int node) + { + int tofree, this_cpu; + + if (!ac || !ac->avail) +- return; ++ return 0; + if (ac->touched && !force) { + ac->touched = 0; + } else { +@@ -4171,6 +4174,7 @@ void drain_array(struct kmem_cache *cach + } + slab_spin_unlock_irq(&l3->list_lock, this_cpu); + } ++ return 1; + } + + /** +@@ -4208,10 +4212,10 @@ static void cache_reap(struct work_struc + */ + l3 = searchp->nodelists[node]; + +- reap_alien(searchp, l3, &this_cpu); ++ work_done += reap_alien(searchp, l3, &this_cpu); + +- drain_array(searchp, l3, cpu_cache_get(searchp, this_cpu), +- 0, node); ++ work_done += drain_array(searchp, l3, ++ cpu_cache_get(searchp, this_cpu), 0, node); + + /* + * These are racy checks but it does not matter +@@ -4222,7 +4226,7 @@ static void cache_reap(struct work_struc + + l3->next_reap = jiffies + REAPTIMEOUT_LIST3; + +- drain_array(searchp, l3, l3->shared, 0, node); ++ work_done += drain_array(searchp, l3, l3->shared, 0, node); + + if (l3->free_touched) + l3->free_touched = 0; +@@ -4241,7 +4245,8 @@ next: + next_reap_node(); + out: + /* Set up the next iteration */ +- schedule_delayed_work(work, round_jiffies_relative(REAPTIMEOUT_CPUC)); ++ schedule_delayed_work(work, ++ round_jiffies_relative((1+!work_done) * REAPTIMEOUT_CPUC)); + } + + #ifdef CONFIG_SLABINFO --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0081-sched-enable-irqs-in-preempt-in-notifier-call.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0081-sched-enable-irqs-in-preempt-in-notifier-call.patch @@ -0,0 +1,36 @@ +From: Thomas Gleixner +Date: Mon, 14 Jan 2008 14:02:44 +0200 +Subject: CFS: enable irqs in fire_sched_in_preempt_notifier + +KVM expects the notifier call with irqs enabled. It's necessary due +to a possible IPI call. Make the preempt-rt version behave the same +way as mainline. + +Signed-off-by: Thomas Gleixner + +--- + kernel/sched.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:01:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:01:22.000000000 -0500 +@@ -1821,8 +1821,17 @@ static void fire_sched_in_preempt_notifi + struct preempt_notifier *notifier; + struct hlist_node *node; + ++ if (hlist_empty(&curr->preempt_notifiers)) ++ return; ++ ++ /* ++ * The KVM sched in notifier expects to be called with ++ * interrupts enabled. ++ */ ++ local_irq_enable(); + hlist_for_each_entry(notifier, node, &curr->preempt_notifiers, link) + notifier->ops->sched_in(notifier, raw_smp_processor_id()); ++ local_irq_disable(); + } + + static void --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0432-nmi-watchdog-fix-1.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0432-nmi-watchdog-fix-1.patch @@ -0,0 +1,35 @@ +From h-shimamoto@ct.jp.nec.com Thu May 15 10:14:15 2008 +Date: Mon, 28 Apr 2008 11:14:39 -0700 +From: Hiroshi Shimamoto +To: Ingo Molnar , Steven Rostedt , + Thomas Gleixner +Cc: linux-kernel@vger.kernel.org, linux-rt-users@vger.kernel.org +Subject: [PATCH -rt 1/4] x86_64: send NMI after nmi_show_regs on + +From: Hiroshi Shimamoto + +The flags nmi_show_regs should be set before send NMI. + +Signed-off-by: Hiroshi Shimamoto +--- + arch/x86/kernel/nmi_64.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_64.c 2009-02-08 00:03:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c 2009-02-08 00:04:16.000000000 -0500 +@@ -327,11 +327,11 @@ void nmi_show_all_regs(void) + if (system_state == SYSTEM_BOOTING) + return; + +- smp_send_nmi_allbutself(); +- + for_each_online_cpu(i) + nmi_show_regs[i] = 1; + ++ smp_send_nmi_allbutself(); ++ + for_each_online_cpu(i) { + while (nmi_show_regs[i] == 1) + barrier(); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0451-multi-reader-lock-account.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0451-multi-reader-lock-account.patch @@ -0,0 +1,447 @@ +From: Steven Rostedt +Subject: map read/write locks back to their readers + +This patch adds a mapping from the read/write lock back to the owners +that are readers. This is a link list of tasks that own the lock for read. + +The link list is protected by the read/write lock's mutex wait_lock. To +prevent grabbing this spinlock on the fast path, the list in not updated +when there is only one reader. The reader task is pointed to by the +owner field of the rw_mutex. When the second reader grabs the read lock +it will add the first owner to the list under the wait_lock. + +Signed-off-by: Steven Rostedt +--- + include/linux/rt_lock.h | 3 + include/linux/sched.h | 2 + kernel/fork.c | 8 ++ + kernel/rtmutex.c | 187 ++++++++++++++++++++++++++++++++++-------------- + 4 files changed, 146 insertions(+), 54 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/rt_lock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rt_lock.h 2009-02-08 00:04:24.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rt_lock.h 2009-02-08 00:04:25.000000000 -0500 +@@ -65,6 +65,7 @@ struct rw_mutex { + struct rt_mutex mutex; + atomic_t count; /* number of times held for read */ + atomic_t owners; /* number of owners as readers */ ++ struct list_head readers; + }; + + /* +@@ -194,7 +195,7 @@ extern int __bad_func_type(void); + */ + + #define __RWSEM_INITIALIZER(name) \ +- { .owners.mutex = __RT_MUTEX_INITIALIZER(name.owners.mutex), \ ++ { .owners.mutex = __RT_MUTEX_INITIALIZER(name.owners.mutex), \ + RW_DEP_MAP_INIT(name) } + + #define DECLARE_RWSEM(lockname) \ +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:04:23.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:04:25.000000000 -0500 +@@ -1009,6 +1009,8 @@ struct sched_entity { + struct rw_mutex; + struct reader_lock_struct { + struct rw_mutex *lock; ++ struct list_head list; ++ struct task_struct *task; + int count; + }; + +Index: linux-2.6.24.7-rt27/kernel/fork.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/fork.c 2009-02-08 00:04:23.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/fork.c 2009-02-08 00:04:25.000000000 -0500 +@@ -1208,6 +1208,14 @@ static struct task_struct *copy_process( + + #ifdef CONFIG_PREEMPT_RT + p->reader_lock_count = 0; ++ { ++ int i; ++ for (i = 0; i < MAX_RWLOCK_DEPTH; i++) { ++ INIT_LIST_HEAD(&p->owned_read_locks[i].list); ++ p->owned_read_locks[i].count = 0; ++ p->owned_read_locks[i].lock = NULL; ++ } ++ } + #endif + + if (pid != &init_struct_pid) { +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:24.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:25.000000000 -0500 +@@ -1011,6 +1011,14 @@ rt_rwlock_set_owner(struct rw_mutex *rwm + rwm->owner = (struct task_struct *)val; + } + ++static inline void init_rw_lists(struct rw_mutex *rwm) ++{ ++ if (unlikely(!rwm->readers.prev)) { ++ init_lists(&rwm->mutex); ++ INIT_LIST_HEAD(&rwm->readers); ++ } ++} ++ + /* + * The fast paths of the rw locks do not set up owners to + * the mutex. When blocking on an rwlock we must make sure +@@ -1035,11 +1043,59 @@ update_rw_mutex_owner(struct rw_mutex *r + rt_mutex_set_owner(mutex, mtxowner, 0); + } + ++/* ++ * The fast path does not add itself to the reader list to keep ++ * from needing to grab the spinlock. We need to add the owner ++ * itself. This may seem racy, but in practice, it is fine. ++ * The link list is protected by mutex->wait_lock. But to find ++ * the lock on the owner we need to read the owners reader counter. ++ * That counter is modified only by the owner. We are OK with that ++ * because to remove the lock that we are looking for, the owner ++ * must first grab the mutex->wait_lock. The lock will not disappear ++ * from the owner now, and we don't care if we see other locks ++ * held or not held. ++ */ ++ ++static inline void ++rt_rwlock_update_owner(struct rw_mutex *rwm, unsigned owners) ++{ ++ struct reader_lock_struct *rls; ++ struct task_struct *own; ++ int i; ++ ++ if (!owners || rt_rwlock_pending(rwm)) ++ return; ++ ++ own = rt_rwlock_owner(rwm); ++ if (own == RT_RW_READER) ++ return; ++ ++ for (i = own->reader_lock_count - 1; i >= 0; i--) { ++ if (own->owned_read_locks[i].lock == rwm) ++ break; ++ } ++ /* It is possible the owner didn't add it yet */ ++ if (i < 0) ++ return; ++ ++ rls = &own->owned_read_locks[i]; ++ /* It is also possible that the owner added it already */ ++ if (rls->list.prev && !list_empty(&rls->list)) ++ return; ++ ++ list_add(&rls->list, &rwm->readers); ++ ++ /* change to reader, so no one else updates too */ ++ rt_rwlock_set_owner(rwm, RT_RW_READER, RT_RWLOCK_CHECK); ++} ++ + static int try_to_take_rw_read(struct rw_mutex *rwm, int mtx) + { + struct rt_mutex *mutex = &rwm->mutex; + struct rt_mutex_waiter *waiter; ++ struct reader_lock_struct *rls; + struct task_struct *mtxowner; ++ int owners; + int reader_count, i; + int incr = 1; + +@@ -1055,8 +1111,15 @@ static int try_to_take_rw_read(struct rw + /* check to see if we don't already own this lock */ + for (i = current->reader_lock_count - 1; i >= 0; i--) { + if (current->owned_read_locks[i].lock == rwm) { ++ rls = ¤t->owned_read_locks[i]; ++ /* ++ * If this was taken via the fast path, then ++ * it hasn't been added to the link list yet. ++ */ ++ if (!rls->list.prev || list_empty(&rls->list)) ++ list_add(&rls->list, &rwm->readers); + rt_rwlock_set_owner(rwm, RT_RW_READER, 0); +- current->owned_read_locks[i].count++; ++ rls->count++; + incr = 0; + goto taken; + } +@@ -1067,13 +1130,16 @@ static int try_to_take_rw_read(struct rw + + /* if the owner released it before we marked it then take it */ + if (!mtxowner && !rt_rwlock_owner(rwm)) { +- WARN_ON(atomic_read(&rwm->count)); +- rt_rwlock_set_owner(rwm, current, 0); ++ /* Still unlock with the slow path (for PI handling) */ ++ rt_rwlock_set_owner(rwm, RT_RW_READER, 0); + goto taken; + } + ++ owners = atomic_read(&rwm->owners); ++ rt_rwlock_update_owner(rwm, owners); ++ + /* Check for rwlock limits */ +- if (rt_rwlock_limit && atomic_read(&rwm->owners) >= rt_rwlock_limit) ++ if (rt_rwlock_limit && owners >= rt_rwlock_limit) + return 0; + + if (mtxowner && mtxowner != RT_RW_READER) { +@@ -1125,8 +1191,11 @@ static int try_to_take_rw_read(struct rw + atomic_inc(&rwm->owners); + reader_count = current->reader_lock_count++; + if (likely(reader_count < MAX_RWLOCK_DEPTH)) { +- current->owned_read_locks[reader_count].lock = rwm; +- current->owned_read_locks[reader_count].count = 1; ++ rls = ¤t->owned_read_locks[reader_count]; ++ rls->lock = rwm; ++ rls->count = 1; ++ WARN_ON(rls->list.prev && !list_empty(&rls->list)); ++ list_add(&rls->list, &rwm->readers); + } else + WARN_ON_ONCE(1); + } +@@ -1146,12 +1215,13 @@ try_to_take_rw_write(struct rw_mutex *rw + + own = rt_rwlock_owner(rwm); + ++ /* owners must be zero for writer */ ++ rt_rwlock_update_owner(rwm, atomic_read(&rwm->owners)); ++ + /* readers or writers? */ + if ((own && !rt_rwlock_pending(rwm))) + return 0; + +- WARN_ON(atomic_read(&rwm->count)); +- + /* + * RT_RW_PENDING means that the lock is free, but there are + * pending owners on the mutex +@@ -1179,7 +1249,7 @@ rt_read_slowlock(struct rw_mutex *rwm, i + unsigned long saved_state = -1, state, flags; + + spin_lock_irqsave(&mutex->wait_lock, flags); +- init_lists(mutex); ++ init_rw_lists(rwm); + + if (try_to_take_rw_read(rwm, mtx)) { + spin_unlock_irqrestore(&mutex->wait_lock, flags); +@@ -1193,8 +1263,6 @@ rt_read_slowlock(struct rw_mutex *rwm, i + waiter.task = NULL; + waiter.write_lock = 0; + +- init_lists(mutex); +- + if (mtx) { + /* + * We drop the BKL here before we go into the wait loop to avoid a +@@ -1278,10 +1346,8 @@ rt_read_slowlock(struct rw_mutex *rwm, i + debug_rt_mutex_free_waiter(&waiter); + } + +-static inline void +-rt_read_fastlock(struct rw_mutex *rwm, +- void fastcall (*slowfn)(struct rw_mutex *rwm, int mtx), +- int mtx) ++static inline int ++__rt_read_fasttrylock(struct rw_mutex *rwm) + { + retry: + if (likely(rt_rwlock_cmpxchg(rwm, NULL, current))) { +@@ -1301,13 +1367,41 @@ rt_read_fastlock(struct rw_mutex *rwm, + } + + atomic_inc(&rwm->owners); +- reader_count = current->reader_lock_count++; ++ reader_count = current->reader_lock_count; + if (likely(reader_count < MAX_RWLOCK_DEPTH)) { + current->owned_read_locks[reader_count].lock = rwm; + current->owned_read_locks[reader_count].count = 1; + } else + WARN_ON_ONCE(1); +- } else ++ /* ++ * If this task is no longer the sole owner of the lock ++ * or someone is blocking, then we need to add the task ++ * to the lock. ++ */ ++ smp_mb(); ++ current->reader_lock_count++; ++ if (unlikely(rwm->owner != current)) { ++ struct rt_mutex *mutex = &rwm->mutex; ++ struct reader_lock_struct *rls; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&mutex->wait_lock, flags); ++ rls = ¤t->owned_read_locks[reader_count]; ++ if (!rls->list.prev || list_empty(&rls->list)) ++ list_add(&rls->list, &rwm->readers); ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ } ++ return 1; ++ } ++ return 0; ++} ++ ++static inline void ++rt_read_fastlock(struct rw_mutex *rwm, ++ void fastcall (*slowfn)(struct rw_mutex *rwm, int mtx), ++ int mtx) ++{ ++ if (unlikely(!__rt_read_fasttrylock(rwm))) + slowfn(rwm, mtx); + } + +@@ -1330,7 +1424,7 @@ rt_read_slowtrylock(struct rw_mutex *rwm + int ret = 0; + + spin_lock_irqsave(&mutex->wait_lock, flags); +- init_lists(mutex); ++ init_rw_lists(rwm); + + if (try_to_take_rw_read(rwm, mtx)) + ret = 1; +@@ -1344,31 +1438,9 @@ static inline int + rt_read_fasttrylock(struct rw_mutex *rwm, + int fastcall (*slowfn)(struct rw_mutex *rwm, int mtx), int mtx) + { +-retry: +- if (likely(rt_rwlock_cmpxchg(rwm, NULL, current))) { +- int reader_count; +- +- rt_mutex_deadlock_account_lock(&rwm->mutex, current); +- atomic_inc(&rwm->count); +- /* +- * It is possible that the owner was zeroed +- * before we incremented count. If owner is not +- * current, then retry again +- */ +- if (unlikely(rwm->owner != current)) { +- atomic_dec(&rwm->count); +- goto retry; +- } +- +- atomic_inc(&rwm->owners); +- reader_count = current->reader_lock_count++; +- if (likely(reader_count < MAX_RWLOCK_DEPTH)) { +- current->owned_read_locks[reader_count].lock = rwm; +- current->owned_read_locks[reader_count].count = 1; +- } else +- WARN_ON_ONCE(1); ++ if (likely(__rt_read_fasttrylock(rwm))) + return 1; +- } else ++ else + return slowfn(rwm, mtx); + } + +@@ -1392,7 +1464,7 @@ rt_write_slowlock(struct rw_mutex *rwm, + waiter.write_lock = 1; + + spin_lock_irqsave(&mutex->wait_lock, flags); +- init_lists(mutex); ++ init_rw_lists(rwm); + + if (try_to_take_rw_write(rwm, mtx)) { + spin_unlock_irqrestore(&mutex->wait_lock, flags); +@@ -1479,8 +1551,6 @@ rt_write_slowlock(struct rw_mutex *rwm, + if (mtx && unlikely(saved_lock_depth >= 0)) + rt_reacquire_bkl(saved_lock_depth); + +- WARN_ON(atomic_read(&rwm->count)); +- + debug_rt_mutex_free_waiter(&waiter); + + } +@@ -1492,10 +1562,9 @@ rt_write_fastlock(struct rw_mutex *rwm, + { + unsigned long val = (unsigned long)current | RT_RWLOCK_WRITER; + +- if (likely(rt_rwlock_cmpxchg(rwm, NULL, val))) { ++ if (likely(rt_rwlock_cmpxchg(rwm, NULL, val))) + rt_mutex_deadlock_account_lock(&rwm->mutex, current); +- WARN_ON(atomic_read(&rwm->count)); +- } else ++ else + slowfn(rwm, mtx); + } + +@@ -1517,7 +1586,7 @@ rt_write_slowtrylock(struct rw_mutex *rw + int ret = 0; + + spin_lock_irqsave(&mutex->wait_lock, flags); +- init_lists(mutex); ++ init_rw_lists(rwm); + + if (try_to_take_rw_write(rwm, mtx)) + ret = 1; +@@ -1535,7 +1604,6 @@ rt_write_fasttrylock(struct rw_mutex *rw + + if (likely(rt_rwlock_cmpxchg(rwm, NULL, val))) { + rt_mutex_deadlock_account_lock(&rwm->mutex, current); +- WARN_ON(atomic_read(&rwm->count)); + return 1; + } else + return slowfn(rwm, mtx); +@@ -1551,6 +1619,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + { + struct rt_mutex *mutex = &rwm->mutex; + struct rt_mutex_waiter *waiter; ++ struct reader_lock_struct *rls; + unsigned long flags; + unsigned int reader_count; + int savestate = !mtx; +@@ -1576,6 +1645,10 @@ rt_read_slowunlock(struct rw_mutex *rwm, + current->reader_lock_count--; + WARN_ON_ONCE(i != current->reader_lock_count); + atomic_dec(&rwm->owners); ++ rls = ¤t->owned_read_locks[i]; ++ WARN_ON(!rls->list.prev || list_empty(&rls->list)); ++ list_del_init(&rls->list); ++ rls->lock = NULL; + } + break; + } +@@ -1589,9 +1662,12 @@ rt_read_slowunlock(struct rw_mutex *rwm, + * be set to current or readers. This means that another reader + * already reset the lock, so there is nothing left to do. + */ +- if ((rt_rwlock_owner(rwm) != current && +- rt_rwlock_owner(rwm) != RT_RW_READER)) ++ if (unlikely(rt_rwlock_owner(rwm) != current && ++ rt_rwlock_owner(rwm) != RT_RW_READER)) { ++ /* Update the owner if necessary */ ++ rt_rwlock_update_owner(rwm, atomic_read(&rwm->owners)); + goto out; ++ } + + /* + * If there are more readers and we are under the limit +@@ -1667,6 +1743,7 @@ rt_read_fastunlock(struct rw_mutex *rwm, + WARN_ON(!rwm->owner); + atomic_dec(&rwm->count); + if (likely(rt_rwlock_cmpxchg(rwm, current, NULL))) { ++ struct reader_lock_struct *rls; + int reader_count = --current->reader_lock_count; + int owners; + rt_mutex_deadlock_account_unlock(current); +@@ -1679,7 +1756,10 @@ rt_read_fastunlock(struct rw_mutex *rwm, + atomic_set(&rwm->owners, 0); + WARN_ON_ONCE(1); + } +- WARN_ON_ONCE(current->owned_read_locks[reader_count].lock != rwm); ++ rls = ¤t->owned_read_locks[reader_count]; ++ WARN_ON_ONCE(rls->lock != rwm); ++ WARN_ON(rls->list.prev && !list_empty(&rls->list)); ++ rls->lock = NULL; + } else + slowfn(rwm, mtx); + } +@@ -1830,6 +1910,7 @@ void rt_mutex_rwsem_init(struct rw_mutex + rwm->owner = NULL; + atomic_set(&rwm->count, 0); + atomic_set(&rwm->owners, 0); ++ INIT_LIST_HEAD(&rwm->readers); + + __rt_mutex_init(mutex, name); + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0009-CVE-2008-2148-simplify_sched_fair.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0009-CVE-2008-2148-simplify_sched_fair.patch @@ -0,0 +1,45 @@ +Subject: sched: simplify sched_slice() + +From: Ingo Molnar + +X-Git-Tag: v2.6.25-rc6~5 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=6a6029b8cefe0ca7e82f27f3904dbedba3de4e06 + +sched: simplify sched_slice() + +Use the existing calc_delta_mine() calculation for sched_slice(). This +saves a divide and simplifies the code because we share it with the +other /cfs_rq->load users. + +It also improves code size: + + text data bss dec hex filename + 42659 2740 144 45543 b1e7 sched.o.before + 42093 2740 144 44977 afb1 sched.o.after + +Signed-off-by: Ingo Molnar +Signed-off-by: Peter Zijlstra +--- + + kernel/sched_fair.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_fair.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_fair.c 2009-02-08 00:00:38.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_fair.c 2009-02-08 00:00:44.000000000 -0500 +@@ -263,12 +263,8 @@ static u64 __sched_period(unsigned long + */ + static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se) + { +- u64 slice = __sched_period(cfs_rq->nr_running); +- +- slice *= se->load.weight; +- do_div(slice, cfs_rq->load.weight); +- +- return slice; ++ return calc_delta_mine(__sched_period(cfs_rq->nr_running), ++ se->load.weight, &cfs_rq->load); + } + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0330-RT_utsname.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0330-RT_utsname.patch @@ -0,0 +1,37 @@ +--- + init/Makefile | 2 +- + scripts/mkcompile_h | 4 +++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/init/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/init/Makefile 2009-02-07 23:59:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/init/Makefile 2009-02-08 00:03:27.000000000 -0500 +@@ -30,4 +30,4 @@ $(obj)/version.o: include/linux/compile. + include/linux/compile.h: FORCE + @echo ' CHK $@' + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \ +- "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CC) $(KBUILD_CFLAGS)" ++ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CONFIG_PREEMPT_RT)" "$(CC) $(KBUILD_CFLAGS)" +Index: linux-2.6.24.7-rt27/scripts/mkcompile_h +=================================================================== +--- linux-2.6.24.7-rt27.orig/scripts/mkcompile_h 2009-02-07 23:59:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/scripts/mkcompile_h 2009-02-08 00:03:27.000000000 -0500 +@@ -2,7 +2,8 @@ TARGET=$1 + ARCH=$2 + SMP=$3 + PREEMPT=$4 +-CC=$5 ++PREEMPT_RT=$5 ++CC=$6 + + # If compile.h exists already and we don't own autoconf.h + # (i.e. we're not the same user who did make *config), don't +@@ -43,6 +44,7 @@ UTS_VERSION="#$VERSION" + CONFIG_FLAGS="" + if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi + if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi ++if [ -n "$PREEMPT_RT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS RT"; fi + UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS $TIMESTAMP" + + # Truncate to maximum length --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0450-multi-reader-limit.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0450-multi-reader-limit.patch @@ -0,0 +1,254 @@ +From: Steven Rostedt +Subject: implement reader limit on read write locks + +This patch allows for limiting the number of readers a lock may have. +The limit is default to "no limit". The read write locks now keep +track of, not only the number of times a lock is held by read, but also +the number of tasks that have a reader. i.e. If 2 tasks hold the same +read/write lock, and one task holds the lock twice, the count for the +read/write lock would be 3 and the owner count is 2. + +The limit of readers is controlled by + + /proc/sys/kernel/rwlock_reader_limit + +If this is set to zero or negative, than there is no limit. + +Signed-off-by: Steven Rostedt +--- + include/linux/rt_lock.h | 1 + kernel/rtmutex.c | 89 +++++++++++++++++++++++++++++++++++------------- + kernel/sysctl.c | 14 +++++++ + 3 files changed, 80 insertions(+), 24 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/rt_lock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rt_lock.h 2009-02-08 00:04:23.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rt_lock.h 2009-02-08 00:04:24.000000000 -0500 +@@ -64,6 +64,7 @@ struct rw_mutex { + struct task_struct *owner; + struct rt_mutex mutex; + atomic_t count; /* number of times held for read */ ++ atomic_t owners; /* number of owners as readers */ + }; + + /* +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:23.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:24.000000000 -0500 +@@ -997,6 +997,8 @@ __rt_spin_lock_init(spinlock_t *lock, ch + } + EXPORT_SYMBOL(__rt_spin_lock_init); + ++int rt_rwlock_limit; ++ + static inline int rt_release_bkl(struct rt_mutex *lock, unsigned long flags); + static inline void rt_reacquire_bkl(int saved_lock_depth); + +@@ -1070,6 +1072,10 @@ static int try_to_take_rw_read(struct rw + goto taken; + } + ++ /* Check for rwlock limits */ ++ if (rt_rwlock_limit && atomic_read(&rwm->owners) >= rt_rwlock_limit) ++ return 0; ++ + if (mtxowner && mtxowner != RT_RW_READER) { + int mode = mtx ? STEAL_NORMAL : STEAL_LATERAL; + +@@ -1116,6 +1122,7 @@ static int try_to_take_rw_read(struct rw + rt_rwlock_set_owner(rwm, RT_RW_READER, 0); + taken: + if (incr) { ++ atomic_inc(&rwm->owners); + reader_count = current->reader_lock_count++; + if (likely(reader_count < MAX_RWLOCK_DEPTH)) { + current->owned_read_locks[reader_count].lock = rwm; +@@ -1293,6 +1300,7 @@ rt_read_fastlock(struct rw_mutex *rwm, + goto retry; + } + ++ atomic_inc(&rwm->owners); + reader_count = current->reader_lock_count++; + if (likely(reader_count < MAX_RWLOCK_DEPTH)) { + current->owned_read_locks[reader_count].lock = rwm; +@@ -1352,6 +1360,7 @@ retry: + goto retry; + } + ++ atomic_inc(&rwm->owners); + reader_count = current->reader_lock_count++; + if (likely(reader_count < MAX_RWLOCK_DEPTH)) { + current->owned_read_locks[reader_count].lock = rwm; +@@ -1543,6 +1552,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + struct rt_mutex *mutex = &rwm->mutex; + struct rt_mutex_waiter *waiter; + unsigned long flags; ++ unsigned int reader_count; + int savestate = !mtx; + int i; + +@@ -1565,6 +1575,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + if (!current->owned_read_locks[i].count) { + current->reader_lock_count--; + WARN_ON_ONCE(i != current->reader_lock_count); ++ atomic_dec(&rwm->owners); + } + break; + } +@@ -1572,20 +1583,34 @@ rt_read_slowunlock(struct rw_mutex *rwm, + WARN_ON_ONCE(i < 0); + + /* +- * If there are more readers, let the last one do any wakeups. +- * Also check to make sure the owner wasn't cleared when two +- * readers released the lock at the same time, and the count +- * went to zero before grabbing the wait_lock. ++ * If the last two (or more) readers unlocked at the same ++ * time, the owner could be cleared since the count went to ++ * zero. If this has happened, the rwm owner will not ++ * be set to current or readers. This means that another reader ++ * already reset the lock, so there is nothing left to do. + */ +- if (atomic_read(&rwm->count) || +- (rt_rwlock_owner(rwm) != current && +- rt_rwlock_owner(rwm) != RT_RW_READER)) { +- spin_unlock_irqrestore(&mutex->wait_lock, flags); +- return; +- } ++ if ((rt_rwlock_owner(rwm) != current && ++ rt_rwlock_owner(rwm) != RT_RW_READER)) ++ goto out; ++ ++ /* ++ * If there are more readers and we are under the limit ++ * let the last reader do the wakeups. ++ */ ++ reader_count = atomic_read(&rwm->count); ++ if (reader_count && ++ (!rt_rwlock_limit || atomic_read(&rwm->owners) >= rt_rwlock_limit)) ++ goto out; + + /* If no one is blocked, then clear all ownership */ + if (!rt_mutex_has_waiters(mutex)) { ++ /* ++ * If count is not zero, we are under the limit with ++ * no other readers. ++ */ ++ if (reader_count) ++ goto out; ++ + /* We could still have a pending reader waiting */ + if (rt_mutex_owner_pending(mutex)) { + /* set the rwm back to pending */ +@@ -1597,24 +1622,32 @@ rt_read_slowunlock(struct rw_mutex *rwm, + goto out; + } + +- /* We are the last reader with pending waiters. */ ++ /* ++ * If the next waiter is a reader, this can be because of ++ * two things. One is that we hit the reader limit, or ++ * Two, there is a pending writer. ++ * We still only wake up one reader at a time (even if ++ * we could wake up more). This is because we dont ++ * have any idea if a writer is pending. ++ */ + waiter = rt_mutex_top_waiter(mutex); +- if (waiter->write_lock) ++ if (waiter->write_lock) { ++ /* only wake up if there are no readers */ ++ if (reader_count) ++ goto out; + rwm->owner = RT_RW_PENDING_WRITE; +- else ++ } else { ++ /* ++ * It is also possible that the reader limit decreased. ++ * If the limit did decrease, we may not be able to ++ * wake up the reader if we are currently above the limit. ++ */ ++ if (rt_rwlock_limit && ++ unlikely(atomic_read(&rwm->owners) >= rt_rwlock_limit)) ++ goto out; + rwm->owner = RT_RW_PENDING_READ; ++ } + +- /* +- * It is possible to have a reader waiting. We still only +- * wake one up in that case. A way we can have a reader waiting +- * is because a writer woke up, a higher prio reader came +- * and stole the lock from the writer. But the writer now +- * is no longer waiting on the lock and needs to retake +- * the lock. We simply wake up the reader and let the +- * reader have the lock. If the writer comes by, it +- * will steal the lock from the reader. This is the +- * only time we can have a reader pending on a lock. +- */ + wakeup_next_waiter(mutex, savestate); + + out: +@@ -1630,15 +1663,22 @@ rt_read_fastunlock(struct rw_mutex *rwm, + int mtx) + { + WARN_ON(!atomic_read(&rwm->count)); ++ WARN_ON(!atomic_read(&rwm->owners)); + WARN_ON(!rwm->owner); + atomic_dec(&rwm->count); + if (likely(rt_rwlock_cmpxchg(rwm, current, NULL))) { + int reader_count = --current->reader_lock_count; ++ int owners; + rt_mutex_deadlock_account_unlock(current); + if (unlikely(reader_count < 0)) { + reader_count = 0; + WARN_ON_ONCE(1); + } ++ owners = atomic_dec_return(&rwm->owners); ++ if (unlikely(owners < 0)) { ++ atomic_set(&rwm->owners, 0); ++ WARN_ON_ONCE(1); ++ } + WARN_ON_ONCE(current->owned_read_locks[reader_count].lock != rwm); + } else + slowfn(rwm, mtx); +@@ -1789,6 +1829,7 @@ void rt_mutex_rwsem_init(struct rw_mutex + + rwm->owner = NULL; + atomic_set(&rwm->count, 0); ++ atomic_set(&rwm->owners, 0); + + __rt_mutex_init(mutex, name); + } +Index: linux-2.6.24.7-rt27/kernel/sysctl.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sysctl.c 2009-02-08 00:04:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sysctl.c 2009-02-08 00:04:24.000000000 -0500 +@@ -150,6 +150,10 @@ static int parse_table(int __user *, int + void __user *, size_t, struct ctl_table *); + #endif + ++#ifdef CONFIG_PREEMPT_RT ++extern int rt_rwlock_limit; ++#endif ++ + + #ifdef CONFIG_PROC_SYSCTL + static int proc_do_cad_pid(struct ctl_table *table, int write, struct file *filp, +@@ -399,6 +403,16 @@ static struct ctl_table kern_table[] = { + .proc_handler = &proc_dointvec, + }, + #endif ++#ifdef CONFIG_PREEMPT_RT ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "rwlock_reader_limit", ++ .data = &rt_rwlock_limit, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++#endif + { + .ctl_name = KERN_PANIC, + .procname = "panic", --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0096-hrtimers-overrun-api.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0096-hrtimers-overrun-api.patch @@ -0,0 +1,52 @@ +--- + include/linux/hrtimer.h | 3 +++ + kernel/hrtimer.c | 22 ++++++++++++++++++++++ + 2 files changed, 25 insertions(+) + +Index: linux-2.6.24.7-rt27/include/linux/hrtimer.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/hrtimer.h 2009-02-08 00:00:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/hrtimer.h 2009-02-08 00:01:27.000000000 -0500 +@@ -297,6 +297,9 @@ static inline int hrtimer_is_queued(stru + /* Forward a hrtimer so it expires after now: */ + extern unsigned long + hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval); ++/* Overrun count: */ ++extern unsigned long ++hrtimer_overrun(struct hrtimer *timer, ktime_t now, ktime_t interval); + + /* Precise sleep: */ + extern long hrtimer_nanosleep(struct timespec *rqtp, +Index: linux-2.6.24.7-rt27/kernel/hrtimer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/hrtimer.c 2009-02-08 00:01:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/hrtimer.c 2009-02-08 00:01:27.000000000 -0500 +@@ -730,6 +730,28 @@ hrtimer_forward(struct hrtimer *timer, k + } + EXPORT_SYMBOL_GPL(hrtimer_forward); + ++unsigned long ++hrtimer_overrun(struct hrtimer *timer, ktime_t now, ktime_t interval) ++{ ++ unsigned long orun = 1; ++ ktime_t delta; ++ ++ delta = ktime_sub(now, timer->expires); ++ ++ if (delta.tv64 < 0) ++ return 0; ++ ++ if (interval.tv64 < timer->base->resolution.tv64) ++ interval.tv64 = timer->base->resolution.tv64; ++ ++ if (unlikely(delta.tv64 >= interval.tv64)) ++ orun = ktime_divns(delta, ktime_to_ns(interval)) + 1; ++ ++ return orun; ++} ++EXPORT_SYMBOL_GPL(hrtimer_overrun); ++ ++ + /* + * enqueue_hrtimer - internal function to (re)start a timer + * --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0019-0005-sched-pull-RT-tasks-from-overloaded-runqueues.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0019-0005-sched-pull-RT-tasks-from-overloaded-runqueues.patch @@ -0,0 +1,286 @@ +From dffbb24fa9f221779f42ad2a7633608a7d6a2148 Mon Sep 17 00:00:00 2001 +From: Steven Rostedt +Date: Tue, 11 Dec 2007 10:02:37 +0100 +Subject: [PATCH] sched: pull RT tasks from overloaded runqueues + +This patch adds the algorithm to pull tasks from RT overloaded runqueues. + +When a pull RT is initiated, all overloaded runqueues are examined for +a RT task that is higher in prio than the highest prio task queued on the +target runqueue. If another runqueue holds a RT task that is of higher +prio than the highest prio task on the target runqueue is found it is pulled +to the target runqueue. + +Signed-off-by: Steven Rostedt +Signed-off-by: Ingo Molnar + +--- + kernel/sched.c | 2 + kernel/sched_rt.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 178 insertions(+), 11 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:00:51.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:00:51.000000000 -0500 +@@ -3706,6 +3706,8 @@ need_resched_nonpreemptible: + switch_count = &prev->nvcsw; + } + ++ schedule_balance_rt(rq, prev); ++ + if (unlikely(!rq->nr_running)) + idle_balance(cpu, rq); + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:00:51.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:00:51.000000000 -0500 +@@ -175,8 +175,17 @@ static void put_prev_task_rt(struct rq * + static int double_lock_balance(struct rq *this_rq, struct rq *busiest); + static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep); + ++static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu) ++{ ++ if (!task_running(rq, p) && ++ (cpu < 0 || cpu_isset(cpu, p->cpus_allowed))) ++ return 1; ++ return 0; ++} ++ + /* Return the second highest RT task, NULL otherwise */ +-static struct task_struct *pick_next_highest_task_rt(struct rq *rq) ++static struct task_struct *pick_next_highest_task_rt(struct rq *rq, ++ int cpu) + { + struct rt_prio_array *array = &rq->rt.active; + struct task_struct *next; +@@ -195,26 +204,36 @@ static struct task_struct *pick_next_hig + } + + queue = array->queue + idx; ++ BUG_ON(list_empty(queue)); ++ + next = list_entry(queue->next, struct task_struct, run_list); +- if (unlikely(next != rq->curr)) +- return next; ++ if (unlikely(pick_rt_task(rq, next, cpu))) ++ goto out; + + if (queue->next->next != queue) { + /* same prio task */ + next = list_entry(queue->next->next, struct task_struct, run_list); +- return next; ++ if (pick_rt_task(rq, next, cpu)) ++ goto out; + } + ++ retry: + /* slower, but more flexible */ + idx = find_next_bit(array->bitmap, MAX_RT_PRIO, idx+1); +- if (unlikely(idx >= MAX_RT_PRIO)) { +- WARN_ON(1); /* rt_nr_running was 2 and above! */ ++ if (unlikely(idx >= MAX_RT_PRIO)) + return NULL; +- } + + queue = array->queue + idx; +- next = list_entry(queue->next, struct task_struct, run_list); ++ BUG_ON(list_empty(queue)); ++ ++ list_for_each_entry(next, queue, run_list) { ++ if (pick_rt_task(rq, next, cpu)) ++ goto out; ++ } ++ ++ goto retry; + ++ out: + return next; + } + +@@ -301,13 +320,15 @@ static int push_rt_task(struct rq *this_ + + assert_spin_locked(&this_rq->lock); + +- next_task = pick_next_highest_task_rt(this_rq); ++ next_task = pick_next_highest_task_rt(this_rq, -1); + if (!next_task) + return 0; + + retry: +- if (unlikely(next_task == this_rq->curr)) ++ if (unlikely(next_task == this_rq->curr)) { ++ WARN_ON(1); + return 0; ++ } + + /* + * It's possible that the next_task slipped in of +@@ -331,7 +352,7 @@ static int push_rt_task(struct rq *this_ + * so it is possible that next_task has changed. + * If it has, then try again. + */ +- task = pick_next_highest_task_rt(this_rq); ++ task = pick_next_highest_task_rt(this_rq, -1); + if (unlikely(task != next_task) && task && paranoid--) { + put_task_struct(next_task); + next_task = task; +@@ -374,6 +395,149 @@ static void push_rt_tasks(struct rq *rq) + ; + } + ++static int pull_rt_task(struct rq *this_rq) ++{ ++ struct task_struct *next; ++ struct task_struct *p; ++ struct rq *src_rq; ++ cpumask_t *rto_cpumask; ++ int this_cpu = this_rq->cpu; ++ int cpu; ++ int ret = 0; ++ ++ assert_spin_locked(&this_rq->lock); ++ ++ /* ++ * If cpusets are used, and we have overlapping ++ * run queue cpusets, then this algorithm may not catch all. ++ * This is just the price you pay on trying to keep ++ * dirtying caches down on large SMP machines. ++ */ ++ if (likely(!rt_overloaded())) ++ return 0; ++ ++ next = pick_next_task_rt(this_rq); ++ ++ rto_cpumask = rt_overload(); ++ ++ for_each_cpu_mask(cpu, *rto_cpumask) { ++ if (this_cpu == cpu) ++ continue; ++ ++ src_rq = cpu_rq(cpu); ++ if (unlikely(src_rq->rt.rt_nr_running <= 1)) { ++ /* ++ * It is possible that overlapping cpusets ++ * will miss clearing a non overloaded runqueue. ++ * Clear it now. ++ */ ++ if (double_lock_balance(this_rq, src_rq)) { ++ /* unlocked our runqueue lock */ ++ struct task_struct *old_next = next; ++ next = pick_next_task_rt(this_rq); ++ if (next != old_next) ++ ret = 1; ++ } ++ if (likely(src_rq->rt.rt_nr_running <= 1)) ++ /* ++ * Small chance that this_rq->curr changed ++ * but it's really harmless here. ++ */ ++ rt_clear_overload(this_rq); ++ else ++ /* ++ * Heh, the src_rq is now overloaded, since ++ * we already have the src_rq lock, go straight ++ * to pulling tasks from it. ++ */ ++ goto try_pulling; ++ spin_unlock(&src_rq->lock); ++ continue; ++ } ++ ++ /* ++ * We can potentially drop this_rq's lock in ++ * double_lock_balance, and another CPU could ++ * steal our next task - hence we must cause ++ * the caller to recalculate the next task ++ * in that case: ++ */ ++ if (double_lock_balance(this_rq, src_rq)) { ++ struct task_struct *old_next = next; ++ next = pick_next_task_rt(this_rq); ++ if (next != old_next) ++ ret = 1; ++ } ++ ++ /* ++ * Are there still pullable RT tasks? ++ */ ++ if (src_rq->rt.rt_nr_running <= 1) { ++ spin_unlock(&src_rq->lock); ++ continue; ++ } ++ ++ try_pulling: ++ p = pick_next_highest_task_rt(src_rq, this_cpu); ++ ++ /* ++ * Do we have an RT task that preempts ++ * the to-be-scheduled task? ++ */ ++ if (p && (!next || (p->prio < next->prio))) { ++ WARN_ON(p == src_rq->curr); ++ WARN_ON(!p->se.on_rq); ++ ++ /* ++ * There's a chance that p is higher in priority ++ * than what's currently running on its cpu. ++ * This is just that p is wakeing up and hasn't ++ * had a chance to schedule. We only pull ++ * p if it is lower in priority than the ++ * current task on the run queue or ++ * this_rq next task is lower in prio than ++ * the current task on that rq. ++ */ ++ if (p->prio < src_rq->curr->prio || ++ (next && next->prio < src_rq->curr->prio)) ++ goto bail; ++ ++ ret = 1; ++ ++ deactivate_task(src_rq, p, 0); ++ set_task_cpu(p, this_cpu); ++ activate_task(this_rq, p, 0); ++ /* ++ * We continue with the search, just in ++ * case there's an even higher prio task ++ * in another runqueue. (low likelyhood ++ * but possible) ++ */ ++ ++ /* ++ * Update next so that we won't pick a task ++ * on another cpu with a priority lower (or equal) ++ * than the one we just picked. ++ */ ++ next = p; ++ ++ } ++ bail: ++ spin_unlock(&src_rq->lock); ++ } ++ ++ return ret; ++} ++ ++static void schedule_balance_rt(struct rq *rq, ++ struct task_struct *prev) ++{ ++ /* Try to pull RT tasks here if we lower this rq's prio */ ++ if (unlikely(rt_task(prev)) && ++ rq->rt.highest_prio > prev->prio) ++ pull_rt_task(rq); ++} ++ + static void schedule_tail_balance_rt(struct rq *rq) + { + /* +@@ -496,6 +660,7 @@ move_one_task_rt(struct rq *this_rq, int + } + #else /* CONFIG_SMP */ + # define schedule_tail_balance_rt(rq) do { } while (0) ++# define schedule_balance_rt(rq, prev) do { } while (0) + #endif /* CONFIG_SMP */ + + static void task_tick_rt(struct rq *rq, struct task_struct *p) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0550-7cfb0435330364f90f274a26ecdc5f47f738498c.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0550-7cfb0435330364f90f274a26ecdc5f47f738498c.patch @@ -0,0 +1,38 @@ +commit 7cfb0435330364f90f274a26ecdc5f47f738498c +Author: Thomas Gleixner +Date: Wed Sep 3 21:37:24 2008 +0000 + + HPET: make minimum reprogramming delta useful + + The minimum reprogramming delta was hardcoded in HPET ticks, + which is stupid as it does not work with faster running HPETs. + The C1E idle patches made this prominent on AMD/RS690 chipsets, + where the HPET runs with 25MHz. Set it to 5us which seems to be + a reasonable value and fixes the problems on the bug reporters + machines. We have a further sanity check now in the clock events, + which increases the delta when it is not sufficient. + + Signed-off-by: Thomas Gleixner + Tested-by: Luiz Fernando N. Capitulino + Tested-by: Dmitry Nezhevenko + Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/hpet.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/hpet.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/hpet.c 2009-02-07 23:59:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/hpet.c 2009-02-08 00:05:11.000000000 -0500 +@@ -221,8 +221,8 @@ static void hpet_legacy_clockevent_regis + /* Calculate the min / max delta */ + hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, + &hpet_clockevent); +- hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30, +- &hpet_clockevent); ++ /* 5 usec minimum reprogramming delta. */ ++ hpet_clockevent.min_delta_ns = 5000; + + /* + * Start hpet with the boot cpu mask and make it --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0327-lockdep-rt-mutex.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0327-lockdep-rt-mutex.patch @@ -0,0 +1,159 @@ +Subject: lockdep-rt: annotate PREEMPT_RT DEFINE_MUTEX + + +Signed-off-by: Peter Zijlstra +--- + include/linux/mutex.h | 16 ++++++---- + include/linux/rt_lock.h | 70 ++++++++++++++++++++---------------------------- + 2 files changed, 39 insertions(+), 47 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/mutex.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/mutex.h 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/mutex.h 2009-02-08 00:03:26.000000000 -0500 +@@ -18,6 +18,13 @@ + + #include + ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++# define __DEP_MAP_MUTEX_INITIALIZER(lockname) \ ++ , .dep_map = { .name = #lockname } ++#else ++# define __DEP_MAP_MUTEX_INITIALIZER(lockname) ++#endif ++ + #ifdef CONFIG_PREEMPT_RT + + #include +@@ -29,9 +36,11 @@ struct mutex { + #endif + }; + ++ + #define __MUTEX_INITIALIZER(mutexname) \ + { \ + .lock = __RT_MUTEX_INITIALIZER(mutexname.lock) \ ++ __DEP_MAP_MUTEX_INITIALIZER(mutexname) \ + } + + #define DEFINE_MUTEX(mutexname) \ +@@ -141,13 +150,6 @@ do { \ + # define mutex_destroy(mutex) do { } while (0) + #endif + +-#ifdef CONFIG_DEBUG_LOCK_ALLOC +-# define __DEP_MAP_MUTEX_INITIALIZER(lockname) \ +- , .dep_map = { .name = #lockname } +-#else +-# define __DEP_MAP_MUTEX_INITIALIZER(lockname) +-#endif +- + #define __MUTEX_INITIALIZER(lockname) \ + { .count = ATOMIC_INIT(1) \ + , .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) \ +Index: linux-2.6.24.7-rt27/include/linux/rt_lock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rt_lock.h 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rt_lock.h 2009-02-08 00:03:26.000000000 -0500 +@@ -27,30 +27,31 @@ typedef struct { + } spinlock_t; + + #ifdef CONFIG_DEBUG_RT_MUTEXES +-# define __SPIN_LOCK_UNLOCKED(name) \ +- (spinlock_t) { { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name) \ +- , .save_state = 1, .file = __FILE__, .line = __LINE__ }, SPIN_DEP_MAP_INIT(name) } ++# define __RT_SPIN_INITIALIZER(name) \ ++ { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name.wait_lock), \ ++ .save_state = 1, \ ++ .file = __FILE__, \ ++ .line = __LINE__, } + #else +-# define __SPIN_LOCK_UNLOCKED(name) \ +- (spinlock_t) { { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name) }, SPIN_DEP_MAP_INIT(name) } ++# define __RT_SPIN_INITIALIZER(name) \ ++ { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) } + #endif +-# define SPIN_LOCK_UNLOCKED __SPIN_LOCK_UNLOCKED(spin_old_style) ++ ++#define __SPIN_LOCK_UNLOCKED(name) (spinlock_t) \ ++ { .lock = __RT_SPIN_INITIALIZER(name), \ ++ SPIN_DEP_MAP_INIT(name) } ++ + #else /* !PREEMPT_RT */ +- typedef raw_spinlock_t spinlock_t; +-# ifdef CONFIG_DEBUG_SPINLOCK +-# define _SPIN_LOCK_UNLOCKED \ +- { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \ +- .magic = SPINLOCK_MAGIC, \ +- .owner = SPINLOCK_OWNER_INIT, \ +- .owner_cpu = -1 } +-# else +-# define _SPIN_LOCK_UNLOCKED \ +- { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED } +-# endif +-# define SPIN_LOCK_UNLOCKED _SPIN_LOCK_UNLOCKED +-# define __SPIN_LOCK_UNLOCKED(name) _SPIN_LOCK_UNLOCKED ++ ++typedef raw_spinlock_t spinlock_t; ++ ++#define __SPIN_LOCK_UNLOCKED _RAW_SPIN_LOCK_UNLOCKED ++ + #endif + ++#define SPIN_LOCK_UNLOCKED __SPIN_LOCK_UNLOCKED(spin_old_style) ++ ++ + #define __DEFINE_SPINLOCK(name) \ + spinlock_t name = __SPIN_LOCK_UNLOCKED(name) + +@@ -89,32 +90,20 @@ typedef struct { + #endif + } rwlock_t; + +-# ifdef CONFIG_DEBUG_RT_MUTEXES +-# define __RW_LOCK_UNLOCKED(name) (rwlock_t) \ +- { .lock = { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name), \ +- .save_state = 1, .file = __FILE__, .line = __LINE__ } } +-# else +-# define __RW_LOCK_UNLOCKED(name) (rwlock_t) \ +- { .lock = { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name) } } +-# endif ++#define __RW_LOCK_UNLOCKED(name) (rwlock_t) \ ++ { .lock = __RT_SPIN_INITIALIZER(name), \ ++ RW_DEP_MAP_INIT(name) } + #else /* !PREEMPT_RT */ + +- typedef raw_rwlock_t rwlock_t; +-# ifdef CONFIG_DEBUG_SPINLOCK +-# define _RW_LOCK_UNLOCKED \ +- (rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED, \ +- .magic = RWLOCK_MAGIC, \ +- .owner = SPINLOCK_OWNER_INIT, \ +- .owner_cpu = -1 } +-# else +-# define _RW_LOCK_UNLOCKED \ +- (rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED } +-# endif +-# define __RW_LOCK_UNLOCKED(name) _RW_LOCK_UNLOCKED ++typedef raw_rwlock_t rwlock_t; ++ ++#define __RW_LOCK_UNLOCKED _RAW_RW_LOCK_UNLOCKED ++ + #endif + + #define RW_LOCK_UNLOCKED __RW_LOCK_UNLOCKED(rw_old_style) + ++ + #define DEFINE_RWLOCK(name) \ + rwlock_t name __cacheline_aligned_in_smp = __RW_LOCK_UNLOCKED(name) + +@@ -236,7 +225,8 @@ do { \ + */ + + #define __RWSEM_INITIALIZER(name) \ +- { .lock = __RT_MUTEX_INITIALIZER(name.lock) } ++ { .lock = __RT_MUTEX_INITIALIZER(name.lock), \ ++ RW_DEP_MAP_INIT(name) } + + #define DECLARE_RWSEM(lockname) \ + struct rw_semaphore lockname = __RWSEM_INITIALIZER(lockname) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0471-fix_vdso_gtod_vsyscall64_2.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0471-fix_vdso_gtod_vsyscall64_2.patch @@ -0,0 +1,90 @@ +This patch fixes VDSO GTOD enhancements for the case where kernel.vsyscall64=2. +In this case VDSO GTOD presents a cheap way to access gettimeofday() with no +need to issue a real system call. This fix enforces the 1ms resolution VDSO +GTOD should present when kernel.vsyscall64=2. + +This patch offers this resolution for the clocksources that have a vread() +function, such as tsc and hpet. Otherwise it keeps uses the read() function +offered by the clocksource, that may be costly. + +Also, a few other tweaks are performed. + +Signed-off-by: Luis Claudio R. Goncalves + +--- + arch/x86/kernel/vsyscall_64.c | 35 +++++++++++++++++++++++++++++++---- + 1 file changed, 31 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/vsyscall_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/vsyscall_64.c 2009-02-08 00:03:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/vsyscall_64.c 2009-02-08 00:04:34.000000000 -0500 +@@ -74,14 +74,40 @@ void update_vsyscall(struct timespec *wa + unsigned long flags; + + write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags); ++ ++ if (likely(vsyscall_gtod_data.sysctl_enabled == 2)) { ++ struct timespec tmp = *(wall_time); ++ cycle_t (*vread)(void); ++ cycle_t now; ++ ++ vread = vsyscall_gtod_data.clock.vread; ++ if (likely(vread)) ++ now = vread(); ++ else ++ now = clock->read(); ++ ++ /* calculate interval: */ ++ now = (now - clock->cycle_last) & clock->mask; ++ /* convert to nsecs: */ ++ tmp.tv_nsec += ( now * clock->mult) >> clock->shift; ++ ++ while (tmp.tv_nsec >= NSEC_PER_SEC) { ++ tmp.tv_sec += 1; ++ tmp.tv_nsec -= NSEC_PER_SEC; ++ } ++ ++ vsyscall_gtod_data.wall_time_sec = tmp.tv_sec; ++ vsyscall_gtod_data.wall_time_nsec = tmp.tv_nsec; ++ } else { ++ vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; ++ vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; ++ } + /* copy vsyscall data */ + vsyscall_gtod_data.clock.vread = clock->vread; + vsyscall_gtod_data.clock.cycle_last = clock->cycle_last; + vsyscall_gtod_data.clock.mask = clock->mask; + vsyscall_gtod_data.clock.mult = clock->mult; + vsyscall_gtod_data.clock.shift = clock->shift; +- vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; +- vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; + vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic; + write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); + } +@@ -134,7 +160,8 @@ static __always_inline void do_vgettimeo + } while (tmp.tv_usec != tv->tv_usec || + tmp.tv_sec != tv->tv_sec); + +- tv->tv_usec /= NSEC_PER_USEC; ++ tv->tv_usec /= NSEC_PER_MSEC; ++ tv->tv_usec *= USEC_PER_MSEC; + return; + } + +@@ -146,7 +173,6 @@ static __always_inline void do_vgettimeo + gettimeofday(tv,NULL); + return; + } +- now = vread(); + base = __vsyscall_gtod_data.clock.cycle_last; + mask = __vsyscall_gtod_data.clock.mask; + mult = __vsyscall_gtod_data.clock.mult; +@@ -156,6 +182,7 @@ static __always_inline void do_vgettimeo + nsec = __vsyscall_gtod_data.wall_time_nsec; + } while (read_seqretry(&__vsyscall_gtod_data.lock, seq)); + ++ now = vread(); + /* calculate interval: */ + cycle_delta = (now - base) & mask; + /* convert to nsecs: */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0445-adaptive-spinlock-lite-v2.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0445-adaptive-spinlock-lite-v2.patch @@ -0,0 +1,178 @@ +From: Steven Rostedt +Subject: adaptive spinlocks lite + +After talking with Gregory Haskins about how they implemented his +version of adaptive spinlocks and before I actually looked at their +code, I was thinking about it while lying in bed. + +I always thought that adaptive spinlocks were to spin for a short +period of time based off of some heuristic and then sleep. This idea +is totally bogus. No heuristic can account for a bunch of different +activities. But Gregory mentioned something to me that made a hell of a lot +of sense. And that is to only spin while the owner is running. + +If the owner is running, then it would seem that it would be quicker to +spin then to take the scheduling hit. While lying awake in bed, it dawned +on me that we could simply spin in the fast lock and never touch the +"has waiters" flag, which would keep the owner from going into the +slow path. Also, the task itself is preemptible while spinning so this +would not affect latencies. + +The only trick was to not have the owner get freed between the time +you saw the owner and the time you check its run queue. This was +easily solved by simply grabing the RCU read lock because freeing +of a task must happen after a grace period. + +I first tried to stay only in the fast path. This works fine until you want +to guarantee that the highest prio task gets the lock next. I tried all +sorts of hackeries and found that there was too many cases where we can +miss. I finally concurred with Gregory, and decided that going into the +slow path was the way to go. + +I then started looking into what the guys over at Novell did. The had the +basic idea correct, but went way overboard in the implementation, making +it far more complex than it needed to be. I rewrote their work using the +ideas from my original patch, and simplified it quite a bit. + +This is the patch that they wanted to do ;-) + +Special thanks goes out to Gregory Haskins, Sven Dietrich and +Peter Morreale, for proving that adaptive spin locks certainly *can* +make a difference. + +Signed-off-by: Steven Rostedt +--- + include/linux/sched.h | 2 + + kernel/rtmutex.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++--- + kernel/sched.c | 5 +++ + 3 files changed, 68 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:04:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:04:22.000000000 -0500 +@@ -2217,6 +2217,8 @@ static inline void migration_init(void) + } + #endif + ++extern int task_is_current(struct task_struct *task); ++ + #define TASK_STATE_TO_CHAR_STR "RMSDTtZX" + + #endif /* __KERNEL__ */ +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:21.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:22.000000000 -0500 +@@ -8,6 +8,12 @@ + * Copyright (C) 2005 Kihon Technologies Inc., Steven Rostedt + * Copyright (C) 2006 Esben Nielsen + * ++ * Adaptive Spinlocks: ++ * Copyright (C) 2008 Novell, Inc., Gregory Haskins, Sven Dietrich, ++ * and Peter Morreale, ++ * Adaptive Spinlocks simplification: ++ * Copyright (C) 2008 Red Hat, Inc., Steven Rostedt ++ * + * See Documentation/rt-mutex-design.txt for details. + */ + #include +@@ -674,6 +680,54 @@ update_current(unsigned long new_state, + *saved_state = TASK_RUNNING; + } + ++#ifdef CONFIG_SMP ++static int adaptive_wait(struct rt_mutex_waiter *waiter, ++ struct task_struct *orig_owner) ++{ ++ int sleep = 0; ++ ++ for (;;) { ++ ++ /* we are the owner? */ ++ if (!waiter->task) ++ break; ++ ++ /* ++ * We need to read the owner of the lock and then check ++ * its state. But we can't let the owner task be freed ++ * while we read the state. We grab the rcu_lock and ++ * this makes sure that the owner task wont disappear ++ * between testing that it still has the lock, and checking ++ * its state. ++ */ ++ rcu_read_lock(); ++ /* Owner changed? Then lets update the original */ ++ if (orig_owner != rt_mutex_owner(waiter->lock)) { ++ rcu_read_unlock(); ++ break; ++ } ++ ++ /* Owner went to bed, so should we */ ++ if (!task_is_current(orig_owner)) { ++ sleep = 1; ++ rcu_read_unlock(); ++ break; ++ } ++ rcu_read_unlock(); ++ ++ cpu_relax(); ++ } ++ ++ return sleep; ++} ++#else ++static int adaptive_wait(struct rt_mutex_waiter *waiter, ++ struct task_struct *orig_owner) ++{ ++ return 1; ++} ++#endif ++ + /* + * Slow path lock function spin_lock style: this variant is very + * careful not to miss any non-lock wakeups. +@@ -689,6 +743,7 @@ rt_spin_lock_slowlock(struct rt_mutex *l + { + struct rt_mutex_waiter waiter; + unsigned long saved_state, state, flags; ++ struct task_struct *orig_owner; + + debug_rt_mutex_init_waiter(&waiter); + waiter.task = NULL; +@@ -741,13 +796,16 @@ rt_spin_lock_slowlock(struct rt_mutex *l + saved_flags = current->flags & PF_NOSCHED; + current->lock_depth = -1; + current->flags &= ~PF_NOSCHED; ++ orig_owner = rt_mutex_owner(lock); + spin_unlock_irqrestore(&lock->wait_lock, flags); + + debug_rt_mutex_print_deadlock(&waiter); + +- update_current(TASK_UNINTERRUPTIBLE, &saved_state); +- if (waiter.task) +- schedule_rt_mutex(lock); ++ if (adaptive_wait(&waiter, orig_owner)) { ++ update_current(TASK_UNINTERRUPTIBLE, &saved_state); ++ if (waiter.task) ++ schedule_rt_mutex(lock); ++ } + + spin_lock_irqsave(&lock->wait_lock, flags); + current->flags |= saved_flags; +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:04:15.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:04:22.000000000 -0500 +@@ -573,6 +573,11 @@ int runqueue_is_locked(void) + return ret; + } + ++int task_is_current(struct task_struct *task) ++{ ++ return task_rq(task)->curr == task; ++} ++ + /* + * Debugging: various feature bits + */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0556-61c22c34c6f80a8e89cff5ff717627c54cc14fd4.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0556-61c22c34c6f80a8e89cff5ff717627c54cc14fd4.patch @@ -0,0 +1,55 @@ +commit 61c22c34c6f80a8e89cff5ff717627c54cc14fd4 +Author: Thomas Gleixner +Date: Tue Sep 9 21:38:57 2008 +0200 + + clockevents: remove WARN_ON which was used to gather information + + The issue of the endless reprogramming loop due to a too small + min_delta_ns was fixed with the previous updates of the clock events + code, but we had no information about the spread of this problem. I + added a WARN_ON to get automated information via kerneloops.org and to + get some direct reports, which allowed me to analyse the affected + machines. + + The WARN_ON has served its purpose and would be annoying for a release + kernel. Remove it and just keep the information about the increase of + the min_delta_ns value. + + Signed-off-by: Thomas Gleixner + +--- + kernel/time/tick-oneshot.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/time/tick-oneshot.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-oneshot.c 2009-02-08 00:05:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-oneshot.c 2009-02-08 00:05:14.000000000 -0500 +@@ -43,19 +43,17 @@ int tick_dev_program_event(struct clock_ + * and emit a warning. + */ + if (++i > 2) { +- printk(KERN_WARNING "CE: __tick_program_event of %s is " +- "stuck %llx %llx\n", dev->name ? dev->name : "?", +- now.tv64, expires.tv64); +- printk(KERN_WARNING +- "CE: increasing min_delta_ns %ld to %ld nsec\n", +- dev->min_delta_ns, dev->min_delta_ns << 1); +- WARN_ON(1); +- +- /* Double the min. delta and try again */ ++ /* Increase the min. delta and try again */ + if (!dev->min_delta_ns) + dev->min_delta_ns = 5000; + else +- dev->min_delta_ns <<= 1; ++ dev->min_delta_ns += dev->min_delta_ns >> 1; ++ ++ printk(KERN_WARNING ++ "CE: %s increasing min_delta_ns to %lu nsec\n", ++ dev->name ? dev->name : "?", ++ dev->min_delta_ns << 1); ++ + i = 0; + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0047-0035-sched-add-credits-for-RT-balancing-improvements.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0047-0035-sched-add-credits-for-RT-balancing-improvements.patch @@ -0,0 +1,26 @@ +From ce3b1244b9da66db0c51602a59bf1e4de9a75686 Mon Sep 17 00:00:00 2001 +From: Ingo Molnar +Date: Tue, 11 Dec 2007 10:02:46 +0100 +Subject: [PATCH] sched: add credits for RT balancing improvements + +add credits for RT balancing improvements. + +Signed-off-by: Ingo Molnar + +--- + kernel/sched.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:01:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:01:05.000000000 -0500 +@@ -22,6 +22,8 @@ + * by Peter Williams + * 2007-05-06 Interactivity improvements to CFS by Mike Galbraith + * 2007-07-01 Group scheduling enhancements by Srivatsa Vaddagiri ++ * 2007-11-29 RT balancing improvements by Steven Rostedt, Gregory Haskins, ++ * Thomas Gleixner, Mike Kravetz + */ + + #include --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0301-pagefault-disable-cleanup.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0301-pagefault-disable-cleanup.patch @@ -0,0 +1,185 @@ +Subject: [patch] clean up the page fault disabling logic +From: Ingo Molnar + +decouple the pagefault-disabled logic from the preempt count. + +Signed-off-by: Ingo Molnar +--- + arch/arm/mm/fault.c | 2 +- + arch/mips/mm/fault.c | 2 +- + arch/powerpc/mm/fault.c | 2 +- + arch/x86/mm/fault_32.c | 2 +- + arch/x86/mm/fault_64.c | 2 +- + include/linux/sched.h | 1 + + include/linux/uaccess.h | 33 +++------------------------------ + kernel/fork.c | 1 + + mm/memory.c | 22 ++++++++++++++++++++++ + 9 files changed, 32 insertions(+), 35 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/arm/mm/fault.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mm/fault.c 2009-02-08 00:01:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mm/fault.c 2009-02-08 00:03:13.000000000 -0500 +@@ -229,7 +229,7 @@ do_page_fault(unsigned long addr, unsign + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ +- if (in_atomic() || !mm) ++ if (in_atomic() || !mm || current->pagefault_disabled) + goto no_context; + + /* +Index: linux-2.6.24.7-rt27/arch/mips/mm/fault.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/mm/fault.c 2009-02-07 23:59:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/mm/fault.c 2009-02-08 00:03:13.000000000 -0500 +@@ -69,7 +69,7 @@ asmlinkage void do_page_fault(struct pt_ + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ +- if (in_atomic() || !mm) ++ if (in_atomic() || !mm || current->pagefault_disabled) + goto bad_area_nosemaphore; + + down_read(&mm->mmap_sem); +Index: linux-2.6.24.7-rt27/arch/powerpc/mm/fault.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/mm/fault.c 2009-02-07 23:59:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/mm/fault.c 2009-02-08 00:03:13.000000000 -0500 +@@ -184,7 +184,7 @@ int __kprobes do_page_fault(struct pt_re + } + #endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/ + +- if (in_atomic() || mm == NULL) { ++ if (in_atomic() || mm == NULL || current->pagefault_disabled) { + if (!user_mode(regs)) + return SIGSEGV; + /* in_atomic() in user mode is really bad, +Index: linux-2.6.24.7-rt27/arch/x86/mm/fault_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/mm/fault_32.c 2009-02-08 00:02:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/mm/fault_32.c 2009-02-08 00:03:13.000000000 -0500 +@@ -358,7 +358,7 @@ fastcall void __kprobes do_page_fault(st + * If we're in an interrupt, have no user context or are running in an + * atomic region then we must not take the fault.. + */ +- if (in_atomic() || !mm) ++ if (in_atomic() || !mm || current->pagefault_disabled) + goto bad_area_nosemaphore; + + /* When running in the kernel we expect faults to occur only to +Index: linux-2.6.24.7-rt27/arch/x86/mm/fault_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/mm/fault_64.c 2009-02-08 00:01:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/mm/fault_64.c 2009-02-08 00:03:13.000000000 -0500 +@@ -369,7 +369,7 @@ asmlinkage void __kprobes do_page_fault( + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ +- if (unlikely(in_atomic() || !mm)) ++ if (unlikely(in_atomic() || !mm || current->pagefault_disabled)) + goto bad_area_nosemaphore; + + /* +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:02:55.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:03:13.000000000 -0500 +@@ -1179,6 +1179,7 @@ struct task_struct { + /* mutex deadlock detection */ + struct mutex_waiter *blocked_on; + #endif ++ int pagefault_disabled; + #ifdef CONFIG_TRACE_IRQFLAGS + unsigned int irq_events; + int hardirqs_enabled; +Index: linux-2.6.24.7-rt27/include/linux/uaccess.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/uaccess.h 2009-02-07 23:59:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/uaccess.h 2009-02-08 00:03:13.000000000 -0500 +@@ -6,37 +6,10 @@ + + /* + * These routines enable/disable the pagefault handler in that +- * it will not take any locks and go straight to the fixup table. +- * +- * They have great resemblance to the preempt_disable/enable calls +- * and in fact they are identical; this is because currently there is +- * no other way to make the pagefault handlers do this. So we do +- * disable preemption but we don't necessarily care about that. ++ * it will not take any MM locks and go straight to the fixup table. + */ +-static inline void pagefault_disable(void) +-{ +- inc_preempt_count(); +- /* +- * make sure to have issued the store before a pagefault +- * can hit. +- */ +- barrier(); +-} +- +-static inline void pagefault_enable(void) +-{ +- /* +- * make sure to issue those last loads/stores before enabling +- * the pagefault handler again. +- */ +- barrier(); +- dec_preempt_count(); +- /* +- * make sure we do.. +- */ +- barrier(); +- preempt_check_resched(); +-} ++extern void pagefault_disable(void); ++extern void pagefault_enable(void); + + #ifndef ARCH_HAS_NOCACHE_UACCESS + +Index: linux-2.6.24.7-rt27/kernel/fork.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/fork.c 2009-02-08 00:02:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/fork.c 2009-02-08 00:03:13.000000000 -0500 +@@ -1158,6 +1158,7 @@ static struct task_struct *copy_process( + p->hardirq_context = 0; + p->softirq_context = 0; + #endif ++ p->pagefault_disabled = 0; + #ifdef CONFIG_LOCKDEP + p->lockdep_depth = 0; /* no locks held yet */ + p->curr_chain_key = 0; +Index: linux-2.6.24.7-rt27/mm/memory.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/memory.c 2009-02-08 00:02:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/memory.c 2009-02-08 00:03:13.000000000 -0500 +@@ -2613,6 +2613,28 @@ unlock: + return 0; + } + ++void pagefault_disable(void) ++{ ++ current->pagefault_disabled++; ++ /* ++ * make sure to have issued the store before a pagefault ++ * can hit. ++ */ ++ barrier(); ++} ++EXPORT_SYMBOL(pagefault_disable); ++ ++void pagefault_enable(void) ++{ ++ /* ++ * make sure to issue those last loads/stores before enabling ++ * the pagefault handler again. ++ */ ++ barrier(); ++ current->pagefault_disabled--; ++} ++EXPORT_SYMBOL(pagefault_enable); ++ + /* + * By the time we get here, we already hold the mm semaphore + */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0136-m68knommu-make-cmpxchg-RT-safe.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0136-m68knommu-make-cmpxchg-RT-safe.patch @@ -0,0 +1,58 @@ +From fb918e8b87e699c8174d8f7fbff1ab558c7389b0 Mon Sep 17 00:00:00 2001 +From: Sebastian Siewior +Date: Fri, 18 Apr 2008 17:02:29 +0200 +Subject: [PATCH] m68knommu: make cmpxchg RT-safe + +Signed-off-by: Sebastian Siewior +Signed-off-by: Thomas Gleixner +--- + include/asm-m68knommu/system.h | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/system.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/system.h 2009-02-08 00:01:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/system.h 2009-02-08 00:01:46.000000000 -0500 +@@ -2,9 +2,10 @@ + #define _M68KNOMMU_SYSTEM_H + + #include ++#include ++#include + #include + #include +- + /* + * switch_to(n) should switch tasks to task ptr, first checking that + * ptr isn't the current task, in which case it does nothing. This +@@ -128,7 +129,7 @@ static inline unsigned long __xchg(unsig + { + unsigned long tmp, flags; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + + switch (size) { + case 1: +@@ -150,7 +151,7 @@ static inline unsigned long __xchg(unsig + : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + } +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + return tmp; + } + #else +@@ -203,10 +204,10 @@ __cmpxchg(volatile void *ptr, unsigned l + + if (size == 4) { + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + if ((prev = *p) == old) + *p = new; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + return prev; + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0401-use-edge-triggered-irq-handler-instead-of-simple-irq.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0401-use-edge-triggered-irq-handler-instead-of-simple-irq.patch @@ -0,0 +1,67 @@ +From: Remy Bohmer +Subject: [AT91: PATCH]: Use edge triggered interrupt handling for AT91-GPIO instead of simple_irq-handler + +On ARM there is a problem where the interrupt handler stalls when they are +coming faster than the kernel can handle. +The problem seems to occur on RT primarily, but the problem is also valid for +non-RT kernels. + +The problem is twofold: +* the handle_simple_irq() mechanism is used for GPIO, but because the GPIO +interrupt source is actually an edge triggered interrupt source, the +handle_edge_irq() mechanism must be used. While using the simple_irq() +mechanisms edges can be missed for either mainline as RT kernels. +The simple_irq mechanism is *never* meant to be used for these types +of interrupts. See the thread at: http://lkml.org/lkml/2007/11/26/73 +* The RT kernels has a problem that the interrupt get masked forever while +the interrupt thread is running and a new interrupt arrives. +In the interrupt threads there is masking done in the handle_simple_irq() +path, while a simple_irq typically cannot be masked. + +This patch only solves the first bullet, which is enough for AT91, by +moving the GPIO interrupt handler towards the handle_edge_irq(). +To solve the problem in the simple_irq() path a seperate fix has to be done, +but as it is no longer used by AT91, that fix will not affect AT91. + +Tested on: +* AT91rm9200-ek, and proprietary board +* AT91SAM9261-ek. (This patches also solves the problem that the DM9000 does + not work on this board while using PREEMPT-RT) + +Signed-off-by: Remy Bohmer +--- + arch/arm/mach-at91/gpio.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/arm/mach-at91/gpio.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mach-at91/gpio.c 2009-02-07 23:59:44.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mach-at91/gpio.c 2009-02-08 00:04:00.000000000 -0500 +@@ -362,12 +362,18 @@ static int gpio_irq_type(unsigned pin, u + return (type == IRQT_BOTHEDGE) ? 0 : -EINVAL; + } + ++static void gpio_irq_ack_noop(unsigned int irq) ++{ ++ /* Dummy function. */ ++} ++ + static struct irq_chip gpio_irqchip = { + .name = "GPIO", + .mask = gpio_irq_mask, + .unmask = gpio_irq_unmask, + .set_type = gpio_irq_type, + .set_wake = gpio_irq_set_wake, ++ .ack = gpio_irq_ack_noop, + }; + + static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) +@@ -442,7 +448,7 @@ void __init at91_gpio_irq_setup(void) + * shorter, and the AIC handles interrupts sanely. + */ + set_irq_chip(pin, &gpio_irqchip); +- set_irq_handler(pin, handle_simple_irq); ++ set_irq_handler(pin, handle_edge_irq); + set_irq_flags(pin, IRQF_VALID); + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0388-filemap-dont-bug-non-atomic.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0388-filemap-dont-bug-non-atomic.patch @@ -0,0 +1,18 @@ +--- + mm/filemap.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: linux-2.6.24.7-rt27/mm/filemap.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/filemap.c 2009-02-08 00:03:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/filemap.c 2009-02-08 00:03:55.000000000 -0500 +@@ -1763,7 +1763,9 @@ size_t iov_iter_copy_from_user_atomic(st + char *kaddr; + size_t copied; + ++#ifndef CONFIG_PREEMPT_RT + BUG_ON(!in_atomic()); ++#endif + kaddr = kmap_atomic(page, KM_USER0); + if (likely(i->nr_segs == 1)) { + int left; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0141-preempt-irqs-direct-debug-keyboard.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0141-preempt-irqs-direct-debug-keyboard.patch @@ -0,0 +1,94 @@ +--- + include/linux/sched.h | 6 ++++++ + init/main.c | 2 ++ + kernel/irq/handle.c | 31 +++++++++++++++++++++++++++++++ + 3 files changed, 39 insertions(+) + +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:01:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:01:50.000000000 -0500 +@@ -271,6 +271,12 @@ extern void account_process_tick(struct + extern void update_process_times(int user); + extern void scheduler_tick(void); + ++#ifdef CONFIG_GENERIC_HARDIRQS ++extern int debug_direct_keyboard; ++#else ++# define debug_direct_keyboard 0 ++#endif ++ + #ifdef CONFIG_DETECT_SOFTLOCKUP + extern void softlockup_tick(void); + extern void spawn_softlockup_task(void); +Index: linux-2.6.24.7-rt27/init/main.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/init/main.c 2009-02-08 00:01:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/init/main.c 2009-02-08 00:01:50.000000000 -0500 +@@ -858,5 +858,7 @@ static int __init kernel_init(void * unu + * initmem segments and start the user-mode stuff.. + */ + init_post(); ++ WARN_ON(debug_direct_keyboard); ++ + return 0; + } +Index: linux-2.6.24.7-rt27/kernel/irq/handle.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/irq/handle.c 2009-02-08 00:01:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/irq/handle.c 2009-02-08 00:01:50.000000000 -0500 +@@ -132,6 +132,11 @@ irqreturn_t handle_IRQ_event(unsigned in + irqreturn_t ret, retval = IRQ_NONE; + unsigned int status = 0; + ++#ifdef __i386__ ++ if (debug_direct_keyboard && irq == 1) ++ lockdep_off(); ++#endif ++ + handle_dynamic_tick(action); + + /* +@@ -163,9 +168,30 @@ irqreturn_t handle_IRQ_event(unsigned in + } + local_irq_disable(); + ++#ifdef __i386__ ++ if (debug_direct_keyboard && irq == 1) ++ lockdep_on(); ++#endif + return retval; + } + ++/* ++ * Hack - used for development only. ++ */ ++int __read_mostly debug_direct_keyboard = 0; ++ ++int __init debug_direct_keyboard_setup(char *str) ++{ ++ debug_direct_keyboard = 1; ++ printk(KERN_INFO "Switching IRQ 1 (keyboard) to to direct!\n"); ++#ifdef CONFIG_PREEMPT_RT ++ printk(KERN_INFO "WARNING: kernel may easily crash this way!\n"); ++#endif ++ return 1; ++} ++ ++__setup("debug_direct_keyboard", debug_direct_keyboard_setup); ++ + int redirect_hardirq(struct irq_desc *desc) + { + /* +@@ -175,6 +201,11 @@ int redirect_hardirq(struct irq_desc *de + !desc->thread) + return 0; + ++#ifdef __i386__ ++ if (debug_direct_keyboard && (desc - irq_desc == 1)) ++ return 0; ++#endif ++ + BUG_ON(!irqs_disabled()); + if (desc->thread && desc->thread->state != TASK_RUNNING) + wake_up_process(desc->thread); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0517-ftrace-call-function-pointer.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0517-ftrace-call-function-pointer.patch @@ -0,0 +1,26 @@ +Date: Tue, 15 Jul 2008 08:09:29 -0700 +From: Josh Triplett +Subject: [PATCH] ftrace: Actually call function pointer in ftrace_stop + +ftrace_stop used a function pointed as a no-op expression, rather than +actually calling it. + +Signed-off-by: Josh Triplett +Signed-off-by: Thomas Gleixner +--- + kernel/trace/trace.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/trace/trace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace.c 2009-02-08 00:04:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace.c 2009-02-08 00:04:56.000000000 -0500 +@@ -3268,7 +3268,7 @@ void ftrace_stop(void) + if (tr->ctrl) { + tr->ctrl = 0; + if (saved_tracer && saved_tracer->ctrl_update) +- saved_tracer->ctrl_update; ++ saved_tracer->ctrl_update(tr); + } + + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0384-lock-init-plist-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0384-lock-init-plist-fix.patch @@ -0,0 +1,70 @@ +From jan.kiszka@siemens.com Fri Oct 26 22:37:46 2007 +Date: Fri, 26 Oct 2007 17:38:19 +0200 +From: Jan Kiszka +To: linux-kernel@vger.kernel.org +Cc: Thomas Gleixner , Ingo Molnar +Subject: [PATCH] Fix plist initialisation for CONFIG_DEBUG_PI_LIST +Resent-Date: Fri, 26 Oct 2007 18:38:07 +0200 (CEST) +Resent-From: Thomas Gleixner +Resent-To: Steven Rostedt +Resent-Subject: [PATCH] Fix plist initialisation for CONFIG_DEBUG_PI_LIST + + [ The following text is in the "ISO-8859-15" character set. ] + [ Your display is set for the "iso-8859-1" character set. ] + [ Some special characters may be displayed incorrectly. ] + +PLIST_NODE_INIT (once used, only in -rt ATM) will fail when +CONFIG_DEBUG_PI_LIST is enabled as it then generates a &NULL +statement. This patch fixes the issue indirectly by turning +the _lock argument of PLIST_HEAD_INIT into a pointer and +adopting its users. + +Signed-off-by: Jan Kiszka + +--- + include/linux/plist.h | 4 ++-- + include/linux/rtmutex.h | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/plist.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/plist.h 2009-02-08 00:03:50.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/plist.h 2009-02-08 00:03:54.000000000 -0500 +@@ -99,13 +99,13 @@ struct plist_node { + /** + * PLIST_HEAD_INIT - static struct plist_head initializer + * @head: struct plist_head variable name +- * @_lock: lock to initialize for this list ++ * @_lock: lock * to initialize for this list + */ + #define PLIST_HEAD_INIT(head, _lock) \ + { \ + .prio_list = LIST_HEAD_INIT((head).prio_list), \ + .node_list = LIST_HEAD_INIT((head).node_list), \ +- PLIST_HEAD_LOCK_INIT(&(_lock)) \ ++ PLIST_HEAD_LOCK_INIT(_lock) \ + } + + /** +Index: linux-2.6.24.7-rt27/include/linux/rtmutex.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rtmutex.h 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rtmutex.h 2009-02-08 00:03:54.000000000 -0500 +@@ -64,7 +64,7 @@ struct hrtimer_sleeper; + + #define __RT_MUTEX_INITIALIZER(mutexname) \ + { .wait_lock = RAW_SPIN_LOCK_UNLOCKED(mutexname) \ +- , .wait_list = PLIST_HEAD_INIT(mutexname.wait_list, mutexname.wait_lock) \ ++ , .wait_list = PLIST_HEAD_INIT(mutexname.wait_list, &mutexname.wait_lock) \ + , .owner = NULL \ + __DEBUG_RT_MUTEX_INITIALIZER(mutexname)} + +@@ -98,7 +98,7 @@ extern void rt_mutex_unlock(struct rt_mu + + #ifdef CONFIG_RT_MUTEXES + # define INIT_RT_MUTEXES(tsk) \ +- .pi_waiters = PLIST_HEAD_INIT(tsk.pi_waiters, tsk.pi_lock), \ ++ .pi_waiters = PLIST_HEAD_INIT(tsk.pi_waiters, &tsk.pi_lock), \ + INIT_RT_MUTEX_DEBUG(tsk) + #else + # define INIT_RT_MUTEXES(tsk) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0424-printk-in-atomic-hack-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0424-printk-in-atomic-hack-fix.patch @@ -0,0 +1,45 @@ +From: Steven Rostedt +Subject: fix printk in atomic hack + +The printk in atomic hack had a slight bug. This but was triggered +by debug locking options. The hack prevents grabbing sleeping spin +locks in printk console drivers if we are in atomic (can't sleep). +But the unlock had a bug where it incorrectely assumed that if +we are in printk and atomic, that we didn't grab the lock. The debug +locking can encapsulate these options and cause unlocks to be in atomic +when the lock was not. This means we would not release the lock after +it was taken. + +The patch only skips releasing the lock if in printk - atomic *and* +not the lock owner. + +Special thanks goes to Jon Masters for digging his head deep into +this crap and narrowing it down to a problem with printks and locks. + +Signed-off-by: Steven Rostedt +--- + kernel/rtmutex.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:03:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:13.000000000 -0500 +@@ -634,7 +634,7 @@ rt_spin_lock_fastlock(struct rt_mutex *l + void fastcall (*slowfn)(struct rt_mutex *lock)) + { + /* Temporary HACK! */ +- if (!current->in_printk) ++ if (likely(!current->in_printk)) + might_sleep(); + else if (in_atomic() || irqs_disabled()) + /* don't grab locks for printk in atomic */ +@@ -651,7 +651,7 @@ rt_spin_lock_fastunlock(struct rt_mutex + void fastcall (*slowfn)(struct rt_mutex *lock)) + { + /* Temporary HACK! */ +- if (current->in_printk && (in_atomic() || irqs_disabled())) ++ if (unlikely(rt_mutex_owner(lock) != current) && current->in_printk) + /* don't grab locks for printk in atomic */ + return; + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0143-preempt-irqs-hrtimer.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0143-preempt-irqs-hrtimer.patch @@ -0,0 +1,148 @@ + include/linux/hrtimer.h | 10 ++++++++++ + kernel/hrtimer.c | 35 ++++++++++++++++++++++++++++++++++- + kernel/itimer.c | 1 + + kernel/posix-timers.c | 3 +++ + 4 files changed, 48 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/include/linux/hrtimer.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/hrtimer.h 2009-02-08 00:01:27.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/hrtimer.h 2009-02-08 00:01:51.000000000 -0500 +@@ -200,6 +200,9 @@ struct hrtimer_cpu_base { + struct list_head cb_pending; + unsigned long nr_events; + #endif ++#ifdef CONFIG_PREEMPT_SOFTIRQS ++ wait_queue_head_t wait; ++#endif + }; + + #ifdef CONFIG_HIGH_RES_TIMERS +@@ -270,6 +273,13 @@ static inline int hrtimer_restart(struct + return hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS); + } + ++/* Softirq preemption could deadlock timer removal */ ++#ifdef CONFIG_PREEMPT_SOFTIRQS ++ extern void hrtimer_wait_for_timer(const struct hrtimer *timer); ++#else ++# define hrtimer_wait_for_timer(timer) do { cpu_relax(); } while (0) ++#endif ++ + /* Query timers: */ + extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer); + extern int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp); +Index: linux-2.6.24.7-rt27/kernel/hrtimer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/hrtimer.c 2009-02-08 00:01:27.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/hrtimer.c 2009-02-08 00:01:51.000000000 -0500 +@@ -989,7 +989,7 @@ int hrtimer_cancel(struct hrtimer *timer + + if (ret >= 0) + return ret; +- cpu_relax(); ++ hrtimer_wait_for_timer(timer); + } + } + EXPORT_SYMBOL_GPL(hrtimer_cancel); +@@ -1100,6 +1100,32 @@ int hrtimer_get_res(const clockid_t whic + } + EXPORT_SYMBOL_GPL(hrtimer_get_res); + ++#ifdef CONFIG_PREEMPT_SOFTIRQS ++# define wake_up_timer_waiters(b) wake_up(&(b)->wait) ++ ++/** ++ * hrtimer_wait_for_timer - Wait for a running timer ++ * ++ * @timer: timer to wait for ++ * ++ * The function waits in case the timers callback function is ++ * currently executed on the waitqueue of the timer base. The ++ * waitqueue is woken up after the timer callback function has ++ * finished execution. ++ */ ++void hrtimer_wait_for_timer(const struct hrtimer *timer) ++{ ++ struct hrtimer_clock_base *base = timer->base; ++ ++ if (base && base->cpu_base) ++ wait_event(base->cpu_base->wait, ++ !(timer->state & HRTIMER_STATE_CALLBACK)); ++} ++ ++#else ++# define wake_up_timer_waiters(b) do { } while (0) ++#endif ++ + #ifdef CONFIG_HIGH_RES_TIMERS + + /* +@@ -1246,6 +1272,8 @@ static void run_hrtimer_softirq(struct s + } + } + spin_unlock_irq(&cpu_base->lock); ++ ++ wake_up_timer_waiters(cpu_base); + } + + #endif /* CONFIG_HIGH_RES_TIMERS */ +@@ -1296,6 +1324,8 @@ static inline void run_hrtimer_queue(str + } + } + spin_unlock_irq(&cpu_base->lock); ++ ++ wake_up_timer_waiters(cpu_base); + } + + /* +@@ -1477,6 +1507,9 @@ static void __cpuinit init_hrtimers_cpu( + cpu_base->clock_base[i].cpu_base = cpu_base; + + hrtimer_init_hres(cpu_base); ++#ifdef CONFIG_PREEMPT_SOFTIRQS ++ init_waitqueue_head(&cpu_base->wait); ++#endif + } + + #ifdef CONFIG_HOTPLUG_CPU +Index: linux-2.6.24.7-rt27/kernel/itimer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/itimer.c 2009-02-08 00:00:14.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/itimer.c 2009-02-08 00:01:51.000000000 -0500 +@@ -170,6 +170,7 @@ again: + /* We are sharing ->siglock with it_real_fn() */ + if (hrtimer_try_to_cancel(timer) < 0) { + spin_unlock_irq(&tsk->sighand->siglock); ++ hrtimer_wait_for_timer(&tsk->signal->real_timer); + goto again; + } + expires = timeval_to_ktime(value->it_value); +Index: linux-2.6.24.7-rt27/kernel/posix-timers.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/posix-timers.c 2009-02-08 00:00:14.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/posix-timers.c 2009-02-08 00:01:51.000000000 -0500 +@@ -809,6 +809,7 @@ retry: + + unlock_timer(timr, flag); + if (error == TIMER_RETRY) { ++ hrtimer_wait_for_timer(&timr->it.real.timer); + rtn = NULL; // We already got the old time... + goto retry; + } +@@ -848,6 +849,7 @@ retry_delete: + + if (timer_delete_hook(timer) == TIMER_RETRY) { + unlock_timer(timer, flags); ++ hrtimer_wait_for_timer(&timer->it.real.timer); + goto retry_delete; + } + +@@ -880,6 +882,7 @@ retry_delete: + + if (timer_delete_hook(timer) == TIMER_RETRY) { + unlock_timer(timer, flags); ++ hrtimer_wait_for_timer(&timer->it.real.timer); + goto retry_delete; + } + list_del(&timer->list); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0470-lockstat-output.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0470-lockstat-output.patch @@ -0,0 +1,25 @@ +Subject: lockstat: warn about disabled lock debugging +From: Peter Zijlstra + +Avoid confusion and clearly state lock debugging got disabled. + +Signed-off-by: Peter Zijlstra +--- + kernel/lockdep_proc.c | 4 ++++ + 1 file changed, 4 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/lockdep_proc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/lockdep_proc.c 2009-02-07 23:59:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/lockdep_proc.c 2009-02-08 00:04:33.000000000 -0500 +@@ -516,6 +516,10 @@ static void seq_stats(struct seq_file *m + static void seq_header(struct seq_file *m) + { + seq_printf(m, "lock_stat version 0.2\n"); ++ ++ if (unlikely(!debug_locks)) ++ seq_printf(m, "*WARNING* lock debugging disabled!! - possibly due to a lockdep warning\n"); ++ + seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1)); + seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s " + "%14s %14s\n", --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0358-pmtmr-override.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0358-pmtmr-override.patch @@ -0,0 +1,36 @@ +Subject: pmtmr: allow command line override of ioport +From: Thomas Gleixner +Date: Wed, 21 May 2008 21:14:58 +0200 + +Signed-off-by: Thomas Gleixner +--- + drivers/clocksource/acpi_pm.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +Index: linux-2.6.24.7-rt27/drivers/clocksource/acpi_pm.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/clocksource/acpi_pm.c 2009-02-07 23:59:48.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/clocksource/acpi_pm.c 2009-02-08 00:03:41.000000000 -0500 +@@ -215,3 +215,22 @@ pm_good: + * but we still need to load before device_initcall + */ + fs_initcall(init_acpi_pm_clocksource); ++ ++/* ++ * Allow an override of the IOPort. Stupid BIOSes do not tell us about ++ * the PMTimer, but we might know where it is. ++ */ ++static int __init parse_pmtmr(char *arg) ++{ ++ unsigned long base; ++ char *e; ++ ++ base = simple_strtoul(arg, &e, 16); ++ ++ printk(KERN_INFO "PMTMR IOPort override: 0x%04lx -> 0x%04lx\n", ++ pmtmr_ioport, base); ++ pmtmr_ioport = base; ++ ++ return 1; ++} ++__setup("pmtmr=", parse_pmtmr); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0547-7205656ab48da29a95d7f55e43a81db755d3cb3a.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0547-7205656ab48da29a95d7f55e43a81db755d3cb3a.patch @@ -0,0 +1,65 @@ +commit 7205656ab48da29a95d7f55e43a81db755d3cb3a +Author: Thomas Gleixner +Date: Wed Sep 3 21:37:03 2008 +0000 + + clockevents: enforce reprogram in oneshot setup + + In tick_oneshot_setup we program the device to the given next_event, + but we do not check the return value. We need to make sure that the + device is programmed enforced so the interrupt handler engine starts + working. Split out the reprogramming function from tick_program_event() + and call it with the device, which was handed in to tick_setup_oneshot(). + Set the force argument, so the devices is firing an interrupt. + + Signed-off-by: Thomas Gleixner + Signed-off-by: Ingo Molnar + +--- + kernel/time/tick-oneshot.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/time/tick-oneshot.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-oneshot.c 2009-02-07 23:59:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-oneshot.c 2009-02-08 00:05:10.000000000 -0500 +@@ -23,11 +23,11 @@ + #include "tick-internal.h" + + /** +- * tick_program_event ++ * tick_program_event internal worker function + */ +-int tick_program_event(ktime_t expires, int force) ++static int __tick_program_event(struct clock_event_device *dev, ++ ktime_t expires, int force) + { +- struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; + ktime_t now = ktime_get(); + + while (1) { +@@ -41,6 +41,16 @@ int tick_program_event(ktime_t expires, + } + + /** ++ * tick_program_event ++ */ ++int tick_program_event(ktime_t expires, int force) ++{ ++ struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; ++ ++ return __tick_program_event(dev, expires, force); ++} ++ ++/** + * tick_resume_onshot - resume oneshot mode + */ + void tick_resume_oneshot(void) +@@ -61,7 +71,7 @@ void tick_setup_oneshot(struct clock_eve + { + newdev->event_handler = handler; + clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); +- clockevents_program_event(newdev, next_event, ktime_get()); ++ __tick_program_event(newdev, next_event, 1); + } + + /** --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0449-multi-reader-account.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0449-multi-reader-account.patch @@ -0,0 +1,210 @@ +From: Steven Rostedt +Subject: map tasks to reader locks held + +This patch keeps track of all reader locks that are held for a task. +The max depth is currently set to 5. A task may own the same lock +multiple times for read without affecting this limit. It is bad programming +practice to hold more than 5 different locks for read at the same time +anyway so this should not be a problem. The 5 lock limit should be way +more than enough. + +Signed-off-by: Steven Rostedt +--- + include/linux/sched.h | 14 ++++++++++ + kernel/fork.c | 4 +++ + kernel/rtmutex.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++---- + 3 files changed, 80 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:04:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:04:23.000000000 -0500 +@@ -1005,6 +1005,14 @@ struct sched_entity { + #endif + }; + ++#ifdef CONFIG_PREEMPT_RT ++struct rw_mutex; ++struct reader_lock_struct { ++ struct rw_mutex *lock; ++ int count; ++}; ++ ++#endif + struct task_struct { + volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ + void *stack; +@@ -1226,6 +1234,12 @@ struct task_struct { + #endif + + #define MAX_PREEMPT_TRACE 25 ++#define MAX_RWLOCK_DEPTH 5 ++ ++#ifdef CONFIG_PREEMPT_RT ++ int reader_lock_count; ++ struct reader_lock_struct owned_read_locks[MAX_RWLOCK_DEPTH]; ++#endif + + #ifdef CONFIG_PREEMPT_TRACE + unsigned long preempt_trace_eip[MAX_PREEMPT_TRACE]; +Index: linux-2.6.24.7-rt27/kernel/fork.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/fork.c 2009-02-08 00:03:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/fork.c 2009-02-08 00:04:23.000000000 -0500 +@@ -1206,6 +1206,10 @@ static struct task_struct *copy_process( + p->lock_count = 0; + #endif + ++#ifdef CONFIG_PREEMPT_RT ++ p->reader_lock_count = 0; ++#endif ++ + if (pid != &init_struct_pid) { + retval = -ENOMEM; + pid = alloc_pid(task_active_pid_ns(p)); +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:23.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:23.000000000 -0500 +@@ -1038,6 +1038,8 @@ static int try_to_take_rw_read(struct rw + struct rt_mutex *mutex = &rwm->mutex; + struct rt_mutex_waiter *waiter; + struct task_struct *mtxowner; ++ int reader_count, i; ++ int incr = 1; + + assert_spin_locked(&mutex->wait_lock); + +@@ -1048,6 +1050,16 @@ static int try_to_take_rw_read(struct rw + if (unlikely(rt_rwlock_writer(rwm))) + return 0; + ++ /* check to see if we don't already own this lock */ ++ for (i = current->reader_lock_count - 1; i >= 0; i--) { ++ if (current->owned_read_locks[i].lock == rwm) { ++ rt_rwlock_set_owner(rwm, RT_RW_READER, 0); ++ current->owned_read_locks[i].count++; ++ incr = 0; ++ goto taken; ++ } ++ } ++ + /* A writer is not the owner, but is a writer waiting */ + mtxowner = rt_mutex_owner(mutex); + +@@ -1103,6 +1115,14 @@ static int try_to_take_rw_read(struct rw + /* RT_RW_READER forces slow paths */ + rt_rwlock_set_owner(rwm, RT_RW_READER, 0); + taken: ++ if (incr) { ++ reader_count = current->reader_lock_count++; ++ if (likely(reader_count < MAX_RWLOCK_DEPTH)) { ++ current->owned_read_locks[reader_count].lock = rwm; ++ current->owned_read_locks[reader_count].count = 1; ++ } else ++ WARN_ON_ONCE(1); ++ } + rt_mutex_deadlock_account_lock(mutex, current); + atomic_inc(&rwm->count); + return 1; +@@ -1256,10 +1276,13 @@ rt_read_fastlock(struct rw_mutex *rwm, + void fastcall (*slowfn)(struct rw_mutex *rwm, int mtx), + int mtx) + { +-retry: ++ retry: + if (likely(rt_rwlock_cmpxchg(rwm, NULL, current))) { ++ int reader_count; ++ + rt_mutex_deadlock_account_lock(&rwm->mutex, current); + atomic_inc(&rwm->count); ++ smp_mb(); + /* + * It is possible that the owner was zeroed + * before we incremented count. If owner is not +@@ -1269,6 +1292,13 @@ retry: + atomic_dec(&rwm->count); + goto retry; + } ++ ++ reader_count = current->reader_lock_count++; ++ if (likely(reader_count < MAX_RWLOCK_DEPTH)) { ++ current->owned_read_locks[reader_count].lock = rwm; ++ current->owned_read_locks[reader_count].count = 1; ++ } else ++ WARN_ON_ONCE(1); + } else + slowfn(rwm, mtx); + } +@@ -1308,6 +1338,8 @@ rt_read_fasttrylock(struct rw_mutex *rwm + { + retry: + if (likely(rt_rwlock_cmpxchg(rwm, NULL, current))) { ++ int reader_count; ++ + rt_mutex_deadlock_account_lock(&rwm->mutex, current); + atomic_inc(&rwm->count); + /* +@@ -1319,6 +1351,13 @@ retry: + atomic_dec(&rwm->count); + goto retry; + } ++ ++ reader_count = current->reader_lock_count++; ++ if (likely(reader_count < MAX_RWLOCK_DEPTH)) { ++ current->owned_read_locks[reader_count].lock = rwm; ++ current->owned_read_locks[reader_count].count = 1; ++ } else ++ WARN_ON_ONCE(1); + return 1; + } else + return slowfn(rwm, mtx); +@@ -1502,9 +1541,10 @@ static void fastcall noinline __sched + rt_read_slowunlock(struct rw_mutex *rwm, int mtx) + { + struct rt_mutex *mutex = &rwm->mutex; ++ struct rt_mutex_waiter *waiter; + unsigned long flags; + int savestate = !mtx; +- struct rt_mutex_waiter *waiter; ++ int i; + + spin_lock_irqsave(&mutex->wait_lock, flags); + +@@ -1519,6 +1559,18 @@ rt_read_slowunlock(struct rw_mutex *rwm, + */ + mark_rt_rwlock_check(rwm); + ++ for (i = current->reader_lock_count - 1; i >= 0; i--) { ++ if (current->owned_read_locks[i].lock == rwm) { ++ current->owned_read_locks[i].count--; ++ if (!current->owned_read_locks[i].count) { ++ current->reader_lock_count--; ++ WARN_ON_ONCE(i != current->reader_lock_count); ++ } ++ break; ++ } ++ } ++ WARN_ON_ONCE(i < 0); ++ + /* + * If there are more readers, let the last one do any wakeups. + * Also check to make sure the owner wasn't cleared when two +@@ -1580,9 +1632,15 @@ rt_read_fastunlock(struct rw_mutex *rwm, + WARN_ON(!atomic_read(&rwm->count)); + WARN_ON(!rwm->owner); + atomic_dec(&rwm->count); +- if (likely(rt_rwlock_cmpxchg(rwm, current, NULL))) ++ if (likely(rt_rwlock_cmpxchg(rwm, current, NULL))) { ++ int reader_count = --current->reader_lock_count; + rt_mutex_deadlock_account_unlock(current); +- else ++ if (unlikely(reader_count < 0)) { ++ reader_count = 0; ++ WARN_ON_ONCE(1); ++ } ++ WARN_ON_ONCE(current->owned_read_locks[reader_count].lock != rwm); ++ } else + slowfn(rwm, mtx); + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0533-cpu-hotplug-fix-fix-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0533-cpu-hotplug-fix-fix-fix.patch @@ -0,0 +1,161 @@ +--- + arch/x86/kernel/head64.c | 1 + arch/x86/kernel/setup64.c | 54 +++++++++++++++++++++++++++++++++++++++++++ + arch/x86/kernel/smpboot_64.c | 54 ------------------------------------------- + arch/x86/kernel/traps_64.c | 1 + 4 files changed, 55 insertions(+), 55 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/head64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/head64.c 2009-02-08 00:05:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/head64.c 2009-02-08 00:05:05.000000000 -0500 +@@ -70,7 +70,6 @@ void __init x86_64_start_kernel(char * r + cpu_pda(i) = &boot_cpu_pda[i]; + + pda_init(0); +- allocate_stacks(0); + copy_bootdata(__va(real_mode_data)); + #ifdef CONFIG_SMP + cpu_set(0, cpu_online_map); +Index: linux-2.6.24.7-rt27/arch/x86/kernel/setup64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/setup64.c 2009-02-08 00:04:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/setup64.c 2009-02-08 00:05:05.000000000 -0500 +@@ -143,6 +143,60 @@ void pda_init(int cpu) + pda->irqstackptr += IRQSTACKSIZE-64; + } + ++static char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ] ++__attribute__((section(".bss.page_aligned"))); ++ ++int __cpuinit allocate_stacks(int cpu) ++{ ++ static const unsigned int order[N_EXCEPTION_STACKS] = { ++ [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, ++#if DEBUG_STACK > 0 ++ [DEBUG_STACK - 1] = DEBUG_STACK_ORDER ++#endif ++ }; ++ struct tss_struct *t = &per_cpu(init_tss, cpu); ++ int node = cpu_to_node(cpu); ++ struct page *page; ++ char *estack; ++ int v; ++ ++ if (cpu && !t->irqstack) { ++ page = alloc_pages_node(node, GFP_KERNEL, ++ IRQSTACK_ORDER); ++ if (!page) ++ goto fail_oom; ++ t->irqstack = page_address(page); ++ } ++ ++ if (!cpu) ++ estack = boot_exception_stacks; ++ ++ for (v = 0; v < N_EXCEPTION_STACKS; v++) { ++ if (t->estacks[v]) ++ continue; ++ ++ if (cpu) { ++ page = alloc_pages_node(node, GFP_KERNEL, order[v]); ++ if (!page) ++ goto fail_oom; ++ estack = page_address(page); ++ } ++ estack += PAGE_SIZE << order[v]; ++ /* ++ * XXX: can we set t->isr[v] here directly, or will that be ++ * modified later? - the existance of orig_ist seems to suggest ++ * it _can_ be modified, which would imply we'd need to reset ++ * it. ++ */ ++ t->estacks[v] = estack; ++ } ++ ++ return 0; ++ ++fail_oom: ++ return -ENOMEM; ++} ++ + extern asmlinkage void ignore_sysret(void); + + /* May not be marked __init: used by software suspend */ +Index: linux-2.6.24.7-rt27/arch/x86/kernel/smpboot_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/smpboot_64.c 2009-02-08 00:05:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/smpboot_64.c 2009-02-08 00:05:05.000000000 -0500 +@@ -535,60 +535,6 @@ static void __cpuinit do_fork_idle(struc + complete(&c_idle->done); + } + +-static char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ] +-__attribute__((section(".bss.page_aligned"))); +- +-int __cpuinit allocate_stacks(int cpu) +-{ +- static const unsigned int order[N_EXCEPTION_STACKS] = { +- [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, +-#if DEBUG_STACK > 0 +- [DEBUG_STACK - 1] = DEBUG_STACK_ORDER +-#endif +- }; +- struct tss_struct *t = &per_cpu(init_tss, cpu); +- int node = cpu_to_node(cpu); +- struct page *page; +- char *estack; +- int v; +- +- if (cpu && !t->irqstack) { +- page = alloc_pages_node(node, GFP_KERNEL, +- IRQSTACK_ORDER); +- if (!page) +- goto fail_oom; +- t->irqstack = page_address(page); +- } +- +- if (!cpu) +- estack = boot_exception_stacks; +- +- for (v = 0; v < N_EXCEPTION_STACKS; v++) { +- if (t->estacks[v]) +- continue; +- +- if (cpu) { +- page = alloc_pages_node(node, GFP_KERNEL, order[v]); +- if (!page) +- goto fail_oom; +- estack = page_address(page); +- } +- estack += PAGE_SIZE << order[v]; +- /* +- * XXX: can we set t->isr[v] here directly, or will that be +- * modified later? - the existance of orig_ist seems to suggest +- * it _can_ be modified, which would imply we'd need to reset +- * it. +- */ +- t->estacks[v] = estack; +- } +- +- return 0; +- +-fail_oom: +- return -ENOMEM; +-} +- + /* + * Boot one CPU. + */ +Index: linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/traps_64.c 2009-02-08 00:04:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c 2009-02-08 00:05:05.000000000 -0500 +@@ -1138,6 +1138,7 @@ void __init trap_init(void) + /* + * Should be a barrier for any external CPU state. + */ ++ allocate_stacks(0); + cpu_init(); + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0316-Allocate-RTSJ-memory-for-TCK-conformance-test.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0316-Allocate-RTSJ-memory-for-TCK-conformance-test.patch @@ -0,0 +1,168 @@ +Allocate RTSJ memory for TCK conformance test. + +From: Theodore Ts'o + +This kernel message allocates memory which is required by the +real-time TCK conformance test which tests the JVM's RTSJ +implementation. Unfortunately, RTSJ requires that Java programs have +direct access to physical memory. This kernel reserves memory which +can then be used by an external /dev/rmem loadable kernel module. + +Signed-off-by: "Theodore Ts'o" +--- + + drivers/char/Kconfig | 7 +++ + drivers/char/Makefile | 2 + drivers/char/alloc_rtsj_mem.c | 88 ++++++++++++++++++++++++++++++++++++++++++ + init/main.c | 7 +++ + 4 files changed, 104 insertions(+) + +Index: linux-2.6.24.7-rt27/drivers/char/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/char/Kconfig 2009-02-08 00:03:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/char/Kconfig 2009-02-08 00:03:19.000000000 -0500 +@@ -1083,6 +1083,13 @@ config RMEM + patching /dev/mem because we don't expect this functionality + to ever be accepted into mainline. + ++config ALLOC_RTSJ_MEM ++ tristate "RTSJ-specific hack to reserve memory" ++ default m ++ help ++ The RTSJ TCK conformance test requires reserving some physical ++ memory for testing /dev/rmem. ++ + config DEVPORT + bool + depends on !M68K +Index: linux-2.6.24.7-rt27/drivers/char/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/char/Makefile 2009-02-08 00:03:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/char/Makefile 2009-02-08 00:03:19.000000000 -0500 +@@ -114,6 +114,8 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o + obj-$(CONFIG_JS_RTC) += js-rtc.o + js-rtc-y = rtc.o + ++obj-$(CONFIG_ALLOC_RTSJ_MEM) += alloc_rtsj_mem.o ++ + # Files generated that shall be removed upon make clean + clean-files := consolemap_deftbl.c defkeymap.c + +Index: linux-2.6.24.7-rt27/drivers/char/alloc_rtsj_mem.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/drivers/char/alloc_rtsj_mem.c 2009-02-08 00:03:19.000000000 -0500 +@@ -0,0 +1,88 @@ ++/* ++ * alloc_rtsj_mem.c -- Hack to allocate some memory ++ * ++ * Copyright (C) 2005 by Theodore Ts'o ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++MODULE_AUTHOR("Theodore Tso"); ++MODULE_DESCRIPTION("RTSJ alloc memory"); ++MODULE_LICENSE("GPL"); ++ ++static void *mem = 0; ++int size = 0, addr = 0; ++ ++module_param(size, int, 0444); ++module_param(addr, int, 0444); ++ ++static void __exit shutdown_module(void) ++{ ++ kfree(mem); ++} ++ ++#ifndef MODULE ++void __init alloc_rtsj_mem_early_setup(void) ++{ ++ if (size > PAGE_SIZE*2) { ++ mem = alloc_bootmem(size); ++ if (mem) { ++ printk(KERN_INFO "alloc_rtsj_mem: got %d bytes " ++ "using alloc_bootmem\n", size); ++ } else { ++ printk(KERN_INFO "alloc_rtsj_mem: failed to " ++ "get %d bytes from alloc_bootmem\n", size); ++ } ++ } ++} ++#endif ++ ++static int __init startup_module(void) ++{ ++ static char test_string[] = "The BOFH: Servicing users the way the " ++ "military\n\tservices targets for 15 years.\n"; ++ ++ if (!size) ++ return 0; ++ ++ if (!mem) { ++ mem = kmalloc(size, GFP_KERNEL); ++ if (mem) { ++ printk(KERN_INFO "alloc_rtsj_mem: got %d bytes " ++ "using kmalloc\n", size); ++ } else { ++ printk(KERN_ERR "alloc_rtsj_mem: failed to get " ++ "%d bytes using kmalloc\n", size); ++ return -ENOMEM; ++ } ++ } ++ memcpy(mem, test_string, min(sizeof(test_string), (size_t) size)); ++ addr = virt_to_phys(mem); ++ return 0; ++} ++ ++module_init(startup_module); ++module_exit(shutdown_module); ++ +Index: linux-2.6.24.7-rt27/init/main.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/init/main.c 2009-02-08 00:02:43.000000000 -0500 ++++ linux-2.6.24.7-rt27/init/main.c 2009-02-08 00:03:19.000000000 -0500 +@@ -100,6 +100,12 @@ static inline void acpi_early_init(void) + #ifndef CONFIG_DEBUG_RODATA + static inline void mark_rodata_ro(void) { } + #endif ++#ifdef CONFIG_ALLOC_RTSJ_MEM ++extern void alloc_rtsj_mem_early_setup(void); ++#else ++static inline void alloc_rtsj_mem_early_setup(void) { } ++#endif ++ + + #ifdef CONFIG_TC + extern void tc_init(void); +@@ -613,6 +619,7 @@ asmlinkage void __init start_kernel(void + #endif + vfs_caches_init_early(); + cpuset_init_early(); ++ alloc_rtsj_mem_early_setup(); + mem_init(); + kmem_cache_init(); + setup_per_cpu_pageset(); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0072-ppc-rename-xmon-mcount.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0072-ppc-rename-xmon-mcount.patch @@ -0,0 +1,72 @@ +From tsutomu.owa@toshiba.co.jp Mon May 14 17:19:36 2007 +Date: Mon, 14 May 2007 17:19:36 +0900 +From: Tsutomu OWA +To: linuxppc-dev@ozlabs.org, linux-kernel@vger.kernel.org +Cc: mingo@elte.hu, tglx@linutronix.de +Subject: Re: [patch 4/5] powerpc 2.6.21-rt1: rename mcount variable in xmon to xmon_mcount + + +Rename variable name "mcount" in xmon to xmon_mcount, since it conflicts +with mcount() function used by latency trace function. + +Signed-off-by: Tsutomu OWA +-- owa + +--- + +From tsutomu.owa@toshiba.co.jp Mon May 14 17:19:36 2007 +Date: Mon, 14 May 2007 17:19:36 +0900 +From: Tsutomu OWA +To: linuxppc-dev@ozlabs.org, linux-kernel@vger.kernel.org +Cc: mingo@elte.hu, tglx@linutronix.de +Subject: Re: [patch 4/5] powerpc 2.6.21-rt1: rename mcount variable in xmon to xmon_mcount + + +Rename variable name "mcount" in xmon to xmon_mcount, since it conflicts +with mcount() function used by latency trace function. + +Signed-off-by: Tsutomu OWA +-- owa + +--- + arch/powerpc/xmon/xmon.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/xmon/xmon.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/xmon/xmon.c 2009-02-08 00:00:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/xmon/xmon.c 2009-02-08 00:01:17.000000000 -0500 +@@ -2129,7 +2129,7 @@ print_address(unsigned long addr) + static unsigned long mdest; /* destination address */ + static unsigned long msrc; /* source address */ + static unsigned long mval; /* byte value to set memory to */ +-static unsigned long mcount; /* # bytes to affect */ ++static unsigned long xmon_mcount; /* # bytes to affect */ + static unsigned long mdiffs; /* max # differences to print */ + + void +@@ -2141,19 +2141,20 @@ memops(int cmd) + scanhex((void *)(cmd == 's'? &mval: &msrc)); + if( termch != '\n' ) + termch = 0; +- scanhex((void *)&mcount); ++ scanhex((void *)&xmon_mcount); + switch( cmd ){ + case 'm': +- memmove((void *)mdest, (void *)msrc, mcount); ++ memmove((void *)mdest, (void *)msrc, xmon_mcount); + break; + case 's': +- memset((void *)mdest, mval, mcount); ++ memset((void *)mdest, mval, xmon_mcount); + break; + case 'd': + if( termch != '\n' ) + termch = 0; + scanhex((void *)&mdiffs); +- memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs); ++ memdiffs((unsigned char *)mdest, (unsigned char *)msrc, ++ xmon_mcount, mdiffs); + break; + } + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0321-fix-softirq-checks-for-non-rt-preempt-hardirq.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0321-fix-softirq-checks-for-non-rt-preempt-hardirq.patch @@ -0,0 +1,31 @@ +--- + include/linux/bottom_half.h | 2 +- + kernel/softirq.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/bottom_half.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/bottom_half.h 2009-02-08 00:01:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/bottom_half.h 2009-02-08 00:03:22.000000000 -0500 +@@ -1,7 +1,7 @@ + #ifndef _LINUX_BH_H + #define _LINUX_BH_H + +-#ifdef CONFIG_PREEMPT_RT ++#ifdef CONFIG_PREEMPT_HARDIRQS + # define local_bh_disable() do { } while (0) + # define __local_bh_disable(ip) do { } while (0) + # define _local_bh_enable() do { } while (0) +Index: linux-2.6.24.7-rt27/kernel/softirq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/softirq.c 2009-02-08 00:03:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/softirq.c 2009-02-08 00:03:22.000000000 -0500 +@@ -146,7 +146,7 @@ static void trigger_softirqs(void) + } + } + +-#ifndef CONFIG_PREEMPT_RT ++#ifndef CONFIG_PREEMPT_HARDIRQS + + /* + * This one is for softirq.c-internal use, --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0478-x86-disable-spinlock-preempt.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0478-x86-disable-spinlock-preempt.patch @@ -0,0 +1,34 @@ +x86: disable spinlock preempt feature since we have ticketlocks + +From: Gregory Haskins + +The spinlock preempt feature utilizes spin_trylock() to implement +preemptible waiters. However, doing so circumvents the benefit of +using a FIFO/ticket lock, so we disable the feature when ticketlocks +are enabled. + +Signed-off-by: Gregory Haskins +CC: Nick Piggin +--- + + kernel/spinlock.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/spinlock.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/spinlock.c 2009-02-08 00:04:15.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/spinlock.c 2009-02-08 00:04:37.000000000 -0500 +@@ -115,9 +115,12 @@ EXPORT_SYMBOL(__write_trylock_irqsave); + * If lockdep is enabled then we use the non-preemption spin-ops + * even on CONFIG_PREEMPT, because lockdep assumes that interrupts are + * not re-enabled during lock-acquire (which the preempt-spin-ops do): ++ * ++ * We also disable them on x86 because we now have ticket/fifo locks, ++ * which are defeated using a preemptible spinlock + */ + #if !defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP) || \ +- defined(CONFIG_DEBUG_LOCK_ALLOC) ++ defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_X86) + + void __lockfunc __read_lock(raw_rwlock_t *lock) + { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0382-rt-delayed-prio.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0382-rt-delayed-prio.patch @@ -0,0 +1,89 @@ +Subject: rt: PI-workqueue: propagate prio for delayed work + +Delayed work looses its enqueue priority, and will be enqueued on the prio +of the softirq thread. Ammend this. + +Signed-off-by: Peter Zijlstra +--- + include/linux/workqueue.h | 1 + + kernel/workqueue.c | 16 ++++++++++------ + 2 files changed, 11 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/workqueue.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/workqueue.h 2009-02-08 00:03:51.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/workqueue.h 2009-02-08 00:03:52.000000000 -0500 +@@ -40,6 +40,7 @@ struct work_struct { + struct delayed_work { + struct work_struct work; + struct timer_list timer; ++ int prio; + }; + + struct execute_work { +Index: linux-2.6.24.7-rt27/kernel/workqueue.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/workqueue.c 2009-02-08 00:03:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/workqueue.c 2009-02-08 00:03:52.000000000 -0500 +@@ -153,12 +153,12 @@ static void insert_work(struct cpu_workq + + /* Preempt must be disabled. */ + static void __queue_work(struct cpu_workqueue_struct *cwq, +- struct work_struct *work) ++ struct work_struct *work, int prio) + { + unsigned long flags; + + spin_lock_irqsave(&cwq->lock, flags); +- insert_work(cwq, work, current->normal_prio, current->normal_prio); ++ insert_work(cwq, work, prio, prio); + spin_unlock_irqrestore(&cwq->lock, flags); + } + +@@ -180,7 +180,7 @@ int fastcall queue_work(struct workqueue + + if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) { + BUG_ON(!plist_node_empty(&work->entry)); +- __queue_work(wq_per_cpu(wq, cpu), work); ++ __queue_work(wq_per_cpu(wq, cpu), work, current->normal_prio); + ret = 1; + } + return ret; +@@ -193,7 +193,8 @@ void delayed_work_timer_fn(unsigned long + struct cpu_workqueue_struct *cwq = get_wq_data(&dwork->work); + struct workqueue_struct *wq = cwq->wq; + +- __queue_work(wq_per_cpu(wq, raw_smp_processor_id()), &dwork->work); ++ __queue_work(wq_per_cpu(wq, raw_smp_processor_id()), ++ &dwork->work, dwork->prio); + } + + /** +@@ -236,6 +237,7 @@ int queue_delayed_work_on(int cpu, struc + BUG_ON(!plist_node_empty(&work->entry)); + + /* This stores cwq for the moment, for the timer_fn */ ++ dwork->prio = current->normal_prio; + set_wq_data(work, wq_per_cpu(wq, raw_smp_processor_id())); + timer->expires = jiffies + delay; + timer->data = (unsigned long)dwork; +@@ -725,7 +727,8 @@ int schedule_on_each_cpu(void (*func)(vo + work->info = info; + INIT_WORK(&work->work, schedule_on_each_cpu_func); + set_bit(WORK_STRUCT_PENDING, work_data_bits(&work->work)); +- __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), &work->work); ++ __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), ++ &work->work, current->normal_prio); + } + unlock_cpu_hotplug(); + +@@ -772,7 +775,8 @@ int schedule_on_each_cpu_wq(struct workq + + INIT_WORK(work, func); + set_bit(WORK_STRUCT_PENDING, work_data_bits(work)); +- __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work); ++ __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work, ++ current->normal_prio); + } + flush_workqueue(wq); + free_percpu(works); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0319-fix-migrating-softirq.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0319-fix-migrating-softirq.patch @@ -0,0 +1,115 @@ +From rostedt@goodmis.org Wed Jun 13 14:47:26 2007 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.1.7-deb (2006-10-05) on debian +X-Spam-Level: +X-Spam-Status: No, score=0.0 required=5.0 tests=AWL autolearn=unavailable + version=3.1.7-deb +Received: from ms-smtp-02.nyroc.rr.com (ms-smtp-02.nyroc.rr.com + [24.24.2.56]) by mail.tglx.de (Postfix) with ESMTP id AB7B665C3D9 for + ; Wed, 13 Jun 2007 14:47:26 +0200 (CEST) +Received: from [192.168.23.10] (cpe-24-94-51-176.stny.res.rr.com + [24.94.51.176]) by ms-smtp-02.nyroc.rr.com (8.13.6/8.13.6) with ESMTP id + l5DClGVg022890; Wed, 13 Jun 2007 08:47:17 -0400 (EDT) +Subject: [PATCH RT] fix migrating softirq [cause of network hang] +From: Steven Rostedt +To: Ingo Molnar +Cc: LKML , RT , Thomas Gleixner , john stultz +Content-Type: text/plain +Date: Wed, 13 Jun 2007 08:47:16 -0400 +Message-Id: <1181738836.10408.54.camel@localhost.localdomain> +Mime-Version: 1.0 +X-Mailer: Evolution 2.6.3 +X-Virus-Scanned: Symantec AntiVirus Scan Engine +X-Evolution-Source: imap://tglx%40linutronix.de@localhost:8993/ +Content-Transfer-Encoding: 8bit + +Softirqs are bound to a single CPU. That is to say, that once a softirq +function starts to run, it will stay on the CPU that it is running on +while it's running. + +In RT, softirqs are threads, and we have a softirq thread per cpu. Each +softirq thread is bound to a single CPU that it represents. + +In order to speed things up and lower context switches in RT, if a +softirq thread is of the same priority as an interrupt thread, then when +the interrupt thread is about to exit, it tests to see if any softirq +threads need to be run on that cpu. Instead of running the softirq +thread, it simply performs the functions for the softirq within the +interrupt thread. + +The problem is, nothing prevents the interrupt thread from migrating. + +So while the interrupt thread is running the softirq function, it may +migrate to another CPU in the middle of that function. This means that +any CPU data that the softirq is touching can be corrupted. + +I was experiencing a network hang that sometimes would come back, and +sometimes not. Using my logdev debugger, I started to debug this +problem. I came across this at the moment of the hang: + + +[ 389.131279] cpu:0 (IRQ-11:427) tcp_rcv_established:4056 rcv_nxt=-1665585797 +[ 389.131615] cpu:1 192.168.23.72:22 <== 192.168.23.60:41352 ack:2629381499 seq:1773074099 (----A-) len:0 win:790 end_seq:1773074099 +[ 389.131626] cpu:1 (IRQ-11:427) ip_finish_output2:187 dst->hh=ffff81003b213080 +[ 389.131635] cpu:1 (IRQ-11:427) ip_finish_output2:189 hh_output=ffffffff80429009 + + +Here we see IRQ-11 in the process of finishing up the softirq-net-tx +function. In the middle of it, we receive a packet, and that must have +pushed the interrupt thread over to CPU 1, and it finished up the +softirq there. + +This patch temporarily binds the hardirq thread on the CPU that it runs +the softirqs on. With this patch I have not seen my network hang. I ran +it over night, doing compiles and such, and it seems fine. I would be +able to cause the hang with various loads within a minute, now I can't +cause it after several minutes. + +I'm assuming that this fix may fix other bugs too. + +Signed-off-by: Steven Rostedt + +--- + kernel/irq/manage.c | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/irq/manage.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/irq/manage.c 2009-02-08 00:03:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/irq/manage.c 2009-02-08 00:03:21.000000000 -0500 +@@ -777,7 +777,15 @@ static int do_irqd(void * __desc) + struct irq_desc *desc = __desc; + + #ifdef CONFIG_SMP +- set_cpus_allowed(current, desc->affinity); ++ cpumask_t cpus_allowed, mask; ++ ++ cpus_allowed = desc->affinity; ++ /* ++ * Restrict it to one cpu so we avoid being migrated inside of ++ * do_softirq_from_hardirq() ++ */ ++ mask = cpumask_of_cpu(first_cpu(desc->affinity)); ++ set_cpus_allowed(current, mask); + #endif + current->flags |= PF_NOFREEZE | PF_HARDIRQ; + +@@ -801,8 +809,16 @@ static int do_irqd(void * __desc) + /* + * Did IRQ affinities change? + */ +- if (!cpus_equal(current->cpus_allowed, desc->affinity)) +- set_cpus_allowed(current, desc->affinity); ++ if (!cpus_equal(cpus_allowed, desc->affinity)) { ++ cpus_allowed = desc->affinity; ++ /* ++ * Restrict it to one cpu so we avoid being ++ * migrated inside of ++ * do_softirq_from_hardirq() ++ */ ++ mask = cpumask_of_cpu(first_cpu(desc->affinity)); ++ set_cpus_allowed(current, mask); ++ } + #endif + schedule(); + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0077-powerpc-ftrace-stop-on-oops.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0077-powerpc-ftrace-stop-on-oops.patch @@ -0,0 +1,33 @@ +Subject: powerpc: ftrace stop on crash +From: Thomas Gleixner +Date: Sun, 27 Jul 2008 09:42:36 +0200 + +Stop tracing, when we run into an oops/bug. That way we can see what +led to that. + +Signed-off-by: Thomas Gleixner +--- + arch/powerpc/kernel/traps.c | 3 +++ + 1 file changed, 3 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/traps.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/traps.c 2009-02-08 00:00:24.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/traps.c 2009-02-08 00:01:19.000000000 -0500 +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -111,6 +112,8 @@ int die(const char *str, struct pt_regs + if (debugger(regs)) + return 1; + ++ ftrace_stop(); ++ + oops_enter(); + + if (die.lock_owner != raw_smp_processor_id()) { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0298-radix-concurrent-lockdep.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0298-radix-concurrent-lockdep.patch @@ -0,0 +1,46 @@ +--- + lib/radix-tree.c | 24 +++++++++++++++++++++++- + 1 file changed, 23 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/lib/radix-tree.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/radix-tree.c 2009-02-08 00:03:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/radix-tree.c 2009-02-08 00:03:12.000000000 -0500 +@@ -79,6 +79,26 @@ static unsigned long height_to_maxindex[ + #ifdef CONFIG_RADIX_TREE_CONCURRENT + static struct lock_class_key radix_node_class[RADIX_TREE_MAX_PATH]; + #endif ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++static const char *radix_node_key_string[RADIX_TREE_MAX_PATH] = { ++ "radix-node-00", ++ "radix-node-01", ++ "radix-node-02", ++ "radix-node-03", ++ "radix-node-04", ++ "radix-node-05", ++ "radix-node-06", ++ "radix-node-07", ++ "radix-node-08", ++ "radix-node-09", ++ "radix-node-10", ++ "radix-node-11", ++ "radix-node-12", ++ "radix-node-13", ++ "radix-node-14", ++ "radix-node-15", ++}; ++#endif + + #ifdef CONFIG_RADIX_TREE_OPTIMISTIC + static DEFINE_PER_CPU(unsigned long[RADIX_TREE_MAX_PATH+1], optimistic_histogram); +@@ -224,7 +244,9 @@ radix_tree_node_alloc(struct radix_tree_ + BUG_ON(radix_tree_is_indirect_ptr(ret)); + #ifdef CONFIG_RADIX_TREE_CONCURRENT + spin_lock_init(&ret->lock); +- lockdep_set_class(&ret->lock, &radix_node_class[height]); ++ lockdep_set_class_and_name(&ret->lock, ++ &radix_node_class[height], ++ radix_node_key_string[height]); + #endif + ret->height = height; + return ret; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0463-sched-load_balance-is_runnable.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0463-sched-load_balance-is_runnable.patch @@ -0,0 +1,159 @@ +Subject: sched: even weaker newidle balancing +From: Peter Zijlstra + +On each round see if any of the classes became runnable - if so, stop +balancing and run the thing. + +Signed-off-by: Peter Zijlstra +--- + include/linux/sched.h | 2 ++ + kernel/sched.c | 28 ++++++++++++++++++++-------- + kernel/sched_fair.c | 7 +++++++ + kernel/sched_idletask.c | 7 +++++++ + kernel/sched_rt.c | 6 ++++++ + 5 files changed, 42 insertions(+), 8 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:04:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:04:30.000000000 -0500 +@@ -922,6 +922,8 @@ struct sched_class { + void (*pre_schedule) (struct rq *this_rq, struct task_struct *task); + void (*post_schedule) (struct rq *this_rq); + void (*task_wake_up) (struct rq *this_rq, struct task_struct *task); ++ ++ int (*is_runnable) (struct rq *this_rq); + #endif + + void (*set_curr_task) (struct rq *rq); +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:04:30.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:04:30.000000000 -0500 +@@ -2533,6 +2533,21 @@ out: + return max_load_move - rem_load_move; + } + ++static int is_runnable(struct rq *this_rq, const struct sched_class *target_class) ++{ ++ const struct sched_class *class = sched_class_highest; ++ ++ for (; class; class = class->next) { ++ if (class->is_runnable(this_rq)) ++ return 1; ++ ++ if (class == target_class) ++ break; ++ } ++ ++ return 0; ++} ++ + /* + * move_tasks tries to move up to max_load_move weighted load from busiest to + * this_rq, as part of a balancing operation within domain "sd". +@@ -2552,15 +2567,15 @@ static int move_tasks(struct rq *this_rq + *lb_flags |= LB_START; + + do { +- unsigned long load_moved; +- + *lb_flags |= LB_COMPLETE; + +- load_moved = class->load_balance(this_rq, this_cpu, busiest, +- max_load_move - total_load_moved, ++ total_load_moved += class->load_balance(this_rq, this_cpu, ++ busiest, max_load_move - total_load_moved, + sd, idle, lb_flags, &this_best_prio); + +- total_load_moved += load_moved; ++ if (idle == CPU_NEWLY_IDLE && ++ is_runnable(this_rq, class)) ++ return 1; + + if (*lb_flags & LB_COMPLETE) { + class = class->next; +@@ -2569,9 +2584,6 @@ static int move_tasks(struct rq *this_rq + *lb_flags &= ~LB_START; + schedstat_inc(this_rq, lb_breaks); + +- if (idle == CPU_NEWLY_IDLE && total_load_moved) +- break; +- + double_rq_unlock(this_rq, busiest); + local_irq_enable(); + +Index: linux-2.6.24.7-rt27/kernel/sched_fair.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_fair.c 2009-02-08 00:04:29.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_fair.c 2009-02-08 00:04:30.000000000 -0500 +@@ -1188,6 +1188,12 @@ move_one_task_fair(struct rq *this_rq, i + + return 0; + } ++ ++static int ++is_runnable_fair(struct rq *this_rq) ++{ ++ return !!this_rq->cfs.nr_running; ++} + #endif + + /* +@@ -1307,6 +1313,7 @@ static const struct sched_class fair_sch + #ifdef CONFIG_SMP + .load_balance = load_balance_fair, + .move_one_task = move_one_task_fair, ++ .is_runnable = is_runnable_fair, + #endif + + .set_curr_task = set_curr_task_fair, +Index: linux-2.6.24.7-rt27/kernel/sched_idletask.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_idletask.c 2009-02-08 00:04:28.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_idletask.c 2009-02-08 00:04:30.000000000 -0500 +@@ -59,6 +59,12 @@ move_one_task_idle(struct rq *this_rq, i + { + return 0; + } ++ ++static int ++is_runnable_idle(struct rq *this_rq) ++{ ++ return 1; ++} + #endif + + static void task_tick_idle(struct rq *rq, struct task_struct *curr) +@@ -117,6 +123,7 @@ const struct sched_class idle_sched_clas + #ifdef CONFIG_SMP + .load_balance = load_balance_idle, + .move_one_task = move_one_task_idle, ++ .is_runnable = is_runnable_idle, + #endif + + .set_curr_task = set_curr_task_idle, +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:04:28.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:04:30.000000000 -0500 +@@ -792,6 +792,11 @@ static void switched_from_rt(struct rq * + if (!rq->rt.rt_nr_running) + pull_rt_task(rq); + } ++ ++static int is_runnable_rt(struct rq *rq) ++{ ++ return !!rq->rt.rt_nr_running; ++} + #endif /* CONFIG_SMP */ + + /* +@@ -920,6 +925,7 @@ const struct sched_class rt_sched_class + .post_schedule = post_schedule_rt, + .task_wake_up = task_wake_up_rt, + .switched_from = switched_from_rt, ++ .is_runnable = is_runnable_rt, + #endif + + .set_curr_task = set_curr_task_rt, --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0328-lockstat-rt-hooks.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0328-lockstat-rt-hooks.patch @@ -0,0 +1,168 @@ +--- + include/linux/lockdep.h | 28 ++++++++++++++++++++++++++++ + kernel/rt.c | 25 ++++++++++++++++--------- + kernel/rtmutex.c | 4 ++-- + 3 files changed, 46 insertions(+), 11 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/lockdep.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/lockdep.h 2009-02-08 00:01:36.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/lockdep.h 2009-02-08 00:03:26.000000000 -0500 +@@ -361,6 +361,28 @@ do { \ + lock_acquired(&(_lock)->dep_map); \ + } while (0) + ++#define LOCK_CONTENDED_RT(_lock, f_try, f_lock) \ ++do { \ ++ if (!f_try(&(_lock)->lock)) { \ ++ lock_contended(&(_lock)->dep_map, _RET_IP_); \ ++ f_lock(&(_lock)->lock); \ ++ lock_acquired(&(_lock)->dep_map); \ ++ } \ ++} while (0) ++ ++ ++#define LOCK_CONTENDED_RT_RET(_lock, f_try, f_lock) \ ++({ \ ++ int ret = 0; \ ++ if (!f_try(&(_lock)->lock)) { \ ++ lock_contended(&(_lock)->dep_map, _RET_IP_); \ ++ ret = f_lock(&(_lock)->lock); \ ++ if (!ret) \ ++ lock_acquired(&(_lock)->dep_map); \ ++ } \ ++ ret; \ ++}) ++ + #else /* CONFIG_LOCK_STAT */ + + #define lock_contended(lockdep_map, ip) do {} while (0) +@@ -369,6 +391,12 @@ do { \ + #define LOCK_CONTENDED(_lock, try, lock) \ + lock(_lock) + ++#define LOCK_CONTENDED_RT(_lock, f_try, f_lock) \ ++ f_lock(&(_lock)->lock) ++ ++#define LOCK_CONTENDED_RT_RET(_lock, f_try, f_lock) \ ++ f_lock(&(_lock)->lock) ++ + #endif /* CONFIG_LOCK_STAT */ + + #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS) +Index: linux-2.6.24.7-rt27/kernel/rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rt.c 2009-02-08 00:02:03.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rt.c 2009-02-08 00:03:26.000000000 -0500 +@@ -98,16 +98,22 @@ EXPORT_SYMBOL(_mutex_init); + void __lockfunc _mutex_lock(struct mutex *lock) + { + mutex_acquire(&lock->dep_map, 0, 0, _RET_IP_); +- rt_mutex_lock(&lock->lock); ++ LOCK_CONTENDED_RT(lock, rt_mutex_trylock, rt_mutex_lock); + } + EXPORT_SYMBOL(_mutex_lock); + ++static int __lockfunc __rt_mutex_lock_interruptible(struct rt_mutex *lock) ++{ ++ return rt_mutex_lock_interruptible(lock, 0); ++} ++ + int __lockfunc _mutex_lock_interruptible(struct mutex *lock) + { + int ret; + + mutex_acquire(&lock->dep_map, 0, 0, _RET_IP_); +- ret = rt_mutex_lock_interruptible(&lock->lock, 0); ++ ret = LOCK_CONTENDED_RT_RET(lock, rt_mutex_trylock, ++ __rt_mutex_lock_interruptible); + if (ret) + mutex_release(&lock->dep_map, 1, _RET_IP_); + return ret; +@@ -118,7 +124,7 @@ EXPORT_SYMBOL(_mutex_lock_interruptible) + void __lockfunc _mutex_lock_nested(struct mutex *lock, int subclass) + { + mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_); +- rt_mutex_lock(&lock->lock); ++ LOCK_CONTENDED_RT(lock, rt_mutex_trylock, rt_mutex_lock); + } + EXPORT_SYMBOL(_mutex_lock_nested); + +@@ -127,7 +133,8 @@ int __lockfunc _mutex_lock_interruptible + int ret; + + mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_); +- ret = rt_mutex_lock_interruptible(&lock->lock, 0); ++ ret = LOCK_CONTENDED_RT_RET(lock, rt_mutex_trylock, ++ __rt_mutex_lock_interruptible); + if (ret) + mutex_release(&lock->dep_map, 1, _RET_IP_); + return ret; +@@ -203,7 +210,7 @@ EXPORT_SYMBOL(rt_read_trylock); + void __lockfunc rt_write_lock(rwlock_t *rwlock) + { + rwlock_acquire(&rwlock->dep_map, 0, 0, _RET_IP_); +- __rt_spin_lock(&rwlock->lock); ++ LOCK_CONTENDED_RT(rwlock, rt_mutex_trylock, __rt_spin_lock); + } + EXPORT_SYMBOL(rt_write_lock); + +@@ -223,7 +230,7 @@ void __lockfunc rt_read_lock(rwlock_t *r + return; + } + spin_unlock_irqrestore(&lock->wait_lock, flags); +- __rt_spin_lock(lock); ++ LOCK_CONTENDED_RT(rwlock, rt_mutex_trylock, __rt_spin_lock); + } + + EXPORT_SYMBOL(rt_read_lock); +@@ -359,14 +366,14 @@ EXPORT_SYMBOL(rt_down_write_trylock); + void fastcall rt_down_write(struct rw_semaphore *rwsem) + { + rwsem_acquire(&rwsem->dep_map, 0, 0, _RET_IP_); +- rt_mutex_lock(&rwsem->lock); ++ LOCK_CONTENDED_RT(rwsem, rt_mutex_trylock, rt_mutex_lock); + } + EXPORT_SYMBOL(rt_down_write); + + void fastcall rt_down_write_nested(struct rw_semaphore *rwsem, int subclass) + { + rwsem_acquire(&rwsem->dep_map, subclass, 0, _RET_IP_); +- rt_mutex_lock(&rwsem->lock); ++ LOCK_CONTENDED_RT(rwsem, rt_mutex_trylock, rt_mutex_lock); + } + EXPORT_SYMBOL(rt_down_write_nested); + +@@ -411,7 +418,7 @@ static void __rt_down_read(struct rw_sem + return; + } + spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); +- rt_mutex_lock(&rwsem->lock); ++ LOCK_CONTENDED_RT(rwsem, rt_mutex_trylock, rt_mutex_lock); + } + + void fastcall rt_down_read(struct rw_semaphore *rwsem) +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:03:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:03:26.000000000 -0500 +@@ -785,8 +785,8 @@ rt_spin_lock_slowunlock(struct rt_mutex + + void __lockfunc rt_spin_lock(spinlock_t *lock) + { +- rt_spin_lock_fastlock(&lock->lock, rt_spin_lock_slowlock); + spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); ++ LOCK_CONTENDED_RT(lock, rt_mutex_trylock, __rt_spin_lock); + } + EXPORT_SYMBOL(rt_spin_lock); + +@@ -800,8 +800,8 @@ EXPORT_SYMBOL(__rt_spin_lock); + + void __lockfunc rt_spin_lock_nested(spinlock_t *lock, int subclass) + { +- rt_spin_lock_fastlock(&lock->lock, rt_spin_lock_slowlock); + spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); ++ LOCK_CONTENDED_RT(lock, rt_mutex_trylock, __rt_spin_lock); + } + EXPORT_SYMBOL(rt_spin_lock_nested); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0010-fix_inotify_user_coalescing-bz453990.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0010-fix_inotify_user_coalescing-bz453990.patch @@ -0,0 +1,59 @@ +Subject: A potential bug in inotify_user.c + +From: Yan Zheng + +X-Git-Tag: v2.6.25-rc1~775 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=1c17d18e3775485bf1e0ce79575eb637a94494a2;hp=19c561a60ffe52df88dd63de0bff480ca094efe4 + +A potential bug in inotify_user.c + +Following comment is at fs/inotify_user.c:287 +/* coalescing: drop this event if it is a dupe of the previous */ + +I think the previous event in the comment should be the last event in the +link list. But inotify_dev_get_event return the first event in the list. +In addition, it doesn't check whether the list is empty + +Signed-off-by: Yan Zheng +Acked-by: Robert Love +Cc: John McCutchan +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + + fs/inotify_user.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/fs/inotify_user.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/inotify_user.c 2009-02-08 00:00:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/inotify_user.c 2009-02-08 00:00:46.000000000 -0500 +@@ -248,6 +248,19 @@ inotify_dev_get_event(struct inotify_dev + } + + /* ++ * inotify_dev_get_last_event - return the last event in the given dev's queue ++ * ++ * Caller must hold dev->ev_mutex. ++ */ ++static inline struct inotify_kernel_event * ++inotify_dev_get_last_event(struct inotify_device *dev) ++{ ++ if (list_empty(&dev->events)) ++ return NULL; ++ return list_entry(dev->events.prev, struct inotify_kernel_event, list); ++} ++ ++/* + * inotify_dev_queue_event - event handler registered with core inotify, adds + * a new event to the given device + * +@@ -273,7 +286,7 @@ static void inotify_dev_queue_event(stru + put_inotify_watch(w); /* final put */ + + /* coalescing: drop this event if it is a dupe of the previous */ +- last = inotify_dev_get_event(dev); ++ last = inotify_dev_get_last_event(dev); + if (last && last->event.mask == mask && last->event.wd == wd && + last->event.cookie == cookie) { + const char *lastname = last->name; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0214-preempt-realtime-mips.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0214-preempt-realtime-mips.patch @@ -0,0 +1,1204 @@ + arch/mips/Kconfig | 13 ++ + arch/mips/kernel/asm-offsets.c | 2 + arch/mips/kernel/entry.S | 22 +++- + arch/mips/kernel/i8259.c | 2 + arch/mips/kernel/module.c | 2 + arch/mips/kernel/process.c | 8 + + arch/mips/kernel/scall32-o32.S | 2 + arch/mips/kernel/scall64-64.S | 2 + arch/mips/kernel/scall64-n32.S | 2 + arch/mips/kernel/scall64-o32.S | 2 + arch/mips/kernel/semaphore.c | 22 +++- + arch/mips/kernel/signal.c | 4 + arch/mips/kernel/signal32.c | 4 + arch/mips/kernel/smp.c | 27 +++++ + arch/mips/kernel/traps.c | 2 + arch/mips/mm/init.c | 2 + arch/mips/sibyte/cfe/smp.c | 4 + arch/mips/sibyte/sb1250/irq.c | 6 + + arch/mips/sibyte/sb1250/smp.c | 2 + arch/mips/sibyte/swarm/setup.c | 6 + + include/asm-mips/asmmacro.h | 8 - + include/asm-mips/atomic.h | 1 + include/asm-mips/bitops.h | 5 - + include/asm-mips/hw_irq.h | 1 + include/asm-mips/i8259.h | 2 + include/asm-mips/io.h | 1 + include/asm-mips/linkage.h | 5 + + include/asm-mips/m48t35.h | 2 + include/asm-mips/rwsem.h | 176 ++++++++++++++++++++++++++++++++++++++ + include/asm-mips/semaphore.h | 31 +++--- + include/asm-mips/spinlock.h | 18 +-- + include/asm-mips/spinlock_types.h | 4 + include/asm-mips/thread_info.h | 2 + include/asm-mips/time.h | 2 + include/asm-mips/timeofday.h | 5 + + include/asm-mips/uaccess.h | 12 -- + 36 files changed, 331 insertions(+), 80 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/mips/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/Kconfig 2009-02-08 00:02:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/Kconfig 2009-02-08 00:02:23.000000000 -0500 +@@ -702,18 +702,16 @@ source "arch/mips/vr41xx/Kconfig" + + endmenu + ++ + config RWSEM_GENERIC_SPINLOCK + bool +- depends on !PREEMPT_RT + default y + + config RWSEM_XCHGADD_ALGORITHM + bool +- depends on !PREEMPT_RT + + config ASM_SEMAPHORES + bool +-# depends on !PREEMPT_RT + default y + + config ARCH_HAS_ILOG2_U32 +@@ -1898,6 +1896,15 @@ config SECCOMP + + If unsure, say Y. Only embedded should say N here. + ++config GENERIC_TIME ++ bool ++ default y ++ ++source "kernel/time/Kconfig" ++ ++config CPU_SPEED ++ int "CPU speed used for clocksource/clockevent calculations" ++ default 600 + endmenu + + config LOCKDEP_SUPPORT +Index: linux-2.6.24.7-rt27/arch/mips/kernel/asm-offsets.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/asm-offsets.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/asm-offsets.c 2009-02-08 00:02:23.000000000 -0500 +@@ -10,9 +10,11 @@ + */ + #include + #include ++#include + #include + #include + #include ++#include + + #include + #include +Index: linux-2.6.24.7-rt27/arch/mips/kernel/entry.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/entry.S 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/entry.S 2009-02-08 00:02:23.000000000 -0500 +@@ -30,7 +30,7 @@ + .align 5 + #ifndef CONFIG_PREEMPT + FEXPORT(ret_from_exception) +- local_irq_disable # preempt stop ++ raw_local_irq_disable # preempt stop + b __ret_from_irq + #endif + FEXPORT(ret_from_irq) +@@ -41,7 +41,7 @@ FEXPORT(__ret_from_irq) + beqz t0, resume_kernel + + resume_userspace: +- local_irq_disable # make sure we dont miss an ++ raw_local_irq_disable # make sure we dont miss an + # interrupt setting need_resched + # between sampling and return + LONG_L a2, TI_FLAGS($28) # current->work +@@ -51,7 +51,9 @@ resume_userspace: + + #ifdef CONFIG_PREEMPT + resume_kernel: +- local_irq_disable ++ raw_local_irq_disable ++ lw t0, kernel_preemption ++ beqz t0, restore_all + lw t0, TI_PRE_COUNT($28) + bnez t0, restore_all + need_resched: +@@ -61,7 +63,9 @@ need_resched: + LONG_L t0, PT_STATUS(sp) # Interrupts off? + andi t0, 1 + beqz t0, restore_all ++ raw_local_irq_disable + jal preempt_schedule_irq ++ sw zero, TI_PRE_COUNT($28) + b need_resched + #endif + +@@ -69,7 +73,7 @@ FEXPORT(ret_from_fork) + jal schedule_tail # a0 = struct task_struct *prev + + FEXPORT(syscall_exit) +- local_irq_disable # make sure need_resched and ++ raw_local_irq_disable # make sure need_resched and + # signals dont change between + # sampling and return + LONG_L a2, TI_FLAGS($28) # current->work +@@ -142,19 +146,21 @@ FEXPORT(restore_partial) # restore part + .set at + + work_pending: +- andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS ++ # a2 is preloaded with TI_FLAGS ++ andi t0, a2, (_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED) + beqz t0, work_notifysig + work_resched: ++ raw_local_irq_enable t0 + jal schedule + +- local_irq_disable # make sure need_resched and ++ raw_local_irq_disable # make sure need_resched and + # signals dont change between + # sampling and return + LONG_L a2, TI_FLAGS($28) + andi t0, a2, _TIF_WORK_MASK # is there any work to be done + # other than syscall tracing? + beqz t0, restore_all +- andi t0, a2, _TIF_NEED_RESCHED ++ andi t0, a2, (_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED) + bnez t0, work_resched + + work_notifysig: # deal with pending signals and +@@ -170,7 +176,7 @@ syscall_exit_work: + li t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT + and t0, a2 # a2 is preloaded with TI_FLAGS + beqz t0, work_pending # trace bit set? +- local_irq_enable # could let do_syscall_trace() ++ raw_local_irq_enable # could let do_syscall_trace() + # call schedule() instead + move a0, sp + li a1, 1 +Index: linux-2.6.24.7-rt27/arch/mips/kernel/i8259.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/i8259.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/i8259.c 2009-02-08 00:02:23.000000000 -0500 +@@ -29,7 +29,7 @@ + */ + + static int i8259A_auto_eoi = -1; +-DEFINE_SPINLOCK(i8259A_lock); ++DEFINE_RAW_SPINLOCK(i8259A_lock); + static void disable_8259A_irq(unsigned int irq); + static void enable_8259A_irq(unsigned int irq); + static void mask_and_ack_8259A(unsigned int irq); +Index: linux-2.6.24.7-rt27/arch/mips/kernel/module.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/module.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/module.c 2009-02-08 00:02:23.000000000 -0500 +@@ -40,7 +40,7 @@ struct mips_hi16 { + static struct mips_hi16 *mips_hi16_list; + + static LIST_HEAD(dbe_list); +-static DEFINE_SPINLOCK(dbe_lock); ++static DEFINE_RAW_SPINLOCK(dbe_lock); + + void *module_alloc(unsigned long size) + { +Index: linux-2.6.24.7-rt27/arch/mips/kernel/process.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/process.c 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/process.c 2009-02-08 00:02:23.000000000 -0500 +@@ -54,7 +54,7 @@ void __noreturn cpu_idle(void) + /* endless idle loop with no priority at all */ + while (1) { + tick_nohz_stop_sched_tick(); +- while (!need_resched()) { ++ while (!need_resched() && !need_resched_delayed()) { + #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG + extern void smtc_idle_loop_hook(void); + +@@ -64,9 +64,11 @@ void __noreturn cpu_idle(void) + (*cpu_wait)(); + } + tick_nohz_restart_sched_tick(); +- preempt_enable_no_resched(); +- schedule(); ++ local_irq_disable(); ++ __preempt_enable_no_resched(); ++ __schedule(); + preempt_disable(); ++ local_irq_enable(); + } + } + +Index: linux-2.6.24.7-rt27/arch/mips/kernel/scall32-o32.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/scall32-o32.S 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/scall32-o32.S 2009-02-08 00:02:23.000000000 -0500 +@@ -73,7 +73,7 @@ stack_done: + 1: sw v0, PT_R2(sp) # result + + o32_syscall_exit: +- local_irq_disable # make sure need_resched and ++ raw_local_irq_disable # make sure need_resched and + # signals dont change between + # sampling and return + lw a2, TI_FLAGS($28) # current->work +Index: linux-2.6.24.7-rt27/arch/mips/kernel/scall64-64.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/scall64-64.S 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/scall64-64.S 2009-02-08 00:02:23.000000000 -0500 +@@ -72,7 +72,7 @@ NESTED(handle_sys64, PT_SIZE, sp) + 1: sd v0, PT_R2(sp) # result + + n64_syscall_exit: +- local_irq_disable # make sure need_resched and ++ raw_local_irq_disable # make sure need_resched and + # signals dont change between + # sampling and return + LONG_L a2, TI_FLAGS($28) # current->work +Index: linux-2.6.24.7-rt27/arch/mips/kernel/scall64-n32.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/scall64-n32.S 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/scall64-n32.S 2009-02-08 00:02:23.000000000 -0500 +@@ -69,7 +69,7 @@ NESTED(handle_sysn32, PT_SIZE, sp) + sd v0, PT_R0(sp) # set flag for syscall restarting + 1: sd v0, PT_R2(sp) # result + +- local_irq_disable # make sure need_resched and ++ raw_local_irq_disable # make sure need_resched and + # signals dont change between + # sampling and return + LONG_L a2, TI_FLAGS($28) # current->work +Index: linux-2.6.24.7-rt27/arch/mips/kernel/scall64-o32.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/scall64-o32.S 2009-02-08 00:00:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/scall64-o32.S 2009-02-08 00:02:23.000000000 -0500 +@@ -98,7 +98,7 @@ NESTED(handle_sys, PT_SIZE, sp) + 1: sd v0, PT_R2(sp) # result + + o32_syscall_exit: +- local_irq_disable # make need_resched and ++ raw_local_irq_disable # make need_resched and + # signals dont change between + # sampling and return + LONG_L a2, TI_FLAGS($28) +Index: linux-2.6.24.7-rt27/arch/mips/kernel/semaphore.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/semaphore.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/semaphore.c 2009-02-08 00:02:23.000000000 -0500 +@@ -36,7 +36,7 @@ + * sem->count and sem->waking atomic. Scalability isn't an issue because + * this lock is used on UP only so it's just an empty variable. + */ +-static inline int __sem_update_count(struct semaphore *sem, int incr) ++static inline int __sem_update_count(struct compat_semaphore *sem, int incr) + { + int old_count, tmp; + +@@ -67,7 +67,7 @@ static inline int __sem_update_count(str + : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) + : "r" (incr), "m" (sem->count)); + } else { +- static DEFINE_SPINLOCK(semaphore_lock); ++ static DEFINE_RAW_SPINLOCK(semaphore_lock); + unsigned long flags; + + spin_lock_irqsave(&semaphore_lock, flags); +@@ -80,7 +80,7 @@ static inline int __sem_update_count(str + return old_count; + } + +-void __up(struct semaphore *sem) ++void __compat_up(struct compat_semaphore *sem) + { + /* + * Note that we incremented count in up() before we came here, +@@ -94,7 +94,7 @@ void __up(struct semaphore *sem) + wake_up(&sem->wait); + } + +-EXPORT_SYMBOL(__up); ++EXPORT_SYMBOL(__compat_up); + + /* + * Note that when we come in to __down or __down_interruptible, +@@ -104,7 +104,7 @@ EXPORT_SYMBOL(__up); + * Thus it is only when we decrement count from some value > 0 + * that we have actually got the semaphore. + */ +-void __sched __down(struct semaphore *sem) ++void __sched __compat_down(struct compat_semaphore *sem) + { + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); +@@ -133,9 +133,9 @@ void __sched __down(struct semaphore *se + wake_up(&sem->wait); + } + +-EXPORT_SYMBOL(__down); ++EXPORT_SYMBOL(__compat_down); + +-int __sched __down_interruptible(struct semaphore * sem) ++int __sched __compat_down_interruptible(struct compat_semaphore * sem) + { + int retval = 0; + struct task_struct *tsk = current; +@@ -165,4 +165,10 @@ int __sched __down_interruptible(struct + return retval; + } + +-EXPORT_SYMBOL(__down_interruptible); ++EXPORT_SYMBOL(__compat_down_interruptible); ++ ++int fastcall compat_sem_is_locked(struct compat_semaphore *sem) ++{ ++ return (int) atomic_read(&sem->count) < 0; ++} ++EXPORT_SYMBOL(compat_sem_is_locked); +Index: linux-2.6.24.7-rt27/arch/mips/kernel/signal.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/signal.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/signal.c 2009-02-08 00:02:23.000000000 -0500 +@@ -629,6 +629,10 @@ static void do_signal(struct pt_regs *re + siginfo_t info; + int signr; + ++#ifdef CONFIG_PREEMPT_RT ++ local_irq_enable(); ++ preempt_check_resched(); ++#endif + /* + * We want the common case to go fast, which is why we may in certain + * cases get here from kernel mode. Just return without doing anything +Index: linux-2.6.24.7-rt27/arch/mips/kernel/signal32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/signal32.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/signal32.c 2009-02-08 00:02:23.000000000 -0500 +@@ -655,6 +655,10 @@ static int setup_rt_frame_32(struct k_si + if (err) + goto give_sigsegv; + ++#ifdef CONFIG_PREEMPT_RT ++ local_irq_enable(); ++ preempt_check_resched(); ++#endif + /* + * Arguments to signal handler: + * +Index: linux-2.6.24.7-rt27/arch/mips/kernel/smp.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/smp.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/smp.c 2009-02-08 00:02:23.000000000 -0500 +@@ -91,7 +91,22 @@ asmlinkage __cpuinit void start_secondar + cpu_idle(); + } + +-DEFINE_SPINLOCK(smp_call_lock); ++DEFINE_RAW_SPINLOCK(smp_call_lock); ++ ++/* ++ * this function sends a 'reschedule' IPI to all other CPUs. ++ * This is used when RT tasks are starving and other CPUs ++ * might be able to run them. ++ */ ++void smp_send_reschedule_allbutself(void) ++{ ++ int cpu = smp_processor_id(); ++ int i; ++ ++ for (i = 0; i < NR_CPUS; i++) ++ if (cpu_online(i) && i != cpu) ++ core_send_ipi(i, SMP_RESCHEDULE_YOURSELF); ++} + + struct call_data_struct *call_data; + +@@ -314,6 +329,8 @@ int setup_profiling_timer(unsigned int m + return 0; + } + ++static DEFINE_RAW_SPINLOCK(tlbstate_lock); ++ + static void flush_tlb_all_ipi(void *info) + { + local_flush_tlb_all(); +@@ -371,6 +388,7 @@ static inline void smp_on_each_tlb(void + void flush_tlb_mm(struct mm_struct *mm) + { + preempt_disable(); ++ spin_lock(&tlbstate_lock); + + if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { + smp_on_other_tlbs(flush_tlb_mm_ipi, mm); +@@ -383,6 +401,7 @@ void flush_tlb_mm(struct mm_struct *mm) + if (cpu_context(cpu, mm)) + cpu_context(cpu, mm) = 0; + } ++ spin_unlock(&tlbstate_lock); + local_flush_tlb_mm(mm); + + preempt_enable(); +@@ -406,6 +425,8 @@ void flush_tlb_range(struct vm_area_stru + struct mm_struct *mm = vma->vm_mm; + + preempt_disable(); ++ spin_lock(&tlbstate_lock); ++ + if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { + struct flush_tlb_data fd = { + .vma = vma, +@@ -423,6 +444,7 @@ void flush_tlb_range(struct vm_area_stru + if (cpu_context(cpu, mm)) + cpu_context(cpu, mm) = 0; + } ++ spin_unlock(&tlbstate_lock); + local_flush_tlb_range(vma, start, end); + preempt_enable(); + } +@@ -454,6 +476,8 @@ static void flush_tlb_page_ipi(void *inf + void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) + { + preempt_disable(); ++ spin_lock(&tlbstate_lock); ++ + if ((atomic_read(&vma->vm_mm->mm_users) != 1) || (current->mm != vma->vm_mm)) { + struct flush_tlb_data fd = { + .vma = vma, +@@ -470,6 +494,7 @@ void flush_tlb_page(struct vm_area_struc + if (cpu_context(cpu, vma->vm_mm)) + cpu_context(cpu, vma->vm_mm) = 0; + } ++ spin_unlock(&tlbstate_lock); + local_flush_tlb_page(vma, page); + preempt_enable(); + } +Index: linux-2.6.24.7-rt27/arch/mips/kernel/traps.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/kernel/traps.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/kernel/traps.c 2009-02-08 00:02:23.000000000 -0500 +@@ -320,7 +320,7 @@ void show_registers(const struct pt_regs + printk("\n"); + } + +-static DEFINE_SPINLOCK(die_lock); ++static DEFINE_RAW_SPINLOCK(die_lock); + + void __noreturn die(const char * str, const struct pt_regs * regs) + { +Index: linux-2.6.24.7-rt27/arch/mips/mm/init.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/mm/init.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/mm/init.c 2009-02-08 00:02:23.000000000 -0500 +@@ -61,7 +61,7 @@ + + #endif /* CONFIG_MIPS_MT_SMTC */ + +-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); ++DEFINE_PER_CPU_LOCKED(struct mmu_gather, mmu_gathers); + + /* + * We have up to 8 empty zeroed pages so we can map one of the right colour +Index: linux-2.6.24.7-rt27/arch/mips/sibyte/cfe/smp.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/sibyte/cfe/smp.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/sibyte/cfe/smp.c 2009-02-08 00:02:23.000000000 -0500 +@@ -107,4 +107,8 @@ void __cpuinit prom_smp_finish(void) + */ + void prom_cpus_done(void) + { ++#ifdef CONFIG_HIGH_RES_TIMERS ++ extern void sync_c0_count_master(void); ++ sync_c0_count_master(); ++#endif + } +Index: linux-2.6.24.7-rt27/arch/mips/sibyte/sb1250/irq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/sibyte/sb1250/irq.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/sibyte/sb1250/irq.c 2009-02-08 00:02:23.000000000 -0500 +@@ -82,7 +82,7 @@ static struct irq_chip sb1250_irq_type = + /* Store the CPU id (not the logical number) */ + int sb1250_irq_owner[SB1250_NR_IRQS]; + +-DEFINE_SPINLOCK(sb1250_imr_lock); ++DEFINE_RAW_SPINLOCK(sb1250_imr_lock); + + void sb1250_mask_irq(int cpu, int irq) + { +@@ -316,6 +316,10 @@ void __init arch_init_irq(void) + #ifdef CONFIG_KGDB + imask |= STATUSF_IP6; + #endif ++ ++#ifdef CONFIG_HIGH_RES_TIMERS ++ imask |= STATUSF_IP7; ++#endif + /* Enable necessary IPs, disable the rest */ + change_c0_status(ST0_IM, imask); + +Index: linux-2.6.24.7-rt27/arch/mips/sibyte/sb1250/smp.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/sibyte/sb1250/smp.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/sibyte/sb1250/smp.c 2009-02-08 00:02:23.000000000 -0500 +@@ -60,7 +60,7 @@ void __cpuinit sb1250_smp_finish(void) + extern void sb1250_clockevent_init(void); + + sb1250_clockevent_init(); +- local_irq_enable(); ++ raw_local_irq_enable(); + } + + /* +Index: linux-2.6.24.7-rt27/arch/mips/sibyte/swarm/setup.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/mips/sibyte/swarm/setup.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/mips/sibyte/swarm/setup.c 2009-02-08 00:02:23.000000000 -0500 +@@ -136,6 +136,12 @@ void __init plat_mem_setup(void) + if (m41t81_probe()) + swarm_rtc_type = RTC_M4LT81; + ++#ifdef CONFIG_HIGH_RES_TIMERS ++ /* ++ * set the mips_hpt_frequency here ++ */ ++ mips_hpt_frequency = CONFIG_CPU_SPEED * 1000000; ++#endif + printk("This kernel optimized for " + #ifdef CONFIG_SIMULATION + "simulation" +Index: linux-2.6.24.7-rt27/include/asm-mips/asmmacro.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/asmmacro.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/asmmacro.h 2009-02-08 00:02:23.000000000 -0500 +@@ -21,7 +21,7 @@ + #endif + + #ifdef CONFIG_MIPS_MT_SMTC +- .macro local_irq_enable reg=t0 ++ .macro raw_local_irq_enable reg=t0 + mfc0 \reg, CP0_TCSTATUS + ori \reg, \reg, TCSTATUS_IXMT + xori \reg, \reg, TCSTATUS_IXMT +@@ -29,21 +29,21 @@ + _ehb + .endm + +- .macro local_irq_disable reg=t0 ++ .macro raw_local_irq_disable reg=t0 + mfc0 \reg, CP0_TCSTATUS + ori \reg, \reg, TCSTATUS_IXMT + mtc0 \reg, CP0_TCSTATUS + _ehb + .endm + #else +- .macro local_irq_enable reg=t0 ++ .macro raw_local_irq_enable reg=t0 + mfc0 \reg, CP0_STATUS + ori \reg, \reg, 1 + mtc0 \reg, CP0_STATUS + irq_enable_hazard + .endm + +- .macro local_irq_disable reg=t0 ++ .macro raw_local_irq_disable reg=t0 + mfc0 \reg, CP0_STATUS + ori \reg, \reg, 1 + xori \reg, \reg, 1 +Index: linux-2.6.24.7-rt27/include/asm-mips/atomic.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/atomic.h 2009-02-08 00:02:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/atomic.h 2009-02-08 00:02:23.000000000 -0500 +@@ -573,7 +573,6 @@ static __inline__ long atomic64_add_retu + raw_local_irq_restore(flags); + } + #endif +-#endif + + smp_llsc_mb(); + +Index: linux-2.6.24.7-rt27/include/asm-mips/bitops.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/bitops.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/bitops.h 2009-02-08 00:02:23.000000000 -0500 +@@ -606,9 +606,6 @@ static inline unsigned long __ffs(unsign + } + + /* +- * fls - find last bit set. +- * @word: The word to search +- * + * This is defined the same way as ffs. + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. + */ +@@ -626,6 +623,8 @@ static inline int fls64(__u64 word) + + return 64 - word; + } ++#define __bi_local_irq_save(x) raw_local_irq_save(x) ++#define __bi_local_irq_restore(x) raw_local_irq_restore(x) + #else + #include + #endif +Index: linux-2.6.24.7-rt27/include/asm-mips/hw_irq.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/hw_irq.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/hw_irq.h 2009-02-08 00:02:23.000000000 -0500 +@@ -9,6 +9,7 @@ + #define __ASM_HW_IRQ_H + + #include ++#include + + extern atomic_t irq_err_count; + +Index: linux-2.6.24.7-rt27/include/asm-mips/i8259.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/i8259.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/i8259.h 2009-02-08 00:02:23.000000000 -0500 +@@ -35,7 +35,7 @@ + #define SLAVE_ICW4_DEFAULT 0x01 + #define PIC_ICW4_AEOI 2 + +-extern spinlock_t i8259A_lock; ++extern raw_spinlock_t i8259A_lock; + + extern int i8259A_irq_pending(unsigned int irq); + extern void make_8259A_irq(unsigned int irq); +Index: linux-2.6.24.7-rt27/include/asm-mips/io.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/io.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/io.h 2009-02-08 00:02:23.000000000 -0500 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + #include + #include +Index: linux-2.6.24.7-rt27/include/asm-mips/linkage.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/linkage.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/linkage.h 2009-02-08 00:02:23.000000000 -0500 +@@ -3,6 +3,11 @@ + + #ifdef __ASSEMBLY__ + #include ++ ++/* FASTCALL stuff */ ++#define FASTCALL(x) x ++#define fastcall ++ + #endif + + #define __weak __attribute__((weak)) +Index: linux-2.6.24.7-rt27/include/asm-mips/m48t35.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/m48t35.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/m48t35.h 2009-02-08 00:02:23.000000000 -0500 +@@ -6,7 +6,7 @@ + + #include + +-extern spinlock_t rtc_lock; ++extern raw_spinlock_t rtc_lock; + + struct m48t35_rtc { + volatile u8 pad[0x7ff8]; /* starts at 0x7ff8 */ +Index: linux-2.6.24.7-rt27/include/asm-mips/rwsem.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/include/asm-mips/rwsem.h 2009-02-08 00:02:23.000000000 -0500 +@@ -0,0 +1,176 @@ ++/* ++ * include/asm-mips/rwsem.h: R/W semaphores for MIPS using the stuff ++ * in lib/rwsem.c. Adapted largely from include/asm-ppc/rwsem.h ++ * by john.cooper@timesys.com ++ */ ++ ++#ifndef _MIPS_RWSEM_H ++#define _MIPS_RWSEM_H ++ ++#ifndef _LINUX_RWSEM_H ++#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead" ++#endif ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#include ++ ++/* ++ * the semaphore definition ++ */ ++struct compat_rw_semaphore { ++ /* XXX this should be able to be an atomic_t -- paulus */ ++ signed long count; ++#define RWSEM_UNLOCKED_VALUE 0x00000000 ++#define RWSEM_ACTIVE_BIAS 0x00000001 ++#define RWSEM_ACTIVE_MASK 0x0000ffff ++#define RWSEM_WAITING_BIAS (-0x00010000) ++#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS ++#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) ++ raw_spinlock_t wait_lock; ++ struct list_head wait_list; ++#if RWSEM_DEBUG ++ int debug; ++#endif ++}; ++ ++/* ++ * initialisation ++ */ ++#if RWSEM_DEBUG ++#define __RWSEM_DEBUG_INIT , 0 ++#else ++#define __RWSEM_DEBUG_INIT /* */ ++#endif ++ ++#define __COMPAT_RWSEM_INITIALIZER(name) \ ++ { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \ ++ LIST_HEAD_INIT((name).wait_list) \ ++ __RWSEM_DEBUG_INIT } ++ ++#define COMPAT_DECLARE_RWSEM(name) \ ++ struct compat_rw_semaphore name = __COMPAT_RWSEM_INITIALIZER(name) ++ ++extern struct compat_rw_semaphore *rwsem_down_read_failed(struct compat_rw_semaphore *sem); ++extern struct compat_rw_semaphore *rwsem_down_write_failed(struct compat_rw_semaphore *sem); ++extern struct compat_rw_semaphore *rwsem_wake(struct compat_rw_semaphore *sem); ++extern struct compat_rw_semaphore *rwsem_downgrade_wake(struct compat_rw_semaphore *sem); ++ ++static inline void compat_init_rwsem(struct compat_rw_semaphore *sem) ++{ ++ sem->count = RWSEM_UNLOCKED_VALUE; ++ spin_lock_init(&sem->wait_lock); ++ INIT_LIST_HEAD(&sem->wait_list); ++#if RWSEM_DEBUG ++ sem->debug = 0; ++#endif ++} ++ ++/* ++ * lock for reading ++ */ ++static inline void __down_read(struct compat_rw_semaphore *sem) ++{ ++ if (atomic_inc_return((atomic_t *)(&sem->count)) > 0) ++ smp_wmb(); ++ else ++ rwsem_down_read_failed(sem); ++} ++ ++static inline int __down_read_trylock(struct compat_rw_semaphore *sem) ++{ ++ int tmp; ++ ++ while ((tmp = sem->count) >= 0) { ++ if (tmp == cmpxchg(&sem->count, tmp, ++ tmp + RWSEM_ACTIVE_READ_BIAS)) { ++ smp_wmb(); ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * lock for writing ++ */ ++static inline void __down_write(struct compat_rw_semaphore *sem) ++{ ++ int tmp; ++ ++ tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS, ++ (atomic_t *)(&sem->count)); ++ if (tmp == RWSEM_ACTIVE_WRITE_BIAS) ++ smp_wmb(); ++ else ++ rwsem_down_write_failed(sem); ++} ++ ++static inline int __down_write_trylock(struct compat_rw_semaphore *sem) ++{ ++ int tmp; ++ ++ tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, ++ RWSEM_ACTIVE_WRITE_BIAS); ++ smp_wmb(); ++ return tmp == RWSEM_UNLOCKED_VALUE; ++} ++ ++/* ++ * unlock after reading ++ */ ++static inline void __up_read(struct compat_rw_semaphore *sem) ++{ ++ int tmp; ++ ++ smp_wmb(); ++ tmp = atomic_dec_return((atomic_t *)(&sem->count)); ++ if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0) ++ rwsem_wake(sem); ++} ++ ++/* ++ * unlock after writing ++ */ ++static inline void __up_write(struct compat_rw_semaphore *sem) ++{ ++ smp_wmb(); ++ if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS, ++ (atomic_t *)(&sem->count)) < 0) ++ rwsem_wake(sem); ++} ++ ++/* ++ * implement atomic add functionality ++ */ ++static inline void rwsem_atomic_add(int delta, struct compat_rw_semaphore *sem) ++{ ++ atomic_add(delta, (atomic_t *)(&sem->count)); ++} ++ ++/* ++ * downgrade write lock to read lock ++ */ ++static inline void __downgrade_write(struct compat_rw_semaphore *sem) ++{ ++ int tmp; ++ ++ smp_wmb(); ++ tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count)); ++ if (tmp < 0) ++ rwsem_downgrade_wake(sem); ++} ++ ++/* ++ * implement exchange and add functionality ++ */ ++static inline int rwsem_atomic_update(int delta, struct compat_rw_semaphore *sem) ++{ ++ smp_mb(); ++ return atomic_add_return(delta, (atomic_t *)(&sem->count)); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* _MIPS_RWSEM_H */ +Index: linux-2.6.24.7-rt27/include/asm-mips/semaphore.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/semaphore.h 2009-02-08 00:02:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/semaphore.h 2009-02-08 00:02:23.000000000 -0500 +@@ -47,38 +47,41 @@ struct compat_semaphore { + wait_queue_head_t wait; + }; + +-#define __SEMAPHORE_INITIALIZER(name, n) \ ++#define __COMPAT_SEMAPHORE_INITIALIZER(name, n) \ + { \ + .count = ATOMIC_INIT(n), \ + .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + } + +-#define __DECLARE_SEMAPHORE_GENERIC(name, count) \ +- struct semaphore name = __SEMAPHORE_INITIALIZER(name, count) ++#define __COMPAT_MUTEX_INITIALIZER(name) \ ++ __COMPAT_SEMAPHORE_INITIALIZER(name, 1) + +-#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1) ++#define __COMPAT_DECLARE_SEMAPHORE_GENERIC(name, count) \ ++ struct compat_semaphore name = __COMPAT_SEMAPHORE_INITIALIZER(name,count) + +-static inline void sema_init(struct semaphore *sem, int val) ++#define COMPAT_DECLARE_MUTEX(name) __COMPAT_DECLARE_SEMAPHORE_GENERIC(name, 1) ++ ++static inline void compat_sema_init (struct compat_semaphore *sem, int val) + { + atomic_set(&sem->count, val); + init_waitqueue_head(&sem->wait); + } + +-static inline void init_MUTEX(struct semaphore *sem) ++static inline void compat_init_MUTEX (struct compat_semaphore *sem) + { +- sema_init(sem, 1); ++ compat_sema_init(sem, 1); + } + +-static inline void init_MUTEX_LOCKED(struct semaphore *sem) ++static inline void compat_init_MUTEX_LOCKED (struct compat_semaphore *sem) + { +- sema_init(sem, 0); ++ compat_sema_init(sem, 0); + } + +-extern void __down(struct semaphore * sem); +-extern int __down_interruptible(struct semaphore * sem); +-extern void __up(struct semaphore * sem); ++extern void __compat_down(struct compat_semaphore * sem); ++extern int __compat_down_interruptible(struct compat_semaphore * sem); ++extern void __compat_up(struct compat_semaphore * sem); + +-static inline void down(struct semaphore * sem) ++static inline void compat_down(struct compat_semaphore * sem) + { + might_sleep(); + +@@ -111,6 +114,8 @@ static inline void compat_up(struct comp + __compat_up(sem); + } + ++extern int compat_sem_is_locked(struct compat_semaphore *sem); ++ + #define compat_sema_count(sem) atomic_read(&(sem)->count) + + #include +Index: linux-2.6.24.7-rt27/include/asm-mips/spinlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/spinlock.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/spinlock.h 2009-02-08 00:02:23.000000000 -0500 +@@ -28,7 +28,7 @@ + * We make no fairness assumptions. They have a cost. + */ + +-static inline void __raw_spin_lock(raw_spinlock_t *lock) ++static inline void __raw_spin_lock(__raw_spinlock_t *lock) + { + unsigned int tmp; + +@@ -70,7 +70,7 @@ static inline void __raw_spin_lock(raw_s + smp_llsc_mb(); + } + +-static inline void __raw_spin_unlock(raw_spinlock_t *lock) ++static inline void __raw_spin_unlock(__raw_spinlock_t *lock) + { + smp_mb(); + +@@ -83,7 +83,7 @@ static inline void __raw_spin_unlock(raw + : "memory"); + } + +-static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock) ++static inline unsigned int __raw_spin_trylock(__raw_spinlock_t *lock) + { + unsigned int temp, res; + +@@ -144,7 +144,7 @@ static inline unsigned int __raw_spin_tr + */ + #define __raw_write_can_lock(rw) (!(rw)->lock) + +-static inline void __raw_read_lock(raw_rwlock_t *rw) ++static inline void __raw_read_lock(__raw_rwlock_t *rw) + { + unsigned int tmp; + +@@ -189,7 +189,7 @@ static inline void __raw_read_lock(raw_r + /* Note the use of sub, not subu which will make the kernel die with an + overflow exception if we ever try to unlock an rwlock that is already + unlocked or is being held by a writer. */ +-static inline void __raw_read_unlock(raw_rwlock_t *rw) ++static inline void __raw_read_unlock(__raw_rwlock_t *rw) + { + unsigned int tmp; + +@@ -223,7 +223,7 @@ static inline void __raw_read_unlock(raw + } + } + +-static inline void __raw_write_lock(raw_rwlock_t *rw) ++static inline void __raw_write_lock(__raw_rwlock_t *rw) + { + unsigned int tmp; + +@@ -265,7 +265,7 @@ static inline void __raw_write_lock(raw_ + smp_llsc_mb(); + } + +-static inline void __raw_write_unlock(raw_rwlock_t *rw) ++static inline void __raw_write_unlock(__raw_rwlock_t *rw) + { + smp_mb(); + +@@ -277,7 +277,7 @@ static inline void __raw_write_unlock(ra + : "memory"); + } + +-static inline int __raw_read_trylock(raw_rwlock_t *rw) ++static inline int __raw_read_trylock(__raw_rwlock_t *rw) + { + unsigned int tmp; + int ret; +@@ -321,7 +321,7 @@ static inline int __raw_read_trylock(raw + return ret; + } + +-static inline int __raw_write_trylock(raw_rwlock_t *rw) ++static inline int __raw_write_trylock(__raw_rwlock_t *rw) + { + unsigned int tmp; + int ret; +Index: linux-2.6.24.7-rt27/include/asm-mips/spinlock_types.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/spinlock_types.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/spinlock_types.h 2009-02-08 00:02:23.000000000 -0500 +@@ -7,13 +7,13 @@ + + typedef struct { + volatile unsigned int lock; +-} raw_spinlock_t; ++} __raw_spinlock_t; + + #define __RAW_SPIN_LOCK_UNLOCKED { 0 } + + typedef struct { + volatile unsigned int lock; +-} raw_rwlock_t; ++} __raw_rwlock_t; + + #define __RAW_RW_LOCK_UNLOCKED { 0 } + +Index: linux-2.6.24.7-rt27/include/asm-mips/thread_info.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/thread_info.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/thread_info.h 2009-02-08 00:02:23.000000000 -0500 +@@ -112,6 +112,7 @@ register struct thread_info *__current_t + #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ + #define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */ + #define TIF_SECCOMP 4 /* secure computing */ ++#define TIF_NEED_RESCHED_DELAYED 6 /* reschedule on return to userspace */ + #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ + #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ + #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ +@@ -129,6 +130,7 @@ register struct thread_info *__current_t + #define _TIF_NEED_RESCHED (1< + #include + +-extern spinlock_t rtc_lock; ++extern raw_spinlock_t rtc_lock; + + /* + * RTC ops. By default, they point to weak no-op RTC functions. +Index: linux-2.6.24.7-rt27/include/asm-mips/timeofday.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/include/asm-mips/timeofday.h 2009-02-08 00:02:23.000000000 -0500 +@@ -0,0 +1,5 @@ ++#ifndef _ASM_MIPS_TIMEOFDAY_H ++#define _ASM_MIPS_TIMEOFDAY_H ++#include ++#endif ++ +Index: linux-2.6.24.7-rt27/include/asm-mips/uaccess.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-mips/uaccess.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-mips/uaccess.h 2009-02-08 00:02:23.000000000 -0500 +@@ -427,7 +427,6 @@ extern size_t __copy_user(void *__to, co + const void *__cu_from; \ + long __cu_len; \ + \ +- might_sleep(); \ + __cu_to = (to); \ + __cu_from = (from); \ + __cu_len = (n); \ +@@ -483,7 +482,6 @@ extern size_t __copy_user_inatomic(void + const void *__cu_from; \ + long __cu_len; \ + \ +- might_sleep(); \ + __cu_to = (to); \ + __cu_from = (from); \ + __cu_len = (n); \ +@@ -562,7 +560,6 @@ extern size_t __copy_user_inatomic(void + const void __user *__cu_from; \ + long __cu_len; \ + \ +- might_sleep(); \ + __cu_to = (to); \ + __cu_from = (from); \ + __cu_len = (n); \ +@@ -593,7 +590,6 @@ extern size_t __copy_user_inatomic(void + const void __user *__cu_from; \ + long __cu_len; \ + \ +- might_sleep(); \ + __cu_to = (to); \ + __cu_from = (from); \ + __cu_len = (n); \ +@@ -611,7 +607,6 @@ extern size_t __copy_user_inatomic(void + const void __user *__cu_from; \ + long __cu_len; \ + \ +- might_sleep(); \ + __cu_to = (to); \ + __cu_from = (from); \ + __cu_len = (n); \ +@@ -638,7 +633,6 @@ __clear_user(void __user *addr, __kernel + { + __kernel_size_t res; + +- might_sleep(); + __asm__ __volatile__( + "move\t$4, %1\n\t" + "move\t$5, $0\n\t" +@@ -687,7 +681,6 @@ __strncpy_from_user(char *__to, const ch + { + long res; + +- might_sleep(); + __asm__ __volatile__( + "move\t$4, %1\n\t" + "move\t$5, %2\n\t" +@@ -724,7 +717,6 @@ strncpy_from_user(char *__to, const char + { + long res; + +- might_sleep(); + __asm__ __volatile__( + "move\t$4, %1\n\t" + "move\t$5, %2\n\t" +@@ -743,7 +735,6 @@ static inline long __strlen_user(const c + { + long res; + +- might_sleep(); + __asm__ __volatile__( + "move\t$4, %1\n\t" + __MODULE_JAL(__strlen_user_nocheck_asm) +@@ -773,7 +764,6 @@ static inline long strlen_user(const cha + { + long res; + +- might_sleep(); + __asm__ __volatile__( + "move\t$4, %1\n\t" + __MODULE_JAL(__strlen_user_asm) +@@ -790,7 +780,6 @@ static inline long __strnlen_user(const + { + long res; + +- might_sleep(); + __asm__ __volatile__( + "move\t$4, %1\n\t" + "move\t$5, %2\n\t" +@@ -821,7 +810,6 @@ static inline long strnlen_user(const ch + { + long res; + +- might_sleep(); + __asm__ __volatile__( + "move\t$4, %1\n\t" + "move\t$5, %2\n\t" --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0044-0031-Subject-SCHED-Only-balance-our-RT-tasks-within-ou.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0044-0031-Subject-SCHED-Only-balance-our-RT-tasks-within-ou.patch @@ -0,0 +1,169 @@ +From 04746d899536b279a7bf3298d4a84a1d5baf9090 Mon Sep 17 00:00:00 2001 +From: Gregory Haskins +Date: Tue, 11 Dec 2007 10:02:43 +0100 +Subject: [PATCH] Subject: SCHED - Only balance our RT tasks within our + +We move the rt-overload data as the first global to per-domain +reclassification. This limits the scope of overload related cache-line +bouncing to stay with a specified partition instead of affecting all +cpus in the system. + +Finally, we limit the scope of find_lowest_cpu searches to the domain +instead of the entire system. Note that we would always respect domain +boundaries even without this patch, but we first would scan potentially +all cpus before whittling the list down. Now we can avoid looking at +RQs that are out of scope, again reducing cache-line hits. + +Note: In some cases, task->cpus_allowed will effectively reduce our search +to within our domain. However, I believe there are cases where the +cpus_allowed mask may be all ones and therefore we err on the side of +caution. If it can be optimized later, so be it. + +Signed-off-by: Gregory Haskins +CC: Christoph Lameter +Signed-off-by: Ingo Molnar + +--- + kernel/sched.c | 7 ++++++ + kernel/sched_rt.c | 57 +++++++++++++++++++++++++++++------------------------- + 2 files changed, 38 insertions(+), 26 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:01:03.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:01:03.000000000 -0500 +@@ -289,6 +289,13 @@ struct root_domain { + atomic_t refcount; + cpumask_t span; + cpumask_t online; ++ ++ /* ++ * The "RT overload" flag: it gets set if a CPU has more than ++ * one runnable RT task. ++ */ ++ cpumask_t rto_mask; ++ atomic_t rto_count; + }; + + static struct root_domain def_root_domain; +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:01:03.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:01:03.000000000 -0500 +@@ -5,22 +5,14 @@ + + #ifdef CONFIG_SMP + +-/* +- * The "RT overload" flag: it gets set if a CPU has more than +- * one runnable RT task. +- */ +-static cpumask_t rt_overload_mask; +-static atomic_t rto_count; +- +-static inline int rt_overloaded(void) ++static inline int rt_overloaded(struct rq *rq) + { +- return atomic_read(&rto_count); ++ return atomic_read(&rq->rd->rto_count); + } + + static inline void rt_set_overload(struct rq *rq) + { +- rq->rt.overloaded = 1; +- cpu_set(rq->cpu, rt_overload_mask); ++ cpu_set(rq->cpu, rq->rd->rto_mask); + /* + * Make sure the mask is visible before we set + * the overload count. That is checked to determine +@@ -29,23 +21,25 @@ static inline void rt_set_overload(struc + * updated yet. + */ + wmb(); +- atomic_inc(&rto_count); ++ atomic_inc(&rq->rd->rto_count); + } + + static inline void rt_clear_overload(struct rq *rq) + { + /* the order here really doesn't matter */ +- atomic_dec(&rto_count); +- cpu_clear(rq->cpu, rt_overload_mask); +- rq->rt.overloaded = 0; ++ atomic_dec(&rq->rd->rto_count); ++ cpu_clear(rq->cpu, rq->rd->rto_mask); + } + + static void update_rt_migration(struct rq *rq) + { +- if (rq->rt.rt_nr_migratory && (rq->rt.rt_nr_running > 1)) ++ if (rq->rt.rt_nr_migratory && (rq->rt.rt_nr_running > 1)) { + rt_set_overload(rq); +- else ++ rq->rt.overloaded = 1; ++ } else { + rt_clear_overload(rq); ++ rq->rt.overloaded = 0; ++ } + } + #endif /* CONFIG_SMP */ + +@@ -302,7 +296,7 @@ static int find_lowest_cpus(struct task_ + int count = 0; + int cpu; + +- cpus_and(*lowest_mask, cpu_online_map, task->cpus_allowed); ++ cpus_and(*lowest_mask, task_rq(task)->rd->online, task->cpus_allowed); + + /* + * Scan each rq for the lowest prio. +@@ -576,18 +570,12 @@ static int pull_rt_task(struct rq *this_ + struct task_struct *p, *next; + struct rq *src_rq; + +- /* +- * If cpusets are used, and we have overlapping +- * run queue cpusets, then this algorithm may not catch all. +- * This is just the price you pay on trying to keep +- * dirtying caches down on large SMP machines. +- */ +- if (likely(!rt_overloaded())) ++ if (likely(!rt_overloaded(this_rq))) + return 0; + + next = pick_next_task_rt(this_rq); + +- for_each_cpu_mask(cpu, rt_overload_mask) { ++ for_each_cpu_mask(cpu, this_rq->rd->rto_mask) { + if (this_cpu == cpu) + continue; + +@@ -805,6 +793,20 @@ static void task_tick_rt(struct rq *rq, + } + } + ++/* Assumes rq->lock is held */ ++static void join_domain_rt(struct rq *rq) ++{ ++ if (rq->rt.overloaded) ++ rt_set_overload(rq); ++} ++ ++/* Assumes rq->lock is held */ ++static void leave_domain_rt(struct rq *rq) ++{ ++ if (rq->rt.overloaded) ++ rt_clear_overload(rq); ++} ++ + static void set_curr_task_rt(struct rq *rq) + { + struct task_struct *p = rq->curr; +@@ -834,4 +836,7 @@ const struct sched_class rt_sched_class + + .set_curr_task = set_curr_task_rt, + .task_tick = task_tick_rt, ++ ++ .join_domain = join_domain_rt, ++ .leave_domain = leave_domain_rt, + }; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0430-remove-spinlock-define.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0430-remove-spinlock-define.patch @@ -0,0 +1,52 @@ +From ghaskins@novell.com Mon Mar 24 17:45:51 2008 +Date: Fri, 07 Mar 2008 09:06:35 -0500 +From: Gregory Haskins +To: mingo@elte.hu, rostedt@goodmis.org, tglx@linutronix.de, + linux-rt-users@vger.kernel.org +Cc: ghaskins@novell.com, linux-kernel@vger.kernel.org +Subject: [PATCH] RT: fix spinlock preemption feature when PREEMPT_RT is + enabled + + [ The following text is in the "utf-8" character set. ] + [ Your display is set for the "iso-8859-1" character set. ] + [ Some characters may be displayed incorrectly. ] + +kernel/spinlock.c implements two versions of spinlock wrappers around +the arch-specific implementations: + +1) A simple passthrough which implies disabled preemption while spinning + +2) A "preemptible waiter" version which uses trylock. + +Currently, PREEMPT && SMP will turn on the preemptible feature, and +lockdep or PREEMPT_RT will disable it. Disabling the feature for +lockdep makes perfect sense, but PREEMPT_RT is counter-intuitive. My +guess is that this was inadvertent, so this patch once again enables +the feature for PREEMPT_RT. + +(Since PREEMPT is set for PREEMPT_RT, we simply get rid of the extra +condition). + +I have tested the PREEMPT_RT kernel with this patch and all seems well. +Therefore, if there *is* an issue with running preemptible versions of +these spinlocks under PREEMPT_RT, it is not immediately apparent why. + +Signed-off-by: Gregory Haskins +--- + + kernel/spinlock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/spinlock.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/spinlock.c 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/spinlock.c 2009-02-08 00:04:15.000000000 -0500 +@@ -117,7 +117,7 @@ EXPORT_SYMBOL(__write_trylock_irqsave); + * not re-enabled during lock-acquire (which the preempt-spin-ops do): + */ + #if !defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP) || \ +- defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_PREEMPT_RT) ++ defined(CONFIG_DEBUG_LOCK_ALLOC) + + void __lockfunc __read_lock(raw_rwlock_t *lock) + { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0182-percpu-locked-mm.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0182-percpu-locked-mm.patch @@ -0,0 +1,454 @@ + arch/ppc/mm/init.c | 2 - + arch/x86/mm/init_32.c | 2 - + arch/x86/mm/init_64.c | 2 - + include/asm-generic/percpu.h | 24 ++++++++++++ + include/asm-generic/tlb.h | 9 +++- + include/asm-x86/percpu_32.h | 19 +++++++++ + include/asm-x86/percpu_64.h | 25 ++++++++++++ + include/linux/percpu.h | 23 +++++++++++ + mm/swap.c | 85 ++++++++++++++++++++++++++++++++++++------- + 9 files changed, 173 insertions(+), 18 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/ppc/mm/init.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ppc/mm/init.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ppc/mm/init.c 2009-02-08 00:02:09.000000000 -0500 +@@ -55,7 +55,7 @@ + #endif + #define MAX_LOW_MEM CONFIG_LOWMEM_SIZE + +-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); ++DEFINE_PER_CPU_LOCKED(struct mmu_gather, mmu_gathers); + + unsigned long total_memory; + unsigned long total_lowmem; +Index: linux-2.6.24.7-rt27/arch/x86/mm/init_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/mm/init_32.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/mm/init_32.c 2009-02-08 00:02:09.000000000 -0500 +@@ -47,7 +47,7 @@ + + unsigned int __VMALLOC_RESERVE = 128 << 20; + +-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); ++DEFINE_PER_CPU_LOCKED(struct mmu_gather, mmu_gathers); + unsigned long highstart_pfn, highend_pfn; + + static int noinline do_test_wp_bit(void); +Index: linux-2.6.24.7-rt27/arch/x86/mm/init_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/mm/init_64.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/mm/init_64.c 2009-02-08 00:02:09.000000000 -0500 +@@ -53,7 +53,7 @@ EXPORT_SYMBOL(dma_ops); + + static unsigned long dma_reserve __initdata; + +-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); ++DEFINE_PER_CPU_LOCKED(struct mmu_gather, mmu_gathers); + + /* + * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the +Index: linux-2.6.24.7-rt27/include/asm-generic/percpu.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-generic/percpu.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-generic/percpu.h 2009-02-08 00:02:09.000000000 -0500 +@@ -19,6 +19,10 @@ extern unsigned long __per_cpu_offset[NR + __typeof__(type) per_cpu__##name \ + ____cacheline_aligned_in_smp + ++#define DEFINE_PER_CPU_LOCKED(type, name) \ ++ __attribute__((__section__(".data.percpu"))) __DEFINE_SPINLOCK(per_cpu_lock__##name##_locked); \ ++ __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name##_locked ++ + /* var is in discarded region: offset to particular copy we want */ + #define per_cpu(var, cpu) (*({ \ + extern int simple_identifier_##var(void); \ +@@ -26,6 +30,15 @@ extern unsigned long __per_cpu_offset[NR + #define __get_cpu_var(var) per_cpu(var, smp_processor_id()) + #define __raw_get_cpu_var(var) per_cpu(var, raw_smp_processor_id()) + ++#define per_cpu_lock(var, cpu) \ ++ (*RELOC_HIDE(&per_cpu_lock__##var##_locked, __per_cpu_offset[cpu])) ++#define per_cpu_var_locked(var, cpu) \ ++ (*RELOC_HIDE(&per_cpu__##var##_locked, __per_cpu_offset[cpu])) ++#define __get_cpu_lock(var, cpu) \ ++ per_cpu_lock(var, cpu) ++#define __get_cpu_var_locked(var, cpu) \ ++ per_cpu_var_locked(var, cpu) ++ + /* A macro to avoid #include hell... */ + #define percpu_modcopy(pcpudst, src, size) \ + do { \ +@@ -38,19 +51,30 @@ do { \ + + #define DEFINE_PER_CPU(type, name) \ + __typeof__(type) per_cpu__##name ++#define DEFINE_PER_CPU_LOCKED(type, name) \ ++ __DEFINE_SPINLOCK(per_cpu_lock__##name##_locked); \ ++ __typeof__(type) per_cpu__##name##_locked + + #define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \ + DEFINE_PER_CPU(type, name) + + #define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var)) ++#define per_cpu_var_locked(var, cpu) (*((void)(cpu), &per_cpu__##var##_locked)) + #define __get_cpu_var(var) per_cpu__##var + #define __raw_get_cpu_var(var) per_cpu__##var ++#define __get_cpu_lock(var, cpu) per_cpu_lock__##var##_locked ++#define __get_cpu_var_locked(var, cpu) per_cpu__##var##_locked + + #endif /* SMP */ + + #define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name ++#define DECLARE_PER_CPU_LOCKED(type, name) \ ++ extern spinlock_t per_cpu_lock__##name##_locked; \ ++ extern __typeof__(type) per_cpu__##name##_locked + + #define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var) + #define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var) ++#define EXPORT_PER_CPU_LOCKED_SYMBOL(var) EXPORT_SYMBOL(per_cpu_lock__##var##_locked); EXPORT_SYMBOL(per_cpu__##var##_locked) ++#define EXPORT_PER_CPU_LOCKED_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu_lock__##var##_locked); EXPORT_SYMBOL_GPL(per_cpu__##var##_locked) + + #endif /* _ASM_GENERIC_PERCPU_H_ */ +Index: linux-2.6.24.7-rt27/include/asm-generic/tlb.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-generic/tlb.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-generic/tlb.h 2009-02-08 00:02:09.000000000 -0500 +@@ -42,11 +42,12 @@ struct mmu_gather { + unsigned int nr; /* set to ~0U means fast mode */ + unsigned int need_flush;/* Really unmapped some ptes? */ + unsigned int fullmm; /* non-zero means full mm flush */ ++ int cpu; + struct page * pages[FREE_PTE_NR]; + }; + + /* Users of the generic TLB shootdown code must declare this storage space. */ +-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); ++DECLARE_PER_CPU_LOCKED(struct mmu_gather, mmu_gathers); + + /* tlb_gather_mmu + * Return a pointer to an initialized struct mmu_gather. +@@ -54,8 +55,10 @@ DECLARE_PER_CPU(struct mmu_gather, mmu_g + static inline struct mmu_gather * + tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) + { +- struct mmu_gather *tlb = &get_cpu_var(mmu_gathers); ++ int cpu; ++ struct mmu_gather *tlb = &get_cpu_var_locked(mmu_gathers, &cpu); + ++ tlb->cpu = cpu; + tlb->mm = mm; + + /* Use fast mode if only one CPU is online */ +@@ -91,7 +94,7 @@ tlb_finish_mmu(struct mmu_gather *tlb, u + /* keep the page table cache within bounds */ + check_pgt_cache(); + +- put_cpu_var(mmu_gathers); ++ put_cpu_var_locked(mmu_gathers, tlb->cpu); + } + + /* tlb_remove_page +Index: linux-2.6.24.7-rt27/include/asm-x86/percpu_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/percpu_32.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/percpu_32.h 2009-02-08 00:02:09.000000000 -0500 +@@ -51,6 +51,10 @@ extern unsigned long __per_cpu_offset[]; + + /* Separate out the type, so (int[3], foo) works. */ + #define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name ++#define DECLARE_PER_CPU_LOCKED(type, name) \ ++ extern spinlock_t per_cpu_lock__##name##_locked; \ ++ extern __typeof__(type) per_cpu__##name##_locked ++ + #define DEFINE_PER_CPU(type, name) \ + __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name + +@@ -59,6 +63,10 @@ extern unsigned long __per_cpu_offset[]; + __typeof__(type) per_cpu__##name \ + ____cacheline_aligned_in_smp + ++#define DEFINE_PER_CPU_LOCKED(type, name) \ ++ __attribute__((__section__(".data.percpu"))) __DEFINE_SPINLOCK(per_cpu_lock__##name##_locked); \ ++ __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name##_locked ++ + /* We can use this directly for local CPU (faster). */ + DECLARE_PER_CPU(unsigned long, this_cpu_off); + +@@ -74,6 +82,15 @@ DECLARE_PER_CPU(unsigned long, this_cpu_ + + #define __get_cpu_var(var) __raw_get_cpu_var(var) + ++#define per_cpu_lock(var, cpu) \ ++ (*RELOC_HIDE(&per_cpu_lock__##var##_locked, __per_cpu_offset[cpu])) ++#define per_cpu_var_locked(var, cpu) \ ++ (*RELOC_HIDE(&per_cpu__##var##_locked, __per_cpu_offset[cpu])) ++#define __get_cpu_lock(var, cpu) \ ++ per_cpu_lock(var, cpu) ++#define __get_cpu_var_locked(var, cpu) \ ++ per_cpu_var_locked(var, cpu) ++ + /* A macro to avoid #include hell... */ + #define percpu_modcopy(pcpudst, src, size) \ + do { \ +@@ -85,6 +102,8 @@ do { \ + + #define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var) + #define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var) ++#define EXPORT_PER_CPU_LOCKED_SYMBOL(var) EXPORT_SYMBOL(per_cpu_lock__##var##_locked); EXPORT_SYMBOL(per_cpu__##var##_locked) ++#define EXPORT_PER_CPU_LOCKED_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu_lock__##var##_locked); EXPORT_SYMBOL_GPL(per_cpu__##var##_locked) + + /* fs segment starts at (positive) offset == __per_cpu_offset[cpu] */ + #define __percpu_seg "%%fs:" +Index: linux-2.6.24.7-rt27/include/asm-x86/percpu_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/percpu_64.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/percpu_64.h 2009-02-08 00:02:09.000000000 -0500 +@@ -19,6 +19,9 @@ + /* Separate out the type, so (int[3], foo) works. */ + #define DEFINE_PER_CPU(type, name) \ + __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name ++#define DEFINE_PER_CPU_LOCKED(type, name) \ ++ __attribute__((__section__(".data.percpu"))) __DEFINE_SPINLOCK(per_cpu_lock__##name##_locked); \ ++ __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name##_locked + + #define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \ + __attribute__((__section__(".data.percpu.shared_aligned"))) \ +@@ -36,6 +39,15 @@ + extern int simple_identifier_##var(void); \ + RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()); })) + ++#define per_cpu_lock(var, cpu) \ ++ (*RELOC_HIDE(&per_cpu_lock__##var##_locked, __per_cpu_offset(cpu))) ++#define per_cpu_var_locked(var, cpu) \ ++ (*RELOC_HIDE(&per_cpu__##var##_locked, __per_cpu_offset(cpu))) ++#define __get_cpu_lock(var, cpu) \ ++ per_cpu_lock(var, cpu) ++#define __get_cpu_var_locked(var, cpu) \ ++ per_cpu_var_locked(var, cpu) ++ + /* A macro to avoid #include hell... */ + #define percpu_modcopy(pcpudst, src, size) \ + do { \ +@@ -54,15 +66,28 @@ extern void setup_per_cpu_areas(void); + #define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \ + DEFINE_PER_CPU(type, name) + ++#define DEFINE_PER_CPU_LOCKED(type, name) \ ++ spinlock_t per_cpu_lock__##name##_locked = SPIN_LOCK_UNLOCKED; \ ++ __typeof__(type) per_cpu__##name##_locked ++ + #define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var)) ++#define per_cpu_var_locked(var, cpu) (*((void)(cpu), &per_cpu__##var##_locked)) + #define __get_cpu_var(var) per_cpu__##var + #define __raw_get_cpu_var(var) per_cpu__##var ++#define __get_cpu_lock(var, cpu) per_cpu_lock__##var##_locked ++#define __get_cpu_var_locked(var, cpu) per_cpu__##var##_locked + + #endif /* SMP */ + + #define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name + ++#define DECLARE_PER_CPU_LOCKED(type, name) \ ++ extern spinlock_t per_cpu_lock__##name##_locked; \ ++ extern __typeof__(type) per_cpu__##name##_locked ++ + #define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var) + #define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var) ++#define EXPORT_PER_CPU_LOCKED_SYMBOL(var) EXPORT_SYMBOL(per_cpu_lock__##var##_locked); EXPORT_SYMBOL(per_cpu__##var##_locked) ++#define EXPORT_PER_CPU_LOCKED_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu_lock__##var##_locked); EXPORT_SYMBOL_GPL(per_cpu__##var##_locked) + + #endif /* _ASM_X8664_PERCPU_H_ */ +Index: linux-2.6.24.7-rt27/include/linux/percpu.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/percpu.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/percpu.h 2009-02-08 00:02:09.000000000 -0500 +@@ -31,6 +31,29 @@ + &__get_cpu_var(var); })) + #define put_cpu_var(var) preempt_enable() + ++/* ++ * Per-CPU data structures with an additional lock - useful for ++ * PREEMPT_RT code that wants to reschedule but also wants ++ * per-CPU data structures. ++ * ++ * 'cpu' gets updated with the CPU the task is currently executing on. ++ * ++ * NOTE: on normal !PREEMPT_RT kernels these per-CPU variables ++ * are the same as the normal per-CPU variables, so there no ++ * runtime overhead. ++ */ ++#define get_cpu_var_locked(var, cpuptr) \ ++(*({ \ ++ int __cpu = raw_smp_processor_id(); \ ++ \ ++ *(cpuptr) = __cpu; \ ++ spin_lock(&__get_cpu_lock(var, __cpu)); \ ++ &__get_cpu_var_locked(var, __cpu); \ ++})) ++ ++#define put_cpu_var_locked(var, cpu) \ ++ do { (void)cpu; spin_unlock(&__get_cpu_lock(var, cpu)); } while (0) ++ + #ifdef CONFIG_SMP + + struct percpu_data { +Index: linux-2.6.24.7-rt27/mm/swap.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/swap.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/swap.c 2009-02-08 00:02:10.000000000 -0500 +@@ -33,10 +33,64 @@ + /* How many pages do we try to swap or page in/out together? */ + int page_cluster; + ++/* ++ * On PREEMPT_RT we don't want to disable preemption for cpu variables. ++ * We grab a cpu and then use that cpu to lock the variables accordingly. ++ */ ++#ifdef CONFIG_PREEMPT_RT ++static DEFINE_PER_CPU_LOCKED(struct pagevec, lru_add_pvecs) = { 0, }; ++static DEFINE_PER_CPU_LOCKED(struct pagevec, lru_add_active_pvecs) = { 0, }; ++static DEFINE_PER_CPU_LOCKED(struct pagevec, lru_rotate_pvecs) = { 0, }; ++ ++#define swap_get_cpu_var_irq_save(var, flags, cpu) \ ++ ({ \ ++ (void)flags; \ ++ &get_cpu_var_locked(var, &cpu); \ ++ }) ++#define swap_put_cpu_var_irq_restore(var, flags, cpu) \ ++ put_cpu_var_locked(var, cpu) ++#define swap_get_cpu_var(var, cpu) \ ++ &get_cpu_var_locked(var, &cpu) ++#define swap_put_cpu_var(var, cpu) \ ++ put_cpu_var_locked(var, cpu) ++#define swap_per_cpu_lock(var, cpu) \ ++ ({ \ ++ spin_lock(&__get_cpu_lock(var, cpu)); \ ++ &__get_cpu_var_locked(var, cpu); \ ++ }) ++#define swap_per_cpu_unlock(var, cpu) \ ++ spin_unlock(&__get_cpu_lock(var, cpu)); ++#define swap_get_cpu() raw_smp_processor_id(); ++#define swap_put_cpu() ++#else + static DEFINE_PER_CPU(struct pagevec, lru_add_pvecs) = { 0, }; + static DEFINE_PER_CPU(struct pagevec, lru_add_active_pvecs) = { 0, }; + static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs) = { 0, }; + ++#define swap_get_cpu_var_irq_save(var, flags, cpu) \ ++ ({ \ ++ (void)cpu; \ ++ local_irq_save(flags); \ ++ &__get_cpu_var(var); \ ++ }) ++#define swap_put_cpu_var_irq_restore(var, flags, cpu) \ ++ local_irq_restore(flags) ++#define swap_get_cpu_var(var, cpu) \ ++ ({ (void)cpu; &get_cpu_var(var); }) ++#define swap_put_cpu_var(var, cpu) \ ++ do { \ ++ (void)cpu; \ ++ put_cpu_var(var); \ ++ } while(0) ++#define swap_per_cpu_lock(var, cpu) \ ++ &per_cpu(lru_add_pvecs, cpu) ++#define swap_per_cpu_unlock(var, cpu) \ ++ do { } while(0) ++#define swap_get_cpu() get_cpu() ++#define swap_put_cpu() put_cpu(); ++ ++#endif /* CONFIG_PREEMPT_RT */ ++ + /* + * This path almost never happens for VM activity - pages are normally + * freed via pagevecs. But it gets used by networking. +@@ -139,6 +193,7 @@ int rotate_reclaimable_page(struct page + { + struct pagevec *pvec; + unsigned long flags; ++ int cpu; + + if (PageLocked(page)) + return 1; +@@ -150,11 +205,10 @@ int rotate_reclaimable_page(struct page + return 1; + + page_cache_get(page); +- local_irq_save(flags); +- pvec = &__get_cpu_var(lru_rotate_pvecs); ++ pvec = swap_get_cpu_var_irq_save(lru_rotate_pvecs, flags, cpu); + if (!pagevec_add(pvec, page)) + pagevec_move_tail(pvec); +- local_irq_restore(flags); ++ swap_put_cpu_var_irq_restore(lru_rotate_pvecs, flags, cpu); + + if (!test_clear_page_writeback(page)) + BUG(); +@@ -204,22 +258,24 @@ EXPORT_SYMBOL(mark_page_accessed); + */ + void fastcall lru_cache_add(struct page *page) + { +- struct pagevec *pvec = &get_cpu_var(lru_add_pvecs); ++ int cpu; ++ struct pagevec *pvec = swap_get_cpu_var(lru_add_pvecs, cpu); + + page_cache_get(page); + if (!pagevec_add(pvec, page)) + __pagevec_lru_add(pvec); +- put_cpu_var(lru_add_pvecs); ++ swap_put_cpu_var(lru_add_pvecs, cpu); + } + + void fastcall lru_cache_add_active(struct page *page) + { +- struct pagevec *pvec = &get_cpu_var(lru_add_active_pvecs); ++ int cpu; ++ struct pagevec *pvec = swap_get_cpu_var(lru_add_active_pvecs, cpu); + + page_cache_get(page); + if (!pagevec_add(pvec, page)) + __pagevec_lru_add_active(pvec); +- put_cpu_var(lru_add_active_pvecs); ++ swap_put_cpu_var(lru_add_active_pvecs, cpu); + } + + /* +@@ -231,15 +287,17 @@ static void drain_cpu_pagevecs(int cpu) + { + struct pagevec *pvec; + +- pvec = &per_cpu(lru_add_pvecs, cpu); ++ pvec = swap_per_cpu_lock(lru_add_pvecs, cpu); + if (pagevec_count(pvec)) + __pagevec_lru_add(pvec); ++ swap_per_cpu_unlock(lru_add_pvecs, cpu); + +- pvec = &per_cpu(lru_add_active_pvecs, cpu); ++ pvec = swap_per_cpu_lock(lru_add_active_pvecs, cpu); + if (pagevec_count(pvec)) + __pagevec_lru_add_active(pvec); ++ swap_per_cpu_unlock(lru_add_active_pvecs, cpu); + +- pvec = &per_cpu(lru_rotate_pvecs, cpu); ++ pvec = swap_per_cpu_lock(lru_rotate_pvecs, cpu); + if (pagevec_count(pvec)) { + unsigned long flags; + +@@ -248,12 +306,15 @@ static void drain_cpu_pagevecs(int cpu) + pagevec_move_tail(pvec); + local_irq_restore(flags); + } ++ swap_per_cpu_unlock(lru_rotate_pvecs, cpu); + } + + void lru_add_drain(void) + { +- drain_cpu_pagevecs(get_cpu()); +- put_cpu(); ++ int cpu; ++ cpu = swap_get_cpu(); ++ drain_cpu_pagevecs(cpu); ++ swap_put_cpu(); + } + + #ifdef CONFIG_NUMA --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0054-0044-sched-remove-some-old-cpuset-logic.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0054-0044-sched-remove-some-old-cpuset-logic.patch @@ -0,0 +1,67 @@ +From 4115ceb4075bf6156a26446777eef274de82610e Mon Sep 17 00:00:00 2001 +From: Gregory Haskins +Date: Tue, 11 Dec 2007 10:02:48 +0100 +Subject: [PATCH] sched: remove some old cpuset logic + +We had support for overlapping cpuset based rto logic in early +prototypes that is no longer used, so remove it. + +Signed-off-by: Gregory Haskins +Signed-off-by: Steven Rostedt +Signed-off-by: Ingo Molnar + +--- + kernel/sched_rt.c | 33 --------------------------------- + 1 file changed, 33 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:01:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:01:08.000000000 -0500 +@@ -582,38 +582,6 @@ static int pull_rt_task(struct rq *this_ + continue; + + src_rq = cpu_rq(cpu); +- if (unlikely(src_rq->rt.rt_nr_running <= 1)) { +- /* +- * It is possible that overlapping cpusets +- * will miss clearing a non overloaded runqueue. +- * Clear it now. +- */ +- if (double_lock_balance(this_rq, src_rq)) { +- /* unlocked our runqueue lock */ +- struct task_struct *old_next = next; +- +- next = pick_next_task_rt(this_rq); +- if (next != old_next) +- ret = 1; +- } +- if (likely(src_rq->rt.rt_nr_running <= 1)) { +- /* +- * Small chance that this_rq->curr changed +- * but it's really harmless here. +- */ +- rt_clear_overload(this_rq); +- } else { +- /* +- * Heh, the src_rq is now overloaded, since +- * we already have the src_rq lock, go straight +- * to pulling tasks from it. +- */ +- goto try_pulling; +- } +- spin_unlock(&src_rq->lock); +- continue; +- } +- + /* + * We can potentially drop this_rq's lock in + * double_lock_balance, and another CPU could +@@ -637,7 +605,6 @@ static int pull_rt_task(struct rq *this_ + continue; + } + +- try_pulling: + p = pick_next_highest_task_rt(src_rq, this_cpu); + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0040-0027-sched-clean-up-pull_rt_task.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0040-0027-sched-clean-up-pull_rt_task.patch @@ -0,0 +1,97 @@ +From dec733755cbc9c260d74ae3163029a87f98932f7 Mon Sep 17 00:00:00 2001 +From: Ingo Molnar +Date: Tue, 11 Dec 2007 10:02:39 +0100 +Subject: [PATCH] sched: clean up pull_rt_task() + +clean up pull_rt_task(). + +Signed-off-by: Ingo Molnar + +--- + kernel/sched_rt.c | 22 ++++++++++------------ + 1 file changed, 10 insertions(+), 12 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:01:02.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:01:02.000000000 -0500 +@@ -572,12 +572,9 @@ static void push_rt_tasks(struct rq *rq) + + static int pull_rt_task(struct rq *this_rq) + { +- struct task_struct *next; +- struct task_struct *p; ++ int this_cpu = this_rq->cpu, ret = 0, cpu; ++ struct task_struct *p, *next; + struct rq *src_rq; +- int this_cpu = this_rq->cpu; +- int cpu; +- int ret = 0; + + /* + * If cpusets are used, and we have overlapping +@@ -604,23 +601,25 @@ static int pull_rt_task(struct rq *this_ + if (double_lock_balance(this_rq, src_rq)) { + /* unlocked our runqueue lock */ + struct task_struct *old_next = next; ++ + next = pick_next_task_rt(this_rq); + if (next != old_next) + ret = 1; + } +- if (likely(src_rq->rt.rt_nr_running <= 1)) ++ if (likely(src_rq->rt.rt_nr_running <= 1)) { + /* + * Small chance that this_rq->curr changed + * but it's really harmless here. + */ + rt_clear_overload(this_rq); +- else ++ } else { + /* + * Heh, the src_rq is now overloaded, since + * we already have the src_rq lock, go straight + * to pulling tasks from it. + */ + goto try_pulling; ++ } + spin_unlock(&src_rq->lock); + continue; + } +@@ -634,6 +633,7 @@ static int pull_rt_task(struct rq *this_ + */ + if (double_lock_balance(this_rq, src_rq)) { + struct task_struct *old_next = next; ++ + next = pick_next_task_rt(this_rq); + if (next != old_next) + ret = 1; +@@ -670,7 +670,7 @@ static int pull_rt_task(struct rq *this_ + */ + if (p->prio < src_rq->curr->prio || + (next && next->prio < src_rq->curr->prio)) +- goto bail; ++ goto out; + + ret = 1; + +@@ -682,9 +682,7 @@ static int pull_rt_task(struct rq *this_ + * case there's an even higher prio task + * in another runqueue. (low likelyhood + * but possible) +- */ +- +- /* ++ * + * Update next so that we won't pick a task + * on another cpu with a priority lower (or equal) + * than the one we just picked. +@@ -692,7 +690,7 @@ static int pull_rt_task(struct rq *this_ + next = p; + + } +- bail: ++ out: + spin_unlock(&src_rq->lock); + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0346-export-schedule-on-each-cpu.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0346-export-schedule-on-each-cpu.patch @@ -0,0 +1,18 @@ + + +--- + kernel/workqueue.c | 1 + + 1 file changed, 1 insertion(+) + +Index: linux-2.6.24.7-rt27/kernel/workqueue.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/workqueue.c 2009-02-08 00:03:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/workqueue.c 2009-02-08 00:03:35.000000000 -0500 +@@ -670,6 +670,7 @@ out: + + return err; + } ++EXPORT_SYMBOL(schedule_on_each_cpu); + + /** + * schedule_on_each_cpu_wq - call a function on each online CPU on a per-CPU wq --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0050-0039-sched-get-rid-of-new_cpu-in-try_to_wake_up.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0050-0039-sched-get-rid-of-new_cpu-in-try_to_wake_up.patch @@ -0,0 +1,55 @@ +From 48bbd36b0a1a82e2601ad726d9f1e1338e2af12b Mon Sep 17 00:00:00 2001 +From: Dmitry Adamushko +Date: Tue, 11 Dec 2007 10:02:47 +0100 +Subject: [PATCH] sched: get rid of 'new_cpu' in try_to_wake_up() + +Clean-up try_to_wake_up(). + +Get rid of the 'new_cpu' variable in try_to_wake_up() [ that's, one #ifdef section less ]. +Also remove a few redundant blank lines. + +Signed-off-by: Dmitry Adamushko +Signed-off-by: Ingo Molnar + +--- + kernel/sched.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:01:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:01:06.000000000 -0500 +@@ -1545,9 +1545,6 @@ static int try_to_wake_up(struct task_st + unsigned long flags; + long old_state; + struct rq *rq; +-#ifdef CONFIG_SMP +- int new_cpu; +-#endif + + rq = task_rq_lock(p, &flags); + old_state = p->state; +@@ -1565,9 +1562,9 @@ static int try_to_wake_up(struct task_st + if (unlikely(task_running(rq, p))) + goto out_activate; + +- new_cpu = p->sched_class->select_task_rq(p, sync); +- if (new_cpu != cpu) { +- set_task_cpu(p, new_cpu); ++ cpu = p->sched_class->select_task_rq(p, sync); ++ if (cpu != orig_cpu) { ++ set_task_cpu(p, cpu); + task_rq_unlock(rq, &flags); + /* might preempt at this point */ + rq = task_rq_lock(p, &flags); +@@ -1594,10 +1591,8 @@ static int try_to_wake_up(struct task_st + } + } + } +- + #endif + +- + out_activate: + #endif /* CONFIG_SMP */ + schedstat_inc(p, se.nr_wakeups); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0132-arm-cmpxchg-support-armv6.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0132-arm-cmpxchg-support-armv6.patch @@ -0,0 +1,66 @@ +[PATCH -rt] cmpxchg support on ARMv6 + +Current rt patch don't support the cmpxchg on ARMv6. This patch supports cmpxchg in ARMv6. +It's tested on OMAP2 (apollon board). + +Signed-off-by: Kyungmin Park + +p.s., Pleaes cc to me, I'm not subscriber on this mailing list. + +-- + +--- + include/asm-arm/atomic.h | 40 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +Index: linux-2.6.24.7-rt27/include/asm-arm/atomic.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/atomic.h 2009-02-08 00:01:44.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/atomic.h 2009-02-08 00:01:44.000000000 -0500 +@@ -114,6 +114,46 @@ static inline void atomic_clear_mask(uns + : "cc"); + } + ++/* ++ * Atomic compare and exchange. ++ */ ++#define __HAVE_ARCH_CMPXCHG 1 ++ ++extern unsigned long wrong_size_cmpxchg(volatile void *ptr); ++ ++static inline unsigned long __cmpxchg(volatile void *ptr, ++ unsigned long old, ++ unsigned long new, int size) ++{ ++ volatile unsigned long *p = ptr; ++ ++ if (size == 4) { ++ unsigned long oldval, res; ++ ++ do { ++ __asm__ __volatile__("@ atomic_cmpxchg\n" ++ "ldrex %1, [%2]\n" ++ "mov %0, #0\n" ++ "teq %1, %3\n" ++ "strexeq %0, %4, [%2]\n" ++ : "=&r" (res), "=&r" (oldval) ++ : "r" (p), "Ir" (old), "r" (new) ++ : "cc"); ++ } while (res); ++ ++ return oldval; ++ } else ++ return wrong_size_cmpxchg(ptr); ++} ++ ++#define cmpxchg(ptr,o,n) \ ++({ \ ++ __typeof__(*(ptr)) _o_ = (o); \ ++ __typeof__(*(ptr)) _n_ = (n); \ ++ (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ ++ (unsigned long)_n_, sizeof(*(ptr))); \ ++}) ++ + #else /* ARM_ARCH_6 */ + + #include --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0282-qrcu.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0282-qrcu.patch @@ -0,0 +1,193 @@ +From: "Paul E. McKenney" +Subject: [PATCH] QRCU with lockless fastpath + +Hello! + +This is an updated version of Oleg Nesterov's QRCU that avoids the +earlier lock acquisition on the synchronize_qrcu() fastpath. This passes +rcutorture on x86 and the weakly ordered POWER. A promela model of the +code passes as noted before for 2 readers and 3 updaters and for 3 readers +and 2 updaters. 3 readers and 3 updaters runs every machine that I have +access to out of memory -- nothing like a little combinatorial explosion! +However, after some thought, the proof ended up being simple enough: + +1. If synchronize_qrcu() exits too soon, then by definition + there has been a reader present during synchronize_srcu()'s + full execution. + +2. The counter corresponding to this reader will be at least + 1 at all times. + +3. The synchronize_qrcu() code forces at least one of the counters + to be at least one at all times -- if there is a reader, the + sum will be at least two. (Unfortunately, we cannot fetch + the pair of counters atomically.) + +4. Therefore, the only way that synchronize_qrcu()s fastpath can + see a sum of 1 is if it races with another synchronize_qrcu() -- + the first synchronize_qrcu() must read one of the counters before + the second synchronize_qrcu() increments it, and must read the + other counter after the second synchronize_qrcu() decrements it. + There can be at most one reader present through this entire + operation -- otherwise, the first synchronize_qrcu() will see + a sum of 2 or greater. + +5. But the second synchronize_qrcu() will not release the mutex + until after the reader is done. During this time, the first + synchronize_qrcu() will always see a sum of at least 2, and + therefore cannot take the remainder of the fastpath until the + reader is done. + +6. Because the second synchronize_qrcu() holds the mutex, no other + synchronize_qrcu() can manipulate the counters until the reader + is done. A repeat of the race called out in #4 above therefore + cannot happen until after the reader is done, in which case it + is safe for the first synchronize_qrcu() to proceed. + +Therefore, two summations of the counter separated by a memory barrier +suffices and the implementation shown below also suffices. + +(And, yes, the fastpath -could- check for a sum of zero and exit +immediately, but this would help only in case of a three-way race +between two synchronize_qrcu()s and a qrcu_read_unlock(), would add +another compare, so is not worth it.) + +Signed-off-by: Paul E. McKenney +--- + + include/linux/srcu.h | 22 +++++++++++++ + kernel/srcu.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 108 insertions(+) + +Index: linux-2.6.24.7-rt27/include/linux/srcu.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/srcu.h 2009-02-07 23:59:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/srcu.h 2009-02-08 00:03:01.000000000 -0500 +@@ -27,6 +27,8 @@ + #ifndef _LINUX_SRCU_H + #define _LINUX_SRCU_H + ++#include ++ + struct srcu_struct_array { + int c[2]; + }; +@@ -50,4 +52,24 @@ void srcu_read_unlock(struct srcu_struct + void synchronize_srcu(struct srcu_struct *sp); + long srcu_batches_completed(struct srcu_struct *sp); + ++/* ++ * fully compatible with srcu, but optimized for writers. ++ */ ++ ++struct qrcu_struct { ++ int completed; ++ atomic_t ctr[2]; ++ wait_queue_head_t wq; ++ struct mutex mutex; ++}; ++ ++int init_qrcu_struct(struct qrcu_struct *qp); ++int qrcu_read_lock(struct qrcu_struct *qp); ++void qrcu_read_unlock(struct qrcu_struct *qp, int idx); ++void synchronize_qrcu(struct qrcu_struct *qp); ++ ++static inline void cleanup_qrcu_struct(struct qrcu_struct *qp) ++{ ++} ++ + #endif +Index: linux-2.6.24.7-rt27/kernel/srcu.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/srcu.c 2009-02-07 23:59:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/srcu.c 2009-02-08 00:03:01.000000000 -0500 +@@ -256,3 +256,89 @@ EXPORT_SYMBOL_GPL(srcu_read_unlock); + EXPORT_SYMBOL_GPL(synchronize_srcu); + EXPORT_SYMBOL_GPL(srcu_batches_completed); + EXPORT_SYMBOL_GPL(srcu_readers_active); ++ ++int init_qrcu_struct(struct qrcu_struct *qp) ++{ ++ qp->completed = 0; ++ atomic_set(qp->ctr + 0, 1); ++ atomic_set(qp->ctr + 1, 0); ++ init_waitqueue_head(&qp->wq); ++ mutex_init(&qp->mutex); ++ ++ return 0; ++} ++ ++int qrcu_read_lock(struct qrcu_struct *qp) ++{ ++ for (;;) { ++ int idx = qp->completed & 0x1; ++ if (likely(atomic_inc_not_zero(qp->ctr + idx))) ++ return idx; ++ } ++} ++ ++void qrcu_read_unlock(struct qrcu_struct *qp, int idx) ++{ ++ if (atomic_dec_and_test(qp->ctr + idx)) ++ wake_up(&qp->wq); ++} ++ ++void synchronize_qrcu(struct qrcu_struct *qp) ++{ ++ int idx; ++ ++ smp_mb(); /* Force preceding change to happen before fastpath check. */ ++ ++ /* ++ * Fastpath: If the two counters sum to "1" at a given point in ++ * time, there are no readers. However, it takes two separate ++ * loads to sample both counters, which won't occur simultaneously. ++ * So we might race with a counter switch, so that we might see ++ * ctr[0]==0, then the counter might switch, then we might see ++ * ctr[1]==1 (unbeknownst to us because there is a reader still ++ * there). So we do a read memory barrier and recheck. If the ++ * same race happens again, there must have been a second counter ++ * switch. This second counter switch could not have happened ++ * until all preceding readers finished, so if the condition ++ * is true both times, we may safely proceed. ++ * ++ * This relies critically on the atomic increment and atomic ++ * decrement being seen as executing in order. ++ */ ++ ++ if (atomic_read(&qp->ctr[0]) + atomic_read(&qp->ctr[1]) <= 1) { ++ smp_rmb(); /* Keep two checks independent. */ ++ if (atomic_read(&qp->ctr[0]) + atomic_read(&qp->ctr[1]) <= 1) ++ goto out; ++ } ++ ++ mutex_lock(&qp->mutex); ++ ++ idx = qp->completed & 0x1; ++ if (atomic_read(qp->ctr + idx) == 1) ++ goto out_unlock; ++ ++ atomic_inc(qp->ctr + (idx ^ 0x1)); ++ ++ /* ++ * Prevent subsequent decrement from being seen before previous ++ * increment -- such an inversion could cause the fastpath ++ * above to falsely conclude that there were no readers. Also, ++ * reduce the likelihood that qrcu_read_lock() will loop. ++ */ ++ ++ smp_mb__after_atomic_inc(); ++ qp->completed++; ++ ++ atomic_dec(qp->ctr + idx); ++ __wait_event(qp->wq, !atomic_read(qp->ctr + idx)); ++out_unlock: ++ mutex_unlock(&qp->mutex); ++out: ++ smp_mb(); /* force subsequent free after qrcu_read_unlock(). */ ++} ++ ++EXPORT_SYMBOL_GPL(init_qrcu_struct); ++EXPORT_SYMBOL_GPL(qrcu_read_lock); ++EXPORT_SYMBOL_GPL(qrcu_read_unlock); ++EXPORT_SYMBOL_GPL(synchronize_qrcu); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0014-m68knommu-upstream-patches.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0014-m68knommu-upstream-patches.patch @@ -0,0 +1,9160 @@ +From: Sebastian Siewior +Date: Sun, 27 Apr 2008 14:28:21 +0200 +Subject: m68knommu: upstream pending patches + +That's a conglomerate of Greg Ungerers and Sebastian Siewiors +m68knommu patches which are not in .24 but on the way upstream +(partly included in .25/.26) + +Compressed-into-one-patch-by: tglx +--- + arch/m68knommu/Kconfig | 24 + arch/m68knommu/Makefile | 31 + arch/m68knommu/kernel/asm-offsets.c | 1 + arch/m68knommu/kernel/irq.c | 11 + arch/m68knommu/kernel/setup.c | 2 + arch/m68knommu/kernel/time.c | 109 - + arch/m68knommu/kernel/traps.c | 112 + + arch/m68knommu/kernel/vmlinux.lds.S | 90 - + arch/m68knommu/platform/5206/config.c | 76 - + arch/m68knommu/platform/5206e/config.c | 80 - + arch/m68knommu/platform/520x/config.c | 101 + + arch/m68knommu/platform/523x/config.c | 138 +- + arch/m68knommu/platform/5249/config.c | 77 - + arch/m68knommu/platform/5272/config.c | 89 - + arch/m68knommu/platform/527x/config.c | 87 + + arch/m68knommu/platform/528x/config.c | 355 +++++ + arch/m68knommu/platform/5307/Makefile | 14 + arch/m68knommu/platform/5307/config.c | 88 - + arch/m68knommu/platform/5307/entry.S | 235 --- + arch/m68knommu/platform/5307/head.S | 222 --- + arch/m68knommu/platform/5307/pit.c | 97 - + arch/m68knommu/platform/5307/timers.c | 155 -- + arch/m68knommu/platform/5307/vectors.c | 105 - + arch/m68knommu/platform/532x/config.c | 179 +- + arch/m68knommu/platform/532x/spi-mcf532x.c | 176 ++ + arch/m68knommu/platform/532x/usb-mcf532x.c | 171 ++ + arch/m68knommu/platform/5407/config.c | 83 - + arch/m68knommu/platform/68328/ints.c | 2 + arch/m68knommu/platform/68328/timers.c | 56 + arch/m68knommu/platform/68360/config.c | 5 + arch/m68knommu/platform/coldfire/Makefile | 32 + arch/m68knommu/platform/coldfire/dma.c | 39 + arch/m68knommu/platform/coldfire/dma_timer.c | 84 + + arch/m68knommu/platform/coldfire/entry.S | 241 +++ + arch/m68knommu/platform/coldfire/head.S | 222 +++ + arch/m68knommu/platform/coldfire/irq_chip.c | 110 + + arch/m68knommu/platform/coldfire/pit.c | 180 ++ + arch/m68knommu/platform/coldfire/timers.c | 182 ++ + arch/m68knommu/platform/coldfire/vectors.c | 105 + + drivers/net/fec.c | 1812 +++++++++++++-------------- + drivers/serial/68328serial.c | 2 + drivers/serial/mcf.c | 22 + drivers/serial/mcfserial.c | 121 - + fs/nfs/file.c | 4 + include/asm-generic/vmlinux.lds.h | 40 + include/asm-m68knommu/bitops.h | 30 + include/asm-m68knommu/byteorder.h | 16 + include/asm-m68knommu/cacheflush.h | 2 + include/asm-m68knommu/commproc.h | 19 + include/asm-m68knommu/dma.h | 3 + include/asm-m68knommu/m523xsim.h | 147 ++ + include/asm-m68knommu/m528xsim.h | 63 + include/asm-m68knommu/m532xsim.h | 86 - + include/asm-m68knommu/mcfcache.h | 2 + include/asm-m68knommu/mcfuart.h | 3 + mm/nommu.c | 10 + mm/page_alloc.c | 8 + 57 files changed, 4172 insertions(+), 2384 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/m68knommu/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/Kconfig 2009-02-08 00:00:32.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/Kconfig 2009-02-08 00:00:48.000000000 -0500 +@@ -53,10 +53,22 @@ config GENERIC_CALIBRATE_DELAY + bool + default y + ++config GENERIC_TIME ++ bool ++ default y ++ ++config GENERIC_CMOS_UPDATE ++ bool ++ default y ++ + config TIME_LOW_RES + bool + default y + ++config GENERIC_CLOCKEVENTS ++ bool ++ default n ++ + config NO_IOPORT + def_bool y + +@@ -100,11 +112,14 @@ config M5206e + + config M520x + bool "MCF520x" ++ select GENERIC_CLOCKEVENTS + help + Freescale Coldfire 5207/5208 processor support. + + config M523x + bool "MCF523x" ++ select GENERIC_CLOCKEVENTS ++ select GENERIC_HARDIRQS_NO__DO_IRQ + help + Freescale Coldfire 5230/1/2/4/5 processor support + +@@ -130,6 +145,7 @@ config M5275 + + config M528x + bool "MCF528x" ++ select GENERIC_CLOCKEVENTS + help + Motorola ColdFire 5280/5282 processor support. + +@@ -153,6 +169,7 @@ endchoice + config M527x + bool + depends on (M5271 || M5275) ++ select GENERIC_CLOCKEVENTS + default y + + config COLDFIRE +@@ -658,6 +675,13 @@ config ROMKERNEL + + endchoice + ++config GENERIC_HARDIRQS_NO__DO_IRQ ++ bool "Force generic IRQ implementation" ++ ++source "kernel/time/Kconfig" ++if COLDFIRE ++source "kernel/Kconfig.preempt" ++endif + source "mm/Kconfig" + + endmenu +Index: linux-2.6.24.7-rt27/arch/m68knommu/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/Makefile 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/Makefile 2009-02-08 00:00:48.000000000 -0500 +@@ -61,17 +61,17 @@ MODEL := $(model-y) + # for the selected cpu. ONLY need to define this for the non-base member + # of the family. + # +-cpuclass-$(CONFIG_M5206) := 5307 +-cpuclass-$(CONFIG_M5206e) := 5307 +-cpuclass-$(CONFIG_M520x) := 5307 +-cpuclass-$(CONFIG_M523x) := 5307 +-cpuclass-$(CONFIG_M5249) := 5307 +-cpuclass-$(CONFIG_M527x) := 5307 +-cpuclass-$(CONFIG_M5272) := 5307 +-cpuclass-$(CONFIG_M528x) := 5307 +-cpuclass-$(CONFIG_M5307) := 5307 +-cpuclass-$(CONFIG_M532x) := 5307 +-cpuclass-$(CONFIG_M5407) := 5307 ++cpuclass-$(CONFIG_M5206) := coldfire ++cpuclass-$(CONFIG_M5206e) := coldfire ++cpuclass-$(CONFIG_M520x) := coldfire ++cpuclass-$(CONFIG_M523x) := coldfire ++cpuclass-$(CONFIG_M5249) := coldfire ++cpuclass-$(CONFIG_M527x) := coldfire ++cpuclass-$(CONFIG_M5272) := coldfire ++cpuclass-$(CONFIG_M528x) := coldfire ++cpuclass-$(CONFIG_M5307) := coldfire ++cpuclass-$(CONFIG_M532x) := coldfire ++cpuclass-$(CONFIG_M5407) := coldfire + cpuclass-$(CONFIG_M68328) := 68328 + cpuclass-$(CONFIG_M68EZ328) := 68328 + cpuclass-$(CONFIG_M68VZ328) := 68328 +@@ -90,13 +90,14 @@ export PLATFORM BOARD MODEL CPUCLASS + cflags-$(CONFIG_M5206) := -m5200 + cflags-$(CONFIG_M5206e) := -m5200 + cflags-$(CONFIG_M520x) := -m5307 +-cflags-$(CONFIG_M523x) := -m5307 ++cflags-$(CONFIG_M523x) := $(call cc-option,-mcpu=523x,-m5307) + cflags-$(CONFIG_M5249) := -m5200 +-cflags-$(CONFIG_M527x) := -m5307 ++cflags-$(CONFIG_M5271) := $(call cc-option,-mcpu=5271,-m5307) + cflags-$(CONFIG_M5272) := -m5307 +-cflags-$(CONFIG_M528x) := -m5307 ++cflags-$(CONFIG_M5275) := $(call cc-option,-mcpu=5275,-m5307) ++cflags-$(CONFIG_M528x) := $(call cc-option,-m528x,-m5307) + cflags-$(CONFIG_M5307) := -m5307 +-cflags-$(CONFIG_M532x) := -m5307 ++cflags-$(CONFIG_M532x) := $(call cc-option,-mcpu=532x,-m5307) + cflags-$(CONFIG_M5407) := -m5200 + cflags-$(CONFIG_M68328) := -m68000 + cflags-$(CONFIG_M68EZ328) := -m68000 +Index: linux-2.6.24.7-rt27/arch/m68knommu/kernel/asm-offsets.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/kernel/asm-offsets.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/kernel/asm-offsets.c 2009-02-08 00:00:48.000000000 -0500 +@@ -91,6 +91,7 @@ int main(void) + DEFINE(TI_TASK, offsetof(struct thread_info, task)); + DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); ++ DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count)); + DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); + + return 0; +Index: linux-2.6.24.7-rt27/arch/m68knommu/kernel/irq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/kernel/irq.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/kernel/irq.c 2009-02-08 00:00:48.000000000 -0500 +@@ -23,7 +23,7 @@ asmlinkage void do_IRQ(int irq, struct p + struct pt_regs *oldregs = set_irq_regs(regs); + + irq_enter(); +- __do_IRQ(irq); ++ generic_handle_irq(irq); + irq_exit(); + + set_irq_regs(oldregs); +@@ -34,12 +34,16 @@ void ack_bad_irq(unsigned int irq) + printk(KERN_ERR "IRQ: unexpected irq=%d\n", irq); + } + ++#ifndef CONFIG_M523x + static struct irq_chip m_irq_chip = { + .name = "M68K-INTC", + .enable = enable_vector, + .disable = disable_vector, + .ack = ack_vector, + }; ++#else ++void coldfire_init_irq_chip(void); ++#endif + + void __init init_IRQ(void) + { +@@ -47,12 +51,16 @@ void __init init_IRQ(void) + + init_vectors(); + ++#ifndef CONFIG_M523x + for (irq = 0; (irq < NR_IRQS); irq++) { + irq_desc[irq].status = IRQ_DISABLED; + irq_desc[irq].action = NULL; + irq_desc[irq].depth = 1; + irq_desc[irq].chip = &m_irq_chip; + } ++#else ++ coldfire_init_irq_chip(); ++#endif + } + + int show_interrupts(struct seq_file *p, void *v) +@@ -79,4 +87,3 @@ int show_interrupts(struct seq_file *p, + + return 0; + } +- +Index: linux-2.6.24.7-rt27/arch/m68knommu/kernel/setup.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/kernel/setup.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/kernel/setup.c 2009-02-08 00:00:48.000000000 -0500 +@@ -165,7 +165,7 @@ void __init setup_arch(char **cmdline_p) + printk(KERN_INFO "DragonEngine II board support by Georges Menie\n"); + #endif + #ifdef CONFIG_M5235EVB +- printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)"); ++ printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)\n"); + #endif + + #ifdef DEBUG +Index: linux-2.6.24.7-rt27/arch/m68knommu/kernel/time.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/kernel/time.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/kernel/time.c 2009-02-08 00:00:48.000000000 -0500 +@@ -22,7 +22,6 @@ + #include + + #include +-#include + #include + + #define TICK_SIZE (tick_nsec / 1000) +@@ -34,14 +33,13 @@ static inline int set_rtc_mmss(unsigned + return -1; + } + ++#ifndef CONFIG_GENERIC_CLOCKEVENTS + /* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ + irqreturn_t arch_timer_interrupt(int irq, void *dummy) + { +- /* last time the cmos clock got updated */ +- static long last_rtc_update=0; + + write_seqlock(&xtime_lock); + +@@ -52,49 +50,12 @@ irqreturn_t arch_timer_interrupt(int irq + if (current->pid) + profile_tick(CPU_PROFILING); + +- /* +- * If we have an externally synchronized Linux clock, then update +- * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be +- * called as close as possible to 500 ms before the new second starts. +- */ +- if (ntp_synced() && +- xtime.tv_sec > last_rtc_update + 660 && +- (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && +- (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { +- if (set_rtc_mmss(xtime.tv_sec) == 0) +- last_rtc_update = xtime.tv_sec; +- else +- last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ +- } +-#ifdef CONFIG_HEARTBEAT +- /* use power LED as a heartbeat instead -- much more useful +- for debugging -- based on the version for PReP by Cort */ +- /* acts like an actual heart beat -- ie thump-thump-pause... */ +- if (mach_heartbeat) { +- static unsigned cnt = 0, period = 0, dist = 0; +- +- if (cnt == 0 || cnt == dist) +- mach_heartbeat( 1 ); +- else if (cnt == 7 || cnt == dist+7) +- mach_heartbeat( 0 ); +- +- if (++cnt > period) { +- cnt = 0; +- /* The hyperbolic function below modifies the heartbeat period +- * length in dependency of the current (5min) load. It goes +- * through the points f(0)=126, f(1)=86, f(5)=51, +- * f(inf)->30. */ +- period = ((672<= 1000000) { +- usec -= 1000000; +- sec++; +- } +- +- tv->tv_sec = sec; +- tv->tv_usec = usec; ++ return read_rtc_mmss(); + } + +-EXPORT_SYMBOL(do_gettimeofday); +- +-int do_settimeofday(struct timespec *tv) ++int update_persistent_clock(struct timespec now) + { +- time_t wtm_sec, sec = tv->tv_sec; +- long wtm_nsec, nsec = tv->tv_nsec; +- +- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) +- return -EINVAL; +- +- write_seqlock_irq(&xtime_lock); +- /* +- * This is revolting. We need to set the xtime.tv_usec +- * correctly. However, the value in this location is +- * is value at the last tick. +- * Discover what correction gettimeofday +- * would have done, and then undo it! +- */ +- nsec -= (hw_timer_offset() * 1000); +- +- wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); +- wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); +- +- set_normalized_timespec(&xtime, sec, nsec); +- set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); ++ return set_rtc_mmss(now.tv_sec); ++} + +- ntp_clear(); +- write_sequnlock_irq(&xtime_lock); +- clock_was_set(); +- return 0; ++void time_init(void) ++{ ++ hw_timer_init(); + } +-EXPORT_SYMBOL(do_settimeofday); +Index: linux-2.6.24.7-rt27/arch/m68knommu/kernel/traps.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/kernel/traps.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/kernel/traps.c 2009-02-08 00:00:48.000000000 -0500 +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -102,56 +103,79 @@ asmlinkage void buserr_c(struct frame *f + force_sig(SIGSEGV, current); + } + ++static void print_this_address(unsigned long addr, int i) ++{ ++#ifdef CONFIG_KALLSYMS ++ printk(KERN_EMERG " [%08lx] ", addr); ++ print_symbol(KERN_CONT "%s\n", addr); ++#else ++ if (i % 5) ++ printk(KERN_CONT " [%08lx] ", addr); ++ else ++ printk(KERN_CONT "\n" KERN_EMERG " [%08lx] ", addr); ++ i++; ++#endif ++} + + int kstack_depth_to_print = 48; + +-void show_stack(struct task_struct *task, unsigned long *stack) ++static void __show_stack(struct task_struct *task, unsigned long *stack) + { + unsigned long *endstack, addr; +- extern char _start, _etext; ++#ifdef CONFIG_FRAME_POINTER ++ unsigned long *last_stack; ++#endif + int i; + +- if (!stack) { +- if (task) +- stack = (unsigned long *)task->thread.ksp; +- else +- stack = (unsigned long *)&stack; +- } ++ if (!stack) ++ stack = (unsigned long *)task->thread.ksp; + + addr = (unsigned long) stack; + endstack = (unsigned long *) PAGE_ALIGN(addr); + + printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack); + for (i = 0; i < kstack_depth_to_print; i++) { +- if (stack + 1 > endstack) ++ if (stack + 1 + i > endstack) + break; + if (i % 8 == 0) + printk("\n" KERN_EMERG " "); +- printk(" %08lx", *stack++); ++ printk(" %08lx", *(stack + i)); + } + printk("\n"); +- +- printk(KERN_EMERG "Call Trace:"); + i = 0; +- while (stack + 1 <= endstack) { ++ ++#ifdef CONFIG_FRAME_POINTER ++ printk(KERN_EMERG "Call Trace:\n"); ++ ++ last_stack = stack - 1; ++ while (stack <= endstack && stack > last_stack) { ++ ++ addr = *(stack + 1); ++ print_this_address(addr, i); ++ i++; ++ ++ last_stack = stack; ++ stack = (unsigned long *)*stack; ++ } ++ printk("\n"); ++#else ++ printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n"); ++ while (stack <= endstack) { + addr = *stack++; + /* +- * If the address is either in the text segment of the +- * kernel, or in the region which contains vmalloc'ed +- * memory, it *may* be the address of a calling +- * routine; if so, print it so that someone tracing +- * down the cause of the crash will be able to figure +- * out the call path that was taken. ++ * If the address is either in the text segment of the kernel, ++ * or in a region which is occupied by a module then it *may* ++ * be the address of a calling routine; if so, print it so that ++ * someone tracing down the cause of the crash will be able to ++ * figure out the call path that was taken. + */ +- if (((addr >= (unsigned long) &_start) && +- (addr <= (unsigned long) &_etext))) { +- if (i % 4 == 0) +- printk("\n" KERN_EMERG " "); +- printk(" [<%08lx>]", addr); ++ if (__kernel_text_address(addr)) { ++ print_this_address(addr, i); + i++; + } + } +- printk("\n"); ++ printk(KERN_CONT "\n"); ++#endif + } + + void bad_super_trap(struct frame *fp) +@@ -298,19 +322,47 @@ asmlinkage void set_esp0(unsigned long s + current->thread.esp0 = ssp; + } + +- + /* + * The architecture-independent backtrace generator + */ + void dump_stack(void) + { +- unsigned long stack; +- +- show_stack(current, &stack); ++ /* ++ * We need frame pointers for this little trick, which works as follows: ++ * ++ * +------------+ 0x00 ++ * | Next SP | -> 0x0c ++ * +------------+ 0x04 ++ * | Caller | ++ * +------------+ 0x08 ++ * | Local vars | -> our stack var ++ * +------------+ 0x0c ++ * | Next SP | -> 0x18, that is what we pass to show_stack() ++ * +------------+ 0x10 ++ * | Caller | ++ * +------------+ 0x14 ++ * | Local vars | ++ * +------------+ 0x18 ++ * | ... | ++ * +------------+ ++ */ ++ ++ unsigned long *stack; ++ ++ stack = (unsigned long *)&stack; ++ stack++; ++ __show_stack(current, stack); + } +- + EXPORT_SYMBOL(dump_stack); + ++void show_stack(struct task_struct *task, unsigned long *stack) ++{ ++ if (!stack && !task) ++ dump_stack(); ++ else ++ __show_stack(task, stack); ++} ++ + #ifdef CONFIG_M68KFPU_EMU + asmlinkage void fpemu_signal(int signal, int code, void *addr) + { +Index: linux-2.6.24.7-rt27/arch/m68knommu/kernel/vmlinux.lds.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/kernel/vmlinux.lds.S 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/kernel/vmlinux.lds.S 2009-02-08 00:00:48.000000000 -0500 +@@ -7,6 +7,8 @@ + * run kernels. + */ + ++#define OUTPUT_DATA_SECTION > DATA ++ + #include + + #if defined(CONFIG_RAMKERNEL) +@@ -34,7 +36,6 @@ + #define DATA_ADDR + #endif + +- + OUTPUT_ARCH(m68k) + ENTRY(_start) + +@@ -64,81 +65,32 @@ SECTIONS { + _stext = . ; + TEXT_TEXT + SCHED_TEXT ++ LOCK_TEXT + *(.text.lock) + +- . = ALIGN(16); /* Exception table */ +- __start___ex_table = .; +- *(__ex_table) +- __stop___ex_table = .; +- +- *(.rodata) *(.rodata.*) +- *(__vermagic) /* Kernel version magic */ +- *(.rodata1) +- *(.rodata.str1.1) +- +- /* Kernel symbol table: Normal symbols */ +- . = ALIGN(4); +- __start___ksymtab = .; +- *(__ksymtab) +- __stop___ksymtab = .; +- +- /* Kernel symbol table: GPL-only symbols */ +- __start___ksymtab_gpl = .; +- *(__ksymtab_gpl) +- __stop___ksymtab_gpl = .; +- +- /* Kernel symbol table: Normal unused symbols */ +- __start___ksymtab_unused = .; +- *(__ksymtab_unused) +- __stop___ksymtab_unused = .; +- +- /* Kernel symbol table: GPL-only unused symbols */ +- __start___ksymtab_unused_gpl = .; +- *(__ksymtab_unused_gpl) +- __stop___ksymtab_unused_gpl = .; +- +- /* Kernel symbol table: GPL-future symbols */ +- __start___ksymtab_gpl_future = .; +- *(__ksymtab_gpl_future) +- __stop___ksymtab_gpl_future = .; +- +- /* Kernel symbol table: Normal symbols */ +- __start___kcrctab = .; +- *(__kcrctab) +- __stop___kcrctab = .; +- +- /* Kernel symbol table: GPL-only symbols */ +- __start___kcrctab_gpl = .; +- *(__kcrctab_gpl) +- __stop___kcrctab_gpl = .; +- +- /* Kernel symbol table: GPL-future symbols */ +- __start___kcrctab_gpl_future = .; +- *(__kcrctab_gpl_future) +- __stop___kcrctab_gpl_future = .; +- +- /* Kernel symbol table: strings */ +- *(__ksymtab_strings) +- +- /* Built-in module parameters */ +- . = ALIGN(4) ; +- __start___param = .; +- *(__param) +- __stop___param = .; +- + . = ALIGN(4) ; +- _etext = . ; + } > TEXT + ++ _etext = . ; ++ ++ RODATA ++ + .data DATA_ADDR : { + . = ALIGN(4); + _sdata = . ; + DATA_DATA ++ . = ALIGN(16); /* Exception table */ ++ __start___ex_table = .; ++ *(__ex_table) ++ __stop___ex_table = .; + . = ALIGN(8192) ; + *(.data.init_task) + _edata = . ; + } > DATA + ++ BUG_TABLE ++ PERCPU(4096) ++ + .init : { + . = ALIGN(4096); + __init_begin = .; +@@ -169,12 +121,6 @@ SECTIONS { + __init_end = .; + } > INIT + +- /DISCARD/ : { +- *(.exit.text) +- *(.exit.data) +- *(.exitcall.exit) +- } +- + .bss : { + . = ALIGN(4); + _sbss = . ; +@@ -184,5 +130,11 @@ SECTIONS { + _ebss = . ; + } > BSS + +-} ++ _end = . ; + ++ /DISCARD/ : { ++ *(.exit.text) ++ *(.exit.data) ++ *(.exitcall.exit) ++ } ++} +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/5206/config.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/5206/config.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/5206/config.c 2009-02-08 00:00:48.000000000 -0500 +@@ -13,12 +13,11 @@ + #include + #include + #include +-#include ++#include + #include + #include +-#include + #include +-#include ++#include + + /***************************************************************************/ + +@@ -26,15 +25,51 @@ void coldfire_reset(void); + + /***************************************************************************/ + +-/* +- * DMA channel base address table. +- */ +-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { +- MCF_MBAR + MCFDMA_BASE0, +- MCF_MBAR + MCFDMA_BASE1, ++static struct mcf_platform_uart m5206_uart_platform[] = { ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE1, ++ .irq = 73, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE2, ++ .irq = 74, ++ }, ++ { }, + }; + +-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; ++static struct platform_device m5206_uart = { ++ .name = "mcfuart", ++ .id = 0, ++ .dev.platform_data = m5206_uart_platform, ++}; ++ ++static struct platform_device *m5206_devices[] __initdata = { ++ &m5206_uart, ++}; ++ ++/***************************************************************************/ ++ ++static void __init m5206_uart_init_line(int line, int irq) ++{ ++ if (line == 0) { ++ writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); ++ writeb(irq, MCFUART_BASE1 + MCFUART_UIVR); ++ mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1); ++ } else if (line == 1) { ++ writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); ++ writeb(irq, MCFUART_BASE2 + MCFUART_UIVR); ++ mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2); ++ } ++} ++ ++static void __init m5206_uarts_init(void) ++{ ++ const int nrlines = ARRAY_SIZE(m5206_uart_platform); ++ int line; ++ ++ for (line = 0; (line < nrlines); line++) ++ m5206_uart_init_line(line, m5206_uart_platform[line].irq); ++} + + /***************************************************************************/ + +@@ -74,24 +109,21 @@ void mcf_settimericr(unsigned int timer, + + /***************************************************************************/ + +-int mcf_timerirqpending(int timer) ++void __init config_BSP(char *commandp, int size) + { +- unsigned int imr = 0; +- +- switch (timer) { +- case 1: imr = MCFSIM_IMR_TIMER1; break; +- case 2: imr = MCFSIM_IMR_TIMER2; break; +- default: break; +- } +- return (mcf_getipr() & imr); ++ mcf_setimr(MCFSIM_IMR_MASKALL); ++ mach_reset = coldfire_reset; + } + + /***************************************************************************/ + +-void config_BSP(char *commandp, int size) ++static int __init init_BSP(void) + { +- mcf_setimr(MCFSIM_IMR_MASKALL); +- mach_reset = coldfire_reset; ++ m5206_uarts_init(); ++ platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices)); ++ return 0; + } + ++arch_initcall(init_BSP); ++ + /***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/5206e/config.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/5206e/config.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/5206e/config.c 2009-02-08 00:00:48.000000000 -0500 +@@ -10,8 +10,9 @@ + + #include + #include ++#include + #include +-#include ++#include + #include + #include + #include +@@ -23,15 +24,51 @@ void coldfire_reset(void); + + /***************************************************************************/ + +-/* +- * DMA channel base address table. +- */ +-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { +- MCF_MBAR + MCFDMA_BASE0, +- MCF_MBAR + MCFDMA_BASE1, ++static struct mcf_platform_uart m5206_uart_platform[] = { ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE1, ++ .irq = 73, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE2, ++ .irq = 74, ++ }, ++ { }, + }; + +-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; ++static struct platform_device m5206_uart = { ++ .name = "mcfuart", ++ .id = 0, ++ .dev.platform_data = m5206_uart_platform, ++}; ++ ++static struct platform_device *m5206_devices[] __initdata = { ++ &m5206_uart, ++}; ++ ++/***************************************************************************/ ++ ++static void __init m5206_uart_init_line(int line, int irq) ++{ ++ if (line == 0) { ++ writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); ++ writeb(irq, MCFUART_BASE1 + MCFUART_UIVR); ++ mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1); ++ } else if (line == 1) { ++ writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); ++ writeb(irq, MCFUART_BASE2 + MCFUART_UIVR); ++ mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2); ++ } ++} ++ ++static void __init m5206_uarts_init(void) ++{ ++ const int nrlines = ARRAY_SIZE(m5206_uart_platform); ++ int line; ++ ++ for (line = 0; (line < nrlines); line++) ++ m5206_uart_init_line(line, m5206_uart_platform[line].irq); ++} + + /***************************************************************************/ + +@@ -71,21 +108,7 @@ void mcf_settimericr(unsigned int timer, + + /***************************************************************************/ + +-int mcf_timerirqpending(int timer) +-{ +- unsigned int imr = 0; +- +- switch (timer) { +- case 1: imr = MCFSIM_IMR_TIMER1; break; +- case 2: imr = MCFSIM_IMR_TIMER2; break; +- default: break; +- } +- return (mcf_getipr() & imr); +-} +- +-/***************************************************************************/ +- +-void config_BSP(char *commandp, int size) ++void __init config_BSP(char *commandp, int size) + { + mcf_setimr(MCFSIM_IMR_MASKALL); + +@@ -99,3 +122,14 @@ void config_BSP(char *commandp, int size + } + + /***************************************************************************/ ++ ++static int __init init_BSP(void) ++{ ++ m5206_uarts_init(); ++ platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices)); ++ return 0; ++} ++ ++arch_initcall(init_BSP); ++ ++/***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/520x/config.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/520x/config.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/520x/config.c 2009-02-08 00:00:48.000000000 -0500 +@@ -5,7 +5,7 @@ + * + * Copyright (C) 2005, Freescale (www.freescale.com) + * Copyright (C) 2005, Intec Automation (mike@steroidmicros.com) +- * Copyright (C) 1999-2003, Greg Ungerer (gerg@snapgear.com) ++ * Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com) + */ + +@@ -13,21 +13,93 @@ + + #include + #include ++#include + #include ++#include + #include +-#include ++#include ++#include ++#include + + /***************************************************************************/ + +-/* +- * DMA channel base address table. +- */ +-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS]; +-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; ++void coldfire_reset(void); + + /***************************************************************************/ + +-void coldfire_reset(void); ++static struct mcf_platform_uart m520x_uart_platform[] = { ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE1, ++ .irq = MCFINT_VECBASE + MCFINT_UART0, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE2, ++ .irq = MCFINT_VECBASE + MCFINT_UART1, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE3, ++ .irq = MCFINT_VECBASE + MCFINT_UART2, ++ }, ++ { }, ++}; ++ ++static struct platform_device m520x_uart = { ++ .name = "mcfuart", ++ .id = 0, ++ .dev.platform_data = m520x_uart_platform, ++}; ++ ++static struct platform_device *m520x_devices[] __initdata = { ++ &m520x_uart, ++}; ++ ++/***************************************************************************/ ++ ++#define INTC0 (MCF_MBAR + MCFICM_INTC0) ++ ++static void __init m520x_uart_init_line(int line, int irq) ++{ ++ u32 imr; ++ u16 par; ++ u8 par2; ++ ++ writeb(0x03, INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line); ++ ++ imr = readl(INTC0 + MCFINTC_IMRL); ++ imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1); ++ writel(imr, INTC0 + MCFINTC_IMRL); ++ ++ switch (line) { ++ case 0: ++ par = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART); ++ par |= MCF_GPIO_PAR_UART_PAR_UTXD0 | ++ MCF_GPIO_PAR_UART_PAR_URXD0; ++ writew(par, MCF_IPSBAR + MCF_GPIO_PAR_UART); ++ break; ++ case 1: ++ par = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART); ++ par |= MCF_GPIO_PAR_UART_PAR_UTXD1 | ++ MCF_GPIO_PAR_UART_PAR_URXD1; ++ writew(par, MCF_IPSBAR + MCF_GPIO_PAR_UART); ++ break; ++ case 2: ++ par2 = readb(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C); ++ par2 &= ~0x0F; ++ par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 | ++ MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; ++ writeb(par2, MCF_IPSBAR + MCF_GPIO_PAR_FECI2C); ++ break; ++ } ++} ++ ++static void __init m520x_uarts_init(void) ++{ ++ const int nrlines = ARRAY_SIZE(m520x_uart_platform); ++ int line; ++ ++ for (line = 0; (line < nrlines); line++) ++ m520x_uart_init_line(line, m520x_uart_platform[line].irq); ++} + + /***************************************************************************/ + +@@ -42,9 +114,20 @@ void mcf_autovector(unsigned int vec) + + /***************************************************************************/ + +-void config_BSP(char *commandp, int size) ++void __init config_BSP(char *commandp, int size) + { + mach_reset = coldfire_reset; ++ m520x_uarts_init(); ++} ++ ++/***************************************************************************/ ++ ++static int __init init_BSP(void) ++{ ++ platform_add_devices(m520x_devices, ARRAY_SIZE(m520x_devices)); ++ return 0; + } + ++arch_initcall(init_BSP); ++ + /***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/523x/config.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/523x/config.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/523x/config.c 2009-02-08 00:00:48.000000000 -0500 +@@ -16,11 +16,15 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +-#include ++#include ++ ++#ifdef CONFIG_MTD ++#include ++#endif + + /***************************************************************************/ + +@@ -28,14 +32,58 @@ void coldfire_reset(void); + + /***************************************************************************/ + +-/* +- * DMA channel base address table. +- */ +-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { +- MCF_MBAR + MCFDMA_BASE0, ++static struct mcf_platform_uart m523x_uart_platform[] = { ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE1, ++ .irq = MCFINT_VECBASE + MCFINT_UART0, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE2, ++ .irq = MCFINT_VECBASE + MCFINT_UART0 + 1, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE3, ++ .irq = MCFINT_VECBASE + MCFINT_UART0 + 2, ++ }, ++ { }, ++}; ++ ++static struct platform_device m523x_uart = { ++ .name = "mcfuart", ++ .id = 0, ++ .dev.platform_data = m523x_uart_platform, + }; + +-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; ++static struct platform_device *m523x_devices[] __initdata = { ++ &m523x_uart, ++}; ++ ++/***************************************************************************/ ++ ++#define INTC0 (MCF_MBAR + MCFICM_INTC0) ++ ++static void __init m523x_uart_init_line(int line, int irq) ++{ ++ u32 imr; ++ ++ if ((line < 0) || (line > 2)) ++ return; ++ ++ writeb(0x30+line, (INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line)); ++ ++ imr = readl(INTC0 + MCFINTC_IMRL); ++ imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1); ++ writel(imr, INTC0 + MCFINTC_IMRL); ++} ++ ++static void __init m523x_uarts_init(void) ++{ ++ const int nrlines = ARRAY_SIZE(m523x_uart_platform); ++ int line; ++ ++ for (line = 0; (line < nrlines); line++) ++ m523x_uart_init_line(line, m523x_uart_platform[line].irq); ++} + + /***************************************************************************/ + +@@ -49,15 +97,85 @@ void mcf_disableall(void) + + void mcf_autovector(unsigned int vec) + { +- /* Everything is auto-vectored on the 5272 */ ++ /* Everything is auto-vectored on the 523x */ + } + + /***************************************************************************/ + +-void config_BSP(char *commandp, int size) ++#if defined(CONFIG_SAVANT) ++ ++/* ++ * Do special config for SAVANT BSP ++ */ ++static void __init config_savantBSP(char *commandP, int size) ++{ ++ /* setup BOOTPARAM_STRING */ ++ strncpy(commandP, "root=/dev/mtdblock1 ro rootfstype=romfs", size); ++ /* Look at Chatter DIP Switch, if CS3 is enabled */ ++ { ++ uint32_t *csmr3 = (uint32_t *) (MCF_IPSBAR + MCF523x_CSMR3); ++ uint32_t *csar3 = (uint32_t *) (MCF_IPSBAR + MCF523x_CSAR3); ++ uint16_t *dipsP = (uint16_t *) *csar3; ++ uint16_t dipSetOff = *dipsP & 0x0100; // switch #1 ++ uint16_t *btnPressP = (uint16_t *)(*csar3 + 0x10); ++ uint16_t shortButtonPress = *btnPressP & 0x8000; ++ if (*csmr3 & 1) { ++ /* CS3 enabled */ ++ if (!dipSetOff && shortButtonPress) { ++ /* switch on, so be quiet */ ++ strncat(commandP, " console=", size-strlen(commandP)-1); ++ } ++ } ++ } ++ commandP[size-1] = 0; ++ ++ /* Set on-chip peripheral space to user mode */ ++ { ++ uint8_t *gpacr = (uint8_t *) (MCF_IPSBAR + MCF523x_GPACR); ++ uint8_t *pacr1 = (uint8_t *) (MCF_IPSBAR + MCF523x_PACR1); ++ uint8_t *pacr4 = (uint8_t *) (MCF_IPSBAR + MCF523x_PACR4); ++ uint8_t *pacr7 = (uint8_t *) (MCF_IPSBAR + MCF523x_PACR7); ++ uint8_t *pacr8 = (uint8_t *) (MCF_IPSBAR + MCF523x_PACR8); ++ *gpacr = 0x04; ++ *pacr1 = 0x40; /* EIM required for Chip Select access */ ++ *pacr4 = 0x40; /* I2C */ ++ *pacr7 = 0x44; /* INTC0 & 1 handy for debug */ ++ *pacr8 = 0x40; /* FEC MAC */ ++ } ++ ++#ifdef CONFIG_MTD ++ /* all board spins cannot access flash from linux unless we change the map here */ ++ { ++ uint32_t *csar0 = (uint32_t *) (MCF_IPSBAR + MCF523x_CSAR0); ++ uint32_t start = *csar0; ++ uint32_t size = 0xffffFFFF - start + 1; ++ physmap_configure(start, size, CONFIG_MTD_PHYSMAP_BANKWIDTH, NULL); ++ } ++#endif ++} ++ ++#endif /* CONFIG_SAVANT */ ++ ++/***************************************************************************/ ++ ++void __init config_BSP(char *commandp, int size) + { + mcf_disableall(); ++#if defined(CONFIG_SAVANT) ++ config_savantBSP(commandp, size); ++#endif /* CONFIG_SAVANT */ + mach_reset = coldfire_reset; ++ m523x_uarts_init(); ++} ++ ++/***************************************************************************/ ++ ++static int __init init_BSP(void) ++{ ++ platform_add_devices(m523x_devices, ARRAY_SIZE(m523x_devices)); ++ return 0; + } + ++arch_initcall(init_BSP); ++ + /***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/5249/config.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/5249/config.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/5249/config.c 2009-02-08 00:00:48.000000000 -0500 +@@ -12,11 +12,11 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +-#include ++#include + + /***************************************************************************/ + +@@ -24,17 +24,51 @@ void coldfire_reset(void); + + /***************************************************************************/ + +-/* +- * DMA channel base address table. +- */ +-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { +- MCF_MBAR + MCFDMA_BASE0, +- MCF_MBAR + MCFDMA_BASE1, +- MCF_MBAR + MCFDMA_BASE2, +- MCF_MBAR + MCFDMA_BASE3, ++static struct mcf_platform_uart m5249_uart_platform[] = { ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE1, ++ .irq = 73, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE2, ++ .irq = 74, ++ } ++}; ++ ++static struct platform_device m5249_uart = { ++ .name = "mcfuart", ++ .id = 0, ++ .dev.platform_data = m5249_uart_platform, + }; + +-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; ++static struct platform_device *m5249_devices[] __initdata = { ++ &m5249_uart, ++}; ++ ++/***************************************************************************/ ++ ++static void __init m5249_uart_init_line(int line, int irq) ++{ ++ if (line == 0) { ++ writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); ++ writeb(irq, MCFUART_BASE1 + MCFUART_UIVR); ++ mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1); ++ } else if (line == 1) { ++ writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); ++ writeb(irq, MCFUART_BASE2 + MCFUART_UIVR); ++ mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2); ++ } ++} ++ ++static void __init m5249_uarts_init(void) ++{ ++ const int nrlines = ARRAY_SIZE(m5249_uart_platform); ++ int line; ++ ++ for (line = 0; (line < nrlines); line++) ++ m5249_uart_init_line(line, m5249_uart_platform[line].irq); ++} ++ + + /***************************************************************************/ + +@@ -71,24 +105,21 @@ void mcf_settimericr(unsigned int timer, + + /***************************************************************************/ + +-int mcf_timerirqpending(int timer) ++void __init config_BSP(char *commandp, int size) + { +- unsigned int imr = 0; +- +- switch (timer) { +- case 1: imr = MCFSIM_IMR_TIMER1; break; +- case 2: imr = MCFSIM_IMR_TIMER2; break; +- default: break; +- } +- return (mcf_getipr() & imr); ++ mcf_setimr(MCFSIM_IMR_MASKALL); ++ mach_reset = coldfire_reset; + } + + /***************************************************************************/ + +-void config_BSP(char *commandp, int size) ++static int __init init_BSP(void) + { +- mcf_setimr(MCFSIM_IMR_MASKALL); +- mach_reset = coldfire_reset; ++ m5249_uarts_init(); ++ platform_add_devices(m5249_devices, ARRAY_SIZE(m5249_devices)); ++ return 0; + } + ++arch_initcall(init_BSP); ++ + /***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/5272/config.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/5272/config.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/5272/config.c 2009-02-08 00:00:48.000000000 -0500 +@@ -13,11 +13,11 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +-#include ++#include + + /***************************************************************************/ + +@@ -37,14 +37,57 @@ unsigned char ledbank = 0xff; + + /***************************************************************************/ + +-/* +- * DMA channel base address table. +- */ +-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { +- MCF_MBAR + MCFDMA_BASE0, ++static struct mcf_platform_uart m5272_uart_platform[] = { ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE1, ++ .irq = 73, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE2, ++ .irq = 74, ++ }, ++ { }, + }; + +-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; ++static struct platform_device m5272_uart = { ++ .name = "mcfuart", ++ .id = 0, ++ .dev.platform_data = m5272_uart_platform, ++}; ++ ++static struct platform_device *m5272_devices[] __initdata = { ++ &m5272_uart, ++}; ++ ++/***************************************************************************/ ++ ++static void __init m5272_uart_init_line(int line, int irq) ++{ ++ u32 v; ++ ++ if ((line >= 0) && (line < 2)) { ++ v = (line) ? 0x0e000000 : 0xe0000000; ++ writel(v, MCF_MBAR + MCFSIM_ICR2); ++ ++ /* Enable the output lines for the serial ports */ ++ v = readl(MCF_MBAR + MCFSIM_PBCNT); ++ v = (v & ~0x000000ff) | 0x00000055; ++ writel(v, MCF_MBAR + MCFSIM_PBCNT); ++ ++ v = readl(MCF_MBAR + MCFSIM_PDCNT); ++ v = (v & ~0x000003fc) | 0x000002a8; ++ writel(v, MCF_MBAR + MCFSIM_PDCNT); ++ } ++} ++ ++static void __init m5272_uarts_init(void) ++{ ++ const int nrlines = ARRAY_SIZE(m5272_uart_platform); ++ int line; ++ ++ for (line = 0; (line < nrlines); line++) ++ m5272_uart_init_line(line, m5272_uart_platform[line].irq); ++} + + /***************************************************************************/ + +@@ -80,20 +123,7 @@ void mcf_settimericr(int timer, int leve + + /***************************************************************************/ + +-int mcf_timerirqpending(int timer) +-{ +- volatile unsigned long *icrp; +- +- if ((timer >= 1 ) && (timer <= 4)) { +- icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); +- return (*icrp & (0x8 << ((4 - timer) * 4))); +- } +- return 0; +-} +- +-/***************************************************************************/ +- +-void config_BSP(char *commandp, int size) ++void __init config_BSP(char *commandp, int size) + { + #if defined (CONFIG_MOD5272) + volatile unsigned char *pivrp; +@@ -109,10 +139,6 @@ void config_BSP(char *commandp, int size + /* Copy command line from FLASH to local buffer... */ + memcpy(commandp, (char *) 0xf0004000, size); + commandp[size-1] = 0; +-#elif defined(CONFIG_MTD_KeyTechnology) +- /* Copy command line from FLASH to local buffer... */ +- memcpy(commandp, (char *) 0xffe06000, size); +- commandp[size-1] = 0; + #elif defined(CONFIG_CANCam) + /* Copy command line from FLASH to local buffer... */ + memcpy(commandp, (char *) 0xf0010000, size); +@@ -125,3 +151,14 @@ void config_BSP(char *commandp, int size + } + + /***************************************************************************/ ++ ++static int __init init_BSP(void) ++{ ++ m5272_uarts_init(); ++ platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices)); ++ return 0; ++} ++ ++arch_initcall(init_BSP); ++ ++/***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/527x/config.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/527x/config.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/527x/config.c 2009-02-08 00:00:48.000000000 -0500 +@@ -16,11 +16,11 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +-#include ++#include + + /***************************************************************************/ + +@@ -28,14 +28,72 @@ void coldfire_reset(void); + + /***************************************************************************/ + +-/* +- * DMA channel base address table. +- */ +-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { +- MCF_MBAR + MCFDMA_BASE0, ++static struct mcf_platform_uart m527x_uart_platform[] = { ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE1, ++ .irq = MCFINT_VECBASE + MCFINT_UART0, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE2, ++ .irq = MCFINT_VECBASE + MCFINT_UART1, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE3, ++ .irq = MCFINT_VECBASE + MCFINT_UART2, ++ }, ++ { }, + }; + +-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; ++static struct platform_device m527x_uart = { ++ .name = "mcfuart", ++ .id = 0, ++ .dev.platform_data = m527x_uart_platform, ++}; ++ ++static struct platform_device *m527x_devices[] __initdata = { ++ &m527x_uart, ++}; ++ ++/***************************************************************************/ ++ ++#define INTC0 (MCF_MBAR + MCFICM_INTC0) ++ ++static void __init m527x_uart_init_line(int line, int irq) ++{ ++ u16 sepmask; ++ u32 imr; ++ ++ if ((line < 0) || (line > 2)) ++ return; ++ ++ /* level 6, line based priority */ ++ writeb(0x30+line, INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line); ++ ++ imr = readl(INTC0 + MCFINTC_IMRL); ++ imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1); ++ writel(imr, INTC0 + MCFINTC_IMRL); ++ ++ /* ++ * External Pin Mask Setting & Enable External Pin for Interface ++ */ ++ sepmask = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART); ++ if (line == 0) ++ sepmask |= UART0_ENABLE_MASK; ++ else if (line == 1) ++ sepmask |= UART1_ENABLE_MASK; ++ else if (line == 2) ++ sepmask |= UART2_ENABLE_MASK; ++ writew(sepmask, MCF_IPSBAR + MCF_GPIO_PAR_UART); ++} ++ ++static void __init m527x_uarts_init(void) ++{ ++ const int nrlines = ARRAY_SIZE(m527x_uart_platform); ++ int line; ++ ++ for (line = 0; (line < nrlines); line++) ++ m527x_uart_init_line(line, m527x_uart_platform[line].irq); ++} + + /***************************************************************************/ + +@@ -54,10 +112,21 @@ void mcf_autovector(unsigned int vec) + + /***************************************************************************/ + +-void config_BSP(char *commandp, int size) ++void __init config_BSP(char *commandp, int size) + { + mcf_disableall(); + mach_reset = coldfire_reset; + } + + /***************************************************************************/ ++ ++static int __init init_BSP(void) ++{ ++ m527x_uarts_init(); ++ platform_add_devices(m527x_devices, ARRAY_SIZE(m527x_devices)); ++ return 0; ++} ++ ++arch_initcall(init_BSP); ++ ++/***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/528x/config.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/528x/config.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/528x/config.c 2009-02-08 00:00:48.000000000 -0500 +@@ -16,26 +16,314 @@ + #include + #include + #include +-#include ++#include ++#include ++#include ++#include + #include + #include + #include +-#include ++#include ++#include ++ ++#ifdef CONFIG_MTD_PARTITIONS ++#include ++#endif + + /***************************************************************************/ + + void coldfire_reset(void); ++void coldfire_qspi_cs_control(u8 cs, u8 command); ++ ++/***************************************************************************/ ++ ++#if defined(CONFIG_SPI) ++ ++#if defined(CONFIG_WILDFIRE) ++#define SPI_NUM_CHIPSELECTS 0x02 ++#define SPI_PAR_VAL 0x07 // Enable DIN, DOUT, CLK ++#define SPI_CS_MASK 0x18 ++ ++#define FLASH_BLOCKSIZE (1024*64) ++#define FLASH_NUMBLOCKS 16 ++#define FLASH_TYPE "m25p80" ++ ++#define M25P80_CS 0 ++#define MMC_CS 1 ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition stm25p_partitions[] = { ++ /* sflash */ ++ [0] = { ++ .name = "stm25p80", ++ .offset = 0x00000000, ++ .size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS, ++ .mask_flags = 0 ++ } ++}; ++ ++#endif ++ ++#elif defined(CONFIG_WILDFIREMOD) ++ ++#define SPI_NUM_CHIPSELECTS 0x08 ++#define SPI_PAR_VAL 0x07 // Enable DIN, DOUT, CLK ++#define SPI_CS_MASK 0x78 ++ ++#define FLASH_BLOCKSIZE (1024*64) ++#define FLASH_NUMBLOCKS 64 ++#define FLASH_TYPE "m25p32" ++/* Reserve 1M for the kernel parition */ ++#define FLASH_KERNEL_SIZE (1024 * 1024) ++ ++#define M25P80_CS 5 ++#define MMC_CS 6 ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition stm25p_partitions[] = { ++ /* sflash */ ++ [0] = { ++ .name = "kernel", ++ .offset = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS - FLASH_KERNEL_SIZE, ++ .size = FLASH_KERNEL_SIZE, ++ .mask_flags = 0 ++ }, ++ [1] = { ++ .name = "image", ++ .offset = 0x00000000, ++ .size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS - FLASH_KERNEL_SIZE, ++ .mask_flags = 0 ++ }, ++ [2] = { ++ .name = "all", ++ .offset = 0x00000000, ++ .size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS, ++ .mask_flags = 0 ++ } ++}; ++#endif ++ ++#else ++#define SPI_NUM_CHIPSELECTS 0x04 ++#define SPI_PAR_VAL 0x7F // Enable DIN, DOUT, CLK, CS0 - CS4 ++#endif ++ ++#ifdef MMC_CS ++static struct coldfire_spi_chip flash_chip_info = { ++ .mode = SPI_MODE_0, ++ .bits_per_word = 16, ++ .del_cs_to_clk = 17, ++ .del_after_trans = 1, ++ .void_write_data = 0 ++}; ++ ++static struct coldfire_spi_chip mmc_chip_info = { ++ .mode = SPI_MODE_0, ++ .bits_per_word = 16, ++ .del_cs_to_clk = 17, ++ .del_after_trans = 1, ++ .void_write_data = 0xFFFF ++}; ++#endif ++ ++#ifdef M25P80_CS ++static struct flash_platform_data stm25p80_platform_data = { ++ .name = "ST M25P80 SPI Flash chip", ++#ifdef CONFIG_MTD_PARTITIONS ++ .parts = stm25p_partitions, ++ .nr_parts = sizeof(stm25p_partitions) / sizeof(*stm25p_partitions), ++#endif ++ .type = FLASH_TYPE ++}; ++#endif ++ ++static struct spi_board_info spi_board_info[] __initdata = { ++#ifdef M25P80_CS ++ { ++ .modalias = "m25p80", ++ .max_speed_hz = 16000000, ++ .bus_num = 1, ++ .chip_select = M25P80_CS, ++ .platform_data = &stm25p80_platform_data, ++ .controller_data = &flash_chip_info ++ }, ++#endif ++#ifdef MMC_CS ++ { ++ .modalias = "mmc_spi", ++ .max_speed_hz = 16000000, ++ .bus_num = 1, ++ .chip_select = MMC_CS, ++ .controller_data = &mmc_chip_info ++ } ++#endif ++}; ++ ++static struct coldfire_spi_master coldfire_master_info = { ++ .bus_num = 1, ++ .num_chipselect = SPI_NUM_CHIPSELECTS, ++ .irq_source = MCF5282_QSPI_IRQ_SOURCE, ++ .irq_vector = MCF5282_QSPI_IRQ_VECTOR, ++ .irq_mask = ((0x01 << MCF5282_QSPI_IRQ_SOURCE) | 0x01), ++ .irq_lp = 0x2B, // Level 5 and Priority 3 ++ .par_val = SPI_PAR_VAL, ++ .cs_control = coldfire_qspi_cs_control, ++}; ++ ++static struct resource coldfire_spi_resources[] = { ++ [0] = { ++ .name = "qspi-par", ++ .start = MCF5282_QSPI_PAR, ++ .end = MCF5282_QSPI_PAR, ++ .flags = IORESOURCE_MEM ++ }, ++ ++ [1] = { ++ .name = "qspi-module", ++ .start = MCF5282_QSPI_QMR, ++ .end = MCF5282_QSPI_QMR + 0x18, ++ .flags = IORESOURCE_MEM ++ }, ++ ++ [2] = { ++ .name = "qspi-int-level", ++ .start = MCF5282_INTC0 + MCFINTC_ICR0 + MCF5282_QSPI_IRQ_SOURCE, ++ .end = MCF5282_INTC0 + MCFINTC_ICR0 + MCF5282_QSPI_IRQ_SOURCE, ++ .flags = IORESOURCE_MEM ++ }, ++ ++ [3] = { ++ .name = "qspi-int-mask", ++ .start = MCF5282_INTC0 + MCFINTC_IMRL, ++ .end = MCF5282_INTC0 + MCFINTC_IMRL, ++ .flags = IORESOURCE_MEM ++ } ++}; ++ ++static struct platform_device coldfire_spi = { ++ .name = "spi_coldfire", ++ .id = -1, ++ .resource = coldfire_spi_resources, ++ .num_resources = ARRAY_SIZE(coldfire_spi_resources), ++ .dev = { ++ .platform_data = &coldfire_master_info, ++ } ++}; ++ ++void coldfire_qspi_cs_control(u8 cs, u8 command) ++{ ++ u8 cs_bit = ((0x01 << cs) << 3) & SPI_CS_MASK; ++ ++#if defined(CONFIG_WILDFIRE) ++ u8 cs_mask = ~(((0x01 << cs) << 3) & SPI_CS_MASK); ++#endif ++#if defined(CONFIG_WILDFIREMOD) ++ u8 cs_mask = (cs << 3) & SPI_CS_MASK; ++#endif ++ ++ /* ++ * Don't do anything if the chip select is not ++ * one of the port qs pins. ++ */ ++ if (command & QSPI_CS_INIT) { ++#if defined(CONFIG_WILDFIRE) ++ MCF5282_GPIO_DDRQS |= cs_bit; ++ MCF5282_GPIO_PQSPAR &= ~cs_bit; ++#endif ++ ++#if defined(CONFIG_WILDFIREMOD) ++ MCF5282_GPIO_DDRQS |= SPI_CS_MASK; ++ MCF5282_GPIO_PQSPAR &= ~SPI_CS_MASK; ++#endif ++ } ++ ++ if (command & QSPI_CS_ASSERT) { ++ MCF5282_GPIO_PORTQS &= ~SPI_CS_MASK; ++ MCF5282_GPIO_PORTQS |= cs_mask; ++ } else if (command & QSPI_CS_DROP) { ++ MCF5282_GPIO_PORTQS |= SPI_CS_MASK; ++ } ++} ++ ++static int __init spi_dev_init(void) ++{ ++ int retval; ++ ++ retval = platform_device_register(&coldfire_spi); ++ if (retval < 0) ++ return retval; ++ ++ if (ARRAY_SIZE(spi_board_info)) ++ retval = spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); ++ ++ return retval; ++} ++ ++#endif /* CONFIG_SPI */ + + /***************************************************************************/ + +-/* +- * DMA channel base address table. +- */ +-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { +- MCF_MBAR + MCFDMA_BASE0, ++static struct mcf_platform_uart m528x_uart_platform[] = { ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE1, ++ .irq = MCFINT_VECBASE + MCFINT_UART0, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE2, ++ .irq = MCFINT_VECBASE + MCFINT_UART0 + 1, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE3, ++ .irq = MCFINT_VECBASE + MCFINT_UART0 + 2, ++ }, ++ { }, ++}; ++ ++static struct platform_device m528x_uart = { ++ .name = "mcfuart", ++ .id = 0, ++ .dev.platform_data = m528x_uart_platform, ++}; ++ ++static struct platform_device *m528x_devices[] __initdata = { ++ &m528x_uart, + }; + +-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; ++/***************************************************************************/ ++ ++#define INTC0 (MCF_MBAR + MCFICM_INTC0) ++ ++static void __init m528x_uart_init_line(int line, int irq) ++{ ++ u8 port; ++ u32 imr; ++ ++ if ((line < 0) || (line > 2)) ++ return; ++ ++ /* level 6, line based priority */ ++ writeb(0x30+line, INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line); ++ ++ imr = readl(INTC0 + MCFINTC_IMRL); ++ imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1); ++ writel(imr, INTC0 + MCFINTC_IMRL); ++ ++ /* make sure PUAPAR is set for UART0 and UART1 */ ++ if (line < 2) { ++ port = readb(MCF_MBAR + MCF5282_GPIO_PUAPAR); ++ port |= (0x03 << (line * 2)); ++ writeb(port, MCF_MBAR + MCF5282_GPIO_PUAPAR); ++ } ++} ++ ++static void __init m528x_uarts_init(void) ++{ ++ const int nrlines = ARRAY_SIZE(m528x_uart_platform); ++ int line; ++ ++ for (line = 0; (line < nrlines); line++) ++ m528x_uart_init_line(line, m528x_uart_platform[line].irq); ++} + + /***************************************************************************/ + +@@ -54,10 +342,57 @@ void mcf_autovector(unsigned int vec) + + /***************************************************************************/ + +-void config_BSP(char *commandp, int size) ++#ifdef CONFIG_WILDFIRE ++void wildfire_halt (void) ++{ ++ writeb(0, 0x30000007); ++ writeb(0x2, 0x30000007); ++} ++#endif ++ ++#ifdef CONFIG_WILDFIREMOD ++void wildfiremod_halt (void) ++{ ++ printk("WildFireMod hibernating...\n"); ++ ++ /* Set portE.5 to Digital IO */ ++ MCF5282_GPIO_PEPAR &= ~(1 << (5 * 2)); ++ ++ /* Make portE.5 an output */ ++ MCF5282_GPIO_DDRE |= (1 << 5); ++ ++ /* Now toggle portE.5 from low to high */ ++ MCF5282_GPIO_PORTE &= ~(1 << 5); ++ MCF5282_GPIO_PORTE |= (1 << 5); ++ ++ printk("Failed to hibernate. Halting!\n"); ++} ++#endif ++ ++void __init config_BSP(char *commandp, int size) + { + mcf_disableall(); +- mach_reset = coldfire_reset; ++ ++#ifdef CONFIG_WILDFIRE ++ mach_halt = wildfire_halt; ++#endif ++#ifdef CONFIG_WILDFIREMOD ++ mach_halt = wildfiremod_halt; ++#endif ++} ++ ++/***************************************************************************/ ++ ++static int __init init_BSP(void) ++{ ++ m528x_uarts_init(); ++#ifdef CONFIG_SPI ++ spi_dev_init(); ++#endif ++ platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices)); ++ return 0; + } + ++arch_initcall(init_BSP); ++ + /***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/5307/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/5307/Makefile 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/5307/Makefile 2009-02-08 00:00:48.000000000 -0500 +@@ -16,17 +16,5 @@ ifdef CONFIG_FULLDEBUG + EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 + endif + +-obj-$(CONFIG_COLDFIRE) += entry.o vectors.o +-obj-$(CONFIG_M5206) += timers.o +-obj-$(CONFIG_M5206e) += timers.o +-obj-$(CONFIG_M520x) += pit.o +-obj-$(CONFIG_M523x) += pit.o +-obj-$(CONFIG_M5249) += timers.o +-obj-$(CONFIG_M527x) += pit.o +-obj-$(CONFIG_M5272) += timers.o +-obj-$(CONFIG_M5307) += config.o timers.o +-obj-$(CONFIG_M532x) += timers.o +-obj-$(CONFIG_M528x) += pit.o +-obj-$(CONFIG_M5407) += timers.o ++obj-y += config.o + +-extra-y := head.o +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/5307/config.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/5307/config.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/5307/config.c 2009-02-08 00:00:48.000000000 -0500 +@@ -13,11 +13,11 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +-#include ++#include + #include + + /***************************************************************************/ +@@ -38,17 +38,51 @@ unsigned char ledbank = 0xff; + + /***************************************************************************/ + +-/* +- * DMA channel base address table. +- */ +-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { +- MCF_MBAR + MCFDMA_BASE0, +- MCF_MBAR + MCFDMA_BASE1, +- MCF_MBAR + MCFDMA_BASE2, +- MCF_MBAR + MCFDMA_BASE3, ++static struct mcf_platform_uart m5307_uart_platform[] = { ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE1, ++ .irq = 73, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE2, ++ .irq = 74, ++ }, ++ { }, ++}; ++ ++static struct platform_device m5307_uart = { ++ .name = "mcfuart", ++ .id = 0, ++ .dev.platform_data = m5307_uart_platform, + }; + +-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; ++static struct platform_device *m5307_devices[] __initdata = { ++ &m5307_uart, ++}; ++ ++/***************************************************************************/ ++ ++static void __init m5307_uart_init_line(int line, int irq) ++{ ++ if (line == 0) { ++ writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); ++ writeb(irq, MCFUART_BASE1 + MCFUART_UIVR); ++ mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1); ++ } else if (line == 1) { ++ writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); ++ writeb(irq, MCFUART_BASE2 + MCFUART_UIVR); ++ mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2); ++ } ++} ++ ++static void __init m5307_uarts_init(void) ++{ ++ const int nrlines = ARRAY_SIZE(m5307_uart_platform); ++ int line; ++ ++ for (line = 0; (line < nrlines); line++) ++ m5307_uart_init_line(line, m5307_uart_platform[line].irq); ++} + + /***************************************************************************/ + +@@ -85,27 +119,12 @@ void mcf_settimericr(unsigned int timer, + + /***************************************************************************/ + +-int mcf_timerirqpending(int timer) +-{ +- unsigned int imr = 0; +- +- switch (timer) { +- case 1: imr = MCFSIM_IMR_TIMER1; break; +- case 2: imr = MCFSIM_IMR_TIMER2; break; +- default: break; +- } +- return (mcf_getipr() & imr); +-} +- +-/***************************************************************************/ +- +-void config_BSP(char *commandp, int size) ++void __init config_BSP(char *commandp, int size) + { + mcf_setimr(MCFSIM_IMR_MASKALL); + + #if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \ +- defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) || \ +- defined(CONFIG_CLEOPATRA) ++ defined(CONFIG_SECUREEDGEMP3) || defined(CONFIG_CLEOPATRA) + /* Copy command line from FLASH to local buffer... */ + memcpy(commandp, (char *) 0xf0004000, size); + commandp[size-1] = 0; +@@ -117,7 +136,7 @@ void config_BSP(char *commandp, int size + + mach_reset = coldfire_reset; + +-#ifdef MCF_BDM_DISABLE ++#ifdef CONFIG_BDM_DISABLE + /* + * Disable the BDM clocking. This also turns off most of the rest of + * the BDM device. This is good for EMC reasons. This option is not +@@ -128,3 +147,14 @@ void config_BSP(char *commandp, int size + } + + /***************************************************************************/ ++ ++static int __init init_BSP(void) ++{ ++ m5307_uarts_init(); ++ platform_add_devices(m5307_devices, ARRAY_SIZE(m5307_devices)); ++ return 0; ++} ++ ++arch_initcall(init_BSP); ++ ++/***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/5307/entry.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/5307/entry.S 2009-02-08 00:00:33.000000000 -0500 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,235 +0,0 @@ +-/* +- * linux/arch/m68knommu/platform/5307/entry.S +- * +- * Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com) +- * Copyright (C) 1998 D. Jeff Dionne , +- * Kenneth Albanowski , +- * Copyright (C) 2000 Lineo Inc. (www.lineo.com) +- * Copyright (C) 2004-2006 Macq Electronique SA. (www.macqel.com) +- * +- * Based on: +- * +- * linux/arch/m68k/kernel/entry.S +- * +- * Copyright (C) 1991, 1992 Linus Torvalds +- * +- * This file is subject to the terms and conditions of the GNU General Public +- * License. See the file README.legal in the main directory of this archive +- * for more details. +- * +- * Linux/m68k support by Hamish Macdonald +- * +- * 68060 fixes by Jesper Skov +- * ColdFire support by Greg Ungerer (gerg@snapgear.com) +- * 5307 fixes by David W. Miller +- * linux 2.4 support David McCullough +- * Bug, speed and maintainability fixes by Philippe De Muyter +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-.bss +- +-sw_ksp: +-.long 0 +- +-sw_usp: +-.long 0 +- +-.text +- +-.globl system_call +-.globl resume +-.globl ret_from_exception +-.globl ret_from_signal +-.globl sys_call_table +-.globl ret_from_interrupt +-.globl inthandler +-.globl fasthandler +- +-enosys: +- mov.l #sys_ni_syscall,%d3 +- bra 1f +- +-ENTRY(system_call) +- SAVE_ALL +- move #0x2000,%sr /* enable intrs again */ +- +- cmpl #NR_syscalls,%d0 +- jcc enosys +- lea sys_call_table,%a0 +- lsll #2,%d0 /* movel %a0@(%d0:l:4),%d3 */ +- movel %a0@(%d0),%d3 +- jeq enosys +- +-1: +- movel %sp,%d2 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d2 /* at start of kernel stack */ +- movel %d2,%a0 +- movel %a0@,%a1 /* save top of frame */ +- movel %sp,%a1@(TASK_THREAD+THREAD_ESP0) +- btst #(TIF_SYSCALL_TRACE%8),%a0@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8) +- bnes 1f +- +- movel %d3,%a0 +- jbsr %a0@ +- movel %d0,%sp@(PT_D0) /* save the return value */ +- jra ret_from_exception +-1: +- movel #-ENOSYS,%d2 /* strace needs -ENOSYS in PT_D0 */ +- movel %d2,PT_D0(%sp) /* on syscall entry */ +- subql #4,%sp +- SAVE_SWITCH_STACK +- jbsr syscall_trace +- RESTORE_SWITCH_STACK +- addql #4,%sp +- movel %d3,%a0 +- jbsr %a0@ +- movel %d0,%sp@(PT_D0) /* save the return value */ +- subql #4,%sp /* dummy return address */ +- SAVE_SWITCH_STACK +- jbsr syscall_trace +- +-ret_from_signal: +- RESTORE_SWITCH_STACK +- addql #4,%sp +- +-ret_from_exception: +- btst #5,%sp@(PT_SR) /* check if returning to kernel */ +- jeq Luser_return /* if so, skip resched, signals */ +- +-Lkernel_return: +- moveml %sp@,%d1-%d5/%a0-%a2 +- lea %sp@(32),%sp /* space for 8 regs */ +- movel %sp@+,%d0 +- addql #4,%sp /* orig d0 */ +- addl %sp@+,%sp /* stk adj */ +- rte +- +-Luser_return: +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 /* at base of kernel stack */ +- movel %d1,%a0 +- movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */ +- andl #_TIF_WORK_MASK,%d1 +- jne Lwork_to_do /* still work to do */ +- +-Lreturn: +- move #0x2700,%sr /* disable intrs */ +- movel sw_usp,%a0 /* get usp */ +- movel %sp@(PT_PC),%a0@- /* copy exception program counter */ +- movel %sp@(PT_FORMATVEC),%a0@-/* copy exception format/vector/sr */ +- moveml %sp@,%d1-%d5/%a0-%a2 +- lea %sp@(32),%sp /* space for 8 regs */ +- movel %sp@+,%d0 +- addql #4,%sp /* orig d0 */ +- addl %sp@+,%sp /* stk adj */ +- addql #8,%sp /* remove exception */ +- movel %sp,sw_ksp /* save ksp */ +- subql #8,sw_usp /* set exception */ +- movel sw_usp,%sp /* restore usp */ +- rte +- +-Lwork_to_do: +- movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */ +- btst #TIF_NEED_RESCHED,%d1 +- jne reschedule +- +- /* GERG: do we need something here for TRACEing?? */ +- +-Lsignal_return: +- subql #4,%sp /* dummy return address */ +- SAVE_SWITCH_STACK +- pea %sp@(SWITCH_STACK_SIZE) +- clrl %sp@- +- jsr do_signal +- addql #8,%sp +- RESTORE_SWITCH_STACK +- addql #4,%sp +- jmp Lreturn +- +-/* +- * This is the generic interrupt handler (for all hardware interrupt +- * sources). Calls upto high level code to do all the work. +- */ +-ENTRY(inthandler) +- SAVE_ALL +- moveq #-1,%d0 +- movel %d0,%sp@(PT_ORIG_D0) +- +- movew %sp@(PT_FORMATVEC),%d0 /* put exception # in d0 */ +- andl #0x03fc,%d0 /* mask out vector only */ +- +- movel %sp,%sp@- /* push regs arg */ +- lsrl #2,%d0 /* calculate real vector # */ +- movel %d0,%sp@- /* push vector number */ +- jbsr do_IRQ /* call high level irq handler */ +- lea %sp@(8),%sp /* pop args off stack */ +- +- bra ret_from_interrupt /* this was fallthrough */ +- +-/* +- * This is the fast interrupt handler (for certain hardware interrupt +- * sources). Unlike the normal interrupt handler it just uses the +- * current stack (doesn't care if it is user or kernel). It also +- * doesn't bother doing the bottom half handlers. +- */ +-ENTRY(fasthandler) +- SAVE_LOCAL +- +- movew %sp@(PT_FORMATVEC),%d0 +- andl #0x03fc,%d0 /* mask out vector only */ +- +- movel %sp,%sp@- /* push regs arg */ +- lsrl #2,%d0 /* calculate real vector # */ +- movel %d0,%sp@- /* push vector number */ +- jbsr do_IRQ /* call high level irq handler */ +- lea %sp@(8),%sp /* pop args off stack */ +- +- RESTORE_LOCAL +- +-ENTRY(ret_from_interrupt) +- jeq 2f +-1: +- RESTORE_ALL +-2: +- moveb %sp@(PT_SR),%d0 +- andl #0x7,%d0 +- jhi 1b +- +- /* check if we need to do software interrupts */ +- movel irq_stat+CPUSTAT_SOFTIRQ_PENDING,%d0 +- jeq ret_from_exception +- +- pea ret_from_exception +- jmp do_softirq +- +-/* +- * Beware - when entering resume, prev (the current task) is +- * in a0, next (the new task) is in a1,so don't change these +- * registers until their contents are no longer needed. +- * This is always called in supervisor mode, so don't bother to save +- * and restore sr; user's process sr is actually in the stack. +- */ +-ENTRY(resume) +- movel %a0, %d1 /* get prev thread in d1 */ +- +- movel sw_usp,%d0 /* save usp */ +- movel %d0,%a0@(TASK_THREAD+THREAD_USP) +- +- SAVE_SWITCH_STACK +- movel %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */ +- movel %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */ +- RESTORE_SWITCH_STACK +- +- movel %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore thread user stack */ +- movel %a0, sw_usp +- rts +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/5307/head.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/5307/head.S 2009-02-08 00:00:33.000000000 -0500 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,222 +0,0 @@ +-/*****************************************************************************/ +- +-/* +- * head.S -- common startup code for ColdFire CPUs. +- * +- * (C) Copyright 1999-2006, Greg Ungerer . +- */ +- +-/*****************************************************************************/ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-/*****************************************************************************/ +- +-/* +- * If we don't have a fixed memory size, then lets build in code +- * to auto detect the DRAM size. Obviously this is the prefered +- * method, and should work for most boards. It won't work for those +- * that do not have their RAM starting at address 0, and it only +- * works on SDRAM (not boards fitted with SRAM). +- */ +-#if CONFIG_RAMSIZE != 0 +-.macro GET_MEM_SIZE +- movel #CONFIG_RAMSIZE,%d0 /* hard coded memory size */ +-.endm +- +-#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \ +- defined(CONFIG_M5249) || defined(CONFIG_M527x) || \ +- defined(CONFIG_M528x) || defined(CONFIG_M5307) || \ +- defined(CONFIG_M5407) +-/* +- * Not all these devices have exactly the same DRAM controller, +- * but the DCMR register is virtually identical - give or take +- * a couple of bits. The only exception is the 5272 devices, their +- * DRAM controller is quite different. +- */ +-.macro GET_MEM_SIZE +- movel MCF_MBAR+MCFSIM_DMR0,%d0 /* get mask for 1st bank */ +- btst #0,%d0 /* check if region enabled */ +- beq 1f +- andl #0xfffc0000,%d0 +- beq 1f +- addl #0x00040000,%d0 /* convert mask to size */ +-1: +- movel MCF_MBAR+MCFSIM_DMR1,%d1 /* get mask for 2nd bank */ +- btst #0,%d1 /* check if region enabled */ +- beq 2f +- andl #0xfffc0000, %d1 +- beq 2f +- addl #0x00040000,%d1 +- addl %d1,%d0 /* total mem size in d0 */ +-2: +-.endm +- +-#elif defined(CONFIG_M5272) +-.macro GET_MEM_SIZE +- movel MCF_MBAR+MCFSIM_CSOR7,%d0 /* get SDRAM address mask */ +- andil #0xfffff000,%d0 /* mask out chip select options */ +- negl %d0 /* negate bits */ +-.endm +- +-#elif defined(CONFIG_M520x) +-.macro GET_MEM_SIZE +- clrl %d0 +- movel MCF_MBAR+MCFSIM_SDCS0, %d2 /* Get SDRAM chip select 0 config */ +- andl #0x1f, %d2 /* Get only the chip select size */ +- beq 3f /* Check if it is enabled */ +- addql #1, %d2 /* Form exponent */ +- moveql #1, %d0 +- lsll %d2, %d0 /* 2 ^ exponent */ +-3: +- movel MCF_MBAR+MCFSIM_SDCS1, %d2 /* Get SDRAM chip select 1 config */ +- andl #0x1f, %d2 /* Get only the chip select size */ +- beq 4f /* Check if it is enabled */ +- addql #1, %d2 /* Form exponent */ +- moveql #1, %d1 +- lsll %d2, %d1 /* 2 ^ exponent */ +- addl %d1, %d0 /* Total size of SDRAM in d0 */ +-4: +-.endm +- +-#else +-#error "ERROR: I don't know how to probe your boards memory size?" +-#endif +- +-/*****************************************************************************/ +- +-/* +- * Boards and platforms can do specific early hardware setup if +- * they need to. Most don't need this, define away if not required. +- */ +-#ifndef PLATFORM_SETUP +-#define PLATFORM_SETUP +-#endif +- +-/*****************************************************************************/ +- +-.global _start +-.global _rambase +-.global _ramvec +-.global _ramstart +-.global _ramend +- +-/*****************************************************************************/ +- +-.data +- +-/* +- * During startup we store away the RAM setup. These are not in the +- * bss, since their values are determined and written before the bss +- * has been cleared. +- */ +-_rambase: +-.long 0 +-_ramvec: +-.long 0 +-_ramstart: +-.long 0 +-_ramend: +-.long 0 +- +-/*****************************************************************************/ +- +-.text +- +-/* +- * This is the codes first entry point. This is where it all +- * begins... +- */ +- +-_start: +- nop /* filler */ +- movew #0x2700, %sr /* no interrupts */ +- +- /* +- * Do any platform or board specific setup now. Most boards +- * don't need anything. Those exceptions are define this in +- * their board specific includes. +- */ +- PLATFORM_SETUP +- +- /* +- * Create basic memory configuration. Set VBR accordingly, +- * and size memory. +- */ +- movel #CONFIG_VECTORBASE,%a7 +- movec %a7,%VBR /* set vectors addr */ +- movel %a7,_ramvec +- +- movel #CONFIG_RAMBASE,%a7 /* mark the base of RAM */ +- movel %a7,_rambase +- +- GET_MEM_SIZE /* macro code determines size */ +- addl %a7,%d0 +- movel %d0,_ramend /* set end ram addr */ +- +- /* +- * Now that we know what the memory is, lets enable cache +- * and get things moving. This is Coldfire CPU specific. +- */ +- CACHE_ENABLE /* enable CPU cache */ +- +- +-#ifdef CONFIG_ROMFS_FS +- /* +- * Move ROM filesystem above bss :-) +- */ +- lea _sbss,%a0 /* get start of bss */ +- lea _ebss,%a1 /* set up destination */ +- movel %a0,%a2 /* copy of bss start */ +- +- movel 8(%a0),%d0 /* get size of ROMFS */ +- addql #8,%d0 /* allow for rounding */ +- andl #0xfffffffc, %d0 /* whole words */ +- +- addl %d0,%a0 /* copy from end */ +- addl %d0,%a1 /* copy from end */ +- movel %a1,_ramstart /* set start of ram */ +- +-_copy_romfs: +- movel -(%a0),%d0 /* copy dword */ +- movel %d0,-(%a1) +- cmpl %a0,%a2 /* check if at end */ +- bne _copy_romfs +- +-#else /* CONFIG_ROMFS_FS */ +- lea _ebss,%a1 +- movel %a1,_ramstart +-#endif /* CONFIG_ROMFS_FS */ +- +- +- /* +- * Zero out the bss region. +- */ +- lea _sbss,%a0 /* get start of bss */ +- lea _ebss,%a1 /* get end of bss */ +- clrl %d0 /* set value */ +-_clear_bss: +- movel %d0,(%a0)+ /* clear each word */ +- cmpl %a0,%a1 /* check if at end */ +- bne _clear_bss +- +- /* +- * Load the current task pointer and stack. +- */ +- lea init_thread_union,%a0 +- lea THREAD_SIZE(%a0),%sp +- +- /* +- * Assember start up done, start code proper. +- */ +- jsr start_kernel /* start Linux kernel */ +- +-_exit: +- jmp _exit /* should never get here */ +- +-/*****************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/5307/pit.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/5307/pit.c 2009-02-08 00:00:33.000000000 -0500 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,97 +0,0 @@ +-/***************************************************************************/ +- +-/* +- * pit.c -- Freescale ColdFire PIT timer. Currently this type of +- * hardware timer only exists in the Freescale ColdFire +- * 5270/5271, 5282 and other CPUs. +- * +- * Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com) +- * Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com) +- */ +- +-/***************************************************************************/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/***************************************************************************/ +- +-/* +- * By default use timer1 as the system clock timer. +- */ +-#define TA(a) (MCF_IPSBAR + MCFPIT_BASE1 + (a)) +- +-/***************************************************************************/ +- +-static irqreturn_t hw_tick(int irq, void *dummy) +-{ +- unsigned short pcsr; +- +- /* Reset the ColdFire timer */ +- pcsr = __raw_readw(TA(MCFPIT_PCSR)); +- __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR)); +- +- return arch_timer_interrupt(irq, dummy); +-} +- +-/***************************************************************************/ +- +-static struct irqaction coldfire_pit_irq = { +- .name = "timer", +- .flags = IRQF_DISABLED | IRQF_TIMER, +- .handler = hw_tick, +-}; +- +-void hw_timer_init(void) +-{ +- volatile unsigned char *icrp; +- volatile unsigned long *imrp; +- +- setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &coldfire_pit_irq); +- +- icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 + +- MCFINTC_ICR0 + MCFINT_PIT1); +- *icrp = ICR_INTRCONF; +- +- imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR); +- *imrp &= ~MCFPIT_IMR_IBIT; +- +- /* Set up PIT timer 1 as poll clock */ +- __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); +- __raw_writew(((MCF_CLK / 2) / 64) / HZ, TA(MCFPIT_PMR)); +- __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW | +- MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); +-} +- +-/***************************************************************************/ +- +-unsigned long hw_timer_offset(void) +-{ +- volatile unsigned long *ipr; +- unsigned long pmr, pcntr, offset; +- +- ipr = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR); +- +- pmr = __raw_readw(TA(MCFPIT_PMR)); +- pcntr = __raw_readw(TA(MCFPIT_PCNTR)); +- +- /* +- * If we are still in the first half of the upcount and a +- * timer interrupt is pending, then add on a ticks worth of time. +- */ +- offset = ((pmr - pcntr) * (1000000 / HZ)) / pmr; +- if ((offset < (1000000 / HZ / 2)) && (*ipr & MCFPIT_IMR_IBIT)) +- offset += 1000000 / HZ; +- return offset; +-} +- +-/***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/5307/timers.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/5307/timers.c 2009-02-08 00:00:33.000000000 -0500 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,155 +0,0 @@ +-/***************************************************************************/ +- +-/* +- * timers.c -- generic ColdFire hardware timer support. +- * +- * Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com) +- */ +- +-/***************************************************************************/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/***************************************************************************/ +- +-/* +- * By default use timer1 as the system clock timer. +- */ +-#define TA(a) (MCF_MBAR + MCFTIMER_BASE1 + (a)) +- +-/* +- * Default the timer and vector to use for ColdFire. Some ColdFire +- * CPU's and some boards may want different. Their sub-architecture +- * startup code (in config.c) can change these if they want. +- */ +-unsigned int mcf_timervector = 29; +-unsigned int mcf_profilevector = 31; +-unsigned int mcf_timerlevel = 5; +- +-/* +- * These provide the underlying interrupt vector support. +- * Unfortunately it is a little different on each ColdFire. +- */ +-extern void mcf_settimericr(int timer, int level); +-extern int mcf_timerirqpending(int timer); +- +-#if defined(CONFIG_M532x) +-#define __raw_readtrr __raw_readl +-#define __raw_writetrr __raw_writel +-#else +-#define __raw_readtrr __raw_readw +-#define __raw_writetrr __raw_writew +-#endif +- +-/***************************************************************************/ +- +-static irqreturn_t hw_tick(int irq, void *dummy) +-{ +- /* Reset the ColdFire timer */ +- __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER)); +- +- return arch_timer_interrupt(irq, dummy); +-} +- +-/***************************************************************************/ +- +-static struct irqaction coldfire_timer_irq = { +- .name = "timer", +- .flags = IRQF_DISABLED | IRQF_TIMER, +- .handler = hw_tick, +-}; +- +-/***************************************************************************/ +- +-static int ticks_per_intr; +- +-void hw_timer_init(void) +-{ +- setup_irq(mcf_timervector, &coldfire_timer_irq); +- +- __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); +- ticks_per_intr = (MCF_BUSCLK / 16) / HZ; +- __raw_writetrr(ticks_per_intr - 1, TA(MCFTIMER_TRR)); +- __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | +- MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR)); +- +- mcf_settimericr(1, mcf_timerlevel); +- +-#ifdef CONFIG_HIGHPROFILE +- coldfire_profile_init(); +-#endif +-} +- +-/***************************************************************************/ +- +-unsigned long hw_timer_offset(void) +-{ +- unsigned long tcn, offset; +- +- tcn = __raw_readw(TA(MCFTIMER_TCN)); +- offset = ((tcn + 1) * (1000000 / HZ)) / ticks_per_intr; +- +- /* Check if we just wrapped the counters and maybe missed a tick */ +- if ((offset < (1000000 / HZ / 2)) && mcf_timerirqpending(1)) +- offset += 1000000 / HZ; +- return offset; +-} +- +-/***************************************************************************/ +-#ifdef CONFIG_HIGHPROFILE +-/***************************************************************************/ +- +-/* +- * By default use timer2 as the profiler clock timer. +- */ +-#define PA(a) (MCF_MBAR + MCFTIMER_BASE2 + (a)) +- +-/* +- * Choose a reasonably fast profile timer. Make it an odd value to +- * try and get good coverage of kernel operations. +- */ +-#define PROFILEHZ 1013 +- +-/* +- * Use the other timer to provide high accuracy profiling info. +- */ +-irqreturn_t coldfire_profile_tick(int irq, void *dummy) +-{ +- /* Reset ColdFire timer2 */ +- __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER)); +- if (current->pid) +- profile_tick(CPU_PROFILING, regs); +- return IRQ_HANDLED; +-} +- +-/***************************************************************************/ +- +-void coldfire_profile_init(void) +-{ +- printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n", PROFILEHZ); +- +- /* Set up TIMER 2 as high speed profile clock */ +- __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR)); +- +- __raw_writetrr(((MCF_CLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR)); +- __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | +- MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR)); +- +- request_irq(mcf_profilevector, coldfire_profile_tick, +- (IRQF_DISABLED | IRQ_FLG_FAST), "profile timer", NULL); +- mcf_settimericr(2, 7); +-} +- +-/***************************************************************************/ +-#endif /* CONFIG_HIGHPROFILE */ +-/***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/5307/vectors.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/5307/vectors.c 2009-02-08 00:00:33.000000000 -0500 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,105 +0,0 @@ +-/***************************************************************************/ +- +-/* +- * linux/arch/m68knommu/platform/5307/vectors.c +- * +- * Copyright (C) 1999-2007, Greg Ungerer +- */ +- +-/***************************************************************************/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/***************************************************************************/ +- +-#ifdef TRAP_DBG_INTERRUPT +- +-asmlinkage void dbginterrupt_c(struct frame *fp) +-{ +- extern void dump(struct pt_regs *fp); +- printk(KERN_DEBUG "%s(%d): BUS ERROR TRAP\n", __FILE__, __LINE__); +- dump((struct pt_regs *) fp); +- asm("halt"); +-} +- +-#endif +- +-/***************************************************************************/ +- +-extern e_vector *_ramvec; +- +-void set_evector(int vecnum, void (*handler)(void)) +-{ +- if (vecnum >= 0 && vecnum <= 255) +- _ramvec[vecnum] = handler; +-} +- +-/***************************************************************************/ +- +-/* Assembler routines */ +-asmlinkage void buserr(void); +-asmlinkage void trap(void); +-asmlinkage void system_call(void); +-asmlinkage void inthandler(void); +- +-void __init init_vectors(void) +-{ +- int i; +- +- /* +- * There is a common trap handler and common interrupt +- * handler that handle almost every vector. We treat +- * the system call and bus error special, they get their +- * own first level handlers. +- */ +- for (i = 3; (i <= 23); i++) +- _ramvec[i] = trap; +- for (i = 33; (i <= 63); i++) +- _ramvec[i] = trap; +- for (i = 24; (i <= 31); i++) +- _ramvec[i] = inthandler; +- for (i = 64; (i < 255); i++) +- _ramvec[i] = inthandler; +- _ramvec[255] = 0; +- +- _ramvec[2] = buserr; +- _ramvec[32] = system_call; +- +-#ifdef TRAP_DBG_INTERRUPT +- _ramvec[12] = dbginterrupt; +-#endif +-} +- +-/***************************************************************************/ +- +-void enable_vector(unsigned int irq) +-{ +- /* Currently no action on ColdFire */ +-} +- +-void disable_vector(unsigned int irq) +-{ +- /* Currently no action on ColdFire */ +-} +- +-void ack_vector(unsigned int irq) +-{ +- /* Currently no action on ColdFire */ +-} +- +-/***************************************************************************/ +- +-void coldfire_reset(void) +-{ +- HARD_RESET_NOW(); +-} +- +-/***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/532x/config.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/532x/config.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/532x/config.c 2009-02-08 00:00:48.000000000 -0500 +@@ -21,10 +21,11 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include ++#include + #include + #include + +@@ -38,11 +39,75 @@ extern unsigned int mcf_timerlevel; + + /***************************************************************************/ + +-/* +- * DMA channel base address table. +- */ +-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { }; +-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; ++int sys_clk_khz = 0; ++int sys_clk_mhz = 0; ++ ++void wtm_init(void); ++void scm_init(void); ++void gpio_init(void); ++void fbcs_init(void); ++void sdramc_init(void); ++int clock_pll (int fsys, int flags); ++int clock_limp (int); ++int clock_exit_limp (void); ++int get_sys_clock (void); ++ ++/***************************************************************************/ ++ ++static struct mcf_platform_uart m532x_uart_platform[] = { ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE1, ++ .irq = MCFINT_VECBASE + MCFINT_UART0, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE2, ++ .irq = MCFINT_VECBASE + MCFINT_UART1, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE3, ++ .irq = MCFINT_VECBASE + MCFINT_UART2, ++ }, ++ { }, ++}; ++ ++static struct platform_device m532x_uart = { ++ .name = "mcfuart", ++ .id = 0, ++ .dev.platform_data = m532x_uart_platform, ++}; ++ ++static struct platform_device *m532x_devices[] __initdata = { ++ &m532x_uart, ++}; ++ ++/***************************************************************************/ ++ ++static void __init m532x_uart_init_line(int line, int irq) ++{ ++ if (line == 0) { ++ MCF_INTC0_ICR26 = 0x3; ++ MCF_INTC0_CIMR = 26; ++ /* GPIO initialization */ ++ MCF_GPIO_PAR_UART |= 0x000F; ++ } else if (line == 1) { ++ MCF_INTC0_ICR27 = 0x3; ++ MCF_INTC0_CIMR = 27; ++ /* GPIO initialization */ ++ MCF_GPIO_PAR_UART |= 0x0FF0; ++ } else if (line == 2) { ++ MCF_INTC0_ICR28 = 0x3; ++ MCF_INTC0_CIMR = 28; ++ } ++} ++ ++static void __init m532x_uarts_init(void) ++{ ++ const int nrlines = ARRAY_SIZE(m532x_uart_platform); ++ int line; ++ ++ for (line = 0; (line < nrlines); line++) ++ m532x_uart_init_line(line, m532x_uart_platform[line].irq); ++} + + /***************************************************************************/ + +@@ -66,22 +131,11 @@ void mcf_settimericr(unsigned int timer, + + /***************************************************************************/ + +-int mcf_timerirqpending(int timer) ++void __init config_BSP(char *commandp, int size) + { +- unsigned int imr = 0; +- +- switch (timer) { +- case 1: imr = 0x1; break; +- case 2: imr = 0x2; break; +- default: break; +- } +- return (mcf_getiprh() & imr); +-} +- +-/***************************************************************************/ ++ sys_clk_khz = get_sys_clock(); ++ sys_clk_mhz = sys_clk_khz/1000; + +-void config_BSP(char *commandp, int size) +-{ + mcf_setimr(MCFSIM_IMR_MASKALL); + + #if !defined(CONFIG_BOOTPARAM) +@@ -99,7 +153,7 @@ void config_BSP(char *commandp, int size + mcf_profilevector = 64+33; + mach_reset = coldfire_reset; + +-#ifdef MCF_BDM_DISABLE ++#ifdef CONFIG_BDM_DISABLE + /* + * Disable the BDM clocking. This also turns off most of the rest of + * the BDM device. This is good for EMC reasons. This option is not +@@ -110,6 +164,17 @@ void config_BSP(char *commandp, int size + } + + /***************************************************************************/ ++ ++static int __init init_BSP(void) ++{ ++ m532x_uarts_init(); ++ platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices)); ++ return 0; ++} ++ ++arch_initcall(init_BSP); ++ ++/***************************************************************************/ + /* Board initialization */ + + /********************************************************************/ +@@ -152,24 +217,9 @@ void config_BSP(char *commandp, int size + + #define NAND_FLASH_ADDRESS (0xD0000000) + +-int sys_clk_khz = 0; +-int sys_clk_mhz = 0; +- +-void wtm_init(void); +-void scm_init(void); +-void gpio_init(void); +-void fbcs_init(void); +-void sdramc_init(void); +-int clock_pll (int fsys, int flags); +-int clock_limp (int); +-int clock_exit_limp (void); +-int get_sys_clock (void); + + asmlinkage void __init sysinit(void) + { +- sys_clk_khz = clock_pll(0, 0); +- sys_clk_mhz = sys_clk_khz/1000; +- + wtm_init(); + scm_init(); + gpio_init(); +@@ -207,25 +257,61 @@ void scm_init(void) + + void fbcs_init(void) + { ++#if defined(CONFIG_COBRA5329) ++ /* The COBRA5329 by senTec needs this settings */ ++ ++ /* ++ * We need to give the LCD enough bandwidth ++ */ ++ ++ MCF_XBS_PRS1 = MCF_XBS_PRIO_LCD(MCF_PRIO_LVL_1) ++ | MCF_XBS_PRIO_CORE(MCF_PRIO_LVL_2) ++ | MCF_XBS_PRIO_FEC(MCF_PRIO_LVL_3) ++ | MCF_XBS_PRIO_USBHOST(MCF_PRIO_LVL_4) ++ | MCF_XBS_PRIO_EDMA(MCF_PRIO_LVL_5) ++ | MCF_XBS_PRIO_USBOTG(MCF_PRIO_LVL_6) ++ | MCF_XBS_PRIO_FACTTEST(MCF_PRIO_LVL_7); ++ ++ /* Boot Flash connected to FBCS0 */ ++ MCF_FBCS0_CSAR = FLASH_ADDRESS; ++ MCF_FBCS0_CSCR = (MCF_FBCS_CSCR_PS_16 ++ | MCF_FBCS_CSCR_BEM ++ | MCF_FBCS_CSCR_AA ++ | MCF_FBCS_CSCR_WS(8)); ++ ++ MCF_FBCS0_CSMR = (MCF_FBCS_CSMR_BAM_1G ++ | MCF_FBCS_CSMR_V); ++ ++ /* Fix bug #10 in the errata */ ++ MCF_FBCS1_CSAR = 0xC0000000; ++ MCF_FBCS1_CSCR = (MCF_FBCS_CSCR_PS_16 ++ | MCF_FBCS_CSCR_BEM ++ | MCF_FBCS_CSCR_AA ++ | MCF_FBCS_CSCR_WS(8)); ++ ++ MCF_FBCS1_CSMR = (0x30000000 ++ | MCF_FBCS_CSMR_V ++ | MCF_FBCS_CSMR_WP ); ++#else + MCF_GPIO_PAR_CS = 0x0000003E; + + /* Latch chip select */ + MCF_FBCS1_CSAR = 0x10080000; + +- MCF_FBCS1_CSCR = 0x002A3780; ++ MCF_FBCS1_CSCR = 0x002A3580 | (MCF_FBCS1_CSCR&0x200); + MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_2M | MCF_FBCS_CSMR_V); + + /* Initialize latch to drive signals to inactive states */ +- *((u16 *)(0x10080000)) = 0xFFFF; ++ *((u16 *)(0x10080000)) = 0xD3FF; + +- /* External SRAM */ +- MCF_FBCS1_CSAR = EXT_SRAM_ADDRESS; +- MCF_FBCS1_CSCR = (MCF_FBCS_CSCR_PS_16 +- | MCF_FBCS_CSCR_AA +- | MCF_FBCS_CSCR_SBM +- | MCF_FBCS_CSCR_WS(1)); +- MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_512K +- | MCF_FBCS_CSMR_V); ++// /* External SRAM */ ++// MCF_FBCS1_CSAR = EXT_SRAM_ADDRESS; ++// MCF_FBCS1_CSCR = (MCF_FBCS_CSCR_PS_16 ++// | MCF_FBCS_CSCR_AA ++// | MCF_FBCS_CSCR_SBM ++// | MCF_FBCS_CSCR_WS(1)); ++// MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_512K ++// | MCF_FBCS_CSMR_V); + + /* Boot Flash connected to FBCS0 */ + MCF_FBCS0_CSAR = FLASH_ADDRESS; +@@ -236,6 +322,7 @@ void fbcs_init(void) + | MCF_FBCS_CSCR_WS(7)); + MCF_FBCS0_CSMR = (MCF_FBCS_CSMR_BAM_32M + | MCF_FBCS_CSMR_V); ++#endif + } + + void sdramc_init(void) +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/532x/spi-mcf532x.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/532x/spi-mcf532x.c 2009-02-08 00:00:48.000000000 -0500 +@@ -0,0 +1,176 @@ ++/***************************************************************************/ ++/* ++ * linux/arch/m68knommu/platform/532x/spi-mcf532x.c ++ * ++ * Sub-architcture dependant initialization code for the Freescale ++ * 532x SPI module ++ * ++ * Yaroslav Vinogradov yaroslav.vinogradov@freescale.com ++ * Copyright Freescale Semiconductor, Inc 2006 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++/***************************************************************************/ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SPI_NUM_CHIPSELECTS 0x04 ++#define SPI_PAR_VAL 0xFFF0 /* Enable DIN, DOUT, CLK */ ++ ++#define MCF532x_QSPI_IRQ_SOURCE (31) ++#define MCF532x_QSPI_IRQ_VECTOR (64 + MCF532x_QSPI_IRQ_SOURCE) ++ ++#define MCF532x_QSPI_PAR (0xFC0A405A) ++#define MCF532x_QSPI_QMR (0xFC05C000) ++#define MCF532x_INTC0_ICR (0xFC048040) ++#define MCF532x_INTC0_IMRL (0xFC04800C) ++ ++/* on 5329 EVB ADS7843 is connected to IRQ4 */ ++#define ADS784x_IRQ_SOURCE 4 ++#define ADS784x_IRQ_VECTOR (64+ADS784x_IRQ_SOURCE) ++#define ADS7843_IRQ_LEVEL 2 ++ ++ ++void coldfire_qspi_cs_control(u8 cs, u8 command) ++{ ++} ++ ++#if defined(CONFIG_TOUCHSCREEN_ADS7843) ++static struct coldfire_spi_chip ads784x_chip_info = { ++ .mode = SPI_MODE_0, ++ .bits_per_word = 8, ++ .del_cs_to_clk = 17, ++ .del_after_trans = 1, ++ .void_write_data = 0 ++}; ++ ++static struct ads7843_platform_data ads784x_platform_data = { ++ .model = 7843, ++ .vref_delay_usecs = 0, ++ .x_plate_ohms = 580, ++ .y_plate_ohms = 410 ++}; ++#endif ++ ++ ++static struct spi_board_info spi_board_info[] = { ++#if defined(CONFIG_TOUCHSCREEN_ADS7843) ++ { ++ .modalias = "ads7843", ++ .max_speed_hz = 125000 * 16, ++ .bus_num = 1, ++ .chip_select = 1, ++ .irq = ADS784x_IRQ_VECTOR, ++ .platform_data = &ads784x_platform_data, ++ .controller_data = &ads784x_chip_info ++ } ++#endif ++}; ++ ++static struct coldfire_spi_master coldfire_master_info = { ++ .bus_num = 1, ++ .num_chipselect = SPI_NUM_CHIPSELECTS, ++ .irq_source = MCF532x_QSPI_IRQ_SOURCE, ++ .irq_vector = MCF532x_QSPI_IRQ_VECTOR, ++ .irq_mask = (0x01 << MCF532x_QSPI_IRQ_SOURCE), ++ .irq_lp = 0x5, /* Level */ ++ .par_val = 0, /* not used on 532x */ ++ .par_val16 = SPI_PAR_VAL, ++ .cs_control = coldfire_qspi_cs_control, ++}; ++ ++static struct resource coldfire_spi_resources[] = { ++ [0] = { ++ .name = "qspi-par", ++ .start = MCF532x_QSPI_PAR, ++ .end = MCF532x_QSPI_PAR, ++ .flags = IORESOURCE_MEM ++ }, ++ ++ [1] = { ++ .name = "qspi-module", ++ .start = MCF532x_QSPI_QMR, ++ .end = MCF532x_QSPI_QMR + 0x18, ++ .flags = IORESOURCE_MEM ++ }, ++ ++ [2] = { ++ .name = "qspi-int-level", ++ .start = MCF532x_INTC0_ICR + MCF532x_QSPI_IRQ_SOURCE, ++ .end = MCF532x_INTC0_ICR + MCF532x_QSPI_IRQ_SOURCE, ++ .flags = IORESOURCE_MEM ++ }, ++ ++ [3] = { ++ .name = "qspi-int-mask", ++ .start = MCF532x_INTC0_IMRL, ++ .end = MCF532x_INTC0_IMRL, ++ .flags = IORESOURCE_MEM ++ } ++}; ++ ++static struct platform_device coldfire_spi = { ++ .name = "coldfire-qspi", ++ .id = -1, ++ .resource = coldfire_spi_resources, ++ .num_resources = ARRAY_SIZE(coldfire_spi_resources), ++ .dev = { ++ .platform_data = &coldfire_master_info, ++ } ++}; ++ ++#if defined(CONFIG_TOUCHSCREEN_ADS7843) ++static int __init init_ads7843(void) ++{ ++ /* GPIO initiaalization */ ++ MCF_GPIO_PAR_IRQ = MCF_GPIO_PAR_IRQ_PAR_IRQ4(0); ++ /* EPORT initialization */ ++ MCF_EPORT_EPPAR = MCF_EPORT_EPPAR_EPPA4(MCF_EPORT_EPPAR_FALLING); ++ MCF_EPORT_EPDDR = 0; ++ MCF_EPORT_EPIER = MCF_EPORT_EPIER_EPIE4; ++ /* enable interrupt source */ ++ MCF_INTC0_ICR4 = ADS7843_IRQ_LEVEL; ++ MCF_INTC0_CIMR = ADS784x_IRQ_SOURCE; ++} ++#endif ++ ++static int __init spi_dev_init(void) ++{ ++ int retval = 0; ++#if defined(CONFIG_TOUCHSCREEN_ADS7843) ++ init_ads7843(); ++#endif ++ ++ retval = platform_device_register(&coldfire_spi); ++ if (retval < 0) ++ goto out; ++ ++ if (ARRAY_SIZE(spi_board_info)) ++ retval = spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); ++ ++ ++out: ++ return retval; ++} ++ ++arch_initcall(spi_dev_init); +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/532x/usb-mcf532x.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/532x/usb-mcf532x.c 2009-02-08 00:00:48.000000000 -0500 +@@ -0,0 +1,171 @@ ++/*************************************************************************** ++ * usb-mcf532x.c - Platform level (mcf532x) USB initialization. ++ * ++ * Andrey Butok Andrey.Butok@freescale.com. ++ * Copyright Freescale Semiconductor, Inc 2006 ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ *************************************************************************** ++ * Changes: ++ * v0.01 31 March 2006 Andrey Butok ++ * Initial Release - developed on uClinux with 2.6.15.6 kernel ++ * ++ * WARNING: The MCF532x USB functionality was tested ++ * only with low-speed USB devices (cause of HW bugs). ++ */ ++ ++#undef DEBUG ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Start address of HC registers.*/ ++#define MCF532x_USB_HOST_REG_START (0xfc0b4000) ++/* End address of HC registers */ ++#define MCF532x_USB_HOST_REG_END (MCF532x_USB_HOST_REG_START+0x200) ++/* USB Host Interrupt number */ ++#define MCF532x_USB_HOST_INT_NUMBER (128+48) ++ ++#ifdef CONFIG_USB_OTG ++/* Start address of OTG module registers.*/ ++#define MCF532x_USB_OTG_REG_START (0xfc0b0000) ++/* End address of OTG module registers */ ++#define MCF532x_USB_OTG_REG_END (MCF532x_USB_OTG_REG_START+0x200) ++/* USB OTG Interrupt number */ ++#define MCF532x_USB_OTG_INT_NUMBER (128+47) ++#endif ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void ++usb_release(struct device *dev) ++{ ++ /* normally not freed */ ++} ++ ++/* ++ * USB Host module structures ++ */ ++static struct resource ehci_host_resources[] = { ++ { ++ .start = MCF532x_USB_HOST_REG_START, ++ .end = MCF532x_USB_HOST_REG_END, ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = MCF532x_USB_HOST_INT_NUMBER, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device ehci_host_device = { ++ .name = "ehci", ++ .id = 1, ++ .dev = { ++ .release = usb_release, ++ .dma_mask = 0x0}, ++ .num_resources = ARRAY_SIZE(ehci_host_resources), ++ .resource = ehci_host_resources, ++}; ++ ++/* ++ * USB OTG module structures. ++ */ ++#ifdef CONFIG_USB_OTG ++static struct resource ehci_otg_resources[] = { ++ { ++ .start = MCF532x_USB_OTG_REG_START, ++ .end = MCF532x_USB_OTG_REG_END, ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = MCF532x_USB_OTG_INT_NUMBER, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device ehci_otg_device = { ++ .name = "ehci", ++ .id = 0, ++ .dev = { ++ .release = usb_release, ++ .dma_mask = 0x0}, ++ .num_resources = ARRAY_SIZE(ehci_otg_resources), ++ .resource = ehci_otg_resources, ++}; ++#endif ++ ++typedef volatile u8 vuint8; /* 8 bits */ ++ ++static int __init ++mcf532x_usb_init(void) ++{ ++ int status; ++ ++ /* ++ * Initialize the clock divider for the USB: ++ */ ++#if CONFIG_CLOCK_FREQ == 240000000 ++ /* ++ * CPU oerating on 240Mhz (MISCCR[USBDIV]=1) ++ * this is the default ++ */ ++ (*(volatile u16 *) (0xFC0A0010)) |= (0x0002); ++#elif CONFIG_CLOCK_FREQ == 180000000 ++ /* ++ * CPU oerating on 180Mhz (MISCCR[USBDIV]=0) ++ */ ++ (*(volatile u16 *) (0xFC0A0010)) &= ~(0x0002); ++#else ++ #error "CLOCK must be 240MHz or 180Mhz" ++#endif ++ /* ++ * Register USB Host device: ++ */ ++ status = platform_device_register(&ehci_host_device); ++ if (status) { ++ pr_info ++ ("USB-MCF532x: Can't register MCF532x USB Host device, %d\n", ++ status); ++ return -ENODEV; ++ } ++ pr_info("USB-MCF532x: MCF532x USB Host device is registered\n"); ++ ++#ifdef CONFIG_USB_OTG ++ /* ++ * Register USB OTG device: ++ * Done only USB Host. ++ * TODO: Device and OTG functinality. ++ */ ++ status = platform_device_register(&ehci_otg_device); ++ if (status) { ++ pr_info ++ ("USB-MCF532x: Can't register MCF532x USB OTG device, %d\n", ++ status); ++ return -ENODEV; ++ } ++ pr_info("USB-MCF532x: MCF532x USB OTG device is registered\n"); ++#endif ++ ++ return 0; ++} ++ ++subsys_initcall(mcf532x_usb_init); +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/5407/config.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/5407/config.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/5407/config.c 2009-02-08 00:00:48.000000000 -0500 +@@ -13,11 +13,11 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +-#include ++#include + + /***************************************************************************/ + +@@ -29,17 +29,51 @@ extern unsigned int mcf_timerlevel; + + /***************************************************************************/ + +-/* +- * DMA channel base address table. +- */ +-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { +- MCF_MBAR + MCFDMA_BASE0, +- MCF_MBAR + MCFDMA_BASE1, +- MCF_MBAR + MCFDMA_BASE2, +- MCF_MBAR + MCFDMA_BASE3, ++static struct mcf_platform_uart m5407_uart_platform[] = { ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE1, ++ .irq = 73, ++ }, ++ { ++ .mapbase = MCF_MBAR + MCFUART_BASE2, ++ .irq = 74, ++ }, ++ { }, + }; + +-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; ++static struct platform_device m5407_uart = { ++ .name = "mcfuart", ++ .id = 0, ++ .dev.platform_data = m5407_uart_platform, ++}; ++ ++static struct platform_device *m5407_devices[] __initdata = { ++ &m5407_uart, ++}; ++ ++/***************************************************************************/ ++ ++static void __init m5407_uart_init_line(int line, int irq) ++{ ++ if (line == 0) { ++ writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); ++ writeb(irq, MCFUART_BASE1 + MCFUART_UIVR); ++ mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1); ++ } else if (line == 1) { ++ writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); ++ writeb(irq, MCFUART_BASE2 + MCFUART_UIVR); ++ mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2); ++ } ++} ++ ++static void __init m5407_uarts_init(void) ++{ ++ const int nrlines = ARRAY_SIZE(m5407_uart_platform); ++ int line; ++ ++ for (line = 0; (line < nrlines); line++) ++ m5407_uart_init_line(line, m5407_uart_platform[line].irq); ++} + + /***************************************************************************/ + +@@ -76,21 +110,7 @@ void mcf_settimericr(unsigned int timer, + + /***************************************************************************/ + +-int mcf_timerirqpending(int timer) +-{ +- unsigned int imr = 0; +- +- switch (timer) { +- case 1: imr = MCFSIM_IMR_TIMER1; break; +- case 2: imr = MCFSIM_IMR_TIMER2; break; +- default: break; +- } +- return (mcf_getipr() & imr); +-} +- +-/***************************************************************************/ +- +-void config_BSP(char *commandp, int size) ++void __init config_BSP(char *commandp, int size) + { + mcf_setimr(MCFSIM_IMR_MASKALL); + +@@ -105,3 +125,14 @@ void config_BSP(char *commandp, int size + } + + /***************************************************************************/ ++ ++static int __init init_BSP(void) ++{ ++ m5407_uarts_init(); ++ platform_add_devices(m5407_devices, ARRAY_SIZE(m5407_devices)); ++ return 0; ++} ++ ++arch_initcall(init_BSP); ++ ++/***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/68328/ints.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/68328/ints.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/68328/ints.c 2009-02-08 00:00:48.000000000 -0500 +@@ -101,6 +101,8 @@ void __init init_vectors(void) + IMR = ~0; + } + ++void do_IRQ(int irq, struct pt_regs *fp); ++ + /* The 68k family did not have a good way to determine the source + * of interrupts until later in the family. The EC000 core does + * not provide the vector number on the stack, we vector everything +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/68328/timers.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/68328/timers.c 2009-02-08 00:00:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/68328/timers.c 2009-02-08 00:00:48.000000000 -0500 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -51,6 +52,19 @@ + #define TICKS_PER_JIFFY 10 + #endif + ++static u32 m68328_tick_cnt; ++ ++/***************************************************************************/ ++ ++static irqreturn_t hw_tick(int irq, void *dummy) ++{ ++ /* Reset Timer1 */ ++ TSTAT &= 0; ++ ++ m68328_tick_cnt += TICKS_PER_JIFFY; ++ return arch_timer_interrupt(irq, dummy); ++} ++ + /***************************************************************************/ + + static irqreturn_t hw_tick(int irq, void *dummy) +@@ -69,6 +83,33 @@ static struct irqaction m68328_timer_irq + .handler = hw_tick, + }; + ++/***************************************************************************/ ++ ++static cycle_t m68328_read_clk(void) ++{ ++ unsigned long flags; ++ u32 cycles; ++ ++ local_irq_save(flags); ++ cycles = m68328_tick_cnt + TCN; ++ local_irq_restore(flags); ++ ++ return cycles; ++} ++ ++/***************************************************************************/ ++ ++static struct clocksource m68328_clk = { ++ .name = "timer", ++ .rating = 250, ++ .read = m68328_read_clk, ++ .shift = 20, ++ .mask = CLOCKSOURCE_MASK(32), ++ .flags = CLOCK_SOURCE_IS_CONTINUOUS, ++}; ++ ++/***************************************************************************/ ++ + void hw_timer_init(void) + { + /* disable timer 1 */ +@@ -84,19 +125,8 @@ void hw_timer_init(void) + + /* Enable timer 1 */ + TCTL |= TCTL_TEN; +-} +- +-/***************************************************************************/ +- +-unsigned long hw_timer_offset(void) +-{ +- unsigned long ticks = TCN, offset = 0; +- +- /* check for pending interrupt */ +- if (ticks < (TICKS_PER_JIFFY >> 1) && (ISR & (1 << TMR_IRQ_NUM))) +- offset = 1000000 / HZ; +- ticks = (ticks * 1000000 / HZ) / TICKS_PER_JIFFY; +- return ticks + offset; ++ m68328_clk.mult = clocksource_hz2mult(TICKS_PER_JIFFY*HZ, m68328_clk.shift); ++ clocksource_register(&m68328_clk); + } + + /***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/68360/config.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/68360/config.c 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/68360/config.c 2009-02-08 00:00:48.000000000 -0500 +@@ -103,11 +103,6 @@ void hw_timer_init(void) + pquicc->timer_tgcr = tgcr_save; + } + +-unsigned long hw_timer_offset(void) +-{ +- return 0; +-} +- + void BSP_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) + { +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/Makefile +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/Makefile 2009-02-08 00:00:48.000000000 -0500 +@@ -0,0 +1,32 @@ ++# ++# Makefile for the m68knommu kernel. ++# ++ ++# ++# If you want to play with the HW breakpoints then you will ++# need to add define this, which will give you a stack backtrace ++# on the console port whenever a DBG interrupt occurs. You have to ++# set up you HW breakpoints to trigger a DBG interrupt: ++# ++# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT ++# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT ++# ++ ++ifdef CONFIG_FULLDEBUG ++AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 ++endif ++ ++obj-$(CONFIG_COLDFIRE) += dma.o entry.o vectors.o ++obj-$(CONFIG_M5206) += timers.o ++obj-$(CONFIG_M5206e) += timers.o ++obj-$(CONFIG_M520x) += pit.o ++obj-$(CONFIG_M523x) += pit.o dma_timer.o irq_chip.o ++obj-$(CONFIG_M5249) += timers.o ++obj-$(CONFIG_M527x) += pit.o ++obj-$(CONFIG_M5272) += timers.o ++obj-$(CONFIG_M528x) += pit.o ++obj-$(CONFIG_M5307) += timers.o ++obj-$(CONFIG_M532x) += timers.o ++obj-$(CONFIG_M5407) += timers.o ++ ++extra-y := head.o +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/dma.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/dma.c 2009-02-08 00:00:48.000000000 -0500 +@@ -0,0 +1,39 @@ ++/***************************************************************************/ ++ ++/* ++ * dma.c -- Freescale ColdFire DMA support ++ * ++ * Copyright (C) 2007, Greg Ungerer (gerg@snapgear.com) ++ */ ++ ++/***************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/***************************************************************************/ ++ ++/* ++ * DMA channel base address table. ++ */ ++unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { ++#ifdef MCFDMA_BASE0 ++ MCF_MBAR + MCFDMA_BASE0, ++#endif ++#ifdef MCFDMA_BASE1 ++ MCF_MBAR + MCFDMA_BASE1, ++#endif ++#ifdef MCFDMA_BASE2 ++ MCF_MBAR + MCFDMA_BASE2, ++#endif ++#ifdef MCFDMA_BASE3 ++ MCF_MBAR + MCFDMA_BASE3, ++#endif ++}; ++ ++unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; ++ ++/***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/dma_timer.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/dma_timer.c 2009-02-08 00:00:48.000000000 -0500 +@@ -0,0 +1,84 @@ ++/* ++ * dma_timer.c -- Freescale ColdFire DMA Timer. ++ * ++ * Copyright (C) 2007, Benedikt Spranger ++ * Copyright (C) 2008. Sebastian Siewior, Linutronix ++ * ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define DMA_TIMER_0 (0x00) ++#define DMA_TIMER_1 (0x40) ++#define DMA_TIMER_2 (0x80) ++#define DMA_TIMER_3 (0xc0) ++ ++#define DTMR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x400) ++#define DTXMR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x402) ++#define DTER0 (MCF_IPSBAR + DMA_TIMER_0 + 0x403) ++#define DTRR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x404) ++#define DTCR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x408) ++#define DTCN0 (MCF_IPSBAR + DMA_TIMER_0 + 0x40c) ++ ++#define DMA_FREQ ((MCF_CLK / 2) / 16) ++ ++/* DTMR */ ++#define DMA_DTMR_RESTART (1 << 3) ++#define DMA_DTMR_CLK_DIV_1 (1 << 1) ++#define DMA_DTMR_CLK_DIV_16 (2 << 1) ++#define DMA_DTMR_ENABLE (1 << 0) ++ ++static cycle_t cf_dt_get_cycles(void) ++{ ++ return __raw_readl(DTCN0); ++} ++ ++static struct clocksource clocksource_cf_dt = { ++ .name = "coldfire_dma_timer", ++ .rating = 200, ++ .read = cf_dt_get_cycles, ++ .mask = CLOCKSOURCE_MASK(32), ++ .shift = 20, ++ .flags = CLOCK_SOURCE_IS_CONTINUOUS, ++}; ++ ++static int __init init_cf_dt_clocksource(void) ++{ ++ /* ++ * We setup DMA timer 0 in free run mode. This incrementing counter is ++ * used as a highly precious clock source. With MCF_CLOCK = 150 MHz we ++ * get a ~213 ns resolution and the 32bit register will overflow almost ++ * every 15 minutes. ++ */ ++ __raw_writeb(0x00, DTXMR0); ++ __raw_writeb(0x00, DTER0); ++ __raw_writel(0x00000000, DTRR0); ++ __raw_writew(DMA_DTMR_CLK_DIV_16 | DMA_DTMR_ENABLE, DTMR0); ++ clocksource_cf_dt.mult = clocksource_hz2mult(DMA_FREQ, ++ clocksource_cf_dt.shift); ++ return clocksource_register(&clocksource_cf_dt); ++} ++ ++arch_initcall(init_cf_dt_clocksource); ++ ++#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen in tsc / x86 */ ++#define CYC2NS_SCALE ((1000000 << CYC2NS_SCALE_FACTOR) / (DMA_FREQ / 1000)) ++ ++static unsigned long long cycles2ns(unsigned long cycl) ++{ ++ return (unsigned long long) ((unsigned long long)cycl * CYC2NS_SCALE) ++ >> CYC2NS_SCALE_FACTOR; ++} ++ ++unsigned long long sched_clock(void) ++{ ++ unsigned long cycl = __raw_readl(DTCN0); ++ ++ return cycles2ns(cycl); ++} +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/entry.S +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/entry.S 2009-02-08 00:00:48.000000000 -0500 +@@ -0,0 +1,241 @@ ++/* ++ * linux/arch/m68knommu/platform/5307/entry.S ++ * ++ * Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com) ++ * Copyright (C) 1998 D. Jeff Dionne , ++ * Kenneth Albanowski , ++ * Copyright (C) 2000 Lineo Inc. (www.lineo.com) ++ * Copyright (C) 2004-2006 Macq Electronique SA. (www.macqel.com) ++ * ++ * Based on: ++ * ++ * linux/arch/m68k/kernel/entry.S ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file README.legal in the main directory of this archive ++ * for more details. ++ * ++ * Linux/m68k support by Hamish Macdonald ++ * ++ * 68060 fixes by Jesper Skov ++ * ColdFire support by Greg Ungerer (gerg@snapgear.com) ++ * 5307 fixes by David W. Miller ++ * linux 2.4 support David McCullough ++ * Bug, speed and maintainability fixes by Philippe De Muyter ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++.bss ++ ++sw_ksp: ++.long 0 ++ ++sw_usp: ++.long 0 ++ ++.text ++ ++.globl system_call ++.globl resume ++.globl ret_from_exception ++.globl ret_from_signal ++.globl sys_call_table ++.globl ret_from_interrupt ++.globl inthandler ++.globl fasthandler ++ ++enosys: ++ mov.l #sys_ni_syscall,%d3 ++ bra 1f ++ ++ENTRY(system_call) ++ SAVE_ALL ++ move #0x2000,%sr /* enable intrs again */ ++ ++ cmpl #NR_syscalls,%d0 ++ jcc enosys ++ lea sys_call_table,%a0 ++ lsll #2,%d0 /* movel %a0@(%d0:l:4),%d3 */ ++ movel %a0@(%d0),%d3 ++ jeq enosys ++ ++1: ++ movel %sp,%d2 /* get thread_info pointer */ ++ andl #-THREAD_SIZE,%d2 /* at start of kernel stack */ ++ movel %d2,%a0 ++ movel %a0@,%a1 /* save top of frame */ ++ movel %sp,%a1@(TASK_THREAD+THREAD_ESP0) ++ btst #(TIF_SYSCALL_TRACE%8),%a0@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8) ++ bnes 1f ++ ++ movel %d3,%a0 ++ jbsr %a0@ ++ movel %d0,%sp@(PT_D0) /* save the return value */ ++ jra ret_from_exception ++1: ++ movel #-ENOSYS,%d2 /* strace needs -ENOSYS in PT_D0 */ ++ movel %d2,PT_D0(%sp) /* on syscall entry */ ++ subql #4,%sp ++ SAVE_SWITCH_STACK ++ jbsr syscall_trace ++ RESTORE_SWITCH_STACK ++ addql #4,%sp ++ movel %d3,%a0 ++ jbsr %a0@ ++ movel %d0,%sp@(PT_D0) /* save the return value */ ++ subql #4,%sp /* dummy return address */ ++ SAVE_SWITCH_STACK ++ jbsr syscall_trace ++ ++ret_from_signal: ++ RESTORE_SWITCH_STACK ++ addql #4,%sp ++ ++ret_from_exception: ++ move #0x2700,%sr /* disable intrs */ ++ btst #5,%sp@(PT_SR) /* check if returning to kernel */ ++ jeq Luser_return /* if so, skip resched, signals */ ++ ++#ifdef CONFIG_PREEMPT ++ movel %sp,%d1 /* get thread_info pointer */ ++ andl #-THREAD_SIZE,%d1 /* at base of kernel stack */ ++ movel %d1,%a0 ++ movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */ ++ andl #_TIF_NEED_RESCHED,%d1 ++ jeq Lkernel_return ++ ++ movel %a0@(TI_PREEMPTCOUNT),%d1 ++ cmpl #0,%d1 ++ jne Lkernel_return ++ ++ pea Lkernel_return ++ jmp preempt_schedule_irq /* preempt the kernel */ ++#endif ++ ++Lkernel_return: ++ moveml %sp@,%d1-%d5/%a0-%a2 ++ lea %sp@(32),%sp /* space for 8 regs */ ++ movel %sp@+,%d0 ++ addql #4,%sp /* orig d0 */ ++ addl %sp@+,%sp /* stk adj */ ++ rte ++ ++Luser_return: ++ movel %sp,%d1 /* get thread_info pointer */ ++ andl #-THREAD_SIZE,%d1 /* at base of kernel stack */ ++ movel %d1,%a0 ++ movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */ ++ andl #_TIF_WORK_MASK,%d1 ++ jne Lwork_to_do /* still work to do */ ++ ++Lreturn: ++ move #0x2700,%sr /* disable intrs */ ++ movel sw_usp,%a0 /* get usp */ ++ movel %sp@(PT_PC),%a0@- /* copy exception program counter */ ++ movel %sp@(PT_FORMATVEC),%a0@-/* copy exception format/vector/sr */ ++ moveml %sp@,%d1-%d5/%a0-%a2 ++ lea %sp@(32),%sp /* space for 8 regs */ ++ movel %sp@+,%d0 ++ addql #4,%sp /* orig d0 */ ++ addl %sp@+,%sp /* stk adj */ ++ addql #8,%sp /* remove exception */ ++ movel %sp,sw_ksp /* save ksp */ ++ subql #8,sw_usp /* set exception */ ++ movel sw_usp,%sp /* restore usp */ ++ rte ++ ++Lwork_to_do: ++ movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */ ++ move #0x2000,%sr /* enable intrs again */ ++ btst #TIF_NEED_RESCHED,%d1 ++ jne reschedule ++ ++ /* GERG: do we need something here for TRACEing?? */ ++ ++Lsignal_return: ++ subql #4,%sp /* dummy return address */ ++ SAVE_SWITCH_STACK ++ pea %sp@(SWITCH_STACK_SIZE) ++ clrl %sp@- ++ jsr do_signal ++ addql #8,%sp ++ RESTORE_SWITCH_STACK ++ addql #4,%sp ++ jmp Lreturn ++ ++/* ++ * This is the generic interrupt handler (for all hardware interrupt ++ * sources). Calls upto high level code to do all the work. ++ */ ++ENTRY(inthandler) ++ SAVE_ALL ++ moveq #-1,%d0 ++ movel %d0,%sp@(PT_ORIG_D0) ++ ++ movew %sp@(PT_FORMATVEC),%d0 /* put exception # in d0 */ ++ andl #0x03fc,%d0 /* mask out vector only */ ++ ++ movel %sp,%sp@- /* push regs arg */ ++ lsrl #2,%d0 /* calculate real vector # */ ++ movel %d0,%sp@- /* push vector number */ ++ jbsr do_IRQ /* call high level irq handler */ ++ lea %sp@(8),%sp /* pop args off stack */ ++ ++ bra ret_from_interrupt /* this was fallthrough */ ++ ++/* ++ * This is the fast interrupt handler (for certain hardware interrupt ++ * sources). Unlike the normal interrupt handler it just uses the ++ * current stack (doesn't care if it is user or kernel). It also ++ * doesn't bother doing the bottom half handlers. ++ */ ++ENTRY(fasthandler) ++ SAVE_LOCAL ++ ++ movew %sp@(PT_FORMATVEC),%d0 ++ andl #0x03fc,%d0 /* mask out vector only */ ++ ++ movel %sp,%sp@- /* push regs arg */ ++ lsrl #2,%d0 /* calculate real vector # */ ++ movel %d0,%sp@- /* push vector number */ ++ jbsr do_IRQ /* call high level irq handler */ ++ lea %sp@(8),%sp /* pop args off stack */ ++ ++ RESTORE_LOCAL ++ ++ENTRY(ret_from_interrupt) ++ /* the fasthandler is confusing me, haven't seen any user */ ++ jmp ret_from_exception ++ ++/* ++ * Beware - when entering resume, prev (the current task) is ++ * in a0, next (the new task) is in a1,so don't change these ++ * registers until their contents are no longer needed. ++ * This is always called in supervisor mode, so don't bother to save ++ * and restore sr; user's process sr is actually in the stack. ++ */ ++ENTRY(resume) ++ movel %a0, %d1 /* get prev thread in d1 */ ++ ++ movel sw_usp,%d0 /* save usp */ ++ movel %d0,%a0@(TASK_THREAD+THREAD_USP) ++ ++ SAVE_SWITCH_STACK ++ movel %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */ ++ movel %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */ ++ RESTORE_SWITCH_STACK ++ ++ movel %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore thread user stack */ ++ movel %a0, sw_usp ++ rts +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/head.S +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/head.S 2009-02-08 00:00:48.000000000 -0500 +@@ -0,0 +1,222 @@ ++/*****************************************************************************/ ++ ++/* ++ * head.S -- common startup code for ColdFire CPUs. ++ * ++ * (C) Copyright 1999-2006, Greg Ungerer . ++ */ ++ ++/*****************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/*****************************************************************************/ ++ ++/* ++ * If we don't have a fixed memory size, then lets build in code ++ * to auto detect the DRAM size. Obviously this is the prefered ++ * method, and should work for most boards. It won't work for those ++ * that do not have their RAM starting at address 0, and it only ++ * works on SDRAM (not boards fitted with SRAM). ++ */ ++#if CONFIG_RAMSIZE != 0 ++.macro GET_MEM_SIZE ++ movel #CONFIG_RAMSIZE,%d0 /* hard coded memory size */ ++.endm ++ ++#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \ ++ defined(CONFIG_M5249) || defined(CONFIG_M527x) || \ ++ defined(CONFIG_M528x) || defined(CONFIG_M5307) || \ ++ defined(CONFIG_M5407) ++/* ++ * Not all these devices have exactly the same DRAM controller, ++ * but the DCMR register is virtually identical - give or take ++ * a couple of bits. The only exception is the 5272 devices, their ++ * DRAM controller is quite different. ++ */ ++.macro GET_MEM_SIZE ++ movel MCF_MBAR+MCFSIM_DMR0,%d0 /* get mask for 1st bank */ ++ btst #0,%d0 /* check if region enabled */ ++ beq 1f ++ andl #0xfffc0000,%d0 ++ beq 1f ++ addl #0x00040000,%d0 /* convert mask to size */ ++1: ++ movel MCF_MBAR+MCFSIM_DMR1,%d1 /* get mask for 2nd bank */ ++ btst #0,%d1 /* check if region enabled */ ++ beq 2f ++ andl #0xfffc0000, %d1 ++ beq 2f ++ addl #0x00040000,%d1 ++ addl %d1,%d0 /* total mem size in d0 */ ++2: ++.endm ++ ++#elif defined(CONFIG_M5272) ++.macro GET_MEM_SIZE ++ movel MCF_MBAR+MCFSIM_CSOR7,%d0 /* get SDRAM address mask */ ++ andil #0xfffff000,%d0 /* mask out chip select options */ ++ negl %d0 /* negate bits */ ++.endm ++ ++#elif defined(CONFIG_M520x) ++.macro GET_MEM_SIZE ++ clrl %d0 ++ movel MCF_MBAR+MCFSIM_SDCS0, %d2 /* Get SDRAM chip select 0 config */ ++ andl #0x1f, %d2 /* Get only the chip select size */ ++ beq 3f /* Check if it is enabled */ ++ addql #1, %d2 /* Form exponent */ ++ moveql #1, %d0 ++ lsll %d2, %d0 /* 2 ^ exponent */ ++3: ++ movel MCF_MBAR+MCFSIM_SDCS1, %d2 /* Get SDRAM chip select 1 config */ ++ andl #0x1f, %d2 /* Get only the chip select size */ ++ beq 4f /* Check if it is enabled */ ++ addql #1, %d2 /* Form exponent */ ++ moveql #1, %d1 ++ lsll %d2, %d1 /* 2 ^ exponent */ ++ addl %d1, %d0 /* Total size of SDRAM in d0 */ ++4: ++.endm ++ ++#else ++#error "ERROR: I don't know how to probe your boards memory size?" ++#endif ++ ++/*****************************************************************************/ ++ ++/* ++ * Boards and platforms can do specific early hardware setup if ++ * they need to. Most don't need this, define away if not required. ++ */ ++#ifndef PLATFORM_SETUP ++#define PLATFORM_SETUP ++#endif ++ ++/*****************************************************************************/ ++ ++.global _start ++.global _rambase ++.global _ramvec ++.global _ramstart ++.global _ramend ++ ++/*****************************************************************************/ ++ ++.data ++ ++/* ++ * During startup we store away the RAM setup. These are not in the ++ * bss, since their values are determined and written before the bss ++ * has been cleared. ++ */ ++_rambase: ++.long 0 ++_ramvec: ++.long 0 ++_ramstart: ++.long 0 ++_ramend: ++.long 0 ++ ++/*****************************************************************************/ ++ ++.text ++ ++/* ++ * This is the codes first entry point. This is where it all ++ * begins... ++ */ ++ ++_start: ++ nop /* filler */ ++ movew #0x2700, %sr /* no interrupts */ ++ ++ /* ++ * Do any platform or board specific setup now. Most boards ++ * don't need anything. Those exceptions are define this in ++ * their board specific includes. ++ */ ++ PLATFORM_SETUP ++ ++ /* ++ * Create basic memory configuration. Set VBR accordingly, ++ * and size memory. ++ */ ++ movel #CONFIG_VECTORBASE,%a7 ++ movec %a7,%VBR /* set vectors addr */ ++ movel %a7,_ramvec ++ ++ movel #CONFIG_RAMBASE,%a7 /* mark the base of RAM */ ++ movel %a7,_rambase ++ ++ GET_MEM_SIZE /* macro code determines size */ ++ addl %a7,%d0 ++ movel %d0,_ramend /* set end ram addr */ ++ ++ /* ++ * Now that we know what the memory is, lets enable cache ++ * and get things moving. This is Coldfire CPU specific. ++ */ ++ CACHE_ENABLE /* enable CPU cache */ ++ ++ ++#ifdef CONFIG_ROMFS_FS ++ /* ++ * Move ROM filesystem above bss :-) ++ */ ++ lea _sbss,%a0 /* get start of bss */ ++ lea _ebss,%a1 /* set up destination */ ++ movel %a0,%a2 /* copy of bss start */ ++ ++ movel 8(%a0),%d0 /* get size of ROMFS */ ++ addql #8,%d0 /* allow for rounding */ ++ andl #0xfffffffc, %d0 /* whole words */ ++ ++ addl %d0,%a0 /* copy from end */ ++ addl %d0,%a1 /* copy from end */ ++ movel %a1,_ramstart /* set start of ram */ ++ ++_copy_romfs: ++ movel -(%a0),%d0 /* copy dword */ ++ movel %d0,-(%a1) ++ cmpl %a0,%a2 /* check if at end */ ++ bne _copy_romfs ++ ++#else /* CONFIG_ROMFS_FS */ ++ lea _ebss,%a1 ++ movel %a1,_ramstart ++#endif /* CONFIG_ROMFS_FS */ ++ ++ ++ /* ++ * Zero out the bss region. ++ */ ++ lea _sbss,%a0 /* get start of bss */ ++ lea _ebss,%a1 /* get end of bss */ ++ clrl %d0 /* set value */ ++_clear_bss: ++ movel %d0,(%a0)+ /* clear each word */ ++ cmpl %a0,%a1 /* check if at end */ ++ bne _clear_bss ++ ++ /* ++ * Load the current task pointer and stack. ++ */ ++ lea init_thread_union,%a0 ++ lea THREAD_SIZE(%a0),%sp ++ ++ /* ++ * Assember start up done, start code proper. ++ */ ++ jsr start_kernel /* start Linux kernel */ ++ ++_exit: ++ jmp _exit /* should never get here */ ++ ++/*****************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/irq_chip.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/irq_chip.c 2009-02-08 00:00:48.000000000 -0500 +@@ -0,0 +1,110 @@ ++/* ++ * IRQ-Chip implementation for Coldfire ++ * ++ * Author: Sebastian Siewior ++ */ ++ ++#include ++#include ++#include ++#include ++ ++static inline void *coldfire_irqnum_to_mem(unsigned int irq) ++{ ++ u32 imrp; ++ ++ imrp = MCF_IPSBAR; ++#if defined(MCFINT_INTC1_VECBASE) ++ if (irq > MCFINT_INTC1_VECBASE) { ++ imrp += MCFICM_INTC1; ++ irq -= MCFINT_PER_INTC; ++ } else ++#endif ++ imrp += MCFICM_INTC0; ++ ++ irq -= MCFINT_VECBASE; ++ ++ if (irq > 32) ++ imrp += MCFINTC_IMRH; ++ else ++ imrp += MCFINTC_IMRL; ++ ++ return (void *)imrp; ++} ++ ++static inline unsigned int coldfire_irqnum_to_bit(unsigned int irq) ++{ ++ irq -= MCFINT_VECBASE; ++ ++ if (irq > 32) ++ irq -= 32; ++ ++ return irq; ++} ++ ++static void coldfire_mask(unsigned int irq) ++{ ++ volatile unsigned long *imrp; ++ u32 mask; ++ u32 irq_bit; ++ ++ imrp = coldfire_irqnum_to_mem(irq); ++ irq_bit = coldfire_irqnum_to_bit(irq); ++ ++ mask = 1 << irq_bit; ++ *imrp |= mask; ++} ++ ++static void coldfire_unmask(unsigned int irq) ++{ ++ volatile unsigned long *imrp; ++ u32 mask; ++ u32 irq_bit; ++ ++ imrp = coldfire_irqnum_to_mem(irq); ++ irq_bit = coldfire_irqnum_to_bit(irq); ++ ++ mask = 1 << irq_bit; ++ *imrp &= ~mask; ++} ++ ++static void coldfire_nop(unsigned int irq) ++{ ++} ++ ++static struct irq_chip m_irq_chip = { ++ .name = "M68K-INTC", ++ .ack = coldfire_nop, ++ .mask = coldfire_mask, ++ .unmask = coldfire_unmask, ++}; ++ ++void __init coldfire_init_irq_chip(void) ++{ ++ volatile u32 *imrp; ++ volatile u8 *icrp; ++ u32 irq; ++ u32 i; ++ ++ for (irq = 0; irq < NR_IRQS; irq++) ++ set_irq_chip_and_handler_name(irq, &m_irq_chip, ++ handle_level_irq, m_irq_chip.name); ++ ++ /* setup prios for interrupt sources (first field is reserved) */ ++ icrp = (u8 *)MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0; ++ for (i = 1; i <= 63; i++) ++ icrp[i] = i; ++ ++ /* remove the disable all flag, disable all interrupt sources */ ++ imrp = coldfire_irqnum_to_mem(MCFINT_VECBASE); ++ *imrp = 0xfffffffe; ++ ++#if defined(MCFINT_INTC1_VECBASE) ++ icrp = (u8 *)MCF_IPSBAR + MCFICM_INTC1 + MCFINTC_ICR0; ++ for (i = 1; i <= 63; i++) ++ icrp[i] = i; ++ ++ imrp = coldfire_irqnum_to_mem(MCFINT_INTC1_VECBASE); ++ *imrp = 0xfffffffe; ++#endif ++} +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/pit.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/pit.c 2009-02-08 00:00:48.000000000 -0500 +@@ -0,0 +1,180 @@ ++/***************************************************************************/ ++ ++/* ++ * pit.c -- Freescale ColdFire PIT timer. Currently this type of ++ * hardware timer only exists in the Freescale ColdFire ++ * 5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire ++ * family members will probably use it too. ++ * ++ * Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com) ++ * Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com) ++ */ ++ ++/***************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/***************************************************************************/ ++ ++/* ++ * By default use timer1 as the system clock timer. ++ */ ++#define FREQ ((MCF_CLK / 2) / 64) ++#define TA(a) (MCF_IPSBAR + MCFPIT_BASE1 + (a)) ++#define INTC0 (MCF_IPSBAR + MCFICM_INTC0) ++#define PIT_CYCLES_PER_JIFFY (FREQ / HZ) ++ ++static u32 pit_cnt; ++ ++/* ++ * Initialize the PIT timer. ++ * ++ * This is also called after resume to bring the PIT into operation again. ++ */ ++ ++static void init_cf_pit_timer(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ switch (mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ ++ __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); ++ __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR)); ++ __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \ ++ MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \ ++ MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); ++ break; ++ ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ case CLOCK_EVT_MODE_UNUSED: ++ ++ __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); ++ break; ++ ++ case CLOCK_EVT_MODE_ONESHOT: ++ ++ __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); ++ __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \ ++ MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \ ++ TA(MCFPIT_PCSR)); ++ break; ++ ++ case CLOCK_EVT_MODE_RESUME: ++ /* Nothing to do here */ ++ break; ++ } ++} ++ ++/* ++ * Program the next event in oneshot mode ++ * ++ * Delta is given in PIT ticks ++ */ ++static int cf_pit_next_event(unsigned long delta, ++ struct clock_event_device *evt) ++{ ++ __raw_writew(delta, TA(MCFPIT_PMR)); ++ return 0; ++} ++ ++struct clock_event_device cf_pit_clockevent = { ++ .name = "pit", ++ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, ++ .set_mode = init_cf_pit_timer, ++ .set_next_event = cf_pit_next_event, ++ .shift = 32, ++ .irq = MCFINT_VECBASE + MCFINT_PIT1, ++}; ++ ++ ++ ++/***************************************************************************/ ++ ++static irqreturn_t pit_tick(int irq, void *dummy) ++{ ++ struct clock_event_device *evt = &cf_pit_clockevent; ++ u16 pcsr; ++ ++ /* Reset the ColdFire timer */ ++ pcsr = __raw_readw(TA(MCFPIT_PCSR)); ++ __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR)); ++ ++ pit_cnt += PIT_CYCLES_PER_JIFFY; ++ evt->event_handler(evt); ++ return IRQ_HANDLED; ++} ++ ++/***************************************************************************/ ++ ++static struct irqaction pit_irq = { ++ .name = "timer", ++ .flags = IRQF_DISABLED | IRQF_TIMER, ++ .handler = pit_tick, ++}; ++ ++/***************************************************************************/ ++ ++static cycle_t pit_read_clk(void) ++{ ++ unsigned long flags; ++ u32 cycles; ++ u16 pcntr; ++ ++ local_irq_save(flags); ++ pcntr = __raw_readw(TA(MCFPIT_PCNTR)); ++ cycles = pit_cnt; ++ local_irq_restore(flags); ++ ++ return cycles + PIT_CYCLES_PER_JIFFY - pcntr; ++} ++ ++/***************************************************************************/ ++ ++static struct clocksource pit_clk = { ++ .name = "pit", ++ .rating = 100, ++ .read = pit_read_clk, ++ .shift = 20, ++ .mask = CLOCKSOURCE_MASK(32), ++ .flags = CLOCK_SOURCE_IS_CONTINUOUS, ++}; ++ ++/***************************************************************************/ ++ ++void hw_timer_init(void) ++{ ++ u32 imr; ++ ++ cf_pit_clockevent.cpumask = cpumask_of_cpu(smp_processor_id()); ++ cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32); ++ cf_pit_clockevent.max_delta_ns = ++ clockevent_delta2ns(0xFFFF, &cf_pit_clockevent); ++ cf_pit_clockevent.min_delta_ns = ++ clockevent_delta2ns(0x3f, &cf_pit_clockevent); ++ clockevents_register_device(&cf_pit_clockevent); ++ ++ setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq); ++ ++#if !defined(CONFIG_M523x) ++ __raw_writeb(ICR_INTRCONF, INTC0 + MCFINTC_ICR0 + MCFINT_PIT1); ++ imr = __raw_readl(INTC0 + MCFPIT_IMR); ++ imr &= ~MCFPIT_IMR_IBIT; ++ __raw_writel(imr, INTC0 + MCFPIT_IMR); ++ ++#endif ++ pit_clk.mult = clocksource_hz2mult(FREQ, pit_clk.shift); ++ clocksource_register(&pit_clk); ++} ++ ++/***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/timers.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/timers.c 2009-02-08 00:00:48.000000000 -0500 +@@ -0,0 +1,182 @@ ++/***************************************************************************/ ++ ++/* ++ * timers.c -- generic ColdFire hardware timer support. ++ * ++ * Copyright (C) 1999-2008, Greg Ungerer ++ */ ++ ++/***************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/***************************************************************************/ ++ ++/* ++ * By default use timer1 as the system clock timer. ++ */ ++#define FREQ (MCF_BUSCLK / 16) ++#define TA(a) (MCF_MBAR + MCFTIMER_BASE1 + (a)) ++ ++/* ++ * Default the timer and vector to use for ColdFire. Some ColdFire ++ * CPU's and some boards may want different. Their sub-architecture ++ * startup code (in config.c) can change these if they want. ++ */ ++unsigned int mcf_timervector = 29; ++unsigned int mcf_profilevector = 31; ++unsigned int mcf_timerlevel = 5; ++ ++/* ++ * These provide the underlying interrupt vector support. ++ * Unfortunately it is a little different on each ColdFire. ++ */ ++extern void mcf_settimericr(int timer, int level); ++void coldfire_profile_init(void); ++ ++#if defined(CONFIG_M532x) ++#define __raw_readtrr __raw_readl ++#define __raw_writetrr __raw_writel ++#else ++#define __raw_readtrr __raw_readw ++#define __raw_writetrr __raw_writew ++#endif ++ ++static u32 mcftmr_cycles_per_jiffy; ++static u32 mcftmr_cnt; ++ ++/***************************************************************************/ ++ ++static irqreturn_t mcftmr_tick(int irq, void *dummy) ++{ ++ /* Reset the ColdFire timer */ ++ __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER)); ++ ++ mcftmr_cnt += mcftmr_cycles_per_jiffy; ++ return arch_timer_interrupt(irq, dummy); ++} ++ ++/***************************************************************************/ ++ ++static struct irqaction mcftmr_timer_irq = { ++ .name = "timer", ++ .flags = IRQF_DISABLED | IRQF_TIMER, ++ .handler = mcftmr_tick, ++}; ++ ++/***************************************************************************/ ++ ++static cycle_t mcftmr_read_clk(void) ++{ ++ unsigned long flags; ++ u32 cycles; ++ u16 tcn; ++ ++ local_irq_save(flags); ++ tcn = __raw_readw(TA(MCFTIMER_TCN)); ++ cycles = mcftmr_cnt; ++ local_irq_restore(flags); ++ ++ return cycles + tcn; ++} ++ ++/***************************************************************************/ ++ ++static struct clocksource mcftmr_clk = { ++ .name = "tmr", ++ .rating = 250, ++ .read = mcftmr_read_clk, ++ .shift = 20, ++ .mask = CLOCKSOURCE_MASK(32), ++ .flags = CLOCK_SOURCE_IS_CONTINUOUS, ++}; ++ ++/***************************************************************************/ ++ ++void hw_timer_init(void) ++{ ++ setup_irq(mcf_timervector, &mcftmr_timer_irq); ++ ++ __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); ++ mcftmr_cycles_per_jiffy = FREQ / HZ; ++ __raw_writetrr(mcftmr_cycles_per_jiffy, TA(MCFTIMER_TRR)); ++ __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | ++ MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR)); ++ ++ mcftmr_clk.mult = clocksource_hz2mult(FREQ, mcftmr_clk.shift); ++ clocksource_register(&mcftmr_clk); ++ ++ mcf_settimericr(1, mcf_timerlevel); ++ ++#ifdef CONFIG_HIGHPROFILE ++ coldfire_profile_init(); ++#endif ++} ++ ++/***************************************************************************/ ++#ifdef CONFIG_HIGHPROFILE ++/***************************************************************************/ ++ ++/* ++ * By default use timer2 as the profiler clock timer. ++ */ ++#define PA(a) (MCF_MBAR + MCFTIMER_BASE2 + (a)) ++ ++/* ++ * Choose a reasonably fast profile timer. Make it an odd value to ++ * try and get good coverage of kernel operations. ++ */ ++#define PROFILEHZ 1013 ++ ++/* ++ * Use the other timer to provide high accuracy profiling info. ++ */ ++irqreturn_t coldfire_profile_tick(int irq, void *dummy) ++{ ++ /* Reset ColdFire timer2 */ ++ __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER)); ++ if (current->pid) ++ profile_tick(CPU_PROFILING); ++ return IRQ_HANDLED; ++} ++ ++/***************************************************************************/ ++ ++static struct irqaction coldfire_profile_irq = { ++ .name = "profile timer", ++ .flags = IRQF_DISABLED | IRQF_TIMER, ++ .handler = coldfire_profile_tick, ++}; ++ ++void coldfire_profile_init(void) ++{ ++ printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n", ++ PROFILEHZ); ++ ++ setup_irq(mcf_profilevector, &coldfire_profile_irq); ++ ++ /* Set up TIMER 2 as high speed profile clock */ ++ __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR)); ++ ++ __raw_writetrr(((MCF_BUSCLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR)); ++ __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | ++ MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR)); ++ ++ mcf_settimericr(2, 7); ++} ++ ++/***************************************************************************/ ++#endif /* CONFIG_HIGHPROFILE */ ++/***************************************************************************/ +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/vectors.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/vectors.c 2009-02-08 00:00:48.000000000 -0500 +@@ -0,0 +1,105 @@ ++/***************************************************************************/ ++ ++/* ++ * linux/arch/m68knommu/platform/5307/vectors.c ++ * ++ * Copyright (C) 1999-2007, Greg Ungerer ++ */ ++ ++/***************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/***************************************************************************/ ++ ++#ifdef TRAP_DBG_INTERRUPT ++ ++asmlinkage void dbginterrupt_c(struct frame *fp) ++{ ++ extern void dump(struct pt_regs *fp); ++ printk(KERN_DEBUG "%s(%d): BUS ERROR TRAP\n", __FILE__, __LINE__); ++ dump((struct pt_regs *) fp); ++ asm("halt"); ++} ++ ++#endif ++ ++/***************************************************************************/ ++ ++extern e_vector *_ramvec; ++ ++void set_evector(int vecnum, void (*handler)(void)) ++{ ++ if (vecnum >= 0 && vecnum <= 255) ++ _ramvec[vecnum] = handler; ++} ++ ++/***************************************************************************/ ++ ++/* Assembler routines */ ++asmlinkage void buserr(void); ++asmlinkage void trap(void); ++asmlinkage void system_call(void); ++asmlinkage void inthandler(void); ++ ++void __init init_vectors(void) ++{ ++ int i; ++ ++ /* ++ * There is a common trap handler and common interrupt ++ * handler that handle almost every vector. We treat ++ * the system call and bus error special, they get their ++ * own first level handlers. ++ */ ++ for (i = 3; (i <= 23); i++) ++ _ramvec[i] = trap; ++ for (i = 33; (i <= 63); i++) ++ _ramvec[i] = trap; ++ for (i = 24; (i <= 31); i++) ++ _ramvec[i] = inthandler; ++ for (i = 64; (i < 255); i++) ++ _ramvec[i] = inthandler; ++ _ramvec[255] = 0; ++ ++ _ramvec[2] = buserr; ++ _ramvec[32] = system_call; ++ ++#ifdef TRAP_DBG_INTERRUPT ++ _ramvec[12] = dbginterrupt; ++#endif ++} ++ ++/***************************************************************************/ ++ ++void enable_vector(unsigned int irq) ++{ ++ /* Currently no action on ColdFire */ ++} ++ ++void disable_vector(unsigned int irq) ++{ ++ /* Currently no action on ColdFire */ ++} ++ ++void ack_vector(unsigned int irq) ++{ ++ /* Currently no action on ColdFire */ ++} ++ ++/***************************************************************************/ ++ ++void coldfire_reset(void) ++{ ++ HARD_RESET_NOW(); ++} ++ ++/***************************************************************************/ +Index: linux-2.6.24.7-rt27/drivers/net/fec.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/net/fec.c 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/net/fec.c 2009-02-08 00:00:48.000000000 -0500 +@@ -2,12 +2,6 @@ + * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * +- * This version of the driver is specific to the FADS implementation, +- * since the board contains control registers external to the processor +- * for the control of the LevelOne LXT970 transceiver. The MPC860T manual +- * describes connections using the internal parallel port I/O, which +- * is basically all of Port D. +- * + * Right now, I am very wasteful with the buffers. I allocate memory + * pages and then divide them into 2K frame buffers. This way I know I + * have buffers large enough to hold one frame within one buffer descriptor. +@@ -49,17 +43,9 @@ + #include + #include + +-#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \ +- defined(CONFIG_M5272) || defined(CONFIG_M528x) || \ +- defined(CONFIG_M520x) || defined(CONFIG_M532x) + #include + #include + #include "fec.h" +-#else +-#include +-#include +-#include "commproc.h" +-#endif + + #if defined(CONFIG_FEC2) + #define FEC_MAX_PORTS 2 +@@ -67,6 +53,7 @@ + #define FEC_MAX_PORTS 1 + #endif + ++ + /* + * Define the fixed address of the FEC hardware. + */ +@@ -79,15 +66,15 @@ static unsigned int fec_hw[] = { + #elif defined(CONFIG_M523x) || defined(CONFIG_M528x) + (MCF_MBAR + 0x1000), + #elif defined(CONFIG_M520x) +- (MCF_MBAR+0x30000), ++ (MCF_MBAR + 0x30000), + #elif defined(CONFIG_M532x) +- (MCF_MBAR+0xfc030000), ++ (MCF_MBAR + 0xfc030000), + #else +- &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec), ++ &(((immap_t *) IMAP_ADDR)->im_cpm.cp_fec), + #endif + }; + +-static unsigned char fec_mac_default[] = { ++static unsigned char fec_mac_default[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + +@@ -101,20 +88,20 @@ static unsigned char fec_mac_default[] = + #define FEC_FLASHMAC 0xf0006000 + #elif defined(CONFIG_CANCam) + #define FEC_FLASHMAC 0xf0020000 +-#elif defined (CONFIG_M5272C3) ++#elif defined(CONFIG_M5272C3) + #define FEC_FLASHMAC (0xffe04000 + 4) + #elif defined(CONFIG_MOD5272) +-#define FEC_FLASHMAC 0xffc0406b ++#define FEC_FLASHMAC 0xffc0406b + #else + #define FEC_FLASHMAC 0 + #endif + + /* Forward declarations of some structures to support different PHYs + */ +- ++typedef void (mii_func)(uint val, struct net_device *dev); + typedef struct { + uint mii_data; +- void (*funct)(uint mii_reg, struct net_device *dev); ++ mii_func *funct; + } phy_cmd_t; + + typedef struct { +@@ -165,7 +152,6 @@ typedef struct { + #define PKT_MINBUF_SIZE 64 + #define PKT_MAXBLR_SIZE 1520 + +- + /* + * The 5270/5271/5280/5282/532x RX control register also contains maximum frame + * size bits. Other FEC hardware does not, so we need to take that into +@@ -188,75 +174,67 @@ typedef struct { + */ + struct fec_enet_private { + /* Hardware registers of the FEC device */ +- volatile fec_t *hwp; ++ volatile fec_t *hwp; + + struct net_device *netdev; + + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + unsigned char *tx_bounce[TX_RING_SIZE]; +- struct sk_buff* tx_skbuff[TX_RING_SIZE]; +- ushort skb_cur; +- ushort skb_dirty; ++ struct sk_buff *tx_skbuff[TX_RING_SIZE]; ++ ushort skb_cur; ++ ushort skb_dirty; + + /* CPM dual port RAM relative addresses. +- */ +- cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ +- cbd_t *tx_bd_base; +- cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ +- cbd_t *dirty_tx; /* The ring entries to be free()ed. */ +- uint tx_full; +- spinlock_t lock; +- +- uint phy_id; +- uint phy_id_done; +- uint phy_status; +- uint phy_speed; +- phy_info_t const *phy; ++ */ ++ cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ ++ cbd_t *tx_bd_base; ++ cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ ++ cbd_t *dirty_tx; /* The ring entries to be free()ed. */ ++ uint tx_full; ++ /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */ ++ spinlock_t hw_lock; ++ /* hold while accessing the mii_list_t() elements */ ++ spinlock_t mii_lock; ++ ++ uint phy_id; ++ uint phy_id_done; ++ uint phy_status; ++ uint phy_speed; ++ phy_info_t const *phy; + struct work_struct phy_task; + +- uint sequence_done; +- uint mii_phy_task_queued; ++ uint sequence_done; ++ uint mii_phy_task_queued; ++ ++ uint phy_addr; + +- uint phy_addr; ++ int index; ++ int opened; ++ int link; ++ int old_link; ++ int full_duplex; ++}; + +- int index; +- int opened; +- int link; +- int old_link; +- int full_duplex; +-}; +- +-static int fec_enet_open(struct net_device *dev); +-static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); +-static void fec_enet_mii(struct net_device *dev); +-static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); +-static void fec_enet_tx(struct net_device *dev); +-static void fec_enet_rx(struct net_device *dev); +-static int fec_enet_close(struct net_device *dev); +-static void set_multicast_list(struct net_device *dev); + static void fec_restart(struct net_device *dev, int duplex); + static void fec_stop(struct net_device *dev); +-static void fec_set_mac_address(struct net_device *dev); +- + + /* MII processing. We keep this as simple as possible. Requests are + * placed on the list (if there is room). When the request is finished + * by the MII, an optional function may be called. + */ + typedef struct mii_list { +- uint mii_regval; +- void (*mii_func)(uint val, struct net_device *dev); +- struct mii_list *mii_next; ++ uint mii_regval; ++ void (*mii_func)(uint val, struct net_device *dev); ++ struct mii_list *mii_next; + } mii_list_t; + +-#define NMII 20 +-static mii_list_t mii_cmds[NMII]; +-static mii_list_t *mii_free; +-static mii_list_t *mii_head; +-static mii_list_t *mii_tail; ++#define NMII 20 ++static mii_list_t mii_cmds[NMII]; ++static mii_list_t *mii_free; ++static mii_list_t *mii_head; ++static mii_list_t *mii_tail; + +-static int mii_queue(struct net_device *dev, int request, +- void (*func)(uint, struct net_device *)); ++static int mii_queue(struct net_device *dev, int request, mii_func *funct); + + /* Make MII read/write commands for the FEC. + */ +@@ -272,52 +250,52 @@ static int mii_queue(struct net_device * + /* Register definitions for the PHY. + */ + +-#define MII_REG_CR 0 /* Control Register */ +-#define MII_REG_SR 1 /* Status Register */ +-#define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */ +-#define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */ +-#define MII_REG_ANAR 4 /* A-N Advertisement Register */ +-#define MII_REG_ANLPAR 5 /* A-N Link Partner Ability Register */ +-#define MII_REG_ANER 6 /* A-N Expansion Register */ +-#define MII_REG_ANNPTR 7 /* A-N Next Page Transmit Register */ +-#define MII_REG_ANLPRNPR 8 /* A-N Link Partner Received Next Page Reg. */ ++#define MII_REG_CR 0 /* Control Register */ ++#define MII_REG_SR 1 /* Status Register */ ++#define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */ ++#define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */ ++#define MII_REG_ANAR 4 /* A-N Advertisement Register */ ++#define MII_REG_ANLPAR 5 /* A-N Link Partner Ability Register */ ++#define MII_REG_ANER 6 /* A-N Expansion Register */ ++#define MII_REG_ANNPTR 7 /* A-N Next Page Transmit Register */ ++#define MII_REG_ANLPRNPR 8 /* A-N Link Partner Received Next Page Reg. */ + + /* values for phy_status */ + +-#define PHY_CONF_ANE 0x0001 /* 1 auto-negotiation enabled */ +-#define PHY_CONF_LOOP 0x0002 /* 1 loopback mode enabled */ +-#define PHY_CONF_SPMASK 0x00f0 /* mask for speed */ +-#define PHY_CONF_10HDX 0x0010 /* 10 Mbit half duplex supported */ +-#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */ +-#define PHY_CONF_100HDX 0x0040 /* 100 Mbit half duplex supported */ +-#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */ +- +-#define PHY_STAT_LINK 0x0100 /* 1 up - 0 down */ +-#define PHY_STAT_FAULT 0x0200 /* 1 remote fault */ +-#define PHY_STAT_ANC 0x0400 /* 1 auto-negotiation complete */ +-#define PHY_STAT_SPMASK 0xf000 /* mask for speed */ +-#define PHY_STAT_10HDX 0x1000 /* 10 Mbit half duplex selected */ +-#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */ +-#define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */ +-#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */ ++#define PHY_CONF_ANE 0x0001 /* 1 auto-negotiation enabled */ ++#define PHY_CONF_LOOP 0x0002 /* 1 loopback mode enabled */ ++#define PHY_CONF_SPMASK 0x00f0 /* mask for speed */ ++#define PHY_CONF_10HDX 0x0010 /* 10 Mbit half duplex supported */ ++#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */ ++#define PHY_CONF_100HDX 0x0040 /* 100 Mbit half duplex supported */ ++#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */ ++ ++#define PHY_STAT_LINK 0x0100 /* 1 up - 0 down */ ++#define PHY_STAT_FAULT 0x0200 /* 1 remote fault */ ++#define PHY_STAT_ANC 0x0400 /* 1 auto-negotiation complete */ ++#define PHY_STAT_SPMASK 0xf000 /* mask for speed */ ++#define PHY_STAT_10HDX 0x1000 /* 10 Mbit half duplex selected */ ++#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */ ++#define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */ ++#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */ + +- +-static int +-fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) ++static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct fec_enet_private *fep; +- volatile fec_t *fecp; +- volatile cbd_t *bdp; +- unsigned short status; ++ volatile fec_t *fecp; ++ volatile cbd_t *bdp; ++ unsigned short status; ++ unsigned long flags; + + fep = netdev_priv(dev); +- fecp = (volatile fec_t*)dev->base_addr; ++ fecp = (volatile fec_t *)dev->base_addr; + + if (!fep->link) { + /* Link is down or autonegotiation is in progress. */ + return 1; + } + ++ spin_lock_irqsave(&fep->hw_lock, flags); + /* Fill in a Tx ring entry */ + bdp = fep->cur_tx; + +@@ -328,6 +306,7 @@ fec_enet_start_xmit(struct sk_buff *skb, + * This should not happen, since dev->tbusy should be set. + */ + printk("%s: tx queue full!.\n", dev->name); ++ spin_unlock_irqrestore(&fep->hw_lock, flags); + return 1; + } + #endif +@@ -337,28 +316,29 @@ fec_enet_start_xmit(struct sk_buff *skb, + status &= ~BD_ENET_TX_STATS; + + /* Set buffer length and buffer pointer. +- */ ++ */ + bdp->cbd_bufaddr = __pa(skb->data); + bdp->cbd_datlen = skb->len; + + /* +- * On some FEC implementations data must be aligned on +- * 4-byte boundaries. Use bounce buffers to copy data +- * and get it aligned. Ugh. ++ * On some FEC implementations data must be aligned on ++ * 4-byte boundaries. Use bounce buffers to copy data ++ * and get it aligned. Ugh. + */ + if (bdp->cbd_bufaddr & 0x3) { + unsigned int index; + index = bdp - fep->tx_bd_base; +- memcpy(fep->tx_bounce[index], (void *) bdp->cbd_bufaddr, bdp->cbd_datlen); ++ memcpy(fep->tx_bounce[index], (void *)bdp->cbd_bufaddr, ++ bdp->cbd_datlen); + bdp->cbd_bufaddr = __pa(fep->tx_bounce[index]); + } + + /* Save skb pointer. +- */ ++ */ + fep->tx_skbuff[fep->skb_cur] = skb; + + dev->stats.tx_bytes += skb->len; +- fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; ++ fep->skb_cur = (fep->skb_cur + 1) & TX_RING_MOD_MASK; + + /* Push the data cache so the CPM does not get stale memory + * data. +@@ -366,14 +346,13 @@ fec_enet_start_xmit(struct sk_buff *skb, + flush_dcache_range((unsigned long)skb->data, + (unsigned long)skb->data + skb->len); + +- spin_lock_irq(&fep->lock); + + /* Send it on its way. Tell FEC it's ready, interrupt when done, + * it's the last BD of the frame, and to put the CRC on the end. + */ + + status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR +- | BD_ENET_TX_LAST | BD_ENET_TX_TC); ++ | BD_ENET_TX_LAST | BD_ENET_TX_TC); + bdp->cbd_sc = status; + + dev->trans_start = jiffies; +@@ -382,7 +361,7 @@ fec_enet_start_xmit(struct sk_buff *skb, + fecp->fec_x_des_active = 0; + + /* If this was the last BD in the ring, start at the beginning again. +- */ ++ */ + if (status & BD_ENET_TX_WRAP) { + bdp = fep->tx_bd_base; + } else { +@@ -394,15 +373,14 @@ fec_enet_start_xmit(struct sk_buff *skb, + netif_stop_queue(dev); + } + +- fep->cur_tx = (cbd_t *)bdp; ++ fep->cur_tx = (cbd_t *) bdp; + +- spin_unlock_irq(&fep->lock); ++ spin_unlock_irqrestore(&fep->hw_lock, flags); + + return 0; + } + +-static void +-fec_timeout(struct net_device *dev) ++static void fec_timeout(struct net_device *dev) + { + struct fec_enet_private *fep = netdev_priv(dev); + +@@ -410,115 +388,200 @@ fec_timeout(struct net_device *dev) + dev->stats.tx_errors++; + #ifndef final_version + { +- int i; +- cbd_t *bdp; ++ int i; ++ cbd_t *bdp; + +- printk("Ring data dump: cur_tx %lx%s, dirty_tx %lx cur_rx: %lx\n", +- (unsigned long)fep->cur_tx, fep->tx_full ? " (full)" : "", +- (unsigned long)fep->dirty_tx, +- (unsigned long)fep->cur_rx); ++ printk ++ ("Ring data dump: cur_tx %lx%s, dirty_tx %lx cur_rx: %lx\n", ++ (unsigned long)fep->cur_tx, fep->tx_full ? " (full)" : "", ++ (unsigned long)fep->dirty_tx, (unsigned long)fep->cur_rx); + +- bdp = fep->tx_bd_base; +- printk(" tx: %u buffers\n", TX_RING_SIZE); +- for (i = 0 ; i < TX_RING_SIZE; i++) { +- printk(" %08x: %04x %04x %08x\n", +- (uint) bdp, +- bdp->cbd_sc, +- bdp->cbd_datlen, +- (int) bdp->cbd_bufaddr); +- bdp++; +- } ++ bdp = fep->tx_bd_base; ++ printk(" tx: %u buffers\n", TX_RING_SIZE); ++ for (i = 0; i < TX_RING_SIZE; i++) { ++ printk(" %08x: %04x %04x %08x\n", ++ (uint) bdp, ++ bdp->cbd_sc, ++ bdp->cbd_datlen, (int)bdp->cbd_bufaddr); ++ bdp++; ++ } + +- bdp = fep->rx_bd_base; +- printk(" rx: %lu buffers\n", (unsigned long) RX_RING_SIZE); +- for (i = 0 ; i < RX_RING_SIZE; i++) { +- printk(" %08x: %04x %04x %08x\n", +- (uint) bdp, +- bdp->cbd_sc, +- bdp->cbd_datlen, +- (int) bdp->cbd_bufaddr); +- bdp++; +- } ++ bdp = fep->rx_bd_base; ++ printk(" rx: %lu buffers\n", (unsigned long)RX_RING_SIZE); ++ for (i = 0; i < RX_RING_SIZE; i++) { ++ printk(" %08x: %04x %04x %08x\n", ++ (uint) bdp, ++ bdp->cbd_sc, ++ bdp->cbd_datlen, (int)bdp->cbd_bufaddr); ++ bdp++; ++ } + } + #endif + fec_restart(dev, fep->full_duplex); + netif_wake_queue(dev); + } + +-/* The interrupt handler. +- * This is called from the MPC core interrupt. ++/* During a receive, the cur_rx points to the current incoming buffer. ++ * When we update through the ring, if the next incoming buffer has ++ * not been given to the system, we just set the empty indicator, ++ * effectively tossing the packet. + */ +-static irqreturn_t +-fec_enet_interrupt(int irq, void * dev_id) ++static void fec_enet_rx(struct net_device *dev) + { +- struct net_device *dev = dev_id; +- volatile fec_t *fecp; +- uint int_events; +- int handled = 0; ++ struct fec_enet_private *fep; ++ volatile fec_t *fecp; ++ volatile cbd_t *bdp; ++ unsigned short status; ++ struct sk_buff *skb; ++ ushort pkt_len; ++ __u8 *data; + +- fecp = (volatile fec_t*)dev->base_addr; ++#ifdef CONFIG_M532x ++ flush_cache_all(); ++#endif + +- /* Get the interrupt events that caused us to be here. +- */ +- while ((int_events = fecp->fec_ievent) != 0) { +- fecp->fec_ievent = int_events; ++ fep = netdev_priv(dev); ++ spin_lock_irq(&fep->hw_lock); ++ fecp = (volatile fec_t *)dev->base_addr; + +- /* Handle receive event in its own function. ++ /* First, grab all of the stats for the incoming packet. ++ * These get messed up if we get called due to a busy condition. ++ */ ++ bdp = fep->cur_rx; ++ ++ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { ++ ++#ifndef final_version ++ /* Since we have allocated space to hold a complete frame, ++ * the last indicator should be set. + */ +- if (int_events & FEC_ENET_RXF) { +- handled = 1; +- fec_enet_rx(dev); ++ if ((status & BD_ENET_RX_LAST) == 0) ++ printk("FEC ENET: rcv is not +last\n"); ++#endif ++ ++ if (!fep->opened) ++ goto rx_processing_done; ++ ++ /* Check for errors. */ ++ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | ++ BD_ENET_RX_CR | BD_ENET_RX_OV)) { ++ dev->stats.rx_errors++; ++ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { ++ /* Frame too long or too short. */ ++ dev->stats.rx_length_errors++; ++ } ++ if (status & BD_ENET_RX_NO) /* Frame alignment */ ++ dev->stats.rx_frame_errors++; ++ if (status & BD_ENET_RX_CR) /* CRC Error */ ++ dev->stats.rx_crc_errors++; ++ if (status & BD_ENET_RX_OV) /* FIFO overrun */ ++ dev->stats.rx_fifo_errors++; + } + +- /* Transmit OK, or non-fatal error. Update the buffer +- descriptors. FEC handles all errors, we just discover +- them as part of the transmit process. +- */ +- if (int_events & FEC_ENET_TXF) { +- handled = 1; +- fec_enet_tx(dev); ++ /* Report late collisions as a frame error. ++ * On this error, the BD is closed, but we don't know what we ++ * have in the buffer. So, just drop this frame on the floor. ++ */ ++ if (status & BD_ENET_RX_CL) { ++ dev->stats.rx_errors++; ++ dev->stats.rx_frame_errors++; ++ goto rx_processing_done; + } + +- if (int_events & FEC_ENET_MII) { +- handled = 1; +- fec_enet_mii(dev); ++ /* Process the incoming frame. ++ */ ++ dev->stats.rx_packets++; ++ pkt_len = bdp->cbd_datlen; ++ dev->stats.rx_bytes += pkt_len; ++ data = (__u8 *) __va(bdp->cbd_bufaddr); ++ ++ /* This does 16 byte alignment, exactly what we need. ++ * The packet length includes FCS, but we don't want to ++ * include that when passing upstream as it messes up ++ * bridging applications. ++ */ ++ skb = dev_alloc_skb(pkt_len - 4); ++ ++ if (skb == NULL) { ++ printk("%s: Memory squeeze, dropping packet.\n", ++ dev->name); ++ dev->stats.rx_dropped++; ++ } else { ++ skb_put(skb, pkt_len - 4); /* Make room */ ++ skb_copy_to_linear_data(skb, data, pkt_len - 4); ++ skb->protocol = eth_type_trans(skb, dev); ++ netif_rx(skb); + } ++rx_processing_done: + +- } +- return IRQ_RETVAL(handled); +-} ++ /* Clear the status flags for this buffer. ++ */ ++ status &= ~BD_ENET_RX_STATS; + ++ /* Mark the buffer empty. ++ */ ++ status |= BD_ENET_RX_EMPTY; ++ bdp->cbd_sc = status; + +-static void +-fec_enet_tx(struct net_device *dev) ++ /* Update BD pointer to next entry. ++ */ ++ if (status & BD_ENET_RX_WRAP) ++ bdp = fep->rx_bd_base; ++ else ++ bdp++; ++ ++#if 1 ++ /* Doing this here will keep the FEC running while we process ++ * incoming frames. On a heavily loaded network, we should be ++ * able to keep up at the expense of system resources. ++ */ ++ fecp->fec_r_des_active = 0; ++#endif ++ } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */ ++ fep->cur_rx = (cbd_t *) bdp; ++ ++#if 0 ++ /* Doing this here will allow us to process all frames in the ++ * ring before the FEC is allowed to put more there. On a heavily ++ * loaded network, some frames may be lost. Unfortunately, this ++ * increases the interrupt overhead since we can potentially work ++ * our way back to the interrupt return only to come right back ++ * here. ++ */ ++ fecp->fec_r_des_active = 0; ++#endif ++ spin_unlock_irq(&fep->hw_lock); ++} ++ ++static void fec_enet_tx(struct net_device *dev) + { +- struct fec_enet_private *fep; +- volatile cbd_t *bdp; ++ struct fec_enet_private *fep; ++ volatile cbd_t *bdp; + unsigned short status; +- struct sk_buff *skb; ++ struct sk_buff *skb; + + fep = netdev_priv(dev); +- spin_lock(&fep->lock); ++ spin_lock_irq(&fep->hw_lock); + bdp = fep->dirty_tx; + + while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { +- if (bdp == fep->cur_tx && fep->tx_full == 0) break; ++ if (bdp == fep->cur_tx && fep->tx_full == 0) ++ break; + + skb = fep->tx_skbuff[fep->skb_dirty]; + /* Check for errors. */ + if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | +- BD_ENET_TX_RL | BD_ENET_TX_UN | +- BD_ENET_TX_CSL)) { ++ BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { + dev->stats.tx_errors++; +- if (status & BD_ENET_TX_HB) /* No heartbeat */ ++ if (status & BD_ENET_TX_HB) /* No heartbeat */ + dev->stats.tx_heartbeat_errors++; +- if (status & BD_ENET_TX_LC) /* Late collision */ ++ if (status & BD_ENET_TX_LC) /* Late collision */ + dev->stats.tx_window_errors++; +- if (status & BD_ENET_TX_RL) /* Retrans limit */ ++ if (status & BD_ENET_TX_RL) /* Retrans limit */ + dev->stats.tx_aborted_errors++; +- if (status & BD_ENET_TX_UN) /* Underrun */ ++ if (status & BD_ENET_TX_UN) /* Underrun */ + dev->stats.tx_fifo_errors++; +- if (status & BD_ENET_TX_CSL) /* Carrier lost */ ++ if (status & BD_ENET_TX_CSL) /* Carrier lost */ + dev->stats.tx_carrier_errors++; + } else { + dev->stats.tx_packets++; +@@ -556,164 +619,32 @@ fec_enet_tx(struct net_device *dev) + netif_wake_queue(dev); + } + } +- fep->dirty_tx = (cbd_t *)bdp; +- spin_unlock(&fep->lock); +-} +- +- +-/* During a receive, the cur_rx points to the current incoming buffer. +- * When we update through the ring, if the next incoming buffer has +- * not been given to the system, we just set the empty indicator, +- * effectively tossing the packet. +- */ +-static void +-fec_enet_rx(struct net_device *dev) +-{ +- struct fec_enet_private *fep; +- volatile fec_t *fecp; +- volatile cbd_t *bdp; +- unsigned short status; +- struct sk_buff *skb; +- ushort pkt_len; +- __u8 *data; +- +-#ifdef CONFIG_M532x +- flush_cache_all(); +-#endif +- +- fep = netdev_priv(dev); +- fecp = (volatile fec_t*)dev->base_addr; +- +- /* First, grab all of the stats for the incoming packet. +- * These get messed up if we get called due to a busy condition. +- */ +- bdp = fep->cur_rx; +- +-while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { +- +-#ifndef final_version +- /* Since we have allocated space to hold a complete frame, +- * the last indicator should be set. +- */ +- if ((status & BD_ENET_RX_LAST) == 0) +- printk("FEC ENET: rcv is not +last\n"); +-#endif +- +- if (!fep->opened) +- goto rx_processing_done; +- +- /* Check for errors. */ +- if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | +- BD_ENET_RX_CR | BD_ENET_RX_OV)) { +- dev->stats.rx_errors++; +- if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { +- /* Frame too long or too short. */ +- dev->stats.rx_length_errors++; +- } +- if (status & BD_ENET_RX_NO) /* Frame alignment */ +- dev->stats.rx_frame_errors++; +- if (status & BD_ENET_RX_CR) /* CRC Error */ +- dev->stats.rx_crc_errors++; +- if (status & BD_ENET_RX_OV) /* FIFO overrun */ +- dev->stats.rx_fifo_errors++; +- } +- +- /* Report late collisions as a frame error. +- * On this error, the BD is closed, but we don't know what we +- * have in the buffer. So, just drop this frame on the floor. +- */ +- if (status & BD_ENET_RX_CL) { +- dev->stats.rx_errors++; +- dev->stats.rx_frame_errors++; +- goto rx_processing_done; +- } +- +- /* Process the incoming frame. +- */ +- dev->stats.rx_packets++; +- pkt_len = bdp->cbd_datlen; +- dev->stats.rx_bytes += pkt_len; +- data = (__u8*)__va(bdp->cbd_bufaddr); +- +- /* This does 16 byte alignment, exactly what we need. +- * The packet length includes FCS, but we don't want to +- * include that when passing upstream as it messes up +- * bridging applications. +- */ +- skb = dev_alloc_skb(pkt_len-4); +- +- if (skb == NULL) { +- printk("%s: Memory squeeze, dropping packet.\n", dev->name); +- dev->stats.rx_dropped++; +- } else { +- skb_put(skb,pkt_len-4); /* Make room */ +- skb_copy_to_linear_data(skb, data, pkt_len-4); +- skb->protocol=eth_type_trans(skb,dev); +- netif_rx(skb); +- } +- rx_processing_done: +- +- /* Clear the status flags for this buffer. +- */ +- status &= ~BD_ENET_RX_STATS; +- +- /* Mark the buffer empty. +- */ +- status |= BD_ENET_RX_EMPTY; +- bdp->cbd_sc = status; +- +- /* Update BD pointer to next entry. +- */ +- if (status & BD_ENET_RX_WRAP) +- bdp = fep->rx_bd_base; +- else +- bdp++; +- +-#if 1 +- /* Doing this here will keep the FEC running while we process +- * incoming frames. On a heavily loaded network, we should be +- * able to keep up at the expense of system resources. +- */ +- fecp->fec_r_des_active = 0; +-#endif +- } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */ +- fep->cur_rx = (cbd_t *)bdp; +- +-#if 0 +- /* Doing this here will allow us to process all frames in the +- * ring before the FEC is allowed to put more there. On a heavily +- * loaded network, some frames may be lost. Unfortunately, this +- * increases the interrupt overhead since we can potentially work +- * our way back to the interrupt return only to come right back +- * here. +- */ +- fecp->fec_r_des_active = 0; +-#endif ++ fep->dirty_tx = (cbd_t *) bdp; ++ spin_unlock_irq(&fep->hw_lock); + } + +- + /* called from interrupt context */ +-static void +-fec_enet_mii(struct net_device *dev) ++static void fec_enet_mii(struct net_device *dev) + { +- struct fec_enet_private *fep; +- volatile fec_t *ep; +- mii_list_t *mip; +- uint mii_reg; ++ struct fec_enet_private *fep; ++ volatile fec_t *ep; ++ mii_list_t *mip; ++ uint mii_reg; ++ mii_func *mii_func = NULL; + + fep = netdev_priv(dev); ++ spin_lock_irq(&fep->mii_lock); ++ + ep = fep->hwp; + mii_reg = ep->fec_mii_data; + +- spin_lock(&fep->lock); +- + if ((mip = mii_head) == NULL) { + printk("MII and no head!\n"); + goto unlock; + } + + if (mip->mii_func != NULL) +- (*(mip->mii_func))(mii_reg, dev); ++ mii_func = *(mip->mii_func); + + mii_head = mip->mii_next; + mip->mii_next = mii_free; +@@ -723,26 +654,71 @@ fec_enet_mii(struct net_device *dev) + ep->fec_mii_data = mip->mii_regval; + + unlock: +- spin_unlock(&fep->lock); ++ spin_unlock_irq(&fep->mii_lock); ++ if (mii_func) ++ mii_func(mii_reg, dev); + } + +-static int +-mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *)) ++/* The interrupt handler. ++ * This is called from the MPC core interrupt. ++ */ ++static irqreturn_t fec_enet_interrupt(int irq, void *dev_id) ++{ ++ struct net_device *dev = dev_id; ++ volatile fec_t *fecp; ++ uint int_events; ++ irqreturn_t ret = IRQ_NONE; ++ ++ fecp = (volatile fec_t *)dev->base_addr; ++ ++ /* Get the interrupt events that caused us to be here. ++ */ ++ do { ++ int_events = fecp->fec_ievent; ++ fecp->fec_ievent = int_events; ++ ++ /* Handle receive event in its own function. ++ */ ++ if (int_events & FEC_ENET_RXF) { ++ ret = IRQ_HANDLED; ++ fec_enet_rx(dev); ++ } ++ ++ /* Transmit OK, or non-fatal error. Update the buffer ++ descriptors. FEC handles all errors, we just discover ++ them as part of the transmit process. ++ */ ++ if (int_events & FEC_ENET_TXF) { ++ ret = IRQ_HANDLED; ++ fec_enet_tx(dev); ++ } ++ ++ if (int_events & FEC_ENET_MII) { ++ ret = IRQ_HANDLED; ++ fec_enet_mii(dev); ++ } ++ ++ } while (int_events); ++ ++ return ret; ++} ++ ++ ++static int mii_queue(struct net_device *dev, int regval, mii_func *func) + { + struct fec_enet_private *fep; +- unsigned long flags; +- mii_list_t *mip; +- int retval; ++ unsigned long flags; ++ mii_list_t *mip; ++ int retval; + + /* Add PHY address to register command. +- */ ++ */ + fep = netdev_priv(dev); +- regval |= fep->phy_addr << 23; ++ spin_lock_irqsave(&fep->mii_lock, flags); + ++ regval |= fep->phy_addr << 23; + retval = 0; + +- spin_lock_irqsave(&fep->lock,flags); +- + if ((mip = mii_free) != NULL) { + mii_free = mip->mii_next; + mip->mii_regval = regval; +@@ -759,14 +735,13 @@ mii_queue(struct net_device *dev, int re + retval = 1; + } + +- spin_unlock_irqrestore(&fep->lock,flags); +- +- return(retval); ++ spin_unlock_irqrestore(&fep->mii_lock, flags); ++ return retval; + } + + static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c) + { +- if(!c) ++ if (!c) + return; + + for (; c->mii_data != mk_mii_end; c++) +@@ -827,11 +802,11 @@ static void mii_parse_anar(uint mii_reg, + /* ------------------------------------------------------------------------- */ + /* The Level one LXT970 is used by many boards */ + +-#define MII_LXT970_MIRROR 16 /* Mirror register */ +-#define MII_LXT970_IER 17 /* Interrupt Enable Register */ +-#define MII_LXT970_ISR 18 /* Interrupt Status Register */ +-#define MII_LXT970_CONFIG 19 /* Configuration Register */ +-#define MII_LXT970_CSR 20 /* Chip Status Register */ ++#define MII_LXT970_MIRROR 16 /* Mirror register */ ++#define MII_LXT970_IER 17 /* Interrupt Enable Register */ ++#define MII_LXT970_ISR 18 /* Interrupt Status Register */ ++#define MII_LXT970_CONFIG 19 /* Configuration Register */ ++#define MII_LXT970_CSR 20 /* Chip Status Register */ + + static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev) + { +@@ -855,28 +830,28 @@ static void mii_parse_lxt970_csr(uint mi + } + + static phy_cmd_t const phy_cmd_lxt970_config[] = { +- { mk_mii_read(MII_REG_CR), mii_parse_cr }, +- { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, +- { mk_mii_end, } +- }; +-static phy_cmd_t const phy_cmd_lxt970_startup[] = { /* enable interrupts */ +- { mk_mii_write(MII_LXT970_IER, 0x0002), NULL }, +- { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ +- { mk_mii_end, } +- }; ++ {mk_mii_read(MII_REG_CR), mii_parse_cr}, ++ {mk_mii_read(MII_REG_ANAR), mii_parse_anar}, ++ {mk_mii_end,} ++}; ++static phy_cmd_t const phy_cmd_lxt970_startup[] = { /* enable interrupts */ ++ {mk_mii_write(MII_LXT970_IER, 0x0002), NULL}, ++ {mk_mii_write(MII_REG_CR, 0x1200), NULL}, /* autonegotiate */ ++ {mk_mii_end,} ++}; + static phy_cmd_t const phy_cmd_lxt970_ack_int[] = { +- /* read SR and ISR to acknowledge */ +- { mk_mii_read(MII_REG_SR), mii_parse_sr }, +- { mk_mii_read(MII_LXT970_ISR), NULL }, +- +- /* find out the current status */ +- { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr }, +- { mk_mii_end, } +- }; +-static phy_cmd_t const phy_cmd_lxt970_shutdown[] = { /* disable interrupts */ +- { mk_mii_write(MII_LXT970_IER, 0x0000), NULL }, +- { mk_mii_end, } +- }; ++ /* read SR and ISR to acknowledge */ ++ {mk_mii_read(MII_REG_SR), mii_parse_sr}, ++ {mk_mii_read(MII_LXT970_ISR), NULL}, ++ ++ /* find out the current status */ ++ {mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr}, ++ {mk_mii_end,} ++}; ++static phy_cmd_t const phy_cmd_lxt970_shutdown[] = { /* disable interrupts */ ++ {mk_mii_write(MII_LXT970_IER, 0x0000), NULL}, ++ {mk_mii_end,} ++}; + static phy_info_t const phy_info_lxt970 = { + .id = 0x07810000, + .name = "LXT970", +@@ -891,12 +866,12 @@ static phy_info_t const phy_info_lxt970 + + /* register definitions for the 971 */ + +-#define MII_LXT971_PCR 16 /* Port Control Register */ +-#define MII_LXT971_SR2 17 /* Status Register 2 */ +-#define MII_LXT971_IER 18 /* Interrupt Enable Register */ +-#define MII_LXT971_ISR 19 /* Interrupt Status Register */ +-#define MII_LXT971_LCR 20 /* LED Control Register */ +-#define MII_LXT971_TCR 30 /* Transmit Control Register */ ++#define MII_LXT971_PCR 16 /* Port Control Register */ ++#define MII_LXT971_SR2 17 /* Status Register 2 */ ++#define MII_LXT971_IER 18 /* Interrupt Enable Register */ ++#define MII_LXT971_ISR 19 /* Interrupt Status Register */ ++#define MII_LXT971_LCR 20 /* LED Control Register */ ++#define MII_LXT971_TCR 30 /* Transmit Control Register */ + + /* + * I had some nice ideas of running the MDIO faster... +@@ -938,35 +913,35 @@ static void mii_parse_lxt971_sr2(uint mi + } + + static phy_cmd_t const phy_cmd_lxt971_config[] = { +- /* limit to 10MBit because my prototype board +- * doesn't work with 100. */ +- { mk_mii_read(MII_REG_CR), mii_parse_cr }, +- { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, +- { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, +- { mk_mii_end, } +- }; +-static phy_cmd_t const phy_cmd_lxt971_startup[] = { /* enable interrupts */ +- { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL }, +- { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ +- { mk_mii_write(MII_LXT971_LCR, 0xd422), NULL }, /* LED config */ +- /* Somehow does the 971 tell me that the link is down +- * the first read after power-up. +- * read here to get a valid value in ack_int */ +- { mk_mii_read(MII_REG_SR), mii_parse_sr }, +- { mk_mii_end, } +- }; ++ /* limit to 10MBit because my prototype board ++ * doesn't work with 100. */ ++ {mk_mii_read(MII_REG_CR), mii_parse_cr}, ++ {mk_mii_read(MII_REG_ANAR), mii_parse_anar}, ++ {mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2}, ++ {mk_mii_end,} ++}; ++static phy_cmd_t const phy_cmd_lxt971_startup[] = { /* enable interrupts */ ++ {mk_mii_write(MII_LXT971_IER, 0x00f2), NULL}, ++ {mk_mii_write(MII_REG_CR, 0x1200), NULL}, /* autonegotiate */ ++ {mk_mii_write(MII_LXT971_LCR, 0xd422), NULL}, /* LED config */ ++ /* Somehow does the 971 tell me that the link is down ++ * the first read after power-up. ++ * read here to get a valid value in ack_int */ ++ {mk_mii_read(MII_REG_SR), mii_parse_sr}, ++ {mk_mii_end,} ++}; + static phy_cmd_t const phy_cmd_lxt971_ack_int[] = { +- /* acknowledge the int before reading status ! */ +- { mk_mii_read(MII_LXT971_ISR), NULL }, +- /* find out the current status */ +- { mk_mii_read(MII_REG_SR), mii_parse_sr }, +- { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, +- { mk_mii_end, } +- }; +-static phy_cmd_t const phy_cmd_lxt971_shutdown[] = { /* disable interrupts */ +- { mk_mii_write(MII_LXT971_IER, 0x0000), NULL }, +- { mk_mii_end, } +- }; ++ /* acknowledge the int before reading status ! */ ++ {mk_mii_read(MII_LXT971_ISR), NULL}, ++ /* find out the current status */ ++ {mk_mii_read(MII_REG_SR), mii_parse_sr}, ++ {mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2}, ++ {mk_mii_end,} ++}; ++static phy_cmd_t const phy_cmd_lxt971_shutdown[] = { /* disable interrupts */ ++ {mk_mii_write(MII_LXT971_IER, 0x0000), NULL}, ++ {mk_mii_end,} ++}; + static phy_info_t const phy_info_lxt971 = { + .id = 0x0001378e, + .name = "LXT971", +@@ -981,12 +956,12 @@ static phy_info_t const phy_info_lxt971 + + /* register definitions */ + +-#define MII_QS6612_MCR 17 /* Mode Control Register */ +-#define MII_QS6612_FTR 27 /* Factory Test Register */ +-#define MII_QS6612_MCO 28 /* Misc. Control Register */ +-#define MII_QS6612_ISR 29 /* Interrupt Source Register */ +-#define MII_QS6612_IMR 30 /* Interrupt Mask Register */ +-#define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */ ++#define MII_QS6612_MCR 17 /* Mode Control Register */ ++#define MII_QS6612_FTR 27 /* Factory Test Register */ ++#define MII_QS6612_MCO 28 /* Misc. Control Register */ ++#define MII_QS6612_ISR 29 /* Interrupt Source Register */ ++#define MII_QS6612_IMR 30 /* Interrupt Mask Register */ ++#define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */ + + static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev) + { +@@ -996,46 +971,54 @@ static void mii_parse_qs6612_pcr(uint mi + + status = *s & ~(PHY_STAT_SPMASK); + +- switch((mii_reg >> 2) & 7) { +- case 1: status |= PHY_STAT_10HDX; break; +- case 2: status |= PHY_STAT_100HDX; break; +- case 5: status |= PHY_STAT_10FDX; break; +- case 6: status |= PHY_STAT_100FDX; break; +-} ++ switch ((mii_reg >> 2) & 7) { ++ case 1: ++ status |= PHY_STAT_10HDX; ++ break; ++ case 2: ++ status |= PHY_STAT_100HDX; ++ break; ++ case 5: ++ status |= PHY_STAT_10FDX; ++ break; ++ case 6: ++ status |= PHY_STAT_100FDX; ++ break; ++ } + + *s = status; + } + + static phy_cmd_t const phy_cmd_qs6612_config[] = { +- /* The PHY powers up isolated on the RPX, +- * so send a command to allow operation. +- */ +- { mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL }, ++ /* The PHY powers up isolated on the RPX, ++ * so send a command to allow operation. ++ */ ++ {mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL}, + +- /* parse cr and anar to get some info */ +- { mk_mii_read(MII_REG_CR), mii_parse_cr }, +- { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, +- { mk_mii_end, } +- }; +-static phy_cmd_t const phy_cmd_qs6612_startup[] = { /* enable interrupts */ +- { mk_mii_write(MII_QS6612_IMR, 0x003a), NULL }, +- { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ +- { mk_mii_end, } +- }; ++ /* parse cr and anar to get some info */ ++ {mk_mii_read(MII_REG_CR), mii_parse_cr}, ++ {mk_mii_read(MII_REG_ANAR), mii_parse_anar}, ++ {mk_mii_end,} ++}; ++static phy_cmd_t const phy_cmd_qs6612_startup[] = { /* enable interrupts */ ++ {mk_mii_write(MII_QS6612_IMR, 0x003a), NULL}, ++ {mk_mii_write(MII_REG_CR, 0x1200), NULL}, /* autonegotiate */ ++ {mk_mii_end,} ++}; + static phy_cmd_t const phy_cmd_qs6612_ack_int[] = { +- /* we need to read ISR, SR and ANER to acknowledge */ +- { mk_mii_read(MII_QS6612_ISR), NULL }, +- { mk_mii_read(MII_REG_SR), mii_parse_sr }, +- { mk_mii_read(MII_REG_ANER), NULL }, +- +- /* read pcr to get info */ +- { mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr }, +- { mk_mii_end, } +- }; +-static phy_cmd_t const phy_cmd_qs6612_shutdown[] = { /* disable interrupts */ +- { mk_mii_write(MII_QS6612_IMR, 0x0000), NULL }, +- { mk_mii_end, } +- }; ++ /* we need to read ISR, SR and ANER to acknowledge */ ++ {mk_mii_read(MII_QS6612_ISR), NULL}, ++ {mk_mii_read(MII_REG_SR), mii_parse_sr}, ++ {mk_mii_read(MII_REG_ANER), NULL}, ++ ++ /* read pcr to get info */ ++ {mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr}, ++ {mk_mii_end,} ++}; ++static phy_cmd_t const phy_cmd_qs6612_shutdown[] = { /* disable interrupts */ ++ {mk_mii_write(MII_QS6612_IMR, 0x0000), NULL}, ++ {mk_mii_end,} ++}; + static phy_info_t const phy_info_qs6612 = { + .id = 0x00181440, + .name = "QS6612", +@@ -1050,13 +1033,13 @@ static phy_info_t const phy_info_qs6612 + + /* register definitions for the 874 */ + +-#define MII_AM79C874_MFR 16 /* Miscellaneous Feature Register */ +-#define MII_AM79C874_ICSR 17 /* Interrupt/Status Register */ +-#define MII_AM79C874_DR 18 /* Diagnostic Register */ +-#define MII_AM79C874_PMLR 19 /* Power and Loopback Register */ +-#define MII_AM79C874_MCR 21 /* ModeControl Register */ +-#define MII_AM79C874_DC 23 /* Disconnect Counter */ +-#define MII_AM79C874_REC 24 /* Recieve Error Counter */ ++#define MII_AM79C874_MFR 16 /* Miscellaneous Feature Register */ ++#define MII_AM79C874_ICSR 17 /* Interrupt/Status Register */ ++#define MII_AM79C874_DR 18 /* Diagnostic Register */ ++#define MII_AM79C874_PMLR 19 /* Power and Loopback Register */ ++#define MII_AM79C874_MCR 21 /* ModeControl Register */ ++#define MII_AM79C874_DC 23 /* Disconnect Counter */ ++#define MII_AM79C874_REC 24 /* Recieve Error Counter */ + + static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev) + { +@@ -1069,37 +1052,39 @@ static void mii_parse_am79c874_dr(uint m + if (mii_reg & 0x0080) + status |= PHY_STAT_ANC; + if (mii_reg & 0x0400) +- status |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX); ++ status |= ++ ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX); + else +- status |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX); ++ status |= ++ ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX); + + *s = status; + } + + static phy_cmd_t const phy_cmd_am79c874_config[] = { +- { mk_mii_read(MII_REG_CR), mii_parse_cr }, +- { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, +- { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr }, +- { mk_mii_end, } +- }; +-static phy_cmd_t const phy_cmd_am79c874_startup[] = { /* enable interrupts */ +- { mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL }, +- { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ +- { mk_mii_read(MII_REG_SR), mii_parse_sr }, +- { mk_mii_end, } +- }; ++ {mk_mii_read(MII_REG_CR), mii_parse_cr}, ++ {mk_mii_read(MII_REG_ANAR), mii_parse_anar}, ++ {mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr}, ++ {mk_mii_end,} ++}; ++static phy_cmd_t const phy_cmd_am79c874_startup[] = { /* enable interrupts */ ++ {mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL}, ++ {mk_mii_write(MII_REG_CR, 0x1200), NULL}, /* autonegotiate */ ++ {mk_mii_read(MII_REG_SR), mii_parse_sr}, ++ {mk_mii_end,} ++}; + static phy_cmd_t const phy_cmd_am79c874_ack_int[] = { +- /* find out the current status */ +- { mk_mii_read(MII_REG_SR), mii_parse_sr }, +- { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr }, +- /* we only need to read ISR to acknowledge */ +- { mk_mii_read(MII_AM79C874_ICSR), NULL }, +- { mk_mii_end, } +- }; +-static phy_cmd_t const phy_cmd_am79c874_shutdown[] = { /* disable interrupts */ +- { mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL }, +- { mk_mii_end, } +- }; ++ /* find out the current status */ ++ {mk_mii_read(MII_REG_SR), mii_parse_sr}, ++ {mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr}, ++ /* we only need to read ISR to acknowledge */ ++ {mk_mii_read(MII_AM79C874_ICSR), NULL}, ++ {mk_mii_end,} ++}; ++static phy_cmd_t const phy_cmd_am79c874_shutdown[] = { /* disable interrupts */ ++ {mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL}, ++ {mk_mii_end,} ++}; + static phy_info_t const phy_info_am79c874 = { + .id = 0x00022561, + .name = "AM79C874", +@@ -1109,7 +1094,6 @@ static phy_info_t const phy_info_am79c87 + .shutdown = phy_cmd_am79c874_shutdown + }; + +- + /* ------------------------------------------------------------------------- */ + /* Kendin KS8721BL phy */ + +@@ -1120,27 +1104,27 @@ static phy_info_t const phy_info_am79c87 + #define MII_KS8721BL_PHYCR 31 + + static phy_cmd_t const phy_cmd_ks8721bl_config[] = { +- { mk_mii_read(MII_REG_CR), mii_parse_cr }, +- { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, +- { mk_mii_end, } +- }; +-static phy_cmd_t const phy_cmd_ks8721bl_startup[] = { /* enable interrupts */ +- { mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL }, +- { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ +- { mk_mii_read(MII_REG_SR), mii_parse_sr }, +- { mk_mii_end, } +- }; ++ {mk_mii_read(MII_REG_CR), mii_parse_cr}, ++ {mk_mii_read(MII_REG_ANAR), mii_parse_anar}, ++ {mk_mii_end,} ++}; ++static phy_cmd_t const phy_cmd_ks8721bl_startup[] = { /* enable interrupts */ ++ {mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL}, ++ {mk_mii_write(MII_REG_CR, 0x1200), NULL}, /* autonegotiate */ ++ {mk_mii_read(MII_REG_SR), mii_parse_sr}, ++ {mk_mii_end,} ++}; + static phy_cmd_t const phy_cmd_ks8721bl_ack_int[] = { +- /* find out the current status */ +- { mk_mii_read(MII_REG_SR), mii_parse_sr }, +- /* we only need to read ISR to acknowledge */ +- { mk_mii_read(MII_KS8721BL_ICSR), NULL }, +- { mk_mii_end, } +- }; +-static phy_cmd_t const phy_cmd_ks8721bl_shutdown[] = { /* disable interrupts */ +- { mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL }, +- { mk_mii_end, } +- }; ++ /* find out the current status */ ++ {mk_mii_read(MII_REG_SR), mii_parse_sr}, ++ /* we only need to read ISR to acknowledge */ ++ {mk_mii_read(MII_KS8721BL_ICSR), NULL}, ++ {mk_mii_end,} ++}; ++static phy_cmd_t const phy_cmd_ks8721bl_shutdown[] = { /* disable interrupts */ ++ {mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL}, ++ {mk_mii_end,} ++}; + static phy_info_t const phy_info_ks8721bl = { + .id = 0x00022161, + .name = "KS8721BL", +@@ -1153,7 +1137,7 @@ static phy_info_t const phy_info_ks8721b + /* ------------------------------------------------------------------------- */ + /* register definitions for the DP83848 */ + +-#define MII_DP8384X_PHYSTST 16 /* PHY Status Register */ ++#define MII_DP8384X_PHYSTST 16 /* PHY Status Register */ + + static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev) + { +@@ -1169,15 +1153,19 @@ static void mii_parse_dp8384x_sr2(uint m + } else + fep->link = 0; + /* Status of link */ +- if (mii_reg & 0x0010) /* Autonegotioation complete */ ++ if (mii_reg & 0x0010) /* Autonegotioation complete */ + *s |= PHY_STAT_ANC; +- if (mii_reg & 0x0002) { /* 10MBps? */ +- if (mii_reg & 0x0004) /* Full Duplex? */ ++ /* 10MBps? */ ++ if (mii_reg & 0x0002) { ++ /* Full Duplex? */ ++ if (mii_reg & 0x0004) + *s |= PHY_STAT_10FDX; + else + *s |= PHY_STAT_10HDX; +- } else { /* 100 Mbps? */ +- if (mii_reg & 0x0004) /* Full Duplex? */ ++ } else { ++ /* 100 Mbps then */ ++ /* Full Duplex? */ ++ if (mii_reg & 0x0004) + *s |= PHY_STAT_100FDX; + else + *s |= PHY_STAT_100HDX; +@@ -1186,32 +1174,33 @@ static void mii_parse_dp8384x_sr2(uint m + *s |= PHY_STAT_FAULT; + } + +-static phy_info_t phy_info_dp83848= { ++static phy_info_t phy_info_dp83848 = { + 0x020005c9, + "DP83848", + +- (const phy_cmd_t []) { /* config */ +- { mk_mii_read(MII_REG_CR), mii_parse_cr }, +- { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, +- { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 }, +- { mk_mii_end, } ++ (const phy_cmd_t[]){ /* config */ ++ {mk_mii_read(MII_REG_CR), mii_parse_cr}, ++ {mk_mii_read(MII_REG_ANAR), mii_parse_anar}, ++ {mk_mii_read(MII_DP8384X_PHYSTST), ++ mii_parse_dp8384x_sr2}, ++ {mk_mii_end,} + }, +- (const phy_cmd_t []) { /* startup - enable interrupts */ +- { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ +- { mk_mii_read(MII_REG_SR), mii_parse_sr }, +- { mk_mii_end, } ++ (const phy_cmd_t[]){ /* startup - enable interrupts */ ++ {mk_mii_write(MII_REG_CR, 0x1200), NULL}, /* autonegotiate */ ++ {mk_mii_read(MII_REG_SR), mii_parse_sr}, ++ {mk_mii_end,} + }, +- (const phy_cmd_t []) { /* ack_int - never happens, no interrupt */ +- { mk_mii_end, } ++ (const phy_cmd_t[]){ /* ack_int - never happens, no interrupt */ ++ {mk_mii_end,} + }, +- (const phy_cmd_t []) { /* shutdown */ +- { mk_mii_end, } ++ (const phy_cmd_t[]){ /* shutdown */ ++ {mk_mii_end,} + }, + }; + + /* ------------------------------------------------------------------------- */ + +-static phy_info_t const * const phy_info[] = { ++static phy_info_t const *const phy_info[] = { + &phy_info_lxt970, + &phy_info_lxt971, + &phy_info_qs6612, +@@ -1221,22 +1210,38 @@ static phy_info_t const * const phy_info + NULL + }; + +-/* ------------------------------------------------------------------------- */ +-#if !defined(CONFIG_M532x) +-#ifdef CONFIG_RPXCLASSIC +-static void +-mii_link_interrupt(void *dev_id); +-#else +-static irqreturn_t +-mii_link_interrupt(int irq, void * dev_id); +-#endif ++#if defined(CONFIG_M5272) ++static void fec_phy_ack_intr(void) ++{ ++ volatile unsigned long *icrp; ++ /* Acknowledge the interrupt */ ++ icrp = (volatile unsigned long *)(MCF_MBAR + MCFSIM_ICR1); ++ *icrp = 0x0d000000; ++} ++ ++/* This interrupt occurs when the PHY detects a link change. ++*/ ++static irqreturn_t mii_link_interrupt(int irq, void *dev_id) ++{ ++ struct net_device *dev = dev_id; ++ struct fec_enet_private *fep = netdev_priv(dev); ++ ++ fec_phy_ack_intr(); ++ ++#if 0 ++ disable_irq(fep->mii_irq); /* disable now, enable later */ + #endif + +-#if defined(CONFIG_M5272) ++ mii_do_cmd(dev, fep->phy->ack_int); ++ mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ ++ ++ return IRQ_HANDLED; ++} ++ + /* + * Code specific to Coldfire 5272 setup. + */ +-static void __inline__ fec_request_intrs(struct net_device *dev) ++static void __init fec_request_intrs(struct net_device *dev) + { + volatile unsigned long *icrp; + static const struct idesc { +@@ -1244,27 +1249,36 @@ static void __inline__ fec_request_intrs + unsigned short irq; + irq_handler_t handler; + } *idp, id[] = { +- { "fec(RX)", 86, fec_enet_interrupt }, +- { "fec(TX)", 87, fec_enet_interrupt }, +- { "fec(OTHER)", 88, fec_enet_interrupt }, +- { "fec(MII)", 66, mii_link_interrupt }, +- { NULL }, ++ /* ++ * Available but not allocated because not handled: ++ * fec(OTHER) 88 ++ */ ++ { "fec(RX)", 86, fec_enet_interrupt}, ++ { "fec(TX)", 87, fec_enet_interrupt}, ++ { "fec(MII)", 66, mii_link_interrupt}, ++ { NULL, 0 }, + }; + + /* Setup interrupt handlers. */ + for (idp = id; idp->name; idp++) { +- if (request_irq(idp->irq, idp->handler, 0, idp->name, dev) != 0) +- printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, idp->irq); ++ int ret; ++ ++ ret =request_irq(idp->irq, idp->handler, IRQF_DISABLED, idp->name, ++ dev); ++ if (ret) ++ printk("FEC: Could not allocate %s IRQ(%d)!\n", ++ idp->name, idp->irq); + } + + /* Unmask interrupt at ColdFire 5272 SIM */ +- icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3); ++ icrp = (volatile unsigned long *)(MCF_MBAR + MCFSIM_ICR3); + *icrp = 0x00000ddd; +- icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); ++ icrp = (volatile unsigned long *)(MCF_MBAR + MCFSIM_ICR1); + *icrp = 0x0d000000; + } + +-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) ++static void __init fec_set_mii(struct net_device *dev, ++ struct fec_enet_private *fep) + { + volatile fec_t *fecp; + +@@ -1282,7 +1296,7 @@ static void __inline__ fec_set_mii(struc + fec_restart(dev, 0); + } + +-static void __inline__ fec_get_mac(struct net_device *dev) ++static void __init fec_get_mac(struct net_device *dev) + { + struct fec_enet_private *fep = netdev_priv(dev); + volatile fec_t *fecp; +@@ -1303,8 +1317,8 @@ static void __inline__ fec_get_mac(struc + (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) + iap = fec_mac_default; + } else { +- *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; +- *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); ++ *((unsigned long *)&tmpaddr[0]) = fecp->fec_addr_low; ++ *((unsigned short *)&tmpaddr[4]) = (fecp->fec_addr_high >> 16); + iap = &tmpaddr[0]; + } + +@@ -1312,36 +1326,29 @@ static void __inline__ fec_get_mac(struc + + /* Adjust MAC if using default MAC address */ + if (iap == fec_mac_default) +- dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; ++ dev->dev_addr[ETH_ALEN - 1] = ++ fec_mac_default[ETH_ALEN - 1] + fep->index; + } + +-static void __inline__ fec_enable_phy_intr(void) ++static void fec_enable_phy_intr(void) + { + } + +-static void __inline__ fec_disable_phy_intr(void) ++static void fec_disable_phy_intr(void) + { + volatile unsigned long *icrp; +- icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); ++ icrp = (volatile unsigned long *)(MCF_MBAR + MCFSIM_ICR1); + *icrp = 0x08000000; + } + +-static void __inline__ fec_phy_ack_intr(void) +-{ +- volatile unsigned long *icrp; +- /* Acknowledge the interrupt */ +- icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); +- *icrp = 0x0d000000; +-} +- +-static void __inline__ fec_localhw_setup(void) ++static void fec_localhw_setup(void) + { + } + + /* + * Do not need to make region uncached on 5272. + */ +-static void __inline__ fec_uncache(unsigned long addr) ++static void __init fec_uncache(unsigned long addr) + { + } + +@@ -1353,7 +1360,7 @@ static void __inline__ fec_uncache(unsig + * Code specific to Coldfire 5230/5231/5232/5234/5235, + * the 5270/5271/5274/5275 and 5280/5282 setups. + */ +-static void __inline__ fec_request_intrs(struct net_device *dev) ++static void __init fec_request_intrs(struct net_device *dev) + { + struct fec_enet_private *fep; + int b; +@@ -1361,20 +1368,16 @@ static void __inline__ fec_request_intrs + char *name; + unsigned short irq; + } *idp, id[] = { +- { "fec(TXF)", 23 }, +- { "fec(TXB)", 24 }, +- { "fec(TXFIFO)", 25 }, +- { "fec(TXCR)", 26 }, +- { "fec(RXF)", 27 }, +- { "fec(RXB)", 28 }, +- { "fec(MII)", 29 }, +- { "fec(LC)", 30 }, +- { "fec(HBERR)", 31 }, +- { "fec(GRA)", 32 }, +- { "fec(EBERR)", 33 }, +- { "fec(BABT)", 34 }, +- { "fec(BABR)", 35 }, +- { NULL }, ++ /* ++ * Available but not allocated because not handled: ++ * fec(TXB) 24, fec(TXFIFO) 25, fec(TXCR) 26, fec(RXB) 28, ++ * fec(LC) 30, fec(HBERR) 31, fec(GRA) 32, fec(EBERR) 33, ++ * fec(BABT) 34, fec(BABR), 35 ++ */ ++ { "fec(TXF)", 23}, ++ { "fec(RXF)", 27}, ++ { "fec(MII)", 29}, ++ { NULL, 0}, + }; + + fep = netdev_priv(dev); +@@ -1382,43 +1385,47 @@ static void __inline__ fec_request_intrs + + /* Setup interrupt handlers. */ + for (idp = id; idp->name; idp++) { +- if (request_irq(b+idp->irq, fec_enet_interrupt, 0, idp->name, dev) != 0) +- printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq); +- } ++ int ret; + ++ ret = request_irq(b + idp->irq, fec_enet_interrupt, IRQF_DISABLED, ++ idp->name, dev); ++ if (ret) ++ printk("FEC: Could not allocate %s IRQ(%d)!\n", ++ idp->name, b + idp->irq); ++ } ++#if defined(CONFIG_M527x) || defined(CONFIG_M528x) + /* Unmask interrupts at ColdFire 5280/5282 interrupt controller */ + { +- volatile unsigned char *icrp; +- volatile unsigned long *imrp; ++ volatile unsigned char *icrp; ++ volatile unsigned long *imrp; + int i, ilip; + + b = (fep->index) ? MCFICM_INTC1 : MCFICM_INTC0; +- icrp = (volatile unsigned char *) (MCF_IPSBAR + b + +- MCFINTC_ICR0); ++ icrp = (volatile unsigned char *)(MCF_IPSBAR + b + ++ MCFINTC_ICR0); + for (i = 23, ilip = 0x28; (i < 36); i++) + icrp[i] = ilip--; + +- imrp = (volatile unsigned long *) (MCF_IPSBAR + b + +- MCFINTC_IMRH); ++ imrp = (volatile unsigned long *)(MCF_IPSBAR + b + ++ MCFINTC_IMRH); + *imrp &= ~0x0000000f; +- imrp = (volatile unsigned long *) (MCF_IPSBAR + b + +- MCFINTC_IMRL); ++ imrp = (volatile unsigned long *)(MCF_IPSBAR + b + ++ MCFINTC_IMRL); + *imrp &= ~0xff800001; + } +- ++#endif + #if defined(CONFIG_M528x) + /* Set up gpio outputs for MII lines */ + { + volatile u16 *gpio_paspar; + volatile u8 *gpio_pehlpar; + +- gpio_paspar = (volatile u16 *) (MCF_IPSBAR + 0x100056); +- gpio_pehlpar = (volatile u16 *) (MCF_IPSBAR + 0x100058); ++ gpio_paspar = (volatile u16 *)(MCF_IPSBAR + 0x100056); ++ gpio_pehlpar = (volatile u16 *)(MCF_IPSBAR + 0x100058); + *gpio_paspar |= 0x0f00; + *gpio_pehlpar = 0xc0; + } + #endif +- + #if defined(CONFIG_M527x) + /* Set up gpio outputs for MII lines */ + { +@@ -1443,7 +1450,8 @@ static void __inline__ fec_request_intrs + #endif /* CONFIG_M527x */ + } + +-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) ++static void __init fec_set_mii(struct net_device *dev, ++ struct fec_enet_private *fep) + { + volatile fec_t *fecp; + +@@ -1461,7 +1469,7 @@ static void __inline__ fec_set_mii(struc + fec_restart(dev, 0); + } + +-static void __inline__ fec_get_mac(struct net_device *dev) ++static void __init fec_get_mac(struct net_device *dev) + { + struct fec_enet_private *fep = netdev_priv(dev); + volatile fec_t *fecp; +@@ -1482,8 +1490,8 @@ static void __inline__ fec_get_mac(struc + (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) + iap = fec_mac_default; + } else { +- *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; +- *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); ++ *((unsigned long *)&tmpaddr[0]) = fecp->fec_addr_low; ++ *((unsigned short *)&tmpaddr[4]) = (fecp->fec_addr_high >> 16); + iap = &tmpaddr[0]; + } + +@@ -1491,29 +1499,26 @@ static void __inline__ fec_get_mac(struc + + /* Adjust MAC if using default MAC address */ + if (iap == fec_mac_default) +- dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; ++ dev->dev_addr[ETH_ALEN - 1] = ++ fec_mac_default[ETH_ALEN - 1] + fep->index; + } + +-static void __inline__ fec_enable_phy_intr(void) ++static void fec_enable_phy_intr(void) + { + } + +-static void __inline__ fec_disable_phy_intr(void) ++static void fec_disable_phy_intr(void) + { + } + +-static void __inline__ fec_phy_ack_intr(void) +-{ +-} +- +-static void __inline__ fec_localhw_setup(void) ++static void fec_localhw_setup(void) + { + } + + /* + * Do not need to make region uncached on 5272. + */ +-static void __inline__ fec_uncache(unsigned long addr) ++static void __init fec_uncache(unsigned long addr) + { + } + +@@ -1524,7 +1529,7 @@ static void __inline__ fec_uncache(unsig + /* + * Code specific to Coldfire 520x + */ +-static void __inline__ fec_request_intrs(struct net_device *dev) ++static void __init fec_request_intrs(struct net_device *dev) + { + struct fec_enet_private *fep; + int b; +@@ -1532,20 +1537,16 @@ static void __inline__ fec_request_intrs + char *name; + unsigned short irq; + } *idp, id[] = { +- { "fec(TXF)", 23 }, +- { "fec(TXB)", 24 }, +- { "fec(TXFIFO)", 25 }, +- { "fec(TXCR)", 26 }, +- { "fec(RXF)", 27 }, +- { "fec(RXB)", 28 }, +- { "fec(MII)", 29 }, +- { "fec(LC)", 30 }, +- { "fec(HBERR)", 31 }, +- { "fec(GRA)", 32 }, +- { "fec(EBERR)", 33 }, +- { "fec(BABT)", 34 }, +- { "fec(BABR)", 35 }, +- { NULL }, ++ /* ++ * Available but not allocated because not handled: ++ * fec(TXB) 24, fec(TXFIFO) 25, fec(TXCR) 26, fec(RXB) 28, ++ * fec(LC) 30, fec(HBERR) 31, fec(GRA) 32, fec(EBERR) 33, ++ * fec(BABT) 34, fec(BABR) 35 ++ */ ++ { "fec(TXF)", 23}, ++ { "fec(RXF)", 27}, ++ { "fec(MII)", 29}, ++ { NULL, 0}, + }; + + fep = netdev_priv(dev); +@@ -1553,28 +1554,34 @@ static void __inline__ fec_request_intrs + + /* Setup interrupt handlers. */ + for (idp = id; idp->name; idp++) { +- if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0) +- printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq); ++ int ret; ++ ++ ret = request_irq(b + idp->irq, fec_enet_interrupt, IRQF_DISABLED, ++ idp->name, dev); ++ if (ret) ++ printk("FEC: Could not allocate %s IRQ(%d)!\n", ++ idp->name, b + idp->irq); + } + + /* Unmask interrupts at ColdFire interrupt controller */ + { +- volatile unsigned char *icrp; +- volatile unsigned long *imrp; ++ volatile unsigned char *icrp; ++ volatile unsigned long *imrp; + +- icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 + +- MCFINTC_ICR0); ++ icrp = (volatile unsigned char *)(MCF_IPSBAR + MCFICM_INTC0 + ++ MCFINTC_ICR0); + for (b = 36; (b < 49); b++) + icrp[b] = 0x04; +- imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + +- MCFINTC_IMRH); ++ imrp = (volatile unsigned long *)(MCF_IPSBAR + MCFICM_INTC0 + ++ MCFINTC_IMRH); + *imrp &= ~0x0001FFF0; + } + *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FEC) |= 0xf0; + *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C) |= 0x0f; + } + +-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) ++static void __init fec_set_mii(struct net_device *dev, ++ struct fec_enet_private *fep) + { + volatile fec_t *fecp; + +@@ -1592,7 +1599,7 @@ static void __inline__ fec_set_mii(struc + fec_restart(dev, 0); + } + +-static void __inline__ fec_get_mac(struct net_device *dev) ++static void __init fec_get_mac(struct net_device *dev) + { + struct fec_enet_private *fep = netdev_priv(dev); + volatile fec_t *fecp; +@@ -1607,14 +1614,14 @@ static void __inline__ fec_get_mac(struc + */ + iap = FEC_FLASHMAC; + if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && +- (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) ++ (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) + iap = fec_mac_default; + if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && +- (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) ++ (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) + iap = fec_mac_default; + } else { +- *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; +- *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); ++ *((unsigned long *)&tmpaddr[0]) = fecp->fec_addr_low; ++ *((unsigned short *)&tmpaddr[4]) = (fecp->fec_addr_high >> 16); + iap = &tmpaddr[0]; + } + +@@ -1622,26 +1629,23 @@ static void __inline__ fec_get_mac(struc + + /* Adjust MAC if using default MAC address */ + if (iap == fec_mac_default) +- dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; +-} +- +-static void __inline__ fec_enable_phy_intr(void) +-{ ++ dev->dev_addr[ETH_ALEN - 1] = ++ fec_mac_default[ETH_ALEN - 1] + fep->index; + } + +-static void __inline__ fec_disable_phy_intr(void) ++static void fec_enable_phy_intr(void) + { + } + +-static void __inline__ fec_phy_ack_intr(void) ++static void fec_disable_phy_intr(void) + { + } + +-static void __inline__ fec_localhw_setup(void) ++static void fec_localhw_setup(void) + { + } + +-static void __inline__ fec_uncache(unsigned long addr) ++static void __init fec_uncache(unsigned long addr) + { + } + +@@ -1651,7 +1655,7 @@ static void __inline__ fec_uncache(unsig + /* + * Code specific for M532x + */ +-static void __inline__ fec_request_intrs(struct net_device *dev) ++static void __init fec_request_intrs(struct net_device *dev) + { + struct fec_enet_private *fep; + int b; +@@ -1659,20 +1663,16 @@ static void __inline__ fec_request_intrs + char *name; + unsigned short irq; + } *idp, id[] = { +- { "fec(TXF)", 36 }, +- { "fec(TXB)", 37 }, +- { "fec(TXFIFO)", 38 }, +- { "fec(TXCR)", 39 }, +- { "fec(RXF)", 40 }, +- { "fec(RXB)", 41 }, +- { "fec(MII)", 42 }, +- { "fec(LC)", 43 }, +- { "fec(HBERR)", 44 }, +- { "fec(GRA)", 45 }, +- { "fec(EBERR)", 46 }, +- { "fec(BABT)", 47 }, +- { "fec(BABR)", 48 }, +- { NULL }, ++ /* ++ * Available but not allocated because not handled: ++ * fec(TXB) 37, fec(TXFIFO) 38, fec(TXCR) 39, fec(RXB) 41, ++ * fec(LC) 43, fec(HBERR) 44, fec(GRA) 45, fec(EBERR) 46, ++ * fec(BABT) 47, fec(BABR) 48 ++ */ ++ { "fec(TXF)", 36}, ++ { "fec(RXF)", 40}, ++ { "fec(MII)", 42}, ++ { NULL, 0}, + }; + + fep = netdev_priv(dev); +@@ -1680,9 +1680,13 @@ static void __inline__ fec_request_intrs + + /* Setup interrupt handlers. */ + for (idp = id; idp->name; idp++) { +- if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0) +- printk("FEC: Could not allocate %s IRQ(%d)!\n", +- idp->name, b+idp->irq); ++ int ret; ++ ++ ret = request_irq(b + idp->irq, fec_enet_interrupt, IRQF_DISABLED, ++ idp->name, dev); ++ if (ret) ++ printk("FEC: Could not allocate %s IRQ(%d)!\n", ++ idp->name, b + idp->irq); + } + + /* Unmask interrupts */ +@@ -1700,31 +1704,31 @@ static void __inline__ fec_request_intrs + MCF_INTC0_ICR47 = 0x2; + MCF_INTC0_ICR48 = 0x2; + +- MCF_INTC0_IMRH &= ~( +- MCF_INTC_IMRH_INT_MASK36 | +- MCF_INTC_IMRH_INT_MASK37 | +- MCF_INTC_IMRH_INT_MASK38 | +- MCF_INTC_IMRH_INT_MASK39 | +- MCF_INTC_IMRH_INT_MASK40 | +- MCF_INTC_IMRH_INT_MASK41 | +- MCF_INTC_IMRH_INT_MASK42 | +- MCF_INTC_IMRH_INT_MASK43 | +- MCF_INTC_IMRH_INT_MASK44 | +- MCF_INTC_IMRH_INT_MASK45 | +- MCF_INTC_IMRH_INT_MASK46 | +- MCF_INTC_IMRH_INT_MASK47 | +- MCF_INTC_IMRH_INT_MASK48 ); ++ MCF_INTC0_IMRH &= ~(MCF_INTC_IMRH_INT_MASK36 | ++ MCF_INTC_IMRH_INT_MASK37 | ++ MCF_INTC_IMRH_INT_MASK38 | ++ MCF_INTC_IMRH_INT_MASK39 | ++ MCF_INTC_IMRH_INT_MASK40 | ++ MCF_INTC_IMRH_INT_MASK41 | ++ MCF_INTC_IMRH_INT_MASK42 | ++ MCF_INTC_IMRH_INT_MASK43 | ++ MCF_INTC_IMRH_INT_MASK44 | ++ MCF_INTC_IMRH_INT_MASK45 | ++ MCF_INTC_IMRH_INT_MASK46 | ++ MCF_INTC_IMRH_INT_MASK47 | ++ MCF_INTC_IMRH_INT_MASK48); + + /* Set up gpio outputs for MII lines */ + MCF_GPIO_PAR_FECI2C |= (0 | +- MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC | +- MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO); ++ MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC | ++ MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO); + MCF_GPIO_PAR_FEC = (0 | +- MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC | +- MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC); ++ MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC | ++ MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC); + } + +-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) ++static void __init fec_set_mii(struct net_device *dev, ++ struct fec_enet_private *fep) + { + volatile fec_t *fecp; + +@@ -1741,7 +1745,7 @@ static void __inline__ fec_set_mii(struc + fec_restart(dev, 0); + } + +-static void __inline__ fec_get_mac(struct net_device *dev) ++static void __init fec_get_mac(struct net_device *dev) + { + struct fec_enet_private *fep = netdev_priv(dev); + volatile fec_t *fecp; +@@ -1762,8 +1766,8 @@ static void __inline__ fec_get_mac(struc + (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) + iap = fec_mac_default; + } else { +- *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; +- *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); ++ *((unsigned long *)&tmpaddr[0]) = fecp->fec_addr_low; ++ *((unsigned short *)&tmpaddr[4]) = (fecp->fec_addr_high >> 16); + iap = &tmpaddr[0]; + } + +@@ -1771,143 +1775,109 @@ static void __inline__ fec_get_mac(struc + + /* Adjust MAC if using default MAC address */ + if (iap == fec_mac_default) +- dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; +-} +- +-static void __inline__ fec_enable_phy_intr(void) +-{ ++ dev->dev_addr[ETH_ALEN - 1] = ++ fec_mac_default[ETH_ALEN - 1] + fep->index; + } + +-static void __inline__ fec_disable_phy_intr(void) ++static void fec_enable_phy_intr(void) + { + } + +-static void __inline__ fec_phy_ack_intr(void) ++static void fec_disable_phy_intr(void) + { + } + +-static void __inline__ fec_localhw_setup(void) ++static void fec_localhw_setup(void) + { + } + + /* + * Do not need to make region uncached on 532x. + */ +-static void __inline__ fec_uncache(unsigned long addr) ++static void __init fec_uncache(unsigned long addr) + { + } + + /* ------------------------------------------------------------------------- */ + +- + #else + + /* + * Code specific to the MPC860T setup. + */ +-static void __inline__ fec_request_intrs(struct net_device *dev) ++static void __init fec_request_intrs(struct net_device *dev) + { + volatile immap_t *immap; + +- immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ ++ immap = (immap_t *) IMAP_ADDR; /* pointer to internal registers */ + +- if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0) ++ if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != ++ 0) + panic("Could not allocate FEC IRQ!"); +- +-#ifdef CONFIG_RPXCLASSIC +- /* Make Port C, bit 15 an input that causes interrupts. +- */ +- immap->im_ioport.iop_pcpar &= ~0x0001; +- immap->im_ioport.iop_pcdir &= ~0x0001; +- immap->im_ioport.iop_pcso &= ~0x0001; +- immap->im_ioport.iop_pcint |= 0x0001; +- cpm_install_handler(CPMVEC_PIO_PC15, mii_link_interrupt, dev); +- +- /* Make LEDS reflect Link status. +- */ +- *((uint *) RPX_CSR_ADDR) &= ~BCSR2_FETHLEDMODE; +-#endif +-#ifdef CONFIG_FADS +- if (request_8xxirq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0) +- panic("Could not allocate MII IRQ!"); +-#endif + } + +-static void __inline__ fec_get_mac(struct net_device *dev) ++static void __init fec_get_mac(struct net_device *dev) + { + bd_t *bd; + +- bd = (bd_t *)__res; ++ bd = (bd_t *) __res; + memcpy(dev->dev_addr, bd->bi_enetaddr, ETH_ALEN); +- +-#ifdef CONFIG_RPXCLASSIC +- /* The Embedded Planet boards have only one MAC address in +- * the EEPROM, but can have two Ethernet ports. For the +- * FEC port, we create another address by setting one of +- * the address bits above something that would have (up to +- * now) been allocated. +- */ +- dev->dev_adrd[3] |= 0x80; +-#endif + } + +-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) ++static void __init fec_set_mii(struct net_device *dev, ++ struct fec_enet_private *fep) + { + extern uint _get_IMMR(void); + volatile immap_t *immap; + volatile fec_t *fecp; + + fecp = fep->hwp; +- immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ ++ immap = (immap_t *) IMAP_ADDR; /* pointer to internal registers */ + + /* Configure all of port D for MII. +- */ ++ */ + immap->im_ioport.iop_pdpar = 0x1fff; + + /* Bits moved from Rev. D onward. +- */ ++ */ + if ((_get_IMMR() & 0xffff) < 0x0501) + immap->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */ + else + immap->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */ + + /* Set MII speed to 2.5 MHz +- */ ++ */ + fecp->fec_mii_speed = fep->phy_speed = +- ((bd->bi_busfreq * 1000000) / 2500000) & 0x7e; ++ ((bd->bi_busfreq * 1000000) / 2500000) & 0x7e; + } + +-static void __inline__ fec_enable_phy_intr(void) ++static void fec_enable_phy_intr(void) + { + volatile fec_t *fecp; + + fecp = fep->hwp; + + /* Enable MII command finished interrupt +- */ +- fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; +-} +- +-static void __inline__ fec_disable_phy_intr(void) +-{ ++ */ ++ fecp->fec_ivec = (FEC_INTERRUPT / 2) << 29; + } + +-static void __inline__ fec_phy_ack_intr(void) ++static void fec_disable_phy_intr(void) + { + } + +-static void __inline__ fec_localhw_setup(void) ++static void fec_localhw_setup(void) + { + volatile fec_t *fecp; + + fecp = fep->hwp; + fecp->fec_r_hash = PKT_MAXBUF_SIZE; + /* Enable big endian and don't care about SDMA FC. +- */ ++ */ + fecp->fec_fun_code = 0x78000000; + } + +-static void __inline__ fec_uncache(unsigned long addr) ++static void __init fec_uncache(unsigned long addr) + { + pte_t *pte; + pte = va_to_pte(mem_addr); +@@ -1936,11 +1906,19 @@ static void mii_display_status(struct ne + } else { + printk("link up"); + +- switch(*s & PHY_STAT_SPMASK) { +- case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break; +- case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break; +- case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break; +- case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break; ++ switch (*s & PHY_STAT_SPMASK) { ++ case PHY_STAT_100FDX: ++ printk(", 100MBit Full Duplex"); ++ break; ++ case PHY_STAT_100HDX: ++ printk(", 100MBit Half Duplex"); ++ break; ++ case PHY_STAT_10FDX: ++ printk(", 10MBit Full Duplex"); ++ break; ++ case PHY_STAT_10HDX: ++ printk(", 10MBit Half Duplex"); ++ break; + default: + printk(", Unknown speed/duplex"); + } +@@ -1957,14 +1935,15 @@ static void mii_display_status(struct ne + + static void mii_display_config(struct work_struct *work) + { +- struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task); ++ struct fec_enet_private *fep = ++ container_of(work, struct fec_enet_private, phy_task); + struct net_device *dev = fep->netdev; + uint status = fep->phy_status; + + /* +- ** When we get here, phy_task is already removed from +- ** the workqueue. It is thus safe to allow to reuse it. +- */ ++ ** When we get here, phy_task is already removed from ++ ** the workqueue. It is thus safe to allow to reuse it. ++ */ + fep->mii_phy_task_queued = 0; + printk("%s: config: auto-negotiation ", dev->name); + +@@ -1994,14 +1973,15 @@ static void mii_display_config(struct wo + + static void mii_relink(struct work_struct *work) + { +- struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task); ++ struct fec_enet_private *fep = ++ container_of(work, struct fec_enet_private, phy_task); + struct net_device *dev = fep->netdev; + int duplex; + + /* +- ** When we get here, phy_task is already removed from +- ** the workqueue. It is thus safe to allow to reuse it. +- */ ++ ** When we get here, phy_task is already removed from ++ ** the workqueue. It is thus safe to allow to reuse it. ++ */ + fep->mii_phy_task_queued = 0; + fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0; + mii_display_status(dev); +@@ -2009,8 +1989,7 @@ static void mii_relink(struct work_struc + + if (fep->link) { + duplex = 0; +- if (fep->phy_status +- & (PHY_STAT_100FDX | PHY_STAT_10FDX)) ++ if (fep->phy_status & (PHY_STAT_100FDX | PHY_STAT_10FDX)) + duplex = 1; + fec_restart(dev, duplex); + } else +@@ -2028,12 +2007,12 @@ static void mii_queue_relink(uint mii_re + struct fec_enet_private *fep = netdev_priv(dev); + + /* +- ** We cannot queue phy_task twice in the workqueue. It +- ** would cause an endless loop in the workqueue. +- ** Fortunately, if the last mii_relink entry has not yet been +- ** executed now, it will do the job for the current interrupt, +- ** which is just what we want. +- */ ++ ** We cannot queue phy_task twice in the workqueue. It ++ ** would cause an endless loop in the workqueue. ++ ** Fortunately, if the last mii_relink entry has not yet been ++ ** executed now, it will do the job for the current interrupt, ++ ** which is just what we want. ++ */ + if (fep->mii_phy_task_queued) + return; + +@@ -2056,18 +2035,17 @@ static void mii_queue_config(uint mii_re + } + + phy_cmd_t const phy_cmd_relink[] = { +- { mk_mii_read(MII_REG_CR), mii_queue_relink }, +- { mk_mii_end, } +- }; ++ {mk_mii_read(MII_REG_CR), mii_queue_relink}, ++ {mk_mii_end,} ++}; + phy_cmd_t const phy_cmd_config[] = { +- { mk_mii_read(MII_REG_CR), mii_queue_config }, +- { mk_mii_end, } +- }; ++ {mk_mii_read(MII_REG_CR), mii_queue_config}, ++ {mk_mii_end,} ++}; + + /* Read remainder of PHY ID. + */ +-static void +-mii_discover_phy3(uint mii_reg, struct net_device *dev) ++static void mii_discover_phy3(uint mii_reg, struct net_device *dev) + { + struct fec_enet_private *fep; + int i; +@@ -2076,8 +2054,8 @@ mii_discover_phy3(uint mii_reg, struct n + fep->phy_id |= (mii_reg & 0xffff); + printk("fec: PHY @ 0x%x, ID 0x%08x", fep->phy_addr, fep->phy_id); + +- for(i = 0; phy_info[i]; i++) { +- if(phy_info[i]->id == (fep->phy_id >> 4)) ++ for (i = 0; phy_info[i]; i++) { ++ if (phy_info[i]->id == (fep->phy_id >> 4)) + break; + } + +@@ -2093,8 +2071,7 @@ mii_discover_phy3(uint mii_reg, struct n + /* Scan all of the MII PHY addresses looking for someone to respond + * with a valid ID. This usually happens quickly. + */ +-static void +-mii_discover_phy(uint mii_reg, struct net_device *dev) ++static void mii_discover_phy(uint mii_reg, struct net_device *dev) + { + struct fec_enet_private *fep; + volatile fec_t *fecp; +@@ -2107,14 +2084,14 @@ mii_discover_phy(uint mii_reg, struct ne + if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) { + + /* Got first part of ID, now get remainder. +- */ ++ */ + fep->phy_id = phytype << 16; + mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), +- mii_discover_phy3); ++ mii_discover_phy3); + } else { + fep->phy_addr++; + mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), +- mii_discover_phy); ++ mii_discover_phy); + } + } else { + printk("FEC: No PHY device found.\n"); +@@ -2124,33 +2101,23 @@ mii_discover_phy(uint mii_reg, struct ne + } + } + +-/* This interrupt occurs when the PHY detects a link change. +-*/ +-#ifdef CONFIG_RPXCLASSIC +-static void +-mii_link_interrupt(void *dev_id) +-#else +-static irqreturn_t +-mii_link_interrupt(int irq, void * dev_id) +-#endif ++/* Set a MAC change in hardware. ++ */ ++static void fec_set_mac_address(struct net_device *dev) + { +- struct net_device *dev = dev_id; +- struct fec_enet_private *fep = netdev_priv(dev); +- +- fec_phy_ack_intr(); ++ volatile fec_t *fecp; + +-#if 0 +- disable_irq(fep->mii_irq); /* disable now, enable later */ +-#endif ++ fecp = ((struct fec_enet_private *)netdev_priv(dev))->hwp; + +- mii_do_cmd(dev, fep->phy->ack_int); +- mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ ++ /* Set station address. */ ++ fecp->fec_addr_low = dev->dev_addr[3] | (dev->dev_addr[2] << 8) | ++ (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24); ++ fecp->fec_addr_high = (dev->dev_addr[5] << 16) | ++ (dev->dev_addr[4] << 24); + +- return IRQ_HANDLED; + } + +-static int +-fec_enet_open(struct net_device *dev) ++static int fec_enet_open(struct net_device *dev) + { + struct fec_enet_private *fep = netdev_priv(dev); + +@@ -2165,7 +2132,7 @@ fec_enet_open(struct net_device *dev) + if (fep->phy) { + mii_do_cmd(dev, fep->phy->ack_int); + mii_do_cmd(dev, fep->phy->config); +- mii_do_cmd(dev, phy_cmd_config); /* display configuration */ ++ mii_do_cmd(dev, phy_cmd_config); /* display configuration */ + + /* Poll until the PHY tells us its configuration + * (not link state). +@@ -2174,7 +2141,7 @@ fec_enet_open(struct net_device *dev) + * This should take about 25 usec per register at 2.5 MHz, + * and we read approximately 5 registers. + */ +- while(!fep->sequence_done) ++ while (!fep->sequence_done) + schedule(); + + mii_do_cmd(dev, fep->phy->startup); +@@ -2185,7 +2152,7 @@ fec_enet_open(struct net_device *dev) + */ + fep->link = 1; + } else { +- fep->link = 1; /* lets just try it and see */ ++ fep->link = 1; /* lets just try it and see */ + /* no phy, go full duplex, it's most likely a hub chip */ + fec_restart(dev, 1); + } +@@ -2195,13 +2162,12 @@ fec_enet_open(struct net_device *dev) + return 0; /* Success */ + } + +-static int +-fec_enet_close(struct net_device *dev) ++static int fec_enet_close(struct net_device *dev) + { + struct fec_enet_private *fep = netdev_priv(dev); + + /* Don't know what to do yet. +- */ ++ */ + fep->opened = 0; + netif_stop_queue(dev); + fec_stop(dev); +@@ -2219,7 +2185,7 @@ fec_enet_close(struct net_device *dev) + * this kind of feature?). + */ + +-#define HASH_BITS 6 /* #bits in hash */ ++#define HASH_BITS 6 /* #bits in hash */ + #define CRC32_POLY 0xEDB88320 + + static void set_multicast_list(struct net_device *dev) +@@ -2233,76 +2199,61 @@ static void set_multicast_list(struct ne + fep = netdev_priv(dev); + ep = fep->hwp; + +- if (dev->flags&IFF_PROMISC) { ++ if (dev->flags & IFF_PROMISC) { + ep->fec_r_cntrl |= 0x0008; +- } else { ++ return ; ++ } + +- ep->fec_r_cntrl &= ~0x0008; ++ ep->fec_r_cntrl &= ~0x0008; + +- if (dev->flags & IFF_ALLMULTI) { +- /* Catch all multicast addresses, so set the +- * filter to all 1's. +- */ +- ep->fec_hash_table_high = 0xffffffff; +- ep->fec_hash_table_low = 0xffffffff; +- } else { +- /* Clear filter and add the addresses in hash register. +- */ +- ep->fec_hash_table_high = 0; +- ep->fec_hash_table_low = 0; +- +- dmi = dev->mc_list; +- +- for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) +- { +- /* Only support group multicast for now. +- */ +- if (!(dmi->dmi_addr[0] & 1)) +- continue; +- +- /* calculate crc32 value of mac address +- */ +- crc = 0xffffffff; +- +- for (i = 0; i < dmi->dmi_addrlen; i++) +- { +- data = dmi->dmi_addr[i]; +- for (bit = 0; bit < 8; bit++, data >>= 1) +- { +- crc = (crc >> 1) ^ +- (((crc ^ data) & 1) ? CRC32_POLY : 0); +- } +- } +- +- /* only upper 6 bits (HASH_BITS) are used +- which point to specific bit in he hash registers +- */ +- hash = (crc >> (32 - HASH_BITS)) & 0x3f; +- +- if (hash > 31) +- ep->fec_hash_table_high |= 1 << (hash - 32); +- else +- ep->fec_hash_table_low |= 1 << hash; +- } +- } ++ if (dev->flags & IFF_ALLMULTI) { ++ /* Catch all multicast addresses, so set the ++ * filter to all 1's. ++ */ ++ ep->fec_hash_table_high = 0xffffffff; ++ ep->fec_hash_table_low = 0xffffffff; ++ return ; + } +-} ++ /* ++ * Clear filter and add the addresses in hash register. ++ */ ++ ep->fec_hash_table_high = 0; ++ ep->fec_hash_table_low = 0; + +-/* Set a MAC change in hardware. +- */ +-static void +-fec_set_mac_address(struct net_device *dev) +-{ +- volatile fec_t *fecp; ++ dmi = dev->mc_list; + +- fecp = ((struct fec_enet_private *)netdev_priv(dev))->hwp; ++ for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) { ++ /* Only support group multicast for now. ++ */ ++ if (!(dmi->dmi_addr[0] & 1)) ++ continue; + +- /* Set station address. */ +- fecp->fec_addr_low = dev->dev_addr[3] | (dev->dev_addr[2] << 8) | +- (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24); +- fecp->fec_addr_high = (dev->dev_addr[5] << 16) | +- (dev->dev_addr[4] << 24); ++ /* calculate crc32 value of mac address ++ */ ++ crc = 0xffffffff; ++ ++ for (i = 0; i < dmi->dmi_addrlen; i++) { ++ data = dmi->dmi_addr[i]; ++ for (bit = 0; bit < 8; ++ bit++, data >>= 1) { ++ crc = ++ (crc >> 1) ^ ++ (((crc ^ data) & 1) ? ++ CRC32_POLY : 0); ++ } ++ } + ++ /* only upper 6 bits (HASH_BITS) are used ++ which point to specific bit in he hash registers ++ */ ++ hash = (crc >> (32 - HASH_BITS)) & 0x3f; ++ ++ if (hash > 31) ++ ep->fec_hash_table_high |= ++ 1 << (hash - 32); ++ else ++ ep->fec_hash_table_low |= 1 << hash; ++ } + } + + /* Initialize the FEC Ethernet on 860T (or ColdFire 5272). +@@ -2310,38 +2261,40 @@ fec_set_mac_address(struct net_device *d + /* + * XXX: We need to clean up on failure exits here. + */ ++static int index; + int __init fec_enet_init(struct net_device *dev) + { + struct fec_enet_private *fep = netdev_priv(dev); +- unsigned long mem_addr; +- volatile cbd_t *bdp; +- cbd_t *cbd_base; +- volatile fec_t *fecp; +- int i, j; +- static int index = 0; ++ unsigned long mem_addr; ++ volatile cbd_t *bdp; ++ cbd_t *cbd_base; ++ volatile fec_t *fecp; ++ int i, j; + + /* Only allow us to be probed once. */ + if (index >= FEC_MAX_PORTS) + return -ENXIO; + + /* Allocate memory for buffer descriptors. +- */ ++ */ + mem_addr = __get_free_page(GFP_KERNEL); + if (mem_addr == 0) { + printk("FEC: allocate descriptor memory failed?\n"); + return -ENOMEM; + } + ++ spin_lock_init(&fep->hw_lock); ++ spin_lock_init(&fep->mii_lock); + /* Create an Ethernet device instance. +- */ +- fecp = (volatile fec_t *) fec_hw[index]; ++ */ ++ fecp = (volatile fec_t *)fec_hw[index]; + + fep->index = index; + fep->hwp = fecp; + fep->netdev = dev; + + /* Whack a reset. We should wait for this. +- */ ++ */ + fecp->fec_ecntrl = 1; + udelay(10); + +@@ -2353,13 +2306,12 @@ int __init fec_enet_init(struct net_devi + */ + fec_get_mac(dev); + +- cbd_base = (cbd_t *)mem_addr; +- /* XXX: missing check for allocation failure */ ++ cbd_base = (cbd_t *) mem_addr; + + fec_uncache(mem_addr); + + /* Set receive and transmit descriptor base. +- */ ++ */ + fep->rx_bd_base = cbd_base; + fep->tx_bd_base = cbd_base + RX_RING_SIZE; + +@@ -2369,20 +2321,20 @@ int __init fec_enet_init(struct net_devi + fep->skb_cur = fep->skb_dirty = 0; + + /* Initialize the receive buffer descriptors. +- */ ++ */ + bdp = fep->rx_bd_base; +- for (i=0; icbd_sc = BD_ENET_RX_EMPTY; + bdp->cbd_bufaddr = __pa(mem_addr); + mem_addr += FEC_ENET_RX_FRSIZE; +@@ -2391,43 +2343,44 @@ int __init fec_enet_init(struct net_devi + } + + /* Set the last buffer to wrap. +- */ ++ */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* ...and the same for transmmit. +- */ ++ */ + bdp = fep->tx_bd_base; +- for (i=0, j=FEC_ENET_TX_FRPPG; i= FEC_ENET_TX_FRPPG) { ++ /* XXX: missing check for allocation failure */ + mem_addr = __get_free_page(GFP_KERNEL); + j = 1; + } else { + mem_addr += FEC_ENET_TX_FRSIZE; + j++; + } +- fep->tx_bounce[i] = (unsigned char *) mem_addr; ++ fep->tx_bounce[i] = (unsigned char *)mem_addr; + + /* Initialize the BD for every fragment in the page. +- */ ++ */ + bdp->cbd_sc = 0; + bdp->cbd_bufaddr = 0; + bdp++; + } + + /* Set the last buffer to wrap. +- */ ++ */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* Set receive and transmit descriptor base. +- */ +- fecp->fec_r_des_start = __pa((uint)(fep->rx_bd_base)); +- fecp->fec_x_des_start = __pa((uint)(fep->tx_bd_base)); ++ */ ++ fecp->fec_r_des_start = __pa((uint) (fep->rx_bd_base)); ++ fecp->fec_x_des_start = __pa((uint) (fep->tx_bd_base)); + + /* Install our interrupt handlers. This varies depending on + * the architecture. +- */ ++ */ + fec_request_intrs(dev); + + fecp->fec_hash_table_high = 0; +@@ -2446,8 +2399,8 @@ int __init fec_enet_init(struct net_devi + dev->stop = fec_enet_close; + dev->set_multicast_list = set_multicast_list; + +- for (i=0; ifec_ievent = 0xffc00000; +- fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | +- FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); ++ fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII); + + /* Queue up command to detect the PHY and initialize the + * remainder of the interface. +@@ -2473,8 +2425,7 @@ int __init fec_enet_init(struct net_devi + * change. This only happens when switching between half and full + * duplex. + */ +-static void +-fec_restart(struct net_device *dev, int duplex) ++static void fec_restart(struct net_device *dev, int duplex) + { + struct fec_enet_private *fep; + volatile cbd_t *bdp; +@@ -2485,42 +2436,42 @@ fec_restart(struct net_device *dev, int + fecp = fep->hwp; + + /* Whack a reset. We should wait for this. +- */ ++ */ + fecp->fec_ecntrl = 1; + udelay(10); + + /* Clear any outstanding interrupt. +- */ ++ */ + fecp->fec_ievent = 0xffc00000; + fec_enable_phy_intr(); + + /* Set station address. +- */ ++ */ + fec_set_mac_address(dev); + + /* Reset all multicast. +- */ ++ */ + fecp->fec_hash_table_high = 0; + fecp->fec_hash_table_low = 0; + + /* Set maximum receive buffer size. +- */ ++ */ + fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; + + fec_localhw_setup(); + + /* Set receive and transmit descriptor base. +- */ +- fecp->fec_r_des_start = __pa((uint)(fep->rx_bd_base)); +- fecp->fec_x_des_start = __pa((uint)(fep->tx_bd_base)); ++ */ ++ fecp->fec_r_des_start = __pa((uint) (fep->rx_bd_base)); ++ fecp->fec_x_des_start = __pa((uint) (fep->tx_bd_base)); + + fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; + fep->cur_rx = fep->rx_bd_base; + + /* Reset SKB transmit buffers. +- */ ++ */ + fep->skb_cur = fep->skb_dirty = 0; +- for (i=0; i<=TX_RING_MOD_MASK; i++) { ++ for (i = 0; i <= TX_RING_MOD_MASK; i++) { + if (fep->tx_skbuff[i] != NULL) { + dev_kfree_skb_any(fep->tx_skbuff[i]); + fep->tx_skbuff[i] = NULL; +@@ -2528,43 +2479,43 @@ fec_restart(struct net_device *dev, int + } + + /* Initialize the receive buffer descriptors. +- */ ++ */ + bdp = fep->rx_bd_base; +- for (i=0; icbd_sc = BD_ENET_RX_EMPTY; + bdp++; + } + + /* Set the last buffer to wrap. +- */ ++ */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* ...and the same for transmmit. +- */ ++ */ + bdp = fep->tx_bd_base; +- for (i=0; icbd_sc = 0; + bdp->cbd_bufaddr = 0; + bdp++; + } + + /* Set the last buffer to wrap. +- */ ++ */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* Enable MII mode. +- */ ++ */ + if (duplex) { +- fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;/* MII enable */ +- fecp->fec_x_cntrl = 0x04; /* FD enable */ ++ fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04; /* MII enable */ ++ fecp->fec_x_cntrl = 0x04; /* FD enable */ + } else { + /* MII enable|No Rcv on Xmit */ + fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x06; +@@ -2573,22 +2524,20 @@ fec_restart(struct net_device *dev, int + fep->full_duplex = duplex; + + /* Set MII speed. +- */ ++ */ + fecp->fec_mii_speed = fep->phy_speed; + + /* And last, enable the transmit and receive processing. +- */ ++ */ + fecp->fec_ecntrl = 2; + fecp->fec_r_des_active = 0; + + /* Enable interrupts we wish to service. +- */ +- fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | +- FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); ++ */ ++ fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII); + } + +-static void +-fec_stop(struct net_device *dev) ++static void fec_stop(struct net_device *dev) + { + volatile fec_t *fecp; + struct fec_enet_private *fep; +@@ -2597,23 +2546,23 @@ fec_stop(struct net_device *dev) + fecp = fep->hwp; + + /* +- ** We cannot expect a graceful transmit stop without link !!! +- */ +- if (fep->link) +- { ++ ** We cannot expect a graceful transmit stop without link !!! ++ */ ++ if (fep->link) { + fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ + udelay(10); + if (!(fecp->fec_ievent & FEC_ENET_GRA)) +- printk("fec_stop : Graceful transmit stop did not complete !\n"); +- } ++ printk ++ ("fec_stop : Graceful transmit stop did not complete !\n"); ++ } + + /* Whack a reset. We should wait for this. +- */ ++ */ + fecp->fec_ecntrl = 1; + udelay(10); + + /* Clear outstanding MII command interrupts. +- */ ++ */ + fecp->fec_ievent = FEC_ENET_MII; + fec_enable_phy_intr(); + +@@ -2624,7 +2573,7 @@ fec_stop(struct net_device *dev) + static int __init fec_enet_module_init(void) + { + struct net_device *dev; +- int i, j, err; ++ int i, err; + DECLARE_MAC_BUF(mac); + + printk("FEC ENET Version 0.2\n"); +@@ -2651,5 +2600,4 @@ static int __init fec_enet_module_init(v + } + + module_init(fec_enet_module_init); +- + MODULE_LICENSE("GPL"); +Index: linux-2.6.24.7-rt27/drivers/serial/68328serial.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/serial/68328serial.c 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/serial/68328serial.c 2009-02-08 00:00:48.000000000 -0500 +@@ -1410,7 +1410,7 @@ rs68328_init(void) + + if (request_irq(uart_irqs[i], + rs_interrupt, +- IRQ_FLG_STD, ++ IRQF_DISABLED, + "M68328_UART", NULL)) + panic("Unable to attach 68328 serial interrupt\n"); + } +Index: linux-2.6.24.7-rt27/drivers/serial/mcf.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/serial/mcf.c 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/serial/mcf.c 2009-02-08 00:00:48.000000000 -0500 +@@ -69,7 +69,7 @@ static unsigned int mcf_tx_empty(struct + + static unsigned int mcf_get_mctrl(struct uart_port *port) + { +- struct mcf_uart *pp = (struct mcf_uart *) port; ++ struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned long flags; + unsigned int sigs; + +@@ -87,7 +87,7 @@ static unsigned int mcf_get_mctrl(struct + + static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs) + { +- struct mcf_uart *pp = (struct mcf_uart *) port; ++ struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); +@@ -104,7 +104,7 @@ static void mcf_set_mctrl(struct uart_po + + static void mcf_start_tx(struct uart_port *port) + { +- struct mcf_uart *pp = (struct mcf_uart *) port; ++ struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); +@@ -117,7 +117,7 @@ static void mcf_start_tx(struct uart_por + + static void mcf_stop_tx(struct uart_port *port) + { +- struct mcf_uart *pp = (struct mcf_uart *) port; ++ struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); +@@ -130,7 +130,7 @@ static void mcf_stop_tx(struct uart_port + + static void mcf_stop_rx(struct uart_port *port) + { +- struct mcf_uart *pp = (struct mcf_uart *) port; ++ struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); +@@ -163,7 +163,7 @@ static void mcf_enable_ms(struct uart_po + + static int mcf_startup(struct uart_port *port) + { +- struct mcf_uart *pp = (struct mcf_uart *) port; ++ struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); +@@ -189,7 +189,7 @@ static int mcf_startup(struct uart_port + + static void mcf_shutdown(struct uart_port *port) + { +- struct mcf_uart *pp = (struct mcf_uart *) port; ++ struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); +@@ -273,7 +273,7 @@ static void mcf_set_termios(struct uart_ + + static void mcf_rx_chars(struct mcf_uart *pp) + { +- struct uart_port *port = (struct uart_port *) pp; ++ struct uart_port *port = &pp->port; + unsigned char status, ch, flag; + + while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) { +@@ -319,7 +319,7 @@ static void mcf_rx_chars(struct mcf_uart + + static void mcf_tx_chars(struct mcf_uart *pp) + { +- struct uart_port *port = (struct uart_port *) pp; ++ struct uart_port *port = &pp->port; + struct circ_buf *xmit = &port->info->xmit; + + if (port->x_char) { +@@ -352,7 +352,7 @@ static void mcf_tx_chars(struct mcf_uart + static irqreturn_t mcf_interrupt(int irq, void *data) + { + struct uart_port *port = data; +- struct mcf_uart *pp = (struct mcf_uart *) port; ++ struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned int isr; + + isr = readb(port->membase + MCFUART_UISR) & pp->imr; +@@ -434,7 +434,7 @@ static struct uart_ops mcf_uart_ops = { + + static struct mcf_uart mcf_ports[3]; + +-#define MCF_MAXPORTS (sizeof(mcf_ports) / sizeof(struct mcf_uart)) ++#define MCF_MAXPORTS ARRAY_SIZE(mcf_ports) + + /****************************************************************************/ + #if defined(CONFIG_SERIAL_MCF_CONSOLE) +Index: linux-2.6.24.7-rt27/drivers/serial/mcfserial.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/serial/mcfserial.c 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/serial/mcfserial.c 2009-02-08 00:00:48.000000000 -0500 +@@ -65,7 +65,8 @@ struct timer_list mcfrs_timer_struct; + #define CONSOLE_BAUD_RATE 115200 + #define DEFAULT_CBAUD B115200 + #elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \ +- defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET) ++ defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET) || \ ++ defined(CONFIG_SAVANT) + #define CONSOLE_BAUD_RATE 19200 + #define DEFAULT_CBAUD B19200 + #endif +@@ -324,7 +325,7 @@ static void mcfrs_start(struct tty_struc + * ----------------------------------------------------------------------- + */ + +-static inline void receive_chars(struct mcf_serial *info) ++static noinline void receive_chars(struct mcf_serial *info) + { + volatile unsigned char *uartp; + struct tty_struct *tty = info->tty; +@@ -369,7 +370,7 @@ static inline void receive_chars(struct + return; + } + +-static inline void transmit_chars(struct mcf_serial *info) ++static noinline void transmit_chars(struct mcf_serial *info) + { + volatile unsigned char *uartp; + +@@ -1489,14 +1490,28 @@ int mcfrs_open(struct tty_struct *tty, s + /* + * Based on the line number set up the internal interrupt stuff. + */ +-static void mcfrs_irqinit(struct mcf_serial *info) ++static int mcfrs_irqinit(struct mcf_serial *info) + { ++ volatile unsigned char *uartp; ++ int ret; ++ ++ uartp = info->addr; ++ /* Clear mask, so no surprise interrupts. */ ++ uartp[MCFUART_UIMR] = 0; ++ ++ ret = request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED, ++ "ColdFire UART", NULL); ++ if (ret) { ++ printk("MCFRS: Unable to attach ColdFire UART %d interrupt " ++ "vector=%d, error: %d\n", info->line, ++ info->irq, ret); ++ return ret; ++ } ++ + #if defined(CONFIG_M5272) + volatile unsigned long *icrp; + volatile unsigned long *portp; +- volatile unsigned char *uartp; + +- uartp = info->addr; + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2); + + switch (info->line) { +@@ -1518,11 +1533,10 @@ static void mcfrs_irqinit(struct mcf_ser + portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT); + *portp = (*portp & ~0x000003fc) | 0x000002a8; + #elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) +- volatile unsigned char *icrp, *uartp; ++#if !defined(CONFIG_M523x) ++ volatile unsigned char *icrp; + volatile unsigned long *imrp; + +- uartp = info->addr; +- + icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + + MCFINTC_ICR0 + MCFINT_UART0 + info->line); + *icrp = 0x30 + info->line; /* level 6, line based priority */ +@@ -1530,6 +1544,14 @@ static void mcfrs_irqinit(struct mcf_ser + imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + + MCFINTC_IMRL); + *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); ++#endif ++#if defined(CONFIG_M523x) ++ { ++ volatile unsigned short *par_uartp; ++ par_uartp = (volatile unsigned short *) (MCF_MBAR + MCF523x_GPIO_PAR_UART); ++ *par_uartp = 0x3FFF; /* setup GPIO for UART0, UART1 & UART2 */ ++ } ++#endif + #if defined(CONFIG_M527x) + { + /* +@@ -1554,37 +1576,38 @@ static void mcfrs_irqinit(struct mcf_ser + } + #endif + #elif defined(CONFIG_M520x) +- volatile unsigned char *icrp, *uartp; +- volatile unsigned long *imrp; +- +- uartp = info->addr; +- +- icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + +- MCFINTC_ICR0 + MCFINT_UART0 + info->line); +- *icrp = 0x03; ++ { ++ volatile unsigned char *icrp; ++ volatile unsigned long *imrp; + +- imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + +- MCFINTC_IMRL); +- *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); +- if (info->line < 2) { +- unsigned short *uart_par; +- uart_par = (unsigned short *)(MCF_IPSBAR + MCF_GPIO_PAR_UART); +- if (info->line == 0) +- *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD0 +- | MCF_GPIO_PAR_UART_PAR_URXD0; +- else if (info->line == 1) +- *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD1 +- | MCF_GPIO_PAR_UART_PAR_URXD1; ++ icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + ++ MCFINTC_ICR0 + MCFINT_UART0 + info->line); ++ *icrp = 0x03; ++ ++ imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + ++ MCFINTC_IMRL); ++ *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); ++ if (info->line < 2) { ++ unsigned short *uart_par; ++ uart_par = (unsigned short *)(MCF_IPSBAR + ++ MCF_GPIO_PAR_UART); ++ if (info->line == 0) ++ *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD0 ++ | MCF_GPIO_PAR_UART_PAR_URXD0; ++ else if (info->line == 1) ++ *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD1 ++ | MCF_GPIO_PAR_UART_PAR_URXD1; + } else if (info->line == 2) { + unsigned char *feci2c_par; +- feci2c_par = (unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C); ++ feci2c_par = (unsigned char *)(MCF_IPSBAR + ++ MCF_GPIO_PAR_FECI2C); + *feci2c_par &= ~0x0F; + *feci2c_par |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 +- | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; ++ | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; + } ++ } + #elif defined(CONFIG_M532x) +- volatile unsigned char *uartp; +- uartp = info->addr; ++ + switch (info->line) { + case 0: + MCF_INTC0_ICR26 = 0x3; +@@ -1605,7 +1628,6 @@ static void mcfrs_irqinit(struct mcf_ser + break; + } + #else +- volatile unsigned char *icrp, *uartp; + + switch (info->line) { + case 0: +@@ -1623,23 +1645,12 @@ static void mcfrs_irqinit(struct mcf_ser + default: + printk("MCFRS: don't know how to handle UART %d interrupt?\n", + info->line); +- return; ++ return -ENODEV; + } + +- uartp = info->addr; + uartp[MCFUART_UIVR] = info->irq; + #endif +- +- /* Clear mask, so no surprise interrupts. */ +- uartp[MCFUART_UIMR] = 0; +- +- if (request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED, +- "ColdFire UART", NULL)) { +- printk("MCFRS: Unable to attach ColdFire UART %d interrupt " +- "vector=%d\n", info->line, info->irq); +- } +- +- return; ++ return 0; + } + + +@@ -1729,7 +1740,6 @@ static int __init + mcfrs_init(void) + { + struct mcf_serial *info; +- unsigned long flags; + int i; + + /* Setup base handler, and timer table. */ +@@ -1769,12 +1779,12 @@ mcfrs_init(void) + return(-EBUSY); + } + +- local_irq_save(flags); +- + /* + * Configure all the attached serial ports. + */ + for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) { ++ int ret; ++ + info->magic = SERIAL_MAGIC; + info->line = i; + info->tty = 0; +@@ -1792,14 +1802,11 @@ mcfrs_init(void) + + info->imr = 0; + mcfrs_setsignals(info, 0, 0); +- mcfrs_irqinit(info); +- +- printk("ttyS%d at 0x%04x (irq = %d)", info->line, +- (unsigned int) info->addr, info->irq); +- printk(" is a builtin ColdFire UART\n"); ++ ret = mcfrs_irqinit(info); ++ if (!ret) ++ printk("ttyS%d at 0x%p (irq = %d) is a builtin " ++ "ColdFire UART\n", info->line, info->addr, info->irq); + } +- +- local_irq_restore(flags); + return 0; + } + +Index: linux-2.6.24.7-rt27/fs/nfs/file.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/nfs/file.c 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/nfs/file.c 2009-02-08 00:00:48.000000000 -0500 +@@ -64,7 +64,11 @@ const struct file_operations nfs_file_op + .write = do_sync_write, + .aio_read = nfs_file_read, + .aio_write = nfs_file_write, ++#ifdef CONFIG_MMU + .mmap = nfs_file_mmap, ++#else ++ .mmap = generic_file_mmap, ++#endif + .open = nfs_file_open, + .flush = nfs_file_flush, + .release = nfs_file_release, +Index: linux-2.6.24.7-rt27/include/asm-generic/vmlinux.lds.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-generic/vmlinux.lds.h 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-generic/vmlinux.lds.h 2009-02-08 00:00:48.000000000 -0500 +@@ -6,6 +6,10 @@ + #define VMLINUX_SYMBOL(_sym_) _sym_ + #endif + ++#ifndef OUTPUT_DATA_SECTION ++#define OUTPUT_DATA_SECTION ++#endif ++ + /* Align . to a 8 byte boundary equals to maximum function alignment. */ + #define ALIGN_FUNCTION() . = ALIGN(8) + +@@ -25,11 +29,11 @@ + *(.rodata) *(.rodata.*) \ + *(__vermagic) /* Kernel version magic */ \ + *(__markers_strings) /* Markers: strings */ \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + .rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \ + *(.rodata1) \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* PCI quirks */ \ + .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ +@@ -48,89 +52,89 @@ + VMLINUX_SYMBOL(__start_pci_fixups_resume) = .; \ + *(.pci_fixup_resume) \ + VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* RapidIO route ops */ \ + .rio_route : AT(ADDR(.rio_route) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_rio_route_ops) = .; \ + *(.rio_route_ops) \ + VMLINUX_SYMBOL(__end_rio_route_ops) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* Kernel symbol table: Normal symbols */ \ + __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab) = .; \ + *(__ksymtab) \ + VMLINUX_SYMBOL(__stop___ksymtab) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ + *(__ksymtab_gpl) \ + VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* Kernel symbol table: Normal unused symbols */ \ + __ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \ + *(__ksymtab_unused) \ + VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* Kernel symbol table: GPL-only unused symbols */ \ + __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \ + *(__ksymtab_unused_gpl) \ + VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* Kernel symbol table: GPL-future-only symbols */ \ + __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \ + *(__ksymtab_gpl_future) \ + VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* Kernel symbol table: Normal symbols */ \ + __kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab) = .; \ + *(__kcrctab) \ + VMLINUX_SYMBOL(__stop___kcrctab) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \ + *(__kcrctab_gpl) \ + VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* Kernel symbol table: Normal unused symbols */ \ + __kcrctab_unused : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_unused) = .; \ + *(__kcrctab_unused) \ + VMLINUX_SYMBOL(__stop___kcrctab_unused) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* Kernel symbol table: GPL-only unused symbols */ \ + __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \ + *(__kcrctab_unused_gpl) \ + VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* Kernel symbol table: GPL-future-only symbols */ \ + __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \ + *(__kcrctab_gpl_future) \ + VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* Kernel symbol table: strings */ \ + __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ + *(__ksymtab_strings) \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + /* Built-in module parameters. */ \ + __param : AT(ADDR(__param) - LOAD_OFFSET) { \ +@@ -138,7 +142,7 @@ + *(__param) \ + VMLINUX_SYMBOL(__stop___param) = .; \ + VMLINUX_SYMBOL(__end_rodata) = .; \ +- } \ ++ } OUTPUT_DATA_SECTION \ + \ + . = ALIGN((align)); + +@@ -227,7 +231,7 @@ + __start___bug_table = .; \ + *(__bug_table) \ + __stop___bug_table = .; \ +- } ++ } OUTPUT_DATA_SECTION + + #define NOTES \ + .notes : AT(ADDR(.notes) - LOAD_OFFSET) { \ +@@ -261,5 +265,5 @@ + .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { \ + *(.data.percpu) \ + *(.data.percpu.shared_aligned) \ +- } \ ++ } OUTPUT_DATA_SECTION \ + __per_cpu_end = .; +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/bitops.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/bitops.h 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/bitops.h 2009-02-08 00:00:48.000000000 -0500 +@@ -14,8 +14,38 @@ + #error only can be included directly + #endif + ++#if defined (__mcfisaaplus__) || defined (__mcfisac__) ++static inline int ffs(unsigned int val) ++{ ++ if (!val) ++ return 0; ++ ++ asm volatile( ++ "bitrev %0\n\t" ++ "ff1 %0\n\t" ++ : "=d" (val) ++ : "0" (val) ++ ); ++ val++; ++ return val; ++} ++ ++static inline int __ffs(unsigned int val) ++{ ++ asm volatile( ++ "bitrev %0\n\t" ++ "ff1 %0\n\t" ++ : "=d" (val) ++ : "0" (val) ++ ); ++ return val; ++} ++ ++#else + #include + #include ++#endif ++ + #include + #include + +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/byteorder.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/byteorder.h 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/byteorder.h 2009-02-08 00:00:48.000000000 -0500 +@@ -1,13 +1,27 @@ + #ifndef _M68KNOMMU_BYTEORDER_H + #define _M68KNOMMU_BYTEORDER_H + +-#include ++#include + + #if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) + # define __BYTEORDER_HAS_U64__ + # define __SWAB_64_THRU_32__ + #endif + ++#if defined (__mcfisaaplus__) || defined (__mcfisac__) ++static inline __attribute_const__ __u32 ___arch__swab32(__u32 val) ++{ ++ asm( ++ "byterev %0" ++ : "=d" (val) ++ : "0" (val) ++ ); ++ return val; ++} ++ ++#define __arch__swab32(x) ___arch__swab32(x) ++#endif ++ + #include + + #endif /* _M68KNOMMU_BYTEORDER_H */ +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/cacheflush.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/cacheflush.h 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/cacheflush.h 2009-02-08 00:00:48.000000000 -0500 +@@ -53,7 +53,7 @@ static inline void __flush_cache_all(voi + #endif /* CONFIG_M5407 */ + #if defined(CONFIG_M527x) || defined(CONFIG_M528x) + __asm__ __volatile__ ( +- "movel #0x81400100, %%d0\n\t" ++ "movel #0x81000200, %%d0\n\t" + "movec %%d0, %%CACR\n\t" + "nop\n\t" + : : : "d0" ); +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/commproc.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/commproc.h 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/commproc.h 2009-02-08 00:00:48.000000000 -0500 +@@ -519,25 +519,6 @@ typedef struct scc_enet { + #define SICR_ENET_CLKRT ((uint)0x00002c00) + #endif + +-#ifdef CONFIG_RPXCLASSIC +-/* Bits in parallel I/O port registers that have to be set/cleared +- * to configure the pins for SCC1 use. +- */ +-#define PA_ENET_RXD ((ushort)0x0001) +-#define PA_ENET_TXD ((ushort)0x0002) +-#define PA_ENET_TCLK ((ushort)0x0200) +-#define PA_ENET_RCLK ((ushort)0x0800) +-#define PB_ENET_TENA ((uint)0x00001000) +-#define PC_ENET_CLSN ((ushort)0x0010) +-#define PC_ENET_RENA ((ushort)0x0020) +- +-/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to +- * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero. +- */ +-#define SICR_ENET_MASK ((uint)0x000000ff) +-#define SICR_ENET_CLKRT ((uint)0x0000003d) +-#endif +- + /* SCC Event register as used by Ethernet. + */ + #define SCCE_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/dma.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/dma.h 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/dma.h 2009-02-08 00:00:48.000000000 -0500 +@@ -35,7 +35,8 @@ + /* + * Set number of channels of DMA on ColdFire for different implementations. + */ +-#if defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) ++#if defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) || \ ++ defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) + #define MAX_M68K_DMA_CHANNELS 4 + #elif defined(CONFIG_M5272) + #define MAX_M68K_DMA_CHANNELS 1 +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/m523xsim.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/m523xsim.h 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/m523xsim.h 2009-02-08 00:00:48.000000000 -0500 +@@ -11,7 +11,6 @@ + #define m523xsim_h + /****************************************************************************/ + +- + /* + * Define the 523x SIM register set addresses. + */ +@@ -27,10 +26,35 @@ + #define MCFINTC_IACKL 0x19 /* */ + #define MCFINTC_ICR0 0x40 /* Base ICR register */ + ++/* INTC0 - interrupt numbers */ + #define MCFINT_VECBASE 64 /* Vector base number */ +-#define MCFINT_UART0 13 /* Interrupt number for UART0 */ +-#define MCFINT_PIT1 36 /* Interrupt number for PIT1 */ +-#define MCFINT_QSPI 18 /* Interrupt number for QSPI */ ++#define MCFINT_EPF4 4 /* EPORT4 */ ++#define MCFINT_EPF5 5 /* EPORT5 */ ++#define MCFINT_EPF6 6 /* EPORT6 */ ++#define MCFINT_EPF7 7 /* EPORT7 */ ++#define MCFINT_UART0 13 /* UART0 */ ++#define MCFINT_QSPI 18 /* QSPI */ ++#define MCFINT_PIT1 36 /* PIT1 */ ++#define MCFINT_PER_INTC 64 ++ ++/* INTC1 - interrupt numbers */ ++#define MCFINT_INTC1_VECBASE (MCFINT_VECBASE + MCFINT_PER_INTC) ++#define MCFINT_TC0F 27 /* eTPU Channel 0 */ ++#define MCFINT_TC1F 28 /* eTPU Channel 1 */ ++#define MCFINT_TC2F 29 /* eTPU Channel 2 */ ++#define MCFINT_TC3F 30 /* eTPU Channel 3 */ ++#define MCFINT_TC4F 31 /* eTPU Channel 4 */ ++#define MCFINT_TC5F 32 /* eTPU Channel 5 */ ++#define MCFINT_TC6F 33 /* eTPU Channel 6 */ ++#define MCFINT_TC7F 34 /* eTPU Channel 7 */ ++#define MCFINT_TC8F 35 /* eTPU Channel 8 */ ++#define MCFINT_TC9F 36 /* eTPU Channel 9 */ ++#define MCFINT_TC10F 37 /* eTPU Channel 10 */ ++#define MCFINT_TC11F 38 /* eTPU Channel 11 */ ++#define MCFINT_TC12F 39 /* eTPU Channel 12 */ ++#define MCFINT_TC13F 40 /* eTPU Channel 13 */ ++#define MCFINT_TC14F 41 /* eTPU Channel 14 */ ++#define MCFINT_TC15F 42 /* eTPU Channel 15 */ + + /* + * SDRAM configuration registers. +@@ -41,5 +65,120 @@ + #define MCFSIM_DACR1 0x50 /* SDRAM base address 1 */ + #define MCFSIM_DMR1 0x54 /* SDRAM address mask 1 */ + ++/* ++ * GPIO Registers and Pin Assignments ++ */ ++#define MCF_GPIO_PAR_FECI2C 0x100047 /* FEC Pin Assignment reg */ ++#define MCF523x_GPIO_PAR_UART 0x100048 /* UART Pin Assignment reg */ ++#define MCF523x_GPIO_PAR_QSPI 0x10004a /* QSPI Pin Assignment reg */ ++#define MCF523x_GPIO_PAR_TIMER 0x10004c /* TIMER Pin Assignment reg */ ++#define MCF523x_GPIO_PDDR_QSPI 0x10001a /* QSPI Pin Direction reg */ ++#define MCF523x_GPIO_PDDR_TIMER 0x10001b /* TIMER Pin Direction reg */ ++#define MCF523x_GPIO_PPDSDR_QSPI 0x10002a /* QSPI Pin Data reg */ ++#define MCF523x_GPIO_PPDSDR_TIMER 0x10002b /* TIMER Pin Data reg */ ++ ++#define MCF_GPIO_PAR_FECI2C_PAR_SDA(x) (((x) & 0x03) << 0) ++#define MCF_GPIO_PAR_FECI2C_PAR_SCL(x) (((x) & 0x03) << 2) ++ ++/* ++ * eTPU Registers ++ */ ++#define MCF523x_ETPU 0x1d0000 /* eTPU Base */ ++#define MCF523x_ETPU_CIOSR 0x00220 /* eTPU Intr Overflow Status */ ++#define MCF523x_ETPU_CIER 0x00240 /* eTPU Intr Enable */ ++#define MCF523x_ETPU_CR(c) (0x00400 + ((c) * 0x10)) /* eTPU c Config */ ++#define MCF523x_ETPU_SCR(c) (0x00404 + ((c) * 0x10)) /* eTPU c Status & Ctrl */ ++#define MCF523x_ETPU_SDM 0x08000 /* eTPU Shared Data Memory */ ++ ++/* ++ * WDOG registers ++ */ ++#define MCF523x_WCR ((volatile uint16_t *) (MCF_IPSBAR + 0x140000)) /* control register 16 bits */ ++#define MCF523x_WMR ((volatile uint16_t *) (MCF_IPSBAR + 0x140002)) /* modulus status 16 bits */ ++#define MCF523x_MCNTR ((volatile uint16_t *) (MCF_IPSBAR + 0x140004)) /* count register 16 bits */ ++#define MCF523x_WSR ((volatile uint16_t *) (MCF_IPSBAR + 0x140006)) /* service register 16 bits */ ++ ++/* ++ * Reset registers ++ */ ++#define MCF523x_RSR ((volatile uint8_t *) (MCF_IPSBAR + 0x110001)) /* reset reason codes */ ++ ++/* ++ * WDOG bit level definitions and macros. ++ */ ++#define MCF523x_WCR_ENABLE_BIT 0x0001 ++ ++#define MCF523x_WCR_ENABLE 0x0001 ++#define MCF523x_WCR_DISABLE 0x0000 ++#define MCF523x_WCR_HALTEDSTOP 0x0002 ++#define MCF523x_WCR_HALTEDRUN 0x0000 ++#define MCF523x_WCR_DOZESTOP 0x0004 ++#define MCF523x_WCR_DOZERUN 0x0000 ++#define MCF523x_WCR_WAITSTOP 0x0008 ++#define MCF523x_WCR_WAITRUN 0x0000 ++ ++#define MCF523x_WMR_DEFAULT_VALUE 0xffff ++ ++/* ++ * Inter-IC (I2C) Module ++ * Read/Write access macros for general use ++ */ ++#define MCF_I2C_I2ADR ((volatile u8 *) (MCF_IPSBAR + 0x0300)) /* Address */ ++#define MCF_I2C_I2FDR ((volatile u8 *) (MCF_IPSBAR + 0x0304)) /* Freq Divider */ ++#define MCF_I2C_I2CR ((volatile u8 *) (MCF_IPSBAR + 0x0308)) /* Control */ ++#define MCF_I2C_I2SR ((volatile u8 *) (MCF_IPSBAR + 0x030C)) /* Status */ ++#define MCF_I2C_I2DR ((volatile u8 *) (MCF_IPSBAR + 0x0310)) /* Data I/O */ ++ ++/* ++ * Bit level definitions and macros ++ */ ++#define MCF_I2C_I2ADR_ADDR(x) (((x) & 0x7F) << 0x01) ++#define MCF_I2C_I2FDR_IC(x) ((x) & 0x3F) ++ ++#define MCF_I2C_I2CR_IEN 0x80 /* I2C enable */ ++#define MCF_I2C_I2CR_IIEN 0x40 /* interrupt enable */ ++#define MCF_I2C_I2CR_MSTA 0x20 /* master/slave mode */ ++#define MCF_I2C_I2CR_MTX 0x10 /* transmit/receive mode */ ++#define MCF_I2C_I2CR_TXAK 0x08 /* transmit acknowledge enable */ ++#define MCF_I2C_I2CR_RSTA 0x04 /* repeat start */ ++ ++#define MCF_I2C_I2SR_ICF 0x80 /* data transfer bit */ ++#define MCF_I2C_I2SR_IAAS 0x40 /* I2C addressed as a slave */ ++#define MCF_I2C_I2SR_IBB 0x20 /* I2C bus busy */ ++#define MCF_I2C_I2SR_IAL 0x10 /* aribitration lost */ ++#define MCF_I2C_I2SR_SRW 0x04 /* slave read/write */ ++#define MCF_I2C_I2SR_IIF 0x02 /* I2C interrupt */ ++#define MCF_I2C_I2SR_RXAK 0x01 /* received acknowledge */ ++ ++/* ++ * Edge Port (EPORT) Module ++ */ ++#define MCF523x_EPPAR 0x130000 ++#define MCF523x_EPDDR 0x130002 ++#define MCF523x_EPIER 0x130003 ++#define MCF523x_EPDR 0x130004 ++#define MCF523x_EPPDR 0x130005 ++#define MCF523x_EPFR 0x130006 ++ ++/* ++ * Chip Select (CS) Module ++ */ ++#define MCF523x_CSAR0 0x80 ++#define MCF523x_CSAR3 0xA4 ++#define MCF523x_CSMR3 0xA8 ++ ++/* ++ * System Access Control Unit (SACU) ++ */ ++#define MCF523x_PACR1 0x25 ++#define MCF523x_PACR2 0x26 ++#define MCF523x_PACR3 0x27 ++#define MCF523x_PACR4 0x28 ++#define MCF523x_PACR5 0x2A ++#define MCF523x_PACR6 0x2B ++#define MCF523x_PACR7 0x2C ++#define MCF523x_PACR8 0x2E ++#define MCF523x_GPACR 0x30 ++ + /****************************************************************************/ + #endif /* m523xsim_h */ +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/m528xsim.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/m528xsim.h 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/m528xsim.h 2009-02-08 00:00:48.000000000 -0500 +@@ -30,6 +30,9 @@ + #define MCFINT_VECBASE 64 /* Vector base number */ + #define MCFINT_UART0 13 /* Interrupt number for UART0 */ + #define MCFINT_PIT1 55 /* Interrupt number for PIT1 */ ++#define MCFINT_QSPI 18 /* Interrupt number for QSPI */ ++ ++#define MCF5282_INTC0 (MCF_IPSBAR + MCFICM_INTC0) + + /* + * SDRAM configuration registers. +@@ -50,44 +53,53 @@ + /* Port UA Pin Assignment Register (8 Bit) */ + #define MCF5282_GPIO_PUAPAR 0x10005C + ++#define MCF5282_GPIO_PORTQS (*(volatile u8 *) (MCF_IPSBAR + 0x0010000D)) ++#define MCF5282_GPIO_DDRQS (*(volatile u8 *) (MCF_IPSBAR + 0x00100021)) ++#define MCF5282_GPIO_PORTQSP (*(volatile u8 *) (MCF_IPSBAR + 0x00100035)) ++#define MCF5282_GPIO_PQSPAR (*(volatile u8 *) (MCF_IPSBAR + 0x00100059)) ++ ++#define MCF5282_GPIO_PEPAR (*(volatile u16 *) (MCF_IPSBAR + 0x00100052)) ++ ++#define MCF5282_GPIO_PORTE (*(volatile u8 *) (MCF_IPSBAR + 0x00100004)) ++#define MCF5282_GPIO_DDRE (*(volatile u8 *) (MCF_IPSBAR + 0x00100018)) ++#define MCF5282_GPIO_PORTEP (*(volatile u8 *) (MCF_IPSBAR + 0x0010002C)) ++ + /* Interrupt Mask Register Register Low */ + #define MCF5282_INTC0_IMRL (volatile u32 *) (MCF_IPSBAR + 0x0C0C) + /* Interrupt Control Register 7 */ + #define MCF5282_INTC0_ICR17 (volatile u8 *) (MCF_IPSBAR + 0x0C51) + +- +- + /********************************************************************* + * + * Inter-IC (I2C) Module + * + *********************************************************************/ + /* Read/Write access macros for general use */ +-#define MCF5282_I2C_I2ADR (volatile u8 *) (MCF_IPSBAR + 0x0300) // Address +-#define MCF5282_I2C_I2FDR (volatile u8 *) (MCF_IPSBAR + 0x0304) // Freq Divider +-#define MCF5282_I2C_I2CR (volatile u8 *) (MCF_IPSBAR + 0x0308) // Control +-#define MCF5282_I2C_I2SR (volatile u8 *) (MCF_IPSBAR + 0x030C) // Status +-#define MCF5282_I2C_I2DR (volatile u8 *) (MCF_IPSBAR + 0x0310) // Data I/O ++#define MCF_I2C_I2ADR (volatile u8 *) (MCF_IPSBAR + 0x0300) // Address ++#define MCF_I2C_I2FDR (volatile u8 *) (MCF_IPSBAR + 0x0304) // Freq Divider ++#define MCF_I2C_I2CR (volatile u8 *) (MCF_IPSBAR + 0x0308) // Control ++#define MCF_I2C_I2SR (volatile u8 *) (MCF_IPSBAR + 0x030C) // Status ++#define MCF_I2C_I2DR (volatile u8 *) (MCF_IPSBAR + 0x0310) // Data I/O + + /* Bit level definitions and macros */ +-#define MCF5282_I2C_I2ADR_ADDR(x) (((x)&0x7F)<<0x01) ++#define MCF_I2C_I2ADR_ADDR(x) (((x)&0x7F)<<0x01) + +-#define MCF5282_I2C_I2FDR_IC(x) (((x)&0x3F)) ++#define MCF_I2C_I2FDR_IC(x) (((x)&0x3F)) + +-#define MCF5282_I2C_I2CR_IEN (0x80) // I2C enable +-#define MCF5282_I2C_I2CR_IIEN (0x40) // interrupt enable +-#define MCF5282_I2C_I2CR_MSTA (0x20) // master/slave mode +-#define MCF5282_I2C_I2CR_MTX (0x10) // transmit/receive mode +-#define MCF5282_I2C_I2CR_TXAK (0x08) // transmit acknowledge enable +-#define MCF5282_I2C_I2CR_RSTA (0x04) // repeat start +- +-#define MCF5282_I2C_I2SR_ICF (0x80) // data transfer bit +-#define MCF5282_I2C_I2SR_IAAS (0x40) // I2C addressed as a slave +-#define MCF5282_I2C_I2SR_IBB (0x20) // I2C bus busy +-#define MCF5282_I2C_I2SR_IAL (0x10) // aribitration lost +-#define MCF5282_I2C_I2SR_SRW (0x04) // slave read/write +-#define MCF5282_I2C_I2SR_IIF (0x02) // I2C interrupt +-#define MCF5282_I2C_I2SR_RXAK (0x01) // received acknowledge ++#define MCF_I2C_I2CR_IEN (0x80) // I2C enable ++#define MCF_I2C_I2CR_IIEN (0x40) // interrupt enable ++#define MCF_I2C_I2CR_MSTA (0x20) // master/slave mode ++#define MCF_I2C_I2CR_MTX (0x10) // transmit/receive mode ++#define MCF_I2C_I2CR_TXAK (0x08) // transmit acknowledge enable ++#define MCF_I2C_I2CR_RSTA (0x04) // repeat start ++ ++#define MCF_I2C_I2SR_ICF (0x80) // data transfer bit ++#define MCF_I2C_I2SR_IAAS (0x40) // I2C addressed as a slave ++#define MCF_I2C_I2SR_IBB (0x20) // I2C bus busy ++#define MCF_I2C_I2SR_IAL (0x10) // aribitration lost ++#define MCF_I2C_I2SR_SRW (0x04) // slave read/write ++#define MCF_I2C_I2SR_IIF (0x02) // I2C interrupt ++#define MCF_I2C_I2SR_RXAK (0x01) // received acknowledge + + + +@@ -107,6 +119,11 @@ + #define MCF5282_QSPI_QDR MCF_IPSBAR + 0x0354 + #define MCF5282_QSPI_QCR MCF_IPSBAR + 0x0354 + ++#define MCF5282_QSPI_PAR (MCF_IPSBAR + 0x00100059) ++ ++#define MCF5282_QSPI_IRQ_SOURCE 18 ++#define MCF5282_QSPI_IRQ_VECTOR (64 + MCF5282_QSPI_IRQ_SOURCE) ++ + /* Bit level definitions and macros */ + #define MCF5282_QSPI_QMR_MSTR (0x8000) + #define MCF5282_QSPI_QMR_DOHIE (0x4000) +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/m532xsim.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/m532xsim.h 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/m532xsim.h 2009-02-08 00:00:48.000000000 -0500 +@@ -16,6 +16,7 @@ + #define MCFINT_VECBASE 64 + #define MCFINT_UART0 26 /* Interrupt number for UART0 */ + #define MCFINT_UART1 27 /* Interrupt number for UART1 */ ++#define MCFINT_UART2 28 /* Interrupt number for UART2 */ + + #define MCF_WTM_WCR MCF_REG16(0xFC098000) + +@@ -72,9 +73,21 @@ + #define mcf_getimr() \ + *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) + ++#define mcf_getimrh() \ ++ *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMRH)) ++ ++#define mcf_getimrl() \ ++ *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMRL)) ++ + #define mcf_setimr(imr) \ + *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) = (imr); + ++#define mcf_setimrh(imr) \ ++ *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMRH)) = (imr); ++ ++#define mcf_setimrl(imr) \ ++ *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMRL)) = (imr); ++ + #define mcf_getipr() \ + *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPR)) + +@@ -131,31 +144,31 @@ + *********************************************************************/ + + /* Read/Write access macros for general use */ +-#define MCF532x_I2C_I2ADR (volatile u8 *) (0xFC058000) // Address +-#define MCF532x_I2C_I2FDR (volatile u8 *) (0xFC058004) // Freq Divider +-#define MCF532x_I2C_I2CR (volatile u8 *) (0xFC058008) // Control +-#define MCF532x_I2C_I2SR (volatile u8 *) (0xFC05800C) // Status +-#define MCF532x_I2C_I2DR (volatile u8 *) (0xFC058010) // Data I/O ++#define MCF_I2C_I2ADR (volatile u8 *) (0xFC058000) /* Address */ ++#define MCF_I2C_I2FDR (volatile u8 *) (0xFC058004) /* Freq Divider */ ++#define MCF_I2C_I2CR (volatile u8 *) (0xFC058008) /* Control */ ++#define MCF_I2C_I2SR (volatile u8 *) (0xFC05800C) /* Status */ ++#define MCF_I2C_I2DR (volatile u8 *) (0xFC058010) /* Data I/O */ + + /* Bit level definitions and macros */ +-#define MCF532x_I2C_I2ADR_ADDR(x) (((x)&0x7F)<<0x01) ++#define MCF_I2C_I2ADR_ADDR(x) (((x)&0x7F)<<0x01) + +-#define MCF532x_I2C_I2FDR_IC(x) (((x)&0x3F)) ++#define MCF_I2C_I2FDR_IC(x) (((x)&0x3F)) + +-#define MCF532x_I2C_I2CR_IEN (0x80) // I2C enable +-#define MCF532x_I2C_I2CR_IIEN (0x40) // interrupt enable +-#define MCF532x_I2C_I2CR_MSTA (0x20) // master/slave mode +-#define MCF532x_I2C_I2CR_MTX (0x10) // transmit/receive mode +-#define MCF532x_I2C_I2CR_TXAK (0x08) // transmit acknowledge enable +-#define MCF532x_I2C_I2CR_RSTA (0x04) // repeat start +- +-#define MCF532x_I2C_I2SR_ICF (0x80) // data transfer bit +-#define MCF532x_I2C_I2SR_IAAS (0x40) // I2C addressed as a slave +-#define MCF532x_I2C_I2SR_IBB (0x20) // I2C bus busy +-#define MCF532x_I2C_I2SR_IAL (0x10) // aribitration lost +-#define MCF532x_I2C_I2SR_SRW (0x04) // slave read/write +-#define MCF532x_I2C_I2SR_IIF (0x02) // I2C interrupt +-#define MCF532x_I2C_I2SR_RXAK (0x01) // received acknowledge ++#define MCF_I2C_I2CR_IEN (0x80) /* I2C enable */ ++#define MCF_I2C_I2CR_IIEN (0x40) /* interrupt enable */ ++#define MCF_I2C_I2CR_MSTA (0x20) /* master/slave mode */ ++#define MCF_I2C_I2CR_MTX (0x10) /* transmit/receive mode */ ++#define MCF_I2C_I2CR_TXAK (0x08) /* transmit acknowledge enable */ ++#define MCF_I2C_I2CR_RSTA (0x04) /* repeat start */ ++ ++#define MCF_I2C_I2SR_ICF (0x80) /* data transfer bit */ ++#define MCF_I2C_I2SR_IAAS (0x40) /* I2C addressed as a slave */ ++#define MCF_I2C_I2SR_IBB (0x20) /* I2C bus busy */ ++#define MCF_I2C_I2SR_IAL (0x10) /* aribitration lost */ ++#define MCF_I2C_I2SR_SRW (0x04) /* slave read/write */ ++#define MCF_I2C_I2SR_IIF (0x02) /* I2C interrupt */ ++#define MCF_I2C_I2SR_RXAK (0x01) /* received acknowledge */ + + #define MCF532x_PAR_FECI2C (volatile u8 *) (0xFC0A4053) + +@@ -2234,5 +2247,36 @@ + #define MCF_EPORT_EPFR_EPF6 (0x40) + #define MCF_EPORT_EPFR_EPF7 (0x80) + ++/********************************************************************* ++ * ++ * Cross-Bar Switch (XBS) ++ * ++ *********************************************************************/ ++#define MCF_XBS_PRS1 MCF_REG32(0xFC004100) ++#define MCF_XBS_CRS1 MCF_REG32(0xFC004110) ++#define MCF_XBS_PRS4 MCF_REG32(0xFC004400) ++#define MCF_XBS_CRS4 MCF_REG32(0xFC004410) ++#define MCF_XBS_PRS6 MCF_REG32(0xFC004600) ++#define MCF_XBS_CRS6 MCF_REG32(0xFC004610) ++#define MCF_XBS_PRS7 MCF_REG32(0xFC004700) ++#define MCF_XBS_CRS7 MCF_REG32(0xFC004710) ++ ++#define MCF_XBS_PRIO_FACTTEST(x) (((x)&0x7) << 28) ++#define MCF_XBS_PRIO_USBOTG(x) (((x)&0x7) << 24) ++#define MCF_XBS_PRIO_USBHOST(x) (((x)&0x7) << 20) ++#define MCF_XBS_PRIO_LCD(x) (((x)&0x7) << 16) ++#define MCF_XBS_PRIO_FEC(x) (((x)&0x7) << 8) ++#define MCF_XBS_PRIO_EDMA(x) (((x)&0x7) << 4) ++#define MCF_XBS_PRIO_CORE(x) (((x)&0x7) << 0) ++ ++#define MCF_PRIO_LVL_1 (0) ++#define MCF_PRIO_LVL_2 (1) ++#define MCF_PRIO_LVL_3 (2) ++#define MCF_PRIO_LVL_4 (3) ++#define MCF_PRIO_LVL_5 (4) ++#define MCF_PRIO_LVL_6 (5) ++#define MCF_PRIO_LVL_7 (6) ++ ++ + /********************************************************************/ + #endif /* m532xsim_h */ +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/mcfcache.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/mcfcache.h 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/mcfcache.h 2009-02-08 00:00:48.000000000 -0500 +@@ -60,7 +60,7 @@ + nop + movel #0x0000c020, %d0 /* Set SDRAM cached only */ + movec %d0, %ACR0 +- movel #0xff00c000, %d0 /* Cache Flash also */ ++ movel #0x00000000, %d0 /* No other regions cached */ + movec %d0, %ACR1 + movel #0x80000200, %d0 /* Setup cache mask */ + movec %d0, %CACR /* Enable cache */ +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/mcfuart.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/mcfuart.h 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/mcfuart.h 2009-02-08 00:00:48.000000000 -0500 +@@ -12,7 +12,6 @@ + #define mcfuart_h + /****************************************************************************/ + +- + /* + * Define the base address of the UARTS within the MBAR address + * space. +@@ -33,7 +32,7 @@ + #define MCFUART_BASE2 0x240 /* Base address of UART2 */ + #define MCFUART_BASE3 0x280 /* Base address of UART3 */ + #elif defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) +-#if defined(CONFIG_NETtel) || defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) ++#if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3) + #define MCFUART_BASE1 0x200 /* Base address of UART1 */ + #define MCFUART_BASE2 0x1c0 /* Base address of UART2 */ + #else +Index: linux-2.6.24.7-rt27/mm/nommu.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/nommu.c 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/nommu.c 2009-02-08 00:00:48.000000000 -0500 +@@ -952,6 +952,16 @@ unsigned long do_mmap_pgoff(struct file + if (ret < 0) + goto error; + ++ /* ++ * If the driver implemented his own mmap(), the ++ * base addr could have changed. Therefor ++ * vm_end musst be updated to. ++ * ++ * See comment of DaveM in mm/mmap.c as reference ++ */ ++ if(addr != vma->vm_start) ++ vma->vm_end = vma->vm_start + len; ++ + /* okay... we have a mapping; now we have to register it */ + result = (void *) vma->vm_start; + +Index: linux-2.6.24.7-rt27/mm/page_alloc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/page_alloc.c 2009-02-08 00:00:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/page_alloc.c 2009-02-08 00:00:48.000000000 -0500 +@@ -4317,6 +4317,14 @@ void *__init alloc_large_system_hash(con + if (numentries > max) + numentries = max; + ++ /* ++ * we will allocate at least a page (even on low memory systems) ++ * so do a fixup here to ensure we utilise the space that will be ++ * allocated, this also prevents us reporting -ve orders ++ */ ++ if (bucketsize * numentries < PAGE_SIZE) ++ numentries = (PAGE_SIZE + bucketsize - 1) / bucketsize; ++ + log2qty = ilog2(numentries); + + do { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0507-ftrace-stop-trace-on-crash.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0507-ftrace-stop-trace-on-crash.patch @@ -0,0 +1,155 @@ +Subject: fix-tracer-wreckage-wtf-is-this-code-all-features.patch +From: Thomas Gleixner +Date: Thu, 19 Jun 2008 19:24:14 +0200 + +Signed-off-by: Thomas Gleixner +--- + arch/x86/kernel/traps_32.c | 2 ++ + arch/x86/kernel/traps_64.c | 3 +++ + include/linux/ftrace.h | 11 ++++++++--- + kernel/trace/ftrace.c | 17 +++++++++++++++++ + kernel/trace/trace.c | 31 +++++++++++++++++++++++++++++++ + 5 files changed, 61 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/traps_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/traps_32.c 2009-02-08 00:03:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/traps_32.c 2009-02-08 00:04:52.000000000 -0500 +@@ -385,6 +385,8 @@ void die(const char * str, struct pt_reg + static int die_counter; + unsigned long flags; + ++ ftrace_stop(); ++ + oops_enter(); + + if (die.lock_owner != raw_smp_processor_id()) { +Index: linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/traps_64.c 2009-02-08 00:03:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c 2009-02-08 00:04:52.000000000 -0500 +@@ -524,6 +524,9 @@ void __kprobes oops_end(unsigned long fl + void __kprobes __die(const char * str, struct pt_regs * regs, long err) + { + static int die_counter; ++ ++ ftrace_stop(); ++ + printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff,++die_counter); + #ifdef CONFIG_PREEMPT + printk("PREEMPT "); +Index: linux-2.6.24.7-rt27/include/linux/ftrace.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/ftrace.h 2009-02-08 00:04:48.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/ftrace.h 2009-02-08 00:04:52.000000000 -0500 +@@ -38,12 +38,18 @@ extern void mcount(void); + void ftrace_enable(void); + void ftrace_disable(void); + ++/* totally disable ftrace - can not re-enable after this */ ++void ftrace_kill(void); ++void __ftrace_kill(void); ++ + #else /* !CONFIG_FTRACE */ + # define register_ftrace_function(ops) do { } while (0) + # define unregister_ftrace_function(ops) do { } while (0) + # define clear_ftrace_function(ops) do { } while (0) + # define ftrace_enable() do { } while (0) + # define ftrace_disable() do { } while (0) ++# define ftrace_kill() do { } while (0) ++# define __ftrace_kill() do { } while (0) + #endif /* CONFIG_FTRACE */ + + #ifdef CONFIG_DYNAMIC_FTRACE +@@ -90,9 +96,6 @@ void ftrace_enable_daemon(void); + # define ftrace_enable_daemon() do { } while (0) + #endif + +-/* totally disable ftrace - can not re-enable after this */ +-void ftrace_kill(void); +- + static inline void tracer_disable(void) + { + #ifdef CONFIG_FTRACE +@@ -138,9 +141,11 @@ static inline void tracer_disable(void) + #ifdef CONFIG_TRACING + extern void + ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3); ++void ftrace_stop(void); + #else + static inline void + ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) { } ++static inline void ftrace_stop(void) { } + #endif + + #ifdef CONFIG_EVENT_TRACER +Index: linux-2.6.24.7-rt27/kernel/trace/ftrace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/ftrace.c 2009-02-08 00:04:48.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/ftrace.c 2009-02-08 00:04:52.000000000 -0500 +@@ -1490,6 +1490,23 @@ void ftrace_kill(void) + } + + /** ++ * __ftrace_kill - shutdown ftrace in a mean fashion ++ * ++ * In case of system failure we want to stop ftrace as soon as ++ * possible. This is like ftrace_kill but does not grab the ++ * mutexes nor does it call the kstop machine. ++ * ++ * This one is save to use in atomic. ++ */ ++void __ftrace_kill(void) ++{ ++ ftrace_disabled = 1; ++ ftrace_enabled = 0; ++ ++ clear_ftrace_function(); ++} ++ ++/** + * register_ftrace_function - register a function for profiling + * @ops - ops structure that holds the function for profiling. + * +Index: linux-2.6.24.7-rt27/kernel/trace/trace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace.c 2009-02-08 00:04:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace.c 2009-02-08 00:04:52.000000000 -0500 +@@ -3243,6 +3243,37 @@ static __init void tracer_init_debugfs(v + #endif + } + ++/** ++ * ftrace_stop - called when we need to drastically disable the tracer. ++ */ ++void ftrace_stop(void) ++{ ++ struct tracer *saved_tracer = current_trace; ++ struct trace_array *tr = &global_trace; ++ struct trace_array_cpu *data; ++ int i; ++ ++ __ftrace_kill(); ++ for_each_tracing_cpu(i) { ++ data = tr->data[i]; ++ atomic_inc(&data->disabled); ++ } ++ tracer_enabled = 0; ++ ++ /* ++ * TODO: make a safe method to ctrl_update. ++ * ctrl_update may schedule, but currently only ++ * does when ftrace is enabled. ++ */ ++ if (tr->ctrl) { ++ tr->ctrl = 0; ++ if (saved_tracer && saved_tracer->ctrl_update) ++ saved_tracer->ctrl_update; ++ } ++ ++ ++} ++ + static int trace_alloc_page(void) + { + struct trace_array_cpu *data; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0062-ftrace-function-record-nop.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0062-ftrace-function-record-nop.patch @@ -0,0 +1,39 @@ +From: Steven Rostedt +Subject: ftrace: define function trace nop + +When CONFIG_FTRACE is not enabled, the tracing_start_functon_trace +and tracing_stop_function_Trace should be nops. + +Signed-off-by: Steven Rostedt +--- + kernel/trace/trace.h | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/trace/trace.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace.h 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace.h 2009-02-08 00:01:12.000000000 -0500 +@@ -223,8 +223,6 @@ void trace_function(struct trace_array * + unsigned long parent_ip, + unsigned long flags); + +-void tracing_start_function_trace(void); +-void tracing_stop_function_trace(void); + void tracing_start_cmdline_record(void); + void tracing_stop_cmdline_record(void); + int register_tracer(struct tracer *type); +@@ -241,6 +239,14 @@ void update_max_tr_single(struct trace_a + + extern cycle_t ftrace_now(int cpu); + ++#ifdef CONFIG_FTRACE ++void tracing_start_function_trace(void); ++void tracing_stop_function_trace(void); ++#else ++# define tracing_start_function_trace() do { } while (0) ++# define tracing_stop_function_trace() do { } while (0) ++#endif ++ + #ifdef CONFIG_CONTEXT_SWITCH_TRACER + typedef void + (*tracer_switch_func_t)(void *private, --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0029-0015-sched-wake-balance-fixes.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0029-0015-sched-wake-balance-fixes.patch @@ -0,0 +1,87 @@ +From ec30f584b4d095d00067850f07f3dc65d587939b Mon Sep 17 00:00:00 2001 +From: Gregory Haskins +Date: Tue, 11 Dec 2007 10:02:38 +0100 +Subject: [PATCH] sched: wake-balance fixes + +We have logic to detect whether the system has migratable tasks, but we are +not using it when deciding whether to push tasks away. So we add support +for considering this new information. + +Signed-off-by: Gregory Haskins +Signed-off-by: Steven Rostedt +Signed-off-by: Ingo Molnar + +--- + kernel/sched.c | 2 ++ + kernel/sched_rt.c | 10 ++++++++-- + 2 files changed, 10 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:00:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:00:57.000000000 -0500 +@@ -270,6 +270,7 @@ struct rt_rq { + unsigned long rt_nr_migratory; + /* highest queued rt task prio */ + int highest_prio; ++ int overloaded; + }; + + /* +@@ -6744,6 +6745,7 @@ void __init sched_init(void) + rq->migration_thread = NULL; + INIT_LIST_HEAD(&rq->migration_queue); + rq->rt.highest_prio = MAX_RT_PRIO; ++ rq->rt.overloaded = 0; + #endif + atomic_set(&rq->nr_iowait, 0); + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:00:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:00:57.000000000 -0500 +@@ -16,6 +16,7 @@ static inline cpumask_t *rt_overload(voi + } + static inline void rt_set_overload(struct rq *rq) + { ++ rq->rt.overloaded = 1; + cpu_set(rq->cpu, rt_overload_mask); + /* + * Make sure the mask is visible before we set +@@ -32,6 +33,7 @@ static inline void rt_clear_overload(str + /* the order here really doesn't matter */ + atomic_dec(&rto_count); + cpu_clear(rq->cpu, rt_overload_mask); ++ rq->rt.overloaded = 0; + } + + static void update_rt_migration(struct rq *rq) +@@ -444,6 +446,9 @@ static int push_rt_task(struct rq *rq) + + assert_spin_locked(&rq->lock); + ++ if (!rq->rt.overloaded) ++ return 0; ++ + next_task = pick_next_highest_task_rt(rq, -1); + if (!next_task) + return 0; +@@ -671,7 +676,7 @@ static void schedule_tail_balance_rt(str + * the lock was owned by prev, we need to release it + * first via finish_lock_switch and then reaquire it here. + */ +- if (unlikely(rq->rt.rt_nr_running > 1)) { ++ if (unlikely(rq->rt.overloaded)) { + spin_lock_irq(&rq->lock); + push_rt_tasks(rq); + spin_unlock_irq(&rq->lock); +@@ -683,7 +688,8 @@ static void wakeup_balance_rt(struct rq + { + if (unlikely(rt_task(p)) && + !task_running(rq, p) && +- (p->prio >= rq->curr->prio)) ++ (p->prio >= rq->rt.highest_prio) && ++ rq->rt.overloaded) + push_rt_tasks(rq); + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0307-highmem-revert-mainline.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0307-highmem-revert-mainline.patch @@ -0,0 +1,24 @@ +--- + mm/highmem.c | 9 --------- + 1 file changed, 9 deletions(-) + +Index: linux-2.6.24.7-rt27/mm/highmem.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/highmem.c 2009-02-07 23:59:51.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/highmem.c 2009-02-08 00:03:16.000000000 -0500 +@@ -104,15 +104,6 @@ static void flush_all_zero_pkmaps(void) + flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP)); + } + +-/* Flush all unused kmap mappings in order to remove stray +- mappings. */ +-void kmap_flush_unused(void) +-{ +- spin_lock(&kmap_lock); +- flush_all_zero_pkmaps(); +- spin_unlock(&kmap_lock); +-} +- + static inline unsigned long map_new_virtual(struct page *page) + { + unsigned long vaddr; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0288-2.6.21-rc6-lockless5-lockless-probe.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0288-2.6.21-rc6-lockless5-lockless-probe.patch @@ -0,0 +1,29 @@ +From: Nick Piggin +Subject: [patch 5/9] mm: lockless probe + +Probing pages and radix_tree_tagged are lockless operations with the +lockless radix-tree. Convert these users to RCU locking rather than +using tree_lock. + +Signed-off-by: Nick Piggin + +--- + mm/readahead.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/mm/readahead.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/readahead.c 2009-02-07 23:59:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/readahead.c 2009-02-08 00:03:04.000000000 -0500 +@@ -376,9 +376,9 @@ ondemand_readahead(struct address_space + if (hit_readahead_marker) { + pgoff_t start; + +- read_lock_irq(&mapping->tree_lock); ++ rcu_read_lock(); + start = radix_tree_next_hole(&mapping->page_tree, offset, max+1); +- read_unlock_irq(&mapping->tree_lock); ++ rcu_read_unlock(); + + if (!start || start - offset > max) + return 0; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0320-only-run-softirqs-from-irq-thread-when-irq-affinity-is-set.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0320-only-run-softirqs-from-irq-thread-when-irq-affinity-is-set.patch @@ -0,0 +1,168 @@ +From linux-rt-users-owner@vger.kernel.org Wed Aug 8 22:43:28 2007 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.1.7-deb (2006-10-05) on debian +X-Spam-Level: +X-Spam-Status: No, score=0.0 required=5.0 tests=AWL autolearn=unavailable + version=3.1.7-deb +Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by + mail.tglx.de (Postfix) with ESMTP id 6193665C3D9; Wed, 8 Aug 2007 22:43:28 + +0200 (CEST) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id + S1755519AbXHHUn0 (ORCPT + 1 other); + Wed, 8 Aug 2007 16:43:26 -0400 +Received: (majordomo@vger.kernel.org) by vger.kernel.org id + S1755399AbXHHUn0 (ORCPT ); Wed, 8 Aug 2007 + 16:43:26 -0400 +Received: from ms-smtp-03.nyroc.rr.com ([24.24.2.57]:59763 "EHLO + ms-smtp-03.nyroc.rr.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with + ESMTP id S1754194AbXHHUnY (ORCPT ); + Wed, 8 Aug 2007 16:43:24 -0400 +Received: from gandalf.stny.rr.com (cpe-24-94-51-176.stny.res.rr.com + [24.94.51.176]) by ms-smtp-03.nyroc.rr.com (8.13.6/8.13.6) with ESMTP id + l78KgX4S011873; Wed, 8 Aug 2007 16:42:33 -0400 (EDT) +Received: from localhost ([127.0.0.1] ident=rostedt) by gandalf.stny.rr.com + with esmtp (Exim 4.67) (envelope-from ) id + 1IIsMT-0003mx-ET; Wed, 08 Aug 2007 16:42:33 -0400 +Subject: [PATCH RT] Only run softirqs from the irq thread if the irq + affinity is set to 1 CPU +From: Steven Rostedt +To: Ingo Molnar +Cc: RT , LKML , Thomas Gleixner , john stultz +Content-Type: text/plain +Date: Wed, 08 Aug 2007 16:42:32 -0400 +Message-Id: <1186605752.29097.18.camel@localhost.localdomain> +Mime-Version: 1.0 +X-Mailer: Evolution 2.10.2 +X-Virus-Scanned: Symantec AntiVirus Scan Engine +Sender: linux-rt-users-owner@vger.kernel.org +Precedence: bulk +X-Mailing-List: linux-rt-users@vger.kernel.org +X-Filter-To: .Kernel.rt-users +X-Evolution-Source: imap://tglx%40linutronix.de@localhost:8993/ +Content-Transfer-Encoding: 8bit + +Ingo and Thomas, + +John and I have been discussing all the "run softirq from IRQ thread" +lately and discovered something nasty. + +Now it is a nice optimization to run softirqs from the IRQ thread, but +it may not be feasible because of the semantics of the IRQ thread +compared with the softirq thread. Namely, the softirq thread is bound to +a single CPU and the IRQ thread is not. + +We use to think that it would be fine to simply bind an IRQ thread to a +single CPU, either at the start of the IRQ thread code, or just while it +is running the softirq code. But this has a major flaw as John Stultz +discovered. + +If a RT hog that is of higher priority than the IRQ thread preempts the +IRQ thread while it is bound to the CPU (more likely with the latest +code that always binds the IRQ thread to 1 CPU), then that IRQ is, in +essence, masked. That means no more actions will be taken place by that +IRQ while the RT thread is running. Normally, one would expect, that if +the IRQ has its affinity set to all CPUS, if a RT thread were to preempt +the IRQ thread and run for a long time, it would be expected that the +IRQ thread would migrate to another CPU and finish. Letting more +interrupts from the IRQ line in (remember that the IRQ line is masked +until the IRQ finishes its handler). + +This patch will only run the softirq functions if the IRQ thread and the +softirq thread have the same priority **and** the IRQ thread is already +bound to a single CPU. If we are running on UP or the IRQ thread is +bound to a single CPU, we already have the possibility of having a RT +hog starve the IRQ. But we should not add that scenario when the IRQ +thread has its affinity set to run on other CPUS that don't have RT hogs +on them. + +Signed-off-by: Steven Rostedt + +--- + kernel/irq/manage.c | 32 +++++++++++++++++++++----------- + kernel/softirq.c | 9 ++++++++- + 2 files changed, 29 insertions(+), 12 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/irq/manage.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/irq/manage.c 2009-02-08 00:03:21.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/irq/manage.c 2009-02-08 00:03:22.000000000 -0500 +@@ -775,17 +775,28 @@ static int do_irqd(void * __desc) + { + struct sched_param param = { 0, }; + struct irq_desc *desc = __desc; ++ int run_softirq = 1; + + #ifdef CONFIG_SMP +- cpumask_t cpus_allowed, mask; ++ cpumask_t cpus_allowed; + + cpus_allowed = desc->affinity; + /* +- * Restrict it to one cpu so we avoid being migrated inside of +- * do_softirq_from_hardirq() ++ * If the irqd is bound to one CPU we let it run softirqs ++ * that have the same priority as the irqd thread. We do ++ * not run it if the irqd is bound to more than one CPU ++ * due to the fact that it can ++ * 1) migrate to other CPUS while running the softirqd ++ * 2) if we pin the irqd to a CPU to run the softirqd, then ++ * we risk a high priority process from waking up and ++ * preempting the irqd. Although the irqd may be able to ++ * run on other CPUS due to its irq affinity, it will not ++ * be able to since we bound it to a CPU to run softirqs. ++ * So a RT hog could starve the irqd from running on ++ * other CPUS that it's allowed to run on. + */ +- mask = cpumask_of_cpu(first_cpu(desc->affinity)); +- set_cpus_allowed(current, mask); ++ if (cpus_weight(cpus_allowed) != 1) ++ run_softirq = 0; /* turn it off */ + #endif + current->flags |= PF_NOFREEZE | PF_HARDIRQ; + +@@ -801,7 +812,8 @@ static int do_irqd(void * __desc) + do { + set_current_state(TASK_INTERRUPTIBLE); + do_hardirq(desc); +- do_softirq_from_hardirq(); ++ if (run_softirq) ++ do_softirq_from_hardirq(); + } while (current->state == TASK_RUNNING); + + local_irq_enable_nort(); +@@ -812,12 +824,10 @@ static int do_irqd(void * __desc) + if (!cpus_equal(cpus_allowed, desc->affinity)) { + cpus_allowed = desc->affinity; + /* +- * Restrict it to one cpu so we avoid being +- * migrated inside of +- * do_softirq_from_hardirq() ++ * Only allow the irq thread to run the softirqs ++ * if it is bound to a single CPU. + */ +- mask = cpumask_of_cpu(first_cpu(desc->affinity)); +- set_cpus_allowed(current, mask); ++ run_softirq = (cpus_weight(cpus_allowed) == 1); + } + #endif + schedule(); +Index: linux-2.6.24.7-rt27/kernel/softirq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/softirq.c 2009-02-08 00:03:21.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/softirq.c 2009-02-08 00:03:22.000000000 -0500 +@@ -114,7 +114,14 @@ static void wakeup_softirqd(int softirq) + * context processing it later on. + */ + if ((current->flags & PF_HARDIRQ) && !hardirq_count() && +- (tsk->normal_prio == current->normal_prio)) ++ (tsk->normal_prio == current->normal_prio) && ++ /* ++ * The hard irq thread must be bound to a single CPU to run ++ * a softirq. Don't worry about locking, the irq thread ++ * should be the only one to modify the cpus_allowed, when ++ * the irq affinity changes. ++ */ ++ (cpus_weight(current->cpus_allowed) == 1)) + return; + #endif + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0408-kernel-bug-after-entering-something-from-login.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0408-kernel-bug-after-entering-something-from-login.patch @@ -0,0 +1,74 @@ +From r.schwebel@pengutronix.de Fri Jan 11 20:50:39 2008 +Date: Fri, 11 Jan 2008 23:35:49 +0100 +From: Robert Schwebel +To: Steven Rostedt +Cc: linux-rt-users@vger.kernel.org +Subject: lost patch for mpc52xx spinlock + + [ The following text is in the "iso-8859-15" character set. ] + [ Your display is set for the "iso-8859-1" character set. ] + [ Some special characters may be displayed incorrectly. ] + +Hi Steven, + +this patch from tglx seems to got lost, can you add it to the next +release? + +Robert +-- + Robert Schwebel | http://www.pengutronix.de + OSADL Testlab @ Pengutronix | http://www.osadl.org + +----------8<---------- + +Subject: Re: Kernel Bug when entering something after login +From: Thomas Gleixner +To: Juergen Beisert +Cc: linux-rt-users@vger.kernel.org +In-Reply-To: <200707251900.47704.juergen127@kreuzholzen.de> +References: <200707251900.47704.juergen127@kreuzholzen.de> +Date: Wed, 25 Jul 2007 21:06:38 +0200 +Message-Id: <1185390398.3227.8.camel@chaos> + +On Wed, 2007-07-25 at 19:00 +0200, Juergen Beisert wrote: +> [c0245db0] [c01bdb98] rt_spin_lock_slowlock+0x4c/0x224 (unreliable) +> [c0245e10] [c011823c] uart_start+0x24/0x48 +> [c0245e30] [c0113ff4] n_tty_receive_buf+0x170/0xfd4 +> [c0245ef0] [c010f0dc] flush_to_ldisc+0xe0/0x130 +> [c0245f20] [c011b51c] mpc52xx_uart_int+0x194/0x350 +> [c0245f50] [c0046dfc] handle_IRQ_event+0x6c/0x110 +> [c0245f80] [c00475ec] thread_simple_irq+0x90/0xf8 +> [c0245fa0] [c00479a0] do_irqd+0x34c/0x3cc +> [c0245fd0] [c0033380] kthread+0x48/0x84 +> [c0245ff0] [c00104ac] kernel_thread+0x44/0x60 +> Instruction dump: +> 70090008 40820144 80010064 bb410048 38210060 7c0803a6 4e800020 801c0010 +> 5400003a 7c001278 7c000034 5400d97e <0f000000> 39600004 91610008 80010008 +> note: IRQ-131[93] exited with preempt_count 1 + +Yup. That's a deadlock. In mainline this does not happen, as the +spinlock is a NOP. Turn on CONFIG_PROVE_LOCKING in mainline and you see +the problem as well. + +Solution below + + tglx + +--- + drivers/serial/mpc52xx_uart.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: linux-2.6.24.7-rt27/drivers/serial/mpc52xx_uart.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/serial/mpc52xx_uart.c 2009-02-07 23:59:44.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/serial/mpc52xx_uart.c 2009-02-08 00:04:04.000000000 -0500 +@@ -501,7 +501,9 @@ mpc52xx_uart_int_rx_chars(struct uart_po + } + } + ++ spin_unlock(&port->lock); + tty_flip_buffer_push(tty); ++ spin_lock(&port->lock); + + return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY; + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0037-0024-sched-clean-up-kernel-sched_rt.c.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0037-0024-sched-clean-up-kernel-sched_rt.c.patch @@ -0,0 +1,50 @@ +From 602b4d5727366261c3a6aca52189ae6304adf38c Mon Sep 17 00:00:00 2001 +From: Ingo Molnar +Date: Tue, 11 Dec 2007 10:02:39 +0100 +Subject: [PATCH] sched: clean up kernel/sched_rt.c + +clean up whitespace damage and missing comments in kernel/sched_rt.c. + +Signed-off-by: Ingo Molnar + +--- + kernel/sched_rt.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:01:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:01:01.000000000 -0500 +@@ -4,16 +4,24 @@ + */ + + #ifdef CONFIG_SMP ++ ++/* ++ * The "RT overload" flag: it gets set if a CPU has more than ++ * one runnable RT task. ++ */ + static cpumask_t rt_overload_mask; + static atomic_t rto_count; ++ + static inline int rt_overloaded(void) + { + return atomic_read(&rto_count); + } ++ + static inline cpumask_t *rt_overload(void) + { + return &rt_overload_mask; + } ++ + static inline void rt_set_overload(struct rq *rq) + { + rq->rt.overloaded = 1; +@@ -28,6 +36,7 @@ static inline void rt_set_overload(struc + wmb(); + atomic_inc(&rto_count); + } ++ + static inline void rt_clear_overload(struct rq *rq) + { + /* the order here really doesn't matter */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0157-preempt-irqs-ppc-preempt-schedule-irq-entry-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0157-preempt-irqs-ppc-preempt-schedule-irq-entry-fix.patch @@ -0,0 +1,105 @@ +From tsutomu.owa@toshiba.co.jp Tue May 22 13:47:39 2007 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.1.7-deb (2006-10-05) on debian +X-Spam-Level: +X-Spam-Status: No, score=0.0 required=5.0 tests=UNPARSEABLE_RELAY + autolearn=unavailable version=3.1.7-deb +Received: from inet-tsb5.toshiba.co.jp (inet-tsb5.toshiba.co.jp + [202.33.96.24]) by mail.tglx.de (Postfix) with ESMTP id 57F7E65C065 for + ; Tue, 22 May 2007 13:47:39 +0200 (CEST) +Received: from tsb-wall.toshiba.co.jp ([133.199.160.134]) by + inet-tsb5.toshiba.co.jp with ESMTP id l4MBlERT003242; Tue, 22 May 2007 + 20:47:14 +0900 (JST) +Received: (from root@localhost) by tsb-wall.toshiba.co.jp id + l4MBlEQK014361; Tue, 22 May 2007 20:47:14 +0900 (JST) +Received: from ovp1.toshiba.co.jp [133.199.192.124] by + tsb-wall.toshiba.co.jp with ESMTP id WAA14360; Tue, 22 May 2007 20:47:14 + +0900 +Received: from mx2.toshiba.co.jp (localhost [127.0.0.1]) by + ovp1.toshiba.co.jp with ESMTP id l4MBlEDs007674; Tue, 22 May 2007 20:47:14 + +0900 (JST) +Received: from rdcgw.rdc.toshiba.co.jp by toshiba.co.jp id l4MBlDm9015993; + Tue, 22 May 2007 20:47:13 +0900 (JST) +Received: from island.swc.toshiba.co.jp by rdcgw.rdc.toshiba.co.jp + (8.8.8p2+Sun/3.7W) with ESMTP id UAA17003; Tue, 22 May 2007 20:47:13 +0900 + (JST) +Received: from forest.toshiba.co.jp (forest [133.196.122.2]) by + island.swc.toshiba.co.jp (Postfix) with ESMTP id 6A26B40002; Tue, 22 May + 2007 20:47:13 +0900 (JST) +Date: Tue, 22 May 2007 20:47:13 +0900 +Message-ID: +From: Tsutomu OWA +To: linuxppc-dev@ozlabs.org, linux-kernel@vger.kernel.org +Cc: mingo@elte.hu, tglx@linutronix.de +Subject: [PATCH] powerpc 2.6.21-rt6: replace preempt_schedule w/ + preempt_schedule_irq +User-Agent: Wanderlust/2.8.1 (Something) Emacs/20.7 Mule/4.0 (HANANOEN) +Organization: Software Engineering Center, TOSHIBA. +MIME-Version: 1.0 (generated by SEMI 1.14.4 - "Hosorogi") +Content-Type: text/plain; charset=US-ASCII +X-Evolution-Source: imap://tglx%40linutronix.de@localhost:8993/ +Content-Transfer-Encoding: 8bit + + +Hi Ingo and Thomas, + +Please apply. + +Replace preempt_schedule() w/ preempt_schedule_irq() in irq return path, +to avoid irq-entry recursion and stack overflow problems for powerpc64. +It hits when doing netperf from another machine to the machine running rt kernel. + +This patch applies on top of linux-2.6.21 + patch-2.6.21-rt6. + +Compile, boot and netperf tested on celleb. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +~ $ uname -a +Linux Linux 2.6.21-rt6 #1 SMP PREEMPT RT Tue May 22 19:18:00 JST 2007 ppc64 unkn +own +~ $ Unable to handle kernel paging request for data at address 0xc0000180004cd9b +0 +Faulting instruction address: 0xc00000000003da48 +cpu 0x0: Vector: 300 (Data Access) at [c00000000fffba00] + pc: c00000000003da48: .resched_task+0x34/0xc4 + lr: c0000000000410b4: .try_to_wake_up+0x4cc/0x5a8 + sp: c00000000fffbc80 + msr: 9000000000001032 + dar: c0000180004cd9b0 + dsisr: 40000000 + current = 0xc00000000244ed20 + paca = 0xc0000000004cd980 + pid = 425, comm = netserver +enter ? for help +[c00000000fffbd00] c0000000000410b4 .try_to_wake_up+0x4cc/0x5a8 +[c00000000fffbde0] c0000000000880c8 .redirect_hardirq+0x68/0x88 +[c00000000fffbe60] c00000000008aec8 .handle_level_irq+0x13c/0x220 +[c00000000fffbf00] c000000000032538 .spider_irq_cascade+0x98/0xec +[c00000000fffbf90] c000000000022280 .call_handle_irq+0x1c/0x2c +[c0000000025abea0] c00000000000c33c .do_IRQ+0xc8/0x17c +[c0000000025abf30] c00000000000444c hardware_interrupt_entry+0x18/0x4c +--- + arch/powerpc/kernel/entry_64.S | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_64.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/entry_64.S 2009-02-08 00:01:55.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_64.S 2009-02-08 00:01:56.000000000 -0500 +@@ -579,14 +579,9 @@ do_work: + cmpdi r0,0 + crandc eq,cr1*4+eq,eq + bne restore +- /* here we are preempting the current task */ + 1: +- li r0,1 +- stb r0,PACASOFTIRQEN(r13) +- stb r0,PACAHARDIRQEN(r13) +- ori r10,r10,MSR_EE +- mtmsrd r10,1 /* reenable interrupts */ +- bl .preempt_schedule ++ /* preempt_schedule_irq() expects interrupts disabled. */ ++ bl .preempt_schedule_irq + mfmsr r10 + clrrdi r9,r1,THREAD_SHIFT + rldicl r10,r10,48,1 /* disable interrupts again */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0086-spinlock-trylock-cleanup-sungem.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0086-spinlock-trylock-cleanup-sungem.patch @@ -0,0 +1,20 @@ +--- + drivers/net/sungem.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/drivers/net/sungem.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/net/sungem.c 2009-02-08 00:00:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/net/sungem.c 2009-02-08 00:01:24.000000000 -0500 +@@ -1031,10 +1031,8 @@ static int gem_start_xmit(struct sk_buff + (csum_stuff_off << 21)); + } + +- local_irq_save(flags); +- if (!spin_trylock(&gp->tx_lock)) { ++ if (!spin_trylock_irqsave(&gp->tx_lock, flags)) { + /* Tell upper layer to requeue */ +- local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } + /* We raced with gem_do_stop() */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0347-powerpc-rearrange-thread-flags-to-work-with-andi-instruction.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0347-powerpc-rearrange-thread-flags-to-work-with-andi-instruction.patch @@ -0,0 +1,46 @@ +From tony@bakeyournoodle.com Wed Sep 26 10:25:29 2007 +Date: Tue, 04 Sep 2007 17:09:02 +1000 +From: Tony Breeds +To: linux-rt-users@vger.kernel.org +Subject: [PATCH 1/5] [POWERPC] Rearrange thread flags to work with the + "andi" instruction. + +Signed-off-by: Tony Breeds + +--- + + include/asm-powerpc/thread_info.h | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/include/asm-powerpc/thread_info.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-powerpc/thread_info.h 2009-02-08 00:02:28.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-powerpc/thread_info.h 2009-02-08 00:03:36.000000000 -0500 +@@ -121,11 +121,11 @@ static inline struct thread_info *curren + #define TIF_RESTOREALL 11 /* Restore all regs (implies NOERROR) */ + #define TIF_NOERROR 12 /* Force successful syscall return */ + #define TIF_RESTORE_SIGMASK 13 /* Restore signal mask in do_signal */ +-#define TIF_FREEZE 14 /* Freezing for suspend */ +-#define TIF_RUNLATCH 15 /* Is the runlatch enabled? */ +-#define TIF_ABI_PENDING 16 /* 32/64 bit switch needed */ + #define TIF_NEED_RESCHED_DELAYED \ +- 17 /* reschedule on return to userspace */ ++ 14 /* reschedule on return to userspace */ ++#define TIF_FREEZE 15 /* Freezing for suspend */ ++#define TIF_RUNLATCH 16 /* Is the runlatch enabled? */ ++#define TIF_ABI_PENDING 17 /* 32/64 bit switch needed */ + + + /* as above, but as bit values */ +@@ -142,10 +142,10 @@ static inline struct thread_info *curren + #define _TIF_RESTOREALL (1< +To: linuxppc-dev@ozlabs.org +Cc: mingo@elte.hu, tglx@linutronix.de +Subject: Re: [RFC] [patch 1/2] powerpc 2.6.21-rt1: fix kernel hang and/or panic + + +> It occurs on 2.6.21 + patch-2.6.21-rt1 + series of patches that I posted +> yesterday. + +When doing 'hdparm -t /dev/hda' several times, it silently hangs. +I think it freezes since It does not response to ping as well. +On the other hand, PREEMPT_NONE kernel works just fine. + +After looking into the rt interrupt handling code, I noticed +that code path differs between PREEMPT_NONE and PREEMPT_RT; + NONE: mask() -> unmask() -> eoi() + RT: mask() -> eoi() -> unmask() + +The hypervisor underlying the linux on Celleb wants to be called +in this "mask() -> unmask() -> eoi()" order. This patch mimics +the behavior of PREEPT_NONE even if PREEMPT_RT is specified. + +Or, would it be better to create/add a new (threaded) irq handler? + +Any comments? + +Thanks in advance + +Signed-off-by: Tsutomu OWA +-- owa + +--- + arch/powerpc/platforms/celleb/interrupt.c | 39 +++++++++++++++++++++++++----- + 1 file changed, 33 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/celleb/interrupt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/celleb/interrupt.c 2009-02-08 00:00:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/celleb/interrupt.c 2009-02-08 00:01:56.000000000 -0500 +@@ -29,6 +29,10 @@ + #include "interrupt.h" + #include "beat_wrapper.h" + ++#ifdef CONFIG_PREEMPT_HARDIRQS ++extern int hardirq_preemption; ++#endif /* CONFIG_PREEMPT_HARDIRQS */ ++ + #define MAX_IRQS NR_IRQS + static DEFINE_SPINLOCK(beatic_irq_mask_lock); + static uint64_t beatic_irq_mask_enable[(MAX_IRQS+255)/64]; +@@ -71,12 +75,35 @@ static void beatic_mask_irq(unsigned int + spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); + } + ++static void __beatic_eoi_irq(unsigned int irq_plug) ++{ ++ s64 err; ++ ++ if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) { ++ if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */ ++ panic("Failed to downcount IRQ! Error = %16lx", err); ++ ++ printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug); ++ } ++} ++ + static void beatic_unmask_irq(unsigned int irq_plug) + { + unsigned long flags; + ++#ifdef CONFIG_PREEMPT_HARDIRQS ++ if (hardirq_preemption) ++ __beatic_eoi_irq(irq_plug); ++#endif /* CONFIG_PREEMPT_HARDIRQS */ ++ + spin_lock_irqsave(&beatic_irq_mask_lock, flags); + beatic_irq_mask_enable[irq_plug/64] |= 1UL << (63 - (irq_plug%64)); ++ ++#ifdef CONFIG_PREEMPT_HARDIRQS ++ if (hardirq_preemption) ++ beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64)); ++#endif /* CONFIG_PREEMPT_HARDIRQS */ ++ + beatic_update_irq_mask(irq_plug); + spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); + } +@@ -93,15 +120,15 @@ static void beatic_ack_irq(unsigned int + + static void beatic_end_irq(unsigned int irq_plug) + { +- s64 err; + unsigned long flags; + +- if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) { +- if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */ +- panic("Failed to downcount IRQ! Error = %16lx", err); ++#ifdef CONFIG_PREEMPT_HARDIRQS ++ if (hardirq_preemption) ++ return; ++#endif /* CONFIG_PREEMPT_HARDIRQS */ ++ ++ __beatic_eoi_irq(irq_plug); + +- printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug); +- } + spin_lock_irqsave(&beatic_irq_mask_lock, flags); + beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64)); + beatic_update_irq_mask(irq_plug); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0222-preempt-realtime-powerpc-b2.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0222-preempt-realtime-powerpc-b2.patch @@ -0,0 +1,69 @@ + + To convert the spinlocks into the raw onces to fix the following warnings/errors. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Badness at arch/powerpc/kernel/entry_64.S:651 +Call Trace: +[C0000000006133E0] [C00000000000FAAC] show_stack+0x68/0x1b0 (unreliable) +[C000000000613480] [C0000000001EF004] .repor000001EF004] .report_bug+0x94/0xe8 +[C000000000613510] [C0000000003EAD58] .program_check_exception+0x170/0x5a8 +[C00000000000487C] program_check_common+0xfc/0x100 +--- + arch/powerpc/kernel/irq.c | 2 +- + arch/powerpc/kernel/rtas.c | 2 +- + arch/powerpc/mm/hash_native_64.c | 2 +- + include/asm-powerpc/rtas.h | 2 +- + 4 files changed, 4 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/irq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/irq.c 2009-02-08 00:02:30.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/irq.c 2009-02-08 00:02:30.000000000 -0500 +@@ -403,7 +403,7 @@ void do_softirq(void) + #ifdef CONFIG_PPC_MERGE + + static LIST_HEAD(irq_hosts); +-static DEFINE_SPINLOCK(irq_big_lock); ++static DEFINE_RAW_SPINLOCK(irq_big_lock); + static DEFINE_PER_CPU(unsigned int, irq_radix_reader); + static unsigned int irq_radix_writer; + struct irq_map_entry irq_map[NR_IRQS]; +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/rtas.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/rtas.c 2009-02-08 00:00:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/rtas.c 2009-02-08 00:02:30.000000000 -0500 +@@ -41,7 +41,7 @@ + #include + + struct rtas_t rtas = { +- .lock = SPIN_LOCK_UNLOCKED ++ .lock = RAW_SPIN_LOCK_UNLOCKED(lock) + }; + EXPORT_SYMBOL(rtas); + +Index: linux-2.6.24.7-rt27/arch/powerpc/mm/hash_native_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/mm/hash_native_64.c 2009-02-08 00:00:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/mm/hash_native_64.c 2009-02-08 00:02:30.000000000 -0500 +@@ -36,7 +36,7 @@ + + #define HPTE_LOCK_BIT 3 + +-static DEFINE_SPINLOCK(native_tlbie_lock); ++static DEFINE_RAW_SPINLOCK(native_tlbie_lock); + + static inline void __tlbie(unsigned long va, int psize, int ssize) + { +Index: linux-2.6.24.7-rt27/include/asm-powerpc/rtas.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-powerpc/rtas.h 2009-02-08 00:00:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-powerpc/rtas.h 2009-02-08 00:02:30.000000000 -0500 +@@ -58,7 +58,7 @@ struct rtas_t { + unsigned long entry; /* physical address pointer */ + unsigned long base; /* physical address pointer */ + unsigned long size; +- spinlock_t lock; ++ raw_spinlock_t lock; + struct rtas_args args; + struct device_node *dev; /* virtual address pointer */ + }; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0573-tracer-fix-clock-backwards.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0573-tracer-fix-clock-backwards.patch @@ -0,0 +1,83 @@ +Subject: tracer-fix-clock-backwards.patch +From: Thomas Gleixner +Date: Fri, 09 Jan 2009 17:12:08 +0100 + +Signed-off-by: Thomas Gleixner +--- + kernel/trace/trace_hist.c | 49 +++++++++++++++++++++++++++++++--------------- + 1 file changed, 34 insertions(+), 15 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/trace/trace_hist.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace_hist.c 2009-02-08 00:04:44.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace_hist.c 2009-02-08 00:05:23.000000000 -0500 +@@ -359,11 +359,17 @@ notrace void tracing_hist_preempt_stop(i + stop = ftrace_now(cpu); + stop_set++; + start = per_cpu(hist_irqsoff_start, cpu); +- latency = (long)nsecs_to_usecs(stop - start); +- if (latency > 1000000) { +- printk("%d: latency = %ld (%lu)\n", __LINE__, latency, latency); +- printk("%d: start=%Ld stop=%Ld\n", __LINE__, start, stop); +- } ++ ++ if (stop > start) { ++ latency = (long)nsecs_to_usecs(stop - start); ++ if (latency > 1000000) { ++ printk("%d: latency = %ld (%lu)\n", __LINE__, ++ latency, latency); ++ printk("%d: start=%Ld stop=%Ld\n", __LINE__, ++ start, stop); ++ } ++ } else ++ latency = 0; + barrier(); + per_cpu(hist_irqsoff_tracing, cpu) = 0; + latency_hist(INTERRUPT_LATENCY, cpu, latency); +@@ -377,11 +383,17 @@ notrace void tracing_hist_preempt_stop(i + if (1 || !(stop_set++)) + stop = ftrace_now(cpu); + start = per_cpu(hist_preemptoff_start, cpu); +- latency = (long)nsecs_to_usecs(stop - start); +- if (latency > 1000000) { +- printk("%d: latency = %ld (%lu)\n", __LINE__, latency, latency); +- printk("%d: start=%Ld stop=%Ld\n", __LINE__, start, stop); +- } ++ ++ if (stop > start) { ++ latency = (long)nsecs_to_usecs(stop - start); ++ if (latency > 1000000) { ++ printk("%d: latency = %ld (%lu)\n", __LINE__, ++ latency, latency); ++ printk("%d: start=%Ld stop=%Ld\n", __LINE__, ++ start, stop); ++ } ++ } else ++ latency = 0; + barrier(); + per_cpu(hist_preemptoff_tracing, cpu) = 0; + latency_hist(PREEMPT_LATENCY, cpu, latency); +@@ -397,11 +409,18 @@ notrace void tracing_hist_preempt_stop(i + if (1 || !stop_set) + stop = ftrace_now(cpu); + start = per_cpu(hist_preemptirqsoff_start, cpu); +- latency = (long)nsecs_to_usecs(stop - start); +- if (latency > 1000000) { +- printk("%d: latency = %ld (%lu)\n", __LINE__, latency, latency); +- printk("%d: start=%Ld stop=%Ld\n", __LINE__, start, stop); +- } ++ ++ if (stop > start) { ++ latency = (long)nsecs_to_usecs(stop - start); ++ if (latency > 1000000) { ++ printk("%d: latency = %ld (%lu)\n", __LINE__, ++ latency, latency); ++ printk("%d: start=%Ld stop=%Ld\n", __LINE__, ++ start, stop); ++ } ++ } else ++ latency = 0; ++ + barrier(); + per_cpu(hist_preemptirqsoff_tracing, cpu) = 0; + latency_hist(PREEMPT_INTERRUPT_LATENCY, cpu, latency); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0370-rcu-preempt-boost-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0370-rcu-preempt-boost-fix.patch @@ -0,0 +1,95 @@ +--- + kernel/rcupreempt-boost.c | 39 ++++++++++++++++++++++++++++++++++++--- + kernel/rcupreempt.c | 1 + + 2 files changed, 37 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rcupreempt-boost.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt-boost.c 2009-02-08 00:03:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt-boost.c 2009-02-08 00:03:46.000000000 -0500 +@@ -221,6 +221,11 @@ RCU_BOOST_TRACE_FUNC_DECL(over_taken) + # define rcu_trace_boost_over_taken(rbd) do { } while (0) + #endif /* CONFIG_RCU_TRACE */ + ++static inline int rcu_is_boosted(struct task_struct *task) ++{ ++ return !list_empty(&task->rcub_entry); ++} ++ + /* + * Helper function to boost a task's prio. + */ +@@ -259,7 +264,7 @@ void __rcu_preempt_boost(void) + rcu_trace_boost_boost_called(RCU_BOOST_ME); + + /* check to see if we are already boosted */ +- if (unlikely(curr->rcub_rbdp)) ++ if (unlikely(rcu_is_boosted(curr))) + return; + + /* +@@ -311,15 +316,42 @@ void __rcu_preempt_unboost(void) + rcu_trace_boost_unboost_called(RCU_BOOST_ME); + + /* if not boosted, then ignore */ +- if (likely(!curr->rcub_rbdp)) ++ if (likely(!rcu_is_boosted(curr))) + return; + ++ /* ++ * Need to be very careful with NMIs. ++ * If we take the lock and an NMI comes in ++ * and it may try to unboost us if curr->rcub_rbdp ++ * is still set. So we zero it before grabbing the lock. ++ * But this also means that we might be boosted again ++ * so the boosting code needs to be aware of this. ++ */ + rbd = curr->rcub_rbdp; ++ curr->rcub_rbdp = NULL; ++ ++ /* ++ * Now an NMI might have came in after we grab ++ * the below lock. This check makes sure that ++ * the NMI doesn't try grabbing the lock ++ * while we already have it. ++ */ ++ if (unlikely(!rbd)) ++ return; + + spin_lock_irqsave(&rbd->rbs_lock, flags); ++ /* ++ * It is still possible that an NMI came in ++ * between the "is_boosted" check and setting ++ * the rcu_rbdp to NULL. This would mean that ++ * the NMI already dequeued us. ++ */ ++ if (unlikely(!rcu_is_boosted(curr))) ++ goto out; ++ + list_del_init(&curr->rcub_entry); + +- rcu_trace_boost_unboosted(curr->rcub_rbdp); ++ rcu_trace_boost_unboosted(rbd); + + curr->rcu_prio = MAX_PRIO; + +@@ -330,6 +362,7 @@ void __rcu_preempt_unboost(void) + curr->rcub_rbdp = NULL; + + spin_unlock(&curr->pi_lock); ++ out: + spin_unlock_irqrestore(&rbd->rbs_lock, flags); + } + +Index: linux-2.6.24.7-rt27/kernel/rcupreempt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt.c 2009-02-08 00:03:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt.c 2009-02-08 00:03:46.000000000 -0500 +@@ -309,6 +309,7 @@ void __rcu_read_unlock(void) + */ + + ACCESS_ONCE(__get_cpu_var(rcu_flipctr)[idx])--; ++ + local_irq_restore(oldirq); + + __rcu_preempt_unboost(); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0557-38c052f8cff1bd323ccfa968136a9556652ee420.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0557-38c052f8cff1bd323ccfa968136a9556652ee420.patch @@ -0,0 +1,64 @@ +commit 38c052f8cff1bd323ccfa968136a9556652ee420 +Author: Ingo Molnar +Date: Sat Aug 23 17:59:07 2008 +0200 + + rtc: fix deadlock + + if get_rtc_time() is _ever_ called with IRQs off, we deadlock badly + in it, waiting for jiffies to increment. + + So make the code more robust by doing an explicit mdelay(20). + + This solves a very hard to reproduce/debug hard lockup reported + by Mikael Pettersson. + + Reported-by: Mikael Pettersson + Signed-off-by: Ingo Molnar + +--- + include/asm-generic/rtc.h | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +Index: linux-2.6.24.7-rt27/include/asm-generic/rtc.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-generic/rtc.h 2009-02-07 23:59:33.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-generic/rtc.h 2009-02-08 00:05:15.000000000 -0500 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #define RTC_PIE 0x40 /* periodic interrupt enable */ + #define RTC_AIE 0x20 /* alarm interrupt enable */ +@@ -44,7 +45,6 @@ static inline unsigned char rtc_is_updat + + static inline unsigned int get_rtc_time(struct rtc_time *time) + { +- unsigned long uip_watchdog = jiffies; + unsigned char ctrl; + #ifdef CONFIG_MACH_DECSTATION + unsigned int real_year; +@@ -52,19 +52,15 @@ static inline unsigned int get_rtc_time( + + /* + * read RTC once any update in progress is done. The update +- * can take just over 2ms. We wait 10 to 20ms. There is no need to ++ * can take just over 2ms. We wait 20ms. There is no need to + * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. + * If you need to know *exactly* when a second has started, enable + * periodic update complete interrupts, (via ioctl) and then + * immediately read /dev/rtc which will block until you get the IRQ. + * Once the read clears, read the RTC time (again via ioctl). Easy. + */ +- +- if (rtc_is_updating() != 0) +- while (jiffies - uip_watchdog < 2*HZ/100) { +- barrier(); +- cpu_relax(); +- } ++ if (rtc_is_updating()) ++ mdelay(20); + + /* + * Only the values that we read from the RTC are set. We leave --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0442-rtmutex-lateral-steal.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0442-rtmutex-lateral-steal.patch @@ -0,0 +1,136 @@ +allow rt-mutex lock-stealing to include lateral priority + +From: Gregory Haskins + +The current logic only allows lock stealing to occur if the current task +is of higher priority than the pending owner. We can gain signficant +throughput improvements (200%+) by allowing the lock-stealing code to +include tasks of equal priority. The theory is that the system will make +faster progress by allowing the task already on the CPU to take the lock +rather than waiting for the system to wake-up a different task. + +This does add a degree of unfairness, yes. But also note that the users +of these locks under non -rt environments have already been using unfair +raw spinlocks anyway so the tradeoff is probably worth it. + +The way I like to think of this is that higher priority tasks should +clearly preempt, and lower priority tasks should clearly block. However, +if tasks have an identical priority value, then we can think of the +scheduler decisions as the tie-breaking parameter. (e.g. tasks that the +scheduler picked to run first have a logically higher priority amoung tasks +of the same prio). This helps to keep the system "primed" with tasks doing +useful work, and the end result is higher throughput. + +Thanks to Steven Rostedt for pointing out that RT tasks should be excluded +to prevent the introduction of an unnatural unbounded latency. + +[ Steven Rostedt - removed config option to disable ] + +Signed-off-by: Gregory Haskins +Signed-off-by: Steven Rostedt +--- + + kernel/rtmutex.c | 17 +++++++++++------ + kernel/rtmutex_common.h | 19 +++++++++++++++++++ + 2 files changed, 30 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:21.000000000 -0500 +@@ -318,7 +318,7 @@ static int rt_mutex_adjust_prio_chain(st + * assigned pending owner [which might not have taken the + * lock yet]: + */ +-static inline int try_to_steal_lock(struct rt_mutex *lock) ++static inline int try_to_steal_lock(struct rt_mutex *lock, int mode) + { + struct task_struct *pendowner = rt_mutex_owner(lock); + struct rt_mutex_waiter *next; +@@ -330,7 +330,7 @@ static inline int try_to_steal_lock(stru + return 1; + + spin_lock(&pendowner->pi_lock); +- if (current->prio >= pendowner->prio) { ++ if (!lock_is_stealable(pendowner, mode)) { + spin_unlock(&pendowner->pi_lock); + return 0; + } +@@ -383,7 +383,7 @@ static inline int try_to_steal_lock(stru + * + * Must be called with lock->wait_lock held. + */ +-static int try_to_take_rt_mutex(struct rt_mutex *lock) ++static int do_try_to_take_rt_mutex(struct rt_mutex *lock, int mode) + { + /* + * We have to be careful here if the atomic speedups are +@@ -406,7 +406,7 @@ static int try_to_take_rt_mutex(struct r + */ + mark_rt_mutex_waiters(lock); + +- if (rt_mutex_owner(lock) && !try_to_steal_lock(lock)) ++ if (rt_mutex_owner(lock) && !try_to_steal_lock(lock, mode)) + return 0; + + /* We got the lock. */ +@@ -419,6 +419,11 @@ static int try_to_take_rt_mutex(struct r + return 1; + } + ++static inline int try_to_take_rt_mutex(struct rt_mutex *lock) ++{ ++ return do_try_to_take_rt_mutex(lock, STEAL_NORMAL); ++} ++ + /* + * Task blocks on lock. + * +@@ -684,7 +689,7 @@ rt_spin_lock_slowlock(struct rt_mutex *l + init_lists(lock); + + /* Try to acquire the lock again: */ +- if (try_to_take_rt_mutex(lock)) { ++ if (do_try_to_take_rt_mutex(lock, STEAL_LATERAL)) { + spin_unlock_irqrestore(&lock->wait_lock, flags); + return; + } +@@ -707,7 +712,7 @@ rt_spin_lock_slowlock(struct rt_mutex *l + int saved_lock_depth = current->lock_depth; + + /* Try to acquire the lock */ +- if (try_to_take_rt_mutex(lock)) ++ if (do_try_to_take_rt_mutex(lock, STEAL_LATERAL)) + break; + /* + * waiter.task is NULL the first time we come here and +Index: linux-2.6.24.7-rt27/kernel/rtmutex_common.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex_common.h 2009-02-07 23:59:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex_common.h 2009-02-08 00:04:21.000000000 -0500 +@@ -121,6 +121,25 @@ extern void rt_mutex_init_proxy_locked(s + extern void rt_mutex_proxy_unlock(struct rt_mutex *lock, + struct task_struct *proxy_owner); + ++ ++#define STEAL_LATERAL 1 ++#define STEAL_NORMAL 0 ++ ++/* ++ * Note that RT tasks are excluded from lateral-steals to prevent the ++ * introduction of an unbounded latency ++ */ ++static inline int lock_is_stealable(struct task_struct *pendowner, int mode) ++{ ++ if (mode == STEAL_NORMAL || rt_task(current)) { ++ if (current->prio >= pendowner->prio) ++ return 0; ++ } else if (current->prio > pendowner->prio) ++ return 0; ++ ++ return 1; ++} ++ + #ifdef CONFIG_DEBUG_RT_MUTEXES + # include "rtmutex-debug.h" + #else --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0332-paravirt-function-pointer-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0332-paravirt-function-pointer-fix.patch @@ -0,0 +1,34 @@ +--- + arch/x86/kernel/paravirt_32.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/paravirt_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/paravirt_32.c 2009-02-07 23:59:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/paravirt_32.c 2009-02-08 00:03:28.000000000 -0500 +@@ -407,6 +407,16 @@ struct pv_apic_ops pv_apic_ops = { + #endif + }; + ++#ifdef CONFIG_HIGHPTE ++/* ++ * kmap_atomic() might be an inline or a macro: ++ */ ++static void *kmap_atomic_func(struct page *page, enum km_type idx) ++{ ++ return kmap_atomic(page, idx); ++} ++#endif ++ + struct pv_mmu_ops pv_mmu_ops = { + .pagetable_setup_start = native_pagetable_setup_start, + .pagetable_setup_done = native_pagetable_setup_done, +@@ -434,7 +444,7 @@ struct pv_mmu_ops pv_mmu_ops = { + .pte_update_defer = paravirt_nop, + + #ifdef CONFIG_HIGHPTE +- .kmap_atomic_pte = kmap_atomic, ++ .kmap_atomic_pte = kmap_atomic_func, + #endif + + #ifdef CONFIG_X86_PAE --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0503-rt-mutex-use-inline.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0503-rt-mutex-use-inline.patch @@ -0,0 +1,28 @@ +Subject: rt-mutex-cleanup.patch +From: Thomas Gleixner +Date: Fri, 20 Jun 2008 12:20:09 +0200 + +Signed-off-by: Thomas Gleixner +--- + kernel/rtmutex.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:50.000000000 -0500 +@@ -124,9 +124,12 @@ static inline void mark_rt_rwlock_check( + #endif + + #ifdef CONFIG_PREEMPT_RT +-#define task_is_reader(task) ((task) == RT_RW_READER) ++static inline int task_is_reader(struct task_struct *task) ++{ ++ return task == RT_RW_READER; ++} + #else +-#define task_is_reader(task) (0) ++static inline int task_is_reader(struct task_struct *task) { return 0; } + #endif + + int pi_initialized; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0227-preempt-realtime-powerpc-celleb-raw-spinlocks.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0227-preempt-realtime-powerpc-celleb-raw-spinlocks.patch @@ -0,0 +1,44 @@ +From tsutomu.owa@toshiba.co.jp Mon May 14 15:28:23 2007 +Date: Mon, 14 May 2007 15:28:23 +0900 +From: Tsutomu OWA +To: linuxppc-dev@ozlabs.org, linux-kernel@vger.kernel.org +Cc: mingo@elte.hu, tglx@linutronix.de +Subject: Re: [patch 2/4] powerpc 2.6.21-rt1: convert spinlocks to raw ones for Celleb. + + +Convert more spinlocks to raw ones for Celleb. + +Signed-off-by: Tsutomu OWA +-- owa + +--- + arch/powerpc/platforms/celleb/htab.c | 2 +- + arch/powerpc/platforms/celleb/interrupt.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/celleb/htab.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/celleb/htab.c 2009-02-08 00:00:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/celleb/htab.c 2009-02-08 00:02:32.000000000 -0500 +@@ -40,7 +40,7 @@ + #define DBG_LOW(fmt...) do { } while(0) + #endif + +-static DEFINE_SPINLOCK(beat_htab_lock); ++static DEFINE_RAW_SPINLOCK(beat_htab_lock); + + static inline unsigned int beat_read_mask(unsigned hpte_group) + { +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/celleb/interrupt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/celleb/interrupt.c 2009-02-08 00:01:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/celleb/interrupt.c 2009-02-08 00:02:32.000000000 -0500 +@@ -34,7 +34,7 @@ extern int hardirq_preemption; + #endif /* CONFIG_PREEMPT_HARDIRQS */ + + #define MAX_IRQS NR_IRQS +-static DEFINE_SPINLOCK(beatic_irq_mask_lock); ++static DEFINE_RAW_SPINLOCK(beatic_irq_mask_lock); + static uint64_t beatic_irq_mask_enable[(MAX_IRQS+255)/64]; + static uint64_t beatic_irq_mask_ack[(MAX_IRQS+255)/64]; + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0491-rwlock-fixes.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0491-rwlock-fixes.patch @@ -0,0 +1,176 @@ +From: Steven Rostedt +Subject: rwlock: fix pi_list race conditions + +Found a few pi_list problems, this patch fixes. + +Signed-off-by: Steven Rostedt +--- + kernel/rtmutex.c | 56 ++++++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 41 insertions(+), 15 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:44.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:45.000000000 -0500 +@@ -1108,6 +1108,23 @@ update_rw_mutex_owner(struct rw_mutex *r + rt_mutex_set_owner(mutex, mtxowner, 0); + } + ++#ifdef CONFIG_DEBUG_RT_MUTEXES ++/* ++ * A rw lock is about to be added or has already been ++ * removed from current. Make sure it doesn't exist still. ++ */ ++static void rw_check_held(struct rw_mutex *rwm) ++{ ++ int reader_count = current->reader_lock_count; ++ int i; ++ ++ for (i = 0; i < reader_count; i++) ++ WARN_ON_ONCE(current->owned_read_locks[i].lock == rwm); ++} ++#else ++# define rw_check_held(rwm) do { } while (0) ++#endif ++ + /* + * The fast path does not add itself to the reader list to keep + * from needing to grab the spinlock. We need to add the owner +@@ -1122,16 +1139,14 @@ update_rw_mutex_owner(struct rw_mutex *r + */ + + static inline void +-rt_rwlock_update_owner(struct rw_mutex *rwm, unsigned owners) ++rt_rwlock_update_owner(struct rw_mutex *rwm, struct task_struct *own) + { + struct reader_lock_struct *rls; +- struct task_struct *own; + int i; + +- if (!owners || rt_rwlock_pending(rwm)) ++ if (!own || rt_rwlock_pending(rwm)) + return; + +- own = rt_rwlock_owner(rwm); + if (own == RT_RW_READER) + return; + +@@ -1201,7 +1216,7 @@ static int try_to_take_rw_read(struct rw + } + + owners = atomic_read(&rwm->owners); +- rt_rwlock_update_owner(rwm, owners); ++ rt_rwlock_update_owner(rwm, rt_rwlock_owner(rwm)); + + /* Check for rwlock limits */ + if (rt_rwlock_limit && owners >= rt_rwlock_limit) +@@ -1253,6 +1268,7 @@ static int try_to_take_rw_read(struct rw + taken: + if (incr) { + atomic_inc(&rwm->owners); ++ rw_check_held(rwm); + reader_count = current->reader_lock_count++; + if (likely(reader_count < MAX_RWLOCK_DEPTH)) { + rls = ¤t->owned_read_locks[reader_count]; +@@ -1280,11 +1296,12 @@ try_to_take_rw_write(struct rw_mutex *rw + own = rt_rwlock_owner(rwm); + + /* owners must be zero for writer */ +- rt_rwlock_update_owner(rwm, atomic_read(&rwm->owners)); ++ if (own) { ++ rt_rwlock_update_owner(rwm, own); + +- /* readers or writers? */ +- if ((own && !rt_rwlock_pending(rwm))) +- return 0; ++ if (!rt_rwlock_pending(rwm)) ++ return 0; ++ } + + /* + * RT_RW_PENDING means that the lock is free, but there are +@@ -1431,6 +1448,7 @@ __rt_read_fasttrylock(struct rw_mutex *r + } + + atomic_inc(&rwm->owners); ++ rw_check_held(rwm); + reader_count = current->reader_lock_count; + if (likely(reader_count < MAX_RWLOCK_DEPTH)) { + current->owned_read_locks[reader_count].lock = rwm; +@@ -1713,6 +1731,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + WARN_ON(!rls->list.prev || list_empty(&rls->list)); + list_del_init(&rls->list); + rls->lock = NULL; ++ rw_check_held(rwm); + } + break; + } +@@ -1729,7 +1748,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + if (unlikely(rt_rwlock_owner(rwm) != current && + rt_rwlock_owner(rwm) != RT_RW_READER)) { + /* Update the owner if necessary */ +- rt_rwlock_update_owner(rwm, atomic_read(&rwm->owners)); ++ rt_rwlock_update_owner(rwm, rt_rwlock_owner(rwm)); + goto out; + } + +@@ -1786,7 +1805,8 @@ rt_read_slowunlock(struct rw_mutex *rwm, + if (rt_rwlock_limit && + unlikely(atomic_read(&rwm->owners) >= rt_rwlock_limit)) + goto out; +- rwm->owner = RT_RW_PENDING_READ; ++ if (!reader_count) ++ rwm->owner = RT_RW_PENDING_READ; + } + + wakeup_next_waiter(mutex, savestate); +@@ -1812,6 +1832,7 @@ rt_read_fastunlock(struct rw_mutex *rwm, + WARN_ON(!atomic_read(&rwm->count)); + WARN_ON(!atomic_read(&rwm->owners)); + WARN_ON(!rwm->owner); ++ smp_mb(); + atomic_dec(&rwm->count); + if (likely(rt_rwlock_cmpxchg(rwm, current, NULL))) { + struct reader_lock_struct *rls; +@@ -1830,7 +1851,9 @@ rt_read_fastunlock(struct rw_mutex *rwm, + rls = ¤t->owned_read_locks[reader_count]; + WARN_ON_ONCE(rls->lock != rwm); + WARN_ON(rls->list.prev && !list_empty(&rls->list)); ++ WARN_ON(rls->count != 1); + rls->lock = NULL; ++ rw_check_held(rwm); + } else + slowfn(rwm, mtx); + } +@@ -1936,8 +1959,11 @@ rt_write_slowunlock(struct rw_mutex *rwm + next = rt_mutex_top_waiter(mutex); + /* delete incase we didn't go through the loop */ + plist_del(&next->pi_list_entry, &pendowner->pi_waiters); +- /* add back in as top waiter */ +- plist_add(&next->pi_list_entry, &pendowner->pi_waiters); ++ ++ /* This could also be a reader (if reader_limit is set) */ ++ if (next->write_lock) ++ /* add back in as top waiter */ ++ plist_add(&next->pi_list_entry, &pendowner->pi_waiters); + + rwm->prio = next->task->prio; + } else +@@ -1997,6 +2023,7 @@ rt_mutex_downgrade_write(struct rw_mutex + /* we have the lock and are sole owner, then update the accounting */ + atomic_inc(&rwm->count); + atomic_inc(&rwm->owners); ++ rw_check_held(rwm); + reader_count = current->reader_lock_count++; + rls = ¤t->owned_read_locks[reader_count]; + if (likely(reader_count < MAX_RWLOCK_DEPTH)) { +@@ -2058,8 +2085,7 @@ rt_mutex_downgrade_write(struct rw_mutex + + /* delete incase we didn't go through the loop */ + plist_del(&next->pi_list_entry, ¤t->pi_waiters); +- /* add back in as top waiter */ +- plist_add(&next->pi_list_entry, ¤t->pi_waiters); ++ /* No need to add back since readers don't have PI waiters */ + } else + rwm->prio = MAX_PRIO; + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0105-netfilter-more-debugging.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0105-netfilter-more-debugging.patch @@ -0,0 +1,28 @@ + +doing netfilter changes and turning on netfilter debug means +we've got to interpret netfilter warning messages a bit more. + +--- + include/net/netfilter/nf_conntrack.h | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/include/net/netfilter/nf_conntrack.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/net/netfilter/nf_conntrack.h 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/net/netfilter/nf_conntrack.h 2009-02-08 00:01:32.000000000 -0500 +@@ -63,11 +63,14 @@ union nf_conntrack_help { + #ifdef CONFIG_NETFILTER_DEBUG + #define NF_CT_ASSERT(x) \ + do { \ +- if (!(x)) \ ++ if (!(x)) { \ + /* Wooah! I'm tripping my conntrack in a frenzy of \ + netplay... */ \ + printk("NF_CT_ASSERT: %s:%i(%s)\n", \ + __FILE__, __LINE__, __FUNCTION__); \ ++ if (printk_ratelimit()) \ ++ WARN_ON(1); \ ++ } \ + } while(0) + #else + #define NF_CT_ASSERT(x) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0166-rt-mutex-trivial-route-cast-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0166-rt-mutex-trivial-route-cast-fix.patch @@ -0,0 +1,17 @@ +--- + net/ipv4/route.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/net/ipv4/route.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/net/ipv4/route.c 2009-02-08 00:00:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/net/ipv4/route.c 2009-02-08 00:02:00.000000000 -0500 +@@ -240,7 +240,7 @@ static spinlock_t *rt_hash_locks; + spin_lock_init(&rt_hash_locks[i]); \ + } + #else +-# define rt_hash_lock_addr(slot) NULL ++# define rt_hash_lock_addr(slot) ((spinlock_t *)NULL) + # define rt_hash_lock_init() + #endif + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0544-rtmutex-debug-magic.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0544-rtmutex-debug-magic.patch @@ -0,0 +1,425 @@ +From: Steven Rostedt +Subject: rtmutex: check integrity + +When PREEMPT_RT is configured on, a spinlock or semaphore can turn into +a rt_mutex. Since they also may stay the same in some cases (depending on +what type they were defined as) the API for them is determined by the +type. For example, if a spin lock is of type spinlock_t it will be converted +to an rt_mutex, and if it is defined as raw_spinlock_t it will stay the +same. + +If the locks are passed as pointers and typecasted to the wrong lock, +things can break. This patch adds a integrity check to make sure that +the rt_mutexs are indeed rt_mutexes when used. + +Signed-off-by: Steven Rostedt +--- + include/linux/rt_lock.h | 46 +++++++++++++++++++++++++++++++++++++++------- + include/linux/rtmutex.h | 25 ++++++++++++++++++++++++- + kernel/rt.c | 15 +++++++++++++-- + kernel/rtmutex.c | 31 +++++++++++++++++++++++++++++-- + lib/Kconfig.debug | 13 +++++++++++++ + 5 files changed, 118 insertions(+), 12 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/rt_lock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rt_lock.h 2009-02-08 00:04:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rt_lock.h 2009-02-08 00:05:09.000000000 -0500 +@@ -27,15 +27,47 @@ typedef struct { + #endif + } spinlock_t; + ++#ifdef CONFIG_RTMUTEX_CHECK ++#define RT_SPIN_CHECK_MAGIC 0x52545350 /* RTSP */ ++# define __RT_SPIN_CHECK_INIT , .magic = RT_SPIN_CHECK_MAGIC ++# define rt_spinlock_magic_check(mutex) \ ++ WARN_ON_ONCE((mutex)->lock.magic != RT_SPIN_CHECK_MAGIC) ++ ++# define rt_rwlock_magic_check(lock) \ ++ WARN_ON_ONCE((lock)->magic != RT_SPIN_CHECK_MAGIC); ++static inline void check_rt_spin_lock_init(spinlock_t *lock) ++{ ++ lock->lock.magic = RT_SPIN_CHECK_MAGIC; ++} ++static inline void check_rt_rwlock_init(struct rt_mutex *lock) ++{ ++ lock->magic = RT_SPIN_CHECK_MAGIC; ++} ++#else ++# define __RT_SPIN_CHECK_INIT ++static inline void rt_spinlock_magic_check(spinlock_t *lock) ++{ } ++static inline void rt_rwlock_magic_check(struct rt_mutex *lock) ++{ } ++static inline void check_rt_spin_lock_init(spinlock_t *lock) ++{ } ++static inline void check_rt_rwlock_init(struct rt_mutex *lock) ++{ } ++#endif ++ + #ifdef CONFIG_DEBUG_RT_MUTEXES +-# define __RT_SPIN_INITIALIZER(name) \ +- { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name.wait_lock), \ +- .save_state = 1, \ +- .file = __FILE__, \ +- .line = __LINE__, } ++# define __RT_SPIN_INITIALIZER(name) \ ++ { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name.wait_lock), \ ++ .save_state = 1, \ ++ .file = __FILE__, \ ++ .line = __LINE__ \ ++ __RT_SPIN_CHECK_INIT } ++ + #else +-# define __RT_SPIN_INITIALIZER(name) \ +- { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) } ++# define __RT_SPIN_INITIALIZER(name) \ ++ { \ ++ .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \ ++ __RT_SPIN_CHECK_INIT } + #endif + + #define __SPIN_LOCK_UNLOCKED(name) (spinlock_t) \ +Index: linux-2.6.24.7-rt27/include/linux/rtmutex.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rtmutex.h 2009-02-08 00:03:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rtmutex.h 2009-02-08 00:05:09.000000000 -0500 +@@ -31,7 +31,9 @@ struct rt_mutex { + int save_state; + const char *name, *file; + int line; +- void *magic; ++#endif ++#ifdef CONFIG_RTMUTEX_CHECK ++ unsigned long magic; + #endif + }; + +@@ -62,10 +64,31 @@ struct hrtimer_sleeper; + # define rt_mutex_debug_task_free(t) do { } while (0) + #endif + ++#ifdef CONFIG_RTMUTEX_CHECK ++#define RT_MUTEX_CHECK_MAGIC 0x52544d58 /* RTMX */ ++# define __RT_MUTEX_CHECK_INIT \ ++ , .magic = RT_MUTEX_CHECK_MAGIC ++# define rt_mutex_magic_check(lock) \ ++ WARN_ON_ONCE((lock)->magic != RT_MUTEX_CHECK_MAGIC); ++static inline void check_rt_mutex_init(struct rt_mutex *lock) ++{ ++ lock->magic = RT_MUTEX_CHECK_MAGIC; ++} ++#else ++# define __RT_MUTEX_CHECK_INIT ++static inline void rt_mutex_magic_check(struct rt_mutex *lock) ++{ ++} ++static inline void check_rt_mutex_init(struct rt_mutex *lock) ++{ ++} ++#endif ++ + #define __RT_MUTEX_INITIALIZER(mutexname) \ + { .wait_lock = RAW_SPIN_LOCK_UNLOCKED(mutexname) \ + , .wait_list = PLIST_HEAD_INIT(mutexname.wait_list, &mutexname.wait_lock) \ + , .owner = NULL \ ++ __RT_MUTEX_CHECK_INIT \ + __DEBUG_RT_MUTEX_INITIALIZER(mutexname)} + + #define DEFINE_RT_MUTEX(mutexname) \ +Index: linux-2.6.24.7-rt27/kernel/rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rt.c 2009-02-08 00:04:27.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rt.c 2009-02-08 00:05:09.000000000 -0500 +@@ -165,7 +165,10 @@ EXPORT_SYMBOL(_mutex_unlock); + */ + int __lockfunc rt_write_trylock(rwlock_t *rwlock) + { +- int ret = rt_mutex_down_write_trylock(&rwlock->owners); ++ int ret; ++ ++ rt_rwlock_magic_check(&rwlock->owners.mutex); ++ ret = rt_mutex_down_write_trylock(&rwlock->owners); + + if (ret) + rwlock_acquire(&rwlock->dep_map, 0, 1, _RET_IP_); +@@ -176,6 +179,7 @@ EXPORT_SYMBOL(rt_write_trylock); + + int __lockfunc rt_write_trylock_irqsave(rwlock_t *rwlock, unsigned long *flags) + { ++ rt_rwlock_magic_check(&rwlock->owners.mutex); + *flags = 0; + return rt_write_trylock(rwlock); + } +@@ -185,6 +189,7 @@ int __lockfunc rt_read_trylock(rwlock_t + { + int ret; + ++ rt_rwlock_magic_check(&rwlock->owners.mutex); + ret = rt_mutex_down_read_trylock(&rwlock->owners); + if (ret) + rwlock_acquire_read(&rwlock->dep_map, 0, 1, _RET_IP_); +@@ -249,6 +254,7 @@ void __rt_rwlock_init(rwlock_t *rwlock, + lockdep_init_map(&rwlock->dep_map, name, key, 0); + #endif + rt_mutex_rwsem_init(&rwlock->owners, name); ++ check_rt_rwlock_init(&rwlock->owners.mutex); + } + EXPORT_SYMBOL(__rt_rwlock_init); + +@@ -281,8 +287,10 @@ EXPORT_SYMBOL(rt_downgrade_write); + + int fastcall rt_down_write_trylock(struct rw_semaphore *rwsem) + { +- int ret = rt_mutex_down_write_trylock(&rwsem->owners); ++ int ret; + ++ rt_mutex_magic_check(&rwsem->owners.mutex); ++ ret = rt_mutex_down_write_trylock(&rwsem->owners); + if (ret) + rwsem_acquire(&rwsem->dep_map, 0, 1, _RET_IP_); + return ret; +@@ -311,6 +319,7 @@ int fastcall rt_down_read_trylock(struct + { + int ret; + ++ rt_mutex_magic_check(&rwsem->owners.mutex); + ret = rt_mutex_down_read_trylock(&rwsem->owners); + if (ret) + rwsem_acquire(&rwsem->dep_map, 0, 1, _RET_IP_); +@@ -403,6 +412,7 @@ int fastcall rt_down_trylock(struct sema + * embedded mutex internally. It would be quite complex to remove + * these transient failures so lets try it the simple way first: + */ ++ rt_mutex_magic_check(&sem->lock); + if (rt_mutex_trylock(&sem->lock)) { + __down_complete(sem); + return 0; +@@ -419,6 +429,7 @@ void fastcall rt_up(struct semaphore *se + * Disable preemption to make sure a highprio trylock-er cannot + * preempt us here and get into an infinite loop: + */ ++ rt_mutex_magic_check(&sem->lock); + preempt_disable(); + count = atomic_inc_return(&sem->count); + /* +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:05:09.000000000 -0500 +@@ -950,6 +950,7 @@ rt_spin_lock_slowunlock(struct rt_mutex + + void __lockfunc rt_spin_lock(spinlock_t *lock) + { ++ rt_spinlock_magic_check(lock); + spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED_RT(lock, rt_mutex_trylock, __rt_spin_lock); + } +@@ -965,6 +966,7 @@ EXPORT_SYMBOL(__rt_spin_lock); + + void __lockfunc rt_spin_lock_nested(spinlock_t *lock, int subclass) + { ++ rt_spinlock_magic_check(lock); + spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); + LOCK_CONTENDED_RT(lock, rt_mutex_trylock, __rt_spin_lock); + } +@@ -974,6 +976,7 @@ EXPORT_SYMBOL(rt_spin_lock_nested); + + void __lockfunc rt_spin_unlock(spinlock_t *lock) + { ++ rt_spinlock_magic_check(lock); + /* NOTE: we always pass in '1' for nested, for simplicity */ + spin_release(&lock->dep_map, 1, _RET_IP_); + rt_spin_lock_fastunlock(&lock->lock, rt_spin_lock_slowunlock); +@@ -1002,6 +1005,8 @@ int __lockfunc rt_spin_trylock(spinlock_ + { + int ret = rt_mutex_trylock(&lock->lock); + ++ rt_spinlock_magic_check(lock); ++ + if (ret) + spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); + +@@ -1013,6 +1018,8 @@ int __lockfunc rt_spin_trylock_irqsave(s + { + int ret; + ++ rt_spinlock_magic_check(lock); ++ + *flags = 0; + ret = rt_mutex_trylock(&lock->lock); + if (ret) +@@ -1024,6 +1031,8 @@ EXPORT_SYMBOL(rt_spin_trylock_irqsave); + + int _atomic_dec_and_spin_lock(spinlock_t *lock, atomic_t *atomic) + { ++ rt_spinlock_magic_check(lock); ++ + /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */ + if (atomic_add_unless(atomic, -1, 1)) + return 0; +@@ -1046,6 +1055,7 @@ __rt_spin_lock_init(spinlock_t *lock, ch + lockdep_init_map(&lock->dep_map, name, key, 0); + #endif + __rt_mutex_init(&lock->lock, name); ++ check_rt_spin_lock_init(lock); + } + EXPORT_SYMBOL(__rt_spin_lock_init); + +@@ -1486,11 +1496,13 @@ rt_read_fastlock(struct rw_mutex *rwm, + + void fastcall rt_mutex_down_read(struct rw_mutex *rwm) + { ++ rt_mutex_magic_check(&rwm->mutex); + rt_read_fastlock(rwm, rt_read_slowlock, 1); + } + + void fastcall rt_rwlock_read_lock(struct rw_mutex *rwm) + { ++ rt_rwlock_magic_check(&rwm->mutex); + rt_read_fastlock(rwm, rt_read_slowlock, 0); + } + +@@ -1650,11 +1662,13 @@ rt_write_fastlock(struct rw_mutex *rwm, + + void fastcall rt_mutex_down_write(struct rw_mutex *rwm) + { ++ rt_mutex_magic_check(&rwm->mutex); + rt_write_fastlock(rwm, rt_write_slowlock, 1); + } + + void fastcall rt_rwlock_write_lock(struct rw_mutex *rwm) + { ++ rt_rwlock_magic_check(&rwm->mutex); + rt_write_fastlock(rwm, rt_write_slowlock, 0); + } + +@@ -1890,11 +1904,13 @@ rt_read_fastunlock(struct rw_mutex *rwm, + + void fastcall rt_mutex_up_read(struct rw_mutex *rwm) + { ++ rt_mutex_magic_check(&rwm->mutex); + rt_read_fastunlock(rwm, rt_read_slowunlock, 1); + } + + void fastcall rt_rwlock_read_unlock(struct rw_mutex *rwm) + { ++ rt_rwlock_magic_check(&rwm->mutex); + rt_read_fastunlock(rwm, rt_read_slowunlock, 0); + } + +@@ -2031,11 +2047,13 @@ rt_write_fastunlock(struct rw_mutex *rwm + + void fastcall rt_mutex_up_write(struct rw_mutex *rwm) + { ++ rt_mutex_magic_check(&rwm->mutex); + rt_write_fastunlock(rwm, rt_write_slowunlock, 1); + } + + void fastcall rt_rwlock_write_unlock(struct rw_mutex *rwm) + { ++ rt_rwlock_magic_check(&rwm->mutex); + rt_write_fastunlock(rwm, rt_write_slowunlock, 0); + } + +@@ -2052,6 +2070,7 @@ rt_mutex_downgrade_write(struct rw_mutex + unsigned long flags; + int reader_count; + ++ rt_mutex_magic_check(&rwm->mutex); + spin_lock_irqsave(&mutex->wait_lock, flags); + init_rw_lists(rwm); + +@@ -2523,6 +2542,7 @@ void __sched rt_mutex_lock(struct rt_mut + { + might_sleep(); + ++ rt_mutex_magic_check(lock); + rt_mutex_fastlock(lock, TASK_UNINTERRUPTIBLE, 0, rt_mutex_slowlock); + } + EXPORT_SYMBOL_GPL(rt_mutex_lock); +@@ -2543,6 +2563,7 @@ int __sched rt_mutex_lock_interruptible( + { + might_sleep(); + ++ rt_mutex_magic_check(lock); + return rt_mutex_fastlock(lock, TASK_INTERRUPTIBLE, + detect_deadlock, rt_mutex_slowlock); + } +@@ -2569,6 +2590,7 @@ rt_mutex_timed_lock(struct rt_mutex *loc + { + might_sleep(); + ++ rt_mutex_magic_check(lock); + return rt_mutex_timed_fastlock(lock, TASK_INTERRUPTIBLE, timeout, + detect_deadlock, rt_mutex_slowlock); + } +@@ -2594,6 +2616,7 @@ EXPORT_SYMBOL_GPL(rt_mutex_trylock); + */ + void __sched rt_mutex_unlock(struct rt_mutex *lock) + { ++ rt_mutex_magic_check(lock); + rt_mutex_fastunlock(lock, rt_mutex_slowunlock); + } + EXPORT_SYMBOL_GPL(rt_mutex_unlock); +@@ -2608,9 +2631,10 @@ EXPORT_SYMBOL_GPL(rt_mutex_unlock); + */ + void rt_mutex_destroy(struct rt_mutex *lock) + { ++ rt_mutex_magic_check(lock); + WARN_ON(rt_mutex_is_locked(lock)); +-#ifdef CONFIG_DEBUG_RT_MUTEXES +- lock->magic = NULL; ++#ifdef CONFIG_RTMUTEX_CHECK ++ lock->magic = 0; + #endif + } + +@@ -2632,6 +2656,7 @@ void __rt_mutex_init(struct rt_mutex *lo + plist_head_init(&lock->wait_list, &lock->wait_lock); + + debug_rt_mutex_init(lock, name); ++ check_rt_mutex_init(lock); + } + EXPORT_SYMBOL_GPL(__rt_mutex_init); + +@@ -2665,6 +2690,7 @@ void rt_mutex_init_proxy_locked(struct r + void rt_mutex_proxy_unlock(struct rt_mutex *lock, + struct task_struct *proxy_owner) + { ++ rt_mutex_magic_check(lock); + debug_rt_mutex_proxy_unlock(lock); + rt_mutex_set_owner(lock, NULL, 0); + rt_mutex_deadlock_account_unlock(proxy_owner); +@@ -2684,6 +2710,7 @@ void rt_mutex_proxy_unlock(struct rt_mut + */ + struct task_struct *rt_mutex_next_owner(struct rt_mutex *lock) + { ++ rt_mutex_magic_check(lock); + if (!rt_mutex_has_waiters(lock)) + return NULL; + +Index: linux-2.6.24.7-rt27/lib/Kconfig.debug +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/Kconfig.debug 2009-02-08 00:04:46.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/Kconfig.debug 2009-02-08 00:05:09.000000000 -0500 +@@ -192,6 +192,19 @@ config DEBUG_RT_MUTEXES + When realtime preemption is enabled this includes spinlocks, + rwlocks, mutexes and (rw)semaphores + ++config RTMUTEX_CHECK ++ bool "RT Mutex integrity checker" ++ depends on PREEMPT_RT ++ default y ++ help ++ When PREEMPT_RT is configured, most spinlocks and semaphores ++ are converted into mutexes. There still exists true spin locks ++ and old style semaphores. There are places in the kernel that ++ passes the lock via pointer and typecasts it back. This ++ can circumvent the compiler conversions. This option will add ++ a magic number to all converted locks and check to make sure ++ the lock is appropriate for the function being used. ++ + config DEBUG_PI_LIST + bool + default y --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0125-rcu-new-9.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0125-rcu-new-9.patch @@ -0,0 +1,537 @@ +From paulmck@linux.vnet.ibm.com Thu Sep 27 15:33:20 2007 +Date: Mon, 10 Sep 2007 11:42:40 -0700 +From: Paul E. McKenney +To: linux-kernel@vger.kernel.org +Cc: linux-rt-users@vger.kernel.org, mingo@elte.hu, akpm@linux-foundation.org, + dipankar@in.ibm.com, josht@linux.vnet.ibm.com, tytso@us.ibm.com, + dvhltc@us.ibm.com, tglx@linutronix.de, a.p.zijlstra@chello.nl, + bunk@kernel.org, ego@in.ibm.com, oleg@tv-sign.ru, srostedt@redhat.com +Subject: [PATCH RFC 9/9] RCU: preemptible documentation and comment cleanups + +Work in progress, not for inclusion. + +This patch updates the RCU documentation to reflect preemptible RCU as +well as recent publications. Fix an incorrect comment in the code. +Change the name ORDERED_WRT_IRQ() to ACCESS_ONCE() to better describe +its function. + +Signed-off-by: Paul E. McKenney +--- + + Documentation/RCU/RTFP.txt | 234 ++++++++++++++++++++++++++++++++++++++++-- + Documentation/RCU/rcu.txt | 20 +++ + Documentation/RCU/torture.txt | 44 ++++++- + kernel/rcupreempt.c | 22 +-- + 4 files changed, 290 insertions(+), 30 deletions(-) + +Index: linux-2.6.24.7-rt27/Documentation/RCU/RTFP.txt +=================================================================== +--- linux-2.6.24.7-rt27.orig/Documentation/RCU/RTFP.txt 2009-02-08 00:00:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/Documentation/RCU/RTFP.txt 2009-02-08 00:01:42.000000000 -0500 +@@ -9,8 +9,8 @@ The first thing resembling RCU was publi + [Kung80] recommended use of a garbage collector to defer destruction + of nodes in a parallel binary search tree in order to simplify its + implementation. This works well in environments that have garbage +-collectors, but current production garbage collectors incur significant +-read-side overhead. ++collectors, but most production garbage collectors incur significant ++overhead. + + In 1982, Manber and Ladner [Manber82,Manber84] recommended deferring + destruction until all threads running at that time have terminated, again +@@ -99,16 +99,25 @@ locking, reduces contention, reduces mem + parallelizes pipeline stalls and memory latency for writers. However, + these techniques still impose significant read-side overhead in the + form of memory barriers. Researchers at Sun worked along similar lines +-in the same timeframe [HerlihyLM02,HerlihyLMS03]. These techniques +-can be thought of as inside-out reference counts, where the count is +-represented by the number of hazard pointers referencing a given data +-structure (rather than the more conventional counter field within the +-data structure itself). ++in the same timeframe [HerlihyLM02]. These techniques can be thought ++of as inside-out reference counts, where the count is represented by the ++number of hazard pointers referencing a given data structure (rather than ++the more conventional counter field within the data structure itself). ++ ++By the same token, RCU can be thought of as a "bulk reference count", ++where some form of reference counter covers all reference by a given CPU ++or thread during a set timeframe. This timeframe is related to, but ++not necessarily exactly the same as, an RCU grace period. In classic ++RCU, the reference counter is the per-CPU bit in the "bitmask" field, ++and each such bit covers all references that might have been made by ++the corresponding CPU during the prior grace period. Of course, RCU ++can be thought of in other terms as well. + + In 2003, the K42 group described how RCU could be used to create +-hot-pluggable implementations of operating-system functions. Later that +-year saw a paper describing an RCU implementation of System V IPC +-[Arcangeli03], and an introduction to RCU in Linux Journal [McKenney03a]. ++hot-pluggable implementations of operating-system functions [Appavoo03a]. ++Later that year saw a paper describing an RCU implementation of System ++V IPC [Arcangeli03], and an introduction to RCU in Linux Journal ++[McKenney03a]. + + 2004 has seen a Linux-Journal article on use of RCU in dcache + [McKenney04a], a performance comparison of locking to RCU on several +@@ -117,10 +126,27 @@ number of operating-system kernels [Paul + describing how to make RCU safe for soft-realtime applications [Sarma04c], + and a paper describing SELinux performance with RCU [JamesMorris04b]. + +-2005 has seen further adaptation of RCU to realtime use, permitting ++2005 brought further adaptation of RCU to realtime use, permitting + preemption of RCU realtime critical sections [PaulMcKenney05a, + PaulMcKenney05b]. + ++2006 saw the first best-paper award for an RCU paper [ThomasEHart2006a], ++as well as further work on efficient implementations of preemptible ++RCU [PaulEMcKenney2006b], but priority-boosting of RCU read-side critical ++sections proved elusive. An RCU implementation permitting general ++blocking in read-side critical sections appeared [PaulEMcKenney2006c], ++Robert Olsson described an RCU-protected trie-hash combination ++[RobertOlsson2006a]. ++ ++In 2007, the RCU priority-boosting problem finally was solved ++[PaulEMcKenney2007BoostRCU], and an RCU paper was first accepted into ++an academic journal [ThomasEHart2007a]. An LWN article on the use of ++Promela and spin to validate parallel algorithms [PaulEMcKenney2007QRCUspin] ++also described Oleg Nesterov's QRCU, the first RCU implementation that ++can boast deep sub-microsecond grace periods (in absence of readers, ++and read-side overhead is roughly that of a global reference count). ++ ++ + Bibtex Entries + + @article{Kung80 +@@ -203,6 +229,41 @@ Bibtex Entries + ,Address="New Orleans, LA" + } + ++@conference{Pu95a, ++Author = "Calton Pu and Tito Autrey and Andrew Black and Charles Consel and ++Crispin Cowan and Jon Inouye and Lakshmi Kethana and Jonathan Walpole and ++Ke Zhang", ++Title = "Optimistic Incremental Specialization: Streamlining a Commercial ++Operating System", ++Booktitle = "15\textsuperscript{th} ACM Symposium on ++Operating Systems Principles (SOSP'95)", ++address = "Copper Mountain, CO", ++month="December", ++year="1995", ++pages="314-321", ++annotation=" ++ Uses a replugger, but with a flag to signal when people are ++ using the resource at hand. Only one reader at a time. ++" ++} ++ ++@conference{Cowan96a, ++Author = "Crispin Cowan and Tito Autrey and Charles Krasic and ++Calton Pu and Jonathan Walpole", ++Title = "Fast Concurrent Dynamic Linking for an Adaptive Operating System", ++Booktitle = "International Conference on Configurable Distributed Systems ++(ICCDS'96)", ++address = "Annapolis, MD", ++month="May", ++year="1996", ++pages="108", ++isbn="0-8186-7395-8", ++annotation=" ++ Uses a replugger, but with a counter to signal when people are ++ using the resource at hand. Allows multiple readers. ++" ++} ++ + @techreport{Slingwine95 + ,author="John D. Slingwine and Paul E. McKenney" + ,title="Apparatus and Method for Achieving Reduced Overhead Mutual +@@ -312,6 +373,49 @@ Andrea Arcangeli and Andi Kleen and Orra + [Viewed June 23, 2004]" + } + ++@conference{Michael02a ++,author="Maged M. Michael" ++,title="Safe Memory Reclamation for Dynamic Lock-Free Objects Using Atomic ++Reads and Writes" ++,Year="2002" ++,Month="August" ++,booktitle="{Proceedings of the 21\textsuperscript{st} Annual ACM ++Symposium on Principles of Distributed Computing}" ++,pages="21-30" ++,annotation=" ++ Each thread keeps an array of pointers to items that it is ++ currently referencing. Sort of an inside-out garbage collection ++ mechanism, but one that requires the accessing code to explicitly ++ state its needs. Also requires read-side memory barriers on ++ most architectures. ++" ++} ++ ++@conference{Michael02b ++,author="Maged M. Michael" ++,title="High Performance Dynamic Lock-Free Hash Tables and List-Based Sets" ++,Year="2002" ++,Month="August" ++,booktitle="{Proceedings of the 14\textsuperscript{th} Annual ACM ++Symposium on Parallel ++Algorithms and Architecture}" ++,pages="73-82" ++,annotation=" ++ Like the title says... ++" ++} ++ ++@InProceedings{HerlihyLM02 ++,author={Maurice Herlihy and Victor Luchangco and Mark Moir} ++,title="The Repeat Offender Problem: A Mechanism for Supporting Dynamic-Sized, ++Lock-Free Data Structures" ++,booktitle={Proceedings of 16\textsuperscript{th} International ++Symposium on Distributed Computing} ++,year=2002 ++,month="October" ++,pages="339-353" ++} ++ + @article{Appavoo03a + ,author="J. Appavoo and K. Hui and C. A. N. Soules and R. W. Wisniewski and + D. M. {Da Silva} and O. Krieger and M. A. Auslander and D. J. Edelsohn and +@@ -447,3 +551,111 @@ Oregon Health and Sciences University" + Realtime turns into making RCU yet more realtime friendly. + " + } ++ ++@conference{ThomasEHart2006a ++,Author="Thomas E. Hart and Paul E. McKenney and Angela Demke Brown" ++,Title="Making Lockless Synchronization Fast: Performance Implications ++of Memory Reclamation" ++,Booktitle="20\textsuperscript{th} {IEEE} International Parallel and ++Distributed Processing Symposium" ++,month="April" ++,year="2006" ++,day="25-29" ++,address="Rhodes, Greece" ++,annotation=" ++ Compares QSBR (AKA "classic RCU"), HPBR, EBR, and lock-free ++ reference counting. ++" ++} ++ ++@Conference{PaulEMcKenney2006b ++,Author="Paul E. McKenney and Dipankar Sarma and Ingo Molnar and ++Suparna Bhattacharya" ++,Title="Extending RCU for Realtime and Embedded Workloads" ++,Booktitle="{Ottawa Linux Symposium}" ++,Month="July" ++,Year="2006" ++,pages="v2 123-138" ++,note="Available: ++\url{http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184} ++\url{http://www.rdrop.com/users/paulmck/RCU/OLSrtRCU.2006.08.11a.pdf} ++[Viewed January 1, 2007]" ++,annotation=" ++ Described how to improve the -rt implementation of realtime RCU. ++" ++} ++ ++@unpublished{PaulEMcKenney2006c ++,Author="Paul E. McKenney" ++,Title="Sleepable {RCU}" ++,month="October" ++,day="9" ++,year="2006" ++,note="Available: ++\url{http://lwn.net/Articles/202847/} ++Revised: ++\url{http://www.rdrop.com/users/paulmck/RCU/srcu.2007.01.14a.pdf} ++[Viewed August 21, 2006]" ++,annotation=" ++ LWN article introducing SRCU. ++" ++} ++ ++@unpublished{RobertOlsson2006a ++,Author="Robert Olsson and Stefan Nilsson" ++,Title="{TRASH}: A dynamic {LC}-trie and hash data structure" ++,month="August" ++,day="18" ++,year="2006" ++,note="Available: ++\url{http://www.nada.kth.se/~snilsson/public/papers/trash/trash.pdf} ++[Viewed February 24, 2007]" ++,annotation=" ++ RCU-protected dynamic trie-hash combination. ++" ++} ++ ++@unpublished{PaulEMcKenney2007BoostRCU ++,Author="Paul E. McKenney" ++,Title="Priority-Boosting {RCU} Read-Side Critical Sections" ++,month="February" ++,day="5" ++,year="2007" ++,note="Available: ++\url{http://lwn.net/Articles/220677/} ++Revised: ++\url{http://www.rdrop.com/users/paulmck/RCU/RCUbooststate.2007.04.16a.pdf} ++[Viewed September 7, 2007]" ++,annotation=" ++ LWN article introducing RCU priority boosting. ++" ++} ++ ++@unpublished{ThomasEHart2007a ++,Author="Thomas E. Hart and Paul E. McKenney and Angela Demke Brown and Jonathan Walpole" ++,Title="Performance of memory reclamation for lockless synchronization" ++,journal="J. Parallel Distrib. Comput." ++,year="2007" ++,note="To appear in J. Parallel Distrib. Comput. ++ \url{doi=10.1016/j.jpdc.2007.04.010}" ++,annotation={ ++ Compares QSBR (AKA "classic RCU"), HPBR, EBR, and lock-free ++ reference counting. Journal version of ThomasEHart2006a. ++} ++} ++ ++@unpublished{PaulEMcKenney2007QRCUspin ++,Author="Paul E. McKenney" ++,Title="Using Promela and Spin to verify parallel algorithms" ++,month="August" ++,day="1" ++,year="2007" ++,note="Available: ++\url{http://lwn.net/Articles/243851/} ++[Viewed September 8, 2007]" ++,annotation=" ++ LWN article describing Promela and spin, and also using Oleg ++ Nesterov's QRCU as an example (with Paul McKenney's fastpath). ++" ++} ++ +Index: linux-2.6.24.7-rt27/Documentation/RCU/rcu.txt +=================================================================== +--- linux-2.6.24.7-rt27.orig/Documentation/RCU/rcu.txt 2009-02-08 00:00:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/Documentation/RCU/rcu.txt 2009-02-08 00:01:42.000000000 -0500 +@@ -36,6 +36,14 @@ o How can the updater tell when a grace + executed in user mode, or executed in the idle loop, we can + safely free up that item. + ++ Preemptible variants of RCU (CONFIG_PREEMPT_RCU) get the ++ same effect, but require that the readers manipulate CPU-local ++ counters. These counters allow limited types of blocking ++ within RCU read-side critical sections. SRCU also uses ++ CPU-local counters, and permits general blocking within ++ RCU read-side critical sections. These two variants of ++ RCU detect grace periods by sampling these counters. ++ + o If I am running on a uniprocessor kernel, which can only do one + thing at a time, why should I wait for a grace period? + +@@ -46,7 +54,10 @@ o How can I see where RCU is currently u + Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu", + "rcu_read_lock_bh", "rcu_read_unlock_bh", "call_rcu_bh", + "srcu_read_lock", "srcu_read_unlock", "synchronize_rcu", +- "synchronize_net", and "synchronize_srcu". ++ "synchronize_net", "synchronize_srcu", and the other RCU ++ primitives. Or grab one of the cscope databases from: ++ ++ http://www.rdrop.com/users/paulmck/RCU/linuxusage/rculocktab.html + + o What guidelines should I follow when writing code that uses RCU? + +@@ -67,7 +78,12 @@ o I hear that RCU is patented? What is + + o I hear that RCU needs work in order to support realtime kernels? + +- Yes, work in progress. ++ This work is largely completed. Realtime-friendly RCU can be ++ enabled via the CONFIG_PREEMPT_RCU kernel configuration parameter. ++ In addition, the CONFIG_PREEMPT_RCU_BOOST kernel configuration ++ parameter enables priority boosting of preempted RCU read-side ++ critical sections, though this is only needed if you have ++ CPU-bound realtime threads. + + o Where can I find more information on RCU? + +Index: linux-2.6.24.7-rt27/Documentation/RCU/torture.txt +=================================================================== +--- linux-2.6.24.7-rt27.orig/Documentation/RCU/torture.txt 2009-02-08 00:00:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/Documentation/RCU/torture.txt 2009-02-08 00:01:42.000000000 -0500 +@@ -37,6 +37,24 @@ nfakewriters This is the number of RCU f + to trigger special cases caused by multiple writers, such as + the synchronize_srcu() early return optimization. + ++preempt_torture Specifies that torturing of preemptible RCU is to be ++ undertaken, defaults to no such testing. This test ++ creates a kernel thread that runs at the lowest possible ++ realtime priority, alternating between ten seconds ++ of spinning and a short sleep period. The goal is ++ to preempt lower-priority RCU readers. Note that this ++ currently does not fail the full test, but instead simply ++ counts the number of times that a ten-second CPU burst ++ coincides with a stall in grace-period detection. ++ ++ Of course, if the grace period advances during a CPU burst, ++ that indicates that no RCU reader was preempted, so the ++ burst ends early in that case. ++ ++ Note that such stalls are expected behavior in preemptible ++ RCU implementations when RCU priority boosting is not ++ enabled (PREEMPT_RCU_BOOST=n). ++ + stat_interval The number of seconds between output of torture + statistics (via printk()). Regardless of the interval, + statistics are printed when the module is unloaded. +@@ -46,12 +64,13 @@ stat_interval The number of seconds betw + + shuffle_interval + The number of seconds to keep the test threads affinitied +- to a particular subset of the CPUs. Used in conjunction +- with test_no_idle_hz. ++ to a particular subset of the CPUs, defaults to 5 seconds. ++ Used in conjunction with test_no_idle_hz. + + test_no_idle_hz Whether or not to test the ability of RCU to operate in + a kernel that disables the scheduling-clock interrupt to + idle CPUs. Boolean parameter, "1" to test, "0" otherwise. ++ Defaults to omitting this test. + + torture_type The type of RCU to test: "rcu" for the rcu_read_lock() API, + "rcu_sync" for rcu_read_lock() with synchronous reclamation, +@@ -82,8 +101,6 @@ be evident. ;-) + + The entries are as follows: + +-o "ggp": The number of counter flips (or batches) since boot. +- + o "rtc": The hexadecimal address of the structure currently visible + to readers. + +@@ -117,8 +134,8 @@ o "Reader Pipe": Histogram of "ages" of + o "Reader Batch": Another histogram of "ages" of structures seen + by readers, but in terms of counter flips (or batches) rather + than in terms of grace periods. The legal number of non-zero +- entries is again two. The reason for this separate view is +- that it is easier to get the third entry to show up in the ++ entries is again two. The reason for this separate view is that ++ it is sometimes easier to get the third entry to show up in the + "Reader Batch" list than in the "Reader Pipe" list. + + o "Free-Block Circulation": Shows the number of torture structures +@@ -145,6 +162,21 @@ of the "old" and "current" counters for + "idx" value maps the "old" and "current" values to the underlying array, + and is useful for debugging. + ++In addition, preemptible RCU rcutorture runs will report preemption ++stalls: ++ ++rcu-torture: rtc: ffffffff88005a40 ver: 17041 tfle: 1 rta: 17041 rtaf: 7904 rtf: 16941 rtmbe: 0 ++rcu-torture: Reader Pipe: 975332139 34406 0 0 0 0 0 0 0 0 0 ++rcu-torture: Reader Batch: 975349310 17234 0 0 0 0 0 0 0 0 0 ++rcu-torture: Free-Block Circulation: 17040 17030 17028 17022 17009 16994 16982 16969 16955 16941 0 ++Preemption stalls: 0 ++ ++The first four lines are as before, and the last line records the number ++of times that grace-period processing stalled during a realtime CPU burst. ++Note that a non-zero value does not -prove- that RCU priority boosting is ++broken, because there are other things that can stall RCU grace-period ++processing. Here is hoping that someone comes up with a better test! ++ + + USAGE + +Index: linux-2.6.24.7-rt27/kernel/rcupreempt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt.c 2009-02-08 00:01:41.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt.c 2009-02-08 00:01:42.000000000 -0500 +@@ -133,7 +133,7 @@ static cpumask_t rcu_cpu_online_map = CP + * only to mediate communication between mainline code and hardware + * interrupt and NMI handlers. + */ +-#define ORDERED_WRT_IRQ(x) (*(volatile typeof(x) *)&(x)) ++#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) + + /* + * RCU_DATA_ME: find the current CPU's rcu_data structure. +@@ -186,7 +186,7 @@ void __rcu_read_lock(void) + struct task_struct *me = current; + int nesting; + +- nesting = ORDERED_WRT_IRQ(me->rcu_read_lock_nesting); ++ nesting = ACCESS_ONCE(me->rcu_read_lock_nesting); + if (nesting != 0) { + + /* An earlier rcu_read_lock() covers us, just count it. */ +@@ -211,9 +211,9 @@ void __rcu_read_lock(void) + * casts to prevent the compiler from reordering. + */ + +- idx = ORDERED_WRT_IRQ(rcu_ctrlblk.completed) & 0x1; ++ idx = ACCESS_ONCE(rcu_ctrlblk.completed) & 0x1; + smp_read_barrier_depends(); /* @@@@ might be unneeded */ +- ORDERED_WRT_IRQ(__get_cpu_var(rcu_flipctr)[idx])++; ++ ACCESS_ONCE(__get_cpu_var(rcu_flipctr)[idx])++; + + /* + * Now that the per-CPU counter has been incremented, we +@@ -223,7 +223,7 @@ void __rcu_read_lock(void) + * of the need to increment the per-CPU counter. + */ + +- ORDERED_WRT_IRQ(me->rcu_read_lock_nesting) = nesting + 1; ++ ACCESS_ONCE(me->rcu_read_lock_nesting) = nesting + 1; + + /* + * Now that we have preventing any NMIs from storing +@@ -232,7 +232,7 @@ void __rcu_read_lock(void) + * rcu_read_unlock(). + */ + +- ORDERED_WRT_IRQ(me->rcu_flipctr_idx) = idx; ++ ACCESS_ONCE(me->rcu_flipctr_idx) = idx; + local_irq_restore(oldirq); + } + } +@@ -244,7 +244,7 @@ void __rcu_read_unlock(void) + struct task_struct *me = current; + int nesting; + +- nesting = ORDERED_WRT_IRQ(me->rcu_read_lock_nesting); ++ nesting = ACCESS_ONCE(me->rcu_read_lock_nesting); + if (nesting > 1) { + + /* +@@ -284,7 +284,7 @@ void __rcu_read_unlock(void) + * DEC Alpha. + */ + +- idx = ORDERED_WRT_IRQ(me->rcu_flipctr_idx); ++ idx = ACCESS_ONCE(me->rcu_flipctr_idx); + smp_read_barrier_depends(); /* @@@ Needed??? */ + + /* +@@ -293,7 +293,7 @@ void __rcu_read_unlock(void) + * After this, any interrupts or NMIs will increment and + * decrement the per-CPU counters. + */ +- ORDERED_WRT_IRQ(me->rcu_read_lock_nesting) = nesting - 1; ++ ACCESS_ONCE(me->rcu_read_lock_nesting) = nesting - 1; + + /* + * It is now safe to decrement this task's nesting count. +@@ -304,7 +304,7 @@ void __rcu_read_unlock(void) + * but that is OK, since we have already fetched it. + */ + +- ORDERED_WRT_IRQ(__get_cpu_var(rcu_flipctr)[idx])--; ++ ACCESS_ONCE(__get_cpu_var(rcu_flipctr)[idx])--; + local_irq_restore(oldirq); + } + } +@@ -496,7 +496,7 @@ rcu_try_flip_waitmb(void) + /* + * Attempt a single flip of the counters. Remember, a single flip does + * -not- constitute a grace period. Instead, the interval between +- * at least three consecutive flips is a grace period. ++ * at least GP_STAGES+2 consecutive flips is a grace period. + * + * If anyone is nuts enough to run this CONFIG_PREEMPT_RCU implementation + * on a large SMP, they might want to use a hierarchical organization of --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0025-0011-sched-break-out-search-for-RT-tasks.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0025-0011-sched-break-out-search-for-RT-tasks.patch @@ -0,0 +1,114 @@ +From 34addd81b2d8c437daf1f295b924459a6bc34f5e Mon Sep 17 00:00:00 2001 +From: Gregory Haskins +Date: Tue, 11 Dec 2007 10:02:38 +0100 +Subject: [PATCH] sched: break out search for RT tasks + +Isolate the search logic into a function so that it can be used later +in places other than find_locked_lowest_rq(). + +Signed-off-by: Gregory Haskins +Signed-off-by: Steven Rostedt +Signed-off-by: Ingo Molnar + +--- + kernel/sched_rt.c | 66 +++++++++++++++++++++++++++++++----------------------- + 1 file changed, 39 insertions(+), 27 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:00:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:00:55.000000000 -0500 +@@ -259,54 +259,66 @@ static struct task_struct *pick_next_hig + + static DEFINE_PER_CPU(cpumask_t, local_cpu_mask); + +-/* Will lock the rq it finds */ +-static struct rq *find_lock_lowest_rq(struct task_struct *task, +- struct rq *this_rq) ++static int find_lowest_rq(struct task_struct *task) + { +- struct rq *lowest_rq = NULL; + int cpu; +- int tries; + cpumask_t *cpu_mask = &__get_cpu_var(local_cpu_mask); ++ struct rq *lowest_rq = NULL; + + cpus_and(*cpu_mask, cpu_online_map, task->cpus_allowed); + +- for (tries = 0; tries < RT_MAX_TRIES; tries++) { +- /* +- * Scan each rq for the lowest prio. +- */ +- for_each_cpu_mask(cpu, *cpu_mask) { +- struct rq *rq = &per_cpu(runqueues, cpu); ++ /* ++ * Scan each rq for the lowest prio. ++ */ ++ for_each_cpu_mask(cpu, *cpu_mask) { ++ struct rq *rq = cpu_rq(cpu); + +- if (cpu == this_rq->cpu) +- continue; ++ if (cpu == rq->cpu) ++ continue; + +- /* We look for lowest RT prio or non-rt CPU */ +- if (rq->rt.highest_prio >= MAX_RT_PRIO) { +- lowest_rq = rq; +- break; +- } ++ /* We look for lowest RT prio or non-rt CPU */ ++ if (rq->rt.highest_prio >= MAX_RT_PRIO) { ++ lowest_rq = rq; ++ break; ++ } + +- /* no locking for now */ +- if (rq->rt.highest_prio > task->prio && +- (!lowest_rq || rq->rt.highest_prio > lowest_rq->rt.highest_prio)) { +- lowest_rq = rq; +- } ++ /* no locking for now */ ++ if (rq->rt.highest_prio > task->prio && ++ (!lowest_rq || rq->rt.highest_prio > lowest_rq->rt.highest_prio)) { ++ lowest_rq = rq; + } ++ } ++ ++ return lowest_rq ? lowest_rq->cpu : -1; ++} ++ ++/* Will lock the rq it finds */ ++static struct rq *find_lock_lowest_rq(struct task_struct *task, ++ struct rq *rq) ++{ ++ struct rq *lowest_rq = NULL; ++ int cpu; ++ int tries; + +- if (!lowest_rq) ++ for (tries = 0; tries < RT_MAX_TRIES; tries++) { ++ cpu = find_lowest_rq(task); ++ ++ if (cpu == -1) + break; + ++ lowest_rq = cpu_rq(cpu); ++ + /* if the prio of this runqueue changed, try again */ +- if (double_lock_balance(this_rq, lowest_rq)) { ++ if (double_lock_balance(rq, lowest_rq)) { + /* + * We had to unlock the run queue. In + * the mean time, task could have + * migrated already or had its affinity changed. + * Also make sure that it wasn't scheduled on its rq. + */ +- if (unlikely(task_rq(task) != this_rq || ++ if (unlikely(task_rq(task) != rq || + !cpu_isset(lowest_rq->cpu, task->cpus_allowed) || +- task_running(this_rq, task) || ++ task_running(rq, task) || + !task->se.on_rq)) { + spin_unlock(&lowest_rq->lock); + lowest_rq = NULL; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0171-rt-mutex-i386.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0171-rt-mutex-i386.patch @@ -0,0 +1,732 @@ +--- + arch/x86/Kconfig | 13 ++++++- + arch/x86/kernel/apm_32.c | 2 - + arch/x86/kernel/entry_32.S | 4 +- + arch/x86/kernel/i386_ksyms_32.c | 12 ++++--- + arch/x86/kernel/process_32.c | 10 +++--- + arch/x86/lib/semaphore_32.S | 24 +++++++------- + include/asm-x86/rwsem.h | 41 ++++++++++++------------ + include/asm-x86/semaphore_32.h | 65 +++++++++++++++++++++++---------------- + include/asm-x86/spinlock_32.h | 36 ++++++++++----------- + include/asm-x86/spinlock_types.h | 4 +- + include/asm-x86/thread_info_32.h | 3 + + 11 files changed, 121 insertions(+), 93 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/Kconfig 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/Kconfig 2009-02-08 00:02:04.000000000 -0500 +@@ -96,10 +96,19 @@ config DMI + default y + + config RWSEM_GENERIC_SPINLOCK +- def_bool !X86_XADD ++ bool ++ depends on !X86_XADD || PREEMPT_RT ++ default y ++ ++config ASM_SEMAPHORES ++ bool ++ default y ++ + + config RWSEM_XCHGADD_ALGORITHM +- def_bool X86_XADD ++ bool ++ depends on X86_XADD && !RWSEM_GENERIC_SPINLOCK ++ default y + + config ARCH_HAS_ILOG2_U32 + def_bool n +Index: linux-2.6.24.7-rt27/arch/x86/kernel/apm_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/apm_32.c 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/apm_32.c 2009-02-08 00:02:04.000000000 -0500 +@@ -783,7 +783,7 @@ static int apm_do_idle(void) + */ + smp_mb(); + } +- if (!need_resched()) { ++ if (!need_resched() && !need_resched_delayed()) { + idled = 1; + ret = apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax); + } +Index: linux-2.6.24.7-rt27/arch/x86/kernel/entry_32.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/entry_32.S 2009-02-08 00:01:15.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/entry_32.S 2009-02-08 00:02:04.000000000 -0500 +@@ -481,7 +481,7 @@ ENDPROC(system_call) + ALIGN + RING0_PTREGS_FRAME # can't unwind into user space anyway + work_pending: +- testb $_TIF_NEED_RESCHED, %cl ++ testl $(_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED), %ecx + jz work_notifysig + work_resched: + call schedule +@@ -494,7 +494,7 @@ work_resched: + andl $_TIF_WORK_MASK, %ecx # is there any work to be done other + # than syscall tracing? + jz restore_all +- testb $_TIF_NEED_RESCHED, %cl ++ testl $(_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED), %ecx + jnz work_resched + + work_notifysig: # deal with pending signals and +Index: linux-2.6.24.7-rt27/arch/x86/kernel/i386_ksyms_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/i386_ksyms_32.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/i386_ksyms_32.c 2009-02-08 00:02:04.000000000 -0500 +@@ -10,10 +10,12 @@ + EXPORT_SYMBOL(mcount); + #endif + +-EXPORT_SYMBOL(__down_failed); +-EXPORT_SYMBOL(__down_failed_interruptible); +-EXPORT_SYMBOL(__down_failed_trylock); +-EXPORT_SYMBOL(__up_wakeup); ++#ifdef CONFIG_ASM_SEMAPHORES ++EXPORT_SYMBOL(__compat_down_failed); ++EXPORT_SYMBOL(__compat_down_failed_interruptible); ++EXPORT_SYMBOL(__compat_down_failed_trylock); ++EXPORT_SYMBOL(__compat_up_wakeup); ++#endif + /* Networking helper routines. */ + EXPORT_SYMBOL(csum_partial_copy_generic); + +@@ -28,7 +30,7 @@ EXPORT_SYMBOL(__put_user_8); + + EXPORT_SYMBOL(strstr); + +-#ifdef CONFIG_SMP ++#if defined(CONFIG_SMP) && defined(CONFIG_ASM_SEMAPHORES) + extern void FASTCALL( __write_lock_failed(rwlock_t *rw)); + extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); + EXPORT_SYMBOL(__write_lock_failed); +Index: linux-2.6.24.7-rt27/arch/x86/kernel/process_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/process_32.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/process_32.c 2009-02-08 00:02:04.000000000 -0500 +@@ -113,7 +113,7 @@ void default_idle(void) + smp_mb(); + + local_irq_disable(); +- if (!need_resched()) ++ if (!need_resched() && !need_resched_delayed()) + safe_halt(); /* enables interrupts racelessly */ + else + local_irq_enable(); +@@ -178,7 +178,7 @@ void cpu_idle(void) + /* endless idle loop with no priority at all */ + while (1) { + tick_nohz_stop_sched_tick(); +- while (!need_resched()) { ++ while (!need_resched() && !need_resched_delayed()) { + void (*idle)(void); + + if (__get_cpu_var(cpu_idle_state)) +@@ -201,7 +201,7 @@ void cpu_idle(void) + start_critical_timings(); + } + tick_nohz_restart_sched_tick(); +- preempt_enable_no_resched(); ++ __preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } +@@ -260,10 +260,10 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); + */ + void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) + { +- if (!need_resched()) { ++ if (!need_resched() && !need_resched_delayed()) { + __monitor((void *)¤t_thread_info()->flags, 0, 0); + smp_mb(); +- if (!need_resched()) ++ if (!need_resched() && !need_resched_delayed()) + __mwait(eax, ecx); + } + } +Index: linux-2.6.24.7-rt27/arch/x86/lib/semaphore_32.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/lib/semaphore_32.S 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/lib/semaphore_32.S 2009-02-08 00:02:04.000000000 -0500 +@@ -30,7 +30,7 @@ + * value or just clobbered.. + */ + .section .sched.text +-ENTRY(__down_failed) ++ENTRY(__compat_down_failed) + CFI_STARTPROC + FRAME + pushl %edx +@@ -39,7 +39,7 @@ ENTRY(__down_failed) + pushl %ecx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ecx,0 +- call __down ++ call __compat_down + popl %ecx + CFI_ADJUST_CFA_OFFSET -4 + CFI_RESTORE ecx +@@ -49,9 +49,9 @@ ENTRY(__down_failed) + ENDFRAME + ret + CFI_ENDPROC +- END(__down_failed) ++ END(__compat_down_failed) + +-ENTRY(__down_failed_interruptible) ++ENTRY(__compat_down_failed_interruptible) + CFI_STARTPROC + FRAME + pushl %edx +@@ -60,7 +60,7 @@ ENTRY(__down_failed_interruptible) + pushl %ecx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ecx,0 +- call __down_interruptible ++ call __compat_down_interruptible + popl %ecx + CFI_ADJUST_CFA_OFFSET -4 + CFI_RESTORE ecx +@@ -70,9 +70,9 @@ ENTRY(__down_failed_interruptible) + ENDFRAME + ret + CFI_ENDPROC +- END(__down_failed_interruptible) ++ END(__compat_down_failed_interruptible) + +-ENTRY(__down_failed_trylock) ++ENTRY(__compat_down_failed_trylock) + CFI_STARTPROC + FRAME + pushl %edx +@@ -81,7 +81,7 @@ ENTRY(__down_failed_trylock) + pushl %ecx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ecx,0 +- call __down_trylock ++ call __compat_down_trylock + popl %ecx + CFI_ADJUST_CFA_OFFSET -4 + CFI_RESTORE ecx +@@ -91,9 +91,9 @@ ENTRY(__down_failed_trylock) + ENDFRAME + ret + CFI_ENDPROC +- END(__down_failed_trylock) ++ END(__compat_down_failed_trylock) + +-ENTRY(__up_wakeup) ++ENTRY(__compat_up_wakeup) + CFI_STARTPROC + FRAME + pushl %edx +@@ -102,7 +102,7 @@ ENTRY(__up_wakeup) + pushl %ecx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ecx,0 +- call __up ++ call __compat_up + popl %ecx + CFI_ADJUST_CFA_OFFSET -4 + CFI_RESTORE ecx +@@ -112,7 +112,7 @@ ENTRY(__up_wakeup) + ENDFRAME + ret + CFI_ENDPROC +- END(__up_wakeup) ++ END(__compat_up_wakeup) + + /* + * rw spinlock fallbacks +Index: linux-2.6.24.7-rt27/include/asm-x86/rwsem.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/rwsem.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/rwsem.h 2009-02-08 00:02:04.000000000 -0500 +@@ -44,15 +44,15 @@ + + struct rwsem_waiter; + +-extern struct rw_semaphore *FASTCALL(rwsem_down_read_failed(struct rw_semaphore *sem)); +-extern struct rw_semaphore *FASTCALL(rwsem_down_write_failed(struct rw_semaphore *sem)); +-extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *)); +-extern struct rw_semaphore *FASTCALL(rwsem_downgrade_wake(struct rw_semaphore *sem)); ++extern struct compat_rw_semaphore *FASTCALL(rwsem_down_read_failed(struct compat_rw_semaphore *sem)); ++extern struct compat_rw_semaphore *FASTCALL(rwsem_down_write_failed(struct compat_rw_semaphore *sem)); ++extern struct compat_rw_semaphore *FASTCALL(rwsem_wake(struct compat_rw_semaphore *)); ++extern struct compat_rw_semaphore *FASTCALL(rwsem_downgrade_wake(struct compat_rw_semaphore *sem)); + + /* + * the semaphore definition + */ +-struct rw_semaphore { ++struct compat_rw_semaphore { + signed long count; + #define RWSEM_UNLOCKED_VALUE 0x00000000 + #define RWSEM_ACTIVE_BIAS 0x00000001 +@@ -78,23 +78,23 @@ struct rw_semaphore { + { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \ + LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) } + +-#define DECLARE_RWSEM(name) \ +- struct rw_semaphore name = __RWSEM_INITIALIZER(name) ++#define COMPAT_DECLARE_RWSEM(name) \ ++ struct compat_rw_semaphore name = __RWSEM_INITIALIZER(name) + +-extern void __init_rwsem(struct rw_semaphore *sem, const char *name, ++extern void __compat_init_rwsem(struct rw_semaphore *sem, const char *name, + struct lock_class_key *key); + +-#define init_rwsem(sem) \ ++#define compat_init_rwsem(sem) \ + do { \ + static struct lock_class_key __key; \ + \ +- __init_rwsem((sem), #sem, &__key); \ ++ __compat_init_rwsem((sem), #sem, &__key); \ + } while (0) + + /* + * lock for reading + */ +-static inline void __down_read(struct rw_semaphore *sem) ++static inline void __down_read(struct compat_rw_semaphore *sem) + { + __asm__ __volatile__( + "# beginning down_read\n\t" +@@ -111,7 +111,7 @@ LOCK_PREFIX " incl (%%eax)\n\t" /* + /* + * trylock for reading -- returns 1 if successful, 0 if contention + */ +-static inline int __down_read_trylock(struct rw_semaphore *sem) ++static inline int __down_read_trylock(struct compat_rw_semaphore *sem) + { + __s32 result, tmp; + __asm__ __volatile__( +@@ -134,7 +134,8 @@ LOCK_PREFIX " cmpxchgl %2,%0\n\t" + /* + * lock for writing + */ +-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) ++static inline void ++__down_write_nested(struct compat_rw_semaphore *sem, int subclass) + { + int tmp; + +@@ -160,7 +161,7 @@ static inline void __down_write(struct r + /* + * trylock for writing -- returns 1 if successful, 0 if contention + */ +-static inline int __down_write_trylock(struct rw_semaphore *sem) ++static inline int __down_write_trylock(struct compat_rw_semaphore *sem) + { + signed long ret = cmpxchg(&sem->count, + RWSEM_UNLOCKED_VALUE, +@@ -173,7 +174,7 @@ static inline int __down_write_trylock(s + /* + * unlock after reading + */ +-static inline void __up_read(struct rw_semaphore *sem) ++static inline void __up_read(struct compat_rw_semaphore *sem) + { + __s32 tmp = -RWSEM_ACTIVE_READ_BIAS; + __asm__ __volatile__( +@@ -191,7 +192,7 @@ LOCK_PREFIX " xadd %%edx,(%%eax)\n + /* + * unlock after writing + */ +-static inline void __up_write(struct rw_semaphore *sem) ++static inline void __up_write(struct compat_rw_semaphore *sem) + { + __asm__ __volatile__( + "# beginning __up_write\n\t" +@@ -209,7 +210,7 @@ LOCK_PREFIX " xaddl %%edx,(%%eax)\n + /* + * downgrade write lock to read lock + */ +-static inline void __downgrade_write(struct rw_semaphore *sem) ++static inline void __downgrade_write(struct compat_rw_semaphore *sem) + { + __asm__ __volatile__( + "# beginning __downgrade_write\n\t" +@@ -226,7 +227,7 @@ LOCK_PREFIX " addl %2,(%%eax)\n\t" + /* + * implement atomic add functionality + */ +-static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) ++static inline void rwsem_atomic_add(int delta, struct compat_rw_semaphore *sem) + { + __asm__ __volatile__( + LOCK_PREFIX "addl %1,%0" +@@ -237,7 +238,7 @@ LOCK_PREFIX "addl %1,%0" + /* + * implement exchange and add functionality + */ +-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) ++static inline int rwsem_atomic_update(int delta, struct compat_rw_semaphore *sem) + { + int tmp = delta; + +@@ -249,7 +250,7 @@ LOCK_PREFIX "xadd %0,%1" + return tmp+delta; + } + +-static inline int rwsem_is_locked(struct rw_semaphore *sem) ++static inline int compat_rwsem_is_locked(struct rw_semaphore *sem) + { + return (sem->count != 0); + } +Index: linux-2.6.24.7-rt27/include/asm-x86/semaphore_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/semaphore_32.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/semaphore_32.h 2009-02-08 00:02:04.000000000 -0500 +@@ -3,8 +3,6 @@ + + #include + +-#ifdef __KERNEL__ +- + /* + * SMP- and interrupt-safe semaphores.. + * +@@ -41,29 +39,39 @@ + #include + #include + +-struct semaphore { ++/* ++ * On !PREEMPT_RT all semaphores are compat: ++ */ ++#ifndef CONFIG_PREEMPT_RT ++# define compat_semaphore semaphore ++#endif ++ ++struct compat_semaphore { + atomic_t count; + int sleepers; + wait_queue_head_t wait; + }; + + +-#define __SEMAPHORE_INITIALIZER(name, n) \ ++#define __COMPAT_SEMAPHORE_INITIALIZER(name, n) \ + { \ + .count = ATOMIC_INIT(n), \ + .sleepers = 0, \ + .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + } + +-#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ +- struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) ++#define __COMPAT_MUTEX_INITIALIZER(name) \ ++ __COMPAT_SEMAPHORE_INITIALIZER(name,1) + +-#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) ++#define __COMPAT_DECLARE_SEMAPHORE_GENERIC(name,count) \ ++ struct compat_semaphore name = __COMPAT_SEMAPHORE_INITIALIZER(name,count) + +-static inline void sema_init (struct semaphore *sem, int val) ++#define COMPAT_DECLARE_MUTEX(name) __COMPAT_DECLARE_SEMAPHORE_GENERIC(name,1) ++ ++static inline void compat_sema_init (struct compat_semaphore *sem, int val) + { + /* +- * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); ++ * *sem = (struct compat_semaphore)__SEMAPHORE_INITIALIZER((*sem),val); + * + * i'd rather use the more flexible initialization above, but sadly + * GCC 2.7.2.3 emits a bogus warning. EGCS doesn't. Oh well. +@@ -73,27 +81,27 @@ static inline void sema_init (struct sem + init_waitqueue_head(&sem->wait); + } + +-static inline void init_MUTEX (struct semaphore *sem) ++static inline void compat_init_MUTEX (struct compat_semaphore *sem) + { +- sema_init(sem, 1); ++ compat_sema_init(sem, 1); + } + +-static inline void init_MUTEX_LOCKED (struct semaphore *sem) ++static inline void compat_init_MUTEX_LOCKED (struct compat_semaphore *sem) + { +- sema_init(sem, 0); ++ compat_sema_init(sem, 0); + } + +-fastcall void __down_failed(void /* special register calling convention */); +-fastcall int __down_failed_interruptible(void /* params in registers */); +-fastcall int __down_failed_trylock(void /* params in registers */); +-fastcall void __up_wakeup(void /* special register calling convention */); ++fastcall void __compat_down_failed(void /* special register calling convention */); ++fastcall int __compat_down_failed_interruptible(void /* params in registers */); ++fastcall int __compat_down_failed_trylock(void /* params in registers */); ++fastcall void __compat_up_wakeup(void /* special register calling convention */); + + /* + * This is ugly, but we want the default case to fall through. + * "__down_failed" is a special asm handler that calls the C + * routine that actually waits. See arch/i386/kernel/semaphore.c + */ +-static inline void down(struct semaphore * sem) ++static inline void compat_down(struct compat_semaphore * sem) + { + might_sleep(); + __asm__ __volatile__( +@@ -101,7 +109,7 @@ static inline void down(struct semaphore + LOCK_PREFIX "decl %0\n\t" /* --sem->count */ + "jns 2f\n" + "\tlea %0,%%eax\n\t" +- "call __down_failed\n" ++ "call __compat_down_failed\n" + "2:" + :"+m" (sem->count) + : +@@ -112,7 +120,7 @@ static inline void down(struct semaphore + * Interruptible try to acquire a semaphore. If we obtained + * it, return zero. If we were interrupted, returns -EINTR + */ +-static inline int down_interruptible(struct semaphore * sem) ++static inline int compat_down_interruptible(struct compat_semaphore * sem) + { + int result; + +@@ -123,7 +131,7 @@ static inline int down_interruptible(str + LOCK_PREFIX "decl %1\n\t" /* --sem->count */ + "jns 2f\n\t" + "lea %1,%%eax\n\t" +- "call __down_failed_interruptible\n" ++ "call __compat_down_failed_interruptible\n" + "2:" + :"=&a" (result), "+m" (sem->count) + : +@@ -135,7 +143,7 @@ static inline int down_interruptible(str + * Non-blockingly attempt to down() a semaphore. + * Returns zero if we acquired it + */ +-static inline int down_trylock(struct semaphore * sem) ++static inline int compat_down_trylock(struct compat_semaphore * sem) + { + int result; + +@@ -145,7 +153,7 @@ static inline int down_trylock(struct se + LOCK_PREFIX "decl %1\n\t" /* --sem->count */ + "jns 2f\n\t" + "lea %1,%%eax\n\t" +- "call __down_failed_trylock\n\t" ++ "call __compat_down_failed_trylock\n\t" + "2:\n" + :"=&a" (result), "+m" (sem->count) + : +@@ -157,19 +165,24 @@ static inline int down_trylock(struct se + * Note! This is subtle. We jump to wake people up only if + * the semaphore was negative (== somebody was waiting on it). + */ +-static inline void up(struct semaphore * sem) ++static inline void compat_up(struct compat_semaphore * sem) + { + __asm__ __volatile__( + "# atomic up operation\n\t" + LOCK_PREFIX "incl %0\n\t" /* ++sem->count */ + "jg 1f\n\t" + "lea %0,%%eax\n\t" +- "call __up_wakeup\n" ++ "call __compat_up_wakeup\n" + "1:" + :"+m" (sem->count) + : + :"memory","ax"); + } + +-#endif ++extern int FASTCALL(compat_sem_is_locked(struct compat_semaphore *sem)); ++ ++#define compat_sema_count(sem) atomic_read(&(sem)->count) ++ ++#include ++ + #endif +Index: linux-2.6.24.7-rt27/include/asm-x86/spinlock_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/spinlock_32.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/spinlock_32.h 2009-02-08 00:02:04.000000000 -0500 +@@ -27,12 +27,12 @@ + * (the type definitions are in asm/spinlock_types.h) + */ + +-static inline int __raw_spin_is_locked(raw_spinlock_t *x) ++static inline int __raw_spin_is_locked(__raw_spinlock_t *x) + { + return *(volatile signed char *)(&(x)->slock) <= 0; + } + +-static inline void __raw_spin_lock(raw_spinlock_t *lock) ++static inline void __raw_spin_lock(__raw_spinlock_t *lock) + { + asm volatile("\n1:\t" + LOCK_PREFIX " ; decb %0\n\t" +@@ -55,7 +55,7 @@ static inline void __raw_spin_lock(raw_s + * irq-traced, but on CONFIG_TRACE_IRQFLAGS we never use this variant. + */ + #ifndef CONFIG_PROVE_LOCKING +-static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) ++static inline void __raw_spin_lock_flags(__raw_spinlock_t *lock, unsigned long flags) + { + asm volatile( + "\n1:\t" +@@ -84,7 +84,7 @@ static inline void __raw_spin_lock_flags + } + #endif + +-static inline int __raw_spin_trylock(raw_spinlock_t *lock) ++static inline int __raw_spin_trylock(__raw_spinlock_t *lock) + { + char oldval; + asm volatile( +@@ -103,14 +103,14 @@ static inline int __raw_spin_trylock(raw + + #if !defined(CONFIG_X86_OOSTORE) && !defined(CONFIG_X86_PPRO_FENCE) + +-static inline void __raw_spin_unlock(raw_spinlock_t *lock) ++static inline void __raw_spin_unlock(__raw_spinlock_t *lock) + { + asm volatile("movb $1,%0" : "+m" (lock->slock) :: "memory"); + } + + #else + +-static inline void __raw_spin_unlock(raw_spinlock_t *lock) ++static inline void __raw_spin_unlock(__raw_spinlock_t *lock) + { + char oldval = 1; + +@@ -121,7 +121,7 @@ static inline void __raw_spin_unlock(raw + + #endif + +-static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock) ++static inline void __raw_spin_unlock_wait(__raw_spinlock_t *lock) + { + while (__raw_spin_is_locked(lock)) + cpu_relax(); +@@ -152,7 +152,7 @@ static inline void __raw_spin_unlock_wai + * read_can_lock - would read_trylock() succeed? + * @lock: the rwlock in question. + */ +-static inline int __raw_read_can_lock(raw_rwlock_t *x) ++static inline int __raw_read_can_lock(__raw_rwlock_t *x) + { + return (int)(x)->lock > 0; + } +@@ -161,12 +161,12 @@ static inline int __raw_read_can_lock(ra + * write_can_lock - would write_trylock() succeed? + * @lock: the rwlock in question. + */ +-static inline int __raw_write_can_lock(raw_rwlock_t *x) ++static inline int __raw_write_can_lock(__raw_rwlock_t *x) + { + return (x)->lock == RW_LOCK_BIAS; + } + +-static inline void __raw_read_lock(raw_rwlock_t *rw) ++static inline void __raw_read_lock(__raw_rwlock_t *rw) + { + asm volatile(LOCK_PREFIX " subl $1,(%0)\n\t" + "jns 1f\n" +@@ -175,7 +175,7 @@ static inline void __raw_read_lock(raw_r + ::"a" (rw) : "memory"); + } + +-static inline void __raw_write_lock(raw_rwlock_t *rw) ++static inline void __raw_write_lock(__raw_rwlock_t *rw) + { + asm volatile(LOCK_PREFIX " subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" + "jz 1f\n" +@@ -184,7 +184,7 @@ static inline void __raw_write_lock(raw_ + ::"a" (rw) : "memory"); + } + +-static inline int __raw_read_trylock(raw_rwlock_t *lock) ++static inline int __raw_read_trylock(__raw_rwlock_t *lock) + { + atomic_t *count = (atomic_t *)lock; + atomic_dec(count); +@@ -194,7 +194,7 @@ static inline int __raw_read_trylock(raw + return 0; + } + +-static inline int __raw_write_trylock(raw_rwlock_t *lock) ++static inline int __raw_write_trylock(__raw_rwlock_t *lock) + { + atomic_t *count = (atomic_t *)lock; + if (atomic_sub_and_test(RW_LOCK_BIAS, count)) +@@ -203,19 +203,19 @@ static inline int __raw_write_trylock(ra + return 0; + } + +-static inline void __raw_read_unlock(raw_rwlock_t *rw) ++static inline void __raw_read_unlock(__raw_rwlock_t *rw) + { + asm volatile(LOCK_PREFIX "incl %0" :"+m" (rw->lock) : : "memory"); + } + +-static inline void __raw_write_unlock(raw_rwlock_t *rw) ++static inline void __raw_write_unlock(__raw_rwlock_t *rw) + { + asm volatile(LOCK_PREFIX "addl $" RW_LOCK_BIAS_STR ", %0" + : "+m" (rw->lock) : : "memory"); + } + +-#define _raw_spin_relax(lock) cpu_relax() +-#define _raw_read_relax(lock) cpu_relax() +-#define _raw_write_relax(lock) cpu_relax() ++#define __raw_spin_relax(lock) cpu_relax() ++#define __raw_read_relax(lock) cpu_relax() ++#define __raw_write_relax(lock) cpu_relax() + + #endif /* __ASM_SPINLOCK_H */ +Index: linux-2.6.24.7-rt27/include/asm-x86/spinlock_types.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/spinlock_types.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/spinlock_types.h 2009-02-08 00:02:04.000000000 -0500 +@@ -7,13 +7,13 @@ + + typedef struct { + unsigned int slock; +-} raw_spinlock_t; ++} __raw_spinlock_t; + + #define __RAW_SPIN_LOCK_UNLOCKED { 1 } + + typedef struct { + unsigned int lock; +-} raw_rwlock_t; ++} __raw_rwlock_t; + + #define __RAW_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } + +Index: linux-2.6.24.7-rt27/include/asm-x86/thread_info_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/thread_info_32.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/thread_info_32.h 2009-02-08 00:02:04.000000000 -0500 +@@ -132,15 +132,18 @@ static inline struct thread_info *curren + #define TIF_SYSCALL_AUDIT 6 /* syscall auditing active */ + #define TIF_SECCOMP 7 /* secure computing */ + #define TIF_RESTORE_SIGMASK 8 /* restore signal mask in do_signal() */ ++#define TIF_NEED_RESCHED_DELAYED 10 /* reschedule on return to userspace */ + #define TIF_MEMDIE 16 + #define TIF_DEBUG 17 /* uses debug registers */ + #define TIF_IO_BITMAP 18 /* uses I/O bitmap */ + #define TIF_FREEZE 19 /* is freezing for suspend */ + #define TIF_NOTSC 20 /* TSC is not accessible in userland */ + ++ + #define _TIF_SYSCALL_TRACE (1< +To: linux-rt-users@vger.kernel.org +Cc: linux-kernel@vger.kernel.org, khilman@mvista.com, rostedt@goodmis.org, + Thomas Gleixner , Ingo Molnar +Subject: [PATCH 2.6.24-rt1] timer:fix build warning in timer.c + + [ The following text is in the "UTF-8" character set. ] + [ Your display is set for the "iso-8859-1" character set. ] + [ Some characters may be displayed incorrectly. ] + +Fix the following compile warning without CONFIG_PREEMPT_RT: +kernel/timer.c:937: warning: â^À^Øcount_active_rt_tasksâ^À^Ù defined but not used + +Signed-off-by: Shi Weihua + +--- +--- + kernel/timer.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/timer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/timer.c 2009-02-08 00:03:38.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/timer.c 2009-02-08 00:04:11.000000000 -0500 +@@ -939,20 +939,18 @@ static unsigned long count_active_tasks( + #endif + } + ++#ifdef CONFIG_PREEMPT_RT + /* + * Nr of active tasks - counted in fixed-point numbers + */ + static unsigned long count_active_rt_tasks(void) + { +-#ifdef CONFIG_PREEMPT_RT + extern unsigned long rt_nr_running(void); + extern unsigned long rt_nr_uninterruptible(void); + + return (rt_nr_running() + rt_nr_uninterruptible()) * FIXED_1; +-#else +- return 0; +-#endif + } ++#endif + + /* + * Hmm.. Changed this, as the GNU make sources (load.c) seems to --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0543-qla-mbx-compat-cast.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0543-qla-mbx-compat-cast.patch @@ -0,0 +1,24 @@ +From: Steven Rostedt +Subject: fix semaphore type in qla_mbx + +A compat_semaphore is passed as a pointer to a timeout function, but +that timeout function converts it to a semaphore instead of a compat. + +Signed-off-by: Steven Rostedt +--- + drivers/scsi/qla2xxx/qla_mbx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/drivers/scsi/qla2xxx/qla_mbx.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/scsi/qla2xxx/qla_mbx.c 2009-02-07 23:59:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/scsi/qla2xxx/qla_mbx.c 2009-02-08 00:05:09.000000000 -0500 +@@ -11,7 +11,7 @@ + static void + qla2x00_mbx_sem_timeout(unsigned long data) + { +- struct semaphore *sem_ptr = (struct semaphore *)data; ++ struct compat_semaphore *sem_ptr = (struct compat_semaphore *)data; + + DEBUG11(printk("qla2x00_sem_timeout: entered.\n")); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0476-adapt-remove-extra-try-to-lock.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0476-adapt-remove-extra-try-to-lock.patch @@ -0,0 +1,44 @@ +From ghaskins@novell.com Sat May 24 00:14:29 2008 +Date: Tue, 20 May 2008 10:49:36 -0400 +From: Gregory Haskins +To: mingo@elte.hu, tglx@linutronix.de, rostedt@goodmis.org, + linux-rt-users@vger.kernel.org +Cc: linux-kernel@vger.kernel.org, sdietrich@novell.com, pmorreale@novell.com, + mkohari@novell.com, ghaskins@novell.com +Subject: [PATCH 5/5] remove the extra call to try_to_take_lock + + [ The following text is in the "utf-8" character set. ] + [ Your display is set for the "iso-8859-1" character set. ] + [ Some characters may be displayed incorrectly. ] + +From: Peter W. Morreale + +Remove the redundant attempt to get the lock. While it is true that the +exit path with this patch adds an un-necessary xchg (in the event the +lock is granted without further traversal in the loop) experimentation +shows that we almost never encounter this situation. + +Signed-off-by: Peter W. Morreale +Signed-off-by: Gregory Haskins +--- + + kernel/rtmutex.c | 6 ------ + 1 file changed, 6 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:36.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:37.000000000 -0500 +@@ -842,12 +842,6 @@ rt_spin_lock_slowlock(struct rt_mutex *l + spin_lock_irqsave(&lock->wait_lock, flags); + init_lists(lock); + +- /* Try to acquire the lock again: */ +- if (do_try_to_take_rt_mutex(lock, STEAL_LATERAL)) { +- spin_unlock_irqrestore(&lock->wait_lock, flags); +- return; +- } +- + BUG_ON(rt_mutex_owner(lock) == current); + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0207-arm-trace-preempt-idle.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0207-arm-trace-preempt-idle.patch @@ -0,0 +1,65 @@ +From linux-rt-users-owner@vger.kernel.org Fri Jul 13 20:13:14 2007 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.1.7-deb (2006-10-05) on debian +X-Spam-Level: +X-Spam-Status: No, score=0.0 required=5.0 tests=AWL autolearn=unavailable + version=3.1.7-deb +Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by + mail.tglx.de (Postfix) with ESMTP id 5902865C3EB; Fri, 13 Jul 2007 20:13:14 + +0200 (CEST) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id + S933095AbXGMSNN (ORCPT + 1 other); + Fri, 13 Jul 2007 14:13:13 -0400 +Received: (majordomo@vger.kernel.org) by vger.kernel.org id S933031AbXGMSNM + (ORCPT ); Fri, 13 Jul 2007 14:13:12 -0400 +Received: from deeprooted.net ([216.254.16.51]:38941 "EHLO + paris.hilman.org" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP + id S1760089AbXGMSNH (ORCPT ); Fri, + 13 Jul 2007 14:13:07 -0400 +Received: by paris.hilman.org (Postfix, from userid 1000) id E61B1D2857A; + Fri, 13 Jul 2007 10:52:28 -0700 (PDT) +Message-Id: <20070713175228.623525155@mvista.com> +References: <20070713175214.336577416@mvista.com> +User-Agent: quilt/0.45-1 +Date: Fri, 13 Jul 2007 10:52:18 -0700 +From: Kevin Hilman +To: tglx@linutronix.de, mingo@elte.hu +Cc: linux-rt-users@vger.kernel.org, linux-kernel@vger.kernel.org +Subject: [PATCH -rt 4/6] Add trace_preempt_*_idle() support for ARM. +Content-Disposition: inline; filename=arm-trace-preempt-idle.patch +Sender: linux-rt-users-owner@vger.kernel.org +Precedence: bulk +X-Mailing-List: linux-rt-users@vger.kernel.org +X-Filter-To: .Kernel.rt-users +X-Evolution-Source: imap://tglx%40linutronix.de@localhost:8993/ +Content-Transfer-Encoding: 8bit +Mime-Version: 1.0 + +Add trace functions to ARM idle loop and also move the +tick_nohz_restart_sched_tick() after the local_irq_disable() as is +done on x86. + +Signed-off-by: Kevin Hilman +--- + arch/arm/kernel/process.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/arm/kernel/process.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/process.c 2009-02-08 00:02:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/process.c 2009-02-08 00:02:20.000000000 -0500 +@@ -171,11 +171,13 @@ void cpu_idle(void) + while (!need_resched() && !need_resched_delayed()) + idle(); + leds_event(led_idle_end); +- tick_nohz_restart_sched_tick(); + local_irq_disable(); ++ trace_preempt_exit_idle(); ++ tick_nohz_restart_sched_tick(); + __preempt_enable_no_resched(); + __schedule(); + preempt_disable(); ++ trace_preempt_enter_idle(); + local_irq_enable(); + } + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0178-rt-mutex-m68knommu-add-compat_semaphore.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0178-rt-mutex-m68knommu-add-compat_semaphore.patch @@ -0,0 +1,251 @@ +From 6d12160b217c3a274f638f844a100ecb9d365b06 Mon Sep 17 00:00:00 2001 +From: Sebastian Siewior +Date: Fri, 18 Apr 2008 17:02:24 +0200 +Subject: [PATCH] m68knommu: add compat_semaphore + +basically a rename + +Signed-off-by: Sebastian Siewior +Signed-off-by: Thomas Gleixner +--- + arch/m68knommu/Kconfig | 4 ++ + arch/m68knommu/kernel/Makefile | 3 + + arch/m68knommu/kernel/semaphore.c | 8 ++-- + include/asm-m68knommu/semaphore-helper.h | 8 ++-- + include/asm-m68knommu/semaphore.h | 56 +++++++++++++++++-------------- + 5 files changed, 46 insertions(+), 33 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/m68knommu/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/Kconfig 2009-02-08 00:01:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/Kconfig 2009-02-08 00:02:07.000000000 -0500 +@@ -29,6 +29,10 @@ config RWSEM_XCHGADD_ALGORITHM + bool + default n + ++config ASM_SEMAPHORES ++ bool ++ default y ++ + config ARCH_HAS_ILOG2_U32 + bool + default n +Index: linux-2.6.24.7-rt27/arch/m68knommu/kernel/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/kernel/Makefile 2009-02-08 00:01:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/kernel/Makefile 2009-02-08 00:02:07.000000000 -0500 +@@ -5,8 +5,9 @@ + extra-y := vmlinux.lds + + obj-y += dma.o entry.o init_task.o irq.o m68k_ksyms.o process.o ptrace.o \ +- semaphore.o setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o ++ setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o + + obj-$(CONFIG_MODULES) += module.o + obj-$(CONFIG_COMEMPCI) += comempci.o + obj-$(CONFIG_STACKTRACE) += stacktrace.o ++obj-$(CONFIG_ASM_SEMAPHORES) += semaphore.o +Index: linux-2.6.24.7-rt27/arch/m68knommu/kernel/semaphore.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/kernel/semaphore.c 2009-02-08 00:00:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/kernel/semaphore.c 2009-02-08 00:02:07.000000000 -0500 +@@ -42,7 +42,7 @@ spinlock_t semaphore_wake_lock; + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +-void __up(struct semaphore *sem) ++void __compat_up(struct compat_semaphore *sem) + { + wake_one_more(sem); + wake_up(&sem->wait); +@@ -96,7 +96,7 @@ void __up(struct semaphore *sem) + current->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +-void __sched __down(struct semaphore * sem) ++void __sched __compat_down(struct compat_semaphore * sem) + { + DECLARE_WAITQUEUE(wait, current); + +@@ -107,7 +107,7 @@ void __sched __down(struct semaphore * s + DOWN_TAIL(TASK_UNINTERRUPTIBLE) + } + +-int __sched __down_interruptible(struct semaphore * sem) ++int __sched __compat_down_interruptible(struct compat_semaphore * sem) + { + DECLARE_WAITQUEUE(wait, current); + int ret = 0; +@@ -127,7 +127,7 @@ int __sched __down_interruptible(struct + return ret; + } + +-int __down_trylock(struct semaphore * sem) ++int __compat_down_trylock(struct compat_semaphore * sem) + { + return waking_non_zero_trylock(sem); + } +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/semaphore-helper.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/semaphore-helper.h 2009-02-08 00:00:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/semaphore-helper.h 2009-02-08 00:02:07.000000000 -0500 +@@ -13,12 +13,12 @@ + /* + * These two _must_ execute atomically wrt each other. + */ +-static inline void wake_one_more(struct semaphore * sem) ++static inline void wake_one_more(struct compat_semaphore * sem) + { + atomic_inc(&sem->waking); + } + +-static inline int waking_non_zero(struct semaphore *sem) ++static inline int waking_non_zero(struct compat_semaphore *sem) + { + int ret; + unsigned long flags; +@@ -39,7 +39,7 @@ static inline int waking_non_zero(struct + * 0 go to sleep + * -EINTR interrupted + */ +-static inline int waking_non_zero_interruptible(struct semaphore *sem, ++static inline int waking_non_zero_interruptible(struct compat_semaphore *sem, + struct task_struct *tsk) + { + int ret; +@@ -63,7 +63,7 @@ static inline int waking_non_zero_interr + * 1 failed to lock + * 0 got the lock + */ +-static inline int waking_non_zero_trylock(struct semaphore *sem) ++static inline int waking_non_zero_trylock(struct compat_semaphore *sem) + { + int ret; + unsigned long flags; +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/semaphore.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/semaphore.h 2009-02-08 00:00:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/semaphore.h 2009-02-08 00:02:07.000000000 -0500 +@@ -21,49 +21,55 @@ + * m68k version by Andreas Schwab + */ + ++#ifndef CONFIG_PREEMPT_RT ++# define compat_semaphore semaphore ++#endif + +-struct semaphore { ++struct compat_semaphore { + atomic_t count; + atomic_t waking; + wait_queue_head_t wait; + }; + +-#define __SEMAPHORE_INITIALIZER(name, n) \ ++#define __COMPAT_SEMAPHORE_INITIALIZER(name, n) \ + { \ + .count = ATOMIC_INIT(n), \ + .waking = ATOMIC_INIT(0), \ + .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + } + +-#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ +- struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) ++#define __COMPAT_DECLARE_SEMAPHORE_GENERIC(name,count) \ ++ struct compat_semaphore name = __COMPAT_SEMAPHORE_INITIALIZER(name,count) + +-#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) ++#define COMPAT_DECLARE_MUTEX(name) __COMPAT_DECLARE_SEMAPHORE_GENERIC(name,1) + +-static inline void sema_init (struct semaphore *sem, int val) ++static inline void compat_sema_init (struct compat_semaphore *sem, int val) + { +- *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val); ++ *sem = (struct compat_semaphore)__COMPAT_SEMAPHORE_INITIALIZER(*sem, val); + } + +-static inline void init_MUTEX (struct semaphore *sem) ++static inline void compat_init_MUTEX (struct compat_semaphore *sem) + { +- sema_init(sem, 1); ++ compat_sema_init(sem, 1); + } + +-static inline void init_MUTEX_LOCKED (struct semaphore *sem) ++static inline void compat_init_MUTEX_LOCKED (struct compat_semaphore *sem) + { +- sema_init(sem, 0); ++ compat_sema_init(sem, 0); + } + +-asmlinkage void __down_failed(void /* special register calling convention */); +-asmlinkage int __down_failed_interruptible(void /* params in registers */); +-asmlinkage int __down_failed_trylock(void /* params in registers */); +-asmlinkage void __up_wakeup(void /* special register calling convention */); ++asmlinkage void __compat_down_failed(void /* special register calling convention */); ++asmlinkage int __compat_down_failed_interruptible(void /* params in registers */); ++asmlinkage int __compat_down_failed_trylock(void /* params in registers */); ++asmlinkage void __compat_up_wakeup(void /* special register calling convention */); ++ ++asmlinkage void __compat_down(struct compat_semaphore * sem); ++asmlinkage int __compat_down_interruptible(struct compat_semaphore * sem); ++asmlinkage int __compat_down_trylock(struct compat_semaphore * sem); ++asmlinkage void __compat_up(struct compat_semaphore * sem); + +-asmlinkage void __down(struct semaphore * sem); +-asmlinkage int __down_interruptible(struct semaphore * sem); +-asmlinkage int __down_trylock(struct semaphore * sem); +-asmlinkage void __up(struct semaphore * sem); ++extern int compat_sem_is_locked(struct compat_semaphore *sem); ++#define compat_sema_count(sem) atomic_read(&(sem)->count) + + extern spinlock_t semaphore_wake_lock; + +@@ -72,7 +78,7 @@ extern spinlock_t semaphore_wake_lock; + * "down_failed" is a special asm handler that calls the C + * routine that actually waits. See arch/m68k/lib/semaphore.S + */ +-static inline void down(struct semaphore * sem) ++static inline void compat_down(struct compat_semaphore * sem) + { + might_sleep(); + __asm__ __volatile__( +@@ -87,7 +93,7 @@ static inline void down(struct semaphore + : "cc", "%a0", "%a1", "memory"); + } + +-static inline int down_interruptible(struct semaphore * sem) ++static inline int compat_down_interruptible(struct compat_semaphore * sem) + { + int ret; + +@@ -106,9 +112,9 @@ static inline int down_interruptible(str + return(ret); + } + +-static inline int down_trylock(struct semaphore * sem) ++static inline int compat_down_trylock(struct compat_semaphore * sem) + { +- register struct semaphore *sem1 __asm__ ("%a1") = sem; ++ register struct compat_semaphore *sem1 __asm__ ("%a1") = sem; + register int result __asm__ ("%d0"); + + __asm__ __volatile__( +@@ -134,7 +140,7 @@ static inline int down_trylock(struct se + * The default case (no contention) will result in NO + * jumps for both down() and up(). + */ +-static inline void up(struct semaphore * sem) ++static inline void compat_up(struct compat_semaphore * sem) + { + __asm__ __volatile__( + "| atomic up operation\n\t" +@@ -148,6 +154,8 @@ static inline void up(struct semaphore * + : "cc", "%a0", "%a1", "memory"); + } + ++#include ++ + #endif /* __ASSEMBLY__ */ + + #endif --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0482-ftrace-compile-fixes.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0482-ftrace-compile-fixes.patch @@ -0,0 +1,22 @@ +From: Steven Rostedt +Subject: rt: remove call to stop tracer + +Remove user_trace_stop that was more of a hack to debug xrun latencies. + +Signed-off-by: Steven Rostedt +--- + sound/core/pcm_lib.c | 1 - + 1 file changed, 1 deletion(-) + +Index: linux-2.6.24.7-rt27/sound/core/pcm_lib.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/sound/core/pcm_lib.c 2009-02-08 00:02:41.000000000 -0500 ++++ linux-2.6.24.7-rt27/sound/core/pcm_lib.c 2009-02-08 00:04:39.000000000 -0500 +@@ -131,7 +131,6 @@ static void xrun(struct snd_pcm_substrea + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + #ifdef CONFIG_SND_PCM_XRUN_DEBUG + if (substream->pstr->xrun_debug) { +- user_trace_stop(); + snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n", + substream->pcm->card->number, + substream->pcm->device, --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0406-rcu-preempt-trace-markers-1.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0406-rcu-preempt-trace-markers-1.patch @@ -0,0 +1,517 @@ +From prasad@linux.vnet.ibm.com Fri Jan 11 14:55:27 2008 +Date: Tue, 8 Jan 2008 01:25:09 +0530 +From: K. Prasad +To: linux-kernel@vger.kernel.org, mingo@elte.hu +Cc: Gautham R Shenoy , K. Prasad , + mathieu.desnoyers@polymtl.ca, linux-rt-users@vger.kernel.org, + dipankar@in.ibm.com, paulmck@linux.vnet.ibm.com +Subject: [PATCH 1/2] Markers Implementation for RCU Preempt Tracing - Ver II + +This patch converts Preempt RCU Tracing code infrastructure to implement +markers. + +- The rcupreempt_trace structure has been moved to the tracing + infrastructure and de-linked from the rcupreempt.c code. A per-cpu + instance of rcupreempt_trace structure will be maintained in + rcupreempt_trace.c + +- The above change also renders a few macro definitions unused (such as + RCU_TRACE_CPU, RCU_TRACE_ME and RCU_TRACE_RDP) which have been + removed. + +- Some of the helper functions in rcupreempt.c which were exported only + when CONFIG_RCU_TRACE was set are now exported unconditionally. These + functions operate on per-cpu variables that are used both by the RCU + and RCU Tracing code. The changes help in making RCU Tracing code + operate as a kernel module also. + +- The references to rcupreempt-boost tracing in the module + initialisation and cleanup have been removed here to enable kernel + build, but will be brought in after enclosing them inside a #ifdef + CONFIG_PREEMPT_RCU_BOOST. + +Signed-off-by: K.Prasad +--- + include/linux/rcupreempt.h | 10 ---- + include/linux/rcupreempt_trace.h | 50 ++++++++++++------------ + kernel/Kconfig.preempt | 7 +-- + kernel/rcupreempt.c | 77 ++++++++++---------------------------- + kernel/rcupreempt_trace.c | 79 +++++++++++++++++++++++++++++++++++++-- + 5 files changed, 125 insertions(+), 98 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/rcupreempt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupreempt.h 2009-02-08 00:03:47.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupreempt.h 2009-02-08 00:04:02.000000000 -0500 +@@ -96,16 +96,6 @@ extern int rcu_pending_rt(int cpu); + struct softirq_action; + extern void rcu_process_callbacks_rt(struct softirq_action *unused); + +-#ifdef CONFIG_RCU_TRACE +-struct rcupreempt_trace; +-extern int *rcupreempt_flipctr(int cpu); +-extern long rcupreempt_data_completed(void); +-extern int rcupreempt_flip_flag(int cpu); +-extern int rcupreempt_mb_flag(int cpu); +-extern char *rcupreempt_try_flip_state_name(void); +-extern struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu); +-#endif +- + struct softirq_action; + + #ifdef CONFIG_NO_HZ +Index: linux-2.6.24.7-rt27/include/linux/rcupreempt_trace.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupreempt_trace.h 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupreempt_trace.h 2009-02-08 00:04:02.000000000 -0500 +@@ -69,32 +69,32 @@ struct rcupreempt_trace { + long rcu_try_flip_m2; + }; + +-#ifdef CONFIG_RCU_TRACE +-#define RCU_TRACE(fn, arg) fn(arg); +-#else +-#define RCU_TRACE(fn, arg) +-#endif ++struct rcupreempt_probe_data { ++ const char *name; ++ const char *format; ++ marker_probe_func *probe_func; ++}; ++ ++#define DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_worker) \ ++void rcupreempt_trace_worker##_callback(const struct marker *mdata, \ ++ void *private_data, const char *format, ...) \ ++{ \ ++ struct rcupreempt_trace *trace; \ ++ trace = (&per_cpu(trace_data, smp_processor_id())); \ ++ rcupreempt_trace_worker(trace); \ ++} ++ ++#define INIT_RCUPREEMPT_PROBE(rcupreempt_trace_worker) \ ++{ \ ++ .name = __stringify(rcupreempt_trace_worker), \ ++ .probe_func = rcupreempt_trace_worker##_callback \ ++} + +-extern void rcupreempt_trace_move2done(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_1(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_i1(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_ie1(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_g1(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_a1(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_ae1(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_a2(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_z1(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_ze1(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_z2(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_m1(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_me1(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_try_flip_m2(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_invoke(struct rcupreempt_trace *trace); +-extern void rcupreempt_trace_next_add(struct rcupreempt_trace *trace); ++extern int *rcupreempt_flipctr(int cpu); ++extern long rcupreempt_data_completed(void); ++extern int rcupreempt_flip_flag(int cpu); ++extern int rcupreempt_mb_flag(int cpu); ++extern char *rcupreempt_try_flip_state_name(void); + + #endif /* __KERNEL__ */ + #endif /* __LINUX_RCUPREEMPT_TRACE_H */ +Index: linux-2.6.24.7-rt27/kernel/Kconfig.preempt +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/Kconfig.preempt 2009-02-08 00:03:46.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/Kconfig.preempt 2009-02-08 00:04:02.000000000 -0500 +@@ -172,14 +172,15 @@ config PREEMPT_RCU_BOOST + possible OOM problems. + + config RCU_TRACE +- bool "Enable tracing for RCU - currently stats in debugfs" ++ tristate "Enable tracing for RCU - currently stats in debugfs" + select DEBUG_FS +- default y ++ select MARKERS ++ default m + help + This option provides tracing in RCU which presents stats + in debugfs for debugging RCU implementation. + +- Say Y here if you want to enable RCU tracing ++ Say Y/M here if you want to enable RCU tracing in-kernel/module. + Say N if you are unsure. + + config SPINLOCK_BKL +Index: linux-2.6.24.7-rt27/kernel/rcupreempt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt.c 2009-02-08 00:03:47.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt.c 2009-02-08 00:04:02.000000000 -0500 +@@ -54,7 +54,6 @@ + #include + #include + #include +-#include + + /* + * PREEMPT_RCU data structures. +@@ -71,9 +70,6 @@ struct rcu_data { + struct rcu_head **waittail[GP_STAGES]; + struct rcu_head *donelist; + struct rcu_head **donetail; +-#ifdef CONFIG_RCU_TRACE +- struct rcupreempt_trace trace; +-#endif /* #ifdef CONFIG_RCU_TRACE */ + }; + struct rcu_ctrlblk { + raw_spinlock_t fliplock; /* Protect state-machine transitions. */ +@@ -97,10 +93,8 @@ enum rcu_try_flip_states { + rcu_try_flip_waitmb_state /* "M" */ + }; + static enum rcu_try_flip_states rcu_try_flip_state = rcu_try_flip_idle_state; +-#ifdef CONFIG_RCU_TRACE + static char *rcu_try_flip_state_names[] = + { "idle", "waitack", "waitzero", "waitmb" }; +-#endif /* #ifdef CONFIG_RCU_TRACE */ + + /* + * Enum and per-CPU flag to determine when each CPU has seen +@@ -147,24 +141,6 @@ static cpumask_t rcu_cpu_online_map = CP + #define RCU_DATA_CPU(cpu) (&per_cpu(rcu_data, cpu)) + + /* +- * Helper macro for tracing when the appropriate rcu_data is not +- * cached in a local variable, but where the CPU number is so cached. +- */ +-#define RCU_TRACE_CPU(f, cpu) RCU_TRACE(f, &(RCU_DATA_CPU(cpu)->trace)); +- +-/* +- * Helper macro for tracing when the appropriate rcu_data is not +- * cached in a local variable. +- */ +-#define RCU_TRACE_ME(f) RCU_TRACE(f, &(RCU_DATA_ME()->trace)); +- +-/* +- * Helper macro for tracing when the appropriate rcu_data is pointed +- * to by a local variable. +- */ +-#define RCU_TRACE_RDP(f, rdp) RCU_TRACE(f, &((rdp)->trace)); +- +-/* + * Return the number of RCU batches processed thus far. Useful + * for debug and statistics. + */ +@@ -332,7 +308,7 @@ static void __rcu_advance_callbacks(stru + if (rdp->waitlist[GP_STAGES - 1] != NULL) { + *rdp->donetail = rdp->waitlist[GP_STAGES - 1]; + rdp->donetail = rdp->waittail[GP_STAGES - 1]; +- RCU_TRACE_RDP(rcupreempt_trace_move2done, rdp); ++ trace_mark(rcupreempt_trace_move2done, "NULL"); + } + for (i = GP_STAGES - 2; i >= 0; i--) { + if (rdp->waitlist[i] != NULL) { +@@ -351,7 +327,7 @@ static void __rcu_advance_callbacks(stru + wlc++; + rdp->nextlist = NULL; + rdp->nexttail = &rdp->nextlist; +- RCU_TRACE_RDP(rcupreempt_trace_move2wait, rdp); ++ trace_mark(rcupreempt_trace_move2wait, "NULL"); + } else { + rdp->waitlist[0] = NULL; + rdp->waittail[0] = &rdp->waitlist[0]; +@@ -595,9 +571,9 @@ rcu_try_flip_idle(void) + { + int cpu; + +- RCU_TRACE_ME(rcupreempt_trace_try_flip_i1); ++ trace_mark(rcupreempt_trace_try_flip_i1, "NULL"); + if (!rcu_pending(smp_processor_id())) { +- RCU_TRACE_ME(rcupreempt_trace_try_flip_ie1); ++ trace_mark(rcupreempt_trace_try_flip_ie1, "NULL"); + return 0; + } + +@@ -605,7 +581,7 @@ rcu_try_flip_idle(void) + * Do the flip. + */ + +- RCU_TRACE_ME(rcupreempt_trace_try_flip_g1); ++ trace_mark(rcupreempt_trace_try_flip_g1, "NULL"); + rcu_ctrlblk.completed++; /* stands in for rcu_try_flip_g2 */ + + /* +@@ -635,11 +611,11 @@ rcu_try_flip_waitack(void) + { + int cpu; + +- RCU_TRACE_ME(rcupreempt_trace_try_flip_a1); ++ trace_mark(rcupreempt_trace_try_flip_a1, "NULL"); + for_each_cpu_mask(cpu, rcu_cpu_online_map) + if (rcu_try_flip_waitack_needed(cpu) && + per_cpu(rcu_flip_flag, cpu) != rcu_flip_seen) { +- RCU_TRACE_ME(rcupreempt_trace_try_flip_ae1); ++ trace_mark(rcupreempt_trace_try_flip_ae1, "NULL"); + return 0; + } + +@@ -649,7 +625,7 @@ rcu_try_flip_waitack(void) + */ + + smp_mb(); /* see above block comment. */ +- RCU_TRACE_ME(rcupreempt_trace_try_flip_a2); ++ trace_mark(rcupreempt_trace_try_flip_a2, "NULL"); + return 1; + } + +@@ -667,11 +643,11 @@ rcu_try_flip_waitzero(void) + + /* Check to see if the sum of the "last" counters is zero. */ + +- RCU_TRACE_ME(rcupreempt_trace_try_flip_z1); ++ trace_mark(rcupreempt_trace_try_flip_z1, "NULL"); + for_each_possible_cpu(cpu) + sum += per_cpu(rcu_flipctr, cpu)[lastidx]; + if (sum != 0) { +- RCU_TRACE_ME(rcupreempt_trace_try_flip_ze1); ++ trace_mark(rcupreempt_trace_try_flip_ze1, "NULL"); + return 0; + } + +@@ -684,7 +660,7 @@ rcu_try_flip_waitzero(void) + dyntick_save_progress_counter(cpu); + } + +- RCU_TRACE_ME(rcupreempt_trace_try_flip_z2); ++ trace_mark(rcupreempt_trace_try_flip_z2, "NULL"); + return 1; + } + +@@ -698,16 +674,16 @@ rcu_try_flip_waitmb(void) + { + int cpu; + +- RCU_TRACE_ME(rcupreempt_trace_try_flip_m1); ++ trace_mark(rcupreempt_trace_try_flip_m1, "NULL"); + for_each_cpu_mask(cpu, rcu_cpu_online_map) + if (rcu_try_flip_waitmb_needed(cpu) && + per_cpu(rcu_mb_flag, cpu) != rcu_mb_done) { +- RCU_TRACE_ME(rcupreempt_trace_try_flip_me1); ++ trace_mark(rcupreempt_trace_try_flip_me1, "NULL"); + return 0; + } + + smp_mb(); /* Ensure that the above checks precede any following flip. */ +- RCU_TRACE_ME(rcupreempt_trace_try_flip_m2); ++ trace_mark(rcupreempt_trace_try_flip_m2, "NULL"); + return 1; + } + +@@ -724,9 +700,9 @@ static void rcu_try_flip(void) + { + unsigned long oldirq; + +- RCU_TRACE_ME(rcupreempt_trace_try_flip_1); ++ trace_mark(rcupreempt_trace_try_flip_1, "NULL"); + if (unlikely(!spin_trylock_irqsave(&rcu_ctrlblk.fliplock, oldirq))) { +- RCU_TRACE_ME(rcupreempt_trace_try_flip_e1); ++ trace_mark(rcupreempt_trace_try_flip_e1, "NULL"); + return; + } + +@@ -778,7 +754,7 @@ void rcu_check_callbacks_rt(int cpu, int + if (rcu_ctrlblk.completed == rdp->completed) + rcu_try_flip(); + spin_lock_irqsave(&rdp->lock, oldirq); +- RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp); ++ trace_mark(rcupreempt_trace_check_callbacks, "NULL"); + __rcu_advance_callbacks(rdp); + spin_unlock_irqrestore(&rdp->lock, oldirq); + } +@@ -798,7 +774,7 @@ void rcu_advance_callbacks_rt(int cpu, i + return; + } + spin_lock_irqsave(&rdp->lock, oldirq); +- RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp); ++ trace_mark(rcupreempt_trace_check_callbacks, "NULL"); + __rcu_advance_callbacks(rdp); + spin_unlock_irqrestore(&rdp->lock, oldirq); + } +@@ -900,13 +876,13 @@ void rcu_process_callbacks_rt(struct sof + } + rdp->donelist = NULL; + rdp->donetail = &rdp->donelist; +- RCU_TRACE_RDP(rcupreempt_trace_done_remove, rdp); ++ trace_mark(rcupreempt_trace_done_remove, "NULL"); + spin_unlock_irqrestore(&rdp->lock, flags); + while (list) { + next = list->next; + list->func(list); + list = next; +- RCU_TRACE_ME(rcupreempt_trace_invoke); ++ trace_mark(rcupreempt_trace_invoke, "NULL"); + } + } + +@@ -924,7 +900,7 @@ void fastcall call_rcu_preempt(struct rc + __rcu_advance_callbacks(rdp); + *rdp->nexttail = head; + rdp->nexttail = &head->next; +- RCU_TRACE_RDP(rcupreempt_trace_next_add, rdp); ++ trace_mark(rcupreempt_trace_next_add, "NULL"); + spin_unlock(&rdp->lock); + local_irq_restore(oldirq); + } +@@ -1006,7 +982,6 @@ void synchronize_kernel(void) + synchronize_rcu(); + } + +-#ifdef CONFIG_RCU_TRACE + int *rcupreempt_flipctr(int cpu) + { + return &per_cpu(rcu_flipctr, cpu)[0]; +@@ -1030,13 +1005,3 @@ char *rcupreempt_try_flip_state_name(voi + return rcu_try_flip_state_names[rcu_try_flip_state]; + } + EXPORT_SYMBOL_GPL(rcupreempt_try_flip_state_name); +- +-struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu) +-{ +- struct rcu_data *rdp = RCU_DATA_CPU(cpu); +- +- return &rdp->trace; +-} +-EXPORT_SYMBOL_GPL(rcupreempt_trace_cpu); +- +-#endif /* #ifdef RCU_TRACE */ +Index: linux-2.6.24.7-rt27/kernel/rcupreempt_trace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt_trace.c 2009-02-08 00:03:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt_trace.c 2009-02-08 00:04:02.000000000 -0500 +@@ -43,11 +43,19 @@ + #include + #include + #include ++#include + + static struct mutex rcupreempt_trace_mutex; + static char *rcupreempt_trace_buf; + #define RCUPREEMPT_TRACE_BUF_SIZE 4096 + ++static DEFINE_PER_CPU(struct rcupreempt_trace, trace_data); ++ ++struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu) ++{ ++ return &per_cpu(trace_data, cpu); ++} ++ + void rcupreempt_trace_move2done(struct rcupreempt_trace *trace) + { + trace->done_length += trace->wait_length; +@@ -135,6 +143,51 @@ void rcupreempt_trace_next_add(struct rc + trace->next_length++; + } + ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_move2done); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_move2wait); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_1); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_e1); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_i1); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_ie1); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_g1); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_a1); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_ae1); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_a2); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_z1); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_ze1); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_z2); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_m1); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_me1); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_try_flip_m2); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_check_callbacks); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_done_remove); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_invoke); ++DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_next_add); ++ ++static struct rcupreempt_probe_data rcupreempt_probe_array[] = ++{ ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_move2done), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_move2wait), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_1), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_e1), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_i1), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_ie1), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_g1), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_a1), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_ae1), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_a2), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_z1), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_ze1), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_z2), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_m1), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_me1), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_try_flip_m2), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_check_callbacks), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_done_remove), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_invoke), ++ INIT_RCUPREEMPT_PROBE(rcupreempt_trace_next_add) ++}; ++ + static void rcupreempt_trace_sum(struct rcupreempt_trace *sp) + { + struct rcupreempt_trace *cp; +@@ -297,9 +350,6 @@ static int rcupreempt_debugfs_init(void) + if (!ctrsdir) + goto free_out; + +- if (!rcu_trace_boost_create(rcudir)) +- goto free_out; +- + return 0; + free_out: + if (ctrsdir) +@@ -316,6 +366,21 @@ out: + static int __init rcupreempt_trace_init(void) + { + int ret; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(rcupreempt_probe_array); i++) { ++ struct rcupreempt_probe_data *p = &rcupreempt_probe_array[i]; ++ ret = marker_probe_register(p->name, p->format, ++ p->probe_func, p); ++ if (ret) ++ printk(KERN_INFO "Unable to register rcupreempt \ ++ probe %s\n", rcupreempt_probe_array[i].name); ++ ret = marker_arm(p->name); ++ if (ret) ++ printk(KERN_INFO "Unable to arm rcupreempt probe %s\n", ++ p->name); ++ } ++ printk(KERN_INFO "RCU Preempt markers registered\n"); + + mutex_init(&rcupreempt_trace_mutex); + rcupreempt_trace_buf = kmalloc(RCUPREEMPT_TRACE_BUF_SIZE, GFP_KERNEL); +@@ -329,7 +394,12 @@ static int __init rcupreempt_trace_init( + + static void __exit rcupreempt_trace_cleanup(void) + { +- rcu_trace_boost_destroy(); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(rcupreempt_probe_array); i++) ++ marker_probe_unregister(rcupreempt_probe_array[i].name); ++ printk(KERN_INFO "RCU Preempt markers unregistered\n"); ++ + debugfs_remove(statdir); + debugfs_remove(gpdir); + debugfs_remove(ctrsdir); +@@ -337,6 +407,7 @@ static void __exit rcupreempt_trace_clea + kfree(rcupreempt_trace_buf); + } + ++MODULE_LICENSE("GPL"); + + module_init(rcupreempt_trace_init); + module_exit(rcupreempt_trace_cleanup); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0353-hack-convert-i_alloc_sem-for-direct_io-craziness.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0353-hack-convert-i_alloc_sem-for-direct_io-craziness.patch @@ -0,0 +1,59 @@ +From rostedt@goodmis.org Wed Sep 26 11:12:03 2007 +Date: Mon, 24 Sep 2007 17:14:26 -0400 (EDT) +From: Steven Rostedt +To: LKML +Cc: linux-rt-users , mingo@goodmis.org, + Thomas Gleixner +Subject: [HACK] convert i_alloc_sem for direct_io.c craziness! + + +Hopefully I will get some attention from those that are responsible for +fs/direct_io.c + +Ingo and Thomas, + +This patch converts the i_alloc_sem into a compat_rw_semaphore for the -rt +patch. Seems that the code in fs/direct_io.c does some nasty logic with +the i_alloc_sem. For DIO_LOCKING, I'm assuming that the i_alloc_sem is +used as a reference counter for pending requests. When the request is +made, the down_read is performed. When the request is handled by the block +softirq, then that softirq does an up on the request. So the owner is not +the same between down and up. When all requests are handled, the semaphore +counter should be zero. This keeps away any write access while requests +are pending. + +Now this may all be well and dandy for vanilla Linux, but it breaks +miserbly when converted to -rt. + +1) In RT rw_semaphores must be up'd by the same thread that down's it. + +2) We can't do PI on the correct processes. + +This patch converts (for now) the i_alloc_sem into a compat_rw_semaphore +to give back the old features to the sem. This fixes deadlocks that we've +been having WRT direct_io. But unfortunately, it now opens up +unbonded priority inversion with this semaphore. But really, those that +can be affected by this, shouldn't be doing disk IO anyway. + +The real fix would be to get rid of the read semaphore trickery in +direct_io.c. + +Signed-off-by: Steve Rostedt + +--- + include/linux/fs.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/include/linux/fs.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/fs.h 2009-02-08 00:03:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/fs.h 2009-02-08 00:03:38.000000000 -0500 +@@ -635,7 +635,7 @@ struct inode { + umode_t i_mode; + spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ + struct mutex i_mutex; +- struct rw_semaphore i_alloc_sem; ++ struct compat_rw_semaphore i_alloc_sem; + const struct inode_operations *i_op; + const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ + struct super_block *i_sb; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0350-powerpc-flush_tlb_pending-is-no-more.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0350-powerpc-flush_tlb_pending-is-no-more.patch @@ -0,0 +1,27 @@ +From tony@bakeyournoodle.com Wed Sep 26 10:31:40 2007 +Date: Tue, 04 Sep 2007 17:09:02 +1000 +From: Tony Breeds +To: linux-rt-users@vger.kernel.org +Subject: [PATCH 5/5] [POWERPC] flush_tlb_pending() is no more, + use __flush_tlb_pending() instead. + +Signed-off-by: Tony Breeds + +--- + + arch/powerpc/mm/tlb_64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/mm/tlb_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/mm/tlb_64.c 2009-02-08 00:02:32.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/mm/tlb_64.c 2009-02-08 00:03:37.000000000 -0500 +@@ -215,7 +215,7 @@ void hpte_need_flush(struct mm_struct *m + * always flush it on RT to reduce scheduling latency. + */ + if (machine_is(celleb)) { +- flush_tlb_pending(); ++ __flush_tlb_pending(batch); + return; + } + #endif /* CONFIG_PREEMPT_RT */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0405-ppc64-non-smp-compile-fix-per-cpu.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0405-ppc64-non-smp-compile-fix-per-cpu.patch @@ -0,0 +1,42 @@ +From estarkov@ru.mvista.com Fri Jan 11 14:54:21 2008 +Date: Thu, 20 Dec 2007 17:15:38 +0300 +From: Egor Starkov +To: mingo@elte.hu +Cc: rostedt@goodmis.org, linux-rt-users@vger.kernel.org, + linux-kernel@vger.kernel.org, linuxppc-dev@ozlabs.org +Subject: PPC64 doesn't compile with CONFIG_SMP=n + +Hello Ingo + +I've found out that real-time tree doesn't compile for PPC64 with +CONFIG_SMP=n. + +Think this is due to patch-2.6.21.4-rt10 patch. It has +definitions of following symbols missing: __get_cpu_lock, +__get_cpu_var_locked. + +I've attached the patch to fix the problem. + +Egor Starkov + + [ Part 2: "Attached Text" ] + +Signed-off-by: Egor Starkov + +--- + include/asm-powerpc/percpu.h | 2 ++ + 1 file changed, 2 insertions(+) + +Index: linux-2.6.24.7-rt27/include/asm-powerpc/percpu.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-powerpc/percpu.h 2009-02-08 00:02:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-powerpc/percpu.h 2009-02-08 00:04:02.000000000 -0500 +@@ -68,6 +68,8 @@ extern void setup_per_cpu_areas(void); + + #define __get_cpu_var(var) per_cpu__##var + #define __raw_get_cpu_var(var) per_cpu__##var ++#define __get_cpu_lock(var, cpu) per_cpu_lock__##var##_locked ++#define __get_cpu_var_locked(var, cpu) per_cpu__##var##_locked + + #endif /* SMP */ + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0098-ioapic-fix-too-fast-clocks.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0098-ioapic-fix-too-fast-clocks.patch @@ -0,0 +1,39 @@ +From: Akira Tsukamoto + +This one line patch adds upper bound testing inside timer_irq_works() +when evaluating whether irq timer works or not on boot up. + +It fix the machines having problem with clock running too fast. + +What this patch do is, +if timer interrupts running too fast through IO-APIC IRQ then false back to +i8259A IRQ. + +I really appreciate for the feedback from ATI Xpress 200 chipset user, +It should eliminate the needs of adding no_timer_check on kernel options. + +I have NEC laptop using ATI Xpress 200 chipset with Pentium M 1.8GHz and +its clock keep going forward when kernel compiled with local APIC support. +Many machines based on RS200 chipset seem to have the same problem, +including Acer Ferrari 400X AMD notebook or Compaq R4000. + +Also I would like to have comments on upper bound limit, 16 ticks, which +I chose in this patch. My laptop always reports around 20, which is double from normal. + + + arch/x86/kernel/io_apic_32.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/io_apic_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/io_apic_32.c 2009-02-08 00:00:21.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/io_apic_32.c 2009-02-08 00:01:28.000000000 -0500 +@@ -1900,7 +1900,7 @@ static int __init timer_irq_works(void) + * might have cached one ExtINT interrupt. Finally, at + * least one tick may be lost due to delays. + */ +- if (jiffies - t1 > 4) ++ if (jiffies - t1 > 4 && jiffies - t1 < 16) + return 1; + + return 0; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0229-preempt-realtime-sh.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0229-preempt-realtime-sh.patch @@ -0,0 +1,1051 @@ +From lethal@linux-sh.org Fri Apr 27 10:21:47 2007 +Date: Fri, 27 Apr 2007 10:21:47 +0900 +From: Paul Mundt +To: Thomas Gleixner , Ingo Molnar +Subject: [PATCH] preempt-rt: Preliminary SH support + +Hi Thomas, Ingo, + +Here's preliminary preempt-rt support for SH. It was written against +2.6.21-rc5, but still applies cleanly. I've kept the clock events stuff +out of this patch, since I'm planning on overhauling the timer stuff on +SH first, but this should trickle in through 2.6.22-rc. + +Feel free to either merge this in to preempt-rt or hold off until the +timer stuff gets done. + +Patch from Matsubara-san. + +Signed-off-by: Katsuya MATSUBARA +Signed-off-by: Paul Mundt + +-- + + arch/sh/kernel/cpu/clock.c | 2 - + arch/sh/kernel/cpu/sh4/sq.c | 2 - + arch/sh/kernel/entry-common.S | 8 ++--- + arch/sh/kernel/irq.c | 2 - + arch/sh/kernel/process.c | 10 +++--- + arch/sh/kernel/semaphore.c | 14 ++++++--- + arch/sh/kernel/sh_ksyms.c | 9 ++--- + arch/sh/kernel/signal.c | 7 ++++ + arch/sh/kernel/time.c | 2 - + arch/sh/kernel/traps.c | 2 - + arch/sh/mm/cache-sh4.c | 12 +++---- + arch/sh/mm/init.c | 2 - + arch/sh/mm/pg-sh4.c | 4 +- + arch/sh/mm/tlb-flush.c | 20 ++++++------ + arch/sh/mm/tlb-sh4.c | 4 +- + include/asm-sh/atomic-irq.h | 24 +++++++-------- + include/asm-sh/atomic.h | 8 ++--- + include/asm-sh/bitops.h | 24 +++++++-------- + include/asm-sh/pgalloc.h | 2 - + include/asm-sh/rwsem.h | 46 ++++++++++++++--------------- + include/asm-sh/semaphore-helper.h | 8 ++--- + include/asm-sh/semaphore.h | 59 +++++++++++++++++++++++--------------- + include/asm-sh/system.h | 12 +++---- + include/asm-sh/thread_info.h | 2 + + 24 files changed, 157 insertions(+), 128 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/sh/kernel/cpu/clock.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/kernel/cpu/clock.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/kernel/cpu/clock.c 2009-02-08 00:02:33.000000000 -0500 +@@ -28,7 +28,7 @@ + #include + + static LIST_HEAD(clock_list); +-static DEFINE_SPINLOCK(clock_lock); ++static DEFINE_RAW_SPINLOCK(clock_lock); + static DEFINE_MUTEX(clock_list_sem); + + /* +Index: linux-2.6.24.7-rt27/arch/sh/kernel/cpu/sh4/sq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/kernel/cpu/sh4/sq.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/kernel/cpu/sh4/sq.c 2009-02-08 00:02:33.000000000 -0500 +@@ -37,7 +37,7 @@ struct sq_mapping { + }; + + static struct sq_mapping *sq_mapping_list; +-static DEFINE_SPINLOCK(sq_mapping_lock); ++static DEFINE_RAW_SPINLOCK(sq_mapping_lock); + static struct kmem_cache *sq_cache; + static unsigned long *sq_bitmap; + +Index: linux-2.6.24.7-rt27/arch/sh/kernel/entry-common.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/kernel/entry-common.S 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/kernel/entry-common.S 2009-02-08 00:02:33.000000000 -0500 +@@ -157,7 +157,7 @@ ENTRY(resume_userspace) + mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags + tst #_TIF_WORK_MASK, r0 + bt/s __restore_all +- tst #_TIF_NEED_RESCHED, r0 ++ tst #_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED, r0 + + .align 2 + work_pending: +@@ -209,10 +209,10 @@ work_resched: + tst #_TIF_WORK_MASK, r0 + bt __restore_all + bra work_pending +- tst #_TIF_NEED_RESCHED, r0 ++ tst #_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_DELAYED, r0 + + .align 2 +-1: .long schedule ++1: .long __schedule + 2: .long do_notify_resume + 3: .long restore_all + #ifdef CONFIG_TRACE_IRQFLAGS +@@ -226,7 +226,7 @@ syscall_exit_work: + ! r8: current_thread_info + tst #_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP, r0 + bt/s work_pending +- tst #_TIF_NEED_RESCHED, r0 ++ tst #_TIF_NEED_RESCHED| _TIF_NEED_RESCHED_DELAYED, r0 + #ifdef CONFIG_TRACE_IRQFLAGS + mov.l 5f, r0 + jsr @r0 +Index: linux-2.6.24.7-rt27/arch/sh/kernel/irq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/kernel/irq.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/kernel/irq.c 2009-02-08 00:02:33.000000000 -0500 +@@ -81,7 +81,7 @@ static union irq_ctx *hardirq_ctx[NR_CPU + static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; + #endif + +-asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs) ++asmlinkage notrace int do_IRQ(unsigned int irq, struct pt_regs *regs) + { + struct pt_regs *old_regs = set_irq_regs(regs); + #ifdef CONFIG_IRQSTACKS +Index: linux-2.6.24.7-rt27/arch/sh/kernel/process.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/kernel/process.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/kernel/process.c 2009-02-08 00:02:33.000000000 -0500 +@@ -65,7 +65,7 @@ void default_idle(void) + clear_thread_flag(TIF_POLLING_NRFLAG); + smp_mb__after_clear_bit(); + set_bl_bit(); +- while (!need_resched()) ++ while (!need_resched() && !need_resched_delayed()) + cpu_sleep(); + clear_bl_bit(); + set_thread_flag(TIF_POLLING_NRFLAG); +@@ -86,13 +86,15 @@ void cpu_idle(void) + idle = default_idle; + + tick_nohz_stop_sched_tick(); +- while (!need_resched()) ++ while (!need_resched() && !need_resched_delayed()) + idle(); + tick_nohz_restart_sched_tick(); + +- preempt_enable_no_resched(); +- schedule(); ++ local_irq_disable(); ++ __preempt_enable_no_resched(); ++ __schedule(); + preempt_disable(); ++ local_irq_enable(); + check_pgt_cache(); + } + } +Index: linux-2.6.24.7-rt27/arch/sh/kernel/semaphore.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/kernel/semaphore.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/kernel/semaphore.c 2009-02-08 00:02:33.000000000 -0500 +@@ -46,7 +46,7 @@ DEFINE_SPINLOCK(semaphore_wake_lock); + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +-void __up(struct semaphore *sem) ++void __attribute_used__ __compat_up(struct compat_semaphore *sem) + { + wake_one_more(sem); + wake_up(&sem->wait); +@@ -104,7 +104,7 @@ void __up(struct semaphore *sem) + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +-void __sched __down(struct semaphore * sem) ++void __attribute_used__ __sched __compat_down(struct compat_semaphore * sem) + { + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) +@@ -114,7 +114,7 @@ void __sched __down(struct semaphore * s + DOWN_TAIL(TASK_UNINTERRUPTIBLE) + } + +-int __sched __down_interruptible(struct semaphore * sem) ++int __attribute_used__ __sched __compat_down_interruptible(struct compat_semaphore * sem) + { + int ret = 0; + DOWN_VAR +@@ -133,7 +133,13 @@ int __sched __down_interruptible(struct + return ret; + } + +-int __down_trylock(struct semaphore * sem) ++int __attribute_used__ __compat_down_trylock(struct compat_semaphore * sem) + { + return waking_non_zero_trylock(sem); + } ++ ++fastcall int __sched compat_sem_is_locked(struct compat_semaphore *sem) ++{ ++ return (int) atomic_read(&sem->count) < 0; ++} ++ +Index: linux-2.6.24.7-rt27/arch/sh/kernel/sh_ksyms.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/kernel/sh_ksyms.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/kernel/sh_ksyms.c 2009-02-08 00:02:33.000000000 -0500 +@@ -26,7 +26,6 @@ EXPORT_SYMBOL(sh_mv); + /* platform dependent support */ + EXPORT_SYMBOL(dump_fpu); + EXPORT_SYMBOL(kernel_thread); +-EXPORT_SYMBOL(irq_desc); + EXPORT_SYMBOL(no_irq_type); + + EXPORT_SYMBOL(strlen); +@@ -49,10 +48,10 @@ EXPORT_SYMBOL(get_vm_area); + #endif + + /* semaphore exports */ +-EXPORT_SYMBOL(__up); +-EXPORT_SYMBOL(__down); +-EXPORT_SYMBOL(__down_interruptible); +-EXPORT_SYMBOL(__down_trylock); ++EXPORT_SYMBOL(__compat_up); ++EXPORT_SYMBOL(__compat_down); ++EXPORT_SYMBOL(__compat_down_interruptible); ++EXPORT_SYMBOL(__compat_down_trylock); + + EXPORT_SYMBOL(__udelay); + EXPORT_SYMBOL(__ndelay); +Index: linux-2.6.24.7-rt27/arch/sh/kernel/signal.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/kernel/signal.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/kernel/signal.c 2009-02-08 00:02:33.000000000 -0500 +@@ -564,6 +564,13 @@ static void do_signal(struct pt_regs *re + struct k_sigaction ka; + sigset_t *oldset; + ++#ifdef CONFIG_PREEMPT_RT ++ /* ++ * Fully-preemptible kernel does not need interrupts disabled: ++ */ ++ raw_local_irq_enable(); ++ preempt_check_resched(); ++#endif + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from +Index: linux-2.6.24.7-rt27/arch/sh/kernel/time.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/kernel/time.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/kernel/time.c 2009-02-08 00:02:33.000000000 -0500 +@@ -24,7 +24,7 @@ + struct sys_timer *sys_timer; + + /* Move this somewhere more sensible.. */ +-DEFINE_SPINLOCK(rtc_lock); ++DEFINE_RAW_SPINLOCK(rtc_lock); + EXPORT_SYMBOL(rtc_lock); + + /* Dummy RTC ops */ +Index: linux-2.6.24.7-rt27/arch/sh/kernel/traps.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/kernel/traps.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/kernel/traps.c 2009-02-08 00:02:33.000000000 -0500 +@@ -77,7 +77,7 @@ static void dump_mem(const char *str, un + } + } + +-static DEFINE_SPINLOCK(die_lock); ++static DEFINE_RAW_SPINLOCK(die_lock); + + void die(const char * str, struct pt_regs * regs, long err) + { +Index: linux-2.6.24.7-rt27/arch/sh/mm/cache-sh4.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/mm/cache-sh4.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/mm/cache-sh4.c 2009-02-08 00:02:33.000000000 -0500 +@@ -204,7 +204,7 @@ void flush_cache_sigtramp(unsigned long + index = CACHE_IC_ADDRESS_ARRAY | + (v & boot_cpu_data.icache.entry_mask); + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + jump_to_P2(); + + for (i = 0; i < boot_cpu_data.icache.ways; +@@ -213,7 +213,7 @@ void flush_cache_sigtramp(unsigned long + + back_to_P1(); + wmb(); +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + + static inline void flush_cache_4096(unsigned long start, +@@ -229,10 +229,10 @@ static inline void flush_cache_4096(unsi + (start < CACHE_OC_ADDRESS_ARRAY)) + exec_offset = 0x20000000; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + __flush_cache_4096(start | SH_CACHE_ASSOC, + P1SEGADDR(phys), exec_offset); +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + + /* +@@ -260,7 +260,7 @@ static inline void flush_icache_all(void + { + unsigned long flags, ccr; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + jump_to_P2(); + + /* Flush I-cache */ +@@ -274,7 +274,7 @@ static inline void flush_icache_all(void + */ + + back_to_P1(); +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + + void flush_dcache_all(void) +Index: linux-2.6.24.7-rt27/arch/sh/mm/init.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/mm/init.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/mm/init.c 2009-02-08 00:02:33.000000000 -0500 +@@ -21,7 +21,7 @@ + #include + #include + +-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); ++DEFINE_PER_CPU_LOCKED(struct mmu_gather, mmu_gathers); + pgd_t swapper_pg_dir[PTRS_PER_PGD]; + + void (*copy_page)(void *from, void *to); +Index: linux-2.6.24.7-rt27/arch/sh/mm/pg-sh4.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/mm/pg-sh4.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/mm/pg-sh4.c 2009-02-08 00:02:33.000000000 -0500 +@@ -28,9 +28,9 @@ static inline void *kmap_coherent(struct + vaddr = __fix_to_virt(FIX_CMAP_END - idx); + pte = mk_pte(page, PAGE_KERNEL); + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + flush_tlb_one(get_asid(), vaddr); +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + + update_mmu_cache(NULL, vaddr, pte); + +Index: linux-2.6.24.7-rt27/arch/sh/mm/tlb-flush.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/mm/tlb-flush.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/mm/tlb-flush.c 2009-02-08 00:02:33.000000000 -0500 +@@ -24,7 +24,7 @@ void local_flush_tlb_page(struct vm_area + asid = cpu_asid(cpu, vma->vm_mm); + page &= PAGE_MASK; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + if (vma->vm_mm != current->mm) { + saved_asid = get_asid(); + set_asid(asid); +@@ -32,7 +32,7 @@ void local_flush_tlb_page(struct vm_area + local_flush_tlb_one(asid, page); + if (saved_asid != MMU_NO_ASID) + set_asid(saved_asid); +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + } + +@@ -46,7 +46,7 @@ void local_flush_tlb_range(struct vm_are + unsigned long flags; + int size; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */ + cpu_context(cpu, mm) = NO_CONTEXT; +@@ -71,7 +71,7 @@ void local_flush_tlb_range(struct vm_are + if (saved_asid != MMU_NO_ASID) + set_asid(saved_asid); + } +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + } + +@@ -81,7 +81,7 @@ void local_flush_tlb_kernel_range(unsign + unsigned long flags; + int size; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */ + local_flush_tlb_all(); +@@ -100,7 +100,7 @@ void local_flush_tlb_kernel_range(unsign + } + set_asid(saved_asid); + } +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + + void local_flush_tlb_mm(struct mm_struct *mm) +@@ -112,11 +112,11 @@ void local_flush_tlb_mm(struct mm_struct + if (cpu_context(cpu, mm) != NO_CONTEXT) { + unsigned long flags; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + cpu_context(cpu, mm) = NO_CONTEXT; + if (mm == current->mm) + activate_context(mm, cpu); +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + } + +@@ -131,10 +131,10 @@ void local_flush_tlb_all(void) + * TF-bit for SH-3, TI-bit for SH-4. + * It's same position, bit #2. + */ +- local_irq_save(flags); ++ raw_local_irq_save(flags); + status = ctrl_inl(MMUCR); + status |= 0x04; + ctrl_outl(status, MMUCR); + ctrl_barrier(); +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } +Index: linux-2.6.24.7-rt27/arch/sh/mm/tlb-sh4.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/sh/mm/tlb-sh4.c 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/sh/mm/tlb-sh4.c 2009-02-08 00:02:33.000000000 -0500 +@@ -43,7 +43,7 @@ void update_mmu_cache(struct vm_area_str + } + #endif + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + + /* Set PTEH register */ + vpn = (address & MMU_VPN_MASK) | get_asid(); +@@ -76,7 +76,7 @@ void update_mmu_cache(struct vm_area_str + + /* Load the TLB */ + asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + + void local_flush_tlb_one(unsigned long asid, unsigned long page) +Index: linux-2.6.24.7-rt27/include/asm-sh/atomic-irq.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-sh/atomic-irq.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-sh/atomic-irq.h 2009-02-08 00:02:33.000000000 -0500 +@@ -10,29 +10,29 @@ static inline void atomic_add(int i, ato + { + unsigned long flags; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + *(long *)v += i; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + + static inline void atomic_sub(int i, atomic_t *v) + { + unsigned long flags; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + *(long *)v -= i; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + + static inline int atomic_add_return(int i, atomic_t *v) + { + unsigned long temp, flags; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + temp = *(long *)v; + temp += i; + *(long *)v = temp; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + + return temp; + } +@@ -41,11 +41,11 @@ static inline int atomic_sub_return(int + { + unsigned long temp, flags; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + temp = *(long *)v; + temp -= i; + *(long *)v = temp; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + + return temp; + } +@@ -54,18 +54,18 @@ static inline void atomic_clear_mask(uns + { + unsigned long flags; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + *(long *)v &= ~mask; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + + static inline void atomic_set_mask(unsigned int mask, atomic_t *v) + { + unsigned long flags; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + *(long *)v |= mask; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + + #endif /* __ASM_SH_ATOMIC_IRQ_H */ +Index: linux-2.6.24.7-rt27/include/asm-sh/atomic.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-sh/atomic.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-sh/atomic.h 2009-02-08 00:02:33.000000000 -0500 +@@ -49,11 +49,11 @@ static inline int atomic_cmpxchg(atomic_ + int ret; + unsigned long flags; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + ret = v->counter; + if (likely(ret == old)) + v->counter = new; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + + return ret; + } +@@ -65,11 +65,11 @@ static inline int atomic_add_unless(atom + int ret; + unsigned long flags; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + ret = v->counter; + if (ret != u) + v->counter += a; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + + return ret != u; + } +Index: linux-2.6.24.7-rt27/include/asm-sh/bitops.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-sh/bitops.h 2009-02-07 23:59:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-sh/bitops.h 2009-02-08 00:02:33.000000000 -0500 +@@ -19,9 +19,9 @@ static inline void set_bit(int nr, volat + + a += nr >> 5; + mask = 1 << (nr & 0x1f); +- local_irq_save(flags); ++ raw_local_irq_save(flags); + *a |= mask; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + + /* +@@ -37,9 +37,9 @@ static inline void clear_bit(int nr, vol + + a += nr >> 5; + mask = 1 << (nr & 0x1f); +- local_irq_save(flags); ++ raw_local_irq_save(flags); + *a &= ~mask; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + + static inline void change_bit(int nr, volatile void * addr) +@@ -50,9 +50,9 @@ static inline void change_bit(int nr, vo + + a += nr >> 5; + mask = 1 << (nr & 0x1f); +- local_irq_save(flags); ++ raw_local_irq_save(flags); + *a ^= mask; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + } + + static inline int test_and_set_bit(int nr, volatile void * addr) +@@ -63,10 +63,10 @@ static inline int test_and_set_bit(int n + + a += nr >> 5; + mask = 1 << (nr & 0x1f); +- local_irq_save(flags); ++ raw_local_irq_save(flags); + retval = (mask & *a) != 0; + *a |= mask; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + + return retval; + } +@@ -79,10 +79,10 @@ static inline int test_and_clear_bit(int + + a += nr >> 5; + mask = 1 << (nr & 0x1f); +- local_irq_save(flags); ++ raw_local_irq_save(flags); + retval = (mask & *a) != 0; + *a &= ~mask; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + + return retval; + } +@@ -95,10 +95,10 @@ static inline int test_and_change_bit(in + + a += nr >> 5; + mask = 1 << (nr & 0x1f); +- local_irq_save(flags); ++ raw_local_irq_save(flags); + retval = (mask & *a) != 0; + *a ^= mask; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + + return retval; + } +Index: linux-2.6.24.7-rt27/include/asm-sh/pgalloc.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-sh/pgalloc.h 2009-02-08 00:00:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-sh/pgalloc.h 2009-02-08 00:02:33.000000000 -0500 +@@ -13,7 +13,7 @@ static inline void pmd_populate_kernel(s + set_pmd(pmd, __pmd((unsigned long)pte)); + } + +-static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, ++static inline void notrace pmd_populate(struct mm_struct *mm, pmd_t *pmd, + struct page *pte) + { + set_pmd(pmd, __pmd((unsigned long)page_address(pte))); +Index: linux-2.6.24.7-rt27/include/asm-sh/rwsem.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-sh/rwsem.h 2009-02-08 00:00:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-sh/rwsem.h 2009-02-08 00:02:33.000000000 -0500 +@@ -19,7 +19,7 @@ + /* + * the semaphore definition + */ +-struct rw_semaphore { ++struct compat_rw_semaphore { + long count; + #define RWSEM_UNLOCKED_VALUE 0x00000000 + #define RWSEM_ACTIVE_BIAS 0x00000001 +@@ -27,7 +27,7 @@ struct rw_semaphore { + #define RWSEM_WAITING_BIAS (-0x00010000) + #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS + #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) +- spinlock_t wait_lock; ++ raw_spinlock_t wait_lock; + struct list_head wait_list; + #ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +@@ -45,25 +45,25 @@ struct rw_semaphore { + LIST_HEAD_INIT((name).wait_list) \ + __RWSEM_DEP_MAP_INIT(name) } + +-#define DECLARE_RWSEM(name) \ +- struct rw_semaphore name = __RWSEM_INITIALIZER(name) ++#define COMPAT_DECLARE_RWSEM(name) \ ++ struct compat_rw_semaphore name = __RWSEM_INITIALIZER(name) + +-extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem); +-extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem); +-extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem); +-extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); ++extern struct compat_rw_semaphore *rwsem_down_read_failed(struct compat_rw_semaphore *sem); ++extern struct compat_rw_semaphore *rwsem_down_write_failed(struct compat_rw_semaphore *sem); ++extern struct compat_rw_semaphore *rwsem_wake(struct compat_rw_semaphore *sem); ++extern struct compat_rw_semaphore *rwsem_downgrade_wake(struct compat_rw_semaphore *sem); + +-extern void __init_rwsem(struct rw_semaphore *sem, const char *name, ++extern void __compat_init_rwsem(struct rw_semaphore *sem, const char *name, + struct lock_class_key *key); + +-#define init_rwsem(sem) \ ++#define compat_init_rwsem(sem) \ + do { \ + static struct lock_class_key __key; \ + \ +- __init_rwsem((sem), #sem, &__key); \ ++ __compat_init_rwsem((sem), #sem, &__key); \ + } while (0) + +-static inline void init_rwsem(struct rw_semaphore *sem) ++static inline void compat_init_rwsem(struct rw_semaphore *sem) + { + sem->count = RWSEM_UNLOCKED_VALUE; + spin_lock_init(&sem->wait_lock); +@@ -73,7 +73,7 @@ static inline void init_rwsem(struct rw_ + /* + * lock for reading + */ +-static inline void __down_read(struct rw_semaphore *sem) ++static inline void __down_read(struct compat_rw_semaphore *sem) + { + if (atomic_inc_return((atomic_t *)(&sem->count)) > 0) + smp_wmb(); +@@ -81,7 +81,7 @@ static inline void __down_read(struct rw + rwsem_down_read_failed(sem); + } + +-static inline int __down_read_trylock(struct rw_semaphore *sem) ++static inline int __down_read_trylock(struct compat_rw_semaphore *sem) + { + int tmp; + +@@ -98,7 +98,7 @@ static inline int __down_read_trylock(st + /* + * lock for writing + */ +-static inline void __down_write(struct rw_semaphore *sem) ++static inline void __down_write(struct compat_rw_semaphore *sem) + { + int tmp; + +@@ -110,7 +110,7 @@ static inline void __down_write(struct r + rwsem_down_write_failed(sem); + } + +-static inline int __down_write_trylock(struct rw_semaphore *sem) ++static inline int __down_write_trylock(struct compat_rw_semaphore *sem) + { + int tmp; + +@@ -123,7 +123,7 @@ static inline int __down_write_trylock(s + /* + * unlock after reading + */ +-static inline void __up_read(struct rw_semaphore *sem) ++static inline void __up_read(struct compat_rw_semaphore *sem) + { + int tmp; + +@@ -136,7 +136,7 @@ static inline void __up_read(struct rw_s + /* + * unlock after writing + */ +-static inline void __up_write(struct rw_semaphore *sem) ++static inline void __up_write(struct compat_rw_semaphore *sem) + { + smp_wmb(); + if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS, +@@ -147,7 +147,7 @@ static inline void __up_write(struct rw_ + /* + * implement atomic add functionality + */ +-static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) ++static inline void rwsem_atomic_add(int delta, struct compat_rw_semaphore *sem) + { + atomic_add(delta, (atomic_t *)(&sem->count)); + } +@@ -155,7 +155,7 @@ static inline void rwsem_atomic_add(int + /* + * downgrade write lock to read lock + */ +-static inline void __downgrade_write(struct rw_semaphore *sem) ++static inline void __downgrade_write(struct compat_rw_semaphore *sem) + { + int tmp; + +@@ -165,7 +165,7 @@ static inline void __downgrade_write(str + rwsem_downgrade_wake(sem); + } + +-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) ++static inline void __down_write_nested(struct compat_rw_semaphore *sem, int subclass) + { + __down_write(sem); + } +@@ -173,13 +173,13 @@ static inline void __down_write_nested(s + /* + * implement exchange and add functionality + */ +-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) ++static inline int rwsem_atomic_update(int delta, struct compat_rw_semaphore *sem) + { + smp_mb(); + return atomic_add_return(delta, (atomic_t *)(&sem->count)); + } + +-static inline int rwsem_is_locked(struct rw_semaphore *sem) ++static inline int rwsem_is_locked(struct compat_rw_semaphore *sem) + { + return (sem->count != 0); + } +Index: linux-2.6.24.7-rt27/include/asm-sh/semaphore-helper.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-sh/semaphore-helper.h 2009-02-08 00:00:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-sh/semaphore-helper.h 2009-02-08 00:02:33.000000000 -0500 +@@ -14,12 +14,12 @@ + * This is trivially done with load_locked/store_cond, + * which we have. Let the rest of the losers suck eggs. + */ +-static __inline__ void wake_one_more(struct semaphore * sem) ++static __inline__ void wake_one_more(struct compat_semaphore * sem) + { + atomic_inc((atomic_t *)&sem->sleepers); + } + +-static __inline__ int waking_non_zero(struct semaphore *sem) ++static __inline__ int waking_non_zero(struct compat_semaphore *sem) + { + unsigned long flags; + int ret = 0; +@@ -43,7 +43,7 @@ static __inline__ int waking_non_zero(st + * protected by the spinlock in order to make atomic this atomic_inc() with the + * atomic_read() in wake_one_more(), otherwise we can race. -arca + */ +-static __inline__ int waking_non_zero_interruptible(struct semaphore *sem, ++static __inline__ int waking_non_zero_interruptible(struct compat_semaphore *sem, + struct task_struct *tsk) + { + unsigned long flags; +@@ -70,7 +70,7 @@ static __inline__ int waking_non_zero_in + * protected by the spinlock in order to make atomic this atomic_inc() with the + * atomic_read() in wake_one_more(), otherwise we can race. -arca + */ +-static __inline__ int waking_non_zero_trylock(struct semaphore *sem) ++static __inline__ int waking_non_zero_trylock(struct compat_semaphore *sem) + { + unsigned long flags; + int ret = 1; +Index: linux-2.6.24.7-rt27/include/asm-sh/semaphore.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-sh/semaphore.h 2009-02-08 00:00:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-sh/semaphore.h 2009-02-08 00:02:33.000000000 -0500 +@@ -20,28 +20,35 @@ + #include + #include + +-struct semaphore { ++/* ++ * On !PREEMPT_RT all semaphores are compat: ++ */ ++#ifndef CONFIG_PREEMPT_RT ++# define compat_semaphore semaphore ++#endif ++ ++struct compat_semaphore { + atomic_t count; + int sleepers; + wait_queue_head_t wait; + }; + +-#define __SEMAPHORE_INITIALIZER(name, n) \ ++#define __COMPAT_SEMAPHORE_INITIALIZER(name, n) \ + { \ + .count = ATOMIC_INIT(n), \ + .sleepers = 0, \ + .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + } + +-#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ +- struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) ++#define __COMPAT_DECLARE_SEMAPHORE_GENERIC(name,count) \ ++ struct compat_semaphore name = __COMPAT_SEMAPHORE_INITIALIZER(name,count) + +-#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) ++#define COMPAT_DECLARE_MUTEX(name) __COMPAT_DECLARE_SEMAPHORE_GENERIC(name,1) + +-static inline void sema_init (struct semaphore *sem, int val) ++static inline void compat_sema_init (struct compat_semaphore *sem, int val) + { + /* +- * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); ++ * *sem = (struct compat_semaphore)__SEMAPHORE_INITIALIZER((*sem),val); + * + * i'd rather use the more flexible initialization above, but sadly + * GCC 2.7.2.3 emits a bogus warning. EGCS doesn't. Oh well. +@@ -51,14 +58,14 @@ static inline void sema_init (struct sem + init_waitqueue_head(&sem->wait); + } + +-static inline void init_MUTEX (struct semaphore *sem) ++static inline void compat_init_MUTEX (struct compat_semaphore *sem) + { +- sema_init(sem, 1); ++ compat_sema_init(sem, 1); + } + +-static inline void init_MUTEX_LOCKED (struct semaphore *sem) ++static inline void compat_init_MUTEX_LOCKED (struct compat_semaphore *sem) + { +- sema_init(sem, 0); ++ compat_sema_init(sem, 0); + } + + #if 0 +@@ -68,36 +75,36 @@ asmlinkage int __down_failed_trylock(vo + asmlinkage void __up_wakeup(void /* special register calling convention */); + #endif + +-asmlinkage void __down(struct semaphore * sem); +-asmlinkage int __down_interruptible(struct semaphore * sem); +-asmlinkage int __down_trylock(struct semaphore * sem); +-asmlinkage void __up(struct semaphore * sem); ++asmlinkage void __compat_down(struct compat_semaphore * sem); ++asmlinkage int __compat_down_interruptible(struct compat_semaphore * sem); ++asmlinkage int __compat_down_trylock(struct compat_semaphore * sem); ++asmlinkage void __compat_up(struct compat_semaphore * sem); + + extern spinlock_t semaphore_wake_lock; + +-static inline void down(struct semaphore * sem) ++static inline void compat_down(struct compat_semaphore * sem) + { + might_sleep(); + if (atomic_dec_return(&sem->count) < 0) +- __down(sem); ++ __compat_down(sem); + } + +-static inline int down_interruptible(struct semaphore * sem) ++static inline int compat_down_interruptible(struct compat_semaphore * sem) + { + int ret = 0; + + might_sleep(); + if (atomic_dec_return(&sem->count) < 0) +- ret = __down_interruptible(sem); ++ ret = __compat_down_interruptible(sem); + return ret; + } + +-static inline int down_trylock(struct semaphore * sem) ++static inline int compat_down_trylock(struct compat_semaphore * sem) + { + int ret = 0; + + if (atomic_dec_return(&sem->count) < 0) +- ret = __down_trylock(sem); ++ ret = __compat_down_trylock(sem); + return ret; + } + +@@ -105,11 +112,17 @@ static inline int down_trylock(struct se + * Note! This is subtle. We jump to wake people up only if + * the semaphore was negative (== somebody was waiting on it). + */ +-static inline void up(struct semaphore * sem) ++static inline void compat_up(struct compat_semaphore * sem) + { + if (atomic_inc_return(&sem->count) <= 0) +- __up(sem); ++ __compat_up(sem); + } + ++extern int compat_sem_is_locked(struct compat_semaphore *sem); ++ ++#define compat_sema_count(sem) atomic_read(&(sem)->count) ++ ++#include ++ + #endif + #endif /* __ASM_SH_SEMAPHORE_H */ +Index: linux-2.6.24.7-rt27/include/asm-sh/system.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-sh/system.h 2009-02-08 00:00:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-sh/system.h 2009-02-08 00:02:33.000000000 -0500 +@@ -159,10 +159,10 @@ static inline unsigned long xchg_u32(vol + { + unsigned long flags, retval; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + retval = *m; + *m = val; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + return retval; + } + +@@ -170,10 +170,10 @@ static inline unsigned long xchg_u8(vola + { + unsigned long flags, retval; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + retval = *m; + *m = val & 0xff; +- local_irq_restore(flags); ++ raw_local_irq_restore(flags); + return retval; + } + +@@ -208,11 +208,11 @@ static inline unsigned long __cmpxchg_u3 + __u32 retval; + unsigned long flags; + +- local_irq_save(flags); ++ raw_local_irq_save(flags); + retval = *m; + if (retval == old) + *m = new; +- local_irq_restore(flags); /* implies memory barrier */ ++ raw_local_irq_restore(flags); /* implies memory barrier */ + return retval; + } + +Index: linux-2.6.24.7-rt27/include/asm-sh/thread_info.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-sh/thread_info.h 2009-02-08 00:00:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-sh/thread_info.h 2009-02-08 00:02:33.000000000 -0500 +@@ -111,6 +111,7 @@ static inline struct thread_info *curren + #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ + #define TIF_RESTORE_SIGMASK 3 /* restore signal mask in do_signal() */ + #define TIF_SINGLESTEP 4 /* singlestepping active */ ++#define TIF_NEED_RESCHED_DELAYED 6 /* reschedule on return to userspace */ + #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ + #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ + #define TIF_MEMDIE 18 +@@ -121,6 +122,7 @@ static inline struct thread_info *curren + #define _TIF_NEED_RESCHED (1< +Date: Tue, 11 Dec 2007 10:02:43 +0100 +Subject: [PATCH] sched: update root-domain spans upon departure + +We shouldnt leave cpus enabled in the spans if that RQ has left the domain. + +Signed-off-by: Gregory Haskins +Signed-off-by: Ingo Molnar + +--- + kernel/sched.c | 3 +++ + 1 file changed, 3 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:01:03.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:01:03.000000000 -0500 +@@ -5837,6 +5837,9 @@ static void rq_attach_root(struct rq *rq + if (class->leave_domain) + class->leave_domain(rq); + ++ cpu_clear(rq->cpu, old_rd->span); ++ cpu_clear(rq->cpu, old_rd->online); ++ + if (atomic_dec_and_test(&old_rd->refcount)) + kfree(old_rd); + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0235-preempt-realtime-sched.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0235-preempt-realtime-sched.patch @@ -0,0 +1,1008 @@ +--- + include/linux/sched.h | 47 ++++++ + kernel/sched.c | 375 +++++++++++++++++++++++++++++++++++++++++++------- + kernel/sched_rt.c | 60 +++++++- + 3 files changed, 431 insertions(+), 51 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:02:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:02:37.000000000 -0500 +@@ -91,6 +91,16 @@ struct sched_param { + + #include + ++#ifdef CONFIG_PREEMPT ++extern int kernel_preemption; ++#else ++# define kernel_preemption 0 ++#endif ++#ifdef CONFIG_PREEMPT_VOLUNTARY ++extern int voluntary_preemption; ++#else ++# define voluntary_preemption 0 ++#endif + #ifdef CONFIG_PREEMPT_SOFTIRQS + extern int softirq_preemption; + #else +@@ -200,6 +210,28 @@ extern struct semaphore kernel_sem; + #define set_task_state(tsk, state_value) \ + set_mb((tsk)->state, (state_value)) + ++// #define PREEMPT_DIRECT ++ ++#ifdef CONFIG_X86_LOCAL_APIC ++extern void nmi_show_all_regs(void); ++#else ++# define nmi_show_all_regs() do { } while (0) ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct exec_domain; ++ + /* + * set_current_state() includes a barrier so that the write of current->state + * is correctly serialised wrt the caller's subsequent test of whether to +@@ -319,6 +351,11 @@ extern signed long FASTCALL(schedule_tim + extern signed long schedule_timeout_interruptible(signed long timeout); + extern signed long schedule_timeout_uninterruptible(signed long timeout); + asmlinkage void schedule(void); ++/* ++ * This one can be called with interrupts disabled, only ++ * to be used by lowlevel arch code! ++ */ ++asmlinkage void __sched __schedule(void); + + struct nsproxy; + struct user_namespace; +@@ -1419,6 +1456,15 @@ extern struct pid *cad_pid; + extern void free_task(struct task_struct *tsk); + #define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0) + ++#ifdef CONFIG_PREEMPT_RT ++extern void __put_task_struct_cb(struct rcu_head *rhp); ++ ++static inline void put_task_struct(struct task_struct *t) ++{ ++ if (atomic_dec_and_test(&t->usage)) ++ call_rcu(&t->rcu, __put_task_struct_cb); ++} ++#else + extern void __put_task_struct(struct task_struct *t); + + static inline void put_task_struct(struct task_struct *t) +@@ -1426,6 +1472,7 @@ static inline void put_task_struct(struc + if (atomic_dec_and_test(&t->usage)) + __put_task_struct(t); + } ++#endif + + /* + * Per process flags +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:02:15.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:02:37.000000000 -0500 +@@ -4,6 +4,7 @@ + * Kernel scheduler and related syscalls + * + * Copyright (C) 1991-2002 Linus Torvalds ++ * Copyright (C) 2004 Red Hat, Inc., Ingo Molnar + * + * 1996-12-23 Modified by Dave Grothe to fix bugs in semaphores and + * make semaphores SMP safe +@@ -16,6 +17,7 @@ + * by Davide Libenzi, preemptible kernel bits by Robert Love. + * 2003-09-03 Interactivity tuning by Con Kolivas. + * 2004-04-02 Scheduler domains code by Nick Piggin ++ * 2004-10-13 Real-Time Preemption support by Ingo Molnar + * 2007-04-15 Work begun on replacing all interactivity tuning with a + * fair scheduling design by Con Kolivas. + * 2007-05-05 Load balancing (smp-nice) and other improvements +@@ -59,6 +61,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -114,6 +117,20 @@ unsigned long long __attribute__((weak)) + #define NICE_0_LOAD SCHED_LOAD_SCALE + #define NICE_0_SHIFT SCHED_LOAD_SHIFT + ++#if (BITS_PER_LONG < 64) ++#define JIFFIES_TO_NS64(TIME) \ ++ ((unsigned long long)(TIME) * ((unsigned long) (1000000000 / HZ))) ++ ++#define NS64_TO_JIFFIES(TIME) \ ++ ((((unsigned long long)((TIME)) >> BITS_PER_LONG) * \ ++ (1 + NS_TO_JIFFIES(~0UL))) + NS_TO_JIFFIES((unsigned long)(TIME))) ++#else /* BITS_PER_LONG < 64 */ ++ ++#define NS64_TO_JIFFIES(TIME) NS_TO_JIFFIES(TIME) ++#define JIFFIES_TO_NS64(TIME) JIFFIES_TO_NS(TIME) ++ ++#endif /* BITS_PER_LONG < 64 */ ++ + /* + * These are the 'tuning knobs' of the scheduler: + * +@@ -143,6 +160,32 @@ static inline void sg_inc_cpu_power(stru + } + #endif + ++#define TASK_PREEMPTS_CURR(p, rq) \ ++ ((p)->prio < (rq)->curr->prio) ++ ++/* ++ * Tweaks for current ++ */ ++ ++#ifdef CURRENT_PTR ++struct task_struct * const ___current = &init_task; ++struct task_struct ** const current_ptr = (struct task_struct ** const)&___current; ++struct thread_info * const current_ti = &init_thread_union.thread_info; ++struct thread_info ** const current_ti_ptr = (struct thread_info ** const)¤t_ti; ++ ++EXPORT_SYMBOL(___current); ++EXPORT_SYMBOL(current_ti); ++ ++/* ++ * The scheduler itself doesnt want 'current' to be cached ++ * during context-switches: ++ */ ++# undef current ++# define current __current() ++# undef current_thread_info ++# define current_thread_info() __current_thread_info() ++#endif ++ + static inline int rt_policy(int policy) + { + if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR)) +@@ -278,6 +321,7 @@ struct rt_rq { + struct list_head *rt_load_balance_head, *rt_load_balance_curr; + unsigned long rt_nr_running; + unsigned long rt_nr_migratory; ++ unsigned long rt_nr_uninterruptible; + /* highest queued rt task prio */ + int highest_prio; + int overloaded; +@@ -324,7 +368,7 @@ static struct root_domain def_root_domai + */ + struct rq { + /* runqueue lock: */ +- spinlock_t lock; ++ raw_spinlock_t lock; + + /* + * nr_running and cpu_load should be in the same cacheline because +@@ -357,6 +401,8 @@ struct rq { + */ + unsigned long nr_uninterruptible; + ++ unsigned long switch_timestamp; ++ unsigned long slice_avg; + struct task_struct *curr, *idle; + unsigned long next_balance; + struct mm_struct *prev_mm; +@@ -406,6 +452,13 @@ struct rq { + + /* BKL stats */ + unsigned int bkl_count; ++ ++ /* RT-overload stats: */ ++ unsigned long rto_schedule; ++ unsigned long rto_schedule_tail; ++ unsigned long rto_wakeup; ++ unsigned long rto_pulled; ++ unsigned long rto_pushed; + #endif + struct lock_class_key rq_lock_key; + }; +@@ -569,11 +622,23 @@ unsigned long long notrace cpu_clock(int + } + EXPORT_SYMBOL_GPL(cpu_clock); + ++/* ++ * We really dont want to do anything complex within switch_to() ++ * on PREEMPT_RT - this check enforces this. ++ */ ++#ifdef prepare_arch_switch ++# ifdef CONFIG_PREEMPT_RT ++# error FIXME ++# else ++# define _finish_arch_switch finish_arch_switch ++# endif ++#endif ++ + #ifndef prepare_arch_switch + # define prepare_arch_switch(next) do { } while (0) + #endif + #ifndef finish_arch_switch +-# define finish_arch_switch(prev) do { } while (0) ++# define _finish_arch_switch(prev) do { } while (0) + #endif + + static inline int task_current(struct rq *rq, struct task_struct *p) +@@ -604,7 +669,7 @@ static inline void finish_lock_switch(st + */ + spin_acquire(&rq->lock.dep_map, 0, 0, _THIS_IP_); + +- spin_unlock_irq(&rq->lock); ++ spin_unlock(&rq->lock); + } + + #else /* __ARCH_WANT_UNLOCKED_CTXSW */ +@@ -645,8 +710,8 @@ static inline void finish_lock_switch(st + smp_wmb(); + prev->oncpu = 0; + #endif +-#ifndef __ARCH_WANT_INTERRUPTS_ON_CTXSW +- local_irq_enable(); ++#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW ++ local_irq_disable(); + #endif + } + #endif /* __ARCH_WANT_UNLOCKED_CTXSW */ +@@ -1093,6 +1158,8 @@ static inline int normal_prio(struct tas + prio = MAX_RT_PRIO-1 - p->rt_priority; + else + prio = __normal_prio(p); ++ ++// trace_special_pid(p->pid, PRIO(p), __PRIO(prio)); + return prio; + } + +@@ -1593,6 +1660,13 @@ try_to_wake_up(struct task_struct *p, un + long old_state; + struct rq *rq; + ++#ifdef CONFIG_PREEMPT_RT ++ /* ++ * sync wakeups can increase wakeup latencies: ++ */ ++ if (rt_task(p)) ++ sync = 0; ++#endif + rq = task_rq_lock(p, &flags); + old_state = p->state; + if (!(old_state & state)) +@@ -1658,7 +1732,10 @@ out_activate: + + out_running: + trace_kernel_sched_wakeup(rq, p); +- p->state = TASK_RUNNING; ++ if (mutex) ++ p->state = TASK_RUNNING_MUTEX; ++ else ++ p->state = TASK_RUNNING; + #ifdef CONFIG_SMP + if (p->sched_class->task_wake_up) + p->sched_class->task_wake_up(rq, p); +@@ -1962,7 +2039,7 @@ static void finish_task_switch(struct rq + * Manfred Spraul + */ + prev_state = prev->state; +- finish_arch_switch(prev); ++ _finish_arch_switch(prev); + finish_lock_switch(rq, prev); + #ifdef CONFIG_SMP + if (current->sched_class->post_schedule) +@@ -1989,12 +2066,15 @@ static void finish_task_switch(struct rq + asmlinkage void schedule_tail(struct task_struct *prev) + __releases(rq->lock) + { +- struct rq *rq = this_rq(); +- +- finish_task_switch(rq, prev); ++ preempt_disable(); // TODO: move this to fork setup ++ finish_task_switch(this_rq(), prev); ++ __preempt_enable_no_resched(); ++ local_irq_enable(); + #ifdef __ARCH_WANT_UNLOCKED_CTXSW + /* In this case, finish_task_switch does not reenable preemption */ + preempt_enable(); ++#else ++ preempt_check_resched(); + #endif + if (current->set_child_tid) + put_user(task_pid_vnr(current), current->set_child_tid); +@@ -2043,6 +2123,11 @@ context_switch(struct rq *rq, struct tas + spin_release(&rq->lock.dep_map, 1, _THIS_IP_); + #endif + ++#ifdef CURRENT_PTR ++ barrier(); ++ *current_ptr = next; ++ *current_ti_ptr = next->thread_info; ++#endif + /* Here we just switch the register state and the stack. */ + switch_to(prev, next, prev); + +@@ -2089,6 +2174,11 @@ unsigned long nr_uninterruptible(void) + return sum; + } + ++unsigned long nr_uninterruptible_cpu(int cpu) ++{ ++ return cpu_rq(cpu)->nr_uninterruptible; ++} ++ + unsigned long long nr_context_switches(void) + { + int i; +@@ -3569,6 +3659,8 @@ void scheduler_tick(void) + struct task_struct *curr = rq->curr; + u64 next_tick = rq->tick_timestamp + TICK_NSEC; + ++ BUG_ON(!irqs_disabled()); ++ + spin_lock(&rq->lock); + __update_rq_clock(rq); + /* +@@ -3666,8 +3758,8 @@ static noinline void __schedule_bug(stru + { + struct pt_regs *regs = get_irq_regs(); + +- printk(KERN_ERR "BUG: scheduling while atomic: %s/%d/0x%08x\n", +- prev->comm, prev->pid, preempt_count()); ++ printk(KERN_ERR "BUG: scheduling while atomic: %s/0x%08x/%d, CPU#%d\n", ++ prev->comm, preempt_count(), prev->pid, smp_processor_id()); + + debug_show_held_locks(prev); + if (irqs_disabled()) +@@ -3684,6 +3776,8 @@ static noinline void __schedule_bug(stru + */ + static inline void schedule_debug(struct task_struct *prev) + { ++ WARN_ON(system_state == SYSTEM_BOOTING); ++ + /* + * Test if we are atomic. Since do_exit() needs to call into + * schedule() atomically, we ignore that path for now. +@@ -3738,14 +3832,13 @@ pick_next_task(struct rq *rq, struct tas + /* + * schedule() is the main scheduler function. + */ +-asmlinkage void __sched schedule(void) ++asmlinkage void __sched __schedule(void) + { + struct task_struct *prev, *next; + long *switch_count; + struct rq *rq; + int cpu; + +-need_resched: + preempt_disable(); + cpu = smp_processor_id(); + rq = cpu_rq(cpu); +@@ -3754,7 +3847,6 @@ need_resched: + switch_count = &prev->nivcsw; + + release_kernel_lock(prev); +-need_resched_nonpreemptible: + + schedule_debug(prev); + +@@ -3764,19 +3856,25 @@ need_resched_nonpreemptible: + local_irq_disable(); + __update_rq_clock(rq); + spin_lock(&rq->lock); ++ cpu = smp_processor_id(); + clear_tsk_need_resched(prev); + clear_tsk_need_resched_delayed(prev); + +- if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { ++ if ((prev->state & ~TASK_RUNNING_MUTEX) && ++ !(preempt_count() & PREEMPT_ACTIVE)) { + if (unlikely((prev->state & TASK_INTERRUPTIBLE) && + unlikely(signal_pending(prev)))) { + prev->state = TASK_RUNNING; + } else { ++ touch_softlockup_watchdog(); + deactivate_task(rq, prev, 1); + } + switch_count = &prev->nvcsw; + } + ++ if (preempt_count() & PREEMPT_ACTIVE) ++ sub_preempt_count(PREEMPT_ACTIVE); ++ + #ifdef CONFIG_SMP + if (prev->sched_class->pre_schedule) + prev->sched_class->pre_schedule(rq, prev); +@@ -3796,22 +3894,90 @@ need_resched_nonpreemptible: + ++*switch_count; + + context_switch(rq, prev, next); /* unlocks the rq */ +- } else +- spin_unlock_irq(&rq->lock); ++ __preempt_enable_no_resched(); ++ } else { ++ __preempt_enable_no_resched(); ++ spin_unlock(&rq->lock); ++ } + +- if (unlikely(reacquire_kernel_lock(current) < 0)) { +- cpu = smp_processor_id(); +- rq = cpu_rq(cpu); +- goto need_resched_nonpreemptible; ++ reacquire_kernel_lock(current); ++ if (!irqs_disabled()) { ++ static int once = 1; ++ if (once) { ++ once = 0; ++ print_irqtrace_events(current); ++ WARN_ON(1); ++ } + } +- __preempt_enable_no_resched(); +- if (unlikely(test_thread_flag(TIF_NEED_RESCHED) || +- test_thread_flag(TIF_NEED_RESCHED_DELAYED))) +- goto need_resched; ++} ++ ++/* ++ * schedule() is the main scheduler function. ++ */ ++asmlinkage void __sched schedule(void) ++{ ++ WARN_ON(system_state == SYSTEM_BOOTING); ++ /* ++ * Test if we have interrupts disabled. ++ */ ++ if (unlikely(irqs_disabled())) { ++ printk(KERN_ERR "BUG: scheduling with irqs disabled: " ++ "%s/0x%08x/%d\n", current->comm, preempt_count(), ++ current->pid); ++ print_symbol("caller is %s\n", ++ (long)__builtin_return_address(0)); ++ dump_stack(); ++ } ++ ++ if (unlikely(current->flags & PF_NOSCHED)) { ++ current->flags &= ~PF_NOSCHED; ++ printk(KERN_ERR "%s:%d userspace BUG: scheduling in " ++ "user-atomic context!\n", current->comm, current->pid); ++ dump_stack(); ++ send_sig(SIGUSR2, current, 1); ++ } ++ ++ local_irq_disable(); ++ ++ do { ++ __schedule(); ++ } while (unlikely(test_thread_flag(TIF_NEED_RESCHED) || ++ test_thread_flag(TIF_NEED_RESCHED_DELAYED))); ++ ++ local_irq_enable(); + } + EXPORT_SYMBOL(schedule); + + #ifdef CONFIG_PREEMPT ++ ++/* ++ * Global flag to turn preemption off on a CONFIG_PREEMPT kernel: ++ */ ++int kernel_preemption = 1; ++ ++static int __init preempt_setup (char *str) ++{ ++ if (!strncmp(str, "off", 3)) { ++ if (kernel_preemption) { ++ printk(KERN_INFO "turning off kernel preemption!\n"); ++ kernel_preemption = 0; ++ } ++ return 1; ++ } ++ if (!strncmp(str, "on", 2)) { ++ if (!kernel_preemption) { ++ printk(KERN_INFO "turning on kernel preemption!\n"); ++ kernel_preemption = 1; ++ } ++ return 1; ++ } ++ get_option(&str, &kernel_preemption); ++ ++ return 1; ++} ++ ++__setup("preempt=", preempt_setup); ++ + /* + * this is the entry point to schedule() from in-kernel preemption + * off of preempt_enable. Kernel preemptions off return from interrupt +@@ -3824,6 +3990,8 @@ asmlinkage void __sched preempt_schedule + struct task_struct *task = current; + int saved_lock_depth; + #endif ++ if (!kernel_preemption) ++ return; + /* + * If there is a non-zero preempt_count or interrupts are disabled, + * we do not want to preempt the current task. Just return.. +@@ -3832,6 +4000,7 @@ asmlinkage void __sched preempt_schedule + return; + + do { ++ local_irq_disable(); + add_preempt_count(PREEMPT_ACTIVE); + + /* +@@ -3843,11 +4012,11 @@ asmlinkage void __sched preempt_schedule + saved_lock_depth = task->lock_depth; + task->lock_depth = -1; + #endif +- schedule(); ++ __schedule(); + #ifdef CONFIG_PREEMPT_BKL + task->lock_depth = saved_lock_depth; + #endif +- sub_preempt_count(PREEMPT_ACTIVE); ++ local_irq_enable(); + + /* + * Check again in case we missed a preemption opportunity +@@ -3859,10 +4028,10 @@ asmlinkage void __sched preempt_schedule + EXPORT_SYMBOL(preempt_schedule); + + /* +- * this is the entry point to schedule() from kernel preemption +- * off of irq context. +- * Note, that this is called and return with irqs disabled. This will +- * protect us against recursive calling from irq. ++ * this is is the entry point for the IRQ return path. Called with ++ * interrupts disabled. To avoid infinite irq-entry recursion problems ++ * with fast-paced IRQ sources we do all of this carefully to never ++ * enable interrupts again. + */ + asmlinkage void __sched preempt_schedule_irq(void) + { +@@ -3871,10 +4040,18 @@ asmlinkage void __sched preempt_schedule + struct task_struct *task = current; + int saved_lock_depth; + #endif +- /* Catch callers which need to be fixed */ +- WARN_ON_ONCE(ti->preempt_count || !irqs_disabled()); ++ ++ if (!kernel_preemption) ++ return; ++ /* ++ * If there is a non-zero preempt_count then just return. ++ * (interrupts are disabled) ++ */ ++ if (unlikely(ti->preempt_count)) ++ return; + + do { ++ local_irq_disable(); + add_preempt_count(PREEMPT_ACTIVE); + + /* +@@ -3886,13 +4063,12 @@ asmlinkage void __sched preempt_schedule + saved_lock_depth = task->lock_depth; + task->lock_depth = -1; + #endif +- local_irq_enable(); +- schedule(); ++ __schedule(); ++ + local_irq_disable(); + #ifdef CONFIG_PREEMPT_BKL + task->lock_depth = saved_lock_depth; + #endif +- sub_preempt_count(PREEMPT_ACTIVE); + + /* + * Check again in case we missed a preemption opportunity +@@ -4156,7 +4332,7 @@ EXPORT_SYMBOL(sleep_on_timeout); + void rt_mutex_setprio(struct task_struct *p, int prio) + { + unsigned long flags; +- int oldprio, on_rq, running; ++ int oldprio, prev_resched, on_rq, running; + struct rq *rq; + const struct sched_class *prev_class = p->sched_class; + +@@ -4180,12 +4356,17 @@ void rt_mutex_setprio(struct task_struct + + p->prio = prio; + ++// trace_special_pid(p->pid, __PRIO(oldprio), PRIO(p)); ++ prev_resched = _need_resched(); ++ + if (running) + p->sched_class->set_curr_task(rq); + if (on_rq) { + enqueue_task(rq, p, 0); + check_class_changed(rq, p, prev_class, oldprio, running); + } ++// trace_special(prev_resched, _need_resched(), 0); ++ + task_rq_unlock(rq, &flags); + } + +@@ -4777,14 +4958,17 @@ asmlinkage long sys_sched_yield(void) + */ + spin_unlock_no_resched(&rq->lock); + +- schedule(); ++ __schedule(); ++ ++ local_irq_enable(); ++ preempt_check_resched(); + + return 0; + } + + static void __cond_resched(void) + { +-#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP ++#if defined(CONFIG_DEBUG_SPINLOCK_SLEEP) || defined(CONFIG_DEBUG_PREEMPT) + __might_sleep(__FILE__, __LINE__); + #endif + /* +@@ -4793,10 +4977,11 @@ static void __cond_resched(void) + * cond_resched() call. + */ + do { ++ local_irq_disable(); + add_preempt_count(PREEMPT_ACTIVE); +- schedule(); +- sub_preempt_count(PREEMPT_ACTIVE); ++ __schedule(); + } while (need_resched()); ++ local_irq_enable(); + } + + int __sched cond_resched(void) +@@ -4822,7 +5007,7 @@ int __cond_resched_raw_spinlock(raw_spin + { + int ret = 0; + +- if (need_lockbreak(lock)) { ++ if (need_lockbreak_raw(lock)) { + spin_unlock(lock); + cpu_relax(); + ret = 1; +@@ -4838,6 +5023,25 @@ int __cond_resched_raw_spinlock(raw_spin + } + EXPORT_SYMBOL(__cond_resched_raw_spinlock); + ++#ifdef CONFIG_PREEMPT_RT ++ ++int __cond_resched_spinlock(spinlock_t *lock) ++{ ++#if (defined(CONFIG_SMP) && defined(CONFIG_PREEMPT)) || defined(CONFIG_PREEMPT_RT) ++ if (lock->break_lock) { ++ lock->break_lock = 0; ++ spin_unlock_no_resched(lock); ++ __cond_resched(); ++ spin_lock(lock); ++ return 1; ++ } ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(__cond_resched_spinlock); ++ ++#endif ++ + /* + * Voluntarily preempt a process context that has softirqs disabled: + */ +@@ -4884,11 +5088,15 @@ int cond_resched_hardirq_context(void) + WARN_ON_ONCE(!irqs_disabled()); + + if (hardirq_need_resched()) { ++#ifndef CONFIG_PREEMPT_RT + irq_exit(); ++#endif + local_irq_enable(); + __cond_resched(); ++#ifndef CONFIG_PREEMPT_RT + local_irq_disable(); + __irq_enter(); ++#endif + + return 1; + } +@@ -4896,17 +5104,58 @@ int cond_resched_hardirq_context(void) + } + EXPORT_SYMBOL(cond_resched_hardirq_context); + ++#ifdef CONFIG_PREEMPT_VOLUNTARY ++ ++int voluntary_preemption = 1; ++ ++EXPORT_SYMBOL(voluntary_preemption); ++ ++static int __init voluntary_preempt_setup (char *str) ++{ ++ if (!strncmp(str, "off", 3)) ++ voluntary_preemption = 0; ++ else ++ get_option(&str, &voluntary_preemption); ++ if (!voluntary_preemption) ++ printk("turning off voluntary preemption!\n"); ++ ++ return 1; ++} ++ ++__setup("voluntary-preempt=", voluntary_preempt_setup); ++ ++#endif ++ + /** + * yield - yield the current processor to other threads. + * + * This is a shortcut for kernel-space yielding - it marks the + * thread runnable and calls sys_sched_yield(). + */ +-void __sched yield(void) ++void __sched __yield(void) + { + set_current_state(TASK_RUNNING); + sys_sched_yield(); + } ++ ++void __sched yield(void) ++{ ++ static int once = 1; ++ ++ /* ++ * it's a bug to rely on yield() with RT priorities. We print ++ * the first occurance after bootup ... this will still give ++ * us an idea about the scope of the problem, without spamming ++ * the syslog: ++ */ ++ if (once && rt_task(current)) { ++ once = 0; ++ printk(KERN_ERR "BUG: %s:%d RT task yield()-ing!\n", ++ current->comm, current->pid); ++ dump_stack(); ++ } ++ __yield(); ++} + EXPORT_SYMBOL(yield); + + /* +@@ -5089,6 +5338,7 @@ static void show_task(struct task_struct + void show_state_filter(unsigned long state_filter) + { + struct task_struct *g, *p; ++ int do_unlock = 1; + + #if BITS_PER_LONG == 32 + printk(KERN_INFO +@@ -5097,7 +5347,16 @@ void show_state_filter(unsigned long sta + printk(KERN_INFO + " task PC stack pid father\n"); + #endif ++#ifdef CONFIG_PREEMPT_RT ++ if (!read_trylock(&tasklist_lock)) { ++ printk("hm, tasklist_lock write-locked.\n"); ++ printk("ignoring ...\n"); ++ do_unlock = 0; ++ } ++#else + read_lock(&tasklist_lock); ++#endif ++ + do_each_thread(g, p) { + /* + * reset the NMI-timeout, listing all files on a slow +@@ -5113,7 +5372,8 @@ void show_state_filter(unsigned long sta + #ifdef CONFIG_SCHED_DEBUG + sysrq_sched_debug_show(); + #endif +- read_unlock(&tasklist_lock); ++ if (do_unlock) ++ read_unlock(&tasklist_lock); + /* + * Only show locks if all tasks are dumped: + */ +@@ -5154,7 +5414,9 @@ void __cpuinit init_idle(struct task_str + spin_unlock_irqrestore(&rq->lock, flags); + + /* Set the preempt count _outside_ the spinlocks! */ +-#if defined(CONFIG_PREEMPT) && !defined(CONFIG_PREEMPT_BKL) ++#if defined(CONFIG_PREEMPT) && \ ++ !defined(CONFIG_PREEMPT_BKL) && \ ++ !defined(CONFIG_PREEMPT_RT) + task_thread_info(idle)->preempt_count = (idle->lock_depth >= 0); + #else + task_thread_info(idle)->preempt_count = 0; +@@ -5279,11 +5541,18 @@ EXPORT_SYMBOL_GPL(set_cpus_allowed); + static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) + { + struct rq *rq_dest, *rq_src; ++ unsigned long flags; + int ret = 0, on_rq; + + if (unlikely(cpu_is_offline(dest_cpu))) + return ret; + ++ /* ++ * PREEMPT_RT: this relies on write_lock_irq(&tasklist_lock) ++ * disabling interrupts - which on PREEMPT_RT does not do: ++ */ ++ local_irq_save(flags); ++ + rq_src = cpu_rq(src_cpu); + rq_dest = cpu_rq(dest_cpu); + +@@ -5307,6 +5576,8 @@ static int __migrate_task(struct task_st + ret = 1; + out: + double_rq_unlock(rq_src, rq_dest); ++ local_irq_restore(flags); ++ + return ret; + } + +@@ -7100,6 +7371,9 @@ void __init sched_init(void) + atomic_inc(&init_mm.mm_count); + enter_lazy_tlb(&init_mm, current); + ++#ifdef CONFIG_PREEMPT_RT ++ printk("Real-Time Preemption Support (C) 2004-2007 Ingo Molnar\n"); ++#endif + /* + * Make us the idle thread. Technically, schedule() should not be + * called from this thread, however somewhere below it might be, +@@ -7121,13 +7395,16 @@ void __might_sleep(char *file, int line) + + if ((in_atomic() || irqs_disabled()) && + system_state == SYSTEM_RUNNING && !oops_in_progress) { ++ if (debug_direct_keyboard && hardirq_count()) ++ return; + if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) + return; + prev_jiffy = jiffies; + printk(KERN_ERR "BUG: sleeping function called from invalid" +- " context at %s:%d\n", file, line); +- printk("in_atomic():%d, irqs_disabled():%d\n", +- in_atomic(), irqs_disabled()); ++ " context %s(%d) at %s:%d\n", ++ current->comm, current->pid, file, line); ++ printk("in_atomic():%d [%08x], irqs_disabled():%d\n", ++ in_atomic(), preempt_count(), irqs_disabled()); + debug_show_held_locks(current); + if (irqs_disabled()) + print_irqtrace_events(current); +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:02:37.000000000 -0500 +@@ -115,6 +115,48 @@ static inline void dec_rt_tasks(struct t + #endif /* CONFIG_SMP */ + } + ++static inline void incr_rt_nr_uninterruptible(struct task_struct *p, ++ struct rq *rq) ++{ ++ rq->rt.rt_nr_uninterruptible++; ++} ++ ++static inline void decr_rt_nr_uninterruptible(struct task_struct *p, ++ struct rq *rq) ++{ ++ rq->rt.rt_nr_uninterruptible--; ++} ++ ++unsigned long rt_nr_running(void) ++{ ++ unsigned long i, sum = 0; ++ ++ for_each_online_cpu(i) ++ sum += cpu_rq(i)->rt.rt_nr_running; ++ ++ return sum; ++} ++ ++unsigned long rt_nr_running_cpu(int cpu) ++{ ++ return cpu_rq(cpu)->rt.rt_nr_running; ++} ++ ++unsigned long rt_nr_uninterruptible(void) ++{ ++ unsigned long i, sum = 0; ++ ++ for_each_online_cpu(i) ++ sum += cpu_rq(i)->rt.rt_nr_uninterruptible; ++ ++ return sum; ++} ++ ++unsigned long rt_nr_uninterruptible_cpu(int cpu) ++{ ++ return cpu_rq(cpu)->rt.rt_nr_uninterruptible; ++} ++ + static void enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup) + { + struct rt_prio_array *array = &rq->rt.active; +@@ -122,6 +164,9 @@ static void enqueue_task_rt(struct rq *r + list_add_tail(&p->run_list, array->queue + p->prio); + __set_bit(p->prio, array->bitmap); + inc_rt_tasks(p, rq); ++ ++ if (p->state == TASK_UNINTERRUPTIBLE) ++ decr_rt_nr_uninterruptible(p, rq); + } + + /* +@@ -133,6 +178,9 @@ static void dequeue_task_rt(struct rq *r + + update_curr_rt(rq); + ++ if (p->state == TASK_UNINTERRUPTIBLE) ++ incr_rt_nr_uninterruptible(p, rq); ++ + list_del(&p->run_list); + if (list_empty(array->queue + p->prio)) + __clear_bit(p->prio, array->bitmap); +@@ -500,6 +548,8 @@ static int push_rt_task(struct rq *rq) + + resched_task(lowest_rq->curr); + ++ schedstat_inc(rq, rto_pushed); ++ + spin_unlock(&lowest_rq->lock); + + ret = 1; +@@ -606,6 +656,7 @@ static int pull_rt_task(struct rq *this_ + */ + next = p; + ++ schedstat_inc(src_rq, rto_pulled); + } + out: + spin_unlock(&src_rq->lock); +@@ -617,8 +668,10 @@ static int pull_rt_task(struct rq *this_ + static void pre_schedule_rt(struct rq *rq, struct task_struct *prev) + { + /* Try to pull RT tasks here if we lower this rq's prio */ +- if (unlikely(rt_task(prev)) && rq->rt.highest_prio > prev->prio) ++ if (unlikely(rt_task(prev)) && rq->rt.highest_prio > prev->prio) { + pull_rt_task(rq); ++ schedstat_inc(rq, rto_schedule); ++ } + } + + static void post_schedule_rt(struct rq *rq) +@@ -633,6 +686,7 @@ static void post_schedule_rt(struct rq * + if (unlikely(rq->rt.overloaded)) { + spin_lock_irq(&rq->lock); + push_rt_tasks(rq); ++ schedstat_inc(rq, rto_schedule_tail); + spin_unlock_irq(&rq->lock); + } + } +@@ -642,8 +696,10 @@ static void task_wake_up_rt(struct rq *r + { + if (!task_running(rq, p) && + (p->prio >= rq->rt.highest_prio) && +- rq->rt.overloaded) ++ rq->rt.overloaded) { + push_rt_tasks(rq); ++ schedstat_inc(rq, rto_wakeup); ++ } + } + + static unsigned long --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0317-new-softirq-code.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0317-new-softirq-code.patch @@ -0,0 +1,343 @@ +Subject: [patch] softirq preemption: optimization +From: Ingo Molnar + +optimize softirq preemption by allowing a hardirq context to pick up +softirq processing. + +Signed-off-by: Ingo Molnar +--- + kernel/irq/manage.c | 19 +----- + kernel/softirq.c | 160 ++++++++++++++++++++++++++++++++++++++++------------ + 2 files changed, 131 insertions(+), 48 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/irq/manage.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/irq/manage.c 2009-02-08 00:02:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/irq/manage.c 2009-02-08 00:03:20.000000000 -0500 +@@ -708,7 +708,6 @@ static void thread_edge_irq(irq_desc_t * + desc->status &= ~IRQ_PENDING; + spin_unlock(&desc->lock); + action_ret = handle_IRQ_event(irq, action); +- cond_resched_hardirq_context(); + spin_lock_irq(&desc->lock); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); +@@ -737,7 +736,6 @@ static void thread_do_irq(irq_desc_t *de + desc->status &= ~IRQ_PENDING; + spin_unlock(&desc->lock); + action_ret = handle_IRQ_event(irq, action); +- cond_resched_hardirq_context(); + spin_lock_irq(&desc->lock); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); +@@ -773,8 +771,6 @@ static void do_hardirq(struct irq_desc * + wake_up(&desc->wait_for_handler); + } + +-extern asmlinkage void __do_softirq(void); +- + static int do_irqd(void * __desc) + { + struct sched_param param = { 0, }; +@@ -794,16 +790,13 @@ static int do_irqd(void * __desc) + + while (!kthread_should_stop()) { + local_irq_disable_nort(); +- set_current_state(TASK_INTERRUPTIBLE); +-#ifndef CONFIG_PREEMPT_RT +- irq_enter(); +-#endif +- do_hardirq(desc); +-#ifndef CONFIG_PREEMPT_RT +- irq_exit(); +-#endif ++ do { ++ set_current_state(TASK_INTERRUPTIBLE); ++ do_hardirq(desc); ++ do_softirq_from_hardirq(); ++ } while (current->state == TASK_RUNNING); ++ + local_irq_enable_nort(); +- cond_resched(); + #ifdef CONFIG_SMP + /* + * Did IRQ affinities change? +Index: linux-2.6.24.7-rt27/kernel/softirq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/softirq.c 2009-02-08 00:02:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/softirq.c 2009-02-08 00:03:20.000000000 -0500 +@@ -101,8 +101,26 @@ static void wakeup_softirqd(int softirq) + /* Interrupts are disabled: no need to stop preemption */ + struct task_struct *tsk = __get_cpu_var(ksoftirqd)[softirq].tsk; + +- if (tsk && tsk->state != TASK_RUNNING) +- wake_up_process(tsk); ++ if (unlikely(!tsk)) ++ return; ++#if defined(CONFIG_PREEMPT_SOFTIRQS) && defined(CONFIG_PREEMPT_HARDIRQS) ++ /* ++ * Optimization: if we are in a hardirq thread context, and ++ * if the priority of the softirq thread is the same as the ++ * priority of the hardirq thread, then 'merge' softirq ++ * processing into the hardirq context. (it will later on ++ * execute softirqs via do_softirq_from_hardirq()). ++ * So here we can skip the wakeup and can rely on the hardirq ++ * context processing it later on. ++ */ ++ if ((current->flags & PF_HARDIRQ) && !hardirq_count() && ++ (tsk->normal_prio == current->normal_prio)) ++ return; ++#endif ++ /* ++ * Wake up the softirq task: ++ */ ++ wake_up_process(tsk); + } + + /* +@@ -251,50 +269,100 @@ EXPORT_SYMBOL(local_bh_enable_ip); + * we want to handle softirqs as soon as possible, but they + * should not be able to lock up the box. + */ +-#define MAX_SOFTIRQ_RESTART 10 ++#define MAX_SOFTIRQ_RESTART 20 ++ ++static DEFINE_PER_CPU(u32, softirq_running); + +-asmlinkage void ___do_softirq(void) ++static void ___do_softirq(const int same_prio_only) + { ++ int max_restart = MAX_SOFTIRQ_RESTART, max_loops = MAX_SOFTIRQ_RESTART; ++ __u32 pending, available_mask, same_prio_skipped; + struct softirq_action *h; +- __u32 pending; +- int max_restart = MAX_SOFTIRQ_RESTART; +- int cpu; ++ struct task_struct *tsk; ++ int cpu, softirq; + + pending = local_softirq_pending(); + account_system_vtime(current); + + cpu = smp_processor_id(); + restart: ++ available_mask = -1; ++ softirq = 0; ++ same_prio_skipped = 0; + /* Reset the pending bitmask before enabling irqs */ + set_softirq_pending(0); + +- local_irq_enable(); +- + h = softirq_vec; + + do { ++ u32 softirq_mask = 1 << softirq; ++ + if (pending & 1) { +- { +- u32 preempt_count = preempt_count(); +- h->action(h); +- if (preempt_count != preempt_count()) { +- print_symbol("BUG: softirq exited %s with wrong preemption count!\n", (unsigned long) h->action); +- printk("entered with %08x, exited with %08x.\n", preempt_count, preempt_count()); +- preempt_count() = preempt_count; ++ u32 preempt_count = preempt_count(); ++ ++#if defined(CONFIG_PREEMPT_SOFTIRQS) && defined(CONFIG_PREEMPT_HARDIRQS) ++ /* ++ * If executed by a same-prio hardirq thread ++ * then skip pending softirqs that belong ++ * to softirq threads with different priority: ++ */ ++ if (same_prio_only) { ++ tsk = __get_cpu_var(ksoftirqd)[softirq].tsk; ++ if (tsk && tsk->normal_prio != ++ current->normal_prio) { ++ same_prio_skipped |= softirq_mask; ++ available_mask &= ~softirq_mask; ++ goto next; + } + } ++#endif ++ /* ++ * Is this softirq already being processed? ++ */ ++ if (per_cpu(softirq_running, cpu) & softirq_mask) { ++ available_mask &= ~softirq_mask; ++ goto next; ++ } ++ per_cpu(softirq_running, cpu) |= softirq_mask; ++ local_irq_enable(); ++ ++ h->action(h); ++ if (preempt_count != preempt_count()) { ++ print_symbol("BUG: softirq exited %s with wrong preemption count!\n", (unsigned long) h->action); ++ printk("entered with %08x, exited with %08x.\n", preempt_count, preempt_count()); ++ preempt_count() = preempt_count; ++ } + rcu_bh_qsctr_inc(cpu); + cond_resched_softirq_context(); ++ local_irq_disable(); ++ per_cpu(softirq_running, cpu) &= ~softirq_mask; + } ++next: + h++; ++ softirq++; + pending >>= 1; + } while (pending); + +- local_irq_disable(); +- ++ or_softirq_pending(same_prio_skipped); + pending = local_softirq_pending(); +- if (pending && --max_restart) +- goto restart; ++ if (pending & available_mask) { ++ if (--max_restart) ++ goto restart; ++ /* ++ * With softirq threading there's no reason not to ++ * finish the workload we have: ++ */ ++#ifdef CONFIG_PREEMPT_SOFTIRQS ++ if (--max_loops) { ++ if (printk_ratelimit()) ++ printk("INFO: softirq overload: %08x\n", pending); ++ max_restart = MAX_SOFTIRQ_RESTART; ++ goto restart; ++ } ++ if (printk_ratelimit()) ++ printk("BUG: softirq loop! %08x\n", pending); ++#endif ++ } + + if (pending) + trigger_softirqs(); +@@ -322,7 +390,7 @@ asmlinkage void __do_softirq(void) + p_flags = current->flags & PF_HARDIRQ; + current->flags &= ~PF_HARDIRQ; + +- ___do_softirq(); ++ ___do_softirq(0); + + trace_softirq_exit(); + +@@ -346,20 +414,29 @@ void do_softirq_from_hardirq(void) + if (!local_softirq_pending()) + return; + /* +- * 'immediate' softirq execution: ++ * 'immediate' softirq execution, from hardirq context: + */ ++ local_irq_disable(); + __local_bh_disable((unsigned long)__builtin_return_address(0)); ++#ifndef CONFIG_PREEMPT_SOFTIRQS ++ trace_softirq_enter(); ++#endif + p_flags = current->flags & PF_HARDIRQ; + current->flags &= ~PF_HARDIRQ; ++ current->flags |= PF_SOFTIRQ; + +- ___do_softirq(); ++ ___do_softirq(1); + ++#ifndef CONFIG_PREEMPT_SOFTIRQS + trace_softirq_exit(); +- ++#endif + account_system_vtime(current); +- _local_bh_enable(); + + current->flags |= p_flags; ++ current->flags &= ~PF_SOFTIRQ; ++ ++ _local_bh_enable(); ++ local_irq_enable(); + } + + #ifndef __ARCH_HAS_DO_SOFTIRQ +@@ -690,8 +767,9 @@ static int ksoftirqd(void * __data) + { + struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2 }; + struct softirqdata *data = __data; +- u32 mask = (1 << data->nr); ++ u32 softirq_mask = (1 << data->nr); + struct softirq_action *h; ++ int cpu = data->cpu; + + #ifdef CONFIG_PREEMPT_SOFTIRQS + init_waitqueue_head(&data->wait); +@@ -703,7 +781,8 @@ static int ksoftirqd(void * __data) + + while (!kthread_should_stop()) { + preempt_disable(); +- if (!(local_softirq_pending() & mask)) { ++ if (!(local_softirq_pending() & softirq_mask)) { ++sleep_more: + __preempt_enable_no_resched(); + schedule(); + preempt_disable(); +@@ -715,16 +794,26 @@ static int ksoftirqd(void * __data) + data->running = 1; + #endif + +- while (local_softirq_pending() & mask) { ++ while (local_softirq_pending() & softirq_mask) { + /* Preempt disable stops cpu going offline. + If already offline, we'll be on wrong CPU: + don't process */ +- if (cpu_is_offline(data->cpu)) ++ if (cpu_is_offline(cpu)) + goto wait_to_die; + + local_irq_disable(); ++ /* ++ * Is the softirq already being executed by ++ * a hardirq context? ++ */ ++ if (per_cpu(softirq_running, cpu) & softirq_mask) { ++ local_irq_enable(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ goto sleep_more; ++ } ++ per_cpu(softirq_running, cpu) |= softirq_mask; + __preempt_enable_no_resched(); +- set_softirq_pending(local_softirq_pending() & ~mask); ++ set_softirq_pending(local_softirq_pending() & ~softirq_mask); + local_bh_disable(); + local_irq_enable(); + +@@ -734,6 +823,7 @@ static int ksoftirqd(void * __data) + rcu_bh_qsctr_inc(data->cpu); + + local_irq_disable(); ++ per_cpu(softirq_running, cpu) &= ~softirq_mask; + _local_bh_enable(); + local_irq_enable(); + +@@ -876,19 +966,19 @@ static int __cpuinit cpu_callback(struct + } + #endif + case CPU_DEAD: +- case CPU_DEAD_FROZEN: { +- struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; +- +- sched_setscheduler(p, SCHED_FIFO, ¶m); ++ case CPU_DEAD_FROZEN: + for (i = 0; i < MAX_SOFTIRQ; i++) { ++ struct sched_param param; ++ ++ param.sched_priority = MAX_RT_PRIO-1; + p = per_cpu(ksoftirqd, hotcpu)[i].tsk; ++ sched_setscheduler(p, SCHED_FIFO, ¶m); + per_cpu(ksoftirqd, hotcpu)[i].tsk = NULL; + kthread_stop(p); + } + takeover_tasklets(hotcpu); + break; + #endif /* CONFIG_HOTPLUG_CPU */ +- } + } + return NOTIFY_OK; + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0023-0009-sched-clean-up-this_rq-use-in-kernel-sched_rt.c.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0023-0009-sched-clean-up-this_rq-use-in-kernel-sched_rt.c.patch @@ -0,0 +1,87 @@ +From 320d79d4305922c7ddcc268321245a7d572f4349 Mon Sep 17 00:00:00 2001 +From: Gregory Haskins +Date: Tue, 11 Dec 2007 10:02:37 +0100 +Subject: [PATCH] sched: clean up this_rq use in kernel/sched_rt.c + +"this_rq" is normally used to denote the RQ on the current cpu +(i.e. "cpu_rq(this_cpu)"). So clean up the usage of this_rq to be +more consistent with the rest of the code. + +Signed-off-by: Gregory Haskins +Signed-off-by: Steven Rostedt +Signed-off-by: Ingo Molnar + +--- + kernel/sched_rt.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:00:53.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:00:53.000000000 -0500 +@@ -324,21 +324,21 @@ static struct rq *find_lock_lowest_rq(st + * running task can migrate over to a CPU that is running a task + * of lesser priority. + */ +-static int push_rt_task(struct rq *this_rq) ++static int push_rt_task(struct rq *rq) + { + struct task_struct *next_task; + struct rq *lowest_rq; + int ret = 0; + int paranoid = RT_MAX_TRIES; + +- assert_spin_locked(&this_rq->lock); ++ assert_spin_locked(&rq->lock); + +- next_task = pick_next_highest_task_rt(this_rq, -1); ++ next_task = pick_next_highest_task_rt(rq, -1); + if (!next_task) + return 0; + + retry: +- if (unlikely(next_task == this_rq->curr)) { ++ if (unlikely(next_task == rq->curr)) { + WARN_ON(1); + return 0; + } +@@ -348,24 +348,24 @@ static int push_rt_task(struct rq *this_ + * higher priority than current. If that's the case + * just reschedule current. + */ +- if (unlikely(next_task->prio < this_rq->curr->prio)) { +- resched_task(this_rq->curr); ++ if (unlikely(next_task->prio < rq->curr->prio)) { ++ resched_task(rq->curr); + return 0; + } + +- /* We might release this_rq lock */ ++ /* We might release rq lock */ + get_task_struct(next_task); + + /* find_lock_lowest_rq locks the rq if found */ +- lowest_rq = find_lock_lowest_rq(next_task, this_rq); ++ lowest_rq = find_lock_lowest_rq(next_task, rq); + if (!lowest_rq) { + struct task_struct *task; + /* +- * find lock_lowest_rq releases this_rq->lock ++ * find lock_lowest_rq releases rq->lock + * so it is possible that next_task has changed. + * If it has, then try again. + */ +- task = pick_next_highest_task_rt(this_rq, -1); ++ task = pick_next_highest_task_rt(rq, -1); + if (unlikely(task != next_task) && task && paranoid--) { + put_task_struct(next_task); + next_task = task; +@@ -376,7 +376,7 @@ static int push_rt_task(struct rq *this_ + + assert_spin_locked(&lowest_rq->lock); + +- deactivate_task(this_rq, next_task, 0); ++ deactivate_task(rq, next_task, 0); + set_task_cpu(next_task, lowest_rq->cpu); + activate_task(lowest_rq, next_task, 0); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0196-kstat-add-rt-stats.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0196-kstat-add-rt-stats.patch @@ -0,0 +1,131 @@ +From: Thomas Gleixner +Subject: add rt stats to /proc/stat + +add RT stats to /proc/stat + +Signed-off-by: Ingo Molnar + + fs/proc/proc_misc.c | 24 ++++++++++++++++++------ + include/linux/kernel_stat.h | 2 ++ + kernel/sched.c | 6 +++++- + 3 files changed, 25 insertions(+), 7 deletions(-) + +Index: linux-2.6.24.7-rt27/fs/proc/proc_misc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/proc/proc_misc.c 2009-02-08 00:00:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/proc/proc_misc.c 2009-02-08 00:02:15.000000000 -0500 +@@ -455,7 +455,8 @@ static int show_stat(struct seq_file *p, + { + int i; + unsigned long jif; +- cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; ++ cputime64_t user_rt, user, nice, system_rt, system, idle, ++ iowait, irq, softirq, steal; + cputime64_t guest; + u64 sum = 0; + struct timespec boottime; +@@ -465,7 +466,7 @@ static int show_stat(struct seq_file *p, + if (!per_irq_sum) + return -ENOMEM; + +- user = nice = system = idle = iowait = ++ user_rt = user = nice = system_rt = system = idle = iowait = + irq = softirq = steal = cputime64_zero; + guest = cputime64_zero; + getboottime(&boottime); +@@ -482,6 +483,8 @@ static int show_stat(struct seq_file *p, + irq = cputime64_add(irq, kstat_cpu(i).cpustat.irq); + softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); + steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); ++ user_rt = cputime64_add(user_rt, kstat_cpu(i).cpustat.user_rt); ++ system_rt = cputime64_add(system_rt, kstat_cpu(i).cpustat.system_rt); + guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); + for (j = 0; j < NR_IRQS; j++) { + unsigned int temp = kstat_cpu(i).irqs[j]; +@@ -490,7 +493,10 @@ static int show_stat(struct seq_file *p, + } + } + +- seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", ++ user = cputime64_add(user_rt, user); ++ system = cputime64_add(system_rt, system); ++ ++ seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", + (unsigned long long)cputime64_to_clock_t(user), + (unsigned long long)cputime64_to_clock_t(nice), + (unsigned long long)cputime64_to_clock_t(system), +@@ -499,13 +505,17 @@ static int show_stat(struct seq_file *p, + (unsigned long long)cputime64_to_clock_t(irq), + (unsigned long long)cputime64_to_clock_t(softirq), + (unsigned long long)cputime64_to_clock_t(steal), ++ (unsigned long long)cputime64_to_clock_t(user_rt), ++ (unsigned long long)cputime64_to_clock_t(system_rt), + (unsigned long long)cputime64_to_clock_t(guest)); + for_each_online_cpu(i) { + + /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ +- user = kstat_cpu(i).cpustat.user; ++ user_rt = kstat_cpu(i).cpustat.user_rt; ++ system_rt = kstat_cpu(i).cpustat.system_rt; ++ user = cputime64_add(user_rt, kstat_cpu(i).cpustat.user); + nice = kstat_cpu(i).cpustat.nice; +- system = kstat_cpu(i).cpustat.system; ++ system = cputime64_add(system_rt, kstat_cpu(i).cpustat.system); + idle = kstat_cpu(i).cpustat.idle; + iowait = kstat_cpu(i).cpustat.iowait; + irq = kstat_cpu(i).cpustat.irq; +@@ -513,7 +523,7 @@ static int show_stat(struct seq_file *p, + steal = kstat_cpu(i).cpustat.steal; + guest = kstat_cpu(i).cpustat.guest; + seq_printf(p, +- "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", ++ "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", + i, + (unsigned long long)cputime64_to_clock_t(user), + (unsigned long long)cputime64_to_clock_t(nice), +@@ -523,6 +533,8 @@ static int show_stat(struct seq_file *p, + (unsigned long long)cputime64_to_clock_t(irq), + (unsigned long long)cputime64_to_clock_t(softirq), + (unsigned long long)cputime64_to_clock_t(steal), ++ (unsigned long long)cputime64_to_clock_t(user_rt), ++ (unsigned long long)cputime64_to_clock_t(system_rt), + (unsigned long long)cputime64_to_clock_t(guest)); + } + seq_printf(p, "intr %llu", (unsigned long long)sum); +Index: linux-2.6.24.7-rt27/include/linux/kernel_stat.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/kernel_stat.h 2009-02-08 00:00:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/kernel_stat.h 2009-02-08 00:02:15.000000000 -0500 +@@ -23,6 +23,8 @@ struct cpu_usage_stat { + cputime64_t idle; + cputime64_t iowait; + cputime64_t steal; ++ cputime64_t user_rt; ++ cputime64_t system_rt; + cputime64_t guest; + }; + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:02:15.000000000 -0500 +@@ -3450,7 +3450,9 @@ void account_user_time(struct task_struc + + /* Add user time to cpustat. */ + tmp = cputime_to_cputime64(cputime); +- if (TASK_NICE(p) > 0) ++ if (rt_task(p)) ++ cpustat->user_rt = cputime64_add(cpustat->user_rt, tmp); ++ else if (TASK_NICE(p) > 0) + cpustat->nice = cputime64_add(cpustat->nice, tmp); + else + cpustat->user = cputime64_add(cpustat->user, tmp); +@@ -3509,6 +3511,8 @@ void account_system_time(struct task_str + cpustat->irq = cputime64_add(cpustat->irq, tmp); + else if (softirq_count() || (p->flags & PF_SOFTIRQ)) + cpustat->softirq = cputime64_add(cpustat->softirq, tmp); ++ else if (rt_task(p)) ++ cpustat->system_rt = cputime64_add(cpustat->system_rt, tmp); + else if (p != rq->idle) + cpustat->system = cputime64_add(cpustat->system, tmp); + else if (atomic_read(&rq->nr_iowait) > 0) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0205-preempt-realtime-arm.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0205-preempt-realtime-arm.patch @@ -0,0 +1,235 @@ +--- + arch/arm/kernel/dma.c | 2 +- + arch/arm/kernel/irq.c | 2 +- + arch/arm/kernel/process.c | 2 +- + arch/arm/kernel/signal.c | 8 ++++++++ + arch/arm/kernel/smp.c | 2 +- + arch/arm/kernel/traps.c | 4 ++-- + arch/arm/mm/consistent.c | 2 +- + arch/arm/mm/copypage-v4mc.c | 2 +- + arch/arm/mm/copypage-v6.c | 2 +- + arch/arm/mm/copypage-xscale.c | 2 +- + arch/arm/mm/mmu.c | 2 +- + include/asm-arm/dma.h | 2 +- + include/asm-arm/futex.h | 2 +- + include/asm-arm/tlb.h | 9 ++++++--- + 14 files changed, 27 insertions(+), 16 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/arm/kernel/dma.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/dma.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/dma.c 2009-02-08 00:02:19.000000000 -0500 +@@ -20,7 +20,7 @@ + + #include + +-DEFINE_SPINLOCK(dma_spin_lock); ++DEFINE_RAW_SPINLOCK(dma_spin_lock); + EXPORT_SYMBOL(dma_spin_lock); + + static dma_t dma_chan[MAX_DMA_CHANNELS]; +Index: linux-2.6.24.7-rt27/arch/arm/kernel/irq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/irq.c 2009-02-08 00:01:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/irq.c 2009-02-08 00:02:19.000000000 -0500 +@@ -102,7 +102,7 @@ unlock: + /* Handle bad interrupts */ + static struct irq_desc bad_irq_desc = { + .handle_irq = handle_bad_irq, +- .lock = SPIN_LOCK_UNLOCKED ++ .lock = RAW_SPIN_LOCK_UNLOCKED(bad_irq_desc.lock) + }; + + /* +Index: linux-2.6.24.7-rt27/arch/arm/kernel/process.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/process.c 2009-02-08 00:02:06.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/process.c 2009-02-08 00:02:19.000000000 -0500 +@@ -37,7 +37,7 @@ + #include + #include + +-DEFINE_SPINLOCK(futex_atomic_lock); ++DEFINE_RAW_SPINLOCK(futex_atomic_lock); + + static const char *processor_modes[] = { + "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , +Index: linux-2.6.24.7-rt27/arch/arm/kernel/signal.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/signal.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/signal.c 2009-02-08 00:02:19.000000000 -0500 +@@ -623,6 +623,14 @@ static int do_signal(sigset_t *oldset, s + siginfo_t info; + int signr; + ++#ifdef CONFIG_PREEMPT_RT ++ /* ++ * Fully-preemptible kernel does not need interrupts disabled: ++ */ ++ local_irq_enable(); ++ preempt_check_resched(); ++#endif ++ + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from +Index: linux-2.6.24.7-rt27/arch/arm/kernel/smp.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/smp.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/smp.c 2009-02-08 00:02:19.000000000 -0500 +@@ -522,7 +522,7 @@ static void ipi_call_function(unsigned i + cpu_clear(cpu, data->unfinished); + } + +-static DEFINE_SPINLOCK(stop_lock); ++static DEFINE_RAW_SPINLOCK(stop_lock); + + /* + * ipi_cpu_stop - handle IPI from smp_send_stop() +Index: linux-2.6.24.7-rt27/arch/arm/kernel/traps.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/traps.c 2009-02-08 00:01:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/traps.c 2009-02-08 00:02:19.000000000 -0500 +@@ -233,7 +233,7 @@ static void __die(const char *str, int e + } + } + +-DEFINE_SPINLOCK(die_lock); ++DEFINE_RAW_SPINLOCK(die_lock); + + /* + * This function is protected against re-entrancy. +@@ -276,7 +276,7 @@ void arm_notify_die(const char *str, str + } + + static LIST_HEAD(undef_hook); +-static DEFINE_SPINLOCK(undef_lock); ++static DEFINE_RAW_SPINLOCK(undef_lock); + + void register_undef_hook(struct undef_hook *hook) + { +Index: linux-2.6.24.7-rt27/arch/arm/mm/consistent.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mm/consistent.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mm/consistent.c 2009-02-08 00:02:19.000000000 -0500 +@@ -40,7 +40,7 @@ + * These are the page tables (2MB each) covering uncached, DMA consistent allocations + */ + static pte_t *consistent_pte[NUM_CONSISTENT_PTES]; +-static DEFINE_SPINLOCK(consistent_lock); ++static DEFINE_RAW_SPINLOCK(consistent_lock); + + /* + * VM region handling support. +Index: linux-2.6.24.7-rt27/arch/arm/mm/copypage-v4mc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mm/copypage-v4mc.c 2009-02-08 00:01:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mm/copypage-v4mc.c 2009-02-08 00:02:19.000000000 -0500 +@@ -30,7 +30,7 @@ + #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \ + L_PTE_CACHEABLE) + +-static DEFINE_SPINLOCK(minicache_lock); ++static DEFINE_RAW_SPINLOCK(minicache_lock); + + /* + * ARMv4 mini-dcache optimised copy_user_page +Index: linux-2.6.24.7-rt27/arch/arm/mm/copypage-v6.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mm/copypage-v6.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mm/copypage-v6.c 2009-02-08 00:02:19.000000000 -0500 +@@ -26,7 +26,7 @@ + #define from_address (0xffff8000) + #define to_address (0xffffc000) + +-static DEFINE_SPINLOCK(v6_lock); ++static DEFINE_RAW_SPINLOCK(v6_lock); + + /* + * Copy the user page. No aliasing to deal with so we can just +Index: linux-2.6.24.7-rt27/arch/arm/mm/copypage-xscale.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mm/copypage-xscale.c 2009-02-08 00:01:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mm/copypage-xscale.c 2009-02-08 00:02:19.000000000 -0500 +@@ -32,7 +32,7 @@ + #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \ + L_PTE_CACHEABLE) + +-static DEFINE_SPINLOCK(minicache_lock); ++static DEFINE_RAW_SPINLOCK(minicache_lock); + + /* + * XScale mini-dcache optimised copy_user_page +Index: linux-2.6.24.7-rt27/arch/arm/mm/mmu.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mm/mmu.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mm/mmu.c 2009-02-08 00:02:19.000000000 -0500 +@@ -25,7 +25,7 @@ + + #include "mm.h" + +-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); ++DEFINE_PER_CPU_LOCKED(struct mmu_gather, mmu_gathers); + + extern void _stext, _etext, __data_start, _end; + extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; +Index: linux-2.6.24.7-rt27/include/asm-arm/dma.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/dma.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/dma.h 2009-02-08 00:02:19.000000000 -0500 +@@ -27,7 +27,7 @@ typedef unsigned int dmamode_t; + #define DMA_MODE_CASCADE 2 + #define DMA_AUTOINIT 4 + +-extern spinlock_t dma_spin_lock; ++extern raw_spinlock_t dma_spin_lock; + + static inline unsigned long claim_dma_lock(void) + { +Index: linux-2.6.24.7-rt27/include/asm-arm/futex.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/futex.h 2009-02-08 00:01:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/futex.h 2009-02-08 00:02:19.000000000 -0500 +@@ -7,7 +7,7 @@ + #include + #include + +-extern spinlock_t futex_atomic_lock; ++extern raw_spinlock_t futex_atomic_lock; + + #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ + __asm__ __volatile__ ( \ +Index: linux-2.6.24.7-rt27/include/asm-arm/tlb.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/tlb.h 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/tlb.h 2009-02-08 00:02:19.000000000 -0500 +@@ -36,15 +36,18 @@ + struct mmu_gather { + struct mm_struct *mm; + unsigned int fullmm; ++ int cpu; + }; + +-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); ++DECLARE_PER_CPU_LOCKED(struct mmu_gather, mmu_gathers); + + static inline struct mmu_gather * + tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) + { +- struct mmu_gather *tlb = &get_cpu_var(mmu_gathers); ++ int cpu; ++ struct mmu_gather *tlb = &get_cpu_var_locked(mmu_gathers, &cpu); + ++ tlb->cpu = cpu; + tlb->mm = mm; + tlb->fullmm = full_mm_flush; + +@@ -60,7 +63,7 @@ tlb_finish_mmu(struct mmu_gather *tlb, u + /* keep the page table cache within bounds */ + check_pgt_cache(); + +- put_cpu_var(mmu_gathers); ++ put_cpu_var_locked(mmu_gathers, tlb->cpu); + } + + #define tlb_remove_tlb_entry(tlb,ptep,address) do { } while (0) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0199-cputimer-thread-rt-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0199-cputimer-thread-rt-fix.patch @@ -0,0 +1,56 @@ +--- + kernel/posix-cpu-timers.c | 27 ++++++++++++++------------- + 1 file changed, 14 insertions(+), 13 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/posix-cpu-timers.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/posix-cpu-timers.c 2009-02-08 00:02:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/posix-cpu-timers.c 2009-02-08 00:02:17.000000000 -0500 +@@ -1292,18 +1292,6 @@ void __run_posix_cpu_timers(struct task_ + LIST_HEAD(firing); + struct k_itimer *timer, *next; + +- +-#define UNEXPIRED(clock) \ +- (cputime_eq(tsk->it_##clock##_expires, cputime_zero) || \ +- cputime_lt(clock##_ticks(tsk), tsk->it_##clock##_expires)) +- +- if (UNEXPIRED(prof) && UNEXPIRED(virt) && +- (tsk->it_sched_expires == 0 || +- tsk->se.sum_exec_runtime < tsk->it_sched_expires)) +- return; +- +-#undef UNEXPIRED +- + /* + * Double-check with locks held. + */ +@@ -1428,6 +1416,19 @@ void run_posix_cpu_timers(struct task_st + BUG_ON(!irqs_disabled()); + if(!per_cpu(posix_timer_task, cpu)) + return; ++ ++ ++#define UNEXPIRED(clock) \ ++ (cputime_eq(tsk->it_##clock##_expires, cputime_zero) || \ ++ cputime_lt(clock##_ticks(tsk), tsk->it_##clock##_expires)) ++ ++ if (UNEXPIRED(prof) && UNEXPIRED(virt) && ++ (tsk->it_sched_expires == 0 || ++ tsk->sum_exec_runtime < tsk->it_sched_expires)) ++ return; ++ ++#undef UNEXPIRED ++ + /* get per-cpu references */ + tasklist = per_cpu(posix_timer_tasklist, cpu); + +@@ -1446,7 +1447,7 @@ void run_posix_cpu_timers(struct task_st + per_cpu(posix_timer_tasklist, cpu) = tsk; + } + /* XXX signal the thread somehow */ +- wake_up_process(per_cpu(posix_timer_task,cpu)); ++ wake_up_process(per_cpu(posix_timer_task, cpu)); + } + + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0528-powerpc-xics-move-the-call-to-irq-radix-revmap-from-xics-startup-to-xics-host-map.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0528-powerpc-xics-move-the-call-to-irq-radix-revmap-from-xics-startup-to-xics-host-map.patch @@ -0,0 +1,79 @@ +Subject: powerpc - XICS: move the call to irq_radix_revmap + from xics_startup to xics_host_map +From: Sebastien Dugue +Date: Wed, 23 Jul 2008 17:00:24 +0200 +From: Sebastien Dugue +Date: Tue, 22 Jul 2008 13:05:24 +0200 +Subject: [PATCH][RT] powerpc - XICS: move the call to irq_radix_revmap from xics_startup to xics_host_map + + This patch moves the insertion of an irq into the reverse mapping radix tree +from xics_startup() into xics_host_map(). + + The reason for this change is that xics_startup() is called with preemption +disabled (which is not the case for xics_host_map()) which is a problem under a +preempt-rt kernel as we cannot even allocate GFP_ATOMIC memory for the radix tree +nodes. + + +Signed-off-by: Sebastien Dugue +Cc: Tim Chavez +Cc: Jean Pierre Dion +Cc: linuxppc-dev@ozlabs.org +Cc: paulus@samba.org +Cc: Gilles Carry +Signed-off-by: Thomas Gleixner +Cc: Benjamin Herrenschmidt +Cc: Paul Mackerras +Cc: Michael Ellerman + +--- + arch/powerpc/platforms/pseries/xics.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/pseries/xics.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/pseries/xics.c 2009-02-08 00:01:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/pseries/xics.c 2009-02-08 00:05:02.000000000 -0500 +@@ -262,12 +262,6 @@ static void xics_mask_irq(unsigned int v + + static unsigned int xics_startup(unsigned int virq) + { +- unsigned int irq; +- +- /* force a reverse mapping of the interrupt so it gets in the cache */ +- irq = (unsigned int)irq_map[virq].hwirq; +- irq_radix_revmap(xics_host, irq); +- + /* unmask it */ + xics_unmask_irq(virq); + return 0; +@@ -488,8 +482,14 @@ static int xics_host_match(struct irq_ho + static int xics_host_map_direct(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) + { ++ unsigned int irq; ++ + pr_debug("xics: map_direct virq %d, hwirq 0x%lx\n", virq, hw); + ++ /* force a reverse mapping of the interrupt so it gets in the cache */ ++ irq = (unsigned int)irq_map[virq].hwirq; ++ irq_radix_revmap(xics_host, irq); ++ + get_irq_desc(virq)->status |= IRQ_LEVEL; + set_irq_chip_and_handler(virq, &xics_pic_direct, handle_fasteoi_irq); + return 0; +@@ -498,8 +498,14 @@ static int xics_host_map_direct(struct i + static int xics_host_map_lpar(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) + { ++ unsigned int irq; ++ + pr_debug("xics: map_direct virq %d, hwirq 0x%lx\n", virq, hw); + ++ /* force a reverse mapping of the interrupt so it gets in the cache */ ++ irq = (unsigned int)irq_map[virq].hwirq; ++ irq_radix_revmap(xics_host, irq); ++ + get_irq_desc(virq)->status |= IRQ_LEVEL; + set_irq_chip_and_handler(virq, &xics_pic_lpar, handle_fasteoi_irq); + return 0; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0213-preempt-realtime-arm-shark.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0213-preempt-realtime-arm-shark.patch @@ -0,0 +1,17 @@ +--- + arch/arm/mach-shark/leds.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/arm/mach-shark/leds.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mach-shark/leds.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mach-shark/leds.c 2009-02-08 00:02:23.000000000 -0500 +@@ -32,7 +32,7 @@ static char led_state; + static short hw_led_state; + static short saved_state; + +-static DEFINE_SPINLOCK(leds_lock); ++static DEFINE_RAW_SPINLOCK(leds_lock); + + short sequoia_read(int addr) { + outw(addr,0x24); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0481-x86-delay-enable-preempt-tglx.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0481-x86-delay-enable-preempt-tglx.patch @@ -0,0 +1,138 @@ +From: Steven Rostedt +Subject: x86: enable preemption in delay + +The RT team has been searching for a nasty latency. This latency shows +up out of the blue and has been seen to be as big as 5ms! + +Using ftrace I found the cause of the latency. + + pcscd-2995 3dNh1 52360300us : irq_exit (smp_apic_timer_interrupt) + pcscd-2995 3dN.2 52360301us : idle_cpu (irq_exit) + pcscd-2995 3dN.2 52360301us : rcu_irq_exit (irq_exit) + pcscd-2995 3dN.1 52360771us : smp_apic_timer_interrupt (apic_timer_interrupt +) + pcscd-2995 3dN.1 52360771us : exit_idle (smp_apic_timer_interrupt) + +Here's an example of a 400 us latency. pcscd took a timer interrupt and +returned with "need resched" enabled, but did not reschedule until after +the next interrupt came in at 52360771us 400us later! + +At first I thought we somehow missed a preemption check in entry.S. But +I also noticed that this always seemed to happen during a __delay call. + + pcscd-2995 3dN.2 52360836us : rcu_irq_exit (irq_exit) + pcscd-2995 3.N.. 52361265us : preempt_schedule (__delay) + +Looking at the x86 delay, I found my problem. + +In git commit 35d5d08a085c56f153458c3f5d8ce24123617faf, Andrew Morton +placed preempt_disable around the entire delay due to TSC's not working +nicely on SMP. Unfortunately for those that care about latencies this +is devastating! Especially when we have callers to mdelay(8). + +Here I enable preemption during the loop and account for anytime the task +migrates to a new CPU. The delay asked for may be extended a bit by +the migration, but delay only guarantees that it will delay for that minimum +time. Delaying longer should not be an issue. + +[ + Thanks to Thomas Gleixner for spotting that cpu wasn't updated, + and to place the rep_nop between preempt_enabled/disable. +] + +Signed-off-by: Steven Rostedt +--- + arch/x86/lib/delay_32.c | 31 +++++++++++++++++++++++++++---- + arch/x86/lib/delay_64.c | 30 ++++++++++++++++++++++++++---- + 2 files changed, 53 insertions(+), 8 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/lib/delay_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/lib/delay_32.c 2009-02-07 23:59:38.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/lib/delay_32.c 2009-02-08 00:04:38.000000000 -0500 +@@ -42,13 +42,36 @@ static void delay_loop(unsigned long loo + static void delay_tsc(unsigned long loops) + { + unsigned long bclock, now; ++ int cpu; + +- preempt_disable(); /* TSC's are per-cpu */ ++ preempt_disable(); ++ cpu = smp_processor_id(); + rdtscl(bclock); +- do { +- rep_nop(); ++ for (;;) { + rdtscl(now); +- } while ((now-bclock) < loops); ++ if ((now - bclock) >= loops) ++ break; ++ ++ /* Allow RT tasks to run */ ++ preempt_enable(); ++ rep_nop(); ++ preempt_disable(); ++ ++ /* ++ * It is possible that we moved to another CPU, and ++ * since TSC's are per-cpu we need to calculate ++ * that. The delay must guarantee that we wait "at ++ * least" the amount of time. Being moved to another ++ * CPU could make the wait longer but we just need to ++ * make sure we waited long enough. Rebalance the ++ * counter for this CPU. ++ */ ++ if (unlikely(cpu != smp_processor_id())) { ++ loops -= (now - bclock); ++ cpu = smp_processor_id(); ++ rdtscl(bclock); ++ } ++ } + preempt_enable(); + } + +Index: linux-2.6.24.7-rt27/arch/x86/lib/delay_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/lib/delay_64.c 2009-02-07 23:59:38.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/lib/delay_64.c 2009-02-08 00:04:38.000000000 -0500 +@@ -29,14 +29,36 @@ int read_current_timer(unsigned long *ti + void __delay(unsigned long loops) + { + unsigned bclock, now; ++ int cpu; + +- preempt_disable(); /* TSC's are pre-cpu */ ++ preempt_disable(); ++ cpu = smp_processor_id(); + rdtscl(bclock); +- do { +- rep_nop(); ++ for (;;) { + rdtscl(now); ++ if ((now - bclock) >= loops) ++ break; ++ ++ /* Allow RT tasks to run */ ++ preempt_enable(); ++ rep_nop(); ++ preempt_disable(); ++ ++ /* ++ * It is possible that we moved to another CPU, and ++ * since TSC's are per-cpu we need to calculate ++ * that. The delay must guarantee that we wait "at ++ * least" the amount of time. Being moved to another ++ * CPU could make the wait longer but we just need to ++ * make sure we waited long enough. Rebalance the ++ * counter for this CPU. ++ */ ++ if (unlikely(cpu != smp_processor_id())) { ++ loops -= (now - bclock); ++ cpu = smp_processor_id(); ++ rdtscl(bclock); ++ } + } +- while ((now-bclock) < loops); + preempt_enable(); + } + EXPORT_SYMBOL(__delay); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0520-fix_misplaced_mb.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0520-fix_misplaced_mb.patch @@ -0,0 +1,48 @@ +Subject: rcu: fix misplaced mb() +From: Paul E. McKenney + +In the process of writing up the mechanical proof of correctness for the +dynticks/preemptable-RCU interface, I noticed misplaced memory barriers +in rcu_enter_nohz() and rcu_exit_nohz(). This patch puts them in the +right place and adds a comment. The key thing to keep in mind is that +rcu_enter_nohz() is -exiting- the mode that can legally execute RCU +read-side critical sections. The memory barrier must be between any +potential RCU read-side critical sections and the increment of the per-CPU +dynticks_progress_counter, and thus must come -before- this increment. +And vice versa for rcu_exit_nohz(). + +The locking in the scheduler is probably saving us for the moment. + +Signed-off-by: Paul E. McKenney +--- + + include/linux/rcupreempt.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/rcupreempt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupreempt.h 2009-02-08 00:04:55.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupreempt.h 2009-02-08 00:04:58.000000000 -0500 +@@ -105,6 +105,7 @@ DECLARE_PER_CPU(long, dynticks_progress_ + + static inline void rcu_enter_nohz(void) + { ++ smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ + __get_cpu_var(dynticks_progress_counter)++; + if (unlikely(__get_cpu_var(dynticks_progress_counter) & 0x1)) { + printk("BUG: bad accounting of dynamic ticks\n"); +@@ -113,13 +114,12 @@ static inline void rcu_enter_nohz(void) + /* try to fix it */ + __get_cpu_var(dynticks_progress_counter)++; + } +- mb(); + } + + static inline void rcu_exit_nohz(void) + { +- mb(); + __get_cpu_var(dynticks_progress_counter)++; ++ smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ + if (unlikely(!(__get_cpu_var(dynticks_progress_counter) & 0x1))) { + printk("BUG: bad accounting of dynamic ticks\n"); + printk(" will try to fix, but it is best to reboot\n"); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0121-rcu-new-3.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0121-rcu-new-3.patch @@ -0,0 +1,1503 @@ +From paulmck@linux.vnet.ibm.com Thu Sep 27 00:03:19 2007 +Date: Mon, 10 Sep 2007 11:34:12 -0700 +From: Paul E. McKenney +To: linux-kernel@vger.kernel.org +Cc: linux-rt-users@vger.kernel.org, mingo@elte.hu, akpm@linux-foundation.org, + dipankar@in.ibm.com, josht@linux.vnet.ibm.com, tytso@us.ibm.com, + dvhltc@us.ibm.com, tglx@linutronix.de, a.p.zijlstra@chello.nl, + bunk@kernel.org, ego@in.ibm.com, oleg@tv-sign.ru, srostedt@redhat.com +Subject: [PATCH RFC 3/9] RCU: Preemptible RCU + +Work in progress, not for inclusion. + +This patch implements a new version of RCU which allows its read-side +critical sections to be preempted. It uses a set of counter pairs +to keep track of the read-side critical sections and flips them +when all tasks exit read-side critical section. The details +of this implementation can be found in this paper - + +http://www.rdrop.com/users/paulmck/RCU/OLSrtRCU.2006.08.11a.pdf + +This patch was developed as a part of the -rt kernel development and +meant to provide better latencies when read-side critical sections of +RCU don't disable preemption. As a consequence of keeping track of RCU +readers, the readers have a slight overhead (optimizations in the paper). +This implementation co-exists with the "classic" RCU implementations +and can be switched to at compiler. + +Also includes RCU tracing summarized in debugfs and RCU_SOFTIRQ for +the preemptible variant of RCU. + +Signed-off-by: Dipankar Sarma +Signed-off-by: Steven Rostedt (for RCU_SOFTIRQ) +Signed-off-by: Paul McKenney +--- + + include/linux/interrupt.h | 1 + include/linux/rcuclassic.h | 2 + include/linux/rcupdate.h | 7 + include/linux/rcupreempt.h | 78 +++ + include/linux/rcupreempt_trace.h | 100 +++++ + include/linux/sched.h | 5 + kernel/Kconfig.preempt | 39 + + kernel/Makefile | 7 + kernel/fork.c | 4 + kernel/rcupreempt.c | 766 +++++++++++++++++++++++++++++++++++++++ + kernel/rcupreempt_trace.c | 330 ++++++++++++++++ + 11 files changed, 1336 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/interrupt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/interrupt.h 2009-02-08 00:00:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/interrupt.h 2009-02-08 00:01:39.000000000 -0500 +@@ -256,6 +256,7 @@ enum + #ifdef CONFIG_HIGH_RES_TIMERS + HRTIMER_SOFTIRQ, + #endif ++ RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ + }; + + /* softirq mask and active fields moved to irq_cpustat_t in +Index: linux-2.6.24.7-rt27/include/linux/rcuclassic.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcuclassic.h 2009-02-08 00:01:38.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcuclassic.h 2009-02-08 00:01:39.000000000 -0500 +@@ -142,8 +142,6 @@ extern int rcu_needs_cpu(int cpu); + extern void __rcu_init(void); + extern void rcu_check_callbacks(int cpu, int user); + extern void rcu_restart_cpu(int cpu); +-extern long rcu_batches_completed(void); +-extern long rcu_batches_completed_bh(void); + + #endif /* __KERNEL__ */ + #endif /* __LINUX_RCUCLASSIC_H */ +Index: linux-2.6.24.7-rt27/include/linux/rcupdate.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupdate.h 2009-02-08 00:01:38.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupdate.h 2009-02-08 00:01:39.000000000 -0500 +@@ -53,7 +53,11 @@ struct rcu_head { + void (*func)(struct rcu_head *head); + }; + ++#ifdef CONFIG_CLASSIC_RCU + #include ++#else /* #ifdef CONFIG_CLASSIC_RCU */ ++#include ++#endif /* #else #ifdef CONFIG_CLASSIC_RCU */ + + #define RCU_HEAD_INIT { .next = NULL, .func = NULL } + #define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT +@@ -241,10 +245,13 @@ extern void FASTCALL(call_rcu_bh(struct + /* Exported common interfaces */ + extern void synchronize_rcu(void); + extern void rcu_barrier(void); ++extern long rcu_batches_completed(void); ++extern long rcu_batches_completed_bh(void); + + /* Internal to kernel */ + extern void rcu_init(void); + extern void rcu_check_callbacks(int cpu, int user); ++extern int rcu_needs_cpu(int cpu); + + #endif /* __KERNEL__ */ + #endif /* __LINUX_RCUPDATE_H */ +Index: linux-2.6.24.7-rt27/include/linux/rcupreempt.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/include/linux/rcupreempt.h 2009-02-08 00:01:39.000000000 -0500 +@@ -0,0 +1,78 @@ ++/* ++ * Read-Copy Update mechanism for mutual exclusion (RT implementation) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) IBM Corporation, 2006 ++ * ++ * Author: Paul McKenney ++ * ++ * Based on the original work by Paul McKenney ++ * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. ++ * Papers: ++ * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf ++ * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) ++ * ++ * For detailed explanation of Read-Copy Update mechanism see - ++ * Documentation/RCU ++ * ++ */ ++ ++#ifndef __LINUX_RCUPREEMPT_H ++#define __LINUX_RCUPREEMPT_H ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define rcu_qsctr_inc(cpu) ++#define rcu_bh_qsctr_inc(cpu) ++#define call_rcu_bh(head, rcu) call_rcu(head, rcu) ++ ++extern void __rcu_read_lock(void); ++extern void __rcu_read_unlock(void); ++extern int rcu_pending(int cpu); ++extern int rcu_needs_cpu(int cpu); ++ ++#define __rcu_read_lock_bh() { rcu_read_lock(); local_bh_disable(); } ++#define __rcu_read_unlock_bh() { local_bh_enable(); rcu_read_unlock(); } ++ ++#define __rcu_read_lock_nesting() (current->rcu_read_lock_nesting) ++ ++extern void __synchronize_sched(void); ++ ++extern void __rcu_init(void); ++extern void rcu_check_callbacks(int cpu, int user); ++extern void rcu_restart_cpu(int cpu); ++ ++#ifdef CONFIG_RCU_TRACE ++struct rcupreempt_trace; ++extern int *rcupreempt_flipctr(int cpu); ++extern long rcupreempt_data_completed(void); ++extern int rcupreempt_flip_flag(int cpu); ++extern int rcupreempt_mb_flag(int cpu); ++extern char *rcupreempt_try_flip_state_name(void); ++extern struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu); ++#endif ++ ++struct softirq_action; ++ ++#endif /* __KERNEL__ */ ++#endif /* __LINUX_RCUPREEMPT_H */ +Index: linux-2.6.24.7-rt27/include/linux/rcupreempt_trace.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/include/linux/rcupreempt_trace.h 2009-02-08 00:01:39.000000000 -0500 +@@ -0,0 +1,100 @@ ++/* ++ * Read-Copy Update mechanism for mutual exclusion (RT implementation) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) IBM Corporation, 2006 ++ * ++ * Author: Paul McKenney ++ * ++ * Based on the original work by Paul McKenney ++ * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. ++ * Papers: ++ * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf ++ * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) ++ * ++ * For detailed explanation of Read-Copy Update mechanism see - ++ * http://lse.sourceforge.net/locking/rcupdate.html ++ * ++ */ ++ ++#ifndef __LINUX_RCUPREEMPT_TRACE_H ++#define __LINUX_RCUPREEMPT_TRACE_H ++ ++#ifdef __KERNEL__ ++#include ++#include ++ ++#include ++ ++/* ++ * PREEMPT_RCU data structures. ++ */ ++ ++struct rcupreempt_trace { ++ long next_length; ++ long next_add; ++ long wait_length; ++ long wait_add; ++ long done_length; ++ long done_add; ++ long done_remove; ++ atomic_t done_invoked; ++ long rcu_check_callbacks; ++ atomic_t rcu_try_flip_1; ++ atomic_t rcu_try_flip_e1; ++ long rcu_try_flip_i1; ++ long rcu_try_flip_ie1; ++ long rcu_try_flip_g1; ++ long rcu_try_flip_a1; ++ long rcu_try_flip_ae1; ++ long rcu_try_flip_a2; ++ long rcu_try_flip_z1; ++ long rcu_try_flip_ze1; ++ long rcu_try_flip_z2; ++ long rcu_try_flip_m1; ++ long rcu_try_flip_me1; ++ long rcu_try_flip_m2; ++}; ++ ++#ifdef CONFIG_RCU_TRACE ++#define RCU_TRACE(fn, arg) fn(arg); ++#else ++#define RCU_TRACE(fn, arg) ++#endif ++ ++extern void rcupreempt_trace_move2done(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_1(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_i1(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_ie1(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_g1(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_a1(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_ae1(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_a2(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_z1(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_ze1(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_z2(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_m1(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_me1(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_try_flip_m2(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_invoke(struct rcupreempt_trace *trace); ++extern void rcupreempt_trace_next_add(struct rcupreempt_trace *trace); ++ ++#endif /* __KERNEL__ */ ++#endif /* __LINUX_RCUPREEMPT_TRACE_H */ +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:01:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:01:39.000000000 -0500 +@@ -976,6 +976,11 @@ struct task_struct { + int nr_cpus_allowed; + unsigned int time_slice; + ++#ifdef CONFIG_PREEMPT_RCU ++ int rcu_read_lock_nesting; ++ int rcu_flipctr_idx; ++#endif /* #ifdef CONFIG_PREEMPT_RCU */ ++ + #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) + struct sched_info sched_info; + #endif +Index: linux-2.6.24.7-rt27/kernel/Kconfig.preempt +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/Kconfig.preempt 2009-02-08 00:00:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/Kconfig.preempt 2009-02-08 00:01:39.000000000 -0500 +@@ -52,6 +52,45 @@ config PREEMPT + + endchoice + ++choice ++ prompt "RCU implementation type:" ++ default CLASSIC_RCU ++ ++config CLASSIC_RCU ++ bool "Classic RCU" ++ help ++ This option selects the classic RCU implementation that is ++ designed for best read-side performance on non-realtime ++ systems. ++ ++ Say Y if you are unsure. ++ ++config PREEMPT_RCU ++ bool "Preemptible RCU" ++ depends on PREEMPT ++ help ++ This option reduces the latency of the kernel by making certain ++ RCU sections preemptible. Normally RCU code is non-preemptible, if ++ this option is selected then read-only RCU sections become ++ preemptible. This helps latency, but may expose bugs due to ++ now-naive assumptions about each RCU read-side critical section ++ remaining on a given CPU through its execution. ++ ++ Say N if you are unsure. ++ ++endchoice ++ ++config RCU_TRACE ++ bool "Enable tracing for RCU - currently stats in debugfs" ++ select DEBUG_FS ++ default y ++ help ++ This option provides tracing in RCU which presents stats ++ in debugfs for debugging RCU implementation. ++ ++ Say Y here if you want to enable RCU tracing ++ Say N if you are unsure. ++ + config PREEMPT_BKL + bool "Preempt The Big Kernel Lock" + depends on SMP || PREEMPT +Index: linux-2.6.24.7-rt27/kernel/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/Makefile 2009-02-08 00:01:38.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/Makefile 2009-02-08 00:01:39.000000000 -0500 +@@ -6,7 +6,7 @@ obj-y = sched.o fork.o exec_domain.o + exit.o itimer.o time.o softirq.o resource.o \ + sysctl.o capability.o ptrace.o timer.o user.o user_namespace.o \ + signal.o sys.o kmod.o workqueue.o pid.o \ +- rcupdate.o rcuclassic.o extable.o params.o posix-timers.o \ ++ rcupdate.o extable.o params.o posix-timers.o \ + kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ + hrtimer.o rwsem.o latency.o nsproxy.o srcu.o \ + utsname.o notifier.o +@@ -64,6 +64,11 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softl + obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ + obj-$(CONFIG_SECCOMP) += seccomp.o + obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o ++obj-$(CONFIG_CLASSIC_RCU) += rcuclassic.o ++obj-$(CONFIG_PREEMPT_RCU) += rcupreempt.o ++ifeq ($(CONFIG_PREEMPT_RCU),y) ++obj-$(CONFIG_RCU_TRACE) += rcupreempt_trace.o ++endif + obj-$(CONFIG_RELAY) += relay.o + obj-$(CONFIG_SYSCTL) += utsname_sysctl.o + obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o +Index: linux-2.6.24.7-rt27/kernel/fork.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/fork.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/fork.c 2009-02-08 00:01:39.000000000 -0500 +@@ -1045,6 +1045,10 @@ static struct task_struct *copy_process( + copy_flags(clone_flags, p); + INIT_LIST_HEAD(&p->children); + INIT_LIST_HEAD(&p->sibling); ++#ifdef CONFIG_PREEMPT_RCU ++ p->rcu_read_lock_nesting = 0; ++ p->rcu_flipctr_idx = 0; ++#endif /* #ifdef CONFIG_PREEMPT_RCU */ + p->vfork_done = NULL; + spin_lock_init(&p->alloc_lock); + +Index: linux-2.6.24.7-rt27/kernel/rcupreempt.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt.c 2009-02-08 00:01:39.000000000 -0500 +@@ -0,0 +1,766 @@ ++/* ++ * Read-Copy Update mechanism for mutual exclusion, realtime implementation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright IBM Corporation, 2006 ++ * ++ * Authors: Paul E. McKenney ++ * With thanks to Esben Nielsen, Bill Huey, and Ingo Molnar ++ * for pushing me away from locks and towards counters, and ++ * to Suparna Bhattacharya for pushing me completely away ++ * from atomic instructions on the read side. ++ * ++ * Papers: http://www.rdrop.com/users/paulmck/RCU ++ * ++ * For detailed explanation of Read-Copy Update mechanism see - ++ * Documentation/RCU/ *.txt ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * PREEMPT_RCU data structures. ++ */ ++ ++#define GP_STAGES 2 ++struct rcu_data { ++ spinlock_t lock; /* Protect rcu_data fields. */ ++ long completed; /* Number of last completed batch. */ ++ int waitlistcount; ++ struct tasklet_struct rcu_tasklet; ++ struct rcu_head *nextlist; ++ struct rcu_head **nexttail; ++ struct rcu_head *waitlist[GP_STAGES]; ++ struct rcu_head **waittail[GP_STAGES]; ++ struct rcu_head *donelist; ++ struct rcu_head **donetail; ++#ifdef CONFIG_RCU_TRACE ++ struct rcupreempt_trace trace; ++#endif /* #ifdef CONFIG_RCU_TRACE */ ++}; ++struct rcu_ctrlblk { ++ spinlock_t fliplock; /* Protect state-machine transitions. */ ++ long completed; /* Number of last completed batch. */ ++}; ++static DEFINE_PER_CPU(struct rcu_data, rcu_data); ++static struct rcu_ctrlblk rcu_ctrlblk = { ++ .fliplock = SPIN_LOCK_UNLOCKED, ++ .completed = 0, ++}; ++static DEFINE_PER_CPU(int [2], rcu_flipctr) = { 0, 0 }; ++ ++/* ++ * States for rcu_try_flip() and friends. ++ */ ++ ++enum rcu_try_flip_states { ++ rcu_try_flip_idle_state, /* "I" */ ++ rcu_try_flip_waitack_state, /* "A" */ ++ rcu_try_flip_waitzero_state, /* "Z" */ ++ rcu_try_flip_waitmb_state /* "M" */ ++}; ++static enum rcu_try_flip_states rcu_try_flip_state = rcu_try_flip_idle_state; ++#ifdef CONFIG_RCU_TRACE ++static char *rcu_try_flip_state_names[] = ++ { "idle", "waitack", "waitzero", "waitmb" }; ++#endif /* #ifdef CONFIG_RCU_TRACE */ ++ ++/* ++ * Enum and per-CPU flag to determine when each CPU has seen ++ * the most recent counter flip. ++ */ ++ ++enum rcu_flip_flag_values { ++ rcu_flip_seen, /* Steady/initial state, last flip seen. */ ++ /* Only GP detector can update. */ ++ rcu_flipped /* Flip just completed, need confirmation. */ ++ /* Only corresponding CPU can update. */ ++}; ++static DEFINE_PER_CPU(enum rcu_flip_flag_values, rcu_flip_flag) = rcu_flip_seen; ++ ++/* ++ * Enum and per-CPU flag to determine when each CPU has executed the ++ * needed memory barrier to fence in memory references from its last RCU ++ * read-side critical section in the just-completed grace period. ++ */ ++ ++enum rcu_mb_flag_values { ++ rcu_mb_done, /* Steady/initial state, no mb()s required. */ ++ /* Only GP detector can update. */ ++ rcu_mb_needed /* Flip just completed, need an mb(). */ ++ /* Only corresponding CPU can update. */ ++}; ++static DEFINE_PER_CPU(enum rcu_mb_flag_values, rcu_mb_flag) = rcu_mb_done; ++ ++/* ++ * Macro that prevents the compiler from reordering accesses, but does ++ * absolutely -nothing- to prevent CPUs from reordering. This is used ++ * only to mediate communication between mainline code and hardware ++ * interrupt and NMI handlers. ++ */ ++#define ORDERED_WRT_IRQ(x) (*(volatile typeof(x) *)&(x)) ++ ++/* ++ * RCU_DATA_ME: find the current CPU's rcu_data structure. ++ * RCU_DATA_CPU: find the specified CPU's rcu_data structure. ++ */ ++#define RCU_DATA_ME() (&__get_cpu_var(rcu_data)) ++#define RCU_DATA_CPU(cpu) (&per_cpu(rcu_data, cpu)) ++ ++/* ++ * Helper macro for tracing when the appropriate rcu_data is not ++ * cached in a local variable, but where the CPU number is so cached. ++ */ ++#define RCU_TRACE_CPU(f, cpu) RCU_TRACE(f, &(RCU_DATA_CPU(cpu)->trace)); ++ ++/* ++ * Helper macro for tracing when the appropriate rcu_data is not ++ * cached in a local variable. ++ */ ++#define RCU_TRACE_ME(f) RCU_TRACE(f, &(RCU_DATA_ME()->trace)); ++ ++/* ++ * Helper macro for tracing when the appropriate rcu_data is pointed ++ * to by a local variable. ++ */ ++#define RCU_TRACE_RDP(f, rdp) RCU_TRACE(f, &((rdp)->trace)); ++ ++/* ++ * Return the number of RCU batches processed thus far. Useful ++ * for debug and statistics. ++ */ ++long rcu_batches_completed(void) ++{ ++ return rcu_ctrlblk.completed; ++} ++EXPORT_SYMBOL_GPL(rcu_batches_completed); ++ ++/* ++ * Return the number of RCU batches processed thus far. Useful for debug ++ * and statistics. The _bh variant is identical to straight RCU. ++ */ ++long rcu_batches_completed_bh(void) ++{ ++ return rcu_ctrlblk.completed; ++} ++EXPORT_SYMBOL_GPL(rcu_batches_completed_bh); ++ ++void __rcu_read_lock(void) ++{ ++ int idx; ++ struct task_struct *me = current; ++ int nesting; ++ ++ nesting = ORDERED_WRT_IRQ(me->rcu_read_lock_nesting); ++ if (nesting != 0) { ++ ++ /* An earlier rcu_read_lock() covers us, just count it. */ ++ ++ me->rcu_read_lock_nesting = nesting + 1; ++ ++ } else { ++ unsigned long oldirq; ++ ++ /* ++ * Disable local interrupts to prevent the grace-period ++ * detection state machine from seeing us half-done. ++ * NMIs can still occur, of course, and might themselves ++ * contain rcu_read_lock(). ++ */ ++ ++ local_irq_save(oldirq); ++ ++ /* ++ * Outermost nesting of rcu_read_lock(), so increment ++ * the current counter for the current CPU. Use volatile ++ * casts to prevent the compiler from reordering. ++ */ ++ ++ idx = ORDERED_WRT_IRQ(rcu_ctrlblk.completed) & 0x1; ++ smp_read_barrier_depends(); /* @@@@ might be unneeded */ ++ ORDERED_WRT_IRQ(__get_cpu_var(rcu_flipctr)[idx])++; ++ ++ /* ++ * Now that the per-CPU counter has been incremented, we ++ * are protected from races with rcu_read_lock() invoked ++ * from NMI handlers on this CPU. We can therefore safely ++ * increment the nesting counter, relieving further NMIs ++ * of the need to increment the per-CPU counter. ++ */ ++ ++ ORDERED_WRT_IRQ(me->rcu_read_lock_nesting) = nesting + 1; ++ ++ /* ++ * Now that we have preventing any NMIs from storing ++ * to the ->rcu_flipctr_idx, we can safely use it to ++ * remember which counter to decrement in the matching ++ * rcu_read_unlock(). ++ */ ++ ++ ORDERED_WRT_IRQ(me->rcu_flipctr_idx) = idx; ++ local_irq_restore(oldirq); ++ } ++} ++EXPORT_SYMBOL_GPL(__rcu_read_lock); ++ ++void __rcu_read_unlock(void) ++{ ++ int idx; ++ struct task_struct *me = current; ++ int nesting; ++ ++ nesting = ORDERED_WRT_IRQ(me->rcu_read_lock_nesting); ++ if (nesting > 1) { ++ ++ /* ++ * We are still protected by the enclosing rcu_read_lock(), ++ * so simply decrement the counter. ++ */ ++ ++ me->rcu_read_lock_nesting = nesting - 1; ++ ++ } else { ++ unsigned long oldirq; ++ ++ /* ++ * Disable local interrupts to prevent the grace-period ++ * detection state machine from seeing us half-done. ++ * NMIs can still occur, of course, and might themselves ++ * contain rcu_read_lock() and rcu_read_unlock(). ++ */ ++ ++ local_irq_save(oldirq); ++ ++ /* ++ * Outermost nesting of rcu_read_unlock(), so we must ++ * decrement the current counter for the current CPU. ++ * This must be done carefully, because NMIs can ++ * occur at any point in this code, and any rcu_read_lock() ++ * and rcu_read_unlock() pairs in the NMI handlers ++ * must interact non-destructively with this code. ++ * Lots of volatile casts, and -very- careful ordering. ++ * ++ * Changes to this code, including this one, must be ++ * inspected, validated, and tested extremely carefully!!! ++ */ ++ ++ /* ++ * First, pick up the index. Enforce ordering for ++ * DEC Alpha. ++ */ ++ ++ idx = ORDERED_WRT_IRQ(me->rcu_flipctr_idx); ++ smp_read_barrier_depends(); /* @@@ Needed??? */ ++ ++ /* ++ * Now that we have fetched the counter index, it is ++ * safe to decrement the per-task RCU nesting counter. ++ * After this, any interrupts or NMIs will increment and ++ * decrement the per-CPU counters. ++ */ ++ ORDERED_WRT_IRQ(me->rcu_read_lock_nesting) = nesting - 1; ++ ++ /* ++ * It is now safe to decrement this task's nesting count. ++ * NMIs that occur after this statement will route their ++ * rcu_read_lock() calls through this "else" clause, and ++ * will thus start incrementing the per-CPU coutner on ++ * their own. They will also clobber ->rcu_flipctr_idx, ++ * but that is OK, since we have already fetched it. ++ */ ++ ++ ORDERED_WRT_IRQ(__get_cpu_var(rcu_flipctr)[idx])--; ++ local_irq_restore(oldirq); ++ } ++} ++EXPORT_SYMBOL_GPL(__rcu_read_unlock); ++ ++/* ++ * If a global counter flip has occurred since the last time that we ++ * advanced callbacks, advance them. Hardware interrupts must be ++ * disabled when calling this function. ++ */ ++static void __rcu_advance_callbacks(struct rcu_data *rdp) ++{ ++ int cpu; ++ int i; ++ int wlc = 0; ++ ++ if (rdp->completed != rcu_ctrlblk.completed) { ++ if (rdp->waitlist[GP_STAGES - 1] != NULL) { ++ *rdp->donetail = rdp->waitlist[GP_STAGES - 1]; ++ rdp->donetail = rdp->waittail[GP_STAGES - 1]; ++ RCU_TRACE_RDP(rcupreempt_trace_move2done, rdp); ++ } ++ for (i = GP_STAGES - 2; i >= 0; i--) { ++ if (rdp->waitlist[i] != NULL) { ++ rdp->waitlist[i + 1] = rdp->waitlist[i]; ++ rdp->waittail[i + 1] = rdp->waittail[i]; ++ wlc++; ++ } else { ++ rdp->waitlist[i + 1] = NULL; ++ rdp->waittail[i + 1] = ++ &rdp->waitlist[i + 1]; ++ } ++ } ++ if (rdp->nextlist != NULL) { ++ rdp->waitlist[0] = rdp->nextlist; ++ rdp->waittail[0] = rdp->nexttail; ++ wlc++; ++ rdp->nextlist = NULL; ++ rdp->nexttail = &rdp->nextlist; ++ RCU_TRACE_RDP(rcupreempt_trace_move2wait, rdp); ++ } else { ++ rdp->waitlist[0] = NULL; ++ rdp->waittail[0] = &rdp->waitlist[0]; ++ } ++ rdp->waitlistcount = wlc; ++ rdp->completed = rcu_ctrlblk.completed; ++ } ++ ++ /* ++ * Check to see if this CPU needs to report that it has seen ++ * the most recent counter flip, thereby declaring that all ++ * subsequent rcu_read_lock() invocations will respect this flip. ++ */ ++ ++ cpu = raw_smp_processor_id(); ++ if (per_cpu(rcu_flip_flag, cpu) == rcu_flipped) { ++ smp_mb(); /* Subsequent counter accesses must see new value */ ++ per_cpu(rcu_flip_flag, cpu) = rcu_flip_seen; ++ smp_mb(); /* Subsequent RCU read-side critical sections */ ++ /* seen -after- acknowledgement. */ ++ } ++} ++ ++/* ++ * Get here when RCU is idle. Decide whether we need to ++ * move out of idle state, and return non-zero if so. ++ * "Straightforward" approach for the moment, might later ++ * use callback-list lengths, grace-period duration, or ++ * some such to determine when to exit idle state. ++ * Might also need a pre-idle test that does not acquire ++ * the lock, but let's get the simple case working first... ++ */ ++ ++static int ++rcu_try_flip_idle(void) ++{ ++ int cpu; ++ ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_i1); ++ if (!rcu_pending(smp_processor_id())) { ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_ie1); ++ return 0; ++ } ++ ++ /* ++ * Do the flip. ++ */ ++ ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_g1); ++ rcu_ctrlblk.completed++; /* stands in for rcu_try_flip_g2 */ ++ ++ /* ++ * Need a memory barrier so that other CPUs see the new ++ * counter value before they see the subsequent change of all ++ * the rcu_flip_flag instances to rcu_flipped. ++ */ ++ ++ smp_mb(); /* see above block comment. */ ++ ++ /* Now ask each CPU for acknowledgement of the flip. */ ++ ++ for_each_possible_cpu(cpu) ++ per_cpu(rcu_flip_flag, cpu) = rcu_flipped; ++ ++ return 1; ++} ++ ++/* ++ * Wait for CPUs to acknowledge the flip. ++ */ ++ ++static int ++rcu_try_flip_waitack(void) ++{ ++ int cpu; ++ ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_a1); ++ for_each_possible_cpu(cpu) ++ if (per_cpu(rcu_flip_flag, cpu) != rcu_flip_seen) { ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_ae1); ++ return 0; ++ } ++ ++ /* ++ * Make sure our checks above don't bleed into subsequent ++ * waiting for the sum of the counters to reach zero. ++ */ ++ ++ smp_mb(); /* see above block comment. */ ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_a2); ++ return 1; ++} ++ ++/* ++ * Wait for collective ``last'' counter to reach zero, ++ * then tell all CPUs to do an end-of-grace-period memory barrier. ++ */ ++ ++static int ++rcu_try_flip_waitzero(void) ++{ ++ int cpu; ++ int lastidx = !(rcu_ctrlblk.completed & 0x1); ++ int sum = 0; ++ ++ /* Check to see if the sum of the "last" counters is zero. */ ++ ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_z1); ++ for_each_possible_cpu(cpu) ++ sum += per_cpu(rcu_flipctr, cpu)[lastidx]; ++ if (sum != 0) { ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_ze1); ++ return 0; ++ } ++ ++ smp_mb(); /* Don't call for memory barriers before we see zero. */ ++ ++ /* Call for a memory barrier from each CPU. */ ++ ++ for_each_possible_cpu(cpu) ++ per_cpu(rcu_mb_flag, cpu) = rcu_mb_needed; ++ ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_z2); ++ return 1; ++} ++ ++/* ++ * Wait for all CPUs to do their end-of-grace-period memory barrier. ++ * Return 0 once all CPUs have done so. ++ */ ++ ++static int ++rcu_try_flip_waitmb(void) ++{ ++ int cpu; ++ ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_m1); ++ for_each_possible_cpu(cpu) ++ if (per_cpu(rcu_mb_flag, cpu) != rcu_mb_done) { ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_me1); ++ return 0; ++ } ++ ++ smp_mb(); /* Ensure that the above checks precede any following flip. */ ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_m2); ++ return 1; ++} ++ ++/* ++ * Attempt a single flip of the counters. Remember, a single flip does ++ * -not- constitute a grace period. Instead, the interval between ++ * at least three consecutive flips is a grace period. ++ * ++ * If anyone is nuts enough to run this CONFIG_PREEMPT_RCU implementation ++ * on a large SMP, they might want to use a hierarchical organization of ++ * the per-CPU-counter pairs. ++ */ ++static void rcu_try_flip(void) ++{ ++ unsigned long oldirq; ++ ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_1); ++ if (unlikely(!spin_trylock_irqsave(&rcu_ctrlblk.fliplock, oldirq))) { ++ RCU_TRACE_ME(rcupreempt_trace_try_flip_e1); ++ return; ++ } ++ ++ /* ++ * Take the next transition(s) through the RCU grace-period ++ * flip-counter state machine. ++ */ ++ ++ switch (rcu_try_flip_state) { ++ case rcu_try_flip_idle_state: ++ if (rcu_try_flip_idle()) ++ rcu_try_flip_state = rcu_try_flip_waitack_state; ++ break; ++ case rcu_try_flip_waitack_state: ++ if (rcu_try_flip_waitack()) ++ rcu_try_flip_state = rcu_try_flip_waitzero_state; ++ break; ++ case rcu_try_flip_waitzero_state: ++ if (rcu_try_flip_waitzero()) ++ rcu_try_flip_state = rcu_try_flip_waitmb_state; ++ break; ++ case rcu_try_flip_waitmb_state: ++ if (rcu_try_flip_waitmb()) ++ rcu_try_flip_state = rcu_try_flip_idle_state; ++ } ++ spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, oldirq); ++} ++ ++/* ++ * Check to see if this CPU needs to do a memory barrier in order to ++ * ensure that any prior RCU read-side critical sections have committed ++ * their counter manipulations and critical-section memory references ++ * before declaring the grace period to be completed. ++ */ ++static void rcu_check_mb(int cpu) ++{ ++ if (per_cpu(rcu_mb_flag, cpu) == rcu_mb_needed) { ++ smp_mb(); /* Ensure RCU read-side accesses are visible. */ ++ per_cpu(rcu_mb_flag, cpu) = rcu_mb_done; ++ } ++} ++ ++void rcu_check_callbacks(int cpu, int user) ++{ ++ unsigned long oldirq; ++ struct rcu_data *rdp = RCU_DATA_CPU(cpu); ++ ++ rcu_check_mb(cpu); ++ if (rcu_ctrlblk.completed == rdp->completed) ++ rcu_try_flip(); ++ spin_lock_irqsave(&rdp->lock, oldirq); ++ RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp); ++ __rcu_advance_callbacks(rdp); ++ if (rdp->donelist == NULL) { ++ spin_unlock_irqrestore(&rdp->lock, oldirq); ++ } else { ++ spin_unlock_irqrestore(&rdp->lock, oldirq); ++ raise_softirq(RCU_SOFTIRQ); ++ } ++} ++ ++/* ++ * Needed by dynticks, to make sure all RCU processing has finished ++ * when we go idle: ++ */ ++void rcu_advance_callbacks(int cpu, int user) ++{ ++ unsigned long oldirq; ++ struct rcu_data *rdp = RCU_DATA_CPU(cpu); ++ ++ if (rcu_ctrlblk.completed == rdp->completed) { ++ rcu_try_flip(); ++ if (rcu_ctrlblk.completed == rdp->completed) ++ return; ++ } ++ spin_lock_irqsave(&rdp->lock, oldirq); ++ RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp); ++ __rcu_advance_callbacks(rdp); ++ spin_unlock_irqrestore(&rdp->lock, oldirq); ++} ++ ++static void rcu_process_callbacks(struct softirq_action *unused) ++{ ++ unsigned long flags; ++ struct rcu_head *next, *list; ++ struct rcu_data *rdp = RCU_DATA_ME(); ++ ++ spin_lock_irqsave(&rdp->lock, flags); ++ list = rdp->donelist; ++ if (list == NULL) { ++ spin_unlock_irqrestore(&rdp->lock, flags); ++ return; ++ } ++ rdp->donelist = NULL; ++ rdp->donetail = &rdp->donelist; ++ RCU_TRACE_RDP(rcupreempt_trace_done_remove, rdp); ++ spin_unlock_irqrestore(&rdp->lock, flags); ++ while (list) { ++ next = list->next; ++ list->func(list); ++ list = next; ++ RCU_TRACE_ME(rcupreempt_trace_invoke); ++ } ++} ++ ++void fastcall call_rcu(struct rcu_head *head, ++ void (*func)(struct rcu_head *rcu)) ++{ ++ unsigned long oldirq; ++ struct rcu_data *rdp; ++ ++ head->func = func; ++ head->next = NULL; ++ local_irq_save(oldirq); ++ rdp = RCU_DATA_ME(); ++ spin_lock(&rdp->lock); ++ __rcu_advance_callbacks(rdp); ++ *rdp->nexttail = head; ++ rdp->nexttail = &head->next; ++ RCU_TRACE_RDP(rcupreempt_trace_next_add, rdp); ++ spin_unlock(&rdp->lock); ++ local_irq_restore(oldirq); ++} ++EXPORT_SYMBOL_GPL(call_rcu); ++ ++/* ++ * Wait until all currently running preempt_disable() code segments ++ * (including hardware-irq-disable segments) complete. Note that ++ * in -rt this does -not- necessarily result in all currently executing ++ * interrupt -handlers- having completed. ++ */ ++void __synchronize_sched(void) ++{ ++ cpumask_t oldmask; ++ int cpu; ++ ++ if (sched_getaffinity(0, &oldmask) < 0) ++ oldmask = cpu_possible_map; ++ for_each_online_cpu(cpu) { ++ sched_setaffinity(0, cpumask_of_cpu(cpu)); ++ schedule(); ++ } ++ sched_setaffinity(0, oldmask); ++} ++EXPORT_SYMBOL_GPL(__synchronize_sched); ++ ++/* ++ * Check to see if any future RCU-related work will need to be done ++ * by the current CPU, even if none need be done immediately, returning ++ * 1 if so. Assumes that notifiers would take care of handling any ++ * outstanding requests from the RCU core. ++ * ++ * This function is part of the RCU implementation; it is -not- ++ * an exported member of the RCU API. ++ */ ++int rcu_needs_cpu(int cpu) ++{ ++ struct rcu_data *rdp = RCU_DATA_CPU(cpu); ++ ++ return (rdp->donelist != NULL || ++ !!rdp->waitlistcount || ++ rdp->nextlist != NULL); ++} ++ ++int rcu_pending(int cpu) ++{ ++ struct rcu_data *rdp = RCU_DATA_CPU(cpu); ++ ++ /* The CPU has at least one callback queued somewhere. */ ++ ++ if (rdp->donelist != NULL || ++ !!rdp->waitlistcount || ++ rdp->nextlist != NULL) ++ return 1; ++ ++ /* The RCU core needs an acknowledgement from this CPU. */ ++ ++ if ((per_cpu(rcu_flip_flag, cpu) == rcu_flipped) || ++ (per_cpu(rcu_mb_flag, cpu) == rcu_mb_needed)) ++ return 1; ++ ++ /* This CPU has fallen behind the global grace-period number. */ ++ ++ if (rdp->completed != rcu_ctrlblk.completed) ++ return 1; ++ ++ /* Nothing needed from this CPU. */ ++ ++ return 0; ++} ++ ++void __init __rcu_init(void) ++{ ++ int cpu; ++ int i; ++ struct rcu_data *rdp; ++ ++ for_each_possible_cpu(cpu) { ++ rdp = RCU_DATA_CPU(cpu); ++ spin_lock_init(&rdp->lock); ++ rdp->completed = 0; ++ rdp->waitlistcount = 0; ++ rdp->nextlist = NULL; ++ rdp->nexttail = &rdp->nextlist; ++ for (i = 0; i < GP_STAGES; i++) { ++ rdp->waitlist[i] = NULL; ++ rdp->waittail[i] = &rdp->waitlist[i]; ++ } ++ rdp->donelist = NULL; ++ rdp->donetail = &rdp->donelist; ++ } ++ open_softirq(RCU_SOFTIRQ, rcu_process_callbacks, NULL); ++} ++ ++/* ++ * Deprecated, use synchronize_rcu() or synchronize_sched() instead. ++ */ ++void synchronize_kernel(void) ++{ ++ synchronize_rcu(); ++} ++ ++#ifdef CONFIG_RCU_TRACE ++int *rcupreempt_flipctr(int cpu) ++{ ++ return &per_cpu(rcu_flipctr, cpu)[0]; ++} ++EXPORT_SYMBOL_GPL(rcupreempt_flipctr); ++ ++int rcupreempt_flip_flag(int cpu) ++{ ++ return per_cpu(rcu_flip_flag, cpu); ++} ++EXPORT_SYMBOL_GPL(rcupreempt_flip_flag); ++ ++int rcupreempt_mb_flag(int cpu) ++{ ++ return per_cpu(rcu_mb_flag, cpu); ++} ++EXPORT_SYMBOL_GPL(rcupreempt_mb_flag); ++ ++char *rcupreempt_try_flip_state_name(void) ++{ ++ return rcu_try_flip_state_names[rcu_try_flip_state]; ++} ++EXPORT_SYMBOL_GPL(rcupreempt_try_flip_state_name); ++ ++struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu) ++{ ++ struct rcu_data *rdp = RCU_DATA_CPU(cpu); ++ ++ return &rdp->trace; ++} ++EXPORT_SYMBOL_GPL(rcupreempt_trace_cpu); ++ ++#endif /* #ifdef RCU_TRACE */ +Index: linux-2.6.24.7-rt27/kernel/rcupreempt_trace.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt_trace.c 2009-02-08 00:01:39.000000000 -0500 +@@ -0,0 +1,330 @@ ++/* ++ * Read-Copy Update tracing for realtime implementation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright IBM Corporation, 2006 ++ * ++ * Papers: http://www.rdrop.com/users/paulmck/RCU ++ * ++ * For detailed explanation of Read-Copy Update mechanism see - ++ * Documentation/RCU/ *.txt ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct mutex rcupreempt_trace_mutex; ++static char *rcupreempt_trace_buf; ++#define RCUPREEMPT_TRACE_BUF_SIZE 4096 ++ ++void rcupreempt_trace_move2done(struct rcupreempt_trace *trace) ++{ ++ trace->done_length += trace->wait_length; ++ trace->done_add += trace->wait_length; ++ trace->wait_length = 0; ++} ++void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace) ++{ ++ trace->wait_length += trace->next_length; ++ trace->wait_add += trace->next_length; ++ trace->next_length = 0; ++} ++void rcupreempt_trace_try_flip_1(struct rcupreempt_trace *trace) ++{ ++ atomic_inc(&trace->rcu_try_flip_1); ++} ++void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace) ++{ ++ atomic_inc(&trace->rcu_try_flip_e1); ++} ++void rcupreempt_trace_try_flip_i1(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_try_flip_i1++; ++} ++void rcupreempt_trace_try_flip_ie1(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_try_flip_ie1++; ++} ++void rcupreempt_trace_try_flip_g1(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_try_flip_g1++; ++} ++void rcupreempt_trace_try_flip_a1(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_try_flip_a1++; ++} ++void rcupreempt_trace_try_flip_ae1(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_try_flip_ae1++; ++} ++void rcupreempt_trace_try_flip_a2(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_try_flip_a2++; ++} ++void rcupreempt_trace_try_flip_z1(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_try_flip_z1++; ++} ++void rcupreempt_trace_try_flip_ze1(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_try_flip_ze1++; ++} ++void rcupreempt_trace_try_flip_z2(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_try_flip_z2++; ++} ++void rcupreempt_trace_try_flip_m1(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_try_flip_m1++; ++} ++void rcupreempt_trace_try_flip_me1(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_try_flip_me1++; ++} ++void rcupreempt_trace_try_flip_m2(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_try_flip_m2++; ++} ++void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace) ++{ ++ trace->rcu_check_callbacks++; ++} ++void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace) ++{ ++ trace->done_remove += trace->done_length; ++ trace->done_length = 0; ++} ++void rcupreempt_trace_invoke(struct rcupreempt_trace *trace) ++{ ++ atomic_inc(&trace->done_invoked); ++} ++void rcupreempt_trace_next_add(struct rcupreempt_trace *trace) ++{ ++ trace->next_add++; ++ trace->next_length++; ++} ++ ++static void rcupreempt_trace_sum(struct rcupreempt_trace *sp) ++{ ++ struct rcupreempt_trace *cp; ++ int cpu; ++ ++ memset(sp, 0, sizeof(*sp)); ++ for_each_possible_cpu(cpu) { ++ cp = rcupreempt_trace_cpu(cpu); ++ sp->next_length += cp->next_length; ++ sp->next_add += cp->next_add; ++ sp->wait_length += cp->wait_length; ++ sp->wait_add += cp->wait_add; ++ sp->done_length += cp->done_length; ++ sp->done_add += cp->done_add; ++ sp->done_remove += cp->done_remove; ++ atomic_set(&sp->done_invoked, atomic_read(&cp->done_invoked)); ++ sp->rcu_check_callbacks += cp->rcu_check_callbacks; ++ atomic_set(&sp->rcu_try_flip_1, ++ atomic_read(&cp->rcu_try_flip_1)); ++ atomic_set(&sp->rcu_try_flip_e1, ++ atomic_read(&cp->rcu_try_flip_e1)); ++ sp->rcu_try_flip_i1 += cp->rcu_try_flip_i1; ++ sp->rcu_try_flip_ie1 += cp->rcu_try_flip_ie1; ++ sp->rcu_try_flip_g1 += cp->rcu_try_flip_g1; ++ sp->rcu_try_flip_a1 += cp->rcu_try_flip_a1; ++ sp->rcu_try_flip_ae1 += cp->rcu_try_flip_ae1; ++ sp->rcu_try_flip_a2 += cp->rcu_try_flip_a2; ++ sp->rcu_try_flip_z1 += cp->rcu_try_flip_z1; ++ sp->rcu_try_flip_ze1 += cp->rcu_try_flip_ze1; ++ sp->rcu_try_flip_z2 += cp->rcu_try_flip_z2; ++ sp->rcu_try_flip_m1 += cp->rcu_try_flip_m1; ++ sp->rcu_try_flip_me1 += cp->rcu_try_flip_me1; ++ sp->rcu_try_flip_m2 += cp->rcu_try_flip_m2; ++ } ++} ++ ++static ssize_t rcustats_read(struct file *filp, char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct rcupreempt_trace trace; ++ ssize_t bcount; ++ int cnt = 0; ++ ++ rcupreempt_trace_sum(&trace); ++ mutex_lock(&rcupreempt_trace_mutex); ++ snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt, ++ "ggp=%ld rcc=%ld\n", ++ rcu_batches_completed(), ++ trace.rcu_check_callbacks); ++ snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt, ++ "na=%ld nl=%ld wa=%ld wl=%ld da=%ld dl=%ld dr=%ld di=%d\n" ++ "1=%d e1=%d i1=%ld ie1=%ld g1=%ld a1=%ld ae1=%ld a2=%ld\n" ++ "z1=%ld ze1=%ld z2=%ld m1=%ld me1=%ld m2=%ld\n", ++ ++ trace.next_add, trace.next_length, ++ trace.wait_add, trace.wait_length, ++ trace.done_add, trace.done_length, ++ trace.done_remove, atomic_read(&trace.done_invoked), ++ atomic_read(&trace.rcu_try_flip_1), ++ atomic_read(&trace.rcu_try_flip_e1), ++ trace.rcu_try_flip_i1, trace.rcu_try_flip_ie1, ++ trace.rcu_try_flip_g1, ++ trace.rcu_try_flip_a1, trace.rcu_try_flip_ae1, ++ trace.rcu_try_flip_a2, ++ trace.rcu_try_flip_z1, trace.rcu_try_flip_ze1, ++ trace.rcu_try_flip_z2, ++ trace.rcu_try_flip_m1, trace.rcu_try_flip_me1, ++ trace.rcu_try_flip_m2); ++ bcount = simple_read_from_buffer(buffer, count, ppos, ++ rcupreempt_trace_buf, strlen(rcupreempt_trace_buf)); ++ mutex_unlock(&rcupreempt_trace_mutex); ++ return bcount; ++} ++ ++static ssize_t rcugp_read(struct file *filp, char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ long oldgp = rcu_batches_completed(); ++ ssize_t bcount; ++ ++ mutex_lock(&rcupreempt_trace_mutex); ++ synchronize_rcu(); ++ snprintf(rcupreempt_trace_buf, RCUPREEMPT_TRACE_BUF_SIZE, ++ "oldggp=%ld newggp=%ld\n", oldgp, rcu_batches_completed()); ++ bcount = simple_read_from_buffer(buffer, count, ppos, ++ rcupreempt_trace_buf, strlen(rcupreempt_trace_buf)); ++ mutex_unlock(&rcupreempt_trace_mutex); ++ return bcount; ++} ++ ++static ssize_t rcuctrs_read(struct file *filp, char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ int cnt = 0; ++ int cpu; ++ int f = rcu_batches_completed() & 0x1; ++ ssize_t bcount; ++ ++ mutex_lock(&rcupreempt_trace_mutex); ++ ++ cnt += snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE, ++ "CPU last cur F M\n"); ++ for_each_online_cpu(cpu) { ++ int *flipctr = rcupreempt_flipctr(cpu); ++ cnt += snprintf(&rcupreempt_trace_buf[cnt], ++ RCUPREEMPT_TRACE_BUF_SIZE - cnt, ++ "%3d %4d %3d %d %d\n", ++ cpu, ++ flipctr[!f], ++ flipctr[f], ++ rcupreempt_flip_flag(cpu), ++ rcupreempt_mb_flag(cpu)); ++ } ++ cnt += snprintf(&rcupreempt_trace_buf[cnt], ++ RCUPREEMPT_TRACE_BUF_SIZE - cnt, ++ "ggp = %ld, state = %s\n", ++ rcu_batches_completed(), ++ rcupreempt_try_flip_state_name()); ++ cnt += snprintf(&rcupreempt_trace_buf[cnt], ++ RCUPREEMPT_TRACE_BUF_SIZE - cnt, ++ "\n"); ++ bcount = simple_read_from_buffer(buffer, count, ppos, ++ rcupreempt_trace_buf, strlen(rcupreempt_trace_buf)); ++ mutex_unlock(&rcupreempt_trace_mutex); ++ return bcount; ++} ++ ++static struct file_operations rcustats_fops = { ++ .owner = THIS_MODULE, ++ .read = rcustats_read, ++}; ++ ++static struct file_operations rcugp_fops = { ++ .owner = THIS_MODULE, ++ .read = rcugp_read, ++}; ++ ++static struct file_operations rcuctrs_fops = { ++ .owner = THIS_MODULE, ++ .read = rcuctrs_read, ++}; ++ ++static struct dentry *rcudir, *statdir, *ctrsdir, *gpdir; ++static int rcupreempt_debugfs_init(void) ++{ ++ rcudir = debugfs_create_dir("rcu", NULL); ++ if (!rcudir) ++ goto out; ++ statdir = debugfs_create_file("rcustats", 0444, rcudir, ++ NULL, &rcustats_fops); ++ if (!statdir) ++ goto free_out; ++ ++ gpdir = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops); ++ if (!gpdir) ++ goto free_out; ++ ++ ctrsdir = debugfs_create_file("rcuctrs", 0444, rcudir, ++ NULL, &rcuctrs_fops); ++ if (!ctrsdir) ++ goto free_out; ++ return 0; ++free_out: ++ if (statdir) ++ debugfs_remove(statdir); ++ if (gpdir) ++ debugfs_remove(gpdir); ++ debugfs_remove(rcudir); ++out: ++ return 1; ++} ++ ++static int __init rcupreempt_trace_init(void) ++{ ++ mutex_init(&rcupreempt_trace_mutex); ++ rcupreempt_trace_buf = kmalloc(RCUPREEMPT_TRACE_BUF_SIZE, GFP_KERNEL); ++ if (!rcupreempt_trace_buf) ++ return 1; ++ return rcupreempt_debugfs_init(); ++} ++ ++static void __exit rcupreempt_trace_cleanup(void) ++{ ++ debugfs_remove(statdir); ++ debugfs_remove(gpdir); ++ debugfs_remove(ctrsdir); ++ debugfs_remove(rcudir); ++ kfree(rcupreempt_trace_buf); ++} ++ ++ ++module_init(rcupreempt_trace_init); ++module_exit(rcupreempt_trace_cleanup); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0201-vortex-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0201-vortex-fix.patch @@ -0,0 +1,91 @@ + + +Argh, cut and paste wasn't enough... + +Use this patch instead. It needs an irq disable. But, believe it or not, +on SMP this is actually better. If the irq is shared (as it is in Mark's +case), we don't stop the irq of other devices from being handled on +another CPU (unfortunately for Mark, he pinned all interrupts to one CPU). + +Andrew, + +should this be changed in mainline too? + +-- Steve + +Signed-off-by: Steven Rostedt + + + drivers/net/3c59x.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/drivers/net/3c59x.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/net/3c59x.c 2009-02-08 00:00:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/net/3c59x.c 2009-02-08 00:02:18.000000000 -0500 +@@ -792,9 +792,9 @@ static void poll_vortex(struct net_devic + { + struct vortex_private *vp = netdev_priv(dev); + unsigned long flags; +- local_irq_save(flags); ++ local_irq_save_nort(flags); + (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev); +- local_irq_restore(flags); ++ local_irq_restore_nort(flags); + } + #endif + +@@ -1739,6 +1739,7 @@ vortex_timer(unsigned long data) + int next_tick = 60*HZ; + int ok = 0; + int media_status, old_window; ++ unsigned long flags; + + if (vortex_debug > 2) { + printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", +@@ -1746,7 +1747,7 @@ vortex_timer(unsigned long data) + printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo); + } + +- disable_irq_lockdep(dev->irq); ++ spin_lock_irqsave(&vp->lock, flags); + old_window = ioread16(ioaddr + EL3_CMD) >> 13; + EL3WINDOW(4); + media_status = ioread16(ioaddr + Wn4_Media); +@@ -1769,9 +1770,7 @@ vortex_timer(unsigned long data) + case XCVR_MII: case XCVR_NWAY: + { + ok = 1; +- spin_lock_bh(&vp->lock); + vortex_check_media(dev, 0); +- spin_unlock_bh(&vp->lock); + } + break; + default: /* Other media types handled by Tx timeouts. */ +@@ -1827,7 +1826,7 @@ leave_media_alone: + dev->name, media_tbl[dev->if_port].name); + + EL3WINDOW(old_window); +- enable_irq_lockdep(dev->irq); ++ spin_unlock_irqrestore(&vp->lock, flags); + mod_timer(&vp->timer, RUN_AT(next_tick)); + if (vp->deferred) + iowrite16(FakeIntr, ioaddr + EL3_CMD); +@@ -1860,13 +1859,17 @@ static void vortex_tx_timeout(struct net + /* + * Block interrupts because vortex_interrupt does a bare spin_lock() + */ ++#ifndef CONFIG_PREEMPT_RT + unsigned long flags; + local_irq_save(flags); ++#endif + if (vp->full_bus_master_tx) + boomerang_interrupt(dev->irq, dev); + else + vortex_interrupt(dev->irq, dev); ++#ifndef CONFIG_PREEMPT_RT + local_irq_restore(flags); ++#endif + } + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0168-rt-mutex-core.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0168-rt-mutex-core.patch @@ -0,0 +1,5609 @@ +--- + drivers/input/ff-memless.c | 1 + fs/proc/array.c | 28 + + include/linux/bit_spinlock.h | 4 + include/linux/init_task.h | 3 + include/linux/mutex.h | 57 ++ + include/linux/plist.h | 4 + include/linux/rt_lock.h | 334 +++++++++++++++ + include/linux/rtmutex.h | 4 + include/linux/rwsem-spinlock.h | 35 - + include/linux/rwsem.h | 108 ++++- + include/linux/sched.h | 75 ++- + include/linux/semaphore.h | 49 ++ + include/linux/seqlock.h | 195 ++++++++- + include/linux/spinlock.h | 804 +++++++++++++++++++++++++++++--------- + include/linux/spinlock_api_smp.h | 91 ++-- + include/linux/spinlock_api_up.h | 74 ++- + include/linux/spinlock_types.h | 61 ++ + include/linux/spinlock_types_up.h | 6 + include/linux/spinlock_up.h | 8 + kernel/Makefile | 6 + kernel/fork.c | 6 + kernel/futex.c | 4 + kernel/hrtimer.c | 4 + kernel/lockdep.c | 2 + kernel/rt.c | 571 ++++++++++++++++++++++++++ + kernel/rtmutex-debug.c | 108 +---- + kernel/rtmutex.c | 433 ++++++++++++++++++-- + kernel/rwsem.c | 44 +- + kernel/sched.c | 78 ++- + kernel/spinlock.c | 266 ++++++++---- + lib/dec_and_lock.c | 4 + lib/kernel_lock.c | 4 + lib/locking-selftest.c | 6 + lib/plist.c | 2 + lib/rwsem-spinlock.c | 29 - + lib/rwsem.c | 6 + lib/semaphore-sleepers.c | 16 + lib/spinlock_debug.c | 64 +-- + 38 files changed, 2919 insertions(+), 675 deletions(-) + +Index: linux-2.6.24.7-rt27/drivers/input/ff-memless.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/input/ff-memless.c 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/input/ff-memless.c 2009-02-08 00:02:01.000000000 -0500 +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + #include + #include + +Index: linux-2.6.24.7-rt27/fs/proc/array.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/proc/array.c 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/proc/array.c 2009-02-08 00:02:01.000000000 -0500 +@@ -131,17 +131,19 @@ static inline char *task_name(struct tas + */ + static const char *task_state_array[] = { + "R (running)", /* 0 */ +- "S (sleeping)", /* 1 */ +- "D (disk sleep)", /* 2 */ +- "T (stopped)", /* 4 */ +- "T (tracing stop)", /* 8 */ +- "Z (zombie)", /* 16 */ +- "X (dead)" /* 32 */ ++ "M (running-mutex)", /* 1 */ ++ "S (sleeping)", /* 2 */ ++ "D (disk sleep)", /* 4 */ ++ "T (stopped)", /* 8 */ ++ "T (tracing stop)", /* 16 */ ++ "Z (zombie)", /* 32 */ ++ "X (dead)" /* 64 */ + }; + + static inline const char *get_task_state(struct task_struct *tsk) + { + unsigned int state = (tsk->state & (TASK_RUNNING | ++ TASK_RUNNING_MUTEX | + TASK_INTERRUPTIBLE | + TASK_UNINTERRUPTIBLE | + TASK_STOPPED | +@@ -305,6 +307,19 @@ static inline char *task_context_switch_ + p->nivcsw); + } + ++#define get_blocked_on(t) (-1) ++ ++static char *show_blocked_on(struct task_struct *task, char *buffer) ++{ ++ pid_t pid = get_blocked_on(task); ++ ++ if (pid < 0) ++ return buffer; ++ ++ return buffer + sprintf(buffer,"BlckOn: %d\n",pid); ++} ++ ++ + int proc_pid_status(struct task_struct *task, char *buffer) + { + char *orig = buffer; +@@ -324,6 +339,7 @@ int proc_pid_status(struct task_struct * + buffer = task_show_regs(task, buffer); + #endif + buffer = task_context_switch_counts(task, buffer); ++ buffer = show_blocked_on(task,buffer); + return buffer - orig; + } + +Index: linux-2.6.24.7-rt27/include/linux/bit_spinlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/bit_spinlock.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/bit_spinlock.h 2009-02-08 00:02:01.000000000 -0500 +@@ -1,6 +1,8 @@ + #ifndef __LINUX_BIT_SPINLOCK_H + #define __LINUX_BIT_SPINLOCK_H + ++#if 0 ++ + /* + * bit-based spin_lock() + * +@@ -91,5 +93,7 @@ static inline int bit_spin_is_locked(int + #endif + } + ++#endif ++ + #endif /* __LINUX_BIT_SPINLOCK_H */ + +Index: linux-2.6.24.7-rt27/include/linux/init_task.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/init_task.h 2009-02-08 00:00:53.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/init_task.h 2009-02-08 00:02:01.000000000 -0500 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #define INIT_FDTABLE \ + { \ +@@ -165,7 +166,7 @@ extern struct group_info init_groups; + .journal_info = NULL, \ + .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \ + .fs_excl = ATOMIC_INIT(0), \ +- .pi_lock = __SPIN_LOCK_UNLOCKED(tsk.pi_lock), \ ++ .pi_lock = RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock), \ + .pids = { \ + [PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID), \ + [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID), \ +Index: linux-2.6.24.7-rt27/include/linux/mutex.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/mutex.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/mutex.h 2009-02-08 00:02:01.000000000 -0500 +@@ -12,11 +12,66 @@ + + #include + #include ++#include + #include + #include + + #include + ++#ifdef CONFIG_PREEMPT_RT ++ ++#include ++ ++struct mutex { ++ struct rt_mutex lock; ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ struct lockdep_map dep_map; ++#endif ++}; ++ ++#define __MUTEX_INITIALIZER(mutexname) \ ++ { \ ++ .lock = __RT_MUTEX_INITIALIZER(mutexname.lock) \ ++ } ++ ++#define DEFINE_MUTEX(mutexname) \ ++ struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) ++ ++extern void ++_mutex_init(struct mutex *lock, char *name, struct lock_class_key *key); ++ ++extern void __lockfunc _mutex_lock(struct mutex *lock); ++extern int __lockfunc _mutex_lock_interruptible(struct mutex *lock); ++extern void __lockfunc _mutex_lock_nested(struct mutex *lock, int subclass); ++extern int __lockfunc _mutex_lock_interruptible_nested(struct mutex *lock, int subclass); ++extern int __lockfunc _mutex_trylock(struct mutex *lock); ++extern void __lockfunc _mutex_unlock(struct mutex *lock); ++ ++#define mutex_is_locked(l) rt_mutex_is_locked(&(l)->lock) ++#define mutex_lock(l) _mutex_lock(l) ++#define mutex_lock_interruptible(l) _mutex_lock_interruptible(l) ++#define mutex_trylock(l) _mutex_trylock(l) ++#define mutex_unlock(l) _mutex_unlock(l) ++#define mutex_destroy(l) rt_mutex_destroy(&(l)->lock) ++ ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++# define mutex_lock_nested(l, s) _mutex_lock_nested(l, s) ++# define mutex_lock_interruptible_nested(l, s) \ ++ _mutex_lock_interruptible_nested(l, s) ++#else ++# define mutex_lock_nested(l, s) _mutex_lock(l) ++# define mutex_lock_interruptible_nested(l, s) \ ++ _mutex_lock_interruptible(l) ++#endif ++ ++# define mutex_init(mutex) \ ++do { \ ++ static struct lock_class_key __key; \ ++ \ ++ _mutex_init((mutex), #mutex, &__key); \ ++} while (0) ++ ++#else + /* + * Simple, straightforward mutexes with strict semantics: + * +@@ -144,3 +199,5 @@ extern int fastcall mutex_trylock(struct + extern void fastcall mutex_unlock(struct mutex *lock); + + #endif ++ ++#endif +Index: linux-2.6.24.7-rt27/include/linux/plist.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/plist.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/plist.h 2009-02-08 00:02:01.000000000 -0500 +@@ -81,7 +81,7 @@ struct plist_head { + struct list_head prio_list; + struct list_head node_list; + #ifdef CONFIG_DEBUG_PI_LIST +- spinlock_t *lock; ++ raw_spinlock_t *lock; + #endif + }; + +@@ -125,7 +125,7 @@ struct plist_node { + * @lock: list spinlock, remembered for debugging + */ + static inline void +-plist_head_init(struct plist_head *head, spinlock_t *lock) ++plist_head_init(struct plist_head *head, raw_spinlock_t *lock) + { + INIT_LIST_HEAD(&head->prio_list); + INIT_LIST_HEAD(&head->node_list); +Index: linux-2.6.24.7-rt27/include/linux/rt_lock.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/include/linux/rt_lock.h 2009-02-08 00:02:01.000000000 -0500 +@@ -0,0 +1,334 @@ ++#ifndef __LINUX_RT_LOCK_H ++#define __LINUX_RT_LOCK_H ++ ++/* ++ * Real-Time Preemption Support ++ * ++ * started by Ingo Molnar: ++ * ++ * Copyright (C) 2004, 2005 Red Hat, Inc., Ingo Molnar ++ * ++ * This file contains the main data structure definitions. ++ */ ++#include ++#include ++#include ++ ++#ifdef CONFIG_PREEMPT_RT ++/* ++ * spinlocks - an RT mutex plus lock-break field: ++ */ ++typedef struct { ++ struct rt_mutex lock; ++ unsigned int break_lock; ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ struct lockdep_map dep_map; ++#endif ++} spinlock_t; ++ ++#ifdef CONFIG_DEBUG_RT_MUTEXES ++# define __SPIN_LOCK_UNLOCKED(name) \ ++ (spinlock_t) { { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name) \ ++ , .save_state = 1, .file = __FILE__, .line = __LINE__ }, SPIN_DEP_MAP_INIT(name) } ++#else ++# define __SPIN_LOCK_UNLOCKED(name) \ ++ (spinlock_t) { { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name) }, SPIN_DEP_MAP_INIT(name) } ++#endif ++# define SPIN_LOCK_UNLOCKED __SPIN_LOCK_UNLOCKED(spin_old_style) ++#else /* !PREEMPT_RT */ ++ typedef raw_spinlock_t spinlock_t; ++# ifdef CONFIG_DEBUG_SPINLOCK ++# define _SPIN_LOCK_UNLOCKED \ ++ { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \ ++ .magic = SPINLOCK_MAGIC, \ ++ .owner = SPINLOCK_OWNER_INIT, \ ++ .owner_cpu = -1 } ++# else ++# define _SPIN_LOCK_UNLOCKED \ ++ { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED } ++# endif ++# define SPIN_LOCK_UNLOCKED _SPIN_LOCK_UNLOCKED ++# define __SPIN_LOCK_UNLOCKED(name) _SPIN_LOCK_UNLOCKED ++#endif ++ ++#define __DEFINE_SPINLOCK(name) \ ++ spinlock_t name = __SPIN_LOCK_UNLOCKED(name) ++ ++#define DEFINE_SPINLOCK(name) \ ++ spinlock_t name __cacheline_aligned_in_smp = __SPIN_LOCK_UNLOCKED(name) ++ ++#ifdef CONFIG_PREEMPT_RT ++ ++/* ++ * RW-semaphores are a spinlock plus a reader-depth count. ++ * ++ * Note that the semantics are different from the usual ++ * Linux rw-sems, in PREEMPT_RT mode we do not allow ++ * multiple readers to hold the lock at once, we only allow ++ * a read-lock owner to read-lock recursively. This is ++ * better for latency, makes the implementation inherently ++ * fair and makes it simpler as well: ++ */ ++struct rw_semaphore { ++ struct rt_mutex lock; ++ int read_depth; ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ struct lockdep_map dep_map; ++#endif ++}; ++ ++/* ++ * rwlocks - an RW semaphore plus lock-break field: ++ */ ++typedef struct { ++ struct rt_mutex lock; ++ int read_depth; ++ unsigned int break_lock; ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ struct lockdep_map dep_map; ++#endif ++} rwlock_t; ++ ++# ifdef CONFIG_DEBUG_RT_MUTEXES ++# define __RW_LOCK_UNLOCKED(name) (rwlock_t) \ ++ { .lock = { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name), \ ++ .save_state = 1, .file = __FILE__, .line = __LINE__ } } ++# else ++# define __RW_LOCK_UNLOCKED(name) (rwlock_t) \ ++ { .lock = { .wait_lock = _RAW_SPIN_LOCK_UNLOCKED(name) } } ++# endif ++#else /* !PREEMPT_RT */ ++ ++ typedef raw_rwlock_t rwlock_t; ++# ifdef CONFIG_DEBUG_SPINLOCK ++# define _RW_LOCK_UNLOCKED \ ++ (rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED, \ ++ .magic = RWLOCK_MAGIC, \ ++ .owner = SPINLOCK_OWNER_INIT, \ ++ .owner_cpu = -1 } ++# else ++# define _RW_LOCK_UNLOCKED \ ++ (rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED } ++# endif ++# define __RW_LOCK_UNLOCKED(name) _RW_LOCK_UNLOCKED ++#endif ++ ++#define RW_LOCK_UNLOCKED __RW_LOCK_UNLOCKED(rw_old_style) ++ ++#define DEFINE_RWLOCK(name) \ ++ rwlock_t name __cacheline_aligned_in_smp = __RW_LOCK_UNLOCKED(name) ++ ++#ifdef CONFIG_PREEMPT_RT ++ ++/* ++ * Semaphores - a spinlock plus the semaphore count: ++ */ ++struct semaphore { ++ atomic_t count; ++ struct rt_mutex lock; ++}; ++ ++#define DECLARE_MUTEX(name) \ ++struct semaphore name = \ ++ { .count = { 1 }, .lock = __RT_MUTEX_INITIALIZER(name.lock) } ++ ++extern void fastcall ++__sema_init(struct semaphore *sem, int val, char *name, char *file, int line); ++ ++#define rt_sema_init(sem, val) \ ++ __sema_init(sem, val, #sem, __FILE__, __LINE__) ++ ++extern void fastcall ++__init_MUTEX(struct semaphore *sem, char *name, char *file, int line); ++#define rt_init_MUTEX(sem) \ ++ __init_MUTEX(sem, #sem, __FILE__, __LINE__) ++ ++extern void there_is_no_init_MUTEX_LOCKED_for_RT_semaphores(void); ++ ++/* ++ * No locked initialization for RT semaphores ++ */ ++#define rt_init_MUTEX_LOCKED(sem) \ ++ there_is_no_init_MUTEX_LOCKED_for_RT_semaphores() ++extern void fastcall rt_down(struct semaphore *sem); ++extern int fastcall rt_down_interruptible(struct semaphore *sem); ++extern int fastcall rt_down_trylock(struct semaphore *sem); ++extern void fastcall rt_up(struct semaphore *sem); ++ ++#define rt_sem_is_locked(s) rt_mutex_is_locked(&(s)->lock) ++#define rt_sema_count(s) atomic_read(&(s)->count) ++ ++extern int __bad_func_type(void); ++ ++#undef TYPE_EQUAL ++#define TYPE_EQUAL(var, type) \ ++ __builtin_types_compatible_p(typeof(var), type *) ++ ++#define PICK_FUNC_1ARG(type1, type2, func1, func2, arg) \ ++do { \ ++ if (TYPE_EQUAL((arg), type1)) \ ++ func1((type1 *)(arg)); \ ++ else if (TYPE_EQUAL((arg), type2)) \ ++ func2((type2 *)(arg)); \ ++ else __bad_func_type(); \ ++} while (0) ++ ++#define PICK_FUNC_1ARG_RET(type1, type2, func1, func2, arg) \ ++({ \ ++ unsigned long __ret; \ ++ \ ++ if (TYPE_EQUAL((arg), type1)) \ ++ __ret = func1((type1 *)(arg)); \ ++ else if (TYPE_EQUAL((arg), type2)) \ ++ __ret = func2((type2 *)(arg)); \ ++ else __ret = __bad_func_type(); \ ++ \ ++ __ret; \ ++}) ++ ++#define PICK_FUNC_2ARG(type1, type2, func1, func2, arg0, arg1) \ ++do { \ ++ if (TYPE_EQUAL((arg0), type1)) \ ++ func1((type1 *)(arg0), arg1); \ ++ else if (TYPE_EQUAL((arg0), type2)) \ ++ func2((type2 *)(arg0), arg1); \ ++ else __bad_func_type(); \ ++} while (0) ++ ++#define sema_init(sem, val) \ ++ PICK_FUNC_2ARG(struct compat_semaphore, struct semaphore, \ ++ compat_sema_init, rt_sema_init, sem, val) ++ ++#define init_MUTEX(sem) \ ++ PICK_FUNC_1ARG(struct compat_semaphore, struct semaphore, \ ++ compat_init_MUTEX, rt_init_MUTEX, sem) ++ ++#define init_MUTEX_LOCKED(sem) \ ++ PICK_FUNC_1ARG(struct compat_semaphore, struct semaphore, \ ++ compat_init_MUTEX_LOCKED, rt_init_MUTEX_LOCKED, sem) ++ ++#define down(sem) \ ++ PICK_FUNC_1ARG(struct compat_semaphore, struct semaphore, \ ++ compat_down, rt_down, sem) ++ ++#define down_interruptible(sem) \ ++ PICK_FUNC_1ARG_RET(struct compat_semaphore, struct semaphore, \ ++ compat_down_interruptible, rt_down_interruptible, sem) ++ ++#define down_trylock(sem) \ ++ PICK_FUNC_1ARG_RET(struct compat_semaphore, struct semaphore, \ ++ compat_down_trylock, rt_down_trylock, sem) ++ ++#define up(sem) \ ++ PICK_FUNC_1ARG(struct compat_semaphore, struct semaphore, \ ++ compat_up, rt_up, sem) ++ ++#define sem_is_locked(sem) \ ++ PICK_FUNC_1ARG_RET(struct compat_semaphore, struct semaphore, \ ++ compat_sem_is_locked, rt_sem_is_locked, sem) ++ ++#define sema_count(sem) \ ++ PICK_FUNC_1ARG_RET(struct compat_semaphore, struct semaphore, \ ++ compat_sema_count, rt_sema_count, sem) ++ ++/* ++ * rwsems: ++ */ ++ ++#define __RWSEM_INITIALIZER(name) \ ++ { .lock = __RT_MUTEX_INITIALIZER(name.lock) } ++ ++#define DECLARE_RWSEM(lockname) \ ++ struct rw_semaphore lockname = __RWSEM_INITIALIZER(lockname) ++ ++extern void fastcall __rt_rwsem_init(struct rw_semaphore *rwsem, char *name, ++ struct lock_class_key *key); ++ ++# define rt_init_rwsem(sem) \ ++do { \ ++ static struct lock_class_key __key; \ ++ \ ++ __rt_rwsem_init((sem), #sem, &__key); \ ++} while (0) ++ ++extern void fastcall rt_down_write(struct rw_semaphore *rwsem); ++extern void fastcall ++rt_down_read_nested(struct rw_semaphore *rwsem, int subclass); ++extern void fastcall ++rt_down_write_nested(struct rw_semaphore *rwsem, int subclass); ++extern void fastcall rt_down_read(struct rw_semaphore *rwsem); ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++extern void fastcall rt_down_read_non_owner(struct rw_semaphore *rwsem); ++#else ++# define rt_down_read_non_owner(rwsem) rt_down_read(rwsem) ++#endif ++extern int fastcall rt_down_write_trylock(struct rw_semaphore *rwsem); ++extern int fastcall rt_down_read_trylock(struct rw_semaphore *rwsem); ++extern void fastcall rt_up_read(struct rw_semaphore *rwsem); ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++extern void fastcall rt_up_read_non_owner(struct rw_semaphore *rwsem); ++#else ++# define rt_up_read_non_owner(rwsem) rt_up_read(rwsem) ++#endif ++extern void fastcall rt_up_write(struct rw_semaphore *rwsem); ++extern void fastcall rt_downgrade_write(struct rw_semaphore *rwsem); ++ ++# define rt_rwsem_is_locked(rws) (rt_mutex_is_locked(&(rws)->lock)) ++ ++#define init_rwsem(rwsem) \ ++ PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_init_rwsem, rt_init_rwsem, rwsem) ++ ++#define down_read(rwsem) \ ++ PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_down_read, rt_down_read, rwsem) ++ ++#define down_read_non_owner(rwsem) \ ++ PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_down_read_non_owner, rt_down_read_non_owner, rwsem) ++ ++#define down_read_trylock(rwsem) \ ++ PICK_FUNC_1ARG_RET(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_down_read_trylock, rt_down_read_trylock, rwsem) ++ ++#define down_write(rwsem) \ ++ PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_down_write, rt_down_write, rwsem) ++ ++#define down_read_nested(rwsem, subclass) \ ++ PICK_FUNC_2ARG(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_down_read_nested, rt_down_read_nested, rwsem, subclass) ++ ++ ++#define down_write_nested(rwsem, subclass) \ ++ PICK_FUNC_2ARG(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_down_write_nested, rt_down_write_nested, rwsem, subclass) ++ ++#define down_write_trylock(rwsem) \ ++ PICK_FUNC_1ARG_RET(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_down_write_trylock, rt_down_write_trylock, rwsem) ++ ++#define up_read(rwsem) \ ++ PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_up_read, rt_up_read, rwsem) ++ ++#define up_read_non_owner(rwsem) \ ++ PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_up_read_non_owner, rt_up_read_non_owner, rwsem) ++ ++#define up_write(rwsem) \ ++ PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_up_write, rt_up_write, rwsem) ++ ++#define downgrade_write(rwsem) \ ++ PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_downgrade_write, rt_downgrade_write, rwsem) ++ ++#define rwsem_is_locked(rwsem) \ ++ PICK_FUNC_1ARG_RET(struct compat_rw_semaphore, struct rw_semaphore, \ ++ compat_rwsem_is_locked, rt_rwsem_is_locked, rwsem) ++ ++#endif /* CONFIG_PREEMPT_RT */ ++ ++#endif ++ +Index: linux-2.6.24.7-rt27/include/linux/rtmutex.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rtmutex.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rtmutex.h 2009-02-08 00:02:01.000000000 -0500 +@@ -24,7 +24,7 @@ + * @owner: the mutex owner + */ + struct rt_mutex { +- spinlock_t wait_lock; ++ raw_spinlock_t wait_lock; + struct plist_head wait_list; + struct task_struct *owner; + #ifdef CONFIG_DEBUG_RT_MUTEXES +@@ -63,7 +63,7 @@ struct hrtimer_sleeper; + #endif + + #define __RT_MUTEX_INITIALIZER(mutexname) \ +- { .wait_lock = __SPIN_LOCK_UNLOCKED(mutexname.wait_lock) \ ++ { .wait_lock = RAW_SPIN_LOCK_UNLOCKED(mutexname) \ + , .wait_list = PLIST_HEAD_INIT(mutexname.wait_list, mutexname.wait_lock) \ + , .owner = NULL \ + __DEBUG_RT_MUTEX_INITIALIZER(mutexname)} +Index: linux-2.6.24.7-rt27/include/linux/rwsem-spinlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rwsem-spinlock.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rwsem-spinlock.h 2009-02-08 00:02:01.000000000 -0500 +@@ -28,7 +28,7 @@ struct rwsem_waiter; + * - if activity is -1 then there is one active writer + * - if wait_list is not empty, then there are processes waiting for the semaphore + */ +-struct rw_semaphore { ++struct compat_rw_semaphore { + __s32 activity; + spinlock_t wait_lock; + struct list_head wait_list; +@@ -43,33 +43,32 @@ struct rw_semaphore { + # define __RWSEM_DEP_MAP_INIT(lockname) + #endif + +-#define __RWSEM_INITIALIZER(name) \ +-{ 0, __SPIN_LOCK_UNLOCKED(name.wait_lock), LIST_HEAD_INIT((name).wait_list) \ +- __RWSEM_DEP_MAP_INIT(name) } ++#define __COMPAT_RWSEM_INITIALIZER(name) \ ++{ 0, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) } + +-#define DECLARE_RWSEM(name) \ +- struct rw_semaphore name = __RWSEM_INITIALIZER(name) ++#define COMPAT_DECLARE_RWSEM(name) \ ++ struct compat_rw_semaphore name = __COMPAT_RWSEM_INITIALIZER(name) + +-extern void __init_rwsem(struct rw_semaphore *sem, const char *name, ++extern void __compat_init_rwsem(struct compat_rw_semaphore *sem, const char *name, + struct lock_class_key *key); + +-#define init_rwsem(sem) \ ++#define compat_init_rwsem(sem) \ + do { \ + static struct lock_class_key __key; \ + \ +- __init_rwsem((sem), #sem, &__key); \ ++ __compat_init_rwsem((sem), #sem, &__key); \ + } while (0) + +-extern void FASTCALL(__down_read(struct rw_semaphore *sem)); +-extern int FASTCALL(__down_read_trylock(struct rw_semaphore *sem)); +-extern void FASTCALL(__down_write(struct rw_semaphore *sem)); +-extern void FASTCALL(__down_write_nested(struct rw_semaphore *sem, int subclass)); +-extern int FASTCALL(__down_write_trylock(struct rw_semaphore *sem)); +-extern void FASTCALL(__up_read(struct rw_semaphore *sem)); +-extern void FASTCALL(__up_write(struct rw_semaphore *sem)); +-extern void FASTCALL(__downgrade_write(struct rw_semaphore *sem)); ++extern void FASTCALL(__down_read(struct compat_rw_semaphore *sem)); ++extern int FASTCALL(__down_read_trylock(struct compat_rw_semaphore *sem)); ++extern void FASTCALL(__down_write(struct compat_rw_semaphore *sem)); ++extern void FASTCALL(__down_write_nested(struct compat_rw_semaphore *sem, int subclass)); ++extern int FASTCALL(__down_write_trylock(struct compat_rw_semaphore *sem)); ++extern void FASTCALL(__up_read(struct compat_rw_semaphore *sem)); ++extern void FASTCALL(__up_write(struct compat_rw_semaphore *sem)); ++extern void FASTCALL(__downgrade_write(struct compat_rw_semaphore *sem)); + +-static inline int rwsem_is_locked(struct rw_semaphore *sem) ++static inline int compat_rwsem_is_locked(struct compat_rw_semaphore *sem) + { + return (sem->activity != 0); + } +Index: linux-2.6.24.7-rt27/include/linux/rwsem.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rwsem.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rwsem.h 2009-02-08 00:02:01.000000000 -0500 +@@ -9,6 +9,10 @@ + + #include + ++#ifdef CONFIG_PREEMPT_RT ++# include ++#endif ++ + #ifdef __KERNEL__ + + #include +@@ -16,48 +20,59 @@ + #include + #include + +-struct rw_semaphore; ++#ifndef CONFIG_PREEMPT_RT ++/* ++ * On !PREEMPT_RT all rw-semaphores are compat: ++ */ ++#define compat_rw_semaphore rw_semaphore ++#endif ++ ++struct compat_rw_semaphore; + + #ifdef CONFIG_RWSEM_GENERIC_SPINLOCK +-#include /* use a generic implementation */ ++# include /* use a generic implementation */ ++# ifndef CONFIG_PREEMPT_RT ++# define __RWSEM_INITIALIZER __COMPAT_RWSEM_INITIALIZER ++# define DECLARE_RWSEM COMPAT_DECLARE_RWSEM ++# endif + #else +-#include /* use an arch-specific implementation */ ++# include /* use an arch-specific implementation */ + #endif + + /* + * lock for reading + */ +-extern void down_read(struct rw_semaphore *sem); ++extern void compat_down_read(struct compat_rw_semaphore *sem); + + /* + * trylock for reading -- returns 1 if successful, 0 if contention + */ +-extern int down_read_trylock(struct rw_semaphore *sem); ++extern int compat_down_read_trylock(struct compat_rw_semaphore *sem); + + /* + * lock for writing + */ +-extern void down_write(struct rw_semaphore *sem); ++extern void compat_down_write(struct compat_rw_semaphore *sem); + + /* + * trylock for writing -- returns 1 if successful, 0 if contention + */ +-extern int down_write_trylock(struct rw_semaphore *sem); ++extern int compat_down_write_trylock(struct compat_rw_semaphore *sem); + + /* + * release a read lock + */ +-extern void up_read(struct rw_semaphore *sem); ++extern void compat_up_read(struct compat_rw_semaphore *sem); + + /* + * release a write lock + */ +-extern void up_write(struct rw_semaphore *sem); ++extern void compat_up_write(struct compat_rw_semaphore *sem); + + /* + * downgrade write lock to read lock + */ +-extern void downgrade_write(struct rw_semaphore *sem); ++extern void compat_downgrade_write(struct compat_rw_semaphore *sem); + + #ifdef CONFIG_DEBUG_LOCK_ALLOC + /* +@@ -73,22 +88,79 @@ extern void downgrade_write(struct rw_se + * lockdep_set_class() at lock initialization time. + * See Documentation/lockdep-design.txt for more details.) + */ +-extern void down_read_nested(struct rw_semaphore *sem, int subclass); +-extern void down_write_nested(struct rw_semaphore *sem, int subclass); ++extern void ++compat_down_read_nested(struct compat_rw_semaphore *sem, int subclass); ++extern void ++compat_down_write_nested(struct compat_rw_semaphore *sem, int subclass); + /* + * Take/release a lock when not the owner will release it. + * + * [ This API should be avoided as much as possible - the + * proper abstraction for this case is completions. ] + */ +-extern void down_read_non_owner(struct rw_semaphore *sem); +-extern void up_read_non_owner(struct rw_semaphore *sem); ++extern void ++compat_down_read_non_owner(struct compat_rw_semaphore *sem); ++extern void ++compat_up_read_non_owner(struct compat_rw_semaphore *sem); + #else +-# define down_read_nested(sem, subclass) down_read(sem) +-# define down_write_nested(sem, subclass) down_write(sem) +-# define down_read_non_owner(sem) down_read(sem) +-# define up_read_non_owner(sem) up_read(sem) ++# define compat_down_read_nested(sem, subclass) compat_down_read(sem) ++# define compat_down_write_nested(sem, subclass) compat_down_write(sem) ++# define compat_down_read_non_owner(sem) compat_down_read(sem) ++# define compat_up_read_non_owner(sem) compat_up_read(sem) + #endif + ++#ifndef CONFIG_PREEMPT_RT ++ ++#define DECLARE_RWSEM COMPAT_DECLARE_RWSEM ++ ++/* ++ * NOTE, lockdep: this has to be a macro, so that separate class-keys ++ * get generated by the compiler, if the same function does multiple ++ * init_rwsem() calls to different rwsems. ++ */ ++#define init_rwsem(rwsem) compat_init_rwsem(rwsem) ++ ++static inline void down_read(struct compat_rw_semaphore *rwsem) ++{ ++ compat_down_read(rwsem); ++} ++static inline int down_read_trylock(struct compat_rw_semaphore *rwsem) ++{ ++ return compat_down_read_trylock(rwsem); ++} ++static inline void down_write(struct compat_rw_semaphore *rwsem) ++{ ++ compat_down_write(rwsem); ++} ++static inline int down_write_trylock(struct compat_rw_semaphore *rwsem) ++{ ++ return compat_down_write_trylock(rwsem); ++} ++static inline void up_read(struct compat_rw_semaphore *rwsem) ++{ ++ compat_up_read(rwsem); ++} ++static inline void up_write(struct compat_rw_semaphore *rwsem) ++{ ++ compat_up_write(rwsem); ++} ++static inline void downgrade_write(struct compat_rw_semaphore *rwsem) ++{ ++ compat_downgrade_write(rwsem); ++} ++static inline int rwsem_is_locked(struct compat_rw_semaphore *sem) ++{ ++ return compat_rwsem_is_locked(sem); ++} ++# define down_read_nested(sem, subclass) \ ++ compat_down_read_nested(sem, subclass) ++# define down_write_nested(sem, subclass) \ ++ compat_down_write_nested(sem, subclass) ++# define down_read_non_owner(sem) \ ++ compat_down_read_non_owner(sem) ++# define up_read_non_owner(sem) \ ++ compat_up_read_non_owner(sem) ++#endif /* !CONFIG_PREEMPT_RT */ ++ + #endif /* __KERNEL__ */ + #endif /* _LINUX_RWSEM_H */ +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:02:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:02:01.000000000 -0500 +@@ -168,6 +168,10 @@ print_cfs_rq(struct seq_file *m, int cpu + } + #endif + ++#ifdef CONFIG_PREEMPT_BKL ++extern struct semaphore kernel_sem; ++#endif ++ + /* + * Task state bitmask. NOTE! These bits are also + * encoded in fs/proc/array.c: get_task_state(). +@@ -179,15 +183,17 @@ print_cfs_rq(struct seq_file *m, int cpu + * mistake. + */ + #define TASK_RUNNING 0 +-#define TASK_INTERRUPTIBLE 1 +-#define TASK_UNINTERRUPTIBLE 2 +-#define TASK_STOPPED 4 +-#define TASK_TRACED 8 ++#define TASK_RUNNING_MUTEX 1 ++#define TASK_INTERRUPTIBLE 2 ++#define TASK_UNINTERRUPTIBLE 4 ++#define TASK_STOPPED 8 ++#define TASK_TRACED 16 + /* in tsk->exit_state */ +-#define EXIT_ZOMBIE 16 +-#define EXIT_DEAD 32 ++#define EXIT_ZOMBIE 32 ++#define EXIT_DEAD 64 + /* in tsk->state again */ +-#define TASK_DEAD 64 ++#define TASK_NONINTERACTIVE 128 ++#define TASK_DEAD 256 + + #define __set_task_state(tsk, state_value) \ + do { (tsk)->state = (state_value); } while (0) +@@ -1120,7 +1126,7 @@ struct task_struct { + spinlock_t alloc_lock; + + /* Protection of the PI data structures: */ +- spinlock_t pi_lock; ++ raw_spinlock_t pi_lock; + + #ifdef CONFIG_RT_MUTEXES + /* PI waiters blocked on a rt_mutex held by this task */ +@@ -1163,6 +1169,25 @@ struct task_struct { + unsigned long preempt_trace_parent_eip[MAX_PREEMPT_TRACE]; + #endif + ++#define MAX_LOCK_STACK MAX_PREEMPT_TRACE ++#ifdef CONFIG_DEBUG_PREEMPT ++ int lock_count; ++# ifdef CONFIG_PREEMPT_RT ++ struct rt_mutex *owned_lock[MAX_LOCK_STACK]; ++# endif ++#endif ++#ifdef CONFIG_DETECT_SOFTLOCKUP ++ unsigned long softlockup_count; /* Count to keep track how long the ++ * thread is in the kernel without ++ * sleeping. ++ */ ++#endif ++ /* realtime bits */ ++ ++#ifdef CONFIG_DEBUG_RT_MUTEXES ++ void *last_kernel_lock; ++#endif ++ + /* journalling filesystem info */ + void *journal_info; + +@@ -1409,6 +1434,7 @@ static inline void put_task_struct(struc + #define PF_EXITING 0x00000004 /* getting shut down */ + #define PF_EXITPIDONE 0x00000008 /* pi exit done on shut down */ + #define PF_VCPU 0x00000010 /* I'm a virtual CPU */ ++#define PF_NOSCHED 0x00000020 /* Userspace does not expect scheduling */ + #define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */ + #define PF_SUPERPRIV 0x00000100 /* used super-user privileges */ + #define PF_DUMPCORE 0x00000200 /* dumped core */ +@@ -1545,6 +1571,7 @@ extern struct task_struct *curr_task(int + extern void set_curr_task(int cpu, struct task_struct *p); + + void yield(void); ++void __yield(void); + + /* + * The default (Linux) execution domain. +@@ -1616,6 +1643,9 @@ extern void do_timer(unsigned long ticks + + extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned int state)); + extern int FASTCALL(wake_up_process(struct task_struct * tsk)); ++extern int FASTCALL(wake_up_process_mutex(struct task_struct * tsk)); ++extern int FASTCALL(wake_up_process_sync(struct task_struct * tsk)); ++extern int FASTCALL(wake_up_process_mutex_sync(struct task_struct * tsk)); + extern void FASTCALL(wake_up_new_task(struct task_struct * tsk, + unsigned long clone_flags)); + #ifdef CONFIG_SMP +@@ -1926,7 +1956,22 @@ static inline int need_resched_delayed(v + * cond_resched_softirq() will enable bhs before scheduling. + */ + extern int cond_resched(void); +-extern int cond_resched_lock(spinlock_t * lock); ++extern int __cond_resched_raw_spinlock(raw_spinlock_t *lock); ++extern int __cond_resched_spinlock(spinlock_t *spinlock); ++ ++#define cond_resched_lock(lock) \ ++({ \ ++ int __ret; \ ++ \ ++ if (TYPE_EQUAL((lock), raw_spinlock_t)) \ ++ __ret = __cond_resched_raw_spinlock((raw_spinlock_t *)lock);\ ++ else if (TYPE_EQUAL(lock, spinlock_t)) \ ++ __ret = __cond_resched_spinlock((spinlock_t *)lock); \ ++ else __ret = __bad_spinlock_type(); \ ++ \ ++ __ret; \ ++}) ++ + extern int cond_resched_softirq(void); + extern int cond_resched_softirq_context(void); + extern int cond_resched_hardirq_context(void); +@@ -1935,12 +1980,18 @@ extern int cond_resched_hardirq_context( + * Does a critical section need to be broken due to another + * task waiting?: + */ +-#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) +-# define need_lockbreak(lock) ((lock)->break_lock) ++#if (defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)) || defined(CONFIG_PREEMPT_RT) ++# define need_lockbreak(lock) ({ int __need = ((lock)->break_lock); if (__need) (lock)->break_lock = 0; __need; }) + #else + # define need_lockbreak(lock) 0 + #endif + ++#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) ++# define need_lockbreak_raw(lock) ({ int __need = ((lock)->break_lock); if (__need) (lock)->break_lock = 0; __need; }) ++#else ++# define need_lockbreak_raw(lock) 0 ++#endif ++ + /* + * Does a critical section need to be broken due to another + * task waiting or preemption being signalled: +@@ -2092,7 +2143,7 @@ static inline void migration_init(void) + } + #endif + +-#define TASK_STATE_TO_CHAR_STR "RSDTtZX" ++#define TASK_STATE_TO_CHAR_STR "RMSDTtZX" + + #endif /* __KERNEL__ */ + +Index: linux-2.6.24.7-rt27/include/linux/semaphore.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/include/linux/semaphore.h 2009-02-08 00:02:01.000000000 -0500 +@@ -0,0 +1,49 @@ ++#ifndef _LINUX_SEMAPHORE_H ++#define _LINUX_SEMAPHORE_H ++ ++#ifdef CONFIG_PREEMPT_RT ++# include ++#else ++ ++#define DECLARE_MUTEX COMPAT_DECLARE_MUTEX ++ ++static inline void sema_init(struct compat_semaphore *sem, int val) ++{ ++ compat_sema_init(sem, val); ++} ++static inline void init_MUTEX(struct compat_semaphore *sem) ++{ ++ compat_init_MUTEX(sem); ++} ++static inline void init_MUTEX_LOCKED(struct compat_semaphore *sem) ++{ ++ compat_init_MUTEX_LOCKED(sem); ++} ++static inline void down(struct compat_semaphore *sem) ++{ ++ compat_down(sem); ++} ++static inline int down_interruptible(struct compat_semaphore *sem) ++{ ++ return compat_down_interruptible(sem); ++} ++static inline int down_trylock(struct compat_semaphore *sem) ++{ ++ return compat_down_trylock(sem); ++} ++static inline void up(struct compat_semaphore *sem) ++{ ++ compat_up(sem); ++} ++static inline int sem_is_locked(struct compat_semaphore *sem) ++{ ++ return compat_sem_is_locked(sem); ++} ++static inline int sema_count(struct compat_semaphore *sem) ++{ ++ return compat_sema_count(sem); ++} ++ ++#endif /* CONFIG_PREEMPT_RT */ ++ ++#endif /* _LINUX_SEMAPHORE_H */ +Index: linux-2.6.24.7-rt27/include/linux/seqlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/seqlock.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/seqlock.h 2009-02-08 00:02:01.000000000 -0500 +@@ -32,46 +32,72 @@ + typedef struct { + unsigned sequence; + spinlock_t lock; +-} seqlock_t; ++} __seqlock_t; ++ ++typedef struct { ++ unsigned sequence; ++ raw_spinlock_t lock; ++} __raw_seqlock_t; ++ ++#define seqlock_need_resched(seq) lock_need_resched(&(seq)->lock) ++ ++#ifdef CONFIG_PREEMPT_RT ++typedef __seqlock_t seqlock_t; ++#else ++typedef __raw_seqlock_t seqlock_t; ++#endif ++ ++typedef __raw_seqlock_t raw_seqlock_t; + + /* + * These macros triggered gcc-3.x compile-time problems. We think these are + * OK now. Be cautious. + */ +-#define __SEQLOCK_UNLOCKED(lockname) \ +- { 0, __SPIN_LOCK_UNLOCKED(lockname) } ++#define __RAW_SEQLOCK_UNLOCKED(lockname) \ ++ { 0, RAW_SPIN_LOCK_UNLOCKED(lockname) } ++ ++#ifdef CONFIG_PREEMPT_RT ++# define __SEQLOCK_UNLOCKED(lockname) { 0, __SPIN_LOCK_UNLOCKED(lockname) } ++#else ++# define __SEQLOCK_UNLOCKED(lockname) __RAW_SEQLOCK_UNLOCKED(lockname) ++#endif + + #define SEQLOCK_UNLOCKED \ + __SEQLOCK_UNLOCKED(old_style_seqlock_init) + +-#define seqlock_init(x) \ +- do { \ +- (x)->sequence = 0; \ +- spin_lock_init(&(x)->lock); \ +- } while (0) ++#define raw_seqlock_init(x) \ ++ do { *(x) = (raw_seqlock_t) __RAW_SEQLOCK_UNLOCKED(x); spin_lock_init(&(x)->lock); } while (0) ++ ++#define seqlock_init(x) \ ++ do { *(x) = (seqlock_t) __SEQLOCK_UNLOCKED(x); spin_lock_init(&(x)->lock); } while (0) + + #define DEFINE_SEQLOCK(x) \ + seqlock_t x = __SEQLOCK_UNLOCKED(x) + ++#define DEFINE_RAW_SEQLOCK(name) \ ++ raw_seqlock_t name __cacheline_aligned_in_smp = \ ++ __RAW_SEQLOCK_UNLOCKED(name) ++ ++ + /* Lock out other writers and update the count. + * Acts like a normal spin_lock/unlock. + * Don't need preempt_disable() because that is in the spin_lock already. + */ +-static inline void write_seqlock(seqlock_t *sl) ++static inline void __write_seqlock(seqlock_t *sl) + { + spin_lock(&sl->lock); + ++sl->sequence; + smp_wmb(); + } + +-static inline void write_sequnlock(seqlock_t *sl) ++static inline void __write_sequnlock(seqlock_t *sl) + { + smp_wmb(); + sl->sequence++; + spin_unlock(&sl->lock); + } + +-static inline int write_tryseqlock(seqlock_t *sl) ++static inline int __write_tryseqlock(seqlock_t *sl) + { + int ret = spin_trylock(&sl->lock); + +@@ -83,7 +109,7 @@ static inline int write_tryseqlock(seqlo + } + + /* Start of read calculation -- fetch last complete writer token */ +-static __always_inline unsigned read_seqbegin(const seqlock_t *sl) ++static __always_inline unsigned __read_seqbegin(const seqlock_t *sl) + { + unsigned ret = sl->sequence; + smp_rmb(); +@@ -98,12 +124,118 @@ static __always_inline unsigned read_seq + * + * Using xor saves one conditional branch. + */ +-static __always_inline int read_seqretry(const seqlock_t *sl, unsigned iv) ++static inline int __read_seqretry(seqlock_t *sl, unsigned iv) ++{ ++ int ret; ++ ++ smp_rmb(); ++ ret = (iv & 1) | (sl->sequence ^ iv); ++ /* ++ * If invalid then serialize with the writer, to make sure we ++ * are not livelocking it: ++ */ ++ if (unlikely(ret)) { ++ unsigned long flags; ++ spin_lock_irqsave(&sl->lock, flags); ++ spin_unlock_irqrestore(&sl->lock, flags); ++ } ++ return ret; ++} ++ ++static __always_inline void __write_seqlock_raw(raw_seqlock_t *sl) ++{ ++ spin_lock(&sl->lock); ++ ++sl->sequence; ++ smp_wmb(); ++} ++ ++static __always_inline void __write_sequnlock_raw(raw_seqlock_t *sl) ++{ ++ smp_wmb(); ++ sl->sequence++; ++ spin_unlock(&sl->lock); ++} ++ ++static __always_inline int __write_tryseqlock_raw(raw_seqlock_t *sl) ++{ ++ int ret = spin_trylock(&sl->lock); ++ ++ if (ret) { ++ ++sl->sequence; ++ smp_wmb(); ++ } ++ return ret; ++} ++ ++static __always_inline unsigned __read_seqbegin_raw(const raw_seqlock_t *sl) ++{ ++ unsigned ret = sl->sequence; ++ smp_rmb(); ++ return ret; ++} ++ ++static __always_inline int __read_seqretry_raw(const raw_seqlock_t *sl, unsigned iv) + { + smp_rmb(); + return (iv & 1) | (sl->sequence ^ iv); + } + ++extern int __bad_seqlock_type(void); ++ ++#define PICK_SEQOP(op, lock) \ ++do { \ ++ if (TYPE_EQUAL((lock), raw_seqlock_t)) \ ++ op##_raw((raw_seqlock_t *)(lock)); \ ++ else if (TYPE_EQUAL((lock), seqlock_t)) \ ++ op((seqlock_t *)(lock)); \ ++ else __bad_seqlock_type(); \ ++} while (0) ++ ++#define PICK_SEQOP_RET(op, lock) \ ++({ \ ++ unsigned long __ret; \ ++ \ ++ if (TYPE_EQUAL((lock), raw_seqlock_t)) \ ++ __ret = op##_raw((raw_seqlock_t *)(lock)); \ ++ else if (TYPE_EQUAL((lock), seqlock_t)) \ ++ __ret = op((seqlock_t *)(lock)); \ ++ else __ret = __bad_seqlock_type(); \ ++ \ ++ __ret; \ ++}) ++ ++#define PICK_SEQOP_CONST_RET(op, lock) \ ++({ \ ++ unsigned long __ret; \ ++ \ ++ if (TYPE_EQUAL((lock), raw_seqlock_t)) \ ++ __ret = op##_raw((const raw_seqlock_t *)(lock));\ ++ else if (TYPE_EQUAL((lock), seqlock_t)) \ ++ __ret = op((seqlock_t *)(lock)); \ ++ else __ret = __bad_seqlock_type(); \ ++ \ ++ __ret; \ ++}) ++ ++#define PICK_SEQOP2_CONST_RET(op, lock, arg) \ ++ ({ \ ++ unsigned long __ret; \ ++ \ ++ if (TYPE_EQUAL((lock), raw_seqlock_t)) \ ++ __ret = op##_raw((const raw_seqlock_t *)(lock), (arg)); \ ++ else if (TYPE_EQUAL((lock), seqlock_t)) \ ++ __ret = op((seqlock_t *)(lock), (arg)); \ ++ else __ret = __bad_seqlock_type(); \ ++ \ ++ __ret; \ ++}) ++ ++ ++#define write_seqlock(sl) PICK_SEQOP(__write_seqlock, sl) ++#define write_sequnlock(sl) PICK_SEQOP(__write_sequnlock, sl) ++#define write_tryseqlock(sl) PICK_SEQOP_RET(__write_tryseqlock, sl) ++#define read_seqbegin(sl) PICK_SEQOP_CONST_RET(__read_seqbegin, sl) ++#define read_seqretry(sl, iv) PICK_SEQOP2_CONST_RET(__read_seqretry, sl, iv) + + /* + * Version using sequence counter only. +@@ -155,30 +287,51 @@ static inline void write_seqcount_end(se + s->sequence++; + } + ++#define PICK_IRQOP(op, lock) \ ++do { \ ++ if (TYPE_EQUAL((lock), raw_seqlock_t)) \ ++ op(); \ ++ else if (TYPE_EQUAL((lock), seqlock_t)) \ ++ { /* nothing */ } \ ++ else __bad_seqlock_type(); \ ++} while (0) ++ ++#define PICK_IRQOP2(op, arg, lock) \ ++do { \ ++ if (TYPE_EQUAL((lock), raw_seqlock_t)) \ ++ op(arg); \ ++ else if (TYPE_EQUAL(lock, seqlock_t)) \ ++ { /* nothing */ } \ ++ else __bad_seqlock_type(); \ ++} while (0) ++ ++ ++ + /* + * Possible sw/hw IRQ protected versions of the interfaces. + */ + #define write_seqlock_irqsave(lock, flags) \ +- do { local_irq_save(flags); write_seqlock(lock); } while (0) ++ do { PICK_IRQOP2(local_irq_save, flags, lock); write_seqlock(lock); } while (0) + #define write_seqlock_irq(lock) \ +- do { local_irq_disable(); write_seqlock(lock); } while (0) ++ do { PICK_IRQOP(local_irq_disable, lock); write_seqlock(lock); } while (0) + #define write_seqlock_bh(lock) \ +- do { local_bh_disable(); write_seqlock(lock); } while (0) ++ do { PICK_IRQOP(local_bh_disable, lock); write_seqlock(lock); } while (0) + + #define write_sequnlock_irqrestore(lock, flags) \ +- do { write_sequnlock(lock); local_irq_restore(flags); } while(0) ++ do { write_sequnlock(lock); PICK_IRQOP2(local_irq_restore, flags, lock); preempt_check_resched(); } while(0) + #define write_sequnlock_irq(lock) \ +- do { write_sequnlock(lock); local_irq_enable(); } while(0) ++ do { write_sequnlock(lock); PICK_IRQOP(local_irq_enable, lock); preempt_check_resched(); } while(0) + #define write_sequnlock_bh(lock) \ +- do { write_sequnlock(lock); local_bh_enable(); } while(0) ++ do { write_sequnlock(lock); PICK_IRQOP(local_bh_enable, lock); } while(0) + + #define read_seqbegin_irqsave(lock, flags) \ +- ({ local_irq_save(flags); read_seqbegin(lock); }) ++ ({ PICK_IRQOP2(local_irq_save, flags, lock); read_seqbegin(lock); }) + + #define read_seqretry_irqrestore(lock, iv, flags) \ + ({ \ + int ret = read_seqretry(lock, iv); \ +- local_irq_restore(flags); \ ++ PICK_IRQOP2(local_irq_restore, flags, lock); \ ++ preempt_check_resched(); \ + ret; \ + }) + +Index: linux-2.6.24.7-rt27/include/linux/spinlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/spinlock.h 2009-02-08 00:01:30.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/spinlock.h 2009-02-08 00:02:01.000000000 -0500 +@@ -44,6 +44,42 @@ + * builds the _spin_*() APIs. + * + * linux/spinlock.h: builds the final spin_*() APIs. ++ * ++ * ++ * Public types and naming conventions: ++ * ------------------------------------ ++ * spinlock_t: type: sleep-lock ++ * raw_spinlock_t: type: spin-lock (debug) ++ * ++ * spin_lock([raw_]spinlock_t): API: acquire lock, both types ++ * ++ * ++ * Internal types and naming conventions: ++ * ------------------------------------- ++ * __raw_spinlock_t: type: lowlevel spin-lock ++ * ++ * _spin_lock(struct rt_mutex): API: acquire sleep-lock ++ * __spin_lock(raw_spinlock_t): API: acquire spin-lock (highlevel) ++ * _raw_spin_lock(raw_spinlock_t): API: acquire spin-lock (debug) ++ * __raw_spin_lock(__raw_spinlock_t): API: acquire spin-lock (lowlevel) ++ * ++ * ++ * spin_lock(raw_spinlock_t) translates into the following chain of ++ * calls/inlines/macros, if spin-lock debugging is enabled: ++ * ++ * spin_lock() [include/linux/spinlock.h] ++ * -> __spin_lock() [kernel/spinlock.c] ++ * -> _raw_spin_lock() [lib/spinlock_debug.c] ++ * -> __raw_spin_lock() [include/asm/spinlock.h] ++ * ++ * spin_lock(spinlock_t) translates into the following chain of ++ * calls/inlines/macros: ++ * ++ * spin_lock() [include/linux/spinlock.h] ++ * -> _spin_lock() [include/linux/spinlock.h] ++ * -> rt_spin_lock() [kernel/rtmutex.c] ++ * -> rt_spin_lock_fastlock() [kernel/rtmutex.c] ++ * -> rt_spin_lock_slowlock() [kernel/rtmutex.c] + */ + + #include +@@ -51,29 +87,14 @@ + #include + #include + #include ++#include + #include + #include ++#include + + #include + + /* +- * Must define these before including other files, inline functions need them +- */ +-#define LOCK_SECTION_NAME ".text.lock."KBUILD_BASENAME +- +-#define LOCK_SECTION_START(extra) \ +- ".subsection 1\n\t" \ +- extra \ +- ".ifndef " LOCK_SECTION_NAME "\n\t" \ +- LOCK_SECTION_NAME ":\n\t" \ +- ".endif\n" +- +-#define LOCK_SECTION_END \ +- ".previous\n\t" +- +-#define __lockfunc fastcall __attribute__((section(".spinlock.text"))) +- +-/* + * Pull the raw_spinlock_t and raw_rwlock_t definitions: + */ + #include +@@ -89,42 +110,10 @@ extern int __lockfunc generic__raw_read_ + # include + #endif + +-#ifdef CONFIG_DEBUG_SPINLOCK +- extern void __spin_lock_init(spinlock_t *lock, const char *name, +- struct lock_class_key *key); +-# define spin_lock_init(lock) \ +-do { \ +- static struct lock_class_key __key; \ +- \ +- __spin_lock_init((lock), #lock, &__key); \ +-} while (0) +- +-#else +-# define spin_lock_init(lock) \ +- do { *(lock) = SPIN_LOCK_UNLOCKED; } while (0) +-#endif +- +-#ifdef CONFIG_DEBUG_SPINLOCK +- extern void __rwlock_init(rwlock_t *lock, const char *name, +- struct lock_class_key *key); +-# define rwlock_init(lock) \ +-do { \ +- static struct lock_class_key __key; \ +- \ +- __rwlock_init((lock), #lock, &__key); \ +-} while (0) +-#else +-# define rwlock_init(lock) \ +- do { *(lock) = RW_LOCK_UNLOCKED; } while (0) +-#endif +- +-#define spin_is_locked(lock) __raw_spin_is_locked(&(lock)->raw_lock) +- +-/** +- * spin_unlock_wait - wait until the spinlock gets unlocked +- * @lock: the spinlock in question. ++/* ++ * Pull the RT types: + */ +-#define spin_unlock_wait(lock) __raw_spin_unlock_wait(&(lock)->raw_lock) ++#include + + /* + * Pull the _spin_*()/_read_*()/_write_*() functions/declarations: +@@ -136,16 +125,16 @@ do { \ + #endif + + #ifdef CONFIG_DEBUG_SPINLOCK +- extern void _raw_spin_lock(spinlock_t *lock); +-#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) +- extern int _raw_spin_trylock(spinlock_t *lock); +- extern void _raw_spin_unlock(spinlock_t *lock); +- extern void _raw_read_lock(rwlock_t *lock); +- extern int _raw_read_trylock(rwlock_t *lock); +- extern void _raw_read_unlock(rwlock_t *lock); +- extern void _raw_write_lock(rwlock_t *lock); +- extern int _raw_write_trylock(rwlock_t *lock); +- extern void _raw_write_unlock(rwlock_t *lock); ++ extern __lockfunc void _raw_spin_lock(raw_spinlock_t *lock); ++# define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) ++ extern __lockfunc int _raw_spin_trylock(raw_spinlock_t *lock); ++ extern __lockfunc void _raw_spin_unlock(raw_spinlock_t *lock); ++ extern __lockfunc void _raw_read_lock(raw_rwlock_t *lock); ++ extern __lockfunc int _raw_read_trylock(raw_rwlock_t *lock); ++ extern __lockfunc void _raw_read_unlock(raw_rwlock_t *lock); ++ extern __lockfunc void _raw_write_lock(raw_rwlock_t *lock); ++ extern __lockfunc int _raw_write_trylock(raw_rwlock_t *lock); ++ extern __lockfunc void _raw_write_unlock(raw_rwlock_t *lock); + #else + # define _raw_spin_lock(lock) __raw_spin_lock(&(lock)->raw_lock) + # define _raw_spin_lock_flags(lock, flags) \ +@@ -160,148 +149,590 @@ do { \ + # define _raw_write_unlock(rwlock) __raw_write_unlock(&(rwlock)->raw_lock) + #endif + +-#define read_can_lock(rwlock) __raw_read_can_lock(&(rwlock)->raw_lock) +-#define write_can_lock(rwlock) __raw_write_can_lock(&(rwlock)->raw_lock) ++extern int __bad_spinlock_type(void); ++extern int __bad_rwlock_type(void); ++ ++extern void ++__rt_spin_lock_init(spinlock_t *lock, char *name, struct lock_class_key *key); ++ ++extern void __lockfunc rt_spin_lock(spinlock_t *lock); ++extern void __lockfunc rt_spin_lock_nested(spinlock_t *lock, int subclass); ++extern void __lockfunc rt_spin_unlock(spinlock_t *lock); ++extern void __lockfunc rt_spin_unlock_wait(spinlock_t *lock); ++extern int __lockfunc ++rt_spin_trylock_irqsave(spinlock_t *lock, unsigned long *flags); ++extern int __lockfunc rt_spin_trylock(spinlock_t *lock); ++extern int _atomic_dec_and_spin_lock(atomic_t *atomic, spinlock_t *lock); ++ ++/* ++ * lockdep-less calls, for derived types like rwlock: ++ * (for trylock they can use rt_mutex_trylock() directly. ++ */ ++extern void __lockfunc __rt_spin_lock(struct rt_mutex *lock); ++extern void __lockfunc __rt_spin_unlock(struct rt_mutex *lock); ++ ++#ifdef CONFIG_PREEMPT_RT ++# define _spin_lock(l) rt_spin_lock(l) ++# define _spin_lock_nested(l, s) rt_spin_lock_nested(l, s) ++# define _spin_lock_bh(l) rt_spin_lock(l) ++# define _spin_lock_irq(l) rt_spin_lock(l) ++# define _spin_unlock(l) rt_spin_unlock(l) ++# define _spin_unlock_no_resched(l) rt_spin_unlock(l) ++# define _spin_unlock_bh(l) rt_spin_unlock(l) ++# define _spin_unlock_irq(l) rt_spin_unlock(l) ++# define _spin_unlock_irqrestore(l, f) rt_spin_unlock(l) ++static inline unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) ++{ ++ rt_spin_lock(lock); ++ return 0; ++} ++static inline unsigned long __lockfunc ++_spin_lock_irqsave_nested(spinlock_t *lock, int subclass) ++{ ++ rt_spin_lock_nested(lock, subclass); ++ return 0; ++} ++#else ++static inline unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) ++{ ++ return 0; ++} ++static inline unsigned long __lockfunc ++_spin_lock_irqsave_nested(spinlock_t *lock, int subclass) ++{ ++ return 0; ++} ++# define _spin_lock(l) do { } while (0) ++# define _spin_lock_nested(l, s) do { } while (0) ++# define _spin_lock_bh(l) do { } while (0) ++# define _spin_lock_irq(l) do { } while (0) ++# define _spin_unlock(l) do { } while (0) ++# define _spin_unlock_no_resched(l) do { } while (0) ++# define _spin_unlock_bh(l) do { } while (0) ++# define _spin_unlock_irq(l) do { } while (0) ++# define _spin_unlock_irqrestore(l, f) do { } while (0) ++#endif ++ ++#define _spin_lock_init(sl, n, f, l) \ ++do { \ ++ static struct lock_class_key __key; \ ++ \ ++ __rt_spin_lock_init(sl, n, &__key); \ ++} while (0) ++ ++# ifdef CONFIG_PREEMPT_RT ++# define _spin_can_lock(l) (!rt_mutex_is_locked(&(l)->lock)) ++# define _spin_is_locked(l) rt_mutex_is_locked(&(l)->lock) ++# define _spin_unlock_wait(l) rt_spin_unlock_wait(l) ++ ++# define _spin_trylock(l) rt_spin_trylock(l) ++# define _spin_trylock_bh(l) rt_spin_trylock(l) ++# define _spin_trylock_irq(l) rt_spin_trylock(l) ++# define _spin_trylock_irqsave(l,f) rt_spin_trylock_irqsave(l, f) ++# else ++ ++ extern int this_should_never_be_called_on_non_rt(spinlock_t *lock); ++# define TSNBCONRT(l) this_should_never_be_called_on_non_rt(l) ++# define _spin_can_lock(l) TSNBCONRT(l) ++# define _spin_is_locked(l) TSNBCONRT(l) ++# define _spin_unlock_wait(l) TSNBCONRT(l) ++ ++# define _spin_trylock(l) TSNBCONRT(l) ++# define _spin_trylock_bh(l) TSNBCONRT(l) ++# define _spin_trylock_irq(l) TSNBCONRT(l) ++# define _spin_trylock_irqsave(l,f) TSNBCONRT(l) ++#endif ++ ++#undef TYPE_EQUAL ++#define TYPE_EQUAL(lock, type) \ ++ __builtin_types_compatible_p(typeof(lock), type *) ++ ++#define PICK_OP(op, lock) \ ++do { \ ++ if (TYPE_EQUAL((lock), raw_spinlock_t)) \ ++ __spin##op((raw_spinlock_t *)(lock)); \ ++ else if (TYPE_EQUAL(lock, spinlock_t)) \ ++ _spin##op((spinlock_t *)(lock)); \ ++ else __bad_spinlock_type(); \ ++} while (0) ++ ++#define PICK_OP_RET(op, lock...) \ ++({ \ ++ unsigned long __ret; \ ++ \ ++ if (TYPE_EQUAL((lock), raw_spinlock_t)) \ ++ __ret = __spin##op((raw_spinlock_t *)(lock)); \ ++ else if (TYPE_EQUAL(lock, spinlock_t)) \ ++ __ret = _spin##op((spinlock_t *)(lock)); \ ++ else __ret = __bad_spinlock_type(); \ ++ \ ++ __ret; \ ++}) ++ ++#define PICK_OP2(op, lock, flags) \ ++do { \ ++ if (TYPE_EQUAL((lock), raw_spinlock_t)) \ ++ __spin##op((raw_spinlock_t *)(lock), flags); \ ++ else if (TYPE_EQUAL(lock, spinlock_t)) \ ++ _spin##op((spinlock_t *)(lock), flags); \ ++ else __bad_spinlock_type(); \ ++} while (0) ++ ++#define PICK_OP2_RET(op, lock, flags) \ ++({ \ ++ unsigned long __ret; \ ++ \ ++ if (TYPE_EQUAL((lock), raw_spinlock_t)) \ ++ __ret = __spin##op((raw_spinlock_t *)(lock), flags); \ ++ else if (TYPE_EQUAL(lock, spinlock_t)) \ ++ __ret = _spin##op((spinlock_t *)(lock), flags); \ ++ else __bad_spinlock_type(); \ ++ \ ++ __ret; \ ++}) ++ ++extern void __lockfunc rt_write_lock(rwlock_t *rwlock); ++extern void __lockfunc rt_read_lock(rwlock_t *rwlock); ++extern int __lockfunc rt_write_trylock(rwlock_t *rwlock); ++extern int __lockfunc rt_read_trylock(rwlock_t *rwlock); ++extern void __lockfunc rt_write_unlock(rwlock_t *rwlock); ++extern void __lockfunc rt_read_unlock(rwlock_t *rwlock); ++extern unsigned long __lockfunc rt_write_lock_irqsave(rwlock_t *rwlock); ++extern unsigned long __lockfunc rt_read_lock_irqsave(rwlock_t *rwlock); ++extern void ++__rt_rwlock_init(rwlock_t *rwlock, char *name, struct lock_class_key *key); ++ ++#define _rwlock_init(rwl, n, f, l) \ ++do { \ ++ static struct lock_class_key __key; \ ++ \ ++ __rt_rwlock_init(rwl, n, &__key); \ ++} while (0) ++ ++#ifdef CONFIG_PREEMPT_RT ++# define rt_read_can_lock(rwl) (!rt_mutex_is_locked(&(rwl)->lock)) ++# define rt_write_can_lock(rwl) (!rt_mutex_is_locked(&(rwl)->lock)) ++#else ++ extern int rt_rwlock_can_lock_never_call_on_non_rt(rwlock_t *rwlock); ++# define rt_read_can_lock(rwl) rt_rwlock_can_lock_never_call_on_non_rt(rwl) ++# define rt_write_can_lock(rwl) rt_rwlock_can_lock_never_call_on_non_rt(rwl) ++#endif ++ ++# define _read_can_lock(rwl) rt_read_can_lock(rwl) ++# define _write_can_lock(rwl) rt_write_can_lock(rwl) ++ ++# define _read_trylock(rwl) rt_read_trylock(rwl) ++# define _write_trylock(rwl) rt_write_trylock(rwl) ++# define _write_trylock_irqsave(rwl, flags) \ ++ rt_write_trylock_irqsave(rwl, flags) ++ ++# define _read_lock(rwl) rt_read_lock(rwl) ++# define _write_lock(rwl) rt_write_lock(rwl) ++# define _read_unlock(rwl) rt_read_unlock(rwl) ++# define _write_unlock(rwl) rt_write_unlock(rwl) ++ ++# define _read_lock_bh(rwl) rt_read_lock(rwl) ++# define _write_lock_bh(rwl) rt_write_lock(rwl) ++# define _read_unlock_bh(rwl) rt_read_unlock(rwl) ++# define _write_unlock_bh(rwl) rt_write_unlock(rwl) ++ ++# define _read_lock_irq(rwl) rt_read_lock(rwl) ++# define _write_lock_irq(rwl) rt_write_lock(rwl) ++# define _read_unlock_irq(rwl) rt_read_unlock(rwl) ++# define _write_unlock_irq(rwl) rt_write_unlock(rwl) ++ ++# define _read_lock_irqsave(rwl) rt_read_lock_irqsave(rwl) ++# define _write_lock_irqsave(rwl) rt_write_lock_irqsave(rwl) ++ ++# define _read_unlock_irqrestore(rwl, f) rt_read_unlock(rwl) ++# define _write_unlock_irqrestore(rwl, f) rt_write_unlock(rwl) ++ ++#define __PICK_RW_OP(optype, op, lock) \ ++do { \ ++ if (TYPE_EQUAL((lock), raw_rwlock_t)) \ ++ __##optype##op((raw_rwlock_t *)(lock)); \ ++ else if (TYPE_EQUAL(lock, rwlock_t)) \ ++ ##op((rwlock_t *)(lock)); \ ++ else __bad_rwlock_type(); \ ++} while (0) ++ ++#define PICK_RW_OP(optype, op, lock) \ ++do { \ ++ if (TYPE_EQUAL((lock), raw_rwlock_t)) \ ++ __##optype##op((raw_rwlock_t *)(lock)); \ ++ else if (TYPE_EQUAL(lock, rwlock_t)) \ ++ _##optype##op((rwlock_t *)(lock)); \ ++ else __bad_rwlock_type(); \ ++} while (0) ++ ++#define __PICK_RW_OP_RET(optype, op, lock...) \ ++({ \ ++ unsigned long __ret; \ ++ \ ++ if (TYPE_EQUAL((lock), raw_rwlock_t)) \ ++ __ret = __##optype##op((raw_rwlock_t *)(lock)); \ ++ else if (TYPE_EQUAL(lock, rwlock_t)) \ ++ __ret = _##optype##op((rwlock_t *)(lock)); \ ++ else __ret = __bad_rwlock_type(); \ ++ \ ++ __ret; \ ++}) ++ ++#define PICK_RW_OP_RET(optype, op, lock...) \ ++({ \ ++ unsigned long __ret; \ ++ \ ++ if (TYPE_EQUAL((lock), raw_rwlock_t)) \ ++ __ret = __##optype##op((raw_rwlock_t *)(lock)); \ ++ else if (TYPE_EQUAL(lock, rwlock_t)) \ ++ __ret = _##optype##op((rwlock_t *)(lock)); \ ++ else __ret = __bad_rwlock_type(); \ ++ \ ++ __ret; \ ++}) ++ ++#define PICK_RW_OP2(optype, op, lock, flags) \ ++do { \ ++ if (TYPE_EQUAL((lock), raw_rwlock_t)) \ ++ __##optype##op((raw_rwlock_t *)(lock), flags); \ ++ else if (TYPE_EQUAL(lock, rwlock_t)) \ ++ _##optype##op((rwlock_t *)(lock), flags); \ ++ else __bad_rwlock_type(); \ ++} while (0) ++ ++#define PICK_RW_OP2_RET(optype, op, lock, flags) \ ++({ \ ++ unsigned long __ret; \ ++ \ ++ if (TYPE_EQUAL((lock), raw_rwlock_t)) \ ++ __ret = __##optype##op((raw_rwlock_t *)(lock), flags); \ ++ else if (TYPE_EQUAL(lock, rwlock_t)) \ ++ __ret = _##optype##op((rwlock_t *)(lock), flags); \ ++ else __bad_rwlock_type(); \ ++ \ ++ __ret; \ ++}) ++ ++#ifdef CONFIG_DEBUG_SPINLOCK ++ extern void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name, ++ struct lock_class_key *key); ++# define _raw_spin_lock_init(lock) \ ++do { \ ++ static struct lock_class_key __key; \ ++ \ ++ __raw_spin_lock_init((lock), #lock, &__key); \ ++} while (0) ++ ++#else ++#define __raw_spin_lock_init(lock) \ ++ do { *(lock) = RAW_SPIN_LOCK_UNLOCKED(lock); } while (0) ++# define _raw_spin_lock_init(lock) __raw_spin_lock_init(lock) ++#endif ++ ++#define PICK_OP_INIT(op, lock) \ ++do { \ ++ if (TYPE_EQUAL((lock), raw_spinlock_t)) \ ++ _raw_spin##op((raw_spinlock_t *)(lock)); \ ++ else if (TYPE_EQUAL(lock, spinlock_t)) \ ++ _spin##op((spinlock_t *)(lock), #lock, __FILE__, __LINE__); \ ++ else __bad_spinlock_type(); \ ++} while (0) ++ ++ ++#define spin_lock_init(lock) PICK_OP_INIT(_lock_init, lock) ++ ++#ifdef CONFIG_DEBUG_SPINLOCK ++ extern void __raw_rwlock_init(raw_rwlock_t *lock, const char *name, ++ struct lock_class_key *key); ++# define _raw_rwlock_init(lock) \ ++do { \ ++ static struct lock_class_key __key; \ ++ \ ++ __raw_rwlock_init((lock), #lock, &__key); \ ++} while (0) ++#else ++#define __raw_rwlock_init(lock) \ ++ do { *(lock) = RAW_RW_LOCK_UNLOCKED(lock); } while (0) ++# define _raw_rwlock_init(lock) __raw_rwlock_init(lock) ++#endif ++ ++#define __PICK_RW_OP_INIT(optype, op, lock) \ ++do { \ ++ if (TYPE_EQUAL((lock), raw_rwlock_t)) \ ++ _raw_##optype##op((raw_rwlock_t *)(lock)); \ ++ else if (TYPE_EQUAL(lock, rwlock_t)) \ ++ _##optype##op((rwlock_t *)(lock), #lock, __FILE__, __LINE__);\ ++ else __bad_spinlock_type(); \ ++} while (0) ++ ++#define rwlock_init(lock) __PICK_RW_OP_INIT(rwlock, _init, lock) ++ ++#define __spin_is_locked(lock) __raw_spin_is_locked(&(lock)->raw_lock) ++ ++#define spin_is_locked(lock) PICK_OP_RET(_is_locked, lock) ++ ++#define __spin_unlock_wait(lock) __raw_spin_unlock_wait(&(lock)->raw_lock) + ++#define spin_unlock_wait(lock) PICK_OP(_unlock_wait, lock) + /* + * Define the various spin_lock and rw_lock methods. Note we define these + * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various + * methods are defined as nops in the case they are not required. + */ +-#define spin_trylock(lock) __cond_lock(lock, _spin_trylock(lock)) +-#define read_trylock(lock) __cond_lock(lock, _read_trylock(lock)) +-#define write_trylock(lock) __cond_lock(lock, _write_trylock(lock)) ++// #define spin_trylock(lock) _spin_trylock(lock) ++#define spin_trylock(lock) __cond_lock(lock, PICK_OP_RET(_trylock, lock)) ++ ++//#define read_trylock(lock) _read_trylock(lock) ++#define read_trylock(lock) __cond_lock(lock, PICK_RW_OP_RET(read, _trylock, lock)) ++ ++//#define write_trylock(lock) _write_trylock(lock) ++#define write_trylock(lock) __cond_lock(lock, PICK_RW_OP_RET(write, _trylock, lock)) ++ ++#define write_trylock_irqsave(lock, flags) \ ++ __cond_lock(lock, PICK_RW_OP2_RET(write, _trylock_irqsave, lock, &flags)) ++ ++#define __spin_can_lock(lock) __raw_spin_can_lock(&(lock)->raw_lock) ++#define __read_can_lock(lock) __raw_read_can_lock(&(lock)->raw_lock) ++#define __write_can_lock(lock) __raw_write_can_lock(&(lock)->raw_lock) ++ ++#define spin_can_lock(lock) \ ++ __cond_lock(lock, PICK_OP_RET(_can_lock, lock)) + +-#define spin_lock(lock) _spin_lock(lock) ++#define read_can_lock(lock) \ ++ __cond_lock(lock, PICK_RW_OP_RET(read, _can_lock, lock)) ++ ++#define write_can_lock(lock) \ ++ __cond_lock(lock, PICK_RW_OP_RET(write, _can_lock, lock)) ++ ++// #define spin_lock(lock) _spin_lock(lock) ++#define spin_lock(lock) PICK_OP(_lock, lock) + + #ifdef CONFIG_DEBUG_LOCK_ALLOC +-# define spin_lock_nested(lock, subclass) _spin_lock_nested(lock, subclass) ++# define spin_lock_nested(lock, subclass) PICK_OP2(_lock_nested, lock, subclass) + #else +-# define spin_lock_nested(lock, subclass) _spin_lock(lock) ++# define spin_lock_nested(lock, subclass) spin_lock(lock) + #endif + +-#define write_lock(lock) _write_lock(lock) +-#define read_lock(lock) _read_lock(lock) ++//#define write_lock(lock) _write_lock(lock) ++#define write_lock(lock) PICK_RW_OP(write, _lock, lock) + +-#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) ++// #define read_lock(lock) _read_lock(lock) ++#define read_lock(lock) PICK_RW_OP(read, _lock, lock) + +-#define spin_lock_irqsave(lock, flags) flags = _spin_lock_irqsave(lock) +-#define read_lock_irqsave(lock, flags) flags = _read_lock_irqsave(lock) +-#define write_lock_irqsave(lock, flags) flags = _write_lock_irqsave(lock) ++# define spin_lock_irqsave(lock, flags) \ ++do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ flags = PICK_OP_RET(_lock_irqsave, lock); \ ++} while (0) + + #ifdef CONFIG_DEBUG_LOCK_ALLOC +-#define spin_lock_irqsave_nested(lock, flags, subclass) \ +- flags = _spin_lock_irqsave_nested(lock, subclass) ++# define spin_lock_irqsave_nested(lock, flags, subclass) \ ++do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ flags = PICK_OP2_RET(_lock_irqsave_nested, lock, subclass); \ ++} while (0) + #else +-#define spin_lock_irqsave_nested(lock, flags, subclass) \ +- flags = _spin_lock_irqsave(lock) ++# define spin_lock_irqsave_nested(lock, flags, subclass) \ ++ spin_lock_irqsave(lock, flags) + #endif + +-#else ++# define read_lock_irqsave(lock, flags) \ ++do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ flags = PICK_RW_OP_RET(read, _lock_irqsave, lock); \ ++} while (0) + +-#define spin_lock_irqsave(lock, flags) _spin_lock_irqsave(lock, flags) +-#define read_lock_irqsave(lock, flags) _read_lock_irqsave(lock, flags) +-#define write_lock_irqsave(lock, flags) _write_lock_irqsave(lock, flags) +-#define spin_lock_irqsave_nested(lock, flags, subclass) \ +- spin_lock_irqsave(lock, flags) ++# define write_lock_irqsave(lock, flags) \ ++do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ flags = PICK_RW_OP_RET(write, _lock_irqsave, lock); \ ++} while (0) + +-#endif ++// #define spin_lock_irq(lock) _spin_lock_irq(lock) ++// #define spin_lock_bh(lock) _spin_lock_bh(lock) ++#define spin_lock_irq(lock) PICK_OP(_lock_irq, lock) ++#define spin_lock_bh(lock) PICK_OP(_lock_bh, lock) ++ ++// #define read_lock_irq(lock) _read_lock_irq(lock) ++// #define read_lock_bh(lock) _read_lock_bh(lock) ++#define read_lock_irq(lock) PICK_RW_OP(read, _lock_irq, lock) ++#define read_lock_bh(lock) PICK_RW_OP(read, _lock_bh, lock) ++ ++// #define write_lock_irq(lock) _write_lock_irq(lock) ++// #define write_lock_bh(lock) _write_lock_bh(lock) ++#define write_lock_irq(lock) PICK_RW_OP(write, _lock_irq, lock) ++#define write_lock_bh(lock) PICK_RW_OP(write, _lock_bh, lock) ++ ++// #define spin_unlock(lock) _spin_unlock(lock) ++// #define write_unlock(lock) _write_unlock(lock) ++// #define read_unlock(lock) _read_unlock(lock) ++#define spin_unlock(lock) PICK_OP(_unlock, lock) ++#define read_unlock(lock) PICK_RW_OP(read, _unlock, lock) ++#define write_unlock(lock) PICK_RW_OP(write, _unlock, lock) ++ ++// #define spin_unlock(lock) _spin_unlock_no_resched(lock) ++#define spin_unlock_no_resched(lock) \ ++ PICK_OP(_unlock_no_resched, lock) ++ ++//#define spin_unlock_irqrestore(lock, flags) ++// _spin_unlock_irqrestore(lock, flags) ++//#define spin_unlock_irq(lock) _spin_unlock_irq(lock) ++//#define spin_unlock_bh(lock) _spin_unlock_bh(lock) ++#define spin_unlock_irqrestore(lock, flags) \ ++do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ PICK_OP2(_unlock_irqrestore, lock, flags); \ ++} while (0) + +-#define spin_lock_irq(lock) _spin_lock_irq(lock) +-#define spin_lock_bh(lock) _spin_lock_bh(lock) ++#define spin_unlock_irq(lock) PICK_OP(_unlock_irq, lock) ++#define spin_unlock_bh(lock) PICK_OP(_unlock_bh, lock) + +-#define read_lock_irq(lock) _read_lock_irq(lock) +-#define read_lock_bh(lock) _read_lock_bh(lock) ++// #define read_unlock_irqrestore(lock, flags) ++// _read_unlock_irqrestore(lock, flags) ++// #define read_unlock_irq(lock) _read_unlock_irq(lock) ++// #define read_unlock_bh(lock) _read_unlock_bh(lock) ++#define read_unlock_irqrestore(lock, flags) \ ++do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ PICK_RW_OP2(read, _unlock_irqrestore, lock, flags); \ ++} while (0) ++ ++#define read_unlock_irq(lock) PICK_RW_OP(read, _unlock_irq, lock) ++#define read_unlock_bh(lock) PICK_RW_OP(read, _unlock_bh, lock) ++ ++// #define write_unlock_irqrestore(lock, flags) ++// _write_unlock_irqrestore(lock, flags) ++// #define write_unlock_irq(lock) _write_unlock_irq(lock) ++// #define write_unlock_bh(lock) _write_unlock_bh(lock) ++#define write_unlock_irqrestore(lock, flags) \ ++do { \ ++ BUILD_CHECK_IRQ_FLAGS(flags); \ ++ PICK_RW_OP2(write, _unlock_irqrestore, lock, flags); \ ++} while (0) ++#define write_unlock_irq(lock) PICK_RW_OP(write, _unlock_irq, lock) ++#define write_unlock_bh(lock) PICK_RW_OP(write, _unlock_bh, lock) ++ ++// #define spin_trylock_bh(lock) _spin_trylock_bh(lock) ++#define spin_trylock_bh(lock) __cond_lock(lock, PICK_OP_RET(_trylock_bh, lock)) ++ ++// #define spin_trylock_irq(lock) ++ ++#define spin_trylock_irq(lock) __cond_lock(lock, PICK_OP_RET(_trylock_irq, lock)) ++ ++// #define spin_trylock_irqsave(lock, flags) ++ ++#define spin_trylock_irqsave(lock, flags) \ ++ __cond_lock(lock, PICK_OP2_RET(_trylock_irqsave, lock, &flags)) ++ ++/* "lock on reference count zero" */ ++#ifndef ATOMIC_DEC_AND_LOCK ++# include ++ extern int __atomic_dec_and_spin_lock(atomic_t *atomic, raw_spinlock_t *lock); ++#endif ++ ++#define atomic_dec_and_lock(atomic, lock) \ ++__cond_lock(lock, ({ \ ++ unsigned long __ret; \ ++ \ ++ if (TYPE_EQUAL(lock, raw_spinlock_t)) \ ++ __ret = __atomic_dec_and_spin_lock(atomic, \ ++ (raw_spinlock_t *)(lock)); \ ++ else if (TYPE_EQUAL(lock, spinlock_t)) \ ++ __ret = _atomic_dec_and_spin_lock(atomic, \ ++ (spinlock_t *)(lock)); \ ++ else __ret = __bad_spinlock_type(); \ ++ \ ++ __ret; \ ++})) + +-#define write_lock_irq(lock) _write_lock_irq(lock) +-#define write_lock_bh(lock) _write_lock_bh(lock) + + /* +- * We inline the unlock functions in the nondebug case: ++ * bit-based spin_lock() ++ * ++ * Don't use this unless you really need to: spin_lock() and spin_unlock() ++ * are significantly faster. + */ +-#if defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) || \ +- !defined(CONFIG_SMP) +-# define spin_unlock(lock) _spin_unlock(lock) +-# define read_unlock(lock) _read_unlock(lock) +-# define write_unlock(lock) _write_unlock(lock) +-# define spin_unlock_irq(lock) _spin_unlock_irq(lock) +-# define read_unlock_irq(lock) _read_unlock_irq(lock) +-# define write_unlock_irq(lock) _write_unlock_irq(lock) +-#else +-# define spin_unlock(lock) \ +- do {__raw_spin_unlock(&(lock)->raw_lock); __release(lock); } while (0) +-# define read_unlock(lock) \ +- do {__raw_read_unlock(&(lock)->raw_lock); __release(lock); } while (0) +-# define write_unlock(lock) \ +- do {__raw_write_unlock(&(lock)->raw_lock); __release(lock); } while (0) +-# define spin_unlock_irq(lock) \ +-do { \ +- __raw_spin_unlock(&(lock)->raw_lock); \ +- __release(lock); \ +- local_irq_enable(); \ +-} while (0) +-# define read_unlock_irq(lock) \ +-do { \ +- __raw_read_unlock(&(lock)->raw_lock); \ +- __release(lock); \ +- local_irq_enable(); \ +-} while (0) +-# define write_unlock_irq(lock) \ +-do { \ +- __raw_write_unlock(&(lock)->raw_lock); \ +- __release(lock); \ +- local_irq_enable(); \ +-} while (0) ++static inline void bit_spin_lock(int bitnum, unsigned long *addr) ++{ ++ /* ++ * Assuming the lock is uncontended, this never enters ++ * the body of the outer loop. If it is contended, then ++ * within the inner loop a non-atomic test is used to ++ * busywait with less bus contention for a good time to ++ * attempt to acquire the lock bit. ++ */ ++#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) ++ while (test_and_set_bit(bitnum, addr)) ++ while (test_bit(bitnum, addr)) ++ cpu_relax(); + #endif ++ __acquire(bitlock); ++} + +-#define spin_unlock_irqrestore(lock, flags) \ +- _spin_unlock_irqrestore(lock, flags) +-#define spin_unlock_bh(lock) _spin_unlock_bh(lock) +- +-#define read_unlock_irqrestore(lock, flags) \ +- _read_unlock_irqrestore(lock, flags) +-#define read_unlock_bh(lock) _read_unlock_bh(lock) +- +-#define write_unlock_irqrestore(lock, flags) \ +- _write_unlock_irqrestore(lock, flags) +-#define write_unlock_bh(lock) _write_unlock_bh(lock) +- +-#define spin_trylock_bh(lock) __cond_lock(lock, _spin_trylock_bh(lock)) +- +-#define spin_trylock_irq(lock) \ +-({ \ +- local_irq_disable(); \ +- spin_trylock(lock) ? \ +- 1 : ({ local_irq_enable(); 0; }); \ +-}) ++/* ++ * Return true if it was acquired ++ */ ++static inline int bit_spin_trylock(int bitnum, unsigned long *addr) ++{ ++#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) ++ if (test_and_set_bit(bitnum, addr)) ++ return 0; ++#endif ++ __acquire(bitlock); ++ return 1; ++} + +-#define spin_trylock_irqsave(lock, flags) \ +-({ \ +- local_irq_save(flags); \ +- spin_trylock(lock) ? \ +- 1 : ({ local_irq_restore(flags); 0; }); \ +-}) ++/* ++ * bit-based spin_unlock() ++ */ ++static inline void bit_spin_unlock(int bitnum, unsigned long *addr) ++{ ++#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) ++ BUG_ON(!test_bit(bitnum, addr)); ++ smp_mb__before_clear_bit(); ++ clear_bit(bitnum, addr); ++#endif ++ __release(bitlock); ++} + +-#define write_trylock_irqsave(lock, flags) \ +-({ \ +- local_irq_save(flags); \ +- write_trylock(lock) ? \ +- 1 : ({ local_irq_restore(flags); 0; }); \ +-}) ++/* ++ * Return true if the lock is held. ++ */ ++static inline int bit_spin_is_locked(int bitnum, unsigned long *addr) ++{ ++#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) ++ return test_bit(bitnum, addr); ++#else ++ return 1; ++#endif ++} + +-#define write_trylock_irqsave(lock, flags) \ +-({ \ +- local_irq_save(flags); \ +- write_trylock(lock) ? \ +- 1 : ({ local_irq_restore(flags); 0; }); \ +-}) ++/** ++ * __raw_spin_can_lock - would __raw_spin_trylock() succeed? ++ * @lock: the spinlock in question. ++ */ ++#define __raw_spin_can_lock(lock) (!__raw_spin_is_locked(lock)) + + /* + * Locks two spinlocks l1 and l2. + * l1_first indicates if spinlock l1 should be taken first. + */ +-static inline void double_spin_lock(spinlock_t *l1, spinlock_t *l2, +- bool l1_first) ++static inline void ++raw_double_spin_lock(raw_spinlock_t *l1, raw_spinlock_t *l2, bool l1_first) ++ __acquires(l1) ++ __acquires(l2) ++{ ++ if (l1_first) { ++ spin_lock(l1); ++ spin_lock(l2); ++ } else { ++ spin_lock(l2); ++ spin_lock(l1); ++ } ++} ++ ++static inline void ++double_spin_lock(spinlock_t *l1, spinlock_t *l2, bool l1_first) + __acquires(l1) + __acquires(l2) + { +@@ -314,13 +745,15 @@ static inline void double_spin_lock(spin + } + } + ++ + /* + * Unlocks two spinlocks l1 and l2. + * l1_taken_first indicates if spinlock l1 was taken first and therefore + * should be released after spinlock l2. + */ +-static inline void double_spin_unlock(spinlock_t *l1, spinlock_t *l2, +- bool l1_taken_first) ++static inline void ++raw_double_spin_unlock(raw_spinlock_t *l1, raw_spinlock_t *l2, ++ bool l1_taken_first) + __releases(l1) + __releases(l2) + { +@@ -333,24 +766,19 @@ static inline void double_spin_unlock(sp + } + } + +-/* +- * Pull the atomic_t declaration: +- * (asm-mips/atomic.h needs above definitions) +- */ +-#include +-/** +- * atomic_dec_and_lock - lock on reaching reference count zero +- * @atomic: the atomic counter +- * @lock: the spinlock in question +- */ +-extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); +-#define atomic_dec_and_lock(atomic, lock) \ +- __cond_lock(lock, _atomic_dec_and_lock(atomic, lock)) +- +-/** +- * spin_can_lock - would spin_trylock() succeed? +- * @lock: the spinlock in question. +- */ +-#define spin_can_lock(lock) (!spin_is_locked(lock)) ++static inline void ++double_spin_unlock(spinlock_t *l1, spinlock_t *l2, bool l1_taken_first) ++ __releases(l1) ++ __releases(l2) ++{ ++ if (l1_taken_first) { ++ spin_unlock(l2); ++ spin_unlock(l1); ++ } else { ++ spin_unlock(l1); ++ spin_unlock(l2); ++ } ++} + + #endif /* __LINUX_SPINLOCK_H */ ++ +Index: linux-2.6.24.7-rt27/include/linux/spinlock_api_smp.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/spinlock_api_smp.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/spinlock_api_smp.h 2009-02-08 00:02:01.000000000 -0500 +@@ -19,43 +19,58 @@ int in_lock_functions(unsigned long addr + + #define assert_spin_locked(x) BUG_ON(!spin_is_locked(x)) + +-void __lockfunc _spin_lock(spinlock_t *lock) __acquires(lock); +-void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass) +- __acquires(lock); +-void __lockfunc _read_lock(rwlock_t *lock) __acquires(lock); +-void __lockfunc _write_lock(rwlock_t *lock) __acquires(lock); +-void __lockfunc _spin_lock_bh(spinlock_t *lock) __acquires(lock); +-void __lockfunc _read_lock_bh(rwlock_t *lock) __acquires(lock); +-void __lockfunc _write_lock_bh(rwlock_t *lock) __acquires(lock); +-void __lockfunc _spin_lock_irq(spinlock_t *lock) __acquires(lock); +-void __lockfunc _read_lock_irq(rwlock_t *lock) __acquires(lock); +-void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(lock); +-unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) +- __acquires(lock); +-unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclass) +- __acquires(lock); +-unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) +- __acquires(lock); +-unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) +- __acquires(lock); +-int __lockfunc _spin_trylock(spinlock_t *lock); +-int __lockfunc _read_trylock(rwlock_t *lock); +-int __lockfunc _write_trylock(rwlock_t *lock); +-int __lockfunc _spin_trylock_bh(spinlock_t *lock); +-void __lockfunc _spin_unlock(spinlock_t *lock) __releases(lock); +-void __lockfunc _read_unlock(rwlock_t *lock) __releases(lock); +-void __lockfunc _write_unlock(rwlock_t *lock) __releases(lock); +-void __lockfunc _spin_unlock_bh(spinlock_t *lock) __releases(lock); +-void __lockfunc _read_unlock_bh(rwlock_t *lock) __releases(lock); +-void __lockfunc _write_unlock_bh(rwlock_t *lock) __releases(lock); +-void __lockfunc _spin_unlock_irq(spinlock_t *lock) __releases(lock); +-void __lockfunc _read_unlock_irq(rwlock_t *lock) __releases(lock); +-void __lockfunc _write_unlock_irq(rwlock_t *lock) __releases(lock); +-void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) +- __releases(lock); +-void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) +- __releases(lock); +-void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) +- __releases(lock); ++#define ACQUIRE_SPIN __acquires(lock) ++#define ACQUIRE_RW __acquires(lock) ++#define RELEASE_SPIN __releases(lock) ++#define RELEASE_RW __releases(lock) ++ ++void __lockfunc __spin_lock(raw_spinlock_t *lock) ACQUIRE_SPIN; ++void __lockfunc __spin_lock_nested(raw_spinlock_t *lock, int subclass) ++ ACQUIRE_SPIN; ++void __lockfunc __read_lock(raw_rwlock_t *lock) ACQUIRE_RW; ++void __lockfunc __write_lock(raw_rwlock_t *lock) ACQUIRE_RW; ++void __lockfunc __spin_lock_bh(raw_spinlock_t *lock) ACQUIRE_SPIN; ++void __lockfunc __read_lock_bh(raw_rwlock_t *lock) ACQUIRE_RW; ++void __lockfunc __write_lock_bh(raw_rwlock_t *lock) ACQUIRE_RW; ++void __lockfunc __spin_lock_irq(raw_spinlock_t *lock) ACQUIRE_SPIN; ++void __lockfunc __read_lock_irq(raw_rwlock_t *lock) ACQUIRE_RW; ++void __lockfunc __write_lock_irq(raw_rwlock_t *lock) ACQUIRE_RW; ++unsigned long __lockfunc __spin_lock_irqsave(raw_spinlock_t *lock) ++ ACQUIRE_SPIN; ++unsigned long __lockfunc ++__spin_lock_irqsave_nested(raw_spinlock_t *lock, int subclass) ACQUIRE_SPIN; ++unsigned long __lockfunc __read_lock_irqsave(raw_rwlock_t *lock) ++ ACQUIRE_RW; ++unsigned long __lockfunc __write_lock_irqsave(raw_rwlock_t *lock) ++ ACQUIRE_RW; ++int __lockfunc __spin_trylock(raw_spinlock_t *lock); ++int __lockfunc ++__spin_trylock_irqsave(raw_spinlock_t *lock, unsigned long *flags); ++int __lockfunc __read_trylock(raw_rwlock_t *lock); ++int __lockfunc __write_trylock(raw_rwlock_t *lock); ++int __lockfunc ++__write_trylock_irqsave(raw_rwlock_t *lock, unsigned long *flags); ++int __lockfunc __spin_trylock_bh(raw_spinlock_t *lock); ++int __lockfunc __spin_trylock_irq(raw_spinlock_t *lock); ++void __lockfunc __spin_unlock(raw_spinlock_t *lock) RELEASE_SPIN; ++void __lockfunc __spin_unlock_no_resched(raw_spinlock_t *lock) ++ RELEASE_SPIN; ++void __lockfunc __read_unlock(raw_rwlock_t *lock) RELEASE_RW; ++void __lockfunc __write_unlock(raw_rwlock_t *lock) RELEASE_RW; ++void __lockfunc __spin_unlock_bh(raw_spinlock_t *lock) RELEASE_SPIN; ++void __lockfunc __read_unlock_bh(raw_rwlock_t *lock) RELEASE_RW; ++void __lockfunc __write_unlock_bh(raw_rwlock_t *lock) RELEASE_RW; ++void __lockfunc __spin_unlock_irq(raw_spinlock_t *lock) RELEASE_SPIN; ++void __lockfunc __read_unlock_irq(raw_rwlock_t *lock) RELEASE_RW; ++void __lockfunc __write_unlock_irq(raw_rwlock_t *lock) RELEASE_RW; ++void __lockfunc ++__spin_unlock_irqrestore(raw_spinlock_t *lock, unsigned long flags) ++ RELEASE_SPIN; ++void __lockfunc ++__read_unlock_irqrestore(raw_rwlock_t *lock, unsigned long flags) ++ RELEASE_RW; ++void ++__lockfunc __write_unlock_irqrestore(raw_rwlock_t *lock, unsigned long flags) ++ RELEASE_RW; + + #endif /* __LINUX_SPINLOCK_API_SMP_H */ +Index: linux-2.6.24.7-rt27/include/linux/spinlock_api_up.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/spinlock_api_up.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/spinlock_api_up.h 2009-02-08 00:02:01.000000000 -0500 +@@ -33,12 +33,22 @@ + #define __LOCK_IRQ(lock) \ + do { local_irq_disable(); __LOCK(lock); } while (0) + +-#define __LOCK_IRQSAVE(lock, flags) \ +- do { local_irq_save(flags); __LOCK(lock); } while (0) ++#define __LOCK_IRQSAVE(lock) \ ++ ({ unsigned long __flags; local_irq_save(__flags); __LOCK(lock); __flags; }) ++ ++#define __TRYLOCK_IRQSAVE(lock, flags) \ ++ ({ local_irq_save(*(flags)); __LOCK(lock); 1; }) ++ ++#define __spin_trylock_irqsave(lock, flags) __TRYLOCK_IRQSAVE(lock, flags) ++ ++#define __write_trylock_irqsave(lock, flags) __TRYLOCK_IRQSAVE(lock, flags) + + #define __UNLOCK(lock) \ + do { preempt_enable(); __release(lock); (void)(lock); } while (0) + ++#define __UNLOCK_NO_RESCHED(lock) \ ++ do { __preempt_enable_no_resched(); __release(lock); (void)(lock); } while (0) ++ + #define __UNLOCK_BH(lock) \ + do { preempt_enable_no_resched(); local_bh_enable(); __release(lock); (void)(lock); } while (0) + +@@ -48,34 +58,36 @@ + #define __UNLOCK_IRQRESTORE(lock, flags) \ + do { local_irq_restore(flags); __UNLOCK(lock); } while (0) + +-#define _spin_lock(lock) __LOCK(lock) +-#define _spin_lock_nested(lock, subclass) __LOCK(lock) +-#define _read_lock(lock) __LOCK(lock) +-#define _write_lock(lock) __LOCK(lock) +-#define _spin_lock_bh(lock) __LOCK_BH(lock) +-#define _read_lock_bh(lock) __LOCK_BH(lock) +-#define _write_lock_bh(lock) __LOCK_BH(lock) +-#define _spin_lock_irq(lock) __LOCK_IRQ(lock) +-#define _read_lock_irq(lock) __LOCK_IRQ(lock) +-#define _write_lock_irq(lock) __LOCK_IRQ(lock) +-#define _spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) +-#define _read_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) +-#define _write_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) +-#define _spin_trylock(lock) ({ __LOCK(lock); 1; }) +-#define _read_trylock(lock) ({ __LOCK(lock); 1; }) +-#define _write_trylock(lock) ({ __LOCK(lock); 1; }) +-#define _spin_trylock_bh(lock) ({ __LOCK_BH(lock); 1; }) +-#define _spin_unlock(lock) __UNLOCK(lock) +-#define _read_unlock(lock) __UNLOCK(lock) +-#define _write_unlock(lock) __UNLOCK(lock) +-#define _spin_unlock_bh(lock) __UNLOCK_BH(lock) +-#define _write_unlock_bh(lock) __UNLOCK_BH(lock) +-#define _read_unlock_bh(lock) __UNLOCK_BH(lock) +-#define _spin_unlock_irq(lock) __UNLOCK_IRQ(lock) +-#define _read_unlock_irq(lock) __UNLOCK_IRQ(lock) +-#define _write_unlock_irq(lock) __UNLOCK_IRQ(lock) +-#define _spin_unlock_irqrestore(lock, flags) __UNLOCK_IRQRESTORE(lock, flags) +-#define _read_unlock_irqrestore(lock, flags) __UNLOCK_IRQRESTORE(lock, flags) +-#define _write_unlock_irqrestore(lock, flags) __UNLOCK_IRQRESTORE(lock, flags) ++#define __spin_lock(lock) __LOCK(lock) ++#define __spin_lock_nested(lock, subclass) __LOCK(lock) ++#define __read_lock(lock) __LOCK(lock) ++#define __write_lock(lock) __LOCK(lock) ++#define __spin_lock_bh(lock) __LOCK_BH(lock) ++#define __read_lock_bh(lock) __LOCK_BH(lock) ++#define __write_lock_bh(lock) __LOCK_BH(lock) ++#define __spin_lock_irq(lock) __LOCK_IRQ(lock) ++#define __read_lock_irq(lock) __LOCK_IRQ(lock) ++#define __write_lock_irq(lock) __LOCK_IRQ(lock) ++#define __spin_lock_irqsave(lock) __LOCK_IRQSAVE(lock) ++#define __read_lock_irqsave(lock) __LOCK_IRQSAVE(lock) ++#define __write_lock_irqsave(lock) __LOCK_IRQSAVE(lock) ++#define __spin_trylock(lock) ({ __LOCK(lock); 1; }) ++#define __read_trylock(lock) ({ __LOCK(lock); 1; }) ++#define __write_trylock(lock) ({ __LOCK(lock); 1; }) ++#define __spin_trylock_bh(lock) ({ __LOCK_BH(lock); 1; }) ++#define __spin_trylock_irq(lock) ({ __LOCK_IRQ(lock); 1; }) ++#define __spin_unlock(lock) __UNLOCK(lock) ++#define __spin_unlock_no_resched(lock) __UNLOCK_NO_RESCHED(lock) ++#define __read_unlock(lock) __UNLOCK(lock) ++#define __write_unlock(lock) __UNLOCK(lock) ++#define __spin_unlock_bh(lock) __UNLOCK_BH(lock) ++#define __write_unlock_bh(lock) __UNLOCK_BH(lock) ++#define __read_unlock_bh(lock) __UNLOCK_BH(lock) ++#define __spin_unlock_irq(lock) __UNLOCK_IRQ(lock) ++#define __read_unlock_irq(lock) __UNLOCK_IRQ(lock) ++#define __write_unlock_irq(lock) __UNLOCK_IRQ(lock) ++#define __spin_unlock_irqrestore(lock, flags) __UNLOCK_IRQRESTORE(lock, flags) ++#define __read_unlock_irqrestore(lock, flags) __UNLOCK_IRQRESTORE(lock, flags) ++#define __write_unlock_irqrestore(lock, flags) __UNLOCK_IRQRESTORE(lock, flags) + + #endif /* __LINUX_SPINLOCK_API_UP_H */ +Index: linux-2.6.24.7-rt27/include/linux/spinlock_types.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/spinlock_types.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/spinlock_types.h 2009-02-08 00:02:01.000000000 -0500 +@@ -15,10 +15,27 @@ + # include + #endif + ++/* ++ * Must define these before including other files, inline functions need them ++ */ ++#define LOCK_SECTION_NAME ".text.lock."KBUILD_BASENAME ++ ++#define LOCK_SECTION_START(extra) \ ++ ".subsection 1\n\t" \ ++ extra \ ++ ".ifndef " LOCK_SECTION_NAME "\n\t" \ ++ LOCK_SECTION_NAME ":\n\t" \ ++ ".endif\n" ++ ++#define LOCK_SECTION_END \ ++ ".previous\n\t" ++ ++#define __lockfunc fastcall __attribute__((section(".spinlock.text"))) ++ + #include + + typedef struct { +- raw_spinlock_t raw_lock; ++ __raw_spinlock_t raw_lock; + #if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) + unsigned int break_lock; + #endif +@@ -29,12 +46,12 @@ typedef struct { + #ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; + #endif +-} spinlock_t; ++} raw_spinlock_t; + + #define SPINLOCK_MAGIC 0xdead4ead + + typedef struct { +- raw_rwlock_t raw_lock; ++ __raw_rwlock_t raw_lock; + #if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) + unsigned int break_lock; + #endif +@@ -45,7 +62,7 @@ typedef struct { + #ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; + #endif +-} rwlock_t; ++} raw_rwlock_t; + + #define RWLOCK_MAGIC 0xdeaf1eed + +@@ -64,24 +81,24 @@ typedef struct { + #endif + + #ifdef CONFIG_DEBUG_SPINLOCK +-# define __SPIN_LOCK_UNLOCKED(lockname) \ +- (spinlock_t) { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \ ++# define _RAW_SPIN_LOCK_UNLOCKED(lockname) \ ++ { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \ + .magic = SPINLOCK_MAGIC, \ + .owner = SPINLOCK_OWNER_INIT, \ + .owner_cpu = -1, \ + SPIN_DEP_MAP_INIT(lockname) } +-#define __RW_LOCK_UNLOCKED(lockname) \ +- (rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED, \ ++#define _RAW_RW_LOCK_UNLOCKED(lockname) \ ++ { .raw_lock = __RAW_RW_LOCK_UNLOCKED, \ + .magic = RWLOCK_MAGIC, \ + .owner = SPINLOCK_OWNER_INIT, \ + .owner_cpu = -1, \ + RW_DEP_MAP_INIT(lockname) } + #else +-# define __SPIN_LOCK_UNLOCKED(lockname) \ +- (spinlock_t) { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \ ++# define _RAW_SPIN_LOCK_UNLOCKED(lockname) \ ++ { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \ + SPIN_DEP_MAP_INIT(lockname) } +-#define __RW_LOCK_UNLOCKED(lockname) \ +- (rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED, \ ++# define _RAW_RW_LOCK_UNLOCKED(lockname) \ ++ { .raw_lock = __RAW_RW_LOCK_UNLOCKED, \ + RW_DEP_MAP_INIT(lockname) } + #endif + +@@ -91,10 +108,22 @@ typedef struct { + * Please use DEFINE_SPINLOCK()/DEFINE_RWLOCK() or + * __SPIN_LOCK_UNLOCKED()/__RW_LOCK_UNLOCKED() as appropriate. + */ +-#define SPIN_LOCK_UNLOCKED __SPIN_LOCK_UNLOCKED(old_style_spin_init) +-#define RW_LOCK_UNLOCKED __RW_LOCK_UNLOCKED(old_style_rw_init) + +-#define DEFINE_SPINLOCK(x) spinlock_t x = __SPIN_LOCK_UNLOCKED(x) +-#define DEFINE_RWLOCK(x) rwlock_t x = __RW_LOCK_UNLOCKED(x) ++# define RAW_SPIN_LOCK_UNLOCKED(lockname) \ ++ (raw_spinlock_t) _RAW_SPIN_LOCK_UNLOCKED(lockname) ++ ++# define RAW_RW_LOCK_UNLOCKED(lockname) \ ++ (raw_rwlock_t) _RAW_RW_LOCK_UNLOCKED(lockname) ++ ++#define DEFINE_RAW_SPINLOCK(name) \ ++ raw_spinlock_t name __cacheline_aligned_in_smp = \ ++ RAW_SPIN_LOCK_UNLOCKED(name) ++ ++#define __DEFINE_RAW_SPINLOCK(name) \ ++ raw_spinlock_t name = RAW_SPIN_LOCK_UNLOCKED(name) ++ ++#define DEFINE_RAW_RWLOCK(name) \ ++ raw_rwlock_t name __cacheline_aligned_in_smp = \ ++ RAW_RW_LOCK_UNLOCKED(name) + + #endif /* __LINUX_SPINLOCK_TYPES_H */ +Index: linux-2.6.24.7-rt27/include/linux/spinlock_types_up.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/spinlock_types_up.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/spinlock_types_up.h 2009-02-08 00:02:01.000000000 -0500 +@@ -16,13 +16,13 @@ + + typedef struct { + volatile unsigned int slock; +-} raw_spinlock_t; ++} __raw_spinlock_t; + + #define __RAW_SPIN_LOCK_UNLOCKED { 1 } + + #else + +-typedef struct { } raw_spinlock_t; ++typedef struct { } __raw_spinlock_t; + + #define __RAW_SPIN_LOCK_UNLOCKED { } + +@@ -30,7 +30,7 @@ typedef struct { } raw_spinlock_t; + + typedef struct { + /* no debug version on UP */ +-} raw_rwlock_t; ++} __raw_rwlock_t; + + #define __RAW_RW_LOCK_UNLOCKED { } + +Index: linux-2.6.24.7-rt27/include/linux/spinlock_up.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/spinlock_up.h 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/spinlock_up.h 2009-02-08 00:02:01.000000000 -0500 +@@ -20,19 +20,19 @@ + #ifdef CONFIG_DEBUG_SPINLOCK + #define __raw_spin_is_locked(x) ((x)->slock == 0) + +-static inline void __raw_spin_lock(raw_spinlock_t *lock) ++static inline void __raw_spin_lock(__raw_spinlock_t *lock) + { + lock->slock = 0; + } + + static inline void +-__raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) ++__raw_spin_lock_flags(__raw_spinlock_t *lock, unsigned long flags) + { + local_irq_save(flags); + lock->slock = 0; + } + +-static inline int __raw_spin_trylock(raw_spinlock_t *lock) ++static inline int __raw_spin_trylock(__raw_spinlock_t *lock) + { + char oldval = lock->slock; + +@@ -41,7 +41,7 @@ static inline int __raw_spin_trylock(raw + return oldval > 0; + } + +-static inline void __raw_spin_unlock(raw_spinlock_t *lock) ++static inline void __raw_spin_unlock(__raw_spinlock_t *lock) + { + lock->slock = 1; + } +Index: linux-2.6.24.7-rt27/kernel/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/Makefile 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/Makefile 2009-02-08 00:02:01.000000000 -0500 +@@ -7,7 +7,7 @@ obj-y = sched.o fork.o exec_domain.o + sysctl.o capability.o ptrace.o timer.o user.o user_namespace.o \ + signal.o sys.o kmod.o workqueue.o pid.o \ + rcupdate.o extable.o params.o posix-timers.o \ +- kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ ++ kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o \ + hrtimer.o rwsem.o latency.o nsproxy.o srcu.o \ + utsname.o notifier.o + +@@ -26,7 +26,10 @@ endif + obj-$(CONFIG_SYSCTL) += sysctl_check.o + obj-$(CONFIG_STACKTRACE) += stacktrace.o + obj-y += time/ ++ifneq ($(CONFIG_PREEMPT_RT),y) ++obj-y += mutex.o + obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o ++endif + obj-$(CONFIG_LOCKDEP) += lockdep.o + ifeq ($(CONFIG_PROC_FS),y) + obj-$(CONFIG_LOCKDEP) += lockdep_proc.o +@@ -38,6 +41,7 @@ endif + obj-$(CONFIG_RT_MUTEXES) += rtmutex.o + obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o + obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o ++obj-$(CONFIG_PREEMPT_RT) += rt.o + obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o + obj-$(CONFIG_SMP) += cpu.o spinlock.o + obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o +Index: linux-2.6.24.7-rt27/kernel/fork.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/fork.c 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/fork.c 2009-02-08 00:02:01.000000000 -0500 +@@ -959,6 +959,9 @@ static void rt_mutex_init_task(struct ta + #ifdef CONFIG_RT_MUTEXES + plist_head_init(&p->pi_waiters, &p->pi_lock); + p->pi_blocked_on = NULL; ++# ifdef CONFIG_DEBUG_RT_MUTEXES ++ p->last_kernel_lock = NULL; ++# endif + #endif + } + +@@ -1154,6 +1157,9 @@ static struct task_struct *copy_process( + retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); + if (retval) + goto bad_fork_cleanup_namespaces; ++#ifdef CONFIG_DEBUG_PREEMPT ++ p->lock_count = 0; ++#endif + + if (pid != &init_struct_pid) { + retval = -ENOMEM; +Index: linux-2.6.24.7-rt27/kernel/futex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/futex.c 2009-02-08 00:00:40.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/futex.c 2009-02-08 00:02:01.000000000 -0500 +@@ -2206,7 +2206,11 @@ static int __init init(void) + futex_cmpxchg_enabled = 1; + + for (i = 0; i < ARRAY_SIZE(futex_queues); i++) { ++#ifdef CONFIG_PREEMPT_RT ++ plist_head_init(&futex_queues[i].chain, NULL); ++#else + plist_head_init(&futex_queues[i].chain, &futex_queues[i].lock); ++#endif + spin_lock_init(&futex_queues[i].lock); + } + +Index: linux-2.6.24.7-rt27/kernel/hrtimer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/hrtimer.c 2009-02-08 00:01:51.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/hrtimer.c 2009-02-08 00:02:01.000000000 -0500 +@@ -1544,7 +1544,7 @@ static void migrate_hrtimers(int cpu) + tick_cancel_sched_timer(cpu); + + local_irq_disable(); +- double_spin_lock(&new_base->lock, &old_base->lock, ++ raw_double_spin_lock(&new_base->lock, &old_base->lock, + smp_processor_id() < cpu); + + for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { +@@ -1552,7 +1552,7 @@ static void migrate_hrtimers(int cpu) + &new_base->clock_base[i]); + } + +- double_spin_unlock(&new_base->lock, &old_base->lock, ++ raw_double_spin_unlock(&new_base->lock, &old_base->lock, + smp_processor_id() < cpu); + local_irq_enable(); + put_cpu_var(hrtimer_bases); +Index: linux-2.6.24.7-rt27/kernel/lockdep.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/lockdep.c 2009-02-08 00:01:37.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/lockdep.c 2009-02-08 00:02:01.000000000 -0500 +@@ -67,7 +67,7 @@ module_param(lock_stat, int, 0644); + * to use a raw spinlock - we really dont want the spinlock + * code to recurse back into the lockdep code... + */ +-static raw_spinlock_t lockdep_lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; ++static __raw_spinlock_t lockdep_lock = (__raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; + + static int graph_lock(void) + { +Index: linux-2.6.24.7-rt27/kernel/rt.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/kernel/rt.c 2009-02-08 00:02:01.000000000 -0500 +@@ -0,0 +1,571 @@ ++/* ++ * kernel/rt.c ++ * ++ * Real-Time Preemption Support ++ * ++ * started by Ingo Molnar: ++ * ++ * Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar ++ * Copyright (C) 2006, Timesys Corp., Thomas Gleixner ++ * ++ * historic credit for proving that Linux spinlocks can be implemented via ++ * RT-aware mutexes goes to many people: The Pmutex project (Dirk Grambow ++ * and others) who prototyped it on 2.4 and did lots of comparative ++ * research and analysis; TimeSys, for proving that you can implement a ++ * fully preemptible kernel via the use of IRQ threading and mutexes; ++ * Bill Huey for persuasively arguing on lkml that the mutex model is the ++ * right one; and to MontaVista, who ported pmutexes to 2.6. ++ * ++ * This code is a from-scratch implementation and is not based on pmutexes, ++ * but the idea of converting spinlocks to mutexes is used here too. ++ * ++ * lock debugging, locking tree, deadlock detection: ++ * ++ * Copyright (C) 2004, LynuxWorks, Inc., Igor Manyilov, Bill Huey ++ * Released under the General Public License (GPL). ++ * ++ * Includes portions of the generic R/W semaphore implementation from: ++ * ++ * Copyright (c) 2001 David Howells (dhowells@redhat.com). ++ * - Derived partially from idea by Andrea Arcangeli ++ * - Derived also from comments by Linus ++ * ++ * Pending ownership of locks and ownership stealing: ++ * ++ * Copyright (C) 2005, Kihon Technologies Inc., Steven Rostedt ++ * ++ * (also by Steven Rostedt) ++ * - Converted single pi_lock to individual task locks. ++ * ++ * By Esben Nielsen: ++ * Doing priority inheritance with help of the scheduler. ++ * ++ * Copyright (C) 2006, Timesys Corp., Thomas Gleixner ++ * - major rework based on Esben Nielsens initial patch ++ * - replaced thread_info references by task_struct refs ++ * - removed task->pending_owner dependency ++ * - BKL drop/reacquire for semaphore style locks to avoid deadlocks ++ * in the scheduler return path as discussed with Steven Rostedt ++ * ++ * Copyright (C) 2006, Kihon Technologies Inc. ++ * Steven Rostedt ++ * - debugged and patched Thomas Gleixner's rework. ++ * - added back the cmpxchg to the rework. ++ * - turned atomic require back on for SMP. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rtmutex_common.h" ++ ++#ifdef CONFIG_PREEMPT_RT ++/* ++ * Unlock these on crash: ++ */ ++void zap_rt_locks(void) ++{ ++ //trace_lock_init(); ++} ++#endif ++ ++/* ++ * struct mutex functions ++ */ ++void _mutex_init(struct mutex *lock, char *name, struct lock_class_key *key) ++{ ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ /* ++ * Make sure we are not reinitializing a held lock: ++ */ ++ debug_check_no_locks_freed((void *)lock, sizeof(*lock)); ++ lockdep_init_map(&lock->dep_map, name, key, 0); ++#endif ++ __rt_mutex_init(&lock->lock, name); ++} ++EXPORT_SYMBOL(_mutex_init); ++ ++void __lockfunc _mutex_lock(struct mutex *lock) ++{ ++ mutex_acquire(&lock->dep_map, 0, 0, _RET_IP_); ++ rt_mutex_lock(&lock->lock); ++} ++EXPORT_SYMBOL(_mutex_lock); ++ ++int __lockfunc _mutex_lock_interruptible(struct mutex *lock) ++{ ++ int ret; ++ ++ mutex_acquire(&lock->dep_map, 0, 0, _RET_IP_); ++ ret = rt_mutex_lock_interruptible(&lock->lock, 0); ++ if (ret) ++ mutex_release(&lock->dep_map, 1, _RET_IP_); ++ return ret; ++} ++EXPORT_SYMBOL(_mutex_lock_interruptible); ++ ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++void __lockfunc _mutex_lock_nested(struct mutex *lock, int subclass) ++{ ++ mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_); ++ rt_mutex_lock(&lock->lock); ++} ++EXPORT_SYMBOL(_mutex_lock_nested); ++ ++int __lockfunc _mutex_lock_interruptible_nested(struct mutex *lock, int subclass) ++{ ++ int ret; ++ ++ mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_); ++ ret = rt_mutex_lock_interruptible(&lock->lock, 0); ++ if (ret) ++ mutex_release(&lock->dep_map, 1, _RET_IP_); ++ return ret; ++} ++EXPORT_SYMBOL(_mutex_lock_interruptible_nested); ++#endif ++ ++int __lockfunc _mutex_trylock(struct mutex *lock) ++{ ++ int ret = rt_mutex_trylock(&lock->lock); ++ ++ if (ret) ++ mutex_acquire(&lock->dep_map, 0, 1, _RET_IP_); ++ ++ return ret; ++} ++EXPORT_SYMBOL(_mutex_trylock); ++ ++void __lockfunc _mutex_unlock(struct mutex *lock) ++{ ++ mutex_release(&lock->dep_map, 1, _RET_IP_); ++ rt_mutex_unlock(&lock->lock); ++} ++EXPORT_SYMBOL(_mutex_unlock); ++ ++/* ++ * rwlock_t functions ++ */ ++int __lockfunc rt_write_trylock(rwlock_t *rwlock) ++{ ++ int ret = rt_mutex_trylock(&rwlock->lock); ++ ++ if (ret) ++ rwlock_acquire(&rwlock->dep_map, 0, 1, _RET_IP_); ++ ++ return ret; ++} ++EXPORT_SYMBOL(rt_write_trylock); ++ ++int __lockfunc rt_write_trylock_irqsave(rwlock_t *rwlock, unsigned long *flags) ++{ ++ *flags = 0; ++ return rt_write_trylock(rwlock); ++} ++ ++int __lockfunc rt_read_trylock(rwlock_t *rwlock) ++{ ++ struct rt_mutex *lock = &rwlock->lock; ++ unsigned long flags; ++ int ret; ++ ++ /* ++ * Read locks within the self-held write lock succeed. ++ */ ++ spin_lock_irqsave(&lock->wait_lock, flags); ++ if (rt_mutex_real_owner(lock) == current) { ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ rwlock->read_depth++; ++ rwlock_acquire_read(&rwlock->dep_map, 0, 1, _RET_IP_); ++ return 1; ++ } ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ ++ ret = rt_mutex_trylock(lock); ++ if (ret) ++ rwlock_acquire_read(&rwlock->dep_map, 0, 1, _RET_IP_); ++ ++ return ret; ++} ++EXPORT_SYMBOL(rt_read_trylock); ++ ++void __lockfunc rt_write_lock(rwlock_t *rwlock) ++{ ++ rwlock_acquire(&rwlock->dep_map, 0, 0, _RET_IP_); ++ __rt_spin_lock(&rwlock->lock); ++} ++EXPORT_SYMBOL(rt_write_lock); ++ ++void __lockfunc rt_read_lock(rwlock_t *rwlock) ++{ ++ unsigned long flags; ++ struct rt_mutex *lock = &rwlock->lock; ++ ++ rwlock_acquire_read(&rwlock->dep_map, 0, 0, _RET_IP_); ++ /* ++ * Read locks within the write lock succeed. ++ */ ++ spin_lock_irqsave(&lock->wait_lock, flags); ++ if (rt_mutex_real_owner(lock) == current) { ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ rwlock->read_depth++; ++ return; ++ } ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ __rt_spin_lock(lock); ++} ++ ++EXPORT_SYMBOL(rt_read_lock); ++ ++void __lockfunc rt_write_unlock(rwlock_t *rwlock) ++{ ++ /* NOTE: we always pass in '1' for nested, for simplicity */ ++ rwlock_release(&rwlock->dep_map, 1, _RET_IP_); ++ __rt_spin_unlock(&rwlock->lock); ++} ++EXPORT_SYMBOL(rt_write_unlock); ++ ++void __lockfunc rt_read_unlock(rwlock_t *rwlock) ++{ ++ struct rt_mutex *lock = &rwlock->lock; ++ unsigned long flags; ++ ++ rwlock_release(&rwlock->dep_map, 1, _RET_IP_); ++ // TRACE_WARN_ON(lock->save_state != 1); ++ /* ++ * Read locks within the self-held write lock succeed. ++ */ ++ spin_lock_irqsave(&lock->wait_lock, flags); ++ if (rt_mutex_real_owner(lock) == current && rwlock->read_depth) { ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ rwlock->read_depth--; ++ return; ++ } ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ __rt_spin_unlock(&rwlock->lock); ++} ++EXPORT_SYMBOL(rt_read_unlock); ++ ++unsigned long __lockfunc rt_write_lock_irqsave(rwlock_t *rwlock) ++{ ++ rt_write_lock(rwlock); ++ ++ return 0; ++} ++EXPORT_SYMBOL(rt_write_lock_irqsave); ++ ++unsigned long __lockfunc rt_read_lock_irqsave(rwlock_t *rwlock) ++{ ++ rt_read_lock(rwlock); ++ ++ return 0; ++} ++EXPORT_SYMBOL(rt_read_lock_irqsave); ++ ++void __rt_rwlock_init(rwlock_t *rwlock, char *name, struct lock_class_key *key) ++{ ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ /* ++ * Make sure we are not reinitializing a held lock: ++ */ ++ debug_check_no_locks_freed((void *)rwlock, sizeof(*rwlock)); ++ lockdep_init_map(&rwlock->dep_map, name, key, 0); ++#endif ++ __rt_mutex_init(&rwlock->lock, name); ++ rwlock->read_depth = 0; ++} ++EXPORT_SYMBOL(__rt_rwlock_init); ++ ++/* ++ * rw_semaphores ++ */ ++ ++void fastcall rt_up_write(struct rw_semaphore *rwsem) ++{ ++ rwsem_release(&rwsem->dep_map, 1, _RET_IP_); ++ rt_mutex_unlock(&rwsem->lock); ++} ++EXPORT_SYMBOL(rt_up_write); ++ ++void fastcall rt_up_read(struct rw_semaphore *rwsem) ++{ ++ unsigned long flags; ++ ++ rwsem_release(&rwsem->dep_map, 1, _RET_IP_); ++ /* ++ * Read locks within the self-held write lock succeed. ++ */ ++ spin_lock_irqsave(&rwsem->lock.wait_lock, flags); ++ if (rt_mutex_real_owner(&rwsem->lock) == current && rwsem->read_depth) { ++ spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); ++ rwsem->read_depth--; ++ return; ++ } ++ spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); ++ rt_mutex_unlock(&rwsem->lock); ++} ++EXPORT_SYMBOL(rt_up_read); ++ ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++void fastcall rt_up_read_non_owner(struct rw_semaphore *rwsem) ++{ ++ unsigned long flags; ++ /* ++ * Read locks within the self-held write lock succeed. ++ */ ++ spin_lock_irqsave(&rwsem->lock.wait_lock, flags); ++ if (rt_mutex_real_owner(&rwsem->lock) == current && rwsem->read_depth) { ++ spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); ++ rwsem->read_depth--; ++ return; ++ } ++ spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); ++ rt_mutex_unlock(&rwsem->lock); ++} ++EXPORT_SYMBOL(rt_up_read_non_owner); ++#endif ++ ++/* ++ * downgrade a write lock into a read lock ++ * - just wake up any readers at the front of the queue ++ */ ++void fastcall rt_downgrade_write(struct rw_semaphore *rwsem) ++{ ++ BUG(); ++} ++EXPORT_SYMBOL(rt_downgrade_write); ++ ++int fastcall rt_down_write_trylock(struct rw_semaphore *rwsem) ++{ ++ int ret = rt_mutex_trylock(&rwsem->lock); ++ ++ if (ret) ++ rwsem_acquire(&rwsem->dep_map, 0, 1, _RET_IP_); ++ return ret; ++} ++EXPORT_SYMBOL(rt_down_write_trylock); ++ ++void fastcall rt_down_write(struct rw_semaphore *rwsem) ++{ ++ rwsem_acquire(&rwsem->dep_map, 0, 0, _RET_IP_); ++ rt_mutex_lock(&rwsem->lock); ++} ++EXPORT_SYMBOL(rt_down_write); ++ ++void fastcall rt_down_write_nested(struct rw_semaphore *rwsem, int subclass) ++{ ++ rwsem_acquire(&rwsem->dep_map, subclass, 0, _RET_IP_); ++ rt_mutex_lock(&rwsem->lock); ++} ++EXPORT_SYMBOL(rt_down_write_nested); ++ ++int fastcall rt_down_read_trylock(struct rw_semaphore *rwsem) ++{ ++ unsigned long flags; ++ int ret; ++ ++ /* ++ * Read locks within the self-held write lock succeed. ++ */ ++ spin_lock_irqsave(&rwsem->lock.wait_lock, flags); ++ if (rt_mutex_real_owner(&rwsem->lock) == current) { ++ spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); ++ rwsem_acquire_read(&rwsem->dep_map, 0, 1, _RET_IP_); ++ rwsem->read_depth++; ++ return 1; ++ } ++ spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); ++ ++ ret = rt_mutex_trylock(&rwsem->lock); ++ if (ret) ++ rwsem_acquire(&rwsem->dep_map, 0, 1, _RET_IP_); ++ return ret; ++} ++EXPORT_SYMBOL(rt_down_read_trylock); ++ ++static void __rt_down_read(struct rw_semaphore *rwsem, int subclass) ++{ ++ unsigned long flags; ++ ++ rwsem_acquire_read(&rwsem->dep_map, subclass, 0, _RET_IP_); ++ ++ /* ++ * Read locks within the write lock succeed. ++ */ ++ spin_lock_irqsave(&rwsem->lock.wait_lock, flags); ++ ++ if (rt_mutex_real_owner(&rwsem->lock) == current) { ++ spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); ++ rwsem->read_depth++; ++ return; ++ } ++ spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); ++ rt_mutex_lock(&rwsem->lock); ++} ++ ++void fastcall rt_down_read(struct rw_semaphore *rwsem) ++{ ++ __rt_down_read(rwsem, 0); ++} ++EXPORT_SYMBOL(rt_down_read); ++ ++void fastcall rt_down_read_nested(struct rw_semaphore *rwsem, int subclass) ++{ ++ __rt_down_read(rwsem, subclass); ++} ++EXPORT_SYMBOL(rt_down_read_nested); ++ ++ ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ ++/* ++ * Same as rt_down_read() but no lockdep calls: ++ */ ++void fastcall rt_down_read_non_owner(struct rw_semaphore *rwsem) ++{ ++ unsigned long flags; ++ /* ++ * Read locks within the write lock succeed. ++ */ ++ spin_lock_irqsave(&rwsem->lock.wait_lock, flags); ++ ++ if (rt_mutex_real_owner(&rwsem->lock) == current) { ++ spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); ++ rwsem->read_depth++; ++ return; ++ } ++ spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); ++ rt_mutex_lock(&rwsem->lock); ++} ++EXPORT_SYMBOL(rt_down_read_non_owner); ++ ++#endif ++ ++void fastcall __rt_rwsem_init(struct rw_semaphore *rwsem, char *name, ++ struct lock_class_key *key) ++{ ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ /* ++ * Make sure we are not reinitializing a held lock: ++ */ ++ debug_check_no_locks_freed((void *)rwsem, sizeof(*rwsem)); ++ lockdep_init_map(&rwsem->dep_map, name, key, 0); ++#endif ++ __rt_mutex_init(&rwsem->lock, name); ++ rwsem->read_depth = 0; ++} ++EXPORT_SYMBOL(__rt_rwsem_init); ++ ++/* ++ * Semaphores ++ */ ++/* ++ * Linux Semaphores implemented via RT-mutexes. ++ * ++ * In the down() variants we use the mutex as the semaphore blocking ++ * object: we always acquire it, decrease the counter and keep the lock ++ * locked if we did the 1->0 transition. The next down() will then block. ++ * ++ * In the up() path we atomically increase the counter and do the ++ * unlock if we were the one doing the 0->1 transition. ++ */ ++ ++static inline void __down_complete(struct semaphore *sem) ++{ ++ int count = atomic_dec_return(&sem->count); ++ ++ if (unlikely(count > 0)) ++ rt_mutex_unlock(&sem->lock); ++} ++ ++void fastcall rt_down(struct semaphore *sem) ++{ ++ rt_mutex_lock(&sem->lock); ++ __down_complete(sem); ++} ++EXPORT_SYMBOL(rt_down); ++ ++int fastcall rt_down_interruptible(struct semaphore *sem) ++{ ++ int ret; ++ ++ ret = rt_mutex_lock_interruptible(&sem->lock, 0); ++ if (ret) ++ return ret; ++ __down_complete(sem); ++ return 0; ++} ++EXPORT_SYMBOL(rt_down_interruptible); ++ ++/* ++ * try to down the semaphore, 0 on success and 1 on failure. (inverted) ++ */ ++int fastcall rt_down_trylock(struct semaphore *sem) ++{ ++ /* ++ * Here we are a tiny bit different from ordinary Linux semaphores, ++ * because we can get 'transient' locking-failures when say a ++ * process decreases the count from 9 to 8 and locks/releases the ++ * embedded mutex internally. It would be quite complex to remove ++ * these transient failures so lets try it the simple way first: ++ */ ++ if (rt_mutex_trylock(&sem->lock)) { ++ __down_complete(sem); ++ return 0; ++ } ++ return 1; ++} ++EXPORT_SYMBOL(rt_down_trylock); ++ ++void fastcall rt_up(struct semaphore *sem) ++{ ++ int count; ++ ++ /* ++ * Disable preemption to make sure a highprio trylock-er cannot ++ * preempt us here and get into an infinite loop: ++ */ ++ preempt_disable(); ++ count = atomic_inc_return(&sem->count); ++ /* ++ * If we did the 0 -> 1 transition then we are the ones to unlock it: ++ */ ++ if (likely(count == 1)) ++ rt_mutex_unlock(&sem->lock); ++ preempt_enable(); ++} ++EXPORT_SYMBOL(rt_up); ++ ++void fastcall __sema_init(struct semaphore *sem, int val, ++ char *name, char *file, int line) ++{ ++ atomic_set(&sem->count, val); ++ switch (val) { ++ case 0: ++ __rt_mutex_init(&sem->lock, name); ++ rt_mutex_lock(&sem->lock); ++ break; ++ default: ++ __rt_mutex_init(&sem->lock, name); ++ break; ++ } ++} ++EXPORT_SYMBOL(__sema_init); ++ ++void fastcall __init_MUTEX(struct semaphore *sem, char *name, char *file, ++ int line) ++{ ++ __sema_init(sem, 1, name, file, line); ++} ++EXPORT_SYMBOL(__init_MUTEX); ++ +Index: linux-2.6.24.7-rt27/kernel/rtmutex-debug.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex-debug.c 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex-debug.c 2009-02-08 00:02:01.000000000 -0500 +@@ -16,6 +16,7 @@ + * + * See rt.c in preempt-rt for proper credits and further information + */ ++#include + #include + #include + #include +@@ -29,61 +30,6 @@ + + #include "rtmutex_common.h" + +-# define TRACE_WARN_ON(x) WARN_ON(x) +-# define TRACE_BUG_ON(x) BUG_ON(x) +- +-# define TRACE_OFF() \ +-do { \ +- if (rt_trace_on) { \ +- rt_trace_on = 0; \ +- console_verbose(); \ +- if (spin_is_locked(¤t->pi_lock)) \ +- spin_unlock(¤t->pi_lock); \ +- } \ +-} while (0) +- +-# define TRACE_OFF_NOLOCK() \ +-do { \ +- if (rt_trace_on) { \ +- rt_trace_on = 0; \ +- console_verbose(); \ +- } \ +-} while (0) +- +-# define TRACE_BUG_LOCKED() \ +-do { \ +- TRACE_OFF(); \ +- BUG(); \ +-} while (0) +- +-# define TRACE_WARN_ON_LOCKED(c) \ +-do { \ +- if (unlikely(c)) { \ +- TRACE_OFF(); \ +- WARN_ON(1); \ +- } \ +-} while (0) +- +-# define TRACE_BUG_ON_LOCKED(c) \ +-do { \ +- if (unlikely(c)) \ +- TRACE_BUG_LOCKED(); \ +-} while (0) +- +-#ifdef CONFIG_SMP +-# define SMP_TRACE_BUG_ON_LOCKED(c) TRACE_BUG_ON_LOCKED(c) +-#else +-# define SMP_TRACE_BUG_ON_LOCKED(c) do { } while (0) +-#endif +- +-/* +- * deadlock detection flag. We turn it off when we detect +- * the first problem because we dont want to recurse back +- * into the tracing code when doing error printk or +- * executing a BUG(): +- */ +-static int rt_trace_on = 1; +- + static void printk_task(struct task_struct *p) + { + if (p) +@@ -111,8 +57,8 @@ static void printk_lock(struct rt_mutex + + void rt_mutex_debug_task_free(struct task_struct *task) + { +- WARN_ON(!plist_head_empty(&task->pi_waiters)); +- WARN_ON(task->pi_blocked_on); ++ DEBUG_LOCKS_WARN_ON(!plist_head_empty(&task->pi_waiters)); ++ DEBUG_LOCKS_WARN_ON(task->pi_blocked_on); + } + + /* +@@ -125,7 +71,7 @@ void debug_rt_mutex_deadlock(int detect, + { + struct task_struct *task; + +- if (!rt_trace_on || detect || !act_waiter) ++ if (!debug_locks || detect || !act_waiter) + return; + + task = rt_mutex_owner(act_waiter->lock); +@@ -139,14 +85,15 @@ void debug_rt_mutex_print_deadlock(struc + { + struct task_struct *task; + +- if (!waiter->deadlock_lock || !rt_trace_on) ++ if (!waiter->deadlock_lock || !debug_locks) + return; + + task = find_task_by_pid(waiter->deadlock_task_pid); + if (!task) + return; + +- TRACE_OFF_NOLOCK(); ++ if (!debug_locks_off()) ++ return; + + printk("\n============================================\n"); + printk( "[ BUG: circular locking deadlock detected! ]\n"); +@@ -176,7 +123,6 @@ void debug_rt_mutex_print_deadlock(struc + + printk("[ turning off deadlock detection." + "Please report this trace. ]\n\n"); +- local_irq_disable(); + } + + void debug_rt_mutex_lock(struct rt_mutex *lock) +@@ -185,7 +131,8 @@ void debug_rt_mutex_lock(struct rt_mutex + + void debug_rt_mutex_unlock(struct rt_mutex *lock) + { +- TRACE_WARN_ON_LOCKED(rt_mutex_owner(lock) != current); ++ if (debug_locks) ++ DEBUG_LOCKS_WARN_ON(rt_mutex_owner(lock) != current); + } + + void +@@ -195,7 +142,7 @@ debug_rt_mutex_proxy_lock(struct rt_mute + + void debug_rt_mutex_proxy_unlock(struct rt_mutex *lock) + { +- TRACE_WARN_ON_LOCKED(!rt_mutex_owner(lock)); ++ DEBUG_LOCKS_WARN_ON(!rt_mutex_owner(lock)); + } + + void debug_rt_mutex_init_waiter(struct rt_mutex_waiter *waiter) +@@ -207,9 +154,9 @@ void debug_rt_mutex_init_waiter(struct r + + void debug_rt_mutex_free_waiter(struct rt_mutex_waiter *waiter) + { +- TRACE_WARN_ON(!plist_node_empty(&waiter->list_entry)); +- TRACE_WARN_ON(!plist_node_empty(&waiter->pi_list_entry)); +- TRACE_WARN_ON(waiter->task); ++ DEBUG_LOCKS_WARN_ON(!plist_node_empty(&waiter->list_entry)); ++ DEBUG_LOCKS_WARN_ON(!plist_node_empty(&waiter->pi_list_entry)); ++ DEBUG_LOCKS_WARN_ON(waiter->task); + memset(waiter, 0x22, sizeof(*waiter)); + } + +@@ -225,9 +172,36 @@ void debug_rt_mutex_init(struct rt_mutex + void + rt_mutex_deadlock_account_lock(struct rt_mutex *lock, struct task_struct *task) + { ++#ifdef CONFIG_DEBUG_PREEMPT ++ if (task->lock_count >= MAX_LOCK_STACK) { ++ if (!debug_locks_off()) ++ return; ++ printk("BUG: %s/%d: lock count overflow!\n", ++ task->comm, task->pid); ++ dump_stack(); ++ return; ++ } ++#ifdef CONFIG_PREEMPT_RT ++ task->owned_lock[task->lock_count] = lock; ++#endif ++ task->lock_count++; ++#endif + } + + void rt_mutex_deadlock_account_unlock(struct task_struct *task) + { ++#ifdef CONFIG_DEBUG_PREEMPT ++ if (!task->lock_count) { ++ if (!debug_locks_off()) ++ return; ++ printk("BUG: %s/%d: lock count underflow!\n", ++ task->comm, task->pid); ++ dump_stack(); ++ return; ++ } ++ task->lock_count--; ++#ifdef CONFIG_PREEMPT_RT ++ task->owned_lock[task->lock_count] = NULL; ++#endif ++#endif + } +- +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:02:01.000000000 -0500 +@@ -97,6 +97,22 @@ static inline void mark_rt_mutex_waiters + } + #endif + ++int pi_initialized; ++ ++/* ++ * we initialize the wait_list runtime. (Could be done build-time and/or ++ * boot-time.) ++ */ ++static inline void init_lists(struct rt_mutex *lock) ++{ ++ if (unlikely(!lock->wait_list.prio_list.prev)) { ++ plist_head_init(&lock->wait_list, &lock->wait_lock); ++#ifdef CONFIG_DEBUG_RT_MUTEXES ++ pi_initialized++; ++#endif ++ } ++} ++ + /* + * Calculate task priority from the waiter list priority + * +@@ -253,13 +269,13 @@ static int rt_mutex_adjust_prio_chain(st + plist_add(&waiter->list_entry, &lock->wait_list); + + /* Release the task */ +- spin_unlock_irqrestore(&task->pi_lock, flags); ++ spin_unlock(&task->pi_lock); + put_task_struct(task); + + /* Grab the next task */ + task = rt_mutex_owner(lock); + get_task_struct(task); +- spin_lock_irqsave(&task->pi_lock, flags); ++ spin_lock(&task->pi_lock); + + if (waiter == rt_mutex_top_waiter(lock)) { + /* Boost the owner */ +@@ -277,10 +293,10 @@ static int rt_mutex_adjust_prio_chain(st + __rt_mutex_adjust_prio(task); + } + +- spin_unlock_irqrestore(&task->pi_lock, flags); ++ spin_unlock(&task->pi_lock); + + top_waiter = rt_mutex_top_waiter(lock); +- spin_unlock(&lock->wait_lock); ++ spin_unlock_irqrestore(&lock->wait_lock, flags); + + if (!detect_deadlock && waiter != top_waiter) + goto out_put_task; +@@ -304,7 +320,6 @@ static inline int try_to_steal_lock(stru + { + struct task_struct *pendowner = rt_mutex_owner(lock); + struct rt_mutex_waiter *next; +- unsigned long flags; + + if (!rt_mutex_owner_pending(lock)) + return 0; +@@ -312,9 +327,9 @@ static inline int try_to_steal_lock(stru + if (pendowner == current) + return 1; + +- spin_lock_irqsave(&pendowner->pi_lock, flags); ++ spin_lock(&pendowner->pi_lock); + if (current->prio >= pendowner->prio) { +- spin_unlock_irqrestore(&pendowner->pi_lock, flags); ++ spin_unlock(&pendowner->pi_lock); + return 0; + } + +@@ -324,7 +339,7 @@ static inline int try_to_steal_lock(stru + * priority. + */ + if (likely(!rt_mutex_has_waiters(lock))) { +- spin_unlock_irqrestore(&pendowner->pi_lock, flags); ++ spin_unlock(&pendowner->pi_lock); + return 1; + } + +@@ -332,7 +347,7 @@ static inline int try_to_steal_lock(stru + next = rt_mutex_top_waiter(lock); + plist_del(&next->pi_list_entry, &pendowner->pi_waiters); + __rt_mutex_adjust_prio(pendowner); +- spin_unlock_irqrestore(&pendowner->pi_lock, flags); ++ spin_unlock(&pendowner->pi_lock); + + /* + * We are going to steal the lock and a waiter was +@@ -349,10 +364,10 @@ static inline int try_to_steal_lock(stru + * might be current: + */ + if (likely(next->task != current)) { +- spin_lock_irqsave(¤t->pi_lock, flags); ++ spin_lock(¤t->pi_lock); + plist_add(&next->pi_list_entry, ¤t->pi_waiters); + __rt_mutex_adjust_prio(current); +- spin_unlock_irqrestore(¤t->pi_lock, flags); ++ spin_unlock(¤t->pi_lock); + } + return 1; + } +@@ -411,14 +426,13 @@ static int try_to_take_rt_mutex(struct r + */ + static int task_blocks_on_rt_mutex(struct rt_mutex *lock, + struct rt_mutex_waiter *waiter, +- int detect_deadlock) ++ int detect_deadlock, unsigned long flags) + { + struct task_struct *owner = rt_mutex_owner(lock); + struct rt_mutex_waiter *top_waiter = waiter; +- unsigned long flags; + int chain_walk = 0, res; + +- spin_lock_irqsave(¤t->pi_lock, flags); ++ spin_lock(¤t->pi_lock); + __rt_mutex_adjust_prio(current); + waiter->task = current; + waiter->lock = lock; +@@ -432,17 +446,17 @@ static int task_blocks_on_rt_mutex(struc + + current->pi_blocked_on = waiter; + +- spin_unlock_irqrestore(¤t->pi_lock, flags); ++ spin_unlock(¤t->pi_lock); + + if (waiter == rt_mutex_top_waiter(lock)) { +- spin_lock_irqsave(&owner->pi_lock, flags); ++ spin_lock(&owner->pi_lock); + plist_del(&top_waiter->pi_list_entry, &owner->pi_waiters); + plist_add(&waiter->pi_list_entry, &owner->pi_waiters); + + __rt_mutex_adjust_prio(owner); + if (owner->pi_blocked_on) + chain_walk = 1; +- spin_unlock_irqrestore(&owner->pi_lock, flags); ++ spin_unlock(&owner->pi_lock); + } + else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) + chain_walk = 1; +@@ -457,12 +471,12 @@ static int task_blocks_on_rt_mutex(struc + */ + get_task_struct(owner); + +- spin_unlock(&lock->wait_lock); ++ spin_unlock_irqrestore(&lock->wait_lock, flags); + + res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, waiter, + current); + +- spin_lock(&lock->wait_lock); ++ spin_lock_irq(&lock->wait_lock); + + return res; + } +@@ -475,13 +489,12 @@ static int task_blocks_on_rt_mutex(struc + * + * Called with lock->wait_lock held. + */ +-static void wakeup_next_waiter(struct rt_mutex *lock) ++static void wakeup_next_waiter(struct rt_mutex *lock, int savestate) + { + struct rt_mutex_waiter *waiter; + struct task_struct *pendowner; +- unsigned long flags; + +- spin_lock_irqsave(¤t->pi_lock, flags); ++ spin_lock(¤t->pi_lock); + + waiter = rt_mutex_top_waiter(lock); + plist_del(&waiter->list_entry, &lock->wait_list); +@@ -498,7 +511,7 @@ static void wakeup_next_waiter(struct rt + + rt_mutex_set_owner(lock, pendowner, RT_MUTEX_OWNER_PENDING); + +- spin_unlock_irqrestore(¤t->pi_lock, flags); ++ spin_unlock(¤t->pi_lock); + + /* + * Clear the pi_blocked_on variable and enqueue a possible +@@ -507,7 +520,7 @@ static void wakeup_next_waiter(struct rt + * waiter with higher priority than pending-owner->normal_prio + * is blocked on the unboosted (pending) owner. + */ +- spin_lock_irqsave(&pendowner->pi_lock, flags); ++ spin_lock(&pendowner->pi_lock); + + WARN_ON(!pendowner->pi_blocked_on); + WARN_ON(pendowner->pi_blocked_on != waiter); +@@ -521,9 +534,12 @@ static void wakeup_next_waiter(struct rt + next = rt_mutex_top_waiter(lock); + plist_add(&next->pi_list_entry, &pendowner->pi_waiters); + } +- spin_unlock_irqrestore(&pendowner->pi_lock, flags); ++ spin_unlock(&pendowner->pi_lock); + +- wake_up_process(pendowner); ++ if (savestate) ++ wake_up_process_mutex(pendowner); ++ else ++ wake_up_process(pendowner); + } + + /* +@@ -532,22 +548,22 @@ static void wakeup_next_waiter(struct rt + * Must be called with lock->wait_lock held + */ + static void remove_waiter(struct rt_mutex *lock, +- struct rt_mutex_waiter *waiter) ++ struct rt_mutex_waiter *waiter, ++ unsigned long flags) + { + int first = (waiter == rt_mutex_top_waiter(lock)); + struct task_struct *owner = rt_mutex_owner(lock); +- unsigned long flags; + int chain_walk = 0; + +- spin_lock_irqsave(¤t->pi_lock, flags); ++ spin_lock(¤t->pi_lock); + plist_del(&waiter->list_entry, &lock->wait_list); + waiter->task = NULL; + current->pi_blocked_on = NULL; +- spin_unlock_irqrestore(¤t->pi_lock, flags); ++ spin_unlock(¤t->pi_lock); + + if (first && owner != current) { + +- spin_lock_irqsave(&owner->pi_lock, flags); ++ spin_lock(&owner->pi_lock); + + plist_del(&waiter->pi_list_entry, &owner->pi_waiters); + +@@ -562,7 +578,7 @@ static void remove_waiter(struct rt_mute + if (owner->pi_blocked_on) + chain_walk = 1; + +- spin_unlock_irqrestore(&owner->pi_lock, flags); ++ spin_unlock(&owner->pi_lock); + } + + WARN_ON(!plist_node_empty(&waiter->pi_list_entry)); +@@ -573,11 +589,11 @@ static void remove_waiter(struct rt_mute + /* gets dropped in rt_mutex_adjust_prio_chain()! */ + get_task_struct(owner); + +- spin_unlock(&lock->wait_lock); ++ spin_unlock_irqrestore(&lock->wait_lock, flags); + + rt_mutex_adjust_prio_chain(owner, 0, lock, NULL, current); + +- spin_lock(&lock->wait_lock); ++ spin_lock_irq(&lock->wait_lock); + } + + /* +@@ -598,14 +614,307 @@ void rt_mutex_adjust_pi(struct task_stru + return; + } + +- spin_unlock_irqrestore(&task->pi_lock, flags); +- + /* gets dropped in rt_mutex_adjust_prio_chain()! */ + get_task_struct(task); ++ spin_unlock_irqrestore(&task->pi_lock, flags); ++ + rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task); + } + + /* ++ * preemptible spin_lock functions: ++ */ ++ ++#ifdef CONFIG_PREEMPT_RT ++ ++static inline void ++rt_spin_lock_fastlock(struct rt_mutex *lock, ++ void fastcall (*slowfn)(struct rt_mutex *lock)) ++{ ++ if (likely(rt_mutex_cmpxchg(lock, NULL, current))) ++ rt_mutex_deadlock_account_lock(lock, current); ++ else ++ slowfn(lock); ++} ++ ++static inline void ++rt_spin_lock_fastunlock(struct rt_mutex *lock, ++ void fastcall (*slowfn)(struct rt_mutex *lock)) ++{ ++ if (likely(rt_mutex_cmpxchg(lock, current, NULL))) ++ rt_mutex_deadlock_account_unlock(current); ++ else ++ slowfn(lock); ++} ++ ++/* ++ * Slow path lock function spin_lock style: this variant is very ++ * careful not to miss any non-lock wakeups. ++ * ++ * The wakeup side uses wake_up_process_mutex, which, combined with ++ * the xchg code of this function is a transparent sleep/wakeup ++ * mechanism nested within any existing sleep/wakeup mechanism. This ++ * enables the seemless use of arbitrary (blocking) spinlocks within ++ * sleep/wakeup event loops. ++ */ ++static void fastcall noinline __sched ++rt_spin_lock_slowlock(struct rt_mutex *lock) ++{ ++ struct rt_mutex_waiter waiter; ++ unsigned long saved_state, state, flags; ++ ++ debug_rt_mutex_init_waiter(&waiter); ++ waiter.task = NULL; ++ ++ spin_lock_irqsave(&lock->wait_lock, flags); ++ init_lists(lock); ++ ++ /* Try to acquire the lock again: */ ++ if (try_to_take_rt_mutex(lock)) { ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ return; ++ } ++ ++ BUG_ON(rt_mutex_owner(lock) == current); ++ ++ /* ++ * Here we save whatever state the task was in originally, ++ * we'll restore it at the end of the function and we'll take ++ * any intermediate wakeup into account as well, independently ++ * of the lock sleep/wakeup mechanism. When we get a real ++ * wakeup the task->state is TASK_RUNNING and we change ++ * saved_state accordingly. If we did not get a real wakeup ++ * then we return with the saved state. ++ */ ++ saved_state = xchg(¤t->state, TASK_UNINTERRUPTIBLE); ++ ++ for (;;) { ++ unsigned long saved_flags; ++ int saved_lock_depth = current->lock_depth; ++ ++ /* Try to acquire the lock */ ++ if (try_to_take_rt_mutex(lock)) ++ break; ++ /* ++ * waiter.task is NULL the first time we come here and ++ * when we have been woken up by the previous owner ++ * but the lock got stolen by an higher prio task. ++ */ ++ if (!waiter.task) { ++ task_blocks_on_rt_mutex(lock, &waiter, 0, flags); ++ /* Wakeup during boost ? */ ++ if (unlikely(!waiter.task)) ++ continue; ++ } ++ ++ /* ++ * Prevent schedule() to drop BKL, while waiting for ++ * the lock ! We restore lock_depth when we come back. ++ */ ++ saved_flags = current->flags & PF_NOSCHED; ++ current->lock_depth = -1; ++ current->flags &= ~PF_NOSCHED; ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ ++ debug_rt_mutex_print_deadlock(&waiter); ++ ++ schedule_rt_mutex(lock); ++ ++ spin_lock_irqsave(&lock->wait_lock, flags); ++ current->flags |= saved_flags; ++ current->lock_depth = saved_lock_depth; ++ state = xchg(¤t->state, TASK_UNINTERRUPTIBLE); ++ if (unlikely(state == TASK_RUNNING)) ++ saved_state = TASK_RUNNING; ++ } ++ ++ state = xchg(¤t->state, saved_state); ++ if (unlikely(state == TASK_RUNNING)) ++ current->state = TASK_RUNNING; ++ ++ /* ++ * Extremely rare case, if we got woken up by a non-mutex wakeup, ++ * and we managed to steal the lock despite us not being the ++ * highest-prio waiter (due to SCHED_OTHER changing prio), then we ++ * can end up with a non-NULL waiter.task: ++ */ ++ if (unlikely(waiter.task)) ++ remove_waiter(lock, &waiter, flags); ++ /* ++ * try_to_take_rt_mutex() sets the waiter bit ++ * unconditionally. We might have to fix that up: ++ */ ++ fixup_rt_mutex_waiters(lock); ++ ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ ++ debug_rt_mutex_free_waiter(&waiter); ++} ++ ++/* ++ * Slow path to release a rt_mutex spin_lock style ++ */ ++static void fastcall noinline __sched ++rt_spin_lock_slowunlock(struct rt_mutex *lock) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&lock->wait_lock, flags); ++ ++ debug_rt_mutex_unlock(lock); ++ ++ rt_mutex_deadlock_account_unlock(current); ++ ++ if (!rt_mutex_has_waiters(lock)) { ++ lock->owner = NULL; ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ return; ++ } ++ ++ wakeup_next_waiter(lock, 1); ++ ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ ++ /* Undo pi boosting.when necessary */ ++ rt_mutex_adjust_prio(current); ++} ++ ++void __lockfunc rt_spin_lock(spinlock_t *lock) ++{ ++ rt_spin_lock_fastlock(&lock->lock, rt_spin_lock_slowlock); ++ spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); ++} ++EXPORT_SYMBOL(rt_spin_lock); ++ ++void __lockfunc __rt_spin_lock(struct rt_mutex *lock) ++{ ++ rt_spin_lock_fastlock(lock, rt_spin_lock_slowlock); ++} ++EXPORT_SYMBOL(__rt_spin_lock); ++ ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ ++void __lockfunc rt_spin_lock_nested(spinlock_t *lock, int subclass) ++{ ++ rt_spin_lock_fastlock(&lock->lock, rt_spin_lock_slowlock); ++ spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); ++} ++EXPORT_SYMBOL(rt_spin_lock_nested); ++ ++#endif ++ ++void __lockfunc rt_spin_unlock(spinlock_t *lock) ++{ ++ /* NOTE: we always pass in '1' for nested, for simplicity */ ++ spin_release(&lock->dep_map, 1, _RET_IP_); ++ rt_spin_lock_fastunlock(&lock->lock, rt_spin_lock_slowunlock); ++} ++EXPORT_SYMBOL(rt_spin_unlock); ++ ++void __lockfunc __rt_spin_unlock(struct rt_mutex *lock) ++{ ++ rt_spin_lock_fastunlock(lock, rt_spin_lock_slowunlock); ++} ++EXPORT_SYMBOL(__rt_spin_unlock); ++ ++/* ++ * Wait for the lock to get unlocked: instead of polling for an unlock ++ * (like raw spinlocks do), we lock and unlock, to force the kernel to ++ * schedule if there's contention: ++ */ ++void __lockfunc rt_spin_unlock_wait(spinlock_t *lock) ++{ ++ spin_lock(lock); ++ spin_unlock(lock); ++} ++EXPORT_SYMBOL(rt_spin_unlock_wait); ++ ++int __lockfunc rt_spin_trylock(spinlock_t *lock) ++{ ++ int ret = rt_mutex_trylock(&lock->lock); ++ ++ if (ret) ++ spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); ++ ++ return ret; ++} ++EXPORT_SYMBOL(rt_spin_trylock); ++ ++int __lockfunc rt_spin_trylock_irqsave(spinlock_t *lock, unsigned long *flags) ++{ ++ int ret; ++ ++ *flags = 0; ++ ret = rt_mutex_trylock(&lock->lock); ++ if (ret) ++ spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); ++ ++ return ret; ++} ++EXPORT_SYMBOL(rt_spin_trylock_irqsave); ++ ++int _atomic_dec_and_spin_lock(atomic_t *atomic, spinlock_t *lock) ++{ ++ /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */ ++ if (atomic_add_unless(atomic, -1, 1)) ++ return 0; ++ rt_spin_lock(lock); ++ if (atomic_dec_and_test(atomic)) ++ return 1; ++ rt_spin_unlock(lock); ++ return 0; ++} ++EXPORT_SYMBOL(_atomic_dec_and_spin_lock); ++ ++void ++__rt_spin_lock_init(spinlock_t *lock, char *name, struct lock_class_key *key) ++{ ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ /* ++ * Make sure we are not reinitializing a held lock: ++ */ ++ debug_check_no_locks_freed((void *)lock, sizeof(*lock)); ++ lockdep_init_map(&lock->dep_map, name, key, 0); ++#endif ++ __rt_mutex_init(&lock->lock, name); ++} ++EXPORT_SYMBOL(__rt_spin_lock_init); ++ ++#endif ++ ++#ifdef CONFIG_PREEMPT_BKL ++ ++static inline int rt_release_bkl(struct rt_mutex *lock, unsigned long flags) ++{ ++ int saved_lock_depth = current->lock_depth; ++ ++ current->lock_depth = -1; ++ /* ++ * try_to_take_lock set the waiters, make sure it's ++ * still correct. ++ */ ++ fixup_rt_mutex_waiters(lock); ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ ++ up(&kernel_sem); ++ ++ spin_lock_irq(&lock->wait_lock); ++ ++ return saved_lock_depth; ++} ++ ++static inline void rt_reacquire_bkl(int saved_lock_depth) ++{ ++ down(&kernel_sem); ++ current->lock_depth = saved_lock_depth; ++} ++ ++#else ++# define rt_release_bkl(lock, flags) (-1) ++# define rt_reacquire_bkl(depth) do { } while (0) ++#endif ++ ++/* + * Slow path lock function: + */ + static int __sched +@@ -613,20 +922,29 @@ rt_mutex_slowlock(struct rt_mutex *lock, + struct hrtimer_sleeper *timeout, + int detect_deadlock) + { ++ int ret = 0, saved_lock_depth = -1; + struct rt_mutex_waiter waiter; +- int ret = 0; ++ unsigned long flags; + + debug_rt_mutex_init_waiter(&waiter); + waiter.task = NULL; + +- spin_lock(&lock->wait_lock); ++ spin_lock_irqsave(&lock->wait_lock, flags); ++ init_lists(lock); + + /* Try to acquire the lock again: */ + if (try_to_take_rt_mutex(lock)) { +- spin_unlock(&lock->wait_lock); ++ spin_unlock_irqrestore(&lock->wait_lock, flags); + return 0; + } + ++ /* ++ * We drop the BKL here before we go into the wait loop to avoid a ++ * possible deadlock in the scheduler. ++ */ ++ if (unlikely(current->lock_depth >= 0)) ++ saved_lock_depth = rt_release_bkl(lock, flags); ++ + set_current_state(state); + + /* Setup the timer, when timeout != NULL */ +@@ -635,6 +953,8 @@ rt_mutex_slowlock(struct rt_mutex *lock, + HRTIMER_MODE_ABS); + + for (;;) { ++ unsigned long saved_flags; ++ + /* Try to acquire the lock: */ + if (try_to_take_rt_mutex(lock)) + break; +@@ -660,7 +980,7 @@ rt_mutex_slowlock(struct rt_mutex *lock, + */ + if (!waiter.task) { + ret = task_blocks_on_rt_mutex(lock, &waiter, +- detect_deadlock); ++ detect_deadlock, flags); + /* + * If we got woken up by the owner then start loop + * all over without going into schedule to try +@@ -679,22 +999,26 @@ rt_mutex_slowlock(struct rt_mutex *lock, + if (unlikely(ret)) + break; + } ++ saved_flags = current->flags & PF_NOSCHED; ++ current->flags &= ~PF_NOSCHED; + +- spin_unlock(&lock->wait_lock); ++ spin_unlock_irq(&lock->wait_lock); + + debug_rt_mutex_print_deadlock(&waiter); + + if (waiter.task) + schedule_rt_mutex(lock); + +- spin_lock(&lock->wait_lock); ++ spin_lock_irq(&lock->wait_lock); ++ ++ current->flags |= saved_flags; + set_current_state(state); + } + + set_current_state(TASK_RUNNING); + + if (unlikely(waiter.task)) +- remove_waiter(lock, &waiter); ++ remove_waiter(lock, &waiter, flags); + + /* + * try_to_take_rt_mutex() sets the waiter bit +@@ -702,7 +1026,7 @@ rt_mutex_slowlock(struct rt_mutex *lock, + */ + fixup_rt_mutex_waiters(lock); + +- spin_unlock(&lock->wait_lock); ++ spin_unlock_irqrestore(&lock->wait_lock, flags); + + /* Remove pending timer: */ + if (unlikely(timeout)) +@@ -716,6 +1040,10 @@ rt_mutex_slowlock(struct rt_mutex *lock, + if (unlikely(ret)) + rt_mutex_adjust_prio(current); + ++ /* Must we reaquire the BKL? */ ++ if (unlikely(saved_lock_depth >= 0)) ++ rt_reacquire_bkl(saved_lock_depth); ++ + debug_rt_mutex_free_waiter(&waiter); + + return ret; +@@ -727,12 +1055,15 @@ rt_mutex_slowlock(struct rt_mutex *lock, + static inline int + rt_mutex_slowtrylock(struct rt_mutex *lock) + { ++ unsigned long flags; + int ret = 0; + +- spin_lock(&lock->wait_lock); ++ spin_lock_irqsave(&lock->wait_lock, flags); + + if (likely(rt_mutex_owner(lock) != current)) { + ++ init_lists(lock); ++ + ret = try_to_take_rt_mutex(lock); + /* + * try_to_take_rt_mutex() sets the lock waiters +@@ -741,7 +1072,7 @@ rt_mutex_slowtrylock(struct rt_mutex *lo + fixup_rt_mutex_waiters(lock); + } + +- spin_unlock(&lock->wait_lock); ++ spin_unlock_irqrestore(&lock->wait_lock, flags); + + return ret; + } +@@ -752,7 +1083,9 @@ rt_mutex_slowtrylock(struct rt_mutex *lo + static void __sched + rt_mutex_slowunlock(struct rt_mutex *lock) + { +- spin_lock(&lock->wait_lock); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&lock->wait_lock, flags); + + debug_rt_mutex_unlock(lock); + +@@ -760,13 +1093,13 @@ rt_mutex_slowunlock(struct rt_mutex *loc + + if (!rt_mutex_has_waiters(lock)) { + lock->owner = NULL; +- spin_unlock(&lock->wait_lock); ++ spin_unlock_irqrestore(&lock->wait_lock, flags); + return; + } + +- wakeup_next_waiter(lock); ++ wakeup_next_waiter(lock, 0); + +- spin_unlock(&lock->wait_lock); ++ spin_unlock_irqrestore(&lock->wait_lock, flags); + + /* Undo pi boosting if necessary: */ + rt_mutex_adjust_prio(current); +Index: linux-2.6.24.7-rt27/kernel/rwsem.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rwsem.c 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rwsem.c 2009-02-08 00:02:01.000000000 -0500 +@@ -16,7 +16,7 @@ + /* + * lock for reading + */ +-void __sched down_read(struct rw_semaphore *sem) ++void __sched compat_down_read(struct compat_rw_semaphore *sem) + { + might_sleep(); + rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_); +@@ -24,12 +24,12 @@ void __sched down_read(struct rw_semapho + LOCK_CONTENDED(sem, __down_read_trylock, __down_read); + } + +-EXPORT_SYMBOL(down_read); ++EXPORT_SYMBOL(compat_down_read); + + /* + * trylock for reading -- returns 1 if successful, 0 if contention + */ +-int down_read_trylock(struct rw_semaphore *sem) ++int compat_down_read_trylock(struct compat_rw_semaphore *sem) + { + int ret = __down_read_trylock(sem); + +@@ -38,12 +38,12 @@ int down_read_trylock(struct rw_semaphor + return ret; + } + +-EXPORT_SYMBOL(down_read_trylock); ++EXPORT_SYMBOL(compat_down_read_trylock); + + /* + * lock for writing + */ +-void __sched down_write(struct rw_semaphore *sem) ++void __sched compat_down_write(struct compat_rw_semaphore *sem) + { + might_sleep(); + rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_); +@@ -51,12 +51,12 @@ void __sched down_write(struct rw_semaph + LOCK_CONTENDED(sem, __down_write_trylock, __down_write); + } + +-EXPORT_SYMBOL(down_write); ++EXPORT_SYMBOL(compat_down_write); + + /* + * trylock for writing -- returns 1 if successful, 0 if contention + */ +-int down_write_trylock(struct rw_semaphore *sem) ++int compat_down_write_trylock(struct compat_rw_semaphore *sem) + { + int ret = __down_write_trylock(sem); + +@@ -65,36 +65,36 @@ int down_write_trylock(struct rw_semapho + return ret; + } + +-EXPORT_SYMBOL(down_write_trylock); ++EXPORT_SYMBOL(compat_down_write_trylock); + + /* + * release a read lock + */ +-void up_read(struct rw_semaphore *sem) ++void compat_up_read(struct compat_rw_semaphore *sem) + { + rwsem_release(&sem->dep_map, 1, _RET_IP_); + + __up_read(sem); + } + +-EXPORT_SYMBOL(up_read); ++EXPORT_SYMBOL(compat_up_read); + + /* + * release a write lock + */ +-void up_write(struct rw_semaphore *sem) ++void compat_up_write(struct compat_rw_semaphore *sem) + { + rwsem_release(&sem->dep_map, 1, _RET_IP_); + + __up_write(sem); + } + +-EXPORT_SYMBOL(up_write); ++EXPORT_SYMBOL(compat_up_write); + + /* + * downgrade write lock to read lock + */ +-void downgrade_write(struct rw_semaphore *sem) ++void compat_downgrade_write(struct compat_rw_semaphore *sem) + { + /* + * lockdep: a downgraded write will live on as a write +@@ -103,11 +103,11 @@ void downgrade_write(struct rw_semaphore + __downgrade_write(sem); + } + +-EXPORT_SYMBOL(downgrade_write); ++EXPORT_SYMBOL(compat_downgrade_write); + + #ifdef CONFIG_DEBUG_LOCK_ALLOC + +-void down_read_nested(struct rw_semaphore *sem, int subclass) ++void compat_down_read_nested(struct compat_rw_semaphore *sem, int subclass) + { + might_sleep(); + rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_); +@@ -115,18 +115,18 @@ void down_read_nested(struct rw_semaphor + LOCK_CONTENDED(sem, __down_read_trylock, __down_read); + } + +-EXPORT_SYMBOL(down_read_nested); ++EXPORT_SYMBOL(compat_down_read_nested); + +-void down_read_non_owner(struct rw_semaphore *sem) ++void compat_down_read_non_owner(struct compat_rw_semaphore *sem) + { + might_sleep(); + + __down_read(sem); + } + +-EXPORT_SYMBOL(down_read_non_owner); ++EXPORT_SYMBOL(compat_down_read_non_owner); + +-void down_write_nested(struct rw_semaphore *sem, int subclass) ++void compat_down_write_nested(struct compat_rw_semaphore *sem, int subclass) + { + might_sleep(); + rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_); +@@ -134,14 +134,14 @@ void down_write_nested(struct rw_semapho + LOCK_CONTENDED(sem, __down_write_trylock, __down_write); + } + +-EXPORT_SYMBOL(down_write_nested); ++EXPORT_SYMBOL(compat_down_write_nested); + +-void up_read_non_owner(struct rw_semaphore *sem) ++void compat_up_read_non_owner(struct compat_rw_semaphore *sem) + { + __up_read(sem); + } + +-EXPORT_SYMBOL(up_read_non_owner); ++EXPORT_SYMBOL(compat_up_read_non_owner); + + #endif + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:02:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:02:01.000000000 -0500 +@@ -1585,7 +1585,8 @@ static int sched_balance_self(int cpu, i + * + * returns failure only if the task is already active. + */ +-static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync) ++static int ++try_to_wake_up(struct task_struct *p, unsigned int state, int sync, int mutex) + { + int cpu, orig_cpu, this_cpu, success = 0; + unsigned long flags; +@@ -1671,13 +1672,38 @@ out: + int fastcall wake_up_process(struct task_struct *p) + { + return try_to_wake_up(p, TASK_STOPPED | TASK_TRACED | +- TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0); ++ TASK_RUNNING_MUTEX | TASK_INTERRUPTIBLE | ++ TASK_UNINTERRUPTIBLE, 0, 0); + } + EXPORT_SYMBOL(wake_up_process); + ++int fastcall wake_up_process_sync(struct task_struct * p) ++{ ++ return try_to_wake_up(p, TASK_STOPPED | TASK_TRACED | ++ TASK_RUNNING_MUTEX | TASK_INTERRUPTIBLE | ++ TASK_UNINTERRUPTIBLE, 1, 0); ++} ++EXPORT_SYMBOL(wake_up_process_sync); ++ ++int fastcall wake_up_process_mutex(struct task_struct * p) ++{ ++ return try_to_wake_up(p, TASK_STOPPED | TASK_TRACED | ++ TASK_RUNNING_MUTEX | TASK_INTERRUPTIBLE | ++ TASK_UNINTERRUPTIBLE, 0, 1); ++} ++EXPORT_SYMBOL(wake_up_process_mutex); ++ ++int fastcall wake_up_process_mutex_sync(struct task_struct * p) ++{ ++ return try_to_wake_up(p, TASK_STOPPED | TASK_TRACED | ++ TASK_RUNNING_MUTEX | TASK_INTERRUPTIBLE | ++ TASK_UNINTERRUPTIBLE, 1, 1); ++} ++EXPORT_SYMBOL(wake_up_process_mutex_sync); ++ + int fastcall wake_up_state(struct task_struct *p, unsigned int state) + { +- return try_to_wake_up(p, state, 0); ++ return try_to_wake_up(p, state | TASK_RUNNING_MUTEX, 0, 0); + } + + /* +@@ -3877,7 +3903,8 @@ asmlinkage void __sched preempt_schedule + int default_wake_function(wait_queue_t *curr, unsigned mode, int sync, + void *key) + { +- return try_to_wake_up(curr->private, mode, sync); ++ return try_to_wake_up(curr->private, mode | TASK_RUNNING_MUTEX, ++ sync, 0); + } + EXPORT_SYMBOL(default_wake_function); + +@@ -3917,8 +3944,9 @@ void fastcall __wake_up(wait_queue_head_ + unsigned long flags; + + spin_lock_irqsave(&q->lock, flags); +- __wake_up_common(q, mode, nr_exclusive, 0, key); ++ __wake_up_common(q, mode, nr_exclusive, 1, key); + spin_unlock_irqrestore(&q->lock, flags); ++ preempt_check_resched_delayed(); + } + EXPORT_SYMBOL(__wake_up); + +@@ -3968,8 +3996,9 @@ void complete(struct completion *x) + spin_lock_irqsave(&x->wait.lock, flags); + x->done++; + __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, +- 1, 0, NULL); ++ 1, 1, NULL); + spin_unlock_irqrestore(&x->wait.lock, flags); ++ preempt_check_resched_delayed(); + } + EXPORT_SYMBOL(complete); + +@@ -3980,11 +4009,18 @@ void complete_all(struct completion *x) + spin_lock_irqsave(&x->wait.lock, flags); + x->done += UINT_MAX/2; + __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, +- 0, 0, NULL); ++ 0, 1, NULL); + spin_unlock_irqrestore(&x->wait.lock, flags); ++ preempt_check_resched_delayed(); + } + EXPORT_SYMBOL(complete_all); + ++unsigned int fastcall completion_done(struct completion *x) ++{ ++ return x->done; ++} ++EXPORT_SYMBOL(completion_done); ++ + static inline long __sched + do_wait_for_common(struct completion *x, long timeout, int state) + { +@@ -4735,10 +4771,7 @@ asmlinkage long sys_sched_yield(void) + * Since we are going to call schedule() anyway, there's + * no need to preempt or enable interrupts: + */ +- __release(rq->lock); +- spin_release(&rq->lock.dep_map, 1, _THIS_IP_); +- _raw_spin_unlock(&rq->lock); +- preempt_enable_no_resched(); ++ spin_unlock_no_resched(&rq->lock); + + schedule(); + +@@ -4781,7 +4814,7 @@ EXPORT_SYMBOL(cond_resched); + * operations here to prevent schedule() from being called twice (once via + * spin_unlock(), once by hand). + */ +-int cond_resched_lock(spinlock_t *lock) ++int __cond_resched_raw_spinlock(raw_spinlock_t *lock) + { + int ret = 0; + +@@ -4792,24 +4825,23 @@ int cond_resched_lock(spinlock_t *lock) + spin_lock(lock); + } + if (need_resched() && system_state == SYSTEM_RUNNING) { +- spin_release(&lock->dep_map, 1, _THIS_IP_); +- _raw_spin_unlock(lock); +- preempt_enable_no_resched(); ++ spin_unlock_no_resched(lock); + __cond_resched(); + ret = 1; + spin_lock(lock); + } + return ret; + } +-EXPORT_SYMBOL(cond_resched_lock); ++EXPORT_SYMBOL(__cond_resched_raw_spinlock); + + /* + * Voluntarily preempt a process context that has softirqs disabled: + */ + int __sched cond_resched_softirq(void) + { ++#ifndef CONFIG_PREEMPT_RT + WARN_ON_ONCE(!in_softirq()); +- ++#endif + if (need_resched() && system_state == SYSTEM_RUNNING) { + local_bh_enable(); + __cond_resched(); +@@ -5018,19 +5050,23 @@ static void show_task(struct task_struct + unsigned state; + + state = p->state ? __ffs(p->state) + 1 : 0; +- printk(KERN_INFO "%-13.13s %c", p->comm, +- state < sizeof(stat_nam) - 1 ? stat_nam[state] : '?'); ++ printk("%-13.13s %c [%p]", p->comm, ++ state < sizeof(stat_nam) - 1 ? stat_nam[state] : '?', p); + #if BITS_PER_LONG == 32 +- if (state == TASK_RUNNING) ++ if (0 && (state == TASK_RUNNING)) + printk(KERN_CONT " running "); + else + printk(KERN_CONT " %08lx ", thread_saved_pc(p)); + #else +- if (state == TASK_RUNNING) ++ if (0 && (state == TASK_RUNNING)) + printk(KERN_CONT " running task "); + else + printk(KERN_CONT " %016lx ", thread_saved_pc(p)); + #endif ++ if (task_curr(p)) ++ printk("[curr] "); ++ else if (p->se.on_rq) ++ printk("[on rq #%d] ", task_cpu(p)); + #ifdef CONFIG_DEBUG_STACK_USAGE + { + unsigned long *n = end_of_stack(p); +Index: linux-2.6.24.7-rt27/kernel/spinlock.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/spinlock.c 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/spinlock.c 2009-02-08 00:02:01.000000000 -0500 +@@ -21,7 +21,7 @@ + #include + #include + +-int __lockfunc _spin_trylock(spinlock_t *lock) ++int __lockfunc __spin_trylock(raw_spinlock_t *lock) + { + preempt_disable(); + if (_raw_spin_trylock(lock)) { +@@ -32,9 +32,46 @@ int __lockfunc _spin_trylock(spinlock_t + preempt_enable(); + return 0; + } +-EXPORT_SYMBOL(_spin_trylock); ++EXPORT_SYMBOL(__spin_trylock); + +-int __lockfunc _read_trylock(rwlock_t *lock) ++int __lockfunc __spin_trylock_irq(raw_spinlock_t *lock) ++{ ++ local_irq_disable(); ++ preempt_disable(); ++ ++ if (_raw_spin_trylock(lock)) { ++ spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); ++ return 1; ++ } ++ ++ __preempt_enable_no_resched(); ++ local_irq_enable(); ++ preempt_check_resched(); ++ ++ return 0; ++} ++EXPORT_SYMBOL(__spin_trylock_irq); ++ ++int __lockfunc __spin_trylock_irqsave(raw_spinlock_t *lock, ++ unsigned long *flags) ++{ ++ local_irq_save(*flags); ++ preempt_disable(); ++ ++ if (_raw_spin_trylock(lock)) { ++ spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); ++ return 1; ++ } ++ ++ __preempt_enable_no_resched(); ++ local_irq_restore(*flags); ++ preempt_check_resched(); ++ ++ return 0; ++} ++EXPORT_SYMBOL(__spin_trylock_irqsave); ++ ++int __lockfunc __read_trylock(raw_rwlock_t *lock) + { + preempt_disable(); + if (_raw_read_trylock(lock)) { +@@ -45,9 +82,9 @@ int __lockfunc _read_trylock(rwlock_t *l + preempt_enable(); + return 0; + } +-EXPORT_SYMBOL(_read_trylock); ++EXPORT_SYMBOL(__read_trylock); + +-int __lockfunc _write_trylock(rwlock_t *lock) ++int __lockfunc __write_trylock(raw_rwlock_t *lock) + { + preempt_disable(); + if (_raw_write_trylock(lock)) { +@@ -58,7 +95,21 @@ int __lockfunc _write_trylock(rwlock_t * + preempt_enable(); + return 0; + } +-EXPORT_SYMBOL(_write_trylock); ++EXPORT_SYMBOL(__write_trylock); ++ ++int __lockfunc __write_trylock_irqsave(raw_rwlock_t *lock, unsigned long *flags) ++{ ++ int ret; ++ ++ local_irq_save(*flags); ++ ret = __write_trylock(lock); ++ if (ret) ++ return ret; ++ ++ local_irq_restore(*flags); ++ return 0; ++} ++EXPORT_SYMBOL(__write_trylock_irqsave); + + /* + * If lockdep is enabled then we use the non-preemption spin-ops +@@ -66,17 +117,17 @@ EXPORT_SYMBOL(_write_trylock); + * not re-enabled during lock-acquire (which the preempt-spin-ops do): + */ + #if !defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP) || \ +- defined(CONFIG_DEBUG_LOCK_ALLOC) ++ defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_PREEMPT_RT) + +-void __lockfunc _read_lock(rwlock_t *lock) ++void __lockfunc __read_lock(raw_rwlock_t *lock) + { + preempt_disable(); + rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock); + } +-EXPORT_SYMBOL(_read_lock); ++EXPORT_SYMBOL(__read_lock); + +-unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) ++unsigned long __lockfunc __spin_lock_irqsave(raw_spinlock_t *lock) + { + unsigned long flags; + +@@ -95,27 +146,27 @@ unsigned long __lockfunc _spin_lock_irqs + #endif + return flags; + } +-EXPORT_SYMBOL(_spin_lock_irqsave); ++EXPORT_SYMBOL(__spin_lock_irqsave); + +-void __lockfunc _spin_lock_irq(spinlock_t *lock) ++void __lockfunc __spin_lock_irq(raw_spinlock_t *lock) + { + local_irq_disable(); + preempt_disable(); + spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); + } +-EXPORT_SYMBOL(_spin_lock_irq); ++EXPORT_SYMBOL(__spin_lock_irq); + +-void __lockfunc _spin_lock_bh(spinlock_t *lock) ++void __lockfunc __spin_lock_bh(raw_spinlock_t *lock) + { + local_bh_disable(); + preempt_disable(); + spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); + } +-EXPORT_SYMBOL(_spin_lock_bh); ++EXPORT_SYMBOL(__spin_lock_bh); + +-unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) ++unsigned long __lockfunc __read_lock_irqsave(raw_rwlock_t *lock) + { + unsigned long flags; + +@@ -125,27 +176,27 @@ unsigned long __lockfunc _read_lock_irqs + LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock); + return flags; + } +-EXPORT_SYMBOL(_read_lock_irqsave); ++EXPORT_SYMBOL(__read_lock_irqsave); + +-void __lockfunc _read_lock_irq(rwlock_t *lock) ++void __lockfunc __read_lock_irq(raw_rwlock_t *lock) + { + local_irq_disable(); + preempt_disable(); + rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock); + } +-EXPORT_SYMBOL(_read_lock_irq); ++EXPORT_SYMBOL(__read_lock_irq); + +-void __lockfunc _read_lock_bh(rwlock_t *lock) ++void __lockfunc __read_lock_bh(raw_rwlock_t *lock) + { + local_bh_disable(); + preempt_disable(); + rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock); + } +-EXPORT_SYMBOL(_read_lock_bh); ++EXPORT_SYMBOL(__read_lock_bh); + +-unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) ++unsigned long __lockfunc __write_lock_irqsave(raw_rwlock_t *lock) + { + unsigned long flags; + +@@ -155,43 +206,43 @@ unsigned long __lockfunc _write_lock_irq + LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock); + return flags; + } +-EXPORT_SYMBOL(_write_lock_irqsave); ++EXPORT_SYMBOL(__write_lock_irqsave); + +-void __lockfunc _write_lock_irq(rwlock_t *lock) ++void __lockfunc __write_lock_irq(raw_rwlock_t *lock) + { + local_irq_disable(); + preempt_disable(); + rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock); + } +-EXPORT_SYMBOL(_write_lock_irq); ++EXPORT_SYMBOL(__write_lock_irq); + +-void __lockfunc _write_lock_bh(rwlock_t *lock) ++void __lockfunc __write_lock_bh(raw_rwlock_t *lock) + { + local_bh_disable(); + preempt_disable(); + rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock); + } +-EXPORT_SYMBOL(_write_lock_bh); ++EXPORT_SYMBOL(__write_lock_bh); + +-void __lockfunc _spin_lock(spinlock_t *lock) ++void __lockfunc __spin_lock(raw_spinlock_t *lock) + { + preempt_disable(); + spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); + } + +-EXPORT_SYMBOL(_spin_lock); ++EXPORT_SYMBOL(__spin_lock); + +-void __lockfunc _write_lock(rwlock_t *lock) ++void __lockfunc __write_lock(raw_rwlock_t *lock) + { + preempt_disable(); + rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock); + } + +-EXPORT_SYMBOL(_write_lock); ++EXPORT_SYMBOL(__write_lock); + + #else /* CONFIG_PREEMPT: */ + +@@ -204,7 +255,7 @@ EXPORT_SYMBOL(_write_lock); + */ + + #define BUILD_LOCK_OPS(op, locktype) \ +-void __lockfunc _##op##_lock(locktype##_t *lock) \ ++void __lockfunc __##op##_lock(locktype##_t *lock) \ + { \ + for (;;) { \ + preempt_disable(); \ +@@ -214,15 +265,16 @@ void __lockfunc _##op##_lock(locktype##_ + \ + if (!(lock)->break_lock) \ + (lock)->break_lock = 1; \ +- while (!op##_can_lock(lock) && (lock)->break_lock) \ +- _raw_##op##_relax(&lock->raw_lock); \ ++ while (!__raw_##op##_can_lock(&(lock)->raw_lock) && \ ++ (lock)->break_lock) \ ++ __raw_##op##_relax(&lock->raw_lock); \ + } \ + (lock)->break_lock = 0; \ + } \ + \ +-EXPORT_SYMBOL(_##op##_lock); \ ++EXPORT_SYMBOL(__##op##_lock); \ + \ +-unsigned long __lockfunc _##op##_lock_irqsave(locktype##_t *lock) \ ++unsigned long __lockfunc __##op##_lock_irqsave(locktype##_t *lock) \ + { \ + unsigned long flags; \ + \ +@@ -236,23 +288,24 @@ unsigned long __lockfunc _##op##_lock_ir + \ + if (!(lock)->break_lock) \ + (lock)->break_lock = 1; \ +- while (!op##_can_lock(lock) && (lock)->break_lock) \ +- _raw_##op##_relax(&lock->raw_lock); \ ++ while (!__raw_##op##_can_lock(&(lock)->raw_lock) && \ ++ (lock)->break_lock) \ ++ __raw_##op##_relax(&lock->raw_lock); \ + } \ + (lock)->break_lock = 0; \ + return flags; \ + } \ + \ +-EXPORT_SYMBOL(_##op##_lock_irqsave); \ ++EXPORT_SYMBOL(__##op##_lock_irqsave); \ + \ +-void __lockfunc _##op##_lock_irq(locktype##_t *lock) \ ++void __lockfunc __##op##_lock_irq(locktype##_t *lock) \ + { \ +- _##op##_lock_irqsave(lock); \ ++ __##op##_lock_irqsave(lock); \ + } \ + \ +-EXPORT_SYMBOL(_##op##_lock_irq); \ ++EXPORT_SYMBOL(__##op##_lock_irq); \ + \ +-void __lockfunc _##op##_lock_bh(locktype##_t *lock) \ ++void __lockfunc __##op##_lock_bh(locktype##_t *lock) \ + { \ + unsigned long flags; \ + \ +@@ -261,39 +314,40 @@ void __lockfunc _##op##_lock_bh(locktype + /* irq-disabling. We use the generic preemption-aware */ \ + /* function: */ \ + /**/ \ +- flags = _##op##_lock_irqsave(lock); \ ++ flags = __##op##_lock_irqsave(lock); \ + local_bh_disable(); \ + local_irq_restore(flags); \ + } \ + \ +-EXPORT_SYMBOL(_##op##_lock_bh) ++EXPORT_SYMBOL(__##op##_lock_bh) + + /* + * Build preemption-friendly versions of the following + * lock-spinning functions: + * +- * _[spin|read|write]_lock() +- * _[spin|read|write]_lock_irq() +- * _[spin|read|write]_lock_irqsave() +- * _[spin|read|write]_lock_bh() ++ * __[spin|read|write]_lock() ++ * __[spin|read|write]_lock_irq() ++ * __[spin|read|write]_lock_irqsave() ++ * __[spin|read|write]_lock_bh() + */ +-BUILD_LOCK_OPS(spin, spinlock); +-BUILD_LOCK_OPS(read, rwlock); +-BUILD_LOCK_OPS(write, rwlock); ++BUILD_LOCK_OPS(spin, raw_spinlock); ++BUILD_LOCK_OPS(read, raw_rwlock); ++BUILD_LOCK_OPS(write, raw_rwlock); + + #endif /* CONFIG_PREEMPT */ + + #ifdef CONFIG_DEBUG_LOCK_ALLOC + +-void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass) ++void __lockfunc __spin_lock_nested(raw_spinlock_t *lock, int subclass) + { + preempt_disable(); + spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); + } ++EXPORT_SYMBOL(__spin_lock_nested); + +-EXPORT_SYMBOL(_spin_lock_nested); +-unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclass) ++unsigned long __lockfunc ++__spin_lock_irqsave_nested(raw_spinlock_t *lock, int subclass) + { + unsigned long flags; + +@@ -312,117 +366,130 @@ unsigned long __lockfunc _spin_lock_irqs + #endif + return flags; + } +- +-EXPORT_SYMBOL(_spin_lock_irqsave_nested); ++EXPORT_SYMBOL(__spin_lock_irqsave_nested); + + #endif + +-void __lockfunc _spin_unlock(spinlock_t *lock) ++void __lockfunc __spin_unlock(raw_spinlock_t *lock) + { + spin_release(&lock->dep_map, 1, _RET_IP_); + _raw_spin_unlock(lock); + preempt_enable(); + } +-EXPORT_SYMBOL(_spin_unlock); ++EXPORT_SYMBOL(__spin_unlock); ++ ++void __lockfunc __spin_unlock_no_resched(raw_spinlock_t *lock) ++{ ++ spin_release(&lock->dep_map, 1, _RET_IP_); ++ _raw_spin_unlock(lock); ++ __preempt_enable_no_resched(); ++} ++/* not exported */ + +-void __lockfunc _write_unlock(rwlock_t *lock) ++void __lockfunc __write_unlock(raw_rwlock_t *lock) + { + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_write_unlock(lock); + preempt_enable(); + } +-EXPORT_SYMBOL(_write_unlock); ++EXPORT_SYMBOL(__write_unlock); + +-void __lockfunc _read_unlock(rwlock_t *lock) ++void __lockfunc __read_unlock(raw_rwlock_t *lock) + { + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_read_unlock(lock); + preempt_enable(); + } +-EXPORT_SYMBOL(_read_unlock); ++EXPORT_SYMBOL(__read_unlock); + +-void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) ++void __lockfunc __spin_unlock_irqrestore(raw_spinlock_t *lock, unsigned long flags) + { + spin_release(&lock->dep_map, 1, _RET_IP_); + _raw_spin_unlock(lock); ++ __preempt_enable_no_resched(); + local_irq_restore(flags); +- preempt_enable(); ++ preempt_check_resched(); + } +-EXPORT_SYMBOL(_spin_unlock_irqrestore); ++EXPORT_SYMBOL(__spin_unlock_irqrestore); + +-void __lockfunc _spin_unlock_irq(spinlock_t *lock) ++void __lockfunc __spin_unlock_irq(raw_spinlock_t *lock) + { + spin_release(&lock->dep_map, 1, _RET_IP_); + _raw_spin_unlock(lock); ++ __preempt_enable_no_resched(); + local_irq_enable(); +- preempt_enable(); ++ preempt_check_resched(); + } +-EXPORT_SYMBOL(_spin_unlock_irq); ++EXPORT_SYMBOL(__spin_unlock_irq); + +-void __lockfunc _spin_unlock_bh(spinlock_t *lock) ++void __lockfunc __spin_unlock_bh(raw_spinlock_t *lock) + { + spin_release(&lock->dep_map, 1, _RET_IP_); + _raw_spin_unlock(lock); +- preempt_enable_no_resched(); ++ __preempt_enable_no_resched(); + local_bh_enable_ip((unsigned long)__builtin_return_address(0)); + } +-EXPORT_SYMBOL(_spin_unlock_bh); ++EXPORT_SYMBOL(__spin_unlock_bh); + +-void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) ++void __lockfunc __read_unlock_irqrestore(raw_rwlock_t *lock, unsigned long flags) + { + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_read_unlock(lock); ++ __preempt_enable_no_resched(); + local_irq_restore(flags); +- preempt_enable(); ++ preempt_check_resched(); + } +-EXPORT_SYMBOL(_read_unlock_irqrestore); ++EXPORT_SYMBOL(__read_unlock_irqrestore); + +-void __lockfunc _read_unlock_irq(rwlock_t *lock) ++void __lockfunc __read_unlock_irq(raw_rwlock_t *lock) + { + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_read_unlock(lock); ++ __preempt_enable_no_resched(); + local_irq_enable(); +- preempt_enable(); ++ preempt_check_resched(); + } +-EXPORT_SYMBOL(_read_unlock_irq); ++EXPORT_SYMBOL(__read_unlock_irq); + +-void __lockfunc _read_unlock_bh(rwlock_t *lock) ++void __lockfunc __read_unlock_bh(raw_rwlock_t *lock) + { + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_read_unlock(lock); +- preempt_enable_no_resched(); ++ __preempt_enable_no_resched(); + local_bh_enable_ip((unsigned long)__builtin_return_address(0)); + } +-EXPORT_SYMBOL(_read_unlock_bh); ++EXPORT_SYMBOL(__read_unlock_bh); + +-void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) ++void __lockfunc __write_unlock_irqrestore(raw_rwlock_t *lock, unsigned long flags) + { + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_write_unlock(lock); ++ __preempt_enable_no_resched(); + local_irq_restore(flags); +- preempt_enable(); ++ preempt_check_resched(); + } +-EXPORT_SYMBOL(_write_unlock_irqrestore); ++EXPORT_SYMBOL(__write_unlock_irqrestore); + +-void __lockfunc _write_unlock_irq(rwlock_t *lock) ++void __lockfunc __write_unlock_irq(raw_rwlock_t *lock) + { + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_write_unlock(lock); ++ __preempt_enable_no_resched(); + local_irq_enable(); +- preempt_enable(); ++ preempt_check_resched(); + } +-EXPORT_SYMBOL(_write_unlock_irq); ++EXPORT_SYMBOL(__write_unlock_irq); + +-void __lockfunc _write_unlock_bh(rwlock_t *lock) ++void __lockfunc __write_unlock_bh(raw_rwlock_t *lock) + { + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_write_unlock(lock); +- preempt_enable_no_resched(); ++ __preempt_enable_no_resched(); + local_bh_enable_ip((unsigned long)__builtin_return_address(0)); + } +-EXPORT_SYMBOL(_write_unlock_bh); ++EXPORT_SYMBOL(__write_unlock_bh); + +-int __lockfunc _spin_trylock_bh(spinlock_t *lock) ++int __lockfunc __spin_trylock_bh(raw_spinlock_t *lock) + { + local_bh_disable(); + preempt_disable(); +@@ -431,11 +498,11 @@ int __lockfunc _spin_trylock_bh(spinlock + return 1; + } + +- preempt_enable_no_resched(); ++ __preempt_enable_no_resched(); + local_bh_enable_ip((unsigned long)__builtin_return_address(0)); + return 0; + } +-EXPORT_SYMBOL(_spin_trylock_bh); ++EXPORT_SYMBOL(__spin_trylock_bh); + + int in_lock_functions(unsigned long addr) + { +@@ -443,6 +510,17 @@ int in_lock_functions(unsigned long addr + extern char __lock_text_start[], __lock_text_end[]; + + return addr >= (unsigned long)__lock_text_start +- && addr < (unsigned long)__lock_text_end; ++ && addr < (unsigned long)__lock_text_end; + } + EXPORT_SYMBOL(in_lock_functions); ++ ++void notrace __debug_atomic_dec_and_test(atomic_t *v) ++{ ++ static int warn_once = 1; ++ ++ if (!atomic_read(v) && warn_once) { ++ warn_once = 0; ++ printk("BUG: atomic counter underflow!\n"); ++ WARN_ON(1); ++ } ++} +Index: linux-2.6.24.7-rt27/lib/dec_and_lock.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/dec_and_lock.c 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/dec_and_lock.c 2009-02-08 00:02:01.000000000 -0500 +@@ -17,7 +17,7 @@ + * because the spin-lock and the decrement must be + * "atomic". + */ +-int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) ++int __atomic_dec_and_spin_lock(atomic_t *atomic, raw_spinlock_t *lock) + { + #ifdef CONFIG_SMP + /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */ +@@ -32,4 +32,4 @@ int _atomic_dec_and_lock(atomic_t *atomi + return 0; + } + +-EXPORT_SYMBOL(_atomic_dec_and_lock); ++EXPORT_SYMBOL(__atomic_dec_and_spin_lock); +Index: linux-2.6.24.7-rt27/lib/kernel_lock.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/kernel_lock.c 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/kernel_lock.c 2009-02-08 00:02:01.000000000 -0500 +@@ -24,7 +24,7 @@ + * + * Don't use in new code. + */ +-static DECLARE_MUTEX(kernel_sem); ++DECLARE_MUTEX(kernel_sem); + + /* + * Re-acquire the kernel semaphore. +@@ -44,7 +44,7 @@ int __lockfunc __reacquire_kernel_lock(v + BUG_ON(saved_lock_depth < 0); + + task->lock_depth = -1; +- preempt_enable_no_resched(); ++ __preempt_enable_no_resched(); + + down(&kernel_sem); + +Index: linux-2.6.24.7-rt27/lib/locking-selftest.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/locking-selftest.c 2009-02-08 00:00:11.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/locking-selftest.c 2009-02-08 00:02:01.000000000 -0500 +@@ -940,6 +940,9 @@ static void dotest(void (*testcase_fn)(v + { + unsigned long saved_preempt_count = preempt_count(); + int expected_failure = 0; ++#if defined(CONFIG_DEBUG_PREEMPT) && defined(CONFIG_DEBUG_RT_MUTEXES) ++ int saved_lock_count = current->lock_count; ++#endif + + WARN_ON(irqs_disabled()); + +@@ -989,6 +992,9 @@ static void dotest(void (*testcase_fn)(v + #endif + + reset_locks(); ++#if defined(CONFIG_DEBUG_PREEMPT) && defined(CONFIG_DEBUG_RT_MUTEXES) ++ current->lock_count = saved_lock_count; ++#endif + } + + static inline void print_testname(const char *testname) +Index: linux-2.6.24.7-rt27/lib/plist.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/plist.c 2009-02-08 00:00:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/plist.c 2009-02-08 00:02:01.000000000 -0500 +@@ -53,7 +53,9 @@ static void plist_check_list(struct list + + static void plist_check_head(struct plist_head *head) + { ++#ifndef CONFIG_PREEMPT_RT + WARN_ON(!head->lock); ++#endif + if (head->lock) + WARN_ON_SMP(!spin_is_locked(head->lock)); + plist_check_list(&head->prio_list); +Index: linux-2.6.24.7-rt27/lib/rwsem-spinlock.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/rwsem-spinlock.c 2009-02-08 00:00:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/rwsem-spinlock.c 2009-02-08 00:02:01.000000000 -0500 +@@ -20,7 +20,7 @@ struct rwsem_waiter { + /* + * initialise the semaphore + */ +-void __init_rwsem(struct rw_semaphore *sem, const char *name, ++void __compat_init_rwsem(struct compat_rw_semaphore *sem, const char *name, + struct lock_class_key *key) + { + #ifdef CONFIG_DEBUG_LOCK_ALLOC +@@ -44,8 +44,8 @@ void __init_rwsem(struct rw_semaphore *s + * - woken process blocks are discarded from the list after having task zeroed + * - writers are only woken if wakewrite is non-zero + */ +-static inline struct rw_semaphore * +-__rwsem_do_wake(struct rw_semaphore *sem, int wakewrite) ++static inline struct compat_rw_semaphore * ++__rwsem_do_wake(struct compat_rw_semaphore *sem, int wakewrite) + { + struct rwsem_waiter *waiter; + struct task_struct *tsk; +@@ -103,8 +103,8 @@ __rwsem_do_wake(struct rw_semaphore *sem + /* + * wake a single writer + */ +-static inline struct rw_semaphore * +-__rwsem_wake_one_writer(struct rw_semaphore *sem) ++static inline struct compat_rw_semaphore * ++__rwsem_wake_one_writer(struct compat_rw_semaphore *sem) + { + struct rwsem_waiter *waiter; + struct task_struct *tsk; +@@ -125,7 +125,7 @@ __rwsem_wake_one_writer(struct rw_semaph + /* + * get a read lock on the semaphore + */ +-void fastcall __sched __down_read(struct rw_semaphore *sem) ++void fastcall __sched __down_read(struct compat_rw_semaphore *sem) + { + struct rwsem_waiter waiter; + struct task_struct *tsk; +@@ -168,7 +168,7 @@ void fastcall __sched __down_read(struct + /* + * trylock for reading -- returns 1 if successful, 0 if contention + */ +-int fastcall __down_read_trylock(struct rw_semaphore *sem) ++int fastcall __down_read_trylock(struct compat_rw_semaphore *sem) + { + unsigned long flags; + int ret = 0; +@@ -191,7 +191,8 @@ int fastcall __down_read_trylock(struct + * get a write lock on the semaphore + * - we increment the waiting count anyway to indicate an exclusive lock + */ +-void fastcall __sched __down_write_nested(struct rw_semaphore *sem, int subclass) ++void fastcall __sched ++__down_write_nested(struct compat_rw_semaphore *sem, int subclass) + { + struct rwsem_waiter waiter; + struct task_struct *tsk; +@@ -231,7 +232,7 @@ void fastcall __sched __down_write_neste + ; + } + +-void fastcall __sched __down_write(struct rw_semaphore *sem) ++void fastcall __sched __down_write(struct compat_rw_semaphore *sem) + { + __down_write_nested(sem, 0); + } +@@ -239,7 +240,7 @@ void fastcall __sched __down_write(struc + /* + * trylock for writing -- returns 1 if successful, 0 if contention + */ +-int fastcall __down_write_trylock(struct rw_semaphore *sem) ++int fastcall __down_write_trylock(struct compat_rw_semaphore *sem) + { + unsigned long flags; + int ret = 0; +@@ -260,7 +261,7 @@ int fastcall __down_write_trylock(struct + /* + * release a read lock on the semaphore + */ +-void fastcall __up_read(struct rw_semaphore *sem) ++void fastcall __up_read(struct compat_rw_semaphore *sem) + { + unsigned long flags; + +@@ -275,7 +276,7 @@ void fastcall __up_read(struct rw_semaph + /* + * release a write lock on the semaphore + */ +-void fastcall __up_write(struct rw_semaphore *sem) ++void fastcall __up_write(struct compat_rw_semaphore *sem) + { + unsigned long flags; + +@@ -292,7 +293,7 @@ void fastcall __up_write(struct rw_semap + * downgrade a write lock into a read lock + * - just wake up any readers at the front of the queue + */ +-void fastcall __downgrade_write(struct rw_semaphore *sem) ++void fastcall __downgrade_write(struct compat_rw_semaphore *sem) + { + unsigned long flags; + +@@ -305,7 +306,7 @@ void fastcall __downgrade_write(struct r + spin_unlock_irqrestore(&sem->wait_lock, flags); + } + +-EXPORT_SYMBOL(__init_rwsem); ++EXPORT_SYMBOL(__compat_init_rwsem); + EXPORT_SYMBOL(__down_read); + EXPORT_SYMBOL(__down_read_trylock); + EXPORT_SYMBOL(__down_write_nested); +Index: linux-2.6.24.7-rt27/lib/rwsem.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/rwsem.c 2009-02-08 00:00:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/rwsem.c 2009-02-08 00:02:01.000000000 -0500 +@@ -11,8 +11,8 @@ + /* + * Initialize an rwsem: + */ +-void __init_rwsem(struct rw_semaphore *sem, const char *name, +- struct lock_class_key *key) ++void __compat_init_rwsem(struct rw_semaphore *sem, const char *name, ++ struct lock_class_key *key) + { + #ifdef CONFIG_DEBUG_LOCK_ALLOC + /* +@@ -26,7 +26,7 @@ void __init_rwsem(struct rw_semaphore *s + INIT_LIST_HEAD(&sem->wait_list); + } + +-EXPORT_SYMBOL(__init_rwsem); ++EXPORT_SYMBOL(__compat_init_rwsem); + + struct rwsem_waiter { + struct list_head list; +Index: linux-2.6.24.7-rt27/lib/semaphore-sleepers.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/semaphore-sleepers.c 2009-02-08 00:00:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/semaphore-sleepers.c 2009-02-08 00:02:01.000000000 -0500 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + + /* +@@ -48,12 +49,12 @@ + * we cannot lose wakeup events. + */ + +-fastcall void __up(struct semaphore *sem) ++fastcall void __compat_up(struct compat_semaphore *sem) + { + wake_up(&sem->wait); + } + +-fastcall void __sched __down(struct semaphore * sem) ++fastcall void __sched __compat_down(struct compat_semaphore * sem) + { + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); +@@ -90,7 +91,7 @@ fastcall void __sched __down(struct sema + tsk->state = TASK_RUNNING; + } + +-fastcall int __sched __down_interruptible(struct semaphore * sem) ++fastcall int __sched __compat_down_interruptible(struct compat_semaphore * sem) + { + int retval = 0; + struct task_struct *tsk = current; +@@ -153,7 +154,7 @@ fastcall int __sched __down_interruptibl + * single "cmpxchg" without failure cases, + * but then it wouldn't work on a 386. + */ +-fastcall int __down_trylock(struct semaphore * sem) ++fastcall int __compat_down_trylock(struct compat_semaphore * sem) + { + int sleepers; + unsigned long flags; +@@ -174,3 +175,10 @@ fastcall int __down_trylock(struct semap + spin_unlock_irqrestore(&sem->wait.lock, flags); + return 1; + } ++ ++int fastcall compat_sem_is_locked(struct compat_semaphore *sem) ++{ ++ return (int) atomic_read(&sem->count) < 0; ++} ++ ++EXPORT_SYMBOL(compat_sem_is_locked); +Index: linux-2.6.24.7-rt27/lib/spinlock_debug.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/spinlock_debug.c 2009-02-08 00:00:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/spinlock_debug.c 2009-02-08 00:02:01.000000000 -0500 +@@ -13,8 +13,8 @@ + #include + #include + +-void __spin_lock_init(spinlock_t *lock, const char *name, +- struct lock_class_key *key) ++void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name, ++ struct lock_class_key *key) + { + #ifdef CONFIG_DEBUG_LOCK_ALLOC + /* +@@ -23,16 +23,16 @@ void __spin_lock_init(spinlock_t *lock, + debug_check_no_locks_freed((void *)lock, sizeof(*lock)); + lockdep_init_map(&lock->dep_map, name, key, 0); + #endif +- lock->raw_lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; ++ lock->raw_lock = (__raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; + lock->magic = SPINLOCK_MAGIC; + lock->owner = SPINLOCK_OWNER_INIT; + lock->owner_cpu = -1; + } + +-EXPORT_SYMBOL(__spin_lock_init); ++EXPORT_SYMBOL(__raw_spin_lock_init); + +-void __rwlock_init(rwlock_t *lock, const char *name, +- struct lock_class_key *key) ++void __raw_rwlock_init(raw_rwlock_t *lock, const char *name, ++ struct lock_class_key *key) + { + #ifdef CONFIG_DEBUG_LOCK_ALLOC + /* +@@ -41,15 +41,15 @@ void __rwlock_init(rwlock_t *lock, const + debug_check_no_locks_freed((void *)lock, sizeof(*lock)); + lockdep_init_map(&lock->dep_map, name, key, 0); + #endif +- lock->raw_lock = (raw_rwlock_t) __RAW_RW_LOCK_UNLOCKED; ++ lock->raw_lock = (__raw_rwlock_t) __RAW_RW_LOCK_UNLOCKED; + lock->magic = RWLOCK_MAGIC; + lock->owner = SPINLOCK_OWNER_INIT; + lock->owner_cpu = -1; + } + +-EXPORT_SYMBOL(__rwlock_init); ++EXPORT_SYMBOL(__raw_rwlock_init); + +-static void spin_bug(spinlock_t *lock, const char *msg) ++static void spin_bug(raw_spinlock_t *lock, const char *msg) + { + struct task_struct *owner = NULL; + +@@ -73,7 +73,7 @@ static void spin_bug(spinlock_t *lock, c + #define SPIN_BUG_ON(cond, lock, msg) if (unlikely(cond)) spin_bug(lock, msg) + + static inline void +-debug_spin_lock_before(spinlock_t *lock) ++debug_spin_lock_before(raw_spinlock_t *lock) + { + SPIN_BUG_ON(lock->magic != SPINLOCK_MAGIC, lock, "bad magic"); + SPIN_BUG_ON(lock->owner == current, lock, "recursion"); +@@ -81,13 +81,13 @@ debug_spin_lock_before(spinlock_t *lock) + lock, "cpu recursion"); + } + +-static inline void debug_spin_lock_after(spinlock_t *lock) ++static inline void debug_spin_lock_after(raw_spinlock_t *lock) + { + lock->owner_cpu = raw_smp_processor_id(); + lock->owner = current; + } + +-static inline void debug_spin_unlock(spinlock_t *lock) ++static inline void debug_spin_unlock(raw_spinlock_t *lock) + { + SPIN_BUG_ON(lock->magic != SPINLOCK_MAGIC, lock, "bad magic"); + SPIN_BUG_ON(!spin_is_locked(lock), lock, "already unlocked"); +@@ -98,7 +98,7 @@ static inline void debug_spin_unlock(spi + lock->owner_cpu = -1; + } + +-static void __spin_lock_debug(spinlock_t *lock) ++static void __spin_lock_debug(raw_spinlock_t *lock) + { + u64 i; + u64 loops = loops_per_jiffy * HZ; +@@ -125,7 +125,7 @@ static void __spin_lock_debug(spinlock_t + } + } + +-void _raw_spin_lock(spinlock_t *lock) ++void __lockfunc _raw_spin_lock(raw_spinlock_t *lock) + { + debug_spin_lock_before(lock); + if (unlikely(!__raw_spin_trylock(&lock->raw_lock))) +@@ -133,7 +133,7 @@ void _raw_spin_lock(spinlock_t *lock) + debug_spin_lock_after(lock); + } + +-int _raw_spin_trylock(spinlock_t *lock) ++int __lockfunc _raw_spin_trylock(raw_spinlock_t *lock) + { + int ret = __raw_spin_trylock(&lock->raw_lock); + +@@ -148,13 +148,13 @@ int _raw_spin_trylock(spinlock_t *lock) + return ret; + } + +-void _raw_spin_unlock(spinlock_t *lock) ++void __lockfunc _raw_spin_unlock(raw_spinlock_t *lock) + { + debug_spin_unlock(lock); + __raw_spin_unlock(&lock->raw_lock); + } + +-static void rwlock_bug(rwlock_t *lock, const char *msg) ++static void rwlock_bug(raw_rwlock_t *lock, const char *msg) + { + if (!debug_locks_off()) + return; +@@ -167,8 +167,8 @@ static void rwlock_bug(rwlock_t *lock, c + + #define RWLOCK_BUG_ON(cond, lock, msg) if (unlikely(cond)) rwlock_bug(lock, msg) + +-#if 0 /* __write_lock_debug() can lock up - maybe this can too? */ +-static void __read_lock_debug(rwlock_t *lock) ++#if 1 /* __write_lock_debug() can lock up - maybe this can too? */ ++static void __raw_read_lock_debug(raw_rwlock_t *lock) + { + u64 i; + u64 loops = loops_per_jiffy * HZ; +@@ -193,13 +193,13 @@ static void __read_lock_debug(rwlock_t * + } + #endif + +-void _raw_read_lock(rwlock_t *lock) ++void __lockfunc _raw_read_lock(raw_rwlock_t *lock) + { + RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); +- __raw_read_lock(&lock->raw_lock); ++ __raw_read_lock_debug(lock); + } + +-int _raw_read_trylock(rwlock_t *lock) ++int __lockfunc _raw_read_trylock(raw_rwlock_t *lock) + { + int ret = __raw_read_trylock(&lock->raw_lock); + +@@ -212,13 +212,13 @@ int _raw_read_trylock(rwlock_t *lock) + return ret; + } + +-void _raw_read_unlock(rwlock_t *lock) ++void __lockfunc _raw_read_unlock(raw_rwlock_t *lock) + { + RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); + __raw_read_unlock(&lock->raw_lock); + } + +-static inline void debug_write_lock_before(rwlock_t *lock) ++static inline void debug_write_lock_before(raw_rwlock_t *lock) + { + RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); + RWLOCK_BUG_ON(lock->owner == current, lock, "recursion"); +@@ -226,13 +226,13 @@ static inline void debug_write_lock_befo + lock, "cpu recursion"); + } + +-static inline void debug_write_lock_after(rwlock_t *lock) ++static inline void debug_write_lock_after(raw_rwlock_t *lock) + { + lock->owner_cpu = raw_smp_processor_id(); + lock->owner = current; + } + +-static inline void debug_write_unlock(rwlock_t *lock) ++static inline void debug_write_unlock(raw_rwlock_t *lock) + { + RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); + RWLOCK_BUG_ON(lock->owner != current, lock, "wrong owner"); +@@ -242,8 +242,8 @@ static inline void debug_write_unlock(rw + lock->owner_cpu = -1; + } + +-#if 0 /* This can cause lockups */ +-static void __write_lock_debug(rwlock_t *lock) ++#if 1 /* This can cause lockups */ ++static void __raw_write_lock_debug(raw_rwlock_t *lock) + { + u64 i; + u64 loops = loops_per_jiffy * HZ; +@@ -268,14 +268,14 @@ static void __write_lock_debug(rwlock_t + } + #endif + +-void _raw_write_lock(rwlock_t *lock) ++void __lockfunc _raw_write_lock(raw_rwlock_t *lock) + { + debug_write_lock_before(lock); +- __raw_write_lock(&lock->raw_lock); ++ __raw_write_lock_debug(lock); + debug_write_lock_after(lock); + } + +-int _raw_write_trylock(rwlock_t *lock) ++int __lockfunc _raw_write_trylock(raw_rwlock_t *lock) + { + int ret = __raw_write_trylock(&lock->raw_lock); + +@@ -290,7 +290,7 @@ int _raw_write_trylock(rwlock_t *lock) + return ret; + } + +-void _raw_write_unlock(rwlock_t *lock) ++void __lockfunc _raw_write_unlock(raw_rwlock_t *lock) + { + debug_write_unlock(lock); + __raw_write_unlock(&lock->raw_lock); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0501-rwlock-slowunlock-mutex-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0501-rwlock-slowunlock-mutex-fix.patch @@ -0,0 +1,32 @@ +From: Steven Rostedt +Subject: rwlock: reset mutex on multilpe readers in unlock + +Reset the rwlock mutex owner to readers if the lock is currently held +by other readers. + +Signed-off-by: Steven Rostedt +--- + kernel/rtmutex.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:49.000000000 -0500 +@@ -1795,6 +1795,16 @@ rt_read_slowunlock(struct rw_mutex *rwm, + + wakeup_next_waiter(mutex, savestate); + ++ /* ++ * If we woke up a reader but the lock is already held by readers ++ * we need to set the mutex owner to RT_RW_READER, since the ++ * wakeup_next_waiter set it to the pending reader. ++ */ ++ if (reader_count) { ++ WARN_ON(waiter->write_lock); ++ rt_mutex_set_owner(mutex, RT_RW_READER, 0); ++ } ++ + if (rt_mutex_has_waiters(mutex)) { + waiter = rt_mutex_top_waiter(mutex); + rwm->prio = waiter->task->prio; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0567-tglx-02-sched-remove-useless-nointeractive-state.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0567-tglx-02-sched-remove-useless-nointeractive-state.patch @@ -0,0 +1,28 @@ +From tglx@linutronix.de Fri Dec 19 16:40:02 2008 +Date: Fri, 19 Dec 2008 21:22:48 -0000 +From: Thomas Gleixner +To: LKML +Cc: Ingo Molnar , Steven Rostedt , Peter Zijlstra , Clark Williams , Gregory Haskins , Linux-rt +Subject: [patch 2/7] sched: remove useless nointeractive state + +gone task state reintroduced by rtmutex patches. + +Signed-off-by: Thomas Gleixner +--- + include/linux/sched.h | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/sched.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/sched.h 2009-02-08 00:05:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/sched.h 2009-02-08 00:05:21.000000000 -0500 +@@ -202,8 +202,7 @@ extern struct semaphore kernel_sem; + #define EXIT_ZOMBIE 32 + #define EXIT_DEAD 64 + /* in tsk->state again */ +-#define TASK_NONINTERACTIVE 128 +-#define TASK_DEAD 256 ++#define TASK_DEAD 128 + + #define __set_task_state(tsk, state_value) \ + do { (tsk)->state = (state_value); } while (0) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0145-preempt-irqs-i386-ioapic-mask-quirk.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0145-preempt-irqs-i386-ioapic-mask-quirk.patch @@ -0,0 +1,178 @@ +From mschmidt@redhat.com Thu Jun 21 13:32:02 2007 +Return-Path: +Received: from mx1.redhat.com (mx1.redhat.com [66.187.233.31]) by + mail.tglx.de (Postfix) with ESMTP id CA11565C065 for ; + Thu, 21 Jun 2007 13:32:02 +0200 (CEST) +Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com + [172.16.52.254]) by mx1.redhat.com (8.13.1/8.13.1) with ESMTP id + l5LBVoq3016914; Thu, 21 Jun 2007 07:31:50 -0400 +Received: from pobox.stuttgart.redhat.com (pobox.stuttgart.redhat.com + [172.16.2.10]) by int-mx1.corp.redhat.com (8.13.1/8.13.1) with ESMTP id + l5LBVmp0010104; Thu, 21 Jun 2007 07:31:49 -0400 +Received: from [10.34.32.84] (brian.englab.brq.redhat.com [10.34.32.84]) by + pobox.stuttgart.redhat.com (8.12.11.20060308/8.12.11) with ESMTP id + l5LBVl5k000423; Thu, 21 Jun 2007 13:31:47 +0200 +Message-ID: <467A61A3.7060804@redhat.com> +Date: Thu, 21 Jun 2007 13:31:47 +0200 +From: Michal Schmidt +User-Agent: Thunderbird 1.5.0.12 (X11/20070529) +MIME-Version: 1.0 +To: Steven Rostedt +CC: Ingo Molnar , Thomas Gleixner , linux-rt-users@vger.kernel.org, linux-kernel@vger.kernel.org +Subject: Re: [PATCH -rt] irq nobody cared workaround for i386 +References: <4676CF81.2000205@redhat.com> <4677D7AF.7040700@redhat.com> + <467932B4.6030800@redhat.com> <467936FE.8050704@redhat.com> +In-Reply-To: <467936FE.8050704@redhat.com> +X-Enigmail-Version: 0.94.2.0 +Content-Type: text/plain; charset=ISO-8859-1 +X-Evolution-Source: imap://tglx%40linutronix.de@localhost:8993/ +Content-Transfer-Encoding: 8bit + +Steven Rostedt wrote: +> Michal Schmidt wrote: +> +>> I came to the conclusion that the IO-APICs which need the fix for the +>> nobody cared bug don't have the issue ack_ioapic_quirk_irq is designed +>> to work-around. It should be safe simply to use the normal +>> ack_ioapic_irq as the .eoi method in pcix_ioapic_chip. +>> So this is the port of Steven's fix for the nobody cared bug to i386. It +>> works fine on IBM LS21 I have access to. +>> +>> +> You want to make that "apic > 0". Note the spacing. If it breaks +> 80 characters, then simply put it to a new line. +> +> [...] +> ACK +> +> -- Steve +> + +OK, I fixed the spacing in both occurences. + +Signed-off-by: Michal Schmidt + +--- + arch/x86/kernel/io_apic_32.c | 62 ++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 55 insertions(+), 7 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/io_apic_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/io_apic_32.c 2009-02-08 00:01:51.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/io_apic_32.c 2009-02-08 00:01:52.000000000 -0500 +@@ -261,6 +261,18 @@ static void __unmask_IO_APIC_irq (unsign + __modify_IO_APIC_irq(irq, 0, 0x00010000); + } + ++/* trigger = 0 (edge mode) */ ++static void __pcix_mask_IO_APIC_irq (unsigned int irq) ++{ ++ __modify_IO_APIC_irq(irq, 0, 0x00008000); ++} ++ ++/* mask = 0, trigger = 1 (level mode) */ ++static void __pcix_unmask_IO_APIC_irq (unsigned int irq) ++{ ++ __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000); ++} ++ + static void mask_IO_APIC_irq (unsigned int irq) + { + unsigned long flags; +@@ -279,6 +291,24 @@ static void unmask_IO_APIC_irq (unsigned + spin_unlock_irqrestore(&ioapic_lock, flags); + } + ++static void pcix_mask_IO_APIC_irq (unsigned int irq) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __pcix_mask_IO_APIC_irq(irq); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ ++static void pcix_unmask_IO_APIC_irq (unsigned int irq) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __pcix_unmask_IO_APIC_irq(irq); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ + static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) + { + struct IO_APIC_route_entry entry; +@@ -1224,23 +1254,28 @@ static int assign_irq_vector(int irq) + + return vector; + } ++ + static struct irq_chip ioapic_chip; ++static struct irq_chip pcix_ioapic_chip; + + #define IOAPIC_AUTO -1 + #define IOAPIC_EDGE 0 + #define IOAPIC_LEVEL 1 + +-static void ioapic_register_intr(int irq, int vector, unsigned long trigger) ++static void ioapic_register_intr(int irq, int vector, unsigned long trigger, ++ int pcix) + { ++ struct irq_chip *chip = pcix ? &pcix_ioapic_chip : &ioapic_chip; ++ + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || + trigger == IOAPIC_LEVEL) { + irq_desc[irq].status |= IRQ_LEVEL; +- set_irq_chip_and_handler_name(irq, &ioapic_chip, +- handle_fasteoi_irq, "fasteoi"); ++ set_irq_chip_and_handler_name(irq, chip, handle_fasteoi_irq, ++ pcix ? "pcix-fasteoi" : "fasteoi"); + } else { + irq_desc[irq].status &= ~IRQ_LEVEL; +- set_irq_chip_and_handler_name(irq, &ioapic_chip, +- handle_edge_irq, "edge"); ++ set_irq_chip_and_handler_name(irq, chip, handle_edge_irq, ++ pcix ? "pcix-edge" : "edge"); + } + set_intr_gate(vector, interrupt[irq]); + } +@@ -1310,7 +1345,8 @@ static void __init setup_IO_APIC_irqs(vo + if (IO_APIC_IRQ(irq)) { + vector = assign_irq_vector(irq); + entry.vector = vector; +- ioapic_register_intr(irq, vector, IOAPIC_AUTO); ++ ioapic_register_intr(irq, vector, IOAPIC_AUTO, ++ apic > 0); + + if (!apic && (irq < 16)) + disable_8259A_irq(irq); +@@ -2005,6 +2041,18 @@ static struct irq_chip ioapic_chip __rea + .retrigger = ioapic_retrigger_irq, + }; + ++static struct irq_chip pcix_ioapic_chip __read_mostly = { ++ .name = "IO-APIC", ++ .startup = startup_ioapic_irq, ++ .mask = pcix_mask_IO_APIC_irq, ++ .unmask = pcix_unmask_IO_APIC_irq, ++ .ack = ack_ioapic_irq, ++ .eoi = ack_ioapic_irq, ++#ifdef CONFIG_SMP ++ .set_affinity = set_ioapic_affinity_irq, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; + + static inline void init_IO_APIC_traps(void) + { +@@ -2817,7 +2865,7 @@ int io_apic_set_pci_routing (int ioapic, + mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, + edge_level, active_high_low); + +- ioapic_register_intr(irq, entry.vector, edge_level); ++ ioapic_register_intr(irq, entry.vector, edge_level, ioapic > 0); + + if (!ioapic && (irq < 16)) + disable_8259A_irq(irq); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0060-ftrace-safe-traversal-hlist.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0060-ftrace-safe-traversal-hlist.patch @@ -0,0 +1,41 @@ +From sagar.abhishek@gmail.com Tue May 27 11:53:35 2008 +Date: Sat, 24 May 2008 23:45:02 +0530 +From: Abhishek Sagar +To: rostedt@goodmis.org +Cc: Ingo Molnar , LKML +Subject: [PATCH] ftrace: safe traversal of ftrace_hash hlist + +Hi Steven, + +I noticed that concurrent instances of ftrace_record_ip() have a race between ftrace_hash list traversal during ftrace_ip_in_hash() (before acquiring ftrace_shutdown_lock) and ftrace_add_hash().If it's so then this should fix it. + +Signed-off-by: Abhishek Sagar +--- +Accommodate traversal of ftrace_hash hlist with concurrent insertions. + +--- + kernel/trace/ftrace.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/trace/ftrace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/ftrace.c 2009-02-08 00:01:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/ftrace.c 2009-02-08 00:01:12.000000000 -0500 +@@ -200,7 +200,7 @@ ftrace_ip_in_hash(unsigned long ip, unsi + struct hlist_node *t; + int found = 0; + +- hlist_for_each_entry(p, t, &ftrace_hash[key], node) { ++ hlist_for_each_entry_rcu(p, t, &ftrace_hash[key], node) { + if (p->ip == ip) { + found = 1; + break; +@@ -213,7 +213,7 @@ ftrace_ip_in_hash(unsigned long ip, unsi + static inline void + ftrace_add_hash(struct dyn_ftrace *node, unsigned long key) + { +- hlist_add_head(&node->node, &ftrace_hash[key]); ++ hlist_add_head_rcu(&node->node, &ftrace_hash[key]); + } + + static void ftrace_free_rec(struct dyn_ftrace *rec) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0208-preempt-realtime-arm-bagde4.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0208-preempt-realtime-arm-bagde4.patch @@ -0,0 +1,33 @@ +--- + arch/arm/mach-sa1100/badge4.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/arm/mach-sa1100/badge4.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mach-sa1100/badge4.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mach-sa1100/badge4.c 2009-02-08 00:02:20.000000000 -0500 +@@ -240,15 +240,22 @@ void badge4_set_5V(unsigned subsystem, i + /* detect on->off and off->on transitions */ + if ((!old_5V_bitmap) && (badge4_5V_bitmap)) { + /* was off, now on */ +- printk(KERN_INFO "%s: enabling 5V supply rail\n", __FUNCTION__); + GPSR = BADGE4_GPIO_PCMEN5V; + } else if ((old_5V_bitmap) && (!badge4_5V_bitmap)) { + /* was on, now off */ +- printk(KERN_INFO "%s: disabling 5V supply rail\n", __FUNCTION__); + GPCR = BADGE4_GPIO_PCMEN5V; + } + + local_irq_restore(flags); ++ ++ /* detect on->off and off->on transitions */ ++ if ((!old_5V_bitmap) && (badge4_5V_bitmap)) { ++ /* was off, now on */ ++ printk(KERN_INFO "%s: enabling 5V supply rail\n", __FUNCTION__); ++ } else if ((old_5V_bitmap) && (!badge4_5V_bitmap)) { ++ /* was on, now off */ ++ printk(KERN_INFO "%s: disabling 5V supply rail\n", __FUNCTION__); ++ } + } + EXPORT_SYMBOL(badge4_set_5V); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0184-percpu-locked-netfilter2.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0184-percpu-locked-netfilter2.patch @@ -0,0 +1,118 @@ +--- + include/net/netfilter/nf_conntrack.h | 2 +- + include/net/netfilter/nf_conntrack_ecache.h | 13 +++++++------ + net/netfilter/nf_conntrack_ecache.c | 16 ++++++++-------- + 3 files changed, 16 insertions(+), 15 deletions(-) + +Index: linux-2.6.24.7-rt27/include/net/netfilter/nf_conntrack.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/net/netfilter/nf_conntrack.h 2009-02-08 00:01:32.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/net/netfilter/nf_conntrack.h 2009-02-08 00:02:10.000000000 -0500 +@@ -259,13 +259,13 @@ extern atomic_t nf_conntrack_count; + extern int nf_conntrack_max; + + DECLARE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat); +-#define NF_CT_STAT_INC(count) (__get_cpu_var(nf_conntrack_stat).count++) + #define NF_CT_STAT_INC_ATOMIC(count) \ + do { \ + local_bh_disable(); \ + __get_cpu_var(nf_conntrack_stat).count++; \ + local_bh_enable(); \ + } while (0) ++#define NF_CT_STAT_INC(count) (__raw_get_cpu_var(nf_conntrack_stat).count++) + + extern int + nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size); +Index: linux-2.6.24.7-rt27/include/net/netfilter/nf_conntrack_ecache.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/net/netfilter/nf_conntrack_ecache.h 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/net/netfilter/nf_conntrack_ecache.h 2009-02-08 00:02:10.000000000 -0500 +@@ -15,16 +15,15 @@ struct nf_conntrack_ecache { + struct nf_conn *ct; + unsigned int events; + }; +-DECLARE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache); +- +-#define CONNTRACK_ECACHE(x) (__get_cpu_var(nf_conntrack_ecache).x) ++DECLARE_PER_CPU_LOCKED(struct nf_conntrack_ecache, nf_conntrack_ecache); + + extern struct atomic_notifier_head nf_conntrack_chain; + extern int nf_conntrack_register_notifier(struct notifier_block *nb); + extern int nf_conntrack_unregister_notifier(struct notifier_block *nb); + + extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); +-extern void __nf_ct_event_cache_init(struct nf_conn *ct); ++extern void __nf_ct_event_cache_init(struct nf_conntrack_ecache *ecache, ++ struct nf_conn *ct); + extern void nf_ct_event_cache_flush(void); + + static inline void +@@ -33,12 +32,14 @@ nf_conntrack_event_cache(enum ip_conntra + { + struct nf_conn *ct = (struct nf_conn *)skb->nfct; + struct nf_conntrack_ecache *ecache; ++ int cpu; + + local_bh_disable(); +- ecache = &__get_cpu_var(nf_conntrack_ecache); ++ ecache = &get_cpu_var_locked(nf_conntrack_ecache, &cpu); + if (ct != ecache->ct) +- __nf_ct_event_cache_init(ct); ++ __nf_ct_event_cache_init(ecache, ct); + ecache->events |= event; ++ put_cpu_var_locked(nf_conntrack_ecache, cpu); + local_bh_enable(); + } + +Index: linux-2.6.24.7-rt27/net/netfilter/nf_conntrack_ecache.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/net/netfilter/nf_conntrack_ecache.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/net/netfilter/nf_conntrack_ecache.c 2009-02-08 00:02:10.000000000 -0500 +@@ -29,8 +29,8 @@ EXPORT_SYMBOL_GPL(nf_conntrack_chain); + ATOMIC_NOTIFIER_HEAD(nf_ct_expect_chain); + EXPORT_SYMBOL_GPL(nf_ct_expect_chain); + +-DEFINE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache); +-EXPORT_PER_CPU_SYMBOL_GPL(nf_conntrack_ecache); ++DEFINE_PER_CPU_LOCKED(struct nf_conntrack_ecache, nf_conntrack_ecache); ++EXPORT_PER_CPU_LOCKED_SYMBOL_GPL(nf_conntrack_ecache); + + /* deliver cached events and clear cache entry - must be called with locally + * disabled softirqs */ +@@ -52,22 +52,22 @@ __nf_ct_deliver_cached_events(struct nf_ + void nf_ct_deliver_cached_events(const struct nf_conn *ct) + { + struct nf_conntrack_ecache *ecache; ++ int cpu; + + local_bh_disable(); +- ecache = &__get_cpu_var(nf_conntrack_ecache); ++ ecache = &get_cpu_var_locked(nf_conntrack_ecache, &cpu); + if (ecache->ct == ct) + __nf_ct_deliver_cached_events(ecache); ++ put_cpu_var_locked(nf_conntrack_ecache, cpu); + local_bh_enable(); + } + EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); + + /* Deliver cached events for old pending events, if current conntrack != old */ +-void __nf_ct_event_cache_init(struct nf_conn *ct) ++void ++__nf_ct_event_cache_init(struct nf_conntrack_ecache *ecache, struct nf_conn *ct) + { +- struct nf_conntrack_ecache *ecache; +- + /* take care of delivering potentially old events */ +- ecache = &__get_cpu_var(nf_conntrack_ecache); + BUG_ON(ecache->ct == ct); + if (ecache->ct) + __nf_ct_deliver_cached_events(ecache); +@@ -85,7 +85,7 @@ void nf_ct_event_cache_flush(void) + int cpu; + + for_each_possible_cpu(cpu) { +- ecache = &per_cpu(nf_conntrack_ecache, cpu); ++ ecache = &__get_cpu_var_locked(nf_conntrack_ecache, cpu); + if (ecache->ct) + nf_ct_put(ecache->ct); + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0039-0026-sched-remove-leftover-debugging.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0039-0026-sched-remove-leftover-debugging.patch @@ -0,0 +1,53 @@ +From ef0ff6d04e7609127b8227f8c0b5be2977aae986 Mon Sep 17 00:00:00 2001 +From: Ingo Molnar +Date: Tue, 11 Dec 2007 10:02:39 +0100 +Subject: [PATCH] sched: remove leftover debugging + +remove leftover debugging. + +Signed-off-by: Ingo Molnar + +--- + kernel/sched_rt.c | 8 -------- + 1 file changed, 8 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:01:02.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:01:02.000000000 -0500 +@@ -249,8 +249,6 @@ static struct task_struct *pick_next_hig + struct list_head *queue; + int idx; + +- assert_spin_locked(&rq->lock); +- + if (likely(rq->rt.rt_nr_running < 2)) + return NULL; + +@@ -496,8 +494,6 @@ static int push_rt_task(struct rq *rq) + int ret = 0; + int paranoid = RT_MAX_TRIES; + +- assert_spin_locked(&rq->lock); +- + if (!rq->rt.overloaded) + return 0; + +@@ -542,8 +538,6 @@ static int push_rt_task(struct rq *rq) + goto out; + } + +- assert_spin_locked(&lowest_rq->lock); +- + deactivate_task(rq, next_task, 0); + set_task_cpu(next_task, lowest_rq->cpu); + activate_task(lowest_rq, next_task, 0); +@@ -585,8 +579,6 @@ static int pull_rt_task(struct rq *this_ + int cpu; + int ret = 0; + +- assert_spin_locked(&this_rq->lock); +- + /* + * If cpusets are used, and we have overlapping + * run queue cpusets, then this algorithm may not catch all. --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0561-ftrace-fix-preempt-trace-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0561-ftrace-fix-preempt-trace-fix.patch @@ -0,0 +1,24 @@ +From: Steven Rostedt +Subject: ftrace: fix the preempt-disable start fix + +Signed-off-by: Steven Rostedt +--- + kernel/trace/trace_irqsoff.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/trace/trace_irqsoff.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace_irqsoff.c 2009-02-08 00:04:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace_irqsoff.c 2009-02-08 00:05:19.000000000 -0500 +@@ -364,9 +364,9 @@ void trace_preempt_on(unsigned long a0, + + void trace_preempt_off(unsigned long a0, unsigned long a1) + { +- start_critical_timing(a0, a1); ++ tracing_hist_preempt_start(); + if (preempt_trace()) +- tracing_hist_preempt_start(); ++ start_critical_timing(a0, a1); + } + #endif /* CONFIG_PREEMPT_TRACER */ + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0402-dev-queue-xmit-preempt-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0402-dev-queue-xmit-preempt-fix.patch @@ -0,0 +1,155 @@ +From mingo@elte.hu Fri Jan 11 14:56:57 2008 +Date: Thu, 3 Jan 2008 09:22:03 +0100 +From: Ingo Molnar +To: Steven Rostedt +Subject: [mbeauch@cox.net: FW: [PATCH -rt] Preemption problem in kernel RT + Patch] + + +----- Forwarded message from mbeauch ----- + +Date: Wed, 02 Jan 2008 20:27:09 -0500 +From: mbeauch +To: mingo@elte.hu +Subject: FW: [PATCH -rt] Preemption problem in kernel RT Patch + +Here's the updated patch: + +Changed the real-time patch code to detect recursive calls +to dev_queue_xmit and drop the packet when detected. + + +Signed-off-by: Mark Beauchemin + + +--- + include/linux/netdevice.h | 20 ++++++++++---------- + net/core/dev.c | 14 +++----------- + net/sched/sch_generic.c | 4 ++-- + 3 files changed, 15 insertions(+), 23 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/netdevice.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/netdevice.h 2009-02-08 00:02:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/netdevice.h 2009-02-08 00:04:00.000000000 -0500 +@@ -629,7 +629,7 @@ struct net_device + /* cpu id of processor entered to hard_start_xmit or -1, + if nobody entered there. + */ +- int xmit_lock_owner; ++ void *xmit_lock_owner; + void *priv; /* pointer to private data */ + int (*hard_start_xmit) (struct sk_buff *skb, + struct net_device *dev); +@@ -1341,46 +1341,46 @@ static inline void netif_rx_complete(str + * + * Get network device transmit lock + */ +-static inline void __netif_tx_lock(struct net_device *dev, int cpu) ++static inline void __netif_tx_lock(struct net_device *dev) + { + spin_lock(&dev->_xmit_lock); +- dev->xmit_lock_owner = cpu; ++ dev->xmit_lock_owner = (void *)current; + } + + static inline void netif_tx_lock(struct net_device *dev) + { +- __netif_tx_lock(dev, raw_smp_processor_id()); ++ __netif_tx_lock(dev); + } + + static inline void netif_tx_lock_bh(struct net_device *dev) + { + spin_lock_bh(&dev->_xmit_lock); +- dev->xmit_lock_owner = raw_smp_processor_id(); ++ dev->xmit_lock_owner = (void *)current; + } + + static inline int netif_tx_trylock(struct net_device *dev) + { + int ok = spin_trylock(&dev->_xmit_lock); + if (likely(ok)) +- dev->xmit_lock_owner = raw_smp_processor_id(); ++ dev->xmit_lock_owner = (void *)current; + return ok; + } + + static inline void netif_tx_unlock(struct net_device *dev) + { +- dev->xmit_lock_owner = -1; ++ dev->xmit_lock_owner = (void *)-1; + spin_unlock(&dev->_xmit_lock); + } + + static inline void netif_tx_unlock_bh(struct net_device *dev) + { +- dev->xmit_lock_owner = -1; ++ dev->xmit_lock_owner = (void *)-1; + spin_unlock_bh(&dev->_xmit_lock); + } + +-#define HARD_TX_LOCK(dev, cpu) { \ ++#define HARD_TX_LOCK(dev) { \ + if ((dev->features & NETIF_F_LLTX) == 0) { \ +- __netif_tx_lock(dev, cpu); \ ++ __netif_tx_lock(dev); \ + } \ + } + +Index: linux-2.6.24.7-rt27/net/core/dev.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/net/core/dev.c 2009-02-08 00:02:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/net/core/dev.c 2009-02-08 00:04:00.000000000 -0500 +@@ -1692,18 +1692,10 @@ gso: + Either shot noqueue qdisc, it is even simpler 8) + */ + if (dev->flags & IFF_UP) { +- int cpu = raw_smp_processor_id(); /* ok because BHs are off */ + +- /* +- * No need to check for recursion with threaded interrupts: +- */ +-#ifdef CONFIG_PREEMPT_RT +- if (1) { +-#else +- if (dev->xmit_lock_owner != cpu) { +-#endif ++ if (dev->xmit_lock_owner != (void *)current) { + +- HARD_TX_LOCK(dev, cpu); ++ HARD_TX_LOCK(dev); + + if (!netif_queue_stopped(dev) && + !netif_subqueue_stopped(dev, skb)) { +@@ -3634,7 +3626,7 @@ int register_netdevice(struct net_device + spin_lock_init(&dev->queue_lock); + spin_lock_init(&dev->_xmit_lock); + netdev_set_lockdep_class(&dev->_xmit_lock, dev->type); +- dev->xmit_lock_owner = -1; ++ dev->xmit_lock_owner = (void *)-1; + spin_lock_init(&dev->ingress_lock); + + dev->iflink = -1; +Index: linux-2.6.24.7-rt27/net/sched/sch_generic.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/net/sched/sch_generic.c 2009-02-08 00:02:52.000000000 -0500 ++++ linux-2.6.24.7-rt27/net/sched/sch_generic.c 2009-02-08 00:04:00.000000000 -0500 +@@ -89,7 +89,7 @@ static inline int handle_dev_cpu_collisi + { + int ret; + +- if (unlikely(dev->xmit_lock_owner == raw_smp_processor_id())) { ++ if (unlikely(dev->xmit_lock_owner == (void *)current)) { + /* + * Same CPU holding the lock. It may be a transient + * configuration error, when hard_start_xmit() recurses. We +@@ -146,7 +146,7 @@ static inline int qdisc_restart(struct n + /* And release queue */ + spin_unlock(&dev->queue_lock); + +- HARD_TX_LOCK(dev, raw_smp_processor_id()); ++ HARD_TX_LOCK(dev); + if (!netif_subqueue_stopped(dev, skb)) + ret = dev_hard_start_xmit(skb, dev); + HARD_TX_UNLOCK(dev); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0134-arm-preempt-config.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0134-arm-preempt-config.patch @@ -0,0 +1,27 @@ + arch/arm/Kconfig | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/arm/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/Kconfig 2009-02-08 00:01:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/Kconfig 2009-02-08 00:01:45.000000000 -0500 +@@ -622,18 +622,7 @@ config LOCAL_TIMERS + accounting to be spread across the timer interval, preventing a + "thundering herd" at every timer tick. + +-config PREEMPT +- bool "Preemptible Kernel (EXPERIMENTAL)" +- depends on EXPERIMENTAL +- help +- This option reduces the latency of the kernel when reacting to +- real-time or interactive events by allowing a low priority process to +- be preempted even if it is in kernel mode executing a system call. +- This allows applications to run more reliably even when the system is +- under load. +- +- Say Y here if you are building a kernel for a desktop, embedded +- or real-time system. Say N if you are unsure. ++source kernel/Kconfig.preempt + + config NO_IDLE_HZ + bool "Dynamic tick timer" --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0512-cpu-hotplug-cpu-up-vs-preempt-rt.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0512-cpu-hotplug-cpu-up-vs-preempt-rt.patch @@ -0,0 +1,189 @@ +Subject: cpu-hotplug: cpu_up vs preempt-rt +From: Peter Zijlstra +Date: Tue, 10 Jun 2008 13:13:02 +0200 + +On PREEMPT_RT the allocators use preemptible locks, cpu bootstrap must have IRQs +disabled because there are no IRQ/exception stacks yet, these we allocate +atomically, which is not possible on -rt. + +Solve this by allocating these stacks on the boot cpu (which already has its +stacks). + +This also allows cpu-up to fail instead of panic on OOM scenarios. + +I suspect it also fixes a memory leak, as I cannot find the place where +cpu_down frees these cpu stacks, but each cpu_up used to allocate new ones. + +Signed-off-by: Peter Zijlstra +Cc: Steven Rostedt +Cc: Clark Williams +Cc: Gregory Haskins +Cc: "Paul E. McKenney" +Cc: Gautham R Shenoy +Cc: Pekka Enberg +Cc: Arnaldo Carvalho de Melo +Cc: Peter Zijlstra +Signed-off-by: Thomas Gleixner +--- + arch/x86/kernel/setup64.c | 31 ++-------------------- + arch/x86/kernel/smpboot_64.c | 57 +++++++++++++++++++++++++++++++++++++++++ + include/asm-x86/processor_64.h | 4 ++ + 3 files changed, 65 insertions(+), 27 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/setup64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/setup64.c 2009-02-08 00:03:44.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/setup64.c 2009-02-08 00:04:54.000000000 -0500 +@@ -137,19 +137,12 @@ void pda_init(int cpu) + pda->pcurrent = &init_task; + pda->irqstackptr = boot_cpu_stack; + } else { +- pda->irqstackptr = (char *) +- __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER); +- if (!pda->irqstackptr) +- panic("cannot allocate irqstack for cpu %d", cpu); ++ pda->irqstackptr = (char *)per_cpu(init_tss, cpu).irqstack; + } + +- + pda->irqstackptr += IRQSTACKSIZE-64; + } + +-char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ] +-__attribute__((section(".bss.page_aligned"))); +- + extern asmlinkage void ignore_sysret(void); + + /* May not be marked __init: used by software suspend */ +@@ -203,15 +196,13 @@ void __cpuinit cpu_init (void) + struct tss_struct *t = &per_cpu(init_tss, cpu); + struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu); + unsigned long v; +- char *estacks = NULL; + struct task_struct *me; + int i; + + /* CPU 0 is initialised in head64.c */ + if (cpu != 0) { + pda_init(cpu); +- } else +- estacks = boot_exception_stacks; ++ } + + me = current; + +@@ -245,22 +236,8 @@ void __cpuinit cpu_init (void) + /* + * set up and load the per-CPU TSS + */ +- for (v = 0; v < N_EXCEPTION_STACKS; v++) { +- static const unsigned int order[N_EXCEPTION_STACKS] = { +- [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, +-#if DEBUG_STACK > 0 +- [DEBUG_STACK - 1] = DEBUG_STACK_ORDER +-#endif +- }; +- if (cpu) { +- estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]); +- if (!estacks) +- panic("Cannot allocate exception stack %ld %d\n", +- v, cpu); +- } +- estacks += PAGE_SIZE << order[v]; +- orig_ist->ist[v] = t->ist[v] = (unsigned long)estacks; +- } ++ for (v = 0; v < N_EXCEPTION_STACKS; v++) ++ orig_ist->ist[v] = t->ist[v] = (unsigned long)t->estacks[v]; + + t->io_bitmap_base = offsetof(struct tss_struct, io_bitmap); + /* +Index: linux-2.6.24.7-rt27/arch/x86/kernel/smpboot_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/smpboot_64.c 2009-02-08 00:02:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/smpboot_64.c 2009-02-08 00:04:54.000000000 -0500 +@@ -535,6 +535,60 @@ static void __cpuinit do_fork_idle(struc + complete(&c_idle->done); + } + ++static char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ] ++__attribute__((section(".bss.page_aligned"))); ++ ++static int __cpuinit allocate_stacks(int cpu) ++{ ++ static const unsigned int order[N_EXCEPTION_STACKS] = { ++ [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, ++#if DEBUG_STACK > 0 ++ [DEBUG_STACK - 1] = DEBUG_STACK_ORDER ++#endif ++ }; ++ struct tss_struct *t = &per_cpu(init_tss, cpu); ++ int node = cpu_to_node(cpu); ++ struct page *page; ++ char *estack; ++ int v; ++ ++ if (cpu && !t->irqstack) { ++ page = alloc_pages_node(node, GFP_KERNEL, ++ IRQSTACK_ORDER); ++ if (!page) ++ goto fail_oom; ++ t->irqstack = page_address(page); ++ } ++ ++ if (!cpu) ++ estack = boot_exception_stacks; ++ ++ for (v = 0; v < N_EXCEPTION_STACKS; v++) { ++ if (t->estacks[v]) ++ continue; ++ ++ if (cpu) { ++ page = alloc_pages_node(node, GFP_KERNEL, order[v]); ++ if (!page) ++ goto fail_oom; ++ estack = page_address(page); ++ } ++ estack += PAGE_SIZE << order[v]; ++ /* ++ * XXX: can we set t->isr[v] here directly, or will that be ++ * modified later? - the existance of orig_ist seems to suggest ++ * it _can_ be modified, which would imply we'd need to reset ++ * it. ++ */ ++ t->estacks[v] = estack; ++ } ++ ++ return 0; ++ ++fail_oom: ++ return -ENOMEM; ++} ++ + /* + * Boot one CPU. + */ +@@ -605,6 +659,9 @@ static int __cpuinit do_boot_cpu(int cpu + return PTR_ERR(c_idle.idle); + } + ++ if (allocate_stacks(cpu)) ++ return -ENOMEM; ++ + set_idle_for_cpu(cpu, c_idle.idle); + + do_rest: +Index: linux-2.6.24.7-rt27/include/asm-x86/processor_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/processor_64.h 2009-02-07 23:59:36.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/processor_64.h 2009-02-08 00:04:54.000000000 -0500 +@@ -197,6 +197,10 @@ struct tss_struct { + * 8 bytes, for an extra "long" of ~0UL + */ + unsigned long io_bitmap[IO_BITMAP_LONGS + 1]; ++ ++ void *irqstack; ++ void *estacks[N_EXCEPTION_STACKS]; ++ + } __attribute__((packed)) ____cacheline_aligned; + + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0034-0020-sched-RT-balance-on-new-task.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0034-0020-sched-RT-balance-on-new-task.patch @@ -0,0 +1,25 @@ +From 05bf2130444fa78c75f46b47b39c39f0e337f647 Mon Sep 17 00:00:00 2001 +From: Steven Rostedt +Date: Tue, 11 Dec 2007 10:02:38 +0100 +Subject: [PATCH] sched: RT-balance on new task + +rt-balance when creating new tasks. + +Signed-off-by: Ingo Molnar + +--- + kernel/sched.c | 1 + + 1 file changed, 1 insertion(+) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:00:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:01:00.000000000 -0500 +@@ -1707,6 +1707,7 @@ void fastcall wake_up_new_task(struct ta + inc_nr_running(p, rq); + } + check_preempt_curr(rq, p); ++ wakeup_balance_rt(rq, p); + task_rq_unlock(rq, &flags); + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0502-rwlock-slowunlock-mutex-fix2.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0502-rwlock-slowunlock-mutex-fix2.patch @@ -0,0 +1,51 @@ +From: Steven Rostedt +Subject: rwlock: remove waiter from pi_list + +If the pending owner was a reader and we have multiple readers than +we need to remove it from the pi list. + +[ Thomas Gleixner added the grabing of the pi_locks to the removal ] + +Signed-off-by: Steven Rostedt +--- + kernel/rtmutex.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:49.000000000 -0500 +@@ -1685,6 +1685,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + { + struct rt_mutex *mutex = &rwm->mutex; + struct rt_mutex_waiter *waiter; ++ struct task_struct *pendowner; + struct reader_lock_struct *rls; + unsigned long flags; + unsigned int reader_count; +@@ -1793,6 +1794,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + rwm->owner = RT_RW_PENDING_READ; + } + ++ pendowner = waiter->task; + wakeup_next_waiter(mutex, savestate); + + /* +@@ -1808,6 +1810,17 @@ rt_read_slowunlock(struct rw_mutex *rwm, + if (rt_mutex_has_waiters(mutex)) { + waiter = rt_mutex_top_waiter(mutex); + rwm->prio = waiter->task->prio; ++ /* ++ * If readers still own this lock, then we need ++ * to update the pi_list too. Readers have a separate ++ * path in the PI chain. ++ */ ++ if (reader_count) { ++ spin_lock(&pendowner->pi_lock); ++ plist_del(&waiter->pi_list_entry, ++ &pendowner->pi_waiters); ++ spin_unlock(&pendowner->pi_lock); ++ } + } else + rwm->prio = MAX_PRIO; + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0002-futex-remove-warn-on.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0002-futex-remove-warn-on.patch @@ -0,0 +1,23 @@ +Subject: futex-unlock-rtmutex-on-fault.patch +From: Thomas Gleixner +Date: Sat, 21 Jun 2008 14:14:08 +0200 + +Signed-off-by: Thomas Gleixner +--- + kernel/futex.c | 3 --- + 1 file changed, 3 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/futex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/futex.c 2009-02-08 00:00:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/futex.c 2009-02-08 00:00:40.000000000 -0500 +@@ -1592,9 +1592,6 @@ static int futex_lock_pi(u32 __user *uad + res = fixup_pi_state_owner(uaddr, &q, owner, + fshared); + +- WARN_ON(rt_mutex_owner(&q.pi_state->pi_mutex) != +- owner); +- + /* propagate -EFAULT, if the fixup failed */ + if (res) + ret = res; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0262-preempt-realtime-warn-and-bug-on-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0262-preempt-realtime-warn-and-bug-on-fix.patch @@ -0,0 +1,30 @@ + + To fix the following compile error by enclosing it in ifndef __ASSEMBLY__/endif. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +include/asm-generic/bug.h +include/asm-generic/bug.h: Assembler messages: +include/asm-generic/bug.h:7: Error: Unrecognized opcode: `extern' +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +Signed-off-by: Tsutomu Owa +-- owa + +--- + include/asm-generic/bug.h | 2 ++ + 1 file changed, 2 insertions(+) + +Index: linux-2.6.24.7-rt27/include/asm-generic/bug.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-generic/bug.h 2009-02-08 00:02:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-generic/bug.h 2009-02-08 00:02:51.000000000 -0500 +@@ -3,7 +3,9 @@ + + #include + ++#ifndef __ASSEMBLY__ + extern void __WARN_ON(const char *func, const char *file, const int line); ++#endif /* __ASSEMBLY__ */ + + #ifdef CONFIG_BUG + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0354-dont-let-rt-rw_semaphores-do-non_owner-locks.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0354-dont-let-rt-rw_semaphores-do-non_owner-locks.patch @@ -0,0 +1,128 @@ +From rostedt@goodmis.org Wed Sep 26 11:12:47 2007 +Date: Tue, 25 Sep 2007 11:29:51 -0400 (EDT) +From: Steven Rostedt +To: Peter Zijlstra +Cc: LKML , + linux-rt-users , mingo@goodmis.org, + Thomas Gleixner +Subject: [PATCH RT] Don't let -rt rw_semaphors do _non_owner locks + + +-- +On Tue, 25 Sep 2007, Peter Zijlstra wrote: + +> How about teaching {up,down}_read_non_owner() to barf on rw_semaphore +> in -rt? +> + +Sure thing! + +This patch prevents rw_semaphore in PREEMPT_RT from performing +down_read_non_owner and up_read_non_owner. If this must be used, then +either convert to a completion or use compat_rw_semaphore. + +Signed-off-by: Steven Rostedt + +--- + include/linux/rt_lock.h | 15 +++++---------- + kernel/rt.c | 45 --------------------------------------------- + 2 files changed, 5 insertions(+), 55 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/rt_lock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rt_lock.h 2009-02-08 00:03:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rt_lock.h 2009-02-08 00:03:39.000000000 -0500 +@@ -241,25 +241,20 @@ do { \ + __rt_rwsem_init((sem), #sem, &__key); \ + } while (0) + ++extern void __dont_do_this_in_rt(struct rw_semaphore *rwsem); ++ ++#define rt_down_read_non_owner(rwsem) __dont_do_this_in_rt(rwsem) ++#define rt_up_read_non_owner(rwsem) __dont_do_this_in_rt(rwsem) ++ + extern void fastcall rt_down_write(struct rw_semaphore *rwsem); + extern void fastcall + rt_down_read_nested(struct rw_semaphore *rwsem, int subclass); + extern void fastcall + rt_down_write_nested(struct rw_semaphore *rwsem, int subclass); + extern void fastcall rt_down_read(struct rw_semaphore *rwsem); +-#ifdef CONFIG_DEBUG_LOCK_ALLOC +-extern void fastcall rt_down_read_non_owner(struct rw_semaphore *rwsem); +-#else +-# define rt_down_read_non_owner(rwsem) rt_down_read(rwsem) +-#endif + extern int fastcall rt_down_write_trylock(struct rw_semaphore *rwsem); + extern int fastcall rt_down_read_trylock(struct rw_semaphore *rwsem); + extern void fastcall rt_up_read(struct rw_semaphore *rwsem); +-#ifdef CONFIG_DEBUG_LOCK_ALLOC +-extern void fastcall rt_up_read_non_owner(struct rw_semaphore *rwsem); +-#else +-# define rt_up_read_non_owner(rwsem) rt_up_read(rwsem) +-#endif + extern void fastcall rt_up_write(struct rw_semaphore *rwsem); + extern void fastcall rt_downgrade_write(struct rw_semaphore *rwsem); + +Index: linux-2.6.24.7-rt27/kernel/rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rt.c 2009-02-08 00:03:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rt.c 2009-02-08 00:03:39.000000000 -0500 +@@ -324,25 +324,6 @@ void fastcall rt_up_read(struct rw_semap + } + EXPORT_SYMBOL(rt_up_read); + +-#ifdef CONFIG_DEBUG_LOCK_ALLOC +-void fastcall rt_up_read_non_owner(struct rw_semaphore *rwsem) +-{ +- unsigned long flags; +- /* +- * Read locks within the self-held write lock succeed. +- */ +- spin_lock_irqsave(&rwsem->lock.wait_lock, flags); +- if (rt_mutex_real_owner(&rwsem->lock) == current && rwsem->read_depth) { +- spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); +- rwsem->read_depth--; +- return; +- } +- spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); +- rt_mutex_unlock(&rwsem->lock); +-} +-EXPORT_SYMBOL(rt_up_read_non_owner); +-#endif +- + /* + * downgrade a write lock into a read lock + * - just wake up any readers at the front of the queue +@@ -433,32 +414,6 @@ void fastcall rt_down_read_nested(struct + } + EXPORT_SYMBOL(rt_down_read_nested); + +- +-#ifdef CONFIG_DEBUG_LOCK_ALLOC +- +-/* +- * Same as rt_down_read() but no lockdep calls: +- */ +-void fastcall rt_down_read_non_owner(struct rw_semaphore *rwsem) +-{ +- unsigned long flags; +- /* +- * Read locks within the write lock succeed. +- */ +- spin_lock_irqsave(&rwsem->lock.wait_lock, flags); +- +- if (rt_mutex_real_owner(&rwsem->lock) == current) { +- spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); +- rwsem->read_depth++; +- return; +- } +- spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); +- rt_mutex_lock(&rwsem->lock); +-} +-EXPORT_SYMBOL(rt_down_read_non_owner); +- +-#endif +- + void fastcall __rt_rwsem_init(struct rw_semaphore *rwsem, char *name, + struct lock_class_key *key) + { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0493-rwlock-torture.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0493-rwlock-torture.patch @@ -0,0 +1,834 @@ +From: Steven Rostedt +Subject: rwlock: rwlock torture test + +This patch adds an rwlock torture test that can be used to test rwlocks. +This may only be loaded as a module. Running this will severally bring +the system performance to an halt. + +Signed-off-by: Steven Rostedt +--- + kernel/Makefile | 1 + kernel/rwlock_torture.c | 781 ++++++++++++++++++++++++++++++++++++++++++++++++ + lib/Kconfig.debug | 11 + 3 files changed, 793 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/Makefile 2009-02-08 00:04:31.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/Makefile 2009-02-08 00:04:46.000000000 -0500 +@@ -68,6 +68,7 @@ obj-$(CONFIG_SYSFS) += ksysfs.o + obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o + obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ + obj-$(CONFIG_SECCOMP) += seccomp.o ++obj-$(CONFIG_RWLOCK_TORTURE_TEST) += rwlock_torture.o + obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o + obj-$(CONFIG_CLASSIC_RCU) += rcuclassic.o + obj-$(CONFIG_PREEMPT_RCU) += rcuclassic.o rcupreempt.o +Index: linux-2.6.24.7-rt27/kernel/rwlock_torture.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/kernel/rwlock_torture.c 2009-02-08 00:04:46.000000000 -0500 +@@ -0,0 +1,781 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rtmutex_common.h" ++ ++#ifdef CONFIG_LOGDEV ++#include ++#else ++#define lfcnprint(x...) do { } while (0) ++#define lmark() do { } while(0) ++#define logdev_dump() do { } while (0) ++#endif ++ ++static DEFINE_RWLOCK(lock1); ++static DEFINE_RWLOCK(lock2); ++static DEFINE_RWLOCK(lock3); ++ ++static DECLARE_RWSEM(sem1); ++static DECLARE_RWSEM(sem2); ++static DECLARE_RWSEM(sem3); ++ ++static DEFINE_MUTEX(mutex1); ++static DEFINE_MUTEX(mutex2); ++static DEFINE_MUTEX(mutex3); ++ ++struct locks { ++ union { ++ struct rw_semaphore *sem; ++ rwlock_t *lock; ++ struct mutex *mutex; ++ }; ++ int type; ++ char *name; ++ int read_cnt; ++ int write_cnt; ++ int downgrade; ++ int taken; ++ int retaken; ++}; ++ ++enum { LOCK_TYPE_LOCK = 0, ++ LOCK_TYPE_SEM = 1, ++ LOCK_TYPE_MUTEX = 2 ++}; ++ ++static struct locks test_lock1 = { ++ { ++ .lock = &lock1, ++ }, ++ .type = LOCK_TYPE_LOCK, ++ .name = "lock1", ++}; ++ ++static struct locks test_lock2 = { ++ { ++ .lock = &lock2, ++ }, ++ .type = LOCK_TYPE_LOCK, ++ .name = "lock2", ++}; ++ ++static struct locks test_lock3 = { ++ { ++ .lock = &lock3, ++ }, ++ .type = LOCK_TYPE_LOCK, ++ .name = "lock3", ++}; ++ ++static struct locks test_sem1 = { ++ { ++ .sem = &sem1, ++ }, ++ .type = LOCK_TYPE_SEM, ++ .name = "sem1", ++}; ++ ++static struct locks test_sem2 = { ++ { ++ .sem = &sem2, ++ }, ++ .type = LOCK_TYPE_SEM, ++ .name = "sem2", ++}; ++ ++static struct locks test_sem3 = { ++ { ++ .sem = &sem3, ++ }, ++ .type = LOCK_TYPE_SEM, ++ .name = "sem3", ++}; ++ ++static struct locks test_mutex1 = { ++ { ++ .mutex = &mutex1, ++ }, ++ .type = LOCK_TYPE_MUTEX, ++ .name = "mutex1", ++}; ++ ++static struct locks test_mutex2 = { ++ { ++ .mutex = &mutex2, ++ }, ++ .type = LOCK_TYPE_MUTEX, ++ .name = "mutex2", ++}; ++ ++static struct locks test_mutex3 = { ++ { ++ .mutex = &mutex3, ++ }, ++ .type = LOCK_TYPE_MUTEX, ++ .name = "mutex3", ++}; ++ ++static int test_done; ++ ++#define TIME_MAX 20000 ++ ++#define DEFAULT_NR_THREADS 300 ++#define DEFAULT_NR_RT_THREADS 10 ++ ++/* times in usecs */ ++#define DEFAULT_SCHED_OTHER_TIME_US 1000 ++#define DEFAULT_SCHED_FIFO_TIME_US 200 ++ ++/* this is in millisecs */ ++#define DEFAULT_SCHED_FIFO_SLEEP_TIME 2 ++#define DEFAULT_SCHED_OTHER_SLEEP_TIME 1 ++ ++#define DEFAULT_RT_THREAD_PRIO 40 ++ ++#define NR_TESTS 3 ++static unsigned long sched_other_time_usecs = DEFAULT_SCHED_OTHER_TIME_US; ++static unsigned long sched_fifo_time_usecs = DEFAULT_SCHED_FIFO_TIME_US; ++static unsigned int sched_other_sleep_ms = DEFAULT_SCHED_OTHER_SLEEP_TIME; ++static unsigned int sched_fifo_sleep_ms = DEFAULT_SCHED_FIFO_SLEEP_TIME; ++ ++static unsigned long rt_thread_prio = DEFAULT_RT_THREAD_PRIO; ++static unsigned int thread_count = DEFAULT_NR_THREADS; ++static unsigned int rt_thread_count = DEFAULT_NR_RT_THREADS; ++static int test_time = 30; ++static struct task_struct **tsks; ++ ++static int perform_downgrade_write = 0; ++ ++enum { ++ LOCK_READ = 0, ++ LOCK_WRITE = 1, ++ SEM_READ = 2, ++ SEM_WRITE = 3, ++ MUTEX = 5 /* must be odd */ ++}; ++ ++#ifdef CONFIG_PREEMPT_RT ++static void show_rtm_owner(char *str, struct rt_mutex *rtm) ++{ ++ struct task_struct *owner; ++ unsigned long val; ++ char *name; ++ ++ rcu_read_lock(); ++ val = (unsigned long)rtm->owner; ++ owner = (struct task_struct *)(val & ~3UL); ++ name = "NULL"; ++ if (owner) { ++ if (owner == (struct task_struct *)0x100) ++ name = "READER"; ++ else ++ name = owner->comm; ++ } ++ printk("%s val: %lx owner: %s\n", str, val, name); ++ ++ rcu_read_unlock(); ++} ++ ++static void show_mutex_owner(char *str, struct mutex *mutex) ++{ ++ show_rtm_owner(str, &mutex->lock); ++} ++ ++static void show_rwm_owner(char *str, struct rw_mutex *rwm) ++{ ++ struct reader_lock_struct *rls; ++ struct task_struct *owner; ++ unsigned long val; ++ char *name; ++ ++ rcu_read_lock(); ++ val = (unsigned long)rwm->owner; ++ owner = (struct task_struct *)(val & ~3UL); ++ name = "NULL"; ++ if (owner) { ++ switch ((unsigned long)owner) { ++ case 0x100: ++ name = "READER"; ++ break; ++ case 0x200: ++ name = "PENDING READER"; ++ break; ++ case 0x400: ++ name = "PENDING WRITER"; ++ break; ++ default: ++ name = owner->comm; ++ } ++ } ++ printk("%s val: %lx owner: %s count %d owners %d ", str, val, name, ++ atomic_read(&rwm->count), ++ atomic_read(&rwm->owners)); ++ show_rtm_owner(" mutex: ", &rwm->mutex); ++ list_for_each_entry(rls, &rwm->readers, list) { ++ if (!rls->task) ++ printk("NULL TASK!!!\n"); ++ else ++ printk(" owned by: %s:%d\n", ++ rls->task->comm, rls->task->pid); ++ } ++ rcu_read_unlock(); ++} ++ ++static void show_rwlock_owner(char *str, rwlock_t *lock) ++{ ++ show_rwm_owner(str, &lock->owners); ++} ++ ++static void show_sem_owner(char *str, struct rw_semaphore *sem) ++{ ++ show_rwm_owner(str, &sem->owners); ++} ++ ++void print_owned_read_locks(struct task_struct *tsk) ++{ ++ int i; ++ ++ if (!tsk->reader_lock_count) ++ return; ++ ++ oops_in_progress++; ++ printk(" %s:%d owns:\n", tsk->comm, tsk->pid); ++ for (i = 0; i < tsk->reader_lock_count; i++) { ++ printk(" %p\n", tsk->owned_read_locks[i].lock); ++ } ++ oops_in_progress--; ++} ++ ++#else ++# define show_sem_owner(x...) do { } while (0) ++# define show_rwlock_owner(x...) do { } while (0) ++# define show_mutex_owner(x...) do { } while (0) ++#endif ++ ++static int do_read(int read) ++{ ++ unsigned long x; ++ int ret; ++ ++ x = random32(); ++ ++ /* rwlock can not schedule */ ++ if (!(read & ~1)) { ++ ret = LOCK_READ; ++ goto out; ++ } ++ ++ /* every other time pick a mutex */ ++ if (x & 0x1000) ++ return MUTEX; /* do mutex */ ++ ++ /* alternate between locks and semaphores */ ++ if (x & 0x10) ++ ret = LOCK_READ; ++ else ++ ret = SEM_READ; ++ ++ out: ++ /* Do write 1 in 16 times */ ++ return ret | !(x & 0xf); ++} ++ ++static struct locks * ++pick_lock(struct locks *lock, struct locks *sem, struct locks *mutex, int read) ++{ ++ switch (read) { ++ case LOCK_READ: ++ case LOCK_WRITE: ++ return lock; ++ case SEM_READ: ++ case SEM_WRITE: ++ return sem; ++ case MUTEX: ++ return mutex; ++ } ++ return NULL; ++} ++ ++static void do_lock(struct locks *lock, int read) ++{ ++ switch (read) { ++ case LOCK_READ: ++ if (unlikely(lock->type != LOCK_TYPE_LOCK)) { ++ printk("FAILED expected lock but got %d\n", ++ lock->type); ++ return; ++ } ++ lfcnprint("read lock %s %p count=%d owners=%d", ++ lock->name, lock, atomic_read(&lock->lock->owners.count), ++ atomic_read(&lock->lock->owners.owners)); ++ read_lock(lock->lock); ++ break; ++ case LOCK_WRITE: ++ if (unlikely(lock->type != LOCK_TYPE_LOCK)) { ++ printk("FAILED expected lock but got %d\n", ++ lock->type); ++ return; ++ } ++ lfcnprint("write lock %s %p", lock->name, lock); ++ write_lock(lock->lock); ++ break; ++ case SEM_READ: ++ if (unlikely(lock->type != LOCK_TYPE_SEM)) { ++ printk("FAILED expected sem but got %d\n", ++ lock->type); ++ return; ++ } ++ lfcnprint("read sem %s %p count=%d owners=%d", ++ lock->name, lock, ++ atomic_read(&lock->sem->owners.count), ++ atomic_read(&lock->sem->owners.owners)); ++ down_read(lock->sem); ++ break; ++ case SEM_WRITE: ++ if (unlikely(lock->type != LOCK_TYPE_SEM)) { ++ printk("FAILED expected sem but got %d\n", ++ lock->type); ++ return; ++ } ++ lfcnprint("write sem %s %p", lock->name, lock); ++ down_write(lock->sem); ++ break; ++ case MUTEX: ++ if (unlikely(lock->type != LOCK_TYPE_MUTEX)) { ++ printk("FAILED expected mutex but got %d\n", ++ lock->type); ++ return; ++ } ++ lfcnprint("mutex %s %p", lock->name, lock); ++ mutex_lock(lock->mutex); ++ break; ++ default: ++ printk("bad lock value %d!!!\n", read); ++ } ++ lfcnprint("taken %s %p", lock->name, lock); ++} ++ ++static void do_unlock(struct locks *lock, int read) ++{ ++ switch (read) { ++ case LOCK_READ: ++ if (unlikely(lock->type != LOCK_TYPE_LOCK)) { ++ printk("FAILED expected lock but got %d\n", ++ lock->type); ++ return; ++ } ++ lfcnprint("read lock %s %p count=%d owners=%d", ++ lock->name, lock, atomic_read(&lock->lock->owners.count), ++ atomic_read(&lock->lock->owners.owners)); ++ read_unlock(lock->lock); ++ break; ++ case LOCK_WRITE: ++ if (unlikely(lock->type != LOCK_TYPE_LOCK)) { ++ printk("FAILED expected lock but got %d\n", ++ lock->type); ++ return; ++ } ++ lfcnprint("write lock %s %p", lock->name, lock); ++ write_unlock(lock->lock); ++ break; ++ case SEM_READ: ++ if (unlikely(lock->type != LOCK_TYPE_SEM)) { ++ printk("FAILED expected sem but got %d\n", ++ lock->type); ++ return; ++ } ++ lfcnprint("read sem %s, %p count=%d owners=%d", ++ lock->name, lock, atomic_read(&lock->sem->owners.count), ++ atomic_read(&lock->sem->owners.owners)); ++ up_read(lock->sem); ++ break; ++ case SEM_WRITE: ++ if (unlikely(lock->type != LOCK_TYPE_SEM)) { ++ printk("FAILED expected sem but got %d\n", ++ lock->type); ++ return; ++ } ++ lfcnprint("write sem %s %p", lock->name, lock); ++ up_write(lock->sem); ++ break; ++ case MUTEX: ++ if (unlikely(lock->type != LOCK_TYPE_MUTEX)) { ++ printk("FAILED expected mutex but got %d\n", ++ lock->type); ++ return; ++ } ++ lfcnprint("mutex %s %p", lock->name, lock); ++ mutex_unlock(lock->mutex); ++ break; ++ default: ++ printk("bad lock value %d!!!\n", read); ++ } ++ lfcnprint("unlocked"); ++} ++ ++static void do_something(unsigned long time, int ignore) ++{ ++ lmark(); ++ if (test_done) ++ return; ++ if (time > TIME_MAX) ++ time = TIME_MAX; ++ udelay(time); ++} ++ ++static void do_downgrade(unsigned long time, struct locks *lock, int *read) ++{ ++ struct rw_semaphore *sem = lock->sem; ++ unsigned long x; ++ ++ if (!perform_downgrade_write) ++ return; ++ ++ if (test_done) ++ return; ++ ++ if (*read == SEM_WRITE) { ++ x = random32(); ++ ++ /* Do downgrade write 1 in 16 times of a write */ ++ if (!(x & 0xf)) { ++ lfcnprint("downgrade %p", sem); ++ lock->downgrade++; ++ downgrade_write(sem); ++ do_something(time, 0); ++ /* need to do unlock read */ ++ *read = SEM_READ; ++ } ++ } ++} ++ ++static void update_stats(int read, struct locks *lock) ++{ ++ switch (read) { ++ case LOCK_READ: ++ case SEM_READ: ++ lock->read_cnt++; ++ break; ++ case LOCK_WRITE: ++ case SEM_WRITE: ++ lock->write_cnt++; ++ break; ++ } ++ lock->taken++; ++} ++ ++#define MAX_DEPTH 10 ++ ++static void run_lock(void (*func)(unsigned long time, int read), ++ struct locks *lock, unsigned long time, int read, int depth); ++ ++static void do_again(void (*func)(unsigned long time, int read), ++ struct locks *lock, unsigned long time, int read, int depth) ++{ ++ unsigned long x; ++ ++ if (test_done) ++ return; ++ ++ /* If this was grabbed for read via rwlock, do again */ ++ if (likely(read != LOCK_READ) || depth >= MAX_DEPTH) ++ return; ++ ++ x = random32(); ++ if (x & 1) { ++ lfcnprint("read lock again"); ++ run_lock(func, lock, time, read, depth+1); ++ } ++} ++ ++static void run_lock(void (*func)(unsigned long time, int read), ++ struct locks *lock, unsigned long time, int read, int depth) ++{ ++ if (test_done) ++ return; ++ ++ update_stats(read, lock); ++ if (depth) ++ lock->retaken++; ++ do_lock(lock, read); ++ if (!test_done) { ++ func(time, do_read(read)); ++ do_again(func, lock, time, read, depth); ++ } ++ do_downgrade(time, lock, &read); ++ do_unlock(lock, read); ++ ++} ++ ++static void run_one_lock(unsigned long time, int read) ++{ ++ struct locks *lock; ++ ++ lmark(); ++ lock = pick_lock(&test_lock1, &test_sem1, &test_mutex1, read); ++ run_lock(do_something, lock, time, read, 0); ++} ++ ++static void run_two_locks(unsigned long time, int read) ++{ ++ struct locks *lock; ++ ++ lmark(); ++ lock = pick_lock(&test_lock2, &test_sem2, &test_mutex2, read); ++ run_lock(run_one_lock, lock, time, read, 0); ++} ++ ++static void run_three_locks(unsigned long time, int read) ++{ ++ struct locks *lock; ++ ++ lmark(); ++ lock = pick_lock(&test_lock3, &test_sem3, &test_mutex3, read); ++ run_lock(run_two_locks, lock, time, read, 0); ++} ++ ++static int run_test(unsigned long time) ++{ ++ unsigned long long start; ++ int read; ++ int ret; ++ ++ if (test_done) ++ return 0; ++ ++ start = random32(); ++ ++ read = do_read(MUTEX); ++ ++ switch (ret = (start & 3)) { ++ case 0: ++ run_one_lock(time, read); ++ break; ++ case 1: ++ run_two_locks(time, read); ++ break; ++ case 2: ++ run_three_locks(time, read); ++ break; ++ default: ++ ret = 1; ++ run_two_locks(time, read); ++ } ++ ++ WARN_ON_ONCE(current->reader_lock_count); ++ ++ return ret; ++} ++ ++static int rwlock_thread(void *arg) ++{ ++ long prio = (long)arg; ++ unsigned long time; ++ unsigned long run; ++ struct sched_param param; ++ ++ time = sched_fifo_time_usecs; ++ if (prio) { ++ param.sched_priority = prio; ++ sched_setscheduler(current, SCHED_FIFO, ¶m); ++ time = sched_fifo_time_usecs; ++ } ++ ++ while (!kthread_should_stop()) { ++ run = run_test(time); ++ ++ if (prio) ++ msleep(sched_fifo_sleep_ms); ++ else ++ msleep(sched_other_sleep_ms); ++ } ++ ++ return 0; ++} ++ ++static void print_lock_stat(struct locks *lock) ++{ ++ switch (lock->type) { ++ case LOCK_TYPE_LOCK: ++ case LOCK_TYPE_SEM: ++ printk("%8s taken for read: %9d\n", lock->name, lock->read_cnt); ++ printk("%8s taken for write: %8d\n", lock->name, lock->write_cnt); ++ if (lock->type == LOCK_TYPE_LOCK) { ++ printk("%8s retaken: %9d\n", ++ lock->name, lock->retaken); ++ } else if (perform_downgrade_write) { ++ printk("%8s downgraded: %9d\n", ++ lock->name, lock->downgrade); ++ } ++ } ++ printk("%8s taken: %8d\n\n", lock->name, lock->taken); ++} ++ ++static int __init mutex_stress_init(void) ++{ ++ long i; ++ ++ tsks = kmalloc(sizeof(*tsks) * (thread_count + rt_thread_count), GFP_KERNEL); ++ if (!tsks) { ++ printk("failed to allocate tasks\n"); ++ return -1; ++ } ++ ++ printk("create threads and run for %d seconds\n", test_time); ++ ++ for (i=0; i < thread_count; i++) ++ tsks[i] = kthread_run(rwlock_thread, NULL, "mtest%d", i); ++ for (i=0; i < rt_thread_count; i++) { ++ long prio = rt_thread_prio + i; ++ tsks[thread_count + i] = ++ kthread_run(rwlock_thread, (void*)prio, ++ "mtest%d", thread_count + i); ++ } ++ ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(test_time * HZ); ++ ++ printk("kill threads\n"); ++ test_done = 1; ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ /* sleep some to allow all tasks to finish */ ++ schedule_timeout(3 * HZ); ++ ++ lfcnprint("Done"); ++ ++ show_rwlock_owner("lock1: ", &lock1); ++ show_rwlock_owner("lock2: ", &lock2); ++ show_rwlock_owner("lock3: ", &lock3); ++ ++ show_sem_owner("sem1: ", &sem1); ++ show_sem_owner("sem2: ", &sem2); ++ show_sem_owner("sem3: ", &sem3); ++ ++ show_mutex_owner("mutex1: ", &mutex1); ++ show_mutex_owner("mutex2: ", &mutex2); ++ show_mutex_owner("mutex3: ", &mutex3); ++ ++ oops_in_progress++; ++// logdev_dump(); ++ oops_in_progress--; ++ ++#ifdef CONFIG_PREEMPT_RT ++ for (i=0; i < (thread_count + rt_thread_count); i++) { ++ if (tsks[i]) { ++ struct rt_mutex *mtx; ++ unsigned long own; ++ struct rt_mutex_waiter *w; ++ ++ spin_lock_irq(&tsks[i]->pi_lock); ++ ++ print_owned_read_locks(tsks[i]); ++ ++ if (tsks[i]->pi_blocked_on) { ++ w = (void *)tsks[i]->pi_blocked_on; ++ mtx = w->lock; ++ spin_unlock_irq(&tsks[i]->pi_lock); ++ spin_lock_irq(&mtx->wait_lock); ++ spin_lock(&tsks[i]->pi_lock); ++ own = (unsigned long)mtx->owner & ~3UL; ++ oops_in_progress++; ++ printk("%s:%d is blocked on ", ++ tsks[i]->comm, tsks[i]->pid); ++ __print_symbol("%s", (unsigned long)mtx); ++ if (own == 0x100) ++ printk(" owner is READER\n"); ++ else if (!(own & ~300)) ++ printk(" owner is ILLEGAL!!\n"); ++ else if (!own) ++ printk(" has no owner!\n"); ++ else { ++ struct task_struct *owner = (void*)own; ++ ++ printk(" owner is %s:%d\n", ++ owner->comm, owner->pid); ++ } ++ oops_in_progress--; ++ ++ spin_unlock(&tsks[i]->pi_lock); ++ spin_unlock_irq(&mtx->wait_lock); ++ } else { ++ print_owned_read_locks(tsks[i]); ++ spin_unlock_irq(&tsks[i]->pi_lock); ++ } ++ } ++ } ++#endif ++ for (i=0; i < (thread_count + rt_thread_count); i++) { ++ if (tsks[i]) ++ kthread_stop(tsks[i]); ++ } ++ ++ print_lock_stat(&test_lock1); ++ print_lock_stat(&test_lock2); ++ print_lock_stat(&test_lock3); ++ print_lock_stat(&test_sem1); ++ print_lock_stat(&test_sem2); ++ print_lock_stat(&test_sem3); ++ print_lock_stat(&test_mutex1); ++ print_lock_stat(&test_mutex2); ++ print_lock_stat(&test_mutex3); ++ ++ if (!perform_downgrade_write) { ++ printk("No downgrade writes performed.\n" ++ " To enable it, pass in perform_downgrade_write=1 to the module\n"); ++ } ++ ++ return 0; ++} ++ ++static void mutex_stress_exit(void) ++{ ++} ++ ++module_init(mutex_stress_init); ++module_exit(mutex_stress_exit); ++ ++module_param(perform_downgrade_write, int, 0644); ++MODULE_PARM_DESC(perform_downgrade_write, ++ "Perform downgrade_write in the test"); ++ ++module_param(sched_other_time_usecs, ulong, 0644); ++MODULE_PARM_DESC(sched_other_time_usecs, ++ "Number of usecs to \"do something\""); ++ ++module_param(sched_fifo_time_usecs, ulong, 0644); ++MODULE_PARM_DESC(sched_fifo_time_usecs, ++ "Number of usecs for rt tasks to \"do something\""); ++ ++module_param(sched_other_sleep_ms, uint, 0644); ++MODULE_PARM_DESC(sched_other_sleep_ms, ++ "Number of usecs for tasks to sleep"); ++ ++module_param(sched_fifo_sleep_ms, uint, 0644); ++MODULE_PARM_DESC(sched_fifo_sleep_ms, ++ "Number of usecs for rt tasks to sleep"); ++ ++module_param(rt_thread_prio, long, 0644); ++MODULE_PARM_DESC(rt_thread_prio, "priority if FIFO tasks"); ++ ++module_param(thread_count, uint, 0644); ++MODULE_PARM_DESC(thread_count, "Number of threads to run"); ++ ++module_param(rt_thread_count, uint, 0644); ++MODULE_PARM_DESC(rt_thread_count, "Number of RT threads to run"); ++ ++module_param(test_time, uint, 0644); ++MODULE_PARM_DESC(test_time, "Number of seconds to run the test"); ++ ++MODULE_AUTHOR("Steven Rostedt"); ++MODULE_DESCRIPTION("Mutex Stress"); ++MODULE_LICENSE("GPL"); +Index: linux-2.6.24.7-rt27/lib/Kconfig.debug +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/Kconfig.debug 2009-02-08 00:02:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/Kconfig.debug 2009-02-08 00:04:46.000000000 -0500 +@@ -229,6 +229,17 @@ config DEBUG_SEMAPHORE + verbose debugging messages. If you suspect a semaphore problem or a + kernel hacker asks for this option then say Y. Otherwise say N. + ++config RWLOCK_TORTURE_TEST ++ tristate "torture tests for Priority Inheritance RW locks" ++ depends on DEBUG_KERNEL ++ depends on m ++ default n ++ help ++ This option provides a kernel modules that runs a torture test ++ of several threads that try to grab mutexes, rwlocks and rwsems. ++ ++ Say N if you are unsure. ++ + config DEBUG_LOCK_ALLOC + bool "Lock debugging: detect incorrect freeing of live locks" + depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0418-ppc32_notrace_init_functions.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0418-ppc32_notrace_init_functions.patch @@ -0,0 +1,38 @@ +Subject: don't trace early init functions for ppc32 +By: Luotao Fu + If the latency tracer is turned on in the kernel config, _mcount calls are + added automatically to every function call during compiling since -pg + compiling flag is set. _mcount() checks first the variable mcount_enabled. + (see implementation of _mcount() in arch/powerpc/kernel/entry_32.S) This will + stuck forever if _mcount is called before mcount_enabled is initialized. Hence + we mark some init functions as notrace, so that _mcount calls are not added to + these functions. + +Signed-off-by: Luotao Fu + +--- + arch/powerpc/kernel/cputable.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/cputable.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/cputable.c 2009-02-07 23:59:43.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/cputable.c 2009-02-08 00:04:10.000000000 -0500 +@@ -1333,7 +1333,7 @@ static struct cpu_spec __initdata cpu_sp + + static struct cpu_spec the_cpu_spec; + +-struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr) ++notrace struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr) + { + struct cpu_spec *s = cpu_specs; + struct cpu_spec *t = &the_cpu_spec; +@@ -1380,7 +1380,7 @@ struct cpu_spec * __init identify_cpu(un + return NULL; + } + +-void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) ++notrace void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) + { + struct fixup_entry { + unsigned long mask; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0499-rwlock-pi-lock-reader.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0499-rwlock-pi-lock-reader.patch @@ -0,0 +1,105 @@ +From: Steven Rostedt +Subject: rwlock: pi_lock fixes + +When waking up multiple readers we need to hold the pi_lock to +modify the pending lists. This patch also localizes the locks a bit more. + +Signed-off-by: Steven Rostedt +--- + kernel/rtmutex.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:48.000000000 -0500 +@@ -1918,7 +1918,6 @@ rt_write_slowunlock(struct rw_mutex *rwm + if (!rt_mutex_has_waiters(mutex)) + goto out; + +- spin_lock(&pendowner->pi_lock); + /* + * Wake up all readers. + * This gets a bit more complex. More than one reader can't +@@ -1933,13 +1932,17 @@ rt_write_slowunlock(struct rw_mutex *rwm + while (waiter && !waiter->write_lock) { + struct task_struct *reader = waiter->task; + ++ spin_lock(&pendowner->pi_lock); + plist_del(&waiter->list_entry, &mutex->wait_list); + + /* nop if not on a list */ + plist_del(&waiter->pi_list_entry, &pendowner->pi_waiters); ++ spin_unlock(&pendowner->pi_lock); + ++ spin_lock(&reader->pi_lock); + waiter->task = NULL; + reader->pi_blocked_on = NULL; ++ spin_unlock(&reader->pi_lock); + + if (savestate) + wake_up_process_mutex(reader); +@@ -1957,6 +1960,8 @@ rt_write_slowunlock(struct rw_mutex *rwm + struct rt_mutex_waiter *next; + + next = rt_mutex_top_waiter(mutex); ++ ++ spin_lock(&pendowner->pi_lock); + /* delete incase we didn't go through the loop */ + plist_del(&next->pi_list_entry, &pendowner->pi_waiters); + +@@ -1964,13 +1969,12 @@ rt_write_slowunlock(struct rw_mutex *rwm + if (next->write_lock) + /* add back in as top waiter */ + plist_add(&next->pi_list_entry, &pendowner->pi_waiters); ++ spin_unlock(&pendowner->pi_lock); + + rwm->prio = next->task->prio; + } else + rwm->prio = MAX_PRIO; + +- spin_unlock(&pendowner->pi_lock); +- + out: + + spin_unlock_irqrestore(&mutex->wait_lock, flags); +@@ -2052,18 +2056,21 @@ rt_mutex_downgrade_write(struct rw_mutex + * waiting, until we hit the reader limit, or a writer. + */ + +- spin_lock(¤t->pi_lock); + waiter = rt_mutex_top_waiter(mutex); + while (waiter && !waiter->write_lock) { + struct task_struct *reader = waiter->task; + ++ spin_lock(¤t->pi_lock); + plist_del(&waiter->list_entry, &mutex->wait_list); + + /* nop if not on a list */ + plist_del(&waiter->pi_list_entry, ¤t->pi_waiters); ++ spin_unlock(¤t->pi_lock); + ++ spin_lock(&reader->pi_lock); + waiter->task = NULL; + reader->pi_blocked_on = NULL; ++ spin_unlock(&reader->pi_lock); + + /* downgrade is only for mutexes */ + wake_up_process(reader); +@@ -2083,14 +2090,14 @@ rt_mutex_downgrade_write(struct rw_mutex + /* setup this mutex prio for read */ + rwm->prio = next->task->prio; + ++ spin_lock(¤t->pi_lock); + /* delete incase we didn't go through the loop */ + plist_del(&next->pi_list_entry, ¤t->pi_waiters); ++ spin_unlock(¤t->pi_lock); + /* No need to add back since readers don't have PI waiters */ + } else + rwm->prio = MAX_PRIO; + +- spin_unlock(¤t->pi_lock); +- + rt_mutex_set_owner(mutex, RT_RW_READER, 0); + + spin_unlock_irqrestore(&mutex->wait_lock, flags); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0270-hrtimer-no-printk.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0270-hrtimer-no-printk.patch @@ -0,0 +1,33 @@ +--- + kernel/hrtimer.c | 2 -- + kernel/time/timekeeping.c | 2 ++ + 2 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/hrtimer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/hrtimer.c 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/hrtimer.c 2009-02-08 00:02:54.000000000 -0500 +@@ -632,8 +632,6 @@ static int hrtimer_switch_to_hres(void) + /* "Retrigger" the interrupt to get things going */ + retrigger_next_event(NULL); + local_irq_restore(flags); +- printk(KERN_DEBUG "Switched to high resolution mode on CPU %d\n", +- smp_processor_id()); + return 1; + } + +Index: linux-2.6.24.7-rt27/kernel/time/timekeeping.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/timekeeping.c 2009-02-08 00:02:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/timekeeping.c 2009-02-08 00:02:54.000000000 -0500 +@@ -204,8 +204,10 @@ static void change_clocksource(void) + + tick_clock_notify(); + ++#ifndef CONFIG_PREEMPT_RT + printk(KERN_INFO "Time: %s clocksource has been installed.\n", + clock->name); ++#endif + } + #else + static inline void change_clocksource(void) { } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0452-multi-reader-pi.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0452-multi-reader-pi.patch @@ -0,0 +1,306 @@ +From: Steven Rostedt +Subject: read lock Priority Inheritance implementation + +This patch adds the priority inheritance (PI) to the read / write locks. +When a task is blocked on the lock that eventually is owned by a reader +in the PI chain, it will boost all the readers if they are of lower priority +than the blocked task. + +Signed-off-by: Steven Rostedt +--- + include/linux/init_task.h | 8 +++ + include/linux/rt_lock.h | 4 + + kernel/fork.c | 1 + kernel/rtmutex.c | 115 ++++++++++++++++++++++++++++++++++++++++++---- + 4 files changed, 118 insertions(+), 10 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/init_task.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/init_task.h 2009-02-08 00:03:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/init_task.h 2009-02-08 00:04:25.000000000 -0500 +@@ -99,6 +99,13 @@ extern struct nsproxy init_nsproxy; + #define INIT_PREEMPT_RCU_BOOST(tsk) + #endif /* #else #ifdef CONFIG_PREEMPT_RCU_BOOST */ + ++#ifdef CONFIG_PREEMPT_RT ++# define INIT_RW_OWNERS(tsk) .owned_read_locks = { \ ++ [0 ... (MAX_RWLOCK_DEPTH - 1) ] = { .task = &tsk } }, ++#else ++# define INIT_RW_OWNERS(tsk) ++#endif ++ + extern struct group_info init_groups; + + #define INIT_STRUCT_PID { \ +@@ -189,6 +196,7 @@ extern struct group_info init_groups; + INIT_TRACE_IRQFLAGS \ + INIT_LOCKDEP \ + INIT_PREEMPT_RCU_BOOST(tsk) \ ++ INIT_RW_OWNERS(tsk) \ + } + + +Index: linux-2.6.24.7-rt27/include/linux/rt_lock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rt_lock.h 2009-02-08 00:04:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rt_lock.h 2009-02-08 00:04:25.000000000 -0500 +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_PREEMPT_RT + /* +@@ -66,6 +67,7 @@ struct rw_mutex { + atomic_t count; /* number of times held for read */ + atomic_t owners; /* number of owners as readers */ + struct list_head readers; ++ int prio; + }; + + /* +@@ -98,6 +100,7 @@ typedef struct { + + #define __RW_LOCK_UNLOCKED(name) (rwlock_t) \ + { .owners.mutex = __RT_SPIN_INITIALIZER(name.owners.mutex), \ ++ .owners.prio = MAX_PRIO, \ + RW_DEP_MAP_INIT(name) } + #else /* !PREEMPT_RT */ + +@@ -196,6 +199,7 @@ extern int __bad_func_type(void); + + #define __RWSEM_INITIALIZER(name) \ + { .owners.mutex = __RT_MUTEX_INITIALIZER(name.owners.mutex), \ ++ .owners.prio = MAX_PRIO, \ + RW_DEP_MAP_INIT(name) } + + #define DECLARE_RWSEM(lockname) \ +Index: linux-2.6.24.7-rt27/kernel/fork.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/fork.c 2009-02-08 00:04:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/fork.c 2009-02-08 00:04:25.000000000 -0500 +@@ -1214,6 +1214,7 @@ static struct task_struct *copy_process( + INIT_LIST_HEAD(&p->owned_read_locks[i].list); + p->owned_read_locks[i].count = 0; + p->owned_read_locks[i].lock = NULL; ++ p->owned_read_locks[i].task = p; + } + } + #endif +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:25.000000000 -0500 +@@ -139,6 +139,8 @@ static inline void init_lists(struct rt_ + } + } + ++static int rt_mutex_get_readers_prio(struct task_struct *task, int prio); ++ + /* + * Calculate task priority from the waiter list priority + * +@@ -149,6 +151,8 @@ int rt_mutex_getprio(struct task_struct + { + int prio = min(task->normal_prio, get_rcu_prio(task)); + ++ prio = rt_mutex_get_readers_prio(task, prio); ++ + if (likely(!task_has_pi_waiters(task))) + return prio; + +@@ -191,6 +195,11 @@ static void rt_mutex_adjust_prio(struct + */ + int max_lock_depth = 1024; + ++static int rt_mutex_adjust_readers(struct rt_mutex *orig_lock, ++ struct rt_mutex_waiter *orig_waiter, ++ struct task_struct *top_task, ++ struct rt_mutex *lock, ++ int recursion_depth); + /* + * Adjust the priority chain. Also used for deadlock detection. + * Decreases task's usage by one - may thus free the task. +@@ -200,7 +209,8 @@ static int rt_mutex_adjust_prio_chain(st + int deadlock_detect, + struct rt_mutex *orig_lock, + struct rt_mutex_waiter *orig_waiter, +- struct task_struct *top_task) ++ struct task_struct *top_task, ++ int recursion_depth) + { + struct rt_mutex *lock; + struct rt_mutex_waiter *waiter, *top_waiter = orig_waiter; +@@ -302,8 +312,13 @@ static int rt_mutex_adjust_prio_chain(st + /* Grab the next task */ + task = rt_mutex_owner(lock); + +- /* Writers do not boost their readers. */ ++ /* ++ * Readers are special. We may need to boost more than one owner. ++ */ + if (task == RT_RW_READER) { ++ ret = rt_mutex_adjust_readers(orig_lock, orig_waiter, ++ top_task, lock, ++ recursion_depth); + spin_unlock_irqrestore(&lock->wait_lock, flags); + goto out; + } +@@ -490,9 +505,12 @@ static int task_blocks_on_rt_mutex(struc + spin_unlock(¤t->pi_lock); + + if (waiter == rt_mutex_top_waiter(lock)) { +- /* readers are not handled */ +- if (owner == RT_RW_READER) +- return 0; ++ /* readers are handled differently */ ++ if (owner == RT_RW_READER) { ++ res = rt_mutex_adjust_readers(lock, waiter, ++ current, lock, 0); ++ return res; ++ } + + spin_lock(&owner->pi_lock); + plist_del(&top_waiter->pi_list_entry, &owner->pi_waiters); +@@ -519,7 +537,7 @@ static int task_blocks_on_rt_mutex(struc + spin_unlock_irqrestore(&lock->wait_lock, flags); + + res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, waiter, +- current); ++ current, 0); + + spin_lock_irq(&lock->wait_lock); + +@@ -636,7 +654,7 @@ static void remove_waiter(struct rt_mute + + spin_unlock_irqrestore(&lock->wait_lock, flags); + +- rt_mutex_adjust_prio_chain(owner, 0, lock, NULL, current); ++ rt_mutex_adjust_prio_chain(owner, 0, lock, NULL, current, 0); + + spin_lock_irq(&lock->wait_lock); + } +@@ -663,7 +681,7 @@ void rt_mutex_adjust_pi(struct task_stru + get_task_struct(task); + spin_unlock_irqrestore(&task->pi_lock, flags); + +- rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task); ++ rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task, 0); + } + + /* +@@ -1160,7 +1178,6 @@ static int try_to_take_rw_read(struct rw + if (rt_rwlock_pending_writer(rwm)) + return 0; + if (rt_mutex_has_waiters(mutex)) { +- /* readers don't do PI */ + waiter = rt_mutex_top_waiter(mutex); + if (!lock_is_stealable(waiter->task, mode)) + return 0; +@@ -1174,7 +1191,7 @@ static int try_to_take_rw_read(struct rw + spin_unlock(&mtxowner->pi_lock); + } + } else if (rt_mutex_has_waiters(mutex)) { +- /* Readers don't do PI */ ++ /* Readers do things differently with respect to PI */ + waiter = rt_mutex_top_waiter(mutex); + spin_lock(¤t->pi_lock); + plist_del(&waiter->pi_list_entry, ¤t->pi_waiters); +@@ -1680,6 +1697,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + + /* If no one is blocked, then clear all ownership */ + if (!rt_mutex_has_waiters(mutex)) { ++ rwm->prio = MAX_PRIO; + /* + * If count is not zero, we are under the limit with + * no other readers. +@@ -1910,11 +1928,88 @@ void rt_mutex_rwsem_init(struct rw_mutex + rwm->owner = NULL; + atomic_set(&rwm->count, 0); + atomic_set(&rwm->owners, 0); ++ rwm->prio = MAX_PRIO; + INIT_LIST_HEAD(&rwm->readers); + + __rt_mutex_init(mutex, name); + } + ++static int rt_mutex_get_readers_prio(struct task_struct *task, int prio) ++{ ++ struct reader_lock_struct *rls; ++ struct rw_mutex *rwm; ++ int lock_prio; ++ int i; ++ ++ for (i = 0; i < task->reader_lock_count; i++) { ++ rls = &task->owned_read_locks[i]; ++ rwm = rls->lock; ++ if (rwm) { ++ lock_prio = rwm->prio; ++ if (prio > lock_prio) ++ prio = lock_prio; ++ } ++ } ++ ++ return prio; ++} ++ ++static int rt_mutex_adjust_readers(struct rt_mutex *orig_lock, ++ struct rt_mutex_waiter *orig_waiter, ++ struct task_struct *top_task, ++ struct rt_mutex *lock, ++ int recursion_depth) ++{ ++ struct reader_lock_struct *rls; ++ struct rt_mutex_waiter *waiter; ++ struct task_struct *task; ++ struct rw_mutex *rwm = container_of(lock, struct rw_mutex, mutex); ++ ++ if (rt_mutex_has_waiters(lock)) { ++ waiter = rt_mutex_top_waiter(lock); ++ /* ++ * Do we need to grab the task->pi_lock? ++ * Really, we are only reading it. If it ++ * changes, then that should follow this chain ++ * too. ++ */ ++ rwm->prio = waiter->task->prio; ++ } else ++ rwm->prio = MAX_PRIO; ++ ++ if (recursion_depth >= MAX_RWLOCK_DEPTH) { ++ WARN_ON(1); ++ return 1; ++ } ++ ++ list_for_each_entry(rls, &rwm->readers, list) { ++ task = rls->task; ++ get_task_struct(task); ++ /* ++ * rt_mutex_adjust_prio_chain will do ++ * the put_task_struct ++ */ ++ rt_mutex_adjust_prio_chain(task, 0, orig_lock, ++ orig_waiter, top_task, ++ recursion_depth+1); ++ } ++ ++ return 0; ++} ++#else ++static int rt_mutex_adjust_readers(struct rt_mutex *orig_lock, ++ struct rt_mutex_waiter *orig_waiter, ++ struct task_struct *top_task, ++ struct rt_mutex *lock, ++ int recursion_depth) ++{ ++ return 0; ++} ++ ++static int rt_mutex_get_readers_prio(struct task_struct *task, int prio) ++{ ++ return prio; ++} + #endif /* CONFIG_PREEMPT_RT */ + + #ifdef CONFIG_PREEMPT_BKL --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0057-markers-upstream.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0057-markers-upstream.patch @@ -0,0 +1,1513 @@ +--- + include/linux/immediate.h | 97 ++++++ + include/linux/marker.h | 117 +++++-- + include/linux/module.h | 30 + + kernel/marker.c | 709 ++++++++++++++++++++++++++++++++++------------ + kernel/module.c | 91 +++++ + 5 files changed, 817 insertions(+), 227 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/immediate.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/include/linux/immediate.h 2009-02-08 00:01:09.000000000 -0500 +@@ -0,0 +1,97 @@ ++#ifndef _LINUX_IMMEDIATE_H ++#define _LINUX_IMMEDIATE_H ++ ++/* ++ * Immediate values, can be updated at runtime and save cache lines. ++ * ++ * (C) Copyright 2007 Mathieu Desnoyers ++ * ++ * This file is released under the GPLv2. ++ * See the file COPYING for more details. ++ */ ++ ++#ifdef CONFIG_IMMEDIATE ++ ++#include ++ ++/** ++ * imv_set - set immediate variable (with locking) ++ * @name: immediate value name ++ * @i: required value ++ * ++ * Sets the value of @name, taking the module_mutex if required by ++ * the architecture. ++ */ ++#define imv_set(name, i) \ ++ do { \ ++ name##__imv = (i); \ ++ core_imv_update(); \ ++ module_imv_update(); \ ++ } while (0) ++ ++/* ++ * Internal update functions. ++ */ ++extern void core_imv_update(void); ++extern void imv_update_range(struct __imv *begin, struct __imv *end); ++extern void imv_unref_core_init(void); ++extern void imv_unref(struct __imv *begin, struct __imv *end, void *start, ++ unsigned long size); ++extern int _is_imv_cond_end(unsigned long *begin, unsigned long *end, ++ unsigned long addr1, unsigned long addr2); ++extern int is_imv_cond_end(unsigned long addr1, unsigned long addr2); ++ ++#else ++ ++/* ++ * Generic immediate values: a simple, standard, memory load. ++ */ ++ ++/** ++ * imv_read - read immediate variable ++ * @name: immediate value name ++ * ++ * Reads the value of @name. ++ */ ++#define imv_read(name) _imv_read(name) ++ ++/** ++ * imv_cond - read immediate variable use as condition for if() ++ * @name: immediate value name ++ * ++ * Reads the value of @name. ++ */ ++#define imv_cond(name) _imv_read(name) ++#define imv_cond_end() ++ ++/** ++ * imv_set - set immediate variable (with locking) ++ * @name: immediate value name ++ * @i: required value ++ * ++ * Sets the value of @name, taking the module_mutex if required by ++ * the architecture. ++ */ ++#define imv_set(name, i) (name##__imv = (i)) ++ ++static inline void core_imv_update(void) { } ++static inline void imv_unref_core_init(void) { } ++ ++#endif ++ ++#define DECLARE_IMV(type, name) extern __typeof__(type) name##__imv ++#define DEFINE_IMV(type, name) __typeof__(type) name##__imv ++ ++#define EXPORT_IMV_SYMBOL(name) EXPORT_SYMBOL(name##__imv) ++#define EXPORT_IMV_SYMBOL_GPL(name) EXPORT_SYMBOL_GPL(name##__imv) ++ ++/** ++ * _imv_read - Read immediate value with standard memory load. ++ * @name: immediate value name ++ * ++ * Force a data read of the immediate value instead of the immediate value ++ * based mechanism. Useful for __init and __exit section data read. ++ */ ++#define _imv_read(name) (name##__imv) ++ ++#endif +Index: linux-2.6.24.7-rt27/include/linux/marker.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/marker.h 2009-02-08 00:00:27.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/marker.h 2009-02-08 00:01:09.000000000 -0500 +@@ -12,6 +12,7 @@ + * See the file COPYING for more details. + */ + ++#include + #include + + struct module; +@@ -19,25 +20,35 @@ struct marker; + + /** + * marker_probe_func - Type of a marker probe function +- * @mdata: pointer of type struct marker +- * @private_data: caller site private data ++ * @probe_private: probe private data ++ * @call_private: call site private data + * @fmt: format string +- * @...: variable argument list ++ * @args: variable argument list pointer. Use a pointer to overcome C's ++ * inability to pass this around as a pointer in a portable manner in ++ * the callee otherwise. + * + * Type of marker probe functions. They receive the mdata and need to parse the + * format string to recover the variable argument list. + */ +-typedef void marker_probe_func(const struct marker *mdata, +- void *private_data, const char *fmt, ...); ++typedef void marker_probe_func(void *probe_private, void *call_private, ++ const char *fmt, va_list *args); ++ ++struct marker_probe_closure { ++ marker_probe_func *func; /* Callback */ ++ void *probe_private; /* Private probe data */ ++}; + + struct marker { + const char *name; /* Marker name */ + const char *format; /* Marker format string, describing the + * variable argument list. + */ +- char state; /* Marker state. */ +- marker_probe_func *call;/* Probe handler function pointer */ +- void *private; /* Private probe data */ ++ DEFINE_IMV(char, state);/* Immediate value state. */ ++ char ptype; /* probe type : 0 : single, 1 : multi */ ++ /* Probe wrapper */ ++ void (*call)(const struct marker *mdata, void *call_private, ...); ++ struct marker_probe_closure single; ++ struct marker_probe_closure *multi; + } __attribute__((aligned(8))); + + #ifdef CONFIG_MARKERS +@@ -48,51 +59,73 @@ struct marker { + * Make sure the alignment of the structure in the __markers section will + * not add unwanted padding between the beginning of the section and the + * structure. Force alignment to the same alignment as the section start. ++ * ++ * The "generic" argument controls which marker enabling mechanism must be used. ++ * If generic is true, a variable read is used. ++ * If generic is false, immediate values are used. + */ +-#define __trace_mark(name, call_data, format, args...) \ ++#define __trace_mark(generic, name, call_private, format, args...) \ + do { \ +- static const char __mstrtab_name_##name[] \ ++ static const char __mstrtab_##name[] \ + __attribute__((section("__markers_strings"))) \ +- = #name; \ +- static const char __mstrtab_format_##name[] \ +- __attribute__((section("__markers_strings"))) \ +- = format; \ ++ = #name "\0" format; \ + static struct marker __mark_##name \ + __attribute__((section("__markers"), aligned(8))) = \ +- { __mstrtab_name_##name, __mstrtab_format_##name, \ +- 0, __mark_empty_function, NULL }; \ ++ { __mstrtab_##name, &__mstrtab_##name[sizeof(#name)], \ ++ 0, 0, marker_probe_cb, \ ++ { __mark_empty_function, NULL}, NULL }; \ + __mark_check_format(format, ## args); \ +- if (unlikely(__mark_##name.state)) { \ +- preempt_disable(); \ +- (*__mark_##name.call) \ +- (&__mark_##name, call_data, \ +- format, ## args); \ +- preempt_enable(); \ ++ if (!generic) { \ ++ if (unlikely(imv_cond(__mark_##name.state))) { \ ++ imv_cond_end(); \ ++ (*__mark_##name.call) \ ++ (&__mark_##name, call_private, \ ++ ## args); \ ++ } else \ ++ imv_cond_end(); \ ++ } else { \ ++ if (unlikely(_imv_read(__mark_##name.state))) \ ++ (*__mark_##name.call) \ ++ (&__mark_##name, call_private, \ ++ ## args); \ + } \ + } while (0) + + extern void marker_update_probe_range(struct marker *begin, +- struct marker *end, struct module *probe_module, int *refcount); ++ struct marker *end); + #else /* !CONFIG_MARKERS */ +-#define __trace_mark(name, call_data, format, args...) \ ++#define __trace_mark(generic, name, call_private, format, args...) \ + __mark_check_format(format, ## args) + static inline void marker_update_probe_range(struct marker *begin, +- struct marker *end, struct module *probe_module, int *refcount) ++ struct marker *end) + { } + #endif /* CONFIG_MARKERS */ + + /** +- * trace_mark - Marker ++ * trace_mark - Marker using code patching + * @name: marker name, not quoted. + * @format: format string + * @args...: variable argument list + * +- * Places a marker. ++ * Places a marker using optimized code patching technique (imv_read()) ++ * to be enabled when immediate values are present. + */ + #define trace_mark(name, format, args...) \ +- __trace_mark(name, NULL, format, ## args) ++ __trace_mark(0, name, NULL, format, ## args) + +-#define MARK_MAX_FORMAT_LEN 1024 ++/** ++ * _trace_mark - Marker using variable read ++ * @name: marker name, not quoted. ++ * @format: format string ++ * @args...: variable argument list ++ * ++ * Places a marker using a standard memory read (_imv_read()) to be ++ * enabled. Should be used for markers in code paths where instruction ++ * modification based enabling is not welcome. (__init and __exit functions, ++ * lockdep, some traps, printk). ++ */ ++#define _trace_mark(name, format, args...) \ ++ __trace_mark(1, name, NULL, format, ## args) + + /** + * MARK_NOARGS - Format string for a marker with no argument. +@@ -100,30 +133,42 @@ static inline void marker_update_probe_r + #define MARK_NOARGS " " + + /* To be used for string format validity checking with gcc */ +-static inline void __printf(1, 2) __mark_check_format(const char *fmt, ...) ++static inline void __printf(1, 2) ___mark_check_format(const char *fmt, ...) + { + } + ++#define __mark_check_format(format, args...) \ ++ do { \ ++ if (0) \ ++ ___mark_check_format(format, ## args); \ ++ } while (0) ++ + extern marker_probe_func __mark_empty_function; + ++extern void marker_probe_cb(const struct marker *mdata, ++ void *call_private, ...); ++extern void marker_probe_cb_noarg(const struct marker *mdata, ++ void *call_private, ...); ++ + /* + * Connect a probe to a marker. + * private data pointer must be a valid allocated memory address, or NULL. + */ + extern int marker_probe_register(const char *name, const char *format, +- marker_probe_func *probe, void *private); ++ marker_probe_func *probe, void *probe_private); + + /* + * Returns the private data given to marker_probe_register. + */ +-extern void *marker_probe_unregister(const char *name); ++extern int marker_probe_unregister(const char *name, ++ marker_probe_func *probe, void *probe_private); + /* + * Unregister a marker by providing the registered private data. + */ +-extern void *marker_probe_unregister_private_data(void *private); ++extern int marker_probe_unregister_private_data(marker_probe_func *probe, ++ void *probe_private); + +-extern int marker_arm(const char *name); +-extern int marker_disarm(const char *name); +-extern void *marker_get_private_data(const char *name); ++extern void *marker_get_private_data(const char *name, marker_probe_func *probe, ++ int num); + + #endif +Index: linux-2.6.24.7-rt27/include/linux/module.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/module.h 2009-02-08 00:00:27.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/module.h 2009-02-08 00:01:09.000000000 -0500 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -355,6 +356,12 @@ struct module + /* The command line arguments (may be mangled). People like + keeping pointers to this stuff */ + char *args; ++#ifdef CONFIG_IMMEDIATE ++ struct __imv *immediate; ++ unsigned int num_immediate; ++ unsigned long *immediate_cond_end; ++ unsigned int num_immediate_cond_end; ++#endif + #ifdef CONFIG_MARKERS + struct marker *markers; + unsigned int num_markers; +@@ -462,7 +469,7 @@ int unregister_module_notifier(struct no + + extern void print_modules(void); + +-extern void module_update_markers(struct module *probe_module, int *refcount); ++extern void module_update_markers(void); + + #else /* !CONFIG_MODULES... */ + #define EXPORT_SYMBOL(sym) +@@ -563,13 +570,30 @@ static inline void print_modules(void) + { + } + +-static inline void module_update_markers(struct module *probe_module, +- int *refcount) ++static inline void module_update_markers(void) + { + } + + #endif /* CONFIG_MODULES */ + ++#if defined(CONFIG_MODULES) && defined(CONFIG_IMMEDIATE) ++extern void _module_imv_update(void); ++extern void module_imv_update(void); ++extern int is_imv_cond_end_module(unsigned long addr1, unsigned long addr2); ++#else ++static inline void _module_imv_update(void) ++{ ++} ++static inline void module_imv_update(void) ++{ ++} ++static inline int is_imv_cond_end_module(unsigned long addr1, ++ unsigned long addr2) ++{ ++ return 0; ++} ++#endif ++ + struct device_driver; + #ifdef CONFIG_SYSFS + struct module; +Index: linux-2.6.24.7-rt27/kernel/marker.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/marker.c 2009-02-08 00:00:27.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/marker.c 2009-02-08 00:01:09.000000000 -0500 +@@ -23,39 +23,48 @@ + #include + #include + #include ++#include ++#include + + extern struct marker __start___markers[]; + extern struct marker __stop___markers[]; + ++/* Set to 1 to enable marker debug output */ ++static const int marker_debug; ++ + /* + * markers_mutex nests inside module_mutex. Markers mutex protects the builtin +- * and module markers, the hash table and deferred_sync. ++ * and module markers and the hash table. + */ + static DEFINE_MUTEX(markers_mutex); + + /* +- * Marker deferred synchronization. +- * Upon marker probe_unregister, we delay call to synchronize_sched() to +- * accelerate mass unregistration (only when there is no more reference to a +- * given module do we call synchronize_sched()). However, we need to make sure +- * every critical region has ended before we re-arm a marker that has been +- * unregistered and then registered back with a different probe data. +- */ +-static int deferred_sync; +- +-/* + * Marker hash table, containing the active markers. + * Protected by module_mutex. + */ + #define MARKER_HASH_BITS 6 + #define MARKER_TABLE_SIZE (1 << MARKER_HASH_BITS) + ++/* ++ * Note about RCU : ++ * It is used to make sure every handler has finished using its private data ++ * between two consecutive operation (add or remove) on a given marker. It is ++ * also used to delay the free of multiple probes array until a quiescent state ++ * is reached. ++ * marker entries modifications are protected by the markers_mutex. ++ */ + struct marker_entry { + struct hlist_node hlist; + char *format; +- marker_probe_func *probe; +- void *private; ++ /* Probe wrapper */ ++ void (*call)(const struct marker *mdata, void *call_private, ...); ++ struct marker_probe_closure single; ++ struct marker_probe_closure *multi; + int refcount; /* Number of times armed. 0 if disarmed. */ ++ struct rcu_head rcu; ++ void *oldptr; ++ unsigned char rcu_pending:1; ++ unsigned char ptype:1; + char name[0]; /* Contains name'\0'format'\0' */ + }; + +@@ -63,7 +72,8 @@ static struct hlist_head marker_table[MA + + /** + * __mark_empty_function - Empty probe callback +- * @mdata: pointer of type const struct marker ++ * @probe_private: probe private data ++ * @call_private: call site private data + * @fmt: format string + * @...: variable argument list + * +@@ -72,13 +82,265 @@ static struct hlist_head marker_table[MA + * though the function pointer change and the marker enabling are two distinct + * operations that modifies the execution flow of preemptible code. + */ +-void __mark_empty_function(const struct marker *mdata, void *private, +- const char *fmt, ...) ++void __mark_empty_function(void *probe_private, void *call_private, ++ const char *fmt, va_list *args) + { + } + EXPORT_SYMBOL_GPL(__mark_empty_function); + + /* ++ * marker_probe_cb Callback that prepares the variable argument list for probes. ++ * @mdata: pointer of type struct marker ++ * @call_private: caller site private data ++ * @...: Variable argument list. ++ * ++ * Since we do not use "typical" pointer based RCU in the 1 argument case, we ++ * need to put a full smp_rmb() in this branch. This is why we do not use ++ * rcu_dereference() for the pointer read. ++ */ ++void marker_probe_cb(const struct marker *mdata, void *call_private, ...) ++{ ++ va_list args; ++ char ptype; ++ ++ /* ++ * preempt_disable does two things : disabling preemption to make sure ++ * the teardown of the callbacks can be done correctly when they are in ++ * modules and they insure RCU read coherency. ++ */ ++ preempt_disable(); ++ ptype = mdata->ptype; ++ if (likely(!ptype)) { ++ marker_probe_func *func; ++ /* Must read the ptype before ptr. They are not data dependant, ++ * so we put an explicit smp_rmb() here. */ ++ smp_rmb(); ++ func = mdata->single.func; ++ /* Must read the ptr before private data. They are not data ++ * dependant, so we put an explicit smp_rmb() here. */ ++ smp_rmb(); ++ va_start(args, call_private); ++ func(mdata->single.probe_private, call_private, mdata->format, ++ &args); ++ va_end(args); ++ } else { ++ struct marker_probe_closure *multi; ++ int i; ++ /* ++ * multi points to an array, therefore accessing the array ++ * depends on reading multi. However, even in this case, ++ * we must insure that the pointer is read _before_ the array ++ * data. Same as rcu_dereference, but we need a full smp_rmb() ++ * in the fast path, so put the explicit barrier here. ++ */ ++ smp_read_barrier_depends(); ++ multi = mdata->multi; ++ for (i = 0; multi[i].func; i++) { ++ va_start(args, call_private); ++ multi[i].func(multi[i].probe_private, call_private, ++ mdata->format, &args); ++ va_end(args); ++ } ++ } ++ preempt_enable(); ++} ++EXPORT_SYMBOL_GPL(marker_probe_cb); ++ ++/* ++ * marker_probe_cb Callback that does not prepare the variable argument list. ++ * @mdata: pointer of type struct marker ++ * @call_private: caller site private data ++ * @...: Variable argument list. ++ * ++ * Should be connected to markers "MARK_NOARGS". ++ */ ++void marker_probe_cb_noarg(const struct marker *mdata, void *call_private, ...) ++{ ++ va_list args; /* not initialized */ ++ char ptype; ++ ++ preempt_disable(); ++ ptype = mdata->ptype; ++ if (likely(!ptype)) { ++ marker_probe_func *func; ++ /* Must read the ptype before ptr. They are not data dependant, ++ * so we put an explicit smp_rmb() here. */ ++ smp_rmb(); ++ func = mdata->single.func; ++ /* Must read the ptr before private data. They are not data ++ * dependant, so we put an explicit smp_rmb() here. */ ++ smp_rmb(); ++ func(mdata->single.probe_private, call_private, mdata->format, ++ &args); ++ } else { ++ struct marker_probe_closure *multi; ++ int i; ++ /* ++ * multi points to an array, therefore accessing the array ++ * depends on reading multi. However, even in this case, ++ * we must insure that the pointer is read _before_ the array ++ * data. Same as rcu_dereference, but we need a full smp_rmb() ++ * in the fast path, so put the explicit barrier here. ++ */ ++ smp_read_barrier_depends(); ++ multi = mdata->multi; ++ for (i = 0; multi[i].func; i++) ++ multi[i].func(multi[i].probe_private, call_private, ++ mdata->format, &args); ++ } ++ preempt_enable(); ++} ++EXPORT_SYMBOL_GPL(marker_probe_cb_noarg); ++ ++static void free_old_closure(struct rcu_head *head) ++{ ++ struct marker_entry *entry = container_of(head, ++ struct marker_entry, rcu); ++ kfree(entry->oldptr); ++ /* Make sure we free the data before setting the pending flag to 0 */ ++ smp_wmb(); ++ entry->rcu_pending = 0; ++} ++ ++static void debug_print_probes(struct marker_entry *entry) ++{ ++ int i; ++ ++ if (!marker_debug) ++ return; ++ ++ if (!entry->ptype) { ++ printk(KERN_DEBUG "Single probe : %p %p\n", ++ entry->single.func, ++ entry->single.probe_private); ++ } else { ++ for (i = 0; entry->multi[i].func; i++) ++ printk(KERN_DEBUG "Multi probe %d : %p %p\n", i, ++ entry->multi[i].func, ++ entry->multi[i].probe_private); ++ } ++} ++ ++static struct marker_probe_closure * ++marker_entry_add_probe(struct marker_entry *entry, ++ marker_probe_func *probe, void *probe_private) ++{ ++ int nr_probes = 0; ++ struct marker_probe_closure *old, *new; ++ ++ WARN_ON(!probe); ++ ++ debug_print_probes(entry); ++ old = entry->multi; ++ if (!entry->ptype) { ++ if (entry->single.func == probe && ++ entry->single.probe_private == probe_private) ++ return ERR_PTR(-EBUSY); ++ if (entry->single.func == __mark_empty_function) { ++ /* 0 -> 1 probes */ ++ entry->single.func = probe; ++ entry->single.probe_private = probe_private; ++ entry->refcount = 1; ++ entry->ptype = 0; ++ debug_print_probes(entry); ++ return NULL; ++ } else { ++ /* 1 -> 2 probes */ ++ nr_probes = 1; ++ old = NULL; ++ } ++ } else { ++ /* (N -> N+1), (N != 0, 1) probes */ ++ for (nr_probes = 0; old[nr_probes].func; nr_probes++) ++ if (old[nr_probes].func == probe ++ && old[nr_probes].probe_private ++ == probe_private) ++ return ERR_PTR(-EBUSY); ++ } ++ /* + 2 : one for new probe, one for NULL func */ ++ new = kzalloc((nr_probes + 2) * sizeof(struct marker_probe_closure), ++ GFP_KERNEL); ++ if (new == NULL) ++ return ERR_PTR(-ENOMEM); ++ if (!old) ++ new[0] = entry->single; ++ else ++ memcpy(new, old, ++ nr_probes * sizeof(struct marker_probe_closure)); ++ new[nr_probes].func = probe; ++ new[nr_probes].probe_private = probe_private; ++ entry->refcount = nr_probes + 1; ++ entry->multi = new; ++ entry->ptype = 1; ++ debug_print_probes(entry); ++ return old; ++} ++ ++static struct marker_probe_closure * ++marker_entry_remove_probe(struct marker_entry *entry, ++ marker_probe_func *probe, void *probe_private) ++{ ++ int nr_probes = 0, nr_del = 0, i; ++ struct marker_probe_closure *old, *new; ++ ++ old = entry->multi; ++ ++ debug_print_probes(entry); ++ if (!entry->ptype) { ++ /* 0 -> N is an error */ ++ WARN_ON(entry->single.func == __mark_empty_function); ++ /* 1 -> 0 probes */ ++ WARN_ON(probe && entry->single.func != probe); ++ WARN_ON(entry->single.probe_private != probe_private); ++ entry->single.func = __mark_empty_function; ++ entry->refcount = 0; ++ entry->ptype = 0; ++ debug_print_probes(entry); ++ return NULL; ++ } else { ++ /* (N -> M), (N > 1, M >= 0) probes */ ++ for (nr_probes = 0; old[nr_probes].func; nr_probes++) { ++ if ((!probe || old[nr_probes].func == probe) ++ && old[nr_probes].probe_private ++ == probe_private) ++ nr_del++; ++ } ++ } ++ ++ if (nr_probes - nr_del == 0) { ++ /* N -> 0, (N > 1) */ ++ entry->single.func = __mark_empty_function; ++ entry->refcount = 0; ++ entry->ptype = 0; ++ } else if (nr_probes - nr_del == 1) { ++ /* N -> 1, (N > 1) */ ++ for (i = 0; old[i].func; i++) ++ if ((probe && old[i].func != probe) || ++ old[i].probe_private != probe_private) ++ entry->single = old[i]; ++ entry->refcount = 1; ++ entry->ptype = 0; ++ } else { ++ int j = 0; ++ /* N -> M, (N > 1, M > 1) */ ++ /* + 1 for NULL */ ++ new = kzalloc((nr_probes - nr_del + 1) ++ * sizeof(struct marker_probe_closure), GFP_KERNEL); ++ if (new == NULL) ++ return ERR_PTR(-ENOMEM); ++ for (i = 0; old[i].func; i++) ++ if ((probe && old[i].func != probe) || ++ old[i].probe_private != probe_private) ++ new[j++] = old[i]; ++ entry->refcount = nr_probes - nr_del; ++ entry->ptype = 1; ++ entry->multi = new; ++ } ++ debug_print_probes(entry); ++ return old; ++} ++ ++/* + * Get marker if the marker is present in the marker hash table. + * Must be called with markers_mutex held. + * Returns NULL if not present. +@@ -102,8 +364,7 @@ static struct marker_entry *get_marker(c + * Add the marker to the marker hash table. Must be called with markers_mutex + * held. + */ +-static int add_marker(const char *name, const char *format, +- marker_probe_func *probe, void *private) ++static struct marker_entry *add_marker(const char *name, const char *format) + { + struct hlist_head *head; + struct hlist_node *node; +@@ -118,9 +379,8 @@ static int add_marker(const char *name, + hlist_for_each_entry(e, node, head, hlist) { + if (!strcmp(name, e->name)) { + printk(KERN_NOTICE +- "Marker %s busy, probe %p already installed\n", +- name, e->probe); +- return -EBUSY; /* Already there */ ++ "Marker %s busy\n", name); ++ return ERR_PTR(-EBUSY); /* Already there */ + } + } + /* +@@ -130,34 +390,42 @@ static int add_marker(const char *name, + e = kmalloc(sizeof(struct marker_entry) + name_len + format_len, + GFP_KERNEL); + if (!e) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); + memcpy(&e->name[0], name, name_len); + if (format) { + e->format = &e->name[name_len]; + memcpy(e->format, format, format_len); ++ if (strcmp(e->format, MARK_NOARGS) == 0) ++ e->call = marker_probe_cb_noarg; ++ else ++ e->call = marker_probe_cb; + trace_mark(core_marker_format, "name %s format %s", + e->name, e->format); +- } else ++ } else { + e->format = NULL; +- e->probe = probe; +- e->private = private; ++ e->call = marker_probe_cb; ++ } ++ e->single.func = __mark_empty_function; ++ e->single.probe_private = NULL; ++ e->multi = NULL; ++ e->ptype = 0; + e->refcount = 0; ++ e->rcu_pending = 0; + hlist_add_head(&e->hlist, head); +- return 0; ++ return e; + } + + /* + * Remove the marker from the marker hash table. Must be called with mutex_lock + * held. + */ +-static void *remove_marker(const char *name) ++static int remove_marker(const char *name) + { + struct hlist_head *head; + struct hlist_node *node; + struct marker_entry *e; + int found = 0; + size_t len = strlen(name) + 1; +- void *private = NULL; + u32 hash = jhash(name, len-1, 0); + + head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)]; +@@ -167,12 +435,16 @@ static void *remove_marker(const char *n + break; + } + } +- if (found) { +- private = e->private; +- hlist_del(&e->hlist); +- kfree(e); +- } +- return private; ++ if (!found) ++ return -ENOENT; ++ if (e->single.func != __mark_empty_function) ++ return -EBUSY; ++ hlist_del(&e->hlist); ++ /* Make sure the call_rcu has been executed */ ++ if (e->rcu_pending) ++ rcu_barrier(); ++ kfree(e); ++ return 0; + } + + /* +@@ -184,6 +456,7 @@ static int marker_set_format(struct mark + size_t name_len = strlen((*entry)->name) + 1; + size_t format_len = strlen(format) + 1; + ++ + e = kmalloc(sizeof(struct marker_entry) + name_len + format_len, + GFP_KERNEL); + if (!e) +@@ -191,11 +464,20 @@ static int marker_set_format(struct mark + memcpy(&e->name[0], (*entry)->name, name_len); + e->format = &e->name[name_len]; + memcpy(e->format, format, format_len); +- e->probe = (*entry)->probe; +- e->private = (*entry)->private; ++ if (strcmp(e->format, MARK_NOARGS) == 0) ++ e->call = marker_probe_cb_noarg; ++ else ++ e->call = marker_probe_cb; ++ e->single = (*entry)->single; ++ e->multi = (*entry)->multi; ++ e->ptype = (*entry)->ptype; + e->refcount = (*entry)->refcount; ++ e->rcu_pending = 0; + hlist_add_before(&e->hlist, &(*entry)->hlist); + hlist_del(&(*entry)->hlist); ++ /* Make sure the call_rcu has been executed */ ++ if ((*entry)->rcu_pending) ++ rcu_barrier(); + kfree(*entry); + *entry = e; + trace_mark(core_marker_format, "name %s format %s", +@@ -206,7 +488,8 @@ static int marker_set_format(struct mark + /* + * Sets the probe callback corresponding to one marker. + */ +-static int set_marker(struct marker_entry **entry, struct marker *elem) ++static int set_marker(struct marker_entry **entry, struct marker *elem, ++ int active) + { + int ret; + WARN_ON(strcmp((*entry)->name, elem->name) != 0); +@@ -226,26 +509,64 @@ static int set_marker(struct marker_entr + if (ret) + return ret; + } +- elem->call = (*entry)->probe; +- elem->private = (*entry)->private; +- elem->state = 1; ++ ++ /* ++ * probe_cb setup (statically known) is done here. It is ++ * asynchronous with the rest of execution, therefore we only ++ * pass from a "safe" callback (with argument) to an "unsafe" ++ * callback (does not set arguments). ++ */ ++ elem->call = (*entry)->call; ++ /* ++ * Sanity check : ++ * We only update the single probe private data when the ptr is ++ * set to a _non_ single probe! (0 -> 1 and N -> 1, N != 1) ++ */ ++ WARN_ON(elem->single.func != __mark_empty_function ++ && elem->single.probe_private ++ != (*entry)->single.probe_private && ++ !elem->ptype); ++ elem->single.probe_private = (*entry)->single.probe_private; ++ /* ++ * Make sure the private data is valid when we update the ++ * single probe ptr. ++ */ ++ smp_wmb(); ++ elem->single.func = (*entry)->single.func; ++ /* ++ * We also make sure that the new probe callbacks array is consistent ++ * before setting a pointer to it. ++ */ ++ rcu_assign_pointer(elem->multi, (*entry)->multi); ++ /* ++ * Update the function or multi probe array pointer before setting the ++ * ptype. ++ */ ++ smp_wmb(); ++ elem->ptype = (*entry)->ptype; ++ elem->state__imv = active; ++ + return 0; + } + + /* + * Disable a marker and its probe callback. +- * Note: only after a synchronize_sched() issued after setting elem->call to the +- * empty function insures that the original callback is not used anymore. This +- * insured by preemption disabling around the call site. ++ * Note: only waiting an RCU period after setting elem->call to the empty ++ * function insures that the original callback is not used anymore. This insured ++ * by preempt_disable around the call site. + */ + static void disable_marker(struct marker *elem) + { +- elem->state = 0; +- elem->call = __mark_empty_function; ++ /* leave "call" as is. It is known statically. */ ++ elem->state__imv = 0; ++ elem->single.func = __mark_empty_function; ++ /* Update the function before setting the ptype */ ++ smp_wmb(); ++ elem->ptype = 0; /* single probe */ + /* + * Leave the private data and id there, because removal is racy and +- * should be done only after a synchronize_sched(). These are never used +- * until the next initialization anyway. ++ * should be done only after an RCU period. These are never used until ++ * the next initialization anyway. + */ + } + +@@ -253,14 +574,11 @@ static void disable_marker(struct marker + * marker_update_probe_range - Update a probe range + * @begin: beginning of the range + * @end: end of the range +- * @probe_module: module address of the probe being updated +- * @refcount: number of references left to the given probe_module (out) + * + * Updates the probe callback corresponding to a range of markers. + */ + void marker_update_probe_range(struct marker *begin, +- struct marker *end, struct module *probe_module, +- int *refcount) ++ struct marker *end) + { + struct marker *iter; + struct marker_entry *mark_entry; +@@ -268,15 +586,12 @@ void marker_update_probe_range(struct ma + mutex_lock(&markers_mutex); + for (iter = begin; iter < end; iter++) { + mark_entry = get_marker(iter->name); +- if (mark_entry && mark_entry->refcount) { +- set_marker(&mark_entry, iter); ++ if (mark_entry) { ++ set_marker(&mark_entry, iter, ++ !!mark_entry->refcount); + /* + * ignore error, continue + */ +- if (probe_module) +- if (probe_module == +- __module_text_address((unsigned long)mark_entry->probe)) +- (*refcount)++; + } else { + disable_marker(iter); + } +@@ -286,23 +601,30 @@ void marker_update_probe_range(struct ma + + /* + * Update probes, removing the faulty probes. +- * Issues a synchronize_sched() when no reference to the module passed +- * as parameter is found in the probes so the probe module can be +- * safely unloaded from now on. ++ * ++ * Internal callback only changed before the first probe is connected to it. ++ * Single probe private data can only be changed on 0 -> 1 and 2 -> 1 ++ * transitions. All other transitions will leave the old private data valid. ++ * This makes the non-atomicity of the callback/private data updates valid. ++ * ++ * "special case" updates : ++ * 0 -> 1 callback ++ * 1 -> 0 callback ++ * 1 -> 2 callbacks ++ * 2 -> 1 callbacks ++ * Other updates all behave the same, just like the 2 -> 3 or 3 -> 2 updates. ++ * Site effect : marker_set_format may delete the marker entry (creating a ++ * replacement). + */ +-static void marker_update_probes(struct module *probe_module) ++static void marker_update_probes(void) + { +- int refcount = 0; +- + /* Core kernel markers */ +- marker_update_probe_range(__start___markers, +- __stop___markers, probe_module, &refcount); ++ marker_update_probe_range(__start___markers, __stop___markers); + /* Markers in modules. */ +- module_update_markers(probe_module, &refcount); +- if (probe_module && refcount == 0) { +- synchronize_sched(); +- deferred_sync = 0; +- } ++ module_update_markers(); ++ /* Update immediate values */ ++ core_imv_update(); ++ module_imv_update(); + } + + /** +@@ -310,33 +632,52 @@ static void marker_update_probes(struct + * @name: marker name + * @format: format string + * @probe: probe handler +- * @private: probe private data ++ * @probe_private: probe private data + * + * private data must be a valid allocated memory address, or NULL. + * Returns 0 if ok, error value on error. ++ * The probe address must at least be aligned on the architecture pointer size. + */ + int marker_probe_register(const char *name, const char *format, +- marker_probe_func *probe, void *private) ++ marker_probe_func *probe, void *probe_private) + { + struct marker_entry *entry; + int ret = 0; ++ struct marker_probe_closure *old; + + mutex_lock(&markers_mutex); + entry = get_marker(name); +- if (entry && entry->refcount) { +- ret = -EBUSY; +- goto end; +- } +- if (deferred_sync) { +- synchronize_sched(); +- deferred_sync = 0; ++ if (!entry) { ++ entry = add_marker(name, format); ++ if (IS_ERR(entry)) { ++ ret = PTR_ERR(entry); ++ goto end; ++ } + } +- ret = add_marker(name, format, probe, private); +- if (ret) ++ /* ++ * If we detect that a call_rcu is pending for this marker, ++ * make sure it's executed now. ++ */ ++ if (entry->rcu_pending) ++ rcu_barrier(); ++ old = marker_entry_add_probe(entry, probe, probe_private); ++ if (IS_ERR(old)) { ++ ret = PTR_ERR(old); + goto end; ++ } + mutex_unlock(&markers_mutex); +- marker_update_probes(NULL); +- return ret; ++ marker_update_probes(); /* may update entry */ ++ mutex_lock(&markers_mutex); ++ entry = get_marker(name); ++ WARN_ON(!entry); ++ entry->oldptr = old; ++ entry->rcu_pending = 1; ++ /* write rcu_pending before calling the RCU callback */ ++ smp_wmb(); ++#ifdef CONFIG_PREEMPT_RCU ++ synchronize_sched(); /* Until we have the call_rcu_sched() */ ++#endif ++ call_rcu(&entry->rcu, free_old_closure); + end: + mutex_unlock(&markers_mutex); + return ret; +@@ -346,171 +687,173 @@ EXPORT_SYMBOL_GPL(marker_probe_register) + /** + * marker_probe_unregister - Disconnect a probe from a marker + * @name: marker name ++ * @probe: probe function pointer ++ * @probe_private: probe private data + * + * Returns the private data given to marker_probe_register, or an ERR_PTR(). ++ * We do not need to call a synchronize_sched to make sure the probes have ++ * finished running before doing a module unload, because the module unload ++ * itself uses stop_machine(), which insures that every preempt disabled section ++ * have finished. + */ +-void *marker_probe_unregister(const char *name) ++int marker_probe_unregister(const char *name, ++ marker_probe_func *probe, void *probe_private) + { +- struct module *probe_module; + struct marker_entry *entry; +- void *private; ++ struct marker_probe_closure *old; ++ int ret = -ENOENT; + + mutex_lock(&markers_mutex); + entry = get_marker(name); +- if (!entry) { +- private = ERR_PTR(-ENOENT); ++ if (!entry) + goto end; +- } +- entry->refcount = 0; +- /* In what module is the probe handler ? */ +- probe_module = __module_text_address((unsigned long)entry->probe); +- private = remove_marker(name); +- deferred_sync = 1; ++ if (entry->rcu_pending) ++ rcu_barrier(); ++ old = marker_entry_remove_probe(entry, probe, probe_private); + mutex_unlock(&markers_mutex); +- marker_update_probes(probe_module); +- return private; ++ marker_update_probes(); /* may update entry */ ++ mutex_lock(&markers_mutex); ++ entry = get_marker(name); ++ if (!entry) ++ goto end; ++ entry->oldptr = old; ++ entry->rcu_pending = 1; ++ /* write rcu_pending before calling the RCU callback */ ++ smp_wmb(); ++#ifdef CONFIG_PREEMPT_RCU ++ synchronize_sched(); /* Until we have the call_rcu_sched() */ ++#endif ++ call_rcu(&entry->rcu, free_old_closure); ++ remove_marker(name); /* Ignore busy error message */ ++ ret = 0; + end: + mutex_unlock(&markers_mutex); +- return private; ++ return ret; + } + EXPORT_SYMBOL_GPL(marker_probe_unregister); + +-/** +- * marker_probe_unregister_private_data - Disconnect a probe from a marker +- * @private: probe private data +- * +- * Unregister a marker by providing the registered private data. +- * Returns the private data given to marker_probe_register, or an ERR_PTR(). +- */ +-void *marker_probe_unregister_private_data(void *private) ++static struct marker_entry * ++get_marker_from_private_data(marker_probe_func *probe, void *probe_private) + { +- struct module *probe_module; +- struct hlist_head *head; +- struct hlist_node *node; + struct marker_entry *entry; +- int found = 0; + unsigned int i; ++ struct hlist_head *head; ++ struct hlist_node *node; + +- mutex_lock(&markers_mutex); + for (i = 0; i < MARKER_TABLE_SIZE; i++) { + head = &marker_table[i]; + hlist_for_each_entry(entry, node, head, hlist) { +- if (entry->private == private) { +- found = 1; +- goto iter_end; ++ if (!entry->ptype) { ++ if (entry->single.func == probe ++ && entry->single.probe_private ++ == probe_private) ++ return entry; ++ } else { ++ struct marker_probe_closure *closure; ++ closure = entry->multi; ++ for (i = 0; closure[i].func; i++) { ++ if (closure[i].func == probe && ++ closure[i].probe_private ++ == probe_private) ++ return entry; ++ } + } + } + } +-iter_end: +- if (!found) { +- private = ERR_PTR(-ENOENT); +- goto end; +- } +- entry->refcount = 0; +- /* In what module is the probe handler ? */ +- probe_module = __module_text_address((unsigned long)entry->probe); +- private = remove_marker(entry->name); +- deferred_sync = 1; +- mutex_unlock(&markers_mutex); +- marker_update_probes(probe_module); +- return private; +-end: +- mutex_unlock(&markers_mutex); +- return private; ++ return NULL; + } +-EXPORT_SYMBOL_GPL(marker_probe_unregister_private_data); + + /** +- * marker_arm - Arm a marker +- * @name: marker name ++ * marker_probe_unregister_private_data - Disconnect a probe from a marker ++ * @probe: probe function ++ * @probe_private: probe private data + * +- * Activate a marker. It keeps a reference count of the number of +- * arming/disarming done. +- * Returns 0 if ok, error value on error. ++ * Unregister a probe by providing the registered private data. ++ * Only removes the first marker found in hash table. ++ * Return 0 on success or error value. ++ * We do not need to call a synchronize_sched to make sure the probes have ++ * finished running before doing a module unload, because the module unload ++ * itself uses stop_machine(), which insures that every preempt disabled section ++ * have finished. + */ +-int marker_arm(const char *name) ++int marker_probe_unregister_private_data(marker_probe_func *probe, ++ void *probe_private) + { + struct marker_entry *entry; + int ret = 0; ++ struct marker_probe_closure *old; + + mutex_lock(&markers_mutex); +- entry = get_marker(name); ++ entry = get_marker_from_private_data(probe, probe_private); + if (!entry) { + ret = -ENOENT; + goto end; + } +- /* +- * Only need to update probes when refcount passes from 0 to 1. +- */ +- if (entry->refcount++) +- goto end; +-end: ++ if (entry->rcu_pending) ++ rcu_barrier(); ++ old = marker_entry_remove_probe(entry, NULL, probe_private); + mutex_unlock(&markers_mutex); +- marker_update_probes(NULL); +- return ret; +-} +-EXPORT_SYMBOL_GPL(marker_arm); +- +-/** +- * marker_disarm - Disarm a marker +- * @name: marker name +- * +- * Disarm a marker. It keeps a reference count of the number of arming/disarming +- * done. +- * Returns 0 if ok, error value on error. +- */ +-int marker_disarm(const char *name) +-{ +- struct marker_entry *entry; +- int ret = 0; +- ++ marker_update_probes(); /* may update entry */ + mutex_lock(&markers_mutex); +- entry = get_marker(name); +- if (!entry) { +- ret = -ENOENT; +- goto end; +- } +- /* +- * Only permit decrement refcount if higher than 0. +- * Do probe update only on 1 -> 0 transition. +- */ +- if (entry->refcount) { +- if (--entry->refcount) +- goto end; +- } else { +- ret = -EPERM; +- goto end; +- } ++ entry = get_marker_from_private_data(probe, probe_private); ++ WARN_ON(!entry); ++ entry->oldptr = old; ++ entry->rcu_pending = 1; ++ /* write rcu_pending before calling the RCU callback */ ++ smp_wmb(); ++#ifdef CONFIG_PREEMPT_RCU ++ synchronize_sched(); /* Until we have the call_rcu_sched() */ ++#endif ++ call_rcu(&entry->rcu, free_old_closure); ++ remove_marker(entry->name); /* Ignore busy error message */ + end: + mutex_unlock(&markers_mutex); +- marker_update_probes(NULL); + return ret; + } +-EXPORT_SYMBOL_GPL(marker_disarm); ++EXPORT_SYMBOL_GPL(marker_probe_unregister_private_data); + + /** + * marker_get_private_data - Get a marker's probe private data + * @name: marker name ++ * @probe: probe to match ++ * @num: get the nth matching probe's private data + * ++ * Returns the nth private data pointer (starting from 0) matching, or an ++ * ERR_PTR. + * Returns the private data pointer, or an ERR_PTR. + * The private data pointer should _only_ be dereferenced if the caller is the + * owner of the data, or its content could vanish. This is mostly used to + * confirm that a caller is the owner of a registered probe. + */ +-void *marker_get_private_data(const char *name) ++void *marker_get_private_data(const char *name, marker_probe_func *probe, ++ int num) + { + struct hlist_head *head; + struct hlist_node *node; + struct marker_entry *e; + size_t name_len = strlen(name) + 1; + u32 hash = jhash(name, name_len-1, 0); +- int found = 0; ++ int i; + + head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)]; + hlist_for_each_entry(e, node, head, hlist) { + if (!strcmp(name, e->name)) { +- found = 1; +- return e->private; ++ if (!e->ptype) { ++ if (num == 0 && e->single.func == probe) ++ return e->single.probe_private; ++ else ++ break; ++ } else { ++ struct marker_probe_closure *closure; ++ int match = 0; ++ closure = e->multi; ++ for (i = 0; closure[i].func; i++) { ++ if (closure[i].func != probe) ++ continue; ++ if (match++ == num) ++ return closure[i].probe_private; ++ } ++ } + } + } + return ERR_PTR(-ENOENT); +Index: linux-2.6.24.7-rt27/kernel/module.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/module.c 2009-02-08 00:00:27.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/module.c 2009-02-08 00:01:09.000000000 -0500 +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -46,6 +47,8 @@ + #include + #include + #include ++#include ++#include + + extern int module_sysfs_initialized; + +@@ -1675,6 +1678,8 @@ static struct module *load_module(void _ + unsigned int unusedcrcindex; + unsigned int unusedgplindex; + unsigned int unusedgplcrcindex; ++ unsigned int immediateindex; ++ unsigned int immediatecondendindex; + unsigned int markersindex; + unsigned int markersstringsindex; + struct module *mod; +@@ -1773,6 +1778,9 @@ static struct module *load_module(void _ + #ifdef ARCH_UNWIND_SECTION_NAME + unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME); + #endif ++ immediateindex = find_sec(hdr, sechdrs, secstrings, "__imv"); ++ immediatecondendindex = find_sec(hdr, sechdrs, secstrings, ++ "__imv_cond_end"); + + /* Don't keep modinfo section */ + sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; +@@ -1924,6 +1932,16 @@ static struct module *load_module(void _ + mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; + if (gplfuturecrcindex) + mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; ++#ifdef CONFIG_IMMEDIATE ++ mod->immediate = (void *)sechdrs[immediateindex].sh_addr; ++ mod->num_immediate = ++ sechdrs[immediateindex].sh_size / sizeof(*mod->immediate); ++ mod->immediate_cond_end = ++ (void *)sechdrs[immediatecondendindex].sh_addr; ++ mod->num_immediate_cond_end = ++ sechdrs[immediatecondendindex].sh_size ++ / sizeof(*mod->immediate_cond_end); ++#endif + + mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr; + if (unusedcrcindex) +@@ -1991,11 +2009,17 @@ static struct module *load_module(void _ + + add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); + ++ if (!(mod->taints & TAINT_FORCED_MODULE)) { + #ifdef CONFIG_MARKERS +- if (!mod->taints) + marker_update_probe_range(mod->markers, +- mod->markers + mod->num_markers, NULL, NULL); ++ mod->markers + mod->num_markers); ++#endif ++#ifdef CONFIG_IMMEDIATE ++ /* Immediate values must be updated after markers */ ++ imv_update_range(mod->immediate, ++ mod->immediate + mod->num_immediate); + #endif ++ } + err = module_finalize(hdr, sechdrs, mod); + if (err < 0) + goto cleanup; +@@ -2142,6 +2166,10 @@ sys_init_module(void __user *umod, + /* Drop initial reference. */ + module_put(mod); + unwind_remove_table(mod->unwind_info, 1); ++#ifdef CONFIG_IMMEDIATE ++ imv_unref(mod->immediate, mod->immediate + mod->num_immediate, ++ mod->module_init, mod->init_size); ++#endif + module_free(mod, mod->module_init); + mod->module_init = NULL; + mod->init_size = 0; +@@ -2596,7 +2624,7 @@ EXPORT_SYMBOL(struct_module); + #endif + + #ifdef CONFIG_MARKERS +-void module_update_markers(struct module *probe_module, int *refcount) ++void module_update_markers(void) + { + struct module *mod; + +@@ -2604,8 +2632,61 @@ void module_update_markers(struct module + list_for_each_entry(mod, &modules, list) + if (!mod->taints) + marker_update_probe_range(mod->markers, +- mod->markers + mod->num_markers, +- probe_module, refcount); ++ mod->markers + mod->num_markers); + mutex_unlock(&module_mutex); + } + #endif ++ ++#ifdef CONFIG_IMMEDIATE ++/** ++ * _module_imv_update - update all immediate values in the kernel ++ * ++ * Iterate on the kernel core and modules to update the immediate values. ++ * Module_mutex must be held be the caller. ++ */ ++void _module_imv_update(void) ++{ ++ struct module *mod; ++ ++ list_for_each_entry(mod, &modules, list) { ++ if (mod->taints) ++ continue; ++ imv_update_range(mod->immediate, ++ mod->immediate + mod->num_immediate); ++ } ++} ++EXPORT_SYMBOL_GPL(_module_imv_update); ++ ++/** ++ * module_imv_update - update all immediate values in the kernel ++ * ++ * Iterate on the kernel core and modules to update the immediate values. ++ * Takes module_mutex. ++ */ ++void module_imv_update(void) ++{ ++ mutex_lock(&module_mutex); ++ _module_imv_update(); ++ mutex_unlock(&module_mutex); ++} ++EXPORT_SYMBOL_GPL(module_imv_update); ++ ++/** ++ * is_imv_cond_end_module ++ * ++ * Check if the two given addresses are located in the immediate value condition ++ * end table. Addresses should be in the same object. ++ * The module mutex should be held. ++ */ ++int is_imv_cond_end_module(unsigned long addr1, unsigned long addr2) ++{ ++ struct module *mod = __module_text_address(addr1); ++ ++ if (!mod) ++ return 0; ++ ++ return _is_imv_cond_end(mod->immediate_cond_end, ++ mod->immediate_cond_end + mod->num_immediate_cond_end, ++ addr1, addr2); ++} ++#endif --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0390-rt-sched-groups.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0390-rt-sched-groups.patch @@ -0,0 +1,17 @@ +--- + kernel/cgroup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/cgroup.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/cgroup.c 2009-02-07 23:59:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/cgroup.c 2009-02-08 00:03:56.000000000 -0500 +@@ -168,7 +168,7 @@ list_for_each_entry(_root, &roots, root_ + /* the list of cgroups eligible for automatic release. Protected by + * release_list_lock */ + static LIST_HEAD(release_list); +-static DEFINE_SPINLOCK(release_list_lock); ++static DEFINE_RAW_SPINLOCK(release_list_lock); + static void cgroup_release_agent(struct work_struct *work); + static DECLARE_WORK(release_agent_work, cgroup_release_agent); + static void check_for_release(struct cgroup *cgrp); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0100-write-try-lock-irqsave.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0100-write-try-lock-irqsave.patch @@ -0,0 +1,22 @@ +--- + include/linux/spinlock.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +Index: linux-2.6.24.7-rt27/include/linux/spinlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/spinlock.h 2009-02-08 00:00:21.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/spinlock.h 2009-02-08 00:01:30.000000000 -0500 +@@ -289,6 +289,13 @@ do { \ + 1 : ({ local_irq_restore(flags); 0; }); \ + }) + ++#define write_trylock_irqsave(lock, flags) \ ++({ \ ++ local_irq_save(flags); \ ++ write_trylock(lock) ? \ ++ 1 : ({ local_irq_restore(flags); 0; }); \ ++}) ++ + /* + * Locks two spinlocks l1 and l2. + * l1_first indicates if spinlock l1 should be taken first. --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0292-radix-tree-concurrent.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0292-radix-tree-concurrent.patch @@ -0,0 +1,699 @@ +Subject: radix-tree: concurrent write side support + +Provide support for concurrent write side operations without changing the API +for all current uses. + +Concurrency is realized by means of two locking models; the simple one is +ladder locking, the more complex one is path locking. + +Ladder locking is like walking down a ladder, you place your foot on a spoke +below the one your other foot finds support etc.. There is no walking with both +feet in the air. Likewise with walking a tree, you lock a node below the +current node before releasing it. + +This allows other modifying operations to start as soon as you release the +lock on the root node and even complete before you if they walk another path +downward. + +The modifying operations: insert, lookup_slot and set_tag, use this simple +method. + +The more complex path locking method is needed for operations that need to +walk upwards again after they walked down, those are: tag_clear and delete. + +These lock their whole path downwards and release whole sections at points +where it can be determined the walk upwards will stop, thus also allowing +concurrency. + +Finding the conditions for the terminated walk upwards while doing the downward +walk is the 'interesting' part of this approach. + +The remaining - unmodified - operations will have exclusive locking (since +they're unmodified, they never move the lock downwards from the root node). + +The API for this looks like: + + DEFINE_RADIX_TREE_CONTEXT(ctx, &mapping->page_tree) + + radix_tree_lock(&ctx) + ... do _1_ modifying operation ... + radix_tree_unlock(&ctx) + +Note that before the radix operation the root node is held and will provide +exclusive locking, after the operation the held lock might only be enough to +protect a single item. + +Signed-off-by: Peter Zijlstra +--- + include/linux/radix-tree.h | 77 +++++++++++- + init/Kconfig | 4 + lib/radix-tree.c | 283 ++++++++++++++++++++++++++++++++++++--------- + 3 files changed, 302 insertions(+), 62 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/radix-tree.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/radix-tree.h 2009-02-08 00:03:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/radix-tree.h 2009-02-08 00:03:06.000000000 -0500 +@@ -62,23 +62,65 @@ struct radix_tree_root { + unsigned int height; + gfp_t gfp_mask; + struct radix_tree_node *rnode; ++ spinlock_t lock; + }; + + #define RADIX_TREE_INIT(mask) { \ + .height = 0, \ + .gfp_mask = (mask), \ + .rnode = NULL, \ ++ .lock = __SPIN_LOCK_UNLOCKED(radix_tree_root.lock), \ + } + + #define RADIX_TREE(name, mask) \ + struct radix_tree_root name = RADIX_TREE_INIT(mask) + +-#define INIT_RADIX_TREE(root, mask) \ +-do { \ +- (root)->height = 0; \ +- (root)->gfp_mask = (mask); \ +- (root)->rnode = NULL; \ +-} while (0) ++static inline void INIT_RADIX_TREE(struct radix_tree_root *root, gfp_t gfp_mask) ++{ ++ root->height = 0; ++ root->gfp_mask = gfp_mask; ++ root->rnode = NULL; ++ spin_lock_init(&root->lock); ++} ++ ++struct radix_tree_context { ++ struct radix_tree_root *tree; ++ struct radix_tree_root *root; ++#ifdef CONFIG_RADIX_TREE_CONCURRENT ++ spinlock_t *locked; ++#endif ++}; ++ ++#ifdef CONFIG_RADIX_TREE_CONCURRENT ++#define RADIX_CONTEXT_ROOT(context) \ ++ ((struct radix_tree_root *)(((unsigned long)context) + 1)) ++ ++#define __RADIX_TREE_CONTEXT_INIT(context, _tree) \ ++ .tree = RADIX_CONTEXT_ROOT(&context), \ ++ .locked = NULL, ++#else ++#define __RADIX_TREE_CONTEXT_INIT(context, _tree) \ ++ .tree = (_tree), ++#endif ++ ++#define DEFINE_RADIX_TREE_CONTEXT(context, _tree) \ ++ struct radix_tree_context context = { \ ++ .root = (_tree), \ ++ __RADIX_TREE_CONTEXT_INIT(context, _tree) \ ++ } ++ ++static inline void ++init_radix_tree_context(struct radix_tree_context *ctx, ++ struct radix_tree_root *root) ++{ ++ ctx->root = root; ++#ifdef CONFIG_RADIX_TREE_CONCURRENT ++ ctx->tree = RADIX_CONTEXT_ROOT(ctx); ++ ctx->locked = NULL; ++#else ++ ctx->tree = root; ++#endif ++} + + /** + * Radix-tree synchronization +@@ -155,6 +197,29 @@ static inline void radix_tree_replace_sl + rcu_assign_pointer(*pslot, item); + } + ++static inline void radix_tree_lock(struct radix_tree_context *context) ++{ ++ struct radix_tree_root *root = context->root; ++ rcu_read_lock(); ++ spin_lock(&root->lock); ++#ifdef CONFIG_RADIX_TREE_CONCURRENT ++ BUG_ON(context->locked); ++ context->locked = &root->lock; ++#endif ++} ++ ++static inline void radix_tree_unlock(struct radix_tree_context *context) ++{ ++#ifdef CONFIG_RADIX_TREE_CONCURRENT ++ BUG_ON(!context->locked); ++ spin_unlock(context->locked); ++ context->locked = NULL; ++#else ++ spin_unlock(&context->root->lock); ++#endif ++ rcu_read_unlock(); ++} ++ + int radix_tree_insert(struct radix_tree_root *, unsigned long, void *); + void *radix_tree_lookup(struct radix_tree_root *, unsigned long); + void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long); +Index: linux-2.6.24.7-rt27/init/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/init/Kconfig 2009-02-07 23:59:53.000000000 -0500 ++++ linux-2.6.24.7-rt27/init/Kconfig 2009-02-08 00:03:06.000000000 -0500 +@@ -435,6 +435,10 @@ config CC_OPTIMIZE_FOR_SIZE + config SYSCTL + bool + ++config RADIX_TREE_CONCURRENT ++ bool "Enable concurrent radix tree operations (EXPERIMENTAL)" ++ default y if SMP ++ + menuconfig EMBEDDED + bool "Configure standard kernel features (for small systems)" + help +Index: linux-2.6.24.7-rt27/lib/radix-tree.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/lib/radix-tree.c 2009-02-08 00:03:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/lib/radix-tree.c 2009-02-08 00:03:06.000000000 -0500 +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + + #ifdef __KERNEL__ +@@ -52,11 +53,17 @@ struct radix_tree_node { + struct rcu_head rcu_head; + void *slots[RADIX_TREE_MAP_SIZE]; + unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; ++#ifdef CONFIG_RADIX_TREE_CONCURRENT ++ spinlock_t lock; ++#endif + }; + + struct radix_tree_path { + struct radix_tree_node *node; + int offset; ++#ifdef CONFIG_RADIX_TREE_CONCURRENT ++ spinlock_t *locked; ++#endif + }; + + #define RADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long)) +@@ -69,6 +76,10 @@ struct radix_tree_path { + */ + static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH + 1] __read_mostly; + ++#ifdef CONFIG_RADIX_TREE_CONCURRENT ++static struct lock_class_key radix_node_class[RADIX_TREE_MAX_PATH]; ++#endif ++ + /* + * Radix tree node cache. + */ +@@ -93,7 +104,7 @@ static inline gfp_t root_gfp_mask(struct + * that the caller has pinned this thread of control to the current CPU. + */ + static struct radix_tree_node * +-radix_tree_node_alloc(struct radix_tree_root *root) ++radix_tree_node_alloc(struct radix_tree_root *root, int height) + { + struct radix_tree_node *ret; + gfp_t gfp_mask = root_gfp_mask(root); +@@ -112,6 +123,11 @@ radix_tree_node_alloc(struct radix_tree_ + put_cpu_var(radix_tree_preloads); + } + BUG_ON(radix_tree_is_indirect_ptr(ret)); ++#ifdef CONFIG_RADIX_TREE_CONCURRENT ++ spin_lock_init(&ret->lock); ++ lockdep_set_class(&ret->lock, &radix_node_class[height]); ++#endif ++ ret->height = height; + return ret; + } + +@@ -218,6 +234,22 @@ static inline int any_tag_set(struct rad + return 0; + } + ++static inline int any_tag_set_but(struct radix_tree_node *node, ++ unsigned int tag, int offset) ++{ ++ int idx; ++ int offset_idx = offset / BITS_PER_LONG; ++ unsigned long offset_mask = ~(1UL << (offset % BITS_PER_LONG)); ++ for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { ++ unsigned long mask = ~0UL; ++ if (idx == offset_idx) ++ mask = offset_mask; ++ if (node->tags[tag][idx] & mask) ++ return 1; ++ } ++ return 0; ++} ++ + /* + * Return the maximum key which can be store into a + * radix tree with height HEIGHT. +@@ -247,8 +279,8 @@ static int radix_tree_extend(struct radi + } + + do { +- unsigned int newheight; +- if (!(node = radix_tree_node_alloc(root))) ++ unsigned int newheight = root->height + 1; ++ if (!(node = radix_tree_node_alloc(root, newheight))) + return -ENOMEM; + + /* Increase the height. */ +@@ -260,8 +292,6 @@ static int radix_tree_extend(struct radi + tag_set(node, tag, 0); + } + +- newheight = root->height+1; +- node->height = newheight; + node->count = 1; + node = radix_tree_ptr_to_indirect(node); + rcu_assign_pointer(root->rnode, node); +@@ -271,6 +301,80 @@ out: + return 0; + } + ++#ifdef CONFIG_RADIX_TREE_CONCURRENT ++static inline struct radix_tree_context * ++radix_tree_get_context(struct radix_tree_root **rootp) ++{ ++ struct radix_tree_context *context = NULL; ++ unsigned long addr = (unsigned long)*rootp; ++ ++ if (addr & 1) { ++ context = (struct radix_tree_context *)(addr - 1); ++ *rootp = context->root; ++ } ++ ++ return context; ++} ++ ++#define RADIX_TREE_CONTEXT(context, root) \ ++ struct radix_tree_context *context = \ ++ radix_tree_get_context(&root) ++ ++static inline spinlock_t *radix_node_lock(struct radix_tree_root *root, ++ struct radix_tree_node *node) ++{ ++ spinlock_t *locked = &node->lock; ++ spin_lock(locked); ++ return locked; ++} ++ ++static inline void radix_ladder_lock(struct radix_tree_context *context, ++ struct radix_tree_node *node) ++{ ++ if (context) { ++ struct radix_tree_root *root = context->root; ++ spinlock_t *locked = radix_node_lock(root, node); ++ if (locked) { ++ spin_unlock(context->locked); ++ context->locked = locked; ++ } ++ } ++} ++ ++static inline void radix_path_init(struct radix_tree_context *context, ++ struct radix_tree_path *pathp) ++{ ++ pathp->locked = context ? context->locked : NULL; ++} ++ ++static inline void radix_path_lock(struct radix_tree_context *context, ++ struct radix_tree_path *pathp, struct radix_tree_node *node) ++{ ++ if (context) { ++ struct radix_tree_root *root = context->root; ++ spinlock_t *locked = radix_node_lock(root, node); ++ if (locked) ++ context->locked = locked; ++ pathp->locked = locked; ++ } else ++ pathp->locked = NULL; ++} ++ ++static inline void radix_path_unlock(struct radix_tree_context *context, ++ struct radix_tree_path *punlock) ++{ ++ if (context && punlock->locked && ++ context->locked != punlock->locked) ++ spin_unlock(punlock->locked); ++} ++#else ++#define RADIX_TREE_CONTEXT(context, root) do { } while (0) ++#define radix_ladder_lock(context, node) do { } while (0) ++#define radix_path_init(context, pathp) do { } while (0) ++#define radix_path_lock(context, pathp, node) do { } while (0) ++#define radix_path_unlock(context, punlock) do { } while (0) ++#endif ++ + /** + * radix_tree_insert - insert into a radix tree + * @root: radix tree root +@@ -286,6 +390,8 @@ int radix_tree_insert(struct radix_tree_ + unsigned int height, shift; + int offset; + int error; ++ int tag; ++ RADIX_TREE_CONTEXT(context, root); + + BUG_ON(radix_tree_is_indirect_ptr(item)); + +@@ -305,9 +411,8 @@ int radix_tree_insert(struct radix_tree_ + while (height > 0) { + if (slot == NULL) { + /* Have to add a child node. */ +- if (!(slot = radix_tree_node_alloc(root))) ++ if (!(slot = radix_tree_node_alloc(root, height))) + return -ENOMEM; +- slot->height = height; + if (node) { + rcu_assign_pointer(node->slots[offset], slot); + node->count++; +@@ -319,6 +424,9 @@ int radix_tree_insert(struct radix_tree_ + /* Go a level down */ + offset = (index >> shift) & RADIX_TREE_MAP_MASK; + node = slot; ++ ++ radix_ladder_lock(context, node); ++ + slot = node->slots[offset]; + shift -= RADIX_TREE_MAP_SHIFT; + height--; +@@ -330,12 +438,12 @@ int radix_tree_insert(struct radix_tree_ + if (node) { + node->count++; + rcu_assign_pointer(node->slots[offset], item); +- BUG_ON(tag_get(node, 0, offset)); +- BUG_ON(tag_get(node, 1, offset)); ++ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) ++ BUG_ON(tag_get(node, tag, offset)); + } else { + rcu_assign_pointer(root->rnode, item); +- BUG_ON(root_tag_get(root, 0)); +- BUG_ON(root_tag_get(root, 1)); ++ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) ++ BUG_ON(root_tag_get(root, tag)); + } + + return 0; +@@ -359,6 +467,7 @@ void **radix_tree_lookup_slot(struct rad + { + unsigned int height, shift; + struct radix_tree_node *node, **slot; ++ RADIX_TREE_CONTEXT(context, root); + + node = rcu_dereference(root->rnode); + if (node == NULL) +@@ -384,6 +493,8 @@ void **radix_tree_lookup_slot(struct rad + if (node == NULL) + return NULL; + ++ radix_ladder_lock(context, node); ++ + shift -= RADIX_TREE_MAP_SHIFT; + height--; + } while (height > 0); +@@ -459,6 +570,7 @@ void *radix_tree_tag_set(struct radix_tr + { + unsigned int height, shift; + struct radix_tree_node *slot; ++ RADIX_TREE_CONTEXT(context, root); + + height = root->height; + BUG_ON(index > radix_tree_maxindex(height)); +@@ -466,9 +578,15 @@ void *radix_tree_tag_set(struct radix_tr + slot = radix_tree_indirect_to_ptr(root->rnode); + shift = (height - 1) * RADIX_TREE_MAP_SHIFT; + ++ /* set the root's tag bit */ ++ if (slot && !root_tag_get(root, tag)) ++ root_tag_set(root, tag); ++ + while (height > 0) { + int offset; + ++ radix_ladder_lock(context, slot); ++ + offset = (index >> shift) & RADIX_TREE_MAP_MASK; + if (!tag_get(slot, tag, offset)) + tag_set(slot, tag, offset); +@@ -478,14 +596,24 @@ void *radix_tree_tag_set(struct radix_tr + height--; + } + +- /* set the root's tag bit */ +- if (slot && !root_tag_get(root, tag)) +- root_tag_set(root, tag); +- + return slot; + } + EXPORT_SYMBOL(radix_tree_tag_set); + ++/* ++ * the change can never propagate upwards from here. ++ */ ++static inline int radix_tree_unlock_tag(struct radix_tree_root *root, ++ struct radix_tree_path *pathp, int tag) ++{ ++ int this, other; ++ ++ this = tag_get(pathp->node, tag, pathp->offset); ++ other = any_tag_set_but(pathp->node, tag, pathp->offset); ++ ++ return !this || other; ++} ++ + /** + * radix_tree_tag_clear - clear a tag on a radix tree node + * @root: radix tree root +@@ -508,15 +636,19 @@ void *radix_tree_tag_clear(struct radix_ + * since the "list" is null terminated. + */ + struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path; ++ struct radix_tree_path *punlock = path, *piter; + struct radix_tree_node *slot = NULL; + unsigned int height, shift; ++ RADIX_TREE_CONTEXT(context, root); ++ ++ pathp->node = NULL; ++ radix_path_init(context, pathp); + + height = root->height; + if (index > radix_tree_maxindex(height)) + goto out; + + shift = (height - 1) * RADIX_TREE_MAP_SHIFT; +- pathp->node = NULL; + slot = radix_tree_indirect_to_ptr(root->rnode); + + while (height > 0) { +@@ -526,10 +658,17 @@ void *radix_tree_tag_clear(struct radix_ + goto out; + + offset = (index >> shift) & RADIX_TREE_MAP_MASK; +- pathp[1].offset = offset; +- pathp[1].node = slot; +- slot = slot->slots[offset]; + pathp++; ++ pathp->offset = offset; ++ pathp->node = slot; ++ radix_path_lock(context, pathp, slot); ++ ++ if (radix_tree_unlock_tag(root, pathp, tag)) { ++ for (; punlock < pathp; punlock++) ++ radix_path_unlock(context, punlock); ++ } ++ ++ slot = slot->slots[offset]; + shift -= RADIX_TREE_MAP_SHIFT; + height--; + } +@@ -537,20 +676,22 @@ void *radix_tree_tag_clear(struct radix_ + if (slot == NULL) + goto out; + +- while (pathp->node) { +- if (!tag_get(pathp->node, tag, pathp->offset)) +- goto out; +- tag_clear(pathp->node, tag, pathp->offset); +- if (any_tag_set(pathp->node, tag)) +- goto out; +- pathp--; ++ for (piter = pathp; piter >= punlock; piter--) { ++ if (piter->node) { ++ if (!tag_get(piter->node, tag, piter->offset)) ++ break; ++ tag_clear(piter->node, tag, piter->offset); ++ if (any_tag_set(piter->node, tag)) ++ break; ++ } else { ++ if (root_tag_get(root, tag)) ++ root_tag_clear(root, tag); ++ } + } + +- /* clear the root's tag bit */ +- if (root_tag_get(root, tag)) +- root_tag_clear(root, tag); +- + out: ++ for (; punlock < pathp; punlock++) ++ radix_path_unlock(context, punlock); + return slot; + } + EXPORT_SYMBOL(radix_tree_tag_clear); +@@ -1039,6 +1180,7 @@ static inline void radix_tree_shrink(str + while (root->height > 0) { + struct radix_tree_node *to_free = root->rnode; + void *newptr; ++ int tag; + + BUG_ON(!radix_tree_is_indirect_ptr(to_free)); + to_free = radix_tree_indirect_to_ptr(to_free); +@@ -1065,14 +1207,29 @@ static inline void radix_tree_shrink(str + root->rnode = newptr; + root->height--; + /* must only free zeroed nodes into the slab */ +- tag_clear(to_free, 0, 0); +- tag_clear(to_free, 1, 0); ++ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) ++ tag_clear(to_free, tag, 0); + to_free->slots[0] = NULL; + to_free->count = 0; +- radix_tree_node_free(to_free); + } + } + ++static inline int radix_tree_unlock_all(struct radix_tree_root *root, ++ struct radix_tree_path *pathp) ++{ ++ int tag; ++ int unlock = 1; ++ ++ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { ++ if (!radix_tree_unlock_tag(root, pathp, tag)) { ++ unlock = 0; ++ break; ++ } ++ } ++ ++ return unlock; ++} ++ + /** + * radix_tree_delete - delete an item from a radix tree + * @root: radix tree root +@@ -1089,11 +1246,15 @@ void *radix_tree_delete(struct radix_tre + * since the "list" is null terminated. + */ + struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path; ++ struct radix_tree_path *punlock = path, *piter; + struct radix_tree_node *slot = NULL; +- struct radix_tree_node *to_free; + unsigned int height, shift; + int tag; + int offset; ++ RADIX_TREE_CONTEXT(context, root); ++ ++ pathp->node = NULL; ++ radix_path_init(context, pathp); + + height = root->height; + if (index > radix_tree_maxindex(height)) +@@ -1108,7 +1269,6 @@ void *radix_tree_delete(struct radix_tre + slot = radix_tree_indirect_to_ptr(slot); + + shift = (height - 1) * RADIX_TREE_MAP_SHIFT; +- pathp->node = NULL; + + do { + if (slot == NULL) +@@ -1118,6 +1278,13 @@ void *radix_tree_delete(struct radix_tre + offset = (index >> shift) & RADIX_TREE_MAP_MASK; + pathp->offset = offset; + pathp->node = slot; ++ radix_path_lock(context, pathp, slot); ++ ++ if (slot->count > 2 && radix_tree_unlock_all(root, pathp)) { ++ for (; punlock < pathp; punlock++) ++ radix_path_unlock(context, punlock); ++ } ++ + slot = slot->slots[offset]; + shift -= RADIX_TREE_MAP_SHIFT; + height--; +@@ -1130,41 +1297,45 @@ void *radix_tree_delete(struct radix_tre + * Clear all tags associated with the just-deleted item + */ + for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { +- if (tag_get(pathp->node, tag, pathp->offset)) +- radix_tree_tag_clear(root, index, tag); ++ for (piter = pathp; piter >= punlock; piter--) { ++ if (piter->node) { ++ if (!tag_get(piter->node, tag, piter->offset)) ++ break; ++ tag_clear(piter->node, tag, piter->offset); ++ if (any_tag_set(piter->node, tag)) ++ break; ++ } else { ++ if (root_tag_get(root, tag)) ++ root_tag_clear(root, tag); ++ } ++ } + } + +- to_free = NULL; +- /* Now free the nodes we do not need anymore */ +- while (pathp->node) { +- pathp->node->slots[pathp->offset] = NULL; +- pathp->node->count--; +- /* +- * Queue the node for deferred freeing after the +- * last reference to it disappears (set NULL, above). +- */ +- if (to_free) +- radix_tree_node_free(to_free); ++ /* Now unhook the nodes we do not need anymore */ ++ for (piter = pathp; piter >= punlock && piter->node; piter--) { ++ piter->node->slots[piter->offset] = NULL; ++ piter->node->count--; + +- if (pathp->node->count) { +- if (pathp->node == ++ if (piter->node->count) { ++ if (piter->node == + radix_tree_indirect_to_ptr(root->rnode)) + radix_tree_shrink(root); + goto out; + } ++ } + +- /* Node with zero slots in use so free it */ +- to_free = pathp->node; +- pathp--; ++ BUG_ON(piter->node); + +- } + root_tag_clear_all(root); + root->height = 0; + root->rnode = NULL; +- if (to_free) +- radix_tree_node_free(to_free); + + out: ++ for (; punlock <= pathp; punlock++) { ++ radix_path_unlock(context, punlock); ++ if (punlock->node && punlock->node->count == 0) ++ radix_tree_node_free(punlock->node); ++ } + return slot; + } + EXPORT_SYMBOL(radix_tree_delete); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0174-rt-mutex-ppc-fix-a5.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0174-rt-mutex-ppc-fix-a5.patch @@ -0,0 +1,74 @@ + + To fix the following compile error by changing names from +__{read,write}_trylock to ___raw_{read,write}_trylock in asm-powerpc/spinlock.h + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +include/asm-powerpc/spinlock.h +include/linux/spinlock_api_smp.h:49: error: conflicting types for '__read_trylock' +include/asm/spinlock.h:183: error: previous definition of '__read_trylock' was here +include/linux/spinlock_api_smp.h:50: error: conflicting types for '__write_trylock' +include/asm/spinlock.h:207: error: previous definition of '__write_trylock' was here +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +Signed-off-by: Tsutomu Owa +-- owa + +--- + include/asm-powerpc/spinlock.h | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/include/asm-powerpc/spinlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-powerpc/spinlock.h 2009-02-08 00:02:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-powerpc/spinlock.h 2009-02-08 00:02:05.000000000 -0500 +@@ -179,7 +179,7 @@ extern void __raw_spin_unlock_wait(__raw + * This returns the old value in the lock + 1, + * so we got a read lock if the return value is > 0. + */ +-static long __inline__ __read_trylock(__raw_rwlock_t *rw) ++static long __inline__ ___raw_read_trylock(__raw_rwlock_t *rw) + { + long tmp; + +@@ -203,7 +203,7 @@ static long __inline__ __read_trylock(__ + * This returns the old value in the lock, + * so we got the write lock if the return value is 0. + */ +-static __inline__ long __write_trylock(__raw_rwlock_t *rw) ++static __inline__ long ___raw_write_trylock(__raw_rwlock_t *rw) + { + long tmp, token; + +@@ -226,7 +226,7 @@ static __inline__ long __write_trylock(_ + static void __inline__ __raw_read_lock(__raw_rwlock_t *rw) + { + while (1) { +- if (likely(__read_trylock(rw) > 0)) ++ if (likely(___raw_read_trylock(rw) > 0)) + break; + do { + HMT_low(); +@@ -240,7 +240,7 @@ static void __inline__ __raw_read_lock(_ + static void __inline__ __raw_write_lock(__raw_rwlock_t *rw) + { + while (1) { +- if (likely(__write_trylock(rw) == 0)) ++ if (likely(___raw_write_trylock(rw) == 0)) + break; + do { + HMT_low(); +@@ -253,12 +253,12 @@ static void __inline__ __raw_write_lock( + + static int __inline__ __raw_read_trylock(__raw_rwlock_t *rw) + { +- return __read_trylock(rw) > 0; ++ return ___raw_read_trylock(rw) > 0; + } + + static int __inline__ __raw_write_trylock(__raw_rwlock_t *rw) + { +- return __write_trylock(rw) == 0; ++ return ___raw_write_trylock(rw) == 0; + } + + static void __inline__ __raw_read_unlock(__raw_rwlock_t *rw) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0183-percpu-locked-netfilter.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0183-percpu-locked-netfilter.patch @@ -0,0 +1,130 @@ + net/core/flow.c | 22 ++++++++++++++-------- + net/ipv4/netfilter/arp_tables.c | 4 ++-- + net/ipv4/netfilter/ip_tables.c | 2 +- + 3 files changed, 17 insertions(+), 11 deletions(-) + +--- +Index: linux-2.6.24.7-rt27/net/core/flow.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/net/core/flow.c 2009-02-08 00:01:32.000000000 -0500 ++++ linux-2.6.24.7-rt27/net/core/flow.c 2009-02-08 00:02:10.000000000 -0500 +@@ -40,9 +40,10 @@ atomic_t flow_cache_genid = ATOMIC_INIT( + + static u32 flow_hash_shift; + #define flow_hash_size (1 << flow_hash_shift) +-static DEFINE_PER_CPU(struct flow_cache_entry **, flow_tables) = { NULL }; + +-#define flow_table(cpu) (per_cpu(flow_tables, cpu)) ++static DEFINE_PER_CPU_LOCKED(struct flow_cache_entry **, flow_tables); ++ ++#define flow_table(cpu) (per_cpu_var_locked(flow_tables, cpu)) + + static struct kmem_cache *flow_cachep __read_mostly; + +@@ -169,24 +170,24 @@ static int flow_key_compare(struct flowi + void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, + flow_resolve_t resolver) + { +- struct flow_cache_entry *fle, **head = NULL /* shut up GCC */; ++ struct flow_cache_entry **table, *fle, **head = NULL /* shut up GCC */; + unsigned int hash; + int cpu; + + local_bh_disable(); +- cpu = smp_processor_id(); ++ table = get_cpu_var_locked(flow_tables, &cpu); + + fle = NULL; + /* Packet really early in init? Making flow_cache_init a + * pre-smp initcall would solve this. --RR */ +- if (!flow_table(cpu)) ++ if (!table) + goto nocache; + + if (flow_hash_rnd_recalc(cpu)) + flow_new_hash_rnd(cpu); + hash = flow_hash_code(key, cpu); + +- head = &flow_table(cpu)[hash]; ++ head = &table[hash]; + for (fle = *head; fle; fle = fle->next) { + if (fle->family == family && + fle->dir == dir && +@@ -196,6 +197,7 @@ void *flow_cache_lookup(struct flowi *ke + + if (ret) + atomic_inc(fle->object_ref); ++ put_cpu_var_locked(flow_tables, cpu); + local_bh_enable(); + + return ret; +@@ -221,6 +223,8 @@ void *flow_cache_lookup(struct flowi *ke + } + + nocache: ++ put_cpu_var_locked(flow_tables, cpu); ++ + { + int err; + void *obj; +@@ -250,14 +254,15 @@ nocache: + static void flow_cache_flush_tasklet(unsigned long data) + { + struct flow_flush_info *info = (void *)data; ++ struct flow_cache_entry **table; + int i; + int cpu; + +- cpu = smp_processor_id(); ++ table = get_cpu_var_locked(flow_tables, &cpu); + for (i = 0; i < flow_hash_size; i++) { + struct flow_cache_entry *fle; + +- fle = flow_table(cpu)[i]; ++ fle = table[i]; + for (; fle; fle = fle->next) { + unsigned genid = atomic_read(&flow_cache_genid); + +@@ -268,6 +273,7 @@ static void flow_cache_flush_tasklet(uns + atomic_dec(fle->object_ref); + } + } ++ put_cpu_var_locked(flow_tables, cpu); + + if (atomic_dec_and_test(&info->cpuleft)) + complete(&info->completion); +Index: linux-2.6.24.7-rt27/net/ipv4/netfilter/arp_tables.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/net/ipv4/netfilter/arp_tables.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/net/ipv4/netfilter/arp_tables.c 2009-02-08 00:02:10.000000000 -0500 +@@ -241,7 +241,7 @@ unsigned int arpt_do_table(struct sk_buf + + read_lock_bh(&table->lock); + private = table->private; +- table_base = (void *)private->entries[smp_processor_id()]; ++ table_base = (void *)private->entries[raw_smp_processor_id()]; + e = get_entry(table_base, private->hook_entry[hook]); + back = get_entry(table_base, private->underflow[hook]); + +@@ -951,7 +951,7 @@ static int do_add_counters(void __user * + + i = 0; + /* Choose the copy that is on our node */ +- loc_cpu_entry = private->entries[smp_processor_id()]; ++ loc_cpu_entry = private->entries[raw_smp_processor_id()]; + ARPT_ENTRY_ITERATE(loc_cpu_entry, + private->size, + add_counter_to_entry, +Index: linux-2.6.24.7-rt27/net/ipv4/netfilter/ip_tables.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/net/ipv4/netfilter/ip_tables.c 2009-02-08 00:00:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/net/ipv4/netfilter/ip_tables.c 2009-02-08 00:02:10.000000000 -0500 +@@ -346,7 +346,7 @@ ipt_do_table(struct sk_buff *skb, + read_lock_bh(&table->lock); + IP_NF_ASSERT(table->valid_hooks & (1 << hook)); + private = table->private; +- table_base = (void *)private->entries[smp_processor_id()]; ++ table_base = (void *)private->entries[raw_smp_processor_id()]; + e = get_entry(table_base, private->hook_entry[hook]); + + /* For return from builtin chain */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0428-ppc-tlbflush-preempt.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0428-ppc-tlbflush-preempt.patch @@ -0,0 +1,102 @@ +From estarkov@ru.mvista.com Mon Mar 24 17:41:35 2008 +Date: Wed, 12 Mar 2008 18:37:42 +0300 +From: Egor Starkov +To: mingo@elte.hu +Subject: Memory corruption fixes +Resent-Date: Wed, 12 Mar 2008 17:06:59 +0100 +Resent-Date: Wed, 12 Mar 2008 12:10:04 -0400 +Resent-From: Ingo Molnar +Resent-To: Steven Rostedt + +Hi Ingo, + +I have found out that functions __flush_tlb_pending and hpte_need_flush +must be called from within some kind of spinlock/non-preempt region. Fix +"flush_hash_page_fix.patch" is attached. + +Also debug version of function add_preempt_count can be called +on early stage of boot when current is not set and is 0. +So we can have memory corruption. I had it as stack pointer +exception after "Freeing unused kernel memory" message. Fix +"preempt_debug_trace_fix.patch" is attached. + +Egor Starkov + + [ Part 2: "Attached Text" ] + +Signed-off-by: Egor Starkov +Description: + Functions __flush_tlb_pending and hpte_need_flush must + be called from within some kind of spinlock/non-preempt region + +--- + include/asm-powerpc/pgtable-ppc64.h | 9 ++++++++- + include/asm-powerpc/tlbflush.h | 20 ++++++++++++++++++-- + 2 files changed, 26 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/include/asm-powerpc/pgtable-ppc64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-powerpc/pgtable-ppc64.h 2009-02-07 23:59:43.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-powerpc/pgtable-ppc64.h 2009-02-08 00:04:14.000000000 -0500 +@@ -277,8 +277,15 @@ static inline unsigned long pte_update(s + : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY) + : "cc" ); + +- if (old & _PAGE_HASHPTE) ++ if (old & _PAGE_HASHPTE) { ++#ifdef CONFIG_PREEMPT_RT ++ preempt_disable(); ++#endif + hpte_need_flush(mm, addr, ptep, old, huge); ++#ifdef CONFIG_PREEMPT_RT ++ preempt_enable(); ++#endif ++ } + return old; + } + +Index: linux-2.6.24.7-rt27/include/asm-powerpc/tlbflush.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-powerpc/tlbflush.h 2009-02-08 00:04:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-powerpc/tlbflush.h 2009-02-08 00:04:14.000000000 -0500 +@@ -109,7 +109,15 @@ extern void hpte_need_flush(struct mm_st + + static inline void arch_enter_lazy_mmu_mode(void) + { +- struct ppc64_tlb_batch *batch = &get_cpu_var(ppc64_tlb_batch); ++ struct ppc64_tlb_batch *batch; ++#ifdef CONFIG_PREEMPT_RT ++ preempt_disable(); ++#endif ++ batch = &get_cpu_var(ppc64_tlb_batch); ++ ++#ifdef CONFIG_PREEMPT_RT ++ preempt_enable(); ++#endif + + batch->active = 1; + put_cpu_var(ppc64_tlb_batch); +@@ -117,7 +125,12 @@ static inline void arch_enter_lazy_mmu_m + + static inline void arch_leave_lazy_mmu_mode(void) + { +- struct ppc64_tlb_batch *batch = &get_cpu_var(ppc64_tlb_batch); ++ struct ppc64_tlb_batch *batch; ++ ++#ifdef CONFIG_PREEMPT_RT ++ preempt_disable(); ++#endif ++ batch = &get_cpu_var(ppc64_tlb_batch); + + if (batch->active) { + if (batch->index) { +@@ -125,6 +138,9 @@ static inline void arch_leave_lazy_mmu_m + } + batch->active = 0; + } ++#ifdef CONFIG_PREEMPT_RT ++ preempt_enable(); ++#endif + put_cpu_var(ppc64_tlb_batch); + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0461-sched-load_balance-iterator.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0461-sched-load_balance-iterator.patch @@ -0,0 +1,73 @@ +Subject: sched: fixup the load balancer iterator +From: Peter Zijlstra + +Solve the live-lock from the previous patch by not restarting the load +balance iterator on each go. + +Signed-off-by: Peter Zijlstra +--- + kernel/sched.c | 13 +++++++++++-- + kernel/sched_fair.c | 3 +++ + 2 files changed, 14 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:04:29.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:04:29.000000000 -0500 +@@ -2275,6 +2275,7 @@ static void update_cpu_load(struct rq *t + + #define LB_ALL_PINNED 0x01 + #define LB_COMPLETE 0x02 ++#define LB_START 0x03 + + /* + * double_rq_lock - safely lock two runqueues +@@ -2477,7 +2478,11 @@ balance_tasks(struct rq *this_rq, int th + /* + * Start the load-balancing iterator: + */ +- p = iterator->start(iterator->arg); ++ if (*lb_flags & LB_START) ++ p = iterator->start(iterator->arg); ++ else ++ p = iterator->next(iterator->arg); ++ + if (p) + pinned = 1; + next: +@@ -2544,6 +2549,8 @@ static int move_tasks(struct rq *this_rq + unsigned long total_load_moved = 0; + int this_best_prio = this_rq->curr->prio; + ++ *lb_flags |= LB_START; ++ + do { + unsigned long load_moved; + +@@ -2555,9 +2562,11 @@ static int move_tasks(struct rq *this_rq + + total_load_moved += load_moved; + +- if (!load_moved || *lb_flags & LB_COMPLETE) { ++ if (*lb_flags & LB_COMPLETE) { + class = class->next; ++ *lb_flags |= LB_START; + } else if (sched_feat(LB_BREAK)) { ++ *lb_flags &= ~LB_START; + schedstat_inc(this_rq, lb_breaks); + + double_rq_unlock(this_rq, busiest); +Index: linux-2.6.24.7-rt27/kernel/sched_fair.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_fair.c 2009-02-08 00:04:28.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_fair.c 2009-02-08 00:04:29.000000000 -0500 +@@ -185,6 +185,9 @@ static void __dequeue_entity(struct cfs_ + if (cfs_rq->rb_leftmost == &se->run_node) + cfs_rq->rb_leftmost = rb_next(&se->run_node); + ++ if (cfs_rq->rb_load_balance_curr == &se->run_node) ++ cfs_rq->rb_load_balance_curr = rb_next(&se->run_node); ++ + rb_erase(&se->run_node, &cfs_rq->tasks_timeline); + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0386-dont-disable-preemption-without-IST.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0386-dont-disable-preemption-without-IST.patch @@ -0,0 +1,103 @@ +From ak@suse.de Sat Oct 27 10:32:13 2007 +Date: Sat, 27 Oct 2007 12:39:33 +0200 +From: Andi Kleen +To: linux-rt-users@vger.kernel.org +Subject: [PATCH] Don't disable preemption in exception handlers without IST + + +Some of the exception handlers that run on an IST in a normal kernel +still disable preemption. This causes might_sleep warning when sending signals +for debugging in PREEMPT-RT because sending signals can take a lock. +Since the ISTs are disabled now for those don't disable the preemption. + +This completes the remove IST patch I sent some time ago and fixes +another case where using gdb caused warnings. + +Also it will likely improve latency a little bit. + +Signed-off-by: Andi Kleen + +--- + arch/x86/kernel/traps_64.c | 24 +++++++++++++----------- + 1 file changed, 13 insertions(+), 11 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/traps_64.c 2009-02-08 00:03:44.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c 2009-02-08 00:03:54.000000000 -0500 +@@ -82,20 +82,22 @@ static inline void conditional_sti(struc + local_irq_enable(); + } + +-static inline void preempt_conditional_sti(struct pt_regs *regs) ++static inline void preempt_conditional_sti(struct pt_regs *regs, int stack) + { +- preempt_disable(); ++ if (stack) ++ preempt_disable(); + if (regs->eflags & X86_EFLAGS_IF) + local_irq_enable(); + } + +-static inline void preempt_conditional_cli(struct pt_regs *regs) ++static inline void preempt_conditional_cli(struct pt_regs *regs, int stack) + { + if (regs->eflags & X86_EFLAGS_IF) + local_irq_disable(); + /* Make sure to not schedule here because we could be running + on an exception stack. */ +- preempt_enable_no_resched(); ++ if (stack) ++ preempt_enable_no_resched(); + } + + int kstack_depth_to_print = 12; +@@ -669,9 +671,9 @@ asmlinkage void do_stack_segment(struct + if (notify_die(DIE_TRAP, "stack segment", regs, error_code, + 12, SIGBUS) == NOTIFY_STOP) + return; +- preempt_conditional_sti(regs); ++ preempt_conditional_sti(regs, STACKFAULT_STACK); + do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL); +- preempt_conditional_cli(regs); ++ preempt_conditional_cli(regs, STACKFAULT_STACK); + } + + asmlinkage void do_double_fault(struct pt_regs * regs, long error_code) +@@ -831,9 +833,9 @@ asmlinkage void __kprobes do_int3(struct + if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) { + return; + } +- preempt_conditional_sti(regs); ++ preempt_conditional_sti(regs, DEBUG_STACK); + do_trap(3, SIGTRAP, "int3", regs, error_code, NULL); +- preempt_conditional_cli(regs); ++ preempt_conditional_cli(regs, DEBUG_STACK); + } + + /* Help handler running on IST stack to switch back to user stack +@@ -873,7 +875,7 @@ asmlinkage void __kprobes do_debug(struc + SIGTRAP) == NOTIFY_STOP) + return; + +- preempt_conditional_sti(regs); ++ preempt_conditional_sti(regs, DEBUG_STACK); + + /* Mask out spurious debug traps due to lazy DR7 setting */ + if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { +@@ -918,13 +920,13 @@ asmlinkage void __kprobes do_debug(struc + + clear_dr7: + set_debugreg(0UL, 7); +- preempt_conditional_cli(regs); ++ preempt_conditional_cli(regs, DEBUG_STACK); + return; + + clear_TF_reenable: + set_tsk_thread_flag(tsk, TIF_SINGLESTEP); + regs->eflags &= ~TF_MASK; +- preempt_conditional_cli(regs); ++ preempt_conditional_cli(regs, DEBUG_STACK); + } + + static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr) --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0135-m68knommu-add-cmpxchg-in-default-fashion.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0135-m68knommu-add-cmpxchg-in-default-fashion.patch @@ -0,0 +1,63 @@ +From 46a77f70fc1a6f11c01eb8265feea0ab93c3cbac Mon Sep 17 00:00:00 2001 +From: Sebastian Siewior +Date: Fri, 18 Apr 2008 17:02:27 +0200 +Subject: [PATCH] m68knommu: add cmpxchg in default fashion + +not RT-safe, generic + +Signed-off-by: Sebastian Siewior +Signed-off-by: Thomas Gleixner +--- + include/asm-m68knommu/system.h | 34 +++++++++++++++++++++++++--------- + 1 file changed, 25 insertions(+), 9 deletions(-) + +Index: linux-2.6.24.7-rt27/include/asm-m68knommu/system.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-m68knommu/system.h 2009-02-08 00:00:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-m68knommu/system.h 2009-02-08 00:01:45.000000000 -0500 +@@ -192,20 +192,36 @@ static inline unsigned long __xchg(unsig + * indicated by comparing RETURN with OLD. + */ + #define __HAVE_ARCH_CMPXCHG 1 ++extern unsigned long __cmpxchg_called_with_bad_pointer(volatile void *p, ++ unsigned long old, unsigned long new, int size); + +-static __inline__ unsigned long +-cmpxchg(volatile int *p, int old, int new) ++static inline unsigned long ++__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) + { +- unsigned long flags; +- int prev; ++ unsigned long flags, prev; ++ volatile unsigned int *p = ptr; + +- local_irq_save(flags); +- if ((prev = *p) == old) +- *p = new; +- local_irq_restore(flags); +- return(prev); ++ if (size == 4) { ++ ++ local_irq_save(flags); ++ if ((prev = *p) == old) ++ *p = new; ++ local_irq_restore(flags); ++ return prev; ++ } ++ ++ /* we should not get here, if you do we end up with a linker error */ ++ return __cmpxchg_called_with_bad_pointer(p, old, new, size); + } + ++#define cmpxchg(ptr,o,n) \ ++ ({ \ ++ __typeof__(*(ptr)) _o_ = (o); \ ++ __typeof__(*(ptr)) _n_ = (n); \ ++ (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ ++ (unsigned long)_n_, sizeof(*(ptr))); \ ++ }) ++ + + #ifdef CONFIG_M68332 + #define HARD_RESET_NOW() ({ \ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0176-rt-mutex-arm.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0176-rt-mutex-arm.patch @@ -0,0 +1,380 @@ +--- + arch/arm/kernel/entry-armv.S | 4 +- + arch/arm/kernel/entry-common.S | 14 +++++---- + arch/arm/kernel/process.c | 10 ++++-- + arch/arm/kernel/semaphore.c | 31 +++++++++++++++------ + include/asm-arm/semaphore.h | 59 ++++++++++++++++++++++++++++------------- + include/asm-arm/thread_info.h | 2 + + 6 files changed, 82 insertions(+), 38 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/arm/kernel/entry-armv.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/entry-armv.S 2009-02-08 00:00:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/entry-armv.S 2009-02-08 00:02:06.000000000 -0500 +@@ -204,7 +204,7 @@ __irq_svc: + irq_handler + #ifdef CONFIG_PREEMPT + ldr r0, [tsk, #TI_FLAGS] @ get flags +- tst r0, #_TIF_NEED_RESCHED ++ tst r0, #_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_DELAYED + blne svc_preempt + preempt_return: + ldr r0, [tsk, #TI_PREEMPT] @ read preempt value +@@ -235,7 +235,7 @@ svc_preempt: + str r7, [tsk, #TI_PREEMPT] @ expects preempt_count == 0 + 1: bl preempt_schedule_irq @ irq en/disable is done inside + ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS +- tst r0, #_TIF_NEED_RESCHED ++ tst r0, #_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_DELAYED + beq preempt_return @ go again + b 1b + #endif +Index: linux-2.6.24.7-rt27/arch/arm/kernel/entry-common.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/entry-common.S 2009-02-08 00:01:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/entry-common.S 2009-02-08 00:02:06.000000000 -0500 +@@ -46,7 +46,7 @@ ret_fast_syscall: + fast_work_pending: + str r0, [sp, #S_R0+S_OFF]! @ returned r0 + work_pending: +- tst r1, #_TIF_NEED_RESCHED ++ tst r1, #_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_DELAYED + bne work_resched + tst r1, #_TIF_SIGPENDING + beq no_work_pending +@@ -56,7 +56,8 @@ work_pending: + b ret_slow_syscall @ Check work again + + work_resched: +- bl schedule ++ bl __schedule ++ + /* + * "slow" syscall return path. "why" tells us if this was a real syscall. + */ +@@ -396,6 +397,7 @@ ENTRY(sys_oabi_call_table) + #include "calls.S" + #undef ABI + #undef OBSOLETE ++#endif + + #ifdef CONFIG_FRAME_POINTER + +@@ -445,11 +447,13 @@ mcount: + ldr ip, =mcount_enabled @ leave early, if disabled + ldr ip, [ip] + cmp ip, #0 +- moveq pc,lr ++ moveq pc, lr + + mov ip, sp + stmdb sp!, {r0 - r3, fp, ip, lr, pc} @ create stack frame + ++ mov r2, =mcount_trace_function ++ + ldr r1, [fp, #-4] @ get lr (the return address + @ of the caller of the + @ instrumented function) +@@ -458,7 +462,7 @@ mcount: + + sub fp, ip, #4 @ point fp at this frame + +- bl __trace ++ bl r2 + 1: + ldmdb fp, {r0 - r3, fp, sp, pc} @ pop entry frame and return + +@@ -504,5 +508,3 @@ arm_return_addr: + + #endif + +-#endif +- +Index: linux-2.6.24.7-rt27/arch/arm/kernel/process.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/process.c 2009-02-08 00:01:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/process.c 2009-02-08 00:02:06.000000000 -0500 +@@ -136,7 +136,7 @@ static void default_idle(void) + cpu_relax(); + else { + local_irq_disable(); +- if (!need_resched()) { ++ if (!need_resched() && !need_resched_delayed()) { + timer_dyn_reprogram(); + arch_idle(); + } +@@ -168,13 +168,15 @@ void cpu_idle(void) + idle = default_idle; + leds_event(led_idle_start); + tick_nohz_stop_sched_tick(); +- while (!need_resched()) ++ while (!need_resched() && !need_resched_delayed()) + idle(); + leds_event(led_idle_end); + tick_nohz_restart_sched_tick(); +- preempt_enable_no_resched(); +- schedule(); ++ local_irq_disable(); ++ __preempt_enable_no_resched(); ++ __schedule(); + preempt_disable(); ++ local_irq_enable(); + } + } + +Index: linux-2.6.24.7-rt27/arch/arm/kernel/semaphore.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/kernel/semaphore.c 2009-02-08 00:00:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/kernel/semaphore.c 2009-02-08 00:02:06.000000000 -0500 +@@ -49,14 +49,16 @@ + * we cannot lose wakeup events. + */ + +-void __up(struct semaphore *sem) ++fastcall void __attribute_used__ __compat_up(struct compat_semaphore *sem) + { + wake_up(&sem->wait); + } + ++EXPORT_SYMBOL(__compat_up); ++ + static DEFINE_SPINLOCK(semaphore_lock); + +-void __sched __down(struct semaphore * sem) ++fastcall void __attribute_used__ __sched __compat_down(struct compat_semaphore * sem) + { + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); +@@ -89,7 +91,9 @@ void __sched __down(struct semaphore * s + wake_up(&sem->wait); + } + +-int __sched __down_interruptible(struct semaphore * sem) ++EXPORT_SYMBOL(__compat_down); ++ ++fastcall int __attribute_used__ __sched __compat_down_interruptible(struct compat_semaphore * sem) + { + int retval = 0; + struct task_struct *tsk = current; +@@ -140,6 +144,8 @@ int __sched __down_interruptible(struct + return retval; + } + ++EXPORT_SYMBOL(__compat_down_interruptible); ++ + /* + * Trylock failed - make sure we correct for + * having decremented the count. +@@ -148,7 +154,7 @@ int __sched __down_interruptible(struct + * single "cmpxchg" without failure cases, + * but then it wouldn't work on a 386. + */ +-int __down_trylock(struct semaphore * sem) ++fastcall int __attribute_used__ __compat_down_trylock(struct compat_semaphore * sem) + { + int sleepers; + unsigned long flags; +@@ -168,6 +174,15 @@ int __down_trylock(struct semaphore * se + return 1; + } + ++EXPORT_SYMBOL(__compat_down_trylock); ++ ++fastcall int compat_sem_is_locked(struct compat_semaphore *sem) ++{ ++ return (int) atomic_read(&sem->count) < 0; ++} ++ ++EXPORT_SYMBOL(compat_sem_is_locked); ++ + /* + * The semaphore operations have a special calling sequence that + * allow us to do a simpler in-line version of them. These routines +@@ -185,7 +200,7 @@ asm(" .section .sched.text,\"ax\",%progb + __down_failed: \n\ + stmfd sp!, {r0 - r4, lr} \n\ + mov r0, ip \n\ +- bl __down \n\ ++ bl __compat_down \n\ + ldmfd sp!, {r0 - r4, pc} \n\ + \n\ + .align 5 \n\ +@@ -193,7 +208,7 @@ __down_failed: \n\ + __down_interruptible_failed: \n\ + stmfd sp!, {r0 - r4, lr} \n\ + mov r0, ip \n\ +- bl __down_interruptible \n\ ++ bl __compat_down_interruptible \n\ + mov ip, r0 \n\ + ldmfd sp!, {r0 - r4, pc} \n\ + \n\ +@@ -202,7 +217,7 @@ __down_interruptible_failed: \n\ + __down_trylock_failed: \n\ + stmfd sp!, {r0 - r4, lr} \n\ + mov r0, ip \n\ +- bl __down_trylock \n\ ++ bl __compat_down_trylock \n\ + mov ip, r0 \n\ + ldmfd sp!, {r0 - r4, pc} \n\ + \n\ +@@ -211,7 +226,7 @@ __down_trylock_failed: \n\ + __up_wakeup: \n\ + stmfd sp!, {r0 - r4, lr} \n\ + mov r0, ip \n\ +- bl __up \n\ ++ bl __compat_up \n\ + ldmfd sp!, {r0 - r4, pc} \n\ + "); + +Index: linux-2.6.24.7-rt27/include/asm-arm/semaphore.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/semaphore.h 2009-02-08 00:00:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/semaphore.h 2009-02-08 00:02:06.000000000 -0500 +@@ -5,45 +5,65 @@ + #define __ASM_ARM_SEMAPHORE_H + + #include ++ ++#ifdef CONFIG_PREEMPT_RT ++# include ++#endif ++ + #include + #include + #include + ++/* ++ * On !PREEMPT_RT all semaphores are compat: ++ */ ++#ifndef CONFIG_PREEMPT_RT ++# define semaphore compat_semaphore ++#endif ++ + #include + #include + +-struct semaphore { ++struct compat_semaphore { + atomic_t count; + int sleepers; + wait_queue_head_t wait; + }; + +-#define __SEMAPHORE_INIT(name, cnt) \ ++#define __COMPAT_SEMAPHORE_INITIALIZER(name, cnt) \ + { \ + .count = ATOMIC_INIT(cnt), \ + .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ + } + +-#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ +- struct semaphore name = __SEMAPHORE_INIT(name,count) ++#define __COMPAT_MUTEX_INITIALIZER(name) \ ++ __COMPAT_SEMAPHORE_INITIALIZER(name,1) ++ ++#define __COMPAT_DECLARE_SEMAPHORE_GENERIC(name,count) \ ++ struct compat_semaphore name = __COMPAT_SEMAPHORE_INITIALIZER(name,count) + +-#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) ++#define COMPAT_DECLARE_MUTEX(name) __COMPAT_DECLARE_SEMAPHORE_GENERIC(name,1) + +-static inline void sema_init(struct semaphore *sem, int val) ++static inline void compat_sema_init(struct compat_semaphore *sem, int val) + { + atomic_set(&sem->count, val); + sem->sleepers = 0; + init_waitqueue_head(&sem->wait); + } + +-static inline void init_MUTEX(struct semaphore *sem) ++static inline void compat_init_MUTEX(struct compat_semaphore *sem) ++{ ++ compat_sema_init(sem, 1); ++} ++ ++static inline void compat_init_MUTEX_LOCKED(struct compat_semaphore *sem) + { +- sema_init(sem, 1); ++ compat_sema_init(sem, 0); + } + +-static inline void init_MUTEX_LOCKED(struct semaphore *sem) ++static inline int compat_sema_count(struct compat_semaphore *sem) + { +- sema_init(sem, 0); ++ return atomic_read(&sem->count); + } + + /* +@@ -54,16 +74,18 @@ asmlinkage int __down_interruptible_fai + asmlinkage int __down_trylock_failed(void); + asmlinkage void __up_wakeup(void); + +-extern void __down(struct semaphore * sem); +-extern int __down_interruptible(struct semaphore * sem); +-extern int __down_trylock(struct semaphore * sem); +-extern void __up(struct semaphore * sem); ++extern void __compat_up(struct compat_semaphore *sem); ++extern int __compat_down_interruptible(struct compat_semaphore * sem); ++extern int __compat_down_trylock(struct compat_semaphore * sem); ++extern void __compat_down(struct compat_semaphore * sem); ++ ++extern int compat_sem_is_locked(struct compat_semaphore *sem); + + /* + * This is ugly, but we want the default case to fall through. + * "__down" is the actual routine that waits... + */ +-static inline void down(struct semaphore * sem) ++static inline void compat_down(struct compat_semaphore * sem) + { + might_sleep(); + __down_op(sem, __down_failed); +@@ -73,13 +95,13 @@ static inline void down(struct semaphore + * This is ugly, but we want the default case to fall through. + * "__down_interruptible" is the actual routine that waits... + */ +-static inline int down_interruptible (struct semaphore * sem) ++static inline int compat_down_interruptible (struct compat_semaphore * sem) + { + might_sleep(); + return __down_op_ret(sem, __down_interruptible_failed); + } + +-static inline int down_trylock(struct semaphore *sem) ++static inline int compat_down_trylock(struct compat_semaphore *sem) + { + return __down_op_ret(sem, __down_trylock_failed); + } +@@ -90,9 +112,10 @@ static inline int down_trylock(struct se + * The default case (no contention) will result in NO + * jumps for both down() and up(). + */ +-static inline void up(struct semaphore * sem) ++static inline void compat_up(struct compat_semaphore * sem) + { + __up_op(sem, __up_wakeup); + } + ++#include + #endif +Index: linux-2.6.24.7-rt27/include/asm-arm/thread_info.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-arm/thread_info.h 2009-02-08 00:00:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-arm/thread_info.h 2009-02-08 00:02:06.000000000 -0500 +@@ -141,6 +141,7 @@ extern void iwmmxt_task_switch(struct th + */ + #define TIF_SIGPENDING 0 + #define TIF_NEED_RESCHED 1 ++#define TIF_NEED_RESCHED_DELAYED 3 + #define TIF_SYSCALL_TRACE 8 + #define TIF_POLLING_NRFLAG 16 + #define TIF_USING_IWMMXT 17 +@@ -149,6 +150,7 @@ extern void iwmmxt_task_switch(struct th + + #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) + #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) ++#define _TIF_NEED_RESCHED_DELAYED (1< + +--- + kernel/lockdep.c | 29 +++++++++++++++++------------ + 1 file changed, 17 insertions(+), 12 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/lockdep.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/lockdep.c 2009-02-08 00:03:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/lockdep.c 2009-02-08 00:03:34.000000000 -0500 +@@ -817,6 +817,21 @@ out_unlock_set: + return class; + } + ++#if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_TRACE_IRQFLAGS) ++ ++#define RECURSION_LIMIT 40 ++ ++static int noinline print_infinite_recursion_bug(void) ++{ ++ if (!debug_locks_off_graph_unlock()) ++ return 0; ++ ++ WARN_ON(1); ++ ++ return 0; ++} ++#endif /* CONFIG_PROVE_LOCKING || CONFIG_TRACE_IRQFLAGS */ ++ + #ifdef CONFIG_PROVE_LOCKING + /* + * Allocate a lockdep entry. (assumes the graph_lock held, returns +@@ -947,18 +962,6 @@ static noinline int print_circular_bug_t + return 0; + } + +-#define RECURSION_LIMIT 40 +- +-static int noinline print_infinite_recursion_bug(void) +-{ +- if (!debug_locks_off_graph_unlock()) +- return 0; +- +- WARN_ON(1); +- +- return 0; +-} +- + /* + * Prove that the dependency graph starting at can not + * lead to . Print an error and return 0 if it does. +@@ -1076,6 +1079,7 @@ find_usage_backwards(struct lock_class * + return 1; + } + ++#ifdef CONFIG_PROVE_LOCKING + static int + print_bad_irq_dependency(struct task_struct *curr, + struct held_lock *prev, +@@ -1136,6 +1140,7 @@ print_bad_irq_dependency(struct task_str + + return 0; + } ++#endif /* CONFIG_PROVE_LOCKING */ + + static int + check_usage(struct task_struct *curr, struct held_lock *prev, --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0018-0004-sched-add-rt-overload-tracking.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0018-0004-sched-add-rt-overload-tracking.patch @@ -0,0 +1,77 @@ +From 957d2c0535a8ea69f7f625a97ba64a3af1070c01 Mon Sep 17 00:00:00 2001 +From: Steven Rostedt +Date: Tue, 11 Dec 2007 10:02:37 +0100 +Subject: [PATCH] sched: add rt-overload tracking + +This patch adds an RT overload accounting system. When a runqueue has +more than one RT task queued, it is marked as overloaded. That is that it +is a candidate to have RT tasks pulled from it. + +Signed-off-by: Steven Rostedt +Signed-off-by: Ingo Molnar + +--- + kernel/sched_rt.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:00:51.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:00:51.000000000 -0500 +@@ -3,6 +3,38 @@ + * policies) + */ + ++#ifdef CONFIG_SMP ++static cpumask_t rt_overload_mask; ++static atomic_t rto_count; ++static inline int rt_overloaded(void) ++{ ++ return atomic_read(&rto_count); ++} ++static inline cpumask_t *rt_overload(void) ++{ ++ return &rt_overload_mask; ++} ++static inline void rt_set_overload(struct rq *rq) ++{ ++ cpu_set(rq->cpu, rt_overload_mask); ++ /* ++ * Make sure the mask is visible before we set ++ * the overload count. That is checked to determine ++ * if we should look at the mask. It would be a shame ++ * if we looked at the mask, but the mask was not ++ * updated yet. ++ */ ++ wmb(); ++ atomic_inc(&rto_count); ++} ++static inline void rt_clear_overload(struct rq *rq) ++{ ++ /* the order here really doesn't matter */ ++ atomic_dec(&rto_count); ++ cpu_clear(rq->cpu, rt_overload_mask); ++} ++#endif /* CONFIG_SMP */ ++ + /* + * Update the current task's runtime statistics. Skip current tasks that + * are not in our scheduling class. +@@ -33,6 +65,8 @@ static inline void inc_rt_tasks(struct t + #ifdef CONFIG_SMP + if (p->prio < rq->rt.highest_prio) + rq->rt.highest_prio = p->prio; ++ if (rq->rt.rt_nr_running > 1) ++ rt_set_overload(rq); + #endif /* CONFIG_SMP */ + } + +@@ -54,6 +88,8 @@ static inline void dec_rt_tasks(struct t + } /* otherwise leave rq->highest prio alone */ + } else + rq->rt.highest_prio = MAX_RT_PRIO; ++ if (rq->rt.rt_nr_running < 2) ++ rt_clear_overload(rq); + #endif /* CONFIG_SMP */ + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0400-handle-pending-in-simple-irq.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0400-handle-pending-in-simple-irq.patch @@ -0,0 +1,39 @@ +From: Steven Rostedt +Subject: handle IRQ_PENDING for simple irq handler + +With the IO-APIC pcix hack (level=>edge masking), we can receive +interrupts while masked. But these interrupts might be missed. + +Also, normal "simple" interrupts might be missed too on leaving of +thread handler. + +Signed-off-by: Steven Rostedt + +--- + kernel/irq/manage.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/irq/manage.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/irq/manage.c 2009-02-08 00:03:31.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/irq/manage.c 2009-02-08 00:03:59.000000000 -0500 +@@ -652,14 +652,17 @@ static void thread_simple_irq(irq_desc_t + unsigned int irq = desc - irq_desc; + irqreturn_t action_ret; + +- if (action && !desc->depth) { ++ do { ++ if (!action || desc->depth) ++ break; ++ desc->status &= ~IRQ_PENDING; + spin_unlock(&desc->lock); + action_ret = handle_IRQ_event(irq, action); + cond_resched_hardirq_context(); + spin_lock_irq(&desc->lock); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); +- } ++ } while (desc->status & IRQ_PENDING); + desc->status &= ~IRQ_INPROGRESS; + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0337-mitigate-resched-flood.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0337-mitigate-resched-flood.patch @@ -0,0 +1,144 @@ +[PATCH 1/3] mitigate-resched-interrupt-floods + +Mitigate rescheduling interrupt floods. + +Background: preempt-rt sends a resched interrupt to all +other cpus whenever some realtime task gets preempted. +This is to give that task a chance to continue running +on some other cpu. Unfortunately this can cause 'resched +interrupt floods' when there are large numbers of realtime +tasks on the system that are continually being preempted. + +This patch reduces such interrupts by noting that it is +not necessary to send rescheduling interrupts to every cpu +in the system, just to those cpus in the affinity mask of +the task to be migrated. + +This works well in the real world, as traditionally +realtime tasks are carefully targeted to specific cpus or +sets of cpus, meaning users often give such tasks reduced +affinity masks. + +Signed-off-by: Joe Korty + +--- + arch/x86/kernel/smp_32.c | 9 +++++++++ + arch/x86/kernel/smp_64.c | 9 +++++++++ + include/asm-x86/smp_32.h | 2 ++ + include/asm-x86/smp_64.h | 3 +++ + include/linux/smp.h | 10 ++++++++++ + 5 files changed, 33 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/smp_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/smp_32.c 2009-02-08 00:02:34.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/smp_32.c 2009-02-08 00:03:31.000000000 -0500 +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -485,6 +486,14 @@ void smp_send_reschedule_allbutself(void + send_IPI_allbutself(RESCHEDULE_VECTOR); + } + ++void smp_send_reschedule_allbutself_cpumask(cpumask_t mask) ++{ ++ cpu_clear(smp_processor_id(), mask); ++ cpus_and(mask, mask, cpu_online_map); ++ if (!cpus_empty(mask)) ++ send_IPI_mask(mask, RESCHEDULE_VECTOR); ++} ++ + /* + * Structure and data for smp_call_function(). This is designed to minimise + * static memory requirements. It also looks cleaner. +Index: linux-2.6.24.7-rt27/arch/x86/kernel/smp_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/smp_64.c 2009-02-08 00:02:25.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/smp_64.c 2009-02-08 00:03:31.000000000 -0500 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -305,6 +306,14 @@ void smp_send_reschedule_allbutself(void + send_IPI_allbutself(RESCHEDULE_VECTOR); + } + ++void smp_send_reschedule_allbutself_cpumask(cpumask_t mask) ++{ ++ cpu_clear(smp_processor_id(), mask); ++ cpus_and(mask, mask, cpu_online_map); ++ if (!cpus_empty(mask)) ++ send_IPI_mask(mask, RESCHEDULE_VECTOR); ++} ++ + /* + * Structure and data for smp_call_function(). This is designed to minimise + * static memory requirements. It also looks cleaner. +Index: linux-2.6.24.7-rt27/include/asm-x86/smp_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/smp_32.h 2009-02-07 23:59:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/smp_32.h 2009-02-08 00:03:31.000000000 -0500 +@@ -181,4 +181,6 @@ static __inline int logical_smp_processo + #endif + #endif + ++#define HAVE_RESCHEDULE_ALLBUTSELF_CPUMASK 1 ++ + #endif +Index: linux-2.6.24.7-rt27/include/asm-x86/smp_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/smp_64.h 2009-02-07 23:59:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/smp_64.h 2009-02-08 00:03:31.000000000 -0500 +@@ -126,5 +126,8 @@ static __inline int logical_smp_processo + extern unsigned int boot_cpu_id; + #define cpu_physical_id(cpu) boot_cpu_id + #endif /* !CONFIG_SMP */ ++ ++#define HAVE_RESCHEDULE_ALLBUTSELF_CPUMASK 1 ++ + #endif + +Index: linux-2.6.24.7-rt27/include/linux/smp.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/smp.h 2009-02-08 00:02:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/smp.h 2009-02-08 00:03:31.000000000 -0500 +@@ -7,6 +7,7 @@ + */ + + #include ++#include + + extern void cpu_idle(void); + +@@ -43,6 +44,14 @@ extern void smp_send_reschedule_allbutse + */ + extern void smp_send_reschedule_allbutself(void); + ++#ifdef HAVE_RESCHEDULE_ALLBUTSELF_CPUMASK ++extern void smp_send_reschedule_allbutself_cpumask(cpumask_t); ++#else ++static inline void smp_send_reschedule_allbutself_cpumask(cpumask_t mask) { ++ smp_send_reschedule_allbutself(); ++} ++#endif ++ + + /* + * Prepare machine for booting other CPUs. +@@ -109,6 +118,7 @@ static inline int up_smp_call_function(v + }) + static inline void smp_send_reschedule(int cpu) { } + static inline void smp_send_reschedule_allbutself(void) { } ++static inline void smp_send_reschedule_allbutself_cpumask(cpumask_t mask) { } + #define num_booting_cpus() 1 + #define smp_prepare_boot_cpu() do {} while (0) + #define smp_call_function_single(cpuid, func, info, retry, wait) \ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0484-rcupreempt-trace-marker-update.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0484-rcupreempt-trace-marker-update.patch @@ -0,0 +1,87 @@ +From: Steven Rostedt +Subject: rcupreempt trace update to new markers + +Update the rcupreempt tracing with the new markers. + +Signed-off-by: Steven Rostedt +--- + include/linux/rcupreempt_trace.h | 8 ++++---- + kernel/rcupreempt_trace.c | 21 +++++++++------------ + 2 files changed, 13 insertions(+), 16 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/rcupreempt_trace.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupreempt_trace.h 2009-02-08 00:04:03.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupreempt_trace.h 2009-02-08 00:04:40.000000000 -0500 +@@ -76,8 +76,8 @@ struct rcupreempt_probe_data { + }; + + #define DEFINE_RCUPREEMPT_MARKER_HANDLER(rcupreempt_trace_worker) \ +-void rcupreempt_trace_worker##_callback(const struct marker *mdata, \ +- void *private_data, const char *format, ...) \ ++void rcupreempt_trace_worker##_callback(void *private_data, void *call_data, \ ++ const char *format, va_list *args) \ + { \ + struct rcupreempt_trace *trace; \ + trace = (&per_cpu(trace_data, smp_processor_id())); \ +@@ -113,8 +113,8 @@ struct preempt_rcu_boost_trace { + }; + + #define DEFINE_PREEMPT_RCU_BOOST_MARKER_HANDLER(preempt_rcu_boost_var) \ +-void preempt_rcu_boost_var##_callback(const struct marker *mdata, \ +- void *private_data, const char *format, ...) \ ++void preempt_rcu_boost_var##_callback(void *private_data, void *call_data, \ ++ const char *format, va_list *args) \ + { \ + struct preempt_rcu_boost_trace *boost_trace; \ + boost_trace = (&per_cpu(boost_trace_data, smp_processor_id())); \ +Index: linux-2.6.24.7-rt27/kernel/rcupreempt_trace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt_trace.c 2009-02-08 00:04:03.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt_trace.c 2009-02-08 00:04:40.000000000 -0500 +@@ -536,10 +536,6 @@ static int __init rcupreempt_trace_init( + if (ret) + printk(KERN_INFO "Unable to register rcupreempt \ + probe %s\n", rcupreempt_probe_array[i].name); +- ret = marker_arm(p->name); +- if (ret) +- printk(KERN_INFO "Unable to arm rcupreempt probe %s\n", +- p->name); + } + printk(KERN_INFO "RCU Preempt markers registered\n"); + +@@ -552,10 +548,6 @@ static int __init rcupreempt_trace_init( + if (ret) + printk(KERN_INFO "Unable to register Preempt RCU Boost \ + probe %s\n", preempt_rcu_boost_probe_array[i].name); +- ret = marker_arm(p->name); +- if (ret) +- printk(KERN_INFO "Unable to arm Preempt RCU Boost \ +- markers %s\n", p->name); + } + #endif /* CONFIG_PREEMPT_RCU_BOOST */ + +@@ -573,14 +565,19 @@ static void __exit rcupreempt_trace_clea + { + int i; + +- for (i = 0; i < ARRAY_SIZE(rcupreempt_probe_array); i++) +- marker_probe_unregister(rcupreempt_probe_array[i].name); ++ for (i = 0; i < ARRAY_SIZE(rcupreempt_probe_array); i++) { ++ struct rcupreempt_probe_data *p = &rcupreempt_probe_array[i]; ++ marker_probe_unregister(p->name, p->probe_func, p); ++ } + printk(KERN_INFO "RCU Preempt markers unregistered\n"); + + #ifdef CONFIG_PREEMPT_RCU_BOOST + rcu_trace_boost_destroy(); +- for (i = 0; i < ARRAY_SIZE(preempt_rcu_boost_probe_array); i++) +- marker_probe_unregister(preempt_rcu_boost_probe_array[i].name); ++ for (i = 0; i < ARRAY_SIZE(preempt_rcu_boost_probe_array); i++) { ++ struct preempt_rcu_boost_probe *p = \ ++ &preempt_rcu_boost_probe_array[i]; ++ marker_probe_unregister(p->name, p->probe_func, p); ++ } + printk(KERN_INFO "Preempt RCU Boost markers unregistered\n"); + #endif /* CONFIG_PREEMPT_RCU_BOOST */ + debugfs_remove(statdir); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0116-lockdep-more-entries.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0116-lockdep-more-entries.patch @@ -0,0 +1,23 @@ +--- + kernel/lockdep_internals.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/lockdep_internals.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/lockdep_internals.h 2009-02-08 00:00:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/lockdep_internals.h 2009-02-08 00:01:37.000000000 -0500 +@@ -15,12 +15,12 @@ + * table (if it's not there yet), and we check it for lock order + * conflicts and deadlocks. + */ +-#define MAX_LOCKDEP_ENTRIES 8192UL ++#define MAX_LOCKDEP_ENTRIES 16384UL + + #define MAX_LOCKDEP_KEYS_BITS 11 + #define MAX_LOCKDEP_KEYS (1UL << MAX_LOCKDEP_KEYS_BITS) + +-#define MAX_LOCKDEP_CHAINS_BITS 14 ++#define MAX_LOCKDEP_CHAINS_BITS 15 + #define MAX_LOCKDEP_CHAINS (1UL << MAX_LOCKDEP_CHAINS_BITS) + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0392-printk-dont-bug-on-sched.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0392-printk-dont-bug-on-sched.patch @@ -0,0 +1,38 @@ +--- + kernel/rtmutex.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:03:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:03:56.000000000 -0500 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #include "rtmutex_common.h" + +@@ -635,6 +636,9 @@ rt_spin_lock_fastlock(struct rt_mutex *l + /* Temporary HACK! */ + if (!current->in_printk) + might_sleep(); ++ else if (in_atomic() || irqs_disabled()) ++ /* don't grab locks for printk in atomic */ ++ return; + + if (likely(rt_mutex_cmpxchg(lock, NULL, current))) + rt_mutex_deadlock_account_lock(lock, current); +@@ -646,6 +650,11 @@ static inline void + rt_spin_lock_fastunlock(struct rt_mutex *lock, + void fastcall (*slowfn)(struct rt_mutex *lock)) + { ++ /* Temporary HACK! */ ++ if (current->in_printk && (in_atomic() || irqs_disabled())) ++ /* don't grab locks for printk in atomic */ ++ return; ++ + if (likely(rt_mutex_cmpxchg(lock, current, NULL))) + rt_mutex_deadlock_account_unlock(current); + else --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0113-lockdep-show-held-locks.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0113-lockdep-show-held-locks.patch @@ -0,0 +1,64 @@ +Subject: [patch] lockdep: show held locks when showing a stackdump +From: Ingo Molnar + +show held locks when printing a backtrace. + +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/traps_32.c | 1 + + arch/x86/kernel/traps_64.c | 1 + + kernel/lockdep.c | 9 +++++++-- + 3 files changed, 9 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/traps_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/traps_32.c 2009-02-08 00:01:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/traps_32.c 2009-02-08 00:01:36.000000000 -0500 +@@ -271,6 +271,7 @@ static void show_stack_log_lvl(struct ta + } + printk("\n%sCall Trace:\n", log_lvl); + show_trace_log_lvl(task, regs, esp, log_lvl); ++ debug_show_held_locks(task); + } + + void show_stack(struct task_struct *task, unsigned long *esp) +Index: linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/traps_64.c 2009-02-08 00:01:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/traps_64.c 2009-02-08 00:01:36.000000000 -0500 +@@ -320,6 +320,7 @@ print_trace_warning_symbol(void *data, c + { + print_symbol(msg, symbol); + printk("\n"); ++ debug_show_held_locks(tsk); + } + + static void print_trace_warning(void *data, char *msg) +Index: linux-2.6.24.7-rt27/kernel/lockdep.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/lockdep.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/lockdep.c 2009-02-08 00:01:36.000000000 -0500 +@@ -512,7 +512,11 @@ static void print_lock(struct held_lock + + static void lockdep_print_held_locks(struct task_struct *curr) + { +- int i, depth = curr->lockdep_depth; ++ int i, depth; ++ ++ if (!curr) ++ curr = current; ++ depth = curr->lockdep_depth; + + if (!depth) { + printk("no locks held by %s/%d.\n", curr->comm, task_pid_nr(curr)); +@@ -3229,7 +3233,8 @@ void debug_show_held_locks(struct task_s + printk("INFO: lockdep is turned off.\n"); + return; + } +- lockdep_print_held_locks(task); ++ if (task == current) ++ lockdep_print_held_locks(task); + } + + EXPORT_SYMBOL_GPL(debug_show_held_locks); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0249-preempt-realtime-console.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0249-preempt-realtime-console.patch @@ -0,0 +1,50 @@ +--- + drivers/video/console/fbcon.c | 5 +++-- + include/linux/console.h | 1 + + 2 files changed, 4 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/drivers/video/console/fbcon.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/video/console/fbcon.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/video/console/fbcon.c 2009-02-08 00:02:44.000000000 -0500 +@@ -1306,7 +1306,6 @@ static void fbcon_clear(struct vc_data * + { + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; +- + struct display *p = &fb_display[vc->vc_num]; + u_int y_break; + +@@ -1335,10 +1334,11 @@ static void fbcon_putcs(struct vc_data * + struct display *p = &fb_display[vc->vc_num]; + struct fbcon_ops *ops = info->fbcon_par; + +- if (!fbcon_is_inactive(vc, info)) ++ if (!fbcon_is_inactive(vc, info)) { + ops->putcs(vc, info, s, count, real_y(p, ypos), xpos, + get_color(vc, info, scr_readw(s), 1), + get_color(vc, info, scr_readw(s), 0)); ++ } + } + + static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) +@@ -3322,6 +3322,7 @@ static const struct consw fb_con = { + .con_screen_pos = fbcon_screen_pos, + .con_getxy = fbcon_getxy, + .con_resize = fbcon_resize, ++ .con_preemptible = 1, + }; + + static struct notifier_block fbcon_event_notifier = { +Index: linux-2.6.24.7-rt27/include/linux/console.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/console.h 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/console.h 2009-02-08 00:02:44.000000000 -0500 +@@ -55,6 +55,7 @@ struct consw { + void (*con_invert_region)(struct vc_data *, u16 *, int); + u16 *(*con_screen_pos)(struct vc_data *, int); + unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *); ++ int con_preemptible; // can it reschedule from within printk? + }; + + extern const struct consw *conswitchp; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0233-preempt-realtime-ftrace.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0233-preempt-realtime-ftrace.patch @@ -0,0 +1,118 @@ +--- + kernel/trace/ftrace.c | 4 ++-- + kernel/trace/trace.c | 10 +++++----- + kernel/trace/trace.h | 2 +- + kernel/trace/trace_hist.c | 2 +- + kernel/trace/trace_irqsoff.c | 2 +- + kernel/trace/trace_sched_wakeup.c | 2 +- + 6 files changed, 11 insertions(+), 11 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/trace/ftrace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/ftrace.c 2009-02-08 00:01:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/ftrace.c 2009-02-08 00:02:36.000000000 -0500 +@@ -39,7 +39,7 @@ static int last_ftrace_enabled; + */ + static int ftrace_disabled __read_mostly; + +-static DEFINE_SPINLOCK(ftrace_lock); ++static DEFINE_RAW_SPINLOCK(ftrace_lock); + static DEFINE_MUTEX(ftrace_sysctl_lock); + + static struct ftrace_ops ftrace_list_end __read_mostly = +@@ -166,7 +166,7 @@ static struct hlist_head ftrace_hash[FTR + + static DEFINE_PER_CPU(int, ftrace_shutdown_disable_cpu); + +-static DEFINE_SPINLOCK(ftrace_shutdown_lock); ++static DEFINE_RAW_SPINLOCK(ftrace_shutdown_lock); + static DEFINE_MUTEX(ftraced_lock); + static DEFINE_MUTEX(ftrace_regex_lock); + +Index: linux-2.6.24.7-rt27/kernel/trace/trace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace.c 2009-02-08 00:01:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace.c 2009-02-08 00:02:36.000000000 -0500 +@@ -223,8 +223,8 @@ static const char *trace_options[] = { + * This is defined as a raw_spinlock_t in order to help + * with performance when lockdep debugging is enabled. + */ +-static raw_spinlock_t ftrace_max_lock = +- (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; ++static __raw_spinlock_t ftrace_max_lock = ++ (__raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; + + /* + * Copy the new maximum trace into the separate maximum-trace +@@ -654,7 +654,7 @@ static unsigned map_pid_to_cmdline[PID_M + static unsigned map_cmdline_to_pid[SAVED_CMDLINES]; + static char saved_cmdlines[SAVED_CMDLINES][TASK_COMM_LEN]; + static int cmdline_idx; +-static DEFINE_SPINLOCK(trace_cmdline_lock); ++static DEFINE_RAW_SPINLOCK(trace_cmdline_lock); + + /* temporary disable recording */ + atomic_t trace_record_cmdline_disabled __read_mostly; +@@ -3355,8 +3355,8 @@ __init static int tracer_alloc_buffers(v + /* use the LRU flag to differentiate the two buffers */ + ClearPageLRU(page); + +- data->lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; +- max_tr.data[i]->lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; ++ data->lock = (__raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; ++ max_tr.data[i]->lock = (__raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; + + /* Only allocate if we are actually using the max trace */ + #ifdef CONFIG_TRACER_MAX_TRACE +Index: linux-2.6.24.7-rt27/kernel/trace/trace.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace.h 2009-02-08 00:01:15.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace.h 2009-02-08 00:02:36.000000000 -0500 +@@ -162,7 +162,7 @@ struct trace_entry { + struct trace_array_cpu { + struct list_head trace_pages; + atomic_t disabled; +- raw_spinlock_t lock; ++ __raw_spinlock_t lock; + struct lock_class_key lock_key; + + /* these fields get copied into max-trace: */ +Index: linux-2.6.24.7-rt27/kernel/trace/trace_hist.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace_hist.c 2009-02-08 00:01:14.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace_hist.c 2009-02-08 00:02:36.000000000 -0500 +@@ -412,7 +412,7 @@ int tracing_wakeup_hist __read_mostly = + static unsigned wakeup_prio = (unsigned)-1 ; + static struct task_struct *wakeup_task; + static cycle_t wakeup_start; +-static DEFINE_SPINLOCK(wakeup_lock); ++static DEFINE_RAW_SPINLOCK(wakeup_lock); + + notrace void tracing_hist_wakeup_start(struct task_struct *p, + struct task_struct *curr) +Index: linux-2.6.24.7-rt27/kernel/trace/trace_irqsoff.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace_irqsoff.c 2009-02-08 00:01:14.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace_irqsoff.c 2009-02-08 00:02:36.000000000 -0500 +@@ -24,7 +24,7 @@ static int tracer_enabled __read_most + + static DEFINE_PER_CPU(int, tracing_cpu); + +-static DEFINE_SPINLOCK(max_trace_lock); ++static DEFINE_RAW_SPINLOCK(max_trace_lock); + + enum { + TRACER_IRQS_OFF = (1 << 1), +Index: linux-2.6.24.7-rt27/kernel/trace/trace_sched_wakeup.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace_sched_wakeup.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace_sched_wakeup.c 2009-02-08 00:02:36.000000000 -0500 +@@ -26,7 +26,7 @@ static struct task_struct *wakeup_task; + static int wakeup_cpu; + static unsigned wakeup_prio = -1; + +-static DEFINE_SPINLOCK(wakeup_lock); ++static DEFINE_RAW_SPINLOCK(wakeup_lock); + + static void __wakeup_reset(struct trace_array *tr); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0360-introduce-pick-function-macro.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0360-introduce-pick-function-macro.patch @@ -0,0 +1,252 @@ +From dwalker@mvista.com Wed Sep 26 21:44:14 2007 +Date: Tue, 28 Aug 2007 14:37:49 -0700 +From: Daniel Walker +To: mingo@elte.hu +Cc: mingo@redhat.com, linux-kernel@vger.kernel.org, + linux-rt-users@vger.kernel.org, Peter Zijlstra +Subject: [PATCH -rt 1/8] introduce PICK_FUNCTION + +PICK_FUNCTION() is similar to the other PICK_OP style macros, and was +created to replace them all. I used variable argument macros to handle +PICK_FUNC_2ARG/PICK_FUNC_1ARG. Otherwise the marcos are similar to the +original macros used for semaphores. The entire system is used to do a +compile time switch between two different locking APIs. For example, +real spinlocks (raw_spinlock_t) and mutexes (or sleeping spinlocks). + +This new macro replaces all the duplication from lock type to lock type. +The result of this patch, and the next two, is a fairly nice simplification, +and consolidation. Although the seqlock changes are larger than the originals +I think over all the patchset is worth while. + +Incorporated peterz's suggestion to not require TYPE_EQUAL() to only +use pointers. + +Signed-off-by: Daniel Walker + +--- + include/linux/pickop.h | 36 +++++++++++++ + include/linux/rt_lock.h | 129 +++++++++++++++--------------------------------- + 2 files changed, 77 insertions(+), 88 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/pickop.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7-rt27/include/linux/pickop.h 2009-02-08 00:03:41.000000000 -0500 +@@ -0,0 +1,36 @@ ++#ifndef _LINUX_PICKOP_H ++#define _LINUX_PICKOP_H ++ ++#undef TYPE_EQUAL ++#define TYPE_EQUAL(var, type) \ ++ __builtin_types_compatible_p(typeof(var), type *) ++ ++#undef PICK_TYPE_EQUAL ++#define PICK_TYPE_EQUAL(var, type) \ ++ __builtin_types_compatible_p(typeof(var), type) ++ ++extern int __bad_func_type(void); ++ ++#define PICK_FUNCTION(type1, type2, func1, func2, arg0, ...) \ ++do { \ ++ if (PICK_TYPE_EQUAL((arg0), type1)) \ ++ func1((type1)(arg0), ##__VA_ARGS__); \ ++ else if (PICK_TYPE_EQUAL((arg0), type2)) \ ++ func2((type2)(arg0), ##__VA_ARGS__); \ ++ else __bad_func_type(); \ ++} while (0) ++ ++#define PICK_FUNCTION_RET(type1, type2, func1, func2, arg0, ...) \ ++({ \ ++ unsigned long __ret; \ ++ \ ++ if (PICK_TYPE_EQUAL((arg0), type1)) \ ++ __ret = func1((type1)(arg0), ##__VA_ARGS__); \ ++ else if (PICK_TYPE_EQUAL((arg0), type2)) \ ++ __ret = func2((type2)(arg0), ##__VA_ARGS__); \ ++ else __ret = __bad_func_type(); \ ++ \ ++ __ret; \ ++}) ++ ++#endif /* _LINUX_PICKOP_H */ +Index: linux-2.6.24.7-rt27/include/linux/rt_lock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rt_lock.h 2009-02-08 00:03:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rt_lock.h 2009-02-08 00:03:41.000000000 -0500 +@@ -149,76 +149,40 @@ extern void fastcall rt_up(struct semaph + + extern int __bad_func_type(void); + +-#undef TYPE_EQUAL +-#define TYPE_EQUAL(var, type) \ +- __builtin_types_compatible_p(typeof(var), type *) +- +-#define PICK_FUNC_1ARG(type1, type2, func1, func2, arg) \ +-do { \ +- if (TYPE_EQUAL((arg), type1)) \ +- func1((type1 *)(arg)); \ +- else if (TYPE_EQUAL((arg), type2)) \ +- func2((type2 *)(arg)); \ +- else __bad_func_type(); \ +-} while (0) ++#include + +-#define PICK_FUNC_1ARG_RET(type1, type2, func1, func2, arg) \ +-({ \ +- unsigned long __ret; \ +- \ +- if (TYPE_EQUAL((arg), type1)) \ +- __ret = func1((type1 *)(arg)); \ +- else if (TYPE_EQUAL((arg), type2)) \ +- __ret = func2((type2 *)(arg)); \ +- else __ret = __bad_func_type(); \ +- \ +- __ret; \ +-}) +- +-#define PICK_FUNC_2ARG(type1, type2, func1, func2, arg0, arg1) \ +-do { \ +- if (TYPE_EQUAL((arg0), type1)) \ +- func1((type1 *)(arg0), arg1); \ +- else if (TYPE_EQUAL((arg0), type2)) \ +- func2((type2 *)(arg0), arg1); \ +- else __bad_func_type(); \ +-} while (0) ++/* ++ * PICK_SEM_OP() is a small redirector to allow less typing of the lock ++ * types struct compat_semaphore, struct semaphore, at the front of the ++ * PICK_FUNCTION macro. ++ */ ++#define PICK_SEM_OP(...) PICK_FUNCTION(struct compat_semaphore *, \ ++ struct semaphore *, ##__VA_ARGS__) ++#define PICK_SEM_OP_RET(...) PICK_FUNCTION_RET(struct compat_semaphore *,\ ++ struct semaphore *, ##__VA_ARGS__) + + #define sema_init(sem, val) \ +- PICK_FUNC_2ARG(struct compat_semaphore, struct semaphore, \ +- compat_sema_init, rt_sema_init, sem, val) ++ PICK_SEM_OP(compat_sema_init, rt_sema_init, sem, val) + +-#define init_MUTEX(sem) \ +- PICK_FUNC_1ARG(struct compat_semaphore, struct semaphore, \ +- compat_init_MUTEX, rt_init_MUTEX, sem) ++#define init_MUTEX(sem) PICK_SEM_OP(compat_init_MUTEX, rt_init_MUTEX, sem) + + #define init_MUTEX_LOCKED(sem) \ +- PICK_FUNC_1ARG(struct compat_semaphore, struct semaphore, \ +- compat_init_MUTEX_LOCKED, rt_init_MUTEX_LOCKED, sem) ++ PICK_SEM_OP(compat_init_MUTEX_LOCKED, rt_init_MUTEX_LOCKED, sem) + +-#define down(sem) \ +- PICK_FUNC_1ARG(struct compat_semaphore, struct semaphore, \ +- compat_down, rt_down, sem) ++#define down(sem) PICK_SEM_OP(compat_down, rt_down, sem) + + #define down_interruptible(sem) \ +- PICK_FUNC_1ARG_RET(struct compat_semaphore, struct semaphore, \ +- compat_down_interruptible, rt_down_interruptible, sem) ++ PICK_SEM_OP_RET(compat_down_interruptible, rt_down_interruptible, sem) + + #define down_trylock(sem) \ +- PICK_FUNC_1ARG_RET(struct compat_semaphore, struct semaphore, \ +- compat_down_trylock, rt_down_trylock, sem) ++ PICK_SEM_OP_RET(compat_down_trylock, rt_down_trylock, sem) + +-#define up(sem) \ +- PICK_FUNC_1ARG(struct compat_semaphore, struct semaphore, \ +- compat_up, rt_up, sem) ++#define up(sem) PICK_SEM_OP(compat_up, rt_up, sem) + + #define sem_is_locked(sem) \ +- PICK_FUNC_1ARG_RET(struct compat_semaphore, struct semaphore, \ +- compat_sem_is_locked, rt_sem_is_locked, sem) ++ PICK_SEM_OP_RET(compat_sem_is_locked, rt_sem_is_locked, sem) + +-#define sema_count(sem) \ +- PICK_FUNC_1ARG_RET(struct compat_semaphore, struct semaphore, \ +- compat_sema_count, rt_sema_count, sem) ++#define sema_count(sem) PICK_SEM_OP_RET(compat_sema_count, rt_sema_count, sem) + + /* + * rwsems: +@@ -260,58 +224,47 @@ extern void fastcall rt_downgrade_write( + + # define rt_rwsem_is_locked(rws) (rt_mutex_is_locked(&(rws)->lock)) + +-#define init_rwsem(rwsem) \ +- PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_init_rwsem, rt_init_rwsem, rwsem) +- +-#define down_read(rwsem) \ +- PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_down_read, rt_down_read, rwsem) ++#define PICK_RWSEM_OP(...) PICK_FUNCTION(struct compat_rw_semaphore *, \ ++ struct rw_semaphore *, ##__VA_ARGS__) ++#define PICK_RWSEM_OP_RET(...) PICK_FUNCTION_RET(struct compat_rw_semaphore *,\ ++ struct rw_semaphore *, ##__VA_ARGS__) ++ ++#define init_rwsem(rwsem) PICK_RWSEM_OP(compat_init_rwsem, rt_init_rwsem, rwsem) ++ ++#define down_read(rwsem) PICK_RWSEM_OP(compat_down_read, rt_down_read, rwsem) + + #define down_read_non_owner(rwsem) \ +- PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_down_read_non_owner, rt_down_read_non_owner, rwsem) ++ PICK_RWSEM_OP(compat_down_read_non_owner, rt_down_read_non_owner, rwsem) + + #define down_read_trylock(rwsem) \ +- PICK_FUNC_1ARG_RET(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_down_read_trylock, rt_down_read_trylock, rwsem) ++ PICK_RWSEM_OP_RET(compat_down_read_trylock, rt_down_read_trylock, rwsem) + +-#define down_write(rwsem) \ +- PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_down_write, rt_down_write, rwsem) ++#define down_write(rwsem) PICK_RWSEM_OP(compat_down_write, rt_down_write, rwsem) + + #define down_read_nested(rwsem, subclass) \ +- PICK_FUNC_2ARG(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_down_read_nested, rt_down_read_nested, rwsem, subclass) +- ++ PICK_RWSEM_OP(compat_down_read_nested, rt_down_read_nested, \ ++ rwsem, subclass) + + #define down_write_nested(rwsem, subclass) \ +- PICK_FUNC_2ARG(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_down_write_nested, rt_down_write_nested, rwsem, subclass) ++ PICK_RWSEM_OP(compat_down_write_nested, rt_down_write_nested, \ ++ rwsem, subclass) + + #define down_write_trylock(rwsem) \ +- PICK_FUNC_1ARG_RET(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_down_write_trylock, rt_down_write_trylock, rwsem) ++ PICK_RWSEM_OP_RET(compat_down_write_trylock, rt_down_write_trylock,\ ++ rwsem) + +-#define up_read(rwsem) \ +- PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_up_read, rt_up_read, rwsem) ++#define up_read(rwsem) PICK_RWSEM_OP(compat_up_read, rt_up_read, rwsem) + + #define up_read_non_owner(rwsem) \ +- PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_up_read_non_owner, rt_up_read_non_owner, rwsem) ++ PICK_RWSEM_OP(compat_up_read_non_owner, rt_up_read_non_owner, rwsem) + +-#define up_write(rwsem) \ +- PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_up_write, rt_up_write, rwsem) ++#define up_write(rwsem) PICK_RWSEM_OP(compat_up_write, rt_up_write, rwsem) + + #define downgrade_write(rwsem) \ +- PICK_FUNC_1ARG(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_downgrade_write, rt_downgrade_write, rwsem) ++ PICK_RWSEM_OP(compat_downgrade_write, rt_downgrade_write, rwsem) + + #define rwsem_is_locked(rwsem) \ +- PICK_FUNC_1ARG_RET(struct compat_rw_semaphore, struct rw_semaphore, \ +- compat_rwsem_is_locked, rt_rwsem_is_locked, rwsem) ++ PICK_RWSEM_OP_RET(compat_rwsem_is_locked, rt_rwsem_is_locked, rwsem) + + #endif /* CONFIG_PREEMPT_RT */ + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0486-nmi-show-regs-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0486-nmi-show-regs-fix.patch @@ -0,0 +1,183 @@ +From h-shimamoto@ct.jp.nec.com Tue May 27 19:37:24 2008 +Date: Tue, 27 May 2008 15:45:00 -0700 +From: Hiroshi Shimamoto +To: Steven Rostedt , Ingo Molnar , + Thomas Gleixner +Cc: linux-kernel@vger.kernel.org, linux-rt-users@vger.kernel.org +Subject: [PATCH -rt] fix sysrq+l when nmi_watchdog disabled + +From: Hiroshi Shimamoto + +In nmi_show_all_regs(), set nmi_show_regs for all cpus but NMI never come +to itself when nmi_watchdog is disabled. It means the kernel hangs up when +sysrq+l is issued. + +Call irq_show_regs_callback() itself before calling smp_send_nmi_allbutself(). + +Signed-off-by: Hiroshi Shimamoto +--- +Steven, this is a fix for what you pointed. +http://lkml.org/lkml/2008/4/28/455 + + arch/x86/kernel/nmi_32.c | 51 ++++++++++++++++++++++++++++------------------- + arch/x86/kernel/nmi_64.c | 49 +++++++++++++++++++++++++++++---------------- + 2 files changed, 63 insertions(+), 37 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_32.c 2009-02-08 00:04:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c 2009-02-08 00:04:41.000000000 -0500 +@@ -326,21 +326,49 @@ extern void die_nmi(struct pt_regs *, co + + int nmi_show_regs[NR_CPUS]; + ++static DEFINE_RAW_SPINLOCK(nmi_print_lock); ++ ++notrace int irq_show_regs_callback(int cpu, struct pt_regs *regs) ++{ ++ if (!nmi_show_regs[cpu]) ++ return 0; ++ ++ spin_lock(&nmi_print_lock); ++ printk(KERN_WARNING "NMI show regs on CPU#%d:\n", cpu); ++ printk(KERN_WARNING "apic_timer_irqs: %d\n", ++ per_cpu(irq_stat, cpu).apic_timer_irqs); ++ show_regs(regs); ++ spin_unlock(&nmi_print_lock); ++ nmi_show_regs[cpu] = 0; ++ return 1; ++} ++ + void nmi_show_all_regs(void) + { +- int i; ++ struct pt_regs *regs; ++ int i, cpu; + + if (system_state == SYSTEM_BOOTING) + return; + +- printk(KERN_WARNING "nmi_show_all_regs(): start on CPU#%d.\n", +- raw_smp_processor_id()); ++ preempt_disable(); ++ ++ regs = get_irq_regs(); ++ cpu = smp_processor_id(); ++ ++ printk(KERN_WARNING "nmi_show_all_regs(): start on CPU#%d.\n", cpu); + dump_stack(); + + for_each_online_cpu(i) + nmi_show_regs[i] = 1; + ++ if (regs) ++ irq_show_regs_callback(cpu, regs); ++ else ++ nmi_show_regs[cpu] = 0; ++ + smp_send_nmi_allbutself(); ++ preempt_enable(); + + for_each_online_cpu(i) { + while (nmi_show_regs[i] == 1) +@@ -348,23 +376,6 @@ void nmi_show_all_regs(void) + } + } + +-static DEFINE_RAW_SPINLOCK(nmi_print_lock); +- +-notrace int irq_show_regs_callback(int cpu, struct pt_regs *regs) +-{ +- if (!nmi_show_regs[cpu]) +- return 0; +- +- spin_lock(&nmi_print_lock); +- printk(KERN_WARNING "NMI show regs on CPU#%d:\n", cpu); +- printk(KERN_WARNING "apic_timer_irqs: %d\n", +- per_cpu(irq_stat, cpu).apic_timer_irqs); +- show_regs(regs); +- spin_unlock(&nmi_print_lock); +- nmi_show_regs[cpu] = 0; +- return 1; +-} +- + notrace __kprobes int + nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) + { +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_64.c 2009-02-08 00:04:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c 2009-02-08 00:04:41.000000000 -0500 +@@ -320,17 +320,48 @@ void touch_nmi_watchdog(void) + + int nmi_show_regs[NR_CPUS]; + ++static DEFINE_RAW_SPINLOCK(nmi_print_lock); ++ ++notrace int irq_show_regs_callback(int cpu, struct pt_regs *regs) ++{ ++ if (!nmi_show_regs[cpu]) ++ return 0; ++ ++ spin_lock(&nmi_print_lock); ++ printk(KERN_WARNING "NMI show regs on CPU#%d:\n", cpu); ++ printk(KERN_WARNING "apic_timer_irqs: %d\n", read_pda(apic_timer_irqs)); ++ show_regs(regs); ++ spin_unlock(&nmi_print_lock); ++ nmi_show_regs[cpu] = 0; ++ return 1; ++} ++ + void nmi_show_all_regs(void) + { +- int i; ++ struct pt_regs *regs; ++ int i, cpu; + + if (system_state == SYSTEM_BOOTING) + return; + ++ preempt_disable(); ++ ++ regs = get_irq_regs(); ++ cpu = smp_processor_id(); ++ ++ printk(KERN_WARNING "nmi_show_all_regs(): start on CPU#%d.\n", cpu); ++ dump_stack(); ++ + for_each_online_cpu(i) + nmi_show_regs[i] = 1; + ++ if (regs) ++ irq_show_regs_callback(cpu, regs); ++ else ++ nmi_show_regs[cpu] = 0; ++ + smp_send_nmi_allbutself(); ++ preempt_enable(); + + for_each_online_cpu(i) { + while (nmi_show_regs[i] == 1) +@@ -338,22 +369,6 @@ void nmi_show_all_regs(void) + } + } + +-static DEFINE_RAW_SPINLOCK(nmi_print_lock); +- +-notrace int irq_show_regs_callback(int cpu, struct pt_regs *regs) +-{ +- if (!nmi_show_regs[cpu]) +- return 0; +- +- spin_lock(&nmi_print_lock); +- printk(KERN_WARNING "NMI show regs on CPU#%d:\n", cpu); +- printk(KERN_WARNING "apic_timer_irqs: %d\n", read_pda(apic_timer_irqs)); +- show_regs(regs); +- spin_unlock(&nmi_print_lock); +- nmi_show_regs[cpu] = 0; +- return 1; +-} +- + notrace int __kprobes + nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) + { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0088-neptune-no-at-keyboard.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0088-neptune-no-at-keyboard.patch @@ -0,0 +1,64 @@ +neptune needs this to boot ... +--- + drivers/input/keyboard/atkbd.c | 14 ++++++++++++++ + drivers/input/mouse/psmouse-base.c | 15 +++++++++++++++ + 2 files changed, 29 insertions(+) + +Index: linux-2.6.24.7-rt27/drivers/input/keyboard/atkbd.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/input/keyboard/atkbd.c 2009-02-08 00:00:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/input/keyboard/atkbd.c 2009-02-08 00:01:24.000000000 -0500 +@@ -1401,9 +1401,23 @@ static ssize_t atkbd_show_err_count(stru + return sprintf(buf, "%lu\n", atkbd->err_count); + } + ++static int __read_mostly noatkbd; ++ ++static int __init noatkbd_setup(char *str) ++{ ++ noatkbd = 1; ++ printk(KERN_INFO "debug: not setting up AT keyboard.\n"); ++ ++ return 1; ++} ++ ++__setup("noatkbd", noatkbd_setup); + + static int __init atkbd_init(void) + { ++ if (noatkbd) ++ return 0; ++ + return serio_register_driver(&atkbd_drv); + } + +Index: linux-2.6.24.7-rt27/drivers/input/mouse/psmouse-base.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/input/mouse/psmouse-base.c 2009-02-08 00:00:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/input/mouse/psmouse-base.c 2009-02-08 00:01:24.000000000 -0500 +@@ -1598,10 +1598,25 @@ static int psmouse_get_maxproto(char *bu + return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name); + } + ++static int __read_mostly nopsmouse; ++ ++static int __init nopsmouse_setup(char *str) ++{ ++ nopsmouse = 1; ++ printk(KERN_INFO "debug: not setting up psmouse.\n"); ++ ++ return 1; ++} ++ ++__setup("nopsmouse", nopsmouse_setup); ++ + static int __init psmouse_init(void) + { + int err; + ++ if (nopsmouse) ++ return 0; ++ + kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); + if (!kpsmoused_wq) { + printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n"); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0351-fix-alternate_node_alloc.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0351-fix-alternate_node_alloc.patch @@ -0,0 +1,71 @@ +From ak@suse.de Wed Sep 26 10:34:53 2007 +Date: Mon, 17 Sep 2007 15:36:59 +0200 +From: Andi Kleen +To: mingo@elte.hu, Thomas Gleixner +Cc: linux-rt-users@vger.kernel.org +Subject: [PATCH] Fix alternate_node_alloc() on RT kernel + + +__do_cache_allow/alternate_node_alloc() need to pass the this_cpu variable from +the caller to cache_grow(); otherwise the slab lock for the wrong CPU +can be released when a task switches CPUs inside cache_grow(). + +Signed-off-by: Andi Kleen + +--- + mm/slab.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/mm/slab.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/slab.c 2009-02-08 00:03:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/slab.c 2009-02-08 00:03:37.000000000 -0500 +@@ -1069,7 +1069,7 @@ cache_free_alien(struct kmem_cache *cach + } + + static inline void *alternate_node_alloc(struct kmem_cache *cachep, +- gfp_t flags) ++ gfp_t flags, int *this_cpu) + { + return NULL; + } +@@ -1084,7 +1084,7 @@ static inline void *____cache_alloc_node + + static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, + int nodeid, int *this_cpu); +-static void *alternate_node_alloc(struct kmem_cache *, gfp_t); ++static void *alternate_node_alloc(struct kmem_cache *, gfp_t, int *); + + static struct array_cache **alloc_alien_cache(int node, int limit) + { +@@ -3331,9 +3331,10 @@ ____cache_alloc(struct kmem_cache *cache + * If we are in_interrupt, then process context, including cpusets and + * mempolicy, may not apply and should not be used for allocation policy. + */ +-static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags) ++static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags, ++ int *this_cpu) + { +- int nid_alloc, nid_here, this_cpu = raw_smp_processor_id(); ++ int nid_alloc, nid_here; + + if (in_interrupt() || (flags & __GFP_THISNODE)) + return NULL; +@@ -3343,7 +3344,7 @@ static void *alternate_node_alloc(struct + else if (current->mempolicy) + nid_alloc = slab_node(current->mempolicy); + if (nid_alloc != nid_here) +- return ____cache_alloc_node(cachep, flags, nid_alloc, &this_cpu); ++ return ____cache_alloc_node(cachep, flags, nid_alloc, this_cpu); + return NULL; + } + +@@ -3556,7 +3557,7 @@ __do_cache_alloc(struct kmem_cache *cach + void *objp; + + if (unlikely(current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY))) { +- objp = alternate_node_alloc(cache, flags); ++ objp = alternate_node_alloc(cache, flags, this_cpu); + if (objp) + goto out; + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0364-fork-desched_thread-comment-rework.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0364-fork-desched_thread-comment-rework.patch @@ -0,0 +1,33 @@ +From dwalker@mvista.com Wed Sep 26 22:18:23 2007 +Date: Tue, 28 Aug 2007 14:37:52 -0700 +From: Daniel Walker +To: mingo@elte.hu +Cc: mingo@redhat.com, linux-kernel@vger.kernel.org, + linux-rt-users@vger.kernel.org +Subject: [PATCH -rt 4/8] fork: desched_thread comment rework. + +Lines are too long.. + +Signed-off-by: Daniel Walker + +--- + kernel/fork.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/fork.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/fork.c 2009-02-08 00:03:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/fork.c 2009-02-08 00:03:43.000000000 -0500 +@@ -1839,8 +1839,10 @@ static int desched_thread(void * __bind_ + continue; + schedule(); + +- /* This must be called from time to time on ia64, and is a no-op on other archs. +- * Used to be in cpu_idle(), but with the new -rt semantics it can't stay there. ++ /* ++ * This must be called from time to time on ia64, and is a ++ * no-op on other archs. Used to be in cpu_idle(), but with ++ * the new -rt semantics it can't stay there. + */ + check_pgt_cache(); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0091-kprobes-preempt-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0091-kprobes-preempt-fix.patch @@ -0,0 +1,52 @@ + arch/x86/kernel/kprobes_32.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/kprobes_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/kprobes_32.c 2009-02-08 00:00:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/kprobes_32.c 2009-02-08 00:01:25.000000000 -0500 +@@ -332,7 +332,7 @@ ss_probe: + /* Boost up -- we can execute copied instructions directly */ + reset_current_kprobe(); + regs->eip = (unsigned long)p->ainsn.insn; +- preempt_enable_no_resched(); ++ preempt_enable(); + return 1; + } + #endif +@@ -341,7 +341,7 @@ ss_probe: + return 1; + + no_kprobe: +- preempt_enable_no_resched(); ++ preempt_enable(); + return ret; + } + +@@ -573,7 +573,7 @@ static int __kprobes post_kprobe_handler + } + reset_current_kprobe(); + out: +- preempt_enable_no_resched(); ++ preempt_enable(); + + /* + * if somebody else is singlestepping across a probe point, eflags +@@ -607,7 +607,7 @@ int __kprobes kprobe_fault_handler(struc + restore_previous_kprobe(kcb); + else + reset_current_kprobe(); +- preempt_enable_no_resched(); ++ preempt_enable(); + break; + case KPROBE_HIT_ACTIVE: + case KPROBE_HIT_SSDONE: +@@ -739,7 +739,7 @@ int __kprobes longjmp_break_handler(stru + *regs = kcb->jprobe_saved_regs; + memcpy((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack, + MIN_STACK_SIZE(stack_addr)); +- preempt_enable_no_resched(); ++ preempt_enable(); + return 1; + } + return 0; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0140-preempt-irqs-softirq-in-hardirq.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0140-preempt-irqs-softirq-in-hardirq.patch @@ -0,0 +1,77 @@ +--- + include/linux/interrupt.h | 1 + + kernel/softirq.c | 35 +++++++++++++++++++++++++++++++++++ + 2 files changed, 36 insertions(+) + +Index: linux-2.6.24.7-rt27/include/linux/interrupt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/interrupt.h 2009-02-08 00:01:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/interrupt.h 2009-02-08 00:01:49.000000000 -0500 +@@ -277,6 +277,7 @@ struct softirq_action + asmlinkage void do_softirq(void); + extern void open_softirq(int nr, void (*action)(struct softirq_action*), void *data); + extern void softirq_init(void); ++extern void do_softirq_from_hardirq(void); + + #ifdef CONFIG_PREEMPT_HARDIRQS + # define __raise_softirq_irqoff(nr) raise_softirq_irqoff(nr) +Index: linux-2.6.24.7-rt27/kernel/softirq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/softirq.c 2009-02-08 00:01:48.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/softirq.c 2009-02-08 00:01:49.000000000 -0500 +@@ -296,6 +296,8 @@ restart: + + asmlinkage void __do_softirq(void) + { ++ unsigned long p_flags; ++ + #ifdef CONFIG_PREEMPT_SOFTIRQS + /* + * 'preempt harder'. Push all softirq processing off to ksoftirqd. +@@ -311,6 +313,38 @@ asmlinkage void __do_softirq(void) + */ + __local_bh_disable((unsigned long)__builtin_return_address(0)); + trace_softirq_enter(); ++ p_flags = current->flags & PF_HARDIRQ; ++ current->flags &= ~PF_HARDIRQ; ++ ++ ___do_softirq(); ++ ++ trace_softirq_exit(); ++ ++ account_system_vtime(current); ++ _local_bh_enable(); ++ ++ current->flags |= p_flags; ++} ++ ++/* ++ * Process softirqs straight from hardirq context, ++ * without having to switch to a softirq thread. ++ * This can reduce the context-switch rate. ++ * ++ * NOTE: this is unused right now. ++ */ ++void do_softirq_from_hardirq(void) ++{ ++ unsigned long p_flags; ++ ++ if (!local_softirq_pending()) ++ return; ++ /* ++ * 'immediate' softirq execution: ++ */ ++ __local_bh_disable((unsigned long)__builtin_return_address(0)); ++ p_flags = current->flags & PF_HARDIRQ; ++ current->flags &= ~PF_HARDIRQ; + + ___do_softirq(); + +@@ -319,6 +353,7 @@ asmlinkage void __do_softirq(void) + account_system_vtime(current); + _local_bh_enable(); + ++ current->flags |= p_flags; + } + + #ifndef __ARCH_HAS_DO_SOFTIRQ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0563-rtmutex-fix-rwlock-boosting.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0563-rtmutex-fix-rwlock-boosting.patch @@ -0,0 +1,49 @@ +Subject: rtmutex: fix rwlock boosting +From: Thomas Gleixner +Date: Sat, 06 Dec 2008 17:11:51 +0100 + +The rwlock boosting code path does not boost the first task in the +chain, which is defeating the whole purpose of PI. + +I have no idea why this basic functionality was never +checked. rtmutex-tester is exactly for this kind of static testing and +should be extended with proper rwlock tests ASAP. + +Signed-off-by: Thomas Gleixner +--- + kernel/rtmutex.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:05:19.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:05:19.000000000 -0500 +@@ -2269,15 +2269,25 @@ static int rt_mutex_adjust_readers(struc + } + + list_for_each_entry(rls, &rwm->readers, list) { ++ int chain_walk = 0; ++ + task = rls->task; + get_task_struct(task); ++ ++ spin_lock(&task->pi_lock); ++ __rt_mutex_adjust_prio(task); ++ if (task->pi_blocked_on) ++ chain_walk = 1; ++ spin_unlock(&task->pi_lock); ++ + /* + * rt_mutex_adjust_prio_chain will do + * the put_task_struct + */ +- rt_mutex_adjust_prio_chain(task, 0, orig_lock, +- orig_waiter, top_task, +- recursion_depth+1); ++ if (chain_walk) ++ rt_mutex_adjust_prio_chain(task, 0, orig_lock, ++ orig_waiter, top_task, ++ recursion_depth + 1); + } + + return 0; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0152-preempt-irqs-ppc-ack-irq-fixups.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0152-preempt-irqs-ppc-ack-irq-fixups.patch @@ -0,0 +1,74 @@ +As fasteoi type chips never had to define their ack() method before the +recent Ingo's change to handle_fasteoi_irq(), any attempt to execute handler +in thread resulted in the kernel crash. So, define their ack() methods to be +the same as their eoi() ones... + +Signed-off-by: Sergei Shtylyov + +--- +Since there was no feedback on three solutions I suggested, I'm going the way +of least resistance and making the fasteoi type chips behave the way that +handle_fasteoi_irq() is expecting from them... + + arch/powerpc/platforms/cell/interrupt.c | 1 + + arch/powerpc/platforms/iseries/irq.c | 1 + + arch/powerpc/platforms/pseries/xics.c | 2 ++ + arch/powerpc/sysdev/mpic.c | 1 + + 4 files changed, 5 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/cell/interrupt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/cell/interrupt.c 2009-02-08 00:00:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/cell/interrupt.c 2009-02-08 00:01:54.000000000 -0500 +@@ -90,6 +90,7 @@ static struct irq_chip iic_chip = { + .typename = " CELL-IIC ", + .mask = iic_mask, + .unmask = iic_unmask, ++ .ack = iic_eoi, + .eoi = iic_eoi, + }; + +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/iseries/irq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/iseries/irq.c 2009-02-08 00:00:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/iseries/irq.c 2009-02-08 00:01:54.000000000 -0500 +@@ -278,6 +278,7 @@ static struct irq_chip iseries_pic = { + .shutdown = iseries_shutdown_IRQ, + .unmask = iseries_enable_IRQ, + .mask = iseries_disable_IRQ, ++ .ack = iseries_end_IRQ, + .eoi = iseries_end_IRQ + }; + +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/pseries/xics.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/pseries/xics.c 2009-02-08 00:00:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/pseries/xics.c 2009-02-08 00:01:54.000000000 -0500 +@@ -461,6 +461,7 @@ static struct irq_chip xics_pic_direct = + .startup = xics_startup, + .mask = xics_mask_irq, + .unmask = xics_unmask_irq, ++ .ack = xics_eoi_direct, + .eoi = xics_eoi_direct, + .set_affinity = xics_set_affinity + }; +@@ -471,6 +472,7 @@ static struct irq_chip xics_pic_lpar = { + .startup = xics_startup, + .mask = xics_mask_irq, + .unmask = xics_unmask_irq, ++ .ack = xics_eoi_lpar, + .eoi = xics_eoi_lpar, + .set_affinity = xics_set_affinity + }; +Index: linux-2.6.24.7-rt27/arch/powerpc/sysdev/mpic.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/sysdev/mpic.c 2009-02-08 00:00:13.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/sysdev/mpic.c 2009-02-08 00:01:54.000000000 -0500 +@@ -845,6 +845,7 @@ int mpic_set_irq_type(unsigned int virq, + static struct irq_chip mpic_irq_chip = { + .mask = mpic_mask_irq, + .unmask = mpic_unmask_irq, ++ .ack = mpic_end_irq, + .eoi = mpic_end_irq, + .set_type = mpic_set_irq_type, + }; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0344-cond_resched_softirq-WARN-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0344-cond_resched_softirq-WARN-fix.patch @@ -0,0 +1,24 @@ +Subject: [BUG RT] WARNING: at kernel/sched.c:5071 2.6.23-rc1-rt7 +From: Steven Rostedt + +The below ifndef, shouldn't that be ifndef CONFIG_PREEMPT_SOFTIRQS ? +I hit that warning while I was running !PREEMPT_RT but with both hard +and softiqs as threads. + +--- + kernel/sched.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:03:32.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:03:34.000000000 -0500 +@@ -5071,7 +5071,7 @@ EXPORT_SYMBOL(__cond_resched_spinlock); + */ + int __sched cond_resched_softirq(void) + { +-#ifndef CONFIG_PREEMPT_RT ++#ifndef CONFIG_PREEMPT_SOFTIRQS + WARN_ON_ONCE(!in_softirq()); + #endif + if (need_resched() && system_state == SYSTEM_RUNNING) { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0559-rwlock-handle-bad-locking-practices.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0559-rwlock-handle-bad-locking-practices.patch @@ -0,0 +1,99 @@ +From: Steven Rostedt +Subject: rt: rwlock fix non nested unlocking + +The RW PI locks are sensitive to locking and unlocking order. This is +a bug, since it is not always the case that unlocking will be in the +reverse order of locking. + +This patch lets there be "holes" in the rwlock array for a task. The holes +are caused when a lock is released out of order. + +Signed-off-by: Steven Rostedt +--- + kernel/rtmutex.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 48 insertions(+), 8 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:05:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:05:16.000000000 -0500 +@@ -1739,10 +1739,21 @@ rt_read_slowunlock(struct rw_mutex *rwm, + spin_lock(¤t->pi_lock); + current->owned_read_locks[i].count--; + if (!current->owned_read_locks[i].count) { +- current->reader_lock_count--; +- WARN_ON_ONCE(i != current->reader_lock_count); +- atomic_dec(&rwm->owners); ++ if (likely(i == current->reader_lock_count - 1)) { ++ int count = --current->reader_lock_count; ++ ++ /* check for holes */ ++ for (count--; count >= 0; count--) { ++ rls = ¤t->owned_read_locks[count]; ++ if (likely(rls->lock)) ++ break; ++ current->reader_lock_count--; ++ } ++ WARN_ON(current->reader_lock_count < 0); ++ } /* else ... Bah! bad locking practice */ + rls = ¤t->owned_read_locks[i]; ++ ++ atomic_dec(&rwm->owners); + WARN_ON(!rls->list.prev || list_empty(&rls->list)); + list_del_init(&rls->list); + rls->lock = NULL; +@@ -1879,20 +1890,49 @@ rt_read_fastunlock(struct rw_mutex *rwm, + int owners; + + spin_lock_irqsave(¤t->pi_lock, flags); +- reader_count = --current->reader_lock_count; +- spin_unlock_irqrestore(¤t->pi_lock, flags); +- +- rt_mutex_deadlock_account_unlock(current); ++ reader_count = current->reader_lock_count - 1; + if (unlikely(reader_count < 0)) { + reader_count = 0; + WARN_ON_ONCE(1); + } ++ rls = ¤t->owned_read_locks[reader_count]; ++ if (unlikely(rls->lock != rwm)) { ++ int i; ++ ++ /* Bah! Bad locking practice! */ ++ for (i = reader_count - 1; i >= 0; i--) { ++ rls = ¤t->owned_read_locks[i]; ++ if (rls->lock == rwm) ++ break; ++ } ++ if (unlikely(i < 0)) { ++ /* We don't own the lock?? */ ++ WARN_ON_ONCE(1); ++ spin_unlock_irqrestore(¤t->pi_lock, flags); ++ return; ++ } ++ /* We will have a hole */ ++ } else { ++ struct reader_lock_struct *rs; ++ int count = --current->reader_lock_count; ++ ++ /* check for holes */ ++ for (count--; count >= 0; count--) { ++ rs = ¤t->owned_read_locks[count]; ++ if (likely(rs->lock)) ++ break; ++ current->reader_lock_count--; ++ } ++ WARN_ON(current->reader_lock_count < 0); ++ } ++ spin_unlock_irqrestore(¤t->pi_lock, flags); ++ ++ rt_mutex_deadlock_account_unlock(current); + owners = atomic_dec_return(&rwm->owners); + if (unlikely(owners < 0)) { + atomic_set(&rwm->owners, 0); + WARN_ON_ONCE(1); + } +- rls = ¤t->owned_read_locks[reader_count]; + WARN_ON_ONCE(rls->lock != rwm); + WARN_ON(rls->list.prev && !list_empty(&rls->list)); + WARN_ON(rls->count != 1); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0372-rcupreempt-boost-early-init.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0372-rcupreempt-boost-early-init.patch @@ -0,0 +1,98 @@ +--- + include/linux/rcuclassic.h | 1 + + include/linux/rcupreempt.h | 8 +++++++- + kernel/rcupreempt-boost.c | 16 +++++++++++----- + kernel/rcupreempt.c | 1 + + 4 files changed, 20 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/rcuclassic.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcuclassic.h 2009-02-08 00:01:43.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcuclassic.h 2009-02-08 00:03:47.000000000 -0500 +@@ -88,6 +88,7 @@ static inline void rcu_bh_qsctr_inc(int + #define rcu_process_callbacks_rt(unused) do { } while (0) + #define rcu_enter_nohz() do { } while (0) + #define rcu_exit_nohz() do { } while (0) ++#define rcu_preempt_boost_init() do { } while (0) + + extern void FASTCALL(call_rcu_classic(struct rcu_head *head, + void (*func)(struct rcu_head *head))); +Index: linux-2.6.24.7-rt27/include/linux/rcupreempt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupreempt.h 2009-02-08 00:03:45.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupreempt.h 2009-02-08 00:03:47.000000000 -0500 +@@ -60,7 +60,13 @@ enum rcu_boost_state { + + #define N_RCU_BOOST_STATE (RCU_BOOST_INVALID + 1) + +-#endif /* #ifdef CONFIG_PREEMPT_RCU_BOOST */ ++int __init rcu_preempt_boost_init(void); ++ ++#else /* CONFIG_PREEPMT_RCU_BOOST */ ++ ++#define rcu_preempt_boost_init() do { } while (0) ++ ++#endif /* CONFIG_PREEMPT_RCU_BOOST */ + + /* + * Someone might want to pass call_rcu_bh as a function pointer. +Index: linux-2.6.24.7-rt27/kernel/rcupreempt-boost.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt-boost.c 2009-02-08 00:03:46.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt-boost.c 2009-02-08 00:03:47.000000000 -0500 +@@ -174,9 +174,9 @@ int rcu_trace_boost_create(struct dentry + rcuboostdir = debugfs_create_file("rcuboost", 0444, rcudir, + NULL, &rcuboost_fops); + if (!rcuboostdir) +- return 1; ++ return 0; + +- return 0; ++ return 1; + } + EXPORT_SYMBOL_GPL(rcu_trace_boost_create); + +@@ -552,10 +552,9 @@ static int krcupreemptd(void *data) + return 0; + } + +-static int __init rcu_preempt_boost_init(void) ++int __init rcu_preempt_boost_init(void) + { + struct rcu_boost_dat *rbd; +- struct task_struct *p; + int cpu; + + for_each_possible_cpu(cpu) { +@@ -567,6 +566,13 @@ static int __init rcu_preempt_boost_init + INIT_LIST_HEAD(&rbd->rbs_boosted); + } + ++ return 0; ++} ++ ++static int __init rcu_preempt_start_krcupreemptd(void) ++{ ++ struct task_struct *p; ++ + p = kthread_create(krcupreemptd, NULL, + "krcupreemptd"); + +@@ -579,4 +585,4 @@ static int __init rcu_preempt_boost_init + return 0; + } + +-core_initcall(rcu_preempt_boost_init); ++__initcall(rcu_preempt_start_krcupreemptd); +Index: linux-2.6.24.7-rt27/kernel/rcupreempt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt.c 2009-02-08 00:03:46.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt.c 2009-02-08 00:03:47.000000000 -0500 +@@ -995,6 +995,7 @@ void __init rcu_init_rt(void) + rdp->donelist = NULL; + rdp->donetail = &rdp->donelist; + } ++ rcu_preempt_boost_init(); + } + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0447-rwlocks-lateral-steal.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0447-rwlocks-lateral-steal.patch @@ -0,0 +1,238 @@ +From: Steven Rostedt + +Added lateral steal for rwlocks. + +Signed-off-by: Steven Rostedt + +--- + kernel/rtmutex.c | 58 +++++++++++++++++++++++++++++-------------------------- + 1 file changed, 31 insertions(+), 27 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:23.000000000 -0500 +@@ -1033,7 +1033,7 @@ update_rw_mutex_owner(struct rw_mutex *r + rt_mutex_set_owner(mutex, mtxowner, 0); + } + +-static int try_to_take_rw_read(struct rw_mutex *rwm) ++static int try_to_take_rw_read(struct rw_mutex *rwm, int mtx) + { + struct rt_mutex *mutex = &rwm->mutex; + struct rt_mutex_waiter *waiter; +@@ -1059,7 +1059,9 @@ static int try_to_take_rw_read(struct rw + } + + if (mtxowner && mtxowner != RT_RW_READER) { +- if (!try_to_steal_lock(mutex)) { ++ int mode = mtx ? STEAL_NORMAL : STEAL_LATERAL; ++ ++ if (!try_to_steal_lock(mutex, mode)) { + /* + * readers don't own the mutex, and rwm shows that a + * writer doesn't have it either. If we enter this +@@ -1076,7 +1078,7 @@ static int try_to_take_rw_read(struct rw + if (rt_mutex_has_waiters(mutex)) { + /* readers don't do PI */ + waiter = rt_mutex_top_waiter(mutex); +- if (current->prio >= waiter->task->prio) ++ if (!lock_is_stealable(waiter->task, mode)) + return 0; + /* + * The pending reader has PI waiters, +@@ -1107,7 +1109,7 @@ static int try_to_take_rw_read(struct rw + } + + static int +-try_to_take_rw_write(struct rw_mutex *rwm) ++try_to_take_rw_write(struct rw_mutex *rwm, int mtx) + { + struct rt_mutex *mutex = &rwm->mutex; + struct task_struct *own; +@@ -1129,7 +1131,7 @@ try_to_take_rw_write(struct rw_mutex *rw + */ + WARN_ON(own && !rt_mutex_owner_pending(mutex)); + +- if (!try_to_take_rt_mutex(mutex)) ++ if (!do_try_to_take_rt_mutex(mutex, mtx ? STEAL_NORMAL : STEAL_LATERAL)) + return 0; + + /* +@@ -1142,7 +1144,7 @@ try_to_take_rw_write(struct rw_mutex *rw + } + + static void +-rt_read_slowlock(struct rw_mutex *rwm) ++rt_read_slowlock(struct rw_mutex *rwm, int mtx) + { + struct rt_mutex_waiter waiter; + struct rt_mutex *mutex = &rwm->mutex; +@@ -1152,7 +1154,7 @@ rt_read_slowlock(struct rw_mutex *rwm) + spin_lock_irqsave(&mutex->wait_lock, flags); + init_lists(mutex); + +- if (try_to_take_rw_read(rwm)) { ++ if (try_to_take_rw_read(rwm, mtx)) { + spin_unlock_irqrestore(&mutex->wait_lock, flags); + return; + } +@@ -1178,7 +1180,7 @@ rt_read_slowlock(struct rw_mutex *rwm) + unsigned long saved_flags; + + /* Try to acquire the lock: */ +- if (try_to_take_rw_read(rwm)) ++ if (try_to_take_rw_read(rwm, mtx)) + break; + update_rw_mutex_owner(rwm); + +@@ -1230,7 +1232,8 @@ rt_read_slowlock(struct rw_mutex *rwm) + + static inline void + rt_read_fastlock(struct rw_mutex *rwm, +- void fastcall (*slowfn)(struct rw_mutex *rwm)) ++ void fastcall (*slowfn)(struct rw_mutex *rwm, int mtx), ++ int mtx) + { + retry: + if (likely(rt_rwlock_cmpxchg(rwm, NULL, current))) { +@@ -1246,17 +1249,17 @@ retry: + goto retry; + } + } else +- slowfn(rwm); ++ slowfn(rwm, mtx); + } + + void fastcall rt_mutex_down_read(struct rw_mutex *rwm) + { +- rt_read_fastlock(rwm, rt_read_slowlock); ++ rt_read_fastlock(rwm, rt_read_slowlock, 1); + } + + + static inline int +-rt_read_slowtrylock(struct rw_mutex *rwm) ++rt_read_slowtrylock(struct rw_mutex *rwm, int mtx) + { + struct rt_mutex *mutex = &rwm->mutex; + unsigned long flags; +@@ -1265,7 +1268,7 @@ rt_read_slowtrylock(struct rw_mutex *rwm + spin_lock_irqsave(&mutex->wait_lock, flags); + init_lists(mutex); + +- if (try_to_take_rw_read(rwm)) ++ if (try_to_take_rw_read(rwm, mtx)) + ret = 1; + + spin_unlock_irqrestore(&mutex->wait_lock, flags); +@@ -1275,7 +1278,7 @@ rt_read_slowtrylock(struct rw_mutex *rwm + + static inline int + rt_read_fasttrylock(struct rw_mutex *rwm, +- int fastcall (*slowfn)(struct rw_mutex *rwm)) ++ int fastcall (*slowfn)(struct rw_mutex *rwm, int mtx), int mtx) + { + retry: + if (likely(rt_rwlock_cmpxchg(rwm, NULL, current))) { +@@ -1292,16 +1295,16 @@ retry: + } + return 1; + } else +- return slowfn(rwm); ++ return slowfn(rwm, mtx); + } + + int __sched rt_mutex_down_read_trylock(struct rw_mutex *rwm) + { +- return rt_read_fasttrylock(rwm, rt_read_slowtrylock); ++ return rt_read_fasttrylock(rwm, rt_read_slowtrylock, 1); + } + + static void +-rt_write_slowlock(struct rw_mutex *rwm) ++rt_write_slowlock(struct rw_mutex *rwm, int mtx) + { + struct rt_mutex *mutex = &rwm->mutex; + struct rt_mutex_waiter waiter; +@@ -1317,7 +1320,7 @@ rt_write_slowlock(struct rw_mutex *rwm) + spin_lock_irqsave(&mutex->wait_lock, flags); + init_lists(mutex); + +- if (try_to_take_rw_write(rwm)) { ++ if (try_to_take_rw_write(rwm, mtx)) { + spin_unlock_irqrestore(&mutex->wait_lock, flags); + return; + } +@@ -1335,7 +1338,7 @@ rt_write_slowlock(struct rw_mutex *rwm) + unsigned long saved_flags; + + /* Try to acquire the lock: */ +- if (try_to_take_rw_write(rwm)) ++ if (try_to_take_rw_write(rwm, mtx)) + break; + update_rw_mutex_owner(rwm); + +@@ -1389,7 +1392,8 @@ rt_write_slowlock(struct rw_mutex *rwm) + + static inline void + rt_write_fastlock(struct rw_mutex *rwm, +- void fastcall (*slowfn)(struct rw_mutex *rwm)) ++ void fastcall (*slowfn)(struct rw_mutex *rwm, int mtx), ++ int mtx) + { + unsigned long val = (unsigned long)current | RT_RWLOCK_WRITER; + +@@ -1397,16 +1401,16 @@ rt_write_fastlock(struct rw_mutex *rwm, + rt_mutex_deadlock_account_lock(&rwm->mutex, current); + WARN_ON(atomic_read(&rwm->count)); + } else +- slowfn(rwm); ++ slowfn(rwm, mtx); + } + + void fastcall rt_mutex_down_write(struct rw_mutex *rwm) + { +- rt_write_fastlock(rwm, rt_write_slowlock); ++ rt_write_fastlock(rwm, rt_write_slowlock, 1); + } + + static int +-rt_write_slowtrylock(struct rw_mutex *rwm) ++rt_write_slowtrylock(struct rw_mutex *rwm, int mtx) + { + struct rt_mutex *mutex = &rwm->mutex; + unsigned long flags; +@@ -1415,7 +1419,7 @@ rt_write_slowtrylock(struct rw_mutex *rw + spin_lock_irqsave(&mutex->wait_lock, flags); + init_lists(mutex); + +- if (try_to_take_rw_write(rwm)) ++ if (try_to_take_rw_write(rwm, mtx)) + ret = 1; + + spin_unlock_irqrestore(&mutex->wait_lock, flags); +@@ -1425,7 +1429,7 @@ rt_write_slowtrylock(struct rw_mutex *rw + + static inline int + rt_write_fasttrylock(struct rw_mutex *rwm, +- int fastcall (*slowfn)(struct rw_mutex *rwm)) ++ int fastcall (*slowfn)(struct rw_mutex *rwm, int mtx), int mtx) + { + unsigned long val = (unsigned long)current | RT_RWLOCK_WRITER; + +@@ -1434,12 +1438,12 @@ rt_write_fasttrylock(struct rw_mutex *rw + WARN_ON(atomic_read(&rwm->count)); + return 1; + } else +- return slowfn(rwm); ++ return slowfn(rwm, mtx); + } + + int fastcall rt_mutex_down_write_trylock(struct rw_mutex *rwm) + { +- return rt_write_fasttrylock(rwm, rt_write_slowtrylock); ++ return rt_write_fasttrylock(rwm, rt_write_slowtrylock, 1); + } + + static void fastcall noinline __sched --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0156-preempt-irqs-ppc-fix-more-fasteoi.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0156-preempt-irqs-ppc-fix-more-fasteoi.patch @@ -0,0 +1,89 @@ +From sshtylyov@ru.mvista.com Thu May 17 15:18:39 2007 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.1.7-deb (2006-10-05) on debian +X-Spam-Level: +X-Spam-Status: No, score=0.0 required=5.0 tests=AWL autolearn=unavailable + version=3.1.7-deb +Received: from imap.sh.mvista.com (unknown [63.81.120.155]) by mail.tglx.de + (Postfix) with ESMTP id BFD3A65C065 for ; Thu, 17 May + 2007 15:18:39 +0200 (CEST) +Received: from wasted.dev.rtsoft.ru (unknown [10.150.0.9]) by + imap.sh.mvista.com (Postfix) with ESMTP id 8E3CB3EC9; Thu, 17 May 2007 + 06:18:35 -0700 (PDT) +From: Sergei Shtylyov +Organization: MontaVista Software Inc. +To: mingo@elte.hu, tglx@linutronix.de +Subject: [PATCH 2.6.21-rt2] PowerPC: revert fix for threaded fasteoi IRQ + handlers +Date: Thu, 17 May 2007 17:20:08 +0400 +User-Agent: KMail/1.5 +Cc: linux-kernel@vger.kernel.org, linuxppc-dev@ozlabs.org, dwalker@mvista.com +References: <200611192243.34850.sshtylyov@ru.mvista.com> +In-Reply-To: <200611192243.34850.sshtylyov@ru.mvista.com> +MIME-Version: 1.0 +Content-Disposition: inline +Message-Id: <200705171719.34968.sshtylyov@ru.mvista.com> +Content-Type: text/plain; charset="us-ascii" +X-Evolution-Source: imap://tglx%40linutronix.de@localhost:8993/ +Content-Transfer-Encoding: 8bit + +Revert the change to the "fasteoi" type chips as after handle_fasteoi_irq() had +been fixed, they've become meaningless (and even dangerous -- as was the case +with Celleb that has been fixed earlier)... + +Signed-off-by: Sergei Shtylyov + +--- +The patch in question wasn't even initially accepted but then was erroneously +restored along with the TOD patch. I've asked to revert it but to no avail, +so here's the formal patch to revert it at last... + + arch/powerpc/platforms/iseries/irq.c | 1 - + arch/powerpc/platforms/pseries/xics.c | 2 -- + arch/powerpc/sysdev/mpic.c | 1 - + 3 files changed, 4 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/iseries/irq.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/iseries/irq.c 2009-02-08 00:01:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/iseries/irq.c 2009-02-08 00:01:56.000000000 -0500 +@@ -278,7 +278,6 @@ static struct irq_chip iseries_pic = { + .shutdown = iseries_shutdown_IRQ, + .unmask = iseries_enable_IRQ, + .mask = iseries_disable_IRQ, +- .ack = iseries_end_IRQ, + .eoi = iseries_end_IRQ + }; + +Index: linux-2.6.24.7-rt27/arch/powerpc/platforms/pseries/xics.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/platforms/pseries/xics.c 2009-02-08 00:01:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/platforms/pseries/xics.c 2009-02-08 00:01:56.000000000 -0500 +@@ -461,7 +461,6 @@ static struct irq_chip xics_pic_direct = + .startup = xics_startup, + .mask = xics_mask_irq, + .unmask = xics_unmask_irq, +- .ack = xics_eoi_direct, + .eoi = xics_eoi_direct, + .set_affinity = xics_set_affinity + }; +@@ -472,7 +471,6 @@ static struct irq_chip xics_pic_lpar = { + .startup = xics_startup, + .mask = xics_mask_irq, + .unmask = xics_unmask_irq, +- .ack = xics_eoi_lpar, + .eoi = xics_eoi_lpar, + .set_affinity = xics_set_affinity + }; +Index: linux-2.6.24.7-rt27/arch/powerpc/sysdev/mpic.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/sysdev/mpic.c 2009-02-08 00:01:54.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/sysdev/mpic.c 2009-02-08 00:01:56.000000000 -0500 +@@ -845,7 +845,6 @@ int mpic_set_irq_type(unsigned int virq, + static struct irq_chip mpic_irq_chip = { + .mask = mpic_mask_irq, + .unmask = mpic_unmask_irq, +- .ack = mpic_end_irq, + .eoi = mpic_end_irq, + .set_type = mpic_set_irq_type, + }; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0107-latency-tracing-ppc.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0107-latency-tracing-ppc.patch @@ -0,0 +1,23 @@ + arch/ppc/boot/Makefile | 9 +++++++++ + 1 file changed, 9 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/ppc/boot/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/ppc/boot/Makefile 2009-02-08 00:00:20.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/ppc/boot/Makefile 2009-02-08 00:01:33.000000000 -0500 +@@ -15,6 +15,15 @@ + + # KBUILD_CFLAGS used when building rest of boot (takes effect recursively) + KBUILD_CFLAGS += -fno-builtin -D__BOOTER__ -Iarch/$(ARCH)/boot/include ++ ++ifdef CONFIG_MCOUNT ++# do not trace the boot loader ++nullstring := ++space := $(nullstring) # end of the line ++pg_flag = $(nullstring) -pg # end of the line ++KBUILD_CFLAGS := $(subst ${pg_flag},${space},${KBUILD_CFLAGS}) ++endif ++ + HOSTCFLAGS += -Iarch/$(ARCH)/boot/include + + BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0412-hack-fix-rt-migration.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0412-hack-fix-rt-migration.patch @@ -0,0 +1,54 @@ +From efault@gmx.de Mon Jan 14 23:35:16 2008 +Date: Mon, 14 Jan 2008 09:27:40 +0100 +From: Mike Galbraith +To: Steven Rostedt +Cc: Mariusz Kozlowski , + LKML , RT , + Ingo Molnar , Thomas Gleixner +Subject: Re: 2.6.24-rc7-rt1 + + [ The following text is in the "utf-8" character set. ] + [ Your display is set for the "iso-8859-1" character set. ] + [ Some characters may be displayed incorrectly. ] + + +On Sun, 2008-01-13 at 15:54 -0500, Steven Rostedt wrote: + +> OK, -rt2 will take a bit more beating from me before I release it, so it +> might take some time to get it out (expect it out on Monday). + +Ah, that reminds me (tests, yup) I still need the patchlet below to +resume from ram without black screen of death. No idea why my P4 box +seems to be the only box in the rt galaxy affected. (haven't poked at +it since the holidays) + +--- + kernel/sched_rt.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:02:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:04:07.000000000 -0500 +@@ -33,6 +33,9 @@ static inline void rt_clear_overload(str + + static void update_rt_migration(struct rq *rq) + { ++ if (unlikely(num_online_cpus() == 1)) ++ return; ++ + if (rq->rt.rt_nr_migratory && (rq->rt.rt_nr_running > 1)) { + if (!rq->rt.overloaded) { + rt_set_overload(rq); +@@ -105,8 +108,10 @@ static inline void dec_rt_tasks(struct t + } /* otherwise leave rq->highest prio alone */ + } else + rq->rt.highest_prio = MAX_RT_PRIO; +- if (p->nr_cpus_allowed > 1) ++ if (p->nr_cpus_allowed > 1) { ++ BUG_ON(!rq->rt.rt_nr_migratory); + rq->rt.rt_nr_migratory--; ++ } + + if (rq->rt.highest_prio != highest_prio) + cpupri_set(&rq->rd->cpupri, rq->cpu, rq->rt.highest_prio); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0506-rwlock-protect-reader_lock_count.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0506-rwlock-protect-reader_lock_count.patch @@ -0,0 +1,132 @@ +--- + kernel/rtmutex.c | 35 ++++++++++++++++++++++++++++------- + 1 file changed, 28 insertions(+), 7 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:50.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:51.000000000 -0500 +@@ -1137,6 +1137,12 @@ rt_rwlock_update_owner(struct rw_mutex * + if (own == RT_RW_READER) + return; + ++ /* ++ * We don't need to grab the pi_lock to look at the reader list ++ * since we hold the rwm wait_lock. We only care about the pointer ++ * to this lock, and we own the wait_lock, so that pointer ++ * can't be changed. ++ */ + for (i = own->reader_lock_count - 1; i >= 0; i--) { + if (own->owned_read_locks[i].lock == rwm) + break; +@@ -1256,6 +1262,7 @@ static int try_to_take_rw_read(struct rw + if (incr) { + atomic_inc(&rwm->owners); + rw_check_held(rwm); ++ spin_lock(¤t->pi_lock); + reader_count = current->reader_lock_count++; + if (likely(reader_count < MAX_RWLOCK_DEPTH)) { + rls = ¤t->owned_read_locks[reader_count]; +@@ -1265,6 +1272,7 @@ static int try_to_take_rw_read(struct rw + list_add(&rls->list, &rwm->readers); + } else + WARN_ON_ONCE(1); ++ spin_unlock(¤t->pi_lock); + } + rt_mutex_deadlock_account_lock(mutex, current); + atomic_inc(&rwm->count); +@@ -1420,6 +1428,7 @@ __rt_read_fasttrylock(struct rw_mutex *r + retry: + if (likely(rt_rwlock_cmpxchg(rwm, NULL, current))) { + int reader_count; ++ unsigned long flags; + + rt_mutex_deadlock_account_lock(&rwm->mutex, current); + atomic_inc(&rwm->count); +@@ -1436,30 +1445,31 @@ __rt_read_fasttrylock(struct rw_mutex *r + + atomic_inc(&rwm->owners); + rw_check_held(rwm); +- reader_count = current->reader_lock_count; ++ local_irq_save(flags); ++ spin_lock(¤t->pi_lock); ++ reader_count = current->reader_lock_count++; + if (likely(reader_count < MAX_RWLOCK_DEPTH)) { + current->owned_read_locks[reader_count].lock = rwm; + current->owned_read_locks[reader_count].count = 1; + } else + WARN_ON_ONCE(1); ++ spin_unlock(¤t->pi_lock); + /* + * If this task is no longer the sole owner of the lock + * or someone is blocking, then we need to add the task + * to the lock. + */ +- smp_mb(); +- current->reader_lock_count++; + if (unlikely(rwm->owner != current)) { + struct rt_mutex *mutex = &rwm->mutex; + struct reader_lock_struct *rls; +- unsigned long flags; + +- spin_lock_irqsave(&mutex->wait_lock, flags); ++ spin_lock(&mutex->wait_lock); + rls = ¤t->owned_read_locks[reader_count]; + if (!rls->list.prev || list_empty(&rls->list)) + list_add(&rls->list, &rwm->readers); +- spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ spin_unlock(&mutex->wait_lock); + } ++ local_irq_restore(flags); + return 1; + } + return 0; +@@ -1712,6 +1722,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + + for (i = current->reader_lock_count - 1; i >= 0; i--) { + if (current->owned_read_locks[i].lock == rwm) { ++ spin_lock(¤t->pi_lock); + current->owned_read_locks[i].count--; + if (!current->owned_read_locks[i].count) { + current->reader_lock_count--; +@@ -1723,6 +1734,7 @@ rt_read_slowunlock(struct rw_mutex *rwm, + rls->lock = NULL; + rw_check_held(rwm); + } ++ spin_unlock(¤t->pi_lock); + break; + } + } +@@ -1848,8 +1860,14 @@ rt_read_fastunlock(struct rw_mutex *rwm, + atomic_dec(&rwm->count); + if (likely(rt_rwlock_cmpxchg(rwm, current, NULL))) { + struct reader_lock_struct *rls; +- int reader_count = --current->reader_lock_count; ++ unsigned long flags; ++ int reader_count; + int owners; ++ ++ spin_lock_irqsave(¤t->pi_lock, flags); ++ reader_count = --current->reader_lock_count; ++ spin_unlock_irqrestore(¤t->pi_lock, flags); ++ + rt_mutex_deadlock_account_unlock(current); + if (unlikely(reader_count < 0)) { + reader_count = 0; +@@ -2041,6 +2059,8 @@ rt_mutex_downgrade_write(struct rw_mutex + atomic_inc(&rwm->count); + atomic_inc(&rwm->owners); + rw_check_held(rwm); ++ ++ spin_lock(¤t->pi_lock); + reader_count = current->reader_lock_count++; + rls = ¤t->owned_read_locks[reader_count]; + if (likely(reader_count < MAX_RWLOCK_DEPTH)) { +@@ -2048,6 +2068,7 @@ rt_mutex_downgrade_write(struct rw_mutex + rls->count = 1; + } else + WARN_ON_ONCE(1); ++ spin_unlock(¤t->pi_lock); + + if (!rt_mutex_has_waiters(mutex)) { + /* We are sole owner, we are done */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0087-x86_64-tsc-sync-irqflags-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0087-x86_64-tsc-sync-irqflags-fix.patch @@ -0,0 +1,28 @@ +--- + arch/x86/kernel/tsc_sync.c | 4 ++++ + 1 file changed, 4 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/tsc_sync.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/tsc_sync.c 2009-02-08 00:00:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/tsc_sync.c 2009-02-08 00:01:24.000000000 -0500 +@@ -97,6 +97,7 @@ static __cpuinit void check_tsc_warp(voi + */ + void __cpuinit check_tsc_sync_source(int cpu) + { ++ unsigned long flags; + int cpus = 2; + + /* +@@ -117,8 +118,11 @@ void __cpuinit check_tsc_sync_source(int + /* + * Wait for the target to arrive: + */ ++ local_save_flags(flags); ++ local_irq_enable(); + while (atomic_read(&start_count) != cpus-1) + cpu_relax(); ++ local_irq_restore(flags); + /* + * Trigger the target to continue into the measurement too: + */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0385-ntfs-local-irq-save-nort.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0385-ntfs-local-irq-save-nort.patch @@ -0,0 +1,63 @@ +From efault@gmx.de Sat Oct 27 10:28:42 2007 +Date: Sat, 27 Oct 2007 12:17:49 +0200 +From: Mike Galbraith +To: Ingo Molnar +Cc: Nick Piggin , Steven Rostedt , + LKML , RT , + Thomas Gleixner +Subject: Re: [2.6.23-rt3] NMI watchdog trace of deadlock + +On Sat, 2007-10-27 at 11:44 +0200, Ingo Molnar wrote: +> * Nick Piggin wrote: +> +> > > [10138.175796] [] show_trace+0x12/0x14 +> > > [10138.180291] [] dump_stack+0x16/0x18 +> > > [10138.184769] [] native_smp_call_function_mask+0x138/0x13d +> > > [10138.191117] [] smp_call_function+0x1e/0x24 +> > > [10138.196210] [] on_each_cpu+0x25/0x50 +> > > [10138.200807] [] flush_tlb_all+0x1e/0x20 +> > > [10138.205553] [] kmap_high+0x1b6/0x417 +> > > [10138.210118] [] kmap+0x4d/0x4f +> > > [10138.214102] [] ntfs_end_buffer_async_read+0x228/0x2f9 +> > > [10138.220163] [] end_bio_bh_io_sync+0x26/0x3f +> > > [10138.225352] [] bio_endio+0x42/0x6d +> > > [10138.229769] [] __end_that_request_first+0x115/0x4ac +> > > [10138.235682] [] end_that_request_chunk+0x8/0xa +> > > [10138.241052] [] ide_end_request+0x55/0x10a +> > > [10138.246058] [] ide_dma_intr+0x6f/0xac +> > > [10138.250727] [] ide_intr+0x93/0x1e0 +> > > [10138.255125] [] handle_IRQ_event+0x5c/0xc9 +> > +> > Looks like ntfs is kmap()ing from interrupt context. Should be using +> > kmap_atomic instead, I think. +> +> it's not atomic interrupt context but irq thread context - and -rt +> remaps kmap_atomic() to kmap() internally. + +Hm. Looking at the change to mm/bounce.c, perhaps I should do this +instead? + +--- + fs/ntfs/aops.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/fs/ntfs/aops.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/ntfs/aops.c 2009-02-08 00:02:12.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/ntfs/aops.c 2009-02-08 00:03:54.000000000 -0500 +@@ -139,13 +139,13 @@ static void ntfs_end_buffer_async_read(s + recs = PAGE_CACHE_SIZE / rec_size; + /* Should have been verified before we got here... */ + BUG_ON(!recs); +- local_irq_save(flags); ++ local_irq_save_nort(flags); + kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); + for (i = 0; i < recs; i++) + post_read_mst_fixup((NTFS_RECORD*)(kaddr + + i * rec_size), rec_size); + kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); +- local_irq_restore(flags); ++ local_irq_restore_nort(flags); + flush_dcache_page(page); + if (likely(page_uptodate && !PageError(page))) + SetPageUptodate(page); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0076-powerpc-ftrace-store-mcount.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0076-powerpc-ftrace-store-mcount.patch @@ -0,0 +1,169 @@ +--- + arch/powerpc/kernel/entry_32.S | 4 ++++ + arch/powerpc/kernel/entry_64.S | 5 ++++- + arch/powerpc/kernel/ftrace.c | 21 +++++++-------------- + include/asm-powerpc/ftrace.h | 8 ++++++++ + 4 files changed, 23 insertions(+), 15 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_32.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/entry_32.S 2009-02-08 00:01:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_32.S 2009-02-08 00:01:18.000000000 -0500 +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + #undef SHOW_SYSCALLS + #undef SHOW_SYSCALLS_TASK +@@ -1040,6 +1041,7 @@ _GLOBAL(_mcount) + stw r10,40(r1) + stw r3, 44(r1) + stw r5, 8(r1) ++ subi r3, r3, MCOUNT_INSN_SIZE + .globl mcount_call + mcount_call: + bl ftrace_stub +@@ -1077,6 +1079,7 @@ _GLOBAL(ftrace_caller) + stw r10,40(r1) + stw r3, 44(r1) + stw r5, 8(r1) ++ subi r3, r3, MCOUNT_INSN_SIZE + .globl ftrace_call + ftrace_call: + bl ftrace_stub +@@ -1115,6 +1118,7 @@ _GLOBAL(_mcount) + stw r3, 44(r1) + stw r5, 8(r1) + ++ subi r3, r3, MCOUNT_INSN_SIZE + LOAD_REG_ADDR(r5, ftrace_trace_function) + lwz r5,0(r5) + +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_64.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/entry_64.S 2009-02-08 00:01:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/entry_64.S 2009-02-08 00:01:18.000000000 -0500 +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + /* + * System calls. +@@ -855,6 +856,7 @@ _GLOBAL(_mcount) + mflr r3 + stdu r1, -112(r1) + std r3, 128(r1) ++ subi r3, r3, MCOUNT_INSN_SIZE + .globl mcount_call + mcount_call: + bl ftrace_stub +@@ -871,6 +873,7 @@ _GLOBAL(ftrace_caller) + stdu r1, -112(r1) + std r3, 128(r1) + ld r4, 16(r11) ++ subi r3, r3, MCOUNT_INSN_SIZE + .globl ftrace_call + ftrace_call: + bl ftrace_stub +@@ -892,7 +895,7 @@ _GLOBAL(_mcount) + std r3, 128(r1) + ld r4, 16(r11) + +- ++ subi r3, r3, MCOUNT_INSN_SIZE + LOAD_REG_ADDR(r5,ftrace_trace_function) + ld r5,0(r5) + ld r5,0(r5) +Index: linux-2.6.24.7-rt27/arch/powerpc/kernel/ftrace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/powerpc/kernel/ftrace.c 2009-02-08 00:01:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/powerpc/kernel/ftrace.c 2009-02-08 00:01:18.000000000 -0500 +@@ -15,8 +15,8 @@ + #include + + #include ++#include + +-#define CALL_BACK 4 + + static unsigned int ftrace_nop = 0x60000000; + +@@ -27,9 +27,10 @@ static unsigned int ftrace_nop = 0x60000 + # define GET_ADDR(addr) *(unsigned long *)addr + #endif + ++ + static unsigned int notrace ftrace_calc_offset(long ip, long addr) + { +- return (int)((addr + CALL_BACK) - ip); ++ return (int)(addr - ip); + } + + notrace unsigned char *ftrace_nop_replace(void) +@@ -76,9 +77,6 @@ ftrace_modify_code(unsigned long ip, uns + unsigned new = *(unsigned *)new_code; + int faulted = 0; + +- /* move the IP back to the start of the call */ +- ip -= CALL_BACK; +- + /* + * Note: Due to modules and __init, code can + * disappear and change, we need to protect against faulting +@@ -118,12 +116,10 @@ ftrace_modify_code(unsigned long ip, uns + notrace int ftrace_update_ftrace_func(ftrace_func_t func) + { + unsigned long ip = (unsigned long)(&ftrace_call); +- unsigned char old[4], *new; ++ unsigned char old[MCOUNT_INSN_SIZE], *new; + int ret; + +- ip += CALL_BACK; +- +- memcpy(old, &ftrace_call, 4); ++ memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); + new = ftrace_call_replace(ip, (unsigned long)func); + ret = ftrace_modify_code(ip, old, new); + +@@ -134,16 +130,13 @@ notrace int ftrace_mcount_set(unsigned l + { + unsigned long ip = (long)(&mcount_call); + unsigned long *addr = data; +- unsigned char old[4], *new; +- +- /* ip is at the location, but modify code will subtact this */ +- ip += CALL_BACK; ++ unsigned char old[MCOUNT_INSN_SIZE], *new; + + /* + * Replace the mcount stub with a pointer to the + * ip recorder function. + */ +- memcpy(old, &mcount_call, 4); ++ memcpy(old, &mcount_call, MCOUNT_INSN_SIZE); + new = ftrace_call_replace(ip, *addr); + *addr = ftrace_modify_code(ip, old, new); + +Index: linux-2.6.24.7-rt27/include/asm-powerpc/ftrace.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-powerpc/ftrace.h 2009-02-08 00:01:18.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-powerpc/ftrace.h 2009-02-08 00:01:18.000000000 -0500 +@@ -1,6 +1,14 @@ + #ifndef _ASM_POWERPC_FTRACE + #define _ASM_POWERPC_FTRACE + ++#ifdef CONFIG_FTRACE ++#define MCOUNT_ADDR ((long)(_mcount)) ++#define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ ++ ++#ifndef __ASSEMBLY__ + extern void _mcount(void); ++#endif + + #endif ++ ++#endif /* _ASM_POWERPC_FTRACE */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0195-disable-irqpoll.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0195-disable-irqpoll.patch @@ -0,0 +1,31 @@ + kernel/irq/spurious.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/irq/spurious.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/irq/spurious.c 2009-02-08 00:01:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/irq/spurious.c 2009-02-08 00:02:14.000000000 -0500 +@@ -239,6 +239,11 @@ __setup("noirqdebug", noirqdebug_setup); + + static int __init irqfixup_setup(char *str) + { ++#ifdef CONFIG_PREEMPT_RT ++ printk(KERN_WARNING "irqfixup boot option not supported " ++ "w/ CONFIG_PREEMPT_RT\n"); ++ return 1; ++#endif + irqfixup = 1; + printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n"); + printk(KERN_WARNING "This may impact system performance.\n"); +@@ -250,6 +255,11 @@ __setup("irqfixup", irqfixup_setup); + + static int __init irqpoll_setup(char *str) + { ++#ifdef CONFIG_PREEMPT_RT ++ printk(KERN_WARNING "irqpoll boot option not supported " ++ "w/ CONFIG_PREEMPT_RT\n"); ++ return 1; ++#endif + irqfixup = 2; + printk(KERN_WARNING "Misrouted IRQ fixup and polling support " + "enabled\n"); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0094-msi-suspend-resume-workaround.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0094-msi-suspend-resume-workaround.patch @@ -0,0 +1,19 @@ +--- + drivers/pci/msi.c | 4 ++++ + 1 file changed, 4 insertions(+) + +Index: linux-2.6.24.7-rt27/drivers/pci/msi.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/pci/msi.c 2009-02-08 00:00:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/pci/msi.c 2009-02-08 00:01:26.000000000 -0500 +@@ -241,6 +241,10 @@ static void __pci_restore_msi_state(stru + return; + + entry = get_irq_msi(dev->irq); ++ if (!entry) { ++ WARN_ON(1); ++ return; ++ } + pos = entry->msi_attrib.pos; + + pci_intx_for_msi(dev, 0); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0467-ftrace-record-comm-on-ctrl.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0467-ftrace-record-comm-on-ctrl.patch @@ -0,0 +1,28 @@ +From: Steven Rostedt +Subject: ftrace: record comm on function ctrl change + +On stress tests, it is possible for the comm of that disables the +ftracer to be lost. Record it on turning on or off the function tracer. + +Signed-off-by: Steven Rostedt +--- + kernel/trace/trace.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/trace/trace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace.c 2009-02-08 00:02:36.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace.c 2009-02-08 00:04:32.000000000 -0500 +@@ -1197,10 +1197,12 @@ static struct ftrace_ops trace_ops __rea + void tracing_start_function_trace(void) + { + register_ftrace_function(&trace_ops); ++ tracing_record_cmdline(current); + } + + void tracing_stop_function_trace(void) + { ++ tracing_record_cmdline(current); + unregister_ftrace_function(&trace_ops); + } + #endif --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0511-cpu-hotplug-vs-page-alloc.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0511-cpu-hotplug-vs-page-alloc.patch @@ -0,0 +1,81 @@ +Subject: cpu-hotplug: vs page_alloc +From: Peter Zijlstra +Date: Tue, 10 Jun 2008 13:13:01 +0200 + +On -rt we protect per-cpu state by locks instead of disabling preemption/irqs. +This keeps all the code preemptible at the cost of possible remote memory +access. + +The race was that cpu-hotplug - which assumes to be cpu local and non- +preemptible, didn't take the per-cpu lock. + +This also means that the normal lock acquire needs to be aware of cpus getting +off-lined while its waiting. + +Signed-off-by: Peter Zijlstra +Cc: Steven Rostedt +Cc: Clark Williams +Cc: Gregory Haskins +Cc: "Paul E. McKenney" +Cc: Gautham R Shenoy +Cc: Pekka Enberg +Cc: Arnaldo Carvalho de Melo +Cc: Peter Zijlstra +Signed-off-by: Thomas Gleixner +--- + mm/page_alloc.c | 24 +++++++++++++++++++++--- + 1 file changed, 21 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/mm/page_alloc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/page_alloc.c 2009-02-08 00:03:59.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/page_alloc.c 2009-02-08 00:04:54.000000000 -0500 +@@ -176,7 +176,19 @@ static inline void __lock_cpu_pcp(unsign + static inline void lock_cpu_pcp(unsigned long *flags, int *this_cpu) + { + #ifdef CONFIG_PREEMPT_RT +- (void)get_cpu_var_locked(pcp_locks, this_cpu); ++ spinlock_t *lock; ++ int cpu; ++ ++again: ++ cpu = raw_smp_processor_id(); ++ lock = &__get_cpu_lock(pcp_locks, cpu); ++ ++ spin_lock(lock); ++ if (unlikely(!cpu_online(cpu))) { ++ spin_unlock(lock); ++ goto again; ++ } ++ *this_cpu = cpu; + flags = 0; + #else + local_irq_save(*flags); +@@ -2781,12 +2793,17 @@ static inline void free_zone_pagesets(in + struct zone *zone; + + for_each_zone(zone) { +- struct per_cpu_pageset *pset = zone_pcp(zone, cpu); ++ struct per_cpu_pageset *pset; ++ unsigned long flags; ++ ++ __lock_cpu_pcp(&flags, cpu); ++ pset = zone_pcp(zone, cpu); ++ zone_pcp(zone, cpu) = NULL; ++ unlock_cpu_pcp(flags, cpu); + + /* Free per_cpu_pageset if it is slab allocated */ + if (pset != &boot_pageset[cpu]) + kfree(pset); +- zone_pcp(zone, cpu) = NULL; + } + } + +@@ -2812,6 +2829,7 @@ static int __cpuinit pageset_cpuup_callb + default: + break; + } ++ + return ret; + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0521-fix_sys_sched_rr_get_interval_slice_for_SCHED_FIFO_tasks.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0521-fix_sys_sched_rr_get_interval_slice_for_SCHED_FIFO_tasks.patch @@ -0,0 +1,31 @@ +Subject: sched: fix the wrong time slice value for SCHED_FIFO tasks +From: Miao Xie + +X-Git-Tag: v2.6.25-rc5~13^2~2 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=1868f958eb56fc41c5985c8732e564a400c5fdf5 + +sched: fix the wrong time slice value for SCHED_FIFO tasks + +Function sys_sched_rr_get_interval returns wrong time slice value for +SCHED_FIFO tasks. The time slice for SCHED_FIFO tasks should be 0. + +Signed-off-by: Miao Xie +Signed-off-by: Ingo Molnar +--- + + kernel/sched.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/sched.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched.c 2009-02-08 00:04:55.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched.c 2009-02-08 00:04:59.000000000 -0500 +@@ -5392,7 +5392,7 @@ long sys_sched_rr_get_interval(pid_t pid + time_slice = 0; + if (p->policy == SCHED_RR) { + time_slice = DEF_TIMESLICE; +- } else { ++ } else if (p->policy != SCHED_FIFO) { + struct sched_entity *se = &p->se; + unsigned long flags; + struct rq *rq; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0331-preempt-rt-no-slub.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0331-preempt-rt-no-slub.patch @@ -0,0 +1,16 @@ +--- + init/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +Index: linux-2.6.24.7-rt27/init/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/init/Kconfig 2009-02-08 00:03:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/init/Kconfig 2009-02-08 00:03:28.000000000 -0500 +@@ -647,6 +647,7 @@ config SLAB + + config SLUB + bool "SLUB (Unqueued Allocator)" ++ depends on !PREEMPT_RT + help + SLUB is a slab allocator that minimizes cache line usage + instead of managing queues of cached objects (SLAB approach). --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0242-preempt-realtime-fs-block.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0242-preempt-realtime-fs-block.patch @@ -0,0 +1,407 @@ +--- + block/ll_rw_blk.c | 6 ++-- + fs/aio.c | 6 +++- + fs/block_dev.c | 34 +++++++++++++++++++++------ + fs/dcache.c | 5 ++-- + fs/dnotify.c | 2 - + fs/exec.c | 8 +++++- + fs/file.c | 5 ++-- + fs/lockd/svc.c | 8 +----- + fs/pipe.c | 12 +++++++++ + fs/proc/proc_misc.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/proc/task_mmu.c | 4 ++- + fs/xfs/linux-2.6/mrlock.h | 4 +-- + fs/xfs/xfs_mount.h | 2 - + include/linux/genhd.h | 11 +++++++-- + 14 files changed, 132 insertions(+), 31 deletions(-) + +Index: linux-2.6.24.7-rt27/block/ll_rw_blk.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/block/ll_rw_blk.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/block/ll_rw_blk.c 2009-02-08 00:02:40.000000000 -0500 +@@ -1548,7 +1548,7 @@ static int ll_merge_requests_fn(struct r + */ + void blk_plug_device(struct request_queue *q) + { +- WARN_ON(!irqs_disabled()); ++ WARN_ON_NONRT(!irqs_disabled()); + + /* + * don't plug a stopped queue, it must be paired with blk_start_queue() +@@ -1571,7 +1571,7 @@ EXPORT_SYMBOL(blk_plug_device); + */ + int blk_remove_plug(struct request_queue *q) + { +- WARN_ON(!irqs_disabled()); ++ WARN_ON_NONRT(!irqs_disabled()); + + if (!test_and_clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) + return 0; +@@ -1670,7 +1670,7 @@ EXPORT_SYMBOL(blk_unplug); + **/ + void blk_start_queue(struct request_queue *q) + { +- WARN_ON(!irqs_disabled()); ++ WARN_ON_NONRT(!irqs_disabled()); + + clear_bit(QUEUE_FLAG_STOPPED, &q->queue_flags); + +Index: linux-2.6.24.7-rt27/fs/aio.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/aio.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/aio.c 2009-02-08 00:02:40.000000000 -0500 +@@ -582,13 +582,15 @@ static void use_mm(struct mm_struct *mm) + tsk->flags |= PF_BORROWED_MM; + active_mm = tsk->active_mm; + atomic_inc(&mm->mm_count); +- tsk->mm = mm; +- tsk->active_mm = mm; ++ local_irq_disable(); // FIXME + /* + * Note that on UML this *requires* PF_BORROWED_MM to be set, otherwise + * it won't work. Update it accordingly if you change it here + */ + switch_mm(active_mm, mm, tsk); ++ tsk->mm = mm; ++ tsk->active_mm = mm; ++ local_irq_enable(); + task_unlock(tsk); + + mmdrop(active_mm); +Index: linux-2.6.24.7-rt27/fs/block_dev.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/block_dev.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/block_dev.c 2009-02-08 00:02:40.000000000 -0500 +@@ -1225,14 +1225,32 @@ static int __blkdev_get(struct block_dev + * For now, block device ->open() routine must _not_ + * examine anything in 'inode' argument except ->i_rdev. + */ +- struct file fake_file = {}; +- struct dentry fake_dentry = {}; +- fake_file.f_mode = mode; +- fake_file.f_flags = flags; +- fake_file.f_path.dentry = &fake_dentry; +- fake_dentry.d_inode = bdev->bd_inode; +- +- return do_open(bdev, &fake_file, for_part); ++ struct file *fake_file; ++ struct dentry *fake_dentry; ++ int err = -ENOMEM; ++ ++ fake_file = kmalloc(sizeof(*fake_file), GFP_KERNEL); ++ if (!fake_file) ++ goto out; ++ memset(fake_file, 0, sizeof(*fake_file)); ++ ++ fake_dentry = kmalloc(sizeof(*fake_dentry), GFP_KERNEL); ++ if (!fake_dentry) ++ goto out_free_file; ++ memset(fake_dentry, 0, sizeof(*fake_dentry)); ++ ++ fake_file->f_mode = mode; ++ fake_file->f_flags = flags; ++ fake_file->f_path.dentry = fake_dentry; ++ fake_dentry->d_inode = bdev->bd_inode; ++ ++ err = do_open(bdev, fake_file, for_part); ++ ++ kfree(fake_dentry); ++out_free_file: ++ kfree(fake_file); ++out: ++ return err; + } + + int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags) +Index: linux-2.6.24.7-rt27/fs/dcache.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/dcache.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/dcache.c 2009-02-08 00:02:40.000000000 -0500 +@@ -704,8 +704,9 @@ void shrink_dcache_for_umount(struct sup + { + struct dentry *dentry; + +- if (down_read_trylock(&sb->s_umount)) +- BUG(); ++// -rt: this might succeed there ... ++// if (down_read_trylock(&sb->s_umount)) ++// BUG(); + + dentry = sb->s_root; + sb->s_root = NULL; +Index: linux-2.6.24.7-rt27/fs/dnotify.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/dnotify.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/dnotify.c 2009-02-08 00:02:40.000000000 -0500 +@@ -173,7 +173,7 @@ void dnotify_parent(struct dentry *dentr + + spin_lock(&dentry->d_lock); + parent = dentry->d_parent; +- if (parent->d_inode->i_dnotify_mask & event) { ++ if (unlikely(parent->d_inode->i_dnotify_mask & event)) { + dget(parent); + spin_unlock(&dentry->d_lock); + __inode_dir_notify(parent->d_inode, event); +Index: linux-2.6.24.7-rt27/fs/exec.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/exec.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/exec.c 2009-02-08 00:02:40.000000000 -0500 +@@ -48,6 +48,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -721,11 +722,16 @@ static int exec_mmap(struct mm_struct *m + } + } + task_lock(tsk); ++ ++ local_irq_disable(); + active_mm = tsk->active_mm; ++ activate_mm(active_mm, mm); + tsk->mm = mm; + tsk->active_mm = mm; +- activate_mm(active_mm, mm); ++ local_irq_enable(); ++ + task_unlock(tsk); ++ + arch_pick_mmap_layout(mm); + if (old_mm) { + up_read(&old_mm->mmap_sem); +Index: linux-2.6.24.7-rt27/fs/file.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/file.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/file.c 2009-02-08 00:02:40.000000000 -0500 +@@ -96,14 +96,15 @@ void free_fdtable_rcu(struct rcu_head *r + kfree(fdt->open_fds); + kfree(fdt); + } else { +- fddef = &get_cpu_var(fdtable_defer_list); ++ ++ fddef = &per_cpu(fdtable_defer_list, raw_smp_processor_id()); ++ + spin_lock(&fddef->lock); + fdt->next = fddef->next; + fddef->next = fdt; + /* vmallocs are handled from the workqueue context */ + schedule_work(&fddef->wq); + spin_unlock(&fddef->lock); +- put_cpu_var(fdtable_defer_list); + } + } + +Index: linux-2.6.24.7-rt27/fs/lockd/svc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/lockd/svc.c 2009-02-07 23:59:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/lockd/svc.c 2009-02-08 00:02:40.000000000 -0500 +@@ -349,16 +349,12 @@ lockd_down(void) + * Wait for the lockd process to exit, but since we're holding + * the lockd semaphore, we can't wait around forever ... + */ +- clear_thread_flag(TIF_SIGPENDING); +- interruptible_sleep_on_timeout(&lockd_exit, HZ); +- if (nlmsvc_pid) { ++ if (wait_event_interruptible_timeout(lockd_exit, ++ nlmsvc_pid == 0, HZ) <= 0) { + printk(KERN_WARNING + "lockd_down: lockd failed to exit, clearing pid\n"); + nlmsvc_pid = 0; + } +- spin_lock_irq(¤t->sighand->siglock); +- recalc_sigpending(); +- spin_unlock_irq(¤t->sighand->siglock); + out: + mutex_unlock(&nlmsvc_mutex); + } +Index: linux-2.6.24.7-rt27/fs/pipe.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/pipe.c 2009-02-07 23:59:58.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/pipe.c 2009-02-08 00:02:40.000000000 -0500 +@@ -385,8 +385,14 @@ redo: + wake_up_interruptible_sync(&pipe->wait); + kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); + } ++ /* ++ * Hack: we turn off atime updates for -RT kernels. ++ * Who uses them on pipes anyway? ++ */ ++#ifndef CONFIG_PREEMPT_RT + if (ret > 0) + file_accessed(filp); ++#endif + return ret; + } + +@@ -558,8 +564,14 @@ out: + wake_up_interruptible_sync(&pipe->wait); + kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); + } ++ /* ++ * Hack: we turn off atime updates for -RT kernels. ++ * Who uses them on pipes anyway? ++ */ ++#ifndef CONFIG_PREEMPT_RT + if (ret > 0) + file_update_time(filp); ++#endif + return ret; + } + +Index: linux-2.6.24.7-rt27/fs/proc/proc_misc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/proc/proc_misc.c 2009-02-08 00:02:15.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/proc/proc_misc.c 2009-02-08 00:02:40.000000000 -0500 +@@ -96,6 +96,27 @@ static int loadavg_read_proc(char *page, + return proc_calc_metrics(page, start, off, count, eof, len); + } + ++#ifdef CONFIG_PREEMPT_RT ++static int loadavg_rt_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ extern unsigned long avenrun_rt[]; ++ extern unsigned long rt_nr_running(void); ++ int a, b, c; ++ int len; ++ ++ a = avenrun_rt[0] + (FIXED_1/200); ++ b = avenrun_rt[1] + (FIXED_1/200); ++ c = avenrun_rt[2] + (FIXED_1/200); ++ len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", ++ LOAD_INT(a), LOAD_FRAC(a), ++ LOAD_INT(b), LOAD_FRAC(b), ++ LOAD_INT(c), LOAD_FRAC(c), ++ rt_nr_running(), nr_threads, current->nsproxy->pid_ns->last_pid); ++ return proc_calc_metrics(page, start, off, count, eof, len); ++} ++#endif ++ + static int uptime_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) + { +@@ -555,6 +576,38 @@ static int show_stat(struct seq_file *p, + nr_iowait()); + + kfree(per_irq_sum); ++#ifdef CONFIG_PREEMPT_RT ++ { ++ unsigned long nr_uninterruptible_cpu(int cpu); ++ extern int pi_initialized; ++ unsigned long rt_nr_running(void); ++ unsigned long rt_nr_running_cpu(int cpu); ++ unsigned long rt_nr_uninterruptible(void); ++ unsigned long rt_nr_uninterruptible_cpu(int cpu); ++ ++ int i; ++ ++ seq_printf(p, "pi_init: %d\n", pi_initialized); ++ seq_printf(p, "nr_running(): %ld\n", ++ nr_running()); ++ seq_printf(p, "nr_uninterruptible(): %ld\n", ++ nr_uninterruptible()); ++ for_each_online_cpu(i) ++ seq_printf(p, "nr_uninterruptible(%d): %ld\n", ++ i, nr_uninterruptible_cpu(i)); ++ seq_printf(p, "rt_nr_running(): %ld\n", ++ rt_nr_running()); ++ for_each_online_cpu(i) ++ seq_printf(p, "rt_nr_running(%d): %ld\n", ++ i, rt_nr_running_cpu(i)); ++ seq_printf(p, "nr_rt_uninterruptible(): %ld\n", ++ rt_nr_uninterruptible()); ++ for_each_online_cpu(i) ++ seq_printf(p, "nr_rt_uninterruptible(%d): %ld\n", ++ i, rt_nr_uninterruptible_cpu(i)); ++ } ++#endif ++ + return 0; + } + +@@ -704,6 +757,9 @@ void __init proc_misc_init(void) + int (*read_proc)(char*,char**,off_t,int,int*,void*); + } *p, simple_ones[] = { + {"loadavg", loadavg_read_proc}, ++#ifdef CONFIG_PREEMPT_RT ++ {"loadavgrt", loadavg_rt_read_proc}, ++#endif + {"uptime", uptime_read_proc}, + {"meminfo", meminfo_read_proc}, + {"version", version_read_proc}, +Index: linux-2.6.24.7-rt27/fs/proc/task_mmu.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/proc/task_mmu.c 2009-02-07 23:59:58.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/proc/task_mmu.c 2009-02-08 00:02:40.000000000 -0500 +@@ -416,8 +416,10 @@ static void *m_start(struct seq_file *m, + vma = NULL; + if ((unsigned long)l < mm->map_count) { + vma = mm->mmap; +- while (l-- && vma) ++ while (l-- && vma) { + vma = vma->vm_next; ++ cond_resched(); ++ } + goto out; + } + +Index: linux-2.6.24.7-rt27/fs/xfs/linux-2.6/mrlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/xfs/linux-2.6/mrlock.h 2009-02-07 23:59:58.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/xfs/linux-2.6/mrlock.h 2009-02-08 00:02:40.000000000 -0500 +@@ -23,8 +23,8 @@ + enum { MR_NONE, MR_ACCESS, MR_UPDATE }; + + typedef struct { +- struct rw_semaphore mr_lock; +- int mr_writer; ++ struct compat_rw_semaphore mr_lock; ++ int mr_writer; + } mrlock_t; + + #define mrinit(mrp, name) \ +Index: linux-2.6.24.7-rt27/fs/xfs/xfs_mount.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/xfs/xfs_mount.h 2009-02-07 23:59:58.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/xfs/xfs_mount.h 2009-02-08 00:02:40.000000000 -0500 +@@ -383,7 +383,7 @@ typedef struct xfs_mount { + uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ + uint m_in_maxlevels; /* XFS_IN_MAXLEVELS */ + struct xfs_perag *m_perag; /* per-ag accounting info */ +- struct rw_semaphore m_peraglock; /* lock for m_perag (pointer) */ ++ struct compat_rw_semaphore m_peraglock; /* lock for m_perag (pointer) */ + struct mutex m_growlock; /* growfs mutex */ + int m_fixedfsid[2]; /* unchanged for life of FS */ + uint m_dmevmask; /* DMI events for this FS */ +Index: linux-2.6.24.7-rt27/include/linux/genhd.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/genhd.h 2009-02-07 23:59:58.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/genhd.h 2009-02-08 00:02:40.000000000 -0500 +@@ -157,15 +157,22 @@ struct disk_attribute { + * variants disable/enable preemption. + */ + #ifdef CONFIG_SMP +-#define __disk_stat_add(gendiskp, field, addnd) \ +- (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd) ++#define __disk_stat_add(gendiskp, field, addnd) \ ++do { \ ++ preempt_disable(); \ ++ (per_cpu_ptr(gendiskp->dkstats, \ ++ smp_processor_id())->field += addnd); \ ++ preempt_enable(); \ ++} while (0) + + #define disk_stat_read(gendiskp, field) \ + ({ \ + typeof(gendiskp->dkstats->field) res = 0; \ + int i; \ ++ preempt_disable(); \ + for_each_possible_cpu(i) \ + res += per_cpu_ptr(gendiskp->dkstats, i)->field; \ ++ preempt_enable(); \ + res; \ + }) + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0375-numa-slab-freeing.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0375-numa-slab-freeing.patch @@ -0,0 +1,55 @@ +From ak@suse.de Tue Oct 23 16:24:16 2007 +Date: Tue, 23 Oct 2007 19:13:03 +0200 +From: Andi Kleen +To: linux-rt-users@vger.kernel.org +Subject: [PATCH] Fix rt preempt slab NUMA freeing + + +When this_cpu changes in the free path node needs to change too. +Otherwise the slab can end up in the wrong node's list and this +eventually leads to WARN_ONs and of course worse NUMA performace. + +This patch is likely not complete (the NUMA slab code is *very* hairy), +but seems to make the make -j128 test survive for at least two hours. + +But at least it fixes one case that regularly triggered during +testing, resulting in slabs in the wrong node lists and triggering +WARN_ONs in slab_put/get_obj + +I tried a complete audit of keeping this_cpu/node/slabp in sync when needed, but +it is very hairy code and I likely missed some cases. This so far +fixes only the simple free path; but it seems to be good enough +to not trigger easily anymore on a NUMA system with memory pressure. + +Longer term the only good fix is probably to migrate to slub. +Or disable NUMA slab for PREEMPT_RT (its value has been disputed +in some benchmarks anyways) + +Signed-off-by: Andi Kleen + +--- + mm/slab.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/mm/slab.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/slab.c 2009-02-08 00:03:37.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/slab.c 2009-02-08 00:03:48.000000000 -0500 +@@ -1192,7 +1192,7 @@ cache_free_alien(struct kmem_cache *cach + struct array_cache *alien = NULL; + int node; + +- node = numa_node_id(); ++ node = cpu_to_node(*this_cpu); + + /* + * Make sure we are not freeing a object from another node to the array +@@ -4215,6 +4215,8 @@ static void cache_reap(struct work_struc + + work_done += reap_alien(searchp, l3, &this_cpu); + ++ node = cpu_to_node(this_cpu); ++ + work_done += drain_array(searchp, l3, + cpu_cache_get(searchp, this_cpu), 0, node); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0479-x86-fifo-ticket-spinlocks.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0479-x86-fifo-ticket-spinlocks.patch @@ -0,0 +1,686 @@ +x86: FIFO ticket spinlocks + +From: Nick Piggin + +Introduce ticket lock spinlocks for x86 which are FIFO. The implementation +is described in the comments. The straight-line lock/unlock instruction +sequence is slightly slower than the dec based locks on modern x86 CPUs, +however the difference is quite small on Core2 and Opteron when working out of +cache, and becomes almost insignificant even on P4 when the lock misses cache. +trylock is more significantly slower, but they are relatively rare. + +On an 8 core (2 socket) Opteron, spinlock unfairness is extremely noticable, +with a userspace test having a difference of up to 2x runtime per thread, and +some threads are starved or "unfairly" granted the lock up to 1 000 000 (!) +times. After this patch, all threads appear to finish at exactly the same +time. + +The memory ordering of the lock does conform to x86 standards, and the +implementation has been reviewed by Intel and AMD engineers. + +The algorithm also tells us how many CPUs are contending the lock, so +lockbreak becomes trivial and we no longer have to waste 4 bytes per +spinlock for it. + +After this, we can no longer spin on any locks with preempt enabled +and cannot reenable interrupts when spinning on an irq safe lock, because +at that point we have already taken a ticket and the would deadlock if +the same CPU tries to take the lock again. These are questionable anyway: +if the lock happens to be called under a preempt or interrupt disabled section, +then it will just have the same latency problems. The real fix is to keep +critical sections short, and ensure locks are reasonably fair (which this +patch does). + +Signed-off-by: Nick Piggin +--- + + include/asm-x86/spinlock.h | 225 ++++++++++++++++++++++++++++++++++++++- + include/asm-x86/spinlock_32.h | 221 -------------------------------------- + include/asm-x86/spinlock_64.h | 167 ---------------------------- + include/asm-x86/spinlock_types.h | 2 + 4 files changed, 224 insertions(+), 391 deletions(-) + +Index: linux-2.6.24.7-rt27/include/asm-x86/spinlock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/spinlock.h 2009-02-07 23:59:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/spinlock.h 2009-02-08 00:04:37.000000000 -0500 +@@ -1,5 +1,226 @@ ++#ifndef _X86_SPINLOCK_H_ ++#define _X86_SPINLOCK_H_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Your basic SMP spinlocks, allowing only a single CPU anywhere ++ * ++ * Simple spin lock operations. There are two variants, one clears IRQ's ++ * on the local processor, one does not. ++ * ++ * These are fair FIFO ticket locks, which are currently limited to 256 ++ * CPUs. ++ * ++ * (the type definitions are in asm/spinlock_types.h) ++ */ ++ + #ifdef CONFIG_X86_32 +-# include "spinlock_32.h" ++typedef char _slock_t; ++# define LOCK_INS_DEC "decb" ++# define LOCK_INS_XCH "xchgb" ++# define LOCK_INS_MOV "movb" ++# define LOCK_INS_CMP "cmpb" ++# define LOCK_PTR_REG "a" + #else +-# include "spinlock_64.h" ++typedef int _slock_t; ++# define LOCK_INS_DEC "decl" ++# define LOCK_INS_XCH "xchgl" ++# define LOCK_INS_MOV "movl" ++# define LOCK_INS_CMP "cmpl" ++# define LOCK_PTR_REG "D" ++#endif ++ ++#if (NR_CPUS > 256) ++#error spinlock supports a maximum of 256 CPUs ++#endif ++ ++static inline int __raw_spin_is_locked(__raw_spinlock_t *lock) ++{ ++ int tmp = *(volatile signed int *)(&(lock)->slock); ++ ++ return (((tmp >> 8) & 0xff) != (tmp & 0xff)); ++} ++ ++static inline int __raw_spin_is_contended(__raw_spinlock_t *lock) ++{ ++ int tmp = *(volatile signed int *)(&(lock)->slock); ++ ++ return (((tmp >> 8) & 0xff) - (tmp & 0xff)) > 1; ++} ++ ++static inline void __raw_spin_lock(__raw_spinlock_t *lock) ++{ ++ short inc = 0x0100; ++ ++ /* ++ * Ticket locks are conceptually two bytes, one indicating the current ++ * head of the queue, and the other indicating the current tail. The ++ * lock is acquired by atomically noting the tail and incrementing it ++ * by one (thus adding ourself to the queue and noting our position), ++ * then waiting until the head becomes equal to the the initial value ++ * of the tail. ++ * ++ * This uses a 16-bit xadd to increment the tail and also load the ++ * position of the head, which takes care of memory ordering issues ++ * and should be optimal for the uncontended case. Note the tail must ++ * be in the high byte, otherwise the 16-bit wide increment of the low ++ * byte would carry up and contaminate the high byte. ++ */ ++ ++ __asm__ __volatile__ ( ++ LOCK_PREFIX "xaddw %w0, %1\n" ++ "1:\t" ++ "cmpb %h0, %b0\n\t" ++ "je 2f\n\t" ++ "rep ; nop\n\t" ++ "movb %1, %b0\n\t" ++ /* don't need lfence here, because loads are in-order */ ++ "jmp 1b\n" ++ "2:" ++ :"+Q" (inc), "+m" (lock->slock) ++ : ++ :"memory", "cc"); ++} ++ ++#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) ++ ++static inline int __raw_spin_trylock(__raw_spinlock_t *lock) ++{ ++ int tmp; ++ short new; ++ ++ asm volatile( ++ "movw %2,%w0\n\t" ++ "cmpb %h0,%b0\n\t" ++ "jne 1f\n\t" ++ "movw %w0,%w1\n\t" ++ "incb %h1\n\t" ++ "lock ; cmpxchgw %w1,%2\n\t" ++ "1:" ++ "sete %b1\n\t" ++ "movzbl %b1,%0\n\t" ++ :"=&a" (tmp), "=Q" (new), "+m" (lock->slock) ++ : ++ : "memory", "cc"); ++ ++ return tmp; ++} ++ ++#if defined(CONFIG_X86_32) && \ ++ (defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)) ++/* ++ * On PPro SMP or if we are using OOSTORE, we use a locked operation to unlock ++ * (PPro errata 66, 92) ++ */ ++# define UNLOCK_LOCK_PREFIX LOCK_PREFIX ++#else ++# define UNLOCK_LOCK_PREFIX ++#endif ++ ++static inline void __raw_spin_unlock(__raw_spinlock_t *lock) ++{ ++ __asm__ __volatile__( ++ UNLOCK_LOCK_PREFIX "incb %0" ++ :"+m" (lock->slock) ++ : ++ :"memory", "cc"); ++} ++ ++static inline void __raw_spin_unlock_wait(__raw_spinlock_t *lock) ++{ ++ while (__raw_spin_is_locked(lock)) ++ cpu_relax(); ++} ++ ++/* ++ * Read-write spinlocks, allowing multiple readers ++ * but only one writer. ++ * ++ * NOTE! it is quite common to have readers in interrupts ++ * but no interrupt writers. For those circumstances we ++ * can "mix" irq-safe locks - any writer needs to get a ++ * irq-safe write-lock, but readers can get non-irqsafe ++ * read-locks. ++ * ++ * On x86, we implement read-write locks as a 32-bit counter ++ * with the high bit (sign) being the "contended" bit. ++ */ ++ ++/** ++ * read_can_lock - would read_trylock() succeed? ++ * @lock: the rwlock in question. ++ */ ++static inline int __raw_read_can_lock(__raw_rwlock_t *lock) ++{ ++ return (int)(lock)->lock > 0; ++} ++ ++/** ++ * write_can_lock - would write_trylock() succeed? ++ * @lock: the rwlock in question. ++ */ ++static inline int __raw_write_can_lock(__raw_rwlock_t *lock) ++{ ++ return (lock)->lock == RW_LOCK_BIAS; ++} ++ ++static inline void __raw_read_lock(__raw_rwlock_t *rw) ++{ ++ asm volatile(LOCK_PREFIX " subl $1,(%0)\n\t" ++ "jns 1f\n" ++ "call __read_lock_failed\n\t" ++ "1:\n" ++ ::LOCK_PTR_REG (rw) : "memory"); ++} ++ ++static inline void __raw_write_lock(__raw_rwlock_t *rw) ++{ ++ asm volatile(LOCK_PREFIX " subl %1,(%0)\n\t" ++ "jz 1f\n" ++ "call __write_lock_failed\n\t" ++ "1:\n" ++ ::LOCK_PTR_REG (rw), "i" (RW_LOCK_BIAS) : "memory"); ++} ++ ++static inline int __raw_read_trylock(__raw_rwlock_t *lock) ++{ ++ atomic_t *count = (atomic_t *)lock; ++ ++ atomic_dec(count); ++ if (atomic_read(count) >= 0) ++ return 1; ++ atomic_inc(count); ++ return 0; ++} ++ ++static inline int __raw_write_trylock(__raw_rwlock_t *lock) ++{ ++ atomic_t *count = (atomic_t *)lock; ++ ++ if (atomic_sub_and_test(RW_LOCK_BIAS, count)) ++ return 1; ++ atomic_add(RW_LOCK_BIAS, count); ++ return 0; ++} ++ ++static inline void __raw_read_unlock(__raw_rwlock_t *rw) ++{ ++ asm volatile(LOCK_PREFIX "incl %0" :"+m" (rw->lock) : : "memory"); ++} ++ ++static inline void __raw_write_unlock(__raw_rwlock_t *rw) ++{ ++ asm volatile(LOCK_PREFIX "addl %1, %0" ++ : "+m" (rw->lock) : "i" (RW_LOCK_BIAS) : "memory"); ++} ++ ++#define _raw_spin_relax(lock) cpu_relax() ++#define _raw_read_relax(lock) cpu_relax() ++#define _raw_write_relax(lock) cpu_relax() ++ + #endif +Index: linux-2.6.24.7-rt27/include/asm-x86/spinlock_32.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/spinlock_32.h 2009-02-08 00:02:04.000000000 -0500 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,221 +0,0 @@ +-#ifndef __ASM_SPINLOCK_H +-#define __ASM_SPINLOCK_H +- +-#include +-#include +-#include +-#include +-#include +- +-#ifdef CONFIG_PARAVIRT +-#include +-#else +-#define CLI_STRING "cli" +-#define STI_STRING "sti" +-#define CLI_STI_CLOBBERS +-#define CLI_STI_INPUT_ARGS +-#endif /* CONFIG_PARAVIRT */ +- +-/* +- * Your basic SMP spinlocks, allowing only a single CPU anywhere +- * +- * Simple spin lock operations. There are two variants, one clears IRQ's +- * on the local processor, one does not. +- * +- * We make no fairness assumptions. They have a cost. +- * +- * (the type definitions are in asm/spinlock_types.h) +- */ +- +-static inline int __raw_spin_is_locked(__raw_spinlock_t *x) +-{ +- return *(volatile signed char *)(&(x)->slock) <= 0; +-} +- +-static inline void __raw_spin_lock(__raw_spinlock_t *lock) +-{ +- asm volatile("\n1:\t" +- LOCK_PREFIX " ; decb %0\n\t" +- "jns 3f\n" +- "2:\t" +- "rep;nop\n\t" +- "cmpb $0,%0\n\t" +- "jle 2b\n\t" +- "jmp 1b\n" +- "3:\n\t" +- : "+m" (lock->slock) : : "memory"); +-} +- +-/* +- * It is easier for the lock validator if interrupts are not re-enabled +- * in the middle of a lock-acquire. This is a performance feature anyway +- * so we turn it off: +- * +- * NOTE: there's an irqs-on section here, which normally would have to be +- * irq-traced, but on CONFIG_TRACE_IRQFLAGS we never use this variant. +- */ +-#ifndef CONFIG_PROVE_LOCKING +-static inline void __raw_spin_lock_flags(__raw_spinlock_t *lock, unsigned long flags) +-{ +- asm volatile( +- "\n1:\t" +- LOCK_PREFIX " ; decb %[slock]\n\t" +- "jns 5f\n" +- "2:\t" +- "testl $0x200, %[flags]\n\t" +- "jz 4f\n\t" +- STI_STRING "\n" +- "3:\t" +- "rep;nop\n\t" +- "cmpb $0, %[slock]\n\t" +- "jle 3b\n\t" +- CLI_STRING "\n\t" +- "jmp 1b\n" +- "4:\t" +- "rep;nop\n\t" +- "cmpb $0, %[slock]\n\t" +- "jg 1b\n\t" +- "jmp 4b\n" +- "5:\n\t" +- : [slock] "+m" (lock->slock) +- : [flags] "r" (flags) +- CLI_STI_INPUT_ARGS +- : "memory" CLI_STI_CLOBBERS); +-} +-#endif +- +-static inline int __raw_spin_trylock(__raw_spinlock_t *lock) +-{ +- char oldval; +- asm volatile( +- "xchgb %b0,%1" +- :"=q" (oldval), "+m" (lock->slock) +- :"0" (0) : "memory"); +- return oldval > 0; +-} +- +-/* +- * __raw_spin_unlock based on writing $1 to the low byte. +- * This method works. Despite all the confusion. +- * (except on PPro SMP or if we are using OOSTORE, so we use xchgb there) +- * (PPro errata 66, 92) +- */ +- +-#if !defined(CONFIG_X86_OOSTORE) && !defined(CONFIG_X86_PPRO_FENCE) +- +-static inline void __raw_spin_unlock(__raw_spinlock_t *lock) +-{ +- asm volatile("movb $1,%0" : "+m" (lock->slock) :: "memory"); +-} +- +-#else +- +-static inline void __raw_spin_unlock(__raw_spinlock_t *lock) +-{ +- char oldval = 1; +- +- asm volatile("xchgb %b0, %1" +- : "=q" (oldval), "+m" (lock->slock) +- : "0" (oldval) : "memory"); +-} +- +-#endif +- +-static inline void __raw_spin_unlock_wait(__raw_spinlock_t *lock) +-{ +- while (__raw_spin_is_locked(lock)) +- cpu_relax(); +-} +- +-/* +- * Read-write spinlocks, allowing multiple readers +- * but only one writer. +- * +- * NOTE! it is quite common to have readers in interrupts +- * but no interrupt writers. For those circumstances we +- * can "mix" irq-safe locks - any writer needs to get a +- * irq-safe write-lock, but readers can get non-irqsafe +- * read-locks. +- * +- * On x86, we implement read-write locks as a 32-bit counter +- * with the high bit (sign) being the "contended" bit. +- * +- * The inline assembly is non-obvious. Think about it. +- * +- * Changed to use the same technique as rw semaphores. See +- * semaphore.h for details. -ben +- * +- * the helpers are in arch/i386/kernel/semaphore.c +- */ +- +-/** +- * read_can_lock - would read_trylock() succeed? +- * @lock: the rwlock in question. +- */ +-static inline int __raw_read_can_lock(__raw_rwlock_t *x) +-{ +- return (int)(x)->lock > 0; +-} +- +-/** +- * write_can_lock - would write_trylock() succeed? +- * @lock: the rwlock in question. +- */ +-static inline int __raw_write_can_lock(__raw_rwlock_t *x) +-{ +- return (x)->lock == RW_LOCK_BIAS; +-} +- +-static inline void __raw_read_lock(__raw_rwlock_t *rw) +-{ +- asm volatile(LOCK_PREFIX " subl $1,(%0)\n\t" +- "jns 1f\n" +- "call __read_lock_failed\n\t" +- "1:\n" +- ::"a" (rw) : "memory"); +-} +- +-static inline void __raw_write_lock(__raw_rwlock_t *rw) +-{ +- asm volatile(LOCK_PREFIX " subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" +- "jz 1f\n" +- "call __write_lock_failed\n\t" +- "1:\n" +- ::"a" (rw) : "memory"); +-} +- +-static inline int __raw_read_trylock(__raw_rwlock_t *lock) +-{ +- atomic_t *count = (atomic_t *)lock; +- atomic_dec(count); +- if (atomic_read(count) >= 0) +- return 1; +- atomic_inc(count); +- return 0; +-} +- +-static inline int __raw_write_trylock(__raw_rwlock_t *lock) +-{ +- atomic_t *count = (atomic_t *)lock; +- if (atomic_sub_and_test(RW_LOCK_BIAS, count)) +- return 1; +- atomic_add(RW_LOCK_BIAS, count); +- return 0; +-} +- +-static inline void __raw_read_unlock(__raw_rwlock_t *rw) +-{ +- asm volatile(LOCK_PREFIX "incl %0" :"+m" (rw->lock) : : "memory"); +-} +- +-static inline void __raw_write_unlock(__raw_rwlock_t *rw) +-{ +- asm volatile(LOCK_PREFIX "addl $" RW_LOCK_BIAS_STR ", %0" +- : "+m" (rw->lock) : : "memory"); +-} +- +-#define __raw_spin_relax(lock) cpu_relax() +-#define __raw_read_relax(lock) cpu_relax() +-#define __raw_write_relax(lock) cpu_relax() +- +-#endif /* __ASM_SPINLOCK_H */ +Index: linux-2.6.24.7-rt27/include/asm-x86/spinlock_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/spinlock_64.h 2009-02-08 00:02:25.000000000 -0500 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,167 +0,0 @@ +-#ifndef __ASM_SPINLOCK_H +-#define __ASM_SPINLOCK_H +- +-#include +-#include +-#include +-#include +- +-/* +- * Your basic SMP spinlocks, allowing only a single CPU anywhere +- * +- * Simple spin lock operations. There are two variants, one clears IRQ's +- * on the local processor, one does not. +- * +- * We make no fairness assumptions. They have a cost. +- * +- * (the type definitions are in asm/spinlock_types.h) +- */ +- +-static inline int __raw_spin_is_locked(__raw_spinlock_t *lock) +-{ +- return *(volatile signed int *)(&(lock)->slock) <= 0; +-} +- +-static inline void __raw_spin_lock(__raw_spinlock_t *lock) +-{ +- asm volatile( +- "\n1:\t" +- LOCK_PREFIX " ; decl %0\n\t" +- "jns 2f\n" +- "3:\n" +- "rep;nop\n\t" +- "cmpl $0,%0\n\t" +- "jle 3b\n\t" +- "jmp 1b\n" +- "2:\t" : "=m" (lock->slock) : : "memory"); +-} +- +-/* +- * Same as __raw_spin_lock, but reenable interrupts during spinning. +- */ +-#ifndef CONFIG_PROVE_LOCKING +-static inline void __raw_spin_lock_flags(__raw_spinlock_t *lock, unsigned long flags) +-{ +- asm volatile( +- "\n1:\t" +- LOCK_PREFIX " ; decl %0\n\t" +- "jns 5f\n" +- "testl $0x200, %1\n\t" /* interrupts were disabled? */ +- "jz 4f\n\t" +- "sti\n" +- "3:\t" +- "rep;nop\n\t" +- "cmpl $0, %0\n\t" +- "jle 3b\n\t" +- "cli\n\t" +- "jmp 1b\n" +- "4:\t" +- "rep;nop\n\t" +- "cmpl $0, %0\n\t" +- "jg 1b\n\t" +- "jmp 4b\n" +- "5:\n\t" +- : "+m" (lock->slock) : "r" ((unsigned)flags) : "memory"); +-} +-#endif +- +-static inline int __raw_spin_trylock(__raw_spinlock_t *lock) +-{ +- int oldval; +- +- asm volatile( +- "xchgl %0,%1" +- :"=q" (oldval), "=m" (lock->slock) +- :"0" (0) : "memory"); +- +- return oldval > 0; +-} +- +-static inline void __raw_spin_unlock(__raw_spinlock_t *lock) +-{ +- asm volatile("movl $1,%0" :"=m" (lock->slock) :: "memory"); +-} +- +-static inline void __raw_spin_unlock_wait(__raw_spinlock_t *lock) +-{ +- while (__raw_spin_is_locked(lock)) +- cpu_relax(); +-} +- +-/* +- * Read-write spinlocks, allowing multiple readers +- * but only one writer. +- * +- * NOTE! it is quite common to have readers in interrupts +- * but no interrupt writers. For those circumstances we +- * can "mix" irq-safe locks - any writer needs to get a +- * irq-safe write-lock, but readers can get non-irqsafe +- * read-locks. +- * +- * On x86, we implement read-write locks as a 32-bit counter +- * with the high bit (sign) being the "contended" bit. +- */ +- +-static inline int __raw_read_can_lock(__raw_rwlock_t *lock) +-{ +- return (int)(lock)->lock > 0; +-} +- +-static inline int __raw_write_can_lock(__raw_rwlock_t *lock) +-{ +- return (lock)->lock == RW_LOCK_BIAS; +-} +- +-static inline void __raw_read_lock(__raw_rwlock_t *rw) +-{ +- asm volatile(LOCK_PREFIX "subl $1,(%0)\n\t" +- "jns 1f\n" +- "call __read_lock_failed\n" +- "1:\n" +- ::"D" (rw), "i" (RW_LOCK_BIAS) : "memory"); +-} +- +-static inline void __raw_write_lock(__raw_rwlock_t *rw) +-{ +- asm volatile(LOCK_PREFIX "subl %1,(%0)\n\t" +- "jz 1f\n" +- "\tcall __write_lock_failed\n\t" +- "1:\n" +- ::"D" (rw), "i" (RW_LOCK_BIAS) : "memory"); +-} +- +-static inline int __raw_read_trylock(__raw_rwlock_t *lock) +-{ +- atomic_t *count = (atomic_t *)lock; +- atomic_dec(count); +- if (atomic_read(count) >= 0) +- return 1; +- atomic_inc(count); +- return 0; +-} +- +-static inline int __raw_write_trylock(__raw_rwlock_t *lock) +-{ +- atomic_t *count = (atomic_t *)lock; +- if (atomic_sub_and_test(RW_LOCK_BIAS, count)) +- return 1; +- atomic_add(RW_LOCK_BIAS, count); +- return 0; +-} +- +-static inline void __raw_read_unlock(__raw_rwlock_t *rw) +-{ +- asm volatile(LOCK_PREFIX " ; incl %0" :"=m" (rw->lock) : : "memory"); +-} +- +-static inline void __raw_write_unlock(__raw_rwlock_t *rw) +-{ +- asm volatile(LOCK_PREFIX " ; addl $" RW_LOCK_BIAS_STR ",%0" +- : "=m" (rw->lock) : : "memory"); +-} +- +-#define __raw_spin_relax(lock) cpu_relax() +-#define __raw_read_relax(lock) cpu_relax() +-#define __raw_write_relax(lock) cpu_relax() +- +-#endif /* __ASM_SPINLOCK_H */ +Index: linux-2.6.24.7-rt27/include/asm-x86/spinlock_types.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/spinlock_types.h 2009-02-08 00:02:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/spinlock_types.h 2009-02-08 00:04:37.000000000 -0500 +@@ -9,7 +9,7 @@ typedef struct { + unsigned int slock; + } __raw_spinlock_t; + +-#define __RAW_SPIN_LOCK_UNLOCKED { 1 } ++#define __RAW_SPIN_LOCK_UNLOCKED { 0 } + + typedef struct { + unsigned int lock; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0338-genirq-soft-resend.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0338-genirq-soft-resend.patch @@ -0,0 +1,49 @@ +Subject: x86: activate HARDIRQS_SW_RESEND +From: Ingo Molnar + +activate the software-triggered IRQ-resend logic. + +it appears some chipsets/cpus do not handle local-APIC driven IRQ +resends all that well, so always use the soft mechanism to trigger +the execution of pending interrupts. + +Signed-off-by: Ingo Molnar +--- + arch/x86/Kconfig | 4 ++++ + kernel/irq/manage.c | 8 ++++++++ + 2 files changed, 12 insertions(+) + +Index: linux-2.6.24.7-rt27/arch/x86/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/Kconfig 2009-02-08 00:02:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/Kconfig 2009-02-08 00:03:31.000000000 -0500 +@@ -1230,6 +1230,10 @@ config OUT_OF_LINE_PFN_TO_PAGE + def_bool X86_64 + depends on DISCONTIGMEM + ++config HARDIRQS_SW_RESEND ++ bool ++ default y ++ + menu "Power management options" + depends on !X86_VOYAGER + +Index: linux-2.6.24.7-rt27/kernel/irq/manage.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/irq/manage.c 2009-02-08 00:03:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/irq/manage.c 2009-02-08 00:03:31.000000000 -0500 +@@ -191,6 +191,14 @@ void enable_irq(unsigned int irq) + desc->depth--; + } + spin_unlock_irqrestore(&desc->lock, flags); ++#ifdef CONFIG_HARDIRQS_SW_RESEND ++ /* ++ * Do a bh disable/enable pair to trigger any pending ++ * irq resend logic: ++ */ ++ local_bh_disable(); ++ local_bh_enable(); ++#endif + } + EXPORT_SYMBOL(enable_irq); + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0399-page-alloc-use-real-time-pcp-locking-for-page-draining.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0399-page-alloc-use-real-time-pcp-locking-for-page-draining.patch @@ -0,0 +1,36 @@ +From: Andi Kleen +Subject: [PATCH for 2.6.24rc2-rt1] Use real time pcp locking for page draining during cpu unplug + + +Use real time pcp locking for page draining during cpu unplug + +Looks like a merging mistake that happened at some point. This +is the only place in the file that disables interrupts directly. + +This fixes one case of CPU hotunplug failing on RT, but there +are still more. + +Signed-off-by: Andi Kleen + +--- + mm/page_alloc.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/mm/page_alloc.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/page_alloc.c 2009-02-08 00:03:57.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/page_alloc.c 2009-02-08 00:03:59.000000000 -0500 +@@ -4058,10 +4058,11 @@ static int page_alloc_cpu_notify(struct + int cpu = (unsigned long)hcpu; + + if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) { +- local_irq_disable(); ++ unsigned long flags; ++ __lock_cpu_pcp(&flags, cpu); + __drain_pages(cpu); + vm_events_fold_cpu(cpu); +- local_irq_enable(); ++ unlock_cpu_pcp(flags, cpu); + refresh_cpu_vm_stats(cpu); + } + return NOTIFY_OK; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0440-cache_pci_find_capability.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0440-cache_pci_find_capability.patch @@ -0,0 +1,195 @@ +From: Arnaldo Carvalho de Melo +Subject: [PATCH] Cache calls to pci_find_capability + + +The problem here is that everytime do_irqd masks/unmasks MSI interrupts +it would ask if the device has the MSI capability, and that involves +multiple calls to pci_conf1_read, that can take as high as 44us in +in/out calls, so I just cached results in struct pci_dev. + +With this patch the highest latency still is in masking/unmasking MSI +interrupts, but its down to 159us in a kernel with ftrace, using the +preemptirqsoff tracer: + + +I showed it to Jesse Barnes, the PCI maintainer and he said its 2.6.27 +material, and Rostedt said tglx is OK with it, so please add it to the +-50 kernel-rt release. + +Signed-off-by: Arnaldo Carvalho de Melo + +--- + drivers/pci/msi.c | 12 ++++++------ + drivers/pci/pci.c | 36 ++++++++++++++++++++++++++++++++++++ + drivers/pci/probe.c | 4 ++++ + include/linux/pci.h | 3 +++ + include/linux/pci_regs.h | 1 + + 5 files changed, 50 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/drivers/pci/msi.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/pci/msi.c 2009-02-08 00:01:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/pci/msi.c 2009-02-08 00:04:20.000000000 -0500 +@@ -30,7 +30,7 @@ static void msi_set_enable(struct pci_de + int pos; + u16 control; + +- pos = pci_find_capability(dev, PCI_CAP_ID_MSI); ++ pos = pci_find_capability_cached(dev, PCI_CAP_ID_MSI); + if (pos) { + pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); + control &= ~PCI_MSI_FLAGS_ENABLE; +@@ -45,7 +45,7 @@ static void msix_set_enable(struct pci_d + int pos; + u16 control; + +- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); ++ pos = pci_find_capability_cached(dev, PCI_CAP_ID_MSIX); + if (pos) { + pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); + control &= ~PCI_MSIX_FLAGS_ENABLE; +@@ -311,7 +311,7 @@ static int msi_capability_init(struct pc + + msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ + +- pos = pci_find_capability(dev, PCI_CAP_ID_MSI); ++ pos = pci_find_capability_cached(dev, PCI_CAP_ID_MSI); + pci_read_config_word(dev, msi_control_reg(pos), &control); + /* MSI Entry Initialization */ + entry = alloc_msi_entry(); +@@ -384,7 +384,7 @@ static int msix_capability_init(struct p + + msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */ + +- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); ++ pos = pci_find_capability_cached(dev, PCI_CAP_ID_MSIX); + /* Request & Map MSI-X table region */ + pci_read_config_word(dev, msi_control_reg(pos), &control); + nr_entries = multi_msix_capable(control); +@@ -491,7 +491,7 @@ static int pci_msi_check_device(struct p + if (ret) + return ret; + +- if (!pci_find_capability(dev, type)) ++ if (!pci_find_capability_cached(dev, type)) + return -EINVAL; + + return 0; +@@ -610,7 +610,7 @@ int pci_enable_msix(struct pci_dev* dev, + if (status) + return status; + +- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); ++ pos = pci_find_capability_cached(dev, PCI_CAP_ID_MSIX); + pci_read_config_word(dev, msi_control_reg(pos), &control); + nr_entries = multi_msix_capable(control); + if (nvec > nr_entries) +Index: linux-2.6.24.7-rt27/drivers/pci/pci.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/pci/pci.c 2009-02-07 23:59:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/pci/pci.c 2009-02-08 00:04:20.000000000 -0500 +@@ -170,6 +170,42 @@ int pci_find_capability(struct pci_dev * + } + + /** ++ * pci_find_capability_cached - query for devices' capabilities, cached version ++ * @dev: PCI device to query ++ * @cap: capability code ++ * ++ * Tell if a device supports a given PCI capability. ++ * Returns the address of the requested capability structure within the ++ * device's PCI configuration space or 0 in case the device does not ++ * support it. Possible values for @cap: ++ * ++ * %PCI_CAP_ID_PM Power Management ++ * %PCI_CAP_ID_AGP Accelerated Graphics Port ++ * %PCI_CAP_ID_VPD Vital Product Data ++ * %PCI_CAP_ID_SLOTID Slot Identification ++ * %PCI_CAP_ID_MSI Message Signalled Interrupts ++ * %PCI_CAP_ID_CHSWP CompactPCI HotSwap ++ * %PCI_CAP_ID_PCIX PCI-X ++ * %PCI_CAP_ID_EXP PCI Express ++ */ ++int pci_find_capability_cached(struct pci_dev *dev, int cap) ++{ ++ int pos = 0; ++ ++ WARN_ON_ONCE(cap <= 0 || cap > PCI_CAP_LIST_NR_ENTRIES); ++ ++ if (cap <= PCI_CAP_LIST_NR_ENTRIES) { ++ const int i = cap - 1; ++ if (dev->cached_capabilities[i] == -1) ++ dev->cached_capabilities[i] = pci_find_capability(dev, cap); ++ ++ pos = dev->cached_capabilities[i]; ++ } ++ ++ return pos; ++} ++ ++/** + * pci_bus_find_capability - query for devices' capabilities + * @bus: the PCI bus to query + * @devfn: PCI device to query +Index: linux-2.6.24.7-rt27/drivers/pci/probe.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/pci/probe.c 2009-02-07 23:59:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/pci/probe.c 2009-02-08 00:04:20.000000000 -0500 +@@ -854,6 +854,7 @@ static void pci_release_bus_bridge_dev(s + + struct pci_dev *alloc_pci_dev(void) + { ++ int i; + struct pci_dev *dev; + + dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); +@@ -863,6 +864,9 @@ struct pci_dev *alloc_pci_dev(void) + INIT_LIST_HEAD(&dev->global_list); + INIT_LIST_HEAD(&dev->bus_list); + ++ for (i = 0; i < ARRAY_SIZE(dev->cached_capabilities); ++i) ++ dev->cached_capabilities[i] = -1; ++ + pci_msi_init_pci_dev(dev); + + return dev; +Index: linux-2.6.24.7-rt27/include/linux/pci.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/pci.h 2009-02-07 23:59:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/pci.h 2009-02-08 00:04:20.000000000 -0500 +@@ -193,6 +193,7 @@ struct pci_dev { + unsigned int msix_enabled:1; + unsigned int is_managed:1; + unsigned int is_pcie:1; ++ int cached_capabilities[PCI_CAP_LIST_NR_ENTRIES]; /* See pci_find_capability_cached */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ + +@@ -494,6 +495,7 @@ struct pci_dev __deprecated *pci_find_sl + #endif /* CONFIG_PCI_LEGACY */ + + int pci_find_capability (struct pci_dev *dev, int cap); ++int pci_find_capability_cached(struct pci_dev *dev, int cap); + int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); + int pci_find_ext_capability (struct pci_dev *dev, int cap); + int pci_find_ht_capability (struct pci_dev *dev, int ht_cap); +@@ -760,6 +762,7 @@ static inline int __pci_register_driver( + static inline int pci_register_driver(struct pci_driver *drv) { return 0;} + static inline void pci_unregister_driver(struct pci_driver *drv) { } + static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } ++static inline int pci_find_capability_cached(struct pci_dev *dev, int cap) {return 0; } + static inline int pci_find_next_capability (struct pci_dev *dev, u8 post, int cap) { return 0; } + static inline int pci_find_ext_capability (struct pci_dev *dev, int cap) {return 0; } + +Index: linux-2.6.24.7-rt27/include/linux/pci_regs.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/pci_regs.h 2009-02-07 23:59:42.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/pci_regs.h 2009-02-08 00:04:20.000000000 -0500 +@@ -210,6 +210,7 @@ + #define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ + #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ + #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ ++#define PCI_CAP_LIST_NR_ENTRIES PCI_CAP_ID_MSIX + #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ + #define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ + #define PCI_CAP_SIZEOF 4 --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0253-preempt-realtime-irqs.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0253-preempt-realtime-irqs.patch @@ -0,0 +1,157 @@ +--- + include/linux/irq.h | 10 ++++------ + kernel/irq/handle.c | 10 +++++++++- + kernel/irq/manage.c | 22 ++++++++++++++++------ + kernel/irq/spurious.c | 3 +-- + 4 files changed, 30 insertions(+), 15 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/irq.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/irq.h 2009-02-08 00:01:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/irq.h 2009-02-08 00:02:45.000000000 -0500 +@@ -146,7 +146,6 @@ struct irq_chip { + * @last_unhandled: aging timer for unhandled count + * @thread: Thread pointer for threaded preemptible irq handling + * @wait_for_handler: Waitqueue to wait for a running preemptible handler +- * @cycles: Timestamp for stats and debugging + * @lock: locking for SMP + * @affinity: IRQ affinity on SMP + * @cpu: cpu index useful for balancing +@@ -169,10 +168,10 @@ struct irq_desc { + unsigned int irq_count; /* For detecting broken IRQs */ + unsigned int irqs_unhandled; + unsigned long last_unhandled; /* Aging timer for unhandled count */ +- struct task_struct *thread; +- wait_queue_head_t wait_for_handler; +- cycles_t timestamp; +- spinlock_t lock; ++ struct task_struct *thread; ++ wait_queue_head_t wait_for_handler; ++ cycles_t timestamp; ++ raw_spinlock_t lock; + #ifdef CONFIG_SMP + cpumask_t affinity; + unsigned int cpu; +@@ -408,7 +407,6 @@ extern int set_irq_msi(unsigned int irq, + + /* Early initialization of irqs */ + extern void early_init_hardirqs(void); +-extern cycles_t irq_timestamp(unsigned int irq); + + #if defined(CONFIG_PREEMPT_HARDIRQS) + extern void init_hardirqs(void); +Index: linux-2.6.24.7-rt27/kernel/irq/handle.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/irq/handle.c 2009-02-08 00:01:50.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/irq/handle.c 2009-02-08 00:02:45.000000000 -0500 +@@ -54,12 +54,13 @@ struct irq_desc irq_desc[NR_IRQS] __cach + .chip = &no_irq_chip, + .handle_irq = handle_bad_irq, + .depth = 1, +- .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock), ++ .lock = RAW_SPIN_LOCK_UNLOCKED(irq_desc), + #ifdef CONFIG_SMP + .affinity = CPU_MASK_ALL + #endif + } + }; ++EXPORT_SYMBOL_GPL(irq_desc); + + /* + * What should we do if we get a hw irq event on an illegal vector? +@@ -248,6 +249,13 @@ fastcall unsigned int __do_IRQ(unsigned + desc->chip->end(irq); + return 1; + } ++ /* ++ * If the task is currently running in user mode, don't ++ * detect soft lockups. If CONFIG_DETECT_SOFTLOCKUP is not ++ * configured, this should be optimized out. ++ */ ++ if (user_mode(get_irq_regs())) ++ touch_softlockup_watchdog(); + + spin_lock(&desc->lock); + if (desc->chip->ack) +Index: linux-2.6.24.7-rt27/kernel/irq/manage.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/irq/manage.c 2009-02-08 00:01:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/irq/manage.c 2009-02-08 00:02:45.000000000 -0500 +@@ -500,9 +500,9 @@ void free_irq(unsigned int irq, void *de + * parallel with our fake + */ + if (action->flags & IRQF_SHARED) { +- local_irq_save(flags); ++ local_irq_save_nort(flags); + action->handler(irq, dev_id); +- local_irq_restore(flags); ++ local_irq_restore_nort(flags); + } + #endif + kfree(action); +@@ -594,9 +594,9 @@ int request_irq(unsigned int irq, irq_ha + */ + unsigned long flags; + +- local_irq_save(flags); ++ local_irq_save_nort(flags); + handler(irq, dev_id); +- local_irq_restore(flags); ++ local_irq_restore_nort(flags); + } + #endif + +@@ -614,6 +614,11 @@ int hardirq_preemption = 1; + + EXPORT_SYMBOL(hardirq_preemption); + ++/* ++ * Real-Time Preemption depends on hardirq threading: ++ */ ++#ifndef CONFIG_PREEMPT_RT ++ + static int __init hardirq_preempt_setup (char *str) + { + if (!strncmp(str, "off", 3)) +@@ -628,6 +633,7 @@ static int __init hardirq_preempt_setup + + __setup("hardirq-preempt=", hardirq_preempt_setup); + ++#endif + + /* + * threaded simple handler +@@ -787,12 +793,16 @@ static int do_irqd(void * __desc) + sys_sched_setscheduler(current->pid, SCHED_FIFO, ¶m); + + while (!kthread_should_stop()) { +- local_irq_disable(); ++ local_irq_disable_nort(); + set_current_state(TASK_INTERRUPTIBLE); ++#ifndef CONFIG_PREEMPT_RT + irq_enter(); ++#endif + do_hardirq(desc); ++#ifndef CONFIG_PREEMPT_RT + irq_exit(); +- local_irq_enable(); ++#endif ++ local_irq_enable_nort(); + cond_resched(); + #ifdef CONFIG_SMP + /* +Index: linux-2.6.24.7-rt27/kernel/irq/spurious.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/irq/spurious.c 2009-02-08 00:02:14.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/irq/spurious.c 2009-02-08 00:02:45.000000000 -0500 +@@ -59,9 +59,8 @@ static int misrouted_irq(int irq) + } + action = action->next; + } +- local_irq_disable(); + /* Now clean up the flags */ +- spin_lock(&desc->lock); ++ spin_lock_irq(&desc->lock); + action = desc->action; + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0097-mm-fix-latency.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0097-mm-fix-latency.patch @@ -0,0 +1,87 @@ +From: Hugh Dickins +Subject: reduce pagetable-freeing latencies + +2.6.15-rc1 moved the unlinking of a vma from its prio_tree and anon_vma +into free_pgtables: so the vma is hidden from rmap and vmtruncate before +freeing its page tables, allowing safe descent without page table lock. +But free_pgtables is still called with preemption disabled, and Lee +Revell has now detected high latency there. + +The right fix will be to rework the mmu_gathering, not to need preemption +disabled; but for now an ugly CONFIG_PREEMPT block in free_pgtables, to +make an initial unlinking pass with preemption enabled - made uglier by +CONFIG_IA64 definitions (only ia64 actually uses the start and end given +to tlb_finish_mmu, and our floor and ceiling don't quite work for those). +These CONFIG choices being to minimize the additional TLB flushing. + +Signed-off-by: Hugh Dickins +Signed-off-by: Ingo Molnar +-- + + mm/memory.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +Index: linux-2.6.24.7-rt27/mm/memory.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/memory.c 2009-02-08 00:00:46.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/memory.c 2009-02-08 00:01:27.000000000 -0500 +@@ -261,18 +261,48 @@ void free_pgd_range(struct mmu_gather ** + } while (pgd++, addr = next, addr != end); + } + ++#ifdef CONFIG_IA64 ++#define tlb_start_addr(tlb) (tlb)->start_addr ++#define tlb_end_addr(tlb) (tlb)->end_addr ++#else ++#define tlb_start_addr(tlb) 0UL /* only ia64 really uses it */ ++#define tlb_end_addr(tlb) 0UL /* only ia64 really uses it */ ++#endif ++ + void free_pgtables(struct mmu_gather **tlb, struct vm_area_struct *vma, + unsigned long floor, unsigned long ceiling) + { ++#ifdef CONFIG_PREEMPT ++ struct vm_area_struct *unlink = vma; ++ int fullmm = (*tlb)->fullmm; ++ ++ if (!vma) /* Sometimes when exiting after an oops */ ++ return; ++ if (vma->vm_next) ++ tlb_finish_mmu(*tlb, tlb_start_addr(*tlb), tlb_end_addr(*tlb)); ++ /* ++ * Hide vma from rmap and vmtruncate before freeeing pgtables, ++ * with preemption enabled, except when unmapping just one area. ++ */ ++ while (unlink) { ++ anon_vma_unlink(unlink); ++ unlink_file_vma(unlink); ++ unlink = unlink->vm_next; ++ } ++ if (vma->vm_next) ++ *tlb = tlb_gather_mmu(vma->vm_mm, fullmm); ++#endif + while (vma) { + struct vm_area_struct *next = vma->vm_next; + unsigned long addr = vma->vm_start; + ++#ifndef CONFIG_PREEMPT + /* + * Hide vma from rmap and vmtruncate before freeing pgtables + */ + anon_vma_unlink(vma); + unlink_file_vma(vma); ++#endif + + if (is_vm_hugetlb_page(vma)) { + hugetlb_free_pgd_range(tlb, addr, vma->vm_end, +@@ -285,8 +315,10 @@ void free_pgtables(struct mmu_gather **t + && !is_vm_hugetlb_page(next)) { + vma = next; + next = vma->vm_next; ++#ifndef CONFIG_PREEMPT + anon_vma_unlink(vma); + unlink_file_vma(vma); ++#endif + } + free_pgd_range(tlb, addr, vma->vm_end, + floor, next? next->vm_start: ceiling); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0446-rwsems-mulitple-readers.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0446-rwsems-mulitple-readers.patch @@ -0,0 +1,1106 @@ +From: Steven Rostedt +Subject: add framework for multi readers on rwsems + +Add the frame work for multiple readers and implemnt the code for +rwsem first. + +A new structure is created called rw_mutex. This is used by PREEMPT_RT +rwsems and will later be incorporated with rwlocks. + +The rw_mutex lock encapsulates the rt_mutex for use with rwsems (and later +rwlocks). This patch is just the ground work. It simply allows for mulitple +readers to grab the lock. This disables PI for readers. That is, when +a writer is blocked on a rwsem with readers, it will not boost the readers. +That work will be done later in the patch series. + +Signed-off-by: Steven Rostedt +--- + include/linux/lockdep.h | 13 + include/linux/rt_lock.h | 13 + kernel/rt.c | 64 ---- + kernel/rtmutex.c | 706 +++++++++++++++++++++++++++++++++++++++++++++++- + kernel/rtmutex_common.h | 57 +++ + 5 files changed, 795 insertions(+), 58 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/lockdep.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/lockdep.h 2009-02-08 00:03:26.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/lockdep.h 2009-02-08 00:04:22.000000000 -0500 +@@ -383,6 +383,16 @@ do { \ + ret; \ + }) + ++#define LOCK_CONTENDED_RT_RW(_lock, f_try, f_lock) \ ++do { \ ++ if (!f_try(&(_lock)->owners)) { \ ++ lock_contended(&(_lock)->dep_map, _RET_IP_); \ ++ f_lock(&(_lock)->owners); \ ++ } \ ++ lock_acquired(&(_lock)->dep_map); \ ++} while (0) ++ ++ + #else /* CONFIG_LOCK_STAT */ + + #define lock_contended(lockdep_map, ip) do {} while (0) +@@ -397,6 +407,9 @@ do { \ + #define LOCK_CONTENDED_RT_RET(_lock, f_try, f_lock) \ + f_lock(&(_lock)->lock) + ++#define LOCK_CONTENDED_RT_RW(_lock, f_try, f_lock) \ ++ f_lock(&(_lock)->owners) ++ + #endif /* CONFIG_LOCK_STAT */ + + #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS) +Index: linux-2.6.24.7-rt27/include/linux/rt_lock.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rt_lock.h 2009-02-08 00:03:41.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rt_lock.h 2009-02-08 00:04:22.000000000 -0500 +@@ -60,6 +60,12 @@ typedef raw_spinlock_t spinlock_t; + + #ifdef CONFIG_PREEMPT_RT + ++struct rw_mutex { ++ struct task_struct *owner; ++ struct rt_mutex mutex; ++ atomic_t count; /* number of times held for read */ ++}; ++ + /* + * RW-semaphores are a spinlock plus a reader-depth count. + * +@@ -71,8 +77,7 @@ typedef raw_spinlock_t spinlock_t; + * fair and makes it simpler as well: + */ + struct rw_semaphore { +- struct rt_mutex lock; +- int read_depth; ++ struct rw_mutex owners; + #ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; + #endif +@@ -189,7 +194,7 @@ extern int __bad_func_type(void); + */ + + #define __RWSEM_INITIALIZER(name) \ +- { .lock = __RT_MUTEX_INITIALIZER(name.lock), \ ++ { .owners.mutex = __RT_MUTEX_INITIALIZER(name.owners.mutex), \ + RW_DEP_MAP_INIT(name) } + + #define DECLARE_RWSEM(lockname) \ +@@ -222,7 +227,7 @@ extern void fastcall rt_up_read(struct r + extern void fastcall rt_up_write(struct rw_semaphore *rwsem); + extern void fastcall rt_downgrade_write(struct rw_semaphore *rwsem); + +-# define rt_rwsem_is_locked(rws) (rt_mutex_is_locked(&(rws)->lock)) ++# define rt_rwsem_is_locked(rws) ((rws)->owners.owner != NULL) + + #define PICK_RWSEM_OP(...) PICK_FUNCTION(struct compat_rw_semaphore *, \ + struct rw_semaphore *, ##__VA_ARGS__) +Index: linux-2.6.24.7-rt27/kernel/rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rt.c 2009-02-08 00:03:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rt.c 2009-02-08 00:04:22.000000000 -0500 +@@ -301,26 +301,14 @@ EXPORT_SYMBOL(__rt_rwlock_init); + void fastcall rt_up_write(struct rw_semaphore *rwsem) + { + rwsem_release(&rwsem->dep_map, 1, _RET_IP_); +- rt_mutex_unlock(&rwsem->lock); ++ rt_mutex_up_write(&rwsem->owners); + } + EXPORT_SYMBOL(rt_up_write); + + void fastcall rt_up_read(struct rw_semaphore *rwsem) + { +- unsigned long flags; +- + rwsem_release(&rwsem->dep_map, 1, _RET_IP_); +- /* +- * Read locks within the self-held write lock succeed. +- */ +- spin_lock_irqsave(&rwsem->lock.wait_lock, flags); +- if (rt_mutex_real_owner(&rwsem->lock) == current && rwsem->read_depth) { +- spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); +- rwsem->read_depth--; +- return; +- } +- spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); +- rt_mutex_unlock(&rwsem->lock); ++ rt_mutex_up_read(&rwsem->owners); + } + EXPORT_SYMBOL(rt_up_read); + +@@ -336,7 +324,7 @@ EXPORT_SYMBOL(rt_downgrade_write); + + int fastcall rt_down_write_trylock(struct rw_semaphore *rwsem) + { +- int ret = rt_mutex_trylock(&rwsem->lock); ++ int ret = rt_mutex_down_write_trylock(&rwsem->owners); + + if (ret) + rwsem_acquire(&rwsem->dep_map, 0, 1, _RET_IP_); +@@ -344,38 +332,29 @@ int fastcall rt_down_write_trylock(struc + } + EXPORT_SYMBOL(rt_down_write_trylock); + ++static void __rt_down_write(struct rw_semaphore *rwsem, int subclass) ++{ ++ rwsem_acquire(&rwsem->dep_map, subclass, 0, _RET_IP_); ++ LOCK_CONTENDED_RT_RW(rwsem, rt_mutex_down_write_trylock, rt_mutex_down_write); ++} ++ + void fastcall rt_down_write(struct rw_semaphore *rwsem) + { +- rwsem_acquire(&rwsem->dep_map, 0, 0, _RET_IP_); +- LOCK_CONTENDED_RT(rwsem, rt_mutex_trylock, rt_mutex_lock); ++ __rt_down_write(rwsem, 0); + } + EXPORT_SYMBOL(rt_down_write); + + void fastcall rt_down_write_nested(struct rw_semaphore *rwsem, int subclass) + { +- rwsem_acquire(&rwsem->dep_map, subclass, 0, _RET_IP_); +- LOCK_CONTENDED_RT(rwsem, rt_mutex_trylock, rt_mutex_lock); ++ __rt_down_write(rwsem, subclass); + } + EXPORT_SYMBOL(rt_down_write_nested); + + int fastcall rt_down_read_trylock(struct rw_semaphore *rwsem) + { +- unsigned long flags; + int ret; + +- /* +- * Read locks within the self-held write lock succeed. +- */ +- spin_lock_irqsave(&rwsem->lock.wait_lock, flags); +- if (rt_mutex_real_owner(&rwsem->lock) == current) { +- spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); +- rwsem_acquire_read(&rwsem->dep_map, 0, 1, _RET_IP_); +- rwsem->read_depth++; +- return 1; +- } +- spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); +- +- ret = rt_mutex_trylock(&rwsem->lock); ++ ret = rt_mutex_down_read_trylock(&rwsem->owners); + if (ret) + rwsem_acquire(&rwsem->dep_map, 0, 1, _RET_IP_); + return ret; +@@ -384,22 +363,8 @@ EXPORT_SYMBOL(rt_down_read_trylock); + + static void __rt_down_read(struct rw_semaphore *rwsem, int subclass) + { +- unsigned long flags; +- + rwsem_acquire_read(&rwsem->dep_map, subclass, 0, _RET_IP_); +- +- /* +- * Read locks within the write lock succeed. +- */ +- spin_lock_irqsave(&rwsem->lock.wait_lock, flags); +- +- if (rt_mutex_real_owner(&rwsem->lock) == current) { +- spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); +- rwsem->read_depth++; +- return; +- } +- spin_unlock_irqrestore(&rwsem->lock.wait_lock, flags); +- LOCK_CONTENDED_RT(rwsem, rt_mutex_trylock, rt_mutex_lock); ++ LOCK_CONTENDED_RT_RW(rwsem, rt_mutex_down_read_trylock, rt_mutex_down_read); + } + + void fastcall rt_down_read(struct rw_semaphore *rwsem) +@@ -424,8 +389,7 @@ void fastcall __rt_rwsem_init(struct rw_ + debug_check_no_locks_freed((void *)rwsem, sizeof(*rwsem)); + lockdep_init_map(&rwsem->dep_map, name, key, 0); + #endif +- __rt_mutex_init(&rwsem->lock, name); +- rwsem->read_depth = 0; ++ rt_mutex_rwsem_init(&rwsem->owners, name); + } + EXPORT_SYMBOL(__rt_rwsem_init); + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:22.000000000 -0500 +@@ -87,6 +87,7 @@ static void fixup_rt_mutex_waiters(struc + */ + #if defined(__HAVE_ARCH_CMPXCHG) && !defined(CONFIG_DEBUG_RT_MUTEXES) + # define rt_mutex_cmpxchg(l,c,n) (cmpxchg(&l->owner, c, n) == c) ++# define rt_rwlock_cmpxchg(rwm,c,n) (cmpxchg(&(rwm)->owner, c, n) == c) + static inline void mark_rt_mutex_waiters(struct rt_mutex *lock) + { + unsigned long owner, *p = (unsigned long *) &lock->owner; +@@ -95,13 +96,31 @@ static inline void mark_rt_mutex_waiters + owner = *p; + } while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner); + } ++#ifdef CONFIG_PREEMPT_RT ++static inline void mark_rt_rwlock_check(struct rw_mutex *rwm) ++{ ++ unsigned long owner, *p = (unsigned long *) &rwm->owner; ++ ++ do { ++ owner = *p; ++ } while (cmpxchg(p, owner, owner | RT_RWLOCK_CHECK) != owner); ++} ++#endif /* CONFIG_PREEMPT_RT */ + #else + # define rt_mutex_cmpxchg(l,c,n) (0) ++# define rt_rwlock_cmpxchg(l,c,n) ({ (void)c; (void)n; 0; }) + static inline void mark_rt_mutex_waiters(struct rt_mutex *lock) + { + lock->owner = (struct task_struct *) + ((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS); + } ++#ifdef CONFIG_PREEMPT_RT ++static inline void mark_rt_rwlock_check(struct rw_mutex *rwm) ++{ ++ rwm->owner = (struct task_struct *) ++ ((unsigned long)rwm->owner | RT_RWLOCK_CHECK); ++} ++#endif /* CONFIG_PREEMPT_RT */ + #endif + + int pi_initialized; +@@ -282,6 +301,13 @@ static int rt_mutex_adjust_prio_chain(st + + /* Grab the next task */ + task = rt_mutex_owner(lock); ++ ++ /* Writers do not boost their readers. */ ++ if (task == RT_RW_READER) { ++ spin_unlock_irqrestore(&lock->wait_lock, flags); ++ goto out; ++ } ++ + get_task_struct(task); + spin_lock(&task->pi_lock); + +@@ -315,7 +341,7 @@ static int rt_mutex_adjust_prio_chain(st + spin_unlock_irqrestore(&task->pi_lock, flags); + out_put_task: + put_task_struct(task); +- ++ out: + return ret; + } + +@@ -335,6 +361,8 @@ static inline int try_to_steal_lock(stru + if (pendowner == current) + return 1; + ++ WARN_ON(rt_mutex_owner(lock) == RT_RW_READER); ++ + spin_lock(&pendowner->pi_lock); + if (!lock_is_stealable(pendowner, mode)) { + spin_unlock(&pendowner->pi_lock); +@@ -462,6 +490,10 @@ static int task_blocks_on_rt_mutex(struc + spin_unlock(¤t->pi_lock); + + if (waiter == rt_mutex_top_waiter(lock)) { ++ /* readers are not handled */ ++ if (owner == RT_RW_READER) ++ return 0; ++ + spin_lock(&owner->pi_lock); + plist_del(&top_waiter->pi_list_entry, &owner->pi_waiters); + plist_add(&waiter->pi_list_entry, &owner->pi_waiters); +@@ -474,7 +506,7 @@ static int task_blocks_on_rt_mutex(struc + else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) + chain_walk = 1; + +- if (!chain_walk) ++ if (!chain_walk || owner == RT_RW_READER) + return 0; + + /* +@@ -574,7 +606,7 @@ static void remove_waiter(struct rt_mute + current->pi_blocked_on = NULL; + spin_unlock(¤t->pi_lock); + +- if (first && owner != current) { ++ if (first && owner != current && owner != RT_RW_READER) { + + spin_lock(&owner->pi_lock); + +@@ -747,6 +779,7 @@ rt_spin_lock_slowlock(struct rt_mutex *l + + debug_rt_mutex_init_waiter(&waiter); + waiter.task = NULL; ++ waiter.write_lock = 0; + + spin_lock_irqsave(&lock->wait_lock, flags); + init_lists(lock); +@@ -964,7 +997,671 @@ __rt_spin_lock_init(spinlock_t *lock, ch + } + EXPORT_SYMBOL(__rt_spin_lock_init); + +-#endif ++static inline int rt_release_bkl(struct rt_mutex *lock, unsigned long flags); ++static inline void rt_reacquire_bkl(int saved_lock_depth); ++ ++static inline void ++rt_rwlock_set_owner(struct rw_mutex *rwm, struct task_struct *owner, ++ unsigned long mask) ++{ ++ unsigned long val = (unsigned long)owner | mask; ++ ++ rwm->owner = (struct task_struct *)val; ++} ++ ++/* ++ * The fast paths of the rw locks do not set up owners to ++ * the mutex. When blocking on an rwlock we must make sure ++ * there exists an owner. ++ */ ++static void ++update_rw_mutex_owner(struct rw_mutex *rwm) ++{ ++ struct rt_mutex *mutex = &rwm->mutex; ++ struct task_struct *mtxowner; ++ ++ mtxowner = rt_mutex_owner(mutex); ++ if (mtxowner) ++ return; ++ ++ mtxowner = rt_rwlock_owner(rwm); ++ WARN_ON(!mtxowner); ++ if (rt_rwlock_writer(rwm)) ++ WARN_ON(mtxowner == RT_RW_READER); ++ else ++ mtxowner = RT_RW_READER; ++ rt_mutex_set_owner(mutex, mtxowner, 0); ++} ++ ++static int try_to_take_rw_read(struct rw_mutex *rwm) ++{ ++ struct rt_mutex *mutex = &rwm->mutex; ++ struct rt_mutex_waiter *waiter; ++ struct task_struct *mtxowner; ++ ++ assert_spin_locked(&mutex->wait_lock); ++ ++ /* mark the lock to force the owner to check on release */ ++ mark_rt_rwlock_check(rwm); ++ ++ /* is the owner a writer? */ ++ if (unlikely(rt_rwlock_writer(rwm))) ++ return 0; ++ ++ /* A writer is not the owner, but is a writer waiting */ ++ mtxowner = rt_mutex_owner(mutex); ++ ++ /* if the owner released it before we marked it then take it */ ++ if (!mtxowner && !rt_rwlock_owner(rwm)) { ++ WARN_ON(atomic_read(&rwm->count)); ++ rt_rwlock_set_owner(rwm, current, 0); ++ goto taken; ++ } ++ ++ if (mtxowner && mtxowner != RT_RW_READER) { ++ if (!try_to_steal_lock(mutex)) { ++ /* ++ * readers don't own the mutex, and rwm shows that a ++ * writer doesn't have it either. If we enter this ++ * condition, then we must be pending. ++ */ ++ WARN_ON(!rt_mutex_owner_pending(mutex)); ++ /* ++ * Even though we didn't steal the lock, if the owner ++ * is a reader, and we are of higher priority than ++ * any waiting writer, we might still be able to continue. ++ */ ++ if (rt_rwlock_pending_writer(rwm)) ++ return 0; ++ if (rt_mutex_has_waiters(mutex)) { ++ /* readers don't do PI */ ++ waiter = rt_mutex_top_waiter(mutex); ++ if (current->prio >= waiter->task->prio) ++ return 0; ++ /* ++ * The pending reader has PI waiters, ++ * but we are taking the lock. ++ * Remove the waiters from the pending owner. ++ */ ++ spin_lock(&mtxowner->pi_lock); ++ plist_del(&waiter->pi_list_entry, &mtxowner->pi_waiters); ++ spin_unlock(&mtxowner->pi_lock); ++ } ++ } else if (rt_mutex_has_waiters(mutex)) { ++ /* Readers don't do PI */ ++ waiter = rt_mutex_top_waiter(mutex); ++ spin_lock(¤t->pi_lock); ++ plist_del(&waiter->pi_list_entry, ¤t->pi_waiters); ++ spin_unlock(¤t->pi_lock); ++ } ++ /* Readers never own the mutex */ ++ rt_mutex_set_owner(mutex, RT_RW_READER, 0); ++ } ++ ++ /* RT_RW_READER forces slow paths */ ++ rt_rwlock_set_owner(rwm, RT_RW_READER, 0); ++ taken: ++ rt_mutex_deadlock_account_lock(mutex, current); ++ atomic_inc(&rwm->count); ++ return 1; ++} ++ ++static int ++try_to_take_rw_write(struct rw_mutex *rwm) ++{ ++ struct rt_mutex *mutex = &rwm->mutex; ++ struct task_struct *own; ++ ++ /* mark the lock to force the owner to check on release */ ++ mark_rt_rwlock_check(rwm); ++ ++ own = rt_rwlock_owner(rwm); ++ ++ /* readers or writers? */ ++ if ((own && !rt_rwlock_pending(rwm))) ++ return 0; ++ ++ WARN_ON(atomic_read(&rwm->count)); ++ ++ /* ++ * RT_RW_PENDING means that the lock is free, but there are ++ * pending owners on the mutex ++ */ ++ WARN_ON(own && !rt_mutex_owner_pending(mutex)); ++ ++ if (!try_to_take_rt_mutex(mutex)) ++ return 0; ++ ++ /* ++ * We stole the lock. Add both WRITER and CHECK flags ++ * since we must release the mutex. ++ */ ++ rt_rwlock_set_owner(rwm, current, RT_RWLOCK_WRITER | RT_RWLOCK_CHECK); ++ ++ return 1; ++} ++ ++static void ++rt_read_slowlock(struct rw_mutex *rwm) ++{ ++ struct rt_mutex_waiter waiter; ++ struct rt_mutex *mutex = &rwm->mutex; ++ int saved_lock_depth = -1; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&mutex->wait_lock, flags); ++ init_lists(mutex); ++ ++ if (try_to_take_rw_read(rwm)) { ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ return; ++ } ++ update_rw_mutex_owner(rwm); ++ ++ /* Owner is a writer (or a blocked writer). Block on the lock */ ++ ++ debug_rt_mutex_init_waiter(&waiter); ++ waiter.task = NULL; ++ waiter.write_lock = 0; ++ ++ init_lists(mutex); ++ ++ /* ++ * We drop the BKL here before we go into the wait loop to avoid a ++ * possible deadlock in the scheduler. ++ */ ++ if (unlikely(current->lock_depth >= 0)) ++ saved_lock_depth = rt_release_bkl(mutex, flags); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ ++ for (;;) { ++ unsigned long saved_flags; ++ ++ /* Try to acquire the lock: */ ++ if (try_to_take_rw_read(rwm)) ++ break; ++ update_rw_mutex_owner(rwm); ++ ++ /* ++ * waiter.task is NULL the first time we come here and ++ * when we have been woken up by the previous owner ++ * but the lock got stolen by a higher prio task. ++ */ ++ if (!waiter.task) { ++ task_blocks_on_rt_mutex(mutex, &waiter, 0, flags); ++ /* Wakeup during boost ? */ ++ if (unlikely(!waiter.task)) ++ continue; ++ } ++ saved_flags = current->flags & PF_NOSCHED; ++ current->flags &= ~PF_NOSCHED; ++ ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ ++ debug_rt_mutex_print_deadlock(&waiter); ++ ++ if (waiter.task) ++ schedule_rt_mutex(mutex); ++ ++ spin_lock_irqsave(&mutex->wait_lock, flags); ++ ++ current->flags |= saved_flags; ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ } ++ ++ set_current_state(TASK_RUNNING); ++ ++ if (unlikely(waiter.task)) ++ remove_waiter(mutex, &waiter, flags); ++ ++ WARN_ON(rt_mutex_owner(mutex) && ++ rt_mutex_owner(mutex) != current && ++ rt_mutex_owner(mutex) != RT_RW_READER && ++ !rt_mutex_owner_pending(mutex)); ++ ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ ++ /* Must we reaquire the BKL? */ ++ if (unlikely(saved_lock_depth >= 0)) ++ rt_reacquire_bkl(saved_lock_depth); ++ ++ debug_rt_mutex_free_waiter(&waiter); ++} ++ ++static inline void ++rt_read_fastlock(struct rw_mutex *rwm, ++ void fastcall (*slowfn)(struct rw_mutex *rwm)) ++{ ++retry: ++ if (likely(rt_rwlock_cmpxchg(rwm, NULL, current))) { ++ rt_mutex_deadlock_account_lock(&rwm->mutex, current); ++ atomic_inc(&rwm->count); ++ /* ++ * It is possible that the owner was zeroed ++ * before we incremented count. If owner is not ++ * current, then retry again ++ */ ++ if (unlikely(rwm->owner != current)) { ++ atomic_dec(&rwm->count); ++ goto retry; ++ } ++ } else ++ slowfn(rwm); ++} ++ ++void fastcall rt_mutex_down_read(struct rw_mutex *rwm) ++{ ++ rt_read_fastlock(rwm, rt_read_slowlock); ++} ++ ++ ++static inline int ++rt_read_slowtrylock(struct rw_mutex *rwm) ++{ ++ struct rt_mutex *mutex = &rwm->mutex; ++ unsigned long flags; ++ int ret = 0; ++ ++ spin_lock_irqsave(&mutex->wait_lock, flags); ++ init_lists(mutex); ++ ++ if (try_to_take_rw_read(rwm)) ++ ret = 1; ++ ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ ++ return ret; ++} ++ ++static inline int ++rt_read_fasttrylock(struct rw_mutex *rwm, ++ int fastcall (*slowfn)(struct rw_mutex *rwm)) ++{ ++retry: ++ if (likely(rt_rwlock_cmpxchg(rwm, NULL, current))) { ++ rt_mutex_deadlock_account_lock(&rwm->mutex, current); ++ atomic_inc(&rwm->count); ++ /* ++ * It is possible that the owner was zeroed ++ * before we incremented count. If owner is not ++ * current, then retry again ++ */ ++ if (unlikely(rwm->owner != current)) { ++ atomic_dec(&rwm->count); ++ goto retry; ++ } ++ return 1; ++ } else ++ return slowfn(rwm); ++} ++ ++int __sched rt_mutex_down_read_trylock(struct rw_mutex *rwm) ++{ ++ return rt_read_fasttrylock(rwm, rt_read_slowtrylock); ++} ++ ++static void ++rt_write_slowlock(struct rw_mutex *rwm) ++{ ++ struct rt_mutex *mutex = &rwm->mutex; ++ struct rt_mutex_waiter waiter; ++ int saved_lock_depth = -1; ++ unsigned long flags; ++ ++ debug_rt_mutex_init_waiter(&waiter); ++ waiter.task = NULL; ++ ++ /* we do PI different for writers that are blocked */ ++ waiter.write_lock = 1; ++ ++ spin_lock_irqsave(&mutex->wait_lock, flags); ++ init_lists(mutex); ++ ++ if (try_to_take_rw_write(rwm)) { ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ return; ++ } ++ update_rw_mutex_owner(rwm); ++ ++ /* ++ * We drop the BKL here before we go into the wait loop to avoid a ++ * possible deadlock in the scheduler. ++ */ ++ if (unlikely(current->lock_depth >= 0)) ++ saved_lock_depth = rt_release_bkl(mutex, flags); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ ++ for (;;) { ++ unsigned long saved_flags; ++ ++ /* Try to acquire the lock: */ ++ if (try_to_take_rw_write(rwm)) ++ break; ++ update_rw_mutex_owner(rwm); ++ ++ /* ++ * waiter.task is NULL the first time we come here and ++ * when we have been woken up by the previous owner ++ * but the lock got stolen by a higher prio task. ++ */ ++ if (!waiter.task) { ++ task_blocks_on_rt_mutex(mutex, &waiter, 0, flags); ++ /* Wakeup during boost ? */ ++ if (unlikely(!waiter.task)) ++ continue; ++ } ++ saved_flags = current->flags & PF_NOSCHED; ++ current->flags &= ~PF_NOSCHED; ++ ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ ++ debug_rt_mutex_print_deadlock(&waiter); ++ ++ if (waiter.task) ++ schedule_rt_mutex(mutex); ++ ++ spin_lock_irqsave(&mutex->wait_lock, flags); ++ ++ current->flags |= saved_flags; ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ } ++ ++ set_current_state(TASK_RUNNING); ++ ++ if (unlikely(waiter.task)) ++ remove_waiter(mutex, &waiter, flags); ++ ++ /* check on unlock if we have any waiters. */ ++ if (rt_mutex_has_waiters(mutex)) ++ mark_rt_rwlock_check(rwm); ++ ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ ++ /* Must we reaquire the BKL? */ ++ if (unlikely(saved_lock_depth >= 0)) ++ rt_reacquire_bkl(saved_lock_depth); ++ ++ WARN_ON(atomic_read(&rwm->count)); ++ ++ debug_rt_mutex_free_waiter(&waiter); ++ ++} ++ ++static inline void ++rt_write_fastlock(struct rw_mutex *rwm, ++ void fastcall (*slowfn)(struct rw_mutex *rwm)) ++{ ++ unsigned long val = (unsigned long)current | RT_RWLOCK_WRITER; ++ ++ if (likely(rt_rwlock_cmpxchg(rwm, NULL, val))) { ++ rt_mutex_deadlock_account_lock(&rwm->mutex, current); ++ WARN_ON(atomic_read(&rwm->count)); ++ } else ++ slowfn(rwm); ++} ++ ++void fastcall rt_mutex_down_write(struct rw_mutex *rwm) ++{ ++ rt_write_fastlock(rwm, rt_write_slowlock); ++} ++ ++static int ++rt_write_slowtrylock(struct rw_mutex *rwm) ++{ ++ struct rt_mutex *mutex = &rwm->mutex; ++ unsigned long flags; ++ int ret = 0; ++ ++ spin_lock_irqsave(&mutex->wait_lock, flags); ++ init_lists(mutex); ++ ++ if (try_to_take_rw_write(rwm)) ++ ret = 1; ++ ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ ++ return ret; ++} ++ ++static inline int ++rt_write_fasttrylock(struct rw_mutex *rwm, ++ int fastcall (*slowfn)(struct rw_mutex *rwm)) ++{ ++ unsigned long val = (unsigned long)current | RT_RWLOCK_WRITER; ++ ++ if (likely(rt_rwlock_cmpxchg(rwm, NULL, val))) { ++ rt_mutex_deadlock_account_lock(&rwm->mutex, current); ++ WARN_ON(atomic_read(&rwm->count)); ++ return 1; ++ } else ++ return slowfn(rwm); ++} ++ ++int fastcall rt_mutex_down_write_trylock(struct rw_mutex *rwm) ++{ ++ return rt_write_fasttrylock(rwm, rt_write_slowtrylock); ++} ++ ++static void fastcall noinline __sched ++rt_read_slowunlock(struct rw_mutex *rwm) ++{ ++ struct rt_mutex *mutex = &rwm->mutex; ++ unsigned long flags; ++ struct rt_mutex_waiter *waiter; ++ ++ spin_lock_irqsave(&mutex->wait_lock, flags); ++ ++ rt_mutex_deadlock_account_unlock(current); ++ ++ /* ++ * To prevent multiple readers from zeroing out the owner ++ * when the count goes to zero and then have another task ++ * grab the task. We mark the lock. This makes all tasks ++ * go to the slow path. Then we can check the owner without ++ * worry that it changed. ++ */ ++ mark_rt_rwlock_check(rwm); ++ ++ /* ++ * If there are more readers, let the last one do any wakeups. ++ * Also check to make sure the owner wasn't cleared when two ++ * readers released the lock at the same time, and the count ++ * went to zero before grabbing the wait_lock. ++ */ ++ if (atomic_read(&rwm->count) || ++ (rt_rwlock_owner(rwm) != current && ++ rt_rwlock_owner(rwm) != RT_RW_READER)) { ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ return; ++ } ++ ++ /* If no one is blocked, then clear all ownership */ ++ if (!rt_mutex_has_waiters(mutex)) { ++ /* We could still have a pending reader waiting */ ++ if (rt_mutex_owner_pending(mutex)) { ++ /* set the rwm back to pending */ ++ rwm->owner = RT_RW_PENDING_READ; ++ } else { ++ rwm->owner = NULL; ++ mutex->owner = NULL; ++ } ++ goto out; ++ } ++ ++ /* We are the last reader with pending waiters. */ ++ waiter = rt_mutex_top_waiter(mutex); ++ if (waiter->write_lock) ++ rwm->owner = RT_RW_PENDING_WRITE; ++ else ++ rwm->owner = RT_RW_PENDING_READ; ++ ++ /* ++ * It is possible to have a reader waiting. We still only ++ * wake one up in that case. A way we can have a reader waiting ++ * is because a writer woke up, a higher prio reader came ++ * and stole the lock from the writer. But the writer now ++ * is no longer waiting on the lock and needs to retake ++ * the lock. We simply wake up the reader and let the ++ * reader have the lock. If the writer comes by, it ++ * will steal the lock from the reader. This is the ++ * only time we can have a reader pending on a lock. ++ */ ++ wakeup_next_waiter(mutex, 0); ++ ++ out: ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ ++ /* Undo pi boosting.when necessary */ ++ rt_mutex_adjust_prio(current); ++} ++ ++static inline void ++rt_read_fastunlock(struct rw_mutex *rwm, ++ void fastcall (*slowfn)(struct rw_mutex *rwm)) ++{ ++ WARN_ON(!atomic_read(&rwm->count)); ++ WARN_ON(!rwm->owner); ++ atomic_dec(&rwm->count); ++ if (likely(rt_rwlock_cmpxchg(rwm, current, NULL))) ++ rt_mutex_deadlock_account_unlock(current); ++ else ++ slowfn(rwm); ++} ++ ++void fastcall rt_mutex_up_read(struct rw_mutex *rwm) ++{ ++ rt_read_fastunlock(rwm, rt_read_slowunlock); ++} ++ ++static void fastcall noinline __sched ++rt_write_slowunlock(struct rw_mutex *rwm) ++{ ++ struct rt_mutex *mutex = &rwm->mutex; ++ struct rt_mutex_waiter *waiter; ++ struct task_struct *pendowner; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&mutex->wait_lock, flags); ++ ++ rt_mutex_deadlock_account_unlock(current); ++ ++ if (!rt_mutex_has_waiters(mutex)) { ++ rwm->owner = NULL; ++ mutex->owner = NULL; ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ return; ++ } ++ ++ debug_rt_mutex_unlock(mutex); ++ ++ /* ++ * This is where it gets a bit tricky. ++ * We can have both readers and writers waiting below us. ++ * They are ordered by priority. For each reader we wake ++ * up, we check to see if there's another reader waiting. ++ * If that is the case, we continue to wake up the readers ++ * until we hit a writer. Once we hit a writer, then we ++ * stop (and don't wake it up). ++ * ++ * If the next waiter is a writer, than we just wake up ++ * the writer and we are done. ++ */ ++ ++ waiter = rt_mutex_top_waiter(mutex); ++ pendowner = waiter->task; ++ wakeup_next_waiter(mutex, 0); ++ ++ /* another writer is next? */ ++ if (waiter->write_lock) { ++ rwm->owner = RT_RW_PENDING_WRITE; ++ goto out; ++ } ++ ++ rwm->owner = RT_RW_PENDING_READ; ++ ++ if (!rt_mutex_has_waiters(mutex)) ++ goto out; ++ ++ spin_lock(&pendowner->pi_lock); ++ /* ++ * Wake up all readers. ++ * This gets a bit more complex. More than one reader can't ++ * own the mutex. We give it to the first (highest prio) ++ * reader, and then wake up the rest of the readers until ++ * we wake up all readers or come to a writer. The woken ++ * up readers that don't own the lock will try to take it ++ * when they schedule. Doing this lets a high prio writer ++ * come along and steal the lock. ++ */ ++ waiter = rt_mutex_top_waiter(mutex); ++ while (waiter && !waiter->write_lock) { ++ struct task_struct *reader = waiter->task; ++ ++ plist_del(&waiter->list_entry, &mutex->wait_list); ++ ++ /* nop if not on a list */ ++ plist_del(&waiter->pi_list_entry, &pendowner->pi_waiters); ++ ++ waiter->task = NULL; ++ reader->pi_blocked_on = NULL; ++ ++ wake_up_process(reader); ++ ++ if (rt_mutex_has_waiters(mutex)) ++ waiter = rt_mutex_top_waiter(mutex); ++ else ++ waiter = NULL; ++ } ++ ++ /* If a writer is still pending, then update its plist. */ ++ if (rt_mutex_has_waiters(mutex)) { ++ struct rt_mutex_waiter *next; ++ ++ next = rt_mutex_top_waiter(mutex); ++ /* delete incase we didn't go through the loop */ ++ plist_del(&next->pi_list_entry, &pendowner->pi_waiters); ++ /* add back in as top waiter */ ++ plist_add(&next->pi_list_entry, &pendowner->pi_waiters); ++ } ++ spin_unlock(&pendowner->pi_lock); ++ ++ out: ++ ++ spin_unlock_irqrestore(&mutex->wait_lock, flags); ++ ++ /* Undo pi boosting.when necessary */ ++ rt_mutex_adjust_prio(current); ++} ++ ++static inline void ++rt_write_fastunlock(struct rw_mutex *rwm, ++ void fastcall (*slowfn)(struct rw_mutex *rwm)) ++{ ++ unsigned long val = (unsigned long)current | RT_RWLOCK_WRITER; ++ ++ WARN_ON(rt_rwlock_owner(rwm) != current); ++ if (likely(rt_rwlock_cmpxchg(rwm, (struct task_struct *)val, NULL))) ++ rt_mutex_deadlock_account_unlock(current); ++ else ++ slowfn(rwm); ++} ++ ++void fastcall rt_mutex_up_write(struct rw_mutex *rwm) ++{ ++ rt_write_fastunlock(rwm, rt_write_slowunlock); ++} ++ ++void rt_mutex_rwsem_init(struct rw_mutex *rwm, const char *name) ++{ ++ struct rt_mutex *mutex = &rwm->mutex; ++ ++ rwm->owner = NULL; ++ atomic_set(&rwm->count, 0); ++ ++ __rt_mutex_init(mutex, name); ++} ++ ++#endif /* CONFIG_PREEMPT_RT */ + + #ifdef CONFIG_PREEMPT_BKL + +@@ -1012,6 +1709,7 @@ rt_mutex_slowlock(struct rt_mutex *lock, + + debug_rt_mutex_init_waiter(&waiter); + waiter.task = NULL; ++ waiter.write_lock = 0; + + spin_lock_irqsave(&lock->wait_lock, flags); + init_lists(lock); +Index: linux-2.6.24.7-rt27/kernel/rtmutex_common.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex_common.h 2009-02-08 00:04:21.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex_common.h 2009-02-08 00:04:22.000000000 -0500 +@@ -13,6 +13,7 @@ + #define __KERNEL_RTMUTEX_COMMON_H + + #include ++#include + + /* + * The rtmutex in kernel tester is independent of rtmutex debugging. We +@@ -43,12 +44,14 @@ extern void schedule_rt_mutex_test(struc + * @list_entry: pi node to enqueue into the mutex waiters list + * @pi_list_entry: pi node to enqueue into the mutex owner waiters list + * @task: task reference to the blocked task ++ * @write_lock: true if blocked as writer + */ + struct rt_mutex_waiter { + struct plist_node list_entry; + struct plist_node pi_list_entry; + struct task_struct *task; + struct rt_mutex *lock; ++ int write_lock; + #ifdef CONFIG_DEBUG_RT_MUTEXES + unsigned long ip; + pid_t deadlock_task_pid; +@@ -112,6 +115,60 @@ static inline unsigned long rt_mutex_own + return (unsigned long)lock->owner & RT_MUTEX_OWNER_PENDING; + } + ++#ifdef CONFIG_PREEMPT_RT ++/* ++ * rw_mutex->owner state tracking ++ */ ++#define RT_RWLOCK_CHECK 1UL ++#define RT_RWLOCK_WRITER 2UL ++#define RT_RWLOCK_MASKALL 3UL ++ ++/* used as reader owner of the mutex */ ++#define RT_RW_READER (struct task_struct *)0x100 ++ ++/* used when a writer releases the lock with waiters */ ++/* pending owner is a reader */ ++#define RT_RW_PENDING_READ (struct task_struct *)0x200 ++/* pending owner is a writer */ ++#define RT_RW_PENDING_WRITE (struct task_struct *)0x400 ++/* Either of the above is true */ ++#define RT_RW_PENDING_MASK (0x600 | RT_RWLOCK_MASKALL) ++ ++/* Return true if lock is not owned but has pending owners */ ++static inline int rt_rwlock_pending(struct rw_mutex *rwm) ++{ ++ unsigned long owner = (unsigned long)rwm->owner; ++ return (owner & RT_RW_PENDING_MASK) == owner; ++} ++ ++static inline int rt_rwlock_pending_writer(struct rw_mutex *rwm) ++{ ++ unsigned long owner = (unsigned long)rwm->owner; ++ return rt_rwlock_pending(rwm) && ++ (owner & (unsigned long)RT_RW_PENDING_WRITE); ++} ++ ++static inline struct task_struct *rt_rwlock_owner(struct rw_mutex *rwm) ++{ ++ return (struct task_struct *) ++ ((unsigned long)rwm->owner & ~RT_RWLOCK_MASKALL); ++} ++ ++static inline unsigned long rt_rwlock_writer(struct rw_mutex *rwm) ++{ ++ return (unsigned long)rwm->owner & RT_RWLOCK_WRITER; ++} ++ ++extern void rt_mutex_up_write(struct rw_mutex *rwm); ++extern void rt_mutex_up_read(struct rw_mutex *rwm); ++extern int rt_mutex_down_write_trylock(struct rw_mutex *rwm); ++extern void rt_mutex_down_write(struct rw_mutex *rwm); ++extern int rt_mutex_down_read_trylock(struct rw_mutex *rwm); ++extern void rt_mutex_down_read(struct rw_mutex *rwm); ++extern void rt_mutex_rwsem_init(struct rw_mutex *rwm, const char *name); ++ ++#endif /* CONFIG_PREEMPT_RT */ ++ + /* + * PI-futex support (proxy locking functions, etc.): + */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0578-05-trace-warn-if-irqs-enabled-irqs-off.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0578-05-trace-warn-if-irqs-enabled-irqs-off.patch @@ -0,0 +1,32 @@ +From tglx@linutronix.de Fri Jan 30 06:50:01 2009 +Date: Fri, 30 Jan 2009 11:43:46 -0000 +From: Thomas Gleixner +To: LKML +Cc: Steven Rostedt , Carsten Emde , Carsten Emde +Subject: [patch-rt 5/5] trace: warn if irqs already enabled in irqs_off latency check + +Be consistent: Warn if irqs are already enabled in irqs_off latency +processing, same as in preempt_off and in irqs_off && preempt_off. This +warning can now safely be inserted, after a problem was fixed that +caused false positives. + +Signed-off-by: Carsten Emde +Signed-off-by: Thomas Gleixner + + +--- + kernel/trace/trace_hist.c | 1 + + 1 file changed, 1 insertion(+) + +Index: linux-2.6.24.7-rt27/kernel/trace/trace_hist.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace_hist.c 2009-02-08 00:05:24.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace_hist.c 2009-02-08 00:05:26.000000000 -0500 +@@ -356,6 +356,7 @@ notrace void tracing_hist_preempt_stop(i + #ifdef CONFIG_INTERRUPT_OFF_HIST + if (irqs_on && + per_cpu(hist_irqsoff_tracing, cpu)) { ++ WARN_ON(!irqs_disabled()); + stop = ftrace_now(cpu); + stop_set++; + start = per_cpu(hist_irqsoff_start, cpu); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0477-adaptive-earlybreak-on-steal.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0477-adaptive-earlybreak-on-steal.patch @@ -0,0 +1,48 @@ +From: Steven Rostedt +Subject: rtmutex: break out early on first run + +Lock stealing and non cmpxchg will always go into the slow path. +This patch detects the fact that we didn't go through the work of +blocking and will exit early. + +Signed-off-by: Steven Rostedt +--- + kernel/rtmutex.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:04:37.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:04:37.000000000 -0500 +@@ -834,6 +834,7 @@ rt_spin_lock_slowlock(struct rt_mutex *l + struct rt_mutex_waiter waiter; + unsigned long saved_state, state, flags; + struct task_struct *orig_owner; ++ int missed = 0; + + debug_rt_mutex_init_waiter(&waiter); + waiter.task = NULL; +@@ -860,8 +861,14 @@ rt_spin_lock_slowlock(struct rt_mutex *l + int saved_lock_depth = current->lock_depth; + + /* Try to acquire the lock */ +- if (do_try_to_take_rt_mutex(lock, STEAL_LATERAL)) ++ if (do_try_to_take_rt_mutex(lock, STEAL_LATERAL)) { ++ /* If we never blocked break out now */ ++ if (!missed) ++ goto unlock; + break; ++ } ++ missed = 1; ++ + /* + * waiter.task is NULL the first time we come here and + * when we have been woken up by the previous owner +@@ -920,6 +927,7 @@ rt_spin_lock_slowlock(struct rt_mutex *l + */ + fixup_rt_mutex_waiters(lock); + ++ unlock: + spin_unlock_irqrestore(&lock->wait_lock, flags); + + debug_rt_mutex_free_waiter(&waiter); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0048-0037-sched-whitespace-cleanups-in-topology.h.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0048-0037-sched-whitespace-cleanups-in-topology.h.patch @@ -0,0 +1,26 @@ +From e7e60ed8c8913b8bcebab7e9147d32b3aa430fb8 Mon Sep 17 00:00:00 2001 +From: Ingo Molnar +Date: Tue, 11 Dec 2007 10:02:47 +0100 +Subject: [PATCH] sched: whitespace cleanups in topology.h + +whitespace cleanups in topology.h. + +Signed-off-by: Ingo Molnar + +--- + include/linux/topology.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/include/linux/topology.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/topology.h 2009-02-08 00:00:28.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/topology.h 2009-02-08 00:01:06.000000000 -0500 +@@ -5,7 +5,7 @@ + * + * Copyright (C) 2002, IBM Corp. + * +- * All rights reserved. ++ * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0438-time-gcc-linker-error.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0438-time-gcc-linker-error.patch @@ -0,0 +1,50 @@ +From tglx@linutronix.de Thu May 15 09:57:11 2008 +Date: Wed, 9 Apr 2008 17:45:01 +0200 (CEST) +From: Thomas Gleixner +To: Steven Rostedt +Subject: GCC 4.3 kernel linker error (fwd) + + +There is a fix in mainline for that as well. Pick the mainline one, +though both are ugly as hell. + +Thanks, + tglx + + +---------- Forwarded message ---------- +Date: Tue, 01 Apr 2008 01:10:06 +0200 +From: Carsten Emde +To: Thomas Gleixner +Subject: GCC 4.3 kernel linker error + +Thomas, + +GCC 4.3 still complains with strange linker errors, ("__udivd3 undefined") when +compiling 2.6.24.4-rt4. I reported this problem about two months ago. Wouldn't +you mind to apply the below patch to the next rt release? The patch applies to +2.6.24.4-rt4. + +Carsten. + + + + [ Part 2: "" ] + +--- + include/linux/time.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/include/linux/time.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/time.h 2009-02-08 00:02:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/time.h 2009-02-08 00:04:19.000000000 -0500 +@@ -169,7 +169,7 @@ extern struct timeval ns_to_timeval(cons + * @a: pointer to timespec to be incremented + * @ns: unsigned nanoseconds value to be added + */ +-static inline void timespec_add_ns(struct timespec *a, u64 ns) ++static inline void timespec_add_ns(struct timespec *a, volatile u64 ns) + { + ns += a->tv_nsec; + while(unlikely(ns >= NSEC_PER_SEC)) { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0056-remove-unused-var-warning.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0056-remove-unused-var-warning.patch @@ -0,0 +1,24 @@ +From: Remy Bohmer +Subject: fix warning on dec_rt_tasks on UP + +Signed-off-by: Remy Bohmer + +--- + kernel/sched_rt.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/sched_rt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/sched_rt.c 2009-02-08 00:01:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/sched_rt.c 2009-02-08 00:01:09.000000000 -0500 +@@ -86,8 +86,9 @@ static inline void inc_rt_tasks(struct t + + static inline void dec_rt_tasks(struct task_struct *p, struct rq *rq) + { ++#ifdef CONFIG_SMP + int highest_prio = rq->rt.highest_prio; +- ++#endif + WARN_ON(!rt_task(p)); + WARN_ON(!rq->rt.rt_nr_running); + rq->rt.rt_nr_running--; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0546-d4496b39559c6d43f83e4c08b899984f8b8089b5.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0546-d4496b39559c6d43f83e4c08b899984f8b8089b5.patch @@ -0,0 +1,50 @@ +commit d4496b39559c6d43f83e4c08b899984f8b8089b5 +Author: Thomas Gleixner +Date: Wed Sep 3 21:36:57 2008 +0000 + + clockevents: prevent endless loop in periodic broadcast handler + + The reprogramming of the periodic broadcast handler was broken, + when the first programming returned -ETIME. The clockevents code + stores the new expiry value in the clock events device next_event field + only when the programming time has not been elapsed yet. The loop in + question calculates the new expiry value from the next_event value + and therefor never increases. + + Signed-off-by: Thomas Gleixner + Signed-off-by: Ingo Molnar + +--- + kernel/time/tick-broadcast.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/time/tick-broadcast.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/time/tick-broadcast.c 2009-02-08 00:02:49.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/time/tick-broadcast.c 2009-02-08 00:05:10.000000000 -0500 +@@ -177,6 +177,8 @@ static void tick_do_periodic_broadcast(v + */ + static void tick_handle_periodic_broadcast(struct clock_event_device *dev) + { ++ ktime_t next; ++ + tick_do_periodic_broadcast(); + + /* +@@ -187,10 +189,13 @@ static void tick_handle_periodic_broadca + + /* + * Setup the next period for devices, which do not have +- * periodic mode: ++ * periodic mode. We read dev->next_event first and add to it ++ * when the event alrady expired. clockevents_program_event() ++ * sets dev->next_event only when the event is really ++ * programmed to the device. + */ +- for (;;) { +- ktime_t next = ktime_add(dev->next_event, tick_period); ++ for (next = dev->next_event; ;) { ++ next = ktime_add(next, tick_period); + + if (!clockevents_program_event(dev, next, ktime_get())) + return; --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0252-preempt-realtime-input.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0252-preempt-realtime-input.patch @@ -0,0 +1,45 @@ +--- + drivers/input/gameport/gameport.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +Index: linux-2.6.24.7-rt27/drivers/input/gameport/gameport.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/input/gameport/gameport.c 2009-02-07 23:59:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/input/gameport/gameport.c 2009-02-08 00:02:45.000000000 -0500 +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include /* HZ */ + #include + #include +@@ -100,12 +101,12 @@ static int gameport_measure_speed(struct + tx = 1 << 30; + + for(i = 0; i < 50; i++) { +- local_irq_save(flags); ++ local_irq_save_nort(flags); + GET_TIME(t1); + for (t = 0; t < 50; t++) gameport_read(gameport); + GET_TIME(t2); + GET_TIME(t3); +- local_irq_restore(flags); ++ local_irq_restore_nort(flags); + udelay(i * 10); + if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t; + } +@@ -124,11 +125,11 @@ static int gameport_measure_speed(struct + tx = 1 << 30; + + for(i = 0; i < 50; i++) { +- local_irq_save(flags); ++ local_irq_save_nort(flags); + rdtscl(t1); + for (t = 0; t < 50; t++) gameport_read(gameport); + rdtscl(t2); +- local_irq_restore(flags); ++ local_irq_restore_nort(flags); + udelay(i * 10); + if (t2 - t1 < tx) tx = t2 - t1; + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0122-rcu-new-4.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0122-rcu-new-4.patch @@ -0,0 +1,677 @@ +From paulmck@linux.vnet.ibm.com Thu Sep 27 00:09:37 2007 +Date: Mon, 10 Sep 2007 11:35:25 -0700 +From: Paul E. McKenney +To: linux-kernel@vger.kernel.org +Cc: linux-rt-users@vger.kernel.org, mingo@elte.hu, akpm@linux-foundation.org, + dipankar@in.ibm.com, josht@linux.vnet.ibm.com, tytso@us.ibm.com, + dvhltc@us.ibm.com, tglx@linutronix.de, a.p.zijlstra@chello.nl, + bunk@kernel.org, ego@in.ibm.com, oleg@tv-sign.ru, srostedt@redhat.com +Subject: [PATCH RFC 4/9] RCU: synchronize_sched() workaround for CPU hotplug + +Work in progress, not for inclusion. + +The combination of CPU hotplug and PREEMPT_RCU has resulted in deadlocks +due to the migration-based implementation of synchronize_sched() in -rt. +This experimental patch maps synchronize_sched() back onto Classic RCU, +eliminating the migration, thus hopefully also eliminating the deadlocks. +It is not clear that this is a good long-term approach, but it will at +least permit people doing CPU hotplug in -rt kernels additional wiggle +room in their design and implementation. + +The basic approach is to cause the -rt kernel to incorporate rcuclassic.c +as well as rcupreempt.c, but to #ifdef out the conflicting portions of +rcuclassic.c so that only the code needed to implement synchronize_sched() +remains in a PREEMPT_RT build. Invocations of grace-period detection from +the scheduling-clock interrupt go to rcuclassic.c, which then invokes +the corresponding functions in rcupreempt.c (with _rt suffix added to +keep the linker happy). Also applies the RCU_SOFTIRQ to classic RCU. +The bulk of this patch just moves code around, but likely increases +scheduling-clock latency. + +If this patch does turn out to be the right approach, the #ifdefs in +kernel/rcuclassic.c might be dealt with. ;-) At current writing, Gautham +Shenoy's most recent CPU-hotplug fixes seem likely to obsolete this patch +(which would be a very good thing indeed!). If this really pans out, +this portion of the patch will vanish during the forward-porting process. + +Signed-off-by: Steven Rostedt (for RCU_SOFTIRQ) +Signed-off-by: Paul E. McKenney +--- + + include/linux/rcuclassic.h | 79 +++++-------------------------------- + include/linux/rcupdate.h | 30 ++++++++++++-- + include/linux/rcupreempt.h | 27 ++++++------ + kernel/Makefile | 2 + kernel/rcuclassic.c | 95 ++++++++++++++++++++++++++++++++++++--------- + kernel/rcupdate.c | 22 ++++++++-- + kernel/rcupreempt.c | 50 +++++------------------ + 7 files changed, 158 insertions(+), 147 deletions(-) + +Index: linux-2.6.24.7-rt27/include/linux/rcuclassic.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcuclassic.h 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcuclassic.h 2009-02-08 00:01:39.000000000 -0500 +@@ -42,80 +42,19 @@ + #include + #include + +- +-/* Global control variables for rcupdate callback mechanism. */ +-struct rcu_ctrlblk { +- long cur; /* Current batch number. */ +- long completed; /* Number of the last completed batch */ +- int next_pending; /* Is the next batch already waiting? */ +- +- int signaled; +- +- spinlock_t lock ____cacheline_internodealigned_in_smp; +- cpumask_t cpumask; /* CPUs that need to switch in order */ +- /* for current batch to proceed. */ +-} ____cacheline_internodealigned_in_smp; +- +-/* Is batch a before batch b ? */ +-static inline int rcu_batch_before(long a, long b) +-{ +- return (a - b) < 0; +-} +- +-/* Is batch a after batch b ? */ +-static inline int rcu_batch_after(long a, long b) +-{ +- return (a - b) > 0; +-} ++DECLARE_PER_CPU(int, rcu_data_bh_passed_quiesc); + + /* +- * Per-CPU data for Read-Copy UPdate. +- * nxtlist - new callbacks are added here +- * curlist - current batch for which quiescent cycle started if any +- */ +-struct rcu_data { +- /* 1) quiescent state handling : */ +- long quiescbatch; /* Batch # for grace period */ +- int passed_quiesc; /* User-mode/idle loop etc. */ +- int qs_pending; /* core waits for quiesc state */ +- +- /* 2) batch handling */ +- long batch; /* Batch # for current RCU batch */ +- struct rcu_head *nxtlist; +- struct rcu_head **nxttail; +- long qlen; /* # of queued callbacks */ +- struct rcu_head *curlist; +- struct rcu_head **curtail; +- struct rcu_head *donelist; +- struct rcu_head **donetail; +- long blimit; /* Upper limit on a processed batch */ +- int cpu; +- struct rcu_head barrier; +-}; +- +-DECLARE_PER_CPU(struct rcu_data, rcu_data); +-DECLARE_PER_CPU(struct rcu_data, rcu_bh_data); +- +-/* +- * Increment the quiescent state counter. ++ * Increment the bottom-half quiescent state counter. + * The counter is a bit degenerated: We do not need to know + * how many quiescent states passed, just if there was at least + * one since the start of the grace period. Thus just a flag. + */ +-static inline void rcu_qsctr_inc(int cpu) +-{ +- struct rcu_data *rdp = &per_cpu(rcu_data, cpu); +- rdp->passed_quiesc = 1; +-} + static inline void rcu_bh_qsctr_inc(int cpu) + { +- struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu); +- rdp->passed_quiesc = 1; ++ per_cpu(rcu_data_bh_passed_quiesc, cpu) = 1; + } + +-extern int rcu_pending(int cpu); +-extern int rcu_needs_cpu(int cpu); +- + #define __rcu_read_lock() \ + do { \ + preempt_disable(); \ +@@ -139,9 +78,15 @@ extern int rcu_needs_cpu(int cpu); + + #define __synchronize_sched() synchronize_rcu() + +-extern void __rcu_init(void); +-extern void rcu_check_callbacks(int cpu, int user); +-extern void rcu_restart_cpu(int cpu); ++#define rcu_advance_callbacks_rt(cpu, user) do { } while (0) ++#define rcu_check_callbacks_rt(cpu, user) do { } while (0) ++#define rcu_init_rt() do { } while (0) ++#define rcu_needs_cpu_rt(cpu) 0 ++#define rcu_pending_rt(cpu) 0 ++#define rcu_process_callbacks_rt(unused) do { } while (0) ++ ++extern void FASTCALL(call_rcu_classic(struct rcu_head *head, ++ void (*func)(struct rcu_head *head))); + + #endif /* __KERNEL__ */ + #endif /* __LINUX_RCUCLASSIC_H */ +Index: linux-2.6.24.7-rt27/include/linux/rcupdate.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupdate.h 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupdate.h 2009-02-08 00:01:39.000000000 -0500 +@@ -220,8 +220,11 @@ extern struct lockdep_map rcu_lock_map; + * delimited by rcu_read_lock() and rcu_read_unlock(), + * and may be nested. + */ +-extern void FASTCALL(call_rcu(struct rcu_head *head, +- void (*func)(struct rcu_head *head))); ++#ifdef CONFIG_CLASSIC_RCU ++#define call_rcu(head, func) call_rcu_classic(head, func) ++#else /* #ifdef CONFIG_CLASSIC_RCU */ ++#define call_rcu(head, func) call_rcu_preempt(head, func) ++#endif /* #else #ifdef CONFIG_CLASSIC_RCU */ + + /** + * call_rcu_bh - Queue an RCU for invocation after a quicker grace period. +@@ -249,9 +252,28 @@ extern long rcu_batches_completed(void); + extern long rcu_batches_completed_bh(void); + + /* Internal to kernel */ +-extern void rcu_init(void); + extern void rcu_check_callbacks(int cpu, int user); +-extern int rcu_needs_cpu(int cpu); ++extern long rcu_batches_completed(void); ++extern long rcu_batches_completed_bh(void); ++extern void rcu_check_callbacks(int cpu, int user); ++extern void rcu_init(void); ++extern int rcu_needs_cpu(int cpu); ++extern int rcu_pending(int cpu); ++struct softirq_action; ++extern void rcu_restart_cpu(int cpu); ++ ++DECLARE_PER_CPU(int, rcu_data_passed_quiesc); ++ ++/* ++ * Increment the quiescent state counter. ++ * The counter is a bit degenerated: We do not need to know ++ * how many quiescent states passed, just if there was at least ++ * one since the start of the grace period. Thus just a flag. ++ */ ++static inline void rcu_qsctr_inc(int cpu) ++{ ++ per_cpu(rcu_data_passed_quiesc, cpu) = 1; ++} + + #endif /* __KERNEL__ */ + #endif /* __LINUX_RCUPDATE_H */ +Index: linux-2.6.24.7-rt27/include/linux/rcupreempt.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/rcupreempt.h 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/rcupreempt.h 2009-02-08 00:01:39.000000000 -0500 +@@ -42,25 +42,26 @@ + #include + #include + +-#define rcu_qsctr_inc(cpu) +-#define rcu_bh_qsctr_inc(cpu) + #define call_rcu_bh(head, rcu) call_rcu(head, rcu) +- +-extern void __rcu_read_lock(void); +-extern void __rcu_read_unlock(void); +-extern int rcu_pending(int cpu); +-extern int rcu_needs_cpu(int cpu); +- ++#define rcu_bh_qsctr_inc(cpu) do { } while (0) + #define __rcu_read_lock_bh() { rcu_read_lock(); local_bh_disable(); } + #define __rcu_read_unlock_bh() { local_bh_enable(); rcu_read_unlock(); } +- + #define __rcu_read_lock_nesting() (current->rcu_read_lock_nesting) + ++extern void FASTCALL(call_rcu_classic(struct rcu_head *head, ++ void (*func)(struct rcu_head *head))); ++extern void FASTCALL(call_rcu_preempt(struct rcu_head *head, ++ void (*func)(struct rcu_head *head))); ++extern void __rcu_read_lock(void); ++extern void __rcu_read_unlock(void); + extern void __synchronize_sched(void); +- +-extern void __rcu_init(void); +-extern void rcu_check_callbacks(int cpu, int user); +-extern void rcu_restart_cpu(int cpu); ++extern void rcu_advance_callbacks_rt(int cpu, int user); ++extern void rcu_check_callbacks_rt(int cpu, int user); ++extern void rcu_init_rt(void); ++extern int rcu_needs_cpu_rt(int cpu); ++extern int rcu_pending_rt(int cpu); ++struct softirq_action; ++extern void rcu_process_callbacks_rt(struct softirq_action *unused); + + #ifdef CONFIG_RCU_TRACE + struct rcupreempt_trace; +Index: linux-2.6.24.7-rt27/kernel/Makefile +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/Makefile 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/Makefile 2009-02-08 00:01:39.000000000 -0500 +@@ -65,7 +65,7 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ + obj-$(CONFIG_SECCOMP) += seccomp.o + obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o + obj-$(CONFIG_CLASSIC_RCU) += rcuclassic.o +-obj-$(CONFIG_PREEMPT_RCU) += rcupreempt.o ++obj-$(CONFIG_PREEMPT_RCU) += rcuclassic.o rcupreempt.o + ifeq ($(CONFIG_PREEMPT_RCU),y) + obj-$(CONFIG_RCU_TRACE) += rcupreempt_trace.o + endif +Index: linux-2.6.24.7-rt27/kernel/rcuclassic.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcuclassic.c 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcuclassic.c 2009-02-08 00:01:39.000000000 -0500 +@@ -45,10 +45,53 @@ + #include + #include + #include +-/* #include @@@ */ + #include + #include + ++ ++/* Global control variables for rcupdate callback mechanism. */ ++struct rcu_ctrlblk { ++ long cur; /* Current batch number. */ ++ long completed; /* Number of the last completed batch */ ++ int next_pending; /* Is the next batch already waiting? */ ++ ++ int signaled; ++ ++ spinlock_t lock ____cacheline_internodealigned_in_smp; ++ cpumask_t cpumask; /* CPUs that need to switch in order */ ++ /* for current batch to proceed. */ ++} ____cacheline_internodealigned_in_smp; ++ ++/* Is batch a before batch b ? */ ++static inline int rcu_batch_before(long a, long b) ++{ ++ return (a - b) < 0; ++} ++ ++/* ++ * Per-CPU data for Read-Copy UPdate. ++ * nxtlist - new callbacks are added here ++ * curlist - current batch for which quiescent cycle started if any ++ */ ++struct rcu_data { ++ /* 1) quiescent state handling : */ ++ long quiescbatch; /* Batch # for grace period */ ++ int *passed_quiesc; /* User-mode/idle loop etc. */ ++ int qs_pending; /* core waits for quiesc state */ ++ ++ /* 2) batch handling */ ++ long batch; /* Batch # for current RCU batch */ ++ struct rcu_head *nxtlist; ++ struct rcu_head **nxttail; ++ long qlen; /* # of queued callbacks */ ++ struct rcu_head *curlist; ++ struct rcu_head **curtail; ++ struct rcu_head *donelist; ++ struct rcu_head **donetail; ++ long blimit; /* Upper limit on a processed batch */ ++ int cpu; ++}; ++ + /* Definition for rcupdate control block. */ + static struct rcu_ctrlblk rcu_ctrlblk = { + .cur = -300, +@@ -63,11 +106,11 @@ static struct rcu_ctrlblk rcu_bh_ctrlblk + .cpumask = CPU_MASK_NONE, + }; + +-DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L }; +-DEFINE_PER_CPU(struct rcu_data, rcu_bh_data) = { 0L }; ++static DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L }; ++static DEFINE_PER_CPU(struct rcu_data, rcu_bh_data) = { 0L }; ++DEFINE_PER_CPU(int, rcu_data_bh_passed_quiesc); + + /* Fake initialization required by compiler */ +-static DEFINE_PER_CPU(struct tasklet_struct, rcu_tasklet) = {NULL}; + static int blimit = 10; + static int qhimark = 10000; + static int qlowmark = 100; +@@ -110,8 +153,8 @@ static inline void force_quiescent_state + * sections are delimited by rcu_read_lock() and rcu_read_unlock(), + * and may be nested. + */ +-void fastcall call_rcu(struct rcu_head *head, +- void (*func)(struct rcu_head *rcu)) ++void fastcall call_rcu_classic(struct rcu_head *head, ++ void (*func)(struct rcu_head *rcu)) + { + unsigned long flags; + struct rcu_data *rdp; +@@ -128,7 +171,9 @@ void fastcall call_rcu(struct rcu_head * + } + local_irq_restore(flags); + } +-EXPORT_SYMBOL_GPL(call_rcu); ++EXPORT_SYMBOL_GPL(call_rcu_classic); ++ ++#ifdef CONFIG_CLASSIC_RCU + + /** + * call_rcu_bh - Queue an RCU for invocation after a quicker grace period. +@@ -166,7 +211,9 @@ void fastcall call_rcu_bh(struct rcu_hea + + local_irq_restore(flags); + } ++#ifdef CONFIG_CLASSIC_RCU + EXPORT_SYMBOL_GPL(call_rcu_bh); ++#endif /* #ifdef CONFIG_CLASSIC_RCU */ + + /* + * Return the number of RCU batches processed thus far. Useful +@@ -176,7 +223,9 @@ long rcu_batches_completed(void) + { + return rcu_ctrlblk.completed; + } ++#ifdef CONFIG_CLASSIC_RCU + EXPORT_SYMBOL_GPL(rcu_batches_completed); ++#endif /* #ifdef CONFIG_CLASSIC_RCU */ + + /* + * Return the number of RCU batches processed thus far. Useful +@@ -186,7 +235,11 @@ long rcu_batches_completed_bh(void) + { + return rcu_bh_ctrlblk.completed; + } ++#ifdef CONFIG_CLASSIC_RCU + EXPORT_SYMBOL_GPL(rcu_batches_completed_bh); ++#endif /* #ifdef CONFIG_CLASSIC_RCU */ ++ ++#endif /* #ifdef CONFIG_CLASSIC_RCU */ + + /* + * Invoke the completed RCU callbacks. They are expected to be in +@@ -217,7 +270,7 @@ static void rcu_do_batch(struct rcu_data + if (!rdp->donelist) + rdp->donetail = &rdp->donelist; + else +- tasklet_schedule(&per_cpu(rcu_tasklet, rdp->cpu)); ++ raise_softirq(RCU_SOFTIRQ); + } + + /* +@@ -294,7 +347,7 @@ static void rcu_check_quiescent_state(st + if (rdp->quiescbatch != rcp->cur) { + /* start new grace period: */ + rdp->qs_pending = 1; +- rdp->passed_quiesc = 0; ++ *rdp->passed_quiesc = 0; + rdp->quiescbatch = rcp->cur; + return; + } +@@ -310,7 +363,7 @@ static void rcu_check_quiescent_state(st + * Was there a quiescent state since the beginning of the grace + * period? If no, then exit and wait for the next call. + */ +- if (!rdp->passed_quiesc) ++ if (!*rdp->passed_quiesc) + return; + rdp->qs_pending = 0; + +@@ -369,7 +422,6 @@ static void rcu_offline_cpu(int cpu) + &per_cpu(rcu_bh_data, cpu)); + put_cpu_var(rcu_data); + put_cpu_var(rcu_bh_data); +- tasklet_kill_immediate(&per_cpu(rcu_tasklet, cpu), cpu); + } + + #else +@@ -381,7 +433,7 @@ static void rcu_offline_cpu(int cpu) + #endif + + /* +- * This does the RCU processing work from tasklet context. ++ * This does the RCU processing work from softirq context. + */ + static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp, + struct rcu_data *rdp) +@@ -426,10 +478,11 @@ static void __rcu_process_callbacks(stru + rcu_do_batch(rdp); + } + +-static void rcu_process_callbacks(unsigned long unused) ++static void rcu_process_callbacks(struct softirq_action *unused) + { + __rcu_process_callbacks(&rcu_ctrlblk, &__get_cpu_var(rcu_data)); + __rcu_process_callbacks(&rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data)); ++ rcu_process_callbacks_rt(unused); + } + + static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp) +@@ -464,7 +517,8 @@ static int __rcu_pending(struct rcu_ctrl + int rcu_pending(int cpu) + { + return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) || +- __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu)); ++ __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu)) || ++ rcu_pending_rt(cpu); + } + + /* +@@ -478,7 +532,8 @@ int rcu_needs_cpu(int cpu) + struct rcu_data *rdp = &per_cpu(rcu_data, cpu); + struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu); + +- return (!!rdp->curlist || !!rdp_bh->curlist || rcu_pending(cpu)); ++ return (!!rdp->curlist || !!rdp_bh->curlist || rcu_pending(cpu) || ++ rcu_needs_cpu_rt(cpu)); + } + + void rcu_check_callbacks(int cpu, int user) +@@ -490,7 +545,8 @@ void rcu_check_callbacks(int cpu, int us + rcu_bh_qsctr_inc(cpu); + } else if (!in_softirq()) + rcu_bh_qsctr_inc(cpu); +- tasklet_schedule(&per_cpu(rcu_tasklet, cpu)); ++ rcu_check_callbacks_rt(cpu, user); ++ raise_softirq(RCU_SOFTIRQ); + } + + static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp, +@@ -512,8 +568,9 @@ static void __cpuinit rcu_online_cpu(int + struct rcu_data *bh_rdp = &per_cpu(rcu_bh_data, cpu); + + rcu_init_percpu_data(cpu, &rcu_ctrlblk, rdp); ++ rdp->passed_quiesc = &per_cpu(rcu_data_passed_quiesc, cpu); + rcu_init_percpu_data(cpu, &rcu_bh_ctrlblk, bh_rdp); +- tasklet_init(&per_cpu(rcu_tasklet, cpu), rcu_process_callbacks, 0UL); ++ bh_rdp->passed_quiesc = &per_cpu(rcu_data_bh_passed_quiesc, cpu); + } + + static int __cpuinit rcu_cpu_notify(struct notifier_block *self, +@@ -545,12 +602,14 @@ static struct notifier_block __cpuinitda + * Note that rcu_qsctr and friends are implicitly + * initialized due to the choice of ``0'' for RCU_CTR_INVALID. + */ +-void __init __rcu_init(void) ++void __init rcu_init(void) + { + rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, + (void *)(long)smp_processor_id()); + /* Register notifier for non-boot CPUs */ + register_cpu_notifier(&rcu_nb); ++ rcu_init_rt(); ++ open_softirq(RCU_SOFTIRQ, rcu_process_callbacks, NULL); + } + + module_param(blimit, int, 0); +Index: linux-2.6.24.7-rt27/kernel/rcupdate.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupdate.c 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupdate.c 2009-02-08 00:01:39.000000000 -0500 +@@ -59,6 +59,7 @@ struct rcu_synchronize { + struct completion completion; + }; + ++DEFINE_PER_CPU(int, rcu_data_passed_quiesc); + static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL}; + static atomic_t rcu_barrier_cpu_count; + static DEFINE_MUTEX(rcu_barrier_mutex); +@@ -95,6 +96,22 @@ void synchronize_rcu(void) + } + EXPORT_SYMBOL_GPL(synchronize_rcu); + ++#ifdef CONFIG_PREEMPT_RCU ++ ++/* ++ * Map synchronize_sched() to the classic RCU implementation. ++ */ ++void __synchronize_sched(void) ++{ ++ struct rcu_synchronize rcu; ++ ++ init_completion(&rcu.completion); ++ call_rcu_classic(&rcu.head, wakeme_after_rcu); ++ wait_for_completion(&rcu.completion); ++} ++EXPORT_SYMBOL_GPL(__synchronize_sched); ++#endif /* #ifdef CONFIG_PREEMPT_RCU */ ++ + static void rcu_barrier_callback(struct rcu_head *notused) + { + if (atomic_dec_and_test(&rcu_barrier_cpu_count)) +@@ -138,8 +155,3 @@ void rcu_barrier(void) + mutex_unlock(&rcu_barrier_mutex); + } + EXPORT_SYMBOL_GPL(rcu_barrier); +- +-void __init rcu_init(void) +-{ +- __rcu_init(); +-} +Index: linux-2.6.24.7-rt27/kernel/rcupreempt.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rcupreempt.c 2009-02-08 00:01:39.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rcupreempt.c 2009-02-08 00:01:39.000000000 -0500 +@@ -61,7 +61,6 @@ struct rcu_data { + spinlock_t lock; /* Protect rcu_data fields. */ + long completed; /* Number of last completed batch. */ + int waitlistcount; +- struct tasklet_struct rcu_tasklet; + struct rcu_head *nextlist; + struct rcu_head **nexttail; + struct rcu_head *waitlist[GP_STAGES]; +@@ -550,7 +549,7 @@ static void rcu_check_mb(int cpu) + } + } + +-void rcu_check_callbacks(int cpu, int user) ++void rcu_check_callbacks_rt(int cpu, int user) + { + unsigned long oldirq; + struct rcu_data *rdp = RCU_DATA_CPU(cpu); +@@ -561,19 +560,14 @@ void rcu_check_callbacks(int cpu, int us + spin_lock_irqsave(&rdp->lock, oldirq); + RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp); + __rcu_advance_callbacks(rdp); +- if (rdp->donelist == NULL) { +- spin_unlock_irqrestore(&rdp->lock, oldirq); +- } else { +- spin_unlock_irqrestore(&rdp->lock, oldirq); +- raise_softirq(RCU_SOFTIRQ); +- } ++ spin_unlock_irqrestore(&rdp->lock, oldirq); + } + + /* + * Needed by dynticks, to make sure all RCU processing has finished +- * when we go idle: ++ * when we go idle. (Currently unused, needed?) + */ +-void rcu_advance_callbacks(int cpu, int user) ++void rcu_advance_callbacks_rt(int cpu, int user) + { + unsigned long oldirq; + struct rcu_data *rdp = RCU_DATA_CPU(cpu); +@@ -589,7 +583,7 @@ void rcu_advance_callbacks(int cpu, int + spin_unlock_irqrestore(&rdp->lock, oldirq); + } + +-static void rcu_process_callbacks(struct softirq_action *unused) ++void rcu_process_callbacks_rt(struct softirq_action *unused) + { + unsigned long flags; + struct rcu_head *next, *list; +@@ -613,8 +607,8 @@ static void rcu_process_callbacks(struct + } + } + +-void fastcall call_rcu(struct rcu_head *head, +- void (*func)(struct rcu_head *rcu)) ++void fastcall call_rcu_preempt(struct rcu_head *head, ++ void (*func)(struct rcu_head *rcu)) + { + unsigned long oldirq; + struct rcu_data *rdp; +@@ -631,28 +625,7 @@ void fastcall call_rcu(struct rcu_head * + spin_unlock(&rdp->lock); + local_irq_restore(oldirq); + } +-EXPORT_SYMBOL_GPL(call_rcu); +- +-/* +- * Wait until all currently running preempt_disable() code segments +- * (including hardware-irq-disable segments) complete. Note that +- * in -rt this does -not- necessarily result in all currently executing +- * interrupt -handlers- having completed. +- */ +-void __synchronize_sched(void) +-{ +- cpumask_t oldmask; +- int cpu; +- +- if (sched_getaffinity(0, &oldmask) < 0) +- oldmask = cpu_possible_map; +- for_each_online_cpu(cpu) { +- sched_setaffinity(0, cpumask_of_cpu(cpu)); +- schedule(); +- } +- sched_setaffinity(0, oldmask); +-} +-EXPORT_SYMBOL_GPL(__synchronize_sched); ++EXPORT_SYMBOL_GPL(call_rcu_preempt); + + /* + * Check to see if any future RCU-related work will need to be done +@@ -663,7 +636,7 @@ EXPORT_SYMBOL_GPL(__synchronize_sched); + * This function is part of the RCU implementation; it is -not- + * an exported member of the RCU API. + */ +-int rcu_needs_cpu(int cpu) ++int rcu_needs_cpu_rt(int cpu) + { + struct rcu_data *rdp = RCU_DATA_CPU(cpu); + +@@ -672,7 +645,7 @@ int rcu_needs_cpu(int cpu) + rdp->nextlist != NULL); + } + +-int rcu_pending(int cpu) ++int rcu_pending_rt(int cpu) + { + struct rcu_data *rdp = RCU_DATA_CPU(cpu); + +@@ -699,7 +672,7 @@ int rcu_pending(int cpu) + return 0; + } + +-void __init __rcu_init(void) ++void __init rcu_init_rt(void) + { + int cpu; + int i; +@@ -719,7 +692,6 @@ void __init __rcu_init(void) + rdp->donelist = NULL; + rdp->donetail = &rdp->donelist; + } +- open_softirq(RCU_SOFTIRQ, rcu_process_callbacks, NULL); + } + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0494-ftrace-wakeup-rawspinlock.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0494-ftrace-wakeup-rawspinlock.patch @@ -0,0 +1,106 @@ +From: Steven Rostedt +Subject: ftrace: user raw spin lock for wakeup function trace + +Lockdep gets hung up by function traces that call spinlocks. Change +wakeup spin lock used in the wake up function tracing to raw. + +Signed-off-by: Steven Rostedt +--- + kernel/trace/trace_sched_wakeup.c | 27 ++++++++++++++++----------- + 1 file changed, 16 insertions(+), 11 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/trace/trace_sched_wakeup.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace_sched_wakeup.c 2009-02-08 00:02:36.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace_sched_wakeup.c 2009-02-08 00:04:46.000000000 -0500 +@@ -26,7 +26,8 @@ static struct task_struct *wakeup_task; + static int wakeup_cpu; + static unsigned wakeup_prio = -1; + +-static DEFINE_RAW_SPINLOCK(wakeup_lock); ++static __raw_spinlock_t wakeup_lock = ++ (__raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; + + static void __wakeup_reset(struct trace_array *tr); + +@@ -56,7 +57,8 @@ wakeup_tracer_call(unsigned long ip, uns + if (unlikely(disabled != 1)) + goto out; + +- spin_lock_irqsave(&wakeup_lock, flags); ++ raw_local_irq_save(flags); ++ __raw_spin_lock(&wakeup_lock); + + if (unlikely(!wakeup_task)) + goto unlock; +@@ -71,7 +73,8 @@ wakeup_tracer_call(unsigned long ip, uns + trace_function(tr, data, ip, parent_ip, flags); + + unlock: +- spin_unlock_irqrestore(&wakeup_lock, flags); ++ __raw_spin_unlock(&wakeup_lock); ++ raw_local_irq_restore(flags); + + out: + atomic_dec(&data->disabled); +@@ -145,7 +148,8 @@ wakeup_sched_switch(void *private, void + if (likely(disabled != 1)) + goto out; + +- spin_lock_irqsave(&wakeup_lock, flags); ++ local_irq_save(flags); ++ __raw_spin_lock(&wakeup_lock); + + /* We could race with grabbing wakeup_lock */ + if (unlikely(!tracer_enabled || next != wakeup_task)) +@@ -174,7 +178,8 @@ wakeup_sched_switch(void *private, void + + out_unlock: + __wakeup_reset(tr); +- spin_unlock_irqrestore(&wakeup_lock, flags); ++ __raw_spin_unlock(&wakeup_lock); ++ local_irq_restore(flags); + out: + atomic_dec(&tr->data[cpu]->disabled); + } +@@ -209,8 +214,6 @@ static void __wakeup_reset(struct trace_ + struct trace_array_cpu *data; + int cpu; + +- assert_spin_locked(&wakeup_lock); +- + for_each_possible_cpu(cpu) { + data = tr->data[cpu]; + tracing_reset(data); +@@ -229,9 +232,11 @@ static void wakeup_reset(struct trace_ar + { + unsigned long flags; + +- spin_lock_irqsave(&wakeup_lock, flags); ++ local_irq_save(flags); ++ __raw_spin_lock(&wakeup_lock); + __wakeup_reset(tr); +- spin_unlock_irqrestore(&wakeup_lock, flags); ++ __raw_spin_unlock(&wakeup_lock); ++ local_irq_restore(flags); + } + + static void +@@ -252,7 +257,7 @@ wakeup_check_start(struct trace_array *t + goto out; + + /* interrupts should be off from try_to_wake_up */ +- spin_lock(&wakeup_lock); ++ __raw_spin_lock(&wakeup_lock); + + /* check for races. */ + if (!tracer_enabled || p->prio >= wakeup_prio) +@@ -274,7 +279,7 @@ wakeup_check_start(struct trace_array *t + CALLER_ADDR1, CALLER_ADDR2, flags); + + out_locked: +- spin_unlock(&wakeup_lock); ++ __raw_spin_unlock(&wakeup_lock); + out: + atomic_dec(&tr->data[cpu]->disabled); + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0206-preempt-realtime-arm-rawlock-in-mmu_context-h.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0206-preempt-realtime-arm-rawlock-in-mmu_context-h.patch @@ -0,0 +1,44 @@ +From khilman@mvista.com Fri Aug 31 05:09:03 2007 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.1.7-deb (2006-10-05) on debian +X-Spam-Level: +X-Spam-Status: No, score=0.0 required=5.0 tests=AWL autolearn=unavailable + version=3.1.7-deb +Received: from paris.hilman.org (deeprooted.net [216.254.16.51]) by + mail.tglx.de (Postfix) with ESMTP id 1F21965C003 for ; + Fri, 31 Aug 2007 05:09:03 +0200 (CEST) +Received: by paris.hilman.org (Postfix, from userid 1000) id C5837E4C5FE; + Thu, 30 Aug 2007 20:09:02 -0700 (PDT) +Message-Id: <20070831030841.799694742@mvista.com> +User-Agent: quilt/0.45-1 +Date: Thu, 30 Aug 2007 20:08:41 -0700 +From: Kevin Hilman +To: Ingo Molnar , Thomas Gleixner +Cc: LKML , RT-Users +Subject: [PATCH 2.6.23-rc2-rt2] ARM: use raw lock in __new_context +X-Evolution-Source: imap://tglx%40linutronix.de@localhost:8993/ +Content-Transfer-Encoding: 8bit +Mime-Version: 1.0 + +The ARM CPU ASID lock should be raw as it's used by schedule() when +creating a new context. + +Signed-off-by: Kevin Hilman + +--- + arch/arm/mm/context.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/arm/mm/context.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mm/context.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mm/context.c 2009-02-08 00:02:20.000000000 -0500 +@@ -14,7 +14,7 @@ + #include + #include + +-static DEFINE_SPINLOCK(cpu_asid_lock); ++static DEFINE_RAW_SPINLOCK(cpu_asid_lock); + unsigned int cpu_last_asid = ASID_FIRST_VERSION; + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0542-futex-trivial-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0542-futex-trivial-fix.patch @@ -0,0 +1,50 @@ +From ankita@in.ibm.com Wed Sep 10 02:10:05 2008 +Date: Wed, 10 Sep 2008 11:36:24 +0530 +From: Ankita Garg +To: Steven Rostedt +Cc: LKML , RT , Ingo Molnar , Thomas Gleixner +Subject: Re: 2.6.24.7-rt18 + +Hi Steven, + +On Tue, Sep 09, 2008 at 11:44:42PM -0400, Steven Rostedt wrote: +> We are pleased to announce the 2.6.24.7-rt18 tree, which can be +> downloaded from the location: +> +> http://rt.et.redhat.com/download/ +> +> Information on the RT patch can be found at: +> +> http://rt.wiki.kernel.org/index.php/Main_Page +> +> Changes since 2.6.24.7-rt17 +> +> - seqlock serialize writes (Gregory Haskins) +> +> - Fix above patch that broke non PREEMPT_RT (Steven Rostedt) +> +> - Add sysctl to warn on RT task using non PI futex (Steven Rostedt) +> + +A trivial patch to remove the hard coded value of MAX_RT_PRIO in the +above patch. + +Signed-off-by: Ankita Garg + +--- + kernel/futex.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/kernel/futex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/futex.c 2009-02-08 00:05:08.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/futex.c 2009-02-08 00:05:09.000000000 -0500 +@@ -1250,7 +1250,7 @@ static int futex_wait(u32 __user *uaddr, + "RT task %s:%d with priority %d" + " using non PI futex\n", + current->comm, current->pid, +- 100 - current->prio); ++ MAX_RT_PRIO - current->prio); + } + } + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0570-tglx-05-rtmutex-remove-uber-optimization.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0570-tglx-05-rtmutex-remove-uber-optimization.patch @@ -0,0 +1,84 @@ +From tglx@linutronix.de Fri Dec 19 16:40:02 2008 +Date: Fri, 19 Dec 2008 21:23:02 -0000 +From: Thomas Gleixner +To: LKML +Cc: Ingo Molnar , Steven Rostedt , Peter Zijlstra , Clark Williams , Gregory Haskins , Linux-rt +Subject: [patch 5/7] rtmutex: remove uber optimization + +The adaptive spin patches introduced an overdesigned optimization for +the adaptive path. This avoidance of those code pathes is not worth +the extra conditionals and furthermore it is inconsistent in itself. + +Remove it and use the same mechanism as the other lock pathes. That +way we have a consistent state manipulation scheme and less extra +cases. + +Signed-off-by: Thomas Gleixner +--- + kernel/rtmutex.c | 18 +++--------------- + 1 file changed, 3 insertions(+), 15 deletions(-) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex.c 2009-02-08 00:05:22.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex.c 2009-02-08 00:05:22.000000000 -0500 +@@ -839,7 +839,6 @@ rt_spin_lock_slowlock(struct rt_mutex *l + struct rt_mutex_waiter waiter; + unsigned long saved_state, flags; + struct task_struct *orig_owner; +- int missed = 0; + + debug_rt_mutex_init_waiter(&waiter); + waiter.task = NULL; +@@ -861,20 +860,15 @@ rt_spin_lock_slowlock(struct rt_mutex *l + * about original state TASK_INTERRUPTIBLE as well, as we + * could miss a wakeup_interruptible() + */ +- saved_state = current->state; ++ saved_state = rt_set_current_blocked_state(current->state); + + for (;;) { + unsigned long saved_flags; + int saved_lock_depth = current->lock_depth; + + /* Try to acquire the lock */ +- if (do_try_to_take_rt_mutex(lock, STEAL_LATERAL)) { +- /* If we never blocked break out now */ +- if (!missed) +- goto unlock; ++ if (do_try_to_take_rt_mutex(lock, STEAL_LATERAL)) + break; +- } +- missed = 1; + + /* + * waiter.task is NULL the first time we come here and +@@ -904,12 +898,6 @@ rt_spin_lock_slowlock(struct rt_mutex *l + if (adaptive_wait(&waiter, orig_owner)) { + put_task_struct(orig_owner); + +- saved_state = rt_set_current_blocked_state(saved_state); +- /* +- * The xchg() in update_current() is an implicit +- * barrier which we rely upon to ensure current->state +- * is visible before we test waiter.task. +- */ + if (waiter.task) + schedule_rt_mutex(lock); + } else +@@ -918,6 +906,7 @@ rt_spin_lock_slowlock(struct rt_mutex *l + spin_lock_irqsave(&lock->wait_lock, flags); + current->flags |= saved_flags; + current->lock_depth = saved_lock_depth; ++ saved_state = rt_set_current_blocked_state(saved_state); + } + + rt_restore_current_state(saved_state); +@@ -936,7 +925,6 @@ rt_spin_lock_slowlock(struct rt_mutex *l + */ + fixup_rt_mutex_waiters(lock); + +- unlock: + spin_unlock_irqrestore(&lock->wait_lock, flags); + + debug_rt_mutex_free_waiter(&waiter); --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0485-marker-upstream-example.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0485-marker-upstream-example.patch @@ -0,0 +1,74 @@ +From: Steven Rostedt +Subject: markers: update samples to markers upstream. + +Update the marker sample code to match upstream. + +Signed-off-by: Steven Rostedt +--- + samples/markers/probe-example.c | 24 +++++++++--------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +Index: linux-2.6.24.7-rt27/samples/markers/probe-example.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/samples/markers/probe-example.c 2009-02-07 23:59:38.000000000 -0500 ++++ linux-2.6.24.7-rt27/samples/markers/probe-example.c 2009-02-08 00:04:40.000000000 -0500 +@@ -20,31 +20,27 @@ struct probe_data { + marker_probe_func *probe_func; + }; + +-void probe_subsystem_event(const struct marker *mdata, void *private, +- const char *format, ...) ++void probe_subsystem_event(void *private, void *calldata, ++ const char *format, va_list *args) + { +- va_list ap; + /* Declare args */ + unsigned int value; + const char *mystr; + + /* Assign args */ +- va_start(ap, format); +- value = va_arg(ap, typeof(value)); +- mystr = va_arg(ap, typeof(mystr)); ++ value = va_arg(*args, typeof(value)); ++ mystr = va_arg(*args, typeof(mystr)); + + /* Call printk */ + printk(KERN_DEBUG "Value %u, string %s\n", value, mystr); + + /* or count, check rights, serialize data in a buffer */ +- +- va_end(ap); + } + + atomic_t eventb_count = ATOMIC_INIT(0); + +-void probe_subsystem_eventb(const struct marker *mdata, void *private, +- const char *format, ...) ++void probe_subsystem_eventb(void *private, void *calldata, ++ const char *format, va_list *args) + { + /* Increment counter */ + atomic_inc(&eventb_count); +@@ -72,10 +68,6 @@ static int __init probe_init(void) + if (result) + printk(KERN_INFO "Unable to register probe %s\n", + probe_array[i].name); +- result = marker_arm(probe_array[i].name); +- if (result) +- printk(KERN_INFO "Unable to arm probe %s\n", +- probe_array[i].name); + } + return 0; + } +@@ -85,7 +77,9 @@ static void __exit probe_fini(void) + int i; + + for (i = 0; i < ARRAY_SIZE(probe_array); i++) +- marker_probe_unregister(probe_array[i].name); ++ marker_probe_unregister(probe_array[i].name, ++ probe_array[i].probe_func, &probe_array[i]); ++ + printk(KERN_INFO "Number of event b : %u\n", + atomic_read(&eventb_count)); + } --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0294-lock_page_ref.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0294-lock_page_ref.patch @@ -0,0 +1,441 @@ +Subject: mm: lock_page_ref + +Change the PG_nonewref operations into locking primitives and place them +so that they provide page level serialization with regard to the page_tree +operations. (basically replace the tree_lock with a per page lock). + +The normal page lock has sufficiently different (and overlapping) scope and +protection rules that this second lock is needed. + +Signed-off-by: Peter Zijlstra +--- + fs/buffer.c | 6 ++++-- + include/linux/page-flags.h | 21 --------------------- + include/linux/pagemap.h | 45 +++++++++++++++++++++++++++++++++++++++++++-- + mm/filemap.c | 14 ++++++++------ + mm/migrate.c | 25 +++++++++++++------------ + mm/page-writeback.c | 18 ++++++++++++------ + mm/swap_state.c | 14 ++++++++------ + mm/swapfile.c | 6 ++++-- + mm/truncate.c | 9 ++++++--- + mm/vmscan.c | 14 +++++++------- + 10 files changed, 105 insertions(+), 67 deletions(-) + +Index: linux-2.6.24.7-rt27/fs/buffer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/fs/buffer.c 2009-02-08 00:03:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/fs/buffer.c 2009-02-08 00:03:08.000000000 -0500 +@@ -697,7 +697,8 @@ static int __set_page_dirty(struct page + if (TestSetPageDirty(page)) + return 0; + +- spin_lock_irq(&mapping->tree_lock); ++ lock_page_ref_irq(page); ++ spin_lock(&mapping->tree_lock); + if (page->mapping) { /* Race with truncate? */ + WARN_ON_ONCE(warn && !PageUptodate(page)); + +@@ -710,7 +711,8 @@ static int __set_page_dirty(struct page + radix_tree_tag_set(&mapping->page_tree, + page_index(page), PAGECACHE_TAG_DIRTY); + } +- spin_unlock_irq(&mapping->tree_lock); ++ spin_unlock(&mapping->tree_lock); ++ unlock_page_ref_irq(page); + __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); + + return 1; +Index: linux-2.6.24.7-rt27/include/linux/page-flags.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/page-flags.h 2009-02-08 00:03:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/page-flags.h 2009-02-08 00:03:08.000000000 -0500 +@@ -279,25 +279,4 @@ static inline void set_page_writeback(st + test_set_page_writeback(page); + } + +-static inline void set_page_nonewrefs(struct page *page) +-{ +- preempt_disable(); +- SetPageNoNewRefs(page); +- smp_wmb(); +-} +- +-static inline void __clear_page_nonewrefs(struct page *page) +-{ +- smp_wmb(); +- __ClearPageNoNewRefs(page); +- preempt_enable(); +-} +- +-static inline void clear_page_nonewrefs(struct page *page) +-{ +- smp_wmb(); +- ClearPageNoNewRefs(page); +- preempt_enable(); +-} +- + #endif /* PAGE_FLAGS_H */ +Index: linux-2.6.24.7-rt27/include/linux/pagemap.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/pagemap.h 2009-02-08 00:03:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/pagemap.h 2009-02-08 00:03:08.000000000 -0500 +@@ -14,6 +14,7 @@ + #include + #include + #include /* for in_interrupt() */ ++#include + + /* + * Bits in mapping->flags. The lower __GFP_BITS_SHIFT bits are the page +@@ -64,6 +65,47 @@ static inline void mapping_set_gfp_mask( + #define page_cache_release(page) put_page(page) + void release_pages(struct page **pages, int nr, int cold); + ++static inline void lock_page_ref(struct page *page) ++{ ++ bit_spin_lock(PG_nonewrefs, &page->flags); ++ smp_wmb(); ++} ++ ++static inline void unlock_page_ref(struct page *page) ++{ ++ bit_spin_unlock(PG_nonewrefs, &page->flags); ++} ++ ++static inline void wait_on_page_ref(struct page *page) ++{ ++ while (unlikely(test_bit(PG_nonewrefs, &page->flags))) ++ cpu_relax(); ++} ++ ++#define lock_page_ref_irq(page) \ ++ do { \ ++ local_irq_disable(); \ ++ lock_page_ref(page); \ ++ } while (0) ++ ++#define unlock_page_ref_irq(page) \ ++ do { \ ++ unlock_page_ref(page); \ ++ local_irq_enable(); \ ++ } while (0) ++ ++#define lock_page_ref_irqsave(page, flags) \ ++ do { \ ++ local_irq_save(flags); \ ++ lock_page_ref(page); \ ++ } while (0) ++ ++#define unlock_page_ref_irqrestore(page, flags) \ ++ do { \ ++ unlock_page_ref(page); \ ++ local_irq_restore(flags); \ ++ } while (0) ++ + /* + * speculatively take a reference to a page. + * If the page is free (_count == 0), then _count is untouched, and 0 +@@ -139,8 +181,7 @@ static inline int page_cache_get_specula + * page refcount has been raised. See below comment. + */ + +- while (unlikely(PageNoNewRefs(page))) +- cpu_relax(); ++ wait_on_page_ref(page); + + /* + * smp_rmb is to ensure the load of page->flags (for PageNoNewRefs()) +Index: linux-2.6.24.7-rt27/mm/filemap.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/filemap.c 2009-02-08 00:03:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/filemap.c 2009-02-08 00:03:08.000000000 -0500 +@@ -144,9 +144,11 @@ void remove_from_page_cache(struct page + + BUG_ON(!PageLocked(page)); + +- spin_lock_irq(&mapping->tree_lock); ++ lock_page_ref_irq(page); ++ spin_lock(&mapping->tree_lock); + __remove_from_page_cache(page); +- spin_unlock_irq(&mapping->tree_lock); ++ spin_unlock(&mapping->tree_lock); ++ unlock_page_ref_irq(page); + } + + static int sync_page(void *word) +@@ -456,8 +458,8 @@ int add_to_page_cache(struct page *page, + int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); + + if (error == 0) { +- set_page_nonewrefs(page); +- spin_lock_irq(&mapping->tree_lock); ++ lock_page_ref_irq(page); ++ spin_lock(&mapping->tree_lock); + error = radix_tree_insert(&mapping->page_tree, offset, page); + if (!error) { + page_cache_get(page); +@@ -467,8 +469,8 @@ int add_to_page_cache(struct page *page, + mapping_nrpages_inc(mapping); + __inc_zone_page_state(page, NR_FILE_PAGES); + } +- spin_unlock_irq(&mapping->tree_lock); +- clear_page_nonewrefs(page); ++ spin_unlock(&mapping->tree_lock); ++ unlock_page_ref_irq(page); + radix_tree_preload_end(); + } + return error; +Index: linux-2.6.24.7-rt27/mm/migrate.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/migrate.c 2009-02-08 00:03:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/migrate.c 2009-02-08 00:03:08.000000000 -0500 +@@ -303,16 +303,16 @@ static int migrate_page_move_mapping(str + return 0; + } + +- set_page_nonewrefs(page); +- spin_lock_irq(&mapping->tree_lock); ++ lock_page_ref_irq(page); ++ spin_lock(&mapping->tree_lock); + + pslot = radix_tree_lookup_slot(&mapping->page_tree, + page_index(page)); + + if (page_count(page) != 2 + !!PagePrivate(page) || + (struct page *)radix_tree_deref_slot(pslot) != page) { +- spin_unlock_irq(&mapping->tree_lock); +- clear_page_nonewrefs(page); ++ spin_unlock(&mapping->tree_lock); ++ unlock_page_ref_irq(page); + return -EAGAIN; + } + +@@ -329,14 +329,7 @@ static int migrate_page_move_mapping(str + + radix_tree_replace_slot(pslot, newpage); + page->mapping = NULL; +- spin_unlock_irq(&mapping->tree_lock); +- clear_page_nonewrefs(page); +- +- /* +- * Drop cache reference from old page. +- * We know this isn't the last reference. +- */ +- __put_page(page); ++ spin_unlock(&mapping->tree_lock); + + /* + * If moved to a different zone then also account +@@ -351,6 +344,14 @@ static int migrate_page_move_mapping(str + __dec_zone_page_state(page, NR_FILE_PAGES); + __inc_zone_page_state(newpage, NR_FILE_PAGES); + ++ unlock_page_ref_irq(page); ++ ++ /* ++ * Drop cache reference from old page. ++ * We know this isn't the last reference. ++ */ ++ __put_page(page); ++ + return 0; + } + +Index: linux-2.6.24.7-rt27/mm/page-writeback.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/page-writeback.c 2009-02-08 00:03:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/page-writeback.c 2009-02-08 00:03:08.000000000 -0500 +@@ -1008,7 +1008,8 @@ int __set_page_dirty_nobuffers(struct pa + if (!mapping) + return 1; + +- spin_lock_irq(&mapping->tree_lock); ++ lock_page_ref_irq(page); ++ spin_lock(&mapping->tree_lock); + mapping2 = page_mapping(page); + if (mapping2) { /* Race with truncate? */ + BUG_ON(mapping2 != mapping); +@@ -1022,7 +1023,8 @@ int __set_page_dirty_nobuffers(struct pa + radix_tree_tag_set(&mapping->page_tree, + page_index(page), PAGECACHE_TAG_DIRTY); + } +- spin_unlock_irq(&mapping->tree_lock); ++ spin_unlock(&mapping->tree_lock); ++ unlock_page_ref_irq(page); + if (mapping->host) { + /* !PageAnon && !swapper_space */ + __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); +@@ -1178,7 +1180,8 @@ int test_clear_page_writeback(struct pag + struct backing_dev_info *bdi = mapping->backing_dev_info; + unsigned long flags; + +- spin_lock_irqsave(&mapping->tree_lock, flags); ++ lock_page_ref_irqsave(page, flags); ++ spin_lock(&mapping->tree_lock); + ret = TestClearPageWriteback(page); + if (ret) { + radix_tree_tag_clear(&mapping->page_tree, +@@ -1189,7 +1192,8 @@ int test_clear_page_writeback(struct pag + __bdi_writeout_inc(bdi); + } + } +- spin_unlock_irqrestore(&mapping->tree_lock, flags); ++ spin_unlock(&mapping->tree_lock); ++ unlock_page_ref_irqrestore(page, flags); + } else { + ret = TestClearPageWriteback(page); + } +@@ -1207,7 +1211,8 @@ int test_set_page_writeback(struct page + struct backing_dev_info *bdi = mapping->backing_dev_info; + unsigned long flags; + +- spin_lock_irqsave(&mapping->tree_lock, flags); ++ lock_page_ref_irqsave(page, flags); ++ spin_lock(&mapping->tree_lock); + ret = TestSetPageWriteback(page); + if (!ret) { + radix_tree_tag_set(&mapping->page_tree, +@@ -1220,7 +1225,8 @@ int test_set_page_writeback(struct page + radix_tree_tag_clear(&mapping->page_tree, + page_index(page), + PAGECACHE_TAG_DIRTY); +- spin_unlock_irqrestore(&mapping->tree_lock, flags); ++ spin_unlock(&mapping->tree_lock); ++ unlock_page_ref_irqrestore(page, flags); + } else { + ret = TestSetPageWriteback(page); + } +Index: linux-2.6.24.7-rt27/mm/swap_state.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/swap_state.c 2009-02-08 00:03:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/swap_state.c 2009-02-08 00:03:08.000000000 -0500 +@@ -79,8 +79,8 @@ static int __add_to_swap_cache(struct pa + BUG_ON(PagePrivate(page)); + error = radix_tree_preload(gfp_mask); + if (!error) { +- set_page_nonewrefs(page); +- spin_lock_irq(&swapper_space.tree_lock); ++ lock_page_ref_irq(page); ++ spin_lock(&swapper_space.tree_lock); + error = radix_tree_insert(&swapper_space.page_tree, + entry.val, page); + if (!error) { +@@ -90,8 +90,8 @@ static int __add_to_swap_cache(struct pa + mapping_nrpages_inc(&swapper_space); + __inc_zone_page_state(page, NR_FILE_PAGES); + } +- spin_unlock_irq(&swapper_space.tree_lock); +- clear_page_nonewrefs(page); ++ spin_unlock(&swapper_space.tree_lock); ++ unlock_page_ref_irq(page); + radix_tree_preload_end(); + } + return error; +@@ -205,9 +205,11 @@ void delete_from_swap_cache(struct page + + entry.val = page_private(page); + +- spin_lock_irq(&swapper_space.tree_lock); ++ lock_page_ref_irq(page); ++ spin_lock(&swapper_space.tree_lock); + __delete_from_swap_cache(page); +- spin_unlock_irq(&swapper_space.tree_lock); ++ spin_unlock(&swapper_space.tree_lock); ++ unlock_page_ref_irq(page); + + swap_free(entry); + page_cache_release(page); +Index: linux-2.6.24.7-rt27/mm/swapfile.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/swapfile.c 2009-02-08 00:03:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/swapfile.c 2009-02-08 00:03:08.000000000 -0500 +@@ -367,13 +367,15 @@ int remove_exclusive_swap_page(struct pa + retval = 0; + if (p->swap_map[swp_offset(entry)] == 1) { + /* Recheck the page count with the swapcache lock held.. */ +- spin_lock_irq(&swapper_space.tree_lock); ++ lock_page_ref_irq(page); ++ spin_lock(&swapper_space.tree_lock); + if ((page_count(page) == 2) && !PageWriteback(page)) { + __delete_from_swap_cache(page); + SetPageDirty(page); + retval = 1; + } +- spin_unlock_irq(&swapper_space.tree_lock); ++ spin_unlock(&swapper_space.tree_lock); ++ unlock_page_ref_irq(page); + } + spin_unlock(&swap_lock); + +Index: linux-2.6.24.7-rt27/mm/truncate.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/truncate.c 2009-02-08 00:03:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/truncate.c 2009-02-08 00:03:08.000000000 -0500 +@@ -350,18 +350,21 @@ invalidate_complete_page2(struct address + if (PagePrivate(page) && !try_to_release_page(page, GFP_KERNEL)) + return 0; + +- spin_lock_irq(&mapping->tree_lock); ++ lock_page_ref_irq(page); ++ spin_lock(&mapping->tree_lock); + if (PageDirty(page)) + goto failed; + + BUG_ON(PagePrivate(page)); + __remove_from_page_cache(page); +- spin_unlock_irq(&mapping->tree_lock); ++ spin_unlock(&mapping->tree_lock); ++ unlock_page_ref_irq(page); + ClearPageUptodate(page); + page_cache_release(page); /* pagecache ref */ + return 1; + failed: +- spin_unlock_irq(&mapping->tree_lock); ++ spin_unlock(&mapping->tree_lock); ++ unlock_page_ref_irq(page); + return 0; + } + +Index: linux-2.6.24.7-rt27/mm/vmscan.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/vmscan.c 2009-02-08 00:03:05.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/vmscan.c 2009-02-08 00:03:08.000000000 -0500 +@@ -385,8 +385,8 @@ int remove_mapping(struct address_space + BUG_ON(!PageLocked(page)); + BUG_ON(mapping != page_mapping(page)); + +- set_page_nonewrefs(page); +- spin_lock_irq(&mapping->tree_lock); ++ lock_page_ref_irq(page); ++ spin_lock(&mapping->tree_lock); + /* + * The non racy check for a busy page. + * +@@ -421,22 +421,22 @@ int remove_mapping(struct address_space + if (PageSwapCache(page)) { + swp_entry_t swap = { .val = page_private(page) }; + __delete_from_swap_cache(page); +- spin_unlock_irq(&mapping->tree_lock); ++ spin_unlock(&mapping->tree_lock); + swap_free(swap); + goto free_it; + } + + __remove_from_page_cache(page); +- spin_unlock_irq(&mapping->tree_lock); ++ spin_unlock(&mapping->tree_lock); + + free_it: +- __clear_page_nonewrefs(page); ++ unlock_page_ref_irq(page); + __put_page(page); /* The pagecache ref */ + return 1; + + cannot_free: +- spin_unlock_irq(&mapping->tree_lock); +- clear_page_nonewrefs(page); ++ spin_unlock(&mapping->tree_lock); ++ unlock_page_ref_irq(page); + return 0; + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0210-preempt-realtime-arm-integrator.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0210-preempt-realtime-arm-integrator.patch @@ -0,0 +1,31 @@ +--- + arch/arm/mach-integrator/core.c | 2 +- + arch/arm/mach-integrator/pci_v3.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/arm/mach-integrator/core.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mach-integrator/core.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mach-integrator/core.c 2009-02-08 00:02:22.000000000 -0500 +@@ -164,7 +164,7 @@ static struct amba_pl010_data integrator + + #define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET + +-static DEFINE_SPINLOCK(cm_lock); ++static DEFINE_RAW_SPINLOCK(cm_lock); + + /** + * cm_control - update the CM_CTRL register. +Index: linux-2.6.24.7-rt27/arch/arm/mach-integrator/pci_v3.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/arm/mach-integrator/pci_v3.c 2009-02-08 00:00:07.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/arm/mach-integrator/pci_v3.c 2009-02-08 00:02:22.000000000 -0500 +@@ -162,7 +162,7 @@ + * 7:2 register number + * + */ +-static DEFINE_SPINLOCK(v3_lock); ++static DEFINE_RAW_SPINLOCK(v3_lock); + + #define PCI_BUS_NONMEM_START 0x00000000 + #define PCI_BUS_NONMEM_SIZE SZ_256M --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0357-watchdog_use_timer_and_hpet_on_x86_64.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0357-watchdog_use_timer_and_hpet_on_x86_64.patch @@ -0,0 +1,35 @@ +This modifies nmi_watchdog_tick behavior for +x86_64 arch to consider both timer and hpet IRQs +just as the i386 arch does. + +Signed-off-by: David Bahi + +--- + arch/x86/kernel/nmi_64.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_64.c 2009-02-08 00:02:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c 2009-02-08 00:03:40.000000000 -0500 +@@ -371,7 +371,6 @@ nmi_watchdog_tick(struct pt_regs * regs, + touched = 1; + } + +- sum = read_pda(apic_timer_irqs) + read_pda(irq0_irqs); + if (__get_cpu_var(nmi_touch)) { + __get_cpu_var(nmi_touch) = 0; + touched = 1; +@@ -387,6 +386,12 @@ nmi_watchdog_tick(struct pt_regs * regs, + cpu_clear(cpu, backtrace_mask); + } + ++ /* ++ * Take the local apic timer and PIT/HPET into account. We don't ++ * know which one is active, when we have highres/dyntick on ++ */ ++ sum = read_pda(apic_timer_irqs) + kstat_cpu(cpu).irqs[0]; ++ + #ifdef CONFIG_X86_MCE + /* Could check oops_in_progress here too, but it's safer + not too */ --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0505-rtmutex-debug-fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0505-rtmutex-debug-fix.patch @@ -0,0 +1,23 @@ +Subject: rtmutex-debug-fix.patch +From: Thomas Gleixner +Date: Fri, 20 Jun 2008 12:27:50 +0200 + +Signed-off-by: Thomas Gleixner +--- + kernel/rtmutex-debug.c | 3 +++ + 1 file changed, 3 insertions(+) + +Index: linux-2.6.24.7-rt27/kernel/rtmutex-debug.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/rtmutex-debug.c 2009-02-08 00:02:01.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/rtmutex-debug.c 2009-02-08 00:04:51.000000000 -0500 +@@ -59,6 +59,9 @@ void rt_mutex_debug_task_free(struct tas + { + DEBUG_LOCKS_WARN_ON(!plist_head_empty(&task->pi_waiters)); + DEBUG_LOCKS_WARN_ON(task->pi_blocked_on); ++#ifdef CONFIG_PREEMPT_RT ++ WARN_ON(task->reader_lock_count); ++#endif + } + + /* --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0435-nmi-watchdog-fix-4.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0435-nmi-watchdog-fix-4.patch @@ -0,0 +1,63 @@ +From h-shimamoto@ct.jp.nec.com Thu May 15 10:15:22 2008 +Date: Mon, 28 Apr 2008 11:19:21 -0700 +From: Hiroshi Shimamoto +To: Ingo Molnar , Steven Rostedt , + Thomas Gleixner +Cc: linux-kernel@vger.kernel.org, linux-rt-users@vger.kernel.org +Subject: [PATCH -rt 4/4] wait for finish show_regs() before panic + +From: Hiroshi Shimamoto + +It might cause kdump failure that the kernel doesn't wait for finish +show_regs(). The nmi_show_regs variable for show_regs() flag is cleared +before show_regs() is really called. This flag should be cleared after +show_regs(). +kdump stops all CPUs other than crashing CPU by NMI handler, but if +show_regs() takes a bit time, kdump cannot wait and will continue process. +It means that the 2nd kernel and the old kernel run simultaneously and it +might cause unexpected behavior, such as randomly reboot. + +Signed-off-by: Hiroshi Shimamoto +Signed-off-by: Maxim Uvarov +--- + arch/x86/kernel/nmi_32.c | 2 +- + arch/x86/kernel/nmi_64.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_32.c 2009-02-08 00:04:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_32.c 2009-02-08 00:04:18.000000000 -0500 +@@ -355,13 +355,13 @@ notrace int irq_show_regs_callback(int c + if (!nmi_show_regs[cpu]) + return 0; + +- nmi_show_regs[cpu] = 0; + spin_lock(&nmi_print_lock); + printk(KERN_WARNING "NMI show regs on CPU#%d:\n", cpu); + printk(KERN_WARNING "apic_timer_irqs: %d\n", + per_cpu(irq_stat, cpu).apic_timer_irqs); + show_regs(regs); + spin_unlock(&nmi_print_lock); ++ nmi_show_regs[cpu] = 0; + return 1; + } + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/nmi_64.c 2009-02-08 00:04:17.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/nmi_64.c 2009-02-08 00:04:18.000000000 -0500 +@@ -345,12 +345,12 @@ notrace int irq_show_regs_callback(int c + if (!nmi_show_regs[cpu]) + return 0; + +- nmi_show_regs[cpu] = 0; + spin_lock(&nmi_print_lock); + printk(KERN_WARNING "NMI show regs on CPU#%d:\n", cpu); + printk(KERN_WARNING "apic_timer_irqs: %d\n", read_pda(apic_timer_irqs)); + show_regs(regs); + spin_unlock(&nmi_print_lock); ++ nmi_show_regs[cpu] = 0; + return 1; + } + --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0234-preempt-realtime-ftrace-disable-ftraced.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0234-preempt-realtime-ftrace-disable-ftraced.patch @@ -0,0 +1,26 @@ +--- + init/main.c | 4 ++++ + 1 file changed, 4 insertions(+) + +Index: linux-2.6.24.7-rt27/init/main.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/init/main.c 2009-02-08 00:02:16.000000000 -0500 ++++ linux-2.6.24.7-rt27/init/main.c 2009-02-08 00:02:36.000000000 -0500 +@@ -59,6 +59,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -783,6 +784,9 @@ static int noinline init_post(void) + (void) sys_dup(0); + (void) sys_dup(0); + ++#ifdef CONFIG_PREEMPT_RT ++ ftrace_disable_daemon(); ++#endif + if (ramdisk_execute_command) { + run_init_process(ramdisk_execute_command); + printk(KERN_WARNING "Failed to execute %s\n", --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0011-x86_64-ia32_syscall_restart_fix.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0011-x86_64-ia32_syscall_restart_fix.patch @@ -0,0 +1,134 @@ +Bugzilla: + +From: Clark Williams + +https://bugzilla.redhat.com/show_bug.cgi?id=434998 + +Description: +The code to restart syscalls after signals depends on checking for a +negative orig_rax, and for particular negative -ERESTART* values in rax. +These fields are 64 bits and for a 32-bit task they get zero-extended, +therefore they are never negative and syscall restart behavior is lost. + +Solution: +Doing sign-extension where it matters. + +For orig_rax, the only time the value should be -1 but winds up as +0x0ffffffff is via a 32-bit ptrace call. So the patch changes ptrace to +sign-extend the 32-bit orig_eax value when it's stored; it doesn't +change the checks on orig_rax, though it uses the new current_syscall() +inline to better document the subtle importance of the used of +signedness there. + +The rax value is stored a lot of ways and it seems hard to get them all +sign-extended at their origins. So for that, we use the +current_syscall_ret() to sign-extend it only for 32-bit tasks at the +time of the -ERESTART* comparisons. + +Upstream status: +commit 40f0933d51f4cba26a5c009a26bb230f4514c1b6 + +Test status: +Built on all arch and tested on x86_64 using the reproducer provided in +bugzilla. + +Brew build: +http://brewweb.devel.redhat.com/brew/taskinfo?taskID=1365391 + +Regards, +Jerome +--- + + arch/x86/ia32/ptrace32.c | 10 +++++++++- + arch/x86/kernel/signal_64.c | 38 +++++++++++++++++++++++++++++++++----- + 2 files changed, 42 insertions(+), 6 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/ia32/ptrace32.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/ia32/ptrace32.c 2009-02-08 00:00:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/ia32/ptrace32.c 2009-02-08 00:00:47.000000000 -0500 +@@ -75,10 +75,18 @@ static int putreg32(struct task_struct * + R32(esi, rsi); + R32(ebp, rbp); + R32(eax, rax); +- R32(orig_eax, orig_rax); + R32(eip, rip); + R32(esp, rsp); + ++ case offsetof(struct user_regs_struct32, orig_eax): { ++ /* ++ * Sign-extend the value so that orig_eax = -1 ++ * causes (long)orig_rax < 0 tests to fire correctly. ++ */ ++ stack[offsetof(struct pt_regs, orig_rax)/8] = (long) (s32) val; ++ break; ++ } ++ + case offsetof(struct user32, regs.eflags): { + __u64 *flags = &stack[offsetof(struct pt_regs, eflags)/8]; + val &= FLAG_MASK; +Index: linux-2.6.24.7-rt27/arch/x86/kernel/signal_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/signal_64.c 2009-02-08 00:00:35.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/signal_64.c 2009-02-08 00:00:47.000000000 -0500 +@@ -311,6 +311,35 @@ give_sigsegv: + } + + /* ++ * Return -1L or the syscall number that @regs is executing. ++ */ ++static long current_syscall(struct pt_regs *regs) ++{ ++ /* ++ * We always sign-extend a -1 value being set here, ++ * so this is always either -1L or a syscall number. ++ */ ++ return regs->orig_rax; ++} ++ ++/* ++ * Return a value that is -EFOO if the system call in @regs->orig_rax ++ * returned an error. This only works for @regs from @current. ++ */ ++static long current_syscall_ret(struct pt_regs *regs) ++{ ++#ifdef CONFIG_IA32_EMULATION ++ if (test_thread_flag(TIF_IA32)) ++ /* ++ * Sign-extend the value so (int)-EFOO becomes (long)-EFOO ++ * and will match correctly in comparisons. ++ */ ++ return (int) regs->rax; ++#endif ++ return regs->rax; ++} ++ ++/* + * OK, we're invoking a handler + */ + +@@ -327,9 +356,9 @@ handle_signal(unsigned long sig, siginfo + #endif + + /* Are we from a system call? */ +- if ((long)regs->orig_rax >= 0) { ++ if (current_syscall(regs) >= 0) { + /* If so, check system call restarting.. */ +- switch (regs->rax) { ++ switch (current_syscall_ret(regs)) { + case -ERESTART_RESTARTBLOCK: + case -ERESTARTNOHAND: + regs->rax = -EINTR; +@@ -430,10 +459,9 @@ static void do_signal(struct pt_regs *re + } + + /* Did we come from a system call? */ +- if ((long)regs->orig_rax >= 0) { ++ if (current_syscall(regs) >= 0) { + /* Restart the system call - no handlers present */ +- long res = regs->rax; +- switch (res) { ++ switch (current_syscall_ret(regs)) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0389-fix-bug-on-in-filemap.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0389-fix-bug-on-in-filemap.patch @@ -0,0 +1,25 @@ +From: Steven Rostedt +Subject: Change bug_on for atomic to pagefault_disabled. + +The lockless page changes decoupled the pagefault disabled +from preempt count. The bug_on in filemap.c is now not correct. +This patch uses the proper check. + +Signed-off-by: Steven Rostedt +--- + mm/filemap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/mm/filemap.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/mm/filemap.c 2009-02-08 00:03:55.000000000 -0500 ++++ linux-2.6.24.7-rt27/mm/filemap.c 2009-02-08 00:03:55.000000000 -0500 +@@ -1764,7 +1764,7 @@ size_t iov_iter_copy_from_user_atomic(st + size_t copied; + + #ifndef CONFIG_PREEMPT_RT +- BUG_ON(!in_atomic()); ++ BUG_ON(!current->pagefault_disabled); + #endif + kaddr = kmap_atomic(page, KM_USER0); + if (likely(i->nr_segs == 1)) { --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0078-ftrace-m68knommu-add-FTRACE-support.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0078-ftrace-m68knommu-add-FTRACE-support.patch @@ -0,0 +1,128 @@ +From 674ceaadcb008adc57249a54c1b5b20c74c8c80b Mon Sep 17 00:00:00 2001 +From: Sebastian Siewior +Date: Wed, 9 Jul 2008 13:33:20 +0200 +Subject: [PATCH] m68knommu: add FTRACE support + +due to a gcc bug or feature or me too stupid, the following patch +has to be applied to gcc: + +|m68k: remove label generation on -pg +| +|haven't found a reason why this flag is needed. Maybe glibc needs this label. +|However this implementation puts the labels too far away. +| +|Signed-off-by: Sebastian Siewior +| +|--- a/gcc/config/m68k/linux.h +|+++ b/gcc/config/m68k/linux.h +|@@ -143,7 +143,6 @@ along with GCC; see the file COPYING3. +| #undef FUNCTION_PROFILER +| #define FUNCTION_PROFILER(FILE, LABELNO) \ +| { \ +|- asm_fprintf (FILE, "\tlea (%LLP%d,%Rpc),%Ra1\n", (LABELNO)); \ +| if (flag_pic) \ +| fprintf (FILE, "\tbsr.l _mcount@PLTPC\n"); \ +| else \ +|--- a/gcc/config/m68k/m68k.h +|+++ b/gcc/config/m68k/m68k.h +|@@ -576,7 +576,7 @@ extern enum reg_class regno_reg_class[]; +| #define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0 +| +| #define FUNCTION_PROFILER(FILE, LABELNO) \ +|- asm_fprintf (FILE, "\tlea %LLP%d,%Ra0\n\tjsr mcount\n", (LABELNO)) +|+ asm_fprintf (FILE, "\tjsr mcount\n", (LABELNO)) +| +| #define EXIT_IGNORE_STACK 1 +| + +Signed-off-by: Sebastian Siewior +Signed-off-by: Thomas Gleixner +--- + arch/m68knommu/Kconfig | 1 + arch/m68knommu/kernel/process.c | 2 + + arch/m68knommu/platform/coldfire/entry.S | 33 +++++++++++++++++++++++++++++++ + kernel/trace/trace.c | 1 + 4 files changed, 36 insertions(+), 1 deletion(-) + +Index: linux-2.6.24.7-rt27/arch/m68knommu/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/Kconfig 2009-02-08 00:00:48.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/Kconfig 2009-02-08 00:01:19.000000000 -0500 +@@ -175,6 +175,7 @@ config M527x + config COLDFIRE + bool + depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407) ++ select HAVE_FTRACE + default y + + config CLOCK_SET +Index: linux-2.6.24.7-rt27/arch/m68knommu/kernel/process.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/kernel/process.c 2009-02-08 00:00:24.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/kernel/process.c 2009-02-08 00:01:19.000000000 -0500 +@@ -74,7 +74,9 @@ void cpu_idle(void) + { + /* endless idle loop with no priority at all */ + while (1) { ++ stop_critical_timings(); + idle(); ++ start_critical_timings(); + preempt_enable_no_resched(); + schedule(); + preempt_disable(); +Index: linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/entry.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/m68knommu/platform/coldfire/entry.S 2009-02-08 00:00:48.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/m68knommu/platform/coldfire/entry.S 2009-02-08 00:01:19.000000000 -0500 +@@ -55,6 +55,39 @@ sw_usp: + .globl inthandler + .globl fasthandler + ++#ifdef CONFIG_FTRACE ++ENTRY(_mcount) ++ linkw %fp, #0 ++ ++ moveal ftrace_trace_function, %a0 ++ movel #ftrace_stub, %d0 ++ cmpl %a0@, %d0 ++ ++ bnew do_mcount ++ ++ unlk %fp ++ rts ++ ++do_mcount: ++ ++ movel %fp, %d0 ++ moveal %d0, %a1 ++ ++ moveal %a1@, %a0 ++ movel %a0@(4), %sp@- /* push parent ip */ ++ movel %a1@(4), %sp@- /* push ip */ ++ ++ moveal ftrace_trace_function, %a0 ++ jsr %a0@ ++ ++ unlk %fp ++ ++.globl ftrace_stub ++ftrace_stub: ++ rts ++END(mcount) ++#endif ++ + enosys: + mov.l #sys_ni_syscall,%d3 + bra 1f +Index: linux-2.6.24.7-rt27/kernel/trace/trace.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/trace/trace.c 2009-02-08 00:01:15.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/trace/trace.c 2009-02-08 00:01:19.000000000 -0500 +@@ -31,7 +31,6 @@ + + #include + +-#include + #include + + #include "trace.h" --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0175-rt-mutex-x86-64.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0175-rt-mutex-x86-64.patch @@ -0,0 +1,465 @@ +--- + arch/x86/Kconfig | 2 - + arch/x86/kernel/entry_64.S | 18 +++++----- + arch/x86/kernel/tsc_sync.c | 2 - + arch/x86/kernel/vsyscall_64.c | 2 - + arch/x86/kernel/x8664_ksyms_64.c | 10 +++-- + arch/x86/lib/thunk_64.S | 12 ++++-- + include/asm-x86/semaphore_64.h | 67 +++++++++++++++++++++++---------------- + include/asm-x86/spinlock_64.h | 28 ++++++++-------- + include/asm-x86/thread_info_64.h | 2 + + 9 files changed, 81 insertions(+), 62 deletions(-) + +Index: linux-2.6.24.7-rt27/arch/x86/Kconfig +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/Kconfig 2009-02-08 00:02:04.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/Kconfig 2009-02-08 00:02:05.000000000 -0500 +@@ -107,7 +107,7 @@ config ASM_SEMAPHORES + + config RWSEM_XCHGADD_ALGORITHM + bool +- depends on X86_XADD && !RWSEM_GENERIC_SPINLOCK ++ depends on X86_XADD && !RWSEM_GENERIC_SPINLOCK && !PREEMPT_RT + default y + + config ARCH_HAS_ILOG2_U32 +Index: linux-2.6.24.7-rt27/arch/x86/kernel/entry_64.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/entry_64.S 2009-02-08 00:01:15.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/entry_64.S 2009-02-08 00:02:05.000000000 -0500 +@@ -375,8 +375,8 @@ sysret_check: + /* Handle reschedules */ + /* edx: work, edi: workmask */ + sysret_careful: +- bt $TIF_NEED_RESCHED,%edx +- jnc sysret_signal ++ testl $(_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED),%edx ++ jz sysret_signal + TRACE_IRQS_ON + sti + pushq %rdi +@@ -399,7 +399,7 @@ sysret_signal: + leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1 + xorl %esi,%esi # oldset -> arg2 + call ptregscall_common +-1: movl $_TIF_NEED_RESCHED,%edi ++1: movl $(_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED),%edi + /* Use IRET because user could have changed frame. This + works because ptregscall_common has called FIXUP_TOP_OF_STACK. */ + cli +@@ -456,8 +456,8 @@ int_with_check: + /* First do a reschedule test. */ + /* edx: work, edi: workmask */ + int_careful: +- bt $TIF_NEED_RESCHED,%edx +- jnc int_very_careful ++ testl $(_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED),%edx ++ jz int_very_careful + TRACE_IRQS_ON + sti + pushq %rdi +@@ -492,7 +492,7 @@ int_signal: + movq %rsp,%rdi # &ptregs -> arg1 + xorl %esi,%esi # oldset -> arg2 + call do_notify_resume +-1: movl $_TIF_NEED_RESCHED,%edi ++1: movl $(_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED),%edi + int_restore_rest: + RESTORE_REST + cli +@@ -698,8 +698,8 @@ bad_iret: + /* edi: workmask, edx: work */ + retint_careful: + CFI_RESTORE_STATE +- bt $TIF_NEED_RESCHED,%edx +- jnc retint_signal ++ testl $(_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED),%edx ++ jz retint_signal + TRACE_IRQS_ON + sti + pushq %rdi +@@ -725,7 +725,7 @@ retint_signal: + RESTORE_REST + cli + TRACE_IRQS_OFF +- movl $_TIF_NEED_RESCHED,%edi ++ movl $(_TIF_NEED_RESCHED|_TIF_NEED_RESCHED_DELAYED),%edi + GET_THREAD_INFO(%rcx) + jmp retint_check + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/tsc_sync.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/tsc_sync.c 2009-02-08 00:01:24.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/tsc_sync.c 2009-02-08 00:02:05.000000000 -0500 +@@ -33,7 +33,7 @@ static __cpuinitdata atomic_t stop_count + * we want to have the fastest, inlined, non-debug version + * of a critical section, to be able to prove TSC time-warps: + */ +-static __cpuinitdata raw_spinlock_t sync_lock = __RAW_SPIN_LOCK_UNLOCKED; ++static __cpuinitdata __raw_spinlock_t sync_lock = __RAW_SPIN_LOCK_UNLOCKED; + static __cpuinitdata cycles_t last_tsc; + static __cpuinitdata cycles_t max_warp; + static __cpuinitdata int nr_warps; +Index: linux-2.6.24.7-rt27/arch/x86/kernel/vsyscall_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/vsyscall_64.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/vsyscall_64.c 2009-02-08 00:02:05.000000000 -0500 +@@ -55,7 +55,7 @@ int __vgetcpu_mode __section_vgetcpu_mod + + struct vsyscall_gtod_data __vsyscall_gtod_data __section_vsyscall_gtod_data = + { +- .lock = SEQLOCK_UNLOCKED, ++ .lock = __RAW_SEQLOCK_UNLOCKED(__vsyscall_gtod_data.lock), + .sysctl_enabled = 1, + }; + +Index: linux-2.6.24.7-rt27/arch/x86/kernel/x8664_ksyms_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/x8664_ksyms_64.c 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/x8664_ksyms_64.c 2009-02-08 00:02:05.000000000 -0500 +@@ -17,10 +17,12 @@ EXPORT_SYMBOL(mcount); + + EXPORT_SYMBOL(kernel_thread); + +-EXPORT_SYMBOL(__down_failed); +-EXPORT_SYMBOL(__down_failed_interruptible); +-EXPORT_SYMBOL(__down_failed_trylock); +-EXPORT_SYMBOL(__up_wakeup); ++#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK ++EXPORT_SYMBOL(__compat_down_failed); ++EXPORT_SYMBOL(__compat_down_failed_interruptible); ++EXPORT_SYMBOL(__compat_down_failed_trylock); ++EXPORT_SYMBOL(__compat_up_wakeup); ++#endif + + EXPORT_SYMBOL(__get_user_1); + EXPORT_SYMBOL(__get_user_2); +Index: linux-2.6.24.7-rt27/arch/x86/lib/thunk_64.S +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/lib/thunk_64.S 2009-02-08 00:01:09.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/lib/thunk_64.S 2009-02-08 00:02:05.000000000 -0500 +@@ -40,11 +40,13 @@ + thunk rwsem_wake_thunk,rwsem_wake + thunk rwsem_downgrade_thunk,rwsem_downgrade_wake + #endif +- +- thunk __down_failed,__down +- thunk_retrax __down_failed_interruptible,__down_interruptible +- thunk_retrax __down_failed_trylock,__down_trylock +- thunk __up_wakeup,__up ++ ++#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK ++ thunk __compat_down_failed,__compat_down ++ thunk_retrax __compat_down_failed_interruptible,__compat_down_interruptible ++ thunk_retrax __compat_down_failed_trylock,__compat_down_trylock ++ thunk __compat_up_wakeup,__compat_up ++#endif + + #ifdef CONFIG_TRACE_IRQFLAGS + /* put return address in rdi (arg1) */ +Index: linux-2.6.24.7-rt27/include/asm-x86/semaphore_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/semaphore_64.h 2009-02-08 00:00:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/semaphore_64.h 2009-02-08 00:02:05.000000000 -0500 +@@ -5,6 +5,10 @@ + + #ifdef __KERNEL__ + ++#ifndef CONFIG_PREEMPT_RT ++# define compat_semaphore semaphore ++#endif ++ + /* + * SMP- and interrupt-safe semaphores.. + * +@@ -43,28 +47,33 @@ + #include + #include + +-struct semaphore { ++struct compat_semaphore { + atomic_t count; + int sleepers; + wait_queue_head_t wait; + }; + +-#define __SEMAPHORE_INITIALIZER(name, n) \ ++#define __COMPAT_SEMAPHORE_INITIALIZER(name, n) \ + { \ + .count = ATOMIC_INIT(n), \ + .sleepers = 0, \ + .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + } + +-#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ +- struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) ++#define __COMPAT_MUTEX_INITIALIZER(name) \ ++ __COMPAT_SEMAPHORE_INITIALIZER(name,1) ++ ++#define __COMPAT_DECLARE_SEMAPHORE_GENERIC(name,count) \ ++ struct compat_semaphore name = __COMPAT_SEMAPHORE_INITIALIZER(name,count) + +-#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) ++#define COMPAT_DECLARE_MUTEX(name) __COMPAT_DECLARE_SEMAPHORE_GENERIC(name,1) + +-static inline void sema_init (struct semaphore *sem, int val) ++#define compat_sema_count(sem) atomic_read(&(sem)->count) ++ ++static inline void compat_sema_init (struct compat_semaphore *sem, int val) + { + /* +- * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); ++ * *sem = (struct compat_semaphore)__SEMAPHORE_INITIALIZER((*sem),val); + * + * i'd rather use the more flexible initialization above, but sadly + * GCC 2.7.2.3 emits a bogus warning. EGCS doesn't. Oh well. +@@ -74,32 +83,33 @@ static inline void sema_init (struct sem + init_waitqueue_head(&sem->wait); + } + +-static inline void init_MUTEX (struct semaphore *sem) ++static inline void compat_init_MUTEX (struct compat_semaphore *sem) + { +- sema_init(sem, 1); ++ compat_sema_init(sem, 1); + } + +-static inline void init_MUTEX_LOCKED (struct semaphore *sem) ++static inline void compat_init_MUTEX_LOCKED (struct compat_semaphore *sem) + { +- sema_init(sem, 0); ++ compat_sema_init(sem, 0); + } + +-asmlinkage void __down_failed(void /* special register calling convention */); +-asmlinkage int __down_failed_interruptible(void /* params in registers */); +-asmlinkage int __down_failed_trylock(void /* params in registers */); +-asmlinkage void __up_wakeup(void /* special register calling convention */); ++asmlinkage void __compat_down_failed(void /* special register calling convention */); ++asmlinkage int __compat_down_failed_interruptible(void /* params in registers */); ++asmlinkage int __compat_down_failed_trylock(void /* params in registers */); ++asmlinkage void __compat_up_wakeup(void /* special register calling convention */); + +-asmlinkage void __down(struct semaphore * sem); +-asmlinkage int __down_interruptible(struct semaphore * sem); +-asmlinkage int __down_trylock(struct semaphore * sem); +-asmlinkage void __up(struct semaphore * sem); ++asmlinkage void __compat_down(struct compat_semaphore * sem); ++asmlinkage int __compat_down_interruptible(struct compat_semaphore * sem); ++asmlinkage int __compat_down_trylock(struct compat_semaphore * sem); ++asmlinkage void __compat_up(struct compat_semaphore * sem); ++asmlinkage int compat_sem_is_locked(struct compat_semaphore *sem); + + /* + * This is ugly, but we want the default case to fall through. + * "__down_failed" is a special asm handler that calls the C + * routine that actually waits. See arch/x86_64/kernel/semaphore.c + */ +-static inline void down(struct semaphore * sem) ++static inline void compat_down(struct compat_semaphore * sem) + { + might_sleep(); + +@@ -107,7 +117,7 @@ static inline void down(struct semaphore + "# atomic down operation\n\t" + LOCK_PREFIX "decl %0\n\t" /* --sem->count */ + "jns 1f\n\t" +- "call __down_failed\n" ++ "call __compat_down_failed\n" + "1:" + :"=m" (sem->count) + :"D" (sem) +@@ -118,7 +128,7 @@ static inline void down(struct semaphore + * Interruptible try to acquire a semaphore. If we obtained + * it, return zero. If we were interrupted, returns -EINTR + */ +-static inline int down_interruptible(struct semaphore * sem) ++static inline int compat_down_interruptible(struct compat_semaphore * sem) + { + int result; + +@@ -129,7 +139,7 @@ static inline int down_interruptible(str + "xorl %0,%0\n\t" + LOCK_PREFIX "decl %1\n\t" /* --sem->count */ + "jns 2f\n\t" +- "call __down_failed_interruptible\n" ++ "call __compat_down_failed_interruptible\n" + "2:\n" + :"=&a" (result), "=m" (sem->count) + :"D" (sem) +@@ -141,7 +151,7 @@ static inline int down_interruptible(str + * Non-blockingly attempt to down() a semaphore. + * Returns zero if we acquired it + */ +-static inline int down_trylock(struct semaphore * sem) ++static inline int compat_down_trylock(struct compat_semaphore * sem) + { + int result; + +@@ -150,7 +160,7 @@ static inline int down_trylock(struct se + "xorl %0,%0\n\t" + LOCK_PREFIX "decl %1\n\t" /* --sem->count */ + "jns 2f\n\t" +- "call __down_failed_trylock\n\t" ++ "call __compat_down_failed_trylock\n\t" + "2:\n" + :"=&a" (result), "=m" (sem->count) + :"D" (sem) +@@ -164,17 +174,20 @@ static inline int down_trylock(struct se + * The default case (no contention) will result in NO + * jumps for both down() and up(). + */ +-static inline void up(struct semaphore * sem) ++static inline void compat_up(struct compat_semaphore * sem) + { + __asm__ __volatile__( + "# atomic up operation\n\t" + LOCK_PREFIX "incl %0\n\t" /* ++sem->count */ + "jg 1f\n\t" +- "call __up_wakeup\n" ++ "call __compat_up_wakeup\n" + "1:" + :"=m" (sem->count) + :"D" (sem) + :"memory"); + } ++ ++#include ++ + #endif /* __KERNEL__ */ + #endif +Index: linux-2.6.24.7-rt27/include/asm-x86/spinlock_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/spinlock_64.h 2009-02-08 00:00:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/spinlock_64.h 2009-02-08 00:02:05.000000000 -0500 +@@ -17,12 +17,12 @@ + * (the type definitions are in asm/spinlock_types.h) + */ + +-static inline int __raw_spin_is_locked(raw_spinlock_t *lock) ++static inline int __raw_spin_is_locked(__raw_spinlock_t *lock) + { + return *(volatile signed int *)(&(lock)->slock) <= 0; + } + +-static inline void __raw_spin_lock(raw_spinlock_t *lock) ++static inline void __raw_spin_lock(__raw_spinlock_t *lock) + { + asm volatile( + "\n1:\t" +@@ -40,7 +40,7 @@ static inline void __raw_spin_lock(raw_s + * Same as __raw_spin_lock, but reenable interrupts during spinning. + */ + #ifndef CONFIG_PROVE_LOCKING +-static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) ++static inline void __raw_spin_lock_flags(__raw_spinlock_t *lock, unsigned long flags) + { + asm volatile( + "\n1:\t" +@@ -65,7 +65,7 @@ static inline void __raw_spin_lock_flags + } + #endif + +-static inline int __raw_spin_trylock(raw_spinlock_t *lock) ++static inline int __raw_spin_trylock(__raw_spinlock_t *lock) + { + int oldval; + +@@ -77,12 +77,12 @@ static inline int __raw_spin_trylock(raw + return oldval > 0; + } + +-static inline void __raw_spin_unlock(raw_spinlock_t *lock) ++static inline void __raw_spin_unlock(__raw_spinlock_t *lock) + { + asm volatile("movl $1,%0" :"=m" (lock->slock) :: "memory"); + } + +-static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock) ++static inline void __raw_spin_unlock_wait(__raw_spinlock_t *lock) + { + while (__raw_spin_is_locked(lock)) + cpu_relax(); +@@ -102,17 +102,17 @@ static inline void __raw_spin_unlock_wai + * with the high bit (sign) being the "contended" bit. + */ + +-static inline int __raw_read_can_lock(raw_rwlock_t *lock) ++static inline int __raw_read_can_lock(__raw_rwlock_t *lock) + { + return (int)(lock)->lock > 0; + } + +-static inline int __raw_write_can_lock(raw_rwlock_t *lock) ++static inline int __raw_write_can_lock(__raw_rwlock_t *lock) + { + return (lock)->lock == RW_LOCK_BIAS; + } + +-static inline void __raw_read_lock(raw_rwlock_t *rw) ++static inline void __raw_read_lock(__raw_rwlock_t *rw) + { + asm volatile(LOCK_PREFIX "subl $1,(%0)\n\t" + "jns 1f\n" +@@ -121,7 +121,7 @@ static inline void __raw_read_lock(raw_r + ::"D" (rw), "i" (RW_LOCK_BIAS) : "memory"); + } + +-static inline void __raw_write_lock(raw_rwlock_t *rw) ++static inline void __raw_write_lock(__raw_rwlock_t *rw) + { + asm volatile(LOCK_PREFIX "subl %1,(%0)\n\t" + "jz 1f\n" +@@ -130,7 +130,7 @@ static inline void __raw_write_lock(raw_ + ::"D" (rw), "i" (RW_LOCK_BIAS) : "memory"); + } + +-static inline int __raw_read_trylock(raw_rwlock_t *lock) ++static inline int __raw_read_trylock(__raw_rwlock_t *lock) + { + atomic_t *count = (atomic_t *)lock; + atomic_dec(count); +@@ -140,7 +140,7 @@ static inline int __raw_read_trylock(raw + return 0; + } + +-static inline int __raw_write_trylock(raw_rwlock_t *lock) ++static inline int __raw_write_trylock(__raw_rwlock_t *lock) + { + atomic_t *count = (atomic_t *)lock; + if (atomic_sub_and_test(RW_LOCK_BIAS, count)) +@@ -149,12 +149,12 @@ static inline int __raw_write_trylock(ra + return 0; + } + +-static inline void __raw_read_unlock(raw_rwlock_t *rw) ++static inline void __raw_read_unlock(__raw_rwlock_t *rw) + { + asm volatile(LOCK_PREFIX " ; incl %0" :"=m" (rw->lock) : : "memory"); + } + +-static inline void __raw_write_unlock(raw_rwlock_t *rw) ++static inline void __raw_write_unlock(__raw_rwlock_t *rw) + { + asm volatile(LOCK_PREFIX " ; addl $" RW_LOCK_BIAS_STR ",%0" + : "=m" (rw->lock) : : "memory"); +Index: linux-2.6.24.7-rt27/include/asm-x86/thread_info_64.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/asm-x86/thread_info_64.h 2009-02-08 00:00:10.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/asm-x86/thread_info_64.h 2009-02-08 00:02:05.000000000 -0500 +@@ -111,6 +111,7 @@ static inline struct thread_info *stack_ + #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ + #define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/ + #define TIF_IRET 5 /* force IRET */ ++#define TIF_NEED_RESCHED_DELAYED 6 /* reschedul on return to userspace */ + #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ + #define TIF_SECCOMP 8 /* secure computing */ + #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal */ +@@ -133,6 +134,7 @@ static inline struct thread_info *stack_ + #define _TIF_SECCOMP (1<regs, args->trapnr)) + ret = NOTIFY_STOP; +- preempt_enable(); + break; + default: + break; +Index: linux-2.6.24.7-rt27/arch/x86/kernel/kprobes_64.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/arch/x86/kernel/kprobes_64.c 2009-02-07 23:59:50.000000000 -0500 ++++ linux-2.6.24.7-rt27/arch/x86/kernel/kprobes_64.c 2009-02-08 00:03:23.000000000 -0500 +@@ -655,11 +655,9 @@ int __kprobes kprobe_exceptions_notify(s + break; + case DIE_GPF: + /* kprobe_running() needs smp_processor_id() */ +- preempt_disable(); +- if (kprobe_running() && ++ if (per_cpu(current_kprobe, raw_smp_processor_id()) && + kprobe_fault_handler(args->regs, args->trapnr)) + ret = NOTIFY_STOP; +- preempt_enable(); + break; + default: + break; +Index: linux-2.6.24.7-rt27/include/linux/netpoll.h +=================================================================== +--- linux-2.6.24.7-rt27.orig/include/linux/netpoll.h 2009-02-07 23:59:50.000000000 -0500 ++++ linux-2.6.24.7-rt27/include/linux/netpoll.h 2009-02-08 00:03:23.000000000 -0500 +@@ -77,7 +77,7 @@ static inline void *netpoll_poll_lock(st + rcu_read_lock(); /* deal with race on ->npinfo */ + if (dev && dev->npinfo) { + spin_lock(&napi->poll_lock); +- napi->poll_owner = smp_processor_id(); ++ napi->poll_owner = raw_smp_processor_id(); + return napi; + } + return NULL; +Index: linux-2.6.24.7-rt27/kernel/hrtimer.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/hrtimer.c 2009-02-08 00:03:21.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/hrtimer.c 2009-02-08 00:03:23.000000000 -0500 +@@ -1222,7 +1222,9 @@ void hrtimer_interrupt(struct clock_even + + static void run_hrtimer_softirq(struct softirq_action *h) + { +- struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); ++ struct hrtimer_cpu_base *cpu_base; ++ ++ cpu_base = &per_cpu(hrtimer_bases, raw_smp_processor_id()); + + spin_lock_irq(&cpu_base->lock); + +Index: linux-2.6.24.7-rt27/kernel/workqueue.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/kernel/workqueue.c 2009-02-08 00:03:00.000000000 -0500 ++++ linux-2.6.24.7-rt27/kernel/workqueue.c 2009-02-08 00:03:23.000000000 -0500 +@@ -186,7 +186,7 @@ void delayed_work_timer_fn(unsigned long + struct cpu_workqueue_struct *cwq = get_wq_data(&dwork->work); + struct workqueue_struct *wq = cwq->wq; + +- __queue_work(wq_per_cpu(wq, smp_processor_id()), &dwork->work); ++ __queue_work(wq_per_cpu(wq, raw_smp_processor_id()), &dwork->work); + } + + /** --- linux-2.6.24.orig/debian/binary-custom.d/rt/patchset/0257-preempt-realtime-rawlocks.patch +++ linux-2.6.24/debian/binary-custom.d/rt/patchset/0257-preempt-realtime-rawlocks.patch @@ -0,0 +1,114 @@ +--- + drivers/oprofile/oprofilefs.c | 2 +- + drivers/pci/access.c | 2 +- + drivers/video/console/vgacon.c | 2 +- + include/linux/kprobes.h | 2 +- + include/linux/oprofile.h | 2 +- + include/linux/percpu_counter.h | 2 +- + kernel/kprobes.c | 2 +- + kernel/softlockup.c | 2 +- + 8 files changed, 8 insertions(+), 8 deletions(-) + +Index: linux-2.6.24.7-rt27/drivers/oprofile/oprofilefs.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/oprofile/oprofilefs.c 2009-02-07 23:59:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/oprofile/oprofilefs.c 2009-02-08 00:02:47.000000000 -0500 +@@ -21,7 +21,7 @@ + + #define OPROFILEFS_MAGIC 0x6f70726f + +-DEFINE_SPINLOCK(oprofilefs_lock); ++DEFINE_RAW_SPINLOCK(oprofilefs_lock); + + static struct inode * oprofilefs_get_inode(struct super_block * sb, int mode) + { +Index: linux-2.6.24.7-rt27/drivers/pci/access.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/pci/access.c 2009-02-07 23:59:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/pci/access.c 2009-02-08 00:02:47.000000000 -0500 +@@ -11,7 +11,7 @@ + * configuration space. + */ + +-static DEFINE_SPINLOCK(pci_lock); ++static DEFINE_RAW_SPINLOCK(pci_lock); + + /* + * Wrappers for all PCI configuration access functions. They just check +Index: linux-2.6.24.7-rt27/drivers/video/console/vgacon.c +=================================================================== +--- linux-2.6.24.7-rt27.orig/drivers/video/console/vgacon.c 2009-02-07 23:59:56.000000000 -0500 ++++ linux-2.6.24.7-rt27/drivers/video/console/vgacon.c 2009-02-08 00:02:47.000000000 -0500 +@@ -51,7 +51,7 @@ + #include